From 86610465514c33b8fd35a4dd71e9613de0b7884b Mon Sep 17 00:00:00 2001 From: Daniel Abraham Date: Mon, 5 Aug 2024 11:55:26 +0300 Subject: [PATCH 01/33] Initial draft --- task_chain/autokitteh.yaml | 18 +++++++ task_chain/interactive_message.json.txt | 47 ++++++++++++++++++ task_chain/program.py | 66 +++++++++++++++++++++++++ 3 files changed, 131 insertions(+) create mode 100644 task_chain/autokitteh.yaml create mode 100644 task_chain/interactive_message.json.txt create mode 100644 task_chain/program.py diff --git a/task_chain/autokitteh.yaml b/task_chain/autokitteh.yaml new file mode 100644 index 00000000..3680ffd8 --- /dev/null +++ b/task_chain/autokitteh.yaml @@ -0,0 +1,18 @@ +# This YAML file is a declarative manifest that describes the setup +# of an AutoKitteh project that ...TODO... +# +# After applying this file, initialize this AutoKitteh project's +# Slack connection. + +version: v1 + +project: + name: task_chain + connections: + - name: slack_conn + integration: slack + triggers: + - name: slack_slash_command + connection: slack_conn + event_type: slash_command + call: program.py:on_slack_slash_command diff --git a/task_chain/interactive_message.json.txt b/task_chain/interactive_message.json.txt new file mode 100644 index 00000000..a3dd5bfa --- /dev/null +++ b/task_chain/interactive_message.json.txt @@ -0,0 +1,47 @@ +[ + { + "type": "header", + "text": { + "type": "plain_text", + "emoji": true, + "text": ":warning: Workflow Error" + } + }, + { + "type": "divider" + }, + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "MESSAGE" + } + }, + { + "type": "divider" + }, + { + "type": "actions", + "elements": [ + { + "type": "button", + "text": { + "type": "plain_text", + "emoji": true, + "text": "Retry" + }, + "value": "retry", + }, + { + "type": "button", + "style": "danger", + "text": { + "type": "plain_text", + "emoji": true, + "text": "Abort" + }, + "value": "abort", + } + ] + } +] diff --git a/task_chain/program.py b/task_chain/program.py new file mode 100644 index 00000000..aa500c71 --- /dev/null +++ b/task_chain/program.py @@ -0,0 +1,66 @@ +"""TODO: Documentation header...""" + +from collections.abc import Callable +from pathlib import Path + +import autokitteh +from autokitteh.slack import slack_client + + +slack = slack_client("slack_conn") + + +def on_slack_slash_command(event) -> None: + """Use a Slack slash command from a user to start a task chain.""" + # Note to the interested reader: it's easy to improve this function + # to traverse a DAG with BFS or DFS, instead of a simple dynamic list. + next_task, ok = task_wrapper(task1, event.data.user_id) + while next_task: + next_task, ok = task_wrapper(next_task, event.data.user_id) + + if ok: + success_message = "Workflow completed successfully :smiley_cat:" + slack.chat_postMessage(channel=event.data.user_id, text=success_message) + + +def task_wrapper(task: Callable, user_id: str) -> tuple[Callable | None, bool]: + """Enable optional retries when tasks fail.""" + try: + return task(), True + except Exception as e: + retry = ask_user(task.__name__, str(e), user_id) + result = task if retry else None + return result, False + + +def ask_user(task_name: str, err: str, user_id: str) -> bool: + """Ask the user what to do when a task fails (retry / abort).""" + sub = autokitteh.subscribe("slack_conn", 'event_type == "interaction"') + + blocks = Path("interactive_message.json.txt").read_text() + blocks = blocks.replace("MESSAGE", f"The task `{task_name}` failed:\n\n`{err}`") + slack.chat_postMessage(channel=user_id, text="dummy text", blocks=blocks) + + event = autokitteh.next_event(sub) + autokitteh.unsubscribe(sub) + return event.actions[0]["value"] == "retry" + + +def task1() -> Callable | None: + print("Task 1 is doing stuff...") + return task2 + + +def task2() -> Callable | None: + print("Task 2 is doing stuff...") + return task3 + + +def task3() -> Callable | None: + print("Task 3 is doing stuff...") + raise RuntimeError("Something bad happened") + + +def task4() -> Callable | None: + print("Task 4 is doing stuff...") + return None # This is the last task. From 7784237e4027805b3664fff30341a357ae74aba1 Mon Sep 17 00:00:00 2001 From: Daniel Abraham Date: Mon, 5 Aug 2024 15:35:43 +0300 Subject: [PATCH 02/33] 2 approaches side-by-side --- task_chain/ask_user.py | 36 ++++++++++++++ task_chain/autokitteh.yaml | 6 ++- task_chain/event_driven.py | 49 ++++++++++++++++++ task_chain/interactive_message.json.txt | 2 + task_chain/main.py | 11 +++++ task_chain/program.py | 66 ------------------------- task_chain/single_workflow.py | 35 +++++++++++++ task_chain/tasks.py | 23 +++++++++ 8 files changed, 161 insertions(+), 67 deletions(-) create mode 100644 task_chain/ask_user.py create mode 100644 task_chain/event_driven.py create mode 100644 task_chain/main.py delete mode 100644 task_chain/program.py create mode 100644 task_chain/single_workflow.py create mode 100644 task_chain/tasks.py diff --git a/task_chain/ask_user.py b/task_chain/ask_user.py new file mode 100644 index 00000000..4946e485 --- /dev/null +++ b/task_chain/ask_user.py @@ -0,0 +1,36 @@ +"""Ask the user what to do when a task fails (retry / abort). + +If `wait_resp` is True, this function waits for the user's response. +It returns True if the user wants to retry the task, and False if +the user wants to abort the workflow. + +If `wait_resp` is False, this function returns immediately +and its return value is meaningless. +""" + +from pathlib import Path + +import autokitteh +from autokitteh.slack import slack_client + + +slack = slack_client("slack_conn") + + +def ask_user(task_name: str, error: str, user_id: str, *, wait_resp: bool) -> bool: + if wait_resp: + sub = autokitteh.subscribe("slack_conn", 'event_type == "interaction"') + + message = f"The task `{task_name}` failed:\n\n`{error}`" + blocks = Path("interactive_message.json.txt").read_text() + blocks = blocks.replace("MESSAGE", message).replace("TASK_NAME", task_name) + slack.chat_postMessage(channel=user_id, text="dummy text", blocks=blocks) + + # Event-driven approach: the user's response is handled by a different workflow. + if not wait_resp: + return False + + # Single-workflow approach: wait for and handle the user's response in this workflow. + event = autokitteh.next_event(sub) + autokitteh.unsubscribe(sub) + return event.actions[0]["value"] == "retry" diff --git a/task_chain/autokitteh.yaml b/task_chain/autokitteh.yaml index 3680ffd8..c884c181 100644 --- a/task_chain/autokitteh.yaml +++ b/task_chain/autokitteh.yaml @@ -15,4 +15,8 @@ project: - name: slack_slash_command connection: slack_conn event_type: slash_command - call: program.py:on_slack_slash_command + call: main.py:on_slack_slash_command + - name: slack_interaction + connection: slack_conn + event_type: interaction + call: event_driven.py:on_slack_interaction diff --git a/task_chain/event_driven.py b/task_chain/event_driven.py new file mode 100644 index 00000000..3ae01e34 --- /dev/null +++ b/task_chain/event_driven.py @@ -0,0 +1,49 @@ +"""This module uses an event-driven approach for this project. + +A single workflow is in charge of running all the tasks, except retries: + +1. First workflow: + - Trigger: Slack slash command + - Task 1 -> Task 2 -> Task 3 (error) -> Workflow error +2. Second workflow: + - Trigger: user clicks the "Retry" button in Slack + - Task 3 (retry) -> Task 4 -> Successful workflow completion +""" + +from collections.abc import Callable + +from autokitteh.slack import slack_client + +from ask_user import ask_user + + +slack = slack_client("slack_conn") + + +def run_tasks(task: Callable, user_id: str) -> None: + # Note to the interested reader: it's easy to improve this + # loop to traverse a DAG, instead of a simple dynamic list. + next_task = run_retriable_task(task, user_id) + while next_task: + next_task = run_retriable_task(next_task, user_id) + + success_message = "Workflow completed successfully :smiley_cat:" + slack.chat_postMessage(channel=user_id, text=success_message) + + +def run_retriable_task(task: Callable, user_id: str) -> Callable | None: + try: + return task() + except Exception as e: + ask_user.ask_user(task.__name__, str(e), user_id, wait_resp=True) + raise e # Abort the current workflow. + + +def on_slack_interaction(event): + """Handle the user's response (retry / abort) in a new workflow.""" + if event.data.actions[0]["value"] == "abort": + return + + # This workflow's starting point is a retry of the failed task in the aborted workflow. + task_name = event.data.actions[0]["action_id"].split()[-1] + run_tasks(globals()[task_name], event.data.user.id) diff --git a/task_chain/interactive_message.json.txt b/task_chain/interactive_message.json.txt index a3dd5bfa..9bbe4bab 100644 --- a/task_chain/interactive_message.json.txt +++ b/task_chain/interactive_message.json.txt @@ -31,6 +31,7 @@ "text": "Retry" }, "value": "retry", + "action_id": "RETRY TASK_NAME" }, { "type": "button", @@ -41,6 +42,7 @@ "text": "Abort" }, "value": "abort", + "action_id": "ABORT TASK_NAME" } ] } diff --git a/task_chain/main.py b/task_chain/main.py new file mode 100644 index 00000000..6220347b --- /dev/null +++ b/task_chain/main.py @@ -0,0 +1,11 @@ +"""Main entry-point for the "task chain" project.""" + +# import event_driven +import single_workflow +import tasks + + +def on_slack_slash_command(event): + """Use a Slack slash command from a user to start a chain of tasks.""" + single_workflow.run_tasks(tasks.task1, event.data.user_id) + # Alternative approach: event_driven.run_tasks(tasks.task1, event.data.user_id) diff --git a/task_chain/program.py b/task_chain/program.py deleted file mode 100644 index aa500c71..00000000 --- a/task_chain/program.py +++ /dev/null @@ -1,66 +0,0 @@ -"""TODO: Documentation header...""" - -from collections.abc import Callable -from pathlib import Path - -import autokitteh -from autokitteh.slack import slack_client - - -slack = slack_client("slack_conn") - - -def on_slack_slash_command(event) -> None: - """Use a Slack slash command from a user to start a task chain.""" - # Note to the interested reader: it's easy to improve this function - # to traverse a DAG with BFS or DFS, instead of a simple dynamic list. - next_task, ok = task_wrapper(task1, event.data.user_id) - while next_task: - next_task, ok = task_wrapper(next_task, event.data.user_id) - - if ok: - success_message = "Workflow completed successfully :smiley_cat:" - slack.chat_postMessage(channel=event.data.user_id, text=success_message) - - -def task_wrapper(task: Callable, user_id: str) -> tuple[Callable | None, bool]: - """Enable optional retries when tasks fail.""" - try: - return task(), True - except Exception as e: - retry = ask_user(task.__name__, str(e), user_id) - result = task if retry else None - return result, False - - -def ask_user(task_name: str, err: str, user_id: str) -> bool: - """Ask the user what to do when a task fails (retry / abort).""" - sub = autokitteh.subscribe("slack_conn", 'event_type == "interaction"') - - blocks = Path("interactive_message.json.txt").read_text() - blocks = blocks.replace("MESSAGE", f"The task `{task_name}` failed:\n\n`{err}`") - slack.chat_postMessage(channel=user_id, text="dummy text", blocks=blocks) - - event = autokitteh.next_event(sub) - autokitteh.unsubscribe(sub) - return event.actions[0]["value"] == "retry" - - -def task1() -> Callable | None: - print("Task 1 is doing stuff...") - return task2 - - -def task2() -> Callable | None: - print("Task 2 is doing stuff...") - return task3 - - -def task3() -> Callable | None: - print("Task 3 is doing stuff...") - raise RuntimeError("Something bad happened") - - -def task4() -> Callable | None: - print("Task 4 is doing stuff...") - return None # This is the last task. diff --git a/task_chain/single_workflow.py b/task_chain/single_workflow.py new file mode 100644 index 00000000..e7d58310 --- /dev/null +++ b/task_chain/single_workflow.py @@ -0,0 +1,35 @@ +"""This module uses a single-workflow approach for this project. + +A single workflow is in charge of running all the tasks, including retries. +It handles Slack interactions internally using runtime event subscriptions. +""" + +from collections.abc import Callable + +from autokitteh.slack import slack_client + +from ask_user import ask_user + + +slack = slack_client("slack_conn") + + +def run_tasks(task: Callable, user_id: str) -> None: + # Note to the interested reader: it's easy to improve this + # loop to traverse a DAG, instead of a simple dynamic list. + next_task, ok = run_retriable_task(task, user_id) + while next_task: + next_task, ok = run_retriable_task(next_task, user_id) + + if ok: + success_message = "Workflow completed successfully :smiley_cat:" + slack.chat_postMessage(channel=user_id, text=success_message) + + +def run_retriable_task(task: Callable, user_id: str) -> tuple[Callable | None, bool]: + try: + return task(), True + except Exception as e: + retry = ask_user.ask_user(task.__name__, str(e), user_id, wait_resp=True) + result = task if retry else None + return result, False diff --git a/task_chain/tasks.py b/task_chain/tasks.py new file mode 100644 index 00000000..b2085960 --- /dev/null +++ b/task_chain/tasks.py @@ -0,0 +1,23 @@ +"""Executable tasks that run in our workflow.""" + +from collections.abc import Callable + + +def task1() -> Callable | None: + print("Task 1 is doing stuff...") + return task2 + + +def task2() -> Callable | None: + print("Task 2 is doing stuff...") + return task3 + + +def task3() -> Callable | None: + print("Task 3 is doing stuff...") + raise RuntimeError("Something bad happened") + + +def task4() -> Callable | None: + print("Task 4 is doing stuff...") + return None # This is the last task. From a958ea16813512bc8e517dab369db8f916ef26f0 Mon Sep 17 00:00:00 2001 From: Daniel Abraham Date: Tue, 6 Aug 2024 10:13:45 +0300 Subject: [PATCH 03/33] Fix bug --- task_chain/event_driven.py | 2 +- task_chain/single_workflow.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/task_chain/event_driven.py b/task_chain/event_driven.py index 3ae01e34..f16bc465 100644 --- a/task_chain/event_driven.py +++ b/task_chain/event_driven.py @@ -35,7 +35,7 @@ def run_retriable_task(task: Callable, user_id: str) -> Callable | None: try: return task() except Exception as e: - ask_user.ask_user(task.__name__, str(e), user_id, wait_resp=True) + ask_user(task.__name__, str(e), user_id, wait_resp=True) raise e # Abort the current workflow. diff --git a/task_chain/single_workflow.py b/task_chain/single_workflow.py index e7d58310..7d750f62 100644 --- a/task_chain/single_workflow.py +++ b/task_chain/single_workflow.py @@ -30,6 +30,6 @@ def run_retriable_task(task: Callable, user_id: str) -> tuple[Callable | None, b try: return task(), True except Exception as e: - retry = ask_user.ask_user(task.__name__, str(e), user_id, wait_resp=True) + retry = ask_user(task.__name__, str(e), user_id, wait_resp=True) result = task if retry else None return result, False From 467c17248b5d5c5ba320ab16688b6ed8ccdf29c3 Mon Sep 17 00:00:00 2001 From: Daniel Abraham Date: Tue, 6 Aug 2024 10:32:29 +0300 Subject: [PATCH 04/33] Use project var to select workflow mode --- task_chain/ask_user.py | 16 +++++++++++----- task_chain/autokitteh.yaml | 3 +++ task_chain/event_driven.py | 2 +- task_chain/main.py | 14 +++++++++++--- task_chain/single_workflow.py | 2 +- 5 files changed, 27 insertions(+), 10 deletions(-) diff --git a/task_chain/ask_user.py b/task_chain/ask_user.py index 4946e485..e7c89fe3 100644 --- a/task_chain/ask_user.py +++ b/task_chain/ask_user.py @@ -8,29 +8,35 @@ and its return value is meaningless. """ +import os from pathlib import Path import autokitteh from autokitteh.slack import slack_client +SINGLE_WORKFLOW = os.getenv("SINGLE_WORKFLOW", "true").lower() + + slack = slack_client("slack_conn") -def ask_user(task_name: str, error: str, user_id: str, *, wait_resp: bool) -> bool: - if wait_resp: +def ask_user(task_name: str, error: str, user_id: str) -> bool: + wait_for_response = SINGLE_WORKFLOW in ["true", "yes", "on", "1"] + + if wait_for_response: sub = autokitteh.subscribe("slack_conn", 'event_type == "interaction"') message = f"The task `{task_name}` failed:\n\n`{error}`" blocks = Path("interactive_message.json.txt").read_text() blocks = blocks.replace("MESSAGE", message).replace("TASK_NAME", task_name) - slack.chat_postMessage(channel=user_id, text="dummy text", blocks=blocks) + slack.chat_postMessage(channel=user_id, text="blocks", blocks=blocks) # Event-driven approach: the user's response is handled by a different workflow. - if not wait_resp: + if not wait_for_response: return False # Single-workflow approach: wait for and handle the user's response in this workflow. event = autokitteh.next_event(sub) autokitteh.unsubscribe(sub) - return event.actions[0]["value"] == "retry" + return event.actions[0].value == "retry" diff --git a/task_chain/autokitteh.yaml b/task_chain/autokitteh.yaml index c884c181..9eeb3f8c 100644 --- a/task_chain/autokitteh.yaml +++ b/task_chain/autokitteh.yaml @@ -8,6 +8,9 @@ version: v1 project: name: task_chain + vars: + - name: SINGLE_WORKFLOW + value: true connections: - name: slack_conn integration: slack diff --git a/task_chain/event_driven.py b/task_chain/event_driven.py index f16bc465..990ff175 100644 --- a/task_chain/event_driven.py +++ b/task_chain/event_driven.py @@ -35,7 +35,7 @@ def run_retriable_task(task: Callable, user_id: str) -> Callable | None: try: return task() except Exception as e: - ask_user(task.__name__, str(e), user_id, wait_resp=True) + ask_user(task.__name__, str(e), user_id) raise e # Abort the current workflow. diff --git a/task_chain/main.py b/task_chain/main.py index 6220347b..ba584afb 100644 --- a/task_chain/main.py +++ b/task_chain/main.py @@ -1,11 +1,19 @@ """Main entry-point for the "task chain" project.""" -# import event_driven +import os + +import event_driven import single_workflow import tasks +SINGLE_WORKFLOW = os.getenv("SINGLE_WORKFLOW", "true").lower() + + def on_slack_slash_command(event): """Use a Slack slash command from a user to start a chain of tasks.""" - single_workflow.run_tasks(tasks.task1, event.data.user_id) - # Alternative approach: event_driven.run_tasks(tasks.task1, event.data.user_id) + first_task = tasks.task1 + if SINGLE_WORKFLOW in ["true", "yes", "on", "1"]: + single_workflow.run_tasks(first_task, event.data.user_id) + else: + event_driven.run_tasks(first_task, event.data.user_id) diff --git a/task_chain/single_workflow.py b/task_chain/single_workflow.py index 7d750f62..b569adf6 100644 --- a/task_chain/single_workflow.py +++ b/task_chain/single_workflow.py @@ -30,6 +30,6 @@ def run_retriable_task(task: Callable, user_id: str) -> tuple[Callable | None, b try: return task(), True except Exception as e: - retry = ask_user(task.__name__, str(e), user_id, wait_resp=True) + retry = ask_user(task.__name__, str(e), user_id) result = task if retry else None return result, False From 317b30dd31d54cc163436e4cc32a8002a4110f3d Mon Sep 17 00:00:00 2001 From: Daniel Abraham Date: Tue, 6 Aug 2024 10:38:22 +0300 Subject: [PATCH 05/33] Fix bug in retrying event-based task --- task_chain/event_driven.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/task_chain/event_driven.py b/task_chain/event_driven.py index 990ff175..f0ab6112 100644 --- a/task_chain/event_driven.py +++ b/task_chain/event_driven.py @@ -15,6 +15,7 @@ from autokitteh.slack import slack_client from ask_user import ask_user +import tasks slack = slack_client("slack_conn") @@ -46,4 +47,4 @@ def on_slack_interaction(event): # This workflow's starting point is a retry of the failed task in the aborted workflow. task_name = event.data.actions[0]["action_id"].split()[-1] - run_tasks(globals()[task_name], event.data.user.id) + run_tasks(getattr(tasks, task_name), event.data.user.id) From ab8e54b55191626bccd26fbe6e0055d35531f4f8 Mon Sep 17 00:00:00 2001 From: Daniel Abraham Date: Tue, 6 Aug 2024 16:27:29 +0300 Subject: [PATCH 06/33] Cosmetic tweak --- task_chain/ask_user.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/task_chain/ask_user.py b/task_chain/ask_user.py index e7c89fe3..cdab4e97 100644 --- a/task_chain/ask_user.py +++ b/task_chain/ask_user.py @@ -30,7 +30,7 @@ def ask_user(task_name: str, error: str, user_id: str) -> bool: message = f"The task `{task_name}` failed:\n\n`{error}`" blocks = Path("interactive_message.json.txt").read_text() blocks = blocks.replace("MESSAGE", message).replace("TASK_NAME", task_name) - slack.chat_postMessage(channel=user_id, text="blocks", blocks=blocks) + slack.chat_postMessage(channel=user_id, text="Workflow error", blocks=blocks) # Event-driven approach: the user's response is handled by a different workflow. if not wait_for_response: From e1130cb2742634b00c036fc042b97205b8b5d385 Mon Sep 17 00:00:00 2001 From: Daniel Abraham Date: Tue, 6 Aug 2024 16:38:30 +0300 Subject: [PATCH 07/33] Don't handle interaction events in new WF in single-WF mode --- task_chain/event_driven.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/task_chain/event_driven.py b/task_chain/event_driven.py index f0ab6112..6a7722ca 100644 --- a/task_chain/event_driven.py +++ b/task_chain/event_driven.py @@ -11,6 +11,7 @@ """ from collections.abc import Callable +import os from autokitteh.slack import slack_client @@ -18,6 +19,9 @@ import tasks +SINGLE_WORKFLOW = os.getenv("SINGLE_WORKFLOW", "true").lower() + + slack = slack_client("slack_conn") @@ -42,6 +46,9 @@ def run_retriable_task(task: Callable, user_id: str) -> Callable | None: def on_slack_interaction(event): """Handle the user's response (retry / abort) in a new workflow.""" + if SINGLE_WORKFLOW in ["true", "yes", "on", "1"]: + return + if event.data.actions[0]["value"] == "abort": return From ed460d5ddcf7e8e2633e00a2ca31b87ca68112f4 Mon Sep 17 00:00:00 2001 From: Daniel Abraham Date: Wed, 7 Aug 2024 13:40:03 +0300 Subject: [PATCH 08/33] Restructure --- task_chain/ask_user.py | 42 ---------- task_chain/event_driven.py | 57 ------------- task_chain/{ => event_driven}/autokitteh.yaml | 7 +- .../interactive_message.json.txt | 4 +- task_chain/event_driven/program.py | 83 +++++++++++++++++++ task_chain/main.py | 19 ----- task_chain/single_workflow.py | 35 -------- .../single_workflow/advanced/autokitteh.yaml | 18 ++++ .../advanced/interactive_message.json.txt | 47 +++++++++++ .../single_workflow/advanced/program.py | 75 +++++++++++++++++ .../single_workflow/basic/autokitteh.yaml | 18 ++++ .../basic/interactive_message.json.txt | 47 +++++++++++ task_chain/single_workflow/basic/program.py | 76 +++++++++++++++++ task_chain/tasks.py | 23 ----- 14 files changed, 368 insertions(+), 183 deletions(-) delete mode 100644 task_chain/ask_user.py delete mode 100644 task_chain/event_driven.py rename task_chain/{ => event_driven}/autokitteh.yaml (77%) rename task_chain/{ => event_driven}/interactive_message.json.txt (91%) create mode 100644 task_chain/event_driven/program.py delete mode 100644 task_chain/main.py delete mode 100644 task_chain/single_workflow.py create mode 100644 task_chain/single_workflow/advanced/autokitteh.yaml create mode 100644 task_chain/single_workflow/advanced/interactive_message.json.txt create mode 100644 task_chain/single_workflow/advanced/program.py create mode 100644 task_chain/single_workflow/basic/autokitteh.yaml create mode 100644 task_chain/single_workflow/basic/interactive_message.json.txt create mode 100644 task_chain/single_workflow/basic/program.py delete mode 100644 task_chain/tasks.py diff --git a/task_chain/ask_user.py b/task_chain/ask_user.py deleted file mode 100644 index cdab4e97..00000000 --- a/task_chain/ask_user.py +++ /dev/null @@ -1,42 +0,0 @@ -"""Ask the user what to do when a task fails (retry / abort). - -If `wait_resp` is True, this function waits for the user's response. -It returns True if the user wants to retry the task, and False if -the user wants to abort the workflow. - -If `wait_resp` is False, this function returns immediately -and its return value is meaningless. -""" - -import os -from pathlib import Path - -import autokitteh -from autokitteh.slack import slack_client - - -SINGLE_WORKFLOW = os.getenv("SINGLE_WORKFLOW", "true").lower() - - -slack = slack_client("slack_conn") - - -def ask_user(task_name: str, error: str, user_id: str) -> bool: - wait_for_response = SINGLE_WORKFLOW in ["true", "yes", "on", "1"] - - if wait_for_response: - sub = autokitteh.subscribe("slack_conn", 'event_type == "interaction"') - - message = f"The task `{task_name}` failed:\n\n`{error}`" - blocks = Path("interactive_message.json.txt").read_text() - blocks = blocks.replace("MESSAGE", message).replace("TASK_NAME", task_name) - slack.chat_postMessage(channel=user_id, text="Workflow error", blocks=blocks) - - # Event-driven approach: the user's response is handled by a different workflow. - if not wait_for_response: - return False - - # Single-workflow approach: wait for and handle the user's response in this workflow. - event = autokitteh.next_event(sub) - autokitteh.unsubscribe(sub) - return event.actions[0].value == "retry" diff --git a/task_chain/event_driven.py b/task_chain/event_driven.py deleted file mode 100644 index 6a7722ca..00000000 --- a/task_chain/event_driven.py +++ /dev/null @@ -1,57 +0,0 @@ -"""This module uses an event-driven approach for this project. - -A single workflow is in charge of running all the tasks, except retries: - -1. First workflow: - - Trigger: Slack slash command - - Task 1 -> Task 2 -> Task 3 (error) -> Workflow error -2. Second workflow: - - Trigger: user clicks the "Retry" button in Slack - - Task 3 (retry) -> Task 4 -> Successful workflow completion -""" - -from collections.abc import Callable -import os - -from autokitteh.slack import slack_client - -from ask_user import ask_user -import tasks - - -SINGLE_WORKFLOW = os.getenv("SINGLE_WORKFLOW", "true").lower() - - -slack = slack_client("slack_conn") - - -def run_tasks(task: Callable, user_id: str) -> None: - # Note to the interested reader: it's easy to improve this - # loop to traverse a DAG, instead of a simple dynamic list. - next_task = run_retriable_task(task, user_id) - while next_task: - next_task = run_retriable_task(next_task, user_id) - - success_message = "Workflow completed successfully :smiley_cat:" - slack.chat_postMessage(channel=user_id, text=success_message) - - -def run_retriable_task(task: Callable, user_id: str) -> Callable | None: - try: - return task() - except Exception as e: - ask_user(task.__name__, str(e), user_id) - raise e # Abort the current workflow. - - -def on_slack_interaction(event): - """Handle the user's response (retry / abort) in a new workflow.""" - if SINGLE_WORKFLOW in ["true", "yes", "on", "1"]: - return - - if event.data.actions[0]["value"] == "abort": - return - - # This workflow's starting point is a retry of the failed task in the aborted workflow. - task_name = event.data.actions[0]["action_id"].split()[-1] - run_tasks(getattr(tasks, task_name), event.data.user.id) diff --git a/task_chain/autokitteh.yaml b/task_chain/event_driven/autokitteh.yaml similarity index 77% rename from task_chain/autokitteh.yaml rename to task_chain/event_driven/autokitteh.yaml index 9eeb3f8c..f1a9c7ef 100644 --- a/task_chain/autokitteh.yaml +++ b/task_chain/event_driven/autokitteh.yaml @@ -8,9 +8,6 @@ version: v1 project: name: task_chain - vars: - - name: SINGLE_WORKFLOW - value: true connections: - name: slack_conn integration: slack @@ -18,8 +15,8 @@ project: - name: slack_slash_command connection: slack_conn event_type: slash_command - call: main.py:on_slack_slash_command + call: program.py:on_slack_slash_command - name: slack_interaction connection: slack_conn event_type: interaction - call: event_driven.py:on_slack_interaction + call: program.py:on_slack_interaction diff --git a/task_chain/interactive_message.json.txt b/task_chain/event_driven/interactive_message.json.txt similarity index 91% rename from task_chain/interactive_message.json.txt rename to task_chain/event_driven/interactive_message.json.txt index 9bbe4bab..ca0fefc8 100644 --- a/task_chain/interactive_message.json.txt +++ b/task_chain/event_driven/interactive_message.json.txt @@ -31,7 +31,7 @@ "text": "Retry" }, "value": "retry", - "action_id": "RETRY TASK_NAME" + "action_id": "RETRY INDEX" }, { "type": "button", @@ -42,7 +42,7 @@ "text": "Abort" }, "value": "abort", - "action_id": "ABORT TASK_NAME" + "action_id": "ABORT INDEX" } ] } diff --git a/task_chain/event_driven/program.py b/task_chain/event_driven/program.py new file mode 100644 index 00000000..64aa36fc --- /dev/null +++ b/task_chain/event_driven/program.py @@ -0,0 +1,83 @@ +"""This module uses an event-driven approach for the task-chain project. + +A single workflow is in charge of running all the tasks, except retries: + +1. First workflow: + - Trigger: Slack slash command + - Task 1 -> Task 2 -> Task 3 (error) -> Workflow error +2. Second workflow: + - Trigger: user clicks the "Retry" button in Slack + - Task 3 (retry) -> Task 4 -> Successful workflow completion +""" + +from pathlib import Path + +from autokitteh.slack import slack_client + + +slack = slack_client("slack_conn") + + +def step1(): + print("Step 1 is doing stuff...") + + +def step2(): + print("Step 2 is doing stuff...") + + +def step3(): + print("Step 3 is doing stuff...") + raise RuntimeError("Something bad happened") + + +def step4(): + print("Step 4 is doing stuff...") + + +tasks = [step1, step2, step3, step4] + + +def on_slack_slash_command(event): + """Use a Slack slash command from a user to start a chain of tasks.""" + run_tasks(event.data.user_id) + + +def run_tasks(user_id): + # Note to the interested reader: it's easy to improve this project + # to traverse a dynamic DAG, instead of a simple static list. + for i, task in enumerate(tasks): + run_retriable_task(task, i, user_id) + + message = "Workflow completed successfully :smiley_cat:" + slack.chat_postMessage(channel=user_id, text=message) + + +def run_retriable_task(task, i, user_id): + try: + task() + except Exception as e: + ask_user_retry_or_abort(task.__name__, e, i, user_id) + raise e # Abort the current workflow. + + message = f"Task `{task.__name__}` completed" + slack.chat_postMessage(channel=user_id, text=message) + + +def ask_user_retry_or_abort(task_name, error, i, user_id): + message = f"The task `{task_name}` failed: `{error}`" + blocks = Path("interactive_message.json.txt").read_text() + blocks = blocks.replace("MESSAGE", message).replace("INDEX", str(i)) + slack.chat_postMessage(channel=user_id, text="Workflow error", blocks=blocks) + + +def on_slack_interaction(event): + """Handle the user's response (retry / abort) in a new workflow.""" + if event.data.actions[0]["value"] == "abort": + return + + # This workflow's starting point is a retry of the failed task in the aborted workflow. + global tasks + i = int(event.data.actions[0]["action_id"].split()[-1]) + tasks = tasks[i:] + run_tasks(event.data.user.id) diff --git a/task_chain/main.py b/task_chain/main.py deleted file mode 100644 index ba584afb..00000000 --- a/task_chain/main.py +++ /dev/null @@ -1,19 +0,0 @@ -"""Main entry-point for the "task chain" project.""" - -import os - -import event_driven -import single_workflow -import tasks - - -SINGLE_WORKFLOW = os.getenv("SINGLE_WORKFLOW", "true").lower() - - -def on_slack_slash_command(event): - """Use a Slack slash command from a user to start a chain of tasks.""" - first_task = tasks.task1 - if SINGLE_WORKFLOW in ["true", "yes", "on", "1"]: - single_workflow.run_tasks(first_task, event.data.user_id) - else: - event_driven.run_tasks(first_task, event.data.user_id) diff --git a/task_chain/single_workflow.py b/task_chain/single_workflow.py deleted file mode 100644 index b569adf6..00000000 --- a/task_chain/single_workflow.py +++ /dev/null @@ -1,35 +0,0 @@ -"""This module uses a single-workflow approach for this project. - -A single workflow is in charge of running all the tasks, including retries. -It handles Slack interactions internally using runtime event subscriptions. -""" - -from collections.abc import Callable - -from autokitteh.slack import slack_client - -from ask_user import ask_user - - -slack = slack_client("slack_conn") - - -def run_tasks(task: Callable, user_id: str) -> None: - # Note to the interested reader: it's easy to improve this - # loop to traverse a DAG, instead of a simple dynamic list. - next_task, ok = run_retriable_task(task, user_id) - while next_task: - next_task, ok = run_retriable_task(next_task, user_id) - - if ok: - success_message = "Workflow completed successfully :smiley_cat:" - slack.chat_postMessage(channel=user_id, text=success_message) - - -def run_retriable_task(task: Callable, user_id: str) -> tuple[Callable | None, bool]: - try: - return task(), True - except Exception as e: - retry = ask_user(task.__name__, str(e), user_id) - result = task if retry else None - return result, False diff --git a/task_chain/single_workflow/advanced/autokitteh.yaml b/task_chain/single_workflow/advanced/autokitteh.yaml new file mode 100644 index 00000000..3680ffd8 --- /dev/null +++ b/task_chain/single_workflow/advanced/autokitteh.yaml @@ -0,0 +1,18 @@ +# This YAML file is a declarative manifest that describes the setup +# of an AutoKitteh project that ...TODO... +# +# After applying this file, initialize this AutoKitteh project's +# Slack connection. + +version: v1 + +project: + name: task_chain + connections: + - name: slack_conn + integration: slack + triggers: + - name: slack_slash_command + connection: slack_conn + event_type: slash_command + call: program.py:on_slack_slash_command diff --git a/task_chain/single_workflow/advanced/interactive_message.json.txt b/task_chain/single_workflow/advanced/interactive_message.json.txt new file mode 100644 index 00000000..a3dd5bfa --- /dev/null +++ b/task_chain/single_workflow/advanced/interactive_message.json.txt @@ -0,0 +1,47 @@ +[ + { + "type": "header", + "text": { + "type": "plain_text", + "emoji": true, + "text": ":warning: Workflow Error" + } + }, + { + "type": "divider" + }, + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "MESSAGE" + } + }, + { + "type": "divider" + }, + { + "type": "actions", + "elements": [ + { + "type": "button", + "text": { + "type": "plain_text", + "emoji": true, + "text": "Retry" + }, + "value": "retry", + }, + { + "type": "button", + "style": "danger", + "text": { + "type": "plain_text", + "emoji": true, + "text": "Abort" + }, + "value": "abort", + } + ] + } +] diff --git a/task_chain/single_workflow/advanced/program.py b/task_chain/single_workflow/advanced/program.py new file mode 100644 index 00000000..b5007d6a --- /dev/null +++ b/task_chain/single_workflow/advanced/program.py @@ -0,0 +1,75 @@ +"""This module uses a single-workflow approach for this project. + +A single workflow is in charge of running all the tasks, including retries. +It handles Slack interactions internally using runtime event subscriptions. +""" + +from pathlib import Path + +import autokitteh +from autokitteh.slack import slack_client + + +slack = slack_client("slack_conn") + + +def step1(): + print("Step 1 is doing stuff...") + + +def step2(): + print("Step 2 is doing stuff...") + + +def step3(): + print("Step 3 is doing stuff...") + raise RuntimeError("Something bad happened") + + +def step4(): + print("Step 4 is doing stuff...") + + +tasks = [step1, step2, step3, step4] + + +def on_slack_slash_command(event): + """Use a Slack slash command from a user to start a chain of tasks.""" + user_id = event.data.user_id + + # Note to the interested reader: it's easy to improve this project + # to traverse a dynamic DAG, instead of a simple static list. + success = True + while len(tasks) > 0 and success: + success = run_retriable_task(tasks[0], user_id) + + if success: + message = "Workflow completed successfully :smiley_cat:" + slack.chat_postMessage(channel=user_id, text=message) + + +def run_retriable_task(task, user_id) -> bool: + try: + task() + except Exception as e: + return ask_user_retry_or_abort(task.__name__, e, user_id) + + message = f"Task `{task.__name__}` completed" + slack.chat_postMessage(channel=user_id, text=message) + + global tasks + tasks.remove(task) + return True + + +def ask_user_retry_or_abort(task_name, error, user_id) -> bool: + sub = autokitteh.subscribe("slack_conn", 'event_type == "interaction"') + + blocks = Path("interactive_message.json.txt").read_text() + blocks = blocks.replace("MESSAGE", f"The task `{task_name}` failed: `{error}`") + slack.chat_postMessage(channel=user_id, text="Workflow error", blocks=blocks) + + # Wait for and handle the user's response in this workflow. + event = autokitteh.next_event(sub) + autokitteh.unsubscribe(sub) + return event.actions[0]["value"] == "retry" diff --git a/task_chain/single_workflow/basic/autokitteh.yaml b/task_chain/single_workflow/basic/autokitteh.yaml new file mode 100644 index 00000000..3680ffd8 --- /dev/null +++ b/task_chain/single_workflow/basic/autokitteh.yaml @@ -0,0 +1,18 @@ +# This YAML file is a declarative manifest that describes the setup +# of an AutoKitteh project that ...TODO... +# +# After applying this file, initialize this AutoKitteh project's +# Slack connection. + +version: v1 + +project: + name: task_chain + connections: + - name: slack_conn + integration: slack + triggers: + - name: slack_slash_command + connection: slack_conn + event_type: slash_command + call: program.py:on_slack_slash_command diff --git a/task_chain/single_workflow/basic/interactive_message.json.txt b/task_chain/single_workflow/basic/interactive_message.json.txt new file mode 100644 index 00000000..a3dd5bfa --- /dev/null +++ b/task_chain/single_workflow/basic/interactive_message.json.txt @@ -0,0 +1,47 @@ +[ + { + "type": "header", + "text": { + "type": "plain_text", + "emoji": true, + "text": ":warning: Workflow Error" + } + }, + { + "type": "divider" + }, + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "MESSAGE" + } + }, + { + "type": "divider" + }, + { + "type": "actions", + "elements": [ + { + "type": "button", + "text": { + "type": "plain_text", + "emoji": true, + "text": "Retry" + }, + "value": "retry", + }, + { + "type": "button", + "style": "danger", + "text": { + "type": "plain_text", + "emoji": true, + "text": "Abort" + }, + "value": "abort", + } + ] + } +] diff --git a/task_chain/single_workflow/basic/program.py b/task_chain/single_workflow/basic/program.py new file mode 100644 index 00000000..a58a7b84 --- /dev/null +++ b/task_chain/single_workflow/basic/program.py @@ -0,0 +1,76 @@ +"""This module uses a single-workflow approach for this project. + +A single workflow is in charge of running all the tasks, including retries. +It handles Slack interactions internally using runtime event subscriptions. +""" + +from pathlib import Path + +import autokitteh +from autokitteh.slack import slack_client + + +slack = slack_client("slack_conn") + + +def step1(): + print("Step 1 is doing stuff...") + + +def step2(): + print("Step 2 is doing stuff...") + + +def step3(): + print("Step 3 is doing stuff...") + raise RuntimeError("Something bad happened") + + +def step4(): + print("Step 4 is doing stuff...") + + +def on_slack_slash_command(event): + """Use a Slack slash command from a user to start a chain of tasks.""" + user_id = event.data.user_id + + if not run_retriable_task(step1, user_id): + return + if not run_retriable_task(step2, user_id): + return + if not run_retriable_task(step3, user_id): + return + if not run_retriable_task(step4, user_id): + return + + message = "Workflow completed successfully :smiley_cat:" + slack.chat_postMessage(channel=user_id, text=message) + + +def run_retriable_task(task, user_id) -> bool: + result = True + while result: + try: + task() + break + except Exception as e: + result = ask_user_retry_or_abort(task.__name__, e, user_id) + + if result: + message = f"Task `{task.__name__}` completed" + slack.chat_postMessage(channel=user_id, text=message) + + return result + + +def ask_user_retry_or_abort(task_name, error, user_id) -> bool: + sub = autokitteh.subscribe("slack_conn", 'event_type == "interaction"') + + blocks = Path("interactive_message.json.txt").read_text() + blocks = blocks.replace("MESSAGE", f"The task `{task_name}` failed: `{error}`") + slack.chat_postMessage(channel=user_id, text="Workflow error", blocks=blocks) + + # Wait for and handle the user's response in this workflow. + event = autokitteh.next_event(sub) + autokitteh.unsubscribe(sub) + return event.actions[0]["value"] == "retry" diff --git a/task_chain/tasks.py b/task_chain/tasks.py deleted file mode 100644 index b2085960..00000000 --- a/task_chain/tasks.py +++ /dev/null @@ -1,23 +0,0 @@ -"""Executable tasks that run in our workflow.""" - -from collections.abc import Callable - - -def task1() -> Callable | None: - print("Task 1 is doing stuff...") - return task2 - - -def task2() -> Callable | None: - print("Task 2 is doing stuff...") - return task3 - - -def task3() -> Callable | None: - print("Task 3 is doing stuff...") - raise RuntimeError("Something bad happened") - - -def task4() -> Callable | None: - print("Task 4 is doing stuff...") - return None # This is the last task. From 3bb20ab196a9aaf362078f1f6cc83d2705935e27 Mon Sep 17 00:00:00 2001 From: Daniel Abraham Date: Wed, 7 Aug 2024 14:42:09 +0300 Subject: [PATCH 09/33] Documentation --- task_chain/README.md | 31 +++++++++++++++++++ task_chain/event_driven/autokitteh.yaml | 3 +- task_chain/event_driven/program.py | 2 +- .../single_workflow/advanced/autokitteh.yaml | 3 +- .../single_workflow/advanced/program.py | 6 ++-- .../single_workflow/basic/autokitteh.yaml | 3 +- task_chain/single_workflow/basic/program.py | 6 ++-- 7 files changed, 44 insertions(+), 10 deletions(-) create mode 100644 task_chain/README.md diff --git a/task_chain/README.md b/task_chain/README.md new file mode 100644 index 00000000..9d624909 --- /dev/null +++ b/task_chain/README.md @@ -0,0 +1,31 @@ +# Task Chain + +This project demonstrates running a sequence of tasks, in several ways. + +- Single-workflow approach: + - A single workflow runs all the tasks, including retry loops; it handles + Slack interactions using runtime event subscriptions + - ["Basic" mode](./single_workflow/basic/) - ... + - ["Advanced" mode](./single_workflow/advanced/) - ... +- [Event-driven approach](./event_driven/) + - A single workflow runs all the tasks, except retries + +```mermaid +flowchart LR + slack{Slack event} + task1[Task 1] + task2[Task 2] + task3a[Task 3] + task3b[Task 3] + task4[Task 4] + error((fa:fa-circle-xmark Workflow error)) + success((fa:fa-circle-check Workflow success)) + slack -. Slash command .-> task1 + slack -. Click "retry" .-> task3b + subgraph Workflow 1 + task1 --> task2 --> task3a ~~~ error + end + subgraph Workflow 1 + task3b --> task4 ~~~ success + end +``` diff --git a/task_chain/event_driven/autokitteh.yaml b/task_chain/event_driven/autokitteh.yaml index f1a9c7ef..fd4d2bbd 100644 --- a/task_chain/event_driven/autokitteh.yaml +++ b/task_chain/event_driven/autokitteh.yaml @@ -1,5 +1,6 @@ # This YAML file is a declarative manifest that describes the setup -# of an AutoKitteh project that ...TODO... +# of an AutoKitteh project that runs a sequence of tasks, using an +# event-driven approach. # # After applying this file, initialize this AutoKitteh project's # Slack connection. diff --git a/task_chain/event_driven/program.py b/task_chain/event_driven/program.py index 64aa36fc..dfc3f0d0 100644 --- a/task_chain/event_driven/program.py +++ b/task_chain/event_driven/program.py @@ -1,6 +1,6 @@ """This module uses an event-driven approach for the task-chain project. -A single workflow is in charge of running all the tasks, except retries: +A single workflow runs all the tasks, except retries: 1. First workflow: - Trigger: Slack slash command diff --git a/task_chain/single_workflow/advanced/autokitteh.yaml b/task_chain/single_workflow/advanced/autokitteh.yaml index 3680ffd8..edb9bf9b 100644 --- a/task_chain/single_workflow/advanced/autokitteh.yaml +++ b/task_chain/single_workflow/advanced/autokitteh.yaml @@ -1,5 +1,6 @@ # This YAML file is a declarative manifest that describes the setup -# of an AutoKitteh project that ...TODO... +# of an AutoKitteh project that runs a sequence of tasks, using an +# advanced single-workflow approach. # # After applying this file, initialize this AutoKitteh project's # Slack connection. diff --git a/task_chain/single_workflow/advanced/program.py b/task_chain/single_workflow/advanced/program.py index b5007d6a..36811173 100644 --- a/task_chain/single_workflow/advanced/program.py +++ b/task_chain/single_workflow/advanced/program.py @@ -1,7 +1,7 @@ -"""This module uses a single-workflow approach for this project. +"""This module uses a single-workflow approach for the task-chain project. -A single workflow is in charge of running all the tasks, including retries. -It handles Slack interactions internally using runtime event subscriptions. +A single workflow runs all the tasks, including retry loops. +It handles Slack interactions using runtime event subscriptions. """ from pathlib import Path diff --git a/task_chain/single_workflow/basic/autokitteh.yaml b/task_chain/single_workflow/basic/autokitteh.yaml index 3680ffd8..16a651e8 100644 --- a/task_chain/single_workflow/basic/autokitteh.yaml +++ b/task_chain/single_workflow/basic/autokitteh.yaml @@ -1,5 +1,6 @@ # This YAML file is a declarative manifest that describes the setup -# of an AutoKitteh project that ...TODO... +# of an AutoKitteh project that runs a sequence of tasks, using a +# basic single-workflow approach. # # After applying this file, initialize this AutoKitteh project's # Slack connection. diff --git a/task_chain/single_workflow/basic/program.py b/task_chain/single_workflow/basic/program.py index a58a7b84..10025764 100644 --- a/task_chain/single_workflow/basic/program.py +++ b/task_chain/single_workflow/basic/program.py @@ -1,7 +1,7 @@ -"""This module uses a single-workflow approach for this project. +"""This module uses a single-workflow approach for the task-chain project. -A single workflow is in charge of running all the tasks, including retries. -It handles Slack interactions internally using runtime event subscriptions. +A single workflow runs all the tasks, including retry loops. +It handles Slack interactions using runtime event subscriptions. """ from pathlib import Path From 4e63195f958e59fdd4030c8609018a242c42a114 Mon Sep 17 00:00:00 2001 From: Daniel Abraham Date: Wed, 7 Aug 2024 14:43:34 +0300 Subject: [PATCH 10/33] Fix flowchart --- task_chain/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/task_chain/README.md b/task_chain/README.md index 9d624909..6fa12431 100644 --- a/task_chain/README.md +++ b/task_chain/README.md @@ -21,7 +21,7 @@ flowchart LR error((fa:fa-circle-xmark Workflow error)) success((fa:fa-circle-check Workflow success)) slack -. Slash command .-> task1 - slack -. Click "retry" .-> task3b + slack -. Retry button clicked .-> task3b subgraph Workflow 1 task1 --> task2 --> task3a ~~~ error end From 8002175cee7f7a7d9a07ac1c3162fbb46eca92cd Mon Sep 17 00:00:00 2001 From: Daniel Abraham Date: Wed, 7 Aug 2024 14:45:58 +0300 Subject: [PATCH 11/33] Flowchart fix --- task_chain/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/task_chain/README.md b/task_chain/README.md index 6fa12431..fd310139 100644 --- a/task_chain/README.md +++ b/task_chain/README.md @@ -16,16 +16,16 @@ flowchart LR task1[Task 1] task2[Task 2] task3a[Task 3] - task3b[Task 3] + task3b[Task 3 retry] task4[Task 4] error((fa:fa-circle-xmark Workflow error)) success((fa:fa-circle-check Workflow success)) slack -. Slash command .-> task1 slack -. Retry button clicked .-> task3b subgraph Workflow 1 - task1 --> task2 --> task3a ~~~ error + task1 --> task2 --> task3a -.-> error end - subgraph Workflow 1 - task3b --> task4 ~~~ success + subgraph Workflow 2 + task3b --> task4 -.-> success end ``` From 981ec10e85ba46c19ec10d1a0e0a09576fe560b5 Mon Sep 17 00:00:00 2001 From: Daniel Abraham Date: Wed, 7 Aug 2024 14:49:06 +0300 Subject: [PATCH 12/33] Fix flowchart --- task_chain/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/task_chain/README.md b/task_chain/README.md index fd310139..ea3f3e6a 100644 --- a/task_chain/README.md +++ b/task_chain/README.md @@ -18,12 +18,12 @@ flowchart LR task3a[Task 3] task3b[Task 3 retry] task4[Task 4] - error((fa:fa-circle-xmark Workflow error)) - success((fa:fa-circle-check Workflow success)) + error((Error)) + success((Success)) slack -. Slash command .-> task1 slack -. Retry button clicked .-> task3b subgraph Workflow 1 - task1 --> task2 --> task3a -.-> error + task1 --> task2 --> task3a -.-> error -. Retry/abort? .-> slack end subgraph Workflow 2 task3b --> task4 -.-> success From 920994a6ce195d9a4d65f935d9b4bd4f6ad93a85 Mon Sep 17 00:00:00 2001 From: Daniel Abraham Date: Wed, 7 Aug 2024 14:52:03 +0300 Subject: [PATCH 13/33] Fix flowchart --- task_chain/README.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/task_chain/README.md b/task_chain/README.md index ea3f3e6a..c2441bb0 100644 --- a/task_chain/README.md +++ b/task_chain/README.md @@ -18,14 +18,16 @@ flowchart LR task3a[Task 3] task3b[Task 3 retry] task4[Task 4] - error((Error)) - success((Success)) + error(("`Workflow + Error`")) + success(("`Workflow + Success`")) slack -. Slash command .-> task1 slack -. Retry button clicked .-> task3b - subgraph Workflow 1 - task1 --> task2 --> task3a -.-> error -. Retry/abort? .-> slack - end subgraph Workflow 2 task3b --> task4 -.-> success end + subgraph Workflow 1 + task1 --> task2 --> task3a -.-> error -. Retry/abort message .-> slack + end ``` From 2df79f6acf3e733123fafd391fbb743e7213b459 Mon Sep 17 00:00:00 2001 From: Daniel Abraham Date: Wed, 7 Aug 2024 14:55:30 +0300 Subject: [PATCH 14/33] Fix flowchart --- task_chain/README.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/task_chain/README.md b/task_chain/README.md index c2441bb0..6668f9fe 100644 --- a/task_chain/README.md +++ b/task_chain/README.md @@ -12,22 +12,23 @@ This project demonstrates running a sequence of tasks, in several ways. ```mermaid flowchart LR - slack{Slack event} + slack{"`Slack + Event`"} task1[Task 1] task2[Task 2] task3a[Task 3] - task3b[Task 3 retry] + task3b[Task 3 (Retry)] task4[Task 4] error(("`Workflow Error`")) success(("`Workflow Success`")) - slack -. Slash command .-> task1 - slack -. Retry button clicked .-> task3b + slack -. Slash Command .-> task1 + slack -. Retry Button Clicked .-> task3b subgraph Workflow 2 task3b --> task4 -.-> success end subgraph Workflow 1 - task1 --> task2 --> task3a -.-> error -. Retry/abort message .-> slack + task1 --> task2 --> task3a -.-> error -. Retry/Abort Message .-> slack end ``` From 61c05ad1a3d3c547827b21023723ae7e39d80e17 Mon Sep 17 00:00:00 2001 From: Daniel Abraham Date: Wed, 7 Aug 2024 14:56:07 +0300 Subject: [PATCH 15/33] Fix flowchart --- task_chain/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/task_chain/README.md b/task_chain/README.md index 6668f9fe..dbe7b6da 100644 --- a/task_chain/README.md +++ b/task_chain/README.md @@ -17,7 +17,7 @@ flowchart LR task1[Task 1] task2[Task 2] task3a[Task 3] - task3b[Task 3 (Retry)] + task3b[Task 3 Retry] task4[Task 4] error(("`Workflow Error`")) From dfa7c044ccaa481eb227abd11f47f3f534530bd7 Mon Sep 17 00:00:00 2001 From: Daniel Abraham Date: Wed, 7 Aug 2024 15:15:29 +0300 Subject: [PATCH 16/33] Final text tweaks --- task_chain/README.md | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/task_chain/README.md b/task_chain/README.md index dbe7b6da..2f71015e 100644 --- a/task_chain/README.md +++ b/task_chain/README.md @@ -2,13 +2,17 @@ This project demonstrates running a sequence of tasks, in several ways. -- Single-workflow approach: - - A single workflow runs all the tasks, including retry loops; it handles - Slack interactions using runtime event subscriptions - - ["Basic" mode](./single_workflow/basic/) - ... - - ["Advanced" mode](./single_workflow/advanced/) - ... -- [Event-driven approach](./event_driven/) - - A single workflow runs all the tasks, except retries +**Single-workflow approach**: a single workflow runs all the tasks, including +retry loops; it handles Slack interactions using runtime event subscriptions + +- ["Basic" mode](./single_workflow/basic/) - explicit specification of the + workflow's steps, each step is retried in its own loop + +- ["Advanced" mode](./single_workflow/advanced/) - a single loop iterating + over a global list of all the steps, and handling all retries + +**[Event-driven approach](./event_driven/)**: a single workflow runs all the +tasks, except retries, which branch into separate workflows ```mermaid flowchart LR @@ -24,11 +28,12 @@ flowchart LR success(("`Workflow Success`")) slack -. Slash Command .-> task1 + error -. Retry/Abort Message .-> slack slack -. Retry Button Clicked .-> task3b subgraph Workflow 2 task3b --> task4 -.-> success end subgraph Workflow 1 - task1 --> task2 --> task3a -.-> error -. Retry/Abort Message .-> slack + task1 --> task2 --> task3a -.-> error end ``` From 1b9cc8fe1f228391ac87655bddb872732b729875 Mon Sep 17 00:00:00 2001 From: Daniel Abraham Date: Wed, 7 Aug 2024 15:21:14 +0300 Subject: [PATCH 17/33] Tweaks --- task_chain/README.md | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/task_chain/README.md b/task_chain/README.md index 2f71015e..3af6d431 100644 --- a/task_chain/README.md +++ b/task_chain/README.md @@ -1,18 +1,19 @@ # Task Chain -This project demonstrates running a sequence of tasks, in several ways. +This project demonstrates running a sequence of tasks, in three ways. -**Single-workflow approach**: a single workflow runs all the tasks, including -retry loops; it handles Slack interactions using runtime event subscriptions +1. **Single-workflow approach**: a single workflow runs all the tasks, + including retry loops; it handles Slack interactions using runtime event + subscriptions -- ["Basic" mode](./single_workflow/basic/) - explicit specification of the - workflow's steps, each step is retried in its own loop + 1. ["Basic" mode](./single_workflow/basic/) - an explicit specification of + the transition between steps, and each step is retried in its own loop -- ["Advanced" mode](./single_workflow/advanced/) - a single loop iterating - over a global list of all the steps, and handling all retries + 2. ["Advanced" mode](./single_workflow/advanced/) - a single loop iterating + over a global list of all the steps, and handling all retries -**[Event-driven approach](./event_driven/)**: a single workflow runs all the -tasks, except retries, which branch into separate workflows +2. **[Event-driven approach](./event_driven/)**: a single workflow runs + multiple tasks, except for retries, which branch into separate workflows ```mermaid flowchart LR @@ -30,10 +31,10 @@ flowchart LR slack -. Slash Command .-> task1 error -. Retry/Abort Message .-> slack slack -. Retry Button Clicked .-> task3b - subgraph Workflow 2 - task3b --> task4 -.-> success - end subgraph Workflow 1 task1 --> task2 --> task3a -.-> error end + subgraph Workflow 2 + task3b --> task4 -.-> success + end ``` From 9128a1ff49f41285f1ff65cb38f7effeaa78bf3a Mon Sep 17 00:00:00 2001 From: Daniel Abraham Date: Wed, 7 Aug 2024 15:25:39 +0300 Subject: [PATCH 18/33] Flowchart tweak --- task_chain/README.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/task_chain/README.md b/task_chain/README.md index 3af6d431..063818bf 100644 --- a/task_chain/README.md +++ b/task_chain/README.md @@ -13,11 +13,14 @@ This project demonstrates running a sequence of tasks, in three ways. over a global list of all the steps, and handling all retries 2. **[Event-driven approach](./event_driven/)**: a single workflow runs - multiple tasks, except for retries, which branch into separate workflows + multiple tasks, except for retries, which branch into separate workflows; + see the following flowchart diagram: ```mermaid flowchart LR - slack{"`Slack + slack1{"`Slack + Event`"} + slack2{"`Slack Event`"} task1[Task 1] task2[Task 2] @@ -28,13 +31,11 @@ flowchart LR Error`")) success(("`Workflow Success`")) - slack -. Slash Command .-> task1 - error -. Retry/Abort Message .-> slack - slack -. Retry Button Clicked .-> task3b subgraph Workflow 1 - task1 --> task2 --> task3a -.-> error + slack1 -. Slash Command .-> task1 --> task2 --> task3a -.-> error end subgraph Workflow 2 - task3b --> task4 -.-> success + slack2 -. Retry Button Clicked .-> task3b --> task4 -.-> success end + error -. Retry/Abort Message .-> slack2 ``` From c3704bf996acc935b7b5e9a79f178f3f3055e26c Mon Sep 17 00:00:00 2001 From: Daniel Abraham Date: Wed, 7 Aug 2024 15:28:55 +0300 Subject: [PATCH 19/33] Flowchart tweak --- task_chain/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/task_chain/README.md b/task_chain/README.md index 063818bf..49c37d3f 100644 --- a/task_chain/README.md +++ b/task_chain/README.md @@ -37,5 +37,4 @@ flowchart LR subgraph Workflow 2 slack2 -. Retry Button Clicked .-> task3b --> task4 -.-> success end - error -. Retry/Abort Message .-> slack2 ``` From c8506293d6b5181274b39535a3b00131e06d5384 Mon Sep 17 00:00:00 2001 From: Daniel Abraham Date: Wed, 7 Aug 2024 15:32:07 +0300 Subject: [PATCH 20/33] Fix flowchart --- task_chain/README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/task_chain/README.md b/task_chain/README.md index 49c37d3f..da1930b4 100644 --- a/task_chain/README.md +++ b/task_chain/README.md @@ -17,7 +17,7 @@ This project demonstrates running a sequence of tasks, in three ways. see the following flowchart diagram: ```mermaid -flowchart LR +flowchart TB slack1{"`Slack Event`"} slack2{"`Slack @@ -32,9 +32,11 @@ flowchart LR success(("`Workflow Success`")) subgraph Workflow 1 - slack1 -. Slash Command .-> task1 --> task2 --> task3a -.-> error + direction LR + slack1 -. Slash Command .-> task1 --> task2 --> task3a -.-> error end subgraph Workflow 2 - slack2 -. Retry Button Clicked .-> task3b --> task4 -.-> success + direction LR + slack2 -. Retry Button Clicked .-> task3b --> task4 -.-> success end ``` From a00641c63faf702dbbe3f7b483e498542d74ad10 Mon Sep 17 00:00:00 2001 From: Daniel Abraham Date: Wed, 7 Aug 2024 15:39:18 +0300 Subject: [PATCH 21/33] Fix flowchart --- task_chain/README.md | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/task_chain/README.md b/task_chain/README.md index da1930b4..7eb8c257 100644 --- a/task_chain/README.md +++ b/task_chain/README.md @@ -20,23 +20,28 @@ This project demonstrates running a sequence of tasks, in three ways. flowchart TB slack1{"`Slack Event`"} - slack2{"`Slack - Event`"} task1[Task 1] task2[Task 2] task3a[Task 3] - task3b[Task 3 Retry] - task4[Task 4] error(("`Workflow Error`")) + + slack2{"`Slack + Event`"} + task3b[Task 3 Retry] + task4[Task 4] success(("`Workflow Success`")) - subgraph Workflow 1 - direction LR - slack1 -. Slash Command .-> task1 --> task2 --> task3a -.-> error + + subgraph w1 [Workflow 1] + direction LR + slack1 -. Slash Command .-> task1 --> task2 --> task3a -.-> error end - subgraph Workflow 2 - direction LR - slack2 -. Retry Button Clicked .-> task3b --> task4 -.-> success + + subgraph w2 [Workflow 2] + direction LR + slack2 -. Retry Button Clicked .-> task3b --> task4 -.-> success end + + w1 -. Retry/Abort Message .-> w2 ``` From 8cead8380bb66cf07e6efd19a9d66abdff465269 Mon Sep 17 00:00:00 2001 From: Daniel Abraham Date: Wed, 7 Aug 2024 15:47:14 +0300 Subject: [PATCH 22/33] Flowchart for single-WF --- task_chain/README.md | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/task_chain/README.md b/task_chain/README.md index 7eb8c257..2b3cf316 100644 --- a/task_chain/README.md +++ b/task_chain/README.md @@ -12,9 +12,32 @@ This project demonstrates running a sequence of tasks, in three ways. 2. ["Advanced" mode](./single_workflow/advanced/) - a single loop iterating over a global list of all the steps, and handling all retries +```mermaid +flowchart LR + slack{"`Slack + Event`"} + task1[Task 1] + task2[Task 2] + task3[Task 3] + task4[Task 4] + message{"`Retry/Abort + Message`"} + error(("`Workflow + Error`")) + success(("`Workflow + Success`")) + + subgraph Workflow 1 + slack1 -. Slash Command .-> task1 --> task2 --> task3 + task3 --> task4 --> success + task3 --> message + message -- Retry --> task3 + message -- Abort --> error + end +``` + 2. **[Event-driven approach](./event_driven/)**: a single workflow runs - multiple tasks, except for retries, which branch into separate workflows; - see the following flowchart diagram: + multiple tasks, except for retries, which branch into separate workflows ```mermaid flowchart TB From 1bc0789796cc96ab11ec52d3c71300f54c435f61 Mon Sep 17 00:00:00 2001 From: Daniel Abraham Date: Wed, 7 Aug 2024 15:49:21 +0300 Subject: [PATCH 23/33] Fix flowchart --- task_chain/README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/task_chain/README.md b/task_chain/README.md index 2b3cf316..27f51cc4 100644 --- a/task_chain/README.md +++ b/task_chain/README.md @@ -28,9 +28,10 @@ flowchart LR Success`")) subgraph Workflow 1 - slack1 -. Slash Command .-> task1 --> task2 --> task3 - task3 --> task4 --> success - task3 --> message + direction LR + slack -. Slash Command .-> task1 --> task2 --> task3 + task3 -- Success --> task4 --> success + task3 -- Error --> message message -- Retry --> task3 message -- Abort --> error end From a10882ec42e30a5b3fbca1d0d8acb9d609541e5a Mon Sep 17 00:00:00 2001 From: Daniel Abraham Date: Wed, 7 Aug 2024 17:28:43 +0300 Subject: [PATCH 24/33] Fix: don't forget i after first retry --- task_chain/event_driven/program.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/task_chain/event_driven/program.py b/task_chain/event_driven/program.py index dfc3f0d0..ea5c1c0e 100644 --- a/task_chain/event_driven/program.py +++ b/task_chain/event_driven/program.py @@ -40,14 +40,15 @@ def step4(): def on_slack_slash_command(event): """Use a Slack slash command from a user to start a chain of tasks.""" - run_tasks(event.data.user_id) + run_tasks(0, event.data.user_id) -def run_tasks(user_id): +def run_tasks(start_index, user_id): # Note to the interested reader: it's easy to improve this project # to traverse a dynamic DAG, instead of a simple static list. for i, task in enumerate(tasks): - run_retriable_task(task, i, user_id) + if i >= start_index: + run_retriable_task(task, i, user_id) message = "Workflow completed successfully :smiley_cat:" slack.chat_postMessage(channel=user_id, text=message) @@ -77,7 +78,5 @@ def on_slack_interaction(event): return # This workflow's starting point is a retry of the failed task in the aborted workflow. - global tasks i = int(event.data.actions[0]["action_id"].split()[-1]) - tasks = tasks[i:] - run_tasks(event.data.user.id) + run_tasks(i, event.data.user.id) From 2e1c9baf3228547dbc77a411f9a77493e72a4c02 Mon Sep 17 00:00:00 2001 From: Daniel Abraham Date: Wed, 7 Aug 2024 17:39:04 +0300 Subject: [PATCH 25/33] improvement: step3 can sometimes succeed --- task_chain/event_driven/program.py | 4 +++- task_chain/single_workflow/advanced/program.py | 4 +++- task_chain/single_workflow/basic/program.py | 4 +++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/task_chain/event_driven/program.py b/task_chain/event_driven/program.py index ea5c1c0e..94b9ffaf 100644 --- a/task_chain/event_driven/program.py +++ b/task_chain/event_driven/program.py @@ -11,6 +11,7 @@ """ from pathlib import Path +import random from autokitteh.slack import slack_client @@ -28,7 +29,8 @@ def step2(): def step3(): print("Step 3 is doing stuff...") - raise RuntimeError("Something bad happened") + if random.choice([True, False]): + raise RuntimeError("Something bad happened") def step4(): diff --git a/task_chain/single_workflow/advanced/program.py b/task_chain/single_workflow/advanced/program.py index 36811173..e7b80b09 100644 --- a/task_chain/single_workflow/advanced/program.py +++ b/task_chain/single_workflow/advanced/program.py @@ -5,6 +5,7 @@ """ from pathlib import Path +import random import autokitteh from autokitteh.slack import slack_client @@ -23,7 +24,8 @@ def step2(): def step3(): print("Step 3 is doing stuff...") - raise RuntimeError("Something bad happened") + if random.choice([True, False]): + raise RuntimeError("Something bad happened") def step4(): diff --git a/task_chain/single_workflow/basic/program.py b/task_chain/single_workflow/basic/program.py index 10025764..866287e8 100644 --- a/task_chain/single_workflow/basic/program.py +++ b/task_chain/single_workflow/basic/program.py @@ -5,6 +5,7 @@ """ from pathlib import Path +import random import autokitteh from autokitteh.slack import slack_client @@ -23,7 +24,8 @@ def step2(): def step3(): print("Step 3 is doing stuff...") - raise RuntimeError("Something bad happened") + if random.choice([True, False]): + raise RuntimeError("Something bad happened") def step4(): From 5d9a42ac6d72e36dd4231f3bbd91cfb6f4e1439b Mon Sep 17 00:00:00 2001 From: Daniel Abraham Date: Wed, 7 Aug 2024 17:48:14 +0300 Subject: [PATCH 26/33] final README improvements --- task_chain/README.md | 16 ++++++++++++---- task_chain/slack.png | Bin 0 -> 80819 bytes 2 files changed, 12 insertions(+), 4 deletions(-) create mode 100644 task_chain/slack.png diff --git a/task_chain/README.md b/task_chain/README.md index 27f51cc4..ae8f4819 100644 --- a/task_chain/README.md +++ b/task_chain/README.md @@ -1,16 +1,24 @@ # Task Chain -This project demonstrates running a sequence of tasks, in three ways. +This project demonstrates running a sequence of tasks with fault tolerance. + +The workflow is resilient to errors in each step (with the ability to retry +each failing step on-demand), as well as server-side failures (thanks to +AutoKitteh's durable execution). + +![Slack screenshot](./slack.png) + +This directory contains three variants of this project: 1. **Single-workflow approach**: a single workflow runs all the tasks, including retry loops; it handles Slack interactions using runtime event subscriptions 1. ["Basic" mode](./single_workflow/basic/) - an explicit specification of - the transition between steps, and each step is retried in its own loop + the transitions between steps, and each step is retried in its own loop - 2. ["Advanced" mode](./single_workflow/advanced/) - a single loop iterating - over a global list of all the steps, and handling all retries + 2. ["Advanced" mode](./single_workflow/advanced/) - a single loop iterates + over a global list of all the steps, and handles all the retries ```mermaid flowchart LR diff --git a/task_chain/slack.png b/task_chain/slack.png new file mode 100644 index 0000000000000000000000000000000000000000..47ca2bba3ecbebfb1703468a3037ba6d8f2bb949 GIT binary patch literal 80819 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 z zw5qQOfWiqvMNJ(V5k{+s#m&P52Yc;vE(dpx3uZs?eLxY-HQ z5(SJK{=p=AESIX4&Vp{c&&?oc=;&3R8&|0+wgd!w5TB>$xa>L-)77mt7#J8R-Mh$) ziyc4npL5a4ql@1nTCEwH{tvu3p|z_9@-M*Hbh8^bq|#rZ6iRm{asq=*@_^>xfRw@x z88X3ow>Oy{9ZccWvW+=|#!n4d_)2drDJL31__HqtAP`e!%Y}H@K(mU=W2~s^8t^F+ z3=ZK0JTD;_m~qNwk9=%wb&^!7s<8BG`+s%$LFbdn5)oZ!u5bt$&fqaJF&TN__qZZj z7P;w#y1!d6s-QF*|DZ-M+k}gqP_~~fi35GAAP1PmWxjfIF_12L}&B@Q@d|AE1f~UCoyPk z4rh#mkp@63c@=FvQHE=KTMdqVInmM4^ES;^15;MOImtTAeIp^s!QMWJ!D~ZE8C$21 z+48!wm)K3@jjqXHa@$b_OgRN@L}K}eI$dvDTU($RtlpqymQF9cLqw|t5;y|>$6-8{ zdT6tJ@CkFefym`D$NEMrNzx^KfVew-Z)aH{^INDox7*mO-okY5&YAFYnfP z$>?-(jfHfkWcC2(#D8joQ9s=TAZ<> z7p?@KItT523FTdQsGL$N(Py0ESH{876g6-j?>=d+Ah?}bUm;F@{Tgw3L9JA_gwW>g zZO|L}!WYaN-4fc)Jpf4_8dAIMFX3@HEWL}a-0wvF01u&zGyC}~@cChZU=sYe#9ld{Q%PBQSm&CRL=@7YYIeO}!w7jp%BM|--Cm`i;Go+YySggFf0rJG(&}+} zuDJp#?fhr^HCv3Dw%T_t57icXQ}mvAJ<+88smn`xok2ia1O-v9P}>WC3(;-h;d|IW z1AsU98u7*tE3!;$)Xf`jy_J+D%FalZS!r15EC;vc?o(O}dQqm0seBIS8;k~&A+E?+@$&4b|r;` zz9`ZtS+E9uMYMH0*VU}Y`TbJMR>!Qns2KkpwwRh%VMq!Hx0-F{ z+u}xwT0Jgq^Q!U*q(ONW$`^dQ6BDcr{Bq(hM>q7$%*-@2)p_sMLso#Jpg4#1?dVwr zsLy3^+I{(yJ9=|_n#Qkx&E);8#OrggNlG*brVc=(jI}7r$tk}H8SYJ!A;)1boSc{t z%Nx5ZSlU`UXgw&%(h5_;&zm$|ec8=_xlISTcI%BC;nSJEd>t2t3$eAGP~BTH&Fyi% zF^`EilIo{{g4l3%;=~Ou7up!#M+M&%1=8K@{20XpWxs0*4YPzrQBqty`a8$=KBq_R zmFmTUV!k;Qj;aO8=>puX#Z973dU=V^?EDxGe1f;FN0bqhf;tPu{3`l31JdxXUco?0 zCf(P?N10ezsSithmTKNBr-q>6W2`2M@v70+-E+yVzi0Jua;lp&e+~5ABw5(j zfo^u1Z@Zc31~?QzeL6BC^dw!7GU1p452NTi#faSMTXj%P2@bIxX|KL8 z`ly#p>Iuv+Nb^`fJWzSFya`~6xhHC=o2#sp<$r<%YGMN_D@R@1{+xM{Rvj=GlVLPe zbDk)S$^8^D*w^>qu-pbjkckNiY)u_9e2<0YT^s9tF3Vo+TFT51Ig|PY`cP`jJzHVq zoj;ML>Z3d;v7;l~$RINg)q=EWh|%dr#6-D>=l1-w!`K>AheejM#fqvpM$j#=LHJkJ zqMgkW#02|RPJcempZA_wS!u3(`zFx#ZS`xEG72I}G2^6Z%X)roZTW_jt(dLEQmRky zCy$^rAA4ozS`jt1Mvz)vOtLi~K>2w}OtyJp-sH1HkOi2srG82Mg}vS=3pqYJ)2QE{ z+&p#kiks=^5P&c#Dzh)oydVt-g{@0SQvYBo@FeID=X5wxbi;*8$ay@IE^)Q|Jc@h4 zLbLPo((!ukwq7l?nvJ9Ccs)dHO}>Bowi5__dwUB&m?<2*^te~iJl|H&#(sNvWaRMD zBiJ;MF?>u(k>@hAXfDBQnBKyxJwc2gYMI;V&)M*a;(spWjWxIpg|A`V^er! z`WB~ICl<~TeWZ1$*SsLCerKGqzEepmcN8L!H#+krerM=Omz8bFGH=YZnDNip+P$-Ft z=YyBjAxz53t1d5u;4%By;?YR1ej$xWkYl6`C3>&_t}^JAxX63`Qdly|w2f(bsC!{S zMcYfNNRfi_5|7hXK-02R;LQ)vPuZIvnvbTMhwjH#DUkJ)+ipIos?Hch@x^Auff7_> zeZ?7LN?q@17$xQJU}pvM_5Ci`3Iqi0BCgG=r_vV1(NxVb!FR9_p6TCgqq@$xgOUCC zSKatShk>x_ZdzvT8o?_wx+@Buo`i&6b{2i3yc*4fbvZe!AtA?!6H!>$uczQpr0neE z3|2mAH4Lu${Jj}jTH=Gq%F8cE>W$>xLyJ?Bis%$CR~d-TFQ3bMdmAP(#0w!MDa+}} z(j?F%Aht802_=h_ClnTz1HlET0rm9-D_6J;IKj&J__P~qn=<18K%mCsD)XN`T7hxG zCuEY%6fsDLB|9USy)-O<%J?fzrib+~=2>{c0n?yS_Ro_`n;s`PN&j5(T!VPMrJSXe z>TQ9(g;x}_Mk+3H?CJpbg`pG5!9;9UCcbX!Q?nH z5)}e}b#j6ZA25U}ndDN`R#8!5lN;LA-u6oLG4HR*j66ycq{!eE-~2Ln{UUs6+3 zjVjtlCwy0jc)V^W0KNz5n4i~pgU0SHtfN}%d4nikB)xUE&w_-PXjO5+p|(9`z=rCr zRBfse`g1?}Yw{gNg7w+V?w+zHiOUwHh7BAfku>J9EUM8z*AQa6o-U~I$_<&?{Uj4R9WAf!CJ?0NfYdphdK-t+MOW^;?z z=Mnmuy>ok0*Ew#^p!ov=e5U|q6^cG3%ce&HJ~YbeyH=ShRhJFM^Wa~PcnrL3b4RzQ z45QF6#&boHaL6#ipn&7Tx0JMt+VgX#y*7yNOmcDxOMcy55V?_>Pai9kz_+=FQ(3EQ z&jA%3qqxsh&4Zar=0MUldOB4mU|D%QC2fy*EPT7MiJ#&4#XDmIQn?n;=+$twMZ{B5 zQUdk2y!kM8U{Unz_|5H$7gG_x>~|-M&H;l>_jfeu&xlpKrW3m6hsqqq6MTX_pQvSlb||uzUK8Dbyq?iu7^yB?XYOLx624 zW8IwB(ZPa}ygW2y{4lFnkzF2VoRmzcWRlaz31yqZ`#!_^z}f%Hm(5`>!uHS4U3-q^ z-8(qQ{r$cB)!|0^Hp$=i^NsGzhA3c|HFy1R%jH0P=8TuvY$EjQ&%6zs@53D``;#^S z$HVco&K=a>VV)zxKkYsx(>Jr|y9g)DfrUQ<1v{cOxci~r6b!a57W)61)klIz9_IZ` zt2n(^EN!?yrLJ|B3G9{*7NO3k>|ade{T4Q3mE$3&@ZEKXlL+GJ{cWM{%r?Fq4bopi zv~}SO{r9F~GCU#ZVvhqNAmIBn$5zrTDth)p(Z130*EJ8n=Tk;P$&w>+J}Uoxm$eIg z;IGLNWnht_lPwGFtI2S*T(P{XWP=ze6x@087)+uw&SG_c&9gP^#mfXZjj+)55=jgt zOPc7|*e@ac)=T!?r;X|R=?DBz$PlkP%5vAW3x*i2>wD6q0l4#{cH@iw*8@pIUY_-P z5{O7hH$4Q^Sz8D~oqqxc@NAf8@c%N|!{U2R@BUSwFIxgO`PhqES2 zZd+v>iR}y+64xIyxV$#6Lop#B|2Y12HWC;Z$U;YekIinqKl9qAWw>4^g+yrkHt;}f z&b)V6>#b-cuu=)bX^l@wF=JA^z1`(@In)H)JlDPf@Yi*2hos+Pp(4ycOa-!;ht=+d zuU`@Q`P={g)rD{ZS2>PlZsjsjY#r7f7xSFW`tq;m3;4N#NR#l*w-U98m$Hc|BmqM^4|n&cujr($n;J>4(csnKEi93EJiDcX82AglGx%9OF;tvD*bBly&a5*P1%)$> zPEpMJlisYg-sL`~!Rr$j@Y;wxXFn+^P4-CfLplJU$bbDe7o>S^9vM@v+(YtRN2><;C8){$p0%oI168+QdfK##r+AonWbKigb*v|VX zLF~4^B2C0|3KNYhm0vdReS0~7p`?@#b|1)%1)t^F$UA1{{AGSN5a|jBquh6$o}Lb+ zHCQgzw^BqUG)zpjwVY2*C$+9_ZC#Bajqty}`aHcdqG77gWF{8>mQ-?zMRJo{^QP$6 zoXnL<<}}AxDI44L?O+te2+GyrI_=@QhDv>wnyiMU`5*E3)B{bH1&=>9*r2q3$-Q?< z8tljKP0a1lVO}WF^2CBB`M8Lus$Xlvr{A)QX*HL$czFHSKML4U7f7ZoR0+dXsg^32 z95{Ob7m%p5h9415iLtTVdoi;h(Ks%um#w9k$^QBSx!^{e)0n_a-s+$J-Z<1#?Tz+x$ zZa#;~Z{3!hw%1e}*4P*|lEJ@KC8}>=0A674v(=P@6wm3y6~TeChPb%7{;Jfq*Oxy& zcnF9Hy{&&3Cd})GRZN&u#Kq6kJ4a)0T3hP?Lnc$$zd6?H4nK<0SG+|DU=)oX;9~O8hqyxyqdt zS-oBtR5bm97&%8~Qdea)j!_+96O@(aJ;ip4axomqYa^M|tI$kZ0Ell@kaq5G;7`}Wh9A})t0QaM zN+O;jnJ-rYtVUWE&0i4-v1lyHS7^|M6cH)f zF|B=t&Dhh1IJ$z~1pIk@sG_88zJSC*EMZk9Nr@RMf>G7=(=M{!2_&g#LZIZRT!xPL z0z2$u#q?T=FPhLa65ZQIy@c(HHtq~ny2~lkM+d(_ed?c_U%L1*CvW)KTkaV%c*8+-~U|>HKdE0?q+XDoOsl5lqw1zko#K z`4@Ohgy&zFV&43Z{V73k^WXi!`0_vY|M$WF-v3_*qy20D|F-`B&5Ol8A^$=X+V$>e z^#d2uBfELGYF+pG+kdzK@KF77;!qGOQ3T`X+bT3tO-RDO5^C;7M~qn+yCO!-WL9;c z8BvzEHo*M_hxL5tY%X}O{`thT?L>;A_uW|}3(%o`v&Y`=7wy{%(?7lYXD1j7t2x>j zG>9rw_x!Y|VG{g4hTkVz*Inz3Gnwax0^KNL4PKZt()p;c#iS7XJ9JF^>(6R5dhd`G z--#4+Ml#Rzzy8;LLx7Yfv%DuP5?}yNDgdDxKzmrfTK?&oedFdqk7Q|2h_t zS~d+7{>?;}O_&#t2-`(!=;iR=!Jrej5wa z?G~-?TI=Sb_-;F#`hkOdv)e%86us0&-r*D*GcRuoctS8_HO$f}mkgQLsFz`vOq$op zMne1c8Qz|jR8)*RR7e=&1Xa>!E&rSy$@mbQrS=>r6QGgmy7*Q!oX4DSM^~2mR?V6T z+BrSweD+nQLt|3>#m70d)yp5@)@}R??NNQkJT#PJDE-EFFCN@cqeB)QEu+mn1Sz1R zt@=A~+`O-N{j&4^1yUGdSZZ>L*F{3!aEeZ@LQ9v0lS1>Xj@7_xA zy8X@Tt%<#hX&W-PwF@J%n8J-S0;&Aw!zMWXdiZP~`qDZx2{KX$lS^!a(9bypJrNO` z$|Yt!nW$_Y59CE)Xus(0p8y}4ffgE`!qE)}nbWq3OZWWU>iBcs<34~VE!F4vuU|QW zaIUfpm}c^g52q`#Gzg2z%09U7cR4wVWO`ht+{g@Dd?tJzokG`xX6%qxIPs@HvYAx| zeZ^B2pn`)YHK^jG!#1yy4eKVwdLIv?EKnGN=TM@OWm-{x1v|`0^?P8zAq|%VXL;hD z^H1VPToF0e;Yv_JEIzPCElbR86uRO{@yEf4=b+k{HBR9 zl9&f%yJ!d>F+vT8_eFuxR-g&vKb>0c5?^8;g*!j1UdE+SSRerUmt8#MEjC6~VfoBw zGW{+xAz#`4Dro(+-o$?2?ary|qT0nyhpGyISD<5t6&2nZ4E zY+{lveJn9RMYrR~SFXSr$&()I+)5a){Q*-^JZ~=^^xn1Kqq+AZiF4|4eX0ry9xz#n z{P)NHKV@epbm)}{yzSA!SZGZZ;JYaJk?bT+!BJ!oBhd~!EhHdZM7}|SLf=oegOkLp zvl^CsA2ZI8pM*8Vg3iiqW~i}d3&1+8_z`?@u1c>nq5KeIHpvnFs ziNQl5(n*l7-ZEpf*&%>p$p%#?MkK`}_lm(9+i+klN*?P?w8!1l57jHmH^>8*JLAox z6aXf1Je=sW(r*z>kg^}k-rN2W5X4^C2Vm$f2QWUBzg7KY?*uQrkAnX_?gQ^su$XF) z5mniqpfI(OYLA-5TWpp9(s+9Tc!+FdH60AbZ3orjRXc$L(%b|lC)dp%;6JKW07#Fw zaM#Vwdl83ITCme z%*41fkHdw=PXzgpj#4#LGd6XIEhiy0HFf*LBOJu>VD93v=n6PsD=Xs0qEh(WpA^u~ z?*9Gz4S3DDTeM~0!METzTFBJuz6w4PHLaP5>BTEdn0}W9C0#6zbt=BQkB!tkQ`_+1QSJSk!(;B4w+6oG5 z?7pI!mivqhq2yII{xoUv@e@m}j2yfBX){}ZSM1#S^+$J7diuiZDp?X$PdEXK@$Q6& z*0N&BWKeMMD+t6F0H_ViZp#-GElaKL09-udU$!5hhl`Enaon!-oGpR&gFv96??D#3 z94nGDWvbj#wJ@-E`p1f}_rt}YgWn?*U`$@7>lBQ06%>5`UeEjdp?=`odf%Y^N4+fZ zC`3_9>jC6V_ooAl!*V-_VPEeqr3_~W{1d2^irFld?7eQbW8NM%Us-QeJlrm(X2iw0 zoaF5BGPWGISny=-S2$FRa_w*Jt*o+o+l`D5>_eA3)WQ4x#8qTc#$ zXP~03*lH%VU}MjJnIC>}rgCc2+!-500+)xIY~}4Zuiw*2fOtfKe-QqKuArih#oI)t zzm}hbe3?AoBdl}{9=8>1=ugHAm3TnUTPlw*hh7JHx!h4wa{JV)my!6KhVK0-M@L5o z7**1Exaiwhpfny(anWgKD_Qc~&VFh%dZU7XfI!mnG+epTnL5x8eYx4ym89(&8TGcM zzrR1x@)Xm-xEWwt*O$$&z;jxdTg;uHMYW$rUM+de(?|Y@9oTR%=D+PZH3FtFS@KFo z+;%xXqv@;OzqhWiFX4L|a4s%p8zyKy^cA&n|H-0QVJi}KFnP1(emY5sb~B2HKR%;+!yBhZT+al?>d|BJNMDi((-^Z=F?fFp75ge?S=b86u)(2bViv{iA`Ih4R9Yw z_t95#KE#yaeSh?Mc*Qg)x$7aGmcI2D+QpLkK_@EzI(J@iv3Yk|$u->hOljhDVk-mI zS8b1r4Zv7$E?oMGvKj;^*t7uijs(;h>NMX6ZKVacR0 zH;(Suv_1?25WpC*ocA3-fa>>WCWkJ!OM?|@5;P1KT1{-c1@&xY|AwG`Xp=&>q)v^ykc|*@V8)KoUEvo2NyNkqr`EZe>t+VQ`FkfX5T$L+oHQQ9S zlS9b>CQ`5t2Z$Q5Xp}Y+=HPfAuL%Q%R=ABWQX4MZTlcWihRmx}@ujOguvu8o#C|mw zNZQxCta!B@h5@DCq?V3MI%jlzt@DNWG<2pYi5n*c+mLbH_5}sN92>DwoR08!B*_sz zVDc_Ylf{U9avB=^U6|IcHw!?cfuh2~?I`|7Nq%=p$~bj;<%Y$*-HDxXpU0{rA?5m{ zB${@RY+rz|Y;(J7|S zu-s>^&8s((I2G$8M9Y4PtPJ0bEY^-1G&W_iu_cT7O zt*u@^PiLS~s9Bv)y|%tQ_jTNqm5<9O`={+jY77`;3bNdW4@#Zqogl{tF3XKmxu8mW z#9?hOMII3SV`e5F86{?xNI-qEYqG|&9a!T)L(Owk$tct`zA}tW zcExmMwO~sd>W!Rcn?$}c{Sv)C>YZ2IA1~)qp>tJyOi93?*%bc-ZmiC5uV>keFgN5_X^@Fpjp|!2+1#11GU z{9yzEKeS48w2*BD7Yky~&V{DTj_&S{TwIOiNj{+>W7!710YML(v2mz8K75Yb$H}9) z8SRwhT?2;94ay~EW;@Q!Wkmx)pqAwzB|d;(`(kv*kvV11lHFri4Ip#Blnbq2=|X+` z@xyhan9bSaPN(eQ{sEL<=8YyD*hfNFE?~Nijh+oYI5jZCL~=qg!%6-EP6 z*u>aW_oEL^i@wc{hl59X+d)I>8q*=L5MZG$8@>GdhizS*3NFtR0Q)2oZ5rl3c({0E zlIKMnaEqIL{1})eaaCSvtZy+e1qLP~@~0}IE;R9#MAeND5sG)@bQ08g-^(#0=2aM8 zOdARoI^^^caoG~SW{SsThFRP2_n^^O#GI+=m5Ks7)bk&jyg+Igo#f)S5VqFKVs6gB zaRvsY+)t6VL=rIgmxKt&h>p$mY`0XpxuRQx-#R)jM_ze**O>6z(?{Cd%0|z}f4UI)Ycg+E@Qe_KuclW*eUz$ejDdCw< zmh5|VcfRl+^?{McrcBVMtEDurB2*uPyyvSo^V@r@vJ**E#?`H`5b zYF<&$3pH1oSX^8T9_P08orUUO#Yi2-=W&g``$`y8dsMD$tNbaTUvfrbnEqk-UhV{+ zhnyX$E*d2^S&BzwGPI4m_;I7qi75bMZsuNqT2$@jKC&YUx(rFSecPfEm(SxD4W%y{ z!7<<0u^N&H&1d4ftdK*)!!gTA-|%edca9O|oD@nzLA=wi2VD9ncb2U8>M*To;+MQ`WmDl1a+L=$FE|r_M!?)Day)bb1Zp|>isO=sG7-^6h z802K^0Poi{5~~kvY!~)qJF_Jgit!dWhu_;RbZedC$15$W>Ob34$_{ z8M;u%AtXWQ^qL5tj0_nmehq%(TUCG{wJ3Ejq)vI3E)QFxs9W90;G4C3E+bUG9bqq% zfXML-kvh=0EJCf*lvq>c4QY0Ue_8_uhKrP^Fe$7T7!5z$czdft%x7d?L*P4s4ca#f zacgO54EdBI)70Afr+KpP}Ft zu#kj;dCBP`RmA8fF2%oVNw~YUHD9q@RxWz>C%bcc@f`(6!OzbCsVKOFry%`FYTwwB zLI{d&$zrKp{FyGpu0;*0PL%>;UJ~g2ZjWoiFMI9C82w~>5RFQIOFRc)+IBt&vftwM z3NxS>DOg-`2+LUuO(mE`{8ytpsVClgCQJ4JeihqA?DzGTDqS^OBaIhjxF5^|<|S?^ zDcwChnx#+n%}249%a*t2E?+vEld!eBD;C zdY}r~#x8{w%>?2{Eg>TXn{l-Fdbou?(l&9SertsS3^SD%tNk*=a=!0KwjHl#WIgIK zn56QNfAM1`L!re|!?dv9%f;EP6lWoL-n$0PS~?T3edp6=C00hEAo*%Nvlj2NB9sUM z7Vf;lO4HuR48Xo|ln#vuRr{gK_td45Ej!WdQUR)0RKesIbyjnzcU8z8d;e8cAwxkG>02>;z?zY=f{tC_dr<7?_A&X~*=_J=xc zU;fc&X#VFb3;l;h^E&QeW4kE^yoeqa6KNh32`MRuNWEQdQ!jh@v|>x*%nMx>E7{^9 zwi4yCHf)l_WuLo;$f`9mvR@erhpk)XbNFYB&E8->1n}+t4Dc8VxAW=)DY?96e;lZ# zVtyW{df^)whgAyMhd@Kb{m@K{)5`r}{NlM{%zpR?F8(GQ&+6Y_lAC-hZd9={WBfIT z3JuyBx)hR``91yiR_O}1e%`96$gEtr@vL;}Q)Z8fjZQL>_POQQ34r@>Y3FY~`J5#V8GMRz^imz{@Pny;YFSep5B#7~0?@hv z#&&PO<{PFK&$I7a{dk|N!P`ux)8uH@8FaKrscvoo=AO+<%?}VU2?-Z^bNd6Bg;>~G zA%v5Yq5H}0v7S7y*@H-6VpOhOH#Ykw2<^1}X(*lR%ntyy5uetSPfhC7m)-BQ=7LOg z-Ue8UsalNBNbAApF?}!47byKj`i4%J%H^iWE#fhkkb;bzz6KgXt{)u&1sP+Z4GGC3 zwAu{x)FFhD*oU@P;JEoMqD1Qs&7p4RaK8P%B=3Z0QzGf~jDX;jw6Thkx{i&_ruCwJ z{#Y6EO}XU5nwY%&*ivhI-5q*SS&>$|x3K>zh0rrJsjO(vW-u^S)*DIWFtQKrXYyPm z)oQ&w_~bFkK3CdX#`||+*5OmG2hJ=o9=_jmCX57On$PqxK|g^nvxA;$F?2fXG_-sUtxIJmXWRxYbYXzjZJL!1u+i zB?!e_n|nYPe9w1{B$)E7c-2760r@t)cVn{Z3RZXZvAkS+C!KC;><41}=M03lf}!~n zoDsmwK}uMz!0oip>3MzZ?1?14<1o^G4OXsgX49~X%gp548=WnX&a~9;C3bGU+u~#> z)6;vMH&KSl&N@%L-E=&}vD|jOngfyqWi{J1D$U)FXVqy$$fPRLEQCgQ`X+C>bk5sXVoS8< zcg@d2!!fO=TQ)tc$ce-oi(%ukvYrNOMk>_ql))ODZZ{h-TJ*F$#frhf#nU?`j=w)Pl&V~{g zTYeON*JHOgV#1Zq;5)z<^`2{6ENeu7+_#+JG%PqAbMIg6QPO{SSP>=GX!q^}Wf!fx zXcZL|6JulVi;IS+VQ;dU6&N@)q2HmffdOmUwrd9zvlppZ;+D7oP{BFmG1O^9L1th|YXHI{#ep>suo8ias? zEMFM!hI3Y2EO|ZpgN8d}czUGbN8yiJtgMAFv?gZdjl7=Lzs83d{b@}SMbUbyLe#b2 z<=|etfxvdib)utmKt-xYR-9xHosZaQ-+U_%r4#ghC0JPHpFDv|*8L58wkOcWkm>0GaqKI>jnco=r z=ZTz9R~=@GG@|sTbqJ(rP{cn%kMW2j%KCw-|1&o7R6F!}Qj16YW4MQ@X>qMT`yk=> zP`p$|x|L2u3HXiek>HbhjDPLf;>1HMQ9>B1^|1re$s|B6%us+R)0KOiJBpW@8Zpse zn@1?hm1;j%@1*mZ_yqvDo~UQ4pCKxtCtkX@W($*%a#L;P&b=mv zeDRk-;2HAz{}=fC7s`kVz3?LQ3p9+~yJrY;THRaF@63em?K4*LhaYu7tQ>6?4CSQf z939O69Ps}XX8hOH{)K`5e~xMXzrR@ao*%>o>ej@qXc93+k_!91fc166hVLBR6irRz zm~Mw~)H?*BC$=FUxY%#ewhN-$B&1k~UQXOqs`n%d&SBm1In(o&?7Xjz$pzutVcb+d zeR+I;pU`7mLr@}#9Tq6>-f6>3Dnf@{f+Y^DPfNx(aIpTG`97bM2%NK;hLP>??fKQ2 zd`SXg;E?fjQo`K9<*z{6m}K1G)NrLVX@R0ZDj9v&@L-)nnFVLAJJ z>GXFhA-Wi`Jb4Hcenfhw-yI?81ePRugjh&aSop5H664K7)G~kzU!v@D9EHAv=$^zT zp^`{9R$Yyis?`J`6T?El*k4@sb2DW+QN0W(#tcPVlhqHDWL3|*adhI7R5T|s+%F`P z`MlK4%x33p+7*8QLRLBBhmI4*leFZ2}K7r*V zN_aTn)hcz{#PfDR#5-|!q*1d;zfkf#X-q?<4gFK)2O3-iSUQMmnR2k`3QMou)3v!w z3hxepRJu30ALS-y35(k*%nx@S{>a-EwPLz?uF1o2?sH$ z1oWh&HQrPhI6Fro5ObV{F}6FVaav4uf~e}H?}kmOq&W9AqvpY%Xf$5uC-|c1uHdgZ zFdzBEl{=#4<639dulF>qLW_v(cdvPlo>%HR?x(FF;_+^ALduRW*KBp(3^&U>Ljq z-hDa$B=`912b!L5(jSR_EWCr8jZ0qt4>cXu4w^|rY1qgYyO<1je0BB;w@O%ZHKo)4 z;Q~09r>u_8s@(TIo*pSY<$e5aQE(0GilA~tEzy6=GdC0HQDY-{{KB`7oPBTd$!_WM|B-1W5I*i1Nvg49ufPsz#cP7kt4n@NvwjtwAt0^LCZ<3 zD)XdAs|)YmytR6#AFAF%Lr#A%85X+Uv$A#cq_cE?(_rDx_A9Aj?<(u5Ik=*dXFGFT z=`)V`DJ`Kf?JLEaICmQNpuT)cbNhk)yWu)BFK8Hl$hX2D@FTV|QOL5dLgiJ7SgA{H zD{9zgjV|GB1WowmOmwm@bhx_qt~qZ)h>Ph(BaR;QEPK1vi5&YzZZq{_twc*sN(H7F zK_5%hWC;5jE^je0JIjT`xH)$)v{)P36$|S1q}hT-w_`}NTq+l?sxhiLaymDDkbvlK z-#So;xW$defU;tLf5G_H6O8N<(?q+~H2<~3VjspC$P z4ZOXt76(Z-g{^wA+RrS_h8@y_=%p_pEjw;KZjq6=*SsKr1qUvR4l4`?^{DiC3fH zquWL#`{D84#3=9lD6gmOTQCXWx7WRLJ?(P?C0+O;+Pr5^CZK_0DHw4bEko zSEt$2Cm}Msh_}3Of$hU7%`e5iOqN-G!pFgB(0$~E{4r&PpyA-$U8v}2G7z{rM)n!D z6nAoa&ipCa4Wz}8AiiG?2W(9#@+RIweL=yWyKFWf@^T$M%2VdAv-Jif`m=zBS<5W% zTen=KE7aqsWf)Xj!mB=$tRyU)25TIrF$BoBsh$J=VE-mEzz$*~eSebw_<;S}kU6(6 zJ}wRu7wzxb+S=aU-6p|+$w&%-cGtLpN`r%+>&UKA)4EC(NN7%xz#P;BU;+wqa?j&O zo{{#-?eiUlp%xWcU0um2;$a;iu_}H1423PBg;agGn46V;B_iO<4~Yk>-)?OUY@AkB zGDWDj8lL2IGctbg+^%#$$kx-NeWtmFg0htRZOrLcdz}mhul_S^Sio{hx}Wqv9DF$@J! z;*IKn^XY4DPIo~Y#zNa4Y~B~K7|8jD1 zG~FWAF>mSzK6r+<&dpgzppipkkkBYfq+q^aZy3Tt3MpN2fFD$@oFVYBV5HWAPd5KK zEax5Q0gC|j_xHz=s`|#d$$l|kbqGWWdswkk&R3maVrH(%kN#e=3bths?5&mAIsG;S9C^_ntaqfMf(d0s?M7_F4+&qI}Xx7)0M3y>b zbu|fkXB0>{TfB}MsRWk3t?l216(UdA81FCkEJ-mo4j)WZp=qe0ApVVq^U4Lf?yzB; z;w%ia;w5R8%**#~RJtMZ(D7ets)*XPZfOp?DAMY7694KgS;CR{i3kku9dH>%ZqA3( zc6I4=_ltBXN+gVxSg?cHHx-x9a;EWYYuS4*14&Ko{=#Fd3jqMXCTh;NwM7!z+PmrF zy`l}aKY2q%>`y0(IFw5rml%s%CPsMK_!$@uLwiZm&aN?s6t6rlZ<;FFwU&z%dO4O| zi6CwFyL%)YHcr@<$NY{FyBKJHv(nP;PTpnZ7myUu!tYF&?a(ro#P`FQ@I|MlZW79z zjfxTj_HbTa-Wd+>0bRBnRXhMbdA-SUZ#bFH{B}BnfvWF{|JwA(roF+4qOMpO)=u-yLfY`6RBKdkjzOzL4vC-)Ei=NZf;nJud@U?ysHi!B0f0);X|OzhrRof zNqLXD;JOWXQW^SW5<Rr0UKaB06>9bzIvL z^XF!b%F{MCy)S8kKhnOCTuibli_mCn9#o5&z<%Hk+d>}Wp1v{F9tzVK$Vf4;jW=Af zS}H$lZ*ABwz>LVU&yqos6-&M$2$NZ#&tEQ0o*0+-jRE;fRVwqolxIfFwxur4)jUTf zAnI;BsZG4x)FAEv+dKc$RkZZZ!A607yL9WL#Ewk?fg-%Q;d-0MM&+TnoJT`?Lg?@D z&IvD`sf;RRI4>*Fou5dDa4HOBE*Em)5pv=m4?k}&$snF95keLgF zE>vOG{a}R$>W)gbq=otc{ep^vKOWBhWBn;6K^CjK)0hxIiqD%Ls1`qnz}Ap%SDSp7 zbAgK1En+XVzwD#i-9K4gcai43zzgiv1BFHlWNZLnOlaV}2{TTC@fk4EtEaVHBEKU* zdc->kXqCNh`$Pe$2JoZ-m?_F)V^TN4y*!}TaF#@?!hiqc#`ROr%^8kng$y79Jpt9M ziDVWw7S;qQ@BMus(!J6<8fFaOX8o{O_p7kDzt;O9XtTi`$c67Wwm@tN@H`I<=WnV4 ziQyM0lV52p2t`lLrC+PQ#u$@(w_AuwOP*9g)h52Vm*Q8>=xJ6vY$b>4DYxxz!u5|v zm?N+9PH}QaD6Bn6S2EmQoRKjhxpZm%x02Pc?qo8qQdtB~x)q8nk}&J9mC=40q^nV# z{7=)G)Ra}EIZunl$^$dCnm{dPWiF=Iz;g{R##K%qd{GP*hOGsXTSz5X!`6gwMP(C^ zcEDPx8it1J;bvFuZTGLdZ|NHrFwoJ#nq?f1|BJS_V2Y!Apf?-05Q1CK;O+zu1b25y zaCdhI5+Jy{ySqEVo#5{7?%VHg_x}O5YPV{NVrIH#divhJdd_(^{(SKye!Ho4LJM&O zor`D8PqmDoF}xS#WXthe+>RI5Ova_9^nI+EVy20Y)2MB&DLIS@K|rVpezHLLW*+f) zkgo~x-91n$7mA#g^08t?r{P}tmltTP_1wTZ&9~R8QpF)4yH#Nc8+iBxxvTQA+@D}h zXD>yZ5Wna%W^PG?Z7S;@k@!1nzbz7l(0#EZ^}Q>V>k(Y}MH+BVYG`A6VwwH6& z-5p(B*xE0r`Z8IGSr)!K8T>~pEX(I6c-ltKE?AvRl5oK8Y{ZO6eY~-luO`kR(|3K1ds+1nPF zz0|-zq)10B)o*U_E8lImK}n>Z&z}sm4eX0OjlMN}Z5=(+%)2~+m&t_36(cGA=U%Zu ziWT#tzACn|shBhv6Ww!`g`;s))3R3j>VeabOutHgYDJG_?Otr@sytR7y~7K}{AQFH|RtBY!BYCoS(9pe{; zo}Cgz;Uv~ume0E@LlKdY&z$|)PeKto>=BeKwq>z37*rM<5d|srq8qnp^kG3au>Qna zyLC7m^+0|h(cyY05lP?r1mn3PAwZ>~3k7=v=ga5e;{XovesxF1#DF6fFpX|-4}Azz zL2@F4>zM0R*(*08D~tGT`tPjIXV8@+4sZ4dWdU+Cxj>BrPzCxy@i{!#`w14lX+I5&R|A4o^du~bTr9LiSCAW}9Z*aP$3iz*PiAuexD zPx+(Cd_~d$XI-nkmuCI4iKVcMTcxeWlgKrG>xbRhG+z?NKZ@%s3j7SR^}FKr7Kg7J zR6}KNc&Ji_`a$dAM5nat_I3T^I=u`5^a5pSMk^r5DhgzkfF0apMC<(v7A`I>Cgvf_ zyD3nmS)STxeXE_aAA$@F$bI(tvG>br9csi`we2gSd*H~Ei>l*oqGwZO&XjREIPCG$ zVuRk;e%-}C4nBT3v%UTG8jp_NW{fgfV2rIghnw3nuwrzcgc{q=Hsq3Z*!uh@}H8nrOSsWeeZ|l%!qjm97`p1b|v)oyY%`C%C5im z_vKkqdH8N~$fi5uH1MGfnPRSAxX&)tH z<33wR%C4U2urE?_%iI6ub5^r4I=5XsQ&Ks9)g8h(=T^ z_kBP9`#zb&_)Mar8m=N$QB}E18Il0}g z3_-~e&^7R%Lq0p3H5G^$9iPb-={`oex34Um@;Rx`?W>n;fMvUHX96>WL8={hYpE+0KR@Tzj-KdF7IL}-81%5 zy03n*Owp?nec0>>HFkgJUy-9X9FiLdFJ`!J8ejy6k|+F#-Gio!h0pja`L~FPy9pYJ zFUsAW#p$`3C!A|53Jiu4%Dz>7yIW$^`4|EIEp>gLa0ttbiZN#iec%!Iywhu9EOom08}Xn_qnv!@$E2jF;u#Aux)yODAo z&6@XI-isV9Y?!aH@}tO2!szjJL{V~q%+t!2`rOfVDc5tE(EB$wuFguYc>l`SQXs4A z2b8ZC_Yk%fZ84Klv@aBp9A&pAc*S{n{;F`sjkk7gVqQog6s3tnL?b;^4cUdHbsRC+ zMpA;xr`(xY+@XKI-t-9s6~F#1&&Ryw9P^N!9VdhqN_Z&I6yUHpx7E6x%5!L#5+`GmFC3%+Z>N9DzJ2eG$w1(gzi zLFA{?!)czIeE zJ%*M+x~fwiHNLNksQ7dcOfBVI;0;7{TFQgCYuv*B_v<;wIg?GarsM;X&&WhCt+iU! zh%|Z_SCZl#F(_o)>|Hj0vbvs5>@^K2WR;qmBO?@uG4}m%Q z#p@)Z#Ub$D{B>Yp(3QZ7%lYb9+vM_cD}mZ~hQz?2KsY#95VY0#BsiP)3MO)#E}xg_ zJ{BYn0@@PHQ5myZ%3BT~tChwl0SMu{bQDlzk7zsy$j9r0OBQXTSvxqcs`ZM?iawnl!+feiTIXO6V5`s`iY6Rl>A zG=&J&wxDX0I3}2A%~)zn-OH&3-XM@c;!BgtIaSjQmL`G6&KKo$>C8yLlQYIM4Gg>L z*|DKgD^Vp_SAv{l#YLol=ARaBt62xJGsq$UsgXF#d=WsG-}US|LCGE67#h;=5kx9r zqj5%sKIBWA)xe)tyt#ejJuO% zzFLU*FL+_k;=kYpxp2*4?sFY&FZV3c^^LcPc=nI=e^ey#)`R2g>uS0ZG=AVrwL7n! z@;ADud>*ebOB9W;;w_`s{jti`?DOuIJCO33d`?kINnQB^pn2Xxs`1@uSKvW`JH^Cf zCpCs=%V@@CZjgMm=CXs)X8!s-GHM6R~&jN z%tYpL?RJ=mg?@aps3fDH;D6|PeT0E2bdYU)OKJS)hDL?KGZ1&zWJ_t$S|X!#DCIo(6|`lD#iw`y8@G*~|IRM7 zqsDk98tIxV`Zx33ig*2$+mZLvr-$4Cd421a4XwJg5{rw5K$s#u3*YkjT?dl$m@0ho z;NW7SOBG3RpsF?b)2qVik0S!yrrjT7{(Db9zub$=UH+=0f&g4!kkdHU4DaJm_h zi!9?%bj%@4X$1v@`|m=YFM&#AU|(75WBZHbsyUT*f7j!MJ0B?ZUH}8F z;D|h{HWp356-W>u2eVtwq7xC+lMnbS2($~N_y|ruSVbx43 z+tO2wtheK}Rs+?2n&lrIw)@S)7Ehg#pds^FuIyb4uV}rF?^OA?S!h%R2WX2)W7kcQ z9WkS~V5b?I?p99?#y&O}5vnNfn(f-(j38TAS1+QP(}wy|nJv5ElAL46prS$GVuU%N zUj2?*$P@Z3{T0c}Q^7zkj$H_w6r6CeU7$_mxqChFwGk^y};Jl-Y< z!vqOEw)hB~=AwL%tV1rWJRZ4`O6(Y}Dbpml{rAqd7Sw3qREr<+6$E~$H-Vuk4z5ps#*hVB>)7@MwD(g!Ep|CXs$BtDc_rj9 zolQ=d8o6RIWVpPvER>RcbGR6)FZhgLN%)rTzm3v~}&t!ez zVZW?*&sgguc(c`|@Sq^`>%BMi-|Ta>Na(k`voWOf9Ma~vD!SIUZ8->H1_tXMT%pOJ8H~Re%|>xx+RjJF`%bS*^jsiOmVl|e2jQ}p3DaGB;bJ- zr&IU)bk?O6?dL0Atq2VW;)3kylUW9z?d_NsNj=>_IH2FK-u5v^TU`3M6!1kBOD&3m z1w2C!@F<~uKlj2U*ON6?6Po+p8R>;p4~y<+=%yWJn2d)P2fi>l8;7S++&1p&;v#G>A2Of8JF01vF4 zTTPowh;Pm>ToxhEg%^c)R?kf8zs}=2Qd)f- z%D9VLT}^|(@wIPs<(5%!Qt@=mMVp4If7Qj!(P4-yFTrmDAU7_jLS2orl5++r0(!>U z`xF#2{vN*Hs-q84t!^Dan4w{9EPrp9d-(a)Qs5BqjhN~&#AN&&9HKO>;B>TOzWYzf zK*f-i9gQYNYIGu%bANXiqKof-<@KVsc6&>|`4*KX-h3+n;dssGd^Vpk9E7wDUB?~X zYJ2z9&uhn~r1Wf0fx5Pn)mCf}xC;k6IUiX`uS_2O+hn{gRjbA$LK8b=O|SMTpFC^^ zB!lpDCLQn?OT+nsTf#}wD&gAw^Xs0^&*wfsS6>J^917k){aRjjRp#ba^2d?h0>AxtBIe`E@Xqgn$Q zDWt;x-aH4MxbxxBRFpe+CWWGTV_a>Ec)9%>zP_fuJL$qtn9UhjVZl7Y2v{va1Fz5b z9=Gv{tlWmSPv1$SKM=B+{=J&l(|MX+2{wU?T(3JcXSK@}ln;hcNShvLcs3Wvz&|%P!_M_*URkHE?vr z5<>IF2W8Yv`S(i**B8<_w36Yo_oE+DG*Kz(C#|j0z{RAkN@RdTUVNOK^ce$T8tT$_ z+uNVD+al=(<|^zW-^2*K9@!+}kaU2kqAj^Wtoc79f$y9YB|S$xx<~%pDq)&Kk88zH zfwI6sBI#jf&;AK(bFk}P*We5+XCwWuB4ZyHTza{NTsqJRt#oiNXiky!Z=1@&gSovq6)KVnq73dL!MyPS7eRJMy2D|a+sAv17I=~u6~-Sde>ym>s0Cg0T6rCO(~ zfEjb3gg04xj+r%_Hi_ z6<@bJ;Qj0ZWi=KlcJiHttQzrYOsn2!muFPgr!D3zmg?<{NUFP|OUq8^T<5CRZu2(f z@Rd}|F^-VNQMENWK)fYawkS@~XP2vq)UsY-YqKQP!=2Wu0~%9+A%+47m0nAn(BZ|U zFVt;PFeth^9jeDxeJc67nW4;`&5Yejs)Em4DAtw=uZ$ccTq_S3oI##MvPM411h1sHB70$!?q zZtMA+`j`!EMO_yb=GzGv=9$zzkir@L4l)#qRZpG)|tT)gKZb!~OMa z8y!|aEGXd;fr@Bme|t80WE&jT7Cg@FPWD?brD!d6pQ`xE+_3HJlJwWu{h*pv6tu0y z`fs~cNQac`4z>o%`((XHF3S50GO9Lv!u%p*1xO++X)Fn;{1c^JI8 zVY0bPzbDR|j7j^nF@E3^mQHzN9iJqre94*{NCvSi2ivbHLh+vPUQ&5XN|eNKh(ll1 zl9WfqKhmSMOlua3leG3Hi4APSBeUCHhA1;rY`4R|2Yr;47T;*lG{T{vq}*?`;%Tsc zrB}D_uv^o;{g^qizeNfyn8v47=e){Y5j2}4A_ZDPGr)U_f|;3wnYsJ;mhh|XMQ$WN z0}aEpS$*RQ3%P5I5~Uodg|&FPS$4lY!380*yW-$ru)OnB_x-YPGp@_NRhyB{{c<-E z%c6b>W`dW`Zsh6@GrjV8^y;dzF|TE*I~hN4yP%f1Y+OaF~+^mTfA0+!)MP{_nS@_RK0cI5KyUaHOcYOT$1 zT&kj?A{iP2r5KpIes{9?{2CNak~{)Bq{W(beb&o7z`p9yvtwkJ+xz8VJRM9mUMGni z`p-q>A}cwZK;OCIvMvoQ)VVo?F<$-Yp5gJ6n1L5EciLBRU0YRgYC1^U@3?I$&B}Qh zVjgZ8*pF*XeA6${;%J2_d+j|kSwvXf!POLG8p|2nS#_SSc~w4$Q6}o;Z_PG8gEuyX z8>&j-f=>-wT+cDfeG-;%Q($jrTAa><6hM;mQoFoy8kS}50m~lvOlMoRVm+ny+?=K) zN87N7w4Ywnyg1Oo%*(@1!yh9%508W8oL1A`-m7@3-wZ=QP*)%An_jr0=)L>;Jx(7Y zIU6&H;7#s6mGiSR2uRFZJ6%UR&yndD6D#V2tobDi4mgS4HEtL6oCT2bu_{H!NB&JY zea9n%u#09>3;P2zNbTa&(djN%@%)0qX8R?`eEt4i*@jmxJi++!XOipdNl$n|^B0Wy z0tt7D&}N-}bzdK;v`&J?`7w08`WZxE-YMFFP+k2{qkiONLSv%uWbf4OdtX0gHbs*s zu{a9@MZ(V)Op4g$Sv1a=p&iZe7U{};$U`R(T0J$z9XW5pgww;-EKe317Q(EOjF(w# z_OpwF3m1?a9>(Jel0%(BR3y*NgY4P)@nQDOHk4QbMz|#b>ndw>OJF@Chc`w%Jf{vd zZnZZ-?fEug^48VDX1<^HFp&d462l`Ovgb&@WV{pW7jTf3%j#68E&PB(#qk&_{YFtQ zZt2Jd?CkD0PRERSmC=7Ip985!4)M+2>?!iSS5%<(OtZkoK3Je$6RHa@ynpU1LL?ct z$aRb|Z(zX9WA^CQj2bJ~Q~$8KFnowI{po#ev#1^uXVtCvgK%g{VO*4ov#8A_ehT8B zDU9fXJ&~b7N&Hx)v(|?|uT<+W08LrB%wJ9Y5J~mZ=2{qeYB-NvJrhr;7@9rm)DF*I zg5=L4A`(M0yB&x;Gdo)Af@04vClc)wr>)Ta7*oP<1d(LFmE6xC6Vy@0KiTq}jy(@k zVMg&Hewda1g=;2h_oJ}g%tFc!h9r||5l0Irx(%F9CKZtx>SM?aQ+`k__;(8vFSBG`)rfpi~nfb4#v~jGH(CHx87t5dd zoy{s!mezNfwKBr-o*z7hH+W{1!$pXoD0mFa%_-twz80e(_iMAIJgaMcTjj$}4PAK% z3zJ&9OA8km$R%Hc?OomP-O@*?Z;4RyIw8DU-_s77pU9Z>5cI)q6ah$V^m4$E;yj3r zKi%^wV#YPK6dvkg85|F?_&r|7?;SuSyJwm%2N~V`!|c+^Pj(AyMhm-Y>~WOdyyp++%SoXnu$~hTsE#`5?x>;pAb(a97WNMgWyjLuP6mq z{zE*d?%xTY%Go%(`-``DXbxO~L?7g|>23Lvksvxrk$99d3=|y#wBV<38@d(U&4e7L zt{lp&SZ(XFWdp)_ktKRvjNGhXXL!$p+gfmnIrpZ!YA6ZkU)O}(H>$cb{Rtoa%O`l6 z(h_ZK3f$WG!9Zw1-(D!)cbG$@K%s0Jmg!UH#JGeUR_$!r=?(>nL0582`a*T!S3H-& zg=(ujb^~GxX`km04b$lu3Oxurd3B@exuZ?H*7C^!>@o;{)uJ?=M74nPl*Y;dt zNK~iW`wx3EIl<)pt`bcv_9;M~N|}b#EM?!h6<_Z;R6AYPpIFTb|936NAo;HXvv5s< zGFcC&+j{H9ZqplgJ0SGG_jg@$v;V6`;2}S8N@s@wc`}JBD#+h=J|kW3D}-UQ=4^Pl zu&mHi5}$TxJaX}^{`(DJF%b{u!_nrEfd9bzhk_USzX#@j<>OCWB>ul=g7VS-J^TOo z?L>TDHbF1Y0Y3@<--p|0Q&ZC;zx`oG``&Y1yN8{jb9O|9nFKzy8|) zcOP!w-1{A!&0oC>@$o|>H1Q;?e-gn4ty~^1g+Xvga^Fl z8jZ@P{!j3aI2)o%*=js1RCUYrsEC2ebOkV;S2Tm}2EMl~d>p~O`W)N2Vj|OP;r`KI zpxg19g|f^vb5)U`{Y&=~B#8gV(TNKE3!6K2e4B%xMQYZ$F%A8{<2H7F&mWgIXslXu zjx@X`kJTzW?OI{tuYF4|c3|Qbh!(>9);K9{3J-hZg$o9~HdV*84cK?6P_c1Py)|K;DXy z!8>+z-%q>?(zjQ{wXy&a#Gj{aDSYTv)mpMVB_G2UC({S2mQTP;v#okxUP+o*C~zWh z)1*_*o60LB7!$C*->6wyjoRedwGZA)W;pebu#Tu4#CH%hqa8W+J`&`|t$C|jjmlRE zKcnMk-<(oMRT{7|45x`No4lg|rv37mP-ADUp{b~J3TPmA@qVDQLo}kz;E(6GgwMd4 zcYfb)^Fq*3rpP*vE)-DdmHoayszN4##puoe@)_DzZ1;6s-~`$p3x+_gmcY~bl*_tS z??b9pILUX|@l;kgAj9J=5X?2zuJaf=h+zADn)EqAL(~DE`Ap>=#FnV#qvqg1+d$mEXmqbXt>A+Tt(tbEz4&qk`YH= z&J##U#?!m$DzDBSE8Xu=6RWAswyvtMS}V^aR9I5PAVh@HG;NpRoz}-I*acLva2f8} zqYXC_sIJgP$4f9L=|y^8>9Rr~G+y*jTqk!KJj`^pkQ4Hj9E{WnBX!@Wxc!MKq|^RP z5Fl(e!^oL{>;|u$Dez3Q&*AkhE}u|dyx(_H3$n81qw8=H@RInbX*eVSK$S99Z*P>* zL5sjUJ!X#j(GIUW&#&b2b+OV}*>dsRjBN8HlXb4Kqjv5!fRscO20`z~oQYlY zVT-St$dY0GGV(lUm0+aDLjcd3pn^^1xnsq;{b7$Fjh+<#hsIDdWRLp=G{5Bs7RX<{0-Q|Q+Cw%H(4zB5vlc607G=I9?zC_C zd{sI6R>e7V$trIcK$`nLv5grE8)DO>DiLk_Y&v$?Gi^Wfw{@UX?(v=9sEuqdUmPcm z00JlsO%roCRSFXQYXNO$x09^DVs>D^A1lZIx)Uq6{AzXN*g|_?zMekUHJd{4R!(V2 zbW;7O$w`}5l%uRTY3ZkWiLbY5Fre)=eZ-t%qix345 zMr*2E9z#rgDIIuA zdPKH1-`TsO(D?*tb1=uyN=Dm$W^}URF?)Wkd+k(ItDmX-q{MmuN8QmN&v(AWY*At{ zCXv#-;+#ehWZZlV40L7*OofWr<*AAJ>%}uX|8DNo(qqoIizXhKONC}H^%9Rve-ow#^+{e6 zLi>b97TK(tO`>Ot*G62`KJP;v8Qx6ln*A+B>V-?o1(x`TYKs%*<1y(Ss9A;OgN%z90o9IRyoI5{-28qVS3R*l91x# z6Y-DV${945DKfr9i^nJ_>gPB;)m**!`(Kx<%Sub@s}~%cXqX|y2N2^cVW?6(_UdbzxvoETkQ&Mwnz~GleOCsUe4Na({g4m8m_&q~#F15`Uc0kRyuHco4XajOM=E}6 zR7L)Q&*OgKLggY!b68B zjW`X2H?sKDgfpBmt?_*CDwR(plT9Cv1=rcsF-fwI_`@n)@O+kB*7}Ic(TsH}r6aLX z!(~JI6~aF=`%hHT`#?6!l6yc9cY;3X99$J?G;stw%QmPF6z^%~FKUhkQBLd5pQ zW)JH?h7!=Ve=YF%kh@`{)_%RV*6#7WZcqk#{cU&FDOy>ge;AlT@-MM9iUssoVm&RFG%!i@(-kzXFqX z{mR{3W~$g=4~dZ%1sGX(H2|ILfoa)bm^V^}7c8Lbae8~o;|$s5bw4(GGD$)~5yZ3c z2x?q!vAP^Gh%pe4-N&_TDxa<=I{n{eCd4zrq?Mr|38!~(2gvpjpZ2(LxZ~nQsGj@i z)@a1#{LSFVs&UP>*EL%nC!#i+w0UbtG8>KE|BB|ku~kTH7^?Nk-RTph2vY728&Cxl zhNV?{n%TE(xI#Fz3?`#84vQ0~ekf%dtOgfbz5#s}7CPnDl*&fe$FzLe|EdkS9>KeJpH9hDQd1*-vB^`Ta9Y3B ztoF6_SVT7=fQ?n7E@VL`(@`RmG6~UplU^UTj3ikkW!P!Hw(S~xmU}S%V@xJwZ>scI z{;TEE20y!inyT_jb@>%R)6bV8#;HfdO0&B8={?0XL?Hrgtg@OEG`#8p_2V2Spv<4(@8PrQ3+Aej5rVHKd+ zN2%_6MN>I-qC#tGMV4NM-eK!9YEUXU*6<`L<@yf2wM5rEGnPi>c&Pj$PR(9q(bugc z8TgfPFflO5=Y`wQ;%)G zqNAbJX^y1@8=K@6g6UPu^sZ$f(A@1L+D)+-0~j@S(A6arQ2^r$!J1sj;B{C(pLn`Z zT^lVx#BWJODF(uZ71bg}o4lUls5#N0f3hUYX7H*gXe56kN(50RoBjA8iH+6djJLI& z!;wOp4Y4VE#KC56CbttfF3C@2kN>3DjJ$$F0cM=yTbf} zg2KWHH&f?{v(?158~apFQxloBapsGRuKNJ5f5s1g6g#S529aUlxJ6W=O#o={GUIWJCafefSn zqPb_-1o-(Qa*DtZslLAhd~bb9^bFA;5q**5ODKLeGSSLW;o~o= za-Bu3QZV;Ezd0*aaN@OWWZSaeEV=T%tWjzLPWIEPv z-{cB}yndwlyt2Q%BP%J9t?;txFRCTVo!g+!{a#_DvDHdjI6$nMz<~UF zEv7y5?8a(-KYZ}LJVrt*#~E{?3X3AMg5?i@SW(uPJj_aVZ-fA|HPW@Y$SnYxFg-^y z95dpKp!qZ^*E``d>f|?*)$*6`q+954avGgWKk18qSnOb&cO2J~@-rJ1Io?KQ$B=PI zW`$$4wN`tc`{)XMmnU0sN_P}@?yFOvDI7V!tgiIT7D$+|jjq+;9DH_+6QOkhN41U+x7ZUYr643N^3Bu-|}onFbP zh5CVPlIy2pr2`1{HV0qt6)yZp5oCorTl*B{b z?+)LO7i$X#wv(?qi@Vo@{sWNTwet_Tqm={h|)QKbk%={MOkaMP+R6OMUcb;#&OzidEVfH z2SrVWT-g=m6BFIMEOsl>5`q=a4j9uX`Sh=S=5{+Zo+z$OP*lu!>tDyW*W-w&??fer z>REFnATyrUE?j;>$?PVL_XG!*$|f`uzJZjt^O)G!m>4v*O7HhZtL5hX97P(?nO6+r z%D`ui9Ez6zm++%f>_% zSZxjkbXWD%yJqY%S}%7Q5%~zhI&8-HP9)I+A z{?{jkH(|3{v)<;OOaE1H`?~j8U{Mac7040`Vyn&&WI-1;qPXutp?T*$W27^Q+-23~ z7){nUeoKjIwn?-W*g=-v(mJW~w!oxxbT_`xGFWcxV4cuYYI!+6%K8l9yDH`>W`7Dy z7Us5fw`#q`zuo8Z%bq^sKJ0L&&h(m-9tf9TloE)_MgYFcNJN&!cMs~opsbB<$7Yrv zRI}iknx5D7)Klaya2W*@em(TX%B5G#_XPFUnKgz8lLD@nf61Np+1qp{g2M5^f?aHh z{__cxe>{Pj8VQAeeo%0F9Vx$W_9S6IgNhTQ@|7Fs_ z#eVp(yQ|gk(nHgt;PKrk@o@su$ru`igy?y9en=o z5{kN{GkR_!^c@oAV|4g2jf=-(<$FV0bG!YrL~0a8W``^vT`h-b>znLprNg#&IzDGZ z*k^#kaHRPi_C0(Ijs2nBfEy{ZQ!qD1@%frSfUw-T$s$};|L%OW8ltPN1Gy7&yLAZo z(L1GzX?gSb0?Le@dV`R=_Z7`p=+z(mM|Qy!@mR`fMZP-tFymI5H*JLD{j zxSuCTTJF!EW})|_p>lCOJ|qNuP0)MJNW^&svi_JhlUBDv66EGli1@(_(ijet;pJ)ZT49r+D-P-4eAgpY=jG(97B(+%X@R@}1WnJ> zUiU%3*XZYcw1eglB%hY4E!4O52>U6w-qDL&S&!HCSNpCH0Q5IiNvJ!$``V#p`L#0* zsDBeVW3)fN{t}}-oLiXN^=pwR795Xj0>1T8l9D06+!;=B&DhFf$Em{hmjzFxv5uBE zd`}+gMVK*O^x5jeZ=O4CJ@+v!#TKJN3&-Wd17y>9HGC}RzaHWqf==Y#{pyek;`{u#JjQG?Gr+~|{Q5tEj-G#aNXKDP zk`bTz@UAxBp!`hb9UUDndXM`fvZ+Fi7Ard+E8g51tXE-y=;&y3nN<4EGD_DOpUcSr z{slE7E*DrsNyf{j3j5eqpLNP7_D(Gy-Xranzb}`WDgaZvo-mWS{oKwNtNYcT4D&)F zfKFE6etkorwA4@CxFqF$l1U|c$l<;4$%G?mZADkd?B1c0cL4jjobKB`&QE7v9X+9Z z;mfg)?`LVM-}I_N|Bn{HsC@@}XI>7!X0dF!0VG1@D<;Rq*-Eq|5iYJaElz`asYPp) zbZqCZpHn$rKLD4Pmte+%O?9mf>PDH&Oc5pqfN^BuA?ZZ+=d|?ZX(N|@uSJTCn?e%U z=zLjPlMqJ-emFF=^(9vnSWvTbM7!EFz~DjV|AB<3l@cf%Tae3OD@?oONYxjwyRHFSA3X!fcLDqUYHOa2Yn-YKdy4eST_OVO;j z<&Pyr8LL-uzak>!M+MR{^wwF8)gpb)ibLNl)2Uf_`LuvUeWRwLs+S|06~`_IJuol; z)deP9E!oo6JT$2@#MfJ&>Bfqa$5`vM^0U9c3zI6y%8vK!W6#QP1vrGsI~_08zu}h9 z&qgDP2nl(vZfhj)fnkc|mZIS9a!I*rvosc_N^1!8JPHWzh}+3~@)4T-@EaX{OG~NF zTOH0WB?uOPh{T!E5dCyu$;#iaw^}J@nHz zKX4^<@zbR3bN{))$tIlw$>NEP;l>W>+jYOz5x#pAkVj9 zbP-%7L?<;O0}f~{TI)XA@rDNEx;cMOhf%Fo5YCIEVRb7hb9&Z91BPkZ=-=*4^8ujE zdy=I6keiTJ2KLwAzqA;~Yc0E{&74w$5LfOz^|l2)S35SEMJn9c8PF~A`u$DzIPD4ZSvE>n5aDb8+7HbW*d8uT*w>dSHC8B_?>ZUZEXy*nV{m0+p%+$1JK7w|l(lymS=_ec9UX;BIpBV%t3QPm zSA1Sf-Iq^LQW@90yORg6Dr!lda^)PY1tXe ziIh}TZ)t=2@=cvzzVz&D!o@p{K&LNRNMD~Y2(!A*Xw~)c(kSA*dIUC{Tj$$4E26JI z^EmTnH7ZL2MGfi*_S(9?!it_T$(w#{jB~{Hsu9#(^$j%DA9|viAVz0u~8}HUiVziHR-~85` z*ygi2-RL=j3PRjCb)sr~^D+HWhv{!W51VZ_awg5-DHDb>wFN&&+clwok7k#!?=P`6 zP-a6hmW#VTB8CEfEw=8j9|`>$&^H+6*sFdw+ufQwBbg@;OmV4I{f4e9@Oi8@lgd_A z^?B5}!64_ymao*@T-+fPE2I_vHa$I3nkptH=9``u==KH2IQwI%Jo*n{hIvrNI9L1S z0MP_)JvKJf4JJHvtMh4@z~S1rqOxJS*ddV7VYJYIkr?MVIQT>3;c-8caiwub#T5n9 z9U!J2<}J4|%rv~ra(q6U+5a6A2g*uZy^sS|CCB)Iizh8|_|Iom6x#gDHmAu{XW#?J zicevW9OyR!ha1}p&w;g(ERwiaq}n&wRb`^K!U>7T_@=|8PzD@c-#bM_?41-;yMb?# ze|`f<_o|1qZNMa-&ea%0@CXzc1goeNTQnPBN(x1RiLltrDHaXwSwHiy=JbocGE<2Q z8PLRg;?io#UI-G`>LhV1^Lk$Q8Zn(LbcFS)aC;S%vY11|bC$HDKb)c#A>M9L8toPY zY4Q07m=sw2Lv^e@Y7`ZLhK}g|TtVt)swh11p?LLg+1rrq#SWLtkvRve{&^+SIDo;<9xT3W?|4OpVvt6x*lsp-`WOc@Mq2Y zXDe+l1_N(MZw*CXZI>3Bnx2euj|`aND9QS0F%bR9zGMB>b{A1pULpAciU<>k;qQ9R zeeNH<2ckZhX_I-qZwz)KjT~d)6+1Hn^2)o(*Sq;E3s<1}#)o{oOnvGfe+}46yOUiR zU^v>Td{fXNu1oPPZ zY;2`PNi&teCM5Ao-j3HE-8fFi?Dm`(mxxpBhw^1ll@`Ia;Aul-T}b-?d^p0IYKRq9 zKpd2f2fkS+AG<;*X&@uNl`{2K^v-H)n}1VnDisH}4(9`$dydX`(ZD$hjIYeIG>Ltl zOjAMaZ!y1_-j3TU{MIA6~~Ym-P$w$GIoGL zx!11$ULNI2j>r^u_V(-qz~MVhn$qFO2!t>3@3U1r@n4veH{@&{*47LFJhVT!U8omO zdHu8)zbpe}#atO{f8n8w(7yq`rHFo0+AJV$egy#wCE<)$Gq0+^K`fo@{6&+DgEzN% zyRCjW@o$n}a8SOh){G3)<$8Qe{GH8*p`v;|Y;(JQ zYAu1cf5`Ot5OKyd0L*&=U6JJK`XN&^s!{v}!sUYD=^ zNPw=jB?S(5(%;#lD>|Qlhv9$!cs%uuuTM54`&7RUv0^9`@I?|}4>{M&mjm z8o?@1$4d-JbiZ3Kcl>((Ih_|m(ujqR4^kp}$6BZ(2cQ5p88Ir1a?a<1u}<4`Fixj% z#1MIuHlK_VZpLmYpjTvVU3LlB2(rF%l(G8bsTMIZQNc!9RT$mj{w{8N8CcnPcz6z6 zKbzMZFa28{|B~C@ZGd<6nX!=H=xP${1QeVHzdgbMK`2DJE@}Z;i64phKLg+&ZBF&y zp*u%LGyH01`GqDyjz8wRj$P<7lWV7$JVb^@)ugb>%6CHJF%xR#I@B&NhP#5F@xvp8 zhaTsR6}o-EZ9a+*pZIw--j<+_+&B-L;sOQa)b-v=YOLArEoGAbMz>pxd%U+H*v?tMeHp?5DR`04@Wp<*_W9LKOKpT0s#2ON!nQVvk21)wndlD;MP=42@zsjeljgW zIt$TgraGSUMcgS*U5ip>OxzV9OJQ<##{4!`6+v#LWMjBpTj(RfQ!s5Nx9x`SJ{AL* z@3zlv6RyhRaR+77R{iq0k5!i?JCCjBW%eJ+{Y~S3yy?|BUh=Qmf6?vaQdpfWH~F|T zg`8LW0}-$HYe(!rRB|$x#oXw|zQvl}v2&|LjHl6|6gs8!?@&c3KrjX&B!u<6+2VAG zoi?F8BMIXZIT-cH{dC?5OoGuZCK(x-NlC(r%0l{E;hZZMN3@JeV;|OR{k;5%tuuHf zsL=ZR``6qC{zS=^;tC=~dfcYe16fn1s_pGHdhc(F#UB9E4&qXDW;buF86@ViG| zIMR7sZ4&dB4k;0mSb14+K=9Y1iwpR3vNuZz5%&LZ=XvVeyIgMkk1H?&5NfSEXG&4KAz-@7W3L}(S$vT76h5?)S zu|t-eFmnPF2si_uLWFCH+A?Q8nTP*J;kGGrZ9jXuZi$=#*>!CEFyLjQ_N%f@K+}2M)~%qw*wCC_S5w$YaRs_ zEMK0Liwd}OyLOIshPXFxU*lJ2R>(04i+>M;GZW~x_t?!AZ`5i9f25xfL4mt^YU3?} z$;rfcF$BzHJU!b68VwxnjdjxwWm#@RpB4}OaEo3kOVfY$#W)jI+Z#!V-o)%!m$A1` zZSln!WO69-S&^xqcsD0)wa8Wy&An=Sw-K-WgJ}G}$a~AEtlsxuaD$+LN|&H?r-XEg zba#i+ozk5uAtfN)(p^5JfOLa&w{&-%oA3AcKQpuDoLTeYtTQi$x6iX4_P+Pt_r9*{ zQ+VF|W<+z^Q3)hkXOT>`lW&i^zTs!+$XE*+QAyw@&J}z(Jo8B=cdsyjJN$e9k@{)M z7^?m^f4MKXiPm=$O+${_bb7*SMV`mq)I{6k)s|pv`jC!m#{~&7;68$SD`s4FEZ$}Y z^lrL;I1H8Nzsy!EgssIT*}~RLLfgr3Lt)XzYK2Y<`aT>i_>)z%jEu%7d5RO^uaaUM zuK->K?>lVfxd+1|ax*H?Do*7--b-NHubJ5u&Uj73e71XCSybdK;0-37jR&*v;bNn} zbK>syx}2dmzwrLeLG^zBu?XP8Iy9TJ+ zf|tu_ipzjPzRIk-N#Ph>tQ3r`lA->z)|zqNHs>va+}W*Q0nv*Wu^BjF`&83*T==L?5u2igJ zn~0fp(lf$ytib47BW$l#3Xs>)Ai{_$O}XtRFQ1;ZiVa-8-U=%xCnvk}1d#tC%FKjJ zOMJ6wns&ZDq0ST^LGZ=_+`rECDNnI*ad8FCZ!&Ru^-F#3vhIo42*QEmG%xRU7TSb^ ze3_w1hkwxEqhDvQc&TN+3!(pB1@kA_M3oipaoeU_R4625fJv*tbual7IXQWn=aD_M zh!TQO_o(tRoKx*_?PWVYGQ3;PPK1Xnxb(lR70vCJrWtSEQa*kE+5;`M!u$TyX88U| zM6- zxhX8~T3lcKJlFnmpqlwA@8fyY`j_lMpUV56gR7^0N>Zl--<+glz9lu3dg|4jnO^&0 z$=Pl@NQbE&^x$22Him-Mie_s@@rUAp&y=nAGXJfh=?yhXO8j_RzpCo-hG3=5+!I8^ zpl5BLfy1|kRqc$+?)2@i0JK_H7KwrUs(dP_41Ey^7d#@$Mv1s!04RQRBVe6rs;e{?DI*#+qM5gdgHnz_z{!t_h>ojlrBA zpyMvJITFuRnwIvPJc5Eh04(jYJ2!36$K9{p3N?3C#hN!Vtr~R!e$zqhlgxj;1R_i9jj4@TU%W+EH8~z%sF}N8e5dbyshT9Xt^XBvM{f`RE9I74 zHF|p7YL|F?5bgV%9@RVg??CopaQ->pP6z%Xv z@e=p(mTmNVb^?%AlL4j|SDpfLiFi0Tw`CvNX2pqmySur^hf>FgYAp{#r9oU7_riPp z^&!FgB26rftkfhB)q9B|caFekIy$KBJwFI{#S@ zLxB0Z)qOPRr$iJwJ4WCj8V>IGZsQ~s8S)UVA6#BRaOnMRc#tUfao_9%o1 z_?XygJzwlUNXU7sfph(8-)G(<%U|I4Es4Q{_Zk(|^pYJ2cAK&D3X!2wFZecY5!$UX z7JS~0hm@7&g!-wnM`g*fss^wVwNl2dIO>y&LwF*waj=RX`9?>N)aa6v$8@VI_E<>& zq>_@9d+ZyXclvt&1c*3tyZhUkc9P=uw#?MQOP~V~}Dk`$(SLJ21XV1Rg z;4U9#dDie>NiP4LjvL&>MV8Ii63yIJia*AvjnJJyH;T`%?gD};w_OD{X z=m^N6ORs{W$fAu&*@Atn3j)P4_jlM|F&}3d1Hy5C`Xo}jn5Q*50*w9juV^8iuN=>eUF#_A=pMrhfM5ZAOVi)ueCaVWfGr@PVb^W z?=Tf~)_4sM#u#lExZwSK+2Gyb>7vh`&LkVxBRS-_z8Tpo<9-S6C&UyBo7&+8$)kKklT5+?P5`sZTg zS3>oE(c&~iD5S2pfxae^R==Xo{0Gs-P(S`XLvDMmRu~JH4qkeSzg1ta^+DVA9w6Iv z*vtt3C4UWZnXpz{Bn1tHHxceP;pw24EHkuLwHOGnz81}-?%>E(D7uW{WJd|AwMfu) z_-ke0NzorJy$S;demLlY=b(R>><(X+{!b+2iru?7WPk8IhkO|lbhAHO(IZM99|6uZ zJ)#s*h7f&~AmAD&sBE2Hg~j3sr0s9P?19kBjwcA7G;Ponnq|V{c?4Lj`(wjbDE_zXx0lnV*k)$hUl@(C;|Dxn3!atl*JXAWd@sa19K(@I+ggBgU=gQ&rEorkc{^Q-?s@ics@zQ&fACv;CmPXy{nH1H`tf;bzsmAvdLtt9>PDz0l&%U&@$Zx`M| zk(llEjm=~N(Ra-(1s;M-8v-Is2wD%fd^#CS$q?D|t&*^(l2r8Ic5i<#Gaa45V2nNx zX(NMp3wwJCQDE+mjTd|2xn%QH9PkZw_|gWCUA;t22WxC&a8)mJoAlR9vEpf2FYg&y zN>WNN~#3mZkLx-%Bo#%MyxO~ELA<5 zs;Qz`YWR#Y$K0<3;Z&TQoPy1-JqPohNTX#w%S%Yh*6`{AW6j{BqsQvs#kbi%q$*^M z{rHiM5_AKYi_4j0X{9U)5~DYN0LS5*Q9#DcNrKL79;i!HD6GF|WqG-t-A+wSVT&RP z@&Shv%TgwKIwllu*RI7DmwC5OTCZ?!ey<#QUXF3<``pULG(LTcE-!F+0YXP^z3)Sr z8LiJles9~R=dw>F+)L?tDgQo{syo$Zv6=n3IhxyJT(L+kkanLdn=H7kWu~-h%c&Yk%YT}JeR+pgG7C8G$4rmfol9&)6G|%ieT=&N5 z|151X?D+Uar1ciLw?fcr@&NcgdNfw&6W(5(Cvcj|0pp|;m$@tzF@dA5h7#R62gz~h zedSaflh^6~yHBkRnoUAn$Em#HU-4TuCUC1585wn(mir&Zlu{-CcgkN&;k=tIXqdt^ z2AAxLH0!_Cx1dXe)VZwBf&Qm=Wvqs;`L53Ce81U{5Nw}x(H!slz7K_ci^A%%bP^^30i}#c zshmNtf{fY%>>DhR<&fQRJ*6D;ET;wshja%yG85U+Jkw}L)<8#drU$&BE&UfA4;+OQG&Q;Rhdbp`_zdZ)8-nz<9jLNXLIyX zD16aLu-}sSO5lAv0zOF!iYf(N>WbO)WKxyyFOeskGSlHvK#U=BdZfZTdFE9I+6f0I zmyPpID)FCz=!sIE^QAZTQz=QnEHdeGhi#CL?Zd^vhZrhZu9JrKOuk+sQmyJu8iNtGT3SZ%7od8b=)$m%WdV{ zevJmBe0ktZw#VyJV((O{FS&5LZf&#b_$JV{3XGI5`eIlrc1klUL$K67eT^K{QU5>ksD?kO;eH%+;!iN0lL+saK) z)R*~+{?#f0llEo4z}?U04a0qk%|8NKv0+nQ9e3k{Ye}PwHq3%`hKna2W2fI~C{B75 zN#8|};XZMBUD&g;`1{$LQ$6eWpI0tjS&)D1$!F|#{}xj0U%8*?j(copi&b+c&|dLi zL#%9UcuZP5G2{<0X1&oSJ;2!t?xJ4z#mLJ%hLZZvW|O%ExZxqN+8gUP6DE~#zkp(7 zDM{w=L%D{@pqpMKFvF|-**yw&(>HMzHj?Gn(NYbJ_80!fq|eDsdf(sOAGZn5En1l?agun4A#7r z{LPa_qT0|>P4zYVdQTsJOO>#e*Q<9e!qW3FM^kIgZwqI;Gj&dckWA_gzNjj53@}}N z#q}P7k_8-1rYw6cKZVGH|FG6GHW?0zAdYBl-`>r>fq@ba@J4k6Pm=>o2MgP%q$p5J zd*O||OwqN#90c6@6SPRvm0Ch9zW%Nj>MQ=t0LE6lit1m)?4p zNnmCb4hnu8pau`Qtr3-sXNOF6j}O#1WnaL&Ndtd16z7N^6)a@m_t_WY=kL3y|N3!K zAiYkH@H@=o5!UGlSE8W)fx<0Q*NC6oM zoy1#?a|egNhDf2vm>9=ZiMj<^;jTS?K@et9Z5H)s@-ep^$Px;S?ALC}_i#SnYXomc zBoq{svCY64Vy^UNg_$Hy+kEXAV;r1+Ry<^tLrGI}R{)bB69-#TO|52h6U=QQ!ie!Q z$87Fx#H}l(8WEl#R&USUCFJHpzd)+`gzcp3F`}}R8MNqX;B?7r{RfrT`SpzB>w0Xc zN=oZ>Oy9g!MO_JxtKif-a+AD$ISntsgOkH{@7=NbEXAHzy_|JhGrh^%LFb%S?o(EJ z^*$)TipMI&DQ!GG)@=3L)TR&V2a_idJIZ>CGhJ?{b7q%ETP!-3Ap}KqI-Y2ayr!ZO zyHIdpz~l0y@B$SAgbrkKxe{B;_Vs}r3QE-M9;&Lbohwli6d9zX;SEof^M@^}3&t!` zN-~^S*xQh73MeT%YP!3fuxM6UTcSy0dI>5cqDh9Oq@`C@47O8^Ev!U?zni^{LUNKo z>h9tS<_8T-p2QtWRZGj`cVPkyIyov;Hgk1XX5qWjE6&9_)$2hU8?T?SxgMmq1Uy+= zU%#!fT}b8k=-7l)A4C?DT|EWoaqZk?-=;=A+Nz&_hY(JPy zM)#H)&X+&8^Z=d|7`wkZr!FLiza^Y;%ktcvsZksec`;!`kk)>9+2y*Kc>#-o4d zC-$}$2`gd`f2bw>?|X#?Sp80CAK|k|%oi_6@##un)ec4~M&YViRr3hO#$&0Rio=TG zuqwNDclF?>xt=kv!ZR8ggp1X-KW03i6Lt+;%%85d#A|W-p+^&ff{H@ttY;CJ8VUzB z>NQ(U(LdkZB#58<{22*)tvCGvmv zcTEZd1H6H$!oZ`hd2z;UwM(JYj>tUtnOB#aMxUbCck0)%Cjc_DQshH*K18 zDF=@RpRJvlF;4Ay@@=O~Xa7%QicL}f=Z5QEZ@tgcqu8Ky^=r2zL zZ{utfjtD)47gY={T5;ExaEStpD#{*~5qRHbH6p8k0W(ylQ5>$2ptTe*W>U)O*KSeB zVupBsYCX955%Se3NvGMe*pgz%*Q09m@tH1Pp)QGwomp#88Of79r2s9fk*VqatkYON zS?UJr%bTn^)an+nuWFQ)3Oy)`ttoQ6>fMg@qPvasN;y~l4zF~|e@p10>tA2xC`L4F zBEEEUlh${8Ln1VnBfX*5=w4$vqecN}er(gd75bj#-OPtKL7`?L-pAn+&mXt3$qUBD zBzY{|1SK&aqa~EAh*FX(f4kK}M4(NGqV*$Jf{$3`8NW55Eoz8@6A%DSk_`HT-_4xu zOrDt9Uzu7uT@WJs$BvEPg;*BD>D5n+uqo2wDDE0k)XQ<(rvC!>J`hTD^hM~)sUJREJ#I3q)O6XOuLMccxQtp% zISE=PFL8wk-WMEei`BT?Jg5jJ1?>I8fgaga>Du`x6?IBPrQ_3Rbm?IoTR} zM}f(mG61S~?`q%W=ZhcXq;c>8Uxuq+Db>y!Mb?_eh)R`!JdKJ&?NmqBK|rkQp&GVFHH@XWd3=mggw?|&F@{URF3ZfCRhqlvkXfgmLBN1 zw>oDuAyPJ@KcW&OvVo!y800M)^YfD%u5?7erCU238OBh}9uabX-@POqeGFj`+%IMH z$RZ4?>;6)WRgmLO(p`u1g)5HbRP(J-T;A*dhOoH(?D`Fs_!G7deg+VizC%E-H5kFD zs;VMFh8u0^K}YXtg)TK~g?yR-WVbWPqEB)* z^LB2XBDPyBoB$aD>EfW5A-KEBP4gKzZjhjGHvrs~-TSs&nyr%Y;&#kUoH(3_C(v&L z`*g7teUEx?21Z6iU*w1|G^9LJCMp3YCN8e7^HS#Yg@dKGn;U0<3IQ|Ful&HtAy2|4 z4kYVBL))h*JWeOCo;^j=u5kS@H_^G?4`4ux(JJ#nGs~d0y~ya1Qd@m!viV-9ZDP7% zZF|9I0Sy8?=U4-&bmC~ zKgYKLw7$yiC4I|;RZ$v@>#|8r2)+jgWp4`A=f>))-={0l;gAQTdHBrD*p_&ZGF|d+3*SUad+CdeY=#BiW24OUB1ehjI3_sRzFT}e1Eb) z^_eaIC#RN8CixRRv2wTA76A$6jy7HoOf%`$qd1YpNod!aA1}}1 z&3k+7ZujcPNEi#NZ49LH+88q;V$S@dK9pGTx~-+z~i#TX`e-&%)A) zyZb8~Cn7*Ss6rR}6t8cvua7;6kw@1I;8yhX^q_QZuxq)Q{(=<~ZNxhD3+~a?`~;_< zU};5#Qt5=as3_bokew!YzkoNOmEMtRg71;i){p`BxYGpxkZ|tPaWWzfLvPei^x@m?Eg^10XS>q9yq^h9y?`5yHWq~X zij{(l%%J_qn4x!i*I724pM-H&$hdzx(%=7vQaXMhnT4N*=I`ak2IMyVCe?aAhn}Fmblq=61MqYD zn8n7R2L@!tktCIa8I2+Ayg#K4hOqV9^ZE^TO>((dY9vonYaqL=Kl$o$jQ2Y+;d#>k z41SgI!zqvP7~Hq=sgo!vkl-YWIA&^g7jE}`l6F8>t(?mwP6;;&%IR+9Tq*(9CehIB ziwoDK_oAZhwF@?LHMiFtR`mPMFkEK0wQ6JOQ}^2&H|GBDmsYz68{tOM!Nu}Vnc5%9 zra!3a-s{oZS+{YaKirE@#gF)yJ(YP}d}|Wqre)NvX9gLZUs$WV(h~KZG0Yez&hpdn zDe!T@+`Fo{V8xw9g2_h_oCKMeL3st*@AG4C&+@AGzH-Df6!rE}Z{>Ws>cv9g^Ls^I zM2I%cFpz|j)mky@vF{a`n#$sSk{5X43SNK1W*Tw*eSJ6J0rM^&0Bj)EwfuZ6>aVt= zb+RDgoQK30T}emB6J!}ZClsvKw7sqym(};C#Qf43?!`q#mH5LP)WvtLLAv$c7i;nQ zgb4wiyYAb?E~weBUcRv~^7L!~V#iep5Vo#0?PptSeSZ9XV4z#G8t`!B1xWustDR{y z-JjPLyjhhlyRF|J865?%`SwhkQOutwH3Q;>}kUY`yMi!~!EZy>pXkBwfuf=vaAhEtlc|K}OgqgCnW9>d$XS z9m5gJ>K34Ca(WlAzz62Tkiy6O3IiL8aE+NNOtkRh)ZS1|%dg3OLU5-lzPZ+MkUvX}u&Q zQ<5|B#qm?MfcG+gF8&nI|9IE2n0^FP4EZS2zO9rq85u%Bsn0)0Ug)>uRjy1R+kp z(T41qW#F8Vn?uPres%ZfXlS+Z8afjk4zAn|ToaC5=Vu*P6ny#$8be*b^&+mF2Zwc5 zw!)b#-bEbIk(%8ua+j206ee18Sdvd9VhDR)KP5x**YUn@p#$aU|KUXh2B=ghXcLVe zw3UT_+Gk*b&mwuVw#5d=sU(d=0#)c3ON&0j?(7Ewo*~k`Km>*yFxlw0R59iO{6;#~BOyMUh;|dU1Q|XXw+LXgm~M`hH=Ku!Qm!KWXl&Is?#Z%~#}4YJcB>9?a0b8(=Te*mH`M82 z4Nevud)XDhTF}K7V23EhbZ?&;usvLBQU9BMB!}PI#>LJ_;93N-UuyrLkpkaRg#+Kl zBhXUO3F`---m09R;uDK9+(aTj0$E?FwbP0pN33zi_xzj#6-8~E-z1GOzXU$9tJj&t zf4BfhLzUI$nMyR!FN@k+LK$*zbm1cBq|%3r^8nQ?1Z&X2LA5it`wd=89YInLM*^15 zXT>oGTGTfq!9cgUStx5jdW)Xj?VDPBukcMONP`R!pujh!IJjNmq`1=G=qSOwp1UEH z_m>#r+}xru zK;ovmbDK8A-EI=8==sCx-aH3$Luz85qc00Bw92V3c~-q4jk~L)Cul^!w65yYp=Dta zNWp4dhrxYvR_vq>Fs-%@UCaLYXZ|OIT0kI?I*MzZaNEn~u0eSG8mNNHXA0YndXah}AU!f#A- zE18d0o($W@l@*R);M1jgBMo{V8JUkCRj~VqxM8p$L{WyB$qBCzQ0HV)Vn%iL;;wGo zhZ4}s@-GN#(A6<2iV44SLPoZi3L>NCWCj)>ew`UAbSuj%DddL4K(AS;`yN|tP?vL8xx~!!9HH!%Eu=&(e=#9-AmZh zUxuo?yC2x#zSk_tNc*A@9T|yEOsuYD(O}2&l+!}&q5EchHTdyrQ#s9IqU2TE>!twE z{dgL-_xQKMH~(&QKTBpeH!w5%y#Kj#wkq6{~X_^#3W7!to(c^JJe~T zhf}b>xNqhgs7LG3nb;&Sz2I{_xHvQ%gM(`#XXy26HtY-zPrE=oHcOrKTtC?aegV~J z>uYPpT9s!vuw(BjCcP>WcJ|f&*g{kyzLVJbtD_1+ap~}GlDVrDuF3kr#ChkMYQ%y^g&=U-ASD4n60V>E**hKZO7W0 z`i;tE%g@))&&!|otT4}k9S~~23lF{QT-(?n49{_I1YO-(%ah<5+X?6ClNU`Bx5HWD z;e^*^>0HuMQYcTKl9Q3OwzYvN3+QS*@0w-xJr70aq(AQcF~2B#0&I7{ttl1O0qQcC z&fV&2=V*jc_SxSvU`pcFI1l1Jv4jC`2f((nC&XYgE>tf)?G-PbsFjuTKAX}6X-H~G zjLe*zbUZu~S&I28p}341pvsz0^MReMeEkA|5E!5*1x5l{c*Bh+OlH17wfFPq&lB;@ zS1nI~aJ(MW(#*?#-(FTby7G7M-4FR=_=qPHJT8cVqH50yf3a!w*g$JTTb{;6?8METgEdv zz;1>z1Uam3veVP2&4$mL1S(DX{~h@@gP6Pp!mUwxSvX%nuNIZoJ8kp_Z4&4YT&`Vs z37UosBjjGb2Gjc@kNtp-Frnw@`5%6qq3*mtSP0$gqnrq1?zN%XAhlk_+8fSW8)H61 zSS%!u3peK|5feh_$(NNEf&b+*Pw(Kq)SU|VNc+iWGZd)drQ3aN$S(C3L!(LF#uJ24 zv#mybdZq-J_UU4W0J~Ns`6o1D&BG3Di3o(|c%_0CvCFVG->P=nc8 zbzWYc7ENFfqpO>qRndo=pPvR(_`xXQ`vRr=$zMG^Jps!zN6=M1f}GM#4qM}~u&_X% zH(p@e3s7^)(gr$_is8*uXv^={Sb|o&j7c%`3FO z_kGIpUqt!dhRc!{el1{tLgZ*DaLJEqCbZR`?0peF!4`Hy`w+4dFNH&puX(-Ky zKw7Gx;ANY5SmulMwRk;%Xa;nyym(_$#7w-P+7V7T1FmrD#)9toU5ReJ=dl34vNAwr z#u`0p_4qyRu4ZhTn7!vzw%}AY%_T{CShc)_p9INzUqWwX5C8tk9%Y&Bl7)VK)Z!I_?`E=SDL}(sL-)^9XstC!XQ1~-tDQ6j?hcIX>>n3>;UGKU7H?e2 zSo(@i!213!mR{YE6VM%|C2ZiBa@lx!>-P?Ut3^(BcGsGNtU@HL0@K3UYl4rZeDC_> zqh|!{X3K%%4?Y{E%{NDdNep(qc8W4(fz)O1J*GCL1qNg3pvX|>Ytu(6i@{ zixHrs9)6u-Nu0`<;uPy`i9^R*VI)5{ZRv{2gcU6orG@gla-MUPH!)4D(>!qBV52LlA%^R1cY1BaFd>!W-844 z^#B&DP}D~C^jMrn4WSpOOH@=;q{!v!F!>nW{6sHy2AiBklIj*E7fqh-{uyu*M})wn z66W33k;MF6N%#@eiB;IUVBWUb$fxzP@9bqC6CzX`joU|2$(dACQiwV)e>U{_#a2C* z+QVIo6*SMvOPGoI+@koxthw0v>T7w(oaqknPN9It5=j!Ow&`5%8#77*ZewT6x1{}> zcrwZd^GzX2GsVxs2>*YAc750Qe@469;o`~|3;&A?u-N^_7htf&Q(uW$ZS6_Eb#)=N zDA@NG$C77}Sr!rGoKn%y7oIhI3HfT#mlH%kUeBt-wU)GF2JAC%EUL9~pIZOLZ6!yL z9|Lm2t10xrF@0&);GqB9QNtf%)VV;y*1GTS0I00%G0P7=+~0vbTzMTv`r2N%{A|Uf zEy>>oP}jh~JZ!r_S(I<^71xEh(<_SrxL+3K@Ads2I9M|hpcgw{Z={InZqT#s7|sHP z9}QcqYGQx4wbs)PPr;+(qqwFc3nAY+Fl%gdKed{uDVCrhU^A(TH*UT#h|yoZe2O=W zeY;LrO86|;G}W7qn)AH%@+qhOIx(wmXQ-6e51Q+06eJ~9a%Fh&Yy_fir=shAB@H+7 zI*R`}xaIw!dro|ix5CC?b<9nclh9Hw-izf8QfQr50G87jV#B)$#!iV=2 zSB$(wM^9HPEU*6u=iAK`4UKz>#{{%hpHOehEl#JWG5FeAPo8@Yn^f-2Hv$3_KciNa z&d>L$z~zN2-A7jx9zy+OI2@g0sa^^ia^Uh}KOLs2*2`G-LWkAS_SS0dyGea*(9Yc| z6reUjt2WFd%yHa1lI(Ei?uezMMB|&FpJ?OysG*DGG2{xL!+{FD)H86_(I%RkZ2$in z;re~rJfu&j+2n~xO2N)vp5t%~`DW(LH!77zvGR7F7j4T9 zRhph27VXRe0Pl2X_??D>=hAX}u(DpmcSOi~re*v3Tjj7ONcbW`hv*Bc`^S3Yqin1kHaGat zG!?ZVhj}Ywb5y`oDlw}ygr0FoOjIx{a^N|JsH2L!_N{Wtmhe#SCiNOLM)5%004U?1Ia`f7^n~#M$Gr`Kaaw39tXfdO_$EwZ+0DF z+^~iHNjM1f5}JosmR}^l_}?ke#e&*fz0}W9v5w zmBX6`ogQdPgF|!+ozzbgzWBaE(h<=+utzP zI-Dkgeh8ra;9_sAZ)~is&wthxXWUB3PP9Wy)7+t}DO+=vqs-xL@5u^iw~6yi(Tn)9 z91{>1^zL2#8|9K$rt{A zCovX<%?qlhYAilRyn!TE0^{MMcnOV6XyzsHC<4XJ$(6P|I~TpFb2Ym&@0@^%;4|QH zpi%DmqPN1iURT)=O+uPiL9>!0JDtR*dnAX=R0a(N#r^J*8vxN$o-@7RC1W{W)Hqj9 z1jsZs`U_3BS7*fq1wamMX8bk_$(z;lyMyK&eHgyA3b+&1O zxuciIvD#QSSKGD#)yy(?2mHjgV1AlOjveRgbw>S1zksX7Jm_U5W2nrkr!SB75CEy} zhf;o^QDEep$JzMT{;R#Zb3Eqc($UR8oG$-dMktxbX)D&aSMb`1dt!0s?wm8j6aC zyS1Rvyl-Ne>8aN(0p?C_)>BH2dV)Ul(rhLI+PpVz~X!_>tXdB5*!*7UN&JQQ5hUF{rBBhBp{ zv?DZqxYn582&-hGt2#YpsIFKbs>csMi6Aec!sfcK{<*%;l9FrF^lh51Jfo zY{yBqwO8#tyq*_b-*SJ*C37{&ZgYT{(3USGEMaed2#_~0NBCpXxVx>z>2(<^K|#cM zw)FkGS>g|VqCxQ1ciz2PiU)pzMyN!!+r_o>+>y?9U}FP*O;R~Zk>o)^qUPpLn&xWe z1`T<5sZGZU#^ePq1Jl`NZO&60JzQ=NVwhXb_M4>T<rKEab7EX{(wMC9FaFaLLlK$MN63{dxY}`}lWfJDkvPPOz}9BtD(aJImNG zDJfO13nluA@9B9Nbae@GzmFodI}&$JbMb~%gpsn)j0*UEo2^MPcQol#;(n_J)a??;==LsAGEjV%LLBJpO#GGgk?ZAGDtkaI zCz){7SN#|1u!)z>P>`U&Oi<}K}$XmPC?rjaBD*St_g=pfZZ&MSMV% zq-3dd%|L|o*ki=oZG?mw-4F-REv|lrx2BNAP2I5OAVm8$#Lj3yV|Jxi!iOF)V^}^V zLxmNgJrDlttYW$;J$R@3gG{-fS3oZIPowz{+VpRv!UMwa&*%R=5#&F5vHz7H-)yJT zq?>J}#i0G0N^nricB3EA)!(1L49p01$I$a zVI<_yku3N8ee)NK_6|(ETpF0fq`@E2#@YW>%E2D`;5&z2Y zBCkjhpejGI4^lxHw55b}VIujK z<)<+$ZVp zB&|LF`DG_`3V#^~H=ba42!#u+vrdR1?uqDQRG9u7yYH=gxZA?mN(mwi7;u1n%@p5h zJS&<^Tc9Nxse{teZ|u^mG%EXM}igE?-jYcQlV_kVPG_`zwfQby{loU!@$< z_q)+q=?yGB{&m`%Cz1FX^oCXoAkg(CulG&g=IHZm_TL@OyACeE*^k)gW=e>)QJ_e@ zR3*_w4m1Zh7l+zof?$HTyS}fhfpSr&yH9EqQ$HmjH(*m4Bf!OG1cnHvbZZ>8O zK|^FR@SW)8OP&3x!nrpNxqwW>{go}LUjxU5$?$W+8qNokd}OxX+tm-Niu1^ z9x%xAW@3^xOVh)w!U43)E(zwh+M1d#u(7k1^7rZrPsfS~BqbS7+*3$o0h|D$2KC31 zWT@h)si_|Ut8YHho7}~QT%Q@MvXJngdY25 z_)--~lVz+I`OfEt)N^kZwlWr-^TWCR1|}X+NVy#uO@{de zBH`z6+rG`UYI$wkV-);>k7)4Z#US`D8#6N?i1iq75QbCAeZrdgl_K}?Beq&=%D{!a zA>1#M%6@m}0WeehN-Su@Knn}#VcyYXvw4rbQ4BAvi2dl>X9zJcQ>4$oy*`?kLE`!p zI}5#>iMib!xfe5zQV&-Hmyc**CBv^)+sd%Ro6Eg*!=y6FgeEl?X-MdcSqN#eqZwL? z43jB0dn6E!jlAS@mAJ5T*%&zO^$FP;ZsY~j0aWO7XlQsyND=4SoQum@@3Ad4U|T;V z^EKUje;U^CkEq|oz`zZTwG)4*sA6Ts0KMdL9Wtq$cYF6#7EUO>W~ra-*Y@EEIMhdh z>l*LB9oae?HPxN@X0&@Lr{2~TR3*cux_Eq^5uIgPw#TSVa^+9%l(a?r7W@(b^Ttla5gWR&y7vIX& z*z8wLs|9o_^n6d)!f+^64T9IXpmd}Rzf6tzM*UA0CFFshhM3##WSOxX>YBRZP2o`vtEcpK&PJ@YRl+{M}~MQFhkDVTPKjk5#)D^1I$4Y5xXe7tPFlzK}32Xu=WW_>5!w~0-T&etL`N(dHf4CNi&pp`b zV|#EVC9lfLW*ZuIc8a#OCRORNL}kKA>F7pGN_+bIS>o_51U1Rsz(8ag#Qc7z(I~kcUxl*>+IFpTa=Cj#$lfI*2U#IIdmUtt;~>f&na3U> zo9xZ=>Gyk{KOTSKx}3}TuJa!E{kp+%{8UW{R1An)kPE|TpP{J zBDJWm*hWsJTaS8?&<|qddw=SFVb~C$86<7P!T`dE*<1px#89jitgXt7GsIJIN7}!3{<2g6dV#13^0~U8t_CfA9qq%c)a`- zX{#mazOivx8eVHe$y*d}c{pphBU%!1_l(2nM0ceUz zy!zPCZp+Og7)o3{q`CO}1xN%iTDQap(Z)v7p!MDc5h%R8KEJ!U(0+>G%`nOaAS9Su zJ%cS9c0IQyzU|#@X|5bZp_u%)hM1!|JcC!yz+P(JXLEZW4(ADllWZH>qrIdutn<|h zZ2vife*FA-yP(hNAV?vCKdptCEWF@F@=UptZ0tu;HQ*mOnY(!nCdckfX+t(?higmU zzds(7k>qJmt=#4DK>7mbbpsR?J5p+PPdokqU&SYXuWAz} z%6~(y?(XjY%0CWigm}2Q=?bO8+V>WfHUlpgI~#S0M{TYptvx`rtUs~?Scs!#rkqg* z9?KsWbFPKty)LN0(8z1|iuh!A-gK5NoXx4!7z^?Zyk6-S)jePN`m!seO7{A2Bt^t& z*4ei{`Lk{bxI95xuiC~~3CAm*vNNEjp7*&(MtnOUnFfAvsI9Gm{xkW7C14*E8x9W2-hd3E%e?1o(b6(!jf^j+mmgJG0cNVY?8RjS z|D&-~tM9%1`MJ5;+S)JD4sEcciCJ=0(_TDo5F@eytH0mg%=C*k@2{!43atrk}C;oVSC_AHrj) z!Ab;jjXjk6?u@^ubxMA}l`B|~=<84N_Tu8=4y1@2ta$UQSXMT!Xq1d$Y_vA;U!pmb zps!8YmG2F|JUUt*9c2uT87o24OL&n$K%KJkw&7Xc{tAr|R=>ar=zB2h#(7s=jdh1gkv*wJYBvwC>#~XP7Q`Na;ANojc>DIP z0_z_jg()+>%6D2wQnm!sN0;L*>kq=TES8FjiV6xisw2SK<8v}w7h=8a1dmb1B?8M7 zI2wrHUEjXtH)`stOjFDOj&&M%wu#SP$YZQqjk9I(9O^*#L@Ey;uZU!!b5NebbbL_F zz!_4Uz@s%)=PAa(p`L*dPQ{SR(*z~29Nv9b)kY80>TDgl+8#Zyc?1GXoNjh5fLG|- zqyrd>?w0x@!DdDNVZyT^FeEH2R5p_WMuqP+Uu`w|>&x`&UpK$>#lgV=m!c(_Sk|cC z`El0EK5+bgHt?SsOUpcfZEw8Vp03H^>~VO+1Q4HV6&A2M-=5DLp=iRyD6{j?g3f4P zJ?;eXf8QLA>;Pg^&9`ryVq&L18wN!e=;o+t=NV};_Z#h0xZ_dh8^eH)ra|uhd$~Iu z>5-Sm@J){wgqf7+lo8_NJNi}r&Nh$LLlkKY-VSLy!4`R+GCj3^b-pQM)^K_Sw*TQj zjtoqLls9f8W@T>oLP-^Sdn`hC+)K3UKu(C|}{5d!zB=30bdeS-*U5igp zj;7)_;pGuJ!<`i$?AIv*ukot9+-nIqQJc#)CXI;aIqY&^z~C|8FO&rokWR9tAX+Ep=YqI?NPwfjMaY#MfXp#i-HE1qPdoV|!jzSrrmcb@T3eQ0nNj@{boO z!Y=c>ws-j3Kn;<8FvFYt!UM=T(7H|f236SF429l{EmhMs_M#T&LL>Quul0AjVh?YH zM&)wajoip2bibjYp@~R(aImt(Gg0qi0alJb4laRMZyp@;a-QAf6bavB#Lg@dY_1N_ z^8p8_-GK~g9%12NlFGd$^+!%~za_8Na`EpeM%pYB7rUoE3NpW#r%IK%xeRQM0IIhg zV0|K{mvRnLa{GoTgp^Kx?&?sNgG%i~GZQ`Yi>CmfAtWDU8yMSNpx?0rFvdt#7{y|3!+lL!8~70!pi_o4*ls6d7?S-dq z6eX(FnB;KTJ%$-T5FOD!Ep=`%?saBL4Tgn=f-|xOxBZ0N z#f5T)yaahl-nXqCo`a_trks`4pEiXE{|~^6zOwQ_{~TV99NlaO=vQ1wDVo98ebTfao#N~EXeqmnX!9=d-P#)AFPhw z_o!yrfRqbC2~x%8Kr4d#AIod+#n)v@c1<9u_e zVI4;6a(DFEAM!@`O-d@NTTrTK;CB2y`9A;yz&YcUL*8v%8tmkMHkLR=CGE2{VV&vk zAw+ui-zTb%ebJFIAI8GW*+EUgqF&ybrk8a33KajGjR>NG;>V+wQuJ$>-?17 z_G0H3%gF^DQC{W6`60$T|BC=8=KYM9Y}_Hjn!PWDp?)!AhlF;+mBV@?6XqYi@^8K^ zN9j9Ky|5K@>X|j6;?M3rbLb6Kouq5&nLd4W&0)CzVA&v#wFl-A&G_ZCXEc|>b&7bM z(W-o3`Kd5YtBX|cTN8eauhgWaXaSb@=JR=^pnSbMul>B>6N8_zI&%5Vcl}o{SumT! zQ%!2vVLN5vmT&+5Vv>nydv|>mGPL7nWi`tKo4c%e?a&hVtF_TOnqFLUTH93w_YSSF zOWQr@n`JLrH)7huct);5=o2FqCC^!ZI9{1}%XRJUVX_e9td8y-kua~g&z9$J@&Dlg zyt%lQItO?_N>& zK_FeAf`WpAZa? zSMjramQ5iUZPJ$04~IuL=hHHf^0Q}l852#%MPOf_@Qe*|n7^JCIT+%!fjhHH8rry7 zQB4i38mO5fq};Q%M#V=$W_l2QRcZ=RTXdZ-g*W#Mws+J;O$AK$ogctmAFEWHRPjyf zq~5}FDmUNVCG|HA`&zkQJbWAd)5!Ht2)r*Mp@84u!Lq(9oIzm)hK#sFBqtaI&n?o@ zv1)W)#DogRHb8ZZcgy#%-n>U~q3vgcV$P80@7p=`B*iuLr*TdiDsFFbzdC%PS1CV% zcSbW&nY_%-vDnC%ty*0TC7`D#7qgr33|W%_60I4ktvOF*5K`C#$E4 zX*dPlTc>Fgpz%*|eyHm;!gEOM_aqx;P#LmoqkEaCU7R>K*s%r9to+XCdH0* zx;3h5Wfz?;^w1AsiTf$vNw9!RJ8#dW!rhf%EJT~5qyhHg1tIjt(%KOAfcdIOYm6P0 z7eV!jUeL&Y(}?x|?#A`eq8AVz9-bc3>J>oy1gG;I?qS3rK1vNWX zD~L1(PbH60C?Tj;vWdN_)BL2-$RzOybCGMoJHuTAa8R>3CQGQ7R#qfhDe={G8^ z^RXB4A}S3DUzG}WMkFnH4`}anaebqtD|x2sfoxy06wg@F`{drBZ%<(eJJ6YGx{dz< zOXn_hrCj#?{fDp=Q70nE({sn~PajQ+*-nv=<&sc*B)vE*px?{L$N*WSKeD!M`Yh{7 zQYX5waKmiLj=&$E#nRFeI3=1t*SIv4S4`~xV=bI--yE)c&gpxWa4&Yi(-S?uDn;-7 z^Td?s0CXufWLC=~Ej_#9md79_=DoiJcIQJwf;c#5VBC>30KEjRuAQ05(B8X%qCoy9 zWn@EsLL$Cs%Z{tpZiiEXdn08?->VHh!*5!S0YRMS650XY-XR91Al4_Ca}<}#+jz%!1dugz>9j1j|H~Cni|<%yR1Uu`nXsH0NG?DW&a4003+qu4Y^-XH(~{?=Jb)v?2gT9#d6!xvBM?&s2D z)ea@3oVTG~VK%HpY>nbt$!(9h?ufYitTEKVV^AC+c~{(hLGIA4Iu`h{20Nd$MaLnC ziy0|60o+udpB>y6kUBcg_PSJAEi*&FObQ}=q1-h%c;iW`;$wxf%{jidteHUv51ChB zgR_2qUcDhG%)!a2T#okK9Cuv%^<%eLa$im&%e{X<$}@4*JJAx1QA)J#Utuha776tr zVp3D-7#L;&7iW1{9$K3&;D^#wR2`4U5e{w-4O2ubwb>)tdHMNt>^~H(B<1FJ5J9w2 zwfHC&__03Pdc|0DLQhV9G~(Dz<@ z?E$8J%kESjfr17|P6b~=)_tcJ^Jt{UO)ch0=l`BB671_JQL1Q0(D-zbK7Ra|Hp*(D zHTXT&UD#ZoDe{=VOe=Pl@M3HdWo-&ZNzd|VWgH6Q&R$U}b8~a6iR!xVkg-{^fB)_5 zbN;e<&cG?%pugDGKw*SjK@blk_E)IYA;I^l_k;B5tLddY?ojQ-IdEwUr?97MjRc1^1$1E&B zsvtF3U~N@Tsga$Nb8!-_t~N(WGdVPGN(>eC=Q(`#4F8CCg5I2sbdY!Sx)}XK^eob{ z<#KKRU<6A}Ke-~D&Q`-EcK`R((dN-fOkGO$@84^MoRNzQ-~U8tmTZu{n%ka|j)_i7 zj!jOEr6D7mk(CMPiebTh@+G?N}tv5_WM@4C80)T4PI z(xsQk`>1vBuC&;Pn>zlRTavxw(F*;>L!Z2{|@z5gVO#RaRhnwFM29mTvKr)7{|FSm9`% zZL*W;&fgbDSnsM24}D>G#Qe|6A?#bXq|bi5wxsOq>O;s*l2eQgJU9_Lv!XW8k8xJ0 zB}dL)?_|!El$C+D(uv>rT(0t{6joaqE(*9BoMMGHOIKMBEVYouZtN70gy+WcF4M09 zbyG+nwV%rMZHlA1i;Lht5w5QRyD+Swyu7^kO*Y1RjGD~CHMJrBtLYqDwlPg3zq;^m zlAd-~LG2Q5Ud+2Ce#5_h9d|{g<5O03uY+E0lX82f#AP>eYocK@FKN|pA3gX_LTJ`b zw#hD}an|i@=V{M7!$izSEzY-|m#Nx8ZQA1D-`=4*Vl7p`t9gEYe(bpHy<|0U^%5R7 zYIn?XM=i1ZiWtTZr>d?*MVGZe7iYW zz$|D#`}?{N7^M+~VL`a;_h$~&k_4C^@73D%o;%vAtQWsxGLO8v0=AZxA;gh>RdwU! zI!!X%?LyT7VSYOsyijCb9$dxJuSLeiC7MgK+*Zpk#ITM4f>;iJEWB4$;@-}(l`xZQ zL+xZJ3;qF7paAA_71BBOH5glgL&TT^m`JKYUSG_YQ|;-NXHdQO0sFtI3owux?gC{C zkSeRCfA*)m^Rmh@g`7ChSC5O4m=M9YOQBFyTznfcH}|P8!UgAIN2#_tiS{16jf(D3 zS0y3z{Y3WkSN}J~oNRiisi_Hou$YEVFL$~~Es--Z9JoA+4>vrV~r_vJAQQilX(8ujb*JA{YHLHNb-Dn$U-siS;PFaJ6}oegd;&04WdJ zMxdNxkhEE7ePmKP)(>2d`7ey|vJeP|q>?W|apUV_B~8hi&+e^u&wi!z~iA#`%6E63YBVGaA62g6WYt37Xrj#Pr!53Tp*|d z2q^n*fdNCk#p+I&L@@A+Nd{g^tsrPZvvRVtWlRpThHa4^1;W1Lm!O>3KRCcxI9s(I zOcg~ZJo|faKqqO{mqa%nSZ}xT&Fl#suRT|fSL-_ra@EcbP!LKRobkW+47mQO_^&lM zoxbs(;+L5l(JJsul{PmAG|)>hJ1jFf!YC=Da0X}(ZL7U?m63ck|8ZI77&GnJM$b%f ziw?u*NqVI_M5Cnl6dj&lqrqa>SXYr;#CG_pLNi)4%f&kcb=tN?l*ItGj%cCzWdiy) z62NjLj&@A2UY2nt+QF8ePru2gohq}l^Te}1f{}4b*EAUmt|d3y>LG;CZIc}Cq+CyNK)w(k5wS9!BhQ-&DX}N@1B3(1z0HE1f09NUJE##&7gHrmCj=` z==scp4aurZQvr9o;d+hsa~Vo;*i(70kBM5(by5$vghC%zq;SXI?bgFtvlEm_un3jN z(Q6A7$*mmY8y+4GyTdT0=PLYXxkzZKBdX-0#FyOmHYP~GS|KnE?qG*cB{HNQuj|2LJD*I zKA(rL6}8U_GC^0WJE*Tw)W*z zn`oe{ncvOzUg$RgHfdAP#x8aAmp7kxV$EQzxrymqt`9OH{P+a~oF}K9P!cyawY;e6 zvPsG+uGRgO3_(FQwme&~XT&<*mKE?Ec)rk~|LBNR!FINBu&S~W0AZ*nD{>4aZ(Suemf^?;RZvjCjE55vQdDFMK8BpFcjf5L*uCl6 z3-eX|AMqlv6f~p;SO2UqNE|vYxjxxZN*=1W8Hy9kQ6dg7k740`QPCJ{DK08{asiA+ z^k>bF$8G1|e*klRfC|g!yv_3FQEGgA-F*F?lhZZo;uy65{V5_s+{INU<+`_Xi(lls zu2y>NOl|KUx)wQG*sezedSz+7x!+q!6t>ipz{8<->3lfh0y^W#&qG^EdRL1ncRAG6 z(gb8!S>^ZWeozBcxx?AU=3%BiXtsaNkN!)5uj!O5TTT5`AWGVYzL|;CPc$kroJk8=t6F z57GZ%Hr`5f=*zE|<2c^L8|}$0yD(4=l%?;$RMz>KpOS^i)GUnYV!S>>@;nq8#C!*T zbqfcZJZZ+U7s->Uo0yl$&66r-M+%M7qh-V<94f%pR(O^pz{fOV(r9v7V;E``a03QS zI$vTIauVvUq6Q=zn`)rxv-__FXrD86c-gFXxfCQ(hr*bqzOTDcM_HQNSn9if$Y zZ>hg3q;5#(P#UT>=Tl}`e#??eg4rsyE3E(2$!QxA8?ZOz_A2j5NDN2s$1jEzR|RR) zk64vHvVvrUQjPoAZGoiVgsEmo0a$VFdX>S|Ru(62sX>iRP?j$CwzIZAeNbfUpt@@f zbuB|lbB0qEmqxE3p{jL zHjR!CDWM!1=g%MbA!IVJZy9Y&8OP1WX2GT|NNaXE_W2o+WA5uoSfvk3 z?qg34*`-+<@=U9HMTkITIT9@|3zlHscyxu`)o;jeEN;yHQ3SMaZlU&hqm6+^-AD^; zDEK2i3p`kknFKFdf?PG4L6Q~%>nn7kw9f-_CKGr*ytgFLQEI5px*)k_lfvwqfvRX< zLVj^3fU}OP_hQ@8^u)JSZXqa(BcQ7;H>us>((>-(w7q=DnwiA~ zHvKlaA@Y6~gwAUD(QVNw={km%w+qWSyuEl3iMVR?e-8}_BMG@egTqY57Tv`Q`ML}< zgKiBLd`bwe>0K<`oD@NSF=%upvz=X8QF5J0@}CO@8*?#hE$;8Hg-%}u_b9xl5E=$z zC;E{3&UG%-@Bi;*6CZrngQdYAay_GesSJAv{BJMnT|9 NMM3Rpnf&XZ{{b+QRmlJV literal 0 HcmV?d00001 From 542dd27cfa700ddbad0d19cda0f0c88b5f82cb74 Mon Sep 17 00:00:00 2001 From: Daniel Abraham Date: Wed, 7 Aug 2024 17:56:47 +0300 Subject: [PATCH 27/33] resize screenshot --- task_chain/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/task_chain/README.md b/task_chain/README.md index ae8f4819..b24ac1ae 100644 --- a/task_chain/README.md +++ b/task_chain/README.md @@ -6,7 +6,7 @@ The workflow is resilient to errors in each step (with the ability to retry each failing step on-demand), as well as server-side failures (thanks to AutoKitteh's durable execution). -![Slack screenshot](./slack.png) +Slack screenshot This directory contains three variants of this project: From 95575ad64f5f625eff8cef33188f63d0fcefba34 Mon Sep 17 00:00:00 2001 From: Daniel Abraham Date: Wed, 7 Aug 2024 18:01:57 +0300 Subject: [PATCH 28/33] tweak size --- task_chain/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/task_chain/README.md b/task_chain/README.md index b24ac1ae..48ebd9d8 100644 --- a/task_chain/README.md +++ b/task_chain/README.md @@ -6,7 +6,7 @@ The workflow is resilient to errors in each step (with the ability to retry each failing step on-demand), as well as server-side failures (thanks to AutoKitteh's durable execution). -Slack screenshot +Slack screenshot This directory contains three variants of this project: From d4837c68e684f59ecbfc9833b0fc04c347c95987 Mon Sep 17 00:00:00 2001 From: Daniel Abraham Date: Wed, 7 Aug 2024 18:17:29 +0300 Subject: [PATCH 29/33] Add another screenshot --- task_chain/README.md | 4 +++- task_chain/images/slack1.png | Bin 0 -> 48253 bytes task_chain/{slack.png => images/slack2.png} | Bin 3 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 task_chain/images/slack1.png rename task_chain/{slack.png => images/slack2.png} (100%) diff --git a/task_chain/README.md b/task_chain/README.md index 48ebd9d8..1a816982 100644 --- a/task_chain/README.md +++ b/task_chain/README.md @@ -6,7 +6,9 @@ The workflow is resilient to errors in each step (with the ability to retry each failing step on-demand), as well as server-side failures (thanks to AutoKitteh's durable execution). -Slack screenshot +Slack screenshot 1 +  +Slack screenshot 2 This directory contains three variants of this project: diff --git a/task_chain/images/slack1.png b/task_chain/images/slack1.png new file mode 100644 index 0000000000000000000000000000000000000000..884a64298d05313145e364315025f847db6d1c87 GIT binary patch literal 48253 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 Date: Wed, 7 Aug 2024 18:18:12 +0300 Subject: [PATCH 30/33] Remove whitespace --- task_chain/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/task_chain/README.md b/task_chain/README.md index 1a816982..01683bc2 100644 --- a/task_chain/README.md +++ b/task_chain/README.md @@ -7,7 +7,6 @@ each failing step on-demand), as well as server-side failures (thanks to AutoKitteh's durable execution). Slack screenshot 1Slack screenshot 2 This directory contains three variants of this project: From ff54665ec1de8cd26003e87daf7db1a45daef3f3 Mon Sep 17 00:00:00 2001 From: Daniel Abraham Date: Wed, 7 Aug 2024 18:21:32 +0300 Subject: [PATCH 31/33] Flowchart tweak --- task_chain/README.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/task_chain/README.md b/task_chain/README.md index 01683bc2..bfa71d93 100644 --- a/task_chain/README.md +++ b/task_chain/README.md @@ -31,18 +31,16 @@ flowchart LR task4[Task 4] message{"`Retry/Abort Message`"} - error(("`Workflow - Error`")) - success(("`Workflow - Success`")) + end(("`Workflow + End`")) subgraph Workflow 1 direction LR slack -. Slash Command .-> task1 --> task2 --> task3 - task3 -- Success --> task4 --> success + task3 -- Success --> task4 -.-> end task3 -- Error --> message message -- Retry --> task3 - message -- Abort --> error + message -- Abort -.-> end end ``` From 31677c12b34252f2a45df25fd158f2a0fa70580e Mon Sep 17 00:00:00 2001 From: Daniel Abraham Date: Wed, 7 Aug 2024 18:22:14 +0300 Subject: [PATCH 32/33] fix flowchart --- task_chain/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/task_chain/README.md b/task_chain/README.md index bfa71d93..c3363a04 100644 --- a/task_chain/README.md +++ b/task_chain/README.md @@ -31,16 +31,16 @@ flowchart LR task4[Task 4] message{"`Retry/Abort Message`"} - end(("`Workflow + wend(("`Workflow End`")) subgraph Workflow 1 direction LR slack -. Slash Command .-> task1 --> task2 --> task3 - task3 -- Success --> task4 -.-> end + task3 -- Success --> task4 -.-> wend task3 -- Error --> message message -- Retry --> task3 - message -- Abort -.-> end + message -- Abort -.-> wend end ``` From a52baace80337f3cade403441145a2ed779921cf Mon Sep 17 00:00:00 2001 From: Daniel Abraham Date: Wed, 7 Aug 2024 18:23:48 +0300 Subject: [PATCH 33/33] fix flowchart --- task_chain/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/task_chain/README.md b/task_chain/README.md index c3363a04..4a27aed9 100644 --- a/task_chain/README.md +++ b/task_chain/README.md @@ -40,7 +40,7 @@ flowchart LR task3 -- Success --> task4 -.-> wend task3 -- Error --> message message -- Retry --> task3 - message -- Abort -.-> wend + message -. Abort .-> wend end ```