From 02bfe7f6b5bd738df096a1fc8378ba6f49ff83ac Mon Sep 17 00:00:00 2001 From: Ludwig Holl Date: Wed, 6 Nov 2024 13:12:06 +0100 Subject: [PATCH 01/61] updated issue templates --- .github/ISSUE_TEMPLATE/BUG.yml | 61 ++++++++++++++++++++--- .github/ISSUE_TEMPLATE/FEATURE.yml | 55 +++++++++++++++++---- .github/ISSUE_TEMPLATE/ISSUE.yml | 79 ++++++++++++------------------ 3 files changed, 132 insertions(+), 63 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/BUG.yml b/.github/ISSUE_TEMPLATE/BUG.yml index ab864385..a6a4b49a 100644 --- a/.github/ISSUE_TEMPLATE/BUG.yml +++ b/.github/ISSUE_TEMPLATE/BUG.yml @@ -1,24 +1,73 @@ name: 🐞 Bug title: "[Bug]: " -description: Something doesn't behave as it should. +description: A bug that requires attention. labels: ["bug"] body: - type: textarea id: current attributes: label: Current Behavior - placeholder: The car doesnt see a traffic light on Map1. + description: Describe the current, unexpected behavior. + placeholder: The car doesn’t detect the traffic light on Map1. - type: textarea id: expected attributes: label: Expected Behavior - placeholder: The car does see the traffic light on Map1. + description: Describe the expected, correct behavior. + placeholder: The car should detect the traffic light on Map1. - type: textarea id: reproduce attributes: - label: How to reproduce the issue + label: Steps to Reproduce + description: Provide steps to reproduce the issue. placeholder: | - * Start the simulation with Map1 - * after 600m the car won't stop at the traffic light. \ No newline at end of file + * Start simulation on Map1. + * After 600m, the car should stop at the traffic light. + + - type: textarea + id: definition_of_done + attributes: + label: Definition of Done + description: Criteria to consider this issue resolved. + placeholder: | + - The car detects traffic lights on Map1 correctly. + - The issue no longer occurs in similar scenarios. + + - type: input + id: effort_estimate + attributes: + label: Effort Estimate + description: Approximate effort required (e.g., hours). + placeholder: Enter effort estimate. + + - type: textarea + id: testability + attributes: + label: Testability + description: Describe how to test the fix. + placeholder: Describe testing steps for verification. + + - type: textarea + id: dependencies + attributes: + label: Dependencies + description: List any dependent tasks or issues. + placeholder: Link dependencies here (e.g., #123). + + - type: markdown + attributes: + value: | + **Add Priority Label**: + - p1: Immediate attention + - p2: High priority + - p3: Standard priority + - p4: Low priority + + **Add Group Label**: + - perception: Related to sensor processing and scene understanding + - planning: Related to path planning and decision making + - acting: Related to vehicle control and actuation + - research: Related to research and experimentation + - infrastructure: Related to system infrastructure and setup diff --git a/.github/ISSUE_TEMPLATE/FEATURE.yml b/.github/ISSUE_TEMPLATE/FEATURE.yml index 65b5c9a6..80f6b3ac 100644 --- a/.github/ISSUE_TEMPLATE/FEATURE.yml +++ b/.github/ISSUE_TEMPLATE/FEATURE.yml @@ -1,20 +1,57 @@ name: 💡 Feature title: "[Feature]: " -description: Something we should implement. +description: A new feature to be implemented. labels: ["feature"] body: - type: textarea - id: desc + id: description attributes: - label: Description - description: Short description about what to do. - placeholder: The vehicle should detect traffic lights and it's states. + label: Feature Description + description: Provide a summary of the feature. + placeholder: The vehicle should detect traffic lights and their states. - type: textarea - id: dod + id: definition_of_done attributes: label: Definition of Done - description: What is required to mark the issue as done? + description: Completion criteria for the feature. placeholder: | - - 90% of the traffic lights are detected - - 90% of the traffic light states are detected correctly" \ No newline at end of file + - Detects 90% of traffic lights. + - Correctly identifies 90% of traffic light states. + + - type: input + id: effort_estimate + attributes: + label: Effort Estimate + description: Estimated effort (e.g., in hours). + placeholder: Enter effort estimate. + + - type: textarea + id: testability + attributes: + label: Testability + description: How will the feature be tested? + placeholder: Describe test cases and success criteria. + + - type: textarea + id: dependencies + attributes: + label: Dependencies + description: List any dependencies on other issues. + placeholder: Link dependencies here (e.g., #456). + + - type: markdown + attributes: + value: | + **Add Priority Label**: + - p1: Immediate attention + - p2: High priority + - p3: Standard priority + - p4: Low priority + + **Add Group Label**: + - perception: Related to sensor processing and scene understanding + - planning: Related to path planning and decision making + - acting: Related to vehicle control and actuation + - research: Related to research and experimentation + - infrastructure: Related to system infrastructure and setup diff --git a/.github/ISSUE_TEMPLATE/ISSUE.yml b/.github/ISSUE_TEMPLATE/ISSUE.yml index 0ebbfe5d..45ec9c37 100644 --- a/.github/ISSUE_TEMPLATE/ISSUE.yml +++ b/.github/ISSUE_TEMPLATE/ISSUE.yml @@ -1,78 +1,55 @@ -name: "Issue Template" -description: "Template for creating issues" -labels: [] -assignees: [] +name: "General Issue" +title: "[General]: " +description: Template for general issues. +labels: ["general"] body: - - type: markdown - attributes: - value: | - ## Please fill out all relevant fields: - - type: textarea id: description attributes: - label: "Detailed Description" - description: "Describe the issue in detail" + label: Detailed Description + description: Describe the issue in detail. placeholder: | - Enter description here + Enter description here: - What is the problem? - - What is the expected behavior? - - What is the actual behavior? + - What is the expected outcome? - type: textarea id: definition_of_done attributes: - label: "Definition of Done" - description: "What needs to be completed for the task to be considered done?" + label: Definition of Done + description: Criteria for considering the task complete. placeholder: | - Example criteria: - - [ ] Implementation completed and tested - - [ ] Documentation updated - - [ ] Code review passed - - [ ] All tests passing + - Implementation completed and tested + - Documentation updated + - Code review passed + - All tests passing - type: input id: effort_estimate attributes: - label: "Effort Estimate" - description: "Estimate the effort required (e.g., in hours)" - placeholder: "Enter effort estimate here" + label: Effort Estimate + description: Estimate the effort required. + placeholder: Enter effort estimate here. - type: textarea id: testability attributes: - label: "Testability" - description: "How can the implementation be tested?" - placeholder: "Enter testing methods here" + label: Testability + description: How to verify the issue's resolution. + placeholder: Enter test methods and validation criteria. - type: textarea id: dependencies attributes: - label: "Dependencies" - description: "Are there dependencies on other tasks or systems?" - placeholder: | - Enter dependencies here - - Task A must be completed before this task can start - - Link issues here with # + label: Dependencies + description: List dependencies, if any. + placeholder: Link dependencies here (e.g., #789). - type: markdown - id: prioritization attributes: value: | - Add a priority label to this issue (p1 to p4) based on the following criteria: - - p1: Critical issue that needs immediate attention - - p2: Important issue that should be addressed soon - - p3: Issue that should be addressed in the near future - - p4: Issue that can be addressed later - - - type: markdown - id: labels - attributes: - value: | - Add any relevant labels to this issue: - - standard labels: + **Add Standard Label**: - bug: Something isn't working - enhancement: New feature or request - help wanted: Extra attention is needed @@ -81,7 +58,13 @@ body: - question: Further information is requested - wontfix: This will not be worked on - project-specific labels: + **Add Priority Label**: + - p1: Immediate attention + - p2: High priority + - p3: Standard priority + - p4: Low priority + + **Add Group Label**: - perception: Related to sensor processing and scene understanding - planning: Related to path planning and decision making - acting: Related to vehicle control and actuation From 75e7297704dd864d456b75a5414224aab9642ddf Mon Sep 17 00:00:00 2001 From: Peter Viechter Date: Wed, 6 Nov 2024 16:48:44 +0100 Subject: [PATCH 02/61] Debug wrapper WIP --- build/docker-compose.leaderboard.yaml | 6 +- code/debug_wrapper.py | 123 +++++++++++++++++++++++ code/perception/launch/perception.launch | 2 +- code/perception/src/debug_wrapper.py | 1 + code/perception/src/lidar_distance.py | 20 +++- 5 files changed, 148 insertions(+), 4 deletions(-) create mode 100755 code/debug_wrapper.py create mode 120000 code/perception/src/debug_wrapper.py diff --git a/build/docker-compose.leaderboard.yaml b/build/docker-compose.leaderboard.yaml index 32fc98fc..126f3d09 100644 --- a/build/docker-compose.leaderboard.yaml +++ b/build/docker-compose.leaderboard.yaml @@ -8,4 +8,8 @@ services: extends: file: agent_service.yaml service: agent - command: bash -c "sleep 10 && sudo chown -R ${USER_UID}:${USER_GID} ../ && sudo chmod -R a+w ../ && python3 /opt/leaderboard/leaderboard/leaderboard_evaluator.py --debug=0 --routes=$${ROUTE} --agent=/workspace/code/agent/src/agent/agent.py --host=$${CARLA_SIM_HOST} --track=MAP" + command: |- + bash -c "sleep 10 && sudo chown -R ${USER_UID}:${USER_GID} ../ && \ + sudo chmod -R a+w ../ && sudo mkdir -p $${XDG_RUNTIME_DIR} && sudo chmod 0700 $${XDG_RUNTIME_DIR} && sudo chown -R ${USER_UID}:${USER_GID} $${XDG_RUNTIME_DIR} && \ + (rqt_console &) && disown -a && \ + python3 /opt/leaderboard/leaderboard/leaderboard_evaluator.py --debug=0 --routes=$${ROUTE} --agent=/workspace/code/agent/src/agent/agent.py --host=$${CARLA_SIM_HOST} --track=MAP" diff --git a/code/debug_wrapper.py b/code/debug_wrapper.py new file mode 100755 index 00000000..f1cecd9f --- /dev/null +++ b/code/debug_wrapper.py @@ -0,0 +1,123 @@ +#!/usr/bin/env python3 + +import importlib +import importlib.util +import os +import sys +import argparse + +import rospy + +DEBUG_WRAPPER_MSG_PREFIX = "[debug_wrapper]:" +TYPE_PARAM = "~debug_type" +PORT_PARAM = "~debug_port" +WAIT_PARAM = "~debug_wait" + + +def eprint(*args, **kwargs): + """Print to stderr""" + print(*args, file=sys.stderr, **kwargs) + + +def logfatal(msg: str): + """Only works after ros node has been initialized""" + rospy.logfatal( + f"""{DEBUG_WRAPPER_MSG_PREFIX} FAILED TO START NODE - NODE WILL NOT SHOW UP: + {msg}""" + ) + + +def logerr(msg: str): + """Only works after ros node has been initialized""" + rospy.logerr(f"{DEBUG_WRAPPER_MSG_PREFIX} {msg}") + + +def loginfo(msg: str): + """Only works after ros node has been initialized""" + rospy.loginfo(f"{DEBUG_WRAPPER_MSG_PREFIX} {msg}") + + +def logdebug(msg: str): + """Only works after ros node has been initialized""" + print(f"{DEBUG_WRAPPER_MSG_PREFIX} {msg}") + + +def get_required_params(): + try: + result = {} + if not rospy.has_param(TYPE_PARAM): + logfatal( + """Missing parameter to start debug wrapper: debug_type + Add it in the launch configuration""" + ) + result["type"] = str(rospy.get_param(TYPE_PARAM)) + if rospy.has_param(PORT_PARAM): + result["port"] = int(rospy.get_param(PORT_PARAM)) + else: + logerr( + """Missing parameter to start debugger: debug_port + Add it in the launch configuration""" + ) + result["port"] = None + result["wait"] = bool(rospy.get_param(WAIT_PARAM, False)) + return result + except BaseException as error: + logerr(f"Failed to get required node parameters: {error}") + raise error + + +def run_node_at(path: str): + try: + runpy.run_path(path, run_name="__main__") + except BaseException as error: + logfatal( + f"""Failed to run node module at {path}: + {error}""" + ) + raise error + + +def start_debugger(port: int, node_module_name: str, wait_for_debugee: bool = False): + debugger_spec = importlib.util.find_spec("debugpy") + if debugger_spec is not None: + try: + import debugpy + + debugpy.listen(("localhost", port)) + loginfo(f"Started debugger on port {port} for {node_module_name}") + if wait_for_debugee: + debugpy.wait_for_client() + except BaseException as error: + # Yes, all exceptions should be catched and sent into rosconsole + logerr(f"Failed to start debugger: {error}") + else: + logerr("debugpy module not found. Unable to start debugger") + + +def main(argv): + """# http://wiki.ros.org/Nodes: 7. Special keys -- __name is the node's name. + # In this case the name is set by the launch file + # Todo: when using rosrun, the name also has to be set somehow + ros_node_name: str = __name + # We have to init the node to be able to log and access parameters + rospy.init_node(name=ros_node_name)""" + node_args = rospy.myargv(argv=sys.argv) + parser = argparse.ArgumentParser( + prog="debug wrapper", + ) + parser.add_argument("--debug_node") + parser.add_argument("--debug_port") + parser.add_argument("--debug_wait") + args, unknown = parser.parse_known_args(node_args) + + base_dir = os.path.abspath(os.path.dirname(__file__)) + logdebug(f"Node {ros_node_name} started at {base_dir}") + params = get_required_params() + if params["port"] is not None: + start_debugger(params["port"], params["type"], wait_for_debugee=params["wait"]) + target_type_path = os.path.join(base_dir, params["type"]) + run_node_at(target_type_path) + + +if __name__ == "__main__": + main(argv=sys.argv) diff --git a/code/perception/launch/perception.launch b/code/perception/launch/perception.launch index 8d6072e7..f194174c 100644 --- a/code/perception/launch/perception.launch +++ b/code/perception/launch/perception.launch @@ -75,7 +75,7 @@ - + diff --git a/code/perception/src/debug_wrapper.py b/code/perception/src/debug_wrapper.py new file mode 120000 index 00000000..e4e2c378 --- /dev/null +++ b/code/perception/src/debug_wrapper.py @@ -0,0 +1 @@ +../../debug_wrapper.py \ No newline at end of file diff --git a/code/perception/src/lidar_distance.py b/code/perception/src/lidar_distance.py index 04394ee2..93ab1bc2 100755 --- a/code/perception/src/lidar_distance.py +++ b/code/perception/src/lidar_distance.py @@ -120,7 +120,6 @@ def listener(self): Initializes the node and it's publishers """ # run simultaneously. - rospy.init_node("lidar_distance") self.bridge = CvBridge() self.pub_pointcloud = rospy.Publisher( @@ -246,6 +245,23 @@ def reconstruct_img_from_lidar(self, coordinates_xyz, focus): return dist_array -if __name__ == "__main__": +def ros_init(): + """Initializes the node for basic ROS functions. + + Must only be called ONCE and not as part of def main() + + Required for debugger entry""" + rospy.init_node("lidar_distance") + + +def main(): + """Main entry point of this node + + Required for debugger entry""" lidar_distance = LidarDistance() lidar_distance.listener() + + +if __name__ == "__main__": + rospy.init_node("lidar_distance") + main() From 4ef21fcc0fd686663ec395a781a949e4cfd9debc Mon Sep 17 00:00:00 2001 From: Peter Viechter Date: Thu, 7 Nov 2024 03:16:15 +0100 Subject: [PATCH 03/61] Basic debug wrapper working --- .vscode/launch.json | 23 +++++ code/debug_wrapper.py | 123 ++++++++++++----------- code/perception/launch/perception.launch | 2 +- code/perception/src/lidar_distance.py | 6 +- pyrightconfig.json | 25 +++++ 5 files changed, 114 insertions(+), 65 deletions(-) create mode 100644 .vscode/launch.json create mode 100644 pyrightconfig.json diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..e7ed6ee0 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,23 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Python Debugger: Remote Attach", + "type": "debugpy", + "request": "attach", + "connect": { + "host": "localhost", + "port": 5678 + }, + "pathMappings": [ + { + "localRoot": "${workspaceFolder}/code", + "remoteRoot": "/internal_workspace/catkin_ws/src" + } + ] + } + ] +} \ No newline at end of file diff --git a/code/debug_wrapper.py b/code/debug_wrapper.py index f1cecd9f..88486091 100755 --- a/code/debug_wrapper.py +++ b/code/debug_wrapper.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -import importlib import importlib.util import os import sys @@ -14,9 +13,13 @@ WAIT_PARAM = "~debug_wait" -def eprint(*args, **kwargs): +def printdebug(msg: str): + print(f"{DEBUG_WRAPPER_MSG_PREFIX} {msg}") + + +def printerror(msg: str): """Print to stderr""" - print(*args, file=sys.stderr, **kwargs) + print(f"{DEBUG_WRAPPER_MSG_PREFIX} {msg}", file=sys.stderr) def logfatal(msg: str): @@ -37,47 +40,25 @@ def loginfo(msg: str): rospy.loginfo(f"{DEBUG_WRAPPER_MSG_PREFIX} {msg}") -def logdebug(msg: str): - """Only works after ros node has been initialized""" - print(f"{DEBUG_WRAPPER_MSG_PREFIX} {msg}") - - -def get_required_params(): - try: - result = {} - if not rospy.has_param(TYPE_PARAM): - logfatal( - """Missing parameter to start debug wrapper: debug_type - Add it in the launch configuration""" - ) - result["type"] = str(rospy.get_param(TYPE_PARAM)) - if rospy.has_param(PORT_PARAM): - result["port"] = int(rospy.get_param(PORT_PARAM)) - else: - logerr( - """Missing parameter to start debugger: debug_port - Add it in the launch configuration""" - ) - result["port"] = None - result["wait"] = bool(rospy.get_param(WAIT_PARAM, False)) - return result - except BaseException as error: - logerr(f"Failed to get required node parameters: {error}") - raise error - - -def run_node_at(path: str): - try: - runpy.run_path(path, run_name="__main__") - except BaseException as error: - logfatal( - f"""Failed to run node module at {path}: - {error}""" - ) - raise error +def import_module_at(path: str): + basename = os.path.basename(path) + module_dir = os.path.dirname(path) + module_name = os.path.splitext(basename)[0] + # Based on https://docs.python.org/3/library/importlib.html#importing-a-source-file-directly + """ spec = importlib.util.spec_from_file_location( + name=module_name, location=path, submodule_search_locations=[module_dir] + ) + if spec is None: + raise Exception(f"Failed to load {path} as module {module_name}") + module = importlib.util.module_from_spec(spec) + sys.modules[module_name] = module + spec.loader.exec_module(module) """ + sys.path.append(module_dir) + module = importlib.import_module(module_name) + return module -def start_debugger(port: int, node_module_name: str, wait_for_debugee: bool = False): +def start_debugger(port: int, node_module_name: str, wait_for_client: bool = False): debugger_spec = importlib.util.find_spec("debugpy") if debugger_spec is not None: try: @@ -85,7 +66,7 @@ def start_debugger(port: int, node_module_name: str, wait_for_debugee: bool = Fa debugpy.listen(("localhost", port)) loginfo(f"Started debugger on port {port} for {node_module_name}") - if wait_for_debugee: + if wait_for_client: debugpy.wait_for_client() except BaseException as error: # Yes, all exceptions should be catched and sent into rosconsole @@ -94,29 +75,49 @@ def start_debugger(port: int, node_module_name: str, wait_for_debugee: bool = Fa logerr("debugpy module not found. Unable to start debugger") +class ArgumentParserError(Exception): + pass + + +class ThrowingArgumentParser(argparse.ArgumentParser): + def error(self, message): + raise ArgumentParserError(message) + + def main(argv): - """# http://wiki.ros.org/Nodes: 7. Special keys -- __name is the node's name. - # In this case the name is set by the launch file - # Todo: when using rosrun, the name also has to be set somehow - ros_node_name: str = __name - # We have to init the node to be able to log and access parameters - rospy.init_node(name=ros_node_name)""" - node_args = rospy.myargv(argv=sys.argv) - parser = argparse.ArgumentParser( + node_args = rospy.myargv(argv=argv) + parser = ThrowingArgumentParser( prog="debug wrapper", ) - parser.add_argument("--debug_node") - parser.add_argument("--debug_port") - parser.add_argument("--debug_wait") - args, unknown = parser.parse_known_args(node_args) + parser.add_argument("--debug_node", required=True) + parser.add_argument("--debug_port", required=False, type=int) + parser.add_argument("--debug_wait", default=False, type=bool) + args, unknown_args = parser.parse_known_args(node_args) + debug_node = args.debug_node base_dir = os.path.abspath(os.path.dirname(__file__)) - logdebug(f"Node {ros_node_name} started at {base_dir}") - params = get_required_params() - if params["port"] is not None: - start_debugger(params["port"], params["type"], wait_for_debugee=params["wait"]) - target_type_path = os.path.join(base_dir, params["type"]) - run_node_at(target_type_path) + printdebug(f"Node {args.debug_node} starting at {base_dir}") + + target_type_path = os.path.join(base_dir, debug_node) + module = import_module_at(target_type_path) + + module.init_ros() + + if args.debug_port is not None: + start_debugger( + args.debug_port, args.debug_node, wait_for_client=args.debug_wait + ) + else: + logerr( + """Missing parameter to start debugger: --debug_port + Add it in the launch configuration""" + ) + + try: + module.main(unknown_args) + except BaseException as error: + logfatal(f"Failed to run node {debug_node}: {error}") + raise error if __name__ == "__main__": diff --git a/code/perception/launch/perception.launch b/code/perception/launch/perception.launch index f194174c..39d97263 100644 --- a/code/perception/launch/perception.launch +++ b/code/perception/launch/perception.launch @@ -75,7 +75,7 @@ - + diff --git a/code/perception/src/lidar_distance.py b/code/perception/src/lidar_distance.py index 93ab1bc2..84afa1b2 100755 --- a/code/perception/src/lidar_distance.py +++ b/code/perception/src/lidar_distance.py @@ -245,7 +245,7 @@ def reconstruct_img_from_lidar(self, coordinates_xyz, focus): return dist_array -def ros_init(): +def init_ros(): """Initializes the node for basic ROS functions. Must only be called ONCE and not as part of def main() @@ -254,7 +254,7 @@ def ros_init(): rospy.init_node("lidar_distance") -def main(): +def main(argv=None): """Main entry point of this node Required for debugger entry""" @@ -263,5 +263,5 @@ def main(): if __name__ == "__main__": - rospy.init_node("lidar_distance") + init_ros() main() diff --git a/pyrightconfig.json b/pyrightconfig.json new file mode 100644 index 00000000..5cafbb7c --- /dev/null +++ b/pyrightconfig.json @@ -0,0 +1,25 @@ +{ + "include": ["code/src"], + + "exclude": [], + + "ignore": [], + + "defineConstant": { + "DEBUG": true + }, + + "typeCheckingMode": "standard", + "strictListInference": true, + "strictDictionaryInference": true, + "strictSetInference": true, + + "pythonVersion": "3.8", + "pythonPlatform": "Linux", + + "executionEnvironments": [ + { + "root": "code/src" + } + ] +} From 4a55b03832f96879d7847f779b8907533359c217 Mon Sep 17 00:00:00 2001 From: Peter Viechter Date: Thu, 7 Nov 2024 15:32:08 +0100 Subject: [PATCH 04/61] Revert lidar distance changes --- code/perception/src/lidar_distance.py | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/code/perception/src/lidar_distance.py b/code/perception/src/lidar_distance.py index 84afa1b2..04394ee2 100755 --- a/code/perception/src/lidar_distance.py +++ b/code/perception/src/lidar_distance.py @@ -120,6 +120,7 @@ def listener(self): Initializes the node and it's publishers """ # run simultaneously. + rospy.init_node("lidar_distance") self.bridge = CvBridge() self.pub_pointcloud = rospy.Publisher( @@ -245,23 +246,6 @@ def reconstruct_img_from_lidar(self, coordinates_xyz, focus): return dist_array -def init_ros(): - """Initializes the node for basic ROS functions. - - Must only be called ONCE and not as part of def main() - - Required for debugger entry""" - rospy.init_node("lidar_distance") - - -def main(argv=None): - """Main entry point of this node - - Required for debugger entry""" +if __name__ == "__main__": lidar_distance = LidarDistance() lidar_distance.listener() - - -if __name__ == "__main__": - init_ros() - main() From b159c55d9b3f6b63cf8790b08985a1a6be1b199e Mon Sep 17 00:00:00 2001 From: Peter Viechter Date: Thu, 7 Nov 2024 18:22:18 +0100 Subject: [PATCH 05/61] Debugger working with docker + logging improvements --- .vscode/launch.json | 8 +- build/agent_service.yaml | 1 + build/docker-compose.leaderboard.yaml | 2 + build/docker/agent/Dockerfile | 3 +- code/debug_logger_node.py | 77 +++++++++++++++ code/debug_wrapper.py | 114 ++++++++++++++--------- code/perception/launch/perception.launch | 2 +- code/requirements.txt | 1 + doc/development/debugging.md | 39 ++++++++ 9 files changed, 198 insertions(+), 49 deletions(-) create mode 100755 code/debug_logger_node.py create mode 100644 doc/development/debugging.md diff --git a/.vscode/launch.json b/.vscode/launch.json index e7ed6ee0..29e9ce53 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,19 +5,19 @@ "version": "0.2.0", "configurations": [ { - "name": "Python Debugger: Remote Attach", + "name": "53000 leaderboard attach", "type": "debugpy", "request": "attach", "connect": { "host": "localhost", - "port": 5678 + "port": 53000 }, "pathMappings": [ { "localRoot": "${workspaceFolder}/code", - "remoteRoot": "/internal_workspace/catkin_ws/src" + "remoteRoot": "${env:PAF_CODE_ROOT}" } ] } - ] + ], } \ No newline at end of file diff --git a/build/agent_service.yaml b/build/agent_service.yaml index 530eb208..5255aae4 100644 --- a/build/agent_service.yaml +++ b/build/agent_service.yaml @@ -30,6 +30,7 @@ services: - ROS_HOSTNAME=agent - XDG_RUNTIME_DIR=/tmp/runtime-carla - ROUTE=/opt/leaderboard/data/routes_devtest.xml + - DEBUG_WRAPPER_DEFAULT_HOST=0.0.0.0 # Simple route without special scenarios # - ROUTE=/workspace/code/routes/routes_simple.xml volumes: diff --git a/build/docker-compose.leaderboard.yaml b/build/docker-compose.leaderboard.yaml index 126f3d09..8d6633ee 100644 --- a/build/docker-compose.leaderboard.yaml +++ b/build/docker-compose.leaderboard.yaml @@ -8,6 +8,8 @@ services: extends: file: agent_service.yaml service: agent + ports: + - "53000-53100:53000-53100" command: |- bash -c "sleep 10 && sudo chown -R ${USER_UID}:${USER_GID} ../ && \ sudo chmod -R a+w ../ && sudo mkdir -p $${XDG_RUNTIME_DIR} && sudo chmod 0700 $${XDG_RUNTIME_DIR} && sudo chown -R ${USER_UID}:${USER_GID} $${XDG_RUNTIME_DIR} && \ diff --git a/build/docker/agent/Dockerfile b/build/docker/agent/Dockerfile index 408fae6c..1ac2cebc 100644 --- a/build/docker/agent/Dockerfile +++ b/build/docker/agent/Dockerfile @@ -171,7 +171,8 @@ RUN source /opt/ros/noetic/setup.bash && catkin_make ADD ./build/docker/agent/entrypoint.sh /entrypoint.sh # set the default working directory to the code -WORKDIR /workspace/code +ENV PAF_CODE_ROOT=/workspace/code +WORKDIR ${PAF_CODE_ROOT} RUN echo "source /opt/ros/noetic/setup.bash" >> ~/.bashrc RUN echo "source /catkin_ws/devel/setup.bash" >> ~/.bashrc diff --git a/code/debug_logger_node.py b/code/debug_logger_node.py new file mode 100755 index 00000000..202bcfc6 --- /dev/null +++ b/code/debug_logger_node.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python3 +""" +This is a dedicated debug logger node + +Without a fully initialized node, log messages do not show up in the rqt_console + +This is why this node is used by the debug_wrapper for logging +before it has initialized it's node +""" + +import time +import sys +from multiprocessing.connection import Listener + +import rospy + + +def eprint(msg: str): + print(f"[debug_logger_node]: {msg}", file=sys.stderr) + + +def log(name: str, msg: str, level: str): + msg = f"[debug_logger for {name}]: {msg}" + + level = level.lower() + if level == "debug": + rospy.logdebug(msg) + elif level == "info": + rospy.loginfo(msg) + elif level == "warn": + rospy.logwarn(msg) + elif level == "error": + rospy.logerr(msg) + else: + rospy.logfatal(msg) + + +def main(): + try: + address = ("localhost", 52999) # family is deduced to be 'AF_INET' + listener = Listener( + address, authkey=b"debug_logger" + ) # Only one listerner can be active at once + eprint("Debug logger node started") + except OSError as error: + eprint(f"Failed to start listener: {error}. Exiting...") + exit(0) + + rospy.init_node(name="debug_logger") + time.sleep( + 5.0 + ) # We need to wait a bit until the node is fully initialized to send log messages + + # Based on + # https://stackoverflow.com/questions/6920858/interprocess-communication-in-python + while not rospy.is_shutdown(): + conn = listener.accept() + print(f"[debug_logger]: connection accepted from {listener.last_accepted}") + msg = conn.recv() + conn.close() + log_msg = "Wrong log message format" + log_name = "NAMERR" + log_level = "fatal" + if isinstance(msg, dict): + if "name" in msg: + log_name = msg["name"] + if "msg" in msg: + log_msg = msg["msg"] + if "level" in msg: + log_level = msg["level"] + log(log_name, log_msg, log_level) + + listener.close() + + +if __name__ == "__main__": + main() diff --git a/code/debug_wrapper.py b/code/debug_wrapper.py index 88486091..993b216d 100755 --- a/code/debug_wrapper.py +++ b/code/debug_wrapper.py @@ -2,70 +2,89 @@ import importlib.util import os +import subprocess +import runpy import sys +import shutil import argparse +from multiprocessing.connection import Client import rospy -DEBUG_WRAPPER_MSG_PREFIX = "[debug_wrapper]:" -TYPE_PARAM = "~debug_type" -PORT_PARAM = "~debug_port" -WAIT_PARAM = "~debug_wait" +NODE_NAME = "NAMEERR" +LOGGER_STARTED = False -def printdebug(msg: str): - print(f"{DEBUG_WRAPPER_MSG_PREFIX} {msg}") +def start_logger(): + global LOGGER_STARTED + # read directory of this python file with resolved symlinks + real_dir = os.path.dirname(os.path.realpath(__file__)) + logger_path = os.path.join(real_dir, "debug_logger_node.py") + eprint(f"Starting logger at {logger_path}") + try: + python_path: str = shutil.which("python3") + subprocess.Popen( + [python_path, logger_path], + start_new_session=True, + ) + LOGGER_STARTED = True + except BaseException as error: + eprint(f"Failed to start logger: {error}") + + +def eprint(msg: str): + print(f"[debug_wrapper]: {msg}", file=sys.stderr) -def printerror(msg: str): - """Print to stderr""" - print(f"{DEBUG_WRAPPER_MSG_PREFIX} {msg}", file=sys.stderr) +def log(msg: str, level: str): + if LOGGER_STARTED: + try: + address = ("localhost", 52999) + conn = Client(address, authkey=b"debug_logger") + conn.send({"name": NODE_NAME, "msg": msg, "level": level}) + conn.close() + except BaseException as error: + eprint(msg) + eprint(f"Failed to send to logger: {error}") + else: + eprint(msg) def logfatal(msg: str): - """Only works after ros node has been initialized""" - rospy.logfatal( - f"""{DEBUG_WRAPPER_MSG_PREFIX} FAILED TO START NODE - NODE WILL NOT SHOW UP: - {msg}""" - ) + log(f"FAILED TO START NODE - NODE WILL NOT SHOW UP: {msg}", "fatal") def logerr(msg: str): - """Only works after ros node has been initialized""" - rospy.logerr(f"{DEBUG_WRAPPER_MSG_PREFIX} {msg}") + log(msg, "error") + + +def logwarn(msg: str): + log(msg, "warn") def loginfo(msg: str): - """Only works after ros node has been initialized""" - rospy.loginfo(f"{DEBUG_WRAPPER_MSG_PREFIX} {msg}") + log(msg, "info") -def import_module_at(path: str): +def run_module_at(path: str): basename = os.path.basename(path) module_dir = os.path.dirname(path) module_name = os.path.splitext(basename)[0] - # Based on https://docs.python.org/3/library/importlib.html#importing-a-source-file-directly - """ spec = importlib.util.spec_from_file_location( - name=module_name, location=path, submodule_search_locations=[module_dir] - ) - if spec is None: - raise Exception(f"Failed to load {path} as module {module_name}") - module = importlib.util.module_from_spec(spec) - sys.modules[module_name] = module - spec.loader.exec_module(module) """ sys.path.append(module_dir) - module = importlib.import_module(module_name) - return module + runpy.run_module(module_name, run_name="__main__") -def start_debugger(port: int, node_module_name: str, wait_for_client: bool = False): +def start_debugger( + node_module_name: str, host: str, port: int, wait_for_client: bool = False +): debugger_spec = importlib.util.find_spec("debugpy") if debugger_spec is not None: try: import debugpy - debugpy.listen(("localhost", port)) - loginfo(f"Started debugger on port {port} for {node_module_name}") + debugpy.configure(subProcess=False) + debugpy.listen((host, port)) + logwarn(f"Started debugger on {host}:{port} for {node_module_name}") if wait_for_client: debugpy.wait_for_client() except BaseException as error: @@ -81,31 +100,38 @@ class ArgumentParserError(Exception): class ThrowingArgumentParser(argparse.ArgumentParser): def error(self, message): + logfatal(f"Wrong node arguments. Check launch config. : {message}") raise ArgumentParserError(message) def main(argv): + global NODE_NAME + start_logger() + + default_host = "localhost" + if "DEBUG_WRAPPER_DEFAULT_HOST" in os.environ: + default_host = os.environ["DEBUG_WRAPPER_DEFAULT_HOST"] + node_args = rospy.myargv(argv=argv) parser = ThrowingArgumentParser( prog="debug wrapper", ) - parser.add_argument("--debug_node", required=True) + parser.add_argument("--debug_node", required=True, type=str) parser.add_argument("--debug_port", required=False, type=int) + parser.add_argument("--debug_host", default=default_host, type=str) parser.add_argument("--debug_wait", default=False, type=bool) args, unknown_args = parser.parse_known_args(node_args) - debug_node = args.debug_node + debug_node = args.debug_node + NODE_NAME = debug_node base_dir = os.path.abspath(os.path.dirname(__file__)) - printdebug(f"Node {args.debug_node} starting at {base_dir}") - - target_type_path = os.path.join(base_dir, debug_node) - module = import_module_at(target_type_path) - - module.init_ros() if args.debug_port is not None: start_debugger( - args.debug_port, args.debug_node, wait_for_client=args.debug_wait + args.debug_node, + args.debug_host, + args.debug_port, + wait_for_client=args.debug_wait, ) else: logerr( @@ -113,8 +139,10 @@ def main(argv): Add it in the launch configuration""" ) + target_type_path = os.path.join(base_dir, debug_node) + loginfo(f"Node {args.debug_node} starting at {base_dir}") try: - module.main(unknown_args) + run_module_at(target_type_path) except BaseException as error: logfatal(f"Failed to run node {debug_node}: {error}") raise error diff --git a/code/perception/launch/perception.launch b/code/perception/launch/perception.launch index 39d97263..b7a78c48 100644 --- a/code/perception/launch/perception.launch +++ b/code/perception/launch/perception.launch @@ -75,7 +75,7 @@ - + diff --git a/code/requirements.txt b/code/requirements.txt index b9b6155d..55de87f0 100644 --- a/code/requirements.txt +++ b/code/requirements.txt @@ -16,3 +16,4 @@ numpy==1.23.5 ultralytics==8.1.11 scikit-learn>=0.18 pandas==2.0.3 +debugpy==1.8.7 \ No newline at end of file diff --git a/doc/development/debugging.md b/doc/development/debugging.md new file mode 100644 index 00000000..45a3a6f5 --- /dev/null +++ b/doc/development/debugging.md @@ -0,0 +1,39 @@ +# Debugging + +**Summary:** This page explains multiple debugging methods for ROS nodes. + +- [Debugging possibilities](#debugging-possibilities) + - [Message based debugging](#message-based-debugging) + - [VS Code debugger](#vs-code-debugger) +- [Rebuild docker containers](#rebuild-docker-containers) +- [Sources](#sources) + +## Debugging possibilities + +There are two main debugging possibilities + +### Message based debugging + +Messages can be logged into the ROS console vie the `rospy.logdebug`, `rospy.loginfo`, `rospy.logwarn`, `rospy.logerror` and `rospy.logfatal` functions. + +### VS Code debugger + + + +## Rebuild docker containers + +The docker images on your pc might not match the latest Dockerfile in the repository + +To update them, open a terminal and change into the *build* directory. Execute: + +```bash +export USER_UID=$(id -u) +export USER_GID=$(id -g) +export USERNAME=$(id -u -n) +docker compose -f ./docker-compose.leaderboard.yaml up -d --build +docker compose -f ./docker-compose.dev.yaml up -d --build +``` + +## Sources + + From 3d43f017bc12e045b46bc297b3813664883217cf Mon Sep 17 00:00:00 2001 From: Peter Viechter Date: Fri, 8 Nov 2024 15:53:06 +0100 Subject: [PATCH 06/61] Debug logger node added to launch config + general logging improvements --- code/agent/launch/agent.launch | 4 + code/debug_logger_node.py | 77 --------- code/debug_wrapper.py | 41 ++--- code/debugging/CMakeLists.txt | 204 ++++++++++++++++++++++++ code/debugging/launch/debugging.launch | 4 + code/debugging/package.xml | 62 +++++++ code/debugging/src/debug_logger_node.py | 126 +++++++++++++++ 7 files changed, 412 insertions(+), 106 deletions(-) delete mode 100755 code/debug_logger_node.py create mode 100644 code/debugging/CMakeLists.txt create mode 100644 code/debugging/launch/debugging.launch create mode 100644 code/debugging/package.xml create mode 100755 code/debugging/src/debug_logger_node.py diff --git a/code/agent/launch/agent.launch b/code/agent/launch/agent.launch index fb9ef983..7861a38f 100644 --- a/code/agent/launch/agent.launch +++ b/code/agent/launch/agent.launch @@ -21,5 +21,9 @@ + + + + diff --git a/code/debug_logger_node.py b/code/debug_logger_node.py deleted file mode 100755 index 202bcfc6..00000000 --- a/code/debug_logger_node.py +++ /dev/null @@ -1,77 +0,0 @@ -#!/usr/bin/env python3 -""" -This is a dedicated debug logger node - -Without a fully initialized node, log messages do not show up in the rqt_console - -This is why this node is used by the debug_wrapper for logging -before it has initialized it's node -""" - -import time -import sys -from multiprocessing.connection import Listener - -import rospy - - -def eprint(msg: str): - print(f"[debug_logger_node]: {msg}", file=sys.stderr) - - -def log(name: str, msg: str, level: str): - msg = f"[debug_logger for {name}]: {msg}" - - level = level.lower() - if level == "debug": - rospy.logdebug(msg) - elif level == "info": - rospy.loginfo(msg) - elif level == "warn": - rospy.logwarn(msg) - elif level == "error": - rospy.logerr(msg) - else: - rospy.logfatal(msg) - - -def main(): - try: - address = ("localhost", 52999) # family is deduced to be 'AF_INET' - listener = Listener( - address, authkey=b"debug_logger" - ) # Only one listerner can be active at once - eprint("Debug logger node started") - except OSError as error: - eprint(f"Failed to start listener: {error}. Exiting...") - exit(0) - - rospy.init_node(name="debug_logger") - time.sleep( - 5.0 - ) # We need to wait a bit until the node is fully initialized to send log messages - - # Based on - # https://stackoverflow.com/questions/6920858/interprocess-communication-in-python - while not rospy.is_shutdown(): - conn = listener.accept() - print(f"[debug_logger]: connection accepted from {listener.last_accepted}") - msg = conn.recv() - conn.close() - log_msg = "Wrong log message format" - log_name = "NAMERR" - log_level = "fatal" - if isinstance(msg, dict): - if "name" in msg: - log_name = msg["name"] - if "msg" in msg: - log_msg = msg["msg"] - if "level" in msg: - log_level = msg["level"] - log(log_name, log_msg, log_level) - - listener.close() - - -if __name__ == "__main__": - main() diff --git a/code/debug_wrapper.py b/code/debug_wrapper.py index 993b216d..91b3d961 100755 --- a/code/debug_wrapper.py +++ b/code/debug_wrapper.py @@ -2,34 +2,15 @@ import importlib.util import os -import subprocess import runpy import sys -import shutil import argparse +import time from multiprocessing.connection import Client import rospy NODE_NAME = "NAMEERR" -LOGGER_STARTED = False - - -def start_logger(): - global LOGGER_STARTED - # read directory of this python file with resolved symlinks - real_dir = os.path.dirname(os.path.realpath(__file__)) - logger_path = os.path.join(real_dir, "debug_logger_node.py") - eprint(f"Starting logger at {logger_path}") - try: - python_path: str = shutil.which("python3") - subprocess.Popen( - [python_path, logger_path], - start_new_session=True, - ) - LOGGER_STARTED = True - except BaseException as error: - eprint(f"Failed to start logger: {error}") def eprint(msg: str): @@ -37,17 +18,22 @@ def eprint(msg: str): def log(msg: str, level: str): - if LOGGER_STARTED: + error = None + success = False + start_time = time.monotonic() + while not success and start_time + 5.0 > time.monotonic(): try: address = ("localhost", 52999) conn = Client(address, authkey=b"debug_logger") conn.send({"name": NODE_NAME, "msg": msg, "level": level}) conn.close() - except BaseException as error: - eprint(msg) - eprint(f"Failed to send to logger: {error}") - else: + success = True + except BaseException as e: + error = e + if not success: eprint(msg) + if error is not None: + eprint(f"Failed to send to logger: {error}") def logfatal(msg: str): @@ -82,7 +68,6 @@ def start_debugger( try: import debugpy - debugpy.configure(subProcess=False) debugpy.listen((host, port)) logwarn(f"Started debugger on {host}:{port} for {node_module_name}") if wait_for_client: @@ -105,9 +90,6 @@ def error(self, message): def main(argv): - global NODE_NAME - start_logger() - default_host = "localhost" if "DEBUG_WRAPPER_DEFAULT_HOST" in os.environ: default_host = os.environ["DEBUG_WRAPPER_DEFAULT_HOST"] @@ -123,6 +105,7 @@ def main(argv): args, unknown_args = parser.parse_known_args(node_args) debug_node = args.debug_node + global NODE_NAME NODE_NAME = debug_node base_dir = os.path.abspath(os.path.dirname(__file__)) diff --git a/code/debugging/CMakeLists.txt b/code/debugging/CMakeLists.txt new file mode 100644 index 00000000..8cc214d8 --- /dev/null +++ b/code/debugging/CMakeLists.txt @@ -0,0 +1,204 @@ +cmake_minimum_required(VERSION 3.0.2) +project(debugging) + +## Compile as C++11, supported in ROS Kinetic and newer +# add_compile_options(-std=c++11) + +## Find catkin macros and libraries +## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz) +## is used, also find other catkin packages +find_package(catkin REQUIRED COMPONENTS + rospy +) + +## System dependencies are found with CMake's conventions +# find_package(Boost REQUIRED COMPONENTS system) + + +## Uncomment this if the package has a setup.py. This macro ensures +## modules and global scripts declared therein get installed +## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html +# catkin_python_setup() + +################################################ +## Declare ROS messages, services and actions ## +################################################ + +## To declare and build messages, services or actions from within this +## package, follow these steps: +## * Let MSG_DEP_SET be the set of packages whose message types you use in +## your messages/services/actions (e.g. std_msgs, actionlib_msgs, ...). +## * In the file package.xml: +## * add a build_depend tag for "message_generation" +## * add a build_depend and a exec_depend tag for each package in MSG_DEP_SET +## * If MSG_DEP_SET isn't empty the following dependency has been pulled in +## but can be declared for certainty nonetheless: +## * add a exec_depend tag for "message_runtime" +## * In this file (CMakeLists.txt): +## * add "message_generation" and every package in MSG_DEP_SET to +## find_package(catkin REQUIRED COMPONENTS ...) +## * add "message_runtime" and every package in MSG_DEP_SET to +## catkin_package(CATKIN_DEPENDS ...) +## * uncomment the add_*_files sections below as needed +## and list every .msg/.srv/.action file to be processed +## * uncomment the generate_messages entry below +## * add every package in MSG_DEP_SET to generate_messages(DEPENDENCIES ...) + +## Generate messages in the 'msg' folder +# add_message_files( +# FILES +# Message1.msg +# Message2.msg +# ) + +## Generate services in the 'srv' folder +# add_service_files( +# FILES +# Service1.srv +# Service2.srv +# ) + +## Generate actions in the 'action' folder +# add_action_files( +# FILES +# Action1.action +# Action2.action +# ) + +## Generate added messages and services with any dependencies listed here +# generate_messages( +# DEPENDENCIES +# std_msgs # Or other packages containing msgs +# ) + +################################################ +## Declare ROS dynamic reconfigure parameters ## +################################################ + +## To declare and build dynamic reconfigure parameters within this +## package, follow these steps: +## * In the file package.xml: +## * add a build_depend and a exec_depend tag for "dynamic_reconfigure" +## * In this file (CMakeLists.txt): +## * add "dynamic_reconfigure" to +## find_package(catkin REQUIRED COMPONENTS ...) +## * uncomment the "generate_dynamic_reconfigure_options" section below +## and list every .cfg file to be processed + +## Generate dynamic reconfigure parameters in the 'cfg' folder +# generate_dynamic_reconfigure_options( +# cfg/DynReconf1.cfg +# cfg/DynReconf2.cfg +# ) + +################################### +## catkin specific configuration ## +################################### +## The catkin_package macro generates cmake config files for your package +## Declare things to be passed to dependent projects +## INCLUDE_DIRS: uncomment this if your package contains header files +## LIBRARIES: libraries you create in this project that dependent projects also need +## CATKIN_DEPENDS: catkin_packages dependent projects also need +## DEPENDS: system dependencies of this project that dependent projects also need +catkin_package( +# INCLUDE_DIRS include +# LIBRARIES debugging +# CATKIN_DEPENDS rospy +# DEPENDS system_lib +) + +########### +## Build ## +########### + +## Specify additional locations of header files +## Your package locations should be listed before other locations +include_directories( +# include + ${catkin_INCLUDE_DIRS} +) + +## Declare a C++ library +# add_library(${PROJECT_NAME} +# src/${PROJECT_NAME}/debugging.cpp +# ) + +## Add cmake target dependencies of the library +## as an example, code may need to be generated before libraries +## either from message generation or dynamic reconfigure +# add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) + +## Declare a C++ executable +## With catkin_make all packages are built within a single CMake context +## The recommended prefix ensures that target names across packages don't collide +# add_executable(${PROJECT_NAME}_node src/debugging_node.cpp) + +## Rename C++ executable without prefix +## The above recommended prefix causes long target names, the following renames the +## target back to the shorter version for ease of user use +## e.g. "rosrun someones_pkg node" instead of "rosrun someones_pkg someones_pkg_node" +# set_target_properties(${PROJECT_NAME}_node PROPERTIES OUTPUT_NAME node PREFIX "") + +## Add cmake target dependencies of the executable +## same as for the library above +# add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) + +## Specify libraries to link a library or executable target against +# target_link_libraries(${PROJECT_NAME}_node +# ${catkin_LIBRARIES} +# ) + +############# +## Install ## +############# + +# all install targets should use catkin DESTINATION variables +# See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html + +## Mark executable scripts (Python etc.) for installation +## in contrast to setup.py, you can choose the destination +# catkin_install_python(PROGRAMS +# scripts/my_python_script +# DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} +# ) + +## Mark executables for installation +## See http://docs.ros.org/melodic/api/catkin/html/howto/format1/building_executables.html +# install(TARGETS ${PROJECT_NAME}_node +# RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} +# ) + +## Mark libraries for installation +## See http://docs.ros.org/melodic/api/catkin/html/howto/format1/building_libraries.html +# install(TARGETS ${PROJECT_NAME} +# ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} +# LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} +# RUNTIME DESTINATION ${CATKIN_GLOBAL_BIN_DESTINATION} +# ) + +## Mark cpp header files for installation +# install(DIRECTORY include/${PROJECT_NAME}/ +# DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION} +# FILES_MATCHING PATTERN "*.h" +# PATTERN ".svn" EXCLUDE +# ) + +## Mark other files for installation (e.g. launch and bag files, etc.) +# install(FILES +# # myfile1 +# # myfile2 +# DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} +# ) + +############# +## Testing ## +############# + +## Add gtest based cpp test target and link libraries +# catkin_add_gtest(${PROJECT_NAME}-test test/test_debugging.cpp) +# if(TARGET ${PROJECT_NAME}-test) +# target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME}) +# endif() + +## Add folders to be run by python nosetests +# catkin_add_nosetests(test) diff --git a/code/debugging/launch/debugging.launch b/code/debugging/launch/debugging.launch new file mode 100644 index 00000000..4388cbbf --- /dev/null +++ b/code/debugging/launch/debugging.launch @@ -0,0 +1,4 @@ + + + + diff --git a/code/debugging/package.xml b/code/debugging/package.xml new file mode 100644 index 00000000..5598d5ed --- /dev/null +++ b/code/debugging/package.xml @@ -0,0 +1,62 @@ + + + debugging + 0.0.0 + The debugging package + + + + + peter + + + + + + TODO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + catkin + rospy + rospy + rospy + + + + + + + + diff --git a/code/debugging/src/debug_logger_node.py b/code/debugging/src/debug_logger_node.py new file mode 100755 index 00000000..68bc4b6c --- /dev/null +++ b/code/debugging/src/debug_logger_node.py @@ -0,0 +1,126 @@ +#!/usr/bin/env python3 +""" +This is a dedicated debug logger node + +Without a fully initialized node, log messages only show up in the logfile. +But not in the /rosout topic and thus not in the rqt_console + +This is why this node is used by the debug_wrapper for logging +before it has initialized its own node +""" + +import time +import sys +from multiprocessing.connection import Listener, Client +import threading +import signal + +import rospy + +ADDRESS = ("localhost", 52999) +AUTHKEY = b"debug_logger" +CLOSE_MSG = "close" +LISTENER_THREAD = None +NODE_RUNNING = True + +MESSAGES_MUTEX = threading.Lock() +MESSAGES = [] + + +def eprint(msg: str): + print(f"[debug_logger_node]: {msg}", file=sys.stderr) + + +def log(name: str, msg: str, level: str): + msg = f"[debug_logger for {name}]: {msg}" + + level = level.lower() + if level == "debug": + rospy.logdebug(msg) + elif level == "info": + rospy.loginfo(msg) + elif level == "warn": + rospy.logwarn(msg) + elif level == "error": + rospy.logerr(msg) + else: + rospy.logfatal(msg) + + +def run_listener(listener: Listener): + running = True + while running: + conn = listener.accept() + print(f"[debug_logger]: connection accepted from {listener.last_accepted}") + msg = None + if conn.poll(timeout=2.0): + msg = conn.recv() + if isinstance(msg, str): + if msg.lower() == CLOSE_MSG: + running = False + msg = None + conn.close() + if msg is not None: + with MESSAGES_MUTEX: + MESSAGES.append(msg) + listener.close() + + +def close_listener(): + try: + conn = Client(ADDRESS, authkey=AUTHKEY) + conn.send(CLOSE_MSG) + conn.close() + except BaseException: + pass + + +def exit_cleanup(signum=None, frame=None): + close_listener() + if LISTENER_THREAD is not None: + LISTENER_THREAD.join() + global NODE_RUNNING + NODE_RUNNING = False + + +def main(): + try: + # Based on + # https://stackoverflow.com/questions/6920858/interprocess-communication-in-python + # Only one listener can be active at once + listener = Listener(ADDRESS, authkey=AUTHKEY) + eprint("Debug logger node started") + except OSError as error: + eprint(f"Failed to run listener: {error}. Exiting...") + exit(0) + signal.signal(signal.SIGINT, exit_cleanup) + signal.signal(signal.SIGTERM, exit_cleanup) + global LISTENER_THREAD + LISTENER_THREAD = threading.Thread(target=run_listener, args=(listener,)) + LISTENER_THREAD.start() + + rospy.init_node(name="debug_logger") + # We need to wait a bit until the node is fully initialized to send log messages + time.sleep(5.0) + rospy.on_shutdown(exit_cleanup) + + while NODE_RUNNING: + with MESSAGES_MUTEX: + while len(MESSAGES) > 0: + msg = MESSAGES.pop() + log_msg = "Wrong log message format" + log_name = "NAMERR" + log_level = "fatal" + if isinstance(msg, dict): + if "name" in msg: + log_name = msg["name"] + if "msg" in msg: + log_msg = msg["msg"] + if "level" in msg: + log_level = msg["level"] + log(log_name, log_msg, log_level) + time.sleep(0.5) + + +if __name__ == "__main__": + main() From 37c308a2d59271f3c758c7471d23b8b2aa8dd864 Mon Sep 17 00:00:00 2001 From: Peter Viechter Date: Fri, 8 Nov 2024 16:39:14 +0100 Subject: [PATCH 07/61] Update remoteRoot source mapping variable PAF_CATKIN_CODE_ROOT --- .vscode/launch.json | 2 +- build/docker/agent/Dockerfile | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 29e9ce53..68420ca7 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -15,7 +15,7 @@ "pathMappings": [ { "localRoot": "${workspaceFolder}/code", - "remoteRoot": "${env:PAF_CODE_ROOT}" + "remoteRoot": "${env:PAF_CATKIN_CODE_ROOT}" } ] } diff --git a/build/docker/agent/Dockerfile b/build/docker/agent/Dockerfile index 1ac2cebc..48818408 100644 --- a/build/docker/agent/Dockerfile +++ b/build/docker/agent/Dockerfile @@ -165,14 +165,16 @@ COPY --chown=$USERNAME:$USERNAME ./code /workspace/code/ # Link code into catkin workspace RUN ln -s /workspace/code /catkin_ws/src +# For debugger +ENV PAF_CATKIN_CODE_ROOT=/catkin_ws/src + # re-make the catkin workspace RUN source /opt/ros/noetic/setup.bash && catkin_make ADD ./build/docker/agent/entrypoint.sh /entrypoint.sh # set the default working directory to the code -ENV PAF_CODE_ROOT=/workspace/code -WORKDIR ${PAF_CODE_ROOT} +WORKDIR /workspace/code RUN echo "source /opt/ros/noetic/setup.bash" >> ~/.bashrc RUN echo "source /catkin_ws/devel/setup.bash" >> ~/.bashrc From b5cc5e4d1d7a7f8e4c5a88052fee8b683ccb8b49 Mon Sep 17 00:00:00 2001 From: Peter Viechter Date: Fri, 8 Nov 2024 21:25:21 +0100 Subject: [PATCH 08/61] Revert perception.launch --- code/perception/launch/perception.launch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/perception/launch/perception.launch b/code/perception/launch/perception.launch index b7a78c48..10f79a80 100644 --- a/code/perception/launch/perception.launch +++ b/code/perception/launch/perception.launch @@ -75,7 +75,7 @@ - + From 6fad77251a403f501121a41110188255623d4449 Mon Sep 17 00:00:00 2001 From: Peter Viechter Date: Fri, 8 Nov 2024 21:55:36 +0100 Subject: [PATCH 09/61] Add detailed documentation --- code/debug_wrapper.py | 63 +++++++++++ code/debugging/launch/debugging.launch | 2 +- .../{debug_logger_node.py => debug_logger.py} | 39 ++++++- doc/development/debugging.md | 103 +++++++++++++++++- 4 files changed, 198 insertions(+), 9 deletions(-) rename code/debugging/src/{debug_logger_node.py => debug_logger.py} (73%) diff --git a/code/debug_wrapper.py b/code/debug_wrapper.py index 91b3d961..c02d8d0a 100755 --- a/code/debug_wrapper.py +++ b/code/debug_wrapper.py @@ -1,4 +1,39 @@ #!/usr/bin/env python3 +"""Debug wrapper node + +Node that wraps a python ros node +and is able to open a debugpy remote debugger instance. + +Logs any exceptions from the node and other information +into the ros console via the debug_logger node. + +Always tries to at least start the node, +even if dependencies like debugpy are missing. + +Usage: + Already done for existing ros packages: symlink this file into the package. Example: + `cd code/perception/src && ln -s ../../debug_wrapper.py debug_wrapper.py` + + Adjust the launch configuration to use the debug_wrapper.py + instead of the node file and set the required args + + More info in [debugging.md](doc/development/debugging.md) + +Arguments: + --debug_node: Required: The filename of the node to debug + --debug_port: The port the debugger listens on. If not set, + --debug_host: The host the debugger binds to. + Defaults to the environment variable `DEBUG_WRAPPER_DEFAULT_HOST` if set, + otherwise `localhost` + --debug_wait: If True, the wrapper waits until a client (VS Code) is connected + and only then starts node execution + +Raises: + ArgumentParserError: Missing required parameters + error: If the started debug_node raises an exception, + it is logged and then raised again +""" + import importlib.util import os @@ -14,10 +49,24 @@ def eprint(msg: str): + """Log msg into stderr. + + Used instead of print, because only stderr seems to reliably land in agent.log + + Args: + msg (str): Log message + """ print(f"[debug_wrapper]: {msg}", file=sys.stderr) def log(msg: str, level: str): + """Log msg via the debug_logger node + + Args: + msg (str): Log message + level (str): Log level. One of (debug), info, warn, error, fatal. + debug level not recommended, because these are not published to /rosout + """ error = None success = False start_time = time.monotonic() @@ -53,6 +102,11 @@ def loginfo(msg: str): def run_module_at(path: str): + """Runs a python module based on its file path + + Args: + path (str): python file path to run + """ basename = os.path.basename(path) module_dir = os.path.dirname(path) module_name = os.path.splitext(basename)[0] @@ -63,6 +117,15 @@ def run_module_at(path: str): def start_debugger( node_module_name: str, host: str, port: int, wait_for_client: bool = False ): + """_summary_ + + Args: + node_module_name (str): Name of the underlying node. Only used for logging + host (str): host the debugger binds to + port (int): debugger port + wait_for_client (bool, optional): If the debugger should wait + for a client to attach. Defaults to False. + """ debugger_spec = importlib.util.find_spec("debugpy") if debugger_spec is not None: try: diff --git a/code/debugging/launch/debugging.launch b/code/debugging/launch/debugging.launch index 4388cbbf..330263e8 100644 --- a/code/debugging/launch/debugging.launch +++ b/code/debugging/launch/debugging.launch @@ -1,4 +1,4 @@ - + diff --git a/code/debugging/src/debug_logger_node.py b/code/debugging/src/debug_logger.py similarity index 73% rename from code/debugging/src/debug_logger_node.py rename to code/debugging/src/debug_logger.py index 68bc4b6c..6778531d 100755 --- a/code/debugging/src/debug_logger_node.py +++ b/code/debugging/src/debug_logger.py @@ -1,9 +1,16 @@ #!/usr/bin/env python3 -""" -This is a dedicated debug logger node +"""Dedicated debug logger node. + +It can receive messages via a multiprocessing ipc socket on localhost:52999. +Message format is a python dict with keys {name, msg, level}. +It will then send those messages into the ros console via rospy.log*() -Without a fully initialized node, log messages only show up in the logfile. -But not in the /rosout topic and thus not in the rqt_console +Main usecase: it enables not initialized python nodes to publish log messages +to the /rosout topic. + +Without a fully initialized node, +log messages from python files only show up in the ros logfile, +but not in the /rosout topic and thus not in the rqt_console This is why this node is used by the debug_wrapper for logging before it has initialized its own node @@ -28,10 +35,25 @@ def eprint(msg: str): - print(f"[debug_logger_node]: {msg}", file=sys.stderr) + """Log msg into stderr. + + Used instead of print, because only stderr seems to reliably land in agent.log + + Args: + msg (str): Log message + """ + print(f"[debug_logger]: {msg}", file=sys.stderr) def log(name: str, msg: str, level: str): + """Log to the ros console + + Args: + name (str): Node name this message should be associated with + msg (str): Log message + level (str): Log level. One of (debug), info, warn, error, fatal. + debug level not recommended, because these are not published to /rosout + """ msg = f"[debug_logger for {name}]: {msg}" level = level.lower() @@ -48,6 +70,13 @@ def log(name: str, msg: str, level: str): def run_listener(listener: Listener): + """Run the multiprocessing listener + + The listener exits when it receives CLOSE_MSG + + Args: + listener (Listener): Listener to run + """ running = True while running: conn = listener.accept() diff --git a/doc/development/debugging.md b/doc/development/debugging.md index 45a3a6f5..9d364145 100644 --- a/doc/development/debugging.md +++ b/doc/development/debugging.md @@ -4,27 +4,124 @@ - [Debugging possibilities](#debugging-possibilities) - [Message based debugging](#message-based-debugging) + - [Viewing the messages](#viewing-the-messages) + - [Problems of message based debugging](#problems-of-message-based-debugging) - [VS Code debugger](#vs-code-debugger) + - [Setup steps required once](#setup-steps-required-once) + - [Required once for the node you want to debug](#required-once-for-the-node-you-want-to-debug) + - [Debugging workflow after setup](#debugging-workflow-after-setup) + - [Known problems of debugging with VS Code](#known-problems-of-debugging-with-vs-code) - [Rebuild docker containers](#rebuild-docker-containers) - [Sources](#sources) ## Debugging possibilities -There are two main debugging possibilities +There are two main debugging possibilities: Message based and VS Code based ### Message based debugging Messages can be logged into the ROS console vie the `rospy.logdebug`, `rospy.loginfo`, `rospy.logwarn`, `rospy.logerror` and `rospy.logfatal` functions. +Most messages are then published to the /rosout topic. + +`rospy.logdebug` is not recommended, because these messages are not published to /rosout by default. + +Note that the node has to be initialized with `rospy.init_node()` before logging, otherwise the messages are not published to /rosout and just end up in stdout/stderr. + +#### Viewing the messages + +There are several ways to view the ROS log messages + +- The most convenient way to view logs is via the **rqt_console** GUI, which starts when the leaderboard is started. + It allows filtering for debug levels, nodes and message content. + + Caveat: It only includes messages published to the /rosout topic. + +- Execute `rosconsole echo` inside the *build-agent* container. This shows the /rosout messages from this point on. + +- The leaderboard logs usually end up in [code/log/ros](../../code/log/ros). + + This includes the [agent.log](../../code/log/ros/agent.log) file where most of all the nodes output is captured. + It seems to exclude stdout of the nodes and excludes the debug log level. stderr and all other levels are included. + Exceptions that occur at node initialization can also be found here. + +- More accurate "per-node" logs including the debug level and stdout end up in the individual node log files. + These can be found in the directory returned by running `roslaunch-logs` inside the *build-agent* container. (Usually `~/.ros/log`) + +- Manually starting a node with `rosrun ` inside the *build-agent* container helps to view stdout, stderr and exceptions. + +More information can be found in the [Wiki](https://wiki.ros.org/rospy/Overview/Logging) + +#### Problems of message based debugging + +- Time intensive and cumbersome: leaderboard has to be restarted to add a new message +- Frequent log messages "spam" the log +- Exceptions on node initialization do not show up in the /rosout topic +- If messages are sent right after `rospy.init_node()`, they might not be published to the /rosout topic ### VS Code debugger +Debug individual nodes with the VS Code debugger. This allows usage of breakpoints and code stepping. + +#### Setup steps required once + +1. Make sure the docker images are up-to-date: [Rebuild docker containers](#rebuild-docker-containers) +2. Start the `build/docker-compose.dev.yaml` containers and attach VS Code to the **build-agent-dev** container. Always use the VS Code remote for debugging +3. Make sure the recommended extensions are installed in the VS Code remote. + +#### Required once for the node you want to debug + +Adjust the launch configuration of the node to use the [debug_wrapper.py](../../code/debug_wrapper.py) node. + +Change the type to **debug_wrapper.py** and set `args="--debug_node= --debug_port="`. +*debug_port* can be a port in range **53000-53100**, because those are exposed from the [leaderboard docker configuration](../../build/docker-compose.leaderboard.yaml). + +Configuration example for the [lidar_distance.py](../../code/perception/src/lidar_distance.py) node: [launch configuration](../../code/perception/launch/perception.launch) + +- Original entry: + + ```launch + + + + + ``` + +- Entry modified for debugging: + + ```launch + + + + + ``` + +By default, the affected node will start up as usual. When you attach the debugger later, you are then only able to debug the callbacks the node receives. +But if you set `--debug_wait=True`, it will block the node from starting until VS Code attaches and allow you to debug the initialization of the node. + +If the leaderboard hangs on `Setting up the agent` after the configuration has been adjusted, there most likely is a mistake in the launch configuration. + +More usage information can be found in the [debug_wrapper](../../code/debug_wrapper.py) and the [debug_logger](../../code/debugging/src/debug_logger.py) + +#### Debugging workflow after setup + +1. Start/Restart the [leaderboard](../../build/docker-compose.leaderboard.yaml) as usual +2. Wait for the application to start up +3. Add breakpoints to your node. +4. Start the VS Code debugger (debugging tab). A default launch configuration named *53000 leaderboard attach* is available. It uses port **53000**. + +Any errors/exceptions the debug_wrapper encounters are published to /rosout via the [debug_logger](../../code/debugging/src/debug_logger.py). +With the **rqt_console** GUI you can filter by node *debug_logger* to see all messages related to the wrapper. + +#### Known problems of debugging with VS Code +- Adjusting the launch configurations is a bit cumbersome +- The side effects of just "stopping" a node with the debugger are unknown ## Rebuild docker containers The docker images on your pc might not match the latest Dockerfile in the repository -To update them, open a terminal and change into the *build* directory. Execute: +To update them, open a terminal, change into the *build* directory and execute: ```bash export USER_UID=$(id -u) @@ -36,4 +133,4 @@ docker compose -f ./docker-compose.dev.yaml up -d --build ## Sources - + From 1dd75132524fa979e1dc386971a8bdac4c9914bc Mon Sep 17 00:00:00 2001 From: Peter Viechter Date: Fri, 8 Nov 2024 22:00:57 +0100 Subject: [PATCH 10/61] Add debugger comment --- build/docker-compose.leaderboard.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/build/docker-compose.leaderboard.yaml b/build/docker-compose.leaderboard.yaml index 8d6633ee..4c43bd87 100644 --- a/build/docker-compose.leaderboard.yaml +++ b/build/docker-compose.leaderboard.yaml @@ -9,6 +9,7 @@ services: file: agent_service.yaml service: agent ports: + # Reserved ports for the debugger - "53000-53100:53000-53100" command: |- bash -c "sleep 10 && sudo chown -R ${USER_UID}:${USER_GID} ../ && \ From 5753cad1a1cc5810e0802d39eea5c90489324f06 Mon Sep 17 00:00:00 2001 From: Peter Viechter Date: Fri, 8 Nov 2024 22:09:18 +0100 Subject: [PATCH 11/61] Add missing symlinks --- code/acting/src/debug_wrapper.py | 1 + code/mock/src/debug_wrapper.py | 1 + code/planning/src/debug_wrapper.py | 1 + 3 files changed, 3 insertions(+) create mode 120000 code/acting/src/debug_wrapper.py create mode 120000 code/mock/src/debug_wrapper.py create mode 120000 code/planning/src/debug_wrapper.py diff --git a/code/acting/src/debug_wrapper.py b/code/acting/src/debug_wrapper.py new file mode 120000 index 00000000..e4e2c378 --- /dev/null +++ b/code/acting/src/debug_wrapper.py @@ -0,0 +1 @@ +../../debug_wrapper.py \ No newline at end of file diff --git a/code/mock/src/debug_wrapper.py b/code/mock/src/debug_wrapper.py new file mode 120000 index 00000000..e4e2c378 --- /dev/null +++ b/code/mock/src/debug_wrapper.py @@ -0,0 +1 @@ +../../debug_wrapper.py \ No newline at end of file diff --git a/code/planning/src/debug_wrapper.py b/code/planning/src/debug_wrapper.py new file mode 120000 index 00000000..e4e2c378 --- /dev/null +++ b/code/planning/src/debug_wrapper.py @@ -0,0 +1 @@ +../../debug_wrapper.py \ No newline at end of file From 8694e5e6a82a80dbab0b587a12c974824b6f1a48 Mon Sep 17 00:00:00 2001 From: vinzenzm Date: Fri, 8 Nov 2024 23:26:29 +0100 Subject: [PATCH 12/61] Added two tasks to vscode which can be executed in order to run catkin_make inside the container. One of them is more convenient as a list of containers is automatically provided. It however depends on a vscode extension not yet in recomendations. We might need to select one of the two options and remove the other. --- .vscode/extensions.json | 3 ++- .vscode/tasks.json | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 .vscode/tasks.json diff --git a/.vscode/extensions.json b/.vscode/extensions.json index c27bbad5..596e223e 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -12,6 +12,7 @@ "richardkotze.git-mob", "ms-vscode-remote.remote-containers", "valentjn.vscode-ltex", - "ms-python.black-formatter" + "ms-python.black-formatter", + "augustocdias.tasks-shell-input" ] } \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 00000000..e59d7898 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,36 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Run 'catkin_make' in Docker container. Write container name.", + "type": "shell", + "command": "docker exec -it ${input:container_name} bash -c 'cd ../../catkin_ws && source /opt/ros/noetic/setup.bash && bash devel/setup.bash && catkin_make'", + "problemMatcher": [], + "detail": "Executes 'catkin_make' in built-agent-dev-1 container. The container must be running.", + "dependsOn": [], + }, + { + "label": "Run 'catkin_make' in docker container. Autochoose docker container.", + "type": "shell", + "command": "docker exec -it ${input:container_name_shell} bash -c 'cd ../../catkin_ws && source /opt/ros/noetic/setup.bash && bash devel/setup.bash && catkin_make'", + "problemMatcher": [], + "detail": "Executes 'catkin_make' selected container. Requires Tasks Shell Input Extension.", + } + ], + "inputs": [ + { + "id": "container_name", + "description": "Name of docker container", + "default": "build-agent-dev-1", + "type": "promptString" + }, + { + "id": "container_name_shell", + "type": "command", + "command": "shellCommand.execute", + "args": { + "command": "docker ps --format '{{.Names}}'", + } + } + ] +} \ No newline at end of file From 95912ca96c153cdc706758ce02024824d8cd6d98 Mon Sep 17 00:00:00 2001 From: Peter Viechter Date: Sat, 9 Nov 2024 14:59:44 +0100 Subject: [PATCH 13/61] Add setup.py --- code/debugging/CMakeLists.txt | 2 +- code/debugging/setup.py | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 code/debugging/setup.py diff --git a/code/debugging/CMakeLists.txt b/code/debugging/CMakeLists.txt index 8cc214d8..a857d84f 100644 --- a/code/debugging/CMakeLists.txt +++ b/code/debugging/CMakeLists.txt @@ -18,7 +18,7 @@ find_package(catkin REQUIRED COMPONENTS ## Uncomment this if the package has a setup.py. This macro ensures ## modules and global scripts declared therein get installed ## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html -# catkin_python_setup() +catkin_python_setup() ################################################ ## Declare ROS messages, services and actions ## diff --git a/code/debugging/setup.py b/code/debugging/setup.py new file mode 100644 index 00000000..d320ac00 --- /dev/null +++ b/code/debugging/setup.py @@ -0,0 +1,6 @@ +#!/usr/bin/env python +from distutils.core import setup +from catkin_pkg.python_setup import generate_distutils_setup + +setup_args = generate_distutils_setup(packages=["debugging"], package_dir={"": "src"}) +setup(**setup_args) From 9d2cafe943c2adfa5bdef9c651616c848def33da Mon Sep 17 00:00:00 2001 From: vinzenzm Date: Sat, 9 Nov 2024 15:40:02 +0100 Subject: [PATCH 14/61] Updated documentation and improved upon acting debuggin. Added a new acting_debug launch file which launches only the necessary components for debugging. Updated the documentation for how to use the debugging node. Fixed a visual bug in the debug node where the trajectory was visualized wrongly. --- code/acting/launch/acting_debug.launch | 40 +++++++++++++++++++++ code/acting/src/acting/Acting_Debug_Node.py | 13 ++++++- doc/acting/acting_testing.md | 27 +++++++------- 3 files changed, 67 insertions(+), 13 deletions(-) create mode 100644 code/acting/launch/acting_debug.launch diff --git a/code/acting/launch/acting_debug.launch b/code/acting/launch/acting_debug.launch new file mode 100644 index 00000000..e0353b7c --- /dev/null +++ b/code/acting/launch/acting_debug.launch @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/code/acting/src/acting/Acting_Debug_Node.py b/code/acting/src/acting/Acting_Debug_Node.py index b3289747..da6104c8 100755 --- a/code/acting/src/acting/Acting_Debug_Node.py +++ b/code/acting/src/acting/Acting_Debug_Node.py @@ -178,6 +178,17 @@ def __init__(self): self.__vehicle_steers = [] self.positions = [] + # Initialize agent position + self.x = 0 + self.y = 0 + self.z = 0 + + # For visual purposes we set the trajectory height to vehicle heigt. + # The trajectory z coordinated do not affect steering or else. + # There is quite some confusion about visual height an actual height + # This parameter might needs adustment + self.z_visual = 0 + # Generate Trajectory as selected in TRAJECTORY_TYPE self.path_msg = Path() self.path_msg.header.stamp = rospy.Time.now() @@ -286,7 +297,7 @@ def updated_trajectory(self, target_trajectory): pos.header.frame_id = "global" pos.pose.position.x = wp[0] pos.pose.position.y = wp[1] - pos.pose.position.z = 704 # needed for visuals + pos.pose.position.z = self.z_visual # currently not used therefore zeros pos.pose.orientation.x = 0 pos.pose.orientation.y = 0 diff --git a/doc/acting/acting_testing.md b/doc/acting/acting_testing.md index a5a67791..49bd88e7 100644 --- a/doc/acting/acting_testing.md +++ b/doc/acting/acting_testing.md @@ -2,26 +2,27 @@ **Summary:** This page shows ways to test and tune acting components and to verify that they work as intended. -- [How to test/tune acting components independedly](#how-to-testtune-acting-components-independedly) - - [Acting\_Debug\_Node](#acting_debug_node) - - [Setup for Testing with the Debug-Node](#setup-for-testing-with-the-debug-node) - - [Operating the Debug-Node](#operating-the-debug-node) +- [Acting\_Debug\_Node](#acting_debug_node) + - [Setup for Testing with the Debug-Node](#setup-for-testing-with-the-debug-node) + - [Operating the Debug-Node](#operating-the-debug-node) ## Acting_Debug_Node The [Acting_Debug_Node](../../code/acting/src/acting/Acting_Debug_Node.py) allows you to tune/test/verify all acting components independently of Planning-Inputs and also lets you easily output the data needed to plot/verify the tuning/testing you have done. +There is a dedicated [acting_debug.launch](../../code/acting/launch/acting_debug.launch) file which starts the acting component **as well as the necesarry perception components** automatically. It is recommended to first test the [Acting_Debug_Node](../../code/acting/src/acting/Acting_Debug_Node.py) +with an empty road scenario. The following guide provides instructions on how to launch this setup. + ### Setup for Testing with the Debug-Node -To use the [Acting_Debug_Node](../../code/acting/src/acting/Acting_Debug_Node.py) you first have to edit a few files in your current branch: +To use the [Acting_Debug_Node](../../code/acting/src/acting/Acting_Debug_Node.py) you first have to edit a few files in your current branch: \\ +**! Make sure to revert these changes when pushing your branch!** -- In the [acting.launch](../../code/acting/launch/acting.launch) file, you need to un-comment the ```Acting_Debug_Node```-node. -- Disable Planning from sending *trajectory*, *target_velocity*, *unstuck* or *emergency* Messages. -The easiest way to achieve this is to go to the [planning.launch](../../code/planning/launch/planning.launch) and just comment-out every active node. -- As the Perception-nodes use alot of processing power and ressources and you most likely do not need them, you can disable them, again commenting-out unwanted nodes in the [perception.launch](../../code/perception/launch/perception.launch) file. -**IMPORTANT:** As you need the **position_heading_publisher_node** and most likely the **kalman_filter** for the GNSS/IMU data, do keep those 2 active! -- There is a developer-enviroment ready to use, if you want to test your components on an empty road. -To switch to this, go to [docker_compose.yml](../../build/docker-compose.yml), where you will find which enviroment is currently chosen in lines 64-66. Uncomment the ```dev_launch``` and comment-out the ```leaderboard_evaluator``` if you want to use this developer-enviroment. +- In [dev.launch](../../code/agent/launch/dev.launch) the [agent.launch](../../code/agent/launch/agent.launch) file is included. Change this to include [acting_debug.launch](../../code/acting/launch/acting_debug.launch) from the **acting** package. +As mentioned above this includes everything we need. +- In [docker-compose.devroute.yaml](../../build/docker-compose.devroute.yaml) change the command to 'bash -c "sleep 10 && roslaunch agent/launch/dev.launch"' +- You can now 'docker compose up' the [docker-compose.devroute.yaml](../../build/docker-compose.devroute.yaml). + This should result in an empty road scenario with rviz and rqt. To now decide whether to work on noisy sensor data, with or without the kalman-filter, here is how to change this: @@ -30,6 +31,8 @@ To now decide whether to work on noisy sensor data, with or without the kalman-f If you want to test a component on ideal sensor data (position/heading/both), go to the [dev_objects.json](../../code/agent/config/dev_objects.json) and find the ```GNSS```(position) and the ```IMU```(heading) sensors (lines 142-173) and set their noise-attributes to 0. It is then also recommended to set the ```pos_filter``` and ```heading_filter``` of the **position_heading_publisher_node** to None (as filtering ideal sensor data will make them inaccurate again). +In [acting_debug.launch](../../code/acting/launch/acting_debug.launch) you can also set up different plot configurations for the rqt-window. + ### Operating the Debug-Node When you open the [Acting_Debug_Node](../../code/acting/src/acting/Acting_Debug_Node.py) you will see, that alot of Testing-Options are selectable via Global Variables. From e7de5fca23441bd9cf74a747af7c4eadb4585eff Mon Sep 17 00:00:00 2001 From: Sebastian Seitz Date: Sun, 10 Nov 2024 12:19:52 +0100 Subject: [PATCH 15/61] add link to videos of the runs --- doc/research/paf24/general/current_state.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/research/paf24/general/current_state.md b/doc/research/paf24/general/current_state.md index bffc2432..f5a9d194 100755 --- a/doc/research/paf24/general/current_state.md +++ b/doc/research/paf24/general/current_state.md @@ -128,6 +128,8 @@ Here are the raw notes in case misunderstandings have been made when grouping th ### Run 1 +[Link to Video of the Run](https://drive.google.com/file/d/1Hb4arEC5ocfUD2KZh1bNVwRG2hoML8E9/view?usp=drive_link) + - Scared to get out of parking spot - lane not held causing problems when avoiding open car door - stopping for no apparent reason @@ -153,6 +155,8 @@ Here are the raw notes in case misunderstandings have been made when grouping th ### Run 2 +[Link to Video of the Run](https://drive.google.com/file/d/1xot90LTNcSYOkLa1sXJJeMFBkXKmFO2x/view?usp=drive_link) + - merges without giving way to traffic - does not respect open car door - crashes into car in front when going after stop at red light @@ -168,6 +172,8 @@ Here are the raw notes in case misunderstandings have been made when grouping th ### Run 3 +[Link to Video of the Run](https://drive.google.com/file/d/1ERvN3nGddzuvtRqtIF2PKlFrcMzH2MrA/view?usp=drive_link) + - does not give way when exiting a parking spot - LIDAR detects floor - trajectory for overtaking is wrong / no overtake needed From 9f66f64c5ff48e90559c98c5f9ed551a4819bd72 Mon Sep 17 00:00:00 2001 From: Ludwig <66259585+SirMDA@users.noreply.github.com> Date: Sun, 10 Nov 2024 13:27:25 +0100 Subject: [PATCH 16/61] Update .github/ISSUE_TEMPLATE/BUG.yml Co-authored-by: asamluka --- .github/ISSUE_TEMPLATE/BUG.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/ISSUE_TEMPLATE/BUG.yml b/.github/ISSUE_TEMPLATE/BUG.yml index a6a4b49a..2b5787e0 100644 --- a/.github/ISSUE_TEMPLATE/BUG.yml +++ b/.github/ISSUE_TEMPLATE/BUG.yml @@ -69,5 +69,6 @@ body: - perception: Related to sensor processing and scene understanding - planning: Related to path planning and decision making - acting: Related to vehicle control and actuation + - system: Related to the general behavior of the system - research: Related to research and experimentation - infrastructure: Related to system infrastructure and setup From d69d71aa25b3ebdf0d3248fa334bec04349993be Mon Sep 17 00:00:00 2001 From: Ludwig <66259585+SirMDA@users.noreply.github.com> Date: Sun, 10 Nov 2024 13:27:33 +0100 Subject: [PATCH 17/61] Update .github/ISSUE_TEMPLATE/FEATURE.yml Co-authored-by: asamluka --- .github/ISSUE_TEMPLATE/FEATURE.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/ISSUE_TEMPLATE/FEATURE.yml b/.github/ISSUE_TEMPLATE/FEATURE.yml index 80f6b3ac..2076d028 100644 --- a/.github/ISSUE_TEMPLATE/FEATURE.yml +++ b/.github/ISSUE_TEMPLATE/FEATURE.yml @@ -53,5 +53,6 @@ body: - perception: Related to sensor processing and scene understanding - planning: Related to path planning and decision making - acting: Related to vehicle control and actuation + - system: Related to the general behavior of the system - research: Related to research and experimentation - infrastructure: Related to system infrastructure and setup From 483fb6bc815772b98d9ba39fe205a7b52fcd0901 Mon Sep 17 00:00:00 2001 From: Ludwig <66259585+SirMDA@users.noreply.github.com> Date: Sun, 10 Nov 2024 13:27:42 +0100 Subject: [PATCH 18/61] Update .github/ISSUE_TEMPLATE/ISSUE.yml Co-authored-by: asamluka --- .github/ISSUE_TEMPLATE/ISSUE.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/ISSUE_TEMPLATE/ISSUE.yml b/.github/ISSUE_TEMPLATE/ISSUE.yml index 45ec9c37..e41a074c 100644 --- a/.github/ISSUE_TEMPLATE/ISSUE.yml +++ b/.github/ISSUE_TEMPLATE/ISSUE.yml @@ -68,5 +68,6 @@ body: - perception: Related to sensor processing and scene understanding - planning: Related to path planning and decision making - acting: Related to vehicle control and actuation + - system: Related to the general behavior of the system - research: Related to research and experimentation - infrastructure: Related to system infrastructure and setup From 71a3cdd22b2c64b84002f6f88d8c087ca5f46d61 Mon Sep 17 00:00:00 2001 From: Ludwig <66259585+SirMDA@users.noreply.github.com> Date: Sun, 10 Nov 2024 13:28:06 +0100 Subject: [PATCH 19/61] Update .github/ISSUE_TEMPLATE/ISSUE.yml Co-authored-by: asamluka --- .github/ISSUE_TEMPLATE/ISSUE.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/ISSUE.yml b/.github/ISSUE_TEMPLATE/ISSUE.yml index e41a074c..9b8c80ca 100644 --- a/.github/ISSUE_TEMPLATE/ISSUE.yml +++ b/.github/ISSUE_TEMPLATE/ISSUE.yml @@ -29,8 +29,8 @@ body: id: effort_estimate attributes: label: Effort Estimate - description: Estimate the effort required. - placeholder: Enter effort estimate here. + description: Approximate effort required (e.g., hours). + placeholder: Enter effort estimate. - type: textarea id: testability From 060bb9f93995dd3585fc09cc4761c7ecec8df198 Mon Sep 17 00:00:00 2001 From: Ludwig <66259585+SirMDA@users.noreply.github.com> Date: Sun, 10 Nov 2024 13:28:18 +0100 Subject: [PATCH 20/61] Update .github/ISSUE_TEMPLATE/FEATURE.yml Co-authored-by: asamluka --- .github/ISSUE_TEMPLATE/FEATURE.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/FEATURE.yml b/.github/ISSUE_TEMPLATE/FEATURE.yml index 2076d028..82d8c642 100644 --- a/.github/ISSUE_TEMPLATE/FEATURE.yml +++ b/.github/ISSUE_TEMPLATE/FEATURE.yml @@ -23,7 +23,7 @@ body: id: effort_estimate attributes: label: Effort Estimate - description: Estimated effort (e.g., in hours). + description: Approximate effort required (e.g., hours). placeholder: Enter effort estimate. - type: textarea From 14c098b4b4b84af351f714bfe87510905a534e52 Mon Sep 17 00:00:00 2001 From: Ludwig <66259585+SirMDA@users.noreply.github.com> Date: Sun, 10 Nov 2024 13:28:35 +0100 Subject: [PATCH 21/61] Update .github/ISSUE_TEMPLATE/ISSUE.yml Co-authored-by: asamluka --- .github/ISSUE_TEMPLATE/ISSUE.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/ISSUE.yml b/.github/ISSUE_TEMPLATE/ISSUE.yml index 9b8c80ca..25bc8724 100644 --- a/.github/ISSUE_TEMPLATE/ISSUE.yml +++ b/.github/ISSUE_TEMPLATE/ISSUE.yml @@ -44,7 +44,7 @@ body: attributes: label: Dependencies description: List dependencies, if any. - placeholder: Link dependencies here (e.g., #789). + placeholder: Link dependencies here (e.g., the issue #789). - type: markdown attributes: From 46451efcecd8b2355b8d137b00291122b53c9227 Mon Sep 17 00:00:00 2001 From: Ludwig Holl Date: Sun, 10 Nov 2024 14:17:00 +0100 Subject: [PATCH 22/61] added escape-character --- .github/ISSUE_TEMPLATE/BUG.yml | 2 +- .github/ISSUE_TEMPLATE/FEATURE.yml | 2 +- .github/ISSUE_TEMPLATE/ISSUE.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/BUG.yml b/.github/ISSUE_TEMPLATE/BUG.yml index 2b5787e0..aee5410c 100644 --- a/.github/ISSUE_TEMPLATE/BUG.yml +++ b/.github/ISSUE_TEMPLATE/BUG.yml @@ -54,7 +54,7 @@ body: attributes: label: Dependencies description: List any dependent tasks or issues. - placeholder: Link dependencies here (e.g., #123). + placeholder: Link dependencies here (e.g., \#123). - type: markdown attributes: diff --git a/.github/ISSUE_TEMPLATE/FEATURE.yml b/.github/ISSUE_TEMPLATE/FEATURE.yml index 82d8c642..366bab21 100644 --- a/.github/ISSUE_TEMPLATE/FEATURE.yml +++ b/.github/ISSUE_TEMPLATE/FEATURE.yml @@ -38,7 +38,7 @@ body: attributes: label: Dependencies description: List any dependencies on other issues. - placeholder: Link dependencies here (e.g., #456). + placeholder: Link dependencies here (e.g., \#456). - type: markdown attributes: diff --git a/.github/ISSUE_TEMPLATE/ISSUE.yml b/.github/ISSUE_TEMPLATE/ISSUE.yml index 25bc8724..6ad88fbf 100644 --- a/.github/ISSUE_TEMPLATE/ISSUE.yml +++ b/.github/ISSUE_TEMPLATE/ISSUE.yml @@ -44,7 +44,7 @@ body: attributes: label: Dependencies description: List dependencies, if any. - placeholder: Link dependencies here (e.g., the issue #789). + placeholder: Link dependencies here (e.g., the issue \#789). - type: markdown attributes: From 672709f6aefa84c9eab40481f6f3fc8ec5a37dd8 Mon Sep 17 00:00:00 2001 From: RoyaLxPole Date: Sun, 10 Nov 2024 18:05:40 +0100 Subject: [PATCH 23/61] create .md file for drawio board --- .../drawio_legend/Loesungs_Vorschlag.jpg | Bin 0 -> 18194 bytes .../research_assets/drawio_legend/Problem.jpg | Bin 0 -> 14081 bytes .../research_assets/drawio_legend/Team.jpg | Bin 0 -> 17935 bytes .../research_assets/drawio_legend/Ziel.jpg | Bin 0 -> 9260 bytes .../drawio_legend/gemeinsames_Problem.jpg | Bin 0 -> 16080 bytes .../drawio_legend/generell.jpg | Bin 0 -> 68683 bytes .../drawio_legend/two_teams_problem.jpg | Bin 0 -> 8646 bytes .../\303\234bergeordnetes_Problem.jpg" | Bin 0 -> 22890 bytes doc/general/drawio_board.md | 54 ++++++++++++++++++ 9 files changed, 54 insertions(+) create mode 100644 doc/assets/research_assets/drawio_legend/Loesungs_Vorschlag.jpg create mode 100644 doc/assets/research_assets/drawio_legend/Problem.jpg create mode 100644 doc/assets/research_assets/drawio_legend/Team.jpg create mode 100644 doc/assets/research_assets/drawio_legend/Ziel.jpg create mode 100644 doc/assets/research_assets/drawio_legend/gemeinsames_Problem.jpg create mode 100644 doc/assets/research_assets/drawio_legend/generell.jpg create mode 100644 doc/assets/research_assets/drawio_legend/two_teams_problem.jpg create mode 100644 "doc/assets/research_assets/drawio_legend/\303\234bergeordnetes_Problem.jpg" create mode 100644 doc/general/drawio_board.md diff --git a/doc/assets/research_assets/drawio_legend/Loesungs_Vorschlag.jpg b/doc/assets/research_assets/drawio_legend/Loesungs_Vorschlag.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2146e7dc9b4e8d928f8f3165e49407594acc203a GIT binary patch literal 18194 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 G?*9W>!ZslQ literal 0 HcmV?d00001 diff --git a/doc/assets/research_assets/drawio_legend/Team.jpg b/doc/assets/research_assets/drawio_legend/Team.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9274342394b192d08552c93db9f1cb288c15435c GIT binary patch literal 17935 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 z zi1aoJ7Ajq`!TMz=t#6Ky)zkFK|F%4LVop7wY+1gKbYV5DjziPyClhJ~!91D0ZaBCY zfP>kBZ8(T>LtuHMSE8Pzr7x(4-Lph$y6&M%|DW=}P@Wm)^(|bbCp~a4m%&zzz`S)yH|mcCTsATFlEkoN2Qcl6ck0=6XkXD>U73FWvWBTOXS#wTjTd&ey>A5YM zs^xQTYBmbz+^F{7zGJFu60xL?X&-%MUFaQa&6_Xz=gO=o%p3ydzYq2|ghm^TuqQvT zs1xPNST9|20Jer;>AaF;Rd;~a(b4p39nsTQYdw*|)pte0Z806#7XIVmwpU0e47IA~ zPaW0b^ZBy^^pBxWndpe3E5a8~FkofA&(~Faivy<8rM-pNXnA56@Td?iEiJgRa(4%R zDJ2qb2X=u>j`syUv5{q_c7PdC`@*r zj9)O96Bo4%9#WzFYd`khYwYi5{vxfIi36zu9CVt0o;H|k4N-1Ng8}pOz=?Lk0K5y^ ztn=sx%-45HVQkhyY}HB=t9#5x=eCDNA)Nxxy1C$@4XUaf#(#%I#eWT|@U;OWD_STJOZ*88|8hwOG z?u4DtirhJw0fNyIxJyh<1@IGHF6Iq zQg-_#K5!pn-C+XtiBfnoj>T~@`xZ=8Ep~wN7idj|Tlv~nqmg;h&U23};30_zVUMd4 z`Imwi8&04$4!ht$A}xRoo3ix(rTKHAU~FLp^f~%CeTN`A|A$zU98yqsK>2t_jk4%i2Oe|zYbWV(qyF#7H6z4EuCpt(SSi&igQL6I4G zc5BjT({5>l!Z57{slGzha>{mPCR5-I7i9_eb4exSWfCFzd3yCn;Af`jB zqH`-2_F`#B@#$GGyAi#J#n2iE)p1EP1bS!=k_rb|R-i2mcvc@s8(Ey3I`%H{^NVEy z1Sfp#gE&FDgu#-*c&&z&pU*LdY1OM%P_#yh<97;~8gZ0y;6766wt#X1;h?F&08S=0 zp4#M$Bgn8=Jz8T2x7b;WAR!CT6C^m;z|?>P7wtas_A^pA&Bg5rh1h-ja7dGf$tD3~ ugUoe-i@-koGv!y|l5=29eTp#Bj1C-xTzJA5F@y}lc5x^D9|lD6_x}S9f7|W= literal 0 HcmV?d00001 diff --git a/doc/assets/research_assets/drawio_legend/gemeinsames_Problem.jpg b/doc/assets/research_assets/drawio_legend/gemeinsames_Problem.jpg new file mode 100644 index 0000000000000000000000000000000000000000..01ec28e099e6cb843dc0112a513b85098b069df1 GIT binary patch literal 16080 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�f?|I07E$ ze7}9@Cj~fN!-v+oKorL_5gt-tf<*(AN5_9i+rUEHpU4D%%iAD7>zs5vVZ94H^LB&~ zu`@>%SjSiS#5T(oy`D)TT^oC+lq?<(y|8D42~1gno_SkS51^kkx64)+BH5l-Tc$h@ zog8y9yJ>QEcaxy8*OBOmgWDR-_0XaF-3Xo9ssT?HlAqtp*_gpqVV1LR>8~dz(=#aw zmVG8)Ad=khqRk`mN%`{+P|67`G9h2x_YnU+z(Mh}=-sf-eh{Js#X?r1X4JUo z1i(%>yX&SKRr)=+E6#*%vQlx>QoRctz2G06bZ9_S7}$&k&mPT}zX5-}O9isoxd~1R zSo=?ZFA3--QLMo;AZNiX^&VkTG!3YsI4XjKemc|0b$yo^IMXZ~wW38`-OQZ_$D85M zMV{~zbT7bXS++t{TsM2Z6SV~w!-IlOkGE4Rkrcj7qwo_z-XY2*8c>VK;=0awAH4lM zVz85F@O?x&hP@s!27MoXf?o0af6KsLK!^T1wFXLkWS{;}>^lR(AlHa$Xq<)`7ho_- uu|Py}U1#_{i`4tK^DPM4@c#mxAPuSj literal 0 HcmV?d00001 diff --git a/doc/assets/research_assets/drawio_legend/generell.jpg b/doc/assets/research_assets/drawio_legend/generell.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9dd47446ff4d53890876a4b532f6db390b93611b GIT binary patch literal 68683 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�tbRazpa^fOv3D|ug3Xz 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 Ou=Zb*{%4c^QvW|fO@5jH literal 0 HcmV?d00001 diff --git a/doc/assets/research_assets/drawio_legend/two_teams_problem.jpg b/doc/assets/research_assets/drawio_legend/two_teams_problem.jpg new file mode 100644 index 0000000000000000000000000000000000000000..79b917c0d02cccfa97a4aedeae5899ccbd692e93 GIT binary patch literal 8646 zcmeHsc|4SD`}ZaLmdMt^++~fBy#>=IBt#*^%H{c@BQ9&-_PfLp5NcUYv!CkuDP!B{2t%)dmhJe9w+z(90hirKWA_b zU}9ndox2ChTdUeA#kSkjp8cSwpvwK|G!BW=rFBAPog_)s-@Sr4xr9YT_w1FDmXSRqr>3rFFDszjWE$!t#ohwS(hzC+8b3uD9=a`}q3#2ZTHbeHivAJR&AGE>31kn3q$gLPP1(8PdzB`dh4Ho^@{b8&{X}-P=Vv{B1>D+s!FN$kgu-|d@lgQDs z>_YJCh||?b?g;^*VfDOlYf^1CPx8%Tkw@y@Rwp+*tG4nd;{#O0U-+}DcbW z@}X%}6%A zFI^b~(hcoFAXK<`o1r;r%5{md%J;VL!(N`_VpsTD7t{hzm!J!ioLAwmDJ|l~j5&t6 zSYWCo<@XvLfiLJW-F)P@$ z=X!uZzf50kyMOH-{Q)@V9s1}_tuy&MLtv|``ma#Rm!e4t^>DKC-s)n=itE@m#>6-+mSNkt*+}L3r`Lx5 z{Zv{M!zV@>8LzQhqU&VEU)X%!jZ(ROF-TyJVtOA0gmxCro6zZ-oqrj2ZL@VfD`m?K z1m3!RUjP9f^lZ$JxdDL{b2gKQlCdDbl~51;C?FvEa%rL0{#5;Q7zzZc(DBfU;nWc= zrgz!!(Pg)_p82za|6=BZF0`a%dba1ZJCq^p|EP>Egh|lV7?Y{5!mOrWT$!k0NRG-bdYwpyC+o|;ZsMe=`?~C?k3HdAV zSu(x2R(7cBj?|JO#^m+NG5Dki5(I2BLEy7P9zI7p$A2q@Ij|_O!HP-8!Fe&K#)8pX z0|MAq%qEREaW&`l8Ba#}7W+!>{C8T`?9=hZpb&<2WlmqxR{mWOfG5H>)(H*ww5!QV z7-ZuKds?Y z0bJA&vI4~5j0*@{3xxPKvh-dga?ovEMzO+?X3LKv56D%YI_A;h`A++Ou`|1foR9!q zt3zIo@AM=CfItT~q$jC$1VgVl1$|@oS|ue7&HIXDVPYgYea(Eg z!96&S zDo3Zw-<#o#bC!50iDC~vjvl+!E0`Q}vm-lqb+2rCO~}gA^axqtzima2-`gn|ah=#w zy;SnpmQ-6P8e-mg^U9;e4E6)}_czMHk|gae(}GXU+{lu}DOxG;x|rimr{^0C8anwm zHe&9}j1^{M3n@YC>m5we zh9h-Efxr&f*pq}R#(i(a>QP?nbG9eU9e3zUGAp>;$#^t#igJ{i_}lX8(E|C@#oFEE zuNbYIQ@%3!2fn$HT&5K58s#1kf)%-;|+*XrWa#i^}9oB`Nq&&th@FcP6nzJvtBNRYm3 z256Ms7;JoiKd3XDbF*H4r?8*sR G9SOMsw%0WIeis8P?2B%koY!>JOol70tRtd0 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 O52?iK{c(d29QZ!~&V=&- literal 0 HcmV?d00001 diff --git "a/doc/assets/research_assets/drawio_legend/\303\234bergeordnetes_Problem.jpg" "b/doc/assets/research_assets/drawio_legend/\303\234bergeordnetes_Problem.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..888626278dbf3bd1ebe250e799ef5583ad199f28 GIT binary patch literal 22890 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 Date: Sun, 10 Nov 2024 20:50:26 +0100 Subject: [PATCH 24/61] Update doc/general/drawio_board.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- doc/general/drawio_board.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/doc/general/drawio_board.md b/doc/general/drawio_board.md index b47e4095..77ec41f4 100644 --- a/doc/general/drawio_board.md +++ b/doc/general/drawio_board.md @@ -1,12 +1,11 @@ # Drawio Board for planning future work -**Summary:** This page gives an overview over the usage of the draw.io board and gives links to videos to give general tipps how to work with draw.io +**Summary:** This page provides an overview of the draw.io board usage and provides links to videos with general tips on how to work with draw.io - [Drawio Board for planning future work](#drawio-board-for-planning-future-work) - -[Link](#link) - -[Legend](#legend) - -[Tips](#tips) - + - [Link](#link) + - [Legend](#legend) + - [Tips](#tips) ## Link From 9f9f371033c1501688ed3203c8cbce083f0c84b3 Mon Sep 17 00:00:00 2001 From: RoyaLxPole <124280467+RoyaLxPole@users.noreply.github.com> Date: Sun, 10 Nov 2024 20:50:52 +0100 Subject: [PATCH 25/61] Update doc/general/drawio_board.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- doc/general/drawio_board.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/general/drawio_board.md b/doc/general/drawio_board.md index 77ec41f4..647a39af 100644 --- a/doc/general/drawio_board.md +++ b/doc/general/drawio_board.md @@ -42,7 +42,7 @@ This node is used to provide a description for an atomic problem that cannot be This node is used to describe the approach to the problem. If an issue has already been created on GitHub, the issue number should be included here. ![generell](../assets/research_assets/drawio_legend/generell.jpg) -This nodes are used to describe problems that have not yet been assigned to a team or to describe a problem that affects all teams equally. +These nodes are used to describe problems that have not yet been assigned to a team or to describe problems that affect all teams equally. ## Tips From 635475f36f77f8da37e23fda92fb840b68c02978 Mon Sep 17 00:00:00 2001 From: RoyaLxPole <124280467+RoyaLxPole@users.noreply.github.com> Date: Sun, 10 Nov 2024 20:51:22 +0100 Subject: [PATCH 26/61] Update doc/general/drawio_board.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- doc/general/drawio_board.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/general/drawio_board.md b/doc/general/drawio_board.md index 647a39af..20157973 100644 --- a/doc/general/drawio_board.md +++ b/doc/general/drawio_board.md @@ -13,7 +13,7 @@ The work on the draw.io board please click [here](https://drive.google.com/drive ## Legend -Please use the predefined nodes if you´re working with the board, if you thing there is missing something please contact Marcin Kuhnert (Discord: RoyaLxPole) for the PAF24. +Please use the predefined nodes when working with the board. If you think something is missing, please contact Marcin Kuhnert (Discord: RoyaLxPole) for the PAF24. Explanation: ![Ziele](../assets/research_assets/drawio_legend/Ziel.jpg) From 7595cb59f09bfb62c79c5f13dfb06bb5054e34dd Mon Sep 17 00:00:00 2001 From: RoyaLxPole <124280467+RoyaLxPole@users.noreply.github.com> Date: Sun, 10 Nov 2024 20:51:40 +0100 Subject: [PATCH 27/61] Update doc/general/drawio_board.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- doc/general/drawio_board.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/general/drawio_board.md b/doc/general/drawio_board.md index 20157973..e22fc089 100644 --- a/doc/general/drawio_board.md +++ b/doc/general/drawio_board.md @@ -9,7 +9,7 @@ ## Link -The work on the draw.io board please click [here](https://drive.google.com/drive/folders/1dNyrnDdsj0m7kymDQUUqu2WinR4lQJpe) +To access the draw.io board, please click [here](https://drive.google.com/drive/folders/1dNyrnDdsj0m7kymDQUUqu2WinR4lQJpe) ## Legend From 84884e1a8b528f1089b581985fdaa6e3811d3d0d Mon Sep 17 00:00:00 2001 From: RoyaLxPole <124280467+RoyaLxPole@users.noreply.github.com> Date: Sun, 10 Nov 2024 20:58:44 +0100 Subject: [PATCH 28/61] litter update --- doc/general/drawio_board.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/general/drawio_board.md b/doc/general/drawio_board.md index e22fc089..1b866821 100644 --- a/doc/general/drawio_board.md +++ b/doc/general/drawio_board.md @@ -3,9 +3,9 @@ **Summary:** This page provides an overview of the draw.io board usage and provides links to videos with general tips on how to work with draw.io - [Drawio Board for planning future work](#drawio-board-for-planning-future-work) - - [Link](#link) - - [Legend](#legend) - - [Tips](#tips) + - [Link](#link) + - [Legend](#legend) + - [Tips](#tips) ## Link @@ -20,14 +20,14 @@ Explanation: This node is primarily for the software engineers who define the goals or sub-goals to be achieved for all teams. The goals should be defined as precisely as possible.These goals are added either in a separate graph or directly above the problems. - ![Team](../assets/research_assets/drawio_legend/Team.jpg) This node is for assigning the respective teams or a person from a team. Each team is assigned its own color. Green for Perception, Red for Acting, and Blue for Planning. ![Uebergeordnetes Problem](../assets/research_assets/drawio_legend/Übergeordnetes_Problem.jpg) -This node is used to describe a higher-level problem that cannot currently be defined in detail or can be broken down into smaller problems. As described in the previous node, each team has its own color. If there is a problem that affects two teams, the color is determined by adding the colors in hexadecimal notation. +This node is used to describe a higher-level problem that cannot currently be defined in detail or can be broken down into smaller problems. As described in the previous node, each team has its own color. +If there is a problem that affects two teams, the color is determined by adding the colors in hexadecimal notation. ![two teams prolbem](../assets/research_assets/drawio_legend/two_teams_problem.jpg) @@ -50,4 +50,4 @@ For effective work on the board, please watch the following video and read the b [Video](https://www.google.com/search?q=draw.io+mind+map+tutorial&rlz=1C1VDKB_deDE929DE929&oq=draw+io+mind&gs_lcrp=EgZjaHJvbWUqCAgDEAAYFhgeMggIABBFGCcYOzIGCAEQRRg5MgcIAhAAGIAEMggIAxAAGBYYHjIICAQQABgWGB4yCAgFEAAYFhgeMgYIBhBFGDwyBggHEEUYPdIBCDgyNzBqMGo3qAIAsAIA&sourceid=chrome&ie=UTF-8#fpstate=ive&vld=cid:6448d106,vid:mooBFL_jhxg,st:0) -[Blog](https://drawio-app.com/blog/organization-charts-and-mind-maps-in-draw-io/) \ No newline at end of file +[Blog](https://drawio-app.com/blog/organization-charts-and-mind-maps-in-draw-io/) From 86e5fc4a7994f1fe9e4eb82af3918b2c305d9bc6 Mon Sep 17 00:00:00 2001 From: JulianTrommer <46600808+JulianTrommer@users.noreply.github.com> Date: Tue, 12 Nov 2024 09:21:19 +0100 Subject: [PATCH 29/61] Updated docs of GitHub actions --- .github/workflows/build.yml | 2 +- doc/development/build_action.md | 50 +++++++++++++++++++++++++++------ doc/development/drive_action.md | 46 ++++++++++++++++++++++++------ 3 files changed, 81 insertions(+), 17 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b6682121..04e74f47 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -123,5 +123,5 @@ jobs: rm -rf /tmp/.buildx-cache/cache/latest mv /tmp/.buildx-cache/cache-new/latest /tmp/.buildx-cache/cache/latest - - name: Prune all images older than 1 days from self-hosted runner + - name: Prune all images older than 1 day from self-hosted runner run: docker image prune -a -f --filter "until=24h" \ No newline at end of file diff --git a/doc/development/build_action.md b/doc/development/build_action.md index 191f8ae2..ec534253 100644 --- a/doc/development/build_action.md +++ b/doc/development/build_action.md @@ -8,9 +8,16 @@ - [The `build-and-push-image` job](#the-build-and-push-image-job) - [1. Checkout repository (`actions/checkout@v3`)](#1-checkout-repository-actionscheckoutv3) - [2. Set up Docker Buildx (`docker/setup-buildx-action@v2`)](#2-set-up-docker-buildx-dockersetup-buildx-actionv2) - - [3. Log in to the Container registry (`docker/login-action@v2`)](#3-log-in-to-the-container-registry-dockerlogin-actionv2) - - [4. Test building the image (`docker/build-push-action@v3`)](#4-test-building-the-image-dockerbuild-push-actionv3) - - [5. Build and push the image (`docker/build-push-action@v3`)](#5-build-and-push-the-image-dockerbuild-push-actionv3) + - [3. Cache Docker layers](#3-cache-docker-layers) + - [4. Log in to the Container registry (`docker/login-action@v2`)](#4-log-in-to-the-container-registry-dockerlogin-actionv2) + - [5. Test building the image (`docker/build-push-action@v3`)](#5-test-building-the-image-dockerbuild-push-actionv3) + - [6. Build and push the image (`docker/build-push-action@v3`)](#6-build-and-push-the-image-dockerbuild-push-actionv3) + - [7. Save pull request artifact](#7-save-pull-request-artifact) + - [8. Save merge artifact](#8-save-merge-artifact) + - [9. Upload artifact](#9-upload-artifact) + - [10. Clean up PR Cache](#10-clean-up-pr-cache) + - [11. Clean up merge Cache](#11-clean-up-merge-cache) + - [12. Prune all images older than one day](#12-prune-all-images-older-than-one-day) ## General @@ -21,8 +28,7 @@ to [GitHub Packages](ghcr.io). The image can then be pulled with `docker pull ghcr.io/una-auxme/paf:latest` to get the latest version or `docker pull ghcr.io/una-auxme/paf:` to get a specific version. -If action is triggered by a pull request the created image is then used to execute a test run in the leaderboard, using -the devtest routes. The results of this simulation are then added as a comment to the pull request. +After the action is finished the `drive` action is triggered. ## The `build-and-push-image` job @@ -37,19 +43,47 @@ Set's up Buildx. This is needed to set up the correct driver to allow caching in Detailed description why this is needed can be found [here](https://github.com/docker/build-push-action/issues/163#issuecomment-1053657228). -### 3. Log in to the Container registry ([`docker/login-action@v2`](https://github.com/docker/login-action)) +### 3. Cache Docker layers + +Creates (if not done previously) and sets up the cache for the Docker layers. + +### 4. Log in to the Container registry ([`docker/login-action@v2`](https://github.com/docker/login-action)) Logs in with `GITHUB_TOKEN` into the registry (ghcr.io). Example taken from [here](https://docs.github.com/en/actions/publishing-packages/publishing-docker-images) -### 4. Test building the image ([`docker/build-push-action@v3`](https://github.com/docker/build-push-action/)) +### 5. Test building the image ([`docker/build-push-action@v3`](https://github.com/docker/build-push-action/)) Tries to build the image without pushing it to the repository packages if the workflow was triggered with a pull request. -### 5. Build and push the image ([`docker/build-push-action@v3`](https://github.com/docker/build-push-action/)) +### 6. Build and push the image ([`docker/build-push-action@v3`](https://github.com/docker/build-push-action/)) This action builds the image and pushes it to repository under the `latest` tag if the workflow was triggered with a merge to the `main` branch. To avoid large downloads of the base image the [GitHub Actions cache](https://docs.docker.com/build/building/cache/backends/gha/) is used to cache the image after build. + +### 7. Save pull request artifact + +If the action was triggered by a pull request an artifact is created with the corresponding PR ID (used for commenting on the PR in the `drive` action). + +### 8. Save merge artifact + +If the action was triggered by a merge an artifact is created with an invalid PR ID to signalise the `drive` action that it was not triggered by a PR. + +### 9. Upload artifact + +Uploads the artifact to the given path with a retention of the given number of days. + +### 10. Clean up PR Cache + +Removes the previous obsolete PR cache. + +### 11. Clean up merge Cache + +Removes the previous obsolete test cache. + +### 12. Prune all images older than one day + +Removes all images from the runner that are older than one day to free disk space. diff --git a/doc/development/drive_action.md b/doc/development/drive_action.md index b5570002..eef9ed89 100644 --- a/doc/development/drive_action.md +++ b/doc/development/drive_action.md @@ -4,11 +4,17 @@ - [The drive job](#the-drive-job) - [1. Checkout repository (`actions/checkout@v3`)](#1-checkout-repository-actionscheckoutv3) - - [2. Run agent with docker-compose](#2-run-agent-with-docker-compose) - - [3. Copy simulation results file out of container](#3-copy-simulation-results-file-out-of-container) - - [4. Stop docker-compose stack](#4-stop-docker-compose-stack) - - [5. Comment result in pull request `actions/github-script@v6`](#5-comment-result-in-pull-request-actionsgithub-scriptv6) + - [2. Download artifact](#2-download-artifact) + - [3. Unzip artifact](#3-unzip-artifact) + - [4. Return artifact JSON](#4-return-artifact-json) + - [5. Run agent with docker-compose](#5-run-agent-with-docker-compose) + - [6. Copy simulation results file out of container](#6-copy-simulation-results-file-out-of-container) + - [7. Stop docker-compose stack](#7-stop-docker-compose-stack) + - [8. Create simulation results table](#8-create-simulation-results-table) + - [9. Print simulation results](#9-print-simulation-results) + - [10. Comment result in pull request `actions/github-script@v6`](#10-comment-result-in-pull-request-actionsgithub-scriptv6) - [Simulation results](#simulation-results) + - [11. Prune all images older than one day](#11-prune-all-images-older-than-one-day) ## The drive job @@ -20,7 +26,19 @@ The `drive` job is executed conditionally on `pull_request`, after the build suc Same step as in the [build job](#1-checkout-repository--actionscheckoutv3-) -### 2. Run agent with docker-compose +### 2. Download artifact + +Downloads the artifact that was uploaded during the preceeding `build` action. + +### 3. Unzip artifact + +Extracts the files of the downloaded artifact. + +### 4. Return artifact JSON + +Parses the extracted file in the JSON format to read the information inside the file. + +### 5. Run agent with docker-compose Runs the agent with the [`build/docker-compose.cicd.yaml`](../../build/docker-compose.cicd.yaml) that only contains the bare minimum components for test execution: @@ -30,11 +48,11 @@ bare minimum components for test execution: - Agent container, run through the Carla [`leaderboard_evaluator`](https://github.com/carla-simulator/leaderboard/blob/leaderboard-2.0/leaderboard/leaderboard_evaluator.py). -### 3. Copy simulation results file out of container +### 6. Copy simulation results file out of container Copies the created `simulation_results.json` file out of the agent container into the current container -### 4. Stop docker-compose stack +### 7. Stop docker-compose stack Stops the remaining containers (Carla, roscore) and removes the volumes with: `$ docker-compose down -v`. @@ -42,7 +60,15 @@ Stops the remaining containers (Carla, roscore) and removes the volumes with: This step is important to clean up the remaining containers to have a clean run everytime. This is also the reason for the `if: always()`, that ensures step execution. -### 5. Comment result in pull request [`actions/github-script@v6`](https://github.com/marketplace/actions/github-script) +### 8. Create simulation results table + +Reads the simulation results an creates a table for better readability. + +### 9. Print simulation results + +Prints the simulation results table to the action. + +### 10. Comment result in pull request [`actions/github-script@v6`](https://github.com/marketplace/actions/github-script) This steps uses a JS script to parse the simulation results and add a comment with a results table to the corresponding pull request. @@ -68,3 +94,7 @@ An example comment for this would be: | Yield emergency vehicles infractions | 0.0 | | Scenario timeouts | 62.046 | | Min speed infractions | 0.0 | + +### 11. Prune all images older than one day + +Removes all images from the runner that are older than one day to free disk space. \ No newline at end of file From 3f7378710e8eef39b08dc98e9781b8e0588067d8 Mon Sep 17 00:00:00 2001 From: JulianTrommer <46600808+JulianTrommer@users.noreply.github.com> Date: Tue, 12 Nov 2024 09:30:50 +0100 Subject: [PATCH 30/61] Added newline to drive action --- doc/development/drive_action.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/development/drive_action.md b/doc/development/drive_action.md index eef9ed89..b734105b 100644 --- a/doc/development/drive_action.md +++ b/doc/development/drive_action.md @@ -97,4 +97,4 @@ An example comment for this would be: ### 11. Prune all images older than one day -Removes all images from the runner that are older than one day to free disk space. \ No newline at end of file +Removes all images from the runner that are older than one day to free disk space. From 6ed2ae2c722ae017d9a24ec6f0c068cb53334b85 Mon Sep 17 00:00:00 2001 From: Peter Viechter Date: Tue, 12 Nov 2024 15:02:26 +0100 Subject: [PATCH 31/61] Improve dockerfile ENV var usage --- build/docker/agent/Dockerfile | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/build/docker/agent/Dockerfile b/build/docker/agent/Dockerfile index 48818408..fb6d9202 100644 --- a/build/docker/agent/Dockerfile +++ b/build/docker/agent/Dockerfile @@ -162,11 +162,10 @@ RUN source ~/.bashrc && pip install -r /workspace/requirements.txt # Add agent code COPY --chown=$USERNAME:$USERNAME ./code /workspace/code/ -# Link code into catkin workspace -RUN ln -s /workspace/code /catkin_ws/src - # For debugger ENV PAF_CATKIN_CODE_ROOT=/catkin_ws/src +# Link code into catkin workspace +RUN ln -s /workspace/code ${PAF_CATKIN_CODE_ROOT} # re-make the catkin workspace RUN source /opt/ros/noetic/setup.bash && catkin_make From 96240644773f57c45a927e0bbf107b2ef6e9618d Mon Sep 17 00:00:00 2001 From: Peter Viechter Date: Tue, 12 Nov 2024 15:04:27 +0100 Subject: [PATCH 32/61] Remove unnecessary uses of BaseException and fix debug_wait flag --- code/debug_wrapper.py | 8 +++++--- code/debugging/src/debug_logger.py | 2 +- doc/development/debugging.md | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/code/debug_wrapper.py b/code/debug_wrapper.py index c02d8d0a..924f7037 100755 --- a/code/debug_wrapper.py +++ b/code/debug_wrapper.py @@ -77,7 +77,7 @@ def log(msg: str, level: str): conn.send({"name": NODE_NAME, "msg": msg, "level": level}) conn.close() success = True - except BaseException as e: + except Exception as e: error = e if not success: eprint(msg) @@ -135,7 +135,7 @@ def start_debugger( logwarn(f"Started debugger on {host}:{port} for {node_module_name}") if wait_for_client: debugpy.wait_for_client() - except BaseException as error: + except Exception as error: # Yes, all exceptions should be catched and sent into rosconsole logerr(f"Failed to start debugger: {error}") else: @@ -164,7 +164,7 @@ def main(argv): parser.add_argument("--debug_node", required=True, type=str) parser.add_argument("--debug_port", required=False, type=int) parser.add_argument("--debug_host", default=default_host, type=str) - parser.add_argument("--debug_wait", default=False, type=bool) + parser.add_argument("--debug_wait", action="store_true") args, unknown_args = parser.parse_known_args(node_args) debug_node = args.debug_node @@ -190,6 +190,8 @@ def main(argv): try: run_module_at(target_type_path) except BaseException as error: + # Yes, all exceptions including SystemExit should be catched. + # We want to always know when a node exits logfatal(f"Failed to run node {debug_node}: {error}") raise error diff --git a/code/debugging/src/debug_logger.py b/code/debugging/src/debug_logger.py index 6778531d..317843ce 100755 --- a/code/debugging/src/debug_logger.py +++ b/code/debugging/src/debug_logger.py @@ -100,7 +100,7 @@ def close_listener(): conn = Client(ADDRESS, authkey=AUTHKEY) conn.send(CLOSE_MSG) conn.close() - except BaseException: + except Exception: pass diff --git a/doc/development/debugging.md b/doc/development/debugging.md index 9d364145..42003d96 100644 --- a/doc/development/debugging.md +++ b/doc/development/debugging.md @@ -96,7 +96,7 @@ Configuration example for the [lidar_distance.py](../../code/perception/src/lida ``` By default, the affected node will start up as usual. When you attach the debugger later, you are then only able to debug the callbacks the node receives. -But if you set `--debug_wait=True`, it will block the node from starting until VS Code attaches and allow you to debug the initialization of the node. +But if you set `--debug_wait`, it will block the node from starting until VS Code attaches and allow you to debug the initialization of the node. If the leaderboard hangs on `Setting up the agent` after the configuration has been adjusted, there most likely is a mistake in the launch configuration. From b4c3ed8843cfeaa829745bf38da25716b9ea961b Mon Sep 17 00:00:00 2001 From: Peter Viechter Date: Tue, 12 Nov 2024 15:06:41 +0100 Subject: [PATCH 33/61] Remove pyrightconfig (unnecessary for this issue) --- pyrightconfig.json | 25 ------------------------- 1 file changed, 25 deletions(-) delete mode 100644 pyrightconfig.json diff --git a/pyrightconfig.json b/pyrightconfig.json deleted file mode 100644 index 5cafbb7c..00000000 --- a/pyrightconfig.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "include": ["code/src"], - - "exclude": [], - - "ignore": [], - - "defineConstant": { - "DEBUG": true - }, - - "typeCheckingMode": "standard", - "strictListInference": true, - "strictDictionaryInference": true, - "strictSetInference": true, - - "pythonVersion": "3.8", - "pythonPlatform": "Linux", - - "executionEnvironments": [ - { - "root": "code/src" - } - ] -} From 2302dc9d968cba94a4c22d367b4c161555cbea6c Mon Sep 17 00:00:00 2001 From: Peter Viechter Date: Tue, 12 Nov 2024 15:16:57 +0100 Subject: [PATCH 34/61] Add rough architecture documentation based on CodeRabbit --- doc/development/debugging.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/doc/development/debugging.md b/doc/development/debugging.md index 42003d96..3e26453f 100644 --- a/doc/development/debugging.md +++ b/doc/development/debugging.md @@ -11,6 +11,7 @@ - [Required once for the node you want to debug](#required-once-for-the-node-you-want-to-debug) - [Debugging workflow after setup](#debugging-workflow-after-setup) - [Known problems of debugging with VS Code](#known-problems-of-debugging-with-vs-code) + - [Debug Components Architecture](#debug-components-architecture) - [Rebuild docker containers](#rebuild-docker-containers) - [Sources](#sources) @@ -100,8 +101,6 @@ But if you set `--debug_wait`, it will block the node from starting until VS Cod If the leaderboard hangs on `Setting up the agent` after the configuration has been adjusted, there most likely is a mistake in the launch configuration. -More usage information can be found in the [debug_wrapper](../../code/debug_wrapper.py) and the [debug_logger](../../code/debugging/src/debug_logger.py) - #### Debugging workflow after setup 1. Start/Restart the [leaderboard](../../build/docker-compose.leaderboard.yaml) as usual @@ -117,6 +116,15 @@ With the **rqt_console** GUI you can filter by node *debug_logger* to see all me - Adjusting the launch configurations is a bit cumbersome - The side effects of just "stopping" a node with the debugger are unknown +#### Debug Components Architecture + +More technical usage information can be found in the: + +- [debug_wrapper](../../code/debug_wrapper.py): Acts as a proxy that wraps the target node and enables remote debugging capabilities. +- [debug_logger](../../code/debugging/src/debug_logger.py): Handles the logging of debugging-related events and exceptions, ensuring they are properly published to the ROS ecosystem. + +The wrapper uses the logger to ensure that any debugging-related issues (connection problems, initialization errors, etc.) are visible through the /rosout topic. + ## Rebuild docker containers The docker images on your pc might not match the latest Dockerfile in the repository From 4db8bdaa4ff8fac8812e10194f3e6bab3cdd8d09 Mon Sep 17 00:00:00 2001 From: Peter Viechter Date: Tue, 12 Nov 2024 15:30:51 +0100 Subject: [PATCH 35/61] Fix message ordering in logger --- code/debugging/src/debug_logger.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/debugging/src/debug_logger.py b/code/debugging/src/debug_logger.py index 317843ce..4d45b6f5 100755 --- a/code/debugging/src/debug_logger.py +++ b/code/debugging/src/debug_logger.py @@ -136,7 +136,7 @@ def main(): while NODE_RUNNING: with MESSAGES_MUTEX: while len(MESSAGES) > 0: - msg = MESSAGES.pop() + msg = MESSAGES.pop(0) log_msg = "Wrong log message format" log_name = "NAMERR" log_level = "fatal" From 09342c27c09b301e6af828ebbc70063b320237fc Mon Sep 17 00:00:00 2001 From: Peter Viechter Date: Tue, 12 Nov 2024 15:50:42 +0100 Subject: [PATCH 36/61] Add exception handling to the receiver in the debug_logger --- code/debugging/src/debug_logger.py | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/code/debugging/src/debug_logger.py b/code/debugging/src/debug_logger.py index 4d45b6f5..62f7eb4b 100755 --- a/code/debugging/src/debug_logger.py +++ b/code/debugging/src/debug_logger.py @@ -79,16 +79,21 @@ def run_listener(listener: Listener): """ running = True while running: - conn = listener.accept() - print(f"[debug_logger]: connection accepted from {listener.last_accepted}") - msg = None - if conn.poll(timeout=2.0): - msg = conn.recv() - if isinstance(msg, str): - if msg.lower() == CLOSE_MSG: - running = False - msg = None - conn.close() + try: + conn = listener.accept() + print(f"[debug_logger]: connection accepted from {listener.last_accepted}") + msg = None + if conn.poll(timeout=2.0): + msg = conn.recv() + if isinstance(msg, str): + if msg.lower() == CLOSE_MSG: + running = False + msg = None + conn.close() + except Exception as error: + eprint(f"Failed to receive message: {error}") + continue + if msg is not None: with MESSAGES_MUTEX: MESSAGES.append(msg) From bda286aae58d6adeeedaa376fbfaefe0e285ada5 Mon Sep 17 00:00:00 2001 From: Peter Viechter Date: Tue, 12 Nov 2024 16:28:31 +0100 Subject: [PATCH 37/61] Fix PAF_CATKIN_CODE_ROOT path --- build/docker/agent/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/docker/agent/Dockerfile b/build/docker/agent/Dockerfile index fb6d9202..e2176159 100644 --- a/build/docker/agent/Dockerfile +++ b/build/docker/agent/Dockerfile @@ -163,9 +163,9 @@ RUN source ~/.bashrc && pip install -r /workspace/requirements.txt COPY --chown=$USERNAME:$USERNAME ./code /workspace/code/ # For debugger -ENV PAF_CATKIN_CODE_ROOT=/catkin_ws/src +ENV PAF_CATKIN_CODE_ROOT=/catkin_ws/src/code # Link code into catkin workspace -RUN ln -s /workspace/code ${PAF_CATKIN_CODE_ROOT} +RUN ln -s -T /workspace/code ${PAF_CATKIN_CODE_ROOT} # re-make the catkin workspace RUN source /opt/ros/noetic/setup.bash && catkin_make From 5716ef77d2853b2ca988a1feeb6d17153cf90a01 Mon Sep 17 00:00:00 2001 From: Peter Viechter Date: Tue, 12 Nov 2024 16:28:52 +0100 Subject: [PATCH 38/61] Add warning when debugging with debug_wait --- code/debug_wrapper.py | 1 + 1 file changed, 1 insertion(+) diff --git a/code/debug_wrapper.py b/code/debug_wrapper.py index 924f7037..cafd493f 100755 --- a/code/debug_wrapper.py +++ b/code/debug_wrapper.py @@ -134,6 +134,7 @@ def start_debugger( debugpy.listen((host, port)) logwarn(f"Started debugger on {host}:{port} for {node_module_name}") if wait_for_client: + logwarn("Waiting until debugging client is attached...") debugpy.wait_for_client() except Exception as error: # Yes, all exceptions should be catched and sent into rosconsole From 676073ee2bd6cccd89648bbc6d31b17918e9c3f5 Mon Sep 17 00:00:00 2001 From: vinzenzm Date: Tue, 12 Nov 2024 23:43:57 +0100 Subject: [PATCH 39/61] Removed one version of the catkin_make task. As the addition of a vscode extension is no problem, the cumbersome way of selecting the task via an input field was removed. This now requires the tasksshellinput extension. --- .vscode/tasks.json | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/.vscode/tasks.json b/.vscode/tasks.json index e59d7898..9f845638 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -2,30 +2,16 @@ "version": "2.0.0", "tasks": [ { - "label": "Run 'catkin_make' in Docker container. Write container name.", + "label": "Run 'catkin_make' in docker container. Choose container from list of running containers.", "type": "shell", "command": "docker exec -it ${input:container_name} bash -c 'cd ../../catkin_ws && source /opt/ros/noetic/setup.bash && bash devel/setup.bash && catkin_make'", "problemMatcher": [], - "detail": "Executes 'catkin_make' in built-agent-dev-1 container. The container must be running.", - "dependsOn": [], - }, - { - "label": "Run 'catkin_make' in docker container. Autochoose docker container.", - "type": "shell", - "command": "docker exec -it ${input:container_name_shell} bash -c 'cd ../../catkin_ws && source /opt/ros/noetic/setup.bash && bash devel/setup.bash && catkin_make'", - "problemMatcher": [], - "detail": "Executes 'catkin_make' selected container. Requires Tasks Shell Input Extension.", + "detail": "Executes 'catkin_make' selected container. Requires Tasks Shell Input Extension, in order to generate the list of containers.", } ], "inputs": [ { "id": "container_name", - "description": "Name of docker container", - "default": "build-agent-dev-1", - "type": "promptString" - }, - { - "id": "container_name_shell", "type": "command", "command": "shellCommand.execute", "args": { From 634f678a5df379c314c326457bc8367ba0a23477 Mon Sep 17 00:00:00 2001 From: Ralf Date: Wed, 13 Nov 2024 12:50:37 +0100 Subject: [PATCH 40/61] Add first draft of radar node --- code/perception/launch/perception.launch | 6 ++ code/perception/src/radar_node.py | 97 ++++++++++++++++++++++++ 2 files changed, 103 insertions(+) create mode 100755 code/perception/src/radar_node.py diff --git a/code/perception/launch/perception.launch b/code/perception/launch/perception.launch index 8d6072e7..302a97d6 100644 --- a/code/perception/launch/perception.launch +++ b/code/perception/launch/perception.launch @@ -79,4 +79,10 @@ + + + + + + diff --git a/code/perception/src/radar_node.py b/code/perception/src/radar_node.py new file mode 100755 index 00000000..b35060c1 --- /dev/null +++ b/code/perception/src/radar_node.py @@ -0,0 +1,97 @@ +#!/usr/bin/env python +import rospy +import ros_numpy +import numpy as np +import lidar_filter_utility +from sensor_msgs.msg import PointCloud2 + +# from mpl_toolkits.mplot3d import Axes3D +# from itertools import combinations +from sensor_msgs.msg import Image as ImageMsg +from cv_bridge import CvBridge + +# from matplotlib.colors import LinearSegmentedColormap + + +class RadarNode: + """See doc/perception/lidar_distance_utility.md on + how to configute this node + """ + + def callback(self, data): + """Callback function, filters a PontCloud2 message + by restrictions defined in the launchfile. + + Publishes a Depth image for the specified camera angle. + Each angle has do be delt with differently since the signs of the + coordinate system change with the view angle. + + :param data: a PointCloud2 + """ + coordinates = ros_numpy.point_cloud2.pointcloud2_to_array(data) + + # Center + reconstruct_bit_mask_center = lidar_filter_utility.bounding_box( + coordinates, + max_x=np.inf, + min_x=0.0, + min_z=-1.6, + ) + reconstruct_coordinates_center = coordinates[reconstruct_bit_mask_center] + reconstruct_coordinates_xyz_center = np.array( + lidar_filter_utility.remove_field_name( + reconstruct_coordinates_center, "intensity" + ).tolist() + ) + dist_array_center = self.reconstruct_img_from_lidar( + reconstruct_coordinates_xyz_center, focus="Center" + ) + dist_array_center_msg = self.bridge.cv2_to_imgmsg( + dist_array_center, encoding="passthrough" + ) + dist_array_center_msg.header = data.header + self.dist_array_center_publisher.publish(dist_array_center_msg) + + def listener(self): + """ + Initializes the node and it's publishers + """ + # run simultaneously. + rospy.init_node("lidar_distance") + self.bridge = CvBridge() + + self.pub_pointcloud = rospy.Publisher( + rospy.get_param( + "~point_cloud_topic", + "/carla/hero/" + rospy.get_namespace() + "_filtered", + ), + PointCloud2, + queue_size=10, + ) + + # publisher for dist_array + self.dist_array_center_publisher = rospy.Publisher( + rospy.get_param("~image_distance_topic", "/paf/hero/Center/dist_array"), + ImageMsg, + queue_size=10, + ) + + # publisher for dist_array + self.dist_array_center_publisher = rospy.Publisher( + rospy.get_param("~image_distance_topic", "/paf/hero/Center/dist_array"), + ImageMsg, + queue_size=10, + ) + + rospy.Subscriber( + rospy.get_param("~source_topic", "/carla/hero/RADAR"), + PointCloud2, + self.callback, + ) + + rospy.spin() + + +if __name__ == "__main__": + lidar_distance = RadarNode() + lidar_distance.listener() \ No newline at end of file From 76193d607ac927e038c74edfb6991f7d679423f8 Mon Sep 17 00:00:00 2001 From: ll7 Date: Wed, 13 Nov 2024 14:42:59 +0100 Subject: [PATCH 41/61] Add sprint summary template and update guidelines for submission Fixes #451 --- doc/dev_talks/paf24/README.md | 1 + .../paf24/sprint_review_meeting_guidelines.md | 2 +- .../paf24/sprint_summary_template.md | 35 +++++++++++++++++++ 3 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 doc/dev_talks/paf24/sprint_summary_template.md diff --git a/doc/dev_talks/paf24/README.md b/doc/dev_talks/paf24/README.md index 4a2ada4b..70503b4d 100644 --- a/doc/dev_talks/paf24/README.md +++ b/doc/dev_talks/paf24/README.md @@ -11,6 +11,7 @@ - [Student Roles](./student_roles.md) - [Joker Rules](./joker_rules_paf24.md) - [Sprint Review Meeting Guidelines](./sprint_review_meeting_guidelines.md) + - [Sprint Summary Template](./sprint_summary_template.md) ## Notes for Sprints diff --git a/doc/dev_talks/paf24/sprint_review_meeting_guidelines.md b/doc/dev_talks/paf24/sprint_review_meeting_guidelines.md index 3dc2228d..0c41eeef 100644 --- a/doc/dev_talks/paf24/sprint_review_meeting_guidelines.md +++ b/doc/dev_talks/paf24/sprint_review_meeting_guidelines.md @@ -17,7 +17,7 @@ ### 1.1. Pre-Meeting Agenda - **Summary Submission**: By **Monday at 11:30 AM** (before the meeting), submit a summary of your work on Digicampus. - - TODO A template will be provided. + - A template can be found here: [Summary of Work Template](./sprint_summary_template.md). - Upload your document to DigiCampus at [this link](https://digicampus.uni-augsburg.de/dispatch.php/course/files?cid=5b0c38206c78cc03880bc2e71997220f). - Inform us of your group composition and presentation order for our note-taking. - **12:00 - 13:30**: Sample Review diff --git a/doc/dev_talks/paf24/sprint_summary_template.md b/doc/dev_talks/paf24/sprint_summary_template.md new file mode 100644 index 00000000..27785587 --- /dev/null +++ b/doc/dev_talks/paf24/sprint_summary_template.md @@ -0,0 +1,35 @@ +# Sprint Summary by *FirstName LastName* + +- Sprint Review Date: YYYY-MM-DD +- My team members: +- Area of contribution: + +## 1. My work + +### 1.1. Issues and PRs I worked on and my contribution + +- Link + - My contribution + +### 1.2. PRs I reviewed + +- Link + +### 1.3. Work I contributed but is not directly linked to a PR or an issue + +- For example draw.io board updates. + +### 1.4. Effort estimate (optional) + +- Estimated hours I worked for the project during the last sprint: + +## 2. Things I would like to mention (optional) + +- Lessons learned +- Issues faced +- Feedback +- Personal reflections + +--- + +Submit your summary to our DigiCampus course page by Monday at 11:30 AM. From d537803e1b86b44418f326c6fac171b20782c1e0 Mon Sep 17 00:00:00 2001 From: Ralf Date: Thu, 14 Nov 2024 12:05:39 +0100 Subject: [PATCH 42/61] update radar node --- code/perception/launch/perception.launch | 4 +- code/perception/src/radar_node.py | 90 ++++++++++++++++-------- 2 files changed, 61 insertions(+), 33 deletions(-) diff --git a/code/perception/launch/perception.launch b/code/perception/launch/perception.launch index 302a97d6..8320e3f5 100644 --- a/code/perception/launch/perception.launch +++ b/code/perception/launch/perception.launch @@ -81,8 +81,8 @@ - - + + diff --git a/code/perception/src/radar_node.py b/code/perception/src/radar_node.py index b35060c1..bd8f351f 100755 --- a/code/perception/src/radar_node.py +++ b/code/perception/src/radar_node.py @@ -10,6 +10,8 @@ from sensor_msgs.msg import Image as ImageMsg from cv_bridge import CvBridge +from std_msgs.msg import Float32 + # from matplotlib.colors import LinearSegmentedColormap @@ -28,29 +30,53 @@ def callback(self, data): :param data: a PointCloud2 """ - coordinates = ros_numpy.point_cloud2.pointcloud2_to_array(data) + # coordinates = ros_numpy.point_cloud2.pointcloud2_to_array(data) # Center - reconstruct_bit_mask_center = lidar_filter_utility.bounding_box( - coordinates, - max_x=np.inf, - min_x=0.0, - min_z=-1.6, - ) - reconstruct_coordinates_center = coordinates[reconstruct_bit_mask_center] - reconstruct_coordinates_xyz_center = np.array( - lidar_filter_utility.remove_field_name( - reconstruct_coordinates_center, "intensity" - ).tolist() - ) - dist_array_center = self.reconstruct_img_from_lidar( - reconstruct_coordinates_xyz_center, focus="Center" - ) - dist_array_center_msg = self.bridge.cv2_to_imgmsg( - dist_array_center, encoding="passthrough" - ) - dist_array_center_msg.header = data.header - self.dist_array_center_publisher.publish(dist_array_center_msg) + + # reconstruct_bit_mask_center = lidar_filter_utility.bounding_box( + # coordinates, + # max_x=np.inf, + # min_x=0.0, + # min_z=-1.6, + # ) + # reconstruct_coordinates_center = coordinates[reconstruct_bit_mask_center] + # reconstruct_coordinates_xyz_center = np.array( + # lidar_filter_utility.remove_field_name( + # reconstruct_coordinates_center, "intensity" + # ).tolist() + # ) + # dist_array_center = self.reconstruct_img_from_lidar( + # reconstruct_coordinates_xyz_center, focus="Center" + # ) + # dist_array_center_msg = self.bridge.cv2_to_imgmsg( + # dist_array_center, encoding="passthrough" + # ) + # dist_array_center_msg.header = data.header + # self.dist_array_center_publisher.publish(dist_array_center_msg) + + coordinates = ros_numpy.point_cloud2.pointcloud2_to_array(data) + + # x_values = coordinates['x'] + # rospy.loginfo("Erste 5 x Werte: {x_values[:5]}") + + # depth_values = coordinates['depth'] + # rospy.loginfo("Erste 5 Depth Werte: {depth_values[:5]}") + + dtype_info = "\n".join([f"Feld '{name}': {coordinates.dtype[name]}" for name in coordinates.dtype.names]) + + # rospy.loginfo("DatentypenNeu: " + dtype_info) # funktioniert + + # rospy.loginfo("DatentypenAlt: " + coordinates.dtype) + + + + msg = np.min[coordinates['Range']] + + dtype_msginfo = ["{type(msg).__name__}"] + rospy.loginfo("DatentypenMsg: " + dtype_msginfo) + + self.dist_array_radar_publisher.publish(msg) def listener(self): """ @@ -70,16 +96,18 @@ def listener(self): ) # publisher for dist_array - self.dist_array_center_publisher = rospy.Publisher( - rospy.get_param("~image_distance_topic", "/paf/hero/Center/dist_array"), - ImageMsg, - queue_size=10, - ) - # publisher for dist_array - self.dist_array_center_publisher = rospy.Publisher( - rospy.get_param("~image_distance_topic", "/paf/hero/Center/dist_array"), - ImageMsg, + # self.dist_array_center_publisher = rospy.Publisher( + # rospy.get_param("~image_distance_topic", "/paf/hero/Center/dist_array"), + # ImageMsg, + # queue_size=10, + # ) + + # publisher for radar dist_array + self.dist_array_radar_publisher = rospy.Publisher( + rospy.get_param("~image_distance_topic", "/paf/hero/Radar/array"), + # PointCloud2, + Float32, queue_size=10, ) @@ -94,4 +122,4 @@ def listener(self): if __name__ == "__main__": lidar_distance = RadarNode() - lidar_distance.listener() \ No newline at end of file + lidar_distance.listener() From ed8b7106ec00a22eecc333c9feecfc2c4aaa5e2d Mon Sep 17 00:00:00 2001 From: vinzenzm Date: Thu, 14 Nov 2024 20:56:31 +0100 Subject: [PATCH 43/61] Split up Acting and Control Moved pure_pursuit, stanley, vehicle and velocity controller to new control pck Changed topic names in the new control package Added a passthrough node in acting, which passes necessary topic to control Adapted acting launch file to accomodate the changes --- code/acting/launch/acting.launch | 38 ++------ code/acting/src/acting/passthrough.py | 87 +++++++++++++++++++ code/control/CMakeLists.txt | 18 ++++ code/control/launch/control.launch | 28 ++++++ code/control/package.xml | 22 +++++ code/control/setup.py | 6 ++ code/control/src/__init__.py | 0 .../src}/pure_pursuit_controller.py | 8 +- .../src}/stanley_controller.py | 8 +- .../src}/vehicle_controller.py | 0 .../src}/velocity_controller.py | 2 +- 11 files changed, 179 insertions(+), 38 deletions(-) create mode 100755 code/acting/src/acting/passthrough.py create mode 100644 code/control/CMakeLists.txt create mode 100644 code/control/launch/control.launch create mode 100644 code/control/package.xml create mode 100644 code/control/setup.py create mode 100644 code/control/src/__init__.py rename code/{acting/src/acting => control/src}/pure_pursuit_controller.py (97%) rename code/{acting/src/acting => control/src}/stanley_controller.py (97%) rename code/{acting/src/acting => control/src}/vehicle_controller.py (100%) rename code/{acting/src/acting => control/src}/velocity_controller.py (98%) diff --git a/code/acting/launch/acting.launch b/code/acting/launch/acting.launch index 5855c9fb..25e6ddce 100644 --- a/code/acting/launch/acting.launch +++ b/code/acting/launch/acting.launch @@ -1,41 +1,21 @@ - + - - - - - - - + + - - - - - - - - - - - - - - - - - - - + + + + \ No newline at end of file diff --git a/code/acting/src/acting/passthrough.py b/code/acting/src/acting/passthrough.py new file mode 100755 index 00000000..253e108c --- /dev/null +++ b/code/acting/src/acting/passthrough.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python + +import ros_compatibility as roscomp +from ros_compatibility.node import CompatibleNode +from rospy import Publisher, Subscriber +from std_msgs.msg import Float32 +from geometry_msgs.msg import PoseStamped +from nav_msgs.msg import Path + + +from dataclasses import dataclass +from typing import Type, Dict + + +@dataclass +class passthrough: + pub_name: str + sub_name: str + topic_type: Type + + +class Passthrough(CompatibleNode): + """This nodes sole purpose is to pass through all messages that control needs. + The purpose of this is that Control-Package should not have any global dependencies, + but is only dependent on the acting package. + """ + + role_name = "hero" # Legacy will change soon + + # Topics for velocity controller. + target_velocity = passthrough( + pub_name="/paf/acting/target_velocity", + sub_name=f"/paf/{role_name}/target_velocity", + topic_type=Float32, + ) + # Topics for steering controllers + trajectory = passthrough( + pub_name="/paf/acting/trajectory", + sub_name=f"/paf/{role_name}/trajectory", + topic_type=Path, + ) + position = passthrough( + pub_name="/paf/acting/current_pos", + sub_name=f"/paf/{role_name}/current_pos", + topic_type=PoseStamped, + ) + heading = passthrough( + pub_name="/paf/acting/current_heading", + sub_name=f"/paf/{role_name}/current_heading", + topic_type=Float32, + ) + + passthrough_topics = [target_velocity, trajectory, position, heading] + + def __init__(self): + self.publishers: Dict[str, Publisher] = {} + self.subscribers: Dict[str, Subscriber] = {} + for topic in self.passthrough_topics: + self.publishers[topic.pub_name] = self.new_publisher( + topic.topic_type, topic.pub_name, qos_profile=1 + ) + + self.subscribers[topic.pub_name] = self.new_subscription( + topic.topic_type, + topic.sub_name, + callback=self.publishers[topic.pub_name].publish, + qos_profile=1, + ) + + +def main(args=None): + """Start the node. + This is the entry point, if called by a launch file. + """ + roscomp.init("passthrough", args=args) + + try: + node = Passthrough() + node.spin() + except KeyboardInterrupt: + pass + finally: + roscomp.shutdown() + + +if __name__ == "__main__": + main() diff --git a/code/control/CMakeLists.txt b/code/control/CMakeLists.txt new file mode 100644 index 00000000..a3c31c0e --- /dev/null +++ b/code/control/CMakeLists.txt @@ -0,0 +1,18 @@ +cmake_minimum_required(VERSION 3.0.2) +project(control) + + +find_package(catkin REQUIRED) + +catkin_python_setup() + +find_package(catkin REQUIRED COMPONENTS + rospy + std_msgs +) +catkin_package() + + +include_directories( +) + diff --git a/code/control/launch/control.launch b/code/control/launch/control.launch new file mode 100644 index 00000000..88a55e26 --- /dev/null +++ b/code/control/launch/control.launch @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/code/control/package.xml b/code/control/package.xml new file mode 100644 index 00000000..9aa803d6 --- /dev/null +++ b/code/control/package.xml @@ -0,0 +1,22 @@ + + + control + 0.0.0 + The control package for PAF Carla + + Vinzenz Malke + + + + + + TODO + + + message_runtime + catkin + + + + + \ No newline at end of file diff --git a/code/control/setup.py b/code/control/setup.py new file mode 100644 index 00000000..a712859a --- /dev/null +++ b/code/control/setup.py @@ -0,0 +1,6 @@ +#!/usr/bin/env python +from distutils.core import setup +from catkin_pkg.python_setup import generate_distutils_setup + +setup_args = generate_distutils_setup(packages=["control"], package_dir={"": "src"}) +setup(**setup_args) diff --git a/code/control/src/__init__.py b/code/control/src/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/code/acting/src/acting/pure_pursuit_controller.py b/code/control/src/pure_pursuit_controller.py similarity index 97% rename from code/acting/src/acting/pure_pursuit_controller.py rename to code/control/src/pure_pursuit_controller.py index 4259fe78..fbf6526b 100755 --- a/code/acting/src/acting/pure_pursuit_controller.py +++ b/code/control/src/pure_pursuit_controller.py @@ -11,7 +11,7 @@ from acting.msg import Debug import numpy as np -from helper_functions import vector_angle, points_to_vector +from acting.helper_functions import vector_angle, points_to_vector # Tuneable Values for PurePursuit-Algorithm K_LAD = 0.85 # optimal in dev-launch @@ -33,12 +33,12 @@ def __init__(self): self.role_name = self.get_param("role_name", "ego_vehicle") self.position_sub: Subscriber = self.new_subscription( - Path, f"/paf/{self.role_name}/trajectory", self.__set_path, qos_profile=1 + Path, "/paf/acting/trajectory", self.__set_path, qos_profile=1 ) self.path_sub: Subscriber = self.new_subscription( PoseStamped, - f"/paf/{self.role_name}/current_pos", + "/paf/acting/current_pos", self.__set_position, qos_profile=1, ) @@ -52,7 +52,7 @@ def __init__(self): self.heading_sub: Subscriber = self.new_subscription( Float32, - f"/paf/{self.role_name}/current_heading", + "/paf/acting/current_heading", self.__set_heading, qos_profile=1, ) diff --git a/code/acting/src/acting/stanley_controller.py b/code/control/src/stanley_controller.py similarity index 97% rename from code/acting/src/acting/stanley_controller.py rename to code/control/src/stanley_controller.py index 3463e90e..86b26221 100755 --- a/code/acting/src/acting/stanley_controller.py +++ b/code/control/src/stanley_controller.py @@ -12,7 +12,7 @@ from std_msgs.msg import Float32 from acting.msg import StanleyDebug -from helper_functions import vector_angle, points_to_vector +from acting.helper_functions import vector_angle, points_to_vector K_CROSSERR = 0.4 # 1.24 was optimal in dev-launch! @@ -28,12 +28,12 @@ def __init__(self): # Subscribers self.position_sub: Subscriber = self.new_subscription( - Path, f"/paf/{self.role_name}/trajectory", self.__set_path, qos_profile=1 + Path, "/paf/acting/trajectory", self.__set_path, qos_profile=1 ) self.path_sub: Subscriber = self.new_subscription( PoseStamped, - f"/paf/{self.role_name}/current_pos", + "/paf/acting/current_pos", self.__set_position, qos_profile=1, ) @@ -47,7 +47,7 @@ def __init__(self): self.heading_sub: Subscriber = self.new_subscription( Float32, - f"/paf/{self.role_name}/current_heading", + "/paf/acting/current_heading", self.__set_heading, qos_profile=1, ) diff --git a/code/acting/src/acting/vehicle_controller.py b/code/control/src/vehicle_controller.py similarity index 100% rename from code/acting/src/acting/vehicle_controller.py rename to code/control/src/vehicle_controller.py diff --git a/code/acting/src/acting/velocity_controller.py b/code/control/src/velocity_controller.py similarity index 98% rename from code/acting/src/acting/velocity_controller.py rename to code/control/src/velocity_controller.py index db1f53aa..a863748c 100755 --- a/code/acting/src/acting/velocity_controller.py +++ b/code/control/src/velocity_controller.py @@ -23,7 +23,7 @@ def __init__(self): self.target_velocity_sub: Subscriber = self.new_subscription( Float32, - f"/paf/{self.role_name}/target_velocity", + "/paf/acting/target_velocity", self.__get_target_velocity, qos_profile=1, ) From ae9f0e707acc8836e90baec7efeabce6ed230b60 Mon Sep 17 00:00:00 2001 From: vinzenzm Date: Sat, 16 Nov 2024 21:36:06 +0100 Subject: [PATCH 44/61] Added control documentation Moved necessary documentation from acting to control. Added documentation for passthrough node. Adjusted linking in Readmes --- doc/acting/README.md | 11 ++++++----- doc/acting/passthrough.md | 17 +++++++++++++++++ doc/control/README.md | 14 ++++++++++++++ doc/control/architecture_documentation.md | 0 .../control_testing.md} | 0 doc/{acting => control}/steering_controllers.md | 0 doc/{acting => control}/vehicle_controller.md | 0 doc/{acting => control}/velocity_controller.md | 0 8 files changed, 37 insertions(+), 5 deletions(-) create mode 100644 doc/acting/passthrough.md create mode 100644 doc/control/README.md create mode 100644 doc/control/architecture_documentation.md rename doc/{acting/acting_testing.md => control/control_testing.md} (100%) rename doc/{acting => control}/steering_controllers.md (100%) rename doc/{acting => control}/vehicle_controller.md (100%) rename doc/{acting => control}/velocity_controller.md (100%) diff --git a/doc/acting/README.md b/doc/acting/README.md index f55e66eb..a8d9acf7 100644 --- a/doc/acting/README.md +++ b/doc/acting/README.md @@ -2,9 +2,10 @@ This folder contains the documentation of the acting component. +The acting component receives information from the [planning component](./../planning/README.md) as well +as the [perception component](./../perception/README.md). It processes this information in order to +navigate on a local basis. + 1. [Architecture](./architecture_documentation.md) -2. [Overview of the Velocity Controller](./velocity_controller.md) -3. [Overview of the Steering Controllers](./steering_controllers.md) -4. [Overview of the Vehicle Controller Component](./vehicle_controller.md) -5. [How to test/tune acting components independedly](./acting_testing.md) -6. [Main frame publisher](./mainframe_publisher.md) +2. [Main frame publisher](./main_frame_publisher.md) +3. [Passthrough](./passthrough.md) \ No newline at end of file diff --git a/doc/acting/passthrough.md b/doc/acting/passthrough.md new file mode 100644 index 00000000..d4e42d4d --- /dev/null +++ b/doc/acting/passthrough.md @@ -0,0 +1,17 @@ +# Passthrough + +>[!NOTE] +>The passthrough component is a temporary solution while beeing in the transitioning phase of +>splitting up the acting component into acting and control. + +**Summary:** This page is ought to provide an overview of the passthrough node and +reason why it exists + +## Overview: +The passthrough node subscribes to topics on a global scale and republishes them into the "paf/acting" namespace. The control package subscribes to these re-emitted topics. + +## Reasoning: +Before the control package was outsourced and became its own package it resided within the acting package. +Therefor many global dependencies existed in the control package. As the goal of the outsourcing was +to eliminate global dependencies in control theory the passthrough node was created as a first stepping +stone towards independence. \ No newline at end of file diff --git a/doc/control/README.md b/doc/control/README.md new file mode 100644 index 00000000..f3f069b6 --- /dev/null +++ b/doc/control/README.md @@ -0,0 +1,14 @@ +# Documentation of control component + +This folder contains the documentation of the control component. + +The control component applies control theory based on a local trajectory provided +by the [acting component](./../acting/README.md). It uses knowledge of the current state +of the vehicle in order to send [CarlaEgoVehicleControl](https://carla.readthedocs.io/en/0.9.8/ros_msgs/#CarlaEgoVehicleControlmsg) commands to the Simulator. + + +1. [Architecture](./architecture_documentation.md) +2. [Overview of the Velocity Controller](./velocity_controller.md) +3. [Overview of the Steering Controllers](./steering_controllers.md) +4. [Overview of the Vehicle Controller Component](./vehicle_controller.md) +5. [How to test/tune control components independently](./control_testing.md) \ No newline at end of file diff --git a/doc/control/architecture_documentation.md b/doc/control/architecture_documentation.md new file mode 100644 index 00000000..e69de29b diff --git a/doc/acting/acting_testing.md b/doc/control/control_testing.md similarity index 100% rename from doc/acting/acting_testing.md rename to doc/control/control_testing.md diff --git a/doc/acting/steering_controllers.md b/doc/control/steering_controllers.md similarity index 100% rename from doc/acting/steering_controllers.md rename to doc/control/steering_controllers.md diff --git a/doc/acting/vehicle_controller.md b/doc/control/vehicle_controller.md similarity index 100% rename from doc/acting/vehicle_controller.md rename to doc/control/vehicle_controller.md diff --git a/doc/acting/velocity_controller.md b/doc/control/velocity_controller.md similarity index 100% rename from doc/acting/velocity_controller.md rename to doc/control/velocity_controller.md From 4b90716f5cc1ca936e008088462d2787c22565e0 Mon Sep 17 00:00:00 2001 From: vinzenzm Date: Sat, 16 Nov 2024 23:40:49 +0100 Subject: [PATCH 45/61] Updated acting and control documentation. No Code changes. Added new architecuraly diagrams. Added and updated linking through markdown documentation. Moved assets into correct folder and updated docs accordingly. --- doc/acting/README.md | 7 +- .../acting_testing.md} | 6 +- doc/acting/architecture_documentation.md | 97 ++++++------------ doc/assets/acting/acting_architecture.png | Bin 0 -> 112754 bytes ...ing.png => architecture_acting_legacy.png} | Bin .../Steering_PurePursuit.png | Bin .../Steering_PurePursuit_Tuning.png | Bin .../{acting => control}/Steering_Stanley.png | Bin .../Steering_Stanley_ComparedToPurePur.png | Bin .../VelContr_PID_BrakingWithThrottlePID.png | Bin .../VelContr_PID_StepResponse.png | Bin .../VelContr_PID_differentVelocities.png | Bin doc/assets/control/control_architecture.png | Bin 0 -> 129940 bytes .../emergency_brake_stats_graph.png | Bin doc/control/README.md | 10 +- doc/control/architecture_documentation.md | 81 +++++++++++++++ doc/control/steering_controllers.md | 19 ++-- doc/control/vehicle_controller.md | 15 ++- doc/control/velocity_controller.md | 13 ++- 19 files changed, 140 insertions(+), 108 deletions(-) rename doc/{control/control_testing.md => acting/acting_testing.md} (92%) create mode 100644 doc/assets/acting/acting_architecture.png rename doc/assets/acting/{Architecture_Acting.png => architecture_acting_legacy.png} (100%) rename doc/assets/{acting => control}/Steering_PurePursuit.png (100%) rename doc/assets/{acting => control}/Steering_PurePursuit_Tuning.png (100%) rename doc/assets/{acting => control}/Steering_Stanley.png (100%) rename doc/assets/{acting => control}/Steering_Stanley_ComparedToPurePur.png (100%) rename doc/assets/{acting => control}/VelContr_PID_BrakingWithThrottlePID.png (100%) rename doc/assets/{acting => control}/VelContr_PID_StepResponse.png (100%) rename doc/assets/{acting => control}/VelContr_PID_differentVelocities.png (100%) create mode 100644 doc/assets/control/control_architecture.png rename doc/assets/{acting => control}/emergency_brake_stats_graph.png (100%) diff --git a/doc/acting/README.md b/doc/acting/README.md index a8d9acf7..f2046e78 100644 --- a/doc/acting/README.md +++ b/doc/acting/README.md @@ -2,10 +2,7 @@ This folder contains the documentation of the acting component. -The acting component receives information from the [planning component](./../planning/README.md) as well -as the [perception component](./../perception/README.md). It processes this information in order to -navigate on a local basis. - 1. [Architecture](./architecture_documentation.md) 2. [Main frame publisher](./main_frame_publisher.md) -3. [Passthrough](./passthrough.md) \ No newline at end of file +3. [Passthrough](./passthrough.md) +4. [How to test/tune the acting component](./acting_testing.md) \ No newline at end of file diff --git a/doc/control/control_testing.md b/doc/acting/acting_testing.md similarity index 92% rename from doc/control/control_testing.md rename to doc/acting/acting_testing.md index 49bd88e7..108e3c3a 100644 --- a/doc/control/control_testing.md +++ b/doc/acting/acting_testing.md @@ -8,15 +8,15 @@ ## Acting_Debug_Node -The [Acting_Debug_Node](../../code/acting/src/acting/Acting_Debug_Node.py) allows you to tune/test/verify all acting components independently of Planning-Inputs and also lets you easily output the data needed to plot/verify the tuning/testing you have done. +The [Acting_Debug_Node](../../code/acting/src/acting/Acting_Debug_Node.py) allows you to tune/test/verify all acting and control components independently of Planning-Inputs and also lets you easily output the data needed to plot/verify the tuning/testing you have done. There is a dedicated [acting_debug.launch](../../code/acting/launch/acting_debug.launch) file which starts the acting component **as well as the necesarry perception components** automatically. It is recommended to first test the [Acting_Debug_Node](../../code/acting/src/acting/Acting_Debug_Node.py) with an empty road scenario. The following guide provides instructions on how to launch this setup. ### Setup for Testing with the Debug-Node -To use the [Acting_Debug_Node](../../code/acting/src/acting/Acting_Debug_Node.py) you first have to edit a few files in your current branch: \\ -**! Make sure to revert these changes when pushing your branch!** +To use the [Acting_Debug_Node](../../code/acting/src/acting/Acting_Debug_Node.py) you first have to edit a few files in your current branch: +>[!WARNING]! Make sure to revert these changes when pushing your branch! - In [dev.launch](../../code/agent/launch/dev.launch) the [agent.launch](../../code/agent/launch/agent.launch) file is included. Change this to include [acting_debug.launch](../../code/acting/launch/acting_debug.launch) from the **acting** package. As mentioned above this includes everything we need. diff --git a/doc/acting/architecture_documentation.md b/doc/acting/architecture_documentation.md index 5c1aeb9d..f4699186 100644 --- a/doc/acting/architecture_documentation.md +++ b/doc/acting/architecture_documentation.md @@ -1,68 +1,46 @@ -# Architecture +# Acting: Overview and Architecture -**Summary**: This documentation shows the current Acting Architecture. +**Summary**: The acting component receives information from the [planning component](./../planning/README.md) as well +as the [perception component](./../perception/README.md). It processes this information in order to +navigate on a local basis. This information is then processed in the [control_component](./../control/README.md). -- [Architecture](#architecture) - - [Acting Architecture](#acting-architecture) - - [Summary of Acting Components](#summary-of-acting-components) - - [pure\_pursuit\_controller.py](#pure_pursuit_controllerpy) - - [stanley\_controller.py](#stanley_controllerpy) - - [velocity\_controller.py](#velocity_controllerpy) - - [vehicle\_controller.py](#vehicle_controllerpy) - - [helper\_functions.py](#helper_functionspy) - - [MainFramePublisher.py](#mainframepublisherpy) +- [Acting Architecture](#acting-architecture) +- [Components of acting](#components-of-acting) + - [passthrough.py](#passthroughpy) + - [main\_frame\_publisher.py](#main_frame_publisherpy) + - [helper\_functions.py](#helper_functionspy) ## Acting Architecture -![MISSING: Acting-ARCHITECTURE](../assets/acting/Architecture_Acting.png) +![MISSING: Acting-ARCHITECTURE](./../assets/acting/acting_architecture.png) -## Summary of Acting Components +> [!NOTE] +> [Click here to go to control architecture](./../control/architecture_documentation.md) -### pure_pursuit_controller.py +## Components of acting -- Inputs: - - **trajectory**: Path - - **current_pos**: PoseStamped - - **Speed**: CarlaSpeedometer - - **current_heading**: Float32 -- Outputs: - - **pure_pursuit_steer**: Float32 - - **pure_p_debug**: Debug +### passthrough.py -### stanley_controller.py +> [!TIP] +> For documentation on passthrough component see: [passthrough](./passthrough.md) -- Inputs: - - **trajectory**: Path - - **current_pos**: PoseStamped - - **Speed**: CarlaSpeedometer - - **current_heading**: Float32 -- Outputs: - - **stanley_steer**: Float32 - - **stanley_debug**: StanleyDebug - -### velocity_controller.py +### main_frame_publisher.py +> [!TIP] +> Follow this link for [Documentation](./main_frame_publisher.md) on this Node. - Inputs: - - **target_velocity**: Float32 - - **Speed**: CarlaSpeedometer + - **current_pos**: PoseStampled + - **current_heading**: Float32 - Outputs: - - **throttle**: Float32 - - **brake**: Float32 - -### vehicle_controller.py + - **transform**: broadcasts heroframe-transform via TransformBroadcaster +- This node handles the translation from the static main frame to the moving hero frame. The hero frame always moves and rotates as the ego vehicle does. The hero frame is used by sensors like the lidar. Rviz also uses the hero frame. The main frame is used for planning +- rotation = - **current_heading** +- position x = cos(rotation) \* **current_pos**.x + sin(rotation) \* **current_pos**.y +- position y = sin(rotation) \* **current_pos**.x + cos(rotation) \* **current_pos**.y +- position z = - **current_pos**.z +- rot_quat = rot as quaternion +- **transform** = position x/y/z, rot_quat, Timestamp(now), “global”, “hero” -- Inputs: - - **emergency**: Bool - - **curr_behavior**: String - - **Speed**: CarlaSpeedometer - - **throttle**: Float32 - - **brake**: Float32 - - **pure_pursuit_steer**: Float32 - - **stanley_steer**: Float32 -- Outputs: - - **vehicle_control_cmd**: [CarlaEgoVehicleControl](https://carla.readthedocs.io/en/0.9.8/ros_msgs/#CarlaEgoVehicleControlmsg) - - **status**: Bool - - **emergency**: Bool ### helper_functions.py @@ -95,19 +73,4 @@ Interpolate linearly between start and end, with a minimal distance of interval_ - **_clean_route_duplicates(route: List[Tuple[float, float]], min_dist: float) -> List[Tuple[float, float]]**:\ Remove duplicates in the given List of tuples, if the distance between them is less than min_dist. - **interpolate_route(orig_route: List[Tuple[float, float]], interval_m=0.5)**:\ -Interpolate the given route with points inbetween,holding the specified distance interval threshold. - -### MainFramePublisher.py - -- Inputs: - - **current_pos**: PoseStampled - - **current_heading**: Float32 -- Outputs: - - **transform**: broadcasts heroframe-transform via TransformBroadcaster -- This node handles the translation from the static main frame to the moving hero frame. The hero frame always moves and rotates as the ego vehicle does. The hero frame is used by sensors like the lidar. Rviz also uses the hero frame. The main frame is used for planning -- rotation = - **current_heading** -- position x = cos(rotation) \* **current_pos**.x + sin(rotation) \* **current_pos**.y -- position y = sin(rotation) \* **current_pos**.x + cos(rotation) \* **current_pos**.y -- position z = - **current_pos**.z -- rot_quat = rot as quaternion -- **transform** = position x/y/z, rot_quat, Timestamp(now), “global”, “hero” +Interpolate the given route with points inbetween,holding the specified distance interval threshold. \ No newline at end of file diff --git a/doc/assets/acting/acting_architecture.png b/doc/assets/acting/acting_architecture.png new file mode 100644 index 0000000000000000000000000000000000000000..fd2a780dae5fd20c4e54cf8ca8c91929740d7fce GIT binary patch literal 112754 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�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 f~=O_=!BJB+$X<#;$5Z%v`J zqtFW7^LJn~QfFyGFCVbZBuFp!o}|0xZ{lEe!>A!i8}%$9?*L#Va?7gg=fgqjN3j_A zP1F|@D;9cuH+OVxmBh>*gu;Egn(_`ofAAZhL)sB17ZS9<~F$4ooF zW}GhLQA`IV%ICHRQBI!cuXev3(Y8GcN6X*0)TrVjk{Vpra!x7t(Hmr8r1#xd!x zXy^Q{x5GWd5dGM555FVO4%!t5FArgSoFV9na2kitgd-(Y!NnJQ4k$I-LxU=*WW6m?D3uMRO zewH6zc_?&y@sFiBA)$2J1?msxI#o~jm`;4OR>+dv8B$+nzA|F|yN3v@JsmRIA7T3p zbg=vN%BE+uXp4BBb6j%5ektA%_sH}470Im5=l=~k`u57#(WeL4*`T7%oG_+&Z(1w* zLgA4@-gRnow^_E&cQ>?%@ZQCnH`bY25S>+Ot@z@#LP3CAa?|bDAez@-HVSDRezbLJ zx}Yk&0E&_ODRi+>=Q%}d<5aD>GE1NBq;G1_od2F|VKuY&z_-GvoDt*VrYcUJLwi@w zP(K`Y#c^EvDqhgS(w5z2L{Yh5(T6f(Hg8E#>hj`*S=GqB*Q!THDvW>pytZ$x)_;0H z_thQ{OivRK)=<1pKm>%;I;p*n=U}AL4M}PG${q;(%iDo?fKtcG$+-!jJ{WWajimq? znz$K2ZvyTNNTol1jPN?u0-Z&WtLMh8G8p@-a1A|Lj8%&0(OsD*68a@q`w!p_5Irph z!Ngd>J-Y-hFHl(BcWxw4hQ5xXc)yFVHVQ#aYQe)I)Vj&T3ney#pRP~ycUIXR=;iY` z&Z-@_;qD#f%NM>p+m#_;-l4rXUX*h!F2S&;?zz)MZ{ZZNY&UAP?3hCJsa?p%5%^cia9` zlLK9OKlg}(9tAq{#{2Uj234~lpC zCDa&+mf+ExIdi73VJ<8oiN9rt#FEI>E{U~_>Z z&a>*k>k>FVsB5-|v9R+x|0^cpqG_KlHJg$YixU99f2HmiA$xmJL~>-xOAieB)Mq}I zh>sP9si;2d7#i@Ek9nOQ6Kvrho9a-^NNq3}lb82MZDszn&iup(#dH1}%x=!(tdE&0 zii}b(*v$XC;;^#yi%-OOyL_vi(s*6HYS%z)N%e)|`(3BWFm!0hG{|MkigS0BP%z^` z?!#B-nv?k*nhxLD9R(Se!RPT~*pqKIr#(Jt#Q|jOOfY{)gU;+aY)f2aXU{BIUds60 zjmvlTcet%ta#GO2V6RDx)=$#Ko3BE)WKsXKb!#^iSI6PC1Ti@3$yT=S{O94gNffHU zKLHuRr+{|XE-GnE;Xua=kUxp(8+gC{0&Y(c*8&@`>1kUOl_#B?!~jH*fepxg@O=a* zM{=z|QmZ!^vYTK5zZ6f*1hzVlb&`AWp}XD{F%fqdP`%Nzre$PYgzFGal~0fW>^qTx zgxWrMI?fz;M-n)$ve+C6_~ZB$S3wpxw(|BI9)yHw!B1l=j4{o zsTs*)+&^FXrO?Sdv0zancvsOKJXT@UGq@qH&Ln)US#xo|BS%F0a^gk;>_k0*i zYrNblq;S&G#a8CN)n{-iRyR7wD0kM1PD*Feie0H-0|bHzBhKGOm^I6ES0)cEukpy8 zuH+ET>6>j_^1Y~|@$J<>)Y$Y`cajr}(aNxSk}%DLqRM-zgy-KWjxjHlp2^ixu{=pw zO?glLv*Sz2T3QNV(t7g*FIehKrvdk;E0BE^9>8}SK4fus)+;ai=&7kD>_;tX+uXxR3M*=|9%g+RO-!-!PlDt31E z*Gj#b;CbMQf^BStfU_}33ZqmLoLsUa9D0IpWETh)&xb+xgxC0r5F_far@Ta&;Bp&h zadg+h@^h=Gd&#!+SBLuaRGc|qt_k(-vKx&Nmt-mVB>81ePn=--`6!5{+c=nAl- zsXCXohH}`9Pp!kbYQq5o?`F8B&U1YO>p3#05NBvwm}BHKgAb4-_1#CAz@qH zjh%CUM=c#8&wPj1d&zGSd`ti5o}0%wE9uzCf?3{xj)0S zi(XIC4OVbn{km6zf1_Jz2lErVD8J&8vg_sYZaT3U1jCSc(Z)` zYqkd+(x8M8jKJg(`GTVyjyceE9@=%pohTk)$poApocF)vZ2>(;d+nsZf@OsMZIF&v zAy#yl$KOG=;ITLo0PRx5HdT=)sZ%vI=9n+x_`;kz@cprz=Y4#-K3DSXb7;Oj=<;`S z-p10N&`x_%yIsNc!VU)xt})wMK3CaIRMnE#>S{(Y*p!(xT^CBys;s*}e`gw$FOtB^B5z@p{uU{m_$7-cz-I3a4A zE__VR2zqT*szBQAvogX`3tvoVu4P@Xd`9NXehL551GTPhvPSpsM5R4ju+p|N6zKgXQkB*F z%^_T5#vxok#d6W$aLGSP)!z-+ctoG%u+JFlJ)^oFOYUsz!?fgAE^K#bgXH5?wu5)? z>@2Pr>yP*2Da`y~BYWM{)Q00Wy3?_#fS1Q}qW;5fTP254pqy}=89s*>o{--T*to8T z7L4GP5C9(_B5!L4sd)B>)Kl!Dbs=IL(`Ehm=OC%$L)!I>-SX8T5Uc*Wv-!gA41@!0 zbv=GpM?vzpL{YF3Hv@;uREUlN0F3%)AVmK)|6za`z}jszKZIcP(8kNca85= z({#F>zfagdq3Q6DoDDJ9@=Nei!x4*d6$uV*Mq!6H%u0`5{M5-;DB!twhe1mG_rC3T z&`~9R(*bG8vJD@MDi|qA?69mH>~ayzlQ zFne|zw}f1{%CVx~S|^3sh}vr%bQxk1v{9#X-bz`~U0pomeLd&FtM_eX)ls6BXa9T^ zcibLQaX&)Nx1jVPg?~7OzXt`2#6N~J`HnT+))y|BzkE}va4GEWpKSIw1Bb5F$w$e! zoaq}Xd25kJHC6l4kGUR|$DJqSW_{Y>e^I@-^bdQd{vy>_jwMwMTmuR33`SL?McKk4 z8HyefTQP|gog42)?8|0|9tczbxC=5ZFwl^RL{kX&hi_m=D#3;Z-3;PZ`4Qr0JMg}F zh@>b0Wk3PW0M!Zl7~<#xCOnB$!0f!~POF(QhPqN&Z!v3RO4>~7Kv3C;PXpwVg2t7y zv9)7psSxfB?M9)2K*zwq!^WFNFpVJW5x8MOxAd-gXbS_MJ1i%l#)hcJa^@&`VK7SR zg#qZ3uvq~_pnh&>AX!c8OgYY!mzV!X2!cz4y9rbcpjIQMqJ22I)WC1=@_Ia4kf$!d zO=38?!e~Dyr#G${WJw0_>rl5^*3AF&rtDjxmWo2*yDJR)9JN1m&(F@%!oL*=7IL{6 zC@{5#EDf-5r9}f$_fVJJ_c(ET3T8Pl8bq)&3-@J8;93dLHvsBc?!6>kY9(Yv(jO3d2yo3B1GZ}ww!a#AuU~OYSPZvSJmW2p z78YY(2Se4g09Mf#pe*6$p2i^tw4wwk6mkpU*kBLNHPrtf^{(yqOUcZ9j%wBq+ukU8 zbAIR9QQLtgsNDc!ijRGwgLY*U&~7Kpiwj(rex@4xiWOObSc@T{gPdV&+VzWG1LHF@ z#u(p_zJ2mf{X@9U5jT812+BfO!;)-ZqNS6N$ZMU4tufT4k~nBG+8l`&C5gX_TI?A+YtVZX33V*z*MmfT2GJ&VVWWk>D|x{G%hIj8zH!5ifZZXyzHp|m5$Ot8SW zRx&p;lN?EzO+z#7b1GUa%Sr>o%~pw{_^QMmXQHRw|A9oE53?zAqirQ8|6Ahvd z@6f#$<)x(^2-`l9s5*hWEC7@cld~^)8RxKM9bkG^wW}Pbihy1r1+jd9|4=dF(u*MO zTPuy`2hY0;i9>!&8k?%Sw9`Gf7IP)WCZ-Lp4Z3mB#@3#+Fr@n&@F-NgURKp?*N%Fl z7n(y1*39<(LiYXX4AvTxqFZ%DX|{+S-k3*;{}2~ai=9n8Dt4|S@%iDz=OLQcOw2yl z+`QprcKv01Bw%}{oUlZf+xx#)+FtPH}7BHe;ugm zBWg-H#C>>Um=}&6-(USNqm<%~8P@OoR*|^pV6MRZ@DQ_XGL47YpKx4&go6_i2*@Gy z$OwE_zh4u={xE1O28W-7`ag=Jpwqon;ky6eflQ(*V3nrfCDOSC3sS=N0G>pM^6rIJ zk@#J}z3XafBLEG&(x_Z`7CF_sRqk&b9=QjogYCSxe|%UZPBBzHGe?WRdge*6Y2t7hK~N{<)=H15jBOGm3lDRWiF1;Dwa&VsGcyhrUTzKcellOiMP2aj|)H zL@50|ch2JbLkTBqf8-2U9v;z1Q6K7)sQ(>U7iO2=6Zk=g=@R|(WTp-38qL$kLt5`| z7Pid2xBu=Dyc-Nt%t3~`(W-)5_o?3+4`drqW-pnSw`fYNG%!9UTgBBBTF_KFDaD*I z7j}ElRun`CMOdOALSWJ71&$Gx1KL#>4OzAAR@J?Exhg#gGc!m->>-?POv6WnY!zut|Q-_C@NEOj!5%AQZ4+Op*UAKz$8NmSrY5Lhs_MwgXw)*GtbumGWy z#+&U8{3b}ZUl{2x30{d9nCsU$LG4w%grb1n*|lfIHis#;7Tk+|zFplAn}YMPCHr5AIevdyQbi+-f${2+|gpwkN z(#6aJ57cfX(~9YY5=*Zl#}!d|+oMO0WYNXOLIWG;;?yZ#(kVzM4u2SUhK8q8hg6(G z^AE!wWPD@{X!pQwrtv0r)13XWzU@Y-jS~O%U5D)`@mX11taK!fIXpoRNz2ii(rYa< zVBIMPzq%ueqoFxPaeKcu`0v$KD(nrNIC8WZ4^!QgdJi>yqAlgokcT^S)`jE^r3b1~ z9*y0c)9TS$t-3All1ZJ(4wIO*G>`syq~UQYQ6^eBs+x1GF7AAMlTNKe9N!@ zR!1L{?_+QaBo-L(raBGkFP@#HWd|cSgk0F~3E2qmBTmIq*a@|$*-){*a;e`j=inqy zD;hbY(iNZeUd%fv_62)F7?zfSuksqjpaH)iLLY?JcLnB87r2_YM-ytgiVE1p_Nq0% zL3uZ6(C=YcnJw|vh&UD9f&4g|h`~3Bi8c{^!|er9;4p!bknN?N^Xz^24Q)u7qjAuY z(nh*Dpa-n`+&H>hOl*m$F`+)4t+I&sq$9aB;ww-TK-G#Fjdh%w`JproUZwP!|()-r$u_w z$qgC1hw+8>U|xzwj>mBcJJEjE0lV&xyKPK-MEiRV-N_Wk-w@Zs8$aH5*cB`=kvuvs zF8Q^!R8ab)z`%|81`y{GROc-n0lG4quIt*^rfdtEX@dp62!+ochKBu}YMO4_DcV`K zm4tp|yzMfjQuiV3+ePjj>*wJg(^1~0eK$yp9Xw3T940#5>EGyP^8@CXXH&SNe9UvBId?+Z8@7>>!%mT{Ly1rZ9X)KyQ ztP;85Lx$qxJcuRNu5p6i7=v034!k2ApKrn7_mEERa~QTjI^CFKm)vqIpAxPtgSMps zl`<^<`j|WCuJ7D(DR>vd$6~&SLjYG)qiHsOmXh?KTM*>A-UuctDP>U&+RhY+H1OAz zmk-=7SBX~vEh`0DZbC)J%nW8VcJ0PnGyC*Ybdrr>nMPWRzkM3%d@yJm?%ujb_{rp? zHRkviIR6D5Jx^Pp-+2#p$>owkv<6x{^eD_p>^&^K-l}rrxr1!>=dB_73i#>Z+IeyG za`5u{lAr|?T*|gOtaoPD%uOL&st_J#nLuKRY6CWXVUEu?tU)$Cu@xhQycBFh32f+w zV-Q7x+$|K!q5kRh$6YV4W3*}h?slAA!gGE$I`3QFUE)`bJ-P&DHY52FmFPz9uPm>> zfp_5HwO_9Xy_lpQK#33EA0GSMVa}rJr=Z~7h0)w7 ze0}i5K`B+t(a(Vj`y|Ul^URKo;^N}!_!>s3yYh6ZfVz^Fk^(dgc;9@HXlcfmX_=`K ziNI)MdCb?1xJ;)xX~(Nr_J-Mw!@L3Y#YO<)V5c@X_|M>GbQ8}EQ1XD(^;Cv6o5hKs z2{HYbr@@fHOWHd^uR7`^MegXw%@S9g5~edu%?sZpAmX`0=zY1}ya?)60%?>B1`-?;| zI0Q$Qv?RQp9=+oJFke6-_T4@IOGeIH!kO4@v-KCrs1MUct2U=m>!Z+#!iLHnn$ZvG z#tliI%gY}ET_~G5;mz$FI=HQ%LQs&8erMFw%m`n~{*nj7L$S{JVJ;C*TvWZoU2^@H z#nHkgLP-{}ve@g_(%-4*W{Ut*8o)eHI+_TQ#mUp;o7oqB;k0m=B3fct%te{E=WD+i z1Q!G69r08MRpbDIG@MX&m$p-R!vSixy%urn$s8kNFBLPZtnUY?Gr-qoD-ARIMPD$x z0ZjZuTA5F1Bxj}9?gK<~8lT3Hpqh9U+~(okmUcT}vRdlTAqaZR++HB9z$JufnFFB886-cLm!0pa@U}mzuJLu^fV(uBz$#^HQ!4VFcKt7NX z2oGy7ep9wk%pK`X)fe;74KEJc6`X)KBwscagi9l?Gh#Cp(tkgXwo?H>2VhVFQ@uyZ z7ub3SILW_1^!Gv_I(h2nx6h-`2&OXX=_Uc>3*&xms(y*=i)%vLqx0&xfA#mvh)@`qmBRE?aZyJavt*f_n*&~ zC&EPBaO7flEbg}KxFt-;LNKmpgW(*i5A2=Y#pH9@&fG@m*ZzROKvZV?J^Ee)+dp{t zZ~&yJtJihc8Hv!C^k=WwWoZp9FOSXzYw@UgO+?&~3@X1{Y7mv3&6wJ_C5`PlG&e}C zcuE7KBiW$8j}Qm#k6|y*J{>?*Z2$4Qk)^jrE3G?b1JlNL2%g4U*pdwMd3=2LI&wuZ zf3GOG!l>W2{gH!{6CAh?KzhA;L7~L69u@UP)ZfbS24A1B5>v=@jdL0rFV;goEgQs& z#j|=(Rxf`)J_SQBFOX%SQ5ycV3O?_U+sgibeuUNWj<@$FG~TDtI{ycTRrV)n@83`K zX5Nou@HPPPD9!Won*ah|=uV3Lx^T$nOP8)Zu^ZpCM*5P`#=G2VdORYmMP$0n1uhr? zObm>T&yt_8cJPBwll56ws)8?O2cySxbT6iLipourueA1Jf$(5Og^J-|tU>KY@@KL% zLXg;jYkwJj@Nha0KY$od8SCqRe}_r(t;LN?jP5_?qg94AIPa5h8x@;DV=by+vDDl| zxpk|GG4m6$ekS?QjRO~2cmCqVVpL#k)i6G^szIo1+U#OdZf0i1n>XJ&Q*;h~h;M~F#B>H_H+B>OgTU#nl~F z6an(YXeCD3W>yQl2Gs<(L*1M?pTKtHJJZ)#&QF&*cRe|9JoA)z?m|t|lU~JX&S#8T z)9h3}WNFpAZP9#@qUov;mc-BSF1X@n$RX3AbpdOGlwFyrSY_30;TlHN&+w@|Sz*4K zV=-*tEAuikJ^j+!gFHF4a{J^)C!ZXB)2axIV)%r?Q~(a4s1qYoQno$(+^N_}JaJMR z(Rjkn3ria={wN#kOwz^Vtc+@UzWoM&Wo@BRYFNOmh~Tc@w}kNpfzZH!PvOQ5ZZsE# zd2O|FEO|P<$a;VeOmy|n;j9C9L^V#y+h>+N9jk!Q&eo_$qEr$jI4I**v;ZrJ)vf3q_>Ht z*!g{0qD$oeQ{fzl#4Y;#`O_yp*Tvb1O5$n<(DdX<)BW1mvI$}a2p>JmyY(p{g24*( zEvH4tFSdbx3ECryN0e7VSjniHNfFQr*_%Ac>marbVbih!*T zv_!xxpdy2&o$4`d6s&sX9UMe(5Dp)x?3bV9kOs|)10U9sXP z2s~8;%n9%smtz8*5p+-D~?3VU@MGV-m3LtwsLWi}l#3l29GP;)pmfApEP}8g@$xXlY5kjVvI- zVvgkTL*&EWy^+N)n=ln^DNPMSX8DB+9+(ZmP7|;$FeAWBfVpMK2KD#Yz~^8s9TwR` zZ6^>58zoRSQS#%*_F)hOBnu$q0gr4MMGjXuNdI-FdT}>&VGRvWA~ne ziwn|awxXO(|NVR&g1 z4LyqWHF#a&{zjtK;FJfV#&ACl{Fwo z@mL=f0;^EiZ-$`hg_I5cxg5A0j5loTc^Rs0uwjt#AT+DNqBdOMRS<_L`0on13mgW;nS%A7;D3Z4FJ&i z?ML;@3YKhl*(UB5b76_V=T_I$bPmU-BSDLNFpNUcNlOSE{l9m+@R|^8HaJifV5k25 z#+3C=-3Ic@zn_FtoF&45V37+KFOnM3;<_*-FsVWFs@?=b7);vN^~1%hUDKl2V1}lMY(YW6+m4>gFg(}aKfP|A{Kg>H0@DRsv2fm*SPgRpA>Ztfflex zBaV8vs~`RT{X5gV30@MbA0e87w+Y($VqnN55sO&&?%OA`c7J6#1_Q)!2N*L-xu4id zh^06|zhMLiUc6aWtNdKwe~P~-GTLo-T{ukbb>epQIpICj`AgH97|O9R$ZU$={EFv^ zp7m8Cp&I*4?+ln4W?IZHlh8mYAIRG8nuc|W|FnnV4ZbJj@5#?$4cO+G2CT<%9@>Ew z4JsNO7TtcNp*3Q_o_66vwL=iU%e*y6J}yNz8#Zplk%$4*@M&r3!b|NvEP?yc76JU3 zxjo|4_tFc(dK%GCSYKq2mL3Ejo1%@AP=FOh`$}?QPAKE8IHAvnWeM^K)v03$j5&o9 zIdsqVziYT|Ls%X9XJSCp2y!9Tr1;WgEl_081NIhe3qm(f%!$IG492j0-6lTb%0=95cCNupUi#mr>|U`n}9*{zo0Ys;D@q) zoovzeH~=r|)|&UGbBoKZ)&iDFOMNpY=^Ch38?$W^7Sge!1M0;dJPcpbp(AkMfP-64 z_CS)A@k#`U(744L(xx6Gs79@?K7rn4VLC6)padvYnYr77Cc(ZCo_e?5q#H73HjGkW zm1cw(dJKgrta`p(!Ph1BF_;9Be*(k{Tbu!m9MNM?m>y%-0`U#N4?zk@Ki}IjO@w~f z46%|Mk-~uFJWr>2SU5B-xnTfBbb2`D(5uEkxYIfguW*Oi4zD#hg7jB?^Jhtn8vyU2 z@Z|jb@Mg1|M__%Cpok0ZH*i-y3y_+UE+dHz;RqTwwvt?7MI{*NFo8r9|Aleh7#D+ zwQZdapkwF@WZ&{IGATYFxpsVZp?AT}I?5QjZ=ymRUMZOW!;PCYv|NBA#yH&J9{i^7 zU5r)ahj}-M=mFG00kBwyi2(6*ae(TA=S@i|oF>X~ALkHJi}~AGOy_8z`X*Q;@jJ&$ zF_Viuij1rA2Gvnt zGZ5ql5la4%|GDwEYviDedk^(4dN6Vi5C`TL>3su+t5BiX--i3*PF@`aR5n2^)TBwx zX7fK@{_4s$PWK0*o69r0SK?%q0MWENPi)1M#vORd6F$haGGwZz!CB8$$GC%QMwiXx5o3BuaB}+6)M(wWj)NRDC+U-A&;I$9^D!a2 zGTZON%WOsM?x_#a?iyB_=D|h@OtIyk-=~QOnwQ5$W#2#VmTZ+@51s=2!^lYlMBCfP z=Kv??R|&va<27e_$41;%LV&t$*|-iqT1-4QVDUKI%N6jZH4PgTJXe1Xr$YpuuDvb| zlR2_S6D2<8)8SM49~&AP@@@vm*AKg0%W?Y-}+Qm&Vx{lA_%6&7m!tp z^WLt_A+|+Ua}%qL2dP`Ew^Mt0g4{=}*OHpf)FELzZ*WuS zw29_APukD*jgJ3#IkQ})>nZ0OltCRMFDiS#l0)F<&n|shy_yS`8Wc?RH~#~+-**!` zol%$nkE{29=X!7d$B9xBN@ZlErAbEih>&EZGP6UnvNuVgkc5y`BqXWq%*=|66xlmu zWbg5RzB}hW-{0eZ9(VWY-1i}$_jp~`^}L<~PcxyU#HP}*Jd^aK&WA97-q4T|r~Afo zO9?bLihebKmL)#anjYaK6gg04KoSe!Y8n)f)fD4nyD2x3k+r@x@F~!C#ra0mVJ8L0 zbq+PON#iephZV%r@7WW(@FfMK38Cxh@?5b5P4Np@@4uCr?ZZ-p^zspAT_4@C^U;$h zTLAgksIC02%?ZnbnWi&=?a|2qfCgeuxN4f4r;!ga@i0)KNd=qq{=ZrQ+1mA>)M_aoO{U8r8eqq9Ei|WJ%V{J|9=zqRWDP7BSlDA!7@})| z`8hnd#=jdEzud-(-MykF%a3k}n_os#Inyg|npM`MoHL!3Hl3_!8osZTQOWhm?@`Lx ztT@(`Y^E#ngPQ80dfTX@eVWzwo%)*oQ_Dgl+VV>5>wak^p|6T+Prs_23{n%FV_o!H z>Z9-T@k-gYp+e{R{79JmJ$I3cGjweI%I<+1SM~mM`Q{jWdi4%D)NO)ysX6huGI2YGp%oL8K4A8!QzBj&DU`Ch{DjY!r4~xbjA~3h5e8?7Q zl1KigKGdMkLKbDE%#L`+m#D8(2u`2II_;8{))ykx8G1s`k0+ku%R$}gfkh6cwP^y{ z9Dm7$EeB!0gei)+^YDzWv*R3vOmPQ}YtfC>8Q^(Xd~-QVB-n+wU+2-e6%9hKOYc4U zf&KekV=~*+jpx3HwHR<~b32bFc^s}V-p>(?M*7;shn_|Aj9%OPVKLJ>W3EwC5#928 z0oqlyAv8+Y&JYQ*5d0qE;NXQ%;Wqza9?ZJnTwO=A!+6xWuZ2|umGDx00^EqXzrG$hA^C}U;s)z!=t&Sdko zzvau(S#uRlyBm0_^}8Bh5B<#pJu9I*la-Yi6kL~bw%Tm|5vBdJu!KBT?Vc(rnbB&L zK)ytmE-QTz43)f4Ay9>dM|}e&HkRsfg*O+u&K*Fh$mD%Z@hL*BhPGJ% zcKJlFkE;3*B$9WXV&0qspeYW(K#vIMMK??IabOHNeOx$v=+GpbDNmy|!FY42wcfJ| zMp_+BmsM3^?%j(s2bjJOZrpmIF+tvO!NwZqzk}$CihF`_FGP5GFFV?@3tQ;@P`#|y z-TZ6ow3WHuj^CBfxW5$>O8vXTS(YEhEUpN%oci(OyQxXvjE_MfmyD+|zgE!0S5-G{ zzwq4Ot{8SZ-~=ZiNVF(~+xQ7b?$@;HZFoe8FjK-44CbK7CUE#-tNV^z`J5u1@#gTb zJuwMc&vv<`v0Q#8Anq-@Dy1M@b?^B?bN>y8n7OV1p``{!GY6(DVK#Rk_uI52F`V>j znS1Pt?tS>OA1Xef$# z(=MTICzAy8`Z%$(+V6*FXL!X{C(DOcH?9o==d*~ou`3~Y_^rpDfgt7E|FV0f{NKDf zBE}M2diG?p(xoD^CS%3P>wA;>NB79dtQ~V4vV2S)oR=a+sR=iH{+qmsxwW(m_I^p*KD)5=O)ymfcGnK6+O>V4rmI7n~g zWIxtiWw{^Ha-pZv*fh6&37mfnChE!KBl|0q(Z~_hGoUbo7zq22TLPAq)6;1k+Y1lg zD?g6VRG11;b>9?px00OO@VCC`T$`i%gEqI)&%SK^vls3+4Ch!q2+B6W0laACuqEh> zqBQl^L~FxCm&nQwYvB2nra3r%!c31q*Aq-rE-0VhM|<|16(y3gRCkaHS96Y99E^(wGiUgdo&!;^N}C>@@o_7rIL{oa5DJ2^ED2?*oNv zLDF+Hhxxg;z@xOLmEX!uon^~_7WXpK>18H=CR*X`UHo{FSDwY4~xbVZlKTLohrDbuFgi@LslJFw8V zGoll{(Y=rQj|LtN&x4ay1zz*w@3f3O1S5#ZM1@J1{3A;brz7?N( zr75ycxw+K|Z!6BT0HhGqX$1q?q>E2VU~UQvhnk#1$Tz}p5>5fx*Ek8|64FV?c!|6g z`=^$=SXjUVD8J`DA@9YL#c56@Qh?Prh-qN=Oza-aPhk~3zrf02XHI=H=s}my!3$5B z<;?Bcg9?@PE@`Rj)y&7XNAizUrKvfC@r-|%A= z8kwRN{clF6NABPMBjeI|Z2pZz#hdIXDn^Oh>le6H0|;t^+c!2cEH5N4 zuY?xvocU#7ZSlf(yzQcvWA`J;yDPGEEI;FmHf!7D$JENjoWFeWV7pzj{A8tZ2ohi* zI>S=?&-?aU0KH(o;-c6b8yy{>mNp*N?vAAa#wX6alL3`wXoJme+!(&JvJMv7M`S*p z16Sw%{g#~b11@x;l|sg2?e+}!Htnk3QQDJUZQ%4lSv*GVs>cHtn%d1hOA_J%xs84{ zEy_Jn^l=9~TBtz;_*^bKxgb&Wpd?1lTH(P9;{KC6wbZM^)`G0eqG!ii!rz$O^`1M}ENPxoedZx+R@h<0utH+O@Ua%|&Ief?BtT&(j*QQk7p84HA9%FU~n{6o;zXkL=vp6%ceHHz)SB^G)&8=w@5}6$7d* zMg?e+;d=h zhy;~|NCj{P;k#h*^E4*-C3IbcN>d0%o1lM;Kk4k~s0H+klnwIzkTwD$*-@lRb5>WE z6`}{bdh6VFFCa1`z=STax#7@|5?-xjNvDb?V5?{FJ4(%p82iU zP14g6eDeD57yFjFTl9`N^lMF&tdLF=je6!-v{w`abla9BH+FoA*VUE2Hb%n4v`=Gl z;2fWJbpFaiwKoP#Na^wQuWb{qt%19@9dm}jbwGbnm_yTF8M_=a32nN zEB?{Fz=A6}Vyw(6H2Nfg{l`ZAuYhc|NzXe(-p8X20x0y?2ZV(`)L5N^Mjo0Q5}+}J zU5={iF04Y4IOGFzLP6*WtQbJOM}s5@>o26)O$-u}K(H|ZjJKWgLJJMnBQMNAAQyva zf+4`4i4iOb0HNeAZ6PC z`i$QMq&g?v+w`Ls+%6YolMzCt{YPtP;joN+m_ zX9@2+)>t84{1zO6`+f36^U1^yFCWm;uLTvDbO-s#md9_bOORN!eF$m$pyj#tN$RCS zr0>_}FA4M;(OK34b~Cd%?^x!9J^a+~#+g-xMQcp|Fm;bE4$|Ejf(OqkM${)mEo)pl zcIoU zfrgTvjjO$$xL#q_(|sm~cb?g=aFc;(ib6vODa}7ii(yW<20?~60L*0cTYCtkfRGcA zAY!o!MlsMU^w{PTp<+09v$ej)2-$UrUB|@58Br5^nv}p60U(p=6I+uOKPtvDkh8g& zg76fPA=qQS_v1K+qxx+74_*l^oAmvVZ&qVLCA}wV;;+;FU~nf(spPFIZ8p z)y)04-)fv>pz_V>HWp@K3i?$zC0F!Cq5;b~LK$_SXZ8>5#`*6ZXE6L>B;<4A) z3Yc$4*|j_Ato2S`tZDzkeWOQz!Q6+=_pMbw(<}2=X7BkLbCqAOT%23w4d8rrEwoBe zGO=;ea+x1T8P+m*=9Uw4(l;i>7s;33j%3=)cJYNRjxNh7f^{Kfzw28uBxTr&vR7ok zIO~0JdD6e;2J(%@efN&OB9t*APMr8eAUinK?}g4di`Q306jBJJM}q9|TrJ+CIusOq z>IkC36gZwju&U|Y1Ps2D!K)hAotc|+*q8_4lXs01ySffz!l%@&i}z1(Q<^&0!VK8J z@auH*NDe)VuN==|)W`cxsHu>kN_Z9kMu};Vv6{jqoG=$g_DL*Imika~P z;da(Dmb@|S$g{zQWuuM5nJ0(2_fwr{RhRg#AldQa{6E2iw%J90!Ufi4&z%!1;Qv!? zlF5D3R&`}h{JVqXi`fn`H77n9e|q-(`Vh0D^2~yDbk1!5U?79|u7XZk9S;^=UEj=R z7jYadpZk;FT2`xlIq@aWs^W%%_>oPko1k!D?sQ@X{UfRMPUW||p9g9_z9ySk@Y|BB zlON?U@MtC5$B%bvVWzsig#ePLr|rCRxJNeD>m!Egnj+dS|B4Y%+Ts&3dOpZ_r7oRM zKwD0MLF$&ur{ITfa@R>*GuX$vAK^T@*BiP;-jcXy*Npz}o}EcPTXlmjLJ|8(4yBkL z=*@nAYj138d(bojNg1i-!J`DJ*h}4_t1t@W#eanI*C2i*FmGVyx3HF+*W3g}M`jj-|nGq&OQQEP&9%adJQT?p*K`|96#V*u;F ziI(~f6C5`1_QrN18K5lsmiOi@oUngHY_VEFw>lID^no8oT$HO3;{*@)cN!-rT)-^A zDu@hV%ps6QvD=%U=)4FPp-BFZJv&%MBhe2zM1Cq@3M1Lwm3N-O)xb!^PL%SO3Mg76@BR$AND1ZsCS zp@c5>1O?xC&-ZR}L0MJv>gSaVE|aq*-o);Dqpt*g+{coV_0>DZ%mOB&t~%{`QX`E-)_LV9yU?|8*FY)=ibn}jZZB0n{ z{mJ6^QmJt2vA9ZXW9Z$+wF@f?oWGUN$fy5(<8ZA*C(Hhxdh`>@+5{rLK2Qb(mWY7T9F=mjA`(6}@K>Lo!ou6>w#X?0U zNfkQr?%qj@Av=(WLAD{%n^DhAaHs+{brSr8A|1tJOo{#ptG#VLA4>~eX0Xs2&(TCL z0nR(jsz+NgOcy3PiM}7JO)@x^-&IR9#`G~1Bnf+SP`$Cdv_Z-;T+j$DK1K%wtK|=E zCiul{b6TA*PN#1p0e-cts8gUi#z$YwETASOqb}M4QCu+J=(Xd?bl>_ zD}#Edwb)(aTk-Gw@wC63W=lKFF1J_wG@YDmYfMPWI26LZC~svKR#{o26)v8d(n%=v zg22xOyG6I_Vj626t!o))TNhZmeLD?|u6JLUPRf&A`4QeBz%}$9f+0dMOPJO7lxF&I zvKXo$fX_pB4EubjV5`Br=Pz6mQY4#RrUOcpK59!=Iq{) zp}5ikqdv5MYnM3K0MZO?WIFwsQfzkGsMZq_P;5J5X4W+0{Uj&svUc5ONtIi-ZBJYl zDD7X};qWju`a}Cl*Tjk=#Sp*Kt-92i)3HiZw;hkFoTZk(B$={5=~PnE5S``I9JA1@ z3(G5sk2Qsy85;Q4MA?GVF1$IU{>J^yiO;z%Ln}pCeY+{U>D-WG7+s%Ve%mn_s}sAs zF!TPjk+J*2%l5ifTRL9DpHsgnYOe`LJ=2dZEW^3xZ+CsV(4M+jTi#%uRJ=>GENm&t z=MJlS@IEuW3oG&jU}Bi3B1g|Ub@*$XSTy$dnFyf842-qWzTLAw#~rajPEwJIneZBD zPywQ&mNs`s{Ee{dSR^}}@8xvWnaqv#!y8T;^&=CGw7aH%bRT`sG5B_5&hnsDIa|h? zffBEIBiok)wlfa7F`0u~80|F@6#1CV*$1ggIQJ5bk-F*D?IzQORL7~C^(7iBSN1*F zvRUlZ8UFvUEdSnfn^>m?L3ewEW*D}A{}|a&QM!&f7Hlw_kn;biaHOe$TvYb*>q<2;O>f$DUIafk9zX zTe&H9N9mV6+y&h|k1l^S_(Qrp;xPZMyIUF8tgCyH`(0{?+{*E{?dn(0Gu5>f-%Po| z_is9S1Cnk3eCcdD(v)=nn zkfjn-Q*py5qqg~5y3V<}PA<6<-2<`6!zt6pH~oxsu1TS>EiXHF+xu;DK_bO@QyLE|ns3FF7AzdX=asd;H7h!u zuYao}5uZ$>XPq&Ik7%>yW5}i9vcVdS=a1$`XajdCV-V28!c5zIvadIDIcl!);XOn%!V7NlI$kudevjM}3c#{kI196c?-q z)NpF@ydG`t962=fcw1nNBJ-2ch4~e-{&~G&A3IFdf&#mEjpS+r8N=h*-1v8g2#P=X zeQ=I!$MK*C6;tmNwE05b%v(`gNE{eXBeBv`EI!)*dOR&s=N!E|YdXu%g*u(ZHlDEs z<0Lf^LuyutW2F2W!EO%%<#uM7LC=2wJXac!O&BsGSAwEVOa3stJd6?c1OKT@SFRk| zH!Ese&?$yBK#Q~P<>IyU+pQx^Bn{JKU}TJN=15_qwuXGB7xemz*i@W-i^#{x#w@3?I` z?AskytKaVtU04jTXwScwz0g%x7v$#uu8OM0HUC5BPo^>H!}2tgM5}V`_r!2-&l}Y& z*BwW9AG$7UH}!*eEA_TbXW0_YwWR_ZO;P^*7-_adi zJvwKY+n%ICUkW5WNGZ8|XoeWy2?~?vVmX_nXMUv~gE;zwxs<;X{^p*yn9` zW$u1TyNDA>(2siJ_&IB;vZtcH`#hJ~P8PYuNpz5IrELB`0Fa8F@|gGHV?ca9vWe{Q zD*>rt1)Re#Y!jttl^@sDDINR1`NfsvfIOb(=F(@hY%hhYf-^RFi(johiQ)B@aO`?J z#;913>LQ6>FiL3b=IWie_pP;6h>x_sqR@s};!4eZ*LHtSeFw`u66^77Q+|HywOuT1 zM%>zq-4tG%N`1dBF^jHpYtJ~T<{5Kk&z-SoEso00?UJbrOI@8G^3uOK&ll&mD)V^P z<6~l4W!p#Ns)uH{UHW#{nr#1Lxej9cnYZsg2&bl|n;15~FwhL3o8y0V@pq)4$W>iU z;&>F|UwL3*wc33`d7Gp7#s9m}x&s$=rz*kXsTG3=NB*syDm;Zj{l_eSta)?aoU72S z9ukb=cmxppgpEJh3ANWfV9O8*sz41l5s5q?A`?cP@SqYw!vJy6*$2*~-O!pED*u}=S zm7iI2raEK`TOytN~oHS)Wu?{ zFar=K6Ka{=l&zU{5uw#RNUeL-hsE(Pk?tjcH%1Mo^+BP(C*|EVB0Bg1n}23%zuhzL zC6)6FcCbZP_2vQ|*QvRa)Rv0Tk_CGESym!}GqQ;0V|d@`0)weBT-ydrRs@>``)qbu%OeKh)LLHBo1C)TQGF;|r7#X81_7csi5* zNUgl_$1km6;~CEueWrI_{dAF2x8hg2wcU#>23+}aFIWG{?Iob8zv%3$i}aU6=Nw*r z;^zksUJs9=^_359otR=`I60Kp$GK(&iJM2O?X>%}UE4{etenZd6JA60G!l|%v5Ja{ zX6NVoW|n*_?YP#T#XK&mj(m5W@-i1=uzY%$`V(3`WcYpZCMApHGpx9E;J?KL)v3+4 zF%CAINE`=;jPqEszNiy(GFK8!$W`HL6LZr&`zxeGU3)yovJObl>pBglRzzP9;4 zi`)b-8LF1fSb%f}zA{y7f0~5EK{IzM8?&09OTTryJdC)EIF9U!W;!#rJt`)$jLUPG zwtJ=5X=Hdz|7M*%>uP*A$>iD@r}y(+?T`gKD4+=vY3}%Jq%8I&VRM8{K1$4px`5K@TmP8Ba;1+~)N+f2SPi~zN2}c%iDreR zkH@PjH1lqbACRj3IQ?K(-^B;_?}w0m-TW5rWFVF%(Hj2z>kEXU8xvbInDF=P4QLsy z?4RnHaz?kaUK3w5F|bsxL~=a*ci4q=wRl_Izmgsbo#Y=k{RVnIp&$DOSLj=yu2ND` zY7{!Z+dUw<*!jm(pkd`r2^*kC1fGLrNv01n6hX|(>$Jj3Cl7>5QUWFgpzzZun3Syg z;^RNEbs6A806hna#_--j1*{s`%EKp2FX? z68`jYJR8{ZhxWx8;YV}F9=F4$n&sSzPI>Dah1x)NZeHKVG$)pvO}7ooQ0}U#q>V5M zKP5>1JNV3H9j)M&{=;_58b@^asI%2h-P_q`4u2nl?M+BH&{G|gBO$V@A#MTB`XYD5 z+e81n92IiErksh$7pvT+#zrFJ$FZQ(t99Hl@yc-sZ+tfGgxQ>K28Xcla+ddfRUuI+ zhxmG@s?)DBGefJYsw8JRtOUg4X+Q@=*7sjW8)*%V$c^_%xJ`djzn5KFe;XxbANY+) z={FjK(Oh%58eivPI!TA2>y9ceLs7a z_U>H>L^AkV2;K0(V4MV;2s^|@WyK?*V-|g@mybU3ne?AAK==_Dj_<5Gh2Ip-YaR1v zI0J?D`D@ph;djb9?XV;-!Okdh*!$h(T{qsCC5@HK&s&Q5cQHsS*zOM5wsUyLw^K{k zZaEg1rJ5!6I&T-#5vxd+v1@#gddQ^elM1_3%sHY3fFRrS>(etlucdC|0}urjpA>h{ z|KGN&LS@>u2*h6inPU=`W@bRbsVENsggpF65RPMmGzE2h!lgrGnK1Z)ka1*m^dJw< zW3WJ9tEFw&AM(3yxOho!TZKy&c+$FFYYxN}Eq2e}ElpksTLVZtE=F*&>>ZuSUfz2C zurzHr?ME4P<)OvrT3@KIyc6+a`}o`ylo&=jdL<2Me+!g=#Owe%2TQ(|?8c_Xb5{(> z>1L|9IR!5HZrj->ibbn1SP8u_?;?c6_jVs55uGe0BUJgY$Ra+~zoe9kdktM(N{Ds^ zGYQw2P#r`mU_*o@GLB;WX4bW6_b9V)Yx%J=XB-;b5xb6kF}7wfeIcxf&`|?zh1P~B zRIsEm$<%ys^e#h=+G~xE0bIodiyU;aCwKgBUsX}LUEZsYM3Qoo*!A%Zi%^crP|;(o zw_o+Sz6#hUm{)LDH^T3hIm45qbiYzgOP!K!B@<6<`c>N8A?cPGn{z~jDcv_ROwN`o zO3qe|iYe9|?45g)(cP=Qg@vMs>8pW2{p4oGk8v))7@ITnlno4??>-mk{BI?WIf20$ znioQuou0mVKbmH6gbBm0Yu93Sn{6GLbA@aLIcBVUC6H#JkwmqE-r)q%MiOM%$B*w+ z8iw@U&o~Q(@=!OHH8n(x>^2waQbesi1HX)rW@x0h2(57m96Ryk#cK@`VI})ZZdvzz zAMAbQ*xWxdM{CHVpT)2>n_=6TecW19NB4MlUi#kB9bDe5XjLSiGQtUQFnAv|vXK_p=_1Gpoc=op4wu7WmG(i1cXMfSs46x0*F4Ah_-$zs>r zqT|GZc71g=St8tMI*`^XH=2Ug`8Kw#nNW@q+83Ffq~ihY>e===LR;Svm-;WqDe-Ro zP$G;Q(HUa{1c}c{C?l^S)JP+}*`S~c0+^SHiRE7U6NJ?p9%xwn{`PWfC9G(%kh%`@ zJ|N66ii8?cA806Q^jp(x8ur{x6t);xz8vPc9gZX zhd^^IW3{2&+z>q5vvY`WX=yXhAP(!~I9IHn)!kNetXyP&HF?;n?^s5k5#sgmvuG;)U*bqCDTWg-@|VTs)O+Rbfq9Og`+RI*$-W> zIDMqKHuCPREJ+?_f7{Zd%!E>T7HW*KYQzkqv zyDv}4#@9VM_3cNOqN%n(=R7Mji`cBa@Vi{cZ%rc!)x8xz#SJDAi7ybHJh3;U#jk#}d~|8{`zVWhYd>&=-Z|%y@wsOtckVb02T79qZP{t@oz7~< zVZoD>Mv>ks0i=mS3_(gkQsQUsF}%ZKitq!5-vyxz=*JPgAMgx}AYns*6z%W>JDy{J zhm02v5`9p35^E9I8X2sypSb&%Zn5byjH`8YbnG1+mrF$Vo&&)h9iS9MtXM}U_6aS_ z&#PX!A`Jxy3AAC?99xaCecm}I+T}WW3c6lW0tY~#(kT+wU_Y>K%GtC|VTdJ|(;oAh zC|yJ=g#&?zt3%l2TeGGkK#Cx+Lmy@H`EY~^*w~<2lOXz)9b@Ll1u_vDkL(l0%4 zex+jeJ>?8!3ul-*OCy+WW>f0C-BKj!C!hGZNZbF?_pL&VOavhXdt}@U8$o8(81~&P zEQ;_Z=H}*xuZ$k$0o;(gdC#zYCUlapeT1JJ_Mp(T0pX(^{rx-P`E!UuAHo0=w;256 zAb9wLjrt!@G!(a8piPtz{-vQ zTd70Ohk!~Soo=w3Lt|HFl?zqwdDxYM{REy0x7WHm3R*3MaQX9X=7ekxQFw%*3brHI z?0trcWi?n+Te}8UQiO05@DPlO1Bj#Z=8so9)zz_lflm$`xP43fT5w863fUb2qk_?~ zdIv4NzZCn_Lxx?@Frgf(ptpn*iYcNmDq*jt#KbasT7ieJ+V)5uTS5FMWMPsNPv43w|vlsldD9`}5?>)KyEfvnhdWsa{xYT zEprPC#B~IrOcMPH4i~rz{i=)IUJA&MV0YvXJifTvF3!id8xDPqH)bU!hP))#LB3vT zUk8o^TSy=#^6Kg>&m8ud5e4+Zh3ClmL$UQ-DCma0A68>=cx3q>Px!OHP)#LJQd}8m z6p8GzzRCdQ_GnfA=a_0yFNo#<5-#c$U6J_15}gDif`Db4h?I3yR+yT^6-<0EmtMVN z&9@!eVw4w!SmAKU-$4OwG{z`p~}3E7iOlkJTb{A6T$TLE$|uWZbH z%>wf8rwu;^{f2pHf|3#vHf6M|gtKNQCX(GYjrVYDaF71VpFkED3WkeDvAYoJ6bO3L z(ECjWS-Y2a)5(*IGft>cQQ(8DKN<@5T0MxHA5yAGwH=z4v96-%W0zmvs%CKt%$tk2 z{XZ?ac=Ge--XQqLRR++*ckZu1Lq44 zCenf;@qIn+JCjsLB&>O&NDv-7TMxzAd7`m4k|#d_XMurqI@K+x=32n+b5(MBE-K0#{S_vO2LuFKN-S<;62M`PKwpO8 zJrF&fxuFS(J+Pmxqk;Jutd`=K*e6M8Ldtw zk+y{+*aggf;+&z^v2Q%~r(PyVFeM)9uWxgMTAG0^Eq4QBtqMWMX9ti4M+i_2LY~jSqeaC!CmZsff1# z2Oe%Gx&G?n6m~P%j=>`r4HC3+pYS%Nq^GlFy#~KxFXuHmc#YyIg;lf-0{+Nn-v&ZL zO8g-(9Gn5;vnE=m^zwd+zMbWlkZ=xqvZO~Ho5%lbGX!b!d%6BgN=`2)LJZ}iJi?r zvyJ--+9Q1bL{NUQf1gU0Si6t=4jrb*i}+r{fz-4#BkV?qjX21ce_u{$e;?If{lC}X z3N9`VuwoW>XUJ_Qsw!?M zJ?NsOYlVmZbJal1G-W{L0X-&i_*$RF+XTo47H+Yj#!n(5F6-%Sg#Q_`%_n-skAM}i zyv5HZ1;r#P^!s-ekNof7@AaV(2W?sE!OoNyWWfyHckbNzR8w;hoFIsw37nWvu0pxL zW)Q4(O3ymj1YHr@lNr$aA=E8Janmexo)R+u6GT2u`S1PO`YbJNJN!KEZB@Zz16{dY zP9eHi!bb;*FL;OGWYc?Vv78mBmbEpPR=OI07y}Q&2G6lV7Mv&7*YTLWtwJs$CPo2e zI6}`;2p1L?A`)^BWX1QgwJBoIelAOj3xk`1#v<&=6HI4PN=nq2e>ziM`;q_eb@+I; zly29q1Nc$UcAzDUYcf6pIhxn{DwoF!;6D(kfk#$HI8kYMc%QxUJ92gP=gU4%MP z;yYR%4*1Cu#|J{RKk765$PW3hwA{w++}w`VekTWqcU~Kws4p-+!}v}_ zu%LK%SM^V!X%PPXu$(CR2H9HmOSYISE+{H)-cptg!xqA~8x@qRXm%GSD**9RP;l@d zY!s&p5j+T^H85EMpY}4rk8;YjXx9Y!>CKdk&lSlJp(pysJ%&j)qlJxxIIZA=1L?m! zSj$*0@`SZ-?VoZ6L8=$CGm$w0?^BRC2(CH&>EPxfvm7=?1dRW!G8Ha47#qP^#S@xL zF2bQ>`}r`$iXw@eJxe?fnT5)52m^n@@q4Rsk2+$Zr<_HRKM(?AUaYlX$8AW|y}f&( zFZ~2*_~)zYI``VgO<+ohV*`%}JZurx!vfAAz!v1tqgffJu zY2G>$C%-Lzz)!)nbyEKw9khL-+J(;CasroG|HlPDArl|9#4aiYff-9f@umQPrboXk zXXoZ-VwNKWH>l;H@(>>qb1=as0^^W4tl=mnitQdAeI7h@aN;58vbf^#V`sVzLnSCs z0I8!A!S$Jl_f>IU-jRn*K4{^{E}3+gb1f=d>y`(LBmaB% z*eg!|wLPGuTwLkis0&xu6*}%3LJXlkoLm^&z)V}_ihvzkNQfi=2NImBJy21S?&swV z#nFmYF#duG&Na>!Mz%CC)p3`3AS4C-O+M*ccl2)v7zxS_EK#<&cZvuLBeOyP1~Thq zJ(mLADId9?54?Fi`~lhqw5Y2y#LY=feGYdS#N{wyvjq6ciu&gdYe> z&;%f_ARuEF1Va%RAF)3edtZa}u18WHio4*5@b^)bz1Q~bh{adOT|5cg=kHyRtazIZ zPX*M2%Kl)9I_T9gg;Ng?t;kgOU^?>g)U-U!fO`f$ue&%KToNU4WB|45aV)4`)=<}V zIZW&W*}P)<`V74u&0-n*9*OBhn5B}E(%F^*7+PSuIsI=h$CcM85KJ#5$kaChLX!s~}qQaRrX2R@;s&F!$=4!=&M zz`#w$D+-Q8=um7%({s1X(kuPbdVgzc`vPIj{ovpT`nDU-Rpe+`*^4VoVeH35wBRoA zFve}t`kTWBuI;zxX5aE&7!)m+BUTk?Bs&Hlm|4uadYojiandj9CIYy&ZG zj-ZebE;TTRQc-y{rau(&zsJ`9l4Rm#BgF@$%@)-^#$UcvxWmd_2qEv=fBYg{)|ZAZ zC@aHi)%yDm#!#d*!>*;0key?ogeei!9Ge=Nn$Ce|hi9+3Sq*#iEt?HkgDK#Lj~*TS zJOenVt+(p{T!TvoJU|G6CH!KXi*#?_W?CruXOO~|p%5G4IGgTcvV4*3O{;eiTYO*` zM1h|#n!8>~Q2GGF;_1To!9#`aV7-(BLmTb`ylw#@AqyM@eKk}|j8Cu8O_cQ-XM`8% zE5ur)qTEPRq(svYoLf(ER?+O>8Dqs14`EUHT#H!}lic>!e7hkb&1Upf0E~9X0hkrGH1qEc86>}fAeN@o4HvJruo}asb`;u=?MmK zaY0-D^XJd)3-twBUtvFl4mW3m;rQCx8dko9l@isKa{t%;1hJ!PlrT8iSiDklh0Wo=E)QGX&fJ&B7e&258Dkvx*Y{tO~C&6v7gKthEzD`Eu z>9O6o}l%|hNyoK3$(;bB|Y6(V!*WupbasvN>(TC^iG8HFnoiFT?qOwJavHJ&?4Pe zO%2<0UvhvJz2(ll0SU%`?`2AZec_%UwIKGBa(7sEs)WfWd2Qv5|KFCO=ZCspQf_Vw z8#&Gp_mN)1ipg)-DZ$+yGcS%UC;;(J8=yl0LrGqW#YSz7M>v{Riu~kKuHl8vyR@WV4BzR$(;)n^PB+lK03d@658MRrel;n- z&V!DTLJ@n(2Tr7@UI6*GC;~@;xuwLLZ>V!GhQb$f<%&U<_P+Rky^diR!8-qHf*>;T z+byF>xTa`_i46f_1>l1hBzq3rWHc5&O4w)ao-!wVFLQEmit`U=Wn=`SEd>VznGDx) zTA~WWfq%DRjJ7Q^@w3bQKR|IMzy~VGr<9S=lZ4=`vdbFErhxxEeJ@=O-aS5kWQ)rVZSNzE8XWesX$R%7vlZ8Gc=N=f}1EnG+Ru_TL`oF740* zrQ~x+dgqTWnf1U~0Pc&AR79wE4gF?5j^xnbwbq6qh35^Q&yHlam}P6B+FU1lK=R@l z8!_atZ~CvQ67Qob3e>JQf4{Z6jQla!ApZBqcwZo$y-4x@zutJyo-KzYqT`Z&_V~ZK zr}!nkuCsSpS=r@Z8?fPik(D(YxUd4`>?f%4Ev~gdC*z#^wvj*-@e!Nwl4%}c5fQ>} zZE@V%>+cY^ovZMyx%p_x)c}mLcEb(NGu%r+-`t8C1US@dsYdU5@-EP$6}+V$mg2c4 zmH+R#UVKW}kb^2l@zvbQs%p>{qmHXCs~utLuJd6x2?kSyI;npk`W&Lzp}_>49Lu)a zLjhN_8N|G@1Xs^wx73(qVwLIHsjXASpBOChq2GR2C5$?{0hOBwksj(NnqoBk@a?3-BZbcVJ*LW8*R^NHps`NYd##6}&jT7jR8zII zJ;2w9RgbHi8yc6Pecg*&fcRpm9}P4w4)8X#|IUCRF%J&H(A|Bdy?YC>8-<_Jd)RGD z1_LYnL%>-w^g09a0vI;nWde8uQD!57qgm)u(JG^vMKckKf=#$n0>EMOTx2I9NfXcvWn~n_j%C7&4I)xfBx?~Ijm=wJSFhPr?kR+8LWk>U zI&^}qJO4T=R-_yfgZbXy$EMHx+s$l9BxrtD!cCtFJ3xdyuttOt$YH#LAY~BzYV;Deus^BNs6kp$mj;i;D1o z0K!W86S$X)iwkiDAkR`&Q>%gimvDu^8XEpZWTvmpfejMQh-h$l3BCpN9_w!@p1~Lk zX=UDo1_v)FUQ#>Nu62P7T9<{OhBhFjb} z86#;F1{W(x)Z*ypqyZnNrD5F z8~(qStzZsP&lDJA8LO}FFPQe@fmS-=s1SbQ(l&^J92|9Ws=HD!qQb$O@Yh}cVTnmH zvG9Uw6@#}-+7BMfwk*l&1!B?w>f_aWzg^_dn=J$_#Xi!h(+R-cy6fQ$?py^MY6 zm(hn67FoF$kqxb^xK7PecL1wteD>|;r5jl(Sz2LQJC3JY^%TnbsHW}93sMTuVha=& z)Oc`eQ&pZ#{~|>77vQ1{0@C4w2SG!TF*W4?uuCK#thf8#ySIbVnVFgbD6G#DQ=X{d zv9T9;h5=Y_tit1y1S&h{W(WA-p3flo%KpeG805#lEXe%u@-OwPS0Q7?GiQ2@L%%^d z*3v&4fS6=`({&z?Ug4PUpfNc(%sq>{1l%cEhrmI(o~eA|#^Zb7?7#Pqn{rWe=Kidz0<* z*?j7ilYlcoc0ivH30gaWR*?kC9z;nY-Z!!gy7*wMm?eu$5y2%PD3pqe@sAfA)~V}D zXpO;YH{y@3&*Q|G;9a8*lC^8=5+OJsga>X&2=|S3Jo1E>A4EsEFn;AW%_>6*_%krc z`#f>V(Ur#KAhtIcJU2lAN3mH-&y)oWwXDZZ3Mf9;rr9!yCtI3iWWm+u`;{h5ouEV$ z{ok)rU*;x;?hjy${T#@DGVoc$=`40xg{i6GZ@dj#C=z!xC#t^U{KO?H=20{&q?1=r zFfu;!JhxqPVM^YDB4BuYtfJGPy3^`Bi{T+Y?rla=2deH$OVLp%?KvK9VZr^HcmY5& zD%9n|TTTK!CdxWB_Lcw>OhC4T;_?=th2=l6Ka=tDl0ffFoF+g=Q4xVu!H7ZEeM$xk zT+qx6f!1JWwH|hRXn@;EiL<_c>K5d7fO0(A9AYsy6FfX(fsDR}gn+6rEW#25(&xZY z`<$+G*gFqp&A{*x{zPtos?R-FAyy5573=e2koVQ)v7iGk&ZV>;1onZ$f4Q9Z-(vCa z2z&5JT6XxGr=gNcJ7Rxa6}>^DMpV@pdlUeid>v7mHbUpX%;i>pBp@bj>t_4eA)WRk6=T<`{E#C=Gln~2g7T^>%H zU09%lD=ERPQA#Eg>=%wDMn?jt!pOVM6cZL38}!v=hDKcgU=eOgeco$~NWeXu!Da+} z8Msg2p^)9LPY>bwuNSb1@fp#ng#Pd1-OWs5Y!5m3^WsDO6UVAXZ4Cm0${AP`HKaD# z2<4MUD^5oByT!~VmBkv!nV;5&YkWoJ+Gzfw`>efv&yCE+&W5wvjik&w=2B)|Yoq$P zO-&3KC0ISKhmG;|-GLk%A6qQBmJK8#JSQT?>nIOvLx~9qd4o^1l?pl#7>Uzz%hv!r zdEncXp4G?%q$JrwK|v93+omQ|T!Hxea%CM@TF;2G`})g20KT z0$QVPY{f~?HzPlVe`7U(^MgNr4F~4Zqs`bOp8Nti6FVOr`e&2CP}L?bBt7cA7IU-> z;i?pu+XQPrf38r_yvKer&@iv%vRr>trers&3S{20BRc%o!Eb*JB zk3Y}CTpJmaDm^f;OWfx1n1bOIC@7eP?fn5+%5kGs#aM`40DNcfEW}Jzst25e&eLKrAXx}h_>y*KW&@8!Lxo1Aw@Sz zv*R5>;>RDPj9EM$s+CE+a;Kgmu*0C)S6=S=A@-1vLj%A1CT#W7QWK`L)di;q`ZZ>L z>Bq*N*SPs~w>&vjVxx1LLEpcH*ZY6poBjKHYpye!qesjv_PhR4c-gVaLO?FhA8yQw zwk~$Li7vJzA59f~D1Ov`gzm^>=AZ75i|>xn4=hQ{ExS%ER&uq%`o(7CwdT;cjXk?; zLgo?L*fZV}Ici!bjteeMT5o+AbkJbRSXwEXQzVf%8aF*gA3&`8{_pl}+EL)BlFiN* zu6DlmwWbD^{d&svrQt(D--S{aH8!_&tQ|Bwa8T23PQXmi=FVJuS8xA&)dw@(hvd?B zd}`ZQcJTDw^N$2QwkR4WT`A6aXv9@?_S^J{`%zBs#$x^!X8e~d`L=&rFV1Jp!2v1G zYgeHjN<|>%ZdN5Pz3!5-*zGqKyvdvkbv@tzD!ArUIY@H-<%`MYH%_VMHxph=3#xao zo%6Ks-(k_EBbWKL>Q&Ok#ny#C2(g>FG_`ZWb-0B&HAVlL;Q_DZjFqUTXKt-V)AJWr zo~su<*MDE_*TD6e+IrT~U3+D5{z`cDU5IlZcQ^oRWW^}a7wzRwIgV4+=MDU`$ck><+j)gl}=f;y`wg3n`X!RzT*=`OGilLj|Y=Y4om3vfk#x@rA$48K!LM{3RGzkr}`g= z6f4h0Ze=Z;p%9&)7B2RvFLGb}CLySGwer-)OvyEIFV^m&<>=MbDUSTXS+STjg%D1Vj`vOG#QhW#k_@h0|K>+1LTuKW7W5^7azb# z1F8|G1WfKA4Alt=#VVo3uX@)Ekwx)t=1VT<{9G-rLu;RNdw5_l)cdh)qGU!39W%3g z)rE`}BWQi7sbx9h_Za3~J~|xXPF#=2|DKdXt@p{;E-lwK-Bpe(4g9k~qNh&3#yRvT zqouE~b+xy8Vfwo{JP-So8z9|4G)rq?fb%a?nni1;uf`Emq1r7CU9A_!?p*xTUF>r! zber~h3W*}i9W}pnq^9^LW6;B=lgrUPxi)jzaYZA(_qi~zhx>$8;BbZz0vN6YADSu@bQC3i2 z{u%lk8XLVktrqk^GDnVuy>REVv+ya$HVGc2;+FaeSC0Et&de;in^GlWbi|a+%vV3| z*gvxb(_w7K;8P14Fn+Vd75&xZ`^}|g87lT|PU!6PFKkEH4Q6=JSM53BiCp6Ki&t9= zSb4YTskgkx)CFB6OoaMx2@)S05iJN~k(R!@@%=i_=ei^RA7O7D zR@K(Uje;nsltoGi3J3^@gmg%Ww4@*{f~0hZqI4VyL1`)J?iK{eO?P*9*S=%x@%_$s z|G0NQkK%){)|zw88e{yTL-6ATNk?e&!+%e+ma$|AchB;yOS73}-*-l-ms1)UcpX#3gB>9}en9d03vSaA z?S@jziyyPTIh>uQh9HsYT%95s$|vlkVk=bHDtzVR(_$o}x5 zR$Q>MR79>$BThhF-RW*uQ|aDt#?gu3gx-la<@ULtmd;O_h|M2fC2A+F+N^YRQE`G> z_twX?V71nnYWw1%0}mUD`_y4=Gu$k=+#OZ5zr5nyh%? z{=S{Di3xzYLD(G}BE3Ks`FE8E(6$Z6MG&7Qt1WakQ^-O|%yXXicUlis`vRT@zToLK zNQyxL1*(Cd_%l5-!|Hxqf0e2l@6y$!-}#Vb;J8n0Dfb;vHfh@%TI64$x_7Nu_v(G& zl=t!PuTprW^6sX*fAapz7$`elXJKc0GgSgqPPKf4|v zE-Ln-%u$ds_@wjzz_cWBJ5>j?2d*^}i5?PwW}D?QdBCjK)FaoukscRQJcU>LPqpje zhBoCw!a}TJmop>U;@I7ff)htlUi&Le`L-+QrRUvJ4*GKpEg2bQ2g8nSJR5uv*jn(P z6Wa@(a}BT@GQAlKaoE{vT8#TFjx1!Ss92Fb-*0(Bn59mERI6zbxRV_!eSsM=jQ=)_bQ+^BD zEQ%fs|NOP3k~_^`9uy^Hq(eMH^VJl zI|2({Tg_yCk&wp6zcO`%MOYZMAAG5XdoB2l!@+t3K51KBvj39nS)lPOxzbOfA$BsZ zr@isQ7isL2g&XK#b+p?UZwF8f6rE7|e}JaQ(W;6BZ91p-HrJrM3xUQX5F3jxTId4= zB`5%(jGN$m3AuDY;bMU@2@qJ)ji8_s^UnneKo)+Q`Sn5@Q5U|!x*dB`yP_cM^7J%b z*yVI~LNdnn(&tGXf+UQqD_>+~WSI$uG`=^tQ)Q}_zo*!`0=ZQXQON^_97>Z0PWBL! zy#yQps65+6qRg}LEh@J#6;q^jA$217<^?#uO@sc_3;>m=K`^|Yas~>Xpu|414A1rh znuN-eL7|-%GWn3;>8Y@{_{eW{5hHqEkmttrPm~gWy4zBz!h+?x>#^R}yLTPlyKD6s z!2&;Eu-WLKYrMUzJ65hxV9l%P6)Z2zGc721e*Pi(;M>%sFc~byZd+yVDV92+3<@=0 z@E_oZ&gzESp!gF)LLPoIGu3>C-QN`wVTS2JJPE-giX;T7rN+BK^nbAckkr2esO^t8 zu3z8ULs}|b_}z)Ad5hQ3KYbF|Vr(vD)+{v|RU_}sx#HtKuX3dD9|RpfeAmDv`hx1UthHDEqP!;{b^OrC{D?+;>|j^|jEMy{M>5 z=<%8#Ob#D1jFS2^>S$(UTV#8r`zyIiQu5c(vKwh%%E**{joK`K$&h}k1Gp6kLKc&< z5FpuSKE^}gyvhmyy)Rsr)F9qz2ntLB1nX#~BgKI*N^X#ox1)e@kiQ)6(*+y`KwfgK z7i0xaR@orl=3a=lhD4w)JpbC~KFAfCrQgHV@(Y~t$8 zB5WL-S8$inxAnNFo&tO<>JcC*?Jc!o8S}XgO-qcAnp!}T-vKr4gA!{GFSZDrPq6YY zO!!A^?tT+n99u`O+QFY zfzI!2g$#TgU8pdMB(y}0Ke>NE^E#C$ix@N@v>bh8UE~6v-I>NM4#Z@6WJFhC;5gypvthT$LHtAl7HoyPwJHX^-j_oml~R`50y|}(#Ti7LrFwP*iWTR z3Fa7pUFrfAF_cH1l2Vu)Wh%h?fMbN>vZAu*0F}HAGKUvxSN5#H3lzMVP)SG>4hrf$ zKv=+#*Vdjee*qM%1i)HA))Y3VMqnZUauSE+(FeE~@cAfRHqlYVaxiHXP;UCOLIO(W z4kM#K=v)SXUjQrkF;rn=Y|_K zap?R#gT;m{J8ss3!sq8N-Ir(tjbiM)XRs_LSSZ|XdEjfiylaRg9!E|zy*%|Fd4b$; z?_v@dHw>zukKz3Sigx(16YFnvPGYA_R`+as$+(1!jO93X@ml&urC}Kp&$#4SCnV%T z)+OSlyS<}mIa{a%XiLZpLpf0o&_<{g%^{u4%2wWLU)FKU)Zz&aa38zZ$96f?nVp=?GDk}H&zU_XMhHb4~B*8=OC z!)^p%jjUJRvafKO=?!KMiN8=@=R#gxr7NA%^YihXv|dKUTjF07xd+;qT? z^E5h3K@i(CC)yy=7c-E-MMG4c^Av29N4@J| zp*3$)%hudP!=BLWs9hqW%#)cY9`}xQj+HAmpBcV{eK@h8-8udCZL5fT{KyAMoElS3 z_|fw!j#ExCU=MIv-72ov=6lwpSip-_5QmFo)_fXkhi+*Ys8V`2H48-s0L&)fS^$O4 z#v@aT0f;Od4>)5(eY3MOrz6mS-EEJf5f%|H&{zO~I7-SDWberHGJ&+OUofNw5}!9ubvw83IB=B3leDzleI{%E*!73c_0xqZLA1AL7&SBVLk0I=)O^-P)C8Tx zI(##$Zs)bTapP9QF_E^>!RcewY`vWz@>exmJlq=(43G)migk?O_ealvCGwpd-@f(v z^M%c*+w*KrzjV;7ws(93{l0B__VL**#I#i%XtiXde^1Yv3mMs%WH}fW8*e#SBqeGs zI$%N5*+UAOWPolE%u4M0H>1*bcIbysNqj>) zlrc7HzhS=q$E8l}s@-g1iPhXQfFpeYax%bsW6Y7(*48iJ#ejetEi9yL9b7XS3noTJ zXgZ*)g~A^Kv$g1~c2Wv3PXQGCq~7&)5|pl@0C5C11n`Mbf{6g|{)M7E0&IX+#+B{S zBNX)+cA(6cWzShkWovchabcMX|96>s@Q^vS`ti8*y5C$O*?Rc4**+zY=;}eVgzj2R z?1EpK;)qjqZ~x;${?|onrEnHiYg>~TtI}CjQ{g|rr>_6;-NLj1fe;^?VyUC3Igxd< zuHSnwk^7GA^~)a~OKc8~OZmkt4btLwYsz#52n)V!-R*d_J4ux}82J;<$RwjB_;(Rp z7@=LimnPhtnrY?DU^x)D(DW4?I^C>8NOZTH}I8wdC4c zD>nPV>0rzrV$eB1#%!Yj>twd2;UY$0MgXmW6;7g~V#ZjUNiok>iy9{u=MY&0V*d+?72%Ec2I;ppp7Ye3{qSSy3R0dHj zf{pCD8yqk!I=O#u$+8}iQ+JIRnCJb)a=H(GEM0VMC6dsb(W6iM&ZXz1Z_Sp&>>kX> z64|&MEI8jqbRPKAG{vxF)^6vgxLDEc^m!?!eL{1W%>&b+B7X|aisFyFXz(4Nqnqv6%SlhlJ8}cU4Pk9X;dvqJ95u! z??Uik_1>oDEe|0Qty=By5yV+flybDzC=gHO=#ZUMuog)IjnVA*Yp~$dl>52=4x7Zz zjv!wflJMLcw2A2-Fd6hlmznLj^5-6wUy|b&u@Sw;8}Xp=b&(Y;itF^s;ElrHr=XV~=HNe*Q#!oCS{@ge}UmVMc_CPC^V9)6=Qts+?N z?ww*wmK*U9_Z?}9x>bTOQ9j`IfiNztqC%J`9>_zz2!{a3xU8)>dTQl9k&APlmAxG`Qh)QNA-0{d1N^aQ)Ifdgh?r zuv_Mii}+zGDiBo+g-0}LWT>*~&R#|vrNGA*IKhW6E00|phvftfrhi?Jw%>p8K%*p9 zuEeZ<%4Yk-5LtI7$A78z(oDxx9+CF9q;Kz+%X#LjDoQb8PO zsO64<00rz01X+6szQCma=ve8fIU(O3drxD)QO7v@giYa|TiQ=utjQmF`bT>caY;kw zbg-{jXIFbwTHs9V$T*K{H&=6HELk6sg)moNd_c%CFAK0+001dprZfN;ka||C=@}G` za41Hdstdrm7A2Djp-)ps3@`fq2M>U#wIXH5y#$ph)~I#~95Xr?rm2E^e|F@$avX|h zqBZENPWx{JT-RTe2NFw4*PNq`I_@dMN@=}zhRvn+Qrg9aeTSv$g9b}nAn3Mk@1%Ba z{P2gBaw?_ubr%zJtTP1?yC79sVEGu9SkmnB4Wz@HrAJ;6h4SxYPr<^{-pl%>@}xI( zbZ=1qm6k2XoN}K{VBj2RZkIXyxail?;^Q08ux1zfXo>Irg$suZ7Vc6mHY>ov9!HvF zYiw#fV_+ceO?`}DDy8%w0ix4^4!WVHB@G z!y0D>!FSW6H|bt%>49on*#brS$})*vTXqW*R;C|h6w8HT}w;U|^Mbj^1W)O<8^ zg+s;P@*j0nZ!_#yl~ndry-wfR9*irx&Z6}^MVf|ZhYV+)@<8J|(8o5y)|#LqiAHRF zNG4)silXblf&9y3i&(!YPn4TdV=$#0@LDWij6=be%Vx2Yl^=MjD5*p!1Q{JR9)YWB zcdmLCFt25>q-4thpwivhIeC*xA95Q2<{>w)V8nO#l8E&{Y>M=q96higC&HV)$&@!OKy_>pKFKWSo34QUEkkBI{l2%uf6tS(PwWjpARU_s%^4;luI0A_qh42Fl( z@3EQh+`s?bi~{H=0I*Nx#YaGdU;oA1dy_8~kdLUdT_!ikLVbf4?$}Js>>+0K8)TN+Qs(f=DIaI#?dWZOf=ldyVTR6w>D9^is&b-i5=9h zdtdafcO*NkVVP>~lDZ`%H0&;kyi%7lrJ|xU(>OKbghg&G)V6q_Pod24aWb!cH=Kxe zJ>Kosmsuu2dkK@&EQKO-*j?#N(?l=&%2IMEo z{};l7s|2nuP4FrDghd;O{*Bh!Mezkg7pJmB`jlLXef7!eoadCe41b+d%4MjY-f{$+q z*2)Y|v5J8mj#AeE$Rkf1ryMYP0miny-O6I!B}QcHr*#iZDh)uQ!0g~;Z>0&uDn`~f zfXoi56`-@A5%bzTkmK9Bh=y{&1`HRdQp2(U)XvYJKPP50LW%{XjC*R_-2u5Ho|u>Q zSQ&VBsH`iX*Y=Of2m1TBA*=+zFo$m!ydE6d#w|LPGo8_GvD+zQa0(-U1oklkPsx zaZ+sSf83>o(R_&cU`b>2B5xtLhG z#j(-WJ*8xJWP7-SE0CIE*U8BdbkX##sz#R(;SV~-ltw?l*!1)It+=NSjdwyS?CDA+ zNE9RX`eVH-|WsfYYySZ!(t+sD+~+Q&B;tk&cEQSOu!-LovS*~`CP-lsu~YNOIk%x zT7^wKlq7NJeVyr#SH(Joks!)LEd5%V5L>)}WM+z`me2e#MFe(9kMF?Rk2R|)%ksAs z(GHsCe9UwdCDH@D^R zyQyI?xQJf9MTaqiVu(Q+3*|%uI59Y813{W#=~n*88kn?$1h)uK&*2ONdP^wEf7~zv z)g@rS&1pXRYX>1H2N5P@XaI3$<2OTg{d!#(y&?*$40U{L3Drj>4XGa4&Si{D9h$f78qx-c&>cY;`DXgm<6I64jfUB*9+@(P(JmKtW>PTFy8I@QgX zX{L^tH?7#s*p+P#ua#=3zwPe>l{+Q@3gm~2r_(cA{=rRlhr=72HX1H`;u*?J&tQ>} zl@iYg_c*+GVftpZwSb`+Q->GNs0>qckkZQ6`WiG5yO2+G8t@0*S5$Zmb0;kxK~ZWn@gkCio#i5(T)LyiRA z4ix^Cq7^})!v~7MU=|BxuKhLl@%Gn{p{xg>_((?r#D660M%PfjMGqh5imVR+nl1Qv z5aq>ZR{{FDyK5r{K8`>iFFTr#8j-mTUdx@N0fD4@$}9tnuyOhr6f5B%mFRvqwi}-)!oS>XCmP!>ctani#fVa8jZCtKZEW) z_AW8+ii8Z){`S=epFVxSA$$51d4BO=L++Oc`iI?(VBwm7P;oTgj~k@vjS})=8}h4M>lV-%XNFK6JysY+Fka;b6t2O z*PnwQz>L-Cr}u#1r$ih*&dYbQtKnFA7UuD*bZN}chbOQBAwGTe!Cvua$w+kWVE#WE3S8(H$RPi%e|C5 zGhTu5thmHEJ2jE8Ap5GdCV}<_@y427t*&XU+Z}JOGw1u7hm>Fao<02Nb>q_)$=Ss& z(I5&Lp@VhfKv>G)W7QTQu0L`Or7i#`57bExrSw6DC!ujIEG$ga!J+hOKRTS~P-t>g znH7rE#ziPWHaHKL0l1%F8CFo6=S>`wX=(*t-E*z<8r5Wmwj5Kg-B)~Zk_{(bWnMaY zyLNVQ-;JZD;^wWv$vr*Zu;4(KC)J!|<~xaws+?j&ad|sIBYEPYH~4KCSVQSinI(3HGg2NXE&?sIcu!h%E-KR zTL0Q$%hkMaf*Y7N970kBp_h9 z3J5xfZzh3c8mJmT9TuhO0f|s3ITcqNo}6Sj&!nfD8eP0L)6zYS-+5r||^L z=-?TE$|$d*;sp>BAkstK+in0Jm0>zq9ySCZLI5*vEgMKlu*E{2wlhoPF%(=-nsl_G zl47uxeA=*;Mwe?2p&@gaCn2@6_T_cH<%(#j-Q41-EPKJDJYxCEa_9<68x@%m>+pAH zBsu5Vg29uHU-2WjkFPn`U1A9N{d_*BuYi0A(*kymVHxD>J19dfko&W%hymwTAQ%B@ z!K?ysUe^f;LA^^p6`Ky~lDN3IfCooCDJWKqBm;QdK@mm`Dyvm-<#4yK;-0aW-eENmmu?hkU;o$}e8`dRs68e>~ESFI7s*f$~m zVganytD|~P*6(ilF)H0bm42Z3vtEs33e$8%#=h(&Q2a`;AHg0rVmD!40*+lE69>j` zg_;*IFt!d3EFQ0|5CL9QeYK=%CLt|tNrMIOPvEp$90mMb&`cOKEw&R@1+7CE(5MCi zSA57+B{4)%Di!tIk`qTn;zND}tFDVwn@&ry+!t1se>#jK$rj{ZrsYZD=mrY}?ycrI zm}I26ze1PEsq$HimK3e7em`HLUC;CArf0Kgy*AQ^H6I(@I;UPkTWT*$uzst{35O87 z?tuRT@@Is8?y!;D8I7^KE3ZS9D6^J-vc2H)I+8|M5J_Ngw>vM0SY|LTw(i<3=^hg# z?cqK$alY7*y=ohgXdZ0)idI3YziYE?M$J2*w!4CIAD2?zb?reVQ#xQAB)C0XRGJ`86?q%EZ5s!m)k5oiD1?Y;tBp!>jR(yu$o3LQG+yz#0Og0 z)SHQ2K0~IEU?|dbcRV^iOB_4TANXfv&Ag)YW%fqZ+1?3r1a@$f=TE(({)Y@eO$Vyf zg$ozJLyzv^!+)R_Y|0r$>J`0Txm*VuUX**3>xihm;!R$+b8CkFY?`Gu;SXekz9v&_ zO>31rQ*u=Sa{*Mnf-Zu^tT!(^pE|xgu`A&>=XHJnFXL%#TiJ)xb=GL!lJ4E%nk(f~ zc2CYX@Rg(~BqwF;Z`ky(yg6*8tkt7hOwpcZ77(ou1+n^Tx1RjMaQ_iogr{#rd>!e8 zVPVZCgLLz%Jt`sZ*}tgehAWd(jpi{?)^jm@e*GV{i5hal51#Lk!^#Oyf4@VomM{&_-H9BHVSa zUY7SK{5`%uDYpFP#9hY6N7fZ`X$H)3W zYZDX{Bp2G^$HXA@gv|G2^6Q&n)hEoT4x>KV)te+4%gb@W7_fYqz{*275_yHa=IAO@ z>v%)ik^U*IG?mUi!bt0w7A+8Q7I@r5(V$as-C-@OcifdNDEP6?Z8mg8Q!+GkwuNbd ze@dB!fOy??_WHiSuJf@Bx%b}Q!e*?; zTdZ15Eli;^N_P5_3hWGDa+Pc4bZU1vUIcWOGI8Sc|w$o?9P zq_IY=GkW%)Ck6HQS(#EDmu{;e_@d%(Z`|4Z8s#&jCAwJej_h|_%ZQk<9lUb<)Aiz* z3!QMu=w44r(@L_zQj{7d9_?Yr$rb0_H}B0)2)sOM``0w~3DM9aGz0Z#)cI_S=uUNx zqY}Imf=-(#QxEqB`pQvx2Goa#7gc`PdePX(?|i5?&gT@wi#=e1RWbxJFrzwwf{ z`p)X7)Xk_zF)#wZZE4Gq_vkHCR>!3v`Q$p8?612FV6fM0Q5u_{4V84PFw=iKE^mDp zDSdIw0jnM9x>sr{x8^FCdep9ZIoclEZ9z71%Gdji%hpi8Eyb_;vKj1$QEy&A`H5UU z>PkqPjEmb`IQ#lgA|dmi*Gt{)OY(4$9hD7eiAEmOgxW08L`GD($8!G#FdYk*O11 z+v9rg*AF?+vMc!~%J_qV`%6YB2F_jA)}4*h)2iRBD;)HED#DYBLodu!b9#<%>~pD{ zOJmR(5rgAmlBZtwXX^a^JD7FdeVLxx*uQpednm?cef)~~;{xf%?!VsnG(jWSM>xnd8TIXCuOE{(d>q8WVc`Rj&<|Pm(h@I1tXOm1p1*1 z(yi)-nCLD=hU?8Zh3%!(RMRotpFgukag7tz?15jyJbPeF`>VAM3q|6$?q&XR33$o z6`x=joq&3LYO`K<)ap)>VZZicY3Y#nc{f|gH!f_NX5qmJ_lQmR%HcHp%pQzA*~@|} zrvK-a$hLT(qp)?=&5D{KXhWXDow|;04 z-~EQSQT1t3`z$Cj>tll{)4kaN_lu#;bj$MN7c5=7FMs8e$$I%`_M!f6Xd#EHOw7ki!t?-{vo?!JoZc8Y1zYv>#^$F!MBg|{9cN0lzVZpbh zk0RM}11ThGSL19CNqe~yGD*rc-DA{C{~e!C>0Z~y{! z;8=JA5w9=r;8U2zJ)0#GXq!B0B%5m;A4r3~N19^#SO1 zcyDH4!=_?J_7P!~>?itw_q6)nWArPXpVTmMQLB}@%7dR4EjAC%I?xKfOgg(sv^x9O z%_PjlAaB^rkQ3jfX7&1b)23Ck@PT_p{hEdF-CLYba_B*kyq}kt_bto4f9E;s%aPl> zg{;pP&cN?KL`csAcTSJQ zi0gk?x>SDp%A1W9|E9}7Qt|mx{yH|=*9rBfGpz{QNKe%_-XXM?rJm{ZCI(;Q(l3Sp z?B7pe>hF=zd}?-61|9uX=1ZBS>5}HNpJqy7WYit=v<+6rYaXfDpT9ACZA7O!Hm|U= zIG$<5t|qJ>94H)|oCG<1zsGS}$ZupTd*A#5j(9io7xC^;gl>S(bCbUt-lu&W%!l7` zV74ssHtG78ZBmObP~MsAYNF2<124s-?(AXavOfM0$JqK}Xl*CU+?-RL^%jND z|NRMSSy3he)VKDor)*)*+Pns_hPo_5P*B#)g<<5j*)0y?0*y<2U0=uKdoPY;Bn*>2 zIp8j6KApyPszOrDuctBm^S8ZZ;dSwV{BKYt2{xGj5M?o!8O@L5>W=%F_2$rsDNPAs zi$?8~0&6glcWO~eg^8{l6ESt-lKlb;m&pWr2y*Z0XMr>2|GlvzH!XJ2C@4)lLPpYk z3?>yjtY9R$e5+>H;_CVSMQ&}=pUbv4jX%mWUW`;8)$f{puP(9jbKNV~M<*mzj@Giy zb2$x#O8NZ}3__R3hc?FThU!O_mZ@HUe87PAOzV)2#$QVx2?)t_vwOc5X$LO|zur`x z?2#?NCVeTtVOkZLMM&+G(rw)>s^@OUG{0N@H~jSRIlYJJS-ycf2+fdIG-$cv=Ba99 z2-SaX534z6AXw@DRKrMQZ^q_Ux+O@qe;B2n<9c?tQOYE;XH~$(^{}{EkE&3EnpFg| z$D-xvgY?$`)_i~Ur2qA#;CTN=DlAn8(YbCM!k(Bn*^M5K;ZIl$mqaWdj3@8c@3F6r zN-ou1_-gWXlT9T4%4s#>v05N`K_nhR6plcW32m18 z5?}D_z3_MCm~Bw_-6^)+n6lW5pPtpW3(`%^$CW_N|D{sR0UpQ7fI?i1%-pyud)VhG zJFYz9TGNXeR~|I(6Rk{{^hh4NSUJ}%y}^AOJyFUvI>~byIrQq@L%t93NuuRYARYd4 z_j1(3D^iGY<2Qd_1bnp`jqYZfA#Qt3ouc)$p%)v1;(>vlN>@gi3cKz~d;E5+eSJYC z6e$icvx6(Q-*WQSuGGCkOH9~nx-714aT_;Fq{h|yI6_bjm5aTE7%+F{=3BenGvBS%cQK!ybC5n6}K18`JxF3KwyB+j(0ts;bot4DLEdWEYW&7>FC~`L$oaX8%^Aw z1QM}brj56Vedzfvg!cJCs`wV^`!Xr%6|*P;sR$!e`n1UDn|kZsvn;Hr_HFs z-yeq3?}uvecI^8IccA<49bRCvKZUi&;!j!hZxjFD-R>zYb`3H`|LGN%aB;(%aJv7$ zzEu|=0N0oJ@AZ|T0lJ zf+wO4STUc`gL~HEE3?@CcXT0u|MfgNPsShC8CZeNs6SKrTonM zVW#@_TPpCyq(ZYtNmA)8PQttE7f-yeEiMH28P}P<`)*8-Xq+s}uYOj%k01sQ@d=REw8Ut3GBzC3;JfA{n?kcU}2ogu4MYyF)euKkEI zpT->{ZqEH_Xku)`uUFrmBwpSv>8eq+cS`n_e_j*p)RJajrz$DiG@C?`nnw{JbYJx2 z6Qu#Q_tLbaV^~M8kmxFA+D|2IufHpn_p(8}dfQ@zX-_HhMAW`W{O`cvuD-Pn>tW^$ z>84A*J??F*&jnP5+sv*_`t~7ByGEMXkYvKmx9Ob|y-&E+TJl7No_!z*u9r18AiNz> zEh6U1o!FE5@J+4sBj>mrz5n%F@Hf;6uzE$}65j|mXC7R6{A8Nr#*fgY(B6pV#74__ zbG8$5MjpA1=$T(eMKgMWQ@+>cuf~s7ht_1C($u(~IML!)21sJO?#@|}CqR`Ee}CK_ z+M<#OnvMEj9M?K%+K>xnqh)Vt_kylA;*$ruOS5tZN)2l6QQ4`^(2sn2XF20I)qO*p zM%zgmA%#a-iyiU#A@|w*OfgeQ%pM%CEGL`XH@|9@p5k36)E0Re5@AM@adgz$Q+gg3 zs#akQa)Ez#5IFS+VfF^Yy7l-ho`O&6aZQ8N?el=4SKsWdET%)A4{29jNLQ}4*s1YE z8feeW&*VSw@5AW75%Run=w(A(#6+X^ctw;+<7jJPowc&*-!}m9sq7*zMr`IN!Rd_W zgg)9Mtmyh`FZ{uYO3be{&Ix&S{H1!Gluv!hM60So40w@0yiQfiRs$v;%9s)FU$LLBV{~#aUhUeo z@UQYow4ku&^pxhKbPJ#R_kug|@nK;HE79E2N8u+Y2Bown3XVd>3zwN zj`DeTbJyLGc67Sq^lsR3 zzce1x)`U%{>s@`g=4U-;^Op_UHu>`(WcyT3r_awsn&_7fjSW7p5BM+#XSknig(OYv zxhhXp4=f3u%rjQ-iG?N-eNVIxGpkt<*-&`BNI)HE*XkX`vWG2=DTZv+!( z%5Uh3S5k7ld+ROYL-GYa3&UNlJ@2JSt*j`$p;vx3)z3EE!#k-W(w$>LX15o&A$!tYS(f**@LP?|Zz`%aR9@#5s6Kz&w!S;EnKE}Pjd(8TtqyTeWNK)`VUsgm-wH!1(t>rnbKJ!iMs|YA*a%Kovr!J-xWaJwSsH1ktzqH9ac5pg66(>)3roUsku=;x74+NQXiF{w zE>t+OG*{Q}lQYToZyu2sEp;{p82xE@bYm^cCYlhNZQ~6y#*&(Zhyj6Qg@HiTXGe5A z|7bgQVeQ)NN8FnWOMMn{mEqCuREMC{u^VSA3-`;gdl^MjbO^JW$sNPb>!J6Q!LC5< z3q6aWyCW~w(~#q$+gWaF;v>a-wzzp?f(ni=LrkfHw!Bwco4Doe_cia)g+}?M=bMhG z4t!n_Iv-e`e=I~^d3R1{;92ufTy!4=3!QuTK(xH2a?rgcqb+mE{329KSfi_2l}*xn z;y#aNk<=3|W>?o3zWOtgg)lu|(M+Lxyly7ktSqpM{cNU@$(voHIYGdL?87>>Bzf$9 zARBT|J3<1G=4mXwLF{0Y>8DFkY$n1EFs_hkWD}Cs_tdWxElxB`H_TvwqkK{+3rC?An4rRRe!_lO) z3ie|txJAzXL|4Fd*R0WM?-kCFE3e!I%ZMle03_}Kn9MquzLtlQr%_CPIbb!^tiO2uU08t&>tVNc$17Rh|J zVW|+id6#s_{v$s;(ggA*)r{im`AmJ6s66TG=Z{USb|;G1P87!o&m)bO8Qd>dGBeQ` zhQ5CSDuN>seO)=;=IfS^?~?s)Q~V{iUqaW>;=eqi;Qf?R#z@iq&o8PP?$J+4$6o48 zr*V|c$AiZv`c->eXH&fHe~cwFPUGq=>Mf-x-D znX*e0l5`oF5R&BgRWJFL`6pq_HNK{8(~z*RB5}%9muCXZ!sQEJxfyts<0Ci&72nv7 z8!X9VVeuB>77iepqmuOLx{0U$ydx&!i~@9_9Rmj{-Si?^j%PV95;0B43Et4=TQl66 zdaSh5m~C2U<}&}q@SddgLPv5vn#X}!Hf}qV&R3Or4*;D@BZ+~9mvk2m&7*zV*3#+K zuLoDVaB8%-&hU+fHuzJ5i%&&nyhf9~6axiE9di+kSN9j~ItBy;N}rAd({=6$8m-M_ zBJ7ZH=Pu5l_@b-mFaLfpA#4K!QhYRasg&`A0s3SI#ZaSFjgizYeWG9Eb@v}X4z1?9 zmeZvW{QTPQANTm|7x#Pq%&zu6BY4o>|A3q4Yazpu?V3P&qC&Ani9yM|H~ZT-JlJRs z!E?i%rkN8pXX!D#B?1TDoMGM9VKb?T{DFbi9@1=V7Js!}Z7%JZ*hf60FtgV4^%JCn zQRW(kM@lAlP1E+#yT)}7!#Zeu^QmIUJ$J-4o(pJbgPUV$XkY0Rbzf9RYj9L~;bS8` z&5hi1UXt;JYs97pE>SMR@C`{~<<~FT8)PsDC+9P%p)*(e#?mw1A3JK>UTtk+yv$yV z;3p-qbx$;%SPu@Ce4c1ViNLkI$KO-LA>+43Y;)%rkj4g}jf$NjxX=g{; zOKQzpFAS8|o9kh1Awmtz5_{Jt*4vB-{>Sq~f)_7>`{$fS#3qD$}P zFO2%;X<-odXPrbt>ue)#(&80M`?AEqQo{a4e4~9N9(|3@NGUk=meD%3C(f`NpMo}p zn}#nI;o?(;knv#wnKyLR$af>c|gIiKXOwZtgREJvYQymt7vU`xTp==UiciiJ);N&=~6}ZkS6+|0hZC-OUXhop%I(DZhr(00Tvq+Zy zqlWSudPT-if0*Ws^eg&vF?`>iNqylYbIfVB`Tp~Hj($@M$9(x#`Oa6thdij^h5iT+amCQ;_Y3xw+4fB~zv; zy?G;(Xuf-@%X@2?K-byjumSJP5Xon|AIQD1uadD>*_6M$I?!Sw`>UrJu|Jro93?*S zDLI+rnG9o>2ZczX(P@OSZS0WrzYRc(Ut)_r*ZE=F!(ri4>4zQA!lN~0bi3-z;r;sB zp6XGBeMp^7m@}g`?(##)lWoqy;=B@*y^P=*M&~T(spf&?7}(g@u=@0`&REZ>Ae{Wuhws4vkqq5)OWIJs*{B{z#+dWJd zW=E}Rb{ajqzTSDC)GS;%j?4-5XD>P@N9M@8Kjl;;B+O24ge0fxwB6ls=9DU7g(QbR zc2F?{HK^SW9`fgvM`Y$3yW}i{sh4JT*{C~~iItUwKl&B_iPhd@c@l&oclFr+H%XpE zx~=~d*4*ff&$hqswvyqbUvJ&g$`oEA$LQ!>V%#s*OfRSGStMNGof#g}m9+aU=9t}f zOW8tIp^HA|e&%yel#)&4-8^%E z*5BSz|L*_Huu+shg;gQ=%|V{U-gpVZ#Ja_4=nE;J2=5mRDd6GRDed0KRa;h8QAwPh zChb#OzBNtsy~2Au!_xJ2%h0&=yT2DRnsV#gjqaC1Xx7Ya+66BKH+lG;z#uSm5 zC@d>W3;e3tRnr`mEa^wYU+v#z^>4UKq{1`z_1R8L$o4glcL>*2*Da55s1Mke%P3HZ z%*`*h`&|5cmzu?VnT(~`0gaebCn?Vw_h@AsQH>tKzU;Ofo1{q(&;(OfQFw*zB3r}J zH?f_kwv4TzFQ$x6@4QZ+O4eDK+;XMG@}I9u3OaI~c4adYdKBDxlNZ-T3;ExwaTWn6g(xTCnfWa+tC6#8~xzDe@$MZ@2 z48O#{MBmk%ZlxT@Lz6)Y5a6)7`y{xSB!LqX9S)`sf9bIQG77_K+`ynR@l?je6+AU5 zN}uv}&%!-EKYtUvvU2;LWEL6O-0CcKfq$xtrt9p=dMfAqog?RBRo)HRt6S@|77=Je zBis+unSa13i2efF=DAbX0O#9DAs!O0;Qyz(>x_!>YPVxIMkOYQf>Mm2fPjTjKk14f zBfX3xFoGWu7%7SfMg~FDSdrqOD2Q~V3?-}kpShsgj^5$*r%@65qv+WubrT%iv ztB_MqeHkJupP|4>DAvvK6uH3@=EfFUgsS-Wi7B9XHqYsfcj|Yd^GyDp)>&nkxxKlf zs>;S_sgnEg51ez)caE*|-l3Xb@wl0>^hBV$o7?q^AsH><+TGm))k%ea0B;~Wo6-@x zWc9y-tAFTF!{#vjH>FfYSWK)XspOY0Iof<~qf-KtLZNP~R{MBW`Y>okgy-Zx!X9h9 z6@DF=%4YmOkpJ+zd*1JBB&0-NUeob4JW*J73r~_G_`mR#v!O^N`1!57@c;7^);jFt zPahZ<$cn74s%nBFi<}_c)Kazs`f^`6g`!pe_Wk>emoJ&>5Y%&2D}jFAr-_La?3w*} z7DEgBOLh2Tz&x>TFAo0rJD5HoIc5m_m&&Q}-=z;f`t7^n4nGGbFXn?N0qhm#Nb zi~aWhK#K2LTwI*Nx)7qUyhvaTHH*V!G5dz*US0(Nynuu0E;Jr26+{}Fno{oG)h(H9 zdv9T5lMY0f{MM~>s2jjSgFze))n+wy_3n4?jFt(kCtQ|1qS!s4O6~3Kn~z|xv%H*~ zDUEhHA|j%zw^uH!+2wmT+_uowb<-_H{upaudt!=rma6C}l8`RX8*e&O=ls`;bYrmR9 zX=4^(Ug9bqdSDn!$;e;;THKgyzJA{P`Q)h>Z{iB0qqP7C*=uM>cXCPrD>i7wmP<&a zLo-Tc$+#$hRl@u+acf@ofkJUx4(yc^)Hqr)?fqNwj%I+E0)vz6+27=JRk9KU@DPCo z%10$04kyL7#J8_CF9X1eUW1PHUsfYy_ADU^g`wx;Q-nR-DIiWxNlMbgKIkiffsk`y zgcJs1lQ}R<8^HI|-rj!Y@?}#4gR8Lmo8$CR^TC+-;rxE*Fm?iVTJ9f7^tDN zx`>0`VQX1XJ0w`Jh5K+>pg7R45R_|+2dkR$!kVAS7~q#am)M8WJrHU`@ z+7pNwBnN4J-VarH)$T5$aG!1C(z>dHdon2;fewmS$adO zbPlC7BO6%MG@#SFUno5as>lrxRo2C$#z?V3zh3<852!y~5v*;uYviW+T0ly%L9N}GpuZwOTs72EwWJpG+6|cfA}GC; zKYJD}#lH__#TjBE-@A1^Tc*g&H^Eyrz+$pX#}8GhzL!-|3Ab-fkCyC*q{2~iK?dv>wUf-$j#D2VE`ZmrfuS}Wa(D;H z2xst!LpQ5la%Oyw&&SH`9BFQ23Y3y;;Az17#uc0PTr93);gDrX6dC5A-+*6-8X4p9 z%dV}ty#RxPc!L>Y73$hn=m{br;#7f=rkj{Z(aI|;8;Qw*41lb0!%izOqj8~UhhuNd z`i_4wx1}V)l%B@xI6>hnoO+l8O^w?YtwNF-3X+nN>LWGUoOoEgCDb#A$HqdX&;Rz@ zv&WC)o-?a~yc&IdQ8ERK+5OnDf4d1xAmV~3R&0a=FwSH}14wn-;(mR7J=9+0v2H6P z)vY;Hui-M(U0cKg;Fvkm1^4fB@mIO8GQB#^EEp-BBScN^7u#(28_vjqD9C(S{;QTA z=8xM$;zm{-eP9asgkd^lK#npHM#Jq(7K>5!Y)=i%nOw%X{dWnT<`Q|BN8)NHO^zHn0%M9>8Nfsk>F(=GL9@<8 zV9hn1#JgHS--YVgTc?9j6ps6@=Vd__S#yG7f;B|OL9qqe1;VRW8>|Vx1W|c=2M04j zN$~Xwu*7+D=f03A!I~7KvVuXB6c0877RWSn%fJVD-(?Unq6TDi$?!HdxyMgo-LZRO zE_y&D<#1g*jSc*ztMW}SL1v#E>eOxAj?jyF|3kDIG?8-PjXd)`|HZ7-ev-i`5g+I7 z;c@-;?c0L|P%9yq;KW0z3Srg>8I|LpwYBvIZ|_O{rcl7s5wm-MA1vzdLCSy(LW$K1 z43#+5r>yuICcX1q+3YF{pVN6pJ@fslmDh>ydz+uc1qN#J1h-7Z*X z*(_L-p9nWTez%5(#)=0%5F50!v&#lAfcl5hIem2r{-2>r&pPUU-c3nC7^)?n4sOQskWnMj5)9Su9j|Yyci&LjuP> z$7(BHiI^Z#l0^#_ngF3ELqjq~CLkMfG>B55e2g?dd^kDMXUwuPOnJ|SeW^9z7^GWS zr9kfR$*%Q5qjm19Rz}d*Ds#=3aiiZKu!R0UoMS#TT zzDc(!vVxdGJ%nhbY49vOXh@GhAKMvuN6YX3KG%MF#wS2R-3oC38`78*S+GAtTaHWt zXi=ce7YhOFXKif;HXQ`cja~W z_9g=u`)Pc<2kf(1u6giCB&0)!A{=5LX|Pd!PNeU|;n8<()_~EAsk5_DrP1Nl0C98% zdW}T!5fZ+3?D!Pn)6v-(i#%)oCjOAJYWa(KAD!N)vp@|9=d6}o*9|l_w1u|1wosc} zTe(QuPnriBCn%OX-gyH-+**icL}NyA zem}764Nz-2lw&1B<1vpDB<7(_E2U|$5_9;0?!mz{NGkT_wjK$oWmzE0gm03e6&Dv1 z!KUtkfz*=e!J}dtr}Bv*cK`KPq^IxEqem5OifBh?o zM2?k<$>B&=g~i3wuuNM|K=D18%jHf@Pj6+9uv}l}o00?`v|!*Awx^1D!qsp=0MwG@ z7z9Lk5{wVfsohmoRfV8Vu5Mm{Kc#>Ufx@>#Kal{L7I;7m+6^X?spKSSYirv&je2hy zhRnc{K~la^RrS7d?qE&KxxwPv@#$9<;BnMlZxm7USV&W0`}XZfoc8_t@>rSZB&ZC_t+Epq9ZjsPv!0Od)XQzS=a=`^l(eK9(QS0XiHe>JHv}-@ospV%!{txu7$d zF4ifA97VlJx%KPUV_ke}5lunLc1lls*F3fTJiG#q(x(u@A(%HR)C-k!r;lBz?1iTx zj?pkm;{XU$Yf~+=8cI&jDCZ81jWr=SxCB*HRKU}?J}fT?oYe2^>_qY(d+g0q+JuIh zSLfyRRF57LxZ#L|hl9!hUchFGi z=?sx<@7zJK9SN^onFP$fvV$=2k&z$sK@f6rsd!!R8ts*T@Xb5=iQVOG6fOVm&QABI zb-%3OBE~`+>e|DDHDDP^fC>uA($51LplxmfM`j|lmA$;Z_3JFNOw)_TtRS7rASF4H zrqRD{A5A$u^VzX7xL_sR8F5vB3`_eziAA8m(;A?Lc4{lkk#26Wv9VENFc>>jRk@j& zW+>|+34Fij_-CjS@ALG`fqmzI7;^OeD_c~gTfz+X8W>n;YoCK?dMxDXpF8C^fs7V^ z*#K!%xYg^oZk?>!#7#-rtIi%d_>T=D5%UwNc=ALCG)pDy8IrPtr1gfszkhnkXLg(K z2qh0D)uui?hCi%7{rRILGOB*)ADbfh(`{^yw62362iXblWx;XJ;V#^2WGXW=w~%}f@^jaVKTkLl*M~7E zgv#tlA2-7Z+3yO^DyXRH!luc4>jth)UUejYCuRxKyb%yV&%onE4G#^~f(LCq+7Bd> z4ZOI=o*F8%-x5akojQr!X(aUxRvM^pF3%F=C|1;Sqr6mO(%>KjJ3cs?-F0n`>{FR- zIHNL3({|RZSvRL%5Dy8T?)yH`=7pA3(TSeTkFJI}Ji$aI7LZ4KXM zwET4uZ&>#rl^F+nK(H~rsy`rfdi)&v6B|Drt0*tGFgK5bLb%x>{s}d)f}9B&R%le1 zUeZrRK28EuSDCu+RDMg2^Lp_0UYkV@{&MkJ{Nq!29#6}lBUJ(!&lKQERwAAjx1&h-l3DUZK4zUL3svn z{#s4V5^lQ)j2j%&y@*d}3fv_11$?{ZMIp&1)KraedxTtH6(0a!&jsQ%x3`}}kFop8 zrAsyNbqy)>4a7Q-^rOrUl|XrvHD-O!?mX1u(?QpL{=x6sU zT`B0V^z$+puupKFDtwxpjLHkR*@|gw02#Dsz?6@mjHS$I&qluc^V+qj^wV`~L*bMnL{OIg=zs% z<(HO|c#Gaqo-GghjnPQjH()-Hq2+!|Oh`D~TbB^N?>MJs7EmY$TARg{(OiSik1 z-k3Y&PC`9W$4b9>{6XcHvWu21xdF^GnA_|%8R!=w5B7NKir|;a)0~+)PO>AUABz?* zZb0ps2!F1}L7MaqJa}OS>qyyH`1-;sVF?K(Z*On)@s4va%aGK4{g!Xld^Gz7h$NI$RaH?ww}#%EEZAnFgr$TxpZYB5QiSxd{bN>e%3`5Ur4Sn@&dBKSd$G;ZEHdl^)=_ z3Zp@*1NU&X%G=&abR`unGk34r<`N9UA^p1UZu?ef+tWGdy04F`#n<}nt-dSjo>tf+ zd*Y|{Z@-im&-rCm13DKz5Dmr>C>~f-{RuQdNW>KP|E`4$n-dSuO>&de)PbvRkI}$H zmnchJY2(J5jZQi9sG92Ug0{K5h{n?D9n5=0dUzTbYp^(VbFzorLA}L+n?xeAGKoJ? z6wQMO6BJ)Jw3+VQW41JII#^0U20mkEXc&Nu9b||>$OkqAFEits6QVj5`hHH%fU^3uIq0DZ6FS|N5@W$U4bih~*Hz z`Iif;#l=S<4uFjb!LiJEG;c}Gk_ka*e4uE&Yq;v07T)-B^gT4NbV((N96U~H1q&S} zn3p+-C8$vU77aMHoFA|#<69T+LqAOvO)1iXx`F9NO5NsOq1e}6q^h&yqR-^mVYC_W z|LQL-Tif;iy|HPH3(7SrbNqWJL;P7ep>%BJp#R`2pPyw=gv8`l0S_qN8&j z{TvWK%WT}3;oy~qVvuzC&CEE+^F1KVD6gVo1zNW=e*bv|(&HiB9HN$Hv8V_xHEP zr^g{2ezA6v|0WtslDZuZ-eZf@*NgC5kaV|!7n@1CkFZYH)4N1IB8Z5rLnzm6ZpWPA z8At~L{aI4(HwsqhChG;`-+jFdzvoQPg@`X{6QMPL4z&p?QdD|ie38mI(l(Kjos2vJ zvXKmYsXz)2cb*6d-18SNZovDY{P0*UScT*Z0l)pLE4_U?Ph<>Q4!u~EXf_0wl$4+n z!`p2@%Me~2o_yx+aq@vEI~(4~US2`L!pJBPj`v1L$XY}SG?J3A(QJ{B&`nT&DSP^T zzZ*t{U;d9|5wQM%O7Zouuw=+D;&k$T2Jb4bs7RJ*)k1II2dE5RJc|0~LsZKVau-EK ze1%Eudi{D09s~8Y?50g7$Q&0fT^h>eZg{f5SLW-u9E^o6Q*BTM;t?1pPmWt=knceG z`TKDn$GJPebc0XVH>3*+3(IS3hpu*%xooSbuQx~i_Gh_Z8L?vdPa2C%2il6~$;0Ep p&s@DO_!Iseefa~uu(4kAb*F_nCi!w97z;c&({24pPH*^L}f;b2D$n*DKzi=gj8r z(m$F&#<%!B?9w-^=kjGYEZ#Eo@wVCaJY#7iXanQ?LU1|xwC#;wI&SFDGr{9WXC6~g z)6=!uA>SWwrgl}YfPEL8sqoiLKOUvXq!k_27`|_N=RQ6b2`8E}TT;#E168s|k7v0U z=SGlwV^@NL9q&9}41-@TC;a05AJGb!dg6CG$o!(sy-fSl40B;0S1)fKUmmVQW)EX_ z7BOO6-fFV%?+NS=Pb}R;;n5fz#n+7j#D*EOL;2TN;j2d-4}3bRC(9qVKhbJ-z3erJ zpd?lhe4?8!`}5KaNe>Sq1j^y@bnJC`B;d;VkRCy~#wZn^Q`V`z)dDY-$LH`fI{IW*lP|=} zrT6T4z-M}y6vPAkgF*1{yeU++aN>p(hg^(BbHO}p_^N+=Akv-Xj1i?H^mK#KAf5#r zTiE{E#2-E5N6FkHUxs-;C&wiH#nv>9zOy^~wQYd!LO+chB2Ph9lJvRd$U1>OQSMdE zdhX9Kt?XpWUS`&qKzvfvcRiV31795G)QS#tY$_}7cy(-MoarhX7rgNW?jWHL47^V( z?*%1XLtu~w@$`haS$E}BEpp8lmM!v3l?7!r49w@}H4H@ysGz9ot>%mMhmajYFm>HG z%oo?)H+Pk6sR?-=zpEdbzZ`R<;jxjb_)) zy$Z1&O05%L-$hsax?F3;^=bWM@(*L3OJ$CsDy+FE1%2{BS%$p4e=hdDw=A%PPZ5wBLANosa2H zYe%N7{xVAoBS>^g-lE~<)rIb)TvIRWzZFso|0GlTTon1Z)C8FhW!i)ZXA{#K7Rc;# zew$Vo<;i=|(Vqzo{h+b`o;UPxDWz;~Jv){PzT=>OM4tsg%V02CT%Xa{nU)7{_gz3F zi|$rg3K=a+`6_b4o~Ko0!+5xg`di(dn!LzJ;UtpUH_6($0urpFU6TwWEfm|cbPH=t zW7vsHttfFb>2)W{+fKKn@@AJ|RJ8GeUvZTbiuJ0~sue_hyI7PRgh{{J+OjnmmQ}5t zB)&J&z9vR0?{NKPO!SXUT@)s;-7A9{q4lk=>*mWhW-Hz$jjU0}PaXXulQE8Zj2jJ) zcdM0lfCVGp3v11(^OIDpbtW|?Mg1vm2fbxUcecWrzSR2E)x}k(VQNA0I1#pv*+wX> zK5no1U^EgO8r{3h9{t4MhH1Eg&FkgJtQTGO4Mc`?Pr`dj)R?J#&yo#}?k)Sv@(4C) z4;K4x*Xyz{HUm6(h`7NQ`urX1t z$gzB7=gEb4b-sM1V=*Ax3>gR2YXiQr@o%&vH42$!Rasrv*Uh`I0p0o zvguS!AoErExs+%|2u*&~9(7+#n_sDE9vPx%Rr0zXnUI2mnUv+r7-2J#{12$WNS@8d zn=HqBfnioC0j5VyxC_i5C57%Li4>}G)@Y9Gpd-s)-D#9KQ9rV2>Nu>A)9V^*(kd~j zjLkfuK!lj!+Ecr!wDSQ!GW6Dj>9BE*m^}$nsK#yU@<-qV7&I6N3v+(P!HcHH(4lKU z3?lb`5!IFyr)fKPVPnPb;CyL`3`ee94R<@MdFl0tZW3o{>gX>2R!_oxeM5~msk%=a z_E*u$quKeYba^x~|J*WYn7+gt#HNbxe=2A~gE{T6XUu@on0t1i3J;f?q~NcNo14ts(|#!dROjjM$7dVcsn$kM1(0VE?-I6@~GC8aE{za~W)a`Y#Zr?NXV(}=BH z;zT%hC6%)ZL4<=n`khtR)F6 zxNs48`m#mc5bvt$JR)7V)D(E=(jv)0rkHW&oL>)t7^YkD&wTGW zb!JsQ>Gli)?tCaZrgV`y#h;_JWoda49P^9_j;*C?|K-rn98=1%(mc&;ftm`}r9btX z8&ZYydN|Dz5t@b!dn6=Lq2!=r13e;94t)yO!3+MTX6ljOFs#IQL!lehH~-`nnWOm> zm7%d=W-N+L>FP;3VVn`e?w2P>Q+xL0uUc?iJmCwkjQaJh0FYtS? zkonZq2b?_MH(R(XKhkwXb&0{Ez{<@#V`z3&@kwgn!8>okNxv;EkZ`!D;0{79lTI|m zHF%NqR8EAL&?hY1@+C7B=1cNJ2vXsTf1infm_x_zN#=v<>z^A4iWBDXLPfT^fE(`H z>9tO7*n?nhM7I#lK|{x$e8TetJe$euX$bmi`ExRw?+!sEvzZx~T-Fk?)8$clF%-LH zDyU^--SjkVyU@j1bap+s|AK4xmXj4JumR+r0QnP)gp93weTyXgH5UUeR&IBMp=^N% zDT)&LF!8Xz6+e1Dl96<;&;(|QtzJBZ^u(jEOKY|qeGv5aDL5MhOQ6$A*57tnR*m+t3{0VRPwXZq3lvIfo=4Oxr-St}m;tNSD zKgr#zttsHcSc7?>kVIC)W4_TsdIk=ct|-9lX8pwo#LHgh#|}M=l3uBZnOBp7$%nV& zbT-v4irP+)Tk$pR`9cj7sAPjdLNXu`9LrxVA@Q4bm=o)TEQ7scS@a9+pJj-5FW|LKhm<{1Q#AKXOk}Y8$#s!?uF1l1lcT{tnx)KY14O3A*styb#>jVlc8Johs z7@Kr9HFOz_T5MXgO5<#QS$k;`&@z5X_mcg~m9CqxZdoV6Goo_?uk-4pm!!-UD7WO$0nAI3+bf<~(bzAayw z{=oQmHqO&Bl}V#;}LP4}RV z%Jk+FJ4s8yiodVEIV!J;gQkW9n{NBOT-U-5a+W%=+TpN_SgrmTxg)OzJTF%v`@CufWDEc zdCzOB@eI9BRQQ~8^oQNw5Y{6U>@c-x+aHYBnXqVzpOZKaX%M7HCgSx&{Tg>6!(d7B z`<2QnjOCkMx7!Rfd8U(QhhrEI!~ell1UfSR$^Zjv<2S*iI(0_O{9GRYFc`zYcCAq8 zqzRRlGT>`b+iIFq?^G@D30tTf#yb$w9=UB0&)F7Qldt=f1}k*=_l>Fh?|CZj3Evtq zc0z0jTomcxMJjle$ft;w z`iB|Nolgsw?g*U@YYV05@?jl=d8g~+N#S&0>iIP@e&!^wO}usY{(z+w+p!|#)KK+* zEGVbVpEVA~m^1$h`Pus$g&RCNhq5WHcVy8CblxgK4lT558vEP18 zKE|68@eM^e-U8cfG>lqhNr7*$u6hF2ti?pu-We%IVqKV*4m>)HqLI#%IvS~D|LXu! zu&{G)+1Ag3lslP+svhmxKNnbYiJbEycQoDuUFRl)g{tjaY-J8)#w-X=txir> z>`qe*8;}tH`NFjxa*rx!-q3h~(AW|_!1k4D>_}tvvM{q6XXV$qN4(W9>4OkC0*~EK zrk2lH?1J@QiqwleJMiD*JU|O7&#Sma5zw8DLXdUUX!vUIqy0OWyUUQM>d_FzuC0}! zT9=UBVHK@dM8dge6Bfx6T*bB#zTRs))Pg;&vv-v{dN^1vYv37;VdPChk2JyOzmmeA zzDVs3n$dgD3}jnBLX2+8p7uJX@l-v#&%bm2cs^#8wod0i^q0`VBzV;3bN$;a|yzpZzuw26|W)B4_Bvb zVQrc-H0Y>imV<@rmcrmFFpWJqX9|r6I)T#6!@Q zSGMxq?zJ0^dWqTaHOrI|QX(LRdVOgG8zx|0vg_)7Kbw7>huRdxV7MGpJ=46`)9%%w zoE?#fU$F7O=o3Ptmv>~&d*4*Nf9)1}E>wMU|vQMgP~z z02&zCeu)B7eP0L$3{{Krv7pK$xXnrxu*Jj)8sNoCQEk3y5Xv#W22&wPM@1KG={Q}O z*8bbtsVEOACxP`3YV(P2^9WR8V4bkRhhbmm#HcMzm#K~l z(scd#2?93X&?1$ETKa1}f#Lndus(*4>|ujo1r z`no59M}!buKl6-Z_HeX5vQ!e`&|p@0nqG-ejT}q_xRvu!bH5-LqHVwgRB5Zo<0MpezKXtJ&)>(EijR z>FIH?o1-+ZfkEdXE`Qe_QB)na2)bu`DrW!Vf#6!@)iHnn^$A4rtNa1U$q6>*fX1g| zpp7rn=lNc)ql;MB-Z|O(ty>A`FhQHhN{Rtz;CK{m3jj`VPEy(~AP@q^#~TcknT-S7 zgmIOY7l-+afQpTZC^J9j1p<+Pq{W2QJXcQEy?oW?U*9hm=`%7Y*p^2WIHh{2hLORs zlt05p*}iI2sMo6>D{R{~G(<2oM$H@A>+3+J`76^p&;-N6sw_i6LWZJZpeH5xO_|+o z5(lY`swj~loFDG8#E-AF+~@iT9Zv3zzplAdZEuGYBa_TPYgFop8yFBB9UZ|BdN^^r z7f8lyFpG&POjl^vVL~2#x0uWxDN`?>6MP^#ot-X_WHTK^gc21K6PtTeeO4@7XQP9h zN&Wr<6%7rIr{e}f9r#4-R0xfS3kM4vxc9#!F-{zg=zkZ$IT2an|Nm=ikAv}yzTJ4C z$s|fy1@DY_p||wM>%*qbw_W1*;rG|gciMC^GBW2$pSQjJOJ_6*yc;ae!bYSJyC8u2zSzM;fIG#I^)R=0C?lN#h)|xi9wzPC~ z5JrcSIn*6`%F1X^P*9cCk}){Ko1K1GO28L+N(3IZLe|_C_2=g2FAIoYVM}I5=6>y}V8&r}+M?^$qlLIoe4*0&6=)PZG-ARTDn~;B-Okd{PGjv=?@|+5~YiN>_ccm#p~P`_{%{ zDtBU5QD|b(FkroPBNm_QYED)0awnSU3b2K%huwHpef`Q&K$D5cl|Oz20#XRe74Z4( zcC2CG|7hN5zbfJG&dJn%0nWj}0eX2o4=9n0C*meRW^CR9U#QfD>9)-C3+pj5`ZxCr zkywx*ysxKFI@yUgXU*#{#}|;WnwnZdMh0A9kI~kOZS{WV^O@<@-U#U9qspw6Q{{U*uc=k3F&K-#`1Dj$B%Aizc99Vp2~SKz16#Mr!F+cxR?qixKul87lr^Jy zKUFub#h`joRzU&T@A+=v)cr$#Ab11>?OGG4>FH_Ldyp0vEpvT`oKW~m^ z!%+ku0s)cdXxCY=Sp6X(BPZ8xuu(s5A4_G}J#E@7_Bh|b#KK~6SmOrt=k;R#sNWC~ukuUPZT#i&gq?NJ#s@ zmiE^@Hj6B$azShU&!_y4d&zcd&51un!>=Z|Hc_##zD-#4nXx8*|324xmXLr7XoCeW zmj8O3jh&P8YRNSI>uxL;t8p)6tK0D)U3GhJQJO*7e|$3JZc{PfNwuo;$p#$*1NdP@ z5Dg=vpoNda^}$5ttUV`wG&TbnEp22}6nt<<$mOH&_taFArd2H8M9zH3_&!n3zg{ys8a4Xz1xFI5`_{DZ00MLUa##vbUt=<)KJ;dGSD9 zn*nRA;V8s$(^mXDkbT`j5MaZ@!z7Q9g8;8AEi2yDKB}H6a9jjcUa;FbP$P8Fe^ST45LW52)FMe%pP4#n= zX0-vx_o4@;La!yMy`5h@3|N9IytTFUn&17p-9~!`U|P=aulFth!X#&9joCM?hpjst z7H2tt8;yRaZNKP6;J;fkT{?BIYQGwNZ}o3mSCE&NKmJ4Xegq&CB{z4vB(dN3PlmpU zs}5~QKN{o!d7<$f$+H;%oZxN+h6ZisXHnn zvUy}Kq}rT3JsT@3D#(j1Ei882+eW6Q4u6j^lJoIp0TBEfP#GZq8Qz%TAHpFuI+gT> zoiE=zLl<7$*HgWVdPPNQNA zh$Z$NR)--df=YkHR}%g&qo6^Y!3I(asP4bh1*>-W?x!mQT${dqKm?F`>=qYm+9pXv@gJ8~R>C zIksOy2Ymqn=*F?AH+z=M_W?QoIh-A4we5IH2#I_)4zIWGpW)!)Rg^xk`#(qFx@xc_ zBy)ybx*Qdh$p7vF$PQT`Lh`@g0M0YDG(F`1@9Uobuh;2(SA#yU2EP7G{#~B}x&!`h z_nqJGB0OB|_MKmE55;eu_Yq$}7_sB9;K}2#n6PIsoAjD78?)oF;K?zZd(9BZhRu3R z8jTU)HEN~;JvO|;pPsy-cKCD}Y*KXNKgk|EGQ7={pbCQKe1rfCs6cq*nnN1O`{15j46w5ZDvSqdWBX< zaBXHK&K&8#?>GPEWu>FeNd*M-g;5h-X13o6WiGPu@-}5V%2UG*@cw0U%(dBASykD; z>K;}UZ>S>#GSDeVl@Ln>)5f&R)c1Uy++Kau-T9Hc1Lh~0&}LrA&ck5KU?BHJMtLhAv8_J zt{##NH>w1j#ARm|StVxZki>3nD(qP(S>|<~>r1+G7EopRxM- z56W#S#pHIOLMdeoYB`~<5)DfnBs%#F3y%E5>-%ee@3Pbxh@m4yj%u9h81C@;Q5Rjn z!I3Qmi4s%e@XwxumHZun!b_+Qq1FUm>W8m(=J8r$ncogDNN2Z_$sFq>@z%ysn4G|g zg}RgS`GX)-n0n2A?+DDXJ@%iL*UfgbX6bmtK-F1wcKQL0s7jcAuO%b`6z9J?YpwbikS-285lIXnIna z$wYQ*(m%2W$y_xM_}iCo#NrVv(j_ZW?qRSVeVzMZ7n-Blzcz(swJ}s45L5*jPP**d zq|;)dVy3FSlE5b3qBD!(?=%mTv~v31MhVsgKTY3x=8Nn^G*TxL`4IhFfL#;3S3WII zmOiVOT=;=nAxtW^vU`NLUS}Qv4wjwE`!8qyJJ-TE}kV+3R008N9y*i7c4>?#T=f3j+`POZRL^dci(j$Tv*oSk5_|4 zy~6E-9=i`-X(=69weKejRaE7lwPLHg5wHs*us|%ZPSm{Qcpi0603OR2pIkWXYSPzw z6>>rc*BDBeGX6NVnDg7soEg;wj=CRRLC;g?_=d`ZkR!I}WI%U1$RCYBwZxH93qPpa1BqXuvAx!7S(b9+AN9>;EbC4En0v zc}cgi!%fetjX@*`C=8DZqinC1)nA|tu^h=*3lVT@{r)C0Ln2bWfC>Hi8m?_iXH3cx z`mH}gdTtiBJEY)GAua088w8X+A9`zwj{l#_>5F9i7u8p^nar~ zhQ$U1{iBgsYpB&R)sz!@n$4J`kBw>Q=qtGIVc}#G*1@OW4!6A7@{_6toS&&O+lpU< zh5KL{q#rFa`>?-}3r3w?zS900F~7|fuXyn${p5--yScZ`%MC~cI0{9%jZt#{6+3s* z>-F`lyi!QIl5-TpH2$br*qb~`sG|-)&GG9r-M<@!Zd zd-zYZw_MXO(3(#g9$pNtap{a{KlKc?zoeyoZP71zG!tW|ofbGkPZd*kBhp1!R9aW7 zD$oM92Qk91IZ|$GS=V5MBsx39`uX`Y*-2#ONY1SBNN>E?Wkwem^HDDyEd%ZDLAj%` zS+z3#%b^HWTsmxbz6bW#Whjild8~o5;c>g`T$>O-%JP#AbG>ts@*F{1X zKVo|Hxb7r5YswnE$XI&W|8sQK# z+?iw$DY~5A6s5T!DDCj5Kv?>p+->HJkgaDI*=(8BfBi<5c<;l|w zIVT&-pqMOITGG3ORQroZ?dN6Qe3N`DJ3F)6t9h*o?65dIkp#*J4!XsyO9C%b zOB4ztS=Z#sXGpvjCbTs>O%LRyabCU-*!J%*#OK+H8hQZ|7KV`nJKW^=^DTeF3tEgv zkwEP?3!9OVv0y)bb_OlS3yNDz(T~cGc|CL*ntCifZf4BF!69u=TeDf&*zua^1ID!W zw#(Tg#-ueHS%Xc zn2E>Il+2ez0qYH*Q3#@t*5U8Ve@}g=0M0HrmHTB%d^iH0UJrm*D2&s z4O4wSPKhFC!KRS~6^QCX1C97)?2n`7>r{%Eg!r~|%ft4*5XBr(RCx<--Lf1B>W^QS z!*u%BF890FkAG*oxQ^CmfQW7P;!FN~4R2*bO8j=kF=6aoY^{Gwk2hbtqJGr%z{c8K#DWivPW_$fI;qHuVT2Eq);1d3 zsAEUW$XGwagQDj}Hahv8-4Bg`;w3|VNblexf$&(<(dhLbQst~|nXOZsjzT_xfu)Sj zXIkrDl9he??%Vf|k+G*UybO$jaW8(4bBl}b&qDz!BFEQr4!>|x@oC1H`ggC4m~o`e zQ~eiA<_B_vC+sZmdl<}IkEBIB%i`>S#LeAAwx{di=J>vu=J~Toh$$fP#^pxtUP3do zM!itL_8wi2O4^?XeHc2DM1$j7n#)a<4Dw_QRBfpS1-8CJoisN;< znQVW7^YJ(>dQW&m#N$j*6f%%L+gK~W7V7B=rl2hnEzn@+^>9wh?u^)2>m6eyl zBA^sF1(1Gwgvu6rcp)Ec(y73Sl^7j;^K;DlJ);5=IsG}bCRjco<7>h%{*1D9>j@W+ zDCE3R*KHi#i*9NjV2(_bm-W3=j&L1VpS_*^nF{Bp3X2ynE)!;*OPCkSF0b24&Yb0& zb6cNAhm}#?>dC_m!}YPL^Jm<6{tMj=pW}{#)c82-7Vd-FZ`CYLf4{U7F*R^BgszC{ zo~Jy>D=?1GN>}K1#Br1_I9(HR5i57D8&l5_jaCu1>6VQQ-~NhDxB{*;ijTYO*N$xSpES*yD+UClMzm#< z)NGBEEiR2vPz{KQsd-uP=Qw>mghU9P^@ZQ%kGrf0N6EK@t|+8!yy1aH-R--M;$$uX zcE>%MJD!< zIeHcbuk?2z2Ru-X$R|3K)e zc%iYRZ^SN(isuLUZ>BWEbXz-@pG;Y^JRRayM6tmt^iRES&jT;m5$C!k{s;c#vvPp*{3(x)m82IS!jYqCtF`ye%i13Ci~G za;82bW+L^sVFby9b-pY|=g#dhdBdb7j>NGlyiMhfM-d`a_32S1bnw7vJbnbCZ_h}^Rk?IpK$8A zcevXoy{YG*mNyk*VKY_UTq(UTVYA=uD4)v_`X^aE5xXq=zPI+*m$RPDuW#Mgk0Vnn zlJOZvvNZYx(tDaGMV2N3emEa80#a!CjLHKe-it>VlU>u*0nRn=d;3#HPGKs1ETkg# z)_*JJ>$n6AT)rEIE%y~^r!^9&=JE4fff2*nO7lt*9p%OPukTtN9@F=$(1>$9=d+BB#x8FM?w_)hbSd6f?$HcS43`;?C)3s8 zx`h@5{8kn+&{IafEvFri$^B<-9k0-8u)IxF9wEUO#5UO}CAVS)fc0o~l!xJ2nwP9K zmHtVMhWeMS4m|mnhsN$zE3fOh)#LeO5$Ou@0=9}$N`cI$|ASfU@Nq`Pq4yx(`^T0C zzqf@&?DB6xqA-8jHY2MA^_#p2wL5-C#6?<+^irDLj_2!YG%2XI5E-(KB;o>PTGQC+ z*s3z(7aP}wWrk)XZ^X!m>|?Uv0>#z)*Q1B`%aDr5OjN+TvMr`tLxT}B2sICNYU->b_SoNf9WKqsV&UBs2#&-5GDaYp z5eWJ}8Hw%Pur6|H zVjQ~|b87S5#OYlY&_%>X4*;W%Hm@RArH(%3e=@`g4$Qx8ODi#m(r}bsi z8Du0|fZm?9+NNIL6Ht93!1n|uo_+1eSh_D+sx$_L>hy9e<;W6ykoTniLGGw_Wb}&O z@blSrZ_{qH!tH8(CWS^Mbm~Pgad%i90dfsK^L4)U*zfbiB(!Au#E^j8?JJ4}{>KFX zF0EY#`y*U!_@--Usgffra+|CbM zHR$_zzod6uUqxGI7?LIQ(I55GnCkxP)_2P$wanZ9;3%l5Yb+NHqTr(+mfv5px0gRL zm)+BRlxrXZ-zV|TmmOJum(A+s)~|G+=ev{LFt}vg*#N|Nfd?GH>gvA1?X2JSH*y4W z^&QcIu>W=LgBWQvYc%?Mm+dV!qCZ^jk4tuN3F9&)`T7G#+ z0D*_CIU5(<sfd`dsI(?M=In_7eGUQG<8S9x z83V%yUY9rC@TlMLXX)NBhbX*xo9|xOui-Z^M$>J?m%Z(WUiY&ekDl8z3(@wxnKLUQ z&SM_TH2Wfcu>Y~ILVac!m~Tmh0fIc{tJ0BY--<$z=kI!igsl7=ShH|gO<-AS^_z`u zptOSNapWcV4VZ8coArrA;-+hhblssfvXBBF_B_`ZJ;I|yRuA(_snY7x4MJgTJvjl8 zZA8Vw8^d~aFuBxpWchsjStLFg*5;f_F+FD5s{i;J9SyffwCf#9;OWL_CB_gP9WQv9 zK&-9~*F_2S_7Did6vBifCaNzQ9xYl>9yjqg)>1m8UMS(Q2*&sy z6`cm-k_-|lCYJ>Dj#f*@{fnDlyBv%b@0)fw>(%AZUYtqubrdRkUQ@@Odsx6_sR3 z6*Fks=?vcAfbp*cp{)-ZbHH35EuOQGxFJR+uJaD~3wSP8KP-1Nu^dSz1F4}Nuj|^^ zLk_$cLU*C)a+l@ou3%E!H0HAB2jmW>|C;e*deRjqNKAWb1psiUkfm4nwdnD=}2JKrI2-Rm-g~Q zdsXrOvwi=oxGXHR5E2m@Vho#MxBCskb1iq_etn_}xhsAZUa+8$DsOsOlZE>fM&|6l z0%>!ZW16?}ArPHm0!AB&x{WzHmg3FfgJfQ*A04(TJOlM&D`7?(ur`=J)vxZV_coE-Q5LmN$e+Z&Haphjz ze^VjZ15s_R-3pCrkCE=0JuV5s`D>^GmA-%nDtdEBvV;xl`K zAfQn|BrH6a5%+_Nc$*G%mDB2?UVbd7Bpkfap%+zz-kv;wN4N+ljP$C%mef?A&}p1K z1_Ji*H-kBS>EgS4OGn=M)8g07ww>0o7T_H}%h>jfwyU|QsFK6A8|_@+`fB#H(SOti zVM)I|GLW>pv?B6GktpsL#0Hzxf1G)e@BpI&7Yk2T&59nz7J;U8azH5{Fyaq4S#TST zv;B_+Z3T5x+MvL^hYQRkayDjM*BxOXM<72U`sjN5E$KY)*t(?Ews}HW>pvyn&8qfT zLqMe%ChImrPs@y@1oOFMT7r$?0A~{Xl4++v4`hcjSE&yP~RP zITHy|#1~8DdV>qFez28JYD*itA%DX%#2_M=NVtjSVX|iCtdsBgPhpjay!-t(WbGY= z$*J@l*P@b2TVC*JH5@P~K!~Io#|v6EQx{W&sGbtfDGzHcmRakxAQNp(z+FtU^2rV} z!2tTQW=|Bz#fm#dQDxUlI?Z7mK0+iw^W9kvJ966^QkMXJ#(K+jQB^N%Dk!Rhz13DK z{%qhukShsmQBt%v^8d_4D*Ps=HHg~|4S1Oi+!o|-lN7mq^Huc-B&ov+X9xxop`HUJ z@q0|}j#ze1P1Q}kkfGI>b!=%BGrX_HBY0r|U1*OW0TZZL%y==LH-^uW80?sIrlRt1 zLv_fdU==AD$zq2Sw4nZBs&S<#>m(~mpZeovmP^Ns8#z6R-^de{887`8$NQc)c6|qy zb|Y(tAe5$+WXyMkWy)MGpV~upP9b&s;2OBuzpn;3d1YC-F7CR{&-}INHe*LaLl?Jk z#b)_=*_x#Gv6clkV~_v_G^nP;mCr}Esg}o)2biQV#);+kB}LX!qgVZ0i&I)vlNJYN zA-Ce+7e8T`H74PujFgVUnGM|z*l0Mq{6{@U{0hghdL}1d`Kv`63R{@ycNKjeG z1Gr$tfsvgssaA+c4b(Ryw(u_{#Lo0z>Y5@g6fqd5es&p9Q-#2VGh~p|m49QUF7LG(IOrJCvFcXZtTMT4zknMTLZ%P)IIG$4NnS z@4Eq0HCaCwB>4$9HIDCpPON(^kb5lPdTa#0Kd``fEcrZo`Y~p9DCp%<>1|MDuFJFg zpqv-vD3#}=|M5I&bUM+9E%^Z55-MKyxW9k6!wU5w>u!=gkAeg{RJ)!biwZ9V?wrlE3JQP}t^X{FfNCMV@%W9IP%z&HZfJw;f_pMk`{ zX`{KI|E!$s5b}EY^RNwaakM}>V|bVgUqxd}=FsyY4#Q>a)TLW+LQ)R zW+GQ2ID`OFSBH@w4jGI#)-$_$m3i610*wu#z^kw5ENp zWZ+Z+Ttr$pLSQGy4*%iKKfQE4p2-T0z)T{WsmZYC1^vg`_p%obGQyp7DYhGj$%`K$ z`~f{=6Hzl(W26m5j;+Rwt$*p5`UXt+cU{1Y*fUvhq+*$(iAzRvlwsA%Zu;7<6|Jj1qMSjB=*B5wOdZyPTT~AMMbnEWJAX6I7fJi z!iy0x+D$Tv7b?N1T&G9%u_y71XxGQ7QKQbdQIsqlGQ#2|ZHM9kXIJ zWld+nmB&G{7?)t9O2#edaV>p402od?w?3CJ?GG=4zF7&%hyfjXT|BIT zAYs0t+aTHc_46b-X^{g+NC9XGRu@yFu5uQIhnjE-pvD43v*PCF^ua+1s6wRWQ+IT9 zbSXJGvzx!u@KP`u`ug&wrsNJy_-SKq{hOxpd<*>Ht1;NoQ04R9y?yxe&Dh0rO4N(p>t`JWMgrcTEdD;n<%0Ysm6;*fXEW|jLH*E!0i+$pT(J&oGhxQ_QClA zNShTJ>)CA#^NRo=>&eN>BdM#an^{<}dR`bMB`0GMBqm$mWCX`G8}3}PH~&MqEwvsz zyx+P6gre`+?!fO4FilXJ7QcNkO|G~2Tv=j9tOo4>A_=o8r*=(xFf6MMbH+F%Zl%_Q zhTI?tuok-mRFO*eU^(G3;J-FG?UuR`nA*GZ#iNHuN68o%VnahA0h$qJHm91N-uS^p z*2vfxIW={7BnGwfVU7o@>t7|P5~TTs1r=pwVPM{gg@r}!>;KTO?l9!gl;_HNpmk2@ zz?Lg#@>gpXAU*=@Lx5qInVybgVq&83&&$)Z`LjMC;FW_Wf5{Ec=wId!oPf*q9JyYN zQ0FBiC-;>q7XYlc82^ff-DGIPfL9L3j$7=EjEt9ya3KnAZml3R9;6eE@G~r$D+WMR za(RL|9~8_#q9`mb2XZQ^s#xjnRscDdUavU;pe81bF}B4l*I8mu*t;zZN z^3&4N78VvJWM+EzZvre25fKsB3m{w$TbHm5h=~Q}=aX&t-Rpbb{u_Wm;SU@!Q&C!} zy|{1+Lna&rIAvN5Hdp{-lXX$g1t~Hz5*|p%vN^Lj?RNkg+|Ix9YAPWi!w#?2mbp2# zvyOWMhptz5BA*i$z_WXV-Y!u93T@$*FN~L$*U5TYnt;z8Kr-A|khHd@1t{Z^6f6KQ zdh>~&l=NoPGbQbR-I z_=EpeQ9(a5JL^^h1pi?V$2J;BGUqBfM#c{&;^B-elX-U_7~n!C0AKfECpt1FX0Kt< zU>8_6K;)DT0x3FSU;}OBw|F#m zt>qLE!0bL+tR{Yax-D?r?5v#Pb58o`w@eaIdW!93AGq=Y_V(rlgdBs-SDxW!(5*@`_)Dkqi#?b3h`u( zaUTw+9nN~In<^?$+U(KDTtp1>oF*#@{sj1uGH0&f5YUJ}T3a&}1s_ADlc@k0CA-Rz z2Mib>mg|hpmO7UStGF}Q5SZke0smH<7oLboaI8^Wina>G~n!0o$C;p;o;%G=!Sropl0#Du>#okxX1+DU!0wPgMWm0JAkWAZ_u6& z!~&>-keql0Ks{BC|EJy|zgE4pT= z?|CwqfV3S(3$D~p_m39pJFgeE*Nq71y6>yD1(Umuhqb_+oNFVsoCo!LT0uc5@061- zoJ}3KZ3&2w6>t+?7U+QtTkSRrKsY=lAE_sO>ad`YZ^XTq4P5q?MHLi+QSVVxPj^Cm z<^E;Fz-=->dxury*UEtzESOxp;9bz>PgL686>{MQn}Qo?&gEhr20?7f*-@PFxyCm0 zQ;L#~pFbK@-mq?Ch5GG>8b%ftY_Q}Rg@xOJ7OrrZqd`4N>3PNh?+{2K^bN%Of2{bv z3OaLwHuM<=koK`?;WJR7DSLPbD=8^~pp=C;PR_}R5B@-+0TqkF7-Y|mo*r5r9@WNW z0|=s>U0tt-vQ^1FbRmczb?aUbe!FtEu@3ya^|3`9`3Peq+|&_}!HfS~0jJ&F;Fhoo>w! zT$$*ltdn3 zI7Tjvk{x! zUf#iCBSnwH>gmEay(AWO$BSVa5VMXI|NQxbY>ln@OJPU21u~YWw-g0ML0X=bl_hv_ zG*`1ftU2L%d5-KuM1HD!zN(f%_z8R*s1H2OoGy;qMdGcd<{}&+F_v#O52QT>OM&6p z(Ke{|Ib9FTV-*-ibX<|t%y7H>bgMpLbo3<|Uc1bel)3r+!wFk_NC*p%>kS~v($dmC zfTRuWpgjo)h69~n!K%bh1Xw6x0H1CJ{vRd?t8n~a2Y&&fH~c^r4pLk*y;Ho?A8ce{ z!2B>;mKw4H-VAciP0$(3FvZ0s_f1d>*b;Htb+^@0_Qr=+L5NNE}48}48I-ckI zh@I!hj~~wiT4&$l;^NW?2%PxsKIG;mE3OF*4ITc}0T+4%4xX&<-wognYFW4525In{lo&WN*0=`Czjqo8a&;rCjAPpv^+cRB+qK)%& zL9$5ahQr!oXWZ8z(^i1vp!Kwog@cK8?b>rHfvkdp0xl2T@WHnmWfk zQS^I~Pi++3q>(HUt_P(F4Hh$mbG{Ax-{Tby0(glV@^pO8pDCtML)zjy}+jH%< z2&%N466_PXJR8($i_-PLZh$m#WqG`m<*M%$uW#Q-P`bLiLp1sfI7@{?f`VG164`gb zMn^^R&EFYOFg^K%v0eUs2$Bs1WIB_ASHyO)CkaXcI5Bu$D}xzmtcTaLb93o#V39d$ zPdhl(-Qrhrp4RD~P1*&gmps*th7AW>crQ5Y4$9W22g31qO9`IBU|E^#d$ctVE`d46 z`qMaJ=&4eZ$3ph}@5e?5xW?2gZRj33tj|PhTJY;HKqmIhh<6Eq8+fC5tOo#;BBV?d zMUivv5WyWRSkEo&5hO4H3_6A*{PWvK5<#cGGPtFY;EMnkQs4REbU!RWG#paNltO#b z&AL;Ii$l-LD9B~oert$HZFwk%$g=L3{*7(7^xlUs7Kj_+QBk(P-|FDV)5fYF*2xejC9q zkA*mO|78IRxcFLOk>ImmznZR?pdce7vsN^nRs$;*yxT95&`#+|7Sr1Xx8||9I2!mx zX2I2g)Cq9K9{Ck3O5Cfvo5R+B{p}C-}qxNz;0~>*le7j88|0^c48AQqsZh2w}sfr3ATM z?UU~csp#c0WVi9)+-_hLtd^sg#2fi*wHiVU&@7}$eD?W7vNgjsXk@|hE zH5G_y4bE@u_DMMyTi_$YC*FarXbpLF#TQc1z(0pYobpJA1zBdFq3)OhPPUDV|7!XZ zIItc37SK{2_ACxmgpWMQ+f5wL@xq^i-z;4rt_$%o!YOcG&B_25%eaz%yzb@6$k{Bu zCm%~^9M?wWQvBRPl&u$>B#T8SIt*p2L$WaL4&igD}v=wueAv`2?7c6h4w=K zoh@?YmjNdAo`+v(s+DwfeFi5VTa2;MxgcoY8c!3wnX|1Z#{jhInCf+FwuCBlc>k(~7^5YKPfKgCtuW4nSUjADPH08%CtZBsGU;p_5%(SU!0Py-`c=}{BCvqO!*<8I| zQKNtYUWF^D>ny)P_Q*z}Ee~pW9A$>#b(7ci!b=;Ak9ev1G`w%DWG2j}%f8ss{*^V3 zY2UXhe#sJhw7uJzhjD-U9B*Mi!p@pDdtf1uf8rBnVtV@3g#LC|(P%(h`t8AnGY!RI z#_RvpJ!Zvx=olE*aAcOfjHRyPk#&IQ(S0ImN#Kj9?^OT?T;`8B)B%F4DOl96iC&8<5k7f>ivFZ(kD4`{ zHuaYD*7^8Wh;NuQ>J=J4gQ@(HS{qFZBL|0rqVnmuyGb%Pu23X(7AlQ>5;K0yEo;`5 zBb)Ur>IwlZ0k&kAC}AMg1pNUC!}cT#mLpScSKiOfn3Pf$=QMS~h@~q81_Vq3;t_ny zL0UF8oCN;!!As2}BT?bugphwxY#UN4Du{Dmu;6{MYHw+48vrOabtV6v^+un7T~;^~SH>Wq<CP#-O zbpu`W#<$Er0jPMi781DyVm{%K7H{uPUEC~T)>Ptas%H}tLbwrqOUn=yW;#K^SYRIr z9336I1%S1I8ga8Muz4^PDexdgj+{D#knuN#-V;Z$waNwWC;;d}&r1)W9a@AACw%ks z*sSka&l+373u4q%F-H@c4#b8zZa8l{7j3 zxHj*2*3C5SVhZXC8sr7?6W%S;g)hcuHb!HYuCmTIS`0q1lB#%nhg~P|)2C~-u7~t+ z>EQNNxweVY6T=(AZ@UO`MhWlpUcj(&U_`XCwtlrfS~x#HkFuCJ3MICGb@iizg98M) zLMq%{jIk_&i$~5e(iT#{!`>grQDX<-FS#{U3srtPMDthy`v8FAuenK9hI2{#`uYGuQ-yV+ zFfuYyad3QQ)2`w^vB~}Zofhskd|S{hu`+-Ax0l`_dkMMJe?Lh+A{KlwqY_Y1D43d> zhK(+PDfG%au~*JOU8rbYtmW5p0&4&U-}lN{NKP~8{l){;I2?-RzPLx$4i4#1i3LfD zgHu1(gjJ*DBOteE2trBE7(=@koSd9ctWNe!V7>dpnVyrlADTmb0hQ-q*;`HFiz9vO zKiL0viY&U*|6P>vp6tLw<=DMqMy%O9#26_iE{=_d_XbKE`PZKI0&xqs@7`5^>ntgG zRajU!(nL*74MGm^VaN^dpb44T*yv3O5q6oJ!D}d=_IL^&c?7BKuMT-t#z5%uh$$#| z0GOif?0A>d-kDvqEO2H<559?djZ-1tEOHsMZ1n%)3|t!AV;6dN{wN1|YD4Y*7`(k$ zVRsV$C$CMk6JO+jA^e)_!Ftw+U{ys0Ra7_Y%F*fR?(tH>bmR^;KE4s~CMefQAATR+ z2Xp5#yciD;5267V)JNS;92trUi-==-#0?T3Sj}S$;sA26f!Q5N%?Q&9r;Oh9qN=(& zEHd&3t>>s}-z(1(BfyDCT2DX>InfW7?rmb6U$S2b#eEMl(QU<$wVe4T27x;0<0~ za9Y`S36!LPHOL%VrPs6smvt}vgYk5o5bQ9dFpW%n@|@FVUfSb$fhd?#Bv>ck2tEYx zLO59}vOtM!Zf<6(FvEveFSpPxwaraVMkOUB1wP?riSf;}v@|jymvC^2BM|_0(C5#e z;nd-{y1D{Rg`-)5&PM7Br7DDFxtA}Ap@drcktFWt=l9X`IQ`f8mO!v!TaHr5Fo&Xsm61i)BB;L0Bl`@2=M8*B(<&`-p- zU1Bo$9!Tv7;G__{fY0QV|{f1v4>V?!jvq z-*9wvg!rQ`4(l(i0l8cKX~BkbWitHzu4(D`js_UowRJ7vBJ|;40cC|@X=w>0*II2v z9C8A%93!;|z2W8tDXGa#WrZj`!qi{jK*?&7BnqI?zFuy*ycV!pXb2p~j zOzXnc`DAsUmLSiR)pl;5Hfl+?mf~wDmBg#L4|#ld#Z|A+YjY4e%C%e!C^V!goGQJ1 z*};(D=2KkE#m2^a(F42*f-WyEE?|#Y0TFYPoV@pBe+{X!IXE~*$Hr7o0~IpnfMi1W zzr@5uQitaU5MhcPHZI3iwv((y8XQZqbSpTB-JHo?73Ol)i-S^`A$pSiih!YmKmLtsX&mw(&?qN^G7s~@2;fMg2D z5!{wju?e0R(Fl7Dg$WQt>ynNaFV)qzp)A@)-Wp!`z-;)w9Q~~jp#x&%)(;Ks=S}3Z z%+36w6%m=a#q>z^>aJS8QPtUT&IpTwj`(Jw^H({6ryhYP zHs)?pvp*J1j%p7`dtvm4F*ixWg!@Z?7ddMAlJsGdRtaG9e|2_#E+Z#552FCgf0yBA zsdT|egm$2jfFu$j7Ix!90neRun)05Dkb;7O8_Zp>TOa)l$6tpx$m9IvXT7H**`de$=`;3OH_FZ-CIi?|N__ zMdW<%79f(21se+I`I~Si2Q&NcL10A^DeS>fXyqVXI$(BRLzf7FJ20DQgy}CMHwAEV z-?ghFfsZV*T~a`h19WAczI^$Wk?h~f&;NICI=l2yocR|S6mxL&nfe8oQHA86y*lGm z!g9QuCXYgLD4a}%o^&&;>z8zdgT2nB<-Iu4eD*9uckKB%jX)Jc#j&(FFTz|$zRmNx zCwbQOvks*itgWr~Yp4fXxmUjNm|cAg42(cr-Z<4?*|ehZmy}S8r@*c*kG z5P1a%6+n+YvHW2`-mJd=oq0`HR~M#c(4YXH=LBpjl(DYRO#WV`18)W=Wf9i)d!$rY z=M(4+DGF|*E3fDZy$>Pb$!>G6)PV26x|NSU3_S~;=A^?RWZ5gBsIGnE=qQz#hkAy3+ z=l3qwt~I??RwWKe64WMad7E0`(3;8K{7l{EnE34W@|6h2MEZtt8WqAO?NsU|zCn5#Y0kSvAXQ z(zx>+>X}_xSG>Ws_*0UI-oItb1oik+Y z-(qN-w5yAx{UiqXQJ3bknbk(!joiy+7uG(tlV|8 z@&nXUH*VaZ!jb(~f83n8>Gxa4WG~ryg1uc6tG*i>Rprl z#5g-00n9N}4SCM?n-kHH3{I6FOF310zT*RudG|J9;iL;qn0qMr>RMdn*h%ALx1}q91PX1J`bb84`}*>D zaQ&Y&!5&txu$txR22xn(Z52dSGGVu)^qoq`uNu2CWiSM&rtR%KWYm~C<;{MLp9MQlkVNh{#g*7xhMp|uf{i1MrAX(}#;Dp{zu&-}3E~c{% zG(Vt=l&qTb0_mj3DHy5WAtmjGS`T4ppvO(dZ{r7Lw~{CZ5`{C>fEr;(+A45Q058EC z>1=7wJbWXY_64}@pShalrn_NZzT6l6SW&?T5%w`KOmL}CUC*tpeF_N)S=fp=gm5U& z#s}-$3KBEsiGap@_bJebkglz4ZFBD2C*^pJ?(OYOtw)cnUXuv*KiWn>`5kU> z<6tN=$uRyY{2w?bC?M1UddByj_+eWuT4=kHJ}BS8#>OtRyE&MlNEr-+q9#%L0a|?S zGyupvz7q`^sBRk~BBF`OUVSofl?BAck}2{3w=9mZfnGz)IGJiSy1rfns)Fkjf)(Ru zMMa$OfwD0;fSfYGHV4iM$OqtF+Q!E2GB9M2OkcWduvrq9GXQ!7T$2KM$W}Bp2S~{&NKihN)in# z%xTQRb)jgo)Tx{aI6G8SncMx z%iQA`bo=Yx!qDQY?*(#b(gvofHn`Hgp80Z5=SgTi6EX@U(h0R6;sAph1T>s65+RQUvHS04_FQ3QjKs~I_8M%@#$}iLnYUH@MTqByikV5^#;tN9OlkXP4$B- z(m+!JiW9)u%C`m2db~S86Zyp;Blw`541$ZudbJDQ6}u`k9kqT;D7+X6al&QO7S4zA zSuR;NHZ}?YDx3`&b0_~L^}b3n!=d+`x$UK@pQu`(l3HL^HgQVbsGzp0aa|#bv>}e| zGf8SG>IiQY?F-rIWKv>M#b0><1QwKs^p1g zmx!kqh%%RpCYOk27jP)Dy#37l7KKB)k_w9#`3TbBtrQtm#Z$eWqq{KH}!D z5-3XbD`7s6`fQ>#=%wgU`Ple4;6$^#&4p}$2AEh`b8R1_r`w~Lo15p6-l)>~(J?+w zf{BS~jRHr?&oi~ACKk|*h7Lr&$ivFYNg?=LY&xKR>&{}bIv?>g#R z;_7!KYw@C$->F#ms=NwP$&+9%mP|T$k~TyYp?NRN4>wLKX={k_^$OiXEIc?l4hjh-e3i)veF;~NmWo|5cs3Rr-kbH z^l+=)m>Zm&gCKuE<^gKt-pNu4(8SJsVpv=#6dw5OJ>LZ`cGr2L|~;u0cmfFR+{zwtj$-1oOf6RTdJGskdk&oHH_e zL?jHSnD!RN7{3dBHWLgrn|NkC5t^m-jNeXl(}Nu+g2pC|MmZWs?($+kLP__19W$l2 zA=^o|;9dm(vaO<$$19eTfctw3cbB`_@2T=9IhclY-6M|Be_+~vz)0@Hiob~^rcGx= zxP6g5XJ@`5XH1lTm1voXo!tm(_wO)25CoG*UlG)FK<@lO+J`{zzk*bFsd0kz*`Y_8 z^>C}>GYv0U$krBg{E?SMsOe-`A4BIFnds@e68zMd4}i@RD+x$C6)b>CfwIV{g%!Ln z8Vfjs1dSFLSBRp=-x32fa_eYLt?hp-$<9Fi@d0*?4Rmb)#=c~IW(YsVGLR*_apT#B zy?s7M(}wNuyzC&=cgx+y55kRJWp+H)jr6ZeMyVX9sBF6(-Gv?GjyccfAZ!Yd9P#cM@6nq@3F*_HMshbT6?HPj`??x0cAWmSC=;yXof{ zfnA{~fMIKIp9T|A5lz_W=;)6WDg5>I^&>#^SRgy0qk9L`8zC^CK;~lM;YsF?jPOzR zoTquh6h=X4(%bimLze33?w*4Z7mbRKZ`4K{>P=zbW8Z-^F!`sk@$mQP;~XXWIVj1D zCadfre|tl(gyysK6Gw9&E7BF&f%{itv(KKZ%*Us4UJ^2Y(EEk=_SyK=KQkgXRW)@9 zWif5n7Dzq3r{dRGvLKA&}?sS zL;XEOFn{9OkO9CBD4D|XP!zHA(-Bm`wro_pR;FdyFA)3mIA7d*UQMOOpHg7@zAcZO z^PLb6rcI!u;VapNVaA2w#O<0@djBiFd06hM!Y5sV*#UDLD)UsInU##)l}3+}ewp2fI?k|M&&%;#vq^NaNdVk@Wi2U})^=hX}owOqqpx#mU7* zVbrw_T^QajGwA5$( zDe%+&DCf3!r*UGoU_`(d1LjYCVF?$c5g10FnazJx?6-EMP`=nae>QsbNtQ;%RuS4) zdA%7WVk2;KVb7lJ4JrckCia4a!wE_iq%8m%A%0*RK#2^}CG-a(Z&&{OX@Z2ceaJhq z3z+NybfMzib~-h?#NoyOer_5cKlx?|TmmrHpMhW0)7NhXb`u_`=7F>lmZ7cy{F<`h z-wTLqu`jM0XkuhoCnyA{85ut=bVm&W>x^_S`{RY2_kK#TP6i-w2+)EFLac+NpX`xC zATW})uz`>b0mTc@>GV`oUVvnu{{8dDMc(9oUZBtjgj}=8yVu{FvVMa&^b)WzytEl8 z>|pXo1Aw{&9M+NloD=l>{u$Rk$;{6PT4mK6imI>3==JGv%(l84V;?RKv(qjoW2u_+i3eH+u1i(#$AK{fU_N4JhBSbnw~rLK_Z!LK*7F;5+(6hK zP(L6oTev^pUl#tUT7mct0QiZiDYK%`zDlVfsOM=J7>ccC#Q@$p9gG=4Q>0DRknJ7| z%cp2ABhJ??SP;IYp-;R#QOSjjSO#hm`t~zROPCGt-M%7X6NoeHwR;3eF#S%hO(}v>Ty@sjfLSX1;l(I7 zX`q&cR4GayPh%Xt&Ps$sN4SIDEiA7(P9kk*0Yf5>_GjuJ2lD7-KR7UMph~>LZelGM z$+jx_`Rt{#sE##1zfrffZ9y{J{t}Yy5@Ywuo%wfESo=A&_GqpCIgB!&Bu$7umbMEy zIk*y)w!tH`mbTyNJGI62;f zq=9_nSu0cHxYz`8UMty~XuX!bxHV}Mr0XszWTk`gIBxry;2ADN6 zJ)!DMw_h6`a!E#F1SjVgfW^qPec)7<2QxzGMv;n6g*k$;=5y|?=>O9K2vnq@gw)-S z>#8AUzV^C@^*Nj4HR=e)V>2zX6voLI{u|5;^UMs~2OAu#PqUbxrko8}$PNsr6j^@g zDkR?_-BV)6;^|~#%t%Z%nM4WK@)%aj4S$ZMvf48(g+X_FT}VB^Hy0;v>Z2IjRZp`X zW@cPkBf_DA7K1FNp+y~`&5!ez-DY>gT2yw^O)0521$@Pa!u{q2VzRBh=kqtDSK;Xn zIceWbWweynIBkCnwd&9?FWQG2QKs`*-o+*@>qSmgJtM>Nk6aBR- zqG!uR2~AXGS)Lk>^VY8YX-c>rTqQnYHa51mKDL`K%w<0M0B9gaR#roR8ADaZwbVcf z!$k6Tkhr&jO)7Rhv>+oVH=CG(t{CfnvprnK@xBB7grp&?C zG%{8B3Zk)f1{M-B^*uhmuK;NVpi|NysH6AhO?u}1zj%IThDR=d2)IYV_yQfMLUeo` zr&$c7UuypLt;D@aQK*MOG1kDTt)gOp-B5dRvKFa-=gyrr;9Vp}E=R1NUy09dvV~P^ zdl~&{Jdf33DkZe@`|;Y<(3RlLp2dw*#`|oq&fE`m9BZH6Rlk2~LUZnFm+Baza4D-3 z9Lv`nsg3EZXFxn`x-Xx`5TTh;hAZ}#)GvuSA^Qt$z%5U)YzN7?0o*k0(9BA)xZB|> zU({57Qne*jY6I}UdP`*mmywWj@9Hg=6#p+aLMYA>5h|*yN*xkWZ-b&64U%ibJbOJE zWLRH?Jx%+bJTZ;V1=CtlDwMgw^x~Bx`0`ns(YpRcR zUSW7){r#0pYe;@<6qU#l*gWh>HdR|MnPzv)lBr)+jNdDGIsRICkn82{LepBFGK%{3u2P`)AkoM|~o5NN^C70n`2aC4su+6clV4hgxY0SK_;BZiO3dN>D2$ zJ6xAE97MgY7Ei^)^EFPUzk@nIF|+Y@QPA+WP_{-VUfcSW{;qI5V>0p|d=BYFwB9>U zs~Mk82e;MoGPmO;U%h7k$2f<+p}Veg zL9wM83T7fwN;hyH3t}YSFnvZ`A6xT$>t2NB><>58GVN(h?XiXKocDtSCmsG=v5yia zX1e+Zd*6*13CbjF@=nXA%C3dLPupE7rkcG+mF-j1ryV(bWu7;yy)Hj?jY-ETbkY52 zr!aEG6?Z-1$&9Rl(1<+gg7>@<8v5H{QX8mtv_wj7^-bV+n~2s;&ut3B?9H!m0fWRc#H!)FM$^fVyH$& zMxfQWIH|uu*$>J9i8R80f*eZ3i2~9i^YIdY@c-NdlO~86pvSKjq~D0;h!3p|aOoi} zG;p@fgFXg%VZZQcAjtF7QH4N2**Y{-Dibwik0w}^yc@1PjzPdQym_v~7<+|=*sg^k zb?1~4lZlzBxv}p(5F}2{RmIMy!WV)5hU5Bk1wT#49FNc+9bR^d>%Z6Ijy`&|VY#<5 z<(>M=&PU_Knx4%+wgz=`W5ib*Gh};x4*!b>)2HPP*Unz{rpDoKv%V)kdzvHWOFo?y z9Pn15ms4-NrsqGFIC84mZs_nfpDGOLiFHE}KG~6qk2~|^ojCUSLr`}ztG0s^fMvSU zUQjS4ZCIo+h!hQY?25b%Ey1-?d^S5|FPQ13dIj&V5JrU; zZ7nkq+T0b^p}4PkSHi*KiqNC-xtZ<3j#TCMQ@6yPc~$1Oi+i>eoX&8R44ZzdthQd& zLRCCBx{i0i`piT#k)`^v`tU2}q7c1>pOo+3KD8dc)--J}AMyM}Qbth)K^D5!My~Nl z6Ly3cJ?Ibp9%b(}y|D@IMe`>d!OPdnefxIPMP5yEudKG_?0|tbRVz_GQG~LNKTJn^ zeD}=k)A7tF%8I{6+`SXp&Xy~OJ!jLH>*|NMU246r=qDIVt!IoC9%9j89xg>KZ?wcd z)%)q0pnuWc&3D*Nf=4ORT%txqV9VzHg4Ip^q>sgJZS=kN>7_x#D1-AwC-%CCOTbrK z?1{l@7M7^KrFSDl#Y;b|QBcJsZ`E6F;2yH`2>I5f(BFy)ZTbq^?riuzA&ztIN{k%6 z&bLF3>GPV;P00k~=nt2|oQs#o=!l{7v9{&jH?Ux4bKN1 zj&Pg$^lzk9e(2yY_Vck#n44Hp{a*Y2W7l{`$-ZN9ZvAuLp5NdUJ%WQ~abkrtC!F;`|e-B)DT zjS?!GhB#OeR|4|D2Ou&E0E%^20R`mu{(XQf(?4>Y6<8DG@eZ${=_&}1#zBl&TXm-j zB{wWu0NY~W;QRr3Kt@5q4}xFN&09hYQBWTtNKL-T+|FP%6>R+go9`+9g<&uaMcMM?%EYfeL7-&uI{l%7HNrf&uR zBcNVe19Tsz-!iu_8&K@a+DXJ_eP&1Y%H4HlUhjh( zz5akN&1!ha^CbdnN87e>+2$-;>{x%rDvJ}N*I|4%f9`wqPGIA%h>2Qb|NMQ3YW2rX z@HC`tW@Yusv!|X4?Q}Z4Z)+PLyS--K@YQ&xnx@}8EQFGpW>oNY>t-z3y7BCqyxe-} zZ>5*cuaF6T9ML6_NVsoiyFdig|CMg|HpA&Fw~V;6@q4>H-6W z6hkX7`Pa`WTguxBzUOLav<=B9RCg@5ze!eRa#~Bv=;-Ow|CJi8@Pqs`9 zB~6E7w|&XQUXS;AEVqg5Hhz3Ny?SUgmc51_`XxrUW0CyyE8iQevC3mX z9#>(M)8JTx@tiG!Ujrec=PrL2@JGsI3mjI1Ee{o~{*s6;PMH|2yIc>elT*=}E&IE@ zodi9hSUzi1FYwm_1S~L{x{S-nU;uF~v`2@T$U$@f-ET*EE6fH^fG;l_0}}WM58MG= zTG{>XzP`5JUR(KuyVd|j zH)zd54dp12R?`i?D#XYF(wN4^MsN7<9H1S$fo;J4e ztZ#9OP@#WTc$C^Nrk{&b@qwiLSYGEJ6u~b2mD>ZoPXVtb_EE@`UZUBDhv=nyt$Gg% z+_#ke+#xht-&RXYtG56H|nI{NxCX$hmgdLB`J;{Wi3`qjioZxA}$?Ci)$ z*S<6xC-C?4*KbzJQ8idv2>TZQPA6mTXoU}8*dgv_NQy7HI=^#j>WCmpmh5k`h%$aU ze#{P$Q|w`#=4ay=AB(kacm-eSGgh%tx&eY%EV?YxPJsvHX8qpW_@8{bUjK+v(=_UB z+fZ4ts}ZL0NqSX_4QZ<_*R`XU{rhtgaWV0irN792I9=}EhL^1CoMPmnovBw^T&p~O zSHr>O^V#=QDQ$3j!gE@G@SxVo`K#r)q@ZBryL{p9B>jvPj`f=a&)H^-Ek9|bJ)sX9 z=&7~nox0?*Ag1h(X)P1_Kz!6NNSl^kZ2dc4V{mJX|7)*^TVTB+S6`f>Bz=T62Mwv0 zrH4j{*gd16fn(#`Ts}wP=+YR6U*F1wa@xds%->sj4H@TYQtNE~_4k7R9v zuE#MQ=)IEoX8t3So`J&-RHg`M1^yQCP9j~}{QP`IvMVS-lFf*M5x(HrAvh3v|A2ET z6&!0ID~biR!ukg3VZrU8O^+AzWNG)^Nyp##DrHahG{%t--i|_@`D4Hq8+jpIvUiwe zn=Gs|)Se7&M!rYU2{X+1nXl-r#W$Nz+Kv_}c!(y^HRxOF+xlZwy-9n!ql|A zMjh03mKxn@cfNP-F39J^{XTq8?pOAzZ!r;Jq@G!Bp<{c5b9owU-wjtXsG2&;e(`L~9((+&PrGG|^&`8}%?XejB%Lwx zA7YGsFq-@6&Y@9#usEZD%cjMNUodrI6O{`)gP4FsdC4wsv+jDs)Nor-?ytS;DCvFb z9l!Xmv98h5>K33oxv_`bUbZ_XX)&%UU1JfkRD61ZBAK#MwStee(j=vuOY8C*o?h}$ z=atR41ZvD_Vrdy_qGtQU5!}C{<1aM_>}?9_-Q10+nRv*9G$a}p)`l#|e-D$)R5r0L ztILuJSeYz|SJ-)Co+dI#7~Z*11?er!E=c>iwFGtyD+h-=m|Fh=iAEf#?!kBv3snUL zDEjIyFI<6}Wy6uInBCt4DIdZoeZV6J>VN=5=}_xB!88k?3@yS>-&Ue*ZI#5Rwf z1WB?DHre~oKOA24dIH$&;Gm2)U2De8hUA{M0M+NOBUzc5O_J9P4Hrh-bbM0BOZKv5 z%vg9(Zna-;9O*_&X?(0ML1&ugb1f=iu_j)#hDa%6?~p=RM%INMKj^McNEA5Rw$ZNo zR{jv&?sf00 zioU`IDA(CndmtcApF6dir*)xL9-bFPnL1W`aP8z^*-s&ZAwLm|H23z0kc6z}{UMR+ zhAN$tE!Ok+<+rZKb0h34gS9lQE|XHK5pdZ?Qm(-X!6_x*$;?=AGxTp+vbq~db+ItZ zR9a!{vg0en2ImYel~|l_Z_X;5B(Upe_Oxa-cPA@fyUYeI`IGyMfLJXRT5>U(|#QK!mt~}@lxmF>d?)qYFg;YD|2 z+}br9<6wxWr*$-BXI$^?V;rql%~4;F+&+kE9~vvL#|KnCV=T8WZ=$M|C@$*GdbkAKVHvs_6_d^K2gbIW@riW;NFF>;ACR z{d0?6`2|C1V=N6bmc{!=fvQTH#K+6mob0ie+{p8yONL(%65cL09P!p<`?Qwk$<%%J zp!@yw+(q-B%JC;IQdVcLd#-G6xL?#M)1 zzLB+SG*p)RcjW^6I71|f@7PGG@So7(26|FFJm=~r0YMWo^#EWbm=$YaA_EwM&h+Es zm#58q*WXM2>>cYvi*rU9^^hb^#n{$=X9*Js->^bg zP73X5QSW4h1Z?xo=GFe`r0+F8QBx;aio8V0b=rYiZ2AL7pRdEz>A%}t>%xB-@Po)* zo*!E~+EcH_w1$UAZjbI>($KJcuvVO+-L2{Ic#Zx@WvV z`?sLq$Ms6SmaDrsEQ*3YOQD5p*4a375*S4Pv8R461whUr18mIlYukW$d{aReP5(@dJMv_YZNfN*w#Bjk%hC z3@qDMaesI8bQ&#&f5^5kwV^TO|L{Q8(AfPw@2LA^r7Z(uST`nUFB5F8sV6!7U0uIT zgoA?hx5!d?Nm;}Es`FipBXsAPnKvWzYr4;Af-ResN4AoxJQRo9x8ry%r&v87uFYHz zAn<6(9g!M6n%3PFIL)B>oMpXD!Jd~-;+4Q_uKzn;{A@b25&h`&ucu;t)9jp4hfwkP zH|yK^437@D0&VCl+#|V1-QB^zjN$~`(CU(uczb#WQ}#I**HoZqUd^)qLaWW^3bAp6KFa zMl`9ELj1yqQcakNVx0Rc5SP;Gc_TSWsXOTofoEHlIx#`CWNaZ=BsZ7jByI4rme{PB z_%ZQCmPpWqU{CUP7fxOS-L%}WH&Mrk*an3Fm=##2t9E*I0ZTrAO}J z4^^ElvELbJ>dz5f6iU@}t$SG*`QtPLY zgHHwzWV}m-?G*YylO?3{uKTz~g|e6nex|lm;iaNgW>OU5+|28#eqq+@*@g>~%;8#; z7zxWu$g{LQHFe!}x5mLarLu0rkq;K5YoF|ouIWLAS-dhqw-KfP>dK$as=L9B?9XB= zzGXMPEW)dM$@=5@XLn+j!z&$h*^>6|bYU|52d9(AXg$E0O?#aAF~{M>DTI^`x*c>Z!NED;s;=@m^`lt&3)upD~qm(`DXQY10no26&Jkx0#Z zxZ|jBS2FDLsAc3$SSMM#t0g*9e+>RxtxN_`Tp_}HWDFBL`W0sHu)uOzt#51`?{u@n zqzqhy1Azf|daz`S5nWdk94qU_Rj`bO^?nLtKB1=6+M{@)(ugksoRbTB z_|mBaw95W`(msFjZ!bik{?haU4~RH5`(w2)Zj<}p=Z{f%wYFTkI33PYYQF6)qLdAk z(Wy!-u{Kipt9UD^`N+LuVV0&z&+m}Twl?`Hk{HClxGSSBqWDBM&~*18b-$!GfQ)wF zv35Wso7nziFb7q zWZuuk;3(S^kUo8QrJ{;YSw*?2O1`?{YlN?CQlh7{kw7Vzqh+M-vyQ51htJW^y(H80 zp4C&7;F(V)cK1G0^@?!SCB%D6YH$&(eV4ZS)Qf%_!`krg-}IK@pCtWv@*MA{8wAy=~=#J`|?r5Ln z)4r9reCY4KxETvMl$GD9aXsEp{QAHJ3$ldGtnwWM!FY=(&Kg^GPb@KTnVdT8S@w(l9u~plJeApjQWnc8?@QXraO-`;#JwOH?;Y3Ny6zZ0)H z3>@98s2;x5D_eL+jYx-OjO?m8{PLKL#~bA=zo8V zzG|UQE!ZrdbaJV9Z8Z3xyEl_vR4vkXV*F`rgjiT=&abe~vA%NmFtA4-nQdDxz0+bM zVZ-tH+rRvDu=7zVu`O@8a>>+e#o;MIWg9t4bX!nSkI*tpQD_dSL+JLh<@8{Zyk4#4 zA@l{VWAlUjW% zZW2j|w)&txy>^u;ATj(|suYIFy;_tN`;)Vak39rv9|J-gPMzbO-`Fhn)h^W>PF33-0WRq>KBo=nmj0?`K7#gCaC=IyVS;tw{lWLzC5W$F!_f*6)7JY zzZ+s$)^Rmp2Sb_&;Dr7Gih1mhnGs0y7QhHH(MwuE;SHEmd5Yp?-5(P!{&`;hu(O9oaN z(oemzzccSZW4~z?b8f>VF|opLV8BMUo24ROo6xj0pq~5f6LLzLF@7S`O_BU}?HorB z#gif$=UX?J80d(CUIayT`aY_DNRur8mDbVk#)!m4h-KpNNb9pLop0B>Y4^NwH|O!Z zWS2f<9di*HSX9uBSHEd~_{||8$)cO$ItiEm#9339E$*iX28KTB0(*A3-YU)`%dpG` znqT=Z(GDn1yxS8J+BVVr0Wxwpv{03h;A#t$-J`C#!n86r9}9Cmg+4{Kg^1-3a?UqW zlzcRAN!s$vE-Yk}))tSGY*upS2`5jAls$hfBw$G?*ZXa7p_Xo9f8bKaMhfem-;F;4 z@K|*kdiwXEvX zyuZKC_y7Iek4N2gm)_p*>pHLVe2wFHzT$N3wH=K2GHw(JEofa=luBz@{#BqXOTqPy z`Ao^KJ-cmsu58g7%l3Ljp|f#jP|CIL;3Mjx$0-$$r|G5yUOMb&*+GAej@s2{GWyXg zc{X;=TQ5)U3VcDk>)Po>?aTnf>m0%lIt#-`+a?xb8^6>UFk`pB7$+QK2G5XtWJFe@o(PBC)gJ3We~kwksZ!& z_L=w0Gp3}ahpiU(Mx2)>8V1?MS8WB|4ZIn4(CoS|6%(Zqn=5ep%mK@9!rWmjk3`)* zT`#(k8l@7?rSVQx^ZVF3iPk{NXJ59TSAecTneFM9O3oNm<(%e!&bBvwF!COWs5WAM zd(?2#mpaC{r-wdl+JYs(_uxCr!=f7L@|A9#mdZ3^Q;~7U>--@bM>~A`h6~krcmSqx71K!3>jBBkoe;s=aIHP4p&S1P1Bl z+&p+)j+%Pc*^BNQVyi0trr15d%|WN*&$lOWHld2XC6ht+vFpXiFIFRsYGbz;*Kn{1 z6$(|Z94Y&4H{S6v{y`zf?U&QXYZkV+TCjgyv9Hi(!6wvxL0i}L{hr7}%S8_2V@rI3 zUU8mf4J<*@}II3*QRu|LzlMcF&>cby>XLO^kRRvWTTPr{uF~~{gOTZ zT!|h!*mEwyQ-r^e%|!FSu9N?pAC zsxUWlAthtHcczu+i_c!ABmP3)>u-{moEX1<=;PxNGrXM(+q;^LxeJnFpZ)1L{UV}G zdw7WHTC?xWJDah>=`Eg?f?AD}lQ)LiFE%C)mj&lXPLGCs{^<2rI=wdNMPS40)#Lkp zDyP}g)jxM6satZh?!NDFdbOnA;?J|J*+O3K?5mFELPm>UdfH5dokv$TY>6>#{O1~o zYuX$I{&2h?cT($hr0^XYckxe9j}fc7 zL0Yg?ukoe14&@c;rp2G$T&4&0vwtc$I@>4x|$^eL^OVue8Djoq(x< z(k*W1m1@YHX0O&nI(XTX8LQfFpcbhM&XW0QIn%;AVz=q)Kta`gQ7t_Bzjp7U+1vG4 zHnH!fA{#cmBIC4dF_VmI6WosS+PVgvQF5&8DP47QVyVtmR5`Y{&etpm?{T3otNfhC zwXiq!TGF+5Dq%GtR?fG_T7+v>XO5j4?bq`R*(~L4`ZaTnoSdAemlyMn%s9w*o?ePx zPi|M1tmyL0RbWPoV8v_KM*#>(X;4GVrNUtclD&4VWxH0ts?I(4prGbR?r~yVUtKI* zO-yeq2SBzJ($SNdqbb1f!4UTzX8us^Amd<)B)Oxv)rGf8?cTu3p1LbCVfVS&q~7y| zV{;#jm-pPD<3vsIp|gnKn!1?t3_jt)RSaH1sb=P-Ba4qsYHBfj+Nz@DqS-n?5M z*6881CCPo-SxK-_02StS=$vba4GGtR}znDTcqkr{xj7GhU&tfe_ww5y5I5k zU{RdQl_R>V3g2CpHfq?7M1Sg7-aGZ{rool{(wVYmlETiOXk>_wjkt=AFwXUQrPy~g zo}tq>?-}{?DQg#1F;ly5>H@9xK#dtt$}dq0rYt?l2L3NJjFkUGQwLy^APz_bxEjpC zX`pt_9iW3$CJOpEs4#z|o0LH#z6QE-L;@TAE8JizBDh@GxhRM)y)j862zVPesE?I3 z#?Z9`6W~Hhb3>Mu9uaQO-Gv7IEuckTL(qnpC2Z8$^p1!KnZxj+y?TH zNT(^u06Q>0tO!_P$BrU&0#lcldb1(^od$qlO_z1{%hQHb-t@f1Wo3_l|NdPSk^95+ z3=sueTAp%tb|x^{W?PA-fbVogaL!A>-VTRM54;Cfg_(L~RPb+d=1r_UAY@lsRpo`$ z4hE8cM8=md6TdU6&J_3(cqsc}V9;xMuSby^wULu@+maN& zPmZZjw6}41-fg>>T_r(vFYd=cs2gurU!j<`Ucp(jzQGp*2i649>eVgZS{ge$_G4#H z=H%2=)cg1H*kssFoOrR`H_mF8G4eW)^soAiU(<>iSzuwh9hs};xRPPkl-ne_dbZgo>jTyIm$O#` zbA8(zm>yP1=I0vpwEohSPtY&PuZDLFmcYXgvMw^Su+Z+`f8qfN0+L;UQ079NI0rzC zm?e-&ZX(Wy$oCZ1hI*!XHK|Afl(P?DF7Ofa{thJ)s#5&b*c+K`qy`7!uZ{gx6;RHR z$t6@n2o{QkxpVjKi&&S0sz5MJF3ZC@7&J#T6v{cQr$eg=stMsPG3^4lT?>gQA$Q{D zK};4B8|fTk)bN)0Zwru>7+2W~hJ%)60~`raze0cN;q84f`rE1h;iR(2MZ5tVcN;y= z6VhG6LqN!Y)3A8-3=d1gJU0j}`zC6}o3Ix2*` z`Io9jtH60Uz^Lf(%TMATYA-6bcc6V=SemX)yz-xhC2$ZAs}1yUxuCg&p}>tjxi&E= z1#aAFKwrM0K?3?B!L_28+mBZmtL21OybN$$=K^@@iTngjFMfxKg8)OA{w(Ma8HI?~ z``fLXIEKNlCmOM}YuC;<7p{E9jzIvTD1{NubfHOGo?@6vvLR$jC-5`ES6=y(S?CuYUX2qR0LtrlS%Rf)3M6LIMq1EL%iys9JO{?m>qC4m3 zFI=w>5?8A+-&J}3cfQ7}X^$5csi8%RPFrlcximS1Hm+v;9?Do3BenKO>G+O4doF>6 zjH?Hi^5wJUhwwXie1A@8d~nZFiI`pNQY)ms7%ST2)H8fsd0a1n$yM%_7-fx&d|0-} z!$w~I(cSZBn7rh?tX_SWyl#FKUfDiq*1;^Vf3JIG^mAqBwv*0p8E z=>(#INVf(ihxR_l{0Q*Tb^vP&^bt6z;7H?SY^RKXuDwVkU;K3!A{iF=9ng{{bcA(T zxlJK3yko-!>(e)YUG;fzu$tL|gwOtNi17%w1IPr50Id)AV2J>iG8CIvJz!n0tn>CK zsUX+WfYVzSl1$;Hi4suC|Ec2Q@dJeA3VNR{fZ5<%9fII)!}Zc9JIVb5@5CEESYXyP zPmTeja5i3vKqqy1=qLaDIdf z6!Z8`oKB%AxT)I$+;%I>@yS)m=nS&xC z2VxW}unQn{1rK2#=(k}6szQze!ko5bMeCsTZy?F zpS{F9lOW{?j}4G2qCQO5uMQUqf`EmX{B3P#WLlY01`Ry~3x&QdbaM391YzwB6{;*hIn@SBls>>nZt*BSL!;)GZxG*n8Y-Knvh`}1z5azv^&tQGe zvRK|7b!^(hX@6vS8LLQc$iv?8XZC;Z<(+rz-QBn~T=fWLU1YhUb>Q=nle-Mf#q~_x zbgBlp&d_h6cU>=02PrfRZwug9b9~DB%yD6M{HM-Z!LA;znO_nklT z7l0A+4?wrGhk5Hux24ix!C26ALH%DTIXM=XbU?$%ZF8{_po=Y>?>#OiR>=N+H45UO zoXl{YFPT_vh$eFM{@m4Mm8HvV%FU9|%)2|(bD%TGr_X6Jc?C`rC8KFh)&ME(JAJze zezk!{xG-La(=5EOi*|uu+xtuA`7ocU~lehQAY7W&;+QS#Irrmylpk;7y zp)Xznef9AZCkWuhn}JUy)K~r9f=ML7+u$DRgQtoIy&lfPxx3K$zQV)W-1zAJeTt9j zC+%_%1XW$c@Cn$?$9^@&R29BFD&RE#K6eC6T||L&*fT(5`Tad9bTJ=TK)>MN3IvHb zOJNG|$7@hvXu*T3zT!S>KTJc>)NHr#yoWRv>A)CQ3>~NTR{((>TmK;Ltj>Rj0R$kp zr@U-mNT1zJPhSZpcZWUy0bz&tQl`$;oMo%o9~lduS^z1!u&~f9JT68Pn>aZ)x2X$T z8wK24Bc2UZ$cPcHk>MRz|5W_sweKH~)Szet@%U-yZKDv6Qc#ou#xo;Qr_l&CZ<)F--Cb zxn@5L!of)vvpsyUwED*8TXJV(-Ffx}x>|&~C@MHUdf_G^*)h$Z9V=F(Ipe>6kdK>g z`NG&B^=14aYcAvKsENG=Cs)t;KW^Ck`|qJg8>uhbXGVo!p^(!7SBtD1BIJbYtUg&w zi1HD_pvg_Z^gIQ?LJQMga6bHlZbFLzOiRLhAkaftqljt_7^;eznzxX-Veg+p=a%An zTC4MIpov;3$R3JD3n9hN8M+9p)HD$1o`4ommf-h%T}| zv7sX;*|=@*MB?o;^xgou8~(0)5j(bwx(I{{{cj_ zAHpt-i}}hfo2VEMHS4v2+%)r}eN5pGzBg{ui+(+y5%E;wvRv4f4a@><6>@){){mrc z(J_|j)&yA;>R7&<#{WbgT{M~U7mYqTpb^GDu{nq7r;v7O%gw#&h2O2eoqHmthKe3P zR9^u)H=g_$1Ws$em~$BDERv@#BpGgFI4keVd*SKv(!$X~tAt%Q4}^aSHoI3YxWw%q zpNIt3@9gr!nE7oRSQ9IRm$(fxW{(a37PGohvRY$wVVjVI{5a>SOFqv~=1p-#Wat6i zBvkk>t~XkfLm2AbJa}1Xw*6DKoduZq;4%WRc;Z1*y zQ7Htyj1ZRFZsZz0uW>05<{h^S!9qBU*avJ6F2LT1w~rK9NNA3TQEQam4YUib9NSNQ z)&%PG%KF4BvToqdB%?^kr~(i?EediSFbaeq?%)Xn2-}6Q^01jC%J5-S3gL=DOhRUR zV9v;VN<_1^*}d(I!o(8^mKyWXqi%4EE_@j0yH!W#F?A0Q zlXec!l)u0hTs*HetZfpO{1$C_@=Y<;2j_elszS+v%eapg>JKF*(VEO%dAd*N6y>~p8M;1**3+dAzz+xV}o z=KJM)n`I0Pj$s$>0~XJ6E{WAR2-MhVK=`0-EjJPTw1dx1tg!Rv`R3kvT<&-3`)oA6 z?W;`7P>e|T_iWGSH`D)}M;|?H{IDjG(s6wA$1lf@n@=)5$qJ)-7h`yeF7k__^_OM& z1mVfJHpcTs`3`RFzHeox+mcP%2t$9VpJQ|K&4Kvs6t+HjqIyBU7?a;cx`ZY+TTB=1 zqWEjOId{lbGEsGHokMxuFk=U-iJX*Odj zgx18Q?7YN}CiJskK3RQ6P9a^r4eKNO_13%(cypsd#Ep6Gc%Qq+FBZ-+MW-Q`iik*B zF~O8$x3xY`{MqIw%q+<2CApY#PO!c=Ab@^ClCfgOWx|fH~y?(L%q9z?SNPR>^ z!hc%ypc$B~MFHSL;m|H#-_JL6vBD8K`8|7fu;KuDqUrN7Wr--I$h0MbM+RJ9Npc3c zFA|$$4-(ulZ$r7(?MDqNJ`LnI+6$TaQ|Tq<=i?Ql>ldTGH(%_feemhXjsS^M$9bnt z9=@=h4tWh|kpw$Q;6r$G(KviaCT3|2@77^N!k>`Q;v~I}uiLwg`)p3u@~u4js7d1| zT*6OK{?G|qZi$2DeRy`8iu{XGg}Ev-gJ7oNWqN`G^dS5$_Fq8c4K zpXCUd>9?Gudmmh@$2V{zQ?p1n`EO>2^_rM3Zk>(0!sWIKi{I@XUZqiA&6RI|<>=Yg zhQp;A`Drk})nWMQp$TG4nT55Nt@WGzGZ!Z2ARs3X@NU?TPhJ4r=C0Sky! zg@AwT|5f1+e|oA^lmv}%dXQ914_O4rRgVSoTzX;5 z`QlMd9Iv;$QNDulJ$d7MXX67bwjMI(a{Wa1cZ6R=HHko}3%n(Ok*cbsozw67tDV?` zVkQX{#l#|!tq>V3$jQw7;+o>Gm7){d7_~b7C|7Dxo&HmAYZ_zJB7OROkbc+k+NivV z&3`=ioAwE`R1d77V@s#o5T;C-|TPfUsoFA*) z$rk`ZIg%S)*wyl;YlKLogf|LvALW)U#cgdG4{d45q@D0^Lbw7OBMP7_%t&Y;p%nUX zPw4gVumGStAs0ONnd4nb?97ZU1ptm1O!UuGGtdUGDy1GuJYmP&mFT#*-;X#m4eX?n z<)a%HqVVHS&eTngyBjzp1UMdV4-;e256h_By3MDuP)n8}%QP#@&Qj31VB$5dm#et9 zc>JZ;by4!mVHAqD6yiPxNFIuzcbD=NH_MtW+d?Crg}5@uerugKijbluG^rXkxURtZB!TtT3nt@JX-?=rZPRl;do^q;E!PEGlO81iy z=O)7qvbp<$8m6Wf0;potsij1u0vO$Ytc&>}e}^Mx>TLYvh1d1bO2Z1bWa4I=`Nqsm zk&`0u%=X_17X%Aj^(YkssLRaHhtYXE>^pAL!Bml1-4cOiZybqA!3U5^)Nj8tu75*m zSQBQ&au-br)L-ixJa(uO3>o-Sx6cQuB}#-V$88U&pgZI??|=F5xy@F&3WLk%zHHgm zlW^4U;6Jqzo0SO@*O=9v%_g0oTO1|~Tad9RKolowtv1GU$wmlcfRK~*)t*d<6A9Rl zhL*PDHVK4WY>JIgFDBE%P}OCZwShSV3_TBZt=alJco}dAzm6xkM2gm9wWto zDL~?PFfiQx{PzS#fgtyu_^x50Wfy^D#ydC?Bu_X?ey#!l7F_|K> zqG4c=Mj_Fpqd-MT>4N_;859hPw`-YWiQy>8>mChQ;UI-|l6(KtL_ZURM2Nv6?;Kzj zfS#ck0RUVn2zN%`qTKI3^#3r@#N7H)(ETkvF*!c~>85HOwHukvh}fy}zAT4VWEPCVgEd z#$8rJ5oGrc4ocz_A(N!Yi}sB7DR-TNLxQ?dQidrX7rqzYp1G-T?})59HZ(U4^U5 zoRD6w-?))Psb39j(j5y?r{Xbge1gi`X-p&2gsKfo9+~j0-6*_tRk>_ zke)|;>Wxifgy9TIG3~Xrz8Dxh7Y3BL~`4#3Djb!t4q4#GLS7r#Qp&SM`yy(8pN zWI?0{nuVfLj4#NzFI>4vtX({jgvUUEM6nA2Dj3%LusV7^dnGmwpsv)zv^u|u zz{toP1nA-L=)JGx(a13ECID%az6q@zdrEd&F8*sgx#5YgZ!98TRWrIG0(wD}h#%A# z;#maxaS1Shr%YlI$SIcjWadnUtpVsKNi8l54ILd}%(MbRi5uIEszMJ;%3Vlevbz^+ z@Oa^lpg1qc=hXVViyY(s`?yXfl2Wr_Jee#yh=luB`?d!#Gv#3A|T-Pw_6ELZ{NS);eF|9pOsZu7z}YFZ-`b&1c2x$ z?j;3zBv9$CL!A{h6^zXy!RMHeK0z(pKODflCN*UYa>E;~f^BXd6+Iut_@gkcQ&Ur8 zhu&}&;7+9H;)zY*AFQ&?=3R?KHQ?JjwbQ7;lTI~`@^{?T_!M8jXvL_u&*)d-mB=6_ z3RHk_IOg1Na!Jxc%Pksf5#wdPk@O45M|7%j?U{Lbn?xc_g2$S__hC2)o>5X`L#vHE zw5aZrB0d)H1{_U@StI$J3jbfeIWN=7(lnJ$3gG{HQG1$+FadH*eckdW%OfMO$QU z5gQFIx^X1ve#ICJHadBt99dOB%Y({?;y$`+65zlSBfr3%siWWokeO)c zmt*iL=D&V4X|7pTOH%P_7+imljjdA4Is2vI&6}2G2kf&}&GGptuu8{1ASNKh8njsw zKF6S}g<)r^q2o9R>WtH|Hs$s6QGOo!o^-c0N4v@vV^&nPg1{_F*yDxVn@sYuU*Pn= z<8lT$1?npEKyO)8in7{I{O=Va*J@swluWSNPiSO}JUUT}fr*F~KcJ_|)`xKyWP}@v ztEMpGxa~&uI_dfG2bDK#IFq#VL*N$<#Od=M15iNBnlwr9MIMimOkSR_y_&2n z6$P3AW0O`K-@gG|NXsA??t?{*o1z?ZHv?iLc7}cu2-e~wBEcuiYeq#4`6I#Je?V)Jf>ezOh%xmZJ0`C(c zXd?t1Iftrp0aYaqZrlePZ5Wzli20<~a%@@UgI`@kkq6iM7fSx5?BD%!b;UmYXju$l zilc)L(RD21VBzJN25dHuaq6!L(3{u`q?Iq($kFq7{_^Ez#C*V~9AabJf_^-)x51eX zM8Nt`>v}61td_w&R`QsMIv1=!gl6h**?o2tdhzis%Sq9H&=(b3)@QqW~VJ|X8)RX2CY3CNu{eA&S5kw zML|!!kBwc2i2TH;wpit7B#POz<*BvZgEj_d8 z?-{H8`l-EG4e>|q%}+y%N80B0W9?$h+0z>TjyEg_I*U{b(A67ZtnIU_16>>#-h&K9 zW~NZr5o{9X?~S}|zWC)|hh^wV&8!{y+Adc&1=IChqDRjcElLC!-=F;b_jeipfIg44 zwKW-1!@RdA@K28yCuv6Dt{PtnKlRgz}T?7spxE{tz%m4m9q_K4ryiD-+ z5b~8Gt~-8iXZjEPdKuv@QobV`98}J#X;(WC}|LoHiFH7`%l!3&^!S& z)&tddBo`Wb!|{R2%>Q?<>v7x%3p*yP5LzRd`V90o{hc}29fe9NDqm2IB+w!<<`<)` zd2>Bg%1AvY@x-G z2Pe{5H2Q*ZB|%vt`e*>XDShI&knWN{#KW%JUF@EIIMv3l{a?33&Suh_5#2z<@bL2Z z;G1qnTy;oTcs~O&J$QNQSKn=BP3IR)<1{zgllmW&&0BObfX=h;tvI`=WAZOda00Hfzgf4-9VV<3Vs>A<{5H5I= zxP;`XRx3cP!^w&{A|xxvo{e}-dF@dSb|?_=F|0A;kjrV_5?>?WvLbAeKf4DHK%Rcv z$$z~!UQf&thPa3vdaPq zaRhS(U&(aZ_OE*%^#!pI15P&5cS3HF3i$}mX9Op|NG^s<4KI5EdBW=QxC;r25zgUA znnpZ-6?ixRPDq+=k?8QRE#yMdDTsg3AGnPC4`CuO?fYF^ToAl`MzdeQs>f~p;2t8o z>938HLm!4@mN@wd7ab8C{vF1r|2AV_NH=BtubtGGbS4Qniu{B^i##1j@4rThVZ}2M z%0FI=Jmrr0+G|z3AUOq6mJ~Aag=mI9L2Hg1bBG}R*=j2ozJAc~Uu#*xWYAU+trTRr z>nO;WXdHz%@Uq0aKzNbZcQ74B0{hLxpFfzUaS%BM{_ed=GY7s=`|vxA)FN{m5cx|! zOFl~@{9o_hd>@Y3XoykJ`rGdHxkr|f6p2ZGfruWj?FRlQR1=4Vg*6}At%H~<4MWyU z&oBU6j%P53))G%hH1;p+pc>xi>;HSd(ReN!8;#06&e#quyGdC;oZfYaG;opN&>bs7 zHB%B-irJz06NdT-p(#V zXw4*GGp8{@7C;b^o*K1&U`E!i%*YlX_0WM5p)iNeG_2+X>arR94et3MDp(L%Z< zFaK=)sG#4!-h7)1BA9dM&Oysmrlo?s1z{h7jzWxRfR5JKug{#cqG*60gD4X9HMB}C zD)#pE_dgE^xCnX}Q8Lg7!cdM-rS6R+Eg8x{lu4eRFm6|D{KN9Ei?!JbaF7dN8V({q z3b2lCP-9LdloGVe#$}x`tuEJJ1fdheS4xsAsC!@M4u+c(zj@U>Y$3Jy)!;Oy03d+P zj^vc-fmA3*$53A%8)dh-1WJ?;M7_c?7&{sS$GLa^vA8Bm#@rH*j_%@a+ivUZ_d;R( z;a!%3>{Vd_;{st_wgQ&?Y+|vBFwcm`tcMw0JpOEq(kn$a1-5fZic#{Y4WU=MNhPJ$$$pK9Tq8 zN!LyUvegE$=eF}u0B4P?OEwl`mij6Ywn3oh^KRRrvb6$xHd`s9LxYJ(DkG$>3uQaJBjOHx6BCqN%KzaH!C zgcHp-xx0}9qMHop7@W2RQc;!HPnB1uJTU&{@|}b3Ws=?3Gn@8E_ocP=6y2~<3e;fd z6sEY<#P&i;{`iYHC8-x%=&dwPEsY2nncWfu@D4c}TUp{qodaCXud|OP+WRh#> z)V|yE4ny+szt&4PZUa`FbRbYG*p7i&G!Vq$5kcNW6BdeK$qRd`AEsmCK^y#8C`JsJ z*joHifu?g=6BZOCVQxOAtfRBkc8dq2C{qOX*<{aAph1w#%4M7Vp}t-b#bQiODf#)6 z$;D;W#BsE@_XxX|&jy$H#x1BDv}6SmTq&M{y|^QLz&o zX+80(w3^MA-xsocT8VI*S1kapZSsiuQ)pVCH!jEWe#x!B1!}=q+zgtR^v7{>&(AxM z3=f$uVaYk!>!HTX2|aQAxM;Cr2tg@ECW;W|b<#ys@Ao!Y8}UCP?J zZ(n6SEbifU<`1pSa2>okpq#<=CfV_-9S4HynZt)7wyK#EMXM-uP>Xz{9Jhx8Ke{|S4+c-T9SDyA6KO32f zaC&fyqm>gU|1ACdyn&A6s|v&JJq&%jRXBF-zN(^oKFLk6)6pq^cK*(A43i^?FP9SX z4g-3;RkHF#&y`DuR6_k7og>yaP9EhiDm~zL=w+TTXJ~n9bNw_swJRgFYs53hRR-Em zeYOfpDzeTB`{=e*@kgkaFD!A}(ldLXce+Jm93>e?DP|!#|K#U5x)CIe!MMO6mIw#& zwTfPt$c0MOMVv(0s5@XJ(km3}Xc&c<;&mBIL@;Cci_;R8UGoHMJ^@Y zW8J*=qdMBC4oyOW$oCSDRw1=40_&TVjg1%#FefDhWvFbO=KiC>`?tE`$Bv#a*~x0| z?T1fiZ|Do-JW_%zI31ZtF5 zBzE02UPGV$kivh{%5C9^IX|y|io0>P+)4L)EAH%E{u z&YF~wOsqV`2NhMc{y{9>;;X9KN{X_w=3ElBzi11GPcRDdx=_x=T+CvUVJLsq+Vi7t zU|_mM&$nVjzWP{C4jDRw_&<=t(K!%p9fX4f9*wZ654w@DH{vLk6FoX)GGA(ItJrn>bKfYt_Zm(nL%P?7t z=j^oi4Q#EPrzwZ zS3aB0k;UQnDVc0|ZPmVp)BH|D!e!5=DdY4GMip>U+ZjE|OvTHb5hzS3E~{F{#7Q0U zNYyUUUqfE1e_?G8?ehwD!5W?7dq%YT&Q@Kr{-&te0gVmHqkdZ*Gw)-SJVf$9wzlWY z(&klr!$j|eV1-Pgu>T%FdkRF}XYsK}DUS>yl8RA06Bt^G9>)I+0OGR`ZW#Q9M^g_M z1$DjYdTGuzqznOhE@qR7+^T=$v0lz+gE)R{o?N66z8JIT!*pdu<;jxsDR0dW$cYaH z%d;wvIk#Cn&b3Kqq0Zk!oga8sjOm@7(8U-7S;IY(y{&nXi{Ivo%8oDR5nE$sLSxts zs>qz8ZvTPFX|9Q&OSg?&B+fU|AE=3}O&PIvo(-LE=IYTYyFC1MmNn^=zn@ll&|<^2 z?9p9jAsg$Cec;%>E}vOG)33v@;ON&v)f!&12p^)RXW|%RcS4yf^j~N}GpmI?aelY#MV*DFumC&yHrbX5gv{smw$_^t+ z@hu*r$pnE)76okx=xMTsFZ*n;K7kvmZqqrTaZFT4{?mgw@Ty8QLu|p0D%Or>-{(ZBAr*qPSf6OV-S4>2dVazr*WHm#y!4Cj@LK!(0TKl79++XdbQ>#(uoq+@J zBOG?U^-~=9Uf}w=5td}@x82HYBLX!*x{o6)A>u(?K4K8VyhW0PLitp9s3IKYnU`qd ztaNYfr3TS`V~O|pHv+3PM7f989F)NJmk1cAC(D@pBO+=@g`nmAA?O032nZ$CGSrs! zGTZcH3#ooxJ6Hydblk~g)=&OcuU}|+1c%j}h%!HL#4O}7P1mridQALn$#7}4uYF;) zHE%xtT5Zjpo_LwO`k;6G>vMhX);STs&jp|N#JIKG@QQgIKGrm+;ggi^jT(IrEQ==tEyL)=y zz||C?zTNsq``T|-We3b{pCJYT!uRxA_j-Qa+TPTqYeyr?M!>x0=!ys?{59f?6Ohq@DYv=R-;?K zJEcF1<(C%6N~%!avIQug`$QHiT$T3%v1#PMk7dB^(tl5K@{+NMAA z81I*CdN}zZU}s)$Y{K*l_MnLm0h85qk!!p3+4YuwA99-dbn|V&Ed4;SEcuhBph&J8 zm*t$VE$-gk*LPxRUPO?`K1ybtiRiK=+mD}-BY3IF{t4$Rj6(Y@PvKt?;jpBAznh=_sqWz4=T|wPQQ{$0zH|31 zr&3?cuYjA)<%PwbQd`*Bm~u4L^hNap7O1t7FH2nX^BH1_)rpUP6JsNBRFFoh(Y?LK zBcHvF2s@B1Lg~6wZ0You&!0D7&@HKX4rIol5CefS83&Jqp8(>yxFDX}0U4cZK!9@6 z!0Y$#p8-F=!N$hsYjrikTwTAs`o!TI)WN%U>5 zj}H}m!laS%skC%G2&Pfd;|Fx35t$=X(zCGeb$8!zf60aFKUx5P7P(7_P2BclnzpvK zWK=E%sv!`jV6x%YP5rAV57>^i?>m3~Jcbpae!NjVDG=Q1N%Zsl0s`DYOQpc%nzFL8 zO)-j+=ymhEtT@d&lCgN`)^c%kM`4lyI*{w?Vx;LX2?I96b=&EA;%0xAR91SD$}{Xi z5U+@eijs;D-mc2KYv&-UE(8E3&``;pdVnW1I2CkRwVJD8|^98vs+Hspy z?xjCtH0fL5GBmHd>yec9c6!z2PHa8BUB4dYM{oUkFW)U)hqKRx)&NSHnja}aH}p(u z<1*i_wG`%YTXB8-E#@xMpRx9@Q=ggAW`>!reXu^#(CHjb*)UMovDz(HFh<0Us>!og@mwAAM=OiclkL;7)~!FuIbuPe1^ zQE90gsn^#CjZZ-PVKvcp4orQB?^z%(bi%k6qJ$@NcwnbOtu65f3~Ho;4YffZ(T0GE zdIPmY`I5B=kpq z;Q0dnt#RL+CYOGHfb~gH25H(2o!j@brqn5_E&QaZkdlkeio1WTTBD)9ZBwSBwq}9D z#&q>%-vZ8n%ars&`zQsGm#*#l_3M$#>RAeBA-m1@)@`WP$T+vPv@`2V(-W_zHH=qJ zZ*`pA=eBYC&wJ@^OL?Y8e_y{9xBjfo>$4mU_il;K%ZUGaC^b1j(uiTX*x43`TwnQS!`+v63KCU9h(`qilKQ7gXZe@SS09UL>* z75y{h3xkF1E9p5=r$PgP&lgumShd!z+rYxXj4>|!bSh0YIah-soKoKoz5Nm8YuNQm z(O1>=%j=8MA43*Bu)6mkuFlGO0j;Mv?S@X@!;BNHPxo2VyV25Ve@b;{|M=>9Ox zg%PiDiY(ieU9UIIDXOVe_?-N??tNEPdP}R2?yFP3mMbi*e+Oy3)KC%$kMIxo$d1{a zcxLQUlH%(o<8R*c$<9iUuOVe+MYc&T+xIRX2h)?! zH8ryPKSn5E?8NOqZ#xkSso}u^*02kUt}#Vt)uTT)F3y<83+@Ke$UqCl{q^fZTin-P zz1on_o9ns`rCrQSxM5)MNQn(iF7~FMi|5fRm`5Cof#Nrj8nq)IikKmi1k@cI7DqF| zkyt_%{2c@!WVsFwR-ksYr3kLt_vz{Pey<-ww*{@m=Lmy|+YtgN4}X8!{{H^o!^1}c zq^vA0uOn2$adH~R)!(^s;s(J;K2)j63|k6JWAaW)ItjUnF0$A+ZndML((HJ3VR1Q}*f0 z(<#r8eG~-~a}3-2_XJYB3<>ESZf1}ubNSxU^rdrW#p>2aEdqk7g(?Aouh>p@m)&M> z{bX`6_sB4Ug0RaY_#@% zQj!S8h7Ai@*>@Fdqt^rv#=9}Llq5&;(au zubC#LGmKg1eC=j$wS8n{9tsgCl*+xzTjrgss?2#4Cz|NejP#F;@fqKOpHb=5G!-5B zSM%BmCI+g#UmP`O>FoI&$YEnB86G^FQ_G@3Mc_l=&+bfzkWQU5aTdUJopWSd}ugHr-_XI8H z&rY~djV&oZ-ZPe0*Y3Uj5Fh_-US*|Uh8JG5`JT?C^4EAy`TL-MrP09m01xNLZ%Lo7 zdrm9wWnl1n=y+)#14DE69bGaR5513U>%J{y3I{r(a>7~b;09k08!coR+tEjgL75!= z)eieslp|oPltA7taC@jxByyE&Tc8r#=h9y*qmoDjaPN!1ecOrgi4eqKNVc&*u>~Xa zz-l0y{r&s*A7^X=>aqwdc4&*9p@GGP!ERGiQ)8hVMMC3wuF=s)AYWLU(7*3*ZyHjB z-rv7Ta-1lZm@}^X_X2K_a-s9R@5x%y$V60=HD9BqFt>ctjSb5>>f{cy2N;nYu5eG; zWmr};mGutK^v83$*Y9U+WSQetQks2HQBkw@)j_c!|1xU7kmpJV`j4|;T_dlkZXJ20 z^RD&VBMZ|a*_zZQ40pfCzN~1WJiTwSup;k_qcF`%_cQucOO4Z~SNGG3o)+1C-~i>{ zjhOMOhdYM46~#f3q#;R)nADv};XfKT`@Kr_pBUbK|8***-%h&ns>IgRj%x2+NY4&& z2>52ba8gM7Clq0|oEN8g%yE>fy^u9(|DPNz9qC`!$)&7xSKL&( zd0}>VSheI^Lqplub{Y*Ki4SSqm*tWiY5p3QZlEw7Jy2d%jnlQW?`yhJpiAa%``V38 zbF(zhX?l!j<`M^PeY&44BjCW{ael!6g1hs^uv)bk%&i}7hAU?xA{(M7cig1O zKEA&@p5V`Mf)gbJcBd$~>f~fPA^nC7p$`(lcbeHW_i-@(Y@m7(7)U1mA>x$)_70-5 zl|rf7A3s7M?TNx}Y@7}u(X;2zA1blwBXg%9(zAE(POM$aC@dTYmv2*30E!_y_wB2I zAdM&hppMIr-JX__v9SxmIW!H8#=KBqkvJDewC(NNU}>Ml6kDjW)z#@a^WK7U=Xo{9S;?=Pp zY1U!%so^M31~NbDJF+CeGEGk@>hqR#n0mdriEhH{Y@ z-`X|Sc|Wea%Cv3fK&+gbqJp;1mBSY$BsPiMTc+nUJbzD%KCAWFGnLEgvhi^p(J=(Nw-MSKb9hcs>C#~#m8xDNmzLaIoeEOJA&tj9#D<1AI-zs+Bznxgn z<>hWO|I1asFT;<$1Wlv#d+$~Go)LD zAOXIFM}EEt0m{nrmWHOKokpBSDi>I6qLx}nvfxavM@bPfxw@vNe3n(HD)$T8K7l*) zwGvw}Xzm)B<}uL4@e2wPg+IbfEJ2R8L-n*2aw(TSj*m#_o?|qWWjv>Q>oUIMD<%5gj<+Ha+e3EH z(SG(gatNL0hIB)hZ8Ii@H_nS>Z{ypvHM!J4F)CpP??0gXi2K+toCR%N3l8MhN!gk( zZx7b2;bXAtRx8{o-CuiHWR%LQ@W*}Cl4Fe)jV}}|WSBYmLi2_AP9L0TlF(jt8?@QW z?X>G>vSx9RSAYF#Om~w_pYUbGag(FpL!%2<#OK{lQ)?9%{ycY-<#U?N@J7ek17E*p zOH=%AvOi_B=iR{tyTe<>oT=GO7`~fz`lcs|94V90El-RVcyBMnbcI3MNRm>zaAD2W zv>(CjWi9fN$z~!8gI(LXZKN-3NGTC?n28E@_1!$OSuPzK1k8u!1qcEhe`mJoEXP@6 z!g;`Wg|85+7@_@$C}v&4LoTTBx`5@lC@1F&y$t#|Um;s0^XDkgqW68#32P})Q`VXgOC7N!pR$D zv|w_(2}&6jy-!v5@L6xNl~#e?<$RJ#s(I6ZL!-r&%!uXT3lSEv1BaTv)xU{YxEfl9 zO>+<#K5G(e)n_MtR@g%WJ!PI@{QRQBI}}+|5pfYT(fnq2*|hPr)gJN zpR_%dS?t@Jov$=dDHqqaSOy_18PW#*+W@4aIW7!oCUnpn^&=FX`|5veDIdnW(@^!I z!d{9=(H9;FuZ0i}#c_gUh3CYHz$@Q?g7Ou&w#3TG4f{8{3W(EY$0k`>Yb-cU;?~>l zU)!%Sg{#wtBykvZMxCtI_?SO#NH4=oC7b;6<;(BEqu&A~xm1Sywd5ZqWj}};{O6;d zzY^d$e@BRh(O=S0n=)6fv}5;goQ0(gpLTgD&1F+hY@>Gc>ON=DF_-2!WsR8E%{9#= zyp=IVoLa(!*8CVPfK@d`TOVor%McZAc*Roo@dw&mlDmrZTxZoM98Z8)PaZgJi^R(yXD^)IR)2hcZH*}56ejJEm zR1Q=&OW_%qG`H|bSZi}cB=yMFhZ7h2cEu$;HeO7r)K})SSgHEEvUg=rr{O_+6gP#G z^6pz7)$I;=>Cbua=Y?J2I<4^Jbt|JC4O>t{+W0Gcr>jRcJg#B3?wJ~;*NBac9z6f} z@ZG={Zy1jZ*OvrZtvNWX*yCE8qU2Y|Y2O=Zcy?>wXXQej7(wcf0XM^f#lN%;zUa%i zSo_Ye<(#|vv_$Qi`w)a;(P}k;&|!kOHn5s0%2`eqQ0l(e|t!G*g^a4aTL9{bTp2biwQS04oThQ zR-nSoF80?;aI$m#8u)hO&Ax!=8rL3C9rXJx|Nn9I9^hF2Z~M5Wq$yjJ%*ZAoltS4n zBr{}|9U;<|kR*hJgk=DV%DiJcXW&O{0-|zGMp5uQUeLmG4_kDZculMV9UFUTU zZA0JJ`g>C5PH^*Hic3p2Vi{McJF)fSrr2?b+YKG6%7)JVl4>-S+N2)Ntd7}KRk3%a ze}a|vrKRQ8;EKJ217OySzdN(^c@Y$LAYS9R7wZpS-++MXo}N|TUq1lq{8ioZx+CRC zO4J`%^PD`nn0h-SUpIS)%;&jgC$BeJ|+hR%m^n+xc-3OF~&vfDf;1cR8Hi*j&%) zy1IgGyTj+!KLh)t{u+5GPKYxp9ug%_t+t5UHd@CjoN94#dNFl~GI4ofZBmcBS$Vwd z*Uu%6V?o+`Gm_Kn&Wzt=TrsQT!ke}}UDD1?oq4@geAdaye#!b{Lz=(I$7h`+1guK$ z|8V18^lP$|{YQ4OyREXL5YN%>h}O}SDWj3Jn!F@*E}Lh-Yo$P(i8E^Tjq}vpmto4^ z+euE894SuwRdap)b^!rD;O>fbo>ElTXxH4NNZK0jWOU-n=d+uOCmp_cRTmT%#LVyzPH}m@I`@9>? z=iffETm_D{(Ymw>;v|Ty8!e?6hYzey`Ss-b=6=6rNxq?c^iSC$FAlcEy_vl-RKK4n zIGg7P?MJmEv`%`-U>-AZ`ypd~jzFeQWk#O^Z0K(-PzZ<~8|(AlrQLCI=$BcRUFS9D zg?alW%QI&Uc|+(wJIz(R=jN*8(=d6LO_B4juCZ1#RHu{YWiv(2PwY1T-V?MPDN@xB zFIDu@A0O&143<~FNT(n>Id3?NI;CBDV$0Fv%mMq~Z3H$;y=tOK_I}^uoV%VKV06>Y zd?oLSRo7dwKMpNVJxuu(SWF97NbM#5P=g@b{MpV(OQU-7si*$+s&pQgOR^5czR%n) zvV)Z~YAs`Oo>6ey74=gxDT)^_n!x%9K*zD53!tWsVA@^LvDo}KK_dxna?MVn`QXlcIT*38p$vc9UPY@R;q`+F=rR_rJo|TVDN)VP>tYdefqH zb$V2xxpZ65#o>v8IibJ1caS*Te;b_x27gm%8yjMy1K;G)GwF+`EuY!m7M7t{>t{x zaUJ#Il0^qdxlQ-Xzm0uKc<{^Y6?gx0Qf{YXX0njrqVBMVvTJcd+AMrgT3#aM%|C9t?P*na^8FbHfZHk-Z z=~HF5VgF45yAIZX!@Y`^!=KQIuVgGI?;Ray;5V69Ydmp6%+d15?@Yn|S8GyMNyjG! z)`j+|@Se~w-A5Gsb^|1v8$Pz{KdzWLily!JH|>49wBAHiN=Hwf zq76}y1rmfH1I#jFO3wj?bD zbXY)#2zazv_KrLp5}^SDcbjifmN4T_yvLfFTisj7%bIrK(zq`b<*$P-l3Se=ZG`pq zuHLkZH)*AQ>h3}RSucAy)Zoe&OD(A#ONfyd&{2|IZKHCn-|jpqRk#iq(@@r61{ z_;kvbR4DQVvI-7T{BgK6zN;93ECk&4)>|5Vi ztfbV|u6KN-_!yN{_k;W{T3>ozqNWqEHMZC<#n|JMu|;{BY-%mW$;pFPc7XY~NM6TW z@bk#psY&TU^)luVDym{e;jpvk22lDqKMbU;={b8ZiIZ=n^I4xhnRHD|I_FKM(-jZx zLW2*`oHM*}($1f@GE!B?{@Ce*67m-P5&RT)Xo}{I$M+A+uH4=4>-*$9l%+-9N7Dj4 zBUB7LX8(@5(w@9}f~8u?Z1Z(=f&0qovcrMjYgcriANolqc|bp^8PJoMC;O|Fh7Nx3 zMao7VtmP^8j@-qG{zcOT$C2j9@15xkwq#OG&C;pEqiJO%{8o+J+2h|8b%z)Y85Z{0 zk(Qh{IV)wOed3tZ$yb$gW+QMrM-B#Zg%>lH^HZf>w%qw&gw=rDti2%VN;WK|z+u>5sH)>Gl6`LKv|rJS__ zMY7HbvxO%QY&X29EQOsH$7QwU==HLNtvYs-QP7{f5un7&A-TQ}`y$GW$CB94 zzBE+Vm(0vpa(e57Qf5$P!3JRT)fJZZ7>fd6id*lvV=Au z0J5vQdy73#4@e#x@tx5t{StT?j5`VYWsLs+=ueswyDXOYpfL-!mD7jJNOFJeq)dML z_=##wYxnMR>#rDY4yHNHtXz0KAHV)N065CY+_o%{yRf_!BSgk>DI+s;xdxN{`|>6GQ=JDj`|O1 zd$R{!XxSPc&xY=G!`wr;PDwR6Ba>G<$@gM?WmEkw8k-0IgM{YHq_Ya8-S3l69UO=` zsQpWXhIVvf#7L5~*+|x?>`6&QpXl4ek&$&5ip~W}ZKD(PWSv%~y@<+j-H5*FX&`mb zE60d&9lqAirRIYDr;F(|H1zMseBCvj%lEx+aR&)+)PB>Jn(603Hy`aVN-g1L40->e zyS18v&Vh_Z)b+{ksnUXLSFN>g8?pu|2nZzoT@B=Tw`n{*s=xlNE}p3-@bJ+E6+y6Y zirX3z{t6is90q7{O-?+ZDYboCLcHi86`i`Nc~rP&GN8ID!;n{03BHcqufZoo|#KD}I`5e>_`#*!Sr%#_|qV3&6 z&_Yn3x_NkHUGF&w3iw00I1{MdAexEqo&!%U>gPVec_v9X zHZk#z+~;DepRK+)-1bfMG^KP|?%5mCHkTM^6zD}_nN9yyQl_nCSQqm^k!_pW`q^F`z*ioqKeKc|dUBuV2FyRj4BouM4< z|3TfX&4%}aMaeHCsICS^SS@31CqfpkVmvTY?bP z6IPwKjSmc6zGh?708PdF&8DU%xwsbNYuBnlWk}D+U_N=0T2fMy@ZgEIS&{*9vJ?@oeo{Fs(*1DrUXyn zl4B2b7p%9rwi2;&GEpv_AN-q6D(JcCIY@|v-fxT4E87wy+pth;pKa+|>OhrKxCg_v z8*&Cezwk+5Zg$2b@q8>xOsu|tauEmGskiUgHItHtCdN$fNA211G1<#B;K9RZQBl4- zdDz&h^vTNZ_(jOOyb7TTA;Bo=s<9=aXxT(X{qE;m3WtOQ7Vkx2ao)gC?yS1hL7L{l zsqO=sPUOgp(_!I#bN1X?3hkn8&#uw$KiZ!;B?QE3hpOvpow0S+@_%72W4+HesQ?4I zPZeiJoMhCVh}L0T$Qh z#p#W3*P6hiER*}FwNHW-r4`S%d~;fP)W?|U0&W$&qEa0BQ+4-!!mZWqdrbO2_*Pcy zqriO@65gcBp#A4+C{w%Dd+%wosL%-ikQ|=ELifrVS*PVQ{KHFhTuUa}d`4#+)R|p1 zo_8(x={PSPxnm>Ahw)Z-ro&!>8X-{}-D&juA&6;`t9u5M*^X#x>7LQE7R1T)At>{- zmq0-9k3W0nQ&g8a7HccXUV^!C1~tto*Qvu0P*;FhPgO8NOS%+FUrSjn3$QJzX(A7<%t;N76YuLIDA+MPXK>j zQ-Ihgtf(|KHKF%{p6Fa$%W0uu8rU|1qXS_OVfYpa@ge_^qnmy4s4$3(+*M#Ep;A1cngB;-}U`--sQCc3~N8^Xw6e z25&E!a?s~r?sOB^2!9$fo;&xW=%?;XOHqD)LDuXlBeA{Aj+^G&FN(UCbZwWEyzRco zcz*M2#j|=d&%Y~qjgi8y(5Ac+wyUxz+h2ClrNgt-pdjqxCPVdPrJIuS=dped5>1QG zq#ui}lfHZEK_%owUajmIon%*1-NeIS`7KlAC;MjmqmTsGB6a8m4vJG7%zK){$Ithwtf5dFQCW6leQdaGu(Zy!90|p zqyXQN+E_Nlrd1DbD$tdy%gcYH3S$VYeCEuVDBe6+N`rAw1Jne`FybhkI4M;(?We@W z1DE>cpe7=LS-J_V2MD7I;9QTl1riICW3(6=c=plWoq6i6v3l!2qZ#k3!#5?R9vOY2NNTgTYVD%4kPuQ2 z_v$RUy{+TM#tsXerJC0_(JGCw1b^9TpjYtaUFnXmHD7EjRu&sbl-!bJ{Xf`&q(%ZP zFF~dA!80K;lI7KWDf@!_>sPke??22{uj+QgYv9u-8NyZ!T~MHQvN=5IVev$1W8=`z zb4E^XCnlukV4;$r#Xm?%d0*rBL&wcz94jz>s=yumegL!iU;d)~Bp-2EvvZ8uo5z<&+PI~|>7PYjKHnR4_<3u5moBGGynNt{J#LG)7Bn#}THnoVoNAN_+V~(@8jn0*0x;3!&Jpz8p#Hz zb8F)Vw<{jFpAZV7IgH#aFh6UT6ehe#ak=SE*&oG>sItCZfwFDRIqj%WFvu<$5Lsho zRm10%pgAH0B-Vb4g^le2YOhO6Ut2mmEiir|=!+ms=?tj-o5mHMSyZKV%+?sRjA!L3 zx_>`=>vN&mbYX$YPi+Styk09fk&mW1mjA;#hp|F^eO(hDGk4yu2c=Kl7puE2b22p? ziYKa)qiwGj{jXaMbiGs*2#wYY=gp3#v+R=TL$UTKI{FAoy>`)M4n&z?GadsY3qJ`M`WlpN zLY${hN8;1icSNcY15)BLK#5O~$xsNWpV^-dTaG<@_d?QT4B}V24^i!%P4r_*YR}72 zGq#C2nwI!k}}!yyLAR}BsUa&Xq5HRG9-dmI1QOg>HsCPVKHxQv1>RL)UON|q~!vs+&4twwNUkgAzJ{Xu~w z#F_oLW+&6B9U#2KPgDNyin&!6e50Fl)Y&h!Zsg&kgq;ZnB?6IpXE@P-N*e8$+dqH)tN?Wo)?$M& zy0{90?Xmp1$8aGphk3L1&+;f(yL>HLD%qb5uf^X!H4~uxw4itJzTF4|(W7t>xiz!~ zzQs!zuEc6_Ik>u7fH<*Pum^4jbF~8yu_sPhE!*YEVnTImF}kR?>lK5s%?&k|gHbvP zaw^9iE{1DaXVcRCHZ@Cplp%BELFuU<%gGcWukKP%J&?V$*}y6u7Qs2=C|FhBc4kjG z`@cn&@r#LCcqyIasG!uN+ACsf?&9?uSjT~$x zcV0Al&JPQoj%u7)a)|Sd5G%Y|N&iED4gq2$SUIP}#0cs#eAG_e{wtiCnyQ~~?*od6 zr0Xr9JU@p+jpS0O_ivX{0XPJAN`6=hzIo44i!j{AjABc#i@87?Bmo$Al zb=w|;cX!~eMw6T{Mu)2pEO0_d;@sH zx1M9yC#Mv-z*Lk_!buh?Gr(YN(qa`CwW>sJ|M5XybBTja; zktUs*r;1C2?p77++hK~3XHD@8$17RQW4X9%zV+U@=|4HMaPw_Jky!38#I_R`{!{d; z{P4NVXwoD8whb?Iimk>>&U&3axawWhRA?~LbzAs3iqP{_3Blo4o@&n>jx@5$Hv2_= zh$_0NZpQ8A5r4DERHrpZ!6&_IS6{UWS*$7YtnerDq%F==_GoT*z0Xw?P%~Tps`dUr zUNeE^JTnS|t9FKU;Yyrf*u6k>|D4QhU zh_nitq4caQ!s`%JHIhpu{LfEMs~r(a6?1_p#c6GhLK z{PD1G7&IyJmB6!R2SJ%ZrM5KmV>+P9I|ToL#*r{s1SON;(Ez`ifdo${P4hodM~4|1 z9h{xbpucIa87Y&vxdcTpS`2_0PeAQ!YD9f7;f#N3=1F1+^$m4gch1TRDc6SSm9xw3J*l;{<;iL?cqSjJUW$&sD0y1Zkh zYIuky`8bz$(CZLYbt|#mx9J}4bmyEOrX3x>n#h-y<+PH>&Bdu5qWNA!GnOkMKl>?I zTMz#VzQ9*e73xO3GPdTFw>ml{NUZR?GnOBe=QD0xYw-JQo6P%#T#NM`O;F@zCB17> zp>}VdVPQW=+R81&_KSV@3FW;R{FmCg3p{r#YMG6MJPXlLQt=`SFObDwjIG{(td{Zh zFJM;IXSB~eSy|mk;v102@o8ZEYrXFm#kz^p)D1!8d1K$c`M!LuE%I8W`L!hB$pn4v z{CMYnP;7}JmZ%!Ry*|I-pM(XEPrs|gLlj>EkY^53_x)FT-mkAg{e;!v^mpD0cp|fsn5t|OemWHsb0gGiy!5f51v~>IaL&Kpx?Z%HL&=hz9_`ioS zQo>sR+Cxc|{}L_B*LTVcAiOwru3{-;UU`6#QCUf854J=W1kA#s2jUYj3d*~?3;u3O z8}@W}$0R4O>W9SWrLe;u0c>P~XRM&`-YW|BbO7#8o;>Mx>(-@B5dDteC(17<@Ksn2 zE0`ZwT`M(?Ei;n8I>V&@m(+NCPR9R(2M{p=_ebZuh4>jB?xDLI5YRNhloq1E)|qBx z0WnDX*$!ei#tGJ+Gldup1`yg|{k?*9P1H@8GqgwJA?X?2wMXEh{umsTxwmugl+}Ls z#R;;H_|}gQ>=r;orjbO6Jqq{!EtDFYi(QO|4?orCEwj;W#{OhK_e+`J_rUROx^$J7 zsK(&IL$J%hd)&Bw85)-tgamVXpczj`7@FY*A&HdsevQ8#g4z3j7Jm)3IscbnlQ$g6 zOih#fZ^>HE`n6M1C)d^TzRf?cd@FvZK>=lf(vwtu{Cb$Ge^-h9oGQC)Dz_~D|2J%> za$1`uXL90OeS?daW!X?aCN_v9HgKzj>S!3M`xX{c6lmR*VV1Xg;}?>&g=vvJjMGIn z@Gwyv9kn2(27o$ps-V@U`b6cmx$=}t>uE1)$R zBmCu@$3>OODJ{|n( z_(Y+dcCTw$H-xy^L)CyaOZXs-j`kY3B3S0BM$&oSP~>Yq(dXqrI*|BBBHHO#a2;_s zT)TFSlB!SgNGEi~wJ2Tq`T0LqRNR9xY6h@VlwK8&53+Fb^0M>r_=BHJm@G%n{&lqy zfrT)(Jwm5W0u=Q=IHyn=kr37i;6V@MeL(b1Mt1fGLtZ|q{0~sPQ&H+o**hh1dG#=Ek^9h{A)Elt}}hRJ?ydRDzLFQ4UT{=VA_2yqDsc|IA}Q z-V>dju1VQ}Bn6$7$}Ot*EPnlIQ{fXX2B0287|m_ficHo)We zFq$M-fy(IUgd(Mr%J;lu=gf7~dn-Mr89_nn3y!#@F^Q10mmsFaC<%c;ZZSsLhw>#? z{G(Hu>C!q}J?W4@!fROkSUWjoV`Dt6tm!{#Tc2((`J;??Ajq5N&IMgyMLRzOdp1XC zP$DBELDwZ>iE;!d01n9*%vCnOQ3@#x^!+HQxF?4qe?rReAUE z?p<6o-iDQqXAcz9kjEYy{v`XBOoKK1&e_8I^heK7Tu{AW7h$`yo{>&LrhHK2_0o7q z=Z$L?&5^gR-Mr@dT5Lp3P3?@V?1Sw?Qkhv<6{u@)G=P)CdQ_$t-T_BzbyT0FZMf3x zJTXK`Uwd5mnU1cUp}N>D+2OYq!y3B!Dqa~ru^QvDTT|rx6;fni38l`hemumot)sNH z-I~oho+3x#!S8w}lDO`tb(YnZf+oTd0`#9@dB*khno_PjIeVOM=57`e_b5h{eT%0g zzWtc63`{Gc){(d9jhu9F`a1Y7uf{O$jCzBU*zwDx+yWch}py zc6=(WywYfKz1?AvdhSx}o!(>HNaD@q8mY-`;+p?dOwGZLySn*ja~>s(0SWUK;y*1d zErgIs!!pzjk(gMViNba$_R@-HcLP5pr09iyy#SChC3TXxHovFqoHDLvCG8d)#pq@6KY*llIbORzI4dBMmmyGGK$?Jl^3CzB!RufZ`4Za@m*wCR zSy;B=ZDeI-UH=AFEZ1kJEYm+ZWUrG`?s%mEq=lqR5ZRP)Jche!>0}N-EFur<%E&t# z14*yV(qfwi!n53Ey2yEq0_Olqv6!#ZXS2HZ+=-5kCPM26pICRRhG~!m=!xK${m=5R z_5RoJONrf2M8GtY{rb~u;0E>P|G*?28|x*263 zg`_hn8gI1pZ>LtO#J!l3x}SIsjxb_~l*I0lUsUw-_wOgc!NGg_-J+?esh_`krC?~t zgs3r$A_#w2?52pG=xqv>%Gqis%F};C?|U^(>~2N>7cc0JC-a*KUgi{im6({Wdqs#L zrFG9RJ69w1Q@KNO!3&Ra_2T7Hv}3fnQnM?y-@wBx@r9+ZLN+}WSBT52CY1-lDlDQk zB+Ndk6!*FEC2SlV)@+L0W}VxE(3jqb*|MW!$g-eiEujG^60s}9x7qKfol;^Kq9erYG?%3^H|MV|KY&?WB{NPaW7 z5HBnll{sNcc}FH*=I7i=XHg$pfnzNhX~gJeS@@t zP@PNRowHEk^Yf=`xZ0teh(XtdUi$2F2{_J8+O5CRza^1FA(3;q?ZE+8d1T5#B#*+C z2>XN)dXV*PQA2~5(b3IN60P7U*hNMb1EMf|h{&EEaPkuMtMHENVh-R zYMjLFdhHwWgJpA}i`x$L9v{se$hz4nrYAiA-R+Y(<((3}i@GeTe{b%)x{=W0U8n-h z{2ScyM7-+KfH&dvi0i3a;23}1mf=ojrr<~MYcha3u?Z34N^%-rt>2C#+EBPPA`P4% zoF^qEfsGe}e(Vs?DVVY>f4{dMI}e=IHpUA3EidD{P5T$R4*m}p07n=RQ9(3H0Ixy$ zW9m8j!_^wfC&C2=aX#N6-^A&9X{6dY$q&V_wSi-Nq5XcFvopcx*ba1_%5q~iyxtRZ zYx%(LGZ2U96x|f|a^&=&@mx))2g9X?P!ixyLgMYz%bM|IgQ&iz*qjJ~HT2np8i8n6 z3E6U|p~vTw&67-iCB?)Z5LGJBDc^(5famC#1nUOg*Id z*ft3-hi_9ATPE>jNyYsNoQjw^X8~`s8!Uje~MTG$AVe;^xY<<#>1O!Sy zpjiYqO&G;uXkgXxfes#c7HF_@%M0vk@Zs}Ed?wuQQ?7_2AHkMk8g7uZzzU#ybglTK zJoPqJR8Jegn{K-C76dsE!O^&$8OZyPK3oQbk?2P;TTlS#GYaFjfPjF^ZRE^TPckDL zSa0a6PK{}DQtdw7lN&!iGG{4iLJ{Dzu;ILdS?&B(9|J%>Cb#cCJ>rG~0fbGCFFL_?E=h|}89;#&fcqT^s%z-ma&Jr! z#$s{;pzQnIKij(>qd$^M{mQxwA@8nq>Wp~Ub&5)Li+BAfncB*};K@$1QQqI~)q~D5 z6Ow(V+wA6Osud3dR%aH^Ab2SKH;ABv1Q$Vk?EiqFf_1oxL zJrzmbZHvF(3`S1ThMv7GZSioy^2ywEp--~^pYd-w+(ae`_QDSWE>Z~MA_NmC#*zDt z+>S?Zw}<6@uBX)fWxv2+m-6r`@{2tsBjUu4R950jsOE z5AOD75fO@5qk)o(VcXBc0WvBVn>`U=gHhH4RKn^mI!RifM4metOBm(Bn(C-2yrzGD zfbk!&pK&EoAD6T6mcy+LcK}6xd`N9p=sS<0DMqfM;az-7ClSSqNtrn!I{qa9io7Q5 zkX<@3^cusJBwSS06%kYL-$57~5fzFjdOQw%AuutK6TyExzJzn}f4@;1{WW%r;4^K4 z_>DzM$`Ce5|K48WSLk#cTwKh7QNZTSh(Z!iWqpF~p8PI#4mNi7!KtYLKR>_iaW5g) zD+l0(#{EAf>c3ZPJAh?{&k#}RvhgFXrr+8j(!0>_y?GlJs6fBh{*I>s!*~Q&tX*(- z!J%(%N?h85|1NDXk$oZkPj7Jn>Ggjo?RTm1Bd>jW+aWDXRx z#A`kOzaH1;qln!S$rKj>p|EAZKs~lP`2U*VCJGT;jkClK%3Vu)8b)DBr*4sp)kwcP zJ^f<)IpX6WiM(9=Y?MYmsC1f!$QEr=$C|GMml0LY#eXZ!jc_w=QxK0P70`L18M$_7 zC86x)`F}pami)#?%?k=5FVFL=CKR&~%O~-kq4&BA>?+-m%QV)O6wK<5>)2-b?@5~O zMO2eTxn3brdU*Ira2#t3;rZU?py#@ue(}hzGwRlY7NIBpJ$IYHmMvR~k!DE(HQ7Va zez$Y~ZVqjhDml!mQgX{ zu*NGTW54b&<}k^Z&dBRD6{K8$IdRsfN{jbj+MM;Nb1M7dFNb@NmWUe}DYUj8Z)lR+ z!l}ijM4z(#5^lqEEOP{9Dw~-NUH?1)1|Wb43&lme@)JKlwr7K>MXy+&Z&&S8)6-M1 zwthd!2cFI18XVG)tZ_-<7boSD@#lPcDU0vOB9fc85azCmYim->u#mWEKtYz6t)!!) z1BMy&3u*H-2M*jRD=TBY|Nb~!(;Wi43hv)gtd%rMtqyY?KK5|D#NdX*uaIH)fxIvp z4!iQE_$|XL7fCoN6($Vswyem<@}4>_5l<{m^3mdAGB3x`>&@QR{>T)6%Vn9HVWzzE zt%)h^=A`A?klG^evi4RktbcuMg8=AD#!h3IzJ*rTwkv%L3HmcwS2SZ=x{Ug5d&Wz0 zSUJp@mfP zp+-vRcjAt6(YoAZP9ge1esc7VM$E@JWd^-sVQLQ@Q6g`y?I2zs6L?ZwMhqtjTPc(| z<(-{6cd>`C0wzNKEj&pHS~3Q?*mhr|PSjSgC0ye{Exs~a(b}3N_aT}%aArN+7q)sYBMUQ-u!(xv2@xI{Ie^FVP4dY~BOwfSI zfVq0Tjyy!+(#X{zOr5~jKnq?tB@$exl_cAW6LJ}a`zhF^ZftCzwwyyy84>X5=5`8G z+052Hw*PD`0X~6)w9ARx|D8xDmE}(>wjOLI_Vw6(5g47|0=zu4OTDJ5vT_E)oH>kv z5U!vIemBn+0rd97d>^q~ygr4>nC%eST8I_K4RHizu{BAp3?0Jz#?H)v_f2}l^BLj+ z|Luxv_lS@3-`Vk>|HWzx((VB)-Su2tKtO;Pk`PIPpFSatmKSa(FV3vX0-Qpak~xs% zTq{Dx5G@^zj68xs2|6XFo9S#GnDnLN82H||^Z%D5kSMb6@TrfeBM9e5yg=?yIRSt{ zcMP%e%cFhrcnxA&lDmo3YfF|7eqU$qXTt9h;w{*L-rGL8^Z);jtMQK4kgkeZQ#g@m z3p|=2ZlZvMbvlS^WEvvBASWiC0L3W@rh^3RPDND(Yj$~LH)H)}tX~{|J;2HKpR14Z z93?D*Y%UzNPQoEL?_NUu!^l=K8a(3L*r-H=ULb0^Wqg5%u@b)i?FEVlOv;+Ds>fR5 z9--zrnxd@;&(1LP3`jKLKxhCy6r_F_;p`+}bYf;FB$U-uqwv30_FKSL4u1KP-6t^~ zX9uSG!6>JO^pB2gB|E=257RQjSp=sxVXTVAl|@1#0xwIn4&eW=UdT}*M8KGrpob*9 zY(NfxMpB+Q<}s2$8d+ji#{aX2H!evG4GZJMYhe*%Cky>Qua%8BZA14lHgsRQ`S#2x zK8c$Wx~#dSvQ0)PugEkQahX32AW?^!&rk^f1-`}%Q*KNjh+K!86J6>FgUtWyc27ct zFnBDUz?o0+RFD1mabJx3@EB2miP6*+oVlxh4twvP7WpHHy*h-obRK;Mk~0WXtgC3Q zh>ll-F`;#g7*k?Ez<%;1p(yWn`?>d(u+=BnS)Rx2BPG!1e@lbGC)mESZuE(ho#!Eb z!`{f}b3g{K)wF}+F+E|OK`7cWHF8>#T6g!t?KJ|F zBqDW*FyO~fimN0SM>H}3>Vdo1eajpF8m~Bpx*W-Bq6Ub*$>OK?4|$iQ#nq1n)1$Dd zEbS3O3_w&MRK)M5uatR7q8I~0{j0E(2)#k12^KSvl!tqGAUzTv=QAV#pr1D*rNo}d zMx&)kr0)q`Yy4=;&yQ6A#~SXl2VEb4 z^N)7N6n&8=>LDVbl*pL^5WZ44?j;gJd}M>JKr|uquDY7>Mvc?9wK-Bub8M3V_fpOE z{ZmUw)f*fi_o(PpWUN_z^kVM_-Gi&$NMGc)%*?lh&5mx-+Hm&tr^Y1jxXDcTpvler^&>8 z?CcCh!4JddT_17V5b-)ZJfBYvU`cjkoCw!(5OoNo3&$@pJw{0dDDytv7PhQ%ET_AA zDes^c%PTgu#J+_<1Ps4?P$dzbu&|pM1Q`{%HE1Z@27NiylG{J%W^6?z4T8YEZrgYG zoUwb^BLoD4>|4M@Fa)Wv6rKeH;ee4ShSIn20a*1FF1R#kCuspWehxr281^DSpfG|M zE*N>e4c4LI(8P6ZG&eO}gVY|_#vyoq5Zj(LWXcFJvgL6D`$!kp5|$2KJw0=fyi(B9 z@79fI@CFzH@cBDP^jJffXBL>0w6?Yq#s&yEA=uWU*O`fYyx!xu5-_@x0q6RTephk~ zkr##opaM4m#`>Xm{^t|AAVTOs2o?^&81TO{*WS@AwIPdw4ryGFF?IbY;;vH1SRxIs1nQ^mjX;2SCr&gjdgBxTCD#l` zn$jy_GHGe)#i_n4=9e)tGeh(eAxy#bF%=BIQLqN@)>f=1EVmlG6gD&yP~)C5hz6iY z2JUk`LKO2c01pBfKVcj6fw>b{cs1SK;V2$RVEzOqKQqD01Hep7V!@~we`#|vf=K3r zj}jDu{h6-`KNw$**T&%Pp@~Wd*uv0MgmEo4nv6!u^bc0`a3FKv+znA48A@eIC<)iWfZz zs&cO;&O5PR9S13YPmawa z_&j5mO>DPD+ju<rr9h7Z_H@w2tx9?jgRizTVdS^vuU? z_%kd{5O9bcjT#=II4^3On@K-!c(|5bgO5C;>C$zuG%`<$Oo~09)p=oN7b~dg= zTzT8>75>N8Zg;-+bgs~zvTmmgr8_R78!V}?Bg`(Y&K#?q*nfx#UZKUdQ!c+L@#6v) z-WjDr-D;lh#qInuyN8ddfvbh=(6=g7% zlgxAf<14j-SGMmJ5OReY+XUB`$U8$F+e3TWRc{(RmhtE2v6+}0li(m_$f{FvID5Qm zC7yC5R83z^;o{jbmsXMqmz#-g)>_sNLwTs)k!J6^$8A^v=ddQ7q734w?Y zWJls!o>rNCvJ^Bu`HKH#L`oW+a@bR9B`Uc+<{f6~aasH1X-E$nIG++9x3}MzRG)1~X1-*6V{OQt=NC!-J`K0B0K%`_=SR!2b#nEc;y&*(51i~vk*gh1%%Tn5 zTxs?OIBu7dI(J)j<^}ajb$wkqD-*hS*^ZhgyARQOP|-{5rI!$~#vlCYNl85-^$&lz z$QS}=%zV2Zt^y^_rim6gj>msyp>JpjK%1A)a*9p zpx3Np`;X!GMI#N$BD#G2E2M?}c`njXVfO+fw$T-I+~{so*kL%ePngX4=a-GjE2Yxd zWk*LX+pHH{wpmlt&;X)Cvxs`uo;Xu-IalJan<1A=E?y%jDhmCv#f{|E?18ifjPwX5 zCuU_Qbkpx3!m@W(MF^b_jP8)~1`jbu6z>XYHAuh$*Z?|4H)Ne4(dC<5Mwf!1j4wE5 zu&Aj0cEq(TKl*(;C*-TL_tApF`cMybj_}Xaj$dc615@b&dV6kV*q8FlQJ!- zIP)TuE`=?L&cveo@*y(bUWvGUmhVO$k)sEvRvR z>}mITSbw^5)?@gdX0lMj+p_B5d>9hZuX-$5%o4|tH(|j9q zJIT`B98nAwtpOPuGgo)!GBR(W@h-qk`Y(6!>eU8lIV(a$v&5yRilz{)-)j_z+cnvGD%#y zTYQ7qHgh&A+9!KC+Z7^v4}U2dbGYeLsiL#=H>OPdv)wo>;-WqS`D zjVecE-@>Q?qrLsjk6Jh0x3A`PUyb>Y_%wEnVz-kYXTH9Yq4pMf4-qf_;u*Uke{UAM z$lh^7nghhd$r#gDm#eq;m#*$3nH&fyl6i0-mTN>u?~3hqX|Zg%Hk}x?wWJ7T>)*Hd z5#;D#`|X9IAN3ElG$u*#m2AwV*Q@Srza?Vc7bCk|*unDq2+i<4ha-#0WsUmAydG+D<;5-;O(FL)m*2V=hvQ|=hsgZLpM-l4S?zllCtzmleaouAi|j{H_NejGTV z^lxR|BvzJ|p29}?JeuE938x429@lvuZ56#dWoK zyJ4>jig{x83g}s<=jA?`wS&Nvh#@*cXj|a^4T09pR)NIn9OhLjZipqaA|A#y?my5fR=NN}% z;BAILwJ=Skbv1ALyj0bDzqU}E0B|d#MNadp@$A4`vZMiTyLB%ejZY86oTe1+TGTZ= z?V7dy^wP8=v!Py5cXsaZ#hJ%tl?X-$sVJD$^?b?#ESiPD%mu0R6Ly4T<&q7xy9uYt zUi8j;@+OR!OdCH+eq_kgck_R^0Ed`(eqV`5)~_4u?VuI^RIOt1D5`0n4xhzSDs}}w zg^LBxE)FJ9p7u0wm~$y_k>&8g?OuUqHbvomD)SqDom8074B zx=cscsn4lJVs2&S?SA5QN{x>CjT5FzWA!x5S+lKXCzu>M_a2ctjQ9>HLwU*%)71bx_igLz?_6h7M__I zrxCMWvWNbE8Pp}b3N03hXlidS&dqSq5xnfUtkKt_je#sRUhA5}!gd2;2jd=XNuPa0 zMSM-&@z5Km$~wyTZOTbyPq#d|*>^?V@EWW2AEuL@CBc=!$1_=o)S$uF5`Vtg3^9t` ztuNm)P{YKsywLfF?$iOlmResOqjgR5X5CGChvV{JtPZ>7ub7@b^hZ4CGwIb#+VIk; zOJt?_HYkSyUDKiPP7GQAz###|qQqu+FD?J~+@fjpc$xlLgF{2-f#bgaEUp^H?}Kcm z!I$QYz~IqIWuo{L&uZpF$pMZEp6m+GZ>K9fZkd{MwHF#?k~9W?{k-d)zW?15ZiBn} zR*9yZ+-xjD{;`AAOX+{91qEBbeCxh6?%$7Ww?Ql9_qekgUhVnC4uR*o%)X1_|mmTEfPaQm6Gw`Aa?!r5iW=q)6|gI}II-$QHWofca$;jZW<2ok5NqyKmm_MUxw7@UYz;K)xd%ILH`5Gw zDm=&-RFEt+>A&0jVc`UKa%SYG*ke87x3k=&iWbkC3SKriCTq=LyDuqP%3D0;fxh z!zUg}E{T%#uNd!^w$(j%0}SW@23bE9WwP zmX90fR!612GmA@peHbXc{&=T}*9YBoX_A1~kIlbqF0f=9@UOp~sA@TsK{D@og5r*{ zI)j_d@3#!81QhD?n4jtP+QFV|lje1Q_Um^!kMm@7#2L}N%Cl>%6;KU|2)$x1mNb@B zy!2Ye{y;C z76+)7t>vXm`O+M+?8rSRx$|ZgkLg5Zi}1cQRrQtyo|xMVZY@7r>|bSDRsNB*Sox84 zUH^0xyTp59uC(E3l4bD|+B}!moGn|jiv-!5kBB5~+7^mzrr0)wNMx57Y+YVXnr2%b zRBibDc^F-@**}uY6Z#@1%-#sV2Z-hj(sX}JPWlH1?uX=}!ZLefQ8(9?AX=SGZifcH zF>gRGZFuTi4*3I_^0JKuJ}46EFhS5un!x%O0`VMpDEJsL7*d;=n|B)yKu;F0EdewF z0T|z*_b?5Vl!K`|2}BOLj(~4#Vas)W8uT}UQ$?V92$Uu%{rj66xYk1`1_{O$u%i^m zC{@fWA<_X#!V3L1ph43NU0R`Qdobj}Fy;^ig<}OR0_h3G5{cohVJb`yiKue`Sa09z zdR&C@$Vn7V5Jr&9^m|Mn#8lZZjpNv{yXa5bYuDvs)CgTtzxz0kqm$FLjlp}R8K3|Z zs_agGl;~6Yo3@`^JQt@vV6V@Z(&RJM=f3qzu8YK7hX0SP_kibm@85tmMT0byRVq6X zqU;7jG72Fi8QIF7m6WndBr_2zS=lQ^$cXF}N+j82Wj)uYbME{8KdYRh$ z_xl;|_w~NU5#zCCiHiz(r<2lbw1ur@%(SWR1~AQy#NKHCP**%$Qr)!;)8$qh^RQQ{-i+Oej6hv?^ciOY>7mVWV6xP+eQ?`0YIE9rBVOYtX z^)Y(1*z1O4tA=Xx%iQ(AUodA7HvL%H$l)X5@LX-TKf@9B%&WU7mRzLn_-1Up zxjfCueJD1qE&PSNywdyDP8zWV#vFx)!K}4w7h)Y-A8ijkQBrwj_ta_92K+$r5Ua_u z*SITHh&oBGLawy_n5p&A6#P__EAv0EQ|Nj2Z+5XC`xIGcoNm-<9L>DUw10U_%VD&; zR@3)Kd-u5u=Re-fNT@$}Aoy0v>hd#AHyhrl-JxNA|7M4x#T1MO4`2Sxub`m#L}2h~ za7f5R!`wh+b)Dg0YtJg$_UWzc%1#S+h6qn;{cuR!v|;(W$)ljm4^ZLVMG z^X>ekQ;R3MY+2r>*!^s0Sh=*vL(kQRnP+;=X+{GR0kXE12Rv z3=5M7Ig2|)3hD~XfvO>$Eyt*e*v})vE`22DGeCq5n>S~DD#ox8H@=UL&m~~KAZ9Y( zz?KaM904(lERYj)-EQ&EKLKjc!p#JA>LQwK$b-Y*y^~&^PW5~UiZq1Wl{GbmR#8a6 zaVAoBa2-#enI&m9~@mriU;!}%9taRnxvQwR9x0ApSRhE?8?kGZo#ZYScI!3YLw6>77x5CTI zD+WVnT_h(~Bl>-O=Qkmxa)QYcqKwU_)=xxu2$D-59_1vt3Qy-#oXbr_I20INKyA7 zpIRE*L#!;C^qQiMKW~8;)?LdY=AWRpn<0cqtSKUym~g_~UMuqL@-;d{9QA%5@vXmb z+$QcpXNS|-lr2Z|L?1+jmrgtpTziD(L)ke#6GFp^4VS;K$oAuIDK_Ef?_*J1JcklX zE)@>Cg3_TEtw)iYm;Wv1`lXLC#r26M`fi2p?L{06H~e^bBUW*9b6?2oqht`FHt0&o zx>#FjT%H*?U(8yX-e@}4Iy}3o?X5Xuo^xK|auwrmw>edA?y4~1?@v#y6nd?4XIb;^ z_`r>bq)w%wwj2{Fjn~V2q*mTUxZIrP;^B#N41D`qFNf|%t6unx&_ofr0OlVRpN3A? zolgC|oGX|}>g#99n+%6Hrmjj8Gv???T?)uyKVz_zu*bB$a7SwK zZ1sHTtAo&n>CmVPWP6?P;laACfKS;yU*DwqAzRCh;owRWk}#IuoysdEAhSca0GA0& z^db0x?~gw~oGSv@g$6u{aOfbTy&K?ObqKp-#I=b2G@;8s!~3whmZ-Iy#Sm8iMn zJ}SSzg9k$ru!%9KIjyX00!A#00PJH21Pz~?E!$Ho%w`mORwj26XK0;pf!SZ6R(B~N*YAmki*bJ zm9)0fQ-CgvxuP}0Sdx4?bXib%UBHkTWD7DU>ZG>7bq>b@RPLfW!(&+rRMD^dE(U#X z+^}h)?5z3S^u@rQEK>o7_K7J6aI|df3MB_))Lz;+PEqVF=I_bhe=*O;*1jUmYHszr zj%ghfo0g4JlcTQ(&n> z&+^p^QBxzGsZrt$$B@Vhh4f0Xg!a|tp3tY^R>^YJKawpPwX-%1Bw9w~MqUr=4Z6%g zdAIGY*xRX=%+6PuvsM!Irb3I0)mC_PIIw@a<+d^>>ojJ+&vnX6Tk+9{kR=w*>0A@>*p!sB6>sNrhE&xt$7>|nh=_|#Y=XOSBhF038_wI`0ZIa%D z_u8N9e>}h`^tnT#ZIAeeVS<5xuuwQ%0c6N{Js}@wDji=UE`YH*RA)~bR_HOPbNI( z!o|fT@*n8AIc$o%BNbSz-!FC~>UYZl^&dwZD~+$j$7v+h5882tz(AU>^D=G5tjSs3 ztIX$(B2&aW+B?4u4AsRW94Uye_gC+o?ulBRZ%6Zv((W2o{58L+;n0Ell!#xu`zCU=2tR%Dkd49x(=ba% zLo;N~6S^qfP$^Wqr|9Fit_r7#_QS2bQ^ufQO6+r;oZ>5(H}c#RB`WTd-c5!iaUDJ|IfZ~aT7RXylwkV zAGPTUfmAcGp(lsAu5xXsr&m?G=vQyrXSaAYd$`SF$>vGYsG;PG-5 z=GGT8l67Y@12kjz+Ghn#dX=Y2?_?cZ>{&fIc@5We_6LQT{$ZV#bX%Kqe&y6}uD#hn zWwlzmv0MqN8;ij1s=*A~gSu~@81byQcCFjRr)(WLeJE1VXW%m|n0*6ERIFmOwhif~ zZypjkz$X>xPU&ILS<4v^ee{I)#Ge$+6o*a+)(LU;M_JzIPupzslikntGW1m;>NJ2rOxRr|;S+PW|v-YDw?<+^23EUY|p|2r+X79Xn*A{@m?z}l$Rid6dS0;CA0y`LOciMYx#S)b#3Ox4RFhsBi@v_YQcr~ zd3^jT8<<&0E{>l>-21u<1r={YGBbtH(~&?%a2Vbc@o{iaCTsZWc@9M^G76bWgVsI| zyB{rB{K9LRFpE}}#yr()S84?7DEOgiB;zMIh~3poCCSerE$x@nG0LC>2a{MAIB2Gf z=qqs!PPsd)%F-JC0Cn#2Iz%89VH87HUv|#*$ zp=ZJ9-gp&Gr`J7u7u^<*+4WIS$kEHR{x*I;;LCN0>xch}$jzGJGjHcDwmwq|M|S2eiC;zn z83J=2pC+-hbwW=wrDW!gPWxmjX3OPIU+M^^@o8TWJeN=;k8ASaqv%0MQLEH+Dra$zuzv;XP;gs-!OR!`p4C;&=4VfQ z*$mE0|I5VaR}(`M3x^t(r=G6x0}LUYMA)R&=~x$)5q%bX8X)o6MObC2TFY zzmok>C%JGCK3G4#zW0J&wV>gx045fH8Gb1jD}DLip2idlpnhp-Xm@6+|yIGn=&Z9}I}{DQoQvEcZXr<~UA|+i@V>!;9)S&FgKH6)T7I{pv5g z&rp`~)U2vL`{`u-otU&=jKyea2@$q`_`=5c=p2WvpL>RR7oI*C(NQ$CDVBr^s0-&p zsnlY(e#;(KN#T1w$1SO>)KjaRFMG`G2+@|8P8)My@Yvxvvt6-R=ZsU5uy{ui&Gms# z--gPj<~=5~MYD&_b4XGaQO?F>X5Q9~@XX`sk2)54LpEvOWaXA-hp0rQjDT}ONHG*m z_osPlzO<@ixoft+kK;D2`qAPB(b^M`Sel=5U$NL1%l?$IPVc4bqvDuR{joXv_#I`1 zGe7T6KFd``oLZiB_op|oS^J0rEeyo)lXosk^~qXU5r%lCeKFhZIsc?29&Lgzo2%IhW`+-l8dKs-*dpHys3pX1bGxwv2N?OMH$`$^2f zYRyFhyZFJ9*su35NXw{hQs+NE$h&skAlC!hy&+9uSJ;cC_U%9XE>=;Vy>4MTTyr#1 z=f{_U?y#CKh@7`->mA^Gs**DEoVnnJwGaKyo!riM$&kqLv}r1>nq%Z8%?5)2i-nN1 zZeBAs7w#%MrcU?pn}#l`mW7_vo3@zUQG3}tW_^a$qoew$8MCu}L(j_jYaIPQ4VIV7 zgBfeDr?tN6ePlhh*;EyO=U#O6;;rS^B~rPRd;*No|iBD>w&?}zxyc5fmFk0~uG zg3}vWY#E`)tofI7ir{QkNy)bwu^bW-T}|skX=AftkOD>f*o9jI4q9!;I={?DX>teu z9%&Aglvq%G+4`(yaehyY9*ds%bk4)gqwnaq??^M86}}j$dv#C8w_4^4S=8pPo6DTp zjyjw6GeiA%;tOlGHscA`BLfy@?B1I9+cVhXHDU*@8B6LNx0+oN$@H$e6}IB!E3&-I z4pZv3PO-&7%S`jm=*>OsBDsdak8J}yYux;2448LazpE{`=0dxf&CIm}3pGaJU!G4t zCQ$Gx_v@CQud^;QLTgMu97qMFgh+|#%#fdio-X3Z`yML)0@sC3eM3uUeVwtU<-4W& z3Zp_-P^0?oSt!wM&(=1Sx6)YE&zA3!H}-hF`PbP)9=BmQtAF1sBYEu!AK7ueyRHkz zJUEs;nZEq4UYUuCXHcN7zG3#e-{nO2Vsa5KQ%edj&o9UKojtj; zL)7ol-G0=C9%ogHzBuYcRWl!}NFA8DA-K$2IMlza@p$_=bv>(Jw}3dF zvYfB*c%P?kPIbyqb93|QjnNAu+M11<4GLgdM;QbAGpu9;ui+EMpq&R{vX>o)6DN26 zZ1J{`$$6`8yZ#WmwYK_4k9J;8%6cfh!JynCOW0rXVUm41rCE?fyo^!sMcz0yO>ehi z0c#n}6yb39Pm-=-JOfihmP@ays$X*RhCG76%c=xF1rvNQX#Kyeh-N>W>#+wn^}Rm^ z0$0z)u(w}_ItETBoLpQFy|_N`T6AO%Mi(b|r(Dz@Taz*OefIFK%~@4IZ@!nGxl~`V zakt>`VDXnplYwYvA?p@8z(@BL73XZH)*l+sD{m+Xs{Phw+7bU|95Q z#39z<<%xItR`XM}1=d?7I3NG`q-`_NAfp#08CEJs^ZkW=UzzQrT}(QH!k2$|Z%R1h z>1|lN?1x4t^=!E8%Ez1d0pm5RsYco(jhPpRjFwtP=4S#Tzqfv=d@SuaLg}Au>9t$@ z?*-`J2w%)yLZ+W}-ThaDX%|LZ`a?8PNnHk@NYU2TMx-P}#DY~kkN&j(MmG|MWWasG z)rvL|{hxNGDco5%;(n~q?@qzkU~q8IG)o}3qKiZle|$LWv0=Aw(5-8)3O8SPp*}4t zt^8rj`%nF~9ILM#(%<*4n2Ms)(dvC!ng5gHwpaA?KmM9d8lRmm?e4xg*6JoV_2BUb zi9bh88f(+8R?CWiDN4`DND7^J)xgNf*J3bW$~$%l=UDF+ZeH&F_6t-^EstYVzP6V5 zN-Eoxmv>WB;0Oq9xc-u}*}zDrxFA}0_LHpk?ach|of0kwL-e+~Q#f63*%ZD`#H6yM z?xkfS= z?a}Jq@b^gLf4(j-R~JSl$Q`8tYYGd^nS(m@KU@G35em`6i(>eeRlrk`1DL! zOZns2-Xx&;Y8tAtiCdxw-`AYsR?G2faC)YNcY5cQ;f$=mkksGBMvlqjFFTblTbg*A z#4zq(;k$F(&?PKLj6y@0LEGM3L8F5$qpfE;qNTw^#j!&svo|laJV^h6^&i{Wj-d%4 z@sC?{PwbkVYy`KP-?P4eN%Go*InTnH_rYs|gCCDKJ=l6dTN?-o&&}nVk#(YVAz!L5 zew3`6QZBv$(BpGyAT3jq-_tcu>S($Ioi?lhcU@$u8Ab?;1t z1l<4Ff%iNyJ>8$xs#gkS3+>p$g~wkf#;>zV4R9N2Rx{dBZ1kmWFId5zLtgBK383OH@{gir4BKL4fg-!i%wX>kFP4s=d?JNDqd*_PZSd^LU@|Qi)dHY*m zUyZWVuuS}`t1=#0bKGGAf~JkHEQ|cgLSDNGcoa!TSSj@@5qY!EdO7WJpU%U`4nL&- z_9936b$@JeNl8i6mpZrX1EF1lz@g+MjRc6A-+(QMFAQf8BT~SmM4vGjA4)L?hX_*4 zf~D8{@!@_VWrGdZgb!E zUAHjf_uM&SXTpF?WFF)8ULAkpUb3ZbFAVD|7+`@4f#FmB_?c=4?F!RTH=ePEDMXa?pR#2w1?@G=@36f zufAKzp(Rlj-6iYwr?&Kcd%KjLy^es&_91Ih+rFbB<;Zc%$b~r=fT8eSH+iPjUWDb?jExZs8uGjWu|9sN(~(5Oi(; z8D%kiJ+RC1p|7uE^5_m2=&YK9zX(wG{YYrLLHdt@feHYTFgIZXuieS1X|YxTcEA6! z9Oyn5pdB$HHcPYpS-cdHU$TBG@KlOMcxm1cV~F_En%wHi=#`jRxXHDkr=U75J4N0q zSo6Ge)iDWml5_!G&LfXQPhEOd0dONV&6gcQ(jH$lEHa zpfTTQsi5GzX2QVb4x>m3X4}vfqC)-P-u(R2n(caA20i8HJ7%wXdnqmz9PTUje}Dbh ztbnARWbw*J8wZ(ZDk>Mw`_!9$&1&5?H-CY9+2dx;nNf-wS93|6Z|fzNY003~MTH6W zIkQsQ?;4C0PdiPhFVD=SxzNWYIkPc!Pi|B?xpb8`8IDFLHq_IqE7Dl@*6tRz*aZhm zBivF6EpxrK1;Xo{Mc?dtLe&`zW z@4E2T?U-C(_tVkxkXCl_HM$ej*9J<$nC@?^X1KW5GTG8h_X20?3yOCNhGi*5V(D4g z1~upE#!r3e8J`?~mEjSuR~OoIP{c?kgqkgyC3^ez7Q5s(hOHV60=0+TK7Mow`+}qX zdr6pYuH@HS`aYqB8D!(R#JKnD%=Ap#u^__2%CSG^eREG&bJTETk0|CG1QBi zh6%1PU(~(WK2fTt;Wo+p%(A0ds~GLk6AsF-KknHoTA#DkIdONc9&d?UsmOksoo3to z1K+Q*@}p4?4Oiw*hBG;GozGON;&t&eL;cVe(Ivwp6cs)YXQT zz(U{oi;_=UV^+5xNaHeTtg~U86(~2`Uog9LyJyWZ=XON-1tcf)qG`HS;#M2~w9ItT z{l?2zuec93n{g*`AA9oVY1JzQ96=xQerL?NNJ(pHaaAa@?Em#mPSsopH{z!CYo_Dv zhx(_S`;7X(V^=FbV5E*OOus#6jVnRPtC4Cdu5l1*GP(__e3_#i!Ea9%*iL@d3K)^- ziuuLTKEUcRXUkln%oJCpQubxt*tkvcDpWVr)EjNC+sh?uTt75&P|9llW>r;>j{MMX zQ47lv&Q#6;?C+S@h2+BOuSjMbr0Wjh$qUt5o*pV5v3k?j^a~yqV^=-8 zJnz)5DgC*toi4=N?LDFVohp6)fNXVP_zc6yX6Tcn21#;(FX?nTfyB zt5^3yX@cLqm)gq%hYk@~AP91v>MoCdso)Ab-|@A{^Oow$3*LMOb(cfq{ybWe((SG$;+K(ea!WW6pOaZ$0#Om z-7VmV61DsG?%UGZb?di{OH)K-TU`2lGLTk~^Rd5<$5$Y(7ql-l94Qo|nfvoFIxGOt zZzG=>jY4yAkMynZFU2XM_ooy-7M%C-_d3FxFC=4W#5%^!YW2v=YYn7l!O~A&_V!-J zpoEP!wtIu=pue@v_RhEMbph%NRA%1;mCpsb=#NRSupe0N5j*45uXR6VXMMUmN4JN& zFvYf~u3@Ae6X{9an`ys`PkdHj%=5Q3%dgI-(OoVRRXzH>UXClJL7tupCBG{VYQLd% zb){r4=EoVepG;qk`i<;(Zf6%dQXT|kBW&2VgdwFI`umU)Zc+t%E`&O7X%pSC)e;_>pM-fZg|-gAjE`B zIF7ynR{uG}L>a=3F&$>BCtFpxcL-hmuBd87rDbxBvx=v@y_zawK}dT1x?yzjV4(a+i2vZ7{%vw_oK|6cO$Bv`s`MljrG%~*cR=a-W_?= zsBA}{{=pcAajMC8%@y*Z=XUfezsbo#$g9d~g9Mnc{PjBVaVaZNlj-}Ma%D06(@lS= zN6y^72?jTFoqL{cl;;u)?6T{wb5#yci2Ea@aDGK@=wRb38FS&(cGaZe!L4=SZwqu+ zmPV=ri(h7Vq>dI<9@X%q8_|5T@#ysf{=dxDeS2uRVQ~8mHMV326!EE?+}!)%dWN9~ zFk|au?jw0Hw}P2QPLy9>z4(i~`T+;JlOo(aTwKqdKVJ)}Heo#3+ZQEYP1fL{)NL}S ze(o!5I{-HuUtF4Sx|0DO$F|q;W0tL>l@aW&FksF-n}^KIgU4CEdOf zFIrDk#27;l0v&55jeuZb3>h*?OW#;~vPlsQ^@R1ePpJ#FwpTh+BhRXSZLMMKxugsY z&I9`&bh|m;@SoppTF>Q^EfHbx?6F2YjMD@$RtA(#NG7tfvdP6^VPTL_UNSPWZ+w0l zc)9h_x{_EAw;2s}^)8{U_TNg@1uz{`Gtom17aXAG=I6gbI$T`rnOqDJbX(hLUlrEd z&N!ueqa3>pusD&UN8^2BRFd9b4!0oU?F}$Knk||hvvl{mHf>+h+ui-kkmP1FR(t$G7AW5j08X4AzKyvU6S_PrWfDe6ik z#=+Pzv*FoQF{vhv$s&yntSN|_`407Sq_}es-n_NR9#ibh&Zi-H||9UlY-!=!CJ#sJuapI>VUHUcQW4U+Y)8F3#hrsi%f40zDP2nYx&s^I!%Y0}UqO(}_9^ z`zWwI)&BwQIGH9-Ie6z{aR%{MyG{zI{MPNvV!6GCSA#7#}-A(SUZFN4pT&6MPQ$Y;dD zM@s8~16I<>8sEpp0*i}RltS@9lR^&aK*9pMvF9&d_`ur?ZWmWOvy-ppvvO3PTH4Rc z^Pwx#=GzIN$%N0O_2$aGwWppG!5{Xrkx?1$_#qkhWi>`qvE(BT+WLz+$G^qzyT-RO z$T^lGD}*h3OG}$*TTJ>xzWtteQqCw3HVY`EK8{QMY&c-*TTsk%NKZTO=iU#x5W6ed z*zkjsOZ;@`Xa&vqscX}U<(-^+{}IOcpbDoUO*%{HyPv~`_` zK7D42Kz7qp)nJ{Pkd4k4^B>4*sqV&F%pC0Y1J)7GD9m~)&K`aS5II*vOpVA#8c248 z*>>Qw0%&K2S2gi?Xkp&|Pv8VhpHkJMLqkmzUX6Uodj$7G;!25qMm)7(9r_HT0mxkC zY0LCA{ow;O`U(^mL70*do+AXYJgc@E4~1yzv2t+Sg^7Q2gy>RTu?4e4=24d>KYdlF z_$MXRnt4xbcY8f!U=-WjlHGEl^XlgdiX{Us`PU@+*+i=ptGReyO2?~R9=mc^^MTk| ztC^stt-UPHKcC$t3@^-JVzEf+9;_e6q9mSWg!GBkQ}`~MhPG{H6-7g!(L>vV5lvCW zv8gXg%Fg*_+}(ecMVl$o=;DVV-A{b1D{5QUg;G~mbA3>=yyv*hQS?+cYg&lNV+Q$O z8(0~h!rcLO493|O?Iqx!Q~Yd*->6&QU<7p>H0QhH)jT}A`7nrpAwno<3gK0lo8tKx zLJ)O;jSXD+)K#Bh>4?B$MaZ?G77Y1%uQO5QhFv}T=$jB8O}c+FIDzm!ys;r;+nznd z^IHDw*%Zy`{J7$4%w5B_c1d{|XdBQB-|oFdcPN40KP#WLkDMJBlOBLN-YUiEnPg zWDf)M{V+HD(9xm2dS8u#G|!&Z+Vd1DcJWW960dy(-1ys4>-=C+nqy{JZTn726EP<2 z@ax$!SATTb>`F@Fs^sf8J5HrJrN~*y7oVH9JtUsmQJ;QMXYTVz{gzy(V;_|Sfy*W$ zq7O^pVPs?t#+I-FB2--QKR@FNmu5N}=$@}q;SM2sG~mDCRS->A<7uBhdzSql6*7h= zgK#+qv9P2;t^DD(6JPXOT3Uc(-Xk2nHp9S)c9W+D<~)YJ_wS@;W(I@QtD>v>2{YJV zUG|9u4vcZ-vi=261xGzI98Uy}axH%bdYZ89~n2ji^+}3K$Z;!LjNVK25L~(zkLSAH8MaV|) z?S0#W9EQa;rxem0vrFGs?sPQ~8)i0N7H&#+t5UT8tBJj!VCzApxlw_$manY4eT$r? zYos_c6$-w+QE_U)%Ym%vzT zI|bez!6`5=p6Gj|OvlJ*?sDP6XyWv9>u0;?MU>SSgKxeBz;YT54AoVw4&m-J3W%ilYm zdSezUt{vQ2>mHl2?d0|i7sy)2y|G!MV1J`2|K%3~D)FhY3f3`IDl+liKF9TC)I**n zyl%MBaAHDdpPW}*ghcj?Rhy}$iq^-dxD!o|-QC^9MUpHY!Xkk!%V&_mGqsb~CbEE^ z2!n%d#8e2^^b~$mtY)s~Y!_?C0i>w%qGzl}$FKQfWzE2(x7#F2HP2uBWb!m$ayA+o zB^@`6dtasPpB1%(f$@k&i&li%$+S`QG|GWx6WUk2bIb`r9XX`oDgv8kA zx9(q)$QNMVVdT=pun`;8#xA2GHBZD!@@(#WUQBk7ujYvj={S5y_yO^1fk~l~g~h>@ zKdr?!*RPw?PD{Z%7}L01o=!=4>{M1(63GQAu@GDj`nj>~Fw7R@3LHk@tUgc`!t+`? z>psw>C)gf@?E-qjl}J?sFe9F~?y^;ey7w-Qcsjf>JOg;1CajeaI*J3(1n2+++yVwA zw_SAV7M82qYU>%qAGyb8h#ga15~cCaIf zt3O>`uppn;2?X>IP;ttzfI7AHe)_TExU`4OU~ zeL+@UbvF=Bu9_l+_GZY4s{oF#y5u}!%m60^Z@Tzj`NiDLd!k$2Ru1p-EAHAp)v53G zY-WmkzpUXWB|#VW9n|ltWN|R;5Z{d#h)$Dw7pb4B5L6^(O~X$FJsL+^iv-^Y)2${7SOA z|N9NaY=*c}*PlGnyxvf0b;YF*mxRiS4LbdIxJI3lk(mG#+z7sIMrSL;Z6u5mknz2M0AskgY|i(Vg>w`o4ND*X z(4sT@)A_gdL&T5y4E%Fo(pp|!?TZ6>mCf`obr|6db`^*K3Iy>0&BuFu{bLBf1O>CK zp&fz|ybE?`pfeL+Yd9v8 z^$3{_`^~M>ErgGZRTC&axdCjElgS#b3!)-F-}0K}n?KsP2Ie(#bX2&|$~(^PH(W<; z8@0IT25vJU7NgWA)@SU5v-;XKGfpz!Z`ct z_(I?CuwO_B?9Qn%d_IQ($tS|P5{=pdhZ8uiotc7+0jN+6o*?eP2SGt4DDlH!Bu9au ziYu`9CRIv;hA6OoOlW!s2dQoVZjKWBD77#w7?Z%WQ(0M=6xASNgBJZtJ?9QPu3s3t z!Z4*0mN>9bQE-@Bt(dfdWQB&It;5Qt^KR zt9t;}VxIZ^?uaO&fGqF>2xy=QQylp|_rwchBjVkJdj^h0@%Zv!b1F&-F>Jm1e*Z78 zn`aU5d zH-#zM0X#JFN#G!|K5vhpN$nLhxa0^Vw&Oc@8pG$i?xJ0G+Fa4LAah;rJ(6y@EekD3 z6wz?x_WZK!uU7|JX_mHR=4EX-h5WSoe;KiWB z>;0w2wtFO8grrs$1>xjngzq+KP`}~4=6+tMQ$-EX9lV|E-AGtluwOx#gJ4$l_FgL; zYy&(A(yJgnW)d!ipMm$RFOVYkPJcg~&k$URP%Us&G7IuU2?RD5{6J0l?W2#{?!(?S z#KHxz5;i@t8@VpnAd4U=t~3t40yjS>h`55|jlR~&34r{40&1GoN8}?A#76{eSmg*N zBiu!j@&>AJQ%4IX?oXsVB~i-|ZWnmr2#2$1;hn_{0w!H+$T!5fGihM(!))|)=-R*+ zo7<5%M8|g4B{MFp9Mgs62wR)57i^ zLZk5H7)?8~d6P7f2|z6g!{OO7u$W88FZ?s&DT07Q(K?A)Ch`jx7Tw;7P$LtQ3@ifT zzlhu#CEc&#+pz2YJsgUiSC(dRa=r4)Gn54@gB+KzzAsLleggM8;%kP5VK>;|jpnmO z%NXt+sO*IA_XWJzgSk9j)tLxkrCSE&+o`?LqcYrHwPt-9J}>vsReT(4%o(#=0o=y<^PO2*@5~dH^)jpxeN7`XtK!Y5gfpcP8@() zu(zLS#G0(QaWeS)hYPU0bO9s(d5+QQg;FGy9*PM+ypCGsG}Ecldbr5!Jb2+9Ha@Yj zCw&OcsY}=y&{m$l@nJJ=0)F$BgTzn~H<=7>+g!JK0b;d?w$r$vr$Hv-pErJj0_e(q z_}oKHLv<$%Mn8!dz~V~vN9*15&@u&U701!?;B@U%DH>_ikI;C4;_>LggLeoLIE_hd z-=%vCv4ErhHH|vWUlW}9b?fGbu*OP#`-hwSBEm9+(80Ktm=F?U1OVIUz8^~;xeT5H zv^}@*uiZxLB-uY)3>hVtdYn zwphY~Mdi`(F`U;RR@j$6-P)@s2CpUe)KU;8`lP?C!{_Cv#Fsak=q-bSmhgq){O*q* z5zT%d@+}d}a{5-&X+X0R&6@g$0klKLqgCW`1okZnF)=rA7an=lw*_Rhf6lnu6knl< zMdFzJ-kRXh&{k%paSGV@N5JiVDLd5jA8L$%J-vyc;Ys+t6Vqr^vDn2a_005$0tB3_ z!s#(4rI6Gd6cOS3A2LiwapnjjbP0u%Sk0gTae@~MF-t^D07+}WHd|u@>+)!iKUb08 z25-Ot;E_NvQdF7m;w7Y;*6+hsJ+Nmd=7M9|Ls4jG31UeOGeT5FL_q0{Rcm&^t>{yP zNT_t!Lu^3wzw2Rz{tjDJslpj`LvBHV$gj53|2@%ffCdc%LpxL?Un z@$4=ODBr7*H%E10jT-#da7z%mC8MxK44_P0#^~JEVyAeaBHX(qn{NvHx_{p3=$ro! zStJW|mVb_c&2jads}{TnN<~L^D zSFZ(yr4Q+Rq%ugs>4hftpkCnvZ3PxE>cee5`?&f;IZ-R^ zT)$}-Ikx*(ms=AQDx*%a8jdE!_88X=>0?OIfHH{GV5G@HBoQiH+@FWRn}O})dlG{KlkpO+f=#>lZzxO7uZ8txM$Z7O-xC56`$ZQXWRCBq$H@keOOzW1x2+Ml4Yy zwi?Bv_le{1WyFb(75*4MJ<0dgVRwvScRsJKE`!<+OVk=3v7C6Pp5Ve06KpV99|3pn zc>TQy%@B#UKnF&Wi3`6mY#fYN^3jGr+;NDK&(!hh6`CqYyWx%|?*$|ZbnbF!zp1ut zNtw=VnLO77At%hc@>{+GHTwZv5tu*(oyjA1B|NzryX)R_J@WrKr0O|u&rq}4S5P^y zG5`3Otxq-7b%IVJwmTd(13CHOOo#>z_m(tXNSvQH`URjx{1SE5)i8yH&B_NPnof+5 ze?{W~2^g_cFg?RXX--4)`1kq985NIp*ltS(g#zs#pnF5)Pm0-so zLryR`Y48>%Wz7$4r$#OE!4rjBSW%}*sPfm_D-T(8JFC}HM zW@=uqO)yr&JVC--4Y>-xvd}bSklq`j0ARFp=JNP+=LfILiJ%|jUd%eC+M zqhw8oRphzJxYw_1f`=z&X38rn5;Z2};Bo)+rw_ikcJfXho}`60o-pe`>WA9-^H=`3 zy3=v+@Kg&$K{$;6U6q0<@P;j0(0Dck_X&iqL~Qo|Z-XTg;yxolDYB%-H{?*ZkK(Ix zv$E=Dm?Xa>EftK1}bS`}qEJWsw7lJ0iCySy0d) z-9fY)sUb0%Ll{i|%2M%)9DISuPy#3sd;*(XK9N%h<>Pwh99-a2@S2LC6T{^9FV=9} z@I0Yjv#^eChZpSW(;t73nv-A*H{ovQHU)rfdc<4x4#^QwRqyY!D_C0QMbMs?!(+~dlMEhoL zWVDY)w3J2176$bMNyMmdscN6r|J6G)jiLyPy*r~dBR&1wbgRAz&RI8bSc$p{OP!b; zqZmXXWBtIk@LGSB(!h@G+n*!=+^K;$1vCL1cR1(tk}R-;rIlLE0jwlU;k zI4LCwWS<&<4Huvdqd>i8jFTVgy2^;`t&a|M+|JE;otz94-F=*#KeHdh$Tszn8w9C2 zXWA}Cyq#hG7I^Qe6#H!<2BoM2K?f{qy#CLp>M3Dd+1Wjv?O`Opk>cl^%221C$!z%c zMV&tnY{ip)P(F;OUU@8eTdL{Kyl;1im(>px|0L{$@wX(vG-3kAem2t7>={W>`WLT; zjSJ);mG7-ikpyqp4_<(q1F69=h(b-&n5r)YO!kBj1upgrIy&D62f5zUdWQe^hw?vh zRdqLLw=vn-YrR(&@6`M494jb1qd~`1zZWfCAc9I&)zyvi->pEpP8`<$ofe_pdL$k8 z3>Ss4b@v%S6+k~ZU>|?jusjV((FYIqsRh1J`WrqoAGGr4-;zL<)qX+#^~h_Rsq2qF z1n{Tsnc2CM__~r`~;sqlaXh_;A6KU?75v0k|g__842i zvc?d+iv-(Uw{su7{7Q*8gKC{Q&v z(fuUHo9emb3n*zRzV!>z zFkp2`!6fG32V`|x+4?(Z7{n*zAKElQpNkQqw6fh7#`-}(4ps)IBO@aTlM2~ksBkLf z!RdE=a)Olvj@`~9F){xi? z3#R`GsC}?uz>TOPRXw;7sC!}x3m5rXhhUn645x&%d1n&~cx+$1dR1a7R3*=On|6iZ zE4OKXDE>DEWP%Tf$&7iG?CH*JZOhHItI5+-{>8Q;OjC{$MeCxJthT0+kYe=#0 zT;$m8d>1E&04{3?0YIp@jD{JXCOk++B&iV(lo%e8^jH=a7EA-KgHz=(_l*+Bbsh0e zh5opr7=~MVt|Ld_P2vO?0Hi)*=7UiibOg>LS*<8(bNoi2gE4J*PIdhFaT33g;QI(( zbYw`3I~I4~j$>4R5xG-w|J!eKzL+K5yMMnIA{*flgzMagw)z1`oe(j@RJ0hHkkxn~ zs3cys{83j|M+--yUa`}h5zcbY-#;Ft1E3Qj|Ef!E@G5bVDe*c|z}B2F?+N?}QZ8wN zP-CJVScQP~eSj9uM&(#`mSb9>ktmMP5;U=0Z_ZMX2tH(;pzTosOa(M#u%}px%+=sj zBu=tGD2UwhR{wL}{SC?ZyC{1-$1!aWr~8|Xw12-BN%KL0iQWvI9%fz>SQRAi1g*Ey zP(nh28VC@Ab>d!d^8f<@#gYvWiMPvt%yBZyVgh38=x72CJV+PQ3DcM-$6?I@+gp?C zd<$aW%_tfotOhjfSCe;-5QK`Vs{4Q}fZ1B-lAw|XT(rxBz@Z)L)k% z=oLvWMJv4vN)yc9NL2ubYyv(vE@I;%^^1?=>EC^3+H~;1Kfyb_;ji8ZK+wkj^Y<FmCerxmdIt4ri2}bdl~cuU+v@{i}O=BKRyFRY!xe{)YX4dPuBMj zoO`H0rK$NqKk0Ss-aYFs85sI1SkAjPl$X%Od#_W-VhAz%lvx#P{I=oEkD=%3Z(gx) zJ^!-wg3&t_b?=FswJP@NJML74U-dextnR$K`9{biL5TIh^?Z^R{+US=Djhj_xfLlq}NQ8kn;DH=8k< zpI6xN#cLyldWZ{mHP{x9WBGVa>T934+Hq|1+_}&CMfX!)(CQv%-8tiMbdK`Uz(8Qs zQ>iV>M?81rm>${tVTtUqNf<1sz#asM#EtOB5(LRKEcbhcmYPfvK>tbyP}J!1?Af#P znwn((DeKQrMh;;3-2;?&TPdHFmerj*p`X}~@tj0>Q<+{^O<<}I&9 zzi(Z#ohQa5h_V6+whSwG5N`n|WzZwkWy`#mnwe^$RM$}4CrQ3C~s!JP80&Y?s;-uUM+ zH{L9|O>P<9FL8AT8-4A{<6)|IwRNe+o=c1A*X%^D-VDge)TH4owvA2KCgfJjRDT?~WTQ=@6n>PU`RSgwBVw1n_ib=-kFvMs$va2$ z617rxR#|)N?5z7?1}+}%*aLh|8-^_=)wY}qit?`NU`X7_Yim|dJ@A+}-C_2@BiS#4 zPUE7$8Mn1u)qy!mNq)6ZGWCX;ht2&g<5#lU6cM zFz3CE(;RD&q&11?>Oq+_@@PHTi_!mf4XT0tOK!m{b=~fF<+S46nO4p!MQlHvc;M9P z4 zT%Im3Z}oceU#z6jU(HlL|sGng4dlUNT)S?pRM)2 z)0@?)-1Ti!C9}REKLgb(Rj(L^BYV?5nkO4>t-dc1XnT2Nb~tKD^2a;reL7jJvFhd} z5l1u)>7EWuyC9Bo0M#2|2T;Ro@Vtk^2??iDr`$s5#DSad3k};AAsjTlWOmk~`_v^1 z-hB)r&nhi*wryv+rl1_z7$l~d8rb)ebZsM33=7yNbW)(IJfaeQx|i|eUpN7#lIj$BFB zQj)e4s^`@S`aI8YP-h6UCQF?XH7+}YH?YMyIV4MdGH~8P+dOi zRWbd?UTn51sg<%o$_A?O*+kvOgfk3Fd;N#>?Nw7&^q+c^d(}zQm9(zZPIGb54~u)e z7rq=J#Fj08PT~6XkL|@zE%}u9r#Ue9S{2@Vkv-D1OXk$64;;HUF~lmJ`k=}6em|b& zH7ceBhjoJC#(fQ^hQK|MUYbmb^zj%%F+h=JQKBgle(W3oY zcEYGZ>muKHj<&nN%<*qq*Lus*_M}K?y>vY~UU_lG{Wt6MpP59B(4nTIw_NR4{Bo$2MWwY7ii_XY_6D^+|@B;%)T#au3O;T=S|;U^XGt!$v{l2hRKM)+TEU7&e?TyK|>^+9hmpMyznEGV#=H?}rWh z=7U<~&ZzCb9K`VOsqF(lHs52DPgC>EzFyj=oq67H2Yy~u4P3muW&aOdUmaFew7h)~ z5fucLMnVNaX;4Di0Hj5_k?u|@1qEqokW!Ftq&uV$q+1%KQ$p&SZQS3ze|+b8K+geo zti9H(nR(xLX3A2lWK{aVIYrN4>F=Jqzv!o*!hXn>dqJ4y!j=KUoY)#-}A zw|aiep2u0gTKpuaB5iO+IPogprb3uz&*4&Eruwy)q82p`Q!~v*qlFi!%*ku_ry5ZE zn}Xb^)2Qt$LEmjSui3B6_T%zXS1T~Ct&GR;;|9`juzB3U75H-PG`^jDrs?xZ()~~5 zye)526Q&|^)JrYC3DVU3#GyL*g`IG`N-*zI7PavGfR@v4?eVtPrRbCIhmk_ZeQ$F` z0`^~!NlWT=)qGEB>X(GXGQWhIn{nmMn>8{3oAvDEug=0OXe0q}+aFIBlt0solHOik89j3aDQAP;zFmLjAp(=t5zIwas&U#cwPXUrQ8U4%=~Kz~rsbd7_edAV=T!71-YXT2PsW%} zrw8waYRWxcHRp>u{d%#!p}vKlVKz5uE!82?#EL7<-*r*1TII7ByJ|6N;|rz8Wju;b zuT`Gty`O_*?Va<-Z?K^Mk_(sJ#o}7QXT7*=?v1|fDLILuP;N*}d!miN<+LTi=-zbD z<6`3^VTPO5AY3N_LIL6}`TP6Jo>0JlK=ca~ov!!zM*SK6B!kgkBbx{Dm?D?6e9{1s z%>!qkcK~XkLE`6;ni?4tD+bzB!WJhmV4&P7J4Kmo*eKW$<-aRkP$c5myKs2D*YSsX z-&_ALvT82M;TE%#b^c_$QHedzIM%;^^}DNIpw%d*?{b21f!2Ayu(JFLiv8ikG{sCp z<@@)^I@``nPNg$%ZS)ak20Bc(1ZUWhdw;iUE5jkX|F9`v=ib|(2Kz0)oB>HvO@#~b z3Dovgfw3w@!v4ePt)-*!8cJB?71y8WAB3=^c=i$Ol22Ab=b!#jYknGEBY~ zvVZbbMj2F}hb16v13<6l1*Lbx1AYDZJ3cw!iL(H&f(6+_Kyqj9^w=Q zKH!iT4&@;+m9eSy6bbh2c32THe^-QH&w_hr@TrSX<{{gZf=l10h{v9I8k zRHWZg{Y}#cua2DBcdFV?b?;sw-Gy#wE`{Vop-tG; zs|H#{D!}og<>xDnqwS$Z%_4YfmCO29MiF)n2Lm0K|kRDFx^}2Z? zG?WKr_Ws`d=bEbe?b9P7n@9$X$)#V4n_H#%g|I2Vp|8Q1gf<>gd;Np4EnN$(0)dme z@qDbr*e<`?Y$=@Q2-e*7Z(f?7*`Ezxyl3+5rT!&S7S|)L6MknLn@FbQN7gnPBmxuy znc?2+<)KN#!weclzI~pUWveMMj_!3H?dAN(4fRi!hW*qnj?h(I_&l^t(u4h;6y-at zYeX<>b|U3&0PI5p&=(yt$4FUmm>oLzND0!!si8S9bT;UQ97Kj5MUXdSwLinSAvqRk zNP{CNCU$YW+z#^m6hPLYbKJ@#VVUf|Y;Ew4cG zvX3)m&dJoYw^)A$drPZ+Pd2+Y@HN`C$(5q?m;=6wdm{$VUzpPD;FhGcRzXJ`leM7QDodF{Sy;x1vmi?a~e>4Ib)LBhdogHH)= zvn$lx@_peUhYq+XWZZ$MkrA;9@^Og33rvUE5R}@K;~GHoA0W$&h@kx%6Kf%Hq2`lt z4gbvV$Jwl`*6}en;__(LfnLH`@I;D2rUKcC{{7BrZH%P%zBS3X1P2G7I^Wm*qNSuV z8Q;6;yMH#ay%CBe5ks*sXn=~e(Cf=o41&f-NCiHClo~~P<^x|4kBp4e7~Q% zWI;K1kY}{Cv~2ir=V;dO!|%`nUuYWg-hhO9Lx);~od!(?k>f(9q+!l_@xqPNZe+y& zGx^diPx*~G%sm=0z3L2mKe19uItPPekfDuMGkLjwdgjhhm26#F$`MqH|5kyEy44)` zZui7lZ0AW)vCDzA7Y?}?r0bwJ;Rj$yA^QYSz1aWF1Q7#pdK(!k)J{0 zpA9s!NGnqaVu0VG_zv;

AaV8zV0rpM6;EhGoK!D!gkXqNi))a_KdfmF~v!-JQ^D zj>*-Gm@`q8L96B58*>us^Uka!vk^ocE_^-y$wTttCTEHDX%8E(25vf}z2OqWxWWUW;E7WAzayke zSn&|KA)F6@yO7qC_G@FJP?z7L>L(#Y&e_GAzW)BRAcmNMFQgALBwUeUgNKV;4NS8e zTwF@bC`FcWPm#x89MUntfq472#bVN)i{N$p>-*PHr*AhViYx>ruu%l}@5{~3KMjub zJJj`%m>onaL;&Bn(r^K|G&6ALw`gd*z=p8`+bZMn8|GUMC}0n?0$&~M^E|Xlof&tS z$X0<&{uiJNBeb*xw_kUVcpjoRWGtZE+}5{8xN+85Fe;GC7KDu*ilDQCiWS%mp-_() zKp0`@j0rIuG+OSW)h2?HLQpLTRu>kMR|IAN6=Y@*E&_lJd{((ne|y{Br?k(`!;^p9 zneaiSs8yq6mvi;*vfn}FeFvsP9CDfreMw>L%5ahOlLia!rrpAOC;K~hvrY{=@0ZZu zW}4qr)X-a8Vt1_4c+Y9t(u?b#C>h#Bbc=s=ow&ZEHPlG$Gz05JeCo*wuKBVPo+KV# z*RoanmbDSDDVNNkZ5hMpgft%>LdW7G>ALx|D*AD;`J>&G0AkeV{-72PvnOP>*Gwkj zKB5jvp>VW(`$9AHB&`J=1wsaegwV}9cUn`I7mG*DbpYQ4i1rEzNh>sRhAbr&%94u= zQKPRo8^kVw0KJY~G1m6?G%m$eXTzrG88V5t3weaATCCUc~xAK|+i15RPjS8oTh z%jSP_in{4CJRp59$@FN#{ge+tOC3lrA~YMM1^PlLk6?e5r}03RC~%`eteK+%73!LR zuy^StbXU%;+9icG12yq~`8SV1k6jdC7APcxiQ?U#^aM1_+ndsj_$3VGp($@@NQfh3 znvuGtfGVUyA`7q;Vd*^jw`iWy*pv)6Z>GxrakY61&SK&@%t-34jU1nv$0#a&v4QYH zq*vpUSuf4La(1CnPn3~P^Tv2e8}lcHlMVD$bIOO07fg)CQYo<%-LT|#hsvg^51rul zO3jC=Qprl{rzT&uc3p8ezVujgG@Pd?Aa%?fQ>!769J_k++_bh1D`~*kP&!q^;U3kD z5>0c#XCtfS>n9suLXlseM>p4Nb;!&NJRDE?T3F!<%~vN{;)3`dd}qFT+v3QXDZqTO zp}%BDuYN)!ll0u|C?!Xa@i(od-O^XyDb+7~=Q2hXKI^p`4Y;F^DE5V0kx`Grm7_w~K9|y^$K1*ij|A)Aswq=>hYA#Y7!tf|FN~YKhF0CCjga zJ6|;2sgQ*d%S?1y!^#_~6T>N+szZCEt<(Q4Gu{6U)&|yvTUp)xwoVJ`Dgq}&NACm>dEc^4Gp2j!V(&@_g2#%|!#0Qn5X`djg;L-03f(YbVE7mK|1Ri-v8$U7z2znmJfb z3;yI@^m^mlQ~PxRRP8G&k^SD;g{b>Z)^p`~EEI9O&-&S2j*nHUUAFCtUA9;g+>R;v zkGt47+_zYh%qs#G*K6E6xA_m6uM}E*_jl*t#=gTC;&c+{9ugkf5HExkwLOi+dr&gC z|9qj-rfH*QE;ZH0v{!g(%rTVIkv+n8kEOhtN8E?JY$br?t{1QX^8mwvFvY%6{S<&c z81bv%uQsmQZ+i>GIt}#zZxIDg`U^Y}F3U-j)I$26C^T$`wh#x@pbSO&GR>#NnAhun zW(9^O(m@y;sWjPC9IyZt+S5Ex;0QqxfarmU3gRslQGa%|zsZ((jK+b)R&?Bua$8mc zTIb~0);eg}>hqRsAzz_mpU7d{T3o&>vVJ-w!%o5P4fw5ieg}P{bi1nq0lB9KI8)D` z<3~nJudj>9h|am?@^S>$1ePZ>PPmHrsbY4!)MmTnX+7^3IHpMot_dXdX*5j{5yQ+e z8}~}i9L%$vD=9SZi3(&?fe49&Zx$yaOGDDih{T4Fc|P9FHJzMX$nxoRcQQwM@Wk~R zy(kSwt_Qn~mp|u-c3k;Bbr$0+Di31QU-lJ&9Fn9uMM{qIuYz5wk76>ccUH!txx2f+ zJbwHw>-nR#wNcE_?iNXiU2fmSn#@`_wy>#I>qv5#kbIdy`Ez+7d9Y}3YtcO-?ygsj zoXpeOcxIv=!yj?4?-^&EW4cMyhis?7!36B?1{2eoum1zc1xEv?5=d*4P}Y{)#A5;a zmLvnPi};VQfgtQn$ixo=NBGX@H~^eb>wXicB~Z`@D$Sz-l8!W2fN&mB?|^%ln?~H+ z*q9F~Zh(~S2BucOINbi7x9Pa}3h_M-h{pNf6m&=we?5Lnb9_$AFA$oA!;IIRn~g25 zEUb(TB4nOgt9Df?HYe}Z@2uD6=w+$?erL4t@nfxf@h8r47o9P1CENnP3YQ|IsHWm`L;^p*y0V;LI?au%``=6b3G-tBY(asnU z8p!fNYhlhH+ht^+E;Wv8HKg8}&ErYYR9heJJQUZ+jntu)VlnQ~^>0dOrdjMQTE4Hd z9~uH<_j8!GZ*j;+g>y%)fiQSt6-Iatiu_GONjV)5^B9cHZ+8h8072e#qWU;CSF$=o zF;`>Z=<2W3!yiYVfYAdrx#s*wi%kXtfypBO)j(HQPEtfjNPawKL2MohdWGB)H~e0C zA1M(Go7*5>zoOG`|D0d!Peg=8{c!@tfcDBXW*beE&-u!xCTElRaN3nck)Q%vzBu6v z7v$R`b5*;r);m8y4#>%{4GRf>1Fl}>vOeO9TRS>X?5L4YI_kM=Q7I(%)zZG}^b7=l zhY4}#Yd>~Kj9^#C>Co5InX)}+jVb&2i(+N0B66L>B1QGkewK*vnTm!+fA9QLeH!qd ztjg7PR_)0xj`Yr;m`Y*-cpR?aU3p;p)zS-^>a6n7do#DwGf>mhMi%;e>XPv&$me)W zYxe|^pfJRFwNo@Lxdn$S2geBV0yrNDD3X|~cCLaO#mCrv7c5SSM6|UK zjl*mYK=!SrKNo-@EA?-2{EjJ;`CoQ2#1$zf0X(PH2z?5$tAjBjP=bD0NuD+=siPHjIpjlY|l_cH3O zd0{tmB6Ih^pji`W$DZ-;dV$qMu9tV zk{3*Hjl=R$GyV&W-e?Hr^}um}zmIo5B#(ESxrF*xVzbTrj^!39dz z3>KL*2NqT_{IVy2pt^)V-g{v-60530t^LTN`njqxDLf5>?~bAT>J=v`%;liw^!O~;x1lmTkA*pnaqQQyVB^ECP5S{JhoAt4&#z#0Ijs{@~|0 zq7Ne8IR5*~cU|tSV$hsA-NTi3edSeUUZ>4*7Y?Y_TTU?A+atv@zX_^KrO)s4GM7TP z#^e}eWQ=PS->DQC8x7G=MnGL42${N;Srv2C4r2E1yX>=|0N^SeH%Hb0c>blp2kLS@ zcPY@vXi%49 z&Z|MquG-~X0keaaI#227Q~jozjFcH|9Z~hd$y2`dsEX6ts0w$APV=TuKB;ECmCqY8 zi03J}YU|iDH>Z=QK8(IyvL-+GnV(M6$hbeFu}%}4{C4#%KE5~@w78O)BBS1UhxHhc zgG2q2j1WHPngKww_(;POY9L7gBrCsc0+goZ)19#$`E%HgG7uqrAzG|aKyo&Iw-fc~ zZ>khe|KMyN5;(Q-&#XyOXpi`E&m?D3?M$=7+T@RUNk=lA>GHh~Qn~!ZM@RTk^m0HV zgn~O%z+r(@3&t03;M3#*FuDD!{RD_Mz~IcCDC~mW0%`80TxfU&1u9ZRX@qnKgM-fwELljt?mdfgtLzl`mp6U^@Lln?h}If2SP9KiHR0 z*!~(_R%5qh8Ft>wU;E0*Rl1}KKw+t_Ud9#Dwh0RNu?5(Tr_W+4y0({do;(;>qZIuy z91|9)k-YZuf!Nx4$O`BKv*P0GplDD!!n^8EdeA}sHd1K;sGd-T6vF04kR>7&)IfQdU1L7_!>)YMi2qyN)?k`5hB< zVmP#GS~#6?H@1^thjeA@+)cb0Xg1Okf&1OyutuPM^^N{sz^B#O1)s7hVSh9K~ zC_M$1bOIvihGIGJ6zBmwLcy(DLXkh9tv!OCaPZtdRaV9VkqF5wgYVr04;i{m>qARA zrECR+4+s1oE(oX~E+XS~eAi6rP6kT9bC*aT!!!Y1R4>65#h~T}I3*||3rM4xWr^U~ zCM4e&0aN^#3H{@x(DP* z3mw`mj4aF;myCiK19wo}fgFCU_-On2{}{fG$3^Rca?mV%*7WFAY=FSVOyZl;w)P8| zcp^$_>JO)<^Mr)&DAhc*z8M2T$lF}DQ63E>QOCzVhGVbKd74utN~&U?oLme!qC?VQ zK*#ON)l2}sD*g5TArL4c3l}LSP;_T|;`GD;jPoO4O+yC=LcqQFHKl=W^BitNejEC$ zAZovy_otA(K_q;T1jNvSv=QQy0~el6s}_ZbhaeLKojXCe3u#5i0h=mBs0AFninVe` zGzPO(eI0~y&uKD6BSxS5nEB!q`g;8XWwG-=}nABEUw z>8ByCu|0UhVeu^~)I8Th6DZkp#HbS`uaV+h6Mj1G$g(_>b7T)sXcmOIsgUkOiEYWr zLMm7bk^_*D@q!txkXZoPtT>qF-5`U}aQ!I{Q+>YIjvW>e#fu*wKj(C{wQ=9-2H^sf zrMS+_j9W7L)pc*Y84`+5BqVqZtT87c*$tU%MA8B{QZpzHV2L4FNuad^fS&a(n7@R; zJxJy{LDP8>VC%tT3e#YKMUcUI+)NMt$TP{aUj`DTOc|HPZ1187hKKQ2C&V{jq2p8V zcT7=oJbl6Ihm1i|(goh=qkJKuDWa>-7;}d;s?J<`EtQGNRh_QBQf!OV0J*Z zxmmqx$&LMt$7hxYFp|t!?<|Ob3;T-enL>`w@=vTC<)%U%i+u1iOYy^8aMadTTT8^>*jkG$J%t1 zP%MzVLFSpS<`WhLRTkh<9Cw3YV{V9ud*h?K^cE zYA#zAS9YhblHF>APgyX|T_(Hcm#si~UW4A$Ddf*b|wuUo|J9*lGwJVz*2!AuN(F<7(#EH4WbE|~ zo0%k1f^yVuS7f4&j{E6Fn9^Z2Z-GfK0J7S5$C*nYk9h(+6x2{aIG68?M|e6FL4yq? zEnA^15BNn%;0htCLhwKi`t103hjfsZr?3LLp@s?+l52;&1kzA|K&I;w>AgwVXl5am zP9-3a0J>kr@g#%#*B4;J4}*2p4cIe?C~6@Oya>5>&M`}Li1KhDXQ2a+YYb8wNbwLL zdn3Xwu!v0viP6aD4uE$2bFrE(n;0-tvIneGA(%q!6L>8MyBu;{SJEh-s6{8>+93-f z!On@sam-w;v60Kq*OG{6hJmR`UCn=awn16xEuc-PUTIB+D9P|v63;71-6$G77p7BHj&?@5F(~i2j zC{IsT3{0JaMT;lr=O?we4lultJj+~@VbN8kOpaGY#tAk&2G4JFhTI&}BXEqB;+4Xr zs33O`!Z1&*Vl$F`-n?8mW6!-AdxRFytroq*8kJ3)O(=2V7RBHel||^UAmD$3M$AYk zp@5|yb4lFt{JBhd0;+yt*gi5s&OxX!3vdreM*!qZoK$-V3^(W;Sb4|WiIvJ=(CM0OG^Eqy40gKjUgagPBi0(C& z!5IwP%eIe$Ak9%MashsN>Z&`4@qYCYO(0GlXk9@VbcO}8gWuf_%}hCBz&aTs?123Y z@fg_l^9&4Rt&X??vlv#IgLJw&n`Uga3shJ!&T4Ia)-H}>CAp-uF>PS^96RIa=WRWl zjiEYpF6O5sl9Q~&8>D2V^u8OVbQ}1y(_0VI+XF@yYt^S}S8cTml{Wl*>zTPpO(d{S zy1VyEWaN*Ism&Z!SzO`7CBIRaNq$&{7l z$OHnbK76o#5(u-vP2cntVSQr#hf-AA%2Q+S9&t+Qq(LkK90`Iz8{r&#bfE8Qg@oJiI`sslXm6FXgBp`!KhY85Yaw+l!9j&< ziG#98bWiyWL8gvi-Fod2o8XJ|z+E71|3DhS8e>G9q6A@csH9@EyHt zp{@;=?1S#QhFEWp<>>0Z$m$HNO7`#C8~YptXy^Pv~9#p3zwk1F^N26W&L1+*<-0F_G2$&uWW!CYw= zI0WZM;dm#}rRTXG+9To#gcAc^E}(tT_aJWxNEVMDKJ@U|=RxRKP?c3hMWvq#B6g5$ zXM7rAA5?2dIN70v7$RRK`{H}JH$GU{x1@3ywIAh0B`8PbfoA@YaLoKQ0d zNKfO|?Tm0oPcPgpyWRI2vp>!_D-Ao>tm`SCa4n&7=zI1v8!MwpKh)0>Rw{{!=b;e@ zmCZ7!OLPuu%6=9ndKeN)aQ)Bl-CqZ=7tQtpD)uRMPlscg z%u8l0xul{`*5Mu9~|5zSc~#=HD0A_xE?w0Ci4pHEj( z`!0yyj3}k_Mbz@G$zQAlvTA&mLspdh)*8@q&hgJ^R@7iVZRz|1vjphOa79 z65|*zb!J|WEe||ri2*Mq=y;jgin6_4Etg+7<`PQ0SGV%b0T+iwTC7DMzIZ!_0Ij10 zjhI1=A7{;ZnqqHc5B zzui&Pyp>_031&G>-tV_Tep2)-N%+z&#m7wezw=X{r9?OI%}2iY%(eR%_MEpFF&|^< zauWD>r?gEp*@L$5hmWhu!N z1sx7uk@&f!9A9{fwGckcFZRgA~a zWgn@GAcwsiEa#?aYhGoM{6a&&R2E8ETSf*mZmrXFln5l;ziYblf+4;<^IgehlbDtZ%Z~o%WA7cV`RQk6fBeFX> zQe>e1&FjISnvGU+RArd!CTskP#8K{gK-pCPkfK|F&2sUCEq?RTx~2K(YfbOYeY+(u zlLdRa2nOEmreymzA{UQ3!`fVRkyrt90p_`MrE2`a95W?VyV|kq7n*;ubCtyL+RKo{ z<0)(1n;xlHNR&?-KL7C?ZZsCrbVs`^7SZ29EAs%3r4X{_G<7>QYvR8(De8!g+iiBL zs7W29ZcC}IbaF|w7A|DYlTWz$&5T-P&bRYN{qzgq8;U%}JS;ekwU6B@vyqDC6n_0& zDlN$MXG!U9vi7PYBkFs?)$0cIUELkBZ8MB?e0mfWF}{tOXEftC*~YzbwEg|-oUY*U zqE3X*TRXQLcPV}uv-egh`{T3x{vO0iWI8UEea=c?qM`}Y$r`I}rtUOFwYCqJt}Q=T z#p}>;9)l+}-HorqN3=AE{MEBVp_=*YRAd5{?^?F3B_LC~_;279um4E}cf4X{wcL1T zp_x4B=X$`l(jKY!J#GHx7%uIHy=+G@U#qPBUm^1V)@bwi>XW#~`0N+OwE=SV+ncwY)rtBn^s^~>vMv(_WP{}FxrX5!$G z-wQLx(QvMWMfQt`^0X(JvSeSFZC6+GH@I@YqrgF4kidms$M%RKD6vjA(|b6rp}%Z z8E#I8b_DhmEV*J3;uU*SX0E)k-I{9Ud3C(pSQ?~vyw)&s!s`{nd1~MN;z;d06LX*8 zK-f1zMyB?y@Pwl?)7Jlewx#bjL8LzWpT_*Li>zP}?g#w7%$N>>H*ZQM!}mSwLyq9vj6YIIy$)~PDS6h0MH^TvIaZ+m4ZPEe1nr6=nas#AT`%B7@@c1=`n z>DA=ZYXj#3`r1Gx^Y7*2pD%p48-^eGY-%%{o=r>A{0)yQrDG-WLywJ`d}abHfseBR ziXSVnPboOjw9LoO+h{)$GpLeW^e+LEtz|y&X~g?OJ$kand6QlhMzz0(oxKQcpYA=5 zf!qz7itzyTd;~wfcD;N+C~vWMlaBL_m8lLz^T-J)*|H+Kmif?m#SwGfW}CX1WbJ;= zs8CY$a~%QiCx*31`el?=DGOO?6#U;6h{Gk7hYH zyg_(U*{Le`vW`&AjJ|jA6)*0P>8rjUy_(so|87NWL1+&FyJh6lW8cT|;JJNepM7yD zOmTT?q_Q+ff4Y;`x6GXPd(Tz>;%^CxhtX*0L*tHO;w-OUA5}7OowX4CSxF>QhH1@v zS%o$t>N!=dw)`^T-=|wvZ}gVq%9RN_G0nJd&^CB+FhN@azckZgPg2$tKV^v9vEZ}i zs$^rVEql{jQZ1HAhp%>}yK87*OWnVWVb{< zwAiR0z1cd+fFn#&(q@NDX;s;+k)8J99y;Eq)9EgrI2KTuD!2ObqVdY-sU~5do#=G<_+@P zI%1OK$$y7vxle+9?iL~u3_B<>B^#^et6LqFwfb=xV*1A1|?Qc)LXQzBG+3nMNKuFidOTX#rxDUt}D>dh^+X zKdvV@pQk=`AJ)KRSGT$FZKyekY-5D*5>)G*~U6`A(a$=onG(}~8-1StdC6)$tcAF|jsFZocpfl(pJvmEK*_K}#)j#|Kk89y7CSeswSV zwd+-=!X{OUHl@>oG>?C2&C)SP`ZlY`$Qiqejq*xIaso#(`${HG4e7a< zXmEqHI6&vXs*+87=7=?_gIJOV+s!S?!=n~5=^Q#2vFqhN)0|U%tMYGkzm=muhh6QC zXA1F2SeXh@wLVuLwj$%d!G9b3M)A+$m$?BO^`F*E>ZfdBW`VRzuC|93NjWpq#2ZlnM2 z@OogP+KA9_|J)G@CFpbGKf@XEvB+rzg_`@X0g&iEhnoA(_@PiAzCF zrG_Oj`7r*R{+9Re#}(i9l2)_jPP{K&gjzRL!*Xftm1zu-$)=(5O~nhLj_D8UH)iy@ zN7(T0d4A3tPQpz8QJpXeKY1^`Rcow+tbzjwDPk{%T*SDe*m5VKoldcZUbAHa$J<(L zfsIYK#mphSelfCnF?@7Q{>@Amb5JjBNdvv#^JI}f^JsEW=G%x4Oc}iepL4tzb4A24 zy$@{_#PdlQg$>}1EL&*ssCi_=T1c;L%RMtT$xH^q^u+pine|DPreX^-ZA2GC3Q9DW zYbvTMski6CBSx9GtNna$!Kvvov2Q_1z1GK%xAQ9t%Cgvo{X-T%U5)mS<%r4PQ=kV?D-f zIZt>~jHN#i|B`bqP8<0wM3I{C{mkETKAy#_^p-&Pb`S)t3? zOS)L5VF_7P4>Sxpq$8&5oo|PB+MJuW}Q8ALpwBC{DO7?xJ&e8C+{BpN0S60mD zNPNkhHuI7G%ZBo<@|mRQj9cYrc7*>tcTzVYHD$SDo)vMX zT`W=kIHHn#@k(Rw^IP}|H)-#bIQhoj$r4iuHw`fgrQ`FG7{>4VYNBPWVvs`~Ic}R# zr0=cbF-njzBGz^G_u*?f^@+VMegZ=fQEgRwx7<>aQ~!{iTOjKt{Rd9tXs~Q33&v`@HcTWe6lI`Fq?g}DBHe7#giN#>(5mOy*5Nf zhzf((CRp@R*H2(d)VSolEIwPDmQ*G`)fZM@cI_;8P%X=L8~x2lY3q5(Z2g6Po+HfT z#WstgDz}o6l9d5Mcd9pM{#+*dUF=8GB*Rhh zd2!&Q`6Mn?Qbffq5eu(o&~dg6eVxeCygT3QR0{nwt)1&s?~xnNG$fb4O)=I5W*?bt@(O7dL{>UrvUd@df6Th5J*Tly(8R!8MkrT?>f|o|7 zjpUPZAJM13nJ(b_IU&nNq)3zSYveeF-ob>8?b8!$DIO1zKD9ED5L=d=M;PN@%efuI zg8LG2URUSRDIS*}*ZbVR^*Pfxdqn{b6S5=m!#g7n(^hZyQ^Yjhh=QGbY%CBk2+^kA`RTgSJ%=^oHS+o7Q-T2=7_2xpN*rQB!Da}@kZbqejL-QR8znI_7tt@sN(PhP!FTZw=oV;2`sy8BIJmeFW?E2#T zv=B@o#$Ihj&zhO)!K3TgcW=2D6_O?N2)J&!o0v{<^O63!Ng-ZO#442E8Of1|9gLpB z?eDJ?$4Xy*uj#rkbAu^HF~s-dH)HO^>O}#ukfo~88vE1aFMZ^i_r*7TF!@i#tffN2 zT9b?3c6Qe-eN@xUWLWXd*VN8$CI!kXz6K{` zEPB>PU)x_yiTvXNG&dDC_GZvIcxHK}!(?|DXxOM3qBvs#L)Mc+~-ut;t z>RjQh-O*M}n!%x_q2iD0d{9{cc_BN!UKa6&8W~^mt5%zl;jxdyU;0J(wb&}?M7Ovz zZi$*#D5}!q8q&Q`FDKWDQb-L`41mUCkIP-SXXLKaR$E3rVd+ACmY00RvPO@Ki^M{cd#13aH_mG}B{czpvJ@5R7!~?G z`p7OrCXN@)tXGHAjyf5wqY1=x6$wiD7}a>MRjsoNFnISS(q-E2HhKG|D(tKjNB$W9 zbNz_3DH~$msop)OYS7=`lkW2)+`_ij(pn*NF;9igfj(YcCdtCvV@((=5J6W~K*(aw zDHbEGexE{-Lj&{e*>yQya)nxT=GJff)-_ib)9QUliWKZj*x^I@RI~oBA3YtIDjIR+ z4ps~}%8V(z#V~J)wBFbdA7qKwM#`nu~+CfE>(b%+1(SP79GgkCsQaJQ;w_JtkxJlCan59 znxVgU*XoXHpROW@WqX3F(x=S7&;tbCO(@$8+6@wR8ndx|A+O4=*X!TtkmQ?)ez(ok z#rI~5-Ms!rqjtVNv6doz2b{gqBZKaz|*qW<^>@>e(;lx7ilOJYljJi8I_)2*c>^S|} z9(8pI(}p1DCgSlqu?dyR4)hEclG3Rrv=s{(gof<&72~4Bl<%Jgj=weG8QMJ)cUI4+ zfLVePM*Qd)3l;O4M7l|LJ4~a2$HTktS(&1Jrg-;`hcFSd5wEpSNMYt~n)#bt!&^m; z&2AHB2R`OZ8s8*LKdo4pb0~gW`$l2MvEocO%4uV^N_jngU>8mB4*kMJ{xvJJT*@PX zAJn(S6Hd+j`Eii@jCoylIl$1bH>{r_u9ZvmjC0?QiF9d;V`2JMC#RKg?y)T|wu3^L z=@+?{@0kQXN&k7MjQt3l6oRhD?I%t11sKUa82uRU7w3MD8hi^Qv9T~rn4eAxDN|t! z$gv(Y;pfPJi5h}0$-KNY)@(gewUl)bm@yW>{cRuJm1C2~?rcK8#7@dcW zPZ7@ai8V%dWB*ms+x|C_MBTnSzZTK(qNGGxqh{7pNj$OpbN&@_!=qQ$ZANS^^4)!j zG*pAW%bDXhE-}V-KXX|{YcrESw0i-Dx>trB!#21@P~_tBmf_+l1;d z1DW{9!duKg&AF&5$d_%gco=u8pLM{AxwdBArlrY zh05{2yqFtPeW`3S#(s{dJ4i_NW@3e|kLR1+bY3@D%c7q5UB`M;N!@C+efuEU^=h<| z=vap-O>W~{tnnFsSBFu}o{Ikrrfehig5a_Z_mI7upSaVl(6ZF>?p*t$gbdq$LIF67 zo!u@T2K_^a@#?3gdo7s3>)$+lfCB7(1+KFC6+W3!iTH z$gVu5CR1_mM9D|~QSg)9bhDkux=)>#PakTCgky{1WU9h*VJEtFu>FQ)o{G}_#aub5 z3%T{EYk~5rarTm1hJ`kDh`jEt+|`eSt`-ZUx2`<-ciAsR97HbmkgoKd?y6M;YMxlU zSB{Fvd}v*fB@K>Ohg;U}?bZ?uvBaUQi_zn3o(uDFDqM!x*fH?xoik+Sl#XkHWi6Z}=eBOmIyC^>+)}JbS zHN8KMK1ivbdJ@ivI`Mju1*TH{xbvjEdLuoD+2zIH&q1QD#b49+MW3zj|9Y3|urk=V zS3`N!wLDP8xuZ!f$}dvn5@<|L`74+1$%yP}2;mH#^jAsoWNTmH!FZy=yL}(2RNZe^ z^b7sBf40u6pUoa;oW0mr`$gH6V=F(g+ked5Z_M08ndsJgm1hr}s`7rihd);;jE$-` zh}tppZMN}k-loI>D&K7;P0OOXd)2*vcbJovlXTGhO zjgMS=A(hhj;MKot8k+488BXt<$XZ`_0^itdKI9yYGkZxMb>^M>WL~jSex@8){jTSu zB{W)fHPYoC3}?++#f)?heLVik%y#LocZ5PIH6Nv5{zzL^5K%9oUL5IIC}$nbjo$dw zQ|7;d^Tl5pOtugQsc~&xx%WSSCJ-(@&xScmC-Kbtk`H$d#$DTBa4qC45kLQ+mUiwsA)J5;3C&{2b zXsavt|BAcvu$tDsogo~QgOo9Hl5Gm9jie%tnrB3$I?d7~X~I#5O0|n9wUOpY!*0~z zq*95pOVWhenk3EA;Ju%{`M&qPuJ^C+pKo95N?7|@&w8HUyw>l&tCNOr{B>3(hAE~d zM=cOSmHY)GSUTqWcDfP9rKVwYRsE_*i>k~QW!&{?5skR=Wh=J_kJW;##I|C!*fNDB zoctPBT2eEWt={RVmzXpdl)rk(im(--jVUpG;k}`^ztSW) zSzk^+2|?0y)^VO=$v)f5bC%C#E#hW5a77!PILPzs{%lqbD@U~i$=B!|s5fGqZ5^@^O<{ez_s`%(`DI6Mh?F8M z3{|SQr6e3$WqzxMUpL5fx9}?31IDgyzi}U-Rs3=}21jo*%xJn4rK&VFx_*%Ea{*mS za-qSYs;=UZqQ}{RH73u^bDmqi(>vps^iQAGwbGsRBo)sKjM=F>9GVL=R_ePo$gNzp z>cIl8l7U9wB9Qu0?ZoVttoImMDvw#dEh$bRq#o^FTv1i+2R||2x-zW{0`@*yeXhHx zxr}!7M(jT-X3MJhGpf2ARLqvE{25a9DRV0ys#V%mov*7{`2Ef6)up>k8Fw;P^54}j z_^cnN>bJ$OY-2%#kZW*Yu^+;_J)$r`uKX7HKEX<@x&ifK+^I^|K z7QAqm5`UC`9FRHf_~XlNPcX9xPy|roWBL7fI-2!EBXcuLp!gd%IUAo%HHUxW{Dz+@ zi~ehskc*45`@dF8NpbM^UxnCzuT=g=4fo#*rsN`v|Nk!%dL1nj+g1m(rAw_2=mqx+ z-vag`-1ol|in$NjgU&Tl#_QB8sbSUgO=y9428?l&4Yd$>-F%$&y05wmbyaV%!P50J zn!LUsEtHe=!c$hdOj<*O-mw&Y32|}F4eU|9#SWu*EPJ=Rx0hDYp(Q04COk3i$-~RL zmHw&^tQc{!?9;f+{z5&@Tg(CA+)e#1%G$!qf`u75In^D5nw;?V=Rm7^FiX|KJm{gL6Jlj$MOnxmUG^@i`rd!xIGsCaq9meOlxLj{MGugdk`*w>n zXAT7`9l?A(i;Gu25f>MK{=uG4F7n*Quxc{!EtM^Tf!1bb@;W*?H;!y{*td3Qa(dys zt2l;SrCNS2W!wVxl;460ba(w0zJ>VT#FUf<^vURHX$`)8Y0Wr}UmgHI9(d|0Cj|V; zvNAFrmX*o#ELl>$%irWJ69lhnoMm_Yhb+76?2W;Hi-?Gb@811DcEkPf@YRg$Z0R?$ zU1waS1TRVnLLiiA59{JVYe7z#nen`KSO^DX!A^vIrzOi}At)s|k2ERW=*kVhb4PPy zu;$sb(M7|N1JCw0?=fo(nlxSvXv18x9xM9MyA>_a#^QnZO^ ztd#i&d&A|+m*a)r+gG06$D6Ub!0^rh>$cVdAembOT_gPN-Maev(0TLb)z{bK!jEJ( zl&Eo%JJ%QN+fp?*H+SkN=ZVqYf?McD$AyDrq?vPov$JzzQj*Tb;M&g4N09rSam)lX zr6r`M-cL5P{f>{14uK~>kVq(kT5Mxp}p7nRW5M*adl0l-|!k&TD6IF}GyMud0?Wi4+X z0LApx)B*qoRTCe1&H@d?km&Eg*3C-HRb7vp;s(L?vhBU0^C6%0?FDZeBuxE_V ztpx@g1#?njkK$dxUg4u+cm2VX@$ltK^%V=R(X1w4zoxa=<;;Bbl~JO(UAjaDu@K*? zym0PpsM01!!nj-ucEQj})9yR$fw+v>w;#56@nQ;8J24S&vKMA$=`OZE<@$kJ`8AN0 zi6#TGadOfbeKEAW*wee>%gYr;$H$qwf0}?RM1h(=efq?A{YZUXotA?w9TtVcM=LW4 zhWikPlet)Us&KG;4eb$HU;EG!yUF<^=AtRQtgfYH?K+MozCX&|+kQ0RSXo5OtGP1M6H7{Ro4XKO=D17I;s7lk&S6xSYCnT3dr>AT6 zI33@!XOELEXR(^exIs>6F`%t0+#?~uup7BqV;+)4Wwn4D>R1c?%^Q7%LC$)({{~4v z&0OSLsv;7Sn3lG)a?ERRDst!CtA}7h0|EoXYBH@?uUT_TC5DgJx92hETQpS_L}#C2 zCsn8|!H>WR;!NMc?}skZ2IuOTv2#DNI|uNbJ5prx<`oO(c4x7_b((n=ig=nC5f!C> z^5nW}u2l_Y&={p0R6_T6f=Yn+;rD&w3IAxLJcbHdP2 zQ%#NM8f7US??aFHIGSbS2HWhdwqx1#uc~3oJ`PV{e<++l`|SvO#xMT)@EBchdQUQa3b|0dU7uG^-ty7#E3D?*mw0!-0V(I!62p=8EsyC0oJSKhCU~H_A-J)O6J2 zGIMRvIrFaAt5~?Fvod68!W|Iv?dv8#IqW}{@`lH{8sq947>tq@gRjyE7Gft(8?&Gf zAdRaBdr~~~+DvQ}nz0E<6BBJ;*c_FQO;q(b9sMM|bVL6x5w@gys|AoHwcHeIl)9)rJUk4)4+>l~TZWIIJ$kEPU>}-{8-duF92~rq1a}A^;KF))dV-lqg-g6Y z4(7r&caFNT#wR8A?1{GDm+UH)diyp%@p_<}+RC?(JzzuxEbHba+Pv z1qEE!8G+w~yL92?mjWmnv$i&9ajB+(fx&KyUzrISS3~*v`N6#y0}w=g2o$Zpy*&+4 z1YQaNC1%^Gbgq#omXPQmK93Uy7YlNg#NMhjHO*`iw4wt{q8AvIb-1uIqyz!U^yfci znAT~9u|-AF=so(Fotc^GHe9op%p>yPC4FouF|Dt&CH z5*LDg=lHQ>b)dC-2q>K%w1nM;9R}ynVD8ncSKonxiv%u8G^p1oNb`EZR$u%4`QNzP z5d*JLgLiq3aiDM8t_*!{gfM~fDxs&xlI5^pPhX$^YP7&9*F(5ZxOW}#)eXS6903D$ zH-JpFoSjGWE$jFN1V)+k8C?SC539;@$QuDAWmUh6H7Gh-M}MG=w;|ATj3b(HHKu_q+6^1yyyKW_WD{ZXU0r5l7jVJ+l zmjwD|D}81r=szyDeovbxNDEaGb^=ze$9O?|17b(%Z|~>8hNd-__q%Lc%PSzWIYe2x z@9I5YXHbB0&z{u}-~XCk8s+uP*UNBkuL8}k?Fo_I>2DP>(1QA}UmpX=c(k?)Y(RQ| zIUOu)?!OJMThURcf!+M*vS`sFD{4%| zkVeJKVJAi~?0DP9Tdn$oy?eBG7dTvrWi-ucZfI#qMsVbTHhDJy5e($L0=%^o7WQPG zgFG|`jghp*z8&htBFdL#We*-aNCI}`iXf$|XEKKaQW>~UqV}Rjx%ch&ZHKZTC?oc$ z%uysn*#j^Rl5QjMAP*g_HlESO7$m|1YEB|JH+?1lgvq@;)~mTRAE z8+Yoh-vV2zZkKa{{1t{%*Vs4>XqDYdyuMw9HNJ2m=XO}wz&<;XkYLN9&724QZ(IC9 z1K7n~g;>KMHkza?K)d?e#O5)OOAWwoj?HTKSwBgF?(S~G@h4HfqkhIyS0Xr0UxlMu zJCHviv=>rQ-54BH&3gDdM+|iEREo>yxL}|ntV*RR4Wj}JMCSJIBFJ^as#nn0a7KB2 zjBTqJNIjK=4+~KZ9UU{F$v*4%uH~&B7}q(?9`11u`z#5hMHb>JLMqQd(KGup*ERNk za{Y{3@Xlp;M8u^2ONssa6L1UTH(7*Y!`QgpCvr1%4F!|$tplD0F5}k7#i9RBM*luI z1EHv@h>mu&Yev&&k46x-S)&#Jgw}U*{o`4F3ehTY%y+=`U5Bz1J~nP5oAA?RbaXU4 zGV)eqpT|erO7l$OYY@?Nx)d-jjoXn-@%(wM!oot5r6b`a=;#6d{@nn0fW0P(sD?%$ zd=pS!(w3At>H9%ykUdkXQ%Cuo{vVzT7)? zk+q_5_~n7b)KtSuO?09i|wz?)MNo_b2koa&awK zrhMcOC!(J5XRF)J-xr`FVu4HuY`B4=M!<0XUQj$);9QM&VX#u0lt~Kg^7)P`Gqioc z;OJ35c!m15HsW*88eMIYZee4i3avl}NqYpGp>BiX@3$6S`)6I()Q~510~pk|QLUj> zK7#k7Rhph}zIl`PZft@kMR&?3-LU@c+jvk)PG%3DSC6Fb-;Y{R0l>lxZ-UWf|0ORKY-$!T55{=NZu+ z>27td*kAmFer9EFUmw{v%*BR!;=HkPMw3lh|KidhX3us{&mgL_C~V=o^t1EVtzb*q zdn!9YX?XLd7eFxWRg|bp6B{)r;BeAV=TWx)!!udGFJFuL`nbh%USB_YvEjL#=7CE$ zkqBBLN&umGAj?UTWN*lrZI#xn4}&>HSrELzby}RH%dP{jcX74g{-}^nsXA&FgV6)< z79DCt15|CMzkNmx`*Fdh5!DvtWIIGfiT6Say_KDv=*{}Pu>Um1LagD5ir3`<4#S_+ zY+Lhh@p6g_u~D zBhsxy(pq1k#SuXeM zHRdD&K_!S%zMLv9{skw~^NqeSoHioLR}o zF_`ZK*?H}J-_i$=af{QZWue)8ox73uK?l9DG@HY!`1AmaAA0y}&a;U5{^|`I21Av2?HV_%rdH6o__Q<) z1Qgg}Ei@wtK$pZ&aj)C3DwT!bpE6I5_=UovUW@pRMXJtL!krrqK&#M z{(%3f9t!Um%taAF9JZ{WH5G+R)Ep!^wcnDnq_|&lRvUo=65ea2XHbmjL%xcd4Td<| z3=eB_`g8fVkuH^$vSO?;xTiL1j~>Vn;^@>KM%T@9*R4#FV0? zoR&|_qMEuo>iH_7VMk%tC0)PXPuAbIm-Dpp{R#Fga-Qv4%*e_jK|LzukT*%kPyUb< z)P5nItWh_-W1<*MjE)r?H&XQnno8g{(B1I+`*Mz#lbXernOUC2#yEiU^7`4czmRB2 zP^qzpAKV9hubzPc!U>KpnOzI`x zo44~VM3Gwg_#%CP)*`Tu`|#mRjCO)aErNd(+J)GU6ea@Vj#RT8kV4})j=))bH4b7p z*Yf(hOVe=^44`GixtK0x4_;zU-mEXtdDb!bykih$VKrK4jX5fw4CFX?41wJgkXywR z_d64anipOvFM`7o-a>!14S|#KgnLo07d2wXmjRaom|1MjhT`^}1+6b@*n{JN1AA}8 zy|f}?v4U5gzF*hJeqeEAcXDOdFe38JsG#2+H&GL)k&j`1$$YZiN5a^R*X0=3Ys2n@qKvM [!NOTE] +> [Click here to go to acting architecture](./../acting/architecture_documentation.md) + +## Summary of Control Components + +### Steering controllers +> [!TIP] +> Follow this link for the [Documentation](./steering_controllers.md) on steering controllers. + +#### pure_pursuit_controller.py + +- Inputs: + - **trajectory**: Path + - **current_pos**: PoseStamped + - **Speed**: CarlaSpeedometer + - **current_heading**: Float32 +- Outputs: + - **pure_pursuit_steer**: Float32 + - **pure_p_debug**: Debug + +#### stanley_controller.py + +- Inputs: + - **trajectory**: Path + - **current_pos**: PoseStamped + - **Speed**: CarlaSpeedometer + - **current_heading**: Float32 +- Outputs: + - **stanley_steer**: Float32 + - **stanley_debug**: StanleyDebug + +### Velocity controllers +> [!TIP] +> Follow this link for the ([Documentation](./velocity_controller.md)) on velocity component. + +#### velocity_controller.py + +- Inputs: + - **target_velocity**: Float32 + - **Speed**: CarlaSpeedometer +- Outputs: + - **throttle**: Float32 + - **brake**: Float32 + +### vehicle_controller.py +> [!TIP] +> Follow this link for [Documentation](./vehicle_controller.md) on vehicle controller. + +- Inputs: + - **emergency**: Bool + - **curr_behavior**: String + - **Speed**: CarlaSpeedometer + - **throttle**: Float32 + - **brake**: Float32 + - **pure_pursuit_steer**: Float32 + - **stanley_steer**: Float32 +- Outputs: + - **vehicle_control_cmd**: [CarlaEgoVehicleControl](https://carla.readthedocs.io/en/0.9.8/ros_msgs/#CarlaEgoVehicleControlmsg) + - **status**: Bool + - **emergency**: Bool \ No newline at end of file diff --git a/doc/control/steering_controllers.md b/doc/control/steering_controllers.md index e7c0a474..3b8cacdb 100644 --- a/doc/control/steering_controllers.md +++ b/doc/control/steering_controllers.md @@ -2,10 +2,9 @@ **Summary:** This page provides an overview of the current status of both steering controllers, the PurePursuit and the Stanley Controller. -- [Overview of the Steering Controllers](#overview-of-the-steering-controllers) - - [General Introduction to Steering Controllers](#general-introduction-to-steering-controllers) - - [PurePursuit Controller](#purepursuit-controller) - - [Stanley Controller](#stanley-controller) +- [General Introduction to Steering Controllers](#general-introduction-to-steering-controllers) +- [PurePursuit Controller](#purepursuit-controller) +- [Stanley Controller](#stanley-controller) ## General Introduction to Steering Controllers @@ -16,12 +15,12 @@ Currently, two different, independently running Steering Controllers are impleme ## PurePursuit Controller -The [PurePursuit Controller's](../../code/acting/src/acting/pure_pursuit_controller.py) main feature to determine a steering-output is the so-called **look-ahead-distance d_la** (l_d in Image). +The [PurePursuit Controller's](../../code/control/src/pure_pursuit_controller.py) main feature to determine a steering-output is the so-called **look-ahead-distance d_la** (l_d in Image). For more indepth information about the PurePursuit Controller, click [this link](https://de.mathworks.com/help/nav/ug/pure-pursuit-controller.html) and [this link](https://thomasfermi.github.io/Algorithms-for-Automated-Driving/Control/PurePursuit.html). At every moment it checks a point of the trajectory in front of the vehicle with a distance of **$d_{la}$** and determines a steering-angle so that the vehicle will aim straight to this point of the trajectory. -![MISSING: PurePursuit-ShowImage](../assets/acting/Steering_PurePursuit.png) +![MISSING: PurePursuit-ShowImage](../assets/control/Steering_PurePursuit.png) This **look-ahead-distance $d_{la}$** is velocity-dependent, as at higher velocities, the controller should look further ahead onto the trajectory. @@ -32,17 +31,17 @@ $$ \delta = arctan({2 \cdot L_{vehicle} \cdot sin(\alpha) \over d_{la}})$$ To tune the PurePursuit Controller, you can tune the factor of this velocity-dependence **$k_{ld}$**. Also, for an unknown reason, we needed to add an amplification to the output-steering signal before publishing aswell **$k_{pub}$**, which highly optimized the steering performance in the dev-launch: -![MISSING: PurePursuit-Optimization_Image](../assets/acting/Steering_PurePursuit_Tuning.png) +![MISSING: PurePursuit-Optimization_Image](../assets/control/Steering_PurePursuit_Tuning.png) **NOTE:** The **look-ahead-distance $d_{la}$** should be highly optimally tuned already for optimal sensor data and on the dev-launch! In the Leaderboard-Launch this sadly does not work the same, so it requires different tuning and needs to be optimized/fixed. ## Stanley Controller -The [Stanley Controller's](../../code/acting/src/acting/stanley.py) main features to determine a steering-output is the so-called **cross-track-error** (e_fa in Image) and the **trajectory-heading** (theta_e in Image). +The [Stanley Controller's](../../code/control/src/stanley_controller.py ) main features to determine a steering-output is the so-called **cross-track-error** (e_fa in Image) and the **trajectory-heading** (theta_e in Image). For more indepth information about the Stanley Controller, click [this link](https://medium.com/roboquest/understanding-geometric-path-tracking-algorithms-stanley-controller-25da17bcc219) and [this link](https://ai.stanford.edu/~gabeh/papers/hoffmann_stanley_control07.pdf). -![MISSING: Stanley-SHOW-IMAGE](../assets/acting/Steering_Stanley.png) +![MISSING: Stanley-SHOW-IMAGE](../assets/control/Steering_Stanley.png) At every moment it checks the closest point of the trajectory to itself and determines a two steering-angles: @@ -55,7 +54,7 @@ $$ \delta = \theta_e - arctan({k_{ce} \cdot e_{fa} \over v})$$ To tune the Stanley Controller, you tune the factor **$k_{ce}$**, which amplifies (or diminishes) how strong the **cross-track-error**-calculated steering-angle will "flow" into the output steering-angle. -![MISSING: Stanley-Compared to PurePursuit](../assets/acting/Steering_Stanley_ComparedToPurePur.png) +![MISSING: Stanley-Compared to PurePursuit](../assets/control/Steering_Stanley_ComparedToPurePur.png) As for the PurePursuit Controller, sadly the achieved good tuning in the Dev-Launch was by far too strong for the Leaderboard-Launch, which is why we needed to Hotfix the Steering in the last week to Tune Stanley alot "weaker". We do not exactly know, why the two launches are this different. (Dev-Launch and Leaderboard-Launch differentiate in synchronicity, Dev-Launch is synchronous, Leaderboard-Launch is asynchronous?) diff --git a/doc/control/vehicle_controller.md b/doc/control/vehicle_controller.md index 62dfefe7..9a307c02 100644 --- a/doc/control/vehicle_controller.md +++ b/doc/control/vehicle_controller.md @@ -2,15 +2,14 @@ **Summary:** This page provides an overview of the current status of the Vehicle Controller Component. -- [Overview of the Vehicle Controller Component](#overview-of-the-vehicle-controller-component) - - [General Introduction to the Vehicle Controller Component](#general-introduction-to-the-vehicle-controller-component) - - [Vehicle Controller Output](#vehicle-controller-output) - - [Emergency Brake](#emergency-brake) - - [Unstuck Routine](#unstuck-routine) +- [General Introduction to the Vehicle Controller Component](#general-introduction-to-the-vehicle-controller-component) +- [Vehicle Controller Output](#vehicle-controller-output) +- [Emergency Brake](#emergency-brake) +- [Unstuck Routine](#unstuck-routine) ## General Introduction to the Vehicle Controller Component -The [Vehicle Controller](../../code/acting/src/acting/vehicle_controller.py) collects all information from the other controllers in Acting ```throttle```, ```brake```, ```pure_puresuit_steer``` and ```stanley_steer``` +The [Vehicle Controller](../../code/control/src/vehicle_controller.py) collects all information from the other controllers in Control ```throttle```, ```brake```, ```pure_puresuit_steer``` and ```stanley_steer``` to fill them into the CARLA-Vehicle Command Message ```vehicle_control_cmd``` and send this to the CARLA simulator. It also reacts to some special case - Messages from Planning, such as emergency-braking or executing the unstuck-routine. @@ -50,7 +49,7 @@ This is done to prevent firing the emergency brake each time the main loop is re Comparison between normal braking and emergency braking: -![Braking Comparison](/doc/assets/acting/emergency_brake_stats_graph.png) +![Braking Comparison](/doc/assets/control/emergency_brake_stats_graph.png) _Please be aware, that this bug abuse might not work in newer updates!_ @@ -65,5 +64,5 @@ Inside the Unstuck Behavior we want drive backwards without steering, which is w It's also important to note, that we always receive a target_speed of -3 when in the unstuck routine. Also the __reverse attribute is True in this case. This is the only case we can drive backwards for now. When implementing an exhausting backwards driving approach this has to be kept in mind, because we DO NOT try to drive at the speed of -3 m/s. We only use the -3 as a keyword for driving backwards at full throttle for a specefic amount of time! -(see [velocity_controller.py](/code/acting/src/acting/velocity_controller.py) +(see [velocity_controller.py](/code/control/src/velocity_controller.py) and [maneuvers.py](/code/planning/src/behavior_agent/behaviours/maneuvers.py)) diff --git a/doc/control/velocity_controller.md b/doc/control/velocity_controller.md index b4715997..6315e2bb 100644 --- a/doc/control/velocity_controller.md +++ b/doc/control/velocity_controller.md @@ -2,13 +2,12 @@ **Summary:** This page provides an overview of the current status of the velocity_controller. -- [Overview of the Velocity Controller](#overview-of-the-velocity-controller) - - [General Introduction to Velocity Controller](#general-introduction-to-velocity-controller) - - [Current Implementation](#current-implementation) +- [General Introduction to Velocity Controller](#general-introduction-to-velocity-controller) +- [Current Implementation](#current-implementation) ## General Introduction to Velocity Controller -The [velocity_controller](../../code/acting/src/acting/velocity_controller.py) implements our way to make the CARLA-Vehicle drive at a ```target_velocity``` (published by Planning) by using a tuned PID-Controller to calculate a ```throttle``` and a ```brake``` for the CARLA-Vehicle-Command. +The [velocity_controller](../../code/control/src/velocity_controller.py) implements our way to make the CARLA-Vehicle drive at a ```target_velocity``` (published by Planning) by using a tuned PID-Controller to calculate a ```throttle``` and a ```brake``` for the CARLA-Vehicle-Command. For more information about PID-Controllers and how they work, follow [this link](https://en.wikipedia.org/wiki/Proportional%E2%80%93integral%E2%80%93derivative_controller). **IMPORTANT:** The CARLA ```vehicle_control_cmd``` only allows you to use a ```throttle``` and a ```brake``` value, both with an allowed range from 0-1, to control the driven speed. @@ -17,16 +16,16 @@ For more information about PID-Controllers and how they work, follow [this link] Currently, we use a tuned PID-Controller which was tuned for the speed of 14 m/s (around 50 km/h), as this is the most commonly driven velocity in this simulation: -![MISSING: PID-TUNING-IMAGE](../assets/acting/VelContr_PID_StepResponse.png) +![MISSING: PID-TUNING-IMAGE](../assets/control/VelContr_PID_StepResponse.png) Be aware, that the CARLA-Vehicle shifts gears automatically, resulting in the bumps you see! As PID-Controllers are linear by nature, the velocity-system is therefore linearized around 50 km/h, meaning the further you deviate from 50 km/h the worse the controller's performance gets: -![MISSING: PID-LINEARIZATION-IMAGE](../assets/acting/VelContr_PID_differentVelocities.png) +![MISSING: PID-LINEARIZATION-IMAGE](../assets/control/VelContr_PID_differentVelocities.png) As the Velocity Controller also has to handle braking, we currently use ```throttle```-optimized PID-Controller to calculate ```brake``` aswell (Since adding another Controller, like a P-Controller, did not work nearly as well!): -![MISSING: PID-BRAKING-IMAGE](../assets/acting/VelContr_PID_BrakingWithThrottlePID.png) +![MISSING: PID-BRAKING-IMAGE](../assets/control/VelContr_PID_BrakingWithThrottlePID.png) Currently, there is no general backwards-driving implemented here, as this was not needed (other than the [Unstuck Routine](/doc/planning/Behavior_detailed.md)). From 5760c6d7bb16fa2dcc0ec27a7d7b3f0228699b52 Mon Sep 17 00:00:00 2001 From: vinzenzm Date: Sat, 16 Nov 2024 23:49:22 +0100 Subject: [PATCH 46/61] Minor documentation improvements on acting and control --- doc/acting/README.md | 6 +++--- doc/acting/passthrough.md | 10 ++++++++-- doc/control/architecture_documentation.md | 2 +- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/doc/acting/README.md b/doc/acting/README.md index f2046e78..b081c665 100644 --- a/doc/acting/README.md +++ b/doc/acting/README.md @@ -2,7 +2,7 @@ This folder contains the documentation of the acting component. -1. [Architecture](./architecture_documentation.md) -2. [Main frame publisher](./main_frame_publisher.md) -3. [Passthrough](./passthrough.md) +1. [Overview and Architecture](./architecture_documentation.md) +2. [Passthrough](./passthrough.md) +3. [Main frame publisher](./main_frame_publisher.md) 4. [How to test/tune the acting component](./acting_testing.md) \ No newline at end of file diff --git a/doc/acting/passthrough.md b/doc/acting/passthrough.md index d4e42d4d..7c3e7d27 100644 --- a/doc/acting/passthrough.md +++ b/doc/acting/passthrough.md @@ -7,10 +7,16 @@ **Summary:** This page is ought to provide an overview of the passthrough node and reason why it exists -## Overview: +- [Overview](#overview) +- [Reasoning](#reasoning) + +## Overview The passthrough node subscribes to topics on a global scale and republishes them into the "paf/acting" namespace. The control package subscribes to these re-emitted topics. -## Reasoning: +> [!NOTE] +> See [acting architecture](./architecture_documentation.md) for further information. + +## Reasoning Before the control package was outsourced and became its own package it resided within the acting package. Therefor many global dependencies existed in the control package. As the goal of the outsourcing was to eliminate global dependencies in control theory the passthrough node was created as a first stepping diff --git a/doc/control/architecture_documentation.md b/doc/control/architecture_documentation.md index 56725431..9dd55d15 100644 --- a/doc/control/architecture_documentation.md +++ b/doc/control/architecture_documentation.md @@ -52,7 +52,7 @@ which starts the simulation. ### Velocity controllers > [!TIP] -> Follow this link for the ([Documentation](./velocity_controller.md)) on velocity component. +> Follow this link for the [Documentation](./velocity_controller.md) on velocity component. #### velocity_controller.py From 4fb8afbea53b32abaca81659f1ada27bba617a3c Mon Sep 17 00:00:00 2001 From: vinzenzm Date: Sun, 17 Nov 2024 23:36:03 +0100 Subject: [PATCH 47/61] Made the linter happy with newlines and trailing spaces --- doc/acting/README.md | 2 +- doc/acting/architecture_documentation.md | 10 +++++----- doc/acting/passthrough.md | 4 +++- doc/control/README.md | 2 +- doc/control/architecture_documentation.md | 17 ++++++++++------- 5 files changed, 20 insertions(+), 15 deletions(-) diff --git a/doc/acting/README.md b/doc/acting/README.md index b081c665..e9845154 100644 --- a/doc/acting/README.md +++ b/doc/acting/README.md @@ -5,4 +5,4 @@ This folder contains the documentation of the acting component. 1. [Overview and Architecture](./architecture_documentation.md) 2. [Passthrough](./passthrough.md) 3. [Main frame publisher](./main_frame_publisher.md) -4. [How to test/tune the acting component](./acting_testing.md) \ No newline at end of file +4. [How to test/tune the acting component](./acting_testing.md) diff --git a/doc/acting/architecture_documentation.md b/doc/acting/architecture_documentation.md index f4699186..4bb6f520 100644 --- a/doc/acting/architecture_documentation.md +++ b/doc/acting/architecture_documentation.md @@ -14,18 +14,19 @@ navigate on a local basis. This information is then processed in the [control_co ![MISSING: Acting-ARCHITECTURE](./../assets/acting/acting_architecture.png) -> [!NOTE] +> [!NOTE] > [Click here to go to control architecture](./../control/architecture_documentation.md) ## Components of acting ### passthrough.py -> [!TIP] +> [!TIP] > For documentation on passthrough component see: [passthrough](./passthrough.md) ### main_frame_publisher.py -> [!TIP] + +> [!TIP] > Follow this link for [Documentation](./main_frame_publisher.md) on this Node. - Inputs: @@ -41,7 +42,6 @@ navigate on a local basis. This information is then processed in the [control_co - rot_quat = rot as quaternion - **transform** = position x/y/z, rot_quat, Timestamp(now), “global”, “hero” - ### helper_functions.py - **vectors_to_angle_abs(x1: float, y1: float, x2: float, y2: float) -> float**:\ @@ -73,4 +73,4 @@ Interpolate linearly between start and end, with a minimal distance of interval_ - **_clean_route_duplicates(route: List[Tuple[float, float]], min_dist: float) -> List[Tuple[float, float]]**:\ Remove duplicates in the given List of tuples, if the distance between them is less than min_dist. - **interpolate_route(orig_route: List[Tuple[float, float]], interval_m=0.5)**:\ -Interpolate the given route with points inbetween,holding the specified distance interval threshold. \ No newline at end of file +Interpolate the given route with points inbetween,holding the specified distance interval threshold. diff --git a/doc/acting/passthrough.md b/doc/acting/passthrough.md index 7c3e7d27..eabd32b1 100644 --- a/doc/acting/passthrough.md +++ b/doc/acting/passthrough.md @@ -11,13 +11,15 @@ reason why it exists - [Reasoning](#reasoning) ## Overview + The passthrough node subscribes to topics on a global scale and republishes them into the "paf/acting" namespace. The control package subscribes to these re-emitted topics. > [!NOTE] > See [acting architecture](./architecture_documentation.md) for further information. ## Reasoning + Before the control package was outsourced and became its own package it resided within the acting package. Therefor many global dependencies existed in the control package. As the goal of the outsourcing was to eliminate global dependencies in control theory the passthrough node was created as a first stepping -stone towards independence. \ No newline at end of file +stone towards independence. diff --git a/doc/control/README.md b/doc/control/README.md index a51234b3..211d7149 100644 --- a/doc/control/README.md +++ b/doc/control/README.md @@ -5,4 +5,4 @@ This folder contains the documentation of the control component. 1. [Overview and Architecture](./architecture_documentation.md) 2. [Overview of the Velocity Controller](./velocity_controller.md) 3. [Overview of the Steering Controllers](./steering_controllers.md) -4. [Overview of the Vehicle Controller Component](./vehicle_controller.md) \ No newline at end of file +4. [Overview of the Vehicle Controller Component](./vehicle_controller.md) diff --git a/doc/control/architecture_documentation.md b/doc/control/architecture_documentation.md index 9dd55d15..89c44042 100644 --- a/doc/control/architecture_documentation.md +++ b/doc/control/architecture_documentation.md @@ -1,6 +1,6 @@ # Control: Overview and Architecture -**Summary**: +**Summary**: The control component applies control theory based on a local trajectory provided by the [acting component](./../acting/README.md). It uses knowledge of the current state of the vehicle in order to send [CarlaEgoVehicleControl](https://carla.readthedocs.io/en/0.9.8/ros_msgs/#CarlaEgoVehicleControlmsg) commands to the Simulator. This component also sends the [/carla/hero/status](https://leaderboard.carla.org/get_started/) command, @@ -19,16 +19,17 @@ which starts the simulation. ![MISSING: Control-ARCHITECTURE](./../assets/control/control_architecture.png) -> [!NOTE] +> [!NOTE] > [Click here to go to acting architecture](./../acting/architecture_documentation.md) ## Summary of Control Components -### Steering controllers -> [!TIP] +### Steering controllers + +> [!TIP] > Follow this link for the [Documentation](./steering_controllers.md) on steering controllers. -#### pure_pursuit_controller.py +#### pure_pursuit_controller.py - Inputs: - **trajectory**: Path @@ -50,7 +51,8 @@ which starts the simulation. - **stanley_steer**: Float32 - **stanley_debug**: StanleyDebug -### Velocity controllers +### Velocity controllers + > [!TIP] > Follow this link for the [Documentation](./velocity_controller.md) on velocity component. @@ -64,6 +66,7 @@ which starts the simulation. - **brake**: Float32 ### vehicle_controller.py + > [!TIP] > Follow this link for [Documentation](./vehicle_controller.md) on vehicle controller. @@ -78,4 +81,4 @@ which starts the simulation. - Outputs: - **vehicle_control_cmd**: [CarlaEgoVehicleControl](https://carla.readthedocs.io/en/0.9.8/ros_msgs/#CarlaEgoVehicleControlmsg) - **status**: Bool - - **emergency**: Bool \ No newline at end of file + - **emergency**: Bool From 7ecd33e4d1f19a77d581331292543a3183b0c582 Mon Sep 17 00:00:00 2001 From: Ralf Date: Mon, 18 Nov 2024 17:08:25 +0100 Subject: [PATCH 48/61] update radar node --- code/perception/src/radar_node.py | 61 +++++-------------------------- 1 file changed, 10 insertions(+), 51 deletions(-) diff --git a/code/perception/src/radar_node.py b/code/perception/src/radar_node.py index bd8f351f..b1a7d603 100755 --- a/code/perception/src/radar_node.py +++ b/code/perception/src/radar_node.py @@ -30,53 +30,29 @@ def callback(self, data): :param data: a PointCloud2 """ - # coordinates = ros_numpy.point_cloud2.pointcloud2_to_array(data) - - # Center - - # reconstruct_bit_mask_center = lidar_filter_utility.bounding_box( - # coordinates, - # max_x=np.inf, - # min_x=0.0, - # min_z=-1.6, - # ) - # reconstruct_coordinates_center = coordinates[reconstruct_bit_mask_center] - # reconstruct_coordinates_xyz_center = np.array( - # lidar_filter_utility.remove_field_name( - # reconstruct_coordinates_center, "intensity" - # ).tolist() - # ) - # dist_array_center = self.reconstruct_img_from_lidar( - # reconstruct_coordinates_xyz_center, focus="Center" - # ) - # dist_array_center_msg = self.bridge.cv2_to_imgmsg( - # dist_array_center, encoding="passthrough" - # ) - # dist_array_center_msg.header = data.header - # self.dist_array_center_publisher.publish(dist_array_center_msg) coordinates = ros_numpy.point_cloud2.pointcloud2_to_array(data) - # x_values = coordinates['x'] # rospy.loginfo("Erste 5 x Werte: {x_values[:5]}") # depth_values = coordinates['depth'] # rospy.loginfo("Erste 5 Depth Werte: {depth_values[:5]}") - dtype_info = "\n".join([f"Feld '{name}': {coordinates.dtype[name]}" for name in coordinates.dtype.names]) - + # dtype_info = "\n".join([f"Feld '{name}': {coordinates.dtype[name]}" for name in coordinates.dtype.names]) # rospy.loginfo("DatentypenNeu: " + dtype_info) # funktioniert - # rospy.loginfo("DatentypenAlt: " + coordinates.dtype) - - + #msg = np.min(coordinates['Velocity']) + # rospy.loginfo("DatentypenMsg: " + str(msg.dtype)) + # rospy.loginfo("WertMsg: " + str(msg)) - msg = np.min[coordinates['Range']] + #self.dist_array_radar_publisher.publish(msg) - dtype_msginfo = ["{type(msg).__name__}"] - rospy.loginfo("DatentypenMsg: " + dtype_msginfo) + for coordinate in coordinates: - self.dist_array_radar_publisher.publish(msg) + if coordinate['y'] == 0: + if coordinate['x'] <= 15: + msg = coordinate['Velocity']*3.6 + self.dist_array_radar_publisher.publish(msg) def listener(self): """ @@ -86,23 +62,6 @@ def listener(self): rospy.init_node("lidar_distance") self.bridge = CvBridge() - self.pub_pointcloud = rospy.Publisher( - rospy.get_param( - "~point_cloud_topic", - "/carla/hero/" + rospy.get_namespace() + "_filtered", - ), - PointCloud2, - queue_size=10, - ) - - # publisher for dist_array - - # self.dist_array_center_publisher = rospy.Publisher( - # rospy.get_param("~image_distance_topic", "/paf/hero/Center/dist_array"), - # ImageMsg, - # queue_size=10, - # ) - # publisher for radar dist_array self.dist_array_radar_publisher = rospy.Publisher( rospy.get_param("~image_distance_topic", "/paf/hero/Radar/array"), From c76df157312d7bfea06e7e0586a8dea456c20aa6 Mon Sep 17 00:00:00 2001 From: ll7 <32880741+ll7@users.noreply.github.com> Date: Tue, 19 Nov 2024 11:32:42 +0100 Subject: [PATCH 49/61] Update the sprint review presentation guideline Fixes #452 --- .../paf24/sprint_review_meeting_guidelines.md | 3 +- doc/development/sprint_review_presentation.md | 82 +++++++------------ 2 files changed, 30 insertions(+), 55 deletions(-) diff --git a/doc/dev_talks/paf24/sprint_review_meeting_guidelines.md b/doc/dev_talks/paf24/sprint_review_meeting_guidelines.md index 0c41eeef..c5a2e19f 100644 --- a/doc/dev_talks/paf24/sprint_review_meeting_guidelines.md +++ b/doc/dev_talks/paf24/sprint_review_meeting_guidelines.md @@ -43,7 +43,8 @@ - Example: A team of three has a total of 15 minutes and may allocate time as they see fit. - A unified grade will be given unless individual assessment is warranted. - Timeboxing will be strictly enforced: only content shared within the allotted time will be evaluated. Presentations will be stopped at the time limit. -- TODO The sprint review presentation guideline will be updated. +- The sprint review presentation guideline will be updated. in [#452](https://github.com/una-auxme/paf/issues/452). + - [sprint_review_presentation.md](../../development/sprint_review_presentation.md) will be updated accordingly. ## 3. Sprint Review Schedule diff --git a/doc/development/sprint_review_presentation.md b/doc/development/sprint_review_presentation.md index 0452d84e..2e2e6703 100644 --- a/doc/development/sprint_review_presentation.md +++ b/doc/development/sprint_review_presentation.md @@ -1,76 +1,50 @@ # Sprint Review Presentation -**Summary:** Guidelines for creating effective presentations for Sprint Reviews in the PAF project. +**Summary:** Guidelines for creating effective presentations for the Sprint Reviews in the PAF project. -- [1. General Sprint Progress Overview Presentation](#1-general-sprint-progress-overview-presentation) -- [2. Individual Pull Request (PR) Presentations](#2-individual-pull-request-pr-presentations) -- [3. Presentation Style](#3-presentation-style) +- [1. Group Presentations](#1-group-presentations) +- [2. Presentation Style](#2-presentation-style) Creating a good presentation for a **Sprint Review** in PAF is important for communicating the team's achievements, identifying challenges, and planning for future work. -To present the sprint progress effectively, especially when dealing with complex software projects, it can be beneficial to split the presentations into two distinct parts: +## 1. Group Presentations -1. **General Sprint Progress Overview**: This focuses on the big-picture updates, team-wide accomplishments, challenges, and next steps. -2. **Individual Pull Request (PR) Presentations**: These dive into the details of specific features or changes made during the sprint. +These technical presentations meant to present project progress from the sprint. +Not every PR has to be presented, but **each students contribution should be presented**. -## 1. General Sprint Progress Overview Presentation +**Structure of Presentation**: -This presentation is designed for a broader audience and focuses on the overall progress made during the sprint. It highlights major milestones, project status, and challenges, without diving into technical implementation details. -There should be one general overview presentation per sprint, typically delivered a new student who has not presented the general overview before. - -**Structure of the General Overview**: - -- **Title Slide**: Sprint number, project name, team, and sprint dates. -- **Agenda**: Outline the structure of the presentation. - - *See below* -- **Sprint Goals**: Briefly describe the objectives of the sprint and how they fit into the overall project roadmap. -- **Completed Work**: Provide an overview of features that were completed. This section should focus on **overall vehicle improvement** rather than technical details. - - Optionally include a **demo** of key features. - - **Before-and-after visuals** of new functionality if applicable. -- **In-progress Work**: Mention features or tasks that were started but not completed, along with explanations of why they weren’t finished. -- **Challenges & Blockers**: Present the key blockers and how they were addressed or escalated. If some remain unresolved, suggest plans for mitigation. -- **Sprint Metrics**: Include relevant metrics: - - Any improvements in testing or driving score. -- **Next Steps**: Outline the focus areas for the next sprint, upcoming deadlines, and potential risks. - -**Duration**: 5-20 minutes, depending on the complexity of the sprint. - -## 2. Individual Pull Request (PR) Presentations - -These are more focused, technical presentations meant to review individual pull requests (PRs) from the sprint. They are aimed at the development team and technical stakeholders, providing detailed insight into the code changes, implementation logic, and technical considerations of each PR. -Not every PR has to be presented, but **every student should be able to highlight their contributions**. - -**Structure of the PR Presentation**: - -- **Title Slide**: Pull request title, associated issue number(s), and contributor(s). +- **Title Slide**: Area of contribution, PR numbers, and contributor(s). - **Agenda**: - - *See below* -- **PR Overview**: Start with the problem or issue the PR addresses. - - Describe the goal of the changes (e.g., adding a feature, fixing a bug, refactoring code). -- **Key Accomplishments**: Go over the technical changes made in the PR. - - **Code snippets**: Highlight important parts of the code that were changed or added. - - **Design patterns or architectural choices**: Explain any significant technical decisions. -- **Technical Challenges and Solutions**: Discuss any technical difficulties encountered while implementing the PR. - - Mention how challenges were overcome and what alternatives were considered. -- **Code Review Outcomes**: Summarize any feedback from peer reviews. - - Highlight any requested changes and how they were addressed. - - Point out best practices followed or any areas for future improvement. -- **Testing and Validation**: Show how the changes were tested. + - Clearly outline what will be covered. +- **Overview**: + - Start by describing the problem or feature request being addressed. + - Explain the goal of the changes. +- **Key Accomplishments**: + - Summarize the technical changes made during the sprint. + - Highlight key features implemented or problems solved. + - Design Patterns/Architectural Choices: Explain significant technical decisions. +- **Technical Challenges and Solutions**: + - Discuss challenges encountered and how they were resolved. + - Outline alternative approaches considered, if any. +- **Code Review Outcomes**: + - Summarize feedback received during peer reviews. + - Highlight requested changes and how they were addressed. + - Mention best practices followed and areas for improvement. +- **Testing and Validation**: Explain how the changes were tested. - **Automated tests**: Unit, integration, or end-to-end tests that were added or updated. - **Manual tests**: If manual validation was done, explain the scenarios tested. -- **Demo (if applicable)**: Provide a quick live demo or walkthrough of the feature or bug fix that the PR addresses. -- **Next Steps**: If the PR impacts other work or needs further iterations, describe those next steps. +- **Demo**: Provide a quick live demo or walkthrough of the feature or bug fix that the PR addresses. +- **Next Steps**: If the changes impacts other work or needs further iterations, describe those next steps. -**Duration**: 5-10 minutes per Pull-Request. +**Duration**: **5 minutes** per person. -## 3. Presentation Style +## 2. Presentation Style - **Focus on outcomes**: Highlight the progress made and how it impacts the overall project goals. - **Use visuals and charts**: Use screenshots, graphs, and videos to illustrate progress. -- **Interactive**: Ask for feedback, highlight areas that require input or decisions. - **Keep it high-level**: Avoid too much technical jargon. - **Stay concise**: Respect everyone’s time and keep the presentation focused on what matters most. -- **Collaborate**: Collaborate with the team to ensure all aspects of the sprint are covered. - **Consistent Slide Design**: Use a consistent slide design (fonts, colors, layout) to improve readability. - Templates for AuxMe-Presentations: From 9a693ebc9dbdb7eaedf127717a72cbf85b7e0b3c Mon Sep 17 00:00:00 2001 From: ll7 Date: Tue, 19 Nov 2024 14:49:01 +0100 Subject: [PATCH 50/61] Update sprint review presentation guidelines for clarity and accuracy --- doc/dev_talks/paf24/sprint_review_meeting_guidelines.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/dev_talks/paf24/sprint_review_meeting_guidelines.md b/doc/dev_talks/paf24/sprint_review_meeting_guidelines.md index c5a2e19f..603190f1 100644 --- a/doc/dev_talks/paf24/sprint_review_meeting_guidelines.md +++ b/doc/dev_talks/paf24/sprint_review_meeting_guidelines.md @@ -43,8 +43,8 @@ - Example: A team of three has a total of 15 minutes and may allocate time as they see fit. - A unified grade will be given unless individual assessment is warranted. - Timeboxing will be strictly enforced: only content shared within the allotted time will be evaluated. Presentations will be stopped at the time limit. -- The sprint review presentation guideline will be updated. in [#452](https://github.com/una-auxme/paf/issues/452). - - [sprint_review_presentation.md](../../development/sprint_review_presentation.md) will be updated accordingly. +- The sprint review presentation guideline was updated in [#452](https://github.com/una-auxme/paf/issues/452). + - The [sprint_review_presentation.md](../../development/sprint_review_presentation.md) is updated. ## 3. Sprint Review Schedule From 0f53cbf316ff40ab67b1a4c18c388452d1781323 Mon Sep 17 00:00:00 2001 From: ll7 Date: Tue, 19 Nov 2024 14:51:40 +0100 Subject: [PATCH 51/61] Add autoware mini to the research section Fixes #389 --- doc/research/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/research/README.md b/doc/research/README.md index 1b2caa70..26cea173 100644 --- a/doc/research/README.md +++ b/doc/research/README.md @@ -52,3 +52,4 @@ In addition to the research of the previous years, the following resources can b - [Awesome 3D Object Detection for Autonomous Driving](https://github.com/PointsCoder/Awesome-3D-Object-Detection-for-Autonomous-Driving) - [Microsoft Autonomous Driving Cookbook](https://github.com/microsoft/AutonomousDrivingCookbook) - [End-to-End Autonomous Driving](https://github.com/OpenDriveLab/End-to-end-Autonomous-Driving) +- [UT-ADL/autoware_mini](https://github.com/UT-ADL/autoware_mini) From 08e9711afb0c2ddb4d5d4f41def316f3216f429b Mon Sep 17 00:00:00 2001 From: Ralf Date: Wed, 20 Nov 2024 16:54:16 +0100 Subject: [PATCH 52/61] Aleks and Ralf, implemented first distance detection with radar_node --- code/perception/src/radar_node.py | 72 ++++++++++++++++++------------- 1 file changed, 43 insertions(+), 29 deletions(-) diff --git a/code/perception/src/radar_node.py b/code/perception/src/radar_node.py index b1a7d603..1fa98f2e 100755 --- a/code/perception/src/radar_node.py +++ b/code/perception/src/radar_node.py @@ -4,14 +4,15 @@ import numpy as np import lidar_filter_utility from sensor_msgs.msg import PointCloud2 - +from sklearn.cluster import DBSCAN # from mpl_toolkits.mplot3d import Axes3D # from itertools import combinations from sensor_msgs.msg import Image as ImageMsg from cv_bridge import CvBridge - -from std_msgs.msg import Float32 - +import json +# from std_msgs.msg import Float32 +from std_msgs.msg import String +from rospy.numpy_msg import numpy_msg # from matplotlib.colors import LinearSegmentedColormap @@ -30,29 +31,10 @@ def callback(self, data): :param data: a PointCloud2 """ - - coordinates = ros_numpy.point_cloud2.pointcloud2_to_array(data) - # x_values = coordinates['x'] - # rospy.loginfo("Erste 5 x Werte: {x_values[:5]}") - - # depth_values = coordinates['depth'] - # rospy.loginfo("Erste 5 Depth Werte: {depth_values[:5]}") - - # dtype_info = "\n".join([f"Feld '{name}': {coordinates.dtype[name]}" for name in coordinates.dtype.names]) - # rospy.loginfo("DatentypenNeu: " + dtype_info) # funktioniert - - #msg = np.min(coordinates['Velocity']) - # rospy.loginfo("DatentypenMsg: " + str(msg.dtype)) - # rospy.loginfo("WertMsg: " + str(msg)) - - #self.dist_array_radar_publisher.publish(msg) - - for coordinate in coordinates: - - if coordinate['y'] == 0: - if coordinate['x'] <= 15: - msg = coordinate['Velocity']*3.6 - self.dist_array_radar_publisher.publish(msg) + + clustered_points = cluster_radar_data_from_pointcloud(data, 10) + clustered_points_json = json.dumps(clustered_points) + self.dist_array_radar_publisher.publish(clustered_points_json) def listener(self): """ @@ -64,9 +46,9 @@ def listener(self): # publisher for radar dist_array self.dist_array_radar_publisher = rospy.Publisher( - rospy.get_param("~image_distance_topic", "/paf/hero/Radar/array"), + rospy.get_param("~image_distance_topic", "/paf/hero/Radar/dist_array_unsegmented"), # PointCloud2, - Float32, + String, queue_size=10, ) @@ -79,6 +61,38 @@ def listener(self): rospy.spin() +def pointcloud2_to_array(pointcloud_msg): + cloud_array = ros_numpy.point_cloud2.pointcloud2_to_array(pointcloud_msg) + distances = np.sqrt( + cloud_array["x"] ** 2 + cloud_array["y"] ** 2 + cloud_array["z"] ** 2 + ) + return np.column_stack( + (cloud_array["x"], cloud_array["y"], cloud_array["z"], distances) + ) + + +def cluster_radar_data_from_pointcloud( + pointcloud_msg, max_distance, eps=1.0, min_samples=2 +): + + data = pointcloud2_to_array(pointcloud_msg) + + filtered_data = data[data[:, 3] < max_distance] + filtered_data = filtered_data[(filtered_data[:, 1] >= -1) & (filtered_data[:, 1] <= 1) & (filtered_data[:, 2] <= 1.3) & (filtered_data[:, 2] >= -0.7)] + + if len(filtered_data) == 0: + return {} + + coordinates = filtered_data[:, :2] + clustering = DBSCAN(eps=eps, min_samples=min_samples).fit(coordinates) + + labels = clustering.labels_ + clustered_points = {label: list(labels).count(label) for label in set(labels)} + clustered_points = {int(label): count for label, count in clustered_points.items()} + + return clustered_points + + if __name__ == "__main__": lidar_distance = RadarNode() lidar_distance.listener() From f2ae9e85c174c4505ef6362df841a2a03d339eab Mon Sep 17 00:00:00 2001 From: ll7 <32880741+ll7@users.noreply.github.com> Date: Thu, 21 Nov 2024 07:43:08 +0100 Subject: [PATCH 53/61] Refine sprint review presentation guidelines for clarity and conciseness --- doc/development/sprint_review_presentation.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/development/sprint_review_presentation.md b/doc/development/sprint_review_presentation.md index 2e2e6703..b875ff5c 100644 --- a/doc/development/sprint_review_presentation.md +++ b/doc/development/sprint_review_presentation.md @@ -9,7 +9,7 @@ Creating a good presentation for a **Sprint Review** in PAF is important for com ## 1. Group Presentations -These technical presentations meant to present project progress from the sprint. +These are technical presentations meant to present project progress from the sprint. Not every PR has to be presented, but **each students contribution should be presented**. **Structure of Presentation**: @@ -34,7 +34,8 @@ Not every PR has to be presented, but **each students contribution should be pre - **Testing and Validation**: Explain how the changes were tested. - **Automated tests**: Unit, integration, or end-to-end tests that were added or updated. - **Manual tests**: If manual validation was done, explain the scenarios tested. -- **Demo**: Provide a quick live demo or walkthrough of the feature or bug fix that the PR addresses. +- **Demo**: Provide a quick demo or walkthrough of the feature or bug fix that the PR addresses. + - Prepare screenshots or recordings. - **Next Steps**: If the changes impacts other work or needs further iterations, describe those next steps. **Duration**: **5 minutes** per person. From 9cb4c9e5287aebbb23ea213df5b9470ec42da63e Mon Sep 17 00:00:00 2001 From: vinzenzm <73160933+vinzenzm@users.noreply.github.com> Date: Thu, 21 Nov 2024 09:32:40 +0100 Subject: [PATCH 54/61] Renamed passthrough dataclass to TopicMapping in passthrough --- code/acting/src/acting/passthrough.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/code/acting/src/acting/passthrough.py b/code/acting/src/acting/passthrough.py index 253e108c..3d49d207 100755 --- a/code/acting/src/acting/passthrough.py +++ b/code/acting/src/acting/passthrough.py @@ -13,7 +13,7 @@ @dataclass -class passthrough: +class TopicMapping: pub_name: str sub_name: str topic_type: Type @@ -28,34 +28,34 @@ class Passthrough(CompatibleNode): role_name = "hero" # Legacy will change soon # Topics for velocity controller. - target_velocity = passthrough( + target_velocity = TopicMapping( pub_name="/paf/acting/target_velocity", sub_name=f"/paf/{role_name}/target_velocity", topic_type=Float32, ) # Topics for steering controllers - trajectory = passthrough( + trajectory = TopicMapping( pub_name="/paf/acting/trajectory", sub_name=f"/paf/{role_name}/trajectory", topic_type=Path, ) - position = passthrough( + position = TopicMapping( pub_name="/paf/acting/current_pos", sub_name=f"/paf/{role_name}/current_pos", topic_type=PoseStamped, ) - heading = passthrough( + heading = TopicMapping( pub_name="/paf/acting/current_heading", sub_name=f"/paf/{role_name}/current_heading", topic_type=Float32, ) - passthrough_topics = [target_velocity, trajectory, position, heading] + mapped_topics = [target_velocity, trajectory, position, heading] def __init__(self): self.publishers: Dict[str, Publisher] = {} self.subscribers: Dict[str, Subscriber] = {} - for topic in self.passthrough_topics: + for topic in self.mapped_topics: self.publishers[topic.pub_name] = self.new_publisher( topic.topic_type, topic.pub_name, qos_profile=1 ) From 0af4cc90c99b22e64cc1bcf269a01f085a02a3c6 Mon Sep 17 00:00:00 2001 From: Ralf Date: Thu, 21 Nov 2024 13:13:30 +0100 Subject: [PATCH 55/61] Add radar_node.md --- doc/perception/radar_node.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 doc/perception/radar_node.md diff --git a/doc/perception/radar_node.md b/doc/perception/radar_node.md new file mode 100644 index 00000000..26783bc2 --- /dev/null +++ b/doc/perception/radar_node.md @@ -0,0 +1,36 @@ +# Radar Node + +**Summary:** This page explains what the radar sensor does. + +- [Radar offsets](#radar-offsets) +- [Radar specification](#radar-specification) +- [Radar data output for each detected point](#radar-data-output-for-each-detected-point) +- [Todo](#todo) + +## Radar offsets + +- x: 2 +- y: 0 +- z: 0.7 + +## Radar specification + +- points per second: 1500 points generated by all lasers per second +- maximum range: 100 meters +- horizontal fov: 30 degrees +- vertical fov: 30 degrees + +## Radar data output for each detected point + +- x +- y +- z +- Range +- Velocity +- AzimuthAngle +- ElevationAngle + +## Todo + +- Discuss further processing of radar data +- Combine lidar, radar and camera data From 90cf9f31322e3da23e85ccff9160059574ae4727 Mon Sep 17 00:00:00 2001 From: Ludwig Holl Date: Sat, 23 Nov 2024 16:10:40 +0100 Subject: [PATCH 56/61] updated project management.md and issue templates --- .github/ISSUE_TEMPLATE/BUG.yml | 13 ------------- .github/ISSUE_TEMPLATE/FEATURE.yml | 12 ------------ .github/ISSUE_TEMPLATE/ISSUE.yml | 13 ------------- doc/development/project_management.md | 21 +++++++++++++++++++++ 4 files changed, 21 insertions(+), 38 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/BUG.yml b/.github/ISSUE_TEMPLATE/BUG.yml index aee5410c..afed0980 100644 --- a/.github/ISSUE_TEMPLATE/BUG.yml +++ b/.github/ISSUE_TEMPLATE/BUG.yml @@ -35,13 +35,6 @@ body: - The car detects traffic lights on Map1 correctly. - The issue no longer occurs in similar scenarios. - - type: input - id: effort_estimate - attributes: - label: Effort Estimate - description: Approximate effort required (e.g., hours). - placeholder: Enter effort estimate. - - type: textarea id: testability attributes: @@ -59,12 +52,6 @@ body: - type: markdown attributes: value: | - **Add Priority Label**: - - p1: Immediate attention - - p2: High priority - - p3: Standard priority - - p4: Low priority - **Add Group Label**: - perception: Related to sensor processing and scene understanding - planning: Related to path planning and decision making diff --git a/.github/ISSUE_TEMPLATE/FEATURE.yml b/.github/ISSUE_TEMPLATE/FEATURE.yml index 366bab21..3c906a58 100644 --- a/.github/ISSUE_TEMPLATE/FEATURE.yml +++ b/.github/ISSUE_TEMPLATE/FEATURE.yml @@ -19,13 +19,6 @@ body: - Detects 90% of traffic lights. - Correctly identifies 90% of traffic light states. - - type: input - id: effort_estimate - attributes: - label: Effort Estimate - description: Approximate effort required (e.g., hours). - placeholder: Enter effort estimate. - - type: textarea id: testability attributes: @@ -43,11 +36,6 @@ body: - type: markdown attributes: value: | - **Add Priority Label**: - - p1: Immediate attention - - p2: High priority - - p3: Standard priority - - p4: Low priority **Add Group Label**: - perception: Related to sensor processing and scene understanding diff --git a/.github/ISSUE_TEMPLATE/ISSUE.yml b/.github/ISSUE_TEMPLATE/ISSUE.yml index 6ad88fbf..355cb64f 100644 --- a/.github/ISSUE_TEMPLATE/ISSUE.yml +++ b/.github/ISSUE_TEMPLATE/ISSUE.yml @@ -25,13 +25,6 @@ body: - Code review passed - All tests passing - - type: input - id: effort_estimate - attributes: - label: Effort Estimate - description: Approximate effort required (e.g., hours). - placeholder: Enter effort estimate. - - type: textarea id: testability attributes: @@ -58,12 +51,6 @@ body: - question: Further information is requested - wontfix: This will not be worked on - **Add Priority Label**: - - p1: Immediate attention - - p2: High priority - - p3: Standard priority - - p4: Low priority - **Add Group Label**: - perception: Related to sensor processing and scene understanding - planning: Related to path planning and decision making diff --git a/doc/development/project_management.md b/doc/development/project_management.md index 29a1a0f0..cb4d590e 100644 --- a/doc/development/project_management.md +++ b/doc/development/project_management.md @@ -13,6 +13,27 @@ Issues can be added via the [issues overview](https://github.com/una-auxme/paf/i By clicking "New issue" in the overview you have different templates to create the issue. +After creating the issue it has to be added to the project board. The project board is used to keep track of the +progress of the issue. The project board can be found [here](https://github.com/orgs/una-auxme/projects/3). + +For tracking time and complexity of the issue we will use the predefined `Priority` and `Size` states of the PAF Project +Backlog Board. + +Priority has following states: +- `Urgent`: Critical bug causing system crash, needs immediate fix. +- `High`: Major feature request or significant bug affecting many users. +- `Medium`: Minor feature request or bug with a workaround. +- `Low`: Cosmetic changes or minor improvements. + +Size has following states: +- `Tiny`: Small typo fix or minor code refactor. Estimated time: 30 minutes. +- `Small`: Simple bug fix or small feature addition. Estimated time: 1-2 hours. +- `Medium`: Moderate feature addition or multiple bug fixes. Estimated time: 1-2 days. +- `Large`: Major feature implementation or significant refactor. Estimated time: 1-2 weeks. +- `X-Large`: Large-scale feature or complete module overhaul. Estimated time: 2-4 weeks. Especially `EPIC` issues should + be tagged with this size. + + ## 2. Create a Pull Request To create a pull request, go to the [branches overview](https://github.com/una-auxme/paf/branches) and select ``New Pull Request`` for the branch you want to create a PR for. From 9c40f314a3aeb82a7cf825f631158fab48d2ad05 Mon Sep 17 00:00:00 2001 From: Ludwig Holl Date: Sat, 23 Nov 2024 16:12:58 +0100 Subject: [PATCH 57/61] added size and prio information to the issue templates --- .github/ISSUE_TEMPLATE/BUG.yml | 15 +++++++++++++++ .github/ISSUE_TEMPLATE/FEATURE.yml | 15 +++++++++++++++ .github/ISSUE_TEMPLATE/ISSUE.yml | 15 +++++++++++++++ 3 files changed, 45 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/BUG.yml b/.github/ISSUE_TEMPLATE/BUG.yml index afed0980..0bdbe38e 100644 --- a/.github/ISSUE_TEMPLATE/BUG.yml +++ b/.github/ISSUE_TEMPLATE/BUG.yml @@ -59,3 +59,18 @@ body: - system: Related to the general behavior of the system - research: Related to research and experimentation - infrastructure: Related to system infrastructure and setup + + **Add Labels on the Project Board**: + **Priority:** + - `Urgent`: Critical bug causing system crash, needs immediate fix. + - `High`: Major feature request or significant bug affecting many users. + - `Medium`: Minor feature request or bug with a workaround. + - `Low`: Cosmetic changes or minor improvements. + + **Size:** + - `Tiny`: Small typo fix or minor code refactor. Estimated time: 30 minutes. + - `Small`: Simple bug fix or small feature addition. Estimated time: 1-2 hours. + - `Medium`: Moderate feature addition or multiple bug fixes. Estimated time: 1-2 days. + - `Large`: Major feature implementation or significant refactor. Estimated time: 1-2 weeks. + - `X-Large`: Large-scale feature or complete module overhaul. Estimated time: 2-4 weeks. Especially `EPIC` issues should + be tagged with this size. diff --git a/.github/ISSUE_TEMPLATE/FEATURE.yml b/.github/ISSUE_TEMPLATE/FEATURE.yml index 3c906a58..bdb42505 100644 --- a/.github/ISSUE_TEMPLATE/FEATURE.yml +++ b/.github/ISSUE_TEMPLATE/FEATURE.yml @@ -44,3 +44,18 @@ body: - system: Related to the general behavior of the system - research: Related to research and experimentation - infrastructure: Related to system infrastructure and setup + + **Add Labels on the Project Board**: + **Priority:** + - `Urgent`: Critical bug causing system crash, needs immediate fix. + - `High`: Major feature request or significant bug affecting many users. + - `Medium`: Minor feature request or bug with a workaround. + - `Low`: Cosmetic changes or minor improvements. + + **Size:** + - `Tiny`: Small typo fix or minor code refactor. Estimated time: 30 minutes. + - `Small`: Simple bug fix or small feature addition. Estimated time: 1-2 hours. + - `Medium`: Moderate feature addition or multiple bug fixes. Estimated time: 1-2 days. + - `Large`: Major feature implementation or significant refactor. Estimated time: 1-2 weeks. + - `X-Large`: Large-scale feature or complete module overhaul. Estimated time: 2-4 weeks. Especially `EPIC` issues should + be tagged with this size. diff --git a/.github/ISSUE_TEMPLATE/ISSUE.yml b/.github/ISSUE_TEMPLATE/ISSUE.yml index 355cb64f..e5cbc82c 100644 --- a/.github/ISSUE_TEMPLATE/ISSUE.yml +++ b/.github/ISSUE_TEMPLATE/ISSUE.yml @@ -58,3 +58,18 @@ body: - system: Related to the general behavior of the system - research: Related to research and experimentation - infrastructure: Related to system infrastructure and setup + + **Add Labels on the Project Board**: + **Priority:** + - `Urgent`: Critical bug causing system crash, needs immediate fix. + - `High`: Major feature request or significant bug affecting many users. + - `Medium`: Minor feature request or bug with a workaround. + - `Low`: Cosmetic changes or minor improvements. + + **Size:** + - `Tiny`: Small typo fix or minor code refactor. Estimated time: 30 minutes. + - `Small`: Simple bug fix or small feature addition. Estimated time: 1-2 hours. + - `Medium`: Moderate feature addition or multiple bug fixes. Estimated time: 1-2 days. + - `Large`: Major feature implementation or significant refactor. Estimated time: 1-2 weeks. + - `X-Large`: Large-scale feature or complete module overhaul. Estimated time: 2-4 weeks. Especially `EPIC` issues should + be tagged with this size. From bf594eee06f564485a0233ed2a6a7c178f5027e9 Mon Sep 17 00:00:00 2001 From: Ludwig Holl Date: Sat, 23 Nov 2024 16:18:58 +0100 Subject: [PATCH 58/61] fixed md linter --- doc/development/project_management.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/development/project_management.md b/doc/development/project_management.md index cb4d590e..ef5e45d7 100644 --- a/doc/development/project_management.md +++ b/doc/development/project_management.md @@ -13,19 +13,21 @@ Issues can be added via the [issues overview](https://github.com/una-auxme/paf/i By clicking "New issue" in the overview you have different templates to create the issue. -After creating the issue it has to be added to the project board. The project board is used to keep track of the +After creating the issue it has to be added to the project board. The project board is used to keep track of the progress of the issue. The project board can be found [here](https://github.com/orgs/una-auxme/projects/3). For tracking time and complexity of the issue we will use the predefined `Priority` and `Size` states of the PAF Project Backlog Board. Priority has following states: + - `Urgent`: Critical bug causing system crash, needs immediate fix. - `High`: Major feature request or significant bug affecting many users. - `Medium`: Minor feature request or bug with a workaround. - `Low`: Cosmetic changes or minor improvements. Size has following states: + - `Tiny`: Small typo fix or minor code refactor. Estimated time: 30 minutes. - `Small`: Simple bug fix or small feature addition. Estimated time: 1-2 hours. - `Medium`: Moderate feature addition or multiple bug fixes. Estimated time: 1-2 days. @@ -33,7 +35,6 @@ Size has following states: - `X-Large`: Large-scale feature or complete module overhaul. Estimated time: 2-4 weeks. Especially `EPIC` issues should be tagged with this size. - ## 2. Create a Pull Request To create a pull request, go to the [branches overview](https://github.com/una-auxme/paf/branches) and select ``New Pull Request`` for the branch you want to create a PR for. From 4ca5de6d8dfe5792774bf93a9844426e71497c7a Mon Sep 17 00:00:00 2001 From: vinzenzm Date: Sun, 24 Nov 2024 14:41:57 +0100 Subject: [PATCH 59/61] Fixed incorrect transformation in MainFramePublisher The hero frame was rotated 180 degrees from its true orientation. The code publishing this hero frame was cleaned up, the bug fixed. --- code/acting/src/acting/MainFramePublisher.py | 41 ++++++++++---------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/code/acting/src/acting/MainFramePublisher.py b/code/acting/src/acting/MainFramePublisher.py index a34240e8..50fb47c7 100755 --- a/code/acting/src/acting/MainFramePublisher.py +++ b/code/acting/src/acting/MainFramePublisher.py @@ -1,6 +1,4 @@ #!/usr/bin/env python - -from math import pi, cos, sin import ros_compatibility as roscomp import rospy from geometry_msgs.msg import PoseStamped @@ -9,6 +7,8 @@ from scipy.spatial.transform import Rotation as R from std_msgs.msg import Float32 +import numpy as np + class MainFramePublisher(CompatibleNode): @@ -49,27 +49,28 @@ def loop(timer_event=None): if self.current_pos is None: # conversion only works if pos is known return - rot = -self.current_heading - pos = [0, 0, 0] - pos[0] = ( - cos(rot) * self.current_pos.pose.position.x - - sin(rot) * self.current_pos.pose.position.y - ) - pos[1] = ( - sin(rot) * self.current_pos.pose.position.x - + cos(rot) * self.current_pos.pose.position.y + + # The following converts the current_pos as well as the current_heading + # messages we receive into tf transforms. + + position = np.array( + [ + self.current_pos.pose.position.x, + self.current_pos.pose.position.y, + self.current_pos.pose.position.z, + ] ) - pos[2] = -self.current_pos.pose.position.z - rot_quat = R.from_euler( - "xyz", [0, 0, -self.current_heading + pi], degrees=False - ).as_quat() + rotation = R.from_euler("z", self.current_heading, degrees=False).as_quat() + + # The position and rotation are "the hero frame in global coordinates" + # Therefore we publish the child hero with respect to the parent global br.sendTransform( - pos, - rot_quat, - rospy.Time.now(), - "global", - "hero", + translation=position, + rotation=rotation, + time=rospy.Time.now(), + child="hero", + parent="global", ) self.new_timer(self.control_loop_rate, loop) From ae01b8de9792bdd5a4edc5e90096355e55d89e98 Mon Sep 17 00:00:00 2001 From: Ralf Bernitt Date: Sun, 24 Nov 2024 18:57:00 +0100 Subject: [PATCH 60/61] finish radar node --- code/perception/src/radar_node.py | 54 ++++++------------------------- 1 file changed, 10 insertions(+), 44 deletions(-) diff --git a/code/perception/src/radar_node.py b/code/perception/src/radar_node.py index 1fa98f2e..9b54bd18 100755 --- a/code/perception/src/radar_node.py +++ b/code/perception/src/radar_node.py @@ -4,15 +4,14 @@ import numpy as np import lidar_filter_utility from sensor_msgs.msg import PointCloud2 -from sklearn.cluster import DBSCAN + # from mpl_toolkits.mplot3d import Axes3D # from itertools import combinations from sensor_msgs.msg import Image as ImageMsg from cv_bridge import CvBridge -import json -# from std_msgs.msg import Float32 -from std_msgs.msg import String -from rospy.numpy_msg import numpy_msg + +from std_msgs.msg import Float32 + # from matplotlib.colors import LinearSegmentedColormap @@ -31,10 +30,10 @@ def callback(self, data): :param data: a PointCloud2 """ - - clustered_points = cluster_radar_data_from_pointcloud(data, 10) - clustered_points_json = json.dumps(clustered_points) - self.dist_array_radar_publisher.publish(clustered_points_json) + + coordinates = ros_numpy.point_cloud2.pointcloud2_to_array(data) + msg = np.min(coordinates["Velocity"]) + self.dist_array_radar_publisher.publish(msg) def listener(self): """ @@ -46,9 +45,8 @@ def listener(self): # publisher for radar dist_array self.dist_array_radar_publisher = rospy.Publisher( - rospy.get_param("~image_distance_topic", "/paf/hero/Radar/dist_array_unsegmented"), - # PointCloud2, - String, + rospy.get_param("~image_distance_topic", "/paf/hero/Radar/velocity"), + Float32, queue_size=10, ) @@ -61,38 +59,6 @@ def listener(self): rospy.spin() -def pointcloud2_to_array(pointcloud_msg): - cloud_array = ros_numpy.point_cloud2.pointcloud2_to_array(pointcloud_msg) - distances = np.sqrt( - cloud_array["x"] ** 2 + cloud_array["y"] ** 2 + cloud_array["z"] ** 2 - ) - return np.column_stack( - (cloud_array["x"], cloud_array["y"], cloud_array["z"], distances) - ) - - -def cluster_radar_data_from_pointcloud( - pointcloud_msg, max_distance, eps=1.0, min_samples=2 -): - - data = pointcloud2_to_array(pointcloud_msg) - - filtered_data = data[data[:, 3] < max_distance] - filtered_data = filtered_data[(filtered_data[:, 1] >= -1) & (filtered_data[:, 1] <= 1) & (filtered_data[:, 2] <= 1.3) & (filtered_data[:, 2] >= -0.7)] - - if len(filtered_data) == 0: - return {} - - coordinates = filtered_data[:, :2] - clustering = DBSCAN(eps=eps, min_samples=min_samples).fit(coordinates) - - labels = clustering.labels_ - clustered_points = {label: list(labels).count(label) for label in set(labels)} - clustered_points = {int(label): count for label, count in clustered_points.items()} - - return clustered_points - - if __name__ == "__main__": lidar_distance = RadarNode() lidar_distance.listener() From a8a585e3451169b9cf60365cf4b5a686916deef1 Mon Sep 17 00:00:00 2001 From: Ralf Bernitt Date: Sun, 24 Nov 2024 19:28:29 +0100 Subject: [PATCH 61/61] Bug fixes --- code/perception/src/radar_node.py | 32 +++++++++++-------------------- 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/code/perception/src/radar_node.py b/code/perception/src/radar_node.py index 9b54bd18..04a9d59b 100755 --- a/code/perception/src/radar_node.py +++ b/code/perception/src/radar_node.py @@ -2,33 +2,24 @@ import rospy import ros_numpy import numpy as np -import lidar_filter_utility from sensor_msgs.msg import PointCloud2 - -# from mpl_toolkits.mplot3d import Axes3D -# from itertools import combinations -from sensor_msgs.msg import Image as ImageMsg -from cv_bridge import CvBridge - from std_msgs.msg import Float32 -# from matplotlib.colors import LinearSegmentedColormap - class RadarNode: - """See doc/perception/lidar_distance_utility.md on - how to configute this node + """See doc/perception/radar_node.md on + how to configure this node """ def callback(self, data): - """Callback function, filters a PontCloud2 message - by restrictions defined in the launchfile. + """Process radar Point2Cloud data and publish minimum velocity. - Publishes a Depth image for the specified camera angle. - Each angle has do be delt with differently since the signs of the - coordinate system change with the view angle. + Extracts velocity information from radar data + and publishes the minimum velocity as a + Float32 message - :param data: a PointCloud2 + Args: + data: Point2Cloud message containing radar data with velocity field """ coordinates = ros_numpy.point_cloud2.pointcloud2_to_array(data) @@ -40,8 +31,7 @@ def listener(self): Initializes the node and it's publishers """ # run simultaneously. - rospy.init_node("lidar_distance") - self.bridge = CvBridge() + rospy.init_node("radar_node") # publisher for radar dist_array self.dist_array_radar_publisher = rospy.Publisher( @@ -60,5 +50,5 @@ def listener(self): if __name__ == "__main__": - lidar_distance = RadarNode() - lidar_distance.listener() + radar_node = RadarNode() + radar_node.listener()