From 01986bb8c95017293fb36750382e658dfa7119a1 Mon Sep 17 00:00:00 2001 From: Joey Orlando Date: Wed, 12 Jul 2023 02:45:06 -0400 Subject: [PATCH 01/11] Update CHANGELOG.md (again) --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2fbcabf4..9bd6eeae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,7 +15,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add debounce on Select UI components to avoid making API search requests on each key-down event by @maskin25 ([#2466](https://github.com/grafana/oncall/pull/2466)) -- Fixed schedules slack notifications for deleted organizations ([#2493](https://github.com/grafana/oncall/pull/2493)) ## v1.3.8 (2023-07-11) @@ -36,6 +35,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Address issue where we were improperly parsing Grafana feature flags that were enabled via the `feature_flags.enabled` method by @joeyorlando ([#2477](https://github.com/grafana/oncall/pull/2477)) - Fix cuddled list Markdown issue by @vadimkerr ([#2488](https://github.com/grafana/oncall/pull/2488)) +- Fixed schedules slack notifications for deleted organizations ([#2493](https://github.com/grafana/oncall/pull/2493)) ## v1.3.7 (2023-07-06) From df0ce35ae359699ba38a8a9265cb087f5208935f Mon Sep 17 00:00:00 2001 From: Yulia Shanyrova Date: Wed, 12 Jul 2023 12:11:42 +0200 Subject: [PATCH 02/11] Maintenance page is deprecated, info message was added (#2497) # What this PR does Maintenance page is deprecated, info message was added closes https://github.com/grafana/oncall-private/issues/1737 --------- Co-authored-by: Joey Orlando Co-authored-by: Joey Orlando --- CHANGELOG.md | 7 + .../pages/maintenance/Maintenance.module.css | 4 + .../src/pages/maintenance/Maintenance.tsx | 217 ++---------------- .../src/plugin/GrafanaPluginRootPage.tsx | 2 +- 4 files changed, 29 insertions(+), 201 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9bd6eeae..28f1c7ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +### Changed + +- Deprecated `/maintenance` web UI page. Maintenance is now handled at the integration level and can be performed + within a single integration's page. by @Ukochka ([2497](https://github.com/grafana/oncall/issues/2497)) + ## v1.3.9 (2023-07-12) ### Added diff --git a/grafana-plugin/src/pages/maintenance/Maintenance.module.css b/grafana-plugin/src/pages/maintenance/Maintenance.module.css index 3a4ceeea..af825964 100644 --- a/grafana-plugin/src/pages/maintenance/Maintenance.module.css +++ b/grafana-plugin/src/pages/maintenance/Maintenance.module.css @@ -10,3 +10,7 @@ .title { margin-bottom: var(--title-marginBottom); } + +.info-box { + width: 100%; +} diff --git a/grafana-plugin/src/pages/maintenance/Maintenance.tsx b/grafana-plugin/src/pages/maintenance/Maintenance.tsx index ad1d46b8..a90d1561 100644 --- a/grafana-plugin/src/pages/maintenance/Maintenance.tsx +++ b/grafana-plugin/src/pages/maintenance/Maintenance.tsx @@ -1,220 +1,37 @@ import React from 'react'; -import { Button, VerticalGroup } from '@grafana/ui'; +import { Alert } from '@grafana/ui'; import cn from 'classnames/bind'; import { observer } from 'mobx-react'; -import moment from 'moment-timezone'; -import LegacyNavHeading from 'navbar/LegacyNavHeading'; -import Emoji from 'react-emoji-render'; -import GTable from 'components/GTable/GTable'; -import Text from 'components/Text/Text'; -import WithConfirm from 'components/WithConfirm/WithConfirm'; -import MaintenanceForm from 'containers/MaintenanceForm/MaintenanceForm'; -import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip'; -import { getAlertReceiveChannelDisplayName } from 'models/alert_receive_channel/alert_receive_channel.helpers'; -import { AlertReceiveChannel } from 'models/alert_receive_channel/alert_receive_channel.types'; -import { Maintenance, MaintenanceMode, MaintenanceType } from 'models/maintenance/maintenance.types'; -import { PageProps, WithStoreProps } from 'state/types'; -import { withMobXProviderContext } from 'state/withStore'; -import { UserActions } from 'utils/authorization'; +import PluginLink from 'components/PluginLink/PluginLink'; import styles from './Maintenance.module.css'; const cx = cn.bind(styles); -interface MaintenancePageProps extends PageProps, WithStoreProps {} - -interface MaintenancePageState { - maintenanceData?: { - type?: MaintenanceType; - alert_receive_channel_id?: AlertReceiveChannel['id']; - disabled?: boolean; - }; -} +interface MaintenancePageProps {} @observer -class MaintenancePage extends React.Component { - state: MaintenancePageState = {}; - - async componentDidMount() { - const { - store: { alertReceiveChannelStore }, - } = this.props; - - this.update().then(this.parseQueryParams); - - alertReceiveChannelStore.updateItems().then(() => { - this.forceUpdate(); - }); - } - - componentDidUpdate(prevProps: MaintenancePageProps) { - if (this.props.query.maintenance_type !== prevProps.query.maintenance_type) { - this.parseQueryParams(); - } - } - - parseQueryParams = () => { - const { query } = this.props; - - if ('maintenance_type' in query) { - const preselectedMaintenanceType = query.maintenance_type as MaintenanceType; - const preselectedAlertReceiveChannel = query.alert_receive_channel as AlertReceiveChannel['id']; - - this.setState({ - maintenanceData: { - type: preselectedMaintenanceType, - alert_receive_channel_id: preselectedAlertReceiveChannel, - }, - }); - } - }; - - update = () => { - const { store } = this.props; - const { maintenanceStore } = store; - - return maintenanceStore.updateMaintenances(); - }; - +class MaintenancePage extends React.Component { render() { - const { store } = this.props; - const { maintenanceStore } = store; - const { maintenanceData } = this.state; - - const data = maintenanceStore?.maintenances; - - const columns = [ - { - width: 300, - title: 'Integration', - render: this.renderTitle, - key: 'Title', - }, - { - width: 200, - title: 'Mode', - render: this.renderMode, - key: 'mode', - }, - { - title: 'Progress', - render: this.renderDuration, - key: 'progress', - }, - { - title: 'Time limit', - render: this.renderTimer, - key: 'timer', - }, - { - width: 100, - key: 'action', - render: this.renderActionButtons, - }, - ]; - return ( <> -
- ( -
-
- - - Maintenance - - - Mute noisy sources or use for debugging and avoid bothering your colleagues. - - -
- - - -
- )} - rowKey="id" - columns={columns} - data={data} - /> -
- {maintenanceData && ( - { - this.setState({ maintenanceData: undefined }); - }} - /> - )} + + Maintenance mode is now controlled at the{' '} + Integration level. This page will soon be + removed. + + } + /> ); } - - renderTitle = (maintenance: Maintenance) => { - const { store } = this.props; - const { alertReceiveChannelStore } = store; - const alertReceiveChannel = alertReceiveChannelStore.items - ? alertReceiveChannelStore.items[maintenance.alert_receive_channel_id] - : undefined; - - switch (maintenance.type) { - case MaintenanceType.alert_receive_channel: - return ; - - case MaintenanceType.organization: - return `${store.teamStore.currentTeam?.name} Team`; - } - }; - - renderMode = (maintenance: Maintenance) => { - return maintenance.maintenance_mode === MaintenanceMode.Debug ? 'Debug' : 'Maintenance'; - }; - - renderActionButtons = (maintenance: Maintenance) => { - return ( -
- - - - - -
- ); - }; - - renderDuration = (maintenance: Maintenance) => { - const started = moment(maintenance.started_at_timestamp * 1000); - const ended = moment(maintenance.maintenance_till_timestamp * 1000); - return `${started.format('MMM DD, YYYY HH:mm')} - ${ended.format('MMM DD, YYYY hh:mm')}`; - }; - - renderTimer = (maintenance: Maintenance) => { - return `ends ${moment(maintenance.maintenance_till_timestamp * 1000).fromNow()}`; - }; - - getStopMaintenanceHandler = (maintenance: Maintenance) => { - const { store } = this.props; - const { maintenanceStore } = store; - - return () => { - maintenanceStore.stopMaintenanceMode(maintenance.type, maintenance.alert_receive_channel_id).then(this.update); - }; - }; } -export default withMobXProviderContext(MaintenancePage); +export default MaintenancePage; diff --git a/grafana-plugin/src/plugin/GrafanaPluginRootPage.tsx b/grafana-plugin/src/plugin/GrafanaPluginRootPage.tsx index 0980b4fc..e95b8b16 100644 --- a/grafana-plugin/src/plugin/GrafanaPluginRootPage.tsx +++ b/grafana-plugin/src/plugin/GrafanaPluginRootPage.tsx @@ -171,7 +171,7 @@ export const Root = observer((props: AppRootProps) => { - + From 03d540235087791023a49c6829125c64461b50e8 Mon Sep 17 00:00:00 2001 From: Jack Baldry Date: Wed, 12 Jul 2023 12:16:07 +0100 Subject: [PATCH 03/11] Update team name: grafana/docs-oncall is now grafana/docs-gops (#2512) # What this PR does Fixes the CODEOWNERS file which is marked as invalid because of the team name change. The team will need to be given write access to the repository by a repository admin. https://github.com/orgs/grafana/teams/docs-gops is the team. Signed-off-by: Jack Baldry --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index f699829e..72036a42 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -4,4 +4,4 @@ CHANGELOG.md /grafana-plugin @grafana/grafana-oncall-frontend -/docs @grafana/docs-oncall +/docs @grafana/docs-gops From 79fc5290196efc109a732f020ed423f2d870247f Mon Sep 17 00:00:00 2001 From: Maxim Mordasov Date: Wed, 12 Jul 2023 17:00:16 +0300 Subject: [PATCH 04/11] Tune schedules and badge colors (#2496) # What this PR does Fix rotation modal dateinput overflow, tune schedules colors, fix badge colors ## Which issue(s) this PR fixes https://github.com/grafana/oncall/issues/1002 https://github.com/grafana/oncall/issues/2356 ## Checklist - [ ] Unit, integration, and e2e (if applicable) tests updated - [ ] Documentation added (or `pr:no public docs` PR label added if not required) - [x] `CHANGELOG.md` updated (or `pr:no changelog` PR label added if not required) --- CHANGELOG.md | 5 +++ .../ScheduleQuality.module.scss | 10 ++--- .../UserGroups/UserGroups.module.css | 2 + .../src/components/UserGroups/UserGroups.tsx | 29 +++++++------- .../components/WorkingHours/WorkingHours.tsx | 12 +++--- .../RotationForm/RotationForm.module.css | 2 - .../UsersTimezones/UsersTimezones.tsx | 2 +- grafana-plugin/src/style/vars.css | 38 +++++++++++++------ 8 files changed, 57 insertions(+), 43 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 28f1c7ac..e902ca54 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Deprecated `/maintenance` web UI page. Maintenance is now handled at the integration level and can be performed within a single integration's page. by @Ukochka ([2497](https://github.com/grafana/oncall/issues/2497)) + +### Fixed + +- Schedules: Long popup does not fit screen & buttons unreachable & objects outside of the popup [1002](https://github.com/grafana/oncall/issues/1002) +- New schedules white theme issues [2356](https://github.com/grafana/oncall/issues/2356) ## v1.3.9 (2023-07-12) diff --git a/grafana-plugin/src/components/ScheduleQuality/ScheduleQuality.module.scss b/grafana-plugin/src/components/ScheduleQuality/ScheduleQuality.module.scss index 1cfd657b..b4e2e8cf 100644 --- a/grafana-plugin/src/components/ScheduleQuality/ScheduleQuality.module.scss +++ b/grafana-plugin/src/components/ScheduleQuality/ScheduleQuality.module.scss @@ -1,7 +1,3 @@ -$score-primary: rgba(27, 133, 94, 0.15); -$score-warning: rgba(245, 183, 61, 0.18); -$score-danger: rgba(209, 14, 92, 0.15); - .root { display: flex; flex-direction: row; @@ -18,17 +14,17 @@ $score-danger: rgba(209, 14, 92, 0.15); padding: 4px 10px 3px 10px; &--danger { - background-color: $score-danger; + background-color: var(--tag-background-danger); color: var(--tag-text-danger); border: 1px solid var(--tag-border-danger); } &--warning { - background-color: $score-warning; + background-color: var(--tag-background-warning); color: var(--tag-text-warning); border: 1px solid var(--tag-border-warning); } &--primary { - background-color: $score-primary; + background-color: var(--tag-background-success); color: var(--tag-text-success); border: 1px solid var(--tag-border-success); } diff --git a/grafana-plugin/src/components/UserGroups/UserGroups.module.css b/grafana-plugin/src/components/UserGroups/UserGroups.module.css index f8a4cf39..04440d08 100644 --- a/grafana-plugin/src/components/UserGroups/UserGroups.module.css +++ b/grafana-plugin/src/components/UserGroups/UserGroups.module.css @@ -51,6 +51,8 @@ display: flex; flex-direction: column; gap: 1px; + max-height: calc(100vh - 600px); + overflow: scroll; } .user { diff --git a/grafana-plugin/src/components/UserGroups/UserGroups.tsx b/grafana-plugin/src/components/UserGroups/UserGroups.tsx index b0d4c6bb..6c700d8e 100644 --- a/grafana-plugin/src/components/UserGroups/UserGroups.tsx +++ b/grafana-plugin/src/components/UserGroups/UserGroups.tsx @@ -33,8 +33,6 @@ const SortableHandleHoc = SortableHandle(DragHandle); const UserGroups = (props: UserGroupsProps) => { const { value, onChange, isMultipleGroups, renderUser, showError, disabled } = props; - const rootRef = useRef(); - const handleAddUserGroup = useCallback(() => { onChange([...value, []]); }, [value]); @@ -97,17 +95,6 @@ const UserGroups = (props: UserGroupsProps) => { }; }; - useEffect(() => { - const container = rootRef.current.parentElement.parentElement.parentElement; - const containerParent = container.parentElement; - - containerParent.scroll({ - left: 0, - top: container.scrollHeight, - behavior: 'smooth', - }); - }, [value]); - const renderItem = (item: Item, index: number) => (
  • {renderUser(item.data)} @@ -123,7 +110,7 @@ const UserGroups = (props: UserGroupsProps) => { ); return ( -
    +
    {!disabled && ( ( ({ items, handleAddGroup, isMultipleGroups, renderItem, allowCreate }) => { + const listRef = useRef(); + + useEffect(() => { + const container = listRef.current; + + container.scroll({ + left: 0, + top: container.scrollHeight, + behavior: 'smooth', + }); + }, [items]); + return ( -
      +
        {items.map((item, index) => item.type === 'item' ? ( diff --git a/grafana-plugin/src/components/WorkingHours/WorkingHours.tsx b/grafana-plugin/src/components/WorkingHours/WorkingHours.tsx index effc7952..659a51c3 100644 --- a/grafana-plugin/src/components/WorkingHours/WorkingHours.tsx +++ b/grafana-plugin/src/components/WorkingHours/WorkingHours.tsx @@ -16,13 +16,13 @@ interface WorkingHoursProps { startMoment: dayjs.Dayjs; duration: number; // in seconds className: string; - strong?: boolean; + light?: boolean; } const cx = cn.bind(styles); const WorkingHours: FC = (props) => { - const { timezone, workingHours = default_working_hours, startMoment, duration, className, strong = false } = props; + const { timezone, workingHours = default_working_hours, startMoment, duration, className, light } = props; const endMoment = startMoment.add(duration, 'seconds'); @@ -38,10 +38,10 @@ const WorkingHours: FC = (props) => { - + - - + + {nonWorkingMoments && @@ -56,7 +56,7 @@ const WorkingHours: FC = (props) => { y={0} width={`${(diff * 100) / duration}%`} height="100%" - fill={`${strong ? 'url(#stripes_strong)' : 'url(#stripes)'}`} + fill={light ? 'url(#stripes_light)' : 'url(#stripes)'} /> ); })} diff --git a/grafana-plugin/src/containers/RotationForm/RotationForm.module.css b/grafana-plugin/src/containers/RotationForm/RotationForm.module.css index 803aad27..0e03a13c 100644 --- a/grafana-plugin/src/containers/RotationForm/RotationForm.module.css +++ b/grafana-plugin/src/containers/RotationForm/RotationForm.module.css @@ -1,6 +1,4 @@ .body { - max-height: calc(100vh - 300px); - overflow: scroll; margin: 15px -15px; padding: 15px 0; border-top: var(--border-medium); diff --git a/grafana-plugin/src/containers/UsersTimezones/UsersTimezones.tsx b/grafana-plugin/src/containers/UsersTimezones/UsersTimezones.tsx index 0f2c2058..2b79241a 100644 --- a/grafana-plugin/src/containers/UsersTimezones/UsersTimezones.tsx +++ b/grafana-plugin/src/containers/UsersTimezones/UsersTimezones.tsx @@ -77,7 +77,7 @@ const UsersTimezones: FC = (props) => { return (
        Date: Wed, 12 Jul 2023 17:30:20 +0200 Subject: [PATCH 05/11] Added resources limits definition for wait-for-db container (#2501) # What this PR does Added 'resources limits' definition for wait-for-db container ## Which issue(s) this PR fixes I face a problem: when i install OnCall by Helm, my pods with oncall-engine and oncall-celery stuck on Init state, because they don't have enough resources to run. ## Checklist - [x] Unit, integration, and e2e (if applicable) tests updated - [x] `CHANGELOG.md` updated (or `pr:no changelog` PR label added if not required) - [ ] Documentation added (or `pr:no public docs` PR label added if not required) --------- Co-authored-by: Joey Orlando Co-authored-by: Joey Orlando --- CHANGELOG.md | 5 ++++ helm/oncall/templates/_helpers.tpl | 4 +++ .../__snapshot__/wait_for_db_test.yaml.snap | 28 +++++++++++++++++++ helm/oncall/tests/wait_for_db_test.yaml | 15 ++++++++++ helm/oncall/values.yaml | 7 +++++ 5 files changed, 59 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e902ca54..6b53a492 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +### Added + +- [Helm] Added ability to specify `resources` definition within the `wait-for-db` init container by @Shelestov7 + ([#2501](https://github.com/grafana/oncall/pull/2501)) + ### Changed - Deprecated `/maintenance` web UI page. Maintenance is now handled at the integration level and can be performed diff --git a/helm/oncall/templates/_helpers.tpl b/helm/oncall/templates/_helpers.tpl index e58f9edc..4cf593ee 100644 --- a/helm/oncall/templates/_helpers.tpl +++ b/helm/oncall/templates/_helpers.tpl @@ -92,6 +92,8 @@ Create the name of the service account to use command: ['sh', '-c', "until (python manage.py migrate --check); do echo Waiting for database migrations; sleep 2; done"] securityContext: {{ toYaml .Values.init.securityContext | nindent 4 }} + resources: + {{ toYaml .Values.init.resources | nindent 4 }} env: {{- include "snippet.oncall.env" . | nindent 4 }} {{- include "snippet.mysql.env" . | nindent 4 }} @@ -107,6 +109,8 @@ Create the name of the service account to use command: ['sh', '-c', "until (python manage.py migrate --check); do echo Waiting for database migrations; sleep 2; done"] securityContext: {{ toYaml .Values.init.securityContext | nindent 4 }} + resources: + {{ toYaml .Values.init.resources | nindent 4 }} env: {{- include "snippet.oncall.env" . | nindent 4 }} {{- include "snippet.postgresql.env" . | nindent 4 }} diff --git a/helm/oncall/tests/__snapshot__/wait_for_db_test.yaml.snap b/helm/oncall/tests/__snapshot__/wait_for_db_test.yaml.snap index 7d764bde..fc8d400e 100644 --- a/helm/oncall/tests/__snapshot__/wait_for_db_test.yaml.snap +++ b/helm/oncall/tests/__snapshot__/wait_for_db_test.yaml.snap @@ -71,6 +71,13 @@ database.type=mysql -> should create initContainer for MySQL database (default): image: grafana/oncall:v1.2.36 imagePullPolicy: Always name: wait-for-db + resources: + limits: + cpu: 100m + memory: 128Mi + requests: + cpu: 100m + memory: 128Mi securityContext: {} 2: | - command: @@ -144,6 +151,13 @@ database.type=mysql -> should create initContainer for MySQL database (default): image: grafana/oncall:v1.2.36 imagePullPolicy: Always name: wait-for-db + resources: + limits: + cpu: 100m + memory: 128Mi + requests: + cpu: 100m + memory: 128Mi securityContext: {} database.type=postgresql -> should create initContainer for PostgreSQL database: 1: | @@ -220,6 +234,13 @@ database.type=postgresql -> should create initContainer for PostgreSQL database: image: grafana/oncall:v1.2.36 imagePullPolicy: Always name: wait-for-db + resources: + limits: + cpu: 100m + memory: 128Mi + requests: + cpu: 100m + memory: 128Mi securityContext: {} 2: | - command: @@ -295,4 +316,11 @@ database.type=postgresql -> should create initContainer for PostgreSQL database: image: grafana/oncall:v1.2.36 imagePullPolicy: Always name: wait-for-db + resources: + limits: + cpu: 100m + memory: 128Mi + requests: + cpu: 100m + memory: 128Mi securityContext: {} diff --git a/helm/oncall/tests/wait_for_db_test.yaml b/helm/oncall/tests/wait_for_db_test.yaml index e43b1ef8..9a8bdf8e 100644 --- a/helm/oncall/tests/wait_for_db_test.yaml +++ b/helm/oncall/tests/wait_for_db_test.yaml @@ -8,6 +8,14 @@ chart: appVersion: v1.2.36 tests: - it: database.type=mysql -> should create initContainer for MySQL database (default) + set: + init.resources: + limits: + cpu: 100m + memory: 128Mi + requests: + cpu: 100m + memory: 128Mi asserts: - contains: path: spec.template.spec.initContainers @@ -26,6 +34,13 @@ tests: set: database.type: postgresql externalPostgresql.host: some-postgresql-host + init.resources: + limits: + cpu: 100m + memory: 128Mi + requests: + cpu: 100m + memory: 128Mi asserts: - contains: path: spec.template.spec.initContainers diff --git a/helm/oncall/values.yaml b/helm/oncall/values.yaml index 079ae51f..63963c08 100644 --- a/helm/oncall/values.yaml +++ b/helm/oncall/values.yaml @@ -422,3 +422,10 @@ init: # runAsGroup: 1337 # runAsNonRoot: true # runAsUser: 1337 + resources: {} + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi From d24dc4b630d97eb382a77d79cf577a189eb28f76 Mon Sep 17 00:00:00 2001 From: Joey Orlando Date: Wed, 12 Jul 2023 22:41:44 +0200 Subject: [PATCH 06/11] remove organization maintenance mode + fix integration maintenance mode (#2511) --- CHANGELOG.md | 14 +- .../escalation_snapshot_mixin.py | 4 +- engine/apps/alerts/models/alert.py | 4 +- engine/apps/alerts/models/alert_group.py | 8 - engine/apps/alerts/tasks/distribute_alert.py | 7 +- engine/apps/alerts/tasks/maintenance.py | 20 -- .../tasks/send_update_log_report_signal.py | 6 +- engine/apps/alerts/tests/test_maintenance.py | 72 ----- engine/apps/api/serializers/organization.py | 5 - .../apps/api/tests/test_escalation_policy.py | 4 +- engine/apps/api/tests/test_maintenance.py | 272 ------------------ engine/apps/api/urls.py | 4 - engine/apps/api/views/maintenance.py | 161 ----------- .../public_api/serializers/organizations.py | 12 +- .../apps/slack/scenarios/distribute_alerts.py | 7 +- .../user_management/models/organization.py | 38 +-- .../integrations/maintenanceMode.test.ts | 144 ++++++++++ .../integration-tests/utils/alertGroup.ts | 69 ++++- .../integration-tests/utils/forms.ts | 15 +- .../integration-tests/utils/integrations.ts | 77 +++-- grafana-plugin/playwright.config.ts | 4 + .../Integrations/IntegrationBlockItem.tsx | 2 +- .../components/TooltipBadge/TooltipBadge.tsx | 15 +- .../WithContextMenu/WithContextMenu.tsx | 5 +- .../CollapsedIntegrationRouteDisplay.tsx | 4 +- .../MaintenanceForm.config.tsx | 4 +- .../MaintenanceForm/MaintenanceForm.tsx | 33 +-- .../alert_receive_channel.ts | 15 + .../src/models/maintenance/maintenance.ts | 55 ---- .../models/maintenance/maintenance.types.ts | 19 -- .../src/pages/integration/Integration.tsx | 25 +- .../src/pages/integrations/Integrations.tsx | 1 + .../src/state/rootBaseStore/index.ts | 2 - grafana-plugin/src/utils/index.ts | 8 +- 34 files changed, 371 insertions(+), 764 deletions(-) delete mode 100644 engine/apps/api/tests/test_maintenance.py delete mode 100644 engine/apps/api/views/maintenance.py create mode 100644 grafana-plugin/integration-tests/integrations/maintenanceMode.test.ts delete mode 100644 grafana-plugin/src/models/maintenance/maintenance.ts delete mode 100644 grafana-plugin/src/models/maintenance/maintenance.types.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b53a492..53d9bc95 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,18 +15,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Deprecated `/maintenance` web UI page. Maintenance is now handled at the integration level and can be performed - within a single integration's page. by @Ukochka ([2497](https://github.com/grafana/oncall/issues/2497)) - + within a single integration's page. by @Ukochka ([#2497](https://github.com/grafana/oncall/issues/2497)) + ### Fixed -- Schedules: Long popup does not fit screen & buttons unreachable & objects outside of the popup [1002](https://github.com/grafana/oncall/issues/1002) -- New schedules white theme issues [2356](https://github.com/grafana/oncall/issues/2356) +- Fixed a bug in the integration maintenance mode workflow where a user could not start/stop an integration's + maintenance mode by @joeyorlando ([#2511](https://github.com/grafana/oncall/issues/2511)) +- Schedules: Long popup does not fit screen & buttons unreachable & objects outside of the popup [#1002](https://github.com/grafana/oncall/issues/1002) +- New schedules white theme issues [#2356](https://github.com/grafana/oncall/issues/2356) ## v1.3.9 (2023-07-12) ### Added -- Bring new Jinja editor to webhooks ([2344](https://github.com/grafana/oncall/issues/2344)) +- Bring new Jinja editor to webhooks ([#2344](https://github.com/grafana/oncall/issues/2344)) ### Fixed @@ -83,7 +85,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - UI drawer updates for webhooks2 ([#2419](https://github.com/grafana/oncall/pull/2419)) -- Removed url from sms notification, changed format ([2317](https://github.com/grafana/oncall/pull/2317)) +- Removed url from sms notification, changed format ([#2317](https://github.com/grafana/oncall/pull/2317)) ## v1.3.3 (2023-06-29) diff --git a/engine/apps/alerts/escalation_snapshot/escalation_snapshot_mixin.py b/engine/apps/alerts/escalation_snapshot/escalation_snapshot_mixin.py index b202ceb0..33917d12 100644 --- a/engine/apps/alerts/escalation_snapshot/escalation_snapshot_mixin.py +++ b/engine/apps/alerts/escalation_snapshot/escalation_snapshot_mixin.py @@ -231,9 +231,7 @@ class EscalationSnapshotMixin: """ AlertGroup = apps.get_model("alerts", "AlertGroup") - is_on_maintenace_or_debug_mode = ( - self.channel.maintenance_mode is not None or self.channel.organization.maintenance_mode is not None - ) + is_on_maintenace_or_debug_mode = self.channel.maintenance_mode is not None if ( self.is_restricted diff --git a/engine/apps/alerts/models/alert.py b/engine/apps/alerts/models/alert.py index b49773e8..df4df514 100644 --- a/engine/apps/alerts/models/alert.py +++ b/engine/apps/alerts/models/alert.py @@ -128,10 +128,8 @@ class Alert(models.Model): if group_created: # all code below related to maintenance mode maintenance_uuid = None - if alert_receive_channel.organization.maintenance_mode == AlertReceiveChannel.MAINTENANCE: - maintenance_uuid = alert_receive_channel.organization.maintenance_uuid - elif alert_receive_channel.maintenance_mode == AlertReceiveChannel.MAINTENANCE: + if alert_receive_channel.maintenance_mode == AlertReceiveChannel.MAINTENANCE: maintenance_uuid = alert_receive_channel.maintenance_uuid if maintenance_uuid is not None: diff --git a/engine/apps/alerts/models/alert_group.py b/engine/apps/alerts/models/alert_group.py index 1cf41fec..ca93602a 100644 --- a/engine/apps/alerts/models/alert_group.py +++ b/engine/apps/alerts/models/alert_group.py @@ -426,7 +426,6 @@ class AlertGroup(AlertGroupSlackRenderingMixin, EscalationSnapshotMixin, models. return self.maintenance_uuid is not None def stop_maintenance(self, user: User) -> None: - Organization = apps.get_model("user_management", "Organization") AlertReceiveChannel = apps.get_model("alerts", "AlertReceiveChannel") try: @@ -436,13 +435,6 @@ class AlertGroup(AlertGroupSlackRenderingMixin, EscalationSnapshotMixin, models. except AlertReceiveChannel.DoesNotExist: pass - try: - organization_on_maintenance = Organization.objects.get(maintenance_uuid=self.maintenance_uuid) - organization_on_maintenance.force_disable_maintenance(user) - return - except Organization.DoesNotExist: - pass - self.resolve_by_disable_maintenance() @property diff --git a/engine/apps/alerts/tasks/distribute_alert.py b/engine/apps/alerts/tasks/distribute_alert.py index 0d532772..e5b3e159 100644 --- a/engine/apps/alerts/tasks/distribute_alert.py +++ b/engine/apps/alerts/tasks/distribute_alert.py @@ -46,11 +46,8 @@ def send_alert_create_signal(alert_id): task_logger.debug(f"Started send_alert_create_signal task for alert {alert_id}") alert = Alert.objects.get(pk=alert_id) - is_on_maintenace_mode = ( - alert.group.channel.maintenance_mode == AlertReceiveChannel.MAINTENANCE - or alert.group.channel.organization.maintenance_mode == AlertReceiveChannel.MAINTENANCE - ) - if not is_on_maintenace_mode: + + if alert.group.channel.maintenance_mode != AlertReceiveChannel.MAINTENANCE: alert_create_signal.send( sender=send_alert_create_signal, alert=alert_id, diff --git a/engine/apps/alerts/tasks/maintenance.py b/engine/apps/alerts/tasks/maintenance.py index 6c296248..b1118453 100644 --- a/engine/apps/alerts/tasks/maintenance.py +++ b/engine/apps/alerts/tasks/maintenance.py @@ -16,7 +16,6 @@ from .task_logger import task_logger def disable_maintenance(*args, **kwargs): AlertGroup = apps.get_model("alerts", "AlertGroup") User = apps.get_model("user_management", "User") - Organization = apps.get_model("user_management", "Organization") user = None object_under_maintenance = None user_id = kwargs.get("user_id") @@ -37,12 +36,6 @@ def disable_maintenance(*args, **kwargs): task_logger.info( f"AlertReceiveChannel for disable_maintenance does not exists. Id: {alert_receive_channel_id}" ) - elif "organization_id" in kwargs: - organization_id = kwargs["organization_id"] - try: - object_under_maintenance = Organization.objects.select_for_update().get(pk=organization_id) - except Organization.DoesNotExist: - task_logger.info(f"Organization for disable_maintenance does not exists. Id: {organization_id}") else: task_logger.info(f"Invalid instance id passed in disable_maintenance. Got: {kwargs}") @@ -90,7 +83,6 @@ def disable_maintenance(*args, **kwargs): ) def check_maintenance_finished(*args, **kwargs): AlertReceiveChannel = apps.get_model("alerts", "AlertReceiveChannel") - Organization = apps.get_model("user_management", "Organization") now = timezone.now() maintenance_finish_at = ExpressionWrapper( (F("maintenance_started_at") + F("maintenance_duration")), output_field=fields.DateTimeField() @@ -107,15 +99,3 @@ def check_maintenance_finished(*args, **kwargs): args=(), kwargs={"alert_receive_channel_id": id, "force": True}, ) - - organization_with_expired_maintenance_ids = ( - Organization.objects.filter(maintenance_started_at__isnull=False) - .annotate(maintenance_finish_at=maintenance_finish_at) - .filter(maintenance_finish_at__lt=now) - .values_list("pk", flat=True) - ) - for id in organization_with_expired_maintenance_ids: - disable_maintenance.apply_async( - args=(), - kwargs={"organization_id": id, "force": True}, - ) diff --git a/engine/apps/alerts/tasks/send_update_log_report_signal.py b/engine/apps/alerts/tasks/send_update_log_report_signal.py index 0705654c..771bf887 100644 --- a/engine/apps/alerts/tasks/send_update_log_report_signal.py +++ b/engine/apps/alerts/tasks/send_update_log_report_signal.py @@ -21,11 +21,7 @@ def send_update_log_report_signal(log_record_pk=None, alert_group_pk=None): ) return - is_on_maintenace_mode = ( - alert_group.channel.maintenance_mode == AlertReceiveChannel.MAINTENANCE - or alert_group.channel.organization.maintenance_mode == AlertReceiveChannel.MAINTENANCE - ) - if is_on_maintenace_mode: + if alert_group.channel.maintenance_mode == AlertReceiveChannel.MAINTENANCE: task_logger.debug( f'send_update_log_report_signal: alert_group={alert_group_pk} msg="skip alert_group_update_log_report_signal due to maintenace"' ) diff --git a/engine/apps/alerts/tests/test_maintenance.py b/engine/apps/alerts/tests/test_maintenance.py index 0db353c3..f3f6b57b 100644 --- a/engine/apps/alerts/tests/test_maintenance.py +++ b/engine/apps/alerts/tests/test_maintenance.py @@ -86,40 +86,6 @@ def test_maintenance_integration_will_not_start_twice( assert alert_receive_channel.maintenance_author == user -@pytest.mark.django_db -def test_start_maintenance_team(maintenance_test_setup, mock_start_disable_maintenance_task): - organization, user = maintenance_test_setup - - mode = AlertReceiveChannel.MAINTENANCE - duration = AlertReceiveChannel.DURATION_ONE_HOUR.seconds - - organization.start_maintenance(mode, duration, user) - - assert organization.maintenance_mode == mode - assert organization.maintenance_duration == AlertReceiveChannel.DURATION_ONE_HOUR - assert organization.maintenance_uuid is not None - assert organization.maintenance_started_at is not None - assert organization.maintenance_author == user - - -@pytest.mark.django_db -def test_maintenance_team_will_not_start_twice(maintenance_test_setup, mock_start_disable_maintenance_task): - organization, user = maintenance_test_setup - - mode = AlertReceiveChannel.MAINTENANCE - duration = AlertReceiveChannel.DURATION_ONE_HOUR.seconds - - organization.start_maintenance(mode, duration, user) - with pytest.raises(MaintenanceCouldNotBeStartedError): - organization.start_maintenance(mode, duration, user) - - assert organization.maintenance_mode == mode - assert organization.maintenance_duration == AlertReceiveChannel.DURATION_ONE_HOUR - assert organization.maintenance_uuid is not None - assert organization.maintenance_started_at is not None - assert organization.maintenance_author == user - - @pytest.mark.django_db def test_alert_attached_to_maintenance_incident_integration( maintenance_test_setup, @@ -151,38 +117,6 @@ def test_alert_attached_to_maintenance_incident_integration( assert alert.group.root_alert_group == maintenance_incident -@pytest.mark.django_db -def test_alert_attached_to_maintenance_incident_team( - maintenance_test_setup, - make_alert_receive_channel, - make_alert_with_custom_create_method, - mock_start_disable_maintenance_task, -): - organization, user = maintenance_test_setup - - alert_receive_channel = make_alert_receive_channel( - organization, integration=AlertReceiveChannel.INTEGRATION_GRAFANA - ) - - mode = AlertReceiveChannel.MAINTENANCE - duration = AlertReceiveChannel.DURATION_ONE_HOUR.seconds - - organization.start_maintenance(mode, duration, user) - maintenance_incident = AlertGroup.all_objects.get(maintenance_uuid=organization.maintenance_uuid) - - alert = make_alert_with_custom_create_method( - title="test_title", - message="test_message", - image_url="test_img_url", - link_to_upstream_details=None, - alert_receive_channel=alert_receive_channel, - raw_request_data={"message": "test"}, - integration_unique_data={}, - ) - - assert alert.group.root_alert_group == maintenance_incident - - @pytest.mark.django_db(transaction=True) def test_stop_maintenance( maintenance_test_setup, @@ -214,9 +148,3 @@ def test_stop_maintenance( alert.refresh_from_db() assert maintenance_incident.resolved_by == AlertGroup.DISABLE_MAINTENANCE assert alert.group.resolved_by == AlertGroup.DISABLE_MAINTENANCE - - assert organization.maintenance_mode is None - assert organization.maintenance_duration is None - assert organization.maintenance_uuid is None - assert organization.maintenance_started_at is None - assert organization.maintenance_author is None diff --git a/engine/apps/api/serializers/organization.py b/engine/apps/api/serializers/organization.py index da345d62..67c8e34b 100644 --- a/engine/apps/api/serializers/organization.py +++ b/engine/apps/api/serializers/organization.py @@ -21,7 +21,6 @@ class OrganizationSerializer(EagerLoadingMixin, serializers.ModelSerializer): slack_team_identity = FastSlackTeamIdentitySerializer(read_only=True) name = serializers.CharField(required=False, allow_null=True, allow_blank=True, source="org_title") - maintenance_till = serializers.ReadOnlyField(source="till_maintenance_timestamp") slack_channel = serializers.SerializerMethodField() SELECT_RELATED = ["slack_team_identity"] @@ -32,14 +31,10 @@ class OrganizationSerializer(EagerLoadingMixin, serializers.ModelSerializer): "pk", "name", "slack_team_identity", - "maintenance_mode", - "maintenance_till", "slack_channel", ] read_only_fields = [ "slack_team_identity", - "maintenance_mode", - "maintenance_till", ] def get_slack_channel(self, obj): diff --git a/engine/apps/api/tests/test_escalation_policy.py b/engine/apps/api/tests/test_escalation_policy.py index c435dc99..5f4464b2 100644 --- a/engine/apps/api/tests/test_escalation_policy.py +++ b/engine/apps/api/tests/test_escalation_policy.py @@ -96,7 +96,9 @@ def test_update_notify_multiple_users_step(escalation_policy_internal_api_setup, assert response.status_code == status.HTTP_200_OK assert response.json()["step"] == EscalationPolicy.STEP_NOTIFY_MULTIPLE_USERS - assert response.json()["notify_to_users_queue"] == [first_user.public_primary_key, second_user.public_primary_key] + assert sorted(response.json()["notify_to_users_queue"]) == sorted( + [first_user.public_primary_key, second_user.public_primary_key] + ) @pytest.mark.django_db diff --git a/engine/apps/api/tests/test_maintenance.py b/engine/apps/api/tests/test_maintenance.py deleted file mode 100644 index 1371608b..00000000 --- a/engine/apps/api/tests/test_maintenance.py +++ /dev/null @@ -1,272 +0,0 @@ -import pytest -from django.urls import reverse -from rest_framework import status -from rest_framework.test import APIClient - -from apps.alerts.models import AlertReceiveChannel -from apps.user_management.models import Organization - -# TODO: should probably modify these tests to take into account new rbac permissions - - -@pytest.fixture() -def maintenance_internal_api_setup( - make_organization_and_user_with_plugin_token, - make_escalation_chain, - make_alert_receive_channel, -): - organization, user, token = make_organization_and_user_with_plugin_token() - make_escalation_chain(organization) - alert_receive_channel = make_alert_receive_channel(organization) - return token, organization, user, alert_receive_channel - - -@pytest.mark.django_db -def test_start_maintenance_integration( - maintenance_internal_api_setup, mock_start_disable_maintenance_task, make_user_auth_headers -): - token, _, user, alert_receive_channel = maintenance_internal_api_setup - client = APIClient() - - url = reverse("api-internal:start_maintenance") - data = { - "mode": AlertReceiveChannel.MAINTENANCE, - "duration": AlertReceiveChannel.DURATION_ONE_HOUR.total_seconds(), - "type": "alert_receive_channel", - "alert_receive_channel_id": alert_receive_channel.public_primary_key, - } - response = client.post(url, data=data, format="json", **make_user_auth_headers(user, token)) - - alert_receive_channel.refresh_from_db() - assert response.status_code == status.HTTP_200_OK - assert alert_receive_channel.maintenance_mode == AlertReceiveChannel.MAINTENANCE - assert alert_receive_channel.maintenance_duration == AlertReceiveChannel.DURATION_ONE_HOUR - assert alert_receive_channel.maintenance_uuid is not None - assert alert_receive_channel.maintenance_started_at is not None - assert alert_receive_channel.maintenance_author is not None - - -@pytest.mark.django_db -def test_start_maintenance_integration_user_team( - maintenance_internal_api_setup, mock_start_disable_maintenance_task, make_user_auth_headers, make_team -): - token, organization, user, alert_receive_channel = maintenance_internal_api_setup - another_team = make_team(organization) - user.current_team = another_team - user.save() - - client = APIClient() - - url = reverse("api-internal:start_maintenance") - data = { - "mode": AlertReceiveChannel.MAINTENANCE, - "duration": AlertReceiveChannel.DURATION_ONE_HOUR.total_seconds(), - "type": "alert_receive_channel", - "alert_receive_channel_id": alert_receive_channel.public_primary_key, - } - response = client.post(url, data=data, format="json", **make_user_auth_headers(user, token)) - - alert_receive_channel.refresh_from_db() - assert response.status_code == status.HTTP_200_OK - assert alert_receive_channel.maintenance_mode == AlertReceiveChannel.MAINTENANCE - assert alert_receive_channel.maintenance_duration == AlertReceiveChannel.DURATION_ONE_HOUR - assert alert_receive_channel.maintenance_uuid is not None - assert alert_receive_channel.maintenance_started_at is not None - assert alert_receive_channel.maintenance_author is not None - - -@pytest.mark.django_db -def test_start_maintenance_integration_different_team( - maintenance_internal_api_setup, mock_start_disable_maintenance_task, make_user_auth_headers, make_team -): - token, organization, user, alert_receive_channel = maintenance_internal_api_setup - another_team = make_team(organization) - other_team = make_team(organization) - user.current_team = another_team - user.save() - # integration belongs to non-general team, != user current team - alert_receive_channel.team = other_team - alert_receive_channel.save() - - client = APIClient() - - url = reverse("api-internal:start_maintenance") - data = { - "mode": AlertReceiveChannel.MAINTENANCE, - "duration": AlertReceiveChannel.DURATION_ONE_HOUR.total_seconds(), - "type": "alert_receive_channel", - "alert_receive_channel_id": alert_receive_channel.public_primary_key, - } - response = client.post(url, data=data, format="json", **make_user_auth_headers(user, token)) - assert response.status_code == status.HTTP_400_BAD_REQUEST - - alert_receive_channel.refresh_from_db() - assert alert_receive_channel.maintenance_mode is None - - -@pytest.mark.django_db -def test_stop_maintenance_integration( - maintenance_internal_api_setup, - mock_start_disable_maintenance_task, - make_user_auth_headers, -): - token, _, user, alert_receive_channel = maintenance_internal_api_setup - client = APIClient() - mode = AlertReceiveChannel.MAINTENANCE - duration = AlertReceiveChannel.DURATION_ONE_HOUR.seconds - alert_receive_channel.start_maintenance(mode, duration, user) - url = reverse("api-internal:stop_maintenance") - data = { - "type": "alert_receive_channel", - "alert_receive_channel_id": alert_receive_channel.public_primary_key, - } - response = client.post(url, data=data, format="json", **make_user_auth_headers(user, token)) - alert_receive_channel.refresh_from_db() - assert response.status_code == status.HTTP_200_OK - assert alert_receive_channel.maintenance_mode is None - assert alert_receive_channel.maintenance_duration is None - assert alert_receive_channel.maintenance_uuid is None - assert alert_receive_channel.maintenance_started_at is None - assert alert_receive_channel.maintenance_author is None - - -@pytest.mark.django_db -def test_start_maintenance_organization( - maintenance_internal_api_setup, - mock_start_disable_maintenance_task, - make_user_auth_headers, -): - token, organization, user, _ = maintenance_internal_api_setup - client = APIClient() - - url = reverse("api-internal:start_maintenance") - data = { - "mode": Organization.MAINTENANCE, - "duration": Organization.DURATION_ONE_HOUR.total_seconds(), - "type": "organization", - } - response = client.post(url, data=data, format="json", **make_user_auth_headers(user, token)) - - organization.refresh_from_db() - assert response.status_code == status.HTTP_200_OK - assert organization.maintenance_mode == Organization.MAINTENANCE - assert organization.maintenance_duration == Organization.DURATION_ONE_HOUR - assert organization.maintenance_uuid is not None - assert organization.maintenance_started_at is not None - assert organization.maintenance_author is not None - - -@pytest.mark.django_db -def test_stop_maintenance_team( - maintenance_internal_api_setup, - mock_start_disable_maintenance_task, - make_user_auth_headers, -): - token, organization, user, _ = maintenance_internal_api_setup - client = APIClient() - mode = Organization.MAINTENANCE - duration = AlertReceiveChannel.DURATION_ONE_HOUR.seconds - organization.start_maintenance(mode, duration, user) - url = reverse("api-internal:stop_maintenance") - data = { - "type": "organization", - } - response = client.post(url, data=data, format="json", **make_user_auth_headers(user, token)) - organization.refresh_from_db() - assert response.status_code == status.HTTP_200_OK - assert organization.maintenance_mode is None - assert organization.maintenance_duration is None - assert organization.maintenance_uuid is None - assert organization.maintenance_started_at is None - assert organization.maintenance_author is None - - -@pytest.mark.django_db -def test_maintenances_list( - maintenance_internal_api_setup, - mock_start_disable_maintenance_task, - make_user_auth_headers, -): - token, organization, user, alert_receive_channel = maintenance_internal_api_setup - client = APIClient() - mode = AlertReceiveChannel.MAINTENANCE - duration = AlertReceiveChannel.DURATION_ONE_HOUR.seconds - alert_receive_channel.start_maintenance(mode, duration, user) - organization.start_maintenance(mode, duration, user) - url = reverse("api-internal:maintenance") - response = client.get(url, format="json", **make_user_auth_headers(user, token)) - - expected_payload = [ - { - "organization_id": organization.public_primary_key, - "type": "organization", - "maintenance_mode": 1, - "maintenance_till_timestamp": organization.till_maintenance_timestamp, - "started_at_timestamp": organization.started_at_timestamp, - }, - { - "alert_receive_channel_id": alert_receive_channel.public_primary_key, - "type": "alert_receive_channel", - "maintenance_mode": 1, - "maintenance_till_timestamp": alert_receive_channel.till_maintenance_timestamp, - "started_at_timestamp": alert_receive_channel.started_at_timestamp, - }, - ] - - assert response.status_code == status.HTTP_200_OK - assert response.json() == expected_payload - - -@pytest.mark.django_db -def test_maintenances_list_include_all_user_teams( - maintenance_internal_api_setup, - mock_start_disable_maintenance_task, - make_user_auth_headers, - make_team, -): - token, organization, user, alert_receive_channel = maintenance_internal_api_setup - another_team = make_team(organization) - other_team = make_team(organization) - # setup user teams - user.teams.add(another_team) - user.teams.add(other_team) - user.current_team = other_team - user.save() - # integration belongs to non-general team, != user current team - alert_receive_channel.team = another_team - alert_receive_channel.save() - - client = APIClient() - mode = AlertReceiveChannel.MAINTENANCE - duration = AlertReceiveChannel.DURATION_ONE_HOUR.seconds - alert_receive_channel.start_maintenance(mode, duration, user) - url = reverse("api-internal:maintenance") - response = client.get(url, format="json", **make_user_auth_headers(user, token)) - - expected_payload = [ - { - "alert_receive_channel_id": alert_receive_channel.public_primary_key, - "type": "alert_receive_channel", - "maintenance_mode": 1, - "maintenance_till_timestamp": alert_receive_channel.till_maintenance_timestamp, - "started_at_timestamp": alert_receive_channel.started_at_timestamp, - }, - ] - - assert response.status_code == status.HTTP_200_OK - assert response.json() == expected_payload - - -@pytest.mark.django_db -def test_empty_maintenances_list( - maintenance_internal_api_setup, mock_start_disable_maintenance_task, make_user_auth_headers -): - token, _, user, alert_receive_channel = maintenance_internal_api_setup - client = APIClient() - url = reverse("api-internal:maintenance") - response = client.get(url, format="json", **make_user_auth_headers(user, token)) - - expected_payload = [] - alert_receive_channel.refresh_from_db() - assert response.status_code == status.HTTP_200_OK - assert response.data == expected_payload diff --git a/engine/apps/api/urls.py b/engine/apps/api/urls.py index ffd52356..4c7e67bd 100644 --- a/engine/apps/api/urls.py +++ b/engine/apps/api/urls.py @@ -15,7 +15,6 @@ from .views.features import FeaturesAPIView from .views.gitops import TerraformGitOpsView, TerraformStateView from .views.integration_heartbeat import IntegrationHeartBeatView from .views.live_setting import LiveSettingViewSet -from .views.maintenance import MaintenanceAPIView, MaintenanceStartAPIView, MaintenanceStopAPIView from .views.on_call_shifts import OnCallShiftView from .views.organization import ( CurrentOrganizationView, @@ -84,9 +83,6 @@ urlpatterns = [ ), optional_slash_path("terraform_file", TerraformGitOpsView.as_view(), name="terraform_file"), optional_slash_path("terraform_imports", TerraformStateView.as_view(), name="terraform_imports"), - optional_slash_path("maintenance", MaintenanceAPIView.as_view(), name="maintenance"), - optional_slash_path("start_maintenance", MaintenanceStartAPIView.as_view(), name="start_maintenance"), - optional_slash_path("stop_maintenance", MaintenanceStopAPIView.as_view(), name="stop_maintenance"), optional_slash_path("slack_settings", SlackTeamSettingsAPIView.as_view(), name="slack-settings"), optional_slash_path( "slack_settings/acknowledge_remind_options", diff --git a/engine/apps/api/views/maintenance.py b/engine/apps/api/views/maintenance.py deleted file mode 100644 index 1617b207..00000000 --- a/engine/apps/api/views/maintenance.py +++ /dev/null @@ -1,161 +0,0 @@ -from rest_framework import status -from rest_framework.decorators import action -from rest_framework.permissions import IsAuthenticated -from rest_framework.response import Response -from rest_framework.views import APIView - -from apps.alerts.models import AlertReceiveChannel -from apps.alerts.models.maintainable_object import MaintainableObject -from apps.api.permissions import RBACPermission -from apps.auth_token.auth import PluginAuthentication -from common.api_helpers.exceptions import BadRequest -from common.api_helpers.mixins import TeamFilteringMixin -from common.exceptions import MaintenanceCouldNotBeStartedError - - -class GetObjectMixin: - def get_object(self, request): - organization = request.auth.organization - type = request.data.get("type", None) - - if type == "organization": - instance = organization - elif type == "alert_receive_channel": - pk = request.data.get("alert_receive_channel_id", None) - if pk is not None: - try: - instance = AlertReceiveChannel.objects.get( - public_primary_key=pk, - organization=organization, - ) - if instance.team is not None and instance.team not in self.request.user.teams.all(): - raise BadRequest(detail={"alert_receive_channel_id": ["unknown id"]}) - except AlertReceiveChannel.DoesNotExist: - raise BadRequest(detail={"alert_receive_channel_id": ["unknown id"]}) - else: - raise BadRequest(detail={"alert_receive_channel_id": ["id is required"]}) - else: - raise BadRequest(detail={"type": ["Unknown type"]}) - - return instance - - -class MaintenanceAPIView(APIView, TeamFilteringMixin): - """Deprecated. Maintenance management is now performed on integrations page (alert_receive_channel/ endpoint))""" - - authentication_classes = (PluginAuthentication,) - permission_classes = (IsAuthenticated, RBACPermission) - - rbac_permissions = { - "get": [RBACPermission.Permissions.MAINTENANCE_READ], - "filters": [RBACPermission.Permissions.MAINTENANCE_READ], - } - - def get(self, request): - organization = self.request.auth.organization - - response = [] - integrations_under_maintenance = ( - AlertReceiveChannel.objects.filter( - maintenance_mode__isnull=False, organization=organization, *self.available_teams_lookup_args - ) - .distinct() - .order_by("maintenance_started_at") - ) - - if organization.maintenance_mode is not None: - response.append( - { - "organization_id": organization.public_primary_key, - "type": "organization", - "maintenance_mode": organization.maintenance_mode, - "maintenance_till_timestamp": organization.till_maintenance_timestamp, - "started_at_timestamp": organization.started_at_timestamp, - } - ) - - for i in integrations_under_maintenance: - response.append( - { - "alert_receive_channel_id": i.public_primary_key, - "type": "alert_receive_channel", - "maintenance_mode": i.maintenance_mode, - "maintenance_till_timestamp": i.till_maintenance_timestamp, - "started_at_timestamp": i.started_at_timestamp, - } - ) - - return Response(response, status=200) - - @action(methods=["get"], detail=False) - def filters(self, request): - filter_name = request.query_params.get("search", None) - api_root = "/api/internal/v1/" - - filter_options = [ - { - "name": "team", - "type": "team_select", - "href": api_root + "teams/", - "global": True, - }, - ] - - if filter_name is not None: - filter_options = list(filter(lambda f: filter_name in f["name"], filter_options)) - - return Response(filter_options) - - -class MaintenanceStartAPIView(GetObjectMixin, APIView): - """Deprecated. Maintenance management is now performed on integrations page (alert_receive_channel/ endpoint))""" - - authentication_classes = (PluginAuthentication,) - permission_classes = (IsAuthenticated, RBACPermission) - rbac_permissions = { - "post": [RBACPermission.Permissions.MAINTENANCE_WRITE], - } - - def post(self, request): - mode = request.data.get("mode", None) - duration = request.data.get("duration", None) - try: - mode = int(mode) - except (ValueError, TypeError): - raise BadRequest(detail={"mode": ["Invalid mode"]}) - if mode not in [MaintainableObject.DEBUG_MAINTENANCE, MaintainableObject.MAINTENANCE]: - raise BadRequest(detail={"mode": ["Unknown mode"]}) - try: - duration = int(duration) - except (ValueError, TypeError): - raise BadRequest(detail={"duration": ["Invalid duration"]}) - if duration not in MaintainableObject.maintenance_duration_options_in_seconds(): - raise BadRequest(detail={"mode": ["Unknown duration"]}) - - instance = self.get_object(request) - try: - instance.start_maintenance(mode, duration, request.user) - except MaintenanceCouldNotBeStartedError as e: - if type(instance) == AlertReceiveChannel: - detail = {"alert_receive_channel_id": ["Already on maintenance"]} - else: - detail = str(e) - raise BadRequest(detail=detail) - - return Response(status=status.HTTP_200_OK) - - -class MaintenanceStopAPIView(GetObjectMixin, APIView): - """Deprecated. Maintenance management is now performed on integrations page (alert_receive_channel/ endpoint))""" - - authentication_classes = (PluginAuthentication,) - permission_classes = (IsAuthenticated, RBACPermission) - rbac_permissions = { - "post": [RBACPermission.Permissions.MAINTENANCE_WRITE], - } - - def post(self, request): - instance = self.get_object(request) - user = request.user - instance.force_disable_maintenance(user) - return Response(status=status.HTTP_200_OK) diff --git a/engine/apps/public_api/serializers/organizations.py b/engine/apps/public_api/serializers/organizations.py index 4df06f13..f1e88544 100644 --- a/engine/apps/public_api/serializers/organizations.py +++ b/engine/apps/public_api/serializers/organizations.py @@ -2,17 +2,11 @@ from rest_framework import serializers from apps.user_management.models import Organization -from .maintenance import MaintainableObjectSerializerMixin - -class OrganizationSerializer(serializers.ModelSerializer, MaintainableObjectSerializerMixin): +class OrganizationSerializer(serializers.ModelSerializer): id = serializers.ReadOnlyField(read_only=True, source="public_primary_key") class Meta: model = Organization - fields = MaintainableObjectSerializerMixin.Meta.fields + [ - "id", - ] - read_only_fields = MaintainableObjectSerializerMixin.Meta.fields + [ - "id", - ] + fields = ["id"] + read_only_fields = ["id"] diff --git a/engine/apps/slack/scenarios/distribute_alerts.py b/engine/apps/slack/scenarios/distribute_alerts.py index b07b0598..19f41a18 100644 --- a/engine/apps/slack/scenarios/distribute_alerts.py +++ b/engine/apps/slack/scenarios/distribute_alerts.py @@ -66,12 +66,7 @@ class AlertShootingStep(scenario_step.ScenarioStep): AlertGroup.all_objects.filter(pk=alert.group.pk).update(slack_message_sent=False) raise e - is_on_debug_mode = ( - alert.group.channel.maintenance_mode == AlertReceiveChannel.DEBUG_MAINTENANCE - or alert.group.channel.organization.maintenance_mode == AlertReceiveChannel.DEBUG_MAINTENANCE - ) - - if is_on_debug_mode: + if alert.group.channel.maintenance_mode == AlertReceiveChannel.DEBUG_MAINTENANCE: self._send_debug_mode_notice(alert.group, channel_id) if alert.group.is_maintenance_incident: diff --git a/engine/apps/user_management/models/organization.py b/engine/apps/user_management/models/organization.py index fa2b8b2d..caa19d82 100644 --- a/engine/apps/user_management/models/organization.py +++ b/engine/apps/user_management/models/organization.py @@ -11,8 +11,6 @@ from django.utils import timezone from mirage import fields as mirage_fields from apps.alerts.models import MaintainableObject -from apps.alerts.tasks import disable_maintenance -from apps.slack.utils import post_message_to_channel from apps.user_management.subscription_strategy import FreePublicBetaSubscriptionStrategy from common.insight_log import ChatOpsEvent, ChatOpsTypePlug, write_chatops_insight_log from common.oncall_gateway import create_oncall_connector, delete_oncall_connector, delete_slack_connector @@ -75,6 +73,9 @@ class OrganizationManager(models.Manager): return OrganizationQuerySet(self.model, using=self._db).filter(deleted_at__isnull=True) +# TODO: in a subsequent PR, remove the inheritance from MaintainableObject (plus generate the database migration file) +# this will remove the maintenance related columns that're no longer used on the organization object +# class Organization(models.Model): class Organization(MaintainableObject): auth_tokens: "RelatedManager['ApiAuthToken']" mobile_app_auth_tokens: "RelatedManager['MobileAppAuthToken']" @@ -255,39 +256,6 @@ class Organization(MaintainableObject): token_model = apps.get_model("auth_token", "PluginAuthToken") token_model.objects.filter(organization=self).delete() - """ - Following methods: start_disable_maintenance_task, force_disable_maintenance, get_organization, get_verbal serve for - MaintainableObject. - """ - - def start_disable_maintenance_task(self, countdown): - maintenance_uuid = disable_maintenance.apply_async( - args=(), - kwargs={ - "organization_id": self.pk, - }, - countdown=countdown, - ) - return maintenance_uuid - - def force_disable_maintenance(self, user): - disable_maintenance(organization_id=self.pk, force=True, user_id=user.pk) - - def get_organization(self): - return self - - def get_team(self): - return None - - def get_verbal(self): - return self.org_title - - def notify_about_maintenance_action(self, text, send_to_general_log_channel=True): - # TODO: this method should be refactored. - # It's binded to slack and sending maintenance notification only there. - if send_to_general_log_channel: - post_message_to_channel(self, self.general_log_channel_id, text) - """ Following methods: phone_calls_left, sms_left, emails_left diff --git a/grafana-plugin/integration-tests/integrations/maintenanceMode.test.ts b/grafana-plugin/integration-tests/integrations/maintenanceMode.test.ts new file mode 100644 index 00000000..df73c7cd --- /dev/null +++ b/grafana-plugin/integration-tests/integrations/maintenanceMode.test.ts @@ -0,0 +1,144 @@ +import { test, expect, Page, Locator } from '../fixtures'; +import { verifyThatAlertGroupIsRoutedCorrectlyButNotEscalated } from '../utils/alertGroup'; +import { EscalationStep, createEscalationChain } from '../utils/escalationChain'; +import { clickButton, generateRandomValue, selectDropdownValue } from '../utils/forms'; +import { + assignEscalationChainToIntegration, + createIntegration, + filterIntegrationsTableAndGoToDetailPage, + sendDemoAlert, +} from '../utils/integrations'; +import { goToOnCallPage } from '../utils/navigation'; + +type MaintenanceModeType = 'Debug' | 'Maintenance'; + +test.describe('maintenance mode works', () => { + test.slow(); // this test is doing a good amount of work, give it time + + const MAINTENANCE_DURATION = '1 hour'; + const REMAINING_TIME_TEXT = '59m left'; + const REMAINING_TIME_TOOLTIP_TEST_ID = 'maintenance-mode-remaining-time-tooltip'; + + const createRoutedText = (escalationChainName: string): string => + `alert group assigned to route "default" with escalation chain "${escalationChainName}"`; + + const _openIntegrationSettingsPopup = async (page: Page): Promise => { + const integrationSettingsPopupElement = page.getByTestId('integration-settings-context-menu'); + await integrationSettingsPopupElement.click(); + return integrationSettingsPopupElement; + }; + + const getRemainingTimeTooltip = (page: Page): Locator => page.getByTestId(REMAINING_TIME_TOOLTIP_TEST_ID); + + const enableMaintenanceMode = async (page: Page, mode: MaintenanceModeType): Promise => { + const integrationSettingsPopupElement = await _openIntegrationSettingsPopup(page); + /** + * we need to click twice here, because adding the escalation chain route + * doesn't unfocus out of the select element after selecting an option + */ + await integrationSettingsPopupElement.click(); + + // open the maintenance mode settings drawer + fill in the maintenance details + await page.getByTestId('integration-start-maintenance').click(); + + // fill in the form + const maintenanceModeDrawer = page.getByTestId('maintenance-mode-drawer'); + + await selectDropdownValue({ + page, + startingLocator: maintenanceModeDrawer, + selectType: 'grafanaSelect', + placeholderText: 'Choose mode', + value: mode, + optionExactMatch: false, + }); + + await selectDropdownValue({ + page, + startingLocator: maintenanceModeDrawer, + selectType: 'grafanaSelect', + placeholderText: 'Choose duration', + value: MAINTENANCE_DURATION, + optionExactMatch: false, + }); + + await maintenanceModeDrawer.getByTestId('create-maintenance-button').click(); + + const maintenanceModeRemainingTimeTooltip = getRemainingTimeTooltip(page); + await maintenanceModeRemainingTimeTooltip.waitFor({ state: 'visible' }); + + expect(await page.getByTestId(`${REMAINING_TIME_TOOLTIP_TEST_ID}-text`).innerText()).toContain(REMAINING_TIME_TEXT); + }; + + const disableMaintenanceMode = async (page: Page, integrationName: string): Promise => { + await goToOnCallPage(page, 'integrations'); + + await filterIntegrationsTableAndGoToDetailPage(page, integrationName); + await _openIntegrationSettingsPopup(page); + + // click the stop maintenance button + await page.getByTestId('integration-stop-maintenance').click(); + + // in the modal popup, confirm that we want to stop it + await clickButton({ + page, + buttonText: 'Stop', + startingLocator: page.getByRole('dialog'), + }); + + await getRemainingTimeTooltip(page).waitFor({ state: 'hidden' }); + }; + + const createIntegrationAndEscalationChainAndEnableMaintenanceMode = async ( + page: Page, + userName: string, + maintenanceModeType: MaintenanceModeType + ): Promise<{ + escalationChainName: string; + integrationName: string; + }> => { + const escalationChainName = generateRandomValue(); + const integrationName = generateRandomValue(); + + await createEscalationChain(page, escalationChainName, EscalationStep.NotifyUsers, userName); + await createIntegration(page, integrationName); + await assignEscalationChainToIntegration(page, escalationChainName); + await enableMaintenanceMode(page, maintenanceModeType); + + return { escalationChainName, integrationName }; + }; + + test('debug mode', async ({ adminRolePage: { page, userName } }) => { + const { escalationChainName, integrationName } = await createIntegrationAndEscalationChainAndEnableMaintenanceMode( + page, + userName, + 'Debug' + ); + await sendDemoAlert(page); + await verifyThatAlertGroupIsRoutedCorrectlyButNotEscalated( + page, + integrationName, + createRoutedText(escalationChainName) + ); + + await disableMaintenanceMode(page, integrationName); + }); + + test('"maintenance" mode', async ({ adminRolePage: { page, userName } }) => { + const { integrationName } = await createIntegrationAndEscalationChainAndEnableMaintenanceMode( + page, + userName, + 'Maintenance' + ); + await sendDemoAlert(page); + + // TODO: there seems to be a bug here where "maintenance" mode alert groups don't show up in the UI + // await verifyThatAlertGroupIsRoutedCorrectlyButNotEscalated( + // page, + // integrationName, + // createRoutedText(escalationChainName) + // ); + + await disableMaintenanceMode(page, integrationName); + }); +}); diff --git a/grafana-plugin/integration-tests/utils/alertGroup.ts b/grafana-plugin/integration-tests/utils/alertGroup.ts index 385b3cbd..1a72d941 100644 --- a/grafana-plugin/integration-tests/utils/alertGroup.ts +++ b/grafana-plugin/integration-tests/utils/alertGroup.ts @@ -1,10 +1,15 @@ -import { Page, expect } from '@playwright/test'; +import { Locator, Page, expect } from '@playwright/test'; import { selectDropdownValue, selectValuePickerValue } from './forms'; import { goToOnCallPage } from './navigation'; const MAX_RETRIES = 5; +const ALERT_GROUP_REGISTERED_TEXT = 'alert group registered'; -// const sleep = async (seconds: number) => new Promise((resolve) => setTimeout(resolve, seconds * 1000)); +const getIncidentTimelineList = async (page: Page): Promise => { + const incidentTimelineList = page.getByTestId('incident-timeline-list'); + await incidentTimelineList.waitFor({ state: 'visible' }); + return incidentTimelineList; +}; /** * recursively refreshes the page waiting for the background celery workers to have done their job of @@ -15,18 +20,28 @@ const incidentTimelineContainsStep = async (page: Page, triggeredStepText: strin return Promise.resolve(false); } - if (!page.getByTestId('incident-timeline-list').getByText(triggeredStepText)) { + const incidentTimelineList = await getIncidentTimelineList(page); + + if (!incidentTimelineList.getByText(triggeredStepText)) { await page.reload({ waitUntil: 'networkidle' }); return incidentTimelineContainsStep(page, triggeredStepText, (retryNum += 1)); } return true; }; -export const verifyThatAlertGroupIsTriggered = async ( +/** + * recursively refreshes the page waiting for the background celery workers to have done their job of + * creating the alert group + */ +export const filterAlertGroupsTableByIntegrationAndGoToDetailPage = async ( page: Page, integrationName: string, - triggeredStepText: string + retryNum = 0 ): Promise => { + if (retryNum > MAX_RETRIES) { + throw new Error('we were not able to properly filter the alert groups table by integration'); + } + await goToOnCallPage(page, 'incidents'); // filter by integration @@ -40,10 +55,48 @@ export const verifyThatAlertGroupIsTriggered = async ( await selectValuePickerValue(page, integrationName, false); /** - * wait for the alert groups to be filtered then - * click on the alert group and go to the individual alert group page + * wait for the alert groups to be filtered then by this particular integration (toBeVisible assertion), + * then click on the alert group and go to the individual alert group page */ - await (await page.waitForSelector('table > tbody > tr > td:nth-child(4) a')).click(); + const firstTableRow = page.locator('table > tbody > tr:first-child'); + + try { + /** + * wait for up to 5 seconds for the alert groups to be filtered, if the first row does not correspond + * to `integrationName` assume that the background workers have not created it yet and lets + * recursively retry this function + */ + await firstTableRow.getByText(integrationName).waitFor({ state: 'visible', timeout: 5000 }); + await firstTableRow.locator('td:nth-child(4) a').click(); + } catch (err) { + return filterAlertGroupsTableByIntegrationAndGoToDetailPage(page, integrationName, (retryNum += 1)); + } +}; + +export const verifyThatAlertGroupIsRoutedCorrectlyButNotEscalated = async ( + page: Page, + integrationName: string, + routedText: string +): Promise => { + await filterAlertGroupsTableByIntegrationAndGoToDetailPage(page, integrationName); + + /** + * incidentTimelineContainsStep recursively reloads the alert group page until the engine + * background workers have processed/escalated the alert group + */ + expect(await incidentTimelineContainsStep(page, ALERT_GROUP_REGISTERED_TEXT)).toBe(true); + + const incidentTimelineList = await getIncidentTimelineList(page); + expect(incidentTimelineList).toContainText(routedText); + expect(incidentTimelineList).not.toContainText('triggered step'); +}; + +export const verifyThatAlertGroupIsTriggered = async ( + page: Page, + integrationName: string, + triggeredStepText: string +): Promise => { + await filterAlertGroupsTableByIntegrationAndGoToDetailPage(page, integrationName); expect(await incidentTimelineContainsStep(page, triggeredStepText)).toBe(true); }; diff --git a/grafana-plugin/integration-tests/utils/forms.ts b/grafana-plugin/integration-tests/utils/forms.ts index fb00b9dd..06492210 100644 --- a/grafana-plugin/integration-tests/utils/forms.ts +++ b/grafana-plugin/integration-tests/utils/forms.ts @@ -13,6 +13,10 @@ type SelectDropdownValueArgs = { startingLocator?: Locator; // if true, when selecting the dropdown option, use an exact match, otherwise use a substring contains match optionExactMatch?: boolean; + + // if true, will press enter in the select dropdown. Some dropdowns don't show a list of options + // and instead the user must press enter to trigger the search + pressEnterInsteadOfSelectingOption?: boolean; }; type ClickButtonArgs = { @@ -87,9 +91,16 @@ const chooseDropdownValue = async ({ page, value, optionExactMatch = true }: Sel page.locator(`div[id^="react-select-"][id$="-listbox"] >> ${textMatchSelector(optionExactMatch, value)}`).click(); export const selectDropdownValue = async (args: SelectDropdownValueArgs): Promise => { + const { page, value, pressEnterInsteadOfSelectingOption } = args; + const selectElement = await openSelect(args); - await selectElement.type(args.value); - await chooseDropdownValue(args); + await selectElement.type(value); + + if (pressEnterInsteadOfSelectingOption) { + await page.keyboard.press('Enter'); + } else { + await chooseDropdownValue(args); + } return selectElement; }; diff --git a/grafana-plugin/integration-tests/utils/integrations.ts b/grafana-plugin/integration-tests/utils/integrations.ts index c903f3ad..a8e96a2c 100644 --- a/grafana-plugin/integration-tests/utils/integrations.ts +++ b/grafana-plugin/integration-tests/utils/integrations.ts @@ -1,5 +1,5 @@ import { Page } from '@playwright/test'; -import { clickButton } from './forms'; +import { clickButton, selectDropdownValue } from './forms'; import { goToOnCallPage } from './navigation'; const CREATE_INTEGRATION_MODAL_TEST_ID_SELECTOR = 'div[data-testid="create-integration-modal"]'; @@ -15,11 +15,7 @@ export const openCreateIntegrationModal = async (page: Page): Promise => { await page.waitForSelector(CREATE_INTEGRATION_MODAL_TEST_ID_SELECTOR); }; -export const createIntegrationAndSendDemoAlert = async ( - page: Page, - integrationName: string, - _escalationChainName: string -): Promise => { +export const createIntegration = async (page: Page, integrationName: string): Promise => { await openCreateIntegrationModal(page); // create a webhook integration @@ -27,25 +23,56 @@ export const createIntegrationAndSendDemoAlert = async ( // fill in the required inputs (await page.waitForSelector('input[name="verbal_name"]', { state: 'attached' })).fill(integrationName); - (await page.waitForSelector('textarea[name="description_short"]', { state: 'attached' })).fill("Here goes your integration description"); + (await page.waitForSelector('textarea[name="description_short"]', { state: 'attached' })).fill( + 'Here goes your integration description' + ); - const grafanaUpdateBtn = page.getByTestId("update-integration-button"); + const grafanaUpdateBtn = page.getByTestId('update-integration-button'); await grafanaUpdateBtn.click(); - - /* - * TODO: This is slightly more complicated now, change this in next iteration */ - // const integrationSettingsElement = page.getByTestId('integration-settings'); - - // // assign the escalation chain to the integration - // await selectDropdownValue({ - // page, - // selectType: 'grafanaSelect', - // placeholderText: 'Select Escalation Chain', - // value: escalationChainName, - // startingLocator: integrationSettingsElement, - // }); - - // send demo alert - await clickButton({ page, buttonText: 'Send demo alert', dataTestId: 'send-demo-alert' }); - await clickButton({ page, buttonText: 'Send Alert', dataTestId: "submit-send-alert" }) +}; + +export const assignEscalationChainToIntegration = async (page: Page, escalationChainName: string): Promise => { + await page.getByTestId('integration-escalation-chain-not-selected').click(); + + // assign the escalation chain to the integration + await selectDropdownValue({ + page, + selectType: 'grafanaSelect', + placeholderText: 'Select Escalation Chain', + value: escalationChainName, + startingLocator: page.getByTestId('integration-block-item'), + }); +}; + +export const sendDemoAlert = async (page: Page): Promise => { + await clickButton({ page, buttonText: 'Send demo alert', dataTestId: 'send-demo-alert' }); + await clickButton({ page, buttonText: 'Send Alert', dataTestId: 'submit-send-alert' }); + await page.getByTestId('demo-alert-sent-notification').waitFor({ state: 'visible' }); +}; + +export const createIntegrationAndSendDemoAlert = async ( + page: Page, + integrationName: string, + escalationChainName: string +): Promise => { + await createIntegration(page, integrationName); + await assignEscalationChainToIntegration(page, escalationChainName); + await sendDemoAlert(page); +}; + +export const filterIntegrationsTableAndGoToDetailPage = async (page: Page, integrationName: string): Promise => { + // filter the integrations page by the integration in question, then go to its detail page + await selectDropdownValue({ + page, + selectType: 'grafanaSelect', + placeholderText: 'Search or filter results...', + value: integrationName, + pressEnterInsteadOfSelectingOption: true, + }); + + await ( + await page.waitForSelector( + `div[data-testid="integrations-table"] table > tbody > tr > td:first-child a >> text=${integrationName}` + ) + ).click(); }; diff --git a/grafana-plugin/playwright.config.ts b/grafana-plugin/playwright.config.ts index 424a03e3..aa5657dc 100644 --- a/grafana-plugin/playwright.config.ts +++ b/grafana-plugin/playwright.config.ts @@ -18,6 +18,10 @@ export const ADMIN_USER_STORAGE_STATE = path.join(__dirname, 'integration-tests/ */ const config: PlaywrightTestConfig = { testDir: './integration-tests', + + /* Maximum time all the tests can run for. */ + globalTimeout: 20 * 60 * 1000, // 20 minutes + /* Maximum time one test can run for. */ timeout: 60 * 1000, expect: { diff --git a/grafana-plugin/src/components/Integrations/IntegrationBlockItem.tsx b/grafana-plugin/src/components/Integrations/IntegrationBlockItem.tsx index 384a3016..18503e43 100644 --- a/grafana-plugin/src/components/Integrations/IntegrationBlockItem.tsx +++ b/grafana-plugin/src/components/Integrations/IntegrationBlockItem.tsx @@ -12,7 +12,7 @@ interface IntegrationBlockItemProps { const IntegrationBlockItem: React.FC = (props) => { return ( -
        +
        {props.children}
        diff --git a/grafana-plugin/src/components/TooltipBadge/TooltipBadge.tsx b/grafana-plugin/src/components/TooltipBadge/TooltipBadge.tsx index cdbef993..b3eb8e72 100644 --- a/grafana-plugin/src/components/TooltipBadge/TooltipBadge.tsx +++ b/grafana-plugin/src/components/TooltipBadge/TooltipBadge.tsx @@ -24,7 +24,10 @@ interface TooltipBadgeProps { const cx = cn.bind(styles); const TooltipBadge: FC = (props) => { - const { borderType, text, tooltipTitle, tooltipContent, onHover, addPadding, icon, customIcon, className } = props; + const { borderType, text, tooltipTitle, tooltipContent, onHover, addPadding, icon, customIcon, className, ...rest } = + props; + + const testId = rest['data-testid']; return ( = (props) => { className )} onMouseEnter={onHover} + {...(testId ? { 'data-testid': testId } : {})} > {renderIcon()} - {text && {text}} + {text && ( + + {text} + + )}
        diff --git a/grafana-plugin/src/components/WithContextMenu/WithContextMenu.tsx b/grafana-plugin/src/components/WithContextMenu/WithContextMenu.tsx index a3847476..a5fe4ab2 100644 --- a/grafana-plugin/src/components/WithContextMenu/WithContextMenu.tsx +++ b/grafana-plugin/src/components/WithContextMenu/WithContextMenu.tsx @@ -16,6 +16,7 @@ export const WithContextMenu: React.FC = ({ renderMenuItems, forceIsOpen = false, focusOnOpen = true, + ...rest }) => { const [isMenuOpen, setIsMenuOpen] = useState(false || forceIsOpen); const [menuPosition, setMenuPosition] = useState({ x: 0, y: 0 }); @@ -36,7 +37,7 @@ export const WithContextMenu: React.FC = ({ }, []); return ( - <> +
        {children({ openMenu: (e) => { setIsMenuOpen(true); @@ -56,6 +57,6 @@ export const WithContextMenu: React.FC = ({ focusOnOpen={focusOnOpen} /> )} - +
        ); }; diff --git a/grafana-plugin/src/containers/IntegrationContainers/CollapsedIntegrationRouteDisplay/CollapsedIntegrationRouteDisplay.tsx b/grafana-plugin/src/containers/IntegrationContainers/CollapsedIntegrationRouteDisplay/CollapsedIntegrationRouteDisplay.tsx index 9062d98b..6c4bb66b 100644 --- a/grafana-plugin/src/containers/IntegrationContainers/CollapsedIntegrationRouteDisplay/CollapsedIntegrationRouteDisplay.tsx +++ b/grafana-plugin/src/containers/IntegrationContainers/CollapsedIntegrationRouteDisplay/CollapsedIntegrationRouteDisplay.tsx @@ -145,7 +145,9 @@ const CollapsedIntegrationRouteDisplay: React.FC
        - Not selected + + Not selected +
        )}
    diff --git a/grafana-plugin/src/containers/MaintenanceForm/MaintenanceForm.config.tsx b/grafana-plugin/src/containers/MaintenanceForm/MaintenanceForm.config.tsx index 2e6c8ccd..60a1729f 100644 --- a/grafana-plugin/src/containers/MaintenanceForm/MaintenanceForm.config.tsx +++ b/grafana-plugin/src/containers/MaintenanceForm/MaintenanceForm.config.tsx @@ -4,7 +4,7 @@ import { SelectableValue } from '@grafana/data'; import Emoji from 'react-emoji-render'; import { FormItem, FormItemType } from 'components/GForm/GForm.types'; -import { MaintenanceMode } from 'models/maintenance/maintenance.types'; +import { MaintenanceMode } from 'models/alert_receive_channel/alert_receive_channel.types'; export const form: { name: string; fields: FormItem[] } = { name: 'Maintenance', @@ -31,6 +31,7 @@ export const form: { name: string; fields: FormItem[] } = { validation: { required: true }, normalize: (value) => value, extra: { + placeholder: 'Choose mode', options: [ { value: MaintenanceMode.Debug, @@ -50,6 +51,7 @@ export const form: { name: string; fields: FormItem[] } = { type: FormItemType.Select, validation: { required: true }, extra: { + placeholder: 'Choose duration', options: [ { value: 3600, diff --git a/grafana-plugin/src/containers/MaintenanceForm/MaintenanceForm.tsx b/grafana-plugin/src/containers/MaintenanceForm/MaintenanceForm.tsx index 78f7362f..33814c75 100644 --- a/grafana-plugin/src/containers/MaintenanceForm/MaintenanceForm.tsx +++ b/grafana-plugin/src/containers/MaintenanceForm/MaintenanceForm.tsx @@ -8,7 +8,6 @@ import { observer } from 'mobx-react'; import GForm from 'components/GForm/GForm'; import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip'; import { AlertReceiveChannel } from 'models/alert_receive_channel/alert_receive_channel.types'; -import { MaintenanceType } from 'models/maintenance/maintenance.types'; import { useStore } from 'state/useStore'; import { openNotification, showApiError } from 'utils'; import { UserActions } from 'utils/authorization'; @@ -21,7 +20,6 @@ const cx = cn.bind(styles); interface MaintenanceFormProps { initialData: { - type?: MaintenanceType; alert_receive_channel_id?: AlertReceiveChannel['id']; disabled?: boolean; }; @@ -35,23 +33,22 @@ const MaintenanceForm = observer((props: MaintenanceFormProps) => { const store = useStore(); - const { maintenanceStore } = store; + const { alertReceiveChannelStore } = store; - const handleSubmit = useCallback((data) => { - maintenanceStore - .startMaintenanceMode( - MaintenanceType.alert_receive_channel, + const handleSubmit = useCallback(async (data) => { + try { + await alertReceiveChannelStore.startMaintenanceMode( + initialData.alert_receive_channel_id, data.mode, - data.duration, - data.alert_receive_channel_id - ) - .then(() => { - onHide(); - onUpdate(); + data.duration + ); - openNotification('Maintenance has been started'); - }) - .catch(showApiError); + onHide(); + onUpdate(); + openNotification('Maintenance has been started'); + } catch (err) { + showApiError(err); + } }, []); if (initialData.disabled) { @@ -65,7 +62,7 @@ const MaintenanceForm = observer((props: MaintenanceFormProps) => { return ( -
    +
    Start maintenance mode when performing scheduled maintenance or updates on the infrastructure, which may trigger false alarms. @@ -75,7 +72,7 @@ const MaintenanceForm = observer((props: MaintenanceFormProps) => { Cancel - diff --git a/grafana-plugin/src/models/alert_receive_channel/alert_receive_channel.ts b/grafana-plugin/src/models/alert_receive_channel/alert_receive_channel.ts index 51769285..fb81d578 100644 --- a/grafana-plugin/src/models/alert_receive_channel/alert_receive_channel.ts +++ b/grafana-plugin/src/models/alert_receive_channel/alert_receive_channel.ts @@ -20,6 +20,7 @@ import { AlertReceiveChannel, AlertReceiveChannelOption, AlertReceiveChannelCounters, + MaintenanceMode, } from './alert_receive_channel.types'; export class AlertReceiveChannelStore extends BaseStore { @@ -456,4 +457,18 @@ export class AlertReceiveChannelStore extends BaseStore { this.counters = counters; } + + startMaintenanceMode = (id: AlertReceiveChannel['id'], mode: MaintenanceMode, duration: number): Promise => + makeRequest(`${this.path}${id}/start_maintenance/`, { + method: 'POST', + data: { + mode, + duration, + }, + }); + + stopMaintenanceMode = (id: AlertReceiveChannel['id']) => + makeRequest(`${this.path}${id}/stop_maintenance/`, { + method: 'POST', + }); } diff --git a/grafana-plugin/src/models/maintenance/maintenance.ts b/grafana-plugin/src/models/maintenance/maintenance.ts deleted file mode 100644 index 2a56b4ba..00000000 --- a/grafana-plugin/src/models/maintenance/maintenance.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { action, observable } from 'mobx'; - -import { AlertReceiveChannel } from 'models/alert_receive_channel/alert_receive_channel.types'; -import BaseStore from 'models/base_store'; -import { makeRequest } from 'network'; -import { RootStore } from 'state'; - -import { Maintenance, MaintenanceMode, MaintenanceType } from './maintenance.types'; - -export class MaintenanceStore extends BaseStore { - @observable.shallow - maintenances?: Maintenance[]; - - constructor(rootStore: RootStore) { - super(rootStore); - - this.path = '/maintenance/'; - } - - @action - async updateMaintenances() { - this.maintenances = await this.getAll(); - } - - @action - async startMaintenanceMode( - type: MaintenanceType, - mode: MaintenanceMode, - duration: number, - alertReceiveChannelId?: AlertReceiveChannel['id'] - ) { - return await makeRequest(`/start_maintenance/`, { - method: 'POST', - data: { - type, - mode, - duration, - alert_receive_channel_id: alertReceiveChannelId, - }, - withCredentials: true, - }); - } - - @action - async stopMaintenanceMode(type: MaintenanceType, alertReceiveChannelId: AlertReceiveChannel['id']) { - return await makeRequest(`/stop_maintenance/`, { - method: 'POST', - data: { - type, - alert_receive_channel_id: alertReceiveChannelId, - }, - withCredentials: true, - }); - } -} diff --git a/grafana-plugin/src/models/maintenance/maintenance.types.ts b/grafana-plugin/src/models/maintenance/maintenance.types.ts deleted file mode 100644 index a57c6727..00000000 --- a/grafana-plugin/src/models/maintenance/maintenance.types.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { AlertReceiveChannel } from 'models/alert_receive_channel/alert_receive_channel.types'; - -export enum MaintenanceType { - alert_receive_channel = 'alert_receive_channel', - organization = 'organization', -} - -export enum MaintenanceMode { - Debug, - Maintenance, -} - -export interface Maintenance { - alert_receive_channel_id: AlertReceiveChannel['id']; - type: MaintenanceType; - maintenance_mode: MaintenanceMode; - maintenance_till_timestamp: number; - started_at_timestamp: number; -} diff --git a/grafana-plugin/src/pages/integration/Integration.tsx b/grafana-plugin/src/pages/integration/Integration.tsx index 0bd83838..a8f178a6 100644 --- a/grafana-plugin/src/pages/integration/Integration.tsx +++ b/grafana-plugin/src/pages/integration/Integration.tsx @@ -58,7 +58,6 @@ import { } from 'models/alert_receive_channel/alert_receive_channel.types'; import { AlertTemplatesDTO } from 'models/alert_templates'; import { ChannelFilter } from 'models/channel_filter'; -import { MaintenanceType } from 'models/maintenance/maintenance.types'; import { INTEGRATION_TEMPLATES_LIST } from 'pages/integration/Integration.config'; import IntegrationHelper from 'pages/integration/Integration.helper'; import styles from 'pages/integration/Integration.module.scss'; @@ -606,7 +605,7 @@ class Integration extends React.Component { const DemoNotification: React.FC = () => { return ( -
    +
    Demo alert was generated. Find it on the "Alert Groups" page and make sure it didn't freak out your colleagues 😉 @@ -727,7 +726,7 @@ const IntegrationActions: React.FC = ({ alertReceiveChannel, changeIsTemplateSettingsOpen, }) => { - const { maintenanceStore, alertReceiveChannelStore, heartbeatStore } = useStore(); + const { alertReceiveChannelStore, heartbeatStore } = useStore(); const history = useHistory(); @@ -815,6 +814,7 @@ const IntegrationActions: React.FC = ({ (
    openIntegrationSettings()}> @@ -831,7 +831,11 @@ const IntegrationActions: React.FC = ({ {!alertReceiveChannel.maintenance_till && ( -
    +
    Start Maintenance
    @@ -862,6 +866,7 @@ const IntegrationActions: React.FC = ({ ), }); }} + data-testid="integration-stop-maintenance" > Stop Maintenance
    @@ -941,14 +946,13 @@ const IntegrationActions: React.FC = ({ setMaintenanceData({ disabled: true, alert_receive_channel_id: alertReceiveChannel.id }); } - function onStopMaintenance() { + async function onStopMaintenance() { setConfirmModal(undefined); - maintenanceStore - .stopMaintenanceMode(MaintenanceType.alert_receive_channel, id) - .then(() => maintenanceStore.updateMaintenances()) - .then(() => openNotification('Maintenance has been stopped')) - .then(() => alertReceiveChannelStore.updateItem(alertReceiveChannel.id)); + await alertReceiveChannelStore.stopMaintenanceMode(id); + + openNotification('Maintenance has been stopped'); + await alertReceiveChannelStore.updateItem(id); } }; @@ -1063,6 +1067,7 @@ const IntegrationHeader: React.FC = ({ {alertReceiveChannel.maintenance_till && ( /> { key: T; value: string; @@ -23,7 +25,7 @@ export const getTzOffsetHours = (): number => { }; export function showApiError(error: any) { - if (error.response.status >= 400 && error.response.status < 500) { + if (isNetworkError(error) && error.response && error.response.status >= 400 && error.response.status < 500) { const payload = error.response.data; const text = typeof payload === 'string' @@ -38,7 +40,7 @@ export function showApiError(error: any) { } export function refreshPageError(error: AxiosError) { - if (error.response?.status === 502) { + if (isNetworkError(error) && error.response?.status === 502) { const payload = error.response.data; const text = `Try to refresh the page. ${payload}`; openErrorNotification(text); @@ -48,7 +50,7 @@ export function refreshPageError(error: AxiosError) { } export function throttlingError(error: AxiosError) { - if (error.response?.status === 429) { + if (isNetworkError(error) && error.response?.status === 429) { const seconds = Number(error.response?.headers['retry-after']); const minutes = Math.floor(seconds / 60); const text = From 0b28815d469e48c7cf57f48723a55fe18a80433b Mon Sep 17 00:00:00 2001 From: Ildar Iskhakov Date: Thu, 13 Jul 2023 13:41:31 +0800 Subject: [PATCH 07/11] Unhide direct paging integration (#2483) # What this PR does Fixes https://github.com/grafana/oncall/issues/2442 https://github.com/grafana/oncall/assets/2262529/08bb8e5f-acc6-4f2d-9e38-717c9f37e3da ## Which issue(s) this PR fixes ## Checklist - [ ] Unit, integration, and e2e (if applicable) tests updated - [ ] Documentation added (or `pr:no public docs` PR label added if not required) - [ ] `CHANGELOG.md` updated (or `pr:no changelog` PR label added if not required) --- CHANGELOG.md | 1 + engine/apps/alerts/paging.py | 4 +- engine/apps/alerts/tests/test_paging.py | 14 - .../api/serializers/alert_receive_channel.py | 19 +- engine/apps/api/serializers/paging.py | 5 - engine/apps/api/tests/test_alert_group.py | 24 +- .../api/tests/test_alert_receive_channel.py | 17 -- .../apps/api/views/alert_receive_channel.py | 42 ++- .../public_api/tests/test_integrations.py | 19 -- engine/apps/public_api/views/integrations.py | 3 - engine/config_integrations/direct_paging.py | 2 +- .../ManualAlertGroup.config.ts | 14 - .../ManualAlertGroup.module.css | 20 ++ .../ManualAlertGroup/ManualAlertGroup.tsx | 240 +++++++++++++++--- .../CreateAlertReceiveChannelContainer.tsx | 2 +- .../EscalationVariants/EscalationVariants.tsx | 11 +- .../GrafanaTeamSelect/GrafanaTeamSelect.tsx | 5 +- .../IntegrationForm/IntegrationForm.tsx | 8 +- .../src/pages/incidents/Incidents.tsx | 5 +- .../src/pages/integration/Integration.tsx | 84 ++++-- 20 files changed, 353 insertions(+), 186 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 53d9bc95..f5602d1a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add debounce on Select UI components to avoid making API search requests on each key-down event by @maskin25 ([#2466](https://github.com/grafana/oncall/pull/2466)) +- Make Direct paging integration configurable ([2483](https://github.com/grafana/oncall/pull/2483)) ## v1.3.8 (2023-07-11) diff --git a/engine/apps/alerts/paging.py b/engine/apps/alerts/paging.py index 53a92ba9..d17f6f03 100644 --- a/engine/apps/alerts/paging.py +++ b/engine/apps/alerts/paging.py @@ -42,7 +42,7 @@ def _trigger_alert( deleted_at=None, defaults={ "author": from_user, - "verbal_name": f"Direct paging ({team.name if team else 'General'} team)", + "verbal_name": "Direct paging", }, ) if alert_receive_channel.default_channel_filter is None: @@ -149,8 +149,6 @@ def direct_paging( Otherwise, create a new alert using given title and message. """ - if not users and not schedules and not escalation_chain: - return if users is None: users = [] diff --git a/engine/apps/alerts/tests/test_paging.py b/engine/apps/alerts/tests/test_paging.py index 5d3c79b0..daa73a6a 100644 --- a/engine/apps/alerts/tests/test_paging.py +++ b/engine/apps/alerts/tests/test_paging.py @@ -154,20 +154,6 @@ def test_check_user_availability_on_call( assert warnings == [] -@pytest.mark.django_db -def test_direct_paging_no_one(make_organization, make_user_for_organization): - organization = make_organization() - from_user = make_user_for_organization(organization) - - with patch("apps.alerts.paging.notify_user_task") as notify_task: - direct_paging(organization, None, from_user) - - # no alert group - assert AlertGroup.all_objects.count() == 0 - # no notifications - assert not notify_task.apply_async.called - - @pytest.mark.django_db def test_direct_paging_user(make_organization, make_user_for_organization): organization = make_organization() diff --git a/engine/apps/api/serializers/alert_receive_channel.py b/engine/apps/api/serializers/alert_receive_channel.py index 7e60e943..2cea5a96 100644 --- a/engine/apps/api/serializers/alert_receive_channel.py +++ b/engine/apps/api/serializers/alert_receive_channel.py @@ -117,8 +117,15 @@ class AlertReceiveChannelSerializer(EagerLoadingMixin, serializers.ModelSerializ connection_error = GrafanaAlertingSyncManager.check_for_connection_errors(organization) if connection_error: raise BadRequest(detail=connection_error) + for _integration in AlertReceiveChannel._config: + if _integration.slug == integration: + is_able_to_autoresolve = _integration.is_able_to_autoresolve + instance = AlertReceiveChannel.create( - **validated_data, organization=organization, author=self.context["request"].user + **validated_data, + organization=organization, + author=self.context["request"].user, + allow_source_based_resolving=is_able_to_autoresolve, ) return instance @@ -172,8 +179,11 @@ class AlertReceiveChannelSerializer(EagerLoadingMixin, serializers.ModelSerializ return obj.channel_filters.count() def get_connected_escalations_chains_count(self, obj) -> int: - return len( - set(ChannelFilter.objects.filter(alert_receive_channel=obj).values_list("escalation_chain", flat=True)) + return ( + ChannelFilter.objects.filter(alert_receive_channel=obj, escalation_chain__isnull=False) + .values("escalation_chain") + .distinct() + .count() ) @@ -192,8 +202,7 @@ class FastAlertReceiveChannelSerializer(serializers.ModelSerializer): fields = ["id", "integration", "verbal_name", "deleted"] def get_deleted(self, obj): - # Treat direct paging integrations as deleted, so integration settings are disabled on the frontend - return obj.deleted_at is not None or obj.integration == AlertReceiveChannel.INTEGRATION_DIRECT_PAGING + return obj.deleted_at is not None class FilterAlertReceiveChannelSerializer(serializers.ModelSerializer): diff --git a/engine/apps/api/serializers/paging.py b/engine/apps/api/serializers/paging.py index 7ebaf9a4..b764f7ef 100644 --- a/engine/apps/api/serializers/paging.py +++ b/engine/apps/api/serializers/paging.py @@ -56,17 +56,12 @@ class DirectPagingSerializer(serializers.Serializer): def validate(self, attrs): organization = self.context["organization"] - users = attrs["users"] - schedules = attrs["schedules"] escalation_chain_id = attrs["escalation_chain_id"] alert_group_id = attrs["alert_group_id"] title = attrs["title"] message = attrs["message"] - if len(users) == 0 and len(schedules) == 0 and not escalation_chain_id: - raise serializers.ValidationError("Provide users, schedules, or an escalation chain") - if alert_group_id and (title or message): raise serializers.ValidationError("alert_group_id and (title, message) are mutually exclusive") diff --git a/engine/apps/api/tests/test_alert_group.py b/engine/apps/api/tests/test_alert_group.py index 736ff69c..0bd09c83 100644 --- a/engine/apps/api/tests/test_alert_group.py +++ b/engine/apps/api/tests/test_alert_group.py @@ -8,7 +8,7 @@ from rest_framework import status from rest_framework.response import Response from rest_framework.test import APIClient -from apps.alerts.models import AlertGroup, AlertGroupLogRecord, AlertReceiveChannel +from apps.alerts.models import AlertGroup, AlertGroupLogRecord from apps.api.errors import AlertGroupAPIError from apps.api.permissions import LegacyAccessControlRole from apps.base.models import UserNotificationPolicyLogRecord @@ -1813,28 +1813,6 @@ def test_alert_group_paged_users( assert response.json()["paged_users"] == [user2.short()] -@pytest.mark.django_db -def test_direct_paging_integration_treated_as_deleted( - make_organization_and_user_with_plugin_token, - make_alert_receive_channel, - alert_group_internal_api_setup, - make_channel_filter, - make_alert_group, - make_user_auth_headers, -): - organization, user, token = make_organization_and_user_with_plugin_token() - alert_receive_channel = make_alert_receive_channel( - organization, integration=AlertReceiveChannel.INTEGRATION_DIRECT_PAGING - ) - alert_group = make_alert_group(alert_receive_channel) - - client = APIClient() - url = reverse("api-internal:alertgroup-detail", kwargs={"pk": alert_group.public_primary_key}) - - response = client.get(url, format="json", **make_user_auth_headers(user, token)) - assert response.json()["alert_receive_channel"]["deleted"] is True - - @pytest.mark.django_db def test_alert_group_resolve_resolution_note( make_organization_and_user_with_plugin_token, diff --git a/engine/apps/api/tests/test_alert_receive_channel.py b/engine/apps/api/tests/test_alert_receive_channel.py index e2f42d39..277a8be7 100644 --- a/engine/apps/api/tests/test_alert_receive_channel.py +++ b/engine/apps/api/tests/test_alert_receive_channel.py @@ -675,23 +675,6 @@ def test_alert_receive_channel_counters_per_integration_permissions( assert response.status_code == expected_status -@pytest.mark.django_db -def test_get_alert_receive_channels_direct_paging_hidden_from_list( - make_organization_and_user_with_plugin_token, make_alert_receive_channel, make_user_auth_headers -): - organization, user, token = make_organization_and_user_with_plugin_token() - make_alert_receive_channel(user.organization, integration=AlertReceiveChannel.INTEGRATION_DIRECT_PAGING) - - client = APIClient() - url = reverse("api-internal:alert_receive_channel-list") - response = client.get(url, format="json", **make_user_auth_headers(user, token)) - - # Check no direct paging integrations in the response - assert response.status_code == status.HTTP_200_OK - assert response.json()["count"] == 0 - assert len(response.json()["results"]) == 0 - - @pytest.mark.django_db def test_get_alert_receive_channels_direct_paging_present_for_filters( make_organization_and_user_with_plugin_token, make_alert_receive_channel, make_user_auth_headers diff --git a/engine/apps/api/views/alert_receive_channel.py b/engine/apps/api/views/alert_receive_channel.py index 9bcb3d8e..2e213ae7 100644 --- a/engine/apps/api/views/alert_receive_channel.py +++ b/engine/apps/api/views/alert_receive_channel.py @@ -18,6 +18,7 @@ from apps.api.serializers.alert_receive_channel import ( ) from apps.api.throttlers import DemoAlertThrottler from apps.auth_token.auth import PluginAuthentication +from apps.user_management.models.team import Team from common.api_helpers.exceptions import BadRequest from common.api_helpers.filters import ByTeamModelFieldFilterMixin, TeamModelMultipleChoiceFilter from common.api_helpers.mixins import ( @@ -104,10 +105,39 @@ class AlertReceiveChannelView( } def create(self, request, *args, **kwargs): - if request.data["integration"] is not None and ( - request.data["integration"] in AlertReceiveChannel.WEB_INTEGRATION_CHOICES - ): - return super().create(request, *args, **kwargs) + organization = request.auth.organization + user = request.user + team_lookup = {} + if "team" in request.data: + team_public_pk = request.data.get("team", None) + if team_public_pk is not None: + try: + team = user.available_teams.get(public_primary_key=team_public_pk) + team_lookup = {"team": team} + except Team.DoesNotExist: + return Response(data="invalid team", status=status.HTTP_400_BAD_REQUEST) + else: + team_lookup = {"team__isnull": True} + + if request.data["integration"] is not None: + if request.data["integration"] in AlertReceiveChannel.WEB_INTEGRATION_CHOICES: + # Don't allow multiple Direct Paging integrations + if request.data["integration"] == AlertReceiveChannel.INTEGRATION_DIRECT_PAGING: + try: + AlertReceiveChannel.objects.get( + organization=organization, + integration=AlertReceiveChannel.INTEGRATION_DIRECT_PAGING, + deleted_at=None, + **team_lookup, + ) + return Response( + data="Direct paging integration already exists for this team", + status=status.HTTP_400_BAD_REQUEST, + ) + except AlertReceiveChannel.DoesNotExist: + pass + return super().create(request, *args, **kwargs) + return Response(data="invalid integration", status=status.HTTP_400_BAD_REQUEST) def perform_update(self, serializer): @@ -147,10 +177,6 @@ class AlertReceiveChannelView( if not ignore_filtering_by_available_teams: queryset = queryset.filter(*self.available_teams_lookup_args).distinct() - # Hide direct paging integrations from the list view, but not from the filters - if not is_filters_request: - queryset = queryset.exclude(integration=AlertReceiveChannel.INTEGRATION_DIRECT_PAGING) - return queryset @action(detail=True, methods=["post"], throttle_classes=[DemoAlertThrottler]) diff --git a/engine/apps/public_api/tests/test_integrations.py b/engine/apps/public_api/tests/test_integrations.py index 3a4a2db3..6b75c897 100644 --- a/engine/apps/public_api/tests/test_integrations.py +++ b/engine/apps/public_api/tests/test_integrations.py @@ -726,25 +726,6 @@ def test_set_default_messaging_backend_template( assert response.data == expected_response -@pytest.mark.django_db -def test_get_list_integrations_direct_paging_hidden( - make_organization_and_user_with_token, - make_alert_receive_channel, - make_channel_filter, - make_integration_heartbeat, -): - organization, user, token = make_organization_and_user_with_token() - make_alert_receive_channel(organization, integration=AlertReceiveChannel.INTEGRATION_DIRECT_PAGING) - - client = APIClient() - url = reverse("api-public:integrations-list") - response = client.get(url, format="json", HTTP_AUTHORIZATION=f"{token}") - - # Check no direct paging integrations in the response - assert response.status_code == status.HTTP_200_OK - assert response.json()["results"] == [] - - @pytest.mark.django_db def test_get_list_integrations_link_and_inbound_email( make_organization_and_user_with_token, diff --git a/engine/apps/public_api/views/integrations.py b/engine/apps/public_api/views/integrations.py index eac090eb..5bcb92fb 100644 --- a/engine/apps/public_api/views/integrations.py +++ b/engine/apps/public_api/views/integrations.py @@ -48,9 +48,6 @@ class IntegrationView( queryset = self.serializer_class.setup_eager_loading(queryset) queryset = queryset.annotate(alert_groups_count_annotated=Count("alert_groups", distinct=True)) - # Hide direct paging integrations - queryset = queryset.exclude(integration=AlertReceiveChannel.INTEGRATION_DIRECT_PAGING) - return queryset def get_object(self): diff --git a/engine/config_integrations/direct_paging.py b/engine/config_integrations/direct_paging.py index 40d6e791..755c1cd7 100644 --- a/engine/config_integrations/direct_paging.py +++ b/engine/config_integrations/direct_paging.py @@ -4,7 +4,7 @@ title = "Direct paging" slug = "direct_paging" short_description = None description = None -is_displayed_on_web = False +is_displayed_on_web = True is_featured = False is_able_to_autoresolve = False is_demo_alert_enabled = False diff --git a/grafana-plugin/src/components/ManualAlertGroup/ManualAlertGroup.config.ts b/grafana-plugin/src/components/ManualAlertGroup/ManualAlertGroup.config.ts index 5ce80b2a..e4a5f0cd 100644 --- a/grafana-plugin/src/components/ManualAlertGroup/ManualAlertGroup.config.ts +++ b/grafana-plugin/src/components/ManualAlertGroup/ManualAlertGroup.config.ts @@ -15,19 +15,5 @@ export const manualAlertFormConfig: { name: string; fields: FormItem[] } = { label: 'Description', validation: { required: true }, }, - { - name: 'team', - label: 'Assign to team', - description: - 'Assigning to the teams allows you to filter Alert Groups and configure their visibility. Go to OnCall -> Settings -> Team and Access Settings for more details', - type: FormItemType.GSelect, - extra: { - modelName: 'grafanaTeamStore', - displayField: 'name', - valueField: 'id', - showSearch: true, - allowClear: true, - }, - }, ], }; diff --git a/grafana-plugin/src/components/ManualAlertGroup/ManualAlertGroup.module.css b/grafana-plugin/src/components/ManualAlertGroup/ManualAlertGroup.module.css index 2b167d9c..a421dabc 100644 --- a/grafana-plugin/src/components/ManualAlertGroup/ManualAlertGroup.module.css +++ b/grafana-plugin/src/components/ManualAlertGroup/ManualAlertGroup.module.css @@ -6,3 +6,23 @@ background: var(--secondary-background); width: 100%; } + +.responders-list { + list-style-type: none; + margin-bottom: 20px; + width: 100%; + background: var(--background-secondary); + + & > li .hover-button { + display: none; + } + + & > li:hover .hover-button { + display: inline-flex; + } + + & > li { + padding: 10px 12px; + width: 100%; + } +} diff --git a/grafana-plugin/src/components/ManualAlertGroup/ManualAlertGroup.tsx b/grafana-plugin/src/components/ManualAlertGroup/ManualAlertGroup.tsx index 274b84dd..255f3ea8 100644 --- a/grafana-plugin/src/components/ManualAlertGroup/ManualAlertGroup.tsx +++ b/grafana-plugin/src/components/ManualAlertGroup/ManualAlertGroup.tsx @@ -1,15 +1,35 @@ import React, { FC, useCallback, useState } from 'react'; -import { Button, Drawer, HorizontalGroup, Icon, VerticalGroup } from '@grafana/ui'; +import { + Alert, + Button, + Drawer, + Field, + HorizontalGroup, + Icon, + IconButton, + IconName, + Label, + LoadingPlaceholder, + Tooltip, + VerticalGroup, +} from '@grafana/ui'; import cn from 'classnames/bind'; -import Block from 'components/GBlock/Block'; import GForm from 'components/GForm/GForm'; +import PluginLink from 'components/PluginLink/PluginLink'; import Text from 'components/Text/Text'; import EscalationVariants from 'containers/EscalationVariants/EscalationVariants'; import { prepareForUpdate } from 'containers/EscalationVariants/EscalationVariants.helpers'; -import { Alert } from 'models/alertgroup/alertgroup.types'; +import GrafanaTeamSelect from 'containers/GrafanaTeamSelect/GrafanaTeamSelect'; +import TeamName from 'containers/TeamName/TeamName'; +import { AlertReceiveChannelStore } from 'models/alert_receive_channel/alert_receive_channel'; +import { AlertReceiveChannel } from 'models/alert_receive_channel/alert_receive_channel.types'; +import { Alert as AlertType } from 'models/alertgroup/alertgroup.types'; +import { GrafanaTeam } from 'models/grafana_team/grafana_team.types'; +import IntegrationHelper from 'pages/integration/Integration.helper'; import { useStore } from 'state/useStore'; +import { openWarningNotification } from 'utils'; import { manualAlertFormConfig } from './ManualAlertGroup.config'; @@ -17,7 +37,8 @@ import styles from './ManualAlertGroup.module.css'; interface ManualAlertGroupProps { onHide: () => void; - onCreate: (id: Alert['pk']) => void; + onCreate: (id: AlertType['pk']) => void; + alertReceiveChannelStore: AlertReceiveChannelStore; } const cx = cn.bind(styles); @@ -26,13 +47,24 @@ const ManualAlertGroup: FC = (props) => { const store = useStore(); const [userResponders, setUserResponders] = useState([]); const [scheduleResponders, setScheduleResponders] = useState([]); - const { onHide, onCreate } = props; - const data = { team: store.userStore.currentUser?.current_team }; + const { onHide, onCreate, alertReceiveChannelStore } = props; + + const [selectedTeamId, setSelectedTeam] = useState(); + const [selectedTeamDirectPaging, setSelectedTeamDirectPaging] = useState(); + const [directPagingLoading, setdirectPagingLoading] = useState(); + + const [chatOpsAvailableChannels, setChatopsAvailableChannels] = useState(); + + const data = {}; const handleFormSubmit = async (data) => { + if (selectedTeamId === undefined) { + openWarningNotification('Select team first'); + return; + } store.directPagingStore - .createManualAlertRule(prepareForUpdate(userResponders, scheduleResponders, data)) - .then(({ alert_group_id: id }: { alert_group_id: Alert['pk'] }) => { + .createManualAlertRule(prepareForUpdate(userResponders, scheduleResponders, { team: selectedTeamId, ...data })) + .then(({ alert_group_id: id }: { alert_group_id: AlertType['pk'] }) => { onCreate(id); }) .finally(() => { @@ -40,48 +72,174 @@ const ManualAlertGroup: FC = (props) => { }); }; + const onUpdateSelectedTeam = async (selectedTeamId: GrafanaTeam['id']) => { + setdirectPagingLoading(true); + setSelectedTeamDirectPaging(null); + setSelectedTeam(selectedTeamId); + await alertReceiveChannelStore.updateItems({ team: selectedTeamId, integration: 'direct_paging' }); + const directPagingAlertReceiveChannel = + alertReceiveChannelStore.getSearchResult() && alertReceiveChannelStore.getSearchResult()[0]; + if (directPagingAlertReceiveChannel) { + setSelectedTeamDirectPaging(directPagingAlertReceiveChannel); + await alertReceiveChannelStore.updateChannelFilters(directPagingAlertReceiveChannel.id); + await store.slackChannelStore.updateItems(); + + // The code below is used to get the unique available chotops channels for all routes in integraion + // This is the workaround for IntegrationHelper.getChatOpsChannels, it should be moved to the helper + const filterIds = alertReceiveChannelStore.channelFilterIds[directPagingAlertReceiveChannel.id]; + let availableChannels = []; + let channelKeys = new Set(); + filterIds.map((channelFilterId) => { + IntegrationHelper.getChatOpsChannels(alertReceiveChannelStore.channelFilters[channelFilterId], store) + .filter((channel) => channel) + .map((channel) => { + if (!channelKeys.has(channel.name + channel.icon)) { + availableChannels.push(channel); + channelKeys.add(channel.name + channel.icon); + } + }); + }); + setChatopsAvailableChannels(Array.from(availableChannels)); + } + setdirectPagingLoading(false); + }; + const onUpdateEscalationVariants = useCallback( (value) => { setUserResponders(value.userResponders); - setScheduleResponders(value.scheduleResponders); }, [userResponders, scheduleResponders] ); + const DirectPagingIntegrationVariants = ({ selectedTeamId, selectedTeamDirectPaging, chatOpsAvailableChannels }) => { + const escalationChainsExist = selectedTeamDirectPaging?.connected_escalations_chains_count === 0; + + return ( + + {selectedTeamId && + (directPagingLoading ? ( + + ) : selectedTeamDirectPaging ? ( + + +
      +
    • + + + {escalationChainsExist && ( + + + + )} + {selectedTeamDirectPaging.verbal_name} + + + Team: + + + + {chatOpsAvailableChannels && ( + <> + ChatOps:{' '} + {chatOpsAvailableChannels.map( + (chatOpsChannel: { name: string; icon: IconName }, chatOpsIndex) => ( +
      + {chatOpsChannel.icon && } + {chatOpsChannel.name || ''} +
      + ) + )} + + )} +
      + + + + + +
      +
    • +
    + + {(escalationChainsExist || !chatOpsAvailableChannels) && ( + + + {escalationChainsExist && ( + + Integration doesn't have connected escalation policies. Consider adding responders manually by + user or by email + + )} + {!chatOpsAvailableChannels && ( + Integration doesn't have connected ChatOps channels in messengers. + )} + + + )} +
    + ) : ( + + + + Empty integration for this team will be created automatically. Consider selecting responders by + schedule or user below + + + + ))} +
    + ); + }; + + const submitButtonDisabled = !( + selectedTeamId && + (selectedTeamDirectPaging || userResponders.length || scheduleResponders.length) + ); + return ( - <> - - - - - {store.teamStore.currentTeam.slack_team_identity && ( - - {' '} - - The alert group will also be posted to #{store.teamStore.currentTeam?.slack_channel?.display_name} Slack - channel. - - - )} - - - - - - - + + + + + + + + + + + + + + ); }; diff --git a/grafana-plugin/src/containers/CreateAlertReceiveChannelContainer/CreateAlertReceiveChannelContainer.tsx b/grafana-plugin/src/containers/CreateAlertReceiveChannelContainer/CreateAlertReceiveChannelContainer.tsx index c4177cad..98ee9d81 100644 --- a/grafana-plugin/src/containers/CreateAlertReceiveChannelContainer/CreateAlertReceiveChannelContainer.tsx +++ b/grafana-plugin/src/containers/CreateAlertReceiveChannelContainer/CreateAlertReceiveChannelContainer.tsx @@ -68,7 +68,7 @@ const CreateAlertReceiveChannelContainer = observer((props: CreateAlertReceiveCh label="Assign to team" description="OnCall teams allow you to organize integrations so you can filter and set up access. " > - +

    diff --git a/grafana-plugin/src/containers/EscalationVariants/EscalationVariants.tsx b/grafana-plugin/src/containers/EscalationVariants/EscalationVariants.tsx index 07ca0b8e..c03b19b8 100644 --- a/grafana-plugin/src/containers/EscalationVariants/EscalationVariants.tsx +++ b/grafana-plugin/src/containers/EscalationVariants/EscalationVariants.tsx @@ -26,6 +26,7 @@ export interface EscalationVariantsProps { variant?: 'secondary' | 'primary'; hideSelected?: boolean; disabled?: boolean; + withLabels?: boolean; } const EscalationVariants = observer( @@ -35,6 +36,7 @@ const EscalationVariants = observer( variant = 'primary', hideSelected = false, disabled, + withLabels = false, }: EscalationVariantsProps) => { const [showEscalationVariants, setShowEscalationVariants] = useState(false); @@ -103,7 +105,7 @@ const EscalationVariants = observer(
    {!hideSelected && Boolean(value.userResponders.length || value.scheduleResponders.length) && ( <> - +
      {value.userResponders.map((responder, index) => ( )}
      + {withLabels && }
      @@ -230,11 +233,11 @@ const UserResponder = ({ important, data, onImportantChange, handleDelete }) => }} onChange={onImportantChange} /> - notification chain + notification policies ) : ( - + diff --git a/grafana-plugin/src/containers/GrafanaTeamSelect/GrafanaTeamSelect.tsx b/grafana-plugin/src/containers/GrafanaTeamSelect/GrafanaTeamSelect.tsx index fff5cc91..4f7bebe0 100644 --- a/grafana-plugin/src/containers/GrafanaTeamSelect/GrafanaTeamSelect.tsx +++ b/grafana-plugin/src/containers/GrafanaTeamSelect/GrafanaTeamSelect.tsx @@ -18,15 +18,16 @@ interface GrafanaTeamSelectProps { onSelect: (id: GrafanaTeam['id']) => void; onHide?: () => void; withoutModal?: boolean; + defaultValue?: GrafanaTeam['id']; } -const GrafanaTeamSelect = observer(({ onSelect, onHide, withoutModal }: GrafanaTeamSelectProps) => { +const GrafanaTeamSelect = observer(({ onSelect, onHide, withoutModal, defaultValue }: GrafanaTeamSelectProps) => { const store = useStore(); const { userStore, grafanaTeamStore } = store; const user = userStore.currentUser; - const [selectedTeam, setSelectedTeam] = useState(user.current_team); + const [selectedTeam, setSelectedTeam] = useState(defaultValue); const grafanaTeams = grafanaTeamStore.getSearchResult(); diff --git a/grafana-plugin/src/containers/IntegrationForm/IntegrationForm.tsx b/grafana-plugin/src/containers/IntegrationForm/IntegrationForm.tsx index d550d6c9..543b4c79 100644 --- a/grafana-plugin/src/containers/IntegrationForm/IntegrationForm.tsx +++ b/grafana-plugin/src/containers/IntegrationForm/IntegrationForm.tsx @@ -62,8 +62,12 @@ const IntegrationForm = observer((props: IntegrationFormProps) => { .then((response) => { history.push(`${PLUGIN_ROOT}/integrations/${response.id}`); }) - .catch(() => { - openErrorNotification('Something went wrong, please try again later.'); + .catch((err) => { + if (err.response?.data?.length > 0) { + openErrorNotification(err.response.data); + } else { + openErrorNotification('Something went wrong, please try again later.'); + } }) : alertReceiveChannelStore.update(id, data) ).then(() => { diff --git a/grafana-plugin/src/pages/incidents/Incidents.tsx b/grafana-plugin/src/pages/incidents/Incidents.tsx index b4a91ed2..f26f8bb4 100644 --- a/grafana-plugin/src/pages/incidents/Incidents.tsx +++ b/grafana-plugin/src/pages/incidents/Incidents.tsx @@ -111,7 +111,7 @@ class Incidents extends React.Component const { showAddAlertGroupForm } = this.state; const { store, - store: { alertGroupStore }, + store: { alertGroupStore, alertReceiveChannelStore }, } = this.props; if (!alertGroupStore.irmPlan && !store.isOpenSource()) { @@ -126,7 +126,7 @@ class Incidents extends React.Component Alert Groups @@ -142,6 +142,7 @@ class Incidents extends React.Component onCreate={(id: Alert['pk']) => { history.push(`${PLUGIN_ROOT}/alert-groups/${id}`); }} + alertReceiveChannelStore={alertReceiveChannelStore} /> )} diff --git a/grafana-plugin/src/pages/integration/Integration.tsx b/grafana-plugin/src/pages/integration/Integration.tsx index a8f178a6..550dce15 100644 --- a/grafana-plugin/src/pages/integration/Integration.tsx +++ b/grafana-plugin/src/pages/integration/Integration.tsx @@ -326,7 +326,7 @@ class Integration extends React.Component { Autoresolve: - {IntegrationHelper.truncateLine(templates['resolve_condition_template'] || '')} + {IntegrationHelper.truncateLine(templates['resolve_condition_template'] || 'disabled')}
    @@ -964,6 +964,17 @@ const HowToConnectComponent: React.FC<{ id: AlertReceiveChannel['id'] }> = ({ id const item = alertReceiveChannelStore.items[id]; const url = item?.integration_url || item?.inbound_email; + const howToConnectTagName = (integration: string) => { + switch (integration) { + case 'direct_paging': + return 'Manual'; + case 'email': + return 'Inbound Email'; + default: + return 'HTTP Endpoint'; + } + }; + return ( = ({ id className={cx('how-to-connect__tag')} > - {item?.inbound_email ? 'Inbound Email' : 'HTTP Endpoint'} + {howToConnectTagName(item?.integration)} - {url && ( - + {item?.integration === 'direct_paging' ? ( + <> + Alert Groups raised manually via Web or ChatOps + + + + How it works + + + + + + ) : ( + <> + {url && ( + + )} + + + + How to connect + + + + + )} - - - - How to connect - - - -
    } content={hasAlerts ? null : renderContent()} @@ -1006,12 +1038,20 @@ const HowToConnectComponent: React.FC<{ id: AlertReceiveChannel['id'] }> = ({ id ); function renderContent() { + const callToAction = () => { + if (item?.integration === 'direct_paging') { + return try to raise a demo alert group via Web or Chatops; + } else { + return item.demo_alert_enabled && ; try to send a demo alert; + } + }; + return ( {!hasAlerts && ( - No alerts yet; try to send a demo alert + No alerts yet; {callToAction()} )} From 1c3b362b3437b2f2882785cf23a6d27021975cc9 Mon Sep 17 00:00:00 2001 From: Joey Orlando Date: Thu, 13 Jul 2023 10:41:23 +0200 Subject: [PATCH 08/11] remove unused frontend code (#2482) # What this PR does Removes old code that is no longer referenced/used: - `organization-logs` UI page + model. This page is hidden from navigation, but if you go to it the API endpoint it hits does not exist and returns HTTP 404. - several icons/images that were no longer referenced: - `icons/cross-circled.svg` - `icons/grafana-icon.svg` - `icons/heart-green.svg` - `icons/heart-line.svg` - `icons/heart-red.svg` - Several Icon components in `icons/index.tsx` that were no longer referenced - `img/telegram_discussion.png` - `interceptors/index.ts` - see comment on that file. This interceptor is never invoked. - models - curler - current_subscription - integrations_list - leader - timezone - the `tzs` array of timezone strings was duplicated - webinar - services - experimentManager - googleTagManager - urlManager ## Checklist - [ ] Unit, integration, and e2e (if applicable) tests updated (N/A) - [ ] Documentation added (or `pr:no public docs` PR label added if not required) (N/A) - [ ] `CHANGELOG.md` updated (or `pr:no changelog` PR label added if not required) (N/A) --- grafana-plugin/.eslintrc.js | 2 +- .../UserTimezoneSelect/UserTimezoneSelect.tsx | 8 +- .../OrganizationLogFilters.module.css | 19 - .../OrganizationLogFilters.tsx | 91 --- grafana-plugin/src/declare/index.d.ts | 1 - grafana-plugin/src/icons/cross-circled.svg | 8 - grafana-plugin/src/icons/grafana-icon.svg | 10 - grafana-plugin/src/icons/heart-green.svg | 3 - grafana-plugin/src/icons/heart-line.svg | 24 - grafana-plugin/src/icons/heart-red.svg | 3 - grafana-plugin/src/icons/index.tsx | 190 +----- .../src/img/telegram_discussion.png | Bin 338148 -> 0 bytes grafana-plugin/src/interceptors/index.ts | 19 - grafana-plugin/src/models/card.ts | 14 - grafana-plugin/src/models/curler/curler.ts | 111 ---- .../src/models/curler/curler.types.ts | 26 - .../src/models/current_subscription.ts | 57 -- .../current_subscription.ts | 23 - .../current_subscription.types.ts | 86 --- .../src/models/integrations_list.ts | 6 - grafana-plugin/src/models/leader.ts | 10 - .../organization_log/organization_log.ts | 60 -- .../organization_log.types.ts | 10 - .../src/models/timezone/timezone.helpers.ts | 6 +- .../src/models/timezone/timezone.types.ts | 597 +----------------- grafana-plugin/src/models/webinar/webinar.ts | 67 -- .../src/models/webinar/webinar.types.ts | 13 - grafana-plugin/src/pages/index.tsx | 8 - .../OrganizationLog.module.css | 23 - .../organization-logs/OrganizationLog.tsx | 199 ------ grafana-plugin/src/pages/routes.tsx | 5 - .../src/plugin/GrafanaPluginRootPage.tsx | 5 - .../src/services/experimentManager.ts | 16 - .../src/services/googleTagManager.ts | 5 - grafana-plugin/src/services/urlManager.ts | 24 - .../src/state/rootBaseStore/index.ts | 2 - 36 files changed, 14 insertions(+), 1737 deletions(-) delete mode 100644 grafana-plugin/src/containers/OrganizationLogFilters/OrganizationLogFilters.module.css delete mode 100644 grafana-plugin/src/containers/OrganizationLogFilters/OrganizationLogFilters.tsx delete mode 100644 grafana-plugin/src/declare/index.d.ts delete mode 100644 grafana-plugin/src/icons/cross-circled.svg delete mode 100644 grafana-plugin/src/icons/grafana-icon.svg delete mode 100644 grafana-plugin/src/icons/heart-green.svg delete mode 100644 grafana-plugin/src/icons/heart-line.svg delete mode 100644 grafana-plugin/src/icons/heart-red.svg delete mode 100644 grafana-plugin/src/img/telegram_discussion.png delete mode 100644 grafana-plugin/src/interceptors/index.ts delete mode 100644 grafana-plugin/src/models/card.ts delete mode 100644 grafana-plugin/src/models/curler/curler.ts delete mode 100644 grafana-plugin/src/models/curler/curler.types.ts delete mode 100644 grafana-plugin/src/models/current_subscription.ts delete mode 100644 grafana-plugin/src/models/current_subscription/current_subscription.ts delete mode 100644 grafana-plugin/src/models/current_subscription/current_subscription.types.ts delete mode 100644 grafana-plugin/src/models/integrations_list.ts delete mode 100644 grafana-plugin/src/models/leader.ts delete mode 100644 grafana-plugin/src/models/organization_log/organization_log.ts delete mode 100644 grafana-plugin/src/models/organization_log/organization_log.types.ts delete mode 100644 grafana-plugin/src/models/webinar/webinar.ts delete mode 100644 grafana-plugin/src/models/webinar/webinar.types.ts delete mode 100644 grafana-plugin/src/pages/organization-logs/OrganizationLog.module.css delete mode 100644 grafana-plugin/src/pages/organization-logs/OrganizationLog.tsx delete mode 100644 grafana-plugin/src/services/experimentManager.ts delete mode 100644 grafana-plugin/src/services/googleTagManager.ts delete mode 100644 grafana-plugin/src/services/urlManager.ts diff --git a/grafana-plugin/.eslintrc.js b/grafana-plugin/.eslintrc.js index 9a8d2b07..b58173bb 100644 --- a/grafana-plugin/.eslintrc.js +++ b/grafana-plugin/.eslintrc.js @@ -6,7 +6,7 @@ module.exports = { plugins: ['rulesdir', 'import'], settings: { 'import/internal-regex': - '^assets|^components|^containers|^declare|^icons|^img|^interceptors|^models|^network|^pages|^services|^state|^utils|^plugin', + '^assets|^components|^containers|^icons|^img|^models|^network|^pages|^services|^state|^utils|^plugin', }, rules: { eqeqeq: 'warn', diff --git a/grafana-plugin/src/components/UserTimezoneSelect/UserTimezoneSelect.tsx b/grafana-plugin/src/components/UserTimezoneSelect/UserTimezoneSelect.tsx index 4c7254be..448d20b4 100644 --- a/grafana-plugin/src/components/UserTimezoneSelect/UserTimezoneSelect.tsx +++ b/grafana-plugin/src/components/UserTimezoneSelect/UserTimezoneSelect.tsx @@ -5,8 +5,8 @@ import { Select } from '@grafana/ui'; import cn from 'classnames/bind'; import dayjs from 'dayjs'; -import { getTzOffsetString } from 'models/timezone/timezone.helpers'; -import { Timezone, tzs } from 'models/timezone/timezone.types'; +import { getTzOffsetString, allTimezones } from 'models/timezone/timezone.helpers'; +import { Timezone } from 'models/timezone/timezone.types'; import { User } from 'models/user/user.types'; import styles from './UserTimezoneSelect.module.css'; @@ -111,7 +111,7 @@ const UserTimezoneSelect: FC = (props) => { const handleCreateOption = useCallback( (value: string) => { - const matched = tzs.find((tz) => tz.toLowerCase().includes(value.toLowerCase())); + const matched = allTimezones.find((tz) => tz.toLowerCase().includes(value.toLowerCase())); if (matched) { const now = dayjs().tz(matched); const utcOffset = now.utcOffset(); @@ -150,7 +150,7 @@ const UserTimezoneSelect: FC = (props) => { allowCustomValue onCreateOption={handleCreateOption} formatCreateLabel={(input: string) => { - const matched = tzs.find((tz) => tz.toLowerCase().includes(input.toLowerCase())); + const matched = allTimezones.find((tz) => tz.toLowerCase().includes(input.toLowerCase())); const now = dayjs().tz(matched); if (matched) { return `Select ${getTzOffsetString(now)} (${matched})`; diff --git a/grafana-plugin/src/containers/OrganizationLogFilters/OrganizationLogFilters.module.css b/grafana-plugin/src/containers/OrganizationLogFilters/OrganizationLogFilters.module.css deleted file mode 100644 index 913c13e0..00000000 --- a/grafana-plugin/src/containers/OrganizationLogFilters/OrganizationLogFilters.module.css +++ /dev/null @@ -1,19 +0,0 @@ -.root { - display: block; -} - -.root > * { - margin-bottom: 10px !important; -} - -.root > *:not(:last-child) { - margin-right: 10px !important; -} - -.root .search { - width: 400px; -} - -.select { - min-width: 300px; -} diff --git a/grafana-plugin/src/containers/OrganizationLogFilters/OrganizationLogFilters.tsx b/grafana-plugin/src/containers/OrganizationLogFilters/OrganizationLogFilters.tsx deleted file mode 100644 index 2e0831a8..00000000 --- a/grafana-plugin/src/containers/OrganizationLogFilters/OrganizationLogFilters.tsx +++ /dev/null @@ -1,91 +0,0 @@ -import React, { ChangeEvent, useCallback, useMemo, useState } from 'react'; - -import { RawTimeRange } from '@grafana/data'; -import { HorizontalGroup, Input, TimeRangeInput } from '@grafana/ui'; -import cn from 'classnames/bind'; -import { observer } from 'mobx-react'; - -import RemoteSelect from 'containers/RemoteSelect/RemoteSelect'; - -import styles from './OrganizationLogFilters.module.css'; - -const cx = cn.bind(styles); - -interface OrganizationLogFiltersProps { - value: any; - onChange: (filters: any) => void; - className?: string; -} - -const OrganizationLogFilters = observer((props: OrganizationLogFiltersProps) => { - const { value, onChange } = props; - - const [createAtRaw, setCreateAtRaw] = useState(); - - const onSearchTermChangeCallback = useCallback( - (e: ChangeEvent) => { - const filters = { - ...value, - search: e.currentTarget.value, - }; - - onChange(filters); - }, - [onChange, value] - ); - - const getChangeHandler = (field: string) => { - return (newValue: any) => { - onChange({ - ...value, - [field]: newValue, - }); - }; - }; - - const handleChangeCreatedAt = useCallback( - (filter) => { - onChange({ - ...value, - created_at: filter.from._isValid && filter.to._isValid ? [filter.from, filter.to] : undefined, - }); - - setCreateAtRaw(filter.raw); - }, - [value] - ); - - const createdAtValue = useMemo(() => { - if (value['created_at']) { - return { from: value['created_at'][0].toDate(), to: value['created_at'][1].toDate(), raw: createAtRaw }; - } - return { from: undefined, to: undefined, raw: undefined }; - }, [value]); - - return ( -
    - - - - - -
    - ); -}); - -export default OrganizationLogFilters; diff --git a/grafana-plugin/src/declare/index.d.ts b/grafana-plugin/src/declare/index.d.ts deleted file mode 100644 index a128cf42..00000000 --- a/grafana-plugin/src/declare/index.d.ts +++ /dev/null @@ -1 +0,0 @@ -declare module 'slack-markdown'; diff --git a/grafana-plugin/src/icons/cross-circled.svg b/grafana-plugin/src/icons/cross-circled.svg deleted file mode 100644 index f468d638..00000000 --- a/grafana-plugin/src/icons/cross-circled.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - diff --git a/grafana-plugin/src/icons/grafana-icon.svg b/grafana-plugin/src/icons/grafana-icon.svg deleted file mode 100644 index 15ccfa28..00000000 --- a/grafana-plugin/src/icons/grafana-icon.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/grafana-plugin/src/icons/heart-green.svg b/grafana-plugin/src/icons/heart-green.svg deleted file mode 100644 index 19b895a6..00000000 --- a/grafana-plugin/src/icons/heart-green.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/grafana-plugin/src/icons/heart-line.svg b/grafana-plugin/src/icons/heart-line.svg deleted file mode 100644 index 6c063e81..00000000 --- a/grafana-plugin/src/icons/heart-line.svg +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - diff --git a/grafana-plugin/src/icons/heart-red.svg b/grafana-plugin/src/icons/heart-red.svg deleted file mode 100644 index ab685063..00000000 --- a/grafana-plugin/src/icons/heart-red.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/grafana-plugin/src/icons/index.tsx b/grafana-plugin/src/icons/index.tsx index 3e0141c8..5bba570e 100644 --- a/grafana-plugin/src/icons/index.tsx +++ b/grafana-plugin/src/icons/index.tsx @@ -1,156 +1,6 @@ import React from 'react'; -interface IconProps {} - -export const NewIncidentIcon = (_props: IconProps) => ( - - - - - -); - -export const AcknowledgedIncidentIcon = (_props: IconProps) => ( - - - - - - -); - -export const SilencedIncidentIcon = (_props: IconProps) => ( - - - - - - -); - -export const SentryIcon = (_props: IconProps) => ( - - - - - -); - -export const SilencedIncidentIconTransparent = (_props: IconProps) => ( - - - - - - -); - -export const CurlerIcon = (_props: IconProps) => ( - - - -); - -export const TelegramIcon = (_props: IconProps) => ( - - - -); - -export const AmixrIcon = (_props: IconProps) => ( - - - - -); - -export const AmixrIconColored = (_props: IconProps) => ( - - - - -); - -export const HeartGreenIcon = (_props: IconProps) => ( +export const HeartGreenIcon = () => ( ( ); -export const HeartRedIcon = (_props: IconProps) => ( +export const HeartRedIcon = () => ( ( ); -export const HeartIcon = (_props: IconProps) => ( +export const HeartIcon = () => ( ( ); -export const CrossCircleIcon = (_props: IconProps) => ( +export const CrossCircleIcon = () => ( ( ); -export const ChangeTeamIcon = (_props: IconProps) => ( - - - -); - -export const GrafanaIcon = (_props: IconProps) => ( - - - - - - - - - - -); - -export const ExpandIcon = (_props: IconProps) => { +export const ExpandIcon = () => { return ( { ); }; + export const SlackNewIcon = () => ( yLH?}knL<-+kR305xGu4&u?hVA$hUv6{~nkyT>(Bb>-uwO8ykv_9o z)SKt;RDSWl7x0dSOA@j`I-o%g!83f=erAGxX5Ta?q?R({^BpnFFqZeY_PK`b zS@Zm2^DDo_YBoy#+F9s>9-8%*OsJCXhhIzUgS&4<%HBPZtATma9E_m9&3&8H=^J*t51cYC?7*G2?bll$XxwqFF8JOg&v@0B@n z!~73-KM@x30$;b|{5pfPRf~=#r5lV5>@GQ!JU9A!r?2V%UZxg>lpd2RknZ4X#=0%i zdQg*Y5~9A!I9Ze+2ZuQm9+>Q-a0<`07MYBM+?hx88-y;pne{i~z|ww_2F%R>+Dlx_ zmH`xOCD7R>Tq9S)gG*u_8HYSRH8B2XM6h!AR{)Z{51Jn=eD7K>LYyEvW}V}V<4>Lb z6uAyWg=jQ{4)J_^tr!+2^1vAcIfN%4F&IOk1HTu>h}oF??Wkr6s?^c!Oqw4n-{bKH zd?Xe2+u%)U+wL}Zu$5aBUOE@VF%`}Q*` zRUo!d$aUlE<0#0w{3*f9AiCjSZAcfl#10 zeE{P&qHSJwe6aso&*AP0umwmPz`S#Qlruop(|sIp@-e9NA0V-QqsMM6l`SvYx-fply>b-G{^)Wj9&4r` zUtj6d>1T}u`;~l~D@wPqxv?28+hvC48NA$$)+&VgIBng0*ABlrGr6+jeVN9XgX{wj zJiR5oE2uGm%PvFjXd>rrs+BAHiGv6CkTmK~J%pJIC#j2cVT+jAfrsFSi3zJO_+AVV zTQ?!VCQGvO4HNtzVpsMXdL&SXTP3~)d`kz=26NK)iw#^lEMBLP4e???OCfeE0^cg} zt`Mfb|0pK6esJ=;>0t8pP^Q=36bK=o*JG3@;QPM(3MNYN9Tb&_N$7Pmq*DkW5{x9H zj=m7%u_JU1c6etUElU%qAg?`%Q1?kRM=CzxOHRnH3maiZIPSMsqxq&>8X?D@Kx5du zBA49rzF=W@W}hO1`(&d9}?0upqM)F@THvUluw;2d-`S4Dk%UATd| zh;oD>cDAsG=> zdZ0;B+-am3#Xh!W2=J7?0LwmjB1AHnFa#1j^vh}8Kpzky%tFBx`yj?l!C2&@B&8ub zFJ%5+`<-Jf|M#Mjl%l5Mfa3h3kg4sWgrXxAo^mIVqZAEN^)L(R>vuiTcbjILMw>^Q zFU~3LsGFj4q^t68<*{hF;+x{_B+$0lwn(##{5|%0#BC$MiwAb;f4Oro>~-MN=ixGbH)MxfvC0!tM>% zu17oE6vTuXn8e^=xC~2fYDba@=4Q$a>7B8iiG~T;2_DCg=K5x$C88yTrM70vW{3h?XO*dXs)22sZ>=y*$(U%E zXH9IDR^#6NWctN4V-uj4vF1s>*xN}nY#KU7l{@ie>8E251bqh$fbV5Ja9`kCz*SHp9hK&kGB)%uBy3zVlsX7xx_nFjg(NrK zHgwFu%7Vm-k#og-*?8GR4-{j_Jffe~DN2bYeTU^j(tIl?ly9*H)6<%WYDSCN!e-nj{BYXy8|H-e+_@*AeEqNe^-BL3=lfC zzi42^%l1CzwbPHv>6tGpf>T}>zAuVFjyWJF72y&V&n4*2HhAA%N?;F|=hh(7#)H@Y z$Xud-+%w-T6Uj#)8Xgu=66{VO@WJcL!yJO!k6->v$R}7|v63j4rK=@lsp}{}RE5;4 zlAJ9m- z;#~l^D?24I393;Y;#P?qh*a4Bu;#p)f<8r{kgWK9|0QCaj-h?;3FSW@Lmxaz=Wx!%!?v=6gFmhTAh|$REcyVRB zX;72vq~ebDf)F>EKDlP~Ojb`o84vVEGR&IsQoGUhHCU|nyJgkFx?@;-;;AHKd~n6mtc4?1kKkF~(kY-Pl=18)7 zsuii-nx3vKt4rWWFj@#+KxyDx%4~f+1PtmFJH0)kSvoT+bTR2Eztt`*ZY?f$B0K@A zM5qjuv|Q(%G_`WNSbIh&4o!RBLnLm#KAt}U&<%+iZJEw>2i|ReOVug!Ub0E{YRtne z%1~KQq%J-9E?Z_TfMuJP-`TKsD!-G6C8g(Rub%kW;X1EN*`ja)=$J zNmakd$926~r)XO^FC&`C?@V<$*jH0pBfax5%$|9}<-G}a@p(yPB&@ECq%6q$;`YcU z%|!EvvO@AIsSUtc8)YTnMY-A^Qqrk9qP3yb;=*_D28qZcY_KX=Ic)4|zj|<5KALex zIk{ZQu#d8-*aS~MRwH#|eDH2~_S6Y7>8T3p#Ly(AoyviKUOypyA zSGiieay3vjo!P?M06Kuuq*RaCZgt_VRA`r`tmJK+(0y zR#%5t>wj{D@qPABcwF~!fs=!8U)gA0n;DXZxwZ~E!rPqj zZ!@Py^AWc8X>LM8OX#g$)Jo7&nk~d6xx8r);3G7{fze64xw%okzVV)W@im~$phj)( z>j(dr?tu*HfRwwG)s^6Cfk(z3(i6egzC5>QPk^Ah=&m`Ej%jEBl4ztRZY(Vg^8tGO z5(W_#3kDu~1q=OyfhB-J{Nox1Mgo@bKd%*FY5wd32Llsi27~Zt9}VdD?^iVR4W<6` z8$LD=1_}BL3;OoYhWn4+FI%(W|Kl2A7DTt0>vo|4BVWVlA42>v=q02wI!pTp|!pdql=}@?{Q#wUAUo_mPQVG zWGX*n_>Yda${4n`(MruY0PWMpK#c812> z3c_FhB!~XudvEICV8aanI6FHtIqk@`{TL(H68Eo!MNqjT#PK#gv~6WTMbg_9xL_TmL(S+W$!L*Vg||A!}y_-3YzkOXFw$ zbB4dR{n?)v@cZ!p!VLf7v_D#*tj3SR3;0jA=9At904!t6oo^A*X$K_!Pf?lgoIIGDbY#WeHl+D)893SP27x&jhjutC+RAxsxDW{g~cVBiclX#NmVr{ zz)z4G`F5r}dNtK3qt@9e3&@Y&50+ zN8QPM1kn**8m9W3g!jd=UinFZaF0GgC#Af-Y_l@f6~&_H-5L-^F%-0Dz?xhKybwgBF9Aq;vm z|9~O5FrnID`z7!FZtnRnY*`A+=$V5AugCko=yyVf<9XtCM|Cq2wzjt8j*bP!?_D=z zL`x4D7wRqJsIxp2j$2N^@dq{8uCRO@NEjrwD)&RyUgRs!Pd8~RKKcJ(_Hw9LuM;rf zkdM0gGHBNKf-2e)rvvlz^Us?`JY~GDN^~gEJZJ%c1~`N1a&6F*^Oy);zA}K060h-g zJ#6b+5Xlb~E)4tsMK?ngDmo6?YQ9j@96sFMt2el~67ur$hF|aR-HM8eLR$H4*Zm)k zo!jHO!te%aM)>JAdZMD}Yp4_H)!&csUWBJRFT2{!n-$L0xLSSfK;v8_8%Sh`J6dQM zxSG*f2_%?B_}@>jgBG?z5l0>a?&U|i)4B>zX>?M4B3G#K8aUhNF#$JVfZ4Bt4PDAm=5~NTL`)GAI=J{oh*CKNxoR15`~qB#?^>G-q@O zVenCKF1r}yt$06dkd~n`#o!yS@0V00+HQ2KM`iFhe*sh%us3e`B9TN7Ft$kDU+$4V zLT-{`W3f{BJ)1oaG*_^QIf|Oj`>3;eA8%FwUtgeA2kML;A)&q{gXRfhR-UdKuuxxM zbIdp`Sl<66eTuGJ%(NY1pAnv3s4@uR<2hfePPTPZ#4UEZcg&UlMa|nx%+C{8@s}QS8Ij?ovyGQSnc*w!7`LB95B+Ds6NUUK(@A zZwZ?>Spj=8tW3xXXlHty_r*I_{)0_ngyUMu&&?Pc*>CoVfAe_}|9VL;3s|8_;{9Oj zdbgESwiZr6NLV%q$a;R*Azxal10`9^Rd>0S4djLyqct7XFO!lPGvThkSETR`sM%X~lx`fD8RT7i2xS+wiBs|s%h{wzRsXt{L*q{A0J=57qT z9jaHhkOXc&UDAV^3ktqux*v17t_9%Hj}TflzSAQ{6PpKnwy^6!oG*qr2bvuZ-X9eC zf}aje1nB5g%j0z(_f=zzr2cmswIuC>3ScBU`>7mZck&aoIj>U@UAVHa^Mm9&mM@j> z!-Gc(x1+iL22}W>q#D@HmQK7lu@3FJ@lDixY3Wo-qo1Eno)b&ToBQWIpqk3=X33da zDIXTUIgn(tB24GuM}H2hVQ+LV$2=H~kV6>A`rEnuH+vz-4VO^o zHRo0NMa6>8iqAn~M;^2H3+#AQqs`>9n!6hRvW~%2tHpqA(^=~$#>0RQuT8N=59uTm z>8pT;EA0XdxWwjSH4&z?jEsr-l1Umrk9QBCs!fwka*#4f>-`BBQeFyd(?|s9Fz%$= zM>5uj8spD3+UByCb+SOUTTS5U7(R64vWWOS)Tm_AX>f3Grt8lZGzsg^vaV|%=S;F9 z4zEN7?qeP{sRcq>!4KyHM%#laIYP8%qXR!N1T3UQRZNXPXB;=}WcCt7@m(h`x*e3o z%m_U0$!=vm?PYD62tZQU*w}iZ%n7^??DG?ZthDG>TU3;|vL%@wafZA~Jo!$<0VQ7gwB|6$ zlF+%mY=nQb1HAG3XjnKy7u!=ZB_;OWffDpS6JzxFImLmlovU8y9W)0U45a|U93Nwh zD#>P8KPSXz4ec#}+5Dy&0&>k3D6 z+}Pzdcg?8w$0O_O94CQ>!lM$Evd}~CU%{_q%-r>d)46hB+2>ED4P9I>$3)AHYBK>| zXJO2pj801gTJ})6(g4V&f7COYtV-$<0Bxu2>f&iH*O0W#cxu}LOV`_-eOu4q* zPKL9F&`CHkPkq;rWAgi!T^k95?(iy|Zr&9y$WabPp``mfzvsQf-OBT$PKo#mWcjA_ zTM}EYA-CI)or^xGWCKoGFCw8Lba&m*PTVG8sKGi!L6^$j z!$@!|^ogviTS7>pH1of3uQa7 zt8{lX?4G^kSNl_L^1R2_An`Gg8vSjfg;$&q<(5t9nC`&0v8@w@5;Css$*!$TQusEJ z_C)D;y#+Ud&6bWAscR3fcT?F5+)Eb^J)138J!~&%94wZI1|qMFt^X#&f-JsMJRi0= zFBrPtU?bP@Lbj3l%ifSLW9~~O&MJM>K?kL-2~@XR-;$jBSqH8) zZ`umO4`VDi2ZgdH5Sz6+!d|5FHaS$3F3M9v25S}bRmIC6cJHfLES1*N)B!Ln_Y-b( zvm!S)NzT{(>?SwVvt6_vc>C(rXWw~m&(TY^t#$Y$hKUyj0@@s;62{aeU!cB?zLxR6 z{YlynwV&2y6`#oN-wJrOCa4Psv8HlbXT~QaP);^L4M=ZmUmUe)0gqiyndOXbJQAtL zC;{&7=rp! zE;a2YYB9wnK!FoSl`CE}gNb__2C0+zglW6pQpQ=jYqUP1cRPo4(+Wg$tiNkMPu5k1HP@QW&sMIH#@_ z@EQgbZ?Xt*zdyR~&Jw7UYvIr7f#87Pt1@eKe3_>!ooD4ki+5?9*0`R#n0(w?V~#W0 zCWyh8dlS^v816I_8O-LB-+Lb-(@jAOked^LHTbSz(fyiv$Hb*b?gvAgzp-&* zn@x?*w@`R2ey5LLD6~$rPVJ<+h;MWDqn;_h^&2p|(>Gl)_Te+p7z05-!yjDBsn^w3 zZg6v#Bw`I^RzTKqMMozF&gGHedZwy+hbZOs#Ni?F1~ly>4_g@~i21sj@d|Tp*Iz|! z)Dgk!d0)nLf9Wv>eJEvG_BfSY$t{V^$UcN#jQJZZvraO*R5_oC&%;R0Qnl{ZJ35whWa4A}h?>l{ zJCchP5L?o{=Zol3nF&vGCJ@)ZYIC=JLT4l6Ufo)>m%jEmmMzlzf8)b*CU$+z$H!$<1UALlH4sP>)OS`sJzDaHfHX z0`0V0X*sWc}u+f;p$a?rcOo~8Yc_lK0j?Xl6_JslyVD(=ew+D zTF4FOlJG?KE8^Q=@WreY-w%%(U_xYeNu(@XOc z;^DGTK$>oql9N-F4L-8jOuj-17H}|A(J(#c&2}0H1*EjqItusw!Wf+Ld{#AdFfe=(qzSjmakG}v_4pf{ZlbJ;B zjvZfvItG0*@6MM5tZV&%4&U?Es9p`m#~f9(EJftPA%qL!HC~K65OE%w5!iiVZNWVJ z(L@Z0{xG{G${C*UiptRB3klliyKYYK>%Dy(RjqeF1JS}-tqz2tk;N8d?GfEOE2G*G;B;Zr3pLRn7a1dg&X=P~rQQFEwL7nzxB|p?biJHXW z`<5cdrYHfDl(e)i=SRCw;jm0K`tJKN752+Q(r~4;`T1s?ti}{Tt5J@zX)`vj#qDZJ zmHfid`warO0@+Ot9i{VmyvhlSiSQ1p_Vj+B@$3skRzPfeOs;{()+oxgHZG zO(1>T6`j5(NdG2;XI3A-t3OkAkrTvB0JU{EZ=wFFGBoC9Xjs%Y5BacM|FRJsDn6Ac$X2lzPT# zV*E$1!PE)cX28%9otHXC8`AuO3UxU?)m7$37JP>5!_h_O-hr}vRKimEHE%-$+7X|Q zR!c#n4SIbK*HpdCO*`LJ-Hn<#>Cf%wfX-ae!5z1<+xtt)d#{w@i=*VMh^&*NUBILXhQpXQuPJNK8;%^v4@!{zOHQ}>LPsHqJ*`-P^#4p}op?MH1w=MV5_eD}*{T8X8G9T}^9lrP~izv80(Y^;&yF7R2}(R=nH|HK@IA zT2}h*cCxJBiwK=xFIW!@rm$`W5?V#mDi-vP=S!A#p!3Xb)lSI7?Upj#H1f^v@uF0{=1XW;SQ$MlGY}0wR7k_~dd%Eor2z`MrkGU%ci*0t)7ec6Cn1S~4aD@(ya9Uz_SMP#}lcM-T zmvBT#)AwYbuli>R7}1N!aTL~rE@zut`E8uf!$;$dR|d$${50P}g|Nz*e`clByGxNp zG?W%@hT~Hsnq(UJ>7tC6PXL)6awPUu>Ek-UOHf-QnD-6HOKG%z#3^VOh#KdIzZ2Fo z^Hd>RKopv-s_&h&7S9=40Bl_-yS$ zHT#T*^~iGKr?tzAUvXJrU+nU|Yr1A3sM}GbQ}@|#+XIk;Wh(q@GOIrW0l!jIY^lX@f_AVL|-YF^5PL@f!_s?XTHZn8xsXt0dQ z&eSRJKS<+O&AFLtG)_PmYAU02o_yQ4ce3b>n!($%RY%@?j#&0!(39_5 zJV<>EcW8c=nVLy7D9W&ATY-HfoK|!CMjkZeEO_y}>~p8Z>03&2K|H$9kj3Vi#j-Lp zcr&yeN|<#rbQERuS7*sb&;*(7_Urjh!?juqp!cF*yC$%C`b`-m!ZGN#k9(x}6?ASt z@jO-vLd#vZVi8O(oH(#8HLJJ&U_k&Wi`oAA86DcJ>MRx>NpxSez2fzy6k=n z+C0#CZpK;t2FrRM3?Ohg*Ll9uvAdqzHa1jBVKxXf?T)R0!nf<3oVZB<9V@;Zl`1M~ zsbtJPbA73`0kw1z`9B(z2rpi9@ zl;!VaQ3WUV!?D2XqQo-pTAVk4a-A~;_`p*y(bt;xOH(7!s!n|7!g`qo4ZufOLvPYQ zhYSmdpwj(*c7@1%;L5fU-WRQSv6)3#J5hTj)7Ai0>%gTIc*k5nx|_AUERx zF>cVO&6S!(n$>y{cO% zVz`fl5tjq9=IGSmLe9_c&AF_F{@9^C?`30FPI!H+C=`ZJ5 z+8O58S!^!&=!nkI+Ai!zIMZ!64CXNEkQ_yT;h=Y+a`L<=cDZI>7msBh*?Z#A)&Z?R zQtexu`qIXA!Po&(x_Of-oQUE3H*77tH-Z=VYs_=U4^+C1vmQDiM%~GX5$6_KUh=J;zJ7|eOfp}_1D_(&v4*|yZGC=% zD5#rR;bzi%-d|Q#w>?1GpWXYVD4bV38>S+49@g=ybvxng1@1S|%oKZiW5|uBOV!Ui z;4#$Zv<}^lcA&7O#1jIHb;Nz&DXwv`>L!i%zDQmR)5w|QzVlzUmXT_u{1hD^76 zLY(L%Bc@C6b=iExYUVtk_KN*xQA2=e;KcjcolY@=-x~^-JK2|+@ENZ>Y;$fwVMzT! z4sg#YEssWyD+C>-ak6yR4YrTvP?>&AP7KhLgpuXlG zkKg+V%u6vbPoz)m5FL<3gv`E*a8~;oc0H3y_!)`9uzG*f;{u6xVZRpC{5ZaS?|c-U z+Rn$=$xfK||mu7&;Z&eMKA}W;7*PoN(o5L@vKP`QpTQccBc6+&In=kv( z_TX_o6%;rzL)Yee{A)+qePu)jSh2{fvX?nyRsW5BCya3B4fV(;y06L)H!yM9tVUxe z?`;nXwPxsTpeA5uCe@%wNOgM9`^&>gyMbrB*y34xD#D-}=I#U*PfPFC4ed#fDdH&-SK0qGa_E`hu=<@0VcBC>@ZD$!MbYdslljP&$p~G`Vc}3l08S@G(q0X~= z30O05C^{Z0O=6Z)wou&W`C+i23hYA@EC6?qL2 z4w+GLvwv}6H=P>bq!{qg;%d$8SPINIk89bf#imMXX%0r5)@v;9lbdP zu;U92o^qAZif}G5-o+UNNtI~oT4@}NvdMQXct>vzvHa|c$Efrp^xMX3=wu*F^CLdI zlG6Qbb0jflfxEnpbgP5Deghu6YOYUaN&mR)yi+IIRqzv zvki)M-$^pq?rDFSM*m);RY+9gxE6o?Xki4!=geBoV2LS2eFY(wjow2(lo2e|qZFn- z`5I6xkYefZ4t^P-Q6QIxGF=iAE^V6W{*eTikW zxYC{Lr;SOj<8JrX<2poSXqJl=kl-g-{zlgKPPP%>=}VOCPxq7H=duDptpTC0z(K&% zS7#4-52}v^bzKqQyoEpuH;l%)X@|DOMj)5t!@`A^)4f{)a?c0s`PFXrt_XXkrHl5u z1Fj|S!UK@B_k+80n&AE~UA!oKT-KW(16`apmF(d$Ugb#BWwEQ*GZB^u^%yL&geL)Xm zEc)`-E6h_YfZe$x$WPk=8_j7fb{iw2%<-;A9oA1f{VI$R4NV>{<$vowQ)v zxcuGe7K)xl-ZNZW^`DH01u{tl6BW0DsjKB>SS*~Yb+W`jwppXzm$XmoGrwjUv|1_i zv8*iOSGid8x6ec=8m)|^;(ly51`-lr1@7bX?5!g6xKTFd^903{Y4MWXj~ zld(%hl{92{NOC!lW6<*CH#2FC1g$ntRkbnCMC3Ga3WpyCaD5FFo9bq#k~3@P8z4Y0 zIops{aJdfeZFQhp+?C{pOgUEnRY7sNJ}lh-2P-N5!Ag7fmFzp-py?@tRm0y(irsU} zk-<4GfT7vN?K{!_m8zH*2Ghz`VH`)6Fc#-=+y2PZyn6cRKRrBZZZ_Krv7L!}v$Ve>YIHSfj5D+b#F4=y`(UM zDx67?hrlYu25>;B#b0YeSRWf#B+N*4WH;-~RM#9iCBaRu`bgcTX%`X$Qr%H0&utYqe!tBe*&q^fQVTfK7f#GtNrkhNTlhX<3w8y0C9wa~FbpbjU zO+=HoPo=sr)}ao-8>;q;I1J!M^{p_GEtmuxhr>XMxVwg9n z%OIwkiZM0_E$GR1mB@L6kA&N6&`>dS2qmBF$x@TTdDHYPov2?9=hB0w@eCb#KN=`c z$xo*=nG+vpbxFB3ypC%);odP+-(8jGvDbao-?y~*hU z_vCwx{kVjd$K2gzj;a~|JrSQlZ?owyFz&~nU-(3dld?B1do(+ zAz=0bVJnc)X~73{%*3agc*0Os^=bAbNw@1A6y8`gbPjp!Du;f52x0Vvhm?H_$k_=2 zh=%ezI*$AJw}!+~p6rh#e-BX9*(`IDev!N#+VH$uu$D3y5qTR63XCs`$}$6jR1$`1 zGGj?%y#w*B7}Pa;q{Zg*Rzt9{9`nm{wc^;j+XqnP4gG9#!q8=v4gD0@YGgdd!g&x? zS7_?mpQRsi{AW6eHL3BZu?h)np%OE4eGP)9RGZ$U^Gp!@pm+0Z8?LQy z97}Roh?YKqQt8RmU*YR>=zjeb=1`*SqfO51J_)sDayW@Q|=Ph8a%v_EO{ zV1wb^LI?6pr z_}O-@k+mivW$Xi*Mib-)v?;7jHl8hV5ZN1QnQ-3QW|D{MwzqrqK4Ks?WY?WsecbRS zRlG9Hy?!$Mk1DDrIB`uF~C!ysShK+J02_Lb@Z=3Lr1#l2459 zEXV-*eT-!0Fri7t8S|(^2Z`u}30w2xFU8Lni ziqp1JmEW5oXWoyeI5bJJwrv|nCdiYCKXQ3OC{sYj0s8P>-2Lq82A`=GWIWCyiKxNA zwha?e;Erq>V;#Zj#1HSt&k*dOEtI1La^?EF@B&jGAYJ^;(!*+I%bF=Bnt6I|3Li#c z9yu<$L@ujVtSegD80csh$qXH05g+Q`Nbl@bldgOm&cwM`99!r*gIhN96Z&c9en!j<(>wz2+8-nS=1 zbbQ`MfL>Lhv+MXF)paO$tvo2K(0Mmb_HeKIqD^N!U*S?df9fBJ!W>Rn~1B&8NH=cTj~-1JZBqe!xns}2%PGB46Q>hZ_Qq!P9`0;6; zma|+H-?mhXyFt?){96t$h%A&>#?|NcK*bYR`4d5L2ME%m4jyNzAn$5a=dpvkd+HY= zL62xyyrn;R&?ABDdfZS6#OCfq{ksH8WXtvy>4jecokbINJzt;3f}8om<*ON3%+#x| zjm~-DfP-UIU$w7^pei#?c6xi>sndV?JeROr;}avnVNO7H5*5;u2(6#3J=#% z4R_1EbX;l(ZfT&YqmqHxKf)xNI~NWU7g zS=Wh?cGAAxzH)|%P;6ds12;W`y{{Ss@B8|mMH`z937VG~MSxkn1y$*jvi+M=eG ztV9^0r*o9I_DJir1&AoPj2XqUTKL~`mL+xc5K5_JqEVTav()+bJz>o^DH9Binl)>8 z*4isnq#1^2dWu(<{8InDl|^MCG(&^7Yi?6TJu41V2?xqlL?u$DU(XyLQrCZQ%?{#c zImpvwjP%86a{mrNB7CTB$%)P>-W; z(%(Vz)(+PVx4s`!IOlz9+;f&BLXi4rq=Yj_uvZym)YB}5gC*iQOvHL|sIU-P+XFQu z6w0GUMG~UcNyWq|+yZBj!Ugq{0Z#1qLgyLJOJs&lwy+Ix#T2{wajSFC{{wM&<=Y*x z{l!tMGORFL?%cXj+pZ@Z&)O`-B}{VAzR0vbL?f$01W(7+`>dx7hoybgvfN)rN&F*G zsCt*C+Twn8P%=vMY}l~F)FFSTG{`_$CmG~@0I9&_5CUn!s{3Xq2Bn?-sRQB>u{(Z4LhK&d#+^T+}7?L*6{K$vPwBNLO zC~DnX5^(x~D_-cN0`DDPWr7?#!qPme783Wl(w5<^>ev&ctM9C|D!4ChL8MEKf7;{3J+=)<`!#a5X5?tM%RAP+nyaD z#Ca5+Zf=W1E3a;qUH^_SK=gc zWC^8g794Z@1RBF|8^mmE?^Y=-#+$d$NmEKSw(Ar+B5qtd5bFF1Qv=cJ(l(BkG@(+J zIC{&CoI(%yCgDkh{ro$2+ciQa4MB@Wu>@LAt@X*aQq4Mc3$%ZkSs z|LICSL-C%!x>A>Ka25(bZ*pnH@v?@LV=lJQRRis@Wo}mX?o&bT57p_NLX=+FKSndP zv3TufQGd>HdR_H`p7$}xC$9YqWd*QJoy-^A-1$fTE+WpD$@~RDmrOqilvDL0GJ*9v zziVzT8Eto-#Y9U8%RIk>tXb2?y09S*NcuhZYRlw0BuzJ{uD5mCG4H;!xre=|-K|#2 z&ux&Lij>M&v4jUc_(tiGO;>0fgn)+_0dfJZGRJT8fU3Gr7y-%v;-D^-QYv$JR|`k z+h#1mJu$^eafXMmmW!kC{M4f0aAt%oN=@`qY-s?HEJWZag*|Pax;7=nSd!F3Z>e=( z@FtUI!thr7K~}5dK_6^&R>FL65Vl@oU0MB_l79C)K7(^zt_D^ODHNb{JfV;6Xr5w* z^ri5MNC?=sB*+Wapoq1@PM?hsb9QRUO5`1Td*Ri1HC6#HdC&5m1at=P?|(#qDGn*R z!v6)Tyx~Qzfy$EO?wRb_f5gK70jrE^#wG`TY&4Km>?ofhyx@PSLW1|akHdVS(Dq04 zlT^Iax4jcdU|=MK!kLNUKK3rc9Iu@!pL03Z0vlP0=*{yvCGvm=_J~+=&)=o1l#R*j}2B@U!-6X=2l7HjS$^}O`^*JOAZ59eWF{eVP*c_>iug#|8x zZaE?PuFFDG;w=5(m!`4R;w>RI2gdGD+AGG86jF|ZsfQ!m3;V6vT90W7Th15uNa(mH z-)*txpKO(g^~{o=Yw-(=8#iUs4Z8zP@5hPQVA-xJ+6||}%6@S=`Q7%vrDH>pNr6`-19L{?+!uO5@dr{8i8kN=Q^91u$I3N2(R?KQD#`_Wu&KS-sA~P*h zKLfZzyIurN4+?f~Z<)~YRJ!HwI+I94qiXE3e2l)zCp}7gdsCvkGt})dxHUOpfZ7#& zbuE{u0|y9I)~ySuyVE6%;$x6etsPyc-1_g=pJgI!^>t7@%UYtAvp7}JfT+k4Vl z6C)>dht%z%Q|=^=t5~+a_yrHO`qlI(Jvf44GPmKFiqU*^oef5^TEp=ud7(S%k$WrB zt*(JF5qq02*N{rb6e9wYlQ9i)VY zz3-FGcbBy}yilmkSSd^y;6kKe`>l z%3O83wPX4YH>=BBt?P_lFV3w};^3~-t3bztzP#pQ{5dh6gT0AYAJJ&BMg&lu+FOKQ zr6!2h77L$5K zfsVtlOSyOMVKb2dq^9egPV9DVJELh!HJNnRhMlR%K+$+T#iscBHYV{aTQ*XDepK3{ zrJKBV%&VpEC#yY13vR0O+kr0kDvpCWSMG@>COthGhXB}7wYK!_7qG(tSt{1?j*#o7 za7hpS@v#z|u^6QU`VuN}PhO)rN~mW z#X&08LUn+IE2=rhdUACUu@|Vi#0uOH2 zR`gL^A=T1N1)9ntp{B!f#{pfML30vITRhG;*UE~~d|Ap1DVL=d)53R~;o=!=Nvbo$ zU6T(R%ovVQ`WVpGBFOnLg@VIksLcM>FJFSsQl>E}^W&J1-onmA&6664Y2L8We)5LL ziMq|jiS^}lDZ-f5LN-KLY!PDU0|F%)ylHMf@^91-V>x0!YkQF98yWRK8{X+dAIuVa z$ed-*>jpwk#T9-anbR(bV>?44Wp>Gbh}in*F=$Q6e#C3!yk}#j^TkCjuzzK)>E|s< zLvHDGeVsvatUj!iX|b>}^+=-H07?lmcJPOHUs@1B}!{bctakNtG1aGW8!5+fkP_Q%@ zM0y%!l0=IGbRdn$vrV$?x*Gu7Mw!QiHA-N5{yvxr8~Lp)%~k!jvXKO^t5@1OTV_9R z2osZ&_AD+WgYRketD96UI8&;=I z!H}N5;xuXCIC=qu+KHE56eHCQi&7dc&UmXFzO0U9-0v+j40?{1gYq)}QM`%+aGm=Dgd*cUuF; zk$x(4?o696J7&J?Xd^>!WhHrV`M?uSdklni3?acxp$&)oLQOvaE2=jqo|XFJ4ZW&v zPvu(uod6(LDYRry)4FVg)nj3t z{DlB_MSq+)&4_?sI%)kw;40f$()NtR82Yxh%#>=&eK3q|PrPICy9M(^o3W1;e4Exe z1vQo8-wtb4og;IJu%WClKiT&HvYk}$b=TgviF&@JqPgpDF$sNYTzQ;zh}(;>t9N0s z=E+xd^skGz&pLGVx|^)4-z}NWjyFin+a5Oevt4<%W5wacR|Y%sQFFeMSnb7P>H_dD z8|+1U%kFY3vSMPF zh={2QH~T+3|Mb-R%{V-`K&n(qh#F@ec0CRq#mOU>3F5F>@G4>$+p^}@t~)q{20zlK z5A1#ZRKl~?@o*S>-3@47D#01JHx!4=B9{i2h=KS`wJ2k5yIRE$&`U*QGB0XEjLA*C zR#7Lxz+LtQuyNDxG6sTgvfem49B*Ku&1jg&0nBqibOb`jP<`Tw%Kub@@Ba@k09h?7 ztK0Sf&DU&ktzyq_JaJ(Z( z7A$!ufy>nsMKi+bMhy|UHmp#o>-2Um>w4@=JSQ?kw}3ENk!FM98G(&(Tia?MYhd4D zy%Z08y zO0ob@UL4@QtW`CyvK^r;wUe%rQi<({Lh2+eFRwZ^6G0fH8pjAduo74tbYuRpkca!` zu%vr@PjD&P7F(iGwh(vE-0U>XF^plpbJA?xkyTM^iO*N^{`1I+csP|{;w{C|%k-PQ zEqvy|*FCh#pKfPJ>0Yf&uPjBr+-9vWHqD&-GV+wagCJr%Q(2RchKk{}C5d_*m$)Qx zOjN1rmO-@%aX!QEs%dJN99|0N$H!d!~-i`&NP6E3V6PEqcI{-aCIsloZ zH;%T))gvy8P9JZ00GxGAWkO&3tW2Y(afiNaz^2_K&TUg}Bpt0#d-v*SiTsf=k+8Jy zt(4Wc?&$Xd`j%cwWFQ!cV7p}K!Jrjw)Z-wObKymwED0_c(9OYNRkMU7YKeguD6t1@ zdT8Tu;6#s)@u1^{uCHmWrappz`rIl8qo}3$Fz?|pFl8p#(oK_Bo^*4;FOLG1W9T(C zd$n}hHtT^WAp$pPZ0OwsAQk!MHbjCn-9Vx*YhspCcY~s?GN&M7;e19S`Tk+UEq~R! zU^3aXC1Vbe*_s<*j)@%q;Dk=FB2kk!8jR*y#bA(gcIhLsTmN`+u}u`L$|!cc9lk9Q zJY{c{Bx|4xt)TGDEjQ0;3EQe!PPkha3Oey@(AXF8H0Fxw;>vioYujQ|i5UL-j=v5< zAv@JeD@pJHn)g67G?L!bM!YpK8S9@N=n}9`5F8-x2G4KTx>H@fk+3p;AzBh^>Z~!d zWnm0(UDTerE+aO%Yzs46fi4tD%{k1raAa9^lS~Oid0{t=ZxW8g@g6W4o~X|faN$9z zmOW@%&12hk_-9W|^(cM#%AkE6X=WE+{zqP;A@-YRzCvLM<&n!n;pq{Latqwd(#wIZ zdRO?uBE*ui(IK0Xo5f}N)RVf+2F?5<4@OyIF7mlstiDB@zof4@(1nYiNn2>qR4%cM z{f%Zzn|>1+4-ryY?4NhRXhT+0U-Uh z5}od`5etj(gm45JfU~N(yQBJbL)#l+=o&2WPih72_fst~u1zJgRV&W1E*~oZf)EX- zgHJOR2BGU48$E!aHajhi8xE5hH+nNPO9MH?p@%58l9eXAxmn{qmD^W23w#7}I*!^%@+U98Kz0$OgF z-ud~2S)?}u!5C60kXca-7}nvo^!*Z|MT)Op@uGhimZru&BR90tdY4*BH{`RW?Jd?;-wK&y1^&w#6wh( z(o(PchgX{0&3t$0_|SKPKQ#sH^ib1yP{&{4@G>o}IZ|!ksrY?|O4LMc>dD*k)DU97 zaUf>SYadzL)CY}nn*47W7-Ec(`J82W^2BWHPWf(Q{enz3BwBUqieU&FDZO&ms@1&6w(sHX1Ra!9}OKDSzM&M`jDcU6%7 zb8P{96d901(mi?oL5UUCGuiXS-BphuXBzzQ@obP5t@144@hSi32gLJ;6b@sXB<{@z zo2Iqf!Ib*49}vinft++j6rg56bubb{4rtD4paAAoF1UbjYboe)5 zGh}JXsLn38qIYIvgord#B(QP_XUBSr*{mX76}k!r^}EfVaC_M?sa0z9ap~Ywvj!p8 zu3hJ((@|>mJZsoxhJB0JY>|PxzNj6^B7%b@H@`17s}AVofW$%qReWxFc*`Bwk|h4v zlHx53=j)qu9hz$`B`l6HD;v^1T$W(KxQjE9Q0Xs>ciItL5!NOZ@uwV->-KzpAf*rapS^zNO9h@ zs~7|PNTBS;D(go-TWyl~33H^`-lhN~ky9D`JCD3Sjq762aA_rFsR17r& zA_xWBL>THuKvKW~hsCN3v2BQRz>PbQatbJDl>4kz7g{b`?2g8F@U6e&nN+~x$m@>k z!K2Z&I});CpO}m=8md}flMZBM-o?}DeUlG81O>w3RM{S=kQ<7C6crU!f$Cc2p;&T8 zAS82Ms%fmT@A@!am|!Tj$pw)kN6w$B8Gj;X{9zqoD8hZza6!{bdHZ3aCA%t;nq-@( z4#tX2D6J2?F^R1@7Uft*9yJW-X^Hs8Pb!qbOvcVjYFC0WenU01@0HtV#-JV>?yE`>( z*SitP6N4eA)vQMZ!qZT(-UxeXpNg}Z!`|EPWXBTfcG^#6JdCHs$I~11F1LDZ_@HW( zf*J3#enJ3-7La-vL!iu@9c%%f4%~n$)TpI0U<*e7h?gCLtja{Ap-00CHfPRi#qO77z_1Hvx(kg%`n8zg6c9b1r@51QilxmxI~2bUJ34x7AR6X(QR1q@OW$!G#kcz0JvCbZ?RNF zD#8ulBM(ewc;F|X=MC-Tx1*!+fr&YPQNL3c)ZyvDx^aHO0V4x zMIN01SC9p)9&^3dCu;)q-TbJqP!4OsOzZb&L$RMT1(iLB(V;T#MwZcF5k`Xka5AV` zde#Hnjd7!^a{|Jd?cGAHREBARyW*Ghvs|!-BkrgsU2|qFlz_>M$U+rmN#p4^@kGXf zH*F*7Y1Ulz!JK=S=(?GDfZqA^X2?y$_Grq_^kM{J}yZR>rIu!1527r=Lt;*QUf)SI5Onr1<(YTqR%c0^q5>HTf*>ml;{jFWb}0|~czP>dg5E}cL2)@}9(jzNj493BxnKKp)wE}zc z3}O7Q#2CZ^-xo>M)QGvbG@&GA9E>&xq0x7K@w&8FZ4Xdjn|MgJTP$M=aG0#GY?{S} z6(4zsj*aaDBuZb3a+Q@Clmr5)#?tT>V&6+(VsZYd4B=cW7`m1ZEq*37=lJ`rb#5 zvyB=%$%qZrkRD%-iSj$)$Q+imjj>qMyAm&(V{e@yqAsAePS$PWdH4 z5n8XHU+YN3A%bvE+5uj;bzGX(PhXe<%uTnrt!nzL zbp}_IR~oWe&t1D3VxbcvgBZF6y*wGxa`N-Z=n6mIJN9VIwNlT<+G8Bpl{b?V_&NLu zxBXMb_s1=(CDnZ0WEd6*kZwn|TBv5oLG|n>*lCF->4%3T!`WaO`#}oZ_2If%EWPEUQS`uD3lF zIk&B=tDEfG{z`Fad7xNsvdnW3z{w06Fbl7u51d1e0qz{@R1Hg zVx5}6L!vxlYxpA&&S^X$gNG5IO=X61A`Kv9##=+eVSaqpN_g6;$fEB3t2pr2E5u#S z;Vw@@Wx5htfSLwVr(5ng#2kXsZE)9@PzKzuqDj}sQXebdy|1Q<3~O@L)64!e9*Tu9 ziXKZK6rxl>0;5v4SN4kYSq%@!0a=uB#R4&^N_p#T1WOFAO6u!X0K1p@ee6oN9xx4S zLwu4xV0kOjid865(bG#S^Ri^n3DS>bc{m@-uB;sIQI|pe6XE_Z&pPndG zkNmY;E6D0PDn@=>b-kOSS6c((lQC}&40wRAPr2Tdn`{mxG zb#`s-w2HdlOHuiKz03N%$-ed*Tj?;kDF%nrb^XL?wPC3WjB2fPAUE)XL(ZPjI8UF^ zm@HBy0p!22byi!VLe;sj>YB)ZB4hkD{P8d)Oyi-hQD@G=xQHvZtp>oIWEb#hE-(@B z=Lo{A<)M1JloNe_w8m_S(71|SjJ^aQ_lxbXII6s{pQ$v8L=jI{7S9on*FH!CB<_x; zR8E0S{TekJF?xgOwuzsddc*MIuU^grx|xwKKvi3m2GpeN`54FtZZGyWfJJ-=Q&{D1 zi~@mKV4db(^XjUj7y*b1Uk{jo?V%r_4UU)uK?DRUGB-9on{wpAE032&7u*Ww^aCpYu3$ z{?j}u7g4}_WBAZkGKrZs0#E;BwZn3md#u)B1ZA(3-JS>{g-%2#4kzVmc4J7)0}ueUJ=;_vL4j*0Gy_56vjdYZun8$3 z$n>`{HkbOj=I7;w|MY|J8ehF|EV5b#40tNaYx$|i&v+}I3`g+dKK{)z0#wEAP&9=z z4;|Nc>^h+hZNp886@GeS?#?26W=NDwy=3S0A6{%>|}dv%;@bt^F}!&xc>U z!3q)H^82Y}{0MB2*cDCs1kWMVdIu_~(o+xHX`hxHfrNxah=KeYr2jh<6y+Ji)3Y<3 z>H%NWS+0YMOR2lFT&@R^Tfo}F$HzwjH&kEd^G`9VI{wNb$#<}DqiLwH_70ab29#HT zIfBZJDnmsm9O!(}>8J+~em4CFJ7MAqAv{& z7xnd~j2OV;iPBzDkMPYCVsLhwT4-pbaKukqiHHRBCo)L^p&2Qli9{OM&VX+)H1Ddl zSkncva0PQejwRQ@fq^P8mFKkr!pBh4KW21P<{w(IgzBlGYJ-dMl}v>a4U-EqzymOx z%J4E4Fl1uWkIU_DW0W*p4uV89k`C0r7|}`R5w?9^Wdyvm{|GR*I|sosJp>ZU3_63* zLLio=@7B@&{+ftihW6|t4CX+NO@^QhC!VPE_VuaHSWKj1hxvB7;>g-PCSQrpY#oKh zcfo9dTMOe4Y+J6jLyvI3$7&OPMXDmpKqExoV2CTBNMQp|P=|*#Ax;cCQJ4ZXJZ(S; zSV9#8?WhC$8Or+SA5h-CYp33{c@1q|w2NzK>-C$3`(GAE?gYSeNd)=Z1Oi|YhrXUM z!=FL_t+Luoo#U97esMdK;2UHe!&cr)CSV{B{c}p;|Kk$&d?NsJhDPNv8T4=e`HTPW zf87yrmwm?mx*Gnwdx~2C4rSky|5HHcZ}OIZPAe$;70iFW`3nf~*SFndz>ZM9Yd)g% zx7Yc+{Q9qd<==fJ$Z&g=Pk{^oi-`hm$tWEBEI z$wG>tRv~%L^LL;4-&+|0O_TMR4rLSXU!I-+o5H{Tq+1AV-)K&Th9CYWEcwU!&rJu+ zyofv+`2TL~xN&tLEa|HC7z$OP)+Lf>C~rkb5V_O#pv@n49lN5i|MPk3hPsn{6}@DL zjj^rd77!2+I*NGs&!6~b8Zht%xDgfX6#Rd4r~h#o-3%{%8G0)TBGL~4@6e&)m=TKq zYI1Iy0t?fQsZi46-$bGR7!YMDKrs@7!<`WN>uCJ*?Ei7MfnTv^0&aNy9Aa+Eza0GC zFaGZ_?ifJU6tVF-Z1c}b=70NXz&g=A_RzL{hx)&p0%03K$fA4mGVA8w{>eZ62e%zE z;G^1rWpVpo+70X00drE>^@S1Ve|JK|3&2wQ{|~``niKzD9D;RShr2OT*V;pGaQLIh zFwT59vC>n2VTo+-U1LHuMFOO^!pz%d`9rY;*q~zjH-YW4()f$3*sD7uLe6?F9aDB; z_5(jy>Ph;s@C%8w zAgp&fW(fJLWWn-%*%oV-#_=@@^xx6S#3F%}~`tHcQH&(}+$86pGqjalMHh^SIJFs%Xe z99_ZK$Q7FK7auC-;lfAgvq-12ca%Y0@@7qN*aczBr;6E&?3TB0!{*0^VjD%a;_<@2 z*&x69?^Y6bcRny>jAJA^G&OWi`=8(q6aWdz^<%x#jA{mbWt@*KRABKGgUOcJ$Z$-K zkxR9x8h_xYrT#z)Ci3K|4`FLzkE zFy5_Gl5U1LAek925Q}8e?yV9obeS-&H{oz|!Ni@4`UBTe(@~@2MSeb$e2vO> zgY87q5!Ke>l~aw1z*5Q3OqNueb4{Fo2UpS~cj>C7BFfn|(s$79D;Jn?@(09Fnn5;k zx??1-6I1kquVZ-dU(;qB+(m9Nryh9fT5=WZK`xSx8g4wIF&Y#biu2#wP&?Bh35bz! zU;gs)D8rMMk--NN3be@Rm>6Fhz+qbX&KpbHr@5Jvl#J}#M96?1UA%5wb{Wrrvamb& zUtgMP$jnaQ)J+S!v>PO&O&dliQQtENW5fYwu0)ddxA)_MePyj$s>38y<^gtHHoClL zm)dp4A=P`1PK)y&o6JmN$^$uZHxw5sWMpCn$oBsF_y6Y`HRlnxcXq;`Exren*#M|m z04cyb3V<`$dm^7cYYya64nQKG zT~_v4^Hqw$?%rN@dO8nP<1uf|`@I&xe0v7)c5YAutlTJ+N`EAbo&vtWfFFpE+5+H+ z%SO>Em4K%a_5%9XR}vzafzL7oZ}?!Y>&Ko;eRybXBtuzoIqePZlGWWJID*2j2g7}7 zm=gnWlnh3y%Y=d@_YC^@PCf+^P09xA!mW;XcM+piB0p)GF3RPcmvsjB0*`*!{W4a6 zjNXS-a9q=8+jm|I|Dy7O0S%+3-zbb6K}cqdI(x=4D%Ry4T;B+Z zDvN4zMeL(~3s)Jt>EK1ktSC-O0^2N!jAS*V$lb#e84>#K_tT%L5uURm7BG#(zs^qJ zhzGsoi$&#UKX2)Muuw7pQiy~`Chkt>^IHe-ZA2&#E=}I|?_q$yb9ND0io$X{L|$pB zwEkccX@&kk#O0-}hctuvK)kD z4-{0AO2Gr&x1v-{>pGwn&0&W~#bT+V0b@}`+#ru_T>y3f(|UvCO+3VTS4h5g@a+9c zBo^a6b>y^k_w1%^t)bG^tE2_E7E)P%_NZTL+DtH3o2dt?ea6@k>g+pI(I5yySW4^pkAkBOjQ`myL;|c#EtFUQIGNOCp)tacnBs7(qNP6LcR39cJ%SJCD3r7PRw5em%VI!dioVj;c*6B=L6%9U_(oE|5dRh)2CS>lxh#PMr%{DM{ z>>Ogfjr%tX96JKHFkTi=X#hGP^weh=jpg`UOyZ!BNTs~pTe%@p^<;_@iS$L?MN9W* zWo6CE%M(GE?T+yI*!HQ75U&yusj;0qNM{Fl=&9Z!7iYG8FgB0`Bjo<&Wp0bm{XoK? z)A*=625t28xFoVfdXJy|;uIm)Ko#;4sq5lc6p510col-Q`RT{nK=lwU{^HW6V92^Y zl;yyDBk>oWh8#^wqmAy{VL0+;jyURL$hFDzjb^?h(YcyO-h9qS2-2is&8GO@J}+TE z;*huZ_oJ$-8JUiN+J@C24ocxVQX~IeJ8U}TZZgqgh)pA4?OzPPZ)aoE(V*Mp8war( zlahkXV!a&(bR_D#pg*EIMyN1fX)DxG7Ww7+fGehXgbsp%r*`Rr`#!uzO*CRZzb7b% zxmt;DZ?z$J=uLSj13{RuwgFDgbJ$L5YK|-1Lx+v$ui52;|1IkC)~KfHhYe7J)TzVrCr73I+e2Y6BXhy{fN#Joo5 zlE(0+xtg~MZ3GcBk`aps6L9%t~bua#a!5;=@{+9Qq-6TT{7#u{t1 zGm)|nPsT!zM25$08pcu=p>P}Y5`qkM9Q=TX_QR0?&4&XB_Q#aruFiU8HMZSCj+se( zlch)Fyygd{Y{U0YqusI_Y`@v;!hR?raYJREo?4R7vDoa&4d!K<08A*jyNRi(=e>CW z@NCf;92PL_i%xOeB{ecLvm1z2w~YtP8ij}f!#Ud}z}NHZbSYkA$oo>;bH5*YM~h9T zk5?_A(#e>Z_fx?uK^c`wzu5~sDnfstT^z5nH#k4x5atyd;eFhhGVitL5!SAw&P24C z0S)Q|R{LP9dX`^sE!bA*)J5iOV|Jf#6%L#l&dgd+f6P6U@~gdTZ_4QfOijA74(>pi zxv>>T^c^U_nX5mXeBGgyaFKWn)4uKiGgYhVLI?t!Iwm7Mq!7*l1WHX}cc4>2iJ{F6 zkbU+I20AK;BR8b2aciShCVq#=Kr0+;Z1_>oKVN4x;`7`2vP?l_-U&|KlY>0!8tZ7g zv-`FkU*p}X4}k`mHrV@iIYG2KCoS;a)+bza9^l6nt+cN_y*v#URVPp&?{Xi8^75)K zt2hDmIBOFsydflfQd84SdL1Hii!mQ73P6d^2S4TuMllw|LN8;Luo@wG9 z{@`_}o^c-`rW6DZBQFHtR1r$9=WCoW6l~YjQ-8QhcQO-VU?kLd@Eq!UJuJ^&z;~v9 zDZTO1(%RfQJG&Jv>>I#$DUt}0zsP+Gd?z>It)ujt8234f7$Gjz?s!A;j^|^VdV{UV z=g;BKL7s!k^Rn`Fu3Cb1rA~1SNEEV)i>cI*c;Bc4sY1D4-+K?ujj}H6NWH$89>6yg zTpI;S8ekw$9#=;Q6Si3>7#bRe0d`3w{yf6?-qg>o?R#zj^#rxId$XGM1anWl);#^0 zUIdWOCQ4`6Tf9*yevKc2BS|*kof^j(Ez5=tcR0Y3rKSbpiEK~*dBV>@q72D0R*i}B z?yxyEM)tvl#SrdJ`KdowyBh4Sm@oe;QQxPqh(s8c2xu*eF4ob>qsf@vEy(PqR=7eZ zC$u#$wu-wWSp^e2H}x-^4+7zB^qWy62XOX0zgs$w7fD{U_B@vYo9_-Ifkk=-Xw~A> zapVkCy(|IVOlN`KK*A@gC$@^54|>T=u^PRRaHK24gTA6IPCz~r>ZXi z2GU909jrh{9k%cRppTHgyt0+QDz1H*+~?1D^ag{KVw=BR=?q9cXceWbIW0oZvF6t* zu@M~Y%Y<;1K0o*&hx4CGSFTp!!Bs#@gsp945%6GBs@6Sc<}I3 z>!Zb+G^`^hXhhoeL=Y@S+`v_at|NbKY<0ETtAep!>Q$v2LN`lMb0>vquUMaQUnbF- z^t*`19lX<<8>n2(0}v$&_+o5a)VpzfZaF5wB%-IMr{Yo_2oSyux2HFVGgIE;o|*l`pI^s3bW+VAa-q1BbH{WyGUa_^#OPd1 zl&)FJ`AYP0Mt<8W7%2s57`_XNBC4peNqW@edyyG$e9}}oYsLktDbe3dmJn_;vy#f{ zYEdbvP;Mx%Dd`RZC{^z=gjVh!bmJDj%|L20J2$s54Y-IEV9U4yy-UPoWh3{T=1gj! z+lXkxe-}-A9YN;?N5Ly8|UkUNDg0x^|O$= zcTgj24W0E>!Otof0q3551-8$_h`bsQBdC z77S3hh4Oog*ha33K2&~4^*Z;D!UH}exzO;Va-xT$TnDamAjchEU5JIUqg%%avb5F$ z#SoLjs9vKEnVQn^0MHv5?384O=HHIi+t3&6tb z?Lye@xOi&sly4x7zWH!PCPqV9=iZXlqZ#k_?a{kCucl#r9YZ~0TMl4C z+)Qg!JZxMB)?1f7#Fn|)5NI0sf|2Y`2|wwAWM<(mMCV$uFV1B?UZBc#w-f2f&=98% zvcJfL{!Ie%!2lc`17ibl!G}}ydD3rrZm9!g%34@3zZpMnFasu!5iXgdotQx(x9_hX z54)E}JP`#5cd*5BTHnZpy3;-KDFG7qFd6&aIPu&IfYmi*g5MbjJ%KwPMtWdwX4KL_}JRsl9OfTCw| z?6LpbUBrA6;iL2k|M@h>5zLYEy5DHkN}hECZ73S^&{f2XrGWtXWr&|KF(W*8%2>Yb z`z*Ac6AqC^N0L7>ss{+V($0J$A$ngGl7Cs6L}Kt`iVQ3a7APjwu`jJ|J#4uzH_l%D z$rWpBcGJx4dS6S=0dMVh0O`@U(wxm zK_FyWKP^ymkn6>&QTkk1cVV!1t{9+~ZFlFuu~ap&O;><@+V(VKk=+*`yoVmLxganJUZJ zS?CR{74L7JhF=3KW>~OHGW#9pO+1_gsMpt<6X1bWmdh)I(rMeRZn!V}$-$E}AQ|tI z>&4DoVEvgi~9t)HYRN+NJ5 z^Yz80%vz%Qr~?CD1*bG65!v8}lDtfE(xILUw744W+IJ*O*&NI-5m1}%Sq|lvWe-7f;@&Hjm5NVNP)4@# z&h0oPGZxVHKlS$|TQ1wT1xWAiH69!0eGAQQ|AaK;fLljd*G&S(yky1kybS1C+#a;v&fuHFH!=j99CMDsN-tN2<#0+)|F1^zo)bl|W? zjOHtcpCZy%E>X=d&m zUnYW6e=6op8Eb;OKFuKOwxIvN?gkJ0?~rye&~;gKz9xM88EZ|L35`J;L@F z6vWfP+}uWym&xF=mD#7>r-u%`a%V{s4PxPZKA+A`!K>ZfQv-V-NTf3wCCn=+nc@l> ze8MTIsj7O0>ncDhtk*bDTN{E#>q&StUr6}XsoBx&*`Xy*4j4cq30INB1aEdn2fJxI z#lY?(OD%_c+95qMa5HOc#o(10j<0LoTgl%hAu>Ir?FAQgm9RXTVxBrZDXG?!7uRke zpFle#dvOP1Z(}>>NL-~GiSN%`V~R_huZp*)mYBlsf0s5xnREZSKs~cbk70_=6fc?U zkikZJhiw!dZ(NXV`*?l*I$dn)++c~7C~Jn>LhgE0zlFQY7|on-W^i1!M2)I0>L6C?vj9MfpMt zjLyeIArH8ix?znNT(~_xL^(UU@S3(1ch+xy5)w}5YCh9VIL^r^6yl?KqSqc>pFh zs^{rO%|+v2Yi{~*p}}V9vQJ)7J=$!{pooKx#TW+*^|yH1KVqGbA51ATIN#KzN3z`- zpYF)qS=2|wgoOMW0rvml#6mLbSfIAw@kZm>U?k9#NK}4e=i#LjfFb}$2oKOEgZ$v& z5q`wt@r~AiUaUGXkRAm|CdZ!A53v*6T^?9f1B!&bM@>c?U#S#!Qh2WWQb^E=fl|%9 zWuSN*4c@?csN1~`$*xF2zl8_addDrK*dMI|fi&I*XnYOdfQo|B15`@%0B#)6)|4GU z7}>|>0PUOmYjE-B>LCEEkz;a6zr3e`yZUAUNU6}i-_;sopghB%4d;!w5nSnZHE6Qn z-1n=4>Yr1|1?CDd*BKd^8(_<&-ChL7gQ1V>;~eb{#O& ziceVcjdVf(WEgKO^-xQ0?DyFC{8O--c@rDU0Ra@P>x?xrxSPRDN-!yE1W_LMGoe({ zu&d&3Q4I6C~*GbzBTBM9cu)} zn*``aX3L9;{8d*RL5>^h3`o8E0Ge^~_Qq-;HFmh)#p0rd!~IFu1|Vt#3#CG^<1V!T zAPL%&?%671J%E^67elvy3)tT)E&{Cp&DEqruMBY%f=XZLBe-+Z=#pXx&7Wyn%`&q` zrW2n1@M)jVY0HpJdubGB(S(YzeNn;tLpM-RBJN zV5exN;!1Jks{aJtlw6yu*{#C#^_DzwDSF}0z%SB%59^FkM`;3TSgyr<-{hDri8-3S zE-X;OKTuq}daQAE^;EMHal~xRXalQrwDB32N9m1ib{$>l9iz7Ere0Dau$e&LG7R%J z7xDR`lLr17b`y;PPdCtKI6ed0&^G}$ij)j}-j&LU0E=tXV#MbDU_l~%T2GKK{Qks% zSVUf+-Yz+>clC;sg=dyEvYhsK{HzLxp)X%RPewUqk?9MY3U;pwQ+_U*e=5a;K{7p6 zetaQbj_XxO0G+XD!2R7T%HqA2`6-H63UU~(3P#QpcsR5>R2QaWT*d{RjAr=97`8e79Zya0ZQ z@;t1Pxt$bwo1KTKuKbQ>l;XBGj$Cc(C=wVMNT3D=1|$nT5Cmr;93XjW(+%5>9sm|P zl^;CLdnj3;CFutf>`K7DMUceS2tdW2o8m09bdCm6H*fQQLI?-wx@P>I=oNY_;OGGC z*vKaIT!rIa4kzcS1+(Y}$m7}7w#PJ|0U=dB@{VQ^P_Bb-nrJ_G?pJw|Uuog!{+hg?Z!6F z;0nx17#-Rk?7@0ZifZmG`l+LdMxV}Aj%_{DQ;=uuv{kT1HI8VvM=s!>{pe0rx`lRZ zCs&0zdLRT}G(1mY%|8P_oVl>v3(ADw_wD%>;}=74nRJlm743D?=u-HjX0D%cw&Ybt zLKdcTzQi}v@6luz3YNs9Ub~cCqqpQ_^zBrWzRnY?baf^s(f8XswmTC3?AN@0&Zmw? z+Ay9d-X%OL><#>`XIsSGp`Z5O@t%BL8Y4IsJ@;)qy6J z4W&CXi0Q_6SvYA$&-?5VoL$sV50PRBCZ$u1Zqstd)TKVNS^0?2srjgAXWQ3I0Btl{ z%7qX}Aw8#(aCBmP*n89)g6YvxM?gt+n2|v+^syyV91iQqD&5Dmx{CZDKIM>u zvl6cg#F_7eM`c?E<%~&zxof#Mw77F(=mH6)k(6pQCtODB)uD4dn%f> z>eZv%)#V%qRn$c4qhOOSDtTDRL#c9y<_bKegRz;^^^H;q+%I*AtL`AO) zSW2&?ONz5Wo8pufso_%2-&JzN`_;q}UjCj6@PE1E4;Im7UE|QNvlE0)Qr4nUW->Vv zA0tifR5uJ|FQxf>p)+F5zI11D)#>EPZ}j8&+dr4|sc|L|@l2mF)U8&CMa8h?cwL~+ zH-JOO(0qm81!xUPajQVbD+GT<-vo+61m0Et4yq5K=7J4&N49O@fLdyUNEeQuAvrnu zxy@l-ff(12f5{EdqT8Am+u!A|b}i)P(=_@OJaMfbc}b(pVbj%OZ5r1Sx8NvVOaj|94{cP+RT7BsZ8Ft#bT>I`v1KYgG&}+x#Q&urat*6+yPf-SCaM-5%my3aveMZ zVNUOB3t)G@QF- zTh@n&+QEtpS#jA?t{>@B(yH+My0D@As+-ojzNg?*21AxqLJQh^3=0U~x_mBH`b>qQ z=W|OIHhAdjAUanbknKx{($3*#ZIIcR=b2#0I+GOT$7Ibs#Nu}0<7+;onz~KTW=n?m zbiWoO9p=RejWVEVa;aQuF;ZX44WnIA;=C4xDNifIaKJiDZvU`K`8Ii?)i>#qU9l|R2M`;OK<9w=CJvEr?3Pai)`zM2m~SP7I`+D} z87O}i>KqH;fErPOzTRUw5>}vlTGY1T~g~kSJeJkqI`Ptp2*8ny30GX{vS9GmCL|ZHh zxkBv{2iNto7ZR-AD>MA(w%EvuZ#%{UeI8peuQ}YRy_Z(j>~4?a=m6>JS9M=Czfut> zJ?}a|15W@Tp6I939;`sH3TR~VkYA{~-fYMy$78Q(rTm;(I z9f4Cb3%M_oq~u7Y9u9uMwXfUG2%JY>bukY%2;mfF4&=Vht02lwt=-g`;7|n(R%X2Z zB5CBVhCE2wbo@g-pP75Fl5!ZPma#G`ByCM^2@KIa+mK}#-ajfvY{n;6bY(qHChfK6 zD`IuIay}0CN(PbgY-NzdsNH#K3gl&eTx$s|3zB}7Q@6&-7g;l)ue2tJr&a7*LriH2 zuIyTFB+rUhujpX(dsD}-Ij!UjmJ$b; zQg16CkFb({;2Y>;d+n6n(8U**p=Fq_qh(2_Nakq{xHe|Z$LQ_7GD9>oye75huhZno z>z6A*89`uYySnPG!8s|O7~c9BE8l~E@y2S~zRkhg!6nwWm~|vKBUtt{7IaM2`aa(v zhI(FO%bWhmUaBI|_OMdB?&8bQX;CxP#o5Z>T_RsuUvxpQ-oU8k#e3Q1c65Y>XMhX9 z5b|qckm_gJR7aSx!!j?hSAzZiOF0-Z1{fYY0 z)ETS(5Paug?=CWsuyATP=AE2{QjI@IieB|e^Ac&5tj|(swvxMs{%rF72$3EbrtpRN zBh1VNCyFb3L$)lV*%6YxU|t^P;%gKxsmD{c+_o);o*O-~oILZp(~D#dbcMo&gFddt zvn=j&?X%9QP#XDx-6AOLNC2F}?;s<~SA?gXsK<8ZWR(Ng=dECo4cs7@x*mGXt0904 z{u!a+-CozGEYmpDA$&T)3gXUOXr-ZHp=;~o^(Ky_P3q0|w3=S+s2AOAGgM}3fD(e+ zY5iWYnAH?&l^6BlbHd2ouC2}I+`0f*Hq2Z0QKA*U$5V6I&C4C#^gMp*(nwtw%pbUZ-1TKv$=@-Wpvw8QqWUa6`9+Nja|~zp{aLb?%C9S6Y$NNa%}zRD2=b78w6!0v@ZXvbzz9TJ9| zfzT^la+4C$0A&VgmYj@izM^vmGR3Can??#@lR~A^aM|kctJjdZ`Yovf_WQ90;G_Q! zWp5b}N4Re32Dji4g1cLSyAzz??h+ulJB_;pcL*-Q39gM>AV6?;cN&*lnLB%*nKOI# zIrFc&`d4?=XYae#vrgg|;jfhhDy{-C<#FxEZQaa4ZaMTHCO=KX8f7KNQ}Tk}+N6ml zL3-65mq278*r9l;W4hO8&-#a-z8*17U5&^k%-74!rDb%d+JeEQ>r-o}EGo}~n=jzb z&4)M%`;9DCQsoH*;=|hB8$^FC-d4lqg1SAt(GwXR&Ybe4pigt^-8I$S8$XGI^WnXz z4{Q5TKZ!R7G`zjVjX&8O0S9aExw{!lB)aYY@fNtOM@#qH8JY=Mo&UW?sH;Me?>T*S zTTs|gVA#=}G@R<^nIEb%j011uRlgLXFj?<)zrs&b7}65pzr$`QwA-_OJU{m%hcRKi zcK}DQrt787}GAHt9lQTz!q<|KQDk{89Iq};t{C)Xk`d6z{tJBoUP4go{E3^qQqfnRR$Reh^w_p@lVT`_t zE(+f@?Jm80@rMP!mj;$OpOb#vOG!wM3DVO*{_RrR_eH{2KU z3S3x*i{J_9=8SbXikiDU7*jH)r5_tb->SMQRQygClS*SfIWy)wk!Q&WXckLL>4 zbfZ3>OWx;&kvJJT>;ZKcwQbd6dCYMB_1W_n?p24tcYR%ByO9_y_!s8bc5f!ppvC~< z#JWJ8z{}khR!n9D>%(7_UZyqBD6aFlcPe=ZZ4;*JzJPlt3o(2sG8`#)`c$Flquq5- zoC#~)mueL)Dxk7`{syMOMF7>E2tcQIlD!H1^_QqZ<^<*=e-qdYZ-+-d9uS!MFS|AW zR23RMVK;B|&|h8?(iZ9VzDMQuwVW}#?|Haa(dMdIhXuX$0`iXxl}I3gs9^SBJ)~O{M{I$SJ*@Wcs7NHH zHLLaXJ7-BcXMCQQ%~Xm+C=-W{W4W?rY_dE;4Frr!@#U(jaQRT&t0Ms--H>VUENN)P zI7E|Ld|}7>v)nN>Kim$kirX;m=}d`n#^Tva=r!^DUa@rLYU&5jpnu0NHz6rd4cE4`A``ZDHER7b#8Gg1jiAX@W+h*xOl^YNG(LkvEvd+Jx;~12eG-~n zv93r3a^tjwP+reDeD-SMR*S+1x_ropb`bjldo1)l(7%nu+L=USRbz6ryg!JvdFf83 zLGrSxEA{cpd8Qos{;@4H%fXoJjP{(5-Qp`>B0YB0&ZhZJow0T5G&ix}0$wO5FkswB zQ@G2x(W#DaTY`ewfto@OyPPB|%~#8>C)kLgn^w)Yi2NzLsE*9D!Z~s8s_z7PJ3b9j zQ0=3$%sG5YS*NBWn6+#UOs#BdM{ZMV`h&+YrYcaWuSy@+`G@@6?x*i(ub~1vIYi*PlJPQ)BN`G6SK5)V;jo1Rq0s%DB_j%DJW z?C;dgYQbWUZEMd}^-&i)J1?F;o0{5Kox__VSa)vDpmzhxi4E_7&7Q1f1#Ql6(DMT% z??}vNAtXwqSwHvz-%+OCSCsUW=R-hPCZH%92C7xPt`td_vk|WtV7)YUUAm&XR!@b0 zp+xwP1;=3*sUl665%e%zbSd2VIQvbKb!JEM(wmz#sR6H03T?=h`&=W389a>u%Pf7T z-yEUu5X0uT=CkU#$2+lkx21xpw~4e7s3>(FSi^f)p!Vd*&~ua(+l2juMr^P|ZuB=g zdP`2Q@(7TIH`hbY3+l51d9GSd7fiuaCC*(7c8H4a8|~LlGaUTBF>WkFThN~S$6cj) zl+xD(a}#>pfjx(LnLQ3xTJ$+#7_Jau8HVB=<|8Sb+)t z1Su}~IRjh&RX-s_gvjDwF3k5{K-PgY=j%b#)ctu}(NTy+k9XknotKTR#pcV!+Yves zN8OF}`jd@S$F^a6^e$?Oo#u5a(}_Ornx#2#v0HZKv3teqTcb~)lUvps8>0pF`81=~ z{hWRwF@g$E^ZhXl?)=dlhzLz+nkGuP3So0q?Zd{tnL2KnjMt2=OyhNaqyvctEB}Iu zx~Cg>)CaXgRh3g94i2#r_6!$s*hxuHNvrOgoSR^RK-omGcrQkSI}K!pG<4@cV}iD2 z3JbM1iCJMrNhl>_N&TE6T@1^bbhw>s_A;Scpb@csB`KwFw@GN>60PI29JO|P+jm>w zg(i{DTW?AU)~usW~)^2*ny!bR<3zDP1G?alurcqoZRjYQP9# zqqeT-Qe^^fqkYk(`U}d(Min^6lFWBUt1Q#5Mz6vUr;?wR;WUVP8l@)@oZ?G{7o23r z=u<$|{avJfzHe3QAwx-HXfu^=pm&Eyptq2ZXHe?<_H`!=B*T4Y-;0oE0A#@Lh&o_~ z-M)@O*(orHeRx3%qm*DF*Gp_6PgYzDA{=9R34(o{3}9VW0;`^zn5F#-dEr0XdEIxk zHC}!zz?(X{_h;z!VcsNNkNaBql!P9Ne~#qf4mSMX<;CiXS?s_G$3S(7eu@q)%BGfms4(`kEf(P$qJcVym`nkL)@u* z?+8)AsO?+gWZ2J?CO@S*+O%Hl=_mZWIC}V{+uN41XWN4O;IjG7Z+HG6^rNZzp29(w zz3^Oc6KX{!J1_Kp%tgoF!i)8T3lRG?x4qXPg5Jwu|KdrXAtbj5x;r_432ied8E}vT zT3cKAN&0TCes*_EjZR{{AQ$4>u)c#fW{jl$;z`?GEHrFKtsFiziJ&$0D)Hqvi+aQl zmQJB6@a(PDpsV{W1S5GZLbQMtl}WR#yhhsZxEM}~asT2Kn*(Ayl(P=BbdQU@w} zPJB^Re7^HJb0&@C0&OoMg!>5^ZMT)WRq zE7;*cu8U3iWqXaF_goKgGK8ZePZ~JJlOwhzjUK65($R_hLf!d*mDIa{)mbX0oW;09 zV9}Fg<0xy4;@q2v(&>zD?~|RVaj2^*v@A|3Odtz|>%4oL7akd6C?z4ws+Yc0`h{!XNiPzls*{r z1?hgvvzHNL+(dEjJ_oI2nmE%B%Qs^d%iFE3_wmn#-*pm?dMy7~_s;;A?#ed^!?S}8 z2UcCxC^lqrs&8NsUIGTAl4=IhM;~<;`cvgLSM;Yk?)$?}hMvoaz|0?$=)UU~3i`H; zf9gCHu6180jgE)wvWSuqv=`{q?ufi5RDb0-#&6cCMAmh6&dchwr85tyz7$F5!E zk;y&kW{24{`kd}M`BreI3C~k@3N{GQ_JIk4o@3C1X3|3}{q%av@D@4N

    xP~p~e`z3e6BjaPE5qvTJxf`-RS88$70jNkD>k7yU&nycqQKOn=!|j27TA2+JF$?r;lq;g^rL=F~@7E31iJ z@Ri86!>o?u~g(e(L9Na*gkooF^Sc6BHucuAXvy-ZT7FzTWi2Vlcm zo~nA;*?vLcd&523n%5J7ABbF!y=|vA&wcf!waF%FmDt`Z({dI;kHb6zMcCy<9>J?NbL2RM3jCY{eUP4eNW$RnVnc!MZk%nmW1@!r991KxOvS z4`VJS&kGz0ica{YzBz65#GX6raG7OxWOyz7mLfGIPPZLr?1D5AYSVTFl6mw$dP>VY zR|m63LZ!9K3RWG<-+nf&qCwKWza?NHxEFqB1@EjU^7K(Tgsem-5&DcABcCaq-C+nP z_{)JxEy`5;0p;Vx72cZAP9ID6tu^=D$m2L`YPzaQvuratElUw9Z|q`d$w3 zuUy^@pn1BMfDG0^`3fEU$wTTt5MFrAE*RQcTeC(yd3wIZFB6Hu2?CWu7K2^DEvJV_ z*-RY_O<;I~L9>6p0e+=4rE*4hjrJ@S1^HZ%(q&h*`j9QzQ2uYdxBuL4dru7g`gCWo z;LLPOI=)yz-CuS^|AUZe@GR!9)%YA4>(>8e(YksV@J?iFL3d#rwz^nl@Ot2`0Z1<$ zVwQ7$mwBS$v-1t*zdRq8uAsrQ_Kl4l7pzk#3*O|j3ZNnZ`!G!X93 z(mSW;?C;1+jPphrElv(rzRocdX}>GU-$%0@XDA38YlV%zeJq{Uw1f(gmh=G`y=Hk7 z$sKB{ON%l@Mx%{@S`S7T?q_=|$IsnKY?EJ~7mmqgY<5$jFW{=e2rl~uD1<9=fc#E8 zq{30nq*1B4FUV~-Ux%pV$k~6qr&@c`V0in>ep!R|>bhGf!=Ywva;I|9FS0T2r-05? z;N+a&{IM9@vyFAC7xBS2S3J#KJsJtQHScBN&n~Shw@RH@0{upU==Mryav3iVZ6(_i zpdX@?&OO`vs#y01}*imLD8M3zz!_Kys5Ynb*^Nvfm z+wXyRJ~9KTOMvAD&z?!eb7}&cuAkw{{WAx)GUq&3*qim z>rJNmFE$U}LEXjr3QiMp21x<@<<<1@ORTx%uQ%6z2d4_pqQZ+`6bKebX?h7qA#;YT zaRQg&C?FVJX$&I~M3^{Az@myG=p`})59=Lj{^s&iRRY)`1>_?WGf$+^jh50vCPQPV3!Jw~x1gCT45H0nxz0 z&;O_6)0r7;Z=ugdTtJS&=|*1Z)>MXtAJ4gLQ#=MB!N4$6n8K zeAXkPQ@%@D58iwbCUFkS5mYhbV~~9N)|8=@Hu_Y4VDO)V4oH|5RKpA3>e@i@qVL-N zyf3rSjuKeviO| z3d5iHm|-a)ovT@OykTZd_2CX-$kEFodPdf7%Z;%y@#ilq?1;F@h|N`6S`0t_6i5qA z+cGEx?iWi@5_B{)X}&xMyt_ZHOt+gQa|0Xjt#0Ev{|doXDexYcvb?EQtAk65OZ z>QRXt$uOc~9kUqdj|g1|bgS;mys!g#XqGIf`QUe`on^Du;c^`P?$myGk&NJoEJL(@ z9IK$q!tp`ygn7yL2sRrF=BWGcHa4eEVLGN#k5lutq!|Ue=G2A)U4HnzY=T8QMHh|67vK z$k^YR>hHx%Pjh?uCZmrY9ts1YJ)9A8oV2Fui1DkD|o6jX^)?s)=9&X?kM6AQ{-6XHp5>LEg zRod)ta9`>?vuaxNelFE^>?oml*b{;`@Y(3z95bOJJnz1Pxe7x~V`k55n}eT!dvK#~ zYmxeM4MNJ&t~{Jio&M=3{HYl&#oM=hxwZ zM7vezi<3W@UKl729&nG8;vaAYP`rhzSdHMiSKNBc9Z=ad!t7>Q#|m66XB|DRH$0Nm zOE7H^m=Q?)Iiw;{n)S>-G%;>5J7v4JyCL3o=++==MK`V&Rs0n3+ZoWgj{*wSz6=%f zWnrh*oLN|C2OAwQc?Je^zd0s4Qn2!U6gx^pqCYMN_qw8-UFIX}Vs!2!LkLuKRMy4T zmOXR5B7T44rBuLUp-)tp7tiSQ`&{pH`9Pq}RV{%=BsY|p$+z>e_etuUE#u1Xt8a{r zPyMLpK)~&*#j-8C~p7xuhQ*UI77*;a(wjnBMV(B z&`6p&QqEnzo#w*D@?>S#tYRRIpNF$9En`ahikb^+te|Vr^|Z30P^Z!V3AOd}m(LK2 zva-a;o|eYb)A+T=K3HwOYBdM@yR0XmtN?ctdPt6Fct>{pKTPT#FdwOyH{|Y|Cj|G@ zW>O8j%GBd{22($mc3w!L8M>UTLHUS=loQ^2NZ&a{ux>kCg}<(cBfESz03Fv3ZUYEm zXd0aM=rGy=&i@cj{IfFh&x`JL*q2M%wxZff%@H}2ohBgx!&$>5EcuEYL)yQkzP$aN z$SazWr?LgX5pZc7X#tqIv%5TTm6U0oLI{kwV9(ebX!YpFlB44oJ=PE?e6_P?>x(Dxc4MzNN>c59WK^NIUMdnius z#Eb|>uqYqsN!H&85&03o1+&r5_MUb<`X&B6670ISi}N;T*DhS8_4Ctj=r$dc#_HMh zd1@s9)DgZzIEZ@ZbsUo7KYWg1W&l-o2QB^&(yx9qhse0PKS#-NKdcMA?9EO0n|Aq_ z#`wHOaP8%pmU4wn*>mjmrxpu8{(`@MeQ8j3E1N?LHfwzx=DHneYIcTDiMoeYX{Do)xctg zhlqH|3iiI0JcmBx0$m!|N9%e{MRSOO@hoMza|&l@Pa08QpJ zY1aXl$M?adgh$x*Fp0gza*_ftcr~VzI>z#3-_@Z&E}J?b%y?H=Ur!69;#yfZ7~9J}SHF0dqzdvH8#P#3_wy$|oY?d@qm6rkF-#IJ zQff$3So9hGD)V#+Ms|0;v{$;89t|%=e90|OMwZ9;Uf%}uVuY*lDK*0}+O2TKM4^w{INwRDn0i2L7O2dv>%zDga(H!- z8Ox~_R^LUMEbF+KY)hN^zWNdnZ0gA?*x!~O(JRFX2e=RfAxUorCXUgTvd{ObPw${g zs#GKN%+$*k78WZ-20GCA>dPFcoZ+rKd{t(p{U!STTXRQg_eizct)T~cW1Nx&{f#G* zTN+aH@yp{(rTp|biItY%9eKMpiB+t)kB5tB^E(gU{ZpCBSsRu)4Bp&Vt?aSv6nw?O zhqu(PrJ?<0l`J^H4gu~ca_3nA7#~^fh-pXU|R^45pq7km!(AB=@y)Ozh0CaSR<}A zVM*gL4)(jx3vKT4i=aL4w6scpDv6twaSbUiG_m^W*BxlrO*jgf(fv=LpU6@S0O zA>*QP9UYfhVNzB7^eM>a3j8j>y`U7aP0`bLJAyhb&Cfoc$3&|X614U@f zqw`JxjrJFi;sD5v_w?wvtkSwy+T7bV?&_jgLjeCfQEW?=?*=LW_P2|-$n~8Kfenl# zM7pBXn<`ewbc!WDf`5{N>og056Jy55rmMa%C(3cmw|hV6<(n1vukE-0la*m)35%9> zoK!8`s43(Mk-smp{_^8CZaGZ;$L@(C-f zKX~_};K`lrfoS)be?HA&eY} zavpVxJh{aP4pIhsMNU<+=ngAc_7hUH37rZ(Kx+mS8^XJ#gK-(W;*ZA5j?J2AWqZLl zFcI_D3n!0?3%l-7vK`U);y^}OVWBjI*XWqpU*%%dl$ zgEvsa$p2a~4YXGV@0*1Nkr>|V3jFvJ@*Dq9YK42HfuL#aF;O!&{o02>t9aG4)Ly##e@PBx^s2wd>prI@wib_yB1eJ_CCr zN=H{W`!?y~rHH_eh8(shb+mp5Wmn{Q;nTmH1^18xBn(wLohDdXPNuBte8%T<7P1+m zJ#+WC0@^)24$h9H4^WbxYyCV))?Ar;3z?HA zy{jWcY{>rh1%~0|qkT~GmuT!Bv|kx2#|8z0u9cx)U~3MQ_|?G!uLAtx)=%CB^M<9X z;pYVCRvDp+J=TT5xQ}tsFW^Pntn!?evRIRvL%l#2czv5B%aOIvt~FE^@PJ-~%5YWd zaE0(uq3V66xb~jbO+fyOjrNh2(}v!EG)VtpSNV@SA6AiwY)|7^SKCEin_ado$hV$J zT7vD@bLhAa$pnK8Pybv{3N znxJ;FXvMYtuJfL6R^~h$8G^jVKYn((Mw$n>b^o@S{Eu&=nFG=jN9f(~b+@xlh$z2t z)2Cwx^ThjO^|c6$1biZ!F8EX)wH4Fr)vW1=a9>4pf=a^k^csY;TvRQ0^j0**Mg%4AOve`m_%Nw?| z&S}0X5Tj{@>}@U1inm7NGDHTF{hUWYKfI}4SWQb$Yj~8>*db^qksb=R(o!WiCt#t; zK%TMgSuv#w} z`WZE=Pu#|c_Oh7s<1-Z6Vy^%veeq0G67dmVfzQxvvx3Rsju7!kfV^@HG743xkHo57Vbe@q;Y!b=oGjPakK*;^| z(&%^mEe_g`VTsuUPhn5WP(zd-MtnrDQ_Lgv{k_)2nWubvqBNI%0@h&-bZ>;08FnC& zLeZFf2uLKxJq-sw8(u+9YGhwbzgbiXKW}ZF&D@H=Rwcf*f<=@6PY>|ld^{tDKFpvJ zF8lsI5U(KwFBmR`KRzHrkc>_UM-fd2?5M-p_vCkID zV;`)cG#tK!9nh4z?kRPYwJveQ>~0X8mHp@CXGfS%k7s&d>OiIb)KC3>13s3e7y0s4 zvs?6x>0sJl{B1?IIJ4;)gx29zzivtl6UVE3^|ecCiQ?v6G+KaDNRqAP^%shNTSWio z1OIywP@gNZsuzHxrWWbq;zfahpEj3l6RnrYB_UWR@gSc1X2XB<-eT2%I0_n-}b-!3m&YPL%Hik z<)60uhW%qmX4}|rMBZSL>>?nXxxLu&qTS}ve1MBg)<;XMy(zp2Nqf^`jW!a{O;&oX z-RPb<=X5=+fp#eSj(PkGb%h)sI;&QJy0*4+>TiFi-{1#rlCG}l_E%_uC}$>!Yj2cH zH{nwaUf{E-Sjq?V`S*UbN|POC(74*J<~_(|SE(P!v4HhY+; z-Z;93&75M>8iqjeAb6_U~h-U3ExQ&S`*6d{2Jo%Zcj_LJS_F+^WKfgxriy@Z$XO_y9q)QoF)W$ z5jZ!y_OSh@YRlKnawbBFHW$FL5}5Kk=cY1CgK2tBL&np0SL*F!m8*Lkk$0K6S4QH7 z7Hy=mw;gjlq{Ww``?Sj3A=9yacemS?9uXo^KP$ z30}n@Ui-|Y>zs_Sx_WW^_hO6DcTHT^XoG{Z)>m4wevR|K$E}z@GsY`#O*;ROlzbwq>NT3V9ixCYo(n@O??q$5SDKXTi2KJsR z$+ar?g(mb&%-?*4tsu;PWmPuTNN2RmTB5W}y`IrX(HYK}M7O!lD`1B&|7Ozq&tEw- zV$zMx1)`{*W6|(?NL8`!$xsjJYyV&#e2*PSHux%U=xS?EG~%M=zbg5poH zOT@(MElSHsd28Mkx)~Bx_yj}x{eXirG+7AW6zzO~ zx*4yOkUy5qLA_l~wd~w2bZMKSD?GZgDoQy(;clLL+xV3ypQ+5psWx+>l|SyIq&D9` z`B!y}ppO8<&cf_uCIQc-N~c{m4$kf@EQFYs zVmK%)YqR@wav`omJ9FpaF~U_7D##-7$E(qaB)gMv)Scd0@=<;Qw2VYf3wFZ%FKyp% zgDm>hmLNvmScGV&{1ue^DRIXLHF^4kn`gnVwA4(zPkLcEnmEXPA6TqZjUCI0U0GmN zQu^oHQ?_8*ROs=^|7{1_~86 zJy1l)Z6Dp7NGWY>zp&0`&G^X@VVs@pz>NQZPom90R$Ev3{hO?x0S8bWiOXtMr);LP zvmt!?>cD#9{@Oi5b{(xt*&b+FS6As?an@xy&~1JD!^gg(w^vSf2NN&&EfyOC4BSn~ zf{3ZoY>iF_vkZNuoco#zZ-IoFvxOzxWztPYN8R)ICryL^mHuc7?VE*gJSy9O!S_wv zKUd^*KE%;v@-@Hh^@Jk_kUW<*D_ihHgmYJ89T3QktfpxJk*8;3mWOlZ&l6wG#hbI# zoY{Bum1W6?fVaFrTy94M+`q#+mnnGPW9Gi%(cnOE0}A-#yFt-f}2RSoSu8@&c59kTpfIt zd!-e^oW)H_3Ejzi*P838fyKY-wz73}dz&$37`^k1cfj6V&oifT5KM6(kZ|5~!WGup zf>3}TOmPQ7150NmdmFSKER#r59>a2FxVelb-KrO(mKmzElr*}^jGh{3p26w!F)0Zc z3(IS%nK13~)~1H{d3B*M0O zbXAHpWs5K;F~{9aE~JiG`JJ_CQ!@ zd@oC1R?4F~y4U`nXORE%tn-gMTS+3Tu&m8pn;|HL_E)2B$0WO!D6yN$*PD2ih~roK z`q#{EKIk1$glBQDusMnqPT)^dk3;C0d)Gn`QJUs&JSK*b9TjYnPh1I&K1!!u|UmU_F;9;jQ&29lg76I{NX;P)#EAmc2U?_s@0Kwd3RN|9@>;*2i5aAEzHds_aRYc;U(y7xT^ZKLyc6J;);e#dS!<6 zTe+lMk;@1Uy;_{CqRaN_L_M=oJX#v9w^!lb{70)bND4<+tpdT>L$Qs=rn2^R%UX)L zFenTM=iP2b3go~4w(emBwC4n;W_2;0Yvk>nd3g|L&GCm}TahRnQ|zxlQZU75-=Uu& z^$EH)2VEt`^s=)_+s_~SY=1m>8V(`|9gy>sH~dE4JP8l_yh>*`YPT>m-%qzJoC9u2 zV<^TAgMJssef#2kQXYnUe$>2vpY~~_k9LT&ACAV`Z=PvX$dEOJx)Da;qE4oNd^)O& z;O=?o>SSu^-Ta_mM3oeGbS5^TRAO>Lz2qoH&z*PVd{E4H)&4*2eq#vjwJ)83o);a& ziqPpb8cyKx z65#Q_z1>9LqJ$2LhVf-}o1{Ej-*v=@ts@TCU1;(Skm(DOC41{IlF=Ib1^N}%E{c_jE;3*5TLeb=N}SyqtoBC%Y6JgpD65LoE=#ANb^NTTGAFNE zVC|I6R~1KwTN-dW4^Qc}HD4Nal~#^A(AN`p!E+@!OYFF97+Q{-l{Fr7mK%{hRXJ)C zblQ)&QA5xT+bK(_pmwSM9PAptnwuOSgft&5d3bb^tl9aZ&g-xzJmdn|WP6TeEc&_t z*E%nDU~P3t8lA@?F^HqCIb8T-PIh5?Smk^ZegU*M=i<^;@v>|$qb$=JmYtVjF8m*7 z=uF#7xqq+#{{1i~3%G?3XwMB!tuSDYkRpvkdK>3;T^0 z?|E~;gC$~`mIOJi;K9ms?9bOx?n0kuhzgH!AdZGQ+Fjpzd{I}WLW07thp!3SWnT_f z8gv0*gt`R!Wx=qV?s`b?8dM7Jw>RV@mqVvZmp&`P^SSjh#u^jM$;Bu7K@>H%=Db`w z>#F@R4RsUBxS$?5r%PO1G0vOep3k!~GLYYbu|#Ws$R9~8Q3bN@i2WC8gM4D|0Rnre zoG;Plk-~}4l5(f;s`YO2!>-y)Y4YmB#_djb*BbrwsI2+nVN{_LSWKp|A+mHX6_XaS z3(c?E)+TANLh(4`r|lcW^txU0$tD5jUxH5mCE0o0584y2J*l!qN&HpdRN#k*M4%bM zeac|1IkL3c*Y6DPj!5m%U1&B$JJCrCpL_40-mYZMut#-fh2iQ)@_I+y#)U~BUn3|Q zzd;H}r7WB^J*pEB60%!+&=%6UMZei|D%anKV|9GNf24&;K$2vV3X@*2B~ycQwG+pY zUdl08xS69Z0vHY)dMbH2YIWYkGB-D)W!!DseZ`7azEb_FA7GMG6pYPFmV1_^XZNe& zecW$U#Pe?r>&YH7;D2%l4w&j1rV@i*x!J@etyISiS#ayW$ZT#$oU`*nCvIT)bQ;;q zer~$9Ut-|zdU!P(iBx~k!M`!ySf+9Sup*kz|9kt!Ki20xx`1{R zgUH>nlufJY!m}Y|!MfY98w{_s{cdMP;k-d8!9G|PbP|bB9#{$(>**I7Hqm58T3_O- z0)&?rg0s@wmQ1-vN_U883n?$wA?1nRiB9&B-&hr@lyKU_%-T$W^9K;gX_v#H8q}jR zuY#Td%_Hd>sMn_&)^D4S;2Xs%H*UIzcix><^rdnxH>0(9{5$)hX!KYQ!s7K9Li$~v@XF`4C5j&gn^h;}`8i{77&xd`;|yb{Z5_^Xq^ezS5p=%wP36g7=*OD@;#uzi zXcy!F_`Zd6b3|CNMD5YpQ#e$HxBlb`Ul?sP`4yco=Ihxm9o~$9-(=1@Nu#xAk=LNR z%4zK>NUQpqsG4wk)OaQsj)aO-Vu=OQCP)mZ%`}`D|rXV}k&Qm*9 z@X~**vOL8pTz_#%?bwOHINFJ+S)`W`?5AK_a6EG#YXAxwYw@y;T^0Wk`fYnw*FHJZ zu9aTlyv}}2=zd>Hm;vA~$ti+IuO@_9b07YcWc{WV(v_49@qzp>Og4O;F^u7k+4llm z?M?vm6xI9qarIWn6QJmZ3ZA;aQ(+;|z6p#;X4FJmxEg7+UD^i1O59Yp{Lb3WI;XV< zO5=zRd}AMac%c4UMeQs~SU{2DbYC>(c@}iIlRs$e60f6%VT7ss1m(BgZ5TqW9N^F2 z>~4~{-nTXq@TUKPLQ1Tm+Br4gHyJfgjZi1<(Qik-p&ikJnGLpHp~Gu9?I<}vG2vPb zv+FsxAL6f*ogjLacsBEKDix4%3wFClKoo7hvRnHqm5;y2izUj^{!hnQIs2Tr9FAmtOW_UzK;QjgG~s;H4_}X8__r1PzpR;bvZR?FuyfV zIQ7&5ekdz+tgO`SfgcO2nsgZm4rka^a;bE5KG}|o;dZF~nU!7H5Vu=BNHt)gHaDlt zu?ONH?2ZBPYt|Q-K$Jp{4%fhNGeGD)wYbOtP^{t&Um=F6{ZV+MuM+^nLPp)p`$_&5 zmIg)~Ex{RHIROd#Fc9&JreySw9}}Flb)j*syZ%*BTjf#TOH0Eek>+a15^$7;6P&ZM zyuKJbkDnYKoF3%#y&Zeob+vj@uItL+d)9xy^>UL16u6cFDlAmW?+403g4xt^jpOgM_XtHxZA6NGKX{`KZ4sPbm2DZUXeO zWt{=&2mm0C6anYgZR;Oa$s;-S#o0lRGlQsCzlB5RCcgb5U^} z&x?B3pLpRWZch=y;DsdqL8~@6z7bXYTMGiV7yBKKCoY#x{+bJ)$$K7f;J{MM{FEcZ zOT)>AY+K{nwQ|I%c)~cH>5|3*JE)2yA`-_vX-UF;n8PHqT+UqWEw~J~Rj*Z1uzr=L zo@Lhlca?9AZp&F^4V+c@6SE$_53>Aq2H-{%>u14m7FiBVlAg6|*?HG;yXw6YfI#wX zkQAh6*SrC5HB}gKQl-Z0ac*=EOnP$BzQBmw2F&t_#WY3Qr7u`8UoBzM6oDX+CjP=m zFTl96GeBs6-B2s`-|eovz?L(w$sAkt{&M$AEkOB5dZE; zdm^rd+GR7?b@IucD)TPl&{D$-t=509UJ|QvbQnr{hg%)f;v#fqEoVDfbi||LI>| zm!?&+&F#}y$dn%Y_)P8oLUDzuoGBJPTKKSIbA<&R80dw~0g1x~t>4St180HU_y1n4jqrY;$hDrND zopotyedQ)94m!lGH}CG5h2-S;_xR4TF~J^c{VPfS<_a`?SkKKF>swKz+1^&IE{aeb31DIGv`19g>lS*xRy8CX|6nmr)FI_Xk+xLfx?rAa^*6tL z5{o`6kh0e@Y!0+4K--gS%fGw>7-M$~UmsGRfOH=Q7OUBcbRzHL+W$cqw#t3m|=qIMc#_Qpn;_UbjDKT(V1qMEhxN zao|u~QNg4j8Pd@O0OBrxajy-vx*lB%M#RKaUh~Q^4Z#1$apT`kTe8@tTwoM89RAC< z!_QVom;EBbN;aZ~$Lilryoj~Kao_XgFGhgfvcBC_Qc5~%BckqNOD$vr zv64s|k$_AZ+!lZp8n=$2tW_H-g#I(cGp~YG*23o^s}nvN(&6uBSKY;T--YdFKdy`A z<<|v57u_NT9fQ-m?$14-g2avS3AtpGv=ObM1w1{&Ol0(7j#?B@k2L$pZr%&~`9zTC zEv}m_wYeS@2jUej-ftk#mXGo7Wnq7a^NoWhupavLbbqx|n5dYLl|{4`i=hk${Z8V0 zz;_r-t3X>IlAg`&SPM7zJ1Y&%CpcyRK^+w-{bekT{BKMH6*cuR3AW?kx{03{Ca3DEBW zs>k1OG>wbI(LzAI^jYX$VrpuN!*-@9)qnwzQM8VnwoDL3p}c1BY{dgiQHvVhI&r?++~(IypI_-3?4E4#KWNaR zU8wHciXRxFZ|GDNe}C4vc``y7_?ZBkffkk6{DsB~rcXKJ(-1vphf)A$8d(R1taDjh z({**&5$p9szRTfm!*8y7bOGJcTA!ja@430D%&8%(tB0-Zz^>b8hD%1}xsC_f<2ftm zS&9S?vH_Su9%$eY*T^w1j60*}$oKgf0zmGw7qR=Y zBi~OTlc$sGn*0!{0?>#q*u)NLeq1*5WPl{95degWRn!8x66w6o#nA+StH0Cl`2mYRcpV{LBUb3a5_gd7 zau|qF**R%io26sIC>H>-WBAY}?EvCXLA=qi1V-j}R81hJ$<|rq9?032adT_DKAQX7 z>T;0p8-5Kf{!l7LX;&VtkoG~epCx?iuXudqa%U8h!C{p^MN9i*2wrI87+BGg{${BG zgs*C7{O}?&pYmhg-pXFL|K?yF!7QCcWSv)8-e>0=ku(09anBZ4{V?#IOH^H**3Z@6 zJ;HAb%Q66aeh9e}k+_&p&J)I9U*)}hiBx|C##T0`Lu+@@akhQUnnWXNQ8vtr7LO6k z0Jzbr>%P|1!TyNO*o`HL{8yn%S#F_?xLdt)pLEM&tU|(C?$Qq*OmRuxAcYTxqbs_H z1?+bH)j#lUAEM0$$bW>~U#xxw2q)W*`{A}Wu=T93Eprp{LJ z?Ne?^;~aO1d($0n#LYu8I%&j^qZi?&&iR!aY@q}yV0*N?p5!2>E4mI~AfY~QQs>+0 z?jP095QRD`fM;v_m*~pobLU{l&k$|`9TgWhXG!b(a2>DyL&J*jPW)|9DOK~T@2x(r zUa)Lt0SwyYMA}DFGr-X0w3}{$Oi@QBh+P2y-4;XLBm`Ojr2Nj~S=a3evPA=?4n}{G zR2<3TT%inh%Xtq9H3Nfe4(P>m?fz)y2Q4wb+x5plXTW#c@Qd3jJW|0Tc%NnVT!4Vv zjtSUZ&Rna!Obk9GX;65L0^^y*2wiy`i8gE9IqV#sK7E{L>#b-8brN_2e_T3@!~In6 z;7?hieMP0(Zk8L9+<)`2my;_!=MEh8OFv1{K*H7#p1VKaL*+s`N-pi$U7sUQnU$Li zXB%9wX1}8rJW0KyytIc@dkY?GdSw${A?T;6`+k_MwtM~%b5me4mNV1V<N4(hY}221O#2A(U@Bc2EWlKg&rC7El<`lKm{I;h z9J9RXOQIu1NW%U9G4|GRQMTLOxFRSZ!q6fr!_XipNcYeojkJ_>hoFR%3?6e@7eo3=l7nyKl~-~_`u9P_kFFkzO}qkRJvIBYN82xw7%tMz4Tbs|kznTy>3of=x*^o3UF{sB{dIC%Mv6~ZAv}aI4p-Vb*~1jlgoEAZ~buls$YA)VH`6rl!lr*PsHSCx%<*p3i=`9fKe}c=cDh_gHLXeRr_lrUs0PYIV{q{pWPL*O^R2 zdC%0<<#~2ShKL>I73K>hpBN)G;yt4kLg-H9gHAEX(5sH-0sb9 z$)}_KK*`F)Vcq)bn$i083eyFBHU^w?-_M-!U$&T=etqdaZ6lDkFeNk>WK>?#mPq>L z2R1XFu`Kv3mLP(MoC1Z~ry8o*vF87q;iX%U;e>D9uCZLMk));HbH9OKv(aM?Z=Uz@ zN-dnuV(s-3%vP3T!4o!_Q-S@Wdt$ew-kpyRUpCjalWuBFfWnOU7ej25kqq9>$SB?B zXeuVl+HG<(v#lk9Ek9#60#VdPqF!pzZ)m)e^ zCTbnBa$ft=)BOz&3yTHa<*Z8S-(_(3N5;euO@jO~-M6zYj7g$=87-Gvc7_2kV%}tM z7&^;<6^RdOArkjKHc=9*x<631WFy@K?k;)<{r6t*H6M(0E%JW6+8_TbO#A1aMc)Un2q^BCRQIyq~j=ztKn^3No8D;k~m ztvq^g=c+z!ujUTqDH@m_oXwNR+Xe!LA9`)2+3)oIim843^_`q*-otNwx!HB&O-Z6Y z=L}CNDpTy3i?Bw#?8v;c@o~xGD)$KyGVHz)dk;*0%AF&BEPJkHWt zZ(*IFgqagqE&|9=78o)y^8GK0 z?dF@&93VVRpj7%+O0`^_73#kfzN~~|V`ol?5UDDIEa0@)dJ`a${0N)--tZ$)xZ2b2 zeSI;Y1$GG#VbImi1c*xEhkHXd<~QWYs=`GU#``Vjyq#P03Al}FO}wwdhR_qjm-R)1 z2#d2{L4EDc&$edH!{*04=STW^_;Yl1Bs)pv3$pXy*;T>A-wLHeyQ&ij-i(){k>n~g zq)?ov&g;ab4B|ITNK^2-~k*>e@*}JVM0YC_S*4G(^c) zA3~fw@uJA4i|!cXsCx3`R?U@5lTV3Fr3*jaU4QP)k!^ha=6Wn`zvqkAf#0?9_!Yh0 z=Qpq9<_3K?rP2P`K(5rs?OTpU^``Y~wMzKvuefy*jLEv~)%3@Ad9Fx?@{hl1m6er! z>0up#cs2c$a>`wPP=^f7OF5#{Fp z437S{M_FC~I>6mRpr-%hHNRF93$B z4|eoDv&nvWztIWb{2|%;Ny8oO!TDIU>o1y+-#R-8>6ntl;kbcKw>&n_T1Bw#$WqBL z;5q%}pDtVC%jfwfxI za(%gjYVw+(rL8Rvn7Y>Fy`p}1gQmAg;8Db6QI zPiz;;Ewz*FS(m>cPrx@9>%HAzlSxlhsgU|4{&tFb-Q8a|6h2~7+jnEIF1gAqUF*?& zp$$`W%cQ{W4>Z#e`@4t`PZ@6ck_kCXmb+|p>Bjo87EPBBEQ@1(=R&z=x%HN@a)xbR z+(6jLz@HMQ#QId+%saW;#TMxnduR9h3~e{RDaCwd31!;4*v<)~S$`89+*O+O}z6y=kgEB z>CiEnUL-q*S*sRqjl@_X-PYh^nst^Ms16Z_-@nQRag|s!HkKHIMXz4k$SBi}C$kzf z$*hc}^vwPJAm%&67-}wx9;H+bQb59FeVdiDaMP8Ft;WAZMMPv6#hazM(~fG;P*I7a zm<$xbfo|bd)DMnSU~IXW(MT`=h14Q(<7aaJUXQxK$3Gphlg7ihQkMD^>-OgWLUlo zsb%^;L0ak_-YUFAB_VB_2Sp_#wsvB zrws-hD)G4>^4Zc4TzRrK1$>;~U+bNB0{P2BuD@vG3P>iUJJzqD24r`;`-OY$7q9O9 zF`Vsv2!9B1pP+}j;=)CHdU_a!Y|m}nXB@uu0DOZ=OH0cU1!MMHe{cC7;OSztezgU!*8#*p8kk;9j0K`=!dT<1X3rH=zRi z-Bf6|r2!OS6CbP$nOy_%1V4E^u9D$q%1MZ_EdV|KKH z8G4zVhexBGbzZLosUET)*n>#m(G1~+gH7*G#wsPvQeEOu8?(7_ez}3I;H$p(S^j|$ zZ>WoL2K4kgDb8mW{U=lEf0G@k@%nVY+}ap)!&Ir)tN&2LNbn!|3jHlK@AB9^!Io6J z@Tosl3X;pdH3y(xntMNR@@#K4Cyd3csZiLhk2YNaX-11mZtH9LMPllNDz%6Oz4>)# zk5Rm>uO7aS{^}USfQ^%vzjbrA`-00p5AFnq#3FUBGmD&WU#XG#AQgv(m#c|_thW5$ z4Ve+Vab@}_x^BSgTC;;Dd;P9VYMtwv{mO;E*Ii~=M@nvR`VrQ#esqz(qvyKoB25&& z>PvyO3uzlQz5haYHNKKCYa=_Xi6H#n+5_&3S5JFg@8{>H4NJ3ukny>XAm>-Y*w70D2V-hFgQ{WM^=N|9IIS z17PD%bIaKVlf_JJ83D8VY45k|w6DR23pJdPX3zIpV0S<@}Q@nnj?*Gwr`F}eQ zr7HB`7F&(2#?_>LPc=E2`c-Y>Cg?lavRj?_$rCacG`F-h4MzSDN91+iav>&9&{F%b z6r(tMXr7$PUW$`8KY2fgd;jjvqv}yEcHMEOwILxJ#|w6fDW#2>wQq5Gc`Y^07bytN zt6zZ-`aQdG?1w`IfgL7MOtlg_Wq zRf^NqHl}+^U5;RZM}f4-Y`x1qm^@KyLXPISVJ*;Ad^pKfwdGI7rhw8FfFm966pZm@ zmVqUQGEqMlV|fI zWyaquvFVeiy1m(8xgzptWq2ym#Re_<5ggceKjWxCxvVFYBtsuA3O}=+4OS^lpP88{ z^}2e3(73~n2b-v!wGHDu7Y*U4>lLhhm zwm3SX-kR*sf$8P@{HUt_Q+f)wF#^0%=jm#Z!5?qO#!tl1L-BwQeZHoaM0t3-(L~0a zl=$7oqtOj^G5@-7LFzxb3XyJE6po8cUtoS8Xe*SEvt9AMKlo{7P2}Z?`#p9?pn}80 z*>YSqxS4^6Thp50gCliZVo=TL25E*l_;S6;X>=>_SnE!2{zxNp02~chTBwFKFH!u= zuC%DAsKBrY*q!%%P5IJdd3a<*{m_?4B=9@O^XI1E!DXyRP1MxX)M}?1mhHTS7fLA+ zH>!1(Y(9@D-EOD1&%USG+9O529#4xxi!Hx(7fZ62p!4s2Y&MtD$Df~x;y5$A%6IRX zA69T&ULNn*8mWxUczK4&7&{{|^$#7$M7uuiJU5-zB#Xjx=`yUO&w6O#VCgIA8oAqM zhP#X_&bq~(iKu%iz(_v#US|n=|7addpqS*@Vcw5o4HmyLt!;XX_j3{)ht*gFWaQ-U zM3~K+fP!MB?H)x8I7+0z_|vRiYHS;Mqc;VnLrYqp?xb>N&1E8)=09&xN; z+;Xm0+;aQF*nJJFa6HGk^76OJ+MOh3oO9?cqyw6)QNO8cIQbd$lW@ZbH7j?*7~T&( zS^_y|rC5YC)eclzM`wiuiD|UkvQO{$WA}yAvCGu!ImF^T^bV_4z)qX82L9dAt#sEZ zi>lLyGdDJ9Ja$FnqHPZehl_qTQA}sxHSj7FgH*=TKtH&38bqLpV!`RPllC;UKM;^? z+I`C$^*S*A#`9pVuF*Fx>PnO$)*~zRbW?Xguji;ta&w(dcIMP9q}EDjgJIZfN2Ni2$AN-oRCVYu|AU{D@A zN9F#eP~+fQ`r3E9k=)*DyXLru(c75U9=ohvbe#9ui85hs3+YB*WOPQ2{xS?N`^q7Y z%KXIK#+!3cY}s0WvMGSq3COgho;q*6$C+Wjk^Uk=&;hxC}s@4UeI8$bP?Q3Wpuk*IPJT4(Td-NhNbC|Lapl= z1V8#i+*tU?!JGQN{so1Im-gq)a~dg?@fF##dVxI?t-X*I&C?BtN9{6Dh1v|bkfr4)My)gBIj1*d%OJ%gn$(tnJwP_e<6|o{W}Zx1bJn?q#_J6 z4F(+g$+V{}#n>i9)NBk4()q7DiJv#bW}vf}?D(QHiPq4Jai3S%B(#kww_E!s{!Y`Q zF}#pilC{X#;@S)JjfcGK68PFzd>U2tlZv;&o>+Q7Kb&YK>FtZ$A2E=QhstuHh{Ck* zG59L1UCc*G@D1W|n97ol1O}s!*fZ7mr2UEt8kYmw$%|#($%FHfsCtJi6Y@PdW&JdG z0;fco8pD{(2WLG}N*Rd5x0o(GnLh*;(S{vg$fhoj%qkz4-dkDolA-#p)?B_y4wC`u}&~|MgcX z93O2ux3ZTxufMVMBwmKC4Cv5HoIVZ9$P^=4hCJgb(vI+x76vygc|)S2R}AY0kDp7@;gEDrbaljRuPGqsu*9j~Ot2F~LMXl#x^k-Ss_>@~ zzLmMDk_5bKDFPpDR<}LxR~Y0k^E9Jp;@LsBPk3C3qZ4K{yn?M!)yx5?Rfy}S9j4kn*b1vD4g-KA>;_S>z< zi&Z8X?<0yOt@A*l%}F~rtA052b||*7b@DZ}&F0oy* z9PW1gnIGjF&v(RQwPFZB5K4D<_u*1QaT#gpJcsxG54XW|5dT#0ophF@%fY<6dxn{r z+5M~c3$6{>fFWBY6Qj6US9hBr?**ER#x95iq8AhwNUo7-i`!DEHA^SjoTHM+Usp*; zV~|K(>t%)Pt?+livZ!Ib%=mkIOR}Nyh!tuFZbf{}<&R6Yle#dSng~Q^(utwa-#&GR zmu+(DN&@9;uWD>l!TPe7DypihCEk}-iGe#Kx#7=rs^w7`igkdW={*!4#l8OfO?U;Y z35Wv9itadO9cmVqZ6&+Ul0_$gjqe2{pxP!HE?~3Q2Gd!mYwY4zR!qo*JltgNRo`^Z zB=hNJOwRxK65U5u?PTEH&)s6j_tZ*-SYQXFC=dmFHhakDoCnz8lCNpsmiM{=80hQ` zrd?bz!#AL%n@W$1qdh;_5jMhL4Lqm(0($Q*YRFT7(r?+@(Y?L|;42C*SwV4C#~>!M z7p!S}ywE{@v(Lb%fX2QPQ@?x*2;`}(+#d7zNhR@Kv)uNr@T{Ba*_s)_+4o&EsdpP~9 z@%>K1m)#R(##RUHwI`NPz`3&KNn;z4BC=V4)WY&rfa(o>2L3RSHaU7mRNiMEkq`I0 zhw8Vc<0-2o*EfLp-3RlnrX>q5%qK~H0f;rCQ1d5-e$BjB1M0Q{)V)e{O<&WE;tNDl zQNJnmU5Wq>)?*$~2iMH5_hqcS12}02&cHXKmQznEyL% z+n_Mb1_Z}0&BrAzSK8Cp$2BddQ`TMHsUS~9bSkxCP)KL0+J*^8>>5$G;t%~KPp}%& zal7tUfe5AB5lTvl;uc1xW>Q&*su z-$(<)51sebL3-5|P(`Rylzw2=u9V){OL^+CD{6CaeF{`iDFs1gdEoc?7%J?_puTxlRj?ZCqwxnuYhgH#tv0bb4raG@?J4Lpxx2QIJ9cS61s=gppj`C84~ zv5QzU?*m#psTD6TZ&YF;1LDV`-Mr^X>dx_(hVA{I+}0Br&ESbXu9^(i`vs&s8j)Qo zyiV5f)-$!rUVj(wiE8J9pRKH2Wx4vNBDN=*t`OQem(@85MfYjV@jO4SKW6{-czMTB z>8Mzzrr_Z^IDqjI?imr6`bS_YyO+93;27mbEAq*-j)M<$TJ7~AkVxM57X&L7tM#;v z6a)f6;Lmp*yQb{HUOo~3JLmJ)SGmSE=K$C79Ax3q8v_G6GospP8VDA02XAM_Xc~B` z4}LrunFkAOnKboWVzHgU$0KO*Bg4o0?Zmqh{U$Y~pS2Flr9zwkV^05P&-4F&GfxQ3 z#~`TC?#X~W8nsd&mPi6x8yb!n>BG!ek-W&{WTuham*dsJS5PtRP8J9y^xc0~zkCm* z@XAwGYwv##Adg-U>9z{4zork4KOMNcM=+_a#)|OacgjAx{POKhmjFhR@*XhLkIKGQml(7NtyI3cPO|zk z)GY$}_Dr`{>8baH!x4t603rF_DmbJL1#?m8H8(}41O!V04(~<@_rO^m9~z3IRr=Z| zILF@mbTz(kqKCU%E$!U~Lzu{&G6HnrRjx)UqK24wlFJ*Nn;9EeZ0&MCpRa~e+jruN zI1|A+eb_J=B9Pn5=ew1pNAl{_74s)@}nXO zegQD}FuRF?o?giia(qu8GCe`hCEehBww_xE#mG-67>>}l07vPgAdK}8P+wP)n*j^y z`=_X4Aj-h|QvDJd%n%+%_FVE3#A(VWvKxN{fYFmNkdrJ*&H`WYS)k@A$9cT>7?OyQ z@8eqx@W3f_A3~fVzuisW2Y=e3wRM21^qiG0@z3K52neXhg)3g|U=JIM@&uT(eS7jY z#qKfFzk1OB`~_F?Evm-R&0ig}ks`&=TkQ8XK?=IMPw*_~FurIvJ6OLgdX^MC0Y1+B zZE5ahR@XA86p#HLl+Le7!Z}>Y73B~hYVh9|On8wpVz6oSON<`}jr96AElQ6m2^Hle zfU}huk@Dlx42vFZO^>&%XZ(?okwN<+&AI}98lkv{u>=bQJN8?|r{AEMYG}gEQ2+b| z2Zu_U=do5(zyvxhhk~3g{<@eHDD2O7qBiDlsXZKcIDT zW!7)xL4F6>rsCC_F2=QjFuow-51TV}BQ?)dj$0#+^OdtCn~xWI7ux*%k_)z;ip7Al zt7oq1y~_jS9ma62W5~s;GWlH|_(V`hNOWVPfPxJ1%zVRJI~jR-9NRBH1XZ52MJQse zhetGHE9>`RRxByXWJnT-@Fg4`I?w8WQ`{6RaJsD-{#39M zFH$}@IJnp4E`pT}4<#{(NJvPC7zcXYd?5|z&)i72b`~ENur3=9@E~NrQMT*OI=2g~^nu#KlyqIjE{UFxh?RNTC zd1mUwgIJLt?Avk_QyIlS;-EwjryxR~x}@niY3GUhy{j8`kE8F@1psl;YDn{X zgv^le^85s^As+0q={}kFrr;1%-p%OilLt)B&>Ms~#D^-zX0A~yD;WAt+J*xm{~9!{ ztS-|4G-j%5;YdX-m74*A(?^%+46%@a9OG}F9xb95fjx;@pDk?Q4{;b3GW=pRUfo*{ zDd@0|1GJCCm*z7|)V64p;B<^r0_dUg7wW;?;vt}bgA9Lb!EX=wFLK+Z4+xwu8>~EM z9Z~y-CDqC-!hP}HWaXmQXdYjIP9{2tkZxlaSl04+(1-LcP|RXEfWWVFRQ`Z_V8jcN zO7iTLQo+vW-vVn1#^~c<*B8|LVlNPiHUv^o=^(n4XgKIXRFa`QL^_L){_|1sumAc} z`U68)0X|DEtxvt;LUGO9FsDQ+|63Bc=_zP##Poq$=}V^DPSXiBKYxSnt0H>96Vt5j z3%|t= zFMc|hPrT^aWt)h zm?9Rtw5_dece8yM0yFww3@}nhQu5=B`>)iqqKJFcylWq{QGcF(Cur>a`n4By z)mhCN)T(2PUz(1!*Jm4Qa=5@aQ(@8-Ox#Qf31|d8tYaGnX*Wux3G{>qN9stR{eJe~ z5$6v|)m+6`Ak5V?`73%V1SExyKueJKW2y0AAo}A2@(oYmcjBUXsiG1U%+t=if6{WT z*Tq2`^a@3^Za9NkYCk(uOx)1$bK~XlG>6y4U;FO?HgD^6_ctpBEwBBt2u=1^deD4A zxZt7xqE>xWP}HhsfGo1smr?i#Z;d{1Fb=>U^Up&qJ* zueAIrt2z(H@@FaUW2>k(Fgr<5wug*QzqwIfFz`HK!^sxV@#X2|6cl2?5UK`I&W2g| zONKu!eoXn$_b z4?uAZ*E$%ZS`87XDw*H!9_(cMPk^%Qjn&j&Pu>7+?oSuMQ!xXIY@|||hw#{8DTod` zvv%Q0r~Bmtv0NZ*o2+*!1e4KpONh%2XO2hm8IA@|t#*BCxj@*}2HgiWegq~OQ^^GS zkUaFAhzTwNr`H%_BJ#`!lhU?EhpP1AaO7pV_qEsh&%$_c7x6d$hOH*D#^Av^ML7MW zSrN|VK#<4yl7`4quadI857pW;B-?+fbNbZ_%B|_y;X31Co7Zc6e0=SxbdKWMQ!RNE{@@qc^C-z6&+fIBx;+f%Aq_i2t%<} zg(Spt6&S4u;piJfSyBl@rrd9T{}3H91l!zSVu&r6sB#(}0x6)$>HaDjJ5Hwx*xfnw z_7F5mk!gbOdkagN8G)B_r0l9tl+%w$HI>h0m{aA-v*k=E zqBn-Y5tws&%Dz2i0`bo$Rhmd&Czt}!u!1NOO;lO^;T00fMFh)%V&BhPQ+rV$S9>YK zi7`az&xrU$*jsHqnYr{Cs2^qJ<>l!~4ai{_ZFH|*tvJ2Dsk7oMKIUb1=~tU*a&R*9 z3}bbE`)0+Lwy^>_kXNZA=W8G7(eY)*!1fTJQci0GfJU>Bj_4sV+}kJYA$$7^D+{W| z6tA=O+grqSKA5YoVPE`p?q}j7)7tyKU4H&&7J$0mT?fT1$uQZ}r()!~tL({)`2x*{ zHw3Hm$WX^4*`QAY7~Xh%F-3?tY-e~Bj-I>koABB%e1NX10_6Zkq&29c(3b*x{yCfL zGj&cul@fr0Qq#^&b)CY8he^@=`w{Se423>MXz~_neZEx?^n_u0bfOoLBE*ngHE`z#6xg6EQ+pS2w+XB1H740Q92wK2zP}DYkyW zL;74QA1GSO<#94<&n$4lQG(JL34lM@`DRb9sr%@x(({DY2wcBzRzRuXY%dAkj7hqM z^%x&qLSEQYr&TL>2_%gSa;x76wRbm=mVmrFZh}sqq5huiGexVNv&1cQw&i7fRz;O1moK>1>0bBLifK(lQp28#cAsp!VLT7A$~FSPs5O5)|4S^?O1( zC^$IkLN|P6r$4^2@fCw(4UwjpaFFGwK_>azsBY;ihLSzJ1oE5k5qXZNPk&YV&zL{> zvnGx1r8xN22bf5^bG?1dm!xkOIfASnQ7RXo1$DZT1X&w8lF=kG$;u~?I%NmBRfnt; z#riVKQ9GHXxgm3F`O{c?ir$1v2bE?MhhXo;=A(XP5e24)OP z*zNFdRQKYV>Aq}HNE?L+1X*%RQ?I|mf6HGn`)&+l~{YMxROjPzh?h1O!;R?LO8p!o+FZ8xTEi$LkQtyc3!v6iG-WzC~5Q<=8zuea0q@=LU|tK zgvBBIFm@s>QKfRzX0m}zBMGN|rgG#)Q)R|BLB>M%wvbL*C^{~KPqtiq?^0KYDQMzR za#K`o#(Bsl0&op#fLih(-!B^B-WCW+d~VhY^th%wb4|lpQh1)UZY;nARD_>EtC&JR zD0q^B%+3Adg>nd?a8awyxdLOtd>t>s@%pzk&7Q$<&J80DqU=OdZ24o@1@8-dJy__E zE;`qtMv0tRNjIP0UHXv5gnAioHMQ57&2BL2Ov8IYRt-{)nk}s7$tSUQZO$H2Ji5`D z1-K&6*!BPFRgG+=q>2E*B})4RhDzbr{Qv}5_mr0p#eM{KYZiR)np30j0gXft5TB!3 zOz~D2N~*PU1v;;s;bZ~+@;u8`bAxfe01ku zH3rKGRait4y>~i(aV?U*-L#S=QhzaI8uOJrXFLp3Z!_RG%UUpf6oP(4!z8m|h5T~} zeuH!~elt;mG;4q)+ek*NdrnKYPqr#ei|NatU^w#O4d1IE>b*9Z^%A1qYpKg04PF3! zp_-N@$2ybIJmujM17VcQT*P?~Wrr;{{jTQWV@|~isxjsCbY%UHxAUHK0DAwlIp1Oc zgTW3@amYB}NnBR6V6=_~7Np+XbgzO)gR_&J5-}QqiVj2I4I&rzYHS3ILZI>eK%GQR^m*+;S&m$`f`3`po zdKNV*xc=3Ent^@nFW5n!*|?!bFm z!BTo%A&dR;;z@haA{d%+Z+x+!JXT z<>H7|O=bLY0jU zw9vur?$adcO;czHh0>1q#TOqK&WTZRhJ=R1ZT8=%rkh2|XWj@B6nR1o`lKfwc>)Aj zkFn7vCnteL>WkbHr#^PWc>ljk04Bpn7`IF8y=r<_b+KjV9gPxhcHu#~L!a<#0Pl%u zrk+2p*b$&NEH~1?v%t4G1tM%R&ji3gd|N1i)WRDafO%UeP(=6LdiL-aJ^s^!bih@H zB!iK$hq-1Z^W18-zAD9SDF_w4(gQ{at@iO2Ly)j^fCxyCxEU~J1` zO3mE6LR3RNTy3MnyIs5NY>QOHet}d&I|r#S^W!dn2eTrd!h2)O|M_}uWO#T5MRB4C zvy+eXa6(#nNM+#jMknbq|F@aIG&7v9O2@m?c<>Jz8RYr+lWSNu&>5Gk?C8*8(7Grq zd!-SXn#uub5mA!LeuaW_yiHUSt4VS|qQwGfV$5%; z4gea`q1MHRQV8o~;EZ7%h_-S#|5iHkDQ%kqQsYNZlSE6QCQT;rv zjeLd|WLc4Kow}!o9iPv)2ne?R5jlXuiQmEh#W9(nIHs_6m39Vr2MV9#p0W2kUYKVd zmX9@^m>w&ZR5Qd8BZjY(#aXLtgZad1O&&$rVF2E3Vi`=Jha?_t1o=T?lPG`mvJFM2 zBp8OuYiMK5QyMfa01lWcaUzyjNm)~&tEq%eijNLUOYGc ziZdVMW(KVFRH!koD^n-IHgsCTr+YPcTEPazoOOz-?rnTOd@Nkh>p(4$Fmg z1STot0T*RZAp_YnDHx^b#V`~X-YZM$3oy$rF?oqPYb{QUP4CGr3U(egWP zF9!d5lmiW6?b}TO!4!!>W4{eUij021g!;&;8{!4j zL*(o+@G27#BYPN_U81fVSBt3xAFO$SPE8EA?P_79#oL>>P6Ue9afR}lhvE8GN+WEY z0AyVdfp%&9H8c`7?nWy30vjiaWAwST27tcjkuvh;1jZ=uhQ9PmbbS0yeraV4;K7go^n_p5 z_KVEOG8ZyPEV)JfjqUYbo;cWt!U6!OJr_z2B`>dL?8=DV4bYRt>q3rL?oEXu*`_1Jf*uQcCe$Q zPT9Fn@($mmda!b9BKzdSi5^kPNA5B267`hg+t3J6st7bFFd`2<$X=8NnQZmO`3g$% zM4PU`ok`=}?@IP+n~ZT%&QNnuM81t6>2rUvI>nlLvq6Fc!efNaszp24q4@I4=8N&$ z2QB6E1`(`@0Z)4vpG8N>R1I>l8w*#EcHr7paU!i9F`K&TV7>Gzy@RKLHq&uj&?j?{jYb_;C9U+HtAV zFU7DWA4#|?;1a#*kk8)%R8-ymwxP88eSL`N-Su~3WXFNd3Z(!Lw&09;Elf_?nRC~d z9(~>4>+00ZMPl?JlWUoA8LbLCrFJ(kgCdviGu3{;gJp@Z`O`B4@Vm65_ZfiDQB83( zK(9*=L|zkF3L@WQ)3~<5y-&Xz9Aa~?qlE1sMn$9`PrYl#?c}11#TC!|8^4Z{5)@H> zhw}b21_lObYV1+XDgvL1bN@b^ore%zdG$F$AryR$aNWIxJm!Zc=+9JMf1!6GmXMZ} z6^um^nUaf!7Ag^JB(@0dMXE$teN9-D_}Zd1@=BEiM1s_aU=rHp1ckfET?rBX?1Fz% zZj(dGM4PZwBn6uUH^Qi&$=qaEhx*jRGX}8rq2^lg>6FR)6{b%5aY&M+O2}C(emEZS zuRF*CHk&6jSAi!IMvdy26$U!xN8{IYlTT=hvzAu!@?Nb&QlSs}1jEoj!O`eXPE^1ZVsaTv?XFf0rfSxMz9JX%fcnJKL+iK z&`0l1wwZ&1f+)>IOb7tUqF3*XwSI?P&Ymv|q@@+I`jafeK8T3;R`N+>RHBS_(B&2p z9-p9=m-bBnFP@5tk0+hUK9L^u?*?YpHeU=N(P<@^6%WK^9@5Ydk36+A2Lw!xtuO0_ zx+!rY|EPOuIB2NyARr$KGr4FXyHXIwh=Z>80`Lw4CRdg4uhhZ0tu~nrL_y@5+}*Gb#yMF}ixYO-Vu2 zOq%)4OSbap$K2OJk4A|C+!)KRdmrdt;u5X&?5EtRSM=+qUw;~n)I5-;+X`ClGavx4 z3>0H9fK)$^RPh3I2IiJ&bZKs45KohKe=NrRzkdv_3q*=OWCMjsHd^_mhO|n769&Jr zv2n+zQjniz#AtM^iwblEq;jcvF&oA&v0kJf7dV7D(N2^;{$>X2i82V+6 z{T(1)P&C}JyA?pvgROE$RNk@FwbUt)@Nu0ki-IwcZ8*<;7%3$h-Z1GC5H{B(6Du4Z z^eAq06v-+Z(cW&&;F#RP@FP3HQyM9U-9Jwh9|XHw7NUI{R+-SkjTl(E4#e{IwKo)r zl$&9XjEax7L+ea9mwx^^2*-Go^HWH^taB8c+kCw*i|`=uMrMi)T$H4>=S6;S+#0fX zspzu22CA8kK9=ix-jdsnQX$@Cltg@myE9L59kfs&=Oz=Ejjb?>2%iz zn~~S1+mT--cZXT4n-7cQpOwjbBK!V2t>Bx_H#g0I>B$lFF1;u&0nC{kroBW!pAP^2 zfrc82CgE0r{|d^-6BC!1nE#!UKu)4h@>W}dkms5IlX}-J?R7xzK)aOH6T(yo6nA~E z0L{(zIv-&jp`lllrzBYQj zeSxpD@DO%ybV1rEd9_Oog2{|n+~phI^jv7_2iZq#N|RQZg%=4`nsIM(gYTVE`1aj3 z#$6d(v8N-)&J` zQa$HLNs+b+cfcB={9w1Ag1PBaYc7XIs#D-JUS>VWJ5_F=0}K>uI0<&UxNLLzS)hKU zuv*X%oh;Y%;+yQ*V2d2QQqCw#{tQ+Vw5u{m6SRj_Zrx^^Xf{_hGGNX+d;TJFqSKtP zvkUIc?%k(mY2n3bnJ8lrQ_ZSFGC0lX)I3Rjd9N}eL6TNQ`OTN0!zB)}M6sTJ=9oU~ zaB5d_6WDi7hViT4H_Q323KJg%4WZfBZnIBk0T~a|ldp&FN?!i*w>U=26n&wwa;^ z;Q}bq`Qt8u!lK`(h;+K2IhSiX;vHI>f^+4^eN5hJMslf7j~PINg^yIJMhtOLvrfSL1$1fbHlbimAGH%X-hBGSJuDQ;iX>J6l zP-4tkUyA!PsYEqArsF4RqKkB&qF!HS(`61%Xlz7_)@IPGPR?Vo(%gy-%h?n@q~|?d$?8l^rovb&aW_=F^EZ;%D7@8;A>(^!we z+ywMME!`kAv{zp5Iaok0$f7a}^vQoWfRrnV?=FLh*dz#sbMZRVx*dG<2PkAU08h>c zWTDlQnqty^d$Cnu^7#vAL1oZ(TQr|<^Yd=xWpM_e;)j0T!xw>i_)M%Onx$d!vH&xD z)*P^9KLNbg8i5c9{Gg=?%Z0zUc(8!Ih=pT>EJtSrT5Tk2*H9Su+^Z>&o(+{P8*+gj zW4%bZMy1QyvW$DW4CqbWEplTVb!Wp}4~5zm6m?Z^P<|n~L(RqYk|T_sX7Hk)-afI# z*u8GJQq(_`Vq8^`uOe%6BAVI2vrd05tz7r&a({4tN>2DYdC3)Qr}?tbb-hM-Ja2%|Vk(s|~4!RW`$2we8(pkN&H(BiX_-4i24XsLSci&2} z;KJ(UQDS_V6n5jfTu~`Ck>RxFGm$beB7|}9pK9US&JNOV#1e#Zx zp69e8oa{fE^=sMFKEfJ(g9f^)_~!#W;^Fpl?!QnthK?Ar?Cp-eC_3UjdrYn2G^Dx${jtmAh?F&O|mtvDPURR|p^? zgZ+d4z-zx!6huWe+<3Z{yx)2U&m2iAfA2HOfV~O=VJpVIg_2PL@Mxpp? zoPvQyYK4HHT}wT6heOD60iaba_Z=Ya2CYE2TkZRsgSZTpV(^J~?cprp24v$E<)>6L z6ae@X3)NxfrLs7BMyy!Fw5w(iTvDBPhC8UC1fP4hWDr)*Q1 z%*dipp0Ze7FH;IK-s%vXhcmKMu9ndLaM_q+J=K*7L#dvG`|rAIna;W+ydKan@~aAH z(bk9Lia3V-p!wbx?*M)27!sA;ArqezBeN}Q6YY1i3F!qSZ^$=()Yrq^Y5uOe_w^eY z?juZbBGSINJROH%;-tSdye=2*gLT$=9|6c%1xZU_XtQaNy(fVd;!& z0yiM=F#Wr`2(U{Qlr>%Q1&XE#e!>SL3;@neg2@9#a|iJ_tE}Fqa;?e$&r)&!yBJvY zfWbsXMMbUD#{r1-hMYwao4yE|$Vi`jt%&Ad6xV+PKV1T)aCUy|C*dnMpI4b6x~+Z< zD4@~C3V-(lE5a(uY;Op0f$rZ!rwMz+HS7p#<1iqr6}DD{xyPEWug;HJ6u_X`1id5} z@WJF>*au7sLo(3w{8bT{+(Rjd05&do4g!R2oa$r|2(}X-JkPiSP~5Pfc<3GWd&gjX z44o&5Jr5YY)tuG7^oa9_{_x`xK3yRc94s~LKmss+xJc_cN{VHd3K9QqT`*AB!7TLd z(0o?->h1^9PHDPS=O`gzOoVOAr7Ms{%GEBeTE4XYDW#3q03SY1t`w)0z=t#P)?q~9 zEy_uLB6=bnJ=TNIQRHpR`=_$n@pv-Tn~RE%zw9 zuWKtre>+*$&-b&tGVW977e_}G>LzCr-t6%gL*vreEobD`(`SoR8e2v3N2)^p=_hE0JZJ1 z2|9tguAac*xYA8MG$G2xM^clFASLUdlAe7->h69fKf z)bF0y?oj!j=Ub=wlS}Mgb&{J=siywV-*}u|>B>yUQZWbWF*3j8>6YeHcaRAVCE1Gfm%&0(e1?r|cWwCl)S0-Jty9ml^K{;X!1H?nhRiD+6?!C#Lj; zdER-v7t^xzZ{%}r{0y}IxO?hIb@g;H*ig?AC)9U&=Zov*F03jM{(1)*F5u;C7nl@! z8*F`Lm;@);jGaK52NnE^`~5J!HnjDt4V)F4iWV;86BA<220%~A<`pT< zh&b_q__%KdluL{)(wm6IKEIo2VMb-pxFmPWTc9uJW-3HMK*)n;dnUspMjw0w-*kC< z;Gn%)K>UA{y=73FZ`z!u;98()pitb4w8e@Q4_2VK1-IhvUc9(_aJK@*o!}0^ zEofN$pLef!?RlTIXP!Ni56pxQ_uP}?yiWO@$Hm@-Fu6h-1F-$5)&?Y0t%dL~jPCMf z8-9<_T`4N(v6B_@$GZSN@6g@8v~zpr44%wRgkKyM4T&Ha(iC{pRy=4$e8u0rL?Qkv zP9-f)a7N2Q6J~^#XasmA?S=P>__egMl$7#oU$l^)GJBbR z!n+jugsL&OWns}b_q^U`45^3Yn}8}bFYAM@DGi)C3WAWLue*UO69jS%89p%5@TM=H7XJ|#Gw*|O zsNRJo+_F^dox^izlQf-xV?aq9u!Wye_oZTg1QrH$DkpSxqA3ZrCZo?A+xC5alQGO` z(u=DlqQrmZ-)qRvuly=uxjp@9?=drl^$NJ)%r^JW5LTQDMH|fVJBsq+6G^g^kN6>9 z@8eBx{`&j>=(+e$(O*N6HQpC1w2*IWzyJcz-tDI}{PtdM?fkDYJZC4&4F9^9NeTvV zRQRyVmv<7%ttIE2C5bGOk_K^9?6ZO0==PQMAl|YK>_5V7;;CJ3ySGCMXDx3zC=bpK z7Mna8j8VS*7dzzZl^{N01hA?^yc6$AJ(4w}?&~)FkBCiiW|Zr&H4_iH+NCC&SS#rA z*5YxvWIDQ(I%Dy8bTATO1BV<1rN2a~1d}0+&xFY}o?E$Yqzn2KJ=k8)%#bA`8I&t= zoAa}OhL{8E0B3Hu$?QQm7^o}X^V`raelpqh}X)Xe$2LIxg{zLBZAHoSaLp%)&M77fTCFx`_ zb5Mi@-xss*5f6oRytk1=67Fm87C$uQYp|E)a-z3(O z1-GkSvEljWvn`O)dB%E?5J2_g(_-`URkf1}j4nqe^_>3+68L}UP+#OI@iaHrh1QnO z$IvPs{MeKfl;+p^X-Kgl-ZXaAc_Xd2lRAjAfo%pEKBikG31YPGe;Ip-81Ps(IQ$czI~oAZG_wjaH?@8a=fpe4U78#bNFMa-%~l%Wi`kIDd|7MHBta|)z=qsVJ)8ot&I?zdPXt1o*KaS!B;I1 zbK&ZCifuz3|Bcq8S(CnmxvCZ|L=l_$f6}`6KmTKwP56VTYxwU`+IK`$IrGa|<9uCvAMv`s$`K||CMB|Vu+9;s=N)_|T$5UyFL~h9ucNp>UMw}& z)%jp&YM5u`X|3K~Pn?6$$!0SNyEw|~j0y}Nk4STm@cXT?34K6)2~cjO^;=&ZUp>ydY;0&pezkJv z_22fM3kyP`|9=st6Cs)Xn+kOB%Vn@uXRhA#RW%lNj(55%1Gd5+Bg2@gR-baK0B_;q zH)4_0N?)=Z1t8=>TW?TQbk#Vq3$n@ne{^m5qJGtZk&2 zhGV%cocs@JT&L)lY-t~tz9ifDyNr?hy>ExqBNfw5RVv#MVke4Ze$nJI=)^bm znoM50s#0^8jkcF3<&`eMOTIyJU^r^159gKrjU+KTmfTBoneR%?bcY$FxWGF_%s z7S>7e#@rh@{y%`t>^8!pqTu9#X=Dt+gwx-BttBr4`ogcO;#hqut|l^KS-rq**8YjA zd)Ly#;X4fu@sh*Q8qNluT|fQf;v57p)Dk)Y-rPEG%9m+1GC#0nc$ML4IvFnmztrUy~gtQetDaI;P9k3FIYA~9VlIjV78b|zh^ES0BN)U#+&%jf3)#^Wo5sMbC9cFzY_7RPyr zx#UfQS6X!CtjA2mGMIJ9e{Bb0F%5EU-oG9(u{BL^0++Tne=nuFxO!jY0!V$|8ce~L z6Ad1*|C>B?ysj}f7)_;37a!!5Os&sbUxsd4InU_Cl1DmS8ZJM6F~?WtVZQ#R%T3hq z2cJ*kWzqiI_+Xc0j+wy$6G#m=<`fYBLik!cqilYh2G+nkWUwuyb*ngQO|??l-_{bg z6Y4!61blEFo3WgHn1SXuAZ(1&`tkM|+gj9R;~VZkRtO^jiBB!M4FKn|Orn{LnrMG$ zn@6;;kZrD9QJ)dG3`U!n|1-xa;`a^1c$SUxV8mVIu`j-kFIvw-`OI6{Uo%Ph z!{@^h;f2Wym!G;`%V26xYjz34S)!xV-dAG4VTXxQI?;w zDG58nYZq8ydc*y=C6Qi+X-dDG8_h`-y0I+g4etm!MjgtdhkHz(gK8g9eT_8Y{Wi0Js~Itpg-)J;doV$QDdkRf4Qg4kc&FK6QEoSGsqtrX_8=gTQsM*Ft#Ef z$2-gSS$zQ4-Saw5Sy)t#W~l7`y>Fu<2}sc9EA1J#Bj1ZwfDE&?#E)1 zTMa4dRGQCRSiV2Ba66C0Igc_&-U{E1xJYA%a2V&nUv)$isiQj{bA8-8QoZ-E^eftq zW`z=dly`*n$Zh33l?^v089eHPbYXD{XQ{4q`2J;!uYiA3kLZ_(}b znjaFB&oeiJ?!vh@^0yj}{=OT(kL$&ti-kS$>;L)%|C4V^O$%sexaV2G4}H3c%|CA6 zx*o>6viKycukmuI0l~8xDqeM&29UR6pwKE@Nus$9Sbj{USJO>k({>1@^I4-jg88H{ zjg4SQaYOE6HRf9O7;MRDPkbz4)@QJK;m?N22T|waP6NFa-s*kAPZw)+#C%78HJ>gI z#j(|vi~V(-W;F%2t6q}AZvTDb=Gmo{h0)c`Vwh}qnZbrg8~hrD3PFI13girVwOY-A zpBP}7(fOABEmt*0x2M%uX42Pe!iX*0bF|?YF&2Z+qz<$rskH8E3(G4kgpLQYghKlf z^X|2A0G4J)=~I#CS56#^I&vhEm)FJmt;dTOM3h|o%CZyE>{&b$!beB<*p!d2gm@%Q z<1D>Apj41xlxruXy|;mnbL+@k7iMP8RfjO>ENIc^q_$MoY=Udk0~T^OD3GT9e|}ae zxw&v!XW!+kLG$;GN(vbHT&x&}P?X=hr=$JL4$CJyMQFa|lUgE#6aoc>L~PwUFJ3_UCf7qtfOz`mxIrM}&TTPXfiS(HK=|2;UVU+Lo%F%DL0bE@`*ms z&QF6aMEBU!sOe#+IFW^nYz?vu9NWO(dQh3_8Wpn%p~!>ok_)FlTo)6c!5k^Q%Y6oQ?4xxD++mcYNOY)_dDpS^QdiXn$Tl2|WwKfl+V6NKF+ ze7~^{t@SAaWRpL&c82ECycIP3qA$YO+)}estU-;=qhY(ajgoqLelejcE8zQ8S4;Q5 zS0w&>!1UD{iI|}E@P~Pl#sS}3ccpRRJ+w~=(pyoxjXxzto%{|?A6rpv~BI=puK9S0FgeqL<-6aNB)zY)j=3R~aSo_>yB1-mZK6~rWZcJBACUz8Ow4L=4@txt%G{*?xN z`$Z!7*?^=;v05(Qy!PQ*p5~Y$hzS)eY5c45q}9ivpXVKkTlA=pywjPF;Np`XAD-n{ z+FS*c_iJIw?YxjoLmDrn;ku52D#_ zq)M+0y}00{5f+D=GkUqL>QtxmHncYazR>D}b!L5kGXPPG?oE=RL$y0K+DfVAclXK`wY`_sSOpc2ceg}3Zhl?U24X&*sSiin^$usB>9rMX z)hxU%ZMo7{TpqrI|~uu_wV+`3A#=(Yr`he;Sn(;-$yziNU8J=7jY8jTld-sldJIJK4yDHP_D*soIX%2caKf0cs|l}?$rYm)sF z{@s~DF;9IRddfcwEQ^4bj(yQhyPHd0yV|Smkf3r}U$3ke1s(JGQ-+O^ zt_x#35#k12zr;}lm^UzLW#<&%YX*LMF{$L?d-*=<2JahuCZ34Bpx@GO9v}MxyPO_djf203=#_~d%F556%$}C1D&Fg7 z^cQ{3q7^)Vs><6FKSTH&rw^B;##>9d$cBr^z;a@FeVKo+JbsWP5!+*&KO{L-Tru*7 zDiUmEN^zF%C#8~axNVO4@PNhGYZ^_Nsr?TdR8qN-sG>bh~ z9rmj)M?hGBY(hslGJKthq@pi$gv%<_eIZNTDMvnr!|raDmEF3xkdk1mPuVC)BP}}M z%SA!o`&+kC*m8K~N15vcmpzJEf3Q@_!sM0E(kH&Zq&BD;V&DGpq;3&Hr<=)&pE~>T60I=k~3}iX1%G-~qDI0J?fxgmMv~yX`&bZt}og2F8 zTHg9gk7m-U=Cw8BbY3YyZc=hCDrOpWgXW~R?s&l`&@em^>-J-H^WgVwR_(#o+Pa8# zWC*A!M?!X}JXVVpf+3@09QJeYZt_uYabYXE?4v;Y$n2%7grJ6=pK(^i-l}>(?m@vV z>hRCgS8Z7<8zd6JfB-w>D1y>u%Mx8sgsx|N)RMfOEW3Zu>ZHJ)ONr10UIxG9a;QsE zhXo?}>KS;^jiOY8$;?GkPmXNQmvHo-Am+Y2d$#9(q?Hl$1Owf6FD0r?=!rnzL~}e5 zw*Br}`BWZuTeve5^|o1yt6rym+=DUjtUE#~;NbcZ8m|QOy|U1O;*9kdGOrNFwX9m+ zMlXLsmjeX#d}%EOS3$$^lW%Cox+oSn$Y8bOcka4|^&&Ih13XU+Ehoz+;=Q|??4RF} zYx>aq_zRA+Og@}Mf3O}G>Zs2wLDU$`9&PU8(W%4Wl69#tSC4O{LmYBqkrcinC_KYB zz1hI3a~}(dar{0ycvP>|d*=az;*^ph4a_?E9Wvl`d?u(MtBRgOC@+P)Bsw9jgiI`O4#r4Y%UU3Q`1 zZjXjNJ8dS`6N-$n`!K_4zRBdQ4=+|fm{|jlb8=PvZ`hy*!o#yvRyu7fC%J7YlPGWs zWcBf|VyV?akhdK$b~wyX7dzN9)A#VUe=%a;*iI>8HK0cZUe{LxIw{vEb-^JiQ2$(` zdl-W^W&`i2S`@L}TQ43k)9@XLu$pVlyIXV+kYXv^zgRBYzA~B%_dFPAsC~!oYBz%z@hEZSwfzy zA3F5EL0owigZH`dGplJ{+^w$yh6z|G4$Gj({sVDoPwjvDl!P0zD9Yzbi`EhAYF@KX zm-}d+=QvW0QhqF|wD%bQWz0Axkc{uCkF-bS!YzpJzLdPU(nHCd8Zvan^*7_1H?gH= zaP5d4S>r+bf9 zw>$PCQAzW6BR%6o@4LQKoC|%H-Jh-gGX4~`pYq!;RZZ_(^h_FqRK~4##dTlOCZO`H zK2iwfFxZK?!tp%>m*cIkFvgl)fRH&l(qGQt4>B4eWxpfSfCBt863>^Tj{O~^kTA`4 zjRjDS?JbQZ_8&;>zMiz9nm7c_8&Nr-YyO=rCbvjz3>2duR7oA*E%nK0cyN%Pt#n#foC@RXWx?OT#WTN%y|wvj%Z7COUYag+;no{oWbRh0 z2T1ciYNgWBS+muQ@i_K9wLHKwxC2GK@_%~)+?jPNM?r9DE5_{1Y&f>9DWhydEI8@T zEl)D=h2FoO+V#AMzRN4yezVe?fPBMPHdM(Mlh{z~!jna^$S(lq)EjdkwkSqf%ORWu&y zg1aCGD>uhd0i{xw+UT&8(8%c|;5QM4rC9S8{#+ND1X-_6yH<-seaE=tcjLBpaFni# zooLGXJQr)7)v%ehtd^a*4RD~EYCuei06%%TYu$dt*M6C!c`j$7U|yrxTB9KunU15z6@5qe;q(VGSaNYT`kVmgD`-(- zv)J!#1~1^iRb`4J{!!PNcRm6&74VL&rydKApTfA_#`3Q1Fd??Q0&d-hdc-^(W}fC# zmQCL}eqW+;0p;z_=-DmC=T2L{d*T17ldt8?oBK44L$_ewHLAlMG{F4`!P3WUg;O<7 zDWM+w3MI0n1=1+&{3ZYIYMN_+CGs2vd^G71O~|%eQn?6DWXm?U%ji(!YM0x6P}n@z zt0BBAKE5>K;YJeNTVZ5rXjrjU#qALV@kJ$m2rg#^0Sa_(Nn{|@^$B+BJ1JY}`nksH zFa`~7f=_!N7owY)Z9aiy*^1bzA@C1Gk8~QU>W8eHRt$c2~yvqNL z2DjtJnqIFOesHmL-kdS15XhFrZwbPN)87s z8`eFu_>$cZu!J67^TW$<-2*=el>n#MIjeP_dt{z_gyw+>nrsQIhR~l1U8TJ2>Pj?=j5Qa$ z!>0lwa&rgPn_dCO+MQ2?og9T{KKzJ_I`4qRPo={XS-la>I@eCb*alK>{yL$+1QNI- zaI-~C&$r<R=3N^ z+v)Xo@)eR<7FMuPcRXh6kO9gHfuQ>m-ys$lsb>niSCeEL&%wf@h^G?J0szgEp-k0M>bLQbuF#li|m$G#eCJPtgcKJ8O^SgeV^^s1_U^*<1MF0Q7XZs^rmI~8L3LQGtejo;cBB~AmPI)J5} ze*yW@!<}&5Bj63i#6)&uf%sqN!DzEa7W;HfSzKY{RAOz&b}hd3zz^*RvY>gKU6Q5V zCwZ-0qGMhWP&;@9Meev;1@`wH+m0NUHOmf}-AL2sRU?$W!`&g!9lOMF_f-9^~ ze?n>7=~4xFt9n-qFjcH}OpI0#)v3+^uoIfa9_}3bhMgW+FDU}haxAa-(2W2~18aP? zixMJwOoGSMa#>cs_ylR1#p; zhu9(ZSdq{Tf&sDNDuqRJ;vt`CW%}%$vR3A#3QNwQk?!G5Xuh8?99e(7h%>Oc%v( ziB&D9+h#vZGag{Z+o~#0W<{6`oO>U#Yv77HvP<%DQTd=R{NI~b;}Dd|FVXL3gla`e zUit#QGUKtb@Y;hkR0xyn=3mWhF#M!OU9EYLcK3==AO^fM1(Uupa!a96ui}_em%ZKt znq5-o&?VoXIe!nlG5N0ULaG(-j3aE;;*6MKR~`G%_2WvH%0SyK ziv>$?bOoG#PI(3NDF0T*umwy=DdY1+Htu z>+jB~ra+zb+>4kJ7$_8{_%D)I5Ipj{!MESN1|yi$#!0uZKs3!ieptmy9Lz$qe($le ze3>unrf!vgy7OQvXzlK-hgT1s9;}W!Qz?#5*wwlpa(a9zJn_w;p9d6Vf84b&i5NbA zlW~k{eb&dI-(*(Nd4U89@{wz+p68J$!n?1^vSA9~5mP51Mv?jq%(QK_Q?aOHEYQDe zcYo(L2G@63A*2z$S=bK70EP9Oo?kb+IJrqlC)*Y!aH?an0CZ%oIX}G+&lk;4(wa9cp3Hi=4&^*<8xeyHsJrW%Bk>=D-Cy|L zpgPw(i{571Db6Xkkwo52Kurbhr(D#_oO%M|^%nQ2tzgk$HSVZnD^z7H!I?4K-89)n z?r9h%=&z3ytjo{T^qB^egX_gRVn8!LSZ3I7XB{1-V8RbVHD+ zs-40~TjaB0j8z_dvUuL(62bu!KD zuZ&5BsU%Zg_J}YZbNyY(@3`f60d{zq_S<%p%W7g8vlimx-ijh?ExeJ8c+rK`$|TW> zHx}C15P;ubrhFnoV-Pehs=rQ%GK3G=q+0HP_uC2-RQk?O9-EX?VbT8P8)Ja5Y0UG5 zGyT$ai=TzMQD3Q~CQxWB@(f4Rh3J0?~jMLX~yO6T@;DaQ&kHa?Q zTzaBL5S$9@;(9}}hH^5z1~jN%=uzcVab6YPoqD0rg5UKi5JN5L#m;?HS_=g*llDz# zxEMO?kia5~O?Z1Y&`05Lqq1Xdq-QBy6dbc5orwX06gNuU)2HVc(^>3&iiF7rl5Eap zrR;z%86#(F_e0`9os8wd{5u7BZ^N;ozP-d0?#P}xzuMNxc!6{zsx73Lz9uaVY=6$* zlnk>3j3YdC15s~|J({?>@B~4BX&SjIIrYb5Q}BT|s7k0=(~5g|%jYFwQU^{?1wtq5 z6_jrVh=6w;C3GQ0U09K!VHFaakg4T83!r0D?QFhD9W!BGCmB>B8z0J74Sk>~#<3rMuKCPL;RK#> z*t=*IyUwlBQw)ig`*I?pLeA6s@H$nIQI;mLVfE`*EVH3x&w>4XOHjSOXSCs2)c-V8 znksw(sZMTiYNB)=P*dmoY+s+LSW4z8EcjHSr}rfAG|Stt+Y#35R{veWi?{aWn3|j3AGreOr)v4?nxDiy_{tlcvEW};1;@jPn6LcFTO^Mmmb4p)CrqIK=RJ*N{7Edpt+2@qvspFDMgeblWeKuerQtZe%$_r@pV#WvGK1g%ao zIAfIf-vCC8LF{jpR2CVp&_m5LIZfCP74Gg6qt_Ar*r1Ie^P9&2gK6x!yy#+0jDe7o z;*nX|9+eB(;U2goe;4vju#aF5&JS_W5^RfpT4J%y+*RgwHfyKFOh9;7kL+xR%o>X3 zbD1^m(X=P%8LhZrNmo1(TYSE8?m+r)Qtn)#|N5@iV;y$^dO?SLWX8-2F zXpO&wM;%Io+J8N8BsD9Jinp%ECcNxCE3d^cnc9L$pw#H{vlIIEK^Fxb&UTy9%%Z_j zVRGu3Cio`b9kIlu^^|k{Uw5N%gEe!!_F9`|M3S;M*UJwikTV{euzx4Nt;RYZ)g(lx zijxv;njM(IGsKWlGkPtEovHOVY7#JZYGh0qq#0#N2in;T6hrwO9EI81*;yNDy%~`& zA>`FH+^X&iGj;WPruRmJ;H9w~ECyYBVvTVP6M1&lkB#okZlP;DFmF2?FR$keNsa{o>n}+L zpo6T)tFU=B0>!I}={=e`kH^%m41A+)A=dM=Z)-Ox?x|H{dn1i{6EJR5LOV7lCDBoO zicW|zuB0xy(un?^%gk+hKm^&n+K(D8-wwowT7k6xwWwi$cJ7fC+T7~(# za0@ zFWAXD(3aKt0cMRmJ!Ote9FZMtbBLd(c)82**dQxTCqJ$KlANOk>YTfL5AS=^1HL*u zILR|w0NVO~1n<$cdZ@eY$J$O+vuU?x-Dw}HtW9|Myj!I&y3w$oAco)4>DY@m16}$m z(q5|tS*5;TX4&EcLf!b7ge%4wTXw@NpF3Vz0~&kxO!Gap->OGeC6UpDwMV=42l1?*-z`n8=jvKM&pG?IKd!boMFQ)Xk z;|OU~M;{a6lqWDqAN^|kZchzy&k9RFeYF8-{n?u!=c?ti(e?Q3twrDAQSTPc7(XT=U6HQ!7h0dWwtzcz|Z=$@6!#|{5bGo=*xg1_xwT6}sR3g(KO<=qn z=EWqWWAWt7P>tK3LP(Cq<~465C961R1;A*f^iSVS6NY{GeU+qQR#&zM|F1(%+hr22 zJ0}5VTe~~!53{bALeG#*X@1*Jsv$%Cc{}Oi=C4_vGXva=*~ILrO|jkPb*&iH?8I^O zXxZ?*7$VtQq(s#(*#Y!~DY7!bj6q(iIzw#SSH)bADe0>&N1yHx>F(cr=U>4qsMUcVcop6iq&!RmK`yESUQfP(HWu{q z_YF33Yk>@Dc1x95aHlFOcp78{uD$WT{)}2)mc*Q&HCaA~U%S9VpM#41ylNdORD=F6tm7i^pX4*?aJ(2>_sMJ=gUs9B zC=s{$j})tN^t zP$hpDY^9hO{RvdJ)ULQ|-GG-5ENt@^5JSx}PA9cHy?OR>>cruZ@4HPyprZLE3SKB5lie|~DRv_}3Y< ze}Jan)R&(60_OM&>>L8jn>GqmA}#H#0bZG->#zF9%;p@>^Zw;&_}?7Uzy3H%7H)*|7h@QpC}N#jQ3?XZgZHT@yTdt0ktD(kstxZyZDAOs zzmT5GSmJAe&gbJ?Ijk;9*SOC`sS$mhPOxd)F7wU(Zm@fkTu74dC12@#-q4)?DRauI zg}rR++VC=3Zz^4B-Nl{0Bk#~7uq?J-uzm&(ma_1nT<`(E>rKU1d})0Dt~ibX z=I_NX0aZ8e3IEy{7)%bg9HnF$P&iC;N!;`7{NsE`@9NHV!qV)cw1S6iJk3;im1)_{%$^h;Bvrg!b@{z^i?ZQ~9-8H8>@Syec}T$ClNsE}k#=;X zh;Wf7rvbFOX+jv^)ZvavI7iz|32w8z@Z^K3C2)pN*CaRR>5jLZ)dnkylAE2 zi;oq|No;r@|0jR^4@UR;x-KKXVx|RRhWWK7FR-yMR9#XeoT#xA>&rX4YDLRr#+-Cr z*w^Vlzm74Qq(O@{pku9Cn(_GnDie7z?ov=8LGdb^MnpOt8iQ*H>7;ZYXU?Dg0HHUG z-z->JS|8^Dn=>sqkto;1NSPq^>cOT-11jebqBvbQC>HcBfv@^fe)E?owRLn+ynQe> z-#(bPR%5!b0HX%H&`l}_X`TsY!~oTl@xdRS$?)h5Seu0GZ)2g&!#~w+OW_@<+M=K$ zBbMj;m>%}|*0#5wl`nY0FFm42KH5iFwaS{lX-cbP_>B}vr^S$lPqQj|e}pD$H7ehv+>?!y9u z{csM6BmQI*ZBU2E*EEfQKn+tEGHVgos#=Lg{X7*B`A#@CcO(y)J3=3(-kP9x4fi~0 z0nMmCG|r%Zd2oJ0q^jG`Y`2vqIKI_jNMsW#K5kPsQ_-<%$}rw;M%8TcP61~u{oW05 zy41V7jxF!yc-K?0`>%)&fVp{+wJrXB)aRXTOq7=?Z9c9y)Pzs5O5>!i?BACG#cWJ?dM5xdAcLm z@@!7`iY26&akDJJBPQJYhFUA1vNmx3$$QUW_d{-sa9|$$weavaG${yv>vw47!fawU zzfKFL769()@4>Lt(u1WCN0~pytYInp^bZA1ssAb1EZvw11w!W4?)eUj=&Wgt;|ULC`83z-O9{p7tn%Ob55}oW&%8J3 zM2F0AtC2Pfb3wY_DUvD#an@ezn=lYWPF)4OTcao}0UdQ<9=q0i(OaCd*vx?tv`oG&RZ%W6KrP zRs$H5K>#1HVVF%5?0@r`@Hd^NreRYu_AvFd{`pI8d&kB68#{NqGvovk^gikJ>_S*i5f+_#&;D%r+t7B~lVo+}6L4fA8R z&&kf}>nNJK+wSN0IaXAd!05I9#w=WpLTh-(z@FHN+~-)~-&Zk7;Q4UAFgur%zy{tSblAW?)EAFE^oj6%bAjT)M;DoFx?w-0QcSRp`22_-rY98QPdiA}2Hm7Sv+i9*+Y~s{B!BznEREsfMjfdoArb zOkZ3K_`7pDv@@DE7dLJ`$zOe%R)8}UOy1m4?|jZsy#0qgv~){O1{rs`^Je zdjHan!!&6FFz#U3%&mIv1#63{x}9#n9$E||)X8o*%G8Bjym^I%ErhIsoBw2kO{eM8 z*z<9qeQoj#VjVIxfS|K;VwNupuG6FAnB=v|3^wa{(n+salz`V=ch()4zs8Wlq((Ue9lo} zdKHh$6nym+^<#L?{V$2zyN;@8eYaN|eVJwpzl`9QJ{~64L-ZM0R7Sb_j7u8N#d^e} zJ7(mrdwUlR%|$!9ZT#n;s7pRKB!EwIW}Yy_vu*{Z5j*WgH_yA*dR|5ezXaw#Zxv6KYfEyy2J2erf4 z^;AN54Kh;u*hQ{iMWQSUy=-(m2B~iU3RU(ahvWy$(S=2;0NFWPzj|mDQoa9}K@y4{ z&Asp!6!Ro6&>0mfufd~G$X9Ya-Q~70zc|iDLTj;7U#8o5fSC57+-hGz?7hDYAB~Mt ze8=7BhzM)9dRXrGW-i1h2w%}eQ{t>-w&i?`bKXd~w;c{vhMpcG2~Bvs47n4_2eKR5 zjYLJa@%In!Y27&x0rR+OaB~mk>o(u3osMa-to$@1;wzt6t~D{|&nGPDtwzEVUmY*j z@P0aEp$vu6<}#T5U;?yW8mKXW{u;e*pw#CVooIT|MSLi7@Ys({d7h$Zns!Xi2`W-W zPL%-rkA9>e-^**iY;_$y7>9;S1qI?t)n^4q`$PREx9#*1ERQ85!QcH$b zW{62-^Lc4CoIFssvL!Fwl?dsN-j0SltafM&GhNLe6sl?yTjpodFC3IVr*8k$^$@RE zHGR?H@HSM? z=GOB7eRbAzWBbRyrcuza!7LcX_3%L3AGcK>Esl=I54Xoz7Z*Ire{Dg`b9+izqB2qA z`|@`B=mdL09T$GOx20MRD{xR!^wZ%7Cj7QbYx>8LFMZE)ZaT^h9@1~;Z_6I*62vjd zFHgB((@7guuM{|?3n`XqcemXUA?lrPGz&u4wRJKof8AgGYNv@aYnPm;#=w0t4N=qS zrh6Ga@VX5CU}6CaGMQy@ud<`A}S3t!3|UeCF>a2ZJo zcFIP@t)g-h6^yTGQELGukAx-kt#S!JvwUzvyQwm{^C~34J|M z-;x6VYz$n5TUpyIyG4Ob2jHY^O4isSfPf6oKgl(mh#*DVOIG4GiYd$NG&*xVWB=A7 zBLEv577;$c{_*x(cp&1vhEFK;M2HCh{4WpwBa$^y~fqtaGXo@lQhF>tHJMx zs{->uCLCTon^vv?f!6ScRFdl)`&s)dVu8}QT+G1^zm%pSMi^4Xl7c9ELlBC zNWYZ3dL;t-wf+ir>aDjdr`CGo@uU;nq}-jt!8FP#LO?PN8}@PC2^rqrU?W$7R*Q6Z~FnY(?SQkcPWF@(lJFTEyO^ z;Cu|yF3pBm=&bCIr}9^u#vZ>EK6VlW=Pz>Bx6sk7i)U{LRj|=0+Dg@DjKvzMla9v@ z9%~gop}cv4Z{Zs6__gJf;ZSExngbuNP^)z?iDN)EVTbLqffYHN@ZP1Eoz<-Lht+5R zlY;^>1!Sv`(GNjF4&4ZJH-SnL`G28;PjnX-S{H)*VQ-|%&dvr4@A4hFjx8`zmoJ_* zIyK&JSlX%odVmQcn34^t7q#G3Eugc89!grWz;6CyLGvd2;!6L-DLowMpE zudHkJJYrI67euD(pI!1 z@}%)ZHp7`3+C^to^zD#eYl1mYfF>U-8l06Y2|dnLV8kg<?O= z`m6!#73U%mQU``u)nN0{IjD{JL|8BAet~B{t(3~^;5$#`cv-e!CRqPHB5u*Fx8X(O zY3G}gx42KG32OFZWa5lucRijwdF}g2R3Yrsl7M-k{i3X(gUF`X5Am!Lh@YD7pn@6yQ^g}Hb2TH?)Hxq4S_l{b9tbO-)*eID58Qz_f)Y~X%wXBq!vg>dzjyZ3Rb zqy2PIez(hzrgOVNT7rmf)eCVZ(Tk^p@0T3P9Qpj-*bBQ~ASqN}FB87gtQyFXIxe=2 zL*64~wjPW`;&mU$mvutU@eP-c7b#8aGt2_axd-Vj!yEb<_ykWhaUz4ZH6aOKR6K(u zT~rQQ%v7T`t=>xQK7P}WaKIN;sZ`$_h(FeEBY}q>YYBh#>*c0X+`&c&L$sT~wpZs% zb3s9&_lO(d;;j8m_GcEannMqQ3F(lBi|wv91nVSzy4fQ$gW>G6FC1>KXHZ9R&PE-5 z3@JSPB8g%=yc^@1quC##9D{XoGsAQ##+5%MTI$P<-9;j)4<;H zRk3ECDI-!y+F`Q~R+G1=|LBUxw;AZcll*Nb+0Dg{riH7zr@V}vGl<_+vlw8CkvG!i zYiA6lUxpX6h(`q67WX9!Rp0IJvcmFm`wIV(&CRtXy_twIzI8nDi%v6XpOe2bp<#Aw z*m%ADwUX6W$ik$VLzq+UUr0i~3~qrP)F9YzbR%gg+9alUtm51yJZDe1dPpp}W(9ZZrz#(uN)|e4EjDQP-)}QNWv5$Scu>I9;5`h}aSE{D9AvF}=DB&t zN{!~zv{tS=JNInXLoXa;KH&$fRFam0;2X=ucQAz1C7*QIF~q&9q8QYDtf6qk*(P;! za>zgV;l4w#KmB+S#Xmx@O0P^scQ<$EXzq#T!n}AP279T-Yj>_>h(K{!o||@xAffrj zkCiqt`$@`N?Bin7S3S#g`<1O;$n&QTh|)jqD;FvW6N#i4Slr4uZcgk@mTD?1EQ%Z% z>efd1tUsm69?Ns66E!%H;6Zr4{dHyP@i_spFymdpe^6XaM3Oxlbb4QrbvH6jGT19_ z^D;0{zNRA-?hM$P>S=_|mv%Kgm3b+RySQbXZCAbd+32=`b2U;$f?#MRwS2boG&=7o%<9Ff_t|*#6z(ceOZA{1)G%YHj)ehHaMLNx z;lweC3!JWxkV`+}8#qq{F$jeR!`5w- z3YMXHt}2I$B) zru{ zV(}YqZ;)x4%f^ub>2j;{g`o3(OO)L9b#yM~Ij&c*m9;rfT}((hS-kViN)}bRNydUa zW_)9e)r-+!?jsf6JX4 zVpMpxfi%!P{M68j^8=gW;vMDio(D2u z7UApW^#oe%PcPD+o%iIC7lEG@BSa2IGPEP{M$!szlIzIN*h(!oY!w?y)v$h|z$9JI zH|x9Rin9{!wL>G2^c#UX!b&$MtMvM8pEtaad(jY?OkKKwo-z@kG-siB+Cwws9kZzK zda#$un_6jMkKvvR*u`LXcI&92tr|)j6%2=1d0>;TrZ(QC7tUW za(aGmYk!d$hLgd-i%_n0f~kZ&l2%{=9Viq?@Ibke&HAz&+}nz^o}|I|yV2j?@mpJ5 zC=Xj(EF#?X^S$&|Njq{5FnG>LH{rK^w);k}0;`l;=4`4@!<=UXBYff_sYzNUW{d+HS1^zfe%tNEQZSlVLJ9sG+$@NpO<6LYRjl2;dYrn^aa>7k zF`3qoRR@Xeb>D6x)Nn-p>PPg~3(9BiAQ5C6KO>;*jqQw*52ZQOS7q-Qn^BJXIu;(S z4uwz2>ve##Ywk=7QBaqN@EH9bps0nGs{CB6)oy|Z zJ`9dGChTPv#^vEN-#NyE zm&7_p^xvV;f48#=<^BcLLvC*{lI$CSf zy{h8*p>A~z%`U04=HP4;n|6hFipWaQ}>Bb(|6r6C-1n!q@brq`} zcxOv!)M~t#!aKL?TkS0qXYbDfzw8p7_4gmodp~?1g$azPydb2PO^J?~$XHinN*0m7 z8sh;Je}XoO;%%O&u5U%7jgyqHHp%d9hN;_ugel|qj> zKzgR*PGy#9v?1_gO^Go2Tdza)Z8P)8iFn@yJf~!fIWbW%TN$0!agHT=_aE+c|Ie`r z=6;5$2W2Yl-<#B9Gmbm>iKMRXoe08bkAt5rQP3hiHL~wYD_pN5*|nF$vRlg{0Sot z)7bG1DS`XTYiv5B`}6)1jT@|Jp?b00O@XXe*?Yv{H5cEH<{gE_WNn$B){gaT7I2jP zpfmko950#Nelc;btv>WWcK=snvcGwu;YJp!Ixg8HXE#aZv5kY zb+%u4-#wIUuZ4+Tq2Md}(jwia-J487rPaA_yBtMLDT-xmM=zeeTr<+qX^W`y?B%Ph z=Xg{cxgRL7-j`*@qu0e0wevF5`+j?Fxn~n(ty}GQ7BU{Q`9<=v>df}BR?${>nyB(ByF7`%*QL>_r(i4BDaIEU=-s_RF~6bNWa>po7TZ)*2fyxI6qrVLTRd@ z{DWOrZ~R2J@-=d~%uCHde$DQM`TIVX@54H-e>nU4zg&X5OCootrHMPbBDYy8A;k+g zzP2>Nv8@rW$oL{?Von9U6cOyG6q=$DYPgn&SqxfaM2C;Id*6v|o8y9&Hrq)kdY1;u z-TBF7F?ybFm)j~%rLj3U64?h?Na03vP`36Iqpb0B=?6rHysH@J1%*JWHAR8Wl_2Oa zaKiVjtN)Ybe1bNm4jUnM$dsNrp`E&ntOt8^#E}TKAYVjF4OM(lLEn|N)xreYg|wYf zqr?u?%MW>VEz--%9{(DaP8aEsz3_IWu|9v?VTZ%3=^Q3w;uGC&&Im4F=PSA@~ zE>@7`xtWgdi^Iljyb{(~i zE=GM_ok7B_WjC&AO}h1s=L=@q%iYH<_{V-$G&#>B`X1PahM37GXRQ`Yh(Pr8^vT)N zkL2HZklOf4vpv9xGB1xzpl48Bbi}Mx;kto#s4>;`5o-4zV4a&8qqL(-ptGZm#k4Of zwr#@*&F2tWaCC8~aN~|H@NnV&_a-xcfsz04!u>9mJIm5+u1xK2?YqyOl5v1532_mHI?4E|JemXj)Lf7!Rij2?qs+CH%6}w1=ex@jIk!H7f zNt=Bt?#{(`SRf+*Y-09b(O099JXG~avMrNvS}&QsBe;-q^mdyPGZEV0E6#fMx)7IN5C=Tm9u?5vHH-6|un zV8}ec=(T?Y6wd7+b+PLL^Y(~6jcU5%5)O~i6n-?dMiE1M5v?KWL;RS;?kG@@(L_NRr6`Jz4Ro<| zMhXek=HB@0=ij%36MmqO3|VlqLq?G^x|^Z5p~8$lSJZzM+V>j8D>*P3Z*@3N^WIvK z=ZcPQ>$UGr1dr*<KY09jNv-36~jF|hVsEeg0f9N*!6XcKUDuoyZOIP`d6rPK}byW zI>emp$Ss#=&-#`upnYDSHiW?^bUk&0MEwRT{;jW6maU(-Pms(;@CYG%_l<2w-R>-> zK)kE)?pEeygyZEh&B*Xa3b5)$6=!M;W-@z_?0J#*k6R?8{ES(Gh8Vmb z%_8R4!e3nS_%mM4mkM~AJ0UdiaC|hjHy^0MZ4}0TYGtI5n3#1@>ur1s|k-ltszO(%GwDk35)D^3K zK&EgxgRfp@&x7)i+Sto`8q1r-g3*t|wIcU(v0?wjxoJEQ4P}qSTbv(S9P`c_PLGVe z@K-47XbKWRseys=h%DP}TcyC_{W;*mufS^Z+=#Y$LRswb%@j4s5l`rv zx)lznuI~QQw)w{=l@=27><}_S70du|5)`vc4Y?hL;YAe^^au%$*2hcnSN(BG3hQZ4 zMBUwZi$^6k=K=c6PeWD*8Nn%e3Q=2IL?bKa=ku@&<}Yl|%|0whqT?$wpr`#aSY*zP z^0R6Q8YAlhmp0t#OytR#05v&$H$j{|l%_%D)EkbtMvK!qHph6FE}K6xgIyS6F#F4FPY z=Cl0Q_hVk~mQg&RdLcDol3X-rGPFD(0@;u+Q@diCxgVvNll1rl%+xACXR=`Ss zK3OYA^c>A6B?GRt>hzuo+pd3@DOutu&PVGmRTaM=E}3)H=Bgg$<*iABf;XSWpN(z( z>xtc;Mm|0tguPOd`*CneTEg~IC6ugt37&85d@isPP`xUmEA%{%z|JPqpTF1YizcimX>!rYE2b(s?hA0qNjZSFlgg- zLCwer;paEZCbq*5p1?mvY8=E>;#R?P@sFY@+j<;7y@ z>p$3aqXeWwy^8AySwU!+@Hc1e;6!CAipj>zH2@T?DCt|R~b(%irEpa0`4&)D7TU)eu7yWjq`RvI1> z7WX+pN-HFSl7F0(J{YA3jRj#o8qbZEj`srYMERb7UdFqMC~qc=BF z+1KasX`--FZZ?x-exgQ`BcdK;jJ|M(oBD?$-&ZImxLuoOgt(^+Mf1)knplQW3;=^soN%DSz~W>~S2=6#8AQwGD3wBZs4&@24Lq{0|B-Qa&-f zq+eKPsJ&e0!mfL1g9x>7NS*CQiFx4AJ5>1}R(nFA=%3%)A06h>bmSu=Fk2v2;A=%c z>GAld`+_2#?CH-YYKEGW8Wg=hv3{#Lt>R#PCPnd%=M3dr@^^By;wl#QNyms^$_1yx zXRc~(y{cSwoj;g#BI@*3`Ljptol4GjCTrIbU%XD{U)^5pSM24ftv8nAJw zSlm+17&-o}!u|hXO@9qO0WU~V_3a4MZhcJk=cpQ04&(Y3N{H8F+w;Hqx5<$B8sf!a zoyejq?qP2&M`04v%3l-79xtk_k>zt$$#Y!|Rb`J9T8UZya&maiQMbE>UxX~n<#zA< zI1p|%QeN#l81EY%E# z3FWmF!iOs3nKI#zfiH+>E6t+K+-_zq`&lM2%D#i7?@uOj@;@>?&>|WSifv7yQC^-8 z)^a>z>$t^-<@kooN~aWFL*w%jnvW?DscEnOb7eRg88Oe;q`nWLGMZ1D5&K%?u51$M z_-YnZ4Oi>8hu1b;!OYT+kT=Zk>+4^tk9%m=zH!}Z=I&k2AGmHrfr~%~^%p(D6bWP0 z{lWMjR=*1p2-6X=7)Ib(w4r7ntofJ8a;zDeF|IjZ)GkKinpQRILU)FXb1IUH#jQ3> zj*r8=Xo{j&-EQH%kBDmwt%-^HQ#5Odsy_+#t>eIWn$As)Q=LG$e#}qY`H65(y~sNo zNtsYB1Jo8G(PG_8(H zd_k+{{r%<2+O%F$qzHXA|9;gW8_rQbrrd05KfGAah!G3v?&??%*=pe=e5>=t4TKQA`8tc{2;M0ST$^mYW{J`Su5 zdq!YSRNeq)PnH;tQ@;ecDnmtOILVou#4(?8i}Z{P0mswLUv*XNmrI_O*IQYY76=OX ze|oUW@ZD`WG9>X}U_a91+Wq{&;+)4`V(7l(?Ndx4FfLKM=D+9Kl=rsQ)lO!a-v zQ7jMztDlfo>>()X8zQ}#LQ4CGTu@ImZEB-!TYu5{gvL+OL>4~5M zLpcYv0&?^@MM;>ACO`{~`r1H3E;XX-Y%dlTmW)hV98PC@vK)=rKP3o5rm)t=taMaG z#3-T8=6%h_cO>Ew7r}|7e6_ZNwNU64L~WheRhJgZgwGkh(W0ueBbFB0mw7~CjFg8m z4-95GlTFg6$e>y^8ec&a!$Hx00aH4qe5Tr?)NQAAkMA!U)d$#iXfGHGc|tg^e_HR) zDc&d5-yjv`ynEofH%_@ASB0k10t4!lU!w$hPX+mr;RLaeceI63#_7{u8PXPOr21(U z@_1@7DDYs^GGn4{)km8wp2S*h>{ja?=pxu*dtIzL*{%1*#=hCGk#}|5J#oqu3?Xp+ znJXCh;@7p!!Q-gZ84gwUvoYz3N;7q%k#xVa{rOoKBs_iiifP+f6IG)AnR27ib(xFz zT$jzrsT-AMi<~BOZj3rzq56R(Go%3}`HvGdCvxQ(qHT1WzCOuJ#)Gau-I*LDaJxNP zjlfY4A>>*JWY;c>G^XVtz7X4K1#)ey>(I1~}a;o%VXr#TNJKAW|9W$q2$UiX2~e2vYKAioLp zwGM8n`7hoNV4C<|`J`Gv$BmDN1?Tl93HA@mf%h9zU|Q(DS@kve&s*q7U{BM~?PcKn z@403MfT&t^5wsYJgD0(K&r? zzr3+`i&~LH5Pag^S)|@wG(MEm6jZg`-)?Z-tfeaP&^aB{SBfRFzu&&uuRRcTe}6G= zm((rL$=rP&_-4SjV~88#2^7lT{Nqk1zvM)Chz8o?>ZcAeDqoa179&x{|XY?%nOR#^p0Y0@_&!0QVW;&t?wnGSV1zBMx7h_5V3P%10W_xOqp52+l+ zU2D6i0uxRpomn+0_qD~ecJE6M{c(8GZJVx&Vv=C#mww|(RXY~wNJ^p>Y-k7L`m>4s zk!SgvyibsiG_dETL%lq-)LhPFl^dL^3c(e6GXo(C`z_LUWjR)`ZbIs_+1MU*RA=iK~_TEqvO+5EG!Sv4u0RE zJ0m%tB~FOlmfFXt-4R%vTi7rI{q)MkkQf@tATM#g!bEu#REgnRhxP`ZEC(>u5RvQV zD3*Q^o7k{?`uEHK1ge7Fy`OrC?EZ`jLO0h(dG^U(E7uPO1~t7ma`csox$;vUEV(AG zC=jK2`uTJWN_sQ_0eMwAwZ;WpMsKBnjDKi+|t!%u@zo8uB?HsvW@>}m8eM7iK`AYYL zKrncu%Ih0Q!j8i9LsDD7UtIn z5{%gBsa$2o^D7s&@h}w9hzRjPXR-yJW_mWX9=FPS0+zq=GXL^H#?z4TCQTy8MzUXf zkmzQr#E%IkVTmN(Jkhn1Bx=!(R+ZCq2OC$dZEPJO<_YtBj*;~N9JPG0__vrHav3YX zz7Y+clfM#Ol^iA)NOKV7RS`c4zQeCC!*#qC+N?b^ud? z%-Xv&cm!h&K~2pRunKt{xvOhy)n8**A;G|G+r@{*hdZV^aWADdlKT516KH z0(_p8qU!m)oqBY(4sb4&9z+2$6^}9AxYDrREn3yqLJ)5Jl&7a_xpbd&@~~5es#l~A z1pEb6YFvp5v_X$>6U4jUL;#{9UAR><#lqg%S6{hJV0XbddE1QyyBRR6TdWgK)oHJs zK22~mQ*4xg)nd7=j3ji#RPNU@_^DD5tFrd(f7tHLRFi}wfsV$L^4?oEO#Gc!Z6WAN zz=LpHZ>HIT5%trFPWuLI+go7BxQ(|cg-uEICxQ_W?mm6Yd#K>Dq#mWzy%NTP7VM8< zY_&Nk8~xlpJ6t}oHE%w_pj6$^Jy$B9^S1dOeIBjyc)NI>L7Ci;tUUZtBzG}&% z>}=6~C8%sCM~%`m0P-V&({3@Pr~mr;#)e)$wbXdI)%yaGX!`T@c(WNW3tdq9gW`IB zyk6y^YwdHqcSFv$;j1xpYc&D^SQF{O=odBcQ9W`I#6p66l7Hvg|F`F1;BE?tPW}kt zZU~pBQaysNo=%H@9T6ER8?#ttp&h-~PNR{?4?Uuqe2jda*7dPg-DC zKXP|sl^cwbU$ftxj=sc}n}}{{Y1vd$Q%j6Tw;{z5iJ}!gjj0Fz1q+#}`u4bY53r01 zK$zktq=zj8$Ejiy)2@!R9sK?McY*i#q%3!mDHG%;@&3C1XxxF~Z$m0r_bG@ckZNxsLb73v zyCFe{wwu{`06?=41+N5*N3T6>LD<_VYz*$8hDg_J^%*Yb8tJgB1LO~rsYyS<{_1ii zWF`6>{0TEv7AqsyVc4<`!Rx1cv#ciD{j7_4&{dQxy)X5Cpz6j6)_90&P~(79-@V%BuOi$F}as1rad zvsshMgh%um#h|`lQm|P?qK;8!KCK&lB_dyGGCQHmF^tMZ4Sy*i(RDs+b`Z?Sc2IX> zyy$XK4)Yvm3OxCIjN9!B;eK`PK|}3U6)tqQ4x3c>^Urrbd#sqp2#Z%Xf(bZgPKRA1 zQUnC?SPaJ~S0n}546|Ks&gn^l)@c;hL3A!5=JSbRntue;=K!o;W$eXh2m8$!vLCgf zp9iSlwkVYw>VnS=ZV&PJgj@AewM+IOe=#ds&9R%!Zr>OzP8y5RL|;b;p&1z&835pw z)g-CbUYO9o3+5=H5HHm(Ik+L*ao{NJ1>A`M0n}ht=b=z{y~^OY*)2Wqz%^4~pAvY2 z2!HwRxQit1sKKHc8v8Ocw|t<@58dSc_G(}033;@Nr7-hH9+XG4fooPbtmb;9JL|BK z@TLG)Oo)ZrDcA?!c1rUcfGX1W0F8Ldijf9S#%7QnZWsw=OQrnjou8w2d!} zYq(rSkcQ|1;B^~P1|vo)AvG-kLn9U9yQprn2lQLJeU)g`$MYZSBa>ZNvO(F!D@dNN zTsZ)?_LTiz`0`-X@9((hV-QkKgm}WBykMu6&q}_Op`?Ncf+Y?- z1~&F=D>9ccTZ#U1n_q=iJG`BjWTWeyF@RSS^-dQ!1%1rF4Fh=4u=dk!Fe9PTbuuS zLkU5!?!aw?@chON{P&sZ3Ic0dZJ~qthkt`R8yeA4MsTtN;_po0zhDEmDHOa_DPr#9 z|Jr~ysB&LO1cL(!CbFd|W`Sarx>KX?eAJHp)?g%kQ_}Mpas?Kh68|Lg@9`3pp*#`8 z<%)&k9;e56;~?b8#-QD-*<``|#TCnx6CE5d=ML~*82Oymn-Vm%dGqgTQd3{$syDix z_5pjDOLW}M-mIa=0l_3&)vBLmI1K zQ^ne8sKjkF~v`2TRjxRWcOVC}Q%6ek4!@Hc*9J_%;d z!IZ-ifNGF-f4)}P)wO^5=*wWD35{G{kx9jL$M$5QdWH!Ap3`6j z=dys?Gc}#9Fv(@Er1k{f*Yu6vK-ogQlXCo9lN=`RKe6N;)SuJp5tF4vm0(xhbKq%} z%DO&toXPA=6{nS(&d;1LIGOECmu9h;EzCVe2`8Wn3;WGmbmC8>@IBiZ%ML%= z9`B8NYhp-|UPvGAeOc8e}1AspxCJgk5UmH;;7Qg1bBcXBewRoU$M zOu09T&ICY%a+mXIP(hh?mteo_S7H9EC2zER1CU7F`oZVFwSEl|Y@#Jyk%#9?cc@cB zkiaiy?g5G07O4Jmu%8sGEi(W|9PmMWsbx2BBcJgB@2zo6g42FA2p)6##*&iX=iMIe zY{w)8r-4$JdT+l1w8Q|QM?0L4%d5B7syg+>FxnnAKa1bqjsjSu>CpifHeBZb*2ip8 z!!-1$JWmv=bKNX?B9H8EEr*HF7lSx9Gofr|(g;Lg>bb1nvmfpzT84K$X^5~;C2)O7 zT#NG~jBhZY!XTeMLnN#k^L$>=B+~J0TXCf$ zs1?EW)qjV8|9hz52fm&k1GviM0w@4inlK*T1JX4LF28qEWT`fu416${>_)&xP2Z*M zxlIkEe#Gm0W76VcxaUWmgo2YmMb}rtdVwF0flNDW!OOPah25V3)XPQ{GY-9hA7wY; z6yl$2?*TY83MUt{B-AaDEDC0rXEb)qMp-XksC86Ey~l-l>k<@(gmPS^MV7=ghZwu-rX@9{Cn98R6jS&7dAI+wP~ zXz)}Ty9X*Qkcll-_@x@<|9v(8vL8%<1+w*dks)En+_?=5vQ^#g&fWt4V&^rKBb#e@ zItGsI`<1!`+Zn2S^(PDseTf{itg3f6iw~T8Y@-5}pEDV^cP8@VRe>jXlo$Bjpsex1tlvCttfFj{FTJK@f$WY`!7))Xu0}8TzLas*B8gq>zpjCD;}(8>K8JO%70YSOJB<$4S=QpOb`xB$<}Dr z2K(l!FG=ug7c5!@4Is#sTdZ_Uql>d^0*mucbOG+QhL)jQJ2dslpFjd8c%9Edp%#=0 zV4DH(_!vTfPd8TYWLFDP$|g%q?(|avtYOX6!%K)kKwO&v3{>gY03R|(#6;yzLG8!M z+PwkWMx6Mb;br=4UlKt8j z>9?k@fq(^q2g3cagAJ4=-D`(q9qh4`reIM*H<{tba3DAcOlW;DiBOdRV2Atb$;OY9 zvIe)idR(O-n9bwkr(d}}+$`<^g7PUI2ig8#y3Kxq>-AQJ-;)A|QUD z0mGwz4Or{hX96zQy1n8~g10(dC?~OE5t;%#MBnf%eK7$J2kY}F5zISI`YjrR>{x$1 z>mbs*B?#;vsZE&q=nQO3!aS4>r@-+6g~stwUQwOAIcPMSHEXP&l?RC8QS`ACM7cWZ z8A`p8rNVLQrK{xUJ1gkKxBG!$dq^rz?Q#{S-y@-2u$+7R{}h&BEv>uGr!C|$>NT2LIQ9&=rh1g6-KE7j#z9QuyaCGK93+t8 zN`Nf#L21{Yrl6?tc8y{9>>3B2a%---^byiz?$URcTr4=v0+Hy)?px?^TE&vKf`)5D zJ8_=3Jq2O3Jx#|=PmxJ$OVwz;3cS?5z0scs>OyggJ#;PL`5bb9-fSj%*eu6>i9pqx zF3|;XfcN+3!(Bq7^trtxx5!pWwp`6IE{!VVe2>2emsfP8?)}1vhv~djzLXSBS%3$3 z%y@JAtI5dQ@A8cqYpl~9$ML2{SN%>fPZ;yV`Kkc#qJ^9_t<8TF@*cITX^{JQ3GMJx z{Rt&NU^$je0R$GKVyueM^s1trC{*118Og~_*4D#7@6Z4^&dQ~mkc}-HoG$vENAWtr zw)RmLdfHd$c4uS+c-u_m z-^M)#wPr4P-2uU7c8uSiL#g3;MtH1FS^1_z1V05sl26A%WKP793)u@tjDT-6;!C($m3d zP|#vBo+F#N6bot!cYZBOG?+-i|cus2U z4iW?CieP?ArHZEEoFAU5eUek`Zh@04(QrmtMT61fpH`AeVb|pmR6FDvr|xM=<}%N< z6=38t%#}MbapT&hd&t&|i^Cx(m+oC-o$G<0*+q4>MHms4*+br63ouin1JY;yf#>{R zk?-$5vks%CgR*@K2bw za^>y0D~_(N&hnCNxM=hnlh#=Dar);t&Vl{(wF=U5GE;pdU)r4EXES>yVu+6pxgQQ2GUQg~O>@-m%E|n!yn)-Q*nS z=^LY5N)?SS$Q6!;^d0ZW>u!G}DWU8!-!Yb(Cvz(tBL;k^MJ%Q4KyedA=9HylyUp`1I zFP9dKiOl{t@i>IzaRe|E zUgcahlzC^)nCi6wpIp-mqu{56^Cgwadg_h72OGmLB>br`Q{?L2a<*8oQrk}Bu@rKX zXWd@8-+YuDX8*xo%&)zI@@HFT73rHYeN+2IaafoQ=)JKF(;9_v86AJOsKUFsu|0Uo z?z8Zfa)w3yPW`sZR+6Ao z>LUp3Bq{+LcBfCW8#m=LJD`b^`nSE;5ahFt-A6M?*Um>Kn{M}&iW%6}{+zkO!12!C_CBZF0xYVj-X7vdsP z64t`m;8@q|mm&%`ZL|%xG?xhDN48aU2pVvm(5#q!sXW;;<@3y3k|gLK;AwvdYw+O3|i%K4IwDm14e9qoGkVaqxeTh(m|=X)`PjPr7_j zo=*$=!f%^Mf^7W!q{SXRX!H#;v+>Q1W5rC)9j7yX!48bR#N}||*O~0)2`km?`mCAz z2B!jgX0l5!qi^MI!G+}ov+^1xw#OXgB=C^1GU`hJftT`l!YCH1)fxaSX9Jv&0N|uh?UFzvNG^p2>Y(!!f!g;9O zo0Oyi+Gk-&UL79J~=TZiExOK>=2l+We6U ze?!7I1~lU_bN{LH4H4@jQm{Q6m!AbCum*_sDQT`(8%LU2cVNrRV>;a!{H)4Ldb zDTg%LGt(T^4|0MB^@$e@s-;5{pI@S~r`4zedF zO*_4yY8k$Fa1d0T?3u{{Bbnp)8u|Ojj^IvsR)^tolNU*!^xd(pMZ_Zn0ZVwiTLXzCFocy~a^#dB9Sn`USy~bHy7y=lCMSoj?%uF)j?*K@z@o8LBIV8k{ zXvXOJ27A!4RY!8!+ z$pMfEHq1}@S@r4)foxVc8dMD^KxuGx&-1-s*o~LoH~VLIQoq{>2=^H@%DjB<@SUi9 zRjr){XWC7AgqHUhUB8T2JS$2d(jf(D8DQ@vZoh3G+M28LknWEJ$#M%vyys>Gjj!0z zIEjBO&E}|P?_UqAN#jaj(&NxaJ60@)EXE@^4iAkj$mSY%-4rHV$FS@=HLQ)BZA~mc zgT$3yiq%WBXvWVw=R! zd}*)!nDu&1zHo6isUGhkg^@P`1O=z<>?~tYzIjA^4me!Zy{hdrS^lDW9njn!dGVtf z`oAc9?`W?7Hh#QB2}Nd+s3kDNy@)KjE)9ig6(8UuW>`Y{rvVHfmaTvdZ=;iFJgr{Teo&a_2pv{E* z)|~5@?W=uRT^D25IzBUbXbs4Cl(igFuxq<5+1gtY6YB}|`DOF{jWM)cK*xkA)v6>O)Vc%D zN;LWF9f{U!Rb88B)vpoD{kbrLd$axm(J#fpN0zgKWSlnX*mh4A6TCDA z3D=fD`f1&|3E=fTX(FlrWC2u`gx653_i(v`mIP5@Rq;mx-rjCrF;8p)B)D^(UdxRf zYhWTO1K6-aWM7Nf`Z2fC;0X&bj}CzncNvmOjCvB^1>Stps~?&1Bf8?2c)ob9kSaiQ z|NE>9FZYXjM}}ZfsJDe=2$%|AZ~G!aV|)}qGr|^`!*?rTwsoIZ^QfeVCoh}DrPP?H zEM6ggMdWzXXts)_nb0=OzG(83i*y_a6xhVVdVX_yNEus$CaEfxjxMM3R$IX5?MG)aVtn_CfDS5 z+&8@_1RvYr^g$&tMHDI%ufJZ&J)OaIzdn)X@yA)pGze`*`-90&r`V8M4|~!$0invQ zr-mm7fi}IrFSdl}0Ix{%P*mx!jSRcBVNynd0InA_F5b`-eU*45u;{n<@i0E_+O5Zg zyg7}B0%aT6t=@Bl=jOb0T*xOy&z9nH3ZA&Q8>khsod{^$&JRYniIGj!i9Fa@81tcU zTeM3_@^{JipGsxU7{(b2qN*jRJHHCtSnnE#ca|E^$I>mQYf6Y zGha&YAwcCeFKuqhal>BIo7@ih~tm3^+Z#KC_glP8yo~gAHT)}Q0r$hHn(F3WeYGX43?UWNyuwX)q7l6OZvdu?!@Of zcY>O-*Bq5DGoJ`4OIqPUjrV~xYA%T^<2e|KLN(Vb!LGrWFMOT}D|cxiOL??h!b8C5 z0<*?GkDhaC>T2am?jBscpV+(dB}%Gnn)-?twW;Ls$OV1)Y$NU&|-@>cf@^^Q_-*;e2#q8^Y}O=1+Pa z$jrEMffXTHuaL5Q<9HqmCEOZCm_2hr%LUIrXjN5PHbL0dZ%ST&g@Yd`ExE- z6S^PC;mOO9x-^~(rKuOXq2GWDA7-7HKA8Kx5vKm}L5-g04MIUPB|swgS|V`ZcY827?pW zFxt;5W9HJra^ftScX(|YXxd%yFIK(1A=4-vUgp{{6mCX+gFkU=<}k|O(AG6)lceP9 z!|QylQ?~vo!U_AP4>Pl5j;kUzGWI65Ti$8lYo69pXuGAEt7BO$0hI)@ z=1v4&CgUuA)%qzsqNU40-2GBK`MsK*XJzZHU-F}}q`=TmU%S9Hd!Ed=>isqCs*e0T?zhx6 zL=40MO8X-D=9`u)X~rcJu?jh*-Up+SqPrQH;fW|kS#lTSqZ9vyY762|@Tc^nBUQJr zN1&b33P=dO@ku`-`qdBa$4QztJwod$xA;V&B;BBotLOlo!Bia7ltl;f6LwZ8X_0Hm z>FM93Gvp?~=VLNiT|qn72AcH<%O4;RF@sioT?VT>3H?|@zG4Y!|%Cpp=}dQvda5PXB_P~DQuSWQm~ zDnzI#!u*~JYXkR=fq!(-H<+6+-rockcd*jd#C`(C9=fn8m#T zdbna}zMIKSl20UJI37i3x!eE4<3pot4AepmtLgB=$~5nwP`M~R_u3^c&`sM79X|TE zv^Kj^;8_paUr;B3RLDD4)bcJbi35+~`mBj9HJTvdxkTQ9EuD|kz2Oep$Z$K9#lTNp z>pgnPacAH#eP3#m=lJl3ZP2Bj%oA3Dns{R4 zH^w`&Bk9}Iw?FuLxaJ92$#xm#3>}NPn^adK#%nP8+V)~bqK4q+yK2Z{c5zDTr*RAc1fJG>F?}q`$4Yd+C2C@&&V6j z!gFIx3eza_X|Zs~*uI-rF5Q#ge8(I>WB6=D2oz5i2C=pguAsju1>e!DaVO9;tit5` zTKFIUWIdB^M`r5fufHH31;%rN!UP#K*5bB)g|Re!;;8kBi8vd<-q~jV9N@11VZ)%K zGm(sD$@mcx9yCzNnVDhG6}QfjDt5o=BF#~tr&rjuG-%3^!DqWW4k?b#;1^Cb#WdKc!gsL@Y)o8Pn^R%q6{-Vs^d+?D2-H9gVjzNmyXpz$IwX6mw z#L`@g%7ltk3d~79CO`m>F{2cS{VRclpSht#i z1{$a)C9Hb4H%lbsBul>!;R5C!9=l1P)f!Q;+ z>dKD2b6(7uOft~Z7nH=0o27`SzH+BH%jKODB(HIIo3k5yT~E#GUV-!YvP0XOr^>OI zGpEQ#@vbgNORxi}^ zy#j?9;3Rf=?@+*Zy3EUGE|RSF!i7b~?XZdZEjhyWr(O}TT3ZY&(oMNS2RX-lakXs-^b#`k+35x5sEU$?yvQ)m*7`miq&fU=e^@l-C3 z%PNUO)6s~hNIx?6Svj!G+}U0+c`hZsG|SW%M^ckD6%w#bdV)!`u-OH^xa4cXrf+4(B_#ybMkvx#XYHA z`+f5U2ufXJzjw<$a-+7@lP!)YRjbtkL$9FkioBjL8EL?->^)uSmiT6C-uw`u(8rTm z!#8ezEH?EH&xxamDJSH<|6YxDDj3`Sa%vc=X$&Yd6ZmM#Ow8D|*jYoxv-I6wf4VUK z)$*8LM0r8o=_|K&TbEK~`O_VCX%zkq1;UrJ z4HK0OxOKJW>9M3T#N5NS7$p?5X)PugRbl7?Oy(}fjtzRKs~Nkq*8O%U&u~TX`n@w7 zpqn|#zsfbx0vSFhXe_Ho^KjK9?NtmLpD6ACvMo!TnCgRkjnuzmMEva3A`zDSf%dfPY1f%i7Wz z+dO0NehH6qR?e)+kko^cf=Rwp&GOEzKaZ^c2)Bj<(5)h7QcOFalHlC=?7;s%_iF(C zR=|TLVPaZbaR(Y1I=STUId~E{UqwPzs9!43Wm5rzSx#8nr? zDA`{qXLZpwj@qx>qP#vKwO-bE>UphJdd~Xf^pNo{8Rz<6bRVnUL=N~9R?PUJaS-lZ z8#MMle@k~c;?@5Oz=wIhXjT1hWIv>#Wd@7 zj$^Hn3Mvm(l2{fcCQu`~F7*LjafzI}-})Pg=uyKu51I?hSxbm8s>!M!wy%}QR5yyWCG#U!%AZ2NB?%uNg{;!QcF;==J(A$#=5f^)D_W#&F(d6T~E z*ZW&r{dBnX2sPWAU-xsqpG=>CmQh(CS{ODtTTV zt09j%E;KjfD9@donw=7|ve3Aje;M<8)Z^B{9CZVL>`UR+G)LolfsNT;d#(;uV)32e ze_uzXH$84%tj?yx<+yy@m`!tA@6Krww+huQ7JQSmStU=_%srv<;Sil{TytLoy)A)< zQA(LZa}ViPxgYlBV7clG(PulX-&bPZASmihEIvBDQF|3dpcg0_*lSYG%hypCnKwXT za)jC|iI2#+8n1kMnzHhuL3rd|&xiWwgd70au0keCLDhO?hZNt*@4#|`Tbg8O;9)HV zd9sr85{&aB2?Ac3JQgn{9Y9ID3fDj(*k>mJK#*Nx+pozBdw>29Ba(tD@=`daH1|By ztoIGV*uF+qo6}D(uvI`_yVpQDGqG8_(dRJr!)_{X&V(o7yL2y_s+ikX;#Y?X1%&1$ z{zR_3)kLl*jZOxptEet|+B3$%Dp~V8`56B=QDDYjm~;WR?d`7;500-Q{@NhU<#gjb zZk_sbWDwp^vS7CO77}oxJZ%VH_oYe4(>*{zXvzo}SSM6!Ho$zNnc_%hf>(zk6OUW? z-zwn#2>u^vTJ7NUrKzXJl)XHr`(Et2a|nq(w`i@zyK})h{DjrBqcd1rF|@i|yqPWo z)e3I{msh19P-w?02`to@PAFqJ^b~zX(OVpynEpgD(P#Xie?;u@Kuiac7)rq!Rc^18 z(1^HTg=*Y2t4(1dF$L2s(JfX;L-@>M6asBqJ$R0%uuw4T9bviJ_G|$sF=1YJV#oEn z`nbgF5mxtSY&h`i{3c!<>K7cR5&kvFV%-FcwBy!b}L!!tV6$z-ZcGEa)iXd zXxU-m>J%=@RE5zyYr=%uVxHU(XJ@+(%UnV)fU?%DNot8sAD5CnYC0 zA@HoBJ=mi5Ag>7V^O5ZK{7Dk)F-r8UYh?StFIM*4`$m~Yyzqy0ex3q^LHL744Yx>t zc~_p-?S7y5bey?%P=EO9SLJ>wjKcB)(wkv4(Sl|}@>*$(*0MzI?1K+LwLDLKS}!?$ zvSUTks&E=q{LgomDnTa>05DY$i>`rL(v}7ggL9Yu)cq{WP}&Dy!*ZZiT_{~I%G_6r zr}Foa#lh0TBxk;I#7GKOz*rmVvr-7^n5Rk@1$)oSCg#s1aZZ-WX^e$ znLp%trjLLtv4_8xUV^V6&>4nPR2^dF90r-K#7Votb`r(Ox4^F7&yH^Kx|D+jxC*&|@{CS3Iu z5xu<`Xj3H^$u&)+&-PpSR^iKFd!7u^Nb(WH+HL3a)Nl)@6wRncqHO5Y`3GM%P!Md9 zkEopAUM9#E4ZT+iB-rQiT`qhkNa=ZpX!j9ye$_f^%6$q6f*Bf=RR*%p$i<<5ul2?W zA`1TU%tsAI4J7#_A5`3ph(_5^!k$2ZX4o?esh`uvnAfy-E(w*JQ4E&L+IpTRCCIr^tl0nWA1AhP z&A4QoyMn!JNM7Q#J{_uDmvK)PFWuGytUAN`JR`G&3WSMp_H_ynTc-Ds*mei_;&4>>Ff4XXXRG5=dc2IOrns)pbU0yOI7`_6rl#9b{*!I zEjZ4LUwkz1eD>15KW^Jb82=3jGdbi%a2X`eN8@$3wA(fT33}2gT+fO6L4-g;P5s%PJ8?KL6AeT!O1H<7&1z7VF$>~Lernca1Upxed zJ>d!OF#x1~EzM+Dhrot2U#A@w5{lANKn&sZ4<6XAEuW?@aUCuE+(u32i9)Ez|9U0r zQyD&1-3?r3#r9(QU5ZsLBRY`jsla^7j5&Y_LJHAW3bJ@U8`#2n`%%$ZTwCV|G?k5N zy)lkxt^|p1%d;pq^Qo8kIeRGN(0wBLaTz6}TRWweY1g;QkV6zU>ULIr*kCUpkPv|p zCaDjBFpMVegHA>ebLag%Fzx;BdBn}xD?CR?D6e`jb#`iiz_LrhK8MJ`H(Ff4JExve)z7*}5AJrn0E5!VsFy_}aH35RDp5J;0#N<`I! zP+|*c=8BhL$FAf_$*%O@o;MI-DaZ!DTRI_)BO-*~m6blRM*oJF4J!#zj^|#wT<@{vs(yHqHX&*ej2n|EO4_X7< zP`U9`RR;j)I>XLUV|bMOyjYlW5JnY0|Gdr~6dKiBSj&hhUO>=o1KcfEk{EIsi~C8t zC%lFMd_P25O%4*1a>6jgZ+!S&le>{l&v##I=y&X#2|PUBT1K-!fLLsb9x?h3J&!o& zsgEyMT=xxG@O;*?U^M;%4qw-@ZsdX3pNtoMQwk;@6C^|qYv9#eXPB1?RtmjX*P)u$Eq=YBC$Ih zg$>;&TJ7;9yj3l81lW}w)54{@FdZ9B36(}BP1&?idZ{MW* znJc?gE3Q603_4j=yA78p^llbHx2?CDCz@91T5LMPJl798x6xhtyW)y|r#whN4i~S; zTu~H_e_&w-mH(75_$*8T78Rdli_Z~cx3LLknl$=sR_crP@t8-Oo-D}I0Y<=uppV-p zwS%tYj}%Fe!y8Rv9!#fs*$K&9UB#xn6~k3Q{Jp4j33km&8&UOM3X|mTf`@TgaBKb8 zGWh$KliWz5JNxCJeZVD~asdHuzm=T^I^U>ubiBYV0#`29$*$cpqNCZP;xG$g6v2vc zq#9GnD+OWp4zj}wX{YYLkIs?Kn_9ZggpSwm@^nn?*jm-iOJk{%9iFZnF@|)_l6qVr zy3S>n%{41LB4Fdv6GAO6q53>iosen=>6DEAVZ4h(QWFz!h$y}V-|T}p4L#++ydis> zP&Da6B8(z#m__c9L8Q(q4JVqI@D)WRW{fIBsoxvYzj0sc)4xNxK5Rw|9InnmRqN1@ zDynn0Cb2=u1_ed|WRwhpr)V|1=m)d@SWnOMWhC^%4EU+31oES~fa26M&0TCZv(bLm z-KsMr42Cu>X4V3pU$_09|H9waXBc#jU&Ur;vjp6-Y`85jMzJ7!TZf8>J7lf)!j1<` zgHY?NA`B8-)>}E09?u7rDJnXjReAlVF=ZQnvFJnn9dp6trb&_1%? zb(X8!*a`^bpb|*<0?X?d}bpYa!!_&VaWsUpis7Ar zli;y4-WW2l?`eYGmv7ER-&M8JCZp!`a3wW>lk<6IVTiwd?&^*4Kg|Kwgx|X6#plaL z8C8Dxyn1VUy-ap8?MV0abCoR332E*(5TfWOXxn|27{^N_6AwL9S*B|n3(M;R&}zFW zhb!y_o`XEu4MDAHx@8opYfnz4$c|31)mFF?C}ob&kZ2j_Z$KmJL!a;V4w}8(ec-e* zOM-d!hQ9{JgZj1P*MLnvE@9Tv@y}`uY+^y-2b!+C14N#hELsf@ZB?r?;#NL9$n029 zMya~h!J%|N;^X|W2;cfL1S2vNYL$Q}fctZ$g(tk(npK1Pfj!BHe6=OuM(9@3Ts0EV zQnm+26u)&NiqrbwN7SJ7p1yO}PmbI_SX_t0{$Vz{E7do1v2=RqeM&}k`Tg^}bOZsFFi@TsAkFRRZl1gT_zu?Wa9K*{y2Ao z3(*}^y|P8qf*as8N-^Vv%hZz`iP8#$jq4Lt5NdJsm9<6hfFb zUdlC2U&r{Wun{V@jIU>VIgY?Z(XEkoih@jPziysBet_6&00qcrsU+!9{m0$&(V)+%?f@Qmkvu}t?seu~u zw`^ZB)*V}sP|e(@d9%>UcUs_jdazKNCAAFsM*lP;MU1ukFUSBepsjBv(Vuw&%_1T% zdyHX+goaL8?IMO{axS}Kh-4hB1?_IJbBU#F-_&`Gq;DEKyR}>HNy;EZLWb5ca*o#t zpv$HPNrI`g-)@75qM+Ks>tfiRz=Au=H@WTRJxSZ4UO=UlTV|^ zHK;BKi2I+2PXZ(I-i8d7=Mb?Nkz9;HxA?-xamdGcsKykDvnliN{h@;Ld=e`QBVB`r zvO?=vgMQCIh=mi9_gunaMx*r%IBM2m(|= z$^`;~PJ`a`!3%O;AD;ZWKI8;JR~nnofIeRX$Ty=+j_4Onx}d5cGN73Z<;Ef!`E?#n zo5g8n6B?DY+zz-@Um!Z+BlabT(6XEgF7!k0B}6*LRP#GzYz2Oe5!Odv5)2Gl9X&|# zg%E(QW{Ux_DrkJL^qxSF+ISp-$CTr6Av7Ji)wkQJZz2%UbkcPbO6jtu`d4wfkVt$r7^{weyFZslJJc{u|&i(Rp!3t|$f`iJJ2*z&?Y?a1`Dn~4=S2^{t zsB_I|(QC4Gv=8QtCa^Q89tY-}xFi#G9oOe<#7AcD;_V*DDQ|47omgjFOP4&4k?@aZ z9PZz$yVkEdqxJLZPAiud!;m`|L#6-c0alFcIq$+CB%%w40Xp`gW`B|~M0g9a6(V5; z$@f-Ff;^=NS&}4}+C?6ljk3_w(Pb`K8SNCW1IWINCTe376cCp2d_?nS=y%2twhCgV zu$iB!pUn#qKRNkQ(woE#`7|}S$=0AzD#Yd8uSY@(u()KVg`p(nfCPdKV!g0XCJ^XV zcfqO-=H>}4k_T!(gFeW83_9f*+*krHir%SV(td3jV1kGt2@t_9ENpBuXr6n5)v&^P zPypnapvYSm^i7U*7}nAK4?->9|eQ@{N!;3jv5 z%@U3}>#s98VQfW90im~sB)rU2k0dJ;JnUoa`U_s} zwo^*v5n_YV>r9`1p%T<2^;}P~ zWct1iDFv?l$dQ7*3!@fmo$4hMm->_n6*{vkXj;7-<$prP|3$`0@>4DdlP<+#Rb91_ zWyHckOoc`ysu%aU=|SwnUWUatYdyP0CvnARzcY1jfzgX1L!7;3_W4VcQy*K*?teexH^Kjf1QPd6_^55;%^jc@+` zWw<-6uSc~%Sa@@ozB;Y@TXk(}t8z1mRmWCtB#L<25z2-bA1$>Vnb(mL ztaDYwZ}vF(^k-F~dR{o$E!Vh`AS)Hn`s=F|8p=Nscj=}Z8T=FK* z{ZWi;Ajx$;;@<3WC`rQ4oqnA9*4{IKjx_aAgNk;QBWdmdVsJ~VWNnyIdbXDSwM#MQ zgJ0g)EHSsr0nbM>1dUmvj%S{XRiCr}ESvlXKdXcJXID0jPxxH(ebtk`Z_BNKqd=!LZ{n$&89Sp(aa?5dt*cuv!7!V#Wn`jPzEN5< zxhsc#c&XBs_4XD6DuM3!HEzE~j_m2_fq-4)#Twk)Ml_tie0kXbL%8D5W>OeFu)<3t zVUwuy;o*$v_5ClUxaUL%8**qcsVDd5j>qY8BO^)k;KgBe&6!U!IM|(Yt&GLukj?p^ z&IoS7Srhv&whG5i=1*Vea8B-_LQCSa)Tle0cAaqUREg6xN&nU38ummtW}Oxa+C92y z?06-b3mo#4I#m1V`=ccU=c!XIm-|%Md6no7@9y)Vo|Q1NvME;Cy`EX=zrrWu_0=G4 z`89=`c8{mgoaRIEhm);Y=C)ThbG2Yg^5Fa{` ztgMz0KL!Rm5jx@dYqVe3mwKPlcznde?-kvM+TdRJakd`IWp9_Z`pUkjj^LHFMV<3{ ztnQD;XQ3Mpw4bfDH?IlnvXZlElN{-W-Iks6#d(8hX%{KYw(m=a_I)YRSsd z?Z(c=a+KeLt7v#{&Y@GDJCDhK?hpU8VL^MqKDWJo=Jw@{kUnWkP7vV- zmy;{53nzNRV*Q-%1%&c9;X`<|U`j-@w84~-Sa9d3z@I)4@`(*2(Ffm83+Yv^?K>`1 z{>Ev<^W~RNd65{BoVR_C@bZjH6HYBvA0b>$nX&G!WpTMq zXz?n#l9cnn1II&Srh8k$=m+ixUjDQBy?02cZu1%z5~QfB)rvHlWY(zd5NOVOu@RGL z>-yT{b`Ja+>USXhWxU4zy{uw@q2;nAR0bGG>l`;INhe_Mz^&HHe|*CK94M?e&1<_XlHOzH z|HyoV3-@AyIPG~6mU{%wG_Pj9S$uS-61LC}F&fb&82!Z5DILpB@p6;`yMt*>Y=Lz^ zOCIf0dY9gjY+KF&oXYE@+LOBSy0AoH+m)j$ zmscCl?O*U<6PpGGnGUbY@Dsgqt_|!Fni?Of-78_^T>f<yr37|ujv&!e2=WEVU zCyTzH)fV^^g7V^MS%}WFB94eZ=;~rU4vmj5JNOdcf4t(1`y}$S8`TZupg3o{6$?ECGt>`mFc%tZ`~a~Vi?L0j$fp? z&2;whb#v40JL#`!?_0i)aUt;g6i>?``{aba$is+tE*My9{$84TQ9QM|dWlT$V?yuJ9%(hGetqrQPZ=Vu$bVc8<=Xx z0lvX&rN4}Dbtk~rS{m1pmH_~UfaIbFE2kq)b|q{L<`mO*&@b@(1yBO{S|zK+0vnX+|_&CP!BZD?6bp!sDTIt@^#1X5OwQs-|vTV_{u@FoZB$nQ(90OXT@B0YT?}zVXFivBj@Gu391;*v4VXq6ZJly1fHA zwpXft|9%mfcS(tq`6`-OR6VkwL@8V4n)fh#Gb!Dc0D64C;)X2962E$e=>V(jO6jDNNm<*y&*ez8A+k5cyr`4S8V1P<@Qb=dxbw2$=&lYI zeAxgTm!0ac8@SHvA4FYKCmHIuH46Yo#Nv$RLrF z&mOWf^$V3I)bb)nyH$`Z$chJLR%M1 z>>6}6$;~^-yRH`<#hJ9NbNxwb93F|``R&(PVYU9SFu!LUpF%NzUEzqU}(GyV!=4E9B*2GhA%aK6x;FbHxiTZe4&t@(;y>O!{EKEL-wxkUvBCf2 zU>@K1-Q%B6a&wO=^|8fz(XJ81f1;$u6zz{D38reMre^wLB>(gN*8{9&X(_kGF%o8N z*Y>D*9D2#KY*U4*eTzbg^cmInzQfa$-M282?H}s^7=Q3_f`9qsANYw>Cnhv#*s?Co2r|!s4js!g zLNA&j@LQ#XtLxXKZTq^TSV%(HnSD_xb!Y1xLo(F_7=lT9!^_|jX;CfIxEt*IWd0wk zE(9H7Mo2N7fZop*$$=2^q9!Rxu?v+tq0?k?o}}I>Y6Pzijwd3>XZjIg8wJsXEGkU} zf|up5a&PjZKxv>Rm#V$A+q>%sj*;2YVku;ygFOV(6TS}H6c!evj%^opp-OvMsBrPp zU%dY|+-O&-%5ykSI!pS$?KNCC&UZ3niHiM{Pzxar`*tWGvQyjm#dH!kIFV13NW!K+ zn2IrzOlw(mWx((Wx}P4jt)dkO3Owg6)M-FN1zNa#g}#Zs-yJ+SUwfV? zDG`f-rS7u-MFHXM;dlrtt^y8$H(&-Ja4aPeo7E2$+Mwz{$~v|zxe%2<6_Qb*f9VVy zzc@?nN25d4)LGTYojq}p%oI6CT z$o|J6>T_O-YmLPolB}!1+R1#AI^|{DZ{&@eE5w3@5M`8%U#|X5SHI|hKKgcAXn4gb zXTwQkvByFL&s~K7&b9ZK1-|1((xeN!h}62jGn`ab(eIS@4kzyYx+PGnF^Lw?{`Pgc zs%fy06^XCv&y^IuU&1pqw~OZp!bsjFS;>y^#%wSZ6SaJd{Pwe%IlAh4|L$_0)@wXN zcJz>^#Hu%Mz^b?FRoRgu{kn{*KY9y~A*l0vTcux2(``=gbinQ`WiRU@U0!RS2l&}5 zw9gKQa>1uIQ_D5|=0fA6r)^fES=9Jn7NcHDovc9&2Jsc)#q^rwP>d+!nClYpygb!< z&D6BhG8{%k!onPoYFr#`E;bnaE+%}Sxx4cjjF)84GG0V?2L(dB1ycm`r?V-FZ;VN-(|xzdr)gM^7?b5V49Y*-PuTU^_zIV7%xI6b{~!4o&@Hg zjOlmL2JhaGt+Gj{4$-Ebu)ar6Mek$Z0r1lzrWpDfcK6d`j<~C12L3&n{3^%`(=EBsm{=t3&ODkPDz)4JJ@sIy0M+&i}cw))ML ztKf7wQF z;Q7$m7oS^JkiRZPa{F&?PMdRRv18*mSC%!)%s$x0UNl{bsM$1#RIlYA_WATt5G|PU z`d00elyEDeNYoY4ju#Iunmk_a6J+MS`!?qdru6OJUN7LfC`;) zY47DDajkthV;9YfK~@uXht*jtBTS^2?zg+IUZ#2wVz`fN+9ZvA_x1{+1D!ePHwjjdKQ+X!I6{=>Iw;CsBg)bvAQx9{ z1QmOc-0PEH>~)s-@)ICLGzYP|=qm#6zi5Fer;Vp-%mm)!d;T6?U>JH?mRBytb9ga} zM)Z;I+j{~{v(5K^r3GZY?a2s=ImX+Q-EpO~`n8Z$;-Je=>tSf4rFeJc;c2`}&9d`v zOCGy3zm?i9_G?xBXwj89Qq$0>+FDd^Jr|n$#O+v!1nkgd_VvDFA2m!W$G+ST9?Ufk zbB~cC11@qtJx0~m-so-RT#cn4+&kY@RturhS0M{n+MN8h5o0Xm%lD^7XVCKTn3G$E z%}=`Qbb9`@sqy?ycL$cQemQEBcAG`^vDk3;!~d8(h;051*U2zf~N%Qav+hK2lya;dlAN#Xvt*NzsU+e4H|o?hy9r#2ueI1)`@Si8=+; zM(6KQD1EjPI)G|YgNbeeXzFMa9;h!@SPhPNps*?a$zg4 zB^mw{H$=EtYIK#eeBdZ*dBZUFK1B;+Zz?}Ou}&p}wYH(dLhB%oxh(w62uHLGmTnBC zh)3$->;45ClW^ghVIQ#;R<0Mxdz-O!m7$esY|ThXd&}M3*xA)$p>PrZJHcYf;SPhj~K(nuIy1xGgyDJG;@ zav#$yfsLNAgnWv=#_{YcJVlI^i+50?CV9>J2><9O$ZFXfP>;AmkfOrwvcI{>xe#NG zC3fZd!}=??xH+W8p!#@W_TW>!4^B6ZwH>qs!Lmwz&`ZbtzrX4y=)-oK%-O zmoY4pknYc34J7|IW&Jg5auXXw=ZUBZ))zoP8u%4U13uR}phQ-{R3f9abh^CE8_d6$ zS-Njy7IQWDYlc(0jBHuw4t?RXoG9fPwNuvo3)lef?v=>(eao4kqyExsJoQSC010x(U^@_#>&)34MO+u9w2pCE0i>O;XPUQe^ z@G;)aqT}QgK_euOD(++(kn6H%bRWbk=$nU1viW|lMmSsKf<%gLcf3Bb+j<>@*hPk$U}Vz5i+}X; zxj@Wco!cYKVs$vTxXRobjmQUAU-RG|*RD9$pH=4Gy=oKdgo{J0w9OpO5mVNOKiihy zMDKU$n)saEsrt*|^_$IDn(WzP4t%1z zz6b_%ji1n@V=8gZzGcHJ2c0WS&Qv+^!})BJ4lnINfdDFws@&=KDG(mOG*$fINC)9shh zt4Rfi5$uruhJrH9r7E)ot`h1?+H*a-q##}#)Ab?8+K#?k2xsVXH?$V6^ou4;ZERe& z%Rd3@Aj+N9q~UMCc5=YB%lNw!##Q`(#jCUQ<;3t#=EUvh zsvv43U~!c#{!4{fo7JEoYdS>>FhNKWi&N#p(r9OD z$yR+MMWXI1r>&h3j&5iD%^R`Su6ui%MOeXO+6*e_8n(R4HN`JSj8v=y-ry z>L97$v?#b!<|LG^q&(F;f81hMQ`RjvR8p3;Qk$E#QBn(?)zrXIQt0xL>Fjdlu9SU& zQp>gK?C{8N(Z4xsq#}>9dR)EhU^JwhL3HWEbPCZ-AM0Nfihof#QRvH$O9PGb% z!~Vm#QGPz>8EMLx{PaJ+<}d!VVp%wb(ZzSVDtIdDmUe5eq$f8A#oN<0#3tjlmScZb&4;wKg(xgC~h3w`hzLh4T(b^)TmgT*>k2`3S&RS8L~c#fdun*h6{ zrlmBZwnq$v^tq9_`D_IeT{#uAk~yuvmVNBhBF+sJ=pW=}3?ley>m6}l@z#JFbI{yW zq*huKQVgnwzNeA#tcTT)v4Z)qB~J^_I-F)Ov28wE`{+9i@h@ z`W^?mMRHKx3GpmB+#w(8$x&x71H_ADo_*-z#%NO^rrcv{mXceaGsvQibkQ_gi7!@r zN7upS_EZ|_fhTN-G|Rl59@LQysvcz1sESOVoo<|sTe$6zp&%$}6iA~py6+m#3ake6 zvJcJ5XS^FKd+&WVE%bi=oc+JGp>MA7Z@!?~L`qD*$TR|!IhA;ubk=^huH_7x15*Qo z@piOHuBAbYr8gPJYn@kavhPUo2ZxO*v~Hs06arT14GV4HwK>n5&GjMP$H^`EHN+ECFuI4#DW*1~#oTV1udH1_Tys0qEW( zsD-Y`a4aBKu0(3q0H@QYjf*c9<(8n`vvNfw!L0!KX^42nU zOTn1NOxI!)Xc+#Pr=;ARXd#elEe?owW1dS0;8*Q^X0DliZPZKCElUl~?w3rr;J`>P z71Zho%i^gofeXX5Yx6D{?U2reo?B#ceo3via^KQCm=4{OjJySz;pe4a$Irq!LGoUC@i_&&y@Iz9(P_2=&4z z;q$`xtARS9!=cu3@5SeFuoMvmcV#763xqkCP4#irb<{2=#Edqla<^v7m&S2O6NZ>MuXcc|Q`_xAABOx?p^fyo%e%%-zf=K+(D6TyB|aI5WrvjZ zDfq>xf=34Wq1A?HugpojZjQD2eCt5H_|2` ziuBA+*IyhH`5uVHE^*})FT1azxN`D1hQY?0Ym5PB|JiBb4`be=Xt`gKIu{CWU6>c! zn3DtGE}Z@7mWwyn8Tv*MK&RSfSoa|%Neb)-g;UL@c?GQ6-~gM+aThVJ`pV<=A@T&* znmU3W3jdCUj09AhrT~7*t=z_LyQRJdpY3)z zG*LQqI^qWO^Qmjm7nUyz;3C@E+E~G0s5WfDeFok1>*1&&`%y=Iw z9p)hp>ep-O)d-Vilo2||K$Qz#`L2tx%cAzklRUHh0UeZY3RwCo8^#K(M*y+@x_1m+ zNgf!IA6E3bh*Eu-%KZYV>)`bfR`cm&Br021mvviWXVBn?S8Ae(SNWzJ`&JU7-c~+2y0h)KwcMjn{FvHF1#c0;U$=Eui`;5A9?o)gRRrA z2UG>(T|ta%JIgG9xn?pV?LhfP!m2==BkfH+NVb=}-sk!$kvoNa6Oy_vjBYs@u0k|8 zkcPt8c83c_9m=GuK)l1b#z^ChA^PeF|C644;O&WXO?Bu27(9Kgs-r{vB;K~0mh+bW zAg)p>1YuwoQHnu+a0#Zzp`*SQnBa=$)EAn^M{2A^GE0eg}O&M zEDa9JxKwR^VL>Jn!$SMO4FMbP(8~ey9l_$J(UnQmM-cx%uSF*~^PM$4UNlb2SJf7*C*E+*8PI*-2OL`W zyx!ww8!}E*<($8f+bC5@BzL%`%)#Wd8X|{I0n{1e_o%+g?8~g-Q$Go~mA+RL{On5k z4;pg4Ub<_koQ!Qddqyt;)DnsxM{p85glU)Ete)~NK!5~^n!)-s(a;C(&YWV)Y&j>b zMcyiFhLU)ON$7;FeQ97~|r{25%y zB7&RF%iny1Cn&2tR=H6MCmi!+^7 zZb$}=glhBM$8Ru)8$oQ(Wks8o6~LF!f^a`4ozcXj?K~yIB;94VLmS3B=s@OxSlT@1 zyDB+`|;3tBlg44l!^0TS-Mf694Wq43sr? z>aWAszA;A~=-}J1Z7;X{`&Nc6=j1+dwZ21FYVAqJ=pSH6lvPn6;Q#sYYr$ig*dT~3Ur5v&?pT$S%7 z&TrIGz8S(sy3d#J1P0MR#u3zV`fD~soTj{#wDnkGdL!97i*C4RkDdjw3Lz01d6w%O zq*nXqY0Oy=onQ)mpv1!93OC)k&`AObu&NhHQHKdkXnH+Je04m#j`9lSywBzqmt~#2+@oQrRCv$b*5&rds}!?>ZRFdpA5 zf~TC255;*C|V$H(06RlLVo>s`br((C-uGHzB2mK-y1x9>VHkUHW4 zON9u`IZ@1B-ez#Nl%<08{5*I1V@12MLZI{(f&uNJ-ckp~dE+Z()Rf@<5%B~l#=Mng z3(!7|{1uPFj7G926u-}Lt6ZKS{vylw13TY~9Otkr%ZZ|Q(b6U(8aiUeoH&Hx-Kx($ zpDAQ*1}D>+G{;sxw(%7DaMZ}`Fk2!RMuuhelybDVFUjlP5!TA}{%5}4X#)i;3pDs5 zqMa2wc3rq9m{1v`P$aHgA`tzwom29muC&t@H|ctCtRK55qwLN8LQ6cK25B_zXNxe+ zSX0wXj9SnR;*GCsUz{~)I1>G7@N126)7##{JaUP`{xDKUK>pU>-La2#oWoN{fm4~D ziF_!ez^8H+bJNBDo?+#?@!FWnZmw*HcunqfH=MkQjPP#L{>dtQV+$wO-1{=8?xDpI z>`hYHzZkV+J7>K@jw1O46k_yQ2e4q=J%#TBSvpwh9qQ{(zB!fhY`y4<5oI+E%zx@y z5&g%HN%pr<2}>Ioo__c%c>!alw2iEV+WOmO@rC(}ehm_SvSXhshw*Dl4mUhBZ3DU* zw(Du4Gm0v=vH3hl2F!`uEj$7>WTIC1F@y2m~DZI`TtrD<>!>wX5%J`dpKRZbQnZOh$m;in$ z?DiE#E>2HihATLFD;VxVl~rOR-B>x=Tpv@e(Q^%z_LTNY{cW#${R4Oo+W+wH4<{Xb zhP;iws^EpRB^b*F?#4aOD*>^a;i!h?GMliIi(SV?qV9>PE_hI0^EzdwPX3nUC77D! zQzNPd$&{DckM8c%j;$&H1z@Gv@c(5NkBnPh#efe_VCX&57Z(_v(14aVunn8f25M7Z zU;Ol@H-&H3j{3$Q+Rsep;3!^)a`gPHDrJ~7h)|sbBGAI3{tTJ;&3=xhfFHu+$6%5Z zbumEUgitc-fgt|-V@db&^jEMj(Q%5N92tF!F&7>6sqz9lSY~)(pK-o}I`J9E4h3H2 zb6*du>ydGum#n^gzdeDess<0X=P^Vf+X3UF(Yo>CdW5K9z)KsCK|t)AaisIG1D$(N z+Lmz}J$S4+^hwO5VxyVxl&2ka3|0ZWL-=-cg6rg{EEL^B1sK3Y%D|Pcu-@CaqY{?A z%XXayvb`@Onp}e*XrtU?pE|SHK8F-UCZ1fWdPoMz@5IuV2Sp^F^ja2Nc3iN}&3+2> zPtSDMoZ7Ho+6_MMzA{g({*s+n)M;oFRbInjyr*v3W2kNzX3Cb4v1)LxuCL&_qLpgU zh*sHJ$~Gg)2`h^^^|R+&X`gCYD^%E0wKMk{NNWf9>huy9&(4w;raKcF<(JAE<+g=J z`IGg^eTa3y=J`KFMZjAWN~nhE^#?K?$xEO$lB>zqF*RE0`RaFlsMe?gzvl#(6jc{X z($jlLl)&Z!(oa5)=O{_~@5-945pWG4gQGUj%Sz}?iVd4@3rZe>8aD>SVZOuln5LmmVq-7%Rdg3UrOoDX_5-N7ycqZaV^nWNDZWNhww6jKI5` z$ z^Y|H@egkmU!!e~_zzh~ZDcdp-m67F3`N1SG$${)^YbM?TIL3r)QU1&yua;!9ua+AaqlXN~#Ph51H5S!1X}_4wQPb^obXR^J&`F0E_B9>ucoZG8u4vw- zUzA=gpP8-v*ZHjQMhsD@{#*a$c{Kko**R`ztW{7a4j1MpVzUJ;SXfyd@*Pv^5dR?6 z!F#uV(j}q?+^DqE@~Wibw@#+!Zs0)h;kpaDnbsiBhzRrf3v>c=uEn%2oC@-B3KLdBu--bzc=D~a=!tR~INZXpn2y}F&{#P)ab4Fqw@kl!B%T`|1Hi$Q z`=09@y2GEi4Dc$T-;auV&Id5ry>D`Qy2C-jbtruvkr(pIzE7f0Q^lohftp@Zy?^%Z z_Jb&cr_aR^B3BMT`PXlzAbZ{9@Aocrr3a&jOfGVy@RrC9HdS7_=B&6k5^1$Uq(2&Y zsIhrde5$*oVAfwzF>?M3ifCfgtR=WI#m~^$)K*CMbsgrr**&VLPAp#u%I5?@;Z9F? zIk>ImZd8mX0b^IOF8ze58E*N)^|w*jN|T5!x5G+sDgigMo8F5!9>--r{9SX6UzFm5 zPgIc8SoCY;n2#Uao9L7MJPftFe}-^vxTzO^a|JlFVRhv;kk#5Dj0$Q%O4dP}2kF`a zt>`Mo>#rJr=0qdIclrd$;=mL&N&FbYfda$m+1bHTiw!ZCS6Z=t)HcT_+xrG_4sl|% z)TG~pAQutUdC%s%$w^AD0J;p7=(vP~B9k0v`+GvWMl>r-#Vw$XGD=H<;=TNgLTq+m zIc&VPdN;TILIIk-H8jZ$6ov8d8gGV@Hzbz8j@#4C+^@T9(qFB+Mv}J4U;V?-0ms}0 zyz*-+Q%xr22l{c=lV`M*&*@eB3Drl&d)p(AbL)fPzR%^257Mj#Ubqg3t#-ML1HBdj z01ClQ04wqS+cX9$F3m9%a_M$ z`b#b}K|)PmGURf4ea;O-Mka z^&<)?=#e2I0UIpki8%PZ59(@Ss)%?DdN|%k#a|6D_L3eph#K_>C|Ee7bl{jCts|Hb zBL|d|G-BL-Y(REW_|3fI39a5Ws8TvatC+F`gQf!W7egQoO0h5P!)`<*P9cINO%#Ia zsba*n2C-E+N1#qbmCN?D0Ww6;;;M3Uw|lqOjo<3PkJo~-PNx4TZsKcW8R?TL zi4}k?pvkL7$d{r8nR_TMC~a+L4Do;YVb@JS(%2_-Kc(nttd+RPXO}uaH{6xQ`O5P| zw?yImEO1a=Xz2Ng-Gj0$X;pU! z)p5odV7+}d&-1m_O+!qWb__TrBHfmU$C)TD_>8)QBejncNF9g8sUxnGJ!!rjWCDCc z6Z5wc`)TdSON7Zs#P;M=c~6{>ND4!2S95d%YmJDyj9w{dC2|}5)aa#Cwa~CDD9w8{ z@jdn^T6JrUs6JToL;4!R4SXx_U9Ar~K@Gy%aN)I#q@Q`%^GZ0#?9^ef%;5o^E@yhJ zolEb{$tSo4_RsRK&n5LOdzFu(M}>y4IVXqGx_BwFhF_;w$K4Q<^lZHT$Z*=(6{;|- z+*3bUuCa3sweak!#{RwZu@h%MHlE`_IK_M;MgNA+Cw}~o^aWL9Ys8cbE5SHj&XO3( z-*2(m*BZa{pJOEMD?GI-s7*qRIEj=J(7s)<@3(U6IQOt)a=bnnU#mMKTb={6WHt#% z_n+I#iJcO02ycyOdUc*-G<@3&7WCUl&Rc*8qP}DA2W&@TSadQtl0X3B_Jet?tWfu`voz%7Y z|Hx0WYSm z9D%ww^NmS<3Yj`XA`r32L3hk%rY7Zqc?jug^?*Cm@*e2W3hzWnJbB|}owXGFwi}`N zXUf=G%!jsKpX*$ip!gFpJMk&4BASB}oX?6*2S|c?N`2WP+L9Y+Hi4} z)ZWlDY-7DQHV0bfcAIl?@J|WGgt_^j5q+HZ1^Ligrw^1!9xa>+vWGtt7z!K;F9nYp zt`2*aw&sP6-p&51J3=arBVeS=jl7;!m7^usJGIU}EmRmNHBi(LjQK=RK@ryCmgkY4 zNQp)$A&e-9XI#B{1V zZ(h->+|}3FmCblMVPJYHcRqRnC5Ut8)5SFP3&ed#uYnk2WP3#%sZ=zV_Mo>kui39` zsNVpv*(zvHrVe(1h%9#G){a7(aXME!cWicV>{nDA*y9!T0=%Dx8)9&Kg446V%b&12yu4Rj=U&kT2w#d_-u0 z7nv{gW^QX&sxL%%K9 zL+nPixx;ISdw%XjrSxYrWXPm>g+p@RnuazE9m;Y8hMag46cOEsSu(j@#l#DxeoX?@ zjhYOEBJZbS{bo+?B5a-!XQkD7G)taTdc1QtUIH1iSvPr^Gwo2o8>10SHxe%S^&!h1 zgCkHPw)WnF0V`a*gGgK3SwcZABVan&ANYcYtHHQl**}ggyc~bTE6Oa9T=ryh#OR_0~E6EIcH(kF^c&=F3S?; zcB9Z3$f>WgW2|6>_Yyj;(E{|yvQCL(HE?71S}QZWy7kvX!p`sV+~MPdgBpX9Nb3rG z-C2>YcwvYZp?KPL@r!L4_$D>s#AK9cNhP(!v`6ivP)+jroR^O zy1%n8frtCgE+izQ6dBUIBHg+c#Cx&sbhopi6P}TsXHCIqN^xNJNz&_6gZpK>jz_M} z*hrzXB1(>IxIZJP3^JeAsw3jeqoqA?sHZs7bA&ClAx&^)GzUL03^2LL1k0P7| zV&wv>fy9I3i)UzTI0Uehw9=L4RQU06Kv-Yp<(z9}!D8g6tyCC^!KBT8?KMOEI<$5< zRMPy3@@0kmj0Qf`d|pFyvS@VGKVRA6>=`H=R)Z4Z;Ma(qIUvcY2J@I57TMB%CKQB@^Kw>TCd{tEA<%V?=!_!^%< zWpuM>a!qVi_sDOoASANJC=eBDRvjeX79<#!Z2(ND~}TsPQM z(tUV+Kxqkp&i$H(HXb9R=Y3lxo7vxPZ6}>=0*@O1aJ+dCR#y?D27zAX@luUV3B>dzh5@)tN7pRQgR$^4YQOvQ?8&wo$vz-Dz0eY2=> zF$N0)u3#4%(6!Ns*U1O0gTq8gTuZe2v8# z>h@q_VtDLsw#43sSps=rVC5uh2~~kQyef8!%S9gizJz|wJ=@s}c@u8IDoN>gfoYYi8dX!&n8j7_j{@Sjtmz`eSd zQU3b}KEkP!bY^-s+YnRJtxP3o?}0w8^5(~rJHI=+{v}BS1PfmvN_=mZ{eaKQI07fA_mjtSb#ZaS0X8$bF!~N=A(XkV#9>?zIFX zuRDX!zP~}d0(lXTi&xduaGm&;B=~P*T1p)eMj{PXqIW6}CCI zBYZOc(%-$X_+8Wf@1>bPe~lbE(1w){rZWB4b^hNkCPHWSgOK{eykQ`Drr>|y z=>O+Se$;qiUyyF=np0~&rpNAiE_EBTf}bC^hF|!7EwVskJrZos$U^9%%9={8a&^Qz ziTF*f+KU>O@$!bxTk!19TeH=bTR*FVx5m^JV5?BDwGkX%(wz+}J8*0|Vs<UTAn-<9Do)p{P3xiZK?*zD zr2WZ4D^XT-#h_|>u0*s!9%3({6t6lmVJh!%;$S&4t6433JT--`1D71LoRSCH@XL#r zT>o%|gF4utB{GEGu4iVeG|?JowSL`Th?15@Jl0%%OSA5Vf+@vc%V0s+^v3Y;DS9k# zhS-l#f>M)*D;!&m{bRL^7rV<9P*39V>H-+2vS$55uPBv9#XZsomW3uc6AG%FJwxUq~S71qbhwpbkBwBt&@yFJz|rFTu~$@uo5K^Le|oL;u}wg%-bTMxyOuGxlmUsx4Z6?lPiNXBaWNcy z5@p+yi9&~Q7**GtF80UL2qWW6buhtcBGZd57~6Jr^pwMVW<2ssi!o9s(_B?wn}2#f zaxr~mqjx&D9^&483VE;IU?v`d5+TMk+=(T0;}SC#ktYdreorE=xRX9*lHfuAA-}SbCdmtl!WTSTKsvg^2Q4g+SU*nB>VuXHw z1T7+stj#gLf+nnDe)w4`QT1$r<>k$#bFz%P9m}}61XJgojPSiS(w%%Y{!XR!mlrW1kYnrfA!HL^fI(N`}9xr$o{_;Ab+@o&k z4wDRqMB}4{pOGgAKly_4Kg#rfb4HWI^2c%vo9vc6-3@tcW#g~P^e|N_o+g~<&>#ny zQ5>BCKXML9CV%qDSe?&`>eBGe$@cWrPGuLWWxXYl(uh_md_gSLs7+k|Ux)ASF2TQj zY?iwpRVw$H^}Fs{Zin-A=tbGC8ZhIZFGN%xlELWJ@l}Uc#y+Q0w!opxj8B;&3Yo>D zo(Vn)8whasQG|?12O0Yj+2NrWVkH$8{}gQ&YN z(K2c#?(jtqP9i7%8q&sF7JXBVZ!MvBEt%oQ-49qMtW7=5c*M2$Gp|@5aI-w|g3;KBG?~%MIc3EBX#~+mqq{b~~Ar`O9bOSK6 z{6>SA=GDkTjnx-1w*ENu|H<3n7fMn_hJb~CDEe!9+ulAn&QE-Kt9%S{KKv(0 zkbhm5`DsFeIZ7;xDMey^mEXt=ihUN+f4%B)92l4G-GJG4ORpearPd zZs=kMDTElw_@2r{ly7^n$WyznkgsryZ6-8k5X4#18`XyPyc&QjB8IL5U@An5389Ud`1C#|Fnq;WOGm z6Os|C#K{F$Zq7$x4(=+;=6Q$L^u0eX3kN*lex(1w0b*}}1e4k?FbF7 z|87wQobq=iVPYS!BWQ16jOw?=4)}AQ)!)C;DIZxGSqkhHQ8C6XFudteVRVp{s;_k# zO#9dB{>`rcOO*KWk$`UC1L$llU%z|Rem%)U@vnjbHq4A)q$n5;qOm`FM|sncN^i)U z9*v18o(MkGnTwk&Da(4iCFwB=-Of!K@AD=M@t_KzOgk5lzov4V6Joh>b6%GEjb}JG#)C^N3)Cz?e5@ zk>el6rQj|PCO;_4nm3$1H6igz~g|1~_ONs3+M5RII_l2QG z=+=OaGHpdVLv7-){sko+tY^9(`XOxkYoIw#kqTT7nuab+P(4xwg5}{t2)ClVgMeiIK`Fy3(y8_T`=fgwW4AMh9OD z_1*IFrK$h@(xVZTR4@owj*znlU8OTYlb`-qQK$Dm!_TFPsdJD(hhEhaFJ6m> zfoJauc=-|%ty0q0_&f@XgMM@0lFX69sAbmte;NYhN&H6NuDoq0@!XDK9M7a`} z%YU;cLGs6Ev;|xxG)RH_{hEC#ynoMs!0`28b#(`;-3AN0<4=aUyfi8WpR;doZmG{m zn{H7}zd8}%(!V9eZWGiHd^yM8knCnOYLX(y{QV7cr)rOJw9a%Q#7ckPFxA$qg^n)# zSt16sL5r8KAjAxUdup2gRdcQ>SR)`7t#9p8lI>f}ZJgoj_=(5s4e||l-u&%A`!Ol1 z`?JK*60nb=adHa_9eG@T+1I1@tT#AI;uM3U5px>bJFS@L-j0MsO(nfaanc5mA>#KQQ9~$#U=KK=~o$>u+hy| zg!R4#$(`&_z2JFaH|xJXYlG-{wc_T>diSRMPx=Oe#MpE z+b@u%Hc||H6}R-dUzDS#3rV!aWn^#ttT;!5ajAy;wqNS*krn$-GLP3QK4v%CAKHyX zZ4A6DzhUhs`9S-M7}j!id_`eh%o0&tbT$9AU1#=+56Z=@mcB7kzAssqC4ckx>3cX6 z5-?oKMsP(J#erU8LOPbM4>4lDP!2XTwf{??wu#~f*rIqLCUJK2iIK>}CE91_*hGk?-c1;R%!B%)`+vLqMHM)M^1@)m%1?*L zqAX;}rsMex7**MP#CNr?>m&3K3_33$lp0r#sAKYeH*;FIve0T+puT6$b1TUJWebtH zC8hp;GnUh;oE7~g)9ylty7EJbAc!-vGIRXjS)2gJY@&h=Q6!K>6A0|&_sjb(Br_R+ zgwA+Q{x$BoJnmP@MwSxmSpahTLl49Ec0*MI)BUVFxy9G5O;9@B)p%k4@~p_A(srf} zCCYZ1`eJ7tgw4Ejq75Q7jal~-pPpcrxO2?a6R*X@-j23~&9Gg+XEZho|NH*SD@VRK z-P^Md9|CH}El=c9E;TnGXsMY3@{1+TIlviRsPzGIr~yQKT&D6ziDA#Q=k28qJFw_v zcm1_J7}T9(feLdu-L()#ze4zF0HfV%pn60`e|>QyaB}bAlX=7}_n#AKhhGtvX1kz) z`CtQ3hl{oVTTDJ0VMz-HxGB?!fj4)^OTh%#$w9h!m6#4Pv3X_R9C+gd13#?Rd_YsuFaBZ%SUisf zaydrsE8PHG8HWB?hz5c;4_?Yc4Z^)$^l1x#SW2AKWJ`D{GRupBs_XLwmr)OV6SQbn zbDsL2!59v~L?K~&3XIEalm;=ceX+N(t(ogZ>ho%YaQz8&-`f=>E5LQY*h(&9dG+_R zXA9c|+SHTM^>#X$HoA%e?NY6uq1fp_l$U|8N{kfSPeO^E67yAY003}LR?y{GEx5s? z;lx9Zn#%M&7L%^uw}z^tG)v6nwV*mmKVJ#S>$xE3v)`IR_q~4e^!`yT&Gxeu;iCI) zN#_m1?F^~O9~lk1#lYf*-U`5nQM~S#C)?M9u{0ip@pv_8R!MagkGzsV4Bvhdqmntk zgKBgf`klYyrKy&9W@;1y)E+9Ke%~}tigihu511|HfwA-PP(d3I0iZ!pt*K-ao~`}_ z5VNX)prDdsiRrNS*n?lRuLLP|_}vjw;Rjz@W$>Mby`G=Ic5)u0O11XJ9V)9X0dx0M z1m}V=SG-Yy7u$70Ezc%Bdc;Ad2Eh8d5S$wnJA9(&#pzK(42c(`nO}vN;h)bWk`8-c z53~ZGo=Ay~&^Dc=28xn8gv+R7KyZF{Q#l!uLZ%66+%frks;XL3~IcP zUdDAbvOq}|Ra7l6DvHoFu_Cf)iRH^AT&B=`WWGdW({7beM+^@oUNv{rr_QgW1^C0V zpo4CEOzzW3P(eZ0m8ubir06JPo}JH60(I^da~hSub7qSp`6WN*CcqLL8GUC;Vyxu=x3Kq1I5mZ$!{;k;IjBkT2C0-J2e7=vO-@9saSS9L>&IKtleoo0cVS& zm#*-&IUu}$3~nxA)0auXQ(q4WGkl>gKlGhd_7yyiQf2r_5Xa(!T$Opr333=iPGM@b zy;4+hwgH2ND^Oxs>r%fR`hrC+;ELVXx%jP}4!i@IaQq?~ofIO@d{@+V`yC3F;Wy!# zer^xJ*gwJdpCPByyF!iRo1wxv&NZ z;hHcb?iI#~`xJ`dp@XQ)fdm{HUG*wc08;mKUMfmb)eDyp0oYwm!Td zs=1kAw|^bwhP!#O2bngzrS!V$WGy3ZW3`g(ArNg-WFShD>Fc_`!@XCSl? z7Yh3m1`W9Sxg-i9aw*SbHk>D}A}m#`h7Bq9yTzy-E{hkI=@T-cS;now9;H@qIEIf34xK1MNgs z=E7)h`R;)u$eJk8LVr!({y@s-Pg=OOg>AbvAVc6H;4H?{qs5QJZatCB z6tqdi7Z%jurT3-`7=joOA~W-H?)FRuU&)cq^=F-wYdn*r#GBk znW%d>AEw^FQoD|0VJweMgnn5K8&hG4eCdaY;S=a5>z7k8{XbmJDw3SRA$Hq9KjqLo zE{9FrpvdASXM4Ax=gJiRPY@B63U}GLl}raEqedBxP}oM~T&M@@(wLJ0iowP4#yd;w z;7&9@D7LWJL-HO9pw&b@ux(Go)naMqkJO}a8gd93B-{E<@|-AQg=JhqyWEX#Lo`y^ zUMixMWKpi*NykN&@^;Gm&?_KLHqBJkm+6p*mPCUR*1qo++}9iZTXQg}9F-+@-f-a% zCFBW3f;3Qn>y3zx*W7)uC65x6$4d&)Aps4?i72 z-L>n9h8$yQ5-xI61B@X49zG{GUZ|G-yqf6}9OJn?TsPm7-tAta?6nF+y=00QbutgI z>2sSSwOr^7{v09psL5@*IZ}J$il9IZGx#?(mLzfA$J9M`S3P*G%ZzKTR&$H4 z!1d4>GF1F<=}M-_hCaJh$DQJZLyQ;PSR{%9sn)! z79vuws;OdAsQc*-K>$twEh+y4N>tRS7Wag3#jw~Tit2^w=`g!cYa9U*(mMhV+EIuC z0t0O-DK#t1e}dZl18=`-va;0AA99E7`ZfWjZ?l692fy+cSNU&2Y(K4-$UC-9a~Hi$x4!2%qJei)T> zjuepatL^}bZ+2Z`R(m+DBHh*8QNn3Jv`Wt8%~js_27jNqx#E<%xJ}2}$=OYuJ6M>1 z`T7_}iOKWRk9-XS|6bhs!i~bccE7^AxouO7NGiRNXrRK_r|6juxsG`fd6qq`0W)!!x;{ZC-;M{xR)X!~;C1Pj_ zgO!4jk7nLq#lh;@+WW+h9NxcI@eT^HYu>v)Duu+6QNQu^bX?qfWhTYZE#@>WR4MBl ze0!O=|MN`!NG}?csQ6xXOYLNSKm>9pO$oRMA zLV{!*`lCwNi8lQ3n~H99(L4mA^$=IJHo2GcK%%9F$SI$Tpn$}6S4ObM|Yz+3v<+6_h)sACzc{McSr3tsoTm{OP2d_&gQc%-` zYbMxUs0ULs^3mUmz!dNm)!+F#HSO?_5sUYm)nyFqoU;kZX+@*yZv6UDFy;2c=OT=M zyZ?8vI6P4eO4X;zOvCbZ8XFG30j9jIyc*qeQBygwpS6yKL^j~25Rn^uqo-r)G&kS# zxtoEccisl^c!wD2xqhj7dU`qqc*4sDPr6@7Mn1fr5me*Q^^Vwo5hqpbyC`06%e+RJ z3dqxwjH2gD0MANP!J;_6FBNX}1ZCAp;ivVR4ra#T_CO+wgT=N~GM_xn%Kpxelnf>h zr`+P^;vN!vdRv=ObxV-*MHNlp%D`6Ej?`P^ecf)mMmxA9zw@Pb%kAgn=RdE&OV2h= zbcdfH+`A$fHCHDW_U1r9y1FV8%Vse#4Ls(}q(Wd5{PkFW*#qEzKaL3LPJ2haNl6J` zDhpQ*{CeXhdT@9T7P%mRzJ@|B&@Q3=>w#~SDib=HCGMnPsylraZ7MSC-le>PpKvZ8 zU21L7OFe(S8KX4T9I86&Y2iND_E?aEr4=79NAS4f)ySj#HCL~gTx*g2)~4D6_Zxxi zPD5oOe&oM?&DT-=807#+LEDw5v;;4AFjM7}Zpfcbr>9wixkHuq=ea|JgL2{+f(I+W z3n=s8^DXWpns_I9?=A1t_B_C4t+1F{9X>}`$%48=aCO#8DXSI-ngyq~iz)t0Iai-~ zw5S=z0JNE&>9A}2XX%WcHB;)CQ?&O|%Zfq2r2OZNuXPhG>(A*`@?I9Sjf#g0xgEzu zzc$w3K$3RavyOEusQ;xweQC{;A)wb925@eiU4|V&&)bdlv$M0GQvUQFCmi_IwSRE= z8Y2{f`}QmV*C8f0mN7)EY9P@3torbrCZ;!*eE?P9iitU5=*N!_I*Z|(`td#r*r|_s z&X>dBBO^=8IRF_wb-XbW?_Fj!$Lk98wehX3w^d)WYuw&(6@b}CF7bfH{+7pl=79QJ z==S~!iWtb-tqzLN=qb$B_}fM0N2ZG5cR*jJc+Xf%W4UU5jjUa_aTPQV+?suELwCG! zM#s9dPO1!?Nah}%ldF79`gB_)qJBr*Fs~$i>;L2IEr9CUwr$abKyY`0ySux)LvRi5 z?iSo3I0+UUg1ftWaA)BQTe$06`_;R*&O0~n{Jnn_RluB8i@}_IbQ`U=b~CEeV_8@6 z%_yo)&}e%2AV!JpcwfgPZ@IOWAYD_CiT3V!ugRalFed>>bR0O(^ap1Egnb{yFeF|nm25J)q~t~DwBcW)^#ER)U2y5t04AJToLH?j zi@w0q2A92Bk>y)wDxO=~V8v-SDk^39%{}-+R9RXKE6LO(0jB&`Wm_D4{CY5*c60Rh zhdo3l1eQlRtr(n^yWzWJa%xZI-?^?mCB$U#Il-B|5JST(I}fj>59bJAcKN!$&KL@F z;Dn~YibNvV@52L%8^998vU3=4jP1T8LXy~|05ygoUid|zN5nRE{-=w(K``y0j@v4j zir-lMnn2cAKD0lA{TZP}l3R8rlgCA`m6D0!v%Xf=pBz0NY)r;ET5SKg6jtt?$a4Nk zfG|JJ6LseY4+vcH1IK{Kpf2L`fbXnF4^B+qBuC-71B=#%{6<~0>l_IHio-QERH5_r4cO7}x^l?|H6MGCKl5^#lKaruzXsWVsV zu6Psq6(-`}zPca8zrIaQVlcY7xeb<(%cU_2Se0&rg^^h$wY3T=O(BYKEJ%a zzP{NK2mHW3g~t1+?f)dN0W-O6p5Ze`S(p@HXGf|i{lb)#+Txa+J+}(rj&u2o9sSp3 zgdxy$a%`CEukLoV7MPWqkg8SL-k%#X!$7=13OMHV z-i)N>;O0*-N5wPovjrHQ`)kd?0jQ{o_`ie@<>W=G*in02xR}Y(V*V)(=)#B-hpR&* zWRB*(E)Krge?XDel7u6=U;Sa+E2|~VlYKEse__*15O=XXl-Fs$(suHr@l%=N($Ynu z0Jw7=KB*xoLTpp4XT~+<9Wd`D#TpK>$#~6ko*H8y+y!S>u6YZcp3?!pGSAfUKp>F) z`1rUsU{PG{ly^B^nw`7yoV3^1(0+$nHJsJGTnE|QIolIsRf#;V;k&zzQ3bL*7M9#*aPopT%4AD%h0^vp2MP2t9<~z z1#QJpq0sF8eepwhdZaP?eKtQ4^zEoB0BF}W69AW3aI?+Q&LmP3P`cZABbN$5@ zN056psV1zylm07S=VEzl3nz`+b=SANB~{S2pcEZ8S5@iSt%U^v71~Dwy`CRQG=t82^36kq`w(Xp3T5 zPlkqFRT!7DFgX_yU0m|(^<6s(tFr)-1wbqGE>&1kW@yF)5jX8Mg~8@xTrefEN(!F) zl!to9NHf6NP?ImB3pkW>aK*J%r~HR>=YJ+Z|9vI!Dn;10ov@rkprIB+0&&puVq0=g zvXI3&gor>q4EL2$Yv|4i7Jwuf-#JA%N^O$T^Zd1Az0RzBweL}PcDB61e5G3O&D?nB zOIhsVvT!HBqs4o77O_p+t^b?~@74bLis1NF3rOIHbn_qH#~*HWw@Ce!qLp&Y(pg22 zN(1`X1KK4L zM+i6k0wjiMn1(2V&{#G0x#%0?8D3rI-SQIB_1D^0via_leFSsDBB$Iaa{{beD~`P8 zY5ow-|KJ|}>-7OY1UkuC^-EJJjL5`AVk?0yi7*{o8~p9ne}F$XFla26X3-vLac_-f z!EmE}hB`myvw_g1wM6Px`Z?}e>z-g^(@neC3mIv%V;mE9Q@NAETc+>Ms!5i^uD^Yp zZsBt;(3~d{2(;*)5|#KvqVpg2+oUGM4rM#a@AAi%xY-(T5hMz8gGm)$jnp(II#w;n z6_f}UkYa}U(RXX|THJA>!m!)pvz$lcnES2WkpIA_uPu7Lc3Y?@$Ct78>6V%!ofF%# z@5UpRXjfzC(?H$wKD#)J@58{m9FgiIu+s8BS=;6_8FOXt*vX@p;yKK2ittHE1bwpR zXjcRaeFS6?oX^-GTt*6{3J}d(*^z35oF55%3 zg5P`np7GL&qT{kAElq~PE|-~qJ8*sRH>7H{7@H|2jA;@ls}Q7OO|tnTSK(Zi!UI*vCe}}5&?6R5&5Kf=<(98 z$Lpnqxjzfpt>LB_;_3f<@;dmFpKin&0_+z|t4ROhuH_4a5s$3)aT=X!s|tvJ3CMWG zhDc^clk>9Dh|yvlR791u>0!~Tb2RYmbf~M;c-DKP)}thpS$YnGl6JuGIE-+=0d>!* z8Fta|j9{_TJ16K(`}a-@aaE@o|6(SyUTIJ8<2^nBO!p@*DVKy)zNA=QCT1HC zP6f-!&C#VfIV-9MWm1wIagg8TNTJ)Kk1(0DpFXY^&Rv8TOr{_dg6Nburz|#q8Tx6x#{KWT zxc`p9?@^mkVB{mtRX(26_qPQ8lm*} zJr@ZJP5BwF1IL7A2#z$b)ztL49WRePda|tkSw96_b37m-2ZdakZ|?^2gpT|V5cpSV zt118gtx42zQL$}t|)*e!V5rZXRM z``B^SO{0bAB>0B8g19W(~&Nps#3 zz~UN=-SNgh4tU^HPnVvnv}zMf|Ec+h)b&3-z;`h6>F2Bz>(+F-8c;BPj+hJW)UNk< zc4-CY5r2Wr#4Srdp9dSR(dMBAzfLI2xmaqw$gg zn|;_~AT<-SLYRItwzx1&8__qR%nw0$BF34++cs1Uo92c4!dyZn`fY2w3?5EGjW3;< zpvN`Z9)a6fmh3U7cBame6@7bw)6cI1{s7?MrhcKhPyc5FA~EJMAs6K*;H{h4`tL`6 z?8SJ}*0DD8jqxVhKe(0u%3%I*%drO~U3tsQ**Z#}1H{{HYE6a}#sNEn|L{W;I{*7U zZ-gxxjg)7p;KmezO@}b~R#c!eS`5)jPKA;EZ@5XU7{sRFwq&`Wji~0JPn8p`{KJdB z$E)SRxBdKY^G0%m|8zAZsNmIv5<6r+5SA&;@f8iIqLRu@%Mf?EtHK!2a^NX`rCHqK z>_GQ0b}e)V38&-ANyCQxFw$=fcDcs`I{84k{YF|q9?U~L8?5L#U~4~TPr(Bv9A6nP z1L5yXU~dU>fDY2^D{Va*|1iN~WQRa!Y$wmBX|tPz9#w@Q%VM^MFHHDZ3AYCL0*-so zKHo#!v^bqe;f8*0xuOGlIF=ZzfTy`2hqU5q=g>z4Iqm#XFpE|*D*G6G^Ry>T7lC`x zrmsjpo?u;oy`km;0$1-8zJ1z|t9Q*_K&?AY$n!LsL|PvfTsC=n-cfUwD@c^afz)LVH0B;*U03) z_Ue76xSN~vhUcT6M}LYgcV^Cm8$Vy*>T9PVMTydL`-Yz}i19?ZblKhK(fisfC_7hE zkPiO1)icY4$5r!BeeVC{EUIBLIk(JIYnKJt-})4viN7#~hOAkYdBuJD)Sv~esjb!X2|EkwHL~h3@BV*3MEI4Zx!6zM_Fd3ZyQ@70 zJx`9SLUcA!Vy314^kvZo&Vv2JdDMRNN!Z~T3}pPbcW5+C+HLM7jG-&9f{S0CJmr3N z36u9g8ra7>gH}*vd_lXIarsWFj0ulTQJTEvt z*-n*a>@2kuUjNhOF$c~vwu_UgJnbeL)}_vwM&KK8=U$_VYv5=6{4=(#GXAA`Ez@~ImtVI9sUHuHExlW& z*>h^Kr`d=xyxACM$A)WYiUHYiDyDIjPiwrPg%;P({16y3{tufj!jMLW!q3!nSj9v` zov$6Y^9liW!4C+W9={^^AO%peN4-ee)$HTFRK2OhX0yW3y!otOYZmY7wCiG)hz}4t z2>qT9UZ@Y19ZNeqi44(|RvqZy7%~j_$m$ml?HZe!+7NYhb(PKrEne)OPaIS7!2NZ` zO`K??z%I#vnGmYX3boWJ%rYgRAgAi2K|=u$c)k zOoY%9aY{@tF@-xcR9_(%qSAzYC#E|mys0}-22c#zK{h~QW%4bdk`DE4n@Y}BM}4e? zz?f~DD4HI@PWKPNFF}+mft@HZh)5XMP{&YZJM?=5p7EfXK^JY-hlau~e@Qd!Y_UT5 zpX&8rNRZ8-I9ksaE}MUwN%&5|)kNHMKC&G@-WuxGzeOOXIxj3P+W86Hx86J-WY{P8 z)>uM4$3z_X^TQ z43DpZyrB33v+#vwg^7B=4|)PkB3ia)8`jvqpfM^7GB z9e>PsTcF4%Pn-NbAKo?Yj(@b1@Uw)U51N#w^d-F?dZPf1T>)2TC+C~FDjB>YkR6>x z>1g%FpMIWW!o`$52-5eT3)m$KN5Bp~HI@ax?|Hd|>+$YsZ3iuygErbG#%x*%>$66b zJI@}ur?8`V{6F75xHE6We-Ypj7!a(xc3DWYhV>}(`vJS_61?CC0BB9UyoF4$SmPFu z%i6wlA}VHEyEVOi6zs{Qa4PzeT%{szL!*6}SXTauEmSiZhnPBCNZfI)Q(HM;y;x~H zNOl(*!6J#!pT@5dEA=JyP|(uv?H*8mHBd~yqHHlBS6ScE^=u}mkTHh)&r+e!FqxRW z@KX{!J59tLV0q+#>MTFLa9CQhn{NrC(P=V4Km6s0`wKDvp&fsy3BrNhFdtt-) zNJ2T}m<3B71e=NGdR~Y-rhohQ0bRz=RSlX+#}R~-h&RM--PiH|a(TLb?f&Fw9PLj0U!c99$%+a?_V6dh|iVOv(Bv7?e?spbhH}$JzCsSEi8RxYeZn zX?>pzYg2{p0jb#yNA-eDoPR(q{7a?ue}(lxm(Xr)C4QjFe{lhjwWHujAj>idt+;gw zw7g*lUI)FZE^|A%eJ{WIJPMi?l_f527N)l!KZl_Ud`2sf*ajs)AeyJ$-R8-9<;xDN zdoghjNN*Lfme1e_`tQE#9X~dHI$2n55)0zq(JrDb?)-*#irx#qT_tQfqD`96D5?;R z8FvzRt`4oV7jZMcxH4BJ^iGY!TE(0ts9V$uitRia5Z2DY(AKY$s*hJ5Jj^6cThH(%_8xsGFSB< z)!>ehq~8P}Y%=`SbAYX<0Th*A2j!RmSNmt@RV5I zXNi?O8!ZeuWpDKb$By|mTcR}AdfU-}8FogFMzxl->*u-V&n~Uh zS_INw;sbc`G?-INJ;-!X^5_~Cxy|T7|GsC4j}n(37Mfl~_*?;t4DOCq1D6zI3g6Au zI21+Hp+S^x8>iqwfdFs`iR6Mk8=K-y5I535^(CvaQ8hH>pJ@BcC`+f zpd7y%*12yE+*V8OTlE~9DZ;Id@wE@{*rYh?iE8KH(#gN zvV4#KIoGP)ahS05PRmXt%x+{d`WVh3MOx1l$>(vUSFa|}#*9UipLZjL8it2r!1AT4 zrrE6FOYi`vhn3&n%frf2j72A~Y&AA7lF2RB$;MJfD}YP&8Gqy=+A0gA{nYf|lR?B=$)N`4cgM7WN4Y^ht74P=qjsY*^Tw@*UTo`b|5HHw^6B&18Z5Ts;LZDn z^uKY~*=3`2nWV6{p&hV< zdi>4xHU6SMKlYSIx${}a-AdpG=(TEBUVU7`=z;QvhWR3;9Q(h(BVl1-qXK}XPQSJU zDGVXQPOxO9Em&UqbwS1Ea))1#4hSBR0+#Gdg=GLk&PA0m#5aV1AKY)|Y(T|6M2(tA zUA9nZK9neM2hcGX@}q+Ak0cb$Pl4jyi@BZ*Vj$r!7esQ*3tgWKo_sp@*Bw6z@gQA) z1y%9VNlT zY@Xmbv&~XDaR%$Zy4Ch+sOcMEA~AX!twuDli(q*y2@;#uUu6A`Yjx51sq+Ck)$a z8bP6|()Kc2{Dv$o%LVO@*zBT^q2?ko%t!#udK+A2U+2qt&p2hE2P6fJYbgV{&kO4W zOoX~DaylNbQ5Wx)?(UY8ajkS)-S6MDG$}JhcY2hQzpLAgZ`@sIyH9_fNV%4fx4Z5~ zzQZN!P)^SKdSxu`t=-;wh~Yl3{x_l@_*A$Xj4ZPSzwVTwG4r~V+fsIFf8}?FXGEhv zHwV(rTfq>GxQ5~!O={-3-kPz^O(Qdu#k%MQNW?{!)+UrA)F(_FM z^w{X3W%D>*K2+9;#gd`wx6HJ}znj#O(Yf56!fmXzrWtSDCb5!c#1 zQ((?X`#BHMeRvk;a-o;bsNgdZmJVK?Ofxgy6hTf_^qE6XV>`b1k=Fr{$8!4~V(Kqk zK~8?AHNosUd#{$U5hec(f}HPcvcIf;WY*ukJ?dq!3fRT_J5+sooIN|Okto9>@h5m; zB`hhuRQq7q!kWUgdbXr@nV9oouqAvuqvWM-jS-nOu zyvk=Y5c*`2?+pLS3k-EP?&#>yFbudZ$Bt3112fyB^Q>sI+-9O1@N>YC6J-XZt+PI9 z=z1JL`J8ULfX~x@0|*VSEDFT@M`84#nv9C?>&1Kew}Rvy4P4qqLAn z6*$9(nQkKxi9f6Cw1;9n_2=kdK*%SeK}n{_#z1^{_y~cJ|Gvc`wXQ;sl;Uo_P>5-`8aN|+n zr2|6C<;||@PV0$KD^dDs7DBrKQN@`0jK0m*bvFq+VBs_`(J^*akYknlivMNv{c26= z5Ym^}!Tpd49d(N{NyyB>)T7#ok(1*oy$X8(n-L!gMGdpv?{&jWAzAl}t9#&TR!)wE z;aeY9tctOBg3dv#TUMXoteW3oHNG1~C%jZNao-dE6uTV36Pvr^-Or0F#I%cjOaooJ zzvBw)a{ij&xB2klL!4Q5$?s++t$>|^0F0}R<}u= z)@)JVBkM0IE_}gF$c+xLQZM5+Txg~>O@yKmP4v(Xr`-yB8yMnu0-j~73x-Bs0sBf& zcGn88D+yS56A`SXJ@#w8^4e~tzH~+~4Npu63@cJ3;I*-9Uyx8X#z+zHYqJv@`sf21 zE?W?EEV+a#C?j7rP>0s8)4qqPoWeS7K2Tn&1hV4Z`fVT70!LqZb$vfjb@`z zGpBudpn<7Oubvjiw4gNq5*sR?djUozTXyK7d80i{UZCUpr!%>kHHA>eZOGMQcWter%5}BsZA&#{jWgLM{!Yo=aFU?xyu4G-*)F%Zkx*CE}{HbAPl3P0FK7(1?2S6eZcDF<_v(Y(Nv`{!)CdHUdS5e;2kpP4dN z2*l7d>LAK;?YjMfMO>bQ;|i^sURb7NPwM9wdhqa&M-Xyo8W?Ha$`*s)cPDSy&q8l! zXV)0;=D#S2Z7}JzMS<`=54K9z0$?7_7H;PP%xJ8z$N(LznoE7;`w;&QJv}?(JxdU~ zgnwu*46dM7Se2B-*PbbTs=^<31~2>>0A@g{ypDO2THkE*{pZg)6p+Mq;wS@Vm-=th zAFDjO3O}-Hu$jaaQckh2FvbjT*J_9;&`3tz`$MvR9KcN5hB<=m5YHCnJ zPYD}i5P0m^P<##>xPgJH78ZLs^?;sap*u$PI*hdbgc)tSY6|t-v*LP1g{nTlO5XK}sb0CM-M zV4HOx@Co{6j2O|mJ*L!ES4`SQ-{qUgptl@h$-+WqqfC5wHX_!ze3sWhPd&!xUs(l? z@A`~C#`n0IR$?9+zUkNAJ}aT_BdDm=21`&~`QFRHzc^~f4|Voo^=GW>p0CrVSw$$i z@KfMRm}y$R4!2M}#ysow9TvnKG!|+9t$D z{NsW%@5MG+n%K1|^PzO%hv1nZu&LROByIv@O%Mdk@4y`N^x-iiF{jSu^`b+1w*Bvj z7{X}ceqnA@m6kf88Z|lq?7`zyC7k0dx#@M5)1=%OeQ#vfztAW1CQaT#9_e{cBJo2Z zM(1ZMov?v7dp>rCZ-QV%6Clo%x7?(<&-+r~;H)li?Vak>E-{nxXQP7nbP7_~GMPCo z0#!5)a=dbi`5>EGg|hGFvo^)~ZwEY;YogvfJCL%9LdMk?)^y)A6Jg7A>)j9Z3i?)3;eE+mGkE0zDvK^94t%{zqz2Nvl;O=;wlzPN#$`eu@rDWeQcU_2O z_uVRix1d#KQ3oz@OxUMMty4}9MET7-}z`h6!0DFP(!$yBlo z)QL%`i0}Iy>86lw<^+*pCM&A#bNYlY3uspwI#*zwT3Kiho$|(I**a{}36*~9yl)1M z3nX?n2dGrP2B;}Jf@QPbwm}o8T+b;#6a1YGumr8Ol_Zc-B zI%mlfq|0O5G93)OFk8voVN>!le@2af5tjypmhgBxbqKyq=HBmXa=rg>}S6<&Q55Pi+L~5R3%!y>ome*9F^9CFfnGhr#Z8RQs zo6W93hfn~lc)E2-NX{DBN)(gGHP#VR%n_PcEvYnRs<>VXF(Rs68jLO6FBnvD9~uz@ z8rC)B0gU?N{ffrMsna}{=st?;CMyKKzR-VBI+ z6brv?L)B5X$OqX(Oh?ktq&>xZK4O#hh~rp)95S!XZ)TxTM4TKMW`d>Ko0HErNzl;a zc1oBE>wWS?Rv7FMB4Fx>(AXZE)1J={xAiL=yLBLvJ>D6ri=!fSpJ$lu)la!)dKqm0 zRSOTj<_Nr2IShFg|B+5tWmRLi)|O*wH?{i0889$SHhSMuevHbp&lb>3zs6DCu^naZ zbDq(bSzc=+cP>QS_c0kz?lrV)TnpcpK}ltYnm5qi(m4kEIV+qsrCxHU;cU3>+AS>< z+qbZYu-Ft$3?px3c6OmNql;Bn@J9lAA%-Fm{wRGaxKadrYFKRgn@EF75_xz%6tiDfO|CH+)O0( zEB8J#1uMfXfx?lg*YBGuj8_zMT506=H#InoPnJyPZYUZ@KTs&bq7Zkn*9tF$b14E# zSZgfbs~9jh0jmi-_W=xThhB8!TBdeQzN2VvYF>E!&_yDXTX6DS{W}3yvuUOHD1{%Qli49Sfd}`A?(pJLtTR zQ+)^I#X7S0Yt5%dUVb^LL&Yw?8ed}`+~!*=U=z%J55wQFK2X;lg7fIbTQ~g6s3+&m zoe}e2Qq~tHeH_}4qAaC4Jku7})3(i6WM?rRxX1=Oev}ndf1^Fi+zCnT&77iAqg7v4 z)wz;5lAF_&b)*R9_o)Hv9FF0znC*?G6xZt+8sjh)Vb+Na$TWMglL? zLlE3v&N7?59C=XNH}R4hX5!IzqJiSL9Tc-B`tdKZHyw|89E@7#Zf7q9bc#U*n1M*Dh$OhE?xL>nFf0YYo+p{)P3R^7Lpec^P6)(UO5pY<3m zz=PdRGr#jBqLLT*m7&urg*dVAN z$dFJp@>KGWRMAEN@7aU?r=|0tJsax^;BtjDM{+}I+Z$va>^@1kEK-8*_I({0o|!e4 zxP>uk9_b!}CHpy!Y_cWXQfOZd5thUzrZme1`NAf51RKlPkfYQm!h(lmq- zY#@gn5a|>*s(0r}u^^k;fXew}Eatzs(f{kL^k1%XcR;d!k3r|c z;n)LHxDYH(d?zg}D;rB?)VH23Qs66W@bU4{XUEKTnfSp`T#rSiCVxRe7_Vz%Q^xWc zH8iKFh%&%t{D+ETD!ukL=_GRyVorkD@j`_?D4J2!JgNWp)a9Vw0ew5k)*k({vTK1F z*|*~*eL7;xl*qic~xCs z9#Sc7aE6zJO*;14c*lH6&i$KNfKJ zvKhTy(4se-<;mgMT|F{-jAv!|fJW~W1@;p>>LG*<|ls&{;kA5xEq|R+d4Y_{%bNdul)qj6|mIv z{FI$d=mSm~ES9 zYMyj!Pw!>d^^^tn#OI*OC=Ef&_7X$R)ng?gwyS#g1QScHM>#?zhMJfICGY2Nv_MPN z`%$t~->o(jS>hzq+SEvrBe>m!{+TlRb>FvZ&onLKWryb6Z~(}ojP&=6F`C~?{L=J! zM+hH>^c5q#UG&pBF4e>Jo$bcbhl=X2cm2fPhKwHeCQRZ4ra#4C)VbOvRRla&XLz42 zx-U_^8buDEB$VjT>_)p24KjDA;&*W|wOPrUEs0AWS--d z;q$r-(ippv;1se4>Gk(*Hf-OJ|N}ciO=RJLkLhQVV zkwBdYy-Si_X8S#B|3KAgGXSd6USAKe=9pkZ@q_Ax&+8MHz5jr&DmRkI$e{{L6GuAo z(WY&Gr?IPU7Vh}0hJS{XrB)tw+Tby}WoY{fHPvR6ACHS$fq3d%USgcV)lK)!1yF;d zN{eY@Lw`lSZ}_%~B^B~Ll3r7kTl?*vgo>gaN_%(9;mln{Gu__G)N3mNjDVGb*7H#C zJ1N;77;bs>E6S-=R*n)=0GM@T4YS={ep6R#amtMCIe**~tZjc5C$@<>5t_dPhY>rm zHO8)%`Rst^b%Ki?hf{IWtonwD3Iey?&eKde%mG&sdY82M)ppFA{J|{Qq0de7E;9;( znzaHBH>*>xcJb@a)60C_fGj`r@tHqtF+P$b9?kwX%g@fmB+N-P2^ccl*PFtQac-vr-VRzd+GH&j4 z3Y-%6prOa{Q1;9~(DW%G)vD#jUopkS0!u^>p;%=AWC3=CFW@nnfkL`b3;IsW*!h6X zI|fxXWRg&4*Z^Zvvijz`9wJ|g5Q`B6{F=$3*9F#$>;_j}7C zk(W=AmIM_cPgE0;PN2XKMEObUx=zneaH1c^Qg@zgtXQlXp4BKYxoRL?bjD9fdS{?d zeHg0e=5S;ABrJ{bz<4k{&JF0)21Ded3qS8ApEymA_d|)@{kq4ju|L5#I_u z4EqI3&$aHFWVhZrzdxC!o1ovkZ~?;v<^}l$!xWRMTH)&EwhZPBnQT2^d@aWan>nnH z7Vhg@Sy{=yyuO;;*XbQwem*>~rIIIJ;a)#l+%W2pHtBbjNV0z}n3vao#{y{$vynzz z!JLJPhP1r7F|p8PC*TZ6G76X9^|R~ul5LXxi@w~#oH2c2GI?@h?TM&v5yq}ZJ`Z}J zY2x~AEhZPg(ew{?NfHD2-Zs-HX^9XROf9T7QDGU;%;ig$<7MBL0ZjmG^tZ#9YNScD zK=uzFC|%r%+p;|~BL#)_4~aKtt6x;a<8z6V`o0A788mhVua?{2{@UbO#!lhXQf4cNC$Gh|nXf`$1vm^VOq_IH251<>&!$BM@ zaWpmHlDTKfZ&`SPo>os1&Q6_XX`0V33&D7u%1*am0#}<$B;(IZ);HkO$t>IH_dFp} z=b)-~4qKePY^pPW!*Y+aPQI~+((8oyshrmydRNy{=Utk^awq5mBgL#5GCs4xylh`V z$ofkm)B-LNRq; zANeA4j~l>GuqjF^Y)r1ow>;DImeAn8UB>w``(}h_BLs6s5hkQX{fk%?9zsK$C{QWER~_dNJd$(h%qMaE7MS zRSmq8CiQwFi6#6(--RFc_aP1KXH7NsJ+RCP+^1WbCoKUrzKi~!LNL%H*m;KOMG$a{ zxO%Zthn8hSMPTUb%J*B9h~d%mQZ_xTqC^$lyB|4)K4=?Nqj?3FCXfz;)MQD2jOHCz zEdBoC)bF*|EBf5u6{%CDS)BQ%#brtPB59ZhC}|TdVU(1N90((a3J*JgT3h5T9Y|o1kg*baZvgHiXJ}FBBNJ zN5za}NGp&J}%>P1vcyp!uC(%+!1+*v^x6+78N%&T2vmxp-K=B%lf872x{k8W~B zM_InAy$+WoTNL{Xxx&5G(ipmN?T-;|FXuwKc}O&2vQE)RuG-#v3K{{c0kxtChq2iY zy2k<6hV(z|>*XO53|ix~UfTR;k1AgZB+#wWyoVpyzv-8BC|3;|4SBMBprJDUt~co2 z`4*sKe03E;6&k^YVo=^Pk0%I*cIdCNWL^)ET7TMRY?x**h{luCz&kGAnGPrr z_%MlkJP4GY4y{F0V<2$&ZfP*&gB1HWfx6&oGkNCV`f|Y@U79$YT?`h6SZ0{&oIbN0 zEp$s&Gz7bdl$MkfIt8YPWAt>@vhbGRo4z#zUby4Ts>zLJ09t}7b=&W#En#YEMsb+D zN=SikszK_KEo2VbuOnTef=!Um--9qOQIznGD)t|zgz-v3tv|dspO>=TY#1u{y#HEg za$ligXtQkbHe$Wc(9qw0{0)WXBTI4jiS!-}Ys79)T~Aogh89~wZ5Z8Y?FWYnv23nP zitn{r&@Vg8HxoubDNPvno9ILb{f0(Fp}-R)axsh*oHu*x|!QNVG+Ne zmPnE>2=V_X17zG?Fw&kpU4m2ak5=gm#gGHRsD|-VnWH)WSc{z)y?5DO`-T<+5;jgnq7RC)#hn6ogRWXXGe;`vM-)`s#>k0z zz-F&96l4FrSN^}f9=Fn8|F)9gF#HS4Pd{!I$X{?6$OVw1KS*TBpbD_^i{kbX52@gL-_%61ksFyRZG?-Y=Qp zGv{$0$2wR1*7^!!<>QCaMPzjPl5!XNS#qS-`Iui*mO)7svEwi=o|>}>nq)DM=%XE@ zj_Z$wkH5!-b=rSnnCGbYxtDmPb)sA-$H=`o_I{}Ow>PU}RJe%5yP!$t_U^?w#jftU zW0tDo>qUdgi7@Np%`bRbUEi~7EcfXb@>XD4=ql75b8o+fHY_|JIpR3biunkbfPO&WiUE`*+IIIAz=1Rgc=~i{lbyrs=f}e>= z4YIai6yFJDbMGEhqvodoCI~k)V!!_bE>yFcB=-5BO zQMp%ufuJX#wO%n{@h3FZxMep{iGp}q*l`N@u_j^MlA5W$H80pca286qeg0%3O9$V6 z%7FusBn#s{o_+Jy(Vd!h1lj@#Cc(fcISulymaDsCnZRAG%OlWb9$aChtyRro z5i>_f1c0W}pPc1DzbFh$B!!H{vz^nqs8bxqgAL_nExL=O<_f#YbX@1Fh^^CX$9woN zPS2kHU({Xxr->UmaPD4FPYQM910XP+ssg6;vByM?ob61z@Xlo`Tar#z$Mh~n%kZPB zX$Mi@6a+z7Tv$2)dEr9Ljw?pXBIfG90uVrZtd~P1F-6#F22Z@VRnc}hRbfw)g{84T zzsL`q;AoT>eb?*PdSxetE+0@1xIrD)GoFdG9{2As4faG7Ad|l#Y@#1(h2G##$kQYG zxtpeS9;}giv2EDCIV@>FaEDR#efe|R8PXA)(cTjB4kvMkj$bUY91gl4Qg~9rEw+2K zo{9eE{Bb_aSA2OdTDz3o>OJDy>hb8mFquGtm?KDG?uCE?RAWzKBCEI{JYq~8hMI`| z6AxWNJdEaRjk`a$HmxSSMI9caE{2-KKY=NQe_hZGm)WlB&ml7AD8)RGP-n@Dl&TE! z*`0Hb?um(F4*0~u5P_hT9nKH3E-~MHf@(6*5Xye0eNt^w&XhnJ$`e`-a0ohnWBftV zEVX&;S5gZBOC2^jhdy=Qg)P z=<^Posb(xS^tAATX|ItyjpU}PBat{tt<^E|B+v7{P>RQ~=zW8U6C9P;k6XDkAne3h z(HzS7aS9di=ZX<$0kc8O*$9g*nonm?c8!X8#~9(@`YV=84S?HVdj;n z`igfGrZ7ce#8GK+ICW!^`x?$FW{0OhJRG?gp zojk`ctSp)+pHQBK68QC)XGRkNr+S?U6 z-saO*TH>zfW{61|xhJlTxbV7P*@lb1B9jbFlr?J4b9(dEYxbtX2jz4Oqlkg451d_?r|#1UVtikEzl-oFO~k@k)Lek7l(b)tyjQW&f>p$*ajQCr8^- z^!S2=y8F!C5|g_(?BAXGX-UMxw9Z+R6!RT4g(+>4nY+{JHxulWdJF32p(AO_ckrGk zX~nCRqbI=srZd!j2@C{iWbj3Q#Ar|jNtO_wU_h{FzF=)YBodM!`O#vI0}>xPUTzf< z#_$3i<)%e;udlP`V{ck*T6P~sv`V$2|rjI#C~;{*9B2{{h?+n)f#d}Z#vF%XIZ&QB61jCpPf34l&>lP{^n<683457JoU>J}d<^B8ZRTzLo z{r&s6n_GXlDhxmaLWO}c$I|^(Z63e(V?Aimsb#QDzivC6eff3vyL_eDK-}J8%y$8& z-?!!oeL@~vcd&gAxsAcughbgKX10;Joi)y7=x5#na8x}cf0KSr+Uq4=>`ER9erISJ znXEPh^m*n=K+%M&>UEvF@_=CT6eFjcxZhf*e-FkbG2f#OOgK9Y^J~CM#;~^6OvC6E zIImczwq!p8HFJS zHK83vK`e*^W3S*lfyV#;>OVh{hT>n1Bl&D5^u0J}j~oSl>9Eomm;Vg26HG&)8galB zQ#V;?F-zWm`1{Dj9?8Q1c+m4OpFVb&)x!PYFV0xbW5hM3=(S83z*d zuR!=p%xtZOVx9J8#~q+vlFp0|)S^+>17(*~7+{b7jw@zi?SR}Ec)XmP^ESu$#Cp#m zo?|ljE5ABOF1*RSw41jinK%UuBubmMxTOUp&e6gIv3&r7BaMR9R|=TD+kr<>vzJ_f6} zlK%Ym3Vy}Q8J8zsgg6r*R^~K9NIZf#(wO>_ggqWgc5m{h)syeht3$=*0^Slt%GxYV zstd2M)qjQ-gS!aDxd=F{I4PMH>CK+mk!aPa4nAf<7;+d;j64M=O)-i0()tWjUeeL4 zqdm9K^N^eGDvhyE*PkJuv&56=P-=!joE|Wbu}uhj7#_Kibr<3r)PW#=M?D=4DRA4d z9>ySlG82+wzn6IhsvQbW%}*PPJn)Zb z^3{4Q+LEVk-Bx1OlJ%@D6n?@r)h7Z2P{K5FZga>nVVE^mlR8i3M`KRDwMh|q8Ny=1 z5)KpevhT!U@$cm>PaER8Gg_6s3-&>7;Z>XLvlS;A$9+HKxlovhLk)h#Q`DEEdMB#S zehIAJ5!3>-6o$3c6G`$q?17`$fOZMk!THAbbhJX6vh+YElHaYU8W0Nm4Al9H&RH%} z0tspwHpqgZt{ikBj;^9oYAt-9xNctzL0C5gcNqkl{HmHI=G_dy;sEAHFC_texAL?l9_3Q;|KWd z9Plbr{r@#F|Gd(F-Fr{jm6Zyg842iI2^xWzWnQ~qnH+O$Tps<;r>lPSe4|86T8tv0 znua%k_+rGXX#2UkTF)iL@vg6Is&(QRKP5t^(JgsIjAR zvJ)j@DNvw#c`$x@PJ@WRp7yYq=oBByaC+yHn4R`mwAG}iZUYBo4=T4!ZZJnWbu!7T z{8#Foi@nf2HD7txde(@(R(tuGRM}a~*%yb0kl=NN%Ga@b+M))gmvhc-j91rd;hck7 z7MTou%U)Gl-gDLO9Fdfeq3!XHW;5kRjw1qF{YdhN+U`i)K)x^%65u$jkirvbj?-LHU?~pLZ_|p*~m0(=Tr`Z0^o2eFqNL96Fxn1rc zgF;fuX$qH7z}eoc1`^}IBzn7wXVwvb7Sx#Dh{f4Fw)gH}p+Q|!lM%_d3CVEiC7UQS z5EVc|_kQ+?-dB9SROa%%_jdE_x{ese8oi|!2!(len_Z;D?Y{ub4*BTg z{k=+$+l&gsL~R*=lnI;}w-?=u@Qauw#1A=ML~n1T1Ib3b^{ps~l7v2W4Rqok!yZ>XSxqXy*mW$&;Bt8wZNBK{u-Pz&t zaz z=un87DI(t7JrdaxQzKz{;t)mO>Y*REKQH%Hf&(^_7uBm2#FI=ffu6e}@rkyvB|mIV zVSr{ip)#6StPc{x%!pQ(?03b>o-|V|DrsB9Ps$@^!7{$hfG9Jp{Up`OfGC5zUvGLH%&v}B1;|^FVCl%2g4bU)9q-Pkho;-^U3O+F zJ~kr}M<>X2CyyOK@*p_~-#Q;G2w2$U1|r!Ym{P=wOj+)Ex=2)xBa-HerT2!pIoHp8 z>XTYfa9Sf0;!6I8I81MQ#MC!vfkUXqsE(=9OS7!%{^Hcjncwt`5 zuJ7h+ON1Y{sluLekD9t~5ba~%Gf^Uef=1xw@FSVagzxb<$|j@*LuK_>my^?ZM=Wl1OH8Br1$yl4s+*Tn*z!7{+#hbLp`0B zxBtiEMNfJ66~kkaI;)s#?O*f*=ezW+rn&V^Ze}VS%efyVgKk}=e&hU0=$O@6qWbuQ zGf3hV-*%DGIDzZ#)kGd)RLDv<1|Ny62Gq}gO99U-mdc@`{*=n^69etIq>0~)Fa4fdZyTjFv6zJ@v*y`^Owrb*#shjrwt)rj>62=X@SM&FfVl_H)b ztY76&o>q)o{C*{Gzpnc^^a}dXe+;dcb5&BeQ$jg*t(D0zA1fC}T0$&7Ym~`nZ~9P0 z?q-5Tz4hdU13r(;Tu}bEE7k_X_@YR1z9$Y?LF~M0pE~XNoFC1W8wLL9`GytYrQah- zqJxWW%eJ^IjJa3{rD?Vl{%pN*tC@AE^outPZ zQu>(fRVn##d@n7iH{1JSw$my1Xmh71o41qb!sIR8kK-<|5{ZFV1(%I_?khDlqi#Cy z8(4jU9AP9E(n%$X?Lv;apwCt9-wPRe>g-X0piNF&(6q^Z`3*@JcUWJ66+tmWNyGXJ z4}BkQI#12&88O4Q+hO?ON}pd1)*q^tOSlrQT}ApSbR?|2U~Iadu8u9a}cU1uDs6z}EN~UPP}cC?^u(el;ro-h5*WG6!GL(A1lhGBx7--nJz{=^1kj`rHO*Y7EFS zvpjY+EYH{`k)4K$sk!0X6KhHxhGU^-f1DO)_gufAyu@3{)u=an#`9V#9aus1y1qv% z9krjw9m%N>YcypuJsij(CZ4%NLsOqMBK`U{yd$g!&Nh+_29Xi%F!!QW@k~#YnerAf zrjhw*>HSKaFAUUcurqjDV1dsC(gy z*nO2RRJrD;AKxqfQq0_US{t}4$b0_cYd{&pzwHDb5OOD&>GLhRP@-k#l zJ?;aNNs=U059jl+D|a~1g5f6Nbott$}>)7rujc7V|jLAGk$3EgU z8zTI~6`@Mgfz?IKtyUaIJ=dqqWjO}T4J~SJUV!hB3Aq;A4sK?&spbt~OFbuSj_J7v zH+!87FqyL=xp_~k88j>;Ao~jqlfYNZ+eVesA#BzJ6iQjb4LK`8PO4{l#w2lLe}&g$ z3&2lf1r2)mi_u7rk{uy-@>MD>9*J$)v*`H3ors682#BvMD zMal-PcfEbA%yr}=cL-R#1uxe3kUql4qA)>qy6U0<;fNT_T|5NSS5UVlm{9!W29K(W zt@r6iRHC2en=l=d!l;TjoB$AR2#Op_>TTs2CX66?>^Dbl!X_cio?Zeb+AfJDZV4^k*5r4&|n+0U)H@nlKY&=FcU)B@cglLh05P zOKAAuyX4%5HvCWu9vEQxjwY+*wfXc}-P2gZ>G!iH?0-AVf075kXvdl#cyy)@F7p;k zW>`Ldv+h|fvZ=~1oxv(_m%4(S5*dF9IYnL%|s;pI}` zhLtu#C#L-c$mwg@b__Laqy=4;T_f-V_iU|D9j`7O_1Q1KlJ9BuM8?5&1*rS)t6wc# zWZJh?Lzuq5jx$wr|08)!$jz0PYXdQySKZcJ)55OVHq z?{F*tUKDEww2|C~n9TL&1g^`>Rj!HyWZzZU=On2v6D82apjM824O{F4b(fV z+w0#X70YgfbGCkR$r}}YXg0h_;Wklxsi%YVMAgbw6u#IXT~yG%q(5%z%;}J52Udp=QqOo>zRO-QD9)vqWvbBS|I2>FM_iC?lDSq}oh#oaZbvbIk^>Sh~_uFE;W!Y@DeUL~ZzyaM-< z1X=BS>Z~#ntgZDxN45e92JbyKtJ;3xICnc~dR+*tN>#if%Q`+-3bLp#fhKi2Euc3R zy4rE*k2ul{9|s*bkL}8u2t9XM3dN=n8U0!1*t+uF??5Q>x@l%ASz`LlKi!_0HdNfV z9pP0bRrJZeG@oA>$QgfwIJnscGUwRWlMs}m+YYBLpu*x;6c~EAXwwz-4)B09+I7i> zD)jToUz7C8AylNud;Zc_Jg2N`1!r&~hbRi1k5j;);6c_W;T264Q^qQh3{ zlIviFFvt$<)|( zMvmlQC+B`u*&| z;CvQy6cLd8;dJvme?}f%nEv+LXGrJQMl{Ue>LJlN?0TL0f%#7iSNn~a+4T?ielHgp z#{ScI=FEasa}}x@2pjPkR8t;Fv0^((_{%&ln2Oqmq@RAKPv*e4xY3MtY`#r`_3whI z!ljSA3M4S#$yAI+f>C1(=6DaEvKQ*9MuUkJtQMch+0HS)CtFlIjtJ!(6L-enn^ftf zla?!|>lX5a_R85V(jNC<4SV4Zj^H*+5=D#01a7INOfKifqhequA?NhEvy|;qeQRI> zUb-y)Y^;gXZPM1=`#$SO(z@-wCpTcGkPjI(_KN+4+ISwL8m-SPLto)h&`mNzLINX7 zzugy-{W&%cv7BDgBpQw<|6#J1?0yiwWvauAXmXNCCw{l$(Cy*Kha{) zEa93S>v?IUQEuQ1O2mCWDq@Uv#I}7Zux2wC(@N}KyM=KhcIX2kd#N9gX`MAcGX3_0 z1b6>3wUp*D0~SMrG0TBeGk+rvXXM)bd0kJ{(f#9ZA5MRFx2CYl9es2kF61iJ`{b7W z#MhU6*KNGC?5{_DdxzYLAEY^-w=|)yfC}t42@yle!;@dW z8`jz*hc_EZ70Zlc)%v^WVc@ymx?go3$>~C9BG=|Oks#b54jCUd5)>#UjM!`@?LY+ zYhwJS8aWS8&^ddF)=}q62}?D^xw^q>&ofNDmEu4Qo)o}d>eYl6VICb^MqX^2Fw-MU zG8p?AZMt*Fmuy0t?j;Yhs1@?6M5Ber&fgK~p;4|snfn_T*CaWC8Afv-R3yw}WvMU*F|aUMB_zK#^g-QgPzwzB zmV|m>*Twh@BoT|&)J67ErTm9wTX?F=i@z#>{Pmz}cVrBJ-_v$0yLNid{<(y(0lG?k ze+w{nq)Hq7LJ|4N#8x}OaA+qZGqM{xpXKVenvi)w`>XP$@Uz15pY} zb#^hOgZVPlG$tXy;3j$Kf?C|hZa##ARRpM{o;Xk6VC@grzUP8!*?30ADa7Z)i0}3JV!s=MmXL3|lM;O$`s#RH#F=u$_*Uo0 zY?QO7B%ERFLowmyE$)IIKc5epcj8;LHR6us8Pg z<4G2DgG$!v7FLE3-C)n+k6PeZDisV~D)(3+7AMTbPHdNFOO@gVdmRnnp9?ds<{#7`^ zpKQo^)+la%OsKBKw=^?S(X%lL9><@ulZsmuCmyRo$jN)#Zf!T2lu6%^gGBXnO>k#3 z-IhK~G`d))@;l^>p;>eV<1n%j^>B$^52#d{*mU??*$gJINE>#$Vg~(N!OFjv7I_4F zX}_L6_1{#Mp!s?bfQ(9;|!cYeLf|xiV}FBiM*^ zSfS84zMqHm^=YA0DCB-P&IqM_TAf=-kIHHQqGY*mb zXch>Pc*S{Mu2K5BVyw3tnC3R*61%T_j345g0Mb0zPa@N2`ULo)_x%;hNE zDhVlhd+Mv)Lt^UiVIM9IY`PU3%bKABAF_>n?NQg9%+s%mqX9ABb{P;B9m3RM!krQ{ zpZu9WS7?}Um3u0mG#mKJtx>nq9sE$Le@kUVDi~YWgfdOGr5m-3&uYI`^&x#CfCsNk zQNrYwWA4R^zuYxdK;#4Gv9$4Cdk4eCfDX9HE5j$SvkLbm_mv)8fZ!qZTio52Yom>h zRyM~oz5#4$fzzPgsZ*>-+bvyJ9^C%j?1cc%mxsa(i4Q*Fon4G_rnkpycFW%tOGMK` zAGLf*~;J3s9pwz3Uq=4a^@(LPRZCeg#$RATe`3zFwJL z6Z;mRLr2)5BS2@DXg{mn+!KgF(X@pi=#q#)T|;|@jjhjSWTRt{FX`1&&d2^Fw0`U{ z1K~dHy{wD_tu2kiEE-1gkMdsy_2_olIl&{`M*(tW60g8b_3l@3b0Tj7gp%ko)MX(v z7Nm3(Gqa7WuB0;lBmVJWV2PU^5`zRJT3VNwUE5SwiTPxEq9B}W53DE247>hj=cDoM zu7DBKSwQZMa(QZD_{5WwbBGF=5Vd`<&_h&^X zUDWqup%$c@7JX5a(pRyaT?xoRyhD>JqP7>BlOn$~d=DD71|Q=IL(5t&($0Q;SNMIg z&pP_@QdcuaJzIc9^~3c>vf0Vcf#9J}Y9AwFg5R?{Z4PrsurPaEt%hu*m_&W9MP1b0 z4(qa)RuMji8(kp*(y2Z_-Ea2mhW;FUTMAZEX@oH&qdp!{Gb!Qkzas4%e^51H?ogo# z2H#QYt}_O?|HvVmV2<)^huhgt?OQcUTqe)7Tld@^gNY{rk6Zf_lo1;Wk-MQ)S3}O* zCyFh2QOvEb?uCyX01{v_x1@+i5)}NW96D@7oG)4ZqcY*jbk_*q`sfyrOw9Ko8eq;> zSxQhIirWx6qV1j*rr{Q|4Igk9d9^`BU~oZ{VZ4+u1%OkGI7xqYFc)TW)Z~nx`N}C< z{>A`AH$1#lSg7r0ce%4qeM1Ofw0G9zSTxZjL~8)|bwdYpxfle^Vd6z3hk^r~o1tRe zMsNxNJinF})n4!QVzGKg-8QkJ5r`zPpjSDv$B#B2GehR~jxQnx4KLVAn21l4W+0XN zNc`Q8yMo>kOUvTrp1B`Wy#GwG`3HuJg%dRM&+~SM5n7#IKXWMfa(}G!Iqc;cb@w;X z#;OPYq8z`HJ+tSig;j{>CQrxYD+2dNc`^l3(p~Qjn*`*yYz8UFF-X@R#T`T+W|9v2 zo-xt$-gqNM@5EpdMg|^NEZ|nL+nmpGz^jj$`CYNTv6;_&paFdR0gKT+=cFOKDGej$ zZ@fJH0nEbm9p_3RbTA=39o6*lrWBD5OKYG3ZcjQ(m&2}NkYdn}8t_+Waco1TJ06z^ z{_@e0jB1|&U#XP15(VoD4Hhm<3-`IRn_SvD{STZ~lcX2(PF+25m_{PXiL!FEkOWtP z2cQEQjGEH#vqq8f$?x5=Atk;=Q%QQ{a1R0>Qtc3B`nIbc&YwTyRhGU!YeUxT;885t zJyqm(rpQ4M8q5oZveaQ5_s7w`Q-aGSbxT$miU-Z7%32l1L7>Gh6vAy?uj3v@U3G~d zo|E_R_pC;5cN~44J+x|Vv@%x%n%AwLy6yf@LdL~hDuiQid-qg&vENA^%PS$+$UMRh z_>i@%B>JUx<0~fe!cb)n#oGs%-P!{3mnI?y#lB&docJq)mxKBwPD}y6@%c}IU0wMV zG1{0kQJJTtYrO<(b)~0R)E_b&4v)mg3^lN6!qlBn{8u^(+s9%d0v=yb!Hz+ArrTU` zSB|CK%bw5nEjywJTi7x%#=lvCF7^@$(imz!#Dmm+mg*$ZxgHbMKzx@`I_-r;_R^y` zK1&&phTu2xQfjSDKCtJa1a>c1)s^%Pc~O%Wks?#h)1@EbjLNZwzQDDkh0fVloZR>% zS;vDS>3kFPbuz|XWUVO_%LtjYj?ZjPf=QH;Q}L?z`@Ls5zFY>lg_aAiWv+D7G4Nl3 z2_Q@}MTBelaoVn$^(-}JRox;UD!Q1F!cNa9UK{@82jP;^w$|>0*FGu6g>NcYiRh;U zbcM?qZnUSuN4Prlz3Jg9wgZcpMNfp|PhEm_&f0S!?OE5u{Al>Ee+|vPi%rOU1dIK- zRkZ?jQvZmh|0G`AnCzfTAX{t?z(jT9m9Z6iGrC-Wad3Fgm=IrOM2RZnevGFqv15_( z=(UVh#Bz^d(v@?eD_O$d1KkY+m?Us$(uQu~M z4XM~03vx~vALjNhAEj5BD3jep`U*%uutZ|}XG|D8y5Cg;2QpQnFR=Vozh+HbY+H0w z&vQWD2XaZK?yjs;Z+%ePsgC1lUFP3q8}_QDz-#q6w?yRN8&;NWs82-9BD{aF4JIq;5~x^X<_@$Lovcu7I+bNdys z)fd$fsh2yGef8g`ct_@YV-&D060)~Px+Iw>?D8H38#87->w*1Sd?P0DCvPC3Iwg=G zHc4RUo=Pa<8BY<);@G*O3V-AP=)s$XALgyf$;dmO;0w_B!MtzC#$_?1h!|htpmV9f zs@JfEo-?7UZ4Bc@rgX999ivG=vOLn@Op0+(T@lpP(#%Rq_2Y}LaaWh~GlAZWk2+8n z%$fCLBUXAM`xt5fH`SfkRa$$epFTrg9!P>*dlj7AmsT`2<*oXRD#-zvQ+s5uX|w3F zRJg10;f$@Co*cCAwp{{SJQT{w7nF{;o+HW?8K>f95+D@(l3`Kp3Kl&*n+05gw1>7l zdt@gAbcQE2Fy>qWmH7UAI&9A{1NVJ(6Q(t?ljjH(PaHth7f%+nt)#2lQHHTx4G+#2 zwt%hG-Kp1kMZS+$f5{XcqD&PWc@?dlpn$zWjz1?d*FINuU+{gf; zO~vcU*JZMoL-#-Vg+dckE7KkG9T_{h*sorNMZN5+Z#C_+G-|^Kju90Ajq&+TlkmEq zmV0sU-YjT->eCTXt;>&N0lw{o_@!e8F^LFQ+f(wlLHktbf$F#0A@?l)%;*ofMOW(h zAh8EOs|DlcST5AdCzQHiN{}6f5i{#B4pNa8!BdykV5d6DnXHSINw$In+m!3DcP8&y z_psmbwkEhqczy$59qft8_qaomnw^m6Gb~cH_;eYc58;G1XWQdlUcZE7y!*Hb)lBkR zj1)20gVVJuO%WN$IN>Bj^fq@c=|`!a^@72SYCJ)7nBEtoNzA{DiN~Lf`!Z(-%wX?F zVDEY;kEL|fcVW}{ER|4Khm>a^8a#fHYmnnD!yckd6-15^ zfK0pqQJTH2UFC@ZCb(VUwtcdnRND5c(!_3X*Qi{Y9iDuKG_N?|!MUV!cjO7vrif#Rgy z-C!w%ifGc&*s6Q&kLf9*dzA6<3MK_YSlT096PuH|cdRV%eEEr&y>#wK(_kgkX(Ha< zeQFaim4Y2d&MWJ93~(57+pu}b?^-Dt{Zg&d`(|Uo4SQLVDWw|&?7Zq$QaeT37G6_Q zWcybd5rfI!oZa1Fs8;^^t8a4mNl?Aum3dkcTK>>0f|SND!&G^U^9dT8guEYyYB}OH z_Bu_SG~ib)s4*#hmy`G^NHY040jY3EW?;r`y*xR{yiA*X}R>N0a<3@%yPd07vW*0E^Y{Q`)!0?ubh>64)c|Gu3hx zQ8-(`Gr8&a5GvtU0YI#7dud*^{MAd~b7p?7Rej+R1}`lZVILlt`DJmfJ`j-Be{2ws zEF`)|!M6lce}=U8irD8L6>jHGMo5I)ZZ-Os+A9nI`E^5GDMD?G?HT3R2VD5MO;+@+ zGoz0{UW~cA9cKh4cZMj% z#^4ha7~Bl;in|k~dL_`4_<%Z)lOXi??cmEjomlTm{#u|8#hh78{Wyh9`D+EdaE%6` z5~o~4xbK-o<;HOCHLuaHiEld>ifxLom3!@|ac0}HP8pIoV={ejY6yMrgpk&o$0FQg z>8}wk>d)Ca#Be`*nE#prM#!u+sM*FT)iM&_?uP}ndiU5LOOpE@ z`D|Fhq7E+PC%yv!NJud%(!Tvz9S(r;#1QvfQ2?#Iz>TC|Nq*O^xGK}rx1Q4>Y;X9M zj#4=QB*}Rb3iJ!tGtT{V!u$^9awJ9x01n-EJgq$D9(TE@X)*1WZ4chF)$ihOPmJ`?p0Vd2^@D5Y#^AjVtO45KG){_o4)K{T3fMjrj^4<>QRGWpcIB@8VsB`#@)jx zs>^$;*NEr>^HpH#*iyjaoXo}ec?=-7bE_MSUMnm3?bPQIz$StxT>R{g%qw5g1Gc+& zA9cxj+s-RI+Pzw#PtW$Uf5H-A*iQL!NjRW--v@qi9yED3%QV$gW*bm-&LLN-!r%fq|e^y$?#r5DKMQ6Fq6Q1 z-(v#2<$IINx`X64a(`uH-XFa+cLHV8t*F$=8tDTz{+M$8%WMZmi=7fQuVBe+ zR9oQx-cr)Vk%wH7JVXfg-1PXr=AEtlrgg}^#cKR3jkB!Hx*L;FI-hCdlCm`;_HIdH z7nj5GWO%JMD&%_L0H@)x&^JAmWu|dZpTb#6Rh6CnPrUKY)C#*~@Qmg)0Fctl9 zvT3nmz&KYo+b5Mq_0~P=iNbZLoQtsZEln_4z@wl`aVWx1GN!S8r^nwUf*M8|%*+Gg zlO1dBSq~%VCOs`gr8HyK1Ic^!HC1{pl`()ruoP!FQTQKTbss>AOv@$1e^1(=Uo^aT zE$OApdB*DBLI;+l*wT65AT=Vm%l6^8hs5mu_PP=|1#<^kxs9NDIalAJdIUL|5j|YQ zoYVPd5l0L(r3@9cijzF_ke=Epa8;iBf~x(*U#!hv9n~U1Ool&q&*-FMKhXE>D5G#R zg370Q@7^l5eh5kOT$_~^PB%)SA+WOihIvZC@miM_k(vpO+rjNil7n)|NCf z=e+2_dx6Dq3)Yc!c?NEZx5=8T&@%=%&?9x2V`!bkn7X7-(Tyqjs1(AVRko0qj=kDF z*eA=cwHa~fSammO!d>HpK0g_u^dmsL0h-N$mzaa>h2H~KLxgEr4*3m2lwZ`XegH0+ zpSmt{ZuFXpVdQ#oC$|xFOD-*cZm!B#087}ecHk|c7CTB0?xJhrJT$$v#VPqm_lF;Z ze;f3iwIf`oRm1hA3$^htj%OZ3vWmha{ThW6@I0bTS&l*Ms*Vgq4O@YZmPudXsWUkP z?#`<>zR&Qc`_Hz9cUsJ>_Vjsn)4gW}OGhe}?u=53W)oPEgRv3c6$*YXJP;ZjQ+bh( z97ti|h(js;WT7VhH}V6d4no!OrUH_jxShBKfVh(m*pHIu>ck{T9E5pS6rs9M83%Au z|KZn!u|0HUw?PCqs->#UzytPR&j^(fB%w2^uG zYGf+aJ2zvIdck0Lj!cGBr*O<-df6^sbIXAJ-ZgXL^w;Q}a=XFAo4LqV>QW9oS;rwy zTK8SLF{fr!o#>!)G-DE{2E9;CW`mCJ5_*pN>1#gcGN-k8bd(+2QfrA=46jZ!K=4Mo zX8fglKeKSMblAeSp%|bfSbM9!hjDId72;qg)K@8kO~<-|pVAEv=Y zMEr$100Rppj5zOOuWY%(8w6)S{9z|2L(R5=11T}Hig2tM;5fX>D3X53Q{w5oTTGtG zs%}_}jAH8}s@zQkbeQ^g%jn}Of_<$Ham&n;=?8{mH+=%Pd17H5(?@&G#{E>jqatgE zOA3H1)TYaXnX^j@V)M1voSMR&Ud3ybr(2B@hE)gQj3?S&XAKqt zWolc=d%4Rvs6CU99B7B*4XqnV8UlOtP4ZN+y%t}Usurp~1mEkiRR{n0`vxwcT3t`y z-9L_>tAApg>`7l^9io*0h^fwpi+;^#+@WI?JqF5tdb&lTcw^R`^vpnT(y3r;)$3gY zsIRE4ImMorS!a}Fx3_a4Kj3tBNtf7Uyr}Tr+`tuA*>Y(3Luj<#%LW$$NzOWnGe?HC zN0&VNzfB$pfRat}yAtp5nba5uuB;ro+^d*p@ZYn`g=z%Eb(i47+rl4@t7ASS+NGn! zD(J?=<~Ue894E=z-&i3I@74b_)AeH{lT;rWH@V9~Tp(-CB05hs%GKD@8FHig6y)lv zx<_69t>*B5p5iUQPe%p%GtMy(ekkY&Z$G!Sz`gZ{QU?A<`Wlz;eBR>ZpJ|D4+7*f! zi3-Px=0X|nPLxj<7KIq@JD!80Ni&I>uaLfs*ACMMGF^MB&);l&a-Gm6AHP-sADc2` z^BDw-uMKH@eIxJqgGs=cq!eHH#2pkZpa{qm3~$SSA;JKheMOHz%Qji{CNX~gz45$d z0APQ6yn5TRr^mmJRH9jb6%a79?=q5QwhJhy^Rt(2wf~m;sd+J7p@Ez1YT)r|X0ul& z&Tcn<+tj0W@qYF?<4dZLd8_{Ao+q{W-~aafx&0YQn)5Y%8Je=1r@Jvreh(%&hz)ol zs?K@0&QFrQ3YF%350#r}VP;$nb5BeKK_dp*d+eV?>$P(`lIP8@K=}nVL5v2#QeVI?8kgRJdC-Qd&G55~4zIcg|p~s8~4h1wLO4&;F zm`3k<{2vb-kYvS8O)!wEpO0}lE(}1(&@hZJ-)eI7QI!Yx%`$L#A=B$BpB~z)zeZSy zW6%5cQ;5k(%s#i@7nh{=l$;Uyx$qm8DkH}aEp7euWMav z&H11I`J16?7=3YB&*V}Oyb8&*>8w=-3cJR#HC_?K_>x$Q|2eSw(nRxZ#cPY1uIM)f z=c9vNwRMqdn%)RV;;t>WO8@=qn<=#-rRX>d9KTqOZ>f-xzVW;AbiIUGe3r!3e9dolN?hFS6hL|X!9^_7trLu_f*Ge)Y-2R5%nHUrlSh%3a$ zo8Klk1J?53d-PZDEP3XDam#3ulUEelqC!lN-6i0w862D1_?GOCgpqLR{} z&88$IDzg0rm4V&x!KuXP8|v7^yQ7f*r;QPMzrsX+WW(#>Z|*s%Qrg;LeDPvcSRrYA z!78osO880JmzCm_kYQl~ieWN81&NB~>)9Xa7`sy%bg7=|bAS5E?{#Xf>KsjdaXW)^ zxqQPN@p>?II_M|`Z!r-r=)dddGEJ89-X2~hIAu;IE z!6CpEu|$B+BI!5p{((SLH^i;{9qFeNDxX88)r8eT3j`4TpzY1*cow2@_6n9zq16y~ zqJ5&D%8U;{#f!p(r9-%kpL%f^+IOVyl=b^cr@%KDmOCww7 z^r=9MCy3e!Y>D=~n`DoTRy%J77?O)F`l5*}B6xl(@+ikQr=qv$w-pFeDGwe5pRQ*^ zIOzbfc#I%Rg?6^kIFDA8Fp4OqT2I+#wt^0Gy$`>lf21+?obrUIVzksC*eG#1=@_XH0^d|dmbL7YPnB0+ooF+7b^`B_ zpb+sL>9ZM^SP<%Nvj8mHdbCss-k}Wg>b(RZxntC_@@oK@@j7|W@%D4GhYf<`fhHxf zBxUJj#pm|H%>q4odAC}Pp^4g_tPc&3;oSLZ2@d7w+x({`Y}I8KnfDD$Y4>&7<*Bs8 zIbm=TVKL*q#xu&GN&t}wP ziDp*J+ev;fG@3U|n2p6wwp9&P7>>iP`Pf_K<1S=bo$26E&UV0~Y;}|DHiqp~n8v4d zQ%_f|S*iQyI@j5nt3aCRf%)hDb*IMvUq2+cgNh`ube?&r97LIL7bGw^8R2k*6co&2 z!>N0uPq;!Ai<>ZZ=G6=fXTKD1DIE1H;tY|}>$zeWXsSx0?R&#hUcI;-j~j@F2q{2b zS~$cVIURm~Rq`>F@utlnM3z@18VRk}_%(dY-W(f79G+o|60q0cd;pED~;y>qM5`n0^MbbV;P5-!vq5dD|athStjl_;D8 zximIyiOMR?W`paGbJB7TUvDKNOk z{`=o|U}0s9sYgGYyG*yqm`kZqnv=26=udvHB&A06q}ZY{#==4)+3ChY%dksJX8H}J zOm3zhs_N*f9gH`)UaA;tmAN$;eZ|h1nkxwN-}CNYXn>9T^?fY+EPNk9g&-|4gzZgs z%csd0pV$do_q-vThqI&`&`sp)2@8hL#dm(i=>yR1#Knrmi0jWg&_2%P_F$P@d5^=b z3MAI#ElsS5 zh%LY7kCJPWj0&I@g}`#XvOy&Gl()R1k+RfGBR5Hp`BrY1l0|BdE|j|dw#D$$uk(_PemK$hMOQoM+po^X+){5Gt!~OOE4qJP!@siH zJ!;t6=-c}ev(DrpQt^HJ%<~_^u6KeKkuj!VK;Fibhxhybi1_m%0YCZ@H(Jt>OLauzzo9wPQz0mCQ6 zlp(3Vff~Y)POgAP51{Yi*P+=tlUD9@?w>N04mrNrR|nF0A$+ z7zVv-CaL`ij+IflKX}Uhwu8%vHt{S%k<&geotV>~xond?2&X|YT? zbssEjeuWMsbD0KG(yJDj{j&NvS?NJTPmdXD2O7A_tr#myKr5C;wRK8`&7v*}&st=h zJN~oFdECie;SCkE4As9q4?pnG6}#e199bRdrGLP{!|^)Dt&9!Eaf@tq2)U!Sp$F6) z*VKH_Y9on!@-R%&MsiQrs(ldU?azDF#6U?? zxCIOYE7;PB6xZWhjK>uOjZ5#KkNT32sA^6 zy_Gv!5jJkVy$&9;rc!jpMVAnVG3@J4#3i1bNJN|{w|Ti=RZL{_d+oj(S#ENs_RX$o zCj&>n&GYFd?ruG1pXTd*XRGANKSIs(_09GymJZhgA{>oWl*5GZ{Ye}$;X)6tkv&q!=xfVa!@3a_s?TVwtxZpd zbH@Y3PgwgEe6a#-b6j_5p{3&Jz7h$7CK`-Z0EKKv4ZJ}OfKO+G7-5X=Wb}1ROGQbj z0A2j`gX|YlL_W{OW(;|16|z8AZ(pX`$^Ne6Qm_8+`Wo<%uCGC zi7Jdsg7~%0nYDJ`zi0j&zV}qFd9KIkc300{0Nk;q^%=FIzq(uq`Zw2`KYtEVVvNUx zVv;!(h$6<8gG=-|k)s&NO&xgqHgZN!GmGv&Sahk^Q_IH)`BXlrFHV#;GbR%vyZ9UT zR2Q4XfOVDyN9bAFxE3vA-@)W~QnM0DAAmyVb2FCqt^EZT4`4ymE(Z|=7|12b)GhfT z1*C06x?dhJRxf&cI822e7@)#$ozFa#oO$=RwZxbJ){^E?=U8Di8mwT5Fl1yZWF_?I zNe$)Y9;3YRGeQZ&mEXrwQ~?Isp3CqLktDxKZnVfEmdFUxn*OBRQ5I6#cf2LB-$M*r9gCf`J#;whb&x9l437x1x84lV~?<(94%x#jvGhF zDd)NFWIb`phi+}@+f{9}LHL3&7FY`q`+iYq%kd~tHeEI?#_YhsQVgiO#Cn19=HqYE zL2G{N0LF(5!+Fy?C&um~6j(W{Atb&Z*OnI+rF`)^#P42VxDR!t8%<8+w7`d;i*1%JVp{1D&Ay zcZUxLC#J7g)-Dtoik(WnK#B0(;rk;rp}@U25^VIISrU@mbtk% z=;VE};iyzQ?~lDWxx>_#%1K{d{Uw);Ev@f^ado@+$mFm&IKaf?er5)xK9n_oRnu|$ z4x0H9+s{}^AHi%z=3rvY)2B)H{6E2HZssgFoAcp7O7+S1^t~O;e-rut`U^V)40aPc zgF=cN0y{QL5GLYUAlA%gObhskLCb(hk(^NN2HZmUuPWHen zMtbxm79~azCMQ0dAFw10ia@XWXix6>Hh*9&-{fW%;ncn!r(Wp5*LY+5%?6uO;`xZl z=0I{U;Y^j|;o1ATe!K0D4#alWAh^rH5IWghlMXBeEX311)BpCbMsx<^bqLdHw^E& zQER?YDfBqw)OB4BG$AZL{H2n=mMe6hM`+i9KHBKvLSArkL1`28lNWFUi~&>ZFVYLB zw}xdZ656=^iCgf#wc@#)a|k>TBXqgh&h4WwZZHfwBCI(C{1;Z!(7GZuWSf@{2QJMq zHr}Vn8%-NtcPWRSU3;viuL<`Ui*F#i4~DhHmu7+l0)IPbg&oL*mt}(MQ==wa1Q~oq zCD`MwwgvxX(b>aR*I+f!`@5x26JW2!o^w#0S0jbM`~UT2XaM(`~@(l9LXUkRluWn=TCmVmBZ@q zu+d5jl>)O+2Aa<$AuFh%+~D34X{oT}vaBw691fUgem2?}&nxr1wm0~K7m5{xN|HL3 zTjj6Y=-vYiX={Kc!-afs%o>hAw>c|_nd6|<4~4<;AE*{2Kcj0uch}2%8M35p4fqgKbuB}XZSg>PLLnNl#I@;mg0)ae+DdR z=ZVS<Yfv%yWZ~McF-EHkHR_;ux~;Hp}m^U_xke3h}YL zsV|9`Gs79tM%Yt>b$nK8h{L1}K#R8bAT5w&HKd*uW0kmhke|E*?Oi?S^}{-=fR7O~ zXWz&8+pazQ7MS2kNxZMp1=x9R-|w}Fy+FG#@2&uqaPll@7_fGKxfl-;3#7nT5+q&~ z8bQ{S$jz~7MU5AldTIl=~Dp?P;$!~=RI{`6HY|8P=BlOaCNr|Ff_e@)L{K< zTk|Bs=dK;ziRLI>as&7x(GgibNq=JnaZ|8fhg6TJQ;O9rI{BsQ2fG5FE_46hPN<0purJ3`JKEHt(_`k%o;U`18g0XaI*5_v=B^UD=_#)4o}~ zbIcNgzBLYrkWr4RA84kIU$d5sh;8vEjbxtqp#|*Q2lPldOzZ=W($h^|^>)Dq&mOOA zFh%zj0}L>UIGY~Mi<2J;GLb@@&X?@!ooh=AX|2t=#a!@%I8K6=mv2BP>n3U_E-=_i zU3W5jN9n|6gw!84%@PU$qL4@~PI6K020nBa^f#md0FznweL>7}I(w01Ul*?!YYzrb z;@i0{^j$wxEk@qu_##&=mudxmWoNc zh4Ky7 z{$e)p8e~MK8&PeSHZydslRZE2P!R)uW3;wKoxk=)_yw5`_<6cDpFF2Yb)lt(-uRzl!O$p5K8}W zh(BX{^b@H3A1pj}Vqb9w*Ys0KL*lkL#l5%Yp#$%8y#1Z}8`saG3eVT9bNa!qBiOU1 z+F|IxR;k9^R)%NlF!-G|SH^4zOIELH-Mb%t+}PP*#!6>!YR@wf!ENxO!77#KFo^e& z8#ll2>$BqP2Z|O&v4s!GOO(xF8BdaF?n*)&+&A}!)BWuv(vy*e9KDXAAjp`1^Vp-$@$2+wrrGqCt`e(qZg=5+8GC z{P?r=whV46J_DWacU)pQ{yAX_B=~BIm|vdjJ#ITW)ofB;H$hrTA4<1Hu|u=l{g}nZ zW5uT5Jp0nMLlLezPKx*22S4`$IQ;LQo$yM(y0#Nc^Cqi(_%M~x(`XdIf6{G9lLEMG z_{-0UB*M8@;GxZa-w3#hk|f*ZCn_z}FujAwj2aALEN`1O94UKTqDmbufMFeL`(#B9 zdB3gWelm7SRjb}*4q!e93^oT-j9Wg#EaX@w7Lhr2(PBk^Nq0&BjZzkbGG+e!&qAfT zBM9+Oz8J(eWma7`Se*-~9TJAMj-KQlf~PO--=4lvgrBQ2 zGR=NcrEQ1$j1#@47x+tcSVpJr9<=;=Gcx;nyImpdck)%?khTMZ`FMm1rr zW z@x)+%{dhA~YO-)P4jE!Fn0e#0-RcxxT$R>vonM*kwx4Pnsln!z%D-V^dB8Z^glqBp z;~@3s+x!3Xp-C zCDWl4ss-v~a}MbW@83tE*W1FsJOIN}ch>LbC7 z1m7id7A91LfPc60n&o$L%{S9J%V{RH!q+}esLMT!(T&;ka*Cpc7CTA2didY0yIPCI zU`#Q?0m4gMxqQ>lPR=(CNRLN0%Aow>07r-H(xJ!(w6%By#&Y-bPqTm405~Gn3Y@9tb0L8^6nW=2(PFuJkkeF z`hg@Y*`tV!LQS%&V(Memd#uJO$MN?P(}qClfNu2bK983^VMbkGa_mQt|3b-_#?M}2 zS>LTu3q^sXg`Tgd790Enx&I5)xIiQv{9K$MqnXK%@96YAkKYw4M>(XkoAl!<53syj zb0?(?)dpvY98E63F{{h-?NY>%tZ{F}h_0t+Z3go^RX z3gUlz_iwtL85JBpf7bg?`*e1kRxE}nVi)X>$J!ddST&YkICz?UF?6t*h8L6N^C?NQ z5UjGC9pHtuQ)!v#E*S-I|1>>d#M!B*cG}S9(c2KR&MX}gsrrHP+;yY{g5K+`Y@&K+rpU74aC^MeHG~TBM!0>UVtHWgGG4F*lM; z7WW{#HVe>D5(=jxc>*uq84Q;h_hnJ35gy{wt83Ib=AmP`%{CYlNcU)Um0>$8qG3jm zZ`fmIiA)xxR~ZZ)0v7gcJ}s^IihwL@FUjLom!A>sU%(T@s(m@icK8(AHiVNQp9f`P z*CiOX*vm5Puj@l9m>_7fc(~&rnsj;aYLu{;iJ16X=Kp9A{MV{w z$M$`W)6lW$rFpLnk;QiK)K;+W{aMB1p=plnV3TMitIDsG`6D3X71hS_PcbSY#&@~i zqM<_#KaMuP$qG1lhRXBlWpt&yj%p8&)n9~3plU>VNNJ3GLR}w6i*;3+HrPyh3p+bP zM>(trR|KAHx=kus_gSmz9)Qb8OnCr#Ok8fNJDtZIpwZPHwIP*vVc8ASngIP{!(rZO z(s)*VYp%8&@GtqaxC}eKK+ZX>W++Tk-EvqUs6=c#nBG);ZcnibmeyNeki?1KUS6QPG8iy{<+lN zzjInYPw~+^9I3m=-v8Ue=0-zMU+(jDwRV^P+q?g!9Zu=N;cFj7UwNW@AVd42XlZ!z z?PK7&Y#Aj;ZksqaxyikI))wsD2kT~Oe;MfMWvS2TdVR%8yLcHQa)yy;+d=G=5fdJr zvD(Dcnd_shsrNu`e!2K)3di=45lvVcCO}foOsqd}_QKStw|^i}Wqm6;kF}Q8p*Zz; z!Qmoq|89ZTX1ZjPKMABbuUmv7eRj1LdyA?7KLk(EvqmB&>c_n}x(IVaNZ-$v%VUix~2*wp=qO@OE_tQeJHxYbAxo9<603`^EXom^Hw z&3WqMJ=AD=F*u(%ZLSr4htdymP;eXMS@hT(^tSgoC}Ja_*|!cDhLsI~)LN~E@S+aUIORd70EQH%{Q3NFfiQs^Mi zFU>efE!*4>gR1CeYHXe?e0E;+ayd=#-?bWq@JNjJRbY3J+L?Vp{c-^e^>aGmlp-)$ZTZ8&&}5chXn;aZ#8{l4hYh3 z!0t_7Up?rGU9QF@QPrS$+o_v5J<-95K??J~zq-YKWckHkC8>=J5!2NZ4+O8DQYx%&@4B-O2`r=?1CZ8oq)$?k|m4qwoA(7ue2 zf!{n}46Kj%*JZ9tzAx4?zA{Av%JS~Xlu-m_Jqb`GUP0s9_Ji~{Wm5FPphDACe|^Q~8{gOlBcZGv8wmuS!-iA1ROgZ+TIHMs(-gq_ZEM(ulA`@8zte%~5@J+G zpPt%{0WCy_?$qQ(29_&^A2sQhuS-@R0SB0h7na0!7NAL>A|UMw12PjmJ=+k|5pTc= zK!!gf*0j}00S&WMvWSQk_8Qy)47gt%0XAfYM+o3W_W0ip+jkMU;O+vGLXLke^!`nv z#AN5u{Pr%LG)r1935ApV{J+1-Flgpu)l+hcm0CHIvk*-E~y$Uaj* zlwcVSk!+YNUmaNP(UCndR5c)=MGr0$qu}(6UC(y^I&l#-!|eIa5VMLcMqS2sf69M0 zxUcd2#^VUbkCUR<1z*=!V6)x_@{|f=OCAhC4yfp)TkjZaQ?yf z@+%luocIJjJ!FXoZov#qkR}aohyktsGb?{R>6*NeQ6|LWpcYDjp$eo-v}`Ny2Iry! zRBs9#_2vEuWv~MvE~l=?ekJ4?cj5;8q(UmchRGm=b}UDZ?JZQveG^247%{Mk>-YML z^HSdPNo3dNyOX{$>v`U3tLpi+qWS}A_gaM6P7Wu4m6)w#*#P1PTEXc-{UIm19RERQ zmW<1OkX5bGw?qedmb4RlJExd0@CPcW zCSsl-MEU5FCaS4t(0-c$?mg^sM>yYsncp|V3Ev|*Fx;MN1d+c&xFlMkjgiDJ z5?UdVgg0=K-u^>5rU{CLo6aDqrSk3>FP^%&xp7~8`5vuE2)+z-ob#QRr``8=sGwP` zCzDG1<&w;arf}2a5Y!&go$I#m(v3rxzbg?x)qk;jk@`BqNz=J%Jg(A%;e0xh2hrjv z8SYr!mS}F>GO5Cpw2>p?cS#H8b_^o#e>4+(CG0tOYHsP`jjroC`ixEuOUA#cX>cU2D#DmcCu&ed`06*8%Np&?(La4 z>{aTN&*Q!ELW7(As1$V%;0a9`BmxQ^$00lX_h$+m@O>R(uoS}o#cP-kKKA=3ypS6? zjN*JY1*Ve3@iMsHqCq&?nRWzCekpiyH^f(`uCODa<*=nP9_5qF%O5GZ&%QHzTd!L3 zKhIV;zkE>9TyV`c$_&-%ty+BlOUR)hHVl8PbiSB&*19WeDLXSbE_K$&b6&Hx_KVpS zCDmUigYOv}X{Z=3V?cliO)BsG1Mgl*d%rRoe=^iF0UiuqBqulp-e6*PGk4Jf%Kzqm zz+h~l!%|{4R4{5q&wV~E8D%n);?yA9i=wQ=zWH7fjH5uf%3qVfMD@dkRgD#`z6JYR z&e~PUGICeXLrJ;;m*%2}8fSkR^*wWgtf6RdE)g~Xd&jl|zY`KW*TUKUX}fOH_@CRZ zTAEqwV0O0he{7L0=-eRjc&1xW)O7Qy_H>YMe|<*Vy8~UK8^E|3y>2g@RQjd(xF zx9%{$qX@cj%oaGGg|7`XQ59hPE| z9Od=nb)3-~68@Vr3j9nJA#65gLxFF18-nnYC&a)`qIN+^qguQ!T(5R9a~w|9Ty2we zPlJ9bN^EW|m8^(^zZ4;p<~A|2ID6lzZ+%F^>8O6wsyTbI-0*Gp@?!r28MA2bur)61 z9p7mYp|*l6--9~Q==1}vtDSb@f3^4iYjd^?gOjFmHP>p^eckl=Dc%~M{Lpf*d>PDJ z$riG&=Vy1NuH+crnd?7@iGS>;wse+%abtbs)26hc$cetF5L!oBy}h?4OrbKc7PJO{+{s zQxj37vJ3ayki`{}nJCP7SGiQ%&X^$AHtf^VmFEdh#64b5t|5p+Cb1M`4bLZb8mASx z1Qkgb>NG|MLX=n}uEzzkZ@y$w%=iEyy=?Ak%?LxUwvA-{R||cM|}5tyfxN*dF4pY_JhX6Q$+x}WZ6yef3D zu;ZzF-e&+Kn{!^rYQ4xb1Sk?OA3i1iV2i?=N$6e*D=uTA7{ym5WpQv;Zgjxb=3N0GZ;= zRODth?-&kh$^V;F8t@cwvv-yFVWlbr2&6OOMeqI07hW~#rSjitWn#3i_k(m{9 z;m=emsD`jn0f=J!>5}yyDDq%@XWDB8r2JnQH9p>>J8%8T-cH48uelyQ?*RhR>h);d z#}I1SR(C7fi-{)A$C9qg#a}Dr|Jd69yUiM82vgDsVlq|Cm>$C08O&=gpPSYOuun9T@jzK^X^Cw>ory^A@nX?BVhM##D?g+v* zZsYG1=`iayOchmvDyhq4EW{Lve3djI}xA};h^ zx9uL?(pG?FUE)XXlokD=xj<|6)R3~b8k)y{eD+(aM1MH?#p6Ocxu3zq(b15jetD~1 zKH)Bcj>Vp6)-j}$CQN*GwDSG9hzMf#d!ywu`)R8;g0kh3@V3jtyVR}D!jTC-DeZTt zhl_*n5V+)&DI%ZxR#kD_O$QTUDIkHhfK|zWZo5A2`lE0A%>4GS$W{|I3LJIz@%Hk(Qa&Ift z&AhLz^UIGA*@g`8`m`E?q^e)mU~x3TI^!e)QnY@W@%KnQqM5!X-WPcme`g6ob;-^;alH13^8WaWum&Wb#I(W6;$+4c)wRT(eTY*%IlEt1!j3!riqh= z(q1QU2;P*iHy#J+trs#X=~96mfr8hp0AM9=;V!z*tCq@ZhqPYT1XgyY09-aRSaxTC} z>Z0&&kzRuVK6Jojgv50@#mb+@ZP4TQ49VS+$l9b+Yyc%RUQO5SUDIXbVULQM4&@Q#q;|+_ zu*x55F~u&gj1Di%&u8;RI-p-)U$@^%55Cy(kg>4H2a#4E?jG=LjDnd|DEte<&F_e8 z;3cBGFY6b3KmlLtFOxD@D|;+C^>k%k%J8mw4W}>%U8fb*BXt0%!It zwVN*E7j9|~_GX?1Gj7)xl%M`~{tpU(?;U)s{E<>2swn|}<22dUmjF1TRws>QRZ^uvs2%FU$b$-xZ?JnS}mB)w{2jI&wn-^y|vGQfbU- zv{7af65JyXPqS{iGqWFtd@L6&exC=Z>hDg18~kp8<36w#qI7L=|n9sQr0;gIL5U0^@G}Tzfmg~^fl%*y|UvC zES0^WPCC4bYE_S@ZBrjq_bDyAtiDnYwbOP-iu2FIA~F+d=)SfNs|WqMI=n5ZbI8`B z0-Cyf0!w=AhKw~5Y|2vQAF_dUk4JrFl@eyqtkku~ex$kb)m0N(}@47k%2brx^^1h`{|3kjl z@=6N2@60s4&Y!$OBXxc|f>SXC)7xa&iJ+z(?mf7R5L8>X{u92k%Zaq(b$8)3b0!mI zV1zP$Oke5Dn&w$IbM==0(eGAN$$`>s(SQ#>Npo}?RVBwvh_W0gt!m1WNnX<25@`#? z2VbhKJ&<$b$WjcyghTUQ20Di%dVNbw7pQwMUuCm+r-ui}NCLuQ6x2Y6wv$nvH73s| zceL};d~d4M9%!)VLD{x1-O#q=CKZYMOw=$WF>Fzv=^PNh$`CDq5Dxo43%GgfXAA0k zI`*AwHT8t6gf8)$pYq4=uNpsm%4l39ZXT;UAUyBb?3o8&ZNBz4w6ET}Yu;jde`LM& z{#oCAJ>8)Ae~2fBiQstam}qS$BuTI}gnt?^b42%7eo+)M8=a%K=qAqhXX(HRrf?`O zHWwv@m%1GNluPuMRm0hfEZ{BA^k;i+gO~W+J%_vY1S@-H3uim|%f3BE0d}D%co}2d zdbN<5dg)imB3=$?-2@#9*FviYQ*KzkS6DeboBKUcvcXVdx z#Xb~U(dZ>$t@Gg7Q|lzKJ84>`e_jgn)TwCLwc>2)Ayf419~Ytqd`V@K+MQqd4C4X$ zgzRRKo~Ox+j=``IETC$qb~1&n7*Ps6r<%NOd%-?M&v)2RezrX(0miRU0fW(^_9P0= z0XEuvi+IyEz20>w1X{fS`(ZA!7m)M{9_knGi~b0K1kE03Ux;u5>XQH~1IPf!V!a7R zFde*04#3CIhr+j~U(D>ejC2Cj0ojQHyM>Y&2?1b`r#?M5i7Gu;%^QPjvlDM#B)BbykFPmbf))suJ`IU z-5Bops%8rZA2`HMNskkUJjI(%Qx3aVI=_yg^f|t)9fY3Ao?z+VxC$l#2Orea2gQY} zvt4~g*b5%RX})@A(O%hT(Ei+)?-6{7!HIxM9l+~WB_YP)AH4LeFGa&%;+IPk)H(Wk z1{`C0OhBZ6S+U8js%S%5-uZ zU4qacwLB>~Ic2)R{&IM19e0lyw~jxh)$l;#`d}6KWUET+!9+q!TIR;HXrkQPJ1qMl znzOs?RX<*M&Qi`f2W@)~;d@Xm-1;>p=n2++>K-Kf2)JE)HaZ$#>)3lV-0b9!am-#~ zPh3DNl|2`Zi!#@HjOLO^SK7-nLf{VX*L8Ayt7OowVVPnqwr`q@V$qsfBvJFv8c&-vG?A{3%t^e6fOH*InRGsi zHybo-EmOpm+*n6)Pm}qQz2Nb@cp$vo;C6fY-o|@ly1-&E*A5JOLIBA#sqBx^Qr7n> zD(fFj5U>>k>ZgvuP~2#*vx`KUy%6#?imr^~TMBEvB zioN#r^a>Oo__Bpi5Z90L6ujtGH6wU75>QS*{!)yR66qwuv&y@oOh*mpLw*Fd)qP$E zkAi{%+0t}WCzZaMrgm=Z?kvzke=cCV)Y1Wn+>-{fITr9lz@Pm))@|NBGQWg&mq&R> zl2esLmkLGTY`DUCyziYzCjrq!K&Z$d*Kezt3R+(amKs$xVt!X!ki3k-S?MDyL$oAu*$YwL>xUd}1yBUp-u4)SeR;R8T zh|`2dPmbr*&!5c4AWmZS!pS&+r8aNDC4nlMvNq`J( z`r9l2GjnZ)$RS=}s*vorLsaeD)2^u}Xt|m&D8!b?rr!?EOIMBD1>uOuNX@kcWm6#fpco6jxd}TYZum ziPMKy^sns}mHl_qipniSt=C&1Jsd`j5A;*i>VuU6oOGwPlGTC}QNm~1*6SW`(JmU z-RsqzyO1(0x$BG8YY}g7vLtn3cwN~LOK1yBd}mtkgGtY45hr;_t_7a#sqpu?sPUt6 zQB}Y+zw{1vau}2tOj6Ajd>*|{=U|6ON`mhLVh|D6z=(zz&~Px@;6f@JhgjV24~8%T zy6{-Sv##a4wtAE%0;v3YYLc;nn#f@h2La=3ouU3?jh)?H|MoX=%Wf}peIrZ6U1>Fe z-{9wG=?_0XPPXk=FQ(cxSPZ{7-hhFT#bHp_PbKrd?$etwl_vR^eU75Mbv+?u4(Ab| zh8OVq7IZO~EqAtD0|GJ*c3ror(5(i{kf)O1X z<<-0s|AtFO7a)les7B;<#0ZaoF5kHjfjIr*K%)jlh5ch+s~1|At8a)*-~!v+mD2iA zMquT$#$baK>j64zDfz%dgri_C%J?Osmris?_9`hGbcEkQ%nlu|%Ilidc7Hg)wa89z zv=lI;!jfkud^8^fH$*?JBY~Iu@d65rf z*Yh!_w}N;a2b?tn;H*(fQ?8CHT8i1dr%W4iO7}6+PrLShIH`3$y=QWm`;Tg*YpwE*W93NJFKQe)_ zmsXK)q31EZ9`buLbtsg2VKiFZVWgARIhjK?Oiz8FLEt%PsM zwwhUuZ6`AaNRhPvkvaTy%#CLWP>?$w>IYto2UY&oEv;jh#8z zq4?fPAk+(mOkmaaQeJY3Q3rJkXOs56*YZSz00e0^rwHY?1c0|shxK2LRP zLsKE`d8pf_g> zpZYC_+cZs@ux_%CZRX`)eO!qv6pa6C@nYRvx4ZM*hWA%dSN$i6)$$%rdSjV#G&cgA z6XAbsLfvgX2V*f`_M$g4H3nmzb&^}GZR-{d2uuXY#YSmqNYu_T{FrATQ%IxBIUrNn zae7iLeLkVTE{gg+2~#0faMM%nx%RneUea;Tng9LFhMFFxx%s)tD9`*%>8sfJn-YuS zqTNdp0&YoLrUc0!`3OI4$&C?T7Dw9?^21k~<7R$j^G@8uuzbG1qIPga$=lGg^sJb< zHS3^nVAfyo49CfX>E<)_l(r+@f*@1l*(i!Ld+cX3GvfR%W_$l_V2`g7#eR}#8mUjv zJB8WcwS+Tu<>XR$2~O zZ>`2WCq_*^VnUN$3W&A-7Q~6+RbsMgo8lC=;B~2^^`d5Zvgd}Sx;^sH>(Jwk)6O`` z`7)ww{7CTd^3GaiVB>RvQ!Iz3G>-$G}8G^+)a2ss@V4D!s zh@m|zd89h70(QRlY6qFa9^z`HI|%iId|&J1=JA*85D|2Tmnyr6>YXP^7GmmNFW-y@ zuMx?v3O+4nr<-H3(f;>^T2w=I?1D1k(EgGuL86T1HMWDM%8>`_TyCV1OBj}e57YS~ zMqq0E(!*&ZXZ;GK?mRXrqFk%DA)%QS@&4|+{e8u|{~#ZfIALsEVHJJxijzzI_GuzQw0&buJ^IZnJgK8hIJM z_9aJyb%cJ)mG_}Q&ox(%d+3OSET86!N_!ajGIH44ZiEnFJK>?fEE()$p7XIN~HUTYGmro8-XtY)^QiuIr!H%(deQi zS5cA+a01oD#iDp{kr?P|&0d@M`iW7_jVmMp(!)1@`Zb!(p9gO zV$d0(DnSNgjjeMv<;TF?;lOb;(AgD;s<$@d^o^|ztr8If7`x~JHv{a(n%*uWndk1> z-i-}X^Y0!`v%Tkun=QK#C7$*wq6N-Hx$7gXZhxSX9mzY$RBiRZs=>eL1oA=NiiF63 z)59&vU3DFw)Ab5wQtdLAtF%Mju0G=$lxQht&&vai?pcOT$+^=>?aVy+*r&7bGu!Ho zTZ0O%+G~fA@Mhk`2is7Ev_u7+)ZUC~h08%_9yn`9DmT3hr+(PwU4J-Xb;J^=K6t2^zvpzb zynE!HYH&=Rm%O!rbpud;z+qUOCsjPl3}O@dJ{*&N$n4WfP;fqjxf&6O_o6ibnhi*3 zXfz9fokZsGgMM7U>tiQB5%0YgMXVN4&69#a8BtbOU(}aCU?&HFr-s?m)+fZ%K&3C| zbO2y)Ik(w*+Mv1Qd>dr}&@CEF%Dz68R8%AYJTJU+LKDb{-C>e14GSz>PhEJ3ggaXx zGi&Q|H^?s5IC1!EfPXu*0rEFKoXY}@0drm_>=Ht=xr}FXnAJ319OH5?Qkv>o{Ku46(a+J}s`s)7a6{(h@_TUARBq5Dk!j^5)-b-69j@OEy7oZ(0|haUbq| z-1C|tc>H*k5p7ecX+hBA+Z0T4G7ng>q`~W=qqltrU`4ibGk~v`5?Tya_uI#Up>+44 zx#1kTeav3??{3{j@Z-ntg(UotVdrT8dvD>^;ER?r^_Zz`8!x7ZPS~cxk%PvFMvI3P z(2qAc?LFQ*Y$yHYY>?@RPEfU!1C2ou0x#eCqR>k*_1 z(C}>xYrk14J&5Osenqrvm%br&cBdnELzn}hOLfTdn>TCjPvBoj!$54Aw&vO^(utN6 zP+1OKd6^B>QeU1QH3vQhM0EdZ!P0RBb>qF>NQb~HepSMo0pRzptFGG-e#n{!kzfs& z#qh4X`&D@(^Ak8u@S7L|1rr1C^3{^a zo=#V1H-B8Hxyxuv+7s+vKFf{Vx>HvSGNFgWfjuK1|0}qMP{+@c7*Qlsp+I4kNV2)W zU`&$v_#h0Z8}}BEvd87Dq)uueE#B$&XGO(8N?%zs>RI- zWL^hEJFdwKz2ovha^%U-!)E^aorukN>loCE!Y}7cIk9LXMh%gtrE^M)&>Rn{pO|7j8cnmmlH`Tw+UvQ-PrGm!4a*b{zZskk$jv!SEih;%AsW(5Zs2}|p1%|n6$)OC^ zF7sm5x49JyqRh8H6w*7bz@O5Wtqebye+9}NYCRvhrcAeU?aV3jVWu!9+g}fDO~>w! zU{RR@j82QC?a$!HvV<+pq22$vOf}Byb+}(28L9C+S;sTP=~Mo;oRA^eA7(x;esr*V zuFyJgv)_grl=PH=Qx|lJ5O+y$I?ht^R@}R|hdX0mP4PRW`>Urbfu98_LHn`Afib4VR+j|N>&|fT?h-HWcXU5RhhyNPp2?(@q_)NbMtcJus)WD%%1Nvo`<6msjm$wIKuWjS+D<;tk(sa8-NJM z)@~yfMnmdn{uI3#IjhXZrvT@v82*2|?F5WM**(hd???r8&>7lz&C)r%qhl%JxHBa&)U zMi0L7%OPr87O@a~4>0%GWt?`3ekF-usA`d{-;cR`L*2|{jVY*UYg@5c2d1{4%NI-2 z?B0-QOi{qdP6f`o0T95>QE6quYX<9K5Jfxw2G3EqtS>?voIXAz#wMgaR5vk6GxH`7 z$k3IT&y1Wr#L3QU%fA8vj?y+9W6WHeD%-sZS z&c6P=7PhpZJm#AqfG${>zyy2kV>+Gsnv?-E&#*yj=lVqp=-*FU;+ ze4i2YlKU$dZsF6bETHRG(CgH1kQ#udXj@Ne!Z)z?Tzy=Dk>F#dZ6zFG0ut`$kBdY( zk(=(PUO+0~%>z)2B!DcdOw0TEdJpGawxM5!0uRvJQ1$2dK)1@=fhPo!jIRo!S&G7u zh#h@YQC*4eSN3_Rz&o3(+d|-~4>|FGPs>!mS1{p}dN=QdpjZGTgC3+UrxWi7#W9W5$Wvl&^3;tdTlZxeP_4N_j225tK(N?+fSH|i;ElM7jZaUI1EIo zTUiMU2XbHae$nzqR)CrYFzn2$6F+2<<~%%`CQ#eZhW@2ERl3nUciYGhe2ysrN)r5c zLTvdmy=k^E3&dQdrKPa|3!S+)6|M~>9f(W4LFQHrDHyw%TD6`*1UP{PrPbWa8 zGI+X;D{2<2D8tcvhLMj6K|wVo@Vd*ch-TlypHwbfVi}>+kvRrm5?;R2HWKJHF|E#O zSUSGiYx50+I07CK1tU&CC{mIh{5m}h7L2VmC9&*b{Bu^}O^`B%I|0VUv(Np9XC219 zl%BRt$ZB7-x7&{&ZY>h+B75A%F<+``AAi)wGcfMGB#r4%AAR6v>>bhm@3zjs$~5!X z;HB^5)n%|Jro*W-6x9;>UsUsf_Uo1lx}iZzv-vae)7z>aZcReVCPVUxvs@_}Mv0V$ z)Sg3#6s)ne|1o!PcTQSUyQ0?!#|hMdjaFxT*~L(BbqPpcJl;RE7W0=8IN9*R4DZZl z%X%!<2Vb5oc*nDtlKN&4`$W+LJ)2lEt{wKk1_H?ygu`MK5=se{^m%t#XhUci*TkJN-rz9fWGTbs;6Dv3Jo#Q+H$kwA)n zU`vP^XalpEU)3rZPbRF*3b?1VO0~_JpXL+*QhN!YY#crYg7; zT)+bODjD7at~%;KL}AnnP`_@Q7#6^sbMRg?0@s)nI}L4x7M%X_I$0hQC$Su0D@eM3 zg-Ne?-s$7cMLd!c%57hUj&qGk7R=z_!Q^$lM`|U>`DOaffln*=@eQONn9kwle!nmT z`O~PXlqZ1C{&yW$eY|-x-aZUSx#RI4Kol6yN}^p}5Lnha=yE!qTf7b)S7O=(U4qAQm0B zzqXF&;cXvB@p?pXo%{9pU=joL{4GR6FP)qYBO`oV$ezjfBv}&HDM85#Es?Xdw;z2*bsSZ<-T3_m8)UH z+ts}Kn+Kxik`Y@p^za&&`AMsjLHUb&Z1WP_8HhG`&hXOBL7(T!-p#Hobsaa>qmQ(n z{k__neTSHOvl5L1Aozg=1V8@J)yTv%b92sW5L_C>afkuT8E@$8;RqKxfd1@;3EMA3 z&yNb0i!P`TvFWg%QPv-}^P*2sm;6VdSOGhbwnpgvWdBO27$t-7nnikx%%%9MYlE=; z3|5Jj^)tl`(eA>|AVtP3tge;^N>$4Z*!*L=W2D$NwV`#G!FpJ0RNx8x462P)$bTdB zG53QC;n@%;R+UF3-0FPQZJI;QV|Oca1B{bCG#wk_jlsAxfI`Zzh9B~CgC24ok!zEW z>)kj7vI9PFX`udf3t%Iyh`*WOkQ8;jpPeqr{X3AqcMg+oGJb>z9I^hSP!`<+!7hxg)wfX^EeR7m5y5wbRA zHe23BtKFrbbDWW2^qaFStEMWEraxW3BuR>?Zub7GVh3*D?a}Rcv@cjrow6ovYjhKC zM8K`@-em;zQ-vge2@bguq57M?G2G(Jvuo>&JTs@aE6iYg(+Nv%{GXC-{{DYUR=0ZI zM%6Ay`Y$jQ-!(zv9HeOC{Eu!We=fDBuAVwa8OSL!27XCHZNdxECqM2A4Z& z$v25E2pomjS*o6QTJ-rUcsx)Shku-mhC5{jR7U!)#f81d*+-*0Sq+KWL6qw(&dHM_nL@FEjvb2fs$u!by^bGDhF#ze9!#Y5_+rXrm#Y?EFH` zAr3*bLvq+E(z^MO4c$Zi#WY>pzj;A&9-5@w>!vnS-4zk0y9I!;J2oTUXaBH^*x)y% zR%Dp>e>@=$4o*IMA*3;R0fvdG>_l8~GE|TweJogPFv&rW9|F*t#s$#l(EbZpKg~_@ zc>e{{;iV=W+SR>#se5bG%CI4>A!9}J|3af{J`Typx9-*RMlHv0yd5@q-c<76>nJv_ zm`;rz9^w0EwD7h%K{_-Rd>@mv``)oz@ul#-BD?g_<))co&-RA^uXnFbtM=%Ro4+EP zwPf-o!s=|%sz|KfR>&jK+OH~$G39hpvf5G%usR`!n7PbTcm{V7qbrUsGJ<}G&*mi* z8V29+n^PW4a67f!)Kk?9Y!W0*c4^L^^5!6wKx;i~hawVTCRI8Lf6$TWk4bnHfgnKK zo%!}Bxn1rhyF>zJcGbW7HmgklcY?iVC>^^E^`Owd*a81Vy+iB*(cEt`uv%~(@Fw@$ zI(PnIzN+URhNyN|2(0POEO>$tO2z@??x#D9rM*z)wilFgwn4EhZ}Q1C-fZJq0}jZ~ z*yp<@>x@*_)Pv2>*I8&sPdfmOXZB^r3+dDnCTLA!# z#nRvTLsfBH&yQYwi>ELJFM|;s*1XAc*0jB@)@fW1TkHg{z%e)QH8HPCT7$|rPz)&8 zRbC}h<~BAm%eNt9Kcj$sc)6P^|Flcu@BMtfKOkF_z<%m@XDQSXvRtwDZ&xQL_~mk9 zTUyfgkl@T#^me$DN|1PkEM&N|B~|%AlEAIq9+lX)Jgo}=q+VUCqBtD(23DFKi~&<2 zV4$URc>@8Gq{Cbug0=JbTiS^UR>&4DFllP4(JBUS%-sXRDT8LWUvwK3Me%#&7Z?)q zHYPC|lSvcTVEzoYU2a_s+S7P~lR(T3%x$f?JciC((G)w6M=39A(#f~aMjNcEVM@x* zX7t8TP>lI`;+lW!XZRoeMm{kzePDDMn^Kg#M~XX%y#dnkN!-T)e`8Z>wL)VUi3z0U z_AC12(gmnd3!>)ucN{4SmeW^0^yIb4lr9dfIAxtn_Rp(oJ7PAKz(1-~UiY_zNze|~ zOXrQ$^dC)*(r|S?G^h^OMEGm)`rnGY52PVmbig^SR z1MZsRuSa)3HnDu8JvK|Ult()uy}!{XG)4v0;QMojuw`YbeC+v6rPe4u_+LDo((#Qdgl%wu)M9LeaUq%~diE|V>< z?z#A|}kUB#kvcU78mKzFJxQythBtSGhsFUX>;Bpe&r^+_^(C)XK2= zUNtuKu=gz$>qfrN?R1d_Um-#2AJratRXOSb8wl==s?@Ty19*qA*DNrc^$50~ zycljD4AqfS?*<<%ahlt;aNMd+>X*e9W+`cpQ-|9nIw2f(n*P)bZbzi282uHL@oygw zVqfbNzD775a?JP+EKlK_UqR$hRLGu5Fuhnlu3N~LzFTm@Z8f2Sb&;X+Px!`WGFm@b zXtd7Q-7%6+47vK61H8n%ylZ#I{cEUt?3?G*QWKZ4*)f|bms2xy@x2yZVa%WIyB{MF zh-jV}UP^oj{^`SU4CyY!k8(J#`k?Ec(erStnjJdybp$UgG1qEv*L+M)jnBXUYe5bK zqZ5_Wv|>bUQmSnR;TCTC&hyz#`)7xm0820;lxN$@Uf0Kw-H17tT7za6A53ZN{ac4- z_Pz+=3Rbn&%-~xhf(h9NYFZ}4f3|pUQIQW(KyY26!H5Z7>pZHYv&!y}jP!EJuHTT+ z!m>`_M5G}7YC`4O8v_!Y zLK)Fq;0rLto!p&UFDGd37)i*~RHt%jriXm4W6)5ff9|+;GBid5NBq6+;QwhBvi2bv z^@#A;H6A=K@zL753_l1FWq@2=G4wS@i#D)g6dsslw<~l^slgXs(*nhA1QEbDibG3cvWaL58878$+Pd zlOctP6Vrf(+gk3L_cwbhFGY*ivG77yhAf76lYR-&c@fgJ-ZSGG?|^D7k@g$jU)}1i z+2MueuxIWqe8u*G`iBo{6rVc;3Wj5n3Av{O(o92d{>#~;(dG6yWgu}>LKkls6|?U^ zFYRN8qLi4Qwd)q9_NRutE!1KABE|v96_H8Ch4pxX5A*EQ;`R+uzkc$ndi(c+0ho3U7xqVI1@mT6Rdnk07V*1+!HD%~w*Tyqn3#ri&)n#xn!4!wT64Jfm0V~2 zO`v#~4+XW!Z>Wz1OTUx^{o?H$f`4bf5I`}U#$eWB9Ib>qU8x79aO zfQI((zVwzUCrY6h&t^V%KDErOyH)la&uJ<{zYU!$fKlltR81pEblGAq@PCf-q2Nd^ z)P)_%D6{*NKbrdvTI|%kU$WQBqrm!HIv&04s-PBB|1WLK|Npl>U6>@U)r$4a;zxge zS6O*&aX3B4$c>5%yo0(Y@e?3a?IsCK!|ofDXJYuW79WilhX{dH?m~)tIsww5dR|=+ zqoY&~9*;^v`-xgyQrGPMhzG^k{tR#L`438<>J(++8zkdPb7-X+1;Qty_&xPX$sGE# z`5^L-GHHJJ#b}WX>5ZibR3*L~&*PycdTW6n1%9I6AfrWyjHXJC!iq{b-pL);=C{d% zYx2{mEB*?j`gb2m0|A6)+D31BO2aO#@gzID?fPoQs74eFdk9 z7X`PC4%9=%)a>~Ld1=saf_+BQ-@F?ASMe_-z*znEOWYW=cyx{aJnAl(qU)i#@m9nT z!EH1`{WZPN%iKhJcIMq{BP^#sHseB6E4FH3g8;!Ox}u& zzg^?N#aaYHGk$}@)o+VdRdV?2x%ed+N!BH3k?~f7MI7Ht!so{ol{k3`%`c_ zM)in9#?@5kl20|tx`vfsB>5$lU(|h5{NHc$AHJ>M&`F;J=V_W$`T+T-}t z8MUzzg(2G0_ypz)D}|I$QAU@qyhrDG9SUbw|4jD>MG@6q;o$k1py- zEJvq~l%$g5V}TWf&f+d-XVzwXQtNWi3Ktc+KBy>N8{}XRWd8yAN|s)&+q>Y@ZR=zZTtA`CFTn&b zmy_adiuIde=Lsq0;*zvQH_XDvxt5R3s!=J=KIhfzDjm&N0F>jk*c$m(arK$^hkSn} zllu3)j;N0xmZ;x-gCt)dgZ*s05Nl)!F-1j&YL1}DP?sV@Vvy*cvNN3oF~`W*yl;{3 z@|_>sl?!wHupCt;B_R~BFzV`xnS^&4ahHmOdzrv*-f>F`=+ZdLBQaS|nuwbjH@_F` z?h5&7HI1UYO*s_xsWNKzcAd1GHc>*jG)yljBEDwOBUOts!%VqaI$kV!Zh67__H(@Z zzV(p%^^}NuXMwQAW8&a}czu3`-;FzoZ;*6(jlOhkdD)+h55;HGFRV@9s@>Hsre&Sf zg@S%ooCTKd$NbGk3*R?{CvKkVR*F0-qYDT;Dbqig$UgjPby&YwEX+zBtr99YkmDW) zc~nOijk&0$N@YxsmtQuH9KGbVSDg<}gkvcxN`AeavrS4PUyT&o0n(Hr&4Iu!XH@jJ zUo1PN`5vmoM{0OlzEr@V9bU%rSY;agBF$C0T?}~~j%*PTsiKCqmIiIDEWD%YtDRLzqq*%;sTCh# zczg|#{Xa&DgqpH0GHoZ@@7?}fU)Oj!#afkEDuYC&9*V(+-9J5zE^MB!TBhM@Q>O}A zFz?61EsaMnC@~0GCD(m-S=_&sw*yP3ps#*7f6?bqx|^+uwTKw`eDr1U*#|VZ`f{=L zXFx=I+J^+=BI39q;+Uk_4fAiUu^wQH@->6UR)3;t1<>e`u2D)`s*25a`A%UMqYuat zQ-_L$he^^X8BLYA36(%2%(i4_L_z6?&eTex)iEtKb_+2c^$Pb3901sXb*Ru5<`m4D zfk8=tFPMTv*(@5nt-A=}G^b%Eiqj`FK{(&y4!fA^L=9(Uj?_5*S>=BQfCccCwc-2d5%&V?2;ByNrB3cq8&U)tyw$`{*eS4%3g? zyFD?6@0NR)ONaejA-8>YD90e-@E)F(Gt(7p*(AhHUoE7t2n zYpvV9;qE_Ju})3Rv+m`hCSsK*-HkuhcCVUQnW6mC^xH7`b}nd#W@w0vCZlMkJ;cr3 z+-6|)TRkSv1owE`p`q_Y zPyUjZ@sx{P^Jl9GWZq+qlZSH6Svv2>+3y@Xmt?y>h9XTB6r(5#2Nju~Nu+JXMPWl- z`tdd9p5ZfaEbt}rdvM@Tz&l@aIP-pYuxiy8i%_Fz?J10bTt18&kwZQK2kiT;S3 zMdX%hwI&gOJ3bjI`#vP;D?-gp6z z>}bElH9O3vARDrYI*aPEyTL(-Xc0FzDcsEG;HzZEETP-9Y)hXW;r7<9#xQr2(0*mJ zoHey51C4oj>o6MSAuyK?L1h;eJXdO6Un<2~PGy72^+t{#27-K^ZU90DEe$=?E`(&X|Zr`Q3T0-e& zv&Z7LzkXbHmfXo0OOjh+6wIyISr+>)>?0RGm_<#LgQnHS-aq3pl&VQbR*-e2wm7mDvuD>@Di4mDa*Z@ZCT_;7KT$Uc7A zl$@{u+zA}n3i0OW-mAi;7XmI$R9`_Il0}u3l~^HwE8#W*AQd+>n#kg>SiG2i*v z&+@v2v>y0hzPSAmP-;GHJLfAt)TC_uv(9BDyXIzJ?uJr)TIiQ0gDND9QXfsvujKE> zDOp~QYg00d=0zMQUjf8p1{l$N#^CIjum?Hu+yw`UR}Xh>#(x{4h|QM>qy$0Qa`k&T zwdr(Pv)oFLD~^+SYmuWlAJN9o7JK?{`|WDYao&zzQ+j>d{`oxAgqV}^;!nF%YZ{qI zLRPv{+{sX1A-hs9)UceJ88%Rp>8~}nv1jsktlg@1(R}!}Uo{%sqD$t5>5veSQn1|^ zA%=ZF322`mu7_vn)&K0J+J4|_lS*RZS1H#p7Kk-6%(A-}q=Np*iJ6*`vIE${0!;9Y zbc)PZ=lXmY6}@+s?ts9^crb?I;#Io>;Y{Dfx@j(>kum-KIFk#N2wC>1(WW+{LMjvb8t|IVB}0KYWf*p0X|t zYp9Y~YM5@86JHcr0I7uryY7+c8jUp3izF^vMPd=n(Py9N52T;3qQgv-+_D`)igtuG zl*Fc2ax!#x#LZ{qgr6y;5*ECl)pBTjihV)^JSb4X5V>1;7+pejh1^r3_~h}w_?)%} zKaoxq8AR*_gdtu18U3vhT5lbf->6Nw&CrGecj_KsZsK}9s64pTj)*hGe-dLg1JQ$) zc{jr3b{HK$RbY@ipP@tl=_ir7HnAH29d4dHn#GP7##r0cfdqzbSz_u}15m;N@4 zwB9JlUTA5lIG5!8(u!w1i>fScv5?76gNc)^qfflHXn+1QLsrMrJ>HGNHzIc&n-=-< z>2VXIMsG|+y_oF*fi97Gd3H$u=xyP8)|El3z@C$(Ok$lV1*_sTyW)<=!{!!Jz|=_kxF*v7<%v%`(q zGR3E;POuICo!zHBv+LCaE+Qi0by$43&g;?R1K7w*0AxcGeILL>c&3cEp#qq`172p@ zG_8m+^2pk zE^Hk*Gp8ipR+brNP}f;-@x_SYh+d>Wp*R9^hT3>QGq0drn9chs<8#}+-xUEHfBUeR zr*XKrhSIq{q4vgMFIpv^^}E4v`VT63>v`$<>hmi~jY_%Xhib~RLdVKIxef{aoVRf~ zloBb(HYRJD8SKc|JUf>et`y7U(B3wAQfsq{lB8+UEQcM5qqkbV$|X$OyZtIdu}8DN z@>SMp!@s@&ts4Ca!dR)K^iewG7Gm4pQH#vuo)KDcmZyWK=9E{Jx1Ee?r^&rZ^Zxv$ zwBF`Xl%S*Ud~5BIQqd<;>N$H)whBw}v1*{d;IbPQP_LeV%M9Sbn`>BDaI>|Is{LaM zjl-40Jx90%myTuliK1*ae-#OvTu`*|gNRn@@aE`lmtpYmbEmGEvV)E|MjLuE;Vd(&yK>-{DY$m>& zB}>L+cG+C%IAVVCi>J%+<4-$HQh@!Ag@wh3h7U-ek=ul3&AaQ&r$02H5yE)9njXRG z5O4WzP^F3d#5ac^g3-BIagfy%Y(n~p(gEWc^=fi3oXFUCkpLC}fJ3{4roJuMA{+7? z9j*7k16bp>J}zNw7^@VCOBL@g3OB<59)O5s2x&x%>``{u3S}nN`VBz7pENzQ zwp5W&*CkMqr?;kI3$?9Kbz#805IYreB)l^Q-CM%+Y6C|h?O{|L0441Th|elTE3Yr_&7(i$Z&M7cDGT_jfMS*s|#h;8P?v)#B)VKp@g3 z6V2q9>&D@J*zZ+gcXW(D@d(&wDXVnXwLc8~nn>Qu@b&Z)ALaR+YA&+htgi z**1)yTa8P#QkoY*_55>lUKUoouiaX4eO7E4nnXGACKVQKMr{ynn<(L5X*B-# z1>y>@JU{i96A=Try-dMx)61^_dbxDa=Ni*mocDZBZzuZ!8n@99`nj87P(`{*=k=WC zR1S*Z#%g|Tl|VW!oRi&}0rJ*IZ2=D_r+PP^d!V;9p2`zHY{5Z;acEe!`5GY;^FVf0 z_s(73cwe^2W741*9d#g)uX~5eE&*aOEKHSVDBro2dwG;xLpdpjB*frIQg|Dq7v-lI z)Wq8Ubd02_-=^ilMx7s>t~G%NL6HV^zuUmMR)NE+rb#GvZ19TndHKY?~5` zJOyEf2>Sygi^Klg!)RvxtC-{3aMjc)~U0z zQprJ@3jIvcqcmQ{EF_3?sG;nV_W`R$8(0g)u+S2N0tH5!9t18#uKQTb=Q{v-45fsyaTnYVTlgHz5O(7CoO>s~sr7A$^_n-o zo@-#IQ4r0RHswhR-uD=FMSVzioiE#qqM<=2kU0 zn=T?HuDiaeSQ-QYtjUm!<@EL(+nt32QSzrcTF&V_Vm570+Hm`j<6n@ydxqLRsg$_I zhF`z=a~6zJk>j0wn-f;vm-Jx?wA3 zza8oV%UVH}&Nzn@tyr#;MhBa;NSm~zzz3ZqXH5r{MkiGC3Z@&qeF^LEf4l(b=Vg*; z$T}V*&2@mB(C6T!#3a}JFxVm5*Nn^4F`D9{pnfeN}4Ba8=I7M#PG@+m)Nmcy*wa?iE z{WP)F+h?xJc>u>AmyNRhHp)f*!6KW(-g6GJhPxJFxJi`+v^)dP=3{YjNi<3B+qaTjBch;hNTnnnik z!Vc|>QE`YbpgRBeg(2E=eIn<1N;}8b|DRepu~!LAxJW zLW{9-KxCyxvj*Q8gxIXjSV3|N&K(|Qs$Ut5TXeKMOx;v}A6e-%{H=|F%NMX+9ReIx zt+Rt(ja6e94gf`5+}@sv@2c1H1BUS<;7c>ZM^a8nPF?SUwBikyVDb~^EsB9kvg+af$6*FrarJQy|a7Ypna@mp6HaiPyMvO>b-I#I;h5hW5* zeYJ=)!QkRA(3r?xu*2rltcF7{H}6)%X-p=Nv|Gub ze!mI z`v}hLk2l(Cgji$L>Cf_Lmeb0T-q)YE75qQ&y*EWk#bl|hJ-uMTs9fmHE-Y-OZZE`~ zXHW9amqez_m%KllbgT8HcU_})qJgSZs0_XNJ2;wz!bDIE%~7#b36PRu zsG)qTIhj5pPEe?Uw+RIiH806{`7i0J`RjQE`8U&8V&8peQ0us}GYm+NqVw^cS=Zpm z>C4?6E{q6ighG`C`*OC>(iL?96}*4aS6mA*f0RS1qg4SY>T>(|i7Z*Az%NJ5P@MR8 zDWQknmZqyz(WZasFm|nvxc3N(*Q+HdzEC1`<{_FmR#2wrYC&=CYV>Kf zd_af}a2uLwfOT^eQY{3L(Znjwl>0>$8XmD%33PA%RAHQzlPz)a>7&vvIW#QEb(9|D zbY*ZmJ)GSG85ajJSgge9@V&(kB!_WA=7c3QP@%W^97#uTVpOfY%=lbhU)E-5mX)a+>PJcz;$s{>Sv3tLvm>==x7O4|lRS zMId<|io1Z19MoGlVZJawzjm!^k4l~PtlJ~QUcWGJMu;%1VwDml;gY%u*gRy^DY5aZ z>6@3%b57HAj!zu1QY@cfL(e5{)BzIg(#xq6qFcuEg_q#nDRthg+Av?9?;b0%=kNKRqhw9iivdBm=y>_xr+Dxcg*GyeN zEST=XJn0!^Ktvg)EyHuaQ_eXFBq+@Wn!5ufbrL0rXup}Vz?(X{1UL|+Q@=D}r$z{pKTF%lmzS0Nf$9X^wT@3CL%?(wIO8N&HTN$&Z4yUFm_oArN7oh;w~^ zlH`R@MyfC1U+T+YSMs5w$r`{n_}jftpo^N%`Y|Djyt9MCLXFx7*PYB-xz$f?eOR?* zFxZrj#brY#G$e(M>oJey0f2hwnuL>K7-q+hXyW4w3r;h<5<5h`XPZPWL>tPy7q z`m10OW6-etIj%L=_YW7@+84$9#ICSfAw;^J^c+wO-c45a;&Gr3$JF8ydi?f4xuaox zN89H82jiO^PfN+sY+JtrGWit4MZbordS4p&xi$ppK?O1DFsTRBwa{+t%p*Lsh2?j( zsb3OgOA}q1!FMgzgV5pg4Q2e+!hDcI|LNsS=j+IM8i400%>jUz(2n1N!~kM?Ea1tx zDiVP^TUo8CshOVoVIJTwk9bA&j-eOap-1*x_k^JI$qA!B!Q-&>=pL~a!i@o!hO}*X z0xQ=@DIgKp(eS*Lku;UOWo`GGb0QV&2gzvL9h^gP9m(hXjH>C;8#p&vvlindoxppm zslsl|7C?h+#+NK$h;4gv2!)7LGvw zL+!6gC`9^fhm=8eDo9pV^lqsy1Ad8r5LHvs@`-~6<%@5Zv@{>*iIxu(JM`{_2zKaU z#&-60IX|EzeW6U3s!{*)t1K<}*jzGVxj!eAfnVZJh{~CCwD@UMQ@!=j;*oK>2+2@V zJ5BJ#Z?ZDA6&v+{IelCXL`3%G=$G&JF@6hBFfy*=YN_sW?*!gCtsWb?lm`LhExcxS ztmL(V^xK}Gm<8i;^Lpo=!Cb5Ewd({iCyrXJ3)^wh9+b1Umq<#uWp0J|6MC2XHs6M| zI6G$%Jst0IOTn=skAxpV2@cuF(0n-Bz2d%QUr1ltm zue20#c|Fya7OD-)TUw5_DFQ#gTEkijzJ*PfbEjnFR0otorb)Pv8zz`|T@8@<7wwm4m8$w9*v4?A^dIkt^Z%m#lys?k9O3jF8};SzWUf(oQTfsy9SY@LshU3tR~+e3c%Bj3tXs| zRiaMU2`Tn<6egL0^(Ro1@WQCsP{$oAIQa7FLoKo;@PnwGr!-ksT z9$`&6NdzX(yp~4y*D<0_^)Cg|$5p%^o%OqQu!}ycU7mS@@e8ZZUX9QMTD4Oo)a9^qHLyGr}?A+?jxVv47M#U1pl&oINkRi zKcNqs!Bb<=`5l~rFamO8%-@k!KlqCC#Q3O@TPz|Bm+eNc^S8bs5l1IQgHitI9C~u= zjK}f_5739jO!AX-&>hdS=h1q$FCroH(R7%E z4mI5vqN%-(`@u9^){lN39ICXU#|rfuejYu`)=ROrp4Yj(7g>S2sJP)u@WA`3kRCBO z86*|VZ^v@`QZEx%1!EB1TB*6GrHXA+Z0f$X#(FbwYTI;l)UtpXh{gT*aOwE9S0E7G z5yLaS-bN^`*|bH7H6PBC&M_ep>5O~&6B2q4F8A@H2anq2+)V#z6q@M5wo9eGWZU*p zzTI4L%_N!yo8~u7hq=HogC^nvSdaO|9?v5-%lXVOj&uB7A@*h~vtg|I<#n&l6&WrU z2Vt6C1{dAdHuMIIb&d!X?fL7>Qqb0HriY>~3i8|k^zsE!Fqu!0Tbdnk3%m`)2Rc%F z2*jXAeFGTc%mZ+@P-6ly4A`p)d6y(!V(~Q)AXRw;=OX0!AWpyqyJbX4Vr|v5>u=q?FE0s&s=iY&u0sI;6Y1_NF_e zySuy3&CGe9IUml9&%^M6VeVmueg9*vYpr$tkOBtT@EbYGEY;+76r9wW(Tj8tgAr{9 z`ubUhY`qJ5r^mtSiwRae=O z(_dLX_Ao{>?g0Lys0|a{`Vc_qq`(`L5Bozx zsOs~=H8;*TSzWsnSbprpEfaGg&=B4^LrFk}RA1V<%QBwP!|XtI{>`U$vGOHl)o~P+ za%6*V;@KJ;gB%v_B?|aY1qtbQ%CN2)-+dNG#r6#52Q_2Bm8Hl6QrUJyY^3^Ga$=wO8VuFjcZQqHt!dao;eZ5+s~PgBRIN7ezIGLxkG82RHL?1aHnp zcsxEP7wJrILtiS)eFle{A6_+`llHqr2-=0RwhE7s1c?7KYp!WEf&Vt`^~RhSj;_3j zO=5M=8h>!v{BAa_82H!)md|l>R@f^W@RMztm(bfue4n+)YPtuxoUep&d+rr;SKEB* zG$H3DTMkp67)hw%jje7dRkmX3xFiZXU<+t2x)mix{uP(_h4P0)Jm7^k~@jKYQ^g;cu zEWZp&QoZS6@#yq1wW|2)K%m)Hf^@;Q{VY9jNzog^$&AP-12QGNgKKV38XWt|2Lwkh zhjIWyl=oNU8L>NvESlPhYK)xbPI79^MGQI%+9ffXQ8{s;T@Tkp^^dagaM4n0%3{h} z{oI=o)uzMQBIEUvLRS92QPU>qgb(w3QxR~PY^vdDlX&;N(#7RZY%Bv7EiUt0t>Vk5 z5g$>J1)jo?uyFF(Uso6rLJpPlu5jDQWCS7#5loVlO1Q$yZxIV44Sv6^w3rq*hu^4i< znW>ylnNVsc(h|oV4&@r9`UCu3<7qj4Y$`;;F=jj7y3ElpVYE?>6Q=ajxyL%3_|ujg zE-IP*mtu5KhhqsQ&yz6%m|EL!I&Dwhv5Kod`3 zX=g#gCh_Nm;m5*fU~UYEEUSe#x#(a&R7<+6*lfn`9((oKJ85ddEf#(&jK_EX3S@jaL`f%m|s+UWg!79K^p}jeLK5RdZ3@gYx#>*5_+e_wZ z2oKipSTM$>T|+#oZm*17mQRV??F)}FOsc$p`uP2aT(y+R+bJj;ofAGK^0zbMALmt5 zTOQuEItMzuuM=L|sj)E^Rn2lM-7K<_n?lk{H0esN3cw_p=*V$nRpI6|49t(XyR@G* zT-l(G=$*Z&aqHi9opNpAoA&#Z|CZ3@&{Oi4R$s0#uU?=2X?`XBc#sz;@SorBtPpw3 zrV#yFK-twa@!>rCXiNxxI1UIOX%v69CUE&5~HmW?oS!1+_sGG$Um_6 zb%7VQM*52Go6T4?$Mv@nlXQ73O6yl22fjz#c}d}^u$@JYjlJ6wpGIFN_|{L1Jqlib z#ghC;%N~;R~uqsA)&!yp}9Ow&{25%>CcG9vx zdrp}6BXqnqs<*Bu?L7P=H3b5>vMTHLyS_n}4Q%dTG>@FFq(YR&*Rd%4K!+=nO? zsmtW&FNIp&3ndscC0}ny(!3yF$f+^Lx@aWxJl`d+{$|ms$zxKKEpi}E8YW(wyU_lz zsmOt9hqqA1*KQ`^n2gCjeab&Q_9g*2QB7|$-SNLUoq=ZrW4***?yD~(Sb$NDa7-AV zKmUNcg15zzq)vzCCkqN7@~1%qUX2VQ{H3vKv;J}d9k}7I`dh3v8MBaa@`vYqS&Dn& zDj1~VJ}WHZOZCdR-i%q`Ud9H<&vlA=jN>`n;h{CwRNtdN&4c+74~&v8xFcuYJ+oVK zEn4kp(JDQ_EC^mMP*pSh?fHciU*qKcMerr&ppIKpV4Cxk+vMH zoH%{xER}#$Sub-=V+|4Cb&c{q~s z9Wc{6l-~buQue2l4a2)Qo?OsGWPk?2SKJF0j`)R*I!Q?!`k4L|@$j6Q0g_82Q1vP) zlr9u$;|s(f+<~B=D)}<{!h(tWJkbl+|wO8)w{7Io?w8s`({Lgl9bEwLtB~r zR(^r`>8LTt@XZ$W^VStKBZEojKaAR|{QiMYLos4Z^G++!2nIzDlhK)G2>o=dajSaNWivYqw)LiMBSCZQGA| z#;x{-L1|@Tp3Zb?C#Ja?Qu+TXr1^h0R%s$Qa>wEi)@%Nk2L@pYVam&F%J z`jQWv9=%igzOwTbwWMG?rtmO(KXp6q1W8xz2*yOLg8`{r#;boTkpDSd8Ze)u>N+M$ zUzfPk+RLC)KT8L-XJD-2Ibpp%c3Xly@Nt4(QKN2sh$_2G>BD}oUk15UP!u#q-EZ#j z3GGLvijA;XFGl(Z4yn2?qu(QL3&;1JUTRA0MEPzZ7Bh3`FonIlj2WDyC=GLR8#=Kd z#rzqxw1>cnj`$kB;F^a-dl68Hlpar<36g*FrP+Gk1!Nij8NS+R1j7oE9>!jkIw6mZ z$mTG`SpGFdrxw}MI^xIVTl(JociYc*R@I+z|CvDk=K=3|zh|sW(USUc43QpZL=!jN z+_AE)F2)b{fg8W7(r;7upfpE(-d=Ri;W1=TdPZuw$WH=;`R^$}MDev9W{K91XI|cb zvoxcdcemdg+^f!a&ORLCj76?HKhSxLtB57po+lal5GSe7lUtsTErcILHbnn11koZo z5fC8*oor}^E34R5`FYYB8-7|#e7;8?zf#yc&U7+(m`Nx+u)(mF3$_s1@OzhN$g~*K zdL;UB13=kSO?mGzakX{C3(Cn5g?mcL(|@h-DTqJAqe;R!B!nbRG#UNwc&wa?JSI&3 zVUV6G@?TyMPvNmXFLkTa&PSTkKD@0Yr;_yoQWgqXP1EM_Q8QiJn_piMAt8n2286jv zj7DuZzPWU`Jz5U?VA(H|ns2wf0$*X5p(C<^bJEheG&yUtkD{@d_d_Vl^&f-@KfR(( z=z*)yRchaVC=fjY;?w*JulF+G!guZnPI1I0tLlGS)429^4OCPGcg_1SNe?Fo-c{nt z!1zt3waq+_RVR^Ex^)x+jo--Ie~z5f|H?N-Jb{@UM#}4R>(h>unL}k8wAwAkT+6?|CO%^BZ$+8n{a3>lg{AzU*_kCOfGz-?KrB8Xq$17&m$B~f6DiDC6%BROZ>r2 z3l)2F?Kpb|OJ()9mc*&8hknKLlj$GssVMxhCl_C4lx&FZz{;O*$ieW66WrSh_%9ON zl(gGg8wVqz+qp@Nuj&(k~mtl5IIsGqch`DnlpJ;bWg@qmujE+m29}AkkTB zG6%t+NpgE@^_y{p#>U+`qo?BeLuY3E3zx1H2G$w~(wtd;c~GN;^A2yrp4~X?e^?S} zxZa-0k?-qxpphEJkWEs;Y+m(v4QzNQ4n1)e@pv+nN>vS3wvG)cXRqw?4k5Zsi8mhNCA|xW| zr9UJT%m(toac)`qj&?#Mkf)gI<6rjnhniLwx|7!TX|C9?k!wF6;@Zx)a%J6x=&V>d z#IKdN`e3x-%{b}}?VPwsETAap3kPuTDR z2gt#2SEE8B_*DRKW%x+#(u?155ctGr56t8mbm8O*-igm%U8ZWhjj)z7?9@8fm9Djx zJQDKmhuX#pCFv~n`zXJG-Uiz#%TVDfGG8FW5Zc7(#JMrZJ`)QBqKZYZpxAtQ@DtVG znK#Mf6EecJ{?a2^cpN!a^t~Gt8cwow<&)yK@7vVAzgEdc)}Bo8S|U(GIS9%<$Umey zcY;f%PNf|5hc%#9=J&N{wf-U=>sR8C;g9zA>D_+b@wF7Sy{%>bE5DzaEeT6f2ck0d zu3&tn9D>&&@8(1@Ah&(OxO^#o2Afa;o&NcsE-XCn`Hx4qj)kRn{+p~*S3XGF4(^`v z_zfJ_ji%E&dk;7!JmObghA)x?A~W(Jgyi+99WO6yKAguNggNkRA+B)AS7)cMvdlMk zM`dDFe+T`{bq*506Wb&Z(Z1X!(~JVQEJ0QS)pgorkoLEt4U|C1TQRuaTXfJ!OoE8q7qS)Dy{`T8&3Kpjocnc;2%T=FT+p8=MH^F6|v@1aGI?E!Yki) z4q5wRZ*>O0Y#swj*}=z#ET#t;CxfD#I973~e~F;~xx=30Or4|d-T1`0HLOn#NU6s& zP}ypHcBc9A{HViI$>E*GJ4DamlV>0dMaOj0slff=$P9!Hx#s>x zA2RXh%fC58RVemXF#UF2D%&bpuJV@(ewtPHm*=FJ^k|X2jDLHhh9o0Pe#aDogbGsT zBgT6DIXF)djYB@J3!OdYf|MRaRhaktT&Az-;*W7D)QF{266;)+qPqJJEo&jgvN$OL z52uc)?L@PEaZ&26tZY?bRd+MEgX~H~mOj5!b&mWmn^J$=A3ThSQI323-F8j8K8jNH zdvHPOJ!gy1`oDMTf6CaUTHq;TBzDM;qV+}R;gj7|{{|$9VP^ug;4kFSsr5(Pxfd`* z?aXJLRW=bLap<mCdWrVKc@woS`#X!v((eiTr99#nm%f^G|I4aO z2JPAU5TWVVGCv}xqf4L?s375|Dk>`C=hlAKJKLJ~EAJ zbVnsjZ*745*G0+qkaP_v-(+CbI@M(~BMe2|t^XLenJ>lnsBIHH=hs^aJSk=Q6&#v1 z#ZY->5KgqOtZXPGn8w;|+q@!{$g=!`$kI=a{`-JgYR%tBcNU&)Pzd!OCB*d5tp!-p z0qZs3`3gGWXc_r#YcVKHA6jXs94u4M6UVMpx)MdCL7?zkD$O}aa%=+UTZJ}m6xkqN zM?H0akO5`KFmfk5C>7CL9s?m|f`G7fnvSBxponfs*RT!?pA+l0{+bKq87)a-SlfK} zp|uBj(>l{8CRh1?3QN6Pi)o!vkHkGYgk$yYLE6d9A4Au9g-pwSN~;_62Z5;+ zlhWQQBIe$v`6~EOhb~>gPg_yNk61DrK_oI*E@a_M*Qynm=<1c`?lE+lGezz_`x6|` zsdHD{*f>G*;Ma`Ye+zA*kj(TXYpFuJz~ZtG-=;sM)~E(57}$SVe$OOw3C_nYu@dvj zSSgBeRM}RQ09mhCTlG}4be1a@xA&XF^0#)*dhDX7j90AHmo&=|!}yK11BK3ux$lj{%0XD{I7D6FP935ND@lnMMV{(} z=8Nu^RY0?Pd1VE~d29+C7^r0V)uaCT^RMyo@pIQ8a&q!&lYy5Z9R@s(ds7w^B`xkr*H?=0 z&r#$96m>70dWq!Z`q2Z}x!5aD_=g(5c=2Oj9J_Qp5W~+m)erQM9$+@FYIekATdrss zJla&Up3}S&Q%1yMy9T}0K3Hy@Msz`xXT^uM*IF&b!ccHzzGxY2@dbX)hzxv}t(;t` z-(g5-AIH-bSc$s~hcMgsegYx?+iEOe!YIZjgk!a;$|+r(^h3g%88$@=cdT z)*?2QHjd{^q)i6KzCI!(nanIN;l2YSX`n^FF5?7(mDmi7K#MfZ^!Hu1tg*Tmxf)R! zGY^mCi{H}VDVS8s35ps+5A?G^xtROR1v7Lj$HQ*DeLVFCF^4OFzWlH z$hPI2;6GHlj7fxj9YnWClbAV3j6y7LFC7Z4mxI(Nxzh?*-*$eHA4Z_|{#=AVBlhz1 z1jVThYR7}$bl-akBzwY#aytshXMso#q-~Qvw)%w=Oa*m=mEVLiFd50bRK!+MuicN& zOz|0YPQamS21>GZ>LM6m{4UxwvyT{$3~s)Dt`wF%eoiYI@2H{*%LijkK(Y@eWlf^$ zAT#LEyXP?4@lau4=BaiXw~t7@xEdMaUmlCG66;UwN0XS6cLa5va1@OY^Y*1KM7yO< zeD@(UywHJXA9DUHJV2lB;7%t4Wb;=hF=2g303His;>iPLNrxF`J zVVLAtJSuIR-G1Xff%Lt%{vR2zQAl!5x0|72!neI@%?6%#tCaI((iAR#08oaV;zr-P z?FG=^-B5;lwJKAf!pA7w60ReD6=W8oab(E58tgMM-H*l{qt5b3 zpYdz)H}zdr1xI9Ugw)htf{@T4Xklno&HYJnw|t(%jl*x)?=dpsDp&>12F`6OtPL9` z7*aI^DrN+9>qcnIHnpBSelLWu1{q}fmZo39D)E94!AVB`@|>jnJ+K&bYIAS+N0nYc zC>r@rpZc7a07|gJ<-hbwWBx0A!)-hv^(uY3SFKPuwg$g5*vP=zlxg!1{`_+d+0v|R6Q zg~$;YcXPT8$8J~7mQVf;V5p0PPy4wp{Mg+fRQ`bANY1ZT62jO}D(Jxryuj%6&r1K+ zc=cV6O=LmBzqB6IpusM~O?S*hIniWlN6MvCADEhZ0{Fc5lfWH|*huIdUqs%g=T9{! zN=U2S`q=t!`W@eEdw7H^>9U1R-!e#VzbqP_9EXHKs^>@1Jy`g`16d7>-a;C z!vv28JQvQ&b08Tq@z+41tqm#VZD~%Kwh)B;)Wfv;TTs@D4I+zpXciv=+b55LjsPk$ zy!r2pi{7JjP*Sc|-`8#X8D%C=V5A-Z zEqCmpi&H1NEae)#I$qrm5QVDCe9OTdwwrqMP-nMUkBo28MAE^grF-A14LGCQg>{90 z5VS2WnvZBE)uR2g`|s#_SkOE9l(4?$d`*-3;Yt);Gp?R+JtOL*e2lFWi5sIok_hpY zpIwPNWU#$iS6?}|mBA2;;P#Zpo=1048Moq!-+gh#+A{DYB4zc`{BWX+Kls$5S_C6j z@0{v@bj3f9=-rf}nn+`>I~_Pk!~C3ULN}(A<7avP1|d4pq8Vh&J2to2Hk=W|3{g0U z?g+dBB!jQSUl`9OLi}*62EY8>(Y;SJW=J*&8bJ{=imEUtmflK-O09xp(mW8uF(%;8 z#651$99)`p5CwkQzcq9CiKq%kY{P_MQ>#beO)x zR~M0wKQztCaqdBiy*iw_qymc<3d^}Wpi z4Q95{<#Z1i0IdWl0>%MFVt7HV#qYf=rR0DkaCSVl_&oTZg-zgrR(aae)k4Z@+Yrc) zCZN$|G)Skh6zY8t>g?m*U7Qn8$|*rbsyiD)Kv{>M4I_GGkHHRn_r&7b^4e) zoKMQ2{(Vl1%8}C-g09?t^1IOD#}2Nn6HCCo(&%?}OzHS%)PXc&6Sfc(7@}CD4}Wlk zYlCfWLMcDT+rPY=p^05&k=w05k(Ofxw2JnRDb*{BkfKN{2KitN>vpkZ!g!E~iwvWH z0^3C9R#u3y$$)I(`L!7fYFC`LMO9UCg6Twc#;_%d`y2c|(Z_3rg1o%4F$K|i;IkCs z<$}MoU|qN6Z+N)b)v1jJXcDB@7monn)*OIK?oK4rBybJ#!P#n`t&|$vTzWn_sde1| zk;(P<2B7my$K48|Tn@tPP<)LsRu24PHpTT|8}`b5m2|NbFsqL1+}3bjyj|GrbO&H^ zg>`k)#IV)MG5HFhcWs8Vi_B2(x>rrxeaPb>>3~=Cx<_HJ>Cn9dnA{!kb6>f)W}QtW zWYhlogxlWRxAJVz>Kc)zv`D?*Gu;QqBo29u=zoGA$>(L6kb;Ev5&_^D^R;cV@fLhQr`B`vEUGh@)JgQ}ii z46}j@$5^)$HOzS1Ixui9tDP&uRvQ~EIm#zb(tA|5GEmu-N90#BC5WJW& z3>&%z#(IjK7u~Ndg^pTZI9^PfHY_sw8?7Af>Nw4-*fgfZ+*zz2qFpQee$ycwQq#0= z;Rwt|lX{}R&Ps9J0GMn}xA$qjSmglTqiYaAVmEB2xbp1QH@O;Dcz>b(cd^L*71&!5 zdbscO9c@-k^T$I8Yk%uEI9>0jS{4RDCg$5L#}=$GFT7X|(-rdTdIQWiivirt+Ixx# z1sozi(`o+29DchVbRHMQRp&+bv8Jm(>W9EGJnG+P0$7zRPylDWN+1*AeGJ5*b=(oS z5pZcXtg@&*ejB2~z%m+D)qj;YVcmaOl;2wcbw(OwJo}6a7GazzYvU2JFI%4!F+8R+ z(SV8vBf5ly$A7O1aGzI}pl`*Y_sT`=#eL;3v4V_F^&?0sJ$gDE|BW`TNdQlWkI=>{ zGDMw5)xNkoEaJZVgqgzc6|$YJNUp9=r?7cF3>D`?mF~dopNJaqMNYiHNncL!N z%Hi-%?;-5xZQnBr|t90S>z z<;F~zQ4j7V>?$uO#n#>Jib3>Q2a+4f{P6HnL3M&2Kp{Awa|OOSs-O5-`zs;rY&x!! z4GYF@dG|pIZmEos$Lf%=zM&OTB7yjT$qdbjJ1C)$oeJ z!NGxIz_()>IOBPr&|16=s(C(UN6Voc3MyG62|@3*BF)6ThT6ST3)WYOO*Cwj7TF|9RcGn?iW5cKI*z>`q4 zt{R8yIo`~^iJ5eu3^T=Vz}Mttk8ZGa%4;ld++!>MTo%PY*{&2^$J}7!F73EeMpJ4n z*ZTh3ET}zSTJzk)v_2=^jO=?A*P!%N2IS!RiH*_q+dz@POg7W&o%aQa$GRcy1z=<* zXds=H3m+V6MyP(X{b*Vj7QzChp+g&&*=lE)i?fdMPQ-YDYQxA&fk==19Etg8I%X1?B$aN#1!#*|t zMsPCwQ(`DA1<*-IT}EU4T>aU%cXxK?xVD%|r)OZguKV1ZYZ7JXR*-&!x@CXp) zZ>D-KI4cgr7KJ??r?YF?O}k7Tmi>qXevZymne8tJP*&G8uCo@SlY8j89d{^S?oTsk z4Zi*_L?TCUtJY(3+}2){`}+4SEP;FOnoSKzsBq6rrJLR zgF0-wm-|x%IhnF;^I46a>88`BV(UwsdU&oXOk7bQ&MR`L8Ou4z>FlyVzgIBHH<7m1P8>^b@rD{ zc~F)fT{D9<8I4t@laOSfgg;iP`&tA#{Ri*JEXh}JXYwSM5MHFqk{Q;QN~*h)caMfexQwrJc~ncs93B(n0N z)8FZnyi&kx@Ah#80$zrrY-3K4`hCc;8T~oYe8z^3qub?AUkJI#nbr@;dQuVOkJ^X| zFp`(?;J71MKJwTPSRJ7 zvIckJSU;C27)tDKVit588#Lq-lu`2W)|u*p`I3VCy~mL+Wo_Nf4JR=6Fd2=2n!PZw z#YQOF9e61UM2X7W5{^n=+l9Lqq1DwqysCL(elUGEz1MOT8spU-CH&9km1}i_&lqi& z5ApFXI|Uc7oSAKiAho5B_~2A4fWUBeyvSZnya zF>e*8R-|5=ODj>4SJW0ig#~Pf*QBkEZsFQ?E?ckt5m)c`t0r~jbAek&K#bF3NY{q^ z{J)6NW@Ws12n6Z;w$Ecdu3w{1JuLuVk$nS4^oPbIUS96%4z|Y zbfUbcC$=^3jTzR>7}?_zqK7ne*?1UJGaI#c4rkW|sDIS;c7Oav3TiFN%Kw(3@_7&U z70YJI^9w~0gw}|bx*Cb>wJDvLWx28Q|lNPGT zERNpBjU*vyfI;*HoU4vSL(EsKuMaXE1vmb&p?-mblw?R{lFo&}OABWp*`WdFw{~`n ze?C(N2}v?xl^D7~)q_Llx^RbKMx$RBW2?{pzzZQQ=w%zPLpG*UJ(&{32J_O(gVe)R zuoJ&wc0KmzM_d@uvbgv;VPa2z8Qc{26c1)~wO`KEhsm5y*J{cUaM_+UQE z1Tg*dULmj--aBu?dqmF^e!*OFQaX1u>B{F z!(YdULlrUJ(Wm54TFG9w+|RbuiQxA-m&v-gqG85w^)KPU8GrKsaJyUFJIa z1}tLt8g9zKx-FyS4z~5vC!VThNqI3l48J;abqL7G1~NvdJ3@4{kwjLGon_qKF^~kO zAiu_J_gKH_g==E|op~JwALdy%AX?lw8&hyf~5ehXqhi;pK@5RU@cr92*J_Qc)$pM;@Ma`nh;-$3c&CgE>Z+lW5`+$?c z(n+2u)3z+cs@-%A$r^)Gh3WVbN|TooWI+DF!!d&N9%v@~lN#pme_jCpY8P=N^iHOA z?y1teSZ8MKudXG!l23#2Ub%T6V!1`1WPq|5-`lXKG;#P1zCO?wT|_Y!B|JSTCmkD7 zip|{GFdS@mlxwPFFZBL=Q$^65bYW;7#-yxCj2ytK^AIlE#i#8 za267wNx4_L;MODROx88dS|3!fDiib_J%-Z8)RaQiXAyIU0Nt;7L7$6mO6`h{BOk?b zvtAaG&=7&7>v4^FKjhlNUKTR(*q3))2=ryZvk8j#(-izikC$zG=il)O!+SUyQSfwh zf6xm=aF9FvRT5^88FUH5LJ+Bx-WC@{QxLiSvny;mn4~KWQK!w0jg8eMS0mQVQ_dLk zCXzfdu2uM)BkvH7EtEsry&k8xFp$?-LmHUWqM$8EP7}Z7teoPOOH(hZ=%tv_2E=V}B;tSwIF^EUpKugL(cVcwar|6Wob-23Gf0SI}gO50##U=QlqA|x`*`5Kj zr~8gqrNWcic9>wud`Gl=&VJoyik+z&NlPYf2gpO$|6+@k`|aE4Ik6wE)N_eP-s~6d z#F;6pTtcIz5V(0qFu_HSg2!kO1F`NJy55z~Igi2+=Z}=n{o>Lu{qFxi9~vCBm6sx(PLZ|L)w6+<*tk8hQU=5paxwC5b$#fKi-|v zO(yG-uKEyxSv1Pqw<14p=N1?9ptZ(VUux738dJWg(yOZ`kNI({Ywclc`1+C6nxM%I zqw_K=F7M-bQ&CIJVHHs$#@b;#k%7fFZ!r4BZEdA9{uW#NA|xBzeM^Gi@^$J9BtE&O z{qY69(g@FR7UqACM6?dlJev(BPb`-z{!?A~F2((^u}bk7+JJ#&HXf zAXGmN1owmuy+$0r*M5jZF;vFS&DAm@b0uv-6eH6ladlE^Fg0!{Biam)26*xp=Y zKsl^;rYom>1_=mxSQwP6a5KfD75L3CfuVF(czC#S zElDsKFuY&iL7Mb{vQWYVRgJ@8i(T){>nY8~Om)bItFsIihyw z^?^WltrMHb>__U9JNt)eTgsEE84B$h%j82%+fGK6XaeH;kU?S$>bKx;riYW>wE+*I zoWqN84~1DZ%@!6G2cr`gidOf`H)It zd{fcq^M4EZ9K?vo8)4d%YJ}#_J+{mgwg$MtIA|GBuwB>KCZV=Td|M1%8Su(ZFy3wX z5P#I+YJ#&3s@)$0)!x3{xpkQ4$6X0mUZ2Cw8K-1LMtGHLTPX8tIDFNT2!WPq zB|WPzXbnX|{gB1*At4_x`{z4KN)}x^bT*|lvK)Q2)SKPv=7GsDOWfwS$v|1G1C_}h zVxUgT?wo!Lk|HT-JPEeb<_EB+%opTaz0?x^wP0#|`r#glNDfJrzu@0_*oIR^K7 z7awq}JSkk&qW9Yhj?>0*b@vBI>>_JFt@;{8?P4Ov;%q%PH32M&(jRf&Z)1AxBb#%DO3PCONChepn(0k=`(o?jVXIZ`x^!$-CN?`}%G8mSs5E0oYYBD?8z)So-FbHu^4F!75qDc^$5Z z_M(BVd6&TA!lkjUh-13pYLNRd~*grx;RGGrk*it#C@EDh)14< z+l|>o*#Rd=gX(3QL@-x3xCIlO`UQnMw-;uCWQ#|Ui$%jv+?2*DL9$*@Xg81$*c+9 zVkd-`h*vPOIm6N)ZJIESysIuXi3#Vg(BH97Bm`(ZOb0}h&yo4}KJe+gz-vuh-&v834TchdUW_38W*_yH0zS>ls=`RR1X^I?o}YD!bH!O?<= ztf!{set)2yZBK98ua?s3?&|oxDUm;S2IDpmPdV<3=GM8X$9=TB zF+KESiJ6I>ycU*7!QiT-{gpafQa3s$_`St)*Qsb!^Y-&(>Y=RX#=NrLqhPiDwz5`> z2ThOJ9NliB$`w?=CAJ|>2D2FVJ|-DCm3lJMszAN+!c_@QQc{e69n zs!TC8HtQ=_eh!34oVlyGE6Dvp0LZYBWViKEz;RhL8udz}Ty@{`T zhlr<%Fhn2BAti)8j3E}F4a(raLWx&zUkQqrGFxg^)-yx}Y35Uzqwan-abOA=SIsO& zwxH5%Qx}UYi*?o?uNq78lx70z6>_YsC17($5ED-Jo^sAY`$0kmeh%Cl3 zAHNlK3#K&TTfPBJ;)_ka+Pr}I3-XMV`Q`DV;IzCHh~+qY5BLj@bhI-(W?VffA(qU| z3!8VkT-rl`=4QNj)yeBt)rY6QgXi~hHtMc#iMgb4H0axpi}gl~b9m*V$E{cn;$-sk z4^PI^?tn;9{-ll(NS_|?;qHV*_gYS`?0ecq{Z>ZE$K`@vh77x*aW%dD{KnF>yB}F63$BM27{4U5pAIW# zZX0p`5|8tO3qXr;2|*|dPOed`tGF<`j=Htiy;%w{&@j5yz(ZeaqcN`pEw~UswLvp zjbAz4Pv1a%w$bcSB!!*{xL8K<=2pV;z^?$RxE$^5ObK`LfrZZ&-!}G z{>={xFS_5a&y(K?@%I|^K%57?9h4cKmq|9;`L1hHN9!k1LvhO^pZngmMScd+wli&& zBQV5$Af{TAWsqd!ETG_-jdC5VzWBOedtHc>D8TyllNMWIbvTt737_xUk%3SM$NO#j zhN>Jv*04w^)Ifv$9125jL-y9lcyBB&a3K_#lXxRs9}_3{dj@!EO%YGBZY;w(QUk&| z^w3VTZ>1hB&zXCueT^Mr$_o+ZTSVOk$}8mnx20#Gk-H6Dhh&g%6=QND#K`%iEW*7X zxV=`%Fc$6)oMwM1h-ln2E1tCyHDUageBK?`d`369=*iJ9V`!Ku*aVn}TCDfRJdCQ^ z`Qv5`ds|{8)y&a(vj;G#FZJm+TR#8+clr47&5Rc$wHbIdvkW4~sJGWcp1SpF7gknQ zPRoAkB0v?zVy@PP#gbDADi%jbAKqYN7XDt9usTgGl5aGHJ_7#Qeu5djLbH?ms&BnzQK zq1()Q*TMIIF1@$$_jtyv1fY@vHQS;6Km5>6?3CMYCYNO)^I1+Ohs>hKMDJm zL*+h$pFQt)_4XwwZz69GR9^Uvb3F(`mxmUB+FC6?^2gy# zhNH_G+RNZnt-5~=I=8kEdbbfZB7W;@b}Y#3jhkTGL#sp*$?*-s^Tt1I28s91MqjS0 z3*AjM4MO)!{m zK^ALfrdvv>$C}N5)(cZ*e+zhq0(%*#CeBcqZYTHECGaa>i7a>)3Z7Zx6)`>jRHDHW z)hbYGupq%L&Q2GQF}>s&h90v0&_mQ9hvClUesgv}#GK@!gn`7utXgQz$_T9kOh_$u z{^q@(#H`0vWNZbC+p_=;f9yYhbM?y)*-vPg*5x-G)c2uEZXteV)7_q4NFB4-2p2pk z1#-HVa3*r+CGRI!83rE`;UAUvM**Vti)z7kPhE_QMT`7?ESpJo;iQ`tsrQ8q(rDiD z0^6^iis(Q&+kwZR9dtYB)I7FX$Jo4N)n`#Nzi~qWC?fBjKnp1Ie0Q>^3&@2-1#jm7r<>7VyO!kcnSo&Bz*iZmv9}+jWdv+on4QvOnH07^u^rWi!rw{rYvw z7%5TB6A*watvpT>4_a_iZ~o>aEd{&AQa5GG{Wbuac_Lhq@v&_dvA)b`+*Y~W<9~97 zAnL>c242RL*WJ>+i5Si<9L?-6n!8uL@Rja?UFB$spK9|+4q%#j+^($S*q>Z^r0$nc zM7K_HMNWSYO$CVFK_(x7lv(^+Aq4JUw+Qs=nV4_5t)px zJh7QH>A&2-tpmbulv|Qd1GI$ z;XwZOHA$cZk0Eh8 zl?BtsL0B(<)UGM9wuD_)fo~a+0XdBekzB)V1%3I6VZCs>a0zo}SWeR1f{8g1G;=fq zkoe@)U@JX9;AkVNw*Qgt3R~$2VfHU&I$Z6;hbpF71C1DQ8(CL=EtvSybJlQ7I-B4_ zF7WkJGZ{vfEn<9@{J1uzt^(~Y|U2&n>Sn# z7-CnV0nnCBNTsbgTG#RaaQ4<=QFiV6u;S1PLpRdh-K8|r(yerZbPm#;(%s!4-5_1k zf|P)Ccl>UAzIVUw_t<;;Jl}E5AHz7#z3z2iYhAI<^Ss8c3Zl8pH8+3Gc^dDjwjr^Q zN%N5Qtl4VTTWObP+PSAgzQA7Juz=0CEkj2=_U#=3(Xplj60gmz-75Vq7)qWi0E%c9 zA#h#rCWWiAejj7!C)w*tL_gEp#UBX(T->UB5y-;HQ517W(4CJs!^>DcSY;tjzl-4C zn67!aziIl;b)cbK_;5bGSJG0|vh!B(PrzY_cDxXXQ5_K>QuuQKP&Lg>Zv-*gY3n6S zJWq){xVr29MaFS*D?o5gUNVKIRC{7XyL4@|hQ(M3uN1N2H&7)P-jsVZnAEsxbdote zb7nDU?-j<47T;rso)z}B<3S$1{ZqXc!%LxH;d}`ZaIUC&Bk0H|CE0?6z#pGM#W79zyTYky1!l38Vf9jn zie8~gUGA*2foI3a{oR;y+@4>HGZ8{FltK5fbJqmvi+)Z+9H*GnZ@5y`aQwmlDG<4S zo7Br{{OdBmQ`viCGXFF6s`o)?rR}r*Vfd0_WZCvJH5VX*!mc`>5tTfSMu*& zttO3d+G|t)U|GyvX?dhw}K3| zsljtH@*;8GXrRv<$sVW8yFC;w;iKFkuNpgCWj@cjy4GBHB&tdQ6d_a7Mi47><(u-I zu9hlG6uB7#x5Nr}{-daBI_AA^QiHgWjf)D0icg+x>BES^=@8K{@6cH^RA8Q=GyR}X z-|=OF?(kQ1C>Q`JzP?m89+`VmE93H!sMs$&jtkZWg0nq9B-nMCw$BaOWE7~hzu9N& zP=q6#(rVFj)u8vj!sw>A!0`vWzNYr=;OUITqs4qrXQ698o;3b>qgi)M<)6qX+@HZ6 zPTgeWRJ?o9%^@aZg)g7rlv`HCc-36|=7*vj1X0t4Su&T$Vv@~=vVD%Pmj$kUP2}EhoJ_wvYa+~I6jT)T`O`M)z}OXZrt54vNs@{7 zgSHUNlQjSTG4cGLKZK-8>5YLH8-5_ib~D5VIY+@COv9^4k$|0|rYye34Ge16_9!|% zmDG11Kt|~Q`S#moD=F+rsT$2GqXa64?&x$`lY`@n%@lr-S@*G(kNw|i?ej#G1Q#|= z;`WoxFfL(3wj?~Aq!8bd!SteZ>K9@nZ#EE9_HQM9Ov@ck{E%`a725aN%CI?zzdxKxN zz;kwVwa(6Imrv51nrv~taO6n#abxpXy2epqavEuwfvDi>3~f48KWy>}u5O0s4(RQP z8pRfoIbzx(!AW(#)N#PXm!kWXuf6L z*;PZzM8xW9jcpLxUFA6B_@2b`XGq7t=fO%+Paa>#&YDkOSYVQtskJGeth=qNugPos zMT&rLDv`Fn%D|#z1oC(PsShf)P*_Ml>x0m?LB)0seu^uN)_u)#cOmA-?_$%hUEG06 zSD}Zxe#Sw1rSlg)fpdDp>VnVoAcP526ZHz(kBy0#954L*;Yebi=m#7#!)YI5`lj|W z%D_p-OFZ`}@+QH;2Y0+CO`WdXB}80E6AhtClc;?g#@A7Vi~O3`9SfTSo;V_u6y&V) zsWN=3o@??`MjZmb4LzZOC!9gbM;Xd_6@B)5O&_Iy!T|(775_B>wBR(qpo0sb29qL6 zqZQ0ODEmZl=x)a&y*d>jJu#l(Dvcg-#TT!!dFrHR7r8(Gq|KFOFv1cus=hy$w)sQc z1@BYS@XyUNZbszJyG<3$#3tyiY(Y?#1DeH_a9dS3VV|ae%BpR7M zM4)osgFX)ON(Lq~(hklVU34oe$XJbiBSLuhAIXi7$S1aY^EQJ@2kA_77cDs`X@tYD z!apEhR`2is30qPeW0l}L$%C; z^e1ed5mXc&LItXiZIz$jLaQT+H81d-;L%xl&ZBmP*EfzEtHqxDlTE-I&LXPa8&T)j z9D5>{i0Y^)B6{pS>)SwGO$8gp=x%3I3F1x49){NG_(5nU?JCro+;(#IZq%6XhLxF0 znS2FR87_rCX87I#yX=*uGWmpN2&@1he#IgoKFYC*6x^ zL(IjE0YCN%aaA{`UL~^8OdFMZZl(*lbJXTo`#mr2B$JBw2I*yx3ixL!Jyairx&7tE z56vpy7mf3Pqp6}_Yh#WkiPM?(&vMn{i3Apr*f>-&y^Ep}gDa-fVf|)ye(ki0yVlL5 zU0v``sO%&a&`=+VoL!J6h2fViHMtrXFN!XyXhc%j^iHN!8n<^4N~!(yU)bl3MJtU~ z%~s&}DY^Ih%X|<|u<}3b39&-;wC5Ou0Aoh>( z(eGcV3v2gowM6EfRv)XY%iy&Q4rNgnYnb($a$h-Mys=XNjX8{~p6-sFP}~Xm@hLWm za{{oEo%Pts(sz4^3B0;Gi!IG_A4uJ+^aPx(46%lJ+X;#AQEh>H!&$NR5 z<~7#Zd-N7Qr2>SntmR%GuaZH1hI zBUVl8Dfnz>LbwMO>>fJudaSrS{(-Z5B%ka{>48CvqP1e`a4&V=>*(xbn7L#hR~^Ww zWN~&#%%1!EHPl$Qs1xGVAuE%OGxT8(t>C}oQq8>r*Hdt~w+;6mVF;fnB7W4$wD!CI z@%D$|cdzQ^W(Aiy&TpM}u*o_nrLiIZ z40D^1TSlr(&}_!ZgCJmGY%lCk!FN6p%z8Iny?wI@Htl-uO!x~R*mh9Na|t+jFan&U z1Z|CEvi(T$i+Sz6eK)kmo2G~Dva~c8Rz}NF>6>yxowus0i$&KC2?5&=`vknBLrfKB z?gb{A_;G!8Cz4^Qv|CDy4X~g5ieFsA?hTyKYg*r4w}fYtxY7e>o&TT*vxHs_s)Wqp zYU;Q0P$J&StT>|jtSD!s1V{yRZW$m@^pUOm91_@5Q}2Vx`n;Qd9_J-la(2O<)J=TC zwyWR-#cKsi2%_0XZV+n1X^!+xB6FIy6eB|)`uL#xkXCJI^K@U$bDj*7X*2sKt7JUQ zOafN8>qLDED;bc3KJ#bHm8YzKqc_ZNor1CTL8$1>_<>_w;P)mXRsuytL3Z@7s#km) z#yzlw100zQkT9A+!DunCKQcTDDB(w89co9iQ!geknU`dTWE$_k$V`Am>#Dg4WE-WG z#90>MbiTbZe=U`o84#awqF4T%SG^Te`%@RfKOEKu2ogg~PLxHOqXG&})Z_l_Kxo zJh8hzHKj&Jc*em1OY-aKVQWEMw$LRHOPQM&v$3;FQpC)bCwy#T3jbpVMW*-gWOaBe z4rzhwG%CEP+k!G&q)J$5zCzzn;SCx;$m`T0ZCP;dMnK%yidAG$woC?e z^VhwZcxOD*{3KB_UedP9qZcy^4<~tkBGB}!z;R8m!FKM%z2SUcu}MUoc3v??9+KdY zi*t?Xw`+ckRi>zRAyn_NAM5=wc0eH*g8%7V)RV{F+s{#;E*B9+#AzKZ%*|uY&m9qT z{lA>8u>E1#>5-vIFytsO*Nqb(@P-aNGeAb$q5SfUSxVkthx}{FYi^>x9T~hklpjZS zvm92eI%4S)t>jGVtlV$1$=Drbosmi{5ilch`K1+y-&q>QHy5mgn&k=Wv~`z@4#QVP zgQ7{t=H{qjkqL8V$+>fCe)Tr*N_zr|ytHa}0-^o6YdD*akdIINq}Z$?Jy#_QYI3ru zGQ0@Q_UV&rY_jZ_aXUF~i|iN28PAbv3QlrA96}#0UT3~t?&ztbzd+v2X*}9rO`9dX z@4w@bVhSG)=)7(bk#T=-^yMYl7&g@G7e2dniFcusG{45tUP0-702i#|e`mN3^{080 z__aSd=O+1}!3jlLSPkTf?Z}tEB;|s)kBzb*WYiRvYDW5@=Uc_EoWOHS^}}g2#dLPoxXiRiiTmEkqb60udf%+2w z(g_`fTcDPod}f~^uTRrjJ!e&7*qInn`5Z74L}VeKVK;8J7jz8PY)fUdN0mr=amvvNC$Cb$})M}I0gtRUMM_^P^HtW zfWx8Vrx2E6CNlGj0Vvc-S+4|qb$Kzu*g+Q}wvI6qd~CLns>a03L}ji-NZ9a`6T(vGm4Qt^>hmTGB_am*G&H2 ztM0$OZ_hxHP&q_}m#Oi7D6}Elw_A-$TYhhGLP(Q&YKT5x!K1pH{z` zBw>^NMhm0xt90Qf+h|;VTAsa{H*v}fv0Gd^hf~!dZYGvB4EAMa?$t)6cr|DFRY%l7 z*To<-E})6hDu-$0uU%d5J=(HU-2N)&Ad$02>t)n&Bid!;$4_Y^WW;3p5n8>tnW&U z6xYI44b*s8l!rc0jFc-^Oyv$sb=5A-F9xQlfv_Na9{Lr`k{+L2@C}q4{rHs*x|ACh z9wY>#VHRI|Pa|O9+V=ln20+r_C|MuMnx;a;!z}w&1QJ3|TCXE(fm9*8H2`Y364LOo zyBw_va)s%{`Ff@T{#bXUyiHM}(40zt(<4j0r)!GbwC+gn=<%`PK33C} z>_QMKqA5tI(AK_tM=fsx{j)MetEW+=@`n&EDx8QpJ&mx#JZD0&Z zvxEuexBE_+#jn@8b!^XK2>H9FKP1PWGh+4877{e24Qv=WU{8knRQjO6zPtN*WKToc zNBZxr;rGk`Z|{M0Bl_epOK)OrbS5266C@=ZZnqrNvtf9^2+lm+e73V?tRzS5N0N%L zVYsm&VR~^==N92&iaZZ~*)=^*c+8Dkg_@Jp!} z;IvB;pift!;>?mDLKItQaPO~G!g-zH2M!OR@WAQV}eKZXC)#ms*@v~`9rEc{Sq&$Mu#g^a8jjyXoc2&~J*nvC9i2EY5u=rxqEr)>wAn5lMhjc<6AD_- zP3cvF#Y`9}2t)orD>LqmexF$QS3`jUrZZte{DkxlyEU4YDPSeZfM3r=1mFL zQ)OE@d?pg~CncEPA0TE9L>%R2Pmq};IFMykIgr@Ne7e9O4VT7oHf3^!t-fm z_dKUFfe(1mw^Qg5PrR#Wp)=J!vaqpYf>D}sUI=wA^LKiX|NA>k6Yx2>mF+{^oVam_ zY~(7c2KKCJ`~{QkJg&loj2Dh&M*>H7);Fp$8k;70ctE`1Z((II|7`u5IRNm*{59nj znXpIPeS>-0sW0c$2U7mwT#P_Ly+CPxKiZ(9n5dP3P?&is#6?WDo>yXNVFdzmiVnCc zwK*!F%{wANJ18t{10<*iwTh+`X!nk^CTJ+<^PAW;293^!q(+{-y>C0E`3BGVnfAK) zmS%=t*oy@)Ma1v9q=Zjrii&qJLAd`$*7f_^OL+mpC2@|@O3pFX$-gDC7>_`S_2u@( z=R&eqn&#jrpK8r2^XIqE9Kt@2hW1G^aaXe3Ic+bH=mZ@7;+g|h^3^;(MkRYd!mz)7A83%S{ zC>X#IIm?>I)u67Gugg5yf7ty0_$S04)g*LTG(RQTUVN(`1cg;X{N-a6hW}UfWK-+L z3{Ck8ZW;@m2I@Y$Nxl*~T6r3n=iTfDRjbJv78X-gu*pa0y1oRYY02F4{p^l+;W^KD zE>G1cfJ;FjL>1QG1sVWd2txo;cnmQAINyIszdy}C1_)CUh011ucbV@$08(y7r2wm) zFw%7Id)xQW3qU#o>5DVI@89ym(PU#x9U+qf>MX2f(+y^`B&=&hoQ6|AvwYx06Tk5Q zB5~oE;bCDt;;q~?C|rE-zAvdXpGr8C<&&UDHCrsq zwYJo3`tC&~SIyUO4~f51zd7PbL4u~_07Wyyt^}oZ0derg6UWFB{z>5oOW3aqJPQ@iv;BSmJm&6Vjp5ojChKa2Q1%UM;OEv2U&SrEOy-vlw$Wl{Nj{!`bg|~6X z%HIqSM^vB^#TfaV#`zV$RV&|)psl(=?79?c;Rn7%5s@)FWLAKdG{#tt=Y5O_X-+?` z2LvO>1l*nFVC1#a$%tls(wl9kY7E%yT#@0`-J3DD_Mhr?be193sWUHZYPBhK811S< zA{^G;44`(ZzgIpnIm@s|&g=ZO8lTB7KQd8qP5|h08~}NfZ@n6}M%Z4up00P~jVBck z{{j$)w66dKAoEV*;Z$DLM*#+avgY=Fx+&)3!y&Rl3%&bMh;A&< zeDBN4`<0hTt#yRly_eTBZ48K*bdiGhYl7kFMVc^8)&Nx8h+b_I&~hYw1Xm~GO>5F( zgor{Y37NQTmc55kxRv&sPh?#d7M4_sT|^14eGZi5_zlaj5*BUy2#(L|+q9=kH7Rv( z=4ajm?P8Dfy{_{y?rg@=8yuNC|6YN1%U`GqnlaimI#2pL9YM%LlL#3qR_JWia3-H^ z2@P~iz2Q37S1*&0Zxpncm3?t8V~uo5%yy`jsOR-Y1_5=jyK2nA7+cDteM5LzaW?X# z%aAjh)?Ss}=1QEpuz1Udr4qq>nT}7toDfXX6JPKndYwF`A3JjZ=wBHY36&MS*yJ?G zy_uq9FLiUi7sJ`S@Hbq%H@e*Y2d&*sY5nxBrZzle_&cDg zmt6TMMl%zrJ(ic9{R)sk5+D`1O8tICK-vyeST~w?8lg}SK}06cGG!gEfw`fC$oEhT zp=3ocy00MG&1gIItF~QFnb4KsZB~?B0AOV?=XW<42+&vcUN@Yq>F4L?3_e)C-ktai zpO>K)au?hm?(dEpXIf;D2>DFrS8m|45+Cjl9ymzS(r?!(C#I)W^q+kf244v68ch1X zz*`5jr&!;$ounSrOljLyxQ@ClkpkB%AL72by8tvC2LX8>ljdu^d+;}9M4fBa83r^x z=)bj>oC;-R5{K>1CMI619>r`fbV;PZaP zEC6$j$kp2^29Pm)1JL%2Uqh_j*YJj$UKm7c`~+n0j$yqHVa0Zjw^iFTJTJRm4gg)= zphaH5G1?HO$=6wb*C}=rT?9xomZXl{07UTz;6clO;=pub`D$DP;8&B^3~+6rl|De2 z#9-qdfW?<|QXnn!LmR{cox{F73Q;_w;85ajZ`vN3h7wuDf!@ao0Kis2aUA)1lN z8qs|Req@^av1Cl2*X((n*R7Vr)z?C$<8Y_uu0U~acF3VmkH90j9 z{nttg^2VqoN{MKR zfg%_VIX*@TR=i+jC*08nsij)#^UQJg39tw^0bmKKiJD%!gjwkC=oGL z!mo*lCO>WdmlgmY6f?XC-C1lq60xryVwzEVMMH!7qln0wEsVb3a?p=W!3UT3W}|8R z#{g+zDKM(SsKgj(PHi;wC<=4@5|Cz#s!u3TQu9vO!25pb5C8pC_u)(zDry)wcX-su zJkH~6>Gv&%D%U6!v@bObaQJs5E%d(^-^S1&PtlsWO4o9)k{*gr6mkP>ZBRET5C`BC z-rxH657R|v50aHXqazD zCP&~Pgzf3ebC|RAm)qQba`Y`3<5&FR>j%)ggQ(2=Ry{6mBDWgE1;Oe&SnjE zh@BzeAKC}5@r6}T*!bSiog&2UF)uLQ-%JhAj|$#Y3$p5GtXdLvLK2`&0T%ao;Z(6| zGW*hp$v4M<2rWxdz28oGn~o0PXXd+tzs)zSh4Y3I6|UwG3gtXokuLq3-Y{L&#q+l+ z2U|fxdHFDsX`?btGD#aPipR+>kzW&w9ibq+uE7s{wHpWyo_#+kjFbu|^<}WXj(X-R z?VPOzk}y06K@{nn-34CMS>H}Sp)Wl)UIPvz-NIFZRCQ+tdWi~I{%(8ZU#lYoh<^Eq z4%2>Z)_^VyZQfH9kT0#^^?1a3l6hIsi14?k$m9}dd`Uu|Z5JJ8L_LZSfhF`nntnB8 zJmiME5(#!JXaXTqRU40%&4JS1hU0US0EY{qBjs8R6S2gKh4H)G3z&NVi3og{@taU!@fNe^t+tIAh6OOm9gIcmHQUbWAmH~Z#&z|w1p3yjW_}axU z(e6iCt`aU9+Ut710h&dhDg$THcE%BYZ6a7(XfIvv+54d9;q@kz5J zsPU@Kav{s!>u$!2AkG|v!|EIM+gCOp*_`&j6_hnH0eqir8vExfNT?#%Q_|oUZ}aa* zYUhz6{yNY2L!g_%34+l&B$1U$!nzMi@jOoNal494%ti_H)lrdO;mw3aAI=6nl}Ok% z${ltil^33AghDf)oiE4C@wKle)MFAf(U&2dug$_usQBUPgOi%z8BgJ9GH{n_j`gbKf2#rhx6dIu zU~K1(5ZM7!T=G)RhlUSArxPwD;6P;;ENe6BUPUgUHQ#QH{nf{k1RtNQ zo(){PJ>tY;a`PztX)e3^=pozz)pHL0Fz`8?>FL(E-IB{@|M}hmbXKCPewZ2VbK17E zQfr(DQn;TdkIBK(S(y_Kilkg-SYtJgpi>WqYC_lN_}ELA*gfur>9hdnM;WW*+mq3d zoyN!f8t;HUQRWcC?Pjk&Iq&e+r_o)2v2J9(ApR9PtNn(|T(xlo{J5{3^~7UTlcX-k zSbP1I*SHIVUZbWUPpJQdk951RZti=7%EAis-wPr9+cO%T+s;!+oD3ge^|QgQqB|=T zo-l$#iMr*fSm2>a#pFBfjoJjezG$G-_#htf3jfrC&9WH!gvoS$uB|+Br}7lG-=xdI8W@x};XR zU#AqL2Gmmb6eEJ~hidbPRUZBAA74VqAec9YJ}$YvL&|cD2Wb68TcXfZnKj)qI6tUx zo(2;VbFQMsCHgj?gkYmcHF)`Lb)UX9*DoV@Rn39CmxXDmhh>n!^f_Hfh22(F(6L0*)hbxPdzr{7BU zxbpDutUr5s>AkzyG{aH;1tlDQrZ6|R$9b{=Q1AF*eZOHn^owcdevwbbapmr!gaCPOo5Dk&H%SjI%>T$CUXsVW}^NMg}-q-PT z<^YE8YC#zDN2>?EAY={qq0M{_4-vkGIZemvCNgK9l3eeFfEE-ZwThY|Jyqq($52Y_ zwJT^OZ39Bx#-Yw&^~hqbo|+eS@1BvGX80?y*a{!k* z@dLNQ2iTY^;Dkbt0R~(03bFG~>P3%>MJPEs^O>?ZAUJwGtndJk*5`ahe2k+XYn4?l zCq{|Exw;BQ_f+6D6sd%FScHwi+kUC+!&9Xt4+ z;61YKv*i_4lyU1P(;Iqk0BFMB3C&uFmkZ>(Oqg9KKaX49-VRPwZV7htHg>^Dm|5oN zBPFnmh$;nOVbOKD+6&{|fl#CE<`~e=j!s0KF{%?5-ICG#!;Xt3{f%z6j3D)NPK?)OHOb7N0&W+UB6teZ`vZ+xoxFeqgs}_8>BH$_J#k((UgQwdn9Ue0`yhdy6Shvp5ZnX0tq68 zpCnv`sLg6eA&UvclvMD;q6UeLdtu6XbU}rfUz8E8T=CnsrQVjq=G&j_M}Et-R&*GS zv}r^ePVk9`gGOYALT~QYtB`;q4Sm9Qtp%`wdt;t=%Flt{IwoG~I0KAuMz`}_<}`yx zd2l&qN(dpm{NV&C3CDknQT|ms{{6!(a!4knGd!ive4Es<^n>_qrzxp>B?(GOo#A?| zV(sz|nFUout)f#V?TvT2ED$ZqL$-H2Oy4hWQ?!cNbWZ}J6CKq{bDz5sKr?>yg!f+u zQ90v8$NR;QK)T_8a+5CD9h`(foKV($EG3z%cnm1AegOjJ9Az4K5ke1O-0>D1$+Mr? z*p7h#vmBQ*tNsZ(@=R3k3xdv*cEQpWvQHl3QjAsw%L?>*g_t>~Tedw#aw4Kqa(l&n z#R<jO6sq#9@b zha*Y=O2tG6VuX1^&3ILdENMF!<63}av}gg3l--j{R;tS0I_6tXIa)v4lnL``5pZ4CnfFvffj;q>HW*y6k4Z4L z=i}4&oC#%pJf-5MdH@XC}^K4{KP%&Rf--9B}Z z?I3O`Veajh^HrN&8#Z)kIcd8q&G*uVcF~CrE$a-QV?^S?1pg4Z%%ud?MVX_J8h7od zq&R=2NxiQ|wiNU%52KqxrP~KVv(D#}nbH(g;*vjAQQf-;rR+S3^V?)H`~4TI>+=?8 z6+<`^CTco${&GpgVYuN5&mKd-_CT`sNHNmmDm#VW@ArRr&qM|CPYsASlLE)S-&`~m zSgO=koUhiBa#Ia-49!-NZk0}wh!bzVl~oL& zP*qB;{$9xQn@vb~w^v{_cjE||M0Xi?w5+D{kmY{d>EUgD`;AnyhxbnL0GeqYwcpjZ z@chXdFK$_ZVRH`U$n>aIzf6NfN}c3UVa4C`ME}0&F(N2Zph=`L=&6)rU9h~-cY~t4 zTgjvFgYgRSn;t=r*Zl4HnEh>Zp29oqbczEGJr}`wr7;7+>9W#NEqz=KjvbdO6kQ2tM5pn6cP|?Kr^p})y-Tpf zi}XUfynlLWG9r-|`mM6p?%?3Yz<(UbRYqYUHO{LVkzav{%`_MQN~+rzHpu^BB-miUt3HP_ zLK1-@4H2Sjq6`<1as0I=V~R6v^b?|A%RU|J-jatKhl2H|Sz>(dQsH|+kZ z!CXswf5*8aS8YnanOK>pRFnQg@MMhg6hUVsD`Xf*jG{q@@z+2fGl>bZe_?xtpf1ZY zoZ{azSo~}!_OG|t-k@g<7%BR@vC z+^-=qf#8L9eGU-vSV`qwZPU?J7^6CmjdMw7-s z_CUq90KnZTEQY};d@hQzsXXknlPi~hJ=Is4BO(}CdR0ING1no3-5v&KG zDbyH_;LoAw)trBDv!PFbM;GcH@`XIIT@S6@e*-vF8{RMyNROY)my^zv$KExyb^rDF zAx}w`xx(L9tD9O{#^vQvAZU+7Ho2XO_LuA6x_mf7CM>Pla*6BX`;!B$j(jxz717OT z$qWS$k$VTM*WBn|wht`qF;1v`=>YOJqe66DIKD>b8>A_YWu-$!yyxcscP(y&0=SWs zH>%0zF{^nN0V)~}~9}Joc5l;Tl4pZwrL)32&2fZzn zLmdH%t6G{5>a7w|A?aZ2&84L`6DMvn;iZ455$b`^GL{WNx>^ij|M82mX>h&_v}u4> zSa1qD73~s1W_)#!WheH3FWhI32J%#VB1^@Fy0CG5zCunU@~*`#lGI4tiR?7K=XJLgW`WDtY9B(P%M8V+WIjkxm>2vsz{Q z{QsOt2=U`6i9I1){J(t|M*A!ik+0F>+Xpd`_&^^g7_-DLaF3D4GvRiA zJ2iyl=@6$?=N=nb4%$R}V`;0A=HTm0Pw%sJ)pD@YLz+pEtY*_XL#wi#J!9y$8qrg* zO+*V>PwGOq+tq6j8M{%*`?Dpv2tu@}%1FAW&DIE-oFO->kS`UJ^AvM)_T;>4DFs#q z=u)ufi5EGsQsc3TYn0o(KcFOQBZ7gSgS4VzTaAk7&TyhHT%2Ekbdocj&$uZ6eIMAZ zk1<;7OgJm$?*``sx^>TA=M>sH)}$^R>shQ2cDlP=Hsc++z=lp1_&bopl zX&`@eNc6p^ia`3zgRFxFf?sE35+3ENUpw6x7gYF~gh~qr;CiG0*u#4kX{)ez5@KsYUo3fdQ@obd2*&Z6i1GhN(Zu5J<7xoTFW`AT>d7Q zw^Y&JKg;r@JHNgSKNhn$S`wYG+exj3hF1f+0bJ%AKoOqduV95>?5sV7_x3J-_&z51 zL8$qziIiw$_Q>ZzI>IiA1y@@LIuDnS_D>2tbwI<2nRM{?<*C0vt6 zfrl-qM|zoFApeExv9`BJl{ziA{E!)=Ky6OhfPXJde{M*%J*Po}E}LvR$RGD9oVIKl zA9cQLDz2H*zorVt+Z&k?hUPYqi}WH^&Fl`sPz3+F1la z+(fwLs_Ex!<(q=WJ^!!pl;lN5=;AG|bL;PGQYKvg%bP>0lb?9WaW$0-s{Z8we}!is zUjr*&7;02sQjZLrF>6SsC0Yh~oL*eDjH)%`HtipUnfV~s zM?aPO@up|7WF^#qFtLOZy)7~#)CJb3LQE1)2dpzZ^L?CH$adnVNhld&VVz_DaI%*X zMO@H~tw!@2t{8P{^y#dv(TK58jhHnCtn0x1xRPv)E1tdlwzv<$(8a0g+8jl${!NNS z*-L+zf)Gzt7ng7E!gH1lOWStJlJArn+{=igdZf(pYe^EkU4Y%$bf0-}$lXfUx z+1#Auf{$-4$hEDLm!|M$BI`ILb1(0`C8y8FRC`i8-K*>CTi$Cc_JbBe7|9PFVXms- z?VF4W`}|sKo~Z&K%@e;IzP{-eohL!t!hK+x5WhPQ5@J0sC(2eec(YS@qdg=F_d?oX?E6Dz_uT;Ktdh%V%3} zdc*ruKqJ21Rw~e)$m?bW!UmzNi3ZUgl}8%$O`6S%3$#N#n<`b3d1H5iC2{`kgjNLH zKpAeHPT+Ij^JeF@G8LNK{mQFo-8{mQ-q5(OTg=h?n_4m1FZgEAIZDtjdY&m@iF0<@ z+cU=Qx>RR3Zu=zeduDS?cj~D8ItG_hSTQDFLS=7#LyIWf|4mW6 z)(hyjvo*pq?o?*cxPl6HSR*rI^4YncjpNb3o_uO@%fF;i?&xjICeEHv%9q{;c4J=S zvU$dU_rak+1|uGT?$GMTPTSMv&c2IYM#~W;+QT|hz#Oem)&LzZEw;xYrH7uZxR{ln z<(uW-OS3mivp-I{y5q6zlrnMNxW9pEd&*;UifhE!thUMXW>X{G(mnEiN!J$7gWB!7 zNkm~ro~NQMD>+6|+GwM}Rd)#O;`5T%i`H|;L)I2!X;&}I>2mnA!7(Zkh@sJF97PM} zk#8-QGLhz%`}4Zj(k+Yf8oXoeyOSa=p;y z5t}b+AOyBmR+1+N4EeGvf>|t&hh&fC^HCrl8eduxxNUAOr~uTQ?1?_8AIE+kOrLCX zoNgl`-2E`^>OB62lQd-vF@yVl`&$8}jJ7k98G=1hzB0Big?{SKV#7(srM_9=Y95YZ z7jsU0%IUt@9_H)5zToS(Bf007hE3WQThxmX#A$=RAdC2$M3>iV?|8P*(m2mLaMv8h zwQQEYsj}~ydi12wSiEHk-+dd3S6{g2Q0?*c;0_*>-2m-1EZFffm8K3ZCdT~JkY9Yl z8y%+;9t?Tk%9+O|0_TC6_fAd^{U zv+d54^bfVY2D<*J+f{ES>2godk(@FSc?YE`v|FKEl9N$39%$WieVxjyA}r%q-Dz zW3(pNgPZBp$#U5l6W-mnZ?N-md_`~G(yF8mYru41ofdR_z3DoC>t}DH)a5;bMfg%< zA(zX+KNfST2(Ok?oFv&Kqe71ZC;cWYmLrz)cJhP)HNRH0`CT8`!;bh6?rnTrNbobF z+jb49<)co6ejWR4HpXUAmPW{T@}EYE3Zk&7qqiEt#k$~!p1TgQ2LJS6R1n+tN-mpG z3Oc4B?Hp}+%%^0lJ(UWOzT*8{eoys`c37@*V06>5hUvu4WLu8K+l;YHdwOckgWN6> zny*JEsg3(Kt%WtNE+)|vTb0r2Y;UXLwaJG$zpJ?IIieand#ST}^b>n-yXyz7dtGHL zjnaIpk~|1I^+P1HU&2?K95c7>li5n^NeVVsEo!%{thMO&Y|zxng<{5V=%jZ{%e#$@bVbXFU$AIzV+cXZWj@Yre>d&T)cr&H0 zCSf+1r%A_tn^DoNO2M1MaT~lk*@#mI{sLre)k-{PS3?im`bVeQfft2|f%?$<=e5G#WWZg=)&_ z{LaM1aYT_nzdC(#(zE_BuW)22C8~N9OLg&iC1(I$SGv5sjq+5VK(Z3Q;2@gyO1l(S zTG70`Zt&f2j*a@!u~Dl=?+`(rl0|YdRKeN^A&LH#+3&(HH<3;b>+T{KLK{?D$6Lvk z>5z!RX@BA`P8N(K1j9JAmQh}X6+BaHFw|62xw&??UB?bHW%PMOeh6jgg~Qtuj=mq)4Ca9$!db04QyPPJ zw0p2;Ed-jBSb>rsWV-NYVBaNO+k_UpQPXw0uia42X0RG9!^p-vVV@U&J|+~i=pH(g z-0J8#-#I#VPI-_W-37cMAbZaf(|BR@_~SJG8jF1a}D(g3C$we)s!4=gj$%$xJ4h_fwD~Ambrq+HfO5Auh@YPDx|}80b!mJZmE) zNq2>g1P=W0Bfhbt#QxGP@(!gtthJ&~+tFs?PEH_Ovvy`PCLFJ3s^E}Mb6o?uQgkO} zOVqaYZE+FZW0~nI&nHT{VZ}q?E=Jv819oYe>RpW8s<;zMvA4zg7G0PkyiF~hT6OMP z<3VT5cvt3N}N zO&5X#;-ul6C2jJ-FyiF~3YIm03A*MJ;}?}>Uj?E^8ODk`H)-fjJ8Oy5813R+-WH!C z!zvQN?OpGje*#vuV&>3ZpLzXo*3ZPFg0;@e?}3k`Z4L%W*b6Q-{lyde}z`9!Zu3{Hs zC(`m{*=Ns z^{w0zZO1$)FB2$9axkyd&$7xgp_2=H|oY=^fGy2olp7n&8Q=T zcJ_mIlNkVl2O*&3$OdwP>31XLEW_#?kmdn96pnY5mjKn0(`j?Yx0;9Lo{J9Oo7$hM zaA3drA1UmnJ!{_^TW9_0ABNvp4!gt8SqKkQy4$jB--_JX;$<-A24o&2_C9=nEf8I5 zKPNH^qYe7w@AO+c#>N>(Qc>zFU&l_=WFAmy4JQw%xUp!sqyVi2i02oMe89#zX5nTD zMV5V684uPE#{`NHR9~YFXnq$V_|_EqTG3;+X@W!zCXP0{F_6N!5LC{clXd-#au5)N zzqYVF5jyN@*6!(jlq=a>PR8&A8f+a)t!(~T6AHCN#d8tTT{Q0s>44$;ifqs z_(4i4Qf5rcJ@=aHga}J?s`x6R!P~ImCr!}VPn$g+v^(meLq@(JDS=G}_d(4wt@V_I zW>vJlg9zhzph+(DyMmaX@5i!?D(>5|0!x#ukH2e@@m7DFh!GSO%X6Msp#MB0Z$4#5 zi7_yfED{Mis2Q`JTt0rMuoKmsq%ex}^F@F~%_@WCV@v7-J4IMMlW&_<%s*9w7lDY{ zX5jlD=JB1JOdsC7%I@+bYr0k*iLU^Us(9?78 z{*fhkpYLOXl!HM!0R19F!qXrKdO>x75G!zQuqmPjJwwMs!7JY9QQ1RRC}b#?#FUe= zCaxs2LY@c$>%6g3U`+fLBF_cY*yu*Dhbd2tG<%&h`Xd}5&lVb6)EWn?v)YS_VE=wZFc&`c zBCd~lC3Z#s5^TFb+cbI>3aLAxd;8C#XfjdXZp9^Pl8xsP}&O}7#LMeUVNM?8<6itA#;f{GN zGoGnHz0%yb;mi#)D((cWy$Lw2MQ`3_Xe1P%1VBI*9D@L2{EVsHRge-!Us&@^rqHg) z05Jb(reg2uild~E(X(D`=zy<}9)7W9zeInt%a=FTw5uEDsfgBA>telTJrHKw^UVs4 zDM(zY_;k#g%D&gSqWwHlE^7X+ro|c(P5#;rwg6=Ic)!Pv#TDYIWU~yaFOS55zNGvf zN&UVJ**$@@D?4o+R~WVWN3Ja|(7w4k_2QQFtU~$r=J18wh-M12CIiovB-Rq#M_(l9 z&M31ZUd&POfjyilDA{HGfgvgVECD4z=MF&_@wO}K4UcL}`liDE*@{|^@zFSb+;d-| zOf)1_=3k-G&%dG4Pe?T0KLslPb*WAe3Q52e+wm$v5W4|lhPC5bVTC@MsFntl@-9D4 z+BC=;`m8klq9$+u@oY}x@kyO}rYu$(Mcn9UNB z&`7yarX4_xXhu9&Z6769tR46zQ}0WN=%19}RRB!GEnBpV_(iLxOIhpoKcuy0%h?$` zfOe*N{MTh46IyP5r7`e0*PvGibr`^G1E_NwiCx(oH-wu$E0}yK=k2(4za=`|-7heW zu#xdOhx`e~WarPY1yFV~f(DpdtE636wiMLTKb0PCwTFwyDqQ|r%DWkzlQ$4(qaY|U z#Usc`x$hC5a1v|DZ3mEfaabqg5iBRiz6G0rn^R5>P0k?+A=83tr~(LKM4U&a((K|j z!9qqS_l!U+Og ztsl%&e0fPKT3R}Kx){1c>O5BP-PZsH55HT)0Cqd$ciIZkWmtz{L}tG*~pNB&+KWlia=D0a)DLKi&-zi27B#^&JB#`cu*SV*1{8?@=w#z z2}8vVd8+V}T6GMydyQqbgYEpnyfGv7V1s-Dr5TUmv~S_YlSC$rBb8v|8;T-Y$Ob=_ z%FUtNbXrn)aU^EbA~J7~)NyuvW$@ga`fyLGpfA=0x9b^7Q6#zPmMLerCMJQG5WE_ke>(T6oH2U)QU-V6{qYy6{hlaQM$3xwKzC(0$v6g zzCrAr3%!ucZe&4H2sI0+I$LIV6&`L?_3h+hO7mMG%~3dM!7r(>R6Q5oX{jmu%EW>Q zj;Nh*Utcs6ja=FNU!&*)rG;dNH!py)%WP!4K?6e8DInWnjpL67GCT+hN6|})7RI3O zXWvz<&u=lhFuVOa6EIP@_PNZXh)6-BMW?d4h6A%?a-X}U>E3nr&lB4>Z;a3@&N@VgOEuALdAT0by%vrn3c)IY3w_pl z_C2F4hY(cwjiF;R5yYg$i-Q5gZR^mIH-lBq#}dedy~7wHQc{poGGpf#++()?He9tGR05W{$iM$XU0~m!12io+w8mIZMx3s+^(4KI>TgMz`MiZevw?B zQ5=0xM0nYy!kIwKQn3v&BVx^^s<≧Iq##9x%5#$Vg+1b)>TSH`;L|F>Bp3?00CQ z)5RHz_vUi6E%g`{OWII-t-SGj#d_ZnEZMEkcLhvp+B+F;l%i$l#Yg5#)Q%{jjSsSr zAL`}|Egyov+&c6<>=ellv?7xmHEqpVO3Ec6s-&=7-NCvFb=(UlBm>qVA!{q4bjyH6l~6_`D7!V*)A0hYZz? z)bSVp81E|?B;Px~UMXkP^#Aux{YAWlf`BN7Ew5V~K{Gk~(|0!xl`0a%U`z_&>l&(a z)LNfuP=36F0pw>%DDFyUJ$hQpzBLbnuzg6mhT5x52A)G7#34VJ!FCFnJ@C&f0s?K& zfmJkN0E{o$JT(aM22ozN#@3wtbc|yW+tfNiE$Zt>dna;KPHX{Fl+-gZy0|y0;QxOm@?V zxm!7zH#ndj|Ii->=ySaAMFAaffkYSt=*3xFx3^Uj-*Qwk2;jG2Etf2mKguC{V3h8^ zEGI2-j0+19D3L#?N6z?YN7{dfNt@H1Q`omsK^bKiM*bs=$3Wo3v3UhF?H`%}E#PUt z6#9^RqK}p}Ny^fvP9q86M++>TR}?);j3(zAYc6~RNPRH?dOsN}o+C*dB-k^uM=@0; zd!T}JRqbuGq!Y~Jq9pVw%3)*OgOq%qOFc7m&;IpuJCyjRm10UZbBFp z2&C@hf(Bfqa6)aUq2E>vL6 zvZ8*z7MWeOc~^}s*C}tx$l8A^TZufd2V9ZUgY;cIVILZATa=Se$-D0$Sa=ZLt5>~d z3WYEHU<`aK{vT8NJr%k;N)bB53C%in|LrgSw~?fPXe4#zjaC1<(fuM(!um;d-)D_% zqe6%1KdVK7QW8D$VL~Fr>I$f=Cy#9#lBc*zr|q#i*(f3f^Y~$=yk!&9DI2gwo6?bx zMs!=Zhi;fxDjlo-E_WKrIxT(V~7l_1q9Qe*WP{QiQ@fTEev3l0|;*%>jIpe5h-e{Y10Z8_)y6>gAU}i zi7uTR4y&v~mVU?hYI4t62Z`q#EtsP@xG}0>Pd6jN* z?pp;~f2kKV8Qq*}0E#t^HO$kpv-EK6>0Hzk0xGBk;HN@x#wq@!F~Z7*bmM|c(|$XT z(I%6f>_&p0ADsU>Apv?vuJn5oLVYz3{QIK3zWj-y;L8rD4hkrw2+ zsuPV5BGJeWb?EIOlL`h&iT+OZb_VNzAR<1vVY=R22xl_MTnPxFWi5G@uhZ>nDs5Js zaB2_)(9a?J^UGUBx%X3Q)FfXqaXHlc83eud7EOs3?@N9D#5AC znm@y%X#gv(L8-Pam37(^QZ%!Zv6=cbk%oFF`+ zB0H`3A+Dsu)^J>=gUQFYgYfEz9TPZx7-BgV8gjPsT^rkwpJ9YzOn0()V%1w=#IsY6 z@ys~>6lR0`^D>W}@c5rGo=$4qy~mEhR~xnQth}Y>=sCm4aw}3aFnN?HSE5P70 zld|O_1+d5>V(DN{u~QeDV-!uZwXxaSc(F-ER3NbrSFb5IO^aj&?fm=(1Heq6mN&y1 zNJP|XMHZy`RW1S1GGbjcr(4j4y(UnQ;r%5gAJuUnCmd!s$(5}lv-*P4bc#Gfe`6rb zRo0VWr+2B7PKxDKJ^oA&SxAV`AJrGxp*goD0aJ_YrUtBn2dG^jr(*ZXS>~Rykd#3q z-(396dyB2E?)2Ha8JO1NZCv2p@GtK9B%t0~FAz#{heWC)C^$qT)uJ3r{=`~7z55qj zL+?*IR6sbY0l$i9nBdBAct}Fs|#6i)@85O)L9=?+OPp}88NA~$(U;5G4p+HZNjEO3n)aZ`lDuLh((b%$Tx)@ zK$Av}_UYo`V-NPiEv4)HB)|^za|0b#Imr!2(;7o2Iw?-p#hfAn0xuqdwmjYTd{|dC zRhQlOimA2wm~a^F3%?cDBOUTU!!JjMGwQEnFJMy$z5!L%Gz z)0||qX(UTty&lX)C&(jPB~TC@GL>psN-SPstkIPl|7cednsngAyb`UwnTM|FHYfUP zNePFBEm}L=BZs{ieYKC(KXa9I{_t;IUSPD@Bw(ZnGT`V6|?hj<>osM(8-#Q3qdlP<) zzPLysJt^s17Wj-t-~d7-v}6RKAkvEdc039!qJ)r!*I`IFFBDL9eg%eu6D16F&l}&+ z^Kreh)KWVIn5dOSs(7QxZ>-M^TNBh>Q_MCfmq`i8P{Ca1_}H9G6u*bbx(FJ33yigo zuBfZA<>Wk{IOT%JpJ@aEKAoXVm?#NkBy^&htz4|o%32Y?%96=?vt1HjP?G$#fSJwE z@!9w)bg+`$+-vjf@4plMk`uz0%9Ourkn71Pg6Va4nY=qE(=YY_#18WI=aXxLbhSia z&CR_z5gln0-%V&wdPtG-^nH3gbvE|%mBWw5K7q%5cG zWr0d^+H3d0iKh9RBKA5e3Uj-Cz`tScHuZB+)=QTj4ZL;u^#GyNwDfNY-=~@` ztL6kH{YV~3af>$|Cq^EphtF+7UX)sj~PsoSvizzP3KioU3$;CP0B*Y`tNv&*ZTk$g!u?a4EX4^M6r2}x-}$^l z{uAB)@Rh8aON{j!LITQ8yq*+B6M<0U6%@Japk>r^I@f3nd2%?udR$c;SqN@%5jJ*J zv4dn}FYt5pS4wauB^A*+>fm3muw{D)W4-8&|q z|KQUZA!chhP9~P7OG83x$89%Gbh@5*>sZT^Y}(WE({zk8pM=b4=y^LMC^e0%h_-GK zeoK)P{ol;aZONE1NXI6TTXT%Pk?@9KDDSJMgn)GxjKlH>WdQ0F(GJnnxStst0xCH@ zIU40kPOmB=rj7_Kia<8cG;(1Jb>Vt|*?vq^4#q8X$#?cEd9<0-(s5Ih?A8QT)J8fs z7kUcCYki6-%8g8LY6}z&8tfo+CAGBdvBk!AJdL=ZCh-f(GZXeuYQ>Rvx(2|f&sfab z;wb8H(?(g3*E?d8dfadydt-3%7p2q;eCf7R-0Fc?ukk=l8v==p{ykvF9FS< z(|4LBbOqLc&}(v1lV31$cMaq@$W}|u#Fz<%kb5Z)V&DW^(f(AvCS!OT3QXKM`B4x< zwDYc0G)2rYI&YJ*pR|8PnR=Z{0XP&?_!-4G3Z%;*Ha2cLxtiZ&eH`^svE?7fH*ScS zv%N^dU;5|RL{LffkoM6N@{cP7BD{~wS$w=0@!Q`LI*xsLINZ%{I7$+~_G1(Ycr5gI z$i%=t2oo&p&wZ;`C5d9J`6l2^CZ^rOEk<=Pf$RKP+1DIlXX*Lb#nN;-eyi>#-T4wO z4qMAT;}@f0D6jk{{U0_QfR(}@2U_2XVA*O-N1ZmVF=(6D5@m3;=E_B0q1aqmXWS)8y z>ef=%zJrBy_PU~}1#HbrXF@`x`!+5Bqdj$cYE&XmcC{8QAwI*a0{_gHsGVu;p}5W~ z5a)wgRJ22KA)^}KkjlPjrcPH3Q~_KD45E%+r~`^%Ie$vvVXs2xc=n(GAbDs0OB(@= zA?&qSa2^l<>U-E@hi%BLq^ zi;9HSSL`H5`lS74>=6ZJaAcQ=D%clc5d4TTGOM469|=J34q*cix!&RpVvI~Eeb#}5^Ivu1uD_i=)41Kn ze=JJ^Nh(^xKp=Jz=v9f+z6BAdLw#tp<(;0W5S3EAp7c3pBR$ExEI5k|97K=nL}UD_ zvN+i;x>0-;19G{zQQm*iz~dm<+N?y9f!!)f$}QK2%bzl04<|WF5;i(E>%5I>}HzjCUT2;rd9PZ zf#*vA@2X27uZjDQJh;#r9gpQVahN3DpN%>UBE>OL>$Jnsw$f}(Ub}?S?!uC%$pG7L zBUjf2Vj|{wOsWU9*JwFpu&i({^8xi3auO{2O;eH=i!`o1jv9OCx;dK83`h35E4GPhWuu+eE?f>YrE-SX3mPGTD}^T7;? zpNc&~h|z$ZsCZGwpJ4xz)^DN|9a(1W;be0%$Ljs*!b>7_jaM4Sx6o4X?#+#=?@s|G z=imGT`?Z>J(=AHsJw1uDW#b1YCPLP}m3eL>veIPXA=H#E0u|q*Wz-awN`Yh;{((5H z5H+j4N{fvO6K$?f@b`4@Oke3{YPRa;X(jEwYqGl@_IzslAo`m}@LyIbzI>NLLRxaT zEXeZ9@N+YrkB;@RB7yrp40`!E<-z=*+Mh9}O`XK+dFP<^r`@Kv{)qJuTIYyA1dUvo z<4?AYN7Nk(>#x2OEdA4pmY76gd7`qLoDGd_o4S4C!uGt~ac$ijs&3^dI(&1pv$=0F zn%KJbWLgLpM=78%Nu7$W`$TR%Cq7F0!~K)pXxz7vuEKghKWUzzFejFO8#x>;&t0<- zemSRf&R6+?13e<|Gyuayr}Q`E$E_}WyDb8|LT2LlWbVBww}FOu;|joOrU!%HwNwf- ze^k&Um5*2c^X;$$`0!9#6wgiUY=~uDT0sO3`mkItl}c#jaJyOQ!$XRjpY`#1&~!CA zjfPMrcsWS3-wK2W`YcHt6X0Oba;R%t`-icH2b_M!?LTtmkPr^4Qdn6{w6UJ;0A(`u zEfDF11kJZ-3Q;|zplh0=2r)(`*`RA*Ocm4E{pt9^yLc~Pe)#z#_!2d~WiS3wHUH`X zKjCQ-2TMr{O759zn3omsb@^UN%XFS_!No--em3fAI!HmC0;9-tT3D8igAgrv;%wY^ zqgWR^ZMk&YWog} z;>DlGfHe%LP^=Tj4r2O090Jrnd$s1pQf|QRg~d7pKDRHhr}N{z&*<|rpFI4L%B3Wl z8WaFg#oEkG+w(Xl|41A(#jUVZNUhp){<;fuaT{)4Ntb~If02+PRKBVQ5JS(_L-aOh z98M#m{FH-T#zgIaQ2HY$IizI^O}V-9)bGTpx}a0bG15w=C98kBo*hry^(n z$$w9GE2$EBG%V}qJXN??8?!#{)@whOL^ClwIJ zM1Mh;FVEqDvyQVm7yc*w<4x|yOL%o|*u!(*5BPB`lQ?;FZ45Lt-%%!)%3TW|<{V+Q zW9iHdpLb?gLwLM1jc1{E-lM}KZMy=tO(^ee`!4ha#i@)82b#P?l)xt6*A1E|}?N3V@#p1zoV zv3!rZ+-P|LA=(@@9-A@O28BJ7LfK;JoW@k(N0)p(W=`Nv(Z2jziq;>k2SJvzKe z89x)5dE7907Q(mjy&Wf)yHa{|BGdLC9C6T6kYY%z2^{G8dNsgGotR;ZVal0o)xj^9 zOhQ&90U!JDG8#(~!>v+btunNlg@=JK=U=Q+(p1wPg2f|6VknX9LPjzHrP?C7*av*; z*}ez$M0xsB>2<18p+Qx}-m1mA-!2vf=-aH#NAc07@U&qp1f;JEmYKO-5`$<|!CZHt z0m`|L1o{B-^KNs_z>#GDKCF&ZrT4Y|g9N{WR#HWqT4NWzAG7E(=R>arR)*hN#BK#9J5 z(EoYIDs0}8j{*15@H)+Ae5?0i`1?Yu`l1$^b}>@;Xps3aDa=NSW4Shti!?x9#ukK~ z93-yne+R++7m%TV?ucoaMM6Aiq;w5b*eh`-Vc0QYCW4p|$hNcDGE3 z_W@k@xIZuaSf_)1MBq_w@<^f%}#wvOTWv^X9B4$2t{%uohn_l4m3@ z@8&;xqnWKOKDt9fa(xy#{Y|l9F1S(dUA*GNqTGVjdlK1H-8wj2eD`}CpZq?N2cb}N;_Dg!5*LDX$>@EGTqwX(8%UOiNk!HwU?EvM&%E7pL}`n5dESqcR~?8=U-+%s@{!<9eFDj*}uR@^-UyrSS+u@85fP z#EmH3_3&G^^8|X|(>PqeGiJO4v~I|-jqi0XC9=1$#T(GR{Z@Jm3I>`4AZ|Ge+jey} zw9-F_Qv~gNB4r*`3Q+J2`+g+w_$!6Tv|_no?nXGpMlYkRPY#esqq41t#vb~|a@a~Q zahi2Z2^<_k`d&T_v<$ZDl5*h)=Ii~S)yBDn`I1vyl9xI%UWo)Q5$AJ&qtJd)CcSfH zx#MZ;a=Y{bhnG`8Gz4ek-F$BS$X zENyOY@!|`SKi60mZ=_{QosfX+yhkxgA*B`7`Z7|CTOr^r`O;lXQ2G0SEZPLlRiqlJ zi!S@orrD&;$C?E9dyF`g);;>yMsL5pd`fB41=J|@Ow@^8)lHY|;&HNDvRsLhdC(HT zQM9N}i>5eD5BS~?%f88Z=mC5nP%wkvBgLqBCvXx;zRHgl0UE3~b)SoU>ZJu(78lX$ z3oFx?Eb|>{6f~(`gYoH{@=atfwE4ot4@<8S-fBVo#n+)*|gdrMEZ6 zC&a+D<-)>Iw zZmGCGL-x0D8p*%c7aG5$-0J-An#X?{-WUA-&pANW>SLvqC&~j#OH(y;4o_JSSXaKp z5iA=68QfIWP}2@22wLKDEfq*wZkkB~ zN8^Zcw|JBkaoj~+icB469`qdUB^GP={_@V(?wLy-r$rkI$m>7|r;Htg+|iK=`Q)B~GGcT`-H`U^G2mls89crdNmajddJZA9aB+cN{E#Vcx=~dcRB{*<@ znSq$^RAhaa6>=0ZW)k^ThK}~)f;4C*?S-_`egnTe!ZF_Glf+HWj_7n|J;V+=``zGq zXneg&7z~6K+iG>Ga~h4DP#n~6icc0~%Y0-BXSQWI7qyjE2b@Iy_yFi;%FC{e^vvpf z(F5qB?!}QT0?~xp)jnEa1Q7Z99otJLXU*sI#p`g;e+z{r)V087s&Mi^>kyY6bw_fv z5v`kwD=VvvTolP*(||?{$$I6U1>6o86&QvpHh20(aj)UG6NvdfnuLWVxqN*r$%6&t z|Bg|}w_rN`fyP?G{NpHh z&(Q~L_NRqZjcO$Wjcc9c`11?q0u*({pTEAhg#v(| zUkGkgsE(c8Kl3|x9>d{gv3hTk;H@)dvpND<^|Mtnpj?hk^6U7aF`=YK7!%cBlze#1 z`03x9wVWT&gGy}jZaICay<;&M%E_x(k4!M!ElHQd*PeL0v;oj&+( zRo?HD^l?gD&y#sn*8+?-bv&HrdN?fw)8(w!HWj7xH$k9T_ zMq<@20#NF3l(QfyirjvMUz>i><>1DgSIMNSW?)h}>I~H0%gv4y;gXGmGE`#B%__`f z%ca79KJ0!Q^;+xd2q$78q+sNNXJ{7F6dGAU;yKt&0YEQAs6?LwG}^$1=64gpljEK^ zbrwQ*k2tiIRO7?KoeZej#dS|}GE8teM41p9Wn?qnWBD4ZCZi6PO?QOe8v4Iz?kC5E z7-@{6FuXU$M66M?ek?33UAnB+#!Z+rlx65olFe95C$qFF_C zl3S7+oiJXtj_W4@Qx8%e#5vwGBr{9@Jd#j?r^c6)k;LbSqEcu0y0kEVut}&P znzbZb*QWO87BH^{4OXjEaG~;4tW9W1^6m$`#nLq%Tv}SJIDF;pH9%dAi@Z3GWO56( z2J@9}#n_-r$5V3z1#ppNIzkDwoM)t7L@J5aTJ+_MN77%TZMxiPXPK+Fb1e7PTqS#Z z_1U+pI{#5$DE9yBVHy2nF{F?*VxZ~Gmagyj{#+L%wiW=5jk;e)O7yLwV*rw`2`WlQ zj4iKz*NPyIdL!H`lI;)poQEayrqnH4;)86^RuMV@vg&n>`=O5A`(M!%wl3|l&(Q3a z8{??|&(d$!5(=YQ#_};2vcI7r+w#q$z(Wm~`IbtId|&cL z_G?8^qQ4?!_)M`H*c{*LZKsjLube1XE4k{;=RqL@@ zR`LmN?3z}M+s@F0<9!TKxg0CBD_Y`+R}&v^iJGZad`PRJCGwNShgpH_EmQn>u=e4-X=8#ETb^$ROwBx+txek#BQ;k+s7c!=-BZ2RH{}vgU8+7 z+l5r;0tWE%fX0(aCJP9bD^>h1PwQ)fUZEKWo`OQrRcf!4r;^ncaq$Mf8_uZb=8?;@R@ngEUSWFDCXnLYpcV%1em@%!z_x7|k|Cj3yL=J=F;%vAh{5(mQ7o zFU6wMC9qE;(zSS}#QiqakiHzdjJmFKSNJgmP!h>Jr`Q54YeLReTDS@beFU$ZeZ~36 zWW7PodPrP_M7(luO4?kWu)a+tj;g5Jr?N*BU3eKOphzFa}C zSUwLF$z#H9oK`r^Yx7{9Z92E_^o}i`=98eca;cAArM-?1wF{wM6Js@lcw@1*n2(h> zZ$6W`C^2ki9opz%E3wTzb_Z3I-mIbGF8P_AeDZbDsd?C69Jp~Po5flP)wncV+{ z4w)7g!ad%!S3IEp&BQI6{k=mx-tVm3FZ%s>oz!xY<>fquv#QaeV?QlN;aJgf3H1*4 zC??084=<7kGoa~-76(6ej1zKeGDCzv{x`?kOMiw!12Oi{pNKa96&Z)1^3Ri7X8Qi@ zogTT9P(tA0AqW8e2xuy2%_7TKv;u<&rSTvFZuez<| zrQQY~@RdbwdC@LlrZG@qIFcM}KbI5KP=HmsyscX1e>pE|h(W%ST1t(YlQ>C#*Mv)w z4ZFjk^R~l9YPz1(%{$)Sb+zjh)>7_imnm$OIz;ySKGpG(5en9fXAybLNLN-$1)v*O1XujL{C26OKvA$fttJGQ^ayP*W%k+kl6=}Wo-h8l{ zH7M~b-4A#<3H1)-*!?HneGb^03xJ3o9AAyX(e+ziPU0TsqejT$7nt@_mvcRNb0B2s zFpS23-&xE>jo=J`J`&9jsgYUkK--@&som$+m-eT?cLOIxoPt0KD z6aN=C@C^OJ1nJ;`ISQZ_Bl;%CZ2mrPJ%XE5h}CDZnDn!(l=C4h^c0+^*QR0cjlA+V&8&LV_;f{$huUC_1I6V5}PJB>Nrmqq}0ht_QiAMjwkTzu~ zx8-XVeJ6GI=Jt{X@qmhVTnZAVIUT)1*$VQQZ|LL(uQ~&o?OL?D0ddl1EE8V{Ql_(t} z^8Oi4 z?H)*SXg|xT;%B(P7^+${&M9|`+1jwX_DBD}m7Z+y4 z|J8D7blzN~>LvWoHMU1u4+{srj-Ou+#ueXshj;MCEQo_cv495pFoOV2`hF&V|Gyu= zX^JjgIFdMM4rMs=J4qTIwfCSR-QcP$J%2Uargi*>9!lHq&AIh84!Y!Z74sTXBDddc=P#t6ip=e`Wf6+R^|pl44XZf*SG! z?8iH{y`Ct$SFg18HXe_NKH-)WC-mP3<{cO_9d>kG@@zm%y#)se?vx=1*nUQ|n@sY3 zy#u%v#caQM>jZnzPTNU85~VNw`<~z9_WwdxK0lKbC*F|}OHmHUHGR;3|LrD3++cX5vfIlpDM}Pd8H;)-`pEG7M zdHe&}p2~c58zoM+o3H9Z`?yTneQPfn=H$@4&-ktH;~z-Jy$k|~Y{bdl@iDUbsQqRq zEo!_#wCg_3K z3zW`V$QY4oT?A;okr8+Um5km4!ve_g z4E3!Lp}T6=#$d(D`QwI2U2@6=svs_9`XYS(rq;Gv)JPn12mK@x!%^hv4V{gTw}ljJ z)46`+ZvVBwGj$sLpZhio8R?s}Btn7aGgvu|pRJIoHDBV0+h+RB4MNw+zO@-aWx_z= zSiRp7h^n$cD5ALRWryBwR&+dq={)qSO#SZ>vODp~S7}f`I3EnyMc4q`{^C>Rqv>BY+1ntA?N`2lTsb64lMG)iT#n-3 zkhu&^qKByC3MQ#8r53yS|Le6m<5CKqzvDbW$^g za8cCoEIu}U|COO*A=eT=G(r4k_kw`nG0dppEjtxdfKl@hK{eXr{!1+P_duslQ239m z-r;PyEPVi{1pD!PwN(2>J_iYm<#f0PAqF-_znkgTuBEFxgh2h%BI3ssk^9r0FH53V z%jSbtf%B;7zG|XyEjl-Znivt{FZ>lrQh>!F{&*I%9VGze>`p1IY&T$GIf~H_`|QNa z%iEv%bZ>cskX!lK+Hj2=flnJ3mhL(#C`<3U`@=Jp??p@Y>wSc9AK`_}!9H-r^zS`> zA?Uv+R*M>n({5Fi+Z&-Kf1pj!Znvu0$REPX@~NBjf7b4w{a&KYDkO9!t!K6BPB`sq zo3A4S^?$Ga)4_PJlBI^qkv3h6*~?yzPT==W8`DV`{;g1+tE1MY$Y~V{c&O98^MmQ3svL zj$mz}X@<=Py-8~{;^bh&+uQF$9*9K5$VGU19beiI(o(DaUC-ivpO1-iSdj@hq#L=8 z@M-Al?_YV{Y(r3?CP{Dg4K*kuiKK4P0VZhZgInJ-});GyRBu_6gCywQktMX#=+xqUFM^vinMHzqJv;;UN{VgGdXnP&v?;Q0~O< z7RFH4Bb=zCC`A{8aGLjWA|gS3BmtqsVZb$uUtZsw?YqcnVylu641Wd70HVmimqcj5 zwe4+8lj{Jk?QRm(wwA2yLT^6V8$?t-?uf3XoJ{Lp=&KjZ@mt}3K`#F|_&0-*@s#7- zQ1CzI_n!m)--h@9aP}5Zair_ka3ByY1PdVqcMI;`xLbm|21w&B0fGg0cMI-L z)yjja)9CY#Ya;MU4ZQL7xaJ=&Vyh4=VdUsnziad^qK-VqY29%2*Npl;$xhz`I2-2c ztg{eo&pHV1<%fArrSpr6hfD#ITm*bwy2hjSWHv`=Jt@_-R-s^YX+WQ`WaabB#-lu5 z&srEi-D6F%5z2iK{-}iUVK~|J3qX3;whq`}v>}rk%U3imv-uj@+!oFsE3mHDkE(}+ zPWgFx;g!Q&G{);od#pXEa*y$e%rnqB>g)Gt6mhfTa`ckEyQ1AVq|MC7bN!pI^k5hl zts|SmdY{JG@c!Az^BL%f0F1nJh$^Ql77G+6{9N*z&KRwSTU-Mztuovqp(dFrZfWIk zZ~J<#`HqlE2v{goafZO&;VT$rvxaOG&sbVMd1&cH zIxX6Oj(|>IcAR#iw^5rH?B=KS-UypP#-8;m`}1``xauYDqnHisst@0Jz8tnCHK0?N zqUpR5)BU`Y<9)6yW|6^AA}h2d%N13OWP-ft&#TY!B3cqhl$C~k=nz0f6-L{Ta8O|T zD4&D7BUg8^oMq|FB z((K4of4?L~^R~wFb*v_!l4Y|N!ruSAD~Jp~3fmqroOd93*68IoHKpP6y&tARz`q5?SeDY?HRW)$m>C-+nKT7^vpYbnu z@(kM3pKtI+8G?0vG8N5J50w#I|4ch=<)T@ zMDVn1Nic5T%;lVICqvEbi~<33Gp}k50;GD^>=lmX_0IxK?lc@YZi^y~u<8`IeX|E{ z^$DgDa^f{`|6w|u9&h+ZFt`%Q(6krB#Kh$F$#eL0M})@v>)qcJO#v#$4M5jQcdYMn z)|dd}i^=|6HMBq=(o>&dRKH}qafwK2av4<;A8Icd9|o_>xW^=vP#GZy=z6MJH3Er5 z4lpyuM?>FoTX78ibRKnVa(WuhFaBf!VjH4@4T#K~e`Li86Jy>jnlM;Pi^tJ zY3}N%U*H9kfhxZw9S<{0EbNt2mO%ZZGBqI5n3Mc49@Vrtzru+S9Rw=Bl!k0(YW;7A z^G6o?$AM>?4B^-Bh`Bga1G4k)i20psL@rtzg7`5IQNv~e7nrL+gXpNqbtS0>q?D>{ znWu?ClR)CRb@9AiTz03(gJS;*ssGU8VxP-M#mhomYxdztRrP*3^J9MS4C96iAgff! zh%5&$O}g^9l{SW%5Y_sbw9M_sVHRSW3nG1bNR^T;Ospr&^4Jts$P%@mTC|kQoe(`^ zvflydU)63yjo#WhmKtdy%0zueD@J?zr)h`(8l9gYM0@Kp#cG)fB?`xT=&iP)?@*)7}0{5C53(yhEh~ODCJt zVms>#jU&nuavi@QQ5<8kan0-Oh>pm@*fF;l$m!qBGNN$slqHp~VXGRh+}#{dh_}mV zNx)_+qLOe0^nt@QLn~A^F2&j=SF?NdYQFH@k5%6BA1l9WjsHK2&woMptU%PpSDnsj z57$IP@_8%z^t(-V%6q@-DiuFmxa&Gx6*xgOdUhkcwG&*8nnKLj^k9q4Ud;H`SpMO2 zTh2F46||VmA9&7@PIPC_eauOj{bG@}kR~&lf^Ot?Kj{wsK~(;SzyI3RS7?!47V-T(y>QNu1>>Gc2wS zHx7^#q~e^g3vaFH2ye#U)zSaLnEo^Q1K!puPbAOQHb7!YPFkEQNxFu>t{F-V&(?@* zM1p#JqKj?bHK#Wb$Vd3n^A1#E1YX`0=>ZckFJZ*5U;6Q?V7<*MspFON(Rc6-fxW$*QxvmrmIT}G$cow(S1r-{v9P?Yd@snoyR;=kXcn}^e;%`vdns(?HlcSxmB)Jy3+9xTqJ4n?*Z9>FcZlLrR^WA z%YQhzzdd-32-8pO@m7rlj*k+v!3p!Bj_z9zg@7d&6MO$nRoR)+i zp;$Y(1{1SpX#@TeW1MT94FVBF5Aw%lqM|kc3%)~hxF}|=#UBh}I*Cp+@y~rs0X32) zDjaG{idvi5Lz0G)aKNDc>B6(Ad!2=3#WtzzTIvsflSuuSUomhXL~9>aP$Ad{B5bVn zy|da0P!1HbYsZMoii;|Vw|N#@^=-Z6+tliyziIGH7e=xZv$Bfe`gjM}$WUpdDRs|8 zVu0C_Y-5al{wrrh^`S6R{NfKY%}{N4Jww;|rgYo|jBd#K#lFoX+|8VuWAj6t(vi*F zTSRSKl|S*{{H@FT{j9yCKqE1PB2H%DzTViJ=s;e=;of*$Bf!4*e298wIKwrv{rZIl z8G41~y946Dv!Ue>DzI_fyyxqwt*A#okiF_ zQ#u|fG5JZfm##CzzR;-tBBLXlsKYZ%Hn`$+Vw@%z8&zz?X{vB-;-=&9=jf*ij>-ev z6w2$CBho9h1G1a4;k$ZMTN`cF^)ax!@=Hl~H`A@ykBy;!ux5X}$2%A#0ZU)#m}ApP z5vr7t-Vq2Ys_QTj9ORHAh@|B%_kUxR}P~Uu} zgwayFHg)BVx6!nAIGEzSACKxm+r2e%{J-65dJ7u-kCv=Iz4HIM-rrwISA>zIc2cWm z&TkJ9413$g6&<0eZAMap40wv`XS-e-w+_pgL10RO7idGUNQKg6M77PgxJ$*2(|O@bT|c{nLrL z_<=<7b4<+!dWT>6b1c+4YK3BJ&TcA~p`C~jjJmH#wa7m8vV21FHsXf7tXRyWVeVE_ z%*9+*II`MY>}B)4tx+M*Wet{>L{gz*FOw)Q07FL_V0@qTPGh$DmB}Y9;mzPsakfvW z7nlp&o3^emVh36t@P??`s`Cn;4~MZbM1X$4PfkvXYiMZvcs`E)TfWwsPVqSn?@v2I ze|4kfsiDa*8qLhaZ=hpkv9=~@Q^Bsb1>TMC4dC>#w)(!tH|c7S8^BVqi5-4AmdNnk zAHtq3@RN`q-Tq{GAkl}Uemt63_es~i`fcLmJ$po0JbH|gMv88C<%Cik(}xZR*+EO$ zCfu!=`K3LAX?-2cb>MU%@SXbQHVHYur^=oJlArmxpZ)ONsQItU`|lUi!{Dn9yT2wO zximm!*b(w5WCUV^Pxar0KmUGfB53gf)9EL~dii@NomQnWEL}HoQGsq}?BW6kP2wn; zZB|xX)MpN=+L(bjN){pwSVl@{>9C|^9S|8 z(9b8LjZ@OJ!^fs@bRg&s-g_rLR}sa3>zeMRloQna6GAoPoZ_Z<<-mg@!puIkdzdok zX0rH&ci+{iEgVg0b&u!SbDA5tYdZk z_9p`Eda!sz{_KryK;?;m?FD3^$0J%L@1ni^%)ZvRxR zXXi$noBw`}{^Yy<{bITtLbU8rWN+S5Cn9b74QO`4W8FlsY<`%hj$<`wAmvlXMj6`M zEmzgP*4;p~2^d#BMT`Ct_VwcFk{RbuvyOH*P7DslNIqQkueS2D)Asl&`T7?bN5s>4 zV2(hxo&IQ>s~>pq<2E-xn1aDHBZgIyzeS(XL->_ttuYhDj~_phz6w&<9zQHW#rjn} z;~fUN2@JJ3V2$un?L?GbF(K<&4Xml76k-4y5zpfGzb1KOszS7uV3FI@ieK;g9b-`C zEo@QCSkPuJS+zVP$3mm>i`7T5@rmi1+Ud;2>`G6Ve$glGShznw@c$XV z^&ffJ|MMeI{UgBAQ*&D@gb?Z?P-}9j@m>oOu7&wob$4Mh8H~X*hHQ$L>?zWGD9f!F z`*0?B7>Yi3ceSvPdIgI?y?%FEm|f9cNU6X5gB?RnAw(^)xlZDA4--4}z0%Gd#iD(0 zg74!H!2jWkfdf8T`Uw3j4;l~gE3s^tK5vAjob{+>|2ju+`qi5R#nE?viQ>(c9#hH0Yks@k}UPi5Z~GBRhAW_{%bk3$Qo!Y zrF>P6JU07-Nf(oHckQCjUCs*DEViADso1%-f=3oS4`xYI9D_Ztsjkx@^@{kys`Lp@O=}_2J9m%w z#_D@P6R~v*v!WK)n?qaI5FXu+rGcmox7R-alDRTiX6~Dm;+}p-7t04F%+;nj3b^0n z!auEyKpy1sOl<>Ys^T?loCyAy<#i!AmXrmk$4!}aUISyVj*ftx-1z%cUX>|as$#bc zdx6mP{?z-f$(R$e{L=+UqtZQu$3lee18@Ay@b|`{I^1fA(fqXeG~6n+ZmG{rPqpqZ zn)Lr+OrC9$>2_Xm{o#o6a~)sXqn``EP6c)SbWs=!d>^bEpKH!2LYuUtttD>zG9t<0 zu#3Ce-V?)LCipTAl=5RT1j}EO4M43$?ar^~pCgz`=P{0?mWT0jv;}Gvt6R#Mc$GKR zKIpjsk@Ua%#lLz{w+x*!VZ}(=Tujd{`ANs->=Q9%fk**=LUX}TnDW5$@87TIUF0nF zeaYu2C^^bE_IR3Kb-kcEc>=kBy^peeschypqJ!V<9M-jMz}8!MTNcUl zD54D@F^A<3f#~}!Yv8eC$yrHgS0Ta#X~}H(zsx@U1%cD;p^hxgWxNeVjxXmWIBhEhgGriqhwiy93IUcqW_scGIH7sy_M zSM)3gDbRPYr4AAN)8e1Kg1X)F)g20$0weiK@w^vGH!J}yG4klQ zqY}MDiySbYRW!xhsWj5)cL95@bmA+2g7yr+NT|a#(44I{kc^ISow$J{WvMRRyX@g7 z->oEf?a$oLRL<89jPXApXyWu?1YQbO^1L6rs?0a2*J zK`SkFaHHE{x_LK^-?+Ky_Tqr4w{~mO-g%U-1gZoU7+p$w(jGNhDFvarEOyh>(cCH_ zU&7ELW3{?DPJLZBT|%$2w0M(4Kiv=cW&QQ+g=Zu{-nlVrQ2&ak&zavEUm@7>)p_W5 zo`P1Sz~ag!g~!FBdo207HoC5jl4;^U7hmkbHC4b&Pia5spTh3;Lmo=By;odR$vsn1 zP0Y;p`WQm7bz$DTc~jr`{oriBLcw9r5vKlh=}>mry;gxP?<U&%|AkAF8(~T_n)!&H(&dD4o0#dltWi=600H)Mx;+YBamiZ z6I}hK9d%tCHP`2?(_hg{=~5dB`OTV)`3`kX$|S0v_%pDu3OBpW*OKC%P}Zk|+C$>5 zhyrp1`wyQ36fBVk#nV5*d_Q)&3ZAfOA^E(kr7(6JhO~rncTf>yFVINQALuyx=CI$5 z*@S)M*UK2443gk&3@$_(@X(n>~4;B3u4I{!htNi@fHSw6Emh}MB z>*b`H9wKh_*Kd#kZ_7@jv1rLz%TH6g2r#tljWch#6H{dH0wL8)I3-3ZTQXZio24DH zTbJxZCBrz84On>C@xz#RjlwrNERb>9cwk2=29ROZP}`qydLSN+Ibv<3xSnREx%`M8 zAe{UDD0TbgSorQ}%*}^hfz>a+e8ya))7QP?gmRVp@uW0@9Z1DSGgzD9g>jgmJpB=< zzItKse+{>w7~P9gFpi>`U69n$d`+~U(X9|C?z_&7!q&S`j`V>YBqVeWHuM;507TYxhTA6PocCA z+pI8MJy04gUD7y>f01;0w*7X_KeC9KoSlT(4#wfW%Em$4BlU}Jd|w^Jh)x$e5)e;U z>!SQn7AKVKl~~jYyHTYAw`;Ah(zD! zeT_a=uWC^pS(33YO)9d|JSp-eeBP3io(*zM3m7JD){QO7cUxMmIWZb4!0PG}E$^B;80{+u*1yo8Sy zIfAyz-B&4g!PuqhLKLWgM*rsaI>Nti3|kNt*w!m0qCpjS*hAX`%6H_6BY~;ZK5rxL zn3~+7Pvj`EO%Am$*Spa7h_5cn*#QFOyTnPU9+_ zqw_C)^f{wqFoHyZ2iNetxxe)8k1pSnNFv?LD=y$%k5fO<#o5#8X^FDtL4dCO77X5$ zw`8k9P$;~Md|wNbGBtG6lE=sS={GLCPP3cd_L!7?*aH< zKNh=M;NSkGVgI*B;5jBV=El-C+>3%3F_j)8m7qX=9wmgv=5(OV^{r+&RR|wC!#^ru zMx6$a(I~hQZ_u>O$zXX-7>>D=J(qJD%NTmgcel-}(K^RFmdK@zkhJzCy&oLb41=~_ z73Wuqn&B5^uD+w)FDR2oirZA#Z$w8zFZe6C-V$*5FKNAHZ2n!S^&g({b24b7^CReR zCF*>Lm30dJ1%s8hSA^~?2|-Q~tz#DsnCA z1cCh$6!Y*GS_9EZOr5lH1Fm!o#6(Se%FKf83Pvsx7~Q*@Y;iX(2*fGmIcZ&nw}Vt0Pn#BRmeAL}FrK}rR~6=SvrE};R{<2+VIn0W42f^L zcTGI7_md>Vsj=e}C42r4+fL81p_^X4G&a*x<#Rn_xLUev2>JBX28CknvnJWs2cknY zuWZersrt%k>xLv8&UY$P7%%tgDh5J6cjxKzxN6T*{Qd{pNiaQtG-8)NNcr zI$m4rqQ+hcjW!pvkffeX)BV@uqU++@#=C=5AJ438>+3IUc^dtAbymK|DEJxr@>-1K zSsTrVChGqPzAHrT&^Iq4@${4?jF#*>0DI6LV?7uwadSKDhmWN_R45K6&}3LCuf&K~ zNoYt#6*>K|R=ZknAxn_$zphQp=ByM;b-kribLu@tFD!^KF)|}uTbcXkSI9*)TIhvU zv~k;2UGYik9e|mKM+dkU^wDWJJP%;zP~|+n$MH7#=cD*4vgtQ~8)!+yD%#O$xEL|1 z8LjO(=&LNdsAR*TB_zxEhg0y93>Ncfn%x^@XUdw6-@G;MfxH-wP06)#Bd+WbMQ$h( zi3J8>(cr}fzgRuws+5NB^FL$+-|l6jC)K8XJ!_gOv-fUn+H{_+IZ!h-Ri$9HXGOP^ z=r5vD8ed3^jC;7FP`lg7VlqF_V{%-LU~*X?MS$yM@(zAg`;R+wLW!VtjYO9ykSZ&F zP;U2nezmo!f9}vEY8*!?C91cowf~T}5zR{hULRt%T7&b!nKEvHN{kRE)KfmXu+ zEA0LY5HvC}a<*1A;`>bI50blu^in35vb*M{TQ4MvHApbuUqqNEELN;`?HYYQ+OQdI zQ)2SaZjw%UN0TMmHJK%)NKGw>9$QtlH%ncp?I9aW?<%q*CLPX5?NXkGm92FkU-|3{ zFdVsSHBZ(;!IfNm7Lvqn84E6LQg**=Snhiqj;VngtJvCjk(N!yKA$!S8VpsCgz25}m4ews zbdpTu9_DhsG=ONI{3TefJud-G98qcE`Em62|>%K&KxVJk~OR*UuF1 zbjg}?9muY=>LZKm6++=Pe4b|2j&K6Zh?nU`ZVbc?060E?uD0&*9}E=%$W!>sZ|yxO zNCWJOy{nC}9E^c#VfNPgN~AeOf@pC#*6=Q~;R02yeR54x1@XdOzRH9`!3mf3&|9~NzR);Nu}obh^+|xXV%6HLM>pV^<<~8^bHC~r2fJg^I#Dejqhubb2waD+yZ}x z{==L9Rx^^(zIjzln-HO>zFg-Y zmm~HJ;^LZLQW(vy%tK{a;)W*#v^=$-AID8iT>)qc1stvwsNv3~VfE1Cq2X~}^#lN1 z^aHrjg;L(2Gq$9qM9XglN?xPxBx0e_L3H)vD|fm4Ia&=4ebdbstQf;P0MtztKxIz< zgLH_DVl>waYwyF-PsFPOQxZeN5X=}=Mt>v%pWMk=rn#c@&Z%k&lRm6yU3?Wk8~2mc zd@#XTWiee(0>*&hmiNjtu#mCk=QQIjn_b_zuE9eZUArP|olhRRP~^HD!q7q?PnHzQ zVUdh}VzrPbbcDwCGr(9AH>9f5mU zSgC6gWAKGq%LS_hIff82$>lsUv_`E3Ym@O%;Ep~3dl_gwS1qm6$9g3Zx?DcX&E_GLz*b2#MYDE>;&iq+dz)Yw$a38 zap`d`)81Co2r}uzEzJ{|sx@d#xotTo9L+jMCU9wvTe2oyYQM4M;}twQK=;}vBONml zjf^3hZ2}ionW$#zjjaly5IZgqc^-b+;)WJ@+UP`hcRk$_t6|ynExP6YymSD7ZA)X* zAEg6OZn^k10AC!=X}j5rCWcEShG!owoy;+IxP|C?vByYc1#GRZ16G*Ib2cgj5Qkp& zK0?s|^j)gmrmq12ie<7~;O%M z4|A+N{~_m%+~rFz_7aZ35drBkGR8ebqd zg17y->X&r$)GcewL{=wx!D%fd=MW$rA-OqhX?gU#F+Btx3kzWYDT!rmCudxXy@Mp%6s8x?=BU+g&p$a zUSU>NnVCg~s5Ft6hmFJ>#lPt@Gsh5S5!8Ue*CsYa$e)fYi!~_EW7(U{^okS3R+eiU z7;Vl%bo97fbR3wg2H$<@!FL^`*8%XA%`3m*C^i#}`+*=Xd=Z_?vKinb#fD2 z^@;_9D9{7MsbeC62W;79(SEv*wszrrkntS$@W-&$>+{{Ab6b$Z-pp!R$F8jW5i|;q zijG_LE_EG0A>mb@oI5c^s#E6efny5|Y8go0`^Mm40di8Ab|-xg*uc*<>$H_Qd$Q`9 zn*K+OB8lwPDvAdsFk7XCy?J@n&E8Dp@w0G z$@6~HoVtYoMa@tJhoT|#SwxGfXT`97)s~m&$pb?up2I(G3bCFna(B@Y0&~>F0h{C! z`%6R_jEn&-#>rnrTcrd=iLc!yEKDP&9-Ot%E%#nwtC6inH(MgJU^Z@h9C#NKs}l{$ zaA#*jGN!}X*w_-~S>VNYE{C9R&fQz&!>C$psBul$prvQ*51AsFyX*77*foMsPc7K)|g6wqc z1lUk;c(&@YE}jo6>I6*G-4$99)mx9VEP|NJrbD-rqYjjTL{@OHF}71?8z0|sfZWR$ zx-tsTxhW2b5EQ~^0_t^E86K9mKYRGu?47OvqcZ8F18_K4@Um8JtNR%(2!Qc0 z`Z1pU!DHs>0k>1FXB^=_=vQu!z|`L>X2&_8jpa@~*sB)r@l#Q&@Q+i5SbrknTNXmX zH*es2I~Y^U(am=?RpAC*k}$ojwC%48h?#z{=6v>yw?_3?ia|JXcpJfh!PVWPs7Kaf zdIBI!s8?0xa~xz)t^BHC$%>9hyF>9B`x_|u(m&=5LGSH^<4R^`(wo8zVg!sjm|Oe zXPBOj4n!Yvo!jqN-rtO9)>3aa*;{_hi*bGdRUq*)_?OU7R2$P0sM2L<@4{9K5*?f4{{#YQD{WsD3IVQwGfY7cHF@7YpE7y-Rv*0am#m6TF;CT?v z<1IlAWod7}5#`3nA-(C)YG5LC6J-i^0ExWEE{ufAp?vg85}FUHk(T*KbaU-HN^u*< zB;gA@@~DU9Px+t3QodFRsV^surC2A}O>^aIw)C7nA$haZi>O6feCUSRXvn~qzZ&ks z*w*oEJjHQI%}!b6@ERg}gb!Ulkf)F}_|(n^OCS%!=T%$BC4lTxOm)9Do#v%j){sNv z>~{K&@!1LiLC+w0rpt1&eIriC!kwG=Wts z6sJDcG#0*RxVG~Krb^d8z9VvwyAUizwPHWTqI(NpX(4b4?dDCihCf=}|O&6M$0FT!X|Py#W4 zP(`G3Jsu~`5wTm+AUn*p`o~jt^2HV;Aj6wh&Pk@ z91BV35qH_BIrK`1JiRzPqvG4P-JWQw_tHNLfMny9ohKZDX2+5wP>s`beS5^}@$xh> z#C&-IV=BJCh||V4J^dU&FtMMA} zo^S=eR)w~Gz>X$*)E~ zd({)FbiW9*!VH!9cC6zO02GMjF;47~Nf*Ty(*0f(>{54Mcq8*(?7FgKr=q-z9QQXd z4`9P2VL2~Yfh96PRnLJy)PS_pV`J|Cz}vs_LH9KFiy#rZHa~g=G|;Z+yY^r zQ;_2Hi?||uaD5RL0WZn%)U^}<-p%ZA+TRs@(`_y!imFNY1OhmWoJ)PgkckVEn zh^LO|W;0b@l@jd0W@SAb8zrF%SQ(m;LV%8GIH(`+VdVk{9&XjH$qtxs~yd z{Mnd)kW6EGLXkLGPm+K0+lXA-S$_(rG_YS<)7xQLC8@!rvI2dGIxL0Mt#%xML<>U{ zNUI@7Yf`(URk8eW7;{t=3W=v-Mu~$F$tEe;e7w|ZNM&nk9TDY{E zq@&oLUtNq$=c*;hLrP;INI89Fdf&$DuV^LmtjK1QBf3*0W|<3=6Ni_?s2^%X3ob}W zGb~5zr=oGo?P_^ADadfdI!UX!sX`i(HujNsN%1XN^?bOJ8Wi^*BU$hxn*qJx>nxzb ztR=qmLjStx#|;t19)6&^eA;pAKzmd)%Enu>Y6?s3y1_vh+?j zhjK0fLLv%|IjN&Jz6_?~KyAbXOTX`_&-*KIW$R}$h7}n4P!<@{G_DHSVOQf~o~jC^ z1CJ&pwmnJ6W+RUZ>Y5KV-Jvw$8q8ZY0qGumUGm*I*<=l}o{^GBJw_eOs9N$=U_<96 z$rHU<4X{oe?QUw6+a-1>zPez=PTw?XrX`vEIB{`6^xjA5-V!b9!2FWvNwhVi>#QWB zco%n5ncQqTI-8lmXU;aFqEp|xzH+HkmGWNZ;nr=xPH0(?C;3dnW|_acg1iopWko(* zr9DLW;k$@0ou*#;BN?9oJXS5BPu^vm;_$w90CmYLtrvWS?Qh-;`HoV}1;mh%m07I{ zk~l&3Yvw;4gRHz74x2TA*$YF!N8^3rMGVz*wnBYOY-W2g? z#7j!S^GUdAWH)=2at-7wP&>^x2T_k@@Q>Uyi)$qnmD>3<0<#SF%=wRLB)OhhuucD z{;CYGIp2wrPpS0kO;B(2VlyUiy0jWp≀uIAelpEL>8r71aLpQ|_J4H^Q<0^6`a9 zYLYK1k|H9i=owW7+JfjM@Dh1UZ~Ka^XBjKh9cXdMkhEv$Iy6MoledlRvseyrB1X6M zDz^6VPFnXLXwJ{G40p~1>G3w^$lKot9Cm#;AK*O!YPJO@E6?2Laj|q-)N$G_ z`J7Dv*M}zSDHHnVqivvD7mMP4H~6L1KS6lz z1nn)E0F{9ddWw=CBjY-L(%#LcR>PSg_O6DN{9IqnQe8bK7 z+$M>MsfLc&wnxmU1wnz+L^50Y^{b1yN7UU}G|&d7=eJ9dE}EsZ-IR-qSS!dbX?|Dm z@%%1EQZlnzX71kO;(({F;*{_721Vm($kJs@Q@B~=kjR2?g@nROs&`*aBPwcy@#7xi zJC#ZlyJX3u%6YBd;pZj?t|fAm1nw8)y<^6YGw+h6LZ|(Rg%yEL6-k^V#XkLk-PPDJ zYmEDX_V6_Iw1I=84(k%y4Qc`DlMcGm2=5l}q4UUACX`|d+~GVgsvv_*&Fv@e6my(% zvfP`!nH-1t#YJQGLx?U-5#tx_Sf2##11_gN?YZU|QMRI*Py^RJ?uQYbIjsAxL!Z$B z*7tbdzYaGXcjN5W@0J7&yh-8r;G0UcZ|k6)9cGF05Bv}$UuJOpy=%6^+V%2a@i=~t z4tS^*jv-}h03%@F0N)So=JR69uA`vkX~nRstM~Z;`G&xSd0;+peNaIw+QwUuY;ku}>VyZQEJ2HydQ_AdXlVe#tn2XOp`k={?$PniS2 zMuRS#Z0!td&$XGgc-c8}*bF9?(5U$X*-h8CAaf_6k7&1oc{9a-n|&9wd|g{((Xl;9 zfk#~7?}Z{W@AL<+o9##5TiJv$5xA;#}S-|E{#e_Rh*7HWF~vFv)T0k z(o<6R9dUPmzk0;|qSD~Nw4kTkj>#8GJ+UA^zwhk)I7sKV{T^`Rvw$1kTXH?D1`=+o z1!gI|Q~v!4Bs!V6(-G?3&f?!lDe*2xJs{HOq%Ch6bs$ z^Yb%}J5{Y#;(uIjyjMWhPbiJWQ3xSzl=(O;Y(AH zGvcvIwDfzXX)7xIxXjKIclRA1h8`^T_xnyr_=cOFK~^M6KQ}Jb;-``7&!%vN@T{o_hG2fraIz5Jn<`KETaz_2IbsgTq+$lKYLh z1`yR2ftF^DhpS7I$AdfA)HFbf)X19VH-CIJ7BGcR?nx5qv@9>d~tg=@4Ijd?%di-$EK&Tpe>8< zZKQd>85nRug0YN;lLPdMZ637g*3j)eK0->9>RSXX{_074d;~v8>+YqAjm#K9P@&-o z8K@c1q3J0)_Gob0(M1VT>P%cildBKXC|C5RUdAGi*%%_tCz%tzHLhwGHCroC2AhMc zB2tOK@ELKjn`MiWy2!Lb4kvT44mP{g;3c=d*yPv#130vY>XTe1xR8As3A2K`it z78q!u>OAi>5eFE9OMM>hw1wZOXY6QwOqQkU>QdpH*b9` zzWF9r&h*Wo>pHQYPwN2)cd7mP$?wTLf&XC7|II+@je4?YzPj5O3UK+KpZwLg)=ucb zBc}3^M*jZi^r!by>6D;qV~g#>{c?}X`ODeS6&4?B4mmjT!<0(2a-&>PJbIUAXFfq!|CPoQnz zea6<_T%YfkA(GdD4jH1oSW$V1N!jIi^TGT_RYo&&4cjL(^(DiBjzKzPl8&iw?7DC- zE@%7jD{WIc9Ci$KRCi2T9Tw}mmFczhXa`>T&1w#-UIxf&5X5$vE-zWQ>8OK?9~Ml9 za@%dh^_;WF^schzFE3}5bZ%tkZ5|9nA|!`U8E5ZAxYO2$l?s&;_$dGGuKdrH7{J0e z2A{8BLclDVby?FTEtj=s9bc;TXupzcl-XCaYE78m0g(;a{in9( zl8J(cck#`NfyR9{Ylax&Us=q*R~f{Mi0YKz;~2t7!T<-G*#4IOx;M5AJtD+sR;%3@ zY{H=7wh^AfJ8fCYe@b9>+%Br&{EZk4Hm{o48lLlfN-)1U->lERc&-HgI9Xfs3fF0l-Vw~mZ&#JJP{5d87h5Y_d^98ZYdikeSxp8#@r-kE&V5Y*eJT$k ziu>}VyFG=Sm3>w#?ZzJG#Q=ue(VSz^w|a9=U(~@a(fOkQ`Z?Z~6IQT=1#J~dZqIn* z=`)Sv(udLEhn|OlFC9$cH10Q!MS52!g4}F>9ozp1`a4qTdZf|UZH_8wM)|xy`Fd(D@v_)RxG>qgIn8VI-LbMn;1&X ze4);|y{0FO0Hx-ZBLUSk6mOx*bi&7xWqz5092XbPSSEd8dZ-9F80l{o1+<7DePma6 zaNr9?^0}1<&EzBEa(yDXb0uP(4_TByM0z}A^Ot4_LPiWO!F=cKZ6N;3_x|fHtOJI- zF5(pOub=AyS~Q#wN?N2 zham0Gty0=P)4!dM0Zd|IVs|6mMP^1u#*D?qkOI`wA?J0s?5X*&J@ZhjUD*Hnus>gH zD-Q zGmjR)AF(Q6igF43b+q(U{M?G9g9wC4Q_rcXDT%ZWgmW7Cz8fuxq-#vwb!Sh>r9;WN z^_z|Jg;y(JeT$Zs1-!prNM>5licwA%1RvTK1d>_+8f+#n77%LXWkJkLiWOfY<``Us zIENtCnhzH=cZn-EoeNGQh1OUx?u&~5AA4^d73CVf3k!%!BZ5eav~+5L+k36E-Jbu?f3s%Rn)iL4=YHb{U1qZb85K)2CN!zX7bB1*>nT%yz7hBc(_FkTLzJCK_Onbv#ab z6;h|aFUadLk63T4?Dm^gT79`j^BZq)B@z&}x_yWX+pXSOpp}6pBc4hpEs%I&8MAaMpIKWV{ftv$5qt|P zW>(;_7^9mpbPI0&vr160-vvzpbs#{LwpzO4-Gi?~xWl4iZvSsZ`&*L+mz7E_d8ZNru+`4}pk5Vvj#OrD~s=o>M{{E%`HdkuEp~@}%AAj?AP4Ukk zc<2C)m@6GC@ka{=)|smeT#c%sVcvhgm;cbMt!}qSJrjwwPXE^?P2hf<`Tw~9{<%5- zhfPd)45;4`ImNDj{N+Da@DEcx!U&wBi01n5gQ)*`(*HY<|JjRw`;_oFV8sSm*D10^ zPgN1~7B+rcqMzspF_nRZq^7UhT3|%tF-Si)eapn;JgQ7YG;U8cK0axVS}>D03*)l0 zg;PWj*gLq|omo3s7nX~f3;)?!ww{qDR0dGu>Y+&tD%x?xq1i2neiD+G->b4^X^0lu zJ&xhFl?$Z4c*SO-p4_V~+p;GbYnUwQ+FMRdgeW}{G7r-Qg?;kO|4vFc=MoqkH?I|XRM{qgx*qfw) zV52}bfC$J7-?5Wm{Kvic`=kHyLnW6QfG6nZY4`!E7e)1@?mrghGthcQQj@Q(KG<poccVz=YXR0t4w?n1)1P1s~7hI;V|Midm_Cv2|Ks`Yt``Vs?PB4n- zDJ4n5r<5U!Xs4n9;w-%!gG&iS*hcpGB$Y9B`vpzAJt$4LF?Z_?=sILk{|DP2DZYHh zfO@>fgJ4~Q)F!tdkSz%_>GpQBIPxDiRSLI0t2X|+!)pP`Pc)_e!u!i)3%{~Stjx2R z%i8*pk2aUU{T&U0ZEUl@tI>Z|OaWgc4X;Dc=+qhph_DG|@Qn&Hko_tSh>0+5e*$)Th8S#R@W4sz)W=*5-+y>`H-Ejg z=Y;f?*Wwv3CVyMwW%F~_Z03#{tqId1VOThIn$v2Rj|I{cvsj@Fe{|j0wi*bN#yo=8m#7c1`d*)9qKUalw2z3YEu1kA77a_{ib-Z+X0W7`Z2qvKu6EMLK4CNe3B|G1O3 z;VCvd-fYT3!y~V93+0=VRmKFyQEY}?oSxVz!C@D^P0d!jwmzQgH|!okU)?>r?U^X+ z%l&5_zbtN2*j7qTiedX(bVR>2)I41@SFHl;ZlFrzv0th5gHE|c5h)uQlFEGIj)6lx z)Ci6|-E@ap&a~C(bCr7-FLU7oN^S}}x;@mdJ?hqk*UF6cF%Z>|&y=7PI1_9ZO;ZG) z&g@L`*6*BqRQhMCCP4RYej=W1Kk*^ra@M&u@*ucOF>&!L#n>)W6=-z5&L%s@TGda< z9g3h?#Z36kuR3&&PeG!23s!}5@0G~o2s+DAtA6zqpN`owyit+<@0R@^*ZdYaWqwF& zPe{NV>A|E^N(TDFcbRHO78=RjoCr-Mm~OxRCHQ2&3FL%aWo@EZ2lcLzAqvMgxv5q4 zx+pCqmP=PBw776|zrXvP_xQIff1d|pJdOhjK5f_pC(k(n7iCdHlCdC~ytFIIYbMqA zwG5H3k-ZocJMNe7e0(GI{*!MnhexUe>&0``R{}k9L>%o_sOTm(xu^R_CAdq?g#1bi z+k+pOKcM-8birRLxbWZP-Ix|IY|#70O*0Ld%It3>fihJoL9+M=mPq6;X31z7 zl~IYUeY8l4!{tED$dZW%pR}Tj9<>@CM!^s~pEkV?b}B9Ef>Fy_ii(${I5+w=@kG{w z=%OOKe{HMye^UaPwLrWA|4ipke!+!Y9s4|#wk$P+6pB}w^zGVnk#>2d5NlDQci(i4 zstgxvi91@Kdxt{4!RDSe2OOoKg~a%1G1_!B(mthTly&HO16swIdzTz@ij&164JfWk z%p!Dc9=X|sCMJ?)(pCR6A;h{)7NCpQ=te{`?JwefU$>JzoQdHYM{gY2Th8@fj%gJf z=4IO)^=OG0nXuC^jKaah2e=OK4x*)9;T<@SG8!gZ>ig_5wKAU#jP#eoY7X}+CmKoH zxcyyiTe`#lR7Q;X!R?9(iX9gvOH874ar}F)gXeCMz`hB|J|&A4P|KVQg~uE#OcK*L zr){f=I^?0uT3PJ7em3uPz!}1v3$KBtQ9N$Iw-HA$~2Zqz#&JoV!t#GU2BJ zANRVG;%`|7O6rdM!x!rH2%t(^SPou|M0{*6Dc?GI{ah)Soiq9(Z}9y^*uqC<+Gu+_ zBbSPa@+DvY^71sHW|%=Ud$RB{ON7e==Q}5{4_Qw;-l@>e9;?>vyO(xf?v^aU7`7VB zE3*FZn(iB>d$D58q3Vo52Er854~dAHH`VS14D?3_N%=lu9D5iFJ8rIJnq5Wk(vcZ? zx-d^HSht75O+8uN)CFXg#E)|h^bmgC54x5nrPp#_fu~d3&M(i}@l+ z|L}VLRa#b3TEqKxTpX=io2R_k@jiMc$S~d}3H7976ADQ)9b^$j$P>nS4t_%p%8GO= zepxc-UKp`XK~s3-mtUwJbrcUdpduM0?lKrn(sdQ+$)YqBswe!mnSj$%(u=|a8tzZf z8^RZ*A0r*@_CKctE60)lk)4+`ZpQC@`EyyHadVjN4K;6DhGghP*w;@V7H{RO**_Hd zL`z@H@1U4kO3e0fN}>|srvf#aj5JfUW5}D>{bYdQ#k3L37Abg7biVxIQNXgzlppRDfWWGonosR54?qtrK zl+P>u%zl-kf%WNt3=)9^i-YE)S|XQ-92Q@~k|92MiQa(Uqdm6JLh^Q5f7XiMsx0Ks zv`8;QfDK9GK@=h4sGmONm3;cW9X0yw;a2%uuzcp-s2$za^%jj)pIRArs3@B6;stF~ zlDGdta&2kbK0yz|NwjSJJ9v|M*N63nS51TcT|e{8?PiOVEENBA4?auoyUp)J4ba!@ zv4bA^i9q%}2%TPXkOF^08P;X+cu{tx=MGzeWh zh4EVQ$AhtHA#5hZX?Sudxf(@WrBFkr1}AfK;bzU0S@h$nYx2;BS7LPA?>mzsYt-_d z(t`&E67x$|&h6qTb^my09}J4o2~CTOSvP>(BNN?Od{TmV?82}g6l#&%4QZPY-cR6cBeIs#OaP1n0pL?eJ~x3B$&k8);gWXMu&V z%Thxzhn5PLm}()F9t4$BdRCU%Swz{*zhB^gRd=KbxB)ha3(I3+DdS)P0dLV%a&^?# zk5&Ejdw0ZYGes`)bhQrB2Fex@-E*Evkv_Xq+L~51oD!*MiqZmy!ZB8#86ZD!hQV(^SQ8!&#Q?s{Tu4jYJdXIxp|ILhiBhp~>(sA8VE!G6qpl9%_`g`7?S@5w|aTfs@cJ@yNfT z1!3M&P~9}#GfezvXOgcNPPA*mJ1!LC_&l)2^yhKIWSoeFlTO*I6`oga>Ltn zdm+X))^@gK6R(ju*Y}T1Vn7|I+F@&tetf?SSDKbA$k*%s7(}k7ZTBE>VlLOb7){To zp2f@?J?c#-qKBv$y!gx|^itm}2Cdm7R$*J&^lB>`*0A)`+J&WwB(1n3UM;BrJ_~F?ZAEoG2 z2lLbv=s*JW4zDIE1V`>d$uMlZ@-`LcCE;uCP{o`W1EOR zD(3BdR9P$kG2UFPuo4lt+yC>tg>nw(PcK3|ZXvbjlR;NrqD%pDTUp6yNd*m``z-nd z!ZtB#J_$Lb_l9tozVEq5fRnl$} zn-DB(EKW;6*my}%`H>=+EBXUz54MN zT>t2@FgQU*{0FL#U`;#zM-&2lv~f@H-ODp2745T(L*jdLPq&DdPLNF7lNBqt(B(Fk z+~wfCo1w=HVs-bzhrFbL*_z@8mf0HJ!qIiZQ7r z81Nm-lp&vtoVY(J8Ux{8s{whw-owSE=8_*)FYvIUYp<&(Jq=l)2$URFQy7v|Q~{@^ zAyz?6PGhT5x2!xQ-pAZ{=^b=a@dl*-ohzhi@S|HILF2dNux$b^vD&5Ts4R23{zKkE z#_wn7a1*RbIFc3w0K+$n7;;W}&eK4bP z*Ykvlj%joB$xA?c^DDE~tWRjsNtmYDi053mo-1!OCCq%c`LoQzt=@XcF-y;N+BL3s zPkrk$H2C44L?J3Un{Q|0c>mb$v_lH9+=y6=kQ0uDrwApOA~NgOwz%Ynh!$TD3fM^q)zzfkLI4jiMTAI zfzf#O7RNug_2{~AVX=Kz}I0e)I?K~Ax^>5icl!oywKP*ur252 zHC;!dB9XgYa!2Nv?~YOM=QU@|!`|?1a5Lr7jc(#UT(aXWP2L^8wLA6XtR7S;JLa3= zoF`QB3$l{}cv}2)opA}w~e~OFybst zkq`t-4rx1oX^dWp>Dj0Hvm2MdkF7<}NJvN$k*j2SD*Yl^b1nOIP}&_8^-<<;vZg5q zq;RtfX1|BmZNy}vd-F4OO)Dl8r!9|;;r(F_oWwz%MtOUXoz-rbUdpbdoTcf*0Mt!ipE#QJN?sK@xgP#7Ulp_*m#BjJsEt2N*|vs-05TQ-59quet5n%htI|LSG5Vj8jBoD-~yyu zV>vjDLXN9_-5GFF_uBXGG)11jQ?>EmeP`2n$#NYMeH1wG_e|&Bh9sg;f zUre8;xAh%-IpK{3cWe(s?jUb zi@YSoYo5nD5@V3kXzr%V?7*8!(aq8^QV%TcebR2{@_fl2nX%dytuqiy*a|i4?mb>S zk4Q0LrE(oEIEoz|fn65qRV-x9IP8)Ih)~wLtw*EgTjnEapP16o(V1<@nZyIw!6^zI z0}}v>>`vGkZqrKeU&bW=rKG=SNo$})B%P?Gw6rwKfR;XtJwF4!-MAkqC@46UtNhti zSQ;w=*yrd~*Za3W>;ePZsN1=duBE?JpS0edYeJ(DPKf>#QB+LYnRylWIFx(4NbjeG zw7yTL{8wU<4C@-FB9*u7iIR#H{C+Cn6BlV4Oo9>~1|N@Np4(Z>K%&I)(~8mo>5Q~M zy(C}#ubE9PMF&h>;5B7oLC5$_Q|Pw8G$K=@rp@pAhPEV_b{-%mz-uW-&M$}DVO#7% zmbN%v%`Jp2-buSJs8_Qsg7bS+dIAwv-%6%rN2<7w5&{AgDa`;{pUBEkYa6=DL1(VI zB?kN^T5)fI3#^8lmI5O^%0jc|LUW!>1KYF$I(F`10L?<-PVgl@p~GywU{KIqE(Mos zhK7c`YHn+T8TTYL%AViBz2a}!ca(Y!=;p`OT#-Gb>*u#lqIng`SOPu@FlR0;Fm1h9 zQdkC80V`l7LBS+!-Xsxau&`>X z7?uCd)l76})&u|_K6o`LeHEXO;rHe>V4Y$x`~e1y;y-uxQdL!LOo(HhZie|7SUkmw z*O2YGx8B|Zw7rqx@aWYo0OPwu6&VYRxJF!&#WmA_EG@c%oxt;UeVfrl4Z!TwzAd1| z;oid^2g#z;oa_7b1$Z-j&QILHx+s3Pes;c{o@lME<=mUu~?yHlCB8`_mmp{7AKDx z?)mvOah8<6x${zkLCedYLl4TPyn@XG7PC*IS@(Hpu=Q}%=99&r6f*dpE(oi?UIs=B z0u5!Q9R*_oD{%N@%-JfKVS*qz!slnwe<;Aw`q!4kLkt-nP-thy232|751{P~rWI5Y zOI@WI1%3;uwvAmUnSiZC7aC+oimH3cR#xX(;Sn1JzWD=_&!+te;qM&Ac$3La59?oEQp<^f=~UMh zo~D>TVJ_v|0Qn3|p$??{P^K`g3a3m=i|x?fa83K|>l;dvCh=E{1H7A=>-ATCbPa$W zVyBiNOqW2fxny%*TtsOO%IGkv0l}y3oG58O)k!vK$`01)OF39j8c$GwK=e0O6 zDpQM~VU3tPSv_q-e?qNHZsOot@4>tU3i4D@(q@H*qHj~fW>OY4roEcq2(+XGYVj{d zKDj6;42UnHDxpOoB~Bb%D@OdSbXjz8>DmlNQ#-t*4?8 zbIqD6tNU(BmTPRx&d*+ROnw&{$VnJ5#NE>1mI0hd6}aG1D4K=8{?eq%p6wnZhUv=X)^o_=3# z8~dcJ2N)u156pr8JnUeD#|+DFyu85dKO7Qf;Zc$LZ5bs&2pd01?DA|s7c4cw5QD5U zu(Lx}&9{_f*sUl1wHj$qFbPBC3ebgGjYgy8F-Y2!qD7c;eT;}$25>TC1k?5o`aX<= zivdJ+O5{5`%WtCd!!sElLhSfwwNqvzQF0h=_of6Xb%fLdmV-O+s3UiMqvNg@UwlX1 z{oFjzNmHnyyJqk+h+>4*+3t`ISgK2pekO=I-vvWJ!VkD*#<- zcpXP}HB|jUJJ8Q>(*Q+PbaocX-C|`PuXa;5)R#3&jOw8wA|#v)B%sXvdS$xAV^#f1 zPBqf@Gc?bO4&y9}Mhv=NF&aI1ZlSCY`|;y~=X3YHj6~zAl-^tXe8~ksrAADrh@T|Z zyyh83@pPOJbh-VJ#GXfq=o1%y!`ZLVh2F!F@^?_C)4{{W$O)Ariq2A`-TWHNu0c~> zKlWF$y-^}2a$?lo6|;C41FLzY|6+q|^I1Cg^<1XSOd6d`XQ0J&=;zu{mb=N<`~LxT zOW+PDDdF}xUC$%nZMdC)qct(dZ9_3T1SMB>0IAqI6?GMC!5u1)RUE@B$Znp=c}lcC?c6Zx8NJ_lQhU+1 zU^~;Y$#HA6sMRgda7H?$Q#zP94!lfNH_?SH5dTWw=urLA;hc~#XY zhsm-Gp7tO1#4jrwlSMuH4|>&re!224OE-ApRO8X6{Ud-t=LNk2dd5EO#a0=y%9m3@ zkp6W16b5xYRCJq8g@yf9{QX8ug;G)rl!6grkBgXzbJ zr~$Y}h(_X$4)i_Aij4-vRDokEnr zetug)I{z@k4B{hNI@YhMRUDO#T05DGx1}JGmUXWXe_R%QP;4x}8?`BJUXwR15!vDN zpmFe6OA`b0K^>v0r`Jb)bW~wnpu?w6jp5fVA8cm&^z^S~QbGPJ%hoG|CC=sp7^x+P zdFL*=@#$$j{_9uooyohWRBAbwltlNv>N;c#QvFqr`m-4+Q@1m_@B^Hv1ooi}hq0_4 zqFDU!wV7Wp$+n*NI0{T%AsvQs9^l=)BCE4HVLCK#L zxah4}nzYZwx|N+k2R?M_T&n>mLf&koQamE|O{)y{2$`qu%#3M+c5zRy8rdQPBSGfQ zv%QbkCB=S5(<)jz??NF(O@Jc{4<>Lom}5iJ#68wnVRqPdM;o*>OI8_H9DhA{C;VAq z61}_8SX(+6;1NeCIWa0J*M(eCDfxU5bC7{D56?kZZ8J{M`&{BTd{2HODUPS~cr(+V z)2VSc=&DI-d}2aqT_3f!_I}kGRj;Q|sB$VNjP)Om8po|QDg@xnE+$IED6q`Z3cqSi z_1)_}&Oj;jXbxb0v4N>T8RaU=b;dbMS%&8X0;&^SzK*ln7_Tl~n#hdX9blqU2-8(ij27waQm*YmfNK!F_15XeK5JWLQ#AV|WzX zl$z7}wew6H)C5|@!}F|XP>WXojGUOQMt^N?+x_9u{JpKE40rubqZsj9qh+m{ZQP*d z<4oAj*PFW~S6l~(MlaV6k9_~4D=UN&a-6w$aYA`nW9S_0K3vw&fVi^BRs*TkfF9JZ zFqc>QR$|yN4skb#19&`T;uj~y?k2!nd+OoP2D4>vpSt}esj{pO47-oysjuO= z=4DfTFn`7uCeODdzc&}I{C;hrn*OEF&+H7wL|(Z=YYuqIR@gv&I~1MhVX4nZ7r_|h zE*0EdEOOU9%c13+6J|GiY|UzZ+kNY-r|wdg~#k{08uR`jc4M9mmhD$$JQ`AwRkdM z3&OaMCp$S&v80~6Ki`vNGG@z~TC?QJNkL_vk}j(bOFowvj80x%Cu>r`<_`QOFCrb@ zAwo|i9&ATW#vxB~F%?yyEsxDMg{IHl#mceDm41(Euf{)LElCUKY$`Yywbv@fI1$Es zirsrbnh&&!yfdWtUdxd0Q_9p;5p%Bxn6v;|O8ur+$~MX8=jZ4whV$<#$-=i=25ea= zXZL|H9R&eN! zzwvM+TK~5$M*1{%($q4*A5)IFV(D4j8b}cpDk;{cWY@{{PCY`JjV1`9S5|By9v@p2 zAeD^uS{@4Qe}8LImy(t&ED+T3_5p;_g(FZ&k^2=H%{#Ye85w}Wz~*G+=BJkA*bED9 z&-3*`>0pMUXX$4@+jk_IQ~N5J7_D(n#XIRv*#Qn90S*UYTWRdf{P8tq7cfZ)qH~iw z_Txz5jq8OJ(8OL6eq8)3lA;%Dvdbk6TS@z0iTgGeP2%+(>pH4BP0Y-e5=yV(J_2Y% z67Rh}`AXtvY=oJfSR8dVqu#~-jYN=28u#B?Bgw4hYX#aYHcWA^6>FrIL*3lIfmh}# zEP9f?K(!w?@WNsEdQE-=;^)&VMGm_AZxW{NQ4!xJfxR<+mN5>UynWQ6hiG4y7&}#? zDV3hE!5m0#a&8q>T`pAlk2&ivQK9^2JQrEoYc-Mm0;yGz2ormVU2-!WO@YHbof)0= zw^2QIhW_8;s;j0;9hw!g02gr|yOIKWvK!@ZpQoA@DS_{&1m(z13hpCP>u2!Y zd3t=8*HoeDE)aT<_pR+6FGY1t$p|p@UYuhbgndb}|0hlLfBMv`j3xd|V+v?^&USp& z5lXQ%O^Jwi()^-a4m;VeD208I09YB}w?DL2^#g{v>ha^L2{^>cX#OY{qW!Y7|2x^p zgFsz9(>bOT3yZ1-;iVsIJv|7GHdX+&h$FbsU85BoEn~#T|AT#C_`^FrxhS6oPX*s= zDfU`>b!X@P4#?^uc=Vk0+g5x0WT5xIpEdJazNM8HK*I>67Tj5av;BJjb!kfIm_G#Q zFr}V*%1}$nKtq9;kRMn1mfX*dp$ONL5unwU!O00A3P2|g_*%~Na!>gfRat)oc;?*U z9@~%+>QKHPluaHYxm0HL_4W2&-{3miWCPT?ljFtu#RUZ%{-JbFT$r0ZsM`S&u)Fhb zac&ZSWBF8N5aq{v@{LWxq`0_v*Faf1&(6Al<*>#3(6#}Hmd#Sq66K62sk;CgWMjQl zAPUWT7S)+(TV)Le}#yv~?1~4qLy62__B#U{u^gfx^DN#CX zv~Q8nX7EAZL)?09JdFdY|4vslj@ZwOoNibZJ>&}ln`TRYjefaT4LxnnmPNa}IQBL& z-|SkJZmXMPM|FQ*d-rSb`IkdIl1Z2mOV_im=Iior11JkY(9^9*ir5M=r-Cb!-*9GG}ul7Typ!z z7d{LUs2QdxF|zi@_%2(Enb1&r$yWTPGXOaU7 zntKD!e;gL93VO_WS)DBzR*x~9+8WgX_POHx^d)R_%FLeWegG9-bO}TJ$fpuD_%tJ{kv~BlT1`kjrr*hVHqiUxgX<>Z4Wkw?6Pl~ zE}wfBr%a)aABbL?S7`_fh~uFN2U~Ly!e7-D%wJ}%#91fOfe^Pw3twCQ+F_6c*!%{< z2R1Xy!rF-TGuWp#o<;z4W7=*#NdYo;3@c%6O!yBuHY;pKSVzLS^@tS~Nctd|A3`lH zhBn!R=6zj_MsmOQDvk>PGlk0O4QD`^wrz zz%xN}w(N1rz7;KPLhB{x$YPP>D!Xx^UewC0t~U#O{s9m}Rzlnp5+MWpakx#30Cx+O9c2;uL$R~^oc=*#?+L&V zlCy4BVNtkx;_mxJ0y?i6@tOd@Mp}%$d5i&-)^}eF96?ugZiSNEJA5^a^PukRJyGzG zZJI5`yf&Spuuw8BF|*HJz#Y`#_poU;MY4!-5fDUFyk$^_I$eE|WnJ1T53%slMbJ##r-_M@t5Xm_b=N$Ft{ZdX^%l(qotdBwrHs=vrZ+lrY+%c&ZV z1>ocH8fTSSfVa#>1l@^rk9!~C*RGx7FRayjN0ECDIqN=5STa-lE{obf_r4tct&&^5 zbxe3j|DZ0p*>b~xp(qNLTOvv~F~pE;xBS|4ATf8zyW{jz*2Oi0fy#qkTkcPtiH#xp z+Fz=lJ$8IS&5Reujukzn{ra0UGsMm}Ra!k|cD(%MXq3XV5rA#}bouKk#TWo59O=pw zaSVRyX=pEbvXEblrsyXDEuKs#PI1#7A+vFIeBx3FfvmvW)~(rwB_4{n!7r3K_$Kih zd@+bLl18Pi&7pDpdTVX^CQ#B-*^F>s_1E(JMeMy9KSTZJd*LIzeS}K^#NarhcWXDj zFKVS8;=g0x%yedd9u2}TV&{n_I;^U$?l2DRADbk9vs)I{KLL+>IqcjQw4}(mp0M>4 z{IkYso<9E0k6;ymWP--ZVQ8Y_jX{TB!LX7rr}h{2cZQ>-p=hKSm5qFUh?H12)qjAl zfKn5vaYyRx?H-B5vGGi?MVc~&53%6ZJ2KIVRZGml3gDFc(Z1ETN#L}Q!vRTQHsb71 zKUjL6#c-M!QR{?M!}l4cZzHmA`ijB|9AlQ8?W&L(Sc#r~-jQ&#`z%1q7|SfN)}s?N ze!(|bM!%z7nndTJ4)^^S1J+a|%-oLdL*gbou$`~5agzk4W%+%{36$3+-QF2Ow`QI= z#qmaG#M{?0VcL76bo8!r&_}XZWPQTXM6u==H6Gcn(dL)z763JxtQF@jLkV^1z*;m) zhd2^CnkorH3UiKxZo z$%v1kU)t@!*?O{=C5icrlqrX%{y3i8osytCg3)R~TiVA(pQipOBMi()Y!{iCo_AW2CR+)YhUanUnWU2)m^B>60y;m&O78#?gC zZWL;?;6-_28#j<(Oj`TD`57R znwY;W4FbT=ow(Y2La`)e-z4RaHJyJlPnbv;X9hPo8&ON`Iz+{POO~&F`DILpR#Gny z=A++q;7~fk%2M=TmI7d;8nnGU?-$L~HDRNhrl z*d?F(qc2%T*W3&kIwB`V#QC*jl(A;no31HM%^6L9QHym*n?ttk7#|wlylSS&XT$0v%gh{ zns{EG9~q7Ja^pA5z>a2fxG9d1H<1RZHqtG|>=8vqWCBP97FpI)7HQc64cNe_%hN)^ zoGF=+#B~vo67+?l63fJw>cs{N=KZLsKy)l`Sr-$}6=-W|^+OUzRPi6Z50=p5$8DKJ;eI!3>9UPi3yAIJKNZ z2??6c_Il6&SF$-t{OtIX3o%XDa#%@$UD5H&J%^25_a%GcQ=n#oE-h)8onBPJ>i)*T z`+|%<)4SL_#HncfS?}BIYPeS8IQ()+jSf5v^YgRMQnd*=4|V{j5`D22y}aG^!GVFB z{wPq7Bov0gj965mI=Tw=800ZSNMx$T-h5C_nz_u=^wjGD((geh(JAiCJ|y_M$9ytr z$KTjY-|+kRW}?pc*)RZoy8iJ6&ye88;UthcTs%rY#~e}mvem~= zKz#Zxb{Q^*0FwJ{in+?MBAqUY18LRqoKS3#!n!v`1GQn&5@$6WE{K0}Jh7z|h46Rm zJ8%bxBL3Zy_mTt<(LDY}Bkp}*Jw*d)fI8T_0-09?P-C?P9MY)u#MHQHbufPVT2#Sd zFsk|C>(m%KeTINu;Gt(UkLHCMF*URAc6V)Xs0xmi9!&*sUaNFn z?XN`w;S(I-l-pdutGTMjtxefTC}o}d8JMvP;)G9+=_giGL1=BeqAAc$PPIK3Q65Is z1SVcgplyh7cdCRIApQ(Lsui>!#7UetugA zgZFjGWEBVNVB8 zrT$V}>@YL&J}#Zd$MxDZ${cx_ro*D~S6o^&D~y7ZnpIYE;-ZI#)lXT< zC+$TTA7ni#~Da#{b~^s65^(DC}C!{I~?ScRyrmtW<(>aunF4KNtxAt zL3Kv*^-Wor0Q(_(I_bN3Q<7D8r4bviA?Y)PAIm|8Zgk4$TDD5D;ThuycCI1|uY>mT zq9V>4u)P<(>*rp;U?U|v(8F69MwXwxxC12?(vN;#YMuZet2lt&p>Z-?wY5yOO7&t* zEn+G9bnVd9ZZ>c9xCDrU?llg>Bmh}=76D&UkAbe8vMijerU`Mivs9je7;;XzYK#`{ z28NBM<&qxgx>l^NpMoz>22cza3k;ii;By<3!Y58yMxj?(aL+SKJ611^R~}MHI6CkCn2c=C$1TIs`)?DQ_J%~ zhXu{<5h0;b>SiSeUW+p4V{PSjC3URC(nZ7o79Qj+aRjivPXP(FMMm+gQ-I8!D$S^% zDV4y>SZ<&SxUQPyP%j`69(EB>)juYv&^*XjtP zi@o@AhOwk>*#bm!vpFj_mqoVgsuZ^7*O;rcs{m(YZ}a8(b{CbwfqUW44{vx*z0!@E z4-_Q@w{=5)_4oJRW7c>ji^U9ca6-VjF7{Ymb36}IHz-A$T9N|0!b+fF59~eutUME}G{Ju#05#YPUK2OlTmE>^sA`s=n8Rx6>8yq;Ue!3X`q(kdf48Jo zK0NuIDuhys+c`Mx2^=k57zWF)uIYC4L442&>C!?FS32hX;BOHi+XPmxyulB@F|Ow2_^1>(UtNpdQPg>JJsY@z>kJ8kie;h zOsXFG8CIr!ZFi|*Y4z6f1!g;{WrpKg_O*~L-3+eF4kR!b!mX-kMclStL>EbY8YpvV zc_6qQpokkQP@U{oH%0G;h@z`nqF_H`?PJy;Z*uKK>`nB zN*5XBlt!y@hXT(ciA|J0?L47|VZtQ0_;KZg{^*Qpi~FH6v?sK>PP=+nWB#?K?{xO` zJ&LS+_W)q<$^(_KY6k>dnBaN&?!%AA!-}8|X$88C&rm-b+P;zu3xlfg$g4bV;uMPl zbK05Dw9I@b$e@-K2UMXsDBIl^GH%}M#vn9SBgG(M^px~4!-#vug^HFo{HRFp=rfVC z@+u7Jjqkr6FXr!b?v4L&eI5uyB9RH`)ys2Dmy(*_wb%xnFzx`>Xc7R=(WhN*L}m3* zh%*gq$ec=>h(`^&il6g3)vYSy>ox+(BQ(ID*6(Fj@vitF-14Bn+>)-k zI8Os0RAGdokEZ7V9$X;RO2GK>J<=wQEa213g7fyX$FDNqE>A}x@7H7*_~%5 z2Q7D5{vq5R7#F9`aJo_~HOayke)4M}I0PGHrt%Z_H+~qo~0z;Wh0W?>L^IU433zE~R5Fb0Ds? z>Qj)%d7>C(B!Dv5GiU$Z`N-F!O@mvl`M+?O=lYQ@SaD}3C+MZf;OuD` z{%^$J3E?5uX__BAt?GKJrm+vdquenQC z8uwlOLDkGB8$G{OIKq*0I(R!ds^{Kq&s~qS-(6c$$#e~@KJH9ixvFo2l)xA;VFZk2 zH5Gtu0Q2D-f{E!0v%P%f@~wP(;z6bPO{sLY>)DF&+#OTT1vtA6xaudiVcR~=IX7mP zIwNRMfY_8CH?c2g`c=Q_1Tto3F+glJwF=nuo~@eELrWijfa>JksHm8^D(#e&D$Ezi zo>pK*^LPxe)l1tZ>%aYuDAeYld4=b2Mq7R405-x@u*@5wUqTyr!}q@u>7&AQHp}3h zxtkeDv#dKBl}^gaBuWKefe9yw+-0`|oK1j6*K{c7rQ01_%oR`ayM>N0N`j*to-Uv^ zyd+>z$o6obck=-WHs}sa>lNW|)ETfZ39nNJY^Lt_b@IhdfdyiE7TSYR0Nf{c)n_UP z8uv)o^e?b!%W*HLqw~Xj9`DH)wj@Eh9PvOs z)Y!xN^8zi?c5f;Hva|!|6kQLNjxm^7@xgvwk4nm z5P;zUetfL;6aEGx?{yX*fbw-oLk@smdzvI>C)S;A8p?9^S)VZCYBfGGs2v0KrJJaZ$fd{k zEd6&$LnAS8+t>=Mgu%`Mb)R|kelAO67{m~c8Hz3Eq=rE0g?}9 zJ1h*A9I}~e;cvKsK)ATrsHIu6@=0CG77l32V_9ti7h|!Chk&hQr);h(bJc5I16`4nJu?%axknCn3tVx1_ZLk$*_;`42V$Co0S8dyX*&h zKi`r-pqXm(zXXdD{chQw*8`5~Rq;}X|EO2;Kbki3DX{_}S0vZMBRxP7bu-{5eHnmd zx1sYhGBWZF$_KkR+1gfI!A18aHluMTTn7Q}{UqP2vrzz9w74g0n`IFR(Ct&l!-g?A ztJ(Y%8b2b-@4{C#f3gsG7uEo7xBoQSP#B>8O|9gIi3heXVS|W>a+h`Rkvf4WK=2m6 z`1-h4Rk&xMURKON9~qhmaqBzSA)?pc;!`Fv(OieDe5ZNRQ&SF9YB9iMKdNULuYUlg zTMJR>=Dl+vorU9rx2i9^ICe5K8LIFHNudR#A1wbpd+^siB)>iAx{#OVC&C?@1vYJ2 ziWCJP*bcIKkPGhfuZ^j6ka{+mxsMQhh`%)=}3C$Q?^j$k)*Hdcm}N~Z=M!&J_-{M=Cj9PWXTyGp0w^Gih#2} zdRCRq@+G7?eM}ql(z*z7cRCl{0k4CFaM?gUw0ukURsLzA(p+5W@&Ygtp(7bKUQ86l zf*t@E`l@f?_KVMVhze_Jgn|svK+O*a2d8{}Z@CAR5lmmfq8O*-_OR^2w zb5POB%F4c&H1rK<>~zVs?J&X&*sU{Z^x{$%!DtK#kvFy|H$IxpeVgLf=M zL*~AmEer{11$=J+raHC_AB3+N}mB<^pyu}`^>mfX+mg6dE+V8Em?~634`1xPIeVesR?{Y}mFGnvzn>QP83I;f&0xRB+&c=IX z?CWgwe3#g#?Js!P^!5Aq+rU-vGBMuX-7ooX0SAn;fDY*PRsVm8+4>`8>`9R%m}``juQde`V^u?&26V7LDM&1#JFb|Wp0(jD{_tKy(&Pb+UszR8yf)jYsrs+pB0}f)HH0lMy zLA$~wp`zjjFshYYrHKvKSppe3Ia{91lHf#+><9nz-@gl$;#g$RaPMwTQ|AlrI_x5s>pOe`D%3Jwhn z7z~G22QN*x_xWmjLM$|eu_{5;bj2az&(y$asTZy9h*Yd}w6|$QmB(t$0;dF-vdXGG z-4Cw`7hV_b0-20xJY=+>Gj(zI=9uX>sFpF6~sD zK1VpAv0mhdp8D=NbKe|w-7h|OX4;dT2Tt2>JA4&apdqv}GKDfdU;evr%XXp7#;z$7 zPl*PG$Ofrn3u$CcAcGA`8>b{yCoAgxK7KLJeDT#Rw`r-9FLWO`eP#DUCt_T^pCw4L zNU}Xj?p=OT?MmtO=eHZ$U+;8Np3f3{EIsIyPsLB}^Kuvwj_wSHh67(%>YDZD%P+RL z5!?IltHP%*qI1i#g~~KP?fG*?V=BK^_|N4R`JWtKqJH%Dk1Pft@O1TaS?83{1OS~D Bi8KHJ diff --git a/grafana-plugin/src/interceptors/index.ts b/grafana-plugin/src/interceptors/index.ts deleted file mode 100644 index 193ab832..00000000 --- a/grafana-plugin/src/interceptors/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -import axios from 'axios'; -import qs from 'query-string'; - -import plugin from '../../package.json'; // eslint-disable-line - -// Send version header to all requests -axios.defaults.headers.common['X-OnCall-Plugin-Version'] = plugin?.version; - -axios.interceptors.request.use(function (config) { - // Do something before request is sent - config.paramsSerializer = (params) => { - return qs.stringify(params, { arrayFormat: 'none' }); - }; - - return { - ...config, - withCredentials: true, - }; -}); diff --git a/grafana-plugin/src/models/card.ts b/grafana-plugin/src/models/card.ts deleted file mode 100644 index c2af07c4..00000000 --- a/grafana-plugin/src/models/card.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { ReactElement } from 'react'; - -export interface CardData { - title: string; - subtitle?: string; - value: number; - icon: ReactElement; - rate?: string; - selectable?: boolean; - selected?: boolean; - id?: any; - lg?: string; - xl?: string; -} diff --git a/grafana-plugin/src/models/curler/curler.ts b/grafana-plugin/src/models/curler/curler.ts deleted file mode 100644 index f1e8d994..00000000 --- a/grafana-plugin/src/models/curler/curler.ts +++ /dev/null @@ -1,111 +0,0 @@ -import { action, observable } from 'mobx'; - -import BaseStore from 'models/base_store'; -import { makeRequest } from 'network'; -import { RootStore } from 'state'; - -import { CurlerCheck, CurlerCheckStats, CurlerCheckPing } from './curler.types'; - -export class CurlerStore extends BaseStore { - @observable.shallow - items: { [uuid: string]: CurlerCheck } = {}; - - @observable.shallow - searchResult: { [key: string]: Array } = {}; - - @observable.shallow - stats: { [uuid: string]: CurlerCheckStats } = {}; - - @observable.shallow - pings: { - [uuid: string]: { [date: string]: CurlerCheckPing[] }; - } = {}; - - constructor(rootStore: RootStore) { - super(rootStore); - - this.path = '/curler/checks/'; - } - - @action - async updateById(uuid: CurlerCheck['uuid']) { - const response = await this.getById(uuid); - - this.items = { - ...this.items, - [uuid]: response, - }; - } - - @action - async updateItems(query = '', tzOffset: number) { - const results = await makeRequest(`${this.path}`, { - params: { search: query, offset: tzOffset }, - }); - - this.items = { - ...this.items, - ...results.reduce( - (acc: { [key: string]: CurlerCheck }, item: CurlerCheck) => ({ - ...acc, - [item.uuid]: item, - }), - {} - ), - }; - - this.searchResult = { - ...this.searchResult, - [query]: results.map((item: CurlerCheck) => item.uuid), - }; - } - - getSearchResult(query = '') { - if (!this.searchResult[query]) { - return undefined; - } - - return this.searchResult[query].map((checkId: CurlerCheck['uuid']) => this.items[checkId]); - } - - @action - async updateStats(uuid: CurlerCheck['uuid'], tzOffset: number) { - const response = await makeRequest(`${this.path}${uuid}/stats/`, { - params: { offset: tzOffset }, - }); - - this.stats = { - ...this.stats, - [uuid]: response, - }; - } - - @action - async updatePings(uuid: CurlerCheck['uuid'], date: string, tzOffset: number) { - const response = await makeRequest(`${this.path}${uuid}/pings/`, { - params: { created_at__date: date, offset: tzOffset }, - }); - - this.pings = { - ...this.pings, - [uuid]: { - ...this.pings[uuid], - [date]: response, - }, - }; - } - - @action - async pause(uuid: CurlerCheck['uuid']) { - return await makeRequest(`${this.path}${uuid}/pause/`, { - method: 'PUT', - }).catch(this.onApiError); - } - - @action - async unpause(uuid: CurlerCheck['uuid']) { - return await makeRequest(`${this.path}${uuid}/unpause/`, { - method: 'PUT', - }).catch(this.onApiError); - } -} diff --git a/grafana-plugin/src/models/curler/curler.types.ts b/grafana-plugin/src/models/curler/curler.types.ts deleted file mode 100644 index db8dc6ab..00000000 --- a/grafana-plugin/src/models/curler/curler.types.ts +++ /dev/null @@ -1,26 +0,0 @@ -export interface CurlerCheck { - uuid: string; - created_at: string; - alert_receive_channel: number; - url: string; - frequency: number; - last_pings: CurlerCheckPing[]; - paused: boolean; -} - -export interface CurlerCheckPing { - id: number; - url: string; - created_at: string; - http_status: number; - latency_ms: number; - successful: boolean; - exception_reason: string | null; -} - -export interface CurlerCheckStats { - max_latency: number | null; - min_latency: number | null; - uptime: number; - last_downtime: string; -} diff --git a/grafana-plugin/src/models/current_subscription.ts b/grafana-plugin/src/models/current_subscription.ts deleted file mode 100644 index 547bcf60..00000000 --- a/grafana-plugin/src/models/current_subscription.ts +++ /dev/null @@ -1,57 +0,0 @@ -export interface CurrentSubscriptionDTO { - uuid: string; - created_at: string; - activation_expire_at: any; - charges: string; - stats: { - result_credit: string; - result_active_users_number: string; - month: string; - }; - subscription_plan: string; - users_limit: string; - current_stats: { - // users_on_call: User['pk'][]; - // users_1_weeks_ago: User['pk'][]; - // users_2_weeks_ago: User['pk'][]; - // users_3_weeks_ago: User['pk'][]; - users_on_call: any[]; - users_1_weeks_ago: any[]; - users_2_weeks_ago: any[]; - users_3_weeks_ago: any[]; - active_users_count: number; - estimate_credit: number; - - is_billing_exists: boolean; - active_plan: string; - expires_at: string; - paid_up_users: number; - active_users: number; - admins: number; - users: number; - - active_users_history: Array<{ - month: string; - active_users_amount: number; - }>; - - billing_history: Array<{ - date: string; - plan: number; - paid_up_users_amount: number; - charges: string; - active_users: number; - billing_statement: string; - planned_next_period: boolean; - }>; - - usage_statistics: { - users_on_call: string[]; - users_1_weeks_ago: string[]; - users_2_weeks_ago: string[]; - users_3_weeks_ago: string[]; - active_users_count: number; - estimate_credit: number; - }; - }; -} diff --git a/grafana-plugin/src/models/current_subscription/current_subscription.ts b/grafana-plugin/src/models/current_subscription/current_subscription.ts deleted file mode 100644 index 527ed192..00000000 --- a/grafana-plugin/src/models/current_subscription/current_subscription.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { action, observable } from 'mobx'; - -import BaseStore from 'models/base_store'; -import { makeRequest } from 'network'; -import { RootStore } from 'state'; - -import { Subscription } from './current_subscription.types'; - -export class CurrentSubscriptionStore extends BaseStore { - @observable - currentSubscription?: Subscription; - - constructor(rootStore: RootStore) { - super(rootStore); - - this.path = '/current_subscription/'; - } - - @action - async updateCurrentSubscription() { - this.currentSubscription = await makeRequest(this.path, {}); - } -} diff --git a/grafana-plugin/src/models/current_subscription/current_subscription.types.ts b/grafana-plugin/src/models/current_subscription/current_subscription.types.ts deleted file mode 100644 index 7a52972a..00000000 --- a/grafana-plugin/src/models/current_subscription/current_subscription.types.ts +++ /dev/null @@ -1,86 +0,0 @@ -interface UpdateLicenseOption { - per_month: { - price: number; - product_id: number; - }; - per_year: { - price: number; - product_id: number; - }; -} - -export interface Subscription { - uuid: string; - created_at: string; - activation_expire_at: any; - charges: string; - stats: { - result_credit: string; - result_active_users_number: string; - month: string; - }; - subscription_plan: string; - - active_plan: string; - expires_at: string; - - active_users: string[]; - stakeholders: string[]; - active_users_count: number; - users_limit: number; - stakeholders_count: number; - stakeholders_limit: number; - - show_stakeholders_in_violation_message: boolean; - - update_licence_options: { - business: UpdateLicenseOption; - team: UpdateLicenseOption; - }; - - current_team_primary_key: number; - current_user_primary_key: number; - - trial_days_left: number; - - current_stats: { - users_on_call: any[]; - users_1_weeks_ago: any[]; - users_2_weeks_ago: any[]; - users_3_weeks_ago: any[]; - active_users_count: number; - estimate_credit: number; - - is_billing_exists: boolean; - active_plan: string; - expires_at: string; - paid_up_users: number; - active_users: number; - admins: number; - users: number; - - active_users_history: Array<{ - month: string; - active_users_amount: number; - }>; - - billing_history: Array<{ - date: string; - plan: number; - paid_up_users_amount: number; - charges: string; - active_users: number; - billing_statement: string; - planned_next_period: boolean; - }>; - - usage_statistics: { - users_on_call: string[]; - users_1_weeks_ago: string[]; - users_2_weeks_ago: string[]; - users_3_weeks_ago: string[]; - active_users_count: number; - estimate_credit: number; - }; - }; -} diff --git a/grafana-plugin/src/models/integrations_list.ts b/grafana-plugin/src/models/integrations_list.ts deleted file mode 100644 index fd13f332..00000000 --- a/grafana-plugin/src/models/integrations_list.ts +++ /dev/null @@ -1,6 +0,0 @@ -export interface IntegrationsListDTO { - docs_url: string; - logo_url: string; - id: string; - name: string; -} diff --git a/grafana-plugin/src/models/leader.ts b/grafana-plugin/src/models/leader.ts deleted file mode 100644 index 1f90ca06..00000000 --- a/grafana-plugin/src/models/leader.ts +++ /dev/null @@ -1,10 +0,0 @@ -export interface Leader { - acknowledged_count: number; - avatar: string; - average_response_time: string; - average_response_time_verbal: string; - invited_count: number; - resolved_count: number; - user: string; - username: string; -} diff --git a/grafana-plugin/src/models/organization_log/organization_log.ts b/grafana-plugin/src/models/organization_log/organization_log.ts deleted file mode 100644 index 857317b8..00000000 --- a/grafana-plugin/src/models/organization_log/organization_log.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { action, observable } from 'mobx'; - -import BaseStore from 'models/base_store'; -import { makeRequest } from 'network'; -import { RootStore } from 'state'; - -import { OrganizationLog } from './organization_log.types'; - -export class OrganizationLogStore extends BaseStore { - @observable.shallow - items: { [id: string]: OrganizationLog } = {}; - - @observable.shallow - searchResult?: { - total: number; - page: number; - results: Array; - }; - - constructor(rootStore: RootStore) { - super(rootStore); - - this.path = '/organization_logs/'; - } - - @action - async updateItems(query = '', page: number, filters?: any) { - const { results, count } = await makeRequest(`${this.path}`, { - params: { search: query, page, ...filters }, - }); - - this.items = { - ...this.items, - ...results.reduce( - (acc: { [key: string]: OrganizationLog }, item: OrganizationLog) => ({ - ...acc, - [item.id]: item, - }), - {} - ), - }; - - this.searchResult = { - total: count, - page, - results: results.map((item: OrganizationLog) => item.id), - }; - } - - getSearchResult() { - if (!this.searchResult) { - return undefined; - } - - return { - ...this.searchResult, - results: this.searchResult.results.map((id: OrganizationLog['id']) => this.items[id]), - }; - } -} diff --git a/grafana-plugin/src/models/organization_log/organization_log.types.ts b/grafana-plugin/src/models/organization_log/organization_log.types.ts deleted file mode 100644 index e63da78f..00000000 --- a/grafana-plugin/src/models/organization_log/organization_log.types.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { User } from 'models/user/user.types'; - -export interface OrganizationLog { - id: string; - author: Partial; - type: number; - created_at: string; - description: string; - labels: string[]; -} diff --git a/grafana-plugin/src/models/timezone/timezone.helpers.ts b/grafana-plugin/src/models/timezone/timezone.helpers.ts index 688b409b..db962454 100644 --- a/grafana-plugin/src/models/timezone/timezone.helpers.ts +++ b/grafana-plugin/src/models/timezone/timezone.helpers.ts @@ -1,6 +1,6 @@ import dayjs from 'dayjs'; -const tzs = [ +export const allTimezones = [ 'Africa/Abidjan', 'Africa/Accra', 'Africa/Addis_Ababa', @@ -595,10 +595,6 @@ const tzs = [ 'Zulu', ]; -export const getRandomTimezone = () => { - return tzs[Math.floor(Math.random() * tzs.length)]; -}; - export const getTzOffsetString = (moment: dayjs.Dayjs) => { const userOffset = moment.utcOffset(); const userOffsetHours = userOffset / 60; diff --git a/grafana-plugin/src/models/timezone/timezone.types.ts b/grafana-plugin/src/models/timezone/timezone.types.ts index 8c16ffb0..5a24347f 100644 --- a/grafana-plugin/src/models/timezone/timezone.types.ts +++ b/grafana-plugin/src/models/timezone/timezone.types.ts @@ -1,596 +1,3 @@ -export const tzs: string[] = [ - 'Africa/Abidjan', - 'Africa/Accra', - 'Africa/Addis_Ababa', - 'Africa/Algiers', - 'Africa/Asmara', - 'Africa/Asmera', - 'Africa/Bamako', - 'Africa/Bangui', - 'Africa/Banjul', - 'Africa/Bissau', - 'Africa/Blantyre', - 'Africa/Brazzaville', - 'Africa/Bujumbura', - 'Africa/Cairo', - 'Africa/Casablanca', - 'Africa/Ceuta', - 'Africa/Conakry', - 'Africa/Dakar', - 'Africa/Dar_es_Salaam', - 'Africa/Djibouti', - 'Africa/Douala', - 'Africa/El_Aaiun', - 'Africa/Freetown', - 'Africa/Gaborone', - 'Africa/Harare', - 'Africa/Johannesburg', - 'Africa/Juba', - 'Africa/Kampala', - 'Africa/Khartoum', - 'Africa/Kigali', - 'Africa/Kinshasa', - 'Africa/Lagos', - 'Africa/Libreville', - 'Africa/Lome', - 'Africa/Luanda', - 'Africa/Lubumbashi', - 'Africa/Lusaka', - 'Africa/Malabo', - 'Africa/Maputo', - 'Africa/Maseru', - 'Africa/Mbabane', - 'Africa/Mogadishu', - 'Africa/Monrovia', - 'Africa/Nairobi', - 'Africa/Ndjamena', - 'Africa/Niamey', - 'Africa/Nouakchott', - 'Africa/Ouagadougou', - 'Africa/Porto-Novo', - 'Africa/Sao_Tome', - 'Africa/Timbuktu', - 'Africa/Tripoli', - 'Africa/Tunis', - 'Africa/Windhoek', - 'America/Adak', - 'America/Anchorage', - 'America/Anguilla', - 'America/Antigua', - 'America/Araguaina', - 'America/Argentina/Buenos_Aires', - 'America/Argentina/Catamarca', - 'America/Argentina/ComodRivadavia', - 'America/Argentina/Cordoba', - 'America/Argentina/Jujuy', - 'America/Argentina/La_Rioja', - 'America/Argentina/Mendoza', - 'America/Argentina/Rio_Gallegos', - 'America/Argentina/Salta', - 'America/Argentina/San_Juan', - 'America/Argentina/San_Luis', - 'America/Argentina/Tucuman', - 'America/Argentina/Ushuaia', - 'America/Aruba', - 'America/Asuncion', - 'America/Atikokan', - 'America/Atka', - 'America/Bahia', - 'America/Bahia_Banderas', - 'America/Barbados', - 'America/Belem', - 'America/Belize', - 'America/Blanc-Sablon', - 'America/Boa_Vista', - 'America/Bogota', - 'America/Boise', - 'America/Buenos_Aires', - 'America/Cambridge_Bay', - 'America/Campo_Grande', - 'America/Cancun', - 'America/Caracas', - 'America/Catamarca', - 'America/Cayenne', - 'America/Cayman', - 'America/Chicago', - 'America/Chihuahua', - 'America/Coral_Harbour', - 'America/Cordoba', - 'America/Costa_Rica', - 'America/Creston', - 'America/Cuiaba', - 'America/Curacao', - 'America/Danmarkshavn', - 'America/Dawson', - 'America/Dawson_Creek', - 'America/Denver', - 'America/Detroit', - 'America/Dominica', - 'America/Edmonton', - 'America/Eirunepe', - 'America/El_Salvador', - 'America/Ensenada', - 'America/Fort_Nelson', - 'America/Fort_Wayne', - 'America/Fortaleza', - 'America/Glace_Bay', - 'America/Godthab', - 'America/Goose_Bay', - 'America/Grand_Turk', - 'America/Grenada', - 'America/Guadeloupe', - 'America/Guatemala', - 'America/Guayaquil', - 'America/Guyana', - 'America/Halifax', - 'America/Havana', - 'America/Hermosillo', - 'America/Indiana/Indianapolis', - 'America/Indiana/Knox', - 'America/Indiana/Marengo', - 'America/Indiana/Petersburg', - 'America/Indiana/Tell_City', - 'America/Indiana/Vevay', - 'America/Indiana/Vincennes', - 'America/Indiana/Winamac', - 'America/Indianapolis', - 'America/Inuvik', - 'America/Iqaluit', - 'America/Jamaica', - 'America/Jujuy', - 'America/Juneau', - 'America/Kentucky/Louisville', - 'America/Kentucky/Monticello', - 'America/Knox_IN', - 'America/Kralendijk', - 'America/La_Paz', - 'America/Lima', - 'America/Los_Angeles', - 'America/Louisville', - 'America/Lower_Princes', - 'America/Maceio', - 'America/Managua', - 'America/Manaus', - 'America/Marigot', - 'America/Martinique', - 'America/Matamoros', - 'America/Mazatlan', - 'America/Mendoza', - 'America/Menominee', - 'America/Merida', - 'America/Metlakatla', - 'America/Mexico_City', - 'America/Miquelon', - 'America/Moncton', - 'America/Monterrey', - 'America/Montevideo', - 'America/Montreal', - 'America/Montserrat', - 'America/Nassau', - 'America/New_York', - 'America/Nipigon', - 'America/Nome', - 'America/Noronha', - 'America/North_Dakota/Beulah', - 'America/North_Dakota/Center', - 'America/North_Dakota/New_Salem', - 'America/Ojinaga', - 'America/Panama', - 'America/Pangnirtung', - 'America/Paramaribo', - 'America/Phoenix', - 'America/Port-au-Prince', - 'America/Port_of_Spain', - 'America/Porto_Acre', - 'America/Porto_Velho', - 'America/Puerto_Rico', - 'America/Punta_Arenas', - 'America/Rainy_River', - 'America/Rankin_Inlet', - 'America/Recife', - 'America/Regina', - 'America/Resolute', - 'America/Rio_Branco', - 'America/Rosario', - 'America/Santa_Isabel', - 'America/Santarem', - 'America/Santiago', - 'America/Santo_Domingo', - 'America/Sao_Paulo', - 'America/Scoresbysund', - 'America/Shiprock', - 'America/Sitka', - 'America/St_Barthelemy', - 'America/St_Johns', - 'America/St_Kitts', - 'America/St_Lucia', - 'America/St_Thomas', - 'America/St_Vincent', - 'America/Swift_Current', - 'America/Tegucigalpa', - 'America/Thule', - 'America/Thunder_Bay', - 'America/Tijuana', - 'America/Toronto', - 'America/Tortola', - 'America/Vancouver', - 'America/Virgin', - 'America/Whitehorse', - 'America/Winnipeg', - 'America/Yakutat', - 'America/Yellowknife', - 'Antarctica/Casey', - 'Antarctica/Davis', - 'Antarctica/DumontDUrville', - 'Antarctica/Macquarie', - 'Antarctica/Mawson', - 'Antarctica/McMurdo', - 'Antarctica/Palmer', - 'Antarctica/Rothera', - 'Antarctica/South_Pole', - 'Antarctica/Syowa', - 'Antarctica/Troll', - 'Antarctica/Vostok', - 'Arctic/Longyearbyen', - 'Asia/Aden', - 'Asia/Almaty', - 'Asia/Amman', - 'Asia/Anadyr', - 'Asia/Aqtau', - 'Asia/Aqtobe', - 'Asia/Ashgabat', - 'Asia/Ashkhabad', - 'Asia/Atyrau', - 'Asia/Baghdad', - 'Asia/Bahrain', - 'Asia/Baku', - 'Asia/Bangkok', - 'Asia/Barnaul', - 'Asia/Beirut', - 'Asia/Bishkek', - 'Asia/Brunei', - 'Asia/Calcutta', - 'Asia/Chita', - 'Asia/Choibalsan', - 'Asia/Chongqing', - 'Asia/Chungking', - 'Asia/Colombo', - 'Asia/Dacca', - 'Asia/Damascus', - 'Asia/Dhaka', - 'Asia/Dili', - 'Asia/Dubai', - 'Asia/Dushanbe', - 'Asia/Famagusta', - 'Asia/Gaza', - 'Asia/Harbin', - 'Asia/Hebron', - 'Asia/Ho_Chi_Minh', - 'Asia/Hong_Kong', - 'Asia/Hovd', - 'Asia/Irkutsk', - 'Asia/Istanbul', - 'Asia/Jakarta', - 'Asia/Jayapura', - 'Asia/Jerusalem', - 'Asia/Kabul', - 'Asia/Kamchatka', - 'Asia/Karachi', - 'Asia/Kashgar', - 'Asia/Kathmandu', - 'Asia/Katmandu', - 'Asia/Khandyga', - 'Asia/Kolkata', - 'Asia/Krasnoyarsk', - 'Asia/Kuala_Lumpur', - 'Asia/Kuching', - 'Asia/Kuwait', - 'Asia/Macao', - 'Asia/Macau', - 'Asia/Magadan', - 'Asia/Makassar', - 'Asia/Manila', - 'Asia/Muscat', - 'Asia/Nicosia', - 'Asia/Novokuznetsk', - 'Asia/Novosibirsk', - 'Asia/Omsk', - 'Asia/Oral', - 'Asia/Phnom_Penh', - 'Asia/Pontianak', - 'Asia/Pyongyang', - 'Asia/Qatar', - 'Asia/Qyzylorda', - 'Asia/Rangoon', - 'Asia/Riyadh', - 'Asia/Saigon', - 'Asia/Sakhalin', - 'Asia/Samarkand', - 'Asia/Seoul', - 'Asia/Shanghai', - 'Asia/Singapore', - 'Asia/Srednekolymsk', - 'Asia/Taipei', - 'Asia/Tashkent', - 'Asia/Tbilisi', - 'Asia/Tehran', - 'Asia/Tel_Aviv', - 'Asia/Thimbu', - 'Asia/Thimphu', - 'Asia/Tokyo', - 'Asia/Tomsk', - 'Asia/Ujung_Pandang', - 'Asia/Ulaanbaatar', - 'Asia/Ulan_Bator', - 'Asia/Urumqi', - 'Asia/Ust-Nera', - 'Asia/Vientiane', - 'Asia/Vladivostok', - 'Asia/Yakutsk', - 'Asia/Yangon', - 'Asia/Yekaterinburg', - 'Asia/Yerevan', - 'Atlantic/Azores', - 'Atlantic/Bermuda', - 'Atlantic/Canary', - 'Atlantic/Cape_Verde', - 'Atlantic/Faeroe', - 'Atlantic/Faroe', - 'Atlantic/Jan_Mayen', - 'Atlantic/Madeira', - 'Atlantic/Reykjavik', - 'Atlantic/South_Georgia', - 'Atlantic/St_Helena', - 'Atlantic/Stanley', - 'Australia/ACT', - 'Australia/Adelaide', - 'Australia/Brisbane', - 'Australia/Broken_Hill', - 'Australia/Canberra', - 'Australia/Currie', - 'Australia/Darwin', - 'Australia/Eucla', - 'Australia/Hobart', - 'Australia/LHI', - 'Australia/Lindeman', - 'Australia/Lord_Howe', - 'Australia/Melbourne', - 'Australia/NSW', - 'Australia/North', - 'Australia/Perth', - 'Australia/Queensland', - 'Australia/South', - 'Australia/Sydney', - 'Australia/Tasmania', - 'Australia/Victoria', - 'Australia/West', - 'Australia/Yancowinna', - 'Brazil/Acre', - 'Brazil/DeNoronha', - 'Brazil/East', - 'Brazil/West', - 'CET', - 'CST6CDT', - 'Canada/Atlantic', - 'Canada/Central', - 'Canada/Eastern', - 'Canada/Mountain', - 'Canada/Newfoundland', - 'Canada/Pacific', - 'Canada/Saskatchewan', - 'Canada/Yukon', - 'Chile/Continental', - 'Chile/EasterIsland', - 'Cuba', - 'EET', - 'EST', - 'EST5EDT', - 'Egypt', - 'Eire', - 'Etc/GMT', - 'Etc/GMT+0', - 'Etc/GMT+1', - 'Etc/GMT+10', - 'Etc/GMT+11', - 'Etc/GMT+12', - 'Etc/GMT+2', - 'Etc/GMT+3', - 'Etc/GMT+4', - 'Etc/GMT+5', - 'Etc/GMT+6', - 'Etc/GMT+7', - 'Etc/GMT+8', - 'Etc/GMT+9', - 'Etc/GMT-0', - 'Etc/GMT-1', - 'Etc/GMT-10', - 'Etc/GMT-11', - 'Etc/GMT-12', - 'Etc/GMT-13', - 'Etc/GMT-14', - 'Etc/GMT-2', - 'Etc/GMT-3', - 'Etc/GMT-4', - 'Etc/GMT-5', - 'Etc/GMT-6', - 'Etc/GMT-7', - 'Etc/GMT-8', - 'Etc/GMT-9', - 'Etc/GMT0', - 'Etc/Greenwich', - 'Etc/UCT', - 'Etc/UTC', - 'Etc/Universal', - 'Etc/Zulu', - 'Europe/Amsterdam', - 'Europe/Andorra', - 'Europe/Astrakhan', - 'Europe/Athens', - 'Europe/Belfast', - 'Europe/Belgrade', - 'Europe/Berlin', - 'Europe/Bratislava', - 'Europe/Brussels', - 'Europe/Bucharest', - 'Europe/Budapest', - 'Europe/Busingen', - 'Europe/Chisinau', - 'Europe/Copenhagen', - 'Europe/Dublin', - 'Europe/Gibraltar', - 'Europe/Guernsey', - 'Europe/Helsinki', - 'Europe/Isle_of_Man', - 'Europe/Istanbul', - 'Europe/Jersey', - 'Europe/Kaliningrad', - 'Europe/Kiev', - 'Europe/Kirov', - 'Europe/Lisbon', - 'Europe/Ljubljana', - 'Europe/London', - 'Europe/Luxembourg', - 'Europe/Madrid', - 'Europe/Malta', - 'Europe/Mariehamn', - 'Europe/Minsk', - 'Europe/Monaco', - 'Europe/Moscow', - 'Europe/Nicosia', - 'Europe/Oslo', - 'Europe/Paris', - 'Europe/Podgorica', - 'Europe/Prague', - 'Europe/Riga', - 'Europe/Rome', - 'Europe/Samara', - 'Europe/San_Marino', - 'Europe/Sarajevo', - 'Europe/Saratov', - 'Europe/Simferopol', - 'Europe/Skopje', - 'Europe/Sofia', - 'Europe/Stockholm', - 'Europe/Tallinn', - 'Europe/Tirane', - 'Europe/Tiraspol', - 'Europe/Ulyanovsk', - 'Europe/Uzhgorod', - 'Europe/Vaduz', - 'Europe/Vatican', - 'Europe/Vienna', - 'Europe/Vilnius', - 'Europe/Volgograd', - 'Europe/Warsaw', - 'Europe/Zagreb', - 'Europe/Zaporozhye', - 'Europe/Zurich', - 'GB', - 'GB-Eire', - 'GMT', - 'GMT+0', - 'GMT-0', - 'GMT0', - 'Greenwich', - 'HST', - 'Hongkong', - 'Iceland', - 'Indian/Antananarivo', - 'Indian/Chagos', - 'Indian/Christmas', - 'Indian/Cocos', - 'Indian/Comoro', - 'Indian/Kerguelen', - 'Indian/Mahe', - 'Indian/Maldives', - 'Indian/Mauritius', - 'Indian/Mayotte', - 'Indian/Reunion', - 'Iran', - 'Israel', - 'Jamaica', - 'Japan', - 'Kwajalein', - 'Libya', - 'MET', - 'MST', - 'MST7MDT', - 'Mexico/BajaNorte', - 'Mexico/BajaSur', - 'Mexico/General', - 'NZ', - 'NZ-CHAT', - 'Navajo', - 'PRC', - 'PST8PDT', - 'Pacific/Apia', - 'Pacific/Auckland', - 'Pacific/Bougainville', - 'Pacific/Chatham', - 'Pacific/Chuuk', - 'Pacific/Easter', - 'Pacific/Efate', - 'Pacific/Enderbury', - 'Pacific/Fakaofo', - 'Pacific/Fiji', - 'Pacific/Funafuti', - 'Pacific/Galapagos', - 'Pacific/Gambier', - 'Pacific/Guadalcanal', - 'Pacific/Guam', - 'Pacific/Honolulu', - 'Pacific/Johnston', - 'Pacific/Kiritimati', - 'Pacific/Kosrae', - 'Pacific/Kwajalein', - 'Pacific/Majuro', - 'Pacific/Marquesas', - 'Pacific/Midway', - 'Pacific/Nauru', - 'Pacific/Niue', - 'Pacific/Norfolk', - 'Pacific/Noumea', - 'Pacific/Pago_Pago', - 'Pacific/Palau', - 'Pacific/Pitcairn', - 'Pacific/Pohnpei', - 'Pacific/Ponape', - 'Pacific/Port_Moresby', - 'Pacific/Rarotonga', - 'Pacific/Saipan', - 'Pacific/Samoa', - 'Pacific/Tahiti', - 'Pacific/Tarawa', - 'Pacific/Tongatapu', - 'Pacific/Truk', - 'Pacific/Wake', - 'Pacific/Wallis', - 'Pacific/Yap', - 'Poland', - 'Portugal', - 'ROC', - 'ROK', - 'Singapore', - 'Turkey', - 'UCT', - 'US/Alaska', - 'US/Aleutian', - 'US/Arizona', - 'US/Central', - 'US/East-Indiana', - 'US/Eastern', - 'US/Hawaii', - 'US/Indiana-Starke', - 'US/Michigan', - 'US/Mountain', - 'US/Pacific', - 'US/Pacific-New', - 'US/Samoa', - 'UTC', - 'Universal', - 'W-SU', - 'WET', - 'Zulu', -]; +import { allTimezones } from './timezone.helpers'; -export type Timezone = (typeof tzs)[number]; +export type Timezone = (typeof allTimezones)[number]; diff --git a/grafana-plugin/src/models/webinar/webinar.ts b/grafana-plugin/src/models/webinar/webinar.ts deleted file mode 100644 index 134d6a5d..00000000 --- a/grafana-plugin/src/models/webinar/webinar.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { action, observable } from 'mobx'; -import moment from 'moment-timezone'; - -import BaseStore from 'models/base_store'; -import { makeRequest } from 'network'; -import { RootStore } from 'state'; - -import { Webinar } from './webinar.types'; - -export class WebinarStore extends BaseStore { - @observable.shallow - searchResult?: { [key: string]: Array }; - - @observable.shallow - items?: { [id: string]: Webinar }; - - constructor(rootStore: RootStore) { - super(rootStore); - - this.path = '/webinars/'; - } - - @action - async subscribe(id: Webinar['id']) { - return await makeRequest(`/webinars/${id}/subscribe/`, { - method: 'POST', - withCredentials: true, - }); - } - - async updateItems(query = '') { - const result = await this.getAll(); - - this.items = { - ...this.items, - ...result.reduce( - (acc: { [key: number]: Webinar }, item: Webinar) => ({ - ...acc, - [item.id]: item, - }), - {} - ), - }; - - this.searchResult = { - ...(this.searchResult || {}), - [query]: result.map((item: Webinar) => item.id), - }; - } - - getSearchResult(query = '') { - if (!this.searchResult || !this.items) { - return undefined; - } - - return this.searchResult[query].map((scheduleId: Webinar['id']) => this.items?.[scheduleId]); - } - - getFutureWebinarsCount(): number { - const items = this.getSearchResult(); - if (!items) { - return 0; - } - - return items.filter((webinar?: Webinar) => moment(webinar?.datetime).isAfter() && !webinar?.subscribed).length; - } -} diff --git a/grafana-plugin/src/models/webinar/webinar.types.ts b/grafana-plugin/src/models/webinar/webinar.types.ts deleted file mode 100644 index 7d802143..00000000 --- a/grafana-plugin/src/models/webinar/webinar.types.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { UserDTO } from 'models/user'; - -export interface Webinar { - id: string; - title: string; - additional_emails: string[]; - datetime: string; - description: string; - image: string; - link: string; - registered_users: Array; - subscribed: boolean; -} diff --git a/grafana-plugin/src/pages/index.tsx b/grafana-plugin/src/pages/index.tsx index 9ada4824..48e9a989 100644 --- a/grafana-plugin/src/pages/index.tsx +++ b/grafana-plugin/src/pages/index.tsx @@ -144,13 +144,6 @@ export const pages: { [id: string]: PageDefinition } = [ path: getPath('cloud'), action: UserActions.OtherSettingsWrite, }, - { - icon: 'gf-logs', - id: 'organization-logs', - text: 'Org Logs', - hideFromTabs: true, - path: getPath('organization-logs'), - }, { icon: 'cog', id: 'test', @@ -188,7 +181,6 @@ export const ROUTES = { outgoing_webhooks_2: ['outgoing_webhooks_2', 'outgoing_webhooks_2/:id', 'outgoing_webhooks_2/:action/:id'], maintenance: ['maintenance'], settings: ['settings'], - 'organization-logs': ['organization-logs'], 'chat-ops': ['chat-ops'], 'live-settings': ['live-settings'], cloud: ['cloud'], diff --git a/grafana-plugin/src/pages/organization-logs/OrganizationLog.module.css b/grafana-plugin/src/pages/organization-logs/OrganizationLog.module.css deleted file mode 100644 index 805f05ea..00000000 --- a/grafana-plugin/src/pages/organization-logs/OrganizationLog.module.css +++ /dev/null @@ -1,23 +0,0 @@ -.header { - display: flex; - justify-content: space-between; -} - -.align-top { - vertical-align: top; -} - -.no-author { - background: #fff7e6; -} - -.root .no-background { - background: none; -} - -.root .short-description { - overflow: hidden; - text-overflow: ellipsis; - width: 400px; - white-space: nowrap; -} diff --git a/grafana-plugin/src/pages/organization-logs/OrganizationLog.tsx b/grafana-plugin/src/pages/organization-logs/OrganizationLog.tsx deleted file mode 100644 index 66a7d5b5..00000000 --- a/grafana-plugin/src/pages/organization-logs/OrganizationLog.tsx +++ /dev/null @@ -1,199 +0,0 @@ -import React from 'react'; - -import { Button, HorizontalGroup, Tag, Tooltip } from '@grafana/ui'; -import cn from 'classnames/bind'; -import { debounce } from 'lodash-es'; -import { observer } from 'mobx-react'; -import moment, { Moment } from 'moment-timezone'; -import { RouteComponentProps } from 'react-router-dom'; - -import Avatar from 'components/Avatar/Avatar'; -import GTable from 'components/GTable/GTable'; -import PluginLink from 'components/PluginLink/PluginLink'; -import Text from 'components/Text/Text'; -import OrganizationLogFilters from 'containers/OrganizationLogFilters/OrganizationLogFilters'; -import logo from 'img/logo.svg'; -import { OrganizationLog } from 'models/organization_log/organization_log.types'; -import { WithStoreProps } from 'state/types'; -import { withMobXProviderContext } from 'state/withStore'; -import sanitize from 'utils/sanitize'; - -import styles from './OrganizationLog.module.css'; - -const cx = cn.bind(styles); - -interface OrganizationLogProps extends WithStoreProps, RouteComponentProps {} - -interface OrganizationLogState { - filters: { [key: string]: any }; - page: number; - expandedLogsKeys: string[]; -} - -const INITIAL_FILTERS = {}; - -const ITEMS_PER_PAGE = 50; - -@observer -class OrganizationLogPage extends React.Component { - state: OrganizationLogState = { filters: { ...INITIAL_FILTERS }, page: 1, expandedLogsKeys: [] }; - - componentDidMount() { - this.refresh(); - } - - refresh = () => { - const { store } = this.props; - - const { filters, page } = this.state; - store.OrganizationLogStore.updateItems('', page, { - ...filters, - created_at: filters.created_at - ? filters.created_at.map((m: Moment) => m.utc().format('YYYY-MM-DDTHH:mm:ss')).join('/') - : undefined, - }); - }; - - debouncedRefresh = debounce(this.refresh, 500); - - render() { - const { filters, expandedLogsKeys } = this.state; - const { store } = this.props; - const { OrganizationLogStore } = store; - - const columns = [ - { - width: '40%', - title: 'Action', - render: this.renderShortDescription, - key: 'action', - }, - { - width: '10%', - title: 'User', - render: this.renderUser, - key: 'user', - }, - { - width: '30%', - title: 'Labels', - render: this.renderLabels, - key: 'labels', - }, - { - width: '20%', - title: 'Time', - render: this.renderCreatedAt, - key: 'created_at', - }, - ]; - - const searchResult: any = OrganizationLogStore.getSearchResult() || {}; - - const { total, page, results } = searchResult; - - const loading = !results; - - return ( -

    - ); - } - - handleExpandedRowsChange = (expandedRows: string[]) => { - this.setState({ expandedLogsKeys: expandedRows }); - }; - - handleChangePage = (page: number) => { - this.setState({ page }, this.refresh); - }; - - handleChangeOrganizationLogFilters = (filters: any) => { - this.setState({ filters, page: 1 }, this.debouncedRefresh); - }; - - renderShortDescription = (item: OrganizationLog) => { - return
    {item.description}
    ; - }; - - renderFullDescription = (item: OrganizationLog) => { - return ( -
    - ); - }; - - renderUser = (item: OrganizationLog) => { - if (!item.author) { - return ( - - - - ); - } - - return ( - - - - - - - - ); - }; - - renderLabels = (item: OrganizationLog) => { - if (!item.labels) { - return null; - } - - return ( - - {item.labels.map((label) => ( - - ))} - - ); - }; - - renderCreatedAt = (item: OrganizationLog) => { - return moment(item.created_at).toString(); - }; -} - -export default withMobXProviderContext(OrganizationLogPage); diff --git a/grafana-plugin/src/pages/routes.tsx b/grafana-plugin/src/pages/routes.tsx index 79699577..6bacfe95 100644 --- a/grafana-plugin/src/pages/routes.tsx +++ b/grafana-plugin/src/pages/routes.tsx @@ -2,7 +2,6 @@ import EscalationsChainsPage from 'pages/escalation-chains/EscalationChains'; import IncidentPage from 'pages/incident/Incident'; import IncidentsPage from 'pages/incidents/Incidents'; import MaintenancePage from 'pages/maintenance/Maintenance'; -import OrganizationLogPage from 'pages/organization-logs/OrganizationLog'; import OutgoingWebhooks from 'pages/outgoing_webhooks/OutgoingWebhooks'; import OutgoingWebhooks2 from 'pages/outgoing_webhooks_2/OutgoingWebhooks2'; import SchedulePage from 'pages/schedule/Schedule'; @@ -73,10 +72,6 @@ export const routes: { [id: string]: NavRoute } = [ component: LiveSettingsPage, id: 'live-settings', }, - { - component: OrganizationLogPage, - id: 'organization-logs', - }, { component: CloudPage, id: 'cloud', diff --git a/grafana-plugin/src/plugin/GrafanaPluginRootPage.tsx b/grafana-plugin/src/plugin/GrafanaPluginRootPage.tsx index e95b8b16..6ecc03e5 100644 --- a/grafana-plugin/src/plugin/GrafanaPluginRootPage.tsx +++ b/grafana-plugin/src/plugin/GrafanaPluginRootPage.tsx @@ -27,7 +27,6 @@ import Incidents from 'pages/incidents/Incidents'; import Integration from 'pages/integration/Integration'; import Integrations from 'pages/integrations/Integrations'; import Maintenance from 'pages/maintenance/Maintenance'; -import OrganizationLogPage from 'pages/organization-logs/OrganizationLog'; import OutgoingWebhooks from 'pages/outgoing_webhooks/OutgoingWebhooks'; import OutgoingWebhooks2 from 'pages/outgoing_webhooks_2/OutgoingWebhooks2'; import Schedule from 'pages/schedule/Schedule'; @@ -37,7 +36,6 @@ import ChatOps from 'pages/settings/tabs/ChatOps/ChatOps'; import CloudPage from 'pages/settings/tabs/Cloud/CloudPage'; import LiveSettings from 'pages/settings/tabs/LiveSettings/LiveSettingsPage'; import Users from 'pages/users/Users'; -import 'interceptors'; import { rootStore } from 'state'; import { useStore } from 'state/useStore'; import { isUserActionAllowed } from 'utils/authorization'; @@ -176,9 +174,6 @@ export const Root = observer((props: AppRootProps) => { - - - diff --git a/grafana-plugin/src/services/experimentManager.ts b/grafana-plugin/src/services/experimentManager.ts deleted file mode 100644 index 8eb8ac67..00000000 --- a/grafana-plugin/src/services/experimentManager.ts +++ /dev/null @@ -1,16 +0,0 @@ -import Cookies from 'js-cookie'; -import qs from 'query-string'; - -const query = qs.parse(window.location.search); - -if (query.version === 'nf') { - Cookies.set('nf', '1', { expires: 31, path: '/' }); -} - -export function getABTestVariant() { - return Cookies.get('ab_test_variant'); -} - -export function getIsNoFreeExperiment() { - return Cookies.get('nf') === '1'; -} diff --git a/grafana-plugin/src/services/googleTagManager.ts b/grafana-plugin/src/services/googleTagManager.ts deleted file mode 100644 index 301e4d47..00000000 --- a/grafana-plugin/src/services/googleTagManager.ts +++ /dev/null @@ -1,5 +0,0 @@ -export function pushConvertion(message: any) { - if (window.dataLayer) { - window.dataLayer.push(message); - } -} diff --git a/grafana-plugin/src/services/urlManager.ts b/grafana-plugin/src/services/urlManager.ts deleted file mode 100644 index e9554b0a..00000000 --- a/grafana-plugin/src/services/urlManager.ts +++ /dev/null @@ -1,24 +0,0 @@ -import qs from 'query-string'; - -export function updateQueryParams(params: any, isReplace = false) { - const query = qs.stringify(params); - - if (isReplace) { - window.history.replaceState(null, '', `${window.location.pathname}?${query}`); - return; - } - - window.history.pushState(null, '', `${window.location.pathname}?${query}`); -} - -export function mergeQueryParams(params: any) { - const currentParams = qs.parse(window.location.search); - const newParams = { - ...currentParams, - ...params, - }; - - const query = qs.stringify(newParams); - - return query; -} diff --git a/grafana-plugin/src/state/rootBaseStore/index.ts b/grafana-plugin/src/state/rootBaseStore/index.ts index 7540f7fb..3cb525f7 100644 --- a/grafana-plugin/src/state/rootBaseStore/index.ts +++ b/grafana-plugin/src/state/rootBaseStore/index.ts @@ -18,7 +18,6 @@ import { FiltersStore } from 'models/filters/filters'; import { GlobalSettingStore } from 'models/global_setting/global_setting'; import { GrafanaTeamStore } from 'models/grafana_team/grafana_team'; import { HeartbeatStore } from 'models/heartbeat/heartbeat'; -import { OrganizationLogStore } from 'models/organization_log/organization_log'; import { OutgoingWebhookStore } from 'models/outgoing_webhook/outgoing_webhook'; import { OutgoingWebhook2Store } from 'models/outgoing_webhook_2/outgoing_webhook_2'; import { ResolutionNotesStore } from 'models/resolution_note/resolution_note'; @@ -102,7 +101,6 @@ export class RootBaseStore { alertGroupStore: AlertGroupStore = new AlertGroupStore(this); resolutionNotesStore: ResolutionNotesStore = new ResolutionNotesStore(this); apiTokenStore: ApiTokenStore = new ApiTokenStore(this); - OrganizationLogStore: OrganizationLogStore = new OrganizationLogStore(this); globalSettingStore: GlobalSettingStore = new GlobalSettingStore(this); filtersStore: FiltersStore = new FiltersStore(this); // stores From 77f6dedce5402e4c7f3871ade1c850237538070c Mon Sep 17 00:00:00 2001 From: Joey Orlando Date: Thu, 13 Jul 2023 11:22:59 +0200 Subject: [PATCH 09/11] add index on started_at column in alert groups (#2516) # What this PR does Adds an index on the `started_at` column in the `alerts_alertgroup` table. For the alert groups query used by the `check_escalation_finished_task`, this resulted in a huge performance boost, taking the query time from 89mins to 4secs (on our largest production dataset). ## Which issue(s) this PR fixes closes #724 closes https://github.com/grafana/oncall-private/issues/1713 ## Checklist - [x] Unit, integration, and e2e (if applicable) tests updated - [x] Documentation added (or `pr:no public docs` PR label added if not required) - [x] `CHANGELOG.md` updated (or `pr:no changelog` PR label added if not required) --- CHANGELOG.md | 2 + docs/sources/open-source/_index.md | 11 +- .../0021_alter_alertgroup_started_at.py | 18 + engine/apps/alerts/models/alert_group.py | 2 +- .../alerts/tasks/check_escalation_finished.py | 34 +- .../test_check_escalation_finished_task.py | 355 ++++++++++-------- engine/settings/base.py | 21 +- 7 files changed, 240 insertions(+), 203 deletions(-) create mode 100644 engine/apps/alerts/migrations/0021_alter_alertgroup_started_at.py diff --git a/CHANGELOG.md b/CHANGELOG.md index f5602d1a..685fa9a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [Helm] Added ability to specify `resources` definition within the `wait-for-db` init container by @Shelestov7 ([#2501](https://github.com/grafana/oncall/pull/2501)) +- Added index on `started_at` column in `alerts_alertgroup` table. This substantially speeds up query used by the `check_escalation_finished_task` + task. By @joeyorlando and @Konstantinov-Innokentii ([#2516](https://github.com/grafana/oncall/pull/2516)). ### Changed diff --git a/docs/sources/open-source/_index.md b/docs/sources/open-source/_index.md index 27ca9e60..674f5d78 100644 --- a/docs/sources/open-source/_index.md +++ b/docs/sources/open-source/_index.md @@ -222,12 +222,12 @@ Zvonok.com, complete the following steps: 2. Create a public API key on the Profile->Settings page, and assign its value to `ZVONOK_API_KEY`. 3. Create campaign and assign its ID value to `ZVONOK_CAMPAIGN_ID`. 4. If you are planning to use pre-recorded audio instead of a speech synthesizer, you can copy the ID of the audio clip -to the variable `ZVONOK_AUDIO_ID` (optional step). + to the variable `ZVONOK_AUDIO_ID` (optional step). 5. To make a call with a specific voice, you can set the `ZVONOK_SPEAKER_ID`. -By default, the ID used is `Salli` (optional step). + By default, the ID used is `Salli` (optional step). 6. To process the call status, it is required to add a postback with the GET/POST method on the side of the zvonok.com -service with the following format (optional step): -`${ONCALL_BASE_URL}/zvonok/call_status_events?campaign_id={ct_campaign_id}&call_id={ct_call_id}&status={ct_status}&user_choice={ct_user_choice}` + service with the following format (optional step): + `${ONCALL_BASE_URL}/zvonok/call_status_events?campaign_id={ct_campaign_id}&call_id={ct_call_id}&status={ct_status}&user_choice={ct_user_choice}` The names of the transmitted parameters can be redefined through environment variables: @@ -312,3 +312,6 @@ To configure this feature as such: task runs every 13 minutes so we therefore recommend setting the heartbeat's expected time interval to 15 minutes. If you would like to modify this, we recommend configuring this env variable to 1 or 2 minutes less than the value set for the integration's heartbeat expected time interval. + +Additionally, if you prefer to disable this feature, you can set the `ESCALATION_AUDITOR_ENABLED` environment variable +to `False`. diff --git a/engine/apps/alerts/migrations/0021_alter_alertgroup_started_at.py b/engine/apps/alerts/migrations/0021_alter_alertgroup_started_at.py new file mode 100644 index 00000000..2f05a63a --- /dev/null +++ b/engine/apps/alerts/migrations/0021_alter_alertgroup_started_at.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.20 on 2023-07-13 06:48 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('alerts', '0020_auto_20230711_1532'), + ] + + operations = [ + migrations.AlterField( + model_name='alertgroup', + name='started_at', + field=models.DateTimeField(auto_now_add=True, db_index=True), + ), + ] diff --git a/engine/apps/alerts/models/alert_group.py b/engine/apps/alerts/models/alert_group.py index ca93602a..e44f2527 100644 --- a/engine/apps/alerts/models/alert_group.py +++ b/engine/apps/alerts/models/alert_group.py @@ -242,7 +242,7 @@ class AlertGroup(AlertGroupSlackRenderingMixin, EscalationSnapshotMixin, models. acknowledged_by_confirmed = models.DateTimeField(null=True, default=None) is_escalation_finished = models.BooleanField(default=False) - started_at = models.DateTimeField(auto_now_add=True) + started_at = models.DateTimeField(auto_now_add=True, db_index=True) slack_message_sent = models.BooleanField(default=False) diff --git a/engine/apps/alerts/tasks/check_escalation_finished.py b/engine/apps/alerts/tasks/check_escalation_finished.py index 993ec623..343696c9 100644 --- a/engine/apps/alerts/tasks/check_escalation_finished.py +++ b/engine/apps/alerts/tasks/check_escalation_finished.py @@ -1,7 +1,6 @@ import datetime import typing -import pytz import requests from celery import shared_task from django.apps import apps @@ -96,38 +95,27 @@ def audit_alert_group_escalation(alert_group: "AlertGroup") -> None: task_logger.info(f"{base_msg} passed the audit checks") -def get_auditable_alert_groups_started_at_range() -> typing.Tuple[datetime.datetime, datetime.datetime]: - """ - NOTE: this started_at__range is a bit of a hack.. - we wanted to avoid performing a migration on the alerts_alertgroup table to update - alert groups where raw_escalation_snapshot was None. raw_escalation_snapshot being None is a legitimate case, - where the alert group's integration does not have an escalation chain associated with it. - - However, we wanted a way to be able to differentiate between "actually None" and "there was an error writing to - raw_escalation_snapshot" (as this is performed async by a celery task). - - This field was updated, in the commit that added this comment, to no longer be set to None by default. - As part of this celery task we do a check that this field is in fact not None, so if we were to check older - alert groups, whose integration did not have an escalation chain at the time the alert group was created - we would raise errors - """ - return (datetime.datetime(2023, 3, 25, tzinfo=pytz.UTC), timezone.now() - datetime.timedelta(days=2)) - - -# don't retry this task as the AlertGroup DB query is rather expensive @shared_task def check_escalation_finished_task() -> None: + """ + don't retry this task, the idea is to be alerted of failures + """ AlertGroup = apps.get_model("alerts", "AlertGroup") - AlertReceiveChannel = apps.get_model("alerts", "AlertReceiveChannel") + + now = timezone.now() + two_days_ago = now - datetime.timedelta(days=2) alert_groups = AlertGroup.all_objects.using(get_random_readonly_database_key_if_present_otherwise_default()).filter( - ~Q(channel__integration=AlertReceiveChannel.INTEGRATION_MAINTENANCE), ~Q(silenced=True, silenced_until__isnull=True), # filter silenced forever alert_groups + # here we should query maintenance_uuid rather than joining on channel__integration + # and checking for something like ~Q(channel__integration=AlertReceiveChannel.INTEGRATION_MAINTENANCE) + # this avoids an unnecessary join + maintenance_uuid__isnull=True, is_escalation_finished=False, resolved=False, acknowledged=False, root_alert_group=None, - started_at__range=get_auditable_alert_groups_started_at_range(), + started_at__range=(two_days_ago, now), ) if not alert_groups.exists(): diff --git a/engine/apps/alerts/tests/test_check_escalation_finished_task.py b/engine/apps/alerts/tests/test_check_escalation_finished_task.py index ad057102..ab0cfaaf 100644 --- a/engine/apps/alerts/tests/test_check_escalation_finished_task.py +++ b/engine/apps/alerts/tests/test_check_escalation_finished_task.py @@ -1,11 +1,10 @@ -from unittest.mock import Mock, PropertyMock, patch +from unittest.mock import Mock, PropertyMock, call, patch import pytest import requests from django.test import override_settings from django.utils import timezone -from apps.alerts.models import AlertGroup from apps.alerts.tasks.check_escalation_finished import ( AlertGroupEscalationPolicyExecutionAuditException, audit_alert_group_escalation, @@ -15,40 +14,70 @@ from apps.alerts.tasks.check_escalation_finished import ( MOCKED_HEARTBEAT_URL = "https://hello.com/lsdjjkf" - -# def _get_relevant_log_record_type() -> int: -# return random.choice([AlertGroupLogRecord.TYPE_ESCALATION_TRIGGERED, AlertGroupLogRecord.TYPE_ESCALATION_FAILED]) +now = timezone.now() +yesterday = now - timezone.timedelta(days=1) -def test_send_alert_group_escalation_auditor_task_heartbeat_does_not_call_the_heartbeat_url_if_one_is_not_configured(): - with patch("apps.alerts.tasks.check_escalation_finished.requests") as mock_requests: - send_alert_group_escalation_auditor_task_heartbeat() - mock_requests.get.assert_not_called() +@pytest.fixture +def make_alert_group_that_started_at_specific_date(make_alert_group): + def _make_alert_group_that_started_at_specific_date(alert_receive_channel, started_at=yesterday, **kwargs): + # we can't simply pass started_at to the fixture because started_at is being "auto-set" on the Model + alert_group = make_alert_group(alert_receive_channel, **kwargs) + alert_group.started_at = started_at + alert_group.save() + + return alert_group + + return _make_alert_group_that_started_at_specific_date +def assert_not_called_with(self, *args, **kwargs): + """ + https://stackoverflow.com/a/54838760 + """ + try: + self.assert_called_with(*args, **kwargs) + except AssertionError: + return + raise AssertionError("Expected %s to not have been called." % self._format_mock_call_signature(args, kwargs)) + + +Mock.assert_not_called_with = assert_not_called_with + + +@patch("apps.alerts.tasks.check_escalation_finished.requests") +def test_send_alert_group_escalation_auditor_task_heartbeat_does_not_call_the_heartbeat_url_if_one_is_not_configured( + mock_requests, +): + send_alert_group_escalation_auditor_task_heartbeat() + mock_requests.get.assert_not_called() + + +@patch("apps.alerts.tasks.check_escalation_finished.requests") @override_settings(ALERT_GROUP_ESCALATION_AUDITOR_CELERY_TASK_HEARTBEAT_URL=MOCKED_HEARTBEAT_URL) -def test_send_alert_group_escalation_auditor_task_heartbeat_calls_the_heartbeat_url_if_one_is_configured(): - with patch("apps.alerts.tasks.check_escalation_finished.requests") as mock_requests: +def test_send_alert_group_escalation_auditor_task_heartbeat_calls_the_heartbeat_url_if_one_is_configured(mock_requests): + send_alert_group_escalation_auditor_task_heartbeat() + + mock_requests.get.assert_called_once_with(MOCKED_HEARTBEAT_URL) + mock_requests.get.return_value.raise_for_status.assert_called_once_with() + + +@patch("apps.alerts.tasks.check_escalation_finished.requests") +@override_settings(ALERT_GROUP_ESCALATION_AUDITOR_CELERY_TASK_HEARTBEAT_URL=MOCKED_HEARTBEAT_URL) +def test_send_alert_group_escalation_auditor_task_heartbeat_raises_an_exception_if_the_heartbeat_url_request_fails( + mock_requests, +): + mock_response = Mock() + mock_response.status_code = 500 + mock_response.raise_for_status.side_effect = requests.exceptions.HTTPError + + mock_requests.get.return_value = mock_response + + with pytest.raises(requests.exceptions.HTTPError): send_alert_group_escalation_auditor_task_heartbeat() - mock_requests.get.assert_called_once_with(MOCKED_HEARTBEAT_URL) - mock_requests.get.return_value.raise_for_status.assert_called_once_with() - - -@override_settings(ALERT_GROUP_ESCALATION_AUDITOR_CELERY_TASK_HEARTBEAT_URL=MOCKED_HEARTBEAT_URL) -def test_send_alert_group_escalation_auditor_task_heartbeat_raises_an_exception_if_the_heartbeat_url_request_fails(): - with patch("apps.alerts.tasks.check_escalation_finished.requests") as mock_requests: - mock_response = Mock() - mock_response.status_code = 500 - mock_response.raise_for_status.side_effect = requests.exceptions.HTTPError - - mock_requests.get.return_value = mock_response - - with pytest.raises(requests.exceptions.HTTPError): - send_alert_group_escalation_auditor_task_heartbeat() - - mock_requests.get.assert_called_once_with(MOCKED_HEARTBEAT_URL) - mock_requests.get.return_value.raise_for_status.assert_called_once_with() + mock_requests.get.assert_called_once_with(MOCKED_HEARTBEAT_URL) + mock_requests.get.return_value.raise_for_status.assert_called_once_with() @pytest.mark.django_db @@ -75,6 +104,7 @@ def test_audit_alert_group_escalation_skips_further_validation_if_the_escalation audit_alert_group_escalation(alert_group) +@patch("apps.alerts.escalation_snapshot.snapshot_classes.escalation_snapshot.EscalationSnapshot.next_step_eta_is_valid") @pytest.mark.django_db @pytest.mark.parametrize( "next_step_eta_is_valid_return_value,raises_exception", @@ -85,38 +115,36 @@ def test_audit_alert_group_escalation_skips_further_validation_if_the_escalation ], ) def test_audit_alert_group_escalation_next_step_eta_validation( - escalation_snapshot_test_setup, next_step_eta_is_valid_return_value, raises_exception + mock_next_step_eta_is_valid, escalation_snapshot_test_setup, next_step_eta_is_valid_return_value, raises_exception +): + mock_next_step_eta_is_valid.return_value = next_step_eta_is_valid_return_value + alert_group, _, _, _ = escalation_snapshot_test_setup + + if raises_exception: + with pytest.raises(AlertGroupEscalationPolicyExecutionAuditException): + audit_alert_group_escalation(alert_group) + else: + try: + audit_alert_group_escalation(alert_group) + except AlertGroupEscalationPolicyExecutionAuditException: + pytest.fail() + + mock_next_step_eta_is_valid.assert_called_once_with() + + +@patch( + "apps.alerts.escalation_snapshot.snapshot_classes.escalation_snapshot.EscalationSnapshot.executed_escalation_policy_snapshots", + new_callable=PropertyMock, +) +@pytest.mark.django_db +def test_audit_alert_group_escalation_no_executed_escalation_policy_snapshots( + mock_executed_escalation_policy_snapshots, escalation_snapshot_test_setup ): alert_group, _, _, _ = escalation_snapshot_test_setup - with patch( - "apps.alerts.escalation_snapshot.snapshot_classes.escalation_snapshot.EscalationSnapshot.next_step_eta_is_valid" - ) as mock_next_step_eta_is_valid: - mock_next_step_eta_is_valid.return_value = next_step_eta_is_valid_return_value - - if raises_exception: - with pytest.raises(AlertGroupEscalationPolicyExecutionAuditException): - audit_alert_group_escalation(alert_group) - else: - try: - audit_alert_group_escalation(alert_group) - except AlertGroupEscalationPolicyExecutionAuditException: - pytest.fail() - - mock_next_step_eta_is_valid.assert_called_once_with() - - -@pytest.mark.django_db -def test_audit_alert_group_escalation_no_executed_escalation_policy_snapshots(escalation_snapshot_test_setup): - alert_group, _, _, _ = escalation_snapshot_test_setup - - with patch( - "apps.alerts.escalation_snapshot.snapshot_classes.escalation_snapshot.EscalationSnapshot.executed_escalation_policy_snapshots", - new_callable=PropertyMock, - ) as mock_executed_escalation_policy_snapshots: - mock_executed_escalation_policy_snapshots.return_value = [] - audit_alert_group_escalation(alert_group) - mock_executed_escalation_policy_snapshots.assert_called_once_with() + mock_executed_escalation_policy_snapshots.return_value = [] + audit_alert_group_escalation(alert_group) + mock_executed_escalation_policy_snapshots.assert_called_once_with() # # see TODO: comment in engine/apps/alerts/tasks/check_escalation_finished.py @@ -174,156 +202,151 @@ def test_audit_alert_group_escalation_no_executed_escalation_policy_snapshots(es # mock_executed_escalation_policy_snapshots.assert_called_once_with() +@patch("apps.alerts.tasks.check_escalation_finished.audit_alert_group_escalation") +@patch("apps.alerts.tasks.check_escalation_finished.send_alert_group_escalation_auditor_task_heartbeat") @pytest.mark.django_db def test_check_escalation_finished_task_queries_doesnt_grab_alert_groups_outside_of_date_range( + mocked_send_alert_group_escalation_auditor_task_heartbeat, + mocked_audit_alert_group_escalation, make_organization_and_user, make_alert_receive_channel, - make_alert_group, + make_alert_group_that_started_at_specific_date, ): organization, _ = make_organization_and_user() alert_receive_channel = make_alert_receive_channel(organization) - now = timezone.now() - two_days_ago = now - timezone.timedelta(days=2) - two_days_in_future = now + timezone.timedelta(days=2) + alert_group1 = make_alert_group_that_started_at_specific_date(alert_receive_channel) + make_alert_group_that_started_at_specific_date(alert_receive_channel, now - timezone.timedelta(days=5)) + make_alert_group_that_started_at_specific_date(alert_receive_channel, now + timezone.timedelta(days=5)) - # we can't simply pass started_at to the fixture because started_at is being "auto-set" on the Model - alert_group1 = make_alert_group(alert_receive_channel) - alert_group1.started_at = now + check_escalation_finished_task() - alert_group2 = make_alert_group(alert_receive_channel) - alert_group2.started_at = now - timezone.timedelta(days=5) - - alert_group3 = make_alert_group(alert_receive_channel) - alert_group3.started_at = now + timezone.timedelta(days=5) - - AlertGroup.all_objects.bulk_update([alert_group1, alert_group2, alert_group3], ["started_at"]) - - with patch( - "apps.alerts.tasks.check_escalation_finished.get_auditable_alert_groups_started_at_range" - ) as mocked_get_auditable_alert_groups_started_at_range: - with patch( - "apps.alerts.tasks.check_escalation_finished.audit_alert_group_escalation" - ) as mocked_audit_alert_group_escalation: - with patch( - "apps.alerts.tasks.check_escalation_finished.send_alert_group_escalation_auditor_task_heartbeat" - ) as mocked_send_alert_group_escalation_auditor_task_heartbeat: - mocked_get_auditable_alert_groups_started_at_range.return_value = (two_days_ago, two_days_in_future) - - check_escalation_finished_task() - - mocked_audit_alert_group_escalation.assert_called_once_with(alert_group1) - mocked_send_alert_group_escalation_auditor_task_heartbeat.assert_called_once_with() + mocked_audit_alert_group_escalation.assert_called_once_with(alert_group1) + mocked_send_alert_group_escalation_auditor_task_heartbeat.assert_called_once_with() +@patch("apps.alerts.tasks.check_escalation_finished.audit_alert_group_escalation") +@patch("apps.alerts.tasks.check_escalation_finished.send_alert_group_escalation_auditor_task_heartbeat") @pytest.mark.django_db def test_check_escalation_finished_task_calls_audit_alert_group_escalation_for_every_alert_group( + mocked_send_alert_group_escalation_auditor_task_heartbeat, + mocked_audit_alert_group_escalation, make_organization_and_user, make_alert_receive_channel, - make_alert_group, + make_alert_group_that_started_at_specific_date, ): organization, _ = make_organization_and_user() alert_receive_channel = make_alert_receive_channel(organization) - now = timezone.now() - two_days_ago = now - timezone.timedelta(days=2) - two_days_in_future = now + timezone.timedelta(days=2) + alert_group1 = make_alert_group_that_started_at_specific_date(alert_receive_channel) + alert_group2 = make_alert_group_that_started_at_specific_date(alert_receive_channel) + alert_group3 = make_alert_group_that_started_at_specific_date(alert_receive_channel) - # we can't simply pass started_at to the fixture because started_at is being "auto-set" on the Model - alert_group1 = make_alert_group(alert_receive_channel) - alert_group1.started_at = now + check_escalation_finished_task() - alert_group2 = make_alert_group(alert_receive_channel) - alert_group2.started_at = now + mocked_audit_alert_group_escalation.assert_any_call(alert_group1) + mocked_audit_alert_group_escalation.assert_any_call(alert_group2) + mocked_audit_alert_group_escalation.assert_any_call(alert_group3) - alert_group3 = make_alert_group(alert_receive_channel) - alert_group3.started_at = now - - AlertGroup.all_objects.bulk_update([alert_group1, alert_group2, alert_group3], ["started_at"]) - - with patch( - "apps.alerts.tasks.check_escalation_finished.get_auditable_alert_groups_started_at_range" - ) as mocked_get_auditable_alert_groups_started_at_range: - with patch( - "apps.alerts.tasks.check_escalation_finished.audit_alert_group_escalation" - ) as mocked_audit_alert_group_escalation: - with patch( - "apps.alerts.tasks.check_escalation_finished.send_alert_group_escalation_auditor_task_heartbeat" - ) as mocked_send_alert_group_escalation_auditor_task_heartbeat: - mocked_get_auditable_alert_groups_started_at_range.return_value = (two_days_ago, two_days_in_future) - - check_escalation_finished_task() - - mocked_audit_alert_group_escalation.assert_any_call(alert_group1) - mocked_audit_alert_group_escalation.assert_any_call(alert_group2) - mocked_audit_alert_group_escalation.assert_any_call(alert_group3) - mocked_send_alert_group_escalation_auditor_task_heartbeat.assert_called_once_with() + mocked_send_alert_group_escalation_auditor_task_heartbeat.assert_called_once_with() +@patch("apps.alerts.tasks.check_escalation_finished.audit_alert_group_escalation") +@patch("apps.alerts.tasks.check_escalation_finished.send_alert_group_escalation_auditor_task_heartbeat") @pytest.mark.django_db -def test_check_escalation_finished_task_simply_calls_heartbeat_when_no_alert_groups_found(): - with patch( - "apps.alerts.tasks.check_escalation_finished.audit_alert_group_escalation" - ) as mocked_audit_alert_group_escalation: - with patch( - "apps.alerts.tasks.check_escalation_finished.send_alert_group_escalation_auditor_task_heartbeat" - ) as mocked_send_alert_group_escalation_auditor_task_heartbeat: - check_escalation_finished_task() - mocked_audit_alert_group_escalation.assert_not_called() - mocked_send_alert_group_escalation_auditor_task_heartbeat.assert_called_once_with() +def test_check_escalation_finished_task_filters_the_right_alert_groups( + mocked_send_alert_group_escalation_auditor_task_heartbeat, + mocked_audit_alert_group_escalation, + make_organization_and_user, + make_alert_receive_channel, + make_alert_group_that_started_at_specific_date, +): + organization, _ = make_organization_and_user() + alert_receive_channel = make_alert_receive_channel(organization) + + alert_group1 = make_alert_group_that_started_at_specific_date(alert_receive_channel) + + silenced_for_one_hour_alert_group = make_alert_group_that_started_at_specific_date( + alert_receive_channel, silenced=True, silenced_until=(now + timezone.timedelta(hours=1)) + ) + silenced_forever = make_alert_group_that_started_at_specific_date( + alert_receive_channel, silenced=True, silenced_until=None + ) + + in_maintenance = make_alert_group_that_started_at_specific_date(alert_receive_channel, maintenance_uuid="asdfasdf") + escalation_finished = make_alert_group_that_started_at_specific_date( + alert_receive_channel, is_escalation_finished=True + ) + + resolved = make_alert_group_that_started_at_specific_date(alert_receive_channel, is_escalation_finished=True) + acknowledged = make_alert_group_that_started_at_specific_date(alert_receive_channel, is_escalation_finished=True) + + root_alert_group = make_alert_group_that_started_at_specific_date( + alert_receive_channel, root_alert_group=alert_group1 + ) + + check_escalation_finished_task() + + mocked_audit_alert_group_escalation.assert_has_calls( + [ + call(alert_group1), + call(silenced_for_one_hour_alert_group), + ], + any_order=True, + ) + + mocked_audit_alert_group_escalation.assert_not_called_with(in_maintenance) + mocked_audit_alert_group_escalation.assert_not_called_with(escalation_finished) + + mocked_audit_alert_group_escalation.assert_not_called_with(silenced_forever) + mocked_audit_alert_group_escalation.assert_not_called_with(resolved) + mocked_audit_alert_group_escalation.assert_not_called_with(acknowledged) + + mocked_audit_alert_group_escalation.assert_not_called_with(root_alert_group) +@patch("apps.alerts.tasks.check_escalation_finished.audit_alert_group_escalation") +@patch("apps.alerts.tasks.check_escalation_finished.send_alert_group_escalation_auditor_task_heartbeat") +@pytest.mark.django_db +def test_check_escalation_finished_task_simply_calls_heartbeat_when_no_alert_groups_found( + mocked_send_alert_group_escalation_auditor_task_heartbeat, + mocked_audit_alert_group_escalation, +): + check_escalation_finished_task() + mocked_audit_alert_group_escalation.assert_not_called() + mocked_send_alert_group_escalation_auditor_task_heartbeat.assert_called_once_with() + + +@patch("apps.alerts.tasks.check_escalation_finished.audit_alert_group_escalation") +@patch("apps.alerts.tasks.check_escalation_finished.send_alert_group_escalation_auditor_task_heartbeat") @pytest.mark.django_db def test_check_escalation_finished_task_calls_audit_alert_group_escalation_for_every_alert_group_even_if_one_fails( + mocked_send_alert_group_escalation_auditor_task_heartbeat, + mocked_audit_alert_group_escalation, make_organization_and_user, make_alert_receive_channel, - make_alert_group, + make_alert_group_that_started_at_specific_date, ): organization, _ = make_organization_and_user() alert_receive_channel = make_alert_receive_channel(organization) - now = timezone.now() - two_days_ago = now - timezone.timedelta(days=2) - two_days_in_future = now + timezone.timedelta(days=2) - - # we can't simply pass started_at to the fixture because started_at is being "auto-set" on the Model - alert_group1 = make_alert_group(alert_receive_channel) - alert_group1.started_at = now - - alert_group2 = make_alert_group(alert_receive_channel) - alert_group2.started_at = now - - alert_group3 = make_alert_group(alert_receive_channel) - alert_group3.started_at = now - - AlertGroup.all_objects.bulk_update([alert_group1, alert_group2, alert_group3], ["started_at"]) + alert_group1 = make_alert_group_that_started_at_specific_date(alert_receive_channel) + alert_group2 = make_alert_group_that_started_at_specific_date(alert_receive_channel) + alert_group3 = make_alert_group_that_started_at_specific_date(alert_receive_channel) def _mocked_audit_alert_group_escalation(alert_group): if not alert_group.id == alert_group3.id: raise AlertGroupEscalationPolicyExecutionAuditException("asdfasdf") - with patch( - "apps.alerts.tasks.check_escalation_finished.get_auditable_alert_groups_started_at_range" - ) as mocked_get_auditable_alert_groups_started_at_range: - with patch( - "apps.alerts.tasks.check_escalation_finished.audit_alert_group_escalation" - ) as mocked_audit_alert_group_escalation: - with patch( - "apps.alerts.tasks.check_escalation_finished.send_alert_group_escalation_auditor_task_heartbeat" - ) as mocked_send_alert_group_escalation_auditor_task_heartbeat: - mocked_get_auditable_alert_groups_started_at_range.return_value = (two_days_ago, two_days_in_future) - mocked_audit_alert_group_escalation.side_effect = _mocked_audit_alert_group_escalation + mocked_audit_alert_group_escalation.side_effect = _mocked_audit_alert_group_escalation - with pytest.raises(AlertGroupEscalationPolicyExecutionAuditException) as exc: - check_escalation_finished_task() + with pytest.raises(AlertGroupEscalationPolicyExecutionAuditException) as exc: + check_escalation_finished_task() - assert ( - str(exc.value) - == f"The following alert group id(s) failed auditing: {alert_group1.id}, {alert_group2.id}" - ) + assert str(exc.value) == f"The following alert group id(s) failed auditing: {alert_group1.id}, {alert_group2.id}" - mocked_audit_alert_group_escalation.assert_any_call(alert_group1) - mocked_audit_alert_group_escalation.assert_any_call(alert_group2) - mocked_audit_alert_group_escalation.assert_any_call(alert_group3) + mocked_audit_alert_group_escalation.assert_any_call(alert_group1) + mocked_audit_alert_group_escalation.assert_any_call(alert_group2) + mocked_audit_alert_group_escalation.assert_any_call(alert_group3) - mocked_send_alert_group_escalation_auditor_task_heartbeat.assert_not_called() + mocked_send_alert_group_escalation_auditor_task_heartbeat.assert_not_called() diff --git a/engine/settings/base.py b/engine/settings/base.py index 5b793d27..0664ce0f 100644 --- a/engine/settings/base.py +++ b/engine/settings/base.py @@ -408,6 +408,7 @@ CELERY_MAX_TASKS_PER_CHILD = 1 CELERY_WORKER_SEND_TASK_EVENTS = True CELERY_TASK_SEND_SENT_EVENT = True +ESCALATION_AUDITOR_ENABLED = getenv_boolean("ESCALATION_AUDITOR_ENABLED", default=True) ALERT_GROUP_ESCALATION_AUDITOR_CELERY_TASK_HEARTBEAT_URL = os.getenv( "ALERT_GROUP_ESCALATION_AUDITOR_CELERY_TASK_HEARTBEAT_URL", None ) @@ -418,15 +419,6 @@ CELERY_BEAT_SCHEDULE = { "schedule": 10 * 60, "args": (), }, - "check_escalations": { - "task": "apps.alerts.tasks.check_escalation_finished.check_escalation_finished_task", - # the task should be executed a minute or two less than the integration's configured interval - # - # ex. if the integration is configured to expect a heartbeat every 15 minutes then this value should be set - # to something like 13 * 60 (every 13 minutes) - "schedule": getenv_integer("ALERT_GROUP_ESCALATION_AUDITOR_CELERY_TASK_HEARTBEAT_INTERVAL", 13 * 60), - "args": (), - }, "start_refresh_ical_final_schedules": { "task": "apps.schedules.tasks.refresh_ical_files.start_refresh_ical_final_schedules", "schedule": crontab(minute=15, hour=0), @@ -498,6 +490,17 @@ CELERY_BEAT_SCHEDULE = { }, } +if ESCALATION_AUDITOR_ENABLED: + CELERY_BEAT_SCHEDULE["check_escalations"] = { + "task": "apps.alerts.tasks.check_escalation_finished.check_escalation_finished_task", + # the task should be executed a minute or two less than the integration's configured interval + # + # ex. if the integration is configured to expect a heartbeat every 15 minutes then this value should be set + # to something like 13 * 60 (every 13 minutes) + "schedule": getenv_integer("ALERT_GROUP_ESCALATION_AUDITOR_CELERY_TASK_HEARTBEAT_INTERVAL", 13 * 60), + "args": (), + } + INTERNAL_IPS = ["127.0.0.1"] SELF_IP = os.environ.get("SELF_IP") From 0d8965e355043b80990bb1c301df840b24b3059d Mon Sep 17 00:00:00 2001 From: Joey Orlando Date: Thu, 13 Jul 2023 11:30:34 +0200 Subject: [PATCH 10/11] update changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 685fa9a7..bc55cbd1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## Unreleased +## v1.3.10 (2023-07-13) ### Added From dea1e3b780d9578ec357e7384d09683a498b30cc Mon Sep 17 00:00:00 2001 From: Joey Orlando Date: Thu, 13 Jul 2023 11:30:50 +0200 Subject: [PATCH 11/11] update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bc55cbd1..b945cff8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + ## v1.3.10 (2023-07-13) ### Added