From 1b3421e09e45aa48c2b40bcf45f5d69b847873ab Mon Sep 17 00:00:00 2001 From: Eric Duong Date: Fri, 15 Nov 2024 12:43:16 -0500 Subject: [PATCH 01/11] chore(data-warehouse): refactor logic (#26128) Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com> --- frontend/src/lib/monaco/codeEditorLogic.tsx | 4 +- .../data-warehouse/editor/QueryWindow.tsx | 157 ++------- .../data-warehouse/editor/ResultPane.tsx | 22 +- .../editor/multitabEditorLogic.tsx | 332 ++++++++++++++++++ 4 files changed, 378 insertions(+), 137 deletions(-) create mode 100644 frontend/src/scenes/data-warehouse/editor/multitabEditorLogic.tsx diff --git a/frontend/src/lib/monaco/codeEditorLogic.tsx b/frontend/src/lib/monaco/codeEditorLogic.tsx index 54000263dfb..05506028c1c 100644 --- a/frontend/src/lib/monaco/codeEditorLogic.tsx +++ b/frontend/src/lib/monaco/codeEditorLogic.tsx @@ -245,9 +245,7 @@ export const codeEditorLogic = kea([ } if (props.monaco) { - const defaultQuery = values.featureFlags[FEATURE_FLAGS.SQL_EDITOR] - ? '' - : 'SELECT event FROM events LIMIT 100' + const defaultQuery = 'SELECT event FROM events LIMIT 100' const uri = props.monaco.Uri.parse(currentModelCount.toString()) const model = props.monaco.editor.createModel(defaultQuery, props.language, uri) props.editor?.setModel(model) diff --git a/frontend/src/scenes/data-warehouse/editor/QueryWindow.tsx b/frontend/src/scenes/data-warehouse/editor/QueryWindow.tsx index 1fd177989be..c0dac586cce 100644 --- a/frontend/src/scenes/data-warehouse/editor/QueryWindow.tsx +++ b/frontend/src/scenes/data-warehouse/editor/QueryWindow.tsx @@ -1,19 +1,10 @@ import { Monaco } from '@monaco-editor/react' -import { BindLogic, useActions, useValues } from 'kea' +import { useActions, useValues } from 'kea' import { router } from 'kea-router' -import { - activemodelStateKey, - codeEditorLogic, - CodeEditorLogicProps, - editorModelsStateKey, -} from 'lib/monaco/codeEditorLogic' -import type { editor as importedEditor, Uri } from 'monaco-editor' -import { useCallback, useEffect, useState } from 'react' - -import { dataNodeLogic } from '~/queries/nodes/DataNode/dataNodeLogic' -import { hogQLQueryEditorLogic } from '~/queries/nodes/HogQLQuery/hogQLQueryEditorLogic' -import { HogQLQuery, NodeKind } from '~/queries/schema' +import type { editor as importedEditor } from 'monaco-editor' +import { useState } from 'react' +import { multitabEditorLogic } from './multitabEditorLogic' import { QueryPane } from './QueryPane' import { QueryTabs } from './QueryTabs' import { ResultPane } from './ResultPane' @@ -24,152 +15,54 @@ export function QueryWindow(): JSX.Element { ) const [monaco, editor] = monacoAndEditor ?? [] - const key = router.values.location.pathname - - const [query, setActiveQueryInput] = useState({ - kind: NodeKind.HogQLQuery, - query: '', - }) - - const hogQLQueryEditorLogicProps = { - query, - setQuery: (query: HogQLQuery) => { - setActiveQueryInput(query) - }, - onChange: () => {}, - key, - } - const logic = hogQLQueryEditorLogic(hogQLQueryEditorLogicProps) - const { queryInput, promptError } = useValues(logic) - const { setQueryInput, saveQuery, saveAsView } = useActions(logic) - const codeEditorKey = `hogQLQueryEditor/${router.values.location.pathname}` - const codeEditorLogicProps: CodeEditorLogicProps = { + const logic = multitabEditorLogic({ key: codeEditorKey, - sourceQuery: query, - query: queryInput, - language: 'hogQL', - metadataFilters: query.filters, monaco, editor, - multitab: true, - } - const { activeModelUri, allModels, hasErrors, error, isValidView } = useValues( - codeEditorLogic(codeEditorLogicProps) - ) - - const { createModel, setModel, deleteModel, setModels, addModel, updateState } = useActions( - codeEditorLogic(codeEditorLogicProps) - ) - - const modelKey = `hogQLQueryEditor/${activeModelUri?.path}` - - useEffect(() => { - if (monaco && activeModelUri) { - const _model = monaco.editor.getModel(activeModelUri) - const val = _model?.getValue() - setQueryInput(val ?? '') - saveQuery() - } - }, [activeModelUri]) - - const onAdd = useCallback(() => { - createModel() - }, [createModel]) + }) + const { allTabs, activeModelUri, queryInput, activeQuery, activeTabKey, hasErrors, error, isValidView } = + useValues(logic) + const { selectTab, deleteTab, createTab, setQueryInput, runQuery, saveAsView } = useActions(logic) return (
{ setQueryInput(v ?? '') - updateState() }, onMount: (editor, monaco) => { setMonacoAndEditor([monaco, editor]) - - const allModelQueries = localStorage.getItem(editorModelsStateKey(codeEditorKey)) - const activeModelUri = localStorage.getItem(activemodelStateKey(codeEditorKey)) - - if (allModelQueries) { - // clear existing models - monaco.editor.getModels().forEach((model) => { - model.dispose() - }) - - const models = JSON.parse(allModelQueries || '[]') - const newModels: Uri[] = [] - - models.forEach((model: Record) => { - if (monaco) { - const uri = monaco.Uri.parse(model.path) - const newModel = monaco.editor.createModel(model.query, 'hogQL', uri) - editor?.setModel(newModel) - newModels.push(uri) - } - }) - - setModels(newModels) - - if (activeModelUri) { - const uri = monaco.Uri.parse(activeModelUri) - const activeModel = monaco.editor - .getModels() - .find((model) => model.uri.path === uri.path) - activeModel && editor?.setModel(activeModel) - const val = activeModel?.getValue() - if (val) { - setQueryInput(val) - saveQuery() - } - setModel(uri) - } else if (newModels.length) { - setModel(newModels[0]) - } - } else { - const model = editor.getModel() - - if (model) { - addModel(model.uri) - setModel(model.uri) - } - } }, onPressCmdEnter: (value, selectionType) => { if (value && selectionType === 'selection') { - saveQuery(value) + runQuery(value) } else { - saveQuery() + runQuery() } }, }} /> - - - +
) } diff --git a/frontend/src/scenes/data-warehouse/editor/ResultPane.tsx b/frontend/src/scenes/data-warehouse/editor/ResultPane.tsx index 215a116d07a..40dfee342d2 100644 --- a/frontend/src/scenes/data-warehouse/editor/ResultPane.tsx +++ b/frontend/src/scenes/data-warehouse/editor/ResultPane.tsx @@ -7,6 +7,7 @@ import DataGrid from 'react-data-grid' import { themeLogic } from '~/layout/navigation-3000/themeLogic' import { dataNodeLogic } from '~/queries/nodes/DataNode/dataNodeLogic' +import { NodeKind } from '~/queries/schema' enum ResultsTab { Results = 'results', @@ -17,11 +18,28 @@ interface ResultPaneProps { onSave: () => void saveDisabledReason?: string onQueryInputChange: () => void + logicKey: string + query: string } -export function ResultPane({ onQueryInputChange, onSave, saveDisabledReason }: ResultPaneProps): JSX.Element { +export function ResultPane({ + onQueryInputChange, + onSave, + saveDisabledReason, + logicKey, + query, +}: ResultPaneProps): JSX.Element { const { isDarkModeOn } = useValues(themeLogic) - const { response, responseLoading } = useValues(dataNodeLogic) + const { response, responseLoading } = useValues( + dataNodeLogic({ + key: logicKey, + query: { + kind: NodeKind.HogQLQuery, + query, + }, + doNotLoad: !query, + }) + ) const columns = useMemo(() => { return ( diff --git a/frontend/src/scenes/data-warehouse/editor/multitabEditorLogic.tsx b/frontend/src/scenes/data-warehouse/editor/multitabEditorLogic.tsx new file mode 100644 index 00000000000..7a4a3d4e84e --- /dev/null +++ b/frontend/src/scenes/data-warehouse/editor/multitabEditorLogic.tsx @@ -0,0 +1,332 @@ +import { Monaco } from '@monaco-editor/react' +import { LemonDialog, LemonInput } from '@posthog/lemon-ui' +import { actions, kea, listeners, path, props, propsChanged, reducers, selectors } from 'kea' +import { subscriptions } from 'kea-subscriptions' +import { LemonField } from 'lib/lemon-ui/LemonField' +import { ModelMarker } from 'lib/monaco/codeEditorLogic' +import { editor, MarkerSeverity, Uri } from 'monaco-editor' + +import { dataNodeLogic } from '~/queries/nodes/DataNode/dataNodeLogic' +import { performQuery } from '~/queries/query' +import { HogLanguage, HogQLMetadata, HogQLMetadataResponse, HogQLNotice, HogQLQuery, NodeKind } from '~/queries/schema' + +import { dataWarehouseViewsLogic } from '../saved_queries/dataWarehouseViewsLogic' +import type { multitabEditorLogicType } from './multitabEditorLogicType' + +export interface MultitabEditorLogicProps { + key: string + monaco?: Monaco | null + editor?: editor.IStandaloneCodeEditor | null +} + +export const editorModelsStateKey = (key: string | number): string => `${key}/editorModelQueries` +export const activemodelStateKey = (key: string | number): string => `${key}/activeModelUri` + +export const multitabEditorLogic = kea([ + path(['data-warehouse', 'editor', 'multitabEditorLogic']), + props({} as MultitabEditorLogicProps), + actions({ + setQueryInput: (queryInput: string) => ({ queryInput }), + updateState: true, + runQuery: (queryOverride?: string) => ({ queryOverride }), + setActiveQuery: (query: string) => ({ query }), + setTabs: (tabs: Uri[]) => ({ tabs }), + addTab: (tab: Uri) => ({ tab }), + createTab: () => null, + deleteTab: (tab: Uri) => ({ tab }), + removeTab: (tab: Uri) => ({ tab }), + selectTab: (tab: Uri) => ({ tab }), + setLocalState: (key: string, value: any) => ({ key, value }), + initialize: true, + saveAsView: true, + saveAsViewSuccess: (name: string) => ({ name }), + reloadMetadata: true, + setMetadata: (query: string, metadata: HogQLMetadataResponse) => ({ query, metadata }), + }), + propsChanged(({ actions }, oldProps) => { + if (!oldProps.monaco && !oldProps.editor) { + actions.initialize() + } + }), + reducers(({ props }) => ({ + queryInput: [ + '', + { + setQueryInput: (_, { queryInput }) => queryInput, + }, + ], + activeQuery: [ + null as string | null, + { + setActiveQuery: (_, { query }) => query, + }, + ], + activeModelUri: [ + null as Uri | null, + { + selectTab: (_, { tab }) => tab, + }, + ], + allTabs: [ + [] as Uri[], + { + addTab: (state, { tab }) => { + const newTabs = [...state, tab] + return newTabs + }, + removeTab: (state, { tab: tabToRemove }) => { + const newModels = state.filter((tab) => tab.toString() !== tabToRemove.toString()) + return newModels + }, + setTabs: (_, { tabs }) => tabs, + }, + ], + metadata: [ + null as null | [string, HogQLMetadataResponse], + { + setMetadata: (_, { query, metadata }) => [query, metadata], + }, + ], + modelMarkers: [ + [] as ModelMarker[], + { + setMetadata: (_, { query, metadata }) => { + const model = props.editor?.getModel() + if (!model || !metadata) { + return [] + } + const markers: ModelMarker[] = [] + const metadataResponse = metadata + + function noticeToMarker(error: HogQLNotice, severity: MarkerSeverity): ModelMarker { + const start = model!.getPositionAt(error.start ?? 0) + const end = model!.getPositionAt(error.end ?? query.length) + return { + start: error.start ?? 0, + startLineNumber: start.lineNumber, + startColumn: start.column, + end: error.end ?? query.length, + endLineNumber: end.lineNumber, + endColumn: end.column, + message: error.message ?? 'Unknown error', + severity: severity, + hogQLFix: error.fix, + } + } + + for (const notice of metadataResponse?.errors ?? []) { + markers.push(noticeToMarker(notice, 8 /* MarkerSeverity.Error */)) + } + for (const notice of metadataResponse?.warnings ?? []) { + markers.push(noticeToMarker(notice, 4 /* MarkerSeverity.Warning */)) + } + for (const notice of metadataResponse?.notices ?? []) { + markers.push(noticeToMarker(notice, 1 /* MarkerSeverity.Hint */)) + } + + props.monaco?.editor.setModelMarkers(model, 'hogql', markers) + return markers + }, + }, + ], + })), + listeners(({ values, props, actions }) => ({ + createTab: () => { + let currentModelCount = 1 + const allNumbers = values.allTabs.map((tab) => parseInt(tab.path.split('/').pop() || '0')) + while (allNumbers.includes(currentModelCount)) { + currentModelCount++ + } + + if (props.monaco) { + const uri = props.monaco.Uri.parse(currentModelCount.toString()) + const model = props.monaco.editor.createModel('', 'hogQL', uri) + props.editor?.setModel(model) + actions.addTab(uri) + actions.selectTab(uri) + + const queries = values.allTabs.map((tab) => { + return { + query: props.monaco?.editor.getModel(tab)?.getValue() || '', + path: tab.path.split('/').pop(), + } + }) + actions.setLocalState(editorModelsStateKey(props.key), JSON.stringify(queries)) + } + }, + selectTab: ({ tab }) => { + if (props.monaco) { + const model = props.monaco.editor.getModel(tab) + props.editor?.setModel(model) + } + + const path = tab.path.split('/').pop() + path && actions.setLocalState(activemodelStateKey(props.key), path) + }, + deleteTab: ({ tab: tabToRemove }) => { + if (props.monaco) { + const model = props.monaco.editor.getModel(tabToRemove) + if (tabToRemove == values.activeModelUri) { + const indexOfModel = values.allTabs.findIndex((tab) => tab.toString() === tabToRemove.toString()) + const nextModel = + values.allTabs[indexOfModel + 1] || values.allTabs[indexOfModel - 1] || values.allTabs[0] // there will always be one + actions.selectTab(nextModel) + } + model?.dispose() + actions.removeTab(tabToRemove) + const queries = values.allTabs.map((tab) => { + return { + query: props.monaco?.editor.getModel(tab)?.getValue() || '', + path: tab.path.split('/').pop(), + } + }) + actions.setLocalState(editorModelsStateKey(props.key), JSON.stringify(queries)) + } + }, + setLocalState: ({ key, value }) => { + localStorage.setItem(key, value) + }, + initialize: () => { + const allModelQueries = localStorage.getItem(editorModelsStateKey(props.key)) + const activeModelUri = localStorage.getItem(activemodelStateKey(props.key)) + + if (allModelQueries) { + // clear existing models + props.monaco?.editor.getModels().forEach((model: editor.ITextModel) => { + model.dispose() + }) + + const models = JSON.parse(allModelQueries || '[]') + const newModels: Uri[] = [] + + models.forEach((model: Record) => { + if (props.monaco) { + const uri = props.monaco.Uri.parse(model.path) + const newModel = props.monaco.editor.createModel(model.query, 'hogQL', uri) + props.editor?.setModel(newModel) + newModels.push(uri) + } + }) + + actions.setTabs(newModels) + + if (activeModelUri) { + const uri = props.monaco?.Uri.parse(activeModelUri) + const activeModel = props.monaco?.editor + .getModels() + .find((model: editor.ITextModel) => model.uri.path === uri?.path) + activeModel && props.editor?.setModel(activeModel) + const val = activeModel?.getValue() + if (val) { + actions.setQueryInput(val) + actions.runQuery() + } + uri && actions.selectTab(uri) + } else if (newModels.length) { + actions.selectTab(newModels[0]) + } + } else { + const model = props.editor?.getModel() + + if (model) { + actions.createTab() + } + } + }, + setQueryInput: () => { + actions.updateState() + }, + updateState: async (_, breakpoint) => { + await breakpoint(100) + const queries = values.allTabs.map((model) => { + return { + query: props.monaco?.editor.getModel(model)?.getValue() || '', + path: model.path.split('/').pop(), + } + }) + localStorage.setItem(editorModelsStateKey(props.key), JSON.stringify(queries)) + }, + runQuery: ({ queryOverride }) => { + actions.setActiveQuery(queryOverride || values.queryInput) + }, + saveAsView: async () => { + LemonDialog.openForm({ + title: 'Save as view', + initialValues: { viewName: '' }, + content: ( + + + + ), + errors: { + viewName: (name) => (!name ? 'You must enter a name' : undefined), + }, + onSubmit: ({ viewName }) => actions.saveAsViewSuccess(viewName), + }) + }, + saveAsViewSuccess: async ({ name }) => { + const query: HogQLQuery = { + kind: NodeKind.HogQLQuery, + query: values.queryInput, + } + await dataWarehouseViewsLogic.asyncActions.createDataWarehouseSavedQuery({ name, query }) + }, + reloadMetadata: async (_, breakpoint) => { + const model = props.editor?.getModel() + if (!model || !props.monaco) { + return + } + await breakpoint(300) + const query = values.queryInput + if (query === '') { + return + } + + const response = await performQuery({ + kind: NodeKind.HogQLMetadata, + language: HogLanguage.hogQL, + query: query, + }) + breakpoint() + actions.setMetadata(query, response) + }, + })), + subscriptions(({ props, actions, values }) => ({ + activeModelUri: (activeModelUri) => { + if (props.monaco) { + const _model = props.monaco.editor.getModel(activeModelUri) + const val = _model?.getValue() + actions.setQueryInput(val ?? '') + actions.runQuery() + dataNodeLogic({ + key: values.activeTabKey, + query: { + kind: NodeKind.HogQLQuery, + query: val ?? '', + }, + doNotLoad: !val, + }).mount() + } + }, + queryInput: () => { + actions.reloadMetadata() + }, + })), + selectors({ + activeTabKey: [(s) => [s.activeModelUri], (activeModelUri) => `hogQLQueryEditor/${activeModelUri?.path}`], + isValidView: [(s) => [s.metadata], (metadata) => !!(metadata && metadata[1]?.isValidView)], + hasErrors: [ + (s) => [s.modelMarkers], + (modelMarkers) => !!(modelMarkers ?? []).filter((e) => e.severity === 8 /* MarkerSeverity.Error */).length, + ], + error: [ + (s) => [s.hasErrors, s.modelMarkers], + (hasErrors, modelMarkers) => { + const firstError = modelMarkers.find((e) => e.severity === 8 /* MarkerSeverity.Error */) + return hasErrors && firstError + ? `Error on line ${firstError.startLineNumber}, column ${firstError.startColumn}` + : null + }, + ], + }), +]) From fb4c5b6d863482325c156ad0f67a04e30cca17a9 Mon Sep 17 00:00:00 2001 From: Phani Raj Date: Fri, 15 Nov 2024 12:38:08 -0600 Subject: [PATCH 02/11] fix(Surveys): Allow more than 6 single choice options if the survey is not of type Popover (#26224) Enforce the 6 choices limit only if Survey is of type PopOver --- frontend/src/scenes/surveys/SurveyEditQuestionRow.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/scenes/surveys/SurveyEditQuestionRow.tsx b/frontend/src/scenes/surveys/SurveyEditQuestionRow.tsx index 41e5805fc05..237aaa78597 100644 --- a/frontend/src/scenes/surveys/SurveyEditQuestionRow.tsx +++ b/frontend/src/scenes/surveys/SurveyEditQuestionRow.tsx @@ -10,7 +10,7 @@ import { Group } from 'kea-forms' import { SortableDragIcon } from 'lib/lemon-ui/icons' import { LemonField } from 'lib/lemon-ui/LemonField' -import { Survey, SurveyQuestionType } from '~/types' +import { Survey, SurveyQuestionType, SurveyType } from '~/types' import { defaultSurveyFieldValues, NewSurvey, SurveyQuestionLabel } from './constants' import { QuestionBranchingInput } from './QuestionBranchingInput' @@ -315,7 +315,7 @@ export function SurveyEditQuestionGroup({ index, question }: { index: number; qu ) })}
- {(value || []).length < 6 && ( + {((value || []).length < 6 || survey.type != SurveyType.Popover) && ( <> } From 2b2e7e48b140fd7f2e831a51c144b02f3c5187c8 Mon Sep 17 00:00:00 2001 From: Surbhi Date: Fri, 15 Nov 2024 14:44:21 -0400 Subject: [PATCH 03/11] feat: making role in organization as a required field (#26205) Co-authored-by: Your Name (aider) --- cypress/e2e/signup.cy.ts | 9 +++++++++ frontend/src/lib/components/SignupRoleSelect.tsx | 2 +- .../authentication/signup/signupForm/signupLogic.ts | 3 ++- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/cypress/e2e/signup.cy.ts b/cypress/e2e/signup.cy.ts index bb1a4cf0468..9774236ef81 100644 --- a/cypress/e2e/signup.cy.ts +++ b/cypress/e2e/signup.cy.ts @@ -77,6 +77,9 @@ describe('Signup', () => { cy.get('[data-attr=password]').type(VALID_PASSWORD).should('have.value', VALID_PASSWORD) cy.get('[data-attr=signup-start]').click() cy.get('[data-attr=signup-name]').type('Alice Bob').should('have.value', 'Alice Bob') + cy.get('[data-attr=signup-role-at-organization]').click() + cy.get('.Popover li:first-child').click() + cy.get('[data-attr=signup-role-at-organization]').contains('Engineering') cy.get('[data-attr=signup-submit]').click() cy.wait('@signupRequest').then((interception) => { @@ -93,6 +96,9 @@ describe('Signup', () => { cy.get('[data-attr=password]').type(VALID_PASSWORD).should('have.value', VALID_PASSWORD) cy.get('[data-attr=signup-start]').click() cy.get('[data-attr=signup-name]').type('Alice Bob').should('have.value', 'Alice Bob') + cy.get('[data-attr=signup-role-at-organization]').click() + cy.get('.Popover li:first-child').click() + cy.get('[data-attr=signup-role-at-organization]').contains('Engineering') cy.get('[data-attr=signup-submit]').click() cy.wait('@signupRequest').then(() => { @@ -105,6 +111,9 @@ describe('Signup', () => { const newEmail = `new_user+${Math.floor(Math.random() * 10000)}@posthog.com` cy.get('[data-attr=signup-email]').clear().type(newEmail).should('have.value', newEmail) cy.get('[data-attr=signup-start]').click() + cy.get('[data-attr=signup-role-at-organization]').click() + cy.get('.Popover li:first-child').click() + cy.get('[data-attr=signup-role-at-organization]').contains('Engineering') cy.get('[data-attr=signup-submit]').click() cy.wait('@signupRequest').then((interception) => { diff --git a/frontend/src/lib/components/SignupRoleSelect.tsx b/frontend/src/lib/components/SignupRoleSelect.tsx index f99d00f1f47..0272145cbcc 100644 --- a/frontend/src/lib/components/SignupRoleSelect.tsx +++ b/frontend/src/lib/components/SignupRoleSelect.tsx @@ -3,7 +3,7 @@ import { LemonSelect } from 'lib/lemon-ui/LemonSelect' export default function SignupRoleSelect({ className }: { className?: string }): JSX.Element { return ( - + ([ role_at_organization: '', referral_source: '', } as SignupForm, - errors: ({ name }) => ({ + errors: ({ name, role_at_organization }) => ({ name: !name ? 'Please enter your name' : undefined, + role_at_organization: !role_at_organization ? 'Please select your role in the organization' : undefined, }), submit: async (payload, breakpoint) => { breakpoint() From 39659d71039c393b69b8f15f0c11ba545b8e3f53 Mon Sep 17 00:00:00 2001 From: Hamir Mahal Date: Fri, 15 Nov 2024 10:48:11 -0800 Subject: [PATCH 04/11] refactor: remove redundant references (#25571) Co-authored-by: Sandy Spicer --- funnel-udf/src/steps.rs | 8 ++++---- funnel-udf/src/trends.rs | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/funnel-udf/src/steps.rs b/funnel-udf/src/steps.rs index 9330caf4e1c..21d6fb84e62 100644 --- a/funnel-udf/src/steps.rs +++ b/funnel-udf/src/steps.rs @@ -55,7 +55,7 @@ const DEFAULT_ENTERED_TIMESTAMP: EnteredTimestamp = EnteredTimestamp { }; pub fn process_line(line: &str) -> Value { - let args = parse_args(&line); + let args = parse_args(line); let mut aggregate_funnel_row = AggregateFunnelRow { results: Vec::with_capacity(args.prop_vals.len()), breakdown_step: Option::None, @@ -112,7 +112,7 @@ impl AggregateFunnelRow { self.process_event( args, &mut vars, - &events_with_same_timestamp[0], + events_with_same_timestamp[0], prop_val, false ); @@ -147,7 +147,7 @@ impl AggregateFunnelRow { args, &mut vars, &event, - &prop_val, + prop_val, true ); } @@ -261,4 +261,4 @@ impl AggregateFunnelRow { } } } -} \ No newline at end of file +} diff --git a/funnel-udf/src/trends.rs b/funnel-udf/src/trends.rs index fa7dc162c12..42356dc06d1 100644 --- a/funnel-udf/src/trends.rs +++ b/funnel-udf/src/trends.rs @@ -81,7 +81,7 @@ const DEFAULT_ENTERED_TIMESTAMP: EnteredTimestamp = EnteredTimestamp { }; pub fn process_line(line: &str) -> Value { - let args = parse_args(&line); + let args = parse_args(line); let mut aggregate_funnel_row = AggregateFunnelRow { results: HashMap::new(), breakdown_step: Option::None, @@ -128,7 +128,7 @@ impl AggregateFunnelRow { self.process_event( args, &mut vars, - &event, + event, prop_val, ); } @@ -242,4 +242,4 @@ impl AggregateFunnelRow { } } } -} \ No newline at end of file +} From 27c62f31bbc648ab36b9351fac51ac83701b8e29 Mon Sep 17 00:00:00 2001 From: Raquel Smith Date: Fri, 15 Nov 2024 13:10:58 -0800 Subject: [PATCH 05/11] fix: only let someone use the dashboard templates if they've ingested events (#26226) --- frontend/src/scenes/onboarding/Onboarding.tsx | 7 ++++++- .../DashboardTemplateConfigureStep.tsx | 4 ++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/frontend/src/scenes/onboarding/Onboarding.tsx b/frontend/src/scenes/onboarding/Onboarding.tsx index 522e28c569a..a4106a69173 100644 --- a/frontend/src/scenes/onboarding/Onboarding.tsx +++ b/frontend/src/scenes/onboarding/Onboarding.tsx @@ -26,6 +26,7 @@ import { ExperimentsSDKInstructions } from './sdks/experiments/ExperimentsSDKIns import { FeatureFlagsSDKInstructions } from './sdks/feature-flags/FeatureFlagsSDKInstructions' import { ProductAnalyticsSDKInstructions } from './sdks/product-analytics/ProductAnalyticsSDKInstructions' import { SDKs } from './sdks/SDKs' +import { sdksLogic } from './sdks/sdksLogic' import { SessionReplaySDKInstructions } from './sdks/session-replay/SessionReplaySDKInstructions' import { SurveysSDKInstructions } from './sdks/surveys/SurveysSDKInstructions' @@ -105,12 +106,16 @@ const OnboardingWrapper = ({ children }: { children: React.ReactNode }): JSX.Ele const ProductAnalyticsOnboarding = (): JSX.Element => { const { currentTeam } = useValues(teamLogic) const { featureFlags } = useValues(featureFlagLogic) + const { combinedSnippetAndLiveEventsHosts } = useValues(sdksLogic) + // mount the logic here so that it stays mounted for the entire onboarding flow // not sure if there is a better way to do this useValues(newDashboardLogic) const showTemplateSteps = - featureFlags[FEATURE_FLAGS.ONBOARDING_DASHBOARD_TEMPLATES] == 'test' && window.innerWidth > 1000 + featureFlags[FEATURE_FLAGS.ONBOARDING_DASHBOARD_TEMPLATES] == 'test' && + window.innerWidth > 1000 && + combinedSnippetAndLiveEventsHosts.length > 0 const options: ProductConfigOption[] = [ { diff --git a/frontend/src/scenes/onboarding/productAnalyticsSteps/DashboardTemplateConfigureStep.tsx b/frontend/src/scenes/onboarding/productAnalyticsSteps/DashboardTemplateConfigureStep.tsx index c2740d598ca..9d30f984a4c 100644 --- a/frontend/src/scenes/onboarding/productAnalyticsSteps/DashboardTemplateConfigureStep.tsx +++ b/frontend/src/scenes/onboarding/productAnalyticsSteps/DashboardTemplateConfigureStep.tsx @@ -52,8 +52,8 @@ const UrlInput = ({ iframeRef }: { iframeRef: React.RefObject return (
setInputValue(v)} From cf7aaf66a82399694b8b15f5a518af98668bf8e6 Mon Sep 17 00:00:00 2001 From: Surbhi Date: Fri, 15 Nov 2024 17:22:36 -0400 Subject: [PATCH 06/11] fix: password validation correction (#26227) --- .../src/scenes/authentication/signup/signupForm/signupLogic.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/scenes/authentication/signup/signupForm/signupLogic.ts b/frontend/src/scenes/authentication/signup/signupForm/signupLogic.ts index 1b458e909e0..d1257595c38 100644 --- a/frontend/src/scenes/authentication/signup/signupForm/signupLogic.ts +++ b/frontend/src/scenes/authentication/signup/signupForm/signupLogic.ts @@ -67,7 +67,7 @@ export const signupLogic = kea([ password: !values.preflight?.demo ? !password ? 'Please enter your password to continue' - : values.validatedPassword.feedback + : values.validatedPassword.feedback || undefined : undefined, }), submit: async () => { From 4ce7e9c7814f5b61961cfae8b985846fd4105bf8 Mon Sep 17 00:00:00 2001 From: Dylan Martin Date: Sat, 16 Nov 2024 00:44:55 +0100 Subject: [PATCH 07/11] feat(flags): dynamic cohort matching in rust (#25776) --- rust/Cargo.lock | 6 + rust/feature-flags/Cargo.toml | 2 + rust/feature-flags/src/api.rs | 24 +- rust/feature-flags/src/cohort_cache.rs | 221 +++++ rust/feature-flags/src/cohort_models.rs | 50 + rust/feature-flags/src/cohort_operations.rs | 369 ++++++++ rust/feature-flags/src/flag_definitions.rs | 38 +- rust/feature-flags/src/flag_matching.rs | 880 ++++++++++++++++-- rust/feature-flags/src/flag_request.rs | 21 +- rust/feature-flags/src/lib.rs | 5 +- .../src/{utils.rs => metrics_utils.rs} | 0 rust/feature-flags/src/property_matching.rs | 43 +- rust/feature-flags/src/request_handler.rs | 24 +- rust/feature-flags/src/router.rs | 6 +- rust/feature-flags/src/server.rs | 4 + rust/feature-flags/src/team.rs | 6 +- rust/feature-flags/src/test_utils.rs | 74 +- .../tests/test_flag_matching_consistency.rs | 9 +- 18 files changed, 1671 insertions(+), 111 deletions(-) create mode 100644 rust/feature-flags/src/cohort_cache.rs create mode 100644 rust/feature-flags/src/cohort_models.rs create mode 100644 rust/feature-flags/src/cohort_operations.rs rename rust/feature-flags/src/{utils.rs => metrics_utils.rs} (100%) diff --git a/rust/Cargo.lock b/rust/Cargo.lock index b99943cc4e5..9a263a87878 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -1808,7 +1808,9 @@ dependencies = [ "futures", "health", "maxminddb", + "moka", "once_cell", + "petgraph", "rand", "redis", "regex", @@ -3046,9 +3048,13 @@ version = "0.12.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32cf62eb4dd975d2dde76432fb1075c49e3ee2331cf36f1f8fd4b66550d32b6f" dependencies = [ + "async-lock 3.4.0", + "async-trait", "crossbeam-channel", "crossbeam-epoch", "crossbeam-utils", + "event-listener 5.3.1", + "futures-util", "once_cell", "parking_lot", "quanta 0.12.2", diff --git a/rust/feature-flags/Cargo.toml b/rust/feature-flags/Cargo.toml index 4cf4016767b..4099fd8ab06 100644 --- a/rust/feature-flags/Cargo.toml +++ b/rust/feature-flags/Cargo.toml @@ -39,6 +39,8 @@ health = { path = "../common/health" } common-metrics = { path = "../common/metrics" } tower = { workspace = true } derive_builder = "0.20.1" +petgraph = "0.6.5" +moka = { version = "0.12.8", features = ["future"] } [lints] workspace = true diff --git a/rust/feature-flags/src/api.rs b/rust/feature-flags/src/api.rs index 4430476d28a..9d6b649719b 100644 --- a/rust/feature-flags/src/api.rs +++ b/rust/feature-flags/src/api.rs @@ -89,7 +89,7 @@ pub enum FlagError { #[error("Row not found in postgres")] RowNotFound, #[error("failed to parse redis cache data")] - DataParsingError, + RedisDataParsingError, #[error("failed to update redis cache")] CacheUpdateError, #[error("redis unavailable")] @@ -102,6 +102,12 @@ pub enum FlagError { TimeoutError, #[error("No group type mappings")] NoGroupTypeMappings, + #[error("Cohort not found")] + CohortNotFound(String), + #[error("Failed to parse cohort filters")] + CohortFiltersParsingError, + #[error("Cohort dependency cycle")] + CohortDependencyCycle(String), } impl IntoResponse for FlagError { @@ -138,7 +144,7 @@ impl IntoResponse for FlagError { FlagError::TokenValidationError => { (StatusCode::UNAUTHORIZED, "The provided API key is invalid or has expired. Please check your API key and try again.".to_string()) } - FlagError::DataParsingError => { + FlagError::RedisDataParsingError => { tracing::error!("Data parsing error: {:?}", self); ( StatusCode::SERVICE_UNAVAILABLE, @@ -194,6 +200,18 @@ impl IntoResponse for FlagError { "The requested row was not found in the database. Please try again later or contact support if the problem persists.".to_string(), ) } + FlagError::CohortNotFound(msg) => { + tracing::error!("Cohort not found: {}", msg); + (StatusCode::NOT_FOUND, msg) + } + FlagError::CohortFiltersParsingError => { + tracing::error!("Failed to parse cohort filters: {:?}", self); + (StatusCode::BAD_REQUEST, "Failed to parse cohort filters. Please try again later or contact support if the problem persists.".to_string()) + } + FlagError::CohortDependencyCycle(msg) => { + tracing::error!("Cohort dependency cycle: {}", msg); + (StatusCode::BAD_REQUEST, msg) + } } .into_response() } @@ -205,7 +223,7 @@ impl From for FlagError { CustomRedisError::NotFound => FlagError::TokenValidationError, CustomRedisError::PickleError(e) => { tracing::error!("failed to fetch data: {}", e); - FlagError::DataParsingError + FlagError::RedisDataParsingError } CustomRedisError::Timeout(_) => FlagError::TimeoutError, CustomRedisError::Other(e) => { diff --git a/rust/feature-flags/src/cohort_cache.rs b/rust/feature-flags/src/cohort_cache.rs new file mode 100644 index 00000000000..68894c19f88 --- /dev/null +++ b/rust/feature-flags/src/cohort_cache.rs @@ -0,0 +1,221 @@ +use crate::api::FlagError; +use crate::cohort_models::Cohort; +use crate::flag_matching::{PostgresReader, TeamId}; +use moka::future::Cache; +use std::time::Duration; + +/// CohortCacheManager manages the in-memory cache of cohorts using `moka` for caching. +/// +/// Features: +/// - **TTL**: Each cache entry expires after 5 minutes. +/// - **Size-based eviction**: The cache evicts least recently used entries when the maximum capacity is reached. +/// +/// ```text +/// CohortCacheManager { +/// postgres_reader: PostgresReader, +/// per_team_cohorts: Cache> { +/// // Example: +/// 2: [ +/// Cohort { id: 1, name: "Power Users", filters: {...} }, +/// Cohort { id: 2, name: "Churned", filters: {...} } +/// ], +/// 5: [ +/// Cohort { id: 3, name: "Beta Users", filters: {...} } +/// ] +/// } +/// } +/// ``` +/// +#[derive(Clone)] +pub struct CohortCacheManager { + postgres_reader: PostgresReader, + per_team_cohort_cache: Cache>, +} + +impl CohortCacheManager { + pub fn new( + postgres_reader: PostgresReader, + max_capacity: Option, + ttl_seconds: Option, + ) -> Self { + // We use the size of the cohort list (i.e., the number of cohorts for a given team)as the weight of the entry + let weigher = + |_: &TeamId, value: &Vec| -> u32 { value.len().try_into().unwrap_or(u32::MAX) }; + + let cache = Cache::builder() + .time_to_live(Duration::from_secs(ttl_seconds.unwrap_or(300))) // Default to 5 minutes + .weigher(weigher) + .max_capacity(max_capacity.unwrap_or(10_000)) // Default to 10,000 cohorts + .build(); + + Self { + postgres_reader, + per_team_cohort_cache: cache, + } + } + + /// Retrieves cohorts for a given team. + /// + /// If the cohorts are not present in the cache or have expired, it fetches them from the database, + /// caches the result upon successful retrieval, and then returns it. + pub async fn get_cohorts_for_team(&self, team_id: TeamId) -> Result, FlagError> { + if let Some(cached_cohorts) = self.per_team_cohort_cache.get(&team_id).await { + return Ok(cached_cohorts.clone()); + } + let fetched_cohorts = Cohort::list_from_pg(self.postgres_reader.clone(), team_id).await?; + self.per_team_cohort_cache + .insert(team_id, fetched_cohorts.clone()) + .await; + + Ok(fetched_cohorts) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::cohort_models::Cohort; + use crate::test_utils::{ + insert_cohort_for_team_in_pg, insert_new_team_in_pg, setup_pg_reader_client, + setup_pg_writer_client, + }; + use std::sync::Arc; + use tokio::time::{sleep, Duration}; + + /// Helper function to setup a new team for testing. + async fn setup_test_team( + writer_client: Arc, + ) -> Result { + let team = crate::test_utils::insert_new_team_in_pg(writer_client, None).await?; + Ok(team.id) + } + + /// Helper function to insert a cohort for a team. + async fn setup_test_cohort( + writer_client: Arc, + team_id: TeamId, + name: Option, + ) -> Result { + let filters = serde_json::json!({"properties": {"type": "OR", "values": [{"type": "OR", "values": [{"key": "$active", "type": "person", "value": [true], "negation": false, "operator": "exact"}]}]}}); + insert_cohort_for_team_in_pg(writer_client, team_id, name, filters, false).await + } + + /// Tests that cache entries expire after the specified TTL. + #[tokio::test] + async fn test_cache_expiry() -> Result<(), anyhow::Error> { + let writer_client = setup_pg_writer_client(None).await; + let reader_client = setup_pg_reader_client(None).await; + + let team_id = setup_test_team(writer_client.clone()).await?; + let _cohort = setup_test_cohort(writer_client.clone(), team_id, None).await?; + + // Initialize CohortCacheManager with a short TTL for testing + let cohort_cache = CohortCacheManager::new( + reader_client.clone(), + Some(100), + Some(1), // 1-second TTL + ); + + let cohorts = cohort_cache.get_cohorts_for_team(team_id).await?; + assert_eq!(cohorts.len(), 1); + assert_eq!(cohorts[0].team_id, team_id); + + let cached_cohorts = cohort_cache.per_team_cohort_cache.get(&team_id).await; + assert!(cached_cohorts.is_some()); + + // Wait for TTL to expire + sleep(Duration::from_secs(2)).await; + + // Attempt to retrieve from cache again + let cached_cohorts = cohort_cache.per_team_cohort_cache.get(&team_id).await; + assert!(cached_cohorts.is_none(), "Cache entry should have expired"); + + Ok(()) + } + + /// Tests that the cache correctly evicts least recently used entries based on the weigher. + #[tokio::test] + async fn test_cache_weigher() -> Result<(), anyhow::Error> { + let writer_client = setup_pg_writer_client(None).await; + let reader_client = setup_pg_reader_client(None).await; + + // Define a smaller max_capacity for testing + let max_capacity: u64 = 3; + + let cohort_cache = CohortCacheManager::new(reader_client.clone(), Some(max_capacity), None); + + let mut inserted_team_ids = Vec::new(); + + // Insert multiple teams and their cohorts + for _ in 0..max_capacity { + let team = insert_new_team_in_pg(writer_client.clone(), None).await?; + let team_id = team.id; + inserted_team_ids.push(team_id); + setup_test_cohort(writer_client.clone(), team_id, None).await?; + cohort_cache.get_cohorts_for_team(team_id).await?; + } + + cohort_cache.per_team_cohort_cache.run_pending_tasks().await; + let cache_size = cohort_cache.per_team_cohort_cache.entry_count(); + assert_eq!( + cache_size, max_capacity, + "Cache size should be equal to max_capacity" + ); + + let new_team = insert_new_team_in_pg(writer_client.clone(), None).await?; + let new_team_id = new_team.id; + setup_test_cohort(writer_client.clone(), new_team_id, None).await?; + cohort_cache.get_cohorts_for_team(new_team_id).await?; + + cohort_cache.per_team_cohort_cache.run_pending_tasks().await; + let cache_size_after = cohort_cache.per_team_cohort_cache.entry_count(); + assert_eq!( + cache_size_after, max_capacity, + "Cache size should remain equal to max_capacity after eviction" + ); + + let evicted_team_id = &inserted_team_ids[0]; + let cached_cohorts = cohort_cache + .per_team_cohort_cache + .get(evicted_team_id) + .await; + assert!( + cached_cohorts.is_none(), + "Least recently used cache entry should have been evicted" + ); + + let cached_new_team = cohort_cache.per_team_cohort_cache.get(&new_team_id).await; + assert!( + cached_new_team.is_some(), + "Newly added cache entry should be present" + ); + + Ok(()) + } + + #[tokio::test] + async fn test_get_cohorts_for_team() -> Result<(), anyhow::Error> { + let writer_client = setup_pg_writer_client(None).await; + let reader_client = setup_pg_reader_client(None).await; + let team_id = setup_test_team(writer_client.clone()).await?; + let _cohort = setup_test_cohort(writer_client.clone(), team_id, None).await?; + let cohort_cache = CohortCacheManager::new(reader_client.clone(), None, None); + + let cached_cohorts = cohort_cache.per_team_cohort_cache.get(&team_id).await; + assert!(cached_cohorts.is_none(), "Cache should initially be empty"); + + let cohorts = cohort_cache.get_cohorts_for_team(team_id).await?; + assert_eq!(cohorts.len(), 1); + assert_eq!(cohorts[0].team_id, team_id); + + let cached_cohorts = cohort_cache + .per_team_cohort_cache + .get(&team_id) + .await + .unwrap(); + assert_eq!(cached_cohorts.len(), 1); + assert_eq!(cached_cohorts[0].team_id, team_id); + + Ok(()) + } +} diff --git a/rust/feature-flags/src/cohort_models.rs b/rust/feature-flags/src/cohort_models.rs new file mode 100644 index 00000000000..d1099839017 --- /dev/null +++ b/rust/feature-flags/src/cohort_models.rs @@ -0,0 +1,50 @@ +use crate::flag_definitions::PropertyFilter; +use serde::{Deserialize, Serialize}; +use sqlx::FromRow; + +#[derive(Debug, Clone, Serialize, Deserialize, FromRow)] +pub struct Cohort { + pub id: i32, + pub name: String, + pub description: Option, + pub team_id: i32, + pub deleted: bool, + pub filters: serde_json::Value, + pub query: Option, + pub version: Option, + pub pending_version: Option, + pub count: Option, + pub is_calculating: bool, + pub is_static: bool, + pub errors_calculating: i32, + pub groups: serde_json::Value, + pub created_by_id: Option, +} + +pub type CohortId = i32; + +#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)] +#[serde(rename_all = "UPPERCASE")] +pub enum CohortPropertyType { + AND, + OR, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct CohortProperty { + pub properties: InnerCohortProperty, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct InnerCohortProperty { + #[serde(rename = "type")] + pub prop_type: CohortPropertyType, + pub values: Vec, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct CohortValues { + #[serde(rename = "type")] + pub prop_type: String, + pub values: Vec, +} diff --git a/rust/feature-flags/src/cohort_operations.rs b/rust/feature-flags/src/cohort_operations.rs new file mode 100644 index 00000000000..ea4214ccdc0 --- /dev/null +++ b/rust/feature-flags/src/cohort_operations.rs @@ -0,0 +1,369 @@ +use std::collections::HashSet; +use std::sync::Arc; +use tracing::instrument; + +use crate::cohort_models::{Cohort, CohortId, CohortProperty, InnerCohortProperty}; +use crate::{api::FlagError, database::Client as DatabaseClient, flag_definitions::PropertyFilter}; + +impl Cohort { + /// Returns a cohort from postgres given a cohort_id and team_id + #[instrument(skip_all)] + pub async fn from_pg( + client: Arc, + cohort_id: i32, + team_id: i32, + ) -> Result { + let mut conn = client.get_connection().await.map_err(|e| { + tracing::error!("Failed to get database connection: {}", e); + // TODO should I model my errors more generally? Like, yes, everything behind this API is technically a FlagError, + // but I'm not sure if accessing Cohort definitions should be a FlagError (vs idk, a CohortError? A more general API error?) + FlagError::DatabaseUnavailable + })?; + + let query = "SELECT id, name, description, team_id, deleted, filters, query, version, pending_version, count, is_calculating, is_static, errors_calculating, groups, created_by_id FROM posthog_cohort WHERE id = $1 AND team_id = $2"; + let cohort = sqlx::query_as::<_, Cohort>(query) + .bind(cohort_id) + .bind(team_id) + .fetch_optional(&mut *conn) + .await + .map_err(|e| { + tracing::error!("Failed to fetch cohort from database: {}", e); + FlagError::Internal(format!("Database query error: {}", e)) + })?; + + cohort.ok_or_else(|| { + FlagError::CohortNotFound(format!( + "Cohort with id {} not found for team {}", + cohort_id, team_id + )) + }) + } + + /// Returns all cohorts for a given team + #[instrument(skip_all)] + pub async fn list_from_pg( + client: Arc, + team_id: i32, + ) -> Result, FlagError> { + let mut conn = client.get_connection().await.map_err(|e| { + tracing::error!("Failed to get database connection: {}", e); + FlagError::DatabaseUnavailable + })?; + + let query = "SELECT id, name, description, team_id, deleted, filters, query, version, pending_version, count, is_calculating, is_static, errors_calculating, groups, created_by_id FROM posthog_cohort WHERE team_id = $1"; + let cohorts = sqlx::query_as::<_, Cohort>(query) + .bind(team_id) + .fetch_all(&mut *conn) + .await + .map_err(|e| { + tracing::error!("Failed to fetch cohorts from database: {}", e); + FlagError::Internal(format!("Database query error: {}", e)) + })?; + + Ok(cohorts) + } + + /// Parses the filters JSON into a CohortProperty structure + // TODO: this doesn't handle the deprecated "groups" field, see + // https://github.com/PostHog/posthog/blob/feat/dynamic-cohorts-rust/posthog/models/cohort/cohort.py#L114-L169 + // I'll handle that in a separate PR. + pub fn parse_filters(&self) -> Result, FlagError> { + let cohort_property: CohortProperty = serde_json::from_value(self.filters.clone()) + .map_err(|e| { + tracing::error!("Failed to parse filters for cohort {}: {}", self.id, e); + FlagError::CohortFiltersParsingError + })?; + Ok(cohort_property + .properties + .to_property_filters() + .into_iter() + .filter(|f| !(f.key == "id" && f.prop_type == "cohort")) + .collect()) + } + + /// Extracts dependent CohortIds from the cohort's filters + pub fn extract_dependencies(&self) -> Result, FlagError> { + let cohort_property: CohortProperty = serde_json::from_value(self.filters.clone()) + .map_err(|e| { + tracing::error!("Failed to parse filters for cohort {}: {}", self.id, e); + FlagError::CohortFiltersParsingError + })?; + + let mut dependencies = HashSet::new(); + Self::traverse_filters(&cohort_property.properties, &mut dependencies)?; + Ok(dependencies) + } + + /// Recursively traverses the filter tree to find cohort dependencies + /// + /// Example filter tree structure: + /// ```json + /// { + /// "properties": { + /// "type": "OR", + /// "values": [ + /// { + /// "type": "OR", + /// "values": [ + /// { + /// "key": "id", + /// "value": 123, + /// "type": "cohort", + /// "operator": "exact" + /// }, + /// { + /// "key": "email", + /// "value": "@posthog.com", + /// "type": "person", + /// "operator": "icontains" + /// } + /// ] + /// } + /// ] + /// } + /// } + /// ``` + fn traverse_filters( + inner: &InnerCohortProperty, + dependencies: &mut HashSet, + ) -> Result<(), FlagError> { + for cohort_values in &inner.values { + for filter in &cohort_values.values { + if filter.is_cohort() { + // Assuming the value is a single integer CohortId + if let Some(cohort_id) = filter.value.as_i64() { + dependencies.insert(cohort_id as CohortId); + } else { + return Err(FlagError::CohortFiltersParsingError); + } + } + // NB: we don't support nested cohort properties, so we don't need to traverse further + } + } + Ok(()) + } +} + +impl InnerCohortProperty { + /// Flattens the nested cohort property structure into a list of property filters. + /// + /// The cohort property structure in Postgres looks like: + /// ```json + /// { + /// "type": "OR", + /// "values": [ + /// { + /// "type": "OR", + /// "values": [ + /// { + /// "key": "email", + /// "value": "@posthog.com", + /// "type": "person", + /// "operator": "icontains" + /// }, + /// { + /// "key": "age", + /// "value": 25, + /// "type": "person", + /// "operator": "gt" + /// } + /// ] + /// } + /// ] + /// } + /// ``` + pub fn to_property_filters(&self) -> Vec { + self.values + .iter() + .flat_map(|value| &value.values) + .cloned() + .collect() + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + cohort_models::{CohortPropertyType, CohortValues}, + test_utils::{ + insert_cohort_for_team_in_pg, insert_new_team_in_pg, setup_pg_reader_client, + setup_pg_writer_client, + }, + }; + use serde_json::json; + + #[tokio::test] + async fn test_cohort_from_pg() { + let postgres_reader = setup_pg_reader_client(None).await; + let postgres_writer = setup_pg_writer_client(None).await; + + let team = insert_new_team_in_pg(postgres_reader.clone(), None) + .await + .expect("Failed to insert team"); + + let cohort = insert_cohort_for_team_in_pg( + postgres_writer.clone(), + team.id, + None, + json!({"properties": {"type": "OR", "values": [{"type": "OR", "values": [{"key": "$initial_browser_version", "type": "person", "value": ["125"], "negation": false, "operator": "exact"}]}]}}), + false, + ) + .await + .expect("Failed to insert cohort"); + + let fetched_cohort = Cohort::from_pg(postgres_reader, cohort.id, team.id) + .await + .expect("Failed to fetch cohort"); + + assert_eq!(fetched_cohort.id, cohort.id); + assert_eq!(fetched_cohort.name, "Test Cohort"); + assert_eq!(fetched_cohort.team_id, team.id); + } + + #[tokio::test] + async fn test_list_from_pg() { + let postgres_reader = setup_pg_reader_client(None).await; + let postgres_writer = setup_pg_writer_client(None).await; + + let team = insert_new_team_in_pg(postgres_reader.clone(), None) + .await + .expect("Failed to insert team"); + + // Insert multiple cohorts for the team + insert_cohort_for_team_in_pg( + postgres_writer.clone(), + team.id, + Some("Cohort 1".to_string()), + json!({"properties": {"type": "AND", "values": [{"type": "property", "values": [{"key": "age", "type": "person", "value": [30], "negation": false, "operator": "gt"}]}]}}), + false, + ) + .await + .expect("Failed to insert cohort1"); + + insert_cohort_for_team_in_pg( + postgres_writer.clone(), + team.id, + Some("Cohort 2".to_string()), + json!({"properties": {"type": "OR", "values": [{"type": "property", "values": [{"key": "country", "type": "person", "value": ["USA"], "negation": false, "operator": "exact"}]}]}}), + false, + ) + .await + .expect("Failed to insert cohort2"); + + let cohorts = Cohort::list_from_pg(postgres_reader, team.id) + .await + .expect("Failed to list cohorts"); + + assert_eq!(cohorts.len(), 2); + let names: HashSet = cohorts.into_iter().map(|c| c.name).collect(); + assert!(names.contains("Cohort 1")); + assert!(names.contains("Cohort 2")); + } + + #[test] + fn test_cohort_parse_filters() { + let cohort = Cohort { + id: 1, + name: "Test Cohort".to_string(), + description: None, + team_id: 1, + deleted: false, + filters: json!({"properties": {"type": "OR", "values": [{"type": "OR", "values": [{"key": "$initial_browser_version", "type": "person", "value": ["125"], "negation": false, "operator": "exact"}]}]}}), + query: None, + version: None, + pending_version: None, + count: None, + is_calculating: false, + is_static: false, + errors_calculating: 0, + groups: json!({}), + created_by_id: None, + }; + + let result = cohort.parse_filters().unwrap(); + assert_eq!(result.len(), 1); + assert_eq!(result[0].key, "$initial_browser_version"); + assert_eq!(result[0].value, json!(["125"])); + assert_eq!(result[0].prop_type, "person"); + } + + #[test] + fn test_cohort_property_to_property_filters() { + let cohort_property = InnerCohortProperty { + prop_type: CohortPropertyType::AND, + values: vec![CohortValues { + prop_type: "property".to_string(), + values: vec![ + PropertyFilter { + key: "email".to_string(), + value: json!("test@example.com"), + operator: None, + prop_type: "person".to_string(), + group_type_index: None, + negation: None, + }, + PropertyFilter { + key: "age".to_string(), + value: json!(25), + operator: None, + prop_type: "person".to_string(), + group_type_index: None, + negation: None, + }, + ], + }], + }; + + let result = cohort_property.to_property_filters(); + assert_eq!(result.len(), 2); + assert_eq!(result[0].key, "email"); + assert_eq!(result[0].value, json!("test@example.com")); + assert_eq!(result[1].key, "age"); + assert_eq!(result[1].value, json!(25)); + } + + #[tokio::test] + async fn test_extract_dependencies() { + let postgres_reader = setup_pg_reader_client(None).await; + let postgres_writer = setup_pg_writer_client(None).await; + + let team = insert_new_team_in_pg(postgres_reader.clone(), None) + .await + .expect("Failed to insert team"); + + // Insert a single cohort that is dependent on another cohort + let dependent_cohort = insert_cohort_for_team_in_pg( + postgres_writer.clone(), + team.id, + Some("Dependent Cohort".to_string()), + json!({"properties": {"type": "OR", "values": [{"type": "OR", "values": [{"key": "$browser", "type": "person", "value": ["Safari"], "negation": false, "operator": "exact"}]}]}}), + false, + ) + .await + .expect("Failed to insert dependent_cohort"); + + // Insert main cohort with a single dependency + let main_cohort = insert_cohort_for_team_in_pg( + postgres_writer.clone(), + team.id, + Some("Main Cohort".to_string()), + json!({"properties": {"type": "OR", "values": [{"type": "OR", "values": [{"key": "id", "type": "cohort", "value": dependent_cohort.id, "negation": false}]}]}}), + false, + ) + .await + .expect("Failed to insert main_cohort"); + + let fetched_main_cohort = Cohort::from_pg(postgres_reader.clone(), main_cohort.id, team.id) + .await + .expect("Failed to fetch main cohort"); + + println!("fetched_main_cohort: {:?}", fetched_main_cohort); + + let dependencies = fetched_main_cohort.extract_dependencies().unwrap(); + let expected_dependencies: HashSet = + [dependent_cohort.id].iter().cloned().collect(); + + assert_eq!(dependencies, expected_dependencies); + } +} diff --git a/rust/feature-flags/src/flag_definitions.rs b/rust/feature-flags/src/flag_definitions.rs index baebaa04da3..d62ecc9e0e0 100644 --- a/rust/feature-flags/src/flag_definitions.rs +++ b/rust/feature-flags/src/flag_definitions.rs @@ -1,4 +1,7 @@ -use crate::{api::FlagError, database::Client as DatabaseClient, redis::Client as RedisClient}; +use crate::{ + api::FlagError, cohort_models::CohortId, database::Client as DatabaseClient, + redis::Client as RedisClient, +}; use serde::{Deserialize, Serialize}; use std::sync::Arc; use tracing::instrument; @@ -7,7 +10,7 @@ use tracing::instrument; // TODO: Add integration tests across repos to ensure this doesn't happen. pub const TEAM_FLAGS_CACHE_PREFIX: &str = "posthog:1:team_feature_flags_"; -#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)] #[serde(rename_all = "snake_case")] pub enum OperatorType { Exact, @@ -25,6 +28,8 @@ pub enum OperatorType { IsDateExact, IsDateAfter, IsDateBefore, + In, + NotIn, } #[derive(Debug, Clone, Deserialize, Serialize)] @@ -36,10 +41,28 @@ pub struct PropertyFilter { pub value: serde_json::Value, pub operator: Option, #[serde(rename = "type")] + // TODO: worth making a enum here to differentiate between cohort and person filters? pub prop_type: String, + pub negation: Option, pub group_type_index: Option, } +impl PropertyFilter { + /// Checks if the filter is a cohort filter + pub fn is_cohort(&self) -> bool { + self.key == "id" && self.prop_type == "cohort" + } + + /// Returns the cohort id if the filter is a cohort filter, or None if it's not a cohort filter + /// or if the value cannot be parsed as a cohort id + pub fn get_cohort_id(&self) -> Option { + if !self.is_cohort() { + return None; + } + self.value.as_i64().map(|id| id as CohortId) + } +} + #[derive(Debug, Clone, Deserialize, Serialize)] pub struct FlagGroupType { pub properties: Option>, @@ -68,6 +91,9 @@ pub struct FlagFilters { pub super_groups: Option>, } +// TODO: see if you can combine these two structs, like we do with cohort models +// this will require not deserializing on read and instead doing it lazily, on-demand +// (which, tbh, is probably a better idea) #[derive(Debug, Clone, Deserialize, Serialize)] pub struct FeatureFlag { pub id: i32, @@ -142,7 +168,7 @@ impl FeatureFlagList { tracing::error!("failed to parse data to flags list: {}", e); println!("failed to parse data: {}", e); - FlagError::DataParsingError + FlagError::RedisDataParsingError })?; Ok(FeatureFlagList { flags: flags_list }) @@ -174,7 +200,7 @@ impl FeatureFlagList { .map(|row| { let filters = serde_json::from_value(row.filters).map_err(|e| { tracing::error!("Failed to deserialize filters for flag {}: {}", row.key, e); - FlagError::DataParsingError + FlagError::RedisDataParsingError })?; Ok(FeatureFlag { @@ -200,7 +226,7 @@ impl FeatureFlagList { ) -> Result<(), FlagError> { let payload = serde_json::to_string(&flags.flags).map_err(|e| { tracing::error!("Failed to serialize flags: {}", e); - FlagError::DataParsingError + FlagError::RedisDataParsingError })?; client @@ -1095,7 +1121,7 @@ mod tests { .expect("Failed to set malformed JSON in Redis"); let result = FeatureFlagList::from_redis(redis_client, team.id).await; - assert!(matches!(result, Err(FlagError::DataParsingError))); + assert!(matches!(result, Err(FlagError::RedisDataParsingError))); // Test database query error (using a non-existent table) let result = sqlx::query("SELECT * FROM non_existent_table") diff --git a/rust/feature-flags/src/flag_matching.rs b/rust/feature-flags/src/flag_matching.rs index bdcd542f098..571fe9c84b4 100644 --- a/rust/feature-flags/src/flag_matching.rs +++ b/rust/feature-flags/src/flag_matching.rs @@ -1,30 +1,34 @@ use crate::{ api::{FlagError, FlagValue, FlagsResponse}, + cohort_cache::CohortCacheManager, + cohort_models::{Cohort, CohortId}, database::Client as DatabaseClient, feature_flag_match_reason::FeatureFlagMatchReason, - flag_definitions::{FeatureFlag, FeatureFlagList, FlagGroupType, PropertyFilter}, + flag_definitions::{FeatureFlag, FeatureFlagList, FlagGroupType, OperatorType, PropertyFilter}, metrics_consts::{FLAG_EVALUATION_ERROR_COUNTER, FLAG_HASH_KEY_WRITES_COUNTER}, + metrics_utils::parse_exception_for_prometheus_label, property_matching::match_property, - utils::parse_exception_for_prometheus_label, }; use anyhow::Result; use common_metrics::inc; +use petgraph::algo::{is_cyclic_directed, toposort}; +use petgraph::graph::DiGraph; use serde_json::Value; use sha1::{Digest, Sha1}; use sqlx::{postgres::PgQueryResult, Acquire, FromRow}; use std::fmt::Write; use std::sync::Arc; use std::{ - collections::{HashMap, HashSet}, + collections::{HashMap, HashSet, VecDeque}, time::Duration, }; use tokio::time::{sleep, timeout}; use tracing::{error, info}; -type TeamId = i32; -type GroupTypeIndex = i32; -type PostgresReader = Arc; -type PostgresWriter = Arc; +pub type TeamId = i32; +pub type GroupTypeIndex = i32; +pub type PostgresReader = Arc; +pub type PostgresWriter = Arc; #[derive(Debug)] struct SuperConditionEvaluation { @@ -182,6 +186,7 @@ pub struct FeatureFlagMatcher { pub team_id: TeamId, pub postgres_reader: PostgresReader, pub postgres_writer: PostgresWriter, + pub cohort_cache: Arc, group_type_mapping_cache: GroupTypeMappingCache, properties_cache: PropertiesCache, groups: HashMap, @@ -195,8 +200,8 @@ impl FeatureFlagMatcher { team_id: TeamId, postgres_reader: PostgresReader, postgres_writer: PostgresWriter, + cohort_cache: Arc, group_type_mapping_cache: Option, - properties_cache: Option, groups: Option>, ) -> Self { FeatureFlagMatcher { @@ -204,10 +209,11 @@ impl FeatureFlagMatcher { team_id, postgres_reader: postgres_reader.clone(), postgres_writer: postgres_writer.clone(), + cohort_cache, group_type_mapping_cache: group_type_mapping_cache .unwrap_or_else(|| GroupTypeMappingCache::new(team_id, postgres_reader.clone())), - properties_cache: properties_cache.unwrap_or_default(), groups: groups.unwrap_or_default(), + properties_cache: PropertiesCache::default(), } } @@ -732,12 +738,29 @@ impl FeatureFlagMatcher { .await; } - // NB: we can only evaluate group or person properties, not both - let properties_to_check = self - .get_properties_to_check(feature_flag, property_overrides, flag_property_filters) + // Separate cohort and non-cohort filters + let (cohort_filters, non_cohort_filters): (Vec, Vec) = + flag_property_filters + .iter() + .cloned() + .partition(|prop| prop.is_cohort()); + + // Get the properties we need to check for in this condition match from the flag + any overrides + let target_properties = self + .get_properties_to_check(feature_flag, property_overrides, &non_cohort_filters) .await?; - if !all_properties_match(flag_property_filters, &properties_to_check) { + // Evaluate non-cohort filters first, since they're cheaper to evaluate and we can return early if they don't match + if !all_properties_match(&non_cohort_filters, &target_properties) { + return Ok((false, FeatureFlagMatchReason::NoConditionMatch)); + } + + // Evaluate cohort filters, if any. + if !cohort_filters.is_empty() + && !self + .evaluate_cohort_filters(&cohort_filters, &target_properties) + .await? + { return Ok((false, FeatureFlagMatchReason::NoConditionMatch)); } } @@ -805,6 +828,37 @@ impl FeatureFlagMatcher { } } + /// Evaluates dynamic cohort property filters + /// + /// NB: This method first caches all of the cohorts associated with the team, which allows us to avoid + /// hitting the database for each cohort filter. + pub async fn evaluate_cohort_filters( + &self, + cohort_property_filters: &[PropertyFilter], + target_properties: &HashMap, + ) -> Result { + // At the start of the request, fetch all of the cohorts for the team from the cache + // This method also caches the cohorts in memory for the duration of the application, so we don't need to fetch from + // the database again until we restart the application. + let cohorts = self.cohort_cache.get_cohorts_for_team(self.team_id).await?; + + // Store cohort match results in a HashMap to avoid re-evaluating the same cohort multiple times, + // since the same cohort could appear in multiple property filters. This is especially important + // because evaluating a cohort requires evaluating all of its dependencies, which can be expensive. + let mut cohort_matches = HashMap::new(); + for filter in cohort_property_filters { + let cohort_id = filter + .get_cohort_id() + .ok_or(FlagError::CohortFiltersParsingError)?; + let match_result = + evaluate_cohort_dependencies(cohort_id, target_properties, cohorts.clone())?; + cohort_matches.insert(cohort_id, match_result); + } + + // Apply cohort membership logic (IN|NOT_IN) + apply_cohort_membership_logic(cohort_property_filters, &cohort_matches) + } + /// Check if a super condition matches for a feature flag. /// /// This function evaluates the super conditions of a feature flag to determine if any of them should be enabled. @@ -1048,6 +1102,172 @@ impl FeatureFlagMatcher { } } +/// Evaluates a single cohort and its dependencies. +/// This uses a topological sort to evaluate dependencies first, which is necessary +/// because a cohort can depend on another cohort, and we need to respect the dependency order. +fn evaluate_cohort_dependencies( + initial_cohort_id: CohortId, + target_properties: &HashMap, + cohorts: Vec, +) -> Result { + let cohort_dependency_graph = + build_cohort_dependency_graph(initial_cohort_id, cohorts.clone())?; + + // We need to sort cohorts topologically to ensure we evaluate dependencies before the cohorts that depend on them. + // For example, if cohort A depends on cohort B, we need to evaluate B first to know if A matches. + // This also helps detect cycles - if cohort A depends on B which depends on A, toposort will fail. + let sorted_cohort_ids_as_graph_nodes = + toposort(&cohort_dependency_graph, None).map_err(|e| { + FlagError::CohortDependencyCycle(format!("Cyclic dependency detected: {:?}", e)) + })?; + + // Store evaluation results for each cohort in a map, so we can look up whether a cohort matched + // when evaluating cohorts that depend on it, and also return the final result for the initial cohort + let mut evaluation_results = HashMap::new(); + + // Iterate through the sorted nodes in reverse order (so that we can evaluate dependencies first) + for node in sorted_cohort_ids_as_graph_nodes.into_iter().rev() { + let cohort_id = cohort_dependency_graph[node]; + let cohort = cohorts + .iter() + .find(|c| c.id == cohort_id) + .ok_or(FlagError::CohortNotFound(cohort_id.to_string()))?; + let property_filters = cohort.parse_filters()?; + let dependencies = cohort.extract_dependencies()?; + + // Check if all dependencies have been met (i.e., previous cohorts matched) + let dependencies_met = dependencies + .iter() + .all(|dep_id| evaluation_results.get(dep_id).copied().unwrap_or(false)); + + // If dependencies are not met, mark the current cohort as not matched and continue + // NB: We don't want to _exit_ here, since the non-matching cohort could be wrapped in a `not_in` operator + // and we want to evaluate all cohorts to determine if the initial cohort matches. + if !dependencies_met { + evaluation_results.insert(cohort_id, false); + continue; + } + + // Evaluate all property filters for the current cohort + let all_filters_match = property_filters + .iter() + .all(|filter| match_property(filter, target_properties, false).unwrap_or(false)); + + // Store the evaluation result for the current cohort + evaluation_results.insert(cohort_id, all_filters_match); + } + + // Retrieve and return the evaluation result for the initial cohort + evaluation_results + .get(&initial_cohort_id) + .copied() + .ok_or_else(|| FlagError::CohortNotFound(initial_cohort_id.to_string())) +} + +/// Apply cohort membership logic (i.e., IN|NOT_IN) +fn apply_cohort_membership_logic( + cohort_filters: &[PropertyFilter], + cohort_matches: &HashMap, +) -> Result { + for filter in cohort_filters { + let cohort_id = filter + .get_cohort_id() + .ok_or(FlagError::CohortFiltersParsingError)?; + let matches = cohort_matches.get(&cohort_id).copied().unwrap_or(false); + let operator = filter.operator.unwrap_or(OperatorType::In); + + // Combine the operator logic directly within this method + let membership_match = match operator { + OperatorType::In => matches, + OperatorType::NotIn => !matches, + // Currently supported operators are IN and NOT IN + // Any other operator defaults to false + _ => false, + }; + + // If any filter does not match, return false early + if !membership_match { + return Ok(false); + } + } + // All filters matched + Ok(true) +} + +/// Constructs a dependency graph for cohorts. +/// +/// Example dependency graph: +/// ```text +/// A B +/// | /| +/// | / | +/// | / | +/// C D +/// \ / +/// \ / +/// E +/// ``` +/// In this example: +/// - Cohorts A and B are root nodes (no dependencies) +/// - C depends on A and B +/// - D depends on B +/// - E depends on C and D +/// +/// The graph is acyclic, which is required for valid cohort dependencies. +fn build_cohort_dependency_graph( + initial_cohort_id: CohortId, + cohorts: Vec, +) -> Result, FlagError> { + let mut graph = DiGraph::new(); + let mut node_map = HashMap::new(); + let mut queue = VecDeque::new(); + // This implements a breadth-first search (BFS) traversal to build a directed graph of cohort dependencies. + // Starting from the initial cohort, we: + // 1. Add each cohort as a node in the graph + // 2. Track visited nodes in a map to avoid duplicates + // 3. For each cohort, get its dependencies and add directed edges from the cohort to its dependencies + // 4. Queue up any unvisited dependencies to process their dependencies later + // This builds up the full dependency graph level by level, which we can later check for cycles + queue.push_back(initial_cohort_id); + node_map.insert(initial_cohort_id, graph.add_node(initial_cohort_id)); + + while let Some(cohort_id) = queue.pop_front() { + let cohort = cohorts + .iter() + .find(|c| c.id == cohort_id) + .ok_or(FlagError::CohortNotFound(cohort_id.to_string()))?; + let dependencies = cohort.extract_dependencies()?; + for dep_id in dependencies { + // Retrieve the current node **before** mutable borrowing + // This is safe because we're not mutating the node map, + // and it keeps the borrow checker happy + let current_node = node_map[&cohort_id]; + // Add dependency node if we haven't seen this cohort ID before in our traversal. + // This happens when we discover a new dependency that wasn't previously + // encountered while processing other cohorts in the graph. + let dep_node = node_map + .entry(dep_id) + .or_insert_with(|| graph.add_node(dep_id)); + + graph.add_edge(current_node, *dep_node, ()); + + if !node_map.contains_key(&dep_id) { + queue.push_back(dep_id); + } + } + } + + // Check for cycles, this is an directed acyclic graph so we use is_cyclic_directed + if is_cyclic_directed(&graph) { + return Err(FlagError::CohortDependencyCycle(format!( + "Cyclic dependency detected starting at cohort {}", + initial_cohort_id + ))); + } + + Ok(graph) +} + /// Fetch and locally cache all properties for a given distinct ID and team ID. /// /// This function fetches both person and group properties for a specified distinct ID and team ID. @@ -1443,8 +1663,8 @@ mod tests { OperatorType, }, test_utils::{ - insert_flag_for_team_in_pg, insert_new_team_in_pg, insert_person_for_team_in_pg, - setup_pg_reader_client, setup_pg_writer_client, + insert_cohort_for_team_in_pg, insert_flag_for_team_in_pg, insert_new_team_in_pg, + insert_person_for_team_in_pg, setup_pg_reader_client, setup_pg_writer_client, }, }; @@ -1485,6 +1705,7 @@ mod tests { async fn test_fetch_properties_from_pg_to_match() { let postgres_reader = setup_pg_reader_client(None).await; let postgres_writer = setup_pg_writer_client(None).await; + let cohort_cache = Arc::new(CohortCacheManager::new(postgres_reader.clone(), None, None)); let team = insert_new_team_in_pg(postgres_reader.clone(), None) .await @@ -1534,7 +1755,7 @@ mod tests { team.id, postgres_reader.clone(), postgres_writer.clone(), - None, + cohort_cache.clone(), None, None, ); @@ -1547,7 +1768,7 @@ mod tests { team.id, postgres_reader.clone(), postgres_writer.clone(), - None, + cohort_cache.clone(), None, None, ); @@ -1560,7 +1781,7 @@ mod tests { team.id, postgres_reader.clone(), postgres_writer.clone(), - None, + cohort_cache.clone(), None, None, ); @@ -1573,6 +1794,7 @@ mod tests { async fn test_person_property_overrides() { let postgres_reader = setup_pg_reader_client(None).await; let postgres_writer = setup_pg_writer_client(None).await; + let cohort_cache = Arc::new(CohortCacheManager::new(postgres_reader.clone(), None, None)); let team = insert_new_team_in_pg(postgres_reader.clone(), None) .await .unwrap(); @@ -1590,6 +1812,7 @@ mod tests { operator: None, prop_type: "person".to_string(), group_type_index: None, + negation: None, }]), rollout_percentage: Some(100.0), variant: None, @@ -1611,7 +1834,7 @@ mod tests { team.id, postgres_reader, postgres_writer, - None, + cohort_cache, None, None, ); @@ -1633,6 +1856,7 @@ mod tests { async fn test_group_property_overrides() { let postgres_reader = setup_pg_reader_client(None).await; let postgres_writer = setup_pg_writer_client(None).await; + let cohort_cache = Arc::new(CohortCacheManager::new(postgres_reader.clone(), None, None)); let team = insert_new_team_in_pg(postgres_reader.clone(), None) .await .unwrap(); @@ -1650,6 +1874,7 @@ mod tests { operator: None, prop_type: "group".to_string(), group_type_index: Some(1), + negation: None, }]), rollout_percentage: Some(100.0), variant: None, @@ -1664,10 +1889,12 @@ mod tests { None, ); - let mut cache = GroupTypeMappingCache::new(team.id, postgres_reader.clone()); + let mut group_type_mapping_cache = + GroupTypeMappingCache::new(team.id, postgres_reader.clone()); let group_types_to_indexes = [("organization".to_string(), 1)].into_iter().collect(); - cache.group_types_to_indexes = group_types_to_indexes; - cache.group_indexes_to_types = [(1, "organization".to_string())].into_iter().collect(); + group_type_mapping_cache.group_types_to_indexes = group_types_to_indexes; + group_type_mapping_cache.group_indexes_to_types = + [(1, "organization".to_string())].into_iter().collect(); let groups = HashMap::from([("organization".to_string(), json!("org_123"))]); @@ -1684,8 +1911,8 @@ mod tests { team.id, postgres_reader.clone(), postgres_writer.clone(), - Some(cache), - None, + cohort_cache.clone(), + Some(group_type_mapping_cache), Some(groups), ); @@ -1708,14 +1935,14 @@ mod tests { let flag = create_test_flag_with_variants(1); let postgres_reader = setup_pg_reader_client(None).await; let postgres_writer = setup_pg_writer_client(None).await; - - let mut cache = GroupTypeMappingCache::new(1, postgres_reader.clone()); + let cohort_cache = Arc::new(CohortCacheManager::new(postgres_reader.clone(), None, None)); + let mut group_type_mapping_cache = GroupTypeMappingCache::new(1, postgres_reader.clone()); let group_types_to_indexes = [("group_type_1".to_string(), 1)].into_iter().collect(); let group_type_index_to_name = [(1, "group_type_1".to_string())].into_iter().collect(); - cache.group_types_to_indexes = group_types_to_indexes; - cache.group_indexes_to_types = group_type_index_to_name; + group_type_mapping_cache.group_types_to_indexes = group_types_to_indexes; + group_type_mapping_cache.group_indexes_to_types = group_type_index_to_name; let groups = HashMap::from([("group_type_1".to_string(), json!("group_key_1"))]); @@ -1724,8 +1951,8 @@ mod tests { 1, postgres_reader.clone(), postgres_writer.clone(), - Some(cache), - None, + cohort_cache.clone(), + Some(group_type_mapping_cache), Some(groups), ); let variant = matcher.get_matching_variant(&flag, None).await.unwrap(); @@ -1740,6 +1967,7 @@ mod tests { async fn test_get_matching_variant_with_db() { let postgres_reader = setup_pg_reader_client(None).await; let postgres_writer = setup_pg_writer_client(None).await; + let cohort_cache = Arc::new(CohortCacheManager::new(postgres_reader.clone(), None, None)); let team = insert_new_team_in_pg(postgres_reader.clone(), None) .await .unwrap(); @@ -1751,7 +1979,7 @@ mod tests { team.id, postgres_reader.clone(), postgres_writer.clone(), - None, + cohort_cache.clone(), None, None, ); @@ -1765,6 +1993,7 @@ mod tests { async fn test_is_condition_match_empty_properties() { let postgres_reader = setup_pg_reader_client(None).await; let postgres_writer = setup_pg_writer_client(None).await; + let cohort_cache = Arc::new(CohortCacheManager::new(postgres_reader.clone(), None, None)); let flag = create_test_flag( Some(1), None, @@ -1797,7 +2026,7 @@ mod tests { 1, postgres_reader, postgres_writer, - None, + cohort_cache, None, None, ); @@ -1854,6 +2083,7 @@ mod tests { async fn test_overrides_avoid_db_lookups() { let postgres_reader = setup_pg_reader_client(None).await; let postgres_writer = setup_pg_writer_client(None).await; + let cohort_cache = Arc::new(CohortCacheManager::new(postgres_reader.clone(), None, None)); let team = insert_new_team_in_pg(postgres_reader.clone(), None) .await .unwrap(); @@ -1871,6 +2101,7 @@ mod tests { operator: Some(OperatorType::Exact), prop_type: "person".to_string(), group_type_index: None, + negation: None, }]), rollout_percentage: Some(100.0), variant: None, @@ -1893,7 +2124,7 @@ mod tests { team.id, postgres_reader.clone(), postgres_writer.clone(), - None, + cohort_cache.clone(), None, None, ); @@ -1923,6 +2154,7 @@ mod tests { async fn test_fallback_to_db_when_overrides_insufficient() { let postgres_reader = setup_pg_reader_client(None).await; let postgres_writer = setup_pg_writer_client(None).await; + let cohort_cache = Arc::new(CohortCacheManager::new(postgres_reader.clone(), None, None)); let team = insert_new_team_in_pg(postgres_reader.clone(), None) .await .unwrap(); @@ -1941,6 +2173,7 @@ mod tests { operator: Some(OperatorType::Exact), prop_type: "person".to_string(), group_type_index: None, + negation: None, }, PropertyFilter { key: "age".to_string(), @@ -1948,6 +2181,7 @@ mod tests { operator: Some(OperatorType::Gte), prop_type: "person".to_string(), group_type_index: None, + negation: None, }, ]), rollout_percentage: Some(100.0), @@ -1982,7 +2216,7 @@ mod tests { team.id, postgres_reader.clone(), postgres_writer.clone(), - None, + cohort_cache.clone(), None, None, ); @@ -2006,6 +2240,7 @@ mod tests { async fn test_property_fetching_and_caching() { let postgres_reader = setup_pg_reader_client(None).await; let postgres_writer = setup_pg_writer_client(None).await; + let cohort_cache = Arc::new(CohortCacheManager::new(postgres_reader.clone(), None, None)); let team = insert_new_team_in_pg(postgres_reader.clone(), None) .await .unwrap(); @@ -2025,7 +2260,7 @@ mod tests { team.id, postgres_reader.clone(), postgres_writer.clone(), - None, + cohort_cache.clone(), None, None, ); @@ -2050,6 +2285,7 @@ mod tests { async fn test_property_caching() { let postgres_reader = setup_pg_reader_client(None).await; let postgres_writer = setup_pg_writer_client(None).await; + let cohort_cache = Arc::new(CohortCacheManager::new(postgres_reader.clone(), None, None)); let team = insert_new_team_in_pg(postgres_reader.clone(), None) .await .unwrap(); @@ -2069,7 +2305,7 @@ mod tests { team.id, postgres_reader.clone(), postgres_writer.clone(), - None, + cohort_cache.clone(), None, None, ); @@ -2102,7 +2338,7 @@ mod tests { team.id, postgres_reader.clone(), postgres_writer.clone(), - None, + cohort_cache.clone(), None, None, ); @@ -2150,6 +2386,7 @@ mod tests { operator: None, prop_type: "person".to_string(), group_type_index: None, + negation: None, }, PropertyFilter { key: "age".to_string(), @@ -2157,6 +2394,7 @@ mod tests { operator: Some(OperatorType::Gte), prop_type: "person".to_string(), group_type_index: None, + negation: None, }, ]; @@ -2170,6 +2408,7 @@ mod tests { operator: None, prop_type: "person".to_string(), group_type_index: None, + negation: None, }, PropertyFilter { key: "cohort".to_string(), @@ -2177,6 +2416,7 @@ mod tests { operator: None, prop_type: "cohort".to_string(), group_type_index: None, + negation: None, }, ]; @@ -2189,6 +2429,7 @@ mod tests { async fn test_concurrent_flag_evaluation() { let postgres_reader = setup_pg_reader_client(None).await; let postgres_writer = setup_pg_writer_client(None).await; + let cohort_cache = Arc::new(CohortCacheManager::new(postgres_reader.clone(), None, None)); let team = insert_new_team_in_pg(postgres_reader.clone(), None) .await .unwrap(); @@ -2218,13 +2459,14 @@ mod tests { let flag_clone = flag.clone(); let postgres_reader_clone = postgres_reader.clone(); let postgres_writer_clone = postgres_writer.clone(); + let cohort_cache_clone = cohort_cache.clone(); handles.push(tokio::spawn(async move { let mut matcher = FeatureFlagMatcher::new( format!("test_user_{}", i), team.id, postgres_reader_clone, postgres_writer_clone, - None, + cohort_cache_clone, None, None, ); @@ -2246,6 +2488,7 @@ mod tests { async fn test_property_operators() { let postgres_reader = setup_pg_reader_client(None).await; let postgres_writer = setup_pg_writer_client(None).await; + let cohort_cache = Arc::new(CohortCacheManager::new(postgres_reader.clone(), None, None)); let team = insert_new_team_in_pg(postgres_reader.clone(), None) .await .unwrap(); @@ -2264,6 +2507,7 @@ mod tests { operator: Some(OperatorType::Gte), prop_type: "person".to_string(), group_type_index: None, + negation: None, }, PropertyFilter { key: "email".to_string(), @@ -2271,6 +2515,7 @@ mod tests { operator: Some(OperatorType::Icontains), prop_type: "person".to_string(), group_type_index: None, + negation: None, }, ]), rollout_percentage: Some(100.0), @@ -2300,7 +2545,7 @@ mod tests { team.id, postgres_reader.clone(), postgres_writer.clone(), - None, + cohort_cache.clone(), None, None, ); @@ -2314,7 +2559,7 @@ mod tests { async fn test_empty_hashed_identifier() { let postgres_reader = setup_pg_reader_client(None).await; let postgres_writer = setup_pg_writer_client(None).await; - + let cohort_cache = Arc::new(CohortCacheManager::new(postgres_reader.clone(), None, None)); let flag = create_test_flag( Some(1), None, @@ -2341,7 +2586,7 @@ mod tests { 1, postgres_reader, postgres_writer, - None, + cohort_cache, None, None, ); @@ -2355,6 +2600,7 @@ mod tests { async fn test_rollout_percentage() { let postgres_reader = setup_pg_reader_client(None).await; let postgres_writer = setup_pg_writer_client(None).await; + let cohort_cache = Arc::new(CohortCacheManager::new(postgres_reader.clone(), None, None)); let mut flag = create_test_flag( Some(1), None, @@ -2381,7 +2627,7 @@ mod tests { 1, postgres_reader, postgres_writer, - None, + cohort_cache, None, None, ); @@ -2402,7 +2648,7 @@ mod tests { async fn test_uneven_variant_distribution() { let postgres_reader = setup_pg_reader_client(None).await; let postgres_writer = setup_pg_writer_client(None).await; - + let cohort_cache = Arc::new(CohortCacheManager::new(postgres_reader.clone(), None, None)); let mut flag = create_test_flag_with_variants(1); // Adjust variant rollout percentages to be uneven @@ -2432,7 +2678,7 @@ mod tests { 1, postgres_reader, postgres_writer, - None, + cohort_cache, None, None, ); @@ -2464,6 +2710,7 @@ mod tests { async fn test_missing_properties_in_db() { let postgres_reader = setup_pg_reader_client(None).await; let postgres_writer = setup_pg_writer_client(None).await; + let cohort_cache = Arc::new(CohortCacheManager::new(postgres_reader.clone(), None, None)); let team = insert_new_team_in_pg(postgres_reader.clone(), None) .await .unwrap(); @@ -2491,6 +2738,7 @@ mod tests { operator: None, prop_type: "person".to_string(), group_type_index: None, + negation: None, }]), rollout_percentage: Some(100.0), variant: None, @@ -2510,7 +2758,7 @@ mod tests { team.id, postgres_reader.clone(), postgres_writer.clone(), - None, + cohort_cache, None, None, ); @@ -2524,6 +2772,7 @@ mod tests { async fn test_malformed_property_data() { let postgres_reader = setup_pg_reader_client(None).await; let postgres_writer = setup_pg_writer_client(None).await; + let cohort_cache = Arc::new(CohortCacheManager::new(postgres_reader.clone(), None, None)); let team = insert_new_team_in_pg(postgres_reader.clone(), None) .await .unwrap(); @@ -2551,6 +2800,7 @@ mod tests { operator: Some(OperatorType::Gte), prop_type: "person".to_string(), group_type_index: None, + negation: None, }]), rollout_percentage: Some(100.0), variant: None, @@ -2570,7 +2820,7 @@ mod tests { team.id, postgres_reader.clone(), postgres_writer.clone(), - None, + cohort_cache, None, None, ); @@ -2585,6 +2835,7 @@ mod tests { async fn test_get_match_with_insufficient_overrides() { let postgres_reader = setup_pg_reader_client(None).await; let postgres_writer = setup_pg_writer_client(None).await; + let cohort_cache = Arc::new(CohortCacheManager::new(postgres_reader.clone(), None, None)); let team = insert_new_team_in_pg(postgres_reader.clone(), None) .await .unwrap(); @@ -2603,6 +2854,7 @@ mod tests { operator: None, prop_type: "person".to_string(), group_type_index: None, + negation: None, }, PropertyFilter { key: "age".to_string(), @@ -2610,6 +2862,7 @@ mod tests { operator: Some(OperatorType::Gte), prop_type: "person".to_string(), group_type_index: None, + negation: None, }, ]), rollout_percentage: Some(100.0), @@ -2644,7 +2897,7 @@ mod tests { team.id, postgres_reader.clone(), postgres_writer.clone(), - None, + cohort_cache, None, None, ); @@ -2661,6 +2914,7 @@ mod tests { async fn test_evaluation_reasons() { let postgres_reader = setup_pg_reader_client(None).await; let postgres_writer = setup_pg_writer_client(None).await; + let cohort_cache = Arc::new(CohortCacheManager::new(postgres_reader.clone(), None, None)); let flag = create_test_flag( Some(1), None, @@ -2687,7 +2941,7 @@ mod tests { 1, postgres_reader.clone(), postgres_writer.clone(), - None, + cohort_cache, None, None, ); @@ -2705,6 +2959,7 @@ mod tests { async fn test_complex_conditions() { let postgres_reader = setup_pg_reader_client(None).await; let postgres_writer = setup_pg_writer_client(None).await; + let cohort_cache = Arc::new(CohortCacheManager::new(postgres_reader.clone(), None, None)); let team = insert_new_team_in_pg(postgres_reader.clone(), None) .await .unwrap(); @@ -2723,6 +2978,7 @@ mod tests { operator: None, prop_type: "person".to_string(), group_type_index: None, + negation: None, }]), rollout_percentage: Some(100.0), variant: None, @@ -2734,6 +2990,7 @@ mod tests { operator: Some(OperatorType::Gte), prop_type: "person".to_string(), group_type_index: None, + negation: None, }]), rollout_percentage: Some(100.0), variant: None, @@ -2763,7 +3020,7 @@ mod tests { team.id, postgres_reader.clone(), postgres_writer.clone(), - None, + cohort_cache, None, None, ); @@ -2777,6 +3034,7 @@ mod tests { async fn test_super_condition_matches_boolean() { let postgres_reader = setup_pg_reader_client(None).await; let postgres_writer = setup_pg_writer_client(None).await; + let cohort_cache = Arc::new(CohortCacheManager::new(postgres_reader.clone(), None, None)); let team = insert_new_team_in_pg(postgres_reader.clone(), None) .await .unwrap(); @@ -2795,6 +3053,7 @@ mod tests { operator: Some(OperatorType::Exact), prop_type: "person".to_string(), group_type_index: None, + negation: None, }]), rollout_percentage: Some(0.0), variant: None, @@ -2806,6 +3065,7 @@ mod tests { operator: Some(OperatorType::Exact), prop_type: "person".to_string(), group_type_index: None, + negation: None, }]), rollout_percentage: Some(100.0), variant: None, @@ -2826,6 +3086,7 @@ mod tests { operator: Some(OperatorType::Exact), prop_type: "person".to_string(), group_type_index: None, + negation: None, }]), rollout_percentage: Some(100.0), variant: None, @@ -2850,7 +3111,7 @@ mod tests { team.id, postgres_reader.clone(), postgres_writer.clone(), - None, + cohort_cache.clone(), None, None, ); @@ -2860,7 +3121,7 @@ mod tests { team.id, postgres_reader.clone(), postgres_writer.clone(), - None, + cohort_cache.clone(), None, None, ); @@ -2870,7 +3131,7 @@ mod tests { team.id, postgres_reader.clone(), postgres_writer.clone(), - None, + cohort_cache.clone(), None, None, ); @@ -2897,6 +3158,7 @@ mod tests { async fn test_super_condition_matches_string() { let postgres_reader = setup_pg_reader_client(None).await; let postgres_writer = setup_pg_writer_client(None).await; + let cohort_cache = Arc::new(CohortCacheManager::new(postgres_reader.clone(), None, None)); let team = insert_new_team_in_pg(postgres_reader.clone(), None) .await .unwrap(); @@ -2924,6 +3186,7 @@ mod tests { operator: Some(OperatorType::Exact), prop_type: "person".to_string(), group_type_index: None, + negation: None, }]), rollout_percentage: Some(0.0), variant: None, @@ -2935,6 +3198,7 @@ mod tests { operator: Some(OperatorType::Exact), prop_type: "person".to_string(), group_type_index: None, + negation: None, }]), rollout_percentage: Some(100.0), variant: None, @@ -2955,6 +3219,7 @@ mod tests { operator: Some(OperatorType::Exact), prop_type: "person".to_string(), group_type_index: None, + negation: None, }]), rollout_percentage: Some(100.0), variant: None, @@ -2970,7 +3235,7 @@ mod tests { team.id, postgres_reader.clone(), postgres_writer.clone(), - None, + cohort_cache.clone(), None, None, ); @@ -2986,6 +3251,7 @@ mod tests { async fn test_super_condition_matches_and_false() { let postgres_reader = setup_pg_reader_client(None).await; let postgres_writer = setup_pg_writer_client(None).await; + let cohort_cache = Arc::new(CohortCacheManager::new(postgres_reader.clone(), None, None)); let team = insert_new_team_in_pg(postgres_reader.clone(), None) .await .unwrap(); @@ -3013,6 +3279,7 @@ mod tests { operator: Some(OperatorType::Exact), prop_type: "person".to_string(), group_type_index: None, + negation: None, }]), rollout_percentage: Some(0.0), variant: None, @@ -3024,6 +3291,7 @@ mod tests { operator: Some(OperatorType::Exact), prop_type: "person".to_string(), group_type_index: None, + negation: None, }]), rollout_percentage: Some(100.0), variant: None, @@ -3044,6 +3312,7 @@ mod tests { operator: Some(OperatorType::Exact), prop_type: "person".to_string(), group_type_index: None, + negation: None, }]), rollout_percentage: Some(100.0), variant: None, @@ -3059,7 +3328,7 @@ mod tests { team.id, postgres_reader.clone(), postgres_writer.clone(), - None, + cohort_cache.clone(), None, None, ); @@ -3069,7 +3338,7 @@ mod tests { team.id, postgres_reader.clone(), postgres_writer.clone(), - None, + cohort_cache.clone(), None, None, ); @@ -3079,7 +3348,7 @@ mod tests { team.id, postgres_reader.clone(), postgres_writer.clone(), - None, + cohort_cache.clone(), None, None, ); @@ -3116,6 +3385,473 @@ mod tests { assert_eq!(result_another_id.condition_index, Some(2)); } + #[tokio::test] + async fn test_basic_cohort_matching() { + let postgres_reader = setup_pg_reader_client(None).await; + let postgres_writer = setup_pg_writer_client(None).await; + let cohort_cache = Arc::new(CohortCacheManager::new(postgres_reader.clone(), None, None)); + let team = insert_new_team_in_pg(postgres_reader.clone(), None) + .await + .unwrap(); + + // Insert a cohort with the condition that matches the test user's properties + let cohort_row = insert_cohort_for_team_in_pg( + postgres_reader.clone(), + team.id, + None, + json!({ + "properties": { + "type": "OR", + "values": [{ + "type": "OR", + "values": [{ + "key": "$browser_version", + "type": "person", + "value": "125", + "negation": false, + "operator": "gt" + }] + }] + } + }), + false, + ) + .await + .unwrap(); + + // Insert a person with properties that match the cohort condition + insert_person_for_team_in_pg( + postgres_reader.clone(), + team.id, + "test_user".to_string(), + Some(json!({"$browser_version": 126})), + ) + .await + .unwrap(); + + // Define a flag with a cohort filter + let flag = create_test_flag( + None, + Some(team.id), + None, + None, + Some(FlagFilters { + groups: vec![FlagGroupType { + properties: Some(vec![PropertyFilter { + key: "id".to_string(), + value: json!(cohort_row.id), + operator: Some(OperatorType::In), + prop_type: "cohort".to_string(), + group_type_index: None, + negation: Some(false), + }]), + rollout_percentage: Some(100.0), + variant: None, + }], + multivariate: None, + aggregation_group_type_index: None, + payloads: None, + super_groups: None, + }), + None, + None, + None, + ); + + let mut matcher = FeatureFlagMatcher::new( + "test_user".to_string(), + team.id, + postgres_reader.clone(), + postgres_writer.clone(), + cohort_cache.clone(), + None, + None, + ); + + let result = matcher.get_match(&flag, None, None).await.unwrap(); + + assert!(result.matches); + } + + #[tokio::test] + async fn test_not_in_cohort_matching() { + let postgres_reader = setup_pg_reader_client(None).await; + let postgres_writer = setup_pg_writer_client(None).await; + let cohort_cache = Arc::new(CohortCacheManager::new(postgres_reader.clone(), None, None)); + let team = insert_new_team_in_pg(postgres_reader.clone(), None) + .await + .unwrap(); + + // Insert a cohort with a condition that does not match the test user's properties + let cohort_row = insert_cohort_for_team_in_pg( + postgres_reader.clone(), + team.id, + None, + json!({ + "properties": { + "type": "OR", + "values": [{ + "type": "OR", + "values": [{ + "key": "$browser_version", + "type": "person", + "value": "130", + "negation": false, + "operator": "gt" + }] + }] + } + }), + false, + ) + .await + .unwrap(); + + // Insert a person with properties that do not match the cohort condition + insert_person_for_team_in_pg( + postgres_reader.clone(), + team.id, + "test_user".to_string(), + Some(json!({"$browser_version": 126})), + ) + .await + .unwrap(); + + // Define a flag with a NotIn cohort filter + let flag = create_test_flag( + None, + Some(team.id), + None, + None, + Some(FlagFilters { + groups: vec![FlagGroupType { + properties: Some(vec![PropertyFilter { + key: "id".to_string(), + value: json!(cohort_row.id), + operator: Some(OperatorType::NotIn), + prop_type: "cohort".to_string(), + group_type_index: None, + negation: Some(false), + }]), + rollout_percentage: Some(100.0), + variant: None, + }], + multivariate: None, + aggregation_group_type_index: None, + payloads: None, + super_groups: None, + }), + None, + None, + None, + ); + + let mut matcher = FeatureFlagMatcher::new( + "test_user".to_string(), + team.id, + postgres_reader.clone(), + postgres_writer.clone(), + cohort_cache.clone(), + None, + None, + ); + + let result = matcher.get_match(&flag, None, None).await.unwrap(); + + assert!(result.matches); + } + + #[tokio::test] + async fn test_not_in_cohort_matching_user_in_cohort() { + let postgres_reader = setup_pg_reader_client(None).await; + let postgres_writer = setup_pg_writer_client(None).await; + let cohort_cache = Arc::new(CohortCacheManager::new(postgres_reader.clone(), None, None)); + let team = insert_new_team_in_pg(postgres_reader.clone(), None) + .await + .unwrap(); + + // Insert a cohort with a condition that matches the test user's properties + let cohort_row = insert_cohort_for_team_in_pg( + postgres_reader.clone(), + team.id, + None, + json!({ + "properties": { + "type": "OR", + "values": [{ + "type": "OR", + "values": [{ + "key": "$browser_version", + "type": "person", + "value": "125", + "negation": false, + "operator": "gt" + }] + }] + } + }), + false, + ) + .await + .unwrap(); + + // Insert a person with properties that match the cohort condition + insert_person_for_team_in_pg( + postgres_reader.clone(), + team.id, + "test_user".to_string(), + Some(json!({"$browser_version": 126})), + ) + .await + .unwrap(); + + // Define a flag with a NotIn cohort filter + let flag = create_test_flag( + None, + Some(team.id), + None, + None, + Some(FlagFilters { + groups: vec![FlagGroupType { + properties: Some(vec![PropertyFilter { + key: "id".to_string(), + value: json!(cohort_row.id), + operator: Some(OperatorType::NotIn), + prop_type: "cohort".to_string(), + group_type_index: None, + negation: Some(false), + }]), + rollout_percentage: Some(100.0), + variant: None, + }], + multivariate: None, + aggregation_group_type_index: None, + payloads: None, + super_groups: None, + }), + None, + None, + None, + ); + + let mut matcher = FeatureFlagMatcher::new( + "test_user".to_string(), + team.id, + postgres_reader.clone(), + postgres_writer.clone(), + cohort_cache.clone(), + None, + None, + ); + + let result = matcher.get_match(&flag, None, None).await.unwrap(); + + // The user matches the cohort, but the flag is set to NotIn, so it should evaluate to false + assert!(!result.matches); + } + + #[tokio::test] + async fn test_cohort_dependent_on_another_cohort() { + let postgres_reader = setup_pg_reader_client(None).await; + let postgres_writer = setup_pg_writer_client(None).await; + let cohort_cache = Arc::new(CohortCacheManager::new(postgres_reader.clone(), None, None)); + let team = insert_new_team_in_pg(postgres_reader.clone(), None) + .await + .unwrap(); + + // Insert a base cohort + let base_cohort_row = insert_cohort_for_team_in_pg( + postgres_reader.clone(), + team.id, + None, + json!({ + "properties": { + "type": "OR", + "values": [{ + "type": "OR", + "values": [{ + "key": "$browser_version", + "type": "person", + "value": "125", + "negation": false, + "operator": "gt" + }] + }] + } + }), + false, + ) + .await + .unwrap(); + + // Insert a dependent cohort that includes the base cohort + let dependent_cohort_row = insert_cohort_for_team_in_pg( + postgres_reader.clone(), + team.id, + None, + json!({ + "properties": { + "type": "OR", + "values": [{ + "type": "OR", + "values": [{ + "key": "id", + "type": "cohort", + "value": base_cohort_row.id, + "negation": false, + "operator": "in" + }] + }] + } + }), + false, + ) + .await + .unwrap(); + + // Insert a person with properties that match the base cohort condition + insert_person_for_team_in_pg( + postgres_reader.clone(), + team.id, + "test_user".to_string(), + Some(json!({"$browser_version": 126})), + ) + .await + .unwrap(); + + // Define a flag with a cohort filter that depends on another cohort + let flag = create_test_flag( + None, + Some(team.id), + None, + None, + Some(FlagFilters { + groups: vec![FlagGroupType { + properties: Some(vec![PropertyFilter { + key: "id".to_string(), + value: json!(dependent_cohort_row.id), + operator: Some(OperatorType::In), + prop_type: "cohort".to_string(), + group_type_index: None, + negation: Some(false), + }]), + rollout_percentage: Some(100.0), + variant: None, + }], + multivariate: None, + aggregation_group_type_index: None, + payloads: None, + super_groups: None, + }), + None, + None, + None, + ); + + let mut matcher = FeatureFlagMatcher::new( + "test_user".to_string(), + team.id, + postgres_reader.clone(), + postgres_writer.clone(), + cohort_cache.clone(), + None, + None, + ); + + let result = matcher.get_match(&flag, None, None).await.unwrap(); + + assert!(result.matches); + } + + #[tokio::test] + async fn test_in_cohort_matching_user_not_in_cohort() { + let postgres_reader = setup_pg_reader_client(None).await; + let postgres_writer = setup_pg_writer_client(None).await; + let cohort_cache = Arc::new(CohortCacheManager::new(postgres_reader.clone(), None, None)); + let team = insert_new_team_in_pg(postgres_reader.clone(), None) + .await + .unwrap(); + + // Insert a cohort with a condition that does not match the test user's properties + let cohort_row = insert_cohort_for_team_in_pg( + postgres_reader.clone(), + team.id, + None, + json!({ + "properties": { + "type": "OR", + "values": [{ + "type": "OR", + "values": [{ + "key": "$browser_version", + "type": "person", + "value": "130", + "negation": false, + "operator": "gt" + }] + }] + } + }), + false, + ) + .await + .unwrap(); + + // Insert a person with properties that do not match the cohort condition + insert_person_for_team_in_pg( + postgres_reader.clone(), + team.id, + "test_user".to_string(), + Some(json!({"$browser_version": 125})), + ) + .await + .unwrap(); + + // Define a flag with an In cohort filter + let flag = create_test_flag( + None, + Some(team.id), + None, + None, + Some(FlagFilters { + groups: vec![FlagGroupType { + properties: Some(vec![PropertyFilter { + key: "id".to_string(), + value: json!(cohort_row.id), + operator: Some(OperatorType::In), + prop_type: "cohort".to_string(), + group_type_index: None, + negation: Some(false), + }]), + rollout_percentage: Some(100.0), + variant: None, + }], + multivariate: None, + aggregation_group_type_index: None, + payloads: None, + super_groups: None, + }), + None, + None, + None, + ); + + let mut matcher = FeatureFlagMatcher::new( + "test_user".to_string(), + team.id, + postgres_reader.clone(), + postgres_writer.clone(), + cohort_cache.clone(), + None, + None, + ); + + let result = matcher.get_match(&flag, None, None).await.unwrap(); + + // The user does not match the cohort, and the flag is set to In, so it should evaluate to false + assert!(!result.matches); + } + #[tokio::test] async fn test_set_feature_flag_hash_key_overrides_success() { let postgres_reader = setup_pg_reader_client(None).await; @@ -3123,7 +3859,7 @@ mod tests { let team = insert_new_team_in_pg(postgres_reader.clone(), None) .await .unwrap(); - let distinct_id = "user1".to_string(); + let distinct_id = "user2".to_string(); // Insert person insert_person_for_team_in_pg(postgres_reader.clone(), team.id, distinct_id.clone(), None) @@ -3148,7 +3884,7 @@ mod tests { Some(true), // ensure_experience_continuity ); - // need to convert flag to FeatureFlagRow + // Convert flag to FeatureFlagRow let flag_row = FeatureFlagRow { id: flag.id, team_id: flag.team_id, @@ -3165,8 +3901,8 @@ mod tests { .await .unwrap(); - // Attempt to set hash key override - let result = set_feature_flag_hash_key_overrides( + // Set hash key override + set_feature_flag_hash_key_overrides( postgres_writer.clone(), team.id, vec![distinct_id.clone()], @@ -3175,9 +3911,7 @@ mod tests { .await .unwrap(); - assert!(result, "Hash key override should be set successfully"); - - // Retrieve the hash key overrides + // Retrieve hash key overrides let overrides = get_feature_flag_hash_key_overrides( postgres_reader.clone(), team.id, @@ -3186,14 +3920,10 @@ mod tests { .await .unwrap(); - assert!( - !overrides.is_empty(), - "At least one hash key override should be set" - ); assert_eq!( overrides.get("test_flag"), Some(&"hash_key_2".to_string()), - "Hash key override for 'test_flag' should match the set value" + "Hash key override should match the set value" ); } @@ -3271,10 +4001,12 @@ mod tests { "Hash key override should match the set value" ); } + #[tokio::test] async fn test_evaluate_feature_flags_with_experience_continuity() { let postgres_reader = setup_pg_reader_client(None).await; let postgres_writer = setup_pg_writer_client(None).await; + let cohort_cache = Arc::new(CohortCacheManager::new(postgres_reader.clone(), None, None)); let team = insert_new_team_in_pg(postgres_reader.clone(), None) .await .unwrap(); @@ -3304,6 +4036,7 @@ mod tests { operator: None, prop_type: "person".to_string(), group_type_index: None, + negation: None, }]), rollout_percentage: Some(100.0), variant: None, @@ -3337,7 +4070,7 @@ mod tests { team.id, postgres_reader.clone(), postgres_writer.clone(), - None, + cohort_cache.clone(), None, None, ) @@ -3356,6 +4089,7 @@ mod tests { async fn test_evaluate_feature_flags_with_continuity_missing_override() { let postgres_reader = setup_pg_reader_client(None).await; let postgres_writer = setup_pg_writer_client(None).await; + let cohort_cache = Arc::new(CohortCacheManager::new(postgres_reader.clone(), None, None)); let team = insert_new_team_in_pg(postgres_reader.clone(), None) .await .unwrap(); @@ -3385,6 +4119,7 @@ mod tests { operator: None, prop_type: "person".to_string(), group_type_index: None, + negation: None, }]), rollout_percentage: Some(100.0), variant: None, @@ -3408,7 +4143,7 @@ mod tests { team.id, postgres_reader.clone(), postgres_writer.clone(), - None, + cohort_cache.clone(), None, None, ) @@ -3427,6 +4162,7 @@ mod tests { async fn test_evaluate_all_feature_flags_mixed_continuity() { let postgres_reader = setup_pg_reader_client(None).await; let postgres_writer = setup_pg_writer_client(None).await; + let cohort_cache = Arc::new(CohortCacheManager::new(postgres_reader.clone(), None, None)); let team = insert_new_team_in_pg(postgres_reader.clone(), None) .await .unwrap(); @@ -3456,6 +4192,7 @@ mod tests { operator: None, prop_type: "person".to_string(), group_type_index: None, + negation: None, }]), rollout_percentage: Some(100.0), variant: None, @@ -3484,6 +4221,7 @@ mod tests { operator: Some(OperatorType::Gt), prop_type: "person".to_string(), group_type_index: None, + negation: None, }]), rollout_percentage: Some(100.0), variant: None, @@ -3517,7 +4255,7 @@ mod tests { team.id, postgres_reader.clone(), postgres_writer.clone(), - None, + cohort_cache.clone(), None, None, ) diff --git a/rust/feature-flags/src/flag_request.rs b/rust/feature-flags/src/flag_request.rs index 771c216834c..1cf64eb879a 100644 --- a/rust/feature-flags/src/flag_request.rs +++ b/rust/feature-flags/src/flag_request.rs @@ -158,8 +158,8 @@ impl FlagRequest { pub async fn get_flags_from_cache_or_pg( &self, team_id: i32, - redis_client: Arc, - pg_client: Arc, + redis_client: &Arc, + pg_client: &Arc, ) -> Result { let mut cache_hit = false; let flags = match FeatureFlagList::from_redis(redis_client.clone(), team_id).await { @@ -167,10 +167,14 @@ impl FlagRequest { cache_hit = true; Ok(flags) } - Err(_) => match FeatureFlagList::from_pg(pg_client, team_id).await { + Err(_) => match FeatureFlagList::from_pg(pg_client.clone(), team_id).await { Ok(flags) => { - if let Err(e) = - FeatureFlagList::update_flags_in_redis(redis_client, team_id, &flags).await + if let Err(e) = FeatureFlagList::update_flags_in_redis( + redis_client.clone(), + team_id, + &flags, + ) + .await { tracing::warn!("Failed to update Redis cache: {}", e); // TODO add new metric category for this @@ -206,7 +210,6 @@ mod tests { TEAM_FLAGS_CACHE_PREFIX, }; use crate::flag_request::FlagRequest; - use crate::redis::Client as RedisClient; use crate::team::Team; use crate::test_utils::{insert_new_team_in_redis, setup_pg_reader_client, setup_redis_client}; use bytes::Bytes; @@ -360,6 +363,7 @@ mod tests { operator: Some(OperatorType::Exact), prop_type: "person".to_string(), group_type_index: None, + negation: None, }]), rollout_percentage: Some(50.0), variant: None, @@ -402,6 +406,7 @@ mod tests { operator: Some(OperatorType::Exact), prop_type: "person".to_string(), group_type_index: None, + negation: None, }]), rollout_percentage: Some(100.0), variant: None, @@ -426,7 +431,7 @@ mod tests { // Test fetching from Redis let result = flag_request - .get_flags_from_cache_or_pg(team.id, redis_client.clone(), pg_client.clone()) + .get_flags_from_cache_or_pg(team.id, &redis_client, &pg_client) .await; assert!(result.is_ok()); let fetched_flags = result.unwrap(); @@ -483,7 +488,7 @@ mod tests { .expect("Failed to remove flags from Redis"); let result = flag_request - .get_flags_from_cache_or_pg(team.id, redis_client.clone(), pg_client.clone()) + .get_flags_from_cache_or_pg(team.id, &redis_client, &pg_client) .await; assert!(result.is_ok()); // Verify that the flags were re-added to Redis diff --git a/rust/feature-flags/src/lib.rs b/rust/feature-flags/src/lib.rs index 051b3e27697..67659bfcf9d 100644 --- a/rust/feature-flags/src/lib.rs +++ b/rust/feature-flags/src/lib.rs @@ -1,4 +1,7 @@ pub mod api; +pub mod cohort_cache; +pub mod cohort_models; +pub mod cohort_operations; pub mod config; pub mod database; pub mod feature_flag_match_reason; @@ -8,13 +11,13 @@ pub mod flag_matching; pub mod flag_request; pub mod geoip; pub mod metrics_consts; +pub mod metrics_utils; pub mod property_matching; pub mod redis; pub mod request_handler; pub mod router; pub mod server; pub mod team; -pub mod utils; pub mod v0_endpoint; // Test modules don't need to be compiled with main binary diff --git a/rust/feature-flags/src/utils.rs b/rust/feature-flags/src/metrics_utils.rs similarity index 100% rename from rust/feature-flags/src/utils.rs rename to rust/feature-flags/src/metrics_utils.rs diff --git a/rust/feature-flags/src/property_matching.rs b/rust/feature-flags/src/property_matching.rs index 8d12fe6ab5e..84479f13161 100644 --- a/rust/feature-flags/src/property_matching.rs +++ b/rust/feature-flags/src/property_matching.rs @@ -44,7 +44,7 @@ pub fn match_property( } let key = &property.key; - let operator = property.operator.clone().unwrap_or(OperatorType::Exact); + let operator = property.operator.unwrap_or(OperatorType::Exact); let value = &property.value; let match_value = matching_property_values.get(key); @@ -193,6 +193,12 @@ pub fn match_property( // Ok(false) // } } + OperatorType::In | OperatorType::NotIn => { + // TODO: we handle these in cohort matching, so we can just return false here + // because by the time we match properties, we've already decomposed the cohort + // filter into multiple property filters + Ok(false) + } } } @@ -260,6 +266,7 @@ mod test_match_properties { operator: None, prop_type: "person".to_string(), group_type_index: None, + negation: None, }; assert!(match_property( @@ -313,6 +320,7 @@ mod test_match_properties { operator: Some(OperatorType::Exact), prop_type: "person".to_string(), group_type_index: None, + negation: None, }; assert!(match_property( @@ -335,6 +343,7 @@ mod test_match_properties { operator: Some(OperatorType::Exact), prop_type: "person".to_string(), group_type_index: None, + negation: None, }; assert!(match_property( @@ -379,6 +388,7 @@ mod test_match_properties { operator: Some(OperatorType::IsNot), prop_type: "person".to_string(), group_type_index: None, + negation: None, }; assert!(match_property( @@ -416,6 +426,7 @@ mod test_match_properties { operator: Some(OperatorType::IsNot), prop_type: "person".to_string(), group_type_index: None, + negation: None, }; assert!(match_property( @@ -490,6 +501,7 @@ mod test_match_properties { operator: Some(OperatorType::IsSet), prop_type: "person".to_string(), group_type_index: None, + negation: None, }; assert!(match_property( @@ -538,6 +550,7 @@ mod test_match_properties { operator: Some(OperatorType::Icontains), prop_type: "person".to_string(), group_type_index: None, + negation: None, }; assert!(match_property( @@ -595,6 +608,7 @@ mod test_match_properties { operator: Some(OperatorType::Icontains), prop_type: "person".to_string(), group_type_index: None, + negation: None, }; assert!(match_property( @@ -634,6 +648,7 @@ mod test_match_properties { operator: Some(OperatorType::Regex), prop_type: "person".to_string(), group_type_index: None, + negation: None, }; assert!(match_property( @@ -674,6 +689,7 @@ mod test_match_properties { operator: Some(OperatorType::Regex), prop_type: "person".to_string(), group_type_index: None, + negation: None, }; assert!(match_property( &property_b, @@ -708,6 +724,7 @@ mod test_match_properties { operator: Some(OperatorType::Regex), prop_type: "person".to_string(), group_type_index: None, + negation: None, }; assert!(!match_property( @@ -730,6 +747,7 @@ mod test_match_properties { operator: Some(OperatorType::Regex), prop_type: "person".to_string(), group_type_index: None, + negation: None, }; assert!(match_property( &property_d, @@ -760,6 +778,7 @@ mod test_match_properties { operator: Some(OperatorType::Gt), prop_type: "person".to_string(), group_type_index: None, + negation: None, }; assert!(match_property( @@ -802,6 +821,7 @@ mod test_match_properties { operator: Some(OperatorType::Lt), prop_type: "person".to_string(), group_type_index: None, + negation: None, }; assert!(match_property( @@ -848,6 +868,7 @@ mod test_match_properties { operator: Some(OperatorType::Gte), prop_type: "person".to_string(), group_type_index: None, + negation: None, }; assert!(match_property( @@ -889,6 +910,7 @@ mod test_match_properties { operator: Some(OperatorType::Lt), prop_type: "person".to_string(), group_type_index: None, + negation: None, }; assert!(match_property( @@ -935,6 +957,7 @@ mod test_match_properties { operator: Some(OperatorType::Lt), prop_type: "person".to_string(), group_type_index: None, + negation: None, }; assert!(match_property( @@ -1013,6 +1036,7 @@ mod test_match_properties { operator: Some(OperatorType::IsNot), prop_type: "person".to_string(), group_type_index: None, + negation: None, }; assert!(!match_property( @@ -1034,6 +1058,7 @@ mod test_match_properties { operator: Some(OperatorType::IsSet), prop_type: "person".to_string(), group_type_index: None, + negation: None, }; assert!(match_property( @@ -1049,6 +1074,7 @@ mod test_match_properties { operator: Some(OperatorType::Icontains), prop_type: "person".to_string(), group_type_index: None, + negation: None, }; assert!(match_property( @@ -1070,6 +1096,7 @@ mod test_match_properties { operator: Some(OperatorType::Regex), prop_type: "person".to_string(), group_type_index: None, + negation: None, }; assert!(!match_property( @@ -1085,6 +1112,7 @@ mod test_match_properties { operator: Some(OperatorType::Regex), prop_type: "person".to_string(), group_type_index: None, + negation: None, }; assert!(!match_property( @@ -1118,6 +1146,7 @@ mod test_match_properties { operator: None, prop_type: "person".to_string(), group_type_index: None, + negation: None, }; assert!(!match_property( @@ -1137,6 +1166,7 @@ mod test_match_properties { operator: Some(OperatorType::Exact), prop_type: "person".to_string(), group_type_index: None, + negation: None, }; assert!(!match_property( @@ -1152,6 +1182,7 @@ mod test_match_properties { operator: Some(OperatorType::IsSet), prop_type: "person".to_string(), group_type_index: None, + negation: None, }; assert!(!match_property( @@ -1167,6 +1198,7 @@ mod test_match_properties { operator: Some(OperatorType::IsNotSet), prop_type: "person".to_string(), group_type_index: None, + negation: None, }; assert!(match_property( @@ -1203,6 +1235,7 @@ mod test_match_properties { operator: Some(OperatorType::Icontains), prop_type: "person".to_string(), group_type_index: None, + negation: None, }; assert!(!match_property( @@ -1218,6 +1251,7 @@ mod test_match_properties { operator: Some(OperatorType::NotIcontains), prop_type: "person".to_string(), group_type_index: None, + negation: None, }; assert!(!match_property( @@ -1233,6 +1267,7 @@ mod test_match_properties { operator: Some(OperatorType::Regex), prop_type: "person".to_string(), group_type_index: None, + negation: None, }; assert!(!match_property( @@ -1248,6 +1283,7 @@ mod test_match_properties { operator: Some(OperatorType::NotRegex), prop_type: "person".to_string(), group_type_index: None, + negation: None, }; assert!(!match_property( @@ -1263,6 +1299,7 @@ mod test_match_properties { operator: Some(OperatorType::Gt), prop_type: "person".to_string(), group_type_index: None, + negation: None, }; assert!(!match_property( @@ -1278,6 +1315,7 @@ mod test_match_properties { operator: Some(OperatorType::Gte), prop_type: "person".to_string(), group_type_index: None, + negation: None, }; assert!(!match_property( @@ -1293,6 +1331,7 @@ mod test_match_properties { operator: Some(OperatorType::Lt), prop_type: "person".to_string(), group_type_index: None, + negation: None, }; assert!(!match_property( @@ -1308,6 +1347,7 @@ mod test_match_properties { operator: Some(OperatorType::Lte), prop_type: "person".to_string(), group_type_index: None, + negation: None, }; assert!(!match_property( @@ -1324,6 +1364,7 @@ mod test_match_properties { operator: Some(OperatorType::IsDateBefore), prop_type: "person".to_string(), group_type_index: None, + negation: None, }; assert!(!match_property( diff --git a/rust/feature-flags/src/request_handler.rs b/rust/feature-flags/src/request_handler.rs index 5e0be8faacc..538c6845d2a 100644 --- a/rust/feature-flags/src/request_handler.rs +++ b/rust/feature-flags/src/request_handler.rs @@ -1,5 +1,6 @@ use crate::{ api::{FlagError, FlagsResponse}, + cohort_cache::CohortCacheManager, database::Client, flag_definitions::FeatureFlagList, flag_matching::{FeatureFlagMatcher, GroupTypeMappingCache}, @@ -69,6 +70,7 @@ pub struct FeatureFlagEvaluationContext { feature_flags: FeatureFlagList, postgres_reader: Arc, postgres_writer: Arc, + cohort_cache: Arc, #[builder(default)] person_property_overrides: Option>, #[builder(default)] @@ -108,18 +110,16 @@ pub async fn process_request(context: RequestContext) -> Result = state.postgres_reader.clone(); - let postgres_writer_dyn: Arc = state.postgres_writer.clone(); - let evaluation_context = FeatureFlagEvaluationContextBuilder::default() .team_id(team_id) .distinct_id(distinct_id) .feature_flags(feature_flags_from_cache_or_pg) - .postgres_reader(postgres_reader_dyn) - .postgres_writer(postgres_writer_dyn) + .postgres_reader(state.postgres_reader.clone()) + .postgres_writer(state.postgres_writer.clone()) + .cohort_cache(state.cohort_cache.clone()) .person_property_overrides(person_property_overrides) .group_property_overrides(group_property_overrides) .groups(groups) @@ -224,8 +224,8 @@ pub async fn evaluate_feature_flags(context: FeatureFlagEvaluationContext) -> Fl context.team_id, context.postgres_reader, context.postgres_writer, + context.cohort_cache, Some(group_type_mapping_cache), - None, // TODO maybe remove this from the matcher struct, since it's used internally but not passed around context.groups, ); feature_flag_matcher @@ -359,6 +359,7 @@ mod tests { async fn test_evaluate_feature_flags() { let postgres_reader: Arc = setup_pg_reader_client(None).await; let postgres_writer: Arc = setup_pg_writer_client(None).await; + let cohort_cache = Arc::new(CohortCacheManager::new(postgres_reader.clone(), None, None)); let flag = FeatureFlag { name: Some("Test Flag".to_string()), id: 1, @@ -374,6 +375,7 @@ mod tests { operator: Some(OperatorType::Exact), prop_type: "person".to_string(), group_type_index: None, + negation: None, }]), rollout_percentage: Some(100.0), // Set to 100% to ensure it's always on variant: None, @@ -397,6 +399,7 @@ mod tests { .feature_flags(feature_flag_list) .postgres_reader(postgres_reader) .postgres_writer(postgres_writer) + .cohort_cache(cohort_cache) .person_property_overrides(Some(person_properties)) .build() .expect("Failed to build FeatureFlagEvaluationContext"); @@ -505,6 +508,7 @@ mod tests { async fn test_evaluate_feature_flags_multiple_flags() { let postgres_reader: Arc = setup_pg_reader_client(None).await; let postgres_writer: Arc = setup_pg_writer_client(None).await; + let cohort_cache = Arc::new(CohortCacheManager::new(postgres_reader.clone(), None, None)); let flags = vec![ FeatureFlag { name: Some("Flag 1".to_string()), @@ -556,6 +560,7 @@ mod tests { .feature_flags(feature_flag_list) .postgres_reader(postgres_reader) .postgres_writer(postgres_writer) + .cohort_cache(cohort_cache) .build() .expect("Failed to build FeatureFlagEvaluationContext"); @@ -608,6 +613,7 @@ mod tests { async fn test_evaluate_feature_flags_with_overrides() { let postgres_reader: Arc = setup_pg_reader_client(None).await; let postgres_writer: Arc = setup_pg_writer_client(None).await; + let cohort_cache = Arc::new(CohortCacheManager::new(postgres_reader.clone(), None, None)); let team = insert_new_team_in_pg(postgres_reader.clone(), None) .await .unwrap(); @@ -627,6 +633,7 @@ mod tests { operator: Some(OperatorType::Exact), prop_type: "group".to_string(), group_type_index: Some(0), + negation: None, }]), rollout_percentage: Some(100.0), variant: None, @@ -655,6 +662,7 @@ mod tests { .feature_flags(feature_flag_list) .postgres_reader(postgres_reader) .postgres_writer(postgres_writer) + .cohort_cache(cohort_cache) .group_property_overrides(Some(group_property_overrides)) .groups(Some(groups)) .build() @@ -688,6 +696,7 @@ mod tests { let long_id = "a".repeat(1000); let postgres_reader: Arc = setup_pg_reader_client(None).await; let postgres_writer: Arc = setup_pg_writer_client(None).await; + let cohort_cache = Arc::new(CohortCacheManager::new(postgres_reader.clone(), None, None)); let flag = FeatureFlag { name: Some("Test Flag".to_string()), id: 1, @@ -717,6 +726,7 @@ mod tests { .feature_flags(feature_flag_list) .postgres_reader(postgres_reader) .postgres_writer(postgres_writer) + .cohort_cache(cohort_cache) .build() .expect("Failed to build FeatureFlagEvaluationContext"); diff --git a/rust/feature-flags/src/router.rs b/rust/feature-flags/src/router.rs index 505f18adfb0..e34ea31a3c6 100644 --- a/rust/feature-flags/src/router.rs +++ b/rust/feature-flags/src/router.rs @@ -9,11 +9,12 @@ use health::HealthRegistry; use tower::limit::ConcurrencyLimitLayer; use crate::{ + cohort_cache::CohortCacheManager, config::{Config, TeamIdsToTrack}, database::Client as DatabaseClient, geoip::GeoIpClient, + metrics_utils::team_id_label_filter, redis::Client as RedisClient, - utils::team_id_label_filter, v0_endpoint, }; @@ -22,6 +23,7 @@ pub struct State { pub redis: Arc, pub postgres_reader: Arc, pub postgres_writer: Arc, + pub cohort_cache: Arc, // TODO does this need a better name than just `cohort_cache`? pub geoip: Arc, pub team_ids_to_track: TeamIdsToTrack, } @@ -30,6 +32,7 @@ pub fn router( redis: Arc, postgres_reader: Arc, postgres_writer: Arc, + cohort_cache: Arc, geoip: Arc, liveness: HealthRegistry, config: Config, @@ -42,6 +45,7 @@ where redis, postgres_reader, postgres_writer, + cohort_cache, geoip, team_ids_to_track: config.team_ids_to_track.clone(), }; diff --git a/rust/feature-flags/src/server.rs b/rust/feature-flags/src/server.rs index c9e238fa8fd..69ff759ddfc 100644 --- a/rust/feature-flags/src/server.rs +++ b/rust/feature-flags/src/server.rs @@ -6,6 +6,7 @@ use std::time::Duration; use health::{HealthHandle, HealthRegistry}; use tokio::net::TcpListener; +use crate::cohort_cache::CohortCacheManager; use crate::config::Config; use crate::database::get_pool; use crate::geoip::GeoIpClient; @@ -54,6 +55,8 @@ where } }; + let cohort_cache = Arc::new(CohortCacheManager::new(postgres_reader.clone(), None, None)); + let health = HealthRegistry::new("liveness"); // TODO - we don't have a more complex health check yet, but we should add e.g. some around DB operations @@ -67,6 +70,7 @@ where redis_client, postgres_reader, postgres_writer, + cohort_cache, geoip_service, health, config, diff --git a/rust/feature-flags/src/team.rs b/rust/feature-flags/src/team.rs index 0fa75f0bd3d..f13cf29094b 100644 --- a/rust/feature-flags/src/team.rs +++ b/rust/feature-flags/src/team.rs @@ -42,7 +42,7 @@ impl Team { // TODO: Consider an LRU cache for teams as well, with small TTL to skip redis/pg lookups let team: Team = serde_json::from_str(&serialized_team).map_err(|e| { tracing::error!("failed to parse data to team: {}", e); - FlagError::DataParsingError + FlagError::RedisDataParsingError })?; Ok(team) @@ -55,7 +55,7 @@ impl Team { ) -> Result<(), FlagError> { let serialized_team = serde_json::to_string(&team).map_err(|e| { tracing::error!("Failed to serialize team: {}", e); - FlagError::DataParsingError + FlagError::RedisDataParsingError })?; client @@ -173,7 +173,7 @@ mod tests { let client = setup_redis_client(None); match Team::from_redis(client.clone(), team.api_token.clone()).await { - Err(FlagError::DataParsingError) => (), + Err(FlagError::RedisDataParsingError) => (), Err(other) => panic!("Expected DataParsingError, got {:?}", other), Ok(_) => panic!("Expected DataParsingError"), }; diff --git a/rust/feature-flags/src/test_utils.rs b/rust/feature-flags/src/test_utils.rs index 32a2016bf75..22f7753d979 100644 --- a/rust/feature-flags/src/test_utils.rs +++ b/rust/feature-flags/src/test_utils.rs @@ -1,11 +1,12 @@ use anyhow::Error; use axum::async_trait; use serde_json::{json, Value}; -use sqlx::{pool::PoolConnection, postgres::PgRow, Error as SqlxError, PgPool, Postgres}; +use sqlx::{pool::PoolConnection, postgres::PgRow, Error as SqlxError, Postgres}; use std::sync::Arc; use uuid::Uuid; use crate::{ + cohort_models::Cohort, config::{Config, DEFAULT_TEST_CONFIG}, database::{get_pool, Client, CustomDatabaseError}, flag_definitions::{self, FeatureFlag, FeatureFlagRow}, @@ -23,7 +24,9 @@ pub fn random_string(prefix: &str, length: usize) -> String { format!("{}{}", prefix, suffix) } -pub async fn insert_new_team_in_redis(client: Arc) -> Result { +pub async fn insert_new_team_in_redis( + client: Arc, +) -> Result { let id = rand::thread_rng().gen_range(0..10_000_000); let token = random_string("phc_", 12); let team = Team { @@ -48,7 +51,7 @@ pub async fn insert_new_team_in_redis(client: Arc) -> Result, + client: Arc, team_id: i32, json_value: Option, ) -> Result<(), Error> { @@ -88,7 +91,7 @@ pub async fn insert_flags_for_team_in_redis( Ok(()) } -pub fn setup_redis_client(url: Option) -> Arc { +pub fn setup_redis_client(url: Option) -> Arc { let redis_url = match url { Some(value) => value, None => "redis://localhost:6379/".to_string(), @@ -130,7 +133,7 @@ pub fn create_flag_from_json(json_value: Option) -> Vec { flags } -pub async fn setup_pg_reader_client(config: Option<&Config>) -> Arc { +pub async fn setup_pg_reader_client(config: Option<&Config>) -> Arc { let config = config.unwrap_or(&DEFAULT_TEST_CONFIG); Arc::new( get_pool(&config.read_database_url, config.max_pg_connections) @@ -139,7 +142,7 @@ pub async fn setup_pg_reader_client(config: Option<&Config>) -> Arc { ) } -pub async fn setup_pg_writer_client(config: Option<&Config>) -> Arc { +pub async fn setup_pg_writer_client(config: Option<&Config>) -> Arc { let config = config.unwrap_or(&DEFAULT_TEST_CONFIG); Arc::new( get_pool(&config.write_database_url, config.max_pg_connections) @@ -261,7 +264,7 @@ pub async fn insert_new_team_in_pg( } pub async fn insert_flag_for_team_in_pg( - client: Arc, + client: Arc, team_id: i32, flag: Option, ) -> Result { @@ -310,7 +313,7 @@ pub async fn insert_flag_for_team_in_pg( } pub async fn insert_person_for_team_in_pg( - client: Arc, + client: Arc, team_id: i32, distinct_id: String, properties: Option, @@ -352,3 +355,58 @@ pub async fn insert_person_for_team_in_pg( Ok(()) } + +pub async fn insert_cohort_for_team_in_pg( + client: Arc, + team_id: i32, + name: Option, + filters: serde_json::Value, + is_static: bool, +) -> Result { + let cohort = Cohort { + id: 0, // Placeholder, will be updated after insertion + name: name.unwrap_or("Test Cohort".to_string()), + description: Some("Description for cohort".to_string()), + team_id, + deleted: false, + filters, + query: None, + version: Some(1), + pending_version: None, + count: None, + is_calculating: false, + is_static, + errors_calculating: 0, + groups: serde_json::json!([]), + created_by_id: None, + }; + + let mut conn = client.get_connection().await?; + let row: (i32,) = sqlx::query_as( + r#"INSERT INTO posthog_cohort + (name, description, team_id, deleted, filters, query, version, pending_version, count, is_calculating, is_static, errors_calculating, groups, created_by_id) VALUES + ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14) + RETURNING id"#, + ) + .bind(&cohort.name) + .bind(&cohort.description) + .bind(cohort.team_id) + .bind(cohort.deleted) + .bind(&cohort.filters) + .bind(&cohort.query) + .bind(cohort.version) + .bind(cohort.pending_version) + .bind(cohort.count) + .bind(cohort.is_calculating) + .bind(cohort.is_static) + .bind(cohort.errors_calculating) + .bind(&cohort.groups) + .bind(cohort.created_by_id) + .fetch_one(&mut *conn) + .await?; + + // Update the cohort_row with the actual id generated by sqlx + let id = row.0; + + Ok(Cohort { id, ..cohort }) +} diff --git a/rust/feature-flags/tests/test_flag_matching_consistency.rs b/rust/feature-flags/tests/test_flag_matching_consistency.rs index 94f4f67dcdc..c632d28bc15 100644 --- a/rust/feature-flags/tests/test_flag_matching_consistency.rs +++ b/rust/feature-flags/tests/test_flag_matching_consistency.rs @@ -1,3 +1,6 @@ +use std::sync::Arc; + +use feature_flags::cohort_cache::CohortCacheManager; use feature_flags::feature_flag_match_reason::FeatureFlagMatchReason; /// These tests are common between all libraries doing local evaluation of feature flags. /// This ensures there are no mismatches between implementations. @@ -110,6 +113,7 @@ async fn it_is_consistent_with_rollout_calculation_for_simple_flags() { for (i, result) in results.iter().enumerate().take(1000) { let postgres_reader = setup_pg_reader_client(None).await; let postgres_writer = setup_pg_writer_client(None).await; + let cohort_cache = Arc::new(CohortCacheManager::new(postgres_reader.clone(), None, None)); let distinct_id = format!("distinct_id_{}", i); @@ -118,7 +122,7 @@ async fn it_is_consistent_with_rollout_calculation_for_simple_flags() { 1, postgres_reader, postgres_writer, - None, + cohort_cache, None, None, ) @@ -1209,6 +1213,7 @@ async fn it_is_consistent_with_rollout_calculation_for_multivariate_flags() { for (i, result) in results.iter().enumerate().take(1000) { let postgres_reader = setup_pg_reader_client(None).await; let postgres_writer = setup_pg_writer_client(None).await; + let cohort_cache = Arc::new(CohortCacheManager::new(postgres_reader.clone(), None, None)); let distinct_id = format!("distinct_id_{}", i); let feature_flag_match = FeatureFlagMatcher::new( @@ -1216,7 +1221,7 @@ async fn it_is_consistent_with_rollout_calculation_for_multivariate_flags() { 1, postgres_reader, postgres_writer, - None, + cohort_cache, None, None, ) From f5a567f01a730dce04d09a945e47d7f849dd082b Mon Sep 17 00:00:00 2001 From: Dylan Martin Date: Sat, 16 Nov 2024 01:02:43 +0100 Subject: [PATCH 08/11] feat(flags): add support for matching static cohort membership (#25942) --- rust/feature-flags/src/api.rs | 5 + rust/feature-flags/src/flag_matching.rs | 647 +++++++++++++++++++--- rust/feature-flags/src/request_handler.rs | 1 + rust/feature-flags/src/test_utils.rs | 62 ++- 4 files changed, 636 insertions(+), 79 deletions(-) diff --git a/rust/feature-flags/src/api.rs b/rust/feature-flags/src/api.rs index 9d6b649719b..be21c1c37f5 100644 --- a/rust/feature-flags/src/api.rs +++ b/rust/feature-flags/src/api.rs @@ -108,6 +108,8 @@ pub enum FlagError { CohortFiltersParsingError, #[error("Cohort dependency cycle")] CohortDependencyCycle(String), + #[error("Person not found")] + PersonNotFound, } impl IntoResponse for FlagError { @@ -212,6 +214,9 @@ impl IntoResponse for FlagError { tracing::error!("Cohort dependency cycle: {}", msg); (StatusCode::BAD_REQUEST, msg) } + FlagError::PersonNotFound => { + (StatusCode::BAD_REQUEST, "Person not found. Please check your distinct_id and try again.".to_string()) + } } .into_response() } diff --git a/rust/feature-flags/src/flag_matching.rs b/rust/feature-flags/src/flag_matching.rs index 571fe9c84b4..d9332fce4e4 100644 --- a/rust/feature-flags/src/flag_matching.rs +++ b/rust/feature-flags/src/flag_matching.rs @@ -15,7 +15,7 @@ use petgraph::algo::{is_cyclic_directed, toposort}; use petgraph::graph::DiGraph; use serde_json::Value; use sha1::{Digest, Sha1}; -use sqlx::{postgres::PgQueryResult, Acquire, FromRow}; +use sqlx::{postgres::PgQueryResult, Acquire, FromRow, Row}; use std::fmt::Write; use std::sync::Arc; use std::{ @@ -26,6 +26,7 @@ use tokio::time::{sleep, timeout}; use tracing::{error, info}; pub type TeamId = i32; +pub type PersonId = i32; pub type GroupTypeIndex = i32; pub type PostgresReader = Arc; pub type PostgresWriter = Arc; @@ -176,6 +177,7 @@ impl GroupTypeMappingCache { /// to fetch the properties from the DB each time. #[derive(Clone, Default, Debug)] pub struct PropertiesCache { + person_id: Option, person_properties: Option>, group_properties: HashMap>, } @@ -217,9 +219,18 @@ impl FeatureFlagMatcher { } } - /// Evaluate feature flags for a given distinct_id - /// - Returns a map of feature flag keys to their values - /// - If an error occurs while evaluating a flag, it will be logged and the flag will be omitted from the result + /// Evaluates all feature flags for the current matcher context. + /// + /// ## Arguments + /// + /// * `feature_flags` - The list of feature flags to evaluate. + /// * `person_property_overrides` - Any overrides for person properties. + /// * `group_property_overrides` - Any overrides for group properties. + /// * `hash_key_override` - Optional hash key overrides for experience continuity. + /// + /// ## Returns + /// + /// * `FlagsResponse` - The result containing flag evaluations and any errors. pub async fn evaluate_all_feature_flags( &mut self, feature_flags: FeatureFlagList, @@ -746,22 +757,29 @@ impl FeatureFlagMatcher { .partition(|prop| prop.is_cohort()); // Get the properties we need to check for in this condition match from the flag + any overrides - let target_properties = self + let person_or_group_properties = self .get_properties_to_check(feature_flag, property_overrides, &non_cohort_filters) .await?; // Evaluate non-cohort filters first, since they're cheaper to evaluate and we can return early if they don't match - if !all_properties_match(&non_cohort_filters, &target_properties) { + if !all_properties_match(&non_cohort_filters, &person_or_group_properties) { return Ok((false, FeatureFlagMatchReason::NoConditionMatch)); } // Evaluate cohort filters, if any. - if !cohort_filters.is_empty() - && !self - .evaluate_cohort_filters(&cohort_filters, &target_properties) + if !cohort_filters.is_empty() { + // Get the person ID for the current distinct ID – this value should be cached at this point, but as a fallback we fetch from the database + let person_id = self.get_person_id().await?; + if !self + .evaluate_cohort_filters( + &cohort_filters, + &person_or_group_properties, + person_id, + ) .await? - { - return Ok((false, FeatureFlagMatchReason::NoConditionMatch)); + { + return Ok((false, FeatureFlagMatchReason::NoConditionMatch)); + } } } @@ -809,6 +827,31 @@ impl FeatureFlagMatcher { } } + /// Retrieves the `PersonId` from the properties cache. + /// If the cache does not contain a `PersonId`, it fetches it from the database + /// and updates the cache accordingly. + async fn get_person_id(&mut self) -> Result { + match self.properties_cache.person_id { + Some(id) => Ok(id), + None => { + let id = self.get_person_id_from_db().await?; + self.properties_cache.person_id = Some(id); + Ok(id) + } + } + } + + /// Fetches the `PersonId` from the database based on the current `distinct_id` and `team_id`. + /// This method is called when the `PersonId` is not present in the properties cache. + async fn get_person_id_from_db(&mut self) -> Result { + let postgres_reader = self.postgres_reader.clone(); + let distinct_id = self.distinct_id.clone(); + let team_id = self.team_id; + fetch_person_properties_from_db(postgres_reader, distinct_id, team_id) + .await + .map(|(_, person_id)| person_id) + } + /// Get person properties from cache or database. /// /// This function attempts to retrieve person properties either from a cache or directly from the database. @@ -836,26 +879,45 @@ impl FeatureFlagMatcher { &self, cohort_property_filters: &[PropertyFilter], target_properties: &HashMap, + person_id: PersonId, ) -> Result { // At the start of the request, fetch all of the cohorts for the team from the cache - // This method also caches the cohorts in memory for the duration of the application, so we don't need to fetch from - // the database again until we restart the application. + // This method also caches any cohorts for a given team in memory for the duration of the application, so we don't need to fetch from + // the database again until we restart the application. See the CohortCacheManager for more details. let cohorts = self.cohort_cache.get_cohorts_for_team(self.team_id).await?; - // Store cohort match results in a HashMap to avoid re-evaluating the same cohort multiple times, - // since the same cohort could appear in multiple property filters. This is especially important - // because evaluating a cohort requires evaluating all of its dependencies, which can be expensive. + // Split the cohorts into static and dynamic, since the dynamic ones have property filters + // and we need to evaluate them based on the target properties, whereas the static ones are + // purely based on person properties and are membership-based. + let (static_cohorts, dynamic_cohorts): (Vec<_>, Vec<_>) = + cohorts.iter().partition(|c| c.is_static); + + // Store all cohort match results in a HashMap to avoid re-evaluating the same cohort multiple times, + // since the same cohort could appear in multiple property filters. let mut cohort_matches = HashMap::new(); - for filter in cohort_property_filters { - let cohort_id = filter - .get_cohort_id() - .ok_or(FlagError::CohortFiltersParsingError)?; - let match_result = - evaluate_cohort_dependencies(cohort_id, target_properties, cohorts.clone())?; - cohort_matches.insert(cohort_id, match_result); + + if !static_cohorts.is_empty() { + let results = evaluate_static_cohorts( + self.postgres_reader.clone(), + person_id, + static_cohorts.iter().map(|c| c.id).collect(), + ) + .await?; + cohort_matches.extend(results); } - // Apply cohort membership logic (IN|NOT_IN) + if !dynamic_cohorts.is_empty() { + for filter in cohort_property_filters { + let cohort_id = filter + .get_cohort_id() + .ok_or(FlagError::CohortFiltersParsingError)?; + let match_result = + evaluate_dynamic_cohorts(cohort_id, target_properties, cohorts.clone())?; + cohort_matches.insert(cohort_id, match_result); + } + } + + // Apply cohort membership logic (IN|NOT_IN) to the cohort match results apply_cohort_membership_logic(cohort_property_filters, &cohort_matches) } @@ -971,11 +1033,12 @@ impl FeatureFlagMatcher { let postgres_reader = self.postgres_reader.clone(); let distinct_id = self.distinct_id.clone(); let team_id = self.team_id; - let db_properties = + let (db_properties, person_id) = fetch_person_properties_from_db(postgres_reader, distinct_id, team_id).await?; - // once the properties are fetched, cache them so we don't need to fetch again in a given request + // once the properties and person ID are fetched, cache them so we don't need to fetch again in a given request self.properties_cache.person_properties = Some(db_properties.clone()); + self.properties_cache.person_id = Some(person_id); Ok(db_properties) } @@ -1102,10 +1165,49 @@ impl FeatureFlagMatcher { } } -/// Evaluates a single cohort and its dependencies. +/// Evaluate static cohort filters by checking if the person is in each cohort. +async fn evaluate_static_cohorts( + postgres_reader: PostgresReader, + person_id: i32, // Change this parameter from distinct_id to person_id + cohort_ids: Vec, +) -> Result, FlagError> { + let mut conn = postgres_reader.get_connection().await?; + + let query = r#" + WITH cohort_membership AS ( + SELECT c.cohort_id, + CASE WHEN pc.cohort_id IS NOT NULL THEN true ELSE false END AS is_member + FROM unnest($1::integer[]) AS c(cohort_id) + LEFT JOIN posthog_cohortpeople AS pc + ON pc.person_id = $2 + AND pc.cohort_id = c.cohort_id + ) + SELECT cohort_id, is_member + FROM cohort_membership + "#; + + let rows = sqlx::query(query) + .bind(&cohort_ids) + .bind(person_id) // Bind person_id directly + .fetch_all(&mut *conn) + .await?; + + let result = rows + .into_iter() + .map(|row| { + let cohort_id: CohortId = row.get("cohort_id"); + let is_member: bool = row.get("is_member"); + (cohort_id, is_member) + }) + .collect(); + + Ok(result) +} + +/// Evaluates a dynamic cohort and its dependencies. /// This uses a topological sort to evaluate dependencies first, which is necessary /// because a cohort can depend on another cohort, and we need to respect the dependency order. -fn evaluate_cohort_dependencies( +fn evaluate_dynamic_cohorts( initial_cohort_id: CohortId, target_properties: &HashMap, cohorts: Vec, @@ -1221,6 +1323,16 @@ fn build_cohort_dependency_graph( let mut graph = DiGraph::new(); let mut node_map = HashMap::new(); let mut queue = VecDeque::new(); + + let initial_cohort = cohorts + .iter() + .find(|c| c.id == initial_cohort_id) + .ok_or(FlagError::CohortNotFound(initial_cohort_id.to_string()))?; + + if initial_cohort.is_static { + return Ok(graph); + } + // This implements a breadth-first search (BFS) traversal to build a directed graph of cohort dependencies. // Starting from the initial cohort, we: // 1. Add each cohort as a node in the graph @@ -1283,32 +1395,52 @@ async fn fetch_and_locally_cache_all_properties( let query = r#" SELECT - (SELECT "posthog_person"."properties" - FROM "posthog_person" - INNER JOIN "posthog_persondistinctid" - ON ("posthog_person"."id" = "posthog_persondistinctid"."person_id") - WHERE ("posthog_persondistinctid"."distinct_id" = $1 - AND "posthog_persondistinctid"."team_id" = $2 - AND "posthog_person"."team_id" = $2) - LIMIT 1) as person_properties, - - (SELECT json_object_agg("posthog_group"."group_type_index", "posthog_group"."group_properties") - FROM "posthog_group" - WHERE ("posthog_group"."team_id" = $2 - AND "posthog_group"."group_type_index" = ANY($3))) as group_properties + person.person_id, + person.person_properties, + group_properties.group_properties + FROM ( + SELECT + "posthog_person"."id" AS person_id, + "posthog_person"."properties" AS person_properties + FROM "posthog_person" + INNER JOIN "posthog_persondistinctid" + ON "posthog_person"."id" = "posthog_persondistinctid"."person_id" + WHERE + "posthog_persondistinctid"."distinct_id" = $1 + AND "posthog_persondistinctid"."team_id" = $2 + AND "posthog_person"."team_id" = $2 + LIMIT 1 + ) AS person, + ( + SELECT + json_object_agg( + "posthog_group"."group_type_index", + "posthog_group"."group_properties" + ) AS group_properties + FROM "posthog_group" + WHERE + "posthog_group"."team_id" = $2 + AND "posthog_group"."group_type_index" = ANY($3) + ) AS group_properties "#; let group_type_indexes_vec: Vec = group_type_indexes.iter().cloned().collect(); - let row: (Option, Option) = sqlx::query_as(query) + let row: (Option, Option, Option) = sqlx::query_as(query) .bind(&distinct_id) .bind(team_id) .bind(&group_type_indexes_vec) .fetch_optional(&mut *conn) .await? - .unwrap_or((None, None)); + .unwrap_or((None, None, None)); - if let Some(person_props) = row.0 { + let (person_id, person_props, group_props) = row; + + if let Some(person_id) = person_id { + properties_cache.person_id = Some(person_id); + } + + if let Some(person_props) = person_props { properties_cache.person_properties = Some( person_props .as_object() @@ -1319,7 +1451,7 @@ async fn fetch_and_locally_cache_all_properties( ); } - if let Some(group_props) = row.1 { + if let Some(group_props) = group_props { let group_props_map: HashMap> = group_props .as_object() .unwrap_or(&serde_json::Map::new()) @@ -1342,7 +1474,7 @@ async fn fetch_and_locally_cache_all_properties( Ok(()) } -/// Fetch person properties from the database for a given distinct ID and team ID. +/// Fetch person properties and person ID from the database for a given distinct ID and team ID. /// /// This function constructs and executes a SQL query to fetch the person properties for a specified distinct ID and team ID. /// It returns the fetched properties as a HashMap. @@ -1350,31 +1482,37 @@ async fn fetch_person_properties_from_db( postgres_reader: PostgresReader, distinct_id: String, team_id: TeamId, -) -> Result, FlagError> { +) -> Result<(HashMap, i32), FlagError> { let mut conn = postgres_reader.as_ref().get_connection().await?; let query = r#" - SELECT "posthog_person"."properties" as person_properties - FROM "posthog_person" - INNER JOIN "posthog_persondistinctid" ON ("posthog_person"."id" = "posthog_persondistinctid"."person_id") - WHERE ("posthog_persondistinctid"."distinct_id" = $1 - AND "posthog_persondistinctid"."team_id" = $2 - AND "posthog_person"."team_id" = $2) - LIMIT 1 - "#; + SELECT "posthog_person"."id" as person_id, "posthog_person"."properties" as person_properties + FROM "posthog_person" + INNER JOIN "posthog_persondistinctid" ON ("posthog_person"."id" = "posthog_persondistinctid"."person_id") + WHERE ("posthog_persondistinctid"."distinct_id" = $1 + AND "posthog_persondistinctid"."team_id" = $2 + AND "posthog_person"."team_id" = $2) + LIMIT 1 + "#; - let row: Option = sqlx::query_scalar(query) + let row: Option<(i32, Value)> = sqlx::query_as(query) .bind(&distinct_id) .bind(team_id) .fetch_optional(&mut *conn) .await?; - Ok(row - .and_then(|v| v.as_object().cloned()) - .unwrap_or_default() - .into_iter() - .map(|(k, v)| (k, v.clone())) - .collect()) + match row { + Some((person_id, person_props)) => { + let properties_map = person_props + .as_object() + .unwrap_or(&serde_json::Map::new()) + .iter() + .map(|(k, v)| (k.clone(), v.clone())) + .collect(); + Ok((properties_map, person_id)) + } + None => Err(FlagError::PersonNotFound), + } } /// Fetch group properties from the database for a given team ID and group type index. @@ -1436,11 +1574,11 @@ fn locally_computable_property_overrides( /// Check if all properties match the given filters fn all_properties_match( flag_condition_properties: &[PropertyFilter], - target_properties: &HashMap, + matching_property_values: &HashMap, ) -> bool { flag_condition_properties .iter() - .all(|property| match_property(property, target_properties, false).unwrap_or(false)) + .all(|property| match_property(property, matching_property_values, false).unwrap_or(false)) } async fn get_feature_flag_hash_key_overrides( @@ -1663,8 +1801,9 @@ mod tests { OperatorType, }, test_utils::{ - insert_cohort_for_team_in_pg, insert_flag_for_team_in_pg, insert_new_team_in_pg, - insert_person_for_team_in_pg, setup_pg_reader_client, setup_pg_writer_client, + add_person_to_cohort, get_person_id_by_distinct_id, insert_cohort_for_team_in_pg, + insert_flag_for_team_in_pg, insert_new_team_in_pg, insert_person_for_team_in_pg, + setup_pg_reader_client, setup_pg_writer_client, }, }; @@ -1750,6 +1889,7 @@ mod tests { )) .unwrap(); + // Matcher for a matching distinct_id let mut matcher = FeatureFlagMatcher::new( distinct_id.clone(), team.id, @@ -1763,6 +1903,7 @@ mod tests { assert!(match_result.matches); assert_eq!(match_result.variant, None); + // Matcher for a non-matching distinct_id let mut matcher = FeatureFlagMatcher::new( not_matching_distinct_id.clone(), team.id, @@ -1776,6 +1917,7 @@ mod tests { assert!(!match_result.matches); assert_eq!(match_result.variant, None); + // Matcher for a distinct_id that does not exist let mut matcher = FeatureFlagMatcher::new( "other_distinct_id".to_string(), team.id, @@ -1785,9 +1927,10 @@ mod tests { None, None, ); - let match_result = matcher.get_match(&flag, None, None).await.unwrap(); - assert!(!match_result.matches); - assert_eq!(match_result.variant, None); + let match_result = matcher.get_match(&flag, None, None).await; + + // Expecting an error for non-existent distinct_id + assert!(match_result.is_err()); } #[tokio::test] @@ -3106,6 +3249,19 @@ mod tests { .await .unwrap(); + insert_person_for_team_in_pg(postgres_reader.clone(), team.id, "lil_id".to_string(), None) + .await + .unwrap(); + + insert_person_for_team_in_pg( + postgres_reader.clone(), + team.id, + "another_id".to_string(), + None, + ) + .await + .unwrap(); + let mut matcher_test_id = FeatureFlagMatcher::new( "test_id".to_string(), team.id, @@ -3265,6 +3421,19 @@ mod tests { .await .unwrap(); + insert_person_for_team_in_pg( + postgres_reader.clone(), + team.id, + "another_id".to_string(), + None, + ) + .await + .unwrap(); + + insert_person_for_team_in_pg(postgres_reader.clone(), team.id, "lil_id".to_string(), None) + .await + .unwrap(); + let flag = create_test_flag( Some(1), Some(team.id), @@ -3852,6 +4021,344 @@ mod tests { assert!(!result.matches); } + #[tokio::test] + async fn test_static_cohort_matching_user_in_cohort() { + let postgres_reader = setup_pg_reader_client(None).await; + let postgres_writer = setup_pg_writer_client(None).await; + let cohort_cache = Arc::new(CohortCacheManager::new(postgres_reader.clone(), None, None)); + let team = insert_new_team_in_pg(postgres_reader.clone(), None) + .await + .unwrap(); + + // Insert a static cohort + let cohort = insert_cohort_for_team_in_pg( + postgres_reader.clone(), + team.id, + Some("Static Cohort".to_string()), + json!({}), // Static cohorts don't have property filters + true, // is_static = true + ) + .await + .unwrap(); + + // Insert a person + let distinct_id = "static_user".to_string(); + insert_person_for_team_in_pg( + postgres_reader.clone(), + team.id, + distinct_id.clone(), + Some(json!({"email": "static@user.com"})), + ) + .await + .unwrap(); + + // Retrieve the person's ID + let person_id = + get_person_id_by_distinct_id(postgres_reader.clone(), team.id, &distinct_id) + .await + .unwrap(); + + // Associate the person with the static cohort + add_person_to_cohort(postgres_reader.clone(), person_id, cohort.id) + .await + .unwrap(); + + // Define a flag with an 'In' cohort filter + let flag = create_test_flag( + None, + Some(team.id), + None, + None, + Some(FlagFilters { + groups: vec![FlagGroupType { + properties: Some(vec![PropertyFilter { + key: "id".to_string(), + value: json!(cohort.id), + operator: Some(OperatorType::In), + prop_type: "cohort".to_string(), + group_type_index: None, + negation: Some(false), + }]), + rollout_percentage: Some(100.0), + variant: None, + }], + multivariate: None, + aggregation_group_type_index: None, + payloads: None, + super_groups: None, + }), + None, + None, + None, + ); + + let mut matcher = FeatureFlagMatcher::new( + distinct_id.clone(), + team.id, + postgres_reader.clone(), + postgres_writer.clone(), + cohort_cache.clone(), + None, + None, + ); + + let result = matcher.get_match(&flag, None, None).await.unwrap(); + + assert!( + result.matches, + "User should match the static cohort and flag" + ); + } + + #[tokio::test] + async fn test_static_cohort_matching_user_not_in_cohort() { + let postgres_reader = setup_pg_reader_client(None).await; + let postgres_writer = setup_pg_writer_client(None).await; + let cohort_cache = Arc::new(CohortCacheManager::new(postgres_reader.clone(), None, None)); + let team = insert_new_team_in_pg(postgres_reader.clone(), None) + .await + .unwrap(); + + // Insert a static cohort + let cohort = insert_cohort_for_team_in_pg( + postgres_reader.clone(), + team.id, + Some("Another Static Cohort".to_string()), + json!({}), // Static cohorts don't have property filters + true, + ) + .await + .unwrap(); + + // Insert a person + let distinct_id = "non_static_user".to_string(); + insert_person_for_team_in_pg( + postgres_reader.clone(), + team.id, + distinct_id.clone(), + Some(json!({"email": "nonstatic@user.com"})), + ) + .await + .unwrap(); + + // Note: Do NOT associate the person with the static cohort + + // Define a flag with an 'In' cohort filter + let flag = create_test_flag( + None, + Some(team.id), + None, + None, + Some(FlagFilters { + groups: vec![FlagGroupType { + properties: Some(vec![PropertyFilter { + key: "id".to_string(), + value: json!(cohort.id), + operator: Some(OperatorType::In), + prop_type: "cohort".to_string(), + group_type_index: None, + negation: Some(false), + }]), + rollout_percentage: Some(100.0), + variant: None, + }], + multivariate: None, + aggregation_group_type_index: None, + payloads: None, + super_groups: None, + }), + None, + None, + None, + ); + + let mut matcher = FeatureFlagMatcher::new( + distinct_id.clone(), + team.id, + postgres_reader.clone(), + postgres_writer.clone(), + cohort_cache.clone(), + None, + None, + ); + + let result = matcher.get_match(&flag, None, None).await.unwrap(); + + assert!( + !result.matches, + "User should not match the static cohort and flag" + ); + } + + #[tokio::test] + async fn test_static_cohort_not_in_matching_user_not_in_cohort() { + let postgres_reader = setup_pg_reader_client(None).await; + let postgres_writer = setup_pg_writer_client(None).await; + let cohort_cache = Arc::new(CohortCacheManager::new(postgres_reader.clone(), None, None)); + let team = insert_new_team_in_pg(postgres_reader.clone(), None) + .await + .unwrap(); + + // Insert a static cohort + let cohort = insert_cohort_for_team_in_pg( + postgres_reader.clone(), + team.id, + Some("Static Cohort NotIn".to_string()), + json!({}), // Static cohorts don't have property filters + true, // is_static = true + ) + .await + .unwrap(); + + // Insert a person + let distinct_id = "not_in_static_user".to_string(); + insert_person_for_team_in_pg( + postgres_reader.clone(), + team.id, + distinct_id.clone(), + Some(json!({"email": "notinstatic@user.com"})), + ) + .await + .unwrap(); + + // No association with the static cohort + + // Define a flag with a 'NotIn' cohort filter + let flag = create_test_flag( + None, + Some(team.id), + None, + None, + Some(FlagFilters { + groups: vec![FlagGroupType { + properties: Some(vec![PropertyFilter { + key: "id".to_string(), + value: json!(cohort.id), + operator: Some(OperatorType::NotIn), + prop_type: "cohort".to_string(), + group_type_index: None, + negation: Some(false), + }]), + rollout_percentage: Some(100.0), + variant: None, + }], + multivariate: None, + aggregation_group_type_index: None, + payloads: None, + super_groups: None, + }), + None, + None, + None, + ); + + let mut matcher = FeatureFlagMatcher::new( + distinct_id.clone(), + team.id, + postgres_reader.clone(), + postgres_writer.clone(), + cohort_cache.clone(), + None, + None, + ); + + let result = matcher.get_match(&flag, None, None).await.unwrap(); + + assert!( + result.matches, + "User not in the static cohort should match the 'NotIn' flag" + ); + } + + #[tokio::test] + async fn test_static_cohort_not_in_matching_user_in_cohort() { + let postgres_reader = setup_pg_reader_client(None).await; + let postgres_writer = setup_pg_writer_client(None).await; + let cohort_cache = Arc::new(CohortCacheManager::new(postgres_reader.clone(), None, None)); + let team = insert_new_team_in_pg(postgres_reader.clone(), None) + .await + .unwrap(); + + // Insert a static cohort + let cohort = insert_cohort_for_team_in_pg( + postgres_reader.clone(), + team.id, + Some("Static Cohort NotIn User In".to_string()), + json!({}), // Static cohorts don't have property filters + true, // is_static = true + ) + .await + .unwrap(); + + // Insert a person + let distinct_id = "in_not_in_static_user".to_string(); + insert_person_for_team_in_pg( + postgres_reader.clone(), + team.id, + distinct_id.clone(), + Some(json!({"email": "innotinstatic@user.com"})), + ) + .await + .unwrap(); + + // Retrieve the person's ID + let person_id = + get_person_id_by_distinct_id(postgres_reader.clone(), team.id, &distinct_id) + .await + .unwrap(); + + // Associate the person with the static cohort + add_person_to_cohort(postgres_reader.clone(), person_id, cohort.id) + .await + .unwrap(); + + // Define a flag with a 'NotIn' cohort filter + let flag = create_test_flag( + None, + Some(team.id), + None, + None, + Some(FlagFilters { + groups: vec![FlagGroupType { + properties: Some(vec![PropertyFilter { + key: "id".to_string(), + value: json!(cohort.id), + operator: Some(OperatorType::NotIn), + prop_type: "cohort".to_string(), + group_type_index: None, + negation: Some(false), + }]), + rollout_percentage: Some(100.0), + variant: None, + }], + multivariate: None, + aggregation_group_type_index: None, + payloads: None, + super_groups: None, + }), + None, + None, + None, + ); + + let mut matcher = FeatureFlagMatcher::new( + distinct_id.clone(), + team.id, + postgres_reader.clone(), + postgres_writer.clone(), + cohort_cache.clone(), + None, + None, + ); + + let result = matcher.get_match(&flag, None, None).await.unwrap(); + + assert!( + !result.matches, + "User in the static cohort should not match the 'NotIn' flag" + ); + } + #[tokio::test] async fn test_set_feature_flag_hash_key_overrides_success() { let postgres_reader = setup_pg_reader_client(None).await; @@ -4095,7 +4602,6 @@ mod tests { .unwrap(); let distinct_id = "user4".to_string(); - // Insert person insert_person_for_team_in_pg( postgres_reader.clone(), team.id, @@ -4168,7 +4674,6 @@ mod tests { .unwrap(); let distinct_id = "user5".to_string(); - // Insert person insert_person_for_team_in_pg( postgres_reader.clone(), team.id, diff --git a/rust/feature-flags/src/request_handler.rs b/rust/feature-flags/src/request_handler.rs index 538c6845d2a..5ef43896e64 100644 --- a/rust/feature-flags/src/request_handler.rs +++ b/rust/feature-flags/src/request_handler.rs @@ -97,6 +97,7 @@ pub async fn process_request(context: RequestContext) -> Result, -) -> Result<(), Error> { +) -> Result { + // Changed return type to Result let payload = match properties { Some(value) => value, None => json!({ @@ -329,7 +330,7 @@ pub async fn insert_person_for_team_in_pg( let uuid = Uuid::now_v7(); let mut conn = client.get_connection().await?; - let res = sqlx::query( + let row = sqlx::query( r#" WITH inserted_person AS ( INSERT INTO posthog_person ( @@ -337,10 +338,11 @@ pub async fn insert_person_for_team_in_pg( properties_last_operation, team_id, is_user_id, is_identified, uuid, version ) VALUES ('2023-04-05', $1, '{}', '{}', $2, NULL, true, $3, 0) - RETURNING * + RETURNING id ) INSERT INTO posthog_persondistinctid (distinct_id, person_id, team_id, version) VALUES ($4, (SELECT id FROM inserted_person), $5, 0) + RETURNING person_id "#, ) .bind(&payload) @@ -348,12 +350,11 @@ pub async fn insert_person_for_team_in_pg( .bind(uuid) .bind(&distinct_id) .bind(team_id) - .execute(&mut *conn) + .fetch_one(&mut *conn) .await?; - assert_eq!(res.rows_affected(), 1); - - Ok(()) + let person_id: i32 = row.get::("person_id"); + Ok(person_id) } pub async fn insert_cohort_for_team_in_pg( @@ -410,3 +411,48 @@ pub async fn insert_cohort_for_team_in_pg( Ok(Cohort { id, ..cohort }) } + +pub async fn get_person_id_by_distinct_id( + client: Arc, + team_id: i32, + distinct_id: &str, +) -> Result { + let mut conn = client.get_connection().await?; + let row: (i32,) = sqlx::query_as( + r#"SELECT id FROM posthog_person + WHERE team_id = $1 AND id = ( + SELECT person_id FROM posthog_persondistinctid + WHERE team_id = $1 AND distinct_id = $2 + LIMIT 1 + ) + LIMIT 1"#, + ) + .bind(team_id) + .bind(distinct_id) + .fetch_one(&mut *conn) + .await + .map_err(|_| anyhow::anyhow!("Person not found"))?; + + Ok(row.0) +} + +pub async fn add_person_to_cohort( + client: Arc, + person_id: i32, + cohort_id: i32, +) -> Result<(), Error> { + let mut conn = client.get_connection().await?; + let res = sqlx::query( + r#"INSERT INTO posthog_cohortpeople (cohort_id, person_id) + VALUES ($1, $2) + ON CONFLICT DO NOTHING"#, + ) + .bind(cohort_id) + .bind(person_id) + .execute(&mut *conn) + .await?; + + assert!(res.rows_affected() > 0, "Failed to add person to cohort"); + + Ok(()) +} From 1421cc41bd5d9e69f334e89b9aded8cfc65e2964 Mon Sep 17 00:00:00 2001 From: Zach Waterfield Date: Fri, 15 Nov 2024 19:41:41 -0500 Subject: [PATCH 09/11] feat: add payment entry modal (#25614) Co-authored-by: Raquel Smith Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com> --- ...el-top-to-bottom-breakdown-edit--light.png | Bin 162492 -> 162607 bytes frontend/src/scenes/billing/Billing.tsx | 3 ++ .../src/scenes/billing/PaymentEntryModal.tsx | 44 +++++++++++++----- .../src/scenes/billing/paymentEntryLogic.ts | 8 ++-- 4 files changed, 40 insertions(+), 15 deletions(-) diff --git a/frontend/__snapshots__/scenes-app-insights--funnel-top-to-bottom-breakdown-edit--light.png b/frontend/__snapshots__/scenes-app-insights--funnel-top-to-bottom-breakdown-edit--light.png index 78ea79ea3f74550c79004e8ec145f94889135282..25ab8cd06fd020558975f117de59f999c129fa9e 100644 GIT binary patch literal 162607 zcmcG$g;!PE7dE^>1w;u^KtUQoNol3~&>`K@4bmObAsmnf>F$y)kuK>jkv?=cyz5@? z?;GzQ@P3RlJdDFWd#yd^n)y7_U^y8W208&c1VI?$V!|IF=>8)JdXSEW3_fws3!ejT zNOm7!f>6n?mzxko3W*B~C^~=Jo_ErGx=sk~uj2@cd6#jJqxC*Bc=Jd3Q%yK0!opn3 zvY5!MxJtQDxwx_|wYu7D-fdjz$;-za6*W?y%V6I8q|0YrOHV4%B;``~s8iX`7TorD z&K5*=o4|WU+FMlZ2nf4k@gel^LJK);6phReTM#XM@__>ZqgQ~eVFYhaZqvD-w;~IF z!7F}xDQxNBDJlMcugcpp=kCe;X9JecqP5DPxdfA}yVN;F$S`&xxOE)^=s7ibjwF^l$hQ3u2JP&c%&^{aNtO8(0g zoy*V2iBb%Ivfb`~jk~2j!u@w=WXA+@?#hgj_4|w-7dk?>!}k$&27g5K1>_lDJ*>w4 zcSUSOMG!vq9?rB8G<_l__}UcBMC^>2{284r&!!Y4hL(?0mh|MGtziplErxF0h7}_t z4h%Pu!n5|M8^`*@$Q7cmIWEe>|K3bcE7D$;G=j_5I`IShO#U_V2o}9u=JTF@k^iA~tQ0_0Y9lF$JvNQC!@LK>VNVLdM`hNeWq)HvWx`?oe5E zg>t0j&I|_h)+EA<{|6e)LHCmW;0TM9)R$Pg3&k7ftiEU+Wh$GqU7n7PY`)vt9NbmO zr=cCQH9JL1lNHlNxU|hV!zN~QV^ljD`siB{39~i3WmVHRmnW~NDadz|o+nLBPgi|< z#OZg5N(c?13ChApOLZ1+Z#|2(^))cb5)v((26iV@%4o-@DbUhu(uUF4H6&$qR0c#O6iSXlKXhccMwT`EW(rxe)dx@sOpYH)$9sw6e)Y=|if7Z04Grx}tTJ!cV@eQ^qmbi4 z$Xi*Juxn`Oq-HWF-G?$V^#d@8iqg}OpjWR9H(zYhP*}&hFT->*vZ_`&Tw+tS+t%+v zse@jp+iIoSJhQ541T!_A&n9B@oOS~e-Q)bMC}$9i*}%SH9P7(9t>vBMuZilKn&e)s@5p$OAnrN0 zuJ+E3u2*vOepTiis_N?M8X6t#?cm>*vjt&G%jyvO7v_^zZ<(01D^{W=#^dE)KgMj1 ziI1nmM%&)r?u3)%W*+J7D95_Kl##IQopD$!%qt8Ex`LDNP|dEv*$oz)nwd#VOcWLo*|a&PYT+2}?fo#oX@PG>Y(d9v{+r(m z+L)iU+*|M{FF#mVNI4wO*pA36Sxe<|B4cD6Y^q7JFCS4VcRSNIW5FfPIAjx#$<*t5 zQ>1Np@n(Hc>q~H0631TK?tH`Q%F6Dd*UX*iv3cNhsE3wze)VFO3Y0k~uw;3smz;O6m^xl(e*xd!neZ?_+pl zhqh;D8?M0Ua1;_^Vn|-P)AI0SYH%d|%=mLyVSCZ-FDP$oi>{zxcN{OTuHL^AJr;mM z##WP8R`xw>th1Afhi7?hAi`*Ll~OoIKv0Si5}nE=PDU*}<-^(7x4MyZs1$IX)A)W%AFTDOlOqR(<&@hvjaR9{~~Sy@~CLymzL+j#I#Aw_X%_R8gF%B3OK2G5(my+jHsDx!nPX;~h5 zf3mk#Y@&_1Df*S#BB!mqyR}^0VWh=QGrQx`RjI{KCHjf*x=V7#lTtsS;j*80S;8ePpUA zaR!HjkyQfEoo{vEEB4*dBNc~>p0gAr-W7)m3Zu^nj`J0$@BOGQ=32p*l5|s6QQ2Et z>ouxO{`N96bNPe9sHPTSmlHXfUT6QNUb*w^1kvC~ioE0-NouXyPm$LjG&LnWQ&~;* zB+dJ~CTDx5Q;YS!7#x3`=8{(*#kMiJHXjn@NR0Q<#@7yb{zu)ecu1X2R!2nZYsnA@hv5j$nh!_4V{O0DS zx3^D?E;a;1#p@sY#&M`Z*3x=#*01x3j=i$JKzaJ!!>U*Lo!WaXhiTZz&`{-Re;Dt* zrht3h-)3odNGL}Iwo-ZR)a4%um?jLSuG`wbudnAEC{{s+c$<0Q zslvRT=kFL(`$qKY>*_Qc&l%ZjDl)!if=6saiBMHlg~Xg=xFPXZ@UG$U@ew^_v8;M~ zNrB~j?G;6QRVLCxPaUEf0bA6$e?5b zrG>g|pEKQQwUpoO`98+LfOTo_$vEfoc;12x#9x(8m;LtY=u)@5s=(RZur-trq3ViP zx|x$cNhG-_F_w0YVPu>5%Pva;t(g1MD07N*B5QtGSy@3y?(GMhV9L}!hqAqNBTqX! z1wz84TzPq%hsS%1@YauFgX5!(}w5 zK|n19b`s{Bt?UjnZma|Y{EI(+3T}$N;iCLLZLv8ITg`nU4B~{JwixP zThi$p=S6Zd(dfv??xNce>9cxPb{!@8=Pb!GEX=Hld|uif9yiNfk#J(3>hki<_1tsu zt=QcsenYeTYpWOSJc5$JVmz{lgtj7)_ zb!GB-`ihOMDqUb>X^GdxcA4$=5&mshc(}NXI2p;GXTid`GAZf9n;3%W4f>2`0*0IP z*%_S#1b)b$Nx8Xw`sghjA?1sD0&eHu14(3X64=Zvh*Q}%M|C6~@8Y=UOJA4Px^Y-^ zM+lgq$s;jEln3!S{#%ods^W;A}T+ajrxk*W{MZbx9`EncS$Ks+jcoy7M zTo7z#rl+No*!|W0(w<1=thER4`3T!C{me$`fU9vR+;&GI%{Mp=_Vlo`GDp04^$_~A z{1oZOK=G!1rIWP^6a+VS7m1E6e*%L?MJ3N?!r)IR0_3Novn2^R4a!POWed$M=FXWe zT`z~_nHYY_(9zS6uXaz4dn4Vz9+N05^@P?sVL>@9eB%=(T+kOcER_|-MRfFZiHVuLnDT~f z(-}m$MxI1O)ebdQ$e(}A%&4oVz#O1nJx~&jE~e&Kn|xY7O`cn?6AFCn=pgUPl|gZe zCYUF=bU?$&b>B~J>&XNE_amc>a5u^uUcb&1@kOaQ(i@5U_> z=}MhFR3`-D{`fdsXJ-IZ=5fX7P*t^9s+PT0(OdtJZPsH0V>FgiaWu)M%posHfNbf> z8S=e*D45%K=*od^_tQCu;VP|58#N}8bL%1#^HN-N8JM}`w_kpza#LA)tv*SglEUn5+`JkUwG<_b9w*}}9+$@#zkRXtqVI06_Bz7|8yt7c z;(o%y2-sYY3D1cGCT&J%Yz7^_VxJY#Nrdjyjxt;zjQXA#ss(1VZN=r94H+nYWw?fvHU;p6f*9A)A zQdP^FcQV_a*tsst-u%-M8FSFA-7gIdjXIW_T+sGt);@g@m?`AQ&*^@C-t#oKPP3${ zYCJ>aXfgS1$~M7qhe~R0uHk*uz)$bKb%d@D#!pXut9|k8u;uP1GBUwbSC`3p0d+K& z1M}Gv99!eFJ-3RA3VJ&Fwf=O=l_Bb9s4rX=!O+zvAfY zFGo_qTwPsh=qTCQPh0M8X=!Mf-@bj$ZV}(o!k57C3>{9yg-1x(XTS{m@|?+_8@r-Y zP)LY^oE&&;5P$F8yXWEV-raYh-xW^(`gKrfsD8QX=g*(-p<+_@J$&@2!C^~TS~{$z zrsnhK)|0Kt`~_wk8=JeEGaVb7^5*8-2r?m*$0qKxMj(g1I9gBTaTCoQP5$;RM<$u( zhTK^dpRr!)mU!+;o(R**7tX4kuV9h5O=oQ-O#m8RT0E=>=%wi52_Llz#yq z#Hig^Yc@^;LITv?-+#SRvuHG!va_>O?CS93$rCa%GLXjX?(Twz9w2%&pxWdb7FD?% zr$hJ3gw?k8LdWxh?adpPMIEo|a)TF^1bzSZg*I@-B%~0dT|!hgtv)V$jVzeZ>F)H| zQLH5eENrS-KQuXczBi_jB2_fX1#_3rKu_5(hptku?}wS<%eiucgaezs&wbSuo@y`3d1?)f^v0LZl@=; zfd@$E1&a~LMYJ28nYg$JAs-(fkUp#|Eir+cfMNhBO}?<%`!%b`3kup zAoH@Zoy^tQG3#z^Y|v@eVnY@d7I+MrdHMPIw^UKoi}wZkQ+Q?<7H+{svMJoA?3AXx zKNVEp1J6OGfoza+e(sFoyR^2JEC{%w5qDGw8KDJ>%FQf!o|in*kd3YL;5k4 z?wdbpqO7C@^IIGp9)Iy}s6}DfQq=Gjylv@q5|{bu7bM^7E9csK{BUANGO`+Sid0uO zkZ|beq*^O8+=H;N&YrZv7F*7SI;J;EJ+6q7U)JnR2{!vEsHo&tWZ*!z*LJCyQOlsg z@$~*V*2dr}UJ9qfnlF}7lMlw@$B(}R2mkY^hpTb8&HPURPIFZ%vlUN=sK&S7SbURQdh;H*hwf+J*+}#pb4* zoP**t0Re&7*jR;JnOA5(hlk4>8@b8JeHs)ijR+%O65&{{DzN@kB;t(W?V=_)|*GNYOC+wy=(922z$=tV?k3}Tl+Ra zYP|3f1_szd4uYPM5pH2qm6)I36P`R9$EZ>6c_SLB`YkG|Qh(i1K_RL-Iv=|l8+3!y zIiy`(J4;)xWtxL+=W07q`7<;1Zm*Xap|`AWk55gvt8KO>k|_e=$ow@{^Yu=96Z!Im z8M$3c2hKEW$_E8C*0V7&$x-p~_n{M?&d6!E6I;?2(6oa1E$K-hoTpJ#GVXDt1gOr} zms^b8jFGY#(2vPn(>Y_#8{DQfHIP_e9&fhXoN9=P1=+i5Yilnyd-SMik8IkbqM{-s z>b}p-Y3k_cn1zDAmh3>qcMJE2@Xw!-ps~rxdr;CqNpbPb*`k-EghaQUGNMBc{m8EF zpX&?yfw`=&vNhAhHC~jNDUDKCjy>WG#3Ukk_DoSu?xVH!9s(gz&7YXPMiu2moVVxb z=m;m_v-)cz%J0EOK$f?5;Ox%ZQd=8eV1Qe=Y+DB!woxTD?A6%aqCZcGW|ch}&>=^Q z#fe?eOfU2I2I6co{a!_=V^)$sZ9g7+pw~~rnYme{A{lz|M>5V+bYi+A;pK_UOuA6l zm#{Dpw3~Eqaw^vuq`sZ+rU~4`qx*Jt`+ZuGm_VyFKV2AEFIadf#NEBI`P$6XEwB`i zi>m?Y9?Ja(4^DQA&9+U0zjnu@Ct{5JO6EHI-RcXR3+May;5__^)A5u~)&bQ;szKkk zPiGs$`g89dw5h^huyoGP^Dr?T0H*?+vrxd}gm*T2p+3123l{ZK#D-+~Pg5#-5BB## zl(leocL&h~oY`Yb4BSHV&D#%w;56;dw>-U{-hs$VrT=?;N;2~DYAe1@R_1yT_AzmA z%pM-)WMq(gdGXN<_l@e0JJD_u*jI31nyz$1>>9JZy(9faH(WH|GsUA8w3@ePK^pd% zf{;Wx+?}Aw@MvOuu@u?6FRoNNnb~CkYY~ax(ecRI($>Z%#Fc0iMptPK~`$&V)PpYC=D3W^baX1sjR-i9#hvvaJ-6z z$;&G%DU4sedKKwm4VrwQKm#c=h{oV&5ZL+Mt%o7~{moGmHjWn%h@yENEG#VabaaY= zl+q&3y)=OXMqKaTcXV`&kBuGg&T9w>WloPLBqb>bNTAL+(y>d1X%?RaaOYp|w=TB@ zh96vnz;r~I%j(td7Z&#Y)bd?;n~rM1YnnM7dHK>+i~~yyv|mRC?j8CZ zqzT;exK34jgb|s|)iNO=QN+^gfap@nVI6Q?XML9&%6E2r9M9>%45_Nd1K+IE?0&L6 z{irY2W7NX*2)|!aT>QqU0|8WFK5<>^b;oy!f&!I&Z0(ASl<#ZSb~!TYPHDR0y*du1 zjhofg$%A+3MN;QPKcNr>vFItaOnYZ%$~&8kv^4K+R7T%^$K#FRsi`U8>*kw1G#q9{ zb#(aNymRcFEQ4uv(|{H%ah0ldVim znRI`0J;L{(yMuaZk5=RQKz0V2Nl{cyvuaGQm$%1QPmz^XD$D94E*HLN2@xLwjoch` zk>o`-71}u-mTl=e?aXxG(UbF-e*E}*vSl$&hXIu7^&Wq?1RYP0sZ?m)8%Dx+k-5ny=!N7E837T#Ku! zPI_bdc<-)h$3-xRIGraMXU}#ojyl7D#70RbN{E^CUPF%wc?~8@EWNHT&MFLP-@p9T zb;NglJStLZc12KESLfpF+}_UWm~ZRgkj&+@3qpBDMh0*~>%Wo<_dCo=N=iuF_XXtS z}+$?_ZMsfNbE-#ukh`{HUu^MS3*S!Do6@Zhbnjb@>4kjTS&mat(+Efq1!dP zaJ{0SFrTl-xJD!{wGqPfk53P-k1IPsGm(a#ertOJbY5%S&UP9)s(AzXGl%i$)%iW)p)Ln_!G7%>p?rH=Ttk(zEf4o(-n*`39p8Jsv~)%# z{cUY$mBVSb3zQwdWQf5ldf@fb|8W7X&Pd4D@o;fVFFfae3sB6tU40?p*i7{b|LXPF z^K#SJm>P@3+RKc!gv3*IZ+m5F(JM&qwPIz&KvFd)m&=#u3-5MkOIvoS@cReXk$*G= zp{^Jx8#xjdJ}7)tD0zeU`o`<-R>%PTeb4%&)oiuh`Tp>3lScp+2)u1M1qEhiYKE~u7^|XndIu4cYT?e|JZk{cyY{u#ATG8@2^}6lp)VWJjt+m|p z)&lo>dlPu>d{ugDMeouEb1*^0BgY=Q_ajG|kBiIY_=HG|{yc*@@N3MQVu!#QPB&rQru?Z- zA&5+s1aI$7%&svxmR`q@3Z8`w68$Y73z)&t$M&El79**}T2DJocjSvHLqWle;Nbj} zlo1Yy^q2l1XO0#a;43j>LgvYiqCx?oLCdXQb_7BoK$!a$j&Wx>T83;VBD8J-tH?+UCO5Ntqg9U4HD#Y#ui<$(zf#_(#wB%qe2YLJ02tLhVN|N!^x=O> zEFMRqEpkkFuK3cKz&;@1pR)f+T^e|=3=H|nmcr{0+eiPgTooX{FnG#qdivQq^R3zg zefUdWZ6zgu4lVEOJcOPsok1V_<0BCy36_f#=v&g$0fjEdGzv;eH>Q8)8Fen#$loZ+)zuWZnD$!bLVoA8gHk*!KPTuSqN(Oh} z5JN> z)@ik7?i}~t(9l$rmDRfLj4XFOG5(eO(S-RQ`Nf|0SHih2N}~4n(IDqjI^U$h2i{Ej zqJ4f@8Q3Hw)`#QN!^2Dfps*=FSRs#$lPDf_%-%K92E9$q14fciJlOs(s)?KYThs%O2NqsDDb&G#%t9i6-0@kemt zz`=MX4CwauinJ=*&~Vj)ed{ph5!iSb5f=gEd3WLkK2&^Y&&k96$FaSMtI4ea8LG2W zQZb^{QqmdL`(V9H{@QavFsI>ll50gdYuEd6Rl+W7-a>8qs1^yPvLLn7#l^SR=5T-igplM6J$TJV*Hi}StcsD*1eW>a+1Zgs?MLDS<}+V4p#Y5O zT2F}34yng%zrPdqXs@e|_#L0U1o2tq0#zlN1qGv+5BN`;8iY98X zfroi-FP2sczYBhv+k+I7oct2$V{f!LESz|*SzppjUH#L3@yJ(Z2*6k5apZTOG0|RH z>FY~p4)b1rDzQ)Cu(}_$mzs1o?2|5p9Or)NuS$vH4TFL<#u?h{{d=`0^#p z-J{76SwTLin!Q1m#0d%t4wn{_Dkvug&(b>7P(4=x3 z&Zms8tU_2ADx5+pDm=&MdYmQqy3uy^I*c%`N4HPuz7RdH?jPqaZ64fM_cNL2&=(TE z&R@S`NrPUcdewV$;UPLQfcZght*)ntc`Qs>XQ)#d$nWkiwA@9|=pN_sdwB4$C$VvV ze0Oo_YP%wg8#5geuQcZUT^Y3~Lh5k=7PtS{^aoR<&lE+)^x)f|8PXlSk@p;W&f)nO z^7Hpsm^CpqUD_Fk-HZdmL7t8^^VpmdC6N{p3yT7UJ_Xc0FrZOxVd&}_V2_gUe<|?E zH240&=~wHfErbobg(~$ZzpLcf;T9*CpYor{ybw*gqQZWcWArwGJaLy(q2RKPmLm4~ zX5i>DMmHxWCiY~W*ErkgdmS`#?;^(exZU@I8V|Fq_eYfc4i9Y)PZ{2uT3J!?#nGv8 zHf2;GL!$5(4j=E*qgSFcGXCtBeS)5|(eU50%@jO3*ji*{W~Sk!>Ky7ugFwA~ww+)H z>YYg0%pN3GgI#mUtKEhww(*J^1xZQC%uIcv?VX;MR#h!kt>QukL(iGU+a%mYLn8yL zg<}?I1A*||AAV{3{pomX#PM;ob|*!uH>>MGwWE-bug!92cRyRrTWac_&>=`pdqT1H zG*p28IRWE*v!Z-Lagdq_Mz^)h7IG~0Q(weASu%%e#l*Tgixpe|vp(mr+9q+klMoXF z83x7dLxZGrkwWujV)>Q@gS@&uu~2+QN>t(Ao}L@$g^anmITEky&Hbet#ebyk3NO6V zw~&w6@i!x;)4EKszXTL7&;ztoZ8_bsARgLa4Sw$2NPr1zsMI%op>2o(k=;@IX0(ny zQCY{O(&DgF-oFybTYg5V`Re?FAd&u7TD%53?*KlQVPVnC*nG}O#ydPeZ#jQS;>tO- zx9GJIr_~~F=iuM~%7Bm%bi!qZ*U{Rs+vAtRFuNADI;rNB1*?+zdNn?;6ha)^tAk}R z=sA~iE2Fdn+0D)MZOs+DcIv)mH70a^b=KE6AT2xiuJ#TanwmY6v)MEm%^|_H+&dJ4 zVRq|`M13AV(Q_-WfA)0jQ8!~_oKEhaHH0lFCbCwdr{ZgWC)NCHqj0>d?i%PY>>d&* z@HLH1PZ!YDmDjc+ey^ske)_vrh%-!veWANf#6QfTd)2mw5hY+C^<`mRzjAv~2FeOY zt^*Q>zDtw_cuTYFn6ahZqc=;7{%(T!#cBjZ(j#PX?$S26)% zVJB1NnWsCmvfA4!q9?>EcU@EUq_gDo^d2_>sh7^Rj9Qm3E>M(5fF4r0UFvO?InB*G ztYci4nVu8OSSTl_l{9|onlNH|{&+QaPRmCXbg(h56FE7PJ16weMI@}@EZ+x??J05R z^5$mH!?UR+7emrd2>7DB>zf1W3uZzZd)MKw#$8Ze$`H--H?1blAdk@d;jv;7Jc=aZ z!i7lL*f1d1_ne%k2qkrO*Bykz=7TxchJZkkxyR^gWuKb;>n_SOy8!6*_QxG4uT)Aj zla3eKQ!p`2^Gz2$uRMf=+G+}wfqGEAhxJ8otM-1R+})_@=vZ4>t*x%UIlB!oLbo~F z7%-|lzn&QydP||72}+QYvokK&V_~swdT3*Pz3@|J^pnsI+UAQH^&T$da*(@>|66{6hq#hHVy>|3#Y|Y1exzWC@rl_ESdg;d=$jb zK#b#V-ulx8FnU_R|z$6;xRd+==mYP?WdTH3s4Rn>|TLt!6nVb=#;iv|)T zvRD=050*u9DRZ}PJ!FAdXX-P;@+XhGw+ED8F3`_X*q%_eEIq3_P0rvf&C3H#Z?cQg zh&zlA3I%7iiF~5t0=FlVw{B0)YAo-jr=~VaTTVfn_TyGH{fZNf*1Rs=$h&5n8NK-{+XTBLW z4Cy0ewJ*kf%#kampuz9JNRe-!9-Xb(!^4kj-^Ur2F>y0`G!u`qGLB6|{eHl0Ldg9*G8Bp2c|xG?}pyNEaVz6)_Ystd6sp zDgFQ{?1!%kDCbxYAb?q!#YRS^`}<$)%sRz+-c}V`Ivtjv1-6l)N?SXIDvqs$cI-vR zseE~HQWA?7_423fZD^zy@0EqT*naWh;o-qDRph;G=*I|S+;ai~n%A0E^u08d*-V8c zNSoJ|k5wo7UMP|{uTW7^QQd%JojjX!EZef4ty$iAyOxQ| z@mhk{wzw=*UITM4cIQc*Yt-VW5cMmWUJ|!6qWAWSlsIuQF_CS>z1$L%m5$?Xngb-6 z2-36by+I(hh=^HGy2_twEmgl(P*<<_ypaWIR`Iz}f;~L?ZfD_Ye|Xu!yk*Zye>4Mm z@vTL*vWQ2F7`Yxc!Q)tzGEOeis$l;6kUCvX#bXPF^{*A*I0GUvqY-bR?`%k{I+kBH z=qZt*=759|PqW0basml+0Y;o4eENk>{uakQg0Z|F0CT_ogHFpFUkqBxnX-1KcevlJ`G8 znnZ+hah+t`vcrj4KA1I0ld)-td9`$+j$L1#J%|8Nv9^Ju`6LsR{pcJ8mL&hER%yJ- zVp`=XRb!h`B>)_FFASF2#rGtv$4-g(05tX^r$JiVvpF_)B2S(|_8YgJo?emY+XAz% zn%67&nfjgK6Qj#${^T&~F6kr=DUfEqpPZZ9K2BH$Skc<2cY^6d9UZ1ev0;z!`xPpZ z3?{RSm^GeMh7d&jTI}>zBKZtb8>lCTp0Kfr2QZRAAyiOMF!o;2VB($m+EwLx|JaxT z05Q*urLIgzU1@x?v;Aw})CmC1Vd_0K+QQt!+kGMYp;Ls3Nu9}h1kI@-j{ ztiHa^VxhujcP@d(QNqqmbDktKgtQAzqHkq2(c;C2yQpz2E-g*rty+C8Nf4HX<8^oA zb+)^xbJccsddj1Ii?xCuZ!qW58GY9m_V-|QKH4q!mO%>-k3d^T2MbE|tU!aWa3Bj*-+11vo>9w^d#To-B%v}-Sk1;|xm?QM!11K)aHKc}Z(<3q)we)Vc{Y|MVk zh)1uzOe7TlZ9-x(!x2Wn_&B+$)&>Seq}WJmcBn9U(k{D>$Hhgc75#>TNbYDMjf=uU zl8g*grSq8jCW{9z_}WCz0Z{L#pMmadho0QbQ3xFpmt-*3GOAwQU8|ITF~MuOsQ zC+)v3zPru8mdjmPk!#I0P@t-X5VPbH- z<3GVGaWWU#sISc2Nqpp9yZe)o|2MS2G{_`~NNX)Pn54uP1(d^e-?BxEJ>|{*z`p)&Ij=iYbHa z*UStMus;7Q5l+-<>>){JW@cWU!wwZ4h6d-Q55`?SfB*Jb)EL#fJ_0b~tyM}e(Vp*4 zF793JO@;_(oaIREZm0cw)e!CYr5hSxp56IZj4-FmO_h9pBlqD04leHeaOi6VP0j1Y z6GEKetR0ameZ?$rtO20|a=v5*q?tMg|E%2HQq^0_yIapk`1GHg_HJ$vN}yHB>4323 z>J0vOf%@i&MWLXu;3oS`=A;1>ZvxLSDj~b>p;o}pG@abn#<5?fYN?(Wt%QegBYy_O zZq$1y=Pb`3v*F9bEG>7+GpTc=Qw6bwY4P^b@?Jab`AzI!DC9Qhrl;H7-QF`c&W(+Y zNJ+WfsVTf*yN=96?ul-`ac?<4JkoKz!NbP>Xkaj5KYkz%wi1O!*_=xEpZ@0pPzTDG53>RNM&l8etHaK=5|Ibhk@&WC*M_Ne)pd9wBq}Bi}^o9 z&v0My@U(e>X@H^8QQF^l-`x+6ty{EsYz;^QGaHNsW~$65ot1s@d!8>fm5y z1w`ElNzgc7M6V+vwqXP-_m4$4J`gYr4-dgZ_m7RmTQR(PgwODTfB=A_#>R#k8XAB> zoo_4~czJmV{@}1>d+A*lBQN^{M8A1hS#xvq$8jR z0`S=$Ul1BxEJ$`}%-}g8Vbn#bb_1`~oGM-@7y|fb-=rUFFRz#=D3)hq3Ij0+E1VAm zIXET}h(x~I^FkHbz?L(TFL24J>KkKBSd9Y=?O(fdC8|0k78DnM2=Ce&Zj<2z$XdLH z9GJHQgxv6#QDT%SDIOs1Gkj|SypPSbHFdz$`~8CqwBM|)OS`*ssby1cEqbU8j3UKW zc6K_J4?wr`hhDj+=C{gv0z@ra$Q4+-P?K01u83$lFrlSOIJ0P<$G%^Ad@PNQYJ4eUIk6$7| z)z$MZ+{6iLQLXVO!>D8V^cO>R;2x2Y!+|8fUX`}%G`PYZF3g+CSeXsZNwB!MWE=w-wbHZkVfoFC4XGsdY~#`t==a7HEgiQYY2Llxau1OC zO-=Kgn^O|GA}xrIch;{~RU{3KY~FpdoUK+>RsX(U``1C2HYtZ2Mw2-xOMDfh1kHFb ztN=JySj60aHV~lO_6Q4(h6M*5>Tv@TWbYg*3I_IDFho*RWI;qk1e6X=4h&8VC*b*N zM*NtF)6f0u=WPwylvhzvEA*kjM*tZAQ1~UJN{5%cP>Tz2cTUdwmEd<(Xmud~7yL^7 z2TCg}lr-EwJEKq`ixhL_CZ0BxP?wM>NKa2sNO%F|y++^)0|I@ab=uvrsUm1Y0y?TW zQ-VQ);sC@iuN&zsX0cp<5*TTX)$Esnd;i3h^cn@)Ju(9Wqp%k& z5}dEt*~3ZGR7z7;-ld#ioPg1S6*@`DNBAoE&~p}}?*Og-@WEEqBpw*TA6dMdY@W*R zWvon0k#Ab6t7A3f_}K*W#CZV%@j9N(93_T@mZdPM%0XXoGhwWbxk^lZhUJmnqfMoi z74E%>fy92m5s{_Bd-e?NJ~CmF6>}uF*X`V4htRX$5Z4FtK*-75E{R>s(=#&!FJ4rr z7425fo3bWKiDYN<935>KcqJ`$=b*p)Ut-m3% z>6QAZV1yT1dREp7BF6kFwRGC(W=u@XFBut7S4jTC3GHB2A5BIFFxKtu4ZvI+cP@(o zNg*RcFf?0afS#5XADvK2S~~k`;vU2XY?m@pY-+}Wxv8Xtf%$L~@b-Fo082?nha^En zPhVfn0*4xa{w@W){z~ z>mNb?qzW6B6N%cQz(`O~F7FE{Djyym9a+!U-*hc_0Pxk$#s&q<`9uM#2Dlycnz8g; ze=ij{Qpg)HA++mkV_p)lQBnPBZ=dS#?{9CX4EQv}X9A$KM$y~^92l-&2k81cat<(aS z8S&txp79bh|8+rTrfbU4+|W=2DTn|8z$1M)!^k=c3|u@qKFo5ZeWR$ZUVYiX=D~ec zbn6*o-)A}bONWHl84wRe3*P_De->nl>jEPp6O^>I0e5ncl_0&a(A?Vk?f{@o2U7EM zno&^-o)@c5?4b{!d#D(sS53}W&Y-Kqz{?;&iSz#5)L<$fTr{(;z8*}DT;E<1gQzAH z#bkOYd}yij;za@&n@OBF*JGxjumgh+>AJcc)+nJJe>`t4QNkamRn)oFrt*1}=arev zotKZ11MLR~i?`g?Cuw#7vbnZ)3UgtE7$qQ*c;4KsRO4)$kN*J zQ<-(g!QaGufl^q>!37rGw|+!O;K$53i-YdZt&N*B0DzLOGNpi&SZX~qIjO+&fjV_? zvDW73a8<|dU45fO3Ij}~Ss{X-^yAy-BPw0_N}whN0WiCi2JjSoK7YOioRDbTlirL! zM;8tb$cMXO*K?V$@M*58GnKLKNIU|9YNx?eY8m3}51zL!vzdW#ubJ^ZxDk|`vF|&^9zxBkik@*2v%+~#?7+k}g9Oe7Nx&jVmD7r#TX)+ob zHI?@S{@r$7pXmXQAA%+&Jw3Q$?K3|q1W`pzW2QSi4?yuvZ{65_{jW-}5h3c=FOfq# zjJEEK=>EqAc*`0yz~h1F-&8Q3c{yGvr`W!;{lAjOR((!TZvH(?PKPnCRHZUcw+%TE zizNTk#L;@4RSEF`m9p}o<6SdsV7v!A*soXv`(JsbbEt-Dpk-%^>{R>#4mRUw#!sK0 zD=RC?_&=8q9QUjY|5vC`mUhtlUAhW16rCTg(t`O&WaI#yI@>UbFQK6%OzzQc)`MP{ z#2=Ey2!8X$53X}faRDEFj~}#wTRiVIabIbB$Q!x4{|s8nymUUlKHaiPxWZZ)68%>u zXk@0vFLo5wK{B%FMP!1_9uXxEkQvFV6-psrCa+d*ywF!IzpDx-TXZVb$s+-0XAJ~H zs;4dIf3{3VbNZ9H+;(P86lMH_vx3~xKO<#EDg5c_0j}=)d>IRjdR{xOIxTm?A9$BG zYu+xnJ;i5GFFQ<9vYh+ypJzg$Zw>?n01eNZXXqVz{_d&3|j0oc7mZ{-tY`Ls0K*7p{gsCmhrK%i}^@Zke* z;#qn?K_{nqoq+no&g^in1q=EC7|x3Lwik!E#HGEh z3&Dx@j*ed&A!x;`hw(5NJ-Fjfx&A@|uSa5T?)s7t7&fHCdvad@`#vAm+C8kLjlq@*)>~QRP?QFss9_BzQOOQm6c~S zZGdqbPQo?3Xq^TIWBM!3vzY(x|1hWkafnARCl_IEWmRmk%Xjw@#T$$7+bnT;l`r5t zg2`);qNZ@$AONBxz)`ADiMU^-F7*H|_n!%}n;+Pr1&C77tjU0!(emIs3tlKFC{-TJ zA)}&RX|-&pjSvzb3Jab8S8I!jhVGGpjCu;RXM9^X;v+b}snRhptRXfD_5OGCUlhBL z_=wRJ{82*p#{f4^d~9SYF7M$BL0`T|H{50g2iFClwEY+oj!K_KI{9184s8{)o&9H; zg4P9iaKpbx4cpaM_kZ{O|Ec!>tE+S>f@C7d^=XhljzGDX+#KnOWIHmTYsdScBz3Y5 ze@q-QB@i}74f@yHjEN{J#W^`X-e99Di5oMRm|Wu!YY$<;X8owf^xcxpG;vDi-_z@g z0U8%oDQUur33Aj=BoYV2O|V@Vq;eiERQ{_#1OoIu)blwjo2fFJMM5`@hsLT$x6A%6 zBFFWEI!4}n3=d6Xh8yxme7T&t4hRqayWJ`*3$ir4LPq=poGtYlIz}})9V)ZE|GwDJ z>baEHaXz@Uv**TL`6k)ye`;cUO$nn-kkyv67)M4gRe>Kfu~hd4%rrN*O$M~ z<#&cH*B7+)%15t*14%+s(ypR1zsGoUuzT(EV}bIZmrwrw{~`_o^j2gBMn>=7*H_sT zudd=YcrA{03M!`gtQ=jCcr`{yEY>?T1O}dUkuXM!tF-W&($gC(Hn+GXuv@#$41fL z-Mu~O1i<-FlBmDFA=wctJtIT!Y!}mlOm52J^!DceQ1{;9T=!wvur^U7QKHBSk*sW@ z6tY)#${xv%jD`q_j8uro&dT0Jk|f!i?46N4pHuhqyzg%7*#&FFGEqlYG4w=lFvfjoh9{?d&Veo*>niA z=4>l=+BlCAk_VHU^Hv?W5fxlaMsRm=VzDt;#e)0XIS~fYxGP7N#tfBVuMJFU=^6huO zn^<2>gEbZ)p19`64?E}O&f?|z-aGCa>!he%ZRXdPkC(a_x5?Bx-Yn`7OenH88ZX~ge1o||JHZC&xmVl zZS`30pB8ns}o$Q4^AwTvO>2_y&M&Tcv3<=i=1h0z-_peR{LdBN3m3A! zKl&F5xDw~;5F0`eMWaHH z&wun*#P@xXcrvGw*i`$g_U${m_o)}ZeQ&gD$xj{rYcx6(DSW>yBcnV+al0-e;?0@H z&@?r}#pkpanFR%zSVjeR@F{c~UH7mF#=0x(=-l7ldVGIbO6tzOCtlsmUFHYnLJTxM z4E59y{7MX@YH4^nb*s5LF0dk!?ci$>mw|@3>Tli#9v&XEbwPsmCNeGcZxESOUOl|^ zw|?vW`}d?HKjYp!MXo61IyGDUS4>5Fffxj8P_ZwV4|w^9|6Ck1%m-QCgzCSwzMq4& zo@}k#3DC(dySN~ZltDI25YuGtAQTl*f6Vvt-x2qf9%uFl4j;OwfnsY9KHq$HN>uh7 zC8)g*>7KrblMXgTA6zb~`TBP%mD@N}6NGUwi$XtA7Z-Hb^~v$nE2*Eg$_ zke>c$qmVd)-x~TIElq=Ni!D^!`eluNyNMpHc+@!~sYE|iRrEPrm!SH;Et+!TI`cC3 zzC;mI)%O;BF`w~c8y*m0^+!M@)&bIvR z5*K0>RTV65jZv`ZH=;+sewooc3sXo8+4nLm%=hw{lM!FbghZ$AQ&3O@LFoaG-tYR% zoi4q)OnicUyFbqwK12|UZ(=Gp6=nSfzun21H6GlO?;fQK00t1gH%o^!8xZNClOA9K z2VdWRY{v)?aJe*o!Rg-hX}DICMd1x7xy{M;)Bz^O#xiN~nVAw==JU0Ud_>0HVS|6j`cUap7E+=Aw9QWfA`JQTTCN|cr zlNc4P?c+ZF>{q7n9MJ`Q6Zu|HZV2pBiQxv;Ia+VV=EtUvpJc2ph<7?x?H%u2vR4u{*H(HrMgpXJYuq;2TewPtR_L2bI3*pk|6VQCLy8)I|f+5L~RY#+n6ZM9_>UcQr4thi7aVH7w1( z6BkSL;N)bxl|@k%P`DQ>HoGTy_|sW&@xJ$k$+LY=h^hE^c^@tBPtz{^`ceLVeU1K} z151e`IhmQqFI3dIys}((Y6VavygN^&DS{W*=Dhv>!w#L8Qmqm zJlU5Yn6|8T-ZozS%K#UnXWjE@VKT{1|Cw8t36-1E2Ml|UGCybW3Z1-VWM~M$Y35Gj8ip2grjH1Ubalho0N{#wR z!LuXo_kbqGzG|6+;qgg|oKe$akKEu>*RhUt-A_%P1=xjEZ=R#|=FR^1B2o|ZrImTlHjQPk#{VRv$6W)_FtPw1^4tKk5+YM zSeU!nc~*wK`GI<7WBqHS4D9S(hB2y}8Jg5;$J8TlOxERY7%uBP?GxxQ-53`kfBsY; zOZdHs=%KG65fR0Pj|~Fm93mJ6W^Yo0FB**Ja5K?Hmr&)*D{7!BoBh0kpq7m2Nc( zzt&{aew2{#^@+c!F=xt!BX|6%>J2z`@`4o-15VCx8g9L@d0NEN5N3HodT20Jv<2wev-itA)ZLS8S`lDr zWEA@1#oYRgPwEdcizpag(TprZ@*YYMdFknW7)=QewT7QJNY^W#TNr1srnQ#5hK3vj z$))#6lOC7Y8TGCO6m$@lYeSw%g6=NO5Q2drS~bxZ-S?cPJLMCbpc`{tT{+w2t6s5F zR`$tztP>v}4@$UHA10WMO0HWcLv?^dTLxrbZvr5F5S%SiAkL;pDIO485x<1{IEN%PyJu)StE^Id$-B$T;?TM#rMFD zDReT&{UEHHx$DSP2OXpLrsuRimW1TWTiVyk zoO&xGQ!~K-WxA`u-O7`nXVZM>=>>$@!H+)(U*8`>HhBD1Gsm9V_CU&?bK-i*QV7X z*oS2?xxhxvd>SR^vXI1$;iK4QWV7+q)_abP*9Xi>$k!;HYnsd-zReM4*?U-QBP@JHY9vV5 zaDn#JHY=y-6B?~cLWhUWi^;1F{@RpoU0w$68XO!P8y6>EN|~=Uz1~GD==yYmJlnNS z_5`&=6}gww%;8>IiV~CQ6w9`Z>kF^AZm<2oRgyU?TlR%dljxYrpL~YT)q%dQuG{)5 zkR#C7)$QKe^EsUJDx@?x^>fs8`Mha1+$Z_B@%iv!U!K=t&FBlwd%gsz6lR52L!+ZO zm^}SQQijq_Q{=ELELWbqm{z_v$|P6IU#TZOG(7D4Gt;QXjz5A!fg(kFXvgd<*BE>Y;4Z+a%^EG3SbfC z*aYPh4#l#VV>brie&P1xF;CZzxRRUY(- zP5#xRk{`3}4-yljg}wW|Oh{krHe1Q|hf}|*L-jbx+Mgd;*(>uVLV9oS!}lS3=)K;v zyttjpB!8YGUR0p=bZIb2loTO7CI4`d>b~E~a&UC?(z|73MldW(_I56w`m6Wi^(Zag4m(d z#u2tc$;+O?C+gM=K!%Gkb=~Yd<{+j!>bev54+UL*fd3Soc69YNujjFyI*S)z|TUU3CvcR;y z_x+dmQa(~_PSqJX*4Ns}!diW4oW%ytva`#r>KxU)j~Cjrzy0dv%bgCBvV^{VCA>de zl6Z4D3Qx50*#@xiu=|t6zDriV<8kOv04j;Dgd_wpFOr8z9!{{xm#!?ZE_UVHgs`|= zc)gweq<++Y%a)ICJ)ihtdb+}$JE!Ow`4)LDKJLmkb?z5|`a_&PueC+9=Y!Iw7()ex z=g*%XZZ^nW`)t5$*A{oFg`tH|=w$*+ocqxotz-_)@&O6?&VZAw(Tvp+voo~l1o z%-u@r@D`_(@?u=$h_>;QYu8AVtRWNm-H5w7;G}TfXrBpK9qF4cn{$KZM?-@3OWo9O z+&G)=<)_Y=(MJ&=eUi`O3uvffo?C89Q>(OHd$@UcsLs7&x#M9mN$k82G)JN1!*+#U zL6&Vcd#Bo0XETb=QKmLlv3uAOos4Z1dNKI(sw{cgi-JxDFA`dQhnfLn%hq&Rd3pDx zbIkW_l)`fL(nKZn$lC7Z@bV?o)%H+V58FXaV}gaB;KA4TOFUk7oYIlTS)pDwS8P&J z?>(knG?iWm3>Z7>0Sdmj+iV*sL+);FdU|^3URSBk+KyI_P8nI5ad9ttRi-nLux0AITm7(H z4i~+}WZl7r)&_oFUX)bJvj1{PUNajrMC5_n4}H{|#w`hNZ^HrXotX7CM-83kFbm(J zy+0*$v$*6n8QUzcE9k2bp!pf?see?V@cw9D*~q?q`)qnk##?(#I_8;l@~y?3KD_-C zkV;`76+tGc=o{aAuva8Fi>~SUZplHGZK)4y8|#5&+O}JsBQ|SD96vve z&skQqJXIc=l-3$|b-BadbE%D)0nbQsb9iTZN)=0o=kEECZq6-EYEDeQ zVDNGJ(}{GmuP!40{j*CI-bpzM)XhH=Rd7zdI#rdFjt}vk zp<`phAtEBA-d?i$Urg7Uhif&^3&O$5y4su!9}xXc44M9EA)^(XVR4V^&z_Y)mPp0< zg=XCk?_b9s9lA5r5uGzw-k3fWmPM0rCe8n-s2judtR4A!kcZ&`_a?&5tnFU2^@W2S z{4XLqCG>mV^$A|O!FEe7m50Y<`U#pjzV zE7$e1ZY|=iLxO_?Pm>ZK?j04jcct~TkvUHCHMWZQC5PTzbw9&tac0ozcE}gYLBCds zJ&v^L8mE#G!P2X#t1Eg($toxmdTxLI8sJe8$d>liZfHJYq9fH5>M;0_0J_j|wLUw` zgK%eI_V{^vD`*D|^BGt9wLllfWBJc!C*NeA4Jn0wsm%J)=feiKtM`P7cuWbbFWoE;l`UKag3Gv#H*SzTacFy8P$v z2~ov-jkBz*Y5Lg~MS&T`>+K2h0gP4}*0j@o9y-N$Ki|^n(g&hY^NZlJ-0W*HbpiKI zUYmXUo~X08Awg+r&S`eRgt zzK}qX;a7hUlYh8P7v)X!4wI1|C+tTzx-_rq^7#eV+Q>r0Rc*x=`d#voT&&{dpMabG z>Fzkn@;sa-Z|281$$s~Sig3$Mb+xLrP8m8|GuecLNMVY#jj%*fvU)=)BoZE#9WW+OGZL}=ohLEoLBTXIXE^u(xXdmCm%H#G1>l7 z7UWEU7iZeZyT#8eXC1w9u8MY7*JU48B<~XE8UAJCD}h2Zwf`mNWy0Uc{{34F$^Vnq zlk5Nj1O(sdr2hT+fcyW>kNlY640`iM?IIZQ_>!3B;o?ef-N=d5y%V)>2U);lpIG4j zha~*pddvTl2d@lusi~*{R#<{GMl4!0l^&u>2ZW;DL9Q+~HsL*bGh#Ev_YyqtjvMj( zZ6;W#dxEm|=SbuDLFx(Zb1%ss)8Buyi-7LDh`zb9vZ0fL_k()PwqL=8G*hIz2x2ZJ zubvhF$}lx`o$2L4pQg*+Q1;^GH6M=#lE}-;YkY%p9m{T(*~n8yL3Qj~5Tn|`BDvBByKHfO& zF-x|Ex+v|qT-_CHW@%|^Wb{q=-~%C_o`%4f*8llZrvs~-nwvwNDd>DbK)ci7b$XZ6 zRq;pKeedY8T}emBrn){E?)eK{KuzGP;Z$n!vKN)$q&JI4ULyvIw*iiNPL2p-LHoL3nxx+?==(QYUgpI zitFivzG-_q6wV613-`t~C$KzFAW;iE@^FJ*>Vfnl z>ZucPg`2;@zfGEZhf0w_sjIQMIqS?*Hptt(OG?_Q8?lY5K@CDqE_H$7uut|~VBY>z zZI>QwYspplsvi!|vK^Gh29X@yJ6j4qi6BK&py zW~S-c>WYd1{JyWR@1gAC2BZ)W(_ycRM3-pF?Ym zGY@929}0B8;!J@Alfs?2rRA=Z+3{%#>OCY&B*!*i#r6EXSAx3^^{|u2k3+91Qo#1n zn=NQOLWbuePUaPVO4WqxH9vncd!dt1rDqQ=BML!7Sz&or9Z2v8|NPM(Peh-C6*TUk zLz$oNeCg7|p?gj;8^4V43YVRv<(vn}^kgsx9urM4AL$dyaWiiOb&< zRciwA9K5?}*b6uNN1+PQVo0t>))ISd&!qFrz;5+f%d__JM#qORWM`%xZ1woc7QpnM7f^4J9rW_q{-!u}+ z%eSE;=tFYiqfMU}2BOt#U zW!-=d2su@v5pD^D>GZR1?F+0PoV&-a@!{UaN>+J!xz#bk**%?^hLzplb&DL5y_q2E zW@^e~pK=c){+s@k<{gaOiB z#m+Y1dQoxeo}D_xgq$%og#N+r-@j3Lxzk%B$i!6D(y|D;1}MllgAnyvuZy^t`XS3Z zTS^M9_QC##pKmsokfELgg*u$4qmn=B>KGUpaBXdF-~PL`c^?w7%5l<1B(1Ei(G1|o z!rOBC)6bs@cGVB?wB}}J*WZd1HYx)6Xu^vFpgbaprp^squ2-*)*UULUV3V7>v8^qf zjQq%v3pYRQbU#R5i?@|cNKDMPAN~27$5h2rRorbQ(|%OJL3pnjq0>}5c$yJ0F?0x1 z$Hu_wtDWx3Cq2&fU@b>0+ho_SUCkbYEvcHHKYzY+=T5A@W>H|UZbA}blRxcQQa85n z7)kdTzl15-I$meaF51=J(V?8k5BM`1#|IAx-u}XL7alkpVm4TmFx}gSO#fL~2{BZ8 zU!FHmC{1|oo2;`xoI{7%{3}b=*6HDyS0TQC+fOzT;Og@ zKtRBPF*74$q`0TY(o{$DCATZv8-MEyYzMt;K!rW`gX~KckK4-ZK4MDryV@3ZdwK0O z6#Yh-h-C8SO*%&gNBsAX1VPeECb^eN;y>&b78fmV%tKb;>$4M5QCl~;UqeQef_6Iw zYAY3O{QUgY&uLR#UdMh3JMT`!z4zBgW4Vcaj-M}Gz3M|IIW2PK{!Q6m5>7i_iH`z2jnh3JQ%E(kJnhRZ`-hP%$r z^*?{+WoHu;5gk!5C~_E2)5%|3p4p!2;DH{P1rt5YrfJp+78PZNFLe~q$Snjcmrwo(an0KbP_SX)`Sp`%k> zRkd&b{$42Nfu)G+=y<{=msa5Jr}p-O^tSoihnF=HA=LW#(Ie=NtuIaAUt2KW|F{9C zfcmA&{7?-VA&_ss-YHoMTin8Rb#TbRl2X8xYY{>K1-TydcAF9*es_1K8ua3n^1kZV346O*-j9qTnrymxoQeCoM( z1Dwiv1QwEigmczv$?l2t;*#Rs-@JO2l$ts@F!1r_=iQKMcO{k>!$pBD$Nr7Z-NRNb zEi6!66sleZ_Bw_=SBw^``+>&d<|)`Z7_ZkqIy-)W+KuvUZ;_*ATBwE%SUi~9#aORo zd+Xl46}U&}@-w={TEoDg=LGznKoFXmwK6}N^%UinND*kEZwVrQk<{LnP>O3QCGE%W zpef~8nWK}F20|Zh?joEr6!>vzl8YAz>3OMl3~AjPz6d@`4GceleB)Rj4_pRzR9irP%MRkN@pqV)!%ure#k@pDSvP^5DH(+#{D^3*JuRoL}mVnH0;XQSbMprCw~M4DE92$?Zu;{3hSd<|FFex zU|;|{146+t3>ac6=(8;?FO!mxoP(@g*u1#=8ZSOo=bJQ2QICy+)>>rvp!RTFv;`_= zXlU3xIXgRxa1BohQCm?F5nTb&h&sH&^87qEFYm^9V)W8X-+3}Z)Elswy1F!c_2|{; zu*%C!f-rDz>3zftQ1u&zEMx4IG~L3+ni?6&KZ6EN`dZ$-4;1R<_**xFc?6~Cn!6d8%p486#Z;SFFJptY=9=BA~n7-(@4TE{1N z&4N(QM}-WZPt1Ld@!SNYOn}w5HZ`T*Xu-+l;pJVJn@i?yhVcgX0#jWSBltPExPt0T zRGX@*7{~}g1728I(9X4BDta7DW~!IuuXjK~O4V4n4?frGNZ238c;!EVN0>xJO0XM1 zpbqs{IMx25 z&LmpU-rKeK{_-9E2)wstKS`gXH`%dcxnPYC4BYAuMGR!%xw!}}@?4cI(lGj0uV2?i ziyL$&!W!Pn?&$69MO+fiZG14I4#6Y$;*p5DI}Nc_Fafyd(?dgFOtR4ksiLY1HAy^7 zl8Z)~w(-rIK_MYno~@0)iu@7N!^4i)l4I-|kQ#uuHB?5Fh8ShX89>Do#tGYde`94X zD2NP&3^XP7TUBf-IPPIzE@jiZ0-gxYFpgGf=_dY?JSbRWh}QACNWs4qPl%fm);{s``;K4(vg@|c zE=Az0tQVPV>hvZe0=@w^G=MA^nz0)K}=6<0M-*d zIAXB+Uwn_|TX#tlc9eT=<8#24cn*F&WXOnf7w6ilVuO+gF0rKE3g@|VNQU1hI8V09 zw-0O2cR~U_4`3g%H&atnWFjej?Fe3xM!F;P#T+H1HKe2v@-=Ce5=Fdow>{JF;K73x ztl;FM5OG?}Erv6Hx;^VQR52m>H!?B;`E@jwfE|Q(TTpZ`_X)&&(C%Qgu|IF$zD4ec zrWc^!H4k>}xm{XrL{N2MUf>N=Q!bKx!&m{E2Tj)(t;W`|~H|#Yb!e1mBcJ zjR~=Mj9v&8h!d46Z$nMN*wobjZq>|Bpc}OpZooJ4~Phuor9P@?MBw48Y8&5+`}n( z*WnU1G&HIXFGmSEk{@0HONkt6Cr}xuT}M)tQ&7;})TFAVB?x6mD3GcJf$|0EdnlV@ zM32n1YXYtdNg#GTd9qLa8)D|_XD8xfV(uc)f!nZ)n#Y?aDnwD!(3F_eQ8R}?FtVbe z0;_m+ALY@bx2>#ps*}ylYDAWWFidJ{=+I&SQ4}rn)RdGODk^9GDCx@{YuaORtLhTb zSq!%$Km41K)TtFsRTEcm;fd%WDeFasgaPrG$Ljo(+F@L9Cq&N8B4}%+Lq)w;x1eCm zogpD1p`xvkWG}1K&Di&+EmiE=2fn@vF+5l6%_HEz0qJLS7rt<&u&W%L8^L}WaifLq zi8VQ(pXaXM$x!}!B2}s46)23VS1`}sl*gYjuLH_VFfVA%c7jjGbPF_+TX@IIg}dIr zuj=WTlbegH&{ythV`b$w`jd9zk7z?9GK~v}C=doz|NDXuEQf##(nAz=AT=(4lBlEc z??CY_u8SALO{U=+vuj~Hnh=In{d1i9HPEV`vJ3;uryV{LPSEbj z++JXZWsHYYNsN8MLr6+nzmj+ zsM-9CxTrXiyOUsfk)=#tQBe4a^?5?Y37z>Jtm)UUU(i~==jy6a-kIVv@taXZ^=)`~ z{>nClTG%4xb1Gh6HvuyNc|2wdJf{&n(^+yk;|e@%{QLKWeFqi$EX>S6-&8+w14&l$ z)*rw~h>2pugW2?m!)xnmYTz5nxwZg*E8qUwmIzC`6HLNcRInl{)y=ayam@E_CJ$T7 z3zJM9{s?popmkMR`toG~K|vzncEn#-=*WPZI7}iE&%Xm3AIAAMI@)t}-k3i^6bT9H zQW!Kg4(-=trXloPn>tOaXm(_PSzs(Jq6#r&KcUW*6Ha6Apfgv~WS(a!0|1bqV?EiIxxv_2CV_#ZwZ zVAY<96~nLL%Ek}u+lw-$SrRTiTE7bmS22Z2N=gb=^*#d5nmM@}!pE}5PN+(LLmmPZ zGf#vlSo|3zjyN%paE~i8Zli^t;^0U_t;lKY*TbS$62@X!z%VfdIXbev2M(a6AF+PK zn>XCAulMtL*|EH>6|KJf-SiD1GQ-f9FFjUf=`UPp`0?Yz0A+>)hZ@V?*P7bN5FN+< zE1&fLd~;!{L$!j53Wf&pC2S6Kr2)*aA`wN5h9tlF3022_VS9|=n480}gIK{XXuShc znj9Y&M4pAE$0`M$yqG@VPNi~quU3e1dkPzN*~bO;eaWJ&q63& zw9Ue4^C2Cv2VJZK#hN>7Sl~cPvtl;tGlrn*@A|=!NEbqO#tA^0N_ByDr?{)q8|7n6=mhug7zaY zW*C9v^!w98zw8>ySG=j1Vy1|WTpynUVIFda@56&(0m{nCaK`>FFDKqneL2t0dl)9N ze$ZFn?eTslK|!rgqis^#iUfs~f07zf{b7BkX?CJQ#5>=*%%1wzXSEQgB=zw!{#H_kFFh#NjGt{wZ&59#SYZ)L&pH^Xd0RpaSX z!UjdClU++}T3lE_M-Xg@I5b2|SlXw3aJ?r{J9 zIzCr%K>;qmCr;kNcoSSOgY>hcOFd+gPoW@xH-aNlkMDhrX0&a?3F_Or7K-RE zq(N*ue%;K}bkwiIsw!5U0m%wtPsCqSyN!2RDr5djf!hC_M9%EW}< z`H$`dubUv6Ub?z=l;M%1!NGpa&!?JxJ}@!iIzJ@C8Qz893V4&|WO6CII+lDVpMRBt z5!gT}5#J6A`90O~hiQODEL=SVw-AZBib z_y~rcB23Ri%!z83J#2W(3r`Pi%c^X);SB za15wT(@!T3I3*;En)EmD%z5{tX7>HF*)o2PyE0nQj0BZ2C9Y0URFvyb?fOdaSai?6 zxE>Ugn`uxuBN3nhRgDv)PG;{xuomC*&k2WQ>0&M%=M|zIY{AQXBUq-FU}*TD#j`7b z87p$*oX}(XnY$8VVFgYH|^DcT>avSfvqTgcRJ-cY>_kb+#C8vM_}dDc=E0Ov}!YK5J_TZx7MZ zJvjF(a~E~$+BY&hxR#&nV&)kF0(w-dlaiErmB}QpX=``lPw60vxX!q{d=%m+{dUZGR=|m zC@E_y!GXwYW4G{Ek1b?^4WQTm-CJCaq*CBe+8qT*tNFq)B<^z?cv zD=WLZH!v1S=qFqaQ-%0pJ6<3WFC^f=@R)K7cL6C(ELT`j!heO+0ghS=ZX}ngFgwgd#Muq_@ff-$cdH2WFH`mKL4Iiu6 z(M!xOik7Og4C`ftDB?szdaq;ns@WRLq()3H; z6y4@yV7Lv859NcFh6cz`Ud;jjqp}}CP$KSBMJ#Fwr;Z#kymJSD+s?EUB%FZjQoy~h z0~&&PN2n2hBMTmL{!oxEYngn@*pK)v*+=7AN_Tg6XXj-*oej84T&3PjL#e71ee4n_ zRVnJJG&D3{tPi8KN*w?`*nP=s*dii&kyGbcSgy*;Pa_KP3X%z7&bo0<@+rhKz@`8c z4m$zQ_tl6S73<)zFk=ggHGCF)L}beviSFvLlqa3AYf%c@tE16~wGqg`1X#w`T{D}; zPM4sH3g{l8{o}_{kgLd~_w7oM9M+aZfScrWZQpN%BY(ODA^HX^5-W_-kDQ*K`;S)_ za9}=$Ddy(LMmS$NG<3ky*jW7!yV{yRo!9IsJvuKg+JqzfDCsX7{vzp}j*AcEJbQ4j zm-JC14^|>QwY6oY;BXnsM%~YbZ1(NT?&ibyy)41ray%m_SP0q=!kbtyn}fI3CNnB3 z=JS>EEm|f3t->a?XjcUw6VodmK`qOyAr=f8KyFVbsxa3{&~ZX7#V6R`pSb1pCTbLj z-~fT3@w4Zch3qtiONurF5EJAHvp#-g zKJ1x@W1+(!W2ckkXs^;6qH@dH zIt>l+BO}c2hn^BA(=<5xrpDWau?ntWT7pdBYSQ{%&T} zmhaK2UkX3*P9Lg7;AAPj;(EBI0)HQuegz+b>o|#!-qPR4xhDUBd)WT{(`g+LrKhjJZ4RG55P z3JOO1)!>Nyv6PcPNnetw+^J_+qEZf$B7B#;wf*tbWS#0#@<0dAIjJ&0#y|i zu>-y`2SaMyfFdCEg0)5)F>36LRJa7PrST1B&9)NK(%wTYh^3X!qZpE;`pS#U(sJ^@ zTobyGOe`$u?@%! zJ(X6Ku+MVmxwudQvc*)K<_o%ED7ySN{gYV%hkW32zb1w{B7$$$={IC|jFDaigo@xF z6?c2&(kN(j|*(mZN4J{g6g7_OPVt0qHs+W`jZ zA!HR(g0Ty0Ggl_{#zy!TG+LkiRCsoHGqv+{)#i#C6Rp5+KtGIP57C7XX z?+|ii;AS=cs-jbqHczt~C4Cq;G%C+np*nq1jk4yzpPxrK=6DBr!a^q9?dbs@$Y{(pz?hheGt`F+R; zchDUU9Va}=iCgJa-kUJ3C>{VaQL)*nmE5|eoqtEKlAqy@uu6x&*)3Jhn&dERwo7TD z2DZuGOOM0Idy@FXmrjY#G4+(N(|ai%a!l#)O0p%S_sc%aEkrsX`h2MTzP793)$vv9 z>-QC_UawnzluqL8_8|bR5_CZj-LZ1-UkkFb%IN7u6^)%|LOBB=FlGx9C*lDU8XxDO z=!@tAi2pJ$eV}HsQsbJagdze-dS{a~m;!r0GBk9pTu9kLs1y(!02$CF5?#+Jy+}!2hV2|62)KUCb4Butgg>GCQkoULFM~0M%xSkURPBb3=Q4`_UJGaA4d{=VYoaj5HA!E_P=SO6$%RoHT!o(f|IoJjte z{fm#oPQ^_sNnSH=K2^caM2}!Ft<_u*qZLg}sZN~&jd2p-6Algn zFsXLO%a|=H9S5c)o4B|Ewxa45NKj|N8N*!CGiN02vXJHwk&=2M+rVZ3CUzeFehdb> zCN%^TMkkpAkaeDt))J&B&%zW@dS-cXgPKt&#`%H#xYSP18x zuVs|OmGdcc%o+v|?g2ZRLGknQ<-Hi?e9`8Vy0)$D9GFAkOyYjFmblo%65{+L@v(JQ zkc-oxMy%zAbO^9a?>0Jt5|fgi7R?ng?^tjnuHz{E0mVVq13&>JnWM~+jZ~bSmiT2Y)s0tLMVf5&+C095-wrs0c`F+1}m26bqp!4G^N5xT~es<+b6{4=h_?`9xEghY%t}ad8*7o*$--757f&Hkh z<+*Sn`CeO`6}`G&)vfW32R1LPJdu z?jIT!v|KkoA>Q>$^aJn3+{8p$l;9Fh2Pz{d8zcEl?XP@b*_)Ys_=;L_Z03y*2(J*m z{D2Y19#lBdpu`+fLqbekTT_F}j7k)0GoHBzsjP`wzF#pu+t<^h_kE=2u1Dsv@<;6k zUco7iHW&S+C}-d5(Z@5vQv02XFc+ok%>EnAm1Tp}XEYX6 z9HZOLKG#_P0cqB`l)j4hlzXmFm%-`pP)te=67`*jK4M%PgMHurB;l6M)h{e1@LcH{ ztBq5nfV7T~lQ+JTIzUAg?pIj|i3V>UA8~Z@ArOM!Y0(yzpnWmo^H-GL>Y>D^(Z5du z1u+Dd^w1%_{5w%4gS(ULcc|=qd$mej7yYOYJeX)Z3*6@|x=G=znwoa{fa7U`_IjL! z3ytD3tbjoo92mgC07cx$%Ie499Fj4FBMyH@SgWVdJoAnEmL8npFdF zAleO4H$})6yGM2Rx2RCf-m+qE(VL$hK;dR5B}Hig$u{D85U)a=l?V<|xSmi~w6n9* z(4hP&BoU9GKR!9x_mA|Ut5Rdej41^L0?-1W4iEZ#6C+2jxA*V*z5c}e(63ML!j+@s z6cwq&jP}OR9QOG;TuWs{NcSAtWQC?4yLfk-wG#x8N(-mGZERGTDD)*bhR>!x`MLlo z5y2rcZZC_LkSpa+4yhOZ>n|4sa1Rr!w^I#z1x>e$YHW9MXzJw=fLs&&#Q6%7oQ zYr4sO4EWE^?@B!WwZgMkEIRt-mLNNOY4^gwKrFtyOQvkhqjPvc+gcoV&{cl;6%&Wi zUN{KqTXT{!^4IypqXwvB2;X0t0#Jh9UP{XUMw5qQWzZ6nBmI^hRj~JNt_HfgkPJ~% zQ&Cq|)zAPLfZmIOVuXqkebA$nR8%G=@uO5je0&yIrTK#oPq*Sqp}v43+BL#LfS?i* z61iWe0fI=HnVGq|u3py(&C6Q?vlxl#`}0dcK!9mMZUkgK=tmYI$^hjEcWA=6D_PKO^RF$0_-F|En-dYOj53%B z+f0mn7Zh=%wsmhsBc$V6R#LB_IH3;%U)i881-QH$z;jLJO&lX|lbE|?!H?$$c?4ef z({;}ryc zD1h^s&fMCsU!~XDv6eATe4Qkh=*Zk;HiB04>oA z5b*37Aw5W!c=*>?Ik2viSk>9io*hG5zmJd4P=|iG2SB8Kj5f=pGYaJrGc5*M=_kvzk|fPNT|$#I6+M0|?CSUK!-^z>=P(#^??aGBqoZbW&fts6|=Hh83C#NMamk>j+2-zaU!ioD? zQ}e<=_hVe+9?7SWg9b1FsA`shI)Isskny}nf5kqW7F0)&L<5F*U{?jV>v}$gV1m+}_ySMAX6yBLa96 zB;0N=SiXG0IPVeM>m4)$K^cZ>gUay{AV>cIpg62WWJE;QqkY6XT%wzw9|0`^Dgn=g zYl8-Sgcv?4G{DKh?zXd}$}a%34+KQusA$~yjdMsQ3H$*3K@=Mi)w!Y>y;6+V72Fnt zKRDS;UiVyFl*d2A2Z4seZ&+3gP#han3 zOD-EU-}@Lqu$q+zIcUvtuWg4%MpBSq8*pQ}n*DG!lF~~`tR$~hEj%D=#C?Ej)6>cR znE2$)LN4+1;yNQFXnvyuG*~@&qEZec(`-T&b2 zO~9$_|9(-GvdFLq6@`T)Qzg_R<4UH=JckBDh76f9WGGZfW|B-vrjV(S5>iP*8H&nO z5t%Y18P4bK*?YhHoPC}5+UM+Zw(Ggxe=oJHb>F}H_xpZ7(-$(F!h821k|j~#!`&sxZV$)wpd(JV@DDJn8j#gq*dT^WH ztfW&UJS&{U{Pg0bbz_{zbq(&HE~tp=S1r& z1DX^cpKFj01g2u)^CN^;bc-fvejJ^fpP%R$P)6;}%yPfK|746hJ2yAfir}4d{*<++ zLGNs8noQZ%c=}vfqV;-w4yBZlZLIaE7@@&N+}S z0lit+eBy%cst8;eOaN4)qA+t0M_|uekMB(r-@p41UXYFskTB>(h$m#nj)cU-p5ERD z^D`lBPz8g!Q6fLX6MLf15JU%Yx(UTepO4Y6xxY&T!qu4Sfi=`ztZZrN&eyNS`1x-G z1QO5p+8E?J3>(ky&kwq{6>KP=RLA-qG_>1cY=TE zzkLUu=07PePx9Q&MG|;`c;aM;+~K`1rZ}zRUcj&P{i;&+`8%C{I^-8CiyGz@ZP&G2 zV9*tQZMB;u%59e;TQe9_dCYCL!F22J3-SEh|uCd9rm(L2T#<+beHK`Zej+NI*y64;`TBA zq-G$zPi@PFTT;$AINXejbBC%GER5XDqg2n^T{01kD7eQ)%*x3#y$F)f6P4bY_p?Ei zHIzEX?98uim^V1Z@O*Jgc-e7BME=m&9ZD6TUX6-MQWx}&Ne7jIa=P0zESFh8AYU^( zzS+^_-Z$yp)<3yI$O-u_nRgPg+WtVHD`8n99M?q9RpYO~^G!pSN2O9x3IXIVEi0=q z1(XCO77pOIkP#z~@B*QS`PTC8GA~?F@IyIN_(FokWT~s|h4ujYC}0M1yypR-K}!T} zJ=$`Y8E(2r`xzVUiUH-|$8;|0-cv>`hZg3#PvjYls`2`VWGMsBfpiKA5EgD3BJm;1 z@t3OO^aStr>;20!Ct6?DUz89rUfI@Z9in8EK+&_3I=#W+#klku8l_sSiIF!sU#7hm z8!!YUxXvIiUb5<573(E)qhRvsw%&lf>DalU0V_7E$j5?&_UTo`5JCa^(pqw}xY;bY7*tg#AyBB|m;?fZ0|d0q zEV?H^w0N3Q(1rO;J~pn+QaY$4jBQc7&=i0QY$4z)rwy_}Injqw(Thz?6!rd2MqLyi zZ(wR_f96cLNtBwW=NvvJA{+SQn(!l>@}9;H&&SMh6kS;Sp5xu$h7D)0&rfS}Gb)u3 zgiiAa;Pge~i(bjvO9?SBW)Wqk69~Bzz%F2XV)0U{^gzRR-ov|| z^q!Qmld~HC6=|bFvgg_Hk|p3M1B39gs$~5WfrZtxhl*BaHa89=So`o~Pr9m(*w>eq zb4=*{S1rKMYWF%C*;FhMsU-RcftaiL`LuFHp(|l@)#|bL*bMnXjvh5Ta34X_w@dT^ zFCp2Zdfw^WxxE3(ax{53!`ihP})Ox4^dIVqHCoh7uLKCnknz8c_9u{o%IsOHY z(!@qQW<%%zW{s0^Fpod!`RF&S2M`Ync&Ra=k?!I?0Kl02gJuUhX!=XgwmoH~0*3c$ zZbqk$Wyuxkh35x@X3(~7*qxJ8f4PIOw}KMHqX!)k1g!0!VpLl(p6t}A0hGdI!tQa5 z+5Ipn#-^Awp{PG@Xw0(f&Dql-+j3@k?)l7_@Nk60OXjlqou-$*&$ zt=)D~-%>~Sw%)E?>;f_=ydy!pyaKLnRyCM=YGl@Q(C8;6o6dpqLrD~_U}Ea zuKtusKT>sQe7xnW8xHPe>=?LGZ@LS4tY8C; zTlJsmQ`?wdeEzHet{Q|09%*cDV1J4y^5l49xE6l~ugWdB$O)K=tAul9wY!tj zq~#Z)Cj?~|Z(D>k93)W|Yn)0`*DQ|F16CPDk%glb)3$+?;t_!CAT2t&e{fLpRDHEC?>5;A%ji>3KQ`T*LkQdqSzKTetqM-Yj$M=us)Tz0R}y|1qs9QzI>~UN#VM zaxL|=vB_59|K3@UG_MZA8&GhCOO?5V^M_5enV$?SGj;4XjTHUt09w+2|Enjeqp%IWN!L*;?P@TLE)cng>PHQjXIa10q=+d5fb8r%;@>(?#kof>S zV|{_Eg?f1~)>l+`>gs|seUwoMNrJhAi!*j#L%bOiu`Y|;LSWDbsCGXi+Oo(0h>MAx z-LrT=5t>D=jKEfqtTW~~LQ=k{>P z9DCq(wLLevgLR*ntkU`@UG)Y@>L5-uf74>+9D)uoo>|xg8Z{DRzicF0hEPaxu~eRb z)zZxVnR@=S{m*LgTvw}#`iB{RlE(rWJ4_NFf1G}gAvL|ve@Y6hJQMf(Afz20CwjZf zxw&EK+nU9|z%a(g)6XR(Wh~#y9n;HR7W?DN*=eQVKkYouw8aF?qtsn@6%ty^o^H@% zTP3a4<4j4H?pJ(|NlD2wcy;2dt=Wy^Gv0|zckhuC>1i9i=>@pQu75bhP}9P7_FlQI z_-46ZG{1Pth2;8Yepfe7%DjA9MOV%EYLN70z|MM#5A57Ie1$gv zb_&tBCiMP3zklvXJ9UlhJ3SZ*Y4E^TP(=1SJCJR(jb%^6M&5|V(@Ry-5B6x5=@b!Uhy+m~j7G{pwrW zz|5r;_t9L_t4%^;KVtH-Rij;`yxFu=Ic+Ejw@auFN8ZIjbjN9G(ZrIy5rP`YHL6Ae3F?O#Lbp*= za=3eY=gyXzs>a^Y%zo>CeSJ`(US7v)#{*@j(jVW!Jci|L6bLD@d>o#$qrCLjNtE6o zg}Q4CQ!cu*cufDk00A0`CNxf?8u$SFn6K!c@wxS;vAKB+t^;h&z`fUgW*LBp{PX9} zl~&K*z1t@taa}VTCIb-KC=nz~OP@{E2d?}+!w`Df#wH;-*=MXv{1&hRIPoD1f_W+r z&koC-y7y;gl*xpH@%a*H~&kBPPDd?=uy1}TNsl!!p zpHhKa%(c%Jij>#TxuJ$hOiA$r$?DW}Igk~Ofz`$CTE=_(#7_o`O#9jVVD4E86bNVa z?-~xz&7RF5X{Kjd>)u_O(#$$9KO)M!-*Y(9w&ROJg433Ug<1Z_mF;tnO~Rcph5!v) zal}K9JcFCTkK>ed%uRRb2wO9R9yR%(Bq`Bdf6K+@O5uQAfgD?e0( z*u+-!laLfHb-jICdh8nyP!*|Prp1(8gHasQa6AGmy}J{S@P}{?QQ67rg@v#c+y~S@ z#7TT4`z;7;*aM((<46akCl*Sr^UFnnWuG&^^|G&T70yj+=6&2X3spI75*Hu1%W+I3u=i-;P59(u;E!@)J&|WQ{zZwPF2fQI@+&k-vH_L(4RHi%_`x z@t1>V>+91-S13-l4aYxpw4116ck*v{Zmj!iZMgMoYRollu9YPy|7=L-D(;(Zg|v6^ zz+*?Hdb4EHsFalK7VJTzqxm$P&oijdMC4NLnY&!x2SHprN^xzuxZx@H$P3;;F=64U zxjDG%KsT>0PX_in9G9Y@8Hvr1ekTWYdq`7!fdNWbSYyOEBUJa5udeaX(9G5oNiZ@n z(8)9449+wvI9RPp6I6|K6<4&Ps5n8~1NBu7-r(cs2Q&hK_$}*MsWTW1d-X8?9ivU` znowDoOBC0pZSXF@iy)H8dJoDzEixzPc(s{?_r?$J-#;a1eZ%N0-}xJKfKTaENG-4i zVnP(=HRKwI$)gJ1_w&)VD{XAxu&^L&YJiT^3uistmY``&Cc;3@GI#(%;v?``h?meu~`ls}M>3{i@)j{+B=f_kYpo z;Ch;%#OBw&AKMLyANOogfo!hL&HvWt@ew#!X=oP9`%iKHul@AsqmX1@=iEyC zT71^|ZY@?SZ_fGNVZ8H<^{qn0H#viJ0satQL1zD=h4`a`a>(CrfyL<5`Ww3?by-j& zOhvFTFR|H1Gn-myq#K!Qz?E8evh)V_f>g75P0pX$b7Q-)8eZOIGjT05tfB=?C4`IaiK&rLB%}D{+ING|iZl34 zwCESNWCNjs81=)bnfLFGcu|270aTJKfw+>Cus6-f zXuf*jq69Hzv*fRmM;{?xq0}3-!bB2dH(%a^FnO&JJ?vMFP~S_MKn4~%11Po zluTSF=O))s=AEu{519q!Ps$HJK8KL<5%O*@d z9iG9MBMgxgQZp11;C0z`^{NKdpzj+DWc478Sk_R@SU9@`+JOFqP6 zD$3t+Izdw-t6g0DtVa~sd~u6vDVVxTuHgc(<(cH^sSBRowCVav0hBJ!pFI=Yy?YX^ z7~py!OiLm3n|daMZq7sRjm>*#x@YD#-fR!;EO9*_#TrDAsdw+z$hu!AyhzY-qa%7Q z$ws^Wynw-x{F^neK=&XCG9^A95)A$j?9ER>K^Z5FPY^>8&TqY?-v&;rj&uGcb_3{l^`} zKY;0>PlWJ0jO+{R;hRf-x=7xx8=iqV*JdGgE%p)7zsu*5UY+xH43&UE^H>x7@5j9a^wv10Z@C*POAimbu zuaS_2YTSP638Be!>XoS}e1@erRo55rhsc_#{B!!*Rn~=mG#hZkT_d}Bco2<;yTVx- z8gD=4kTxnXJG5n{+CPk*^rg_JO2}6xofBxA@!3V<)kg;b$KoybJ z05cx$mzKIZnM8}>Mu3tb&GZz>+UbYFj({8>YzO*?Mai*wGa&7L<`9s`gI9AEn1|ED zdOUocGHlK+wGQW{L^N4<`Cxm<&>&OFpW(ioS@=aY1oR(=3706O4fZf^ds1nP*U z=9ASGKRIDil(Iu~Vc|HODo{R8-=YIQc?$ScPP-kjubyC-;8CLy1zKd}F@aEgp4^T6 zA-0HC+Lfv`iBF|wOk2ZxEiw{&6TYx(fqK}Wyw)zZWUqc^bkkR9lC)nQZ*t8BiuLQ0 z(#bzTut5JX7nKgkf&w8Ls6Q{ztDp428et!-0VD*mFLDq(wIjFe9fU><#o~#F&fBRY zU{J6WDyyRCxITdfL8D%$L0T-sZTkkO4vi+2RQ2c)91rZd z?ByE6sZ0j1b1Z-eJM_T1lJkyXBC#m>9&84p^p5?Cj61C7~Rejz1v|nh0nHGq=nSqvnU0_HiO&W^?p<|V_AAEN!zx|ikth2Z9?CrzAGk(+^yxKqgbEmefRX+ z6BQ8&u_bQGmy>FSs){29Xc`SK{Pidn3G*SYoGM8^aHR$fL-CLsaSo|%TzOh2 zoMjt4MI*I=^T?VFfHo@4BVN7wIT$PF=t##|7RIM+rf*?>>k4^rTI__rcMy3IP%0rV zfs1M4(WHX!EJ^X@72-7dOl`Ze5&Y-V`j0p3PUd&!U%Hf(Z4)Y}A#>xJp!AMxK+U_Q zxhhKbHrIb#oHMkCaVFh=J{irno*u}$cHBy=o8?6b6si4@>-~w-cMa*1>-|X!li7y` zW)_A!FyZ#7P(+i|Dam77JnouX>gx;S<;8Toyd#*WOe!(ic07frxIz;QHUzAMDcSKc z18)8PzFs!;T>sH4^sZ~Slah_Bvo8H`R$ruI;Fu47;~a%l|KqN#~6#Xf42TK_r7B{o{NR(L>?7Et#+rA zA@p9UCSPI9``$Sz$96e6!46o0J=7e1hzW2^+&X7)+fljn32M zbkWjZP~ffQBh`QYOn`sz&DytK3FN&nRkt(!!p{d4MY2gCw+U1K`mG4}m`z_@%CXsu zG4IFWP1ei179LI|!BKuWBn0&U=E!lG)Wg;d6~#Y5b>;2x_6e1dcSv+n(s}59@H0Y- z(0G~>0s;bB50Cz*YhajY7=vq*Cg?$@jR0+|;Kqm*qr7-2u7<9=2U9oR@DK3#fK|MF$7 z&DL|17xCA^!|VMFAlb#+1ui2CRqvzk2?1c%0JvL}+r_L{yNI?{lN44bWU zD=8D;;kZ{}(J+t*wHMO)l=$l}2nuU)r}GC>Fkdh~~{l1DsbsaG|#2c@r; zuga(v8X1y~OotDl`qvRQ#{-JmoBq-bI1-@!dfl>W$`hiRg}&<@Ex)=En5y zQFx0mK|pQQc*h)y1F)K=Iy!AQ0&pTY9KQ`;Sj4q!aD>2>1gNjK#7gb(;q?j}yu7s# zX~K&Jz6iX~ZqriQs9y_kGz5awLKVOlf`G4`NLB;E3sCCk?gG;7bU-3iSQGRid}l1(9_cuP$iz;B4}IKLlPtNx;;9%rtbQ zY~$ez0Ragf3uKeR%7WE}aK5Y0Is3cw_x6Hy!; z^HS?y#QoxqW$QREW9hrB;Ct)XW&_XbeKQ#DCd0kDaBCn;`^$zWZ>lr2Hc=q4aXc}J z;455)#di?}1?sUP)vglGM|dzX(hBbv`~SRHl%uYN#f~_Q#zB#N z`vS%aAXE|^4=13b-#Em&;gq(18I3xDj*jl2tSpK%>=Fp^&4B`BdV0F*+|Xs2+e#!@ z-HEwKpnZ^{1gR+guUnPefdk&aP{2VDBn`TT6<1UGvNx%jV#gmarUOTTgx*(kkLyGox(CK<^pn9(?w z_`Fuj?yhDm(dwGNe5wk6y(6jXpEPX8@VtU(j1wfD5{Q&#=__r&HA?2Gh&Y@JK_I8T zg+-xJ0RlOS&8v`NaxH52@dvLVBnCo9`SRn(HeO!BZ2~D9+#k$a_Vk1JB4y%nee~#& zBku>OH@X`eZ6G3{RrdDwMqDc5c0~>xz;@<~J_48a0JRbg2~yO?_TS-Zh5;oIIaeSi z@e&B%irn_kPqcv89YE4_L-$bv);95zcQ=`fD_`gTv3g1Be6Iy!nPb!$HRxHX&G+6H z`QB>yF=B=bGxDt3HiR#!nM|GaeaA8-;QldyEuzso{&%smGW`ayy*=XiVPAH=-|^`{k5K9PI4yVPKx|VHFi52R}Ys;k*v1V!U0<-KF_(h zYwNrbD&jUXf?Dput4-e5jGwWR2T{C-yU(d>|-C z&p6l^g1B2oe}jP^ILP5P!LQ<`-077Y#gn6{8LpaDcTjc}Rbr1m4!j*2Z(CZJCUd9$ zx2lqKlVW3fpS^X$T~~^eRSO~W^6rjNp9-+X#(~m?N9OE}v{_YEg9Oc8N!|BNR*QWo zaZL(KQwq##>h?4(W25k0N_euR^wf z%(B6;v6SfO=+xB07D!p4m;4Bs+?yMFF}Zpemo5!4j513kd@(Z{6?D$|QE$F>hE;HM z^k#f~$nX#nj!H2=7LPcViBrH(#$Kl zGoazVdw_w*prEtC#vSR~U3!9MP(vfv7uv{)iO=8mGxuC^_SQMGseHeP+*3uD%DH02 ztrKU0{(`%9fvH(6nN>$kwuPw}81CplCtj{S#!AJnrjn2=7>Jm~g{u>C2C;$#DjX!r zrZ`UKvuzVrIwt^{19K?yKW=V*?F5;&1mas9ZG#UX40-3oh8`AQ(ifusXVolT!L0I7 zVxObQsGW-vpuP2XVCQ%qHU~VU*p?Q46E>>=bh;=T_9aJ348Is~ZC-y^B%$>7?Pnir zyedP}IOVA7|4VWT%f+UTALWFFbDN%Rn5Xp9wq3#Pr70&gVD~H^SKq!}4@ok#RCpHv z4q18On>^-2)5)c(heQiqvp;GxQXZQ;7>kkW)kn{_|76Qn$P%Uc(^4cp~y7<_-Erq-NSnr)xrDB0XRHpsfFF z%QSB)4V|Lw)W>xn{n~C$1+@;3N!0f8L6|!td7ov?&Y(^$)X;$9|KSfw+$(uo_P_xS z_9q6yU%p;C9aH%>r16xb>GS7ev4S=~xlAJs_&Ij{mp;p-yR6A}t41uyI>)!f7Q%p)5d7@Ek}h?T4bEMIPIyKWPaKqKR z+@P94^eP!;!CgmZ?wg2h64Ecy!=@45{I%3XY<%Kn|M(pPk!(GC)a9Ur_HJ>gsLpcy z%K^2CkSS780GUk$sSeW0nLx0bzPcr7cD5(1-5v(5^%h2_hGCD(Ous}!UEM`N5>qJEYLD>!wpYia zPFt&3?NJvHP|1AX+k4)_lXzJgvyF>nv--L^WnuQjq@*L+dRuH}6SMU4K;G5Yuk~di z{!W{;5+GDL9u~8IS(}Wpi~l*Nvz`?YIPsMM9P-~k{Y(BRb=RHp^kBlbJOcg#lZ<#sm{*>(v5`jT z$n_%i8BA6NhXIE9F7Ynxtj5_Xv*&yt`b*$Wn@yd)%>;e;5;_%Z=aAG9se%yJsUdzT z51SSq7)$`jH4s7Z36Cc_@Ej256HR;tF2WGIBsa@iIx_6Dwij}Ra3qZ(P71w93)zJW&yII5`3t0VKB%yAAr@njs0}e0MgOLQSJhegg+!;}-u${-I zbM*+Ef#U#vSLz6$P&HCsr$dR!YumD7i$|BqW)M&Y*C~+*YEMRH9wITeKEw1NmySRBb}RrqtSyxar43RtOo`T1_Ht|nmm054S- zR{>@V zTBsC^hd_!%Bxb1iSwm6-0tp$PzFOZcZ`sPO+r_&uIN;rP{G zXAv+WL!o4rq~Ag{j3#(=)B$2`u!t!sDMLdDcWG*Bg5C<1Bt|;BojX?-^;v+QA6Q4= z(zKdTTorO?a32BWr!)-EZrA|RCcLiO;g*0l2`m>(9wT`CL5+R}UAfrZIE~)*%gk@& z2VwcDk+O4g(iQx{)z%AX3Jh5on~?xwsr&evn1(dnXn!_Ks9}KQu!VJrx@%9(W|7FpCrX$ND8X zQ-^>%@Uc*?IUY*FgZ&oL>AJc#6x_($hyjyG8vFKb9wU_krW-dKh|CQ|DXNk_Ri3i~ z{Kw8SUBD-;RV)BEbo7+z~Gl%2uO zizZ@5(BQCa3S2;2xu{+7gmy#lUPwm4_vi}8V>esIzzIP9&(jkmfLp|(7I{<_Nn;rIHVo{b7xuT0e^^sW`9*9DOxX0@1>d?vqe#3y$hWh#d zRO#4thKemQ1+1|V=RYtAz_g-3VzhFQ9HITI8to!J!6+nIaLpq^2wi2o=2z5@7Ut$a z!iHeQ2j$EW_1!^i$8{%XBzn4kI|`r!iAoMHOuxrASz{0p3Z3tLwX5J&5G_uaHf${# zqkGq698w|ktY2iEwM@k4`s=7cMB@JD7g9~Qu1c3eb>`i52V+bW> z!uN2rk`SH(*ehVcp8W@K2H zDJByk3LKoLeV@NptjjbLEL99aUQ!Yvcv(n@~3KnAfJWD>0F6O!mAfA=pJUmb|}Oa zhF9=N=@8UFT!j@jxk@F4bVYz}P#XH+UmJ*UsGSCi5vU0bWpwl&06ib8K=#8A46~%( zFb@tfy}WI5-g~Yz(340{>6mK6DG%2vsa+&mz#wJxAlN8&ur(oe4Jm3@Spb1Bgi`Yi z!uzn+9HRD{@?oyLW;XCjLcB+&f>y^=C={fE*VoLZ7h2&-AyL3nY`ew2d9&k-cL*1y zSCclu@OK&NQ^c}o1z=xITk`j#zW_Px}73} z{Q9onWaLSO(e4-KK9Zp$T&^3U!e2)>cgvxG?fuyYU>+hP=YIWymg6_nA@FXZY$;Er zmrTA_H+8qPRF6Lf82|$hX_fo6AKku9<&T*i?L3lF3ihemeP<=q(`Po(UZhI^lod+N zJQieZSdZ-j>eF05i%cD1&Is82iX!{eW6!$gho!|={_JU@kSODkBZD))K|Q0DpM($f zv;QxPPvKiFd6)m&rL4aDhx=w)P{g0Di2?VknwUdsS66ylTZ?OI861TVbc?pvWe*#0CqmH11idZ7w$MSzNl8IoG=)Wg9=_oWT!+E!d@HJqx7L5| z&*|CnNm82YSg;Sa8xOy;v+*t`vD)7CPa~!swzXA!B(Tw`@C3n)f76fSkTYG-Je}j# zH8f9;w?t3zDJlj6bHgr-<4M+gDr3UD6K;A+2w@G=%Og{fDXmPxd<3qyZOIV7Qq>Q7 z4`F|Pt{u@h1O-n11j|Ec7 z>oWFFr_m0yJV=r_nyz5MN6zhZz#Ih_^J>aj6VucC`k5K!c%m9l+t}I;KIDr0hT8LV z$&Kc(H*egi!PL8ypSUEE;{)KA=hpkJELAzbyz+<-UQR>9gs-dpb#imf?Qv}BZ!H>; z;+GXbubEw%oBOh<$sXkhY?(|FjlI_Xvwh4o+t(AlLjSmpx_1!WYZ!!v284U24`cN` zsHm`jvIUZ+RY)AKZP|ON?j&rg*II`Ie>UyBY)<5a;ejKtCTz0OTujc<_L~oP20pls z3h^V(PHZuxOoUJl3|9ceO$Q$hWC~@MYNiexlo(it&t$ClC@=3j3THs+yHSLp_(g!w zr@iWMje>Ld0ImoBff&EKQ?=XlZI0>su4&i_a1!=sYBK$toh4*6z>#oumtp@O{`T!n z^1hrVeRR)AhkQXXZ`Oo%4W$zpFa)%K@}yOk!-yb6I`4Ncfm3Y5!x8|ys6b!^!$k1b zVZtYbbqXCpwvI4l4*0%-NM}!vES!NzO2OIftMFPj;QuU&E|m4z#U2hx8A@O92NV7M zI*__Guqa}Sz+@NwUaJ`pKSWVya__m`|Db{nuKh(=2oT9si_{6^dqFxp{^E4MA!F5c z8d(OS1)Q3f6qI|K;xMqeddv(X>b7bdETeJ*`hM+~K^nYsI8~+vPDQF(ojSD_Z5eOC zLT24*xF#S+dVrz;w+VJ&v{+~t01TQpr}m7h5kKSP&}pluc!f~&KTOJ z%7IG!yXR@`(6*iJeK3v+UvX(F7+Lus4w1ojRr}bDJp+IXfpnlWM3eCW2M08xalALv z){bp~K_3l_p@?Cye)6==94@ORtgaFgP>D>S6zbAq>UKwBiAitVyHYl2qK=TCVQ|JY z<2U3H;)LiIPdv9aQ^&;8@_Nop*Dz*zWa{8C)UmJ_@9!tGv0XZI;2Lz))J#kQq%Zc$ zPi=JM3k+O^C<7J=aCjK|!`m9tC2ji}v7#9^T#^>tm{DLg4)^uY0fn(K*bM2+cokj8^VH5Wf?bout}8U?LM z8POxQT|?h&F+#h`v1@nw>w7O`WIT=CI*QlVvZM&+3PUeBQ`qz1J+rQ*a*`f4ln{PVbQi$d^zvzO(6uyq}kvapn%>y>=3U*c#3~`diV?IbM9Re26HT zQke-UtcU5IS48`6SI2u`4y zcM{dLlhZgR|77c>L(tOR`4`8rgTVJD-K2`mSzjpD>6VZ1|EJbt38-n*b7OZrw5_Kz?Zjx$1+Jd zt37^WctJj`=XFtbw@|93IBP<}X15k1lyDdOi0&E-Qw&qUqYp+~-tR$Z=wUVEVP0tZ z9^rmtL6WIhels&O+ z``>oiI6L#OvrE~(6>NyWctv^F{vb5w>FFn+V8eNijsQK4Jc2bFh^QJGrQXq3Os6Z% zQj^jP^>(pRIXS!Jin1q6AB64deb%v-l6n80xz0VEmu@qq)dvq$2&u!+v#?&73^)a! z%o4ItWpd#Yjzj)ab##z((3cl|CUk{_X=I}$Gndqe;_7ehW(hMRqX!P1Kmw6-A4+CG z{s=vN*ww4|D=MV#hkz_XFXs-$pzm9Zc_aoAP7$TvBrqEM>{F@D#)w8L2|bB(Px*Hs zKhTd|?k4av8mEG0Rg$0vC+9NWy}i_B*tKLIx9`yOkvp#z(fjogqL>}w(+-i^N#|w8f{y*1qyaU@SZyHjMd_qlfNNS-#q-ysG1*m?`^v+BgZ-quk$K?5t z>8N(G8W1!H&B#;~ICyWU^gR4jN$C8X9y)r;ql*F|igKmMT@LYYs#z6=tw$sNtTEeg zg$`=~jX=*y%pi5fGYi5T6aZ1lJTm--a|)qkVC0DrGDvPsIhqcC3i35EB=_r(Wvt*1 zwwUs}W)ewFUnOHZuI7v6N+D6+dN16BM|;ae*>E35wz<25A^N{6KCqs?byW}4p+Erf z2{;3!#vcUmB7b6h7gwb7sZ)_;HiLKvDW@{=3EXYWFP^Iv$wQ}tfwB&mB=xVR(W#Vh zb^e)ngy1+71}ILtm<_2UL>xe}_`Ivj3tGLNGr7n`Lh%gtYQf3DK?J;}_cTAxw{moJ z%O9XWM<*3ZrBHE{9DLhz+2wYqSFsDPKoo)v} zup$JTcxyPHdh}_PqXqL6|7a^Nvy;jFVD1J6E|Q7IPfZ?z2s~WU_Z3h#AWH@fsk?`V zxpfd&Ti2?Oh%Lgfwg(e&-dRo7Z;gv3p^Puc7qOPyrQtxPiV(srBSU(86ZX27U!}KO z9K(fmiFwn01tey%|6@YvanNf-dv{S0zsB45HyXcoNxc7wsveU-@bZ{mi+Ec+FO-lK zcu*WSO;vJYhm%Y;5G#`0H?&{RYahbUG#{NNhK)UeW)Zf?q(@?YqC^rDA`tEQgF!SdGRF{#M&9fA*O-W$ zTChLyQ**N;ur0s=sc7J!@gP${j#4yY`L1G_UE`7-E&L?qizX8g2J%&4i)&6Cn8MUF zUvzPpp*k|sBaH*+10?2%6E!f1$378Uha9cDI>LC}hMag!8+G-oX>5$Q{9KX9x2PE4 zi)7Sw0!3IhGAT~pO{vTpv0pDC9>Gm69AOL{H|ngnlx^|2Y)(mPz9VTGsUo5$!cpa8 zip?%Gl!MxqjBDLrF}97B>aHQk9}?~C9h9C!q@p6Biid{><`#Sy{8tzk<7jIs7N>dV zHm4eifb}{%9V%oo*B00vuH(W2&;&Vod0-~2RFpa(7E#uncXvPNJ39hmAHFLbeR4jf z5QcbF-9T|$U0I2g;Uqp1oN)l65Q(y$jt-4L6qmG!f&z~k3D-CIz`4`Qmkq2gnpJ}> zT+X=pe{;7u7EFj4WnCnPo(A;VI&gy{=?k86r0;U4T>m}z*+fv|Zgw^jDftc_ z-eAl0K8!?p#W?s5=H0<(<&T%t0qvX(1SchvxJI7S{*?I6H_(kkDb^NenRp?J|K zlJd|r3$ur#cb^d1i%kikU-XQOa3Nw=IKjWH=I6KjcV$2N|3jnVh#l_#tuEy`TUbbC z!8@3J;_TmA`*KEDS$&eP?YF5=5#%&>JMhsf&$a;iLny;&X=!V^3gVNJ2pu0a(-q@{ zEG;b|${`8>PQp2fW)1BqqU7n5dg&D;P-ta&z~e0=gITjD5#@D3VHFrZA|2p?^5v(6 zI(aVVGz+Q}?CemW&HzsXgZP*)Gps7*nD6THFQm6xt`Z}Cf%DcPD-9dNOfI$oKE4GXtZZd4;{7in_nYz(J+kZUka9aD~B=(*A*QbC$iT3@%3 zgM)Uu{c~azj+>*9y^}-&ci%^yR{*27b_QQtvKVSxdD@-s@&BU%6 z06M}K4ml`UwqTMFx|t$Jkf5^~j|HfeILo76G${Jv7edBT`rtug>~J9y*s0FMBl=Jrwp*Km@BR zeE2d`|*9O-?J}ir42S5xcNX3OP ze&7gON4FQGB08RVt0Zl$5rzu!K(6}b>vvM--9W9KNW26teiNS)8}9U5DIkW4?_>Hp zu99P2R;L|!@yJ<$*69me_4oE(07ntlX*PW_2bc}Ae-+YKVHaV21keMd&mKj^zTRG_ zNPUr7`z7HhHm0v%zT7x^7o;98UEg-a@->shBq$r3!`XV{KYl1IUJRa4W@ZuOxiqg4 zO1Ch{bYl5P>*YUN7p+5{78D;MVNA>s#+VmJl2b8r770X9OD^~YU$`yIo}bUKiDJ-N zFn&J~dMpI`1MV2A`i4ft!d+?{o%U$;6iweh$WMT!gl{LF49HjGZb7+ZdE!L+&6_=* z;^^U@ zMNWQx_>G%lr=A9_!9k6oK{)QyrR>?D{rG1W`zuseaExGYf7@|m<12qe5V3>!l5=T@?h%R$Af(A6-FeD zKUcL^jAp#dg{F;Ry`iDY%kMb)pAZRHNRx7N1N6<0>l8 z@Y#qn0`M#f0eni-SRTj6Gh8rESs=X?#J=Cy=U_;^EQQ&<<~qK>7KSf~Ffmb?dEfa` zmNjQa;`~X}%;?Ilofw8l=~6?|Ykh&2=F!UfbL%BC@5tZ^nr#;XwlV)E#=XTJju*tdT_1ap9$AUeNpBIf1p-VhgiPG;%$ zoK)Jp*Ta&MI_=JCGr)AIL_CB-9?vcxdljH7Pp|G$YfK;%wT$W$IxVVmvP^qwJ z!iE?VAFr}f1`-w2EWR*z>4GFChFl$jLHbGl`PYX`DjY!BCPYL;T)(abbPhUAkofU? zD-1*u@`@~UoAUA{&g|(h>nm_9tV%{O`E~N!lMd(I7{04vbYaWTG$sgmO?=GD%q)RK zx=U1S4W9*|1O!V7o(=-N3O$|-oK=|DQLtGiVM{k<`;(E$`z)E@b61a_jTGv(ybLA& zl6+gWHrp>+ua&Avw4&bLl)c+@4;>QNv&R+kS#SPHXewcexV9g9bN&!Sw;?1J0{W}2 z>nY_>8pNnWreTY<6r&DO+83}hW)T1{XJU$k{{xZyxFmx%@#o$vb$y;VK;w-70_>UOWeDytNPE}<-@}&#jvj}>mmPOlsknjc3>f=WzJGcdk0zR) z=N6lu-Ot8i!@fNDhL}`2_zZ#yz%GN5NFZ!$(guR!n~G)o<73qffIV-US%8*eOzcg>6*_?ExQxSRX{owQZ%V`7{lmLo z7GDh3V&l*b+{nVR%KnWfdLUwjd8gN&BNfYisLHpD^rI0`w<0rm_J6v)?EF_kw>RESpOl5stwp=ynJN!EJG-)9sO+E zi`nZW0$P3Mh#NFNArhl2%r0+Kd;9iBP3m*f-#N?^?fLKXT9Eqc<;w@<36=9iU zg2C%s|CF^0dKJ1z{eh7sgXf>Sl0Phf6s3vxiYs;2Omp+9}n>ImnfO{Of`@^)f z)Jm^o8N;DN4X_ijxlHHE;KAKSK@D2|;Ub^^c|_}A(SfpMzOoN|7&IK)AemtqigDYi z4*!oBCwBaG>w=lJ58K=4fv`v1=kDONG)wRn1YoCp5wY-SpfOwu03K@?nrQ5|xT>SB zRZaj?I(^kbrcPN~+g-ja1S4Hb%Tl916I5&pYzgdzCZjDyruoP@Owul~tv0yaTt-)CP` z+uPZB*iNk38rNiiAtlF-VaqLyKMSuA)_BMyS+G;oreeJz!9Xp{Jaa`9X6W2YR_iuuBX4e zNBIDz2N(XzK{;SqW_o&;cK@1I$^t5Y?CuBu&?_%a0OTP$z`Mz*soSqKU`R8HbG517 z`RmskPY-l*$!?;60N%HSF>FWB4n`ii%DEZ-u)4#LRAPF;GiIm@gFY8Uo%sINuJrN- zp@f86H+x=v`*s)qjoy?g&C9cQ*yAa?Z#jsXiP0;wO>>4%Yr8SXS6~kLrivhW;A^h! zeEW7$*qsH3UiInEa*?VyOHI)~r=|DsU^7J-pip)BacQiBg@q?>%b`O_OBF+-qv1)@ z_Rh{i&o@Ioa7wx75<3-Wc4=T{fwT)n3f+WpO{+asX1Tn^1FApPw z0k^+;#n4(%R9uWOQ-Sjb)bV}n66l05KwZ#>o$Pai-1YI}t;9rICnxce2V%fFb}f2` z1O=*>m(O-|R*a50a&!B%tX1IgfSyBir>J%g{->a(Ti`7=ODKb#@-glwrXU*Ks#jq4 z>T_rw;1ce6S2(g)Q@`GvoBtUbpm`A7h?gm9|pDyKm&(+YipaBni?rUw~LNg4A}dDi-5r0 z6!wLZ_a1K=yu8l>7=a*W-O9Pn$%=I;7IH7G-}{Zno`{}%^5{Y-FuSd|njW&}j9F;z z;a^u(B{zT76nnw!+vey0`^#pS@GqynTzErwf%kM|WKHbbBof8{@k(mV$6;yL=2s9z zGcs)u5%!RKHL?!&c%1zmU0sO4pMe!0@)s2neA*6`uWit@F{pSKyedKFNpS)c1y6!&#}Lqh=QDDEW~t@dxn& zI0XC>fgN^u5ue4@gZ+4 zqe-wszq0c3nhFaJiHoy~B(&Jh{9gLy>%ltW2lWgz2`CoC$Wy!6kF_{kh;N>?yvbD^ z87ZewTT)(*cYNqbT<15kbcxCAgIgBH#-U_A9i5JjXqiv*Cw|V&aS+KLC0NH@ZEXvL z=Xm)=87>wqmk5eKf>VtW$PIRAby#r~JJKcPO!PNvPR6(UiAqS^z1ql6VtlHoYcHje z?PY7j(dMM^L09#LiI{{{t%F^z8cA2!K-MBg%NXbJm#-ri0<5eAic4a;-*@nFBAp{V zoKfCL@rHA68m5g64xX;LaRbXKCPp{?);DGv8eSUJt)6r^An+sB1d-jMz5MLqCk>j0 zBSjG9nf znaf&egl0ZJnR}=k1xe5ZEo(iU9%^(^D$P?h1ZEi+-pCg@8lq#<$sH2CK|d#l8w%qah74CrL#inUWAnMM5%F zri5lg36(;n;rpG|eLutZJny%?+xE4sdo4G*x~}s)kK@?)|Fn<0%PkbXPDuO*O;-C? zWhMNkr|2hn2%_Qry_3sLbsu@jFIwEIv?2C!@teq3FDyi2^9~)1D;Ur}Jbb|*@f4Q} z{rx5(b++32RJy$`sLXHkqN!eRkOo`Uu92b+`m%M?ruS=yt?x3};`)$Ly9DKQenL~% zUbRjyywe8o)AX(c26|~Hob~?lHxQ_0--ypcuGo!g^cc+_dW4)g6PT9v#pSG+pk1z- z{462s>MMSnM&;{552G=ERn(;i7bzC<#(3pjO|55K&UX9f@19T9np(_vi7Y)EKmASb zl>hPp|1E^RGg)|rzh5PP^-BEZOPQG^MY-#*r4+ArzIFF*VaJJwe|&3(BN$4yj`nDY zjwqb#eJgkK^{|0Y?4yr*&QO!COdR;k{#aA|7K%(LOV}c5RUgSsBml6iKP%%7l*Y>3$0WB;Vdr z@p@Aiw|R5Fw2#|Fsw)49UNR_r+ir4m_M0n?ALqKAtS*~ovj4k11GBxoldW~dVf z&+Bx0?m02}BgfU-BW8r5e0!P{Qnt{T)-3m$Cl8sm~V z(=>)eZKP9FO4#CgTfgda@7t~ED<6M4aMejY_E`Pw_3vjkTp#_VyC4o7|&5ebVkN?=h-HcwJ~R3%!-JO(J?BKN5y?geT|H^EJ<}EfxSTgQb#BG#y_tw^GP2* ze(c&>ZK7bs5Xkv2v+9Z+LV7sSJdM`S7~c9Wk3a_hua&I4&KtFbx0?3o;L%F4xI>4Y zZ}Qt-)7p7s#s2mom+VqY$}?3by2uAedv0a?3rv_=-4A22rMHh8KD+9kBReo6x2QZ-d9FW^m26&D`eLO?mph+33+t83dtv;93FW&iazm2r2QvQj{i=2bd&JFtxJ(n8 zY1AIj4>Hly#rpbv-@bcy&x6fbJ8zTc=~l5qJg5zj`u@sCA6nCQgsJpPYrp)TkHMnU zEgjO$-&Q+M4#>~FIf7=ud0a>9))Ejfr)Lkw%7`b`PBHQ;&D>)3@@do!DZ@!csRD^> z6@4{zv1H#XZKAhd(R+Hes14qGeMP;g`i)F~|4NrhS|Tl4|7<>W=kg0)Q7eQ;M3@Nq zBW!ZVr))eQTh`5RbyHm&%8VAblT)8*i5ribb^%l8?7Bz`EHn24H~1ZjuVZPB1sZp4dWHRAuy?&AMzB<25WSMe1!N=~p9?!oAD=hyzn z#^m7m=EWF(H-9Bk=ELFh)8Z6_7mls1V<-Ll2NS@st{<`c{qnDAq;XhS&dHtA9)9U{ zZ+8FR9>NRybk))tzfx%cC05w>PveiR`#t~du&Z&M*c*qKIDc48TiNJgbjN9>wH3OJ zy0O##HJV!FfBOtW1g8$gEZ7r}O1?s${S{ z1R|KvqK?dH6gt!pC-ghU4t}LNth?erf2lE+zvR;&Z7|Ij1X5mZE`uklsz3en$N3F< zHDcvJV&Ddp)CchmSIy8tsJClZx6u1GxYhAVs7#cy%kcVGUhc4L86EaVgdf zIB?|1LT1MrK79UMOHa=Z_kp|znno+DJdA5!-`(I-t|7r3G}m|%V^vNTtcKI1egeib zn>n+pVqRzN^<(fG@{WFajDCCI=uuCI@Z&DsDDHk9a~g$~Eg|T{;>bN9#!4HV{LP7#S56v}+fQx2R|k@ClUh82ikjt`oGhAV&sX z65>I5dr@$oLB|c5KW^ZdtfQ4Fo3wbbRf|!<$dMUqVv@0EWIQU^b=A zxpS(9j4NBqLj)iN!OJ^_rlFrnn0s#c!s!|d?Cjb>Ael1fcG6m{kC@nM7ngSE%HVt4 zPq5n^J36~5JoxAay&Mx2Wp=6n2Jwt}q~WPq?Xfr18$h$6w%8|_*&xg@Gdv5N&g})F zU9f18i5MlTfKu~6p0cHzJL~Rxy2_QYc|W)N-}}K_AMS11SsxLvTX{DmI&B$jZEL$| z;X*P`!#pcFM zyEboL7?LmOZZrkP{eN^?&^Q;QZ{oOdVK-y_+4+)_$4*j$T|zpWG5RMbCcjRyPId(K z!4Bg2s&|jRD-pdlHF+Z7BYTYZR4z=F#gYKq>*;X;{216&@4@!XqS{g4YHHq1T-&KE z?74G`q+*L`-8=uQWvcr`N&9@Lik0wAlC6zRut&1BdC8nd%7)99mGSwBGZ9cXA&b;L z(+3KE{ioBjN7AVZ_K~;mO)r@#_WhaRy+&l)@f7`UPOecWCO?tx*KeofTk_8m5>yPU zxH?#Y_JxELU0X9Rs+rj$L}mzN&++4yipM8!QRk>wyjTc_U~V;lipQ2M`|&E{Cg;(%3Y|+B2 zz-BZ{<0>NUk^OC~tvBdUl_XWD?`moBVvYRR$KMC>pqH%LVI(TjI5In^n2D;(k!nxY?tb_T<080K%{z#1FO~e!q2769j z`*LKmwV+RJ4c)|Bh2?P^oq9tuNNzGG3i!Rto{+jI#-c=z z64-L!z-$1)+x{Ieb0lJH&OGvLcps4ynR(+4?+m+w`%9_425lE11c#MFxy_q<`9b>3x&RAemfl$5mtA|7Xuz)K)`aH5)Y4VyB+!9D$G%ou1vT^UO~ zo|Ojx3C@I~sBbCfS2tGfhRvHZ(GNq215_5C7$S1#bNskzhAUQl;D%vn+C;2)vUMxu zh=4lGm~lOl?V}l@k7w+|*htUoGGnVaqHtq&-Tw-lqt^C5>TlOotA0WBfd=cw>!8F)@lF(7cX66Ju~u;cdH<^2?qwZ;eCF-q>u|3e(+!%vwHyop`SZ26Oyxw4NNSK zwTF%urw6lz+986Fqr>GRCO7`ZAIWMiyThXh9)??lpk(C?gDb4lWa~YZ(iQVhCnPZF zyK+IT7*EqT-=SP>a#699Y}m93k0%U&n9Ps2t0GCDMj`h$dAVq~DaQn|^{;}qxJYgu zp}DJj$SWy*6x`g~vydi1cO!Hgsi7fEUS+NU#~zb$FoF$b0!6{e>7JiLW{)J{*E-d0 zC1XAjBO!t2o}gsk{OQS{Dbl#lRg{&<%30&=JdkfA8sE~=g-p#4UW7FXBXKxThsel4 zce6!rH&{lIK-q`Jr%LRG`OITe#%914Ynh5AVNZru3I^I!Aj3w_5{-XD^0#>lsk z26VsZ^g4z7>PAimCN21(ZXk~`D@$HS=jfZkg9h=S*Kpe?Bx+Lx8;_dW6C$A4a-eUG zZ*(_YU4D1h&^}JwD7F^115JxTBKcdF``3K6KGtVvS3VT8X7EA2Po5PwySs#}+E^D^ zCSJe2>_7slAPx79=V&gQAd7%8II??8QfK)O-@bjTtvx{~Bab_pe8yAJ9Q>d79>@L` z97czf%<5`z8OjAP3S{W8VH_k3IX5;Jzf-x0RF2;i5)X26Nas{*#4v)Hko|)XW8XkSI0FVYqvnV9R!>i;oPH-pFI`#;jT3g``l3%L z+dzz}23DyBvV>P0C-;lv2bg^i>1fJ%WzA3tuK zkr*gD?pYz^Qf!)H-$|1vGc}oXX2PwOQQsly!6(AbbpJkvC{h=FdNZOAG%VuKA;Zkm z(xLYuGX%<8{Xp&t0k*?D!#9i{+&jlcyt|Q?<-wVFq_v2uf1kR2;7}_@-swCD4D7z$ zK-2BR%QX2!Z6>+%sH>k>Jx!OtyFsj+>vtvSh3h7ry?j7Mmbi8ZHW=jJ}hyv$L`M zt;##TH)-Iz@wl&)l;WYOQB(5#iu<41oY^xV|8HFE-O#%mQKF&0)t@M~prW*6`gULxE zD!O^=7M2lZ6&08mFHcX&m>wulK8OSo_(Zx9^42=rp1XGBIZ;UL&l#e*Oyr$>SG zCY6_Uo3wWs(!yjX;f@Uv_gtW~4zDdwgJPjAxl>G718Fc`jf(W?tZj4MDjuLS3Vvul zR1C6((c`PFt=|Mojo{tRaIyaUZbaJ#k*YCX&H;6Hy`nmc+;JK?HTGM4|A!m&vrqPz z_S|F;HdJZ*l*&$xTy!!HtxQeV`Zn)#y)#f++7GJR_+&!DXXY)s#%?Py@}i2UL)$JT|y*~-c)J#GBr zDEDLa@p1RgSW2J0c+nh*&=U2XS(2gmslAg^QXtmWEe-9DjvH5ZFEO$F=g;rv%uILz z^^6Nqcb+hP2dJN`iTCj`N*)#jgb)#k>EVw*9ul1Md;r(iol^@kf*L%-bxh2pp(1*|Czv5Y^`zTRwrtiV&&|qy zp^HW;9C@giZFQ`J56@gFHdm!+>)EppoH*eR!OSs}cXTY{1n2J@!tskDFWw-5i zZDUC3F#X!Tiwb0`yB#8%OgePe=gUmzJHsbcQd)`VpOY*n@AG0p_l@=4ofCsb6;yi= zvmQxS{bnp=fH&|gl-m%f$B&m#=LDbRh*4CYyBy$${f0)mDRHJErqn(Wj~4&|&z(C; zO-<2_Ss3Y0`@UrmsX_X)r%%JJhcDq$6YfksRMSzOH6`)!!9)FA6_P4U?X-6@2?IkT zCpCpUK|yAAAr~6H9rV)?X_U@LktlZuhZg`{k;aWNJtXRe`Ql_p=29+yjPW~nLlWIh zeKwZg_pj^s;-BHIybXdSahi585MYXqiLLFQjPnL!!t95sQ->ufPsAGPGqI3)WK4kt zP(YS`X0D*=UZyF7bZ&jdE&36Z_mo#WE_h8C^I#>r^V+JXgOR{e(_pwAIPnL(j%$YX z?9aUp*WDjzPes9^U9)y=_pV(ft5MIO62XqtMRwau8}jYQhXhQZbKp}_+;C>HLWzsz zGcw#0@x#3n7rXWey2?Soo<#|= zV%4g?3Grbm9-oA*L4c>W?d+o=lnW&#bk;AP z_bMnX6!NW)jIkw1npqScxElD`!t}W8Q8w==2azM;SPKdgmAx8p!qpx2AK?^24WGq> z`uBfXGVDDgD^Ts1Lh|#9NWSR#dWnnQi&7>xk?;%%r#*Ybam>re%$)MsuBU1@)63Vd zlTmkL_Q=x(t3Q~z`wTx8t*|}2T+(PEC%&*I5tGaAPq=i+W&Qf842^hiA|L;RlXLdS z!!)hsdeO*Y9^AiQZlYExj;fkF<*DoHj4*xvs0r%o0vylgMfu@r!&sQ9;ieXXBqyft zRnN(}6#Y<=d=m%)Rb2MCxLhQ2$jt<6@|-zBA<9uWMIYnWX8Owg`zKDA(Dv({Yy1Zf zW*iJAob@(wA!mNdXo3&0)5Pd*+MQE5XvmO$3Gog8+<*Zi-?x1E{dW6Pb=ehK7yAt= z&DD75Rk{=+rPMn~<3#HYHEA=qk0#Z6Wq&Rk{Z&g2HjmkFyRHz`n&yNFSSbf>Ex3Nk z==YUA3WrXcbZgeZ{)co%uX%dtu0KBV_tBAZ6}ecS;ZT7 zT1=mwaoqO8>4#N;Lb?sC4p$9gXsY>q`^R<@=c)Cts!cbTGrzse?dFp2LX%pRFaIyN zX^nSCSLLgF!|WF<*k%8fv{GGNVdv#hKyM4^LVYDBPeyRRe(t!K5%Lm#&sxFU$hf*K z{d<1gIizFFDC+-~#&frBP4=V1`vt4#c!4>-sCoBV{h*I@cXwYi9-!?N&g0eBwEb>^ zK~nPe>e-W60||v>qAe)9!T2bS?TJcY-E3$9AOMLQF?w`Ob@ikTWd=}iD?fs8(5GCW zcap?#EkLjQ4{%`e6iMxgTdPj5Rp#fn(x7eQ?bKTU;(jx`)|HyD-nd~oY3*{9}&x87hvClb=@aPY4?`& z1LnG3yJjpVOjgOutL111UufBO#QzaHH|^n!CEp8Qz9dzBxP8)yfMEAcO?3_+sst!N zL@=u%_`V~ERme&32re13zaNIMxCJW^wMQl`EkByT1K1Oe!oNUP6P+}(QJ7WE2`C=` z`a;Nx*-+WCD$D89KeCevU`@-o`g3J&sZ^j8@wJ6X!^2I(J>R`Z>=Jux(~IF5*N+^Z zspi*k{dC;+ch42R9yjeIa$-o_>^qekC%NvvFSaIYOpk!GkIuJvUwSAZo0YfK`pT0z z^B1*s+J)_<5-}IW(=g>j_YYYwUMwH5>dDdV6G30)1FvyT$&?r1KRxn=amEzvS} zJ+SFeRdD0!Ds}|~RpmA-!Yk|%P(f?RzYAKBm`ZwRh?8ddafgeoffXiUsE?8fOZ1$<2t zJNJLUs7zn~gHhFvv-t0@P!~%OFb=lpvCC(;xgj~K=0k=`rhyzGujeyxrcte=rcQb$ zOlidzhD++o`SYf>w%(|^>E$Cbdpri?x3EaObZM1VBzG0S=U~bC*KgN7XVKDtNg7i9 zWHZ#1mdDcX7X9-t(=M?|UtaIhlX2H1OPu=3+uvbR*xK z0b-|6>d{YG9N|ZTWL#%M8oVCzr%#>Ac1)Hu1mWhaCw%)Ava5TJf|eI!9RNYms$4;p z%g`#yS{8D(hu6%RVus9W74)r+$!}0s!qo6IPn`H0J*V+YVVEQvCrF}@&bO%ZZ#@gm&s9dj4TOu0V>44DQLvJP*!t3Tbh|Q{Qgbs-O?l|c@IEw*VE$tAprm9B!cSp!V5SSSKzWHw5AdSI$DiF&$>9P2 zf&>xoUI_>a#-nIB)6UM1>&~)8IE8f&GXyDAih4sGZ1Rzv17V);KPQ+KpX+rso7i;%Ue|5(9HIPdXmG4vXhE3A}nl( z){5Xp3;b}Y9@Txn&v&?51oGE;yNHS2TpOi=ChaKX#3NC*{tF%AowGlFxUpWkn?Y%J zvre5w3`&D`1{{jF*S_t!@auZl%eA@|X19lY84zO3o@ykPvUT*-(W9L~am9p4vdaGd z0nJQN3^a^GGRG5e^XXl1);5~?e*G{#3(Klqt(xqTn zVMmV4*mDv$(Gr|Ber+Fe`%U?hi*Ou^E@k+=dm>Zr2n3kEkag|TN_BZRJDa*R*!vrs zsBl4_MK5MfWwPSI!<}=ReDn;(B$V!IKNw_pAJcXeT@M=Olv?et+2o3pdz(8E`znREAINmHQ)~gwg>>GmUAH-*; zYsR?9CtQ7y*YpKy(nKot%X7LjiFbrnEKu@!em*&3ma}GMNda8L$7B_@5dgwX2fk@q z?;XVg;Jl+~*l)H>D^d`jZz$h^uex#Jtnryom2)3Gs@S$StEu$-sJ^b9n%@7_mYnEz z{>u4j_fighw4cB&y7DGVu43@sS61_F7klf?D1LDxbd-gqB@~j7Vg~}Pn5?Rykyl(C zlT%6FHO*%?or2O*eR=t;f&!_e+)7eriH(Vkm6Vk&NvjiB9r+JcRlzx08?iig*@+bT z?@;uOU$>JM(pRc;=Ept%8-y|=;lDvBhGOOKn(ck+yKS7Vo?)Q%mny_zGcZ<7+L>q5 zlSpS-JhYo?r1wc8LPw{>z>e5+=N2znlI~on&OC9SpK9H{Ym%WLtLrgR{c3zX#8WpD zF)?}e|Lq3!6J_7O9|s(Xj#i@tDlebrp-e#_)k%D@g+=fEIU`oh7G@WlKO7WX{Y>XG z=Ez_RA+hE}pBd)3x_e{Gq9uPm5mwJV^*w!4ziG#;)gCm=(p|SeC9124+&>q)*ZH1d zVtsc<=v>~h|90^ebC>+fmoAJ|Q0Odw&8OKd3@ zj+ExuL^&r`)XWdDh*6tO-VGRb>U(Y1Ip7B;^!;T;W&aZxF`4!k7&&b&nX@7J!%rvC zK0`g5f2?#n4&F`uKt7cV1sLgHTsKN&&ov{4Zj{;?d%9nUaZGODL92mVuiTue_~pYH zYQaOdR=&0Eexo7ri+8W;&UJI{bhZ;rJz3Lsyf(`@fzhxy^}4{L&zVRE;dn z&fXbqH+Sw2vUA*ZhN6;06@TdS!-~oIu$N8iy}WdruV3prC0x1#FV4ja7eXcPj%X4D zx)F11cord(atk`gA^(I5$b0B7VYz(xc~Y1$1^5XP30;q0H!MdEi2niMlKc#g{`<~*1RVZ( z;r$4^*Z}gU6*M#?Bo<(ECA$H<=jyd;ua7!w^$bp`A_vcD;^T8svT@83`;DZSRekBT2Y z%hB;9bZY2*FCNdRUY9GPDa%=*H1t#ql;WI%#FfY&gbL_INSuj@3Wy#!c(w%@IRyp6 z*crh#Jbt{IhK4?tc-}B(I^Cl4eg1R34%|4e%jCMK{dNo`c>eO`wHr71o8t}7B1Psb zrx^Qbdhnjbk{@2jU_Zs;!0fdmp9skd`lRK*g>=+kdNYM^(6XEh!1b++Ezl_-KZX9E zPy;Zcrej(oM+W=&A5+uQ^8*YZsz!&mvTxrr4kl())Sn>}O7N#4{~j@7=Y7X+-Mg#X zXQpR|$;BJ=VDkqQmF~F<)uox4Gd?Q8`RUh|1{!zu>bS8Zir^IypCV=cSnml+$2V}1 z?nN=q_^^}~*^K?fx^kd$0k8}Zd7>?40|^vl7*}SZ_Bc0}G$5v|_R)77TE(BsSHAQ%oLT9+aD=b@f;mxxhi62^ z%(`*KN&RhIZD``ZL5sya*|#+;bX$#gAb+*<-AbX5kd&m4Zsxd4@M%CbYH#g7l6pP0 zqcWIDHf2yoLlpAZum6S}^faC*b$r|HSpU!!UiH$*bSs6xHlMZ71jT#6c-W z+!@g>L{M+jLs$!1(Q@(cf0{1(+>sb6EZx6f{}yNd|3@$LO zHO;Nc+hbGXr&}+wogNk*7LjmSc0umHwE&}^V-=mx61Tb`#g6CHRUx3{Gj*V2vdrBs zBBy1r^Y9)}%q8f*XAj-paK>70wX#Z2+km^$4)f+2tzRF1@#0Xk!kKo*OWfB3^VDtK zE*AIu+@(u+1*@wUiqxHZk)JOJm=cD{Bh?zojG-weBl~A=ZRjra zFGi=bl7^s_(`oASEqvKpEs`d1Cab#bZT+ z##){WWF~J+6GmS+&lG_0aM#lj&lC$@ydZNV9ar}v*}sPCWXJov3HQ8oVaL-|!fXbr zJGK~m-=EJ$@hj0ofJ6$lXXEdmELhR)?kd^+?;OTp;emdl6ZGeFWBcPnzMWw5 z;u3b257-|t9nERRi%w)k2Hb?g0m)qdQL`3Z;NPjdqTsP)wc~e*u`R%G^2% zmddH9?3cVdT5i*Gpjk;n5Pzk)j7}7!KMX|1-_FgIS`ch}5@7H?y%#b<3g!Lt2oU{W zy|t1gl=cqGU6SE7;aR_7!?4scM>{yn^7$4@S@`Am*Vgnitb)_>gdy(x7l{eW74Okw zO+#$m*AHOn1=Ss%=7I^f{@e&^EW~Z4*u5H@*l0zJ#e5+k-!p7|(n`*Km*D7U!XoSEQd@RCvtcXe^` zoU8RL(4Jo1^jcg-@%nY^Bn`nT2O0+749LvZG&pn#NM1b?7}*=Rmaek|jPQ z7zw7>Cx|vVXd{AC6ano1W0=p0<~ z42#!vg#ux70U!j`C7ZdO%YplbHAVS`Czh?g^Y${JZDXmwRk{|^0dvm0zqLie z=^4?^iHXcsggkv(ql+S`5|)=ep~v2s(Vw(+$0jifhK?cXyfdrhs{RR4A# z3Lqq@3VE-Y0%M1}fA#7rLAECNSjj?Q0It7p^N;wK{fM~Fu;m)j9K{!`=HK6*nd*x) zuO)lsC*bqc;*%~Dh#Ii+k>6T3Nry%Ximj#*lBlF4M~N~@a;?j!8>yS_2J`@T2#bgS zsIjgQi%U%%q^}s4Z37dCzKfjMUvwo@41~%KN?@`pfUh088mN9`K%Q#-N=TyHFUjOm z#dam4z~lq8UEV)jp@r6h^}bW`(UT{K4<3wUcGCB$H~l;G_UBwh>Bk(P)#l!UySFs1ZG1GnyXu2ngIBfCaKeeo4z zZt{~SUwM9vb+@jYOX4r8Eg(l+@`w{m?^*UOQY?YTCRuwSdf~TkThNJon-H7P7hvnZ zYMfoCm>YWKnk$bRIdU~*9ET$Tzu|K`R}J7k(|D4&ksE@n7?JVwpirL{oTTwjl$z-3 zNV3|1&L?iRjHIO8#><{b&!%X;A-}t*NRYfxL*oKYICxOXlF7t~Dhb7^K*6XO*tgty z_0T)l7ViR49T$?BsWak8VbM6*oiCL+$C9nz z=Q^#5IC5n7eMi;(C&}()3|nh0;ftq+fweGf!;_^zkzrf`>cN zNn)QZP8BRnva^VrUDu{~7b74fu!o0-AY~>ZmA=k*-sa8Mw{M@eZrxX|7o(bXyJKZs z!5yVB0}90yI@9S9jUt%@!+_K1)q;XdP>6r8I!dr>W<_IteJ%&kA}@5>i1wsIKjM3% zZ;dpP1HCSQaRK5{Vc7cj_miSI;&ll0uE<jMb2S!IeYoZQV`g(Evu!h>Ys!$LGxaxCbQSWbeP~Jg znjNf|Hu>+komm&f#Xn*`3I!FF&tJbXb#QUTEgjw+u?UzyhwFM&(KClka(_M%p(a*X z0_$ZOh9JW3I@$!4}j-XWR>5+3Hvo_&;|m{+eh zz~7J&&XyNs^%8v!-EUf%(Sh-7z5kRa4~TlRwT*f+ zM{#Yro3o_hqetIL`qUl>44lDki>X1FtO-%_;|vPJZla>D3^{~+0V4Qd!9}4GVn$V_ zPqS9Isc&6br=3|hy??8JcV`IMT66O!Je@eo3cP|3HWssJ4C3daFRb!N!w~xY`-Q)@ z<7|23C@=&VM5r@F(6hdOQj+L*_gGXEQqGHsiMh^?p{5U9ifWOplRSm?wam`OG4|k0 z#hwxprPtR-kx#*03JS`ZSn9KL%fTx>G&T(+iJyTpYzKWq7zs|Iws{BCyDrQ zyIldC+Q>R!HGC0I@nmpF-VLp1w7BGpaWJ$KsZZ3KB;PIrB(|54k&z4VoO0Ya5G(-2 zct2MqmxL6OA}eXzIAVBS_yT+Wd$>fZ&lw>b`aBqjnoDAGy#4=Whn<D?PFYrg-kDW`(0v zH4~49qM*UcHslsDN70RG0d&*)TYsGXIe2R#m4C%RARf=9>3!bK3e3@vD%udR?L_re z(ASRTwa+T!Y%05NJ25Ex%?$B^H(yNM#*7gw*0z0qULosH*2|Y3*cNsKJ$kVN ztu2rhdno($*V@|JPoJ&>>RG0|x9b&KSpVx61R+7L7!&$#R$Dq_W2~t|fvECTn?U8D z6W@tsh|a6^^X(G0c+pOWH*!h~+V^5a`B8+NXs3qVy?K)+PJ~r|`S`Kfv}v94GH4YG zXgc@`)qWQ}e$Ct(%dMtOU;S!JrdHTqlbahvLcI{8LQ?sgH#$&JKEXZ&N~r;&IV_dFjMU6L^Iv4R_@vzgExo%9Y&&D-iizSO@5~ zt~t&k&zRD#Y|LtB=Tq^Iq$&*Ia$z*lAc@TVndX=z!#@Hqi_A=%MhgGs^y1pi0u1UE@J!|KtF zf*W0eT=2kwJLMbr<+8Ut>K+TXtPoqL{Rh^w7!wxPV$LkY^z`$nz-U2Nu2=zGza!~l z1mpbd>Wc0e0Y4I{M!0xVb9uJtHD$RIGw4?Nz-ZkHO7+L*^r?QiVL?`<@$b1XTKP3V z!l?^9zOn%#1EUb?pT4D?AE?c7K)-uZbr1@7rlL)S{45)TP8v-0!PBSfVO?Pn z5fj{*NI#)Be*An&9dgGJqTG{siVY0)`shWMP$vsh2ZaMjZL#CpwU1tSdXG6U^E6Jg zvllKvtsc)^F~h{9a`@qGV;a_U+9qo_%`ZPf1M#N)?%i&p;s=JGy|cO@D(LY?ANA4a z5)4 zlatE_srAGaF83tuyk%QNc+7)u0*2UqC-*xj;^nJXus$Q@<+uMc*VEp<1D%?HJG;Dx zE`UQedG+?);p4~ERa8vAD#*!|p$pg-9Q-gZPtbHRqPVWEtW?a)1&-N-z-72i607R` zQ1@1Ov~Vy1+pwd)``TaQv%lEA7K#EW3c69qFI0-FG-YVqJa>`nf_9JhgbKK$fmpf$ zt=Z^puONFx`#5i&pu93Q?U^|XnLnLqV(E{=cp?~CvxNc>9RUFH1N{Iw3H#~5<65WxmbT@svAe0&OB7X9$+AqoelW-pq&E>dM3&wcx; zdAHRT7p*C-^PPFGd_&Jry%j4HR`Sp1)1!}<#Du0m{SAt%mM%!p+I{HI4u@kgw}!&d z)i*adUHdBG!h^$cCScqfbSMva{F+*uuQIBgef|3C0)=bKEWM*R^B(LUo;U8{Pn>eB zaT-{FCaS7;Nd9eJ?y&m94uAxU-)9Lj$dGQo$#5z!_69T}HMN-+)28x#9fSEM)~$VM z8LvpGK;!f6(dWSnYp=#n;Vn1Ki)oP_O>?AsA~QQ6s1Drtal~B;()w}T&&$e`B?i7n^gm@ zUjJgYyi4*DLqpR*WwTScS*F;qL^6vewr;P<{49UXiQb2LgsB|2u3Y&6=Eq77Oj?lR zG%w;>Y40GpSf&o3s7ba~b9Sz|w70iNegpH|J83m`((>r^g(68rKf10~o;!!Tv5cM` zRu%Gr{ec%Y8vVMy=%v!PE!py7Gl{MBYG4X@zUotdZI*Cer9p=Pdj*pCRRWMk1v|G71@XclUMP zCX2{s+BO^Cg&RDK%=`ZOlwm#H!oKPFZU3)(FAJ|;E-4i^GuX`3Od_^m#jV5_nROAT zh68l&5bq??-tz6F?N+6WdrfSPuWCJOqCw42Ww}oK!llgX{BvY+{OPl%alxC75;Py3 z{mmehq1v|?S@mYSNWMFjvD>7fJ>&K5x-P!D|L6EqqX#bM$L03}I1fMkX^WNp0r^Hf zcGE)@6^yrq1w3=6dw1I|+nh;R0+HnYxux=FhYq!U*KPS|+uKzyxYuOimg^fYUk28+8=5Qdx}W&V}4}>@j(yh!-(JMAa*uo$q31)-U8Vz{=O) zw0DWdp4SIMpsak7wsz2<)ZxXwR)}Rt#8@U>xWECwMB8?*xjFy5k?NG6y&+XmN~&+9 zn#%9&+eY5UF8VYHv_|H|bLWzWcrh(5;}9a52;+*~!NGISt&oy(z|3PcO?_?jH6K3i%PqMa5&?x_*~$TnG|?T%8k(-ARym1{lTx+mQ#=n0-so zU>YpiE*>|KfISc0rEli&8~j|oZhv_c;n$hM{Sh(Hz~olzT^1Ztuh_40R%+_j#Otpu zQX-2>7Jg{?8P%uHzRH}%MbF%H`gvxiHv2~$X#f3sy;tTl-#43kYb6GisL!92@zhpGs%#t!ZYne%|`L4ya(rLm|1pabfN( zE6UwPiFO5_2r){pDRc$>-eJ`%uJG*A-gWGa3is&fP{|$5btUPkpaM)WT%jeN-wi!~-2|SC*ret^ zwHK7`$7^ecO_&hWbFTixiLPxe7QK7hugZ%=3S(Yz=C4C|=XEdFo)V#&Q7e|OoHSxm zbG1aTp&0+W-V72xQc|jqYS-+`cke3XS(JE|uS#0~?Ahas3D))V)kmo@+QSH>@UZGa zlu~6yUQaq+())CmSZJU8{^^SsghD;+s5*C{aL=ueIy{3qa>726U&zqClPR-9c5U6- zjeleU!6J9vcf?8|o^5KTpSZZv&TgTe!(ENrf7X2*H0|)QmWo#wu8m%#5q`wS@oLeF zGgi6J9;JFsxcE+jrII#)-Hr$6*x>|;U{{MhDh@K6f4=>A!f)^%hofPq+zI6{{xD(i z-d{C?_dkDbB@>u(?ecY(=3%dXH+n3ZKX;vr%Ouabss|RgA!0{e&_s1RDk8;vRk4+R zZ>i@FokR>KZvXqNcbptQa~3v0)A*AIXP!Nvb8FetqzgQXJu-DYFYDTl0CSEC0bI5tV z(%5+9{IMI4?THq*Sa@eC)fjs+HfD)F7EQ*+#`NoaUGBmjAkw1oP|_gpXS2K1z{*FD zRA=A6r`msxL(q$r))$YQ`Sd_{mBsSqJ1Y!6_Nl?V?Vh>>Cs(H~-Pvq5o9($vE)o7H z!AXh5^VF#kUpEME&adZ;LEB}&G<;S7qEwo`Ky{Xly{Uwz_^H{(@rr9qP0z2;YIa{d zw&M}{37$}JJfekN6GUYKX|@>l%6tH=$Y@HtJF>i-L5G6E^I?U*<&8w9&KYy{Sg6B~ zA3FnvJ=`BJryu-y<+#XK-xi=3u5?SKVJsdJQHS@^T_?J=)yF|pIMf=|=AZYR*w}ec z=cESu!=~37)l~i_1wQun5Y5=h zmf~FNsdMJJk63VV^4t}1r{>;|IyU&-yGN_83dxTdQa}6C?zTCs+8puX>-!yr{7A2U zs;Yz5ocn$=pr`Ot->h3WJjy#?w&(Q29a{zU>LVx+wh&n3caq} znHBMO18v!-x;$BK_>(H9J<7QQHmmV^Y1@LurrVgVI&kRNr`g3WxBPluh(Y^z!g1xE z#evWZmF658(~Y=@BCZXD}^unzq^L;tEQfR&wYM%XOX5vr&a@S5+2B{Kfesv zWr#s!I7Ri*vC9L7%`Y`hcu~-6?AT=DEYz0VtYc4%pItVPwa+}3*S^0c*E%~R7Q{#k z2T9L|_BbukxznqcFU_NMlASgK$;ZXU=I`r=nzgff{u{g)Pz*~6ONMC{x=8cL zxz^VBJRM0{CpU)) zu)6ePHWOEh;VPq22G!T0_YtJBv`kD7Ko+>gs(MmAvs0H(PB#0Y7iJI zP)_*|&@^qWt*9y>cIe=a>-mzGxo-LLhPGLE`6fmWK6J`$Mcg_BSjb5uBa|8t#Xoo= z8vp&g6QJPV;DdL2Dk~^dU;$2ijILHfmu1Iv8M}M zOVL$=g3o(*mOOBF^~6N2ck74sFsxhF^&%S3=g7!$HN}4JRQT#u++oO8ZL$mKCg`n7 z2Wo9*$|4a2gbr%o&>la&skwRm`cY(54!YsGeN8tugDLY~sFraHMn?~I9Jv0$ zYlqwG+dVvYFvfOwVBiDVLeNMkOL*vYD^@fjCUbm>fCC}vspML^?eaBs|1_NZg?na{ z)`yNB4Zh9n9&g0?w2D#nVz?)bfJ;}q)^OXf1rTx6F?DI9AkfZz_|PDUC+s?LqTq*w z4iKdW3_J!iAWgYqU)52gdcF!_ipAV>Jj2MFiCc?nYEr*Vy=VT`f{BihaaP zo`;|(QV$%E1akzlP@g(mxECJD-ycdMDxpQBx%GTRXXoEits-QNlE`|;xQyI#Dbi< zv9f!h1Kl7qj6|$PfUJRb;s~DM$|z;zH<+jDdSYQGf1R5)>_N8ZiCcqEc7t&)p>_Lx ztyGkITQ=w>6N9k`?%$usN=9zCMLe4p0+k*t5VYEy7#I_{L&S&T*;rKA;28XOn*>H+ ztZQaYBvDz#=uS{n`~bX0^J-ANov~XHvPvQu&kqm{tm@+{q12Q+uB1HFM4&Z zJs&+r6sV*CyGK4&&wN(9+dWhq=~8oF7tszE?JO}?cBc4m^wgCUK-f7fbW@AF4#MsS+4 z?1WLOYHA3Al}F&~0Lx0b$QmxaM4@#hLF2-$J1j?Q;DLUfdTv3MunN-7H~RpJt-mH)Z?TNk4R zuno5q;GFM8PHR(04m-CB*$1&vbJ$SFjhpP>J_W_&X!`1P>|O|N#k*%ec<>1VA#n(A zmTc%lASGd8u=B+ddTR0@9u0KgFw{4fxX|w~Zw9;h8o0x)(^UbZ=ZEp z;g-rHkG_V?{yu9dzw%(I=eOyzYEkQEN6jS_RD;h9ov@bB36v--4`Nk){AU^?d6-cc z!~=}XIw3Aj$TcEZ0l^68eZzdnO2o)3S1N5Rmm7aRA^VN)E7vIa%KY7t46J?Hg-who zAgLAh#z4GJS5>-l3S@u{kykKpuXRE%Mq3KX1sAzxGDnUbgQyF&^Y-#mw@bfy{rcBBJ&uy=tYvIC$OZiDNJtL#IxOnQ6DK@3+ zyJXBXFxZBp1WXOsf&-q3nS2P_MNoM~Fz^Vgfl=`gu-(J{1mq2LOt$8NvBj~sVb3sU zVByuP7!NAe+$$`+0o!KV$4rNcKtSIEi(%}OiLesPTniJKFjL8Jkey$yEwbznc{6;t ztF!YhtSxBoV`F0xA2+<*3RMfMUUx%HdNhY5#0xFj%~4p(Mhy z!`-QfB9dLU{RG#0D%8nS^>&6ruv9{J??%VE=W?7R|d_eVjdNPjvKq);sRCWCZv= zdU+G&4$fr9`)0ATli_ctis3uvPxk($W+N{*YSb5u;8mlq{rq{5A}KD!fQ8JLK-0T#q(Re~wRp5~P%o zj7MV`G#~EA)`Q`cPqI&DtRZF}h;q&mc3ipF(5;zp4Ej($!>_El(g)lu^oE+o8PLtUMr+lETR^?XP_bIJHa0mRvpLof?WGXmvA z=rL@fO$&+qbrlPFn4fuP=5 zlYO0T@2CtLVR1sQ`1x};mJm`YW2F^8I?RkA37~(cM=vf|AQZHeVVuDPZgh^RJ~_mM zo!tg4Q^c0S7t~_q{0)i&LA}+Gr;nqK(m5XuNH`cb@dp{n$@Q$`d&5hq7=^WIV^inc zs@Qi8ggiHaQrbx?5{jIi-cVP$E<48mTEA?~&pn2H=m8$A*tdu8t39$)2QR&jE~{zJ z2xAM2F(XEF=@1R{`%ME;VCzxvHaC}k`s5!oZY$Ho?@41&dgPdl$&X^@?VhfQSAEdf z!{!q+PKEJ@oukRO4EYNMJ+f^ZLqkVYFlZW#=Q-!wA?SyyUyQenGK3HXVSEo#q1$K9 z%&@RnkB|U=<>(SKW8(le6v!D^^J{EE=zSe);iah3xMApx2(4ql>jTX_{yTM~Ll=-@ z?y{Pe1g*%BQe)+?0+T|!Npm1>(f&~`*7xNS`gqCqMLM03VA48>yec4HNFRc)bYmDn z;!lmwfaBw?Ybbajc(nEX8%Ao>Xjv^Z+m;s6X=` z4TTAsp;|>C2~t@yre4}vwAw%9Sc5bXa`c}*eK+L}>yAV9*s)`biCcpUfJxPo=>xMQ zM7POaijqxDLwtw?1z7=G{U}vc_NNtW?!evCORwK<`xQm)8E*RO^=m&KE%i+CT#=fhF8J#thMql-%~O#XODNoL#%_E4t}PNIdApK(U2K67Af*M82t1 zy6--7Wm{`&9C`I57RUrbC&MdTwpObMSgJQ$1S7|xBS(-hV;t*|xlXC$P3BemEJ0Cd ztWbs zVkvVjlgG&8!moQ&A2rw_sW?mSl1-pxBg#h^@$ObBckUR_IkN?G=#ogz!@I=FN<&jq za=mZEr`~}=HB(g7%yQ-7Kzn;Hw}#3G!76PuX_BqW?QXclFaZQP?1l}O0|L6*Oc|r9 zx&{mF5_RJ5FP}gE1y=*bBdfJZ<1UFXoSp>{d2msbMUc<*8c5bsmgn>#5oci<{*K7Rbk^Vr~e0I$Qo#~)9o?-B&@jN|$_ zZ^_%y2?eVGh4|)?`dON4jAhh0hO}E(RWBcumdK zZR^!WjCfHpIEUhdqsTBMi`JjCWy%JN__?@Tc&e%2q1Y&6-H~FTr8qhE8t1Z#iW8DY zzKuSZtV_5;L@qAI#$8*giG$b`6eM&gxWq^aQB)L)n$LRUY^G;tWlf`o#==AVVto8c z6pp|b6c|E_hf<_K>EW-nC*KQoB-Gb(O&PF;^?Fh9?2HtUw0SQI3WQFIxF62C$*)4? z!29zGEe7p4eE6k668U!sat}ax!m=2>>`Z6Ax+ZN?jq&v9g5Ac(22ss`{{0mnUiIc4 z0I?vpo!)w$-GxU3{TpK~FVi)bYo*?eDCPqj_0;w(aWZsUomYxXHJ`zm6r!Z{1bYT)?ITj#%Rz(%;LCd`qa8ot>=TgZvaW+~8b064XtH_!-+zwV-S~k;vL?I)AfDyHC3f zoeMiLC*i&O!Mw-4NjrLaB_;ovEF%%pug(yEh%WtUaQiX`8wAW*-*#HkjP!K6Fo=8}UZDl=xyy|t zZ4y<4`|bRi`H-aa!M+maQc-%Kq@;w}&QM62%db+s*7H3^qdNOe<8>Y(v5k8&p+!5DrTQT11igIAII=ksabNH|# zPel#kCxgrU9JrKr$IL7gA@|-H*{+qnO8!2;N%));E81O=%6r0 zsKgV(Md3j9l zK*8|9WZVze17dqGpHE6M`Ft!GDJ!KokUi2njS&C^e`-2jzS8|l!vowOo*}Ja4L+IzP?lI z-S%9+u3bM?XLS~ee?x_X`8T!r@6ayhL)9k`*@Y;>@iv&OxiW`r$Gx!e*QS`&h&8`7 z&N?+nPRviv7>?1(sut+#)Qr8)$sp{m>^Y^CI>0XOk54^z|9;d);eY*R`(IvNBGgx?7C0KDI4X0k&#jSKP6?e+jm zv7)qfStxRVwpLmdsec(I=1tNHHfCyiRj?LJpH}(&;F|6CBsY$hc$SFH4aJ&%Y=M+3 zQUlLQ$Jw(LhWGY7(Lc#9lW4%WTe?;$&Ja2vB{fsFLG(+~CKbbas?U)$NU#{goIRQBr^ z2O#`)+Oiv@nviPhW5+7qeQu#0TUorAvj9g8)XPOUb>^R>Lr30a*`zt8M~XZ*$RMm4 zOgg!CG7*DRWkSvp7HVm1BTyM$UDz9x#(I-@ySl0jpL3NJemHrIZxed2XMlrRRIGyl$kvAdH$6Ns@OU#&?9&OYjA&p@uN?joljRZXaC%DdZ9hI z@{imEwK1xWN$Q-(=JthjhdS8W+R}3|)Fs*Kn=sZcC#T;C52*vzbe4a_|9i#^jCo5< zZBL)>)%NzLyx6-RKTxmGWtTiXI==!FnO&59V3cs>1_ts8kw1Y8N6+yD{OpluxQ3Hv z_zClK17VFhfg1vJ*&xT|OKax$UXIzR0iitZ`LB+2BoEQneh89+E@SkvXN09Wi^TyQ z+cD>o6NtIMHmisxQTHTZG>i1OmX^c#YFBhx5y4rEGwKqGIpCV>dQ!(r!=`uriEtkU zWaa12yC>aAmix|M?Kt~or-a3a*=mCazn#8Q#SpElot=zx?A2@6I=B>l`|{-gRSab? zz^u8(Ub4_7Bc0Hy+A{4J~XR0ChxuVXM=di(oQ)^q@p#9-YeGLNZrQLZB16DA(g_5y5I|qk^-~r6In?;Kk1B9;k`dCR`WTml}{Dz24KDVJ+eQzPx zD)?YBIuC%)$*GLAoR%P=Q@uRKa{BakjHr3lFOFJj>?I|_j55@f zsYR-YNPH-T>#hKuj?JpKD?}yQ5ca0K0i;v`GCpbsC8jbYM5Re`Yl@g>Lr>ocb2~r8 zMKr%cQ&V$)Z0xJ^t2*VM1X;&NH84=*)4XEYvP&4({aT^`E(;^Y8MTp#oSc|+ieY@+ z_fxqOh$6pSEzE+3`VM(|wUk>#bAQ?liDeLGP&>^-%Q+=JmF2vn>>;DJrLsdm*W5fQ z4wh%z)~%!p+O@bUjayw6innW0QUzTXB|gta z7nlCfMl43wMN$tOiVr3Y*FK!HAuYY9e=j|={F30I!TSQNnjk4hN7MX^>lnA~12~&u zM)XI#>@RUJ1kp+Cw7hlo&Mq#8aBv}SEWOhW%me6-4S)Likn!QOOg(KTGG~yY7E1Vl zg!M=q-Y8({t-v}Rb^vO|&uLBHU2IE)-Q=`q-~z{w;#D;cgl)Nmv+WaujqEOlLTx1V z1Tuh*e4`xx=Cb%|tP1`9sMXeCRilt55uUtFS=;EHb^DLSH{UJ5Z-J(fG81JH^RK9D zx6L=K?^-r?g~HBzy4NMkLulV3#*@vxI;%FceUs$n8-!wzOy8P;ckr=e<*i-!BX5Nx z&zueOBs}uF-R6%gO%nt>_Ki|Uk+Cz6qWzBaf&oY7b=XxEPou!ePIZeK-W~dG+OoG# z2hnfED_f#P;^Cp<+i$#=-!^Ubu|B=_tn0m&aOaxCn$I=RtRUB@T0Lg@(7`=@Wk)_y z7P#5kg$ts3)pB01UQ{icqPC>tqxx6xKg2#BRjpNIa^}J)BcnKtA!T?v$9Y!yhV zS{o?mCfgmIqQ}ntls0SprnrdNTRV;Bn)Ap?XCz zCmQIdXV0*sRvjA`>#%g=eUA^X{y0A}rODtNN`JZxt#zD;cx>%1C!W+e`~-&iwH7K3 z`W^aHPYQ600MuIJxhV}IgtYwry?Z?_)9kl<=T5qjBKGXTVygvntcC-AqkG{nT0>@l z4h-~$B9xKJ^(VKpbI5B*IcS2A8ek}!e-f?%?f{R3#4ZJ(H+cQP?P=eB`vTaTZ~{^N z>s5mFtk$y`5S^BoyNxmho>+C@D zW_6JqWhmTmK<^pkvA_`+5dogV@$_L9BY9ijT{qLa;4Rs=uW-UpManT?Tu5$0V3j7HNm zoKqpe$fd|BDawz|55%}|DQzM1$Y27PO;~&U(j`A)HCd}|->Zvzmx8Hc04Ptj8nv0w zqpqPrj=F2QB;V6~&A(s^19I2K2=20Ei($Ix7txY89hDLQ=i+Km>W;r9D>h1+ws$TZ zF1!Lw%fueaj}IPlJpX*Fi_7b>KD_z!bF;Q?HQVQ~P(M~^m<@I%^}8lXBJmdJJkPZMh2$>*2g##$b4tVV2IT4?b{8# zk5pECpyGJH7UpHrzKKQX5Vv6f+2o#!^%PKZ_mGmRsuP-eX|4qK0O5xL_Uzr>brl|2 zDJh+m#Sw-KXMlp=2dYe*q>Nq$yU9|$nVAb5XBFwOm31dm|g%E{$5_Fmw z;aAth680|e$}cNhxVcsGi_i$MicJFAc6MV816+K8Fkvd}IJtj8)j$9&Yg9!4Jmp=2 z!7DQl`wb8N-8pX*P1aL0?!-1WpY-rlld9t&1^K(Kw~Si>uY9}l#XNga z)5ev8Z)WTH6YFJOU)GwtD68*==|Nd)EuZ*6WJ{KoP{Y6~e4`6tglQV+Y`LxOm@zP1 z>u??B2+L3-s~A82HD&m-XZr)xc=X^w;9EkD6%jFp{UKTg#L_U~s9j~BZcb^%mZA(&3Mtl6iwPSe=k&)^gFJAedB z4YX^+X90D^3_REQ^MAlNahDkKzX>N|r)hAka||;ueAgtQlU7gf&6TjwLie+$PYdcQ zb<${0JF$d5baqimU%6ruJ8d3QdYF{}9?&{F6f~+qHheOsUnK10pSKq1!D66@30na^ z%Q1c?JiHiVC)>LuCR`V4c&J^*9&7}(_w*KyBJxjoM}pa!)vJMn$z>VK@MDE9&kwqq zYMUL(%QiDNCsov#w*RV$R{Wb6QcLdaA5LHZohoC(2qhf^Vxw+*K!m8t_3vvNAEg%B z{qgd``$JcbUKlMWkvGin+b_(Vl}!APrKiuDF{6Tx9k|BskMRknr$bLlNXln0g6J)Z z?UJaH9)qy9qPt+sx{nIZ@>m9H2z1@g(+hUR42?ggJM5a?N47p*<|`JnCfK!xWQf78Es+*}ebv~b z*M%mF{`n_)byE4S|BG#j8T;0oiw zcLOhtV$unDBrgNvk`H6dUq~EGI7*7Wdmqv@hMtg=YTLGa%4ox#I|jFmHkXl;n;6?~ z*QC8sQB@mXJTWmBwRZU<9{t_X$v4pJ>MOHzg?B$clytc>v(qO#g>7R;$&ETUv{1L~ z>f&3JiWnwjV2X()J}D{GEAdD0GDnJHInGip#hC!XMc&HhL|AAwkA8frtr)9@{ zJ(PSt11_IF&61H*??m&-;2H%WsGIj?OQSss{&zfv!PS%FN-m5)70$6s*-Yi<(4l*) zfG9QgUe(rJW=5uiR6f=cOGft1y)c{uj|epKNXT6ehRP@^C^VEk$~{w4;}NwwF=mEq zi0=O#j0rWca$vCI{P`w$d0w(0Rh``-;nPkpj>0!_Jm;{n{hTLBD2`q>n_*M!)WBQ9fO8&U?bmp@CMV-h%ea;2dcS(Dp^Bu2gd{s#|JUif>};9thB7JJnIpnxXLJij-^5Ssgs3^X z>n;zn8|KsNvUx#2odK%;-nH*S4OHJ~U@}+vJGMEkm!y*1G>fi*Jrx#_H~$u&DpL^r zKD&4aE9roVhg;B^?9nclHq3Bx;))AvANAMW#_2o4vn0`G<|fdOzS&n6TR}~wxI&KZ#p4bj2njAww4R_rSU(T3xY>y}wVSdBPI%XkQc>2@;4?6^8 zlyz*x8+ua8XaCV?I~@K5xk$d=GT@3Ao4)_^%mWak%@8N`{rApXkXY+tZ$F};JyFGS>*U9-Q$!-A zzp+q0Tgv5!?Xz1KOeANQ(+~Re>35hU4kZFS+857M`FOFuKC|mV8$G>-t=eGFn6#v2 z+vDe(+@1?gw2_gv#o)!YJF>A}B|G|F|6={Sdjrtx9yl;HxwK^9S|v(YD?=(`{sXb;A#X+i$@=?-do9nMZ3(k7pWAHJ;~EIR1en z5eyH|0Dk1=VtaB!{KyWBTfkugZ_B`2y4X0eR835j?_X>=&DbO0X-q>nhzf4puvB}% znx><>bgaP_QuEOvU-lNd!>TnjtkjAwTA)WZ6F5F~^is;f|Asm+PpjjJ29AfwLU+{8 z0Ir-^Jq-2~x}zq9?cs!&3 zg9@sA%|0a%UNo+(Un ze+JB{MU&?P-V$tXOU>PWK3a8e-Y)&bQ(p)2fIV>iW_0+}~#7^lkeuhLW) zh3;PfegM(P!T;3rZ!@Jq2`;6vfMA=4SLfv9T=f6#`)`;)5I!2c{2zdVk+UosGFn22 zbram4%v|dg@~1^@fRu9={IUicz3aa1+Qlz}0xmcGJo)8g*05n$?v+OA=_j9f*}UAE z>5-(<_+Nf{aqh&2j>|gzmx7;mwP7DkpHo*D5*tQ;R`Chr(pa5IsfRn4cNVqSlsAa= z_@pA}&&}q4+cay`_M3jw4~)z_+V|s&hSKrIG26Cn6I!5}#Q)TLR}IXzwINZb&892k zfRz~l@gyAR#_Q`ILy<`3y-D&;ipVByTAcCi9LhvC>@zCOo9^L2o!OiHqKGj_|_H?}3 z(`&GyVJ-|S0B6B_#ulM-4{%$lA+dXp#8OBAb?vnVFSPctCr$XtYM<^9hI8Usu^)`oA!Qz{OnH%{Iko&}Vl7+=i zWs~@83s9pN!l@6Ne398^jO}S@Z9V+;ClwusG?S;n2zR6pXmgc*p<j8Zi5MG_%OOKtE9(2;(gC^?LQ%Lwr5# zMLzQG3dCA>!@mgli5?zlr%tV6H={bB ziV2gWS^gW84HJfvjQY`ih3$jXkx8u8SrJ?UR~ zHMGg@pH^eA`SiaoJ(WvGxX4_cEv~cIt!u`#htZiY`8Ax{3l%hY826pw5U*eZpeJR7 zN;f3G?DD4d5Cl}wJYtv;nclq{yCPA>IF*kIj$e4+?NsP1jLa4))YR3HAcQGZ__LUL zglwDD(Ae_01Sf{PSfG|rgOw>y-jGa zlp+KcVgJh8PF??8d*V_b`{2Zk423>@V({)Ey`>s-Q()FdF|hI3S;~jDlLQ>HNoR=? z+Z6Io;zRIO&Nk0=(W33H3XE_Xdl|#&x0&{ij+2g!fKvVSjc3_Vglz0kw{6dQ^opHU zv-$#Zs-GJ`F!?K+X%5l|E~N4oWb6OAgj$K*x{czzKsMRgoE&Ioyk7*Da@z61TdoHT zBi|yO{B@iy-qyGKw_a7pa_>%#gke7Ibm8vUTYlF)PYmDz4c#}#&h9X5yK4}ebMDaf zbZHKFLK?)^o5>&2Hi@&MT#z(z^p(sZ|NS<0`1sl4uNJTL@sZ-x?$Ki&b}k6q8b=z_ z+uwc#=`&eoBox2_Kso-6m0f~eIqf!VM-IXG_~T5oBdfwjqVa#? zFZwpd=l{(wps$BZ2{xFvZRJ~-$~0{D$v3P>&MlOcV-J+w8Brs44v3ho{`1EVRDPE? z|BS&?Gi+*z>*gnrw1OTYe_K-@BwzjNTD)*%?!m(XgOBv2aKsYwWujM4wVqRvxUdu_w=VfF7 zc4?eiNxXoq8yth`=}@6Nh8mI&H2z$%$fR$WASWL{w|VfA_w6S)7zQiFV@G$4*IA&~ zxsj5a;4HWSBIG%)e3VhF@=8kaF)_HT?Rc`Gi%5LNx_kY)Zd+gN))v(EXO4(Z?Vm%rz`j2(ZBVuEj{^c2;m-gfUbI!;}+(V;RpX~6W5VB2_dkbI82kk<>uInOs}AJ zGfRI6t-pPM(C=6>XYKspi1_$>i~x;_a>u9d#*K@|=aa(x&y9NXGUFyG;>Z^s8d_Ud zhu?zugHEEWJynriEzrZd?6&)AU*Fu5`9gZ(n@X<jeoUA zg^C+cYrXkoZVvZ1w9K;WgoEGo^TPp(9qD4wTVQJ7L(m!nlQB9@_oF6%8TdLqu0}=Z zDx5C-yQ@!yr`xdn%|_w2`1*f&Ot%(^vuUAbWVQ*jiDsW&<|Gi~gDMvTBtf%P%@46j zS01x6@uKSAJmSs8rejjq%F8jx&c`rCPj4lWj9Q3T1s&aI-Q4+&2S33q`4>eEG28X` ziUPA9<>&_m28!s$;Q%dr{yfY1%zI>BBm3&As7!da>Wp9tb+X1#WMYOA0G7#lAKh&0 zHoVPhZ`piHIoEIy4bsx<26A()QSs3#gdm!+_T*P2o}(2C(MNb6U9%MkXwV%oc8!Cy zzpSjqOF@|rmr(mQo&(imT`j(M4}GR_muUF-u-9x268TLOJnblOXoLa9$g~cK0;yn zxb<22saAjd0duSejI9i)3T=OUG->PS)xUkmFoEj4qNS9_r@0~b)>%JN-{o`siOS~u z#jFt1mB!lUvyowP0d#EOc!cLhSR8IFSKJF_pgkCi2z<7|*H`FzvqqYV@U|EhyoCQJfsjF6W*<8^1FZk{-Z~*E}Q|7 z>B!_Lm>9GzFDK`6e&w~hce@`l*x7&V7j8)*`0oDU`Lwe0m7mu#GSu}Mp8nY=QKa%o z;zyvKAi?2uzK%92UypjNX=@1nSYRy#)L>VNS6(!@0ZYc@&63M z+kfuQUknq_zp&WFgY8kG?)zk)QS3C@k%YzuA)0%?YGnmc+g}c7SIR$$yn|4|A&)qi zuX5bv-~~KS0C+Mr>+P<@HBCJlm(bx(!$1>EvRwX27I2S#LTgcGCM5YPA0M2*ZwWd3 zshkA%I(RerryxQV_A$O=_ooTn!=XE%`qU!40r{)x{o+g%k4 zt#6%}|1O?Mr{~HlLI;jNqzdrY&tStpeV3$+nzs1H>UY?xjt>c2FW;-z5-)xK+Y79( z8F4fnG+41E{?nA>u7))=dpB?HNdxTJ^|EW;875wTGQ8o(u@)a0Yh z#~x!ZCnt{}YX;v$(Rm!V9oEHx1D~FqO1?XwY}x3x1I5*6okG$N25c)|>3Zkk!>@o4 z^Ukjnh~A4Ae?prXz33=P9L3yVvPGG&kxY_vy``EFeXkhRYoSNZpg}8ioi9mmZa?N+ z-Dl0(2ZLpv2KB_WL(7-$OPC+{x{sWkyxi~J^76|5gM5fo1Aaj`I!a%s=-;?j>hUl?s5zmLGGXlQruI9hKP6!D3g5}-Ng>4ULQLzHVzws%R zXN&qN)=ICq>W2dZS}eSj$iHz#1_7=m7O=WHFY6xI?)o|J?Sb6aCV>fRQe_&6)2?kf zth!)g@S7(m4j6@Z8WhF=s zwniQybP>`PquDTC(BQD+ArM#C%=k9JHJ_DJCqvKF5t*NcHZ3e%q*FE=W+`4qu3TZPam0xGQ zlge*k@VMdQeu)R`mooDA+}iM#?N3%4x#c_ylBSn-=)M=noF0x{v-sPG@>x&?b#;Y5 zufdtbv^vdnl^2O@FX{)uf-{dpC`-!okgz7xUc~vHTz>1~`SblT&j-Il3J(l{JDX5q zzw!bf;girUSof^m{&MyDr4I@$+>|^n3}6h- z-V>j1k~(zwEk-VOX32{*`@y%8%#DvUG`VzeA#XMDniY)75^{`T)_3go^-vmzcki{- zpt{&hlO44V0w99 zY^-AY(0J(w^fo@Xd-9vnU&lV`7aMi%-1%PIPf3*mWTvI1u7{saFW&cC7W%B|$;ocbh4hblZ4o)6>@`J(O3je($hF$;!@@ z*H*s!d9;d1^r#boK7D@k#S7h2bm=47+*p|k?(}wWPr-8S<^9|$^HQ{~k2F$rI7ffozh_Amc zNYX%3eE+`5$~O^v?FWPRB3pYD(3bQ;a{Kj^cJKI@85dj}-X!9gv-r#hn?<6)+>G-X zniT8|4zGK-n1B81>{>CE6zjMrpOl!|sAT?1LWT5=brOJf>EimvID_`r_a3AjO1&Q!+_NN!+jRz$deBSqLKYe>A zqqUzpylF^X9~Bq(wCuvgWb=1>2Ki6>qZH8}seibiSH{uaW_J!8=w| zd~Yf3-FPT!+_T8=qI%D_H}AeUSD&&=r%(93sb~zljoEaBrz+O7?UdV(sUF$_`sebB zPHeN=JiXNBIbU)jUr)?586*;EN@lTK92D7)MnC@nm%Oxcc&KGhaTTV+?#>r;Jl=ME z^QL}KIJB$vsnJcdPVj9rleXpu`Wa-cU(=6)0mqLVInY|yTg5%UYq`J|RE-7|1iF8b zWYS}#=fKI^YgQXoukP2i>!EdP2hd4*w|dp9mtE^$L?>lD9b7hlN7IP-g@!hR%qFu)(4V)|M z)BW1>=g!TU=R~4tY`tX>KfQV?7cX6U)gS*Nk>qk zGKTz?v4qHW0OBB+`YV1v4r71yI&q7s=CL|K{`JV152f`dM}LHqnM(Lw8%s+J1~rEc zbu_&qYPdXuj2l|ZekSCF+(}_V&nRP6ZYFnfFU5|#Zx!FW$NYNLEv5|B;XfS?b-eoB zO3iK67@g5^#nn%m1OtQjN?l%ME~6R3?UY6Tf3lBg#qCm+64~lL6aL4Mh`Sog*6r2U z;4_3mVxs1!(c_7vq?&ZuGO61wrkBV;j6g|F!E2vu%;#n3Z69B|t+=}K{%HP}$aHzI zgo*HtsGFr-zmBB7 zvVEPmQW-OuE^<}xyq2!o1E?3+(P7|b8QF008AbQ+?^|y!+`U}X-nitXB$tQD{Qc)H zd(}c0OE#@7o3-HCg$re0)&=o26SuOGR!+bx#%n~9EeyTpXUE&pDHjlunVOnf?>_wc z`Yp+|1LEgW`=2>zIxyqveC->H#8vmyBEw-O@Nk;J&YlJ4`vP4r_hi$JX)uQXVg%Ds z#t~ixZyPs^n@2BJ<@W|-ze~a!TKi9>eh{c(YfB51Us+ih-4_&+J{X}I8algn$_S+X zudVeYZrothL+|g-Qz{d^8r~8QMSy_O{=E^CaGU61|Q?^3G92GmX!WQza;Z;KXoZCz=ox6rPop)xW%8e|Tw) z(Ta_eHM88W1V!NYAhfH2>k&zB-5RW|9WEW2kZ}KPV{JG3P|)T**gfSXoFdJLkQ>j? zxgcd`Ae3JC)OxFC>*%t8 zvuG-4V*baDfBs>nNjo4W17?}QsFD`~%l>u4ILscnA6VbsW`Zj3^SV^+5_w?apa=l- z9*X)^xO4)j&mH<51OrW&bbF0Ix*#4d$g6~kJBbywzmAp`b8?x5DNJ=oBREybtjna? zksGeyP(!A&slDwoBoV?8EPU}}nIMk$15YdY1EW&TEi1E&8KfH2Sxk(ERC*>~a^$JW zAUzP8eSKy)ZMKZa7E>%-Ydf>8QHT+ya<_|Y_IYXr) z!>En%QYH=GVL_aH^Zq^EcyKzgm+5H>se6t}thgFGd2=148tshu0QCt!F(G zzY+cMJ5V$&vVIM3w&0#EF3t#CIE|Ru3F~x!hbqvJ%O4;qVt5=70WP@Efz{3GulGb5 zhn{F|{kF9AY?bPT9!I*F%nK|E58GvX=d*cWZjU`ZA9qetm#hfr+;IZEA5a;1*3&Lc zk_?1`eJlkU90oW&cE8kb$dI%e#B3~w!*LYQu*#W6WSy z(^@E${p$=2&SAU{IC2vJ_vXzs8q)7Lq)z?kq*|jtSi6n*g?04@@B#vasLOd=-0D|k ztlAnQZ6=03ACa!u#-EXY-*e@WDk4FkGu@yctbFko&tv@fQuEPq#}7XUytVvTQqs)j z$=eL2k}xYASxnE^4x4CKXTf{{+6y0;Gwv$2cG}XXfKZyMI{#lpatqhW8Bt=3(+(DUy zL-sY_cQ(8-^PJhc%OY_KLDis^pFioMc-Z?c({@q*TncEo{DCJ0S-`yTI+g0FdB` zP0<-OVuaNnW1}xrPApyR;$B4d72qg@6GY5nyh2Qz$H zUFjZQntPh{4kmc|qx?D=9ySgcdQT+@L;J|CXc^C)Q3;T9=hXCfx~ z;pd;ZhRNp)Mo=2zF%9yHE;oS+&$I^voU{5&x7{aoh+H(W-7hTs(faLZ%OJ;0LZg$j zvmoLjhU+WM;DdHU0i!PI)90o~PP%p6S)`{_L>fS#=?m1A9Y@AdNuR_*yR$$!~g z_h_G8?Qh>31jXp=|2a`zX{ANGoOtJ^`K!8YSNzhpC0|FN2H=1GW^#}AfBbmxTi%@h zA1`)S9-XWIv*Pz;n&WTY^bjJ-A;;;JjT?A1!+wZ9AtHctr^aXDe*0XWF#f2yTZq(i zLG`M%`_{`Tmf|S$NA13q{B`xlaq)DqHyxT5KQ8vxTeeQgTAaW)j8huXeil^>jC@_) z7wg8rNVHD-hB}ocZ@Ln1+&XMdu9ordr8k=G9X%~~4;_*;({aI+p1NVRhu`v|mNG#J z1SB@(;+=zIb2z-ISkqTvvo*O@PhsPbT53zOl1Tslqmr(td&{uscwHcqsGZ7CCJ3Xx z1{gKdX3i<35+q~+d{1C?eKMWVxd0H*@)sve)r?SgSvD4w9g*3GY=oX?bM@MErZijyYK84Bxprz zQwDjwpTXiHSy%4cm&ya$%qqdmsl%U~I`L+0zmc!=7JfaM6rCGr$|(psA#E1iW59D< z&MBP*u{|!|XF(PY8gFtOXFeMn2+&{-ymw5G6~`KDE~0Og>9G&Tc!V%M;Uj(Jv>F_U zjC2FD$Kys$?lDP-o$`@+?`=F6Jpc*og?7ZO*8FNagCe1;OD8#-$Z8Eysla2X6E8zs zCakr2m84{}-_#u+r*_vhn}RKhw`X);1v&BKY=Q9d5L4yxmf}gfw@XP%GTTwk$o)@Y zV7ri4G_U%x9?i89Drnf5?+lfJk9j!;MC4es_mO)|mmJ>9jM+iZiC<=TSCnk(WY`wsq=IAnl9xG)dp@+8{@nA7qiEnY_i^;>+$LARAnSym+4zHVf3SUx(HxaA43mN+RZKwrn)b3y?LgM7p zXEO7cxMlW^W%_p1g`ru=>FLZxUA)B>?}^T7zKj7#{w{}^u- zZ!F1NST9UBv@az@Cf%4eTx-;S?ns#Lc3C0`LI1Q(>`=xDV}00PPHq%a#&)=v|FIAj zeG^9VFjW-%{>+)RY*P*taTS;!zI?W`zA%hIYxm%12M*m{va%!L!51%n$9}1)t{!V- zG-4Cosi zjfNkK8j~kazm#s>cf^yN$W6U_>Kc|#`LnF-4qLr0i9FwPi!`>ClR5O*w-Vd06P3Ph zxU}`U)W+TNe~Rr#Vm!3U^to&a4#j?mGibV9QcPAM*c6iGvk-cj`TzblYkYzUoyMGQ zBbPmEfCXf3CI+O7nxV8my?b}-lH8ROK7g0PboQL7DG4{Db9;k5aHl*1GHjw<$;Qb5 zuuT&mZ&oWmGv9w+Q_Cvay(PkL82Yu46udmItbJBHtVGLz7oa<&RDG5wo-ENDV@kOi zPiCO(p#O-?M-XLm?7uT%=-+Uq1Sg^zgcxOnE^bm|8NWn4SQ5N|ei`ZxyfB0@Mfiw= zf|r+HS@Ukini-T`j@)5tE=ev5XZ{T{M`un@dj5@m^cCm&L{8qEyxZ zL3ieNMZc#?COy=HE(Ii1U0E}1dFIMs+sGy%yry&xo|}ZcN2^A6uS&_BUKFfvKYqO9 zk)z!_W{{)fSwHo$$gDotx_XI3iZ^afESeLgbfss-PuYI*LsnGXx;e8U>7z_Tz}(-# zC6Qg$SevQ^-_xh%zvGs`HtnoLJ@eNlD>neE2w(pLKBC!VQ;nVm_o|Zjl_JsOE%_A< z8^+l`)XF#{A)2}Ut_O%|(dU#M!JWQ|nH@c#In}~*&FH5%`thTZtoYIi1Ai*unn>cmBX*H7T} z9Ju4!!$W@_=>IPeDRZr&8GM>xjJfV3GiS)UCo@+0#<&v^x8D9}ZH@7BdFR8NGEL2l zG;}U}t&LXIN-MNclMznLF=I9m+UdS#55RuoIA_FkH0z$n?=e2WbgzcBm+v15rtPf9 zSyIA47iv;tCQOBggWcl|5u)s`VC>t(+Qz`k%hzY^w(Z*|TKDXb*p0y<%Hr0rL+PannuCKJJUoI)=&ER5i{ zHEPr$7_>rr=^=u9AmJN^@Wx$q;P8Pr4*&evf^P&EYS|8ptY= zs9(Rn-WLY9MRsCHfD2>IL4KHW`x4L?sVbvs9zGU4Kar|;lRBp5A1s6x^!f$fwXwr z?_0NT+rFL$7t=t)j)8$e*d(ST!5zq$p;*kO1A~jZA3Gu>-qHX$GACDjpz3CQnB-(hSGD5iN3yfn@#PS*!7Uf@WWhS)D#>N6A|Ip>=7 z>*sT)JQhHzrzDA-l=!0FEiPV)`6aTkODik3V$+nC<^kkZ>j?9O`>Qfj4A9`hb$p-j7pG(#7N_nYu5BL zTDQ!4_op}#|53)BMH9n!gU`9VeZ}6y0C9#!X)-Ur+T}pJ{+}pidM#i|-a7SnJQ9n1^$l zmp3$Cr|WiXul3CEJL4s%5){8xOiT=y>YOiPUp~DuqEPhhkOD421E#u|&gZKUDyGNv zA=>c7W}TzU4!2M}pj6Vnlx>>W`Y1~(iAbTS80lmKFTSrh^#q%&=H8*7n5v|tr(dDj zmEMQb#%gLo(rz9eHxnw&jb zr!}U|SYMw}@q5X``~euL5$`U0e0KSq*6RfYLDJ-e_UdAl_4Suo7~rAgdt`Sp2dW$v zED)V3BF&>Soo>l#;&o3?C=+f)qAnROie@NUXpz$?#TH^=&Bc1KgC8v|4L^Qy1bE`P z#+b+CdYwMSOoy#|kXpU2;_cftxI;1AlH~O+tGR5OPVL%*b}wR2Z&~6xFQ+VZoZZ6nfb`T zC5Y76KI0SG2`b$BgL8myWMO{e+mZ8vcP&VJ0vH-*p~{&13F0M$CB8?;mTnJr=z_2qUm@AHSQRvr?evY@qXT)1HqeiyuaLJ`W zLMCNHYajhZfDl+bh~JgQo5+|_PZ19kTy}UWWQ0x4Q|q+W4CE1V7$CZU)+R5h{Q4s` zzIE2J1zfGD!T6}lQ|Z|{Pk4y6-z$l0Bsg&2f9Uu?`$DCqq;`u$-Y_x4huBR#9++}&NsULk#CoeaCBUkJGUQN*`l8V zkIKkZ@g@FdpX!ddvZh zoX!GC&{+%R0QQYXDI&8wjv%b4)Q`k>+PZ=r2SP}4%A{oH)1I8iuHN4FbfVk#3Xbg@ zMoW&T%=iC+8Bc7RJF%JP#&Ah#{c%E*gLy1?`dHITq zsu#T9!U1o1rQR5HOt!F~6KKMg zkS=Oia}$E-832c(kwOABIcY2#FAnDS)ASf`B?Sd!q(e^4VfT$sPzEJ(7Y8~%eJD>? zQ9>$L)5N5mBFk@l!d;Ku0O|+3;{xHWc?0LnOEn7H;5cHqP$r%(h+u7N>EL)wKxu`U&y?-sS}OG@B$T8RTkoi&77$667F;2`Cc$_de4pgfww&>FTx0<#>c+~ z(Ici_nCp$8#Lew6!{~CH3#Tm53kM6rM7fotT;m!CGCg$bSFIXLPpDIf{ind#{L{7)Vp}vik+fifMKTJkD%BRyyU+p~`-nUO5 z9)TgT08Jt7?i?lWm52HDR#ePPORK4^ol<^w>C=0dsMEdQw4AGk(w;frw7cC#?! zhs9lp{OUnL!NEJ`g9Xw~7Vv92;@6g7Qdx>EFcRc>8Y&jEX6=)vMcqvN#|||)$A4=9 zz;S^JCr!FZShAXD8Zlfpl};kniS9yD3wJEuc`MC0DCMX1=o;w7h-13?8#xMbFoieH z&Goh3EuL6O11&AAWgi3D?Q+VN34N0f^XwQvJq}=l+hxN*^YP|@hEB9KUN<1Isx&b& z{5hXC*gW0ugO8@Bj#^!Hn;6Gkn!DW}shn8;`(Z%rxS+HSUj^uCRAYBEkfbu-X$gk! zW78s$+$ycV@TL?n05u9?A2`8d&S$jn39PEPEwjV!rqtR!s(A|#OW!TJ<1VpXXS5Mw z4@{fSpP${~H{|prUKe~e&9+dNSKSZ*J#GpWY0>+EP{dwS_Q42P&Hd5Qi1B8A3ijDC z10w>qD!BJ_aeRKZ02rE0>Q13?{J3r#3zB!4UAD~E)jlR+8PKT!I)ScP&6OO*%$-LW zrDT5sF9Hn%F9Mh1fq^@Q;5wV>VbmFZgv{#a&!1>Uztz9kH_w=U{MmT%@@~i!NdpGR z$*pB}15&`S?u(>uWdFH6|DbV7!?23E;TG1p<63?~POghjH&OYpJ)t)$PCi>k|Hwo0 zAt7%HQxE6lUH?AJ(q>5ci(Y1-!989)vMXEI;nuyGrQ5b0U}E(}1biR3J1$5q2#AK! z>L*_I#;DEDu!}l9Nytb>!=a5EHf%agUn-r%+<=7{rBPMbyEVFpx*5%SDC#l?G{U7%4MX{Rt9L$=$EbcJ4KkeO=E3WQIRRu2!4E5E)JLxzF_97{_B z<S(}D~nXb$Id!=@AARu)%rmvlw^-7rR3^Gyd5)p!k}%>ui+<-3Z}d~ zVPoJ6e<@)No z--Z=J0!+|PJ#wUP|Nh4gAHM$5T<7idCj|xW9NO@>dp*+?JKpWYO_$c0V#BoHbVfEMs?Elydj-VmNjiv6NPg zJNg|1-zTEnpw|X3gP$jqq|J8R%i6bek-K<#KYYo{{eRXY9ijqHeH9Th?j-_eDFc&xO(WHZEJ@J#+cn4x$W27=hs6FD~mcsy^q>y&tS*VE^RI z<1>$^`{^!KvG2il%>>0I+j39S*vF8esjJi#KP=~bTK@V{SxL!CkR`aG%FWQ*r74Q*fYlp9%w_&^q7KDi-=HWy5^xz{@NPe00xZEJi3>tv$5t*)u`G2dd0zMSh6G1`@Z46VE^+0zLof-#PfY zPuP)ZYn`1`23OzGx~zBbQkU!QWhw4WX1cRxy? zox)%|r>Pcr3HCN4r?>vY*3<}7bdfdcY1{H3*IPKr+8@&cJCmta8})Oe_Vibl7G`^wR$WOn?b1%-1wu#WCBGk$dC~J$S&~8Dxuf&PyJFwH-X~9;V#rD#@y;Wc zpUiGuU)kY^{^KQ!w$I%jaO_JT@x6Hx=BmC)F-Nt()fLV3Ua6(8FQCVXHLLt<2W?n) zD9=$z&wS&T(WU#Uwr+oAp7bzQ8jtd0`#DFn=BrsZZFi#Xb_`^>QcjsrichfW^$Xti*DUYS?> zF~DQVg)4q3K?%fH%4B>n1p3c$vtg_A&4#@;F>eU72q1HGHXT(Hc#BaxAGQS?(a!3o zG+$@-+q9PfxnHW5AAS_{>xQvKW@Gl}Ajhd%bO}mGFrR)36)jB0pD*^n)N04MG!et8RdVm;^sc+#mZoja>^4U-NpXFBee9J_EQxf> z%y%2Fr+zfF+TY*)WJZXl%csd< z52sq1B}LfGkZV629+?s4;J7Mv^@ru8Z=AWbvImoZZQpLZp&{_~0L}5(v+sQKW&vqS zjp9HaJ(4`H7ia6qGoZC=H_Ni72xr={Dv4V5uhcKc&+6j;cime$l}etO>ykNr)~78| zXY%`oO%qnc8MD&7u~kdG8t-m9+_YQn*}=@Hl%%B6R4e%!yE9`Nr&=zOo27N`b)Op* zD>+jMs@YT^?7#Q5wV^%DU0g0Bgh9NsAl^sK>V`0T38;{S^&gwA>_hs657MU-A3v{f z;RInJzx18=rEPY#uC&JHz1jbY2w5)`eHPW9oTS=Y?x9FD#pT5Qu5ucwC6Q5DR(9QV zEl*^tS-Gf%X<7NapY^x?sWaY35puYvwfwLJvp(%lmDkv7wY}JROUEcV-KeGvk0`m+ zMUU;Gl&)r*dls4r;M|cDZhZx+D?@SF-qDXw>)#IT6V<*gn2FC^944V#T5ULna-5b@#6I;60DUjyb%;1GgyNnYim(n{(Hf3s>s$hVMO5wI$qq>yR>A;8uji2*7Y0wSY3Y1Kj)WZzqcH6 z+QB*m z;sFu?z%x$+34lnred@8;Ax&TQQ9rxG6JvN!JMHSu$ZF5kkn$QVEX9UHk#?SzFGT+sMSx?!(<5#O()e|Z^Q8Y=<4&(5?olywtWLT8xkjEV zW)9q|n$_QXb@=za(gZLE8+(coC{w_eIw$AC{7m;nni=ERxWPKw>$i}9K_IqY-r)}0u9Nw^lX z;QxHaiEIb2KcC^wh0Rz5FUH`eLHHGNu0zvO(50u!sX1ixfO_(PvNB=@F4UbkHA~;s z)+kA6D9zlnV~J?3Y?1Q>Q0GFk;c^cno;_Yezi0ceuRT>P=FeB&h{RhYijqv<`EBnM zHDAOzo}RUow4PbCj{++aij90~uezP`@(mPz($;Eoy5ee~+e*bUefv7ko{jIp(TmANgGa0e4TshU1OjHd)$I4(P@03gnov5TwxT+` zRk2c5PfPfq40G87DkQKIh7T^PhRMlLzcBSNfEXMUheG8paxA$p3$Ad1GcEZ~PRtJg z4guVFT=2(PBeD5N#epJli(7ATJdy0&(QFETzj54aYP7ls96sMamOVtK4>63xI1*{i z3t}ir-ZoNUi!;D}c$2P6)PVzr%b$-Vp~w9cI31EPCRa|S3JV>+WtiWuiV$VQVY;WD z|2K`OdRJS=VI+EYrr^0ui+Y_fDjvs|avCRJzVw3w6cT{VfTnlL$}V88OHZZyj$Tv8 zO0R1Ag5%$qk62M(aed_YzfHMbsYi^&)E z^z=cc68|X>=uqm>C$%b0<)zYoj;yS{ksKr(-x2cIjw0zg9;VaN=$f+GH)1@$3t$6RG3 z;~cP?y4{uLp>1q;&9g_*rmo@+8FE^%vT1TUh-OJP%z`ZC3fImvr-kocg2}L1>j7he zB3SWox@}ZJLKpCvfq~2#QYpA~>m8c{xtU7PGMb4rW%ad%DVYSfk;|DNk+t(Ox^88o zbvv^JARLCkEEGD?R&y?-Ejt??tm@-O0dM9Nj@U%Tz{IkbSdU1kaQcvJ#r!taA2FhA z*;!uchJ|zI3R5jVzq&a1)M`49aAD)URkuzN-dp19qo<6b>(;*yih$n8rTHtT9ad+I zq2YsOERM{?4;lYk?|5;|nl(lYR|f%S03+xE(&j3LL$rBb3NjM_Buq`en~*C0|jQ)#oPX55*ouwyM!{fE?gHT7G6ldEp~ex)53 zWfq$o`-y_6FI$immhv(Ek)2!9!HdVV7RuG8vZMvt_caC%R{cW@!Y=M~fug@oD=$YTZmFjy!OddQB*IMS{nWxccbJPuV#$e!G@uA+?WCOw$SWMa6d+eI zR8y-0-N&K)zltbht`$F%+?(t3{!tz1Eoz1zu#mO7(yZCaG9kKRkb)Y~S{xr5geDQc zP3g89HF6~6)j+G@i2eIB*a2@{JDNJt0k9Ozc9iIk9(U%@nip$kNTA&xD80i%U>9lR z*c#A2Twg!xocwkVaTc{V?nJ@y$GQ-Z#Y^aijHRJSa%i%Y0CJ>}?pwc#}MuM6~q9cJ-R~ zQK>KI(cX;^7zeLQY$w8aj;tOq#TVG3mY6=LWTc73l;Hi zQ^t86KVHwa69Ug*ynnT{WR{YSzrGSs{`z&^G08!qfywi7j_-f^dDzohTam2#=%LxE z7ow%KJKh#cQV+Kq(K*SsWqxqOivN$a_W?goqg33uw-X1P`=MAqWb0UY8l}!~0r;$H~Eg z(RK15@UcA{Tf#@YWS7rDMFvLaSn&v$AUw-TxUhHch6+6t-D(_&m!~5CyBf0=h(}+9 zZM4X=BfIwdcOnN1O`0SB55mmiWsWE$j)1@Upq`9w3{nJS-)~`YogZsH3F;KnUkmRe z<%JloWR6}7w3{yje;*?j`Oku~e@iMaM%y$;CMI%AUAn|1U=@!K2$c#34*08wzIo$_ zb~`$Suu1Tq_1Z$RHdR&s!9zO?9hE-D%?|FrB)R`-nmiyEgZ|^RGxKI;PC$1oB=r6+ zu(HPDrG}RIN+|yxvaJx_;+-eX%bjlM8i^AQ7ZQ>f@uv!uS>`?6$X3FO1|1WPb8!Gn zd9XhG?CS#~suQ&Zt`A6hckL55o542D-nrlB>u)rf-O2aAeDz8?^%6|yU_mL|uelWw zzf*MW$?iyD^cjpA-br5Z`Rm#lqjnRn{->v7eEzTWj_~B%-nWUQY44|i%aVqUZqvH{ zuX(H5?u>l6!Wkq)e{VvYP6%Vhm#_CS!sJp*<@)-hx{&npm{`c@CYGbeCGe+DV`7he zEq5M-amC>)(J5+r{w`xY$q0H(mnuSlrNHMZlbZM+|14p_7sG9sFkVrNrsM!l1StgA zVj8IyUOk+ifG~W}%Ypk^z#dRjr9}Uz4^!Y!b2>oLM?EPXc@M25z(#hHQjnq#?d|2U zK+z5XcO?hxP1s%#lZ*M5ArFbs#?VvZ@I)6w+=i<-^Cgki(HIBa^^Qh=pbE?uhB_Id zEx3qZ<~L(Y!pUYj8;*YVDKCUOV{9PaO~|1GAVJ)Z(UF6_y$#5n2Xk{JgqIk)+3c*Z z5~WWD?H1lfWSkk{>LAuSk)!jvu%l%ZikEa!e+4#E911>PY0R-Hns;QUK;jHl1V%x; zT2y+Hy-K*J;=RG(oc(dI^bCKn!60(CmRD8~TjX&T;S%8KcON)+58Xpxz4l^9d&pbz zyhJ}OI~0e9>!Luq%momEfb2JzwwSOVZ`awQNA&>?aW24yv;oq|=r=wh4hmQ~(g8L` z#>YX*x>NZhlb(v|1Artn83#n1UcYSyOhfX5>fDUVCTHgjEam+C^^&j!LJxqvBlHWf z6~b80a_CURz*EQ=z!h9st;6^_qu+Q3aSLr=n;01xnV2wbzpkx)0oW1yAGkuyPk2p* zMtVxTL~@{##0cOUsF^NcB2T)L%MMQJ>aXS(cbaR(NhAqW&`CoLjzE4DH8n#`6hT%% zD(H*t-`{~J3dzcM;>Kwbp>grn|3Q7RRj)z^29PmIv|p99wV`}KQC(eswcEWvakJnFKtm}GJYPI-~G3^5<5bKI4An2NH)UcHhFJ99-> zS65Op281(gfUZ<$!fIi@BRpmL8Er&bub0<2VC`vU?dChJ@4K)d%J^L2%m83X)ylaF z`!rgksGLwbC{&VTAOqHxY&M<)F;EMajb;|MP)78l|3V7v7f=PNz_{1YfZV5@l$5DM zN0Jz0p4Q_YKc!@T9~0Az(NR!r!@41Bp86}>S|Bs=$;6|1wBw-RfB;*gFb%*OMqub% z5-@TA@|Ej_55+nzleZhY5wZ_P&llSVkS3Y%?%m-Ah-i_aIfZjAO+8sD2ckG&iV6ULnHhB4tMKvA z<`_K;_`WJ|{P-|HF3Lt%Dlpo}drQ{Nn*|=my%IqKw^HUxmMXSD;7Qr+jJA!prP$el z)%{NbK88b|gP1*hAcQev!q^^`i-)L)i5-AncrT3G(gzXmh7qqjSn$dKE-cN>!AXfG zR0q=3utg+o{7e+Bq(VaBkc zJxkYZh(uAAi&|P?MnEe7%TPNg(W|T~L>L1H#A1WN*~V?+hK3-HUfcof>%?Rp{J(&+ z)Veou7jQ_}Els___zSc9*4AA>cjzKuE(9KTH=g8}$cr&pPR1uD5E9b|@^g848H$VV z8O}S14isLma3OmlR|PLDZ1vw$A8y8rD zLx+Y`Z5wi3V2gdVVub#sRlA+WWKd_eu$$^&8p1j3Y{*gSFU zP7)p5qArZA51pb$`cz-6ecUb>6&PpA;N%cc65++BGFu>&huw=x{EPf5s9bf9m(U6Z zN(Kp1#51DWLsJ`LVbt?XuD;?C!;vN>WeC_sofBqnZ{L`=6K@iOIp$5;BGeD`3c8>r zdS#xtdganRY@e}a(R1#|GC7OUVAzXZ+Nq9VzmAfk#G4G#4LcDb+?zk+C|-g2jBrHa z9Dz-W8sR{#;pgu6p|}9;%5dAm}_U|Z~w`|^wI!(ESiRfQ3Fc=yboW_{&Q86vYzvm%ARC;ll-3rU3XZ=dcF~Tl; z+5hGdBb*fPVq@v|?W@eZfb2j3%>xutRqtdU>{RK)HjQ{El%n%Ud&6ccCiV!5H9VQJ zR!CGJjc3@oQFKKTX@wycG&sCMLS(qf7cgp7Kp?aY^O3!Ty;xDZ9y)Xbwh0Jo6ed2Y zko!r~GBXoF`=EZVLpcvVcEI}ps(7q}+e|Y6Q5T0BM#sld?D8?=9ARG@A?#XM4A3p1 zW`M}%Ar#uc>&nZ1D&)XdFq8xGzKJ4YRqaGBVSV&uce`SJP)oxP1Gxj{6RDu~LeB_U zLfE&jtsaeswz1xjdFEjuM30R%CCL#f@VUbE>h{jj((?t^3H2tOz_&^(MJR<(S8%hj zjii>W%gV{2k7^1I1}9K7_v7{($R`G;-;RA7%3z#n2=+tIz=_ynYWq+mkJA3Zq4NhH z0Dc0zyUyz?hIp?=hVU_dVBi4yKj_I|kHAq;Ibn;<0Z$k&38dW^r@D3X(CetXH`COK z4B33^B+)};l$7|M0?ggi;YZT+u5)^~NidFzXtyaDirG8~mE@N`t;r}20^b3hmDkH;ZvsT=0=ImMRr zW=G0SQ>}3Eq}k}L)HJVAV93kLdSbde^z!87I2rK=P!C64AqsK^mx0fTbpuxnX^~Gn zac5o}an@pVxcL0%D4W25gAdxbzI!jDeR`0T9lJR~@;Mr${0?PDo zD=QlEMYo-QJ1(!MI|vQ^wxTY-;D6uX!AbY+`xRSv8@oZKs%g)9!^{jB8f8k%7CWb85yNnA>xQn_&8LOVKY4(&BW|Sh)Fy_DOz}M+{e<7C%{?n&%*eSs;&L;V0 z*VRsU;OJZD9=tywsJ2fPwSd9_Z2%v9{r~mbM}Q6$E$eD$tSo%tozxIX!lq!V9lhIR zQw4dX3Ky7(Lf=EQJE6ptK1xgGDjq3%XnBeG$Po!!d&2pzaKBhcmnW67a4ESVjf71a z{xjU%P^N875@ehjfuSs9Zl5=JU7Z8A{PmwLKGwMO_p1L_qCl*wAsOUY_zLQ&gR{`~ z!dq}Yf!2WU_+z10qHJDiz*GYM+tE)pb*E-Ked|QNY{Kme| zI2Mr-+?uQr1w?ayUoXx_^nW0lM??M_gctYy&cS2~haU7M-~fqCxN->fgoKK~9X8}3 zbv7d_3l-;$@PY|LWZYK6S+o&m1x^Og1`cj)E1MgcsHlEbbC*EW zPHbT4y-|tiyiAww1k%6c!-RKp97rFQ8sLKZRTkzYU}=h1 zfSv(c*NUIO-nlf=a0^y9XvSWyse^0UPe+#p;0J&LZQAeU8CH1du!&;Bztdfq=i?)f3D6ToTX2^@E=4?OmiRR{M^iHM6Bx(U7X>*FC;Az5 z&RXxm$U-Y;3Y!$wcZfqE?i<8)Kz>PtKiPEr_%YF$7eLiFHpYl8j*01Njz2yn_--6R zIFD-d(vWvGgK`lHDa?PLad2MgRMh;EykRiI1~64F^L zwFSU})&h(v84Dg|jE1`_ZXcjl3-m0dz4PO((^wl=pfx0LazU9RNrt(38QIy8+W^MC zbR^agiNZ8Y0g+V=UfbavMdkwj+seNV#K#U6I7vax@n_sdnHIt?T6Oq7`qi#Ppm(gK z%xF(t2DFL5WW-sEM*;j(lT5W|4AfU-h)MMCOJ^1ryYbw>3qy>Ij{voh?0X2? zptGv%y*Kjk^*^d*4m@H`M+~%)>e5gx;G1S#m+JoRcwY)k)>y{lo!=M zrdg`Y{{#mihSJriznY&sZhoT7u-)PS>B&3#;2#{5>V~~=)PoL3lHKk3tld<42 zIAO+gh6REO=QMHOz!o0%tAON&ux>SATz8npJQn4~Eh645cSFR**`G?9YzGj>*6p)sa-Q!3hRZam`B79}Fz zbfx#5x_MOWdYu%rFjx3*2jQjS{+&zTx`r)L@U0=B88kk0M{L|M91UU(4+c-5WkH~c zguBGSNw$N9`+A{oFj8M%3)yF*2Lhq;c`Qxv5g5K%eW@9xE`C+Rz84n{=fS~L{qo_X z^DbQM>;1!wi9`|&UA{GCq+LU*7{t&|{wUg`^usZ@j(IBB?TGYWm?UxB^53cd=lmWd z4@y=-l3g-V@&5cOrNsJ2>;-7yewbgNjo!h6e;3JS3@nC{;UKgKD8@#Y=xQ)n8)Yr= z8y6QLMf(HfTy>iaI|j7u7FJgLr%vr4ClBhOy1}y-)d6-wzS}iaJKYGPed)V1_z)0! zA(+AmIJOQ?2r4uX7Ro(h+gyx~T(-Y15d_$g*mt?u{T?!@q2@31%SDDU#EtJrj}!Ud zhYtOOp%C?rzibSCwXfQ>bXiEAunByD{tZ*o+j7}@KXN_rk+2w%SV0&_Yi~CWA|C_M?by;$ zE`m+M&5i13UAd7^o$i7aP;mbBo(UR``8!19)qLi)xru>cdj-7U@$M%0j_bv{hyo@OJ zGsj&q2@OhS3#PkVDk)7;B=sju1sOODsrb-JHt=P0YNSVF?hJm4R`TyQ zjE9JV9rRmDTpX&7V(j(^ZoGcYo+Jo0)*D~n4>(rvO?XZ)Eq=h0Wp6o=qs>Okbl&19 z^n&2v4 zdZ>v$p2|fVIhiP2w5}oO$q*aRcQIv z1`Qz}!AK0WlA}g}yf#>E%bR1gJ5lT6bB_98)AcmpsdPQ=oduK6S@ehT8Y2IfaI@jd zQ$E_^6SUbN=mx+N^!25KN$l&>TVY=raN51SAKx6qh+a1!MHHTXsCN!82AE+Nqazk@ z;`i)tZ#6?(QJ`O0-`qMHhcORhn^nV{wx6t%Hs8?5yvt+%Q+aWKQ~7rK9T{%+jCtm1 z3oMrBU;81QvO*0A(s%xrXUvdnF&ZbhQ@|fuw*)se$A0*rATKY!epL>Q61$^e?AC#q z82$RL#PK-@U@RAm8RpNG*UZ2?8*H*@;$XXY0H2E-E8(QTN&^^SM)I{nmSHOrM;#0+PIgyJ!o}JR>ynqm+Nk*N|}FKG@Ll0WnkVXxvL=Q z6(ps*ckf2h$~ss%s3emyRUOX}5jXYq3fFs)fq^XtPcxBD_u1y)>LA2bdAP2lLk0TD z(^|M=5u_!~dAuBO8!n?mU{YqesB#ML3l12RlJInpZryqSLAhL%yLJ)MeVog&7-I!% zixNW?g#O*#-H@tkdgdpxJKFth+WeROZ&y1YT(CSqfBV*Pjn(RRZbI?N{B(?thv~iY zw5Nat5wg#SZk@I^+Mb-c_Pw9o(9lB7ezI7Q+G<~T-B}{VV|m_11Dkc*@zIlsQH3cA zY|+E-Dv<|>WrBt&;u7N%y1qY#AstXTO2TwGi@=Db69XSIR`Dt_=?;Z@1O zd4^$Z_}FQc5(3|`B`B{Ngj1THvB%#)G`YRXu=@gauMLHnk31qp#{shdUdqN0e-DU( zz6m#YMfdXEey$g)vp>NexA(CU55*=D(aXEH#dKRJIOO&vNRw})OKE6r#i3&h3IoLo z4r!pl4j5GJ=!7IL!wcZhJ_sK^C~D)5ZSniifr7!381Ug$1{Q9tK5~l=#)jOzc{7r@ zWI!>HtU$=eU14`}UT9WBd1P>WV*N7_$%(xiFYN&eLy$iJmM?<|auierc0%;=4X{0r z&H~$`(0~)KK+`*)G5(+H-ut5o zp>p(_;u7V7w-~KjPqD~zn#oEv39}tURfw)fJ;lr4R8L}#zxt*_R+sx(_QI`LO9uS2 z`c$p~B?$@Ryi)As&eEIS& z>zu~~Yd-5h$>hhqQDhpVdTUd?uiAZ|gA-cDf;*Qt_ckd>=Iz4-!QUIZd#_nU#7n=9 zno|80_>VC>@SjKm5|U&8GF6H0_*W-RVKeq?;_LtPE#`7tNa`6!-vpF7oBGCFIJQDp z`0c4-P3C2T4fwcK0hLknU#Xoj#M6*sr3V&*7PmMVnb(#^) zx~7}Ny~>PQ_6awM|Bt7k(LVPtD5}Zi4(iGc9zYaUCT9UpIoT>yir?P6BS$w7uLQBQ z39uK=47jj3Z5Rv!y#ee>+#xb7qO^3u9W2Gn2l|k|>e$dK8 zj+ID#!U+M%28Pt*^_;bk9Lx5`UghC&GouZXw+A*h!Ik<5D8v4UlDV;IQ~W{5;P}zk z!)pvPiIE_^N^eu*k&%Eo7%mvkoj)DO61Wz|4@isf4I;}0av{|H*wC%spt^?4!I%}Y zrZ;7a^Nst9((j0=XGms=oBn)7Qy3a0@Lg!*9p=WI$*a=RKMHLvZ{F+$yhbcA0q>3tdNvuKq}}Or z;5_w#1DNy0xMxrA)D+XfgI#$0wM&Dr2SS@A0Er1c(Z4^=!0}-~mD3;2dkY&h;dHFq z82;8JT@&@4hZ7 zazwWYJSig$jRcttN?s0*1MtA1PY81tkTUA5ox66OPA65+{0}^VBIcal7c%f2A8ty( zyMpcS1b3>H7Ha?|8?bp|vX>ky9|{sKF2Z-g*tXCf4R{V>_1A3Tm22+A^Wb-|FrGgV z<>KO^v_y*NAD^#DxWdHATvP=g z9BvbkJ@Zn4FffTl7kZijNW#)Xjo3o;K?xNhIpZB;DY3?T#$wH*ecG2e=r0TZDeLZj z>%=sQGkoKB&jwhY!Lcz-un;IpUVwOg$7Y*^mrhVn5XgZ>9J9Qf;RV1Mjkg8Bhf6Da z0=Xg0-8jV9j{J|9=30mh``>gr=#@&P-Bs&jcZL)$Dp9Auo6J@TMI_E zzMkjs;df7Mwl!hQ971d`08IozniTF)(S@4rux%a!i-zg|`YfDJgE*#4oc{HhjQAxG z!GCtmS@u#jqT=Aj@xBgC%Ld*-q|cr)^{v!LfeTSZp7l7a0%fy-su@4P zDbx~1g*VI&vT~wR9l|RqPigM6ouo_U{|YK=S@k3snnGt~ns9~^gVda7(yonmv)fZ!d0S>_;^PV^{ z3S^AISvgqA7+hEDN*UCE#e+^h6b>-JqR9-x{F*I+iUxGO6FOc}QPa~8{k7e41<9W9 zM3K(hHthac!p!yBu0-kTBSFmuW@cUQBzLVyp}1e+^(yn{CS(mL&w;@0K`jt6fQcWc z5Mzm82xSB4(VJ@&6vjA7%iLQ}CTVX%o-Zy6Lp=~hK@72gKJl+z4hx%GGZPC^0@O-< zW1}U!6PTl{O(9@_+7%xF7mjFLkdLTH6|VmSiWKv*{|geu)p@5DuOfWs4!*zrhk5+{ zb6F9d{{d~x6Q*vn+qFK@vrQ0~|B5XlKR1_39B+~po;ubI?8CuS7`GLGp>Cj{(#fF! zln@ukL@(?h^9u{3winPiL_wZ^bBk!#4Et1?n_HIV6<%H?M}Pw7KlW|xS)pD-)-Q_+ zWAqGSZyoSOUrU#N1 z9KrMq48K=b!I~I50FMRU%%eP|ZufY!)9u&ulgVHBZVT8D|2+6YYZ17Mg)!gV_syHN zwpk_Xe4FX_=T!EvL}U357RRKT4uha3qo8=NSpoaZi@~8Xi=->&=7=iH7qyv&atL28 zLxiA%_{0AOU-cr_LtUN9qKTOziW>8C5lFESGVhTWs~cE=gh=t+XgXFnPs(`M>u zt@T$Gaujk4F*EIbTg^{wCn33_;Gm$*X_c1YWxJ@2(tU4kIEiktXK~`z z_`|O?*_8^76c(Q;(jE(tiTSSQaq&y<$lMBDNnnQF?wj4DS&Yc+5%`gl{N*JonYO=> zx+TcuBsCpet{8_LBB$APA0I5xnTD1fX=$l%d%t{{Ghy$!8%NN61Zgk+@JP^(60+lyUp)(@p`% z9p!AYj&o76!IKJ3^W-G}d!y6w@uu~fe zVpf$)yA;j7$I9#tjkip0U~yomlBrx6o~Xi(hlpM#zWxWuTo_6c5ef$rl{m`Rtb@-e zD!D7Fzd3Q!4h;-B(Rz6)o5!b`AEJ6iwp_j-H$J!9+nASVO)YQTw^`I$6Q&q!1Up#p zznUNlvr8LwNaL^&W1nTR|gR%4jgFC{%LVLu)!_N=zckkS` z3ryii8|J3nX{j3*hgqZv-CD5FKUn-d^y2-)65J9|@9!!1$zly&i#TJP0QM+s0F~n) z1jIW0oZjly@-S~iz=nPjcj z)G-L#uPd+yG^;n^<44@ux0yvBom|D8fCHDw+R({`{IV(~waZnkvL)zCvL0oYPS!-| z6mvNKM$p)Y;M&0D0731C>Pbf!=LN`K*izxbZ%I;{hN_IXAbzaP1jzUj?fwid%8>cV#-M$Kvk&qO1SmJcRr>zV4^`!ock4S?K*(V=WPkYZ z3ORu{Z=Pp(FgB$Lss+G>5%4@&gO8ax9JXg`pL+>DgAd|cdR4wloIsj@UfL@P?tc^` z=sbY2+(kx)K|)7dVd?cM(~DGy|3fypPvpVrnk2S!+z$ohOhIx1KdvPn` z*+2hgK&F>=Zh9lge&GZ`T!QlvmnP&5@7|#TU>U%rG6_B)rk+F50bR~1DCThHSA;#${m~K=`)kZHMpG7*B zA*g#zXcY+dur^H1<4AIRCq=VBA>BfRG;07cv3vV=BK&4vbO4-S7YaP^DxjLt@La{E zlCj`f_5fW0Z=)9}rx-Y9ub4zfJ3u48b#qX;VUl`^=|;q+>fjVBYa_?`JDJ&A8g`sx zBvFtW>AZFcybZqQ({WRPdru}-4qA*3`w<=kXCA=1EBN@hJUyPh*oy2>WrMImj=)G3 zx-C%QTerP`{NxEj!QdBykSZ>27~N{*Caywnc=Ve^&ijjiMJ>r15@h!+ElrveoADX7 z;43OyuAa0+r~ta6qo9^pzCd4ym5U`pWO7SBI+37zcLOKc7kn~ z&Y2%@n`l~qqGySQycxGA=-g+|s!4^EQY}SFPs}G{rlBE5d!fY0C&C}WX03oeBO~A& zs<)VGY=A^79Yqu<%mxXQ;)nCsB%VHHAGBsyy%ueWq9RDP}=os}bMO z-Py6qeTUc-JAn6HJgvASz|_^?Z5%Z~onjq^aa#dS{My&w#i^zHEG`a;P_IFVhbB;l zI!C?}>WNYF)FeLyycLOxB)$#TU0?9loC)qQ#KVC83{s(7L`<*Q zOtJ8U$Rz|~&!1Z<4^Pqds9v*h7dE+UVNpd%a~#$(rR)B_zQ||YOJ_aMTJOswly7oc zU}5W8x?Azvmxg4PL*Im%9Q9^tna$i|Y3}ipM7*fa+Z~Cf0GwJucfZ}>L8MzSr&g@$ zNxN4@3H}yIDgr!o+;^HhOFD(I_;Z{$*750=Fq#Fc2FvYQw}<~KT^UD^>|k{wGtIGr zY#bu!@*=$+eN41mpkcy}bG7VlHF?xK3KfyUMAs&8MWsVzcLRzIs9_R~gU0Ct^u zb_t16$TIC#00OFV-lr_n9fZTAV7izH#Y4TUo7z2m++H!K7;i1goB?KF@}%f=_5w^S zy$8Yo&T#~I4Ws3OWB1wf=gILjl5}f#0&1cfBWD)3 zvFOk0ho3f4%ga3{curthenG2Hp9KQ_<4YgS-3NkVl#JAWyvLLyfz##b)16sq*)ieg{LOW`iqKNTnCc@34r+G_ zT6g5}WxnGRlaXd$j4dRU+<#_k{XtwqFayQ9UA%XeSw<{Hn?{?JjMe;%dGWsH&skYf zPcElkUvpZwy><2K-Gqk&wL!|;N#cvFrkEb*11zDu#Oq1K$ca~=EQ9-Iu9Q*)T}sT2 zet&5HaYXI7i_;{stu!GUXbllNWydg3adP!dMVQL+a{3U;|RN?Rg1B z0Ak=EwnCE$yd5nQ6ITfnM2mm{Yv5RM_<`}j?7kpV9j%#@P=l7_<*lIQj*~whUY@2;TO3^U-C?}`2$2nYx-Vy1E zT=VLi%P0mHr+<4F`(MwpE6W<+*t*S})pcNK=cw0EWq{+T3$D3CO3oBg_6>^7CTYlu<&+AvIdRbyeCq;&dzEdMDG0KB@WrFrg7#p|yl{!Pd z4$lQA=j7?Ng*?q`Jh&CJgRA6>sJ9SZq$Y55uqYwxT6gz#tEa!}22VzPeV#vCNB7qT zJ~Hn@#cTBa3v4(LB9JpKXNi8ad2oNKv&|7$bMX31lFB}k2zqEu6;xtlW9J>W*bQkj zGc*7F;nCI;O$H9d5%xJw*h3Q%JXEG@^Y3TGUYWFJ$1?fRe#ZXyqM4H3_pd(ZXT5IQ zJ@^UkaE~|#Cr78CjelKk%wCZv4w~;fFBr*c?x+r98msV&68ZM_GFe)Bx|PlJ{FAyb zbk%AqccYrK7*r@_x|l%zPE1Vp_4h$h)RK1XYi4GvD;4*&*zC^rYipX>#frCBh1qtmaZyVru>b1>H?zl2*&*mkz5re&7|WSSjqZSOUU z9@hf~9Resht0zi=jX7}FVt5fnI3rZ_mpVbhe-?fD6*YQd33Dsk2;v$zX(39Iw-#W;%_ zqQ0U9)EKKFe>-N?A)k2T$L-{43jsS@`KX<5jYi zv81WZpW-SlckSF+U_E)lPa5!W4}CEaWcGQsFa4 zL#Sjd<8Id&B8oYiWfrE~*jZHUDdA~Yq*%P4+BZ@eT2xpxkc4?(Yk%TQyVBQiR|$aE zy_ak&YAS6`wY1AE*=Y;nc{FS4n!gc@tc2JuTlJe2-@S_C^GH z=E{yUh&z2-RPd5Z3;key2r{XDb#)24xo-&E8p^CP3!b`H+pYqSS!_@BO+)ixk>;gk zk6WHc4i9YJdsVs-p5?$nd`YP{82M= z-$D{$$v+e5_eeNSnuEv}2}PDEFV9DNvtAK&Wzp7sFtHp+_nc9s_4t7;By7Q~yjved zTz|{sZdlR!F`IW=%-GSGS8l-1xU+P=VxKiykwYFK{UK+tE{TF+l4d5k=NdM+hwN_5VqL z@ZU5F{HwxSZ+3ru{d(fvVLv(6=79&BB3|6!)!4rMz@v}KAJJaHuV$CA-1oU7$A~)N zi*GdzncOS6&H_B4<3X~=sM8dd#gt$5V3bLADZzmU@ms~LFPeoavz|V41|+;FOwy-a z%k=i`z31&cE)!j5&ew=fj}Ma)?cuec-7DphseXv3g?Jo#(!1oZD9JU?vs${NtO(tJLRZr74lb-(mv^rEE=xdx;rI#L4swO!`#_*`$K2 zR`BNOI3fCG@mFsY1OcjSXyu42f`wPtmhW?MePjH=g&zuZ z+bu?8nrvoR`*x<^CqtHV%N;e$Y)(`$f$Qn~_CZQr+nL!I4aW>F9f8(6d-sj*Gf_=N zI(yC2@K)zPuPhgFzv+^4Ovxb%D7=Ku3y9+HUAsS(x4*2t4I4sfQ;l+(!>7k(q?88| z%e^M@A5>yY;gfB144A`7YWl~h!uQkKZ`-TkrLlp z-XlKPGaF-9wA3|~&Cy39QQ+z#)cpuMlJb%Ky(||PjJbuc|IBgIg|&`d-l(au0T^Rb z!I+WX+sVh&(uNb(8_CISwX*;84YfR?N_YHCpH!|o*pl3^C0@UPPVv-R*?G+4!a(1l zozUFvV5ti)V`Q)Ct=8uym`i74ob=jAQlaaZP; z&rCQ6jl=RwceOUGE>!5rryEq_Y@Rz;4XV-3lqh|mda45WtTFbt{X>cf5rK08%4wxl z33-#oCO*b~!*#cYzlCsb36C~mm!b63&VJnk4Q9(`5edO;n zRX7Y(>^V(KaQ}fZjh6e)pFiykC)nC=%7J6<6l>jCCJbc)N(uZNrmbp1c7i_ym&Tf> zeMDaD5m&m_h$V$#-X*4KY1y@vl`$v7g{@CI=AXY5M{E>$s;7?uZ4zB-S7pkQuo$zNpdQZ=)KPvIX2@k93rrL&223X&p#I#1ug1WfHD?DhN7bp9BZ%lV$ zI4Az$Wq}~1U#+^OPOpVpKXvD2*q<%ykL5%$dC$Uly)}Vma6QM+{31wG#MxeP|HQ{z zRrkB*cgdXVXU3v191kQ0qgGGrx-N{KFkb`e|#jphOlbXb8nz)@oiEtXgm>`uSa2F;r~|APRi9CuG4*W#yU1B2@y~w=L7|>gbB<|mvB2gz&Vu4g%uGB_D>*u<@^Hhqwk67PI+UXH*;g7TE{O_mwx36c&U-z_8>gygwYMQ} zwc1$U0(B1ttSTzHdwXwVV%kDG?jYjS33Q4@`jQGnFoWe{=bH|j&Q1YDt^`ocs?;&f zZ)QRCL|jHjV~d#>7_w4J7r#9lrC)vK6JNX$;L^!{g;G~1?Aufq#5%CFhskc$PJLS$ zC6zbcY9=iwYd5>RgXJPpq({48hyPUmF`R*0Q=F`A@3LjH)FI4INOzCX#^eIiS`g3Z zFr;XeJpFXTYPx|_Naz+WdDieF+8;UkqlfJfSUEWUse7JARVV+!DW3WbQ`1>yv4RI? zf(14uXzhB@zpv_793+jCJ!=0zDnIv}`T8+ms=nUyALr849z4i)Na=H${E^mJnXodX zyBTvbO4c3WsAr;1&yWxA4(}2)883%MIN~?5oFCYH>1L7GuBLqc$dQGNgH;$Vn{-{H z_1E)PcX&XYUQkTz&nbE=_dqTW!^ib0`1Z<5wz$U|`cp0U?SOV0=$iYIjR&$06ok1s!nCP%0rtZAOCBIb7Imh~XYf{6iA- znWYq!f%)$q?CKQA9~=zcm^4TCYGsZA#aCS2tJRK26=^+=_P>5kpWahvn6MWH&@0oO zc_*h=P@~dWkMxaM%nfm_TIe43gP{Ct*+QeeGt6Y*%Pw=5*sUZgm%?I6SU~bR3iG1I z>?3XGZBK?@Od7h4xUs$ln;qeed47&`_lWaK_(^mUaR-La z4!U~;jD*6QV+*6&`)53MDo~NVIOq*oFyEOo-5K`g2?IPVEcd_p%wglVAF4r)GlN$4 z`n&aRlhEnF1XrqTVf*j;;f(FBkt{w`{=va@kVvKYh6l@&o#JJ8=ES{e^3}XY`KWr3 zf@v0>h)+L1=?3fUr!OYlmvcj0KUPeBOfVZFbABZ;;^!5#wVaBtjkby-Ki(d@Hh2pd zt86F7vY<0uVy;iMlQ3&Z9!(oLa(^Z*nCs1SW1Nk)1ILNc$Ztp!MdM6fZowlm}S_g3@SM3w65>^_S;^vHV|Erx4#a_@G@-@SVf8IMXd zGY&63{hqH)bwHklfHBn8A${-OnSXte5KoK{H0@wQ6kY(rjlk@fb}ZhoeV_iIYwV1f z7U`b@xwpQideL($T%g>+(&M<4qON@bLy4ehL<)^&C67VZso!5iM9kC~_T_ba`c(Y% zj9AZsilm1EN98-(qN%>yc({oJ>I4SM}p9=iIV{Y4+2v81oS zv2n+j8jgH+ww3+{UtcgeFaA-qwtoL)dU1U+=ZO!K@ap-WaTcvGt;}?s>VGiNdHdF_ zYmI)p8J8FG7ffiSEKcSxO{3wax^6voG3K}0_>#&or)viK(N3pIIw8iotm09kn)UO< z5f?@}CZ;{VEPvAW$Z%@wz(!#`aw9Nj>5v(zN(LddcAQv#yy8`*bJ9;5fpGgz8%IBq zM!4_n$-VV(!dBOD3+56VuQ4O<)-0K$)W^)jz6&4;dy>jHgwRhMDj{ejL2)Mt)z_v9 z%!g~kqb4JaRq5YP~;Dd89KYWBX_PW)jJK z`qs#CQ8@QsnwIrRox@R<5OQZ$Lhx(A4k!YzsR& z@WW!u64rJtSkS7Yw4AZryUa`RG~g4Vh>Bg5yur zwdG1~sue(yP%IpF>qdmsD@nbykLnSV&+t2CBh@!nWp_j}I$u*#^)1iuW0`b%+NWMs z{i@Q>l}aP*(4^}Q5|o0+sD42h!?wNQ2*(kM;Cs34FGfW4cYE^e+x*Bcdke52ThiyF zV&50I_0)NF1^u^@On$z0$(ZkKDtBabSzut~S3RD6D72}>_sVUT@HzHU#(=iDzOeW& z%dkwD=w!2Uc)aJt^CpQvjpLvD9N14v-_n^mx>6avt~SeBGax-wn%7Q7PjZhkQmLkP zKN>2QmacfNQg3&R1ozQH>EyXjZgF_4d<{r`AMnmAg#_tb<% z=^uQcxN!M;;J5r?sf+uRmY%p8i3ZopJg#winmoF+q3b2)Y57XVen(^`^?A`Q*T2pg zW5%-OWnWv9~ClF9x2N%naud7Hay)W>=j*b}VCIW8>%}J%_?NhjU>oWVfhc zk@-sj-PzpV?>LlVZgB9ywS|I;T^dUc9_O^ioPLVPd_HX+l2VdfdG2#Y%&riRf)Jk} zqZ9XB1pf7dWc{T&Ln&$L6a^2pEm5bqwA z@atFE%?g6j=Z?Gb&^$| zf3_jNJ6^t@YW@ma*eTwywD9(Fcb@6zNBl2%Pwy0crs_^;D z6z_PC%=fFmtB>xG{7z9YU_(j9a`BI!wHeuX3!CjGzP0FX4F+8J^Vd?L9lKoeBj1-? z%lq(wZQSvJm>7#>uL?)dryD%G$@9=r>c4mXuNKrQ?5L0Rq=}5rF6A)JWKzBn-b+J0 zHTLUDOA^UixAsnRHM%7`$4Ltw49sWNmoA&V@MvaTwvA$6>c$Nv-h>V=?we4+#Yv9Q%z4k!Zc7Qme{tqxCpS4#&hw z^@QSmN0xfysMof;mIXZ!sCeEZ7XMD(ZTmuk-Q)>k;qx9hm}5|6oisV;0Df%hI(^Ai zdkIBlJ}ndMdIb>6hJ=Qo;T#YKZG`0t@f65lm;=c%ZOXzC_oO>YHUCBv*z}fJfvu&lzd+bo(l+&u z#H_LPHB!(+0s^@grI?Sq&QA|RS9*L@CAMsBW%vdA`e_o=hQXbz zkbUF{Yy9?FxcYWRaH{&d)Kur8dFQ)FCcHX( zVk~V)?T7a@8hY%MWPg9y6}`ddPE&W#`P^^Pk*ju}u8U3j%9SXS?Q7{}S@;(0m9+@lnW8VTDzDVSOPt?F)1q!7!%{3zdi zA_jE=I9|P;Vb*bG*5FuDVi_v)a1kGCYop1&&Z@G!=5Xh?a*7pRrjwy6(?i5B6AkWV zddwR$MOkk{=|r)d@crQTEtD683TZF1$}dI+$0#KfzCIkNCxKt~;?s>>>xmCH);q^0 z>4~2;KB7++3I%4E^G4BdOIj(!r6c|k5uDJOIL-}Sfj|;82;_>~sSX?6TUOHjRf6Cj z8z5#AMX@D5(IVacM2sx&;f((tAGL)mf3L>OHSRe-@;~>AS0t*Ogn!`D1`^J9idSHS zDH#h5>kH@A`L+oSODsJ>n{R)fKR-MBR902xD*i66>$y-)^~_6&IQO7%ySfm5e`vmq z^HYa|(<=*()r)jz|31wuTHdX-=fNvpzFbYusXcg%Q!^LAx^Gv<`C0Ta{?er7eg6Ia zmif_)Xr+YI9(~)>$CB8Ovpu|qjO_4fG*IR2YOJIyTHvAp@}6p=867`s+nhM4()qWW z(xmjCdVl4l%73)}#@kghu74>%YmbM)m<3hwM-|;{)w%skZ#V> zy^EU=quiHDSI!c@Dev#~{$GTB2RxSj|F1StA(ApOD~d>zks`b7J(E${L?|nvQV3bu zvV}5|osgA`$WDc__nzl{_xyh6{LVT5^FO_MUiHN7zV7S#Uf=8U`Mj6Q%s)^0|AZX= zc^vLrUFyGoTz)-m;)K~Yx)aUxhyQlC^l-@do+~s9U=^cB&6!gPW1QMHVQ{ zXY>5#=Ry^31CjePvm=utKXF)~3Dd4kyayxCvPRQ#Kf~%oRcy@>fp@KUj}`6Tv)5jV zo-oh`0P{|Kxpi>w96t5CS9sPqK!nxukq-hL(yXlc)Tk;+=O}_i~x|-FSKa>k4K_ET3>Wt-jN#PTrB?nEV1RSOA0HU^OqMb;FS;ytas((Y#EA9;BtYTQ+{ez!$`NW%d^eg)L0&#y4mQQVrUXj$di)pf z%IgU_#tK*)YIl$2yiHT4jgxF|39Oft6m|`bN!46uX9;c+;QfJ^!nb+!s+p{T(oe5Q zh#4{jSM%}xfR8!gC!)A9`B=eg#I!$JVw?Vi=?R&BP6cSq8Cq2p70d77LojWzDeUdY z{t7)TQWethSelupi_<*Id_&=L*BxLLa6z=au30z)ef*Z~qHdb1Eb&j9^Ju`oWofw& z#by*Qd5w*P+;Kh@C{3Wj!7775Q4r$h-ug08jLoO9)@fi&C}OfIF{ZBO0OQCi`@&Vg z^j&VM{n2LV+9a8JqbYq!{LY=RW~>XGfU_x0Cwv@N z+i3q%*szpMrjbcO;2^r@n#zTp{yahLV)+P z0l0f(M9lrAS!bu|-q;QCVw*xA3sdN*iw?hQ82{v3w12EmAAGwYN5j2EnRk2ox;1QS zBd#VV3SYQjQn4F!_<&bs}1Tw`5)J-2u$KLLnH>svfer8z3!#d)@K3W?IJqoQ&BU~`Skf*S}5i_2=B)*ACtSR|8^^L;ICt$O1e zf|1m#m$lz7di1l}?_}lMCP8zO!NQx1L9Rr($J9r>?r;6L*z^KDerq$ea4 z9jmwdhETp>FJ+(G38pL}a{ z9Kss7j9MFgP5vfOW1W!w=#dZ;WPj}C*}4~PJ|G?MPJgNEO%qGD9NRh;s{R}@9YLq& z44?R-Skq0=w#FD{Zhw?9|) z-e%T!;NJcRrpCsK`uc%kVX+2^irU)A!!~7duq@T?_UpV?R9`PT??^&)$w|`^XmQ@W$Qw8UniImB%~#SR$=)*XczBM zt^K}6DH7-*Ng>1N!_xknSih+Ocp{$byUf+WHET<*TZ~t5>I58%O2O*RDs&x>bKF^2^AgF7cy; zgyJ$Lw*Y8xLzmtwj4W7B11EIAje%QyD!=SP{?T}g2{O9Qe)r1cPAOZh2(4I12$p9c zYz=)R#qIV09O%CN#T0Z@c0%J{f@>5iD_K5PvVfpP>ogemFem^0mzGuU1g_F^6gk;RQu zI%MF0BCoKs==Al@H%yf3B%LK8H3R!-d2f9+bw}Q#7_loOYg${&@3tFWyah(EQ~<6- zPk#sFem=}^ehm$sICn+FoanI~>=MBlh{@Ibp84P;^F5Y4%G%^Yf6Qti|WEANw{mCf4NeF>b ze#{Fgt8tf2}7$6n}vnWUe6U`gHjYC&zaQEgY)(HGxT?>i%a_^N+4*m`4lX|_UoLpfbJiS@@uo=Mjf=Zp zoYkkJRWQ+=q@$?##@AQ&(g(@2xu!Y0;I~?8+Q=>t;0sH^@ zq-tvUzI%I55)%!kmy}$U*wrNXU==Cr4;&}IqyB}n9RdyUqId5m4sk`f3yn*zExz+) zD_wKaBV9$PcLhE^);fwnkl9P_O;~UGEt;G)9Uq>f`Qo%R!^_8a3VtfBiAV)_`0!!& zdHY-%t<68SMgn^*EZXa}5rCqia_8GPEj*ypv@PmdCB7yrAiacx5Ftxp+tDW2O;^YA z`s>}@WW!SB6eU%U`JHF0SfmaB0v#P23kwNB%q3Hal1Td+5*b@DI1kM8`x8%1x0pdiz{!;G6ZxL?f$z3=)^(L1Bh$ z#GH>@Yprje3g})mH3)@cDocT#DRrN1+9z;YTe>*R9&20bn>>>HrTt}5a9{jJrMJB6B zTv}fK%a<=%sj1IzrYO>Ao;noS$Pafa`(uQcC^ig+F~PsxGvNd>N+B=ENK32BG)Q%T z5eoEj(4)Yv9qAE%2?Tx|F**4HFN-GYuKY zIxYVg=w=2=`M|To!QOtbnWEMJx|%}Wtb|vD*Li5Oq&O2}#m|lq50c#{j0EByRLr3} zBK(c=U;ay}|I9)`0sObFUv@!2{6zV%fm@5gKW{>`t~qM$^FhwNM$TPh?k>DAnoM&y zHmccwgCiYp9c^xvMfJ^Goy<2)mbv(* z$$r9J1a>xv<-o>FA?Qc`*B8H7~qnUkqw3+-U*f?;~m+tKvW?K@X{87ZwbW80McP~ znd>}fx|y$_W{#0v8c=NPewZ~NF)Zl%n&;)cZV1f)lO=}V@+EX+@K(L9N~Ac3=pr$3 zYdBlXee!Ge_1!D+h{coO8!CP*pV~*bAc@^|W(-;Z_%rp@fT(!o%M7W*2Ft-Cd!JoB zoqk+Y-+1w%3+p zsCyY)XW_Dk&-+HG(woHOWOgRjQ>Vs}GHeAw zEqqzv$pbaV8^p0)DQtYXzdU|5|?d7smrO!$;a2$)Rc{p zA^r`?o-=cE#m;ldtVa1z%pz1BKVlJRCk{oYeB+EyBzJ7+8<<+pa znES9SWc)3?p5&BtRKG@A9+BVp_St39dTt~ib_2HKKX2S_>F&wspXhO1R@2rhKze+F zWwF1%h%Q3e-dc|BkK~`wi|Rw?FBVq!rCvYB*!hqA;x~2viv!15kEf_kc=n&Ogm|Ej zj_&kn?EpHS-(ORVc_vihtb>4@ac5zM4IVbO_SX?BJq66a!@VC#y+2>9rJcvX;{r8Q z`VZpf{dDKsN+VU|?uM|rzE z75Da3TZ`4=>;5bIlaB?Se%d<{IJ&Ufcve;xGNT|W&f+)m#!FW=Gn~@oW|V0v*i2~nrQ4^VbVW+w z0eZnJN^S5>!{0@*|7P1cIubI_9X{=N@oz3bxiNfe@%8dT+2>hVlTcJ&aihxhO*nyA zdYC6c8V7eCWX6Mw4_V!;93c>6@EwFc=Pz8C5fu~?ntMf=4wJGzn6%(N@lB|2Xn?0f zNogtDlP=^8l-JkQ!Gc1+{aMBtk|pj-B1<@US~mt+9dEa5(flT>&u*{mx)7Xl^(DV6 zVy^kQWHmIx4A}7}o&n{@j-TZe8C*R_$at8dRQY=GH_f0$_qa7Y@K@@qX}DwQh4cEW zss<%*ozaspFmRt8e1bvvKc$d%iPO*A<&=Z$%kK*dTN_~mS({rRbtq_rc!la)rjP*e!T*3Y(jc%{QHF&#&y?xf$7Hpp4)c>;C;oI;5RB zb=B2cxA=xXLQGcZD0)ipcYI{z7!1mGN*%)wy7NI2!xFgnl)6y64-WrC&()k!)ixx> ze1}C%DrQUe+S)A(ixSJVP>AOu`0A{e9~%ZOC1q!e+TSuUV3FKU^LmYq#jpRiteM}U zcddVw#S6ubcBK5WD!VFmSs=ezocR^=MHgwx3*nyG>HP|UYjPj63ls;KGl=&|v{%pG`N{hE^Xj!&G9Hzeq_ zL7v#f2*I9P5bo(#kX?SG4u1ifQ<@*P&SSg-iI5CsZnJvi%a^{-5;=^Co6ppq7O!1- zY52W$eKfy(j?|9JpzzlBR^dP9KH>dbVi{$>OEWUMk60@M=7lDcp>CyjZ##du*dXu3~|zo3^}iK72lnbz89&e zC!}`PYu%HMG1kC+&60oPdtaaB*gKE(@)7(rOgyf*lNGvUI^Q{4amH>g2aK$p0?r$& z`JQ{0n8)^-5cBdWJETk-;PiieM2w@Ljfmo=y?yS0=HO)3&$8!cuhO$9yK=&%6IT=1 zSufI@4ZpGdVD4?grlC)%PO%;y8HT!$n$9kyd~vFQrnuW7#Kp$AQ;;WmZ&^C&kH}*2 zL8sN_b-|loPOX+=>G?E6^7Nm)XMEJgp-vG5t94- z`LJ&S2HDM&fz@82#8&5!9cH$Z$V|@In5rNl0RuHJa;X}IA(J5`r51U4e@b-)xq(6B zKb>8UL)_S(E>b$Z*a|G;QBwotfscF*!4Kq zJb|kFG(XdXxcg--SG@MGy%sz=cKS|89-ll$1ldhjHm6J&0;IOoLu~$a-mBSpJq8D< zW(cQ#KONuomXApp9qWOip^Io`<15$Lo?Q7Tvesz*n6+QOg0qyZD@1wUtMJZ5W}JHS z!(;Lf8_6;HwXk@NP3YL5G1L4x z2^{%6(=u=>5Q*j+4?zM(OHYsV)$ptAOoOQ6+Cwb<3HO49^3&?{)Kp0P@h|kHvf|R?_#arx2yiGU|=REO@~9Bre83B3M07n!~VHas=!`tPNi7ZypgD(MN|*sU^~ zoVanXLEW4C#Bxr0`b$OObF_4q+xNYwmER>p?Qz{9Py{sCFpU>A)t@%zrgDMbAvIc> zf#g~@&hzthmiDX{XPkK6%48JTroJ+KO}%g{*={0%@!^lDss1_l;k89r8XOcukR=@> zqo~7ZTU=Zm^!LPHJScKy`Ek+-!fe}t-5a)FqAtM0AN~l$d-v`oCO(YF2y9yAU5^6- zng|wepTjBW=!CH`0cTOyu!E}t+Mp;NBS}TYW=OW7<-?98kqxhUP}_Rp!y+Fee8G9v zIG+0k3~%rq4?R6$f(#(60X1&BP35*Y4z95K1Cqm@yXLHVi4zRwesA2}Sl!1JmXX%= zxGaD{Z?>;zXPkgjEr@sgZS(~3YNa-TNy1W`!v4ic2%Hy}T2Q4i# z!^5T4*#a1M<`$E7)`}Q>$Wr<3$%v|=!?xPRJK{1j zX_(uC_rX-rv1k90V`{AZy}9RBl+;7KP~ZG8d74=i`;)mQ{+-X;$+mv72VGTBT~`*@ zI$+3xGPv#Ax6tw`SR}Qzy(oLt0tr35{^!xrz$hIikDEMs%W64*zzjfjg=31S`{q?* zLP8xGnF|8qVq^PJP2X&M$yPVl2IYPzw}IQ#cM(z1^43;mI1r7>-g9<_Mapoj`zFd? z#3^;fi$6laGpq)ySI8XnVR?ZE_~!D!f%qOjI4FdMgfxcpu<-KoBGU>EMdx~Lh*CLt zdDGvgb~=7^B9$Xu9TI3MNPTmHgQMs+V#8E|`!!x;6nX#byt>B+iIc1MR^dkeE%Oa( z!9!2aIgAccb8Zro76(T~+5P@p2=w4f_=Rgh-}jNtg9O+VTl_pI=m<6S#8kPAG0nR7 zsYB+!u9V{?@7+b$`-+z`G&1|jT*Dwq4!?Wl$oV&0N#)!)2_JiO=7ZU)k)pgfLtk!R zH;eWrDKSyM_>lc<)yWk;W;;z{CSW|Y&F<2gozZA)y}f!7cqEaz=TzdmMelGwN@cwU zlmv4$YU|f!8FKRstY_4!uD{hhd-IyX`|C0`iqf*OW>>0q#LgVt9T1v?`?$fa!-Hp4oKYUCS=aNpRGnGL(}*7wxxc4`{>(IB;M$zxS$dd6HJJn;W3hWN*6quyhP#?7#WstSSg6;9!zt; z>&Jv;>r#!rHS0@X;thI-E~3dDLeg9~%0npPy6UvGHZIe+9rHrGW)440AZaPG=*LCQmc8#V#j!3&&jzmZ~4ft|ZrnhtE=7`D(oo}^@4wv6$ zaAW&(V@KkJ@UYmvEWMueEoTWy!ZY5?z~^~-4@=OLtBlXvqRuJ>!R*PKP7eJx5s#F* z!^p}r52N5vHld=E&q8)`zy-4mvoLgRg{xx_6Bft{3($Yka zhR#H8*Ekd^pq6X;6m^z2pDB^?72vmGSEJs4T&tTyl-)NWDq0toJ-^t#Uf5aWjY5Aj z0!T$_U2yUz(JiS>zqU#kbyo%dEKqwGo!0vSp`p}=4q-pM3jh^E9R&43#GzrYh+yZ% z#fjph9paoE9KF4ICRWA^>G@3tC7OA+9=x>;hT+?va&WB1|pA6r_&b?93$$aP~cm;`Ku4(u(~~ zJ0B5(Y_9o3?Md<4y1+?o_GNuIkZ}tBWmo*2W}#wn(zQaHNw>P)88*l9PQq+#y%dC( z#r=F<^EMhzl|C=EX~WiFEP`noVyTHm8fnV7hlYkQQS0jJ0-|-q%uJU-p@o7lP`gAJ za>b>jgvEx{{Fpg>mHkoWNnkb@)`^!ZO5yEPF{M^hOPifl-YpJc^nbkSgJ~{=;&8>Q z9x_W!y_K3;8?Taj2PVgF4_{4&b60}+--#V2WfAodFH=3d{8qC*J^gBOl%TiZN8`6I z)YP1>vK#V7o~vy9v5n}+Yiv&0-(54f6r`okn45ArufP|2JyEY?a{r<~Bro5N(kS;O zZ(CO!6sQ3gV zud-(c*>vgON$m7PI|m1ud%;ydZHSoy53t~q4pyGHr*@@ET%#anJ*ZT;S0P4FlK9De zx{aFj{t<7f?EzMOhiuTLfkr*=tP5R+ZrIw+01Z*ycOB_3*uO8@ zJ8k(jU*ET{vHEG~Uh2dAE+@+SCxqTT=?Wb!%CK5N9RT<5_qTqoquoJZ2SK_5r?g-< z;%!IR{|=8uPrxAorpc05gjv0=2s@p(4KmQ}9l)RqM$Da^=LI_I$u48zeYgbYpj)?6 zGc&Jo>lWGDLKk6S(f!%ri~v8se5x&1Sh0nc$%F9W@bqotD|h|`vOGeh@$^@P)1TJX z5vzJIemhb**4-TJ^QtZ69QvNlRWp-_iK?a7e|NQ-OfeI?{Q;#X%C;> z3YFj^FWVLtEx3@+AmqdF05b!fa31%%+cFSBIaxU}viZ!{nUKdv>vQ+OmrWLtbnOk)y?-l4wtK^zeb% zCW65N8rt(y`n~GlFNfJ5hH4?XPw!Mc+{0GQW;L1B|9Y)4t@0P?v{MN(j;Ie&?LQ*? z1~R_%^mNgH4Yk$N%Xb~yPaoJ@_BuVC-7t?xl4X|7A zM^?%>ZuEz!0>wPR%^93|&ckQV-$}QdE;QfOT_b}}zJB5Q^4I=|m6a7nS@HKB_rwSN zN6}HDJ<|Q*l7WiK+M%e0dI&tm1nA=^7)*g^hZPkdF2Z=Wyd7*A~f zQS3t?lm2-0`}bu1z|8O+Vw@686>V+aAXtQ)BRM4-#rCK->7lK%8z!0afEAp_mjl6c ze7`uJ-{L;^IpS-%mUqSV@$S-rg)ssB(zQuZ8=IM5-n>f}4LzHB3v&UgjdbUB4+{F8tXjB@^Fx5ge}G4N(be!$IBXsC%g--TM$NlYCiESsuO3m@@b~`t z|6>Aw$=d%tZ1C@I2?|QsL8JwFpv&fZ1UclziHTm(f02y*-Fw3N5BetDz*zg&ukU59 za!OQ8UKQ67_Sf0fgiou!#{ZPcn%wTN#_0LJ!V&{CElmDX{e8J$EkY1P6R< zfEWNnA-JMsXIlgGpr&Uhyvn72kng~Q({b>+hb1Mjdxy3L;Bn?j;Zd(B11f*QEwLR= z)({3GPXwqe=wa|T!Yw^JKd*~K(8$K`IVN)W!o)847ho@CF8rd3qz*{0pkafN6~sY- zH#_?Cu?OK0kb3uwUPxU|F2iga9!Pkc>1b)ejuQ2^MAhFN@T7l9 zj$O(~@FR>=#cEL(by_S!Xtf;JkE~VfnCKYcba_=y?qFd%u857Do!Ph7UHCrVr%y?k zkgkT92xLJY)%yX%a0~vP_V)bIcU7N0fl;T2Up9rAnFM$KU16|z!y*v5H!q#DLHOK6 z$2?2Udf^jc+)gP5fj>;ec4}nmm*U93p;%+_x*{R5k3sl6J3Ed+QbS`2o~1`%dFgr& znHZ!f?Kb8|RA4~|>NF}RVWUrE@%rDg^o|}mVrFP)3-h8wPaWXHj@bz8C?g{y;VQ22 zhTz2O>gtN-6)q}hW z&e>H0t4K{rky2`ds~xhIWr%6{Zjm#2xifgUowfOKDc%=3deGtHEvayMns!PwTtX;+t^IQ8Iyzwup6v%a1O8~ zK6~-d*B+mT3?R#dCt-L<-+6Kpya*YW?<&-HQ+; zPtFUwJJg=goXNkL{%a$OG~M@hL-pXDkT3xy!jr&$`*f4&7AS$?;fITC?CtHXtR@lD zfl5Zuaq_b@;yBoFl3%Gj9p##hfFT|XOtC9T5???Xu!MwnaBy%;3<1qVD1d>I(#(&F z9d6ynPH=Mv)EVpct3$s>%w%O{E5M zn97TTH{z;qLip#cf)pfc0Y!5bj!`rezcRzU+Zt~*d;>f9fuR9sUCbzQ# zvD@*pxWsdZuA7<3#+n@#w7&&!Xn?~AYtz#+z|iH(=g+T;bU$Cc6@T2nC4~YVN_b4n zB-ZV(U$gi~@JJ+PJ3D{brG1onje0b?EEyoq{rQMT>Bm9F#ZsV>usu)5<2RR-oUBZh z^y(Fhj3Ht9d8AXFQNhMd$f#UdT`+gpg;gj?jI@$o93>!xm9gydqT*s) zj6wlfCZ8C^(w>*PEui&g3Bd?0dd)OPydORKs`vCWIs6#W@?&JcHo}GoHaWScR)4|s zOS|n{lV@?Wx*BOTfO z2JRaRNDn|B8}T*%I2fb=$3)_@<7k`AbSr^^5+8&qH@0>>cz!jR5-thRW2TNf#9-?o z>&AU~Iv!Xq=4T_$pO_2ZzmF1i{|>S;0zB@_ zQACLC<+|X$=>o@y_O&E}bcaa#KUpm(Oy(*H7{SAbJ6!u&(JhVoRwJMYQM@>T*!#0q zHHYv(gzV)ac9i-TC&7(#U_5te$2|MV@15@>RMpN$8Q;#p&#jF>mrr%}z_wd>h)p1I zk;xe83^!VLh)H8BLtt$f=vi>$r9F=;ES7>%j21hdC?|0n0b*80-2VVwiRcH;WRM!#pz z;Iju_!?6v`-7^@UA(;*n%mr{*Hih?!Jx)(IL(dO5diW8cRcp)l^4f_$EH5o&$h4T@XX={47>?|t-w@3QZORd??tiHi~Ui93VKGSy!mmcBQ#5l-FXFhRuz zJ90Dy+XY_K<>rMa$ojFJ)(cFC{{5#twCOpp9Qc#t)f6yDS%eM2UmL#&>4k}V(A%RY z^vtwOL014M_Rwh^=X*~5?-@8W@n{t9E54A=R{+64+pBQR)g$pjm7 zq7a>SMBhg7af%cK?l{qf<&7ycc$=!XkDew;m|JJNVd+p5DtU$xk?42NPa7uY24{qr zM7F$glSgKiAuB99xV~5s&}cHoYyF(ML1njU0-~pfhhU6o^{w^h`py}{$8`Gfmj<*Ww%=WEj6c)p z218?P`E!E|q%(h7IOkz{=nyI1LaQlp z{m11lW@JXOc+rsv7dhy7ynNZ+%7zE}+D2_lW&ik7>(1%;({5&$1ya#^T_g*vQng$*ne>BHu?OrCmOq%$b8f14D-#$>$dS*Vh7b<5Pi6Fcy(qg0GO zwLht8gQPu$Z%0AvVi5ae-biGGr6c`O zi&$&x`3qea?k?)B$m!}v1?*%9u{j&be{NxVyuG05Lz!zSevQ+Q8~b~i8m{#3l7RSd z*Dmk=ak=&6CnVy7)3V;>xn?<~L=M{sEw@L>?OV4f#UO&%$@mMs)N3%#woW*C)WUrJ zNvI5C1({+48REzEmYn5?5j^9ut zUHiWRpsq1f7`!ejt0JeBbg0xhn9n;)l)wEfAsKkEv90Zjfx*_d%pOltadGReZuN`7 zpq{?m+T7f*!O&OiKfn?-0$4Ks>ubs&*x)t(j1j`l3B|=aN=iJXy&y-!TdR!z6ZgvW zW!8;Po$t|Q{kCa!UrpP!!R+-SEJV#xclt+rRh4E~=Fzni{^hL9>z7fhdZ*tq<4>4k zlXV|d2tdGs{MD=W!=~jHD?yn({IM5ZC4Wno$ru~lcuexD=qL5ww4%(=5*8xwzwv#? ztN{nK{MywJnswfGeXu4V_Irt2uEW^kE2+(w<=45&KZDBwi;qYGwlLoX+g^oOo{%#0 zlz^$_B)L#f|GC-N;I0`Ld|dv?_{aZyEU>Jn5Y6wrlGAV9w^vSH9<(>qgzj@1jZx=Z ze|oZ2TxP-qfr8=y24uv-vl{K678d4d$v$Q37=i(eV;gO&<5XX#ICS?o3~)Y2+=2B+ z6wjTPiXq9MQ(U{|X7HBdW@A%F!P68i z+E-S3y8OecgE?Z@Uj_wr=OnFw2@w^w8F_!Y$2wO{O*QP4eheCrw(s)FscVnp8$Iw=5}&9LGfnjLaOsp8j|Bb84!pb2y!dnA)o6aL z^>B@ju*2=%Or}oWyQK!z<-Suev7Q_`J!!Gu?h}C`l)n8@u*K~bc~4Ia+=B&VW+r)2K7P&5eKWwtXs5@N56TN0WUe8SJ?CC~_aAQk zQ`&hS@Ug(@(#Y2CDK1D!c(~nT_pZM~vnAs%)|k)qUA+IzdSoOP-RtV&!l9^A@Ja71 zY;wHvY!i{ks%ruWqTV2Q(@w>C}Q9^JeN%>S#qm$S_p%`=h}yhD{paBB;P?c|7wwO8I4VxZ;_!$@{qBV_DN?CL zDah_6skpQAsGzS@$f3YiX0gL$3zAndDP{@NdXLq(@5aR7wo?TKZI9wxo>}KUt!jRy zjc8nI!^zXk+7=(v84ctJKY>wM#3|WMizg)V z!92Vjy)-TlnLf|CLE=lO^Dadz+W1_ec1zl8cV>)er=sfR{c6i!PMHKp_Agu_0j zvA3u`^;o34xr>LHZ379H0O8G^bMG=HRyE}M!r+lu@0<3^MPd)(Oib?xyzir^Bri)k z)OXUQ!*@q){xe1T|Lsa8Nd?nL@AsVot(hd4~O@aKeoKSnd#NbWl~)4SvOu4)#x zUB3GXKmNy~V>M(CYF^3OxKh+U=HNOe9PWiIm?IN^wneJsOd>B=>@9zT&lM%kWJk;#73CPddxF0(x#W|2V@+8i;Q01q3|f z&AU6sYnB~vqL8@fTw=1x^;<*T4xgDeVv9sC@T>oQRiQEQP?Fb2J*+lGVOA)-m1W5E zQcR4yx{U%8cHF+z?R5I9ab#)XQ1j>;8RP z1rNpeCeEB+*oE&!{O_|n8mc;`F1k?ZI!%1a+@>ERE1T0q*3$B=%ys0dM`dd zU)+@Ld>R=40KaVyvPkVIJ|{;LRenS_H+4*rG}n~AyGys!_Gx)yYU=q@zbfJ`mYR2> z$g=Z$m9b<~sX|0_+os_u&r+O!>TOy(TcZ=V9uMLM*GS;JsTxx6*3~{Eqr5HcM~GE) zmE02+>aHOfQfX)ZJP}m*YSh%L+Y?RS=_%+h7l%A-c;WnXB!A7HVQO&HeNhR(!3Zw>f(c+pyqiGx&E;B8$PG1-j zpXo5Xe_?Xo_l4{4WNF({atS4FO3JXzzVoKT$L`74+R7*nXXZXy%+f1*PM$M&>BpBH z4>rrWpA^|vTla>OHahg{MOdup zz1DdW(SW_>cU#)t*R6+`59dEP-jvmy=diNg)e_&asmW)(@lJ0~KrCffeq4oX>E;vn zz^Ip!?qqvQMdAwfASdxn{;22A3@aFACMB8d35f1K`sU*NdR;<7kVM8exr-%Y_~5$x z%ajx~S5B2+68t05utK1+zJc>5>EI9zzG8d)SNv!CjequUqByR)A!p*CMsZD>k8Vm^ zdo(6Tc^P|6ot>M|b^NdUsofaZtqKex=ySxJ3KVT45=iIx5}9l{RmFKz_lIO&yV@u zAMw&F`eGN-qPto;5$NjU4z&2~~Ra)tn3_mDHz)uZi^1(_@T29ql_ z!)a0T<5AgtMfSft?C#v{-Rf`;5Sp>EE!sL`MmR+blJxz>1M*dsohe(PFG7!uj^*d% z9rJQpvU51fXBSs+v;2E$QIA9X(e7*tpao zL=mX%cjSWo$cvy)fp79nliAfC{ybP7;YFSi`g{JUxNE8BM=>5D39?K{zhQxT*^ppH zbU2$jC(f{lT~iBjd$n1ff9~Up4sl_^32>9Pt0O;rRje$U>GSx8y~eGYQUObmD3S1= z1ss!)Qa>A1ueta}+Q!rw+g)_OOMhnlOUT?kixwGA=cjlx(mCL}Z07v0)9fq*hKCQ6 ztzOHHkr!2nSU}jdlCAAgb54O22CNS1uoq56f?s#}PxaBRoS6LGw^o+>+mEizz5Un9 z{Op_Zrs)HoXsN8@!v0_%zc3P;-S_@Nb5F2=+{bU}q`xC0Pda=3is0kvE;bR@UcI^c zY)@mB$|Hvc8ptLcM-(rxB$S6eN>29CQc*EtseHL4cbL#|j_!av z8v>TyFQQLR^(>r7Hz10u8`77&8p>MDzuRHS)-ApMl&NIzjfGj`6Fknef5Ih=h?Nku zbvIh@Q@Klf<^2!cr-jP8Uc{H_%RG7fhbjDsfZ-UwKlJzIgOd+y7x^9&YAw}qQvF=|sHIdliiF^>o2_3yV%YD1k9?m$Q|Rs@v+Il3HQ%nuZCQLz zxIpMnLgef#-3Hht7o&yr%NXtreA&3{dS9;nW$ks=-p|^`mMzL>MB*IAy0!4fK}yG) zQgU;#W=Sf$<+yGWJncRN$TIBFd0`yp{dxZJx38ua(J>kGoqlf`Rg)*#(_^39BUKNM zO zcDWAM*0~lB=L6tuOsi@6`e(^PTZ-6rxOHY|On{nN_xK(mG3k$y1sk8%?-_TfV`v^GQ_nJZn;L9cT)=pdYuzX__~8aN6}g6j)n+|^ z&jAKt1UJ>yzkxId#WEks%^wQeieoaQ^Ey5A|%eOElmLS#w z%?=d2mCcR&`PvZ|_e|5@7^IP2%G>sjBG5kiMVRu6R;${!)ZOB80VgtK70E9N{_h~K z$9kWZxybd(nfCXy&Z53ARhg4 zH_URM8pvTp+|-1~l`Nc43>`ZGu8eo(0$*@}gb2};fLMEadcK~1hP1?vemTxwV`59)I7C@w+=|OV4GZ=_EIz0$V2A~DV zt^{H%!b}@@E$}p95fPx2Bg4alAY#}n0#YTUMu8Rs=_N8cFvP~79|+uYx3^_rZ~EL>>v@5fKx;g~0^naXBvdcz=297jo!g znxWAX-C7UUANutxC`4@~tm2~U>T3X@Zlboot~fd_0TLt^gMJxPVvNH<1A}e= z3C*XgYHGIDrpoO@faxJM8Os0w{`;aL5D^(L(>C+DL_G4nbPb+}#7y7<#eE zoB$gFA7>79Zd7^*a3jpB5vBO`D}h4?gcH+$Op+1GgE*r5#>RtKK1k%jAf(8wox^z_ z$0b+R6q#5u6See`D;Hfai~GPF{*tYrV^&GPyVBAPu%btn06o*4Gox}>!}a+!FtEai zS@7}{sQZAIfo`u%_6Z5@IdSqNlUE5WVR0yjEFQ!%U6GPHh(g2qi$O*r>*{b4j%Pj+ z7%-(6&;=4EVB*lXAjZeO8en~tkfT4>@87={0rZL0Vt$YKlc4BmdI}0ciZRG>0s;j` z0uFs}ysBT|t)#?KOCI<8g{{m9cviJEH=p3*I;0CYFfl&9Vyl+g$&@XiWX)=e<6v;=R5UbVvFTv*1|)|!q@&}o4xJbqLnsqJhM*ukcz6)q zd&wKkbjqM?9d`+iJSiy&Opta5tQiuBcX7Z3G#LaCh%M)5DOe;ey7NXrg+`w3pk3km zLnpDvVPP8Aum8aQ2TT{jsPpFEPPx0g*9m~CF$NC9*7{rk=+j`p1Hl^{8mczv$k2g6WAo9tx2T8b%_UedoV`mPTpM=RsE@lD%@`B;E^5^Dl{ebs$+fWM-mgWyVdXv-%+F8+lelf z4*mI~p{ePFi-S~GJmJ9G<}xVLZMnS7V|*}@sri7UVmoV+x7{R7nbD}W6B)(~A6pd8 zACl41a)#UyTTYnu6(U8AK>?M*ARm4uWu;5y(;~`BH&X{znF*!Aiqa*Y4~QZ5>-0J~ z^_6CN!|>$6#!vs6q0}TizC-Lq&K?|}DHYy+@eYN@8LdQ$$Oj{Uq0UvRDs$E~DcV!* zQ<2%E3FT!NBH8!clXvIpB%h!U8MUzFzAM*LQ_tFy(ViN_pyph)s&d_cum<7#t+a(7 zdXuKaZ&TLA?rL~Onne%iEGBXH_QPZjmaWn>0^H!rQd6@zpR`ROH2N~l&GD*)+AAd%`W^dl zxdT+v%~}l~|MTz4`?Z&myC? zowe9dr zFVz=H7!ozGQ3XtIE^)g!hM)R)9e;URt*BnDG6x*tQ~J_uhrqYNw6VjtZ9?`U!0)Pr z)Vzqw*X(AC82w91qwJv!a#ZyDE=8w?(RvwPxa>2f5JL~H%m32$7rcP zCcAu><7J}K!5zW-E5V;V^5$MF6BgVh%QI#JmTjL1Q=1QtM0fu3dH-8=`@d;w|BV3t zzxT~Gfu+nDx*8x2mlkWva)*C2{5>+2*q*w32xZt2EIE)5ZKe+ zHoHX~LdEgVi>MFLoNKjUwLJaLt5j5OQcAjA&Pv#U4@}Nfek`oo7(ktz4h3PpH=gHU z@2va1qjx-~mGUztvL34*H3K0bp@@%}a}u_+)T7l_On;b)e({)~U=hZRE8Z*ALqoz0 z8W`W9@$j!RK6#Q;0B=~?wFAD&L>@1dRoWHt`|p9~@1PZXs0K#P%G^z{#~?@qQQqYv z+{4m4_xSJIC!qwzH^>usAS9jeCI5K+3_xS>Is_d?tFE7+qCZCX);9BgTOS+LulNF7 zy4&aYhfbb7JBOz;{0azUoc4^cw6v2FO0f0;O$Yhrzc$vEz^{TQ|Lfs1_}D~oo2Y09 zrPUr(%Dl_FbzEEl9uy$pU{{1?7!OZi^^Lmb$8mt@Z{EB~h}Tt62xv4tD3s8o0CCTnhOrPPj$jU}Xi5I8bOdA;8&=ux!z4_n~x)K*b=rEg*$ zMJC?G>p6}c)Ta1+ut*zCL6*?|Ov!`~4g&N!;ZEw&B=zpsSu=ua+S>QP89RD364k%@ zH5j|1+8n3}z|$F;nn63;Vrs$}A;0EE`w{M~Buqf+y-*uJf5|6dpr4I=$_&m1dj0Cu zr~E@KtgMM8B`yfw^&};D`z=lCRj`5WaQeiF_fXsS?jX#$J*FP6^X?Sn)XXt{qUfWj ztSn~0a)sCy9I&OO>>{tNrDdqy@7$R~745rDx&eMfR8$noO2~ln5Pf(r{`y<6MZPjh zEb8Pp0uvSz6g+bDsN;C2El3&b{=+v4wz5m_2ly6!**d=&L0WK`e7E#*E^X#GU1c8o zYOX|QZa(ga$ySs9(cHI3#oWH@4_*{s6-o@nI217wD(vl zwRogrr}`yG&1tEsAlCapOeBOEf*Ur3`}-S6(0Tj<0`^_~obmGIOJreMbf-Av-9M|T z1@ieQ5ky7jv--_XpMHOgU*U4o6ZIsddEC(amLY=MI7CuC#e)(D^|dl!tDE+x&y<{f2o3%d+WC43+e%sekgp5rQPs01pFL5 ze;@6wsDK1RmU2lf01vACf<;TDC#g(jQK! z@~Z+mT3dBldok_N;NTS$Msb6_Oo96P`W)r++Xc5M-G7)_>bFH%V&~3{&b=|bak&|486Q`;GlwfT$ikm z@YhE~bB1Qd*LZ$nz=yYk?n|@{48Gw(V_s04vWO1-$R16{y4B+y9UX~@+v|W*9AWW+ zyQ}o{S#0dq?b~~U4Pj|mV=R3t_dXstff{bTq9i-Iw}x@jvUsw4JuA|uxa6lABoB;xM;XM0sJ>Vk9UCWL#-NXXM;_lg)0b!o=g;Dwn; zvzVKNcF&qf%sCWKM+ki5cb_;0UW}4b8KyBS>c1pZW^ckJL`FuUO3qFYO{MmCb=5PG zQ(*<({I!a5>QqHM<4n}yHq#it>^p8Fo$tV}D6Y3r0VNQaN#O70M0xuZ^`t-pZ`;Xl z&&ox0vW@-fN&Bya?!9zJ;2Va9W21C}R}+`6&-O3h&nk)YP=Xi;?BcU%$kKSH_IgJ=+@FiHvcU!)$=szIC)Rc3jz1E*Um1`nY zLqOjZ7B-rXG ziSx|#S+}n{!lB)d_{DwRl{2)sh(3?m=sF?>mxA%>sk-@6hYroWytxRpTr6T4vR~%; z?~XuovF~d_-Bg;nvv` za2@$wuf@>b4@l%XCd3Al!NFmrqy$>5L6%G)253@)4%!|$>78R{Y@1boEo3KFNlPx4 zG3b*d5=s5(XeSf9gX!VX_MyYc$qC3(AI6wqlrB+`nh(AW*PJ0gALFu3p0jt}s52Uo zejGL&3j;@mH|rcEj!6OI;5-;ih;nNdtmb?aLl- z4a{`AfzN)9gy_&j4GABm)hIqfDzO0CYrF7!#SU&E2?`0V^C|Q4;t_wpm_Wf~Z61u& zL5&qGi9{`@d>wC0O3Hf#AKujqZg^urGcqU@ElkvF`F@`n-PjKz?J(1u@Dgy7a(ZK~ zEs~FH1=RxnqjBm7jW!b={;0+koq7F_+tVXI0Ph6CfBnKvV@6wWF-VFRta9AP>b1yv z5sN;Vj=2mMIV32VU1My-d(E}_Pw`N^An-|Hf6OvEODer9v~vl+=s>Sp&e^)*fs@y> zGJo~w##kbCxj|KFs$G1+4bD~^vE{4jgtgIv}Pp6&*?-yfT6n&KH0PG<~(2lz&3 zXD80~*34#0NGfn!e7(F*zz+<}Rp?8&R%5=@bo$`%a4}f<$ds_KLByq-GH~9iC*dNU z;9kj?pK3&cs)D%}8K6BQQ`)7S*;%r5W4MeN6<(o(!^^Xe15$04l74E!^%8X#}GQ;!H|tSQR~M>m;#+;Ox_wdw-7`17KbP4Z^U@`PvQfG*RS8n#6h8r?a`NKKJz__^9QfIU+cMSj}K08 zexP&%?M3ojfynsc=0w;W^x77{AsjQWpVn-Da~nU%w$(#G=%VRS9__jKYS?|=g~L7- zS6~7|UbVV@csDu$6a(oU4q9KJ2%ZM*I-AR$j&vD1=s_Vd)g*#|f7V)dnO9a-Ve>yn zk=PFHOv~swaIWHn0hUp`Q0<(sj0@ic47M7e>X7k*Vi_r`@snrHq^74cvaa|D81#OO zDMf@2kFMXw#F7M>-26omLZ_sJ$YvBASSRp-`7u(t8#^JF_ZJbX+xtaQSA1JadwX`6 z07bHRa+zci-O|~7&)U-g&DuA7{B9PiqeRir2s|z3GQ~;IDS!jq5U=^PZdO5o+|Heq zXagY9v>~M4+x=o9-F>z)6C)Zktn<1OKt#r=7Nq(GVj1qe77-!4!fqWcir7Zv(wQ4j z-Ap0k#h;(V!{(-%Ic8j#pECw1tq?}}l?w-qrl%L0W8f?T!B$XuI;2yFh_{YimTLNx zbp9BHGB*-Z4D)3Rz@Q^3w5K)Krw4PP@FGfGKJooh>fs1r?tm46GVezi1eOltZYenO z^)+D^ql0kA!((z{Vi$BXBeJuABOQnGd*((H6cxrkod=3GgZ_$Tr~q0%zpy5paCZ@M z(ZpcnTn+tX@suFnGzU#K;f6xQW!3a?6k@|jd?k8h;)ontyOJ|#E0)n)$ z8G%U$e0|Vp+S4LaJX)(F7h!>%5rGoPcBE}s=HSAC%eY;*qTdhyJ-{bkVliIK&$(2# zTpKntWy{IPjIkT(W*o{5ms`i?C&CX0B-H#Rd+j)m{srdKMDE*f$lqh)h43=P{7X`6 zcVKXEjxBdK!ws_TG49XxyJMMZ490M{H{r-DMY!`x`vk0_*x9kKi7h1X&JQ3sNuype zG<-0aw2YAJ-QorT8qsL$UvcUtAN!&2>Sg8=j__E2eYN;$Nwh}hI;>f~Yh~_Hm~+`R zlvdY&@9tgLNnq?{*Cp=-9jZx~bf1}`1`;X5@hh2RE@X) zS`w;DhXhDV3!2CdrqhB}v%phvkYjmAC)!X{fR$Zum4jofn>cSEmu+`8-yhrg;Qmy;l>T#m)qL}Bg%FZ zoc2!|vTX3i8nE)+LXwVnR&Zgw?SfOexSpuCxaF53?H;MXp8k6ceJ|GcH@in1BgKGn zjdPgdg$S`d$YCITTFFk+gi~KpF>?2Aznosg>{9gJoLr_IUD)HA(=N%)ZAmZ@C0HfA zm0(qDkc*D}yG2I2psCM9g*ei_pXejG*OL8eosZIYn6ANFUj4!aV`-v?fK=!%Xvric zxy?nX(3E#F@Ki!{AN0sNBU-Zcz{E{tCYA|nJNV>W#m+wEwctqL2|JDJQa-cIv`kDm zkcC;eCl;jospdKBzf+53MD1%ZFSTxI!vifq7Yo!Ygy!ex6I2nvQCOklfDQs&29U1r zE*kas^*y_K8DO_V)+6PQADenm)(L)k*HW3FC%-$X=*h^G$MWOOuD6dZf>VQs=kXk~ zo;IezKilj^sS_^=p0GfgkWo7q9Yz`8>pt_n)O&T<9@W)}^`@j!G*>Y;6ap$LjrKSy zYPhGzA?$U-m5Mg;wL@w?4p(boau2B#L`8>ZN9*WxIyDONQ;W|Tkf&HdjPzjcuhFSH z!@fi5si{B5#`yW~p)Zux7hP8$A#s3CwXcu42*r(ad0AywtF-SLZYF%>TWnn>BzrUY zJ(2RZy=oBGA*ABa!Y%{dcOblpjAE)25~SRX{Imo-M0CymR#HMK^33{>0L9VCsp!Y6 zZFoqMx_O(5 z&Zw#$Mneb|9H&K)Ftwp^heeKC@ByQHGc(mqwOI8yZ}Cwz${XvArBP2Ef;t(?XanR~ zK&1i$ZD*(KDkD+nBKntby}Bflr9Qx_K8!zFB5WKW?Nb9u*eii#X)?$ zzp?uD>(`kIVq)Dfo}!so&n0O9r}X3#$#nnm?b|QzPF-l}JoeI`#nSQQyUC|1$;`8z zeDc&2cOd%UfgPmL;V%rHpWR`Wzd3c{h$bkZm-F!C4ZoO>8yT0PPp@jwpK9V{S=yN?cx~(M=X3%03B|ZD9y}EigATY?pkpu)aY;pZnB^&Hn{IhKR{M>jkg1CnO zm_R_tAdssIvwX3Gc>uYLVKpuv=?7UiPmSkiR|sRjbgQ#jL?gr96(TB(5%OEpdBO*- z2@tI8GqPxZKItRdo-rTR;P#b19cT3V-QtS0^8>x@UNzCXr_@(Usjieti|Ji{(Y8ai z7j5u--S(vO;+17c8^ApHGGgNs3-CZHbO7B^dp^33&KBm6-#KPWx5^i4ZzkahX0K9p zHfVMoZ_5Sw0o6DN2$nAzxhPithw?Gb#gKNDSo=EjB^6#;feLeTI-cv@KCD?G+xhq?g{MZ%eBz)^`&VB1 zgy709rKdHf=c54`KumMHM9w5HFOP>bP^_&j8PY%Y>Vt^q!(g-F zRMtOO+tua+wX_J-hRaDQ`xj>3dqHz|D|(%~d9AJUpi*P`+~DDo4*WMYK`pYsz2{St zQ?}C6pQEDy_R@6R*tAqY3A2h(_L1#ef#9?+IjsNv{fw`SpgZ~g9Y*k4*lSG0KHTvy;oNt(qw-DM zciQA1+P~i(YYADp|C*I2xl(55KHCCx9pI0~+9|%@w%2Oj<6h5Qm2BdfjKL^V2%4?E z8$MjzhOmCAd|Kp>M^IJi$wmRV&&}XywFBWtR#sL~QBh9L8RaBmbPzWTo`pLE%*(C8 zcWJqP;uXTR%BfSR9MItg<)g0CI{s`_WO(?%*RSU;T!1y^As0Ts$=_B{`V)pSHCgp( ziySJOm1()Y>Fm2pYZGeCoYbC7f9|Ku_45|BzHxmoBmey-R~d?)(R3dxeb;*EH&DG; zRR-fg)1*={f9JDe=BciAt7i1|^ahh|MO_^~r1?-w%c#iC-#kLz!`abM&X$}0J@!t? ztav7_85C$-ct=TAN8wBYmE|D-)Z^jMB}lXuFIL3Y!Dj3m9(D(D0g`fF5*i04%`uuh z=fZZ#V$^6ASsdCvkVK%OQs6=%6VEDeQbLgm@9PLD!&A6Sk;l#Yd#=0NGR~Y~W0sra zh0EWUZt1nPOIY?GBuLNB_yRN!I=5aFibNv%~KE zJUm_x9(<^(3KHe$uj6M5NDW)u8M*E>J*3L2P>bCCYv@YhSqS{G1L1|ltz0P-eSLi^ zs|FS%7nT&{ zjODh|8%{Z1*!q(je#SPDT3fjgZ+Y4v(EjS`;WxsJt1}vZ9Z#^Hdcq!glp9VB`Z^=$ z^!BrkeLq@rCr-S@Q5z8yWH|XZ4>&^z*5I|2wiJ5jE}ou9+{l^l%zv_vHrVv!NlU?{ zzj;<}7(LSS;ZG5LgW5HuZP~}QH!)ZP^`+xe9fMh3$17m zbGDO` zZN~%spp^u|sx;)$r|pW(=IvG(1=si7=VsjP`OgdA9V?R))*Nlq0{Zje0EiAaRdQxJp z-g!lccH)e!u(Olt5^D6={8z!bobWs_O`c6Li{uHCRC|PYUSk> zI3*tfs`LlXp!vm%bDO0EhmDckG>7o={y+8a|KQ8O{DPaJ8;-U(tfzB7@#JyUztbrC GxBd-GW@C5& literal 162492 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%0D?>oB*P<(Y6{e=9z_C%7 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

UP@oFmopW5b?iG=2lrr@ELf(q{@#XFVq|g## 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 IlVTS5AH&TR5dZ)H diff --git a/frontend/src/scenes/billing/Billing.tsx b/frontend/src/scenes/billing/Billing.tsx index fd06e8a6785..5e950359b5f 100644 --- a/frontend/src/scenes/billing/Billing.tsx +++ b/frontend/src/scenes/billing/Billing.tsx @@ -21,6 +21,7 @@ import { BillingCTAHero } from './BillingCTAHero' import { billingLogic } from './billingLogic' import { BillingProduct } from './BillingProduct' import { CreditCTAHero } from './CreditCTAHero' +import { PaymentEntryModal } from './PaymentEntryModal' import { UnsubscribeCard } from './UnsubscribeCard' export const scene: SceneExport = { @@ -82,6 +83,8 @@ export function Billing(): JSX.Element { const platformAndSupportProduct = products?.find((product) => product.type === 'platform_and_support') return (

+ + {showLicenseDirectInput && ( <>
diff --git a/frontend/src/scenes/billing/PaymentEntryModal.tsx b/frontend/src/scenes/billing/PaymentEntryModal.tsx index c4580450167..52092c47d0e 100644 --- a/frontend/src/scenes/billing/PaymentEntryModal.tsx +++ b/frontend/src/scenes/billing/PaymentEntryModal.tsx @@ -1,12 +1,13 @@ import { LemonButton, LemonModal, Spinner } from '@posthog/lemon-ui' import { Elements, PaymentElement, useElements, useStripe } from '@stripe/react-stripe-js' -import { loadStripe } from '@stripe/stripe-js' import { useActions, useValues } from 'kea' -import { useEffect } from 'react' +import { WavingHog } from 'lib/components/hedgehogs' +import { useEffect, useState } from 'react' +import { urls } from 'scenes/urls' import { paymentEntryLogic } from './paymentEntryLogic' -const stripePromise = loadStripe(window.STRIPE_PUBLIC_KEY!) +const stripeJs = async (): Promise => await import('@stripe/stripe-js') export const PaymentForm = (): JSX.Element => { const { error, isLoading } = useValues(paymentEntryLogic) @@ -34,13 +35,17 @@ export const PaymentForm = (): JSX.Element => { setLoading(false) setError(result.error.message) } else { - pollAuthorizationStatus() + pollAuthorizationStatus(result.paymentIntent.id) } } return (
+

+ Your card will not be charged but we place a $0.50 hold on it to verify your card that will be released + in 7 days. +

{error &&
{error}
}
@@ -58,21 +63,34 @@ interface PaymentEntryModalProps { redirectPath?: string | null } -export const PaymentEntryModal = ({ redirectPath = null }: PaymentEntryModalProps): JSX.Element | null => { +export const PaymentEntryModal = ({ + redirectPath = urls.organizationBilling(), +}: PaymentEntryModalProps): JSX.Element => { const { clientSecret, paymentEntryModalOpen } = useValues(paymentEntryLogic) const { hidePaymentEntryModal, initiateAuthorization } = useActions(paymentEntryLogic) + const [stripePromise, setStripePromise] = useState(null) + + useEffect(() => { + // Load Stripe.js asynchronously + const loadStripeJs = async (): Promise => { + const { loadStripe } = await stripeJs() + const publicKey = window.STRIPE_PUBLIC_KEY! + setStripePromise(await loadStripe(publicKey)) + } + void loadStripeJs() + }, []) useEffect(() => { initiateAuthorization(redirectPath) - }, [redirectPath]) + }, [initiateAuthorization, redirectPath]) return (
{clientSecret ? ( @@ -80,9 +98,13 @@ export const PaymentEntryModal = ({ redirectPath = null }: PaymentEntryModalProp ) : ( -
-
- +
+

We're contacting the Hedgehogs for approval.

+
+
+ +
+
)} diff --git a/frontend/src/scenes/billing/paymentEntryLogic.ts b/frontend/src/scenes/billing/paymentEntryLogic.ts index ebedbfe8b8a..ad2b84d0f80 100644 --- a/frontend/src/scenes/billing/paymentEntryLogic.ts +++ b/frontend/src/scenes/billing/paymentEntryLogic.ts @@ -12,7 +12,7 @@ export const paymentEntryLogic = kea({ setLoading: (loading) => ({ loading }), setError: (error) => ({ error }), initiateAuthorization: (redirectPath: string | null) => ({ redirectPath }), - pollAuthorizationStatus: true, + pollAuthorizationStatus: (paymentIntentId?: string) => ({ paymentIntentId }), setAuthorizationStatus: (status: string | null) => ({ status }), showPaymentEntryModal: true, hidePaymentEntryModal: true, @@ -73,7 +73,7 @@ export const paymentEntryLogic = kea({ } }, - pollAuthorizationStatus: async () => { + pollAuthorizationStatus: async ({ paymentIntentId }) => { const pollInterval = 2000 // Poll every 2 seconds const maxAttempts = 30 // Max 1 minute of polling (30 * 2 seconds) let attempts = 0 @@ -81,9 +81,9 @@ export const paymentEntryLogic = kea({ const poll = async (): Promise => { try { const urlParams = new URLSearchParams(window.location.search) - const paymentIntentId = urlParams.get('payment_intent') + const searchPaymentIntentId = urlParams.get('payment_intent') const response = await api.create('api/billing/activate/authorize/status', { - payment_intent_id: paymentIntentId, + payment_intent_id: paymentIntentId || searchPaymentIntentId, }) const status = response.status From 0e2199c7035d5782388f5fdb608290ce6fd4587a Mon Sep 17 00:00:00 2001 From: Dylan Martin Date: Sat, 16 Nov 2024 06:03:20 +0100 Subject: [PATCH 10/11] chore(flags, etc): add `created_from` property to `feature flag created` events (#26230) --- ee/clickhouse/views/experiments.py | 1 + .../scenes/feature-flags/featureFlagLogic.ts | 2 +- posthog/api/early_access_feature.py | 1 + posthog/api/feature_flag.py | 16 +++++- posthog/api/survey.py | 1 + posthog/api/test/test_early_access_feature.py | 31 +++++++++++ posthog/api/test/test_feature_flag.py | 4 ++ posthog/api/test/test_survey.py | 53 +++++++++++++++++++ posthog/api/test/test_web_experiment.py | 20 ++++++- posthog/api/web_experiment.py | 1 + 10 files changed, 127 insertions(+), 3 deletions(-) diff --git a/ee/clickhouse/views/experiments.py b/ee/clickhouse/views/experiments.py index dc4a3170b93..644445067c4 100644 --- a/ee/clickhouse/views/experiments.py +++ b/ee/clickhouse/views/experiments.py @@ -328,6 +328,7 @@ class ExperimentSerializer(serializers.ModelSerializer): "name": f'Feature Flag for Experiment {validated_data["name"]}', "filters": filters, "active": not is_draft, + "creation_context": "experiments", }, context=self.context, ) diff --git a/frontend/src/scenes/feature-flags/featureFlagLogic.ts b/frontend/src/scenes/feature-flags/featureFlagLogic.ts index 8485d628ed0..875b6f56cf8 100644 --- a/frontend/src/scenes/feature-flags/featureFlagLogic.ts +++ b/frontend/src/scenes/feature-flags/featureFlagLogic.ts @@ -302,7 +302,7 @@ export const featureFlagLogic = kea([ }), forms(({ actions, values }) => ({ featureFlag: { - defaults: { ...NEW_FLAG } as FeatureFlagType, + defaults: { ...NEW_FLAG }, errors: ({ key, filters }) => { return { key: validateFeatureFlagKey(key), diff --git a/posthog/api/early_access_feature.py b/posthog/api/early_access_feature.py index 57885666fde..004725393b4 100644 --- a/posthog/api/early_access_feature.py +++ b/posthog/api/early_access_feature.py @@ -203,6 +203,7 @@ class EarlyAccessFeatureSerializerCreateOnly(EarlyAccessFeatureSerializer): "key": feature_flag_key, "name": f"Feature Flag for Feature {validated_data['name']}", "filters": filters, + "creation_context": "early_access_features", }, context=self.context, ) diff --git a/posthog/api/feature_flag.py b/posthog/api/feature_flag.py index d24ee4499a4..5c1485a6d86 100644 --- a/posthog/api/feature_flag.py +++ b/posthog/api/feature_flag.py @@ -115,6 +115,14 @@ class FeatureFlagSerializer(TaggedItemSerializerMixin, serializers.HyperlinkedMo ) can_edit = serializers.SerializerMethodField() + CREATION_CONTEXT_CHOICES = ("feature_flags", "experiments", "surveys", "early_access_features", "web_experiments") + creation_context = serializers.ChoiceField( + choices=CREATION_CONTEXT_CHOICES, + write_only=True, + required=False, + help_text="Indicates the origin product of the feature flag. Choices: 'feature_flags', 'experiments', 'surveys', 'early_access_features', 'web_experiments'.", + ) + class Meta: model = FeatureFlag fields = [ @@ -139,6 +147,7 @@ class FeatureFlagSerializer(TaggedItemSerializerMixin, serializers.HyperlinkedMo "usage_dashboard", "analytics_dashboards", "has_enriched_analytics", + "creation_context", ] def get_can_edit(self, feature_flag: FeatureFlag) -> bool: @@ -317,6 +326,9 @@ class FeatureFlagSerializer(TaggedItemSerializerMixin, serializers.HyperlinkedMo validated_data["created_by"] = request.user validated_data["team_id"] = self.context["team_id"] tags = validated_data.pop("tags", None) # tags are created separately below as global tag relationships + creation_context = validated_data.pop( + "creation_context", "feature_flags" + ) # default to "feature_flags" if an alternative value is not provided self._update_filters(validated_data) @@ -347,7 +359,9 @@ class FeatureFlagSerializer(TaggedItemSerializerMixin, serializers.HyperlinkedMo _create_usage_dashboard(instance, request.user) - report_user_action(request.user, "feature flag created", instance.get_analytics_metadata()) + analytics_metadata = instance.get_analytics_metadata() + analytics_metadata["creation_context"] = creation_context + report_user_action(request.user, "feature flag created", analytics_metadata) return instance diff --git a/posthog/api/survey.py b/posthog/api/survey.py index 1cd91b881c0..3d13981a867 100644 --- a/posthog/api/survey.py +++ b/posthog/api/survey.py @@ -640,6 +640,7 @@ class SurveySerializerCreateUpdateOnly(serializers.ModelSerializer): "name": f"Targeting flag for survey {name}", "filters": filters, "active": active, + "creation_context": "surveys", }, context=self.context, ) diff --git a/posthog/api/test/test_early_access_feature.py b/posthog/api/test/test_early_access_feature.py index 89d1d7369d0..311fbae3cb1 100644 --- a/posthog/api/test/test_early_access_feature.py +++ b/posthog/api/test/test_early_access_feature.py @@ -3,6 +3,7 @@ from unittest.mock import ANY from rest_framework import status from django.core.cache import cache from django.test.client import Client +from unittest.mock import patch from posthog.models.early_access_feature import EarlyAccessFeature from posthog.models import FeatureFlag, Person @@ -520,6 +521,36 @@ class TestEarlyAccessFeature(APIBaseTest): ], } + @patch("posthog.api.feature_flag.report_user_action") + def test_creation_context_is_set_to_early_access_features(self, mock_capture): + response = self.client.post( + f"/api/projects/{self.team.id}/early_access_feature/", + data={ + "name": "Hick bondoogling", + "description": 'Boondoogle your hicks with one click. Just click "bazinga"!', + "stage": "concept", + }, + format="json", + ) + response_data = response.json() + ff_instance = FeatureFlag.objects.get(id=response_data["feature_flag"]["id"]) + mock_capture.assert_called_once_with( + ANY, + "feature flag created", + { + "groups_count": 1, + "has_variants": False, + "variants_count": 0, + "has_rollout_percentage": False, + "has_filters": False, + "filter_count": 0, + "created_at": ff_instance.created_at, + "aggregating_by_groups": False, + "payload_count": 0, + "creation_context": "early_access_features", + }, + ) + class TestPreviewList(BaseTest, QueryMatchingTest): def setUp(self): diff --git a/posthog/api/test/test_feature_flag.py b/posthog/api/test/test_feature_flag.py index b5a2cfd6d18..2d4745313b9 100644 --- a/posthog/api/test/test_feature_flag.py +++ b/posthog/api/test/test_feature_flag.py @@ -300,6 +300,7 @@ class TestFeatureFlag(APIBaseTest, ClickhouseTestMixin): "created_at": instance.created_at, "aggregating_by_groups": True, "payload_count": 0, + "creation_context": "feature_flags", }, ) @@ -334,6 +335,7 @@ class TestFeatureFlag(APIBaseTest, ClickhouseTestMixin): "created_at": instance.created_at, "aggregating_by_groups": False, "payload_count": 0, + "creation_context": "feature_flags", }, ) @@ -385,6 +387,7 @@ class TestFeatureFlag(APIBaseTest, ClickhouseTestMixin): "created_at": instance.created_at, "aggregating_by_groups": False, "payload_count": 0, + "creation_context": "feature_flags", }, ) @@ -438,6 +441,7 @@ class TestFeatureFlag(APIBaseTest, ClickhouseTestMixin): "created_at": instance.created_at, "aggregating_by_groups": False, "payload_count": 0, + "creation_context": "feature_flags", }, ) diff --git a/posthog/api/test/test_survey.py b/posthog/api/test/test_survey.py index cb124c9b970..ee1cc97a696 100644 --- a/posthog/api/test/test_survey.py +++ b/posthog/api/test/test_survey.py @@ -60,6 +60,59 @@ class TestSurvey(APIBaseTest): ] assert response_data["created_by"]["id"] == self.user.id + @patch("posthog.api.feature_flag.report_user_action") + def test_creation_context_is_set_to_surveys(self, mock_capture): + response = self.client.post( + f"/api/projects/{self.team.id}/surveys/", + data={ + "name": "survey with targeting", + "type": "popover", + "targeting_flag_filters": { + "groups": [ + { + "variant": None, + "rollout_percentage": None, + "properties": [ + { + "key": "billing_plan", + "value": ["cloud"], + "operator": "exact", + "type": "person", + } + ], + } + ] + }, + "conditions": {"url": "https://app.posthog.com/notebooks"}, + }, + format="json", + ) + + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + response_data = response.json() + + # Ensure that a FeatureFlag has been created + ff_instance = FeatureFlag.objects.get(id=response_data["internal_targeting_flag"]["id"]) + self.assertIsNotNone(ff_instance) + + # Verify that report_user_action was called for the feature flag creation + mock_capture.assert_any_call( + ANY, + "feature flag created", + { + "groups_count": 1, + "has_variants": False, + "variants_count": 0, + "has_rollout_percentage": True, + "has_filters": True, + "filter_count": 2, + "created_at": ff_instance.created_at, + "aggregating_by_groups": False, + "payload_count": 0, + "creation_context": "surveys", + }, + ) + def test_create_adds_user_interactivity_filters(self): response = self.client.post( f"/api/projects/{self.team.id}/surveys/", diff --git a/posthog/api/test/test_web_experiment.py b/posthog/api/test/test_web_experiment.py index 679df4411c7..7b53e2ce0fa 100644 --- a/posthog/api/test/test_web_experiment.py +++ b/posthog/api/test/test_web_experiment.py @@ -1,6 +1,7 @@ from datetime import datetime, timedelta from rest_framework import status +from unittest.mock import ANY, patch from posthog.models import WebExperiment from posthog.test.base import APIBaseTest @@ -30,7 +31,8 @@ class TestWebExperiment(APIBaseTest): format="json", ) - def test_can_create_basic_web_experiment(self): + @patch("posthog.api.feature_flag.report_user_action") + def test_can_create_basic_web_experiment(self, mock_capture): response = self._create_web_experiment() response_data = response.json() assert response.status_code == status.HTTP_201_CREATED, response_data @@ -53,6 +55,22 @@ class TestWebExperiment(APIBaseTest): assert web_experiment.type == "web" assert web_experiment.variants.get("control") is not None assert web_experiment.variants.get("test") is not None + mock_capture.assert_called_once_with( + ANY, + "feature flag created", + { + "groups_count": 1, + "has_variants": True, + "variants_count": 2, + "has_rollout_percentage": True, + "has_filters": False, + "filter_count": 0, + "created_at": linked_flag.created_at, + "aggregating_by_groups": False, + "payload_count": 0, + "creation_context": "web_experiments", + }, + ) def test_can_list_active_web_experiments(self): response = self._create_web_experiment("active_web_experiment") diff --git a/posthog/api/web_experiment.py b/posthog/api/web_experiment.py index 81aae23f2da..d90d400404d 100644 --- a/posthog/api/web_experiment.py +++ b/posthog/api/web_experiment.py @@ -98,6 +98,7 @@ class WebExperimentsAPISerializer(serializers.ModelSerializer): "name": f'Feature Flag for Experiment {validated_data["name"]}', "filters": filters, "active": False, + "creation_context": "web_experiments", }, context=self.context, ) From e92e4a8af973ec3568795d7229b622707e0c48a7 Mon Sep 17 00:00:00 2001 From: Paul D'Ambra Date: Sat, 16 Nov 2024 16:23:42 +0100 Subject: [PATCH 11/11] chore: screenshot test the inspector list (#26229) Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com> --- ...ponents-playerinspector--default--dark.png | Bin 0 -> 20552 bytes ...onents-playerinspector--default--light.png | Bin 0 -> 20444 bytes .../inspector/PlayerInspector.stories.tsx | 88 ++++++++++++++++++ .../player/inspector/PlayerInspector.tsx | 11 +++ .../player/sidebar/PlayerSidebarTab.tsx | 10 +- 5 files changed, 101 insertions(+), 8 deletions(-) create mode 100644 frontend/__snapshots__/components-playerinspector--default--dark.png create mode 100644 frontend/__snapshots__/components-playerinspector--default--light.png create mode 100644 frontend/src/scenes/session-recordings/player/inspector/PlayerInspector.stories.tsx create mode 100644 frontend/src/scenes/session-recordings/player/inspector/PlayerInspector.tsx diff --git a/frontend/__snapshots__/components-playerinspector--default--dark.png b/frontend/__snapshots__/components-playerinspector--default--dark.png new file mode 100644 index 0000000000000000000000000000000000000000..e1d088184e1c83c96e8288ad0c74226d3b0b8041 GIT binary patch literal 20552 zcmbq*1yCH{n=Jv75G;fcG(aE(cX!AH5AHs}9TMCLVSwNPg3CZ~cL*LlxD2krJ-FMu z{QkSIcK5wkwY9Hms+yT;x^MUG`+es-=X?{SC@+bHPK=I(goGt6C8msogsg&u^xzK~ zGWY~L#^(ZT9ylmVLXe6FUTz{Gy+V=}d#mc2yfbH}izi8fv_G{SM(^UN7#uvA74+p5 z+E*b7PD{>CT#xs%hGB2m*er3aeo$M=8WxuMVOhwiiRIBZ^3Y8zPG1@HH=_OxN69<9 z_Bk_faduv-6?coDOVR5asUyEXw>u`p>@nCPInw_2ynm1XKix#dp5VI~S)oXY`2Y6C zid%joj56eVvEmDr`i@Z)@*!;*DHi+vDm7U|Tw>yUZYdOc<>6w-$(Wa$`*KmR&Z*I* zG}c=yIUL(+Zd&a*^3BPyBL_!C#GU)r<%!Pj%T1E=;p(lq=9{_?6=BvkHaHM1t*I9; zVu&egJ=QOG_%O)CySNz}NbRd4ij1!Oa~^nqZ1CzdGg)<%K|=aGKFob2NAy+{ozo5V z)XG)I+0F>DzT__w6|JIXOUgSm%<{qBz(5HhhozDtOKsH~k7Jp$aDH=jc5`!lP*`Xk zqhn)ZBOHG-+^dlg*0bq&nT6rgSe&n2b%`iHMCajIPnoHSPmF&laH~VoIZhYKmpmw} z$KiE}hZ_XLiISosV9}epYkTW-@wBb<=BkNwT_mV$xh6LQ`}YFUXIrs?K1qsh50Xej z4wGVMRCH;57Mlu(%$L{#3<5Of#57 zxOPmw>T@wetL!cG^yUJO@E4y5v#^Np@Z9adX$Di8RdsY`o_(r$sxu=@FnE`clESg= zcd<#tf`{(k*f>|m#o%Xm^PJN`UtYerr;!S``?Q3+Kp+4KDGjU0ezIYh${$(BOClW4 zytux)tsR@&P5I9!_T@Da@W>PcNWf=AiwA4xY(};dP6fSd{WrgKF(9i zqoCY~c#FKv7_KZ7xoM;ej3Be(Ee;ELKUub|<0Yi$d9wWQ=m+Iqqx%8l`M8L%Q6r}h z7uJHfi9lGcU}%vjb+nJL{VPGrt(&ykgC`2Eg2HeX*URInh6sFUljrWnB6+uQc@OD? z&*kdzS@wAtNr9JZn0F$_JRINsuD{k$NN;X-r&1x7v0WpMNzd``&K`02BX3nd(}pvu z#YF`X?}bt;+#tt;YjTe>PsElHGSUXCwn
>(XSI+ETLBMhTUaveSrsuD|mhzl>Rv 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 I`Gj5m2UZ59@Bjb+ literal 0 HcmV?d00001 diff --git a/frontend/__snapshots__/components-playerinspector--default--light.png b/frontend/__snapshots__/components-playerinspector--default--light.png new file mode 100644 index 0000000000000000000000000000000000000000..e9aabac97d7d9b3a1430be8a3249bd9f254b7916 GIT binary patch literal 20444 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 literal 0 HcmV?d00001 diff --git a/frontend/src/scenes/session-recordings/player/inspector/PlayerInspector.stories.tsx b/frontend/src/scenes/session-recordings/player/inspector/PlayerInspector.stories.tsx new file mode 100644 index 00000000000..1c3376a829f --- /dev/null +++ b/frontend/src/scenes/session-recordings/player/inspector/PlayerInspector.stories.tsx @@ -0,0 +1,88 @@ +import { Meta, StoryFn, StoryObj } from '@storybook/react' +import { BindLogic, useActions, useValues } from 'kea' +import { useEffect } from 'react' +import recordingEventsJson from 'scenes/session-recordings/__mocks__/recording_events_query' +import recordingMetaJson from 'scenes/session-recordings/__mocks__/recording_meta.json' +import { snapshotsAsJSONLines } from 'scenes/session-recordings/__mocks__/recording_snapshots' +import { PlayerInspector } from 'scenes/session-recordings/player/inspector/PlayerInspector' +import { sessionRecordingDataLogic } from 'scenes/session-recordings/player/sessionRecordingDataLogic' +import { sessionRecordingPlayerLogic } from 'scenes/session-recordings/player/sessionRecordingPlayerLogic' + +import { mswDecorator } from '~/mocks/browser' + +type Story = StoryObj +const meta: Meta = { + title: 'Components/PlayerInspector', + component: PlayerInspector, + decorators: [ + mswDecorator({ + get: { + '/api/environments/:team_id/session_recordings/:id': recordingMetaJson, + '/api/environments/:team_id/session_recordings/:id/snapshots': (req, res, ctx) => { + // with no sources, returns sources... + if (req.url.searchParams.get('source') === 'blob') { + return res(ctx.text(snapshotsAsJSONLines())) + } + // with no source requested should return sources + return [ + 200, + { + sources: [ + { + source: 'blob', + start_timestamp: '2023-08-11T12:03:36.097000Z', + end_timestamp: '2023-08-11T12:04:52.268000Z', + blob_key: '1691755416097-1691755492268', + }, + ], + }, + ] + }, + }, + post: { + '/api/environments/:team_id/query': (req, res, ctx) => { + const body = req.body as Record + if (body.query.kind === 'EventsQuery' && body.query.properties.length === 1) { + return res(ctx.json(recordingEventsJson)) + } + + // default to an empty response or we duplicate information + return res(ctx.json({ results: [] })) + }, + }, + }), + ], +} +export default meta + +const BasicTemplate: StoryFn = () => { + const dataLogic = sessionRecordingDataLogic({ sessionRecordingId: '12345', playerKey: 'story-template' }) + const { sessionPlayerMetaData } = useValues(dataLogic) + + const { loadSnapshots, loadEvents } = useActions(dataLogic) + loadSnapshots() + + // TODO you have to call actions in a particular order + // and only when some other data has already been loaded + // 🫠 + useEffect(() => { + loadEvents() + }, [sessionPlayerMetaData]) + + return ( +
+ + + +
+ ) +} + +export const Default: Story = BasicTemplate.bind({}) +Default.args = {} diff --git a/frontend/src/scenes/session-recordings/player/inspector/PlayerInspector.tsx b/frontend/src/scenes/session-recordings/player/inspector/PlayerInspector.tsx new file mode 100644 index 00000000000..dc8c712cef4 --- /dev/null +++ b/frontend/src/scenes/session-recordings/player/inspector/PlayerInspector.tsx @@ -0,0 +1,11 @@ +import { PlayerInspectorControls } from 'scenes/session-recordings/player/inspector/PlayerInspectorControls' +import { PlayerInspectorList } from 'scenes/session-recordings/player/inspector/PlayerInspectorList' + +export function PlayerInspector(): JSX.Element { + return ( + <> + + + + ) +} diff --git a/frontend/src/scenes/session-recordings/player/sidebar/PlayerSidebarTab.tsx b/frontend/src/scenes/session-recordings/player/sidebar/PlayerSidebarTab.tsx index 8f2c12055f2..9c69a46274d 100644 --- a/frontend/src/scenes/session-recordings/player/sidebar/PlayerSidebarTab.tsx +++ b/frontend/src/scenes/session-recordings/player/sidebar/PlayerSidebarTab.tsx @@ -1,9 +1,8 @@ import { useValues } from 'kea' +import { PlayerInspector } from 'scenes/session-recordings/player/inspector/PlayerInspector' import { SessionRecordingSidebarTab } from '~/types' -import { PlayerInspectorControls } from '../inspector/PlayerInspectorControls' -import { PlayerInspectorList } from '../inspector/PlayerInspectorList' import { PlayerSidebarDebuggerTab } from './PlayerSidebarDebuggerTab' import { playerSidebarLogic } from './playerSidebarLogic' import { PlayerSidebarOverviewTab } from './PlayerSidebarOverviewTab' @@ -15,12 +14,7 @@ export function PlayerSidebarTab(): JSX.Element | null { case SessionRecordingSidebarTab.OVERVIEW: return case SessionRecordingSidebarTab.INSPECTOR: - return ( - <> - - - - ) + return case SessionRecordingSidebarTab.DEBUGGER: return default: