From ab5afc7258269c7f8f8cc4bc30b2f08e2f541773 Mon Sep 17 00:00:00 2001 From: Kirill Chernakov Date: Mon, 28 Oct 2024 15:15:22 +0400 Subject: [PATCH 01/11] fix: hovering long dashboard names stretch NavBar (#2317) --- keep-ui/components/navbar/DashboardLink.tsx | 51 ++++++++++++-------- keep-ui/components/navbar/DashboardLinks.tsx | 5 +- 2 files changed, 33 insertions(+), 23 deletions(-) diff --git a/keep-ui/components/navbar/DashboardLink.tsx b/keep-ui/components/navbar/DashboardLink.tsx index cc046de60..80016e0bf 100644 --- a/keep-ui/components/navbar/DashboardLink.tsx +++ b/keep-ui/components/navbar/DashboardLink.tsx @@ -1,8 +1,8 @@ -import { useSortable } from '@dnd-kit/sortable'; +import { useSortable } from "@dnd-kit/sortable"; import { Subtitle } from "@tremor/react"; import { FiLayout } from "react-icons/fi"; import { LinkWithIcon } from "components/LinkWithIcon"; // Ensure you import this correctly -import classNames from 'classnames'; +import { clsx } from "clsx"; interface Dashboard { id: string; @@ -14,31 +14,40 @@ type DashboardLinkProps = { dashboard: Dashboard; pathname: string | null; deleteDashboard: (id: string) => void; + titleClassName?: string; }; -export const DashboardLink = ({ dashboard, pathname, deleteDashboard }: DashboardLinkProps) => { +export const DashboardLink = ({ + dashboard, + pathname, + deleteDashboard, + titleClassName, +}: DashboardLinkProps) => { const href = `/dashboard/${dashboard.dashboard_name}`; - const isActive = decodeURIComponent(pathname|| "") === href; - - const { isDragging } = - useSortable({ - id: dashboard.id, - }); + const isActive = decodeURIComponent(pathname || "") === href; + const { isDragging } = useSortable({ + id: dashboard.id, + }); return ( deleteDashboard(dashboard.id)} - > - - {dashboard.dashboard_name} - - + href={href} + icon={FiLayout} + isDeletable={true} + onDelete={() => deleteDashboard(dashboard.id)} + > + + {dashboard.dashboard_name} + + ); }; diff --git a/keep-ui/components/navbar/DashboardLinks.tsx b/keep-ui/components/navbar/DashboardLinks.tsx index cf0cab3d4..80fcc9c35 100644 --- a/keep-ui/components/navbar/DashboardLinks.tsx +++ b/keep-ui/components/navbar/DashboardLinks.tsx @@ -13,7 +13,7 @@ import { DashboardLink } from "./DashboardLink"; import { Subtitle, Button, Badge, Text } from "@tremor/react"; import { Disclosure } from "@headlessui/react"; import { IoChevronUp } from "react-icons/io5"; -import classNames from "classnames"; +import clsx from "clsx"; import { useDashboards } from "utils/hooks/useDashboards"; import { useApiUrl } from "utils/hooks/useConfig"; @@ -105,7 +105,7 @@ export const DashboardLinks = ({ session }: DashboardProps) => { Beta { dashboard={dashboard} pathname={pathname} deleteDashboard={deleteDashboard} + titleClassName="max-w-[150px] overflow-hidden overflow-ellipsis" /> )) ) : ( From ebbb889f627dea2899e9dc828eb20da99e567760 Mon Sep 17 00:00:00 2001 From: Matvey Kukuy Date: Mon, 28 Oct 2024 18:14:20 +0400 Subject: [PATCH 02/11] fix: keycloak docs (#2309) --- .../authentication/keycloak-auth.mdx | 5 ++-- .../keycloak/keycloak_authverifier.py | 7 ++++++ keycloak/keycloak_entrypoint.sh | 4 ++-- keycloak/readme.md | 24 +++++++++++++++---- 4 files changed, 32 insertions(+), 8 deletions(-) diff --git a/docs/deployment/authentication/keycloak-auth.mdx b/docs/deployment/authentication/keycloak-auth.mdx index 255e67ed2..eb821e7a6 100644 --- a/docs/deployment/authentication/keycloak-auth.mdx +++ b/docs/deployment/authentication/keycloak-auth.mdx @@ -32,6 +32,7 @@ To start Keep with Keycloak authentication, set the following environment variab | AUTH_TYPE | Set to 'KEYCLOAK' for Keycloak authentication | Yes | - | | KEYCLOAK_ID | Your Keycloak client ID (e.g. keep) | Yes | - | | KEYCLOAK_ISSUER | Full URL to Your Keycloak issuer URL e.g. http://localhost:8181/auth/realms/keep | Yes | - | +| KEYCLOAK_SECRET | Your Keycloak client secret | Yes | keep-keycloak-secret | #### Backend Environment Variables @@ -50,5 +51,5 @@ To start Keep with Keycloak authentication, set the following environment variab ### Example configuration To get a better understanding on how to use Keep together with Keycloak, you can: -- See [Keycloak](https://github.com/keephq/keep/tree/main/tests) directory for configuration, realm.json, etc -- See Keep + Keycloak [docker-compose example](https://github.com/keephq/keep/blob/main/keycloak/docker-compose.yml) +- See [Keycloak](https://github.com/keephq/keep/tree/main/keycloak) directory for configuration, realm.json, etc +- See Keep + Keycloak [docker-compose example](https://github.com/keephq/keep/blob/main/keycloak/docker-compose.yaml) diff --git a/ee/identitymanager/identity_managers/keycloak/keycloak_authverifier.py b/ee/identitymanager/identity_managers/keycloak/keycloak_authverifier.py index 1daf5bb6a..1a2fd7516 100644 --- a/ee/identitymanager/identity_managers/keycloak/keycloak_authverifier.py +++ b/ee/identitymanager/identity_managers/keycloak/keycloak_authverifier.py @@ -1,4 +1,5 @@ import os +import logging from fastapi import Depends, HTTPException @@ -8,6 +9,8 @@ from keycloak.keycloak_uma import KeycloakUMA from keycloak.uma_permissions import UMAPermission +logger = logging.getLogger(__name__) + class KeycloakAuthVerifier(AuthVerifierBase): """Handles authentication and authorization for Keycloak""" @@ -55,6 +58,10 @@ def _verify_bearer_token( email = payload.get("preferred_username") org_id = payload.get("active_organization", {}).get("id") org_realm = payload.get("active_organization", {}).get("name") + if org_id is None or org_realm is None: + logger.warning( + "Invalid Keycloak configuration - no org information for user. Check organization mapper: https://github.com/keephq/keep/blob/main/keycloak/keep-realm.json#L93" + ) role = ( payload.get("resource_access", {}) .get(self.keycloak_client_id, {}) diff --git a/keycloak/keycloak_entrypoint.sh b/keycloak/keycloak_entrypoint.sh index d8bfa81e2..74a95fce9 100755 --- a/keycloak/keycloak_entrypoint.sh +++ b/keycloak/keycloak_entrypoint.sh @@ -28,7 +28,7 @@ fi # Start Keycloak in the background echo "Starting Keycloak" -/opt/keycloak/bin/kc.sh start-dev --features=preview --import-realm -Dkeycloak.profile.feature.scripts=enabled -Dkeycloak.migration.strategy=OVERWRITE_EXISTIN & +/opt/keycloak/bin/kc.sh start-dev --log-level=DEBUG --features=preview --import-realm -Dkeycloak.profile.feature.scripts=enabled -Dkeycloak.migration.strategy=OVERWRITE_EXISTIN & echo "Keycloak started" # Try to connect to Keycloak - wait until Keycloak is ready or timeout echo "Waiting for Keycloak to be ready" @@ -62,7 +62,7 @@ echo "Event listener 'last_login' configured" # Configure Content-Security-Policy and X-Frame-Options # So that the SSO connect works with the Keep UI echo "Configuring Content-Security-Policy and X-Frame-Options" -/opt/keycloak/bin/kcadm.sh update realms/${KEEP_REALM} -s 'browserSecurityHeaders.contentSecurityPolicy="frame-src '\''self'\'' '"$KEEP_URL"'; frame-ancestors '\''self'\'' '"$KEEP_URL"'; object-src '\''none'\'';"' +/opt/keycloak/bin/kcadm.sh update realms/${KEEP_REALM} -s 'browserSecurityHeaders.contentSecurityPolicy="frame-src '\''self'\'' '${KEEP_URL}'; frame-ancestors '\''self'\'' '${KEEP_URL}'; object-src '\''none'\'';"' /opt/keycloak/bin/kcadm.sh update realms/${KEEP_REALM} -s 'browserSecurityHeaders.xFrameOptions="ALLOW"' echo "Content-Security-Policy and X-Frame-Options configured" diff --git a/keycloak/readme.md b/keycloak/readme.md index a7f980b42..910bc3a8c 100644 --- a/keycloak/readme.md +++ b/keycloak/readme.md @@ -1,17 +1,33 @@ +# Docker-compose example: +``` +docker-compose -f keycloak/docker-compose.yaml up +``` +Keycloak: http://localhost:8181/auth/ (keep_kc:keep_kc) +Keep login page: http://localhost:3000/ +## For Azure: +Instructions: +1. https://rahulroyz.medium.com/using-keycloak-as-idp-for-azure-ad-sso-authentication-role-authorization-0b309c15eadc +2. https://rahulroyz.medium.com/using-keycloak-as-idp-for-azure-ad-role-authorization-part-2-map-ad-groups-to-keycloak-roles-9850d4acd536 + +Set email, first name & last name for keep_admin user: http://localhost:8181/auth/admin/master/console/#/keep/users +Also please assign admin role for keep_admin. + +# Development + +``` docker run --name phasetwo_test --rm -p 8181:8080 \ -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin \ quay.io/phasetwo/phasetwo-keycloak:latest \ start-dev - - +``` +``` http://localhost:8181/realms/keep/portal/ http://localhost:8181/realms/keep/portal/ - https://euc1.auth.ac/auth/realms/keep/portal - +``` # delete realm to refresh 1. delete the realm from the UI From d101552291ffa35d5d611bb1fd7457a3f76299ea Mon Sep 17 00:00:00 2001 From: Vladimir Filonov Date: Mon, 28 Oct 2024 23:08:23 +0400 Subject: [PATCH 03/11] fix: incident.alerts_count should return count of unique fingerprints instead of alerts (#2217) --- keep/api/core/db.py | 30 ++++++++++---- keep/api/tasks/process_event_task.py | 5 ++- tests/test_incidents.py | 59 ++++++++++++++++++++++------ 3 files changed, 74 insertions(+), 20 deletions(-) diff --git a/keep/api/core/db.py b/keep/api/core/db.py index 0d1c0e3c5..9d6bc7380 100644 --- a/keep/api/core/db.py +++ b/keep/api/core/db.py @@ -2950,7 +2950,9 @@ def get_all_same_alert_ids( def get_alerts_data_for_incident( - alert_ids: List[str | UUID], session: Optional[Session] = None + alert_ids: List[str | UUID], + existed_fingerprints: Optional[List[str]] = None, + session: Optional[Session] = None ) -> dict: """ Function to prepare aggregated data for incidents from the given list of alert_ids @@ -2962,12 +2964,14 @@ def get_alerts_data_for_incident( Returns: dict {sources: list[str], services: list[str], count: int} """ + existed_fingerprints = existed_fingerprints or [] with existed_or_new_session(session) as session: fields = ( get_json_extract_field(session, Alert.event, "service"), Alert.provider_type, + Alert.fingerprint, get_json_extract_field(session, Alert.event, "severity"), ) @@ -2980,8 +2984,9 @@ def get_alerts_data_for_incident( sources = [] services = [] severities = [] + fingerprints = set() - for service, source, severity in alerts_data: + for service, source, fingerprint, severity in alerts_data: if source: sources.append(source) if service: @@ -2991,12 +2996,14 @@ def get_alerts_data_for_incident( severities.append(IncidentSeverity.from_number(severity)) else: severities.append(IncidentSeverity(severity)) + if fingerprint and fingerprint not in existed_fingerprints: + fingerprints.add(fingerprint) return { "sources": set(sources), "services": set(services), "max_severity": max(severities), - "count": len(alerts_data), + "count": len(fingerprints), } @@ -3047,6 +3054,17 @@ def add_alerts_to_incident( ) ).all() ) + existing_fingerprints = set( + session.exec( + select(Alert.fingerprint) + .join(AlertToIncident, AlertToIncident.alert_id == Alert.id) + .where( + AlertToIncident.deleted_at == NULL_FOR_DELETED_AT, + AlertToIncident.tenant_id == tenant_id, + AlertToIncident.incident_id == incident.id, + ) + ).all() + ) new_alert_ids = [ alert_id for alert_id in all_alert_ids if alert_id not in existing_alert_ids @@ -3055,9 +3073,7 @@ def add_alerts_to_incident( if not new_alert_ids: return incident - alerts_data_for_incident = get_alerts_data_for_incident( - new_alert_ids, session - ) + alerts_data_for_incident = get_alerts_data_for_incident(new_alert_ids, existing_fingerprints, session) incident.sources = list( set(incident.sources if incident.sources else []) | set(alerts_data_for_incident["sources"]) @@ -3177,7 +3193,7 @@ def remove_alerts_to_incident_by_incident_id( session.commit() # Getting aggregated data for incidents for alerts which just was removed - alerts_data_for_incident = get_alerts_data_for_incident(all_alert_ids, session) + alerts_data_for_incident = get_alerts_data_for_incident(all_alert_ids, session=session) service_field = get_json_extract_field(session, Alert.event, "service") diff --git a/keep/api/tasks/process_event_task.py b/keep/api/tasks/process_event_task.py index 5e2070743..9347fe49b 100644 --- a/keep/api/tasks/process_event_task.py +++ b/keep/api/tasks/process_event_task.py @@ -527,7 +527,10 @@ def process_event( and isinstance(event, dict) or isinstance(event, FormData) ): - provider_class = ProvidersFactory.get_provider_class(provider_type) + try: + provider_class = ProvidersFactory.get_provider_class(provider_type) + except Exception: + provider_class = ProvidersFactory.get_provider_class("keep") event = provider_class.format_alert( tenant_id=tenant_id, event=event, diff --git a/tests/test_incidents.py b/tests/test_incidents.py index 5cd78fbd2..b9758b638 100644 --- a/tests/test_incidents.py +++ b/tests/test_incidents.py @@ -2,7 +2,7 @@ from itertools import cycle import pytest -from sqlalchemy import func +from sqlalchemy import func, distinct from sqlalchemy.orm.exc import DetachedInstanceError from keep.api.core.db import ( @@ -23,24 +23,40 @@ IncidentSeverity, IncidentStatus, ) -from keep.api.models.db.alert import Alert +from keep.api.models.db.alert import Alert, AlertToIncident from keep.api.utils.enrichment_helpers import convert_db_alerts_to_dto_alerts from tests.fixtures.client import client, test_app # noqa +def test_get_alerts_data_for_incident(db_session, create_alert): + for i in range(100): + create_alert( + f"alert-test-{i % 10}", + AlertStatus.FIRING, + datetime.utcnow(), + { + "source": [f"source_{i % 10}"], + "service": f"service_{i % 10}", + } + ) + + alerts = db_session.query(Alert).all() + + unique_fingerprints = db_session.query(func.count(distinct(Alert.fingerprint))).scalar() -def test_get_alerts_data_for_incident(db_session, setup_stress_alerts_no_elastic): - alerts = setup_stress_alerts_no_elastic(100) assert 100 == db_session.query(func.count(Alert.id)).scalar() + assert 10 == unique_fingerprints data = get_alerts_data_for_incident([a.id for a in alerts]) - assert data["sources"] == set(["source_{}".format(i) for i in range(10)]) - assert data["services"] == set(["service_{}".format(i) for i in range(10)]) - assert data["count"] == 100 + assert data["sources"] == set([f"source_{i}" for i in range(10)]) + assert data["services"] == set([f"service_{i}" for i in range(10)]) + assert data["count"] == unique_fingerprints def test_add_remove_alert_to_incidents(db_session, setup_stress_alerts_no_elastic): alerts = setup_stress_alerts_no_elastic(100) + # Adding 10 non-unique fingerprints + alerts.extend(setup_stress_alerts_no_elastic(10)) incident = create_incident_from_dict( SINGLE_TENANT_UUID, {"user_generated_name": "test", "user_summary": "test"} ) @@ -53,7 +69,10 @@ def test_add_remove_alert_to_incidents(db_session, setup_stress_alerts_no_elasti incident = get_incident_by_id(SINGLE_TENANT_UUID, incident.id) - assert len(incident.alerts) == 100 + # 110 alerts + assert len(incident.alerts) == 110 + # But 100 unique fingerprints + assert incident.alerts_count == 100 assert sorted(incident.affected_services) == sorted( ["service_{}".format(i) for i in range(10)] @@ -66,6 +85,18 @@ def test_add_remove_alert_to_incidents(db_session, setup_stress_alerts_no_elasti service_0 = db_session.query(Alert.id).filter(service_field == "service_0").all() + # Testing unique fingerprints + more_alerts_with_same_fingerprints = setup_stress_alerts_no_elastic(10) + + add_alerts_to_incident_by_incident_id( + SINGLE_TENANT_UUID, incident.id, [a.id for a in more_alerts_with_same_fingerprints] + ) + + incident = get_incident_by_id(SINGLE_TENANT_UUID, incident.id) + + assert incident.alerts_count == 100 + assert db_session.query(func.count(AlertToIncident.alert_id)).scalar() == 120 + remove_alerts_to_incident_by_incident_id( SINGLE_TENANT_UUID, incident.id, @@ -76,7 +107,8 @@ def test_add_remove_alert_to_incidents(db_session, setup_stress_alerts_no_elasti incident = get_incident_by_id(SINGLE_TENANT_UUID, incident.id) - assert len(incident.alerts) == 99 + # 117 because we removed multiple alerts with service_0 + assert len(incident.alerts) == 117 assert "service_0" in incident.affected_services assert len(incident.affected_services) == 10 assert sorted(incident.affected_services) == sorted( @@ -92,11 +124,12 @@ def test_add_remove_alert_to_incidents(db_session, setup_stress_alerts_no_elasti incident_id=incident.id, tenant_id=incident.tenant_id, include_unlinked=True - )[0]) == 100 + )[0]) == 120 incident = get_incident_by_id(SINGLE_TENANT_UUID, incident.id) - assert len(incident.alerts) == 90 + # 108 because we removed multiple alert with same fingerprints + assert len(incident.alerts) == 108 assert "service_0" not in incident.affected_services assert len(incident.affected_services) == 9 assert sorted(incident.affected_services) == sorted( @@ -117,7 +150,7 @@ def test_add_remove_alert_to_incidents(db_session, setup_stress_alerts_no_elasti incident = get_incident_by_id(SINGLE_TENANT_UUID, incident.id) - assert len(incident.alerts) == 89 + assert len(incident.alerts) == 105 assert "source_1" in incident.sources # source_0 was removed together with service_0 assert len(incident.sources) == 9 @@ -137,6 +170,8 @@ def test_add_remove_alert_to_incidents(db_session, setup_stress_alerts_no_elasti ) + + def test_get_last_incidents(db_session, create_alert): severity_cycle = cycle([s.order for s in IncidentSeverity]) From 3f24f578a406b69c05d136878b2a632013d2fab6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 29 Oct 2024 09:09:03 +0000 Subject: [PATCH 04/11] chore(deps): bump mysql-connector-python from 8.4.0 to 9.1.0 (#2296) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Tal --- poetry.lock | 67 +++++++++++++++++++++++++------------------------- pyproject.toml | 2 +- 2 files changed, 35 insertions(+), 34 deletions(-) diff --git a/poetry.lock b/poetry.lock index 563eb33e4..6e253ac55 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2541,44 +2541,45 @@ files = [ [[package]] name = "mysql-connector-python" -version = "8.4.0" -description = "MySQL driver written in Python" +version = "9.1.0" +description = "A self-contained Python driver for communicating with MySQL servers, using an API that is compliant with the Python Database API Specification v2.0 (PEP 249)." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "mysql-connector-python-8.4.0.tar.gz", hash = "sha256:42542d131d63c78416d410fdc9e84b9acb960d715c2e7b28c57ac9577c6d8165"}, - {file = "mysql_connector_python-8.4.0-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:c0a2688d95d53cfbea9352ed61926b47bc9042570570fb8fe0a8d19b1e20f1c4"}, - {file = "mysql_connector_python-8.4.0-cp310-cp310-macosx_13_0_x86_64.whl", hash = "sha256:276bae0d5d44abb7ba1205003b55628e4e6f1d399f1825d518bc607320997b1f"}, - {file = "mysql_connector_python-8.4.0-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:a6d24ea29b3c2bdbba6861590de557665420bfb938f74b5cecc630bac5457d35"}, - {file = "mysql_connector_python-8.4.0-cp310-cp310-manylinux_2_17_x86_64.whl", hash = "sha256:b7876358d9e51f25edc492088c4ce16cd14c2db87c279a965b0f9c327723359c"}, - {file = "mysql_connector_python-8.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:085024bf12d15f9b428938fdbeb50bd9b15dda9c4d3a474e6df061cb08713e6a"}, - {file = "mysql_connector_python-8.4.0-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:4e83fc8ed95005b171ffa36a289dac48625048263b09b56718e8395539ea07d9"}, - {file = "mysql_connector_python-8.4.0-cp311-cp311-macosx_13_0_x86_64.whl", hash = "sha256:cd89d1c8c2d1e33e5ac2d4eac5813422c150a8427fb60a16c59be18c29dd9a94"}, - {file = "mysql_connector_python-8.4.0-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:76c13fde35a038afe50550a9af7b31b28ca3a04cce06f3030980afb20460d28c"}, - {file = "mysql_connector_python-8.4.0-cp311-cp311-manylinux_2_17_x86_64.whl", hash = "sha256:accf10425c6af39a9595a47e7119ebcbcd7351f7df28755dbee01bca5a605b7c"}, - {file = "mysql_connector_python-8.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cda868bb4e1641362d148f5b0d2a86188cffa2f7188831589781b13f2df6f51a"}, - {file = "mysql_connector_python-8.4.0-cp312-cp312-macosx_13_0_arm64.whl", hash = "sha256:3ae951f2e16d089975cb9f05b3f3e58807dc33a2e5a627047bba1c8ad5439d82"}, - {file = "mysql_connector_python-8.4.0-cp312-cp312-macosx_13_0_x86_64.whl", hash = "sha256:af40b5bdd91547d3dbf5fa62bde37e9e840bd7cba3b9246b55c09e6a1cde536f"}, - {file = "mysql_connector_python-8.4.0-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:bb4f3edab78f3fd6f80c6c0a9e5a533704044fc01bfb9e8736e1a993f74aa42d"}, - {file = "mysql_connector_python-8.4.0-cp312-cp312-manylinux_2_17_x86_64.whl", hash = "sha256:e549674c72b596a7386f4a76bbac2ee9581f6632e6713618a70468713b162964"}, - {file = "mysql_connector_python-8.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:aed505adc76b58282c76e6cbf3da195be0f84029a41f05c470be977481896074"}, - {file = "mysql_connector_python-8.4.0-cp38-cp38-macosx_13_0_x86_64.whl", hash = "sha256:d343a4a8133ae9561bd537fc8cdbcab74a0607a5f40698569010fa3c7d4a048f"}, - {file = "mysql_connector_python-8.4.0-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:74b1759d8bd9ccd4296dc2e5abe22ec7efbd1ad12a9032c2cb4d17fa5d0ca6e0"}, - {file = "mysql_connector_python-8.4.0-cp38-cp38-manylinux_2_17_x86_64.whl", hash = "sha256:e6d5a418ef124dd1b18a73fd89431a1862ce7bf68f61275c7d006e8e2f8afcd2"}, - {file = "mysql_connector_python-8.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:427a84027b8314c73f5ff3eb1abdc709a8201b44a491d7b580bdf430b4820a16"}, - {file = "mysql_connector_python-8.4.0-cp39-cp39-macosx_13_0_arm64.whl", hash = "sha256:44a99d44a925ea29c2e423e6d8b1d97ce740c3078d8b41923a81bbcd0a821972"}, - {file = "mysql_connector_python-8.4.0-cp39-cp39-macosx_13_0_x86_64.whl", hash = "sha256:ed276c4e7907da0ad95a9ad122004294d6fb425127064af2ae880033b8e72166"}, - {file = "mysql_connector_python-8.4.0-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:2b5c6fea6513cf208c7116a4a5e36b3ae54e0d37f324a7cfe43fb01cfdf03be6"}, - {file = "mysql_connector_python-8.4.0-cp39-cp39-manylinux_2_17_x86_64.whl", hash = "sha256:651c7824af57eb50f4a79ea04bf6f453b24381e1bb56eee45c0035b4c0c624c0"}, - {file = "mysql_connector_python-8.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:655dccbdc0e2943e62cf69e10a024329248b17b58bfac59c60fd2103db3ba0b0"}, - {file = "mysql_connector_python-8.4.0-py2.py3-none-any.whl", hash = "sha256:35939c4ff28f395a5550bae67bafa4d1658ea72ea3206f457fff64a0fbec17e4"}, + {file = "mysql-connector-python-9.1.0.tar.gz", hash = "sha256:346261a2aeb743a39cf66ba8bde5e45931d313b76ce0946a69a6d1187ec7d279"}, + {file = "mysql_connector_python-9.1.0-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:dcdcf380d07b9ca6f18a95e9516a6185f2ab31a53d290d5e698e77e59c043c9e"}, + {file = "mysql_connector_python-9.1.0-cp310-cp310-macosx_13_0_x86_64.whl", hash = "sha256:948ef0c7da87901176d4320e0f40a3277ee06fe6f58ce151c1e60d8d50fdeaf4"}, + {file = "mysql_connector_python-9.1.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:abf16fc1155ebeba5558e5702dd7210d634ac8da484eca05a640b68a548dc7cf"}, + {file = "mysql_connector_python-9.1.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:aceaab679b852c0a2ec0eed9eb2a490171b3493484f1881b605cbf2f9c5fde6d"}, + {file = "mysql_connector_python-9.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:72dcce5f2e4f5910d65f02eb318c1e4622464da007a3ae5e9ccd64169d8efac3"}, + {file = "mysql_connector_python-9.1.0-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:9b23a8e2acee91b5120febe00c53e7f472b9b6d49618e39fa1af86cdc1f0ade8"}, + {file = "mysql_connector_python-9.1.0-cp311-cp311-macosx_13_0_x86_64.whl", hash = "sha256:e15153cb8ab5fcec00b99077de536489d22d4809fc28f633850398fef0560b1f"}, + {file = "mysql_connector_python-9.1.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:fec943d333851c4b5e57cd0b04dde36e6817f0d4d62b2a58ce028a82be444866"}, + {file = "mysql_connector_python-9.1.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:c36a9b9ebf9587aaa5d7928468fefe8faf6fc993a03cb242bb160ede9cf75b2d"}, + {file = "mysql_connector_python-9.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:7b2eb48518b8c2bc9636883d264b291e5c93824fc6b61823ca9cf396a09474ad"}, + {file = "mysql_connector_python-9.1.0-cp312-cp312-macosx_13_0_arm64.whl", hash = "sha256:f67b22e3eaf5b03ffac97232d3dd67b56abcacad907ad4391c847bad5ba58f0e"}, + {file = "mysql_connector_python-9.1.0-cp312-cp312-macosx_13_0_x86_64.whl", hash = "sha256:c75f674a52b8820c90d466183b2bb59f89bcf09d17ebe9b391313d89565c8896"}, + {file = "mysql_connector_python-9.1.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:e75ecb3df2c2cbe4d92d5dd58a318fa708edebc0fa2d850fc2a9d42481dbb808"}, + {file = "mysql_connector_python-9.1.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:7d99c0a841a2c2a0e4d5b28376c1bfac794ec3821b66eb6fa2f7702cec820ee8"}, + {file = "mysql_connector_python-9.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:30a8f0ba84f8adf15a4877e80b3f97f786ce35616d918b9310578a2bd22952d5"}, + {file = "mysql_connector_python-9.1.0-cp313-cp313-macosx_13_0_arm64.whl", hash = "sha256:d627ebafc0327b935d8783454e7a4b5c32324ed39a2a1589239490ab850bf7d7"}, + {file = "mysql_connector_python-9.1.0-cp313-cp313-macosx_13_0_x86_64.whl", hash = "sha256:e26a08a9500407fa8f4a6504f7077d1312bec4fa52cb0a58c1ad324ca1f3eeaa"}, + {file = "mysql_connector_python-9.1.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:109e17a4ada1442e3881a51e2bbabcb336ad229a619ac61e9ad24bd6b9b117bd"}, + {file = "mysql_connector_python-9.1.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:4f102452c64332b7e042fa37b84d4f15332bd639e479d15035f2a005fb9fbb34"}, + {file = "mysql_connector_python-9.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:25e261f3260ec798c48cb910862a299e565548a1b5421dec84315ddbc9ef28c4"}, + {file = "mysql_connector_python-9.1.0-cp39-cp39-macosx_13_0_arm64.whl", hash = "sha256:ec4386b2426bfb07f83455bf895d8a7e2d6c067343ac05be5511083ca2424991"}, + {file = "mysql_connector_python-9.1.0-cp39-cp39-macosx_13_0_x86_64.whl", hash = "sha256:28fd99ee464ac3b02d1e2a71a63ca4f25c6110e4414a46a5b64631e6d2096899"}, + {file = "mysql_connector_python-9.1.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:e2f0876e1efd76e05853cb0a623dba2746ee70686c043019d811737dd5c3d871"}, + {file = "mysql_connector_python-9.1.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:6d7d5d458d0d600bbbebd9f2bce551e386b359bcce6026f7369b57922d26f13a"}, + {file = "mysql_connector_python-9.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:c350b1aaf257b1b778f44b8bfaeda07751f55e150f5a7464342f36e4aac8e805"}, + {file = "mysql_connector_python-9.1.0-py2.py3-none-any.whl", hash = "sha256:dacf1aa84dc7dd8ae908626c3ae50fce956d0105130c7465fd248a4f035d50b1"}, ] [package.extras] -dns-srv = ["dnspython (>=1.16.0,<=2.3.0)"] +dns-srv = ["dnspython (==2.6.1)"] fido2 = ["fido2 (==1.1.2)"] -gssapi = ["gssapi (>=1.6.9,<=1.8.2)"] -opentelemetry = ["Deprecated (>=1.2.6)", "typing-extensions (>=3.7.4)", "zipp (>=0.5)"] +gssapi = ["gssapi (==1.8.3)"] +telemetry = ["opentelemetry-api (==1.18.0)", "opentelemetry-exporter-otlp-proto-http (==1.18.0)", "opentelemetry-sdk (==1.18.0)"] [[package]] name = "ndg-httpsclient" @@ -5298,4 +5299,4 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", [metadata] lock-version = "2.0" python-versions = ">=3.11,<3.12" -content-hash = "a94488bcf0d635773f1dc9d235a623e6818ed8f7681f4128a7e214c4304e005a" +content-hash = "ca7f650988117bd132b35001a4e3fa4c46e08d76ef0e2545fb481cacb8e2c1c5" diff --git a/pyproject.toml b/pyproject.toml index 6d44fbede..329a61b2e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,7 +19,7 @@ pygithub = "^1.57" sentry-sdk = "^1.15.0" pydantic = "^1.10.4" datefinder = "^0.7.3" -mysql-connector-python = "^8.0.32" +mysql-connector-python = "^9.1.0" logmine = "^0.4.1" astunparse = "^1.6.3" python-json-logger = "^2.0.6" From a37ec4f29685d8325e759817aec2c0de7925e0eb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 29 Oct 2024 09:15:18 +0000 Subject: [PATCH 05/11] chore(deps): bump snowflake-connector-python from 3.12.1 to 3.12.3 (#2329) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- poetry.lock | 56 +++++++++++++++++++++++++------------------------- pyproject.toml | 2 +- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/poetry.lock b/poetry.lock index 6e253ac55..1a4527b81 100644 --- a/poetry.lock +++ b/poetry.lock @@ -4589,37 +4589,37 @@ files = [ [[package]] name = "snowflake-connector-python" -version = "3.12.1" +version = "3.12.3" description = "Snowflake Connector for Python" optional = false python-versions = ">=3.8" files = [ - {file = "snowflake_connector_python-3.12.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c0979324bd96019f500f6c987d4720c9e4d7176df54b1b5aa96875be8c8ff57b"}, - {file = "snowflake_connector_python-3.12.1-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:c889a85966ec6a3384799e594e97301a4be0705d7763a5177104866b75383d8c"}, - {file = "snowflake_connector_python-3.12.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4bfb5fe8db051771480059ffddd5127653f4ac1168c76293655da33c2a2904d7"}, - {file = "snowflake_connector_python-3.12.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1061af4a3a3e66b0c99ab0f8bae5eda28e6324618143b3f5b2d81d1649b8557"}, - {file = "snowflake_connector_python-3.12.1-cp310-cp310-win_amd64.whl", hash = "sha256:3edcf3591b6071ddb02413a0000dea42ee6fe811693d176915edb8687b03ce89"}, - {file = "snowflake_connector_python-3.12.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:226a714eb68bbae328fe49b705ecb304fbd44ea6a7afbb329ba3c389ac9111bc"}, - {file = "snowflake_connector_python-3.12.1-cp311-cp311-macosx_11_0_x86_64.whl", hash = "sha256:7319f63c09efed853d7652cbb38ecc23068e86dbce8340444056787993a854d9"}, - {file = "snowflake_connector_python-3.12.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f86b42a076e14900dc6af2f096343ccf4314d324e7e1153b667d6ee53c60334b"}, - {file = "snowflake_connector_python-3.12.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d231f0d5fb8d7a96b9ab5e9500035bd9f259c80d4b3c482163d156928fb0e546"}, - {file = "snowflake_connector_python-3.12.1-cp311-cp311-win_amd64.whl", hash = "sha256:d9f1bc6b35344b170e2fb30314aa64709b28539084be88e95aacf094e13259eb"}, - {file = "snowflake_connector_python-3.12.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0114370c274ed64fe4aee2333b01e9ff88272837bdaa65fb3a3ee4820dca61b4"}, - {file = "snowflake_connector_python-3.12.1-cp312-cp312-macosx_11_0_x86_64.whl", hash = "sha256:dadd262196cce0132ca7e766f055e00c00497a88fdf83fd48143eb4a469a4527"}, - {file = "snowflake_connector_python-3.12.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473642c0e628b8b9f264cbf31c7f4de44974373db43052b6542a66e751159caf"}, - {file = "snowflake_connector_python-3.12.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bddc4cdcd991f9538726a7c293d2637bb5aed43db68246e06c92c49a6df2b692"}, - {file = "snowflake_connector_python-3.12.1-cp312-cp312-win_amd64.whl", hash = "sha256:b06c63ec0381df1f4da6c4326330a1a40c8fc21fd3dcc2f58df4de395d676893"}, - {file = "snowflake_connector_python-3.12.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3c24119ad64c20a8a691760c81e7d846feea4a6103ba84470116c60f7f31a1b8"}, - {file = "snowflake_connector_python-3.12.1-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:a8ba32c91ebf4de6d3f981cfd6324fb4b833696b639c350f5e5984371957e6f9"}, - {file = "snowflake_connector_python-3.12.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cde5643d8237fc109fed68c6a806297ebe3adeb56ac6865430a78fcaba27f2ef"}, - {file = "snowflake_connector_python-3.12.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a4bc4212db73feab5a79ad28b1d03743cbe48df1e346d219747afde5425c35d"}, - {file = "snowflake_connector_python-3.12.1-cp38-cp38-win_amd64.whl", hash = "sha256:7e5d7a0f1b827304b3ba250fa98c25385a7158ea5333e7857cda2ea91433a354"}, - {file = "snowflake_connector_python-3.12.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a56f9df9db2b03caf9bc7a45f51d7cdfe307b5e2cde7edaa93b67c2d81789db6"}, - {file = "snowflake_connector_python-3.12.1-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:a1ead374d96cf21cb249bf91fe814ab1e1baaa3c3f2391116ccefab8bfa36374"}, - {file = "snowflake_connector_python-3.12.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38698260175321ddef5504170ac1f9e5e92b897844d55ac2fc77bf0783435299"}, - {file = "snowflake_connector_python-3.12.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7f8699ff60924105253e465a54ad150469ddf65082ce029387d65ca404a46cc"}, - {file = "snowflake_connector_python-3.12.1-cp39-cp39-win_amd64.whl", hash = "sha256:93e79497ae0f0be1a10cf2649900db0011e391ede47cbef2803814c32e1d63d6"}, - {file = "snowflake_connector_python-3.12.1.tar.gz", hash = "sha256:e43b7d4b4488ecd97b5bf62539cc502d7e84d8215c547eaeb4dd928c0b7212b9"}, + {file = "snowflake_connector_python-3.12.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:497a096fc379ef0846b2f1cf11a8d7620f0d090f08a77d9e93473845014d57d1"}, + {file = "snowflake_connector_python-3.12.3-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:055c5808d524497213e4cc9ae91ec3e46cb8342b314e78bc3e139d733dc16741"}, + {file = "snowflake_connector_python-3.12.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a5dc512d62ef693041ed2ad82931231caddc16e14ffc2842da3e3dd4240b83d"}, + {file = "snowflake_connector_python-3.12.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a46448f7279d444084eb84a9cddea67662e80ccfaddf41713b9e9aab2b1242e9"}, + {file = "snowflake_connector_python-3.12.3-cp310-cp310-win_amd64.whl", hash = "sha256:821b774b77129ce9f03729456ac1f21d69fedb50e5ce957178131c7bb3d8279f"}, + {file = "snowflake_connector_python-3.12.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:82290134978d11628026b447052219ce8d880e36937204f1f0332dfc3f2e92e9"}, + {file = "snowflake_connector_python-3.12.3-cp311-cp311-macosx_11_0_x86_64.whl", hash = "sha256:20b5c8000ee9cee11b0f9a6ae26640f0d498ce77f7e2ec649a2f0d306523792d"}, + {file = "snowflake_connector_python-3.12.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca6500d16bdbd37da88e589cc3e82b90272471d3aabfe4a79ec1cf4696675acf"}, + {file = "snowflake_connector_python-3.12.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b455ba117a68da436e253899674fae1a93669eaefdde8a903c03eb65b7e87c86"}, + {file = "snowflake_connector_python-3.12.3-cp311-cp311-win_amd64.whl", hash = "sha256:205219fcaeee2d33db5d0d023d60518e3bd8272ce1679be2199d7f362d255054"}, + {file = "snowflake_connector_python-3.12.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3d830ca32c864b730cba5d92900d850752199635c4fb0ae0a70ee677f62aee70"}, + {file = "snowflake_connector_python-3.12.3-cp312-cp312-macosx_11_0_x86_64.whl", hash = "sha256:597b0c74ec57ba693191ae2de8db9536e349ee32cab152df657473e498b6fd87"}, + {file = "snowflake_connector_python-3.12.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2215d8a4c5e25ea0d2183fe693c3fdf058cd6035e5c84710d532dc04ab4ffd31"}, + {file = "snowflake_connector_python-3.12.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8ba9c261904c1ba7cae6035c7881224cf979da39c8b7c7cb10236fdfc57e505"}, + {file = "snowflake_connector_python-3.12.3-cp312-cp312-win_amd64.whl", hash = "sha256:f0d0fcb948ef0812ab162ec9767622f345554043a07439c0c1a9474c86772320"}, + {file = "snowflake_connector_python-3.12.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:fe742a0b2fb1c79a21e95b97c49a05783bc00314d1184d227c5fe5b57688af12"}, + {file = "snowflake_connector_python-3.12.3-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:a8584a44a6bb41d2056cf1b833e629c76e28c5303d2c875c1a23bda46a1cd43a"}, + {file = "snowflake_connector_python-3.12.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd990db8e4886c32ba5c63758e8dc4814e2e75f5fd3fe79d43f7e5ee0fc46793"}, + {file = "snowflake_connector_python-3.12.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4fe7f91f6e44bda877e77403a586d7487ca2c52dc1a32a705b2fea33f9c763a"}, + {file = "snowflake_connector_python-3.12.3-cp38-cp38-win_amd64.whl", hash = "sha256:4994e95eff593dc44c28243ef0ae8d27b8b1aeb96dd64cbcea5bcf0e4dfb77fb"}, + {file = "snowflake_connector_python-3.12.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ac33a7dd54b35f94c4b91369971dbd6467a914dff4b01c46e77e7e6901d7eca4"}, + {file = "snowflake_connector_python-3.12.3-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:a26876322811fe2b93f6d814dcfe016f1df680a12624026ecf57a6bcdf20f969"}, + {file = "snowflake_connector_python-3.12.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c0bb390be2e15b6b7cccab7fbe1ef94e1e9ab13790c974aa44761298cdc2641"}, + {file = "snowflake_connector_python-3.12.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7340f73af4ae72e6af8fe28a1b8e196a0c99943071afc96ce419efb4da80035"}, + {file = "snowflake_connector_python-3.12.3-cp39-cp39-win_amd64.whl", hash = "sha256:c314749bd0151218b654a7d4646a39067ab650bdc86dfebb1884b056b0bdb4b4"}, + {file = "snowflake_connector_python-3.12.3.tar.gz", hash = "sha256:02873c7f7a3b10322e28dddc2be6907f8ab8ecad93d6d6af14c77c2f53091b88"}, ] [package.dependencies] @@ -5299,4 +5299,4 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", [metadata] lock-version = "2.0" python-versions = ">=3.11,<3.12" -content-hash = "ca7f650988117bd132b35001a4e3fa4c46e08d76ef0e2545fb481cacb8e2c1c5" +content-hash = "c021924b92984309ec0904f525c5287b51ff74b2a51017a48c714f85b802f92e" diff --git a/pyproject.toml b/pyproject.toml index 329a61b2e..bfbb2421d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -41,7 +41,7 @@ google-cloud-secret-manager = "^2.16.1" python-jose = "^3.3.0" jwcrypto = "^1.5.6" sqlalchemy = "1.4.41" -snowflake-connector-python = "3.12.1" +snowflake-connector-python = "3.12.3" openai = "1.37.1" opentelemetry-sdk = ">=1.20.0,<1.22" opentelemetry-instrumentation-fastapi = "^0.41b0" From f9358bea286529649992dc0aa802ade8e814fd3e Mon Sep 17 00:00:00 2001 From: Shahar Glazner Date: Tue, 29 Oct 2024 11:29:49 +0200 Subject: [PATCH 06/11] fix(workflows): email template (#2328) --- keep/api/routes/workflows.py | 2 +- keep/iohandler/iohandler.py | 5 +++-- pyproject.toml | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/keep/api/routes/workflows.py b/keep/api/routes/workflows.py index d4acac775..ae8a837e0 100644 --- a/keep/api/routes/workflows.py +++ b/keep/api/routes/workflows.py @@ -187,7 +187,7 @@ def run_workflow( else: event_class = IncidentDto - event_body = body.get("body", {}) + event_body = body.get("body", {}) or body # if its event that was triggered by the UI with the Modal if "test-workflow" in event_body.get("fingerprint", "") or not body: diff --git a/keep/iohandler/iohandler.py b/keep/iohandler/iohandler.py index 244ad561f..ea7467582 100644 --- a/keep/iohandler/iohandler.py +++ b/keep/iohandler/iohandler.py @@ -1,5 +1,6 @@ import ast import copy +import html # TODO: fix this! It screws up the eval statement if these are not imported import inspect @@ -311,8 +312,6 @@ def _parse(self, tree): # this is happens when libraries such as datadog api client # HTML escapes the string and then ast.parse fails () # https://github.com/keephq/keep/issues/137 - import html - try: unescaped_token = html.unescape( token.replace("\r\n", "").replace("\n", "") @@ -376,6 +375,8 @@ def _render(self, key: str, safe=False, default=""): return default if const_rendering: + # https://github.com/keephq/keep/issues/2326 + rendered = html.unescape(rendered) return self._render(rendered, safe, default) return rendered diff --git a/pyproject.toml b/pyproject.toml index bfbb2421d..758f57d9e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "keep" -version = "0.27.6" +version = "0.27.7" description = "Alerting. for developers, by developers." authors = ["Keep Alerting LTD"] readme = "README.md" From ab8c6ff2c34c691952ced03f1aa2a46caa3c384c Mon Sep 17 00:00:00 2001 From: Jay Kumar <70096901+35C4n0r@users.noreply.github.com> Date: Tue, 29 Oct 2024 15:40:17 +0530 Subject: [PATCH 07/11] feat: add Graylog Provider (#2305) Signed-off-by: 35C4n0r Co-authored-by: Shahar Glazner Co-authored-by: Tal --- README.md | 2 + docs/mint.json | 1 + .../documentation/graylog-provider.mdx | 59 ++ docs/providers/overview.mdx | 8 + keep-ui/public/icons/graylog-icon.png | Bin 0 -> 9285 bytes keep/providers/graylog_provider/README.md | 132 ++++ keep/providers/graylog_provider/__init__.py | 0 .../providers/graylog_provider/alerts_mock.py | 37 + .../graylog_provider/docker-compose.yml | 102 +++ .../graylog_provider/graylog_provider.py | 646 ++++++++++++++++++ 10 files changed, 987 insertions(+) create mode 100644 docs/providers/documentation/graylog-provider.mdx create mode 100644 keep-ui/public/icons/graylog-icon.png create mode 100644 keep/providers/graylog_provider/README.md create mode 100644 keep/providers/graylog_provider/__init__.py create mode 100644 keep/providers/graylog_provider/alerts_mock.py create mode 100644 keep/providers/graylog_provider/docker-compose.yml create mode 100644 keep/providers/graylog_provider/graylog_provider.py diff --git a/README.md b/README.md index a9864afe0..39bb76779 100644 --- a/README.md +++ b/README.md @@ -115,6 +115,8 @@ Workflow triggers can either be executed manually when an alert is activated or                       + +                       diff --git a/docs/mint.json b/docs/mint.json index 89f69ba23..d0bcdc482 100644 --- a/docs/mint.json +++ b/docs/mint.json @@ -140,6 +140,7 @@ "providers/documentation/grafana-provider", "providers/documentation/grafana_incident-provider", "providers/documentation/grafana_oncall-provider", + "providers/documentation/graylog-provider", "providers/documentation/http-provider", "providers/documentation/ilert-provider", "providers/documentation/incidentio-provider", diff --git a/docs/providers/documentation/graylog-provider.mdx b/docs/providers/documentation/graylog-provider.mdx new file mode 100644 index 000000000..9f6d9a160 --- /dev/null +++ b/docs/providers/documentation/graylog-provider.mdx @@ -0,0 +1,59 @@ +--- +title: "Graylog Provider" +sidebarTitle: "Graylog Provider" +description: "The Graylog provider enables webhook installations for receiving alerts in Keep" +--- + +## Overview + +The **Graylog Provider** facilitates receiving alerts from Graylog by setting up Webhook connections. It allows seamless integration with Graylog to receive notifications about events and alerts through Keep. + +## Authentication Parameters + +- **Username** (required): Username for authenticating with Graylog's API. +- **Graylog Access Token** (required): Access token for authenticating with Graylog's API. +- **Deployment Url** (required): Deployment URL for connecting to the Graylog instance (e.g., `http://localhost:9000`). + +## Scopes + +- **authenticated**: Mandatory for all operations, ensures the user is authenticated. +- **authorized**: Mandatory for querying incidents and managing resources, ensures the user has `Admin` privileges. + +## Connecting with the Provider + +1. Obtain the **username** and **access token** from your Graylog instance by following [Graylog's API Access Documentation](https://go2docs.graylog.org/current/setting_up_graylog/rest_api_access_tokens.htm?tocpath=Set%20up%20Graylog%7CGet%20Started%20with%20Graylog%7CREST%C2%A0API%7C_____3#CreateanAccessToken). +2. Set the **deployment URL** to your Graylog instance's base URL (e.g., `http://127.0.0.1:9000`). +3. Ensure the user has the **Admin** role in Graylog. + +## Features + +The **Graylog Provider** supports the following key features: + +- **Webhook Setup**: Configures webhooks to send alerts to Keep. +- **Alerts Retrieval**: Fetches and formats alerts from Graylog based on specified search parameters (only a maximum of 10000 most recent alerts) + +## Inputs for Query +- **events_search_parameters**: Takes in a python dict +Example: +``` +{ + "filter": {"alerts": "only"}, + "page": 1, + "per_page": 1000, + "query": "", + "timerange": {"range": 86400, "type": "relative"}, +} +``` +- You can modify this to fetch either alerts, events or both. + +--- + +**Note**: Ensure that the product of `page` and `per_page` does not exceed 10,000. + +--- + +## Useful Links + +- [Graylog API Documentation](https://go2docs.graylog.org/current/what_is_graylog/what_is_graylog.htm?tocpath=What%20Is%20Graylog%253F%7C_____0) +- [Graylog Access Token](https://go2docs.graylog.org/current/setting_up_graylog/rest_api_access_tokens.htm?tocpath=Set%20up%20Graylog%7CGet%20Started%20with%20Graylog%7CREST%C2%A0API%7C_____3#CreateanAccessToken) +- [Quick Setup for Graylog & Integration with Keep](https://github.com/keephq/keep/keep/providers/graylog_provider/README.md) diff --git a/docs/providers/overview.mdx b/docs/providers/overview.mdx index 088806517..c6ae298c0 100644 --- a/docs/providers/overview.mdx +++ b/docs/providers/overview.mdx @@ -268,6 +268,14 @@ By leveraging Keep Providers, users are able to deeply integrate Keep with the t } > + + } +> + qpiM=E6r!REc|%2YNP$9Dsi=I!si@YiDXfoFR2&|e4f=8v zhn$|4kt(IV*mm~6J~z709uJ=-FQ2vUoUQHdpPilAPM#Hi{TdP!WNK{O)71rj^hn?) zU)i_{l%l8gHqbGo;#Kp?`L%hYBbb6*u+>yoVGOO-x1$(z-p{mE=~n5v=x#Fk*nHHW zK)1bBO}*`HyrHsoUQkLy^-%nwgxCXdv4>Jd;$Yc_GO`aJii(TNiiwFZA^tnbE=H>=<_okwZ zHJ=^K9S-&KhT8KXoV*?R9KF3gUdw_&P~LgHxL49>mlY16Z3F?WnN0^qQqc1 zk6{RN@J85pL8<aU*lo2SS8Z>}j_{{OugJn}~(kwHO0e%V(seZR|_j*oeFNeTf$ zgwv{YGX8m&PNg|Eo4)4#)82v62TlX7UnkbyVec%Wcn#aXTreNQak|B@8Mdj!2|p;u zw%I0CkVS8&`y!okrwp$&4ZgYZ3kTy6^YOROh*)d+@@~S=ya|i4HWN?pDphS3W8Zpo zNsHd|*7WC)wdN&eru~eM+)zdu{ z!~0~-y>=tYRY3H^At_z_`edMVlh4mTG7(Ofm-BIIFY-F{$De}YpWgz==#MNaW)ARky%fMI&F!I5;+?&v0Y~&80 z<Gs-~BzjUiZBn4s6bxXc5jFc|Nza!W=pCko|2V!FpUQ zY6#D!#W-RO-%{T5Po)=s{4az@8SsZkuK6j7mRnfYlPm5%fC zt>X1b@rSD|KeRt^rcCb8;;amrGpATRfj4T`1N{B{gM+P5n-!C%VIbZU z<)3^LK9|DZDjdgr9C}KpE7oRP=`(qE2omE|Am%K-WB$~Infx;=^5Gxp;mdb3bM%0InhYy zwA*sM$;F@}Q%*DS@N&jTPlS`;GWwx`-a zzgQtb(H%v#|F*1ua2(cLzQ#SpH|c^{)BQnrQoC=J;6{Z~uW|cTgIkrK{B2cI_o;L8 z#JBpzZ#%-1$sk?dzS4wR^O^`Z(HFngQN<@!-bMKZ@IcDSA(&5s5FH~CuYiFn@>w@#MDKyx+FI{Yz$HF69?r;3P z_Zf-y?rU>=M7r8gbC-CSn)hnG*PsZOba8zCwnvuxK%omO;4LF!Fq$dr1rxn0wP0J| z3wqv?iRHmUJqeEo+m|CER6nGKA6InNn}-B!kvtr)^Ww&nQu%oU(7?&|sG8G_;xU2X zCRBBvc7Un5nWg~C!a7NG@A*|1i_5x7NLQlsh>(1#r%^`q-*Mc~Amv^kos#_I_C)`n z)b-QO${CbmgZJv~y&hV~3wxhZ`;Mt+e^LRM(i_gqPx1(=e^T9i{XXU0v?0R>_j;r- zqm<_ax%(3`)ZCjQ&6ghmJDlU2eCH{7L9m3d6qxSlmm$A^skFv<4R09!n; z_q^7AwCviub!~3{+vX3QO&Fh%S4h1y%G5QY(YeSGTDq1&MN+Il5#dYAQ*jABbnE33 zFx2CkD_4=F=hA4#&YJ`a$2lF-3qQ0yTj%)Lx!4(q`!ct~esk|!qN^NKoE>|rgIx;? zpH8QBHi=0cpNX}9#l56Ny{TQqk9Z_v;*mrT7%dapG+5AP<8G(mSH20rze*c=Bpqh! zp?jj`2U^TLy)=w57CJ?OHKiJcd(X99Fe1}b#jW>x`-CJ=`e^NI2C#SO+Ky&+LxZ#w zxT8;q>>=!2$7~RhUbA)U+9#Z;goJXDmxg%tl^G6)p}}i;J^ZHy^yyCVUp>tPyw!w{ z`-BWr#ENDLFJ}$KKt6PHf}(0VyBOVCP$q>!ixoKT^gJ=RrO=Mp9K4k(c^n-rR~^F% zqAtJmuo7HB?isab#0Yh@6Y6oIRXNseF6~io_9JJEqR%Ne1S-KLXA=lT+i9ep5}+^>cE) z2-fX5A}Q=Yr-^dJiCSasD7PJIp|fbBtS!q!whI{nUtdxrJ3WX}@|4_2zy zaj{DVN0S#2F{so7PG5^&vlJ94QCUqB>tVUlB&Hl5IQhv{Zilv#AbA(E?{-73tN_*R zz7eTh0I9#f`=lyQ{-y0APvUv01S4tQiMd_-n0SPbI{JYD$Q9c-kVYX8PTC#y*}IVQ z+7X+{04+dVd#Atf4m<^EndrJ&pElvE4sWY0<(M(@y*bf5nl$NqHiLKPEyizmMJBiu z$M5fk`r4U-J|RyMT<73oHQNNSp2KI@AayBki|U|PMt=6^*|o6lSJlFb`Rlfy#A3`F zOPe}b^oZn7z(LRc!$AGzO}p)&v+7d;O)A53{CN?SxHe0q4rJB}ZN*Z5K*@ZIyYzc< zzA$&d3#_%XMnD3>Qty37C1lH@d|)~RTiDJaLi=0*#!9?2>*$h2xTppA5x+m=UN1}} ze*{vh-s{;)sOkc?BU|FyZ@#A9i`{|TAn3FEeKrNv7gfAim$Y{7nn__}gL;AF_QFSAVoXwd^CU)0aH@YQ z4c|lcmb7!Ygf=3n3kX+Lun;8>t6wz&;FAn~Lskk5PZ?w&MUH%pj7mm)zqFTw%wwxe z1Uz8z+eHA3RbO5sMjX=e=5fSgPE&X^+?L{#kh6op3C&&piIe&F)Yc=?Tq$lAzv|h%5CIqs zQMKpc)jW=a`QD(Yd^ng}h^(|Pj!KPFB^(nab43_zur11<@A(y{gm2-h1gc_=Zor-k zy*)(J>b>#JC`Nm%#!ClayGB}hhp!=&bdprarzyG_2 zNlUax?O|tU9a$g`VRH|%q*-^`_)X9Tvw`Bcf~}oYU6E8HC~Y6sLT>$?)N$>?q&?X= zWfK7&n}deWfo4qFnRVM@mwBQ4EG~{4R*^NHbV8}b5*PsHZbP==03p63Im>LZ=K*Ch z?20YzWil0ZVq@^<8Sw@fjftcuJM{4`kLAoMJrg6+esSG$6=Iowi>V3QbHzscQXmx! zZuT|wg#dcqY8zP#v9_&d1^uq^oYQ2bEXt4L_Y(i&;=pIhJ+}nQVZ=*t*R%!HS;@!; zfR}2zKT(w_ZNiDesi*1#0Gf<2{4i5U>S=ftq}CJCIP(BS;)|Qyc)V0 zE?wu#;NyELqj0?xKTk(@L0mM0`;WnOLpd#Bx!T47(GuNc69}P2hqPNwY5qM+`c$v zL+0sFnD{-W)o>*313o^Ibcx+J2fI;;N@bi>SZ&j5BJz<8yojI^U~jq6Xpc#M;2p@F zFHaa2-h1IcH3FaT?Te7N6^!qkMqY=V%-GB%e%9+wSpF8;s&HC8W)ie5>pjX4jdxHu zHfVY=G+O3s&&dJY`8~^`f3Wy^{a{!h_FWiErR%0QT9)RYY6k0fH$92No4~N_t_i6> zUreq$M%XzTIh;hBZ0e;O%w=t5>!QH{ zF>pLudC|fwa7B`9yrc9yhecj!}kAtN{|yns>^Kl}fKOLpv{w z!BIbP{$TI39KKLOgtn~h1`3n&xn4zzN$%lP&nQgj1gHGGR~fT<~hLP&MTp6i$3 zZH8w&*A~oc-P^ydU=Cr2;m^MQvoqQl$|thrjE5u^^5+0h9j`+1P@XoRfh{dp(1_%D4EPIyY#ueI0tzLg7`IMJNje4_A{l-L!9U->eY&B zWtqm%%ob=;A!6sqMivyi7wPtshls+010rh4cU{NBV(>E)k;W-OX9?t1^n9@bZOxWz zcvCe%TWRy(W2=KA?l~*tn9ky=^*$FtNYrn?jHO7>mM%zE``e*ikq2`T!Ox9pMcSLN zL-$tj?aT6Z_kSUUWM_-uO<}23OKNAYc!zeRD!i>}_2s78BCSK9A-gsvwk`@V;1$OP zef&3wad|+wY|*mW`(QfKI4&K4Tvb}T^st6w;m;4i(8KZ-W%W-*`-SA^YJ{3kqjRSUDG3C{;AI4CPjguw9PD(?{b&he%ffSum4r?>taVXa(| zIFDg1m&oBt{P@HRiiPfuIhg5^?`(7Joh3BoeB%AavT=afPyjeCyt)vmbLet7j8ssE zzU~|q7P}IVsUJ5$y}mXQViCkN2B2AH6Rg)hdK_$V+MK(Pzxd21>IahCFd6d4g?oM5`fFKn!L6d8sIU{c zjA+ZFg0sF@xRj9U#}11p+wy*9$@XB7a#Z-^rRiziK&B@EnXXiPu8^5bGQo_XOm+w! zDi>q-iyQeoE&i5$<)*gMJ_NiJ1XX>mcv_7Xc|oaS_`U#Sz;Yr@yK2jkC<<8|LBOVO6<9ESx?H8B$CUP@p@b5IW~(o>P@>#&F7F<$gEGBHgV>yQ`PQ_ zxRI3U7$(V=hc|Zm5kHxo(5M0QOQueSFZ55PYCpq9ESeGW8J&7cogqsCNk5hc=|F?fWdZl zYi)i9EDog1%qMA@?aHYrRC^g4IM0?tcPjzY7267jglC(qoZOtc$xPI?c+Z~Cw2KazzKFdF&}{=uYX?sREX(@6vsF5@3T{5_YP3gnNg&iiSP zpGaPw(QZl~H!(AI1-hX^wIV{F)SrQb>sDbhPimf;_|7;eI%Q-G(& z7Tmwkz)pkksBnOSV!5D}dl6;a(KbacTi5+srmrmrC~M<0C>q$0oY9aps7(o>8;9;T zfBzIAa?A=1ZU%VfPJ1*FvCJ{M8<8Jwz}x(DtL}BSsl&Ct6EMjf$nogU`L0w9SWmCE z_R)+wkv4a8Y#W;!`t`uHAy7l|&o^7iU_Bxs%?dK?9+U;`0uZXw)!T&4G z?HzeVtS9%8%r67#273mHD$2v;BnXl!^D`?awLo-olik9|h4Gm2`V}W^EnP3bv)1)` zDHx_7iNzBPs55~JrZCU-nJ@8}-0cQUfTR0mi7Ga$Vhu{CJ0)S3ZB!qD3*Vs~IN&S# zELvQOj26JdJ^FR?yc{`Uzmbv%&N*!7thmn_I$1?FN#1r4>uJvJv%-s0twbu~%+rw7 zYLG!+`9fN0@V%;+uw4A32)2LV(%#XK?6|k1X{n|#Tt4HU?trXFxr-~2_P7km9a~t{ z$ho`E0s9Qmmb;C74Dh4r1B9}(U81Z(w!0UEAmzmuFj47!$P_gKSPzr!4#^Iuqyyi* zX$Bk4XB;h?9i>WiO)mw%T2hV26YHg@USNj|H$9Cp&l-Sg@pz|hG~J zzgaI8vJyFm%aGs6?vCe>d^8bJIx+7Ug7xau9l$aGx3q^pamFDo#*U~OLR@X&yr{gYn>7Ih5nOlrqq()n*8f`00ASH=?Q*| zv;S4+LgzsQ7=4&wfpw}cH%q=`T|)py4&y9u?qV;#kA`ABgZ7?> zx>Q|ToMif!O8aTT{R<%=nIi`$_ayg^R6Uutq_?ai0|sWq+k3v{P%vkAazIm#(_$Y6 znC%8-|6!d*Qj;d6CImr^<_z{20m`&Hpta8ZauO;JAOj&)-$Z_aCWv|PvRC3r=p}>T4Iy zCBRkwmfU%T=}z)xz&6WfNHn=qW-;kn=p(?>coX~ny@u%P{v-U%zRE&`3!&GU@|e^e zl;^aRD+~c&HB3Qve+$~tVk$0m@+U$(uFQ&ANan0`S(EPZi6*RPMU(Ob58 z+$BU~F8=jv68l43@AwpVax;)}!qVk>m(xE(@Vc+vhHyf(>)r7^DK#~;{{D4!`%*-A z9_qG0C>XQ-d<^;)E0%l(lk8GOEs#Nf)5|fsD><_3DCWA#`a>qS{%gY<0-@(LBbXo| zqEEMZYOy4>$t%Kex5E|-^H$&eAv#U4l9LM(-Gv~1>V5c zWg}ja3f;RCqB|i3RFTTYpMwOZiBT+9t2Q`w$j1CzGY#mEAs(yj#1aOpZM} z>6kmBI_OH;_+eiVebtSzaervg9YIlU=aEw5H+hx>l|N9dgS`0oP0j_xbE$?$OjGyiSbNti2|n~Tli=3poPa#)yVZWV6h z&3~$f*CKyZ{8P1g@RW3Ou!tM-^5CXk`Y7b+K9`Q30jM9Lc$;K^RyU%r4&CTC>4p1) zx^?soVZT?tLD8cdS7du*d3Z9)Kat>8TiKsITK_1P6Kzv{wz3IjCvr;vUNXJ%o;c{? zmHi4=*Z)gk;&A7R;tkG&mk<6W{GtV;YG`U6$9Ap}1bLuz1#Vkcd2;5kQN#KFq99W4 zB{89z^ZMS{x;Vnq-^b(3hZ`cg4Q0ts4%Z`ROb$0J-(wNL!0Ww;0wCOK4SiM51U8w{ zDB9t$Pj|RM?ftbDvtx{~JaoUXPRP)2g!R0hqzbGHp(PwOXx*NrEz_J8`x3e@5Mo=L;Op z2$qspeZQh*(KRBRdxMCt`INtlVtwc9j7NFqvU1kG8^J0T*C)TiiYznJ)&nh7DreIQ zk9z!D#~kJ3?cY$XA;#{nZOm7zmN=C{HkaFu)Kda!YDASkx9-1*Fga-iuY2pxn*s7W zsz^%Ma?RjFo?2#7a6++VQei>c=G010Fd}=30Dt*tZoCN5b@l#X6gd35BB^I6!1c&@ zYo~uSWY!$PAnajuJ-_=#_k&Bo8(TenUWhH$bWV~co#6!_!+xq{xQI~8zCp9LKs)+} z#|=b5`pZkRkJ3umk53&wdg}V-!3!!G8=Dvl>y5VNP_y>|lNA}_8+QkTtRA%TRdwu; zNS4hJCgC$1&KAPM(CM+3C;uRo+!7Xo3u8yQW*m3s89OZ{Eof%V@1;$NKUn?eo;!ZJ zxS!~zXo~cl5FOvRyC5Vxy_DOHdJp<>K*Us9Pa7|HTY1+D(h@<|TyGiI>*JY*Z0sFF zHdn8)*D|_Av+{&Be{=5lsI2Is5w3}pE)Ae=dxjEw@=JCpB*pBtQmR8j`fGznAuFO6 z-0+t_f#}`vOrJosZg|#DF!}G6ug4Eww7TOj{0VT$CCP@aJiakm#w%T~9TxscRJuO3 zt$mKkAxh~Zr(EkFJ*w;BhU1Ur!hZkcZd>)g8fp1k{4k-lg2>ymFEpUV$UNtn_srpU4}0C4j`d?i&Ue+GR(Ge&AIL;FRmTDlvlmC^4C1Slg}oV`$3Mvi2F0@+NVl)8Lm#GmE0z! z%abzeZ6APVozn7e-yC1}660&)N%RQKyc8zSC=j{ UU!JABmqPVSRY#>v$vW&m0ES^KZ2$lO literal 0 HcmV?d00001 diff --git a/keep/providers/graylog_provider/README.md b/keep/providers/graylog_provider/README.md new file mode 100644 index 000000000..f1d327f7c --- /dev/null +++ b/keep/providers/graylog_provider/README.md @@ -0,0 +1,132 @@ +# Instructions for a quick setup + +## Setting up Graylog + +### Installation + +1. Spin up Graylog, [docs](https://go2docs.graylog.org/6-0/downloading_and_installing_graylog/docker_installation.htm) + ```bash + cd keep/providers/graylog_provider + docker compose up + ``` +2. Once the containers are up and running, go to [http://localhost:9000](http://localhost:9000) and sign in with + username `admin` & password `admin`. + +### Getting Access Token + +1. Navigate to System > Users and Teams to view the Users Overview page. +2. For the user `Admin`, select Edit tokens from the More drop-down menu. +3. Enter a token name, then click Create Token. + +### Setting up Inputs and Event Definition + + ```python +import requests + +auth = ("YOUR_ACCESS_TOKEN", "token") # from the previous step +headers = { + "Accept": "application/json", + "X-Requested-By": "Keep", + "Content-Type": "application/json", +} + +input_data = { + 'type': 'org.graylog2.inputs.raw.tcp.RawTCPInput', + 'configuration': { + 'bind_address': '0.0.0.0', + 'port': 5044, + 'recv_buffer_size': 1048576, + 'number_worker_threads': 3, + 'tls_cert_file': '', + 'tls_key_file': '', + 'tls_enable': False, + 'tls_key_password': '', + 'tls_client_auth': 'disabled', + 'tls_client_auth_cert_file': '', + 'tcp_keepalive': False, + 'use_null_delimiter': False, + 'max_message_size': 2097152, + 'override_source': None, + 'charset_name': 'UTF-8', + }, + 'title': 'Keep-Input', + 'global': True, +} + +input_response = requests.post( + url="http://127.0.0.1:9000/api/system/inputs", + headers=headers, + json=input_data, + auth=auth, +) + +print(input_response.text) + +event_data = { + 'title': 'Keep-Event', + 'description': 'This is an event for Keep', + 'priority': 3, + 'config': { + 'query': 'source:*', + 'query_parameters': [], + 'streams': [], + 'filters': [], + 'search_within_ms': 86400000, + 'execute_every_ms': 60000, + 'event_limit': 100, + 'group_by': [], + 'series': [], + 'conditions': {}, + 'type': 'aggregation-v1', + }, + 'field_spec': {}, + 'key_spec': [], + 'notification_settings': { + 'grace_period_ms': 300000, + 'backlog_size': None, + }, + 'notifications': [], + 'alert': True, +} + +event_response = requests.post( + url="http://127.0.0.1:9000/api/events/definitions", + headers=headers, + json=event_data, + auth=auth, +) + +print(event_response.text) + ``` + +### Sending a log + +1. After that you can send a plain text message to the Graylog raw/plaintext TCP input running on port 5555 using the + following command: + ```bash + echo 'First log message' | nc localhost 5555 + ``` + +## Setup Keep to receive from Graylog + +--- + +### **Note** + +1. Run without `NGROK` +2. After Step 2, do this: + - Go to Alerts > Notifications + - Click the `title` of the newly create notification > `Edit Notification` > Replace `0.0.0.0` with your ip + address > Click `Add to URL whitelist ` > Fill in the `Title` > `Update Configuration` > `Update Notification` + +--- + +1. Go to `Providers` > search for `Graylog` > + - Username: `admin` + - Graylog Access Token: Access tokens from previous steps + - Deployment Url: http://localhost:9000 + - Install webhook: True + +2. This will create a new notification and install that notification in the existing events. +3. Send a log to `Graylog`, this will trigger an alert. +4. Check your feed. \ No newline at end of file diff --git a/keep/providers/graylog_provider/__init__.py b/keep/providers/graylog_provider/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/keep/providers/graylog_provider/alerts_mock.py b/keep/providers/graylog_provider/alerts_mock.py new file mode 100644 index 000000000..ff3f0ebb7 --- /dev/null +++ b/keep/providers/graylog_provider/alerts_mock.py @@ -0,0 +1,37 @@ +ALERTS = { + "event_definition_id": "671a28a03696bb3801a7a9f1", + "event_definition_type": "aggregation-v1", + "event_definition_title": "Event - 1", + "event_definition_description": ".", + "job_definition_id": "671a97cc3696bb3801a846a6", + "job_trigger_id": "671a9dfe3696bb3801a8536d", + "event": { + "id": "01JAZZJAKS82TDZAE82E0WAENT", + "event_definition_type": "aggregation-v1", + "event_definition_id": "671a28a03696bb3801a7a9f1", + "origin_context": "urn:graylog:message:es:graylog_0:d0a9a7a0-91f1-11ef-9a79-0242ac170004", + "timestamp": "2024-10-24T10:22:04.556Z", + "timestamp_processing": "2024-10-24T19:20:30.585Z", + "timerange_start": None, + "timerange_end": None, + "streams": [], + "source_streams": ["000000000000000000000001"], + "message": "Event - 1", + "source": "server", + "key_tuple": [], + "key": "", + "priority": 3, + "scores": {}, + "alert": True, + "fields": {}, + "group_by_fields": {}, + "replay_info": { + "timerange_start": "2024-10-23T19:20:29.706Z", + "timerange_end": "2024-10-24T19:20:29.706Z", + "query": "source:172.23.0.1", + "streams": ["000000000000000000000001"], + "filters": [], + }, + }, + "backlog": [], +} diff --git a/keep/providers/graylog_provider/docker-compose.yml b/keep/providers/graylog_provider/docker-compose.yml new file mode 100644 index 000000000..7380508d4 --- /dev/null +++ b/keep/providers/graylog_provider/docker-compose.yml @@ -0,0 +1,102 @@ +version: '3' + +services: + # MongoDB: https://hub.docker.com/_/mongo/ + mongodb: + image: "mongo:6.0.18" + ports: + - "27017:27017" + restart: "on-failure" + networks: + - graylog + volumes: + - "mongodb_data:/data/db" + + opensearch: + image: "opensearchproject/opensearch:2.15.0" + environment: + - "OPENSEARCH_JAVA_OPTS=-Xms1g -Xmx1g" + - "bootstrap.memory_lock=true" + - "discovery.type=single-node" + - "action.auto_create_index=false" + - "plugins.security.ssl.http.enabled=false" + - "plugins.security.disabled=true" + # Can generate a password for `OPENSEARCH_INITIAL_ADMIN_PASSWORD` using a linux device via: + # tr -dc A-Z-a-z-0-9_@#%^-_=+ < /dev/urandom | head -c${1:-32} + - "OPENSEARCH_INITIAL_ADMIN_PASSWORD=+_8r#wliY3Pv5-HMIf4qzXImYzZf-M=M" + ulimits: + memlock: + hard: -1 + soft: -1 + nofile: + soft: 65536 + hard: 65536 + ports: + - "9203:9200" + - "9303:9300" + restart: "on-failure" + networks: + - graylog + volumes: + - "opensearch:/usr/share/opensearch/data" + + # Graylog: https://hub.docker.com/r/graylog/graylog/ + graylog: + hostname: "server" + image: "graylog/graylog:6.0" + # To install Graylog Open: "graylog/graylog:6.0" + depends_on: + mongodb: + condition: "service_started" + opensearch: + condition: "service_started" + entrypoint: "/usr/bin/tini -- wait-for-it opensearch:9200 -- /docker-entrypoint.sh" + environment: + GRAYLOG_NODE_ID_FILE: "/usr/share/graylog/data/config/node-id" + GRAYLOG_HTTP_BIND_ADDRESS: "0.0.0.0:9000" + GRAYLOG_ELASTICSEARCH_HOSTS: "http://opensearch:9200" + GRAYLOG_MONGODB_URI: "mongodb://mongodb:27017/graylog" + # To make reporting (headless_shell) work inside a Docker container + GRAYLOG_REPORT_DISABLE_SANDBOX: "true" + # CHANGE ME (must be at least 16 characters)! + GRAYLOG_PASSWORD_SECRET: "somepasswordpepper" + # Password: "admin" + GRAYLOG_ROOT_PASSWORD_SHA2: "8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918" + GRAYLOG_HTTP_EXTERNAL_URI: "http://127.0.0.1:9000/" + ports: + # Graylog web interface and REST API + - "9000:9000/tcp" + # Beats + - "5044:5044/tcp" + # Exposing for TCP Ingestion + - "5555:5555/tcp" + # Syslog TCP + - "5140:5140/tcp" + # Syslog UDP + - "5140:5140/udp" + # GELF TCP + - "12201:12201/tcp" + # GELF UDP + - "12201:12201/udp" + # Forwarder data + - "13301:13301/tcp" + # Forwarder config + - "13302:13302/tcp" + restart: "on-failure" + networks: + - graylog + volumes: + - "graylog_data:/usr/share/graylog/data/data" + - "graylog_config:/usr/share/graylog/data/config" + - "graylog_journal:/usr/share/graylog/data/journal" + +networks: + graylog: + driver: "bridge" + +volumes: + mongodb_data: + opensearch: + graylog_data: + graylog_config: + graylog_journal: \ No newline at end of file diff --git a/keep/providers/graylog_provider/graylog_provider.py b/keep/providers/graylog_provider/graylog_provider.py new file mode 100644 index 000000000..20ad94d4c --- /dev/null +++ b/keep/providers/graylog_provider/graylog_provider.py @@ -0,0 +1,646 @@ +""" +Graylog Provider is a class that allows to install webhooks in Graylog. +""" + +import dataclasses +import math +import uuid +from datetime import datetime, timezone, timedelta +from typing import List +from urllib.parse import urlencode, urljoin, urlparse + +import pydantic +import requests + +from keep.api.models.alert import AlertDto, AlertSeverity, AlertStatus +from keep.contextmanager.contextmanager import ContextManager +from keep.providers.base.base_provider import BaseProvider +from keep.providers.models.provider_config import ProviderConfig, ProviderScope + + +class ResourceAlreadyExists(Exception): + def __init__(self, *args): + super().__init__(*args) + + +@pydantic.dataclasses.dataclass +class GraylogProviderAuthConfig: + """ + Graylog authentication configuration. + """ + + graylog_user_name: str = dataclasses.field( + metadata={ + "required": True, + "description": "Username", + "hint": "Your Username associated with the Access Token", + }, + ) + graylog_access_token: str = dataclasses.field( + metadata={ + "required": True, + "description": "Graylog Access Token", + "hint": "Graylog Access Token ", + "sensitive": True, + }, + ) + deployment_url: str = dataclasses.field( + metadata={ + "required": True, + "description": "Deployment Url", + "hint": "Example: http://127.0.0.1:9000", + }, + ) + + +class GraylogProvider(BaseProvider): + """Install Webhooks and receive alerts from Graylog.""" + + webhook_description = "" + webhook_template = "" + webhook_markdown = """ +💡 For more details on how to configure Graylog to send alerts to Keep, see the [Keep documentation](https://docs.keephq.dev/providers/documentation/graylog-provider). 💡 + +To send alerts from Graylog to Keep, Use the following webhook url to configure Graylog send alerts to Keep: + +1. In Graylog, from the Topbar, go to `Alerts` > `Notifications`. +2. Click "Create Notification". +3. In the New Notification form, configure: + +- **Display Name**: keep-graylog-webhook-integration +- **Title**: keep-graylog-webhook-integration +- **Notification Type**: Custom HTTP Notification +- **URL**: {keep_webhook_api_url} # Whitelist this URL +- **Headers**: X-API-KEY:{api_key} +4. Erase the Body Template. +5. Click on "Create Notification". +6. Go the the `Event Definitions` tab, and select the Event Definition that will trigger the alert you want to send to Keep and click on More > Edit. +7. Go to "Notifications" tab. +8. Click on "Add Notification" and select the "keep-graylog-webhook-integration" that you created in step 3. +9. Click on "Add Notification". +10. Click `Next` > `Update` event definition +""" + PROVIDER_DISPLAY_NAME = "Graylog" + PROVIDER_SCOPES = [ + ProviderScope( + name="authenticated", + description="User is Authorized", + mandatory=True, + mandatory_for_webhook=True, + alias="Rules Reader", + ), + ProviderScope( + name="authorized", + description="Required privileges", + mandatory=True, + mandatory_for_webhook=True, + alias="Rules Reader", + ), + ] + + FINGERPRINT_FIELDS = ["event_definition_id"] + + def __init__( + self, context_manager: ContextManager, provider_id: str, config: ProviderConfig + ): + super().__init__(context_manager, provider_id, config) + self._host = None + + def dispose(self): + """ + Dispose the provider. + """ + pass + + def validate_config(self): + """ + Validates required configuration for Graylog provider. + """ + self.logger.debug("Validating configuration for Graylog provider") + self.authentication_config = GraylogProviderAuthConfig( + **self.config.authentication + ) + + @property + def graylog_host(self): + self.logger.debug("Fetching Graylog host") + if self._host: + self.logger.debug("Returning cached Graylog host") + return self._host + + # Handle host determination logic with logging + if self.authentication_config.deployment_url.startswith( + "http://" + ) or self.authentication_config.deployment_url.startswith("https://"): + self.logger.info("Using supplied Graylog host with protocol") + self._host = self.authentication_config.deployment_url + return self._host + + # Otherwise, attempt to use https + try: + self.logger.debug( + f"Trying HTTPS for {self.authentication_config.deployment_url}" + ) + requests.get( + f"https://{self.authentication_config.deployment_url}", + verify=False, + ) + self.logger.info("HTTPS protocol confirmed") + self._host = f"https://{self.authentication_config.deployment_url}" + except requests.exceptions.SSLError: + self.logger.warning("SSL error encountered, falling back to HTTP") + self._host = f"http://{self.authentication_config.deployment_url}" + except Exception as e: + self.logger.error( + "Failed to determine Graylog host", extra={"exception": str(e)} + ) + self._host = self.authentication_config.deployment_url.rstrip("/") + + return self._host + + @property + def _headers(self): + return { + "Accept": "application/json", + "X-Requested-By": "Keep", + } + + @property + def _auth(self): + return self.authentication_config.graylog_access_token, "token" + + def __get_url(self, paths: List[str] = [], query_params: dict = None, **kwargs): + """ + Helper method to build the url for Graylog api requests. + """ + host = self.graylog_host.rstrip("/").rstrip() + "/api/" + self.logger.info(f"Building URL with host: {host}") + url = urljoin( + host, + "/".join(str(path) for path in paths), + ) + + # add query params + if query_params: + url = f"{url}?{urlencode(query_params)}" + + self.logger.debug(f"Constructed URL: {url}") + return url + + def validate_scopes(self) -> dict[str, bool | str]: + self.logger.info("Validating user scopes for Graylog provider") + required_role = "Admin" + + try: + user_response = requests.get( + url=self.__get_url( + paths=["users", self.authentication_config.graylog_user_name] + ), + headers=self._headers, + auth=self._auth, + ) + self.logger.debug("User information request sent") + if user_response.status_code != 200: + raise Exception(user_response.text) + + authenticated = True + user_response = user_response.json() + if required_role in user_response["roles"]: + self.logger.info("User has required admin privileges") + authorized = True + else: + self.logger.warning("User lacks required admin privileges") + authorized = "Missing admin Privileges" + + except Exception as e: + self.logger.error( + "Error while validating user scopes", extra={"exception": str(e)} + ) + authenticated = str(e) + authorized = False + + return { + "authenticated": authenticated, + "authorized": authorized, + } + + def __get_url_whitelist(self): + try: + self.logger.info("Fetching URL Whitelist") + whitelist_response = requests.get( + url=self.__get_url(paths=["system/urlwhitelist"]), + headers=self._headers, + auth=self._auth, + timeout=10, + ) + if whitelist_response.status_code != 200: + raise Exception(whitelist_response.text) + self.logger.info("Successfully retrieved URL Whitelist") + return whitelist_response.json() + except Exception as e: + self.logger.error( + "Error while fetching URL whitelist", extra={"exception": str(e)} + ) + raise e + + def __update_url_whitelist(self, whitelist): + try: + self.logger.info("Updating URL whitelist") + whitelist_response = requests.put( + url=self.__get_url(paths=["system/urlwhitelist"]), + headers=self._headers, + auth=self._auth, + json=whitelist, + ) + if whitelist_response.status_code != 204: + raise Exception(whitelist_response.text) + self.logger.info("Successfully updated URL whitelist") + except Exception as e: + self.logger.error( + "Error while updating URL whitelist", extra={"exception": str(e)} + ) + raise e + + def __get_events(self, page: int, per_page: int): + self.logger.info( + f"Fetching events from Graylog (page: {page}, per_page: {per_page})" + ) + try: + events_response = requests.get( + url=self.__get_url(paths=["events", "definitions"]), + headers=self._headers, + auth=self._auth, + params={"page": page, "per_page": per_page}, + ) + + if events_response.status_code != 200: + raise Exception(events_response.text) + + events_response = events_response.json() + self.logger.info("Successfully fetched events from Graylog") + return events_response + + except Exception as e: + self.logger.error( + "Error while fetching events", extra={"exception": str(e)} + ) + raise e + + def __update_event(self, event): + try: + self.logger.info(f"Updating event with ID: {event['id']}") + event_update_response = requests.put( + url=self.__get_url(paths=["events", "definitions", event["id"]]), + timeout=10, + json=event, + auth=self._auth, + headers=self._headers, + ) + + if event_update_response.status_code != 200: + raise Exception(event_update_response.text) + + self.logger.info(f"Successfully updated event with ID: {event['id']}") + + except Exception as e: + self.logger.error( + f"Error while updating event with ID: {event['id']}", + extra={"exception": str(e)}, + ) + raise e + + def __get_notification(self, page: int, per_page: int, notification_name: str): + try: + self.logger.info(f"Fetching notification: {notification_name}") + notifications_response = requests.get( + url=self.__get_url(paths=["events", "notifications"]), + params={ + "page": page, + "per_page": per_page, + "query": f"title:{notification_name}", + }, + auth=self._auth, + headers=self._headers, + timeout=10, + ) + if notifications_response.status_code != 200: + raise Exception(notifications_response.text) + self.logger.info(f"Successfully fetched notification: {notification_name}") + return notifications_response.json() + except Exception as e: + self.logger.error( + f"Error while fetching notification {notification_name}", + extra={"exception": str(e)}, + ) + raise e + + def __delete_notification(self, notification_id: str): + try: + self.logger.info( + f"Attempting to delete notification with ID: {notification_id}" + ) + notification_delete_response = requests.delete( + url=self.__get_url(paths=["events", "notifications", notification_id]), + auth=self._auth, + headers=self._headers, + ) + if notification_delete_response.status_code != 204: + raise Exception(notification_delete_response.text) + + self.logger.info( + f"Successfully deleted notification with ID: {notification_id}" + ) + + except Exception as e: + self.logger.error( + f"Error while deleting notification with ID {notification_id}", + extra={"exception": str(e)}, + ) + raise e + + def __create_notification(self, notification_name: str, notification_body): + try: + self.logger.info(f"Attempting to create notification: {notification_name}") + notification_creation_response = requests.post( + url=self.__get_url(paths=["events", "notifications"]), + headers=self._headers, + auth=self._auth, + timeout=10, + json=notification_body, + ) + if notification_creation_response.status_code != 200: + raise Exception(notification_creation_response.text) + + self.logger.info(f"Successfully created notification: {notification_name}") + return notification_creation_response.json() + except Exception as e: + self.logger.error( + f"Error while creating notification {notification_name}", + extra={"exception": str(e)}, + ) + raise e + + def __update_notification(self, notification_id: str, notification_body): + try: + self.logger.info( + f"Attempting to update notification with ID: {notification_id}" + ) + notification_update_response = requests.put( + url=self.__get_url(paths=["events", "notifications", notification_id]), + headers=self._headers, + auth=self._auth, + timeout=10, + json=notification_body, + ) + if notification_update_response.status_code != 200: + raise Exception(notification_update_response.text) + + self.logger.info( + f"Successfully updated notification with ID: {notification_id}" + ) + return notification_update_response.json() + except Exception as e: + self.logger.error( + f"Error while updating notification with ID {notification_id}", + extra={"exception": str(e)}, + ) + raise e + + def setup_webhook( + self, tenant_id: str, keep_api_url: str, api_key: str, setup_alerts: bool = True + ): + self.logger.info("Setting up webhook in Graylog") + try: + event_definitions = [] + events_1 = self.__get_events(page=1, per_page=100) + event_definitions.extend(events_1["event_definitions"]) + total_pages = math.ceil(int(events_1["total"]) / 100) + + for page in range(2, total_pages): + self.logger.debug(f"Fetching events page: {page}") + event_definitions.extend( + self.__get_events(page=page, per_page=100)["event_definitions"] + ) + + # Extracting provider_id from the keep_api_url + parsed_url = urlparse(keep_api_url) + query_params = parsed_url.query + provider_id = query_params.split("provider_id=")[-1] + notification_name = f"Keep-{provider_id}" + + # Whitelist URL + url_whitelist = self.__get_url_whitelist() + url_found = False + for entry in url_whitelist["entries"]: + if entry["value"] == keep_api_url: + self.logger.info("URL already whitelisted") + url_found = True + break + if not url_found: + self.logger.info("Adding URL to whitelist") + url_whitelist["entries"].append( + { + "id": str(uuid.uuid4()), + "title": notification_name, + "value": keep_api_url, + "type": "literal", + } + ) + self.__update_url_whitelist(url_whitelist) + + # Create notification + notification = self.__get_notification( + page=1, per_page=1, notification_name=notification_name + ) + if int(notification["count"]) > 0: + self.logger.info("Notification already exists, deleting it") + self.__delete_notification( + notification_id=notification["notifications"][0]["id"] + ) + + self.logger.info("Creating new notification") + notification_body = { + "title": notification_name, + "description": "Hello, this Notification is created by Keep, please do not change the title.", + "config": { + "type": "http-notification-v2", + "basic_auth": None, + "api_key_as_header": False, + "api_key": "", + "api_secret": None, + "url": keep_api_url, + "skip_tls_verification": True, + "method": "POST", + "time_zone": "UTC", + "content_type": "JSON", + "headers": f"X-API-KEY:{api_key}", + "body_template": "", + }, + } + new_notification = self.__create_notification( + notification_name=notification_name, notification_body=notification_body + ) + + for event_definition in event_definitions: + if event_definition["_scope"] == "SYSTEM_NOTIFICATION_EVENT": + self.logger.info("Skipping SYSTEM_NOTIFICATION_EVENT") + continue + self.logger.info(f"Updating event with ID: {event_definition['id']}") + event_definition["notifications"].append( + {"notification_id": new_notification["id"]} + ) + self.__update_event(event=event_definition) + + self.logger.info("Webhook setup completed successfully") + except Exception as e: + self.logger.error( + "Error while setting up webhook", extra={"exception": str(e)} + ) + raise e + + @staticmethod + def __map_event_to_alert(event: dict) -> AlertDto: + alert = AlertDto( + id=event["event"]["id"], + name=event.get("event_definition_title", event["event"]["message"]), + severity=[AlertSeverity.LOW, AlertSeverity.WARNING, AlertSeverity.HIGH][ + int(event["event"]["priority"]) - 1 + ], + description=event.get("event_definition_description", None), + event_definition_id=event["event"]["event_definition_id"], + origin_context=event["event"].get("origin_context", None), + status=AlertStatus.FIRING, + lastReceived=datetime.fromisoformat( + event["event"]["timestamp"].replace("z", "") + ) + .replace(tzinfo=timezone.utc) + .isoformat(), + message=event["event"].get("message", None), + source=["graylog"], + ) + + alert.fingerprint = GraylogProvider.get_alert_fingerprint( + alert, GraylogProvider.FINGERPRINT_FIELDS + ) + + return alert + + @staticmethod + def _format_alert(event: dict, provider_instance: BaseProvider) -> AlertDto: + return GraylogProvider.__map_event_to_alert(event=event) + + @classmethod + def simulate_alert(cls) -> dict: + from keep.providers.graylog_provider.alerts_mock import ALERTS + import random + import string + + # Use the provided ALERTS structure + alert_data = ALERTS.copy() + + # Start with the base event payload + simulated_alert = alert_data["event"] + + alert_data["event_definition_title"] = random.choice( + [ + "EventDefinition - 1", + "EventDefinition - 2", + "EventDefinition - 3", + ] + ) + + alert_data["event_definition_description"] = random.choice( + [ + "Description - add", + "Description - commit", + "Description - push", + ] + ) + + # Apply variability to the event message and priority + simulated_alert["message"] = alert_data["event_definition_title"] + simulated_alert["priority"] = random.choice([1, 2, 3]) + chars = string.ascii_uppercase + string.digits + # Generate a random ID of specified length + random_id = "".join(random.choice(chars) for _ in range(25)) + simulated_alert["id"] = random_id + + simulated_alert["event_definition_id"] = alert_data["event_definition_id"] = ( + "".join( + random.choice(string.ascii_lowercase + string.digits) for _ in range(24) + ) + ) + + # Set the current timestamp + simulated_alert["timestamp"] = datetime.now().isoformat() + + # Apply variability to replay_info + replay_info = simulated_alert.get("replay_info", {}) + replay_info["timerange_start"] = ( + datetime.now() - timedelta(hours=1) + ).isoformat() + replay_info["timerange_end"] = datetime.now().isoformat() + + simulated_alert["replay_info"] = replay_info + + return alert_data + + def __get_alerts(self, json_data: dict): + try: + self.logger.info( + f"Fetching alerts (page: {json_data['page']}, per_page: {json_data['per_page']})" + ) + alert_response = requests.post( + url=self.__get_url(paths=["events", "search"]), + headers=self._headers, + auth=self._auth, + timeout=10, + json=json_data, + ) + + if alert_response.status_code != 200: + raise Exception(alert_response.text) + + self.logger.info("Successfully fetched alerts") + return alert_response.json() + + except Exception as e: + self.logger.error( + "Error while fetching alerts", extra={"exception": str(e)} + ) + raise e + + def _get_alerts(self) -> list[AlertDto]: + self.logger.info("Getting alerts from Graylog") + json_data = { + "query": "", + "page": 1, + "per_page": 1000, + "filter": { + "alerts": "only", + }, + "timerange": { + "range": 1 * 24 * 60 * 60, + "type": "relative", + }, + } + all_alerts = [] + alerts_1 = self.__get_alerts(json_data=json_data) + all_alerts.extend(alerts_1["events"]) + total_events = max(10, math.ceil(alerts_1["total_events"] / 1000)) + + for page in range(2, total_events + 1): + self.logger.debug(f"Fetching alerts page: {page}") + json_data["page"] = page + alerts = self.__get_alerts(json_data=json_data) + all_alerts.extend(alerts["events"]) + + self.logger.info("Successfully fetched all alerts") + return [ + GraylogProvider.__map_event_to_alert(event=event) for event in all_alerts + ] + + def _query(self, events_search_parameters: dict, **kwargs: dict): + self.logger.info("Querying Graylog with specified parameters") + alerts = self.__get_alerts(json_data=events_search_parameters)["events"] + return [GraylogProvider.__map_event_to_alert(event=event) for event in alerts] From f549b053b30a5104ad7e4cc88ba8c6606e1ae2a2 Mon Sep 17 00:00:00 2001 From: Kirill Chernakov Date: Tue, 29 Oct 2024 14:59:28 +0400 Subject: [PATCH 08/11] feat: merge incidents (#2274) Signed-off-by: Kirill Chernakov --- docs/api-ref/alerts/get-alert-quality.mdx | 3 + docs/api-ref/incidents/add-comment.mdx | 3 + .../get-future-incidents-for-an-incident.mdx | 3 + .../incidents/get-incident-workflows.mdx | 3 + docs/api-ref/incidents/get-incidents-meta.mdx | 3 + docs/api-ref/incidents/merge-incidents.mdx | 3 + docs/mint.json | 10 +- docs/openapi.json | 2 +- keep-ui/app/alerts/alert-pagination.tsx | 121 ++++--- keep-ui/app/globals.css | 42 +++ .../app/incidents/[id]/incident-activity.tsx | 16 +- .../incidents/[id]/incident-alert-menu.tsx | 6 +- .../app/incidents/[id]/incident-alerts.tsx | 151 ++++---- keep-ui/app/incidents/[id]/incident-chat.tsx | 45 +-- .../app/incidents/[id]/incident-header.tsx | 172 +++++++++ ...ncident-info.tsx => incident-overview.tsx} | 208 ++--------- .../app/incidents/[id]/incident-timeline.tsx | 5 +- .../[id]/incident-workflow-table.tsx | 109 +++--- keep-ui/app/incidents/[id]/incident.tsx | 146 ++++---- .../incidents/create-or-update-incident.tsx | 2 + .../incidents/incident-candidate-actions.tsx | 39 +- .../incident-change-status-modal.tsx | 14 +- .../app/incidents/incident-dropdown-menu.tsx | 58 +++ keep-ui/app/incidents/incident-list-error.tsx | 24 ++ ...lder.tsx => incident-list-placeholder.tsx} | 8 +- .../{incident.tsx => incident-list.tsx} | 81 +++-- .../app/incidents/incident-merge-modal.tsx | 204 +++++++++++ keep-ui/app/incidents/incident-pagination.tsx | 18 +- .../incidents/incident-table-component.tsx | 102 +++--- .../incident-table-filters-context.tsx | 99 ++++-- keep-ui/app/incidents/incidents-table.tsx | 335 ++++++++++++------ keep-ui/app/incidents/models.ts | 7 +- keep-ui/app/incidents/page.tsx | 7 +- .../app/incidents/react-quill-override.css | 3 + keep-ui/app/incidents/statuses.tsx | 52 ++- .../app/incidents/vertical-rounded-list.css | 19 + .../ui/DropdownMenu/DropdownMenu.css | 73 ++++ .../ui/DropdownMenu/DropdownMenu.tsx | 285 +++++++++++++++ keep-ui/components/ui/DropdownMenu/index.ts | 1 + keep-ui/components/ui/table/utils.ts | 33 ++ .../incidents/model/useIncidentActions.tsx | 60 ++++ .../features/change-incident-status/index.ts | 1 + .../ui/incident-change-status-select.tsx | 90 +++++ keep-ui/package-lock.json | 8 +- keep-ui/package.json | 2 +- keep-ui/tailwind.config.js | 8 + keep-ui/tsconfig.json | 2 + keep-ui/utils/hooks/useIncidents.ts | 9 +- keep/api/core/db.py | 78 +++- keep/api/models/alert.py | 29 +- keep/api/models/db/alert.py | 33 +- .../versions/2024-10-23-15-21_89b4d3905d26.py | 50 +++ keep/api/routes/incidents.py | 54 +++ keep/api/utils/pluralize.py | 26 ++ tests/test_incidents.py | 314 ++++++++++++++-- 55 files changed, 2514 insertions(+), 765 deletions(-) create mode 100644 docs/api-ref/alerts/get-alert-quality.mdx create mode 100644 docs/api-ref/incidents/add-comment.mdx create mode 100644 docs/api-ref/incidents/get-future-incidents-for-an-incident.mdx create mode 100644 docs/api-ref/incidents/get-incident-workflows.mdx create mode 100644 docs/api-ref/incidents/get-incidents-meta.mdx create mode 100644 docs/api-ref/incidents/merge-incidents.mdx create mode 100644 keep-ui/app/incidents/[id]/incident-header.tsx rename keep-ui/app/incidents/[id]/{incident-info.tsx => incident-overview.tsx} (55%) create mode 100644 keep-ui/app/incidents/incident-dropdown-menu.tsx create mode 100644 keep-ui/app/incidents/incident-list-error.tsx rename keep-ui/app/incidents/{IncidentPlaceholder.tsx => incident-list-placeholder.tsx} (91%) rename keep-ui/app/incidents/{incident.tsx => incident-list.tsx} (71%) create mode 100644 keep-ui/app/incidents/incident-merge-modal.tsx create mode 100644 keep-ui/app/incidents/react-quill-override.css create mode 100644 keep-ui/app/incidents/vertical-rounded-list.css create mode 100644 keep-ui/components/ui/DropdownMenu/DropdownMenu.css create mode 100644 keep-ui/components/ui/DropdownMenu/DropdownMenu.tsx create mode 100644 keep-ui/components/ui/DropdownMenu/index.ts create mode 100644 keep-ui/components/ui/table/utils.ts create mode 100644 keep-ui/entities/incidents/model/useIncidentActions.tsx create mode 100644 keep-ui/features/change-incident-status/index.ts create mode 100644 keep-ui/features/change-incident-status/ui/incident-change-status-select.tsx create mode 100644 keep/api/models/db/migrations/versions/2024-10-23-15-21_89b4d3905d26.py create mode 100644 keep/api/utils/pluralize.py diff --git a/docs/api-ref/alerts/get-alert-quality.mdx b/docs/api-ref/alerts/get-alert-quality.mdx new file mode 100644 index 000000000..277322d33 --- /dev/null +++ b/docs/api-ref/alerts/get-alert-quality.mdx @@ -0,0 +1,3 @@ +--- +openapi: get /alerts/quality/metrics +--- \ No newline at end of file diff --git a/docs/api-ref/incidents/add-comment.mdx b/docs/api-ref/incidents/add-comment.mdx new file mode 100644 index 000000000..2c27f1c25 --- /dev/null +++ b/docs/api-ref/incidents/add-comment.mdx @@ -0,0 +1,3 @@ +--- +openapi: post /incidents/{incident_id}/comment +--- \ No newline at end of file diff --git a/docs/api-ref/incidents/get-future-incidents-for-an-incident.mdx b/docs/api-ref/incidents/get-future-incidents-for-an-incident.mdx new file mode 100644 index 000000000..078b4d930 --- /dev/null +++ b/docs/api-ref/incidents/get-future-incidents-for-an-incident.mdx @@ -0,0 +1,3 @@ +--- +openapi: get /incidents/{incident_id}/future_incidents +--- \ No newline at end of file diff --git a/docs/api-ref/incidents/get-incident-workflows.mdx b/docs/api-ref/incidents/get-incident-workflows.mdx new file mode 100644 index 000000000..012ed48b9 --- /dev/null +++ b/docs/api-ref/incidents/get-incident-workflows.mdx @@ -0,0 +1,3 @@ +--- +openapi: get /incidents/{incident_id}/workflows +--- \ No newline at end of file diff --git a/docs/api-ref/incidents/get-incidents-meta.mdx b/docs/api-ref/incidents/get-incidents-meta.mdx new file mode 100644 index 000000000..52e7a6b62 --- /dev/null +++ b/docs/api-ref/incidents/get-incidents-meta.mdx @@ -0,0 +1,3 @@ +--- +openapi: get /incidents/meta +--- \ No newline at end of file diff --git a/docs/api-ref/incidents/merge-incidents.mdx b/docs/api-ref/incidents/merge-incidents.mdx new file mode 100644 index 000000000..21d697a6c --- /dev/null +++ b/docs/api-ref/incidents/merge-incidents.mdx @@ -0,0 +1,3 @@ +--- +openapi: post /incidents/merge +--- \ No newline at end of file diff --git a/docs/mint.json b/docs/mint.json index d0bcdc482..fe36ffb2d 100644 --- a/docs/mint.json +++ b/docs/mint.json @@ -331,7 +331,8 @@ "api-ref/alerts/unenrich-alert", "api-ref/alerts/search-alerts", "api-ref/alerts/get-alert-audit", - "api-ref/alerts/get-alerts" + "api-ref/alerts/get-alerts", + "api-ref/alerts/get-alert-quality" ] }, { @@ -366,7 +367,12 @@ "api-ref/incidents/get-incident-alerts", "api-ref/incidents/add-alerts-to-incident", "api-ref/incidents/delete-alerts-from-incident", - "api-ref/incidents/confirm-incident" + "api-ref/incidents/confirm-incident", + "api-ref/incidents/add-comment", + "api-ref/incidents/get-future-incidents-for-an-incident", + "api-ref/incidents/get-incident-workflows", + "api-ref/incidents/get-incidents-meta", + "api-ref/incidents/merge-incidents" ] }, { diff --git a/docs/openapi.json b/docs/openapi.json index 5df0d0f5f..54ad8d432 100644 --- a/docs/openapi.json +++ b/docs/openapi.json @@ -1 +1 @@ -{"openapi": "3.0.2", "info": {"title": "Keep API", "description": "Rest API powering https://platform.keephq.dev and friends \ud83c\udfc4\u200d\u2640\ufe0f", "version": "0.1.0"}, "paths": {"/providers": {"get": {"tags": ["providers"], "summary": "Get Providers", "operationId": "get_providers_providers_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/providers/export": {"get": {"tags": ["providers"], "summary": "Get Installed Providers", "description": "export all installed providers", "operationId": "get_installed_providers_providers_export_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/providers/{provider_type}/{provider_id}/configured-alerts": {"get": {"tags": ["providers"], "summary": "Get Alerts Configuration", "description": "Get alerts configuration from a provider", "operationId": "get_alerts_configuration_providers__provider_type___provider_id__configured_alerts_get", "parameters": [{"required": true, "schema": {"type": "string", "title": "Provider Type"}, "name": "provider_type", "in": "path"}, {"required": true, "schema": {"type": "string", "title": "Provider Id"}, "name": "provider_id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {}, "type": "array", "title": "Response Get Alerts Configuration Providers Provider Type Provider Id Configured Alerts Get"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/providers/{provider_type}/{provider_id}/logs": {"get": {"tags": ["providers"], "summary": "Get Logs", "description": "Get logs from a provider", "operationId": "get_logs_providers__provider_type___provider_id__logs_get", "parameters": [{"required": true, "schema": {"type": "string", "title": "Provider Type"}, "name": "provider_type", "in": "path"}, {"required": true, "schema": {"type": "string", "title": "Provider Id"}, "name": "provider_id", "in": "path"}, {"required": false, "schema": {"type": "integer", "title": "Limit", "default": 5}, "name": "limit", "in": "query"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {}, "type": "array", "title": "Response Get Logs Providers Provider Type Provider Id Logs Get"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/providers/{provider_type}/schema": {"get": {"tags": ["providers"], "summary": "Get Alerts Schema", "description": "Get the provider's API schema used to push alerts configuration", "operationId": "get_alerts_schema_providers__provider_type__schema_get", "parameters": [{"required": true, "schema": {"type": "string", "title": "Provider Type"}, "name": "provider_type", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"type": "object", "title": "Response Get Alerts Schema Providers Provider Type Schema Get"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/providers/{provider_type}/{provider_id}/alerts/count": {"get": {"tags": ["providers"], "summary": "Get Alert Count", "description": "Get number of alerts a specific provider has received (in a specific time time period or ever)", "operationId": "get_alert_count_providers__provider_type___provider_id__alerts_count_get", "parameters": [{"required": true, "schema": {"type": "string", "title": "Provider Type"}, "name": "provider_type", "in": "path"}, {"required": true, "schema": {"type": "string", "title": "Provider Id"}, "name": "provider_id", "in": "path"}, {"required": true, "schema": {"type": "boolean", "title": "Ever"}, "name": "ever", "in": "query"}, {"required": false, "schema": {"type": "string", "format": "date-time", "title": "Start Time"}, "name": "start_time", "in": "query"}, {"required": false, "schema": {"type": "string", "format": "date-time", "title": "End Time"}, "name": "end_time", "in": "query"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/providers/{provider_type}/{provider_id}/alerts": {"post": {"tags": ["providers"], "summary": "Add Alert", "description": "Push new alerts to the provider", "operationId": "add_alert_providers__provider_type___provider_id__alerts_post", "parameters": [{"required": true, "schema": {"type": "string", "title": "Provider Type"}, "name": "provider_type", "in": "path"}, {"required": true, "schema": {"type": "string", "title": "Provider Id"}, "name": "provider_id", "in": "path"}, {"required": false, "schema": {"type": "string", "title": "Alert Id"}, "name": "alert_id", "in": "query"}], "requestBody": {"content": {"application/json": {"schema": {"type": "object", "title": "Alert"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/providers/test": {"post": {"tags": ["providers"], "summary": "Test Provider", "description": "Test a provider's alert retrieval", "operationId": "test_provider_providers_test_post", "requestBody": {"content": {"application/json": {"schema": {"type": "object", "title": "Provider Info"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/providers/{provider_type}/{provider_id}": {"delete": {"tags": ["providers"], "summary": "Delete Provider", "operationId": "delete_provider_providers__provider_type___provider_id__delete", "parameters": [{"required": true, "schema": {"type": "string", "title": "Provider Type"}, "name": "provider_type", "in": "path"}, {"required": true, "schema": {"type": "string", "title": "Provider Id"}, "name": "provider_id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/providers/{provider_id}/scopes": {"post": {"tags": ["providers"], "summary": "Validate Provider Scopes", "description": "Validate provider scopes", "operationId": "validate_provider_scopes_providers__provider_id__scopes_post", "parameters": [{"required": true, "schema": {"type": "string", "title": "Provider Id"}, "name": "provider_id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"additionalProperties": {"anyOf": [{"type": "boolean"}, {"type": "string"}]}, "type": "object", "title": "Response Validate Provider Scopes Providers Provider Id Scopes Post"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/providers/{provider_id}": {"put": {"tags": ["providers"], "summary": "Update Provider", "description": "Update provider", "operationId": "update_provider_providers__provider_id__put", "parameters": [{"required": true, "schema": {"type": "string", "title": "Provider Id"}, "name": "provider_id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/providers/install": {"post": {"tags": ["providers"], "summary": "Install Provider", "operationId": "install_provider_providers_install_post", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/providers/install/oauth2/{provider_type}": {"post": {"tags": ["providers"], "summary": "Install Provider Oauth2", "operationId": "install_provider_oauth2_providers_install_oauth2__provider_type__post", "parameters": [{"required": true, "schema": {"type": "string", "title": "Provider Type"}, "name": "provider_type", "in": "path"}], "requestBody": {"content": {"application/json": {"schema": {"type": "object", "title": "Provider Info"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/providers/{provider_id}/invoke/{method}": {"post": {"tags": ["providers"], "summary": "Invoke Provider Method", "description": "Invoke provider special method", "operationId": "invoke_provider_method_providers__provider_id__invoke__method__post", "parameters": [{"required": true, "schema": {"type": "string", "title": "Provider Id"}, "name": "provider_id", "in": "path"}, {"required": true, "schema": {"type": "string", "title": "Method"}, "name": "method", "in": "path"}], "requestBody": {"content": {"application/json": {"schema": {"type": "object", "title": "Method Params"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/providers/install/webhook/{provider_type}/{provider_id}": {"post": {"tags": ["providers"], "summary": "Install Provider Webhook", "operationId": "install_provider_webhook_providers_install_webhook__provider_type___provider_id__post", "parameters": [{"required": true, "schema": {"type": "string", "title": "Provider Type"}, "name": "provider_type", "in": "path"}, {"required": true, "schema": {"type": "string", "title": "Provider Id"}, "name": "provider_id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/providers/{provider_type}/webhook": {"get": {"tags": ["providers"], "summary": "Get Webhook Settings", "operationId": "get_webhook_settings_providers__provider_type__webhook_get", "parameters": [{"required": true, "schema": {"type": "string", "title": "Provider Type"}, "name": "provider_type", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ProviderWebhookSettings"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/actions": {"get": {"tags": ["actions"], "summary": "Get Actions", "description": "Get all actions", "operationId": "get_actions_actions_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "post": {"tags": ["actions"], "summary": "Create Actions", "description": "Create new actions by uploading a file", "operationId": "create_actions_actions_post", "requestBody": {"content": {"multipart/form-data": {"schema": {"$ref": "#/components/schemas/Body_create_actions_actions_post"}}}}, "responses": {"201": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/actions/{action_id}": {"put": {"tags": ["actions"], "summary": "Put Action", "description": "Update an action", "operationId": "put_action_actions__action_id__put", "parameters": [{"required": true, "schema": {"type": "string", "title": "Action Id"}, "name": "action_id", "in": "path"}], "requestBody": {"content": {"multipart/form-data": {"schema": {"$ref": "#/components/schemas/Body_put_action_actions__action_id__put"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "delete": {"tags": ["actions"], "summary": "Delete Action", "description": "Delete an action", "operationId": "delete_action_actions__action_id__delete", "parameters": [{"required": true, "schema": {"type": "string", "title": "Action Id"}, "name": "action_id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/healthcheck": {"get": {"tags": ["healthcheck"], "summary": "Healthcheck", "description": "simple healthcheck endpoint", "operationId": "healthcheck_healthcheck_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"type": "object", "title": "Response Healthcheck Healthcheck Get"}}}}}}}, "/alerts": {"get": {"tags": ["alerts"], "summary": "Get All Alerts", "description": "Get last alerts occurrence", "operationId": "get_all_alerts_alerts_get", "parameters": [{"required": false, "schema": {"type": "integer", "title": "Limit", "default": 1000}, "name": "limit", "in": "query"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/AlertDto"}, "type": "array", "title": "Response Get All Alerts Alerts Get"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "delete": {"tags": ["alerts"], "summary": "Delete Alert", "description": "Delete alert by finerprint and last received time", "operationId": "delete_alert_alerts_delete", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/DeleteRequestBody"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"additionalProperties": {"type": "string"}, "type": "object", "title": "Response Delete Alert Alerts Delete"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/alerts/{fingerprint}/history": {"get": {"tags": ["alerts"], "summary": "Get Alert History", "description": "Get alert history", "operationId": "get_alert_history_alerts__fingerprint__history_get", "parameters": [{"required": true, "schema": {"type": "string", "title": "Fingerprint"}, "name": "fingerprint", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/AlertDto"}, "type": "array", "title": "Response Get Alert History Alerts Fingerprint History Get"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/alerts/{fingerprint}/assign/{last_received}": {"post": {"tags": ["alerts"], "summary": "Assign Alert", "description": "Assign alert to user", "operationId": "assign_alert_alerts__fingerprint__assign__last_received__post", "parameters": [{"required": true, "schema": {"type": "string", "title": "Fingerprint"}, "name": "fingerprint", "in": "path"}, {"required": true, "schema": {"type": "string", "title": "Last Received"}, "name": "last_received", "in": "path"}, {"required": false, "schema": {"type": "boolean", "title": "Unassign", "default": false}, "name": "unassign", "in": "query"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"additionalProperties": {"type": "string"}, "type": "object", "title": "Response Assign Alert Alerts Fingerprint Assign Last Received Post"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/alerts/event": {"post": {"tags": ["alerts"], "summary": "Receive Generic Event", "description": "Receive a generic alert event", "operationId": "receive_generic_event_alerts_event_post", "parameters": [{"required": false, "schema": {"type": "string", "title": "Fingerprint"}, "name": "fingerprint", "in": "query"}], "requestBody": {"content": {"application/json": {"schema": {"anyOf": [{"$ref": "#/components/schemas/AlertDto"}, {"items": {"$ref": "#/components/schemas/AlertDto"}, "type": "array"}, {"type": "object"}], "title": "Event"}}}, "required": true}, "responses": {"202": {"description": "Successful Response", "content": {"application/json": {"schema": {"anyOf": [{"$ref": "#/components/schemas/AlertDto"}, {"items": {"$ref": "#/components/schemas/AlertDto"}, "type": "array"}], "title": "Response Receive Generic Event Alerts Event Post"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/alerts/event/netdata": {"get": {"tags": ["alerts"], "summary": "Webhook Challenge", "description": "Helper function to complete Netdata webhook challenge", "operationId": "webhook_challenge_alerts_event_netdata_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}}}}, "/alerts/event/{provider_type}": {"post": {"tags": ["alerts"], "summary": "Receive Event", "description": "Receive an alert event from a provider", "operationId": "receive_event_alerts_event__provider_type__post", "parameters": [{"required": true, "schema": {"type": "string", "title": "Provider Type"}, "name": "provider_type", "in": "path"}, {"required": false, "schema": {"type": "string", "title": "Provider Id"}, "name": "provider_id", "in": "query"}, {"required": false, "schema": {"type": "string", "title": "Fingerprint"}, "name": "fingerprint", "in": "query"}], "requestBody": {"content": {"application/json": {"schema": {"anyOf": [{"type": "object"}, {"type": "string", "format": "binary"}], "title": "Event"}}}, "required": true}, "responses": {"202": {"description": "Successful Response", "content": {"application/json": {"schema": {"additionalProperties": {"type": "string"}, "type": "object", "title": "Response Receive Event Alerts Event Provider Type Post"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/alerts/{fingerprint}": {"get": {"tags": ["alerts"], "summary": "Get Alert", "description": "Get alert by fingerprint", "operationId": "get_alert_alerts__fingerprint__get", "parameters": [{"required": true, "schema": {"type": "string", "title": "Fingerprint"}, "name": "fingerprint", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AlertDto"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/alerts/enrich": {"post": {"tags": ["alerts"], "summary": "Enrich Alert", "description": "Enrich an alert", "operationId": "enrich_alert_alerts_enrich_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/EnrichAlertRequestBody"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"additionalProperties": {"type": "string"}, "type": "object", "title": "Response Enrich Alert Alerts Enrich Post"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/alerts/unenrich": {"post": {"tags": ["alerts"], "summary": "Unenrich Alert", "description": "Un-Enrich an alert", "operationId": "unenrich_alert_alerts_unenrich_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/UnEnrichAlertRequestBody"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"additionalProperties": {"type": "string"}, "type": "object", "title": "Response Unenrich Alert Alerts Unenrich Post"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/alerts/search": {"post": {"tags": ["alerts"], "summary": "Search Alerts", "description": "Search alerts", "operationId": "search_alerts_alerts_search_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/SearchAlertsRequest"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/AlertDto"}, "type": "array", "title": "Response Search Alerts Alerts Search Post"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/alerts/audit": {"post": {"tags": ["alerts"], "summary": "Get Multiple Fingerprint Alert Audit", "description": "Get alert timeline audit trail for multiple fingerprints", "operationId": "get_multiple_fingerprint_alert_audit_alerts_audit_post", "requestBody": {"content": {"application/json": {"schema": {"items": {"type": "string"}, "type": "array", "title": "Fingerprints"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/AlertAuditDto"}, "type": "array", "title": "Response Get Multiple Fingerprint Alert Audit Alerts Audit Post"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/alerts/{fingerprint}/audit": {"get": {"tags": ["alerts"], "summary": "Get Alert Audit", "description": "Get alert timeline audit trail", "operationId": "get_alert_audit_alerts__fingerprint__audit_get", "parameters": [{"required": true, "schema": {"type": "string", "title": "Fingerprint"}, "name": "fingerprint", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/AlertAuditDto"}, "type": "array", "title": "Response Get Alert Audit Alerts Fingerprint Audit Get"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/incidents": {"get": {"tags": ["incidents"], "summary": "Get All Incidents", "description": "Get last incidents", "operationId": "get_all_incidents_incidents_get", "parameters": [{"required": false, "schema": {"type": "boolean", "title": "Confirmed", "default": true}, "name": "confirmed", "in": "query"}, {"required": false, "schema": {"type": "integer", "title": "Limit", "default": 25}, "name": "limit", "in": "query"}, {"required": false, "schema": {"type": "integer", "title": "Offset", "default": 0}, "name": "offset", "in": "query"}, {"required": false, "schema": {"allOf": [{"$ref": "#/components/schemas/IncidentSorting"}], "default": "creation_time"}, "name": "sorting", "in": "query"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/IncidentsPaginatedResultsDto"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "post": {"tags": ["incidents"], "summary": "Create Incident Endpoint", "description": "Create new incident", "operationId": "create_incident_endpoint_incidents_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/IncidentDtoIn"}}}, "required": true}, "responses": {"202": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/IncidentDto"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/incidents/{incident_id}": {"get": {"tags": ["incidents"], "summary": "Get Incident", "description": "Get incident by id", "operationId": "get_incident_incidents__incident_id__get", "parameters": [{"required": true, "schema": {"type": "string", "title": "Incident Id"}, "name": "incident_id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/IncidentDto"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "put": {"tags": ["incidents"], "summary": "Update Incident", "description": "Update incident by id", "operationId": "update_incident_incidents__incident_id__put", "parameters": [{"required": true, "schema": {"type": "string", "title": "Incident Id"}, "name": "incident_id", "in": "path"}], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/IncidentDtoIn"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/IncidentDto"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "delete": {"tags": ["incidents"], "summary": "Delete Incident", "description": "Delete incident by incident id", "operationId": "delete_incident_incidents__incident_id__delete", "parameters": [{"required": true, "schema": {"type": "string", "title": "Incident Id"}, "name": "incident_id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/incidents/{incident_id}/alerts": {"get": {"tags": ["incidents"], "summary": "Get Incident Alerts", "description": "Get incident alerts by incident incident id", "operationId": "get_incident_alerts_incidents__incident_id__alerts_get", "parameters": [{"required": true, "schema": {"type": "string", "title": "Incident Id"}, "name": "incident_id", "in": "path"}, {"required": false, "schema": {"type": "integer", "title": "Limit", "default": 25}, "name": "limit", "in": "query"}, {"required": false, "schema": {"type": "integer", "title": "Offset", "default": 0}, "name": "offset", "in": "query"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AlertPaginatedResultsDto"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "post": {"tags": ["incidents"], "summary": "Add Alerts To Incident", "description": "Add alerts to incident", "operationId": "add_alerts_to_incident_incidents__incident_id__alerts_post", "parameters": [{"required": true, "schema": {"type": "string", "title": "Incident Id"}, "name": "incident_id", "in": "path"}], "requestBody": {"content": {"application/json": {"schema": {"items": {"type": "string", "format": "uuid"}, "type": "array", "title": "Alert Ids"}}}, "required": true}, "responses": {"202": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/AlertDto"}, "type": "array", "title": "Response Add Alerts To Incident Incidents Incident Id Alerts Post"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "delete": {"tags": ["incidents"], "summary": "Delete Alerts From Incident", "description": "Delete alerts from incident", "operationId": "delete_alerts_from_incident_incidents__incident_id__alerts_delete", "parameters": [{"required": true, "schema": {"type": "string", "title": "Incident Id"}, "name": "incident_id", "in": "path"}], "requestBody": {"content": {"application/json": {"schema": {"items": {"type": "string", "format": "uuid"}, "type": "array", "title": "Alert Ids"}}}, "required": true}, "responses": {"202": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/AlertDto"}, "type": "array", "title": "Response Delete Alerts From Incident Incidents Incident Id Alerts Delete"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/incidents/{incident_id}/confirm": {"post": {"tags": ["incidents"], "summary": "Confirm Incident", "description": "Confirm predicted incident by id", "operationId": "confirm_incident_incidents__incident_id__confirm_post", "parameters": [{"required": true, "schema": {"type": "string", "title": "Incident Id"}, "name": "incident_id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/IncidentDto"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/incidents/{incident_id}/status": {"post": {"tags": ["incidents"], "summary": "Change Incident Status", "description": "Change incident status", "operationId": "change_incident_status_incidents__incident_id__status_post", "parameters": [{"required": true, "schema": {"type": "string", "title": "Incident Id"}, "name": "incident_id", "in": "path"}], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/IncidentStatusChangeDto"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/IncidentDto"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/settings/webhook": {"get": {"tags": ["settings"], "summary": "Webhook Settings", "description": "Get details about the webhook endpoint (e.g. the API url and an API key)", "operationId": "webhook_settings_settings_webhook_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/WebhookSettings"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/settings/users": {"get": {"tags": ["settings"], "summary": "Get Users", "description": "Get all users", "operationId": "get_users_settings_users_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/User"}, "type": "array", "title": "Response Get Users Settings Users Get"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "post": {"tags": ["settings"], "summary": "Create User", "description": "Create a user", "operationId": "create_user_settings_users_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/keep__api__routes__settings__CreateUserRequest"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/settings/users/{user_email}": {"delete": {"tags": ["settings"], "summary": "Delete User", "description": "Delete a user", "operationId": "delete_user_settings_users__user_email__delete", "parameters": [{"required": true, "schema": {"type": "string", "title": "User Email"}, "name": "user_email", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/settings/smtp": {"get": {"tags": ["settings"], "summary": "Get Smtp Settings", "description": "Get SMTP settings", "operationId": "get_smtp_settings_settings_smtp_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "post": {"tags": ["settings"], "summary": "Update Smtp Settings", "description": "Install or update SMTP settings", "operationId": "update_smtp_settings_settings_smtp_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/SMTPSettings"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "delete": {"tags": ["settings"], "summary": "Delete Smtp Settings", "description": "Delete SMTP settings", "operationId": "delete_smtp_settings_settings_smtp_delete", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/settings/smtp/test": {"post": {"tags": ["settings"], "summary": "Test Smtp Settings", "description": "Test SMTP settings", "operationId": "test_smtp_settings_settings_smtp_test_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/SMTPSettings"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/settings/apikey": {"put": {"tags": ["settings"], "summary": "Update Api Key", "description": "Update API key secret", "operationId": "update_api_key_settings_apikey_put", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "post": {"tags": ["settings"], "summary": "Create Key", "description": "Create API key", "operationId": "create_key_settings_apikey_post", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/settings/apikeys": {"get": {"tags": ["settings"], "summary": "Get Keys", "description": "Get API keys", "operationId": "get_keys_settings_apikeys_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/settings/apikey/{keyId}": {"delete": {"tags": ["settings"], "summary": "Delete Api Key", "description": "Delete API key", "operationId": "delete_api_key_settings_apikey__keyId__delete", "parameters": [{"required": true, "schema": {"type": "string", "title": "Keyid"}, "name": "keyId", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/settings/sso": {"get": {"tags": ["settings"], "summary": "Get Sso Settings", "operationId": "get_sso_settings_settings_sso_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/workflows": {"get": {"tags": ["workflows", "alerts"], "summary": "Get Workflows", "description": "Get workflows", "operationId": "get_workflows_workflows_get", "parameters": [{"required": false, "schema": {"type": "boolean", "title": "Is V2", "default": false}, "name": "is_v2", "in": "query"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"anyOf": [{"items": {"$ref": "#/components/schemas/WorkflowDTO"}, "type": "array"}, {"items": {"type": "object"}, "type": "array"}], "title": "Response Get Workflows Workflows Get"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "post": {"tags": ["workflows", "alerts"], "summary": "Create Workflow", "description": "Create or update a workflow", "operationId": "create_workflow_workflows_post", "requestBody": {"content": {"multipart/form-data": {"schema": {"$ref": "#/components/schemas/Body_create_workflow_workflows_post"}}}, "required": true}, "responses": {"201": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/WorkflowCreateOrUpdateDTO"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/workflows/export": {"get": {"tags": ["workflows", "alerts"], "summary": "Export Workflows", "description": "export all workflow Yamls", "operationId": "export_workflows_workflows_export_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"type": "string"}, "type": "array", "title": "Response Export Workflows Workflows Export Get"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/workflows/{workflow_id}/run": {"post": {"tags": ["workflows", "alerts"], "summary": "Run Workflow", "description": "Run a workflow", "operationId": "run_workflow_workflows__workflow_id__run_post", "parameters": [{"required": true, "schema": {"type": "string", "title": "Workflow Id"}, "name": "workflow_id", "in": "path"}], "requestBody": {"content": {"application/json": {"schema": {"type": "object", "title": "Body"}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"type": "object", "title": "Response Run Workflow Workflows Workflow Id Run Post"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/workflows/test": {"post": {"tags": ["workflows", "alerts"], "summary": "Run Workflow From Definition", "description": "Test run a workflow from a definition", "operationId": "run_workflow_from_definition_workflows_test_post", "requestBody": {"content": {"multipart/form-data": {"schema": {"$ref": "#/components/schemas/Body_run_workflow_from_definition_workflows_test_post"}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"type": "object", "title": "Response Run Workflow From Definition Workflows Test Post"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/workflows/json": {"post": {"tags": ["workflows", "alerts"], "summary": "Create Workflow From Body", "description": "Create or update a workflow", "operationId": "create_workflow_from_body_workflows_json_post", "responses": {"201": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/WorkflowCreateOrUpdateDTO"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/workflows/random-templates": {"get": {"tags": ["workflows", "alerts"], "summary": "Get Random Workflow Templates", "description": "Get random workflow templates", "operationId": "get_random_workflow_templates_workflows_random_templates_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"type": "object"}, "type": "array", "title": "Response Get Random Workflow Templates Workflows Random Templates Get"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/workflows/{workflow_id}": {"get": {"tags": ["workflows", "alerts"], "summary": "Get Workflow By Id", "description": "Get workflow executions by ID", "operationId": "get_workflow_by_id_workflows__workflow_id__get", "parameters": [{"required": true, "schema": {"type": "string", "title": "Workflow Id"}, "name": "workflow_id", "in": "path"}, {"required": false, "schema": {"type": "integer", "title": "Tab", "default": 1}, "name": "tab", "in": "query"}, {"required": false, "schema": {"type": "integer", "title": "Limit", "default": 25}, "name": "limit", "in": "query"}, {"required": false, "schema": {"type": "integer", "title": "Offset", "default": 0}, "name": "offset", "in": "query"}, {"required": false, "schema": {"items": {"type": "string"}, "type": "array", "title": "Status"}, "name": "status", "in": "query"}, {"required": false, "schema": {"items": {"type": "string"}, "type": "array", "title": "Trigger"}, "name": "trigger", "in": "query"}, {"required": false, "schema": {"type": "string", "title": "Execution Id"}, "name": "execution_id", "in": "query"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/WorkflowExecutionsPaginatedResultsDto"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "put": {"tags": ["workflows", "alerts"], "summary": "Update Workflow By Id", "description": "Update a workflow", "operationId": "update_workflow_by_id_workflows__workflow_id__put", "parameters": [{"required": true, "schema": {"type": "string", "title": "Workflow Id"}, "name": "workflow_id", "in": "path"}], "responses": {"201": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/WorkflowCreateOrUpdateDTO"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "delete": {"tags": ["workflows", "alerts"], "summary": "Delete Workflow By Id", "description": "Delete workflow", "operationId": "delete_workflow_by_id_workflows__workflow_id__delete", "parameters": [{"required": true, "schema": {"type": "string", "title": "Workflow Id"}, "name": "workflow_id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/workflows/{workflow_id}/raw": {"get": {"tags": ["workflows", "alerts"], "summary": "Get Raw Workflow By Id", "description": "Get workflow executions by ID", "operationId": "get_raw_workflow_by_id_workflows__workflow_id__raw_get", "parameters": [{"required": true, "schema": {"type": "string", "title": "Workflow Id"}, "name": "workflow_id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"type": "string", "title": "Response Get Raw Workflow By Id Workflows Workflow Id Raw Get"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/workflows/executions": {"get": {"tags": ["workflows", "alerts"], "summary": "Get Workflow Executions By Alert Fingerprint", "description": "Get workflow executions by alert fingerprint", "operationId": "get_workflow_executions_by_alert_fingerprint_workflows_executions_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/WorkflowToAlertExecutionDTO"}, "type": "array", "title": "Response Get Workflow Executions By Alert Fingerprint Workflows Executions Get"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/workflows/{workflow_id}/runs/{workflow_execution_id}": {"get": {"tags": ["workflows", "alerts"], "summary": "Get Workflow Execution Status", "description": "Get a workflow execution status", "operationId": "get_workflow_execution_status_workflows__workflow_id__runs__workflow_execution_id__get", "parameters": [{"required": true, "schema": {"type": "string", "title": "Workflow Execution Id"}, "name": "workflow_execution_id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/WorkflowExecutionDTO"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/workflows/executions/list": {"get": {"tags": ["workflows", "alerts"], "summary": "Get Workflow Executions", "description": "List last workflow executions", "operationId": "get_workflow_executions_workflows_executions_list_get", "parameters": [{"description": "Workflow execution ID", "required": false, "schema": {"type": "string", "title": "Workflow Execution Id", "description": "Workflow execution ID"}, "name": "workflow_execution_id", "in": "query"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/WorkflowExecutionDTO"}, "type": "array", "title": "Response Get Workflow Executions Workflows Executions List Get"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/whoami": {"get": {"tags": ["whoami"], "summary": "Get Tenant Id", "description": "Get tenant id", "operationId": "get_tenant_id_whoami_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"type": "object", "title": "Response Get Tenant Id Whoami Get"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/pusher/auth": {"post": {"tags": ["pusher"], "summary": "Pusher Authentication", "description": "Authenticate a user to a private channel\n\nArgs:\n request (Request): The request object\n tenant_id (str, optional): The tenant ID. Defaults to Depends(verify_bearer_token).\n pusher_client (Pusher, optional): Pusher client. Defaults to Depends(get_pusher_client).\n\nRaises:\n HTTPException: 403 if the user is not allowed to access the channel.\n\nReturns:\n dict: The authentication response.", "operationId": "pusher_authentication_pusher_auth_post", "requestBody": {"content": {"application/x-www-form-urlencoded": {"schema": {"$ref": "#/components/schemas/Body_pusher_authentication_pusher_auth_post"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"type": "object", "title": "Response Pusher Authentication Pusher Auth Post"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/status": {"get": {"tags": ["status"], "summary": "Status", "description": "simple status endpoint", "operationId": "status_status_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"type": "object", "title": "Response Status Status Get"}}}}}}}, "/rules": {"get": {"tags": ["rules"], "summary": "Get Rules", "description": "Get Rules", "operationId": "get_rules_rules_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "post": {"tags": ["rules"], "summary": "Create Rule", "description": "Create Rule", "operationId": "create_rule_rules_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/RuleCreateDto"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/rules/{rule_id}": {"put": {"tags": ["rules"], "summary": "Update Rule", "description": "Update Rule", "operationId": "update_rule_rules__rule_id__put", "parameters": [{"required": true, "schema": {"type": "string", "title": "Rule Id"}, "name": "rule_id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "delete": {"tags": ["rules"], "summary": "Delete Rule", "description": "Delete Rule", "operationId": "delete_rule_rules__rule_id__delete", "parameters": [{"required": true, "schema": {"type": "string", "title": "Rule Id"}, "name": "rule_id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/preset": {"get": {"tags": ["preset"], "summary": "Get Presets", "description": "Get all presets for tenant", "operationId": "get_presets_preset_get", "parameters": [{"required": false, "schema": {"type": "string", "title": "Time Stamp"}, "name": "time_stamp", "in": "query"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/PresetDto"}, "type": "array", "title": "Response Get Presets Preset Get"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "post": {"tags": ["preset"], "summary": "Create Preset", "description": "Create a preset for tenant", "operationId": "create_preset_preset_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/CreateOrUpdatePresetDto"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/PresetDto"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/preset/{uuid}": {"put": {"tags": ["preset"], "summary": "Update Preset", "description": "Update a preset for tenant", "operationId": "update_preset_preset__uuid__put", "parameters": [{"required": true, "schema": {"type": "string", "title": "Uuid"}, "name": "uuid", "in": "path"}], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/CreateOrUpdatePresetDto"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/PresetDto"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "delete": {"tags": ["preset"], "summary": "Delete Preset", "description": "Delete a preset for tenant", "operationId": "delete_preset_preset__uuid__delete", "parameters": [{"required": true, "schema": {"type": "string", "title": "Uuid"}, "name": "uuid", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/preset/{preset_name}/alerts": {"get": {"tags": ["preset"], "summary": "Get Preset Alerts", "description": "Get a preset for tenant", "operationId": "get_preset_alerts_preset__preset_name__alerts_get", "parameters": [{"required": true, "schema": {"type": "string", "title": "Preset Name"}, "name": "preset_name", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {}, "type": "array", "title": "Response Get Preset Alerts Preset Preset Name Alerts Get"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/preset/{preset_id}/tab": {"post": {"tags": ["preset"], "summary": "Create Preset Tab", "description": "Create a tab for a preset", "operationId": "create_preset_tab_preset__preset_id__tab_post", "parameters": [{"required": true, "schema": {"type": "string", "title": "Preset Id"}, "name": "preset_id", "in": "path"}], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/CreatePresetTab"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/preset/{preset_id}/tab/{tab_id}": {"delete": {"tags": ["preset"], "summary": "Delete Tab", "description": "Delete a tab from a preset", "operationId": "delete_tab_preset__preset_id__tab__tab_id__delete", "parameters": [{"required": true, "schema": {"type": "string", "title": "Preset Id"}, "name": "preset_id", "in": "path"}, {"required": true, "schema": {"type": "string", "title": "Tab Id"}, "name": "tab_id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/mapping": {"get": {"tags": ["enrichment", "mapping"], "summary": "Get Rules", "description": "Get all mapping rules", "operationId": "get_rules_mapping_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/MappingRuleDtoOut"}, "type": "array", "title": "Response Get Rules Mapping Get"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "post": {"tags": ["enrichment", "mapping"], "summary": "Create Rule", "description": "Create a new mapping rule", "operationId": "create_rule_mapping_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/MappingRuleDtoIn"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/MappingRule"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/mapping/{rule_id}": {"put": {"tags": ["enrichment", "mapping"], "summary": "Update Rule", "description": "Update an existing rule", "operationId": "update_rule_mapping__rule_id__put", "parameters": [{"required": true, "schema": {"type": "integer", "title": "Rule Id"}, "name": "rule_id", "in": "path"}], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/MappingRuleDtoIn"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/MappingRuleDtoOut"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "delete": {"tags": ["enrichment", "mapping"], "summary": "Delete Rule", "description": "Delete a mapping rule", "operationId": "delete_rule_mapping__rule_id__delete", "parameters": [{"required": true, "schema": {"type": "integer", "title": "Rule Id"}, "name": "rule_id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/auth/groups": {"get": {"tags": ["auth", "groups"], "summary": "Get Groups", "description": "Get all groups", "operationId": "get_groups_auth_groups_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/Group"}, "type": "array", "title": "Response Get Groups Auth Groups Get"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "post": {"tags": ["auth", "groups"], "summary": "Create Group", "description": "Create a group", "operationId": "create_group_auth_groups_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/CreateOrUpdateGroupRequest"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/auth/groups/{group_name}": {"put": {"tags": ["auth", "groups"], "summary": "Update Group", "description": "Update a group", "operationId": "update_group_auth_groups__group_name__put", "parameters": [{"required": true, "schema": {"type": "string", "title": "Group Name"}, "name": "group_name", "in": "path"}], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/CreateOrUpdateGroupRequest"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "delete": {"tags": ["auth", "groups"], "summary": "Delete Group", "description": "Delete a group", "operationId": "delete_group_auth_groups__group_name__delete", "parameters": [{"required": true, "schema": {"type": "string", "title": "Group Name"}, "name": "group_name", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/auth/permissions": {"get": {"tags": ["auth", "permissions"], "summary": "Get Permissions", "description": "Get resources permissions", "operationId": "get_permissions_auth_permissions_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/ResourcePermission"}, "type": "array", "title": "Response Get Permissions Auth Permissions Get"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "post": {"tags": ["auth", "permissions"], "summary": "Create Permissions", "description": "Create permissions for resources", "operationId": "create_permissions_auth_permissions_post", "requestBody": {"content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/ResourcePermission"}, "type": "array", "title": "Resource Permissions", "description": "List of resource permissions"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/auth/permissions/scopes": {"get": {"tags": ["auth", "permissions"], "summary": "Get Scopes", "description": "Get all resources types", "operationId": "get_scopes_auth_permissions_scopes_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"type": "string"}, "type": "array", "title": "Response Get Scopes Auth Permissions Scopes Get"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/auth/roles": {"get": {"tags": ["auth", "roles"], "summary": "Get Roles", "description": "Get roles", "operationId": "get_roles_auth_roles_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/Role"}, "type": "array", "title": "Response Get Roles Auth Roles Get"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "post": {"tags": ["auth", "roles"], "summary": "Create Role", "description": "Create role", "operationId": "create_role_auth_roles_post", "requestBody": {"content": {"application/json": {"schema": {"allOf": [{"$ref": "#/components/schemas/CreateOrUpdateRole"}], "title": "Role", "description": "Role"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/auth/roles/{role_id}": {"put": {"tags": ["auth", "roles"], "summary": "Update Role", "description": "Update role", "operationId": "update_role_auth_roles__role_id__put", "parameters": [{"required": true, "schema": {"type": "string", "title": "Role Id"}, "name": "role_id", "in": "path"}], "requestBody": {"content": {"application/json": {"schema": {"allOf": [{"$ref": "#/components/schemas/CreateOrUpdateRole"}], "title": "Role", "description": "Role"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "delete": {"tags": ["auth", "roles"], "summary": "Delete Role", "description": "Delete role", "operationId": "delete_role_auth_roles__role_id__delete", "parameters": [{"required": true, "schema": {"type": "string", "title": "Role Id"}, "name": "role_id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/auth/users": {"get": {"tags": ["auth", "users"], "summary": "Get Users", "description": "Get all users", "operationId": "get_users_auth_users_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/User"}, "type": "array", "title": "Response Get Users Auth Users Get"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "post": {"tags": ["auth", "users"], "summary": "Create User", "description": "Create a user", "operationId": "create_user_auth_users_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/keep__api__routes__auth__users__CreateUserRequest"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/auth/users/{user_email}": {"put": {"tags": ["auth", "users"], "summary": "Update User", "description": "Update a user", "operationId": "update_user_auth_users__user_email__put", "parameters": [{"required": true, "schema": {"type": "string", "title": "User Email"}, "name": "user_email", "in": "path"}], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/UpdateUserRequest"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "delete": {"tags": ["auth", "users"], "summary": "Delete User", "description": "Delete a user", "operationId": "delete_user_auth_users__user_email__delete", "parameters": [{"required": true, "schema": {"type": "string", "title": "User Email"}, "name": "user_email", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/metrics": {"get": {"tags": ["metrics"], "summary": "Get Metrics", "description": "This endpoint is used by Prometheus to scrape such metrics from the application:\n- alerts_total {incident_name, incident_id} - The total number of alerts per incident.\n- open_incidents_total - The total number of open incidents\n\nPlease note that those metrics are per-tenant and are not designed to be used for the monitoring of the application itself.\n\nExample prometheus configuration:\n```\nscrape_configs:\n- job_name: \"scrape_keep\"\n scrape_interval: 5m # It's important to scrape not too often to avoid rate limiting.\n static_configs:\n - targets: [\"https://api.keephq.dev\"] # Or your own domain.\n authorization:\n type: Bearer\n credentials: \"{Your API Key}\"\n\n # Optional, you can add labels to exported incidents. \n # Label values will be equal to the last incident's alert payload value matching the label.\n # Attention! Don't add \"flaky\" labels which could change from alert to alert within the same incident.\n # Good labels: ['labels.department', 'labels.team'], bad labels: ['labels.severity', 'labels.pod_id']\n # Check Keep -> Feed -> \"extraPayload\" column, it will help in writing labels.\n\n params:\n labels: ['labels.service', 'labels.queue']\n # Will resuld as: \"labels_service\" and \"labels_queue\".\n```", "operationId": "get_metrics_metrics_get", "parameters": [{"required": false, "schema": {"items": {"type": "string"}, "type": "array", "title": "Labels"}, "name": "labels", "in": "query"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/extraction": {"get": {"tags": ["enrichment", "extraction"], "summary": "Get Extraction Rules", "description": "Get all extraction rules", "operationId": "get_extraction_rules_extraction_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/ExtractionRuleDtoOut"}, "type": "array", "title": "Response Get Extraction Rules Extraction Get"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "post": {"tags": ["enrichment", "extraction"], "summary": "Create Extraction Rule", "description": "Create a new extraction rule", "operationId": "create_extraction_rule_extraction_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/ExtractionRuleDtoBase"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ExtractionRuleDtoOut"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/extraction/{rule_id}": {"put": {"tags": ["enrichment", "extraction"], "summary": "Update Extraction Rule", "description": "Update an existing extraction rule", "operationId": "update_extraction_rule_extraction__rule_id__put", "parameters": [{"required": true, "schema": {"type": "integer", "title": "Rule Id"}, "name": "rule_id", "in": "path"}], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/ExtractionRuleDtoBase"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ExtractionRuleDtoOut"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "delete": {"tags": ["enrichment", "extraction"], "summary": "Delete Extraction Rule", "description": "Delete an extraction rule", "operationId": "delete_extraction_rule_extraction__rule_id__delete", "parameters": [{"required": true, "schema": {"type": "integer", "title": "Rule Id"}, "name": "rule_id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/dashboard": {"get": {"tags": ["dashboard"], "summary": "Read Dashboards", "operationId": "read_dashboards_dashboard_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/DashboardResponseDTO"}, "type": "array", "title": "Response Read Dashboards Dashboard Get"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "post": {"tags": ["dashboard"], "summary": "Create Dashboard", "operationId": "create_dashboard_dashboard_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/DashboardCreateDTO"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DashboardResponseDTO"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/dashboard/{dashboard_id}": {"put": {"tags": ["dashboard"], "summary": "Update Dashboard", "operationId": "update_dashboard_dashboard__dashboard_id__put", "parameters": [{"required": true, "schema": {"type": "string", "title": "Dashboard Id"}, "name": "dashboard_id", "in": "path"}], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/DashboardUpdateDTO"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DashboardResponseDTO"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "delete": {"tags": ["dashboard"], "summary": "Delete Dashboard", "operationId": "delete_dashboard_dashboard__dashboard_id__delete", "parameters": [{"required": true, "schema": {"type": "string", "title": "Dashboard Id"}, "name": "dashboard_id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/tags": {"get": {"tags": ["tags"], "summary": "Get Tags", "description": "get tags", "operationId": "get_tags_tags_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"type": "object"}, "type": "array", "title": "Response Get Tags Tags Get"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/maintenance": {"get": {"tags": ["maintenance"], "summary": "Get Maintenance Rules", "description": "Get all maintenance rules", "operationId": "get_maintenance_rules_maintenance_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/MaintenanceRuleRead"}, "type": "array", "title": "Response Get Maintenance Rules Maintenance Get"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "post": {"tags": ["maintenance"], "summary": "Create Maintenance Rule", "description": "Create a new maintenance rule", "operationId": "create_maintenance_rule_maintenance_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/MaintenanceRuleCreate"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/MaintenanceRuleRead"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/maintenance/{rule_id}": {"put": {"tags": ["maintenance"], "summary": "Update Maintenance Rule", "description": "Update an existing maintenance rule", "operationId": "update_maintenance_rule_maintenance__rule_id__put", "parameters": [{"required": true, "schema": {"type": "integer", "title": "Rule Id"}, "name": "rule_id", "in": "path"}], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/MaintenanceRuleCreate"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/MaintenanceRuleRead"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "delete": {"tags": ["maintenance"], "summary": "Delete Maintenance Rule", "description": "Delete a maintenance rule", "operationId": "delete_maintenance_rule_maintenance__rule_id__delete", "parameters": [{"required": true, "schema": {"type": "integer", "title": "Rule Id"}, "name": "rule_id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/topology": {"get": {"tags": ["topology"], "summary": "Get Topology Data", "description": "Get all topology data", "operationId": "get_topology_data_topology_get", "parameters": [{"required": false, "schema": {"type": "string", "title": "Provider Id"}, "name": "provider_id", "in": "query"}, {"required": false, "schema": {"type": "string", "title": "Service Id"}, "name": "service_id", "in": "query"}, {"required": false, "schema": {"type": "string", "title": "Environment"}, "name": "environment", "in": "query"}, {"required": false, "schema": {"type": "boolean", "title": "Include Empty Deps", "default": false}, "name": "include_empty_deps", "in": "query"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/TopologyServiceDtoOut"}, "type": "array", "title": "Response Get Topology Data Topology Get"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/topology/applications": {"get": {"tags": ["topology"], "summary": "Get Applications", "description": "Get all applications", "operationId": "get_applications_topology_applications_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/TopologyApplicationDtoOut"}, "type": "array", "title": "Response Get Applications Topology Applications Get"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "post": {"tags": ["topology"], "summary": "Create Application", "description": "Create a new application", "operationId": "create_application_topology_applications_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/TopologyApplicationDtoIn"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/TopologyApplicationDtoOut"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/topology/applications/{application_id}": {"put": {"tags": ["topology"], "summary": "Update Application", "description": "Update an application", "operationId": "update_application_topology_applications__application_id__put", "parameters": [{"required": true, "schema": {"type": "string", "format": "uuid", "title": "Application Id"}, "name": "application_id", "in": "path"}], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/TopologyApplicationDtoIn"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/TopologyApplicationDtoOut"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "delete": {"tags": ["topology"], "summary": "Delete Application", "description": "Delete an application", "operationId": "delete_application_topology_applications__application_id__delete", "parameters": [{"required": true, "schema": {"type": "string", "format": "uuid", "title": "Application Id"}, "name": "application_id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/deduplications": {"get": {"tags": ["deduplications"], "summary": "Get Deduplications", "description": "Get Deduplications", "operationId": "get_deduplications_deduplications_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "post": {"tags": ["deduplications"], "summary": "Create Deduplication Rule", "description": "Create Deduplication Rule", "operationId": "create_deduplication_rule_deduplications_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/DeduplicationRuleRequestDto"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/deduplications/fields": {"get": {"tags": ["deduplications"], "summary": "Get Deduplication Fields", "description": "Get Optional Fields For Deduplications", "operationId": "get_deduplication_fields_deduplications_fields_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"additionalProperties": {"items": {"type": "string"}, "type": "array"}, "type": "object", "title": "Response Get Deduplication Fields Deduplications Fields Get"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/deduplications/{rule_id}": {"put": {"tags": ["deduplications"], "summary": "Update Deduplication Rule", "description": "Update Deduplication Rule", "operationId": "update_deduplication_rule_deduplications__rule_id__put", "parameters": [{"required": true, "schema": {"type": "string", "title": "Rule Id"}, "name": "rule_id", "in": "path"}], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/DeduplicationRuleRequestDto"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "delete": {"tags": ["deduplications"], "summary": "Delete Deduplication Rule", "description": "Delete Deduplication Rule", "operationId": "delete_deduplication_rule_deduplications__rule_id__delete", "parameters": [{"required": true, "schema": {"type": "string", "title": "Rule Id"}, "name": "rule_id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}}, "components": {"schemas": {"AlertActionType": {"enum": ["alert was triggered", "alert acknowledged", "alert automatically resolved", "alert automatically resolved by API", "alert manually resolved", "alert status manually changed", "alert status changed by API", "alert status undone", "alert enriched by workflow", "alert enriched by mapping rule", "alert was deduplicated", "alert was assigned with ticket", "alert was unassigned from ticket", "alert ticket was updated", "alert enrichments disposed", "alert deleted", "alert enriched", "alert un-enriched", "a comment was added to the alert", "a comment was removed from the alert", "Alert is in maintenance window"], "title": "AlertActionType", "description": "An enumeration."}, "AlertAuditDto": {"properties": {"id": {"type": "string", "title": "Id"}, "timestamp": {"type": "string", "format": "date-time", "title": "Timestamp"}, "fingerprint": {"type": "string", "title": "Fingerprint"}, "action": {"$ref": "#/components/schemas/AlertActionType"}, "user_id": {"type": "string", "title": "User Id"}, "description": {"type": "string", "title": "Description"}}, "type": "object", "required": ["id", "timestamp", "fingerprint", "action", "user_id", "description"], "title": "AlertAuditDto"}, "AlertDto": {"properties": {"id": {"type": "string", "title": "Id"}, "name": {"type": "string", "title": "Name"}, "status": {"$ref": "#/components/schemas/AlertStatus"}, "severity": {"$ref": "#/components/schemas/AlertSeverity"}, "lastReceived": {"type": "string", "title": "Lastreceived"}, "firingStartTime": {"type": "string", "title": "Firingstarttime"}, "environment": {"type": "string", "title": "Environment", "default": "undefined"}, "isFullDuplicate": {"type": "boolean", "title": "Isfullduplicate", "default": false}, "isPartialDuplicate": {"type": "boolean", "title": "Ispartialduplicate", "default": false}, "duplicateReason": {"type": "string", "title": "Duplicatereason"}, "service": {"type": "string", "title": "Service"}, "source": {"items": {"type": "string"}, "type": "array", "title": "Source", "default": []}, "apiKeyRef": {"type": "string", "title": "Apikeyref"}, "message": {"type": "string", "title": "Message"}, "description": {"type": "string", "title": "Description"}, "pushed": {"type": "boolean", "title": "Pushed", "default": false}, "event_id": {"type": "string", "title": "Event Id"}, "url": {"type": "string", "maxLength": 65536, "minLength": 1, "format": "uri", "title": "Url"}, "labels": {"type": "object", "title": "Labels", "default": {}}, "fingerprint": {"type": "string", "title": "Fingerprint"}, "deleted": {"type": "boolean", "title": "Deleted", "default": false}, "dismissUntil": {"type": "string", "title": "Dismissuntil"}, "dismissed": {"type": "boolean", "title": "Dismissed", "default": false}, "assignee": {"type": "string", "title": "Assignee"}, "providerId": {"type": "string", "title": "Providerid"}, "providerType": {"type": "string", "title": "Providertype"}, "note": {"type": "string", "title": "Note"}, "startedAt": {"type": "string", "title": "Startedat"}, "isNoisy": {"type": "boolean", "title": "Isnoisy", "default": false}, "enriched_fields": {"items": {}, "type": "array", "title": "Enriched Fields", "default": []}}, "type": "object", "required": ["name", "status", "severity", "lastReceived"], "title": "AlertDto", "example": {"id": "1234", "name": "Alert name", "status": "firing", "lastReceived": "2021-01-01T00:00:00.000Z", "environment": "production", "service": "backend", "source": ["keep"], "message": "Keep: Alert message", "description": "Keep: Alert description", "severity": "critical", "pushed": true, "event_id": "1234", "url": "https://www.keephq.dev?alertId=1234", "labels": {"key": "value"}, "ticket_url": "https://www.keephq.dev?enrichedTicketId=456", "fingerprint": "1234"}}, "AlertPaginatedResultsDto": {"properties": {"limit": {"type": "integer", "title": "Limit", "default": 25}, "offset": {"type": "integer", "title": "Offset", "default": 0}, "count": {"type": "integer", "title": "Count"}, "items": {"items": {"$ref": "#/components/schemas/AlertDto"}, "type": "array", "title": "Items"}}, "type": "object", "required": ["count", "items"], "title": "AlertPaginatedResultsDto"}, "AlertSeverity": {"enum": ["critical", "high", "warning", "info", "low"], "title": "AlertSeverity", "description": "An enumeration."}, "AlertStatus": {"enum": ["firing", "resolved", "acknowledged", "suppressed", "pending"], "title": "AlertStatus", "description": "An enumeration."}, "Body_create_actions_actions_post": {"properties": {"file": {"type": "string", "format": "binary", "title": "File"}}, "type": "object", "title": "Body_create_actions_actions_post"}, "Body_create_workflow_workflows_post": {"properties": {"file": {"type": "string", "format": "binary", "title": "File"}}, "type": "object", "required": ["file"], "title": "Body_create_workflow_workflows_post"}, "Body_pusher_authentication_pusher_auth_post": {"properties": {"channel_name": {"title": "Channel Name"}, "socket_id": {"title": "Socket Id"}}, "type": "object", "required": ["channel_name", "socket_id"], "title": "Body_pusher_authentication_pusher_auth_post"}, "Body_put_action_actions__action_id__put": {"properties": {"file": {"type": "string", "format": "binary", "title": "File"}}, "type": "object", "required": ["file"], "title": "Body_put_action_actions__action_id__put"}, "Body_run_workflow_from_definition_workflows_test_post": {"properties": {"file": {"type": "string", "format": "binary", "title": "File"}}, "type": "object", "title": "Body_run_workflow_from_definition_workflows_test_post"}, "CreateOrUpdateGroupRequest": {"properties": {"name": {"type": "string", "title": "Name"}, "roles": {"items": {"type": "string"}, "type": "array", "title": "Roles"}, "members": {"items": {"type": "string"}, "type": "array", "title": "Members"}}, "type": "object", "required": ["name", "roles", "members"], "title": "CreateOrUpdateGroupRequest"}, "CreateOrUpdatePresetDto": {"properties": {"name": {"type": "string", "title": "Name"}, "options": {"items": {"$ref": "#/components/schemas/PresetOption"}, "type": "array", "title": "Options"}, "is_private": {"type": "boolean", "title": "Is Private", "default": false}, "is_noisy": {"type": "boolean", "title": "Is Noisy", "default": false}, "tags": {"items": {"$ref": "#/components/schemas/TagDto"}, "type": "array", "title": "Tags", "default": []}}, "type": "object", "required": ["options"], "title": "CreateOrUpdatePresetDto"}, "CreateOrUpdateRole": {"properties": {"name": {"type": "string", "title": "Name"}, "description": {"type": "string", "title": "Description"}, "scopes": {"items": {"type": "string"}, "type": "array", "uniqueItems": true, "title": "Scopes"}}, "type": "object", "title": "CreateOrUpdateRole"}, "CreatePresetTab": {"properties": {"name": {"type": "string", "title": "Name"}, "filter": {"type": "string", "title": "Filter"}}, "type": "object", "required": ["name", "filter"], "title": "CreatePresetTab"}, "DashboardCreateDTO": {"properties": {"dashboard_name": {"type": "string", "title": "Dashboard Name"}, "dashboard_config": {"type": "object", "title": "Dashboard Config"}}, "type": "object", "required": ["dashboard_name", "dashboard_config"], "title": "DashboardCreateDTO"}, "DashboardResponseDTO": {"properties": {"id": {"type": "string", "title": "Id"}, "dashboard_name": {"type": "string", "title": "Dashboard Name"}, "dashboard_config": {"type": "object", "title": "Dashboard Config"}, "created_at": {"type": "string", "format": "date-time", "title": "Created At"}, "updated_at": {"type": "string", "format": "date-time", "title": "Updated At"}}, "type": "object", "required": ["id", "dashboard_name", "dashboard_config", "created_at", "updated_at"], "title": "DashboardResponseDTO"}, "DashboardUpdateDTO": {"properties": {"dashboard_config": {"type": "object", "title": "Dashboard Config"}, "dashboard_name": {"type": "string", "title": "Dashboard Name"}}, "type": "object", "title": "DashboardUpdateDTO"}, "DeduplicationRuleRequestDto": {"properties": {"name": {"type": "string", "title": "Name"}, "description": {"type": "string", "title": "Description"}, "provider_type": {"type": "string", "title": "Provider Type"}, "provider_id": {"type": "string", "title": "Provider Id"}, "fingerprint_fields": {"items": {"type": "string"}, "type": "array", "title": "Fingerprint Fields"}, "full_deduplication": {"type": "boolean", "title": "Full Deduplication", "default": false}, "ignore_fields": {"items": {"type": "string"}, "type": "array", "title": "Ignore Fields"}}, "type": "object", "required": ["name", "provider_type", "fingerprint_fields"], "title": "DeduplicationRuleRequestDto"}, "DeleteRequestBody": {"properties": {"fingerprint": {"type": "string", "title": "Fingerprint"}, "lastReceived": {"type": "string", "title": "Lastreceived"}, "restore": {"type": "boolean", "title": "Restore", "default": false}}, "type": "object", "required": ["fingerprint", "lastReceived"], "title": "DeleteRequestBody"}, "EnrichAlertRequestBody": {"properties": {"enrichments": {"additionalProperties": {"type": "string"}, "type": "object", "title": "Enrichments"}, "fingerprint": {"type": "string", "title": "Fingerprint"}}, "type": "object", "required": ["enrichments", "fingerprint"], "title": "EnrichAlertRequestBody"}, "ExtractionRuleDtoBase": {"properties": {"name": {"type": "string", "title": "Name"}, "description": {"type": "string", "title": "Description"}, "priority": {"type": "integer", "title": "Priority", "default": 0}, "attribute": {"type": "string", "title": "Attribute"}, "condition": {"type": "string", "title": "Condition"}, "disabled": {"type": "boolean", "title": "Disabled", "default": false}, "regex": {"type": "string", "title": "Regex"}, "pre": {"type": "boolean", "title": "Pre", "default": false}}, "type": "object", "required": ["name", "regex"], "title": "ExtractionRuleDtoBase"}, "ExtractionRuleDtoOut": {"properties": {"name": {"type": "string", "title": "Name"}, "description": {"type": "string", "title": "Description"}, "priority": {"type": "integer", "title": "Priority", "default": 0}, "attribute": {"type": "string", "title": "Attribute"}, "condition": {"type": "string", "title": "Condition"}, "disabled": {"type": "boolean", "title": "Disabled", "default": false}, "regex": {"type": "string", "title": "Regex"}, "pre": {"type": "boolean", "title": "Pre", "default": false}, "id": {"type": "integer", "title": "Id"}, "created_by": {"type": "string", "title": "Created By"}, "created_at": {"type": "string", "format": "date-time", "title": "Created At"}, "updated_by": {"type": "string", "title": "Updated By"}, "updated_at": {"type": "string", "format": "date-time", "title": "Updated At"}}, "type": "object", "required": ["name", "regex", "id", "created_at"], "title": "ExtractionRuleDtoOut"}, "Group": {"properties": {"id": {"type": "string", "title": "Id"}, "name": {"type": "string", "title": "Name"}, "roles": {"items": {"type": "string"}, "type": "array", "title": "Roles", "default": []}, "members": {"items": {"type": "string"}, "type": "array", "title": "Members", "default": []}, "memberCount": {"type": "integer", "title": "Membercount", "default": 0}}, "type": "object", "required": ["id", "name"], "title": "Group"}, "HTTPValidationError": {"properties": {"detail": {"items": {"$ref": "#/components/schemas/ValidationError"}, "type": "array", "title": "Detail"}}, "type": "object", "title": "HTTPValidationError"}, "IncidentDto": {"properties": {"user_generated_name": {"type": "string", "title": "User Generated Name"}, "assignee": {"type": "string", "title": "Assignee"}, "user_summary": {"type": "string", "title": "User Summary"}, "id": {"type": "string", "format": "uuid", "title": "Id"}, "start_time": {"type": "string", "format": "date-time", "title": "Start Time"}, "last_seen_time": {"type": "string", "format": "date-time", "title": "Last Seen Time"}, "end_time": {"type": "string", "format": "date-time", "title": "End Time"}, "alerts_count": {"type": "integer", "title": "Alerts Count"}, "alert_sources": {"items": {"type": "string"}, "type": "array", "title": "Alert Sources"}, "severity": {"$ref": "#/components/schemas/IncidentSeverity"}, "status": {"allOf": [{"$ref": "#/components/schemas/IncidentStatus"}], "default": "firing"}, "services": {"items": {"type": "string"}, "type": "array", "title": "Services"}, "is_predicted": {"type": "boolean", "title": "Is Predicted"}, "is_confirmed": {"type": "boolean", "title": "Is Confirmed"}, "generated_summary": {"type": "string", "title": "Generated Summary"}, "ai_generated_name": {"type": "string", "title": "Ai Generated Name"}, "rule_fingerprint": {"type": "string", "title": "Rule Fingerprint"}}, "type": "object", "required": ["id", "alerts_count", "alert_sources", "severity", "services", "is_predicted", "is_confirmed"], "title": "IncidentDto", "example": {"id": "c2509cb3-6168-4347-b83b-a41da9df2d5b", "name": "Incident name", "user_summary": "Keep: Incident description", "status": "firing"}}, "IncidentDtoIn": {"properties": {"user_generated_name": {"type": "string", "title": "User Generated Name"}, "assignee": {"type": "string", "title": "Assignee"}, "user_summary": {"type": "string", "title": "User Summary"}}, "type": "object", "title": "IncidentDtoIn", "example": {"id": "c2509cb3-6168-4347-b83b-a41da9df2d5b", "name": "Incident name", "user_summary": "Keep: Incident description", "status": "firing"}}, "IncidentSeverity": {"enum": ["critical", "high", "warning", "info", "low"], "title": "IncidentSeverity", "description": "An enumeration."}, "IncidentSorting": {"enum": ["creation_time", "start_time", "last_seen_time", "severity", "status", "alerts_count", "-creation_time", "-start_time", "-last_seen_time", "-severity", "-status", "-alerts_count"], "title": "IncidentSorting", "description": "An enumeration."}, "IncidentStatus": {"enum": ["firing", "resolved", "acknowledged"], "title": "IncidentStatus", "description": "An enumeration."}, "IncidentStatusChangeDto": {"properties": {"status": {"$ref": "#/components/schemas/IncidentStatus"}, "comment": {"type": "string", "title": "Comment"}}, "type": "object", "required": ["status"], "title": "IncidentStatusChangeDto"}, "IncidentsPaginatedResultsDto": {"properties": {"limit": {"type": "integer", "title": "Limit", "default": 25}, "offset": {"type": "integer", "title": "Offset", "default": 0}, "count": {"type": "integer", "title": "Count"}, "items": {"items": {"$ref": "#/components/schemas/IncidentDto"}, "type": "array", "title": "Items"}}, "type": "object", "required": ["count", "items"], "title": "IncidentsPaginatedResultsDto"}, "MaintenanceRuleCreate": {"properties": {"name": {"type": "string", "title": "Name"}, "description": {"type": "string", "title": "Description"}, "cel_query": {"type": "string", "title": "Cel Query"}, "start_time": {"type": "string", "format": "date-time", "title": "Start Time"}, "duration_seconds": {"type": "integer", "title": "Duration Seconds"}, "suppress": {"type": "boolean", "title": "Suppress", "default": false}, "enabled": {"type": "boolean", "title": "Enabled", "default": true}}, "type": "object", "required": ["name", "cel_query", "start_time"], "title": "MaintenanceRuleCreate"}, "MaintenanceRuleRead": {"properties": {"id": {"type": "integer", "title": "Id"}, "name": {"type": "string", "title": "Name"}, "description": {"type": "string", "title": "Description"}, "created_by": {"type": "string", "title": "Created By"}, "cel_query": {"type": "string", "title": "Cel Query"}, "start_time": {"type": "string", "format": "date-time", "title": "Start Time"}, "end_time": {"type": "string", "format": "date-time", "title": "End Time"}, "duration_seconds": {"type": "integer", "title": "Duration Seconds"}, "updated_at": {"type": "string", "format": "date-time", "title": "Updated At"}, "suppress": {"type": "boolean", "title": "Suppress", "default": false}, "enabled": {"type": "boolean", "title": "Enabled", "default": true}}, "type": "object", "required": ["id", "name", "created_by", "cel_query", "start_time", "end_time"], "title": "MaintenanceRuleRead"}, "MappingRule": {"properties": {"id": {"type": "integer", "title": "Id"}, "tenant_id": {"type": "string", "title": "Tenant Id"}, "priority": {"type": "integer", "title": "Priority", "default": 0}, "name": {"type": "string", "maxLength": 255, "title": "Name"}, "description": {"type": "string", "maxLength": 2048, "title": "Description"}, "file_name": {"type": "string", "maxLength": 255, "title": "File Name"}, "created_by": {"type": "string", "maxLength": 255, "title": "Created By"}, "created_at": {"type": "string", "format": "date-time", "title": "Created At"}, "disabled": {"type": "boolean", "title": "Disabled", "default": false}, "override": {"type": "boolean", "title": "Override", "default": true}, "condition": {"type": "string", "maxLength": 2000, "title": "Condition"}, "type": {"type": "string", "maxLength": 255, "title": "Type"}, "matchers": {"items": {"type": "string"}, "type": "array", "title": "Matchers"}, "rows": {"items": {"type": "object"}, "type": "array", "title": "Rows"}, "updated_by": {"type": "string", "maxLength": 255, "title": "Updated By"}, "last_updated_at": {"type": "string", "format": "date-time", "title": "Last Updated At"}}, "type": "object", "required": ["tenant_id", "name", "type", "matchers"], "title": "MappingRule"}, "MappingRuleDtoIn": {"properties": {"name": {"type": "string", "title": "Name"}, "description": {"type": "string", "title": "Description"}, "file_name": {"type": "string", "title": "File Name"}, "priority": {"type": "integer", "title": "Priority", "default": 0}, "matchers": {"items": {"type": "string"}, "type": "array", "title": "Matchers"}, "type": {"type": "string", "enum": ["csv", "topology"], "title": "Type", "default": "csv"}, "rows": {"items": {"type": "object"}, "type": "array", "title": "Rows"}}, "type": "object", "required": ["name", "matchers"], "title": "MappingRuleDtoIn"}, "MappingRuleDtoOut": {"properties": {"name": {"type": "string", "title": "Name"}, "description": {"type": "string", "title": "Description"}, "file_name": {"type": "string", "title": "File Name"}, "priority": {"type": "integer", "title": "Priority", "default": 0}, "matchers": {"items": {"type": "string"}, "type": "array", "title": "Matchers"}, "type": {"type": "string", "enum": ["csv", "topology"], "title": "Type", "default": "csv"}, "id": {"type": "integer", "title": "Id"}, "created_by": {"type": "string", "title": "Created By"}, "created_at": {"type": "string", "format": "date-time", "title": "Created At"}, "attributes": {"items": {"type": "string"}, "type": "array", "title": "Attributes", "default": []}, "updated_by": {"type": "string", "title": "Updated By"}, "last_updated_at": {"type": "string", "format": "date-time", "title": "Last Updated At"}}, "type": "object", "required": ["name", "matchers", "id", "created_at"], "title": "MappingRuleDtoOut"}, "PermissionEntity": {"properties": {"id": {"type": "string", "title": "Id"}, "type": {"type": "string", "title": "Type"}}, "type": "object", "required": ["id", "type"], "title": "PermissionEntity"}, "PresetDto": {"properties": {"id": {"type": "string", "format": "uuid", "title": "Id"}, "name": {"type": "string", "title": "Name"}, "options": {"items": {}, "type": "array", "title": "Options", "default": []}, "created_by": {"type": "string", "title": "Created By"}, "is_private": {"type": "boolean", "title": "Is Private", "default": false}, "is_noisy": {"type": "boolean", "title": "Is Noisy", "default": false}, "should_do_noise_now": {"type": "boolean", "title": "Should Do Noise Now", "default": false}, "alerts_count": {"type": "integer", "title": "Alerts Count", "default": 0}, "static": {"type": "boolean", "title": "Static", "default": false}, "tags": {"items": {"$ref": "#/components/schemas/TagDto"}, "type": "array", "title": "Tags", "default": []}}, "type": "object", "required": ["id", "name"], "title": "PresetDto"}, "PresetOption": {"properties": {"label": {"type": "string", "title": "Label"}, "value": {"anyOf": [{"type": "string"}, {"type": "object"}], "title": "Value"}}, "type": "object", "required": ["label", "value"], "title": "PresetOption"}, "PresetSearchQuery": {"properties": {"cel_query": {"type": "string", "minLength": 1, "title": "Cel Query"}, "sql_query": {"type": "object", "title": "Sql Query"}, "limit": {"type": "integer", "minimum": 0.0, "title": "Limit", "default": 1000}, "timeframe": {"type": "integer", "minimum": 0.0, "title": "Timeframe", "default": 0}}, "type": "object", "required": ["cel_query", "sql_query"], "title": "PresetSearchQuery"}, "ProviderDTO": {"properties": {"type": {"type": "string", "title": "Type"}, "id": {"type": "string", "title": "Id"}, "name": {"type": "string", "title": "Name"}, "installed": {"type": "boolean", "title": "Installed"}}, "type": "object", "required": ["type", "name", "installed"], "title": "ProviderDTO"}, "ProviderWebhookSettings": {"properties": {"webhookDescription": {"type": "string", "title": "Webhookdescription"}, "webhookTemplate": {"type": "string", "title": "Webhooktemplate"}, "webhookMarkdown": {"type": "string", "title": "Webhookmarkdown"}}, "type": "object", "required": ["webhookTemplate"], "title": "ProviderWebhookSettings"}, "ResourcePermission": {"properties": {"resource_id": {"type": "string", "title": "Resource Id"}, "resource_name": {"type": "string", "title": "Resource Name"}, "resource_type": {"type": "string", "title": "Resource Type"}, "permissions": {"items": {"$ref": "#/components/schemas/PermissionEntity"}, "type": "array", "title": "Permissions"}}, "type": "object", "required": ["resource_id", "resource_name", "resource_type", "permissions"], "title": "ResourcePermission"}, "Role": {"properties": {"id": {"type": "string", "title": "Id"}, "name": {"type": "string", "title": "Name"}, "description": {"type": "string", "title": "Description"}, "scopes": {"items": {"type": "string"}, "type": "array", "uniqueItems": true, "title": "Scopes"}, "predefined": {"type": "boolean", "title": "Predefined", "default": true}}, "type": "object", "required": ["id", "name", "description", "scopes"], "title": "Role"}, "RuleCreateDto": {"properties": {"ruleName": {"type": "string", "title": "Rulename"}, "sqlQuery": {"type": "object", "title": "Sqlquery"}, "celQuery": {"type": "string", "title": "Celquery"}, "timeframeInSeconds": {"type": "integer", "title": "Timeframeinseconds"}, "timeUnit": {"type": "string", "title": "Timeunit"}, "groupingCriteria": {"items": {}, "type": "array", "title": "Groupingcriteria", "default": []}, "groupDescription": {"type": "string", "title": "Groupdescription"}, "requireApprove": {"type": "boolean", "title": "Requireapprove", "default": false}}, "type": "object", "required": ["ruleName", "sqlQuery", "celQuery", "timeframeInSeconds", "timeUnit"], "title": "RuleCreateDto"}, "SMTPSettings": {"properties": {"host": {"type": "string", "title": "Host"}, "port": {"type": "integer", "title": "Port"}, "from_email": {"type": "string", "title": "From Email"}, "username": {"type": "string", "title": "Username"}, "password": {"type": "string", "format": "password", "title": "Password", "writeOnly": true}, "secure": {"type": "boolean", "title": "Secure", "default": true}, "to_email": {"type": "string", "title": "To Email", "default": "keep@example.com"}}, "type": "object", "required": ["host", "port", "from_email"], "title": "SMTPSettings", "example": {"host": "smtp.example.com", "port": 587, "username": "user@example.com", "password": "password", "secure": true, "from_email": "noreply@example.com", "to_email": ""}}, "SearchAlertsRequest": {"properties": {"query": {"$ref": "#/components/schemas/PresetSearchQuery"}, "timeframe": {"type": "integer", "title": "Timeframe"}}, "type": "object", "required": ["query", "timeframe"], "title": "SearchAlertsRequest"}, "TagDto": {"properties": {"id": {"type": "string", "title": "Id"}, "name": {"type": "string", "title": "Name"}}, "type": "object", "required": ["name"], "title": "TagDto"}, "TopologyApplicationDtoIn": {"properties": {"id": {"type": "string", "format": "uuid", "title": "Id"}, "name": {"type": "string", "title": "Name"}, "description": {"type": "string", "title": "Description"}, "services": {"items": {"$ref": "#/components/schemas/TopologyServiceDtoIn"}, "type": "array", "title": "Services", "default": []}}, "type": "object", "required": ["name"], "title": "TopologyApplicationDtoIn"}, "TopologyApplicationDtoOut": {"properties": {"id": {"type": "string", "format": "uuid", "title": "Id"}, "name": {"type": "string", "title": "Name"}, "description": {"type": "string", "title": "Description"}, "services": {"items": {"$ref": "#/components/schemas/TopologyApplicationServiceDto"}, "type": "array", "title": "Services", "default": []}}, "type": "object", "required": ["id", "name"], "title": "TopologyApplicationDtoOut"}, "TopologyApplicationServiceDto": {"properties": {"id": {"type": "integer", "title": "Id"}, "name": {"type": "string", "title": "Name"}, "service": {"type": "string", "title": "Service"}}, "type": "object", "required": ["id", "name", "service"], "title": "TopologyApplicationServiceDto"}, "TopologyServiceDependencyDto": {"properties": {"serviceId": {"type": "integer", "title": "Serviceid"}, "serviceName": {"type": "string", "title": "Servicename"}, "protocol": {"type": "string", "title": "Protocol", "default": "unknown"}}, "type": "object", "required": ["serviceId", "serviceName"], "title": "TopologyServiceDependencyDto"}, "TopologyServiceDtoIn": {"properties": {"id": {"type": "integer", "title": "Id"}}, "type": "object", "required": ["id"], "title": "TopologyServiceDtoIn"}, "TopologyServiceDtoOut": {"properties": {"source_provider_id": {"type": "string", "title": "Source Provider Id"}, "repository": {"type": "string", "title": "Repository"}, "tags": {"items": {"type": "string"}, "type": "array", "title": "Tags"}, "service": {"type": "string", "title": "Service"}, "display_name": {"type": "string", "title": "Display Name"}, "environment": {"type": "string", "title": "Environment", "default": "unknown"}, "description": {"type": "string", "title": "Description"}, "team": {"type": "string", "title": "Team"}, "email": {"type": "string", "title": "Email"}, "slack": {"type": "string", "title": "Slack"}, "ip_address": {"type": "string", "title": "Ip Address"}, "mac_address": {"type": "string", "title": "Mac Address"}, "category": {"type": "string", "title": "Category"}, "manufacturer": {"type": "string", "title": "Manufacturer"}, "id": {"type": "integer", "title": "Id"}, "dependencies": {"items": {"$ref": "#/components/schemas/TopologyServiceDependencyDto"}, "type": "array", "title": "Dependencies"}, "application_ids": {"items": {"type": "string", "format": "uuid"}, "type": "array", "title": "Application Ids"}, "updated_at": {"type": "string", "format": "date-time", "title": "Updated At"}}, "type": "object", "required": ["service", "display_name", "id", "dependencies", "application_ids"], "title": "TopologyServiceDtoOut"}, "UnEnrichAlertRequestBody": {"properties": {"enrichments": {"items": {"type": "string"}, "type": "array", "title": "Enrichments"}, "fingerprint": {"type": "string", "title": "Fingerprint"}}, "type": "object", "required": ["enrichments", "fingerprint"], "title": "UnEnrichAlertRequestBody"}, "UpdateUserRequest": {"properties": {"username": {"type": "string", "title": "Username"}, "password": {"type": "string", "title": "Password"}, "role": {"type": "string", "title": "Role"}, "groups": {"items": {"type": "string"}, "type": "array", "title": "Groups"}}, "type": "object", "title": "UpdateUserRequest"}, "User": {"properties": {"email": {"type": "string", "title": "Email"}, "name": {"type": "string", "title": "Name"}, "role": {"type": "string", "title": "Role"}, "picture": {"type": "string", "title": "Picture"}, "created_at": {"type": "string", "title": "Created At"}, "last_login": {"type": "string", "title": "Last Login"}, "ldap": {"type": "boolean", "title": "Ldap", "default": false}, "groups": {"items": {"$ref": "#/components/schemas/Group"}, "type": "array", "title": "Groups", "default": []}}, "type": "object", "required": ["email", "name", "created_at"], "title": "User"}, "ValidationError": {"properties": {"loc": {"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, "type": "array", "title": "Location"}, "msg": {"type": "string", "title": "Message"}, "type": {"type": "string", "title": "Error Type"}}, "type": "object", "required": ["loc", "msg", "type"], "title": "ValidationError"}, "WebhookSettings": {"properties": {"webhookApi": {"type": "string", "title": "Webhookapi"}, "apiKey": {"type": "string", "title": "Apikey"}, "modelSchema": {"type": "object", "title": "Modelschema"}}, "type": "object", "required": ["webhookApi", "apiKey", "modelSchema"], "title": "WebhookSettings"}, "WorkflowCreateOrUpdateDTO": {"properties": {"workflow_id": {"type": "string", "title": "Workflow Id"}, "status": {"type": "string", "enum": ["created", "updated"], "title": "Status"}, "revision": {"type": "integer", "title": "Revision", "default": 1}}, "type": "object", "required": ["workflow_id", "status"], "title": "WorkflowCreateOrUpdateDTO"}, "WorkflowDTO": {"properties": {"id": {"type": "string", "title": "Id"}, "name": {"type": "string", "title": "Name", "default": "Workflow file doesn't contain name"}, "description": {"type": "string", "title": "Description", "default": "Workflow file doesn't contain description"}, "created_by": {"type": "string", "title": "Created By"}, "creation_time": {"type": "string", "format": "date-time", "title": "Creation Time"}, "triggers": {"items": {"type": "object"}, "type": "array", "title": "Triggers"}, "interval": {"type": "integer", "title": "Interval"}, "disabled": {"type": "boolean", "title": "Disabled", "default": false}, "last_execution_time": {"type": "string", "format": "date-time", "title": "Last Execution Time"}, "last_execution_status": {"type": "string", "title": "Last Execution Status"}, "providers": {"items": {"$ref": "#/components/schemas/ProviderDTO"}, "type": "array", "title": "Providers"}, "workflow_raw": {"type": "string", "title": "Workflow Raw"}, "revision": {"type": "integer", "title": "Revision", "default": 1}, "last_updated": {"type": "string", "format": "date-time", "title": "Last Updated"}, "invalid": {"type": "boolean", "title": "Invalid", "default": false}, "last_executions": {"items": {"type": "object"}, "type": "array", "title": "Last Executions"}, "last_execution_started": {"type": "string", "format": "date-time", "title": "Last Execution Started"}, "provisioned": {"type": "boolean", "title": "Provisioned", "default": false}, "provisioned_file": {"type": "string", "title": "Provisioned File"}}, "type": "object", "required": ["id", "created_by", "creation_time", "providers", "workflow_raw"], "title": "WorkflowDTO"}, "WorkflowExecutionDTO": {"properties": {"id": {"type": "string", "title": "Id"}, "workflow_id": {"type": "string", "title": "Workflow Id"}, "started": {"type": "string", "format": "date-time", "title": "Started"}, "triggered_by": {"type": "string", "title": "Triggered By"}, "status": {"type": "string", "title": "Status"}, "logs": {"items": {"$ref": "#/components/schemas/WorkflowExecutionLogsDTO"}, "type": "array", "title": "Logs"}, "error": {"type": "string", "title": "Error"}, "execution_time": {"type": "number", "title": "Execution Time"}, "results": {"type": "object", "title": "Results"}}, "type": "object", "required": ["id", "workflow_id", "started", "triggered_by", "status"], "title": "WorkflowExecutionDTO"}, "WorkflowExecutionLogsDTO": {"properties": {"id": {"type": "integer", "title": "Id"}, "timestamp": {"type": "string", "format": "date-time", "title": "Timestamp"}, "message": {"type": "string", "title": "Message"}, "context": {"type": "object", "title": "Context"}}, "type": "object", "required": ["id", "timestamp", "message"], "title": "WorkflowExecutionLogsDTO"}, "WorkflowExecutionsPaginatedResultsDto": {"properties": {"limit": {"type": "integer", "title": "Limit", "default": 25}, "offset": {"type": "integer", "title": "Offset", "default": 0}, "count": {"type": "integer", "title": "Count"}, "items": {"items": {"$ref": "#/components/schemas/WorkflowExecutionDTO"}, "type": "array", "title": "Items"}, "passCount": {"type": "integer", "title": "Passcount", "default": 0}, "avgDuration": {"type": "number", "title": "Avgduration", "default": 0.0}, "workflow": {"$ref": "#/components/schemas/WorkflowDTO"}, "failCount": {"type": "integer", "title": "Failcount", "default": 0}}, "type": "object", "required": ["count", "items"], "title": "WorkflowExecutionsPaginatedResultsDto"}, "WorkflowToAlertExecutionDTO": {"properties": {"workflow_id": {"type": "string", "title": "Workflow Id"}, "workflow_execution_id": {"type": "string", "title": "Workflow Execution Id"}, "alert_fingerprint": {"type": "string", "title": "Alert Fingerprint"}, "workflow_status": {"type": "string", "title": "Workflow Status"}, "workflow_started": {"type": "string", "format": "date-time", "title": "Workflow Started"}}, "type": "object", "required": ["workflow_id", "workflow_execution_id", "alert_fingerprint", "workflow_status", "workflow_started"], "title": "WorkflowToAlertExecutionDTO"}, "keep__api__routes__auth__users__CreateUserRequest": {"properties": {"username": {"type": "string", "title": "Username"}, "name": {"type": "string", "title": "Name"}, "password": {"type": "string", "title": "Password"}, "role": {"type": "string", "title": "Role"}, "groups": {"items": {"type": "string"}, "type": "array", "title": "Groups"}}, "type": "object", "required": ["username"], "title": "CreateUserRequest"}, "keep__api__routes__settings__CreateUserRequest": {"properties": {"username": {"type": "string", "title": "Username"}, "password": {"type": "string", "title": "Password"}, "role": {"type": "string", "title": "Role"}}, "type": "object", "required": ["username", "role"], "title": "CreateUserRequest"}}, "securitySchemes": {"API Key": {"type": "apiKey", "in": "header", "name": "X-API-KEY"}, "HTTPBasic": {"type": "http", "scheme": "basic"}, "OAuth2PasswordBearer": {"type": "oauth2", "flows": {"password": {"scopes": {}, "tokenUrl": "token"}}}}}} \ No newline at end of file +{"openapi": "3.0.2", "info": {"title": "Keep API", "description": "Rest API powering https://platform.keephq.dev and friends \ud83c\udfc4\u200d\u2640\ufe0f", "version": "0.1.0"}, "paths": {"/providers": {"get": {"tags": ["providers"], "summary": "Get Providers", "operationId": "get_providers_providers_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/providers/export": {"get": {"tags": ["providers"], "summary": "Get Installed Providers", "description": "export all installed providers", "operationId": "get_installed_providers_providers_export_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/providers/{provider_type}/{provider_id}/configured-alerts": {"get": {"tags": ["providers"], "summary": "Get Alerts Configuration", "description": "Get alerts configuration from a provider", "operationId": "get_alerts_configuration_providers__provider_type___provider_id__configured_alerts_get", "parameters": [{"required": true, "schema": {"type": "string", "title": "Provider Type"}, "name": "provider_type", "in": "path"}, {"required": true, "schema": {"type": "string", "title": "Provider Id"}, "name": "provider_id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {}, "type": "array", "title": "Response Get Alerts Configuration Providers Provider Type Provider Id Configured Alerts Get"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/providers/{provider_type}/{provider_id}/logs": {"get": {"tags": ["providers"], "summary": "Get Logs", "description": "Get logs from a provider", "operationId": "get_logs_providers__provider_type___provider_id__logs_get", "parameters": [{"required": true, "schema": {"type": "string", "title": "Provider Type"}, "name": "provider_type", "in": "path"}, {"required": true, "schema": {"type": "string", "title": "Provider Id"}, "name": "provider_id", "in": "path"}, {"required": false, "schema": {"type": "integer", "title": "Limit", "default": 5}, "name": "limit", "in": "query"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {}, "type": "array", "title": "Response Get Logs Providers Provider Type Provider Id Logs Get"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/providers/{provider_type}/schema": {"get": {"tags": ["providers"], "summary": "Get Alerts Schema", "description": "Get the provider's API schema used to push alerts configuration", "operationId": "get_alerts_schema_providers__provider_type__schema_get", "parameters": [{"required": true, "schema": {"type": "string", "title": "Provider Type"}, "name": "provider_type", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"type": "object", "title": "Response Get Alerts Schema Providers Provider Type Schema Get"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/providers/{provider_type}/{provider_id}/alerts/count": {"get": {"tags": ["providers"], "summary": "Get Alert Count", "description": "Get number of alerts a specific provider has received (in a specific time time period or ever)", "operationId": "get_alert_count_providers__provider_type___provider_id__alerts_count_get", "parameters": [{"required": true, "schema": {"type": "string", "title": "Provider Type"}, "name": "provider_type", "in": "path"}, {"required": true, "schema": {"type": "string", "title": "Provider Id"}, "name": "provider_id", "in": "path"}, {"required": true, "schema": {"type": "boolean", "title": "Ever"}, "name": "ever", "in": "query"}, {"required": false, "schema": {"type": "string", "format": "date-time", "title": "Start Time"}, "name": "start_time", "in": "query"}, {"required": false, "schema": {"type": "string", "format": "date-time", "title": "End Time"}, "name": "end_time", "in": "query"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/providers/{provider_type}/{provider_id}/alerts": {"post": {"tags": ["providers"], "summary": "Add Alert", "description": "Push new alerts to the provider", "operationId": "add_alert_providers__provider_type___provider_id__alerts_post", "parameters": [{"required": true, "schema": {"type": "string", "title": "Provider Type"}, "name": "provider_type", "in": "path"}, {"required": true, "schema": {"type": "string", "title": "Provider Id"}, "name": "provider_id", "in": "path"}, {"required": false, "schema": {"type": "string", "title": "Alert Id"}, "name": "alert_id", "in": "query"}], "requestBody": {"content": {"application/json": {"schema": {"type": "object", "title": "Alert"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/providers/test": {"post": {"tags": ["providers"], "summary": "Test Provider", "description": "Test a provider's alert retrieval", "operationId": "test_provider_providers_test_post", "requestBody": {"content": {"application/json": {"schema": {"type": "object", "title": "Provider Info"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/providers/{provider_type}/{provider_id}": {"delete": {"tags": ["providers"], "summary": "Delete Provider", "operationId": "delete_provider_providers__provider_type___provider_id__delete", "parameters": [{"required": true, "schema": {"type": "string", "title": "Provider Type"}, "name": "provider_type", "in": "path"}, {"required": true, "schema": {"type": "string", "title": "Provider Id"}, "name": "provider_id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/providers/{provider_id}/scopes": {"post": {"tags": ["providers"], "summary": "Validate Provider Scopes", "description": "Validate provider scopes", "operationId": "validate_provider_scopes_providers__provider_id__scopes_post", "parameters": [{"required": true, "schema": {"type": "string", "title": "Provider Id"}, "name": "provider_id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"additionalProperties": {"anyOf": [{"type": "boolean"}, {"type": "string"}]}, "type": "object", "title": "Response Validate Provider Scopes Providers Provider Id Scopes Post"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/providers/{provider_id}": {"put": {"tags": ["providers"], "summary": "Update Provider", "description": "Update provider", "operationId": "update_provider_providers__provider_id__put", "parameters": [{"required": true, "schema": {"type": "string", "title": "Provider Id"}, "name": "provider_id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/providers/install": {"post": {"tags": ["providers"], "summary": "Install Provider", "operationId": "install_provider_providers_install_post", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/providers/install/oauth2/{provider_type}": {"post": {"tags": ["providers"], "summary": "Install Provider Oauth2", "operationId": "install_provider_oauth2_providers_install_oauth2__provider_type__post", "parameters": [{"required": true, "schema": {"type": "string", "title": "Provider Type"}, "name": "provider_type", "in": "path"}], "requestBody": {"content": {"application/json": {"schema": {"type": "object", "title": "Provider Info"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/providers/{provider_id}/invoke/{method}": {"post": {"tags": ["providers"], "summary": "Invoke Provider Method", "description": "Invoke provider special method", "operationId": "invoke_provider_method_providers__provider_id__invoke__method__post", "parameters": [{"required": true, "schema": {"type": "string", "title": "Provider Id"}, "name": "provider_id", "in": "path"}, {"required": true, "schema": {"type": "string", "title": "Method"}, "name": "method", "in": "path"}], "requestBody": {"content": {"application/json": {"schema": {"type": "object", "title": "Method Params"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/providers/install/webhook/{provider_type}/{provider_id}": {"post": {"tags": ["providers"], "summary": "Install Provider Webhook", "operationId": "install_provider_webhook_providers_install_webhook__provider_type___provider_id__post", "parameters": [{"required": true, "schema": {"type": "string", "title": "Provider Type"}, "name": "provider_type", "in": "path"}, {"required": true, "schema": {"type": "string", "title": "Provider Id"}, "name": "provider_id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/providers/{provider_type}/webhook": {"get": {"tags": ["providers"], "summary": "Get Webhook Settings", "operationId": "get_webhook_settings_providers__provider_type__webhook_get", "parameters": [{"required": true, "schema": {"type": "string", "title": "Provider Type"}, "name": "provider_type", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ProviderWebhookSettings"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/actions": {"get": {"tags": ["actions"], "summary": "Get Actions", "description": "Get all actions", "operationId": "get_actions_actions_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "post": {"tags": ["actions"], "summary": "Create Actions", "description": "Create new actions by uploading a file", "operationId": "create_actions_actions_post", "requestBody": {"content": {"multipart/form-data": {"schema": {"$ref": "#/components/schemas/Body_create_actions_actions_post"}}}}, "responses": {"201": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/actions/{action_id}": {"put": {"tags": ["actions"], "summary": "Put Action", "description": "Update an action", "operationId": "put_action_actions__action_id__put", "parameters": [{"required": true, "schema": {"type": "string", "title": "Action Id"}, "name": "action_id", "in": "path"}], "requestBody": {"content": {"multipart/form-data": {"schema": {"$ref": "#/components/schemas/Body_put_action_actions__action_id__put"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "delete": {"tags": ["actions"], "summary": "Delete Action", "description": "Delete an action", "operationId": "delete_action_actions__action_id__delete", "parameters": [{"required": true, "schema": {"type": "string", "title": "Action Id"}, "name": "action_id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/healthcheck": {"get": {"tags": ["healthcheck"], "summary": "Healthcheck", "description": "simple healthcheck endpoint", "operationId": "healthcheck_healthcheck_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"type": "object", "title": "Response Healthcheck Healthcheck Get"}}}}}}}, "/alerts": {"get": {"tags": ["alerts"], "summary": "Get All Alerts", "description": "Get last alerts occurrence", "operationId": "get_all_alerts_alerts_get", "parameters": [{"required": false, "schema": {"type": "integer", "title": "Limit", "default": 1000}, "name": "limit", "in": "query"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/AlertDto"}, "type": "array", "title": "Response Get All Alerts Alerts Get"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "delete": {"tags": ["alerts"], "summary": "Delete Alert", "description": "Delete alert by finerprint and last received time", "operationId": "delete_alert_alerts_delete", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/DeleteRequestBody"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"additionalProperties": {"type": "string"}, "type": "object", "title": "Response Delete Alert Alerts Delete"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/alerts/{fingerprint}/history": {"get": {"tags": ["alerts"], "summary": "Get Alert History", "description": "Get alert history", "operationId": "get_alert_history_alerts__fingerprint__history_get", "parameters": [{"required": true, "schema": {"type": "string", "title": "Fingerprint"}, "name": "fingerprint", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/AlertDto"}, "type": "array", "title": "Response Get Alert History Alerts Fingerprint History Get"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/alerts/{fingerprint}/assign/{last_received}": {"post": {"tags": ["alerts"], "summary": "Assign Alert", "description": "Assign alert to user", "operationId": "assign_alert_alerts__fingerprint__assign__last_received__post", "parameters": [{"required": true, "schema": {"type": "string", "title": "Fingerprint"}, "name": "fingerprint", "in": "path"}, {"required": true, "schema": {"type": "string", "title": "Last Received"}, "name": "last_received", "in": "path"}, {"required": false, "schema": {"type": "boolean", "title": "Unassign", "default": false}, "name": "unassign", "in": "query"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"additionalProperties": {"type": "string"}, "type": "object", "title": "Response Assign Alert Alerts Fingerprint Assign Last Received Post"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/alerts/event": {"post": {"tags": ["alerts"], "summary": "Receive Generic Event", "description": "Receive a generic alert event", "operationId": "receive_generic_event_alerts_event_post", "parameters": [{"required": false, "schema": {"type": "string", "title": "Fingerprint"}, "name": "fingerprint", "in": "query"}], "requestBody": {"content": {"application/json": {"schema": {"anyOf": [{"$ref": "#/components/schemas/AlertDto"}, {"items": {"$ref": "#/components/schemas/AlertDto"}, "type": "array"}, {"type": "object"}], "title": "Event"}}}, "required": true}, "responses": {"202": {"description": "Successful Response", "content": {"application/json": {"schema": {"anyOf": [{"$ref": "#/components/schemas/AlertDto"}, {"items": {"$ref": "#/components/schemas/AlertDto"}, "type": "array"}], "title": "Response Receive Generic Event Alerts Event Post"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/alerts/event/netdata": {"get": {"tags": ["alerts"], "summary": "Webhook Challenge", "description": "Helper function to complete Netdata webhook challenge", "operationId": "webhook_challenge_alerts_event_netdata_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}}}}, "/alerts/event/{provider_type}": {"post": {"tags": ["alerts"], "summary": "Receive Event", "description": "Receive an alert event from a provider", "operationId": "receive_event_alerts_event__provider_type__post", "parameters": [{"required": true, "schema": {"type": "string", "title": "Provider Type"}, "name": "provider_type", "in": "path"}, {"required": false, "schema": {"type": "string", "title": "Provider Id"}, "name": "provider_id", "in": "query"}, {"required": false, "schema": {"type": "string", "title": "Fingerprint"}, "name": "fingerprint", "in": "query"}], "responses": {"202": {"description": "Successful Response", "content": {"application/json": {"schema": {"additionalProperties": {"type": "string"}, "type": "object", "title": "Response Receive Event Alerts Event Provider Type Post"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/alerts/{fingerprint}": {"get": {"tags": ["alerts"], "summary": "Get Alert", "description": "Get alert by fingerprint", "operationId": "get_alert_alerts__fingerprint__get", "parameters": [{"required": true, "schema": {"type": "string", "title": "Fingerprint"}, "name": "fingerprint", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AlertDto"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/alerts/enrich": {"post": {"tags": ["alerts"], "summary": "Enrich Alert", "description": "Enrich an alert", "operationId": "enrich_alert_alerts_enrich_post", "parameters": [{"description": "Dispose on new alert", "required": false, "schema": {"type": "boolean", "title": "Dispose On New Alert", "description": "Dispose on new alert", "default": false}, "name": "dispose_on_new_alert", "in": "query"}], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/EnrichAlertRequestBody"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"additionalProperties": {"type": "string"}, "type": "object", "title": "Response Enrich Alert Alerts Enrich Post"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/alerts/unenrich": {"post": {"tags": ["alerts"], "summary": "Unenrich Alert", "description": "Un-Enrich an alert", "operationId": "unenrich_alert_alerts_unenrich_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/UnEnrichAlertRequestBody"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"additionalProperties": {"type": "string"}, "type": "object", "title": "Response Unenrich Alert Alerts Unenrich Post"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/alerts/search": {"post": {"tags": ["alerts"], "summary": "Search Alerts", "description": "Search alerts", "operationId": "search_alerts_alerts_search_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/SearchAlertsRequest"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/AlertDto"}, "type": "array", "title": "Response Search Alerts Alerts Search Post"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/alerts/audit": {"post": {"tags": ["alerts"], "summary": "Get Multiple Fingerprint Alert Audit", "description": "Get alert timeline audit trail for multiple fingerprints", "operationId": "get_multiple_fingerprint_alert_audit_alerts_audit_post", "requestBody": {"content": {"application/json": {"schema": {"items": {"type": "string"}, "type": "array", "title": "Fingerprints"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/AlertAuditDto"}, "type": "array", "title": "Response Get Multiple Fingerprint Alert Audit Alerts Audit Post"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/alerts/{fingerprint}/audit": {"get": {"tags": ["alerts"], "summary": "Get Alert Audit", "description": "Get alert timeline audit trail", "operationId": "get_alert_audit_alerts__fingerprint__audit_get", "parameters": [{"required": true, "schema": {"type": "string", "title": "Fingerprint"}, "name": "fingerprint", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/AlertAuditDto"}, "type": "array", "title": "Response Get Alert Audit Alerts Fingerprint Audit Get"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/alerts/quality/metrics": {"get": {"tags": ["alerts"], "summary": "Get Alert Quality", "description": "Get alert quality", "operationId": "get_alert_quality_alerts_quality_metrics_get", "parameters": [{"required": false, "schema": {"items": {"type": "string"}, "type": "array", "title": "Fields", "default": []}, "name": "fields", "in": "query"}, {"required": false, "schema": {"type": "string", "title": "Time Stamp"}, "name": "time_stamp", "in": "query"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/incidents": {"get": {"tags": ["incidents"], "summary": "Get All Incidents", "description": "Get last incidents", "operationId": "get_all_incidents_incidents_get", "parameters": [{"required": false, "schema": {"type": "boolean", "title": "Confirmed", "default": true}, "name": "confirmed", "in": "query"}, {"required": false, "schema": {"type": "integer", "title": "Limit", "default": 25}, "name": "limit", "in": "query"}, {"required": false, "schema": {"type": "integer", "title": "Offset", "default": 0}, "name": "offset", "in": "query"}, {"required": false, "schema": {"allOf": [{"$ref": "#/components/schemas/IncidentSorting"}], "default": "creation_time"}, "name": "sorting", "in": "query"}, {"required": false, "schema": {"items": {"$ref": "#/components/schemas/IncidentStatus"}, "type": "array"}, "name": "status", "in": "query"}, {"required": false, "schema": {"items": {"$ref": "#/components/schemas/IncidentSeverity"}, "type": "array"}, "name": "severity", "in": "query"}, {"required": false, "schema": {"items": {"type": "string"}, "type": "array", "title": "Assignees"}, "name": "assignees", "in": "query"}, {"required": false, "schema": {"items": {"type": "string"}, "type": "array", "title": "Sources"}, "name": "sources", "in": "query"}, {"required": false, "schema": {"items": {"type": "string"}, "type": "array", "title": "Affected Services"}, "name": "affected_services", "in": "query"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/IncidentsPaginatedResultsDto"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "post": {"tags": ["incidents"], "summary": "Create Incident Endpoint", "description": "Create new incident", "operationId": "create_incident_endpoint_incidents_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/IncidentDtoIn"}}}, "required": true}, "responses": {"202": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/IncidentDto"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/incidents/meta": {"get": {"tags": ["incidents"], "summary": "Get Incidents Meta", "description": "Get incidents' metadata for filtering", "operationId": "get_incidents_meta_incidents_meta_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/IncidentListFilterParamsDto"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/incidents/{incident_id}": {"get": {"tags": ["incidents"], "summary": "Get Incident", "description": "Get incident by id", "operationId": "get_incident_incidents__incident_id__get", "parameters": [{"required": true, "schema": {"type": "string", "format": "uuid", "title": "Incident Id"}, "name": "incident_id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/IncidentDto"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "put": {"tags": ["incidents"], "summary": "Update Incident", "description": "Update incident by id", "operationId": "update_incident_incidents__incident_id__put", "parameters": [{"required": true, "schema": {"type": "string", "format": "uuid", "title": "Incident Id"}, "name": "incident_id", "in": "path"}, {"description": "Whether the incident update request was generated by AI", "required": false, "schema": {"type": "boolean", "title": "Generatedbyai", "description": "Whether the incident update request was generated by AI", "default": false}, "name": "generatedByAi", "in": "query"}], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/IncidentDtoIn"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/IncidentDto"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "delete": {"tags": ["incidents"], "summary": "Delete Incident", "description": "Delete incident by incident id", "operationId": "delete_incident_incidents__incident_id__delete", "parameters": [{"required": true, "schema": {"type": "string", "format": "uuid", "title": "Incident Id"}, "name": "incident_id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/incidents/merge": {"post": {"tags": ["incidents"], "summary": "Merge Incidents", "description": "Merge incidents", "operationId": "merge_incidents_incidents_merge_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/MergeIncidentsRequestDto"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/MergeIncidentsResponseDto"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/incidents/{incident_id}/alerts": {"get": {"tags": ["incidents"], "summary": "Get Incident Alerts", "description": "Get incident alerts by incident incident id", "operationId": "get_incident_alerts_incidents__incident_id__alerts_get", "parameters": [{"required": true, "schema": {"type": "string", "format": "uuid", "title": "Incident Id"}, "name": "incident_id", "in": "path"}, {"required": false, "schema": {"type": "integer", "title": "Limit", "default": 25}, "name": "limit", "in": "query"}, {"required": false, "schema": {"type": "integer", "title": "Offset", "default": 0}, "name": "offset", "in": "query"}, {"required": false, "schema": {"type": "boolean", "title": "Include Unlinked", "default": false}, "name": "include_unlinked", "in": "query"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AlertWithIncidentLinkMetadataPaginatedResultsDto"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "post": {"tags": ["incidents"], "summary": "Add Alerts To Incident", "description": "Add alerts to incident", "operationId": "add_alerts_to_incident_incidents__incident_id__alerts_post", "parameters": [{"required": true, "schema": {"type": "string", "format": "uuid", "title": "Incident Id"}, "name": "incident_id", "in": "path"}, {"required": false, "schema": {"type": "boolean", "title": "Is Created By Ai", "default": false}, "name": "is_created_by_ai", "in": "query"}], "requestBody": {"content": {"application/json": {"schema": {"items": {"type": "string", "format": "uuid"}, "type": "array", "title": "Alert Ids"}}}, "required": true}, "responses": {"202": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/AlertDto"}, "type": "array", "title": "Response Add Alerts To Incident Incidents Incident Id Alerts Post"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "delete": {"tags": ["incidents"], "summary": "Delete Alerts From Incident", "description": "Delete alerts from incident", "operationId": "delete_alerts_from_incident_incidents__incident_id__alerts_delete", "parameters": [{"required": true, "schema": {"type": "string", "format": "uuid", "title": "Incident Id"}, "name": "incident_id", "in": "path"}], "requestBody": {"content": {"application/json": {"schema": {"items": {"type": "string", "format": "uuid"}, "type": "array", "title": "Alert Ids"}}}, "required": true}, "responses": {"202": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/AlertDto"}, "type": "array", "title": "Response Delete Alerts From Incident Incidents Incident Id Alerts Delete"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/incidents/{incident_id}/future_incidents": {"get": {"tags": ["incidents"], "summary": "Get Future Incidents For An Incident", "description": "Get same incidents linked to this one", "operationId": "get_future_incidents_for_an_incident_incidents__incident_id__future_incidents_get", "parameters": [{"required": true, "schema": {"type": "string", "title": "Incident Id"}, "name": "incident_id", "in": "path"}, {"required": false, "schema": {"type": "integer", "title": "Limit", "default": 25}, "name": "limit", "in": "query"}, {"required": false, "schema": {"type": "integer", "title": "Offset", "default": 0}, "name": "offset", "in": "query"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/IncidentsPaginatedResultsDto"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/incidents/{incident_id}/workflows": {"get": {"tags": ["incidents"], "summary": "Get Incident Workflows", "description": "Get incident workflows by incident id", "operationId": "get_incident_workflows_incidents__incident_id__workflows_get", "parameters": [{"required": true, "schema": {"type": "string", "format": "uuid", "title": "Incident Id"}, "name": "incident_id", "in": "path"}, {"required": false, "schema": {"type": "integer", "title": "Limit", "default": 25}, "name": "limit", "in": "query"}, {"required": false, "schema": {"type": "integer", "title": "Offset", "default": 0}, "name": "offset", "in": "query"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/WorkflowExecutionsPaginatedResultsDto"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/incidents/{incident_id}/confirm": {"post": {"tags": ["incidents"], "summary": "Confirm Incident", "description": "Confirm predicted incident by id", "operationId": "confirm_incident_incidents__incident_id__confirm_post", "parameters": [{"required": true, "schema": {"type": "string", "format": "uuid", "title": "Incident Id"}, "name": "incident_id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/IncidentDto"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/incidents/{incident_id}/status": {"post": {"tags": ["incidents"], "summary": "Change Incident Status", "description": "Change incident status", "operationId": "change_incident_status_incidents__incident_id__status_post", "parameters": [{"required": true, "schema": {"type": "string", "format": "uuid", "title": "Incident Id"}, "name": "incident_id", "in": "path"}], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/IncidentStatusChangeDto"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/IncidentDto"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/incidents/{incident_id}/comment": {"post": {"tags": ["incidents"], "summary": "Add Comment", "description": "Add incident audit activity", "operationId": "add_comment_incidents__incident_id__comment_post", "parameters": [{"required": true, "schema": {"type": "string", "format": "uuid", "title": "Incident Id"}, "name": "incident_id", "in": "path"}], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/IncidentStatusChangeDto"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AlertAudit"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/settings/webhook": {"get": {"tags": ["settings"], "summary": "Webhook Settings", "description": "Get details about the webhook endpoint (e.g. the API url and an API key)", "operationId": "webhook_settings_settings_webhook_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/WebhookSettings"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/settings/smtp": {"get": {"tags": ["settings"], "summary": "Get Smtp Settings", "description": "Get SMTP settings", "operationId": "get_smtp_settings_settings_smtp_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "post": {"tags": ["settings"], "summary": "Update Smtp Settings", "description": "Install or update SMTP settings", "operationId": "update_smtp_settings_settings_smtp_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/SMTPSettings"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "delete": {"tags": ["settings"], "summary": "Delete Smtp Settings", "description": "Delete SMTP settings", "operationId": "delete_smtp_settings_settings_smtp_delete", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/settings/smtp/test": {"post": {"tags": ["settings"], "summary": "Test Smtp Settings", "description": "Test SMTP settings", "operationId": "test_smtp_settings_settings_smtp_test_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/SMTPSettings"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/settings/apikey": {"put": {"tags": ["settings"], "summary": "Update Api Key", "description": "Update API key secret", "operationId": "update_api_key_settings_apikey_put", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "post": {"tags": ["settings"], "summary": "Create Key", "description": "Create API key", "operationId": "create_key_settings_apikey_post", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/settings/apikeys": {"get": {"tags": ["settings"], "summary": "Get Keys", "description": "Get API keys", "operationId": "get_keys_settings_apikeys_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/settings/apikey/{keyId}": {"delete": {"tags": ["settings"], "summary": "Delete Api Key", "description": "Delete API key", "operationId": "delete_api_key_settings_apikey__keyId__delete", "parameters": [{"required": true, "schema": {"type": "string", "title": "Keyid"}, "name": "keyId", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/settings/sso": {"get": {"tags": ["settings"], "summary": "Get Sso Settings", "operationId": "get_sso_settings_settings_sso_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/workflows": {"get": {"tags": ["workflows", "alerts"], "summary": "Get Workflows", "description": "Get workflows", "operationId": "get_workflows_workflows_get", "parameters": [{"required": false, "schema": {"type": "boolean", "title": "Is V2", "default": false}, "name": "is_v2", "in": "query"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"anyOf": [{"items": {"$ref": "#/components/schemas/WorkflowDTO"}, "type": "array"}, {"items": {"type": "object"}, "type": "array"}], "title": "Response Get Workflows Workflows Get"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "post": {"tags": ["workflows", "alerts"], "summary": "Create Workflow", "description": "Create or update a workflow", "operationId": "create_workflow_workflows_post", "requestBody": {"content": {"multipart/form-data": {"schema": {"$ref": "#/components/schemas/Body_create_workflow_workflows_post"}}}, "required": true}, "responses": {"201": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/WorkflowCreateOrUpdateDTO"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/workflows/export": {"get": {"tags": ["workflows", "alerts"], "summary": "Export Workflows", "description": "export all workflow Yamls", "operationId": "export_workflows_workflows_export_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"type": "string"}, "type": "array", "title": "Response Export Workflows Workflows Export Get"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/workflows/{workflow_id}/run": {"post": {"tags": ["workflows", "alerts"], "summary": "Run Workflow", "description": "Run a workflow", "operationId": "run_workflow_workflows__workflow_id__run_post", "parameters": [{"required": true, "schema": {"type": "string", "title": "Workflow Id"}, "name": "workflow_id", "in": "path"}], "requestBody": {"content": {"application/json": {"schema": {"type": "object", "title": "Body"}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"type": "object", "title": "Response Run Workflow Workflows Workflow Id Run Post"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/workflows/test": {"post": {"tags": ["workflows", "alerts"], "summary": "Run Workflow From Definition", "description": "Test run a workflow from a definition", "operationId": "run_workflow_from_definition_workflows_test_post", "requestBody": {"content": {"multipart/form-data": {"schema": {"$ref": "#/components/schemas/Body_run_workflow_from_definition_workflows_test_post"}}}}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"type": "object", "title": "Response Run Workflow From Definition Workflows Test Post"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/workflows/json": {"post": {"tags": ["workflows", "alerts"], "summary": "Create Workflow From Body", "description": "Create or update a workflow", "operationId": "create_workflow_from_body_workflows_json_post", "responses": {"201": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/WorkflowCreateOrUpdateDTO"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/workflows/random-templates": {"get": {"tags": ["workflows", "alerts"], "summary": "Get Random Workflow Templates", "description": "Get random workflow templates", "operationId": "get_random_workflow_templates_workflows_random_templates_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"type": "object"}, "type": "array", "title": "Response Get Random Workflow Templates Workflows Random Templates Get"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/workflows/{workflow_id}": {"get": {"tags": ["workflows", "alerts"], "summary": "Get Workflow By Id", "description": "Get workflow executions by ID", "operationId": "get_workflow_by_id_workflows__workflow_id__get", "parameters": [{"required": true, "schema": {"type": "string", "title": "Workflow Id"}, "name": "workflow_id", "in": "path"}, {"required": false, "schema": {"type": "integer", "title": "Tab", "default": 1}, "name": "tab", "in": "query"}, {"required": false, "schema": {"type": "integer", "title": "Limit", "default": 25}, "name": "limit", "in": "query"}, {"required": false, "schema": {"type": "integer", "title": "Offset", "default": 0}, "name": "offset", "in": "query"}, {"required": false, "schema": {"items": {"type": "string"}, "type": "array", "title": "Status"}, "name": "status", "in": "query"}, {"required": false, "schema": {"items": {"type": "string"}, "type": "array", "title": "Trigger"}, "name": "trigger", "in": "query"}, {"required": false, "schema": {"type": "string", "title": "Execution Id"}, "name": "execution_id", "in": "query"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/WorkflowExecutionsPaginatedResultsDto"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "put": {"tags": ["workflows", "alerts"], "summary": "Update Workflow By Id", "description": "Update a workflow", "operationId": "update_workflow_by_id_workflows__workflow_id__put", "parameters": [{"required": true, "schema": {"type": "string", "title": "Workflow Id"}, "name": "workflow_id", "in": "path"}], "responses": {"201": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/WorkflowCreateOrUpdateDTO"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "delete": {"tags": ["workflows", "alerts"], "summary": "Delete Workflow By Id", "description": "Delete workflow", "operationId": "delete_workflow_by_id_workflows__workflow_id__delete", "parameters": [{"required": true, "schema": {"type": "string", "title": "Workflow Id"}, "name": "workflow_id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/workflows/{workflow_id}/raw": {"get": {"tags": ["workflows", "alerts"], "summary": "Get Raw Workflow By Id", "description": "Get workflow executions by ID", "operationId": "get_raw_workflow_by_id_workflows__workflow_id__raw_get", "parameters": [{"required": true, "schema": {"type": "string", "title": "Workflow Id"}, "name": "workflow_id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"type": "string", "title": "Response Get Raw Workflow By Id Workflows Workflow Id Raw Get"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/workflows/executions": {"get": {"tags": ["workflows", "alerts"], "summary": "Get Workflow Executions By Alert Fingerprint", "description": "Get workflow executions by alert fingerprint", "operationId": "get_workflow_executions_by_alert_fingerprint_workflows_executions_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/WorkflowToAlertExecutionDTO"}, "type": "array", "title": "Response Get Workflow Executions By Alert Fingerprint Workflows Executions Get"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/workflows/{workflow_id}/runs/{workflow_execution_id}": {"get": {"tags": ["workflows", "alerts"], "summary": "Get Workflow Execution Status", "description": "Get a workflow execution status", "operationId": "get_workflow_execution_status_workflows__workflow_id__runs__workflow_execution_id__get", "parameters": [{"required": true, "schema": {"type": "string", "title": "Workflow Execution Id"}, "name": "workflow_execution_id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/WorkflowExecutionDTO"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/whoami": {"get": {"tags": ["whoami"], "summary": "Get Tenant Id", "description": "Get tenant id", "operationId": "get_tenant_id_whoami_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"type": "object", "title": "Response Get Tenant Id Whoami Get"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/pusher/auth": {"post": {"tags": ["pusher"], "summary": "Pusher Authentication", "description": "Authenticate a user to a private channel\n\nArgs:\n request (Request): The request object\n tenant_id (str, optional): The tenant ID. Defaults to Depends(verify_bearer_token).\n pusher_client (Pusher, optional): Pusher client. Defaults to Depends(get_pusher_client).\n\nRaises:\n HTTPException: 403 if the user is not allowed to access the channel.\n\nReturns:\n dict: The authentication response.", "operationId": "pusher_authentication_pusher_auth_post", "requestBody": {"content": {"application/x-www-form-urlencoded": {"schema": {"$ref": "#/components/schemas/Body_pusher_authentication_pusher_auth_post"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"type": "object", "title": "Response Pusher Authentication Pusher Auth Post"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/status": {"get": {"tags": ["status"], "summary": "Status", "description": "simple status endpoint", "operationId": "status_status_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"type": "object", "title": "Response Status Status Get"}}}}}}}, "/rules": {"get": {"tags": ["rules"], "summary": "Get Rules", "description": "Get Rules", "operationId": "get_rules_rules_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "post": {"tags": ["rules"], "summary": "Create Rule", "description": "Create Rule", "operationId": "create_rule_rules_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/RuleCreateDto"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/rules/{rule_id}": {"put": {"tags": ["rules"], "summary": "Update Rule", "description": "Update Rule", "operationId": "update_rule_rules__rule_id__put", "parameters": [{"required": true, "schema": {"type": "string", "title": "Rule Id"}, "name": "rule_id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "delete": {"tags": ["rules"], "summary": "Delete Rule", "description": "Delete Rule", "operationId": "delete_rule_rules__rule_id__delete", "parameters": [{"required": true, "schema": {"type": "string", "title": "Rule Id"}, "name": "rule_id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/preset": {"get": {"tags": ["preset"], "summary": "Get Presets", "description": "Get all presets for tenant", "operationId": "get_presets_preset_get", "parameters": [{"required": false, "schema": {"type": "string", "title": "Time Stamp"}, "name": "time_stamp", "in": "query"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/PresetDto"}, "type": "array", "title": "Response Get Presets Preset Get"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "post": {"tags": ["preset"], "summary": "Create Preset", "description": "Create a preset for tenant", "operationId": "create_preset_preset_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/CreateOrUpdatePresetDto"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/PresetDto"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/preset/{uuid}": {"put": {"tags": ["preset"], "summary": "Update Preset", "description": "Update a preset for tenant", "operationId": "update_preset_preset__uuid__put", "parameters": [{"required": true, "schema": {"type": "string", "title": "Uuid"}, "name": "uuid", "in": "path"}], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/CreateOrUpdatePresetDto"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/PresetDto"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "delete": {"tags": ["preset"], "summary": "Delete Preset", "description": "Delete a preset for tenant", "operationId": "delete_preset_preset__uuid__delete", "parameters": [{"required": true, "schema": {"type": "string", "title": "Uuid"}, "name": "uuid", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/preset/{preset_name}/alerts": {"get": {"tags": ["preset"], "summary": "Get Preset Alerts", "description": "Get a preset for tenant", "operationId": "get_preset_alerts_preset__preset_name__alerts_get", "parameters": [{"required": true, "schema": {"type": "string", "title": "Preset Name"}, "name": "preset_name", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {}, "type": "array", "title": "Response Get Preset Alerts Preset Preset Name Alerts Get"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/preset/{preset_id}/tab": {"post": {"tags": ["preset"], "summary": "Create Preset Tab", "description": "Create a tab for a preset", "operationId": "create_preset_tab_preset__preset_id__tab_post", "parameters": [{"required": true, "schema": {"type": "string", "title": "Preset Id"}, "name": "preset_id", "in": "path"}], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/CreatePresetTab"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/preset/{preset_id}/tab/{tab_id}": {"delete": {"tags": ["preset"], "summary": "Delete Tab", "description": "Delete a tab from a preset", "operationId": "delete_tab_preset__preset_id__tab__tab_id__delete", "parameters": [{"required": true, "schema": {"type": "string", "title": "Preset Id"}, "name": "preset_id", "in": "path"}, {"required": true, "schema": {"type": "string", "title": "Tab Id"}, "name": "tab_id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/mapping": {"get": {"tags": ["enrichment", "mapping"], "summary": "Get Rules", "description": "Get all mapping rules", "operationId": "get_rules_mapping_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/MappingRuleDtoOut"}, "type": "array", "title": "Response Get Rules Mapping Get"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "post": {"tags": ["enrichment", "mapping"], "summary": "Create Rule", "description": "Create a new mapping rule", "operationId": "create_rule_mapping_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/MappingRuleDtoIn"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/MappingRule"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/mapping/{rule_id}": {"put": {"tags": ["enrichment", "mapping"], "summary": "Update Rule", "description": "Update an existing rule", "operationId": "update_rule_mapping__rule_id__put", "parameters": [{"required": true, "schema": {"type": "integer", "title": "Rule Id"}, "name": "rule_id", "in": "path"}], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/MappingRuleDtoIn"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/MappingRuleDtoOut"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "delete": {"tags": ["enrichment", "mapping"], "summary": "Delete Rule", "description": "Delete a mapping rule", "operationId": "delete_rule_mapping__rule_id__delete", "parameters": [{"required": true, "schema": {"type": "integer", "title": "Rule Id"}, "name": "rule_id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/auth/groups": {"get": {"tags": ["auth", "groups"], "summary": "Get Groups", "description": "Get all groups", "operationId": "get_groups_auth_groups_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/Group"}, "type": "array", "title": "Response Get Groups Auth Groups Get"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "post": {"tags": ["auth", "groups"], "summary": "Create Group", "description": "Create a group", "operationId": "create_group_auth_groups_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/CreateOrUpdateGroupRequest"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/auth/groups/{group_name}": {"put": {"tags": ["auth", "groups"], "summary": "Update Group", "description": "Update a group", "operationId": "update_group_auth_groups__group_name__put", "parameters": [{"required": true, "schema": {"type": "string", "title": "Group Name"}, "name": "group_name", "in": "path"}], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/CreateOrUpdateGroupRequest"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "delete": {"tags": ["auth", "groups"], "summary": "Delete Group", "description": "Delete a group", "operationId": "delete_group_auth_groups__group_name__delete", "parameters": [{"required": true, "schema": {"type": "string", "title": "Group Name"}, "name": "group_name", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/auth/permissions": {"get": {"tags": ["auth", "permissions"], "summary": "Get Permissions", "description": "Get resources permissions", "operationId": "get_permissions_auth_permissions_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/ResourcePermission"}, "type": "array", "title": "Response Get Permissions Auth Permissions Get"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "post": {"tags": ["auth", "permissions"], "summary": "Create Permissions", "description": "Create permissions for resources", "operationId": "create_permissions_auth_permissions_post", "requestBody": {"content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/ResourcePermission"}, "type": "array", "title": "Resource Permissions", "description": "List of resource permissions"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/auth/permissions/scopes": {"get": {"tags": ["auth", "permissions"], "summary": "Get Scopes", "description": "Get all resources types", "operationId": "get_scopes_auth_permissions_scopes_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"type": "string"}, "type": "array", "title": "Response Get Scopes Auth Permissions Scopes Get"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/auth/roles": {"get": {"tags": ["auth", "roles"], "summary": "Get Roles", "description": "Get roles", "operationId": "get_roles_auth_roles_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/Role"}, "type": "array", "title": "Response Get Roles Auth Roles Get"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "post": {"tags": ["auth", "roles"], "summary": "Create Role", "description": "Create role", "operationId": "create_role_auth_roles_post", "requestBody": {"content": {"application/json": {"schema": {"allOf": [{"$ref": "#/components/schemas/CreateOrUpdateRole"}], "title": "Role", "description": "Role"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/auth/roles/{role_id}": {"put": {"tags": ["auth", "roles"], "summary": "Update Role", "description": "Update role", "operationId": "update_role_auth_roles__role_id__put", "parameters": [{"required": true, "schema": {"type": "string", "title": "Role Id"}, "name": "role_id", "in": "path"}], "requestBody": {"content": {"application/json": {"schema": {"allOf": [{"$ref": "#/components/schemas/CreateOrUpdateRole"}], "title": "Role", "description": "Role"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "delete": {"tags": ["auth", "roles"], "summary": "Delete Role", "description": "Delete role", "operationId": "delete_role_auth_roles__role_id__delete", "parameters": [{"required": true, "schema": {"type": "string", "title": "Role Id"}, "name": "role_id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/auth/users": {"get": {"tags": ["auth", "users"], "summary": "Get Users", "description": "Get all users", "operationId": "get_users_auth_users_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/User"}, "type": "array", "title": "Response Get Users Auth Users Get"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "post": {"tags": ["auth", "users"], "summary": "Create User", "description": "Create a user", "operationId": "create_user_auth_users_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/CreateUserRequest"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/auth/users/{user_email}": {"put": {"tags": ["auth", "users"], "summary": "Update User", "description": "Update a user", "operationId": "update_user_auth_users__user_email__put", "parameters": [{"required": true, "schema": {"type": "string", "title": "User Email"}, "name": "user_email", "in": "path"}], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/UpdateUserRequest"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "delete": {"tags": ["auth", "users"], "summary": "Delete User", "description": "Delete a user", "operationId": "delete_user_auth_users__user_email__delete", "parameters": [{"required": true, "schema": {"type": "string", "title": "User Email"}, "name": "user_email", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/metrics": {"get": {"tags": ["metrics"], "summary": "Get Metrics", "description": "This endpoint is used by Prometheus to scrape such metrics from the application:\n- alerts_total {incident_name, incident_id} - The total number of alerts per incident.\n- open_incidents_total - The total number of open incidents\n\nPlease note that those metrics are per-tenant and are not designed to be used for the monitoring of the application itself.\n\nExample prometheus configuration:\n```\nscrape_configs:\n- job_name: \"scrape_keep\"\n scrape_interval: 5m # It's important to scrape not too often to avoid rate limiting.\n static_configs:\n - targets: [\"https://api.keephq.dev\"] # Or your own domain.\n authorization:\n type: Bearer\n credentials: \"{Your API Key}\"\n\n # Optional, you can add labels to exported incidents. \n # Label values will be equal to the last incident's alert payload value matching the label.\n # Attention! Don't add \"flaky\" labels which could change from alert to alert within the same incident.\n # Good labels: ['labels.department', 'labels.team'], bad labels: ['labels.severity', 'labels.pod_id']\n # Check Keep -> Feed -> \"extraPayload\" column, it will help in writing labels.\n\n params:\n labels: ['labels.service', 'labels.queue']\n # Will resuld as: \"labels_service\" and \"labels_queue\".\n```", "operationId": "get_metrics_metrics_get", "parameters": [{"required": false, "schema": {"items": {"type": "string"}, "type": "array", "title": "Labels"}, "name": "labels", "in": "query"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/extraction": {"get": {"tags": ["enrichment", "extraction"], "summary": "Get Extraction Rules", "description": "Get all extraction rules", "operationId": "get_extraction_rules_extraction_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/ExtractionRuleDtoOut"}, "type": "array", "title": "Response Get Extraction Rules Extraction Get"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "post": {"tags": ["enrichment", "extraction"], "summary": "Create Extraction Rule", "description": "Create a new extraction rule", "operationId": "create_extraction_rule_extraction_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/ExtractionRuleDtoBase"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ExtractionRuleDtoOut"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/extraction/{rule_id}": {"put": {"tags": ["enrichment", "extraction"], "summary": "Update Extraction Rule", "description": "Update an existing extraction rule", "operationId": "update_extraction_rule_extraction__rule_id__put", "parameters": [{"required": true, "schema": {"type": "integer", "title": "Rule Id"}, "name": "rule_id", "in": "path"}], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/ExtractionRuleDtoBase"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ExtractionRuleDtoOut"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "delete": {"tags": ["enrichment", "extraction"], "summary": "Delete Extraction Rule", "description": "Delete an extraction rule", "operationId": "delete_extraction_rule_extraction__rule_id__delete", "parameters": [{"required": true, "schema": {"type": "integer", "title": "Rule Id"}, "name": "rule_id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/dashboard": {"get": {"tags": ["dashboard"], "summary": "Read Dashboards", "operationId": "read_dashboards_dashboard_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/DashboardResponseDTO"}, "type": "array", "title": "Response Read Dashboards Dashboard Get"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "post": {"tags": ["dashboard"], "summary": "Create Dashboard", "operationId": "create_dashboard_dashboard_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/DashboardCreateDTO"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DashboardResponseDTO"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/dashboard/{dashboard_id}": {"put": {"tags": ["dashboard"], "summary": "Update Dashboard", "operationId": "update_dashboard_dashboard__dashboard_id__put", "parameters": [{"required": true, "schema": {"type": "string", "title": "Dashboard Id"}, "name": "dashboard_id", "in": "path"}], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/DashboardUpdateDTO"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DashboardResponseDTO"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "delete": {"tags": ["dashboard"], "summary": "Delete Dashboard", "operationId": "delete_dashboard_dashboard__dashboard_id__delete", "parameters": [{"required": true, "schema": {"type": "string", "title": "Dashboard Id"}, "name": "dashboard_id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/tags": {"get": {"tags": ["tags"], "summary": "Get Tags", "description": "get tags", "operationId": "get_tags_tags_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"type": "object"}, "type": "array", "title": "Response Get Tags Tags Get"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/maintenance": {"get": {"tags": ["maintenance"], "summary": "Get Maintenance Rules", "description": "Get all maintenance rules", "operationId": "get_maintenance_rules_maintenance_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/MaintenanceRuleRead"}, "type": "array", "title": "Response Get Maintenance Rules Maintenance Get"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "post": {"tags": ["maintenance"], "summary": "Create Maintenance Rule", "description": "Create a new maintenance rule", "operationId": "create_maintenance_rule_maintenance_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/MaintenanceRuleCreate"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/MaintenanceRuleRead"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/maintenance/{rule_id}": {"put": {"tags": ["maintenance"], "summary": "Update Maintenance Rule", "description": "Update an existing maintenance rule", "operationId": "update_maintenance_rule_maintenance__rule_id__put", "parameters": [{"required": true, "schema": {"type": "integer", "title": "Rule Id"}, "name": "rule_id", "in": "path"}], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/MaintenanceRuleCreate"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/MaintenanceRuleRead"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "delete": {"tags": ["maintenance"], "summary": "Delete Maintenance Rule", "description": "Delete a maintenance rule", "operationId": "delete_maintenance_rule_maintenance__rule_id__delete", "parameters": [{"required": true, "schema": {"type": "integer", "title": "Rule Id"}, "name": "rule_id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/topology": {"get": {"tags": ["topology"], "summary": "Get Topology Data", "description": "Get all topology data", "operationId": "get_topology_data_topology_get", "parameters": [{"required": false, "schema": {"type": "string", "title": "Provider Ids"}, "name": "provider_ids", "in": "query"}, {"required": false, "schema": {"type": "string", "title": "Services"}, "name": "services", "in": "query"}, {"required": false, "schema": {"type": "string", "title": "Environment"}, "name": "environment", "in": "query"}, {"required": false, "schema": {"type": "boolean", "title": "Include Empty Deps", "default": false}, "name": "include_empty_deps", "in": "query"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/TopologyServiceDtoOut"}, "type": "array", "title": "Response Get Topology Data Topology Get"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/topology/applications": {"get": {"tags": ["topology"], "summary": "Get Applications", "description": "Get all applications", "operationId": "get_applications_topology_applications_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/TopologyApplicationDtoOut"}, "type": "array", "title": "Response Get Applications Topology Applications Get"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "post": {"tags": ["topology"], "summary": "Create Application", "description": "Create a new application", "operationId": "create_application_topology_applications_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/TopologyApplicationDtoIn"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/TopologyApplicationDtoOut"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/topology/applications/{application_id}": {"put": {"tags": ["topology"], "summary": "Update Application", "description": "Update an application", "operationId": "update_application_topology_applications__application_id__put", "parameters": [{"required": true, "schema": {"type": "string", "format": "uuid", "title": "Application Id"}, "name": "application_id", "in": "path"}], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/TopologyApplicationDtoIn"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/TopologyApplicationDtoOut"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "delete": {"tags": ["topology"], "summary": "Delete Application", "description": "Delete an application", "operationId": "delete_application_topology_applications__application_id__delete", "parameters": [{"required": true, "schema": {"type": "string", "format": "uuid", "title": "Application Id"}, "name": "application_id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/deduplications": {"get": {"tags": ["deduplications"], "summary": "Get Deduplications", "description": "Get Deduplications", "operationId": "get_deduplications_deduplications_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "post": {"tags": ["deduplications"], "summary": "Create Deduplication Rule", "description": "Create Deduplication Rule", "operationId": "create_deduplication_rule_deduplications_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/DeduplicationRuleRequestDto"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/deduplications/fields": {"get": {"tags": ["deduplications"], "summary": "Get Deduplication Fields", "description": "Get Optional Fields For Deduplications", "operationId": "get_deduplication_fields_deduplications_fields_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"additionalProperties": {"items": {"type": "string"}, "type": "array"}, "type": "object", "title": "Response Get Deduplication Fields Deduplications Fields Get"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}, "/deduplications/{rule_id}": {"put": {"tags": ["deduplications"], "summary": "Update Deduplication Rule", "description": "Update Deduplication Rule", "operationId": "update_deduplication_rule_deduplications__rule_id__put", "parameters": [{"required": true, "schema": {"type": "string", "title": "Rule Id"}, "name": "rule_id", "in": "path"}], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/DeduplicationRuleRequestDto"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}, "delete": {"tags": ["deduplications"], "summary": "Delete Deduplication Rule", "description": "Delete Deduplication Rule", "operationId": "delete_deduplication_rule_deduplications__rule_id__delete", "parameters": [{"required": true, "schema": {"type": "string", "title": "Rule Id"}, "name": "rule_id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"API Key": []}, {"HTTPBasic": []}, {"OAuth2PasswordBearer": []}]}}}, "components": {"schemas": {"AlertActionType": {"enum": ["alert was triggered", "alert acknowledged", "alert automatically resolved", "alert automatically resolved by API", "alert manually resolved", "alert status manually changed", "alert status changed by API", "alert status undone", "alert enriched by workflow", "alert enriched by mapping rule", "alert was deduplicated", "alert was assigned with ticket", "alert was unassigned from ticket", "alert ticket was updated", "alert enrichments disposed", "alert deleted", "alert enriched", "alert un-enriched", "a comment was added to the alert", "a comment was removed from the alert", "Alert is in maintenance window", "A comment was added to the incident"], "title": "AlertActionType", "description": "An enumeration."}, "AlertAudit": {"properties": {"id": {"type": "string", "format": "uuid", "title": "Id"}, "fingerprint": {"type": "string", "title": "Fingerprint"}, "tenant_id": {"type": "string", "title": "Tenant Id"}, "timestamp": {"type": "string", "format": "date-time", "title": "Timestamp"}, "user_id": {"type": "string", "title": "User Id"}, "action": {"type": "string", "title": "Action"}, "description": {"type": "string", "title": "Description"}}, "type": "object", "required": ["fingerprint", "tenant_id", "user_id", "action", "description"], "title": "AlertAudit"}, "AlertAuditDto": {"properties": {"id": {"type": "string", "title": "Id"}, "timestamp": {"type": "string", "format": "date-time", "title": "Timestamp"}, "fingerprint": {"type": "string", "title": "Fingerprint"}, "action": {"$ref": "#/components/schemas/AlertActionType"}, "user_id": {"type": "string", "title": "User Id"}, "description": {"type": "string", "title": "Description"}}, "type": "object", "required": ["id", "timestamp", "fingerprint", "action", "user_id", "description"], "title": "AlertAuditDto"}, "AlertDto": {"properties": {"id": {"type": "string", "title": "Id"}, "name": {"type": "string", "title": "Name"}, "status": {"$ref": "#/components/schemas/AlertStatus"}, "severity": {"$ref": "#/components/schemas/AlertSeverity"}, "lastReceived": {"type": "string", "title": "Lastreceived"}, "firingStartTime": {"type": "string", "title": "Firingstarttime"}, "environment": {"type": "string", "title": "Environment", "default": "undefined"}, "isFullDuplicate": {"type": "boolean", "title": "Isfullduplicate", "default": false}, "isPartialDuplicate": {"type": "boolean", "title": "Ispartialduplicate", "default": false}, "duplicateReason": {"type": "string", "title": "Duplicatereason"}, "service": {"type": "string", "title": "Service"}, "source": {"items": {"type": "string"}, "type": "array", "title": "Source", "default": []}, "apiKeyRef": {"type": "string", "title": "Apikeyref"}, "message": {"type": "string", "title": "Message"}, "description": {"type": "string", "title": "Description"}, "pushed": {"type": "boolean", "title": "Pushed", "default": false}, "event_id": {"type": "string", "title": "Event Id"}, "url": {"type": "string", "maxLength": 65536, "minLength": 1, "format": "uri", "title": "Url"}, "labels": {"type": "object", "title": "Labels", "default": {}}, "fingerprint": {"type": "string", "title": "Fingerprint"}, "deleted": {"type": "boolean", "title": "Deleted", "default": false}, "dismissUntil": {"type": "string", "title": "Dismissuntil"}, "dismissed": {"type": "boolean", "title": "Dismissed", "default": false}, "assignee": {"type": "string", "title": "Assignee"}, "providerId": {"type": "string", "title": "Providerid"}, "providerType": {"type": "string", "title": "Providertype"}, "note": {"type": "string", "title": "Note"}, "startedAt": {"type": "string", "title": "Startedat"}, "isNoisy": {"type": "boolean", "title": "Isnoisy", "default": false}, "enriched_fields": {"items": {}, "type": "array", "title": "Enriched Fields", "default": []}, "incident": {"type": "string", "title": "Incident"}}, "type": "object", "required": ["name", "status", "severity", "lastReceived"], "title": "AlertDto", "example": {"id": "1234", "name": "Alert name", "status": "firing", "lastReceived": "2021-01-01T00:00:00.000Z", "environment": "production", "service": "backend", "source": ["keep"], "message": "Keep: Alert message", "description": "Keep: Alert description", "severity": "critical", "pushed": true, "event_id": "1234", "url": "https://www.keephq.dev?alertId=1234", "labels": {"key": "value"}, "ticket_url": "https://www.keephq.dev?enrichedTicketId=456", "fingerprint": "1234"}}, "AlertSeverity": {"enum": ["critical", "high", "warning", "info", "low"], "title": "AlertSeverity", "description": "An enumeration."}, "AlertStatus": {"enum": ["firing", "resolved", "acknowledged", "suppressed", "pending"], "title": "AlertStatus", "description": "An enumeration."}, "AlertWithIncidentLinkMetadataDto": {"properties": {"id": {"type": "string", "title": "Id"}, "name": {"type": "string", "title": "Name"}, "status": {"$ref": "#/components/schemas/AlertStatus"}, "severity": {"$ref": "#/components/schemas/AlertSeverity"}, "lastReceived": {"type": "string", "title": "Lastreceived"}, "firingStartTime": {"type": "string", "title": "Firingstarttime"}, "environment": {"type": "string", "title": "Environment", "default": "undefined"}, "isFullDuplicate": {"type": "boolean", "title": "Isfullduplicate", "default": false}, "isPartialDuplicate": {"type": "boolean", "title": "Ispartialduplicate", "default": false}, "duplicateReason": {"type": "string", "title": "Duplicatereason"}, "service": {"type": "string", "title": "Service"}, "source": {"items": {"type": "string"}, "type": "array", "title": "Source", "default": []}, "apiKeyRef": {"type": "string", "title": "Apikeyref"}, "message": {"type": "string", "title": "Message"}, "description": {"type": "string", "title": "Description"}, "pushed": {"type": "boolean", "title": "Pushed", "default": false}, "event_id": {"type": "string", "title": "Event Id"}, "url": {"type": "string", "maxLength": 65536, "minLength": 1, "format": "uri", "title": "Url"}, "labels": {"type": "object", "title": "Labels", "default": {}}, "fingerprint": {"type": "string", "title": "Fingerprint"}, "deleted": {"type": "boolean", "title": "Deleted", "default": false}, "dismissUntil": {"type": "string", "title": "Dismissuntil"}, "dismissed": {"type": "boolean", "title": "Dismissed", "default": false}, "assignee": {"type": "string", "title": "Assignee"}, "providerId": {"type": "string", "title": "Providerid"}, "providerType": {"type": "string", "title": "Providertype"}, "note": {"type": "string", "title": "Note"}, "startedAt": {"type": "string", "title": "Startedat"}, "isNoisy": {"type": "boolean", "title": "Isnoisy", "default": false}, "enriched_fields": {"items": {}, "type": "array", "title": "Enriched Fields", "default": []}, "incident": {"type": "string", "title": "Incident"}, "is_created_by_ai": {"type": "boolean", "title": "Is Created By Ai", "default": false}}, "type": "object", "required": ["name", "status", "severity", "lastReceived"], "title": "AlertWithIncidentLinkMetadataDto", "example": {"id": "1234", "name": "Alert name", "status": "firing", "lastReceived": "2021-01-01T00:00:00.000Z", "environment": "production", "service": "backend", "source": ["keep"], "message": "Keep: Alert message", "description": "Keep: Alert description", "severity": "critical", "pushed": true, "event_id": "1234", "url": "https://www.keephq.dev?alertId=1234", "labels": {"key": "value"}, "ticket_url": "https://www.keephq.dev?enrichedTicketId=456", "fingerprint": "1234"}}, "AlertWithIncidentLinkMetadataPaginatedResultsDto": {"properties": {"limit": {"type": "integer", "title": "Limit", "default": 25}, "offset": {"type": "integer", "title": "Offset", "default": 0}, "count": {"type": "integer", "title": "Count"}, "items": {"items": {"$ref": "#/components/schemas/AlertWithIncidentLinkMetadataDto"}, "type": "array", "title": "Items"}}, "type": "object", "required": ["count", "items"], "title": "AlertWithIncidentLinkMetadataPaginatedResultsDto"}, "Body_create_actions_actions_post": {"properties": {"file": {"type": "string", "format": "binary", "title": "File"}}, "type": "object", "title": "Body_create_actions_actions_post"}, "Body_create_workflow_workflows_post": {"properties": {"file": {"type": "string", "format": "binary", "title": "File"}}, "type": "object", "required": ["file"], "title": "Body_create_workflow_workflows_post"}, "Body_pusher_authentication_pusher_auth_post": {"properties": {"channel_name": {"title": "Channel Name"}, "socket_id": {"title": "Socket Id"}}, "type": "object", "required": ["channel_name", "socket_id"], "title": "Body_pusher_authentication_pusher_auth_post"}, "Body_put_action_actions__action_id__put": {"properties": {"file": {"type": "string", "format": "binary", "title": "File"}}, "type": "object", "required": ["file"], "title": "Body_put_action_actions__action_id__put"}, "Body_run_workflow_from_definition_workflows_test_post": {"properties": {"file": {"type": "string", "format": "binary", "title": "File"}}, "type": "object", "title": "Body_run_workflow_from_definition_workflows_test_post"}, "CreateOrUpdateGroupRequest": {"properties": {"name": {"type": "string", "title": "Name"}, "roles": {"items": {"type": "string"}, "type": "array", "title": "Roles"}, "members": {"items": {"type": "string"}, "type": "array", "title": "Members"}}, "type": "object", "required": ["name", "roles", "members"], "title": "CreateOrUpdateGroupRequest"}, "CreateOrUpdatePresetDto": {"properties": {"name": {"type": "string", "title": "Name"}, "options": {"items": {"$ref": "#/components/schemas/PresetOption"}, "type": "array", "title": "Options"}, "is_private": {"type": "boolean", "title": "Is Private", "default": false}, "is_noisy": {"type": "boolean", "title": "Is Noisy", "default": false}, "tags": {"items": {"$ref": "#/components/schemas/TagDto"}, "type": "array", "title": "Tags", "default": []}}, "type": "object", "required": ["options"], "title": "CreateOrUpdatePresetDto"}, "CreateOrUpdateRole": {"properties": {"name": {"type": "string", "title": "Name"}, "description": {"type": "string", "title": "Description"}, "scopes": {"items": {"type": "string"}, "type": "array", "uniqueItems": true, "title": "Scopes"}}, "type": "object", "title": "CreateOrUpdateRole"}, "CreatePresetTab": {"properties": {"name": {"type": "string", "title": "Name"}, "filter": {"type": "string", "title": "Filter"}}, "type": "object", "required": ["name", "filter"], "title": "CreatePresetTab"}, "CreateUserRequest": {"properties": {"username": {"type": "string", "title": "Username"}, "name": {"type": "string", "title": "Name"}, "password": {"type": "string", "title": "Password"}, "role": {"type": "string", "title": "Role"}, "groups": {"items": {"type": "string"}, "type": "array", "title": "Groups"}}, "type": "object", "required": ["username"], "title": "CreateUserRequest"}, "DashboardCreateDTO": {"properties": {"dashboard_name": {"type": "string", "title": "Dashboard Name"}, "dashboard_config": {"type": "object", "title": "Dashboard Config"}}, "type": "object", "required": ["dashboard_name", "dashboard_config"], "title": "DashboardCreateDTO"}, "DashboardResponseDTO": {"properties": {"id": {"type": "string", "title": "Id"}, "dashboard_name": {"type": "string", "title": "Dashboard Name"}, "dashboard_config": {"type": "object", "title": "Dashboard Config"}, "created_at": {"type": "string", "format": "date-time", "title": "Created At"}, "updated_at": {"type": "string", "format": "date-time", "title": "Updated At"}}, "type": "object", "required": ["id", "dashboard_name", "dashboard_config", "created_at", "updated_at"], "title": "DashboardResponseDTO"}, "DashboardUpdateDTO": {"properties": {"dashboard_config": {"type": "object", "title": "Dashboard Config"}, "dashboard_name": {"type": "string", "title": "Dashboard Name"}}, "type": "object", "title": "DashboardUpdateDTO"}, "DeduplicationRuleRequestDto": {"properties": {"name": {"type": "string", "title": "Name"}, "description": {"type": "string", "title": "Description"}, "provider_type": {"type": "string", "title": "Provider Type"}, "provider_id": {"type": "string", "title": "Provider Id"}, "fingerprint_fields": {"items": {"type": "string"}, "type": "array", "title": "Fingerprint Fields"}, "full_deduplication": {"type": "boolean", "title": "Full Deduplication", "default": false}, "ignore_fields": {"items": {"type": "string"}, "type": "array", "title": "Ignore Fields"}}, "type": "object", "required": ["name", "provider_type", "fingerprint_fields"], "title": "DeduplicationRuleRequestDto"}, "DeleteRequestBody": {"properties": {"fingerprint": {"type": "string", "title": "Fingerprint"}, "lastReceived": {"type": "string", "title": "Lastreceived"}, "restore": {"type": "boolean", "title": "Restore", "default": false}}, "type": "object", "required": ["fingerprint", "lastReceived"], "title": "DeleteRequestBody"}, "EnrichAlertRequestBody": {"properties": {"enrichments": {"additionalProperties": {"type": "string"}, "type": "object", "title": "Enrichments"}, "fingerprint": {"type": "string", "title": "Fingerprint"}}, "type": "object", "required": ["enrichments", "fingerprint"], "title": "EnrichAlertRequestBody"}, "ExtractionRuleDtoBase": {"properties": {"name": {"type": "string", "title": "Name"}, "description": {"type": "string", "title": "Description"}, "priority": {"type": "integer", "title": "Priority", "default": 0}, "attribute": {"type": "string", "title": "Attribute"}, "condition": {"type": "string", "title": "Condition"}, "disabled": {"type": "boolean", "title": "Disabled", "default": false}, "regex": {"type": "string", "title": "Regex"}, "pre": {"type": "boolean", "title": "Pre", "default": false}}, "type": "object", "required": ["name", "regex"], "title": "ExtractionRuleDtoBase"}, "ExtractionRuleDtoOut": {"properties": {"name": {"type": "string", "title": "Name"}, "description": {"type": "string", "title": "Description"}, "priority": {"type": "integer", "title": "Priority", "default": 0}, "attribute": {"type": "string", "title": "Attribute"}, "condition": {"type": "string", "title": "Condition"}, "disabled": {"type": "boolean", "title": "Disabled", "default": false}, "regex": {"type": "string", "title": "Regex"}, "pre": {"type": "boolean", "title": "Pre", "default": false}, "id": {"type": "integer", "title": "Id"}, "created_by": {"type": "string", "title": "Created By"}, "created_at": {"type": "string", "format": "date-time", "title": "Created At"}, "updated_by": {"type": "string", "title": "Updated By"}, "updated_at": {"type": "string", "format": "date-time", "title": "Updated At"}}, "type": "object", "required": ["name", "regex", "id", "created_at"], "title": "ExtractionRuleDtoOut"}, "Group": {"properties": {"id": {"type": "string", "title": "Id"}, "name": {"type": "string", "title": "Name"}, "roles": {"items": {"type": "string"}, "type": "array", "title": "Roles", "default": []}, "members": {"items": {"type": "string"}, "type": "array", "title": "Members", "default": []}, "memberCount": {"type": "integer", "title": "Membercount", "default": 0}}, "type": "object", "required": ["id", "name"], "title": "Group"}, "HTTPValidationError": {"properties": {"detail": {"items": {"$ref": "#/components/schemas/ValidationError"}, "type": "array", "title": "Detail"}}, "type": "object", "title": "HTTPValidationError"}, "IncidentDto": {"properties": {"user_generated_name": {"type": "string", "title": "User Generated Name"}, "assignee": {"type": "string", "title": "Assignee"}, "user_summary": {"type": "string", "title": "User Summary"}, "same_incident_in_the_past_id": {"type": "string", "format": "uuid", "title": "Same Incident In The Past Id"}, "id": {"type": "string", "format": "uuid", "title": "Id"}, "start_time": {"type": "string", "format": "date-time", "title": "Start Time"}, "last_seen_time": {"type": "string", "format": "date-time", "title": "Last Seen Time"}, "end_time": {"type": "string", "format": "date-time", "title": "End Time"}, "alerts_count": {"type": "integer", "title": "Alerts Count"}, "alert_sources": {"items": {"type": "string"}, "type": "array", "title": "Alert Sources"}, "severity": {"$ref": "#/components/schemas/IncidentSeverity"}, "status": {"allOf": [{"$ref": "#/components/schemas/IncidentStatus"}], "default": "firing"}, "services": {"items": {"type": "string"}, "type": "array", "title": "Services"}, "is_predicted": {"type": "boolean", "title": "Is Predicted"}, "is_confirmed": {"type": "boolean", "title": "Is Confirmed"}, "generated_summary": {"type": "string", "title": "Generated Summary"}, "ai_generated_name": {"type": "string", "title": "Ai Generated Name"}, "rule_fingerprint": {"type": "string", "title": "Rule Fingerprint"}, "merged_into_incident_id": {"type": "string", "format": "uuid", "title": "Merged Into Incident Id"}, "merged_by": {"type": "string", "title": "Merged By"}, "merged_at": {"type": "string", "format": "date-time", "title": "Merged At"}}, "type": "object", "required": ["id", "alerts_count", "alert_sources", "severity", "services", "is_predicted", "is_confirmed"], "title": "IncidentDto", "example": {"id": "c2509cb3-6168-4347-b83b-a41da9df2d5b", "name": "Incident name", "user_summary": "Keep: Incident description", "status": "firing"}}, "IncidentDtoIn": {"properties": {"user_generated_name": {"type": "string", "title": "User Generated Name"}, "assignee": {"type": "string", "title": "Assignee"}, "user_summary": {"type": "string", "title": "User Summary"}, "same_incident_in_the_past_id": {"type": "string", "format": "uuid", "title": "Same Incident In The Past Id"}}, "type": "object", "title": "IncidentDtoIn", "example": {"id": "c2509cb3-6168-4347-b83b-a41da9df2d5b", "name": "Incident name", "user_summary": "Keep: Incident description", "status": "firing"}}, "IncidentListFilterParamsDto": {"properties": {"statuses": {"items": {"$ref": "#/components/schemas/IncidentStatus"}, "type": "array", "default": ["firing", "resolved", "acknowledged", "merged"]}, "severities": {"items": {"$ref": "#/components/schemas/IncidentSeverity"}, "type": "array", "default": ["critical", "high", "warning", "info", "low"]}, "assignees": {"items": {"type": "string"}, "type": "array", "title": "Assignees"}, "services": {"items": {"type": "string"}, "type": "array", "title": "Services"}, "sources": {"items": {"type": "string"}, "type": "array", "title": "Sources"}}, "type": "object", "required": ["assignees", "services", "sources"], "title": "IncidentListFilterParamsDto"}, "IncidentSeverity": {"enum": ["critical", "high", "warning", "info", "low"], "title": "IncidentSeverity", "description": "An enumeration."}, "IncidentSorting": {"enum": ["creation_time", "start_time", "last_seen_time", "severity", "status", "alerts_count", "-creation_time", "-start_time", "-last_seen_time", "-severity", "-status", "-alerts_count"], "title": "IncidentSorting", "description": "An enumeration."}, "IncidentStatus": {"enum": ["firing", "resolved", "acknowledged", "merged"], "title": "IncidentStatus", "description": "An enumeration."}, "IncidentStatusChangeDto": {"properties": {"status": {"$ref": "#/components/schemas/IncidentStatus"}, "comment": {"type": "string", "title": "Comment"}}, "type": "object", "required": ["status"], "title": "IncidentStatusChangeDto"}, "IncidentsPaginatedResultsDto": {"properties": {"limit": {"type": "integer", "title": "Limit", "default": 25}, "offset": {"type": "integer", "title": "Offset", "default": 0}, "count": {"type": "integer", "title": "Count"}, "items": {"items": {"$ref": "#/components/schemas/IncidentDto"}, "type": "array", "title": "Items"}}, "type": "object", "required": ["count", "items"], "title": "IncidentsPaginatedResultsDto"}, "MaintenanceRuleCreate": {"properties": {"name": {"type": "string", "title": "Name"}, "description": {"type": "string", "title": "Description"}, "cel_query": {"type": "string", "title": "Cel Query"}, "start_time": {"type": "string", "format": "date-time", "title": "Start Time"}, "duration_seconds": {"type": "integer", "title": "Duration Seconds"}, "suppress": {"type": "boolean", "title": "Suppress", "default": false}, "enabled": {"type": "boolean", "title": "Enabled", "default": true}}, "type": "object", "required": ["name", "cel_query", "start_time"], "title": "MaintenanceRuleCreate"}, "MaintenanceRuleRead": {"properties": {"id": {"type": "integer", "title": "Id"}, "name": {"type": "string", "title": "Name"}, "description": {"type": "string", "title": "Description"}, "created_by": {"type": "string", "title": "Created By"}, "cel_query": {"type": "string", "title": "Cel Query"}, "start_time": {"type": "string", "format": "date-time", "title": "Start Time"}, "end_time": {"type": "string", "format": "date-time", "title": "End Time"}, "duration_seconds": {"type": "integer", "title": "Duration Seconds"}, "updated_at": {"type": "string", "format": "date-time", "title": "Updated At"}, "suppress": {"type": "boolean", "title": "Suppress", "default": false}, "enabled": {"type": "boolean", "title": "Enabled", "default": true}}, "type": "object", "required": ["id", "name", "created_by", "cel_query", "start_time", "end_time"], "title": "MaintenanceRuleRead"}, "MappingRule": {"properties": {"id": {"type": "integer", "title": "Id"}, "tenant_id": {"type": "string", "title": "Tenant Id"}, "priority": {"type": "integer", "title": "Priority", "default": 0}, "name": {"type": "string", "maxLength": 255, "title": "Name"}, "description": {"type": "string", "maxLength": 2048, "title": "Description"}, "file_name": {"type": "string", "maxLength": 255, "title": "File Name"}, "created_by": {"type": "string", "maxLength": 255, "title": "Created By"}, "created_at": {"type": "string", "format": "date-time", "title": "Created At"}, "disabled": {"type": "boolean", "title": "Disabled", "default": false}, "override": {"type": "boolean", "title": "Override", "default": true}, "condition": {"type": "string", "maxLength": 2000, "title": "Condition"}, "type": {"type": "string", "maxLength": 255, "title": "Type"}, "matchers": {"items": {"type": "string"}, "type": "array", "title": "Matchers"}, "rows": {"items": {"type": "object"}, "type": "array", "title": "Rows"}, "updated_by": {"type": "string", "maxLength": 255, "title": "Updated By"}, "last_updated_at": {"type": "string", "format": "date-time", "title": "Last Updated At"}}, "type": "object", "required": ["tenant_id", "name", "type", "matchers"], "title": "MappingRule"}, "MappingRuleDtoIn": {"properties": {"name": {"type": "string", "title": "Name"}, "description": {"type": "string", "title": "Description"}, "file_name": {"type": "string", "title": "File Name"}, "priority": {"type": "integer", "title": "Priority", "default": 0}, "matchers": {"items": {"type": "string"}, "type": "array", "title": "Matchers"}, "type": {"type": "string", "enum": ["csv", "topology"], "title": "Type", "default": "csv"}, "rows": {"items": {"type": "object"}, "type": "array", "title": "Rows"}}, "type": "object", "required": ["name", "matchers"], "title": "MappingRuleDtoIn"}, "MappingRuleDtoOut": {"properties": {"name": {"type": "string", "title": "Name"}, "description": {"type": "string", "title": "Description"}, "file_name": {"type": "string", "title": "File Name"}, "priority": {"type": "integer", "title": "Priority", "default": 0}, "matchers": {"items": {"type": "string"}, "type": "array", "title": "Matchers"}, "type": {"type": "string", "enum": ["csv", "topology"], "title": "Type", "default": "csv"}, "id": {"type": "integer", "title": "Id"}, "created_by": {"type": "string", "title": "Created By"}, "created_at": {"type": "string", "format": "date-time", "title": "Created At"}, "attributes": {"items": {"type": "string"}, "type": "array", "title": "Attributes", "default": []}, "updated_by": {"type": "string", "title": "Updated By"}, "last_updated_at": {"type": "string", "format": "date-time", "title": "Last Updated At"}}, "type": "object", "required": ["name", "matchers", "id", "created_at"], "title": "MappingRuleDtoOut"}, "MergeIncidentsRequestDto": {"properties": {"source_incident_ids": {"items": {"type": "string", "format": "uuid"}, "type": "array", "title": "Source Incident Ids"}, "destination_incident_id": {"type": "string", "format": "uuid", "title": "Destination Incident Id"}}, "type": "object", "required": ["source_incident_ids", "destination_incident_id"], "title": "MergeIncidentsRequestDto"}, "MergeIncidentsResponseDto": {"properties": {"merged_incident_ids": {"items": {"type": "string", "format": "uuid"}, "type": "array", "title": "Merged Incident Ids"}, "skipped_incident_ids": {"items": {"type": "string", "format": "uuid"}, "type": "array", "title": "Skipped Incident Ids"}, "failed_incident_ids": {"items": {"type": "string", "format": "uuid"}, "type": "array", "title": "Failed Incident Ids"}, "destination_incident_id": {"type": "string", "format": "uuid", "title": "Destination Incident Id"}, "message": {"type": "string", "title": "Message"}}, "type": "object", "required": ["merged_incident_ids", "skipped_incident_ids", "failed_incident_ids", "destination_incident_id", "message"], "title": "MergeIncidentsResponseDto"}, "PermissionEntity": {"properties": {"id": {"type": "string", "title": "Id"}, "type": {"type": "string", "title": "Type"}}, "type": "object", "required": ["id", "type"], "title": "PermissionEntity"}, "PresetDto": {"properties": {"id": {"type": "string", "format": "uuid", "title": "Id"}, "name": {"type": "string", "title": "Name"}, "options": {"items": {}, "type": "array", "title": "Options", "default": []}, "created_by": {"type": "string", "title": "Created By"}, "is_private": {"type": "boolean", "title": "Is Private", "default": false}, "is_noisy": {"type": "boolean", "title": "Is Noisy", "default": false}, "should_do_noise_now": {"type": "boolean", "title": "Should Do Noise Now", "default": false}, "alerts_count": {"type": "integer", "title": "Alerts Count", "default": 0}, "static": {"type": "boolean", "title": "Static", "default": false}, "tags": {"items": {"$ref": "#/components/schemas/TagDto"}, "type": "array", "title": "Tags", "default": []}}, "type": "object", "required": ["id", "name"], "title": "PresetDto"}, "PresetOption": {"properties": {"label": {"type": "string", "title": "Label"}, "value": {"anyOf": [{"type": "string"}, {"type": "object"}], "title": "Value"}}, "type": "object", "required": ["label", "value"], "title": "PresetOption"}, "PresetSearchQuery": {"properties": {"cel_query": {"type": "string", "minLength": 1, "title": "Cel Query"}, "sql_query": {"type": "object", "title": "Sql Query"}, "limit": {"type": "integer", "minimum": 0.0, "title": "Limit", "default": 1000}, "timeframe": {"type": "integer", "minimum": 0.0, "title": "Timeframe", "default": 0}}, "type": "object", "required": ["cel_query", "sql_query"], "title": "PresetSearchQuery"}, "ProviderDTO": {"properties": {"type": {"type": "string", "title": "Type"}, "id": {"type": "string", "title": "Id"}, "name": {"type": "string", "title": "Name"}, "installed": {"type": "boolean", "title": "Installed"}}, "type": "object", "required": ["type", "name", "installed"], "title": "ProviderDTO"}, "ProviderWebhookSettings": {"properties": {"webhookDescription": {"type": "string", "title": "Webhookdescription"}, "webhookTemplate": {"type": "string", "title": "Webhooktemplate"}, "webhookMarkdown": {"type": "string", "title": "Webhookmarkdown"}}, "type": "object", "required": ["webhookTemplate"], "title": "ProviderWebhookSettings"}, "ResourcePermission": {"properties": {"resource_id": {"type": "string", "title": "Resource Id"}, "resource_name": {"type": "string", "title": "Resource Name"}, "resource_type": {"type": "string", "title": "Resource Type"}, "permissions": {"items": {"$ref": "#/components/schemas/PermissionEntity"}, "type": "array", "title": "Permissions"}}, "type": "object", "required": ["resource_id", "resource_name", "resource_type", "permissions"], "title": "ResourcePermission"}, "Role": {"properties": {"id": {"type": "string", "title": "Id"}, "name": {"type": "string", "title": "Name"}, "description": {"type": "string", "title": "Description"}, "scopes": {"items": {"type": "string"}, "type": "array", "uniqueItems": true, "title": "Scopes"}, "predefined": {"type": "boolean", "title": "Predefined", "default": true}}, "type": "object", "required": ["id", "name", "description", "scopes"], "title": "Role"}, "RuleCreateDto": {"properties": {"ruleName": {"type": "string", "title": "Rulename"}, "sqlQuery": {"type": "object", "title": "Sqlquery"}, "celQuery": {"type": "string", "title": "Celquery"}, "timeframeInSeconds": {"type": "integer", "title": "Timeframeinseconds"}, "timeUnit": {"type": "string", "title": "Timeunit"}, "groupingCriteria": {"items": {}, "type": "array", "title": "Groupingcriteria", "default": []}, "groupDescription": {"type": "string", "title": "Groupdescription"}, "requireApprove": {"type": "boolean", "title": "Requireapprove", "default": false}, "resolveOn": {"type": "string", "title": "Resolveon", "default": "never"}}, "type": "object", "required": ["ruleName", "sqlQuery", "celQuery", "timeframeInSeconds", "timeUnit"], "title": "RuleCreateDto"}, "SMTPSettings": {"properties": {"host": {"type": "string", "title": "Host"}, "port": {"type": "integer", "title": "Port"}, "from_email": {"type": "string", "title": "From Email"}, "username": {"type": "string", "title": "Username"}, "password": {"type": "string", "format": "password", "title": "Password", "writeOnly": true}, "secure": {"type": "boolean", "title": "Secure", "default": true}, "to_email": {"type": "string", "title": "To Email", "default": "keep@example.com"}}, "type": "object", "required": ["host", "port", "from_email"], "title": "SMTPSettings", "example": {"host": "smtp.example.com", "port": 587, "username": "user@example.com", "password": "password", "secure": true, "from_email": "noreply@example.com", "to_email": ""}}, "SearchAlertsRequest": {"properties": {"query": {"$ref": "#/components/schemas/PresetSearchQuery"}, "timeframe": {"type": "integer", "title": "Timeframe"}}, "type": "object", "required": ["query", "timeframe"], "title": "SearchAlertsRequest"}, "TagDto": {"properties": {"id": {"type": "string", "title": "Id"}, "name": {"type": "string", "title": "Name"}}, "type": "object", "required": ["name"], "title": "TagDto"}, "TopologyApplicationDtoIn": {"properties": {"id": {"type": "string", "format": "uuid", "title": "Id"}, "name": {"type": "string", "title": "Name"}, "description": {"type": "string", "title": "Description"}, "services": {"items": {"$ref": "#/components/schemas/TopologyServiceDtoIn"}, "type": "array", "title": "Services", "default": []}}, "type": "object", "required": ["name"], "title": "TopologyApplicationDtoIn"}, "TopologyApplicationDtoOut": {"properties": {"id": {"type": "string", "format": "uuid", "title": "Id"}, "name": {"type": "string", "title": "Name"}, "description": {"type": "string", "title": "Description"}, "services": {"items": {"$ref": "#/components/schemas/TopologyApplicationServiceDto"}, "type": "array", "title": "Services", "default": []}}, "type": "object", "required": ["id", "name"], "title": "TopologyApplicationDtoOut"}, "TopologyApplicationServiceDto": {"properties": {"id": {"type": "integer", "title": "Id"}, "name": {"type": "string", "title": "Name"}, "service": {"type": "string", "title": "Service"}}, "type": "object", "required": ["id", "name", "service"], "title": "TopologyApplicationServiceDto"}, "TopologyServiceDependencyDto": {"properties": {"serviceId": {"type": "integer", "title": "Serviceid"}, "serviceName": {"type": "string", "title": "Servicename"}, "protocol": {"type": "string", "title": "Protocol", "default": "unknown"}}, "type": "object", "required": ["serviceId", "serviceName"], "title": "TopologyServiceDependencyDto"}, "TopologyServiceDtoIn": {"properties": {"id": {"type": "integer", "title": "Id"}}, "type": "object", "required": ["id"], "title": "TopologyServiceDtoIn"}, "TopologyServiceDtoOut": {"properties": {"source_provider_id": {"type": "string", "title": "Source Provider Id"}, "repository": {"type": "string", "title": "Repository"}, "tags": {"items": {"type": "string"}, "type": "array", "title": "Tags"}, "service": {"type": "string", "title": "Service"}, "display_name": {"type": "string", "title": "Display Name"}, "environment": {"type": "string", "title": "Environment", "default": "unknown"}, "description": {"type": "string", "title": "Description"}, "team": {"type": "string", "title": "Team"}, "email": {"type": "string", "title": "Email"}, "slack": {"type": "string", "title": "Slack"}, "ip_address": {"type": "string", "title": "Ip Address"}, "mac_address": {"type": "string", "title": "Mac Address"}, "category": {"type": "string", "title": "Category"}, "manufacturer": {"type": "string", "title": "Manufacturer"}, "id": {"type": "integer", "title": "Id"}, "dependencies": {"items": {"$ref": "#/components/schemas/TopologyServiceDependencyDto"}, "type": "array", "title": "Dependencies"}, "application_ids": {"items": {"type": "string", "format": "uuid"}, "type": "array", "title": "Application Ids"}, "updated_at": {"type": "string", "format": "date-time", "title": "Updated At"}}, "type": "object", "required": ["service", "display_name", "id", "dependencies", "application_ids"], "title": "TopologyServiceDtoOut"}, "UnEnrichAlertRequestBody": {"properties": {"enrichments": {"items": {"type": "string"}, "type": "array", "title": "Enrichments"}, "fingerprint": {"type": "string", "title": "Fingerprint"}}, "type": "object", "required": ["enrichments", "fingerprint"], "title": "UnEnrichAlertRequestBody"}, "UpdateUserRequest": {"properties": {"username": {"type": "string", "title": "Username"}, "password": {"type": "string", "title": "Password"}, "role": {"type": "string", "title": "Role"}, "groups": {"items": {"type": "string"}, "type": "array", "title": "Groups"}}, "type": "object", "title": "UpdateUserRequest"}, "User": {"properties": {"email": {"type": "string", "title": "Email"}, "name": {"type": "string", "title": "Name"}, "role": {"type": "string", "title": "Role"}, "picture": {"type": "string", "title": "Picture"}, "created_at": {"type": "string", "title": "Created At"}, "last_login": {"type": "string", "title": "Last Login"}, "ldap": {"type": "boolean", "title": "Ldap", "default": false}, "groups": {"items": {"$ref": "#/components/schemas/Group"}, "type": "array", "title": "Groups", "default": []}}, "type": "object", "required": ["email", "name", "created_at"], "title": "User"}, "ValidationError": {"properties": {"loc": {"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, "type": "array", "title": "Location"}, "msg": {"type": "string", "title": "Message"}, "type": {"type": "string", "title": "Error Type"}}, "type": "object", "required": ["loc", "msg", "type"], "title": "ValidationError"}, "WebhookSettings": {"properties": {"webhookApi": {"type": "string", "title": "Webhookapi"}, "apiKey": {"type": "string", "title": "Apikey"}, "modelSchema": {"type": "object", "title": "Modelschema"}}, "type": "object", "required": ["webhookApi", "apiKey", "modelSchema"], "title": "WebhookSettings"}, "WorkflowCreateOrUpdateDTO": {"properties": {"workflow_id": {"type": "string", "title": "Workflow Id"}, "status": {"type": "string", "enum": ["created", "updated"], "title": "Status"}, "revision": {"type": "integer", "title": "Revision", "default": 1}}, "type": "object", "required": ["workflow_id", "status"], "title": "WorkflowCreateOrUpdateDTO"}, "WorkflowDTO": {"properties": {"id": {"type": "string", "title": "Id"}, "name": {"type": "string", "title": "Name", "default": "Workflow file doesn't contain name"}, "description": {"type": "string", "title": "Description", "default": "Workflow file doesn't contain description"}, "created_by": {"type": "string", "title": "Created By"}, "creation_time": {"type": "string", "format": "date-time", "title": "Creation Time"}, "triggers": {"items": {"type": "object"}, "type": "array", "title": "Triggers"}, "interval": {"type": "integer", "title": "Interval"}, "disabled": {"type": "boolean", "title": "Disabled", "default": false}, "last_execution_time": {"type": "string", "format": "date-time", "title": "Last Execution Time"}, "last_execution_status": {"type": "string", "title": "Last Execution Status"}, "providers": {"items": {"$ref": "#/components/schemas/ProviderDTO"}, "type": "array", "title": "Providers"}, "workflow_raw": {"type": "string", "title": "Workflow Raw"}, "revision": {"type": "integer", "title": "Revision", "default": 1}, "last_updated": {"type": "string", "format": "date-time", "title": "Last Updated"}, "invalid": {"type": "boolean", "title": "Invalid", "default": false}, "last_executions": {"items": {"type": "object"}, "type": "array", "title": "Last Executions"}, "last_execution_started": {"type": "string", "format": "date-time", "title": "Last Execution Started"}, "provisioned": {"type": "boolean", "title": "Provisioned", "default": false}, "provisioned_file": {"type": "string", "title": "Provisioned File"}}, "type": "object", "required": ["id", "created_by", "creation_time", "providers", "workflow_raw"], "title": "WorkflowDTO"}, "WorkflowExecutionDTO": {"properties": {"id": {"type": "string", "title": "Id"}, "workflow_id": {"type": "string", "title": "Workflow Id"}, "started": {"type": "string", "format": "date-time", "title": "Started"}, "triggered_by": {"type": "string", "title": "Triggered By"}, "status": {"type": "string", "title": "Status"}, "workflow_name": {"type": "string", "title": "Workflow Name"}, "logs": {"items": {"$ref": "#/components/schemas/WorkflowExecutionLogsDTO"}, "type": "array", "title": "Logs"}, "error": {"type": "string", "title": "Error"}, "execution_time": {"type": "number", "title": "Execution Time"}, "results": {"type": "object", "title": "Results"}}, "type": "object", "required": ["id", "workflow_id", "started", "triggered_by", "status"], "title": "WorkflowExecutionDTO"}, "WorkflowExecutionLogsDTO": {"properties": {"id": {"type": "integer", "title": "Id"}, "timestamp": {"type": "string", "format": "date-time", "title": "Timestamp"}, "message": {"type": "string", "title": "Message"}, "context": {"type": "object", "title": "Context"}}, "type": "object", "required": ["id", "timestamp", "message"], "title": "WorkflowExecutionLogsDTO"}, "WorkflowExecutionsPaginatedResultsDto": {"properties": {"limit": {"type": "integer", "title": "Limit", "default": 25}, "offset": {"type": "integer", "title": "Offset", "default": 0}, "count": {"type": "integer", "title": "Count"}, "items": {"items": {"$ref": "#/components/schemas/WorkflowExecutionDTO"}, "type": "array", "title": "Items"}, "passCount": {"type": "integer", "title": "Passcount", "default": 0}, "avgDuration": {"type": "number", "title": "Avgduration", "default": 0.0}, "workflow": {"$ref": "#/components/schemas/WorkflowDTO"}, "failCount": {"type": "integer", "title": "Failcount", "default": 0}}, "type": "object", "required": ["count", "items"], "title": "WorkflowExecutionsPaginatedResultsDto"}, "WorkflowToAlertExecutionDTO": {"properties": {"workflow_id": {"type": "string", "title": "Workflow Id"}, "workflow_execution_id": {"type": "string", "title": "Workflow Execution Id"}, "alert_fingerprint": {"type": "string", "title": "Alert Fingerprint"}, "workflow_status": {"type": "string", "title": "Workflow Status"}, "workflow_started": {"type": "string", "format": "date-time", "title": "Workflow Started"}}, "type": "object", "required": ["workflow_id", "workflow_execution_id", "alert_fingerprint", "workflow_status", "workflow_started"], "title": "WorkflowToAlertExecutionDTO"}}, "securitySchemes": {"API Key": {"type": "apiKey", "in": "header", "name": "X-API-KEY"}, "HTTPBasic": {"type": "http", "scheme": "basic"}, "OAuth2PasswordBearer": {"type": "oauth2", "flows": {"password": {"scopes": {}, "tokenUrl": "token"}}}}}} \ No newline at end of file diff --git a/keep-ui/app/alerts/alert-pagination.tsx b/keep-ui/app/alerts/alert-pagination.tsx index fe45aec93..659f4405d 100644 --- a/keep-ui/app/alerts/alert-pagination.tsx +++ b/keep-ui/app/alerts/alert-pagination.tsx @@ -5,10 +5,15 @@ import { ChevronLeftIcon, ChevronRightIcon, TableCellsIcon, -} from "@heroicons/react/24/outline"; +} from "@heroicons/react/16/solid"; import { Button, Text } from "@tremor/react"; -import { StylesConfig, SingleValueProps, components, GroupBase } from 'react-select'; -import Select from 'react-select'; +import { + StylesConfig, + SingleValueProps, + components, + GroupBase, +} from "react-select"; +import Select from "react-select"; import { AlertDto } from "./models"; import { Table } from "@tanstack/react-table"; import { useAlerts } from "utils/hooks/useAlerts"; @@ -24,39 +29,46 @@ interface OptionType { label: string; } - const customStyles: StylesConfig> = { - control: (provided, state) => ({ - ...provided, - borderColor: state.isFocused ? 'orange' : provided.borderColor, - '&:hover': { borderColor: 'orange' }, - boxShadow: state.isFocused ? '0 0 0 1px orange' : provided.boxShadow, - }), - singleValue: (provided) => ({ - ...provided, - display: 'flex', - alignItems: 'center', - }), - menu: (provided) => ({ - ...provided, - color: 'orange', - }), - option: (provided, state) => ({ - ...provided, - backgroundColor: state.isSelected ? 'orange' : provided.backgroundColor, - '&:hover': { backgroundColor: state.isSelected ? 'orange' : '#f5f5f5' }, - color: state.isSelected ? 'white' : provided.color, - }), - }; - - const SingleValue = ({ children, ...props }: SingleValueProps>) => ( - - {children} - - - ); +const customStyles: StylesConfig> = { + control: (provided, state) => ({ + ...provided, + borderColor: state.isFocused ? "orange" : "rgb(229 231 235)", + borderRadius: "0.5rem", + "&:hover": { borderColor: "orange" }, + boxShadow: state.isFocused ? "0 0 0 1px orange" : provided.boxShadow, + }), + singleValue: (provided) => ({ + ...provided, + display: "flex", + alignItems: "center", + }), + menu: (provided) => ({ + ...provided, + color: "orange", + }), + option: (provided, state) => ({ + ...provided, + backgroundColor: state.isSelected ? "orange" : provided.backgroundColor, + "&:hover": { backgroundColor: state.isSelected ? "orange" : "#f5f5f5" }, + color: state.isSelected ? "white" : provided.color, + }), +}; +const SingleValue = ({ + children, + ...props +}: SingleValueProps>) => ( + + {children} + + +); -export default function AlertPagination({ presetName, table, isRefreshAllowed }: Props) { +export default function AlertPagination({ + presetName, + table, + isRefreshAllowed, +}: Props) { const { usePresetAlerts } = useAlerts(); const { mutate, isLoading: isValidating } = usePresetAlerts(presetName); @@ -69,50 +81,59 @@ export default function AlertPagination({ presetName, table, isRefreshAllowed }: Showing {pageCount === 0 ? 0 : pageIndex + 1} of {pageCount}
- + table.setPageSize(Number(selectedOption!.value)) + } + options={[ + { value: "10", label: "10" }, + { value: "20", label: "20" }, + { value: "50", label: "50" }, + { value: "100", label: "100" }, + ]} + menuPlacement="top" />
diff --git a/keep-ui/app/globals.css b/keep-ui/app/globals.css index a05e00ebf..2f68f0d9e 100644 --- a/keep-ui/app/globals.css +++ b/keep-ui/app/globals.css @@ -49,3 +49,45 @@ /* original value is ridiculous 15.000, overflowing toasts*/ @apply z-[1000] !important; } + +@keyframes scroll-shadow-left { + 0% { + filter: none + } + 25%, 100% { + filter: drop-shadow(rgba(0, 0, 0, 0.07) -2px 9px 5px) + } +} + +@keyframes scroll-shadow-right { + 0%, 75% { + filter: drop-shadow(rgba(0, 0, 0, 0.07) 2px 9px 5px) + } + 99% { + filter: none + } +} + +.pagination-button { + @apply shadow-tremor-input border-tremor-border bg-tremor-background ; + + &:not(:first-child) { + @apply -ml-px; + } + + &:first-child:not(:last-child) { + @apply rounded-r-none; + } + + &:last-child:not(:first-child) { + @apply rounded-l-none; + } + + &:not(:first-child):not(:last-child) { + @apply rounded-l-none rounded-r-none; + } + + &:not(:disabled):hover { + @apply bg-slate-100; + } +} diff --git a/keep-ui/app/incidents/[id]/incident-activity.tsx b/keep-ui/app/incidents/[id]/incident-activity.tsx index 9cdf91f26..2ab50d2d9 100644 --- a/keep-ui/app/incidents/[id]/incident-activity.tsx +++ b/keep-ui/app/incidents/[id]/incident-activity.tsx @@ -40,12 +40,13 @@ export function IncidentActivityChronoItem({ activity }: { activity: any }) { ". "; return (
- {activity.type === "alert" && ( - - )} + {activity.type === "alert" && + (activity.initiator as AlertDto)?.severity && ( + + )} {title} {subTitle} @@ -214,6 +215,7 @@ export default function IncidentActivity({ ) ); const chronoIcons = activities?.map((activity, index) => { + console.log("activity", activity); if (activity.type === "comment" || activity.type === "newcomment") { const user = users?.find((user) => user.email === activity.initiator); return ( @@ -224,7 +226,7 @@ export default function IncidentActivity({ /> ); } else { - const source = (activity.initiator as AlertDto).source[0]; + const source = (activity.initiator as AlertDto)?.source?.[0]; const imagePath = `/icons/${source}-icon.png`; return ( diff --git a/keep-ui/app/incidents/[id]/incident-alerts.tsx b/keep-ui/app/incidents/[id]/incident-alerts.tsx index 0177cc705..773a6e492 100644 --- a/keep-ui/app/incidents/[id]/incident-alerts.tsx +++ b/keep-ui/app/incidents/[id]/incident-alerts.tsx @@ -6,6 +6,7 @@ import { } from "@tanstack/react-table"; import { Callout, + Card, Table, TableBody, TableCell, @@ -29,6 +30,7 @@ import IncidentAlertMenu from "./incident-alert-menu"; import IncidentPagination from "../incident-pagination"; import React, { useEffect, useState } from "react"; import { IncidentDto } from "../models"; +import { getCommonPinningStylesAndClassNames } from "@/components/ui/table/utils"; interface Props { incident: IncidentDto; @@ -85,8 +87,12 @@ export default function IncidentAlerts({ incident }: Props) { columnHelper.display({ id: "name", header: "Name", - minSize: 330, - cell: (context) => , + minSize: 100, + cell: (context) => ( +
+ +
+ ), }), columnHelper.accessor("description", { id: "description", @@ -158,7 +164,12 @@ export default function IncidentAlerts({ incident }: Props) { const table = useReactTable({ columns: columns, manualPagination: true, - state: { pagination }, + state: { + pagination, + columnPinning: { + right: ["remove"], + }, + }, rowCount: alerts ? alerts.count : 0, onPaginationChange: setTablePagination, data: alerts?.items ?? [], @@ -166,69 +177,87 @@ export default function IncidentAlerts({ incident }: Props) { }); return ( <> - {!isLoading && (alerts?.items ?? []).length === 0 && ( - - Alerts will show up here as they are correlated into this incident. - - )} - - - - {table.getHeaderGroups().map((headerGroup) => ( - - {headerGroup.headers.map((header, index) => { - return ( - - {flexRender( - header.column.columnDef.header, - header.getContext() - )} - - ); - })} - - ))} - - {alerts && alerts?.items?.length > 0 && ( - - {table.getRowModel().rows.map((row, index) => ( - - {row.getVisibleCells().map((cell, index) => ( - - {flexRender(cell.column.columnDef.cell, cell.getContext())} - - ))} + + {!isLoading && (alerts?.items ?? []).length === 0 && ( + + Alerts will show up here as they are correlated into this incident. + + )} +
+ + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header, index) => { + const { style, className } = + getCommonPinningStylesAndClassNames(header.column); + return ( + + {flexRender( + header.column.columnDef.header, + header.getContext() + )} + + ); + })} ))} - - )} - { - // Skeleton - (isLoading || (alerts?.items ?? []).length === 0) && ( + + {alerts && alerts?.items?.length > 0 && ( - {Array(pagination.pageSize) - .fill("") - .map((index, rowIndex) => ( - - {columns.map((c, cellIndex) => ( - - + {table.getRowModel().rows.map((row, index) => ( + + {row.getVisibleCells().map((cell, index) => { + const { style, className } = + getCommonPinningStylesAndClassNames(cell.column); + return ( + + {flexRender( + cell.column.columnDef.cell, + cell.getContext() + )} - ))} - - ))} + ); + })} + + ))} - ) - } -
+ )} + { + // Skeleton + (isLoading || (alerts?.items ?? []).length === 0) && ( + + {Array(pagination.pageSize) + .fill("") + .map((index, rowIndex) => ( + + {columns.map((c, cellIndex) => ( + + + + ))} + + ))} + + ) + } + +
diff --git a/keep-ui/app/incidents/[id]/incident-chat.tsx b/keep-ui/app/incidents/[id]/incident-chat.tsx index 31634f2f8..942ba125d 100644 --- a/keep-ui/app/incidents/[id]/incident-chat.tsx +++ b/keep-ui/app/incidents/[id]/incident-chat.tsx @@ -19,6 +19,7 @@ import { useSession } from "next-auth/react"; import { toast } from "react-toastify"; import "@copilotkit/react-ui/styles.css"; import "./incident-chat.css"; +import { Card } from "@tremor/react"; export default function IncidentChat({ incident }: { incident: IncidentDto }) { const router = useRouter(); @@ -109,32 +110,34 @@ export default function IncidentChat({ incident }: { incident: IncidentDto }) { ); return ( -
- +
+ -
+ labels={{ + title: "Incident Assitant", + initial: + "Hi! 👋 Lets work together to resolve this incident! Ask me anything", + placeholder: + "For example: What do you think the root cause of this incident might be?", + }} + /> +
+ ); } diff --git a/keep-ui/app/incidents/[id]/incident-header.tsx b/keep-ui/app/incidents/[id]/incident-header.tsx new file mode 100644 index 000000000..da202ee15 --- /dev/null +++ b/keep-ui/app/incidents/[id]/incident-header.tsx @@ -0,0 +1,172 @@ +import { IncidentDto } from "@/app/incidents/models"; +import { Badge, Button, Icon, Subtitle, Title } from "@tremor/react"; +import { Link } from "@/components/ui"; +import { ArrowRightIcon } from "@heroicons/react/16/solid"; +import { MdBlock, MdDone, MdModeEdit, MdPlayArrow } from "react-icons/md"; +import React, { useState } from "react"; +import { + deleteIncident, + handleConfirmPredictedIncident, +} from "@/app/incidents/incident-candidate-actions"; +import { useRouter } from "next/navigation"; +import { useSession } from "next-auth/react"; +import { useApiUrl } from "@/utils/hooks/useConfig"; +import ManualRunWorkflowModal from "@/app/workflows/manual-run-workflow-modal"; +import CreateOrUpdateIncident from "@/app/incidents/create-or-update-incident"; +import Modal from "@/components/ui/Modal"; +import { KeyedMutator } from "swr"; + +function SeverityBadge({ severity }: { severity: IncidentDto["severity"] }) { + let severityColor; + if (severity === "critical") { + severityColor = "red"; + } else if (severity === "info") { + severityColor = "blue"; + } else if (severity === "warning") { + severityColor = "yellow"; + } + return ( + + {severity} + + ); +} + +export function IncidentHeader({ + incident, + mutate, +}: { + incident: IncidentDto; + mutate: KeyedMutator; +}) { + const router = useRouter(); + const { data: session } = useSession(); + const apiUrl = useApiUrl(); + + const [isFormOpen, setIsFormOpen] = useState(false); + + const [runWorkflowModalIncident, setRunWorkflowModalIncident] = + useState(); + + const handleCloseForm = () => { + setIsFormOpen(false); + }; + + const handleFinishEdit = () => { + setIsFormOpen(false); + mutate(); + }; + const handleRunWorkflow = () => { + setRunWorkflowModalIncident(incident); + mutate(); + }; + + const handleStartEdit = () => { + setIsFormOpen(true); + }; + + return ( + <> +
+ + All Incidents{" "} + {" "} + {incident.is_confirmed ? "⚔️ " : "Possible "}Incident Details + +
+ + <SeverityBadge severity={incident.severity} /> + <span> + {incident.user_generated_name || incident.ai_generated_name} + </span> + + +
+ )} +
+ + + + + setRunWorkflowModalIncident(null)} + /> + + ); +} diff --git a/keep-ui/app/incidents/[id]/incident-info.tsx b/keep-ui/app/incidents/[id]/incident-overview.tsx similarity index 55% rename from keep-ui/app/incidents/[id]/incident-info.tsx rename to keep-ui/app/incidents/[id]/incident-overview.tsx index cc484e06a..db1d95b38 100644 --- a/keep-ui/app/incidents/[id]/incident-info.tsx +++ b/keep-ui/app/incidents/[id]/incident-overview.tsx @@ -1,33 +1,21 @@ -import { Badge, Button, Icon, Title } from "@tremor/react"; import { IncidentDto } from "../models"; -import CreateOrUpdateIncident from "../create-or-update-incident"; import Modal from "@/components/ui/Modal"; import React, { useState } from "react"; -import { MdBlock, MdDone, MdModeEdit, MdPlayArrow } from "react-icons/md"; import { useIncident, useIncidentFutureIncidents, } from "@/utils/hooks/useIncidents"; - -import { - deleteIncident, - handleConfirmPredictedIncident, -} from "../incident-candidate-actions"; -import { useSession } from "next-auth/react"; -import { useRouter } from "next/navigation"; -import { useApiUrl } from "utils/hooks/useConfig"; import { format } from "date-fns"; -import { ArrowUturnLeftIcon } from "@heroicons/react/24/outline"; import { Disclosure } from "@headlessui/react"; import classNames from "classnames"; import { IoChevronDown } from "react-icons/io5"; -import IncidentChangeStatusModal from "@/app/incidents/incident-change-status-modal"; import ChangeSameIncidentInThePast from "@/app/incidents/incident-change-same-in-the-past"; -import { STATUS_ICONS } from "@/app/incidents/statuses"; import remarkRehype from "remark-rehype"; import rehypeRaw from "rehype-raw"; import Markdown from "react-markdown"; -import ManualRunWorkflowModal from "@/app/workflows/manual-run-workflow-modal"; +import { Callout } from "@tremor/react"; +import { Link } from "@/components/ui"; +import { IncidentChangeStatusSelect } from "@/features/change-incident-status"; interface Props { incident: IncidentDto; @@ -91,45 +79,36 @@ function Summary({ ); } -export default function IncidentInformation({ incident }: Props) { - const router = useRouter(); - const { data: session } = useSession(); - const { mutate } = useIncident(incident.id); - const [isFormOpen, setIsFormOpen] = useState(false); - const apiUrl = useApiUrl(); - - const [runWorkflowModalIncident, setRunWorkflowModalIncident] = - useState(); - - const handleCloseForm = () => { - setIsFormOpen(false); - }; +function MergedCallout({ + merged_into_incident_id, +}: { + merged_into_incident_id: string; +}) { + const { data: merged_incident } = useIncident(merged_into_incident_id); - const handleStartEdit = () => { - setIsFormOpen(true); - }; + if (!merged_incident) { + return null; + } - const handleFinishEdit = () => { - setIsFormOpen(false); - mutate(); - }; - const handleRunWorkflow = () => { - setRunWorkflowModalIncident(incident); - mutate(); - }; + return ( + +

+ This incident was merged into{" "} + + {merged_incident?.user_generated_name || + merged_incident?.ai_generated_name} + +

+
+ ); +} - const [changeStatusIncident, setChangeStatusIncident] = - useState(); +export default function IncidentOverview({ incident }: Props) { + const { mutate } = useIncident(incident.id); const [changeSameIncidentInThePast, setChangeSameIncidentInThePast] = useState(); - const handleChangeStatus = (e: React.MouseEvent, incident: IncidentDto) => { - e.preventDefault(); - e.stopPropagation(); - setChangeStatusIncident(incident); - }; - const handleChangeSameIncidentInThePast = ( e: React.MouseEvent, incident: IncidentDto @@ -148,114 +127,25 @@ export default function IncidentInformation({ incident }: Props) { incident.id ); - const severity = incident.severity; - let severityColor; - if (severity === "critical") severityColor = "red"; - else if (severity === "info") severityColor = "blue"; - else if (severity === "warning") severityColor = "yellow"; - return (
-
- - {incident.is_confirmed ? "⚔️ " : "Possible "}Incident - - -
- )} - router.back()} + {incident.merged_into_incident_id && ( + -
-
- - {incident.severity} - - - {incident.user_generated_name || incident.ai_generated_name} - -
+ )} + {/*TODO: use this magic property to treat children like a children of a parent flex container */}

Status

-
handleChangeStatus(e, incident)} - className="capitalize flex-grow-0 inline-flex items-center cursor-pointer" - > - {STATUS_ICONS[incident.status]} {incident.status} -
+ { + mutate(); + }} + />
@@ -360,18 +250,6 @@ export default function IncidentInformation({ incident }: Props) { )}
- - - - {changeSameIncidentInThePast ? ( ) : null} - - setChangeStatusIncident(null)} - /> - setRunWorkflowModalIncident(null)} - />
); } diff --git a/keep-ui/app/incidents/[id]/incident-timeline.tsx b/keep-ui/app/incidents/[id]/incident-timeline.tsx index 94b3b5c5f..d865573a5 100644 --- a/keep-ui/app/incidents/[id]/incident-timeline.tsx +++ b/keep-ui/app/incidents/[id]/incident-timeline.tsx @@ -10,6 +10,7 @@ import Image from "next/image"; import AlertSeverity from "app/alerts/alert-severity"; import { EmptyStateCard } from "@/components/ui/EmptyStateCard"; import { useRouter } from "next/navigation"; +import { Card } from "@tremor/react"; const severityColors = { critical: "bg-red-300", @@ -359,7 +360,7 @@ export default function IncidentTimeline({ ); return ( -
+
{/* Time labels */} @@ -431,6 +432,6 @@ export default function IncidentTimeline({ />
)} -
+
); } diff --git a/keep-ui/app/incidents/[id]/incident-workflow-table.tsx b/keep-ui/app/incidents/[id]/incident-workflow-table.tsx index 8998333b7..f0eaf5641 100644 --- a/keep-ui/app/incidents/[id]/incident-workflow-table.tsx +++ b/keep-ui/app/incidents/[id]/incident-workflow-table.tsx @@ -15,6 +15,7 @@ import { TableRow, Button, Badge, + Card, } from "@tremor/react"; import { ExclamationTriangleIcon } from "@radix-ui/react-icons"; import Skeleton from "react-loading-skeleton"; @@ -186,65 +187,69 @@ export default function IncidentWorkflowTable({ incident }: Props) { return ( <> - {!isLoading && (workflows?.items ?? []).length === 0 && ( - - No workflows have been executed for this incident yet. - - )} - - - - {table.getHeaderGroups().map((headerGroup) => ( - - {headerGroup.headers.map((header) => ( - - {flexRender( - header.column.columnDef.header, - header.getContext() - )} - - ))} - - ))} - - {workflows && workflows.items.length > 0 && ( - - {table.getRowModel().rows.map((row) => ( - handleRowClick(row.original)} - > - {row.getVisibleCells().map((cell) => ( - - {flexRender(cell.column.columnDef.cell, cell.getContext())} - + + {!isLoading && (workflows?.items ?? []).length === 0 && ( + + No workflows have been executed for this incident yet. + + )} +
+ + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => ( + + {flexRender( + header.column.columnDef.header, + header.getContext() + )} + ))} ))} - - )} - {(isLoading || (workflows?.items ?? []).length === 0) && ( - - {Array(pagination.pageSize) - .fill("") - .map((_, index) => ( - - {columns.map((_, cellIndex) => ( - - + + {workflows && workflows.items.length > 0 && ( + + {table.getRowModel().rows.map((row) => ( + handleRowClick(row.original)} + > + {row.getVisibleCells().map((cell) => ( + + {flexRender( + cell.column.columnDef.cell, + cell.getContext() + )} ))} ))} - - )} -
+ + )} + {(isLoading || (workflows?.items ?? []).length === 0) && ( + + {Array(pagination.pageSize) + .fill("") + .map((_, index) => ( + + {columns.map((_, cellIndex) => ( + + + + ))} + + ))} + + )} + +
diff --git a/keep-ui/app/incidents/[id]/incident.tsx b/keep-ui/app/incidents/[id]/incident.tsx index a83360b73..43b657dba 100644 --- a/keep-ui/app/incidents/[id]/incident.tsx +++ b/keep-ui/app/incidents/[id]/incident.tsx @@ -1,7 +1,6 @@ "use client"; -import Loading from "app/loading"; -import { useIncident } from "utils/hooks/useIncidents"; -import IncidentInformation from "./incident-info"; +import { useState } from "react"; +import { FiActivity } from "react-icons/fi"; import { Badge, Card, @@ -12,18 +11,20 @@ import { TabPanels, Title, } from "@tremor/react"; -import IncidentAlerts from "./incident-alerts"; -import IncidentTimeline from "./incident-timeline"; import { CiBellOn, CiChat2, CiViewTimeline } from "react-icons/ci"; import { IoIosGitNetwork } from "react-icons/io"; -import IncidentChat from "./incident-chat"; import { Workflows } from "components/icons"; -import IncidentWorkflowTable from "./incident-workflow-table"; +import { useIncident } from "utils/hooks/useIncidents"; import { TopologyMap } from "@/app/topology/ui/map"; import { TopologySearchProvider } from "@/app/topology/TopologySearchContext"; -import { useState } from "react"; -import { FiActivity } from "react-icons/fi"; +import Loading from "app/loading"; +import IncidentWorkflowTable from "./incident-workflow-table"; +import IncidentOverview from "./incident-overview"; +import IncidentAlerts from "./incident-alerts"; +import IncidentTimeline from "./incident-timeline"; +import IncidentChat from "./incident-chat"; import IncidentActivity from "./incident-activity"; +import { IncidentHeader } from "./incident-header"; interface Props { incidentId: string; @@ -31,80 +32,73 @@ interface Props { // TODO: generate metadata with incident name export default function IncidentView({ incidentId }: Props) { - const { data: incident, isLoading, error } = useIncident(incidentId); + const { data: incident, mutate, isLoading, error } = useIncident(incidentId); const [index, setIndex] = useState(0); if (isLoading || !incident) return ; if (error) return Incident does not exist.; return ( - <> -
- -
- - + + + {/* Compensating for page-container padding, TODO: more robust solution */} + - {/* Compensating for page-container padding, TODO: more robust solution */} - - - Activity - - New - - - Alerts - Timeline - Topology - Workflows - - Chat - - New - - - - - + Overview and Alerts + + Activity + + New + + + Timeline + Topology + Workflows + Chat + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + +
); } diff --git a/keep-ui/app/incidents/create-or-update-incident.tsx b/keep-ui/app/incidents/create-or-update-incident.tsx index dfaf52940..2755b6746 100644 --- a/keep-ui/app/incidents/create-or-update-incident.tsx +++ b/keep-ui/app/incidents/create-or-update-incident.tsx @@ -21,6 +21,7 @@ import { useUsers } from "utils/hooks/useUsers"; const ReactQuill = typeof window === "object" ? require("react-quill") : () => false; import "react-quill/dist/quill.snow.css"; +import "./react-quill-override.css"; interface Props { incidentToEdit: IncidentDto | null; @@ -215,6 +216,7 @@ export default function CreateOrUpdateIncident({ modules={modules} formats={formats} // Add formats placeholder="What happened?" + className="border border-tremor-border rounded-tremor-default shadow-tremor-input" required={false} onValueChange={setIncidentUserSummary} /> diff --git a/keep-ui/app/incidents/incident-candidate-actions.tsx b/keep-ui/app/incidents/incident-candidate-actions.tsx index 89dbb53a1..cb5d536fa 100644 --- a/keep-ui/app/incidents/incident-candidate-actions.tsx +++ b/keep-ui/app/incidents/incident-candidate-actions.tsx @@ -37,22 +37,29 @@ export const deleteIncident = async ({ mutate, session, apiUrl, -}: Props) => { - if (confirm("Are you sure you want to delete this incident?")) { - const response = await fetch(`${apiUrl}/incidents/${incidentId}`, { - method: "DELETE", - headers: { - Authorization: `Bearer ${session?.accessToken}`, - }, - }); + skipConfirmation = false, +}: Props & { + skipConfirmation?: boolean; +}) => { + if ( + !skipConfirmation && + !confirm("Are you sure you want to delete this incident?") + ) { + return; + } + const response = await fetch(`${apiUrl}/incidents/${incidentId}`, { + method: "DELETE", + headers: { + Authorization: `Bearer ${session?.accessToken}`, + }, + }); - if (response.ok) { - await mutate(); - toast.success("Incident deleted successfully"); - return true; - } else { - toast.error("Failed to delete incident, contact us if this persists"); - return false; - } + if (response.ok) { + await mutate(); + toast.success("Incident deleted successfully"); + return true; + } else { + toast.error("Failed to delete incident, contact us if this persists"); + return false; } }; diff --git a/keep-ui/app/incidents/incident-change-status-modal.tsx b/keep-ui/app/incidents/incident-change-status-modal.tsx index b8c205c05..7c3d701f5 100644 --- a/keep-ui/app/incidents/incident-change-status-modal.tsx +++ b/keep-ui/app/incidents/incident-change-status-modal.tsx @@ -11,17 +11,7 @@ import { IncidentDto, Status } from "./models"; import { useApiUrl } from "utils/hooks/useConfig"; import { useSession } from "next-auth/react"; import { toast } from "react-toastify"; -import { - CheckCircleIcon, - ExclamationCircleIcon, - PauseIcon, -} from "@heroicons/react/24/outline"; - -const statusIcons = { - [Status.Firing]: , - [Status.Resolved]: , - [Status.Acknowledged]: , -}; +import { STATUS_ICONS } from "@/app/incidents/statuses"; const customSelectStyles = { control: ( @@ -81,7 +71,7 @@ export default function IncidentChangeStatusModal({ value: status, label: (
- {statusIcons[status]} + {STATUS_ICONS[status]} {status.charAt(0).toUpperCase() + status.slice(1)}
), diff --git a/keep-ui/app/incidents/incident-dropdown-menu.tsx b/keep-ui/app/incidents/incident-dropdown-menu.tsx new file mode 100644 index 000000000..5117168f5 --- /dev/null +++ b/keep-ui/app/incidents/incident-dropdown-menu.tsx @@ -0,0 +1,58 @@ +import { + ChevronDoubleRightIcon, + EllipsisHorizontalIcon, + PencilIcon, + PlayIcon, + TrashIcon, +} from "@heroicons/react/24/outline"; +import { DropdownMenu } from "@/components/ui/DropdownMenu"; +import { IncidentDto } from "./models"; + +interface Props { + incident: IncidentDto; + handleEdit: (incident: IncidentDto) => void; + handleRunWorkflow: (incident: IncidentDto) => void; + handleDelete: (incident: IncidentDto) => void; +} + +export function IncidentDropdownMenu({ + incident, + handleEdit, + handleRunWorkflow, + handleDelete, +}: Props) { + return ( + <> + + { + e.preventDefault(); + e.stopPropagation(); + handleEdit(incident); + }} + /> + { + e.preventDefault(); + e.stopPropagation(); + handleRunWorkflow(incident); + }} + /> + { + e.preventDefault(); + e.stopPropagation(); + handleDelete(incident); + }} + /> + + + ); +} diff --git a/keep-ui/app/incidents/incident-list-error.tsx b/keep-ui/app/incidents/incident-list-error.tsx new file mode 100644 index 000000000..2bf10c51a --- /dev/null +++ b/keep-ui/app/incidents/incident-list-error.tsx @@ -0,0 +1,24 @@ +import { Fragment } from "react"; +import { Button, Subtitle, Title } from "@tremor/react"; + +export const IncidentListError = () => { + return ( + +
+
+ Failed to load incidents + + Please try again. If the issue persists, contact us + + +
+
+
+ ); +}; diff --git a/keep-ui/app/incidents/IncidentPlaceholder.tsx b/keep-ui/app/incidents/incident-list-placeholder.tsx similarity index 91% rename from keep-ui/app/incidents/IncidentPlaceholder.tsx rename to keep-ui/app/incidents/incident-list-placeholder.tsx index ff5a4ff8d..3ed86d8f9 100644 --- a/keep-ui/app/incidents/IncidentPlaceholder.tsx +++ b/keep-ui/app/incidents/incident-list-placeholder.tsx @@ -1,16 +1,11 @@ import { Fragment } from "react"; import { Button, Subtitle, Title } from "@tremor/react"; - interface Props { setIsFormOpen: (value: boolean) => void; } - -export const IncidentPlaceholder = ({ - setIsFormOpen, -}: Props) => { - +export const IncidentListPlaceholder = ({ setIsFormOpen }: Props) => { const onCreateButtonClick = () => { setIsFormOpen(true); }; @@ -32,7 +27,6 @@ export const IncidentPlaceholder = ({ Create Incident
- ); }; diff --git a/keep-ui/app/incidents/incident.tsx b/keep-ui/app/incidents/incident-list.tsx similarity index 71% rename from keep-ui/app/incidents/incident.tsx rename to keep-ui/app/incidents/incident-list.tsx index 4fc8efaa2..783e2e517 100644 --- a/keep-ui/app/incidents/incident.tsx +++ b/keep-ui/app/incidents/incident-list.tsx @@ -1,18 +1,19 @@ "use client"; import { Card, Title, Subtitle, Button, Badge } from "@tremor/react"; import Loading from "app/loading"; -import { useState } from "react"; +import React, { useState } from "react"; import { IncidentDto } from "./models"; import CreateOrUpdateIncident from "./create-or-update-incident"; import IncidentsTable from "./incidents-table"; import { useIncidents, usePollIncidents } from "utils/hooks/useIncidents"; -import { IncidentPlaceholder } from "./IncidentPlaceholder"; +import { IncidentListPlaceholder } from "./incident-list-placeholder"; import Modal from "@/components/ui/Modal"; import { PlusCircleIcon } from "@heroicons/react/24/outline"; import PredictedIncidentsTable from "./predicted-incidents-table"; import { SortingState } from "@tanstack/react-table"; import { IncidentTableFilters } from "./incident-table-filters"; import { useIncidentFilterContext } from "./incident-table-filters-context"; +import { IncidentListError } from "@/app/incidents/incident-list-error"; interface Pagination { limit: number; @@ -27,7 +28,7 @@ interface Filters { affected_services: string[]; } -export default function Incident() { +export default function IncidentList() { const [incidentsPagination, setIncidentsPagination] = useState({ limit: 20, offset: 0, @@ -37,8 +38,14 @@ export default function Incident() { { id: "creation_time", desc: true }, ]); - const { statuses, severities, assignees, services, sources } = - useIncidentFilterContext(); + const { + statuses, + severities, + assignees, + services, + sources, + areFiltersApplied, + } = useIncidentFilterContext(); const filters: Filters = { status: statuses, @@ -52,6 +59,7 @@ export default function Incident() { data: incidents, isLoading, mutate: mutateIncidents, + error: incidentsError, } = useIncidents( true, incidentsPagination.limit, @@ -74,6 +82,7 @@ export default function Incident() { const handleCloseForm = () => { setIsFormOpen(false); + setIncidentToEdit(null); }; const handleStartEdit = (incident: IncidentDto) => { @@ -86,6 +95,50 @@ export default function Incident() { setIsFormOpen(false); }; + console.log({ + incidents, + filters, + }); + + function renderIncidents() { + if (incidentsError) { + return ( + + + + ); + } + + if (isLoading) { + // TODO: only show this on the initial load + return ( + + + + ); + } + + if (incidents && (incidents.items.length > 0 || areFiltersApplied)) { + return ( + + ); + } + + // This is shown on the cold page load. FIXME + return ( + + + + ); + } + return (
@@ -127,23 +180,9 @@ export default function Incident() {
+ {/* Filters are placed here so the table could be in loading/not-found state without affecting the controls */} - - {isLoading ? ( - - ) : incidents && incidents.items.length > 0 ? ( - - ) : ( - - )} - + {renderIncidents()}
+
{STATUS_ICONS[incident.status]}
+
+
{incident.user_generated_name}
+
+ + ); +} + +interface Props { + incidents: IncidentDto[]; + mutate: () => void; + handleClose: () => void; + onSuccess?: () => void; +} + +interface OptionType { + value: string; + label: JSX.Element; +} + +// TODO: unify all selects into components/ui/Select.tsx +const customSelectStyles: StylesConfig< + OptionType, + false, + GroupBase +> = { + control: (provided, state) => ({ + ...provided, + borderColor: state.isFocused ? "orange" : "rgb(229 231 235)", + borderRadius: "0.5rem", + "&:hover": { borderColor: "orange" }, + boxShadow: state.isFocused ? "0 0 0 1px orange" : provided.boxShadow, + }), + singleValue: (provided) => ({ + ...provided, + display: "flex", + alignItems: "center", + }), + menu: (provided) => ({ + ...provided, + color: "orange", + }), + option: (provided, state) => ({ + ...provided, + backgroundColor: state.isSelected ? "orange" : provided.backgroundColor, + "&:hover": { backgroundColor: state.isSelected ? "orange" : "#f5f5f5" }, + color: state.isSelected ? "white" : "black", + }), +}; + +export default function IncidentMergeModal({ + incidents, + mutate, + handleClose, + onSuccess, +}: Props) { + const { data: session } = useSession(); + const apiUrl = useApiUrl(); + + const [destinationIncidentId, setDestinationIncidentId] = useState( + incidents[0].id + ); + const destinationIncident = incidents.find( + (incident) => incident.id === destinationIncidentId + ); + const sourceIncidents = incidents.filter( + (incident) => incident.id !== destinationIncidentId + ); + + const incidentOptions = useMemo(() => { + return incidents.map((incident) => ({ + value: incident.id, + label: , + })); + }, [incidents]); + + const selectValue = useMemo(() => { + return { + value: destinationIncidentId, + label: , + }; + }, [destinationIncidentId, destinationIncident]); + + const errors = useMemo(() => { + const errorDict: Record = {}; + if (sourceIncidents.every((i) => i.status === Status.Merged)) { + errorDict["alreadyMerged"] = true; + } + return errorDict; + }, [sourceIncidents]); + + const handleMerge = async () => { + if (!sourceIncidents.length || !destinationIncident) { + toast.error("Please select incidents to merge."); + return; + } + + try { + const response = await fetch(`${apiUrl}/incidents/merge`, { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${session?.accessToken}`, + }, + body: JSON.stringify({ + source_incident_ids: sourceIncidents.map((incident) => incident.id), + destination_incident_id: destinationIncident.id, + }), + }); + + if (response.ok) { + toast.success("Incidents merged successfully!"); + onSuccess?.(); + mutate(); + handleClose(); + } else { + toast.error("Failed to merge incidents."); + } + } catch (error) { + toast.error("An error occurred while merging incidents."); + } + }; + + return ( + +
+
+ Merge Incidents + + Alerts from the following incidents will be moved into the + destination incident and the source incidents would be marked as{" "} + Merged + +
+
+
+ Source Incidents + {errors.alreadyMerged && ( +

+ These incidents were already merged +

+ )} +
+
+ {sourceIncidents.map((incident) => ( + + ))} +
+
+
+
+ Destination Incident +
+ + ); +} diff --git a/keep-ui/package-lock.json b/keep-ui/package-lock.json index ab6a71033..51d1bda23 100644 --- a/keep-ui/package-lock.json +++ b/keep-ui/package-lock.json @@ -25,7 +25,7 @@ "@fortawesome/free-solid-svg-icons": "^6.4.0", "@fortawesome/react-fontawesome": "^0.2.0", "@headlessui/react": "^1.7.14", - "@heroicons/react": "^2.0.18", + "@heroicons/react": "^2.1.5", "@mui/material": "^5.15.18", "@radix-ui/react-icons": "^1.3.0", "@svgr/webpack": "^8.0.1", @@ -4007,9 +4007,9 @@ } }, "node_modules/@heroicons/react": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@heroicons/react/-/react-2.1.3.tgz", - "integrity": "sha512-fEcPfo4oN345SoqdlCDdSa4ivjaKbk0jTd+oubcgNxnNgAfzysfwWfQUr+51wigiWHQQRiZNd1Ao0M5Y3M2EGg==", + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@heroicons/react/-/react-2.1.5.tgz", + "integrity": "sha512-FuzFN+BsHa+7OxbvAERtgBTNeZpUjgM/MIizfVkSCL2/edriN0Hx/DWRCR//aPYwO5QX/YlgLGXk+E3PcfZwjA==", "peerDependencies": { "react": ">= 16" } diff --git a/keep-ui/package.json b/keep-ui/package.json index 7efcbc8e8..089b83050 100644 --- a/keep-ui/package.json +++ b/keep-ui/package.json @@ -26,7 +26,7 @@ "@fortawesome/free-solid-svg-icons": "^6.4.0", "@fortawesome/react-fontawesome": "^0.2.0", "@headlessui/react": "^1.7.14", - "@heroicons/react": "^2.0.18", + "@heroicons/react": "^2.1.5", "@mui/material": "^5.15.18", "@radix-ui/react-icons": "^1.3.0", "@svgr/webpack": "^8.0.1", diff --git a/keep-ui/tailwind.config.js b/keep-ui/tailwind.config.js index 595f66d20..3e6a5b5f5 100644 --- a/keep-ui/tailwind.config.js +++ b/keep-ui/tailwind.config.js @@ -3,6 +3,8 @@ module.exports = { content: [ "./app/**/*.{js,ts,jsx,tsx}", "./components/**/*.{js,ts,jsx,tsx}", + "./entities/**/*.{js,ts,jsx,tsx}", + "./features/**/*.{js,ts,jsx,tsx}", "./node_modules/@tremor/**/*.{js,ts,jsx,tsx}", ], darkMode: "class", @@ -102,6 +104,12 @@ module.exports = { "tremor-title": ["1.125rem", { lineHeight: "1.75rem" }], "tremor-metric": ["1.875rem", { lineHeight: "2.25rem" }], }, + animation: { + "scroll-shadow-left": + "auto linear 0s 1 normal none running scroll-shadow-left", + "scroll-shadow-right": + "auto linear 0s 1 normal none running scroll-shadow-right", + }, }, }, safelist: [ diff --git a/keep-ui/tsconfig.json b/keep-ui/tsconfig.json index 2f8f41709..6d7822423 100644 --- a/keep-ui/tsconfig.json +++ b/keep-ui/tsconfig.json @@ -26,6 +26,8 @@ "@/app/*": ["./app/*"], "@/pages/*": ["./pages/*"], "@/utils/*": ["./utils/*"], + "@/entities/*": ["./entities/*"], + "@/features/*": ["./features/*"] } }, "include": [ diff --git a/keep-ui/utils/hooks/useIncidents.ts b/keep-ui/utils/hooks/useIncidents.ts index b3ba58a26..4c4e8f25d 100644 --- a/keep-ui/utils/hooks/useIncidents.ts +++ b/keep-ui/utils/hooks/useIncidents.ts @@ -36,7 +36,7 @@ export const useIncidents = ( } ) => { const apiUrl = useApiUrl(); - const { data: session } = useSession(); + const { data: session, status: sessionStatus } = useSession(); const filtersParams = new URLSearchParams(); @@ -50,7 +50,7 @@ export const useIncidents = ( } }); - return useSWR( + const swrValue = useSWR( () => session ? `${apiUrl}/incidents?confirmed=${confirmed}&limit=${limit}&offset=${offset}&sorting=${ @@ -60,6 +60,11 @@ export const useIncidents = ( (url) => fetcher(url, session?.accessToken), options ); + + return { + ...swrValue, + isLoading: swrValue.isLoading || sessionStatus === "loading", + }; }; export const useIncidentAlerts = ( diff --git a/keep/api/core/db.py b/keep/api/core/db.py index 9d6bc7380..503e0e018 100644 --- a/keep/api/core/db.py +++ b/keep/api/core/db.py @@ -3081,6 +3081,8 @@ def add_alerts_to_incident( incident.affected_services = list( set(incident.affected_services if incident.affected_services else []) | set(alerts_data_for_incident["services"]) ) + # If incident has alerts already, use the max severity between existing and new alerts, otherwise use the new alerts max severity + incident.severity = max(incident.severity, alerts_data_for_incident["max_severity"].order) if incident.alerts_count else alerts_data_for_incident["max_severity"].order incident.alerts_count += alerts_data_for_incident["count"] alert_to_incident_entries = [ @@ -3114,7 +3116,6 @@ def add_alerts_to_incident( incident.start_time = started_at incident.last_seen_time = last_seen_at - incident.severity = alerts_data_for_incident["max_severity"].order session.add(incident) session.commit() @@ -3255,6 +3256,7 @@ def remove_alerts_to_incident_by_incident_id( ] incident.alerts_count -= alerts_data_for_incident["count"] + incident.severity = alerts_data_for_incident["max_severity"].order incident.start_time = started_at incident.last_seen_time = last_seen_at @@ -3264,6 +3266,80 @@ def remove_alerts_to_incident_by_incident_id( return deleted +class DestinationIncidentNotFound(Exception): + pass + + +def merge_incidents_to_id( + tenant_id: str, + source_incident_ids: List[UUID], + # Maybe to add optional destionation_incident_dto to merge to + destination_incident_id: UUID, + merged_by: str | None = None, +) -> Tuple[List[UUID], List[UUID], List[UUID]]: + with Session(engine) as session: + destination_incident = session.exec( + select(Incident) + .where( + Incident.tenant_id == tenant_id, Incident.id == destination_incident_id + ) + .options(joinedload(Incident.alerts)) + ).first() + + if not destination_incident: + raise DestinationIncidentNotFound( + f"Destination incident with id {destination_incident_id} not found" + ) + + source_incidents = session.exec( + select(Incident).filter( + Incident.tenant_id == tenant_id, + Incident.id.in_(source_incident_ids), + ) + ).all() + + merged_incident_ids = [] + skipped_incident_ids = [] + failed_incident_ids = [] + for source_incident in source_incidents: + source_incident_alerts_ids = [alert.id for alert in source_incident.alerts] + if not source_incident_alerts_ids: + logger.info(f"Source incident {source_incident.id} doesn't have alerts") + skipped_incident_ids.append(source_incident.id) + continue + source_incident.merged_into_incident_id = destination_incident.id + source_incident.merged_at = datetime.now(tz=timezone.utc) + source_incident.status = IncidentStatus.MERGED.value + source_incident.merged_by = merged_by + try: + remove_alerts_to_incident_by_incident_id( + tenant_id, + source_incident.id, + [alert.id for alert in source_incident.alerts], + ) + except OperationalError as e: + logger.error( + f"Error removing alerts to incident {source_incident.id}: {e}" + ) + try: + add_alerts_to_incident( + tenant_id, + destination_incident, + source_incident_alerts_ids, + session=session, + ) + merged_incident_ids.append(source_incident.id) + except OperationalError as e: + logger.error( + f"Error adding alerts to incident {destination_incident.id} from {source_incident.id}: {e}" + ) + failed_incident_ids.append(source_incident.id) + + session.commit() + session.refresh(destination_incident) + return merged_incident_ids, skipped_incident_ids, failed_incident_ids + + def get_alerts_count( tenant_id: str, ) -> int: diff --git a/keep/api/models/alert.py b/keep/api/models/alert.py index c49a89bfb..c9de2b43f 100644 --- a/keep/api/models/alert.py +++ b/keep/api/models/alert.py @@ -4,7 +4,7 @@ import logging import uuid from enum import Enum -from typing import Any, Dict, List, Optional +from typing import Any, Dict, List, Optional, TYPE_CHECKING from uuid import UUID import pytz @@ -19,6 +19,9 @@ from sqlalchemy import desc from sqlmodel import col +if TYPE_CHECKING: + from keep.api.models.db.alert import Incident + logger = logging.getLogger(__name__) @@ -108,6 +111,8 @@ class IncidentStatus(Enum): RESOLVED = "resolved" # Incident has been acknowledged but not resolved ACKNOWLEDGED = "acknowledged" + # Incident was merged with another incident + MERGED = "merged" class IncidentSeverity(SeverityBaseInterface): @@ -409,6 +414,10 @@ class IncidentDto(IncidentDtoIn): same_incident_in_the_past_id: UUID | None + merged_into_incident_id: UUID | None + merged_by: str | None + merged_at: datetime.datetime | None + _tenant_id: str = PrivateAttr() def __str__(self) -> str: @@ -455,7 +464,7 @@ def set_default_values(cls, values: Dict[str, Any]) -> Dict[str, Any]: return values @classmethod - def from_db_incident(cls, db_incident): + def from_db_incident(cls, db_incident: "Incident"): severity = ( IncidentSeverity.from_number(db_incident.severity) @@ -483,6 +492,9 @@ def from_db_incident(cls, db_incident): services=db_incident.affected_services or [], rule_fingerprint=db_incident.rule_fingerprint, same_incident_in_the_past_id=db_incident.same_incident_in_the_past_id, + merged_into_incident_id=db_incident.merged_into_incident_id, + merged_by=db_incident.merged_by, + merged_at=db_incident.merged_at, ) # This field is required for getting alerts when required @@ -490,6 +502,19 @@ def from_db_incident(cls, db_incident): return dto +class MergeIncidentsRequestDto(BaseModel): + source_incident_ids: list[UUID] + destination_incident_id: UUID + + +class MergeIncidentsResponseDto(BaseModel): + merged_incident_ids: list[UUID] + skipped_incident_ids: list[UUID] + failed_incident_ids: list[UUID] + destination_incident_id: UUID + message: str + + class DeduplicationRuleDto(BaseModel): id: str | None # UUID name: str diff --git a/keep/api/models/db/alert.py b/keep/api/models/db/alert.py index b46690734..473574e0a 100644 --- a/keep/api/models/db/alert.py +++ b/keep/api/models/db/alert.py @@ -126,7 +126,7 @@ class Incident(SQLModel, table=True): rule_id: UUID | None = Field( sa_column=Column( UUIDType(binary=False), - ForeignKey("rule.id", use_alter=False, ondelete="CASCADE"), + ForeignKey("rule.id", ondelete="CASCADE"), nullable=True, ), ) @@ -137,7 +137,7 @@ class Incident(SQLModel, table=True): same_incident_in_the_past_id: UUID | None = Field( sa_column=Column( UUIDType(binary=False), - ForeignKey("incident.id", use_alter=False, ondelete="SET NULL"), + ForeignKey("incident.id", ondelete="SET NULL"), nullable=True, ), ) @@ -146,11 +146,38 @@ class Incident(SQLModel, table=True): back_populates="same_incidents_in_the_future", sa_relationship_kwargs=dict( remote_side="Incident.id", + foreign_keys="[Incident.same_incident_in_the_past_id]", ), ) - same_incidents_in_the_future: list["Incident"] = Relationship( + same_incidents_in_the_future: List["Incident"] = Relationship( back_populates="same_incident_in_the_past", + sa_relationship_kwargs=dict( + foreign_keys="[Incident.same_incident_in_the_past_id]", + ), + ) + + merged_into_incident_id: UUID | None = Field( + sa_column=Column( + UUIDType(binary=False), + ForeignKey("incident.id", ondelete="SET NULL"), + nullable=True, + ), + ) + merged_at: datetime | None = Field(default=None) + merged_by: str | None = Field(default=None) + merged_into: Optional["Incident"] = Relationship( + back_populates="merged_incidents", + sa_relationship_kwargs=dict( + remote_side="Incident.id", + foreign_keys="[Incident.merged_into_incident_id]", + ), + ) + merged_incidents: List["Incident"] = Relationship( + back_populates="merged_into", + sa_relationship_kwargs=dict( + foreign_keys="[Incident.merged_into_incident_id]", + ), ) def __init__(self, **kwargs): diff --git a/keep/api/models/db/migrations/versions/2024-10-23-15-21_89b4d3905d26.py b/keep/api/models/db/migrations/versions/2024-10-23-15-21_89b4d3905d26.py new file mode 100644 index 000000000..e34207606 --- /dev/null +++ b/keep/api/models/db/migrations/versions/2024-10-23-15-21_89b4d3905d26.py @@ -0,0 +1,50 @@ +"""Merge Incidents + +Revision ID: 89b4d3905d26 +Revises: 8438f041ee0e +Create Date: 2024-10-21 20:48:40.151171 + +""" + +import sqlalchemy as sa +import sqlalchemy_utils +import sqlmodel +from alembic import op + +# revision identifiers, used by Alembic. +revision = "89b4d3905d26" +down_revision = "8438f041ee0e" +branch_labels = None +depends_on = None + + +def upgrade() -> None: + with op.batch_alter_table("incident", schema=None) as batch_op: + batch_op.add_column( + sa.Column( + "merged_into_incident_id", + sqlalchemy_utils.types.uuid.UUIDType(binary=False), + nullable=True, + ) + ) + batch_op.add_column(sa.Column("merged_at", sa.DateTime(), nullable=True)) + batch_op.add_column( + sa.Column("merged_by", sqlmodel.sql.sqltypes.AutoString(), nullable=True) + ) + batch_op.create_foreign_key( + "fk_incident_merged_into_incident_id", + "incident", + ["merged_into_incident_id"], + ["id"], + ondelete="SET NULL", + ) + + +def downgrade() -> None: + with op.batch_alter_table("incident", schema=None) as batch_op: + batch_op.drop_constraint( + "fk_incident_merged_into_incident_id", type_="foreignkey" + ) + batch_op.drop_column("merged_by") + batch_op.drop_column("merged_at") + batch_op.drop_column("merged_into_incident_id") diff --git a/keep/api/routes/incidents.py b/keep/api/routes/incidents.py index bf2921bd8..ed87d105a 100644 --- a/keep/api/routes/incidents.py +++ b/keep/api/routes/incidents.py @@ -28,6 +28,9 @@ get_workflow_executions_for_incident_or_alert, remove_alerts_to_incident_by_incident_id, update_incident_from_dto_by_id, + get_incidents_meta_for_tenant, + merge_incidents_to_id, + DestinationIncidentNotFound, ) from keep.api.core.dependencies import get_pusher_client from keep.api.core.elastic import ElasticClient @@ -37,10 +40,12 @@ IncidentDto, IncidentDtoIn, IncidentListFilterParamsDto, + MergeIncidentsRequestDto, IncidentSeverity, IncidentSorting, IncidentStatus, IncidentStatusChangeDto, + MergeIncidentsResponseDto, ) from keep.api.models.db.alert import AlertActionType, AlertAudit from keep.api.routes.alerts import _enrich_alert @@ -51,6 +56,7 @@ IncidentsPaginatedResultsDto, WorkflowExecutionsPaginatedResultsDto, ) +from keep.api.utils.pluralize import pluralize from keep.identitymanager.authenticatedentity import AuthenticatedEntity from keep.identitymanager.identitymanagerfactory import IdentityManagerFactory from keep.workflowmanager.workflowmanager import WorkflowManager @@ -348,6 +354,54 @@ def delete_incident( return Response(status_code=202) +@router.post( + "/merge", description="Merge incidents", response_model=MergeIncidentsResponseDto +) +def merge_incidents( + command: MergeIncidentsRequestDto, + authenticated_entity: AuthenticatedEntity = Depends( + IdentityManagerFactory.get_auth_verifier(["write:incident"]) + ), +) -> MergeIncidentsResponseDto: + tenant_id = authenticated_entity.tenant_id + logger.info( + "Merging incidents", + extra={ + "source_incident_ids": command.source_incident_ids, + "destination_incident_id": command.destination_incident_id, + "tenant_id": tenant_id, + }, + ) + + try: + merged_ids, skipped_ids, failed_ids = merge_incidents_to_id( + tenant_id, + command.source_incident_ids, + command.destination_incident_id, + authenticated_entity.email, + ) + + if not merged_ids: + message = "No incidents merged" + else: + message = f"{pluralize(len(merged_ids), 'incident')} merged into {command.destination_incident_id} successfully" + + if skipped_ids: + message += f", {pluralize(len(skipped_ids), 'incident')} were skipped" + if failed_ids: + message += f", {pluralize(len(failed_ids), 'incident')} failed to merge" + + return MergeIncidentsResponseDto( + merged_incident_ids=merged_ids, + skipped_incident_ids=skipped_ids, + failed_incident_ids=failed_ids, + destination_incident_id=command.destination_incident_id, + message=message, + ) + except DestinationIncidentNotFound as e: + raise HTTPException(status_code=400, detail=str(e)) + + @router.get( "/{incident_id}/alerts", description="Get incident alerts by incident incident id", diff --git a/keep/api/utils/pluralize.py b/keep/api/utils/pluralize.py new file mode 100644 index 000000000..7083ca931 --- /dev/null +++ b/keep/api/utils/pluralize.py @@ -0,0 +1,26 @@ +# Maybe to use 'pluralize' from 'inflect' library in the future +def pluralize(count: int, singular: str, plural: str | None = None, include_count: bool = True) -> str: + """ + Returns a string with the correct plural or singular form based on count. + + Args: + count: The number of items + singular: The singular form of the word + plural: The plural form of the word. If None, appends 's' to singular form + include_count: Whether to include the count in the returned string + + Examples: + >>> pluralize(1, "incident") + "1 incident" + >>> pluralize(2, "incident") + "2 incidents" + >>> pluralize(2, "category", "categories") + "2 categories" + >>> pluralize(1, "incident", include_count=False) + "incident" + """ + if plural is None: + plural = singular + 's' + + word = plural if count != 1 else singular + return f"{count} {word}" if include_count else word \ No newline at end of file diff --git a/tests/test_incidents.py b/tests/test_incidents.py index b9758b638..984da9473 100644 --- a/tests/test_incidents.py +++ b/tests/test_incidents.py @@ -13,7 +13,9 @@ get_incident_by_id, get_last_incidents, remove_alerts_to_incident_by_incident_id, - get_incident_alerts_by_incident_id + get_incident_alerts_by_incident_id, + merge_incidents_to_id, + create_alert, ) from keep.api.core.db_utils import get_json_extract_field from keep.api.core.dependencies import SINGLE_TENANT_UUID @@ -22,6 +24,7 @@ AlertStatus, IncidentSeverity, IncidentStatus, + IncidentDto, ) from keep.api.models.db.alert import Alert, AlertToIncident from keep.api.utils.enrichment_helpers import convert_db_alerts_to_dto_alerts @@ -178,30 +181,36 @@ def test_get_last_incidents(db_session, create_alert): status_cycle = cycle([s.value for s in IncidentStatus]) services_cycle = cycle(["keep", None]) - for i in range(50): + for i in range(60): severity = next(severity_cycle) status = next(status_cycle) - incident = create_incident_from_dict(SINGLE_TENANT_UUID, { - "user_generated_name": f"test-{i}", - "user_summary": f"test-{i}", - "is_confirmed": True, - "severity": severity, - "status": status, - }) - create_alert( - f"alert-test-{i}", - AlertStatus(status), - datetime.utcnow(), + service = next(services_cycle) + incident = create_incident_from_dict( + SINGLE_TENANT_UUID, { - "severity": AlertSeverity.from_number(severity), - "service": next(services_cycle), - } - ) - alert = db_session.query(Alert).order_by(Alert.timestamp.desc()).first() - - add_alerts_to_incident_by_incident_id( - SINGLE_TENANT_UUID, incident.id, [alert.id] + "user_generated_name": f"test-{i}", + "user_summary": f"test-{i}", + "is_confirmed": True, + "severity": severity, + "status": status, + }, ) + # Merged incidents don't have alerts + if status != IncidentStatus.MERGED.value: + create_alert( + f"alert-test-{i}", + AlertStatus(status), + datetime.utcnow(), + { + "severity": AlertSeverity.from_number(severity), + "service": service, + }, + ) + alert = db_session.query(Alert).order_by(Alert.timestamp.desc()).first() + + add_alerts_to_incident_by_incident_id( + SINGLE_TENANT_UUID, incident.id, [alert.id] + ) incidents_default, incidents_default_count = get_last_incidents(SINGLE_TENANT_UUID) assert len(incidents_default) == 0 @@ -211,7 +220,7 @@ def test_get_last_incidents(db_session, create_alert): SINGLE_TENANT_UUID, is_confirmed=True ) assert len(incidents_confirmed) == 25 - assert incidents_confirmed_count == 50 + assert incidents_confirmed_count == 60 for i in range(25): assert incidents_confirmed[i].user_generated_name == f"test-{i}" @@ -219,7 +228,7 @@ def test_get_last_incidents(db_session, create_alert): SINGLE_TENANT_UUID, is_confirmed=True, limit=5 ) assert len(incidents_limit_5) == 5 - assert incidents_count_limit_5 == 50 + assert incidents_count_limit_5 == 60 for i in range(5): assert incidents_limit_5[i].user_generated_name == f"test-{i}" @@ -228,7 +237,7 @@ def test_get_last_incidents(db_session, create_alert): ) assert len(incidents_limit_5_page_2) == 5 - assert incidents_count_limit_5_page_2 == 50 + assert incidents_count_limit_5_page_2 == 60 for i, j in enumerate(range(5, 10)): assert incidents_limit_5_page_2[i].user_generated_name == f"test-{j}" @@ -241,7 +250,10 @@ def test_get_last_incidents(db_session, create_alert): SINGLE_TENANT_UUID, is_confirmed=True, with_alerts=True ) for i in range(25): - assert len(incidents_with_alerts[i].alerts) == 1 + if incidents_with_alerts[i].status == IncidentStatus.MERGED.value: + assert len(incidents_with_alerts[i].alerts) == 0 + else: + assert len(incidents_with_alerts[i].alerts) == 1 # Test sorting @@ -255,26 +267,40 @@ def test_get_last_incidents(db_session, create_alert): # Test filters filters_1 = {"severity": [1]} - incidents_with_filters_1, _ = get_last_incidents(SINGLE_TENANT_UUID, is_confirmed=True, filters=filters_1, limit=100) - assert len(incidents_with_filters_1) == 10 + incidents_with_filters_1, _ = get_last_incidents( + SINGLE_TENANT_UUID, is_confirmed=True, filters=filters_1, limit=100 + ) + assert len(incidents_with_filters_1) == 12 assert all([i.severity == 1 for i in incidents_with_filters_1]) filters_2 = {"status": ["firing", "acknowledged"]} - incidents_with_filters_2, _ = get_last_incidents(SINGLE_TENANT_UUID, is_confirmed=True, filters=filters_2, limit=100) - assert len(incidents_with_filters_2) == 17 + 16 - assert all([i.status in ["firing", "acknowledged"] for i in incidents_with_filters_2]) + incidents_with_filters_2, _ = get_last_incidents( + SINGLE_TENANT_UUID, is_confirmed=True, filters=filters_2, limit=100 + ) + assert ( + len(incidents_with_filters_2) == 15 + 15 + ) # 15 confirmed, 15 acknowledged because 60 incidents with cycled status + assert all( + [i.status in ["firing", "acknowledged"] for i in incidents_with_filters_2] + ) filters_3 = {"sources": ["keep"]} - incidents_with_filters_3, _ = get_last_incidents(SINGLE_TENANT_UUID, is_confirmed=True, filters=filters_3, limit=100) - assert len(incidents_with_filters_3) == 50 + incidents_with_filters_3, _ = get_last_incidents( + SINGLE_TENANT_UUID, is_confirmed=True, filters=filters_3, limit=100 + ) + assert len(incidents_with_filters_3) == 45 # 60 minus 15 merged with no alerts assert all(["keep" in i.sources for i in incidents_with_filters_3]) filters_4 = {"sources": ["grafana"]} - incidents_with_filters_4, _ = get_last_incidents(SINGLE_TENANT_UUID, is_confirmed=True, filters=filters_4, limit=100) + incidents_with_filters_4, _ = get_last_incidents( + SINGLE_TENANT_UUID, is_confirmed=True, filters=filters_4, limit=100 + ) assert len(incidents_with_filters_4) == 0 filters_5 = {"affected_services": "keep"} - incidents_with_filters_5, _ = get_last_incidents(SINGLE_TENANT_UUID, is_confirmed=True, filters=filters_5, limit=100) - assert len(incidents_with_filters_5) == 25 + incidents_with_filters_5, _ = get_last_incidents( + SINGLE_TENANT_UUID, is_confirmed=True, filters=filters_5, limit=100 + ) + assert len(incidents_with_filters_5) == 30 # half of incidents assert all(["keep" in i.affected_services for i in incidents_with_filters_5]) @@ -460,3 +486,221 @@ def test_add_alerts_with_same_fingerprint_to_incident(db_session, create_alert): assert len(incident.alerts) == 0 +def test_merge_incidents(db_session, create_alert, setup_stress_alerts_no_elastic): + incident_1 = create_incident_from_dict( + SINGLE_TENANT_UUID, + { + "user_generated_name": "Incident with info severity (destination)", + "user_summary": "Incident with info severity (destination)", + }, + ) + create_alert( + "fp1", + AlertStatus.FIRING, + datetime.utcnow(), + {"severity": AlertSeverity.INFO.value}, + ) + create_alert( + f"fp1", + AlertStatus.FIRING, + datetime.utcnow(), + {"severity": AlertSeverity.INFO.value}, + ) + create_alert( + f"fp2", + AlertStatus.FIRING, + datetime.utcnow(), + {"severity": AlertSeverity.INFO.value}, + ) + alerts_1 = db_session.query(Alert).all() + add_alerts_to_incident_by_incident_id( + SINGLE_TENANT_UUID, incident_1.id, [a.id for a in alerts_1] + ) + incident_2 = create_incident_from_dict( + SINGLE_TENANT_UUID, + { + "user_generated_name": "Incident with critical severity", + "user_summary": "Incident with critical severity", + }, + ) + create_alert( + "fp20", + AlertStatus.FIRING, + datetime.utcnow(), + {"severity": AlertSeverity.CRITICAL.value}, + ) + create_alert( + f"fp20", + AlertStatus.FIRING, + datetime.utcnow(), + {"severity": AlertSeverity.CRITICAL.value}, + ) + create_alert( + f"fp20", + AlertStatus.FIRING, + datetime.utcnow(), + {"severity": AlertSeverity.CRITICAL.value}, + ) + alerts_2 = db_session.query(Alert).filter(Alert.fingerprint.startswith("fp20")).all() + add_alerts_to_incident_by_incident_id( + SINGLE_TENANT_UUID, incident_2.id, [a.id for a in alerts_2] + ) + incident_3 = create_incident_from_dict( + SINGLE_TENANT_UUID, + { + "user_generated_name": "Incident with warning severity", + "user_summary": "Incident with warning severity", + }, + ) + create_alert( + "fp30", + AlertStatus.FIRING, + datetime.utcnow(), + {"severity": AlertSeverity.WARNING.value}, + ) + create_alert( + f"fp30", + AlertStatus.FIRING, + datetime.utcnow(), + {"severity": AlertSeverity.WARNING.value}, + ) + create_alert( + f"fp30", + AlertStatus.FIRING, + datetime.utcnow(), + {"severity": AlertSeverity.INFO.value}, + ) + alerts_3 = db_session.query(Alert).filter(Alert.fingerprint.startswith("fp30")).all() + add_alerts_to_incident_by_incident_id( + SINGLE_TENANT_UUID, incident_3.id, [a.id for a in alerts_3] + ) + + # before merge + incident_1 = get_incident_by_id(SINGLE_TENANT_UUID, incident_1.id) + assert incident_1.severity == IncidentSeverity.INFO.order + incident_2 = get_incident_by_id(SINGLE_TENANT_UUID, incident_2.id) + assert incident_2.severity == IncidentSeverity.CRITICAL.order + incident_3 = get_incident_by_id(SINGLE_TENANT_UUID, incident_3.id) + assert incident_3.severity == IncidentSeverity.WARNING.order + + merge_incidents_to_id( + SINGLE_TENANT_UUID, + [incident_2.id, incident_3.id], + incident_1.id, + "test-user-email", + ) + + incident_1 = get_incident_by_id(SINGLE_TENANT_UUID, incident_1.id, with_alerts=True) + assert len(incident_1.alerts) == 9 + assert incident_1.severity == IncidentSeverity.CRITICAL.order + + incident_2 = get_incident_by_id(SINGLE_TENANT_UUID, incident_2.id, with_alerts=True) + assert len(incident_2.alerts) == 0 + assert incident_2.status == IncidentStatus.MERGED.value + assert incident_2.merged_into_incident_id == incident_1.id + assert incident_2.merged_at is not None + assert incident_2.merged_by == "test-user-email" + + incident_3 = get_incident_by_id(SINGLE_TENANT_UUID, incident_3.id, with_alerts=True) + assert len(incident_3.alerts) == 0 + assert incident_3.status == IncidentStatus.MERGED.value + assert incident_3.merged_into_incident_id == incident_1.id + assert incident_3.merged_at is not None + assert incident_3.merged_by == "test-user-email" + + +@pytest.mark.parametrize("test_app", ["NO_AUTH"], indirect=True) +def test_merge_incidents_app( + db_session, client, test_app, setup_stress_alerts_no_elastic, create_alert +): + incident_1 = create_incident_from_dict( + SINGLE_TENANT_UUID, + {"user_generated_name": "Incident with info severity (destination)", "user_summary": "Incident with info severity (destination)"}, + ) + for i in range(50): + create_alert( + f"alert-1-{i}", + AlertStatus.FIRING, + datetime.utcnow(), + {"severity": AlertSeverity.INFO.value}, + ) + alerts_1 = db_session.query(Alert).filter(Alert.fingerprint.startswith("alert-1-")).all() + add_alerts_to_incident_by_incident_id( + SINGLE_TENANT_UUID, incident_1.id, [a.id for a in alerts_1] + ) + incident_2 = create_incident_from_dict( + SINGLE_TENANT_UUID, + {"user_generated_name": "Incident with critical severity", "user_summary": "Incident with critical severity"}, + ) + for i in range(50): + create_alert( + f"alert-2-{i}", + AlertStatus.FIRING, + datetime.utcnow(), + {"severity": AlertSeverity.CRITICAL.value, "service": "second-service"}, + ) + alerts_2 = ( + db_session.query(Alert).filter(Alert.fingerprint.startswith("alert-2-")).all() + ) + add_alerts_to_incident_by_incident_id( + SINGLE_TENANT_UUID, incident_2.id, [a.id for a in alerts_2] + ) + incident_3 = create_incident_from_dict( + SINGLE_TENANT_UUID, + {"user_generated_name": "test-3", "user_summary": "test-3"}, + ) + alerts_3 = setup_stress_alerts_no_elastic(50) + add_alerts_to_incident_by_incident_id( + SINGLE_TENANT_UUID, incident_3.id, [a.id for a in alerts_3] + ) + empty_incident = create_incident_from_dict( + SINGLE_TENANT_UUID, {"user_generated_name": "test-4", "user_summary": "test-4"} + ) + + incident_1_before_via_api = client.get( + f"/incidents/{incident_1.id}", headers={"x-api-key": "some-key"} + ).json() + assert incident_1_before_via_api["severity"] == IncidentSeverity.INFO.value + assert incident_1_before_via_api["alerts_count"] == 50 + assert "second-service" not in incident_1_before_via_api["services"] + + response = client.post( + "/incidents/merge", + headers={"x-api-key": "some-key"}, + json={ + "source_incident_ids": [ + str(incident_2.id), + str(incident_3.id), + str(empty_incident.id), + ], + "destination_incident_id": str(incident_1.id), + }, + ) + + assert response.status_code == 200 + result = response.json() + assert set(result["merged_incident_ids"]) == {str(incident_2.id), str(incident_3.id)} + assert result["skipped_incident_ids"] == [str(empty_incident.id)] + assert result["failed_incident_ids"] == [] + + incident_1_via_api = client.get( + f"/incidents/{incident_1.id}", headers={"x-api-key": "some-key"} + ).json() + + assert incident_1_via_api["id"] == str(incident_1.id) + assert incident_1_via_api["severity"] == IncidentSeverity.CRITICAL.value + assert incident_1_via_api["alerts_count"] == 150 + assert "second-service" in incident_1_via_api["services"] + + incident_2_via_api = client.get( + f"/incidents/{incident_2.id}", headers={"x-api-key": "some-key"} + ).json() + assert incident_2_via_api["status"] == IncidentStatus.MERGED.value + assert incident_2_via_api["merged_into_incident_id"] == str(incident_1.id) + + incident_3_via_api = client.get( + f"/incidents/{incident_3.id}", + headers={"x-api-key": "some-key"}, + ).json() + assert incident_3_via_api["status"] == IncidentStatus.MERGED.value + assert incident_3_via_api["merged_into_incident_id"] == str(incident_1.id) From fb0b81ca41b05d3e2fd79cf99f8b14a934e83cae Mon Sep 17 00:00:00 2001 From: Ezhil Shanmugham Date: Tue, 29 Oct 2024 16:57:25 +0530 Subject: [PATCH 09/11] feat: checkmk provider (#2308) Co-authored-by: Tal Co-authored-by: Shahar Glazner --- README.md | 2 + docs/images/checkmk-provider_1.png | Bin 0 -> 82701 bytes docs/images/checkmk-provider_2.png | Bin 0 -> 87523 bytes docs/images/checkmk-provider_3.png | Bin 0 -> 135069 bytes docs/images/checkmk-provider_4.png | Bin 0 -> 63604 bytes docs/mint.json | 1 + .../documentation/checkmk-provider.mdx | 89 +++++++++ docs/providers/overview.mdx | 8 + keep-ui/public/icons/checkmk-icon.png | Bin 0 -> 27166 bytes keep/providers/checkmk_provider/README.md | 29 +++ keep/providers/checkmk_provider/__init__.py | 0 .../providers/checkmk_provider/alerts_mock.py | 23 +++ .../checkmk_provider/checkmk_provider.py | 109 +++++++++++ .../checkmk_provider/webhook-keep.py | 177 ++++++++++++++++++ 14 files changed, 438 insertions(+) create mode 100644 docs/images/checkmk-provider_1.png create mode 100644 docs/images/checkmk-provider_2.png create mode 100644 docs/images/checkmk-provider_3.png create mode 100644 docs/images/checkmk-provider_4.png create mode 100644 docs/providers/documentation/checkmk-provider.mdx create mode 100644 keep-ui/public/icons/checkmk-icon.png create mode 100644 keep/providers/checkmk_provider/README.md create mode 100644 keep/providers/checkmk_provider/__init__.py create mode 100644 keep/providers/checkmk_provider/alerts_mock.py create mode 100644 keep/providers/checkmk_provider/checkmk_provider.py create mode 100644 keep/providers/checkmk_provider/webhook-keep.py diff --git a/README.md b/README.md index 39bb76779..ed359d3ef 100644 --- a/README.md +++ b/README.md @@ -211,6 +211,8 @@ Workflow triggers can either be executed manually when an alert is activated or            +            +

Ticketing tools

diff --git a/docs/images/checkmk-provider_1.png b/docs/images/checkmk-provider_1.png new file mode 100644 index 0000000000000000000000000000000000000000..240951859a3f83b3cc555cc625d5caeb2afc30a2 GIT binary patch literal 82701 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

u@Ghz2%N4=+D02an{a{5qJIyGww&c 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

vpln%pCvD+C4k{x>hQ75T*c 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

GR+<7NlKhpZ&s0unh-&yP9b!w;yU`#0x43K^ z@3c^5C#=!DJF2waJz`?@d;M2S*+mk8-rMxPQ~?~I&rngx`n3rNCioL8eO;>oI!Ega zlVpPeOEp;8YEudmp*kW)3`m+}>qX8jl0jbmg=e?LwoP;_j&aYRvm?^K^_yk*!3G_X z3=OJB6u7s$Ws1>ie`)%FTq;b=9{nrjkg4q91Zb>#UoFp-AN(!<+1N;Fxc7WNh%S7= z(R~2@jgKt&*-3*|n3v*N@U!Pd_psRaBwn5IUPOb?u5VellSLfTWB7y1%_Elp4Dc7l9G=b@!AeKLotvy9agA zcCnwbX6dG3wZzq1lYX{~tX*faI}Q3a-)z2fY|+IQ05PbvsC2nUwFG~?@3FXI%Kh+J z7EU@)R+9KF^g+wh{07?%g?E`Y`x|7P@F^ShZOylX`IlD2yBp17=4KJrq`J6;e9fL2iW!ik<6?Emx|{v_2%YmjCEAlK~OI9kOvLBDdK!1xD5onaNsihW% zkDZE27Wz~#vmmp0uzRNk(wvuwQ`5VqXHT)H!DDn8v`!00NioC9ol(r5W#cXumb2wa z4N=9bpX4smF&U@zkVT8&5^i3a2RH>WYTD%&C>=rh;46$bCCa$~-c+zs|L-5!b8r&F z7)$r>=$bVVecWs_u#V_y976>)LKKf<&yO1F%Dk$f4gqs+1%;2?Nv8$o&3)AW)SRiY`qW2Mx|D#g{t7vjRyW;rZKR;-`nBe1c%uelOw`&{@sp#EX3t^_2 zqO_fby+DdEujJ5KlJK}nLH3TZjVaM%;%!GU1oTq!p)ea~SBe$6DZT0Uz?#hmMVm|} z7zZZ1f%vRh%I3_i#dKZlyo2J;`d_XoIvjVI&l&;H|Mc=JYY_e-b!_36v-oR+BVTrk z6MUhaWzSI&WqR0in0+-GNhJ9lE5{K5VR5R$XW7)4sn4>2M}DOS;^;ZnkONSvYKXqv zanz<-;|cY6omESO&%kvNKEa$P=(~qN_QD}&zheQn=dSKQwPB8DZm8fVw3>T}o>htd zHJH8pnl}m{*Q}Sa=+YnCeQW2+aA0h-v-E~R?itzVBW>PY^_hE2v5ag%4(CH6@yiyF zeJY=u)>jzQGm_vpEUs&seHOd>^}`1qP&)TBN325$Z9Vv4^xT-qJn|;{j{S5NafT1n zkn+3THzmi0(EQE^+`{ZGfC3c3F1u?D0YROY>x~YKLMXQ5iG12HpsdJ?5z)9c;rxT` z+Ys@}I=#EcFvn-^A9n?ZiG6^w;*IUEzh|W0b=a9qU-)DS#?I)jnNY5AkU?7b+}(^8 z=Phd4H$-Elm%JPBkDt(sA8=W^rjrs|{oCF#Tb0qdd#>*-5%m7P?T`3)X*=`6{ly~m z#JQz4U8ln?yDV1vMZWT1L{VK=`$h+O#uSKIm*l@!6f)UD1lyvN-Y{bDIk0oyFba9+N#biECSe zU)x`zyno5R!#M7R)s$v&E0{jXJU_C+$LsYvOwFf2IAV!@&nd6843`alo8H<0aLsoO z&V{BHX6cMfJZ5tW+w8ax}rkfPO~jfLN+q7@4BNMh3rL+doaax}PHtV27pTmTC3 z_tI)cB9bo7wm?88=Bjm|{VqPrWyMyG8q_z9Nu#npdQaaMe0);C^if5GXrTgZ7O_zF zNf~Fb1&aNt`TBX^_q4grb8G|F08%i;J=3>Yrh-b-2cdbJU_#Aq1LZOasgt3yrT*x8 zeq;F3x2e#ZOK=9GzaIiqprNjjfGt?ZtDv{JF+{K;GkIS*v2booc-JGu0#DT0!&{FZ z2S%T=dA}m7G3NomHKrjnrIh6vk6`QK#uYqKM?&bo+gRuev|4h}tLG?E#31T|y@D zTeNv*N{B4q*;-lf*|Xy&3|I}b`$;3>__wFI<~l>`Uj$aq_c#y?VZJ}}pfgMEwCKGK zy$YrKt9xPQ=58!kFXV+!XQg=19FP&Rh{P}+rMq49U6+|_2cBUaO5?fVj7IRHmh1ey zQLYnBC|-NT;@~`Nq1S%-bMzsi_9~7TUFfw(sF;Z80gZ_z6)ur}42Z zfaGm$aAoW%e|H&mzgsSfZ1CSg~d$&w)Et^G&MtIp&no&0YRm*GP?(pl-_^c5Z;&kw&F z3g3-OC&;dOFfNSD@!I{O(>cuvnye>)Fb&+xa5_Ifm3MvT_97{`hnOOq*~ccnPq7E} zVJ72ygviD*E_$ElK4&#|#s7k>+|eV;=Fhl+ zU-zUS&n%qan(2@_pLE z?{fwdGTUf<-)GYYJD8sGq{+l2W8+9v`8#HxmQ;WSC}CkQ`iqZt?`OoBfM+fU(HnL9 zt%pdvEfdnmIV*hF-tSk9I1lELHjO0)-Pw*)RL>SpSg6Nj%Bidh{;vH+okW1a$v-NI zUZ9>fKSSlspb~#yJ~Z|KpsM=h$}3}WW*jGcm&{N)z~?>QApaS9O|?Z8I6%Ezcj*!d zH*iP72a>@yANToUKFWU3?v0GJok``c2M>Y7C`X;&0G=Xzdr!=NjzWq@5-(~tKE`F) ziU;})y*;Km`z?777#%t+BC!nox{Ho5`k1)7oFS%DGiHjJ)>|qQ$IHkisdE%pzVluo_MSdwf}0 z=Li#An4M|UqEaHJjrKM)ysTHH}z5a zeLZci>N6;j$IZNfP8vcMPL+L`rreU_5Z3cxAZs?-`wMs2$}}2mX+|tCc$eOG*gP?= zu^R-l-YL}R?UTycDf47`>XC`FrdGM>g?wlyp)k)bt7)!}J-sHNZmx`t`A))FdnYBB zQ@gX2*0!03ZZ>B^yY>s1QHx)X$}$NiE2ffa(7Vw2hC5*YZkfn~VPuIVPqNTV@2Fjj z-yNGVvm+@yc#NOTteF_4=5wNCKy^AjjnN3(gfnds=cta8`KA}CMuY&1g`2M3!M5DI!U8iqzsiW$nj?$oGK>c==&Q@B(%78QPKgGS4dubx(Wo;en zn!(deDpU1gewQm)RcuIL-qMj-R^*(%qZVy?oR!DenGXAj`ZA-AOk6qfjd)|Zx%m}8 zd>QB$61AK+#~}`qLylB&387yfg4CP6Ujl*hanWnoZQo`i;ci!hU)9v-w3b)O`l*OU zr_6nHNoIwA;}j77b*UFkGk9Y@d3S|FQLQdN9@Vb0si&=d%X;U|BE{s`B7jiLXyYX^@O`8uUu3klB){%2xFr6*J#*W5u{NWc{}rFc;>b9>0LoIuHThtf zKGD+>kS99Zr_lf~sNe;>o3aPO_24r0UH0r`ENBH`KKj7s)_lJ=3q zXNS>FdcE=8#EcN&-E|fVW;(_lnTl+MwF3JRUg(g#R&i?UP1P~+2ZUP&- zjT%I}1}UO*Libo1{$Yiax(J;Sku(x>}in zb#Y;~Ft;&w?-%6AUY+Kvoz4qId*18JmKcYq>h6!pYOA%JlAr=IO#zq_zSknBx$HV; z>vd4PbfBDqPLMb7rY-6QfJUp93(6EJaxT7}nWpC1pdrT=W6jsAu?w)xJ+}wv`(%|E zg7ihpm{x+is$Ex5i0HSYtt;p+<$yee!Xy8M4#Mz!dA0v<=Oa$)jK~RE7p>(5 zen|pQVGQ=l!9G=-ax8b=>FhZdRqDjbg=UUcwUlz zq#0BR7oK?~A(mKxEoCVg|K)4BsjKa(sO0pd42dfiR&BeAN(uMxQg=zeuS6Z-2KRX(zQNW?r!Ia)3>~kdse`(YT&ykEK0q z^eU~-lJXO$S>LiHd+8qsvyv??7iAR}WMJn$oUeJ$w%O$UN~%$V8P7N2_d05O66qEd zXO45eH~LpWSt{VeOvTVgs})xAro_we>i1?UNDuPavpCI2i!N$()>~>9s{THB3*Wq% zsAvko`b4Ee_SH$kLkvuwmi8%7M&5RJ*`dQKsH2%$9=RXFES42` z_o%KNeF5R_hKbQ4MYD{OAa}cSFiPO0i>DdRpG9S1^C!b$i@bA>Y9-ht`RZw<($HPhR zYoBnx4lyWq`i#l)pRg-deO%uwJX&L)t8%7YGi|B9wrVr{;-&d}tG_-=!p?Dc*GKk3 zm$QYNE!^m7cV|SrSS}25ykV^Sl&3ml{gV~S@}H!^ex8*<@$HIpWcg;rNUpW7fgdZI zgO8=G!Zn`A=+9cpB`H-Qi!nLf&M9M~kq!?B&mR~4{6ksqxS*pIE8BD8q|qF?n7T-5 z;@B^HQIh(%qkO&hX)P~F>Q!AI>|h{>+@{6Rqaq%mfVG}M{42%%@scKSFC93NGM%xR1GhG6@{JT7= z93H(lqiJBd&fEK#{-zY|*&@F>n;#LIhI98DTFORmO$tQ)uB7(_IpT%c%7t_jm+%G% zR~06rU&x|#RNW)4i4A&lco)}9i=dwLlzq-J%-8jAI*yAK#d7zKor%4awEjNzrt-KI zKi4=A?a!M}5mCi;v7jTlaW1|=lY5lkTB6ERUN7_-htkuU+)%evZMx!n)P{C^mk80_ zakHgUOCg!xnY=Kl?||6~|7y12q_`I+xH&tp>tt{mjxc$ zic3R(Wr14&MIPL1@H6&bO{-(Bt&pAjn%;|5zc6C?iFucl)FhHYm~b~jbhK>TDRjbjq7Z#ZEsnQ9hW!-toy&_!A4ajW^PZr_7h^@#ZIvx`&qq8Sr{C0J zL#QU@T&_{h9{zc;WP%ugij2LT#Jn}4r*OZ9IcGk$ug#3swOqhVrLUpVZ~OujzDKNL zAKKRyFVKUfUCJdfz}cC3LDvDI<6MutK18opOhVFJGOMk>OsYAgY&B z^F>UY;6`dyY`LgtXu(@T3R(TRJ7fqPG$x!{LA3-)Q<(XCQnxDy6I;UcJGx?8Y>TD} zZr8IBT?y3YUTIXcLc*sz=xFL_;+E`1!zRao*rMLsNP@W&oYaUWjr5kgGgb)Vo@g6t98mTn4Nv3?iwoCZNp(I8BA6sEqP;8DyGl=8|f{s zDX(m0{Lg(YWN-ic!ZE+?qTgkvzQ!TkH#>D9O)*g!oq*8N>f_}f6Gl;Z zYoCHVZFB?wfZG*;@uF|m54$TYBrvv{N(7NwW)HQ-&E|=^50DD!O;Zi?&ZGv9i4w)j z4pybRlk|;i2c6l-mc+)s(9IlU%r6nYntISrOaB|99H4b<`iMbIS~JsY^R{H3 zZE4Yiq)=P6X!W#Fb$7m(f>xhCGm4uYZf)`as8JD@pYLuL?F{X-%EML$^$H%>8(lSj zmq55t{7B{=*q;ox9#?hhRsAE$&;n^02LIrV4UVpub-UoFQvjl4<&mq+egtp+gd-y@ z4%Ts93p;eA#|8Vdii%PJR7>Jp4Z763Viu>@y8yB#+cBOu7U1{erZ2?1v7F{$?mJ7H zE?Ux!5r73X?0ZbQJ^0DMT6OI~chuAo?hOS_36PqWJClLiaxUyH@qs#$Un;@PSSj6a zroNT26UB|qPG{$uZSPvd$hK~l5Y7ym0nz~gVV(#G=KRwG5LL;It1>>wjyT~B|F8J2 zCt=wC5oPcH1hM+xBY$bLoZ$qOf}$crgp5PZ!A!gC1Q5^~8KtC46lnYd1lBXq>*ao~ zQ#Dtcaf|~tG2vOTJ~O{9y7TMaRA)$wThIt}k65RfSGD(Ht96$Xf~_s{_%t_A(PZB^ zdxB`55j#=Sm~fd=Y&-!shja~2#sl5f*Bch7W!@hEO*#T)*M$XZ0e`gJW{7Ny74Y%- zd79XnHjNkq^C=MUu}xF_#lsO9?=pWF^RQn!#Z$Bg71wG-PM7PRfu`{J)a?g-S`!kQ zEcZHIM*b){9GhcFuKS$MKpa=5Z^u>K#KVU@*0Z;7SRof5A79JAyC2(9s(2uD3 z>U(y?17k&7DX=Phe%%7cAC}``?0J>9C*o88KhE<13mdw7eX&}lw}@@W?74&sm1)yiBCaL*Sx!1C` z?ZgL-+14`e+~q>Fswt!kw@0cMEXM0teedJz_2C#jF4+o2No#6Q4n{p3XYv%X9=0VSy4(auVU50lalxg4Rpx;k;fHN@X<~mJ$z{~WYz5Sy!0p~8Ay-2XPb5EoJPWi?5 z;nIyD-luf8?hk>CR?jNB6~|_kAEw~0rb=Q}jq*=Ml!{71_30T7t*3N^po^2|2RT#^ z7s#+*GRFfz6@bwDCKn1y7cLk2g!XzNFep=0NV#$#ml@wRmO+~xS6=R~)}C`g)yU_Umo2g*L2 zCrwlz^#?mlbC*hl8cG(ua304K0N5lzD2csV^!=#zvHYG~pG1Q^BqnmAX-U?|Gk8@D-N(T<)z#8Y#wz>w@N` zWqQ3@`0OM>ua^lV@+ob75xJ|Z-D<8q+_g5TY}Mrm7Zq|+kCvyny`j5aLJAb$9cR-p z(W{(780{@C`5NC7c*gqY`s*rJgXY_^R_m{7%k=^m;)@ry40<6LwOp7MpY75hpkY!b zjDLB{5b?4xJ!kff_>24~4TB61#Yi!{ac-gxy=i1>XZF{c3ITGFNJ3Swmffsbq;bg8 zhfeO3cPl7A|}b^%tnm672VhLUV2JKC0FEbS2F>|4P~}reA8>pjW(v3(_a2Rr>r}hPSEcq(`~r}6Z{juf~#eZ zH-C>GO-9n+b{iAAO)i7R*>A%*mW@m`tJg4xjZKs#C@>TqzWb8elx}ew7V_v`Hpk=5 zv7-Z~{kcR2!cDfM>D}}doTylHy5O{zu|KKbVZ|_JWJJ|^1ZtGs0V`^GBiNsLRIS9A zWsFt(V!F|~7E{LBbXPh`%SDOhFija4iPl){hI!eeyI@$nQbfk$?=>iAdIq?(LxXbI$_t5l$h9) z*Gfr^H+RXunLraiMi}UgM745|r@Mp%qDcgEThhnJ6e_oQO%B(sjiXAU+$2wVn075`!PM(|^*7_-9f7mjHzR z>(d+<^Tz`izXXD_uPuSNxejyEEGnI!F4XV!bUcwT0|=>qWXFJ?F$%ar;EF_pqpc>Q z2^q5@S8>EiD_d(!SrO8lx;H+-f6^gUM*ge7*kxi%=EdM5OnRlqhpX@VZW&QxTo>H7 z$NM-!u{O(YhUH5 z_%uXm>~c2lfr^Pz1E(@tEg3l0GVgyhWgLtD^Q4ud z{zqr0F&fn8o_DY^M_d3&=H&u#H&pq-$y0%9u=Y>I=0DjegE$IQh=47C<;(x*?L5Pp z=-Pdc6;Xlb5tN6HbVNV_MF>qr=^$NdM0yF4NDB}Gq9RIfp@SfVCZTtTib|ChsiBAj z2ql0(fCNa+pnJdXK4+inT<62N&V1kl$xPPFS~GL6|GMwrKO;$eNg2qp8^9Um{l@VE zsds-GyQz`;8+!Ravu=KW_WvpN|I?0;KRJN^=P`noU!cCQ%t?&RpMVN+ToJNM?obhj-2oUy=m1;D)#$6B^A=O^*Nj*ELQNQj}IGH*`R{nbto$~ac zG!pO&h%bmzzAD?EAsC*kXCpg z%t;6CWR*G~zS+K*1LO>n&K{wWL$ih4a^Kx8o#s*g2YUh9dRTXKbYLR}@^Xp89s0TJ zBq!5ru{E}Tu9Ge1?gU|aC-T0~&DsvL)+baukY$1D z&V6lqF+7ToBmR8Hr8;^cjsOsjN)#2%PXR6Z?c{c0xEm5T}O}ZG*lA%7FM@>DZ0_z)U-3A|5p3K z%aM`7i0IJ0$T(ycqK7#u$dlsaTqI3?s~csi-=wN?bx1!a<>~xAN_|{{nA;M` zP716wZeLzhGuj^RmbAtShB}bz3I6;2DKZ*scXJoT19CMORoW=g7<`-K_I5^g;HRBq z>Mx}^WdozOdahhH1}Uj{ZKndXd0d= zb#9&9w#Os2Sa>ttm{qdwRVKGt_lI6Fk$(Ds#O2DzJ(oG3+V9oquC?0rO+j^Qm0PU8 z+AOm^GVNjk-nzC`M0z47WKE$;m!+68;V#fN|NQ;Bx?Av_SlqCMbRr(3XwCJlZprCJ zcVkX$KrzVWb(BR9LN>1?5}Kvs}X5g)_=(| zRD{^j(7VAk6GAm~E8=w36!&(cw_1E}$`<7q+iu;QLq~ef0P$k&bh(pEDMBtD^@B(` z%O~EYp!JjbgHcU@?Q4$LKEns*0G`AJTae=}tzB@wHaql_glt}wM$DSU+;;#ZqVw+4 zX=WCHE+Ws*0pNE8pe?>1&iCY?(%x&% z6K|tO%Pg?%Fae)do-bnQ-vZMT1erDG1H99c#$Rdr!qeFK)voMk*{N0At@)iA>FGsl z=;#?1Zzr0^Cm7?z3Pc70m~n2L0k5FhH<@l3J>SF#LaAYq*#4kP0ADI=fvzQRLGst% z;$46NlVIpLQPY3~=i}m?-e%sgavbfcBYfTEi(kxO)FBlcU@DPd#}DdiM2q5;RGUkwm3y$X3Th>fbFTJS22k|k^yU)obs4E3Zh5p@zwX5EK00&#+jt{j(b$rire7~ygZTTUq2rVdoj`u>okP}I3s@5LT5W?T}Pg{ z6t*;{;q&6jBfG3`*u*%mI-U3)*m&sIN+oZhY}_D5Te=`oF{?KPH8zHG2Zz6QXZ-G; zN)^yi5_cFa1xHHV%Ug6facfvaa9yFNGNeyw#WyNl3;@&n%x|dkvK&6~1o1|1I%`P0 z5wL}b+8zq!{Q?rebf?@fsHc+mjN9dgRnxh^^|pT>p+TnSOp?czs!xabDMHZq=iTi z-$>`g*U=FQ>fW!<6KAe;#O#G%YqE+}_+YY{vRYw~xnY1*k7=7()-$oaT=1oXaM*BD z`?aKFMb<7+hpezGL{{Z zx-IL{u>9r;F4l3x_3+CjG&Q2!m`&fJpb|F@4jxWoFm$NtlPNzLAuVB#4tnUAf`Pa&oQMZ_a%` z@PvwH{n?}jFpynRZyJG;w*UEbLm%FL+LEOOoKl>Z@ZlqyR9(-Ih@K~U)*MwV6(5rA zt{{!>j#;c1Ym@KzD5P0nhI*)Nd~adzHoe84WMGI{%rC_!CB0&bsww(Lw6MEekkA?f z0OQZtJ`{1En+9l# ztD=7bc0#|8+-JngM3iVU%Oxa3@SYqDw?wpF_mpNWUmF%G$iq68pq|UyEo0Ua0R6|< z=JE;sV80{&M~U+q^P?82b$*$Ys_wJ#J^)liVt5eyN$O)BccA`;#AE!Lc7Yd%Na5=! zwg<&}3OpWM(d3jA#W6uKs#!^mYy72JW6>wFxmPQW&RAfo?S3~Xo>UH%d#)tj8wrJd(hg0VZ3{5GiNYjbGB?x7 z#-AhBIJ0L%kS>6S4A^drY2$7GYBCy;Z1ZUZs1CuD2I~AKbp_g4GOU(}&Vid}2U0mf zHFJNW;Z74N5A;cY%uwEP3cy$(^i%IJqp zW4Y8Y_n6yf7#u%nW?l1PhTFNt>)|jqJKeukk15V4^1|VbbgL!*Tln0 z;`TK8!c^*ee*mFfTi7S-n+xzmo|g%Q?)(e+K|9N+o`cp63WmHoke>Of9dzYTVk#1& zp|Cd*zBDA1xFMC&urF!SBf|Gd9mnn7Ra zEX)C&KT_@D*uyRe7$T$|>=0Kuouf19BF8}#wjhONon>$89FF$Q&v?@Y;F|KpUT zh8ZS+A2?;J+vAPD2#}rcOrAN$FtAH#di#?GOhJyK-2VeJ#0-eT{6}a8YpoMI|IqdM zXgGID4C&8IjL7sakf86KT*8&c-QvahVKqhU;(A**%V>eY@WDYpM; zeB~&7*1=(Yq9>o&ZYWq6;(tM4v!0Fi)9CrDcy0h9Op1!E!$jQL!of(sNXZ-!ZpZq? zWC~xJwC&YYB&J~?hImGC^G4{}`?(V$7GME>ue}$UwD_mr)+bli#Z~~FI@sR@B42SD5y!GXbPZ)5B~)f2~15aYK}NA zv($;hF!)#!FKn?tyXG$Y;X-h)J$yo$-5{y|8_42ix3`28NoKu`$_D?zq!KR|Y+6h? z*Z<@T?J!$N$nm>?$`6(Cz+JBKNB5O_l*t=guzo6v6sNpMUbR;wI|ykQhIm4^gAe8= zv{B-ehwodqR*{_;yQ=o2RY;|q`^XJP-tC=CFU`QA`7%zVq>1J&I3{;x%40lu{GWuK zwu4Mbs9ERrWQ=Ys$&7-CjWWlXuXgLr;jwLVpZ>0&dAxNj^jVj$t^dV$8eJaiuQKT( zhK_T1m#zpu+Tcm;8f3bYZcH$NW3vwqj$7|U0NC$N@Fd{6vUt)A=#PP?di;giYcV{V zt%@=##?a{r7e0aEcJx?11=A*W*MQYjSAzHQ-Qg33w2b%b%&(>1K3?$soZ=ptYVpOo z>HCMRs>Rgw(T*#G8z9KiEAJ)uJ1*aDf#hW-J?A)504YRVE0?gg zvX zZGL>cC$j6GN5WP&j^PXRlS*Lm{{G_%D~6sZl@4mpz~J=Gjp@YE)f4oW?}O&Ya^L=a z``qERk_B>#ZFZK$m%q@Xzp`7Lj?2sF;{N8<8(T{PNgGqvn~{HCYB~ytx6R8A!yjMq&6$g*;s6%wgqH zg%Y2qUF(yg^NJ$^%_?)PKI*?7&hc?S_)hsI1(7$pk2Y0((lH)X2LOK7=i?oFMw z#8NdrBPGH#1?CkPP#Aq79@^t%ktVkhPu{X6@_P>ywO)>2;4S=? zxH}zLbb3xXH75PhiPH;mEf7iOJnsH&l<0;kyaKvQJhI#`KMj$^<)nLR=|eOKiXVv#3Lf(grg9Rk ze!ofv-rhV|g^vS|l9E7%?_h8Et{Hvw5n;?uQMuO~bjEG#b5C#Sq`Z)Xze}55 zLIkrKj@i9wnAd;}UONCuA}q*vm+<{)ubVH>bgZUrS6N~`^zPObz&~CYn<>R1`BhIGYq=xFM>SWkKSGiEK)1X)gFvpar-_eGQIww;4&hW; zZES=$qf4`>B{Sf0u$8qw5bG092J`&`uy=))7Q>hTcY})xcb=+F34*brBJbx>X|$j1 ztX-^Ykfh<*q|^}L=~8(leGUZu1;F~*j*IZ`Yn4t0_?AW~9-iA=n3WlO8xwyK8)u85 z-SKLzf0%v9b^{IkhSt$_A*vi%5%h&6%+`v{b6eDRx=7O+Ru#AJDUMiqbnGQxQs^uS zQ$x)h>_|{(ts+&Jx1BM-Xnt{|+J#Ps0}cvnT;i73>hHC|<|7Cs2UOQb2bZz8ze;q$ z@g_R_3H(!Zjz-AEVQ;_)25>e4v?o5mIKii0y=zg;`%c?+jE;^+oA^2p89Aj={MLz^ zFh+|Y>`P|Mqp<5P5yu%qcm6~Nw{wN>_%kJCsKNY339j9bxkb+w$j<_MK0P;(uz~c744;PjTI(YH`2`_R|rc zGG%x8ItJ(u)~>=uzT|bxstn%Gh?kKeRQTWh&l#3bWgHK+LD-bHtX>^|N_+!raEju^ z)n3u@>pJSneST^_Qz{Q)1_-?w-u`>X!LWo<)lotEEoei_46<$&NmmBd1Ql~`WS+m( zcAwVYjeyNyT(LkK#s58UiqyMaEM~?*ZA^rPI)aUM__Ez1{GdWtM!GUUNa-2u?mOjQ z$4Mv#hQIy{m?N!mCiHbT-5zkKs=L{3Wy8a()o_3@=%iCeeEV3lR~lVt*QgU{ncyzUH{M(RPoC4H})%YPMru1N&#fa$X7hq-zWi6JRBpC4gQ3AJHL<_`W|ewX-e!EjBMU_BvD1Wd7}^EN?TJa za1U?_WkNYc)dPh=hV9-NO#`VA6B#|+|>^blu2Op`AY{~&xQ4) zYtFBShq3btH$FkyiKt9_-V$~YZ3?Tr2OA+yZFZnNp`muz7mM=UR?mdhZ?m^)bZxjR zHXcHj6xI*Qz$@$Z+AA0^%VE|*JGb8vOvd^V8TR`NOpwClqJiycX01C@4{O!v&3-8RSapql_C(H(4I9 ze*dUk4`36%uBqXJ*{@Nn3%NK$KmEzb+E$@5(+l#mZtCb2$I3*=XOG|9MIOppO6KTW z;LhA!aC;`_Jc*j0)Io;k7vEM1Yvv0us2f-BPUhzqGYey!ztY<0$60;9lx9U%v)BR> zazV2jj0vB;aFw+?5u-FL^L50z zWU3)kAa>C|8L4bzpyXU~-HGU@nGljJdZl$8*;Dg`&25xTq03^FcH0=WuwQ$*by{#v zji#dLu??_{O*K?2kJUI?9FEmACYX^J)q!+1ps#ZK$H$*&9nK(n)=eWNOeLZo36-U} zUsDp0d(fBVq+33AT78c1yT0|6d^O2xpMCbFI(biq`8)O7p5TbuC zTvB;VRGjOrnHQ>M?^}SyAKXptDX%hv>)nX%f33V)XY_c6Iy&aASO;N;I^!5dzi>YL*MB|6;cNVH;)~Kx7CeB4NKDNU z-sqjEj2x>ozMvpqHZnhBcgu0}#>We}r2p`ddUg$5zGUIZ1!Y!JUF;BCC(0pi0!}`& z!$Z_{L;Pjl{D0d_b^B4kS#kHk&E{M&2Gw^1QzojSs}3S|JHzSqIlRCFv*tGt)8>D9 zP5$vJP)b_}vE#>MoQuwLR_^WSVOn2l3LMe*(Dw-%oa+lm0ut zvUDRX0l`?{Iw=8rJTGU7{b?AbkaLV>{~}`h!~*osvS*Xd#}gv&kpZ>_w2)?iOEHcO zD-diiy^9pv_<$q(Q^?!SolZU{M5$#~Mqqa5wFO3L}%sedW(m1l? zzKoh{FU84pgEZ0jw<_%eRm`x}shl3EUHPsiG3xl+qqn7-qF3{$FH`)v`_1rSsFPn7 z$?ad}AFU%ten_9V;GWC1Ro_{bC4={^k3b-RF$Br&je&O0m(3qIIgL9bHyTtp$yLtF zft+MwaPibYA7oW@VXDsjQuItVA}SqmO}oSsV}V-$Ia0rF?R$o3HrR~%a){`hRcHK1 zm9iT#uZEd%+L}R3-A2S+Ot?TCa9mBNTA{u z#^PH|d+$0yU7npSmZ}OanV6xXci^PnneK4i)srd%Lydmch2^NMk{N;%4ikPH00kM6 zV+6FzfNBe$W`ZOvK+V2V8+w>4E)qCs1pu-*J*Lbv{Eeps4xNnz~zRD_*at5+Z|xoH_#WMUvb zO|kXhD^yyz4U3ti5TQpfftk}_hOcUU`?=-(3ku3jHxCsGXSV98@2TfXFX2^Pr~^({ z8#V17Y>nr3s05bwK8=v#5wjkJ#EZ%qfn_!C7ia*GgG7nwT)tfXQV!0bLIXpWoRhov zn!xBR{Y8%KHo%SQ1V>M}DA81`8rKdZC0ft-Z3mDQl%8C?`CcKmEZsF?z6YysVAo{E zSJQ)|bP~jHSo5{a6+M@L5y|RSb62a+1v$L+-CO?I%4Kj|FDSORYNUJB3Un3hY<+yC zc<5usTH1VvXK4`6+kPz|CvQ!VQxcoNVMv$hTW`j6$6*?8$7wq5Htu#`$3-KU?`?it z-$lvLvHdz*YxFBX6m8$(qtYrJn6=%s>u0xE9ULu7$k?tQJ}1>S8UW00ULsWF4XPyG;`D*DcU!xoM_!*EjR4 zO@Z*ilY^If!sSe=w9y4Rz*3S2azzR%VGZc{w9}#j&pV zLLSvjwdm}^-<4Z%?e9+?+MDW^$8(UHZVZ2myH^{V0kQf`H*u-6WenZ^^&`q;C5;8B zSGi|HRs34G1H$LmnJr7}EW#6=AICD9ba$MV^a*uv&XN+THs&(Ea+jlX?3bYbxbGnR zXTnR+ciBwDPtVxLDeGRPTw;liMgkwgr==`&3B&gljX}yLN`&m7`C*?YpRHkpcG+#X z^)g{}nuvC3z{tOr-IjwjNfjqZ*yb&`ML01dL(=39F=~(qU&DS{<-_tl=g7&;c5vqa z+f35;P&6sE4~=?1dK>fRXeZ_UdsenaIn^S?80`@jW^=~VuEniOeQ^D;L zhX96>`^OOcbCj!^e}*~0b#zP7_s9%xsQy^Z&`Me&vs*UZx6mzRVjc;=30hDKa8Bbr zh3Rqa{0CcRiGZJPNqT)JSB9N}=YvQ~fhFJTOLj7`X^y*4ye(%=g35-Hk&<`qDDfuCj&C~SDrV7Y((^M`!oz;RB6R+$Y&%j! zQ*DRSWzYW}%R60+vJC8NW14`zZ~iK-U2Xpr??9`{hE}9a06C~?heIs|$9PzM{wn1S zFYebL2X(R%(HD3Ls1HbO=7q47W)NipXYNyv!J-}cIuQkDlPZBFzpvj=63MiPrNYzw zCuWb>pv>=58S6i^qa`lequ%1Ji%ZBgtK%&*Tk2;cSge*V9Is1KcfViQ{l>t<`-%4)&O!9d$ z6hNu-t~9$gfi+zIV*MdsH-JmSH>8?yy57gw(dzR%@H-;Jwz1!&CBO80^YG#%fApsv zk;vmB1(K*!T(*e2G0&A3`4Nk`Nr(>y{-h@oPn&u-g!-FAbhe?9El*?R%7clFnJko= z^QyH*(-!UI&C}3IT*xk5@iCgXDg~g)p?6di-MVf{LMMdn??pH4$E;0qno4bH(RKRPoRQg}cuCe5w!zrzSM% z%ng3JZ2VhXtAX?Wah~5eNwCDZtPxo_uypqdbNzv4Kv&cqQsRf;l-_FvF-puQ84xm6!9Xo`jTyaHCwElH@BW86N64L*>zSgF9} z)H&}rfhiyqy&JlXn*Ood&(Twc^i0ODQ`4fZQp7lwA64_>`~vv`?E?SP4EanwQ2K*Y z?PRx&R=1ET0)s2Q+MxP|nH!qSt~tLd>uHI!QyMMaoHh4|`{w@{3GXn)8qrVlsp^xn z@7KG3I8T0J)j(d4_F>|O`if^c*IpqZ+?;U}7BH9LXxQk2Y15VNykGcv>0PLvH9t_B z#O|Jx+EUETI=qzzFat&2UpM*7K&Y0A>v9efd*f+kzXi3ia`VR72&^ezI;JCX2v`XGF9B6)fpb5Ue@H52Ua+X@pZQ zFq>VSc)op?HEyM84JgZbpgD6U>w2A8o45X(OgRefNd6fLlx;h&?>%V5d1K=;+Dl0y-D<%wd}AzT(8#1=TZ})VC2wqF3{29h;oiAJ2mi)6W+3DOpde z0wu%C{yO6hu#K!6o8dV;DPXnneik4%@&#bf^`CkkpSU-IqARsoTe|E>kL)3|I`Cg_ zKb=g|cBiTctF>V4LJs6q$>$i;K{(K-B@1Ku>y((_~#aPn0 t)2w_~8CiIaa@%~`^6~`n!}!Ppx@C){6SwQ)HaNOAT1$Ccc=&=-6AL<-3^L>{{O5+%ss<7=RSL%y|3#!`zAtDU6F*4jt~nAi$qyTK^qGTR|^XZ zd-e|A&6Qd&r|6p>x7@WApJSDeFl^tvz_pcAlf%NQiY2;wef#D$fs2xnI~Epc=kKpu zy?~;(SXkEu$_jG2KIVH%WElo}nX(wjp~h=GYdngm4p-ceFDxunk%HdxI9q84*kON!}X0){_B_4cnQE0$piP1 zwru|c7!=i%eTgI3xx2l_j#!2*x?hjLS`Wlwo2FBB{){75H0HD9w(8mSRto>LmHAm< zMEKvvgBQy4?{$JF;m`m1JrV2we))$uQSLf%J2s8ug^YyM+2}h|fdgEZ?QhH7-2M(; z6$2^C%mYtOB*Itqyc_Ab!Pi1NUaiic490+N0rJ0%({(0Q6RKuUp@Ngc$L({+)aT7fG&C0^^bg zNU=RLo{>@22+5`nt{hgk3-}*>s8J|H>>xP$wy!z*-I~FPT<=ypSqT4~%6O4nA_qDv z+|oU>9zr6&U_>s}-pp`eRVt2(d5S@Y; zNa!wf(JLjH6fG`$^`LyW0MFk0&G_(g zkDFjqzuF}<))i$r*N22j)6Y4<435@Ed*!Gr=8o7^kuccMI`yXGfz{vDjfC`I7A#Yd z(s4Px5p$o}9OAdqxa^@3ChauzEd8}vo7^;kBzs?HGeZ^R>zw^VG4^4h2!| zVlO8LeAv+781*;Ada=HmXK^X888{My_rg(QDoA;>H2+#hYMX&98CMef78UC*%GWPw z$35y8Px2O3!8umY8m?ybV(;I*;^Ca}byLdR3GDHBK5*^Ci}yw0AjnfZq*Fw5Vz-m) zoj`$qFop&nu_|iA^Q$z)l4ukk_&R+jU{moTleDMkr)T!Jls9;k3C1K`nVw?rK;H~x zhpIxyox55!#I$Y~le|7TArk%ip7$8j^li(^3b)ug^J-%?FFS(tIKQ5IE=XC!!U+Rn zK6ARxU{0H7EBvIS6olCi(mpR-eIbfS1^TZqc)K;jc6}!} ziZ(o%=$)X^$mz5na54v%Z zYI~epe7f{Y;g(-x-K+MoAyoFrE>lX{=V3C|aV$eyze9P_JWI-i=wtMd2TfeLT)i8wG{JUsdaxM7v4O z-kkO8uwev+KD16ptb^E7Rp5TNX> z0Kofl6CFh$P3N@F`Du|t4n~_xtwuagERYVDml`z(s0~N^{@#BA)=rsnD34PG{Y*}w zxcZXsz2jxV};n}E37UE1W|uijZ}pAr2|Ipe2NaL^j8$a(z;1{dpTt?+?%tvP~P zuH;&OwW}%GO<5&w$Z-7$L%Hsstk+M1@Ssc06`YJNi(N2d2FA%Gy&h#(1Vch(V$q0)Rzje|B}aIxlhvq5~Kn zr@OpwT^IW|0dAT0Hx)S`BqSGECV&z9cSM3G`5ilp!?JF|UJD?=9Pur_>n6g6HFv7> zQ?S6h^wD0S39-0;@)DDOH}3Xxe03`8JKJucw$e-rqsVFSRoHz>jSRleAM;* z`9Qmj%!wx;jICK7z6Qhp$V@l6%~eP!g-uvbJ?MIy%jxI;%xw8`RAIO}^EZ(@mrLe( z2$zIUd}Zv{PnLK8olyKce>qSqu%=TDv{@l`QVP)oVWM}R=_CBBR}I8Gm$iSD)l3FE zws^s{3?SjI`D8#si~F+J^0JF0+!p>gz^a7cpo>#jMK`w$lGQ`@44HeuIl9ak0Q zqmho$YdktAf2k!u>3FAqbnEqfsdqUT;;kTx7IRs9+bj~BWzyDnH0S!W$}kmn#_Kpp z@-G0N!$lColYOp$O{*mw-+pyR^8ncD+~oa*7k`!|v8?7i(u$GgGMmPAHR)hmMm^+h z+K@v@yT(X4rC0eU%ckKytC z5Icy4b+Q=!`6`V@@@mtt*J*~s#nJLrzypl;lKH>(9qur)8=-tDdUUx7J9E)N_)~z! z(@&JtK77k`IV~g7`*tbZz{1<{siWxU(f(~80IKGqoB8xDIuU&E!scS#q@s{;L&gq_)X8O}LKgRJj8R1KSB1~l#x1}MUc@lUyaq;nTH2`Jz*%{Lsp_cjOKJ2;~Y ziNV+DpqTSc26Ov%D0Q>N0X`r?D$OrqC|Ye4LSRwC2Is)wGWKBFYvOQMko)2^0cxUjGI_hTpy4gRJ$ z>h#cGdQ2WD>SF$a$%6AKe}~n9c#zgVHu9j(s7vFKqYx4o@Q=e}lwzsqNa&*sYWW+f za834{Miv?8U_?;5W?0=!V zUs3wA4y5_`qrTo)Vh9MsP_kODbx4r?tq_gZGpXb-pCI5BlI&E{Wy9%+F!{}A-@V4QzOZASL$)j9)KCcEXcs07@{XU*}RKh`< zRhVwO{dL-WQXf_fuEBfnhfZn{!}uO!->hh8<9@}EYy~t@YU%~&F{=5+^CKi*=M#K| zau0KA^){&Z*EyO5j`KL^VyPg{}SD$4zj&Dt%t{uj?f}37>dt-Vx`mwi5Vk6uTC9;FB{a zC+o5Q4!_JBN<e@LppqhXPU#ez2$uzOfGOkI7i&rCBNxZ zo`;{}ym9b(YYrk%^?>_+CH4CtydjY9n;<%@%U#w&rnk){MdST}G_5r+My@w&Mfe5r zcDDSz;}*SUJMqBqw-mrDy=G=*VNZc!kG=1B;pJw(*%#VHzuL0Kr6L zyk~QuLs5ty|JQf#ESO)bX7i~3V68EzJb0YbJ4RqbFGL_=8vJ>=>=0L8^)RpZo-`H! zPR?kme1`MJ{)f+`3U_eC`BKHR*uI=Fv*bzJ@G|%c9&WyfLhtjs3bkkkM%@QIhp@rk z^9b$ic`@1;@Ms_ONLVZW7_Q@gC4ULq4m@zE|JpQXpi(kQU(A|lk7O6t;QP5zuRqu) zBRwWlOQ3HmQ`Ys5DW*Jj7!~aNm!8}Z;-4|XrVIRL4q-cr(DTWC`b{U<;ZKu51%f)t%1ZbhEfq??!#EjC2pU2 z+>>rOCMUYBb=w^Xk25%2Jn!6kn+^^5F6rXqZy46Vq@ALF-6gy+ch%|<<@d2)V?HSG zwjy-*%Z`Hnz0-mn1&^{Myl`nup+)TZQdmlWSE(*6WOA>FbxP)p;W|byOs7uHqbun0v@+h$3yx%eKe2}TFcX!lg+(Q28-<{MxzO7-0FfwDXkwq z&++{QXEpiI3bCY|-qdBrXG^4dAkgj!#+R)548>vEM2NpRZFiGi!Ue_79gH_vNrsqgqnfOgdP(ks`tc9e|}cZ01kR zfI*066PEk*9BCZq*%uHN^@>RyTBkIc?74k( zAX|0<+rZUSFKrdk*J1zn{-fj)1p$TjZc~iq=eI@kHK-sadS1^sk>ig%vLB2nhOjgj z_IY+{HVB?E61e%`Fg~@weggHpLlAz)2>iuTor)kQ+>-7e1gSt0ClF5Y-8ViFS0W>J z>V6znIPTk4Ia+>OY3)IUkOyb1b;cgZr970~KfIr%fHkJl=%47v!6c5Ly*~o{a-LyB=D9vS4oF%n^-@D`?#Wl zKm+%{+k=_Q-c;#}d>UHp#KX2W*haK^XuE)ahX2kR$+)jv&nf!i&i+|ma^X)IpPRij zPVMQ6X>&ta^b1|dMbs43$S51Kie9s>u}%8%wN|o^WXL%E%csJBa+2oO>i-WsOq+i4 zZ+GPXN5YEuUzM%+kIl`3UjN|p@DWjQ_k+u{1Gp5KG^UnOLUw(_>}}Z1yF~>hnW7z} zw6^WXiHyH(WiRzT;{Qu5`@d^wkIhG&e}Jz8NzZxh63&gT(ISS(Xoi-zXo3IKx5sI? zn(Zirc;hzZN-#w#P!G(&sA_lTKi#XS+YOtCf}>v{$w`Ujqa4*g&SM|9ip>-DFxcRH zX09sn6R!4sg?|j2OZ}i6Z(tUX)zN^Fln!U(_@bRH^Z$BVhmxr{nxeoKqJLMxZlV4$ zUt4V$YI~-xG*kW`Z}Qj|YGD~DH4$B#Hqg#C1EU@j68XY# zmRc76b*bDT8AJpF@c}@Qu3wxWml)ai%=CJWVBdB~I1kS7uiJl0P`6D+>#Ti}9`U#k+b#l>?mGP%$)?6)#!xN zefn*!+!LKq=fXMlCtuhqL@>ip2?hzm0Qjd1mRBNa-^E8|m(F4@F8avZH7b5SmuxtT zr{f{M(et_!P#g|>zrmiCymIBb$+cPX%v;5fN7|@-0UVy(xwg#TbN}6Vii@79qs8lqU!jgfC{IME(cKVBYP`WQYWlutG7APsj>(DeiFY& zv5J4zPnK0W30NmU^|gL_^P4t4Z9WVka(QvIasTNB`+elN+|~k&aDCIO+C5_8?BQN9 z4mZVv%1(WnHCG&5t8xlR0w!Ym~Q80aGKZ*7d-_7yTPknKE+*&Is z6FA&Eifm_<$PQc|AS)fk+5@%`Uti8Xzgn)S&nao91Ax(__0InHmNP|}C4tv;cma*f zJr3jg$j8b$h0$#uc083#ben{M-&+8n z6cPtD30!Lp3-!Gt4urnGG;`m2v?Kx8d>6g2J;PQfuyL&a0ZIgle08t>V6hBD!YG8b zB&+#;*u?u6+&gyLPE8G)y-j8o2Mk3@wjv-1_*4&PM{HatKE&UIGyG`|5YSo;N7y=n z?`DqXlTq3IWaoH)tUl!F4Pz7>+gSa4*cQgzU91Dzn;L>%kJ86U+D0=CAUUaBKAclrXD;pUP2Ajjd=imQ{ifa0l8^1aTCExZn;%a8B3&#^SVd=MN z4V&SjkBxeEcV35{o;K34LDP8D;dg0cRVL$XC3C)y)~lGyJk6=#n^I#*$X#EtQW1v3-GO};)H$4k35EX>)W+q4ow@ZFXk&-G;X(-8+J2~!tV^$f9yZ=v{& zx3G$>k510g4|{Po{7kWL)6_bI(Eu+U9G9!;lg}^S^Bb}Vi<@K409895lMhF#=uCrr zzh!aH*E)S>1TTl4T_fntI=cuY`l{n+Hj>XgLWz!(qGg$7av|)#bUqtlr>Cm(4S?7k z@0e|&QmC&1y%nLa9=7RX@{NsH1Tt}i;U9VZ~$4kk;H7lJx1i+JV}3Exs-gz+}~~k!wXJukc%Qp902Yr z3Z7JHSay}~Ab>55@#Dv0u*L6eFszqw9>G?plA$q{4q)<cqCpw0~N6!QbEp=rrM+?7j$@!XTH7QIOh7Pq0p$MNEwa1vJYwnu6|%@&ymOX*cvk@3p?UVkDe?!T*tMKFFL5VDQ#bnSLmrqqhqAn zUO*8_a;E8={L)~(mK5HS&Bb^m3dXUHETfPT(PJ3k>AJ!51Py2w9t$IyQDpW@F>IVt7`aHg7m07!e zpP1sK=w3P=^PN>Sp|r-1j5FpNs%U6^6E@Vef~#_Kr_e&_Ki+XKln16c+;XthF5Q}8 z!=EW(_73z60(HSAJD#icP0zxtke$t3tDMlJnjgU$PJQkZ@F+FIBB#Xc`s#ZKi0<|` zs?x*`>M^qodM9Fqpw!3y^%1|#O*n*Q{N$7JOfKL9NVVNp&gZr%=GwX)oWoELe zRm#MUPUNg|Q3IXYlW)aE;J1;n`$W1)dEY6vL@Kddum#RErN#)hsJ@v%wHOEqdX(;IHNA9csA4WRJ-;ZIt}P@eH<|%7kuFRsA&UFz~I> zc8WgI<|y73)M-3tvrWUPZ1GUx?bHlYZ%H=V6rV%Z8?7KYt%1!0(YPPGnmc%if?&Q( zr~8iZyI1}!{#fnH^@%x9T;xvhL`#*AiGgbMa_R@+W}|3BuL~XtSZYorF%69;31A@M zN3~?~YX=B{GYRGQ_USV8D(4`48#bj7r?I&yH33r=S(k*`Jo{%Cx2-l7h$UBuL7UF5 z5BsYqPw8zlSl&xrejTwa(6}2m_3KOFyG;91XhU4S^=E zg$eJiuvoI|qJ0lNr7|)*bM|18gKCP#FE&E2>z=g^dJP|}`omqGWU>H)UIfWIDPh|tF#Hqh6xJh6! ztiqZc@7X#MY0OPylSQ5CmsK}gf!(f;xM01<6U@6n!8jW!_LpW>y*sgg*l2D|uw0@$ zg95FP)Y%N1Jws}UxI$v)5hSML@Eh}Vg}{0Iud=CUO|3;VeC=Co-vfe3>aU$aL8TfL z#JRQ36wgxKPShH2AdU?vKVhC*G^gFfmH2$!Ir&A0&=Z^{B)aoQ1wc|MzX&UH_$^Caw1;vqR*nmE?iHRwqH@NMs5r4#;JRa zSZCkV5x@k`Bc4Y;nB`W1ibCdpQ-EBT1Llf4`F`OXt^t8o|L^zZ!B&b#FQPC{ri3KZ z>X@z4NODqYo45a?3!6D|!@geE--z4ruS;oD&k2Z&7DJb8hAu|ju8t63;cN^3E)Quf z`;68P%b0ofYqXoxmbz%?WU^{+_(*rkY5=#6#J*XvtV+-_{eS)_`B$2aO&HYz}{2fVF)`pm) zR6~k%(n^%8uo*u@YJDo>N2@2@A7){ zI`Gal;`8i(0y|z+Wv*V3%G6X-uw(j9t&fMv4my5rcUZ4dSw-&i7ku0P?Ic>ePi`%n zA+5fflOG!)`5XKB?rj#LfZ@}zBb8Q1HquBdsX(yo6Ighc8d zmt3@luI$HApd?y&&-G-d^uYu%r(9y`a!0(~b&M^XBN>`avu2P0j=1ebL9XTCt)G5U zOZ~@<>u$(vqbOwa#o&+bq(3;=T3sO{-9Pe6J0wFXsDVUJ?tAh+FoO ztfGj!L9cOG;(ROR5;Fm0KUkz?&oXOSBAJ-663j;3yd((+yx1+^IH~-*7kZe-UYXm2 zcnzuHMNMMd!@j>Wet24_QEUmeq?c9yI{%y1Px3qrC-MP^8v7oy_6W|F7=LUg?Z#`W zW4&)dxxA=#=c)770p9dy`#(NcEuf*G%B@nHW?TiCC7qBvHcWWX)l^Y}P^kWHvTp(~ zVkbDyb28NyjJ|iZs#%C7uR$DdEVR?|%Ij9B%z;z$d&1Ab+D2jXqfPdV6dq|}mk;*7!y`0i3zfANR28P; z|B)=pe&C*NVe4M?i0EB*ywuA%_yFzfMA8|B0@P4%9=(c&h@D~=%<=Y-3f0fzhKAkf>W6ReF6CdAJwz z4j+bgKsFL;39UhuWcQkIoUl3ubr(((HDldpDRgA!}s>)&HzHC8GAFqi;VS?cT@#f5}ALXE-h2X^7 z7RfPsfGRZ;ncI#^XJl`%nHzAiNzKDFGXd?AftJES`E1rrxr?#oUC2Fjbb z^t%a@|D%qjm1d(QWk!u}veEGWQrq^!ce!fsy9uE7H|LwumiF^hlzdxhW%N6;=F2b+ z9>b*qB+0Z&MFIze4Xdv>Z;pe@;!I(GB8yi2eT8EDo3V^Ve}4m4vJ8BzF_`OdNq z)$;vSe`56S43vxep906G^8P=a?ti^}BPvaln@Qg2BY)e}v9R*p7uY=hLDvsSnR$uO zSDkQ+s#kQOGEeUUFxzKi)*B~BHw8PK|5o#jL~{}3W=MG62nW7iyk>H8?Tk+)y!OH~ zG8iP2%5^~M|0$hYiH%{5w)1g7DuWI`TS&J<5WJ4CLaotFvu8AKCQLWBwKN zHD5<+u(abtg(-@R?QvR=tRxnw{RtJQ_grr2HheE5v6<9K3zF1f{bxQ&H_|?r+h#La z9(s|+wF8!Hb9BkPp2*m}t#MXYd{@ie0Mdk`K9c!A=(G zbBv|DeoD%ng?XyZdrhIP2B!0b`|NW5?%6)#;#GTu5^M4Bij^1dHwn*YF;iIZi`ulJ z0x`kXJK}o1<0~;6jg~Vi9v7P@MJ>F{o-ZyZ%E`GgzPxS{wJ%zLW})Zqkd@P3Lf1{5 zz`ce)-c-c-`tF9QeL`q6bV(CZmyr2P;c+zXtNGR-DxXmgm9HnDhT%-%3Y;CcX%IlP z)(A}I1ia>&cdU4}K!aF0T{iue{AYH#Ngr>}c2PMC4L1|=`@SM;lel4(FHSumhypS9 zpofarPph!vMp2L~9#@)Ii{sN8Om?rOw)M-09_u9oLURwYwFRfa$KnZo1jZxVf_--B z+cW-rYx^_Dt%Ni&1?N-m>W&1@kIIxVd2 zX0MSmoW(9CSQy)WUXVIktO2~^B(hht{O3q3H|h7_VCXSDsO z6UAcUfnsj+wQ^>N)*8qM(E4k~DUDh<$Rj2*?&(>TUh!qSb?dD}DdOz9TlCE7xv*bQ zZuGM6(Q8#<_wbQN;?oD;mO_$UH|K-I&dREuAx5?ihqGBhn}KFH1xxb$+YN{eLq8&Q z-joj+1ICm-c0%g##3|eEHm{_?;<-1n!KfdB1?T<+BcAZ7_XGj4!j`|$#+Fp?rj)Im zdP{w?h>H3`jp>>KHc!o`oEpaINUjSUCWK7HTqpLl>eN%`N{*;}$*R5>LtptPk{r+E zr*<~hSzt;e^UH07@PhzqI1}`aX^LOB>xhL$ZYTJP0e)Z@gOuQd>a!}wNw)H%RW^UK-%5jr3)i7EqbiAr0GmDSzHuYNsEkh=V`+Ae zQl4)k&gblFa;E0-7@M^oz}g%Pw#FwppL^c_{nF3`>9ok(84T|mIrAy<5T_ok&V$9h z6o-<`BT|Kj#c3ODT4CDqUGUHOsNx8O?bFRPLsTo0x3yDUvLS6%s`0XeIWrUfS-Noe z8nd>5fI1XZm8aXhmrJBBy^|225k5(zjZk}fE759!`ps6Kz)sCw6Njk}t*j|jKH8ba zJpnJ5n@rWrViqdumgPw5`CJN3HXH($X^o$bjogE|qhud;M1+<1MjQaC zK^V-#jH`XzjEjo&Q`nRf`_SRfezB7(b20SXt-_ZB2$|25YqGc=s<%z(dQ7v6caQKE z&FyWM{0m4w;2z*)hN&r$eG-Gz9vJiWs)(9hE=J<-F|g%QTX#4{@i#G#&WMTc>V$;jBqZRkwoy<_)Zn|gakEV*szHH2V2`kliC+X=+ z^&f?3OEW$E@1(0h;)A2=0sp0m$Hk02`a^U10lw}n2e$e43&mR0^70Cr`NHeCrO)kto2{H}k9HehB%4z+1)dgI9pCR(Br58gc z4k+Gj^%l*D6Fu9L_+H_^&Af4%nfK)csZ|?jFF6v0y1NsT{cOSFirjM|Y=9;#jgA-b zU2eo~*~u`XF{ra#(O(U80cIaQo3Kx}D;CNZALaP^;d-9z(s{Tv1qfdXP1Aka6@@Th&X9IaX#~0G7Sio8%1~`FYEe-ho_h4be}w~lX;O9 z0@bhVPR>61=r`67V<}PWNpyg;HUUQgq(FEZ1S?|PRc1bHLbEIyYw(~d6t!RW-t+04 zU^~>SSBd3pgV6!>k|p?WD$Pv`z!y$Y+9*Tjua4*6kbHzhXNZ8^+FhUA^~a_(v!rI4 z(F3Iza~b<-%+T~?!`j0-OvtcJTh*@ascQ{vMy}3~KR@QR)U{X7zU)DD-9528b&Mjw z?aO4L)?RJb*mPykuOEC=MOGyVL|G=Ty$gfp>|CfUcQp+%b9b*S>YxBL4BRi9VRgW? zfO1V8$s4Z8Dxc6q|2>i?d7t!ZZ|JJ?~cC37FqIvAFT5CN~iJQafSj=!)xhG8f@+rldY4;7~GATkh4 zrDIN{Mc2abV$;11L9D=p^!$RqTp~rRDJY>ocI(Dk#_45x zb>6#{*Ua-k?>5rPom#p#`(;R`C%|;~j&x)DZFDZ~#y1n@n_{fFOwp}cgQNw53CCD; zt|pNH2Km6}IU0+R`MVz+^8|s};?tFNHrP7&Ue?$Bi`t4UWn&Bvhi~C#C#`3Vj)y60gV#f@j(@N26W)k z4mX)ccR+k&1AnEVo|i-dr;Y+QzdoJX^cEdlnq|CQSNDUnu>Z$!@_OF+kMqNjR0amU zUqZ02#>ok>UAY{V%nau@?e(d}PE%f))GK9qpfM49-Jr8_x`}50m?wPM)ICU>o4tm}( zMpXsJB{eJh)dzoZ>?V3x{?qi$LHwuVpdM8ENcX>0&DYK2!c`1=@ zK`G=33Q~8pC~_%s3+&Qp@Fkd^95waq=v} z2#RZeJO)hU)=(Ip6+{GxA6j`AAv?^!6W%Sxdav~vU6EqhnO(B3cucKx*JuB+?sl=c zmYqTz_NSUX#``$~?&>VKL?TuaY zSO)F~IhJ4%?!_7nr>k=%dyi`rSd7_~Vz1d0>y7jKG83r>E72sKQmGNXZK|{Oc|lX+ z*gQgZs5x>j9oxBcZrtJ?s%&r`dR1x`%XDea>|EbL+(L#j-IzNMzv>!jBr9%pdtklYckqi*AHQCOC`*WFtmzc><@D?(9ql5)k@eJF>!>S`N;drthE((zGwj zyQhS?JANjntUbE)D986~EfE3S^7x`v&+P2Ctqq%ggs)BO+*c*=b8=b^+dFH%okn*> zxPgdIFpo9&{Dn|cLjk^0^dMnAUK--!RvXfv2nKauaoyAJg)D}yBCIw&@>0-ii`n}- z7Aej6DsraqQZ+A=p>~zqo==O*B;JOxDP)#L9QeAGeZc+1HvOiT$Yvp{$@Vk4XHqi4SOx_>ZBojD!QkhTDLfYx!f%#gS9Lqj{6PW9Z9bMn{$@w z=TnxWTp~+(Ny=G$dhie6XGPXLEdC0hIJVmvb@v@4jC8YqB_Pe$9Py(@H74~c+d9aW zV;#|*%U3KSw`EXPvjdDm!)9T+og|nSP{m-&kkQX7;somv|yjh%Ue5a;o)(8{o z0BagvPts1?Eb)aYU5*B978q#}a-UjXl<5#=opEWDWCq%fes$>xq+m+{7V94r!tG|P z^cW-fh&dO)+ILOJ8ex8w2}4B=eES!Lgje2Yql(k?VY=TmN4PK5hlCki_vkzv752on z!jDEU(`tIhQ~Msskt zd%n;S7gj$0h|ztoj8CzbLrvEhL+zavS>!H!?w3r*jUTy$()Y@o>|uTd2ohZOPPjHx zxf116S#>Ih3C|J=giq+|-YVv62xU~}Q4EwQ`KezRVx+Cz(lx27m=MD*9Z1(VxvMLP z^$IENBAH|wvmh$rdHL8*#xmOrlxW3?Qpq{_Ahg`^5$<~Yh~0IQJ$Z*q+%tLoTX{P2 zbnCl?LlCmWT6(!H6SbFn--TT3bbl&M-UZPH2joBaWKnW= z<_r2!UFDv{4C`yb=!>;Sw=p5F_BAK-e{kJO3OMx{Tae;tLNcf0<^zdr7tXlT=ZVQZ z6l=Jo&3=(M(IqqK4&CRC=aT-2KGamz$?_}M<-GNpYOUl~6(Js}$8e&Hom?1RpGVuS zag?70e>Vmiys23w)lr?|M4oyet~@!g2~ercUsz0mSib6EQK9S?ccJ2D&UlZYxpvae zp3L*li$*#Nfe6$NNodt&IfJod7F2tKoLX}kb*TV$bqqvJ>@sw8Wj$}_Tf31u=7uQuWfvLD?zCNb0<@L;qHSI6eRvv< zU1v6?OTPrpJ|-()zdHGa6nUj_oWbp}`5>!71FzWbE&|7_L5`oH6vgI}4VCEl8aGm} zj1MI7$plfoUBrm!t^~e)T|(%ClhO*BpBW6YyV!lK_IhOL+{o&QnCLV^E_7r-rV$6S zP0F|{2LLguQ;IRaNmlbd31y$K&ut7m+Om0jHV1Z7N1|+$X1aJgkMw#8+7xrhRGlIf z&vo-O4z6mktSF+r978;0*^4m_r-4P^Dp+O^gg`niVPX!k^>fzzcF}=_MfSwSWWpN` z5a1rQH+dHCuDc|N@0)gf$Lu73?ED~ipBzGRDs+oV-QrHMC_Eb8r&z+V zEK)@0ATNO(xS4ftHja6k)#jYX^4&%1BM@HYSulu2Hi;BESZ7HptDZ@Pmk9JD4myBzvWv?o<)^Rzaf%dOQ0h3Y@W84 zjxQGyFS#SlG&h0Llz5%!1QC9?bCf9C$T+tb>R9BF9sfQZijUUZfP1s&TV}jLD!HUP zo-Kc_yB8b;kUG8G+DpIydZ&!Z3$MvQ1V0|n#?Qq5?AYPsdb}iOA84;76+@e41@_8l z=Azsmon0$+5Gwjvt7G+?(4%QO3(JanHAXG%hcM-gzr7)N#~X+ufz7-w&`(5ChY6b)Egn>qZrQjPci)05oCeu zR+}{xDaX4XQ=DP8YaJbExTgHo{Yg53_kSu~r``rIHmXlnu&LeCJ@|no)Y|`LOsyc} zY^vqF&zI|bHiMtTr`8kb5HjA4F71T*Y-_B=BjXD z|En9Y4*4Z`UGlQQVmO@RhLdZ4Q8qJ5-P6h0(udvg+ARZz}F{)n{uRdZMd16|;1F*H!p9 z`%2T!+tHbRNQA}qrw86xL}yQ)Sf0|rDP|^8FH+2Vfo}!{zMijf&9d8d8i8?N?-;p% z`Yo~Dw7y3Y;nk<37q1$~3U9M8UB&21N7TPX;#p1rj(V2|VVt~~HntZGo%_+UBB9k; zBTFtHX*+`%m#gG|v;Z%@l1A}fx)-E=d1+r*#317wDs10sAez%q6I5Khs+|6Ji14EJ zH%Ns`(s~2Z-XYE`I+kUlm7s+cmyo+!*N23DExZ8Q%3iu+pWD5u*k%zv}T1Uc6WPs_o?U?zc$xJ zKe{jY+SRkbiRG75yBUHE8um;95Iy;rR80A{e?bQ%YawUgPggBE0?Y#VjKts}URMW5Aa zk#T_00q)hSxmF7V_IpHa@!HLMqJx@9_m$?0)1K^f{(X{i;N;?E|K<72*Pbr4;+cyt z&AR^g-iuxOp#8-FWf^;KK0UiY+GU@^pv5lHj#`#Y3@fbTqPs=26thq@8^i5;h6jSclUOxUhzt1v9UB~aO zOV(xCru>lk^KuUlYN-(});OZ$5@nR_ot=i>XzgaV2j4G-S9Es}7NOUDKb9cw;R zd{Ee^(e#FSLWU2>YC(QpwZOgASP*&5aNM>{3U>fXw$T~TPBkj<#Y*rYSlJx9joce;4ZU}7t3dx=oyKZ%^xS@t|HmxoZIt(> zRb|`04lHd6pWvXX-CxJj94VY!fgvseyke2gE>vaeyFWR9(eWl{}L#AVO&Xr@80t3 zsq_Tp?VVl`Lcbk>lee?&#`@?d(-qJ}Q1DJoJsVAE#fg6C=!>sNIWZ`vFCiqVmGqPV zB}5)t$XdH|95Uzg24rmetJkRl`a|b<$@5+xqYy3G(!0XtI!&};nf~BTz;^>*=I~vQ z=2)vwLH4v5`IA)t_V34gXjglMGVT}XS#(G%p}`FIpdNm`%#^~K()QDc9*U@_!z1N5yL>-J4!RVq#|E}@7 z@B4e6^?uL0*88sYU4Qt)8p*z9?{n|-JkH}dHo;5%$MdO&J@x99FjVI15#^Wfrbq8w66hWw^WPYYuF+>VoYFJ14 z>3qp?gZYv63x$@ezrWdy>a+^>#ER^=50DxH>)Kxr)H0>X<&Y0vI~Qv=zOB9mIV$@)EGTu)k` z*4!NzB%_g#ZJl!{4V+UQ{XFZDg^=&`#>_JhF<)B~vmFJy&2;^CM1$t1fHi+|KHCl5 zbHBD=d4%Ng%tQ~pU8HjvvR$m#a}eu%W!B*i1-$zB-JjaM<)Vw-+Ec_cYO1Rf=1@nW z=LmaL>8>pts_uJkxZ3v8-kY1pKy{GjrU5^WPxCsCqn;>=&WhjVE|FEo)rHsD+eN)g z0(-m2XP@8E_Z%?pD5@9z`K20K#J`nsX78=Ot2<6RWrP0)K+6@1Jk{)ErKpY{?6@-b zX6I8x{!kNtHRtzrd5&mOb=;ky&nt*Cv5>B*=_sZPZC|hL$4B);%;UFpO(37b&07Q(lI>1y`M30>KY}#f449J1AcFL5lhd{-y`mlNCRdW`)ke9#sPTYcM zp13a)3T-+R;GbgM@xitj{_CsULEN2Rg`fL8pQ{2l^`}348m;5e*TryVRfT+~oq@`!_x-!iAl>%?Jh!sqfJSvxmx5vm6NyoLdJ z(28#U7x~-jZ>=)v-@$WGyht(eXX-7Da0cY>XuA1LU;7~;9;ZK==X_TtcX`%V@+@jQ zFFr+RrE@Te+GkMIO>dt#mrzt0Ya>{ zT0wi@#>T?Wy2LJ%C8sX1{XO1_@@A}1r^as%ZH8rjbwSdZGMT18Z&0G ze4b^HS(Ed#w_!C0qr#zs7yR9ydKU&(|Dg#&;^5HS_x!&aN+d29J>KB+K@N*D*Y2Q$ zYf3A()SNZw^a#c7SjgKJ37{f(*)3p+8=K%7*RhMvA&APp(}+!{kXz9f|K~$x!?9|* z6AQ;5XUlh+w7l4lPh5&Tdv+7TaMUe^7E2VpDXV7OIxPtT~2-4#lb3tCu$Kn$~{dGDvCxp3C=eDYP=hLz-;GPxGfy-txhdUg*=0c%88gkK= zFnH&m$P|(#-@728Q2zwi-N=yJHEJ)^PhBO_P0%3i8W^`(2aS%2w;w3{G4Ys8JY>xb z2k+DVRi;LoFn;Z+K%wZq!1^t`X5S(dX9mv=dNxYgmr16$9Yj&|0XZ2jgdso93ClteP4*cSAhbK2Oc zWe`{Vk*#azj>67fvpw6{vXFxJ`-}namb_$~Qv!S2rsl{n4 zJ(#+xm$h-2TDfh8pa<7$>kCx>Xb`c%S##X(Jz$&Mm1F9$ubY zY+tk{O?^`Z7O)0e)I~Ht3ghAK06ku8I$jC?0D-=B|C71L+*Y=@&XTtaev@9*>Jmav3_3vw-J5CS&eHd718@4>qEw$xpMhKP}G^h?)UyU(m*^3UlJT-Hvbk)P3^ zd@=h2fS^fcV1MJdg1&3e6FYXeDKKnyOPc?Q{Un{+hJut->0^NJ9uCMWmT;{Wti(8X zYGS%t6dT9tFa(J8V8?Q!$p=m{BrFYM7Zz5YRv~aXsX?i=8Y?KeI7w5~7G7oy$0gC5rxvQ9g9i*_7IS@kSYLey3$h zHKLUEZ{*5VB+kz`M|p?S>K^F4#IBM@CqfyBrx*{)TBrt=MsK*fLc;)dC`YE~1gA_H z-uhUiww&w-*Ym9mSCLRzE$f&}7CEGg(|@7uf+nPZp&f)DnbWdVA;_}K20WfA(o8%~ zvpoK&S{U}MXPaukw=5wKlD)`Av<_X5ULd_GbF|y|uJ=ax{&?kNPaLd|X~&lGDTb#F zUs!`&BG_K@+rF13&my9!@o((z6FW>d1-NXGD=d{n?O;5cjBX?oz=p24k93%S@S_&F za~v!UX};Cv@(5C-WOlczf%QQRu1(vc@Ut`2txGv&G$A%UV%G|L6_f)P6FTgvqBWq^ zrZ|_=n9l1(RM z_1T z*7!ro7jii=^4GFq)*=M$X#|NjwO4!!nJ#-9d7-`aK_u7WJUR-A&`-bIq_5IwB2aWY zTchAc;9b7vWGm5|2b%kv!}@KEXdkj4wp422H9LDc#9@|U86*?(F^Ala@jLvbgVT-P z4^08y`+;8}R7GTFo!8;^7xV-mWm(BXe3t0>+QTuh9kl?k~@2ZN|B=Bd1?@#t&{3VZqN*uY|B`2Sx(p7@HPH+N}k7FTa z^clx}VZIwF0TgsowZ*f|*tLSnjY~wjfS2A~B$OZ|(zv@3|B!P1TA#SCR_+gbYaz~J z2{(o3-VWkVd)Q^G*rb`;o`2zQ_VZV9GUF9Tc_b!dPDq-9;Keyj*%RaM&}Fn>!bD4Z z6Bt%jkAC;myAr(HI4g2-4@o{{5g~g#t&9R_9TM0-;ZjnaO=SC*d*L~ zw?6lwxs;P-8gf;2zTIh*f9*fYue=Tw9=^jonzZ#^wafbe+YodvMK7e2^JuC+8_psK z5O^GpDBi;@9|yI>?{=?EynQ*#H=W9#-YjhhARDOReBL_+Z$FGfUXWb*DdX}RsE5tY)a|hf!yi_Gb=uj>&kZk@ z^a`FiO;Xi`+gp6u+m&aRXh0QB21|~;msEvdmlVIKvDz9t?=>yejRnFUAxt!Vts+6C zxd!JJe(|6#02hlEXeK`{XxHA|8>R{J6FqLKfuyAEZa5t%l=@FO#c5rt`BvU;@~^QP zg}folBG#C?EXL1(Ys9fgjbc8{rZmDx&>4A5RI#WLIb zd-0tW`)YWkMi0c6y<+xeLl^kI3KtLn9(LL~0*~s*ttw8H(1DKDW)1N7$b*8RXtEwH;pjb8 z7oX%WzU`*M@AB4{tF_EOY?H9N3HT=5 zE0XX|IahOOV2}L_q6*T>FXJ>nLjJWc-Pp{dDet%SyMbZL5O=w-p}_dL0%Y^)H%-dzI^}u8~9>0k}}2!O69#np3%y0#``25au=YGlOEHFT_YaBcQ(P)2zKqni&`#OZgTZ^p;}A?ZF; znJV|!*1nZV8OZ2QQ52rflCWTv-!XF=2JC1fe)6sG6B{Fq6U_N!}9mVqJ z`i>*sEcwhLnoP4EtoA2D_}WK*$NsAsBew=)aUv z$?shRj~c9%W@R^f?dBhV=>H)|OO@Mwb*6uRS>Sq`VlygJF!ZhVA4c`xQt+~53;BvR zSErh@66rG4qF!P3>lMa{off0omuAAz?@GtKj3E0aRaU9y5!glQ*mo=lKc;-m5hIZ- z#qpRBd;Z;Lu_A8uK`_CWQQmJ&&-3|4=)a4NCs5*_%tk6q+_9I3rMwcsQNVS z+h?b;PY}1Yj|Q1fLszBjjV7Ns0j(hskTURQp}b>Bc`pjVYNn#fAlphUJ}kV{hSOSf z=$KR%7Eq=A7)uD-_T+i>bYDPUDWF@wwN-B1Wsu^Yz#xZ_XvAEH*o$$omstF&Kes0q zgt_hRlUsc8lQe!vi?EX&wcF23abKgCM)!G_34pjNQIV2YmrLRa;kx<9VK(uk9j-Qa zci0I9cT?78(tZM94O zG+&t`+o-|H_1otLaFfl556q<&s}^o*rH`mg2wKxvW5N72h*xRyl?tOT^H5w;)(K8K zDNaqaNe#TtW$*q-!;tIgOacgq-a7@nxP^R^OG0QgT}t=C-|p+3(X@0qF&jy(qAxKA zqD|X%N6$M|hg{4X==^~{r@h-bS-1vmI2PHsuH88VrKX+~I_50;%n%9ZOQKumYd@p) z-fm0MxYr*=yvA9`$EATxIm-2gT8q|+vDVM^??)GUowz2IZ+ zbanH={Wk^0_=~lgvh3ql#l@A#A(Mb}8~)zs^`{T(>6iX@4*?bHOIu zyeEvW&6{+)t!5?ykT?AE@75>ZaQ2lqNTmc>VOiLK?ZZy=(0@q%1*aDKPy73J!Q&vs z?|jz4?&+m;VR} zYB0{a4{|cWm%l&#M~?tlfM`AFDhzm-yRC|Hep|V{+Ex;nEl~5}UyX^Npl*r$DAQoD<}t#-#Zi%cqgyCd8pBbJ z7|-ZjNMJyhQVMrPWdvg@`k83kHF|3LaYjE%i;Vw$Y}sSDuPZ$BAlKFSuvcf#hlUwq z&*bw8QxQ@4XELr-J@7aiw5pc)#}L?bG6$CR?oak*otIfpiG)%YC+h>L^%pI?yo;}o zK0=%Y6w6^CO;5$TwB(2XsokW<;q?eL_-FAF%WrGD@k1{atB>3kgR9E|NOS|sYZT-} zp?2v(9+0d8ks;dnyJQOQQg%Iun-qj>xs#jMUgsemy_*#ZD4a9S6Mu5xG?(+cq^A#k z{Fts=txDnx>&3|F$u76p9IJC#*z<1{)&q7Pg=tKZ-OPyFoh&(eitA{#AA)r5*3dGn z-AauOAy-J}yE9UyFo0f84r_JaCFYb9MSf|u(MWQfZ}G}P5IgSL`@MBRrJf#B>gL41 zTsT^2TW$g;k04nvN*d*QVCsW-=uR_e|XFHLsYP@jkr3>3{S!@@ju35vg-QQ!eH+6Yr+XAb}!}4 zW`r6!uBj+w{-VFE$dCeYpj14Y2B!1tpMW&NUB|1q*PGQ|-M&14 zl$)zA>Jp8Y_d6+kh96iU%Ikx-;^&}mOn%a`^z>+>(cHB+E3Fmu;I2CHaOFyz3vTf~wdWO5j;Vf5_#CGEu#lDKwn!Y%@c@l@LL%%7Un11J|i-?&Ek zeY^c8(xc|5vTsJS+)TlxIOijZ@p{s0tEid*`?Ug^aS-@8^O}pw2XFjAACvN}Ohqgq zl;krdHqyAjs(Z7a>`^8r{W@zx&h4zi(`Zp<@{8o)Ul5PRqo~(e&>~`2eK$uAp#>-D z;VEs>Bt-CcbP;cG1=jR-N^Vj_CpP~^_EdU<6G$E24qmkmUXdSo1DV^}4xM&EO{L$* zOps|YAl0z;x;7V%1^Y3u#>cL;2YZ4qTxGW`!yF_2Y>N=864`b|Rr^KRJT&y@R%!pV z<#qd5v%?j8lceBX0$|t7$<#jfU=Qc5#n~dUS1tsrkJL*T1{zHkAA#mM5gdP>{2tXR zpZZkCSdVn{JEE5~G0sdVg3JF2ZR?E16Vs|^9X_Gano;-{*nagYs3EI_^+Y7{ALB-4 zTtLJ06>PeqAflWz8H^1E%+47$ti@spRsXQlS`#dtfZOfzy#u0nV#|cXE=19R#u2zh#6`$Vm=(7Lg+#~t% z05#}6O{DxrM5z)0kiM%KBNdaZ4Q>Hj@Lp|MqDgU`eBjqm7>r)3Esa%hO!nEA!ST&R zOwC$*&}+pdTq36q=MR#yQN1IoREcX^NgD^qa0jMXLxyK{6!IGzq2qA{?>A3?)T*sm zYuE*~SGJz2v5lB`YfV{c-7W`cxJLPhAj434h4vg{qu~bS1qiA1!RcP?$wUqHOkGa|)&3QCDDa`vxhiCM?IWs7^Ze6vkBYK5<`Xz)m=TSKJ%SUF&ug(u01|!P8UASXI z3RnJTnOrqXNR*ipk#N4TjMf;lqe)Js}%8FSMh4E){x>nKCj0OTZbSD z&yr<`{}Ho+Dp(M~4`qa62#*7nu)#q=l%$qf4{E&raWgv_;j+y7Y{BoHO_b~=KI-&u zL#cuWAy!GUx$ovz1FggomW+N7g zKM)504s&_J09ju(l%8_N_|!lWg7|Sl^=Ey^Pi97BVjJ&*#yo~v6wNBqU-KTGV+Ju^ z#B20m0x{WGqXm0BT2mc9rO<8pE$C$>=ZeE!6%bLlfjM^+M*iB1jRLf``IMS zyj)rE3cAB@UCo$nFRM)$NBnCEalacU!65V-omVecl|BBPS-|AYRx}*?|`pf^z?->MY*%@5058o{Z%|n^{*yQTKYed{`F5U zm`?IjzTCGfsho{KS<>d2_5Pe#VT0G>hstfeC&tSV0=@h4+>M-qZ;Y_s#QAbq&lu9# zT#sKBNYm9H4Rw*JUiyghVYke+D5b4l#A4%7&D$MKxHf&)rB9cOj&SixkH&K~sD4l> zNScD`;YIL#Ee6*vZlO!o27O#W4h&M>wu(6l>*(KSc#n^rAKIh=_>f7bSECYm|Cyv6 zN`zn}wt~xXmG48_a;e)4$lJwMgmHnz${Ba)y}t{K&-$J$xRH<>oM!92dX4sMzJ7CX z$sb81bJaGzPA1QPWKRHEDJZG%?;lr&jWk@C&gyd*1BN;&=6S;+@6E=ZW|?KWWvRwU zim|*CIvZMX*&#dJ!jHACmc+%g8(+@6E-?H!hih}hfJ}~BLhs% zGX6}6o7l8CW{x$&TE{qkY}0u^fl2YL{ksK(%IwOC=C8!Yo>JtwksuLGTyT<P0FW3Xvr?>|dn+Hy9+lsRgN7j5s)O!wO3 zsI&Eekgwk1#8CIApm@^^Q;&YnUV383Z{h3DM0ByqoUvaKGYuSexg04O^(p2|5?+gl z@7Q(alVoYi50#H+#grcvd=rM0JLlG|z9qRxaQ1v539%7C{>@hay+r^pchJOUL%Or!S7VIA(c7v%LoQ03Fw!`e zpCs`7&+8abw{jH{xVQp5Jk-TJPst!I=tt_l7%5Qb)l26H$yysGw$~jdu=D3+`Lnd) zi6gY0Ckheuf8H4^ZeGyvx}S_I8D8XKQ&f-Al1r-7mb+&gSQGT=p@bCr24f|p5F0?% zeQB#rQsrR|X^YW5+T-n#b+}9coFI zFG01+HseuTiuB5P}?4?zb0qA7kL#`l5MI}XQ3eM6x1!!!Pq zD9*X3LzSJiGxA7zV@oZk9sX}WkP5!37hUMW3MreEvKsX6)&vR}CXW=6-99*HA(TWX z!=_@_uM+9`i`p)UU&6F<6wE^#&;GU}%STZ?KIcq2MF|GMa*F9}#If%JL%}s?coN@Q ziGtRw9Lo08&?UsNiAdVvcuQ9!l75Ya2ilxc{FZ`{1XZM)J+#O+?mMz=yyOGn`_X~E zGoLudo;9c6`c1kn)$Jv&lMmF~_a7(ZcRy^fKJ%KIn2VpjJpO3E)|jgmv3{r#pMpsy zWc9sM1^yNL4$t+)iie0S8yqL6GFM;E4>{r$rL_})u%ICH`@@B%s5BatVxIp%0_cc_ zVJDOTZVY-xRw`Vo?BFe8=TlD@fjQzIqqtw-bRpBgXiQ|Ke3zmAcq?~r?mP!Z$(g>W zBlfRqn5_T@Te(2?N6Umu*(Y&@pT3MF%KZ+rUe7EuZzS&n|DZZInZ)h?;=c1=Tl4rlwWXg3Gk^f$8*JmhUT0wV zAh#>UpFD-%&||S`Nng0>Nj<{p4yF{3U{(W~rZyM>_lV30nFXA?emB{7v4+-Os-K#}sgydmV47>rRvFxRu!VCVQdoHrl#nM;gnVdEw@? zw!-uiV@qj)nta>5qj-(4;`E~2I|G3K78+(FNR*F(q8)3l_L&pn0Mo@(dG~asRrZaN zmVU&NFIaM+7`Nx=<7}&PDb6RpSMKhc$iF99EA^K%FB3(O5f3pNN^#FqIZHKn{ztaO zl6#-dnN9)GwPM`LdI?V%S~QsaOt$*kqWY(z-W=-!9D0nm%i!Aj<3NPnHGTYx$fYwp zXn?hIYzN+YxGgmZb+-{~_4#TQ6Vs~Gs|HO0VW%mRY5yT(Nhdz9rLVd4JvyKKrPl^~ zrMHo^JN?+A2G8?A1Z5H_yX=A!Y5vWa-b6UfskukmwyodwtfH@Zw;(u9H^io(1Fleb z3-IVNkVz6^@rQMc3R38*MbI!KGJ(#UucZui7raH{TDkDIn6sLJ;jWn4%wCCU541|W9o}BY@8+odKr)oSn?XpoXbg7#|kkuDdSLD$%TuhydHbR#gi?ePg1T7x8eQ{^l|xqq4%hg6 z#X;^mU!s`h;9H32$W?udHOFx5v4@G^>HG+NA_*H;F7{|ToWtqgjcECKjf8BsEYfAA zb;YfaQa%_|TU;YwoH&NrfK3zS$VnR|{l={^f-Mc)Cr*8~ zrhkxX7DkWrT+!OE-7EQQYJ8l}TFs)MGI^j5?40@ny9(Cv)uiXO-|Lvh8Rr5hkXmTo z+A0AD9D(QezZgct6RZ}LNjc{HL>;V$_8(16*emz+YZ5HYb1LgzB@4-54sY=fO9D=S zOWFz5$6+Kp#RTzG)w+Ucd<{18bwNYjhN*HZE`}%&ypgI2)#5^@H`)jhr_6juTaUM} ztqO(r*1bVjy_-x>5W7jcFs2F3FNlTJIvRE8p19yE%yVq7Ol1-n4OCblIGzfq`FsE({ zJ*b!MFa8my+thVFO794!cT4?{Z`^QGPE~2&+GBl=LUbRusYg35*VsYr9uevQ$AGI9r(_0-F!Ks1~dAa zmaGC5V6gjbdG?}XoNUw&MaE!z&&&h4KF&KDO&2=UY1Rl$%!yu~eHM3}gHl8X5m_ZC zld7a-rs&*}f2T^T{>jykYc#e?_0BV9a=%CZ?zgG8K!$9sUlm_@S zFEJQKw&9PiuwF8TB=#Mh$&w*+$}~@ZEPRn573suQr{k+hw;GId?_1UWdD%E_V4Pkz za*|cQ$s56+X!&jsV+h6o(F2AUE=SuP_7R>(pDY4<{_W4ljyw_B!H%5jWVWO7HvAqD z#hxS8trCCgyz=M`0au{^KfTJ;nElQhov(0y=!*X+yli32Rd21P69DvM``Z-UzvP|Q z?;Toao#;%`sNzo22XqbkM(`CvMT)iB;rHj+Eyl^UC76)1)VV2k+lu zu60!JOYwqOotrAHb5A0?KulXC_5mBA)qG&3XY`@6fztBGI<`_p6-SU2xvYqond z*aUfNepALeACJ$$F3$iIGYi0a6KI3W|s)|7{h{0AcvQ zPCEWiGZ(o~{{L-H;9uQ{A@lz>qJAhQuc!xLfs{zZYX1$HstKgHYS>jmzZS;uKBOdk zN%o+Nwc<5l)4E(TciA@?(cO>lCrGpR4fFE5b6p037Q#zoj3sV&5A7t#=Fk-evbwOa z0oYe*U`#FoUCvdC=kc&G4Z zDSx(U)n@qb7_EKEyvf7&JW>ke{ac2fw6BCUv}^(|nAWNulFlxEMI>R8Da=?I0d%EV zDMHTR8Hpf$E9{694vZ*1p-zNLvd_Y*M##)xXR4`=O!oaV$V z?{Ul}GvBO9fJ;bhnFW|9Di;H$pHig;9~5Gb4Ll}q5_k~p{~N*oJFBrQ8JE0*TdZwo zc&W{ffKm}|n}0K(%JLXrNM%N$qXu7rJ%boKv*ncy)z2}JUPSpeXF+N5H$!;#1cUK~ z=agkIg1z^QKOF=z)*E(T2NL96d%OQVTp(0E5Sq@tnTmp3jO|_l$++{U(3l0vz|pb)_2rIx^_+@L{zGNsum3U?W86)#+`g%>>Q5q( zGnva6chrK+nbpO^!(wIE3#OUtEs$v8P8PutU~DsO1KRzpkGt(~SZ$JLI1)-#4y!sj zVA`p2)CoD4Q<&GBwPd|ntu;XG01aL#FcCQJzU16phmosH!uGwGcARZHhaGdfePQJK z$7WZRK@U9VIfseLH%G3oIG_|%{KMb>hzRd+e9IXuE-(0gQ;U#{XkqSYQ@#T%4W8fU zjOd!q-s#i4BsSN{V{2cR4ddU;uN31257xbWN;4l?<3CcM^Ba2g0Z2vPMpUGO*v1YH zUU-gDi!LXgO>rn%$4Nv<-!&OO1UiNcI-F8sfTxtv zVFyYol{>ks>OZ)X%=0V`UO+pF1s)|n$BG5^D0Pkf7oHmLo-*3r`|^1DW9~tDVWD9t zwvyR&d-w!&>PHldfHYgJMeMc;G-_Ajkg16LV>GGZ4TlsWjiKHY<&V8_&)SL6%-B}+ zj^sno)u{S5@;LWaNX9nu@P%YmvlqWkiEHagYGdzyay0i2hVS&^_tgBe4`z8evGd_0 z$ocIgF`Vo(*;~2PoN1Jt#kmJF3}J+mycmzBDAPwqmf>M&z)wZ=j_TW^iA^q@ZN!m^ z$Qf`V$ma+QyoVRdFo_SjuP{o|Y87neS}fe$#R6IX*U)0_GGe?l^bYO{cL_P-I`F*=pcw>fBMxikI32^ddvE1*I9zlV?}LpZ8w#6>P~(StQSl;WiTO7BS@Lc_fGRL zZ1el%w(W|FDrt8i;DDz_C;pd(1$>otb+HshDSjyLdT~sbD6K6r-F;)d%0@y`!-WY4 zQ^3a)JWS!s=PlspB2GO1nnX~rU|`#)5lnMv7v-5h2(MG4)XaX~mYuet+=%1B^gM9!uF1n5pSXQr28NWDS|H`)ggh zy&;}aX6!LezJg-c$0UC`+1a1`to2DhnWhX#0QKE9>lMhatE2|#S!*zEvzT;AuiMkWuwpd#(SqXgp_HxfR z{V%em=wdLNwlLG%+&Fw~-9?y7iMd9PuQmF?KpDc2o zg^a18qJ{0M3F8Zz!}>IP6ynbr;0e2ywXU=dri7Qi1*Y#VG_tgt3f=t0Q#o%t!) zkIoat+DxYnctT^7xj1tTP|d9rxEpY*!4qO-!{s?qspb>f}(A}!Pd0( z)TV2`%PbxVSk0CLKB_efI)9GTGK?h@b6OAl!>0;IIfH^#kvlV=YBkY=T6IUqU)2sW zhxPqDslOo(-N%KzE2wJVK9NBR^7579M1bFsM&QD6j@A_sWM$#Ou-7@K%Q;}W%8d!$ z%2>z0dcfgmw`waM(ir-@T=mjn9;)d5+Ic-_%v%`S?K)PDv+V9y45VdvkgQ`(NG6V# z#U^RR6Xl;w6qbI$S)vgvK7yvVHxf#`Bbi_QPWm<#?M$ zCM8Giyce`q_&hK}R$)3SDh}HNNil=dYXv+VOXXA%y2};43W^% z=)PR5cotyltJvy0UpKRTe>@0q0gb@ys{JZMDZ5#7q&jwaJ<|DAWv`td=knc(PqCMa-~7-440&-Y&V zcS9}})ZVKy45K&cYvfDJ>so!a3)vY@?_2kiRw{^%iuAR$)@xH1-WmW*ijD4eV*4vL znuQpQR##5bef2ut{o8!mN@R$0mI(~c=4N;rG(V3YdyM>|gG-{W&%~=QM>sdCK)=xB z)v62YFH~W!mttv;NJyBU23*f#Q6T&&N&n0hd)y}Jz-xO#kzURcvJ*C`86+OTVUhL8 zGM-F-dptHulcUGAF(mzx=xz@8gY_Qf686ZSs91dizr-H#c<9+x zL0?MQsRQ-hS{ZCzr@rYUnCPtrIEyrcqxR7h-N!?hQ{kASiDY2NU;a6#QeCe? zT-yFJ&Xmr^P2`uJfrpxQQGl|Wjij(5L-<3@piWL+u+Blpq2y9?8hYBc%`apYt5yqa zu%)r^CPDrcA35|G#aU4`kZ(mAr}MMPDtDW-Yh3ATgn>eG`s-hr24-t*o!FErF#pd# zQEH|8&n&K{oW>z_79Gf3W1W=8C=#n#OE~9z>(sKsGo6->^#SHE-prRY9m!?_fqz2V zITJYheWLGMn6`<(F4*Rti;Gm;@^DDE}sv1bzVhX9vET0W6`~H+nip z2u(22#`A%mq)76mA8*Bj8UdFoi<^)BT2}v267X8esTTNyN2%=nJ$<%e9l>49Zr*zf zOW$J*+JkMwyOM~3yClUy7Eb}2lsn*gL44LW5D_bF1Br8j)Dgepzy4G7ZGSd}wI8{U ze=Uptw%Z>W&fM9*y}ad4YHi>}W9{X7Zw>kqEavG?l$Z+l0{yHIow@QPp1C-FY9~tz z_A!fyO&8+|lG-3b$4b|PXI|D!woNx3L}Z}ndwk#(>=MeCvL~D_eeSIj z+DN>NWlQ%KHPHlky2SNPYxve$x?}^nt*`v_`m=vkYK|R%V@#BoB6#kSeKGCi=dW~) z%)#zE5Ti5ssF`=|CY@r7mt*Y)ikUlyPnJ_(bqZvP`If2vdn~iRI3uXe$$JFb3)|>? z$B@U;=S`ZKgPE>d_uF{<#e#SkpT7Y^LEt$-IoIc?;~tcftJdSxQxn_8QscE39?TB& zumvywpbdY(!5MP-4d6%puZYFyRHM_k^$OU})r7mFx7nOEox0Zh{FO9+k~sTwcdb+5 zGUP8=R|Dz);(Ho!fN2>&gjqcpf;;n3K zCh&2wjyhO<$s<;N7d&@mpW2Ys9u^3K3#kV3>GV%D3(<)5oyv!&kz|@+pP>uAE%kwm zXdeCq?kG9ql&07!rBMMoEAEhDj1nx39OZ+Gkg(O@3lw zrpe5AhD;@^-9YW`d@I+g2CwWsO#`keq}lDTGqEV)oqhZWR$>EUeFcNS$2XnGkTxe8s%Ej}W;syHRpU^4EJb)?cJ#5+j3YB43u{xQun6-*2#~Af#0RVK_Pr$CNKNLb zg$*Yu>SHyZYc4k@F$Ec&F(3?)=C&RdAa(rlJ(xJnzx#wAo4#+!N1Np^+r_hdSO!k=|}5G zX4E(OkyA!;vbf>bRspJ1;WyDWgo~?8sRcHD=1{A?_yg49Y+h;2Pa|=TD3uu6U64XO zKF+u-iTiZW)0VOA*v3D0qM228fFp2FI1iNGby2Dw-|}Lo0V2RV@;ob%TsOmV#Mh^+ zb|lXxa?l^gV)M=D_~JIS!nug&&JyX(bu?xu`9{?&_|B#2Lq7UNrZr6;yIIump9osdEPi(t^KY!R9?2`A6wDub3b++7H!I_$3IwDYv;H`&wYJ+&7Yk_g z(*=%Gjm2u9tVPeW-U*0asfT5g!d~=qD5!N^FKdhOFCM?gBFUE>E~n3XG6Yn4dFG!T zC*vR-Cit>oU(4xV+3t`cLB$PH&(6q$RXWvyZWKQO$*Dp|ffrOjW4-M-22&Hi-+&0` z>Hpz)Fk=v{gxo)*FL2snERHn#%cN-Vwo2tdBmVKnXsU}Sk9KS)$1-S5gt2t`A&wz% zUDLE9aa8r0(eUk*No8-slqIirqn0ZNXM^PaMGnk%n#Kb}x^F6J{!g2Zfr3qEU{ANB z8Pc8BQ>f+<9n#hJA-(3Kb$;WKxy>W|lSSE^ErifvZAd4LwT^Uf>{Gt%AfTgrx_eg+ zgsw=hu3P$?6c}ftnn}4eT|G+_sN;ejU=eRT4l3#4L$Z5MV_VH;gpH;4c+K9{boVB% z3Y5K_gj8@6+cOy65E5?0&EEY1bn81FvkGXt^G_z+nR92l_hAU&C&^n?iOwOFiv$<% za2j;ItZT?v-O2#c!H+uLoYJQ*;Z z)Qgi~fxUKfJIMai)Yd#=umWXJ%mQs>3;_$)Db3fa%@^Q-=E$RHu&Nclea}8$8PC`HJp%jfdYcW2q(vH7W>pvI^vRgKuACa&IGqKt(cITs?Dce<6E2p8v3* z>}%F)UE3~B^|YguB4gH<6tNXbF0HF*8q30*+DYtoQnoliPY1A(Ea^yqV3g{tXkfRH20Pw68y?Ke;a6k}cmNPG! zK1;xA2!mN4b*ze%N`SZV{@uR_O8%FQ3A2AbG{jsn*K`!b+-6HopV=C z9^0qk|4LTwYgi-PUA;lf$Xn!p+muBb&B9h0d^6tr}ae*V$Lyzgx>FjQpKB zy7EC}AOilDa>b4R(}MXVFWO`=c@HiRFl4!-ck)^0)B6%FjkXUqs{RlOZ_h$P4i;DM zdONw)avvx1U7ttVE_fi~x*Khhfr-&>1XyZ>ps6a0hO}E;O$Vm2nfLrf6_ZwE5eJ7e zCuCaUD|)7In}M<{||F-9TnC4?)|GsNJt|nAtE6yDJ>---3^k`A{_$?BHhvq-5t{14U$8* z48y=63@|j$#?SYh^E>N2zqOuct#f|sxBu7+W)ZXZ?EAj2`?{|8>wQg{Cc_pksQm89 z`dnS$&6l+$-Z{O^_F2%z82&`J-+tahn|f)mpLp8|`q+7J%UQ*6i8`n6_NLoYaE0C|FL{9YkA!ldd3;*-Yqx$Fd&>`{0+2Tk{g@6LSVAi4alWe!nSuSmBwrZFvJ}JuwUKu%6zI(_ zT&7mlJzr^CN1kH1h6B~5OsJf=%Q2W?Cl`s`>?m=xaK1AvIQl1rb>gocuMAFSD0Qq>_xZBQtpt)Fs zVNs|GMc_5GPWvoYh(ZhvRtjq;m8Hxw{wy$ho`$SS9(_~wlS$_rR)^v$YqnbF9ty{6 z(%ep|+zKC{PNtgG;_%Ov{>a(8b_DbW@qVMg= zs6;qwe=%#~l0~&C6eMvT-K@wAYL2oHE&(-sYP%F!6D0N#;3mxs6+! zb7j70fO(2_Z3Nz!k&m~7J6*1YhZDy7O_gsZksQL%2A?J2d3$e8o7J$S&Hdj3zS~XJ zQ)Sd`wqr`uT~QUcSN!KF$DDb-Ro9$?)N8^zfS~^Fi1_m;leXu$wvZyy-n$1hK<8pS z=dHeT4pYJxOUyywSwsD;+O4a{lJ2PK0%X;GFY#gh0`@}3N9l)!Akw;Phm{e5jU{Lc z>R$WBa%#&W%vYJsZ!yy#^ON0~rzsMCt8WUG{>{&T|Kj55A$Ggbw??wI{YA_b=ap2; z9X`xy_*1()U_WuFKs)sCURpuv%9kOM@ZH29K!B38`v>UbZ)Nsyfv>Zv(Dc&QSE@x0 z-QgbSk)!T_s~>kw3!;^%7f5{%`W^sVB|gsAfJ7zwBGOkaJ;(tx@{ye1@v`KTLYZHy zlGWdKR;`Q&F6Ex2EUq6^?UC-T@OEm(QTl{~0i6GGcR4=s}D{z;{iu~Yq zvXDI6A^}L8vv2N$+>N<9UWT{D2RLJmj)+%?b2UJDGpgd2OQ96fif`^zZaIqu0rNXf z+eEbcVyDj~M;&(31RP1azk6b*hE(T$ggt@Da_l~0P5gr(0Y}cX-EcCHb_$jmm|dM1IBa1P$~fR zCE+I}7D-X9{9HLrU3tJ6)3wtfHA+vj;}bG#YE&CO_@g{thydMtue!GQttF~zuV86S z^xN`jB}fMgDKZ!(j}#pDeJxQ(HzlfKQE**NMaZlB0#Y>DYC*6kI+v})8?PeK<}3}C z!IZ4;{RK^{QRYKy^)EU6z4{Ox+l`&q8os$LHtti5JE~PHqgRqZ7Nlk=Vp&y1AIHEH+lJpbHfjNFvD=nnuydaE zJQ^uqHasY^VFo;)QgOq{2}$ZzkU8AKG(-Wntu*c7II3cuoJO&Mtc6VnEdLiIQq2R1zNap z>F6ES?@%blTGm)md+_xcy{IE0d^!-a_i`R{J(P2hS{ufZ!`+l!Ad0xF!`-n@py)Qw zRo-t=>VL3F6{vkJA-6X1*oL+k>N(;Sjl)0+Qw}`PL`3?FDL!C)=o>$So zXA{;*4GXJbf?^$#0*ff&$J!-1)&Jk)){U=ue!}wJgS9ItWi1+L`}?qzwJ{$pdD>h8 z+Hc4bd&5Zh_uz#m6I&}}GX@*g4_qDpP>E$~`#G*Jd9w>gF7KYDc&l9bj-)w|)cB=c zP66aOb=2Ee!6l&DL5Hw;?V?O2hFZ;_J(X_&o%>Kkxja6)LnT*l&!f|BksD=qh+g=O zqn!dtkdY9x<`~+Hza^-gS9CiY7&^aw_kaP74QyZ%H~(wWIR?>{1)6+{a40d7#BDww z^oF5UIG2EI;fD;H^BV&DKQYB;Hz&M5$)px8{Ly>7V)XdkRJeK7pO&^MBj`vj=|p^a z>t4lP9`bx;0;n|m$LHRc7%5_^VWt(YDL zS?$=IrQ-L3OCo4DU7y793px%EHx`3;m4oa5GkP7a74cZK=zw>uh))DB!1?-r%U$pH zIFS^r&ny7PWqw+xRVD!Wh=+}sLV!uDeqOkoiZMC-mBMUWgxGxN$4Qhw)wDuKFH5Su zyZI6(#SvMp(kqYIRN*4GQ?Q737dlEV*yN^l6w5^&x4oEdA~4JRQXAV8ejjCk;)4>X zLJXD;6-mzyb~B=i`5zZaWThz|fs<_CY|QcQ%mvRmOQh7z*+WL{|BuM)z5M?dXt zji@~S_T+=+!CQ9vn^YqDLp})dsa+tjy25ht>{DS@Y`TC3qmgk46Es7dOwZ{|QxQO-(9~GTz)Ho^Ev_ z&KZ1q`A-|5>f?{8G6aZ%B>>k3JX+1wR!_T6GRd7!DPV!k7axm3(Td_z<2*r5DFR6h zbZ%NH4SLKUa;<}>!rzKcl5}%uV%ZMd#Ovv}QNg1tliyt(#y{}uq<1g0Rx^pa_g>UX zc*mYP*5Eoy@jra?>O?oO(F%CoZx?$)?iQ)}0+xj>{Cp_boY)*XR3JxNW zE>~Y;c?BEjFHJB`Ee>BACwsGK$$wBeSY%Oc9Mv}LlT6u@onmvwwZsn)MASEd3|MC? zn(B}j06*w7WU?B@;QayOrJ=~->?2)gpJI`JA zKx5of!YX~k^U^#z1;a_~m+Q0RuBs-E2Pjw>u>l3lE)}*`u|jn&C*HU3C`q~^LzZ9s zh5yT-cQMfa-@qAm^SCRyE3J9IrqAS)L$QEVD>xqX39~#d@)cb2zX#{eRK}o`aNOFJ z@lFE|?a|{#5LVGa#1S6~iyoCHflE!YN=bL=(z->di5d}4&li?}2*3Jy-CXG1UJJE+CyezBfL>jzA3d0r5b-wHS8Fg@;N+1_pbw?UiKXNOPi27!T1 zs&SuIlGhV^;cK9OAFD6&U zJ)>JjTHDrvx;j6u=(bDbH}o@7?@WKY@{NCa&NX!UH3djV@K^Y54ZXRD{I17x=pz02 z*lV0}?I@w)i>T(BvWv~(XSD_tKKglfqq`<#0 zmCK?S$t)2iQ+F)-Ly6pC(KRB}OZYdwgACv0^JmP<1uxg~QQ~46o|ns5ugD9MM2VId z^siB-_R^WF&+tK_f|t3si?3_7zQJz0tsi{Csmndd`Bd2yCimVwS}#M71VA7{=PIZQ z$_Kw)a-W{|Tf*4cJ=CelK!KGeGAX)gqA=63@oC#6eR?3>!-}E0`&ArZ zut(gTqW&767Drt?R0WJS|0zils{U8SlPd9_c0RQW>Vcb?IK4f60|h^{BFMA;vV!}b z&*{Ui8L#c7TE_&s4|BIW-3@uSl3)iz`pQq&7vhle1t)aEE>Zl-H_qJG@wJLlP{wuN zLCbljs{VC@<<$|EZSD%l);MK*NB;`T73%0qgSWh?9P%lngP4^QuHG3a`tMuJMt1!d zSh##aErkDSsqsA4XBuHpJbA&@cDQ!k5CTrB`!B3;*tC1+p84>EZfB&$d=)FurWt7w zqSyW_(qgp%!&auve)SEla=&l|M?9lRdOg#Qw&UX=UgK#oyZw?6C!c$5)Yv~et2-wA zX?rA%&68Du9$)Z%ELH4SU+ghVn1pgJ&|e&l))wgp*>b8(#e>>Y9BqAK^@4@K9P9sV zFXsj&og}%Eym2&|ShPw|eVUP*a6+FK^;KDsZ z+;&Z4P|t513MC(?qKG#xDgV0EQKb~p^8E+E{3HQmiq-gC6rRYYFFCVrd&vA2cTBys zF}^)i9EB&ZC7nao5d}%Yc`p|oRz(vmjCK%>QJzPS#|4*vUO|7Lnx+>igxj2;p;jxM zq1eZ2C7}z9hr@k#?$fOj$_IZ9_~wiN6woLl;2TQk_F3r_ac3-Mg1dj>#f@|sTUu-7Bg*5=*ENz4fJEe z07J2oPH49L^>a!`zb!d&OP{ujEb9yg(_cK_v8)Z)5rrqYg*45^fXd1rQrvudhy04C4({+7R&M#b_ezBg)#;C$ctQroWkOeUiqVdN_nU`}M zq0GTcTv){f^vJqg2BQ0{+cF7HXnQCRE zxh9%)?x?V|Iy`d6fdzV9fu2Q)AeB7qaz6aiERLB5K;KP#7x{K+_~>Zo6|g+cL@Csp zy!5OOI3cM`m#wDRz_#4&M>t%YAKr26GDk6L##cP__i6j@tjgqyK+X4sY@Ag;HBy{} z7-VR8DvN+47CHXX6GPeD=KBx*NhsMwD(Y}6c08F!M|a=;c8`K7KOa2xOm<#hv()FD zT`acp$er~0{nmr|16KwP>7020MO4dkbT((BXM{-06ZJqwMlrYaXXZSkxJ&m2ogK4= zaPu_UE$X-x`fLZ*#p-+?9TBMfCDJ*!Y#yojC6darJ@y`(yOgN7S@HM#u~#qT{iyu? z!C{1u_H^sd=N^%;EP|?G%c^B-RH)vbUvGY+%>K^3Tc-i(jFPPz9}%yu63|++5!jO% z91bzyecTLH(9!dHxB2P872tMvBL(XNPaS$H-nc`ZMz9_Vaot8(pZy04J5Zrh)3;LY zK8_5vcHpMZaf7O_#swPP%GiyXA`#^Z&Gy9*hEV?_RxBfoZ?tw? z`MqXEdBMO*!&VT=%OtI4443L^=I?${!K=|aWuH?l#cZ|!TMhvB_1U{!f~Z*f_MW_I z=o_Ni$uCOfZx9b4(6!5$AWqiG0HtWEzMauKaP`t3Qt~LFsk&*K$lwx>z^_a zS^!vjfg+Y(9*{1ZQuJVFQ4u>^iT00p+G@je(cx)oU&1P+37(PB4j6yCFqz6ccDm^; zuSb)A(WJh=%yU~=lk!8@@aJOXW59$Jj}}BS$FtuLTA-{EJ@0f#Fb=(L1v9T6UecS1 zYo>6&flp=hmGZ6pS&&#KO2b((QK`&)%CDUA6|bIGkOA<~6LeC6ixv}jZz=#DD*ROMNhA0-jZ;ukw4fqM)0Z`yj4iZ^Z^#rtd7 zx8wUlGGJ8Bbh&%#xOvuxOHuhHSBe)1g9$|i?AJppNJP^Z?21>4Z1|$S`2&gp<+1XH z1oRo4FUIiece|1LsJ{=F(XbV4Au8soY3N18SI^IQ=eKpekbCm(2{%URbpL33`b~CZ zFLnPgHz^*I@%=mhOkRp@2#tR1q!ptWYo~DqP%63I0EjKPMQZD0^XrA})IwNMm!zvh zG4VWfMXkMZ{c`jm=2f{?7`TbyqmJB>s?er7e`Ryh8~#GX!=*2jEX zZEv7nv%|h1cAE`v0`3hsPZb>qb2zH%eXx}^U*JG(7J)0RPbK5)F}|g^$60}zrpA9o ziolhj`huJ@p58*9`&o0F$sbas%ThQe9THs@c0?RvkkdEDEjZ|PAwBj@l12sj-(kvq z)(9t@xHRaGJEk|bNKW~l8!lr!mLc`q{~17r<6g~&>L0`}LI#_{dKCx&qh)754yPZs>m2Tmi)ZV!0cdFtd%4uX{YVxuz$kocqpVX4xGvHH?FhO&c)u77|@Ez^*I zGs?FG#p)D)J56ETiqP@lr@IUft7_%4E3LNnpBr(CxwJj{KL@Lq|07cW`bz4&P-3p9 zytv~-y7{SIPL-KWDYpbOFu4T@Gbd?shd)72L@pIjo+q0M4C;3{QfZCI^^0(GVR zhmX`gD6rw5rEx%hbgZ!wR4%$Z&;CNt@k}s3E#J7`lMjulX)w6vrbFEk5c;+Pin(#N zX5@E`&b}x24*3X^{=u%-_4VDAvEzbna$a^+1HP`sT@iS`OZ=5s{ihC9yrLRjvgi`j zIz`wnUpvOChCU0Kqlp=E@S-!FJDl6Tz90Kk15qEKn3CrhPLwDGj$3J8{)bm=0XBVnbcSXKJ zw`0Znx1?n`HZiEmQ0pN99%KOemG*&w!z56kaI+#60xqAB<-pfTw z&8e3T)Bx=ADX@nu5k;>{@%|;OU{r~JZ8abHN<L|pd!6vSps{;@M*)tB#}5c zx=RC)3?7Nvvv<8LAXYFuX=Cy7N>|aQK4oR8)ic3XAqscGvB(1GcOW!Mz|VehFpdZA zgdJJ@oX^kE*xe`$Rv5?B@hmO;i67{q*Vwt2*j_MI5t-^Bq6Sem_w`4;qB?eZcpzj% zv}J(S054URsr}pVI}c?4;wSINq%bc(vUs{&l~aUK5r9!AFkIc8J`k)d(1KqHX6z|% ztVk}HL>YxTq^Gc^91EC2EJU4Zg>vQafB8*!Q=}Z36KS8RiOY=UPT4*WKYL zw^H90x(@GN96!`?!6V{;#r32rbwxVdQGlqXeP9>|LgGlydEHeT^N*o_-_7(JAno*z z{@b(2=8w@NqwHEy+2s!%Y#s+qFIbcbS{?jen0+<(0-4(1Z1c)fMkKJ6*Gqcy@Dt!* zNM%6bFULnf3tqPLGG$ftdQN59$M^dYq;VB1Rm?h{K#8A%S^mT|yMBVK&E+QTM)l_f zFM#7BtZowpGx*r(8rQt>z7_(-?szM7X%oUz7^NNB6@WzYhOI-vrQFf7yZKu{IXime ztNkJsm(XJE)OMnROw`CyXJGdfK{$DG}keIa6|Ao{gUlm z^j#S?P>+);W^TQh8+$ReVng?j{&Si6>IfsFcZ}GqD69H{>HA{7Xj7c#;&=z3B`4N8 zU+H=AqwG|yYF5#Uz;1|6F=zyyaMJYszWx*Q9V{((4LHo0HVadJcIQFX*lI`dP8+fR zq7HzXIo%f?Mi_iAGh|ExHFz>y92oYAsuq$CpI)%aSkx!G&F3Io>5i{E8{O<=s+V<4-aP36m4;=A4@>X5_JkiP`Glg~h84KeNCc%`_Q_^rkFKe7`Wny6VFrv^XCD$*x z#--iber)zSjtR%7*D1`e*NG*^SbrB}!KK>$vs{}pgRX_WC>aNE6YLYs{|dR=cMsuv z@0WPeBi0PK-9CZYGKb^FD9}DIXctP9T_2VgJVC2%92h;hL;GuEzdyBS^YVIP*W`=l z)d0sG!`Cf%pN6@PqlydOs^s4E$I;ti8)Z8My6c=b zBp~zP9BH3O1@SD@M3EGFheGwyhpaSBMh9)Ozo#A&?LR)+UQNHuLcMmph`CH>q6VBp*cMxr7xZ{o3jslO zw=Av2)yaF+_=BsC$6nN{OuC^|wJQ$_m_HSD5olzI+n|+}G4*&D*IpWE6iLjU{i4|| zHu;0@Ia*dG_q_IPd2{!e^MD|v#Q%H!7qeNI&v?C(=3DZN3T)~oOaCF;o8Z!vtiNtl zwyS*^dmi#5g0AWW=~T!uQ1B*5xd&(l)w zWG(z_^M1LkS35f9?%H&2 zBa%F+dABQF!`_>PX3FT<2TL4xVmJFagKEPOdLILxR4Y&4?DDeDXh* zl}wT-dq~jI8D-S^wZP7+(T3)IN9X*Qsfo8K@Zl1$z zVtCfnE1Ox2lzim-0i|vh;+2xP@k@~dNd!N|cu-U)sl(L(Ae8BglF(KiI5aR@+FRh z0S*0Q&DdQ9*-N&w`%#OO3i`#OFvw;{BBX-Ap|@OpcJt9&VH8>Mh>G9=AH&MyAa`S< zs1h$|_GyP(90ZE!XKP)xud88Kl?0pMwSHV{vgjykq6Ss;FviCu z&0k}}srcmW@h)FNe6ll4WXjcLNjvfg;?8D`_6))O;EIc0b%JY2dAg(OLXt-4U zx9DyOw3|2vu~KmkNErO-el{J;faw$nmqI^iK;rNGrhYP|(M96pePN6FP);$W*zoN^ zmUZA_G2J7a+}GAG>1uuMthh)0Dj8(@mL+o;`rv; zqzz1Ia@zwAUXkTm8MOnh@}!;xyX`)?3$5BCe0_E@L`AL($_k3$yXbqk8Z~ zE@4ZZ3m!$BBh{N@K7P3-nt%-()x40$e0g9x@e|>L)Z-;&;hl|u@p^5n4-s|qUmro) z{eDI_23(6iFu#;y@ZVIqjcfT7`Xv1D*MNjbdN8}o_3i#LjtS{+F#nBX15-3wY*;7* zdCqeUCK9F>Y%HW228Ai1RYkT-NB&_gz12+itK~n+N$MR9e>{2rq^Qy*!nWoetLX=6 z^e{iYLM##-c0$f~MAD<^wBpk2w@^Ol$VhTBHzR*+H>$>a*I+E!b6Y-r^(x)U^jc)e zebYo=(CY>2IU*kXAtinQ+vUPU-AFe%x}tH0g4$+I^_6V4fNJy?*QVvuUo&+IKfc&2 zm?j^(s3*1MlzsVX5M{ir$hC?mjxm<~n-3Z`Bb7~&4r=Y1O$62;5w)nBuH*#f+jqvw;Ebr?h8{b5l z*)`|G`VrJid=JZGlnqv!m=1&i6*4Vd`z~IS;Y}Ty(jLhZ13ZY zJX`x?orCjZElZ5x&}E*I7bTEn>lD)^k%x1&24ZEP)32Iy@vn_I4$$YJJ;gi3h_id| zxvn6upfK##ba%|Ug$oGQLSLo@0|U3iEJVNPwuxJ%{RS`g+(8&}lc-#+DO37c*Bw@{ z?yJkjFu+HvK(EWjUspi{e*ZbuygzBelGe1@9NPAw9zH>#+&4x_;X~M7d%@^5UgF(L zr!MgWW!-qQEj);C(1&xj?&w}JrfeaAcq`4?J$M10cRNogDk$4m`YhHYB4~#8*sDxk z1vxqD$@8aj_jo2%_`nPr>|?9CS2FtMV5Tlm7?nadc=FN}#FkzrG!?(9=@?bL-_v0R zZF#Ke$2(i)@!{SI(QmvxNm*<`N8tyoQfwg=Z?*x`WVNTjg8Sp5#mH&N{`BdI@yUha zxn=BZVH$yIf0j`YP8&vIFlEY7s2PSTAgYwN2JU>GXvOoPeBWNLx2M|CJpjtT&PCT( zG(q&Vk|HPJqdoeVV2Y>Je-XL%(^UNRa(sPEUntVuS?^6 zZDgr3Q%g_Y)S&gPxBc^u#AB?yXLmxKvwerqE`=9YWK?5#V*mYXH_NyE29IW+u~opm z5x>V+PM9-ZrBWcb)DbG}ir@8=8TbkTI>P)gcXaEZr|`~*T!g6Vv1__xUp6xYX4@h; z2^s1*dWa&-Citgr$BPbF4>{uGo1E=9?bbA@g%5`&QY4aIpG$jrob9+464Y3Hk&IeI z!^4}an@cHg*XPbA9}XR{<9IY%Qg}~3!G8XIm3s%Sou1mqHj_DD7O}88tE^0y$YhEh zLx*$g&U>L6USfT9$6O)8J>`n$x}o;E#8o!s$#Q?UIAxLIBsSUd(>zkq%j4mEa&v@gGp25%PRk11cHZQ3U6 z7F^+Zk~?Z{Nl81M2J4mb>E0`0p(EENU?BcpSUb|G;zTh`ISCnWnWP}swY9J-law|m z$5zP9@sO)BGg9P{6~HX9OE%%^exHHFsd}HbsTIv5_Uuil!c-a){(Ox5UhKR%mkQUb zar1#-Ta0eb#TZ&L@lgf=W#e%!a`kA&)Tt0_mffDu$Mr97x&C5dYH4t@bAzwssu&xN zxV^uXxlO)!K`t;{7pdE=Qgdplk0GZ%lPx&Hb;KZ8SMl7Ikt}c*r%Th}+=&-WP_IoB z)9e%y5^74%S9n8ltbW5Z!}E%4uBgzOQ&P&l-xI7Xb$XgNk?&NjYjm6voos5!IVPcS z`baHdq(xvsEJU~;i8*YWM<6g4g!fyQoH>BY8I!jCbJPu}UE$bnE@Y+{*CMH{NX?)m zz^)VDDw9`C$UkQh0$WX3iNdQ+&S3o4MS$gii@>rnesmP_`Mvhh<|UbRa-@1qH1Tvr zXzvW;&>#2#esbW(1Y;=6nW@Mi{`Dc{`L?x#A%S_-cf_GPDVb zR2X)NiW6G`%&9ray5C#TtQD$HU^yw{$;hS_zfyt77Euf0bl>DJxG8%TXw?;cN%w>K zI@LkM^MfNK+~ni&%fCD8!~YJR{f7ZeE*P-m+w{o#tAX&SkgDwm`;(L;oWy|(HI2kn z$xPMU+Ey}U43a%L>gFuNQkWvuoW6GHW3y`F@i*kbpgB8>#DS5xkE<*j3#6;k9koJ! z^(`xk#*C)RoAwp#D7Jq+_g%nqA0$}~1^upLkU+XavI}NHN^y&W;g7UvBw|NQ2_gQ75@~~G zE`64r1yac6?vQY6n{M))?eNagzrD}cSr&NLl;v3|Nyssm$1f?UdubN(ZJ#$G2@7e$B0yx zWlBKS8)rqw(0=pmzU$B}H{iFU?tUgXxXX+In;TdKp5C2kfD-`dew74pR{lArxta4qTfyyV6#EU?|GaPlBBA>uwg;i8u)3A^47#l zuzJsnj7m<>&5?LSRdO(HakaiQh-%-Uw;kJQwKRgg1E%monUpH3(FMP|OPFQ{7Q6Mq zp&2Q2N8`}-ocuaXhIa1Sg%(J_;1|YHnsneI<=&iU@6*NJE zI3pk9YNtO7mY+*+a=KY2Q`kO6ya#STwnq1Jc^PdN!s>}Ht*K^ye-cN0@JI)`RTig| z&&_ANyr@83%td>#ymK$1gN*G6JK{@qopDdg#>j%c3s?zi>NEc$@#$o|sRv#HDNJD3 zx{@h1XXMmX@PRafvF&r?Z1qSBebuVq=~uJlsuSW`Tj0SuKgHOJsx23R@IJ4A?0DK6 zvTQUZ0n2IcHSN=nuB&J*)r=P&#zK+dc>M>$vvg-GLAf72A(_t?6_BO~$>Ho_qTzbO z?y=vyT)OaZ`?yyn4Nx7V+mEr=$i2n*Ew_h=;Wbymp^NHm|(+&TCJXJy?N41joQai1ap$_ua^+8z<`fr|e`%^MpZvk;35PesW@2Ch92~ z5f+q58+C0=eAvx}yJ=&IZP165B83qa@Yk4H`0>KJyxC#8mg^PH;>gLXnyJ1Lxcbtwo^wBvcpVWh`MsvPRkV?pLI<{tvR7UY z4kWp-?pB$FADImANtk5K$*bLm57>L_Fq~+TEQS~n{30?6KhcGHTCps_)Tr#M(xx5Z zEyK+!L(#<;#{S-erA1o$g+x&}tC1Qd3!LGw^S2A#IVBPwW5HY|H0*F?1Q{gtfUbAbPbD zKXvrL6n5au$%9|D%BsW2EI??En#xf+Y6jvKJwI)$Uk%f~1SP?RrK$3EoYtpE?XaN; zwzar{iG8?Bp6WiD?K4C3xV#rp`}DgV@|G)UnVzB7)C3&UwZu%Fph9B?FTTAV8`3jU z)K5iI%S`z_uGO;g+IUAls>q>R=D>kLB2=~_L(&I?^l7!sFkL{ujlAjkyr~f7rKG|$ zJNy=gxx{oh4@yr)cLw)vDzLF4my#o`KH|tQNh!#gFJ~+lkr@fb(7`_H@u)kac`pgx zk2>eFV|V<83@h*J2-ehfVn)!}Fy1%452hfeaKg05B_(;}_OnkbIhK@-yYPqam#5t1 z??!1W~(kOZnr4?sQTT2*@J9zi-o$=$h(Mz#AUYV zQCCyVQwpw`CSJM0I>HU5BUlzDazQY5mb;jzRvS0l#ibgrEyu9cB;{c2l>ZH?=u$VBAw)<=hgUeyA>(2xSBe}ID5irnC{gWe5HR4Q zS4Tal$QO>q{WzC0Sr|#CNpDZVg>+AmXlwNiM z0u~;Mq?{47fJRP?Jsai(^(s-~>1avY=dWO9EAZNuUDG8r^3_oZG2AbiXT+{mKlP0| z_S{2W7&w90wJQW6t6&imngo4F%cFM;$fw7lpH1{!z*XL1O}=#7D_jj@^HD*zBAqB& zPb$4@!O^#Fje8@t=hJtCzj$*&XI>Jy@OZwccAiEYRd4=dgf%37rj_F_PI*}t9`Cwt z&F!NVD&>_-E4XPs^^&5evYj_qdO$lUG<2RJ1Di4LXHg);RC>O|GQ1EiI$3IW-%1hd zA}w#r^=7URVW|M;^Nygn8%RfPM?H_YNvOG1cW`4n@y@sAeKar>-(v!3)CIAbmy=CT znz(%LrkTQPlmEXg*#DEk!2jIerY+N+4J;V_qx*^oX7OFG4^|F#I*R=8h8Ka&yJS7w zyi>iWEGy(oR4@(;CtjrrQTKCBo=jR^nBVQsn=)fULH33go@nv+74$faG#&Qcp>K%DO*oovS&UHSE{&^=ClPsKyJM z$DUv@zT#$zsisjQv+s8wZwpx1sS7s{a=t_zO+&`r zzJsnJdIp=@um>^++Mbd=7dQv6zky=f{(|MzJME@d(C!D&?P%ym#qmGxfZ4M53vdJG zFI1XuoDRrcE`~2D!XT`C8j+UmBYzur}zcW8bJ?5I&sJ-wzgIs`IK*1Ler zx<8U`zdNU+mtm1U2lIIWm0+ln=>;q&W7Flk=VyjCy7m%ZI$xH=tORMP{e+RXup>Cz z&d;2u;8S061YH}8AD!PnNKYypKvu-MACS{gr2gix{oVSOVt|zND>QIjOTo75MF##? z=jIKm3C^^$Q_fuJF~TX)No0@vmiuo^0c2vr|)|a(?QW z;@q~_U4$bw?aLWF*)_Rx`_Rzu&jY21y)a^TUs6Ngs{7zmpG+uKp?D%qm?y;Wt2!}8 z@Ve{HaowZr;DdpK^akgLN)b&`Y?ACOvWGyJS7niNQJP}Qkp4PQ=k(|)D+^bSlvN|~ zEu1+m>Cn|_J@wHblh?!4k=j zwJzvY0^MRw7K_~%6^i^>Z#(^Sr=^&#qd%g!BJO8#cciDaw-{0T`Ge@|++YhSs3-GX zpuvs1g`aNree9v`V9M8+stp40$)ve+3w5=eku$f_ivffcMxbW^azy1b5Eq04f$)dD z5iV|eT%*OmH^U8BAvK&CcS98|=$W@XR-TW<-MTtimJDFWP#VFm$~TMZFXc`sOVy^d zO_S|)h2+aJBU)ogI|p=6SM}R#MSW5fr%9@w!zgi2BC;AP_^rO{88C#pF1KG{CB*mn z5;yzCHPq#x(CpK7SBmLRy~E&bISG!VQ#Adpj33TfJ1yjdGwucelQ2+VS1(YKg)hv9 zzf5q8JaZWEB`PhLAZ;!%(axhB>Q-@&OK)U(?Jc!O`1vN+6ql!4wK|*2mfR~vwFnwa zK|LC9#5q~Vx}~V_>zk}rG{cM4aO>(9+vT!^dBF%nC(~2jvkgZ6!to-O%QcO5yVpLg z>29|=X^7;l#g3=UsuRy|Y|-Vy*d^-D#wUj4-*_t=HLYy%(rkEz;daaFo8&`-Hy(B> zQT+H+_I?R}BjB0oHQgR6L6~Ij0Xb5BliNTTLZu^mP~G!@etlT}?%tAM0Oj77Wmj~E zkekLgs+?~OOr(6EVfsDp-fofwM^U3vVzW~_@_TysMpnzRnaUYNvekICAi|Lj#>JCo zK^0}v%G!B(9twV%gGD+l+rtOpMg?5@NBw=MS`&~}tr1oA7VQCkn>(RjWFq zK|baCjR6`eFT9Ljx5EWYO?^7@KZ9?^^qi*#nwY$dla0;eHT{l3z4I<|NS2I|^2T?V zvZW_Um)bl#KNNKT0z4${7|||9Ck%quewd$*7L7YY{5evKZnpG2l|WVx1?`KZpjJ1g z`4^m|Xc~x#`yuGw!YRjFwEE}@%vGJ(Hmo{U%(So1FWwJinCCU87SzQkT(2@wRmPNN zDpqpYX#ovFBs$i|axVUI)9XGL=uNC%c!qwbu@^30a00>o3c_veDINKwwg-KfRz%>c6hD>+U*p!EXY~+n2(Xn(^1C>)Rik z*HMcVeE+?+<^G*^-|ul2{Pr^7!an+Ae=L{1p(bvr%ZYHfV-?TIwl-I3Bx~6SX>x*C z>UA~&ZCM*3n0aabrKrNaZ0HwTP8E!MrE5h2GwlOUw@T}*?0?c%uoC%cwZB3SGC+m! z#Tfi^vjNKK&-`(v%;EMH|EUb>{zFgxwV&FzOx7KTn2f=<0wLx2tq**>x<>w}9%J=g zid2z$J#JVq_twaMr*kpPbDV{BME``fH}B-+)rGX2q+Ws2 z&he8&FhS9c77as{=)KY?7|!!a8Z(W28H#+z$@sF5%$K>Wlryf8g|VZT8kq4_+rryZ zx%@gi{2n{2O)J5)K(E9i#@=$;2#Z#TV1D`SjbPK&A`Qq`le#TV*PA=xAtY+(G!~Lt z!aZYIW4Negsqix-{G6w#F@0uhVM+aTq`|#V5j<>ltW!q+rsY zZ)!hm(LewOW^^Sqk*1{AiDvyVvujl3BD{YdP~P_PkLs9eRdOd-Z@ehq{5@f77%i?f zlWgnE-QH!i7_S4mOHP=Dgjnc+N9B*w%@C4fkE@9fnZh=2W{Cc7CSHWf0YPZixbtL< z2^*z@B_OosFyuxWHtSYCDnO&vFXE&;%+Hwiv2PsQn0Hzgx|;v0)O3OR#n_ z4wpB5S@mPXn@zl2Dq*{PB30*qy!jOG2!cPQ34SYtTIT4O7YnJ+!&oO%fLxUg&EG6l zcK%0sfUxdZ-G>I`?o#wT*tCAM+Vll8kq*MI zs#KRplgQ2|y#D_Gt$n0fge8-(CBQWP=lDPz~( zr=`M9Vn{k3UdNXbvv?C;dm6sP&~%CT3%004iIqYF;t zqI!N>kjLG74CrOCs^4LdsJlwiPk|o3@bO|P^b0cu6Lb(Q1INmvaHdGDt*}HAvzKnB zsuL0-U-b+E_m}j3QjrVP){e8?ZJu6K0}XEhEb}e+GDr;R8jfweG0EP1hzfCtrhnL_ z`TECmEvh$FR@q4-5t>}c4&h}t(HOpD^v_1H=iH;FsaCgOx+!Tt#+0(P0TQR1HfsuU zcIshcP39r9S;FCHPGt5XbH-6>!9}D6)}T3Jz=V{!YM5*!soje)av?JCz&C93Dm@3c zSi#n%FDwPIKwXPB>linzb(aZaG7g&go$YTF{X8f4*q61Q`N$MJ_3qxHR_@0yK8n~tje{fvcV=omC*{Wfwxn)>)6u3@xTWA}3G?#sL`wVbD{wBzWfCw7D> zLr;l(2CEIfHL!C9-PYBqPNV%8iH4Ul*DJhR8M}$rD~qZd8UXSdOh3)1Rr3*`qKCBr z5HP;LHEx(p%Mh;-F{*v;QARB|sfA(!wc<+(KMt~?xHK1h0%ehxIdk%Y%^Uu` z{WL869U=O-H>3V$&qDP=NhdtAy8q>ljpV6U6z+|MVfm1}XKx1G@0onAvBX>TX#Bwk zOKukGivin-Uh-q&MfnU`_+xyP%abS3#`Qnm2_eu99j(QHFC#-hT0{?;+x2{3PVR-ZxOSYK&Rv@P6yj zaR;4N)sERaY{xC7nig7B##-m2MYXgqQ8~&pz9$@g04bZevOYUl9f6eX7U8R|*{>S$ za5~9p&yE|k!I+fzgo-O=-XgUCP%RbWR9|j5n2-OoG2>f|m(>&yaVosBkBSk}H#~ZB zGA{3X&Mg(TWvn3Dr+PqrtBEQ+8+lxr-+d=RJJyEI=cHt6 zFW_VRw5m^?)=eoyH6X2lYrr*i^?s%ZX~ag*ig6Uvd$}!h(FR4 zX6{PSglplBe-QUSEeUaz6tYv?7g$+qague%N!0kJ#(dW@!!;3F>ep6d7s2BhiShxH z66!X}>gJuK3rV*jPS=NJ-#TR}W*Icqc;Z{g{IEygH!^ZQZT$S9<(boc^WXR`&6Z?c_wBq->Lofjsn1T|g-JIH5;rCB#FR;PXQvlvXSaKG*a z(706tM#x}+$ds~XK#S;{^&r6oh@_DGt`*J&0l;AgV}vuV}piAmNYuzTx2l}bZPXW*M}Bgg!IY@FD%JtE05cl z19sMzmtNQ3co|mLdkhPJznnTs&kO@kxn1rI7EB2b-IQ!f79?Ki(LvfUKBKKFc@TX+ ztY&1#dCQ{gfX%{)$4yamR{lGL1zAzcmIol2q)w6?_bud;g})3fn?cxct*s=$F=EIA zC%c2;_jq^Dxlk889ml2)+Hlh_hI>PvvP;aS z2i=0S^CcK!Q6qg)vUVBwpBS<{WG=Nj={125cBoeTRch{A^SWZWL|AuMHNQJR7C(#8 z_%R9{nz5@ZZYdq zfztp#7&rpYC^k=f@Emkqlbht4#WbsFv$uAsz|-J(Ze1-p5T_w@y`i1(!h0Ny|cx~7FTwG8v`!lKUa=(*+=k(rD??sJF%LM-NDz2^+F5O zCA&da%Fd3J8p&4=(5k}RcK9u8R$n3at@5e6Tj7U!N|>{ozSYGiFuOqh2=z$f@e|GY zp|?QFqn?+>3px<;raQCX%PhrYXKglLBc$yg`q|wY2j-OdS88V5S;QHD!2rHO6!0ny zZiW*(8T37uKId*Y(pAnZHkvcZK*)K#C1fo`PS zgN2!SKof_pCoy@e`P7g3lx*6l&k_UJN{qUnEwHkqq|QVdvdOnBF1DEM#3{&YpHSdY zEeA0bR<4lyUwZDazg1^OY6ym?YJyDuEH}Lz5d?3xxA;e1=M*i(psyFY0cW}FpK>xwAikatxBdA} zEyJzI+&N0zNTV2MF`HhMzV!L-wUP00VhUA*k7`&IndjMwSl`S~`?|t?T_GjjpT0>N z@8~8;8tMN>>SdNSat?j2ba9!V1@iWa=gM+i3L2F~j;4X%MBntzRrcK@>oW#sqM@C6 z^CRpO+CXjmoW?b?YJ495&J|&wgwy_q{5}EtPH_$amLRwJf#uWSmS*`lb2Cfs5bO3F z+D#AVtY;81Y&G$p&c?ykmez1+5OUdGvhu{~u@hA-|Ai#dYZ*pH-W8p=8xg^nL7^L9(hJwR;r_INQ)Va5_1P&tYJWk8M0&g(BcP-5D(TTEmF9$o3HW>8wQaE#vVeoC<-6{ut&T^FH_5-qw_2hjzD5k6Jojtr zckN(9)(N1rmu^;d!_OnuvP(y{pe_{)g!b(aF$(!9>oKXsLV$*AAvk%o?YFA2TO#A3 zBVK+}Uj~6C$eXnj9(Yel`+l^WVBNJN>*Tdf7CL9|Ef&ogAW7Q%bM{@yQuUUe3kgHg z+3nvc<*0t7cjKtf^X8G+yz$?0R4}n!0Sr!{fXzLki!h3M8CytRS(M}UpFB)xPYez@AFaK& za$3gz^^^gD|FXZ>9A#Xy!ob&WkDe!02e|1ld2V17^KS*I>GzX15K)1q;d^Uw> z>gIW|Ao_8RexUW(%;1dw?Rcv`|Gxtu^L0Fuscfnr_6<^>pZj?5z|c73f7{rN2-5$j zHuh^|p>pkq5vBcFnPRt5eEBi+2p=0V^vN|a5|=+8U6P4rJRFeu#3N=a;pkrWy`)Hu zJBuhUr?9nxr(3P633O%q5499T`&Q;3yt0AL0OyJ)&oD&Qc^$vNXQ+~`5KKtPDg&rN z0%+O!1&S0nH}P}ff04oS%c9=se@t1igeMQ|w`6LHMu9D(Us5{>D334CN<*P5(=1}P zsMMkhzazQ|y};U%D#JFbx{GD-I%x(!-;#sEken@J5>Nq2r;wWnM~G?pF0-)sR$4h$ zIsjl+{$p=vqNz$ov|9;#qA0%kM8bV_eHuOrGtbfFIKlb4jZ(qXc1Fe44CR3E14T1> z-{GTqD9a#E>H-V!H;pD!S85zI8x-y8wEZ7+GK14T$1P7CGqu9y2;MvQ!8mpi+T%`5 zH!wg8JINWOKx&PrK^EerF)&>Qrb?r26J~Y{^zsn3rf&qd{A-snHpHtZFt^Vs{Y`BP zO8`XI5dpTckp1npXB3bSgHQ?hvs%aFv2-)8FiaSLi;FuU57e#{o*6+mg8q)Qv}>&w z8npi6gXO)|Es?tDW+~{lyIy4keO+{rDlZ2m4hjH|QZu;U)KxJNVd|Yy8WvMWbV=wFGxx{BDMBr|Btt=aMbL+-zrKmkmt2;cA|+lwI<6D;{!AuT zqnfhxa)+$<0#?lR&HUtW^68C>P17Q1g9R>yqjNZ>uGATsM=QbHQE$NW+7!#hC+UC= ztc{GFkgzqjJ}N`*xq|w@xdNMBg=G`FZh9Ss8|&zWtu;YZ&`H&|`kl+H#0)WOk7DUT zCa$rD&;lhLpsr0q*%CzyAnFAB!N{g-ugsyi6;?lV5L^(q={?Oe*c_c)4}4kuU@JZ9 zRMIc;Lx0+zwsH9;iLi}p_VJp!IrOt{=cqrzo}1e@pf4gE@69sJh7VQu;3NBMS85+F z0haAqpy9)Rrf*^F7rA6IJ*{br&|8DvHFTCYs`DJYd(w(!c&`7(O(aKlN(=TQp;P9xWf*IQp?NX12g^0dEpU(2~v^?Wq8?(Ia;p z&bxIT|4{bcf&IuYQX-GW)2cC}bnf5oyqSlB=xrzVW%6IBqe-bl7xXw90hn;Dpk{2L zrIYxB*DK*QGYnNYWiK(Spr&REQa^60I}J6S1b_y;C}iS?=@Y;c>4163i{unda@xd< zSG8Q#-H?d1ut%qzbl(g$C|n(=rA5MSx#|Uns^TPMF3-28z9Nil>JR>sB3^P}-s>gp zNF*@hAHr4`8}k>v0KMC=d~dQjf36^5SkD=4_s9zT(?&q&XU2mfA?%kNS zPJ7*U^z3RU3uUt~my_lM9jT!Jd zyN0z%b|_8V_e8+;a|5TwA7=+02v=Q~(F}LiK}{JU=h@A3MRaxs2~hUA@mXiV5H!sw z^mGYtl>Kz=MIK(Ag9A_eKYwZ_K_EO4cf(%kVE1CJNFwz+fdv?t?+-hXLsT?pVl;5BKGN2lI0eh82um?N#9-a zYjX-_y)3qPB*HqGSvmL*tEQ6i&A#DT%>5F4LG}7WA)y-q zZ+h@=D4e0Q`R|XPTtL4lvDNg4y8KW%u2z?u4inPJ*2t0u7*y`3^V)01JC=O;3eX>wpwsw%0P@t47`u5>3WkhEZF#|Fe;v4Tg3FQ zY{^I@FD)c)0!5nvjNFlM8F8endI=8k&1mY(*lh=LF8kKqo|p^M?e*A)~@$ zIT2Qn+)Wf?CJysLHIoO*2%0eT*^qph0*dPE3b>RS@H9ds!SllX6$D&UGi)yO_cNQ| zln$_iR;jlDA* zh3HTgZWVO7Qx`ze)#gc6vJgVv|Ch&)$T2{_g*8(aOU}qBTft|fw_#coppVw?j!jp~u5tn- zs=2i%)jst}y3F`P-%LnZgq(K{3XmBfO&zT%n##c~WH15z2D-6w=CTFWZS`({p)Z5D zsj=Chnk)WZpi8W}nS~PR)9v3sp20jUWRLu}*}4LJ=ekO^)Xf-&Sth)6tQse-5iMf- z6wurZdS$Z-7P~&zjYdW&cT?vNy^c+?mZ(ZZzTQv?+acg=mLiV0jhtU!rZ zd%Qvf!QFF)fEGL=Sj+5O@X$y(13%pI;*xxQAPL!=%y5TK0i-T}soPY3FtVaP=#e(K z`|14W53h|db@MIRL}%@j%Zy3FMhzR@pEpx^Yog-&i?JI^pTpja)cU7VOGkYlJa(Gv z(x~(pSAmLH%cf6tWnh=+cOF6y`k*2-Icak%$R+)-R($(DsgP$|C8Q?UOQk7 zht;H{wmB`L*ABe<Uva)-L zzVjb(iDtN8Vj^nCayZvZ|I2Xda+0N_sTX3ACE8_@Id-vfr@{LF^(6ADK*o-!};&n2n3SKNLZZF={2t z+`IR|hn+s!8nUjn5z=OSkU9NnA}eB9qg~?{lKE6aG@}mFip$QyT<5YNAF04&ZF}d0 z>|i}qcSR{O9ma7XYDn7E7~f!-O9xVV`k*^Qii!Tuh1kcH)Q)YGe|idEsTn&cm7Dsw zD=|5NS22a=f~4;mojN~=(u))w7!v}fD{AjbUa6%Yw`3^URwTD#Vf?+AbQG6?8KXJj z2~Dzl2RgNiy7M6I+zoC-A6S8awLl6eN%DGF)6^b|^hvWnf1B%u3YN`i{@T;qGI8J| zmWcUG;{ADM?OPP49uEt8ti)*itCXM<=8vyNIs?)N>;RpQ-9Ry(m5BXXL$i1CIf3!N zoXy^t$+}#IG6H&f+U7*9F2d)DNZ}l})dl%}N%-&3Q0hZ2$kuDVLlo(3@1|DNI}HVl zyg!*7K3fs+o)es+n;8E^o;(Q-?{9YIO0+O-!($g20*~>Ado$@y?%BNU>hb(5w zY3JN;v)Ck)d+#$viO{!h(uQIqCxP#tUyOY3UQ26DU!8C6L0#&XZQ^d>Z1zk#l8lHU z4PrSOiPHEY@5bxKceFM04*qag+$=kv0cPE|lU9Ft;O@1Q`#`!+ipQ;~Mq6_ZHzgLj zjN6`!IBrJqLx7S4n;b^$4URnqnKaZPfy;KVBZSj6 z=izq7rR!#0JW@H8>F&jVW7tiXha1|uL$?dRPukOm>K6ymcW?dg51Dpf z9(o_0_9jEGog*@~^;bRtUf)5(b1u)BckO?d#)2(mw+}|nmTc14O+z^UYGwJ{7=RH4 z5YWMVdznlD%lH?Ab?OTt)t_AAWbDu0;UMMLe>@1Qct`4VZT9Gq2omve2A^wh$X9zl zi+C_j?bx|+*rP78_NI21kc|<;JJ!ZL_`_NfdSXk``!Uacw}jUw+}SM3R5lU0vRdP< z;!?Q~bH%erkF=aVB8@myZ}UlRV}~+VFC=nY-nqR0c~YjR-cnAi(UB2^b0~|o$hC|mgsVrb6Bt*T$-g=z*j(fKISX-r`n`^7w^&J{klvwLd6S9R21H!EujCn5x za^p*hcG04x_%lUJ79+yOCH%Tvg%Ob{Y!yBwZ4 zgRPh*RH2W9av_*;?=5oE^9ophRjti)8OtPqw5WJ7+Z+7KHJf`)N@Ay#H&bG}5?qhD zgD{IJx|Mhyf4!CDyRg?HK5^Q$mTm+KVM@wDLXW&9!#(_M1@>m{$nx~}1kaR^bzY`! z@CaQ-RP0ehjefr1`YTkYF`t5sHOt4K>at}|Ijm&@r$lb6R^T^a{(r9_epGO8nuNMp>hNjz)A! z=t_%E^mtcHLxU}wwuII7J2o_l^oA#+eUC>l3 z#AnaimZnN}+sKIyip~J{d-ZYj0iW=LmTVrNl^Kxtq)lwdFO<8Y6m0}tzHSJt1XKF) z`jMt7^Byi>cOh=9y;`n9q|J30mpD&i=I`4GMLYD-0{zN2?ne`W;SwUVKW18Hbd_g z7vuD;V8wh|(qM6C!b%Gb|2I$+?m9(X?b5?Kjvo;QZM|X-&P}zOF@wCdH!)15J*E{x&NjtD~VzMh_{}M;Ac*&ND{`N@SHKPvUI>2h-;m$CKPXUAZ(4O55 zi4G`wgjQT={5siDOVrrdTlw7Zs*JUa5q8DTqNMk6&e~sCWD)hX>&QcI@ywJe^AJDa z#oeG@;1xnP+~do{t)RnKqE_y-&ia;4!7J% z7!H0K2CiFn*kYlEx+q8U3o-aShaB43e#^Yp6oq&UN7^P0am>zj32jG;UCJD<@s%%Tf}StkrI6PVygWna)o#b%R=4J_(^UL{iwR(O9O*@=7D(l7I6tbk%(I48 zTC-s0lGcBSTJW4*V#fgcV_;Yw$^zEEK0=jbfNpH;cNmjRO+X8}PSh=0-Ne*o}P>E2}RfXG8H)Z1F#z>`t5K4hf4i<*zmuV!tYzNsqeF{W-2n9fnR zUD`|qxgF5J>MLEO9Shc*FTnfzAEBLu-CaZnn_8Q|Y5EiEcF!3O&uTlIYTo0CB|Aa& zvAA}P$D?>))N4KJ+i`1Hr(C6NTZ>*tHPd!eBxuOK->iB^#9ioH!>N@a{h|FJsvTXc z!9A!^F$?fR(9Hn@99{Rb<`v%k392fiS#!vZkFFijGE#62_7Tq19`xJ(e zc_RFw)f2!N?QgOvqj&ftXjtu-g3|qcr~-oq@fC^I0K*P_;@6oB~gdN+l5># zqlrlW9)AeeOv%60caBs7MK-a*fo^4=++dhC%1zMK+%SjBbT$Ta7gae<)7^@+vd9`H zL|im8aUB)8S#z$A<&V(Y8`ntisTD#noZA4D%NK_00>aXBw1q>9K!&9d8qh$pdO_1P z{(wskQ4l=F3ns5W04h{Ku4#=8X4VI8itp}cF`1AyJRZ=eUly-emTn2gdV3FmKqX4wTJul#)LSkKVYliCtn6u^*uH@+Vd8Fq!Ux-2gPS6v%lGL z7~f&~EzL1npLj3U_vRgJDfqwNVX~!f0usl=uZ}p$5Ivfj*%FPPmG5(qz;Y_@FY#`n zTzx2cqdjcKx>H#>e?q1fw;gaR(TmUVo;q$kK4-{C-LW5|rnjD-K8H#2Ku8^|78V&) zGu*g%($01EZAi0oR>wx_M$hr}+HR5mBLCf=rWIl4ypI)xIGgoqrMc*gi;}5zf5|wa z#wFi6`c{*Ljk4iWZ`L;l@(VacOP(oOlb=g(4-a13FtEz=Tz;VbsExFEu(ywL^45vA zc4xquWH-hbsp}e^J&K8uV5kBE{(O8n7x@)=Uz_=0DX7W?^_;fys4A^k;neqmsTos~*1t+KbH)>3XWE(XbukqR0#0Ww4+q^X-89s1b zVwn*&-rfbej4DzaM;bK2&z+WGvp(Eg=aRKtzIWyO2_|{Xr_XiEMrL4Zmq!{pFR8zC zxm0VsZK?cvuYOGYeayw^H5Ern)E19gic7nuImV{x`y-!#Zw`?<1o^)V!!n+a{!RAy`v9XK zXyUH~J?ixz;`6B%H#!3UpR9=;13H#o z?A->%_{J zV`X}vL8)4r40$a1>alBM)Bb`za3tPu>M zsa+1Z#1-ijyMSZ_6>PP|<=ERWeC`;KI8?9pIfj~qUfI69l_bt_LUzqphqPMt(2l%$ z>8N~bKX@+QOyf~_YX_OXjA-qua$T4ZgSaW-aoPXyY~Siz#_qYLVevMjEI15t4EyH| zK2?btaS`YgQPmd#11h=HaAP z{eVlAeY?@V$7ts@RhBO^@nD`%u;$1EB8VU~$a{e`3Fb=6bMXjAF^5ME(#bP&X}PZG zF+#uLJgHA~H4V++NR8-jku39(A3SJi|J%XiY9I1i<-zo7TGGnr82qJ*e>kT0ddq6H zrkz6d4M#-$w*mh)7O^90#4R9F&4mx~Vf7cotBxZol$(Jg$q+%Wj!Ou?O7^rIh+xslBd}qt z!fhFw^qz+F>s!D#O^MfMc>&Q-6mVZ4-&u$!y``yZSuuYxh$Tt3#6e;!ng zJ&0?$+*8=>DR}B}lqq*SfYMDXEjs=|XiDvSC+9$MUNnm5zgX)Rey4}!GedSTNxc>~ z`o8aV>N37)0^HYs2t}+TNE*1`Rh-My^-2C5@V-Ior~%zLN&{Q5^&@@XIl!HItNY!7 zX5WYJCQd6`7W###;#Nj}u^6KR!(S?$Trz;@YwivV5djZ29^A3s!9h{_Mq9_0gsm)SA^Q9ap0TV21r@;ld# zIIa)gnuQ~#0{*_1F8pKedDeD=@~d7+^M@^diYylpr_@&c{r8mHF0Yj#6&t8)_Ol^k zQL^c9+3Tg*Cr-z(>&z6SS3!^?!Yz_hInT@>lvMn+y*1!C&I&DO1+* z&sr7lw07~M=OvL*A}Y1>_ug|;VN2wwE;a49%>a{EWynFDXGAS@(THF>_Z3O<^mi zm1l}6gkaGp&dcy(N9g6<0%8=lU;T2$fM!JD%(?1nFY8#Yj6oDaoSMSQU&GU&x? z2@Q^|G7bi`^yRDv3`k}Ggd?iU7O$}rrC3{+)i=SWcEdD6wtpl?if;*uRRpU}E<%h+y6+Wi$NP#?0TgF5*6BGV}BZj0yQ%U_>}?XL{??`H<}V`DI@3 z-AGmP(JCsjwva1J$N-_8m#RkN9MBZsOuQW|O|?;7hBcO?u1bsS@%050rJASNOV)^e z9x(%un98pV%vJe-G#|x!wE%=0UH8Am6%SFI%6)+9!-^=7CT z_nS#Bk-=`C%VBqnOU83giT2{7_r~`R_`m;5Ixt*c%lq8)!q5}S&?l!Z`pSpac>&oY zpdo(FaCwJFI@rpov2L`*U1+(8lFF?MAj=*Y7uRS)@!JPMLl#@dzsyP4=Mu@Y6o?Uiqu) zRh7s}{Mzg=vmOhkB{3UubU(m;5@^b%g`R8mArQZJ#2bGQ301l`%Vqi-&7r7oZSj?) zeGR~gwsP<`h*HTzzod6~bHu)qsmckyzQKF>FQ;WRrFedhk&EeKxbG{EgLVe51eFl% zDOq^FO;Wb4vEHX#pC4G)$p)!%mD<>zYa^`O&oK=p>jwQPS!{Z_$O_e_m3}1eiZJq9 z*-%;OfY!=N(KcsNC%AlgSPL=MuB7ioq1Ih^K=5)?0yVR!n8Gw6HS3us7a1O-1>?KS zC=)g$H`MwNnQA&d0zk0X38GE!m)YC@ooLx0h{V(LHn$IcA!{2~HoM(;RayN#r(N{a zOCLSdSy2@9*dDy+D*{Pj023StLLr3VbCr#$yoYSn58g(1iCT8GzxUHS>ze*DE@`A%dkN^^UD}W3VcoJ`FJw|%DUl)Lk%~aB% z-k%dx)S zp*NJF-ONlA{6b+m7dutnlY$0Z`0WNSe)oJO#mqFQoqI_3E!sd>uv`~zrCW2OtL?(f zC6akkw*t?>1fklV3{qK_jOX!LT1@RXHsFOyt>xOmc zm4qH@^xGY}U^hiN9`BCy%l{JD2y|G^)DO*Hr_%{lw%r*QCZ+Fr49#!jA0#x`bfw(} zGmkAfF&z5E-Fxh^?U+2>-gfrDE^y8DPl^uQQv2l<($wyASrUT%Npj<;*K@9u1i`Iv zfPwJUH58cZAckf~tuLlI_maSyd$Ade%&rhzWtH79-kKN*``oK$!W!1RAb-!wO>&V(X(eWiqb1mrC zr5en4rlmFPr|AA&&Mn`Ut?S731^ZFr96G09|3;fLkvT_ondM7w(1)lb)a!XOw>@HE zbcC4HG5J7pcBq6-diRS2%XG)$JdI(}^^8HWhEGO1eps3vbXDcT@)75>f-ISHW{i3; zA>-S)_`IA|oO(ZFAgGrMqIyYGL@aJ-^Q-J{_FgDlCW)GF6IFy9T_%etYXxfO<~AYT znK4LA^Yq^vCCNQR_|BJQefKd6H%;-OlF+Xq+BD8d@o_ONcZhCL?Q(c)om!K*3t}4J zCao|pN#8D}hMIl)d>QlDj&K3vx#eX+lwZ~x*_ScYGl}haBndG^*2C>Hh!-%xr^3u= z1B93KIXiRVOyB>E+PN1GsFbWJYt|Xd2B~K{99m7yoe!*+yKqs@(WFk*rA8D+`ZBHgDN_{?BbG< z+4>UlsBXw2ONwj)dV1Ol9R37QwX&=N8sYBQI>9myd;pM^NuB)7lT@u4s*5&|;xnGN zP0hNYsY&SPGU3<>(&<-^3xRf!2B8J4nSHSkg)tGY_!nWzUqzhG#w` zvcq!iu8t_H>gDV2IFZT^6a(OM_mOQBw-RZ(hE#R=H8<6*&BEu4c!^hCmMMzZIX!RI z=z&c>9j$3&+*F~t1Wn+7*&lT1i2U-GU2olvW$?4f--zggaptuT#~4lyn@_#DIvK2? zb5>ssbNBY^L>712hgpTh^`J&$3Om$X@Sqo zwCS{LE~nkz5Y9%nC7pZHbLe6%92fC~?BY*VXy7y_X0XktvZa;}^C90oKMo+#n0b7P zwY?zW+PL$>TKEs~OAiGaM_l12?Q?pM3@NW4D}j>eSIas%&$@)E$C0W_+fps6}n5`Ev5bXx%KDr*hRzD=5fA%Qnp01KJ?#t9raKg z4$gw{>0pb`25Q)b^Sq0`~4i5}V32*npBYjQFtIXSOzJXVHOrZ3#=q%)e6 z-sI%nbXB+Z{6`l0ZVF+s{Y02QV+}sLa(qzD-E(5Ng*Ve=R2-Ng+6Moc+0+(D!WQ&@ zi(qCM&$DiJ`}MFZzWoyGK}6IC*h$PtUB$_qH-n@f=oY@Szw_3gJ`L)3|5^$wfr$qo zQZVbEf(sGu6PE_1#9&w6p_joL+vT|$14Rh(kp?2=ZJ!!#SvLB(E}PLhvw#cWqVsg|&}a8S#Hwlu$6lrEn>dobAi%W|B|c0$rYON3u{_fqtZ#BA$3 z+Z>ka6Y-{z=n8;vq#tgtbf0I{7l|WqtcFmNdRm~^Ua#O3tofnFjHzRNhRL>aBI3Bc zt3v?-dw#+1+UH}9?ArD{Kr-vSwPjDOy4_m3?1)=PJ8D0Q2>uV<|2jS;8AnVyq75HG z4eUZeruLa!wgg{m-qusSbV@i@BRU00&4h z7;~BKL(w`;P*`YLv%2G91aYg>Mu(RH!z06n)rdi3EzgMH%(kE1V7k|@ou#5LN4?d4 zNa$kPN&&`X(rf+2p1D<>V>w#?0(8E(EUtX1*sNPgDt|a-NCjY7CD*cV)V=kG*ngGR z`PkQS6`411mzDz1!f6;!Go^}dPiu?II(tzv1pZxJR!pR{Wp)ZvsvDbgo^=)K^(Eoe zPZxQq6O4A3C9oaW>X}?8i7H0#)V+Yz%gr;7`8Q;qA}i4HPed-aU10YpDJ(o9!>fhmR9BnnY$Gut9b(}MFno*;2wIENci|H~Xmb~V!> ze|J1^L!tGM2$71Hz{%B+rM`)rq*Uxsa6V!GTYJ0cvG5hWHm>?;A_Phs&5RNVFvj%l$gKOA_4 zO=4Y$yjt$z^8Q*A_1D6G>waRaq%DQ~;Z?M4zJ{W5S06?(bM5i(IR;(?RTZwSJT}`7 zXWKnpVgKDqxfY)6VPxyAGpV9I+9?^V0IpB5JRZ6#5^2{CWY{WnnD`U2s@*+ z(78gZH2{B}gX{UCzsvUPY~VODy?5K} z&vEL{Y=pX@MvJ}H#jzC@>T?$skUi--_o~+`@qn${M}8*qKXh^8QcBcUZp*beU+z!G zxFo`883Qk%7w~ptT37nuuWu+@CG(*Rk<59bw+Fc${O;HO$q|1(R=^4&ocBpB7uZF! zu@GnSf&B2Lkz2YAYh9d%roBt+{6K5V6xade7XFJ|enI$W7aw;PdesQgIVkie29cE; z%3^79ri57CFci7?jvCOm#P#vLvlEG@Y#Sy>tM8adv@eInNnPs5_bCvg8T%I3cy$5K zlLf|9ftV8DTF#nEwOcH`(6DEoI=G4N-;%LfYhF`(&Q>G|KMQA{<PR8bziwUVG7VNxqx;u&=uUj`Svhq|j9vm2W~HBBb+HhDRT0 z)n(b}0?#Fc)U~7A!ydG!B1#+oV?_2NHai)S*#_j`pL7fsDxvohn^L9)(9^>oddBz9 ziCs=jL8mdr*iR03Nfwcz>eOv=^?+hu}jAFY#COJzik{T+Ujt*?*y1 z=%(V7v`;0p$fJPn;+DkrJ*6eqhvr+EL-^O4_3l{@eLQNsfvVvrGQ3cDHpg|)i1$O; z+XJWB>vEm}y0UQ43qyzyj1LYt|K7N)a;V&_Z0qntuEqn`&a6#54vStdr^`2K8@x}O z;LIBdZlvDsTx^QpHgjWb&HY+k)7Ri(+ji2vcc9gjL*>1n4K3KK>6f73$Nynm*bxMN zq9V5)qx|Vh85_DwLF4^es_3pQ;$0q;JGOnytmv-748jRln|hW)%Dnet2Jx{Qx=NBD zuWjZs%7`vM6*&K{h@ROdSNK1zopo4LVb|_O1Vj)-ItNigLSpDtDM4UB8U&OW8l)Q( zl#&q1Ar+*%yQEi~{qmga>_51;2Cmupti7J~towJ54&-a#w_o1* z>TD}N5cQ<1x9xWu4X?q#S3|MqyQN)4;W})GvO2KJUt^oKThh*M(?ZZ7|1lO!rP%kV zZvaA$(kf2p6-RluKZ5oSfT~Beb^{xLRE{9x0(5LBQj6S8JC-;fRqdfSnqlN3UF{yV zKq-s-;nhDT7o!0Qaq=?3A3O?NlVSwL-2^r>d7z`r|4P&3prL~o#2RCerUmr*F9wek zN07oTtHW*&jUoSvOC#6$v#dpbYB_bp7nm;QFH7&f zmxt<#H{UYp$av~=48U)6v+7qloanEp7L^J+nmVQzYOy}5#is`OTIn(BLb&~M z{bc0Mj~fJeJdWoQ+7ln4Q#@A`XsH6IAcq|;n#0ZBB0x7dG*`EGyR?)BjiLIs*+7{B z(1}hT!4MgIecXb8m)omnfVKcYi062d;}m9d;ftq`6LB@%f7X(ArbH)An$uK<$s-;{ z&MHEgGadEzG))%3_iHmq(mS$!L9#V1*^c8AYI3v?1Z89tUN~;jE=Uh!!`UhP3c-un zOLCe{>;qugtu~F~pytJr_8Xy)H_}m=?X2UbQ3v~UHPK!GdYS`z*9i)r6CHJMiCbZJuB!K3gD&iK zbDGr2OEj?LiaOsGX}J$3S7oAw{OFQG2|gtxsP6)JlPM~qApdVa&5Dvm*A&Byc_=eK zieNV@r<#fqUOXC&Z}CaN4nwuQvPb}K1>l9KZ#ig-tT2~iSQ(1pP;g*WbT2%2D<9)d z?CD`LppCG^6yeFVxZVLuO7y$0BaO32-zliY(?L+a&#F<_n>HlqD;Ku{G#XOxjwYSb6gqiZzk-I*y^;9x&u#?!U4j9Yey zKAH3QQ8p{{xb)o?bFIJEEd{_#`NZ+@<7Z6FcT)9z2v2;-khR1@4}NKHoL(f;F(W9Q z#FRA+;NHmuUcw3YaCVssPhI=HWNE20cHD$QS7&&~nvL!`=9V51&grJFI}h%wa@D_Z ztP@n?`wXKO`o!bme=9=SGU*_W4a`wc)4VSPoV{iJC?~cC^$2624tZMsNI;5rGuvIgw{c*J)^cjKYiHN}_F&`~7>R~C(?>gll9yJ8C^U5y)I_K4v0koO{ zgm&7te2Gg{0>v<$q7DmyN z=Y`~EU2sMHPicBmluwUEsbWbBHsy32Elu>DV-G-2g%<<|u2L{TJAbns4`FLjz~% z8Yv}&t7v`5Klj8uc!tT| z>=hDaeb*wn-w;rzJEU&nI<-YT%NU({1Fh&_5GpeLI+Zv2khaV`a5E(pfQqT-+w$&V zt~c2p{TC)XGw_XtKoi>;gmn$Kn>!`Ko)N+_=NJ%P$U1@J{-|82 zY}aQLz?x20QW+<|C9p`nn~Wfp?k}$5Kah#DU`)E?Oi^`}0cRp%jgf6M2VV0yf4h{l zO-pG5*O`VUu>unYD=m_r2E>C(sQyNjvR`J;A|`IZ7}S(O`FO^Y|4=?AgL4PHnVxk! z7)lqZr5Ejj*Xm}}`#lr>fg2EP(qi+!PjvicZ$a9TYV9D_pq%3({Vxx%G)-+oV<^-j zF+8I(G+~|eZ==+*oLMPtXJb|~Im6pX(Y>52(KYH|1i`@9?Y6OLcPs9d8b1Ad%Q7CL zK29gWO;!Og5r3XhV~uQHglWLjz}J`nRN?wW`(Q(^&mw$OkL!A~KQFR`AhTIX$in2k z7P3QX+qbSHlE6PEnC6m5gc;Jdu-vB8vp(PWc{R9HKs>@{pzaB>lkq4El0Q3<7*I)Q z(*dt0br-mZs7Tp}XS z7r(Qur+kXX0QmjCqBG~Kf|VY@g6Vu76jg>$DM)xCv_DB&-hcX!95j2-hlzxks<|26sm1<(eFh4O!i zk=F&4=4?O6)>K6vAigco%PN2TH zUx;oP>0L7C-AmGQ7k-kr68alV2@=bzS5^bxFUR1;FiTSK*mxCxyyMUySqmq6e3w5R z{7co{LIJ#itM!D=Sw0MwZqg7uzv~MW%PR;G><%r2vOFg%HJ4sr4qG0_*IeEy{+oW7vG+VpViIeb&XeLMl=Kvi+oQ^D zJUNOlTR_PXY7G>nf++IF^Zzv8Pu!5Cb93?M152H}jYGm#~&giYauG z+|d(|2deQ@!}#e^h=&`?HukR2XtKHi*6SA^pcDUGf`LEbHipZBFLoJ3E*NguRzx~K zn%~`U2b@|eL3em5tJRuWS8D@Mqi5p1oH5h;dmDGWki0!7jay-dy0s_1{T+SLbIlQ9 z{70b9cU3PbLd0AcdoHT)H`o}m+7*~}NjP)Ae+A&20}H`ja1BaW^?f1Ct;X%-Ptco6 zXPkeT@qbNx;;n1{)fZq2<{|_M6mn=eX~0Tao}I0HaaKWK3gXGIVNbX`Mf=^ek>$;9 z%Bb*gBOGG0Iv0h%S#pQ`DJ;TR>d#reQWv_Le2(iij;YC%OP_1bXrCpL<_j@SMGtPX zIsF`NHt}*yhBJT1j<(t_QL+Dad|ZazsB8|62wsy8DB;tqtJa|qHWp5ZmuA5gUlc53 zRN8L3q%7DbHw-AxmHPSET$&F>#0x;xWOK*# zZqizqf*{9z+1N{~F@nAEr!GtdMy|^cR>iBiNFZ_ve`u7x#o#n0{dlWyHFqAp8?L^nT7B;IX1bGv7NJ2df{uY_kwEv3yJafXP3GYMBe_O*5eDuz zAFl_v@B%w|5lI0JzA%4kYN}B=)~Q@5ba-d(t9Vs!q=sGMi1F@Cp6pQoEuRx@8hfrG|0lWk7o-CY zu_N<4={!Ia{@xWh9Oihe3?9@=7Xc;rpW0ICaS)`lcW@~CI3EPii5~K;M*s$CXHuuqfznLWAZ{AsaFI+lb`9nmEY);*!=Oj`_ z17|1`&(r`YLAXxJsbB`CP&{O?|ST0@yi(KDYxq0+G~^9ma2 zAxRCDNMmY%XB_ibVu0#@lS#D!!{PTz@7C-@NBy(m@ymy&GG|Rf4RN4vT}Nu)yQp^B zCb6XZGA*L#g(mBCexd+Ps7*C?7hdmJj{`!-h=dqjpMI+AgZWHNyNIi$$6}KJm6%hd#y15>w z7{3pPzx4~10wbqW?#dGmk|(pWiA~or+NDtO5857*eWJIsLz4ljFl^ zJK6ZW25J)y4sjTv{7^`Is>~t8C%ZYnE==G80<`WA<=O`2Rz^*UO~@$MtEwL zF#q#T2QuA~UvlUubjSMoFjfCK9N>2B@SqGbVPq&OGk~G$2d0;_Qi#0f5E&Q!Z)oEr z(f;)+mV2=hQAZR5taar5FIzHRUycZ}R$Y4frxKR(1M+}ZN$U3&SL~3jxTQJuNWW2N zJLT0X61B9lHFD2l6oVWioXcMwJ|`qJY*#QIbcGQ5J#Y(fY?G z%n5)=2tWGY2!U2&dM`DrsuR~myLJf!EYV^5RFeKW4lB=f;D)1$j(}6!pt4b`>@%8Q zcFibHO|px``1~SGDT#p^>QpfYQQWs z@X`vvRCn|_LamuQ7uim$4;s9J3$Q}1&jo$$D=&L#;FhdWwzn5aT)UBa|9ch^yx7Xb6^0|!f zMqb);65{tCVi=<d*%0639ve}S>CDSnT|ge?i<0q^x8 zj;BU-?bD0j8))7T>=v&kkKgO6BdCvy0D1_9%T3%!TC?9Pb}bK{5S=;*h4hJtwQP(^ zzk?*Xp8v4EOH;jmFY)3P@g@I)&Uvptx-%mC%*Jy#d`bQKS&uLqJ11@{Mx5Uhb6ZA0 z<=m?F$>o?Uh?6|W1QQw(r~wjZIBtlu(OV)qMx2Zh!`N~)|(6%5$6X@gS%cuP0$`m;~5 z_aT^G6KLN#3`sh~5FSB#M`t(c&t4Ii;dzioK0M04(UJBblKD;1auNPc_)D{Qy^;qp z@g6D|YEL!}Kiw&*@hlOVy2#1aq_`e~sj@qt@ z@9x{O{We${@*Cx)k{YsganoE~Wbs7v zP-HJbjR)X97iF%+`Wj_>1}Ay-2bC3RhH5TaD8LLBb`xCyHnZK=y}8g1c8)GMzU`V% zed{$HdMAp$ymsSIKuO!IpH?=MM&#XMblne8gt4)7x=w7gUzi^C_sf^v4~zLYlF2Y! zk0>JFG59RQBbIE~!D%Rpz{(dhT|zEGBQI(y9bgSQ;)@DHkft8s8CG@_{q>_BsI$QU zWEfkx%`CPRC@<|A!wH1iWTL%n(A(b&LW77@Gfv$Lzvbh7y_Nhg+qHT#nCIWS4?6(L zpusmW$b7fdH=82{R^Gkdc!%R1@YdY!xHiiRar>nbnR|T8z1BJ0(~ox z!D6dr;JwYoGu&AEMr*+k*eM)f^c#NFu5(r(kheudT54qsPD|m5gfh9*yNeMb51;vx z;~+{Qt_6?rfm@MKyAESMT=%uUBuvyiz&U>n70EckE+TwQ&VH#$CD_%p=EiI{FH>7* zOj84K-=b`n#K(o{YdgJh@nZ92N5F#cc)GRJ6;C8#Qbse~(NS?We8#W@P1+t8wWRegXc{0^}E z4Ae)BW!5)@XETkU@&ocFKwT?X6WReERwUqD8{@iNZOB-lNeW}&&BK|fsXF_t)&uKMVG7Dse(t8y%Sive4%?Iqa+%|iVn&V`WO%gt-P zF#{#kfXB8?z=v|hnUtluX58zP$RIc?cBB8o_3fh}nbR-aqt zdI7GbmbN+vWVSvR)x6W^cb<^0O)?D6HYzQ3B+IQ7-e}6jC*fZj#HY!=$=`di4^mlz z%x|W*l-;@|t#U(}%0~=|lL%Ix;}7XK8#pL4Qo`Ce)7v04swH~ZeOc?UkeYmRhqRQY z-d39=`m+JJ!PtwyK@qt0GQ98gSH}5B(Xn2?ZEc@^E=RNB*&pnV)5AYZ=>X^MUohIe z3D*2VUD#<_1y;KdF|Ugy)d{gnL~B955Brj2U*x% zg6GG*$wNu~(`qnLlI|Yo&GdXB<^{ZZBmTIYdT;oN?cQZ*r+w<0LcGqgxZ&}EO~Ve?!BeKYNVEUQgG+wF^R`C5nJeMN##x3r zw~tMfLDij^M~#Nxmknl`*7!AV9$nbhs9J7J2av(=sYaHFf9)_iEi#(euWKiVYz5h~ zQVtQT@ACn+#9K}CI@=>>xn-Py=jiuH15fZ`uoZoYcgW^ z9^I_QF2k8}Bof1m)28MVp6|j(X@&&lVQkFvx28GvzHS9M4!x)1j$OYe7SKsrvXw$k zpJx%b6cv~8&}{fw#Ci_&$WwNJb<5omZ%Iw}{l#3pCrw`G&qM=6ET^SmFJ#9jUQ5`^ zh&Yi#F<6@`bZ$anc6uLGS07MnHVSGF!UAU)eG83r+3m(@jtK>#H{XKFJpCZIggfsT z7yVrOlE9MN65+%|OUn>v-sLSL&vsm#z1rZ0yCHRQ`sZNdN0Y3#tCM)w`V$()S_A_k zpT!wY0U|WJkP}0{=37zheRTjW&-Qd40qB6E(xT%s41mKXTDvPMVfH|(uwaj-`)XesrAC#H(c7btuOFqgTE7Nd^zI8JUE_!qg)+j z(YW>=jn(^Y#-R_MSv(7%sc`?X!Zg?y!QihM!Z=y;XpAqQWBYa-#?C~UQ(ugoYDrN( z7l-@Jhl%;phvr4$a{a`k=dC2BuM%bj1w-y8)ux~;Kd8$;<+Y(^gy`-qi1s#qY3xZ8 z#_me^7C@*ZJ&@^iH`&LFG49@lTwtWI| zw$G|=hm751hUq}`J3sjqdTzTN_o59}RQJAp-FHy|Llwsdo^@Put03}bXqk>qD2jE-u0yj3GHRvD5hFQwq!}FUVB|NEy6CVBpiYP1DfH@&=Qz{lUHQOr zgG9wjh8G-os3RUh_nSocU4BY%<5ito%Xgjj@Nk@Aek~=xb-0-^%m*u5QR|Sk%;Exk zSz?q88*`-#dq?eeUnZQ3a@)(++(xr}J`1}yVNoEFoH>dhte4}k#^AWsCD?3a!v`2^ zeh^oGh#+qOa?Iz+09P7`?q_17{8&z)RK6?dWuf8(P80FioCd132S-Sbaa2f4@TlEK38rIbfK+f62kj;{&uo@`+d zqeA*D^6ZE7n;Vj2Q@`$psu|BMm7gYO2xIjQA2cJ2q8d?MV_FUL3Z`I zx_H6CXKbj<%;9PMY1pa>PpP0rf`5|O36a(E1&OTqkIzfY+|prk`SG?J+y7J*<%V<8NoW0d!>vcx#nY%5Wqvqk3CzX?)GZ{VlR9nBg%6#JIRn9Ng zN7n^y!H2-If*F>m@Dv78wI2uR<^`HiO7!u|F4{g-GB&G%E1bwoQ=B_CoN3sP`c=^H zF}XSkm@Zux?Ul>{bz?@t$x8!1R0!}=_vB35sJ;#HaHqlZoEn5h`z_ zyG;{XL8~X3S7QhmM!BD;yNV1nS8pt^MAq9(aqd+u7%YEXs<7Bu$>hF>U1$<1Sb2e8 zV~kT3zi};fUe!1p&o5DUcT$N!0uRvIMCxbMDn;_)<~1!DQwcC+$6H#fwWpQDRKaxF z58drCM!e}~6xqhw3(GeUjRRIH0KXz{rb%c%r#Kr+A4vPEjP5`skDUyFpp~%p+8&B* z|7x^2*Kxsv*4jNt%-#s7Vi%076f`#i;=v9`y(V-TFQfJ7N!}4|*>y=p$riYXtKUQ~ zlfj9(E1%r(_Zz9L5i>{{_)ijb;}X5KgU6ST%P}GNIjwVDc(X$}Ded~kCD#)dl&zA| zon!O)%Hu^W*l~5OKupn={&|};Vs^4u|03DYNg!anD0D758uZf(*e`NL`*YuVP}J3( zXL_7_U&6(tJKK5p2{`%u7V=`4OW3g0Kf}S@Q}8bPVETO0RP9rv^mb&PSbRt?q~%od z#P$?Xag;0=nNU=OJUia}X zW(d#E0KVD^+TihJiv!u$o*t6`f2NUTnevolq0Qc4GRq~tjtojAVHegs?i4HAglQVS zh9HM~=&f_((F?NyH@uI7q5MIbWD z&)dr{Msz0kl+T&U)i9K!UVGjyHv%Z5^)rYUsKx>EvvOwrmp28G*zZAmt z{&)Vk--uO0wUDU9QI{6ymt6#@QW2070nV2LHl-f-7CXo_LbYGRn4FTWdEdEw=#V&R ze6ha@3+~!y-`+VB`~|dj4b+RI^LfA!ulE|E#1a*1gJW=2#W$B1h3M}X zfwFo`K+D=boV6h^R267y%IutId8kR)2K0W7aXQ2rav8NIQ=do^f%b*4`~HiF(fb9g zd;3V&vmzBWe;OyK6@Ro{T9M%TD1nX9mvMuo(W9=&`MOV@weRhoP<2{FC}Pt7zRR!c z#Y8f|H2v`?{4TuUteg^Un3pGv;pQWQWd-bc}4wcG4uxd+Di!BB{1T6Km!? zsE4HVq&Gw$u_9?tGtzaeeyP{hegDVzW%O{2?H+=7Cs=l7mjEf6kU!Ef~%_@=3g{rO4N*&26a~@jAvDN8&ZPc8@j7cBZASc3D=1@q!F zKfjmBp1hcF*L0#9d(f2*_I$z_xmM15sj$vCbL>~Wtw-54$bIKk$m%J(%CF23M=MKB zmcxxPODHS65@Voa{yUc(kZnJU3FEIHCe6q`6rf45YW5Ej499-hTh5ZwrH1$rNl)lR za}QWRWquYxtgQaV900B_Y~1{|zLc~Ab7E_u9NMp+^4`<)(#3d5Q*q+b0IXPp-0W!R z%m}f7`Ek0aD8AEH^=+@C!|NXM3>D>!2C1GDt4gHKCk0Y?M)ce~{?W;8d2EM)N4*sYr*hlazdZ$Re9v|! z*1V&uDT;PiQ;E1Mi*pU!wK}C8Y9_s1cxNgiWfn|slF>jS;CiflEQUAY%Tw>69~ zkj|ejZEG{6;$e-g8Vo_g)1H3OgHBkqjN zygcLEv;)}*Ajh4r>B?znR@^7(a#Z0LfAZ4Ej#llv)d?d~PonrmPAHrvps$g>8X|h} z6IUiVxi$q4rbg?V5K(r6yrv+e?FrRt6lmCd zjBVYkOYo35|8DaWm3kKmc|)il)6x)k+EvX9gZ-x_jj{u7>@)_XK}|B2sLaTT-&e0l zWq-zJ=ztUX?aCjs7YC28fjPaYk9qrEOi&FEhnUXI-&T9%W@XvbCT*xT_`*g3i+geB z4po)=Zirp&Ayi7j9*XJ*_`V_Hh!;iuHKA{5Mq$Tgu4&5otbZh_tX44TXE#iGCu2S6 zFwhKM{R7kBDs&1g-&t^}WC+(+5j~Bc&wF?H^Mrv=;-Jv>$56Uya9+vbim^9#TK`Cz zVHm$4nrgf}&zLt{IN-3Ku59tXo8A3V%bvjcVi?gU#$HM%J)wtvTR-#4JjP1w%wGm? zny2HR0}dFg8pivaqY_*h25jT|x%xUFD2-4wy_p#B`cD3lK$4^`w(`MC4Ryp=#H2Gv z4g^%C4pKq|Z8maS%0R5q2u{aTnco!kvypUilmcb~T=NE`c(c!g?nO4ub-B)lJLO!` z2F-)!`Yrk+8dE}vg-Ua*(#U(ZaX#QXNeUInw?>r~*+H_gB}KOtULFN}joGACQ`xL7 zOLZr_WYz=ab~;tBM(pR8<=m!zKRfR7^Q)%x;ga@ljFXcCeEf&qOP&>i^a5*T8hPrq zUO3O2AxpM#k*%7C#Op}k3~Cwe?S|SSQKEzG`QDiCfW_s{!%q@yMiL9)AdxMyIvd>- z3P(4jGpWVt53I{=nX1!#k>%f7|5=*u5Lb(;goiVF$1yu@-d__!t)PvSOCa;y-U5uB z(wL3AliMZ^X`Koueix*(E1|v09|*fz5b+I8J!0NQ7orXQ=vg*i3c1Dw*UcpvBKiQ2 zM=KuAp{Y%()a`DFd|WgdYH?}T8Fj=fyi2~>mD$vfp1rdMB;Fx=V$bk|Qc&|mx@5;7 zU@65+^-NSm+TkgSQ1V4}xt&T|i5q}rS-Kgfkk0YA7!4VVB)GH#tcV1*41$F62@-z8 zNw4$bF>D|&&gcf%e_iU2rgsioRwFxrY+of`v26d}l45o1qe?`wEAIME<)6&-`T@4w zL=_P9cxt!nkB)#87Bx9vlTJu@u4^~NiK=f!G^UwnZm=u;api?4k}Pt=NtytPnZ7eVIG`K-fc)$1_IzvyzAy&!5GmF~C(% zV&Dmt&?q)i2htzakm`*ar39?9Ig0_1%PXradCQHya1kn0WDJ-W1!Ie263!nP8*1x+@uqM zu0VVUVfsO~o7&*M3i9f{(V5`@X|<9cEjlCnko5MEwO&w|S4Z2r)05`Q-X6|BC#nTP zo#?FlzNE3Ra#Nb~RYE*a_K!X%RKNFszL54GKfZ63P)}v6LsGRB;-7;-0kTKAvDP^g>Ab8@}sGP?J>dwEn6lQvJXRWIr1 z59v|$=?t53Yt^M7wqGe=JmH}SVDe_$#IU^_+7I!(^dKzWP3)YH=~>!{ z(C1e3G!Z@8#%VWtyWQ}t_3tr^fF*mPVS+SgD%+FOUpu!s_bzUNnVTM2_`blvQ$ftg zo}F;gVySMa#1uO3o-3k72!VduK`97$^s=#(3^^WI&U|``C^?4A+synT=!J}_+p2P0 zjrNREks~P#iavChi~hnA4y`zI@YcFTSSKQP&${JHQ+{lapSluq(cH3|eKV+gTqAhG zrbpJHDnmH`-kud{HXwGYztw zy;+LLT`a&JblZTOTX1dJgVf7?c(%=H>cdJscgpikqo09coa9`N~DWKQ#QgV}$Fdq{!&*7?C>;tCTN z$eYu0&-X268fqU2?tYw!&Y$a+B5W_Dx@1zr&Jzx5-FFX)AU=uno87fn3Q!~VR9Adz z(FMx>5VW^JeB?@{Z-?i18cGP7UKYJr9QPkoxW8^a2v55?4!_hDR>o>fHgxRbe?&dQ z&xG!w7EV(cvRdBlvhdX|*DO{_BG<>`x_7Jt{@zBQ3PKdgW}7Z8ohZLIQDf?iJuDUH zSs_HC`hk*XO95BL2~&(>O=4rB2+D{TL)(?B*DYO@eLvwzm&K5ccnDc95z@d^ILHV3 zh1>W`hqmIk7HhAyw6~Xrj-RVd6_{3!jlcDFS3M4$pLmzi`jQJ>DrereIMv56nYZ~$ zIYy9hV3?|+Ch7ofBXoW_1ev6E;q`$_6~yi}^cf<^rntLBb3(l^;er-!(tIn+apdNm z27PF>E8hRfkjykFfGTFh=ulMgI%OoMTU z_8Y!X%C&x83F6MUpMPrAQAxtre#w#S;S@8|$;7e-6n%K}ij@Oht)`NcA~$h4GCUQi z&ITdg7natJ^ci?2lbZ5b*ot^{i3^-x(PH=6@ol+Dcgyj_JX=$|sOZc{fENLc?a~s(#!V-M1(iKd(2cQ55AlVt7|fjhetaeB`5%M4mYBco^6lTJdhf&OwdX|> z>Nua)c8;utA4a}D&_)GLU`syy26SeoU)tVFM;74oy9i!}d*b~{k47N&zdz(Zn4|ee zvs^Nm<)0dUd+@?uumimanI`}GI&|PO&?*PG4vJlZC}`pCP~}U~>!t;rWUt}c0?7Y( zxY@9tlai_m2k^*!%`-wv6% zNa}5AV_Dq3Td@!<%D+FzX!E+e_*lODMT? zD?`PNlLalcn%E5hWa&!k8*B2(m5xRy4|t(cK3CgsGvuZd5z)DT+AZmjDU+V%x>6)n z5)(p&^IA7xw?iD@S|1Nmz`vNH!mW%(+D(Uz-VC!4FFQ?+9vbRy?RjFwx2bQ4S=>7- z*6J=dwrqD%-{hG$o7Q{`;_4FL6iRsTdzh20k5eG%N)6vlTCeFzW+127bwrh!^|SHy zj!#1ldApOG1tffqTXM(iH zL8kD+cxh1md;SETOwPEVAN`rAogtRw@Swks>eFf5P&p#XUJGLBvM-OjK1{X~oi&ba z?F#m<;g1Xz(<^VV{&Ivdi6sTQpVL(59oJo+pIaKbZ#{`mf!2LI^1exbm5yyh<}d}^ zF-XX$8D$yiwiy=>=Pc1xAsQsyxtlyEh<5~YIbtJ@G%%lHN!E9nyz&J}`+}#0%?;@T zO=^GI@A8}HF9Xub`Cs#k;N=!)zZ`>K7JTi*150afvoW$#)%m6B(pIA_x%=0%SLB?9hX77MQDeUJP2NED*(|~H+aI3(OFAIig;FaM)g6nM>poF{9fu6(SMY}u5Imo zJei(eWXN~E)-sREN}7FPrJmnOv39?#^=@s5-A&yS(OtzytKiAhZzUj?P)*Ss;Gn&{J7^J*6h9d=-N7$rQ%2FWZMvM3RP`r2|;_@rD zU*svi0i=3b1eIgFre}#S$Ca+P&(_aEXGZDNx2|;RRi;ZAhf6OG_zjIn?j?H60GLA% zoI3P?-QR#stZe>beT~=zUZIGE1HJonI%`)$$~*XVh*JR@oU<@w8i!wny_lAF)uDZ! z^%@&LM>VRCQNJLN4CPKLl}8cnVII55qWII<#ko(d+)CmbQrJ7wtZHonXdDW*K1-aj zSLu;NXQxTWf;pB=Th|NLHixoK1)D?{pvJ>vkKD1)2sW!S9-hJfoPaD8S0{Jh_0i+nc2^3c_47n8V$d7_1ai+rn2r3)Y^P+!u!;&y>rpE znR#u~lkc?ieQ<1goW%&sSg^w&^o6r0)?pm&=d6KB<}~KwpE=^Z(l2`9oOT~uo1A-b zze-}37(zdEJZUEjMdZNIEAzjjs~z2i2dl2Dw#s0f%7fcjVy8GW+I|Rs?0WkpV~)$|{B#i0 zklfsTrEz<8IRol|*wEZ0?4ocF-xw&JQd$6nyZu4i2T%12?!3o=DSN-sPd;=D#(K$R zy@lWkJhVtCUJcEyCz|#kC_uWOSg#d>Mt?sCvI3{i24W+pFTWSdhI=z1B3KJ}GQ+aA zR|vo+d!udAzu1P|tz|*>{o-b)>0V`AN(*hP5hTl=bt^eoeBX|YN{?U5MX#;Z_PZY; ztY?%_l}g~1A4PknuYvT&w#rE3O5QX{J>d&qX9CC0e$$XQH*Ec!i^Lw?`iawM?XT4R z$hOVEJ4N3N;BZ@dsQNGR56f`c)+6-2A0FG_TTy-8Z14GUMo~1c>ed=6DAjW#$Vp22 zB{ku&Ej0MEB#)`i9@KeFU1LgY#?7~NSw38nh#-anY>M9wi7b~#wL(5i! zEXDPl3hT5NcoLX!0$!;D=i2reG5704jUnKC!e^76-CHQcw&vJ$z^lW3%S}BdGjC;; zuuK1h`-}p-5!b+63!hglZI7|2JF8`N_suc6mfK`hCVISyTn#nMu!yCNV^y&4;p4nnOSk@s=U_DI|r5* zF-PMxIy|CQoF9g~IV^oRk2pcm$H@DZ*mgJAA=>py9-rIO*aZuIy=s$4h%0)iTuF5z zl@zsx_vqH-+dTJ+;<2d*4S9=8=Xb|QzYbr%Z14~nsMR;B^|#FkiC(PQr*s(OekKi_ zsCkvYg`aG}r8rn#%f$AJcPW;R@ebfI0p(Yyr_Tw}7_venXx-JL^m_3i5CqRc{Qv`&E0y#-B z4Ns%}rRP5QGxH+Hbf(lX&tyM;#7HY2WXzVro+!1%cM8nS)^VEa+_9->u;$sdnYbx+ zSh6mtXpR>t*0h!aG3w#5P@#s`(ksL$#vci{F4|-Hv9i_^y3tj!@$lsD0|Y9X#}WQ5h~iX_ zV|Xl7*~l;R^Ise&R;*-55VPHVQL{*|*hc*OBf_gLWE)%V0(BJmE}QTd`8qQP%QEj= z2vn9*M*vDaq9%3!-ouKY_-*?WiGfVi%I#2AKJCO%h>i?J-FoHzOH@aPS`^RI|8-7P zjQl*`afZALAv_LSrNs9z3!t=474u(@Vz0Ske$IH9zROf1KTqH34;XCsS3A(p+TlA1 z6@8qp$MW=7ARcCR@4J}w8O-pw2@3g`xq%CH9F--MK)kKKH9T#h<;^cQK~Gx7dzGe*_eb<={}$8+e$L$ah!aJy!LF9SL#D zoA!Ox(enM};1l%f`!e19ImrY4$T;|f8(i`$x7vz95rrD9covbDX-RYJgHpt&1wYwR zlVnt0wm(gh5Q_XTXcK>del+RwL$L#i!H*YR3R%`QjovRJ0{1@6oErA3^{}J_kh^y4 zbE-qaA^##%`GCplnild-y6^o)mlf|oJ<9-7OY}#Y)%HJ4$};;^@A^2Vy)TRskY;+Q z3c0u~;2%GpgIQY+XPewqfydiXDH0d z3c|%VN`*f9Q))$iWE5)KARx)8puyV4>zg+w z1zqS%Ez5-43HejC9$v)JYqQ``-eHh%@HxBH$E?BvUVkF(nPqq;7@{pGPpLCIGBav) zU`tj;wOzc~JU{E;dq-OD_v6{kZ|Cf7!Pbk{6b_@?f9zeHYoz|J@>XaQ%&l=N;7hk8GE1<<(Xi+sjg%OFq z8ijy3MDC@aQ<|jzG3CTYBuv3vDFPOjq>nySzWuCQeJ1xeN@QcCU-Jkyu+`hJc^axS zBXcNA8%CpHpIsmAdCC8jMEo~mfF4`h9cX2KdZGmca!#JI@?`1G1>iSvc!=_ zj)eEZi<6b#8%Kk}4$Q`;{Ykxhs zJq*E;blIWF`;oSk)hCVG*SmyYG>$-?uz1>}5_q?rb;9i=#-rgTVPD1^1K}3nMW?A$ z9l6=ht2mF+4K~H>uqK#A3bUrw= zJlFPaO0bKSXb+-1F)$WKVo0~5L3$>l3m7KkzCt_4=ob}jS~BAG=R z(k{?om8mTOpE&2Ad=+oDdGm$&)gD16c7P62l<8%tm{PvQ)3lWGRV7PX@(Les<&03IwB_oiD!G z*Yj&n^$d@Wb5O` z&~eWxG%|dkVW&@Ic-p6kv!53RqZ)|Lb4ddb_Ez{sHWB>ilWuQ!Y8Q$>lbt;*$zSx> z?SIoc2WhK87yEgWCp%2`$%%M$OzK!>6`CdlIuBHbbCjW{i{CkIF`7H=1xK3BKTm!z zx=Ef*o99~LBwbBsZ|q{ub{=DE6#YCM7eajIchSMy7(5{hqc8Q1`2w6Ufwiag)l zaxd&%cx9!kj+x94kN#O02(n=%MKVbYwfo;x2;@(UgmA{ASu18tCM2i|p4|G>7HDG; z=4{S$-MBAhewp7q)Ve9l8(nZ|lRwu{ZcR3B>#br3>FCy3ox{Sq_XitKaRD>^Z?9&y zx3M%`T4v0d zVo;$2IA67}In-he^Nqwbj^2C}D(Rn%GbC|usPCXL+g9J$@-aD{v~x{uu+iz6WbiC=@Um*rw}l|B%@AYoSt( zQ~0kd&;BJpFv3=@-5(0#{2tkZtOA>*b3N~V29TG7o#4$E%45xF--bZkkEYb2aVhiC z(NF3HIWzUjITf4laGsL=SpgsZI9pBpEJ`xv%sg|RY$5-WS(9!@+PXzyG*ZqTqC043 zp0gloC4uY7-7bJJxhM4HfdBXJh~u_PQdN5pJ{xU8N^4pv11ccq_>5blUli5f?HBdY z-7HQO5|L1cO~&`Wj!|neucJ7dv(|CYzmOXoUv@UaIvJFFV#y~SS+lSptDBQI{4;UP zG4Sahxx%F3TNBx8ap&D-?VwWrhtU1mE1)_(_&ez^wHnVr`zU-HW~!V4An2jlpKW}c zyYSM`XK*@-CHhl4J1~M6&$^_SKhqLwPx~u8h^AtcT+WKKvuu0%C5no57OW^UoUQ)* zzi=W(FxQUO47QAy`f#K*-H{zt81=1lZ$k$p`_+c(m&!^2nl^rE3NBwyfiRZrzeq`z zVggwWLc2?nwuyjh5i6-r9%?)^^Tkv29mO9J5D<=kcE{){7YzggN#(^k)XG1b7WMxa z0%g4_Cy7q$HO)_#R#98dE13|^j6??hJ4PAM{-m=iP3!Wuo`(U^*gHqMsH z+8y8}1$4WTOt~`&HLM~D(P5uk2vkp82v4+M6029{2%{uTE%FGz6fpv`7Np%Y;L?6F zK48g-BH#07_VV_g6f@~MyYbeVsNG)9eFu3a_w8~@w1vrivbI8(tFXJNZTC>%QRaX| z=F|wh%303Su6^Ryj~jWb#|wgWS;%2@#XQ5}*4Ma+7+VQsRU8TY={k3oqN4j_89rvv zObD`(2SY}V@r1@csJKyt>lJI*7Co}7^ ze{iNXPGA5oLlXwda<5kpDD4Gk$@GH!Q4G=c_XQS7%ms7)g>-3QmbLQDc6dcE^R8eo zyCQ_hVvi&6=tfoK;E^Vova0~S-+JbE8csYk%PJNZiD%lDU`nfdn03^3z0vCDreXWH zwXZh}5`Kx#?xU#kX7HMDH7u3RklSFj^V9PyA+ix-oo4HI)0cxx2WIbU4sL z1*STZ0JPKRaWUSnV~)#O8?puZ)lzz3Y7oQbT9;L}qVH{;8#9x(`%8}(=5B~I$t~$F z8VoGGyBycHGeO*;qncuw{+~KtE%&rWHXh6#DMTGKl7W0tdauX(bhdbbcH4=1v#RaN z($XQ!Dk&^w}3z?)@vd5Dw_ zGRxthJ{>cS*XmZS7M_WkLA6zyrx}X{Z zO_&Jgr_h*ZGY%I&`@vAO`^?>D*;B0D{H0s#AxZ03l<2uo@v!&`q@c7(WwZn1Kb!m z=H7a@jaf~&tiSU{o7u*Zu0&ZjP+h~#zepLZ;X7^$-vM1gRSv&S*d{BEM+_7_mR*6 zkopS}3Zr9RRRXcb&20>5F=|YvVI;>zbI4MrKH@K1OstMwR9mg~sdcDoaDz5ok zIIr4p=gd(>%67`$&@&Mf|J}^S;g`<=%v(~7hX_-R7m1MDz)r%yaVdD#4oVX>r6nxQ zs#%F_p`Pf{Wsav34ZzQzaaw7TLD4DK{JhZ^if94DL@s|xdBUZj1e?0EH%^BM^N{dYR`ya>WlnuIEZ%IFkAX%P zPg#oMb}(&XUT3d#rjzg{J8u^>aG-BiU6SLQ9rZ6!l8VKf8Bep}eHN8(*G0Qvg#DnX z@81zzc%kCh@HL|G02)iLsV$}2FA!NsBKG~K&?nGh=5%Or#FL>98eg$YyW17HG4S{H zr&%>VXfI5Nf_+VAzH-OgT<>e*&&~nX_S117p5aEy`9Dy#@h6Vvt)hMPg}$2frl5XI zVfE5&Z4JH9eXY4W@w=g@u`xlNM?}9oa(b{Fqan(y;2Bq61Ai>5?9h)GfSso% zjzjua(TvcEAB_NHrZO7+W>Ist={dhs`9vZ>_gjd3j_;c?lxNsg2dvLa}M+L+@HFsqlH#wB|2>#5-JJ;aT zv-Gk2@@M8J{w%mfcMQle6!8|o0pF<4MOgFe^x>AGNfvjYCA{XC zYPfs(nzkzqP*Khe#e_#5$-pI5; zYxM|D-R6@|P1)Zb+>y5h%|nNw{VoZlpJqVAk#*8>Ct#)atoe}fx4CLIqzqY8xtfc! z(F@A7CB01$74XsDXz10kCPRY7Wl>G5FRnfP?Cg~d0%s;aEi>(}Ar}Q6odxxlZ>+?` zgDN#_Qy?6PpgJY!^TJm&VLx*Z?~{=zfx>sGkXhSV7f5Ijl?fAA0Z3#A2)~nuoreM;*6a40qtz zLl1gm5qM08Dci6j%Dh|zp|k4s4hA@2gUks;$4%Th^@^fd_~^7Ta3eC*%M3H&4H+OZ zj&`vh`x4E0U5gv6DKw_{zT0;)R3qbChNj0VIC21-Na`_W&XMa@_OMJ2y znXPa}$R0z3gy*4{v(O~+eM*`jypB-`QoWo*6@qC!?N=Ja{$SN`MroyG<8POpE-NOU%|{h=AOH~&cfz2 zPj&r|m(0$Y=TLfTkNc}%+UiM!Xt;$GHF0|LI*$fyQDpZwh)ENx=kxZ^nmYdQ2kC%b zokWiO=yZpevy~f3Wd4XQc1IACG}f;lQ|%b<9`3wb(pMCe#&oHg#s*Pyr^D?c@g)Dn z`T_KJ5P5HtS{C}SPn*QDYqnTO+Hp0=yrwf0J((OrG+Nx{O~X3u$e3Ro1A>C6+-xNL zdjc_Ss)LeTu=;K&B7$g!iwk?6kh76VejIiCvoPU*dcRpv{YnYM!9x*<5Yy_K?@&fI zD-R@Q0{ilUz92EytnL%E-2cRcZwUX@IKiQ(4dw$$JM|nSJFfN;sZ~w-*M)-kpKG42 zeF(+oTDx3h#=&fN)TGL*`E7aZ?IgfdI~YCs{y%azjAu*~O}lI@iie!2vXkRvkulNn2+_b~du{(oTpk9Z9T_#cu&Kt=t( z9zV~nJWQrQ`r7~;lbBryiNtqY2wt5d^5qqvF4!pB*|Crd=}EY`vDCWI{_Ch(R66|S zsH7Oyf0XqL)ch-1Iji7*coYF4`A?6Q43oWMe$uI#r~$@9{(pLTQ~w>O8%~6u6CrR} z*e#f=E42w)&oF9^J+U;3audoiy-i6QWN_=(6MLhMDoBm|)mlF~3x74Oo$<^ed}g#x0;EegnduZ#hu_k{+|*fZ19 z<08vm(WRIa(=G?K3ylRXqx?aWQ&U#mWmS7EkDWxK6EiruP_o?HzP7uyrM}Y}W8Y?J zRaQoEoKdfzJiReyb1px-5B`+8y$glx{<_@TgktY@km?JH*ccE4mxasI1q|6NrmU7Z z*!}0#xzxwL5>pmcL+MbOT;8Of(eIA(*_|H;x{fxhHmH-|nhGDtA+2q<*% zCl5!w;J2IpKq8pklo?0V?zilR6z$znw8CN8s%9M({7m)UZz6-s?njC1S*(a^TTx{} zH`}cwvPve|0}}BECtRBbDxP$+pJMS{_Xmn&RA^wcTM|DOjz?5QrArlq zE9$pRU(1c;IoA7q+Tqx=RYv&%KriyHDm$7I=ZtQd?cTIjM>ux$8;us2_0(J9slHJX zP#m+$E@yF~N%u23+qkAl?=3segn6tBBBXr9!RtzV2zelY zi<(_S9TSVtl4mj5UUvQk9Xf6J(mVvwg4saQ*Ry_3YRhL2_a?<9Y1~v7Mir{mqHbZ{ zY-XiXrzNca2}A($PE)?8?P}`w1?kd*KV@E%WDO&lv=Q#wZN4Y6D3l6#fwxQt>6rG` zuM=u-YIw59lR{v>=CVdJB;4o_Y6r4|4SF7k>kU5)ZeDSr z&herU>I)m!n!VEHREuE7wL$*&j`R!hkP-!ZjGFo#TlXwfhf~V)J~>V)Mwh)kVkK?` zRN|pZ2r)=jK5(hC1AYJgT^g)RPSNNqXx|=vqPw`fGI(`Mhp|g%Y+(u^^6Vly+Vm0G z^FHSHT(#pqwu$VLD13iwFySBZBDHxfK;B8J#B;>sJpBqBVy5leI?IV$;0tpHFn@tB z{2u>D3UT~*?3nUI5 zkv~JD7+IW?Gil*eb0FXPxvuij7-(IN|#Z^o8bYQh8jLzafcD>5FXf&KiC4xmUUUK?IM2AmSmKhePhdXg3g9}uxs<6u5xa?$%Cg< z7@%Rka?D+i>kroS{VIZD+;iRFeQ}s4EY#Xh_57s-@fi8troQ3~GLDLSWukU%~|rFRARtyC=QZ zhfiogUm{mv{0x(D?#z%x&vsU2zWq`wq(D)2pzWM{h4O-bs=(2cGIBK{mc_=+Ed{n~ zrW)hwZ)a;BMJn1-AFMUN(UQmiTpI}o+;P3znMa~*D%RBTrO}1jcUftH>3-mVUfojA zx8u#lIilvsz*YI>6yx&IGeg_%5aBqj$@Na230YN3O1`saLOfo@5E1{d=H$W|^!C{nDZa(tr} zQEok?-KhOmOd5b2yePW7ymcV`B0IdKw`S3y0dc)Ud&ua zbNO6HLZBJ!Vy^@XjvACjV2kgPfBKuaMn9e{k0-;|m9qgb3c#GN{xOHbM(;4i(iAIQ zu2I=dlaSA_bM8*gK=AyKUcQ7PqV!eVSJ3IIU4;0!9U;#O#?;TBt`Jtr;7c*ym*acBb*YWFyj5N+S~nPv>Ns2K|?4e`GiTh3qOh2 z{Vb~A)8}MPj=cw*oc97IZNhkSghn(6H%+|hL|G4|n+!Vu-K92Xso>86_uCQNt0w1}cCO5);?Miz?_ z+N1rDDDCU1O~+p9R-VmQqmgG7U>7}#UT-M;wt;X#A`%R-C1Z~+i>?l-#L4}v$1ed4 zwjS1gQB@)BXHD8*md3Q(@1b|rRD&ePh%=1x#)xsuVe;)v39Hb?(OYN6$*nL@Q_ z1R@f9T8Y^!Mq9Zs)uAAx52DkmP}5JDr@3WQ=Bz}U&hySGUpFlW_K%lTR_3HyKiqx1 z&0yClqZ8XtJp4^nr`EhpVS^7pp@s}oj-v?h^i!*1#wV#8gGNi{PBTq*~Ztg3B^*Gh|a3~H`7hm1Xrp#2LmmG;Tp%sa81;jB|xiib9H zRI(f3($TL*)1ggtYcl|vw;ZO(nT%y0p4r^aTH09fj|hAld!ARSJk_J=)(pTzA>yU) zK8W*NE63ipxjrHdZ&=gS+KY3GWvo1U=Edj|@UV&ST$|JxGEp%;EW7prTYG6&Et!qe zu{koSk)H@`V9urU4cP)5RCcg=0Y<56X?aQnSLpN1X&k_I1v9KZ z{L)25Zz7seWz7{{Y%WWY`|y;Bb+S8}Xt?dGG^EnQ%q`kz@omN6Wb?M!5>`pF|D2_2 z@s@Mce4*^d<;BW{=Xi>sGpW`js_KUew-wVRoswk=1+5V4WNoN@{Yf2YC!VZ^GE>QM zt_RQ-$;ecHt9tYv9n@H6Eoa=dwPUU4li48wwEz#3MoS0WMVDm<5q=8BP^qB9S*m8| zdBNP2M2b#9Nlnxg+=-RdCm40(V;|nkkA*_p96l7#DOGRH|WL(?W=4wK@yKKD9A zJEI@Hs%PFt8EcORe@HY+^>rwS~&(H_duFN12;3b4Hsi2^6 zkXv`bv~=&jaAc+5U-@BF1u|U|G%t+?9vjo;gU1nBBB9!I!(<<7{DimbIq9EX97gdK z|9m+8aYmtY(ptV8SNvh{G2F)P2~p9~KN8Kw{eOj11;d@&p>Bewt5fJ35jU;i3td-; zhth=lV7b6y{sE{fX9?7U-beVpHD1fFcF;qY#?-uV!sH&4QaB%oK!SE@>q43#&SV)S zbNq_`#K^ekITSD9YE`bNGKX#hi_Bu^d~YdI%l|&XBKtL}(Myyh-hiISA#tCBPNx`( zZxLlzj+a1>=+-bJg9qxR_6=pgSI3nVsO()jZ0TgWQIYg!Z)JJf<<`(=?b`KtoEiW# zRycn=$qVSiy^M$#cz|(}oMounN?h8Pep5iO)G39$M>5+$ko?Li713wPw`UHz5JJs; zC29y@k_SxuQQ0Y3+nneye*?cTYlj5gEijTDj5yif{X15CluGf(0_4al6Y-G5;F)Z?XScMuT)1i z`qasc{l^s~hI6XM{CBd5fE73qV!gIkAL z&&&Qdh;akz|0PLbVf_z=BRu*4d7LwsiGaqxF?lQ|RBZE6xS+5Q(xPJA(9lqCqRdcn z|A{nVpJ~pe=i`F}m!na`d)`Au<#Ch8?6(-^@jIs*UtK3gk8Q?*}ZFbZr*gDDNrU zjpRq|zlzI~nF->BqxmOA{%3ItvSiC$?O9779wf^DbsfFJ{y4d^(s0QB!)@pLeTGiE zf5!sjkNZ%awRY?uD{YnHZh+!ac&Fa zg8~2akATAz5)qHaShWM^_2%NZGWsxHu`4S}A3STd9){z^sIykIjlbv8kB0lT#CnX- z*gi*C;z%7=J3~H5es+q`TE4}f+U_=jQ@gi%pCOgO!g*@|N3Z4m7!Rk8I57j~_GrGk zGho6L>_AfiOrL93lZhxAp0AR8SKkR{kQX?E0WkhaGmh6gD?JFa+1>lh$`QuyvWT$I zwk7e-xHXzUnGudzN#yR3qx1QUF|*UQl;(z*?4zfaEGCNX^v*ErGmTDeEg?Xy#1QJrl8kPF|kqFgshmRZd-0)bkO zpSyFc&e9EBhKh`*fZUicx4wbI2FhJ_vjOzzof=tjn4oR3gJx}6W^RHJkdA_E@1+gV zf}UoSG2s}PaJM6^rQV__G(_b6luJ*`0U=DVvX#D2XsiKsLFV=5@2j)d%Z5GIy+vC>dp%C4l`kX-@}wYS}9zE;5=$Aj^@PZVup@p29q z%9!18)RnzWbXas|#FV3cxRLfV!FBEj^nCjLw$1H%?!c*eZRegGrp(Hnzed}QkPvhZVol({JvZ8f1pS#QV8wcDZ z&IHdIa?&R>b4rI4@d~nGZ-&O)j5?Gn`j0TgoWLNc&|GTi#?`)d`b69;B_Fk|rRMJ> zj#g-a77&UtQpFb-t`E&cDk0yAxQD{r!2*wKaNJdrT(-qx-Lo~kZ00d|!JGv*W_mm| z6s;o^KB!6&aA{}#p}W0DY6Uju_yLI3-A|zpXS}k{sp7*fnu|H6OGtnALz%%#hf8wo zh3b-8+2*%UNQzNJQN%ab+0P1npY>L7Qj6-o{M@C>x)IXWTd22sVK=4Tn@zXg_rO_N zGzfT`g>bfFkpKBp2kWUP2N}RxaLgd|Y`5Nzu_AQbyRB;F=1W@ilBq5ys|+&TCcB$g z?SAK7xLrz%-S-vHYKy%uMO8XXW9N)7vt578?5ODCs|RRAB=@1cX_m}<$u-mnhb`yq zM~nZo-}8q|QXqSOXU&n!o(JD~r_pxS<%(Xgga2>0o*S=TEdB=?A9s)q?somuSfMa5 z%ajy3f;Z_DhB4Xm)p>y^T-s3lK&d69H4~EY6;JZF$D2tf4}+I9M`?(y5tmgyzE>x2 ztLP?7(}_TqeCB?0Sa9_QY|(5*;K|m*EWbqLl^2}N_REInIT@+$G=Hx{XdD;E#rA(_eIZ$a<4-9Grz8-y(`&E_jM-Wvl?En2XA1;_zSMZJ7#y6>&Y25 z$O_HluGr8C;MD!{_qnmaq2OBc^g&stA#v4ig1dQJ5Zkc@la826gjqV@n;`OTVN$}% zVYinARfKz;L)gp%Hg~eP&hqw8Bx^ zBln_EWufFOlK3U+3CfJUYy0fpE&6E_jy4PrI98rGV7TyYFJ^u@;a(6QVzBN~JNBw- zRhg?QvI;`*~4Z>B+&S^n!1+F&8t)(&tF1 zD)4a~j-VqlIBA_hz^+%z3Y(4_YiS#TmCN9C!ta%{XHXJVwN8f$=Hi9YOUI_ETpzX0 zTepmkJR_6U<#^|o@!ML)%@x`p_U{9i-{k0zO_nmF3`w@%+zeZlI?YqGFvKS)xjvqK zwEBJa?fXkEq}RNQm6kRnSLDeTbf7!He@Mn))*nN0U)jqYXI|bb_Y^vrd1eHz8;IZ> zx^Qt%re}t36^*EBt2*!Vv}PH(BP-|(DCrV`Lkjp@3Qdgp=6VD35?q>!OSRdb-o&D4 z8@~{0&`uGjK=d2yiqT|_q>_FD)%td@!JhFx%`7Brlm-p#bpPx|Ke)^{@f(=OGX2Vk z2=q{p$HIb{&*B}4H_SEw+77jn-hIB+Ko_A`E)1k{u0{0G^98~a?-PqGOzDMGXM=X z893FF62Gq2L8ogl6U=|wWzZo(fT!`1X?jYnr^S5qA+I}E@_Sv`m(J^3eg0dh5yX!< zj`jX16w34oZy)#=rbXhOSctu1>CW1^1f{Ht?%+%qLR6dFc^^<;Up=I)Yg1j#T*HbbZTWzKeMtv z)64_(p{3#uow%Cw^oqXgWeAzm*yZ#%fB#_p!pZR>1=lu6Uo-RbXTck&@8yJyuf^b+ zc1GXSNyXXuqvE=)gzc*+LVurH88f#)K2{vrXh z|621QY^wpIL{aACn)MaQiOIWjJh0vR%0a`nhq?N5r(jym0w&jeQVv+qiav6XZHn2~ zHsnV%@+ye`jt!APPFCpG40L!T%~Ug{pWL&QaR*Y=X`UEf5K397*6~ZRyb?1XOq%w?l;CYSM7F;`c71kP{|P89+WIMUg@CtFyutTWBYpgD6+uWYrh-s zVa(D_!v!7_K?cg_aPKX5r~T>xb9aOj4C{_QcS`5MpFBnzSzIL&Tgl@OIHK}OBZkwx z3ms;n97iKcVLKf2eq(Kw&+gyO-Z7)iLgYFtKgWtbzcRMRV)yTd}8xgrf z8x8XQ4-p7SwBy9*O`oHCgxFm4`E$zSzZm_ov)F(MI%Y%$461^Tax9z}?CQ6rP$Jil z)66?0kv@>}gq&QJkvfdU!Y71+uJ7WpKl!RoX)e3(*9+O}~pf$?Fs z%VufyFy)kqfA^*TjJl-T!&L-i77tgG9J`=J!kL0CONUo23i$JgvlQ7d(wd<4E}$q< zG!*;&Dj0hRSMM-Um&_qg@4Kf1W_|F5gYVqYqTfmfXxV8@~E>Q9r3~F!F$l;9Z$}4?eA3FSElbxB&aEWPuo2Q7jGk|2? z=oW0XA+KR#qrCmT*IBkFehhi&tK zwTDeU14THUqQSg>J_ixbAvFX)sZ9MSU9vr| z->f5G^Z7Z;DgB# z;3tz}@bhmt!ro<&efmFuOS0a+z8~c6f1yAE&6wKwv9wG>o8z?B%p>IYcdm%xD(;RF zDwyu_&=z|3^#?5JvW|4$KMa4gEb%$8WA{YB{85Sl)WCRDE&rNGB>^j}jNe@{2AQVf zs7K1nRqg&>B5mFGp_c!EawgTkhW{_dERlw@E|TI~dA0;A2IX{6E5Vk!wRLGGI`mh` z;w@gRL$<<2!d}Z-^#e5tZ;ujJVJ`x)WyNOx%PaW5@&)J* z1LNztxK{s5OBhi%fG3Mf>ORa{FLd~R+jBg_nA_84lt9jsZ42jV>r4z~FG?>r{sRW# zV;sL)Cz0g?oYR|GSnQQJdU=tbCr=hClFG};O{lLeG}^)WsDFioazQq*__iG=3;`8N zEC1to>X}jVMKx|3D{?MF4&t9AxR(IW4gS^$NPH5A7dCj&Qxc!3Cd1<)B#N&5TXD{f zRYvq*VuId_r)pG;ZDkT292g^&h4USQJ089YJ3nt3h5lYjLCC&_U%bn$ZF{2`9h{!# zp@OVVv2Q3(>k_r|=iD9M(TMWkzPFzakoKi;hv;Z=)j*Qb`aEb<>h#K8F9=QjEh3ZVz%>dT1<7Lz|a=HV5X`SrG!e*H-@fRh>OAD*hIG@#_x!ekjW zXQYMg`Zg#EWp3if!N8>Pl!KXpN2Ul~#;4)*lPW`%ofHb@K1D(6SkWebu1A=Jm zVE=G_eEjh^>f>uzaC7oiC(krHm6NhrsH{^)w$PlaSQ^~q{oA!@tuuNqQG4Q}zBm!z z?DyB;-E7Wca-Ezhof{kD@3cq~ZfOtvv%_pYF}R_aYaHlmWy%%#EhJjt*`WiSni@C=sQ4T|=>>DL?0083U$FvY3qS94%4| zo!sR5Cmsj<4YY};YI+5QYI=Ie4f5bdF}3OU$M32~KBi6`kdiEDWmx+E))%ewa8CsP z>j$GKDvG?KAWx=jSI4d*v#1wGR*aMZ+Y#$EZ5;-@33m}J$>)$EiInrCT0tQxS1CVY z!{7G-nSWC45D+Zs8EW6N4PE3$7#lxwf+_T<*}YqA1zudnFPO__*joj=BEmUJ|0iRQ z{Dj%wp_w@l(vvio2toH=Q zyMPk*{=E_qqVd2XjK~nuZzR8cPQv$(#T$=@Uv+)14cDtb!-1$V zr4>ujSbvEqKIPv&EMwtjgj|!$sK703lbqTVJvv-5{^vRX{C7npM27JXMvNnQQZP-* zrQqFn989l84vN$Ntwl>TK_rGQqxx8GKl2ypyK?})=|lhUEyDt!33tX8OBs+`RIQkQ zHhe3|J$v1HW@(zQWwUtwA1AIDZbKCuM8AFL8-IgAQ4%s2_J++n+#IqwaRnWJ0w@>~5d?4n@U8}+Wo>=<@_ zmqQ#qpRQCzZ6PTp!X-iyIQ5xW%p4CRoZK+ta~;f(<{t2^|9wp&R_QV!E@a$3Ymjt8 zq97f9;M@BF*|U64`a+%~&3HC&SvZCX*k-0NR35)Lt@ocwV}{`ukG0)$qFxJ_jlUw{ z1Y%@&RPDY<>;~_adVSjRjk8)yM7z17PEb7ElOj|FZt_oU=0Lf2`cx7XDD{}O$8?QE z;~ZWA^r;%OeZk?}_-^u7kvvv>7q$H%P$o)4k&JBvh|mQ*K$QH28+YVI@n zL%T-}0;1|?mjh0JCojO1fI>E59lY;oJ*r`Wz3 zyFZWO)I~dH@O(S^WL+Nf1SE*bQrhYyM^Jl+89$+C%|0PzU+M@bjy}2fh{`n>YNftz z*ZwYXW~b>hxD&t6DD=;%$D|vSUMwn?$xBZty0D~B8Aw@7V%4?22eJZmR}j_kxqjcd zW)9S_+wr$azK9DWfc)rvf0=I2jGGQuZ~FE_73l~fxa;3ND3L3= zHuKT|a49M&TX$u#%KWz$WIr*~9bJDUkN%e*_&0_&GcSpFE}JeOaFC;q-jx6*#k81I z?%b6xD_t10`Zo`r{05piz_3~u5InOaVH17@;i~QNHaz@BI0DAkvMV2z?<_!=1x4YI zK)kATc*M~^uloxBsT#?kq4Lz}0AS69WKHQIWoDKwLTR{PBg+y7-HV7P{v z!l)pPjW?@scp^^4-^D(Ef^boh4I=lbpMXS6yL?HN2X3{i-NS}y|EanQL|T!O&H^MB zIHpLgFjlXgrbloN0a|IC_L{bO<=lIh=BDp6FSP2khh!FRnw*u0zu(rV%mJEG%XHZ1 zmr~~$6`{x7PWubuSC;YR~YpM zK#OTj4wMzlr1G@iJUjI+Z7Ix7>t1StKIzW3L3sgYKhXw3HB9Ue$bYI>?w z#0&Op&s*gL#DVqk7~p?&fGKjZbu!WZpylMR+~rc*W|neeE5KHN__7;d|9g3?)u{XG zcGg8=6m$q!mTqz|=r;j7Deal{tqi)neL!mP^;>aiIUxIh;X4-TGI2&Wxd*D|&ypTI zTl9{o>SWF6-b4TkCVif3ZwUS9v+s_`Wo#;lmSxoe!vs6VoXYsWhNoYD|(qBaS z7}rFE7?XNKBW+LK>=#$eE1%zu(`&trw`J9sKOsi|I*Z9e6fxxUKKeig*iUj9nC{Sm7oWD|>16^O-8j#i7CxH8H& z?Xd^BWsq%9Ewm~TzS_Q(AaFzjl*yG`DQFfOHh<>U805q5Xx?Wk?cd8sv+}^m&+Owz zWdF>{NM*7PO&$s}e~3h{CNEA(%_r|+D>(J*+2rNng&8*-sfJdqeLW=QcU%lsuJ zj(%&(vm5oSrg$wHjb$1SXj|BV@73cGP9w-P21^i$;Hbe^4WUG7R6OyPu!}P^JWVA{ z2v8o1>6pLT2<1EZIC-?~?+B_%;=0y5adAP!WL^LCeizecWRn1?RD>nh^cgr}gx~rO zRcZSAO0A5Rp2foXsSF^Uk`z(VmJ#&Gt)4}O$rl2%*D<$binl?!U>AV{ffu2024iaE z_w$QCt1vg+qr#UNz7yF}H+_8AyGz?4GVx4Ff~u!dPpjF!Ga>T6H^zpR{vxz^x_BEX z)0ji*r2j1Skg}=*#k1QsoiLU=+5PhKUdu=w$!<_|pNiNXy>RWNDhkFk?>kQo?m*UCv3X8bO#paMYxI%c-7d!}Hc83Myw% zbxzOt78Z1VK2^C2Fr%{cPxn^Hac;=)p8>~sHwnL>=zcOo1Y>FKPfz?v2=?pM#pRdI zB>o84sG5Fluz5;FRL(}fBl+q)sY)@9nR$NrZXaaZOOE`6?uvk`@qM-waiPsTR}Ixw zl;ZKXz8fBFkWs>Jhpx9}=dnB;9pkKc$RUHsh%iN@zaX!PCk)U+a-0kaJbq}t)%c?l zmk7xZ@S!p;I6yL4gW#a%-q=_(`aew_zza$a`)23C!d8^nq@(t;MNF2vHGlHcA% ztmw>G!uX-@IyEPf**;K18>iWfaeUuG0%!6n@lerGlOq0rblLq=z?zF-ieo`i(*^HL zd1OD7+X=K1mbXNz= zp~^_t1HTLZZJpV+-`l`3AQ5MG5Z-TcdbQ77KZttyf~pSj(jR|^Ql;g}bN9WLfY-(s@m$Fz@|RLJ63zFP64*nDk$)`7r32C8u!t@Mpsp6wOf( zGXA_)yFW7u4J|SZb#tbZp<~P1pSR8G-Z+Md#?oF^GXF)6`KX9qaqxCQ<4Rr^b3r$o zt)yjKSL5ifPZ<~%jQTl0Tzj+sOzjEE#Hjot`pP5#sPqg3zhJ%+nr8DWDKrO^nI>bjE>k?R~KQtpU_CI=aYoHr4# zvV7u<$S0}|*_>*5>FGm@6*`k|;Q;~iEiEml<9&Ck?6L_B+|w}mmsVs|2-24YQ41OZ z&Xq*5BV~odT5jAZ41k$GLmEhJTVecn`FHDc=8B!>XChGC5S&!MHK2ExsVTR?h!Am33Mj%Oc+qzXzwO^{DNPMnq4T{O zbIz)`G?*_FkNXF$n3DOw>dQKttCB&&~(F%tbm`F%0umcEaTL(*yr$= zmcfN_{G3h`%zO8KnwmGu>PPID^RG`_N}gHu+U?IA9IlOga#6|fX?qkLI;`?30Sqf8a_{*QZZq*S_`B ztFxt%(c|5~3#Q6^YQFwVsA9Xk-E!tfJ(4i=j+oXc2bv_o4%hsid}h^W>HUG;&8BJ} z^w0YyN%xzHxB2${-uDucezM4JyZmO&oi$N;iJ{+lt6ch3YXJCAUCz&yw?E!@GRI$i z$>^Vv5FJX+h8eR}vOsJ4B5-N6veUUOP3jlHk86Hx%;sQ;wzIs36q0l{Y8>%b2ak>j zmX`d}yTOq@=Y9UEe%CaEBLgXh6a~o5aOxsBrC*vpjcMZ*;U>kBt&lx&1=&fN#p@IqNj9C~D zMtbFoyiVhf4ft2+3&MWyQ)gw3sD1CxmBGNa=t2hW#DD(lyI^|7iRg)%H+SrI+V*%3 zIpSf)ShWGhKTuz;SF{WnP0%wMx4yVM0c9?Pl9v){3Fnwk`S0-sp2tgtXSQo|U3HD~Q7TYYhr7f2h~cgu6NT zJ}Ri?GP}jM=YsfyF)ujhDYSNnJA#rHJrJ#FOH}lBoeJk2nMr(QwnOe~tsk1Kf<#rR|bT z$$UEh3t0w!LV@;1KgneQ2ulc|`ChH*G4rzT_e<`p;I=&}00T9%mWX@-1Ru7w_BYh6 zj+FmK>wZ4kmMUG|EK9o>XF6sqC#W*bfpBYPaR53H0ly+3Evo*vOfFNK4IF)hP3?7V zwJT6;cyWFAalL(jW=Agdiw@quUGP$i@;(!ardXHKaKvSzBMY99Z;u40`v9pOs8Ml? z>^1lch&VbR3PYgox%fP-^5|qb7JQ!TRWYDW1+w$uIe=f6{p({0vuc2aR|lQ?%j7cr z+oqKoH(dvOY!CIa3kC*oTL!T$a45ZM{p5D$3C&KO&z7)nMh^EZ)q;{gIMSD~G~$)F zEqD>C%-7aY6$P>DTA1AT!Ykd1yP*R4+h|3Q0(pd@jYR>FNnJ*JGNvnstVM_|l4Zie zWk9y}t^*+y?Mr<{L-@Bnr5?0q+e_)(yF)T%(A7k1PsQXOVyQ=;4N#1v{nEb7P+e}x zUe(S*CYb5V(6DAA(fW9XtIW|Q{2DTcXO&WGh>W$O23d3Wc13-rXz5YM2ULaHdtHi} z&VZ7^9|(F^YhzW*n(HWGgVJJP7Duu(^X!<(N5kmu;!`1rs>)lblZC)n9{IjU%2Ipo zJXIlBoLnIy+Gi>mJdpmGbSZ3mGPy!7y#qMp;jK$q$qEP+)<>F+=E@Qf9pq3h7?YGE zIz5r5Eo`{ftO6#S%Pi;7nZLky^19SjrD|dc*B!=VO(Gr4wrzCP0i&_bK4by*vnL#4q{YFD+fw3Ws^BM%BJ1+Hz}YZ=YuknUi&wXC5HsKH;Fb0<6)F16OX#778q+Pu428}G z6zJQ`Gs2D(o-Qgrxlf*8ESM1!JbWH7zQe zE$&DP^ev~)%Q9m7`tNRF`C;Fv`-pHG8+4N~z7yZdDISN>A*11$Fe z(2*ZR4Pq=iKWdm0!h;FSzo$EW_!2@fYWqN)y9QCbAp6+PWzXJ3pDmBAuK0b{N(O6rEtx5Nji6u@Ar5%qtjaZK0dmJuz$TUdnr@=mhyb=v|;q3FO zS@omw*T!ZY%~9J1k0!IRns1WpmTwPNJ+s4|1Q`ClCmHpqQt}s$Z+c1>OfVFR)z9ze z3n#e-ZlP*pGu1^wg~77SGn2@Zsa=2#NTrW0>-%TZS0bVtBkr$R?xE|aJPweiHCN3I zd+&zG$q#ZRAn6}DKv(1yE-w#76-OM*U)Z1;M31!!apEDc(M-^`DzU9esmS}~LmD#Z z=;_3}BhFW^&@h7BY_-Lik9tlW+bG@O$V(Kk<6OR1=qwfn0!S9ToqGL|&|IEL`(~ho zjg5?LJR4i7)_g|?r3~}84VF3kRI-O9XZ)x<%_b)% z*SGv&_TsF2+)7#}1aPhflEY=P=OIM|bKaI5*f-_)8Iv9wx%aE8-uun+6ZmAQY8pnB zmN2?3Rv>mU^vryyQR=|67W=}o^ct2cZ~gIY-Gor&_$CT#V6IA+cXDK&F# z;TERLyEh~V(A1F0sng+O*WDO6%ql;Lmo@ioG);`o2os||g5|sAbt<~bcn-Gvn%%At zzgE`E6q{XyXvdYL%kAGLH7Fo(3sGqU)dina)vEAtE-UyXDu2{+;P!%!E)>&7kfDPu zKekSF0ckazYQ(MEY5odFO+F?wK#Apke%jAb+h}HY1kToVc5~fGIr&2bcQGU zmf1U+u{$SCnJ7y$x8hs#L=cAk4xL6-c;pXuURpiZ>fsn&{~Sh167b+CfzWcPiZ__3lUPE5Qvta6#V&5rRDX-05%N{-aXw@-Hg{5QE z(TDY}W{A~wS1@g8FL{A{;n(0@!3I}+|K3%#F({<2d9JdRyS6k+OE{0q?L`)L;!5Ts z$jg?e3>*O0BY*c1h&gH>dB^|vH5^+i{NH?~&F`@z?s;i_rMU|2f3p6!ob`Orm-CJ_ zZ^wy0KiBJ8pe}^EE{dTqQl?HqezN8w|0k6?#!Xed-up87VCl?z*wF0KAMon-=db6N z4!)=o2#kXA76W;@dK3!if}#&ilwd9nvL)iA?WB!&pXIR={4+E{@3Im<>nIA+JtUWt zmZQ2UM&hjRa>WD4&>(P z|DnY+D4+-~l3&}IqqhaiFBB}btN-x{bLmk@Z`wdqXkCSDPI_SC8|j{I_Q?anUd~$l(t;jPHas7r&9w{X;H$>DsSH|PUP0=mey=c*pwYuz826+ z%isCi>!NiMD23(N&BY9j2daNR(jzr3lnjhX_7qGh9u~?GpuC9kzdH{1rXEi?smX;m zESqPhshBW~*6!OX)-0x72-+L+5?}<16raw#4k*zTxXV zWrylX^>Jeo@@s*Q&!K|gPr}}}G!0r1_1QLR*Iy#+;}k%cZmqx(<<<8AJFAnW*fG0!YB z77)4EN>dxLANFicku8vc4*-wWt{^Hv6;?lNH+Dx=$9^1Tn+i?&HxHF(ozucMH%m38 z6-5JEDa-!P+0^JQG@R zMZ&{&dm_V3Q1KM2m^BPE4<6fKl^at?LeXRqq}?(E*>7Hi<3j>b;cE75(*?peQl%?QF$7ezLlwqFVYcHM8t=NT4n&yNu$;{)xslI(*<9XX&qsj<`M zY`W{hA~`53x(VnT|uN2#YQ&+&fu5i{R0 zPRGZelZVL*mk;*SfyJHhb@Df57W(ixs7bfB}f zG>1bOyt5~7nj*qZE#<=zom(*7@QiGbO-c)N%fTV>(C6vZXtt=|)sx~$j4c6w_Cwn~ zxf-xBFlmo_)@17kTyT9(xW!Haan@{zehL#j7mV#4I``nm8#x)gZG*t5jS}R__zm?o zdC1XnTLj%%reN06Fa^MN^;Q1|KyNyW%oey`Hb~mZ@rHasEZgdv4xmdBV|?XKNCwX%Qac9XvPcck0)j*dzFG z5o-^j<@cBNm3}8hW9NQ*HXp&$r3$okipI~PDs@?oefU;28ix-N2DGr*RQF%!u0Q3x zMlMIqt`M=}h7__E&U`gE5~DP7hInM@%2|1n+7_O^ve*{_Nvr!@L4KVfXIdvbj$vEv zM2n0d!Q?8UOMx$9^v8m<^(31Di>i6GowZbD5^j%)d^93IL!VC|vP-Tw9raBb+=KGntWz{?T!0^jK2=XA4Z+eM&DPF)|c16KgPncERT%Y@cyWcD$Nf) z6F0^=)Ty!Gp6zT=YzGBKnSO{1VcXL%Y?XNUMEDNVj+hsw%gNA!DMOc1MXj&mx-61GBiAg>UqR1bWPOp+U0?XBOENgs_??eE zi|7Wy*lHfLe1b2PCgs!6198oMD(yM8Q>w=Wof62i-5+%q zxHkh!+9jVaCdcZEGA(7?1RCw$k-YEoVhoAr5Kc&dKHq3k%1VOqs}MAfIg~ufy^7oy ze41?HcPQ|x5(^dZH&CL$-3@}!7ybfMixrBWbbz_^3fw{2?%dy+69Fw;W-9uFR^OE+ zGfVKS;`stD9}AGYWvm?A3FtI+rM4n=#fS(tme#+MuFhaEq}>_5=db6>sMhPDl#Ez>Y7mcFGaDrM5+e^fRj(E!9*E-Ck4L`v0v<<=fMOAx@b4ptIUELzL_my)XDyjPoCEvu&=0tZkz=o;K0z)ocyFn6JBD~h z9|w-^)5gKsJW-!r&>9X@w-Wsnlib)t4?2r({xA?R9scy4upyq=S}eubyt7g1VLcFY zK&wMFY3JrBu3X5k%tjiAikteT&y{MErN(uCp{8CwEG?yjJYg{AO|X(TmGmONfK7f; zqu4X50y}a|v%$ezs;KMiil#?Uf`Q8Yf^sJ*Vr!r9ikR`B4$%AZ`I(f;I23q-{{&SF zwmZ|=66Ss(Y-nmQr!Y}c|3RZGL06#hTCgs!)6@=zwjYjdw>h5Lb+6pIq8!e*$e5tX z*GwL*5GnH8aVYNraP0W~Qnd;yV#Qn*Ev4tOuy-5AC;vVQW7v4i{`0+D`gJs#^Oa3mo1KzXhNhyCcZ)iV zXrc|xax1d?It!n?YuBtT0eBNKvE-;a-au2=Q%gotU^Wb@^})=m)UfGaRcthTY+bWe z&%uSpSHgBENB1QKuB0O2?eI9Df}?G|PQl8iCTjF`IvIJ2X-8=XCV5&`Zt z&+?(cF_(qL^~WYp;rniJo2x*Q!c?(FpUO z??#4-%00E#p39EH04h|~J6q22Lrd0n6jC;%7-EW5Np1t{PT~qG&-%tovHjos7*BCSG(axc2ucCz>wDufjYEtz zE_j2mg=kQ#H{J zN-G-=2pA>*hPt>(5GY*&R1y4B0#uE-9065}O?%GM{e4E*XD{#I(({PPy?jCHyjBx8 zRLeC-1-10$nW~!QlwS+DS89!JFpIjm^$pM7z=^uHu4%(?sHM+uFLtJizP>IhDp6C4 zD;Mq-OJ?xDdwGM1okivFL|Oihd!Q+*lVUyt5;*r{;s=h(yJWm-6}8OCHE96SJRkdI z9i+&t%EPo!qB2uM)w%lB*+nH0dQD1P=u8JC;N}uB6hcYumts!DQZznEGwwn@w;YhW zwL`S`IKL_yQpAL}`&i5#8o|PEZ|u$lxZFl?bLuN=`OC#;2at4>GAOEVj|n!N72(7i zi}SLNod_)}Vc!B$<+5s0V5HLgLPpoAcb#>eTBSOOC)sX`ue}Fvy?kehJ^;=;f4xiHVo+6V-t^|gz#VG~yBLI4ydV<<7; z1i>e`!-!#xhB;{D_n-9d+z#I~)qWw)_NN-zR=w0um61Pf5MUp0qV`@o=ktGU2YZMX zQE-K!HYP21AHjm6&bdG-7sm>GbdGvveSn8WP1=XGI5O7OR$Xye{I}DiayNtT`3QT+ zCFko7U+dLgi8yD~t5&zJS(8cbEwofnKJB?NuX!Fx^Xo+Rnhz*n;H6`r0DvITmn+ha z@h&R~imWd;fNHm1H4{ndQ~6f$N(HwRK-B<`E3SsmVdFgUM&-mA-6MuI|&uaqxf>V8nsSdyW2t&XODV?)k6>$?c%(^J7PQ5Iv|~|kj!Tthd^36 z6GkZb(-pg)>=XIj4ZVEf(AlvXL|y7|$2atmj1wfdnfp3p`r|JIOO9Bwx96$=`SOEc z#-Pxfx7(AFP$-mzoPYf8JROd62u|_tNQH`_R_7p5x!_m;;>jX@)y6_&@ekZ8D-~5- zKaV-5srs+1RoB)uDKwRdC-sY^Mn1t;Kp# z-x>LSe|a?vy%kGhYnBCbc3$-60CU*&G>dk)!(=R@5Rd!NjmNZ@^Pjh_@>RVtUV7=9 zm&&fAM8RBNdPl0c>vsf_XHlLt%ERN;QdI(vgJ`_SBpF{9V*w5$(eE7(q%t<|>lQO* zGXkTms@m_l1_1FpbsL1Hoor7!7#zQTzi9X8O}&LB@&=oWT@mQ%DPM`4-jStlf z92#%v;=T9w`q_#Y`iNC~%1Kz2m%IIMxiHIK?b>P9%(u?nn%bYa60J7(KeFVD$IRr+ zxY9o}v!z6)fN4Oh>xZrcB8t~8>WmL63(4q<)}g-SE6O8Q_{VM6Z&}kqwyw=UW~qTy zS$E7GC&fAJC9Ff)(1$gM{%@O$9|8IJFH+0UzGUQ(@n-E_Kao>$@v~P-YU>-S3^9A=}>|EAZoB)Dr?MA^#5AB-F2s$a8^|x#)hl2gV zU-aS)&VJAWAP?dCHhIvioH(-?$W!-`ueI$>q~bvR0FaEt;>eIV5^_r>1ci7}cDoN^ z8cGp%Tj1QjU+)2|w`R@`Y*0%vvf*NnEgr!YwC3Qe(M_yHRUhzBQ4Bc^iey@C(l#?y zCh@8fGMF&!iRC=qz+q}3O(Humpk*b$*g3CoV(kAe&gGYBFOK$*)7!lt?~b9-4CMhE zc4wz9Tk7eo-U3Yhxl%+azE!V$h)h+bB2}+EL)}v&{Va$%4=)-uK!O_Ip7GMp#xNGq zM|aam{SXVD1O$_F%Bqo1U#1QbqD!>3k%nxh&7dirO$$A%lvic}wub8MBGFs@N&e1tjWcmdNW6?SNI z0*F+GF4>Dsf6*&jO!dde%Fob|{2Dos9F5?vqo)htE%f#U|MXk)PD$*8cPJSoA+FzC ztMsbvYR_8SsPxKVypCZ}^%sHL;-usBYcg-yT)I%)^DMFu$rm}U>*?XN?9nVUP0j1{ zmnVQioGGcBm2yZvOsmtaV!j3W}8&X9t1`*@C8n?lgl1nd`tybOfVQC5jt<{K-KzFg*}0o_XGJ>3!5oq!%i6-H4y`;4oUbl%)s z?2?29mpp2$!Zu@5vQnw;{#WI{EzIi@x>48uJX3dS-*MhLA-AT%bB9=3|}Z&(ZR;g z{Js)bqdQ1cLfPGvzq*yJgmd<@kTf$EKjpF++qfFOApbBB%o+L z@(gomr(k7*{g<)KFoZojMQ*l}IUYH4ZwR@NWdt?dLQ?>c`lQKaM+q=va74&w@qEGw zeLWQW?06stQLNVZd_DEUM@4Pi&jcUazPtU>Ct-JK%j0mk-xEu!J@D9!zxhNDFNt@q z1SlVGcOYNClyj}ya>(G-MMCdI*RQ-B@rs;jXk8i^e=Vtr`LLRakq8zGuv{Cg#2i(= zxY*m*2W9FE6e&JM^5gfhkipca+Zg)4eReu=h-wC;zEz_pd5B>j_XOZA18a@BG}s3c8H#Nxqfs8Bl(u zcuI@O+4p+SVjy5ShMa6rd=0}gvu4riJGe$0Cto1=;dR3+jTD*XZ@R# z-an+u?Kc~Nmf!827R_76Q+R*fbJ(<<4ip!oq8`;_ux~9Wb0A+ZImX}LDp~uL^zkNp^F5H~ z8>!Y;#5;A~a*U{U@y^M_3O16?kG#RMTG%t(>#c7a_#oT#))mpr zwvD2VAC{UdqSAcr$I=2e6I)X)KJ0SuRPPa%+-xxu7JW4#xmv@yqwlL~X2#=vJ4Bw3 zz1iFK{r zjh;W21*n3<3^$hjDQ|`SUT-ke+w^_+=X-SMGSs|L{>XuxTS_kg2;<7sFTf9-MLi%E zEs(Exsk8zjT+T~}-dhpZRH41QU1Z>~taqWZW2}6_RWW<&xD3icx#K(qyB8s8$fXE^Qu@V(no$ai*SM@sTN=|t%vf`Y=2AGERU>ZNrtxOeD$$X~4URC#80xO0v)234E|P@XU*YY;9SMi!N6N?Q%W^Kd&2eP`tPOTn&->MMzwodZ#+= z60o%J^{W~VSOCV7$!mP=)l7~HApwSK0XFn*7$>~5n0n93Mb3T{-ubI(K5s^D%ED^x z+DNkyH+PnlB@swQVGX?daRMtJ7v^6@9%ijtzgt4vtLk-5drt)3K2n^5`o=12;X_YP zz@rT1VX}*ay{vOd58PRDRVk-zx#raDN|KF?K!LZV#-Ay>J*K^V`LTzDKr?U-AlS5K zds`f1u%GN@v_AmtgDc&{eg;$ZBl#-3AU+63+F9-cGEbhiv2zi2vtJShJBLAN4#&J< zZMA8OB@4Tp)qAKaLt4q3IH~hx)F{!5aP6H_>r208jTBnbSPi8iZPtc8zKJV^a7N5H znzceVcyi9mjdo3ZI-cj2};I>xJ=) z8&a7Waw;q1Z{d>4Q?X}C^z`_Y{nVktA)QNM`|jT9SuJk9ei6&ZL_eje8LX+QxG-MvnGLw zAXRm*4rnX*U&OV3)MS&fvFW)dAl@irQ`Xul{gy@Fu!00*On@tCVqyZJ(L9g0tjr5_ z>hO#YF?Yw>KpQ+()*AC*7sC9P*o;QfFB?f~DII0J`lGDa%@aw_q&e*!!&vZ@-7U)# zk7{^Vyv(Z1)wju=yCs0U5#s7_-d$c@9S5?%2+r|2-D&VUc?FoI@NinH&7~`{D5Uee zkLDB-^QR6`RtqsAi{j1(qw0@6<=#0c>fZFKjjp;dz7|YVI`|@Ya~%833FRNs>^3q;i=i`F zS?&FIv~EUgfsD;5srTW(@SQBb2mnE!d;&!_iL#$`C;_l!{r|1qK)6`K5G`)_r}&!6-f<%+b*tek~d z3mQo|xA-9P4$EO`YHFJaGXj%m0{?thmgP5ahg4cFLrLJ2x@ob+esSc_c3mNIZtsgM z853s5yO@TOfj>k`HNIXc(z=TU{gj75=;}L`Z{8w zGSi_%-=R6ObG{{{I*Z@%78^~4=57+Ddcb2R0?_y?!jRii>QDnfQL_^wL$z>zvZEP6K7<2T8?4@L_GX&n%p>X_1q)G zjnkkKmP-kboA|yjz~QeDS5jE0rf3&MSwnDsA^nxU^mVbpJLOxr!M>}3b~(U2zQ7GO zp&3s<3fTtBR|s>4iHt)|uQ5E}K$gWLwhrf-oEpQ+ix=@`NqgsaPi~gW1B4Z{_vzoN z(-fbJ=t+Ws#%bgU?mCT3}mB?4T^YheV|m03>I~FC)C8?4;&_9NuK& z2|HxXqFd%nxqUm-qgXuGuZB2}IDtpGha0=_7cVK1!Vwf+IB_R{c$84TQOP9*@oAI5 zqj<;%L0%#Ml7prAce#juyGJ)waId|qMQf38aWLWtAmiCF>LV|;eAmn#oxOzDTf6Pj zMXKE0QUa&iKOtM{9Qx2Vac*!7jz1Nwo;iQ)f5)x^Dfw!50?naqhmieN@qDRLL*22* z3-+CRd&;t3l!kG#V&SuQsOe+dm6)No@U=iZE}*eq4a`Y8DtWnv(*$G6AJOL>KUNk_ z-N=gNwA)VMqzFZ4e*CyR0vq|#J4xDiM}fZ`RE4RCbs9q9u>SEJkUx9s9&>?wyN>`2 z#mCHzE-Eu?4$HoNPaMx%#p&A;{6s4kW{g=U1<1!$-}L=;U{@;*~n&b#OAFHxR9!2l_48r@tw z*U*~|Y1IuOO9RMSbO;93ML{QO2)gta8Et-u>{W)dtJlmMNMBPvFHli7){-T&j;X^a z`xePjQ|y|VF;mwoynF0tlXFpQtA+=-$13?YHY52PRCC8|8(ze1ZEhPHMr?LV#r;!I zB-eOvpgU8+@C4y7IPWob;%(pI_*`u%?bGt&gU-G;o=fNbh=g0J(^mLnaEa&bOl01P z>XVuy`hZ379tv_aZh=Y+UHB`r6nfYj_6IOyk0c!<_-{O%*dS5r-^8G81_JuZyv3ig ze6aVz>LD?gCtf#iAA(CxP*Vqh662e8iifuipLYsHA@yj$8CS0o8-?z_!wE`$K;g0A z`Tq+h%s8nSd${KT4)|0&axHvwblGwWOu5TD+KDaMT8GNNG7^_3X3vZ60Xy*`F+tJm zHNqq!mH;KoPuRTxN&zlX^U?gd00zEZ=Wlw4!|xTYZuf-qdQG5W%Ei_5ahM6c&+5=GR0!U=zfSQ1Vv zqPy6hK$H%|^l$BbjleV_cZiDs_f8Jy=&QEFXljiF!*?(d6<8e*GY)Z)!{u8bt5LT& zSKRI6@4=+%ZvhnVa>kd{*rI~eVzhgyeUQBBcMPzKc)H8`xzrnt6;uUYJbmH6zy`CSwWLJIT12D!P_Ib*Tqm8I5gx_ zs&}2V;?U4e21jK3uRAncix0IkGvDo+@jw%Jvbjt6OB3BE)r7@yFCJw#Y%uCw9PaUvv3DqDxnb7uU|#{+;9DVT{^IwFzW2WKV9k?g6XaeSH*omj0&N5((m$rHOTn} zY(g{c*(0bpL68=aszv+7a3iQX>|DPSNPl5!*z4I+i)-<1x$ah5NPW+9(IH=T{yLp? z@n@q^i_%b|ECjR$-om^eU`*xiKzL0pkpSQFhZg+oa7FtxdvXifh1YanLH287ja*m* zqi_EkX?`RAnU%Kd|xV- z;w}?~xYT7ETl>`vH~A7To=-UFSDt#uY^9z|h}6s6WFsBaxzAnw&l7L^rs333hx9wY zmb)`P-J0)bH+TBphe^Hy6`iwYmiVYOvL)_NPrU>;eM8uEPxPS)+vFcaq#!(T?YDUUdp~5)i^U~|NZv95o^BA zTnZ8C{W6Vr3^g>0A~T3j^#Sg z(_Svmbz?%`EW~+yp&3^>dg=mn>XiWEs{@oh>w zWT-o~qur{0sT=BZA5p#}Nz)G(FGNJxXzYRipq`=W%@&qogkR&>wpfOo;_j!t0!}%L zB|$XP-8_?&KQM9P_UZ*xWH~GC%hPjqeM_ujzzWP`!4NK~O6NA1TmJ#lBhGou==j}E zi@L)k=fns~aLeYHmtD`*9-!Z?t!jp|e-H~C0Y^%w?8iu^H(E1M9)r%Ig?)`Jb*83k2-N)-I+1;Tvt@$F5`5)cC*J(0bV6`O8{T*2Gnb%)oHpa{D}q)c^M z$Rm50S*lH9j!73D&qb3ilp$2oD}K!by3y+mC0xDTw@C85Yu~#i`w0L_k6U|>_&Qj8 z_oGOO@FVud|44t<;bkzzzo$EwlAhDssGqo#dWSjMEGudRL`d#c`z;>qxHHg z082jmIz7dldJR^vuyG8!b3H$I$vMxt_D9dY_Rq|3E;;FlKNYF=KfmZazwRjBQ zt)?*t#SGg%J`6a!#>|WmqRA5HM1>LqPSZJfGbt*WGi9e|3~hU{L~WLk&aSBziQ>wI z6GZi@rjLNfeq~=orw&*NC5VMUfCmFwtnoZzv)&wICR+9^@fBtDD%_xrF+gAxEN=I3 zKe30!G0ikAx`#^r_ua(F+|c$bH{k*i;Eo%q(QskSB>3e)96XGFzB zZfz}8){g{7XDB?=GCK-YTNx_fgUs-DMod-B9eAj)Do=BVS@JVthxS}fc+ylUZm~ii zn#x&1)H>f`nSJZd=8299dA?1^l5gArS~xlte)f&Wej#QxgEfKJ31HfC8A9xEmYJi; zZYK7f(K1T>P;kBB2zxio$-u(&O?Sc@^{y@t_F*|7YsGD^vBNW%@$YO@N!p zONTkXdK>b@>Kv2liiDHYirru4Ja!mbY^030${HOzX8D-lseVt z^RIRUM|*w+i+hUl27iUcK;VI^RI3|MV?W{OwX-A^df=nb&sj;wrJIC4JW@S(g6l){ z6|YWB4VD-pM%0xX=m55l>u_52&_wp!hx8gSDmodAOrDj0WUFj>cE8I%{BSnkQpzWO zP43w@GxN{>xoQ2d&G^+6D^HH6 zgq{2)Ya(bO?=5+v1bb+!zvYz+?H3Ptb1}lChkC6KgJ>^LyZhgx#4CLzawlGFsXyH4 z<&rJTVING5Xt@49#ry0hOpUk5x8MW&K?O}%zsM(y8U&*eaCyMNxZko3v8}d3d9~Cn z}@!Ca{3G)M3& zscXY!X(aV#`r_^z$g`8-)u?C)bk$wAj&b?&6~{)&#FgNsM;#FT!$V~tJT8&L)xm=K z4N%Tzyb@E?JTn58SOp0C6&zfdpDsFMT|0BW4q_WF$NlKJNjP+)@Jal!#nh4`49u!& z-O%hWLm6bpQHse%Kn;4ZgrNkjS&hNJy>TJF&A#VLr$eOpVdQxwzRv$)?5%_1YPxoB zNCG4fELiXmg1b8eC%C)21b4SUa0#x126y*BaQ6WQmmmWSHVn?0-1qZ7U%gf5t2*-s zRZLCI?A_g~yLYeOb*=ck7=uRG`=?46Pfbe1JsIgStg9s9Ay92ClyTBt3lVebLuhqs zKZqKwj|_954{bH^1-IdTW-ECT;hfY?MR|K_Z;LTGM~!`C|2|Kxq2TGEAA}NKR%Sz} z8}isQ?dN$Z6h21_Y}O;n zooPMJ6;PiRN8LwyR0c!~124z(-f&c$b;?r_Ph?nL%ciFV%KP#f z;}DP}yU$bdu=|@Ee{vHpMW%nuT`Y^qSJ}YfnOcPS!cW1cfrVs3;}Gm5BqT~Tsy>LQ ze)@tm$pZ4%0EwhZLb~P+5&!P*c;l_*SYa!s5nxY=K+IToa3w-vEhQ{}IUF(Y8Cq}M zEQ+#B<4jDD>R<4Jagm#09o^sKkw*$da>1h%hx7q0c(6IrH_utPr$Z&`583au6CQ&c zoI#(D8%EA1%N;&Hx=y08Ky_~F6ZMJvL66!#mU`#i&0M%O>0pA$BAuTT} zRInJbUbq&&I-I0zw1lwP0=~HEgK#&twh3FNckQ0Dm^-(9M!`#8Y9>yr0guDuvKc;y zDObRr2L)txUayPa#DOv_ljsK50kC-p+(&bm=0%*x2clxu4=i!nWPV8&0*oT~*&ai& zpz{Zv>!VK>+qBF@mPgE(COlr}zif(Dp+r63Q60QQ@RWHU)dC+gpME!#9#u6Ql9GN^G5jfh7o6RM8ee`vscv8N4)zWA@Umh6ZrFH-y|K{a z3XAdqxDKXzlj-&h>H7zFTwh^Ij2;PX4~`mE(cD21N?qp+mv(6K*Qn$Hb`%Xl=^XqqX+zxpw8l=8R`*?aPz;>fDt z{L^yV(@C6WDgC?}2`fh4gVkQ3^@H~g_P_{l8}xDvhKAA5Oa9nFXo;WEOUulXG)}H{T%i zqyHsW;m7tm3p|uaaA>pOO+vq%tdHF&8Ec%&_iVXkzBV`0A@!p)f=}M1arC2@(?byE zpIqc!N?Z%yp?+|DAnY&Z3I}x=Ua6WUj|bz@amCKoUzWLpiRo|u%}x9_A%MV%^*5RD@9PCzL63m2T`l_zO6L0hFI;;L*M!00 z+BLm}q5qe>!v8Di>u3#m=l;pW$nY!h zMf7=rZvRPgAn^Vt$pKF|g#S4s%(G~Rg|*n+_QY;!__#zF8n@nKrdp)UCOIAfyPY}$ zM6Z4d-Px)KvKTpjE!^LLlcN0>NS@#?UnVXezSeC%p8p}q9NhT}ls-SbTmzHPGy#r5 zKfdkOaW(Vlb~>6pf^Ifld5-+Q3I$wn^m`dD#kHWdt@6Uwe|nO2sk10o?z=5n)jrt^ zbz4zfUnat`>Vy`Z@4LTf9yRd7N@$+seaKg;DVguN-I(5r&^)9fzJlA@{=K<|Jk(D( zhfGBNcWt&_emKyc1;g4b&2%Naid^h5mi#ONToq9dHl}T$VxUCN$6ks2i_Czm1Gcu< zsp-+qH`QUKzDDVvg`ll{0Htw;MS!C-U2G>82GTQ1b>YnZh9uk=(X(cHVjm!k2OoUDTi&omzDI%5fZfR4U zC-23++mpu4MHBV*rDwl*#b1|oqSp$)+hN~6!tLV>Dtz$F5A8C9nN#iFqv%lo@h`9D zh_egZU=PascidTHoaTO}{DO;7iI|AwIinLDUAC_cRnJ7jYLGHlnT!D2+@iU{aSA?d z6$zY)l6w00W`bKy1UJWH=O{ z(wmRIgoO%gG`b`{`TYk1i?BluU0Fnm4`)a8@)c9cXF@9ZtaJjsi-FZ!(D3G3gHrj> ztQTX5?(3(U`L1(TyG5p7xNi9NY=q!k2~M;tZpgo`i#snczHMhr7Z7IX>9NqWAJSw- z>yoB5E?GRE%%V5@JQ;t($FCA#L1;gd)cj~oMqUHGa4{U*cTJ^zFR*B@8d$Tw(Qb%$ zJe;_J)FQ@(!pwVCN<+X{f}Wx?9~iTONs?W(&7zJqS|=aC?95z&kSM%yAL}8qab@K_ z>yxW{Eq>7HL_*2(r(5M=5@qT#zKsmcasx2A)3b>*cDn@)*iOeg@Q(7&xwdbE<8>M; zBfvpkmBU=E-FGyE=F6@623BM@V)}AoK-3-!1kr!PefsTLl5T^OG1Q$qL6eIZiTN9#K#gv?4 z>RaiQpt_9b1~BKiXZa!yovQLT0chuwaltm!s7?EObEA?*2R4DXVR2#r$*BN|zR<GbH+GBR*-0l(YOAKJtS zKSYnhspZriyk^75P}1wme4D*lsTkOn_*S<*SY_ET${1)v}rZB`GpK!gw zThXCzo_URNJyJ*_7j!TnRBS4;tHL5gD)m*Zm*0#$@^XJsP`3}nFts%eW3v_B4`mXk zJbt(o#&-#HIn#6mcq>f%{7K0eD;+)$7`%PjXCEcFpWXCCFQ6+d6R|JA+^f?V%G>vr znjRoRa7EUMDwD|meUyEzhl~Yx_V_z7PArG4eTs5m!wQpYP##%e9+ofDTK=G;J}s>< z_zjTytcTkVw@rCGcVlb7WT6K{a+5|MdHAx^;vj zg+IL(T3X^oUg$G=ELq^>fSb8@9iHl}Ja!|XA-TnrGvh?SguOSJOY<${?Za{vAv$%= ziSe<>ZGg-8NTSNtFNmXm{ZyDgrCouRC>@iIEdB33-GsgIk2*r~Pm!otyh|_5$9G&K z`cBFoWst1jLxyAvf02--qZv7}cIGNWF*SnX!YVy9A5t-POGDZSGOFICObc&c&I_{a z@{zDCUW%e{#6qHkpT~cN?AIv+e8H+Y20v@wSW?FsPu;zC7T8$RsS!0b(har0Sl!Pf zMA6R{mBTZ4-fwyPf%o5)?eliuqFuiz zIzMz5_Y;|8RcaVk3IgezeohZ|bILi&X}hB*$$bby>t;uA6F?uqfiR(-_Y>kj1Xy%v zh-%hq;PFlUKrakC39Ol-Kx-*(R3liVL?Sm8u3n_4zaxpm546naGC?+fc6p34fM3%B}@Lrqu<-4u>-bdbBl-!4E(dHlkWkN|vD*ff8hz!0j0{So1 ze~5x0OXKTyQ&=+riBd9UqSA@GuF$e7R9q=AmO>kv^LjVQ1Mll5%_QIQZ#NSqF7B~j z;s#bKG^M-8spk+{kTpww{&|v17b(f>`etGk8+8CHvcb~jIPGheAeUgagx5N#>|jZU z-yDtkfWr2K5hkp&*HujTL%XMn$y32NleVK^2_;>kyJQW?m?J_#CupqpIiGDK+eZmf zzt<8PBkbj(W#t?`Dj&*EFqYFB3K6w1{K8glRf1n|*oDU@7SqSSmH$Mq{VsUpwsxVk z-105I@~%H)HsYISgf9_+n~`lsp&^`7UtjIa`+j@TMSoBj!WuA!5c03;r@*bFxL2NR zmB=av1DFA`f6GB;uJPl}(QbBo-iJu4q4Hj(*^C0UN9xZ1)kEXjQ_%`-x>N6pZk3eK zvL{Qr^sk}bcU}p-IHU(}@UGM;qAFfGAx@Qwnb;dARUk;>e25|!ekP60AkraXPx@`` zDGmS*^3haihY>X;k6i^MAUPK@y{>Z{ie_&ktUaS7=0Vi3Jel3U8wm>HeX{T`3(VCL)g;NP+ajbB)$uh=G(YPdW}ePqIqw#B+8I|dFG@eD zNY9|9U|&+^lpzh{-e4y!XV=PjP!1$_B=l*@os#JpUK6{tTh=R z1ek5ysoj4gM%i&xUAMw4D&a7s42 zoTw%&v#6XcvPa+629ugTdt~$Vh0~uz3vy7!?9I%{LF@Gj<@JK8a;ZL6 zcu33;hu3Q?a0pQkw0});t##lxRfxW--So#D{YNaB9%#^6Upjj~;)G*FDp4HB{&&qS z-u*+cczBLa^{-{$^3N)=mk2?50sKPRj>IFUfrjskhJN*Dysme0=rYml#XF5P9|d-1 z`)05@$a^n;(5)zG3z~pJs0z~v0_v?BYmBcS`j%1hx!;QEys;(KH)bSdlh=IQ?D4KN zuRIC?E}MN{HH0Py*g3;pnjLW}wJ?HG!+NyD7m+aA5fL~ozGITk|9xUQfu?tiUOf89 zKdfzuUl{!r+aY{*s;5U3Id9SgE1yUXzeumPHC8vOEjDw_LX{%OT0G_1o74A&wdER| z*z!?cSTnKgFv~?#PglNJAU*nM2gSkIJ}9~G9AD&OL|Ag7M#%X-&W;fD;h*ha5N+uZ zC4FnYYPt7oBn@?cUrGbv%9EEkHA4*Of}gcIq@1LF?r6=7N**=o!`5(H?X(e;5mn6X z5D{JlmkVL%*}|UTZa{qPhL+B?Zc{7-|9Pa_U?54X-{mvy3_8gchrjyI<9R_~v7A z4vtG1$gfy?ZSebr6V_h2YqN5X170kVgvrBGCuyfprvbdyZ0EoCzuD>wEO>K`5OI3V zJ`YCLf>03g^})|1ygVzNk8FV@c1!pQr%G%1;qI$5UA2x=0wWTE?mEtFY2IpKX|nj+btn4OhZV&!_a!Tsp$NfIOCcw??*Otz-Vm>;g-3Utk#P{4{ zAhuncyYTHBBQCbH&S%@`(CJ9d?bLO*VvdLI_}OP!+I-9ENYoU{CfpZmxP6imH{6)t zPm4|0B0|pwKhC7@Tm7M42jq`0uOpch(7XUFHVV;a}ZR z!dSw5I)8YH#4xGdtH;+c5=&9;Rb$`powF0w!19}_KK3{a{q{Ps1N%zzr;5$*e@}uw z_7`0%;@IfTgPT!{yMXx6uk}AkB2cnN zp24STou-lGL$OVyn7+MCY~c0CH$u0wkdtF`n1sZ8KV zvAR=*L*bb7c;$Y)KY-86z9m2e+|)wRLwtR?)IFKrL#*(AMaCxlf020Vp=N?CUGCJy zMMc9DRql2mFgzZ9AZ{c~z$w${%w+{FHLOa#1MA3;$%Wsg>Z@*JG;7gvzuVKfQ<>g{ zg+!*RyD$$Ai*>L6^egl=V3vp=cI!?|GccKB&9smsXDN7iw_wj@rGG_YSE<$o@J(AZ z%@~hU1zn`mk`OMme=0nIm)l#>G}1W5er73Z4jm8)?MQ0BKa%sdDh=e|kk~rZ!zg%d zmHi3z%bt2&PxfqweDRj8!|)Tl13A_fYMs@V>}EU03)F7?iDa)?>9LUf+G-dE*nWiZ zv30d-XLI0;mm?>(lVV2J*4TH(SrlFV*6sn_Zi(VP>^6M|(!eD)>(LgX9Y!seca`Pe z>*0IeZZz?zV;wJ{O9_h94W(l_`dP@3mq1$(OUoV;Jr{=@?+%M~ZC(UweWWbxeem1U zVtK!HJ@=n^N-1&h=O{E%tJ^2UDa5Ih=0KJlAYzZ}=Wg=Doq9#axy#2Ifpc|<$3w|3 z`_5? zGjy%?rfXfhm3~iU&<{l`zE>z@en7O?CzaMYi7!+kc=&bQt{uy7gS+OkHu2YDF)yH1 zcG%jE8i6zW!ZHN`4m~75|P0%c(yS+TUMrl(U60oyJWu&zots%{%95JBG5w zVMAU9WImBaYymS*drSLP-^Cpo4T$-(++A0zE|5o;2wvbq)WAb($#|h#jfdZU6!Wl>{2^J& zh%-q_;USnrLNfjOeA5Su3lT)P=>VlD&bvpf5zfoX$J#nuL+Y7L*h2Y8-Yw-8*&Tj;Uhk`(v!< z?$}_3#C1UbLg?GQM$dif+sp=^1D!}s9Vxvl>rX-xJC)^n ztpxam%RsWB+5Lxv`tLK0JDuA{NR~m9m|8e9ft2COc;vx=YR6-{Y7Q^)N@2jlkG+0T z4SlVa@%^!X+8-qfUC`jIJbBD$}?v7VFiJLtEwk^Td7TJ-65U zu7?LBn`M#IxfC_4VQ&%%@6!yCnE?X%A9L`2KtL7o*QDDjBuEmn-@BIFOtPVqaMRQWe*N3G{!J$wlrOM9YJuLVie@I5W*S`ajOWz5)|^995UDjq9KuC}5=ahU4$ zVe}_rtO9mhuJ3>EUwFd^!u~X-psB-F9(m^B-1I7XbFD_eD?oEWT<4k1wXYoNrKTfV zrxN^8XYY4~!CM9ZLgpyRZZO*8BE7!he$bSMKu;RGI90^!{h$r^6716Qh}2$=xuR|m z=`$p}vYT>JrEn#y(!mn@(z6gr`~%e&XVzj3TY8QEAD*~uuUSnMYJ|iAt!Fs!#C*&} z74XPkF}rRKC;mto27btxnJx`<+mX>%9zVefy$mr~Q@m%tpTn3cVbv!%-!OEK&T%L~ za)3+rry)2tMmk0e$X1+uX94lGWOke&5mVByA|oeJXUqSH^LHLz+C{Hsh3<`nm>Fe+ zg7%%e7jKDx?#lqv;gjq4sr*1Ybb_RD?r&!iM~+`e@idGzgl38*>pvt{Nn zzVOA{2g}awUJz?E>y>N=it06dpOL&vudqvWK2b$tX+VGDO*#wS3Q4>5-0mdQ`-F;e zZHry~(B7B|ZZYCHA>@CMSgRPbw}7@}MX{V0-1|5>Ws;kGSW54Y?H8%&2QrqNov2fj?Q5 zL^Bf7ZNZ42_Cx6UtoH1Sv46wIz|9u@C%#81@YL^(8e^bB!{fWO7oCrnWf1jJqBw&a zNJt{#Rv?C#L(BMQXFrySBbop=0S-$&($$o1{SP<#o-n|U(==w zUv}^@;Oyy<&V2OKem7rpzBEi3M^>~GwruF*yFdnVD*BnqeO#KbV{~$bz7xJBpZt&E zLqC!;NUPBl8n}BCXCQD;PF(%7r~5qfZRw{^r5~AJ0n=mEoz0|hwtYg$vs;IAhN>RE z7t{;IN@c(2`DwwaNlom9YJhcXgVK`VAYtEzal~Z;5Y^ACZeCrz-A1c+AYGLj=OI3e zZmhX^^lR^L2q5cXhLIl+gV~6?f5gUkOIL;-({ww5W*yex)cM12Q*KQ!W+r+xU2coZ$rAg2n<%h_kNz+U=+&*=m@p2Kb+cfz|;m>-guO zb7?#7u+H^mG*9XHp9gGJS9*A>to2GU;MCT^zHY@XQNO0WupSl-$a(wi>SWhF57u?l< z4KQR`U%RaY*fXuAPIFBDWrn zSA}EmpP-=A&F#lE<&&xR3#ny0g( z>@?c?4>`DNX644=Gi#at9n4g|Fc*)DCjIFa{eG`?E+oIL5rQx)0CLt1^%p}DzN*<7 ziyVDRw=aiJ!t2MN@i4jtQh*^z`m@zOG}FLr)c;`ZB-i!c0+9uxrrTJ@qR^Q05^>S2 zGxsI#qQe@=eP#D9x69_RPk`=*S~oe0%rVGzgT9sJ;;|&SE zlYyQ%2eAeIHuMmj198e5(}&oAs`Kt2hArR?zE`JD+NVZo)fgG}ge40{mulp$<>T*w z7Hmcy(zZf@q<`%a-fyU#ck?alv{ZMEnuo=`jFVe;JZ-eL#LNZvn3f*^Q)226syzcmE2^i`YI_y^Q1w|ra5z3s?I2L{QOpqzy8^MX%c zm+;voA3W_Axnf`&4{fobo!l~xNa?>m2c7gkbe+_1-R>1~zFb>lm4oOh`w)qfKCa26 z*zU@guoFb}1;=nkQ#h$Fx0BI8%|A6BCn|$an6vM{2ruA=C7rc*1c2YTOummLp+@GR z-Uk#MF0nkkQpf%A8>}EO%WbfvHxwVAvn_~Pym#^RX{GjSOSbLn`YyzCN6TxdrNB!( zVm_#W$i#v{91-1>{LdNJ%*Pi!CEXt7X)(%}#Ik$~PQFMdQ}M3uWGdG2b#~eXjPwTO z4Sa4XVH8r_I4}g0pHkAg@k=ZgimI@BHAD}L5AYQ^XoH@5!cKRErMXFU%^`5Ct_H|CXx4PA@v9v z-x1!yO^7}XY4{3jYl+$Gmdt_x$3J;Aj|+tEG1T@kGU{!ofE^)PCx_}wI`P<58=Fs! z>0Q??z}+7Grtb|J??M8-%;h%ot7nPg>0iyzQ^qnyEzaK##;6@tD)G?_?xS#3N{7;Z zbC0A!wWGX0d=d69)vD5p^>L19qMCuyX<13dRlw@2`|*H>bDEPaX8;LZqe<27WjEI> z&z`Y@JCtCZsnFlx!BC}GR!`3vD8A&JdO~<`B*biU`UbY_!O!^g#Sx^1BG5|uVnGcV z7US&q9DIZv*2T%`Iw_Vi1|vt0=BC<1o^fieLl*$+>-+OB;(XlxLA$h-w|%H z=rer%AEFh$PEUUhaT_Auyd>o9S{bg6tOBb*9H=x9Kr>V+u!soY#vTqAHfsm-CQ%%W_pO5GrrD}r@tt0pfAfMtPJ5U$s>w8$TCQeT9L5);>Vu7_U%^cTc0ywO z*vFZG(zctU_96p)C)tV6)QWM3yH8{-qlQS39@7B#Ous#387Ykm?OslHsA2;oHa>7`i_NyPgvhG>0PD)gtUkKH#^WIaYR-0rz`sH*fW{b14 z{#wTSTW=1kf1wwz^+$ULjcoJ$&aZ%#5LhkU)sa%Egg~6hjG^nqm5H*CnY?gIWVZ?1 zKT-axB9*cHOJ73B{6@KBgt(5GMX3K5f2n`LUEHjyq&El%NPPfKlqTjg;yMIz=bL-l zL{>#@#e!iK*CN?UW#$#TmKtO!`KC;7hySqx=t7OEyf!gs9S%XTdS5zND~8S)MKO#+ zonepd^O3>v%w2;V=I*R~V4qU$z;ImgOF1B4OT0IJ=6r4XhM8cQP3XOd@LeG zbInj>Q{q`nJatO_onmcedSRzMeQpQ2u`teFZI|_Yl=!gnOPbpLX%{WkfRK=TVB4s~ zR&{)!*YCg)XNKz0-?0)CU%JQRJN}C`5*e#AsbkK%|7nXw8%r`d zCsfDe-6F(qMnGvn`M~kkl=1kWdRHA$AFus!W$X<6E*@>tvg19R<+%9>S=Zvxbh9(KDnSD+Im24+S zY^KY)A05Slv!VMa|}j@8xh&T;*LIk#bOzS2W>>WA$^GViUd^4$k+NVo1O#<-WROU#~! zFWD3K3!vIOZLYaxW_U%JzMm%TKI?bO<<7&n$UrA7h>#uLz^s>WsqJ)rCjW}MM~tSu zhy>tNP|WU{tnfNRVyH>soRqo!g1Y@GQ|GFyjH66kS}`6IHfOYMVOcES=0)`PLE7ST zSSU@4z9+}T{UZQg(77LiGi^5Y5?EFed1p$Awh}u-9P&2Ki84Y8=xEEz^1d@iO3Skz zyH1%^0vWTC?m)2h!FZ9pq=DE#mcN3WuMAnS3%;>G@jUky?BIy0C0mAOEjO)$;{I9y zm>=JdsL(w?DX0=~g2GY4pkA&LhyN95*Qt1MRIk87v zq)IMR`nN~1L)J9`J$E=88dKF6RU2l)fhX`TPF(OE*7*w=axw`6rmlqu#C{@2<#~L}C#sYNi9Ag|I=>R_ z5HY-447^Ien7fA*oPb&e<{zC;gX-qb>-p66JJXKh7G{Ei4Gy;hY~~vbYFo85B>9B+ z?lE+GeA;r&JRvzScj84GQ3)#_dY?QUt7F^1xIPdXMO@T^5U*bgkcxFg!3ns#FEtZ%Rx6smJJhvc~M zxmCz_?vCf$p`xwUM<|warFAPP-a{B(onKs1R*2?vs zF^Ap{4QkVj!0J3f4npDMyev2G6|jbq4$X!jJk8^)1Q(E2Y1XG0pXJed6He6tzjK~? zU+*T&DnKMmeDic`O}G$l!^dZ67f25EJ~kLa*=(Eqc>lC@R4nCr{>K@{uXW{fG4HH= z9}e8V%$Wuv>}1+KEArmvD6NC~EB8ZAAf4S~J{_{r(f!^m1pJFO-aV$y>v}aw&F;uk z)M*=(7|lA}dW(-UW6lBR^>+P++cs?*1J_AQac7Wb<27p6jJvlayHn&_&cdL$;&k%4 zr&$PPjr}47(A!3q2IUy5uQCN(-Y=!@<#=~44a zrB6BFVWnIpD(lS7oEnEkj~Nmd8X4S0-% z^sEr@rB2~0Xnt?1YG+mBSLtq|udWi}Sy(hIJ-1s>R6A=1e{?=3&(JWiVEDSyEx^1l zixC;pqy6(*@*Cva@fu?z`NPWCr2xRMC2|T0Ln=LxM}b9c!(y^hb3X#wF&;(R)2~h4 z{W2AtcXD4J_p%BZ09JX$9-7P%#svBRI-Ntr)?4to9#6AVd8tKI`Xk4nAU3mrq4!%XpWwgRKrHo!qd9lfUkFSW6nCTVGwRDl^xTw$q71} z2^21J^a#M=288030Zx84&pp2*s&2HZB4OH)b2BDx0w*X8x#JU5ES4WBV!6A!H$H+D z-14sUgof5i0RFO8N<>OYR{HY5XP|uhQFw&~f<^cZJUyECWz*Ib4p!gc;(S9{N395X zhbPS?3bbvl7b5Jbo+q{UjTD2vbAATvdhPBU+_@#rjfo@iFJolf^7|I{vM;H1s`qGW z)NxAAbTzYJgll(Pq=oG(JK8z$JfBtq82SRX?OPhD2FYZZvMDz#_RXE~WY;i^&I@y0= zzob-#S;6JHzj~2`h$cHqYQyu(?Xwohp>2I#u#AF(UY6_iiOT(?XKrWcnR1qA>aVzm z$uJ*j^$iO@%qEAni{tpH5rR`@ai>3cCjG$+1E1fHLB5b zH+%=c9ZWj$7UTD0IT`k5$K*YB6(HX+HUjJxjy@}gPk(oqGlg8i-;>LaYJ1CnR;FVx z`UbPhi4s=7NP)$Ke}YP`=n@v(p6t^F;EXPyV&dT|mI zc;DZEB4V)jYsJv;{RTp;r;-UeT{0i^dD)kM zmm!J+@+?|C`u3e=a`fouk9|=D%%+?L5|NR;uV{$Si7mR2%}hhSj%RVn`CSruG%Tlc zJ^UWj;u-uJ(a}kSvyD8j5FyG&gncHZ`6@ItiojB;?`@R+uF;g5#+rtE`~4N4>z`4` z{q2=J;8b{RVL`+F&iknCpnHd&>$0Sb2cMRYZZY@ASn`aNcv#9OOQ$br(}3df(f9E# zy&LgEaw5VQ@k#v7ui}#ovAiX9y9m@YsbKc8o|E-p21GkHeENmC!A1E!)6X+5mK&~C zh?24d=FhpFWzgG=x#m5dIXjqt7Mall=G9!-#%R;SK4y=&lF&8Q$#U0NHafg_5Ku@= zZSoAAKx~tkQ^xpm#goFYMB@oL&N*;;Gz#5sGm{686{i>ohPgsd(^xnOGj5Y1tulti z>j6YTvB88~Zjg(6ctTetPiW7nt{q7wP8LPiFgsM}rhTrpB+_4RHe7pff6jZ@ z0X0{tQ-81kY9TP-%x%9cj;$)z4%8^mCVh)bXOQCWYXgbnvDwc;zq(^!+0!RFs2b#1 z(1K+q{cVnvFr(v>uv(l+MRk6^QfEXQtsr~B9? z#0z2+H7GA4>a4Mg!_o*XXt=tqH4PkihZo}-eLIE@5(tmiI(*QA;41y@V!oNsBP1!LtiLl9*QR(7e#3DhLnq=7t`0a!7{8cJr zevy7eyUn%BQBN(7{Ziq$6Yzelx_-z;g~)~hO_SQI+6EEcmL2kj{u#m)_v1}docqbb z`>nro7{e^u6L ztfqw6jp@Efp|zqxko*VociEX_t_QdXCQY*Ftn?GI$+e@l$ZRfq6w1)Mvw^KRJgHs@ z_3Dr}FX2My+zLY)kCK*?D3) z%b&)2mAzCi=7%mjzL#qHT9tk~S5@uV**ettxu{{LD9ly~e?-(jM>iGYn&nvaI2rH8ZnV^;P&gHRvmH4lAff~N#B7(XxY|aeg}5K6)$x6)9Ssx$i+M>< zSIORbBDG?#8 zxV)BpiGPGhPXmBOpyq$VK@1p;uvZOs@pvHJ}Mg+%4u9juZ2 zgfNTcXyVV?rTy84JQL?!f1lb@Q>E_fNx4<442^sF&(9!CTa@K;e#9zrYU~J5jW!=o_n@W;AG(b)y7RzTQ81#^5*uhRPZPPTd z*O4AE_D*lUAKyA}|33q0C7!m6GAkESL<5=oGh*m8En8fIgu=YBSXNtD%*f%DFkk>| zvd|9$5HAttBk!xH<-gx#y31MDuXMI_)s$~S5*?e|dwZ6mIg z{qKjD@qfgn*#9A_UwZU&JoRWuPBMj`!~8--!TkqrJ}|FWr48vEe_kfxkBqU1pSLP~ zWwO`H#~-Syq8ev0@U6(vqJko)n^Sg;{+<`TrkVc7Rk2M}q~Op6n+kQw$0E|PG65kw z8c?-*R&;Y&SSW=6o8R9HX3YD?$^J8;wJ4{e|2X`9)3F`(oFa+MZ3 z@C!=7`M22+d}tGY{H87U8_+`48LB77k1fLKx0hjXtbd7`_KtIjPqY3kTgk|4#&7cD z&eBZN%SfqQoVL?X?E(f@r2MYC_&%>QxZvNn`zq=m-?AWw_+|`3_x4yW_IO2B{^ZfV zR7p&%Na973a{vB1exJGw-BoQKa-yWuRJGAM3o~3HJ4axuBFr&g1?g0Ak!TOG^#{CP zhtdD-4+Nngq%^?~qQ3i4(1AJ$J=rfJIXG{yd>MtzR%>$!A+M~v?(MF2ngnc;Bi&sk z?QxnU96lo!ljw1;EHJ8G`Q0P>)Gs)DzSG`nOyYh(T%?6x>cz`{XSmPtztHpU5V$ZX zY<&vrQA2Kbq~F=!s+o7y89(BGq-l=q?`E?|@6Ii4Z_41#@~41*>z7Xcwk>U?m1(>~XZ{Xo=6}aK!WF_&Q;E$iiF1m#m@4kRJjDqeSJc_b)J$I! z7pL0lce0`k%9d$=j%|5Sk+|!L{G?2Br+RLrsN9c3mRmVANqPqblEgO0P3@Im-1~a1 z8BU+zag#SRXQw0ZWcn*8bV8T=C5CW+<=44WCcBbOE?BEvy|8z+$ zIHv^;TrK4FS~6uUl7c2O@7Ak5cSRWgtJ6Y2aCz~!5rd*GuRFRXbYaCbtN$3SA(RUK zb0?*|m{o);Re0F?9^L;bZ6Jn4S^PTUpYZ+XcdkfQh$xYwl0RM@&H?{k%)hU^js{N% zSwpyS!~eX4fN+A!s2YV34R3JToHx>ty!h-@neSH{R?TiKyi%i%fYRa;Zgh6I`!M|V zSqTyUZz#8utm#DdIW6Ck{qr`$>)?-YY1!w2!%10OIi*$pf{#5=(aV-||kLysknw3C^-=)elNEK2=(kdKqDU>+@ zZs?X~An!g~2*;5+0jR9^*8b z+ozAGTkYF7$yOoF`GA3&lSJ@D>W~2p{Ij9}LRC4Xev>Ot>a!ywwl-*HVv;qyg7TT{ z-^l~v0NXmaC^vPkNNs9%tS^?+p_*lBf=pAK$<9IJ-fDJ1?x?i6JUI2DuEBv@x{*V+ zwA1!js$Fu_i=nDIBav2Ot<@YkmK#jeEz(rgyShG@47mPHRA?m+@ zT~hNL1{7T{2yl9Z z>RAycJUAM~UmkC1(ZoJDd3N^#(8HoS8G)rEsm?>0iG6K3Al@pU=;Vo6wK6Tc(BytW zCzjKYOJv<}TWV6Q#872ud+ONhqPwOmO+&5AdQiXKLEHRl^P<0DI&L%BZgD+(%5bbf z@wH`Rmw$fHAKm$z`|WxpcbdJ9q|?|V;YS}BnN>64s;i~0SgEVLR>+&rmS90g)k&p4-C$37MY^gC|HO+QRSJZsveo5^ID61_E zwCZs*FTTngVwEhV&XZYrov`wh-fz`=10@uG_D$nGp*-<9%2>#>Cwk5f&|xm3wAC$h zPBNge^?M{+#`!3liXIPkw(Rv;sNSyoXh)9V{ZDYfV;|)gM^mEHW_?+PZu#J}I+Zqa zw+HoF{ZEZI{_sIkDR&s6mc~F)kfO;lFSdOw*Wp;ZMz8Dyx@Z7Lz_DT{r-#;t*R6f;f2ywR!Lw7r7w1a&@}S73HQQn|R)9lyzC zP}FdwikhA{#jFbY<5hT1Bqxn^ax9sy&Woq)~-XGQQl<`ifZJX!Frv zPp~HB61DR94CERC3~xKpQYi8%+s`_Dp#fp)pZXB5fx!SZr7(PTS&F_PUc+6+uDiE6 zBVM|qg2fbIa8gP1PFs(!lzl@Cqg=5dDM~dufJGK zW+B3PTWFVA=&w$oKh+Eq$Sh`N(lNuD;13&|kjQPf>iQ;4({)q9Gwh-&@hMfG9ml#YiH6duz}bubEO6{#MQVCzO1A2AT9a(Xk4_iDX|UMpOnG&@t8M> zRB?SRcM)G~AtSA33FUHH%hdLO6w6AdHz}#QBR}L9h5x(sBVcK_{vX=zGODev-5Whn zD8*a6Xo2EZoZ_^&ySux)dvTXyp}0#3uEpJg2P^LGR^If!@8{WjpR?a{_B+No`Is@1 zkz}pRHLtn;ziaACv5|uwCS5-Oo=p)X2+bWeVaY(V*saQ=;B#fatv6#VQg^M!#Pu~O z@6y(X$;jUnr{Az?J`Rg(3n*;JaQB>$ndLM^%~)8YH^@vP!eb+EWPU|jbM}0{OA<^7Cki*ELP0sO$si z4Gw1Lb^KFSEsngVaeVO^3bv<~WhvunZHmb@{UnUTzyH?`)6Qr^K)j&$+eU*G?JVWg z6Dop$=Xz;@+idbdnN~HdU@*@1t+R)2R0=t60=Pey4}Bs3OLti2$^gHVpN2wTp-2hrp4xP60nMu%&v-Jp-X z%*R1Um_-$&7)TMv#yT!!p#7reyGT77xnCsFk!(<-8 zsYC{qI5|9G1f^@yqXD;S9Jyp#8*JrtDmH$k)=ta>zuDl#4JljNm!gWp#?_QCnC4y` ziMh6c&8Iz5-j|~8@UzgZYfi9Ou49qvHVF;z`Ymg0p(C5|p&T$)_a!R1ttnjtUQs~f z5YG5sY5zPhm@Um90kcm%f9<|Fjv=j-6P-%X`vJ&C!RDze9Xe z=m0c{9I@xElr!#Y{y}Q(N4vJtzz?BC+*k_mP4+XmxWXvCldxIF^z_vS=6`A|_&ZAP z*Rwpd)RY!x@@fh$gbUkS3=<4~l}MPH?6PI+MVds*QyF)U`wsRQeXw+6&9VW?-g=A@ zWxiqx^w?oUaComI2{Y+M%iWGkIhZ)^JJl`iicnG=hgEcA>vu63V?wNn>)4qnrVc_I z(0hCx@B6X?jrq>*gIdPK=8+H)x1Hteb?`KK7&_b>pV~-T!}@I{B6;&Q+pH)Q4aPn$ zm2EUpR%n#kIl*ftaY(kZl-gIhY;+~VYqP>jku>mW;m!k3rIJD;@{_*Ti_gwV5xZy{ zY&Bh%jT4W+=buTCjJQO9u-tU&^ooFRH(I_&oOMIuJnGMP%xP8YSLsbG7pa8=*L6}2 zU{-X|8ux?ZSpriUpZL`lyl%4t%c`5&F>-f5Yt)n3q9*^g%q~nwI zHnKTIvjNuWE(6w0U-E5Caq*ZrZq4G0UX7-nhuKuWdN^xm&9yL5&xZ!7$z6j$pyP!I zV_oU#GT0+bu8Yv@DE{I=^I;4Pja^HZN?#2f2A!cvKl@I{uaFQ1#>M>RWW{(cyzDg^ zr}a?X$%5TnxZAOp`0t)SvtJmP`*-SafOFRs9+$Q^?|w#?2fFH?jRHRx1<3;Ui`J4C zm(|20y1!(z)v9iZG2z!UEM7VLxAz9p@hjs z8DWJM60iQg0@1)83*@B`LJBg{G)nWHk1LyfgpY#X2*_u=_lQ+#Rr^e_b5~jCRVt9` zyGG$u41EuaP@0N*Xjcjhhhthe9jJf$;qnXO9PqB?@obkq!q4T#TIICq`V-NaLhG-$ z^%cz=7tsDVHmc;fv=CLA=z4>=`6~XKR-dEyGZt0H+2T53MCv58#fNV2FjHq4?)%XZ zvR8rY_T{%7aZJSm#=+gs4 zD@q~@A!z5hG{8}YjPz^|i=6PfRXXE&`n9b|qAlgRT-DP%w08qbqm25$JXZAl9`c>D zMbYhe!TpIFW*U9XButDmBW`|!X5V%UgI>@vh4jxd3Fa?uWTIrSr*O(uf?pe!TsGtj z+ErZ=>_@g|vv>h6`dK?auyPN{qyx`1(TObA7+nu?NqP6a8m$5h-9mOTy;7adfnP-- zZt+=)(AW;>3Tt(Zwlo(f+w+)YEYxKwg(th2?=Y0FVazSa!I{7^dwsMalw{gpTDYIf z_XV@JZT2-c*Y#BTG289}N(*9mf)af1pN8FF;b`n%1AMT=!Y6f;eDqeveNBf{+b+ja zjM3gei!E;JsU(1rmTujLcJ`csqBgf_jS-ttS?{s#SR6Zud*<9icYjr4 z+gq&T#Ro>Mo5Q7TB9pj7a{+=pV}Xi;jqfbyyPIi~&BXw*Rz2=WwWn1gn?c^+63coxh83v_CwDu3sKvgU$4@8Yi}#TeqWg0!c4v34LQ635Q>*e8&sx z0=Jy#!To`Gwm+Kz2NRji9Y=nrSzS#@uV@b!V*HjQEpjHROLJ+bxbHvBj&rcI1exzN zkamv4fro9Yc4OO#7rCC?j&eXp9aAyF(a9u(!id*J!Ctos*89wlcn#53&I$ly z!KTfkNaAyq(ltQuEOrP}rq-H*|2Ht%K)L?_sp!M8H7eSD&2PaUIhcS|6UxYqo}`rc zx?rt_(;poaW~E?68~rcR_JUH(%r*?%MW^A-E(H3;`6U?=^-@36TI^IOBtkx4duj$- zv9Xb>2OC)q7)Q?3i$g#Ra{@>ANf2>lsk0>Dw+ZTbXGl9FjqABZ9@2h*Y6_jWK6XdA zcHpe;5m5GCT&w6RWjB-bY@5L957%Z9P>f(U+>MkoC|sABy!6jkk_Us5_h+t*hSJu- zEZ$Q`cb`YDof`sYoF1Q9i4bcc0XlJ`&Yp6|Y)hblY$+x2O$#6`;XEmQ{>-%rYD`Xg zo$8WbF98i>zdG&q$K;;IB0!TgfwKAJe-{p z^bMm!OuwYb@cE!lotT%d`vVI36KW~b^UK3BIMRe&7W7Lm-SBVTI})GSJUBfQwFQiR z2FDgFXv{OwPO#?tjskeZ>f>VSq_B~Td}mPQRZ&G8mR$M)S8h2ee*A>DdVQf&sZoz# z-s-fP_H05h1B|7IaM6lG<8D$4_#&DehfrPHw}B~ex3oZbTE(BKhf6#ocCSjeWPCPaTdwpf}*CYdXvPyEeKblc!%EcpmmtFZYw>$8s^|^l1;xeQrivED#Oa*7DwZ`3q>PkO`-gYxfoI_5-?YZiIAU z9+v1el#7loTJODi_v0$s6BG1}c7LewLyr61LjU&n1bH)xV~8yK zkAqhBI=8pSmQTd(=QrqiUt{wkDl~Gr_KwZ(n@+*;T^}F0_#b&8RUH(=xM^LW62I}0 zS|Y9>izVYD5|c&Yr3SlX6 z6%=v=UECuoqmKO4g+B2v&>>;J$nGdN6G&b#}t@mi^il>B&Sl|Gk!24ieChq=2 zJrUjEw>T1NI|1>WD?=Wy;ctEQ1N>FkQ~>S-zx$jQQF*?)Sf=Nr?b?_WnyAye_t}D% zKKH25BLD@}i{`eN0+#RZ%^u}GiMKB-j=q*+dqeXbZA>Me8(Z3v5mePeM2^3ek~K3Mf9H+z;Sn$0om2K#~5)Eze<_>qAPF14YwD*ft)tcEvGIhIe&Zll&{MWjjR zDD_vo;Io&|!Jolsv&gUdXC*bUEshF_mf}YyQcFh`9ad}$h*LZs?t?B~RUK!%;z^Bu zWT+HLWL;o|V=>lbRrq+Kl_hx2Nxj29{4v%lf9_azd5mcIgb?u)^ygIcy5$O`>bm-M~n3E33?b~*w#7*e2XZqbSyHD2i#QpF+y$6Qz z&XI3FG!%1NqgV+=)YT$w8?5zi`Tn*MKVU$8Bo|2C(I)D4O>n5l>d`4)K#BCO(E4Iq z>n)hROXozQo|#<<99NfDsv^Hl)pWc4tagVuH@z$##RhsiqgwZIMc%{4LuRA-NfVV; zUP{-~b&Ki7!~1s-PwfP)y|yh1QOLPzS*Hz>rnDpa2@R+LVQJ3${1ug6fw|iuGaY+q z-1s|&T|e@M8PEW>-DUMO*1DVW&|=}1Ul&TF`U=2n80Gs_IdUBRN>a#LNzr^X?QbuL z4oAYl7~8yY0IFPy&kc*nu4ZwS?U-eoH?<;vZGr??3cYEsspI|c0?aC!Lh0jW;f zpp&r}k>}Tn`VfgRq9;`bxtU!*5%1NxK+AgViTtZ9tXGt=g&R)1{0~W#Qa_2Ho5dT? zx4d{JZzz1z4a5Y;;#D5<6*OWvraNvZ4>l<~>9+w6h@+CbZ)1)c-YRbCHCOb)0xs+H zU$w@o#PRnn%m2Pzr}2{vf;nBwIZ*}@#>%gs2GvIo{u$J8QIdb?i=9wwe&=RWtU#A5 zWahz?nqYa~-=d*v{xq~&81O1}%6`neC`il>Ax<1=B4}HF! zZ$qWL=~a6hrz_m~tm1jo@}CB@7N9@OzYGv1t7W+)zW6@IR*HLp^xwtANY z34%63(ZQ^!On#*Oj-wWJTRTg~e5LoJPqTQEdvW#M-lE=tyT=Sy83xOo%X4gTu2^nv zV>4S5BwFu{xi5v=WWzwTLVoIQgA>ePw?S-#Fq!wKryv~B_3F1L3{(>?{cJ9L6#Z0V zesi#sSWW3n8gtl)z^%0j3md~msFRv`+>xc?i0uRA8xkD$oAzskn%`|VrgfSJ$rg>D zw3KkBrh>JyFU9%9F6)~Z4jMPbt2jcV-8&o_-R+q{W)@z`^jsC!5yXu%_@MScwo7h1 z{ZeUL2;~HcgOv_i&_?Q@LBjx+~m1* zK~@n%+k!j!nyxs#4!9!1E~9X5{R+qyo?3XT*@#wqsdf zmd<*4sI2>j#@EK1rujb9-FA@G&e_(0JvOYMjRV0T3N@D)Z~Zv*SBR;_vS`v@hqI zIhpbqogGhb50?p#mJ{=WMh!GKr^UZ>+IoCGJp7a-EkfyNkeE~NoRm2|@r|=8dz=a< zL!2&}*V@lsc{CwqyQukUV)*;MdvnVl_vN`9M@9EqK=Y-`wsF#bxm_b@%8%!Z=OL!7gioq6QFdnwmg%2J3v zJ$(|ojR#w8M$EYKDeRyfyY%z8aon!kR*@^pK}Ds+dril!-!Lun$%nw8UgmOr<`(po ztMCj1Z*X(aqclTYuEpag*B;v6+&t~R0I*t$!4$Wr%y@Fdy@a&?sM?2t7<>`N!~-@t z(qWIK1qMB(XgZme$<$-QQm>i^(gLK}-7S3h&3(mkAK)6x0OSyPXE|aGWib1<#sL@E zEZOFkkBx`thv&|3Xt>9!YdcC^tcyQ%=;wIcRwHz(VgYL zT0Hu46Pc2y*YWvz4t%}ij3?yt*_f?is$MmAv52!;8l9#v?po$%2ID|ADbu14Yz88G zHAk0o&^aS2Ar`#QsLI~`IaqS>gDTHpI*TbuQOK()_HxQbwMBmUaKQVB+Z7^ld-)F) z)akQo-IBSdc5|LGGgmT~hJ;%+zP}8d7O66X+s{x-FcVRpi(Y}o;Gg#HQr1;xV~s#M zRq}be>g`lHJa7@vtw%9RGO+sITX+V_u8rALNq)AH-FwfHZ_f7E3NrKcbxDop?g=wP zJYM%e2sT$)$QDOBHZ2NM&CVcDC$L7}taZq%H`_pcn_%ezye#pu1Y6o&d*m^GO-!~U zmhEt9)4VnJV~eg=qg0Bkg=68bEU0(VmWko0ID_R6x`*VkKDGOL=*s4*N>TT0uRBR* z7CoJi|G+ZnE05My$a7&hcrI*Md=h}0{0uEI`V8j*s)vO8zkavxcX3otSF3l5*|*h4 zg>~8oG~Kk_Y5C0q)_cM-Ir0SgbEdRYEQ#!H? zp3d(;$!y*cP5pGznV{&`lnU{f@<`Uo{RDyJL)RZeyDu#?-n;|#)3}CkipciNmFGMKM8*1N= zX1E2UG75)o(zvOFd5ei%m5I%Y!c27pP4t_0Xu*+y;;cJ(ViAB#+vk&s?w#4WmZG+q z{C!KxdN^K*Ar!CIw6qfX)(7(LOoCDjLOj~J-SfLn4xUXqtiZ|CHQCAE5=B|bNGy}F zCFh>F3<$!zaL~BkZg;6TxLBSy@quV2N`TdnM%Q=z(X#sy5ybUY*Gr8!yJYUt>FEw@ zj9^N8X^qu-(Prf#QnUQ6P360XR5v=v)6y-)Y`2V}MopTglDK6za&X9d<}lev3Rtdh zq7q(yw@1zq&0c{u)gic<`TFhO`72F=8KmD(9rK~0u(Gm^CLBf~G)a{eJAGoN$9!IX zh>luwvQ93FTPfAb3$VlqT7eaTHBE)X@~5tf5D{|6=BL~okVvm{dNW4fCn!KBCS|BS z6S!p+#~E3SjOw_A49RDXEESrzNF1PcXv( zPtFrEpzcw*+eB13uBbT0CJK(wMPI|R%Z~k}>CVD&_plQBBx_dSggT`$JV zwwrxA=d}!|*fylgtnqnU*It{p%k0Iw@72uX2mU3eId*C>>7R(jSvGSnFc2y7AZ>Q* zs#g`YZ?gt?@-B4bZ>59^wNcDUKhk+_4d*ke=oktyuzu92JPjhZBb^HphKFtVG}%?N z0TW|2#Mbk14);8|qU{%?!|7e2Seo-aGP!T6^;@wxh#-vdgL4d-I5{9(U zRCnajCd8^!)u(@WjJl)8ZIyL{NK5 zYg;b1=WyEl$HnrR(dhd0zq`5z#U*ctP+$~|6vc!K$P>EL5W7h*YaTE^l4tw=?qfIF zdMs71Ho2TR=5<*{m-FSjMRB|#L212ksL>1q-Kr3%@42!GxU@-rq(`Yk5mSN@BhK|| zJ5S%mhc0NI`DDTtPj+`JJ2>#c06)q1)KDa3`#`|1UX~l8PDBXcx9K} zV#D(ITk+>}OG)3RDauoJ;WEZ5&<%6b8#wU=TiodLPe-fx6C;RsyDJAq)^|&d%dCs1 zrFj*RS1E3sC>Wv;hNURFV)e<=<^0mrtOJW+HJ^R2!0TROKD5Cf$Po>GEPWv&nk#y* zD*dYUmRr;BOGVyCe%#2RJVh1_T0#?ynpA=GQp2QArPLGI5?c-1i4)UfgDry9Io3LT zZu_O;!FM7~ewR;ePJ1kcyt#*rqbBQh^3CeTi&zYtm)``$o7O%T^NR;^oN43T^9-2#_KwEiKS^Ey*657xMAn`eyCKJ9}M zkX0lZu?mTY8Af0VrQ=9IJycJIm`EJ6Dy`ok7seFFQuGx+o$mykNRFqula<9+moCh#CliOeDU$pd8EQ%Z z)2zfsw^#JNt%O!Y5kYsan^O6$vYaXd+JJ0z=vqaP+msUx@M7r&-26D4>1gKW$J zogwB%KmdaEzH|}E40);1()M#nutHGIliJdwVbrurAuI|28nbM1-_^iv*v^iasE_t% zhA=5yZ0YW{U6$O|?P(qY>wHrXb@BYFyugzU-q~s`kMrNqHR2Wo7ynF`FNy^HZ2Gi7 zMfa^Q&p40^r>~m(aTxq=1Za<=V|At@oRF7QKZ09z@yX)Y{jd4xW5u_S#S6TLF0ShQ z7tKd;P~UEU=OdNxhVkx{fU8}R|BHZ%?wBVl`_cGiz5P?R$t85b-3dC!TweLrgzzJZ z0***2j`c!Ge@P_s^R~0e@zC&ock+dk&6nY;-eWuB%N+FdPB7&-DsDys`&YPD+Q~^Ul-O)bsKLe$RUs*hP)o( z2N8}VCo3R*QebE`tvcXptrD#+ee<>Lnexq&Gj1{^8o(A;U9Xr_s@YZRMOFD21l)yg zzLnFk;u{uii}w^=$Ln!*bmujl0d4Mi>L~W9LmXu9IxUhx-dNp1vA^v~+;ZD{{fXb+ z>#o2%`VB_Uw-AVVR-U7+0-P zf2oBid!^$yGJ32@AC461#GtvBt&EKS${N2WP-%4^kUY)0uN*2Q1=f!3YuouoqeJjc zTcu_({ZqZvx2aWQyE`f!MzD{kZ+}Yth78djFM6k1d23#qR#6ydF1;|Udt#1Ha6fXE z^XwjaJnAY<7!N1108&uEq_;vh$1CL|ldT6Y0+4p^IQZ0+_KBlW;TKp$}nU+2WK|@H;-p`a#@O#ZQj> zvdDF{E9yhOXyKOG&Imv^J9Awr8>S5EtctSQ1xNu89E@jiK3Q|mwp2Cg@o^DbGo$-e zZnAI3>8eLVW7uU{xws#~=s+CD1{kF=fiX!*@Qk&U#9goAzT+VNr8nFaNPmy;z z#`)-?Z#H7JBDUNyS|YG$aa$_zD>_)u-!m4cGBx_VQ`;XCqis2qr*Hhg4 zbuT>Nldo&$rLP`;%)v?n*<2sPo*yf&QbVYo$wM z3Y#zAq0A47(znI_N5QKXdz)35_&sX{*lpf@|9@-&CjyVNIxysm!SWa_mEDQ=x7Kw|Q3%E;1Rpt4P>0 zO^SnF@UD_DFNWK#Z`CovLamFS=*Pz zNZ9bjun?KyPw)Q#KoI84sliBC)*L*UVRW*HA&)+tD;Mtj*2KMNj|vG1$@f+8SX@l0 zc-8^3onvkhQQL2djc5}kb%{XMOqp?M-{08^w5q~8mJ>yxQ0;FEk{@iQA5oqWPurNri+;bk0{m}GQJ+x)knku-XpRtNK}Ib0EaPJ{RK?9q0$xp~H2iY0!= zy^oNfUNGy;Vyf!2Hs`U+(At4ngKM0t#BXaero!|Zo6-D+-yIjaRxEsT>Y1kX`-<0V zbN)r9`pF2E-)mRaW%srt-MZO&s?l;KpWb5PM0dyL&+L->*IVgV*Fmi&ZHo$?9f9K z$p$4IMYYmv;KrIXOtd;8e(f%ozX@w#+~bME!P6?4pul$;jT(k$ieW51N}Mk&g@LjQ zT-|gg`N*rAWVNDbP6E1$-b6BtzGTh)O+}uHJNhG1qeVqFz6U=(xd%IbO%(|*;wj*WbBZ&u+-;3TNl1FhXl8q~X^8^zC1 zlfn=BOo%Gj$@yw=lt>T=P!53BDJD!V5IFjWJdO8(ydt<4{PR4e4AO*2YHR(^pHg*A zDKaG|KDn(3l!h~tc|#&|Eo5t+^)bt;}qpj zi&_zg#*8)RsYK|nkJ_A>iPQbM$;rU^rNT;^UK7?p#~@alx$9lN=5NX@s-^y2eEGkz zQTP8I8%@?WRV`af5ZDuDt}pY<;yG(AmN-fC;r#}f7(^aMrr2k7sHP>cjr4Xa=PDfi z+(rdIeM6>s7dzWLJr2Bsd=sUazWxLN>@--L-^Bb-wGU-)Mx+d<7C3z}SxIWDaO82^ z1?V7Tz33j37#%X%pscc?>-5$R|7sw#Y_w$23VL`K^%_0MD&+LjHm|l@VchhhZ}+J@ zkAY2wtF)T;FrD%OHFss*YH{@#YKAt^pZnsi| zf3#6y34kvIU>21UdRS6u_j;^+c3*CDrYPELD%l_w(n9Hfg9U?nWQH}CYBrG=eDR&% z^$o{P^f}B$Fq8@DNGMxpmfGN9Icge3Wh}sX2s%f>WWKw%~3Dc(l zaEY22CjX6%HmsLe=`p}U?QW(gx#i~dU40?CE;AnRg?1DF(3LvE`)Mm4N1A2q$Unmz zj4tXwvgp2!jGyt(GeY8jsRtMsp0tL7Vgz)a=eii2#H`gi4KehzWaAZ&kA_lm?)pG( zF3;E${8yiszJQ@KNS&{^tvRP-D|V?)O3~0;!rZ?C{tjbh%cvoXLStfSI$xCsHEtw) z!=&D-k&F($_omv`P?M2(P-`Fn?@Q;;RMy5#pIMcYOX_D7eIImYAjL9uqWb~?X0=R% z+-i@d>YFVxwYc$Xv3mYki$S=5@{fVIBAYV${i{}lQX3fGkcXtcA=I8Zn&jCNE zXmW6E*5{OY@WAglL^9Pg{!k-zc9p57(%8hWU{&VgF)wKzC1#*m7*kt>gAeVsm%XfI<0h-VcnE6wwv#*XMPS+gIdBgp3kEKhED$ z1p4D)P%1g$i>6fHNs%3Dxb@`m@F*^a)m>2W{&1ib4$d~FM46Cj@k+YS672`(TbG9) zn2A*JMx4k&k;U{OfdvBVAD=Ra^iR}zg~XPa)hi>0!-+rJ!i6R!lrbt53+jwGR9eA6 z9>|Ogqg_R2sWEuPN$PWhO?005SS18(srf2~$-%vLj%H+C>NPZV#`SM^W0z5{6Ld3< zbr^Lnf>v0NGadmSPAo4^$W>7s=L}cJbdUUOAxj^_3AC#!v&~B#M5FluMLc4y8KRK@ zgb_>E^39WvHQl8t0DT1OKPy-F|BBv<|9Y*UD;L8d5>u_NChP#E5F%)Y6o)aH0P7D< zMwt>vgvw!-6Yo?TIg9&EXtx)nHfD#O&e>aBDJsAGUyRYOe#*`$w!P6DVdXNY$KYd8 zl=`5O6>ii=C-hOGQkL0=Y=yHjR*RDl@c%}P94|OF=s;@!CPp>CoLWp}(PpC_Cr?W{ zssd91#OBBkigl+18Q{9*AqX~&S0qtps5?Lg8tufjD{ypn)l51F37%40enx^G+qmNS z9~rriV-K)>0kDXf^)?Sz`__M)+17Ud2vrov%SqbXhFI^YHp ztFxZxy&(My?m%Dk=kfU;ujBc+vT9cO2*x`3n+U0p{PnL?$yyUoT>75@BUJ9Yw;<@z z{`(PdGG67r%4z+E^RKnCzn+||`bl2+rsl6~+UN7U#T)~Sg|W1achwU$iavt&vUAiL;McTF^a%3Y2>>_WJ$BOU zKRUHB8Xw&5Os!bGtZ;pg3tCO}vfuuB4SeEtVX4-?BGx)T>zsOW$adksH{A~!1l5}| z;Z!X-b!xwFI!@IYIJr#nrUB`COz^@k+ApmJ*KIuFeJ3Vpl*L;Peq7uCh!tlc}#*Y>t?rpIN6s7%T$vO<& z&nF42G`(9P{sO-1CkZOr^`R%5#>~xqL{sB5xfhYfoZv6Co5xpM@y?i`CHI27-^9{g z(bjSx4SmaN&$2GydYrdUozI_nJp1SOm@Zk;z4uYr1jO)smwb)_9ek&sbMg^(oCnzA zlpa;pvX8~(C=e=onD-3zBOV7aFh?v9Mza|WRy&P-;oNR{!dsJ?_cT>jw|ac zbpj^3PUzr@e*XR+e^`9@mot(hkeE%{nZy!o4L?Fs1tDift0!N_#h{j?i)X?W z;#uE^>k|_De^aBZQuq=52m_L3di^!p@>?5IeV-T&!{P~`QF8-+{ITe%G5%~F=d{`7 zRQbT(eL;5G?WKU-#H$noqAcDo{`&fB{MBl1D$@EAm}Q!dU6JCK=O@$_Uk`-{9?5hu zDzXX~{lWhQ8?jJRH*z^M3%V?oDq}ddz5yr_D6Ux4LcUr(8e`@lY|fkCJ)QnepB4aD z6$3OY7mLm(_S3fE2v|)182b5$jMXOfn~?Ct?NI6~?#pArQs76D|9TW)_>>8e5Sf@c zm8EC#d1R4N-F4js7GhthN;@v_eYFv;D(Nl|t29_P2rMM)Wzq9dqf56d?=~%@tvYWV<>55;D2dwvo9)Fua#St6( zA8|zd^~zXTPmLsdaS$}$7zMX8s-Q6%gL%aS!hLNf=3Rt?se2e4H|49HY(RnpVE9lw z`)#$+!4_?dy}NKUK92nlIr=n!msl=_$=|)US&PBYM3Sy~Z=NiKpBu7gF{jHwCMU1R zRC4HVfvPy;R##(xs0!W8IYMmEz5YY%I>y0bt;5*FkcOoLVGS~`wCg2BEpu&_M0;Ef zs*gSpVbFIBYY%zX6DLdE!1UW1;A72VI^jVdp4UhArb()FhhvCIhsC_1WYbS;2P)PLP0W2&xOZxT$E5%WG{ zU`K}NKY-#NOtvd&_1UTL#n3EcZ>9!+c{Q}Z6r@|J=xWvWe`wh=A&@5ASM+Rncpv@H zq}tMiT%#~l8w%|gJ7>!SWn=%o#!)-p9+KgT9KgW5TuF)us}zVdvMO|&epIPlLJ+08 zh7g#1nDrC#XFvfk`fDH=scP?$iSIj|-^v$f)Vou@>1H_N?&d;KjfF`SDbO%7O?>F+ zh{biGf88ptLH~m=wovhaXO7>r%U6oK@e3%KYjr@1@sa;H?<@dlaYw*kur;o@X-xTQ zt<`$!tziYR&GXQ;3FF6_k~hB&TiG5NjbG=}Nu=Ax) zXWjF%Yd2y=untBSeZ#F`8#aG%D#(+-s8R{jk=T(p1`=AgF16l(m_J(Q+gH~q0gQiO zxbp413I{T=8GkW}$UmzTFiM1Yv!37=9Dr3DB$vz!-_z@SDJ)d0{g_mb5%BbPJ{txG z9{1!l-}%3HNIC_Z#ZL?GGK`bYZj*{jLUqHNP}9(IsVM&k5{XckGPwKS7D*5PtFx>o z@-hcGCN?a?T_l_ZN%kiZU2UZEUR+$C_MQ3q59Mb%q5>xxJ^086g2w_PO}2TJVj9dv zJ~WTbElhMpXlcl6APsvF0GhF{N7Q)z5zt@&P12gRZp`jhW%uhWp|*y^Yo60i}L?kJf2E zC%mHZ>28%azuxa2lp%>NOm~@SdSW3dlk=q?PTXNBro^O8PMyg#(<0IbEjPWZob&Bw z5?he2r=h_X(li(qeMgS~^h#h|mLrTsS`H;o#D;C0WYeBuYc|B6t=R~v%m_oxC*=tg z=u_=&F+b}*A>8h^o$1F{Os?=540Ri-wNrq&_8$$0#;%ZcWd*}jRoq2xK3Rwgn{f0@ z3_5PV>l5*&m5z*`CDE&`vT|dI%)2swNB6N7=OfEvBsG;M>M&OH0^Q~nhmmNt+Jgn< ze->v_CIGBYNofVYq6@nOF4Ma{(FZmq*0opY;&N6NBeBm{ibojdhUi=S>B9qTZ_Udp z4Z4Hs57qL`Z;}u$$4CQqUxfHyc39ZmB>u8U`=PkBo{nt5H+eoaa|rzxh2YIs zh~`XPqhSQ@o0aKijrmKjunV+E&KaaHA8!kTr$0ET;^JER!gOix;BV;vA&Bvv2)Dcb_j;#LP=d}C`M)$0vGm0E2?hhu zOS=K6?QAqJruwa^pW$IJcbKqE%8!XIIOFL8q>YEJHO&Q&mjBR5X$>~HiU+LswN5Y& z23^kwA=mdQb}%rL*^AfXOJ*@8R+G>VBXbygY$oe#{~t5`!MG;Ov*_x>x!g_Ba2PWk zw2H?d^Vl&K9Ggg4uIHlBorisAW#wanGHSG3a}UyD24YY2vC7$fg;VDhd5s8Tvs=%c zGy+_hUtOs%SB@H~urU9k@}5h8;@g%ap%YYKrUtnvg+Au3LP;LoLcO} zVcwz<)&4uwv8(Q4dAvzrYsd0n`x`rb@ zd51aPMlguovBl(0caZ*f66roO&aTKf)@EOY61nG}j0*JSE&ueA_#l|I>bmv01FpBA zJsMkCAn%9c&Krz5^!(4r~0Ka$J|bq@8vm)Px$o zH*S|!5J!NDAKxBAd)|OorS>jx|5AqBv2cimE_w=-z6GSGASzROs;}+N>R#pQa{WtH6M^p zPm^aRBgfm^;&$L3)=mGSNTPhuUVHHCJM3Vdo^)Fj{-T%EplJJt-<08=refugr9d&7OyLkX#Z~ zV#?A)$6Sg^zjCQ5szJ`-zz2|aH=ubbO|x%E)4VdN=@E2)bx|bOk^dQCEr`xT!SKGsqvubH}^#{9GvY;DDMssvh}wp zaX4jvGz0GMB+4vjEXx-+jAr)#i$>Bc386Tgqg+_vmm{!EldZHb>HNAMzd75v8Atwn z!x0wdqwzvIDUT#?UyCVvzCI)+0TE_ga#vV;2eQapB>?#%F}6R`w71m&e|_(u*a2Jm zWXI-N!Ohaa>L0YI@>9Iqnc018Ea7yP+p?Y(8K?3^ltERDob>h~YY6F-}Jp(ex|M5up zlJ%-0vi2IHugz(dZ@nvl*rN{nO?QuY0~4B6IUuxx)TPt3b?*4t*IQmDfDy0y37ZKL zce)`70%`a3TE}M~tCX&M|Kwe|q;~zWcts%C$R|bV1pSC`^|r2F&ZQk1APiwZrOQV2jXX5FKw7y3O!k96IVXV0$*OM?xILchPZz`sema~DefB&5x1VZ$mNK)9| zUdv|b>4~`Il3U(EPp36DJ+Fm&l7P#`x^cLhpfuXcCBtzj9Y zo|=j9!vOPX(#eS~l))^DV-Ms|*W<(s1~$l_&Q|%50WmL?KPCzFeQFtg_^*cjX#V|U z0s3bz&Xe{?lzc|K+t3e9ZX+o27Sb@WjFj5!S-1ia^~8&hX1^!K73aM_G${QNpiKQh ziM*f(IXvQw*E%Wi)7++GoL&lOqTn}TpxW}P&425@TuS4(SkP|c37sKD=i;uY<$J5! zUX!^Ja*p{^rT;-XK-wv!&+so}tpt|Cx)J<>?LR&rK_s zm6%kqThlhBv#5GPJZjWb?nJX;xBBqU-e@szVWlR%Q#(ReeL!Y3gEccE+DUp_q8c(^ zk=&vR#$~x1{K*8aOkgIw?8wG-s%#tem8k3 zGWQo>nspah++g*e)=qJu3KV{;(8vbn)RQh0U zv-ry5$y)MeG?QfBqci|!5N$CUHlaJ6sMaEKDd%~EhauPZ1Fd=TaV4o{-dg)TH{+4h zmb>INE_9n868rEs#9YydKf~SROLX%HH zU!TK}!Vk+4VLgpKcikp1L`bZ;$B!15&XWfGy0$-CPNy(oZS(2qRPfL76U|!a9^**3wHUL-C@m0CVWBTQ1 z=yMg_`RApTQB8X8q#ptYV|BI8B8?;lxlP7s!7Tm44dx8Y$ zliqXBoSAdxnKS2ndDpYn+mEcQ(6zHkcCLN>{{LBaidOhXj}DVkfGiGq@X^XXtmc@mww*EJf)4&iU4#;cTHN0}!XUFdh;=l;Fm^8eehx{W+oVl~TIvj3x>`%sE0| zV4QQ-2QFnH+Lu4E_!mQOWEN__^G|0dw_<6jB(4+F8C4kOsz85{OvPH6({9nE&xii(YP&BbQi9n3g)2qa z8yE{)vfM5M_j)N;^V~b!3Kw$cJF=0oeyLu5+IvVC%egzmAG$lhPupK_)ik&!h~x zxgFp3+dn>IZaFsCH~4iNQd90kCz?6c#aF!1f~1{lG*uqvPgZa|Z5BN>d^=Fhv?uWS zjeTow@{24&YC+(0n~fAI0^)@-c4;kIn2qev)?xl;N@@^&W;FO{Odi^H>6thEMI~h4 z^1AyX!k=f0zU4HCjdMyaE^Si~>H$z{vRnz^w`Nq41Q0ii_@8iXgUZOyhY#lDw9_#f zXfqj`I(jbNgg0QQ@?>npqYy3nE{n8&2p>k`T-H`$IF@ z#*BYwAX=F^r5m+UZ3^t?m&kD0aXxIajQ@V_Ltn*Eo0q>gJdW2dZ|d=^`QOJ%+u&Sr zBS57V3BB@{JH>-H^x0_(q}3`eXZgIL>iuJN`4sIL)dcC9qvGc2i{DxJauS7SITln! zzG-~4$_+V@bEa}NEWaRll+z0|x!-B-tAI!j7Td{b{;c+sQg<PLpDrOE8TJ_Gft8JZ{hbZs}uZ zOtb+(Lx~%1`nHn~w(ZT2!;50dSdV81zx+%1lrugha=- zcK|W8i|kY~`?C{Ua{cM9epUuSs(*t@tr3JFxYb{tt%MNONtoSuwH~DYKq*(@Cx8d0 z$SrbiyW>B}L}1i6I|{%qFi}2btsmvn4MDIFfnRQIR9S;dAW<$3zgDl-)8_W)N)6zb zmx~fV)_C6Qdg*&JcUXg~zW#t)noFX1U_@%cuX?q|T5AlQQZ?MXsw&nVneO-fc|qjb z)}!;Xp@n0t<~Az3V@_jbBN$eqlAp2Zq{E5=>l32co=U_Y%Af@8PE=u1m`5oe3{g-` zs}7zGhl|I=OdZ||LrZisuoWr+(Vc+}oty_xIt|<%LM!U0F)0WPb)tNYT71C(^rXnkLqty9F;vqPTxSAEfKwsp8@tnI%svr&V>6 z8}&sPC2UA{jv8UbXRQgrbd4+Y$&Up1?q(tuIApm8Y61->$9`0iQ*!(uZf^fV!Bm_z z)b+hg`pVgQkji&hfD)C~t;mZ0ZIm9%Jjr`pC3E_B=k6P6($8I_CREwSnms&CUyd^O zS~30&D~TB5Dw2>kjWWp7sFDD?<{t_{=8aQCQ36y7vMWCU%@i;C0gU!mJY>kvQ{PNa z^hkS-AlZK$i0|S|{qp=XaAID&wtTb-BE?s1M9|U3qFK2ZONTVyVoYm$^LZ(`W-P&+ zZ}xUe<1BwA8=HnP4a5mYS30=!Ik0Y7RJXj_U1~q-6YtFWGe|SBb{KrGCx;QfC>V6p zC9-zFT$BwsOE$nWs#>u1^PF1($W|?^30{#ygr&g^8J>MEx7j`LY^h!?U%}kKgy;y;SjuNldB@J!SHHOG1XZDP7qqsH?9O0tL@ zq)O(uf51B2@*g~jxIw|;`74-z3r>eNl7LMwk>)7REPQoI~NWP17sso_nMVXYqo=m@n4xSRr- zWVUex86yB`78LlT2@o+4m{}&;=1r}Ig9s%1^N&T&JS$7XYf{=_#ZdLc{C+VuElvg` zMzhaHPi7}+Ik;@FX&_tuw3yAd&0Ci)9Pnd#xJ#%}tp_@oAQz6ySQ8YfBnExlSJ(rg za%k}$tDekgLZ3&B-hTySow$!#f`2lgB9;f9eo;Fh32S4meSWQ{WYBC9>-zfYp#X@; z^r^}R(X}_Z!pwlyh4Y?9HL&mPL<()HSTe_2ao5{7Pac_Y^T=+};?RiJxS9I?L};Ya_6Pdaxt$jM%X z;w<#vAKE63&F9@fcdu-632Y{Hr4~t)qa85C)9>V2C;Yp%>xxgPLN&`?VQqi14j7Z` z#xP$pa&}8sVRsQhnRucwrLy4(sW_qK$~20*ls;&rtJlA|_cp4z2cZN`=8T3q^=S`< zTF1!CXqH9uhwJQVY}jqxYku?MU2v6GlB?-e#I&a#q-OBoUPX<>M)>iDKFrllg{zRE zYmq2jf7uTruIPM{8DIA~ud`C7gy`s*2+h*C)io-3{M4&YQQcbB~`=E3UeZ3B-UDBeLpA z<(4!&$6bH!!tb=$w$51=wEFq%`9ne<643s#B)Ta@dXuL$<^7;zke6a$N5}YZp5s_F zWt9DhZo5zu1?_0e?t7TQx+*rg8~^s3;V6fU_37x<{rA<8lKNOi2b zYkqfq`eA0KT7;$ba`|kuBgIA-0YM4fazCb(h`15K#ZlbTnd1>pg?Gof>f36@BHjvDIXW~!d{2+`4ZyJ~!?rE~^g6V4; zaBu&<-B9nfK#(!jyoxt-vf?-?0Q9wX+LtP`alT8|A-Pti;$1eg!8hO` z_^PfKx!3ivD#o7PVxv3R@oJmY)8Ugtu_TgUbk>8;j%_GaQA0z<@s6~i3srp=bi7v&>VaqqSlVaRbbRK}-llY`b$6m-r^S-8+)@pFcl<-TuLd-%O|+=6(-U8G;O zto1SH2Ko$H zEU{3#jpbbCRvk(Aw#|*E?3JVHZNwQdP)81QtJv38Ndf6GbAPJXAJBm}mKW)LKce$u zavq}>lAiIn)IuqggZS3D%~aEWs5F1Nd$zlNtLfWaHwarFz`74UhkVD~r#8uMj1I$H zsifl_>SQ?Z#lCum%7{N=^>#nCn;+@8fuva^t)Y7XMj<<}uHoy((I{k=61MVV^NV}5 zvDBSz21)fh81M+Mbj6fe=0U;@H=duAn%ox9dM{y8D1bD;YuT5U?>NaoRW@8tUB6~M zdDpNmJPhylNgY`1n^l~hPjj)=lFPB+i&%E1g=dQe&9}NMo)pZDtsq7WXYDXwrHI@| zB5?{ye0I0XHySUSB@;! z4gX;3c4=2Tuw!C(qn;o**NlseXV*ohvD0N@okd9ZO+UuQAI4JXRiR3Va~!F#Uhw|j z6KTOyr6YmaI8@za7_a|GS#u&6r>m$XW=)r29rQ`g>CT>6sSvAAjFD?TKV61ZkqNUS z(x%%!D^A-OKb!rVDU!&h(|X@9Be|+*LKb})Wf*gj%bH_S+U?Xd5o%%vuC?Nz*^ouv z*KS#Cj;4IXJ+O+oS)^3+`f2}W0U23Hzf2}?K)(!Y=y!_p)d>31cvwT90B`}4qzhC#Gi1VBw)+i_y2-V zVl&medhp1&S^?F3(`0yrpH}`!VV38gCi`Yp$~qX-$Iy|&6Dx+=+v?o=)9Wrrkw6bg zDNZbCSAfm*gHo?incs(FsGAk)<~CvAfu{(jOW}_|TYMqYFYIKBNmUhaHf(Rj0P)(N zz<1*pzP=2din96|JNN8Kk7ixyWcP4nO#-0-XDJI$#->)j1L0BffW0qi=B_qJsHacr z{*PlOn|OpSu?9+q(QLj?C8{-F3)VCMLiA11B#ij`eomy!Hj?lapqI5i)IS3BaB0Pn zrGZwP_+OPAz&s}9Q?amWLYBwJ{gUIPcbmspfSRbb9Mf3>!n9i+5Ry* z)@NrCnC2{-?W}7!iF}vJ1%gL!7^4~0tLQC=tDHW z&!*xv<{b9pDH?1z=Zh|o1gDAW*(+<`ojrd$^p+#ZZ@q%@iHWK)WBwn9bKYm5nDLr0 zzHh0|{N_gb?~KxFea0vH3PwP?;~hXxVT=g}RWV4c`dJEx^d%WXjyNx1S3#iv_taG^ zwIal1pTMrw&3x^pHb;3Z&2`T6^Pb(z>@qLx6fOnYljVd`|I3cjl@B&6LAG69eV-yU z0R+o#l*io6l5$ES#uJ^QN>OJdh2Fs7iYrI{R>hkKnHQ1rwRVG6idtqUu;)cd@EiN} zeB`y$9Q{lT4qP&l2a{0zu>)MRD7d(*Zhz-OCm2Ga_+J$mQ4i|noX@X+MJd33>|W5* z-0uR++WQBx!o16TD9$zSsfzy;ilzHKUmaBGey2+!xUl^RpmwK%uj+pP1cBsFBD1Hv7@vj5yLUCk4Ul#MO&JsL z>8eD#ZpH=D^R4*wZY*!{0gPX5*`Uhw4{$TItwzbH#L{$kS8V1R_ys@0dpJD({lCq5RYy)(By4_Cz&aAz z$lTO}R@2|#f5H#n1aBw9oPNGN6~MdNPRRESI@?l>}*ieQc7-=4bDT1Q zg3S0YUg)sz?X`2Vh8N*oK!b03#d zu*?5&cgmsDf=^7j-KaP{shWorItleNrZF)O6(iJ5~VxFYu2g^qdVB zAa(ff{wCgc@KoJXi(?bF<`}zlGdInhwf&>kSUXr0pW7e=&XrQz_S)myS^JmR3w=*P zEgHui?(Mg9d$z^b0CZilj$6{v9f;OiUQ*183{UW3{^2029KLu~IkR)I!%8x2WvJ7( zaf{zAJA3&<>T$Q%D)NBu64Y0U5ns>3&0?8b&jI7aeQ6wQd=DLfm=AAOz+9))C$6z) zfehY?h3IXLRA22jtE;NyO^=_EWBk?ay{vn$q6n|1DF*JF{gfo+nZrLa$0+@p%+*-( zz_EWo?W(3T^IqqO`pq+a)rX|dlF!7L>f2OPM7_&WcnXgY1Z(>UJFM) zRp&{UU)MJ0{!!()@o%cMcTfw?MaBCPBZOIDukFUSVk+z|I5!pMigx8v?3!_STmO0n zT0#5)%v$$gMKZCqP>oO#2=h!xcM(y6S%F=HE)Vxtn{kRAwf;^jHJ>-}FWzU6mP*b6 zQvWKIZ*(r74wotLm9GV zZE+m$SL8)zVkSW{BUM|YO<)4_@c9H@!>0#|hn7*4q+^Y~^s3!>t6M1D)EWY?wJ11P zcd+AbiOH6Snm+B+Be+U<^*(Jzk~$<%8C_C}$;eDs{d{g4eL zY`MGr@I7Y9ISD)Rv$NFR>EU7P?#xiM)jq0>7#Aap=DCG1i)TibeR-~%m(){4Nez$`T@ZfS0tb-^Yzw!~45e*}vN4 zGN5s8LXZ)wQSK-|g$}0Q=CypfX|Mu^tKB!|2pNldIJh6eTWi>6r2+r$^m~)~PoXjX zY&~^Rn%7|g4ocNcEK0DM@C^hK?6jsz0^7GaEoTc{x{8OBFehY7@vYuELUR{53kJ38 zn2P!aIf$R!rFoDs0*~NZ&BK|$fs%afSgz$94JxlN{^WGE>^DoBci9Bg(^)znN>eI$ zvTKV;@Lu|$=k;Sh3?!x`Nlg)XLhk^|ogXoRdY9=$Pi3u*49)8f%VYPn$ucD5i2jZz zxeuoimhk-MNpl3l!Ds zK+sy`jH__U(&+L;1i0NC^YvK&ScaC;sI*OAj=Fp*xyIW7#`ZIWB!Q|iSpz($gHOL| zq^l8>JDu&lRXe5&#p|eW1E3+7l@qI_T4mS%#!1U>>jH)uZFx^(s1qhg1yQ2{pec_` z`NCSB)Yt0$R*Vp;1rhGhcXQFjxb88}tS!$K@8lF)P z&E@#!HoEa#^a~=X)Q$PqA*{~$P+YmPk1Ft%u89D>*NN%L3_q7q zMpahfFL3?QbzMZalgY%{YwfRFV-x+ovPkXjbGdK3H3jDH5)KEor45y_I_KPhP_6k! z08XAYJhD=D5)ZF}d^lNRgOtW#0wn;!K(sG^IRx9TD4M!F$Eb-^r@T}5+ZRSbd*K_w zYFG$f&amk67-2GzL^R&W6sC1jeCT25lI1i@KAHwfqtF|(!ehq52Z`{YY2epWuS;1I zJ@dZ60c@$CIzByA_1C7$Y|=9Yr8Wr-U|9}8Q=qI|xv31z-w`f^mrTp71q5+gK70I_ z;K!P$`BAk^W&W`XR^co3=KDAFB2IxjZ>aBAs-v~%gF=TLwlT2+r#`|`%Y3%;n91lI zX)=tiF>4iBS|r{@v~sO`B3 zEm;a>%5wlQ!RjDHgUWp_<^cvljW}l#>o*@nABt8&UN*{Km0-R{DfKbJllp6u|zz%GcAhqy)V6r@eqTa(xFB+ z(-{|#16Wmpb@p$oKeZ}}$5X7EgIYv|5^jGKC%>k(nNj1&uycOu6J8qX3SJLd;TZ~A z`WD5OOQ&@ki+UVywvtnK7`c#yO49lvfbYcRggl;L4em1Nwv zr9w6h|6_!-1)?>iVU_73ko)Yj!|~Y&@YIpo(o3tA$wpfd$1+PN2D@JjxnuUe{iWd2 z30O_1D-h9ou3Qp)M2os3vA(-bM=I`Vj4M=~Qxrsp$F0>_%Ytj?FYoq*K|)lGuj%1M z*T?dtU`?m_CZa;UC2m?4fTNP!0`Nfexg!y(*vzpDb%GR11QS)2CGqKYAE?290vB5B zQh;M1Qpd8mEX`@R_=ei3=C?vBWaF%$k&jgen`?iSkkw!Q$P_?FR_6Mt+PnDbrn4(m zu1Y#=qf|VZjxE>b8^gdqbvsGqd0ybwYEhAkE z+L4n}G7zt0_IVgn8qJKu6chT1h5Y@4OB2uN213%#GEHZ(P$eGKj4{dG9R_~>e8C4#>4;z=!82&(_0|6)--N0+bAm~~K8~)+JlrpCh;P&SyB zzw%|8M}z;|P&R;>;3+kR4k>fQ;kvJNv&50(k9-|3^@t`_|*0JcKL4pbL?0O>Grq;lh&LN#g zQbwCL*x36Sjpfyl@k`>e#aM16nQ;>yZiRQzfwn!Zw8-JaF=oFhxm=|v*N5wL$g}V# z&(OK87yerCIWQcRQi^{@+WAKoz<)AGRbki8$;dF{Az0tk)D8#g{E;8)JQJ&6t;Hsz zc&fqt9eK17rVjO~VL3|zE8`1<7kJB+ z3f?Rolkjr%77nlL6EF<_)njL#ShcHg-et;u$i}WTPu%G1*q4dRYGg~UQd*3!MV@epRGuz+Y30g4T~Gl- zW^^1m5<*ZFeA=jJj= zT!bISRpS145NVn4?;sLxpLSKh^&BZoPZ;{jigOM+M#=IanlUDE%2nX0zlFzWt4m)G z&0XhN*m;h$M47eDs( z4$W^+FcYBcV=Y}LLgK14Fgu~!scHb-jGd&_{4>I0MI6*0dKi=NyYs923{}RgihbXx z5OV^UmHBl(VRyr`jm;>oNm^%{BLqcOPxFJ1mH6)#UpMLhoS&9pGx_Q>YxHYN_^=^} zWz7%O5cLOpA1Ea!8U?O>V8J}AZU`?_*7lzNIVM4NAVx%&-T$5=dnYZjid>{%`xOba z_E=oQ1BN8lax9xUrke#3BV95V5N+a%svC1KUlNPi?`x|QSw^$gi zCz`HTw6jx=l&d+xOW<7BE4?&fU~)^J9sD{{;<(AcLBIeK3dmS5tRg|4zFC8n3goox$Hr@r<&a?p%sYlwP z6Zl3b&-EW3yU%W2Q7mgK!1WXRWd|rS@xmPcnhbg`b4-ayeKR=!V>jWD z?^yqMINf)J_E_IFxCVaV>hrUQe+|XnB?{a47F5DgJoZss*!W1 zlgrXNe~&3=tL%cn#989``E0iK5Pe&eNsHEd-zfe$azdrNa1D1s$jSqq?UI6;&y9PO zvDu4b_OEg@q{6`#*R|7UBH+m^>4o@_3H1-7X~Xbf^2%vXfmg7|CUg&OpJrcl{r5Y> zmi?-9W!5Q)z|;w0b48Nh`be7^1#wE)D!7ONiK5At-$W7A3YP82it?)5=(ZT{^?CcU zVx{J%qb+i0b%AL_@Km=HOjaeUXSvBVxMlTXUiK3#Q8OTs&TtrFn`zbvZ>XY$3^Qn0 zrmiBv6CDexzr-F6MvE;w7UlMsB|s<7s@iD@J}|eGOI}wj9-#a;`l!Ru(MV!w-_M7{ z=c?q^WvFOp{Ka8qB7{R2X2yT}ec1ADn`d0A;--a8eHq?UHJuqn>A8mfmz48KA9=b33LXRD$RcY72xyIUl1}J-l8_yp@^|2b7HyT|sNTm)$J~ z4C5ctvmQunHP*1qB8Jzs)I@g8w4#Yb>yFvnFlvr+Y;|~s*rxP8r$O`U`P{v8CMKL` zPw)o2jp&9O2%35St@ zqH7LQE5gHKTT};==T!r_1EPy!nCWvHMLvQbL*&r}rib)(Wzu%f2)5B-1x0~|Lzd5a z`!Z$Y01aX#^52>D=g|sVxQm~qsGPvxrdn3!FIriIx38m~5z(pee|n&ORkR{!-aqW8 zZw$2n{kD^2uCJnmASMU>-m%)~Nsu2>F*rQgd5U-MNQAb3Y%Fe)YM|gKW=MD3gMa1H zl4?t(_(Gi)`eYM(-R~pEvOU|q|HwfaKRc@BM$WE_{F^y4e^x;79CswxoI#p6yr3>w zOG6JG>y^{!fR0^J;~LF@j=*Q6Ys$qLkbtd~M>6zEAWL$(6(WcHelv1Z?a)}CO^9wlVZbP-!%m5*YkI>%fWm3ZH-L)z zP=TtUO*BB~KF``KMvWn{_m5X&Np-_ zEp%-l67d(16L|sm&s~AtnaNe zDc<+o(_%M{as}iU?K)2E0Md6H{P|T#W!mC8ybRR(kY z0XF5s;P&I3{$8&t8Ee6oynfmE6ZX~czylR34v;2%rmOhMEQG>jdEX(xDa}jq(Y9Q? zd8yU@3)`HM+Zu1@CyD|R0=;YByP{v0LiPk)>@h#pM^3X>Brz&{e(0>O)W&dsU!*up zZ!j-$L^YI4WYrS_dsEz9!V_@9xMGIy7IkX(Y6vpa`kJ^KkJcb_?to&NfFOBI~6(D1K+mmOUepf`;Iin`&C6` z)1r7&i}p=&&3Yb$y|4oxaU(-E9o2E?nZCVvGztrNoh2ccesT9K<$Vrhm)sfB6%!@m zT${l?hX@%S%4$|ef4zX(ndfXB}x-=uTGv|hYdTsLnqOucJss6e}i5kxT`K|4DVKx^Lz^ZTkj+&Dj) ztTc^imY%)pxQAX`f26=v1E_Hqk?YC&hOObeRyC0}8j6EO2KY^Yco6WwG zx3}63t{1M}OeQpG;Bhb~?Jp1E;lS3Bh|>G&6?3L;rL-B>bRHO<3O{oW17ESf4LG|5r0^p9>X_&ViR=KUD0 zxC=6o$L8Do+rwej91*hSY^e7GrFn$$FW-Y-g90NjaxpTlj9S*MBTRiDsH0aWtJmKO zTgal`IK8t4l_#w(v?)T_C^6uHtvlJQf(nno^R*6b(HZsA1PIx(8|p*^Wqn+e@Bi?w`0=v$E2doMAw>W|DhlW z^7b=jx;hg5p=q|fOsaRL%RPJTyMn3n)RpGJc6Z@ZmvlnagLgv5`kKC2XI8TllV~R2 zR{vXa6jAYkM<|zOKFg(I{SkZEgl~6;|ohM2p=C(mj`H?!QjY!q#D{1z~{bk z{nV*QB>7HW+I7GKHeWVdr+7J1TrV3nY}J}i>AGY;jz2kO0xNE@b5&3J->4%1qb-2- zD$n{Nx;3X1rxBx8^gK1jrl4Btm@~Ttok*Wl`qybArCRE#n$M4Y)SSb&CK}tTLhpsm zSz8hcD_XuApE9p^K7+4Y@`jKsW(T*~BcPGa$J{}LLakoxgWZY=bEe34dl{4o^?j8S z=|*rAAK6rL-|c2!(_eOw7#CDwxZq4o4{Ya|)DISivI1@TxLX>A*p{YuTnC>NTvcZc zX5ERlSvld9YcASwn|5k%t3IT(ysTjC|0fMe#m@Cxvka}f$P*lt=k4j6d&kIu5UScm zSzh|9l~Mkfu(T{oVVlpy4H(29S(d~(zTsy*Q5SRiy5?fokm^rH(!u_{WKr2Bc^D#d zbzd^Kr7A^!jx_!2iMn$x?=xoBs{Pi~Q7(F^a%3S&^D7&3Klj^dh%SjdM%%tNd%ku_P zqInJ13ka2|80(7XDw-BrHKl`@J{7;Zu#34iTAXf z;Ti<3IpX`8(=a*P+FPIJIq>z2f`}g#LZ!1jlU)y9Q=hH%iwr7#qgFkv@zMO&5FC#^ z&+G3ignope!DmN)Am27E#x4AgyMlY*9BBifnAa7@3`w~IQp6p{Wsv5MQQ42v#aS5bvdFeW$%lg&C(MFa2c*DTp!0{|7s zJ3}9QU9GXbk>~)bcY01!hp2qfY*&6;$W&2m%^hS(@Zfx2FUy|fme-VCu+AqZ_-u1E z!Ek5wL=eV)tn%xQl)aBmfEWGKSYlTyTXY4V?o(E$Sg9z-Lo5zhr3#1QORAP@cn*R> z)Mj43R+^1pmIu!J=(@lsLhY zGrQljX}0Gyc!vl3$Mj}e(D!)mL4V1{QG&6ZbwsYls(xpsklw4HitQFq&T zDpeAcnpd*YD4yN)aJql=v|C>8{P)INJ>TUc^{^nwM88kvzjj9jCW&ff{{}ny za!~cYD`|r4|I=oqjQ8J0vPsJ)t7_i28d4z|PGgny6J>iwJN_Jb1#Tp8Kw)MQM10Zz z3={P;dk{&2tioJU7+O3QD; zHGdr6eR(agTenMBB{?m7!-4}VGoFXB%Q>teLXrfKv@}H53_yTR?3YU#N*Xr%+E7>Q zzE9DewFoRApA+lB>#?3)hT51jSga~irSRvwIJbo?+X3f%(w{7exih6ev zEoUVi1&Y3I=xBU4U-;6&b9Uc_Yh+VhyKL^Z{T@^3)HFRW3c!A0CoPnCqJ9q6K^)MR z?a1Er`x6Y|bW*%8bLAfjQ!F|)9hw!KhnJ}TwK*DmIAdb5*SJnd8><@dq=M)qYO}gL zoCghF9MWUTuGExDByu#2{s%ltw=8ZV;uFC;O5SRr`9{64K^xi_zlHr;kmwXq64@W# zLD9p{Q%tCuWOy7U&w9{urkO$(@)3c9_E>u zvTd7m$wLMKQ>AOu-zuP0w~;mQ%BvGrtryeo z<$AeCn;Ge>rrzid-~2oBsOo$0yh!i+yG@EMdB6Ml@OpFkOZQ(e#=7n8;F?J?GSCqx zAv87JayZ$x?pNCb=SgLBjv~oah$Kmx;%R;DHtW@Adwr>2wa^&z2ym3&wftRA|5%>S z!Scsnk3Qd8(k@Lc<}-J#*KPy`ci^j7+p)=yO|4yysPFNmp7Z9Dnr#)dH-vFJ4*{vS z_EHQ13iySIDJD27g|v3=hx28-@&zpC4Vsk|hCv^wZV0+`Uc9_6=UF+uu`JcnYzr=& zf5TID<~URwM7V0HqLGlGz1EtQt}oE+J9%~}l~VMs&4(Rc;-IV;spEE<^>7zD<&o~R zE%R$-@qId<-8hnnS%(l%RBLj5!Q64%_3mq;P7%a_YetyJOCkR7#&T%|I56+l1-1xw zq~r!iSMrqem7v~|0-tYsal!z<$M8$bXf zo1vL`rJ}{QqgP}5x|O2!UhWxJW2tLtx_4NNOBwCkv;BKHKIiSFYRu=rVs~|4m2JAC zC6vaG6T&_iWm}b*8IxIUz~Y7!b%Py#_J-yMFm@L0&-=()``Qxc_UOhnYKUMV6Tzld zGrSKA!*p%6?chmU>EmhMO6#?>;lc`RWQ_QV%;6nmR0(0_N^vc}w6ax9&je_i*U7@Kx z0rn-5qVi~6#nF+g#xJUY)W+Xd3v)`x9AZO%GwZV}uv z(atj~lqqGhhax6c=u}&%_nskIUQ9KV@;d>qH*xnDjmxQVCu@{!^PqgfF(ropbr!69 zS3Na>YqfCo5Teowf2|+Iv#$Rf9UVN4uG)uW1~#b3%bsb#T=a1FapG5)DniOUJhhJL zYdGhuj-bGfBvxWUC_N36S{eZrHiZqTV!8N&*vAr2*G%h`bsW zDc0j$9@8gN^e`7^mvVobwggLofI$gYy5$P6S{JMNsipc)PBVr^NzQFlJ(j^9V_Qu!jx z!O^yLelWTJ3Xc|R_7Op)=km4GsjiBZc^qJ&%(0Fe9G7i;*56|oW|Ty^X+QX|KS!t2 z&iSBsD6{u@IN~s>u97T;1J0E$12eWF4Pz1rb4d<)hVlREj;7A4_yDb%l8LeU0yu!+ zrs8`EkLcQR>b85@%~g#!&_<0w^_Fp$0qU-@q_FQ!xjLtvm2Su2en--KiWBMKdUDf> zlvk)qo=J(?^DSm*d@LpHRat>4Gjey%-a@PrpuzdwauW)PYetl4_Nwp}fdF4aqwN4K zW-1|7&HkK~2Fh!xDFCmRfjBb3{Ser0r=jSGz1quz_;O77NIE;BmhzzesD+@(pJ1`_uq)zv;weHm1dV~>7?9~3h zMvpFv)+UHL9)X~3eAK-O0sCBmj_Xm~VZDfU`9o4YQ7^YscHr;D-p(f>nuOo*m#H^L zgNJ@_eCbswt_Ay0Xf#hHa={vt*U|hFll@3M6?P2k1y*cLP9s5+slGZ%clYk%_sr8m> zUkddi(+_eTm1Q6m2ND4Q%jB;uLGAg-c3KFQIZQSfv6W6C6g#%i`XB9)IV=B%`ZjFy z??M5zt7dp>CS@O|2CVD#e^`6#pg5ZL?-zmv3ke=Hf#4S0 zS=@uWyIXJ;76}1@2M_M?(Xi(;=D`l`+4g3zUQ1jPMtHgwN+aTJu^MsGu>BT z-_N&+JO7Hi7lAT0Bi&F;eOI(zp|P>%f2oKS7hd^K7}D5g{x zstHJLr2A;WU=FgVpgCyNIl4BCb>N${WcXaBOO&7IeMCS|Z&>*vJ<{q&f!TZorPv}z z;16Fgt+UN@2=uyJU6s6_0^{c8V#vSEB4Sa#MLOZZ{LDd7CwvDoosRjo92DQ}vaKgF z0re$E+np(F`!zWr9;dz0cn0|dr>vu1;wmVI=^D8*X6CYhc5-v<@EDY3-O(M>{1=3b(w}w2J=F;XxAQ2tsrl;-3+zQ z(!Q>d#j7ILFH1Im2_46riqv3pc&kG06-2W-UquH>89Bl7_L+b+o-EOZs%q5|I|Vu{ zbHM^2+c$mm;34Kv6rC^8QB5_E0o6QWBF1;_DkY2!DJS>_hkqg~JEh5~dL&3#?m(8Y z`ugvTbaAfXw5c?Wix03ijEc(nTfgcCVnW9iNAN$N8eV%$l0y6R523qFI9TrvG-dZH zG3k^y@d)tV9#$!QirQk-u;=kTtW$%y@(74Dl%_L-BN~ZESXFNX3-?^P7^U}7X}=w0 zL*zgyjDo3ZxKq{%X4hG~mIp2As(jb!?vTM6ta`g(3ya=3z)bNvEvUcZ8F)7G+JF zfBhK5)Sl|XwaD0odC>^Kz$`>kw~{BP)lVGcF7VBxzR@bYs#*JO>L(XK%wU?>;ZKjN zzZkFS@e}c&md*)7m%kXDk@6@jyN8_G#gp=1q0Vw&y4qy0$aQ0JWAut@({{Op-jDN%oGS!&oKND}_9^2k7ZWRCU!SK(1+ z@n}T-GTY$4!lTgg)O{p)cA?uE1JwGoiN>E11s@k$Cg8Qg%P=iF5Sfc1MAh+#| z_C!BVJPy{BX!*cpBQ!gJtf;IsMpw02OZbL_)(P1`5G8_k*& z$)$?2%!Rm!>G3=>tFOk(vcxeb@ybx;jWIUAwcT{Q+#rF4vtM&et+?hJbr$H!HU7uM z2+3ixWE-=_Eloo|jLM3d;?Y^|li-m%aG}AFAC!WX;nJ_ZCtA?M0a^x9N&{WIKPANmvtA<%Fw-cE^UP@?*WAsuI^}o+Z7$6KMKM$itJ12a{B&h{EbNPUNA51NmAJr_q+}XE3M{(YWSHOegc@^Y&;w8Zp7J7jLS+TgL9#3_guQ4z}U%j-X%v zD4kyZ;OyqwdRh1XEH_G%BHv4OipYC}yNB8%h3fITO?F_|WVKn>C;h+E8~r_t0=|Eh zJb!;}!M}K13n78?{DF`tu)yP8v8iv#WnJ4NlEOdvS?%qA^Rxc$4YL3hi8Xx)dcz+g zPVy{t0H{c!^txhYJI}5*0d3vHK>a`u*B1o8P?{UEWiTfvhCObiO_$>{}nW9iIc9eVhxKW9jBxyToel9$nZZ zPb1vV!%ru|@P>jo#;~wymLf)Nh7O7|@_+J?)IM_7EpbfU+R8_2*GAs7pW2EX2zF<&AgB`oh$W02_UM!SSy?T1Hw%Zu2Hsd80uD+?093VYx=6I)k(L7ld&K7vG zXInkmCcS8kNxFIxlUE$>^$`NJNJ5Fn_jr?Ycy^o+2VQBz9HFRTa+yXR`039~q2kdsg{0-{Xuy7) zof+(`6{XU>CT^NL!qq@tCn68Me?`j_$bLXEanhd3LB!hYljaphy|Ur7B(Xb&HMnWL z3=RsPQeqF3s~#0;@Rj2=`%v3*Ci>v0SHg#)Z4UgJKH7Q}@E&7KhWwGEbM*3)((Z7k z=sudOjn9uBfeYPQKGDci^1I(-bbF*jZE%Suen?jqolibK%Im*ee*fOoq==)oU0Y1g zj%oJ8q~Jto4`*j%y@a@ZNM&Qaha}=KKH2ATmtXR}hPp-u_&?3=GLh*C-aFh`l3vFv zaX*Ybv0Z^4_vfOfucDBHCJQoy#$u9JvWV?ZqmEUP4omnwZhM~}iJ`o`a)6d36syvG z71Ml@^BnH4 zROiC0SJP}{8LEhA@4fecm2HzlYp3U_<`GKVjWjp)Z(S|H8$7z~3pKcEvCA~CdpnI* zI{>5hx*H|`2uJ`W((_vWA-#G+IGhd^C$YxXeDc^kDIdSu+n!9xpOFkC#TTBIwz!FF zOhAC}i!qFQEFhH*;R|OE?{4S_0{B3mYD-!N74eIJPsntIBh04Ly)Dk|0M`07%+fWk zQChan-3}dRmT;GYD!y;P?Wc7byxnmRzT}&jlMnEGQVAR!h0pA4=lHF;B0t+6KJb4G zo%DWhpPpS2cif(VGdS#edvt_xFTCI(%6yx_6NxE2B~S`8xu|hYgJSKlc41TvFsq#4 zu#%{2)o2)|sAWc)e3N~eTO)%Tq8Y5tPoqGf-Fa=#QGGEQ&+w4;dO_+w(KP#jh2_?o*|YrdkJ5@Fwssvh^&T{Z)XbpcbPbAX5N5)W{Qw=z?ZSn|GL9Gq zUFRE~5(@ewU1M>kEePFJ>lPu#=1CToO_<4`mp>%NKRf_TQsbx+^gxLvtl;#Lgy;06 z!smLtOLMsoTK9sppJ%aiyXCCB6n%(vd4FmVlwN&hvb9xn!9z|I@SKk z1+~Zm9msSWP;|Vfkw#a+14FM7tGoN1m)`@a#**!Q%Zw$#NM7Mz8W^20m?Gi zz`h-Bp*3WvqBo{%iRw5y5VQh*hZNR*2&vM@l;I?j$=2eW$W}V-9?9-0*pV)*q*AZ75l(tr;|1>|fjN>0kPANN8`J*UlC*&)YEhQkfEE>PL>6 zDfNiO;><|LmM7Siew^_=Qlja-0BIw%m`yQ@0(L+U`**oG%}T*>neW>JvSyvq{?r4g zj_?6^NX8shyL*VaMeT zd@#EgUhg`720?#2n}(-9c)Gx9v*!SPZaf465^IIypAsS>JInY}2pV-2n2c@0FBI}` zzcfR063B$2a4@Q}xem5X%nVfjpk(Fs-DP`q(dNl&oDt{heKSG`2U_yvaRXt8({Ms) z_#(weZ3;mV?2?p*{FTv?<=Yaeo54ZcJ0X*HCVA|2b3YT*TD7>{)fkhyJr&x+0(a(% z(410@-Omqa6$#?{cErKLhilqh76^SZhyDr6S=)+CtE6s_!#S$93gc378`; z)Pd=HJyCtICt919uo=nU@jsFow1>4!rBZYE9o!KavB~`LezIv)BqZ`fa+P}DN>zRS zIvjVY@!g%N0akN2`qyh@Cbn^z4B$KCgp|2~kBK#xpE+iRJMntPmU0pS2|2)Myf(}z zJfSof@+8YI@zbH#ksjjH)Cgq-wo1DU`j%0WTSz0UUVP0-24ZnB7Hcf|_&*hl^)P06tmG{p3$!#A@Wx0@21uhud?fzf6 z`wCF6RgBSbSVcHf*wLA;GQK;6kjm3~m)(gi$^4vG;}iAqgE z$}?*`R2)`qC~@^M>r;n8D;_~9eu!}*Hu*7M0JamSbTL)ay$g6@r)6&d)oTQgdla2o z?cj_B)C$~Z>^{!>WP}?huI z()MH@uTcNt3rzFdeJ=OBxhpBP>qeBGR~;OGWS5%|mp+GCk=4VA(Cor~K(;2fSR8vi zKhzho_y`_pb46u~5Wxce^zWmbl`X zofE^?-2M+w!{!0DYJ71f(ye;UWGHu0Y^-7ISY1VMP#>N**fcmsoyajQxurEnEAq+p z?GnAjtg(y&o3HO4<|PIkJEM>$O((@g)APf5W8d)RB+#>(`=sT~KC`0(tk}Q@xj2*` z7u_smVl#unGnjNAO*P#N)k)rP4A!WlnD93%2fnw2+Ccb?5X5XXGoZX8tYHiLnyDvR zTV4qm>~%+Z!#k;Ow;-j+F_#eXdy5z~ z6_ZRA#rbb{M!QEh5%#crd@f(n=e4WBW~9*|xeOO%a~LxiOn9|mH72y3y}mDN?hLZ? z$pIpH+vLIKAYutlI_vsT-Qp9cMf_51cs-1;$utx%gy( z$|ncjsK=UgNLLCrR93zcb#Pi5?P6e*vFye*hTG4Hl>gwk=-9stn}H7;3On<5k|m_8 z;A#o*?ha8W)X&a3R?>Fr+N6UNb2SvnI*6WUUI{2#C8z{C-l;1vR>H>;_v3fp$c|7a zSa(VyX@2o%`0WVaA`wkk5BZdadbbq>C zALWM+pN=miKv`&YZ8Gxqo{@+cA9x;q>Lm_(RF`L>mi?019chYQahp?c;z%!lPA?Zz zqrn3m7~S1&=!Xag#8K%#EaC0t*FTD0Gd}|tF^07Qkm15z5wnQSzx?nBrbquYrxng| z*&1)0)-~|<-QDz{naQgm8D>a)RYL%yR##!dErAp>y^izR?3g(>@OI?CMr zC2h}J<%lmcxbpOF6E$WYoTK}Z3*=aN>29hnvv>Mze4i3Bqi8zz9{v@nJ(xR8YNHm} zRb~SwXLjKcd4N{HY+RgxkT}K=r;F+F0g$3ti%lmFD>abD_`BF`5?jrR#H(eqZc-HR z{Ac;f*hz9$5UdKht-?{evRU>XI!^H7tcMp>6wizkwH)C;&7+$kx7 zkF`YJcXhJe5Km#T&3j3tUGU&oS}x_MOPAZ zJ|yprE&bn^)CX9N9PE$fV$$&&WG3>@oi`M%t|uJUqK|PEIDh3YKEh z6#LWl&`REME)sakW~;DzOYEj$&toP@vYGifwQzxVw<&@##_Hqs{e?bQ2M6`<`&ao2 zJ(#nH*npx0vDEWw`x5;?482C>MPaB}|8qnJ9i7tm6;Q$G?~haZan()wUuCd|y@Bfd zbHt0u&`NAIBZR)-{u3PYEt5`&h;n>f)sv7Hs4Ef-j?SSs3>aiO)gxPl4FP#tok#af_Hbs3{x?{-5bUa)Qz5)nj4b`mb)9>Es<6rnqTgm;XQh$Yx$4LA zmu~kr7N#5Js+d!OARUbv(0Gem%4b*{`|Kv~s1vJ+=iO95_x7KF8T4CFVv;c=mW=|% zX(~!0sn*#>=fzWM8H*E3)9r;N^moSsJ{o@Pr_1a3JFyHEjXLUOQ(qcKVVPLy5PH; z+cYaZR#BpXR#3*~-iS1|jC@1T^(L?hQn@<5V9^+3$L2WzWs%%NsXm9p`L0G!sW>#& z>bpG@C)H3Y6Y8H~DgHSS-h^#Cb8lVd(;&!u9kS)5;@bRaNhH`IwM54`^XWI_Ir((l zMlT)AuVuOTy?G@dil=Iu33WFyC^SX=6bfzPZt*`)Q*Blb_S`)`NM0LU%(RI`P6ROok!zD0NI8M@jp)U11zK~}C zFxc3-q>mfg@`Ksttd@U4Og`_^_)7w{wr+=WiW8<3ZB^kIwvEkAo3+&maDh8t%2?9b zpi3?96LcA52&Z}igH*Y}PmYb2Gn#D23!X#y*e|f7RNxD4>00Lmx<*rXY)o9MKv$|~ zA&~xvqh)igU-6r0rDF@ImO=kQQEIbKb5lxB_o14eO$5WewexB6j-NCGdt9>IC-x#< zp}(DEEaQ(;$UEa+TX<=o&dg@$`C1h2{Oz>fiP~Pre+~kwBjijBTMg9GahT4{?dwKI z+>7ws-W430aaCt%(HKO!;J^X{4?QbY!|vqxCJBbnWITqrBUl%Kw3p^%*jf_x4V~}k zkmA|L_AG(%Gqg-aRQlNm$E#vA99sO%cLggCK!`b}a+*}zeDBYQxIBB*rU%wcqY#p(8jb-d|B`qaL=qSo? zIeAgP0Yh~>woyn|^kz3KjTbO^_HbQ&)EsjX-iDXP+Zf*OBxMWt!bcJfFE>ZtIB40$ zv^7I8!zG^M44DygZiOqh$1Y8PiWO;WQx3nyIX-x9@=uZoZ{yG~wF~P%Ep7!8(=LQkjh&Y|o%T7%!?HUIFvySOg$*`*a}ym10Y zLDlpkO>_(GQdayk<2oe0t@_&ftB z^2+&+s{W%;ZP+PbepZP+>fl(QQ7<*|y}oQXdjyWWR(jFr+^c$Vr&AfigMv1}pB%9Y zCsV+v!|=@AVOFgd))LET!Q4$$AcX&fa2!14)XLIUFEyAn1gZ}Bwi+a?bU*bCeDKhu z&r+Qq@zL?#KCbCJ?txepzz3a#r>yjJWzl^(FSwH~wc^Pht$k&m`PpX^vyMZjtY?6p zr_DZRrW^FGwYSRQYNorT z&J+GwEzJr2`!b*n_=@@yufiRX)_cG8FI;TFa3}W*G9)=&23Wa!`3aTe0n@FV-g9C|#GQ(j}J9^AJ(xnxE>=D?c1~jkQv{Wy#{4<097Ir>nOvtu8exBbH?el4|Kzwsmi9Rk6LI$g=#F7B4j%JOVq(Q0wKFW##D% zwG$47lX&9!WB_e#WitGE;wCkfvSI9*s=nB-FPC;>VV<)w5mw&p6I!}_&47g00QZO5 z)@#qxzBE%S;n(pY$I+1TfU)lmR`qrnQeMpmv>Q*7zdV;RLOZ{G9}*}uUFRusF{{Nb zUyx+G#s*&uG1;CEW@|9o;EP+ zJMRlE#dV=$|MV)nD;6u5#VxBSlz@lKvab2NV}dGENYw(ZHrL!m@~NdphOS(!;c%3= zT6)udBVy@i0}8nAZ{=ePDK?d=Ck>R$zDAiksFyQjfedy%W0!6YVJSw=UaOMDp>VDC zvCyIhuERIl3Hjq*1}3T~bfR-EL9?M9yc<)NPx<{=D?C+(C#+wtCX7+W;CY)%Ry({bQqGa63OCxhYj}Rxfd_X1DSVSL z-SlaW0>sf;x;;{s;J8rax>{N0yP(^7gz28QoMQhzx7qB|&xQQC)_gm@W!xsPiQ@Rz zVQR8&tsH3`4$Zgm2Gx2)MKD+46Z_*J@`-b+#w0PP=W8G`iM6h)J8yY4 z0?Mgz0P2zl^p^WFMzq|Fp6MTP^;xRYvD>kvcMtut7%*8a&Hwy1>z)|T_TuEWBY}0$ zbfZ?|85Getp3R^#C%YIbm9f^eiT{f3a)_;()Qbzwia~((O4hNXl4xQ<9O)xuSDSb) z(Y&s~akE^~K$1=+)We5}TymjhzPI{lnnNIv=h=C-O8_-EcfIT2SC3K|rBC_+Op9Yu zRj!7eO3sqp5vh2Ze@eBmt!fW@wcM<-P{?N9?800=KBILi0i8&F8XC)j24xAnTSUzH zXGfV}9P*Yu8_mHO-9YHrAzuO#Ze-iCJ8=?%9T-OmWlshmYp0^|JH}GWl^~#0UB0{; zmJ!n8T)r$#lXW0G&a-=Dx_WgccF!{AO|#EDKwc7;zFrY03OShx+9!1jT@O`K8rba9 zP@QHLpN{#V-ttWn&YB`}9zRvw`(b_~!aA&_Tr*f{YPQ5hLYV^BUNgTzdw<_#&L4Aj zi_@l&;M?W6w}tnWLgVR&zhM$^3r$4v=rt}+0y}p#1ieOO0+AIeTrIQP@r+5%0`U#f zf2F}ZU?OxGp{5*XS84tj0gjo@M?t8%rfhLj+7xyy`407!qx5=1lrj1GX*-;>=()s3 z;Z>{Ub8jhLz&BUVHS@Rn*2j%oCNUfC?`(#n_)ycQ^YQCGWnuVaM~4t6(RA|cN zx%9eLi`Q5~ZP?pI=#>O5iJTSec?#S}HBTqY+qDq;cOOHspFruzP$vkyHmqT&y4bQTOXsEv)^NShsySzO}*9!q6*)jJ?OD5fKl|>JW*{ zQP+15luPjz03W!#y5l zU`!y%^CZ4#R1NB&qv*x|eclGqH1|47Zn@ZtIW+y_C#;8ntR1A1^r-q6ds>PeiYyYmn~uV3y}C~jtL zKHU`a4!xJ&oCM>ICkQ-?@jSO&T6T-H=R&CY8DdR8EFrq))^b}b+I8Bg%R7td>OG?@RM z%T?M^jWxa1g5&W_|0KgOh*ao)1#7hIwOU>cFXeQ+sOv~fS!wGUn?oIu6|%CAl;~*} zXd$2d&TfIf541C!o%T~L^6O!dhVxg5M(y|U%H{ihD4_3B5~Vg4Brp%&N~2;xNTJZ5 zZ+t_S95Tt2t^2UM6*sKg>4i%F;o`n#*S0~Er2o|M&Q(Amb{sgbZ0Wfo%6a84h zDs||ji?jUvXBBf7LP2Dl(p?v|#oWc6&o3d=I>!uHuP;f)s=M8KQn_8th!6tQhlIT| zyhmA(Ozt7$cDrsC_FMzp8_l|T>tpqV-{_cLzw?OvF}OBut^k;bT-=B79AN-0539fW z@II`*I~DN99?^}7I8=`7DL!<~xtQHgImZi$bv1EbzTZ!O8ill&PW6qO*$e#Nd6w2r z6D4BQiQZ03Uk*`a0orS#(ljm`O4_Tys!cZo^H-tw-XEc!rHVxbfzVMaJ0q*dK{Dk; z%NyJwwj!dGrjf0|^iPG8DWtIM3Njg@D^&Xf8>FrCp=Of}==DiD_w^H2Ns{U~XoyyC zTOG+%ljY|fcGHCd82*&fr54eH#?}w_u@jUSRn3z4c%L#|PkU47JSu3s(|}rKkklgO z)Le9}MDSLsL@k`0N5agTsmMN6W6lYNYd#vV!)A02PYDeAS8k6+Q}ppzI)Bot8J9e- zkqyN8EmChO3~R`$^k^iyQpY(n<(ESKpq$Sx-fR@9Hq-b?2d%!klFGemFC*_SKq0Zp z3u=yJfdV|pt;5~ac1`1mJ^2G)zCvOl=HM2o+#M~*_Vf6r&l6)f=zBuY-q)h+@>Fkx zM}O`-C{+xtRFUq>)g@r*3t&bYL*vFYw{66$;4SBH)vyJUhas9$l@%XWU_)fS&&Aw4MOx?*vLq%&auc z(#?;EE_fPiPAjMGQEn}aOjl+K1I;MyfJZaL>9X-t{`GqXI*v~W4C&VI^K)&BH-sX) zQ=|5&p3v9CS^))_Ii|xGT`Fz2{kMyiYmQ0SxymQ&S6u?8dnI++mKl_8G>c{^aJYfGy{ojP$z_4U>^FK4=~SQ0At$)>(yqr z+Zbv319|H0IqN<$I9=D1r0MzNor-6}%@BcH?SWYF_;=#9r41F<7A(Z?$@{N7_BrV_ z%HhB9@QlBXs17Qu&kF7zx`>+c*Gw=#-$Ux)fcy`?;VM+0%|V%P#;dGJZdQX)O`1C>EY>Bmy0*YW^1Ln_z$o6 z6KSFy={m^j-1{`;(dY$&kETWo3M%^zlV%* zR2OpNLz4Dx(YM0IUglm46;TAk=Aqi7X%};zE8f};?VAA3N1betpWu33sb>N_>qX%) z-JUtZlwv7?@v)~28MlxB#3@~N8h-uJ3jaO$9pDmk0f72!mfQm{zk`?i4MkJ&0L{mj zYMga*9`MAz-31q>*-*W^a(VbV2nuYO+s&eiFPg3{s2`2EFI2|6;P;F)TeVe8Ejs1; z$9C#~->j|p`<|jk`7+;#x7Hg1BvD5mVVWPJJyulv>CM_k0GZYBMI|V zL_4EDrQ)YbL>kirEUUW@x;#%bZP}qjuliJvRT*L`+1r7Ag;7#Y@1#8{?(!Gh?xpy@~z_F;J8OXzy^R7)daFrmoGlMzP=bZlC!_6t3iTeq;J?5FY#P50 zeE|BYE3IAYcsPW}hc$Ms{Y?^Jt<CtydNr&@e4i6|82@f)G$`gvI1{f3C@R73PjmcwTDr6a!&U-;h{?@DN@ zM7ZJ?j6nhZG>ZUBi{PpED)P{Wic>4S3X|_ax3^v?dm)`2Bcj&TALfJk63f!>9!9HK~KrU)pAjtV$F&)#{B~)xOJJ zE=p)i5~K6oQOGFqi~d;7DT(6y%FGkV&T_OVXP zG$|kWGa%f0W<6X7@8=7WLeWFUp<+&JdGNv2L7;AjiopOI6UTEEa$wM*rYq73nwyjiCsX7lm5wrb#Eh zhpei;%1LD#FNUUpTtr#zy)HzxoyKlwVt+eI-h-uROHq)HkYF9kT35i{4y(5+WkENc z!{FocqNsaUM0)vYY=A6=o;zKv(4=;H=ziN3SCi)wQnFo3Le-~*L-8;Yzmi|If)S#S zBj4}cE3HXaO?x;Et)D5bUFTNZk10Vc0cJ!JC(+z0Ihhbl-8W z%AuJZYd&$)_45;dewk^V+ow3y9IrzX;Kdt&!vSCk@@e^*;qqgY%wE1v1J$zZJxq|U zr&_6fj{iL*4{5eVu3hhup!Ix)k>IHfc4Ogk!@8(r+vKKV-7I`hel-7i?Ri7JJ@)x% z;ZI={9cufMbv>f@$HbKa9{v3Gy+ff0G9kt1we4^EVeV_rC+j`HlPhkYJ=UM3M=bBK zjKOdObQV)EJTqu!4;P6}bya741Wz3rgC~-uhZdFVJ%*{2U%d0BhCo z9U$%MxV3w)pXpPUP7kqP94+yja;@ar@(x>xlG|>6GJiz$IG0C6FU!X0)AHdlz2UB! zv4rA?pq61~vCvGT;<=fA@NIyg|&}t#5an9Y`{uK;ak@ai=W>OB;U@$8+UzRy7Qvk zOOW>%HJ=Ld`p6tza4U*M5{M`K%IM;Kc7xd4rO&Sjh!o%x-y^e97hg_ut4`~x);HU& z^17Ya>^|RvWmiwymZzsxU7&EX&?<4MXOdr==I?^%)gB?%k989e6@8WXwL4I6)sq5S zgM4>{i(<~9vc>zdQyIGIVYk|fm9G;YeTE zFF22M-NLDpwA_&;p2TZ&HPhc4D}!m{DxuQhUw6lM^>QmHM`}1qLE#cBp)%e3sXRsS zTf$R7$=ciX$X&j4`*q5(r%=m+X-T;-bR~R5A$>GM>hYO9n6a%?9ce-BpERWG93oB#;ik{ z;Gp_-n}J6^Zl@+}u@K6{VKf%bPBV-k6ox&uN5}+2`HorYh$F*1*U{Iq)|ZJ{F`nLX zkbJ>EjW|=YM4_Qpfe9`Ol7h!05?N-&o`D85@H+PQOueD92zJDKz*W8{Wye-SkJY|} zLlG;6d9@vD?H$4@ZIy0u+O6hU5ocraMlJ-_>zy-0qStP4HIX$in$8`nFldowoO|V; zP5-I_;Oq6398X-L5MP(-T=FZ&~I!;rxV9dNf3GPZpU9XMy20q>ggw2wd z^74bk!@yUIS#4PMu8|=wwYq|8k$Ml0RJbw?c-!LJNv`vKTbzAv`rr0|7qwFL#QAN_ zqV+z{Chs&O47?as<3GhPQred&`^}klxv_x5x`a@jlVGFx8Nngzy| zF>0s7P$Ke8S|XF3uc?s(aTu(kZm$1LH>$437L4T^5|b#Q4y$8Q)dxjndi;Vv+1wRV zB-$N~WU*K@Tmt)fQkGYZTd1!Si?!jRyc(tLgbCczR3;h;yQi`IP;gDlh;rRSx<4o6 zUSkiX3<&z%{7Kvo)n}C zEk@l&dKzCC49m^YJwf)4x`esw2(R8gUz1e$l)2Eyk$U?wtH1~>PGbG6Q~b#)aUq6e zb2)>ZId#cWW`4VS9mrx_@`;68UZ%^ik9MKaf?YcGpLP6fP;Fj z$<>U#`{=G|Wv^uC#Y%l4%xLc_YOh{F*w3x1$lux_WsZ^~!c;06$lo${ir(}M0Y2{I zSZYRJ=>~k4+|-lmn+kD+@DJ^B*kbiWTTr`*|MqO0Q!7Zs%smaLwzOLMKJ&B6}gVT#@RW`1-b)qJY zrw&C-gEjIHF=rUgZcN6f0wccp88tdVxM}PJMZdm3dTQj`sVo{lV=vcMxHP<>$u7yw zoFXX+D)kfyh(WymzHd&7y2@S8#6Sh%M`0vgq`KjAJsTg(mVsr6VS*Y_J{~ylDSPu_ zV@n1E52m%U*dgT!q&+TwhGyO9dVHRv|2FUG7+%bknef(JoCA*S$<^1de8yf=ptl_%wjCM$CeZ(=w_v0P1nqw8 z{$U6!5<=b^EAU%c-f>KnE)L$spNY9AGNLf7y5?%H>eKb+poMryqU?uU5#7K_q%AbF z%0#G1d;1u=5Xt5pz4f#Ftc@CCW%BD7rz^~A_Zg#)Kl|LNhXWxAo#_HX38`NLUHaj1 zka7v0K6&ety<2UzABC;Nd}&yMxxdJ5_U1j5!oGhcD!}kC&)K4X-b4NV+u|A$HagjP zwoDpbNYo)eYNzzu zD?EU152SouY+5*@#Au=63*$%rqDYf=(|?;9m^!=?fm)nCxi@Wwp|2$dq{@@g930kjt1LOT*1nvF-K01-xO zuVsfF`psaZQIo2T--@;bs@Qdnk`yGorb?4IgELOT4!!Sq-)dp%|IBwYVUeV`PzJb; z3@A^_d4*o;5(es6+k4pK+8Gy=ev>_!v+}AERC=hxay& zy5uT&FMSoVt}8bFK$FSfaGdKocKYt*QZC{&?ctR6#7*p;kF$h#mVE)( z6VY5-41`V5rb*Izl1x)Cgc8ws}*!9qmLmSY4XQ!j7};e&QQMy# zW)dwtC?oCLxb6?&7{kZ0!V%QZh{>(5>(c!e&wn`?Ky)|PCW3}fi$t6x4c8T|hUJ6a z5Kkwi9qGKdZ7daVSG+ulE7tnQfORTB6UkHClf6~waOv|kdBa&t=-Ll1 z&WT1RBx**+92fXy54)!ARqAAnKc8hej_%KItx8QN!TO}?*0R+BW;LHtzdt(m*O-nS z$TyvsWnUQ>y#?9M|H3mwnYFZA2ijH-Y23UG^SBN%K^enWc*ofm(%WRi<#qE@YcTBb zp812mo^j67n_VV6fb9SoLW1OM+5+v~Iq^0we7ik1g|yRd-};{oSmL+Ok-t0qgA_(z zAu-E{3G?8QAQ1DTWGp^iN;rVQ>LJ!gs3pp8RWcrImsbszZa1OPg3oAw*nFtHh3r^z znHh*|pe{CM*YV`Ce5^gOf~s$pq}~&j&DIU5;47=e_)!F-(uU=Nm9r^z4UGCr#iac^ zptowR-dqPR6C}R*(>gRZr}twJPyRtU%5|oEdyZ4N-`FKxeJ53FWWY7?!XIQ%WMH8` zk07LTuYrmZ3WM65yZTe7vBwkrF7uZp#6cK;b&Q= z+)P}W5=ki$N|b0F#j#3OY;+RTWjO(ikdWpMDgK2&zoS3(h=3KEA?aru`XoWn6(fQ- z#9?p3p#MHOS3wqFh#v_3SeDhWh)F+LjD%okfspnTR8UfR@r1wTU&T{L1GyXw07s7n zNlX6FeUnhsa$b%M{S4!%<(NoStH1oNG0=#b0CxO#jbWxyM~SO=xKedEN-y`T$|qz- z=Z--#sZdLmV`0p-rxbca9+@lH@h201_K@SZ7u_bDSBL;SqPiErPASzZo1Inijl!2Nl{Sw~IrKnA;N+Z>yK8G)KkQH!UZ zu@O=H58|)L(YOiuyu7_I^@3bX&=Gn?*eis=Ymt3P)graRz9>uILfg`=t4zZM&1CrA zB$Q<5E@IwN&e$kN(RjD6{md%LBdmrcBMrWU05eH&U~g|teCfPs>Y*Splep#Zjx?`D+58oNB6!;`4_MWqLt^d8hDn}Ag~ z)+vGHLI)d~-!u7fE`8Cbe`4aqKD&nrBn)7~78`ivE?|f5YADH02~96vY|a$%_)e@8 z$>J!esUTS=tbR#1SfSO>R)@_ma5atD(HJ;lgIUpPgteN^)9~s|Q+U{C+teQ;YD;I8{LtHpUnM zMEOQV=}Vb{8dg@D;TF4}5-Lp@jJpybG;94cw-WQaFJBWmXrk04$n$8r1Mo&GW%Rz+ z9|$9Sd9EV!J%Bzn(o_b30U?>r@Vz6=!Zn3b4z)^i?&n0j+3GaD1=ZZ|q>FwQIy}#X zC?I#gG#4$6sFyDGS$0#gQL%}O{uZX_bJ_PQq7SI>!%H8>NNLwqw=ta;9kH)u!rZZC zF%{mwYl!_x5j^J_t)_8KZ2_~x_{_WZW<{g4uL)L8YOgcqeSt|M#tMNmIt^uy z`m#B-4sB-9h(gU5UUbA_cZNa}N1N-PSrW|{V$_ANO~b2FbQhs_Rg1qw@^3H58!sr8 zK77tB@arzg?mRQwvDE-ZMLy(n~iN7jh)7}(^!p@ z#xM(pV7vkKa5;{`8D9%u`5l16}s(y)%Z4Z?tg`0xPm8Pn6~(fxQ7}Nx~&{N z*jBBzS0yvf5Ky+|tyr-r6lq4wi}#EtiIpK8GmiO!TW3p92m_d$+cW#P+4_3F6pagbiaSI7c#avM^8-_$4q zyi#1%uxz`;jDF3z_g)@hbP@r)MKdCsb?BKmSSQY532M+$1CU$g@2u7MyEauaeGaGx zAr=_uV=r6IcP-aDIShpeHo?8U`LpRczzwvF4X9`2R4+bWotjolPHziCbGUyy0e(jF ze{38AKi;kXnScK%8GHirKdQ!6tiK`DIPYMA@X-A+J>mOy3IF@c%!mw~CW^nwkf;7% zEik~wii!UY8S}qhs4_HUP~1R75*If1IB)*nkNp+cqto|YqsC+$eCybT|{cW0bZh$B3y zn!=@2V_W}bYunwFVNZ}T8GBAL>SDlm0d3x8>nYcr@F1(e^Vu{*wiW889pTW7#Kp7U zV`h(O;jGP~>X)be2@B>=3YE}#PE>{FE%nr8a<3O`au|1&0&UhK;g%Z#+t3YqcXYzn zfyu4oZ+d_s!WFSIlYct0P7L;Qf<9ZO$Gy9QMhgIPybjQQ#3%K`&B;hwx| z1A^*iZOWLM7%Q`I$xnw(Om#sMZHN;|@~^N8jzno7Z?kO>7jo7sMdue+me_1GPyz1* z8zD**>kzSJvD37H7qYxa^qpV4t%LQw`*t=$+>agqq=8eUd<$G)uH5-LS^Xod$@K|j zu|fW!Tn$828VO)WvN}nqK=%^AsOHg0l{x8OSRW#ExAW&d8wX~^NcWh$Ym7h<@xnII zNaek*%92)Tasazeewev*7lUg8_!{*aQQv2>ZxM+qG(J!d@3$0oOHoq#V`*mH{V)eT z@14%{KVP>U?FKD!)Wn$nnXMZ3HxSqWVNOPjPg36ku42Ch`j`!CSfCS|#vZ~Bkec>N z#qxqk>p{FFx z6oc4LNYo&#s}PZu+%7?#sFu968?jZC(}X6F(qS8Gq^#p!moFwXhvLPG~bg!O8 zH7d=dUV5#9V0qkQDAXh(L6@`d`8|XzbP%jnh$=ncv*lLZ?FG*J?pIZy2Pay=cOUld z#&0A|#F*}aDSzN%V3oKj6Qy)QWE{8k=CT;`D_l0&%a-n@x(>TD{&_YB9WsT@b#;KTy}`i5W{%=81KFoYr3(scu?7u?Qp6EJMoSNTwV;WCIFMh@z2$6gHWH zzM+@FgVII_)&`AyzVdb_pgP=#cgmSk739c)e(QH`@ErMxA%^z&XirOxfBC#W#t-|lY?URw>479@g#{`=d5Ty))>%_uR%NU(n*+x!d+O~A?9`H=t=Wny zjYtgo*bcE(QWW$F^oqq4eF?$=Y&{>PNzpk?*&84tc+rgH;$@9(q)j>+#-A*vyXhG^ z-11^N)hMn+N@+>dhA7Fj#Lhk`S#cOO`a`uS7$Op@blS@r&10x(m972}Cut@B-Z$7( z_~n~Wwcc1 zxS%KzAn0BapsY}`^e79M!o0b`0NrZSVsv9ba`~^P5VojKg@1O=1A|s97k>oZIgNx? zb%7GZKvsQ5pE*Nf!lmu zH*GG^q>O0d&oNori!82rkq$MU-C%2rc`E9?agB!ZIz%rzjNI`v+6DyW?<>@6go(s* zhulxUqVN=o*C=lDf;!YA1C&A00fS!)Y88pgv8ek#EwWD8W5I?gLX3qjG=-ZvI5JR* z48UlzCEW((;P~?ot9)%Y+YC6zTMDpI9>PX3uJ95MavJ_^EC1VB^h`1+YE7soGYh1u zsZps%q)5&jMpAi_W>H#t*2H0clC-K|r&|7L58^xezD`#nzbg8-eHf?ji(%#H_co81);RnE} z-IH!ZMWS-Q#FKuq$8M+g@GWa$?zO9s+%IjthhRXJynVwE$Nkew;r z2?n&p07#BqGUJB9gM*P^t#JoE(|BO$^gow+Q|lfDEx1-jHmQQbb6bIcP(k$HRO5gI zN^V1FTv<;@Hi}C`q=g3)?*%r|%O^9m5)v_TIznPn33(-Tqml(BBJ5F=9fZ0kK-AqA`>N?}__y=i0~waka%aW4B!pPB z>I3oy{OBnTG)%7;N{QnwW(uhHbpm<_8pFG?5M9^FuyYl&v;drQ2T1`1i^UL)$_Br> z?U`~LYQq&9Bp0$3_Y@OeJzGurwWX<)Ot^HpiS$K?wMTOc4RAo`>1Le|&*6afKX~jN z(8+_@N+JykY<%=duBziCV$6a31p!?CYBST`+;Ihav(K^oU4ZUd(>xmygH=@J3iJi+ zfQpgy&ugju91GZ2`pjT-IQV2pnuIvc*6qI^_^bnh-Jr%&WEK0XQ0(|3=LF|=6Us?8C8Yyr^3y$&v?A>O+hv=F z_S4m5Lc?>2{h6z2FP#8!+VZ{P}*-e;$G+t^-&i zxjTj9o&c3dz1WaHR04RRV58*XGDF7o?-edlRn-!b1+!6tb!g(>Azq{R76Xc15!U~%sq=y z^a4X|KYPl5Ua#243~%J03}VNxl?)WB&m=(Yrq^lf4$pbPr{l(8wmnf(0L>SRE_nYd z;|&l6FJa2I;t7`8!i5pH%?tb2RJBN8m%R3-n=p!JmV5ANI~Re@G`qEjFNATNY_xrh ziX3!|2E{>LW= zKPZaxph);;LI`j|Ni2N7<-15Q0k7p4RWjrFPddTBY=#7h7<4>uU9T4Fb0u|FxRF}n zajJNgWoOR93_v`RPD7a}E<$!Z=Y&ELZ#7pxuI zJm1UiHvS7_Tc+!%VDheTSw_~&a*-XOh(%^|o%P~7ZG~StO{y&hJ|Gul%{`seVwCJ$ zOv};$Ru6Wzf?r9X=S}82uI5zYg6*6%Fu0_jNt>zH4KrGCB8BECiciLwaMChod*eVe z_eyw>6B;{l@^e%nl3C(Mi|LRa&7C$ZI9=^jsWh2DvVGFK+^i;4&B2BG8%NK$*+rob z#<=(H2KHP0uvb+cieOq$89AzBQ^amIoSw2@&ZFQTXlOB)^swNKm36l%sx4Yl%(}+~ zR@q!FVOIG@Q|vSscE`8lK}A(L?$~D1bD?mWEg!}_RE9>s3Qcjh1W1aU@JF!2ipt@V z(Kd>F=0%(M`HFdXb%mvZIowqih#@gVRHg^bqKl%AWH$GUTjk`$GNgyH3|D~x&PqSC>Dho_ic` z+xpBcmKr1er}zcz2CkQj&_!_J>{O5U`j%hJ*?BJW7Pqm=|06>G&;p!51%tx9c9sE(4-SaD3g}DiX4xPWT z#Saz{XzmoGK+CJ&GAwJcYQ+Vq^DnB*XXR@~8gdJ6ffNtn_o6Dg?QD~_`yZ1;bNq(L z0YuS!Zv1W8)8_-71xE`u+vh5#lqVdYPvIz1R#e^IB!iG67towx_KrQElhFWP)WEn6 zkydJIo1wHW7k?xIq|DVq1k#iW?SV&11J*;EyJ&-l&uhZzEy#wrY1O66X$VvgFZaaX zgC1{yzj00AeD}KpHZb2%XYlreSyDT8aOyHmL2K?Tw8DSe(91;eocA8##Phc%MT_pd zcfQRGEe4hEMuS9UqfE@XJANY48?VzjP-#1Fow5HES~TeL?|!4-zhPs0 zZ(+>aFEM-Unz!7qY^daXY$8Plxl+GMi^xC{1ilvp+fth2R_m30<5z&@|8Xf!RTL?i zE8v|DW`=l*J2=cVzAT^xOej}(UmSUkZnj&=Pw_G#@7rOz&fF*pW;QFF&KSr2#s$Y) zVHq6N7mH31UD>T>h;(!g>{awbqYe=s3Y-Lh>+=s9jG7_(}N=P+3vLKq7#3o)I z!gPy4hb{9?yp2$ShtOYP9n5}oxsd8QANr~0U@*Ja+qns`P__2@y#b2|}_=m4XC8AApo9iN4-jb^!vNsn4S|6jrEw(uED~tX6>5HgV{xmvO{v>DQ zZybU5-bl;HoU@gU{2d@@%b`C&q*_*4nedz^OBE^cpzCcgHn7n1NaF)itm}jkmF)zm zjD32h#dh8*WIX@v8|+B`q6Qo^6X2jZESJm}%+D?KzQ6S4Y%Z=3{oTQU`Epjv^0AaF zZGVP&Q*C?>bwe)cyfZ@*$9u)YFJOt8OtFR@lZuT+;=?t{2t0YZyAtYAU!Yy!n!9s> zp6F?7|2HU5*vRvMY?HN3`8hrPg&|MSHhic)g<7!o&7Fm-miF8No~b|0dhc+jC>tau zz*bu@y6?Ma${vH)ya1e#exC-f@ia{_?a<5?4Hi{Fe&=3$fXl9TY7WE1WGOxQJ5*n% z8B;4)Fxs#nV7ZA7$@4l%lcxs6{OV6Kpdb#U3B%?bt3#5|sByr0)KJtT)y08*p5+98-AXQ36C_LiB|18Q~L0&W>12 z@Qzq?Fk%*5#tw4#nqLf!0~yQf?RAc^X1 zxjEGP1?kHgMd;Q};GN-{k|qPCIZ|j0`qc9eQf!{Wj%QWoBJZ<|OJEho&}_cv?s&Pg zL|^w>aTEfssSx%(Kl9`-wC8^Qo#E3jr%N%5o`QP)X4_toI{V$fON@^2kGYR@<;RQ$ zwk;FJU#_xg#@(fDn)HmaDzZzoEzZZa?nSNTlK1)5qtXDyRRLtjKC4D+MxQ24CJp7? z4Ub34NFAq#PHu{4<9%c$RxH1C6GyEWT<=M3LNo#bd45;ej5I~-44cLn3TtzD#uv*nxY!4ri~WK512{^WM9CKcqz1w#F4 zunNJ~7ZI`aZeIw}VrXXG8FhOFs&x$eipqR-xP@WDKN3DNarObhR|{I)v07afn~8Ry zatNv|4jqYCWew@R+IYtlx$CpAU-O0Bed!d!5c!>}ke2AT|@fyc6=Qy*dq}2~Sci+cYt@DQDh@D zw_JU-Wnq&<70NaRks(rekW^H%M%uMzaN;IE#2e5_WYa1BF{MPs zy36hesg^#Cc3$zVTX*p-0M)YpdJqvFBn@|riJ8)v22!skfbx~AH*?@?&bwU*qFMh` z!O{eGcLU^p-vBnFLOc8Bg&AX0?h5!H*%9x0F+c2~-X#T&Xy?0~5lw*E<54qKS8;&M z;KX@)7&~UlZ_UgbA^iL+O?Awxm8)C}8KIplx>W*x?c90vIU>oukS6}=on&mIdu2mY z!oEr<4pMY2ktm%iPb7O%<%p}WRX1&s(UTc{wDU;65s}^mx^52k@R^w6@{^#)6|u#A zb8lL9A-Zl8uLhQOzU+Y`*A^Q1&iQSEq$I4gwC`YA37K@0gw6k#{N zC_UjlWs@F}F0`d{ZpAHBGa1$k)F(uW*esAsH?JJF6+y4oJ*|<;->rDJIPH)d6S((}o2spl??FJEqwd7G|NzNPQJFJ?|JNvTyzlric znOx}u&ULTEX*a{!C?cTzr^?y0%+)TaYVr9e5FdnbPeDq z6YE(an(d*0ik;#w_$h{^8TbBd>T#t%_btb7`x90C>un00{_rIV?avO& zF;#r;SNXo7!4L1~KF^Uk(@mNFV1;QRaC)dtxQyJnrEw$hS+>y-uf#S7=ruE=OH;L! zhj@Y5w(WKBP}zzkyq;j}({DSQVWvs4BizNdc~xk!I;QAF#@zgkJWPK)hi)KCnMx6N zX3kspC_t-sG1P0_L8R*x3&=TR`8(rR(2`Iv#P*SL-DTPcsl`w0mhV2DOi9O5+Bb=1 zjkb3Ex~BZygrvfex{Z`Sb8;YIqXLaNM+*5_IxRJ-<#xy%;GmdeD=$^b-*@{XtPx>+ zn`)p$un?|ttsW539{DbtF7GZICBz7kJu`y!M&Ml0N&jPl;E6A^|0uT9hg6Z^(>y@*6;ZAvxOr#`-AB>W$osc5*jLYr(+qf_(80b8oqs0&(*}mGtK*8 zh$FZ7#TPVvJ?PigyUy9p;0394kHqJMWwI0Ls?ddHsEY`!XCE?&A)TUDv?ioRq02@F z>rj91n|#TMpz#ZgzHjdynUpsSmwQa7aMCw{gH`*N^eauNJ{Js|V+UPX^$(auXVcU( zL@XqHG3W3d{7TSk?Jfbb1S>)s98VeyBEigW_KFRth1VUvai{=|m+NK0@BryQby4xx zNfJ*HNqK?4*+_Oranft=7)~rxZ6t5n4*e9b)klrxUUPN1@^G^?Q4Yi{{WSOL&r;ez zM$D0)o4$*38Zc7H3zZqiv6zgkDnUaPSYS#SR@S)_VsWvco@Wq=ev9p{q)4B`?3F0H zsJh^#wrpGQYO!BIgG{)|Fz3DtV96C0m%Yny8Dl4{$=^8$A;=>LHf>eU0m;bTkjS|P z9l%3=hl@0Yw1>3h$UkaNA6KCgYlPtwHoY}B?V9B{u_CQE4#Hvo?74+JNOQ=~G<41@ zY(B}%Mk}aRqMKjAl{nfvyqpfhA_!45eKbLOTqs)9nzR$%03WW{wwGai~r)0{)|J5hNf~`S2Hk~LOMrX7~TWSeU!+2ad1T`f)N~`iPow3 zI?S;BR#-vqe}de{N>~BJ339C_>+#ArOD4{?!c$y(i57f7+WD7}Is}x&tN1Rw;#M1r z)h5?15jHDjrt1fOT?^0_zaK6K&Qo&@T!&*a)Tj1JRk4#OLI>O}N6`hEA3qv~kUQ_w z9u%y;<`x;V{_;yqbQ4y`W0QwLSE!<3D##WK5Qa`;gDj<)K~|8%31px_=i`^IPD#1n zO`R(GIy}@ix1Z6FT2$quIK#Yr&}(I4Oihr=5-K&~SmXvd(m~NX)-mnw&2x(N&h3Je zn@E5iDrh>=J%&w@NchDci|JSX*VenZw6|#ada(+zwg;y`!s5^?g>71y`=60aFt}W2 zC27Y~8Mv5CZ*ewz>4oA_p4ryhXuIK`kKE8!b0Ejd8=YlbO2vRZD+y>y_?}`x&|g5j zrlACl^j<2U;m6u24EQ&#WN!F_q$@*u=S!M{A$fnQ=+~&pl$t`~nTDEAg=s9#(t3}} zY2H7+w1Yiv*JRt>1??CtUad{zLDTaTgUO&UMVALv>?z`espqMHF2Yb&dWl1R`Z-C6S6PznyPrON9106njaV~(BR$dJK zA{yg!Wq6++hv1crEWYZFjBadhicPvu3}=U-BDa*Qt4jIYdXF87Ih zhotz$&b?$BH}7ik760+}nW@KrC-u4Bd8yc|U{PAXuJ1))Z-2>ws<26e$auR^k`sJ! zacDAGUD`SFMb8%tR;9%DV_z^Q!B4ru>v7N0g9l1Oc^~gZIuHlFA+DBlT?XNnb=V z2HWKt+RB2m5$eR?BwKE)z@N|Hd1d8FbQoyB9UZ!d;g2QoV!b_76dWzU+3>$g z=mPDCJwXBhruR!d?NZa>6P|ECjL%6 zVX)nlq{=xZUi(ag!AvY(^%H&xmIek?oQ#AZ8ra5ErzOe`iXbV%&DB+2R9EtLh}(u? zW{g$5{B2&>vmTQ6=qcxuN^&^;gRk*~zhmR87UN(@k+nTw zYxrn4t!numZJ!j;^E6L>6ImbllWV~TCWzyx7L}9kvt#|1_>qX+T zBz|B;EAa&bKaDabi!IT(M7y z4!fxqYmRfI)lHa}s>JH*%vKC2*O651uRrOL4lfo#C!A-^Y~2xwroSjcj}4^8i)(yd zC@x20z%P%_<$idQbTjF|{u~uysq&{%n+Sm`(gEZg`R`wqzHa(%psN>Zza|}h1iz%g zu+(x@Z}+ZSTQ9yMFL62RIXh8&(5;4t=nhp^5ECQTBP16g2oeeq)56DNPM|+Wif@U!In?tO4gE47 zO=^B`0dXlmVZ)zRGg2Z*f8%6hvqs-t2d~nS+dr_-aQhh0RtY}b4At-1CaK?>ty!r1 zwQvpbVFDhxQDr#pM5qs~wTe*^1ovH6$#^5C$ghXZnj1)(nS;~_@|THdPCXrXLwPka7t(I@&mHD1g5e3SGB*>X z>oWmnbVI)fRR~%2E?Y+=zO0>_XdWf&5i#rY4gI<5JBpo&V|}|ypYv6+`cAa!gJ!*< zo2K%-V;eXbK&aP_)?~ASaF;XRw>e1wr-!o$`b>}|ebHF$!tiRn{;*Yvz)(uZ?)dE| zfIR!fg!9uxwA1-2Xhh@}Uu~y@)+aH60&9NYtCA(;ls_$n{`PRGrid_hnI7mrQl9H9 z-LRDS;Yh?fA@Uu#*$R0H@Zy>I9NIO8Ecq;`ogGT zqI-{}u?vk>b9;vKdEvS)Aar~5ZjinEdHPv`ko z?of)ZRQDvm|7o|y`w6!v-?k*XR6Uudn9OO{l&0+-?IXUIZ1I-E^F;v9TQ>J((PCxX zEbP$5f6_d_Ej!G^#jT^>GN3K@!a$Vqr&!}RopDBNk!FU@FGqVO1nCb!cX6D2UbB3V zoM*qd<~w7467e{Dff-I}*e)Qor5rn5^*F{_(H!%VU32|v>$!1%4#EY$O|^P}!P4`L zU_di$0-Si-dut?>duX+qKQzp6729{%A7ZaBVx*zQ|UJfw$h9^;eydk@R0>E8u z50r|@tS73nne9!W3brXPUlo5ZP!#(?k{Yb{2-_W&Hgc`>6MLu-9&3{I5pmol)S?`G zL5c0gs#PH(<&tLjJIq5RN^f{tn&COJ2Z9YR`=1~}@NKzW* ze0XC}vXf+5O%Wz*A>7l3v%HwGr8h>Awg&Zb=U`T%Jex$D{+qD2Dzv>%J$myZwf1sp z>dvXP$BHd2Sc&OXEvmd6I93esK6E>*WU)Fah{Zm?$~nfOX0kCKs}Qn)EjLjf8D_&dl*IrA*gpHlfrrknYKA7CwaY>qiBu`YweTTaE}{_IMY~&?)OPvT2O;- zf>PlyjJJ`}VtpA@eOay!w;D*O%DmdqPy(JUz-71^Y*euq+{FiVapuNg!b457+|`NJ zrhT1Zmu8?;Q8lN9B&4M>(M4A~xjR4nDG z?Ff>8OLTjWMkl=D5}lyWb9bklQoyg<|_-kg2Y`5<`j_?7a}16B?Xd_ zRMvFrNFkABbQNL-CU<#%@O398ybMlAsMaXL=YT18n}F2N|E8{o1#-~8@9}QhC34{ zbK#BfTdr_=f*X`}gwM5CjAm2VDNq$RPqC7*?n>#uv+4Cp1~Ra${*BR9L>r5^&NiBn z#5P#Vj?4CmzOsu`Zp&I8V}uMmOPr3hi5r(N{mLT7~{-97+_yF22R=_$e*}JP`82XCT778`yd!G-ogNBGap?(ENHdwgF6Vl~c3UOPumvA{vrc|)M zgwyjkD*3^!LE%x>#ey^m1_@f^_9*k->g;%RVXPe5UnY3!JepyA$dGYkJNxe+^_yTVD!r8(KPxPC-M8FB;c>S5?RM(lqt7aR~ z&Hk#ZuMf^vuHkjx%(a(>ffo>pc&=vlj|pj9C>e4a(2TP4x(RRErhI(pNCZ9K0>RP| z(%O>1%!@vV)l=l(#1qHp9qq{>X@l*AYx0rd?!r1D;yVh8__^31W0$Nz0~ZC z-!xmLfeC4&`^Alffu&d?_X*o@EOHfs9)Yg-_WNuh6+jsm2UABkg+j>7GlC|eIJym% zrp{PgnA=44)eRkq`j6rZl!i;)IOhS`ZY;0!X_GDWpzI+-s77?Yb^?3g?joRKA z%ac+8uNML@C>9qcRZ6$LiD5-r1+AhjKEhhW=%(8f!eYl4YOUqZVu*cP9YnpINHhiq zo)_fW)LZ#wNCRp}&cGQ-VV1~}HDHPhB{`(4dkz6JM)G)#mm%r> zVHM8Vauk4KTq{9`wO>OKOca5mqN^CA{P4{-S~}c7jD7;l=r2I}+&FH2no0K`JE@l@ zsxmXkhk!<}L-4mcFEEhDPe7pi)9H2hxtp84Lc8RB+P$C#$1C=@Z~Ptu0oFw*6PbiK zI$@CEYuRSD^`K@ENwX1~bk_sz^gVOxRg+z|0lH8}NmO8KNRU{Auw3Mi02 zB^QnI@2pK)P0F;I(S&HFG((G15*ZP20nfZ|)S9K}Iiu(^Ywm;;P$u%_l+ehAf8#sl zzx(v)>ITuI7T%Ocr)Zvri~m=LrEhvOb-oJh*^v|I)fI%Z4AEN9j}>>Z$|46jsoGAsKI_t|SE%P=ejot91K-M48)Ch?IG6FFDm4S}W zl)9%EVNvJo6@&HzNKPUzXkn-D^9qMCUlv`vt~yidTT5F9KfYYgC4j7jMzt|l3t9Yh zwhp-&715J6Hz6I7xzfJ$tY-vQQdcYS>btG1%S_cEN6%IaHUy_FPT1d25sbH^ogi?H z5v$hwBAiwcinhgO-R@zk2cwzL5GVRT3~}}AAPawkFMbra2#w=>Sh;&?Bk7!^?R>RK zpU-GWWK0dReoekTI&yk@7D*s}|SYTY7iY)89irI}N z%@ItYSrBxjuOQf+QhbckSD+GvjEtq6MW)+iSF|L-BvG&HF(_%0lj|HZjJ|{j1)%ay z%Ork2{LP{p5ZNm02)AHWZ~ENP<;Rlq?!ruF^7&CKjdy@MK_Fe_*~m|9^EZoOg%n{Y zq$pse51R_4x$kN4-XBO6B862VY0tTRuxY>;{rbyQ7^)irohoK0SmPd=zDt_4D{c|H zNPi?bz%g;2Zn!>&F$!$WI$%lhot7(sU}loizbuG}Fm>0igWasCJI#b`sXaAr6jgIJ z2-95pgd|qu!>0u_s5wF$5lr8D5mjiBj3-oX=C(@8jW+0<$CcIulF_iZ4G!fma2Ts* zhX%oeUQvsO|n0!HvdwK6RNn~Y0={TIk->8nX z)Z~=jG@1y*w}nE-s>`7kZiOl+g$&V3(x167V_}%N3Q5k@rPnMpc#d4imbGhSXtCj! z!nXc$MEw7eYnb9ftkT|5AIu1R^LTqdd|l{J=s9<+?z;*PaS7}Q1whN?WH^&*su*H( zjg6WyuVk{g$vIfa3|kUWQmq4b9eBd?6+vVKOi2jAtyeP8{_eM3=dfIugxSRr2$_mp}z-K7^s=S$4(S3|PQsLer{S0B4t*XrVJNxIM>3bdvNlt418uE!6}Xn*9K@kO=nVJB5|h&7Tpi)$ z7~Yiv3`6!K?PvYLxb=Mw{jaf=U@U&emL=4nCBTja^sJKXfvl{sD=?Bm?qt;VKj#uKeSsZby8)55Q^|@ikS!5tiWTMnXh7-QQE+kh)?9FG3gQc1B`-*PE<+MJ@2xSXQ@5QcxR(?E!eOB#$pWpOz5BmW;S_}^uYT~z4! zcuDeqhu`{S7vc1H8)4g=`16_?Xc3mFL{QJnBY& z!~ZZVAI+pvZ(j1@;Lu+gZ;2T{5POI-X|Kt4g=o-g?&#|NKz|8P>t%{p1E1C)Z|jlU z`3yUbu2WB3)>zecJ6i5=;MNn$zF6Uhm#o;)O531ydc!9Ki7FN33K!_x$@$#_N=G{b zL3kcS=>dJu--Z9h|Arx`;-o`V7`Ja7ckA@w;InPuTv$AkgwIAF!ru}$kI6o8VVKdY zMGMz*Qd}GoWgn|4%v3p(pGfn`vQg-HwmQrx&*jcA>p6?6rRU#F*rKwtzLh?8&T zX5&A(jzwuE9!3jRl8QYBtyRBGuU;hB;t8L(Tf#IW43N4Q|bV0_F=^#2go8QAW$WkF6x_jX9j zNXTw%5_S4)Hkkb`Z6M{Q!f3c`!nk*QD5_bWUE#9O8X zDT&2n-g_NmkgM?fPLst!_oBu$Sj@OGHj6kAa!Wd9`4qGaCuwkY9erG%Q>Pmh>x2UO>yA)c*x?Lydh zBD??p#<+Dg02w!o55~`}HRFeYMGX2ldmSN4$fw5ZXIaMwX$$yr4g;OH{{@xXl=gYpxk)B z&MF*|6nDjYcoFMVhr?=OYO)~D0+#Kn7*_%nO^-YCmi2Pg!@M!CJDd3{D@JEik=3`M zt;=KMO701xxgf*aSd(mK?-eXUV6oIJsFG->KV-<^zh|jFWXe^B&~Sf^juUR=i9dN@ z1^)FdC4RX}me6ZdMZ=F&U93U-$Rw|PHK3N$!O){X%W3jfCB2T%jvEr-;|)?K;1ir!SO{vp+3@U9JpSC1)-dCeR zM7VW@JA2X`R1lRR((Fl(8(xBR6Kk-n6ym7;^14&QSXE(-?}SZSfQ1=$Ti^g+sld)d z)My4+(pK(RO~F!T&EiApJMf|UvM;u<1Us}sofY})QZQ285-xy$5^7myOyVg_# zVMrf-Jt0+0FtShMlQ*ti(^_`vd;kpWe34dk=29%?*o@y~k34VO^;aqnVIetK1xo8Y zzhWKAF_4Tyu*C2HN>}|C*MKxj8icytDSHm(_IaBa?TX&q8tP*RCAr7KB_pPg1Z4UMq+my4jny)Tmm64PXlFDe78 z$)u*KLo4!|pMaS>eLuMZ4P-IXk4NoSgP~Or7GIKQ`pPHZw54cojC|6{W6SFPxsy+v zqnxob8h<0up7>rvJoxJ+UzyxaCtuv}1&fRHMW$a0O|3i7jowBAcT|BD}Qkhkfjotttqu^Vb zkaP&6&^0dpRbO27)O{Sxy0MYm_=|1desT9~=DJN>so;T0g$~qXhEARYTj^gGm9(&Y zADFZSwW~-o*HXZ4hQOd1mAio+fj&@_j@lS@2`3^-Fs~YmZVQC(kkOW2C zTo(Byj(yBRRJ?gZ%s8ZB%baV~+5zk_HtB;xwOIiO8CT|G2lPoyT(!F+$aN^e%Frn28c-({BOl7TJzTSioqKga-IIa z-p;Zs&S=}xxLdHoB?NZ~E&&1rhr(S7O>lR24esti65JBpg1fszp~1b2oOABDx6i%Z z{i*8*>``OC`<1oUeCF(D2`y%UnJ2ZDowI?6C9@t6zUwRL5QYBlW)_Y5l=>Yy(2YV| zA1c|QEy6!^HQ#kHB{8N(n+z`f3r^#K(^tz;?vQ-(6f<}4Op_orpd5G%m_;-~3mj(< z&4z{V`xe(-G)~jT*?wr17BDw5FS?Udd#S_7nAhGUS5rZPHr3GK<2*?GJIMy}InSKd z9g102KRn<5f^$FiPrspep}NR+eREFWujg++L8(+BEP8ix^!KHr@b?y{`6QS*g3+i^ zP@D&&$YP^Em1_ysKzz2mQ)}vs-wx9!94Mt^oY0o`DAztTjme-7u|>ga!*sw~X+aqJ z1i1e=X_MX`8F&h%-?QWaCGMBLINl}BBSO1n^KzcSmATYAgbbg94UZk%neN*V-zmJV zq8e6Hj}NJXvFGb)(IMWukk$B(7N`2`R=m$H)S%i0Z(vicnyx4a&Xii#p{Cos4Aw&x zmnOaiF#!w9zY>2D{SU${@81ct6f(csP>pVLPhY0hhyD5{X(?eKT7t-brOMdM@)Ar%vCK@*i$D?%UqAE6f7T2Ur5?n?Y3$D3x_)1V z4c`d{@x4M{uZ7*+q+3K{mS>(}2fLlgc_h7TD=XUDp@h;RLrsHwme*R1Z3IgWl0`eA z?pIouVl<2HbP7!%H0c7C&W?F6Rpug8X0*hmn!|t}(tJ_~xHen0WXUyVmF_F0gOFUz z%IVtvn*lqW4(@pm7<%C0;B4{}9$@!wl9z!1;+!mLMmqgxrs=W8i zqtsqa+s$cZ8E-DrwI6*;g5$~ek~rfQ5s8Wh3m8|vD=>B+A9M%hwlBH~xjx$G%P#RtesvqtYt(0?D{ zn&r~@Hl<(iqac`At@zs@ii}3I<{D>JO8n%aV2KX?BU$eWaxk4^1^-4@v>h-Rdj_)eOrSEZ&dNOH&->e2z}-J zTp+x=$(Rx>jk(?WDIry97yOdDY>@+=^$(~4dnxpV zGi{%(awhh;hX{pX1$Gn2-J?4*YF?^*M$_v2_Z?6-`~2&yJDRfh$8@UOE`7k6qfH4= z4B%X5m!)uv9NS;ICZSK_7mKJ$;q1bt<%a7|3SX&P$~)$y#v{=ASRk##~N*d@GOC~rvV z+;-odVyz9~!*9U$OP7L}+dWniT>xtouGpl0=}Ikt|2mCE=Jba-GLwN*rY^UwG+!|& zXTgp}pVj~uJ(PoTT}5v$-27u#=IzfKU|m|cf4OK&-4>Q1__m9fQR0x!} z6Z3(41z^Hs{Uh0QpB0)DebbPdXWC%zjYO0sl<&S}SjOib`7C*2dYGLK`F@I~TJUQA zrpVfl)N1%)9(XmrGYXXh9ZaSi?}fDfxa;zpF=f6HHgECif{;u$tp+Vye&5l@uRaK+ z@bvr>FGC?fi&R_q@vKBhT_pvwxE(I7JiHd4{b0}D2BBui9zw2!EGuzzSs~Y`0peD~ zS?KwFD|hX8iRfO{ieXQXZO6bxyEGV&HVYxAeP4!-;TTy@#1YNQXEN!PQ93Lg>vmpi zR``p&riS>lP*TasLecoXlSW-p8t2k)R~;jL3zwthR){+#K`ld&jsil!3$}NVtG&jN zfjC(~CJCoP2pS^M0lQy6q;_j9H)bcnY+Bofd8eZRwLyj;&%RrBxAsNp0_#6>DZR}t zqDEzO`n^i~ZfAV+zYue8Q(F^_O<9jL@?=BEIic3q!Af^Ga~n#zR^hur`PrXG3W+ao zGkI-S$H$PsQ07w_zxNE`O%%Sm2!>3zaEH4mXJ4~}hM^{eAw^T6lG1TOooj_L1=Lb8 z`*lyFr@_6m$nLLr)B+a3H9T#T%W*NFh#IOdIiDF@4wd|9=#x9P12{f>)1zFB5&lTU z1UWv>PkwIBdDj-UdMD;EMWT3;qYeG5z~t1RaX^)n0Fb>uD-%08dQoOrxnji9xaIRNx1p^5Hqkw#CBo(@$#`!_+!I9ZiCoHhm|2sW`*x?oRu|LYepZ+F zn2~eiBH?@fRc-s75bsq!qv0bSPdDKEBQ(9*@K(*vrOKG!sh%UL;1$G1uW_vUGvnXa z1#|Qw!-c7!#(HEuA)p^USraLE*rH8CPz+1nd^kM=xN;UoU&d$MZ%X&(aq!uqr z-(TRb!%n}}^cFsFr3yLib%+zr4^2DEbPPQYO zYKnjro7NivHf+77%A~vr4tuq>11<$awk@|NYdnkG5ZyA&q2dWTV#+X5%9?Ke^(U0Y z`cTk4dXQ*I4z15{E5vDATcr5K(BXp5Xd18{G+{t7M|RO9N8mGPcMCCsg<=(|hh}-$ z#j8V4qKhPVgKOhIDE}`^m{*U?kCE$W!x)E&+O#ArbF8l%#D{8M2?}K`Iybme2IZ;*e{K=Jgc)*PawolI8I%3ff7$*`_CHypu4BwLqc+3Q|`EJi(PL$ zv|{s$k2F4m^rtBVuPp@}3cWYc)U%U?c{`)tYZN!66O#2y#LXFmuNV*;WH*a(aq9wI zj+eUIo)ab)n)?C>BrSZ=$j$^}QJh*M7PoJRY@^`RVtQph^iB zX?8>3)qN6OYcF-u&THTrW#y3ygQgxIjOZn0EA@)|%YtbUTuR7!Ve)j;{GUm%%|-w4 z#-m-w;d9K2qGn8dkXdJ0xnXz<`HkjH>VV@yErDuwYD>-GfbQk_{Ug0|VU7yb4G&Bp zn@#BN6jo?!`j}2q%UN#IB}qn~j zLo}b>0@}!Odo{u5s_^V1>Et2=w#WB|-!3DskN0!1RXTy)F;>}(bAzf?LA|Z455Yo;JSJA2IihIWE@AiE@^{gl| zaL4X0|JvTxMx3qLKBSF7!ViQ(eTurB+x_Q3N3kuSzq(yj719-MO&UP0$ z)SVESKN!P-Ys;qqofCoIUE$7QF!jXtHwJW=DG04&%3@WVk!b2?O_TG&l2nQyq-7jE z&d+o5KztyB|8im0{{t5`GlBXG&%z$kn@erjgXLR7&5A+3m$V0%%FkKSU8H;-g? zCYfCZ34n=z09@L0gNUksR>Q)6C`NFMLPJ@I=mbIU zRros`xTelCj`h9x{!IKlfboK@V?p9VC#>qUAU1whj*YDW9+3H1MTMD;oM& zyUlVI&L^;-h(qi~oi)y>IHcQc;!gCXn`!&R`XSI^^X$3+YL?^MMEENb${@snTWVDW zHGJJmfwFAo?8sZwVn<__vJX-_ z#I9af)4WYLG3S=~;5m(x?d=xZfm_Z+bd}4nl5RKkzo)Q7L_u8q6${&$!+civj`!M% zpg)UkyRzFyG*H!nySf^`8^SEbgvuekf=_jr64N$lZAQQ#dB&BA6cEjcFIYduJX}u* zl(HZPt`?v&55$&ae|+(NJh)L5v!5`xc%r=-3pHTXlj}5VcO7AB+Ge1i%=cDl~g=z870|cM`#yV`gCh9-!@T{|gO^FJ)h}nX6%a_o+X!XEg`vL2P}j z@}}sT`KSKmbis7aG>ewGgV0ZPQY$>x%O}}{m{vJQS}XF;f$Ly{W$3_|r4r%y(#D0A>Jo@#*+Stth_mMlswNl zh4C_w03Db{1YA_AR17i0P|sJj@eNI+8;}J*_#ttwU8)U z(bb_lDZ-}w@hC*BEi;c$2V#EPZKaYvCxMt4->*&MxrunCLsh=<%MMk+E#71?6=~C5#aZ+aWkkZ7-s^2an>u%MRFDI{5H|U zUVEade>($N#cJ+QM_nNd>u*QP!EK z5vec-&rh_uqtW8mUwaDo=2H-g zK-zh?+UfV8&1McIypV&B$iRB1f~-(VJ1f|a=mi}7^Oq0{+yiel}UVj zyJ|4_dHR&9n+yH_5fO9!{)&i=G;%}2CZ6|h+6(@{h}}`i2OUa^qliK}w4fo1bpE!~ zJn1aHAwE7Hky3g>bPft?>TIl8NlYM&L?T!kt!ytY7fZ}6TJ&&`>*KUa-}(@WL@eeM zctQ9&UpEz7p=uYSKPXvutl|O7xqO7jl3iZ!sj%3zZY+3ia6ol2YO^XiaZm0XEzwgk zD9y9r;@)MR_1XD|;{&|_8;1XIqJJ8@0-aC@46E^1sc;7{CFcWio>{DBtkdZMf{+5{ zRzZ(e`jI;Tgw5r!sLVN&$Mc@a_?~iU@V#tY^0nYX5A6Vs^yE2BlL&gc#usq<5iqu| zBqMACV0ao9i0BQw zup&rSwAk`D#DUxT>cwA$8*EB;`4!m!&LH5Aa|#RsOJn$wja@$pLDTKWD}VMh{$f_I zjwy@N5vGGD)EIS;{pq@R~o1Dnu8I>S!%DR1$r_J6Y zHA>=JCd#i(7Zh{@RhhHu$5qQ5GXE*+0K6?}%AMbm|yO1`1P6z?E8AyU96 zY6ImSqnl`Op;weHO`=GtOnauN*=TWIZo>%Z%dC|V;u!@*>9hZkHOVu|ONzmpb@JZk zxtT>8YRu?IBmnKB)T_oj^JWG^Cr3hIM8#B#rLzkHYe`L%Udi2XX7w;VMo{?rV@xC|BPDu->SO%dSkHm{nIi5KZ?P{xEc zb^j6w`OL-F8k%R{n$8Z{K*(5m8iSo}kP8@jKKMN|-j)5__{^){=HkRh- z{y2-j5ykXtolzra-!Tuk&pN5Qf_=T>AuqM;4wT-r!PQVi4*(to!xX9?u5(W$G13R5K3-)_UHXETBO+=<9pH_EWDp{4i9bH=lEGa+Q_=tue^}VluqlA{b;4+2;CA zP$StJZY?y5L-Xoj8nb?=&nj}a*2dnNEN+Y;Jj0WJnVo{xn;w6`z){&oB-)O&_RQ z#5a4{C)CXsqrzYo+RH|@wC6w_UBLb!NTdwCGE@;`raL)Z(dg+~aXpC?aeZbbN9;z- z57dI|mhxTKg<0-tw!I^zoexLG;}U3I+k7xf3{#$Hsbbb~>T`hzEY1D1-Eyjn7%Pkw zkt@>7dPC?rX;g$i6fE$Gq>!YOB8>kkLpJ~#w2H?u!faDQVVuVil!#c2%+K;hBo!TT zWWiZRdhTgJ0)aPLHeBi^u(qj5Z&}fbzng0>Zx5$%)=|&b%828^!yyP*dt^+x6V;GN zIY*Wi&!$JZ6ItyPuNefLF_2OoKcq8@qI=cyNd)4s|*Ds*8-tA5P5I#a}XYC;l|e zP@-I&#M=6V)ic*wcl2f}(GuPyI;+ZgTxO!}J4b(fu|iR{$YjxBwpJnONFFD4QKVWf$ioJOeAEMM}0%pmOj%@!6BUY{O z%Ydu`vXHKs7sM9ZTQaLwEmDxxsjr~7ay7tZnH}JQnF$N~APk*h{!?0~wK5wq>qW=P z7ili~^hgiUmliekEOVg^agYD$996MO<4e5ngTY#;^%7&PjIY;aI4Ey!?li=D$wmCB z z8~Q1##ti3**@R+XiJMNT1|YYK66-N>of$T0X*Ofm^{8%!u0kKSz&VOo^_E~KQ4IY= zwXD4JQ>CrmnA~?#JrVo)E2^P{^i|<>hyr{X$2fVV#k^Ixi);0puJokuoLZNH_kx@t*y`72Wj zdzpP#3=*w8{nFsf-<7}1$n$DO_I1p>FI^V_ClAS`)Q@skEQ6T&BxT+@hRO8vw5QNX zkET?h#o8;T-s_4(S-sFc?%Eg2<%^G*=HeOv_x&~eEIkr~ z(sRR!E!)YXeZ|MWdT0?k%`gC~g3#w0W$l@$kt}LIr?R>&MQZ7y7%_1+)OJJIj)5BksT>WEb(pLgdR3UFCB*51m}EZ;<7DI_{cB8mDfhX2ea9XhnJ zJ@f$xB(+EF6vJkFj?4<(;29_)C6gw-`F1puClTfHCP^K`LfW)7%5BOQL?g6(^C23~ zi;&rFn7@jMk3DS%uBA5)@0&70jbFU8EPiD^K?4Ok80zSYyNm}wD9$DH6E zTK;sCq!(V}gBpe1DZ}sEUY*8Z(O_Qil3kxCLV`1)OiS;;clv zu;{`_m&aM}&_zA1ZQ2j!T#mQ5t7!F#*QRw9$<{qbLt*;~Y92ZJuzkE1S1CM76W`9G zq%0{=fpxgtgCD9N62*EPDlz+{3!XImtWs_thtG$nPUD_81=|a2j6G+asj72KA&@}8 zvFJ>+rpeMI{zzN(Oxtz&ruKOuqxqxTY@$iwCq7;f%hAz!7KPbw`iyp1sVBlpWh;!) z+xK3Ve9p`DuruoB0?d$tpVrj8+!_GGl&~jwtN-51EQ0@f5jf9^P&jUr?`}Wqp3|7T zr|*T|(B3X&`rs+B8W^A<;-_F>K*BObrfeQZve-&|c=Hog%C{IP=71TYe00*87Wp*- z==gZ#OnD~svn&^}{tDC<3omLL|C3nL;o^|ty&C5ye~0jYqxn)B8G7NVsYrN4hl+sW z=O$id(^>QSVx>O7pD&Uqv9}~t=75Qxg1Gy17+Q9jq+F?qLP=w#prT0A4+sbKzj8Tx zOP3GX`{my6&SDUYOyq9i+6W;VGSe zSt$9*d@D@snte>^v{SARzM`wB(4Wrf25Zqza!QKW65`M|8364}{MDz0)-Pev835Ct z8GswJPXFIwKCLL+&Q;{a^p7l)-iYiFmo?;8sWOn{$a|Pcq9sdZnbeHENYF0AQlMkR zac6bGZsf(6BKeCUte|31>68F(L?C`b;7rolL@lOx$qIO5zeRq$_TF^S zVN3i#lw0YiFlj;-I2=xvWV|m>^6fJ&5s{`yB_{NnMQ@`P-V=}Xa}I}b16CL^o76&j z;jyp&kgvD0iaH711*vQBrl7zk>{o;WbECSWgOe?PNT)~79h;fnYf`unP6QbUQB?=A z2y1;ELh~8i>4-{63D6M5fzXsWLCGpLr>Qa{+m?q(@G@eP^(Ffp?u(`6Kk|FfXzZcy zy$6}b+!B!Fb8LYARE$0*8@i}9L|gQl75}<} zMyG|`?r=z4CjB5~tkRKR?GFxaiTKkVRGNt!>hSUsx4ap=(I=Gnud2b3s9MiTd`eAn zwrT-}q(yKL{BaACaP0s)Q3Wuj1Ox;XY809xGmIxj2G9M8h7*CrXR=LOi_W^2HhmTI z#_q%d>2K56Sz7QFr4+Kr)8|eO{Mi4~B8a@Xq@w!|A~KFz9D9=XTXT}aZK;WX}1jI$h0D- z$lO}outZe<)lWo2x6OkWBs@E{1o;Xw516>8c$N6CBO-?NG~)wU+pEi_$pg)KW(b9E zc%X`jlf)>i1Yp8yEGUbDlL(72zR{7lbT5Y|OP~~YR-r%cLi+#3?_tyC%+rK*$GRku zvFJ>QVdg3mLdEUnxapw^A|BZVig<1V1EM8N^3hTvPC>KQl>kVRT zX5^bIu19iE9;Na7Cl>OqFH^4vaQ~kPyJdNQbK+>OvgzLyKKP?*_=^&eEosI^0LlaaM|&a6K}8Vo zNM>q?0*1sCrnadi<8TfIb*X$)vhv$;ntW_Up~H^pZQdGvZKl6V{Ov&i^WAu9hVwyY zJiQ{As|ArVOiK84`}QPUca|-y$zHJ-X7str33I}E58_5ZD8ORe#*um)vS_Uvg%5$; z^PvNC88(*W?_!em&bR8?73ZI%5u&1NZO-dy4bql{{Vj`jgx#&t2IQ`y*du|u^7(l! z(@*fV{P5zSN4LZ(mLHkB1i9eunCbu-DylvyY{4gC&YJJvp=zoe9{j6t*5(=R;hIwi zzr=oDTvvwKeFf}br^p+19kQNNA&))ejmv&(Xs=Eu6}Nl|nN$pXcsMWjZ$x~$+7d|6 z_C7NUo2IBGFj=?>T;L+}3e{_5ZSz#QxMMrJuahaik@I6&h%esCZSapU>wX_eCqyL= zU?0BdPi)_IE!l}53eouWSvZouyjrjYx zV;e#H*YcNK6hh2@=k;>J{}OA<%Zg7jmQfB0n8ju1dB7M!hQ1tYch=xov`DMfh@s|K{d(ZxjCo;{Jx@ z1=bwp-8&^wlnSP%vR%s!SC^*dURGMXe>ataP^M!^Uc8Z{E|J*ArNADyttm(|u$>sv z1Y&nCF+DC^O0sb5sZ`XT?D0*qwfDk!dqBN z3ofw#AB-GI!yxndZHz=OoND*Or59P?O*wSL5Q9aEx;7Jpk<&m6Z=jKOWzsGmCWErA z{0J{aB-lT?Pt8ztA6VD<);3F!#EUbdcbDWyH>iLNE#07W4c#r>NH<6gARR+9d%OW9d)*HzI#iXvU7nPh+17|g%?9v6(C zM?}xer33b+(*<1N| ztV>nLKiaPT_uT9=tkme_$^BSv45yPWUiY7RM`)M*z)YuU&7%!x+h4dlzKsCV0SWTb8XGepKMQ(*90SfWj)#r|s1&FE8D7jNIU zga52S%y%X+#ZCGRcz6GotgzOVr=r2nKv+uaAsHcp-=Ax8!F;mfk*)@YBjkR`x6$^Q ze2OW(qg90#`+Qav)_2Sh96JpTM2dX$zJ}B1V638lI)M*ops`(UPfyvKZCr(xxn`TSlMu#Yo#o$K4%6HgbU;n?6{7yup9 zg#QR5F^`cLW*>r{V)_oTUmNMWmI%tYvbbM__=I3+`4;_7H%M8Q34TRoPSkz-Ug=WE zE0sF^PACL1uixZzRammqcAPX-Jv)fKyi(>2D5mcc}FSF*x2San|!6VMW(ez__kX4IXc|4S1`@7qsc^aB~m@FO1 zP>?&o4?9!Y{?fPcy(teI#=wY8iq5k71X#}J^j^DJ1X4l}a z4Rw$_>)tGNM~j9_lgWYop@T(qJ-&5+6AUjSIVUXNv2yXor(WBnCVKwNO4EE_+{ibr zryOFN@Q^Uzc~_0;K|aDUsM2wrCH_Wy_k6jH@CI*E5+U?@z0zY?VQ8JQFmW5fa%VR;tr|H-#uS^el^;^zvll4I!vNpzma( zeH0S}nqpLvKy-gr;X1+DqAPKK8}c}d(g=<{L1B_wBD)qsmzC`yPt^DW4`8Cz30T9F z&sn^Edb(>mbKvFTr>=UT9S=1}D~#^$1=b7HKsF?ID9$K)4Xaf!8n#lydF^YW>1KVG z28cq{QlCS1IcCsAv-%M?{h|JaO=1y0os7M^`HGF`~8X4BE-7y2SPvZjV!sCP!Nx;&p=E-`e^`hVx;BauhLF^(;XL;rx(f2C?%O%8)LrQ zqbX3RkCh$0uZF{+PhU#YZ_BI8-@64m)$7SdM%@2dx+&idVpWZzpk0K!99|s@W5YW8Y}|=(`6Vz{sPRn~FCr}E3~P4LGOMK}2O?1A zLrpdoJ!WHKK@{uU^;m$8&w?>+HRc#j?}@S8bWM1c%p>?#(Y+oA+nF254P{~0(T(?x z6sDA(^w^D;^GWJ`?P?_v348G)g(~ZOO!!-&y;b=us_3pCceEF^>sWhUk=HQtLsUMP zs(7`-Z~Uq+W%qnwl8VL6t=Qxx++B>i1)oL=8JFGw5s1DdK3KEwi~o3Fd5A2 zu|Dyz>&4_Yh9>Gnz1bkv$oP!EgHH(UxfOu#R-5HuE}&oJE9qs<=0A_V+P^;CE=R>$ zvwq%_=H{&4fBDqmNF|!3hDs;&OVXZ6%AEuxVE%PC8(H{Ef7sdfxK9n1b*w#{cS$;z zKD+M#jlFh z`wn}sV88y7OP#u5A@?)BARF|{4aeH}K*1l@F}5m|?LaS%N4M*8C;c5YJQfJ&qg1w% z%4m>VTsmRe)^mWE%mk!`Ymy<31VpaP+k2B0?vf6LT1D(~o30n{cE>VrW1LvhYuN`+ zBodQrxD>E#+YG^>&C~okWk}AWfyI(H1i4U*7SJZwDS`Ny-oR`C;_9r4xs>q(hpn4WeChtZ-~>dN~UlYVY5I4(UgCLPJ3@ zClprG_7Xoera};O%Y|QDip7cH{uTBQaEe*TVlh7;2hoQ>Z*X30Xg0;d|^7 z3#Vu(cEB*1eD-x7TEEZB>+VVFX=Fj4b?M5XL1!M;+EU@RpC9}sWejB?Wa;IO#JG1! z?WBOm2M^9HdeZ7Q93ClteRPu+EVvaCFTs3{m}!}o%+b`TR%dv4iOWJ=1!7t(0UbHu zFjp!o7}M@iJcJu>dlchWi@|Er_gjb4`uQKO!3{qa*Kp^9)WX5r0)jcTxNXHw~*@Zq~1LZB74yv=UAs$2(LTL76r7 zKKu3spxNy9Fp;q3m7tGHfV+f`lezEME}ygPBuXZmzOD_vu63QK3PMuG7Q z^Odo^kqQyB^9%FPwU&nNq9BTmw|F#AdN_=#CrmY5IiZ?Uz@d#g%wT)Mxu$x=|6saQ zCM?-7j5UBo5#5E_Aw*6~q0SjM5!W&n0~`EeB^__k$>> zxGjs&2v1iPJz5TI4T}j1Eyvz6qob9*@YGHLPk%MrHFyiBf8M6y;f>t|`P_~_Rd)le zr@w$_@V?L!*7Tg&QAAslr$3hW<9yP``N7PY@23X$_eReR5f3YHGrGoZlwIPP!gm{H zB&;6s;CG*v)o0z=No; zsCD}Ddqc|+Q?I;EA{kh%9IegE%BUaLZ(-K1!0Q1N+Vd;S>g<`L%)Se=hq6bF4wqF@ z>dUoB?JCIxmD%;poMRA^mA5MMfYSU5)`2OHh&MhUvQy}m03ZP|tBfxFn-~@ms<3F~ zi}3srhntN~NrfMta-s`X* z-91WDbGWQz2Qmx2R$cqnw$Hzoe=O4_M}sAGVQtfD-U5i2ztf#(2>V%enHxUs+PIV( zukz1yg|t1s$T^{wD=SBv0&flEh=#E0;;ma#q`iLQ4%=y~Dvy=~)8hwN0-$T~n-eob z`5h`)>KRd^@+dfgRW&s)j&A0AHyCV>;69t+b3pEQS9=t2I=XS;=(5fC&+FNKXi83p zZ*2WunExOKj?FEY>q!)nhX~u)PIMRJj?^We)h~F#Eg3(RQCUQ=2R?sQxn#g}NiDTN z^?iXz58?~n6R8OLm==*-1mO_b8$bO4H60Y-XQtcjd4VT9PN}6%HkW&&ah>4@7#Hvl z%L|YEw^LJT^_6r85b+J zF)TUMq;jD{$ThFtNAsRvw$C{qirar%&Yc~#Trx4Nh+aT<+Tm0XhUsJpTVh0E%(m)LES^Iw;=nAgWXQ%J^CUa5@VQOOn zPRSmBLYa|L2368{9G`zG-_GTeFn7u~2SyVjA z`kT_?*4ukKkRqA1rxWV510!iDIXqwf&bL<^`o^;-2~WZr4s$?s_Gk(VFJD9Ec>MFC zpm{18^oUJku^?HQ@h4(2dyE9Z9R&r#m*yULm7<-p1_x%yvlj(j4bYBv8$jnjIL%}&TG90}j}HiN-Nx{?_Rk6!eZij;gw zFG4D&OC?TDc-NRleAtd1x$I=W3D-TotPtJY-i-h?g%y5Sf290j4HrPk+s(*FwN5t# zh9gLbN=|k~atcN<(EMqYn#)0Ty8g6@2Fh?fcU*i0lA+2t)uHta`gny%!as&W^Zu+~ zpq7g_*Df_~5u0IDO)b63V3V=S9x_B)2)Yk(6<2NOBfmm{I%mW7GzzkFR~>>?4~}Nc zrr;5>bhFlPpDu|S%7ULeUdie3wtk=fCSl?Rz<@u;9}=Id%={)2S?m=*9r|-|Q{cK5 zoNigQfY!IMxWo8+dZHyG5GIE7;aHnra8j{PH=RwAJrbA%LJ|+0yMJSGjf^`h$B}Oz zRYI7ss20s)sS-%5)^(^8`xY(?zn4;7kcF^9(?&2 z9|U?j9AwmC`m?mxyl3FpKC?P-Llr9@NGTsL`)mj)D+T19ktmj@kYxZ8!YrR*17w1l zU*K+B@86MADq}@62gIg^ZfKP^vtrPGbVKs>X>oaG^nAj_o8zzDLOt+j#0rUilCR1b z|Mq%T_;qiEam!gZm1n9T^8qkm8g;1MP*2_^%oPEBXZ&bEDvr&9e_fKxHoK*d8y~*Y zcHMXxlK5o9bjw(5hyr&CKhNglj(OEb8T=PhbCkUs%N=jHeu>q!1%3ghF}p>vboqKo z!-23aw)?T9ETE-6w^Nn`L)=1+H(1?e(k5@!0ThMav3Mo_4PQ>QysZVknerPd@Dsb+ z>V%+aVf?4JOfmPNWjV}t2VEgy`7q&cSua``(=bqUo^`v8 z&2n}DF^5T6&gr>>D(k+d&C;Ocz=ZNEh6ChrpC%JaOtI$&$94t3Ic(BP*S#fLU*C;H@L0+_kX}dgg#Mi; z?R;F?=AaewMemIJs^mJH_|H6Yw1Hbh5SXL~Ru#-+(N#(^efuso5i4&quwlXO*Bz)B zR)QJV_y5qV&+y}$BclV`zRbFGT9`_Kj_UarPv=y zSj>X&`Q9THZQUZD8(d{TBH)qv5-1T{;HUDV$=NQsk;h0e@9iwhQJlL54|ANec^j$6 zw2a7}l^AA2f-xF4BX4;-X-?_NEt8drMjIw%yg=FS;K?`YbuPsNxw|r;l=FFds<%lW z3muYpQZ_ZuaOZ=x3~cLG9D|Jw9S4Dc5t%DL~_ZYFmk-A2lQQ_A*uhvoNTZ_no& z&a6Qo?Vjh!uVJ-=n1(w@BE{U|(h$S~#4MPD6ezV{DwQ;b4)UMvIs2}MI=h~)C<3MH z*1}blwgL(69MD!wj>86GA8^6%`U5UN0+V7|mS6Io`51H}RtTcnx+>PLzA{2Pz6HoH z(&TM5PZ7dJlP>8EE^Eh`n1%LJScvIH)>V8I)NBOVC47n6; z80YFwQVFNsS7m2 zLTjUW-wt?#)3;h0EeJ|c&6KnGsf~{7P;TjF5)k;MLWsc6F9XUCZlXj!?q19xyS1(o zImrGk-kwjBi%28jVt)L|Yu>ZUEIc1SGmxdvv?7pYKw@r#uA*Wj3rpMcxEW9_pJ}HB zU?Skr;5k4)ye@i{{|H&X)FRTJvL39_t|3ycfTNLU{ZHrN;PXj!2xgs{LD789tgDUE8Z1vF zYBxL1=o9U=psN>@2Wx8DQ@BBp*6b}dK(>nSUe~0!>&%RLv(Ey4>2ZoY>d$<&{k-*q z_I2B}ggw3ws-z2&#mvQRc>CmpPrsxVUd?fE!_?L7No>~Mz?C3U0a}B>337jo|*0!wbybSuA&4j?6-%j-3AoGKZ)mFDp_bu#Y-x_@ws+8L^~c_-~`rh zmEwHSPAbuAOl?=frC=BIDYj*%K8g^pZAk_U7HWG4rJ>zF{HkuQ{6v(&zb32YZSO%J z?5(Gz%ZF!d4F2(IOwV;`Bjk=AH@>7`GfNK;;&YHA65X5m!)V~`so+~y(ky&ta}e`< zwHre^_nzNOCDO(3)}}K0QE|IMFV-JnmM{ImJq})d7{ovoK9fOYDBUaEk3|Kt8z(sI zl?y9F?QB(8*LpAB*JmcqEyz4ILaZE$wT555t<-sv^?`;|-8dp{lL7^Jt8gT4W-Vte zPKx2c-RMPr#NtN*$(*-8rHX1qNeETUKAK5&{Yr>@TNWJ$#$XVKCTkt-VR2D4XK&FT0@+IMPD)nUe)r zRXYrL$B(SQuNr@Rr=FOHp0uH7cuS8+76j$Nr9M(bp2^^o(uu6GpzB21T9^ z2Uou}^x?b25A<(7=fP(U!~JOC_}!>7edVSmDuNk=#Tu*K_f*r|k`N6;q9BM}lB%#? zHd>kz*$*L~3LsPG@<%-R*moMUX5U;MoG9f?fbG*ISNB&at%@XJ7rM(b27vf*Aham~pWiD1~*r;aRi z{XDr^$Q+uGRZji-vnlz|>ylSTB#_ewWWo$I7hOW@LnZ`Baj~( z5_FiYpby))f;hz=g*86BeB99+7_{;bpETNBe!WjHQOBt;wRTa_T1efYkRie}oyt`v zRN8=^Pea2zl{;W99tXPF(6?=ctpND#z}JyG)-uO_1oGW>&n4fu6b*mU%Cp^;fj>o{ z_91D*&giTls<(;rkE5IFl1LMG*hI*mzYtJffZ$&WQCrpvx3U&UoghFNC_Z3e%3`B644Ep(9h@}=@!*uoyp-Ogq zGSEgZHJ<{-(C6@|tk?amHXO&!T_{(7lc7*)e-q?DbE8;BN&IA81{xJ=GI7xSyre5d2t5O@_mVBI3!3=^%{y|H+3T)o+r zom4Lr97VCGSY1_vrFk`Y z4=E@t4+rSC*!O2i+*wl510apX^s*=OWe+A1XS*d=yUTiexBGd->TIkRPC`p!tQS6N z8{l_^+K*S9#T!syl=_sG0)a~QajbcA%wDX$!;g_4bu@5%NN7g+Yn4or>Q1%+R|lu- zqs`~SX8O8imD?kkV@oOIpRDiJqmE6r477E3q`rdfcLX6281PN3&s#2d!50s}s?_CP zHYVn|Edr!1f_t6#vMraVDey<1Qc_b0ghhuJ7m<~V=XV&Z^=~54A_{uOn+L;L0!)Br zp12A;Sly8g=G`!U1msOEAO~xxMD@2csCzej(_)%!zv*r5eE=}-<9keCe6MN%a8P$` zL52WPSOb|}mY}8e%~H<4MBjo%(d@b3ob7qHn4voWKO~|W&i1II?h^lRv)`24|28++ zxd8;RwY^>8LnidFHNW zkP{l6as?fKC2tKS<%@G4nH#%m2@CV!#eD3u{O^c_d`=)Af&c%Um(ZFU{kJ{DZuRPa zVAPlYJS=+r|6(o8ITK;Cw4*)w1Xhf6DNO2v#|@tR>loFj8e8-%As;>K8Wht1^8M-_ zo1ApnY=RPgrSLxt}h(d;5ShkeE0DVp>W1h%N^(* z`BL#Ic-Pu-2kEBD(st4NfscC^LntmXS12H}00KSWR zhTb;mpB&1ZC_~LHEJ`dO``Z-<^9?JUq4n1C@JAQaXR}ZWPXVnh!p! zKNa5vM1FaB`FcW#Xax9+tf||L-|PPM1=nuswj{gZ4jLMotMi{pkccQt@<&Z_+m!zXeYrH?yXYEB$}2_BkdsN`soI*vU~~Tw#aN(? z{}xQc*dI)=rfjTl->14#?+}zHafi!-+&k?NBiD0vj7qw8s$~Z*l~fv2N*#^lg18sh zBC_HO@93*!XZgt#3@ltdrFSFdA~22qW5X%v37#rWuvu%b7fLb%F>Bf_IoskD$4hKB5+g;Bb#;%3QFhA zThG%HuadgqY0)jq)FyDLbLrr@|AM%88)6y|=bX`q;L7z15g=M?}Wz2iZ7cV}L>pemTWz2=ub4^#0 zO{k_@C@;yk0SlMyFscs)%~eJY2V1Gnt>m%{Lid$J5~T_vgJ9`&kPPARe$*VT~#7V|mR{l5lY{ z45tNPSx8}U0Hfd3EPK=aF@yGaF*NZFf`tr}lCBKzBHKh+OuqMbxgvPX5As~)bnA^K z-Dd;FS)&srbKXeGpVsr=pdKVbiG<2RLt}I5ADN@<9n|gt`W?`GsDV*3Cm$Y`I+nrG zqI%Dtzl=wktoPZS^aoX}(q@6pnUR!P7QM^%Uu(K?ob9bsIFX(b2dPrlh+b*L#H92;&#Z z_}kt{O9MFO2X9S^Wd?${?>t%Bbq?=e?8ZVS7KxR0ccXHkc_{CNNh+&`kUO)o74C99 zsdt|IK~Eb_PP|+&KXe&GYo;|4Z>&jKwqgP+&VP>nJ>4Pa=tRX~I7c$7NYC6;Uf%F6 z%5ea3eF)WA*X4R$2E=*)E>#gl799dd&FTUaM(b09Y$YzTnY)OYgtmCim!c`rqN3Y~j zxVmtS>?0rsbont*vbHIHIh}W4%&|Cr|B_drC>hEnR-ctR{?u++n%#~t?ZQP`cbl%g zIpD_Rcy~e|9@*7?QcITs}+vkvicJ`)pqeXPzyz{{=TAM^QSL(HPur~4hAR6 zE;3tB&6d&pq>7T|k^K73Z5{8&@r%M2S=M4e(G{C0?s{LL6fJDNfFwAN63KU$aIxW) zg_Rt<@6^v%Em%K)^QAOKi{};KFa-S&%9`S}L*<7G>cRMr2*ELT1;c;piJ$^zPU*PX z&eyHqwe-c;cosvs_-ypLWg4^-r<%@+Yj&k+GOC4xn$Aoun0BqIoXHE1&vUqPff|co zjkc_&+?cEH%?G9t2E)9V1jgcWM~iG{v;WpU;Mf0m?c+5OjMTR9=8mz?0>Aq*%)Bwm z?%4hh(<9OxWCrjw+=X?R(NmS^tmD7!-S#-ykork5{IycB|$TC+tKK+cz$Q z)8C-{WZ{z}4l3}c9HPs(brLyiw2@x*?quX}RC4o$S-4*PtDmi<=;~6@o7?Z@KB}rQ z!k>Qka_fHMF}LrSGM_jljDas)l?@(O(U~3l@Jfi0K4S6osfX2c{gD)peWt$7AJ}vZ z_o9wZrs&)IN(eAib+zCNCmMz|Dd!fo&Hd1aJxF-Nz2YItl5DrAp9JIh;sXTf z=cunWce2l6-Ui;d*c_Jc2hs)TLvFS0JA97hK)YXv?fFlmEs&QB*iFu+6b!L1;|s~e z*_Ze~R~vorNHAoT?kiU(sji+y5zKUcNq43ny(7;3D0&-ks=M%Hh>*~5J3i>(>9nS6 zb2m;Yyd!3pwhE~83}&>(xM;#e%OQNY$7vdMTLUch6AHQ-#he(H*6%Smh^?QnHrs^m zF@ws>9JNmfx+l|SM(1d*!qQDF_A5W3+4Hx=g`8;I7egqofO?C8%IPV#(tm0q&MkrW z0}}~%6_Hu^*#uwjw^C&X!pElufm^8~lY&ZJRaO~*wm=yJwG6CkzSey*AM4)N%$gzc ze4hH)SkWI*q%(vVRg(T+Y>ZJcSr_JMG@60P28~lFwt#GJWoH2&d|Hfimolj9CIS;D zY7#E6?A2mPGo?T+sk9(1pQIJbTrimUx=30250kx`neLBe(P>hN*{Lzagr|vl)6V&| z#L6dV-tMXz7)%zv`c>YbX5EXTHt`k&E!C;*W)X4n8QM0tcy;AoL99$jxK3yD#EJ3Q`0_CFew&bz|X{`r$ z1U4m4KM(#o#97gQn9K! zrm=+8nEuFgr|ma-poK{)f$h)c=I)x1Y&{qmz3Wx)h-v%Qn;YaRY3`GXmQ2m44~?{6 zWh&emuT%*>Q*@QGa|1S^Nh^%yUa1h3eAb5}>J7jE*znofiIg?c#e=_tmu?%09A8ad z;`cvJcViuj6Drnl*dNKBH|WPAVz+yg(}$a)&kUCY>iT&p@NV`@`4YvU_W z@1Q4b;jINow9Uej;h2UDGjMEbWGT2gJMufJe=aG~1%cfU(+lDU` zgRHiU_bvC&*8?_x8`M+QRJ)!c5LyL(><%+?bMoG^uBV~-8~t|9H%Ep4gU`t{6e)q0 z`bU#4{!^6|#{EVAttp<=`O2P)LeBRmj`pSL$2khU9sz^XQJUqBf zNI^#jpEMd>oSeo(ZJ|BAy}kYf_v@it2GsrQc^lHcT)d+I<#X)Y|B$8r@V~VDr!j6w z%U_%(LPyqRP@(OJQCZTAgd_c)2G{g%wi_V3gG zR$2bHi~ry9(?1AJTvGC;tG8F$Hgh(3nC*2!iTj^cjR3mW=>Hn?vv>T&eObon?gBy( z-*oCfrHPrHhczu2x^{wWc6WAm$oQ*y!EPd0cO0}z(Z`;iB2JvnPER)3ECL)M_d~ir z+1O&w-3>s|M8)i$oE-8Ah3Sd5a{=Z)JtOeR=H>Lihxp+b-9tlSzQopO5Pn`>G97Cn z#``B!89opMj0NZWDdH9VJ$0=z2**N*?SFI@sy$ifkW`nwD_S#cVAh}7=3dfNcuR#e zX!fQKE%rIR&Jp*Ust_x^%rptvW3d>rLr8Y(!<9Ps)^BeVWnJ$q6y=8jQ4_~>>R9A) zoWzh0iNL-Si@bJXy!jR;MsUrsKD>@$k=(=kVpOW*ey4~1o#9E>V}v~U+CIlAZH6z7 z(q(tHEZsz!E=l@(wq2ZTdHTb^>#6ril8k|$6WT};entsZarZ6-Km}tF?DF$A)zt{9BgdoQVES|+913D{069$*`{tunDxbVF=4P!5ER=M{pq8Ch=d_pfe)nW(IKL##4o4z=X3bp0qD49;68!%n* zKYU_0-apkJkhlJY!-S+zRIqxwCDZt_b1 ziOXS8S>47l_dBtS!*f{`av5Wpz2;fzXo7u3dJqVZt{$hf1EQkGJv~T>4)!Le3GQpR zLb&)ULnz?5^8Lpx%3OKZV&VMB&A$;*?X~3i4I3;hjp9gI5uZ6||HC_>8!Gf2m`nb2 zvp4y-b3y2oaNgO5*IqD<&D(kIaz^|9xQ4`c8fEv|8r~)PY+7gWRu(?gVou_8kky&J zp%9ZMq~u{&ChDo$@$wpKp(}M{G9wy<)VhxLPidmtW|%n~qs7MF6>+GF)=f+54E}1> zqEVSZAQ-ecH0Ua=?=ZR(!7YPy9P88u-CB%6H?uc$YsW9d4_{@7$NTKi5T2ooYFCIr zM1_DCs$PR;y>~GqyEV;1*Kp!ocG!5NWvQ=HqaNRJ!u}C&Sze-6Baz)K{hC~qLHoNb z&^JA$aXe0^!6P*9(eIIP8-mkfn+2agn9pMw_#oFMeaZ?yco%8IFXcj2AuHmMStPGZ zifJ#^*Un{ts1)w?||6MMQOKrR5WTqXyBq#c{=F%(@kaO`ti zbUpUKTck$1py9H@u);54qLX7iB9Gk!aRrVS`IUf&fW3f*59_~0IB5$n`auC*xn`Wq z2gOE9QBae6+_VAn#g|q((#xoI2i!4(@-511Pkz*GKgYA~3E6iXuIxkhi1?q=t%L!o z2;o+s)0)XX)W9voU`9#%ytCxF%F$ymp48OWcjt_C7Gnn1eJ_@k_O!(0K0tj_7|dWaqibqr0=gxtL)9TG$!!N$4gF=;~jz=_IWH-dpmfKqX8C1ra~SjUIIn1gERb7 zVrbAOKtFO&Tc}hVy2MZ;{?Qg|jSg-3NWw%#n#-im_q?4z%oP#xL!1%W25|Pq$w1Td z5Lx<+%G#|Vpsmf~UF#C~QTbqwhRuBgBxHA(ejFbU)t}{=GlEWB>=te znvAY3v5IQ)9H?P7)02_3dsOR1-Xp&0P3<&kHZp`^TyPV~n<5m+yP)NO;F=LM&$#tLu95GZ z#LEsh4LFYI9G|%+pmWd6l$kYEUs>heM&V{}5L~&c?!@ub3nANIJm=!D?4_x9Bw^0I z*I@Q1pof76xocmSGj8yJ=qiC-S3oH^k>Jrqr*Ac!T(oC49yArtO0(9QE~MQDlm@m# zqhsyA6zKuBIklMFLgT0GF#LicKE6DH^Zm-9q#I+52AKxsU<<5Bek3mg2PCZ(2b{v= zFd;*vj1pNCr!}=F2&Db&)y^ilbB)%^>ruv$3JuyuV#b$?oBwI{7LoiH`CYb?k_unl z4F!Hr@$$c5;=hQa^nT;~c$+P5?>+{iXrf5`KfCS!&C~x&oB01t=Ksr}X|4K4D25NJ zt6fe_$aZaZgWAiS41jzs@y}$i~i%q-p zy8im2T5R*-XI5Z6Y#^bBDwBoZ5J}3qJ~Vt8HhRzmKmW?J4>b1LhB7L-o=PJpbr)~E zYro(V*n~5(TaTgKlvPySckWw_4_Y1?E=X9qWvZ55RLle<8@m+yx;lzrW8X%XpklLv zcV2Gp4)@1jU}GySEGM=s4Ur|3RxsEK#zO^*_q1yT($CYqSQ6fm>k`H%t)fl--dN{g zX&|s0Qk>R`f!l8fTXdikW`vh7FdMM^K-@Cuu1l`bGh9CH)D2~lIX+ichna6*D>f6j z@l2tf1B*7&AXNcu;DU$u1zThwP-JWui3+%>r|~A;g0pWE=4Yw6G<$!meQ?Ym&X&gR_~IZj>5-TZ zw*E%D1?#kP07%)Tn7;3}y|3MwrVbQ(;Rn^T)A>U6wRlh2G8M|uS`jcK<>QD?dJo6m zVziM~*R);d!7s1C;Qcg)?N5guGG?wwO7*^nQ8nopo9Bnd53om0{ZWG%-jAy0!e+zE z+xKymkd#AHwQq!VEWFy%|48$^Pd;9UDJHUnB+-b*tl^F{EKQ;BoS-=2uBGFo4r4Pc z(wpv@wM@jMQ46M3eT72RO)2r#Tcp8Y$ey6Dj1zKvac6=Ku`;N)fn_Ia*utJUF&Cab z8*8^FRy4+4r!;b*a-Qim-I2TCoU!iJ6dAd)c8Oq?5mHIZ=@HLFms$@jeAY~nBno!XAPdp zXc+v;c%zDDXxFSXQy4&sMeI2}5@sFFS%TyBh6dlge>5Vg!Gb!jMW_ZjFt7Uaz0j)! z_}nMqi4-35?4ybSt#o&$7!6R5Xw~QDm6F@fRV5X&E2J?BG}h~bR4qfSLC2qyxhJ0{ z!+n1H0w|W~nd3LUWWF3m{i{obP=f|@us`2+w}*0f#L*Y*nG+)XqnX?7Tcz6kKd@{6 zvtvqbh)34}!5ey-m-sJfLytjLqgqA9`F@S2B^S7F5csG>kM*1pc*xOefAKk`c4)20q5@}HUizR-eE!e;c} zf(vWNeS?ms^3)28q6L{nm6ruzk=~!aP)05>dsZ;IufEEdSfogWITr|&+E`iUD8#xTTM#N zU3n1vu^;{9jp`OQ+-`HEJR%BVtJSo7&b%k8?&c53z&X}ed*!05C(DLM<7hCIh7noU*?x=APIU=9Pcj2Fp(>(zR)h zxGQW?E&9+FN9Vr19<;gH$*ntz;k5<3CNol*Z+L(_JT3iYyI~cpbeJ2zWi# zV=OZ){UWz7!uZ0m#p*z(lFyR|KZ~BSgud!a($|x<2&Q_|8dply34x~)FglRTxjfa4 zQ`Oswp*Su_lM6?a;c)?LOI1=aB=Z+hpT2a`e$hpoa{ai7tVO;jQ}ILHM;kucjFD=r zy0@0uV4oUTrZeJFP2qS@um25`Xz==Q*dX&6babG3Y&05+ckre_Oy{5)boJ+9L~vuB z9F}+0xCGcoQOW1E@16$6d})>37yqKBelODS`-!EEq%R;iBf&fI@3fm&hQro}ZwhF= zfgGg#o$w7XV(B(XY)@^APhhdw@sW);U{^^t zOoFr{Zi&3s0P7@lkMRYVPu5U)Rl+v%V!+pAb8brgo(?6|vGHH2uNb0Aq<`3?=0NJba=a1^2JOSdXcpeZ7kfJI zzJ@yw%&sl5d8@A?iq2!4`*X3eM=Ia9C~D!0|1Dwp5ETAmCU!ILWo(ar^4v&RJjpdd zzWfI*jv>FlthQ`a8CXLxu7bihq~dU?XC+fY?w7bD!Fjox-M4wUg=X1D>!J>P+^!^( z4Sasrf`zh}y_g1ZKB@*we+$c@o4+S0tJI2{oLLao&Q7Z&gRf9Ci${SlxQ3v#8jsol zPMhJ-(Ov(L;m95yZkJZJrwf5%+KL(|9wj^1Vewj$tBktb1Zs_NhkWr5hKHY)rnY0^DPU+Jf% ztNBQ`Uy_(lPlDZ4|G|5J<`#?jm4-+aiW_m;fl%m+(dZio@P;A_l{y6p_63VECOs(XyogFrW(Um;sKwa=+%8qV zDpJ)ngR6XES<6WETx4j{+oyT#c(AX~ew4gZ?%e`qcntPQvskhSOLA*iGx7u$BhN=? z?F$)&-7>P)(IabKJ?-TWWTzAsrzowOpNi(UxaI>6uMV`Gj3n2Dl7$^2Qa|pzLSa8C zS5Q};o;9Ng#@Ja((+EBO?GmaEgtv<)X4d_3CdviS-l5<@X1<-8-LHX3XCpZXdC%?H zzZ$!5JvbeEA{1#YUxUq66(3)O&`oj>o0VChHy;Xnq)&*6V$om7E?;WW350QT{Ti2G zDpxiOi{iwB6<({DQ~TN#O>z`w(uz7?prT#B;l}AzZO9t$H9h3;O`_KGV9N3@swyXI z(L_q(*8@KF#cW6hyi~=|)-_M7q1XySv`G@w)Hl_q^|MeBbvR@3;S9yIe8%Tyvf0 z7~>psE}TT2NQYZR%#joxZ6Vu2ekzF+;i;I5J>I*Z^=rCrdBrzco1QX zz~`-or{O1Y00+=gx^w$BlyD`Wee-9Q394*~ zkyLKGQ!eQKadRjCY;1UpE8TKdFS?2g$myFC=ElZC`;?IU*e?ld{p^3VcYqVbFZ3&C zLBuUY)Gs-?&FwT^@GP^wo)qf#b#aHn(iX*CA9kGh{%0YWqY?tpo(M?jNB62~<8y+3 zeSs^_64aVTki+<#cZlEGLv)GdX>7SaO}Bzz4%b(oNy_JBxI>r&q)6(-19aR??iwPk zFVsiMs2p9zYta7rYT0tM3a8zuynAr3v0`W1Zq~ajDP@ ztYEHu`d;c>UrFwSQPZ6tCx`01r+s(pXX>fcFI3ao+Un$Uf}qM}s*_T8gY`+s2k4W{ zp^BGVX)-xweS(%AQc8B#>*dZue zJ3Fq!6IMd41HGffuhAflCZtiP$AVthU1_tk#FEa4y3gb4?bJ_u&oCFu${< z_Gn0%e?|SP6+nVzE>&dMrhfOUkBo8sY_n;-M2a1aCis_wn!_9bzf7*-qURO?S=#DeA_f|9Ch#xQ($#Piudg5Ra&v2gv!Nk2Ey+#Eez=_>kc`PugRDedD$H^=&ir zFFKV?@gbx8tAGeIrM$llx^1d-uwKS=!qK|*NC5RDG&6#o=d%-$KX29G{MppU)bMSS) z>8>L|blIElp86;edZuwbkyFs*wbH_-sl>MU8s?8R_4E;jgX35?;zHZj!{`@Y;jid0 z_n&!kf?spMyZfx^Nc#7F-0u>!hP4;^f{a6Tg-p7fh4-Z1Zi7=KsfX$}$L8|oKqVXQ z=e>Gb+qn8oOQ@T7&u$*3$nd?63lSyoTtLN;JDPb|Fa@YqPNoS^9_rjv^P3GjEz}@n z7eB~Tz>+0l?`A5!pJN2>a+ad!=efkhhJ@2mRdh+P&OSX#i{ILdsFf+o!bbLNND6o= zVdV&XMfW2@G)pcvQ52Spg&9x=bY*suNc!A-Foqja5#R8u^{vQNF^7c7QanBRd=Ygvm|nV zm@cO%Mb^Eii8fAX08OC9jtyzLxQWcIJo_u3ew_!}Ga#(QAThh@kylSiJz(J*!y1^9 zBpc3Lk6phB0M27XA$h? zxs|TGT&h6ZIX_qpU|+4``WUc^weVz*&Ao!^ahJ(uW|whi%*Dt{uD)+wr;pyptqmT6 zEkl_@FGx%6;++uB656e!D#YeKGise}PO5cp#g=z8=v?NvZmAv6Y(>kGK~qh?c%_uk z`VH%(g};~k7ahOLz`R$}P~l}u;Vz?~+~0+W1>K4>@wO$bjNbzOYtkc3`!%c`-y`{i zTaEwrA21)lL~KEA4gpBKtTH(Mn23+;0?C0H=%Z!?uYl;@Qug-t&v-r`K}M_Od%aFo zUQEOO&KKgBcORt*A`+vU&~qOvNy<#g;feXX!Ywdo@i@3B3MM*(ZH7A>KwrEnQ~7;j zb{z}mZ(wnV1j8Rcr0RNbl#%H;=+nN+|HKm+2>U$x2=>_Kj$6DvG~&6J`JtPj z2fvgc&zk)#6%SS7*~RtaBfB-{wt^;?@&#;+fj)J<2F+V6D3=<1jTj(-K9c@^vKqso z76 zq(r+fyt4j!^A5Us-A6^Taxrp$vUyv!upGq9rasFER4K$v97ya_DFz5+evP>t!atg6 zZFaAdL43r<=__ZY(932aQi$q6Z@qr0ZarV@H%fSamVK1B|7x&eQv1&LUmL{`pCckY zvOy3P6GiYdad2@cM0gm>oqk_J{%3CCQGODj@~eVPNyY^Db==JPM9g!nq1}#}5Ufx4 ztFkrDF|71;F2W$%kT2_%0m?|nBPB`K}KcWdoAr$d6)=jZ^zYK$ZKov?*R*?lx^ zal%-(c=0pTjE>A{1$U(_ZV(-A-ToX+lEm0z~*43r;8D%{@I z%$<6ucxM%RuRn0hX-YFN_@j^p1-$@1`{s0?9^QuT?c*5SxE${#bNYXFa&X$bx)N)s znY>ost!_cld0alNtWAWa@b3J}i?A?zLIxk>^+b3bd44R~hI?Q@E-lq$(MD8E3>g`@ z$A}Fh%tqWsZ;(!M_YnoZ7)+L48@t#;ZM1@`tfz;;nDA0MlP840hX~%kpoa-!MA!Pz zp=dDy4uRUJzn_rHDi{sztH;a$;csJ{EkeBN!C4k&?mr7iNH#X8 zPeQ3*#=|e{wX@p)R`RUQ_3ng5U>)W0SMZWEDEn9+joT?zZ<0?lN116T9zDc-~rdqe8IYj-KPEiow* zukfEdwozXxGUm|I=@b76S^7`2MFZ>cm>cZ35}c75-qxPJaCV7Z?O{8@opC=&2^J?@ zEiGWRCU%1~kv-kGuVeS?5To4GD4%*m`K20HY{m+{sz2w~`4vDyOc}fN9rE8joVKhliySJuo11kutnlmW z`uLOX|NGzd1w9_|{;j|GPVoO(LBbq}Uw@lP&T~tXW$5QGCMqgw#K#KR`+jn7L7*oP zw8rx|?{9wC+)TEkQ@*ix(yjg$f`$3>-7kki{n(%L^N7UShE_ZfAHG_V-&JVf5nT=6 z(5S14`TYJjwH!Ouw9HA;Kscf2cKP71QZ?PE_T|w$OUr@{!Y5oCo)6g1na7Gj1kcAK z;y_17MdimM=InE%hA8N9x|@Ai?p1#Y*& z3TfQ?ZclKI3}Wdy5t@I^D+kgT!q3x4kjBtQk8G-5qrAbj?gH%z$PHgDW7-<>XVMeA&wQyP%u4A36MwfRc;pGiz9Dv(xcSV&Cy z@?hcBLIP1CJ}FNhKR)Ib!D?LUMIR!BrplDV66rChB>xyPydM-}Z9dRGa5_M_dcmgB zP}qB@O(7}4^lp&wttqj)CYllMBgnqaIUS_FXHSDF>Pl!_H6q51x+b>cxxtGp`*0T+ zEXk}RTCYpqS3)|oy>P$riDmAOW8a&nsoP{6uJ1$iE?$R|n6#38rM&=ZMS?LQXKFtKH$ z2Q|9ujZX>`VK4);;>dP%j^(Fr4yh(#M>5hM7p1Pg!d@RQ)A@)Y#9M*Li4X3-?9tFD zp?eV9j%e~qc-_0W2pB^~2WGK4EI+9&1QMP%M_%T5}$RvmOPaS<#rYgctIFY03et4zJcs_P5dFNXx-k zvtbsJ-c<(T8;G($sCU=fl7m+)mh5IMU=3B_xWwO;mjB0r=j8hq<0 zX-$-5_evnJ?RZ0eW>Dd{+QVo8X{x)uHa5f#+8K&lRWKE{DV5N{drZ+#B0gjTq=nbF1yyY4@NmN>N9r%vBBAr4`S?cHCs`=yYy zb!x^aiCu^EdU1kO{#)%?sVA<|1OS7^R zoHbrrrJnL_EPa48Lu_l4o-M0b-s$Wcb?F9-G)zxcpDI+%+%ivH?DxJ!8{+opWJ>O+ zh$P2kW+J&6%}JqSKtRwkrnzpfbwC#*yVD`2(>NwuvSR@y>X!AqhtN&AR*{8`XX0gN z#mb<0UOo^c1W`9oedbuu z-Q#6|huwqlzhT%9iFkgL2!tX6A|e78=CRk1?pGl2dl|coUw_}LpWqK5M+V_9_-lO6 zC-lo*bo7KZUTh!yKS^7lk!a7*6a24&L23X$r;%NF>pu1WALl7%7IvRGwK}_vA=|uF zP-2UC~bEEHfeOZE<4FoV3?5a z=8sfL?47WMWsaxCC%lWiQixJet#hgQfiNC=eHld9~i9iFBlP?hB%b33K2{PY?)RARO zGNAs_UH^&27-7Ql$jsu=3XSPoWlW9&r-|Cq88Vn6N9}HSrG*rE+)2dJ*hv}+uY0qS zy8;^(%}qwB$O8l3swCCc1<x;5ixN$axtKO)7Wk`!#onz+hW+33jP} zQ%2eDmzCgBPr~3jUQuORUSrg_bAIhC^%CFKQFu_t9bK=j-J$zkK?ZIpGmY0cPfwr) zJX)q584ZAp6!$xN&>-+vzAvV|=2bN|t$p~hTahF) zaLU>^%)`iwQC!%2ftC9Nld3Qff|^Nw^;S9){AhZNyWZ!mrP0*_r`!9m;a3<`F}-DXx4I>Gb}0Cqtr6dk=ozWxn734u2khw%JJLl5vvmR zBpT``$})PTe&D>JrO4n{2^SqL|49e_CCQZw$BF~XxvmN4?LJ}09Zq@o%E2Xb}uogwRL zH&GFoNKCE70)#&RZ3&-g_(j+X_D>u4?TMjs94vU0Hieq2RS94?r0mFH$jLc=8Q6`r zE);wV3la#a&_GhoWwWGQ?Pk!VDoHdXX1)kLoK}*hN--NlVZ6Y@z;Jb)`;3+!Qc)|U zs5qmy{3Nwb9UdQ4&rR3ZCAk;1B>x~)v!h3{}yU45bOFM#K@pY^E?98tvr5PguRVFJAwyP*Pnl)_p1A5_dI zEaPurHaXD&{3J&JXYkFcrbwr{gcUm0@;u{Tp=z0uj2T(xFg=`hQp!l?n+;vZGUPO6 zWeAm~TZVC4f&@v~BCBCdA9*G8>mTtdu;On=bMyG*zV#b( z(4`irL}(n3RhV5-w$$?Zoul+PiEVe{INt{eB*aDBn9)nBC^@ILxt&a~sGZ8dL1Aen zB50To*EL@qsr@b^}4(Mv;C9@Bgg5cu!UM;j1#QqQDdHk z+mhTfa{0NIGNgh=Kz)r@&p(G&Y$|=Autw98FfnZ!WL~Njvoh&;srQmO*RL=fPh-ym zc^IEyvavP|qNLD&LXKr9v{c%9i)a*AH00GnpgGIRbsUffr=$v`*Eo>hq?@Y9 zDx!d{LOODqFBPX#&f_`P_mR zhIVblSL)ToSWGly7g^ThvX7vw8`L8U-6e{c(P@^0%M_b=T3NRG@!~tZtZmujGK`!- z0zpRadD*Pv@gcqM36jM;D z$u(ZTCn#vz^9xFhTsEW72QDuy-FY(P?I#i_D&LMKUuWB9F2#{wsSQ|mPb-oB#|!W> z)61w$kb@08Q~Z?OtEA{fmm9+mA-CHL-(6XRevNU@yB4=x&-;H`op@q83Q}PlRLhao z4z3H$eFprwq10_HhQoo`vcqrZ6Bw=Kja!kG;7~ZVwmBzY;ndQ_+IU_~hJ^#N@9UjulE{<}dea$MwAS z{mzx{)vS4z#iFF4Wq*QrcJ?lmD?|=#Cnd&~U#)s?Fk7NK)?*E@bPh_58id%?XFH z(3N)IA6!W}VWM+%kM8CoLZ|LZ`J#&FSvOP2 zQ60;YVvY8@9^DhbDAAkGs;zp(q z;L=tPQ~sil_Jzi-A`1zs)%6k~haJxM0;orH3G(z=J}Zg@dEeR#`*DJ=zuk1Gvg5Rl zQ1Z<0*8fn>2TWONVJ?ufzQM*Y>6tMfce z8yZTjl}Da6G~x9n7!E`J1Gt1?Ws7e^IKzz3D#q(}l4sdh$DBZQ;uCt* z&}({lV(wC{?B8IYtKk-;9V460J7g53-R5xG9*P@Rm<&?w4^}F$mW)hvz(}=8PC4*~ zrc6pkP>kmLj19fQm@2HMpW+>U^};ciV$nb(^jjNF2z7pzCL9{cIpk&(N&a9JP*(wm zN1i@To7sjrq|TTAg;u2?!L`Kjxv~(hz+e-E`q?{)Tnus(VkHb$QJP~Bu~s{KEVI4D z++j2pG}6%l5nTzsG!=;R#X~m-O?5$EkS@P+U*Yc6AOE?WX}G<}4ESE(8;bUVX2PDZ zrkU&>sclp+DZuZ7mhM+exz!Ef2^gH{zjxup06A2OQk{}4b=&Ywnu@=;-mF{X$ISJpyY!`R0;{-Y-3qx|w(%++EVcI2gc3;srOC1^&Vf|EMP zYY5Is844DYSmf`;`uBZZK>?z)NAg_;mj$o8R5wBkkwD-m4(7nWpbXA=6@0)G?XHb_HaX9%ck%0 zYu56_3yo*op73Sp{L-p_%UE17wvkVTO6cl>w;?!{22D-f#374tr>k*~Mb1MMKn=mJ z5p zR{XG_fM9`BZ`PAaO~&KWm?weHh%47hqWSrQ19lEuUiT5L(fv-9Q7AhyD5>QfQu)(m;*e-reN|)yHg|tJm6rSJQs& z^$5WFS#zAAjAGICt)zyE%P#=l@qt0K!lSy{{jf2(TP zXcc>*Oq@88u@-xY{7kO0`styg=6aAB_pFyh;EHOO<7&jRmVcbz(}~y#3ky`;b`}?br;Ajo{GIZ&X4$sNwT5b5!ea#OU z)jDMdQ(3g+cV*!Lgd)R|MZYf8!LdSrq{=+IrHP?C&#d#9dn~SbqSL8-=hVR|WT7!o zDy(p_L~Ba=+d=%RZ9S(8oX(;$hx+hpk=4RU(`t(` za3XlM+zk@S@0i)FCunDPi$gQ@5isNiD2Rku1Oj6PN&je?sb0na7R)YfusgiiHOjbD z5~Mir>kFSHMBwDt-1*GZ0v zU!n_epYsd;HuPP&!)_zFUQN{7`yg9`^a+~2cg@?U;HU5SN}xkn<8w)kKdk$4-0$v3 z=4TA4Xb3Ht`J}>Bpg}kBsy|M^lmerDaR8#bGIE!m{g%>5U6iUZ#11mN6&^#etqBYa zEdP{|g!XCR*21x;W?W|NK<}r}fu;U+?2Iijv3}o*hDmTjkuQyhG*3c%g3;10)>$~X zBE55xD&@?n$Imd_6!2P~b1We#>wuujFI|&k%j#Zdlo6YMPD{yO=|I(#L$05oGrOt}pd}rFT@J<#^)0x$w*6FSGGgJBWweKa{7Ng3R zML|FzTTWYXmj$nd;k>6B>kdz;&%AA3$4&sT&-74l zO6X_sn~A@)BC%4B#Lw|TL1eC$e;9R*``gG4av6ZXMoT#Y)g{zg6MrW4=CfdraU|R` z0tHTvGCbFZl%&N%RrJP%o{-bT246H~9cH*TNZEsCR)$(2H$4zRom4f$yc;()p}$DA z>T)2=vQ%ffJF0i_2M~2Y1+rkhUMK%@fMJz}pE?V>y851Nt#{i%VhVlq|EzHs7!h&* zhzehOfN=VBCrcdB#(JuYCMv#b_IkGmr(-gLgrip}5su3X?-_ue*$1(Z8CijEIaL;= z&Q&4#i|qDOm{q93dw)s6nbXefm|2oG@0oV8qXRF)Dl*X8`t0uYNQDpo=cM4;?%y)> zzQ}*;%zvvu5D3YK|JK<4$ie{AQV9RbTISfEb0L z|3^^u{#(=fe^Ej6;Hi5OyViBT!WU$osr?|K^8M&CbeVSie{cSkb!-w22t#q0F`DBiQ(KER;t=={Ali$zF zg$PpUYC~cOmtFC7B&{E=_Mpt4Ps+fV8U%t7;-0f-9@n_u{`fNee$#ojE#rwN!+kvt z0%`C)ZY8YpKCj)qUTYB0y*pOiJ>Tl^I*GGnnJ5yxs@*Ler0*K~IG21^yIY%)oS#NA zmUMTnQY6dBi>?tTjM(5fIU$5CRR}GbvxHx7-@TrP<+xk*;w(e0#Z^h0Ddoz)a_NF= zS2a1u>$28tyBxt>1@px7qTZr1D8S@Qa#n@!LqRt_xR|>wMR~X5z3XS*_}i=$L}-B| zv@_SKW);0e$Me*QAG`{u&^!Fr>>~4n;jfW%1fS-3<5`Th{AlnZ@B($IU#4m+5=CLijqJwUIwS>HU2ouP$iF{%pPavngaP_W zFao7Y@qDp!D%jXwUf ztgYH}%{E4Dx!-(!8fH@tjfPrZqP|!+MBa8&aRn$_-M+VuYaV6zL7*Y%vRZ{+&t5QX zv7w`Kx_MO~3f1pI)~`a9!`5|Clmh@hYAiVxeG>T@SCRW*Uv~hnO%}i?N z;`?F6eOPq7+TT!L<1G8tv!h9;&V5~H?!?TnIqt6db(vk-O6Tn62}%B{g3eS*Uch>D zE!&uy!uLRz8|1tThb1Nom}2==hJ*R6Jot00(r`OsoT8zj-x_mu69wZc#Kyvix-pha zQP>x~k%n##pJ66#vH%D;6i3Tq#qz5Ze7di5^Ovxs+UR;;#VU^ngkgl3b19Bhm! z1_L9?<1!;K)$2TOEbwhKb{Cm`S5^y5(Qc(Wrsn?X^Xh9DOt`r_v{xGy8fQ)X)ZoT- zF_Auaw^pfLs9k#^I|lBTC84jA@4)YO(3_nN!UIf(XNGjWH_dB~YjfH&r(SMqk|a|P z84bEVkEVZ&y6sIzzE*{y2*)uxtqB!%Nk2Y`q%5}FJu!TfTAy5$g?GQ?gO9IwNZm%Y z<5k`B&1LAtC4biLIxdx21;qR&S{13bPgF#OQpx3}Hi&3qMub z*&RHfQw6DG-t$@_xqO$EOKG3OhOlrFWIRa<(u)UPV;wILc`_C}yJEb`yN(OKUt-xK z+`D}C8%J}P;Z5@&P~VU|V`~c+a>k=!KSfr99lLF`Qg2?BR0LZp6>+^+S@@tZ`Xr}e zmjm-jj3LI#t?)zhqpx`-4b!jGFNPmLyVSXQr5Mo{B!ccjR%DDV6T>cjvNu=-y=EHPUbL^Lo--{$Z2?Ljh(z>5S5TYUGrU>47(NS!3 z-??g8ee_g7iqN`l-$k~sO}pGUN|~MqivFGJ%xaXUPW_!SphI3@ow|UOpG((kLYVQF z0dERIh?6ViYdPvxTRVGF#*&Oh_pOuUXIEH;iDZwghQ~9x-hq~YBlK%OXKjzH-8y)# zg!X!CJKwfMjf$_e^BVrXKTbz-EQ`kk{;2M&{ZHX-L&?8hAHEqf&xdpwOssv<267?% zvoC(j0T;d+hfz@lUJ|pS19L$_5A4s1-J0z~9!)FV{%c@QfHcnC`ylo^|M8w{?{A#{ zXKu25i&*ewKybiw5fO}mlin?@%IeiV^xLhKt`AM5iQnfhP-+tqfCQL{56_N1w$F|e zy3vE71D)F`1`XGCM!LGX8X8kce9qN1HG%6B#>r36(L+N*JkR$R#7LCxZqFLVX8LV$ z>7Su3^f=A~FpLbhiTG%ct^RnRV7(o|(nd>*!>H-9Iowcpxf%LK_-eIhOQ)jyC9&W? zFm+2CXD(wGZUbGP6d*LUk&JDgTxwa@jo9vNUDUQ5ai1%oK$zVH=L2kg z{dbo-pHNX}!ou!|iR;&=zT&awy){*T?R7>) z&_=z-j507}_!@e*rgOch>*jWuk+;)K_F#yZ3gScZ240_Rd=%?X%!t7#pC<$?*SH7> zZB#K}t!gEuy_>5SR5G<1Dk@Z}?S$aB*4YBVh7Nc^z|>fLe3qg9PoTNKf7gEafbMl; zK7>s--H=jgGN9q>+u*9VA>Zq9TkHC(_%Vc;B3Z-w-k=kVzkRnFN;^{LUU|DDbegSL zHzdE-#l$pQu~X?$zfYp$E@0F2+cXCY(rEqf_-X!d%aNDHPS8_gILCrVET!Lrf{WyN z)bokNV%(;nl&*bAhXstvXZmm_S}iLtyUq4^vGeT2%@>{6tjblLYrW$nXD5=pY&@dY z$1fp1_@Ch*%qL)dp%EeMZJEu&Z}@GS)|9P8qI!RK`-7<=-*qvNN||0q@Z5%X3apaQ zNNnu&*c!N*nEPh>R(qDZ)yd(I$`6@j+tvNd7e$9&Oa1Qph-^svE{g8c&d!&`rMunk zI5y4eekw?#K}fL6Wl-xlA;kO7f4ww^h>KP@eDtMyHYH@Umbl1a)HmvEyrkc+Ks0&_XY;9fT5muSwf z*WWO5J+4AM|KbB-)#kM^2@nJ7399 z%*4q#%Fo`DGzWTQ!GA;A%P>MTue(y9Pf%X}ZdmDuJg_5(!rpW|gjepZ!sB`1gegFBnSO-C z^p76GE%mEc{hmvA`#)Xx7vN8Gt?SLw=&+pVg9q59&X}afmF49EFFm*yi;2K0u#`PJ zp7bPC5;@;UrZW=P&48wp9V<4`^|=-0Uetw2j4YGU%rY`2Ur#Kh`S~{0%0)1@j^N@;;!B-KU>68kv>pzKpWULxn(x+kZwJ>5K z7O}i;XOlrvT1DP`nb8Vta|QI$z+;m|ij`5tb|OMqpvcopP7;WM-rxwaie+nZ|A4ZI>22KXJK6HoI80V8x5yWuTAZE1 zt_D>GT$ba7ojklaoL1~d0ENQ8x;4S7d5f>V-)w?{6>AQ>oEB65SzHzyh;&%4ftQ=0 z%&aC4IIZC-7Eo>8jfrQjmh^n>5rbD{9e&&ktAVUL;Xx)pK0FD8(VQmrw@z>DF0@!g zVqq9s2mh$Bue4x-mzRBe3^8r(T-hj=Y5q4eQt2}$((Q0qB5;0S8nWU?UcdVUY$_Ex zU8KL2F{QVO{M%kP*+x~9Hy@Jcz0=w|K3-m+=Q7`=v&^S=5acX z^3wjW@V-L!gdvGN_DQa2R|Cxs-+AtU+|$MzM2Jt^a@GcF7~sl`>YMCtu!=WtlTfd~ zOQST$EEWqU*1gW3qWn)6lhon6S}ltnD6c#JDPDxXf7ouR04Sz$Zol=_fk)KMdI$ZqdAh;!fA@wrX=6gl4d$}+Uu~d=DX<@`29pt zBA%W?+Nn(GRZ?c+QzK;m<~pxBHh%uv8a|iR3cD+({lk^6BAvZsW{^@KQobbKbvV{V z+F7o*0o$L7p>pHnp^zM_4f|24d{LmC-CN--R(Q|Mi*WWWL!)K{s#q$F1)N(+rW72+ zW2$6ehx;7-H^vgFQZ-{Pz&{kvzg2277A1|8^@qki?pwRA>)?Cl@J60D`y!o8g@$_` zB|h1ov*&Xj�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 ZLF9^Wyr?AX;RMwa6l7H3B~m6Y{|E8sbOZnZ literal 0 HcmV?d00001 diff --git a/docs/mint.json b/docs/mint.json index fe36ffb2d..182404dc7 100644 --- a/docs/mint.json +++ b/docs/mint.json @@ -122,6 +122,7 @@ "providers/documentation/bash-provider", "providers/documentation/bigquery-provider", "providers/documentation/centreon-provider", + "providers/documentation/checkmk-provider", "providers/documentation/clickhouse-provider", "providers/documentation/cloudwatch-provider", "providers/documentation/console-provider", diff --git a/docs/providers/documentation/checkmk-provider.mdx b/docs/providers/documentation/checkmk-provider.mdx new file mode 100644 index 000000000..71c85ff95 --- /dev/null +++ b/docs/providers/documentation/checkmk-provider.mdx @@ -0,0 +1,89 @@ +--- +title: 'Checkmk' +sidebarTitle: 'Checkmk Provider' +description: 'Checkmk provider allows you to get alerts from Checkmk via webhooks.' +--- + +## Overview + +The Checkmk provider enables seamless integration between Keep and Checkmk. It allows you to get alerts from Checkmk to Keep via webhooks making it easier to manage your infrastructure and applications in one place. + +## Connecting Checkmk to Keep + +To connect Checkmk to Keep, you need to configure it as a webhook from Checkmk. Follow the steps below to set up the integration: + +1. Keep webhook script need to installed on the Checkmk server. + +2. You can download the Keep webhook script using the following command: + +```bash +wget -O webhook-keep.py https://github.com/keephq/keep/blob/main/keep/providers/checkmk_provider/webhook-keep.py?raw=true +``` + +3. Copy the downloaded script to the following path on the Checkmk server: + +If you are using Checkmk Docker container, then copy it to the following path according to your docker volume mapping: + +```bash +cp webhook-keep.py /omd/sites//local/share/check_mk/notifications/webhook-keep.py +cd /omd/sites//local/share/check_mk/notifications +``` + +If you are using Checkmk installed on the server, then copy it to the following path: + +```bash +cp webhook-keep.py ~/local/share/check_mk/notifications/webhook-keep.py +cd ~/local/share/check_mk/notifications +``` + +4. Make the script executable: + +```bash +chmod +x webhook-keep.py +``` + +5. Now go to the Checkmk web interface and navigate to Setup + + + + + +6. Click on Notifications under Events + + + + + +6. Click on Add rule + + + + + +7. In the Notifications method method, select "webhook-keep" as the notification method. + + + + + +8. Configure the Rule properties, Contact selections, and Conditions according to your requirements. + +9. The first parameter is the Webhook URL of Keep which is `https://api.keephq.dev/alerts/event/checkmk`. + +10. The second parameter is the API Key of Keep which you can generate in the [Keep settings](https://platform.keephq.dev/settings?selectedTab=users&userSubTab=api-keys). + +11. Click on Save to save the configuration. + +12. Now you will start receiving alerts from Checkmk to Keep via webhooks when the configured conditions are met. + +## Useful Links + +- [Checkmk](https://checkmk.com/) diff --git a/docs/providers/overview.mdx b/docs/providers/overview.mdx index c6ae298c0..ae455e8cf 100644 --- a/docs/providers/overview.mdx +++ b/docs/providers/overview.mdx @@ -172,6 +172,14 @@ By leveraging Keep Providers, users are able to deeply integrate Keep with the t } > + + } +> + }8AW5m_o!wva7bB3h_yQ%Q?#5m`cIgh-YmS)x*rnUqirkt`Ld zgi2&7Qb?##ct0~k-N*aid%XWW&vhO5b)3K7d4A8&cVA}eo-1mLl_@vJQVu32CT?>x zV_POBwq_U0z6O$B^xv{~vfXiPyxC39C6|%m# zf9H|#-n%m`l;O=k$F^*1Z_Kwfo_?&go@wKkY}@|PCFJr*yH;VQ3;r{|2EU~}UC6ZQ z_r%2DjBaP?StfG+!_^hjg9DFT=Z7uV)zO`v%q0CRSjME>KRrm=+F5SJ7S>W0JmWVM zllftu%W_`lRlQV_bA?2vg9(%UlX}jvt7Y+u)S@JAs?&lfVA}>*UQ$ zr(BlG_Yx;gT>3mSqdgS~#{3UMXILi{YRF6~w?h@3->o3BhADLD`u9>-)An*Ac`5cm z=l0k$r99i&cUY9RcRnVWbVQ(P+Wpa_9!* zlz4EKY{9{T;3Gd;F1j{(|PnaZej?dua$>~ z<73+5VY`GFrU^3?x=puH*fJqF1I`O$elz>}Ye4u33m7Y{oy;(nx=-<}%iQ zU{HgHUkTh{HLn@55_T4%MGmpz*#u{?Y91jbL#r+|<}g)n)~=_r`sL$}~!rWD-A(FnJrrik3HaTd3NSAQ-cy zYRhBwwV`U?9!8$OfEurH;{|ShrLEw}Orb1wWzxGk>bDr&e<3#_V2UnrMd#MhU)8cK zUf~U`eY72@z8tD_oo;A#rLE42&UV)!R_Kjj$IE-{8(5}osSnt|uJ2}W2P_}fU8dhj z#9FnD;;~UxS>Hy{xfsEfl@*!U(&K3gZVfin2edMC?M84%3MkcvGV&rne1c?2S)+cT zpx`L^S+k2359+z2MO+{i-AdgR1=1tO!=27zU3oKjB`jWfY#T)gMsiV7bRL9R$%~Uo z*C1sZq#XsGyMCV%P~PN@CRgYx5?Sq28|@QuG}WXaB8}}liHyf0rnnq$)u$v4(yO*q3t`yg;5G`MISkB~Oqx$ShOX>5p1+l9 z!H47UZIlEQGJWA>(p3nx$godofPxOtbwJTs#1IUwY@?_}g8|FUVAm`SBt+bm(d0)! z5Cc+=ZeTi(mr^px5>Z>Z8Km66w1c$UD8B~8yOt_Cr=n_yDcuNmHH0480I{X5c;ADn zbl~b}aw$A#FsIj}m?i!B5V=wk z6mp=D$Eu8VX7UrOwh|3QQqg&51_~k$kPG_96`k8p@3GHXn@n;yR#o0|p}}qfIljW8 zPw5>H1t7#q2oY^VZMY9k5fIKTnh>sr>sq+ZuIQ|wuc}PeO(qF^e>Ldq;-=_)(+C@? z$)qIUv?VpzH5{MN7H>P(V5bNpx|{YXZ44R5MpT0x2Ly75>^0zUKWkJ_BJ=(8Fk}G) ztDM|MsoDUJoLi|J6_7+35?uy>vN=}T`{#FQX<7~lFZ<{Qy8v`m7ja%i=Z`FqZsU#M z2y29*5HOcwmHXMns!fYG%gudCw0N`J)TiW2dmm`z^zBDDr^Gebl_2L_)Bs@th$uja z(ym?^74$&zrG$eZ9R!-mBrn*$atjDmK!_q!bsln_!i7^IA%5#wUfv9jKtT%Mr|2ww zW{;9OVrgawLYlb!0rG)LV?=n$zCh*~k=zHCVsnu(7 z$qtu}LRE*p4@(ZKVCK-*NG7Q)$GQZo5>}K;!XDhA-Sxq`0P8%g)?mL5>`>waFCec1 zE;iWNBiy@|C6mZvFo6ixWmpkxRoP%wVMFEM{N3%RJpvYFb)19-g!4Rwy@8|~9O}LP z)Ju@63sf5tz(YQoa77t}sU*t2Q_(me;y?=r7=Eq@;DBUWL*5eEVApnOkNpZHpS!iH zvH)DFh)VJ92eWuI*4;tl%;H~Y8_=_61u+73Eh12$x{7!Lyag4A5zoQA5E~}jD24~4 z2?Ty#>lRP9E%0UA$p$+FZ~k!F>NjD|IPz0;4xfQxX)*T)4S^POBdE+|RFp~-Q-Uf8 zo&w8u8-;logip6nIf7AYlnp?Lf~ow7RCBX-axUfRV#JfP`Ke zo(FMn-Uwzbn5eNHR^bGXmB5w-wg#~Ifi2ecaCN&2j8tiWxdCN{H4d>zgq_8{JRkHG z23s%98Zxb}Ekb3Gh1~Pu>nK2k!)AszwY6vSic08b(yBf*mkk;a4A6hqDIz0}S{I-2kiy)?W?N3S%qniWrIrV(qfqM1hUV|AUvFgA@$CacwuM|c6-El>@Y zy6{F56s)lg!@r(DytE;)Iba%hG}DdH=YEdxg_9Cx`fTb~g)jI(?lfDjO$tDaRUlqF zyB;{}ht@hSN)FQ8t1P2Fg&Ok{v55TcrqAl*r2E z(S)67q+$NSKef~S;GSQ&D+J?r?ZpYS46_ai5jGNVmKWV}gqTZzQtVkuP=Bt&L|y2lBEYIdCsj*X($B$jEpMyVAhB`g?lWON?xGVW@0AE0Re}IV*^LG>!`SHs8}!o=86Ex1DkJbw|QmkLx1b$>RE z*8FW~_nS_N7P;<^o6L~4dhZPbRd+Pqn;**`aBr}&IlZUt8@2iTGD^kFvSy;##^CSE z-!+2iWrlL?46l>^9YwV6=E?TP zQ!)k^WHoxqrMLU)#JACjcSEYhlAe#J>MMM2W)Ex^P})MZ5X|(z22pJL3S!4eJ?>j2 zUsNB1wN79`%L#b8{(ceB;vKR zX~VXwCoitRX@c^fEj7}*7kRh<>lmkTD#^PKw67IyL3^!4!{$l&Pq~<@Ngp@eceVd< z4g z?)A}RHRfW!BXkiCmh#$|eBE`9TMG?j{qmWWvVJU^u5NQW9&^@M>BA>WXR$H$N zUfjIv*cH5WP|CHI2^3B&z0Iw4$cF3P#y+JY4E1O30Oz*wEWQCTPUdC>J&E z6U8u@Okt9VzBwYAj^wc6${S5S8U5N8X@(CXCobn)GVCNFf>VZzoOAPnuU)bg->PSR z?NU_@8J4~Ne&*ZA7uED#4MNqE=5c!@LM^?95@6~}B+);^bsZ4t`O)W{J;9eP*7Zdb z%AIpARn6p_8s2&1`Zm>kOyCMrw{L|$+Pe9QojV>vKTUskASL^9Y&79^^%m=!LUm3a?62?E zuQa$jf4uF?@6+984efhKPwKCUiF#+=l{VFVx}^G6RJMeu_h$FjEln>qA|JZ(Z(66` zeF@5ExUSEI=JBy5Jn*AiGfn!}du0j|bw$7IBn$88QyO=-=N24#l&AG&XTI&ovr8Q->Z?4oGxxhHv| zH78>rlZC;Q(okgKkzWfgM9Wd@n>c+HcYUqc zW&bp$Y5$4?C->NQ#@jaAiF)6G(9J*Z%!uD@u(K#!yri*}oV0f2s6FZ7ih2_V4jOts z%>sh$XP$PS4^JSLy@D^z)w}tiz}2xm_Nz;2gleKbNlCkC!Fb92@wFc#`sPudKcQ(t zY>6~D*xIUo)o{+YX(kK49>x1sLz?`D0`D)@h|_hj;8;x@XHHLWf6V=<(a8Kt4cX~{ z&DJm73K#oxuU;qbu{Vvrw7`Gmk7B!X14#n5T!+_3fXnkL-7}Y%hYX@6Zq%E+HwNmf zM=?4)eCyiJq@6_~Yr}Jg`8VP%&QBs*yWeAMWM3F$eV;@lm8Rzd-tzJG`Z+!16sKm^ zTrl_p;_$B{$b$3C#yzQPCYHx>$tS6_z9KtwlC2#}<#74ba2)Uen>9_KBifwXiNngMQ zv+bR`PgrlGT5MPEzOc_I?v~z4;&%Gm4p-Wn!t9&Se!PA75Sm^vntV&*$m5mI&&4E- zTdC$}7OZ$`@_y7w=iHXpJ=a?CUFFR$r#f%jN1pSz`Q>ZgZgfq*>Y3omZ4$w`M%yvO z=?z@XzwW8M^AxvM!{lgZ<_E}fA-1F(#UnqIQZYUeRp|csNG(y!bt+Uf-_ClQtBl8{ z44V~$wa(KUH*Hq$K1LHPLslC$ewP9pC-f)nlkuQ+C-dyB%}YeR9|nETG~9a5I5&f& z-mOTMHr3)w_i=wL=If8KzK^)piAG17-s=-)Qn;I~ue2{v;Qf0(C^1RP)WQb`u9b@YT=0yFt|Z&v>gd zW}3EiW49n{i5JvRe~)ACR@rw;hgZKm8(J1<>2{be{kHD(qWyo+r0>f$x2MKxPLH6T z{!Zxs`qV^hNn8Bh-F)ds+RyYX6ZQFOk$qP|)Vu5{Q7kB--@V>MO!AI&?FCuw^@WRT z<=yMwAA$b9;2GW}r^6_jLOi zV>kIG|IxFnIw=oW$lOtldK3!Bng_b2tYprpMs@ec-hyCin0=RB)Y}0<1;zKfKQa+3 zCQH`}fhl=$Z7i71i)x$%DU+y=vUT=d9Z_$wDxz3kV!!gx=BV|iRDx05HFMt!6Tf7i zYc^Kj{XLH}u|NOo!&uEYI4#25_s#eLnYe0Q$hng*-L?IU%;T7}Wibi;$_*xB1i;Hh zH6jBSqpEF6=+Cb+5qpG9si?+4Y&H?a2G92^*P4haU~_3y;~vV}GcuSL-Yje08566? z*U=uocR62ra@!f1_B?D$H}9s>7On%!`2PG#6R}f(na7t-Z9lUYh3%Pj_8MJLZ_7tSvAc==mW?K2uV9h)vf4-Q zF0MtwtFDV`d`77_v*!9JdfIVw-%sPej8arZadT7ln%i!o-p~5exV7Y#H>W1WYF;1j z&Go-7+no9;kjp_M*%O@scPr=jy zOz$kNH3X?(RHNkw_s4gHM13rcv)Ay7dgp)s7_)of-S~dX9;#Kwoh(o14&xN)#^>xD zArcelvxLCGm#+2a-s0K^xX&8Z$c5`AL83lq<(oyCOvDE7O4kPPrGLaOD>mhtMV^_6 zy#rT!zVtiTTrBFtwY*sbVVH(6)aOh0mdJc8^6+@Tu}uVls795}BaiRM;Nr4ok=|wy z1>&kOU%D!;-dXZlRyO^TUC(L?x;BE|hC# z-!H>6jmqZ2mu|1#-Q|qU<;_w1WO%IF;$`BE<>O;Df1yrwoB39?ojJt`gpJw!z2778 zRoxz=I4Qn#;U-+u?ZkmWHb1f@xF4Zgo7g`;U^I+J^5N0JJ}X1nr z_E7}nq9;T#yYu}HJ@BwGt_gw`*B&{&zce7%JTNiw{JB`w6r3p^WtCeiU+hyiGV*oE zcuAC1=CFFV6ms=}nQtIevE)_n?U!mEaFOAmO@8Udxu}K0C}p>0wPW2MKN42&Js{hB zaIXvx5jB}V%8FCeTP1;8YnPet(qM?cx4f)$`*)G3#$42ZQ{Ua|XwPoAC;&HqSB+|{ z#q(OHBX!>wM>U#C40k*uNbqjxAO~a`e`Zndc2QIBr9C?0(GZX4j6dt*(E^W=#-9;} zDl4J0Y;);j6R~H{h+-Gbd{;rwM3_e_s!>GLn;eD@4u1@?f8@&Z_LEPp_xH3i_qC$? zc_S+QXMeu*PTgrQrAR;cjP|1Q`;qvYQIyr0g#JIM^~$I>Gs~N)tAQm8D5LBj8hBL3 zBP6&Ot7(6kTkC|m?=&J*$jzugC#sP~$|mY#=6fPgKT^CcUdcM!?kA3qc@L|Wt4BGd z#cHzBk*0WQsg(C?G<+g<(dZ(4Z91a?JgLT zP}*UxMW4b{MW_0Z^cvoS?H z?o{uMj_+TGFlcbEYmsW+1k={E$LHy1FF`zjNtkhGW~^o<(SemO#9zHTEVM2D-DTs> z%dwhW&iGh^)>#a_HNPJ+^4QB4viICi57)|@_~WGEv!aRpzbE(L?C0o?sZS*_IN3>}`{Q|;cchD@qbQQ1-uf(}K4_;85o2o$ zrHe(PDDbvE>=Jaoe>Ziyd&dIbfbkT{;wZ}bT1k(6`jVnPqUZa62i#xGHuihJk;f9g zkR@QKq)QzL;pGeA#~=`XxZ};4KUs5s7l8fbO0%(*ZD&|K_857v@r589!*;jFzY8;V zhSFV3>b)1_o9*17!x`?<8uPK5_A@LzdyPDf@P!=o1TBWY-KoaTDWE;T>wK$o=MuT* z*74xaP7B0_-nD+wXmvFo+YWcjuo%MK6$KXAtH0#NYDz_Om%_Kpfo9n8E`E2su`{Zh z)FtjxR`W4@Tw&pBi{Bk*>>P{DC@?k~!<@wO5}Pr`&KM%3lDSKh&Bh|IS*WXHSMg(& zaW<(3on0!EyVTWeY`f0eGc3davUKsnD9S=n?@E=`C-<=Pg|K^ezHbN%KLH?USlN>( zDxz`$OwGp7U|Hl`j64GQLXJT%t+x2IbmL4o*=4DE?|_!u1IvE6#Dp)z1efYD z9;BT!&O8SO^HBcx%QU+osO?X2m$sXY)kCif1S5}Cd?AV;z6N2Uj5DJ^tE%2Bx2*Xy z0i^NVr3cN%cIqIpS$6C*@(|(+;cEi*_K>^M8mv)ztWf)9hI`#+{p_Z$dKPW+{q;N5 zGK?jMf5)sBA(!EkLyq}aGvY0XEUj_LSP~tU%q{A(*L>^>Hh15V)<`gxM297di2AUY zk9lKLv`|{(tg&PbHc@eM%*G6``3{>zW6AEpyxk(?JGmz{Cceu~F5IA-#S#QT!i<|} zWudLJoV(PWPZwn&ix|1OXlSU%d~6@ef~)@GPRfM`6}fKSvK%qtvtS-B~?gd{G_})C*OQ3qKg8yBk?wnn|T%4}?fdN#r9mAyYf1 zNK&0Whl@6Nv-0T@jnCOmJ@)ATNNrsml`+&x8uqW5u0v53=F_zp=YN>lTI9*rM8--or%_YX{K zWm(rux1}ZatI7r@eUU$=|XI}^#>U7fW+<@rc3v49kCZbVx?)rxd&i$;JUU2NMr6wgZR-YvT>Z4+R z+RltQq^A!<%hrnU>2_Runk971Z_a?LhKACQN;ki9q%7(jf3CclUP^9dwiQj4{0dvu zY#J~eb}Pa$bq+--==jVQh%@ZOSwzMs+gb4m){OWK<7Hie2(L~shte!-e?`LJU>US6!>d&Km|NAo%q2s zVUDK(X*i^CLKN2j5tA)+O!u!wpZ5$5ibQ1;^c8|@>>Nzq@#3wYl8mieeH~v{tumS8 zT2y97=X$tI?GWMOvbk`xT`Kuv`Q*aqY};0THKZ5XYm-rqb+zegx$x>l%#TlBl#S*v z{DQXuWB=8`Qk}{D_>?^xvWj}&pl9$nIX9s6cb`3- zx1TTM^oLDXg^vA=?^Rj18B&Lye_hpRJ;#w+ltjrus1}r1OzyufKgaRwP(gtH#eNwF zzx3BtR#tP=^+o;-mlHt!aErvN&vJ9ruP<$KZh~D~oo;Cqk@^2RbH5`)%fZzbcC{Th zpG~Osq>PuXYY;!&cAHjyy*Fo*^pNdb8=e=YEqpmo@f}KVkEY(yMyj3hL8;shieaBe}ueECp}xQc^LaFmii+`fsK6 zu2$w_zNQZ9A#3pcz-$<*wK5cqEA=`=`25$I4h1VibY+@fiTn0Rj6Z*7JZG2GGBJ%_ z$Vh0lTKN^(igpSwr`H`}=+8pRs2#(!Gs`qK&4O+&Qzt#}{OdNpVj9nd199bH;3+j{ zTrrPXp24iT*R2iaSc>QbYyIhtKII$fYy_MCMPVkH&Ia?Zm>WXJFi$XwQsnxpW8-Iy zt(SOMe33ksqL)OEd;z`u9#-9~ zO=F9z;%-nEGm@o_PD8p1160g|BJ}4Zu z$j;>~&zRi5fMM{2THlf!gwVn;-$!=HlSK@7j>N|;`9mumXDC;l$DeaCOwt$EAE3&x z>#vwwLh6|ej_a@VY-EHoU%{IL@lR%^zyLk z`xyZ)h5Oe?&CI|B~FupPp0%7 zCzem7WH5X?u_3XiTy6u+&@V}MD5>-5#D!Dm#a89eJ*d&8m>0p#NYymSy6;1Y+Vl{X zS@okQd6&IrK-4{*`V`2}tcLO%vQh-m65K;T@4x4|lcYFt(jOdzKLx(V$T9kdk_evAv_#v&4o$ZC+5e ztIde9Z4&8OW-dXi$NUcCGb1S{Wa%z$|NNC(<37DSYBbe^ZsiOTX6*NNZFXTe+2i_C zlF-BohA(PMMLh%P@$>)QKH`gz&=~Vg+#Cj`3=1rX^eC&JW6FPsaE=kjgPEltKlLYR z^?76fWkw@pO);ZzwphOpSi=ZqxwJ6n|GjW$NG_OGmMy(nnsf)#N*O&VKlrVjiuIg4 zGaDxNdoZF=Df9lv>k9OWwOM`Mj4fvnCta_dKl5WXw$EJ%?Y8NBHcn4x*Oo-}50(tO z)ysAHA0m(#l_Eys-bV?!6SKTKKdVkzFig>_D(XpL6llwfGnXl;gAApkbKOe@Q07WP zbJN_J8*fCEGe(+x|0hp^(*MkJ%s!{`X!}e`?U)kdf{&?ti3n;y$#L3+RW_XO7!!oh zdY7IKYexR14UATpu5@3`P+~BcTf=isi5ZmA5QYxdUak9(|5pdyLxhJ64u+A3OD_5m zw`Aw0b=@ldp7Mc_Zx^(7^*ryO=Qr>}4LdE@Fz|a_Vm18e8SYWY{wsc0+YW}xPfC}1 z%=RRxd=%B~Frz_mirr#=hJ?nT0u}UfJg+m-U)k#hG3Zy}dsn}QRvM4C59bKo52t5= zW$4u>L5_WlV1MQCdq1jNum!!s%Wc@wv(jb`>(Y&gsk8Je&q6Yu?7q$j)mMF<*M%nd z=~AhUdoT4!X5`sE{udUV&mtMt=&oM-A)8*1*b64NzpgsLsKlRiH&x$mnbZ2`_mpWp zy4I=Vva!Xsb6WRj3r#S_A+^t1OFc{H99@yNtIeNb)uh@3B`u78mbh7eb;z0}j8r=v zd7!L@KKdZl(%}DDzUz&uZ?`KPZRpVIfc3N`UNtf3-Q^FI2{Oir#LboK#-3khl$Cm( z7he9NI<#^qSMsHJE9Y-EhM-@5oh|m5bAM=g?e9Gozx}mE!+rNT9ZD`yQac$ubllv^ zt}*)k8pmk}HN{9E%cH);-KC7;+CKk%H|hw!TBMBvT8+;Gctz=558P{QIDhjpxOcam zEk5y=`}!hsC?k1Ate$&4y+|Laki2OFY1B>Gk>~quEzkTT~d;fz! zwKttOmFSI!U+hx&vA?Nqs_;RBQ39|}aGDTTjLPshnJ1Cs3%;~Z7T{~ro;Mdp8+P>7 z`ZDzDdU5v7_BqpOZtIx+RFjH*vh!bk%Wf5s8DaP6iik_`T-bTtE50PdXr|!n%j-N* zcA)~p<@M4D8;dtp7PFeky&EjZ%%7sA$)~rGH|_ta;IR9`oaq*gA0jNL4N|TrjS>&N zn~S^+mZiJw=R}o#TQui1BrG_P@S24$Ob` z4@Te}qiMs^9~)l(lmF4sTzQe&b^f2_9xKiHH}_WaKa>OO{<=|2@Sjrr`G#|LuG`Y3 z>c~iY&9zsCIP_+totohvYI$+i@0+h`Gx}WWs?dy%!+(v#pKCdXV|Lg7pMR^8zR zb6@J#BaZ)UES3B>Td&9d4@~!!5tawWl7y3adX4u(FrTAft3A3BwS_bnCQZeM|G~%E z70lWGYS7zJBlS6_hz%9}nge=s;UAEeea&2)s8kXE#gEpTkmfnJgeH;RjX!4;midvN z%>4c)tM{?Ie;E*d>u;FYsQ=GC!HKIr6vO;chhOaO{}T>5uZQMLQTz6$(2hA%*RF7! ztFXkkpZ~eQ^u=6ZJXcK1)Y**T*-}2I^4a_5|Mop5MqHZ?A7w#~weO57+}Oz|)yOfA zaZEBWWyd~#m2mNYzCS8@jdT$M&JXTK0fQU@Y}c>8sM?MK{O<|pxLuDZN3%(avR_O=+-Mj%1;_w7r#GywpjmPaOfRF{&2wRK5Nv%ssHlr$KrIgR@BBF zVu|1Pll}_%oGppsWDb>lte&L(kFSRVy_-q+3gEWZ3jTnM(to-RH!B>~g_tciBA%cA zN$+rdY+MLjA5^P-DEl8@8|OZwnK!xCwWN0E@4uz-X!y%kQN+Nerl$dk|0?yTXVn*V zXA1an;<{g{A?e(}Tv?#L%CmmsA=mtBrJgE(%K!K~H;E!)0Qo}?JV_({iw=3;1~J6a zJC{RG(uV$JS_MX&MUXzGRAl&g!M{@a=N#Ku4iY4Yt1;kc%iqfTsRA&jfN}MGlJ-A| zJhNpoPzo?bJ?j;CI-d!{k8z&VM1+GjA#Y2J?_v z`&R6q!C+k-02eP_I(+aXZ#$!v{7JQ$T&fQ-Jcv)yvSxi@l9_^-UJT$V;sNIBIZuy- zH!JWXdEa@TeezqoWR{pHvE&-b2DG|t2g~lvu^YYDpTv%@7mjF~_i*2yjR|kJjRS{i z%DvmU)YD})o6l-1@JhUpfo{KfUIp~bY4O?s%<$p*UBD$dl`peqCW`T2BQ=9pIoqK! z)j3|>No9fh=itC^x?A{#ZD;!f)y;U|Ff*9_PF?Cb7sXd4&j+Qeu>;|o+aYG^EJ8xC zzHdV>(oFGeOF;YFW{_SIMGj$Y@vJ4Fezy209M^Voc#J>!aEyI)N&nDnZpcdTq^lhV zsAA5#4?Q6tiWmdVy__p!>k^Hv?c7S9JRO`ZMpsW=*(!Gtn+MB?o8}7s)uVqm#k!^mJoL=;uc{cNwf0gY|5<$A>t#{{NIHy?3(X25)705JJ z#=T@bWfi@wtJYSsOu9g(f#YfVma}0nUyM0jtp`!iV(L+LW|qCyG}nrd^e|W}q*rd_ z*q=7WMAHElC^a|4{*oNr&Tx43hUGVODQBhf)26&d*6%M z#MJVc^lPw0Fz4y{ywaR&32|v5*GT*{b=Jusr?9>ok6IPh z2tv2Xy61g2<|N+tHJQ?go&wy&<2u)8T^W}$X~)}-FXd>+zC1T)6XKnl)4(9U+N0@l zg=Mym_kB8F0c2?ga{t6^B`o#s@@sfTGq9e|(FaAd^~fX5{~9R~jTX39J%VSO&+h9} zH5*ft=}KSs+d6CF_bOktT|c4nBAAYM%;kyQxd$&>@rS82!|!jh`#C$aB%dnSy5ECg z%(pFb#_YR1n3S5v@Q1(aZ1_8@>BD^d=V99!hL!yt=MGeRNqRfeGU(f%{5Q{T`<^R# z*(!)g14mZt4#`6LM;eRa(}PJn(RSeL3oklm<2U5T?J>W_bTM`tyUhW_7PF1vZw=4@ z1f3twI^^2k62FFghD!(g=S)1&zGLzM>N32v@@mek)h@~J&V7czjR3nBC(X5*gK3Aa zkzyDw+O=!8=v_OKubZ`+;m^E-bIqN2<&DB!%qsxBoqKH-R4?=3H4?sxr@7+f(%CxJ zcQ=aiBaE_)A;7?^*)XB*%Yv*7XC9u+2g0j5@A0|63qbpmOFc2SYot5|+AY0;*?>8B zeP`~oLWbb^ymNs+wG%qhvJ5(YJvGbXxMzZ-P8JC>1p-DXs4UcT7ro^7l^a0#wG83E zmCr?&<`WBNJ9&C+)Rb?Xt)UmM|7u~G{KDW@Hhgg|^n;1X6c2O_Ad8l4nI(3U2_|jb zkEsm#_wLd0SzrB8t<-j%kfH{4%M!L9Z z)ZAHjO@|(mqjM+|Q9K3G)pj%7 zbKyhqOHre2BetlF#sEX5C?0XyK;cB|H|Qi9pS&G_}^Uc-)QvTbok$Z{Qvti0yXqo2RnXB?k>?r=biA^so@E|;?M_= z0&bWo2sC`WyfXeZTk--W`Q;vV8zJ$f_G3PA^2R%T54bcx z)ynvf=sy$u7X|+%!vD3kAh^QO-MZ=6?|yoj6!JfJc(wbT!S%WPRm$4;N`F2NN@mNn zdQp{al$V>gZo&9II}IzjwRieo4CM}v<#gyxR*5g&>D$&d6gZ@-+wrt~FZ*p}ZTHbH z+Ebbvf|VaF5E56P9MYZ=E?)J5z#qetru)EZL*-pg-?k^&)yIAoyt=Dfq92JXU%&Ti z>%K~El4)zquGZ7Qff=Q0m5}%`KH}zORF2>FzHQ&8U86VZwpQnzT8LM(k+Hpfs#a1s z+v#iO-D7_Lo2;|+sg03h{!KYU0|N!RcNT~!Yw!D>(Xtr_Q5z$5KHPn4IV$+l-nUMc z>)jJp?cO{6@eM&cM9nCM*K0i~KTdA@aCfOJm7}zvA|&X0(>}94-Mo3l8^pEi#*|_{ zDstL(lv-67j|$pOS=mjND)f$Kw5&F#7~U!-T@3KbVZB-AHon!aQ+!?B*pOg+;pX^F z!V^Xbr1-&{8NC1vRT??(uL_o{lV78Dc19Si8s0e-)2q}w+3i+xg2Y^k+q@@Eah9&q zQT+Win$vd5H+?#W)7Q+8`fbYt-uS0MJ7%u9vfkX2sr>dV?JXoR z+l_K&O8iL_wbgw-DVw%>T&i_mMY;FN1*M;Yn{M?gUDf`?sk^~3!hs(`79WrQQX<(= zB7VvtvD|HYC9{wC+tj46lMeiN+sEf~#F}C<)A&I4)V8~)3CT)Q+iQL=4IwQky$&&8 zN5#ovii&ct_TRvMb3ewH_AdRco42Y*YWp|O{p)0tz&Z~V-k%;2$2 zpZeJ;4pcd=!Q!>?d8dZ^PZOkD7tv82LiQ=(ZRgDJ&X%iT+kSRjm5Cro+kM7s>}dzb z@fCkqBOORnPPv;Xh6O`TkNP)h*0l@-?QpznP#`fwEm%9RK9H;00wLu@YSVefTsld; z^K7+*U4(=94A%}XW*@)tjP2$MbuHAKTLo=Wb{iPFOjV@US9D9;$rJ25D-CX`CNz1x zm9k@-N%*NGQn&8e;Z&N0^$ZCerwl(aTjv`Vu9-0)sn5IlASk+zdAmZL-`lNu(ed$l zwJ#sD>Mf9JRe&kpEU0Ta$UVyE++t8L8foX4Wl#{;+2$3V`AWa=ZDo>Vso|~0&RYTD zrcP3=jvdyAbk1;;YFkmB)Y)&NgXGy&>13*)eVd38C zc9P7zn4ZmX8ZxXF3PtMrs7j(cd;U^uo$~y0**@<$Fx9Ni6t&W*G ziRhWd`i0+`>iRbr+)7O#snVjLr^)M2A*;{k3&FA9C0XiZNDH1*PE90w+lOmUo*!Z~(oVKws>v(a(=Dl(J6`C#1( zD#}cPLm6&Puk>)@rCHy~hZ8Z2(IQxcDY7(l=f2GkrSNmFs9NeX- zZ!>q}-cobQggIoCOCWVTIELR2PU=0}1i~}tgTJK%Z{DgGY$GFIRGsc*gGa2!9`d(Mo)V+sg=S?5Suuog`q(R#ZR)Q{TYF8dNlf1s0#J=TFY ze%h7svd+{rP=;X*!|HE0h?tAtG@5)D zlFB9o_ZhD)cs0)lNHp_tC6F!;H^3-P2_#WoWSmG@Gl`%bSyyjo0-TZ3_4RfOmf?XN zE0TR=UcKED+FHDRNk13OCfxOQ#O2tK#43mNTo4YB!uq4hw9tB*80?Bfs(dNyoEoX3 zOkP!Q_X&9U=A+3}9CIcFyISCQ4~~&EWWIX4{l~^TYDLHk>+R$qiL$|HGAjsQ0f)PI zL&&9hYw#qFE01NJcSfryt0>glU4TTE@S-4exqCj?bvtjttMF8K5!QBDnn21&?x&pU zRRRuwd@w6E;mMI0Tvn;K`-MZ{mX5o;M}H+^N4DNB0P!Xamjom9g&U?~aFT)(9?;Sl zomWX(U)S-tp$`6ZbGC*P;v^kS#>@* zLKPA@Lm~p!OsrS1N@8usItc^YZ*HAj#<^VrwIfr zxDqu!CB9cl8LpB0(aS8pqt9GD1wPHU6c*YqP36erCq^i|FVSZMeLw=KQiEVGoYAW^ zvKlKgeuNDx3d6_}tiTyT)jMl4Do6`4F39*R39Av-1o?KCg}A@Giu__jy`2;aiZ%jZ zetC&iMvp4pY>g}?gClC7eL)jPL{{Yr^M|wG)$M2Lr2pK!hQ;v9_SVWAlGNUlB zXRkJ7lXVWC-&FAGqeB8opNC+tnb@lok9fDj&8vLGh^?S&KTWs-iM{3%>~Hvir5GH| z0gh}qUj~Wp;JhlG)3?j3icE{OEQAIv)K(x6B1;iV0wCNApqA5wk4(70P8(NV@k+W@ zir@(xy7=wgSdxCLK_-Tv3WIwHn zxoB3AN08(yvIP48*jpIo=MU{F%!pWHU4R6E=whb{J3matSg&zeP({uMVhWHrAAWzl zR0XX9eUjsuiSPyVN#-?tL|3g3Bg6E+K;SqWcYg|cXq zuILbzYNrXQ2naITbzVxv$*}+>OAwk95@)oL0GR6 z;f(J7!TteEuxL5grV3f-dAk-?zr2~b>cu>C$(PbN=RQpspaH2@ zk;i(6nw|HB-Np_PJFBY5z8~xP4>KXgeDpxdRYksx55Q7LN%_ekW^t)=cz{{!mUBH7 z0rn_+wXGF?Id)MMIVmBSRTD#&E4Jfgxi+DrgyrBE4$p#;Y*6xsG}qJfIR3J*+D912 zwpC;?l+Ud9Me^-+kl1Sh!QKb9yS!2Of^hhG2_AyIOSrmlD;Hr ziyJRCJQh|LqDksodpPFaMf=wGJWXh)aWtwTuZ2MUNJDM_Ou`n(R{hS?1a^quk8E9{ zTdL0{94_Dfi)Q5&rwP={Sk16L#zYZzXJPdy;w$Vs)?yTtFlqMcQJRg&pg4#11=iX; zP(EU>Mh>X35!(77yQQJ(dSq1breu(eWf;nNJgPk*s9myV{l|o|rnB1{V?25nz?5T=EDo@@2QyfggadKdyK3Vy2HOIPL&CRSO*PoXkoQFgv;7g zMczE*EVh?vQkF}UCIhDYQ?whGRos!+Oz4y4GX@E=4E#3ei{t%w ze1v!4UaGPv(J!2*a-W3L`nJ|XAhA49s*;b3M|UZ4DM6(&Ar5>qz^qb)@tJn)8BRY| zO3|esD_-ZJ9h2h^R+FtW>{(nCjuHvWo#)v@5qp#q<%5MPU;Xire<+)AF>N{h;+N|S ztEYX#d6=prY4lx^MvT?Dhe#Nfn386$^gKmJ>RQdhSj(H~5{%rr!dPz-80$4@`s!sq zL$HTxXZm$$444dfr}XMk516>MxoINmr%6=PGe)Jg2eP>x{X*N9`)PEewB;ny zMg02OfMy&fK8MWTEe~OfUd=Uh$m3R=bfjBb=^Wz={+QFkLDTREoj%T1m{{%&m1-5} zHmkg&SVjH`PF^L|bkY$gnrNI>q5Ffrs{MPWvvmV3-%)OUG06{ivZSJ7eNEg z+WnEv*!P>3Px>m@r2L^69bmBo9iURmNw30+cELMXh<fDfR56Oi3pB4h89Kg&FXV`9>?_0z;RR{}1((%zOX< literal 0 HcmV?d00001 diff --git a/keep/providers/checkmk_provider/README.md b/keep/providers/checkmk_provider/README.md new file mode 100644 index 000000000..f9f8ff341 --- /dev/null +++ b/keep/providers/checkmk_provider/README.md @@ -0,0 +1,29 @@ +## Checkmk Setup using Docker + +1. Pull the check-mk-cloud image + +```bash +docker pull checkmk/check-mk-cloud:2.3.0p19 +``` + +2. Start the container + +```bash +docker container run -dit \ + -p 8080:5000 \ + -p 8000:8000 \ + --tmpfs /opt/omd/sites/cmk/tmp:uid=1000,gid=1000 \ + -v monitoring:/omd/sites \ + --name monitoring \ + -v /etc/localtime:/etc/localtime:ro \ + --restart always \ + checkmk/check-mk-cloud:2.3.0p19 +``` + +3. Access the Checkmk web interface at `http://localhost:8080/` + +4. You can view your login credentials by running the following command + +```bash +docker container logs monitoring +``` diff --git a/keep/providers/checkmk_provider/__init__.py b/keep/providers/checkmk_provider/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/keep/providers/checkmk_provider/alerts_mock.py b/keep/providers/checkmk_provider/alerts_mock.py new file mode 100644 index 000000000..89a74e5b8 --- /dev/null +++ b/keep/providers/checkmk_provider/alerts_mock.py @@ -0,0 +1,23 @@ +ALERTS = { + "id": "18", + "summary": "CheckMK server1 - DOWN -> UP", + "host": "server1", + "alias": "server1", + "address": "10.10.0.185", + "event": "DOWN -> UP", + "output": "Packet received via smart PING", + "long_output": "", + "status": "UP", + "severity": "OK", + "url": "/check_mk/index.py?start_url=view.py?view_name%3Dhoststatus%26host%3Dserver1%26site%3Dcmk", + "check_command": "check-mk-host-smart", + "site": "cmk", + "what": "HOST", + "notification_type": "RECOVERY", + "contact_name": "agent_registration", + "contact_email": "", + "contact_pager": "", + "date": "2024-10-26", + "long_date_time": "Sat Oct 26 23:20:39 UTC 2024", + "short_date_time": "2024-10-26 23:20:39" +} diff --git a/keep/providers/checkmk_provider/checkmk_provider.py b/keep/providers/checkmk_provider/checkmk_provider.py new file mode 100644 index 000000000..c9aa19be9 --- /dev/null +++ b/keep/providers/checkmk_provider/checkmk_provider.py @@ -0,0 +1,109 @@ +""" +Checkmk is a monitoring tool for Infrastructure and Application Monitoring. +""" + +from keep.api.models.alert import AlertDto, AlertStatus, AlertSeverity +from keep.contextmanager.contextmanager import ContextManager +from keep.providers.base.base_provider import BaseProvider +from keep.providers.models.provider_config import ProviderConfig + +class CheckmkProvider(BaseProvider): + """Get alerts from Checkmk into Keep""" + + webhook_description = "" + webhook_template = "" + webhook_markdown = """ + 💡 For more details on how to configure Checkmk to send alerts to Keep, see the [Keep documentation](https://docs.keephq.dev/providers/documentation/checkmk-provider). + 1. Checkmk supports custom notification scripts. + 2. Install Keep webhook script following the [Keep documentation](https://docs.keephq.dev/providers/documentation/checkmk-provider). + 3. In Checkmk WebUI, go to Setup. + 4. Click on Add rule. + 5. In the Notifications method section, select Webhook - KeepHQ and choose "Call with the following parameters:". + 6. Configure the Rule properties, Contact selections, and Conditions according to your requirements. + 7. The first parameter is the Webhook URL of Keep which is {keep_webhook_api_url}. + 8. The second parameter is the API Key of Keep which is {api_key}. + 9. Click on Save. + 10. Now Checkmk will be able to send alerts to Keep. + """ + + SEVERITIES_MAP = { + "OK": AlertSeverity.INFO, + "WARN": AlertSeverity.WARNING, + "CRIT": AlertSeverity.CRITICAL, + "UNKNOWN": AlertSeverity.INFO, + } + + STATUS_MAP = { + "UP": AlertStatus.RESOLVED, + "DOWN": AlertStatus.FIRING, + "UNREACH": AlertStatus.FIRING + } + + PROVIDER_DISPLAY_NAME = "Checkmk" + PROVIDER_TAGS = ["alert"] + + FINGERPRINT_FIELDS = ["id"] + + def __init__( + self, context_manager: ContextManager, provider_id: str, config: ProviderConfig + ): + super().__init__(context_manager, provider_id, config) + + def validate_config(): + """ + No validation required for Checkmk provider. + """ + pass + + @staticmethod + def _format_alert(event: dict, provider_instance: BaseProvider = None) -> AlertDto | list[AlertDto]: + """ + Service alerts and Host alerts have different fields, so we are mapping the fields based on the event type. + """ + def _check_values(value): + if value not in event or event.get(value) == '': + return None + return event.get(value) + + """ + Service alerts don't have a status field, so we are mapping the status based on the severity. + """ + def _set_severity(status): + if status == "UP": + return AlertSeverity.INFO + elif status == "DOWN": + return AlertSeverity.CRITICAL + elif status == "UNREACH": + return AlertSeverity.CRITICAL + + alert = AlertDto( + id=_check_values("id"), + name=_check_values("check_command"), + description=_check_values("summary"), + severity=CheckmkProvider.SEVERITIES_MAP.get(event.get("severity"), _set_severity(event.get("status"))), + status=CheckmkProvider.STATUS_MAP.get(event.get("status"), AlertStatus.FIRING), + host=_check_values("host"), + alias=_check_values("alias"), + address=_check_values("address"), + service_name=_check_values("service"), + source=["checkmk"], + current_event=_check_values("event"), + output=_check_values("output"), + long_output=_check_values("long_output"), + path_url=_check_values("url"), + perf_data=_check_values("perf_data"), + site=_check_values("site"), + what=_check_values("what"), + notification_type=_check_values("notification_type"), + contact_name=_check_values("contact_name"), + contact_email=_check_values("contact_email"), + contact_pager=_check_values("contact_pager"), + date=_check_values("date"), + lastReceived=_check_values("short_date_time"), + long_date=_check_values("long_date_time"), + ) + + return alert + +if __name__ == "__main__": + pass diff --git a/keep/providers/checkmk_provider/webhook-keep.py b/keep/providers/checkmk_provider/webhook-keep.py new file mode 100644 index 000000000..be0ea2f8c --- /dev/null +++ b/keep/providers/checkmk_provider/webhook-keep.py @@ -0,0 +1,177 @@ +#!/usr/bin/env python3 +# webhook-keep + +""" +This script needs to be copied to the Checkmk server to send notifications to keep. +For more details on how to configure Checkmk to send alerts to Keep, see https://docs.keephq.dev/providers/documentation/checkmk-provider. +""" + +import os +import sys +import requests + + +# Get keep Webhook URL and API Key from environment variables +def GetPluginParams(): + env_vars = os.environ + + WebHookURL = str(env_vars.get("NOTIFY_PARAMETER_1")) + API_KEY = str(env_vars.get("NOTIFY_PARAMETER_2")) + + # "None", if not in the environment variables + if (WebHookURL == "None" or API_KEY == "None"): + print("keep-plugin: Missing Webhook URL or API Key") + return 2, "" # https://docs.checkmk.com/latest/en/notifications.html#_traceable_notifications + + return 0, WebHookURL + + +# Notification details are stored in environment variables +def GetNotificationDetails(): + # https://docs.checkmk.com/latest/en/notifications.html#environment_variables + env_vars = os.environ + print(env_vars) + + SITE = env_vars.get("OMD_SITE") + WHAT = env_vars.get("NOTIFY_WHAT") + NOTIFICATIONTYPE = env_vars.get("NOTIFY_NOTIFICATIONTYPE") + + CONTACTNAME = env_vars.get("NOTIFY_CONTACTNAME") + CONTACTEMAIL = env_vars.get("NOTIFY_CONTACTEMAIL") + CONTACTPAGER = env_vars.get("NOTIFY_CONTACTPAGER") + + DATE = env_vars.get("NOTIFY_DATE") + LONGDATETIME = env_vars.get("NOTIFY_LONGDATETIME") + SHORTDATETIME = env_vars.get("NOTIFY_SHORTDATETIME") + + HOSTNAME = env_vars.get("NOTIFY_HOSTNAME") + HOSTALIAS = env_vars.get("NOTIFY_HOSTALIAS") + ADDRESS = env_vars.get("NOTIFY_HOSTADDRESS") + + HOST_PROBLEM_ID = env_vars.get("NOTIFY_HOSTPROBLEMID") + OUTPUT_HOST = env_vars.get("NOTIFY_HOSTOUTPUT") + NOTIFY_HOSTSTATE = env_vars.get("NOTIFY_HOSTSTATE") + LONG_OUTPUT_HOST = env_vars.get("NOTIFY_LONGHOSTOUTPUT") + HOST_URL = env_vars.get("NOTIFY_HOSTURL") + HOST_CHECK_COMMAND = env_vars.get("NOTIFY_HOSTCHECKCOMMAND") + NOTIFY_LASTHOSTSHORTSTATE = env_vars.get("NOTIFY_LASTHOSTSHORTSTATE") + EVENT_HOST = f"{NOTIFY_LASTHOSTSHORTSTATE} -> {NOTIFY_HOSTSTATE}" + CURRENT_HOST_STATE = env_vars.get("NOTIFY_HOSTSTATE") + + SERVICE_PROBLEM_ID = env_vars.get("NOTIFY_SERVICEPROBLEMID") + SERVICE = env_vars.get("NOTIFY_SERVICEDESC") + OUTPUT_SERVICE = env_vars.get("NOTIFY_SERVICEOUTPUT") + LONG_OUTPUT_SERVICE = env_vars.get("NOTIFY_LONGSERVICEOUTPUT") + SERVICE_URL = env_vars.get("NOTIFY_SERVICEURL") + SERVICE_CHECK_COMMAND = env_vars.get("NOTIFY_SERVICECHECKCOMMAND") + PERF_DATA = env_vars.get("NOTIFY_SERVICEPERFDATA") + NOTIFY_SERVICESTATE = env_vars.get("NOTIFY_SERVICESTATE") + NOTIFY_LASTSERVICESTATE = env_vars.get("NOTIFY_LASTSERVICESTATE") + EVENT_SERVICE = f"{NOTIFY_LASTSERVICESTATE} -> {NOTIFY_SERVICESTATE}" + CURRENT_SERVICE_STATE = env_vars.get("NOTIFY_SERVICESTATE") + + # General information + general = { + "site": SITE, + "what": WHAT, + "notification_type": NOTIFICATIONTYPE, + "contact_name": CONTACTNAME, + "contact_email": CONTACTEMAIL, + "contact_pager": CONTACTPAGER, + "date": DATE, + "long_date_time": LONGDATETIME, + "short_date_time": SHORTDATETIME + } + + # Host related information + host_notify = { + "id": HOST_PROBLEM_ID, + "summary": f"CheckMK {HOSTNAME} - {EVENT_HOST}", + "host": HOSTNAME, + "alias": HOSTALIAS, + "address": ADDRESS, + "event": EVENT_HOST, + "output": OUTPUT_HOST, + "long_output": LONG_OUTPUT_HOST, + "status": CURRENT_HOST_STATE, + "severity": "OK", + "url": HOST_URL, + "check_command": HOST_CHECK_COMMAND, + **general + } + + # Service related information + service_notify = { + "id": SERVICE_PROBLEM_ID, + "summary": f"CheckMK {HOSTNAME}/{SERVICE} {EVENT_SERVICE}", + "host": HOSTNAME, + "alias": HOSTALIAS, + "address": ADDRESS, + "service": SERVICE, + "event": EVENT_SERVICE, + "output": OUTPUT_SERVICE, + "long_output": LONG_OUTPUT_SERVICE, + "status": "UP", + "severity": CURRENT_SERVICE_STATE, + "url": SERVICE_URL, + "check_command": SERVICE_CHECK_COMMAND, + "perf_data": PERF_DATA, + **general + } + + # Handle HOST and SERVICE notifications + if WHAT == "SERVICE": + notify = service_notify + else: + notify = host_notify + + return notify + + +# Start Keep workflow +def StartKeepWorkflow(WebHookURL, data): + return_code = 0 + + API_KEY = str(os.environ.get("NOTIFY_PARAMETER_2")) + + headers = { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + 'X-API-KEY': API_KEY + } + + try: + response = requests.post(WebHookURL, headers=headers, json=data) + + if response.status_code == 200: + print("keep-plugin: Workflow started successfully.") + else: + print( + f"keep-plugin: Failed to start the workflow. Status code: {response.status_code}") + print(response.text) + return_code = 2 + except Exception as e: + print(f"keep-plugin: An error occurred: {e}") + return_code = 2 + + return return_code + + +def main(): + print("keep-plugin: Starting...") + return_code, WebHookURL = GetPluginParams() + + if return_code != 0: + return return_code # Abort, if parameter for the webhook is missing + + print("keep-plugin: Getting notification details...") + data = GetNotificationDetails() + + print("keep-plugin: Starting Keep workflow...") + return_code = StartKeepWorkflow(WebHookURL, data) + print("keep-plugin: Finished.") + return return_code + + +if __name__ == '__main__': + sys.exit(main()) From 05701118afc73a2c312aae1891c64b9e02482565 Mon Sep 17 00:00:00 2001 From: Kirill Chernakov Date: Tue, 29 Oct 2024 16:30:11 +0400 Subject: [PATCH 10/11] refactor: move incident CRUD to `useIncidentActions()` hook, unify revalidation (#2335) --- keep-ui/app/incidents/[id]/incident-chat.tsx | 43 ++--- .../incidents/create-or-update-incident.tsx | 127 ++++----------- .../incident-change-same-in-the-past.tsx | 36 ++--- .../incident-change-status-modal.tsx | 148 ----------------- .../app/incidents/incident-dropdown-menu.tsx | 8 +- keep-ui/app/incidents/incident-list.tsx | 6 - .../app/incidents/incident-merge-modal.tsx | 44 +---- keep-ui/app/incidents/incidents-table.tsx | 31 +--- .../incidents/model/useIncidentActions.tsx | 152 +++++++++++++++++- keep-ui/utils/hooks/useIncidents.ts | 8 +- 10 files changed, 226 insertions(+), 377 deletions(-) delete mode 100644 keep-ui/app/incidents/incident-change-status-modal.tsx diff --git a/keep-ui/app/incidents/[id]/incident-chat.tsx b/keep-ui/app/incidents/[id]/incident-chat.tsx index 942ba125d..084dd7075 100644 --- a/keep-ui/app/incidents/[id]/incident-chat.tsx +++ b/keep-ui/app/incidents/[id]/incident-chat.tsx @@ -4,32 +4,23 @@ import { useCopilotChatSuggestions, } from "@copilotkit/react-ui"; import { IncidentDto } from "../models"; -import { - useIncident, - useIncidentAlerts, - useIncidents, -} from "utils/hooks/useIncidents"; +import { useIncidentAlerts } from "utils/hooks/useIncidents"; import { EmptyStateCard } from "@/components/ui/EmptyStateCard"; import { useRouter } from "next/navigation"; import Loading from "app/loading"; import { useCopilotAction, useCopilotReadable } from "@copilotkit/react-core"; -import { updateIncidentRequest } from "../create-or-update-incident"; -import { useApiUrl } from "utils/hooks/useConfig"; -import { useSession } from "next-auth/react"; -import { toast } from "react-toastify"; import "@copilotkit/react-ui/styles.css"; import "./incident-chat.css"; import { Card } from "@tremor/react"; +import { useIncidentActions } from "@/entities/incidents/model/useIncidentActions"; export default function IncidentChat({ incident }: { incident: IncidentDto }) { const router = useRouter(); - const apiUrl = useApiUrl(); - const { mutate } = useIncidents(true, 20); - const { mutate: mutateIncident } = useIncident(incident.id); const { data: alerts, isLoading: alertsLoading } = useIncidentAlerts( incident.id ); - const { data: session } = useSession(); + + const { updateIncident } = useIncidentActions(); useCopilotReadable({ description: "incidentDetails", @@ -79,22 +70,16 @@ export default function IncidentChat({ incident }: { incident: IncidentDto }) { }, ], handler: async ({ name, summary }) => { - const response = await updateIncidentRequest({ - session: session, - incidentId: incident.id, - incidentName: name, - incidentUserSummary: summary, - incidentAssignee: incident.assignee, - incidentSameIncidentInThePastId: incident.same_incident_in_the_past_id, - generatedByAi: true, - apiUrl: apiUrl!, - }); - - if (response.ok) { - mutate(); - mutateIncident(); - toast.success("Incident updated successfully"); - } + await updateIncident( + incident.id, + { + user_generated_name: name, + user_summary: summary, + assignee: incident.assignee, + same_incident_in_the_past_id: incident.same_incident_in_the_past_id, + }, + true + ); }, }); diff --git a/keep-ui/app/incidents/create-or-update-incident.tsx b/keep-ui/app/incidents/create-or-update-incident.tsx index 2755b6746..3421c362d 100644 --- a/keep-ui/app/incidents/create-or-update-incident.tsx +++ b/keep-ui/app/incidents/create-or-update-incident.tsx @@ -2,7 +2,6 @@ import { TextInput, - Textarea, Divider, Subtitle, Text, @@ -10,18 +9,14 @@ import { Select, SelectItem, } from "@tremor/react"; -import { useSession } from "next-auth/react"; import { FormEvent, useEffect, useState } from "react"; -import { toast } from "react-toastify"; -import { useApiUrl } from "utils/hooks/useConfig"; import { IncidentDto } from "./models"; -import { useIncidents } from "utils/hooks/useIncidents"; -import { Session } from "next-auth"; import { useUsers } from "utils/hooks/useUsers"; const ReactQuill = typeof window === "object" ? require("react-quill") : () => false; import "react-quill/dist/quill.snow.css"; import "./react-quill-override.css"; +import { useIncidentActions } from "@/entities/incidents/model/useIncidentActions"; interface Props { incidentToEdit: IncidentDto | null; @@ -29,56 +24,17 @@ interface Props { exitCallback?: () => void; } -export const updateIncidentRequest = async ({ - session, - incidentId, - incidentName, - incidentUserSummary, - incidentAssignee, - incidentSameIncidentInThePastId, - generatedByAi, - apiUrl, -}: { - session: Session | null; - incidentId: string; - incidentName: string; - incidentUserSummary: string; - incidentAssignee: string; - incidentSameIncidentInThePastId: string | null; - generatedByAi: boolean; - apiUrl: string; -}) => { - const response = await fetch( - `${apiUrl}/incidents/${incidentId}?generatedByAi=${generatedByAi}`, - { - method: "PUT", - headers: { - Authorization: `Bearer ${session?.accessToken}`, - "Content-Type": "application/json", - }, - body: JSON.stringify({ - user_generated_name: incidentName, - user_summary: incidentUserSummary, - assignee: incidentAssignee, - same_incident_in_the_past_id: incidentSameIncidentInThePastId, - }), - } - ); - return response; -}; - export default function CreateOrUpdateIncident({ incidentToEdit, createCallback, exitCallback, }: Props) { - const { data: session } = useSession(); - const { mutate } = useIncidents(true, 20); const [incidentName, setIncidentName] = useState(""); const [incidentUserSummary, setIncidentUserSummary] = useState(""); const [incidentAssignee, setIncidentAssignee] = useState(""); const { data: users = [] } = useUsers(); - const apiUrl = useApiUrl(); + const { addIncident, updateIncident } = useIncidentActions(); + const editMode = incidentToEdit !== null; // Display cancel btn if editing or we need to cancel for another reason (eg. going one step back in the modal etc.) @@ -104,65 +60,38 @@ export default function CreateOrUpdateIncident({ setIncidentAssignee(""); }; - const addIncident = async (e: FormEvent) => { - e.preventDefault(); - const response = await fetch(`${apiUrl}/incidents`, { - method: "POST", - headers: { - Authorization: `Bearer ${session?.accessToken}`, - "Content-Type": "application/json", - }, - body: JSON.stringify({ - user_generated_name: incidentName, - user_summary: incidentUserSummary, - assignee: incidentAssignee, - }), - }); - if (response.ok) { - exitEditMode(); - await mutate(); - toast.success("Incident created successfully"); - - const created = await response.json(); - createCallback?.(created.id); // close the modal and associate the alert incident - } else { - toast.error( - "Failed to create incident, please contact us if this issue persists." - ); - } + // If the Incident is successfully updated or the user cancels the update we exit the editMode and set the editRule in the incident.tsx to null. + const exitEditMode = () => { + exitCallback?.(); + clearForm(); }; - // This is the function that will be called on submitting the form in the editMode, it sends a PUT request to the backend. - const updateIncident = async (e: FormEvent) => { + const handleSubmit = async (e: FormEvent) => { e.preventDefault(); - const response = await updateIncidentRequest({ - session: session, - incidentId: incidentToEdit?.id!, - incidentName: incidentName, - incidentUserSummary: incidentUserSummary, - incidentAssignee: incidentAssignee, - incidentSameIncidentInThePastId: - incidentToEdit?.same_incident_in_the_past_id!, - generatedByAi: false, - apiUrl: apiUrl!, - }); - if (response.ok) { + if (editMode) { + await updateIncident( + incidentToEdit!.id, + { + user_generated_name: incidentName, + user_summary: incidentUserSummary, + assignee: incidentAssignee, + same_incident_in_the_past_id: + incidentToEdit!.same_incident_in_the_past_id, + }, + false + ); exitEditMode(); - await mutate(); - toast.success("Incident updated successfully"); } else { - toast.error( - "Failed to update incident, please contact us if this issue persists." - ); + const newIncident = await addIncident({ + user_generated_name: incidentName, + user_summary: incidentUserSummary, + assignee: incidentAssignee, + }); + createCallback?.(newIncident.id); + exitEditMode(); } }; - // If the Incident is successfully updated or the user cancels the update we exit the editMode and set the editRule in the incident.tsx to null. - const exitEditMode = () => { - exitCallback?.(); - clearForm(); - }; - const submitEnabled = (): boolean => { return !!incidentName; }; @@ -194,7 +123,7 @@ export default function CreateOrUpdateIncident({ }; return ( -

+ Incident Metadata
diff --git a/keep-ui/app/incidents/incident-change-same-in-the-past.tsx b/keep-ui/app/incidents/incident-change-same-in-the-past.tsx index eb44026bf..c59ed9a38 100644 --- a/keep-ui/app/incidents/incident-change-same-in-the-past.tsx +++ b/keep-ui/app/incidents/incident-change-same-in-the-past.tsx @@ -1,14 +1,11 @@ import { Button, Divider, Title } from "@tremor/react"; import Select from "@/components/ui/Select"; -import { useSession } from "next-auth/react"; import { useRouter } from "next/navigation"; import { FormEvent, useState } from "react"; -import { toast } from "react-toastify"; import { useIncidents, usePollIncidents } from "../../utils/hooks/useIncidents"; import Loading from "../loading"; -import { updateIncidentRequest } from "./create-or-update-incident"; import { IncidentDto } from "./models"; -import { useApiUrl } from "../../utils/hooks/useConfig"; +import { useIncidentActions } from "@/entities/incidents/model/useIncidentActions"; interface ChangeSameIncidentInThePast { incident: IncidentDto; @@ -27,33 +24,32 @@ const ChangeSameIncidentInThePast = ({ const [selectedIncident, setSelectedIncident] = useState< string | undefined >(); - const { data: session } = useSession(); + const { updateIncident } = useIncidentActions(); const router = useRouter(); - const apiUrl = useApiUrl(); const associateIncidentHandler = async ( selectedIncidentId: string | null ) => { - const response = await updateIncidentRequest({ - session: session, - incidentId: incident.id, - incidentSameIncidentInThePastId: selectedIncidentId, - incidentName: incident.user_generated_name, - incidentUserSummary: incident.user_summary, - incidentAssignee: incident.assignee, - generatedByAi: false, - apiUrl: apiUrl!, - }); - if (response.ok) { - mutate(); - toast.success("Incident updated successfully!"); + try { + await updateIncident( + incident.id, + { + same_incident_in_the_past_id: selectedIncidentId, + }, + false + ); handleClose(); + } catch (error) { + console.error(error); } }; const handleLinkIncident = (e: FormEvent) => { e.preventDefault(); - if (selectedIncident) associateIncidentHandler(selectedIncident); + if (!selectedIncident) { + return; + } + associateIncidentHandler(selectedIncident); }; const handleUnlinkIncident = (e: FormEvent) => { diff --git a/keep-ui/app/incidents/incident-change-status-modal.tsx b/keep-ui/app/incidents/incident-change-status-modal.tsx deleted file mode 100644 index 7c3d701f5..000000000 --- a/keep-ui/app/incidents/incident-change-status-modal.tsx +++ /dev/null @@ -1,148 +0,0 @@ -import { Button, Title, Subtitle } from "@tremor/react"; -import Modal from "@/components/ui/Modal"; -import Select, { - CSSObjectWithLabel, - ControlProps, - OptionProps, - GroupBase, -} from "react-select"; -import { useState } from "react"; -import { IncidentDto, Status } from "./models"; -import { useApiUrl } from "utils/hooks/useConfig"; -import { useSession } from "next-auth/react"; -import { toast } from "react-toastify"; -import { STATUS_ICONS } from "@/app/incidents/statuses"; - -const customSelectStyles = { - control: ( - base: CSSObjectWithLabel, - state: ControlProps< - { value: Status; label: JSX.Element }, - false, - GroupBase<{ value: Status; label: JSX.Element }> - > - ) => ({ - ...base, - borderColor: state.isFocused ? "orange" : base.borderColor, - boxShadow: state.isFocused ? "0 0 0 1px orange" : base.boxShadow, - "&:hover": { - borderColor: "orange", - }, - }), - option: ( - base: CSSObjectWithLabel, - { - isFocused, - }: OptionProps< - { value: Status; label: JSX.Element }, - false, - GroupBase<{ value: Status; label: JSX.Element }> - > - ) => ({ - ...base, - backgroundColor: isFocused ? "rgba(255,165,0,0.1)" : base.backgroundColor, - "&:hover": { - backgroundColor: "rgba(255,165,0,0.2)", - }, - }), -}; - -interface Props { - incident: IncidentDto | null | undefined; - mutate: () => void; - handleClose: () => void; -} - -export default function IncidentChangeStatusModal({ - incident, - mutate, - handleClose, -}: Props) { - const { data: session } = useSession(); - const [selectedStatus, setSelectedStatus] = useState(null); - const [comment, setComment] = useState(""); - const apiUrl = useApiUrl(); - - if (!incident) return null; - - const statusOptions = Object.values(Status) - .filter((status) => status !== incident.status) // Exclude current status - .map((status) => ({ - value: status, - label: ( -
- {STATUS_ICONS[status]} - {status.charAt(0).toUpperCase() + status.slice(1)} -
- ), - })); - - const clearAndClose = () => { - setSelectedStatus(null); - handleClose(); - }; - - const handleChangeStatus = async () => { - if (!selectedStatus) { - toast.error("Please select a new status."); - return; - } - - try { - const response = await fetch( - `${apiUrl}/incidents/${incident.id}/status`, - { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${session?.accessToken}`, - }, - body: JSON.stringify({ - status: selectedStatus, - comment: comment, - }), - } - ); - - if (response.ok) { - toast.success("Incident status changed successfully!"); - clearAndClose(); - await mutate(); - } else { - toast.error("Failed to change incident status."); - } - } catch (error) { - toast.error("An error occurred while changing incident status."); - } - }; - - return ( - - Change Incident Status - - Change status from {incident.status}{" "} - to: -
-