From 78962be996a24595392da3769e268a9abc6ea727 Mon Sep 17 00:00:00 2001 From: Xi Yan Date: Tue, 4 Mar 2025 16:07:30 -0800 Subject: [PATCH] chore: refactor create_and_execute_turn and resume_turn (#1399) # What does this PR do? - Closes https://github.com/meta-llama/llama-stack/issues/1212 [//]: # (If resolving an issue, uncomment and update the line below) [//]: # (Closes #[issue-number]) ## Test Plan ``` LLAMA_STACK_BASE_URL=http://localhost:8321 pytest -v tests/integration/agents/test_agents.py --inference-model "meta-llama/Llama-3.3-70B-Instruct" ``` image ``` LLAMA_STACK_CONFIG=fireworks pytest -v tests/integration/agents/test_agents.py::test_rag_and_code_agent --inference-model "meta-llama/Llama-3.3-70B-Instruct" ``` [//]: # (## Documentation) --- .../agents/meta_reference/agent_instance.py | 218 +- .../recorded_responses/chat_completion.json | 2638 +++++++++++++++-- .../recorded_responses/chat_completion.pickle | Bin 684331 -> 620451 bytes .../recorded_responses/invoke_tool.json | 78 +- .../recorded_responses/invoke_tool.pickle | Bin 53903 -> 53549 bytes 5 files changed, 2447 insertions(+), 487 deletions(-) diff --git a/llama_stack/providers/inline/agents/meta_reference/agent_instance.py b/llama_stack/providers/inline/agents/meta_reference/agent_instance.py index 921beac27..f868bee2c 100644 --- a/llama_stack/providers/inline/agents/meta_reference/agent_instance.py +++ b/llama_stack/providers/inline/agents/meta_reference/agent_instance.py @@ -12,7 +12,7 @@ import secrets import string import uuid from datetime import datetime -from typing import Any, AsyncGenerator, Dict, List, Optional, Tuple +from typing import Any, AsyncGenerator, Dict, List, Optional, Tuple, Union from urllib.parse import urlparse import httpx @@ -31,7 +31,6 @@ from llama_stack.apis.agents import ( AgentTurnResponseStreamChunk, AgentTurnResponseTurnAwaitingInputPayload, AgentTurnResponseTurnCompletePayload, - AgentTurnResponseTurnStartPayload, AgentTurnResumeRequest, Attachment, Document, @@ -184,115 +183,49 @@ class ChatAgent(ShieldRunnerMixin): span.set_attribute("session_id", request.session_id) span.set_attribute("agent_id", self.agent_id) span.set_attribute("request", request.model_dump_json()) - assert request.stream is True, "Non-streaming not supported" - - session_info = await self.storage.get_session_info(request.session_id) - if session_info is None: - raise ValueError(f"Session {request.session_id} not found") - - turns = await self.storage.get_session_turns(request.session_id) - messages = await self.get_messages_from_turns(turns) - messages.extend(request.messages) - turn_id = str(uuid.uuid4()) span.set_attribute("turn_id", turn_id) - start_time = datetime.now().astimezone().isoformat() - yield AgentTurnResponseStreamChunk( - event=AgentTurnResponseEvent( - payload=AgentTurnResponseTurnStartPayload( - turn_id=turn_id, - ) - ) - ) - - steps = [] - output_message = None - async for chunk in self.run( - session_id=request.session_id, - turn_id=turn_id, - input_messages=messages, - sampling_params=self.agent_config.sampling_params, - stream=request.stream, - documents=request.documents, - toolgroups_for_turn=request.toolgroups, - ): - if isinstance(chunk, CompletionMessage): - logcat.info( - "agents", - f"returning result from the agent turn: {chunk}", - ) - output_message = chunk - continue - - assert isinstance(chunk, AgentTurnResponseStreamChunk), f"Unexpected type {type(chunk)}" - event = chunk.event - if event.payload.event_type == AgentTurnResponseEventType.step_complete.value: - steps.append(event.payload.step_details) - + async for chunk in self._run_turn(request, turn_id): yield chunk - assert output_message is not None - - turn = Turn( - turn_id=turn_id, - session_id=request.session_id, - input_messages=request.messages, - output_message=output_message, - started_at=start_time, - completed_at=datetime.now().astimezone().isoformat(), - steps=steps, - ) - await self.storage.add_turn_to_session(request.session_id, turn) - if output_message.tool_calls: - chunk = AgentTurnResponseStreamChunk( - event=AgentTurnResponseEvent( - payload=AgentTurnResponseTurnAwaitingInputPayload( - turn=turn, - ) - ) - ) - else: - chunk = AgentTurnResponseStreamChunk( - event=AgentTurnResponseEvent( - payload=AgentTurnResponseTurnCompletePayload( - turn=turn, - ) - ) - ) - - yield chunk - async def resume_turn(self, request: AgentTurnResumeRequest) -> AsyncGenerator: with tracing.span("resume_turn") as span: span.set_attribute("agent_id", self.agent_id) span.set_attribute("session_id", request.session_id) span.set_attribute("turn_id", request.turn_id) span.set_attribute("request", request.model_dump_json()) - assert request.stream is True, "Non-streaming not supported" + async for chunk in self._run_turn(request): + yield chunk - session_info = await self.storage.get_session_info(request.session_id) - if session_info is None: - raise ValueError(f"Session {request.session_id} not found") + async def _run_turn( + self, + request: Union[AgentTurnCreateRequest, AgentTurnResumeRequest], + turn_id: Optional[str] = None, + ) -> AsyncGenerator: + assert request.stream is True, "Non-streaming not supported" - turns = await self.storage.get_session_turns(request.session_id) - if len(turns) == 0: - raise ValueError("No turns found for session") + is_resume = isinstance(request, AgentTurnResumeRequest) + session_info = await self.storage.get_session_info(request.session_id) + if session_info is None: + raise ValueError(f"Session {request.session_id} not found") - messages = await self.get_messages_from_turns(turns) + turns = await self.storage.get_session_turns(request.session_id) + if is_resume and len(turns) == 0: + raise ValueError("No turns found for session") + + steps = [] + messages = await self.get_messages_from_turns(turns) + if is_resume: messages.extend(request.tool_responses) - last_turn = turns[-1] last_turn_messages = self.turn_to_messages(last_turn) last_turn_messages = [ x for x in last_turn_messages if isinstance(x, UserMessage) or isinstance(x, ToolResponseMessage) ] - - # TODO: figure out whether we should add the tool responses to the last turn messages last_turn_messages.extend(request.tool_responses) - # get the steps from the turn id - steps = [] - steps = turns[-1].steps + # get steps from the turn + steps = last_turn.steps # mark tool execution step as complete # if there's no tool execution in progress step (due to storage, or tool call parsing on client), @@ -326,62 +259,67 @@ class ChatAgent(ShieldRunnerMixin): ) ) ) + input_messages = last_turn_messages - output_message = None - async for chunk in self.run( - session_id=request.session_id, - turn_id=request.turn_id, - input_messages=messages, - sampling_params=self.agent_config.sampling_params, - stream=request.stream, - ): - if isinstance(chunk, CompletionMessage): - output_message = chunk - continue + turn_id = request.turn_id + start_time = last_turn.started_at + else: + messages.extend(request.messages) + start_time = datetime.now().astimezone().isoformat() + input_messages = request.messages - assert isinstance(chunk, AgentTurnResponseStreamChunk), f"Unexpected type {type(chunk)}" - event = chunk.event - if event.payload.event_type == AgentTurnResponseEventType.step_complete.value: - steps.append(event.payload.step_details) + output_message = None + async for chunk in self.run( + session_id=request.session_id, + turn_id=turn_id, + input_messages=messages, + sampling_params=self.agent_config.sampling_params, + stream=request.stream, + documents=request.documents if not is_resume else None, + toolgroups_for_turn=request.toolgroups if not is_resume else None, + ): + if isinstance(chunk, CompletionMessage): + output_message = chunk + continue - yield chunk - - assert output_message is not None - - last_turn_start_time = datetime.now().astimezone().isoformat() - if len(turns) > 0: - last_turn_start_time = turns[-1].started_at - - turn = Turn( - turn_id=request.turn_id, - session_id=request.session_id, - input_messages=last_turn_messages, - output_message=output_message, - started_at=last_turn_start_time, - completed_at=datetime.now().astimezone().isoformat(), - steps=steps, - ) - await self.storage.add_turn_to_session(request.session_id, turn) - - if output_message.tool_calls: - chunk = AgentTurnResponseStreamChunk( - event=AgentTurnResponseEvent( - payload=AgentTurnResponseTurnAwaitingInputPayload( - turn=turn, - ) - ) - ) - else: - chunk = AgentTurnResponseStreamChunk( - event=AgentTurnResponseEvent( - payload=AgentTurnResponseTurnCompletePayload( - turn=turn, - ) - ) - ) + assert isinstance(chunk, AgentTurnResponseStreamChunk), f"Unexpected type {type(chunk)}" + event = chunk.event + if event.payload.event_type == AgentTurnResponseEventType.step_complete.value: + steps.append(event.payload.step_details) yield chunk + assert output_message is not None + + turn = Turn( + turn_id=turn_id, + session_id=request.session_id, + input_messages=input_messages, + output_message=output_message, + started_at=start_time, + completed_at=datetime.now().astimezone().isoformat(), + steps=steps, + ) + await self.storage.add_turn_to_session(request.session_id, turn) + if output_message.tool_calls: + chunk = AgentTurnResponseStreamChunk( + event=AgentTurnResponseEvent( + payload=AgentTurnResponseTurnAwaitingInputPayload( + turn=turn, + ) + ) + ) + else: + chunk = AgentTurnResponseStreamChunk( + event=AgentTurnResponseEvent( + payload=AgentTurnResponseTurnCompletePayload( + turn=turn, + ) + ) + ) + + yield chunk + async def run( self, session_id: str, diff --git a/tests/integration/fixtures/recorded_responses/chat_completion.json b/tests/integration/fixtures/recorded_responses/chat_completion.json index 021b6c936..4b0d9b1c1 100644 --- a/tests/integration/fixtures/recorded_responses/chat_completion.json +++ b/tests/integration/fixtures/recorded_responses/chat_completion.json @@ -14075,7 +14075,7 @@ { "event": { "delta": { - "text": " provided function definitions are", + "text": " provided function definitions are not suitable for", "type": "text" }, "event_type": { @@ -14090,7 +14090,7 @@ { "event": { "delta": { - "text": " not suitable", + "text": " this task", "type": "text" }, "event_type": { @@ -14105,7 +14105,7 @@ { "event": { "delta": { - "text": " for this task. Please re", + "text": ". Please re", "type": "text" }, "event_type": { @@ -14203,7 +14203,7 @@ { "event": { "delta": { - "text": "get_boiling_point(liquid_name='polyjuice', celcius", + "text": "get_boiling_point(liquid_name='polyjuice", "type": "text" }, "event_type": { @@ -14218,7 +14218,7 @@ { "event": { "delta": { - "text": "=True)]", + "text": "', celcius=True)]", "type": "text" }, "event_type": { @@ -14242,7 +14242,7 @@ "celcius": true, "liquid_name": "polyjuice" }, - "call_id": "3cb5e131-c553-494b-ae31-7d3836fbb4d8", + "call_id": "1fc2d874-894e-4857-ae2b-7aacc75c330e", "tool_name": "get_boiling_point" }, "type": "tool_call" @@ -14315,7 +14315,7 @@ { "event": { "delta": { - "text": " function call returned an", + "text": " function call returned an error", "type": "text" }, "event_type": { @@ -14330,7 +14330,7 @@ { "event": { "delta": { - "text": " error since \"", + "text": " since \"polyjuice\" is", "type": "text" }, "event_type": { @@ -14345,7 +14345,7 @@ { "event": { "delta": { - "text": "polyjuice\" is not a real liquid. Polyju", + "text": " not a real liquid. Polyjuice is a fictional substance", "type": "text" }, "event_type": { @@ -14360,7 +14360,7 @@ { "event": { "delta": { - "text": "ice is a fictional substance from the", + "text": " from the Harry Potter series. The boiling", "type": "text" }, "event_type": { @@ -14375,7 +14375,7 @@ { "event": { "delta": { - "text": " Harry Potter series. The boiling", + "text": " point of a liquid is a physical", "type": "text" }, "event_type": { @@ -14390,7 +14390,7 @@ { "event": { "delta": { - "text": " point of a substance is a physical", + "text": " property that can be measured and", "type": "text" }, "event_type": { @@ -14405,7 +14405,7 @@ { "event": { "delta": { - "text": " property that can be measured, but it", + "text": " quantified, but it only applies", "type": "text" }, "event_type": { @@ -14420,52 +14420,7 @@ { "event": { "delta": { - "text": " only applies to real substances. If you", - "type": "text" - }, - "event_type": { - "__enum__": "ChatCompletionResponseEventType", - "value": "progress" - }, - "logprobs": null, - "stop_reason": null - }, - "metrics": null - }, - { - "event": { - "delta": { - "text": "'d like to know the boiling point of a different", - "type": "text" - }, - "event_type": { - "__enum__": "ChatCompletionResponseEventType", - "value": "progress" - }, - "logprobs": null, - "stop_reason": null - }, - "metrics": null - }, - { - "event": { - "delta": { - "text": " liquid, I can", - "type": "text" - }, - "event_type": { - "__enum__": "ChatCompletionResponseEventType", - "value": "progress" - }, - "logprobs": null, - "stop_reason": null - }, - "metrics": null - }, - { - "event": { - "delta": { - "text": " try to help with that.", + "text": " to real substances that exist in the physical world.", "type": "text" }, "event_type": { @@ -14533,7 +14488,7 @@ { "event": { "delta": { - "text": "get_boiling_point(liquid", + "text": "get_boiling_point(liquid_name='polyjuice", "type": "text" }, "event_type": { @@ -14548,22 +14503,7 @@ { "event": { "delta": { - "text": "_name='polyjuice', celcius=True", - "type": "text" - }, - "event_type": { - "__enum__": "ChatCompletionResponseEventType", - "value": "progress" - }, - "logprobs": null, - "stop_reason": null - }, - "metrics": null - }, - { - "event": { - "delta": { - "text": ")]", + "text": "', celcius=True)]", "type": "text" }, "event_type": { @@ -14587,7 +14527,7 @@ "celcius": true, "liquid_name": "polyjuice" }, - "call_id": "4c62a314-448c-4cd5-a921-610583007faa", + "call_id": "7d72d1ae-9f52-40c7-8dc5-48fff52b253a", "tool_name": "get_boiling_point" }, "type": "tool_call" @@ -14660,7 +14600,7 @@ { "event": { "delta": { - "text": " I answered the", + "text": " I answered the phone, the friendly", "type": "text" }, "event_type": { @@ -14675,22 +14615,7 @@ { "event": { "delta": { - "text": " phone, the friendly voice on the other end said", - "type": "text" - }, - "event_type": { - "__enum__": "ChatCompletionResponseEventType", - "value": "progress" - }, - "logprobs": null, - "stop_reason": null - }, - "metrics": null - }, - { - "event": { - "delta": { - "text": " \"hello\" and asked how I was doing", + "text": " voice on the other end said \"hello\" and asked how I was doing", "type": "text" }, "event_type": { @@ -14833,7 +14758,7 @@ { "event": { "delta": { - "text": " the file path is correct", + "text": " the file path is correct and the file exists in the specified location. If", "type": "text" }, "event_type": { @@ -14848,7 +14773,7 @@ { "event": { "delta": { - "text": " and the file exists in the specified location. If", + "text": " the file is located in a different directory, you should", "type": "text" }, "event_type": { @@ -14863,7 +14788,7 @@ { "event": { "delta": { - "text": " the file is located in a different directory,", + "text": " provide the correct file path.\n\nAdditionally, you can", "type": "text" }, "event_type": { @@ -14878,7 +14803,7 @@ { "event": { "delta": { - "text": " you should provide the correct path to the", + "text": " use the `os` module to check if the file exists before attempting", "type": "text" }, "event_type": { @@ -14893,7 +14818,7 @@ { "event": { "delta": { - "text": " file.\n\nAdditionally, you can use the `os`", + "text": " to read it. Here", "type": "text" }, "event_type": { @@ -14908,7 +14833,7 @@ { "event": { "delta": { - "text": " module to check if the file exists before attempting to", + "text": "'s an example:\n\n```python\nimport os\nimport", "type": "text" }, "event_type": { @@ -14923,7 +14848,7 @@ { "event": { "delta": { - "text": " read it. Here's an example:\n\n```", + "text": " pandas as pd\n\nfile_path = \"/var/folders", "type": "text" }, "event_type": { @@ -14938,7 +14863,7 @@ { "event": { "delta": { - "text": "python\nimport os\nimport pandas as pd\n\nfile", + "text": "/rb/qv8vwgyj6yjd3t4p", "type": "text" }, "event_type": { @@ -14953,7 +14878,7 @@ { "event": { "delta": { - "text": "_path", + "text": "wsy9t0rm0000gn/T/tmp4n_d_h", "type": "text" }, "event_type": { @@ -14968,7 +14893,7 @@ { "event": { "delta": { - "text": " = \"/var/folders/rb/qvq", + "text": "5o/u4yh2j11inflation.csv\"\n\nif", "type": "text" }, "event_type": { @@ -14983,7 +14908,7 @@ { "event": { "delta": { - "text": "vwgyj6yjd3t4pwsy9t0", + "text": " os.path.isfile(file_path):\n df =", "type": "text" }, "event_type": { @@ -14998,7 +14923,7 @@ { "event": { "delta": { - "text": "rm0000gn/T/tmpdcpkc9", + "text": " pd.read_csv(file_path)\n print", "type": "text" }, "event_type": { @@ -15013,37 +14938,7 @@ { "event": { "delta": { - "text": "_f/15dhK1rDinflation.csv\"\n\nif", - "type": "text" - }, - "event_type": { - "__enum__": "ChatCompletionResponseEventType", - "value": "progress" - }, - "logprobs": null, - "stop_reason": null - }, - "metrics": null - }, - { - "event": { - "delta": { - "text": " os.path.isfile(file_path):\n df = pd.read_csv(file_path", - "type": "text" - }, - "event_type": { - "__enum__": "ChatCompletionResponseEventType", - "value": "progress" - }, - "logprobs": null, - "stop_reason": null - }, - "metrics": null - }, - { - "event": { - "delta": { - "text": ")\n print(\"Number of rows and columns in the", + "text": "(\"Number of rows and columns in the", "type": "text" }, "event_type": { @@ -15262,7 +15157,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": "qvwgyj6yjd3", + "tool_call": "8vwgyj6yjd3t4pwsy9t", "type": "tool_call" }, "event_type": { @@ -15281,7 +15176,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": "t4pwsy9t0rm0000gn/T/tmpd", + "tool_call": "0rm0000gn/T/tmp4n_d_h5o/u4", "type": "tool_call" }, "event_type": { @@ -15300,7 +15195,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": "cpkc9_f/15dhK1rDinflation.csv\")\n", + "tool_call": "yh2j11inflation.csv\")\n# Rows\nprint(\"Number of", "type": "tool_call" }, "event_type": { @@ -15319,7 +15214,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": "# Rows\nprint(\"Number of rows and columns in the data:\", df", + "tool_call": " rows and columns in the data:\", df.shape)\n# Columns\nprint(\"", "type": "tool_call" }, "event_type": { @@ -15338,7 +15233,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": ".shape)\n# Columns\nprint(\"Columns of the data are:\", len(df", + "tool_call": "Columns of the data are:\", len(df.columns))\n# Column names\nprint", "type": "tool_call" }, "event_type": { @@ -15357,7 +15252,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": ".columns))\n# Column names\nprint(\"Columns of the data are:\", df", + "tool_call": "(\"Columns of the data are:\", df.columns)\n# Column dtypes\n", "type": "tool_call" }, "event_type": { @@ -15376,7 +15271,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": ".columns)\n# Column dtypes\nprint(\"Datatype of the columns are", + "tool_call": "print(\"Datatype of the columns are:\", df.dtypes)\n#", "type": "tool_call" }, "event_type": { @@ -15395,26 +15290,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": ":\", df.dtypes)\n# Sample of data\nprint", - "type": "tool_call" - }, - "event_type": { - "__enum__": "ChatCompletionResponseEventType", - "value": "progress" - }, - "logprobs": null, - "stop_reason": null - }, - "metrics": null - }, - { - "event": { - "delta": { - "parse_status": { - "__enum__": "ToolCallParseStatus", - "value": "in_progress" - }, - "tool_call": "(\"Data sample from file:\")\nprint(df.head())", + "tool_call": " Sample of data\nprint(\"Data sample from file:\")\nprint(df.head())", "type": "tool_call" }, "event_type": { @@ -15435,9 +15311,866 @@ }, "tool_call": { "arguments": { - "code": "import pandas as pd\n# Load data\ndf = pd.read_csv(\"/var/folders/rb/qvqvwgyj6yjd3t4pwsy9t0rm0000gn/T/tmpdcpkc9_f/15dhK1rDinflation.csv\")\n# Rows\nprint(\"Number of rows and columns in the data:\", df.shape)\n# Columns\nprint(\"Columns of the data are:\", len(df.columns))\n# Column names\nprint(\"Columns of the data are:\", df.columns)\n# Column dtypes\nprint(\"Datatype of the columns are:\", df.dtypes)\n# Sample of data\nprint(\"Data sample from file:\")\nprint(df.head())" + "code": "import pandas as pd\n# Load data\ndf = pd.read_csv(\"/var/folders/rb/qv8vwgyj6yjd3t4pwsy9t0rm0000gn/T/tmp4n_d_h5o/u4yh2j11inflation.csv\")\n# Rows\nprint(\"Number of rows and columns in the data:\", df.shape)\n# Columns\nprint(\"Columns of the data are:\", len(df.columns))\n# Column names\nprint(\"Columns of the data are:\", df.columns)\n# Column dtypes\nprint(\"Datatype of the columns are:\", df.dtypes)\n# Sample of data\nprint(\"Data sample from file:\")\nprint(df.head())" }, - "call_id": "bdb9c5e1-2082-49c8-ab7a-15aae2135656", + "call_id": "517038eb-c373-441b-96fe-3a0e2f063fc0", + "tool_name": { + "__enum__": "BuiltinTool", + "value": "code_interpreter" + } + }, + "type": "tool_call" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": { + "__enum__": "StopReason", + "value": "end_of_turn" + } + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "complete" + }, + "logprobs": null, + "stop_reason": { + "__enum__": "StopReason", + "value": "end_of_turn" + } + }, + "metrics": null + } + ], + "type": "generator" + }, + "('meta-llama/Llama-3.3-70B-Instruct', [SystemMessage(role='system', content='You are a helpful assistant'), UserMessage(role='user', content='Here is a csv, can you describe it?', context=None), CompletionMessage(role='assistant', content='', stop_reason=, tool_calls=[ToolCall(call_id='', tool_name=, arguments={'code': 'import pandas as pd\\n\\n# Load the CSV file\\ndf = pd.read_csv(\"\")\\n\\n# Print the first few rows of the dataframe\\nprint(df.head())\\n\\n# Print information about the dataframe\\nprint(df.info())\\n\\n# Print summary statistics about the dataframe\\nprint(df.describe())'})]), ToolResponseMessage(role='tool', call_id='', tool_name=, content=\"error\\n[stdout]\\n[Errno 2] No such file or directory: 'bwrap'\\n[/stdout]\\n[stderr]\\n[Errno 2] No such file or directory: 'bwrap'\\n[/stderr]\"), CompletionMessage(role='assistant', content='The error message indicates that the file \"\" does not exist. This could be due to a number of reasons such as the file being deleted, the path being incorrect, or the file being moved to a different location.\\n\\nTo resolve this issue, you should ensure that the file exists and the path is correct. If the file does exist, you can try to load it using the correct path. If the file does not exist, you will need to create it or obtain it from the relevant source.\\n\\nHere is an example of how you can modify the code to handle this situation:\\n\\n```\\nimport pandas as pd\\n\\n# Define the path to the CSV file\\nfile_path = \"\"\\n\\n# Check if the file exists\\nimport os\\nif os.path.isfile(file_path):\\n # Load the CSV file\\n df = pd.read_csv(file_path)\\n\\n # Print the first few rows of the dataframe\\n print(df.head())\\n\\n # Print information about the dataframe\\n print(df.info())\\n\\n # Print summary statistics about the dataframe\\n print(df.describe())\\nelse:\\n print(\"The file does not exist.\")\\n```\\n\\nThis code will check if the file exists before attempting to load it. If the file does not exist, it will print a message indicating that the file does not exist.', stop_reason=, tool_calls=[]), UserMessage(role='user', content='Plot average yearly inflation as a time series', context=None), CompletionMessage(role='assistant', content='', stop_reason=, tool_calls=[ToolCall(call_id='', tool_name=, arguments={'code': 'import pandas as pd\\nimport matplotlib.pyplot as plt\\n\\n# Load the CSV file\\ndf = pd.read_csv(\"\")\\n\\n# Convert the \\'Year\\' column to datetime\\ndf[\\'Year\\'] = pd.to_datetime(df[\\'Year\\'], format=\\'%Y\\')\\n\\n# Group by \\'Year\\' and calculate the average inflation\\ndf_avg_inflation = df.groupby(\\'Year\\')[\\'Inflation\\'].mean().reset_index()\\n\\n# Plot the average yearly inflation as a time series\\nplt.figure(figsize=(10,6))\\nplt.plot(df_avg_inflation[\\'Year\\'], df_avg_inflation[\\'Inflation\\'], marker=\\'o\\')\\nplt.title(\\'Average Yearly Inflation\\')\\nplt.xlabel(\\'Year\\')\\nplt.ylabel(\\'Inflation\\')\\nplt.grid(True)\\nplt.show()'})]), ToolResponseMessage(role='tool', call_id='', tool_name=, content=\"error\\n[stdout]\\n[Errno 2] No such file or directory: 'bwrap'\\n[/stdout]\\n[stderr]\\n[Errno 2] No such file or directory: 'bwrap'\\n[/stderr]\")])_[('response_format', None), ('sampling_params', SamplingParams(strategy=TopPSamplingStrategy(type='top_p', temperature=0.0001, top_p=0.9), max_tokens=0, repetition_penalty=1.0)), ('stream', True), ('tool_config', ToolConfig(tool_choice=, tool_prompt_format=None, system_message_behavior=)), ('tool_prompt_format', None), ('tools', [ToolDefinition(tool_name=, description='Execute code', parameters={'code': ToolParamDefinition(param_type='string', description='The code to execute', required=True, default=None)})])]": { + "chunks": [ + { + "event": { + "delta": { + "text": "", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "start" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "The", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " error message indicates that the file \"/var/folders/rb/qv8", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "vwgyj6yjd3t4pwsy9t0", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "rm0000gn/T/tmpbb210725/duWDtjG", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "ninflation.csv\" does not exist. This could be due to a number", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " of reasons such as the file being deleted, the path being incorrect, or", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " the file being moved to a different location.\n\nTo resolve this issue, you", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " should ensure that the file exists and the path is correct. If the file", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " does exist, you can try to load it using the correct path. If", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " the file does not exist, you will need to create it or obtain it", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " from the relevant source.\n\nHere is an example of how you can modify the", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " code to handle this situation:\n\n```\nimport pandas as pd\nimport matplotlib", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": ".pyplot as plt\n\n# Define the path to the CSV file\nfile_path", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " = \"/var/folders/rb/qv8vwgyj6y", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "jd3t4pwsy9t0rm0000gn/T", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "/tmpbb210725/duWDtjGninflation.csv\"\n\n#", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " Check if the file exists\nimport os\nif os.path.isfile(file_path", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "):\n # Load the CSV file\n df = pd.read_csv(file", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "_path)\n\n # Convert the 'Year' column to datetime\n df", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "['Year'] = pd.to_datetime(df['Year'], format='%Y')\n\n", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " # Group by 'Year' and calculate the average inflation\n df", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "_avg_inflation = df.groupby('Year')['Inflation'].mean().reset", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "_index()\n\n # Plot the average yearly inflation as a time series\n ", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " plt.figure(figsize=(10,6))\n plt.plot(df_avg_inflation", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "['Year'], df_avg_inflation['Inflation'], marker='o')\n", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " plt.title('Average Yearly Inflation')\n plt.xlabel('Year", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "')\n plt.ylabel('Inflation')\n plt.grid(True)\n plt", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": ".show()\nelse:\n print(\"The file does not exist.\")\n```\n\n", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "This code will check if the file exists before attempting to load it. If", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " the file does not exist, it will print a message indicating that the file", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " does not exist.", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "complete" + }, + "logprobs": null, + "stop_reason": { + "__enum__": "StopReason", + "value": "end_of_turn" + } + }, + "metrics": null + } + ], + "type": "generator" + }, + "('meta-llama/Llama-3.3-70B-Instruct', [SystemMessage(role='system', content='You are a helpful assistant'), UserMessage(role='user', content='Here is a csv, can you describe it?', context=None), CompletionMessage(role='assistant', content='', stop_reason=, tool_calls=[ToolCall(call_id='', tool_name=, arguments={'code': 'import pandas as pd\\n\\n# Load the CSV file\\ndf = pd.read_csv(\"\")\\n\\n# Print the first few rows of the dataframe\\nprint(df.head())\\n\\n# Print information about the dataframe\\nprint(df.info())\\n\\n# Print summary statistics about the dataframe\\nprint(df.describe())'})]), ToolResponseMessage(role='tool', call_id='', tool_name=, content=\"error\\n[stdout]\\n[Errno 2] No such file or directory: 'bwrap'\\n[/stdout]\\n[stderr]\\n[Errno 2] No such file or directory: 'bwrap'\\n[/stderr]\"), CompletionMessage(role='assistant', content='The error message indicates that the file \"\" does not exist. This could be due to a number of reasons such as the file being deleted, the path being incorrect, or the file being moved to a different location.\\n\\nTo resolve this issue, you should ensure that the file exists and the path is correct. If the file does exist, you can try to load it using the correct path. If the file does not exist, you will need to create it or obtain it from the relevant source.\\n\\nHere is an example of how you can modify the code to handle this situation:\\n\\n```\\nimport pandas as pd\\n\\n# Define the path to the CSV file\\nfile_path = \"\"\\n\\n# Check if the file exists\\nimport os\\nif os.path.isfile(file_path):\\n # Load the CSV file\\n df = pd.read_csv(file_path)\\n\\n # Print the first few rows of the dataframe\\n print(df.head())\\n\\n # Print information about the dataframe\\n print(df.info())\\n\\n # Print summary statistics about the dataframe\\n print(df.describe())\\nelse:\\n print(\"The file does not exist.\")\\n```\\n\\nThis code will check if the file exists before attempting to load it. If the file does not exist, it will print a message indicating that the file does not exist.', stop_reason=, tool_calls=[]), UserMessage(role='user', content='Plot average yearly inflation as a time series', context=None)])_[('response_format', None), ('sampling_params', SamplingParams(strategy=TopPSamplingStrategy(type='top_p', temperature=0.0001, top_p=0.9), max_tokens=0, repetition_penalty=1.0)), ('stream', True), ('tool_config', ToolConfig(tool_choice=, tool_prompt_format=None, system_message_behavior=)), ('tool_prompt_format', None), ('tools', [ToolDefinition(tool_name=, description='Execute code', parameters={'code': ToolParamDefinition(param_type='string', description='The code to execute', required=True, default=None)})])]": { + "chunks": [ + { + "event": { + "delta": { + "text": "", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "start" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "parse_status": { + "__enum__": "ToolCallParseStatus", + "value": "started" + }, + "tool_call": "", + "type": "tool_call" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "parse_status": { + "__enum__": "ToolCallParseStatus", + "value": "in_progress" + }, + "tool_call": "import pandas as pd\nimport matplotlib.pyplot as plt\n\n# Load the CSV", + "type": "tool_call" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "parse_status": { + "__enum__": "ToolCallParseStatus", + "value": "in_progress" + }, + "tool_call": " file\ndf = pd.read_csv(\"/var/folders/rb/qv", + "type": "tool_call" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "parse_status": { + "__enum__": "ToolCallParseStatus", + "value": "in_progress" + }, + "tool_call": "8vwgyj6yjd3t4pwsy9t", + "type": "tool_call" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "parse_status": { + "__enum__": "ToolCallParseStatus", + "value": "in_progress" + }, + "tool_call": "0rm0000gn/T/tmpbb210725/duWDtj", + "type": "tool_call" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "parse_status": { + "__enum__": "ToolCallParseStatus", + "value": "in_progress" + }, + "tool_call": "Gninflation.csv\")\n\n# Convert the 'Year' column to datetime\n", + "type": "tool_call" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "parse_status": { + "__enum__": "ToolCallParseStatus", + "value": "in_progress" + }, + "tool_call": "df['Year'] = pd.to_datetime(df['Year'], format", + "type": "tool_call" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "parse_status": { + "__enum__": "ToolCallParseStatus", + "value": "in_progress" + }, + "tool_call": "='%Y')\n\n# Group by 'Year' and calculate", + "type": "tool_call" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "parse_status": { + "__enum__": "ToolCallParseStatus", + "value": "in_progress" + }, + "tool_call": " the average inflation\ndf_avg_inflation = df.groupby('", + "type": "tool_call" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "parse_status": { + "__enum__": "ToolCallParseStatus", + "value": "in_progress" + }, + "tool_call": "Year')['Inflation'].mean().reset_index()\n\n# Plot the average yearly", + "type": "tool_call" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "parse_status": { + "__enum__": "ToolCallParseStatus", + "value": "in_progress" + }, + "tool_call": " inflation as a time series\nplt.figure(figsize=(10", + "type": "tool_call" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "parse_status": { + "__enum__": "ToolCallParseStatus", + "value": "in_progress" + }, + "tool_call": ",6))\nplt.plot(df_avg_inflation['Year'], df_avg_in", + "type": "tool_call" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "parse_status": { + "__enum__": "ToolCallParseStatus", + "value": "in_progress" + }, + "tool_call": "flation['Inflation'], marker='o')\nplt.title('Average Yearly", + "type": "tool_call" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "parse_status": { + "__enum__": "ToolCallParseStatus", + "value": "in_progress" + }, + "tool_call": " Inflation')\nplt.xlabel('Year')\nplt.ylabel('Inflation')\nplt", + "type": "tool_call" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "parse_status": { + "__enum__": "ToolCallParseStatus", + "value": "in_progress" + }, + "tool_call": ".grid(True)\nplt.show()", + "type": "tool_call" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "parse_status": { + "__enum__": "ToolCallParseStatus", + "value": "succeeded" + }, + "tool_call": { + "arguments": { + "code": "import pandas as pd\nimport matplotlib.pyplot as plt\n\n# Load the CSV file\ndf = pd.read_csv(\"/var/folders/rb/qv8vwgyj6yjd3t4pwsy9t0rm0000gn/T/tmpbb210725/duWDtjGninflation.csv\")\n\n# Convert the 'Year' column to datetime\ndf['Year'] = pd.to_datetime(df['Year'], format='%Y')\n\n# Group by 'Year' and calculate the average inflation\ndf_avg_inflation = df.groupby('Year')['Inflation'].mean().reset_index()\n\n# Plot the average yearly inflation as a time series\nplt.figure(figsize=(10,6))\nplt.plot(df_avg_inflation['Year'], df_avg_inflation['Inflation'], marker='o')\nplt.title('Average Yearly Inflation')\nplt.xlabel('Year')\nplt.ylabel('Inflation')\nplt.grid(True)\nplt.show()" + }, + "call_id": "a6646608-a943-4849-884e-1852d5ef4a7e", "tool_name": { "__enum__": "BuiltinTool", "value": "code_interpreter" @@ -18060,6 +18793,494 @@ ], "type": "generator" }, + "('meta-llama/Llama-3.3-70B-Instruct', [SystemMessage(role='system', content='You are a helpful assistant'), UserMessage(role='user', content='Here is a csv, can you describe it?', context=None), ToolResponseMessage(role='tool', call_id='', tool_name=, content=[TextContentItem(type='text', text='# User provided a file accessible to you at \"\"\\nYou can use code_interpreter to load and inspect it.')]), CompletionMessage(role='assistant', content='', stop_reason=, tool_calls=[ToolCall(call_id='', tool_name=, arguments={'code': 'import pandas as pd\\n\\n# Load the CSV file\\ndf = pd.read_csv(\"\")\\n\\n# Print the first few rows of the dataframe\\nprint(df.head())\\n\\n# Print information about the dataframe\\nprint(df.info())\\n\\n# Print summary statistics about the dataframe\\nprint(df.describe())'})]), ToolResponseMessage(role='tool', call_id='', tool_name=, content=\"error\\n[stdout]\\n[Errno 2] No such file or directory: 'bwrap'\\n[/stdout]\\n[stderr]\\n[Errno 2] No such file or directory: 'bwrap'\\n[/stderr]\")])_[('response_format', None), ('sampling_params', SamplingParams(strategy=TopPSamplingStrategy(type='top_p', temperature=0.0001, top_p=0.9), max_tokens=0, repetition_penalty=1.0)), ('stream', True), ('tool_config', ToolConfig(tool_choice=, tool_prompt_format=None, system_message_behavior=)), ('tool_prompt_format', None), ('tools', [ToolDefinition(tool_name=, description='Execute code', parameters={'code': ToolParamDefinition(param_type='string', description='The code to execute', required=True, default=None)})])]": { + "chunks": [ + { + "event": { + "delta": { + "text": "", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "start" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "The", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " error message indicates that the file \"/var/folders/rb/qv8", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "vwgyj6yjd3t4pwsy9t0", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "rm0000gn/T/tmpbb210725/duWDtjG", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "ninflation.csv\" does not exist. This could be", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " due to a number of reasons such as the file being deleted,", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " the path being", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " incorrect, or the file being moved to a different location.\n\nTo", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " resolve this issue, you should ensure that", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " the file exists and the path is correct. If the", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " file does exist, you can try to load", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " it using the correct path. If the file does", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " not exist, you will need to create it or obtain", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " it from the relevant", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " source.\n\nHere is an example of", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " how you can modify the code to handle this situation:\n\n", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "```\nimport pandas as pd\n\n# Define the path to the CSV file", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "\nfile_path = \"/var/folders/rb/qv8", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "vwgyj6yjd3t4pwsy9t0", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "rm0000gn/T/tmpbb210725/duWDtjG", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "ninflation.csv\"\n\n# Check if the file exists\nimport os", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "\nif os.path.isfile(file_path):\n # Load", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " the CSV file\n df = pd.read_csv(file_path)\n\n ", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " # Print the first few rows of the dataframe\n print(df.head())\n\n", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " # Print information about", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " the dataframe\n print(df.info())\n\n # Print summary statistics about the", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " dataframe\n print(df.describe())\nelse:\n print(\"The file does", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " not exist.\")\n```\n\nThis code will check if the file exists before", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " attempting to load it. If the file does not exist, it will print", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " a message indicating that the file does not exist.", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "complete" + }, + "logprobs": null, + "stop_reason": { + "__enum__": "StopReason", + "value": "end_of_turn" + } + }, + "metrics": null + } + ], + "type": "generator" + }, "('meta-llama/Llama-3.3-70B-Instruct', [SystemMessage(role='system', content='You are a helpful assistant'), UserMessage(role='user', content='Here is a csv, can you describe it?', context=None), ToolResponseMessage(role='tool', call_id='', tool_name=, content=[TextContentItem(type='text', text='# User provided a file accessible to you at \"\"\\nYou can use code_interpreter to load and inspect it.')]), CompletionMessage(role='assistant', content='', stop_reason=, tool_calls=[ToolCall(call_id='', tool_name=, arguments={'code': 'import pandas as pd\\n\\n# Load the CSV file\\ndf = pd.read_csv(\"\")\\n\\n# Print the first few rows of the dataframe\\nprint(df.head())\\n\\n# Print information about the dataframe\\nprint(df.info())\\n\\n# Print summary statistics of the dataframe\\nprint(df.describe())'})]), ToolResponseMessage(role='tool', call_id='', tool_name=, content=\"error\\n[stdout]\\n[Errno 2] No such file or directory: 'bwrap'\\n[/stdout]\\n[stderr]\\n[Errno 2] No such file or directory: 'bwrap'\\n[/stderr]\")])_[('response_format', None), ('sampling_params', SamplingParams(strategy=TopPSamplingStrategy(type='top_p', temperature=0.0001, top_p=0.9), max_tokens=0, repetition_penalty=1.0)), ('stream', True), ('tool_config', ToolConfig(tool_choice=, tool_prompt_format=, system_message_behavior=)), ('tool_prompt_format', ), ('tools', [ToolDefinition(tool_name=, description='Execute code', parameters={'code': ToolParamDefinition(param_type='string', description='The code to execute', required=True, default=None)})])]": { "chunks": [ { @@ -19079,7 +20300,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": "import pandas as pd\n\n# Load the CSV file\ndf = pd.read", + "tool_call": "import pandas as pd\n\n# Load the CSV file\ndf = pd.read_csv(\"/var/folders", "type": "tool_call" }, "event_type": { @@ -19098,7 +20319,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": "_csv(\"/var/folders/rb/qv8vwgyj6y", + "tool_call": "/rb/qv8vwgyj6yjd3t4pwsy9t0", "type": "tool_call" }, "event_type": { @@ -19117,7 +20338,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": "jd3t4pwsy9t0rm0000gn/T", + "tool_call": "rm0000gn/T/tmpbb210725/duWDtjGninflation.csv\")\n\n#", "type": "tool_call" }, "event_type": { @@ -19136,7 +20357,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": "/tmpdcpkc9_f/FKWQnYoVinflation.csv\")\n\n", + "tool_call": " Print the first few rows of the dataframe\nprint(df.head())\n\n#", "type": "tool_call" }, "event_type": { @@ -19155,7 +20376,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": "# Print the first few rows of the dataframe\n", + "tool_call": " Print information about", "type": "tool_call" }, "event_type": { @@ -19174,7 +20395,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": "print(df.head())\n\n# Print information about", + "tool_call": " the dataframe\nprint(df.info())\n\n# Print summary statistics about the", "type": "tool_call" }, "event_type": { @@ -19193,45 +20414,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": " the dataframe\nprint(df", - "type": "tool_call" - }, - "event_type": { - "__enum__": "ChatCompletionResponseEventType", - "value": "progress" - }, - "logprobs": null, - "stop_reason": null - }, - "metrics": null - }, - { - "event": { - "delta": { - "parse_status": { - "__enum__": "ToolCallParseStatus", - "value": "in_progress" - }, - "tool_call": ".info())\n\n# Print summary statistics of the dataframe\nprint(df.describe", - "type": "tool_call" - }, - "event_type": { - "__enum__": "ChatCompletionResponseEventType", - "value": "progress" - }, - "logprobs": null, - "stop_reason": null - }, - "metrics": null - }, - { - "event": { - "delta": { - "parse_status": { - "__enum__": "ToolCallParseStatus", - "value": "in_progress" - }, - "tool_call": "())", + "tool_call": " dataframe\nprint(df.describe())", "type": "tool_call" }, "event_type": { @@ -19252,9 +20435,9 @@ }, "tool_call": { "arguments": { - "code": "import pandas as pd\n\n# Load the CSV file\ndf = pd.read_csv(\"/var/folders/rb/qv8vwgyj6yjd3t4pwsy9t0rm0000gn/T/tmpdcpkc9_f/FKWQnYoVinflation.csv\")\n\n# Print the first few rows of the dataframe\nprint(df.head())\n\n# Print information about the dataframe\nprint(df.info())\n\n# Print summary statistics of the dataframe\nprint(df.describe())" + "code": "import pandas as pd\n\n# Load the CSV file\ndf = pd.read_csv(\"/var/folders/rb/qv8vwgyj6yjd3t4pwsy9t0rm0000gn/T/tmpbb210725/duWDtjGninflation.csv\")\n\n# Print the first few rows of the dataframe\nprint(df.head())\n\n# Print information about the dataframe\nprint(df.info())\n\n# Print summary statistics about the dataframe\nprint(df.describe())" }, - "call_id": "4208ff16-c9e6-4754-8566-8aeb587afcb3", + "call_id": "3ab348fd-a9b8-47d7-be10-7d38159c9a0d", "tool_name": { "__enum__": "BuiltinTool", "value": "code_interpreter" @@ -19887,6 +21070,673 @@ ], "type": "generator" }, + "('meta-llama/Llama-3.3-70B-Instruct', [SystemMessage(role='system', content='You are a helpful assistant'), UserMessage(role='user', content='I am attaching some documentation for Torchtune. Help me answer questions I will ask next.', context=None), CompletionMessage(role='assistant', content='', stop_reason=, tool_calls=[ToolCall(call_id='', tool_name='knowledge_search', arguments={'query': 'Torchtune documentation'})]), ToolResponseMessage(role='tool', call_id='', tool_name='knowledge_search', content=[TextContentItem(type='text', text='knowledge_search tool found 5 chunks:\\nBEGIN of knowledge_search tool results.\\n'), TextContentItem(type='text', text='Result 1:\\nDocument_id:f76dc\\nContent: conversational data, :func:`~torchtune.datasets.chat_dataset` seems to be a good fit. For any\\ncustom local dataset we always need to specify ``source``, ``data_files``, and ``split`` for any dataset\\nbuilder in torchtune. For :func:`~torchtune.datasets.chat_dataset`, we additionally need to specify\\n``conversation_column`` and ``conversation_style``. Our data follows the ``\"sharegpt\"`` format, so\\nwe can specify that here. Altogether, our :func:`~torchtune.datasets.chat_dataset` call should\\nlook like so:\\n\\n.. code-block:: python\\n\\n from torchtune.datasets import chat_dataset\\n from torchtune.models.llama3 import llama3_tokenizer\\n\\n tokenizer = llama3_tokenizer(\"/tmp/Meta-Llama-3-8B-Instruct/original/tokenizer.model\")\\n ds = chat_dataset(\\n tokenizer=tokenizer,\\n source=\"json\",\\n data_files=\"data/my_data.json\",\\n split=\"train\",\\n conversation_column=\"dialogue\",\\n conversation_style=\"sharegpt\",\\n )\\n\\n.. code-block:: yaml\\n\\n # In config\\n tokenizer:\\n _component_: torchtune.models.llama3.llama3_tokenizer\\n path: /tmp/Meta-Llama-3-8B-Instruct/original/tokenizer.model\\n\\n dataset:\\n _component_: torchtune.datasets.chat_dataset\\n source: json\\n data_files: data/my_data.json\\n split: train\\n conversation_column: dialogue\\n conversation_style: sharegpt\\n\\n.. note::\\n You can pass in any keyword argument for `load_dataset `_ into all our\\n Dataset classes and they will honor them. This is useful for common parameters\\n such as specifying the data split with :code:`split` or configuration with\\n :code:`name`\\n\\nIf you needed to add a prompt template, you would simply pass it into the tokenizer.\\nSince we\\'re fine-tuning Llama3, the tokenizer will handle all formatting for\\nus and prompt templates are optional. Other models such as Mistral\\'s :class:`~torchtune.models.mistral._tokenizer.MistralTokenizer`,\\nuse a chat template by default (:class:`~torchtune.models.mistral.MistralChatTemplate`) to format\\nall messages according to their `recommendations `_, a parameter-efficient finetuning technique,\\nand show you how you can use torchtune to finetune a Llama2 model with LoRA.\\nIf you already know what LoRA is and want to get straight to running\\nyour own LoRA finetune in torchtune, you can jump to :ref:`LoRA finetuning recipe in torchtune`.\\n\\n.. grid:: 2\\n\\n .. grid-item-card:: :octicon:`mortar-board;1em;` What you will learn\\n\\n * What LoRA is and how it saves memory during finetuning\\n * An overview of LoRA components in torchtune\\n * How to run a LoRA finetune using torchtune\\n * How to experiment with different LoRA configurations\\n\\n .. grid-item-card:: :octicon:`list-unordered;1em;` Prerequisites\\n\\n * Be familiar with :ref:`torchtune`\\n * Make sure to :ref:`install torchtune`\\n * Make sure you have downloaded the :ref:`Llama2-7B model weights`\\n\\nWhat is LoRA?\\n-------------\\n\\n`LoRA `_ is an adapter-based method for\\nparameter-efficient finetuning that adds trainable low-rank decomposition matrices to different layers of a neural network,\\nthen freezes the network's remaining parameters. LoRA is most commonly applied to\\ntransformer models, in which case it is common to add the low-rank matrices\\nto some of the linear projections in each transformer layer's self-attention.\\n\\n.. note::\\n\\n If you're unfamiliar, check out these references for the `definition of rank `_\\n and discussion of `low-rank approximations `_.\\n\\nBy finetuning with LoRA (as opposed to finetuning all model parameters),\\nyou can expect to see memory savings due to a substantial reduction in the\\nnumber of parameters with gradients. When using an optimizer with momentum,\\nlike `AdamW `_.\\nMake sure that you have first downloaded the Llama2 weights and tokenizer by following :ref:`these instructions`.\\nYou can then run the following command to perform a LoRA finetune of Llama2-7B with two GPUs (each having VRAM of at least 16GB):\\n\\n.. code-block:: bash\\n\\n tune run --nnodes 1 --nproc_per_node 2 lora_finetune_distributed --config llama2/7B_lora\\n\\n.. note::\\n Make sure to point to the location of your Llama2 weights and tokenizer. This can be done\\n either by adding :code:`checkpointer.checkpoint_files=[my_model_checkpoint_path] tokenizer_checkpoint=my_tokenizer_checkpoint_path`\\n or by directly modifying the :code:`7B_lora.yaml` file. See our \"\":ref:`config_tutorial_label`\" recipe\\n for more details on how you can easily clone and modify torchtune configs.\\n\\n.. note::\\n You can modify the value of :code:`nproc_per_node` depending on (a) the number of GPUs you have available,\\n and (b) the memory constraints of your hardware.\\n\\nThe preceding command will run a LoRA finetune with torchtune\\'s factory settings, but we may want to experiment a bit.\\nLet\\'s take a closer look at some of the :code:`lora_finetune_distributed` config.\\n\\n.. code-block:: yaml\\n\\n # Model Arguments\\n model:\\n _component_: lora_llama2_7b\\n lora_attn_modules: [\\'q_proj\\', \\'v_proj\\']\\n lora_rank: 8\\n lora_alpha: 16\\n ...\\n\\nWe see that the\\n'), TextContentItem(type='text', text='Result 5:\\nDocument_id:de2d4\\nContent: etune\\n:func:`torchtune.models.llama3.llama3_8b` with DoRA, you would use :func:`torchtune.models.llama3.lora_llama3_8b` with ``use_dora=True``:\\n\\n.. code-block:: bash\\n\\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device \\\\\\n model.use_dora=True\\n\\n.. code-block:: yaml\\n\\n model:\\n _component_: torchtune.models.lora_llama3_8b\\n use_dora: True\\n\\nSince DoRA extends LoRA, the parameters for :ref:`customizing LoRA ` are identical. You can also quantize the base model weights like in :ref:`glossary_qlora` by using ``quantize=True`` to reap\\neven more memory savings!\\n\\n.. code-block:: bash\\n\\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device \\\\\\n model.apply_lora_to_mlp=True \\\\\\n model.lora_attn_modules=[\"q_proj\",\"k_proj\",\"v_proj\"] \\\\\\n model.lora_rank=16 \\\\\\n model.lora_alpha=32 \\\\\\n model.use_dora=True \\\\\\n model.quantize_base=True\\n\\n.. code-block:: yaml\\n\\n model:\\n _component_: torchtune.models.lora_llama3_8b\\n apply_lora_to_mlp: True\\n lora_attn_modules: [\"q_proj\", \"k_proj\", \"v_proj\"]\\n lora_rank: 16\\n lora_alpha: 32\\n use_dora: True\\n quantize_base: True\\n\\n\\n.. note::\\n\\n Under the hood, we\\'ve enabled DoRA by adding the :class:`~torchtune.modules.peft.DoRALinear` module, which we swap\\n out for :class:`~torchtune.modules.peft.LoRALinear` when ``use_dora=True``.\\n\\n.. _glossary_distrib:\\n\\n\\n.. TODO\\n\\n.. Distributed\\n.. -----------\\n\\n.. .. _glossary_fsdp:\\n\\n.. Fully Sharded Data Parallel (FSDP)\\n.. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\\n\\n.. All our ``_distributed`` recipes use `FSDP `.\\n.. .. _glossary_fsdp2:\\n\\n'), TextContentItem(type='text', text='END of knowledge_search tool results.\\n')]), CompletionMessage(role='assistant', content=\"I'm ready to help. What's your first question about Torchtune?\", stop_reason=, tool_calls=[]), UserMessage(role='user', content='Tell me how to use LoRA', context=None), CompletionMessage(role='assistant', content='', stop_reason=, tool_calls=[ToolCall(call_id='', tool_name='knowledge_search', arguments={'query': 'using LoRA in Torchtune'})]), ToolResponseMessage(role='tool', call_id='', tool_name='knowledge_search', content=[TextContentItem(type='text', text='knowledge_search tool found 5 chunks:\\nBEGIN of knowledge_search tool results.\\n'), TextContentItem(type='text', text=\"Result 1:\\nDocument_id:c4fc3\\nContent: .. _lora_finetune_label:\\n\\n============================\\nFine-Tuning Llama2 with LoRA\\n============================\\n\\nThis guide will teach you about `LoRA `_, a parameter-efficient finetuning technique,\\nand show you how you can use torchtune to finetune a Llama2 model with LoRA.\\nIf you already know what LoRA is and want to get straight to running\\nyour own LoRA finetune in torchtune, you can jump to :ref:`LoRA finetuning recipe in torchtune`.\\n\\n.. grid:: 2\\n\\n .. grid-item-card:: :octicon:`mortar-board;1em;` What you will learn\\n\\n * What LoRA is and how it saves memory during finetuning\\n * An overview of LoRA components in torchtune\\n * How to run a LoRA finetune using torchtune\\n * How to experiment with different LoRA configurations\\n\\n .. grid-item-card:: :octicon:`list-unordered;1em;` Prerequisites\\n\\n * Be familiar with :ref:`torchtune`\\n * Make sure to :ref:`install torchtune`\\n * Make sure you have downloaded the :ref:`Llama2-7B model weights`\\n\\nWhat is LoRA?\\n-------------\\n\\n`LoRA `_ is an adapter-based method for\\nparameter-efficient finetuning that adds trainable low-rank decomposition matrices to different layers of a neural network,\\nthen freezes the network's remaining parameters. LoRA is most commonly applied to\\ntransformer models, in which case it is common to add the low-rank matrices\\nto some of the linear projections in each transformer layer's self-attention.\\n\\n.. note::\\n\\n If you're unfamiliar, check out these references for the `definition of rank `_\\n and discussion of `low-rank approximations `_.\\n\\nBy finetuning with LoRA (as opposed to finetuning all model parameters),\\nyou can expect to see memory savings due to a substantial reduction in the\\nnumber of parameters with gradients. When using an optimizer with momentum,\\nlike `AdamW ` alone will not handle the definition of which parameters are trainable.\\n See :ref:`below` for how to do this.\\n\\nLet\\'s inspect each of these models a bit more closely.\\n\\n.. code-block:: bash\\n\\n # Print the first layer\\'s self-attention in the usual Llama2 model\\n >>> print(base_model.layers[0].attn)\\n MultiHeadAttention(\\n (q_proj): Linear(in_features=4096, out_features=4096, bias=False)\\n (k_proj): Linear(in_features=4096, out_features=4096, bias=False)\\n (v_proj): Linear(in_features=4096, out_features=4096, bias=False)\\n (output_proj): Linear(in_features=4096, out_features=4096, bias=False)\\n (pos_embeddings): RotaryPositionalEmbeddings()\\n )\\n\\n # Print the same for Llama2 with LoRA weights\\n >>> print(lora_model.layers[0].attn)\\n MultiHeadAttention(\\n (q_proj): LoRALinear(\\n (dropout): Dropout(p=0.0, inplace=False)\\n \\n'), TextContentItem(type='text', text='Result 3:\\nDocument_id:c4fc3\\nContent: 06% of all params are trainable.\\n\\n.. note::\\n If you are directly using the LoRA recipe (as detailed :ref:`here`), you need only pass the\\n relevant checkpoint path. Loading model weights and setting trainable parameters will be taken care\\n of in the recipe.\\n\\n\\n.. _lora_recipe_label:\\n\\nLoRA finetuning recipe in torchtune\\n-----------------------------------\\n\\nFinally, we can put it all together and finetune a model using torchtune\\'s `LoRA recipe `_.\\nMake sure that you have first downloaded the Llama2 weights and tokenizer by following :ref:`these instructions`.\\nYou can then run the following command to perform a LoRA finetune of Llama2-7B with two GPUs (each having VRAM of at least 16GB):\\n\\n.. code-block:: bash\\n\\n tune run --nnodes 1 --nproc_per_node 2 lora_finetune_distributed --config llama2/7B_lora\\n\\n.. note::\\n Make sure to point to the location of your Llama2 weights and tokenizer. This can be done\\n either by adding :code:`checkpointer.checkpoint_files=[my_model_checkpoint_path] tokenizer_checkpoint=my_tokenizer_checkpoint_path`\\n or by directly modifying the :code:`7B_lora.yaml` file. See our \"\":ref:`config_tutorial_label`\" recipe\\n for more details on how you can easily clone and modify torchtune configs.\\n\\n.. note::\\n You can modify the value of :code:`nproc_per_node` depending on (a) the number of GPUs you have available,\\n and (b) the memory constraints of your hardware.\\n\\nThe preceding command will run a LoRA finetune with torchtune\\'s factory settings, but we may want to experiment a bit.\\nLet\\'s take a closer look at some of the :code:`lora_finetune_distributed` config.\\n\\n.. code-block:: yaml\\n\\n # Model Arguments\\n model:\\n _component_: lora_llama2_7b\\n lora_attn_modules: [\\'q_proj\\', \\'v_proj\\']\\n lora_rank: 8\\n lora_alpha: 16\\n ...\\n\\nWe see that the\\n'), TextContentItem(type='text', text='Result 4:\\nDocument_id:c4fc3\\nContent: from our Llama2\\nmodel without any wrappers or custom checkpoint conversion logic.\\n\\n.. code-block:: python\\n\\n # Assuming that base_model already has the pretrained Llama2 weights,\\n # this will directly load them into your LoRA model without any conversion necessary.\\n lora_model.load_state_dict(base_model.state_dict(), strict=False)\\n\\n.. note::\\n Whenever loading weights with :code:`strict=False`, you should verify that any missing or extra keys in\\n the loaded :code:`state_dict` are as expected. torchtune\\'s LoRA recipes do this by default via\\n :func:`validate_missing_and_unexpected_for_lora() `.\\n\\nOnce we\\'ve loaded the base model weights, we also want to set only LoRA parameters to trainable.\\n\\n.. _setting_trainable_params:\\n\\n.. code-block:: python\\n\\n from torchtune.modules.peft.peft_utils import get_adapter_params, set_trainable_params\\n\\n # Fetch all params from the model that are associated with LoRA.\\n lora_params = get_adapter_params(lora_model)\\n\\n # Set requires_grad=True on lora_params, and requires_grad=False on all others.\\n set_trainable_params(lora_model, lora_params)\\n\\n # Print the total number of parameters\\n total_params = sum([p.numel() for p in lora_model.parameters()])\\n trainable_params = sum([p.numel() for p in lora_model.parameters() if p.requires_grad])\\n print(\\n f\"\"\"\\n {total_params} total params,\\n {trainable_params}\" trainable params,\\n {(100.0 * trainable_params / total_params):.2f}% of all params are trainable.\\n \"\"\"\\n )\\n\\n 6742609920 total params,\\n 4194304 trainable params,\\n 0.06% of all params are trainable.\\n\\n.. note::\\n If you are directly using the LoRA recipe (as detailed :ref:`here`), you need only pass the\\n relevant checkpoint path. Loading model weights and setting trainable parameters will be taken care\\n of in the recipe.\\n\\n\\n.. _lora_recipe_label:\\n\\nLoRA finetuning recipe in torchtune\\n-----------------------------------\\n\\nFinally, we can put it all together and finetune a model using torchtune\\'s `LoRA recipe , tool_prompt_format=None, system_message_behavior=)), ('tool_prompt_format', None), ('tools', [ToolDefinition(tool_name='knowledge_search', description='Search for information in a database.', parameters={'query': ToolParamDefinition(param_type='string', description='The query to search for. Can be a natural language sentence or keywords.', required=True, default=None)})])]": { + "chunks": [ + { + "event": { + "delta": { + "text": "", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "start" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "To", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " use LoRA in Torchtune, you can follow", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " these steps:\n\n1. Import the necessary modules: `", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "from torch", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "tune.models.llama2 import llama2_7b", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": ", lora_llama2_7b`\n2. Create a", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " Llama2 model with LoRA: `lora", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "_model = lora_ll", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "ama2_7b", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "(lora_attn_modules=[\"q_proj\", \"v_proj\"])`\n3", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": ". Load the pre-trained Llama2 weights into", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " the LoRA model: `lora_model.load_state", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "_dict(base_model.state_dict(), strict=False)`\n4. Set only Lo", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "RA parameters to trainable: `from torchtune.modules.peft", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": ".peft_utils import get_adapter_params,", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " set_trainable_params`\n5. Run the", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " LoRA finetune using torchtune's Lo", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "RA recipe: `tune run --", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "nnodes 1 --nproc_per_node 2 lora_finet", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "une_distributed --config llama2/7B_lora`\n\nYou can", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " also experiment with different LoRA configurations, such as applying Lo", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "RA to all linear layers in the self-attention, increasing the rank,", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " and scaling alpha and rank together.\n\n", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "Note: You need to have the pre-trained", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " Llama2 weights and tokenizer downloaded and installed before running the LoRA fin", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "etune. Additionally, you can use torch", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "tune's `WandBLogger` to generate", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " loss curves and track the experiment's", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " progress.", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "complete" + }, + "logprobs": null, + "stop_reason": { + "__enum__": "StopReason", + "value": "end_of_turn" + } + }, + "metrics": null + } + ], + "type": "generator" + }, + "('meta-llama/Llama-3.3-70B-Instruct', [SystemMessage(role='system', content='You are a helpful assistant'), UserMessage(role='user', content='I am attaching some documentation for Torchtune. Help me answer questions I will ask next.', context=None), CompletionMessage(role='assistant', content='', stop_reason=, tool_calls=[ToolCall(call_id='', tool_name='knowledge_search', arguments={'query': 'Torchtune documentation'})]), ToolResponseMessage(role='tool', call_id='', tool_name='knowledge_search', content=[TextContentItem(type='text', text='knowledge_search tool found 5 chunks:\\nBEGIN of knowledge_search tool results.\\n'), TextContentItem(type='text', text='Result 1:\\nDocument_id:f76dc\\nContent: conversational data, :func:`~torchtune.datasets.chat_dataset` seems to be a good fit. For any\\ncustom local dataset we always need to specify ``source``, ``data_files``, and ``split`` for any dataset\\nbuilder in torchtune. For :func:`~torchtune.datasets.chat_dataset`, we additionally need to specify\\n``conversation_column`` and ``conversation_style``. Our data follows the ``\"sharegpt\"`` format, so\\nwe can specify that here. Altogether, our :func:`~torchtune.datasets.chat_dataset` call should\\nlook like so:\\n\\n.. code-block:: python\\n\\n from torchtune.datasets import chat_dataset\\n from torchtune.models.llama3 import llama3_tokenizer\\n\\n tokenizer = llama3_tokenizer(\"/tmp/Meta-Llama-3-8B-Instruct/original/tokenizer.model\")\\n ds = chat_dataset(\\n tokenizer=tokenizer,\\n source=\"json\",\\n data_files=\"data/my_data.json\",\\n split=\"train\",\\n conversation_column=\"dialogue\",\\n conversation_style=\"sharegpt\",\\n )\\n\\n.. code-block:: yaml\\n\\n # In config\\n tokenizer:\\n _component_: torchtune.models.llama3.llama3_tokenizer\\n path: /tmp/Meta-Llama-3-8B-Instruct/original/tokenizer.model\\n\\n dataset:\\n _component_: torchtune.datasets.chat_dataset\\n source: json\\n data_files: data/my_data.json\\n split: train\\n conversation_column: dialogue\\n conversation_style: sharegpt\\n\\n.. note::\\n You can pass in any keyword argument for `load_dataset `_ into all our\\n Dataset classes and they will honor them. This is useful for common parameters\\n such as specifying the data split with :code:`split` or configuration with\\n :code:`name`\\n\\nIf you needed to add a prompt template, you would simply pass it into the tokenizer.\\nSince we\\'re fine-tuning Llama3, the tokenizer will handle all formatting for\\nus and prompt templates are optional. Other models such as Mistral\\'s :class:`~torchtune.models.mistral._tokenizer.MistralTokenizer`,\\nuse a chat template by default (:class:`~torchtune.models.mistral.MistralChatTemplate`) to format\\nall messages according to their `recommendations `_, a parameter-efficient finetuning technique,\\nand show you how you can use torchtune to finetune a Llama2 model with LoRA.\\nIf you already know what LoRA is and want to get straight to running\\nyour own LoRA finetune in torchtune, you can jump to :ref:`LoRA finetuning recipe in torchtune`.\\n\\n.. grid:: 2\\n\\n .. grid-item-card:: :octicon:`mortar-board;1em;` What you will learn\\n\\n * What LoRA is and how it saves memory during finetuning\\n * An overview of LoRA components in torchtune\\n * How to run a LoRA finetune using torchtune\\n * How to experiment with different LoRA configurations\\n\\n .. grid-item-card:: :octicon:`list-unordered;1em;` Prerequisites\\n\\n * Be familiar with :ref:`torchtune`\\n * Make sure to :ref:`install torchtune`\\n * Make sure you have downloaded the :ref:`Llama2-7B model weights`\\n\\nWhat is LoRA?\\n-------------\\n\\n`LoRA `_ is an adapter-based method for\\nparameter-efficient finetuning that adds trainable low-rank decomposition matrices to different layers of a neural network,\\nthen freezes the network's remaining parameters. LoRA is most commonly applied to\\ntransformer models, in which case it is common to add the low-rank matrices\\nto some of the linear projections in each transformer layer's self-attention.\\n\\n.. note::\\n\\n If you're unfamiliar, check out these references for the `definition of rank `_\\n and discussion of `low-rank approximations `_.\\n\\nBy finetuning with LoRA (as opposed to finetuning all model parameters),\\nyou can expect to see memory savings due to a substantial reduction in the\\nnumber of parameters with gradients. When using an optimizer with momentum,\\nlike `AdamW `_.\\nMake sure that you have first downloaded the Llama2 weights and tokenizer by following :ref:`these instructions`.\\nYou can then run the following command to perform a LoRA finetune of Llama2-7B with two GPUs (each having VRAM of at least 16GB):\\n\\n.. code-block:: bash\\n\\n tune run --nnodes 1 --nproc_per_node 2 lora_finetune_distributed --config llama2/7B_lora\\n\\n.. note::\\n Make sure to point to the location of your Llama2 weights and tokenizer. This can be done\\n either by adding :code:`checkpointer.checkpoint_files=[my_model_checkpoint_path] tokenizer_checkpoint=my_tokenizer_checkpoint_path`\\n or by directly modifying the :code:`7B_lora.yaml` file. See our \"\":ref:`config_tutorial_label`\" recipe\\n for more details on how you can easily clone and modify torchtune configs.\\n\\n.. note::\\n You can modify the value of :code:`nproc_per_node` depending on (a) the number of GPUs you have available,\\n and (b) the memory constraints of your hardware.\\n\\nThe preceding command will run a LoRA finetune with torchtune\\'s factory settings, but we may want to experiment a bit.\\nLet\\'s take a closer look at some of the :code:`lora_finetune_distributed` config.\\n\\n.. code-block:: yaml\\n\\n # Model Arguments\\n model:\\n _component_: lora_llama2_7b\\n lora_attn_modules: [\\'q_proj\\', \\'v_proj\\']\\n lora_rank: 8\\n lora_alpha: 16\\n ...\\n\\nWe see that the\\n'), TextContentItem(type='text', text='Result 5:\\nDocument_id:de2d4\\nContent: etune\\n:func:`torchtune.models.llama3.llama3_8b` with DoRA, you would use :func:`torchtune.models.llama3.lora_llama3_8b` with ``use_dora=True``:\\n\\n.. code-block:: bash\\n\\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device \\\\\\n model.use_dora=True\\n\\n.. code-block:: yaml\\n\\n model:\\n _component_: torchtune.models.lora_llama3_8b\\n use_dora: True\\n\\nSince DoRA extends LoRA, the parameters for :ref:`customizing LoRA ` are identical. You can also quantize the base model weights like in :ref:`glossary_qlora` by using ``quantize=True`` to reap\\neven more memory savings!\\n\\n.. code-block:: bash\\n\\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device \\\\\\n model.apply_lora_to_mlp=True \\\\\\n model.lora_attn_modules=[\"q_proj\",\"k_proj\",\"v_proj\"] \\\\\\n model.lora_rank=16 \\\\\\n model.lora_alpha=32 \\\\\\n model.use_dora=True \\\\\\n model.quantize_base=True\\n\\n.. code-block:: yaml\\n\\n model:\\n _component_: torchtune.models.lora_llama3_8b\\n apply_lora_to_mlp: True\\n lora_attn_modules: [\"q_proj\", \"k_proj\", \"v_proj\"]\\n lora_rank: 16\\n lora_alpha: 32\\n use_dora: True\\n quantize_base: True\\n\\n\\n.. note::\\n\\n Under the hood, we\\'ve enabled DoRA by adding the :class:`~torchtune.modules.peft.DoRALinear` module, which we swap\\n out for :class:`~torchtune.modules.peft.LoRALinear` when ``use_dora=True``.\\n\\n.. _glossary_distrib:\\n\\n\\n.. TODO\\n\\n.. Distributed\\n.. -----------\\n\\n.. .. _glossary_fsdp:\\n\\n.. Fully Sharded Data Parallel (FSDP)\\n.. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\\n\\n.. All our ``_distributed`` recipes use `FSDP `.\\n.. .. _glossary_fsdp2:\\n\\n'), TextContentItem(type='text', text='END of knowledge_search tool results.\\n')]), CompletionMessage(role='assistant', content=\"I'm ready to help. What's your first question about Torchtune?\", stop_reason=, tool_calls=[]), UserMessage(role='user', content='Tell me how to use LoRA', context=None)])_[('response_format', None), ('sampling_params', SamplingParams(strategy=TopPSamplingStrategy(type='top_p', temperature=0.0001, top_p=0.9), max_tokens=0, repetition_penalty=1.0)), ('stream', True), ('tool_config', ToolConfig(tool_choice=, tool_prompt_format=None, system_message_behavior=)), ('tool_prompt_format', None), ('tools', [ToolDefinition(tool_name='knowledge_search', description='Search for information in a database.', parameters={'query': ToolParamDefinition(param_type='string', description='The query to search for. Can be a natural language sentence or keywords.', required=True, default=None)})])]": { + "chunks": [ + { + "event": { + "delta": { + "text": "", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "start" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "[k", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "nowledge_search(query=\"using LoRA in Torchtune", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "\")]", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "parse_status": { + "__enum__": "ToolCallParseStatus", + "value": "succeeded" + }, + "tool_call": { + "arguments": { + "query": "using LoRA in Torchtune" + }, + "call_id": "8413a252-8372-4061-a4a1-0a1d165dd373", + "tool_name": "knowledge_search" + }, + "type": "tool_call" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": { + "__enum__": "StopReason", + "value": "end_of_turn" + } + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "complete" + }, + "logprobs": null, + "stop_reason": { + "__enum__": "StopReason", + "value": "end_of_turn" + } + }, + "metrics": null + } + ], + "type": "generator" + }, + "('meta-llama/Llama-3.3-70B-Instruct', [SystemMessage(role='system', content='You are a helpful assistant'), UserMessage(role='user', content='I am attaching some documentation for Torchtune. Help me answer questions I will ask next.', context=None), CompletionMessage(role='assistant', content='', stop_reason=, tool_calls=[ToolCall(call_id='', tool_name='knowledge_search', arguments={'query': 'Torchtune documentation'})]), ToolResponseMessage(role='tool', call_id='', tool_name='knowledge_search', content=[TextContentItem(type='text', text='knowledge_search tool found 5 chunks:\\nBEGIN of knowledge_search tool results.\\n'), TextContentItem(type='text', text='Result 1:\\nDocument_id:f76dc\\nContent: conversational data, :func:`~torchtune.datasets.chat_dataset` seems to be a good fit. For any\\ncustom local dataset we always need to specify ``source``, ``data_files``, and ``split`` for any dataset\\nbuilder in torchtune. For :func:`~torchtune.datasets.chat_dataset`, we additionally need to specify\\n``conversation_column`` and ``conversation_style``. Our data follows the ``\"sharegpt\"`` format, so\\nwe can specify that here. Altogether, our :func:`~torchtune.datasets.chat_dataset` call should\\nlook like so:\\n\\n.. code-block:: python\\n\\n from torchtune.datasets import chat_dataset\\n from torchtune.models.llama3 import llama3_tokenizer\\n\\n tokenizer = llama3_tokenizer(\"/tmp/Meta-Llama-3-8B-Instruct/original/tokenizer.model\")\\n ds = chat_dataset(\\n tokenizer=tokenizer,\\n source=\"json\",\\n data_files=\"data/my_data.json\",\\n split=\"train\",\\n conversation_column=\"dialogue\",\\n conversation_style=\"sharegpt\",\\n )\\n\\n.. code-block:: yaml\\n\\n # In config\\n tokenizer:\\n _component_: torchtune.models.llama3.llama3_tokenizer\\n path: /tmp/Meta-Llama-3-8B-Instruct/original/tokenizer.model\\n\\n dataset:\\n _component_: torchtune.datasets.chat_dataset\\n source: json\\n data_files: data/my_data.json\\n split: train\\n conversation_column: dialogue\\n conversation_style: sharegpt\\n\\n.. note::\\n You can pass in any keyword argument for `load_dataset `_ into all our\\n Dataset classes and they will honor them. This is useful for common parameters\\n such as specifying the data split with :code:`split` or configuration with\\n :code:`name`\\n\\nIf you needed to add a prompt template, you would simply pass it into the tokenizer.\\nSince we\\'re fine-tuning Llama3, the tokenizer will handle all formatting for\\nus and prompt templates are optional. Other models such as Mistral\\'s :class:`~torchtune.models.mistral._tokenizer.MistralTokenizer`,\\nuse a chat template by default (:class:`~torchtune.models.mistral.MistralChatTemplate`) to format\\nall messages according to their `recommendations `_, a parameter-efficient finetuning technique,\\nand show you how you can use torchtune to finetune a Llama2 model with LoRA.\\nIf you already know what LoRA is and want to get straight to running\\nyour own LoRA finetune in torchtune, you can jump to :ref:`LoRA finetuning recipe in torchtune`.\\n\\n.. grid:: 2\\n\\n .. grid-item-card:: :octicon:`mortar-board;1em;` What you will learn\\n\\n * What LoRA is and how it saves memory during finetuning\\n * An overview of LoRA components in torchtune\\n * How to run a LoRA finetune using torchtune\\n * How to experiment with different LoRA configurations\\n\\n .. grid-item-card:: :octicon:`list-unordered;1em;` Prerequisites\\n\\n * Be familiar with :ref:`torchtune`\\n * Make sure to :ref:`install torchtune`\\n * Make sure you have downloaded the :ref:`Llama2-7B model weights`\\n\\nWhat is LoRA?\\n-------------\\n\\n`LoRA `_ is an adapter-based method for\\nparameter-efficient finetuning that adds trainable low-rank decomposition matrices to different layers of a neural network,\\nthen freezes the network's remaining parameters. LoRA is most commonly applied to\\ntransformer models, in which case it is common to add the low-rank matrices\\nto some of the linear projections in each transformer layer's self-attention.\\n\\n.. note::\\n\\n If you're unfamiliar, check out these references for the `definition of rank `_\\n and discussion of `low-rank approximations `_.\\n\\nBy finetuning with LoRA (as opposed to finetuning all model parameters),\\nyou can expect to see memory savings due to a substantial reduction in the\\nnumber of parameters with gradients. When using an optimizer with momentum,\\nlike `AdamW `_.\\nMake sure that you have first downloaded the Llama2 weights and tokenizer by following :ref:`these instructions`.\\nYou can then run the following command to perform a LoRA finetune of Llama2-7B with two GPUs (each having VRAM of at least 16GB):\\n\\n.. code-block:: bash\\n\\n tune run --nnodes 1 --nproc_per_node 2 lora_finetune_distributed --config llama2/7B_lora\\n\\n.. note::\\n Make sure to point to the location of your Llama2 weights and tokenizer. This can be done\\n either by adding :code:`checkpointer.checkpoint_files=[my_model_checkpoint_path] tokenizer_checkpoint=my_tokenizer_checkpoint_path`\\n or by directly modifying the :code:`7B_lora.yaml` file. See our \"\":ref:`config_tutorial_label`\" recipe\\n for more details on how you can easily clone and modify torchtune configs.\\n\\n.. note::\\n You can modify the value of :code:`nproc_per_node` depending on (a) the number of GPUs you have available,\\n and (b) the memory constraints of your hardware.\\n\\nThe preceding command will run a LoRA finetune with torchtune\\'s factory settings, but we may want to experiment a bit.\\nLet\\'s take a closer look at some of the :code:`lora_finetune_distributed` config.\\n\\n.. code-block:: yaml\\n\\n # Model Arguments\\n model:\\n _component_: lora_llama2_7b\\n lora_attn_modules: [\\'q_proj\\', \\'v_proj\\']\\n lora_rank: 8\\n lora_alpha: 16\\n ...\\n\\nWe see that the\\n'), TextContentItem(type='text', text='Result 5:\\nDocument_id:de2d4\\nContent: etune\\n:func:`torchtune.models.llama3.llama3_8b` with DoRA, you would use :func:`torchtune.models.llama3.lora_llama3_8b` with ``use_dora=True``:\\n\\n.. code-block:: bash\\n\\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device \\\\\\n model.use_dora=True\\n\\n.. code-block:: yaml\\n\\n model:\\n _component_: torchtune.models.lora_llama3_8b\\n use_dora: True\\n\\nSince DoRA extends LoRA, the parameters for :ref:`customizing LoRA ` are identical. You can also quantize the base model weights like in :ref:`glossary_qlora` by using ``quantize=True`` to reap\\neven more memory savings!\\n\\n.. code-block:: bash\\n\\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device \\\\\\n model.apply_lora_to_mlp=True \\\\\\n model.lora_attn_modules=[\"q_proj\",\"k_proj\",\"v_proj\"] \\\\\\n model.lora_rank=16 \\\\\\n model.lora_alpha=32 \\\\\\n model.use_dora=True \\\\\\n model.quantize_base=True\\n\\n.. code-block:: yaml\\n\\n model:\\n _component_: torchtune.models.lora_llama3_8b\\n apply_lora_to_mlp: True\\n lora_attn_modules: [\"q_proj\", \"k_proj\", \"v_proj\"]\\n lora_rank: 16\\n lora_alpha: 32\\n use_dora: True\\n quantize_base: True\\n\\n\\n.. note::\\n\\n Under the hood, we\\'ve enabled DoRA by adding the :class:`~torchtune.modules.peft.DoRALinear` module, which we swap\\n out for :class:`~torchtune.modules.peft.LoRALinear` when ``use_dora=True``.\\n\\n.. _glossary_distrib:\\n\\n\\n.. TODO\\n\\n.. Distributed\\n.. -----------\\n\\n.. .. _glossary_fsdp:\\n\\n.. Fully Sharded Data Parallel (FSDP)\\n.. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\\n\\n.. All our ``_distributed`` recipes use `FSDP `.\\n.. .. _glossary_fsdp2:\\n\\n'), TextContentItem(type='text', text='END of knowledge_search tool results.\\n')])])_[('response_format', None), ('sampling_params', SamplingParams(strategy=TopPSamplingStrategy(type='top_p', temperature=0.0001, top_p=0.9), max_tokens=0, repetition_penalty=1.0)), ('stream', True), ('tool_config', ToolConfig(tool_choice=, tool_prompt_format=None, system_message_behavior=)), ('tool_prompt_format', None), ('tools', [ToolDefinition(tool_name='knowledge_search', description='Search for information in a database.', parameters={'query': ToolParamDefinition(param_type='string', description='The query to search for. Can be a natural language sentence or keywords.', required=True, default=None)})])]": { + "chunks": [ + { + "event": { + "delta": { + "text": "", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "start" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "I", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "'m ready to help. What's", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " your first question about Torchtune?", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "complete" + }, + "logprobs": null, + "stop_reason": { + "__enum__": "StopReason", + "value": "end_of_turn" + } + }, + "metrics": null + } + ], + "type": "generator" + }, "('meta-llama/Llama-3.3-70B-Instruct', [SystemMessage(role='system', content='You are a helpful assistant'), UserMessage(role='user', content='I am attaching some documentation for Torchtune. Help me answer questions I will ask next.', context=None)])_[('response_format', None), ('sampling_params', SamplingParams(strategy=TopPSamplingStrategy(type='top_p', temperature=0.0001, top_p=0.9), max_tokens=0, repetition_penalty=1.0)), ('stream', True), ('tool_config', ToolConfig(tool_choice=, tool_prompt_format=None, system_message_behavior=)), ('tool_prompt_format', None), ('tools', [ToolDefinition(tool_name='knowledge_search', description='Search for information in a database.', parameters={'query': ToolParamDefinition(param_type='string', description='The query to search for. Can be a natural language sentence or keywords.', required=True, default=None)})])]": { "chunks": [ { @@ -19945,7 +21795,7 @@ "arguments": { "query": "Torchtune documentation" }, - "call_id": "42e0a687-a52e-4208-8181-db6e7a84faeb", + "call_id": "f21015ed-e70b-4a2b-a038-9335acbe0c53", "tool_name": "knowledge_search" }, "type": "tool_call" @@ -20282,7 +22132,22 @@ { "event": { "delta": { - "text": " the standard multi-head attention.", + "text": " the standard", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " multi-head attention.", "type": "text" }, "event_type": { @@ -20350,7 +22215,7 @@ { "event": { "delta": { - "text": "nowledge_search(query=\"Llama3-8", + "text": "nowledge_search(query=\"Llama", "type": "text" }, "event_type": { @@ -20365,7 +22230,7 @@ { "event": { "delta": { - "text": "B attention type\")]", + "text": "3-8B attention type\")]", "type": "text" }, "event_type": { @@ -20388,7 +22253,7 @@ "arguments": { "query": "Llama3-8B attention type" }, - "call_id": "b3019313-870b-42e5-a2a3-02f933f153b1", + "call_id": "bf3bf9f9-0e56-4720-a6a9-be8ad9e8dfcb", "tool_name": "knowledge_search" }, "type": "tool_call" @@ -20461,7 +22326,7 @@ { "event": { "delta": { - "text": "nowledge_search(query=\"Llama3-8B attention", + "text": "nowledge_search(query=\"Llama", "type": "text" }, "event_type": { @@ -20476,7 +22341,7 @@ { "event": { "delta": { - "text": " type\")]", + "text": "3-8B attention type\")]", "type": "text" }, "event_type": { @@ -20499,7 +22364,7 @@ "arguments": { "query": "Llama3-8B attention type" }, - "call_id": "e4659511-69a4-412b-b995-fa90f43a25c7", + "call_id": "9c9a922f-afd6-4bc8-83ba-28211bb3fd29", "tool_name": "knowledge_search" }, "type": "tool_call" @@ -20739,7 +22604,7 @@ "arguments": { "query": "current CEO of Meta" }, - "call_id": "ccadcdbb-cfa1-4f69-9c60-0fc50ae35f11", + "call_id": "2039dce8-afbe-4517-bb4a-43c92dab8cff", "tool_name": { "__enum__": "BuiltinTool", "value": "brave_search" @@ -20815,7 +22680,22 @@ { "event": { "delta": { - "text": " boiling point of polyjuice is -100\u00b0C.", + "text": " boiling point of polyjuice is", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " -100\u00b0C.", "type": "text" }, "event_type": { @@ -20951,7 +22831,157 @@ { "event": { "delta": { - "text": " boiling point of polyjuice is -100 degrees Celsius.", + "text": " provided function \"get_boiling_point\" is", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " not sufficient to", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " answer the question as it does not contain information", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " about the boiling point of \"poly", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "juice\". Polyjuice is not a", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " real liquid and does", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " not have a known boiling point. If you", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " have any other questions or need", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " information about a different liquid,", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " I would be happy to try and", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " assist you.", "type": "text" }, "event_type": { @@ -21019,7 +23049,7 @@ { "event": { "delta": { - "text": "get_boiling_point(liquid_name='polyjuice", + "text": "get", "type": "text" }, "event_type": { @@ -21034,7 +23064,22 @@ { "event": { "delta": { - "text": "', celcius=True)]", + "text": "_boiling_point(liquid", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "_name='polyjuice', celcius=True)]", "type": "text" }, "event_type": { @@ -21058,7 +23103,7 @@ "celcius": true, "liquid_name": "polyjuice" }, - "call_id": "cbea2158-ad0a-4faf-a2ec-3e411bd5aa50", + "call_id": "302993c2-3c56-48cf-8891-afac1f20723e", "tool_name": "get_boiling_point" }, "type": "tool_call" @@ -21170,7 +23215,7 @@ "celcius": true, "liquid_name": "polyjuice" }, - "call_id": "ac3bf39b-16e7-46e9-a243-130939094e24", + "call_id": "9544e61b-5e69-427b-b30c-874fdbcf53f7", "tool_name": "get_boiling_point" }, "type": "tool_call" @@ -21273,7 +23318,7 @@ { "event": { "delta": { - "text": "'s not a real substance, it doesn't have a boiling point", + "text": "'s not a real substance, it doesn", "type": "text" }, "event_type": { @@ -21288,7 +23333,7 @@ { "event": { "delta": { - "text": ". Polyjuice Potion is a magical concoction", + "text": "'t have a boiling point. Polyjuice Potion is", "type": "text" }, "event_type": { @@ -21303,7 +23348,7 @@ { "event": { "delta": { - "text": " that allows the drinker to assume the form and", + "text": " a magical concoction that allows the drinker to assume the", "type": "text" }, "event_type": { @@ -21318,7 +23363,7 @@ { "event": { "delta": { - "text": " appearance of another person, but", + "text": " form and appearance of another person, but it's not", "type": "text" }, "event_type": { @@ -21333,7 +23378,7 @@ { "event": { "delta": { - "text": " it's not a physical substance that can", + "text": " a physical substance that can be measured or analyzed in the same", "type": "text" }, "event_type": { @@ -21348,7 +23393,7 @@ { "event": { "delta": { - "text": " be measured or analyzed in the same way as real-world", + "text": " way as real-world chemicals.\n\nIf", "type": "text" }, "event_type": { @@ -21363,7 +23408,7 @@ { "event": { "delta": { - "text": " chemicals.\n\nIf you have any other questions or if there", + "text": " you have any other questions or if there's anything else I can help you", "type": "text" }, "event_type": { @@ -21378,22 +23423,7 @@ { "event": { "delta": { - "text": "'s anything else I can help you with, feel free to ask", - "type": "text" - }, - "event_type": { - "__enum__": "ChatCompletionResponseEventType", - "value": "progress" - }, - "logprobs": null, - "stop_reason": null - }, - "metrics": null - }, - { - "event": { - "delta": { - "text": "!", + "text": " with, feel free to ask!", "type": "text" }, "event_type": { @@ -21500,7 +23530,7 @@ "celcius": true, "liquid_name": "polyjuice" }, - "call_id": "fc32cf9f-db3f-42a8-baad-da88903b53be", + "call_id": "ce595f0c-86f3-4055-b675-09e00007dc97", "tool_name": "get_boiling_point" }, "type": "tool_call" @@ -21656,7 +23686,7 @@ { "event": { "delta": { - "text": " 100th prime number is ", + "text": " 100th prime number is 541", "type": "text" }, "event_type": { @@ -21671,7 +23701,7 @@ { "event": { "delta": { - "text": "541.", + "text": ".", "type": "text" }, "event_type": { @@ -21766,7 +23796,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": "\n if n <= 3:\n return True", + "tool_call": "\n if n <=", "type": "tool_call" }, "event_type": { @@ -21785,7 +23815,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": "\n if n % 2 == 0 or n %", + "tool_call": " ", "type": "tool_call" }, "event_type": { @@ -21804,7 +23834,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": " 3 == 0:\n ", + "tool_call": "3:\n return True\n if n % 2 == 0", "type": "tool_call" }, "event_type": { @@ -21823,7 +23853,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": " return False\n i", + "tool_call": " or n % 3 == 0:\n return False\n i", "type": "tool_call" }, "event_type": { @@ -21842,7 +23872,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": " = 5\n while i * i <= n:\n if n", + "tool_call": " = 5\n while i * i <=", "type": "tool_call" }, "event_type": { @@ -21861,7 +23891,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": " % i == 0 or n % (i + 2) ==", + "tool_call": " n:\n if n % i == 0 or n % (i", "type": "tool_call" }, "event_type": { @@ -21880,7 +23910,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": " 0:\n return False\n i +=", + "tool_call": " + 2) == 0:\n return False\n i +=", "type": "tool_call" }, "event_type": { @@ -21899,7 +23929,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": " 6\n return", + "tool_call": " 6\n return True\n\ndef nth_prime(n):\n count =", "type": "tool_call" }, "event_type": { @@ -21918,7 +23948,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": " True\n\ndef nth_prime(n):\n count = ", + "tool_call": " 0\n num = 2\n while True:\n if", "type": "tool_call" }, "event_type": { @@ -21937,45 +23967,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": "0\n num = 2\n ", - "type": "tool_call" - }, - "event_type": { - "__enum__": "ChatCompletionResponseEventType", - "value": "progress" - }, - "logprobs": null, - "stop_reason": null - }, - "metrics": null - }, - { - "event": { - "delta": { - "parse_status": { - "__enum__": "ToolCallParseStatus", - "value": "in_progress" - }, - "tool_call": " while True:\n if is_prime(num):\n ", - "type": "tool_call" - }, - "event_type": { - "__enum__": "ChatCompletionResponseEventType", - "value": "progress" - }, - "logprobs": null, - "stop_reason": null - }, - "metrics": null - }, - { - "event": { - "delta": { - "parse_status": { - "__enum__": "ToolCallParseStatus", - "value": "in_progress" - }, - "tool_call": " count += 1\n if count == n", + "tool_call": " is_prime(num):\n count += 1\n if count == n", "type": "tool_call" }, "event_type": { @@ -22036,7 +24028,7 @@ "arguments": { "code": "def is_prime(n):\n if n <= 1:\n return False\n if n <= 3:\n return True\n if n % 2 == 0 or n % 3 == 0:\n return False\n i = 5\n while i * i <= n:\n if n % i == 0 or n % (i + 2) == 0:\n return False\n i += 6\n return True\n\ndef nth_prime(n):\n count = 0\n num = 2\n while True:\n if is_prime(num):\n count += 1\n if count == n:\n return num\n num += 1\n\nprint(nth_prime(100))" }, - "call_id": "11645d4d-35d0-4542-bc8d-d01ed1758163", + "call_id": "63d06ce7-5266-4ee8-a620-0e81cf5108a1", "tool_name": { "__enum__": "BuiltinTool", "value": "code_interpreter" @@ -22112,7 +24104,22 @@ { "event": { "delta": { - "text": "plexity the company was founded in 2022.", + "text": "plexity the company was founded in 202", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "2.", "type": "text" }, "event_type": { @@ -22218,7 +24225,7 @@ "arguments": { "query": "Perplexity the company founding date" }, - "call_id": "42bca45b-e3d6-40a8-b110-d9d77328089e", + "call_id": "3804eaba-07f8-448c-8dd4-8ee14d748a05", "tool_name": "knowledge_search" }, "type": "tool_call" @@ -22306,7 +24313,7 @@ { "event": { "delta": { - "text": " the merger of the Basketball Association of America (BAA) and the National", + "text": " the merger of the Basketball", "type": "text" }, "event_type": { @@ -22321,7 +24328,22 @@ { "event": { "delta": { - "text": " Basketball League (NBL).", + "text": " Association of America (BAA) and the National Basketball League (NBL", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": ").", "type": "text" }, "event_type": { @@ -22412,7 +24434,7 @@ "arguments": { "query": "NBA creation date" }, - "call_id": "bc879653-70ed-4c38-8a7f-fa8a4621b088", + "call_id": "d94006c1-5692-4ada-8f1a-d09ef2d46dab", "tool_name": "knowledge_search" }, "type": "tool_call" diff --git a/tests/integration/fixtures/recorded_responses/chat_completion.pickle b/tests/integration/fixtures/recorded_responses/chat_completion.pickle index 4abc0c17e7d9e44535052c241befdb72a42fa952..c4f1c7efdc966d90b11b6df1c5f7d19982624c80 100644 GIT binary patch literal 620451 zcmeFa+ixVtb6MciVC(tJ;~An90oKoi3J!b?c^F#V%E`Rg#OPWMst2 zj3`D%WJg4j#cuavgoT6!Ouz#S{p5XEV4nOSXa-n4EZ}{aKR`3aVDun82o@H*PmA3@ zU?2APedok2FT8YJf~<~esVXxv;>35(`ObH~+xdO}_O*Zb!JmBU75ekhQRRm_pMK?) zO1UROz3Mo6PoKR_e^=*fjq38X>V_MH{=f*!Gup%Z2SF%$cSI2AT~YBpN34|tzJ^~7 z&kcneu9bh}4K&>snyy*G>30T>rU!u?gt{A+r)RYH0^w(y7~o2}fw%2Fq4lVN01XP) z5L#&IA-_Sl-2mT&w(t4oD!sw+qGz9kYnz@crXNkW9#+b}2>PBIh*rn*dpgn2Kh9{C za-jG6j_r0^ecji40e-r#uH5Ad6?9n-MfYHB%j@5be!H(OR>FfmIv#rcRv(XIMEU}^ z4}7s!uhr}I2CmU>__l)n_Vg#M(AyPmuvVYZe9;%79onAT>I+wQ!h^L&tv-$WKvw7r zy@w{Z{DI&rq31a*3~a~l(q(+R&R;6>2g|b!v37;8^XHmA2)$LUO#hUx5*>KH?|Z#| zsD^<@XhxH>*6PWrY_)}@@7bQeb|o{#*VN^j-UqQ5?y~$)zA6bGZ5~v{qfEcj*gkwT z{pbjccK8|%+|l9Zy27Oa^ZcX3KQOF;yBi!m!q1nP`&wWWV;66w)WVwL{g;h&^_@B8*1_??~`v=2Y)cwO*Jo5tz$0kJYhHt<~h zXkFg4-l7KHw7&Z9tTOISE`3Q}us$cpo`=l(;->W_>nrIiU$wq|_*pdH#rh0*V9?k% z(|5dTmC&UkiG+BTP+qO)b!EQ!BB+ zDPdu;5bF3g)`fGR;dVbSazCRPj_`MD&wI2mZ(vkfc4G3pS(nDo+2PkD*Y`ZEf}m#V zp-$@vY(8}#EOt+F7*@>ZF`zB4(}Fy8`87#TWYO*jWcC_=kqtT9gLv(DHcXGKKyLu0M z@wI{NgtkjJ)Y`tjCm?l+3$S;lztZMxioo#gK5b%agCAH`!P4`C zwGYeh4}^bEUS*AdRhASnd?W86P|mR5xuiN|-UZ33aSJ5IBzYQMh1-1b{=oKyxkefY zJ=M_%j?$_=f?mb@xb>>_n)Nz%?2|?P8)F6RBpH#B>mPrAA*udnhkr;@a9wvWPqga} z@1UO}?WASk_ap14)}_NQVA!B5V!I9p!4aPSyS^M;T>I=L$c|o*3TyG zP*2yBpJcbjpISdX%rI7s`cUENTq}(cC#C5l>u1*gbohB28fSXjP2}n^v`-eeCr>`j z!zlHZaroJ2XtT3&_!;U-%QlY=FSi%;Ib(UDSv4B?YkqEJsoJhL%&O6;w-**ny)nO7 zhla$HNDJ=>&3-<$_DJ{oLVCgRbRB+9_q&501a1I@@bGmWwWGs79y4r5K{7r+w|;5; zLd`A><>!KdVF+QKzyy|+G;!S4b@E95_)N>_wC}~1x%?+D?Up&CB{o9V+)S*|l+g;| zmr`|M2gOQBEv1k^il@HC78dbsu=X%w>x$yzwepqs-rKlw6>Z0idZryB=GK(RFOOl? zGRbCXA4cX-w#)Q-Q1PtjQijS}`NI+~q0*{0R`kqhB{Cm&@%zIMOE7yKLATy~B8))@ zBR|lptn!p_X6aEy4n2NH z_jk3w85q05ZwtRWquufbt|@$QgQeT>1Gub)UAJt}(PBEZcRL+e(!TaRPdM6N>wQOe z=?S{&ZO3ctj<(+E;Q1iF^Zp<}Tet1#wp+HVyM~QBs4w61EEkV-1tuVR!#%R52O@sKx~ccHJ6-^15Joj> zpWIJ+7hW3eCR7>iW;bczE?KQc+}RoJuIJeJe#bUorD=F~7{>E6db1klbw@nW?!yh? zgdaqt5f{O^keVej0Do|oI=l|2%>hj90LoWSTX$?&#tFH%bVIZ~Z&%y24bRcR-QYea zK=+e-6h~bf1hxwsSbN*|27PVa>S09Jo$3wUa-e(RZS>M;9Nrf0`i2H47@G*hr;gC> zq5*w?d%?WuuLx|Dj0vK0LxUuc_D8yzTk9M5qE=|>1P1I@ES!36xv^4TS!v>$ukVx3 ziJW=(#T_`#M>AS#`99?ud+H_M!|YT)h}ZZt76E@NN0^8C`vVb#+CBZCdJT)6FY#aR zc)tCCr>?9WQs`h||QL=U|@$#TYw9 zX&4LXnw;SbcXb^oCnAWhK?y;xf=G6y48r?^eji)_dJIeztUPoa`$E00uh66{@aSh3 z_!6z}mFCJRXlCmWKwgUyELNSIwQ zW?SFi->(^N+u%)|2%W7rXB+dg$#M>=U_&dU38~VXje}}n*`2Uzfpe-fsnzH`RYge^ zOyY=|751EAb%0hN`BsLO2X#v~XliKk;qLQ&FulG9*4ej1>9Xm^@)W*tp}}Dd^~KcS z?RUHbA%Yo9cc}G+hj-&yFs!Ys$1SWr(E%f3WC92RaD*@To#d*+U9ihJzEB&QqNT_gvFssFVC)~bCQr=9 z_n~l!u!{Dpv947$0&2esHKJGbI&vyHYQGy6!tdz*9xbW&Tr4N7DJ+tNQ0&aKqeHe} z`DtTry$(r;WuUENmNbLaF!)-Oe&s1$O?45m8>NbA9xr!1N8{3gwx={D$OL{G%NXk( zBx9;VS~1iWn*UuP`WmLh*rkD^r^(T&y9aRt)HDgOgbWL7KeTGv7TwJxda-UdLgM$b zy5M9&+mTX0q|J~E$k)Lv5S9op%`p8Q=<{O{T7yEu`eC9Cl9mrfg{BCb2Er8`g&dbO zCgKM@l{#;vQ_$FeZ^88xHnZEr)mRVUSCgdX$e6C*oBhE(Y#PwW><@HWOEb_pq(Ho_ zw}Y563vbt<14&|dQxPt98Uc}whD|t}u$@3?d(jL+a*~aX*qPUc{~iChP{*Q|@Fc?g z)^rmMgKD%db+hO~Jc>}{Lv#YHhQ_HUTI$X06|=h_TaR=)Il^jtV)j5cXd%UnU{rY( zNY)`Pf%c98PBsjX1CmT;d)i1MQ)fn_5F7f7odJ7Jc9)?IBAJ?*h+k(wGxT&x6|rAW ze~f{$T@&#MlKI2(W3k?xZ>*e3d_XW_OahAQX;44$`SRj|hT(Q-!wN}+9gwKP4}EVR z90xt8>tP;eQudWrt1$^f#v4g_Uku1u$?_!W8srKDxb1=|!|I@4U0kTP9k*&A+y@Z^ zVMFxT#Ox40c2Fe}swB9o^+vThKP+Zg#@&r4nd~;6YS}IDMQ;Gz2LDd%8{Wu_Py5-% z$a)*Ib;vjnhUk`WoB9Ff#_sX@@U%AKo#=B$fbjka`A37QcPV-uYGk)KFeTB~^^Kt& zU~Z)`Utd@nKZTDzDi^`+a~9ktr%%fJ{_z|=8Tb4J3I&`H($9D{566Vx(~;q9c>Rqi zT%L^$|0)W7|1KRw_?>jlo+@(vTkALS?!-C!YvtR`M6Un)ruFM=%o5z(dz zM1PkYv*d0mg1r|x*h>u2vN4T53`hKpP{Ht}k)W?Mi6k?D3pjEcg?Q=Vr;6}0hk_*) zgQESHCb~N&s(1-O&c91U`Y|ERXC96%!*a&*MsyX6y5df+PHFgKcQjYKvZgiUS6rbu z>_480#AhFMJ*;E)DWwL^Iwuer3g==9qkAa&pDVR*CIr5vHMO-htqw~Q1NxRWmn&hj zOv}iCr3O`7(-xR|_*I>pM^Ur2Z{z>qLN_6q8S|}NNAW8lDm|waJ6CdMwC`xm>7kjW zH9WFp@?OO>o8MW}7MZ~mb+lNgrbq_CE8B8IOA4Y~NA#Pq7-aV})&0J~w zH_7VcMC;7TNW}P{rvy1M0{xLa!RY5o{jCO*FG=EEMvZW0jYmH#7QwK`Ptg>7XD!!0 z{JGYcn!;}BhLsG1?Z?A6^!sSr_xodbQDME?4L0+oIZD6piZq z;!@KT#!6$+Tt2dXVg0AWFAr;bGDr58$TND4emeT$|A8YHr&JY2B~PSIjNhzzcBNn+ z-Y$p4+K5PlBu;Nw$7~rRLi;RY^Ynu2c+v5+i}%?qpW_*LV(QpGPtyL<_V77P6$?Le z&QismyB&^fkoc5IHl6AmWsnU^oe5@VI+KhZfn_;jwrsn!ZA5~mu`0jQwY1R4-ZeLR z7wIFZn@03^DUgnBoJ5kmftBdAOiG?p;%-=zObMmr-tnEFt5Tnmccv7oZFd`a3_~gv zNhWz`tkuY`O0AJ!B*`=isj&gES=B<`OBB$bShr|ouj8@Q_MZKXo=f)kZ^!!KL?iNC@qD^7gO3$M}i7?2uNdZj_nGvBJ zew^GB8e-&#nO(tgl7SL) z%x!vzEm8{_B@vs*(T|@lgRogeS*eJ+T*#=)DVZ`8eJOl$@gcucpXi%#j_y_DMm+CB zX%k-kHEq<<4hftSHLq(6^Nn-}=DD0^d~T-%ZoPKSRKItSPDKF~BnJh1l-BNYE~Q+@ zZHmQ=1Xa$G9S>LegfQ+Y1xmEbJ){%7*JUd02F{5`C&zJ>-a!$c@+CeHPx(B1$lgWv z2x3Usk93?c!Kr!5!hsK;GDVT6Q@XNs^UmGYt&Q6^ua>r5I%rRQ$N71v3EA)iJ>_^v zc;V~@7YPwa!L-8~B@h(nW@|s?jm-DYFB6t#2aZOE+5($d%G;u4KKA%+uLUt|a`4hjdy$m^D6_ z-8--=BApP~dbv{b)f(1OX&Q_Cp0^(;UwJ84lKyg&vsEZT+6PUnSKx@# zpoff0%3ehpG)aS8Y5c}2vMJ3@EwJ>ypwYW737pE6s<)&Urlg38Qp{=Oq zOon1PUy(PXY0l3#8_QK8bi~{0%VxDbHwQofbGf;&G%uR%d1P1o;_<&As%9a|_V~Zy z!w>&Q{54ryny9a^#xQQr9@#a=>|4V-$5`2YI_Wt{ew|8!oMsK5eHERFk7G`HDMMiY z^LYz_6@HMX@`JqW0lqPUaNCu3BTGVrxJFF3w1;V$?j{8^3M7?2h7_YVl+=lvIYtUW z6UxZ37hmZo5$vASY_RG3qjt zrbkZnR1;?zn>?E7;Uu&Rgb48jaL+YuYHG_<$b;>?0>Mpr8aLSEu-Xhq(s1&e5lU3d zjqd;&1R;7*>@BC^T*CPu91Wv`@C;voRS3ij;dFqw(vcBBL_G-~po<`(;}IZ7j^qOO zg`$#C{E=whp@3tH{8~F&XW%lvhQ>)b{A*6*x-c9#+tC~wI5j~0h+?GCfD_9qn<^(_ z=iyhy@*y;G0P=J+%iE8K+4R5=t5Z`uJ3CVu)jlU$7gQvQXLxv!qvWfYC8nZ?RX$rv zE#>=(X{wZCcRxw6@-z{7mlD%+8qy^#81#T|#n4B@m9&_Y7ZFwsFh|S^{Ik*>gbRcS zL>F=*_q#D6QR)Q|L;N|lMF0}}gc(Ppoe{zuI^ZXBBKxnEg!PeP*a5U2#WR58FmCK6 z^hN+IaJ7*Et`}fHKp+aS#SxZ#KJ5Hm5>nLVbAn`~_BP&LWHO1L z6WM=32|K)N5&fgvT25rGU<`X6PIc3MdMX_u+N*OS`0A*R5VOMsttO(Fp3I5r6&_!u z)yS2#A!P(|wh*%GCrE0fT0}Ah59CDfr!H>J-v2uFGUV*N+y^i+N}N=t$X|JzHcZ<1 z3;!&FPZMLNg@5+r9c4IU)MFzY?;uJC3Pvn{I(w3`{WI#{nfBMweJ-Um_yeFDGc+A^ zO)@|z5k)5t1Y_`yF;EA}WYl`4-y`%8*H(qzhEG zi*eH!9XB$EQtyj21Xvx(laU3L=;#VwH)#N4#2gyiC`^aqwMo=68sh|-l$oGxw~242 zx-L(RGEYeFC)ZHB>%b33__wIk#z206(~XT?;v2yK5e5;VZ40W>RX`A(;|gk@uo%v- ztp8&D*O3A<;}F^2I1}tx2953MVBj(kM88s%Na&#A(c=M*%Zyf(Nx+HthR1ujOX1Fq z0L48^(&XESro+D)vmr#DM2K4Kgdsemwf+HpVtv#JW49d>oWd_Uxff3hcb6UFR6o9* z^5v!T&a*ogd-IOY5!rLdg8=X;PNZVDHYGBhGW*<~s#7_<*0Vl16F!b&g(NTkL=CbZf56EpQ?;9fzO{PmV z8QKS_j@Hgo4=$Twji7O-A0|9seuQ!Y^>n(MDTag+QwAh32P{63Y6ap{t4_4 z#2T<)W){h{?VKyR*J~sTDMO<1eJY74H18>e4b`u-h)u2!RJyu zmGZjM4}Sz!f_}IWtpRn{6Gv|gY-qGqoe#LYRrDP&eU)=H#FwHm9Ujas;G!#p z3V~?NIT}%BhX7&5%JexRD}%$7t_!!^Fqib@rMc?d(qbER;g&^}Fqo?5!u-O#SQKV` zg(?ik$9Io7KYXa}o5ExI66#(*g+_FGCFEo5`%kmgeyrW?G#knpWcX8y&5t9g#tMg1 ztVfcFY6&EH>yJyXzw*lCx9G3S_)Dtla^WU0PGgneG?>$I;KmtrY-^l#^V~p{|IaTL z(Sa9I;BPoBV#1;AaqvuIMAJ#Wy9_=+k-d!*Skp!J_Sv$xi|9ZR9XKZbSVRX>IYa4K z#wRH{a7G#NEP@{70KX3J>gh}Ce*B%cGIzrU@mjZpwTbPT)q7Tn^-<-9H+K2vxC6wT+CV8Kko(UnKE=!9_WrRCOFf zqUDW}mQ+rX^E)VNlGB*hIq{vcP!7hD77b$@ipq)3>op!fo?&JH+VgnuAPo`Q!>mW7 z(r9K9OQ^Cb-I^2WSC|KbTAU0`xnQ6NM;j@bDmwTzK4U&7n&-;LX6nZoVW_8yBC6QQ z@{(S}g}sZ0x$U7^HIiKW9*(7v>_t)ZgU18g5F;43 z1+MD_!F4TD*&8*nEuL7gPX@U49v5qyzyUb@Yrj9RQLfw7t_#Po2LT-$zNK4`8kVq$ zRWr2&N#rEOSJ!*6|H36|SPky3>Y zMi)df1Zirx9vcm5M;|!h8e4B4Vd;@wc0-^@C)<0{W}|+sUAZ=}ozOqrU53skJvx&UU-q?|wNk_^3`gDlE#eOMy6ywa*xiVnF`4R2y2x`w5F zjuI&jSF&=3C{08I=>4#i5)MRvyuF;KUc6fR2nc`YCJ!l-p2CR&hnL$6oyE@l(n7V< z5N35ASt-?(m4y``7cPjUrlHr3hIz!P1czT45&uV=Xn;~-pHIyO@>r6|_=F@TeB%#Z z4pr>DhDgS09_j3Z6#r3;sF(qtMI3$X%VVv%ii#anouKuwQijK-@410!$wNTc+BZE{ zNS7>OV?ZHpu^6M1EBDovySlIUf(o>CxU0GcYg=CbZuDE>Db~t3U=8<8`Koknv%eZ= z#e4m5%qY{ZG`0^XYD{A%v(RBNW|=`KblB{8kR|c{KuGW%sbXtbXf?<76hz%EG>bNhU#J#=1LlBJVrw zW}$;nbO2XEo9WG_p#FMdSNK? zih6uj9WlMQ?!n71&OHbh|Gs`eK`YXKOcfZwUQ7q79O6JsHBF|r4;NugJDof6Z6Q6j zW7n4C@qHW6b2t(ly^2mMvu1`8RjhgydRgIHEPRW;FxSTW7B7%~ashm7mrwMu!L402wmh~V@EQXt1TxIX=1DJKs|^@Lz-HvX9t zk=jW*VNP`YQ7Yc6)W4i4`7&j(klNYNoq+YuSkJPao4a(PCG=0zKVfh47vOSM@mT&9}Q{Y^iBX6=2lw(&D-|;wJVu(B-hmCnoQ6_<3*;{OK{rY0y%Uh+QH{1>;9X^ zM+DDPG;MAq&FUoYk5)QQ^nW2v`aS>Qzd6y+n}%sr=NFB+>U^h3;XgyKE-%e@OrbZH z>UHBpugv7=-zOyNzVhONea}@jdHF2=kC6B(kFDKPDe>9Er=)sNsur@tTDG}XzVhCC z8#k`v3hN|%v~8>lr^vc@u1kEDNRcaay5a937(T zTL%H3SPKSi0!Bjla&-hLb4V#C!kcj!P%ghoJS-8!aB>w@-*Ga1M%yTxTB>YyPL%!u zLrh)VpxD0_+SEnVrpEe|iZB=_9|#=J4Awp@XOT3v;Hcx7o{*~m)Czd*GSC5ZRQ}?F zZWUoL>#e^BaKW!tvCq$?QcEYMYD@~q9bUMDahFeXFz!4>zrM;ac^M?E^B)GAU#S~N zNp4n~dIMoFAsW>cF}GA*YBV}}+iV-g@^TRdL#^P+HEG4*hi?>NFwaGD%JZs>HCAgl zRWflA1_LC-GcQvxc0LL%uF&Gd2z2TN(&ENAB619T{rR!*OF4NB7Rkc}*rziFzH*{= zNx?7a@F*JOeTngxw6Q=(7e2)FkLS%PLJ;Ue=gJS{yd{U7sr#nZ1GutXwdf~8C30zU zW*C|%`L5CVOwII=#m%tlbHG&B20?*dP96c3gF?_kl=h2%E~i21#8-M-6c1z4o^xr z@JVv$Zg+reY)A10O5LHn^5Tk}C8zG}$ksc~>2w$~cvtEA$yFO#j ze{s|LlJ%9eh5uFS4eL!SvnRc3mGIxC#3x@;u7S#?HNBZ!e$)D@{2{sYrEyM#aW9?6 zOEXS{SFNAozf0E7tOP7lUVT_UK7n_br%E$Np!FYI5ZFsqW67+~byntu zzBGSi{o?S;!xMjG{Sr9Xuk&yp9eyJo?Vgvok_3WamG(X}iO`iQOUXu86j*@+2mGCWmy#5D{hXKHL&d z!s{OGW8nr0(?oR;aTTP7_-Cy={J6w;?05qN=NB}?8o0Z`>b86B=Gz;aRNiC!{Q#td zt{2p{T}t3S#cPqSj0dy^n!e!~C>Q01NKjsN2fb=z+f_8LYTBH3#R|iIusS>IP}Q9p zmEozOyruj)cXg*F!||@z*E)L7M!7Li+4D@ql(APk0?Gs;u?N~6JgBX2$f!7~wfd+< z7H9+DXmW5I6(Ly_;T^xjmw4Kms?}{bX;wFUFCbji9fZ-LD&Uu-C{r6sgVodh-5?>| z8g#qRN;KW}ln_x>ZK-|@fotk6%)1cEq;Esv*{9ID;{avZpgJ*f zH1GtqCC3r3hW?~p2rCOC-2-)C4(fdX{VCiR!j<}av$`bT#&2hBUiJYqz3o=BN`9d2 zbbW8oM@MLQi;!Q6V*qRy7$zunB786j@ZrOei&S;LHbRpB*cO5E7Pc5*Z zkqh%3DRFT!93oevifb(7q6&{4kJ6%sUmHNkOZm6sb>K`Q@yL?2PX^(*Rh5$D4sB0! zvu(#~&yskYy?1l{#+{qBo=J-pW7s8`nG9)6aBbVymohj(FiqAD>LqwM++La6EI zYw5nAArvN-ecWN89FsM)$pmr|gIQV17)0Pj^k1#UwfU-`)Yx5JCGN85x`sbA?#Y;@ zdPl<$?Ni%s=~SD1Bq!#^$ccJtlV9D5XHiZwHYu3#UW=Kl zmO!ZwS_jca#O^+BqM0!5=@_+Ir8c*~MCy6887hWS7C$Y>pf3y?oB`!Yy?funbjUgx z5hG*!uB!ce+hv}tY4>eXENISC4etXwKH2LPnm29Evc32vGn(CDp4dl;KR`BknYuJfp#Ogw(1Q-ZrNHmI2`oqe_e?&|4K%Y1P7f%GdocGs2tWez8q>6%#a zM65yXADWF@s6N84O;)3t963JQcuLJe7v=6!E0nn*AW9tav)unBVo1~SwkX}PkaiO#UXGrZVnfTG2A zCAj)0uh3^Q+KkA+@zNKxVSR`>(PXGuW^MQxTy+~hXe)1u3 zY|Ic;PiWBbYqcx00f^pqd5q?gWxGRlel672!<5GI>FFi~n*M3!PFd+E^C!ri?bG%0 z%HIl)jFZ3Ru5N)P;(3NPZo|enNR&J|KN#2p$p}U`&>h@>bqbTjOm1W?9!z9M!-u5O z+alb?p0=+$yOHuupCIf`@P2M)7`k=-Fg9d4wEK=G)oV~-sB*!O6~K!?O3(Q1k}J@`|| z#{vi%{5{mT8n-_Sp{VLW->F06kNOhhg2R!f<= zIiefOF(FA!6BY%%msTK=gO*2C-1Icbm~hmu8jHA~=8*Q@)ZiEL{7{qMT1#!18J@4V z;_q^%FKJW`){Inx==F3CfJa0ccr>$QxwWJeT}xW6!0M)7FR{Q?RcN73u+vq9 zal{A<9S;P;=~UBETT;x(=i~9~Ni};|dY@MPV}dW)jX&*0pGaJlFfIK-C@(#VUL%_V zkgG?Xmb}#B9*175=kz(WM*1RiS^SG^Oa2HR$+Dn4fPu_4N_YCse&?FC_vr#1U{`mNDQz`R zz07ZJ-XO|P_PQeQSd>OA0_3Y)!}^4i1lR?04UqrCE3bU&75YOJ`z}DFd^9|NIFvFr zF+~3~VMGejk9l=7ASP?|o1_FPDKZZX$C zcyZ<3P6vKO&aoofihbNIii$Yl!CIqMmt||AH4424>9&R1C0r1g6PBg+NtY?Bid9ir z(gOMnydP^@Y^djgQlR22Kh(Y;X%f|9z zXHLvl8*`0jb$)qask+?O_3BDPH0RnKb8b#A^1C+W(NC4NiTtkWn?-&XVSmVSwhU1iWnd@HUcNO_vaSS0&?y@msi4P1lQy^n7z@B#PqCn~RZtzMMc&6e6NLh|x7FT5ZU0fy35Khan#V?y$u zy8R+TwPRlVRvbd+gB_VfvBW{26LEi)c6)Qa?r~sJ=|kAnrJP9q^tFqd-1fh`dfo!g zd|WLIk%CUgZ>T^(oVdhC2RQS6D^B0naFVT$TqYQU!9I>kL-0rhejEVdqFnI0PsSomO-Ywq1Z|g*Y1tY!%fwop8jlOWoPm4{%;x@PSJO zByynb>;!;#F~rW!3_jCqS{)n54CyK1|-WyR(xXua@CCgB~s_+A_Zd;emsG05k-cHAE#yPKuB1?34lv zC+oZYuq1nfbu-BhWL+>DkFh*dS1%4Y)<#b0P{7|d%G;;~ZQ7K#94A5wr z+={$Tzs2uei$A4~qD!7!D?LVnZTg6M!k=p;`aIh^;H6O;zLA-Bt;FyO=>{?kBbf;; z0cXkU4#dP8nX}ds{!x@hr)~*ZBStei(0fiaxR;P)Q<8H``@nf`qDMFy$bQ5B z;7=oFkEK1_K3p03HLVaXd32CP$^N#Y+Xb zClb7BUu>6wj6$FS5zL89=R#lreTW}W)CP?xoWGFuj3|eX+b&=xX)K3`l8`Kf zNkw~+f}T?GOrWC4al3OzsSd2y+C7n_@AXtzRM}ek~06ip>8gGYd$NWKhC(ZYkgtbxWS&Z{R z5E9$&F^{g1AmF7T(Ye?ihm2;-B*V(Ify|)oFcQV2Wbj6P5$J@A%LMibeJEK@Rlyl! z5Zla;3UwzGhUMCD0b+KE!=M1{^Sh#dNe0oh$AX?GON|KHSN&r?k}HwO!wOLAN_TMR z#Dweu!o93xz~p1;)9WI1HfSt3p#qr-=sJ3V!V=nc(QTlv?F0IgKv|-h$S81fX%d}} z2faQ$y$WHrDu+ouK`aEuu~9c6t@~YJfC>3S1e6ETSr~VHfa|Vmz@3nC1MEPTsx~;E zG12hjst4>v2%6O$91I1NWVP)9EbXrvqW4!j+5=L`XxexdfvW4HCE1pyeOvyV9t#?A zNV5PKJb^lDs+j|V=8yV~kID1vu11hydp59T3GI=_C*GNP%ZR5edFUO96@%fWsmlzh zLY0j6^O0x769hL2n^Otg1gA#5It^A6b@cc_b0Br918fS=$wf45cYS<$e_#WWQy?oN zq2n3^DWMhHx-S_`PIKJLE75R7GnqVkCx(fPxr2@hkgQ1_S67aEnr4$Rk|Oj)+A$!= z6~i$g4uScq)gX}=uS7RXOq`^B00t3@U@6cDes?GXg}N?z_%utM5uGuqrrrmZYL!5A zP)vk(a1yORWYT@?c=X$NIY5+P=Yyd}nvLGZMg+LeD$tsDA>Wy?BuFY@>i9SS&L&;L z1QB!$q01QrMBhP^Q8{MV0df;VN-zKt8M=q?5NR!;1*KJB-f3T_cgNj|I)cU!b)~S00=$us zIJDb7281AiFHzGhhSRU*E~5)0_&6D5PI94?hNKJ(+=z=2U9p6*3-t*y&k`UxR>CBr z5mCFtm_%%D5_voyF+&Kqwr}r3szKRgyl470dk=Hgs>n{Xbf+uYzCO(WjigwT*fs3{ zMt1}h3k_0DH1L6Z?+FktWv5Sg&u#TsEAtp$R3qNKc90TV$n9ZQ6e~=FduY{>cqa)2fK!?*z(~r&_#`gDJV3RTNWahtW%=unkZ2)QBswljeZu$y zT6!BCgONP73)0zr==iis*XOys`KHiouC4W}oG0sTf~vX|IC$Aua51!Rr89SiT5jL0TF*BKyDtz|$cWa(Pv5q&ywm-;^X#T~Die zL%VB=UsE4xYHyK$h=3%Oj}2ICw3X20M4mP7nR*==L~^?yR-mvm$o*SU6HC+75k#Qu zk-`Oclyaj;Fzor|#pa^fSTUQ8`f_KbX)MjJ%%kvZ+g#|>JDtXSz22PDn+vnD=>Rr6 zAon7QYW)K#gi~ryq>Hll(jho-glpspBa*|!GpxPD@X@qQB=#wcJn5OFjaunlykn8l zq!7r135pJ8??+04<2^3v_WZ)6LE59``yycF5$zN#Aqgb)isdksad`Xgdx2KrjTs#y z+J10v{SL1sAQIxRJIZA&zI|;v5YyhK0Np?~a@C>ILti&#M> z{Bd&a2&A@SgTsW8mzrivI!2N;3!i85MY_({9>OchT--|iL~Hv|!UU)Us3FA_CcDIg_5Shyw4v^%UJt}7QPEJRJp zU#xK&y^MF7-{!DjL*}}?fv=_EDOZ6#Tb8h#+sJs@E=!2Y?ee441EhDODopB%?({8v z74n6y)oM)l0|Lv$en!$3Q+`%GVHlZqSP^6|)V8ZaIx+K(cfBvSq3O{%mm5(1((X(0 z=A6_-jOaPnirX2{7*CL@uV%vXq;x>|NX2G{{(h!l`A{ zR<&FwFbh90jxR=sF4JK-%h8K~4+&s2dXseO(s&X;HdeT_+@&)&rPr`R&ORs^+LYkU ztfX9twQCxctB49hY5{8%sOX4()?&9mBfY*qfVKt8gT)7#^h(o+jsUa$0VPKY%DCnC zsp%b(zEUOG*@+rbsy=Nv@XEo05PR5=S#oC0sc(%N*kr?ePE(u3u8mP`)3ZOadQ;%C zF`{lM0-4oD9;J1>)>s_s;Xve_}kBT)Z!=jd?T$_XAlUk34ApOQn=c6A~|D&CgpMH`&VrY(H8_iKarEKI6kB4N2m zSWca@Q!3yDW_h|S(cx6hB4Jq%;6o=bdXcc4$=NLumN}n4bJT}}Ek(j|d>T?os*wY* z(W#G5&@tXKBrKm1B{4c%cIp(!I2Dl&ZN<5WG*{!Z5l@>Hc&hBY==cepD&o^DLs@b- zJ@wROh9BV&@_R_N%w}wH@@1-^@s=Rho6zWxAB->>J|YMN;HX@P!#M?D^&s?CwQ>Pi zeQ^M*FJ}7qr#~z`@9fwKiR*t79`psJ6G!Rdr5PsOBluf6gL|7HDC>W9ar*I#+%@bV(?sFw|6u4*(IdUd|7!?ZRHqbe5K z%VuM)y}Z2KIeL7V?)~!c$&;hUZ{hk!M~AO-zWLGNmsGlW)ZY{|HNTGU=f>noipP5( z&HCp!mop>zcx#fQUzgtD_cai)3-o}lq(2GLPb6TVgu9b%uOr$lr z;o8G3=uX#3g>u6U0Nqtc#IBV|qoOuQu^M@tn+80{0JsGUz=j#Py8(=ZYd7EC*d(-q z;n&IgeGv>CfGwT%jC_&%UF3cPD}qAr1z2?fR$YKq2L)Jl0aon;k{ysU3Q;+Y_ELaV z6Bdse7)GQL9UYp7R)AGgPIv)UU4T^=VAb-VO_BQ@PQq}c07C&*4bZFtthxZJX0-Am z_Z#(pP$6L$qp-;RE^@yKI6K0DqZ6zJSarH~OaWF+V4Kky)dH*s!dNx(>%+h0;^t z99t`2dGA!|S5ZOdVC};)CoLjrxjdA$_{oL+j0*M+r+y8i63|hV0{<#T)Q&7BIv^2w zTVkN);pL1xyvR#e6znYu_D-mBT;N|7_*X>?w7|dmgyUaP4cHr=F`z=g6ayVrL<)GM z0v@S=M=Icvih8a^J=db1D^dqxnNL8xd8y%%=7#iy;an*d+VpjsQ_8qnD`$tiKd_Bm z)F9t>9}iH&I_L`n#gkD53t?f;?bu!UBr4vMzXPT20mNXVHZYy$K%CaIuz8|*`(fk&AD_88K z2n^3BpcrVFG>zUZOAXUom`FuCo}mWV`-f7_-eVyvpmG0d(X+cP`f0+myW(K-ld>f0 zgePS^>xpmm24Q~?9`|YtC6%zH+U0!jI69~g4=mfkfU0Z{Ex}Mf18{(Q~{f~0&UWKXIqrx zv#K4_DEF509Bfy2Mn{ynVT<~Y{|$lxoXwC8=^@8p?m_uz4;-CpdiQlyTCPAW)QDI| zce?``4Sr7mycLxCrXlsffK*2vRhF^1x>~3Qy8+Jw*C|K+_70Xg>eVNV5@=NHv%5GiPmmp`4}4{1${UR!W! z`#`G%0|*8^(B2lkp3arizrQcsrq-w}T;s2Ge3<6fpmWqFIBeXQqQn-ZEJ7yr`<@?8 zn6{lA=94W;fEW^Ylm#rMGf{>U(5l?+&JGVFxTfRiT@AfdavQ_vL%`WJ@xny3mMLkR z<;JJ4u{={sNrw_@3m>=J^Pr&PloXmN)SeW<;aeu;cE|@udJqM5sa1Ylri5h0`>`dF z$8_Spz>Jx+8BN-VSY8JR^$6M^NO(hB=>~5XEcGD`>1x#J)XpQT$=hy7Vg;+pz+OYQ zMy;LoQ2ac`^f-q^vL#AfFaG$&0BgL-H@*X_5ghV zFETm2Ooz43bP2Fy>UlMzDqx&b)NC!aXJn1-_`BT8FKO2Xwqr)LMXx6%ji+C3Y{auv zBfQ0IfCJlcE0yV}9mo^SRL2sbJcX=jkZ4R&n}`g#-SzYkG7nva2;zIVa3+4HH(k;m z2#s|{7n>R>B4`(TYF1g<$9Ghgmt@i$N>vGi#w}nRqdhGUPNy1g?(y^+DCbSD$FbAn zYmLva5YCE-=rw|izjC2_bXsamGJY3&tynN&6tW9miW^yx9sSF)pxnZwYAAc7)C)Wn z*k-&^v;AUrnnw41IHO3|v+JedbtJf~OU z#TAt{k_?hcYoq(FLQps!O(dy2v{P9+#FH$X%X4f?^{b<%IwiGOFDGq>s;+ZiHSIn? zi&uToS>0(1$J@W6*sjG|5#86~1_Hd7m`p85Y?7pRp^bRu+Ai&Xp;UpS90X_ZIFkO{ zhKkQ>9@1Gc=m-4h@WMyR}dH7ODi*(r)A+`lA}{445n^7&r)Qzaw;WJ?}u_w^R z9vfhCP0dx8uT?jqU6{ApNVU%8>IfgLQ(oXZyqeY;&*Jj zBwI+TiN1$T4ZYRLoa^BO~&U_t@E0qvhy=(fQRLoV{o z5rI`jAQK+H8@3ZkvB{$7S%LJ-+ZIPdZbe_%t0zGmw_;B>}1q3Jh0EN&dyTOOd z=|dN#;g$Lm3?~Ka;167wDvWOI1Y~W{j!c>)jUqLIt%pQD6uH!P3-enEe|1}xZqs0C z`#v_wK)Yf%b}RZyTMt}I&?kh+&LwW|#SEM>T}UKrfR+-*Zr_7ghi#pFX_>aab|w4$ zYUaVvLp%y8pnk2dht|lwv&rvr|KHw@#KX`_l>i<0LK4q{LD;5+De4%7o)+4vCxrpwP^-9itA$1W07rU-Soc4!Hsm2EfGu)G%= zxHPR*Pa^$&SePXb(o0Pt`c;!w`xQ2>gAh#JO70Op%ganMFR_YRUDP37U!-6{If=~= zC^%`mj>HhlstTPEjstHsfwNMWf!B{jVMfyOO?o#3}s z$^a1)Y59_n+G!djsSM8;vj7WVDI;Jj`ZoC}0qjPb6{I%^gf~^H_8_B2HkH)9AT%Kt zP}SJ&3f@%7e+D}XZIdcV4pYOj#UAFSeV}F^J|#&$&4YLXKWHL=V8CTZFvSVrfKv<; z$v$Q`<>vITd}!k2qsfbvz)QwD8fWyFJjW&Z0Eu;815&f*n|4ZoeV2P8ORRTY>{7AU z4;vGNAN)=sJmy4+T>1%XDK{3zhE|N363LE=>m_$MUbhP$A}t5(vCuN&eH3FRn;%(k z%6I8v-N=;(zabg{yRqscEhpLz!AxLXHtLAZN{@VAK@Vny@TZ5=C2I84I?5SRn;%WL z9#+b7BZ4g}mo!plH?eucfmkU+Y`}~J5R)_;@Y8*D<*x4Qy`aL|w&)(LZF&8>(Qo%@ zFUQ3QX3*=m`goM!dIWxfwoSTNz23kz`VHS!@VcJ1_1{oO|KH zTBBBWrjDsk-iY`;eE=N=<@(0U%ECV=fRs05 zNLawx{zihqCYOG#&|yyme4PMi{OK((Cm`i-)9%8OL?VZ=A;23yNk;q>grXm;PE9px zIZ^msfC#`KfXriA?FvH#0mU}paNR{L0~#?xKF)xZ z3J0bY!=~JIa-wdQ$0rIdXTq6KA2N=$+SFW4%ZbdZ+70Q$q}`7<*TlC4?NLR5=tpv^ zbDwmlZ;=Pu8HgY!s=rg4n#X)^k>4$)Unna%>WMT*b0YE5fYT0?K1pOoN_lN+>K%&c z+j))NpJEy##{p?S%Kr#4mD5@iQ77f80AFe4B{WtG+$=7|%<*6dt zQ%+8VevLv}(wBx@hd7L$6E$B*hwpQu;p?GG12S+BI!Pb=loT&O!xJ8g$nbGy9IISQjg38CFGe9uJbD0x)Z^+;g1yhCt`Z-ZliM;7@ z+GHM&^u}bfL2{z+JJV#rO-*s&kaG2<63a0?_IBiNWlASeb|WOxlB`!bk}?Xvlh?NM zSG3clGd_2c_?}FYMrZ{)`Z#Y_PLuzaBN~R(8fkQQ5_Kpi>MkL|LRokS{zH>Z(L>i| z9DFAy(%wp@7D2pJcr>H28^Cex5J)M2B}iJ-YiLEwx5 z8pPwcPbT2xMCyuE{IXet(ilwEP2@wAldaAI2;HIObyWVw(NB-= zrAYj(_4|o&busv%fx51hau2CyRnGI7Wiz8XS8JrxRFT&4@cscp*1c>E@qn-4S4=OR zR$MF7)blAW%@R%@iDDST0EtdG8&O8G$a^Q2Ay+{%%32NfuuVD0B_f4{(y)+6i3}~I z582^&qnAc?$z|fnJ44uJ5B`p4J9k^RHg4a% zTH1D_bwnz}Fd6g|8#Sa$MkfaBuvVUag#U`vqR^v>;%Uavqm-MG)6d$OE#4%5mU_=cNn+f?6wC@WXqsM7qb}`RHp(`HJ z>5s6yCw6qC!YvxhbmTq`o+Ag3933{Lupi6Tn>DtA_cP4qnncNA8An3tIB_3>4@va+U*DWE zI|%Cb%^Fe@k;@$HRZ6o*lHz|n1I3ef%9BfuA6Jh3@Q-nFa~65uILjQ&8XwH=9au}} ziN0?fG|WchNq2d<;RH{Dz;cZR14*Lw^F-vAyYB4PY}o6&E1}a3gT{Fx?(?(n|0wwW z+~0ifw(XuLy1t3S@+3)XSQMpc<+C+AH46)+GCh5cNVWcH`X?+VzW_D-aS3|q;bpOC z%rCd+>(#}D`h0c1K0jA&&vo?b;{1HuTQvX{uik5kKe+lkB%Of>EXXS zrJNYEG$*ZwVFpai`3b`uBvOca#)LB6GQm}fs((&y8oY*^_VAZVfc@7^sPR_(J91^8 zMpm8C!Z_u7VNLvRpDC<~m(H3vuc+T2$8bxdf-C)aoIbJbjw%#s(+tOtIA~c(BZ@}?R{VG!!oAiRjGPW#m;T_4hP^jz3`TYgJd^---Efli9=F+oq@AV zt(-hv24S;`vQlBAmgy8sVWSo{YGI>VXFBII$uhLgkBu4$%854WInuiizpf1CVMX{n z(fEfjm=mr1JW=*W)?iMX2HW~Y4C*u=h?=DRh_HJSCzMv{s zAICZ@?A`NX?-pJZ4$GY2MM?Qp)c%sXlG^PHZ%g5Ap@1$$ey_hwU?U$#$Y%oSMMgk@ zs`C417>EC6Dk^9Fiu2-LMdm~*!|Zpd7**!QPZOe=0O+!y!LNPEI~emN zBAAdO5h5V`tu4wGe}du74Y&fpu#_H0Nq~wj&L|xwU1r1f?Y>OeoXTl@8=xSjlUY%o zM?&dYfWi3)vUFrFqvw_hadG=BnAIM}&>KhUs6lZ*x7jL{paC{~5 z_m@_+QZ#m@nJK?C&sM}&u&Cll2i!lK4e-!Z%$NxTPtzS9t~7v52SL1OHAHJ zQy=AbwxF3kTL272pOY9lcbU^R34JHcp3fZt?78K8JV1uZxyl~jCpgx9pWznk4v^)#F4z^=1Q~LnOk12&I@Cq zx=ep9)R!8@%G}D*{7O@XC=b6p%ri$S_4e>}*3OO&(;M*ciVv_!tyP-?+Wf%X4Un>V?dIDX zn`B0ezaOCDsKP@vh3L%XmUt4vM^5K6H*kV80tUxbIM74G zxq5gty{6MjHR;<*v4$b8HS5hLo$y`vaik816Yt~jmA$6}Pk7xm546AbTogYDcI_E} z(7JGk{Rn90R2USue$TU9XzA|&eqXpKiy){DDI@e#4r|vZKN?(UIG%;CRh-CE=lIaJ z?uRItXi&8lI=_hmQC&W%RaxJd=C*r;#}B*%2PeGQrfieGWu z4d-y}P!@XuP(0OEg!ktGr2_*vUWl;vZ~pE_PuUe~ITVIzPNkg*9zk_L058f7fcYvw{o7ZknpMDJ&r3Z>=Af=NR(LkUXVBf$A z=xFON&Ie!KwBGvrqsnusvG8GT9_vw0`mt7Ra(wPZhAh7^$$-ttgZ`FQI!O~ITlEDD z*2F~qaVJ6N^@UESVODjVONMb;*Q@Q7xpuX&BpNFneXeaREELA6b(V9YIIsDCf9WOh z-xtPdh)gKhb1}xvmG|D;xN(&%Jp9mNw2{I%EsWE`I34n76vio;uII=&Ekt=C%Et%q z3qK>dO$$F`4=&M`ZLSWxrwdVj&O~{URa0cu6j?PzRt>uz&xG+X?$iOiRxiRUHRjco zajAr3w2_OO$obB>P2{8?8A5cL3dI$fn{?vsB9_rEPPW+!w70;zjd32W-&k)TC^af` ztxKl}Ks;T&@QLAv^MfN)J6q=FIZ7}*tW)X6Ntv6JU%>*M&K_Ni?8weSeQ{yYG^@=z zqENsetyh;jE1jyLFE6)Omg>MIHBTLY`pU=vd{WXOUpu$ykS8e`7v3*9!gEE!<8Z>` z%aRMG@;OgR%uD3~5cfxU+G8x6BA@dUl+QVwA$d;ytVP0Ok?>d~JSHl3k?^=VXmbWs z28HD5jKopP^e{*GlW!iMnVyq-^v{mVh|h_p8|j4lkDG~~6YXErGA96@Hxw$mWiX8L3m&ZtN@>2flvmK08B;~ zL^1?vYHp$CF)B8yf}~t04wd1G3TX29#hGHDll;?%v&VadM_BwkxrIw(+`_3v!uUt$ z=a~HAU&Jz>=vIr0hz$L~1vt{L8;dI|on^f`KWE^tPQ6{#+va?=zOb^i)NHorn?fk3 z^;gEQjVz~CIsANThK>$D7mvx&;b+v4938$!BXTr|qc&W@>t(HT^&VlQ|$^UY-QLj^B-l8n;g(!JcXo+-a zy~3KT0)#5G#EM0QDUq-+0h%^Pw@~>QTa~O?5KVHAM>1kj5+Bw^ARSFMTMf;-7 z9t6T10WPt&Z+UDj83P|iVW?fd`7Rl61m1zUplZ>)EhKg8uLGOV5wzm6RqJ&?vjURU zC8ILlN$@!cy?zV86afl=U%8Jj_xN)Sa40RW(;{;X8(!*LTx5<82L@|gj+_*R3VlZ+ z{aSgb@(_GYblY{yha|b~J&9Vn>!Z%20fZby6Tp3Zv9E1!50D|Ve9ikn zep=D4c>(ZrLMwW3OBj~xIbQc5e)fC9b?pwQ*cAJW)EnJxl zfm#EEmQ+&@Y%Ig;dT1Fy1e(#_0qid=KXU8^>-|0eSG=B$(Soxk`8Dbb;Sb@FuD}FD zB-{gRvkN$uxSuBQeC~Kb063SVg$+Va?jqG&y9u}>?PfP=;I5C6HR8_BXm>rw#`in6 zVPP8a?l6q!XY^(@%Dz}g}Rw6_7j)YsOn9!7NCsou~n2c90h zjb0j!^Vy4V*}KPzuncrh_p3D_dWphmG61I zKwhS~B^+=>BnZZsp|!n%Pq`w!flKhZ_bsn4@8xzREwXK_daT||^Fxyo`PwCX7{s5E z5r4_n3BV-_>qWzci%tO=On00Z&X>TgVvfe@Yu4-YHEqMy-ZerG@|7UT8j!IO)B6HD z7#Q9p2Pc!qj?RuFAkWY+ai$GOvc6n<5}OR`eGmMLFNTlR&o^}Ro((c^yWa21+jKyo z8RQm5Vk0Dn$+SmR1vGuorPFbQU4}>ZY(E@e2B0iBjD+lA{G7hl zM$Intom|U+f78UC=L{I83S*}z4Pzl)lQW#*t}bc^2O@~BK?y;xf=G6yz}W8(`h9Q# z=rORtg>)BnvtHL%Xi^q<^s@_miPrZ@6F^%huW$gCaW|43^7{RO9SUIHK@wwHcycSz z#7}Dv>7|dx?BgbQ3d{<>^#MvX&{n?jeeC8UtYVm|@kU-X0&2esH2GfD>r`p-svX5w z!z=t9-A7GLQ+p5acQj#GED50y`?OtvaWS{rm|L%7nPH3pBS!ej0jjr(?MOKb+9W$U&C&STG42gp2jE;Xm;EH zHBGA{A;SV=g%(w|z}-xu7b^}UBz`ZeXiO%w9ql+o8dat4_$XEFL)jSk*l~z{5A^x* z`m7PMASoY-szItPxDILv6lSbkbQD5D(wOizdMXtvg|5eKL(Rb!)%V=MZe#PJbqdTt zla}Pjn6BTO{lPs*By9Kg2MpylgAGltw%d9;h$*uOe-9h1BnHbfh!GB{VbexsZmc4j z2sJQRmRQL^HtczA8*~6!5PN;}5}rgs>l}cH^aTydjX$~&k0P|h5S;+4p>gU-`pq2u zvb)&!^+;imBdlZ}vj@6C3n^vV%1uv+- z5IYcPSrJA-wPb2$B7U6#%}@d*Rm6Th{V@g#$dbV0BY{#Ik{^rp=6nMPeWwr~*!M6d z0Wcm-4Z00JUtV0$Fx(Co#h`jE2iW-Nhd%0e_@u9NJ47?K!qfXa(N4lJ9Xye{}?OonhyH*G}Pa7>i%n!+j7t#ZV1;DoTX&Pv%w?m7h!P+7u z+W@jFNQv)>V@(qwM`2`$=-sqe-oz3S+HHM60Ic8?EI-f_{q)77(@iqx210RV9$`odLb4YeB zHkK9|a}$iKM;{d-46S?-PxQmuInI5TN&Oh|Y|`3K>GN>rl1vQ#g{wh^_tn$07{R z6fJ^y_xsRKgpYW{@TK9H1pQ7)0Cta@5s+Z6iLD&}>zmu|CGEBcn+T^+^=;SeXlu9% z#a%aB;|dmE((ZZtK~$8uv^j`$5+9d&--SPQ(1XTD)(p0KYIhZisM)Cn78Jv2dgFC@ zPuz_99;qhu41y|xo^ym-!LzE>>D1$#7nqQ8OdF}^lecRo!RIE=-@r@hN<@TuV?+nq zkPl2h^C-^n^i7!2D4J6uvjPD#fysLqgixV;K-NP?gG-yd7nPnz_Jz2hmA^MaD4Bw+ z^{Aq0hs^&{x^lK=dQcasv?xlP1z}C2S_WI5%4EgjCe8!wmvDODaGGbR$WCGD5IqG*|62l?w3pf*CFpP9OseYhXh`9$d2u_31 zp%_oLHHLqD(evP>eFn@)6QGDaBV)^v*pOq36$9DaXC`D1IjxvzI>25OwSVfc`=jX@ z?LGJ+vr&Gm8y~Gl!mWJQ!K$W!0L*Q6J|VskvmNbOa9P=yK0F4KF?uq}CMZ(OE~0%l zESV;3fboh&;zwD!AIO0O-Db!t<7=yYI`l4z>-262xa`^emdWWN_o>^(!GMNW~#;0 zc4+-jNrD;>4%AG zmn*@Q@*^aZ>28I`oOOZJZa;LkkDQlxYAo_%?8FHS(r|z%iyU^ynvK&LsJ*<@1)q?sFcoX{HMr3xVyPi0D zTR6Fn^8|6IQn9fKZ z`on2<@K}nUw1=L47kdW#$j6Z6rrPG zQqu3*Ln6?&dk0x5j@a}NfYNHNBj@$>C-rDMewNYkSXPhv zBFUDJ0kGT01<;4g3Hii$r(A4MP$2%{Hao_)CwRu$?x`eI+ruzewaBX`MD7#Q1Sj{}hO8tFCIp6E7+ZUNm@~~KAluLHI#3b6TM}bARGBx;zYLL5PnYNX;8Uinkq>E zmckDIKYQ;M<4BsF2lh<&%xF?=jmC11G(GYtI;%%yb|;y<Qy}kG7z0k z#yIV#RMlThg9VOrvrMUW?<+j?L@v;4@J#>#NV+R!1Dzwrc}n%V zcnr2$0J#Di3$WY?=vcH5OsUS_Ths)}#GE_?FAYgqRyfrDqoayKJL4xiJ|YlUG^Hk7 z58%tixw#>z`H&iLBG7zFmH&kVzPdA>p~|MywTGm&MHfZvMTY=DWv4JKYJ`I7hL2T5PN zc~P#P$5h5M&kuY|SjYKKB%vl#BA!Ji6x+3V7Gls;z)Qw>@JtyGMgvEt8DR7FB)KxC zi3L8aCQ=cRuqfu&0ITIE^9de%62~eY`>9s=i(o;V|Mb&o)?oxdU0qu-Dl0X!u%g#0 zh1xRmG_N&Qfu~+sHyVx7+DfTh1AzK)OqL7csgKWa@lxVxzwyNxqtkvug=tn1Ib-#M zBuRE+QKyqrklRM>aiGN|1)-Ua7Up&bjf(7s#}RjreR&jKoMoaI_zvQ0&j}D=>|my} zmnr8f%QVf5TkA}eN-r(9*4tWZU^j*1a%UtN&<>fHz}GS*!_e2k+zqHNBKkoDpeR;? z?3Poi&^*X3NtyyKmnbt6$t^6&zDZ&meM&W}!Hf!W8?{3h$yD5_DURkL%1XPqr$*w@Az!=`D; zIb5ajmX@s%o#|v_*iJ+Pyk!*15ISn$fB@YlTL0rHVAPm2zRd zx{Oao$*eWa^=7rUdV+QC$r8}MMDg$5i%T~Sg|X+B3v<~NgE_d;xc z`1w!fr(}~TkVBg4QD_aLc66+cH?2yZtXmFgcT=k58!4@_g+wjlc8z&_o(oEAJon>> z!?m?;EH788dSS)DAFx+73yo66DCp%%sn%FtFY9Y7Pp#5@K^lEDh@1TKa2ox$FU|*> z>2%n~>hzgTn*4aI+ifBT?(}rJmt8*=S@0|v2gVL=<{f*c+ba4?7{zi&|W zAWL{lNA~GWIeQVP^6=JQbu9kNS6>di+h^D}7z!gmx5AIi@+9UT1Pk^0ew{gP zb${~?^5lYg>i{Vhd-WbNbs~{QyK-b)#U^jFm!7FE1C? z%;s{zSZ}n})=Q>QTW+3Uzxj*-=HGpB4!FsXMj2pUq4F|&z;kz)h3ZzOd1a2X0oC1b zLTr9^>;f;u9H5;BAfJ*Ssw#;_j{}g82XarTs;fx=`5A!RQ>yMawGcr5asj#j@66sJ zun8{@zzPzi?H+7yIsLo$nZFjO-21`BJYD6RIp68m`;e=!SM-tg6Ng`Ovs5gVN@dzN z@Eg9paF~n@BL{YT{*&2RGMJ2Myo|ej=Qn@il~-bL!E?h?jIsR}kXvBTHS8QxHZvqk zwqZ&7ZNq4DsG0MSTGKXD955jdymA;~32e3UFtbxo!R2~y@L(*y{9Bs(B?&nl;cU|kZ4?GDt^9Bth>9&!K zd*4E$_Gv}Ot)^X8QFeG(*TFi6IqZlP_amfMB!Uz96>sJYtue;c_Ci$ZucXs@pI;Bw z|Cwo2=TV~?>;D;bDrG(^qfQ3{xG?BS%OJ!1dpxNTGiEpUaJ~~nhEcfzG^HN^!3%! zau6uh(X7<=0;q#fH+3%VLz_A{ZNHp8QMu!Y{d>exO;K5G}~gq%Ue4jEmja`Rjf(w|Lz%QGq7x)J*8aZ#!Y`K?l}TP1klE$AFju z71a$)OjugC?dAaag?mV$MMARRF>N0=D{3p-G{N)++j8G*TCD?ZXUB5}ZqwY^S;S}F zUvF7m)8ls?9fsfGo%DBhG}xuZmK&70Z8rv1*TAf&jXkQiRAkcDEK0=;L*n{jia&@l z{{_|Cws&@t{RQ^;?x2T@LETcndHz8c?I>#BAGp$TR5>>9@9fNbZQV6@`~JLY4PfCw zgge_ddZ($|QJ08g0H|ZE@5^1^0Rs)bENbYc$%lzY1`X+O;mp~#yNdmcFiLwH8(ROsZ#%fYZEN^XdHH#c4@GyqVz;aJ z^lJE&`lbjKtdC7Me3>vT@B-7W$rJHC`S~Tk*I&AA`g-9Oe=AfAYgY<4ZTPPTO@GO8 ztz8RT3`g zK$b>v_(qwuoAYp}Sg8V16GlxYlw|2$XLkU`p12078)ar~#`7n*PjXBTkL7{h>xP|s zLAz;ly(8g)DmiK^rU83F(=ekktTx11eIv1qQezklWjrw9!%Wh?p*`6kg>?+3*J%|B zXJJYlh4oOwwV`no!fWwRZOCFw4OMuP3=`VTVG6IMdR`3?N(hE%>`gK}8(3~?d9!60 z70^YR8$q*vh}JJ*pHdKxQnN_EKMO?lG{$HCvD$@XIZ+JUoez6D)DVyAVEA zOup#SPF;EYC^aBwR4cD3nXfgwsI}>d$b%?4fUgg?L0~{2<9n~DF;y0sC`@g0+WOgQPFXC zm-L3WR4JEMilz0HwPmbO=tJ>xDwr*t4lRgnnUBGA^v!152DOff(d7(-0)9Ff`Yde&!fZozQ}6_*5GIb*H&c&Zl<`$R zsL{Q&gQ|-#W}ZJNIu(B9wukA!O9cx$e4(kk{BgsJ$dp6rhuvVYl6N@daE@9y&TIhYh|0L8|wVWCWQ4r3Px4qZ(ff zyCWRQxY@ULYO=s1#1mFpAVdsINp6SSF(Al;2}gyqQdqqbt_G9S z*}E9tTo-LME`Qq&qhB}@-`=(h$^Y1eY7R$x`Uy*2Se-GbhTg~4S!m$sWndC<2Uj~t zw5=W^2e>k^^8r{y%|<}dz!?<)@7aTVmx+ZD;Z}-6hzqA0?sTB!gp;7FA7IPoOw@5C z!nWJRKR(ozJxCVxk&Q!wX@1Pd&|$$(*pra!5AWmDi)!c<)zpNH=s6ya526@g$3;wQ z*OE;dMTWqmXvbUR(%x@d5SC3eKR{5chgnzd>wI_Atgs;{Od*$8d$|M44U-JJZO0UQ znk**~!^zi5lhFjv?6wLdS+?0fMGjm-nNzb+Nkb|F13R3>NPp2bn|n~7B-K5t94TQQ z2Tkg-gUuEFBR!Am$#_H)!nBL~)*hr9lug+J_-*MP#;l$PKo^au>)ll?5vTCl6iD z>GvH@Q1p8&+C=dYeIzjz7BG9b>L}hRfts>Cc%~UjNQg_6??F<^;?}Xu1z_ew{YHNp zIQ6laJn^^9ZQCC78kjL?bv)fv<#t`Dy%<8wKE&{H(__8yTIyFlId4iMdVsju{-B47 z$pLxivZ41rjQ8U{EE@A?vcFV^6cMw!+N>t*FFTYcgD!MXHM?>6_xAO^3@7Ifr^mehSa5QXMDEL)k)shd10)t$Vm*s( zztVsL!wI&8P#}1D;vTmqzxMtUUM1@Vnmdbm; z^E}1192wL5o+x-YlgcS3YD{|Fp~bKY`q-Xfb--api72d2wO)fEln#(dp%n6@!Y0EZ z?M+CMpy@0mG)fKau8H}Y_{gEXLHkhmKn#6y0LKc0TBdXbWm%J!1+U|QNC~ZB1qwTZ z+P{O^L{fVfXVF0er}Ews%xJ72%u#`XehCJ)#!_u7jA$<~Z;H|) zO^gn-Jme|MBxPctcePD!vVmod`^7Pe4o2^Xfdt2UY*9Y>!ni>0(cG4>9YDwA*>^-c z#gtGLq%7h6W2_^wG z<9NK2iWLgB4MT#bl_An>?1oK{x4Ly+(<)FM65X7XHn>?Sz{(<7Sz5g!Q#BA#$(5TJ z6f{?ohoIf;5E{V4eI8@wo;W0d357EhE69L7PPGJFs5Am#z@YEQXeq-;yk<=o7BT1@ z@@{21-+Tb8q|D-a;wP@{hZvN=0Fd};6St4MUgsmQs!&>BQ=(}g6iz4|#(P$XO%04N zK`#|)frPmpBC4p}$KKAy&(EuQrur3N7pxKN=}LXxnGZyRdKY&T$U8ozFlc6ywHBoj@4YIJX zv8YI1hk*kR#j1x)+h{fFk06`5`#_^$$FY9-hI%GA2BHt-bPVl;Zwg$ z^7{}5Pz3SPa6QSvbKF@^Euc{5&@==)A^P_Kx~#}+;N2ULd(bp`I;?lWDLrun)U^hD zINSCu)92%q;8?ThVB~JWM27bO0*BE6tZ!n(k6l4K!4QNakXov-h5CYao4x|=a$o`# zBOyjc>@w`VlyzF(Ca11SeYK&wSFS-@w>jadAZ=(5wsRlVsqJsWBe$J<6nuV|cz}BM zhPIZtqIdgkeFO4^*NR1{_lMBTFnz@xgGQfKPgow(6NVK*u|jRzfv+msGn5M>bf1K# z_q7HzJ%(6ZgX)(wU(%X$S`n0U(r?vzRL+RTc#2ewWNLcMsaAKPd76)Kh#Zoe)ulBh zH|y!Uwzt{IGR(!4+8Qj^VG^0)IwncraA}Cc`Q7fJY)g! zNFQh#;T|pL4=6cGP(~$x#G-d7eU(bGvlA8+sQTP!VU@!P!hD1cStMs5X@cX_TjM%5 z-Y}oj(DHnLpj15HsrR~lsjrqC{gKtX`CwkH-TB4&Jz2Q;pjPnw!_h~%jyKCIqd&-U z-mF$qzl2j@v>suP);TQl^SB<1<<`?p#gUE)=OiWGNS8pMMSY@0ouWm(k`Q7_tSK25 zmZaob6^2ii9(F@{ z-gb|*il}0!3b190K~|>Wxo41t&M_S*=;3v->tc(MJt8&;gee#BGsGB1FF-4Dhrrz~ zP8=9miOk)Yo10SQOD7Wy4ljuL#VOSjX)EGIg{Z7g=4DYZJ}Yns(v(Gf0*-J~s$(v+ zb%>sn@D?OZc+3WNUV+2Ew~zscVIxc@frq9CHv-N$kgzau(1Es@!)L%j`v4>{*6Df1 zJq@o=yg5Wxd5O&@0}czhPZF=30fz-ke*;=V1{{_>Is*=8z~Kxy3|lhMvKeqV0}hh} zF9Qx|z+oP%l+RM!B`4s9H#6Yyy~}W;h0vA^IGh28k3m~!z+vKffRCk5F#`@q5knbp zI0Fs`!DAV4ctgv8!)e!O_-*!Gq#1BH0}fvfAdWF=Jp&F8`3XayBRqr|a99QN2sZR2 zEO!PRmN-y_ZXz5Z0}f}vVF2AS;P5cuHv8E`lQ4s+)am@P0}Hr3*3eRka$;mKZe-DT{ZssTqs`uf^+h#KJFwgoh$TFSid`dOe#=@XO>Gc9|#^V!gwEsaeE6VR5 zzP;91DX*FtM62l-CQD^~PFbt=6oqtX7yP;-`mu`KbNJpB^24L6*(Y z;a38jci6xqFNRV7e*2Hx|L{MNTnp`AZ~saB!>_e}J-D2|(_Uz|<6pjkuWzW|;)`Di zZay{D%X8yq{(rYJh;;_B{@~`dOHe-~Hx*^jD7kW|oB(W|aWk7{Pl&uSZf5WYAqFAh zxvpp2%!)ByOdTP)K*r6SaWju4(B{dP)>6Ws;kpIZk>8HBo(8w2sp7+DGH&LKn>piV zHbYvMjGNim7-q~PEuUE5Ll(9SVlDBzu)&2rLJBoS={6Kon?bBIZf0)HSVJceT4xaJ z3}T&eGiTh)*j7khMjj5ekHlOO8N@n+Scj16;eRuTwJ`fd^rsm&Gs!C{Ndh+HB(Y1z z&75&Fg8(LxUM{AZMBcTGn>piVwstda=8T&;<7TcZ(CIK#JL6`~xS4}w2GMqzwvVO> zwbSVeCZXLPp&%aRL>?g`&bXOJx+LRf&N3DuNAt{PEXp9(1GUe$tr#WEWTc~*>V5}^C zX_me;OJAC$FU``IX6Z|_^rh-_mhxuDX#ij9^rffeu@CY#ySgPn5ILoZ%JtE}YVINB z_O{&_AZ4@H2SZm235;!|?3H7idJ+lVX-`LHcYsGMq{3x<-=by~cZFITXSr0b#~6ZV z=Mv%Bd)wY(0(HUnFbOr>vXYfI2F8&JAt0d2!8F{=G|seE ziKqA5Rxa7w$;}zay02kt*alHuHyZrEo9I&nEsj08H;(m9kElQIKk>kx4eVE zwlQvqTgbfg07-=(qC53w)9j-Wx<=G5bMxT`V0FB3D2Uq$s-fN=B=uE@K)hAFLyX^% z@kHV}b`uZh$UQ1aIr$c;WKefJ!&a-fex}|<3VQ^vs`eGbXH`PaW1dBRHsm}$=1G+S z^q41A`sQPwg@>X)@K35X(g!nRD;f9X-f{I{8$N7XU36%WiCc)~f&oPPF>X=fEo7ud zo@J|tIw3!%>Q;;j%oR;83xHtSV0#umaBv=Cz>>GDk~P z{c~cW(pt$uZQ01hH`1dr8@AYf{BPh5VDN=(NOn0o^AVJf#-OV+g>_#?0>3=OLXnk? za{I}9JlK?x*_vJIU;>i;54oeUxR94z_x3y)2jr4RDsijT!ZNr0#G5>=fE?FMTh+3{ zXMXQt}ByVkOh1-ey%$oGgFF>ib;NX0KsNCU<1I z_XZFQx~IKo_IkPu?=SD0c10@}m#@gz51v6}1pCVyAUk#bm?>nwPG7;1u z?Ci)q*=n1p3=jRO%nhm1tt~)!@jhHp9u8ySVZYa0WeJ%u?RWx6ih}KdWd`IT@ zQ@X7e=T+CJOvA_!F1Fazz7y~E(kW;-?Ubj`$T3o97~7#99BDzAaF?aZ8v-7(bV~D+ zG60Wh#C;R{jls?6xQ$2zjt6&3l+qpI3R&a1U5M0&G^9um8?B^)>^v&Vux0xcD_B)c z>@~bKEbXj$(rf6`lME8!E~F)Wd9e8wPW+E!`5_agML=3o2FK$;DStux?N-CziQeSN>s+7{|SA17RT+przET|hn z-NM&XNt5AM8yjE7RIUoKh@4naDfxx49LSR}gDRCLUo;JhMwu+p18TcNo><5{v;-nZ z?va=_sgE_sJhiiK%*#U?bE&b~(6{ZYD!1zf6hplp z#wV+Y?MqZKZ(zyEs(}je%d(k3AV-1%`CzenodI%f$_iF@Y#}|mYeBcY_>pwfm|~+v zJ7&8LHg-OxG9SyBfL`lL;byoC%g!FEHoB$|l#o7;ESxWbfSzz)E^0Ta{@{cX==ZXD zi1doyvCX{a8l{@qcd)6UwK^2#UJoB2SJc)YFk^@qg6xAm#6_lboJaZt7n9J0-GKWi z7P{4xhq>dh+^~X$pn_8I=-oIwQHmWeiV|@a>Hd5I;Arrs@N7c~vqd`zb)MD$0zEV{ zs8}EfPP74%-Qu~yh0Fom$Ka7n=}$N~dC)bXdbtBKt%^CP>+!T9Y7M$0Oa#EKP-HIj zf+n)O%XW+7cQAE=+X}o*!%5q9u}ON`#b(#4hhMq%z_bK?!ZgIVbczgrmK_%yUD#oo z)@+;2y}kpnjoDzb3FF3XJ5jK@7aO=bS_dr&<;1Wsiy!2CH%zl%Fu2+;%Hf*Hv5k6skLilMlyy92 zb+OK}zNlbAIf;%RP=u1_I*JRCRe3HvQ6d+@wH6+EXn#obeX}3*db3~WYU%1wq_9+= zk~W?GfhHwkI>BxmC%fQo0v}CN%XXRK{IXHdWfsaLz*6R3&LJZMH4*5yqx*fa4lo0XrkG zU_OQ&G!{TG!=-yLF%vKYCg>*0K6Z!~m^pba;~H0w#xD*8UfkDVKcmIm0q4~N6zj4E zL}yonu``cIIkhK>#QMICT}t#@HUt|JgdglqJ}l;}iCX&c)C$a4=o_vWBO#KzfnP7a zqwDPM!iLD@fISvkMr6put5oqL>n*Td+E_Pg<-u-RJmdeUA9H_?mQnW)AaT&GQ>xf^l#U2ZOlgEX8(6k@KA}J2OKaewcKA0im7oucb93(# z0Rg2_x2II^a%gCwwiwuJL$R)$B(i=I40uzjXbA#+XJ>9Ake`9rENWqX`yfXT_og(+3BxOPRM{!+D5ayoXXN3(QF zwOmM8gH8slOsRs`!b~&cBr;u{JxXzUr^O2_3qEp&hR5+K)qO2(PL1OP1QrBP0lo8t z_z?N(0muQ#b-4u;$du}PBXT2;h@rC>52sZ7cLT8+PZYtBu!ofr65EQWwV_^NjS?`A z9fa|~Hlm#H6!<`uh6sl~0(vZom6C}9zyN>>gK1fhzY(#EV4uV>*#^t4O`QF5ojvIS8K(EjN5AcPUNx31s5TfcGh*7ZyC+jgjSb2SWCgHOqtrpONg+Lm9;fk7-o za%4!3*++7y6)S#Ufs^N-ZcQrT&}W3iX72i9vpMk9s=;cHoynV@$bx>V-jTySmY=C! zg7RGx(cIXh#2C34dO%bfcvAX3JYp8>SKF_(zwi(rPE8m5=Gbi4?F+G3pHHMIeuj{h zznRR%{A&Bx@P8MOA^FGgi_;mBpX;j+-vI!cftr2DIKY$fzrHbNv|uFd8%4zaLVfTa z<>!|WhIWKn{!UcO-}?M3pL>P>q5jE)&Z+7izb~FXK;u(cAO7qTATLBk9SF)=HyXDI0}#-KZ35MtQlg-qOuN zWu;jyw`$FDwYiM+oqviChktAGseH^FI%O0m>c^Kd1^OR-DN|uzIu&+S znSGz+w2)-}rS1UbBR57IY}=z-Tk<@B5Q9h}J`1AYCuxctxsXGCKE%}<+cpSQu;sa+ z1ppweX*Ph?1c03+9kA(=N`h>~a3y#Mz+(V_#33z9Ji|p8BM@qPNyP;SOsKK%>V2HU zh_q6>e-9|PZTq&|dB^c@IEWIt?z#>RXLk?*A=iZ!$Ix=|(>YXZDX7_eb|T7UC!(j) z`4wjmlztC{M6gf-F<3;{w}kEJn0<&EhL<;@UGXsQO~#_YtO?4Vea8j&(WwW8>_qfB z&q+UZr~Q@oSCc1^H`>{W2#Wcy9oEL|8^@f8Vl{G_>hs~(QwO1>5U z-(I|rFZbkg(L^k`)2c(ivT%M^V}xq zH?;ZIz?KLPG9(a~&ue?Ovk#Si*Q_hIJAaF@ywmhK9hOnQPv!*{z?vrHcS?3Mv=Q2X ziR|gqtnP@5%&0b-t+mo>q0}%|3boZ{t+2k zAPqk{OzvA_+kNy>`mE+>&1dzbdc>?6)^o$t4hGDmA4aAhadfAxyJunj9#@$V2scRt z&~RJCZKYH@t%_L9fxYJe8F%ISdpGa!yfFTLFoc6un0Xm;NawVLz^AKmIsOcSdkMUQ&_WizTU%ttB0vKrU0bMJoE=lJ_hT^C>qMPgBsz;_Q zlp`HNk?xy%k0o8hL9c<6(H_TzPpWpSQ{dGtzIEg+$N*&FyvL+-DB(6pwS#BbLsHxO ziP}mX!+zrfzdS&^x7-M(cl-+e2IP6Md_|a#VylBSCAyl^c(EZ%bw?8K8AT%F3Y)C*YZ~`Usf}cU2;c$$D~a>c+1px2Vi!- zbLG~;WfnlW?#C1&Xyu?9&-%LVnUv1B~=MO*s$^4Xzkr$u*JUG8Gr8+O2^&}V@ zERT)jJl>A^q|u2ZXF$ZSAyrYWS}@letA$#*)heu)TWf{#a;dehn`@0qxtg5;b9V-f zc)S9KFl@Zk3qSP44d92(&oBm--N{(MyWb1>3Y{c*en-I3%DEh~eeGZ}7X&O4S@FJ+U=IK0|#-)Wy6;W5UX_v+oL@u=p@XBj*=X z`2Ng-3h9f2Crk@GUKxszA);BR6Nyc|%w?4EM2@p;Ke2aViae2D8;>HKCgASy7taBP z@vCVJBLEUp?Xs_`jf%eRS%gehYt6=5ZOtfDo9kc|X|0wD>y2`=u+}nat+m?na;sFD zz+LuL;!tEq4jcM%VkBRiS&ZaqYSFp3qK?e43?+ zl&bWXQZV@`RYC$ECWYrusgC6{Lqeuh(Juwz2+#ZV&n=$+^;t8$lYmg$HT`+L^@e@Leao0L`P^i}uVw4Yy@ zwcMT0P5YTyi~PvU#5R@WDM(CEvK2%#6t^XI&m8CIGqKT+t4~N(kSml+C8h_hKgj10 z^4@oB&#Wsz8tQWgDX$fRPw(}W?#eJy4?o=xu1H*|mj}cT0o1z(n_Eu*ZulD_&E;aq zM34as1^0-wuf4uMrkD9E`&M|%6S2DT6t~{Z+_=F^X;7IaNet>{?lY`O&X(0GcfygD zhh9pcfAj}e&o9MY%vK2$%3J`g3$*`EeLN2%txBm!!IhTprhdw!iQh#nP7Ej zdPjE-zX0Z3+doRB&pMowi$VZ#)PD2u3x?VC!S0om9i4A$$Wrb(nSx{tLm3R zv=UP3$bOt{iRUZ>NGh9C1I%L%@v%1VQ-H@voIf0Cidq-t%R4H zWL=NU*|ITrzQfJxGX4zj{U`68Z$7;+8QwOZ^}e38M=K@d%PL?Hp0uORAEL?a3x}^` zJYcJUK=TI>T|bT`G;iqq5&oPirk{JorLywpu$Y{EMe>T|WfCE8@~8-!UpSH$w14MG znl*vAKD)9tGAMD|I={&w`LBNSC_x$pbE~3GIXZm1QmU>SO>?cFw;E=lwp?B zHs0oX#n2mT%~lI)ZDi&+QU(42cB4PyZglwN$bNQ|Ae#M|F&&q{O?Up3^WdNH&!5GU zf%76^;Z=3t;Z<`cZ>y{-dF z0PS+Ch3CEK&iexoW!muV)6Ku3Woj|1Pn)}-J_MlQKuU&CIR-e|jD~<;Pj^7R++%lVO+rdHnAbR$@ zrfpj-)Z&i05AIyu2=BdRqA#P{u0ci8J~Z1fDTFtKcKhg_4=pIoS9QPL1pDry_C5-u zvP|5Hce&pOxvA5$&|APF#J`4ZA=fV+*)=f$;T!JJ`T*+FsGSD5b8kBy3|Z*auzZ@% z^j$a{wCfAMfvq(-76tJk>b-EV5-?o}KZ)$kA??>Y^dUMdtmyupWyAKme z*Z(-I8fOuh3=*TnN%ModLhA!!g99H{6<}|B+U2f=%%pL3Z|F@EpoTr|j)lxFI%YR! zU)MwP<9mV`b%p7cU!tPe3a+{O zemz*>_=UN2K3xQpVYGaoa*aLpl1Cn*y~4-Q8h^$j;8)f8PY!{--PJJ>d5{e6{SY+MuH*DPb(w?0Twvh;1;Rz7 zo#qT&W_alhZ038p-*)=yUMWY_MU{>jg$& z4UGZ~x86l!HT4)su{|xC(O7+zQmIzdZra-So4y12O8Rdwf<(8tCKOyuc-XNVRXqXm zw7Mqb84Bjiv_St2OCd#^;sM8ce}wsqFHIM#Uv6mWJqy*q?RvkjZqrezCQ(m_0)*t~ zI(@EBVO{QO=3~fJn95iTPi;Ky_t5)D7v`CP=&T`?9XQH&ku~nXLGM?tfpHr&*tCT^ z`??EkRS&ey9u4Qo@|bH*(+9hx$U)0EaE~n4A7BKS?MqVgIAW&P8c5izY4n#j?-;G}LfMr#i{2mf`qab>9PC*3DgTttH8l4v;tu|yu#nt-A5d+4?s1~ z0mEX6D+;mC?E(`QW2=q1^(vMb`WTemaE^c`9(#N%+Ps}$(+!#kA9t|NYmUq%Jjc1! zf+`Vg!Rg)aaez4xDD55ku3gHK4MjaCpyeJ zs3FM1hn0(lLP)4O#&a7jRSH$WWG`hy%?aQIRs)+C*D3h<4KB%%KD~Tz=?C{9k+9uc z9}Ca*A~rO&+HUC$FRED^ZwKs;?9`}?NUV?*p9LG13)w@7;DjTHWr>xHECM~JVWA#i z@yA{tzC;GmWI;$iz%M9YZT#Vds28Cn`ZNwven?BAJO+5PSeC3^Z2NksFsL35`c|d~ znn58RO@wAaR)Ly2oFz~V(ZR7aQsT#uX-_E?s=v%WWN`rZJq1c}NPeu8Dz!4$@Fx%-*!R#U$QOqWgl>b+Z?7zC=tg{@3OR#Rj0IMqK*3cgl?#>Hu$bY{Xm_JQ=Al4_S~Uyv zqBp?CiGPo68{Wt%#4QgE9A0lUHxF;y9^EDAq8qMd=m!`Zt0(Kjfd{<{4PI?+p#aHY zD|I0M*s1z1-MYR;rMQc8isZ5w8o}y%xmH?Uon#2p=O~=hZa6qmd1E9z#{EVH#1o+dnVMdnGOZb=Ds(N!yOzMZ7N%yiSL+V zkUVWD4{CeIo{teI1Wr>E$Dp>g+eX@uwrKejKgi~Rjg%r9L*@0k%_(12xXg>%g$oyy zR&&j<0cyg)mvPuob9&1mvstent>v3GbcO-sx^@F6P@JyJJQZ}`7p1-7(z@c$P#&s8HXXm&gxBDB7RMsS?MQOjHBszGJ#U9GY(G}DH~uZ$Wm zTH3qkYrM+Zic~(>Ohi1)aR;*f_Rtn2ZawXMHE%&HN%NqMV|7&$tBWm7&eU@?DZi6Y z5C*+KMd1A7e`=iGg{}}yOJ2re3`THMv(Hs)FU8};hVZ{&x?)(PHgbri(R0w8Y(F1O z;B(d1FXnNGTsU7i+kXs`O9Epn2-m~6SE@#7rD?7fmMbeOg_=pA?MkIoD4A>JW^1`z zTGPu%9b#ZR|CE3J$Ird;3SqT^jRl_eH6FT-e&v70}b9`@6Bkr`Lr6WvAKCUH}E z${UhyBag|!DR_?ZO?^xsMj+tg=Z?|u6A~`IcYGswl{&MwqV7znq1*O0aC<|FsJbiA zW3-a`8Yp+_i>j_@cj|(?B56^f!W93+pJRVl5uHU{UJp}3A|^H zjGxdr86xE8;q!IeZTo@e8*r>Y#HZ`7Ydc!yA(&M(j|dXNB{*9`tkMDIYGdEk`#Idb z6hDYhDDBCL;DhrS$4l;np#C$tQqQ+jcfv`Wa_%aGrE=Fm^rs>r0|_f$agqaFGvU1v zSW;f@6N&-QTmV*PGudCNV8J*-MAPXLxPWlWWI>SPsQhy(wEqHsMuH$ubbP+~^q#mx z5M<_*ef`s;d}qjW{H8YQrK3-FxmHfZm&g9^gqL%;Z(n)A4&|Yc|0&dQdamO4j^odr z8lBDiCdhCwae&zN9zh8ON{rDHN{|5DXZa(}U!)p^I}}kcLTHv&XsLrj$V6HvK8so^ z1Y1v{Z-)E*gDoI%uc~;oo5-FT(w^Ze-+_NNa~FiZhw!mSh}QwSQE32r6VVHvK%*fE z**YNQ<}YqtzkRoU z8f^7LT))%duW7Iq%K+Gl<+W3B^itU*xq-`DP9itp4IK}E0u+{sk9RsP{*CMRVk+K| zy7158dsdGjNze>!1Gr`UuW!uFUC?e(CJ}mk_5Ke;(#;ty9C-T%Q2e@4hdj^EF9CtP z)N&9egN{-4YyExiVBLqCmqT<; z+EI3U$nIU*wU@S*{9eD&sFX{qmE|R4@ZmMT^PY{^1q4FCFjT~N%`aeF&sFm-0WeR( zeNIEb-T_>1A*#uB2zOU8S!6&$I8@IJ92!Qeh#)K@zi{r_`g1{B6VZYyzVuv;*mW7J zF{8p}sZj~q=?wsgcMo8U#02#uGFyeyVzAFulYfEfEr%yzsNtf?=czHBAvaZ$3Z|+z zsx@TCEa>ZvwL)#x02Pc`E)`ad>RNeuy}7QJj5HO@zs1>ahyW&VSlxod>KW}j$4l}v z%f_dZHpi{sXR;zrn_~$F(f`8D^nc@@{}q1%T|@S?m>pehg=2M*AzB*IN1pBe{3E4J zrT8lEvA)#t9iSI~%tp0qpU69% zin80x979Pn;|OVH<`@cfqc}t>VTZ{aL*pDnH4TCXKJOqVmaG$2Q)22R!d#ux;TBI@ zhGOg16x=Zr1WJA>I77_3Z|m@9#@VZ8y?4KnK8G!T?DfhA`v*(+zISDB=6k$!xm*4i z3QWR^25JY;DA*2&q8`I=Q3Tr$JY0asfXJbdNH9B%Fx3er`?oa%?0s-L=|T70=eXuz5t@;Jo976O7o44b5JD`O!22j*} zXXYEQ3YtO_EQ|mev-ToiMf38o$Aex1jc^YFwlx9LSpLS`+|JI-H|(9Axxl#Rc;TnC z7oKgcpNqBg(|`t?uS4HYr5#5zKU=<*1S!Nvs+q6%Jb?+RL*K}eYUbOpFh4g3@#AePi0%FH#hGu{r97$~f(#gU6164aJ(vTh zdl1m9exBb7c9fZK-}NE01He2xJ3BZKD&qri_@aBAvQ^G}GnYm;bH#Kkt&>56;UY3W zwr0LTUyqfR@K6}ojiy`m>7msBzqwfp(R?Bg{L3A5nR%UyiG3sUIw!r(XGC0Zi=EJG zlte2G?RP_F_NO#rpKc-^Z-6C+VNw$;1pn~{&dJP&XEe@@n!b)PES<${Gm%k*{gN_^ zoMLo1!;zk7bH>9UrA`n_WTRVjM!X~1c-w{+v~5S{=;&keAkEt%O_vANKxR>9qcRz@ zBN1L%D%kU!3O0+Udcq{|KYlxor}}&NoP^c#`x)Y?{w{9s{GI5T7<2HO(Y16u)qjfX zcRKtv9Z$tF5KqPO((zPM*;U)r{qEk}*^tBm~U?U}4I^9jc_!B*i$^^+&sa;GU}{ekVY>VeY}6 zzRMJ+jf1?JkP8oTH$x;`?je%=>UMqs(ZHVRqnU>JIFF${SFK&XfJ9-~g(*M65j^!! zalV?k((n33q#Xh#3=XSZ&-&Qh1jp9m3L<3r6SWY?m0+$0qyHc`tHbzPpMM3RgZQs4 z@Z=v;*@<~7{92qSdDtTuLR8^2SOjK2BY<=_;|Hscf= zH&6}iMLN6`*{S}o}UfB{SOjEu*nEp zLtkE9DH%p#rCieswPty}u)bVt78*6Px?D3?myOl+bcF3c!D1L6Vf)*kA0J^GoK7Y^ ziA=8BkI|No*FVp$(a{VU>Oqt0NXKd&PqdFe?auf_d(D$c?f@h3RP%SukfDj$FLO{P?mgZ{HU{QgLpDN=#Tvg6Qr(mCFu(upk*Pf|lfDgXXg zG9T&86Vr|{^w61*MdnUM-gfbW4{lz&^vo#SW{a{l^O53QczT#h<|92Gn4S4Zk)Q%b zh|EXYt&{N*yz4K*M|wud^(cSkqUhwu?%JoEik@y;Pg<$B#gw)k+NqPL8q#+> z2!9`M{EdEH439S3u&8e50%ni*Xs**52U>WaaEhK{sN`$Y)}OTPFDz>Tb&G5a+sD}d zR7aiNrUtT)W6f0RxAAtWuyW%}KI!U4MxX7RBOS&UDoe`tv8I&h#=w{oz7GA($CW)L zpL$X7Q*5MAw<;?|h9gVj$TD`@jJ*VszxcA?J33+;IHYahKgORCTKf|r5pO=dt>Jm2 z9!{`>4Cfk;(Ip96$Z-9ht+6J+l$=z_Uz!w$n&h<|_Y7YbkD!DEwgN>-}>eJW|{sLje*qU-P9XaAY#(jhS!I znrhJ5nKx#>Wtv*r#~XNOz6F)Do1kaDO>d74BqCo(f{kP5Td@)%%9CME;kDzj9W&pq zZ$(j64AUBO43k67%s1n&q*IEhBgD+t`s-mDkpxg&0d;1+>g!erOcikWq--7F!kGD{ zt;YFwqQ$Ww#2hgid>m4I<{S1_gk=w%844ZF07>PNnE58W1Kjh3u&|kL%jz*M9mN52 ztaoN^<{P#y5w~c-co$L-Y%vZqJo`=uuu+7I|g=fBL`CwfEp&hnm2+FO{honIPQ8I(98jjT^RcGH}T0hXL_MPrQXJ9qW zkvzZ|I^YC!z%1py&Fv!oFBsUm3@k8V3bfZJP3~syp6L%<`As#E>&VcWza01Z7!+}R~#)Be20H7>AZ)( zX$p$(@yeT>Tl^;l7m)Jq;&O+7l583L9z>_y!^bqQOn%@ zLyoch8Or0?`BVII_%@;mYvxM1QCK!t)(f@DYNODomYRjN)mqDFG+WEn*6LB`&v@@w zM@H|c^Uv@D*4^PxCdcvc%TYHSA(&AK$fMsF#A|@>mS?5pU>W@pF18avUQ%mb99d>V zxgKSyJ=@9rqf^)0sj}b+D~V9A!WUl>g>6=W<74#`-Q6AZOxyQ1KglI#Gq$qSs!wkC z*onCHs7?2YL!8FeMo7wR&|?(JrBV(rsXxf)5J1y+Y|pH#-4`-Qw!cL!pYuq6hYc0n z@W_2lnzQ@C6;Xw}JoZ~KQ|umWZaMwC;cxeYi+TT`Z*Jy%r(f^mQQz$K!KVg&#M~?u zkxjgeYy1u0*3sOa{nX;t4> zacr0g{p*CY!(r_NQwNP96!e%8yRL~`aya&SIQAB&+p4K*LHQSGw$d(l_w@r0TNyW4 z0~Du77ss87oK9V)_QRg%`#7lY!*o^Da@gEXXC{5mR6Ih*o4C}AKu{XKioB_^^=JH~ z*~XvQydVOxAR-Igc$-&d`{_K&z4A(Yx}HtrPkzLFkTm`zOe@pf^CqygeU(C5SvAhL z@u%EsRt#8r3Tx{%vrt=GUM=WmrBPVbkzsUoxmm52OlAD({4Qo#Xzl6z9=;@vJe|Lf z3z>cA6|n)IVo`;C$Nj>Kv+vBVW|J9*#1=wX0v)q%8JoE={5NCm37K)In;C~Pzi8wg z&UC~Hw3c&WB&i}vpYzBvkZ`&+u$#0L(#0KkvysaK314i`^Lhiz*BgKOw;eT&CeiqKU-i2f5zs`+?_jGefIoXtfNr z1(QlfJE5jtL7nn`XY+IqBXu z;?=89Q{{S0<=DP=^$DjGyzm6Qyp5^%(X8mW` zW$^!GE`#0k9^GR*wu$p2|H)hhSzx{M-DM9I00wA1xs@9dS7>;4%~Gl>ccZ#3kNUc(fMxidqwS@v(H$|qIQ{wvYBtt zTe;wfq7DGwpyBzt-2{t5aH6zlz6pytKhU0smH+r4hOr`C=p0xjehF)%r|((-e)1sS zbQI9ZCoK-Jpw7M`MlryUfuz(_O`-51IGGc3=7*{#+>MfF3W_zjLpasQs-okV%wrEi zi#^9))EY1afXhYZ=FGS13WluTKJaABq7{Sz!H|*98Rv)|U{i>gHpo?@BM$oDV|<2* zhGrauXV3n~y`>=t4pU9UL;=_;oR69SSFz1rac=HrYvzaPeV&ObAls7);H7af@a@@aG;pjduzHipK8eH|CJpG&*gz| zY>-2S8WSoH6H&*blq6e#=E>1NLG>lK*ABP6lOfA$Pn-91ZUp*~V z^;iujV;q|u#<8&jl&PSZ3Obf%H&a2+2a@fZX=`zcUi>^5ioYzZVE^b3u6~x?{C{ue ztU5Ps&o^}#dc~Hg(VJrEuA%k7#BCMY{E2K~HvJKcLKzl+*LXlzIKEq5y{A_TYge>^ zm$BW89(67$KM6|fn#OKOsE)%}it#fbP)DeG3O)tb0I*X!;@A;xP2#uIX8T-t)Qj3x z<*PuhWYW754yfC^1AP}R3d~niTs5w?XCA=(Z+NU#i1HVzql|bxB$?+4OpalPpMNm> zVf{ZpG)40=y*B4X1kJp;<7*-$Batd1bRLZVvp{+F1eEK|b$z{3X~C#rz{b&Nt`*j* z4ZToVtCY))Mzv*B)&t7*pB@%1A>(@If5P-T{JD4sNq5eX7kAB{a-x!_J>yz$f9r2! z`Njzt5YhL>H)f4?;Dsm`GaLUmJmIkcCCwz^u9!P+=I0ny{?%-wwwVV_sj6859~c}W81!R{k@xas6&pwA6&Fh zC%xjf%}CG*UJC+xJfM|P^fjj`T=rlU+pq_{LV4Q`>b#+8RqbNi_xs+)(o&ZiXt8Jd zda>#B)Ys~zow|Z=+2+31(tB1Hfc2Kva}4;&p$-T=43N_Y+HE|jUB0PM5LS=WJwQnf zK%pz32LL^Us6N1d5CI@Xjur|iK=_6H zeJAm5&-xf`LUp9EQmj_p(4e$4f?~CF1@Q-LE(v}HzT;ZZsrF4c=er#8CQ}!w-oO(q zOZ6jOy+ss)ybwS+^mLEmJk2&+52Tst@0+F_^jBe3y-nUOd!cFrMta*WsGGubgs1K7 zy3U}FhRR||oIIjo*WJg~qoU*PF6j+#sZuR17t7U3ZCOVC3}+kQ4xCOh>BJ;)4ax;@jdkii0j53VFnkbVIB`JQ(B)?G}q1GveP zlK^XG?A&Qvy9A+8C}@xL?m%!eFy%J~U6u|p0GWoB$dY$l$Jc=Z?K__2x4_aidkxbt zAb1j@XlOZ=OSNKYeQl+NxxfYbtNa5laGy{k5UZMybHM6Ei@CrZ-yJl4)OUjaSlSI7 zB~u~?R)#?40Ejm5_$G>5&K8!8-YWP52tVx+x`}-UffiMusNJw!&tKHKCgFGnLae$D zY#1y-1dUpl?<ok@q9+&Q2zkKcX^m#Zb)f`X9BM7428gmP4^p-sk9gXk@(EUc~<^7J=h5%mQlK+}qgT>}vBm zv!k-#<33Haj@=OMQ``3ZM4NmlC#qxQL@BY!Z|p>)sD>Gvl$r{dC|CiQ+!s~v*1LMc z>|WYY4cS8G7g-14MwF27@uZz>q817)b1UBUQKlbEsKBVeHSYDzrUj(9WSxoM``C5jy*}hx!{)5Yi(Ufkb4%vLzAjP0nma&c z5lzcLHsV#)q?K1K^2QwY^KhzT8G8Jj~cuC z7L)fy^Hr^+&Hyo8!IQC3kvb)27sdryc9cEQYGQWvfYrns`H#e(#@uo;!znXu@+h*h zOG-3Mm3ebk2WRc^m zAWEN)pCg^DP!UihfFTR@8HJxtv8pr_kK?ZJ|I;rk}!ADiczZ)tas#fa;rXCem##sd%KdZE57 z^T~z4K}5O%)e{ zJsOhe2aGR{bl6a7|HlN{$DEP90PE4*Ku>W3v2npzUZKvRHq=0o-HGZxET4kecg#WU zjH^$Mbg_aQ&noqnhS}69B@hilrJd5`0MoX?14yVr$TkMIh8hWU8l-W&NF^7TjLyIg z#B>;ztzN-_gM@{E-9?c@LUy!!I2L3I0P!p2{y-jsg5#QygV6qzYC;uGl^%`AF(SCA zy=U4;Xogt>z%+zV)GD?olFcH8;&+G|rCu<+7-gBuzB@IUOkYDLHae3hgFVO}cX{Jyhh7T0kDQnVVq< z4)#5+80e6g0~k_##{6*$u@sY3wouHlALzD)MJhdpyAN>Y>uuYrqGQE*AE0~(>qzx{ z@TyJif%?uR^-27ZU*}z?YtCTXT`GmqrU$?gZ7hhE!QY|6gMNFYW3%wZ4ik$E*rbp}4_+MV1vC@|!p^7C zi=(&W?BVoJ!Nl6)?mz>S*&NmzYXQFoRSJd)i-Pav3S@Oq@~DcN941i`qe6-z;=E#) z+IvNVUC41k4Itm@s|_4899OSL-_=N8(5?(D#G3?l3tx{A4b>y+fX9*Lvac&Cx*3<6 z$ElmYUXT?SWJQKLA*U`+7Jd4)XdyH@WOZs%>N^mB6by-4v8)eGgfn6>hl-z2QDduU zLjw!XoIH3@hm?Wi7;?J%4mwRrKtG~~O&t$-W*0{PgkzYB8Erm}yq>DrgZYoR>O1p` z+WcPh=~4KJ;%Xkl(jWNh(!=mIswjX}m^K+|4Chi^TI@UZUbipaJBdt6{i4cJKVpug zr=SYgLZl;txKwL`V>X`hs2oB7aKlWuOKK!kSiZD3;>_bSZnnZFT)haJh)7h>ae_ zs1LbIDxv5oBoAiyi^L90S`(bJRTfgFmJ;-4B8EbWXNbh86(4th=Dhmb^d#NywiE*E&PqW zm@KQqa@9@o4}812mQJUBV%=(|)~)m3%_UQ6O;kNr`9;?8uq5`e06^qv$Jza8eNhsVD8u6o3r_QOkk8PkPX$EM0@_8j+Mc+bRy!5y%MEB7?mGjK1AWWl{j0Nkg67eCvanE(fNKYx=+ z6BdYXczE<_2t)f0_r=TjGqO3~z{NWPc1dr}U10Qi_d@HcD*HEbElCcj?Xf z#JWuowwFQf-o7&oW_q?g{Bl9=8m(%hwcc7UluU*du2xC~eMMg{G|V;KSU1;gU$WEUK7^R!iN<|0EW zHb~gz2qxRi;j@SM!#Y@6pK~zcu;~MD&Omk(`QJkuaR#zWfEO~5T?Vovf+liHCopmu z$PN~bSwtpgAiI;Wc627esEx5p;CeHV9sP*(_=sl*j-Cu;7eFP&Z5iV#GLW612s4mf z2zd?M+RA~Jf$W67J_Fg|BuMZgj$iy|Gdx^mAiHXes>P0zf$SJmq%h|h$PTdw#8hS= zJ3umBiGIjHcA+XywLJsbWgxo@WS4>L?gNPKo4W^Lgf=YeebKaf2(cmgiMd%SBI>jZ z?Tf$R+d6E(J^gV2uHGy$N~Djd8{%v0j27+s2b<+$NkP$orZx2*irjJsCZ1HNvbsX$ z@-m451)`f5SQ&7hhze1#xvP^B-JA*9cK$$i8Du~OX+z8PfU*Th7~sn1$I>JCyA02l z7x>|+aKi~;S!t*HQ(_Jezi|SdZ|0$UYY8U^mi5HIu+J=>?{{CFIqDe+Z1jBuD-dMw zIS6kJv04&jA~6zMVYEn5L(F3z@GXReNy1vlvLK-)(kn8&0{JKqJMq{jkC^zmVdW4M zQwFTpj|bMXho0+JE<+G1EExo#aWJ-@J*GD@s<>A=lcCs*nIp-6pA1rxX|d@& zLa=lf+eQ;$0}u`bu}WZrvHWij@4jc@N5ivmP}D^RX@bXwM_X_x879Hrrc1&N(?zV- z@Fm85h4{8fnA0w39{?cEsOm?EFGRSxG%8?tu^Nao#zBd#Ls;wl#jWeN@78bJymkH3 z{I*Ss2ezGo?8DXIQ^IJ&_(|xdBz{1@6m!HCbA*Mn!CtV*h|D4NI1f&36);R z0bZ@xMBSclO{M}FuRk`M15jUa)nK(JgD_-4=bol_SSXjDsa}HeC*l)6e2p~OM~7eD z72*cpagPqasF)Lvh9eygzXYNg*J^r4cMiW`J_45ZC>8N=I42inAdlK_9)1BlhQ5B3 zj!fKN1fS|_bi*EXegmJA;Sc<-j0J~3(RFqqof>@CPbSd1M~P^NzlGa7|6%k@jF|o# z(Y3VM;IHHQoeqCZ)mzGF*E%e(ouZkQ%6?fH6%i19)cHHS<-+0X7&`>VgO9`?ct`CY z$FJrMoxh7efzjhX!pA$EAMfFr^nTOjx}jJXSlq}Pojscrjr z;@VB#1UBpW4?vTVs$c8xdk5=S9-Kz!WMJMbxjmTpOS|^c){@`r*X+7cZ!bGbgW9=jN8zAd z>6FW0&H+IhoDoILuK5Kl6=b6J=K9DJ?C0n248TnY3bNL@YT8B3Wxit};&Hlzp3R^@ z0U44mZ39FYMyu$x^}fmWURAe*O+HsG{Z3H%kT!$uBb5@UJH3;@HP^$|#Nsjpr&yG@H+|1RjU+n^9`n-+21DPxMdUC1(?%BGT~ z@WwVhj>6)%UVQ~SEB@zKl|rr5TrI2_&1K}wZnbcwQCY6)fiLiP zb65iBh;^@%lnJbh_C3+d_5Ar!O&Vz&3tSkOZloH`^ z>TsazA%3tQh~3iEHCJA#Dc0FuBhD&jSvb2ge*E78QkCv8q7-3 zG-rM|-cjabN{{z-7sO$=Mw*YotsXi^!&#*vS9jM)#!*Z`@=ocn288#=fifbGUmceh{Bf+LIN*2bufuOmlw=+Je*{JCmf7fJij3!TQLrByy7K zgw#HT5=I;VZeV^Zk)u>D;NEFE10X$qGqBZ3|qSp6U+Z)1q=4CL^SP zBn0vqy9}@QbtDi|*P&oKNG#k$21+3j3o64ms~c3#N+O!UqJ<=hJVkj<_Yts?tdfOX zQNVH&>Fgm552}Zhr_5rRZk)72VP~QWNQ30vl7TC#aJuQL>{R~FCfW)VDECT$h#Edq zYvPN_?Stkq@$;kqpS|~cawNOX#AZopDbAos|h541dvrgCMGjc)iu<}A=?iQZ%621TPsC4!m+P@v>!M0W7~J@?#m&-p$Q-Gm^}Bm?MO#r`7A zW}TBZv)-Aq$0JN9)?W7#c8&b3I|;Gb7&=ZrJ#jg5(l2|UT2&S;nY&ml4HAZU^YNx1 zHVH)r4jC?(?Y`4KBCTWGX5Bw62NN8(1g9J`+$pi(ZY1X z!3ftUBhT?n*Yd+Ef33P9?<~i+FX1H?{+m*0$sOv3X${54;;XUh$y`n8lLHUz+>U;m zdTenYoy7M{$o(QTm^7R0oFXrX(UtLf5l@;CyNL-3C1hP&TP=F$oQ~ouCY&|H_HLSom zijD!NwgtjYQW$Z!VV*3q6stVK#QgXv>@Rx`6>IEU~yy5UV{^%p9FON28s^U^v`SarDjP+wdUju2@2>NK?w!oCdPZIGy zh!%9ryDVI=fnQ3q(jnIKxAh$aoqgdPMCUaa{u`_?bH=`NxGqV%X2-r?q6YlwL@40Z z&%)vA>B(vB(a&yNE(tr@8?1t@HyisdVZ$C)cC}qAeS*ckbgA041^br)@3cs19@7xP zJbJ2{@=WEDfJ(>wh5&K(+ofvdpOu~o=PnroOF#Ogv_x(90f?AKR_pXqwdAU$Mn>f- z*n{>M$rx%UVl2#9NHLBL`?!bn*h|&KpXxaV*+T@k@X57K%c|K+PfK^r94tKp6TIz} zmyqiOx=}Q<<2)~8XfIW3Z^4DcRhaw5sS%vo94w3mQC0YMxxMR!?q^QDyt;C!TD-cv ziQE!4gyshniWX8m>_+u4=jJks?@!`(q$HJ)Zo!cg)Jr~;58DnvH*C>MdwN^Qm1A(Z zRMAhYq=BkU&j)tP8JMXm%{?q zx!T&^+UkIh>S}kRvaz~>2)@?lT4i&)y>7Q!t(A3qJDXARKO?$zc1FqHerk!aQ+oC$_jL$UvjL^&BJ;gHO4tAFTgAEM>o|Y+39Sk@QJKCXcH@r+vLzInWj zd~Mc~lXc*kvX)S{*c)(gh7(UmH_h)DLv+bKd>CQ~c;hbOB)QP0?gb5Qc7 zrxGvD!Gs$p*~Y{-YS)N)ovxGij$}GS|CG2KRP~k5p$OPgF<;8?DN>rw361#8CT)0~ zeN_=`k)*}^e+YH>(qk4fs2>to!fFT)!ervnT=o04#2K7d$)C&{@HvgSx0MR`&u8QQ za2jWCCHIy7(=4`L#^0O!%3qs~DVT_ooE;sU`-a^|NaGh5znuH#-kBr9dSPMzqWJ3k zxATjM0MC6pZztjTZxExN`)1z!0;1@1-^e?RY+`W5xpDpr3l~KB=f0gc-ZT#ZaWk)I z9)9WOR~ZQdCXUq)&8G}-vvR=Xz9rj;2RSPaH%`i6mdBJKnfs>w;qmmbeC{j#Zggg# zYVPZP^=CI`gf=WJoSP7I2_`$8_2*E2ust%Sy7heHy$M9e&n`vbfu}ZI_+4HY*ID76urPyGHLExc1NXo1C*S` z>%!~iy5_!}*G)q6>t*A<-S)k`;JbhK-Mj_gJysOZ+%lgyEjjs(9Dr;gLHVSwx6)(e z_9F@Z=IxJ|Eq~tu48I#r@vB~n2!K|Atc!-?y(Y3m>MOIo)3JC$vIWq_QhU1nU--dn zx*{{`We_wzgm=~khiK-WA_+H6crgi-Z%~h{H-5F zqj0BI6BrVt*hDrcL58)V({b%e4*?`ja9UGTS}dT(M|E}h_oB-0$x7}a}>;&?x-0Ztf*NW?5ebfbT7$CR)!gmJN&+O5__V@&E`e5L<07JCb z?c(_`zVq=oL|OM-bK4!)1K600JL9tKV;4n!G;o0#VQ%{f$Wj1$00@J*?Pfm!0KrZF zxw++G06Yh<^O+m=yiVYpSO*8=wUyPa8~$hN)3ybt3t*3;zIkxpY4<%J^jxR$vwz`u zfM!4~9ylk$M{VxC=b$g++ipP$ttU?3Qys--8)VJ+o+o58z6pSbwjBV}<3n&;aQYD; zKHM9PtOvF~bkSQt{Z4*0ZTSno@8OZ2g8?vActlPz;ElxX?ASx=z8?~ZASvN4c(m;v zAZ)DLScI+Hy`+GL0eZF_H+Gp=a4x>zcLCxs05%R_)Z+1(zFBwk-oSZoJqEGbAo|Qy zjZ%bU#MCHJXnygK4c-H|+^L}4?E6D&Z{PwQC8_QmyX~}m|HyjaBDK+mbVK?EA)24u zqb2Ib7$|(eZqWfRd;KALbZ=0(W%tQqiMR2krk_7>yuG_5eH491IR&W2Llj_-aW8}y z?R7#>Mk;K6-1`W5X?6e%n{+XE_U=A1rEuzma7;RwI4jky)$Nt-?KNBr?2|?^rM&TA z@cFWpn!ay1$KH6#GnuLKSv<$TU={FJs)wbUe@-@U>ydq0xq-$8h9GijGWS05gQLLrhoQR6K_QyUJ&ch7T>`2M9L2-o*mHqC_qgwm z)V)%Us*8Mlh*^)>n<;)`P>6=eMYLni38K)wKa^ zjypB?6mAdZ`!VDfU)lj?zueHZhc2pt+wIXv-3B65zfFDt512#8&cGjWeulp2T<1CT zs_OvlF%*J!HhqZRM}8ZSa+Jc{08q{`pJ_R#K6-!cmK6f=2e3k@?THLDJ6=x8cgs0OcC(=Rpzm}| zqgY8-)d**#t2eNr|3Y&Oi2(#HX{kzsC8!y|zBj40jxr6Pm1$Hy@8(r26hV(8L%P8QiiN_$BKpU;1puI^KayL0CIZ z_tfjiQhxX6Sk0ZNf^MqB3wfm-viwSf@+*F~!ojO_wOmckaG+#@Rj^}y>|v}hU>Jd< zqEP!>E+DuVTLNlM-g*<$41H|v5&EVrYkW6eynSs5=q3V%TCek#FS3N^WLm+L(919c zPM(I0K&Vh5;1S8B`G!#lg)iIH6v{V^XX2D|LKqX;`A^^DX7(C3$+7I~V|9Bj^?`K{eFBzg3_D;B@cDOU>e{@84k!d z&k$=DS!oz5*}_lufSL^L0cLAQeWuW3Z68vX4ivj9=Lk~J=G?NVFJ=o46P?l2Rjrch_s#v^?`mx8EE_=)C8O~Y?dv}qGdNrrZFpltq0sd zsU3G8gxo_XRP4$~Q@ew0p;v>}S+A{Z*VZ=G zL;>qUsEnRuV^e|BItnYcTY(aR#d1USBd7csld0eJEHdfzw&LCGaZT7L#H? zIluDpJK0@l%Ft@8Qogkdyvy3R2?mTuQ8W4@qv6<+{H-2CqoeB;6nd{MS$xPNKzPb_s`WrX&heIsv&El&b&=?P9Qdsnrc5d34zQp|3()@dqG zOxGRp_8Qj`c%87OV~c{b85M3l#RCd|>TfijJG2#gqal4z_6*Q5LZ3Wqw{ER!C}JKf zYla|U{!#hC=C1YWyQm6NH~q+3v+8wgg{ah?^&@LtzD+-tE*#M?S5*;k?_rbcT0h4B zP$@6{@?rtu0NyV|F8W75CSzP4zO}Ow|D7WTJn(s6W|3;<7>wSJXog z9(-9#SC<83E1GokcxXDBZ|8riJk(-Um7%VpW?lUg+Lvy(`CZo*?@yj%WmHK9GCyem zB)&kcH^BEr5@dl74dnkI1l^$Kw|ITqP}U$UI(i8z?81vpuCK$UPQ|U{(=L41nzj;X zKV02d&3oMs?}M*B$w_z%{rgt=gl^`}T74}(A*v)CgbV9vmM0-nl#Vfc7IY3TDLUuZ zN$@s7F;Dm5gum(Iu+WR{M$WJtosOJ(DZ*901OL=ZSA@8M9;9PJEOa~KB^K73T-b@t$>hHKD`s&wc4rrY8g{3M-^ z^Jai2ICX^!lCI%`TWJ8-epb{Nh&FMF5o=}=^-vGmb_T2cVo9 z(6$*DCgqi^*RSotWC2vMuV|&d_${sgz_HcGPhg0B@y`)(<{gDECtaB@zJb${032#B zAH4W&IjDZw|8~mN`C>sXinH})|J@hAjp(w-ewp=desdKdxxdAg=H=n{@wtB`v19mM zL2tbH9fS&E1#0nK|02ak^zuP+`@6XP@K54rk{|vkzLs^xeh1ed9P-ypy`_x)#v#j_ zuB_Bj{!F?%ljrlykJrA`N`65|9QkbAH#0~aDKkBv)qVFQJl&p5pzO3q zNA2z0*Zof#-P)a>J^49|x?kYz1)&Bw$*;D<6k$XTU zN45FD#*jmq`-Uv<;J6R5vYMt-6EBJs!sTNSFt{~EyK>)}6}2VT1ey$?!%mPpY8B+2 z$lzL)n|aI5eT#k{r%+sC5XN&U7W^qRa7KJE7?M$hh`HQXo-wW@*E^Uge2omwTC-aBr52@HMkk83mfS;jC`8)t4gVI z1xMg++ZiDm5IXm0$4Wau5oR3!o_i^LqFTW50NFD_hq<`#O zDc~jL-p&0`{}JPoN1cTQi06*Rim~dsul9SWGh*xQP6K<;@-+OD23N{`JO26R>0xI* zjfRp>CHMOqqqO%T_x-xq^J@FGXgE^-m08}4+_#}F{uO~;Vepzq4#28rZb*TB;3A`8 z%ODG6xRALs_sx4yRsQgn!>a3*b83-MI!QHZabJ$Ou#{vu>IF0;_wD_&X;>3!mc?e} zzV_GDCUc_W8Mwx^&}@4=Fmy^rE_3$8=+1q^{)mY*$kRZIdymF9qQ(5+EnA(xyzum4 z_CZPN&sbUCTF@A=Nswh2VuVG7$+(pFGyV&<3b54@zVg;Xx@0nPGtH=Ns-{~01eaK<# z051jG$1f7!Jc}M~jtge{+Zj-^e>RY~_PDFHEB0seq1hhov>zkxjx+qlb9!SBJmZed zdaLGkC0^vHJI4(+?PNOe&h#>++x|K}oC6O?9O8FQxj-&*k-Vt`fNDWGTo-NRDv@rJInhk}$;+Qia-# z>9{~>iBGNR@PIdt$v}7vnYrdkggZ(yUlD^<#9+O}OaaD39sWN5d<%aj!>$g`4O@Em z%{LB{AxmF$NY&q@V#E$5{_A%onwjCvFAx928iT-I{2s#LLck41b~FxO_WyOVk>L%8 z{}F#QE7RGrR=@U&OJ(KHi}e``g2CNC3&H-SG^77tzfRkJEpcR1Ba>?2_ZAkeSoavP zP4nmG<6p?au%MT@%hi-~{l=H7Dc{Uc2wbYFe=Flp?s=E0@_#tPw|uD@@Wbgiz9r6Z zB!j?eQn>`BOVy(CCouD7(Y!)OJ=N?1$lV=vE>)}kWi|2}9c;yEuEPCqT4Hz*E>&ax z-@0OLfSkq5xoTwOBpC)kdyJ?b6(C@&_tm3FZJ^Qmg@&s$HdW z>8^>=25|#hkq{-zSH&D~nHqKYPdL#?Z602HLuW+3eDTB0)$R6rYpq>bch=S`8(UYq zm949-PGx<|zUs8Q>)TtcHKet~X_GGx|DPWq^W=A9*m7X^y!b78eP90N-+t|#cV5Gs zKi5D$*W}C?aT8|I3`1j{rF-7R@Pg&#tE{l!Kn2dPROX$gVX{g5yLD`U|ABx09)I*M zm>c5$KPESwy-R-0bHP_goqDT>m;d{>io?s-@vAb`@FqMkWvx@|rQMG|zI*FBe50|_ ztiMjqW2|8l@Qu<8?Ml!33%dAee?rxfV!{_Xn@8+Y#ByM28TE^t2gut55lzoh-VNe&*E6t1HW! zj85QhYM z(D;z5ZG>;zhz1$j&l{0{1oZs+3PGAj@RbvspaDRAP?Mb2SF6Cnlxjst7#X5SVs^?E z+1em#1d_|k+ylv%vihO#gYBojE7#?7m4Ok61uWttiued%eHV~3zemV(30Ps;lETH= zm^YfV1~P|Q*9YTLkpEQH->(I&+NV0LY%~8@4Zp{h?rVLC zL2*iRhHvM74AwNFyKLGV8x)rzU_BJuQ5>nQV#NVK2I$Goa_-wy6YE>T%T1KK#w3{? z0-yT^{cLuS{yd;K6CwHw3%PIXx2IAFa$n_&AWftL{o|=KBgrB6&AF+BhB&qJgW^nN zVdTD%x8{YMIWJEn_pMyB5ZnJsnJoEN5FdTPsW!PE#MO8{63}IyT%g=H=`mACVnCNS z%~n!yDYg>_VmtN_Px1p z$REZ#^JL$f`%3@WY%o{_R+9VL|9%z>Huv@YUJ6bniKJH1C6S-|>TjPH2d)G4)NGzS z4$6Jg>QF(5PxZ&6)@gbEKyFE)9poQ7>Dn0wWD2h5%rml5?#FFY!c1qK;U!0nCH$;U z@Jc>HkuhkwZ`Y5lNecY4oFTb;7UbU1{<(rfl_wY zP}dJAB#2{*Y=k@yYw~sddb1&33d?g&tgbzD5f_A7B3RNHg!J*^j0iMltyAkh9<=uE zLQWxs*w2IE42VZ#5U`2pBIraSTf8=rYvqy*+nO%*z)Om?+kqbvRiqi%9w0~XOTq!r za=dn*CQz7Ey+7{t5FpdF+YahpV;d?`{~Bvmkr!1c|5sY5ZiSp_fT;7FPDM2Ytwh(} z90z0>Knvln58x)n|DqE=^=`&vg{+P=R*JROcPz{+V)tHKxlu*X6rP4(CqigT;MxQ0 zM1#O|F${QC^#-0`S*joL>izhIAcR9t4^cY^2U{Nk{wX?f9M4kyRk^0#Cf{UEt2RK0 z4!nxG$xQXoYRWzU4OJxU$^3|i-433+$5lV*)qs;-TU%ebT3uaV+qfzt{|f5I>IVKW zsbjV-eF2FXVD^Hm?$~eJE!F<=>e|-w+SN@1Z^*t~Ut7l6b-Fk$Zip$HYG0ZiLc*5N zt6;-J&*`cdQ7tzk_ekzY#HQy){c%gA-Dh}{TQm1eG`<-^E+BW#$OX{$%mRA8-y1l! z%#A1|UFUfx@1mZ(YZ%gVCvO78{+rurYR#fD(9$EUheN01GPSvbJZ_KR?GPZ~7J_#E z-b37YiV&Ez5Ma*Cl%2lY!^E?w6s%)=pfJ`liPO+&y5wfyM*^_!hY}EnsqG9~PKOZP zDOEHvomN*isw>-Dn;Vb?PSC&NpAVb}$t8ftY!kJexNh-eu5iT<#_b68o#Q{2b_dYm z8I=P=KGbbIgC{oB=Hhm#fW>``YXT^d)odf+_(BO3S3hNFbIYrOzU z2p<9~-4+yt*hkgIrYPmOS`&*5;(R%XVNFF#q7rx!|F2pVc=L)vt>2+^^?98;LH2vn zr>WMl8_YU&;4RLz$QwODBKb)@0fzN>k>6>?qo{@%iPE-NwLfIfLs! zWaIzsBUDrX1k6H|((sAU&L^mqij)X>kSeTkaf`G-1`=pQI zfH5%~$&}%!V)?G<_4~jRnXFomT^bhrHC6BlvDo9a9$0LkMUt7K%8OqDblt8%pq|(y z{shk97|jP%0$GP>uPC9FR|$DX37~F9)On!F_aaIcA553Q*0Fq4c?c0tnLaWBq=rDD zu&dTbcrrL~LkB^)C__y!nMsG^Ffva9=S|!Fr1pb!5&z$q{B9f4HMC)t1(5Jl+1J_w zx96$$iiA^V0><8;%iudBEXEYuQ5xZht(qy{h%Jre64=1O3P51UrAHPI9AI@em@{bRXbB?>W%{*0d9QK!zMbp&ZBwOzfrLgoy=12l+ZHz<#)6P#OmR(f24l(vT6J@hO7eh=&e+px z8rvdKu<8{YIA~ZX*dB_UP_onA!?Ezk07A!xjfM*!gMkw`(1Wo46oeX0I8}N)B4?=J zs`Y{60m>3mBY8tft2l76ZWb++yhF?=^@7RCD6&G^b7EB?gfFWJMFImWW1(@1V^1E+ zqQmYuyLcl;4OM!>G_P?SHnd*U`5K}R_Y-lRs7`3Tmnc#hqj^_uWrvC$QWGe|GILjv z4`JL58x5Clj18j1AU{DR(PGg!5W@`Xf$h1Nq|#%!`xKD&LnH>tN-nQGj!Z~%C-WC-=jS$cae%UHKSqY zo^QLeK~KaQ@!{5@Q5Y|J@TbtnVvk1nJ5jjqH^lk7P9%PqL}kDyC3$1QBuYn-R(27M zUTmIx|A?IO#OA)opCzriV$4#JG^EsJO5? zp!L2+zmN|+H1(}MuO87 z7MR&{a^poCQU;D=NO6yRbQ){JAx958HXaC_LAMgSW8&d&_kDRiO|z$qpK{h8E-qV( zNAag)^NH$e5yLVXN9xiu^BNezSo!Qh=(EvEmKxI0fIk}!Ms=R@&|VZNi+@pNsUIOD zSrPQ1>CtUyu^p(^=xsKh3TYgQjw1$ex?NHud2>8Snei^mZ|DY(qX>H@tfyP8+xkq# z6Q-V7OIZQSBESY0gPrc!Ywt7@NouUkJ~(!si`wUn7V>wNb zIS%{74>0ky3kmK-?8~TCsyJ-OkjR_U2Bt4c-sLUMe{lts+4{`aBf6~M${H_6%9^vDI!^ixapeV7dLzb&jv=&@3#WA=JW)P=ma`I6egUdO8aSU#P zQba!1^np%s3|<_A4-JYM&N{L2W0XPNY%Ypp@b&nlnrBPJF*xJeieqpcJ5(Hls~92# zO%%uAStGtU2Irx8aSUD@gBQo(j}azlznyaI})FCx2&lnV#zY+@gDbEm6 zN73?>hgjr#37$KU4}z$TQ6J9G4^DA^=2ZHw+<|~}l_3_w*#`qIzBhgT{W%@(XTEAO zeq!=Pzv(CL#XmgL?I)ULPXz+ zW7`gokcaX-VpxzIOv5dqSBRT&lF0qbc$OV^Lbij7jPA*!>~&||PA7X&4w%;`@&rEw za7LIS?A0Ee*r&)B&WS(dc+FTrp01`1uows2q5An)CXBiJV2guJvZ1=!ra-%;-6#Ybiw(f7(ekwLQ zEe|TrcH)6_MEAORN+P(|RVD&cuvGvy5*}4P0)|n?XQ%EdFV>>rXfj1V&Va2Ue;!%= z_CRG=vQ!mKPMSK#|8_zYnyzkHUFUD{d+YJ1R4Ray$@=0U@U7D+0*QRq7x}q1Je8?Y zoxD+mw!SFoE$IR>0;7ZpCBYx)_r}hdH;QD{6Zz3KHBrx*Q2SGRI53@i1sP$S?+E-? zEsxs@F<>uP79<+O>LHP;v4c)AD@$e!Rd9Z4V9dh=E8ekQZ;(tKwRl}rAtQwub!6(H zhHJ;-D41)>Q0>TM%nX&eNrnmSCfI|yHe-lTf*zuoH_7nqV7jU4&6cHN(b>yPDdZF% zAySO`ih4|k>>?4WC-57h;1Hy4cZ{}8QuiiOizTDW^hoV^t-1!LmYU<$Mt1uMp}~#7 z(OFY9mIqq``#Yp)biymfFGpd!hl+L%>1Js%sXi&#cMW@QNKnkQB zs5?VCaB-}T|3_XAQY57z%)LTdY_daCWg4h>t?OvzP&u+z(0@?$l1pOkP^5RX>Suhj z5@N(ZOCUBAK2&-7M($@NDOshFi5i#03TA>Lc6uV!NpdQ!6KY4KBq4?MRF4dRNw~pf zmEx&_b8(eCeBvB{g(s6{rp}3R-jjYn_Yb-YsZQ)swKH)pdHAXQRXF@*9NLSg^_ol$J_w;Ehb4%1~vtg zFmHl}$#I{=!noG4SK6sOEKEq1$HJT(CRC|Zc3BSV=lqAb5vCRHtF%IW?o0WT6rKa` zoJZ?a1Tr;LcC=XJ2+~G!50ZQ>yTz2Lrep%e7y=VfW~(ckK!@1eBG?M-p=3H$965@H z+7@}#S&xy^?t3nF0T^9M7~$FEUFKivAP#%1=w+~UkDz?rK9M6e6Lm_Lo>%q&lujM! zE&wknG%2Y*raoV1vg2W~AoLYF70>~EfzIVT@X%~zy`KPjg-LN{Br*n^nwqTV;dnUW z(>qXRJF1)X6BHo`jtlgvwC%SmPEz%Q0V=@c6=h6xy`3Ekc|S^TKpc3f;zIHzCmlcT z_`tq^qSwH z%C!Tn@@1IgR_>baFe8~fdOwEgh^2!r59*raaed{yr#YH^j1P8@D(r_V1{Ap#I7#j! zn3A3i3JGJ^+^ljElk$SavD;b_=s%zYDyJL?cWXdw#2#{{Ff>X63 zBbK~wAXf>_&;zUqRzB=JXxZ2;EJWCdRDhOs1pO|8r9f(!(-;7LK(=&=5SY}xE(FVS zB<%=V6B$NF&@AX90-!h!v98!*`X{VOfkWgK3VB?^5NY)kO?1rAN2;?j40Hyo%6>$V zs9DHm68iwPh#}Sp02PutNjwV9C6u783XD6~b-p`pmT3qILjn~&CpzI!r6h8-J#+-z zMy8Xf;q+^z$!NkPCLBo=2x8sJ`bQ_=^Sde<4 zk)Ij(&w((aTtXMT=bnD7k$DU+s#11uoTk)PvNBj@Kmhoo5mHi_#+trImVTnZr9@!~ z(!*It^-c}cmgRvk9_mPe>Jq{OR3U}51eipd7Kx!19WPZGm>1dqmiU^^z- zXA*3u+ga&urVNoL1ssX2@I8ohWAh)L*dq}v$_{418KxbxU#lah8&x@>?n$O?6Q!Ve z%_dg$MhB_0lJo~B1P6^aPj3LEJit;lASIaTEiriHr~Qv^eWdTYrG6WOtx0}LoxcJ+%Wti%gAK zD>zKlx-NSRtI2}XgCu%i=8SBOATm&SHP*A*kA?s&LVutZQ>~!YIIpE?26!@@YtqtO z+58bDlJYN7sqFe#5u1@Qsmh$i#=3$+=>X59O^89gfpAOQv7b--R&y$F3lD-8`%ZIBL-;ZO#-x~djZ84hXh`KI2)>Y9?*)JG2O9r}j| zixX5bI2Oc4uVd!A=KG7N+&v>-$ zWo(lIxkjt^#qd;<)+t0nRgmVD=wZTWe(><)&??KqjE1ppzj(BFU*-}JA%J@kS*x2L z+*mTIC*$^ljg$pZW5p^J&%+WFTC4ns)vyhg+MvN})*4KQR5z!!4Q^Kc28|d|yLLlF zRja7<%uNl7Z>dRyWst&72e>#Z&{)jFK({y!CC?0rcA;=x#0=`dAE)MygN-H@I1CuQ z)Eq747)j`xv^Js}C#+b{vPf+)~eIBL{sTyJJ`<6mAg?uAe7RnNsC_ zl#krIHVi@Zu$fP?@tn2SQxnKEo~|L_+@dp1VaqBA!ey%ky$2OY{5P{pPi+BhtA#V1 zNk|xUFyccX$O;)IZBy%>I&%g!^$?g5$V}D5Lw&`%FBamSc7bAtXes@RInLh8c&FuU zgEZ!frRH!N9%KjDKP3f=a)3k6gOY*>0Ry`#Q3|2m4OHIL6?-u1+dI%NyjHDBy`KXZd~tMEm(T=I^BZlmv&#$n{!bSF`~+P zBQ9skV!S}B(q$&fK0D?L(5caJj)`HH)tl?JEu}Xb*}D!7*vXiH$T`ZGt$MniAuRI1 zEV-EOx=e%BD4Q4U2pc)yq@23!PXd%-hO3>sa^|M&8ZpSlIiZd=6&9QrDZ8VsQ)ZD|;YP1%3IQc{XCF8Nay-K6$aCP}kt z3eu)N^d8hFcM#4o7G%+!+3nO1W_4_`VE&qhHj5n;qY9-*Ut}pgdsE;(F{06;0r|0} z9_2i)uWnBNAk(?NzLxpLh=2kxN*88&w83GKpJ(-0qPN~m6sJ1I$Rsu1RF^=Zod@$Y zt=5zdGbJg#whqT9OE+DReq*Nb<_Fz=vvSJQ9}~V%q!$=e9h%h8u0Zz_{}T3ooJonL zq6`Bb9ZeolB>PxCV)n7<(_&XVwM*9Hu$SLmaRHDeVXrskl)Ws`wZLe@YFOW8IP6XN zT(yDrzhe~uS*Imv7<3DLM8i~6vaGlH0mx#w?l)I~^z{4u^DX?D!o~UyEKMm@xkE__&14{Wm$(TcM=ziZ=Z#Wb#C1@ zF09+(zxkasF4kPtW0k+mI==WWz=PFcBFxrR%5&%)O2+yez3IVP!@Z37jbcw{`ibmWse!xD={!JX$(V z6S2Q=R?+3Df}wDDQ3U2%igYCLc9^a+A-3rrRNK8GFt-TIy`LhE0g7nlu0G>AGkTg^ zPWlS8cxjK@gfDhl3X8y85X%*TxkX^^8POY{L#!5oxt*QKa0$j_h||*?c&8!(&JV7| z*?tk2YeGkgz}zA*_l#)fA~2UHxJ6)Y5tz%vt0FKLXGwB^nF^XM0&{n)A~1LA^ieM4 z{|NF7y1_|Hvk1&B0&|PNT*=eWjI&c|V?|)D%4CegVT-_A$+Oh%YV_v*xNN)WY$w}D=DMYsi z2pBRUL8X0%t}e%LTH|NQr8T!0EW~F^ji+TK^M}B}LKZb)2yBu##8A3ID~?nwB*Y#9ZtJ`ZUn-!tSqL%%COm312^Ws#*{{$hgME!rUVfAk{s{7yX7g60sRQJap-@R2tbmCyRf$P}bx0$RC%TQ1<13%KP1ZW-~Q1>AB0x7;Y;mZu3i3b^G0Zkf^WG3rGY zBm32nw5L#or(uq#u!Re_<*6EE0IitE?EvCJMpzb%0N++=K zP3(Wm0RJB}+)ll;J72hyp#To+zbZ+*AyAS_X9OI6bs6pr)$1g~{bZhhfha{b8gdEI zc^4<)ktf1f8%+EbA{E0yVF+!j2VQ|FW$3jEM5zK%N@&t0*SDa0CGC}BfkmoULG@Zt zy=vNVSUX=yM5&87=M{4&mfiGP3y!n1PEgc!o})bBdK|CZF?*$EzLTx~WZ}XNW`oQw zaGmIs#BvFpGcqE(ZVxoh%s(J4-aRKGPaLT_VG0~LSO}vOA zBO|#T-^(o{Q=3q-5bk9dyugat_i>%kH|GFSuNfF?QMPN1YprEPh7^BSMO?9NjNL)U z)Xlu!_D)rgDC%myjATxV2hpl)CP$Q71|cnfy<(AO4}8q_cmSSu&6Fqfy9rDItAQ3$ zzU>IH5oifaDl&qlYQ?g^6?ZrWL8XBy7oKNFQ~YW+Z9tlfGgy+qIEIS-x~gi!AxCDI z&|hXbsN>-WuZ+AN8IzP+^+Lo4IkNQbE+uUZaxx_7nMHDY#PonnmlQpog#?2u8^Rdkkm=7OnJ=(9y!RPRDC z70d=^H0T`h1!Q!>;W#)&S5HsOgaPh~^)Mj+FI%N(No4$}BCt; ze*HRlD^XB6nR-@$Wqz$ z8ePYZ#z@YtZ>(%@E_2PDywq~-uzm*;?MUe;=164zjf+vlb8lQsY8t+ASzuakI3PV2 zHrNowJ@O;4dq4C;O_gvv{*j8#vSfBpLnR}Obath~^!UljAxcS85oX6SnW3*cmNCnl z9%hVCC-6t;7c}6O`cxj(SE?(^5U|m}26 z-33K=LD4vrV)?OHnhupdd@pxiMV<)2c4*NEC z?y%HB5ik1&C)o@;Zm%DOLOp*)_6%zC+Ht`qAAv=S-b_9_gq?+5obV8eTfIc@JCE&w3nC@> zAykzbaG5l~d!|b#43e;)l$WgRmNX$rp0|kWO%bk-JP@&KYG&O^Hkfi`4tune2*=tW z^p#fv;y{0Z??FtYm8q>Pev5agMuLHF6GiCcslDsW$fmT2PdkB<#*UnB)EGzZ0K+vL z`9Wm$oT#BQbM)pI;)H8)h4fY9)w$!)QG?yTg0~N~&k0?iWL#zydD_8D?YCWwjq+hh zqZ0vFP+xEyO}}6HC8V@?cl8)u7dW4eG10-70zBDWK_mRDD>-$W|l+T&)wS;DKVl!IWQy_=KPcm6S-PTnFgCAktZlAr z1Al0`rW>o<8|y0@NeSt?p;nt0y>3c>nloEeE7tWYet>g7rL?RvbXy0Ma4tZqv?~g} zJ7-tMS}8Vj&;`9s9V;$PQ41qX8Ll2`JOXFn9NS#ulI3n>NBt_^rL(gVxA59zrM%` zFRpm1lsslMysA6o>IG(wo<8*Ems?BH(?f+*tBwL}7z?m(y2@VY+d=09gCoPRk5Pdg z(spFkZu`TbIun5U4aQJvO7`Ng16j^v*DDv)uHDA>Q|ddeCgHLLTu-h{L;Eydn7CX9 zF0C}>+r+E0Cm7=9r1jt*S>XB!eR#M~U&@SL;zhnqJz%ZSm=FZfCT%pFj!1LhM$VjF zTv9tYHb+2uH07-Sxy;00VA%Xam^eHU(x*8V1GU+2Tj-3(?8Btv^*u7R`t~s$h+}5C z2(=P)0HRGWbz3mwx-M2#WZq965>S1rBLYjG4$vUu5M_PLYL&#}uGfaa%Mcb$eO3(@ zS2tX{O*NzJ09r zus3BkRw|wcz~#_dweS(+-)>-DHF(WhQ>*=~8G@VD6w!xXwQDy-@oJ=Iy(6G^pQmlK z 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 N&$q?%6!DJA{{i=J6AJ(U literal 684331 zcmeFa%X1{jc_-LpcZ($05=luE$tFcPQQgc0iA-eT4X99B)TH+4l8Ld^9OL|GCWX+Hqq90Ph+!t z-^2dC&%@)94?Maa33Nv{iO!6S@c7*Q^UuGR|Gxk3wZEDF))!u(e?C4g|Hd45bxUSJL=I+qn%0jhXS-oD_^1>+SnNew0Jbu^@BiXqt!_a8Ua^SmiqZINr{A&7M zB)w>(^fSLFj6e!Q*wXE`daf|S&6ubQ zwh{3g495%cO^QQ5u-54fuCJec8g1P3JvsAart!F33S`*zy-+qAH^BZgh>n=!E#`VSMF2Unrx?MkL$)jcvbsU;p+nzF3a>U35J1yNxa$#fWqzZtn$h zqgJieYIR(r-|%e>{p}b}8+y>O#8D+1Y-krO$-*XT;maHIZ4y;_^WeIP3eq|rf> z+d)tAmB{zq1_rj}wCOUw-QX`}^@Hs@rrfy7*ZFhR=tcgzDA9jP*N6^0-wpguH;RXW zM`%{4S!;CER5qH@HVzy=*tnXT;_LC{s?i0p819n#P`aiF9&R2~CZkNh(%3$JGV|mZ zjCS-I4czh3SK88}0rP|7qu(&?p0^(!Kf%v$G50mVDCR!i=!8|rYsrA-KmBxk^n)AV zg&XLSi-GjL2k|sxb})E1sJY|6KA!mte&d%L4a+g3MuWe72|OM+W_Wz>=yiDj);hMo zboAZP&E4YPbwlT=8mE(Zp>d++F5 znX4^Fx>nc-C5^;i9hdFte{=M^ncusCa{zv)=X%YfFS~vlJkz9c`f5n5jFAm}4?o&( z-Lv1O2EJ*3_utqh+?`(fnz~?rMU6cVnf+V$?62A1$X@xT{jH-fqxm-0XUGF%f7kwg z_KsKWY4q&XZCf6vtxw0Tm+#p#c{=QwPff|<=vQA8W)J=D$UuZ0$CZ{aJWGUzV~J@N zIMY~IEQDHtgLUEd1#XALGhG?%S6?*M7(Xx!vA-NYe)g5oV|O&2<-U#&o(!vescIRK zLA(vtn|g?8f1qX^T>MpZvf;NHkZ~TrGHn}-Fm?iD?@xALy2 zhtPI&XsbyzdjW(_ByQY#Pxviy7aOC1FoGoG1zPMf7ju`PUGS!CIUet>YKQcU4)(|E zJ;#k4k8Y?o1LHtK5)v0+Kg)il4bzgL88}_qST;%nyaGK!U`JwY0>6VFSbe}U48o0% zNRU&U5dAv=iI{i55kkz^iauAb;L-0%>iKRzOd+ zjGh~7Iv+#V;l0&<)qc%>9lPl1;`hywLT{YB$jjPilC%AKOpuD@Si&*r2~*3ypf=vHiWH-_g%wd_(zAU59-767RCo8jwwW`{~$SAW~Ow)^%+M_+ZI{$=;TRG^+j^jJxI`mEDdH-hXhv3Q%F zA+r8*LPXd%x>7TBDEUw z254%ZX3SWK-i-1K%P3Kasu^_%dr0P6VsjDSh8vGHTbE-#-Y8xD;DfE3*U)ytsOQ?B z5^l|GIHeKHTB4mnS&Z61%6FMw4=SD)U9su1QTk|_m(cXO7!Z6)(9DWyGAQ=(`{R$M zVF52J0JE!v~|bPx7~I;!!sS+nY0BP8%@6F!rDq& zdykz5&)pFmhK0>1rJPe!=`5i@=)yT^yX{z)$9I;>eHII?uT%TM7Dl# zTbj1#!<_3U&;CSuo&&2|+>?iJ<`|Z~_m0F^Cb!*$mLwiY8-}{RLAyVadmcH^n{ODA zZNkKz74M=k(w85>JP$X!U2)IwI}S!mI+;N4M_%+K)6@i1?? z@~LS}$hwzf8p zYk_e{UMO^y4cSYQFeW@GV>~mil(z03(tusqcN{2m68VcS3cUCZ!M8=^e}wWD-d` z;r9Xf@Wa=3n% z)@SIm%#}|eSK*wYX2@_OmvIN9e*j}m#-ejkbo>K)rYZYAMt}aMfb}QgsRgx%Mqml2 z11C^O?&xfLuCov4bgxZnW9%F{aDu3Z8GxtErKv(M$@wjsFg?+CyxfCpPRIk_#Xbj$ zF?KPfQ6i+PYKC*%)pntr$WUK{5`tcZT6Sg3(TBZm7hC{(OiUGQOmrOkLak=3(WET# z=;s&s3a#(8`GqsA@N@&+DPguCRw3}v->!4uM*=?1w#4K?>XV@A_VAe}8X6+d^iAu08DQjfOQU?NI8tUi9Ch3Tnf0b zp}trG{(sl+OBv2$x+Bq*KHiOI!LW`IKW=07$rcz9BNIXpfFlCQ?&OTuI|44$4?zw%>UE$$+sIk74xd|vK&j>e@0Z73{Y1AL zBJn4AU2r_1O|29VX|v>j3Jfp{ge3w_vrNAa`hrA+R-urvewb>5q~(KAp((mEx4WnX-<>48tVc4YLV0&8q>`Ob3c86O#>R4^Pxd&X%;$% z5{P$JFBO$WUumyJ)wi5_#U(X;UC)wzTruj{HX?2B zPa@23VOVGwRHJ>Ro9PS5C_<5s&;Yn!twUR?1663LP{9H ztneyOtV3J^?HvQ0ZWtg3Bw5V%w2^32XI4L)(GwY(%S+%9cc5s9!qi7Nci z^$)>u&~w^8=5aP-Ux{j!Nf;sJ1KA^2Da(_zYmh4t;Eo5Tj4HiuWqGO6biIm+03bvV zgbmT-5VJ%0IAMiIsF2{Q)asS_#X&K{GVXpd$z-?jRI6@*FFHNwHu&$@zTu6`__UvG z4Xw8kTZf7aVTf)Aj%D;QH%^DwhcB9lfTGVi0mAzyTq?rd7cAUOPM?hL|I;~oa>0R16o@z_$e;6U9*qddXJf_rfcu*| zfS!*Q|3U}DKgotLK2gruGsUuhW&iVFG~k!9Z#Ngq{?GU9U*==kzp@wYe;y#m{>1)d zFnAqPWB>cRTsn?O zr?F`J(O)0iKcfVS)OUW;z`=)YU$mg}qkzy6nxYPYL|vw1g+FZiu@2iYt>0%O2G*`;_qmZ=M^<9EA%Bh58;!PM9dQUrz~q zTg;1%jfqn89Z`cJjOlz^EPxhKO9pJBWPMvtS7u7ZhFF@KC{;fs=7-Z6cD*Bhg#Tj= zc*%gNW%0IfCQ9SCcoy}XmL2h9F+VeDE}PBp6^-HW?9xThx*?V)JH_)E>PS>fO_2nI z)41V9_J9~<|FxLx`uzh@V|fC73+rQ^KPwI;>enYbm{(~q=^tzu=_bvwm&C58Z&+itjPnR> zdQrS4&L}od5nR+D{qt!=$ERMrWC0;_t+WZUuLbrjod>N{P_noaq;7S@OEqGg@A zX^cP`dW;qL_&E|u>f?}1N}r3xoiko2rT32R1b3HpNp)vNF70?bNb(q=(5XA)9beSc z*I21iUou*iy1=g)RBY0p=x5a)X*T)m=wn8?$p1#qrP@XMn^G^Rr5$h77SA&3xu;W} zkq>oRB@!CdfgfwfdmKhcUksk?c-x3i%O=IB%N?JhNYW&~FGYI=(ng{g<~AI3lmZC^ z2q<2KceUrrYpVAxoC_4q!@%ewB!|;WPKOdm5K(k66nFW~dw#^}lDC3@yps2P1YW5H zK^fK-j!z^{mq6HDOxbi1lDd>3sWUQVE;Lp6Ba<_c=W+^OtP_vl62n0T3O{6GE-&){ z=4(rf^=y3Vg}nQPseZR#yI`u{yT~=8*+k}4ctAP-9w(Zrb=<^H(NI9?JVyr*CKwar zKBGX)N;E{ivNd%@+@a-7c?DBe3l>w? znyB;cYgMF*TMY>0^7I@MV<$??n{zE6*}g$IXMQ+$(6?9mb*o-~+Fo6)PnIq>d>V$f zXD*q*RjIYTx$U{A(={9ZhZCji_kX@`9n9VO@SP9dzvcY|DY?iuL^@v;vpGF8+1SA1 z74g773}bKg^gYfOp&aG_S9y2CDWqNpNs*LbicDo%5fdHE`E?{bTCHkm8(lerg?d8~ zsJjq<)p^(xr?*VtMntnKy)x*I$8#nnovq_=vV2fgzKrP+qo?W5&^}pOr}dl*i}6SF z%-@UwNig*j<k>;9JuPm=xtChvYwS`J^!CI))TFvFv z1!ED1=ds-XZtuS$x?&^RviJYu!=L;s{5j*UIk0by-#Nz1?h~cwr;%Uhmmqo#oVJF~ zw~9{Z<5M{4GZ_l`pDtP`q_Bsd$sYc!2YN;b!W}PTKOoeh42X;<%z7GT=x$QNbU@*Z zT3AksQ5*5zoiua8UOp(t(#MrDa+WqS`atG!waF#VXZGZiWmyq2DMBWf8MLzSGQlx4 z3chh-_+cYLCSTl&CKRIh9?q^xIz>vrwCW@*e9!F4nQKjmrr#aq#F-E+-yr8v&IFhc zAycW_XhIZx2kxrTCeMTjdXpVh!t!xU*#mrod)@Td`}Oe1U*N=tyE-vg#&8{W?ciJuD=G5eIHgOW6KlGTN4pP~!U3 z)b8%?)Sz)OA&S>1CKA)4d0+~@*PGcX(93WNhxrjPQAlhPB6tG`aPjamfB-l-Xwa%- zSvD18R7jAiyHiD~b{UkC@u$e$@HWa|iUpb5?L|%o006LeVj4%K#^Qrs57D1i?;Qn1C>2VKs!Hl~T zB63k6#^@N7ACbTr#e3)n5AM)_(t=93l;r8wq!{w+EI8q2N2UhvViOv(8g?DRxFRW& zZk-{dCVw$6Pa7Z9eh`QC`jbN82Gac03biu~* zn3n8>=>6?Dc`maNyl6^ZSQh60HuYJ^!u)I>sTnkeur*NRA<5J#A}uJ#qP5*P&qPPA z)BJ-X(sI5?%Q@qhThVA&Z#LvNWmy7mZoz%W6kuu&nmuQ|<8ipj=KHfhv zYLw`(DY>f{YLz`dyw#(08*vjNI-yEFad?ox6?hq9mV0S77*Jx2QS7G9e9$E zd~;9I1*%)eFo6sPJ>q?uzj9A%5&?=E!LdugpuhXmu!c`iJ_#rxX=7NTf~#Q0o`=f3*M8P&KDf0EBOz3uP}4J~)VKbuQGy z9H7=O;=((0^z?Y|A8-I_xO`IzwYB$;xPkAAVHSsR5uYPz{38By^oJuh1nmWfsKrhg zAq-OO_URKJ9B?D@ev(3Z%v5KJB%Prb&xr1rAL2|uev~`Mkh*U3I~N=57m4fzWHbTi z7iWyI`Oz6HN~q<)55AHxh7x)V;tqb@7^aZGO8UG2L59LO=UYlJ;^Z-9yB)T`NBn!(! zT!Moa}j3pK=7^q39~W*g|}WkNf_38@P-qRb8U;H6Z$JmUfVQBYhX1k`C>y&M)qaY6%C-e-!qK@m47;s#Xhy@(qiyDtfC z6mbJ>)t*0YaL(A`^9YB~L8Tk;yPmzq^rzo>r$_F*@x^f-R24ouDX5?Na44Hs2i#6^ z7E*G6cEV|I;YbTXz5fg@y3|J4@rL{wW8GpW83}RZki5y6U=sp{WBotsw`cXaz)(;P zo$BXMw<$-5HWk!0?OYgPE2tY%gI;}C*247jt~`E5ZjG~*HwviCE)YN4x>~o!P(#u6 zE`z9bxF#h$j~lfrFm+I@mkP3X@of!p)sFGB5&8QlN4Qa=>MvcmyD0?SKxH~qx9o4! ztH2ze73C7j4Wb|=nq-#_U14VfrU4#Jx=dn;zm(MvwvU>=8&~-{e=Z`8MWiu{A3w^{ zA5&lLwQXcBWKt7fNCC4k@4lrnZ8&WL)uK7Xla=m*gNJdJN4$*;DH2(9%a=*~ABb&a zq&%${IPyo!8;3opt}17KP&{QqV_IWmD#}mkk0ebGV-lpA5S=%wJbpaG%mB3K@!&xk zBI<`(*QC;D=2A|m#4p`CA=0lh4~Es`XbNSCfgT)RrZg*k$Wk9z$*W`&qIsb-GCO)W zOId89nlN^<$w`GZB^3a5-|J8vX?-j_Irqgik9EvDhR^0u_k_lFhL@ZHF0jFuaV$Qj zD_LeGN(Y<}fmM~+mm5IKp>pyJa;}mGh+xDT!NC)v^6g~h7}g$YFw+W;S-}LVIu*)x z`!8JDzetDpCl?LQ_z|rwY+p3eO&^upkpbKF$%6s$+x6Z4UJsh)5TtPd<9kV9d`nbg zDW2E{Pb|!d%<<2S(gUtbIEDiZ9A*D`&q3*WPu!5M>GVQ6rGMM7AvkR55SDbVY^J)s zL89br$$o?6Y=aT$X`QLB8pK^ERnMG7u}?+a8D83iF*W$sN48|qjU4W{uEp?zNQWRx z4c88#A#E8wH`-tW?qe8rWSZTSs7K2tpEBF1UmI7i_Z&BJkkRhDRlo!s$VLeD#bUEo&Fd=o);!bY0pAxK*q4=e1W64noF(a*5b-irB#QUPZSjQ*HMWX(@tm_cnvGbmsf)Nh2T?!Z6QoUvx z3yaOlQqzFr&01^HFin+9G$(5z$mbtccstc|>-Uo*hYAU30eDoR(%5g6_@$)%2 zIn;&gvRndqgi&!_qhrk7p}&=dYQ3_0y|U%OY*R(R>q15Tm zkd{Fxn1-;W+imq+sMsL@T?|AzFRb?S+4Jb-0(B)~>%z%bq=rIqV%H$YM+;4|&?N0Q z$nSQJ9M&&>G(90-L*-)b}nvkxbM_6cO$ieGX;?+r*eMQ)pwQ=h5laX?}h&EyPOG-Nz37SS_b!D+-Nu$0}tC^>IXvT*GKUZn_<(C%$e4#qZXU_{jnX&4C+XGG* z3uQj~N;(L|UXeT2aIB5e)ek<{x_J#(P6_f9Y5DFA1?HkPx2=0n48Dinmc*2c{5=KmSmn%2)QR0Pql@;CM5@(QlC-Eono30;qysBQ7+_3 zJggAMaJm(>DSZ#q?H#{RcoaBaHc%tA}R*|?{hD4FmgT$b*@n7kkU4Qxq6Azxe-o@31-0l z{)uo+6Y?M|C+J6Kf@{)ounAGS62mna@GhFoT!#46zULph(n7Mc!u%U_V#Ijb@J3UuvLq4!m~VqCFE*sWCRjnRopN<^4c2kszkkjgooj^dq~uVpzy%5@I!;lec3-m8HA9i(kViW zIG*l>j9E&msDdth)qc%>{RvFuuVk|he(Rq7wR|4JH|;m=@7lR-=~a6g|6WO5^wX+B zv0c7r&)iEdf7AZ1`XRmawfN3cU%H5w=IrxV?Wg$niru$U_-%Z7`m$bqG=Fk#?;uZ6 zHtjJ8{L8fSCsAw9Jm;Z0T1dGQj)9M+nY+kEkV>&c=CO<;kHG{9w*PIG5&!n+tyXP* zxxTd6s;tbnP<(yGK(_4ss#&QmFEymC*77=1q=B%y7E)g6zLs?YFRq!8l)QAg7^eG~Pbya-9d z>t3%@sqc6(&Fexeh^uxKb;I?!IhUZIs)P+yHT{nIx^Qi`q2lA7JQOXXcwW;gc(6Rl5z$Y1;waR2|Fl$iWJSN<=x2H=Q~oiX*-eKYcjX{R6Nv~)AtN? zepjoDT}MJ^OvWzLK->4*uAIx=h*q*RpLOw0$BTFVw8i^*7&K)s(nQDHgA5lLbfo1_ zRZGi(WD8+p*Wr>~rHL=2NCU8>3b#)aEvrD1IJo zMlnOhHaD&Duq#amoB`!2e)pk`=};%HH6vsDuEhKIj>kM%6%QR!ENIR%4IcvUJ>Bb7 z${DW|)n4+FS>d#pCk_d>608*TKrFl$RL7Bg1d3_-Rb0rig#BEzIz$P-H$?fUq(v%( zAp9;0s)NNdst+#!rVw>CjjDJL6bFY+2)BE}uWBW6p~m>h)aOPzCAbS?gQC~U-R79! zu8sk1vE8M~%-8o{DFojbe3~ z70TR_s*09xhI2eR6%(GpumWueN){C)sVEN+ekKOz=PL6o3u%O?&qMsc;>(2W4ke8& z*o3(P0~r~Rvlj{DJf2f8d{;vLQTGD* z191c*CJTYM1J{!&Nq)fm!lc87O73wm&>?t+_X4V6ypE9~2BOZzb9tR~4z;1i%E)f2 z$qvY;nES>UYUf;iY|^E=QOZ^7Elp_}BqdNMgOqkUfz$`vHpu`XeUmf@-o_}|Td4(D zazQM*X_3+fs+MWbi^a4~uvM?16$}Xr0oz8C144Fqc&KcG-{S;x$o(Ea1_dXOkb}_v z;$kBhPStucBV$BxRlFlT31_g|pJg$f^oshE$Yz#8={s1BQZE=>j9k`%bkBiVQ+2o@ zTDa(IPD7(5&NY}J4VaI|H?P^Kp;~X~?llg=Ml2T_YRFk0Zqw*1b{-%n6hBM_DbLYa zcW$MJvK&$iD8x3i1@<@~*E;q+S~1We@flN!&)}b+l1eeS-dQojeqeYG7AcPy?q=+i z9ZwNDQk-}Dn0u@vHS+PRHpFA~otD%`=|}oH9r!L+aa4^@&kp>2RvS#qxTO&?ZXu&v zi97y-O%m?R74xyRdD_TQhaQ2g@gORcl2Vv#dhn-^j|F+=_&d;eJZ=XDHj9Y;FsaCZ zPpaj#5#%7ffE-1!u!~6Ph4JM3`v}XCU?OU9cf6EybYnTDB*oK&MM3YS6-eZu! zJ54GutNT@D5f@fn(%$C<{6c;Z3H7b9(uA4e2Sy|Lu4ej*pkl6;9#j2#O3ddGQ3f8( zELm<1B}F&VR?D!u>DMbPaN~Ris1s~;g}mtVuSE}`(V-ZNi7Byth(8h@8LFtQM^dm- zrWHT53l|asp3uOw%}ItA>5xn&%^|USaBly0k%xMPy(H*KF^PpaAD z>7Uc8-=k>Ae)8!+eKPUx>UFL_ zeM(+Gm~x^a>c9EID_?kp{-G@HOAxCb4v-I)*&81ue}*t3g~>;}dSfts1?mh(IPS0q ziZWQ>-yh>w&z{YCAw<8h*ynG&yuxT_0|p`|RgrhZzUBr+C)}vNQLoli%~xn|(&#|S zY@^r*yoKcwXYVR4kSJn1UmY3(v`691OojHs1HIY|V`EHR{#sJA>a?fp)65k+pR;VnLKebW9=Md-5 z8c=M)7ke0OP#WURMPAvNLeAPPTI7{w;`K#dS!T0L!jS`sFhyP&#at*=h2l-IUAvo0 z7fVCAMPAtpPsS_q%1%lzqxi{fPSD7tvT~4uBPB&%8PcB-+bHtN;_N`>8ch>aio7yP zoGbFmbe1Rc$9$Y2QRJ2B8rd8kE%M6rS(zfQtjH@vsIAB=<0L!I_9^npio7yPoKk62 zMP6BvSGLKCSw&u%P^p7OURhX1G61ZNc7J2r@7{k%`MAhHdKh2Shmzr0@50ed`NPP5 zMozBWs8w;$vW{!?8@{c<2i!59#`(k>wW0)Xz65WPf}l-Mzd?b^r6L7cKD1$JL?; zDd?0sO^E$T!W17J;LP{!M9mU7$<{><6^yd*5J#mU02CxX4uG&L*a-J=6!K|A;7J_H z1?UB%B^Bw?1)^7h==GUJ^s1f@(QA_6SV!L*QJpu*G@B@8Zzhs9FNH4}oY=B7=bNos ztFk!X0@nD_f>klBrB-EWzG*H?Bz~XHv!#y}!{vAY`r;>DD^yR-OA zuW7U#95bZv6lcKi@RmfoyR7%p3DcOA9j{4eP@(c>&%`Q1;sb}L_J$KC3?Ky2nOr(> zK1kk#aqrQuN05k-cHAE#yPOE|K?oNj`PS&@((X{Ffjk^ZsensJ-*BeLc%#~#|R_I6(J469PrzKDrdL~;fGpPrMe0A=^NXVH7i=CEzUi?VcQaBXib9 z%0D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�}}1PA{YaVz&)Dke)3aI%${N zlhy5CM=@4Y8xs77UsPhP{(^{<5mey8Q=I5J> z^HRnR>~D-lw_$YcbG(f3RuhpooZ&B6vQWQ!m z)I~bgUS^dxhK?%K#j;IBEs@1A2FG@S5W1xkj8-yhN&NhWe|O_jr>*_g?_IDhH%{## z3+Yfc*_%MPB)~Bihqlj_li3SkAV%WGt@p@~BY+P~2i2SAodM7+ajEee0J?G|ExLT& zdjn9efN=H5z)Ut1d=4YO+W>e)h!WygAL7dc{#*rQO2cn8$aKS=m-&`dr=xR&;RY8p zC!L{8-;ra#Q5tcMFqg*F1l)@TiACGluhe*U>(%G-OC$RKJoei2(3OnZM=8SC2(n1c zr!n1!lK&WXmJ_)Q+^V40odcjzS9t#D#$Mo(Enr7cH(Z~aV{qCkPzel_R_x4mq~#cu zHpW#3{W(>7of?>9Q$hjt(BpTFU|;-c&)kahu?82u}EhZ8)f(4p0{$;M}ks z*%ApI;=LANaA2eV#Fwu4W21}G=JW*J^p5KTnM7>1T6jK8?tIt_(bgRR@~GQxJD%Y& zl1|bVkbKbOdoFN%lGXr?1K=KlxY4)WumcE_8~#(>()|DhB2A#^#54f_D3FI@XQzj> znbqt5hw9UsxbBC*+=*=c;I=ev&v*THKY8{i(({}asJJH&8QE9gdq-j{liO~B3&kU8 zdupJl+d#Gfic6-cM-GzoQ_P6rd6FsVl{OG+^{_FPInom7!yiWTYdBTLP&IjJlL-=Jw{+0}YEr zODCkdrC2z%>S}$hwzf8pYk_gth*vm%@p`WN@vO)!-)CH7&%ES2n4QXp$r^voBH+)| zj>6l@`#lNxq6bF5avh7EFY%vu{lNJUnRomJL(TvFDfqVK0QiW%-8aC9v^D8_9|0aK z@cmAxF4No+Za4xI1bfU-+8EZ5tOFa7d1-?S-du<+IT&J&afSPeP(jD@~!=4jK;Nn3NV_JA} z%X;Ex#AABtlM(y41)c)4!iU{QX$RWMx8BEYE~5&Dsgi8u6*HvvD+K&j@mm#|yh^5T7E4Mf#6E2oU|h_t7;)Xqj;6N-RU+Po!EpREcm$jQk`WDyXgV0f4*b6_WmjM~MUiQ=N>5`H2!S2i(N7eIArgO*S2V^G+SEG^kw)dLTLEfZ2T(S80d^ds-v@m` zvOcSXK1j+(s%nsG3$BA20)-hX7afI=P&B5zjh-rnDn{VrwxQ-=i|YDb=rpl;(K-dL zphZh^XiPUB%>DEMBoelJ=R<~jo5hBvR@)t;877q3gwcl$RuO~c873%*)Uf5Cq&HR( z38Z*nuq?5XfqvNWn-1sz`XKgt{Sux;N$VV-iSz{xs*PV?NJbG_VuVhB)zCQgB>QHL zggI?&`-WB+)CkA2kJ$s=poNq$f?45Jpjd~v1gaqhIF)Wn{8-HPB&DPY`GPr^r2-k$ zUx*zDw7dwT09!gWvzlLLK{J#MgdQ?>K6E-)5FGz|Bme&-bgG&TOK+%xZcQs9o)7<0|8NNakm4#+ z+6&3edol_!kwE=a3KEJLq1R+M1=t8<31MKDZAIA26B(<76b&I30X7ZChYF#`4BX~; zrrTo?q|CVOWP48R5}Ltudl^=>vEh)tMr#@W|6}mDB#Uc6C?Ru3IUU4939TbC0@AVq zFo0*kEP_PR#>bE)saB|>Z`gi}_mmH+539h2g?AC-uWSGks@vqx=+V0ZSS$6lwG~=( z(Bo=axEWBCI;6|R4Q)MmDBk03wQWa`^R&_O!~BqXcquz@SO9EWpQVBM`0dalX|T2l z?KXt$3Nzw+>{!!8s8JXiB6>INmA9}&q_|`B2&5I9g5^hB@s?*+F^ZzCY=65#;|iZ;ZKu`hdF2+V*iQ1Ct9Oo}w$kZhA+GVqbqaHlZS=Lclx za(!i~zA(nPdh&4*#So>-c-SA-&PndOTpGxLXOq@`MxTfKF_-J2y?xIWg%dA1DbpoM zEkW=ZrI!$y1{yTEtNh^j=r%WpIb$9e7hSwxn^2=^@c2nO_zG(+-&cH|40aLXh}eE(F27|pvGX4re<3$MI#euesuF!wBIHTYlG+VQT4J3h=q9Mm;-JgX%(a1}O;VKqk8dcGna_=lmc=RAF{ zr`59nmstgYYq{5f@=Jytv>s}A9Xh$ys)jan*rB}wY zajP?#$2naxCFO)RGS8=P7ZzGL=7Qo5pvh~KE`KpX0TndctR8l1i{GpYky(_~>G zb|^73m#=v>XYm?Rh<;M!9F}qnYKx`B=t32tfmHWaHg;(+bGoX?%-VSBGDL{8jK)V zFZ5_afa+8t#XNM?pm`_$wEaWw6usC&)z64)U+nJg?sy~DIKO}J)o>}ZI7kSlK^&F_ z$S1uzd>-K@vq|QH`KTnX93XkbR;6!=;We z9@XT4rl>~!KD-0)%?A>G71&Ng9Z!oz#4Nc#uh6EvboDl$iV_yF?u?{UX;L)(P=+j2Evn>S@8kfviXDuteXI>YvES9 z?_yO`Yy_SM_QN66lCT}^S@7ODm_9rP>sddk6Dx{@yUS>*4oapm8(^|xkpojwo*43_ zLAMz&Q2E+ApPRjpT11_j6449xMCLNw$dl}~@o=u;ZQ44}C<$cc#HRMoWSg?Bxc39t zPJ7e%GiZ*UY|g#;?ArS%Q|@_MaoK|k$}av2V~|ta<#_MEN0;p@M{mGa5F&2~BDEJD z+kc)~6aR_^hVD`{Wz3G3PB@dne~#ux?3h#WwT=;WA&;;{SG#@s1OarsNBziF|2tp5 zp1W;5G%K0Ty(PMCG&Pmk)u)D4{7coNnPf8{9b|fjI(NfISOta+v@Tk^WPf1wUaD^W zh>5424HNXZL_H}zQMOp*lRAkoU`Il4dR)3x{koxg!qcR3iBL$6!)xT*hTt%J&?w=& zj(7ZIcBkSiFm*3ghZkZE8FL3Emnz(Kn|+=)H4?BQtJMFQ$Eh}bsXACLJwfWD;gxw# zSzXI0WK)ng)t1vn_~KIa>N{l+9XcP%jdHya*6it<#LHS z6L+A`9Z35**uge}^5tzhmv@=^_=cLp5Dty<%w?i{u%s1EM?wikUj6aWTb8kCwrWd@ zmE{HGZY(a=Rx7JZ#%g6@sa0RH>aEuD+A0EAN%@}Rz5k!RxBHPKyY9qVoS`U|Mj|PS z5;?P?g4r|7tYPJM)~7mK>d%=bdx|~NHEdE{^RmOO`z z{sLR)qMOlN@%}6V^CBYXVv9PlOk(A>Yrl>oRhj-&@y9<`v5fnhMb2FpboZRYNqMP0 zsq1Mgf)-kHGoO@iqse?yZrr7n`J}XwDXz8;3oQtW8Vd{S6p za~-CcPfB{T0-w}5WeuDS&+KX=WZo^DM-~tErS156qDn$pJ#9dz^NDmE-#-m_GI2za zPt3OThKCdausq&p>*@X+^J)02@4P;jQF7m!vZ74c`N9`OmcE$(7~S%%XOf^v`xzYM zp#g33%p!jyo76KLTK4lcJMQT<(sZ&v*LD)#D6J;|0FXfB>rIrkn(w zrk=2^30UmP3UH(WnkSBXUzvc!rk=9AMEeIuun?6y3GPWfAqq}RVebnO2!cFO@O7?S zO+5wmIe??^7&-&OlX{}Qp9C4r^X8?Vj`w8{%0j@RQ~iypr?df6!VEA`XkZ}8Flk;` zNj+8T^X(rYBxl(6vqy* zIT=w<4Oz2isglvY+IBC96UzfDa#1cf2W66;kx!`3-+x96Up>tCJ>t<`^ZSN~cfN0R<6{Z0L?M0O-Rn#2EH4Uy4$P9moD!mhp=#h~KRw;(P#(`a-~>!iN=oJZ)m zDvLBy`o<{R7;=37JQpkMLuvHG!akSU-PdxTe}0)A(ElQq$V~ss z+A20S*SCw??d?vn-C5tPcWU*n5F01@UmedV{-ysl0#4=@{))m4^uN~sQvWNTamRWT zVlcta`s0X+u$G>IS3W$~5?=JZNLTgNFQ%-x$ORRqw1Nv~>IY$f6N*^J7Im^(7iIdB zdmM@cP(o&rOc+Aj9W*LG+-hbSlbJ6MGmK=VxiU@jc~)}GG|g8t)95m2nsMx!RBtD8 zex9P@KEt+5O74tTzpZpfR);fwA52w8JfLKZNZA${pOk$VX$FIYmLAE=;NPKSRQhW1N6!%0foV3~K zwzoQ!YPG#y?5=B~*r;xZ;U3MdQE zC^EslI#xRud2$MQuB2p|>Od{ur@zH|sao8+S)_8DR4@$Ip~nx$sJ1dlT8>=4Mz$ka zleL-u863@&*jZ)2b9ZDy@efMjq*g6^^-O+iNMSFzmrQ}gzRx2nIBhsStUcrp(jiroUJw;pO)?FOiBn!zA^kpXV;g zDpI6k5~NKAHZjtU=4zOi)yZ?XTcHF;I>mg?`SUj`ek-O`VmMK}jupGnpTBkm)oSpc z{`Ri^&Y$4`^1^yG!=pdxe{FB0ws1{s6x*VUtbdhur?{oAw~Ojlr;6I>TBWVlo>{m1 zGE@I*DtG_g%X7)5*XEWfccPhpPA=Y8eJoiPWSTM+XBZ+qI=Mkws4R=>)Z=EgR9S_g zypYF{5Cx^7-tFO7!B>d8GGr!|3r3L1lz$-8lx-AAM@`Q{7TTVD6#-@o?K z>{yGr3onR1`vQ9i16crrRq&C@F7oDrfTF?BYoUxTJh#nV+k&i+#>dtGRm4%*s?`=c z%1hf0N@>L{l{fv%B~;@=J$Q--;1BuhayOf99%6}J5bkVL66^6Ewz!!H@tHQU1Qh%u zfzs32=8%7+3+#`m2WUg=(~!*AE??2jVa8$i65;FB*`C6=mXu5O)h!NRPn&b9qgBLq zZKGXmS33ZZZ)~-TTb=dwV!JLHHL^e0=hG0o9k(+p9kE z9A4nLfa*)?S{Z$s0px!50M-9{X7OMEfm?t<8U-(V+EVbpnI0R83%aE3 zE8iah_Ip-n5-Rv!&WKj#?W4G^qL#O5+DFn2rlAr%YM@?HKd+OO5j%k8lF1l8Cwz77 zfqHA@~^)SJDR*Dh(Ge@$r%MTbd!Oe3xfbGW=dr2jS3sFqQqn(2X=cI#wb zBdtXyegMMBnU#TWv!qAoiZA;or+JMoH8kn!%=ofogx95Z@Vlp^TuPhIO5NUWY^`s% zi}fw7R&1&5MAU7*zVcB8T_#Fi>f1KobXd{)1e`K)XUhzpodJ`$>HTP0vDT6VWZ z{(YD>V&6gw2jv-Zn~bP9v!de6y**2MbZOSBne&n9T0_-=W`#5zZWid2!8Z%%%WXNs z5KukKOC__}#Jok9bo_73HlRgV(;)2+%q(4l6B()ICG~YRh*;!8Rb=>^m0(BN(=W^X zQ;cTaw#>0|WIKnh%w9uYwj#cpnooqgyk?ef6;cM(y{D)H1qp%Fj!rOjvJ;}XV`nrF zmZ!>8P>5{Zvz?CajV#y>--nq?!A&qP9s$r88sZc`LA>f7q8Q;*Zz}&!YN0`gmVIOj z4KP|4r87D@JY{h$3lutIiX;yQAvr+LC1hqsAA+<3kM}T|w`7iidvM_ePCZ;@pB@T> z=O-VBJrZe{y7maU$<~#QKC%wooqg-(o%inTQULSp`yJt819MCJ7GcB|cr8+D;sK?K zrf>T^(=xQ3PNQAZ_AS59I|^k;K#3KX`3X73Pz_97Q+6nlb?4v@y^y!)x+~Cu4(#bv zK#aZ}1ocR5vbL&9&$cy)Q>3oC3&w;+c;D)bP~v=mGH{f@%zsQd!p$-jmL&u-w7~{G z6dj{GRt^qad*pP)!ND3n)BUZkVG5VNs~9l+4lk;AaDV~iHw10&TkVlyYT$Z6b)#-` zM;4`KjXS1k9AAXPz&Nbj>3476Iyi`r7h;Rd(Eu0yz9oKhy|D>8O3IH%4)+pWj@%Fj z2RT~x> zr+v$`?L$cGLxHz}JNB(o30#0IC2h>o;m(dS9DBNr>-(01|KzST#Rx%p!Z<(7d|-g4 zO}E5ZJnF$y@|*N%8=na$cp1C6=>nAwq>LZ+=$=BZ>A`Yn8<8Gc%eew94g%=K}Q%*C!p{MpRW=kj38OQSS- zBQtFiiE30M(LjP>Br~BULpALlQrg7cl(>;Os~Pc+e;=2*pPb9FIxvI5y{g=^XuTs> zgrqH`6>LDGpeW$z0W$GogK6!=mQi93{i%#5CU|(LdisuXu}KR0=!=N6I^^G$6h}cn z>(2|}>k{XaR zlFHjs<|`c&y+(8viDQT&sDlP>gTR15#`i%9nkpi>@V}8ODA5i{YOvJ+UhU{SD%*5N z9V8}n16fB}4w{hCk|#rInL8w&c6`xK**qi@kARmUcR4vHWqbaO_g zxP4#{#>m`<%Xo+9C9!Awt9Br7Dn$#nqk@qq3pK)gCO!mT5brU08_uu|&&M+rq?C`&RRm|MsoBG~au%`L0PGy>EYX zsfE+Xl|RVYy?%hMvoNNLiBNQE z^p&97RdRt9TYooK4V@ zY)etzl|RSFf<_)`hFu^fTr2^!h?O-06a_LsjyI18^@X0l0Spkd@+XEkq9Xyf6zvQ?P;1#MzUyNN!ku+$ABRB8IF|ET5YND0w*C(@$CIoCO+_s;NVma*J&oy)-Zp?cj0;3Afcba)4GQc0K^0 zNVDPW*uX;-0Yf^3d}qeOjL=q!jmZJd3wPR3asnnW)iI8UGP{-~uS8F^#|f@HxM zSvVvJ@fkga0rP*to`f2McptG|*h9A@Sram1V7s2L7+}W*RL3-UlSY#PKq}nv)@W%T z=>~*l2jt6?-GNqtzS6!?JFwiqWY}%{g6)31oLCIUU&|ze1Xq~d zA|++EXnaaEaWQ31a-o!lqzsI#fQylOP#2v;s85i2xLaIU8SxPmu3@fLWA@t z8UyUuPYnzVeu{0av)^;yf2@^w3@_p#xH%4F3r#LBSQa=1=yLXOXcL2C+#}J(iVy1} zF;-Xw_t2^%@lFz`!`p)^L?9s{F44XVNy&>_#WH6goCozA zF8>Z(jGF4Y+K}79)w?4yn>@tPhr}lx8I%X`L7Ap7mBQVJw;$k;irfB^Gyn5nbOTbH zw1k6$pvTlJ7)<28&SwnefEtcZ63cyFGki3{W&n>wnfh7My@APk0D3V+1!;|oYMOap z(`-yk@T8_$*?5NqCkSD#lzM$Ah=ZAl9}ffV3IatlK&Xcy^>=WHI9_PJzC-IxgFOT$ zGR@zp$Wk;*^#Rw?T4RG7Tk-ku$?Jx64o8^c2`OwWwq!;WI?t21<|AWr-(v+2XHq`J zgv2D*9VmuX(8Kl&s{;-*Qbb{O%Ju3`ArAmEg;dDn3L8%c(;Jf{KIzm*V3eBJU1R(j z`$$uJm+V94m<@e=0LKc0S|)V`X<1{+{MXTeND8e<1qwTZ+`s+agi^bQv*@UeQ~96_ zGa7Xe<|yAlUxtCLU2be`)Hby0wgz>6tGiw6Y&NzV)oQn`t#>QkZnaUV)aq(&y)2t{ zab}O5Q%b|J6v8pJhqm`nd+8buw$(r_AvsJu!`cgutgN&!iQ$2k4tdftNixybyLiVU zrHQia(ta^V(ZTHf%$MMJkHyL-y)bH!4s^6FVLO11NoU_F?G!8_J4osk%VFpi%6kt! zc9jBe%#=U_ef!BrH$LFC6n=t-C`p(DX0AUTeXcigdJ(XwDjaFr@V znuXo4gCtT;i>@g(s1C7Vj!PTdEEQmBk*t+BZ!)X;A}YReW0L}MIjs=rrU4-Xc(Bi7 zuAEb+#5bW3hhhb3u*XSCkiC?Q0GKf7J3L#`FcPg<;lMx-y@TH^P3O(Wuu3u)w_-oh z+WrKS;u`>BKQ(dttm`d$1XdN27TA=?G!O_Uv<~Avb%;pyjWGTwmB<1Kb3H^R#3P4XbinuF>Z5Re^{F!aP} zvNw@*@U2DUJ7GB!pRj;=gJ;nFC#nf`13VcRlM;+_fNoH}79tiMDX1`T;GszMV73ic zqxuB0nRXv&6f|(uzd~C+;~xVt27Ee(c0zAu=Aixa2qKfayodIO5C%{L@zP*D@xgP} zSx+vYK<1EX2zEk@?-;r)%WL5B+mL(EGzKcHcm63ob_7(FHhehy)_vj8<0QecW--91 z^#VqQ_W%Niy^-i|Y{uuVpaXvjf*D9G)yP79Rr!E?1^lk+#1NkKBI#iU0YN*aM_@?hQ2zaK#}1N*W&21K7%PgtMO6DAcwwnFV&zOO3WGo%Y6aGwOG_pLTGJu2#Q8>(O2 zd`Z@vvzj0|$KzISh3!mfjAuyIP^Kp5oYZO)nx}YzL*#_qte3Z>+-xQ9+TW)^#(W90 zlu%p!n`F+Fq%g5@j+F9PNq$pYz3580?o$U zK*^DUGHm%%YWjeruT)764uXb!Ri8FmSmkhn5Kpinv*h$8jenf_-mHO*Hp~|^wRFB8 zOBK(vTLW{*{Z-<#Kec+Bk8^VE=GJnDym0YBuHf7!(~r_RZdNy@f8gcZtk)911S~M! zk6=VwG%ft|tPzXk*0ZtV)W8HhNfK{rNFdO{F;T)nQNmG)2{9?wqznsMl5(vM!zZ;K z3_<*j3F3nveENf(lb`L+(_@K_|EQa(qhgAu^@%!YU^V)@WFC#FIxI>|QGSa!HO7<}BJq z0Y?t7TNe-d;udJXlh`n_m6eoR^3bFz79~@FozPUR-UwcB++|^3hhBni`rdYzdKIR$ zAypts^~!7*rh4rw-@J0A|2_JX!=K5j^!+?8?)D4#o2X6SU!yB;_KWmS98fFUtKxE> z{=`bv^LJT!yI;poyZr|J4dbf0Np5hWE<3;7FWDV0UVnPu8fW(H_%$dl5jJ-5{&B}& zRwwVU85uhoZ%L8;A*jiKpCL8DEIv4rHYD8b;D7@@;(+Cym6gy(88#$Xgvj66%;PiAvqRvwD1_}r zhOO}$MQpd<}))~$^!&$@hPT=AUXPx1!DYs#Uv(9kVbcB;G zUiL1X0<&&rIO~sY!0Q+wfij$RhO?dnPS0@G1b+gYm|URW}oVB0(CBs?o zC>hQ==}8X0rQf5R;jA;9^$i~p8iD*Xob`mCGr)zy!kMZNTwsQ?p2SCIIBUX-Cio)5S!XzF+Bq2Lg8VUvD#&ow8O}P3K4!uAqN9(` zfwMkma>pP_<@``e3Kk2olw?>qFIF*`8Xw8&PeB4Mh_ibh5GpD%`!S%RNyHX|M`K{E zJpp_vl5bLMA`W3Rd}NXi@LWg*$%x_%^`4>LpQ+RduZaxxuD`vjzw>7&g%^f;|I*KM zmkZKe0GYo-MI;F+9iZHEKvPrpJGwTB>7?JH2#nOzrhta&9Uu^^mky!!XUALpqm$21 z3i=!PBV#)L86lzhkA@-~@t@1Te&x#X+gt68>ZaJ(C|0)GjbcM=*Na=V>UOcV-QH?% zH9C!r&Du%7O80(!atcrSHC+Gv zL^siQ?(Gx;{el2*eeuwfOGTmoUwat}Jwu^?eDC&kXlPt1gyiOQy6!-K10Fxi_ASJK zQ^RH1zLAj%VH#oP^j4PbTh<_8YfzA`BFpxjW&56)lAVkLWKbrAIK10_8jraKX8*P< z+jo}jJInT+W%~|mt7O@}V|fv?Y~LyZWho7KkcAlldQSM3W&5VR7Fo7^V?iv{8z&Kq z5r5tFRq@p&sAQxV)6vr zy3x_OW{_i>`bSvF5N^lshJ3$YCR!Rv@mBT@Q3Md%N>K`t zhKUa6sAkJ$Ug<5|Nx$!ShNzaQ52%>4;HvbJzEbe4ED<~BSycQ(7411s%9^rso|F)Q zxzEBwF&ufPbsGh#sRl45CFFZ&^@C`5q#Gs%)UWN%x%m7E1pSz|unrn(oTGBLF+iVC zaa9g0W(AP#4lN4>gN20HoH8A0Au-_|4`0WY(}haMR8a~X;1>oSxl|vKYLh!c8==s+ z;swhNt4nAY;eCr{XUeU&quhjHb2u|mE-i~HdcuP0cVuNOB2ybq9*hde?Oz!dMzi1M%J!I z&3TSTnX}vTpn!0S)i@*5o~aJhy3Dy2W-62qPEin)aHdxI4SuRN&$C+iPSuys@G{RJ z;-SEdX|x&5+lW};xNx_i+-jGrr8APBs{V!AIpl60PWh{c3j z;PxSjazDWo?#8}5!jLBV&0BiVC8-IKV5j$j7r8sUOd(AYd^jBA2GGP}z_AArT_v6) zKc>5ui0Q7iHrs2mNICN%eV0vKRc?+9Qw#bQyq=Uao_@Kp(aWefFma+VQ8p}WrLY>b z19^gK!(DY`LI4TRW7$Tck(niYKyG)i=F(=P+Ymu~53Lm0D@D1gJQ51)jHFVL`h#|% zC?%B@OyZGh$&vE45V{wG#w}nRgFVd^X15q_?&0)zP!FA6PlI@Bv3As0#LOf`MDQBP zNvi3x#wdA-_1TtZw+7}=3MPy~a=}Y+BYy;aNfwk_m{biVHNJX*r(8n|S89?j?h%i5 zI7tK*3J1P0r7p&RJW*kKp3jLbOhL6~xtsbG_M$0m(WEKY!o`(j!kFlz`>sP!m^MwM zfh~u2Djg#W(L-W`=h%?ySJ$8FnABpuoU|RaZ3?DUQ637R>^P#kbI=y1eRR!dyB2Fj zbe~_59PcG2^A{vGNz%K}M!0efi%ut=RDq-%1ZT+ggcaR}iqC3Z#{|ciV}5jUVPbvg z!CH6#JzMH>T{;a&O^QTBa>@d=p4FdV3G!QM+OJ=~4s{3(6{4kAlAQ3k@<|B{ZDFz$ z)>Iy2iE!<|Kvc0iJYT4wawxPPsyWnWS zt)m&KuRn7$Qh9&oX5`Z0o%)&E8rp6v(!|i*N45uL^MUO$BdX?|P)#F2rzpHSNWMff z?Bck}>~)`Im=xtKJCB4x!2aZ1Ml1B9bBSby{(Q=5#tdnWJ;bv7W6r62H!tBwmM>P5XfIN*+&E}b@5t-){vwGwD6WSI-Sprc}ZX}iVo+h-mBwj$l8 z;H2$1*d$%$TE{e6!B^UPU|NDcAv88Fogu@Y=fL?#7aA}{>FArkKynI%Fv> zo#nxHd=8HFg(M6*%raR<>DjOybZryr0kIza2m!;%ZfJc$4~4}p5LBA*RG4;X3FF3n zE7q{Q7aO=dTKkj)`un6XiyowxYC;T)8m;zge7JT!tnOBHk8oIC@;aWex~R{*zM$UF zK_onWK*5Qh>quO%tSXT3U?p-jSZl$NhwKlrvF{B1QSS^}v|4;AODcEA9*z}m3G4*B zt*;DFX96u>cBHgOgS2X48Dkb;0qn;Mx*f+L8zo?Wv{_+wql1KZVbvbp7|@wY>Ru3< z(9}Cn8GC{^RkEMqoQ1YYl_Y~{M>oV1%uRcY;~HK8J1l8&=swMZcnUjcB!F;$OO9ZS z6Tkrr3=_#d8W7hvbJDqt*0_8$da*C?qOlIf85GkFn3E5XSm!msI=h^VgB&Ed+!I-1 z{n)}T6z+yIZNrBrF70xIwQ?2<(9n~<(8%IQ)y*)qu zfhG75E+?q!@I{#;*51PtT$o^zWvTKMS&+h;k)(H zzhp{DJ7;O74#vAJO}oT*taC&rztm6CJ5c+5*By1A{2@F)9H%TJ*4@%d>d7cIFb#WT zT8*iY6PZl{ivu*l)YJ35S;0W5{JpRq9FjJ*nbDk(LTQ9qkOO3w#Qx|M=1! zIiLgo;>b|MnE~@sT3LCY04z8Ys8;GJtOgb}Iu`hb`CvnpCRCOP(xl3Rkb06T*h&u$ z4y1!_MH;aJ13}U);``=OPtkWGKi`D+F!f!3x4p8mm~S)v0=g0Tf0C|OB5@BpPhgOV zyIoU1LvPM^45z;DMeHI|u4_!jY`=Bt$=O-VvrYs~y46!p+q;W9{!>rO52PoS3Is`K zDn5~|cLJKgjF@_2YLP344BJV3#BAh5>S?-8s1NC1SpeICc}fC1Qcqu*v^7%9k~oIa zO61k19V*0~q@JLw1WP#s8IyVf+Y1M<^3s%#K0uDg-%8*=~uP4*!xX@OGq(QlYmwq*dvePwBOQRWdLEo z1}iuzArVtQMH_xp2K9e-qy#W1(}@=^PS>Abx$+BF=s!KbJ8HiKr-5>C@y@=aJ{Ea_ z5OOcTbRR?>eDb;{fS{=-XD0@VmYNKVPg8H5lj8F{NNlYw$u|-+PW#R;t4dK+$tj&R=Ao{PtR)1TzxtqGWDd~ z4r-pw+7tZ#mHda$C{HiohS2uFxAf~8Wlh70f^~08>niAIM@vWqu&L0HcpHO#WEG5mF)K?=%Ui#Ieo7DFhF!BI_uQ0Sq*cxrM zh{M2=V@%)>A+QEV7c-jzVh3p7DE)f)*Fwg`TEd~|ayjg|ly?5wl`D~YAA*JYjSw9a z{Td;L#OS9T)ZH%RF~w?;5szg)XcgJgFJ%+u+G z<5?A5m_tBj0r_?T`9zc$MIyra>m-{1OF8idLjS4Kai74qY64YBxE=ze0#OdEDu9%R z_q)L}2wvR9K6kE!mUxzOT(-E1@ihv*1K(0UOw^3jM2m6Z;BCm*9VI_`DStg8cac<= zSD9!Es(u1UJk}8t#hC#xGK7A`aw6&gqs?90yYs<=*4=ye?_AIATftF~mfd7G=qVO6 zvLp+LRDY^p)yMiDM$L`&r!VW($3gt`5Hb#tL-^lNThY33Zw$2((sF1g=-Zzz z);E3iISV(*YPwHdSGPLr zolEV~Z&vVM&noYgy}_{4vOoLuPxW>4nSaJrGO_-p+y^}q5( z*;xOZ=!c|)(;r8_K)ODI82RvALVeNqLWlovzLM$iubd8_)~W*+IWEPk5|Hu)?JGY+ zD(qYFy^-k+P;NkZ`k}Dq$~o0yCd2N*g$X{B@jdS zBTmIQzfxqj>LNJ+1t)Th^g72{UW0)MX@#!Km_^2`wvQZjh=VA>h^6El02aP)eZY6_ z+TL9o5v+F{$HwV&7nT^l&KdhOB_BPVN5{&3&vMz3FrOU>pXtye^9kbA<04riEYX0& zmynW%LyA>!A2ON%A`+&AbHVokP#)<7k8B5d8P7Z^ebJ7DeTBmMzDIv@_%nGn?B{WD zw@(JU#0jxa20r~wjt5Mf6J>i8OPG!T!}xJh_U)fh-{_Biwg1oQpXg}G-}yJGmG$fR zeV0v`(FvDHf9`>hr}Xo!;=htuyHV4St^QtJ?ws9!l$$C z60MQG20uycINUG)I*zt)*Sqb_jrs8U?q+i9o z{Q(;2*YFAF;s!nZUtUD6%w4Ic@cts)G;@BU!!mcAX=Y-4`ONY=Iyj#q;`(pE5)huF zBN_hu#N2anqFtzyIDmh5B|Cs;2XJH?u!krqrn>MzTziNwAMxjsK&BzP+k%E{;ouwl zMy^D5de8yUZ9XO!BxQL#wd~(TPOaGi{L&BLnLUTSB@_0XaNqIOntdz064MkiV^3!6 z>A`rw@{to4N?$Ru2P0u*^BQ00&n2?*K*(msp3K;jHvj*tZtRHz7A6c)$FJ=zL3qx( z0xLe?wgbw%gd!gXQl)lO4?#wpdov}-f14?p> z@A#i-93qc4ayE8U0+>bQQ9KOioC+SK6uMALg_e3+S3#Z)fZbD&V<2S~;pzxI=u;3Q zGWDdaMbjYh!$V^z<3(2RDWr%QGW|h)-{sgtR3b-iP=~S(a}LdLMWuc=cB0wvSCb0w z9y}iYQi-uz&m!L)@t>3@si*BWCol-m+fn8pa@A5W8D@zgZ=C&C)(v1Sof2b@5QKpw zb#^!PRNmpmf9v5-d{A*Ln;r;^!Y(Y^Dq56EnLACZX9ak*YtSC)>zObUlH zxYK-Ha+<+QHA_BvJ!NLeBT5^71Q_Q7;UHo1Qv+3fh*=3sLDg2F+kMQnEX!2Zc6MA%|qlq|NJt$JB3`XRy$R#qplY>HrE?PWx|#$mQd&Pfo!J;h2xV%!HpD$M>z7be}{nQ~lM!7w6LE-n^(Dkyal} zev<8A>yEqZnEePed)B&p9*&Y(oe5B{i^Mxl(!w52soE)ZgzAs1Ll-dEn|I#3w@aza zX5WueMJTC81>(+Ez_L0~Ckv;8AqrXClJTiK@f94`JV`0_wNE?io~+!3BP)>CR4eEaL98Eoju2ky@j9T` z=VP1N8EnJznVQ~CmV>w2YU?P*LK2Hg)eum&bIuXuz^FKN5 zJa|ccn$pOU=g{2FCH1R(-Vs`ArhXU}ocULV+eva@G)_RP+n+1c~e zKYM0oL=VR<9I7a6p=D^z{I!oizIXdNuFwxMty*SA%*=?H8F9k;oS6~H$e5WC9nq|m z5UpG#i8*Wy@ogI!EC=dS6t6iHmfNgQQn{gkr5nbu7A*Lx>5ZG!Qe_qQ74ooa!6pxZ zyXTB3_hli^k{5oOu8~DbAVfMdBhJrWny`gtnG*H4clCGv44D|ul__zCG4D0FXD`V% zR+t5+o8i=q!69FaQS5~!IeR~~U`FzR!2_rGp0*6VNKwpLG#;gob~9I1mW?-FdFgz6 z%na|sC1&Hj{w(N4c#SSISFaNH9T7Bwg*Ew^(+F4G?shxv&9*3Zw%cm4vALxd)o!&@ z-0E&@X^l#~-f1iXSNz5lp|2)B@%7Z=6VFl&mfn&$#bKEjXwnPxs(`aTVnn8L7E&$- zQ6=sVVA3fkW~M`F5PU&JR%V$F0ZF|i)8Thd zhl*cPudY8EME#O_T{$l_{zdomg_&dDNSis9@+K-h;kDYffdu=#*3d=}4TsIBmV1OK zkw-e>Nf4|ydB5#6Ea%h|5{s`H`GV|@yns29Oe-iiqk)Rx$b2vanLL^l2qGEc= zEn#+y5f`<*tLl!hbYXaCEfIqtZ)dd2GXYa$wjcyI2iri+4%n&_$s&*O4ut671wL^}4F1>NQZgugl8 zq5m;=>hZ2YR?d0`@$?8>X+t3 zAl8eUm7B$T$c^iaIwWBpKODP|y2<+XGP?(U4L1X->aHR~sH*6~9Ck-05?i>)kAb`v zl(gbwS2)Qgke%0wH}IbEgmN}e`puxq8Yd{GH=tCYJl|5qwHS#k8ypMe@*nePYvk}Zfd%-+$;Wb{5p1?crsS% zzh9Q`@{vGVD^)E9hX9#D-Vun_-B^}G_t#0g%(i67pD zFgOYPkZ>rxkfcU<$!WfX(0I?wd&bL{^S{!A(yr*GJAKD&IFwO2pSZ90ynmYUC3 zWyl=-h9~`h0Ll8*<2NuLu*^Ug_eSnXyf*DW(!kJN3n>{dwBy_j{&QT4b6<(Vu?x&Z z&D;zTltaZ$B18YvNG&=aS!amr^J{ohlM>OE$fEn0+&*b#jGEx<`4_LEUr=lB2j!8~7-SdX-PPvQ{B_pqdv$0wN z^0+(@nxPhZkR8Gqm&H@j8F|z|nLUIuCoDbwf$AJ8zd!063a2fc-kNfk(zH^cnp?VR z01${|gviu-OE*MU3Hzb^xQleH@T33G7N+teb!e&h3On%x{ZrUzvL!KTyxFmCUhIk^ShQ3v zxc9!mScbRVh9aaq5<09E!3}{gBE0930oC}H>ggS1w_Q`-M`NTC6Bft4F&rX!s68++ zTEJICzXr5WE?qp*6PSSD4IhzV1F1zrIyK~`{lIo%Bg3c$?UPkb?ZJtn+(80JlUZ5sIgfziQ1QNg=CFPxw0oBd(Ff$|l~Ls(}_@3Ww5#6^hMkIfP> z%}*Y1&I1JSk3AS{fUg}WH%tRXVx#WfRXYMejYDPEK$R91+zswCU63E$<8#zaDh7oD zWy*UaN^C}y>aiOAbl?_9k+uLM_4$O(pGi5vb|lyHAg*a`70d1Pz9aO*AR6T zF5hQdW6!+gQK#sz_*uBdpR)+~19{5hquz%jfi$}xspH~JEOx%cf8Mtp<1<)M_zMy- z^S?g<-*yccCHUI|6^uy7#o*pYNaO6-_P~{wX;P@B8S?7_wZqa*u}2PtSqw%N)l+$> z+e3LTwP<91F)0B&PNu@fs_rDjUv!*B@?ah71@>hHL?O+!YQjz=A4Ae< zR|z>9tFKn6G)l@nOZjofvmsw8y*4smgts^XYAhHYCNf)gkAX>DQ$U`fVd6{!>9t{m zBoQa`Y-7DY0srDl$HD678@lSiKsRu^IvmQ|RCKCCNG?SBL2{V(kk%(>H8vIT6mk_d zE^3C(W^|?>VDwR<3pc3&1-?n^ zd%K3D(Pyu4B;V#SjCROd4@ZV4ls!ry9#}#O!NjjBkLjhK%-F{@@D!L8II}TI7SdLJ z??de7!Yg8qis43H?6}l^krI>_?QW4Kuh{j4>EsH3Uv-|)e0_{m?lfUoEKx@x_G!BS z<6>@=8MofTGQ$`nB{uvnNW+djz8h}dw!i86B*Jg+@AHbyyoBe7x4KXz{B0Nv$4`St zz!~T=K&u{22j^M`{~ro5RN&d~9MZti(|#yb*Z?(6t0U@$4#x6ys_=-rxr=tFI81f% zhe<_aen;EEjze8rBLjw`N}m^?1pr;3|I#KLtj`i<$tUF_QZ?xK2Cjn|g4%yrxgZom zLiRD@ZBQx|DnC;^w+%JNhfEl4Y+kfZk^f$!B{?;wH$E!=M8=72g z_tmx=_Dsjy0cE7@&*%(GtRU+=HLMv9WDiLMJD5Q%ORQvM=^xl_1N}gjeC+kXOL!6m zHH75;^abt9jX$^$jv}-~k4!)$KbVrRP5|D__9LT*ZC?!(206n1*fM*73=-lYBXo+q z3MA_gmq0bd07ueDiXV;Ho}^Tu2CpeP)i>zj5~`|Ah%myzMpLsE@ar1-3?)$Zir8ZyHYA~7bZ>yM@L5`N1%q1X1Ybgbnq_ARG;ZkKq=n3q=xK#Y(kUYfOq6ni}OnILUM<;Hj2mfiDIlY@GOaE^T-t zu@G%}AaHWMkx_Ya+jilJp)KyNV`%Cab7Ks6eb_(+n9$(m))okmJhoCB@{a~p?UBdW zQ%ET`aZce{5fd|52O6-lzPZR0CeKkgr`@%2qH zeJVk5#AK;V7P0xP8O5rU6)L!Qbo!u*su+Z#TD-6J2)fP( z7o1@rspy10g!PsVGHomdbPt*rlw~YdbgHXBIDylt<0PYA&ZHFOq+kb<>K(8iC>Sd_ zotcvPA1DpqdNHvkutZ_1fK9>~s~V1lRvA*KUaoAHYa4Q*0H@|kr6)Sr6d|+@-J)s~ zAw(dtRIfM~xrap*YAqr;oK7kf4&Ox!8=6z>kpr~o*+t3q<==Jn=Ei2V(%2B2b)+dz zih_+s6~=`1*^=Os&ohXll0OAna%~UD!v_vFXb)l$buLQ7u?Kg13)TRSFsjiv@+3** zP|L4I-f9cltZk=xEdevS>0d6f)B@xuFF)k3%S?f62M5pLr4i!vTs;9MNv0P(9W;3! zOW?9P$zD1{rwYeI0MWUL&v7?9eV0y&g&;aj+}^()J`?$Xw!>>l@52_Z@Am1}Bt(ZA z0z`+JN9 zHkLS#sq?)-FN=~7&m8XAoDm!9{u{p#17Y?T9d2MSjMQN;9yw%HkVVO{$;%TB^Z=M2 zY&xjO?beU`gqFFJ2>t{V*3+>M8-Q%cy5CvQ=duQUCUzZSh!&O3bB2g(6qxq>FT&Qg)_b(B%1zK0XCRK5RZVnN6mStf?qe!~R@ zL$IN|i~q-(x55cwF|brby`{VZB4R5-DHzHRl-eq;EfpcFv2{VxcbePiB4}GKvVKL` zV3w1c$x_Y8J6xk+Wrg-j%hM+|O!h-!MJ*Lc->C3p;Ou~&*XZ+7b-zZ=dq^(Yz!Nen zQfEd3U!kGZg8!C^zISjkB%}Nfpoj59Ng7x?^Z56?B$rbt4S3KpH zm@X$T(2LR0q%s%%L_bIRQSv$-ixi{@TIjh*=ZKyQl#YFC- zaDyBi=(e+OJ$5|}D1}e(>5k)Awo>~9NnsS1;5dXmAzM%Y{2F7;w2vHhn8)4a=s|o! zYZq&R9?WG)fHDs`!2keyT8N1gp7K=sD%k5=gDV?*IYsK7k$z z)Ez~mNFfEVq~T3@(ov!m;to+oob)cK(~=qr6*g2n@tHMK%81*%h{_pk`H%O2Xuc)m z`|cqnQ;-@DSLq%2rC9JfRrkcYWzdv`u~(7Jo? z{+;W&eTy1;QU!)8Vv19_vf+|=y1{9!$ydaha6gU1i)K*rmD)&jE5D@#;!=JF6TG6^V zu?{uFG^pBAnRk^I_KrfX4D@)pYa_(Vam!A-{OOaeCr7<;e`CB<)ci(Yt9y;%kvrb@ zD$W2ky(>Mdyth;|e821shFWKM*x7D%%XfeD=tJyqKSA6Hf>>aODq+5It1Bx@Mbp|< z1Upax2wF4HLMZ|k0nuNrxxFdvKIAd69v7B7a0WigZ0j;G#m0l{MUjx0%)Zs*K zA>Uoss8zPQ-RcHvu8IxRTwQMzx7If{id(8^uWxOtsK`3QUDyBp+?6Xoy$5IAg*NW9 zw!+z)%VOd>5DJS3z>xjU7AbQU>2qRxVx-J7c6y3Zc*g!bb)K=zGVn~6fmhw{H$ys- zzi7t620pOZ$wmsuxbjC_ObRg~Y zhi(6^q9F$)Ty3f!!AnLxn8Ja4b0wk&rt@$iw*_UxK}JOch025`sh_eOTmT4CmOVEt z(X^fEjM;2b)qF zhVqqUP=bR-LwF=8gO%XLl6qSm)1hxby4spf*zzea$#c2n=rXQqe1&@bMb6r zEa4dzHOE5s&o_21W=cG#p>Em?Hpj?x9uv+&1`-;Vgo)$~1H@UXN=y+T#6Cp?p-7V- zO=V$NR0{h?$o0MjMQGm&&(z_^_@SC^3$Wd^}-Vih9P|TYQPHW~LnDD_-#UUzGK-ub1z$kRpQ2+>PVo;)5Jch*e!IN1D z;bkr%{Hh>bUV1w8zkfSQhyL0-$Rv9;G91x&8Th?WI`sb+P4)jj{Fw|E|A+8eG9CK= zgX_C}`Zbvjof<+qbZRP@*p@pRFEadV+~ZS<41W_h^yx0yr~a4maku}A^f#jO<#e38 z!GDf#%}|{KOD~ET3?aZwqm5by^oc{(Om8w~?W9k%#VZe=k5(Rp7dlfhg5RBvu$u?e zUn;u38ARB{kT*+3z?-oMJ2J>tM?Fo{N89DQ50{FLTL0*0wXLmin-3!Ft|I#r%1|Nx zlYB(^pFtbQLsKwE17s^)q6Nf0NOGH!=7LDo$C8v!WW=gxw}Rhb*$jSLTPg~_Lv`pN z{F?c9ewOD5JXwyljp)@SnyB@F$tYO?(lB&JfQU(Fcc7AnOp1AIsZV-HytGs#{+^F| z1Mk6%-lL+q?QuaekOcRQzFWQAkegrdk z=Ai=duS-PY#?bUiC}ahE7@Su<*Z52{k!Wmf1Cg-w6KNrkD?YFKv;R21Tr{%i{{+<_ zr|5_=ENW3w#c8LRw;_W-`%=;PdnGOnUC7_?55Gh+4!;qBaz3A$YFn7WisdOD^QEPt zHeZN|8cA3W#TpBg_)mTX^6{vEFxur=ihb?NSFWu7(aGm01^o^DIsS^D$>-$wZB1R@ z+^A?;aiiK$i;YfoySTmH=oH%xQD1L}&2?>a`{Y=jjws#FNq>OGj=vfvjYO+KF5Lg@ zOS8jk{d38pXOP9U`Wbrie9iOxx*QoG0}W_V?P#vPaiJajS@*;X?J^gW+ZU6B&njCM zU9GWL<-f%NxBoxVpZ^Je{1ZGc=D&#!@AQ5434fwIS9r>Qekb1#rH$gdu@&1V8%3Wi zC;Vr&IVEO>xL_v{vHX``%Y3A%&(1r;&_m9IEJ}B=^mW%h{`lVQ>y%&)dF@)yoWw3& zd22HtDb9swhpc2i(vF`Pk&d8Akap%HMNN(*mM`;>zIY$$IVIQgaQ#xs(_1eqr~b@c z`;4>Evu*2fEA>8`()I&8b^L5YsXQJBzt1-QhQF=_2b_IaRQL0KmXE-wss#6OR@E~M zmGs)A^(Sfj3))&m-$G-<{v7+C9H{f#)R6dNu9-^yHrq}WbZ(aIC)wT5`m>+6dBEs} z(xkFK*QOHQ=v!5S*I~TracNj7BwpnI6j>|et1A?khn);K+QI&W^qj!&6jJKdf&iGnvFN6#dlqeSHRQVggD!16G}SvhI@Be8Eg6 zG2nOV>AV+*X~!~|%!a0)mM0|jq`sfbWO8w{Q0giD!NdYQEel8LiTRC0o{%v7AoczJ zc9NIgMYlA!Zv;YdAYid@?B4ZNwRpmu%}bn0n(duAXJ!iNx+eQFPWpMbSnLCgdBlVIwT^h-D9)84?{%0g}=sk$Mu| z1@3u4a9HYT*_`9jkx63adS_NrPuMm`+=77FE+jwLVitHf{iKBsxjZ~zad>k;^E}XS z>Paj3>k3fqfR+hpvwu1Llmvdl$bA|kDsmL2eKDgd1CAq3E$*cMMLU|}-1$&j+hx=}0)^1x923EN}}n zBC>n*!Z_hGrr~p{4o-no{a3t5a{|r4wEioqN=<)`f8lX#kE1Jo5Y4~F$K5^^#ft$h z{sdq9$Mom)YI(^d9)HYD{R{j}Ch?%wki>)9(@*Q-Z%xUCLTu@#zWe{AnGZK7aHPNT zSuTM6BAmtL4ZatTPGbJ}2h0gq@}5<-Q|;8--THRBSltkt#m0u%E~>Rgy;!YRw(HxK z?S`l|PWo?t58U;Qsi`~Zzl9$taPgPplX(2qaEwk6(kP|l$-f*$!$Xg8*-&oT=hA;9 z-id{J(Rc3m6c_7{qo!T}8-I8v8^`0kW={1*dWaye;xE1;dRkf`<1^KgFl2U0k4P-` z_&yIkfOZ_Y*IqcdX=ZQ2#Ad~6rIN=>T8|5Pgw706nMbtbrVG*ID<6ftONsBG%^*WO z6dp=&_Rzn=8jxGSHjA7Ty>WBT9zFhzup9&b5XDg%G@Pvs$XG;y!fCLz=z;nq;+vuCN{g z>X37QE)&9^zZB#Tx($V2mg~F4pO-8_+04mIXi=HQD>eU2<4tPUbneJB-fzSemqpdd z*D!XeP`ggkc^ju#ILHP`INFUUm6J);{jlMAurMe`Fjtk7Ja)FT6Oz6sWcr}_W-a+591byKTv)i=8Bc0=2e2A}>f6<~nzEj;}de2E)&`fuPu zX45&tcnX`2^W~Rk(@C#FlNp5A{y};kRLhp3HS;sF-ORKhWCkHKGYDla(9jW_sfG)v zC`(}&L5+6Deqv}SHQgOq9kLFRbKUpYqjE>0f_Xai+h1WQk~=aywQZ)~7R7nD;m9ZG zjp`njknLEgE>+1+z1IE4k?kB31_5=w@qYOERn7A_~ruR43I;?M?wv;D-S|_F!X#^C8MNJ3~KDcx7hM4b++0< zSDzTR)4cYOfAC8@-SjV))FB*-8XA`$^4FzPak_aZ1ED9BekH@v<2`(s34ofZUuQl# z3>StiF%Hk$N0(Xamcm+BSkzjVdTrqw;OOOtXLURETBp0+Eo$w0x7etuTgA4jYDG=m z+S;zv+w1i3Bf|R`VrV>t3jCk{R4GgWEGBumaUC)AF*|gUlzp z5WsyY3~w1CX;IiX9C-gnX0GThJCxY6ErCsp{>jV~S@0Y}`7%(EUvx|c%#jgY29dq~ z0MWOpKi(@GA57?36=liTb)=dI9A+O<7Y4}GQ&8q`%J)^r87mKLMw!YI^-6oJ{IK++ zlJb##M1dV8<%WwO_tX=#l_$h33RuI-fw^!;ZP!z+4kA<$p|9D(wep?`RO8?TyV~K>TXQ+=|=BjW7 z$tgqH$kb29hSC-a$^g3vAk!#fUqx8h_%nP)2s^PAqSb@~&^?v8CoxfkQ`byClWkF2 zl>yC)TUuGU*Hy;$$d_f-Sdk2e5FVFA17|8QxY7ruA7UA(*qn*S|3uP)_zb*6KA+T)!$)U_Ut$} zsKXfaT#~N9dS1>P>Nti1=Y}*IAK_qRTO}adT6VWZxxQeNj(rPF(;R->WE|VAv#Mau zR2#CCCh-2JB&EsB3Ci?3PFItq@1uYR&L-%m@5}VM$;yH0#P{cuHta;&(jckFzx%hh zzOZ>b{`1sXA?{g#psTP-vT05s=Y*y@nleBxPot>QPn7J#A{*WsXZ(o1E0iWnW{AFT zsspuN+`6fZ+$=#YLG70_I`hzidrfG)AP4Fs0^ZMgI+5#??AWTJsfhMM*c9b$N$g`U zB=u=YxdnqP4C|f+s*IepVfZUsvvNkgwAeF(F z9;e@i{q6*d7MQ)7xkv(-3tVy{t}DO+;V0~6^)Jc?e%K4xUsD^ij8WmU2Jb} zuNS-OcBR{>tF`scrk^GC>yvUNNRrzBElQ&L?HO~&BXiw9a)F&&c1c?&U^QENp+lkKQhQci*!r- z76o-I@LJ@I#REzeP2aXV09{xfl7j45qd~E{Z~1-RQIxuJP4~Q^yHhTkqb?~r`d%g)icC(KdR62X6-lSQN?KKMh(!2~YFI)mN9%!f98Xr^b_#?exlO+b!4XmGx4!UTduL%%9^(BWv+;uWIOHvM)N| z7^t~`)eGdz6T73fCH;kJZELNzz5%s2JUrEFYe)|zb{Y`bTQa^gm` z67Tb(i#O*l-r8A<_lq!S@*EuF9@KCV&Om4el1^jtA=zBU%KkIrxt=$C- zDj{-UT<~QM&U7P}-bCV-xP@BAXcfH?grD*R!$e~Tffjb4q}(+e*IQFeL69-cKC(<3 zrVDC;my%qV?@Nh`iYXAe%FlpSVj*VNNJq_C zt12eRO}2}a+os(vlXxtDbmzwH5AKu(8ZB15vqv&B8q%=CrG0A`TQMaUKg59+$T7wp z^&AKxz^oi4P74}B_Hjw$0So1@TN9g%D<{z{%Y5bN1YSh{S1JLosfi+b+Bw|WA@0)Y zI+Ze`agW9{MjZ`9uuttf@1nnd?_121CFLQClk2~4=(`jA(?ne z%8$XN&XGZ7c0zuYE2%$nz2M2nmPk4!xC<{qVti>vG&xlU4dv6bO$s#qMdc1k zYw_WtafaO4UyRCYe;{l+ocsZkx(AjB=NZ~K>SAG3LM0C;K+F#Y76@NrgpM~-P27NW z3Yn`#H?kHFCNhHItCf`d!rRB5cBGn==Lw2&kJ52N-W#9sc5Er)Db=>1-IFqPN8A}M z1pn>fl!QNEesQG3hDv6CFwhZrhW7%jN3nyEA_gMj{JFeII)~g)eP!ezByv(d`P?_> zpmxsH$49zIL5{dezNIZXDoF{%RFKk6(qs&_ZPNiH&>(mlgEvFY1O^S#I9jA!zJq6H zWcgy6OF)A2rt(;RrzQ3C=p%j2IkqWsJ4#MAo?DyvdC@aiAmi3&$hdk;w^HugAKf6~&RkLR zPpW5)ED`jGMU0K=c%&4Dn;sxMWMe_h3I0wr?vL9O6`O^}c9=+Hz$S&lH*nr?hyb|8 z7j_;gy*PT?_90IHB$%kTxZBqN6aB_oz^{In{At3Xp!d=Wr0$^QX%#m};HW@*{Cq!evN ztrl?VreCk}3iJUGP$&4*NO77Esl ztgH2aRsOqtr6grS%Y+6E6k_ZfweSMd^<5*#z@k0DIa?MEJ0q{(B!9rXpGar-MR4X< zDGOMQ{?zg36NGnvHC|F_3m13$+xVNT+}WfnZ}zX#KZzB{f+#W)Fd}3Z;F1Px65ni=v(8=zV(0Qm*a&n7VaMR`z7`9xDv+=xyn4dKWV!X zr4)1Nr<0=pwp2<3AvUUHBUx@Qo$l7P{4!qT0d5M**7E2{ZX2lEv zmldq!__<~tqDDBd>{z6Aih+%y-4oj;7zTI1ATB-BNJD{pVJGwNjYHo~Ej&KuWuJV} z7h!+?0v9G<2C&_4p8>XuZO7?Eq<<5*gW$Zn%wW5Ay;9w-SAmh(thAByR;(jL4~XkZ zt-D>XcdN*GTlGWq-ueL)OT;B_(BLI$sk?T?{Xb^;HS!RyFDMTniq5TP6-P;-$- zJA>D~a7jJPV^G61+%iwi<)|(eHl)>vVcpYFP8N8076(kBNgV$y7I>L{!#)&YJ)0B1@YLLO} zGI(9+t_abU8N4oo*R_T)u@j6MAaFpFMYB>uylEBJD5D#`ZNmmUP@np+>Sl%FLxzaA zA!Kcf;zUhv+^m)=vSuuBv_c)ANlvg8;K|Na>{bP?4j4K5=Zgui%a8&xJR5cu7x-Gh zg8{32acOxnB%h!C;}RfaXQK^|-#P`!7efi8v-4XqCrHf1&(QD;$rt9GiIA#5^8Ht@ zr7rIbM>TpLA{7W>@7k!U5umgWS2uE_aAEZfRe#F1Pb2g~!SXx>fzFa);89d2OK3NzZrd_o?5cAxcA=n3 z3b7^476-^$McvriEUN1@0RUTNtGHF&s-lMbhS*fMkaS+O=KEX^Oc7SbK zOI@n@_bF=>SBmSnPY@t&Vz;0uLWElT@kz)4V|c$ix#^xKCmJ1=5m6;E-Pb5E6S-?B z#tM0pG(qTY;ZTwd;ot~6d5Mm*0kUn8Y-v}OkAVoMNa`nuDTEE2iSo0$7;VHBEshOL3n0cTHV=*M+{wSftOF6pB6?pt zH~p}Fq<7FL(H~M_Xe(C{1g~l*l7v6KC<$lm%FmaMcRBI)iq=({pr8c1uGYfFTF8}= za-oczW|ZHh?6k|DK3OWde)-cUN4;@>W8By3OV#mjdyV0dJKpvx&Hy(0O3y0qmA%1m zx!6kS3=ccot!}xxuIWFjI=7MZ2Dm7A6H4H&-0I3w&B@MHDje;u46z@2h1~84Nf43i ztgARw@Rt;%eYkX4#)!lpB{&2fK( zjGEP6}7P%Tb*K~qakO%`C2-{dUns!K zhJexDxVdK!9|XTW^e+bGwbD{}n=_3rXK~V5lbP@dW*REl=bQOQC;@~j4&=cE#sNzE zj8j{rr-PwG@8(_PUj`h*&pyrC!D^YfzX6pO? ztBPU_SCEyhi2=af&FyjR z+O=!NH`WKj3_&3LNKb65(F0%F#Z*g{hwOz+di1i9(jQKgBUrW8weDe zg?3k^ek86%4mBJYghL=>Gw6(iE+%#A8}W0-!68cxR1ZRf#OOA}^YsA?hqSfkvQ-Bs zLwA_^cH}{zr70~SNNOpK&kV@czVL6Qz9lQUCUg=AHDC@9J#U6F02gkIlQQ)!`kvOY z%OG@te5Jm=KeC3g>xg01AYmfqYn>XGE^!7Z!bYztji()#Bso9RXCXqlW<6r;jXc;QS*K72OZbhBTHpzP3p;F3Vojcms~4*R5QijO z9kg=oIvIXUyw2pqyc5Uj@rOZR1s3Kpxe15h_~ zVjWl9XTh+EHb2LwyT0#w*4lG;Dqt-z{T6WrJalP-ey#yBqcKLYe&XAM9PTbf58@L_ zd$l6?Ac;ONB>UJqY3m*VIss`@yKWQK%#aH!&lNcUQu{=BJn~*}11)Rk1qO@89BiS6 zHv-ENOp2yrzO^mzgPUkBfu9XjcOarOEVu5!U4v~c7$|9j@b`fYwmkJawj3TTvX z72G^s8NONFpa@zS$`9Z;FoJSl9eBNCtf{P07sP1TH8aFN0Ou5{2Yz2twk8`Vtx(Zs zVFjc?@@}yw!U`vwuF6i3)i$u#K=?Bl?@(p0J|vGUz8HHQ73?|3WOWL_7E8KYSS#_j z#@ft!C(0fTFc(>S-Ah=x_*r)nk`gdH)5jjkGO$J~0Pu;-;$1VPtV}?5=38Fg`uC-bXjE`D1dB9XTMN6@~s*G@X zGUWo#v@9m%lIRJoGevd3dkL?ZV6NAjSiSC^WA|!I$wQkoRzd+@+I1zCMnu zsftTA37GuDp<{TmqK2GB>nZXL96{3JOdz2O3)?3g7Y3m0tQFAv$aPApsGVr@N# zG%1-aawcJ!hUqw~!M~8DcFt^(E7YzZZb#W7Ch+r04a{2;*&>^t1^w0W$+-0R*SD@z zLw<3z*INZObuwE-B2!(g?8?~BeS*b3cct33ty4s3k>j(<7!lT4l(w-jLm|aD zR_)_9^1`oF6aS^2V~{;$5eRu=eVkX#UV4_>H*+xeya@lhn_oh9Ah>nW%%<}qkDIVHp4-#gLarRWtEGzG0l2pR=q&8@=5W(!fBs~gt~+x4xr!q!e>-LBW`E9>^omwH>oWW+BI`zY+??}zU7FTeQm z@)o-VlgnBSbAVIZGja?WqWy{cJsmZ9-VOZV$8hHqkdxv;{14Hftr zO68Pk8cW^!?@QROf0uv0k3V|PF0=R_q9ec4_qne~5PX5X?xnIA|C{e;2bfQQJp5SB zTZ)d`ta_~~BMoun6#Ete15<|vxs8u`ty9an8y|hNf9EDVxvvKe6KdG<=LY>H zJHTueV+Rh|0j4?w%?>cL1I+9IGj>#|!3QReHM=HuB0IoTOV`(NfO)~NiZ^jCd-*H! zIUAnWi#fXOMLy?>IL0cu85_wr^Abki_|jr&Et0DYm+XW zq$kgmwS>BbZh^`v-aH-VG{1)oVOBF;WZc83YqPyhrdDtiPgZ}To}n+NlJlgeB6m(@ z!k-guX2Kh_kHoxA*Gaoc5*?y1MZO1BedT<}44=5+lV!V|fyW@ZagTh2bq?=Ij3Eww zhv5CI_7HxColWc;cQ(N|03%CPN6=L3PRBm(dVcxF6S<&6U2f^0i}nCCEKL-nKICpH zDi+!JAZ8vfjgk*9R1<{Of&$Uf6I5igFlC51Tb`de0Y=pBqE?Cii0c_ zhx`+dfS#MWViNl$qD{Dfe`5~HjftGJx$F1F0}jsUz?bjL8~Hg6SGgSv>`!OoemEU; zu#);pzmL0@V~HdPPl*S+j;AC6A}}a=8StM>P?}9HvQs z?^%(Xsc+m)GPabWcDjFAB$1ctVorb4<_W!=8Of9SrtK!eEzO|K47rS4^ax_S3e)X| z2;fAhrD@`4u6LZAlQ(seA3ao=@Ih$k&u7; z?gz}Af8c-?q8m(c3tx#KfVz(ijH;r2C(1R+V<#Jq9X8LB@|aj{F|4b%w)1uv;n# zBni@OhBjCk`lY_p?AnDkVn`f+TvB{;ETF_kb#?go10+3Ie>rL(^8r{E?PcqpH$s+< z4{7MwUB3?$EwU8d?sT1&71qQ0pasx2z@7cdb9&aV?Lp6W`2=rzujkbPShd$`;rSrE z^T{YcS@*lv(-2yS~X%q=)L zZH_=uX>Qnao4#{mRVt&kmDTNA-e>C5js?HViRTYH=D`D}(Q&<=*B*z@{>pIy(|}q$ zbWU){Y6G)Fwd%fuz6@`>11YqgIvrPa6q{{uSHpXrb}6f<4HFbVK@j0h%A( zqb2Ir2pEmPanWgkd!0Udbgx&qV|Pg9insBlrr`G+cWgaYgl?j`o% zBWxVNo2r;3aPMQ}sM$X7Y~sb-+uMI^O5xNA;G1+XaaM}kt2-+@J8SsOw@<3klyXPC z-WSVOZ2G?D9DD64&%~y}XW<-w!z$pfR1Zrxe@G^K>#;p9+`?p+pXAT`p5Ofpz%B9x zT`m8947qJ}ff6d;9@!8?E=}g%r=EZ0dtN_KKXXus>~bGtWB{0eFauw4zdr)a=h%AE z@doN%DM!^sm5o`C*_$YSVo-=g$wjnf)L$c^{-ULG8S5(M3n0}1fYWV5i}e5&q8a?bBpg_;efy+r{7c6!@s`M>XC961#|v% zhhT_Qb5CLTV7?zie(|N@WA@7pExX@EHE=tEJk)Jq1NItZ!*GE=bnNuJ0q1AniOzLi zK(BTkAZ-S?4T!yHP9MFGTsJTRD}}iM(41pFQ+LK5dVlSX6#)GQ5JRZ#iS2`Pqu%bkW00!}!VmgR z*K`;v>7p9pgmkrgHuPU$enV~m0a}diVlXL|FqZgaG#Ee%P#@qpxuB;-!_mx@6?=z+ zvMIfvoZ#0vzjxNw=b7P-qw+(e74r6zQ5R{y2M#nbhDBsAZw7wJdd8PNpRtZNAyW`m zAR&+4rYztE3~v+P0ny2l!BA9X?^5ktT130 zfvBQT`&=#{xENc4nNHq%8`BJZZ0!*Sry*-Rh;{Yi?P)_mHxU@+dY!jCktIAQ(+Z}9 zUWOrX@-&iZAylX`h<}Cxb;+)RWE?rp04Pj0P?}IGpT-==$-y`*fJJk5MAbkraSyOc zKf$aFg5_Pr8Z9<>L(Q3G(mvPxu=Ye z$kbrQ38W5Y2m-e-bI~DC5~_}oY@?;hpfU><`vxirOBCVZh0L4tv8`h^wVTbbR1_f3DBztR{g%yzPZA_{e(Q%K$LFT4F zhFUcXa@QwXApSkIZFr*yK9)Q*aB{wJ13S5F2R68$&_(y)I)!sv2(Is}ZmeuxpJxb@`zY+w?s?cz1v4}} z#{<&<7iBmg-#kVvooA(CsALO2*#l}aG#MQrYR zJ-b6=D{$}~A_mO^3Rm=kj2Una_x1~I2Rj^~S6~~|>9#vP{J&WFR6ll~3n^7JhAJ3v znNxWGW||kRYuB!+h3^i~y$QPb_9`|TN~RAyl5O+{;auK#VKa=N*R6Zlfns;%96<_N z9Ky*aL(pQ@`(3e?MEI!On)0qD-vygU%^xqiy#Rbd7+0(jOpjz0Fwb=rfM>7a8nx&^ zySRW4#kQJr5KCm&gKgzvmuLYN6Y!2=XgzhB*r6yvr1eDD5A-X_K;sXgCg7xDvutS= zExTDVjajL{dZl*UeGq;Rolvj~_wBaCCUN6J{B&;5Y4d?{6@yX7WI**`dBIr5WEGTA zC?`ldD^4Bt^$bcu4GLBuW!|;0DWVliNf)6M`QNpS_hMpBV2Z+30iT3Fwwu@%x+Q3x z_0q~tX>ChQ6mW6`%IJwUHU%iHqo81S3s54^SoW~c9|cDRK(7`6#nGV&h0S-t#e(J+ z+8_~Z7lvLzNqyE1S-+lC1zQ`da3*Zd)&$SL$mm=UUOpOnVd5>u zItnZ=rxpb89KT%x{BOe5N^>l>!9Y?}f@jdUADQSRd_8v@*b%bydF6Sqo<>bS6v* zSf@$2TKG7S2n0}N%>VEx0iRzR9rtU^!h}l$y-}4u$h!vd7@<$Db)#&pYD{7tD{Jy7 zA%#-;!RD^@>AR>0V>kWGTC>V!YlZOCuJto(UA|2}7B3vpFq^6f`1W9+bgf_D|4}J7 z_MBAVXZSr{dcJG@(pp=Ze8=oY@K@YlwzkyEbTd^0kdul2afhAB4ibMAYPg~vg7DzW zTD-a}AX(9MV+t=HPOYZ8-}t5 zVbRe`P-YaKODJJi{+R^Tpp~S4d$Tsw1gJ(j4ZSx6s*%pdeK!HBk$R*1$0xyf zXEGPE*%%x(c2ZyWKdrV(_kR8KL)d5^;|v8M1Mqnk8^Lk<`M3Z4Y}k*~cm2Ds$zPcI z1}>h@u$cNb+ztsMvEgZUTZl;K@xH+iEuM)`LheJ57^c3FIkjc*dOhz1N1(e43#&y$ z+moG9?Ip0!BUxhV8?wBMV>|F%YwAtSDk&_G@ZK0O3+^=0uGF_?MeVRPDJDbVa2CxC zvI^FYWN@v>y}4zlzD3`|ffAP(gyUQZd0N^vq^aWTfDD;YuyJ~5A~eScRa#@G;l(EFc^{pj;5M8AqWYk7k9MuNKNI1?;q}x@;ZxNDjt2;w5dzE=F zf$ZQ958#pg(!j#WSohu-=1%C+c5&)uGfLtrOut7KXox~>2MX$L3%M_7yg9+s&7IjF zu!mw8O3GWC`l0?K#upEo3kwj>T@CwUl~Z5spQFx*k++*w>_PL>NKP6jDfR96@3zK= z&Gk62NjhCE-`g0(y%(wP*TuG5Iw%eM1La?t<-JIK8_MEe5d;;+p}FMsDJF=}SI((LM(HHg($jhGp?Fi@-ang0D3NAaY*y-Pe_d@d zn;!BaTySg3ZgY__Xj}`;wue_FvzEDcVsxjzVSmJg801?ZRlQB)8-ZV*f5}$ohv!Cc z#Nozgt{9zX7mqP>?4)eJg_+bIN%&-JA-2mP6q_n?sm0s zh0bg~G~1mWcVdK#-6_uEIbE?8*Z5+SuBy5Hi066f&hUXvdzdQjsV=5?+h4_jQ*i;O zAx`I*|KmLW$m@C^IF#YC5%)j5*6yCAVt-$8Pf@?zK&wFeDPYw^oEtcZ62`l>=qG;F zCjG>(X4QkmTmb-wIGd(T=J-RW+swK(m?}(G6$i%&5s)II^c79MnFbZ&17AD&QVEUVkry9nC)&Bc`O~>}_)qxU`Ri!k!tZi}s>0#l;rqkG z|H!}5O<#9CU#`#4{{}AqG~oF!RonhURPBqkO&a|*4aCczEG%5J?tA(i=Ju11WgS@1 ztJ>9S%9%dmE7g?mCXoNHRMo$q@Ey0^D^>X)&hR5&sRq0~9kaK@8IC*-plYZzfZUa8 zQC=|rVY2o{eMGx>Rufn?LnLZLM?KS^|46wVG_O>v{-QYas-`7y^_!L$`hqLfnE$V= z$QB@HA>pkW896mZYEol_2p<&;KoCP>ABBOX7{{~NZqH&r0REaYM5brcd65?}e>6YO z?ZO!}1criO9)SNVHB#@)q$5ax{j=>ef&Q;lLw}K=C19H-0RQ=u0{g#G?aJkI`z9hA zd<$$v#BVHL72y9>YEwo(l{CNwXzWDO+FBiY{t>66Zx4-qRS1{YpG=$GIEfdDtg!wbW zpqOWgo_EnZXBqizR?M%V>gHD-^G?Sg+6+=u4=Lp$zIwMSyWxL`ZaRI(_$p_87s!RW zywk}4^ZVIpBoLAZK;;7ldl4XkRj*YAyr+vZso1v=#EmK6LHQZ;0B_@CK1>0>@zF>7 zcW%CRB6ysxfgWSBHO$bfbd}F=ApkL_C3bmCb;eJX;M3-FkFxA!plk!Slfwwa(Ye4( zveU>gDy0ZeX*tmt0WTD=s7+8XV3YVJS(B5T#C3X)ekvX)S{aMNGOJqL}H?dF$YSH-+v+M1f* z{{=`uI1d244E*>!{t3FDIpzH7%JLS&4S0*8|RGX;&L_I-CK;j`EUFAtn zu~6k&s^s>x8;~1aP@}}!r{AvqHRg5tSIy6u=n#D=@`I@AD@RBcFy=lh1w(L#`Og;t zpHzL8&uQ8UrwSZYOgtzO!6#m}^0|Q7J1}snf{7R4(i8oQpd<%*!j%u5_PBiD4IY_m zPxOxlA_^pF18zT@zR-L?!pbYfm6a8c>ySWgfNwhha_ZYJszdJxnD*rrLMIR4*C*6K z6)^W83>lYKivX#VY7LS8(MOR4)0AI^#JGYT49Vrs+ylv%yt>fwz`;|#A-~J#A|oBJ zfyn|MvVe!LD&XPI<9njX#lbbUhJN09*rlHnl(C@lNF$8Q_9CUeLBF2u=b8uNW+LW(VIlR6{lQdDK$ZYI(yQs2ls^8(16mH3hRR<2ni;twSU$7G69=TC#5 zq`plbyy4uL)HirFoR5TOnJ2j?^-X#LnT+6BUN`+nfuE$l(T|8!&xGd?p5?XDqprYO zesc<*MT4K5<8jvDD5)RO9P`SikJ#fobJ_Q%z9ByhcjnQ)H}#eNv)RzD3VI~aC>KWq|Y0C|1 z%S7C|o;f;pJsEy#uJI%^^&|CuUe5BunWTA7V5koqUOqmpLC{8+izO^5n@vdM6CdY6PciJJilz6kTyO1ZjmZk z9ZKBq*?oJxuzicZpDP2^lsj_0lb+LTJ5@#IjEI7G@UtO{&PB~jHvUZnnarw$iSwO@ zifghBh_vu}3ZKo|v>Kg}dlUe&yWybjCAOg;^)Inj z1$j|{@_((4>K4dI3A8!aX%~`3tBYs|E745gh-$tz>>kM-k=V4m!_KHK z((W;~sarDlOfQm~Hg zp2|^35^-{Hx#UNFOX9o4CQC!*C-r9gHaDx67|Gei6 zky!$y%LW11nHLdG<^orIf7BSFzH|J?((VBTJfU)62xy&y#EX$&YVz=r(!!F_TZQ2W z%FjZqr}P~ZT3CT1Fvk4=bOSiq&jm0aPF$gUWC@~Z)Wm#WXJbw>NcnzMUxJgc^+z{*tCpk@}Af*CBVAZOH_}g$9MPcJh)rz zH#u4H&Ng*s)TLpCixu}FSTVV2HgqFIQEU59LipfY@wT8K1U{-Z)I{fPR}G-C)+Kin}=1B5(8r>D?#w1bENG zMSiyyj-nc7EK*7oASjptm^L?5?^b(u-Ra!~z8e2`fH+aX2QUj!Ov6V)JD;Ey3Q{8E zL8`FE#ciks%6C2;bz$LPh0u&C4T({ecb{}H955#O1DP@$RV?2Hy?$3*k;$U#+|aNy!P+!V#JeBm@!&(OywPE3XnBjvOG` zjHvT8mG4D}EKj=%}3 zp9E@~w);u%3h5%0zcKl{4MM_PyxNPM!ExC^8I_Q2I6d&yRA-YQnyiwBSsPFH0 ze`@Vpb{~S<8TDb7ryU6|FL<#^Hb{~VxB2gea9J6%K7f7RcZL#HgxDubSpnkAte#i#l0D z^x;7y&J)!Mte;Pe(Y!0SvO`4=sRI$d6x$v>0>cg_))g zK9(*fsq`4`9s`}ekE|eBDQ2qkfly!>g|1&!ww|ex;FS72`pB<~zSnaWcdbQL_~P=! z<$3pDM#pW=&~fWA+X@(ckM}}jXid#%*tuuh?rhLgu|_<<(V+N|*WP2yI4pbHH))t^hv#B@c00!d8;Cnd(Ssf#fRJWmt8y_Yy62n4@qT+&LkJkGd{X!n#&eXT+^*Xj0o^Myf?`ov4 zS+|gU-!!IydA;rG9#I=Sjx48rRcX<3RB9f(ZeG16GqCBjuu{T`&;~m;C;r51(Lz{s z$hi`lB@gOP?vXm9ma43$jwME!G5k<2G!mSyu)xfolN&GEkTP%_LyG&*L#MGe9CGxq zW8;Cq>9q=>J0=|dM#q!a(=>aw_$g=o;o`Ejcocp*HlL`j7BMV?(NO*L+`I-xFjhXh z7kF&6lBKG2G|`(%a>xOjN!`)LU6{MZbWQKL7GR z{m!=lzJ>q3KuVn?y!~tBx*h%v{yhIOe*x5?AHO~a%2$mNd`5EL;deo#5@9#Zq-dE{ zy*Cc@dqy2!u83PpAI$~uN+D)vhP$4oH&6Sn0Da~)?t3Gb#jK;s-&$&);#=7XGdV}w zPM(H(IT!8{px9uP@>H^%!{^uLDUcL%7zk&=Z_QdMvJ>XHoX=*1v^ryhl$|g~UgzwD zxioPkmYp!uN5ey_Xi>Ln#@fqHm`kzqzpvw1K09GP%UMNF%028r68=kZSBTFfJ7Gp3 z6ucbS3A2t95PxEHsF0m7%Mp5Z!ffI_L_XH^SxI)noSiWD4LTW)5wY>(0e;zRF0vEm z^(dqyJ7FF;5;CR&uCfzm1m0yQ%nZ*#JVJKDoHXLI6K0+_XD7_r33GPB`~*>0#D+D7 zRt5vh94y96AV75n*eafH&(5&xQRu|KL*$5J#BxTz`Qv=*&afp0e>g;39pk|Q51AN7@k%_Tg!&wqz{aA5 z@caREF(R0Q6GXKkFehMSP=Kgb@oL+_5%N1;3>j`Cr_%6AXe{>IVe-X;t9Xzdc0#g) zvP|j8bL@3z-Hs)1amok$@G(0 zFC>dL5zjtEvK^x^-EqZ5a_|r_pFQNps=^t$iEvW8cVdqbhp!XsRD#sls?`Fdt~H!m zZ5f~Wnrf?y@JW7WU?{F5_;gsSiRd$OR#&Cs))`w1sgK9{s*319%5z&I$3Muy(Rq*v zRGz3_#jVxi{RKt<(gdS6s&0vE!EoF|JCF>8Ts+niRc7`eGdPi(R9g%>2$63OhKs5- z2-8J;h*xpZJCY_uw@`~o+l+5U#!b=M>kYlOgU5Zq`=Zo&8;0@_2Mov)uvS%&_lTJ3 zUYALO-W<{C6M@gVzhU^PnCG}WsQA^12jY>^>*gtmj9ym}{!DFFfz3!HRB`?oMjiJY zyC=U`8uka1sqbNCX$g7h$dVyMhbGE8VUK@`kyGlmEy=pmYU zlMK%;rkk4HY*{SEo4w3bJx=if!o;YrsK<0DEZo0sfwd3?hv09!X|!#W5;u{uE16QJ zM@q+Q#Wm2MlpMD-up38+Nvryf&PFP+JlGQ0+#&U$8C)|@72_{bF&qq)ht`0eQLVhA zbiUQ-q1Mdof;xsO8Y|NRsfBWy?)2%sMJ_7-5BV}kJ(PwprwQq%(e_Z4Y4F#z`lppc z<;YqgsRxQ)ax|=6iuA5l{frw{LX5a#nm2NfDo@|Y&8#H*s`M;T5)j};g28SKl6N~w%c=GuDDX*#7==i!97^$(E8iQsBx|Lw}S?ABtdoYuU3byG3Y zwnhEifzh@#s1Rny*(y=YBx4c(M8{!U`SV|(OTCQ+>p*AN)|Sw7y2TZ=1KB9byhQUF zfU2i3@(y%y*9R_&Nq$r5K9R)FoA_XI$0so+t~c$KMl8Px6H?`eFxQ2NN-9NMmc#NH z{~>6E>3Rn$T~8nSO8yd4V=C?$kCv$jWNN6aW3k8){EUcwB+puQovBDQ$*>7?^Cv>g zR#&!wy0EoP5EIx#(R3;}at;l(E%K&e6WL5F+W@}p!v1HNzxoaiu7zy2opEV%_`R~Dj$iE6cJ1X_Tak{nUid~lHqx# zx(3s>oAv-nI|Zik04hyZaH>{hn%X{AJYJiv2UruVeAs!=va#z}h_DeU0EOxZ`dtJ| zfxj?U&_`OoZ0RB)Fez~W(Z^aU={(Sy$lN)CW;u#yhCm~%^OBNCoCnS&l%TB&j62tLzB_D| zX$T5KViG+kI+0JM`f;^AbOba;rjw}Q_-m!fXu?$9U&5GEQmC{cje(JCq!zteRJisM@`@ zQ}^v90iK{?NwwST2H12P032A5dZ3Z_=zA}K+@V}T=e*~>eyo~!3@<8Dc5jViYD-O6 z8Pz;e>%GAMsh&&^jo%|nKhf1~rCtTmK^=GAIg)vHaUq)IX!oDdu|+C1$Z5afHbIi}utG1T8W(X06~bQR}+wF{~O3jt`RPeVH?|HG;@M<&{{^VrSR~ z5D@wUwU}xJt;TsRO*6ogv0Rgu=E~O3D3O$ZkxFIPhl<#Yj7b6JEH>5^6iO2~Aq_(J z=@lGGLnfNGcR1ggK%jw(tf?0&dWvS5J~)iyToaF$=b9}Jw2;zaggiWE%!#P2frpI` z>O1UEUCWj+x$cRkfh$je7lo@zV&0*}@Cq_fA6^ISh1HAD7qrsQ5Y-0h02vNtkgH$S zLMp={?LFJnn^;|A@*4Zdp}j}{5CJl@j}1BITuL}N#};&Aw(8Bz)=I0jy0Nmd zwr;O&mQ>LJ_UwQXFf}R;#!3mt%pPNliuKYW%-N(3V>T)p7K_V7v_HirPkAP}P%CRk ztynagG_qQ7ilKwi`$TJSJmb=~m$8isKCUU;Qe7 zv({ib#JV}IZE&;lH)te=()C*+s#-5zQfyQDU`ntto9C>0$ zvJ zwQ4{`)vT{AYSp0L#T5`cF!X~cI>8!^Z(udDNTY{tlF6%TgSHvK5A_y;hlrku510{N z^9-u50247x#+j55lp3l5Oik&1xSsMh92|HkGCf3WscB_4+Q-n%Tzz0su;Vz)`MP>W z8#$<*?2cibP`E`nxPG2MWlEI~P(Bjx8ZZRW!)89o#&gzQPfZ}xc)EswAB)Zy!3WK=$OE(FV!G=R4OXLUUbHI|-+YsD>asrx{Dm2=cJ9iV8?$S~ zAQ$I^I@(kiYht9_2(4@O%1xXKLTdp-254_MfGdV>e?hSMbOdV)I}cGG+|p}H!$4Qc z{sWehQj}rIpR(v0wXZTsYBf`kHua(Rpgy^SaE`Gci{?yjr+zxCW1|K0D;nA)CQpdg z6CZt%rTFZPf#!rrL5l`F$C`SS^SHdaHGM&*b9sF&am9#$0tSi~W_q;BVUf$TdMwgg zuP2IA9b;sY8gHsgpwMDKLR0Wb(`rrWFjJD!YwK`)vUJl0@i!(KZ!YNeo0U_Z{)n)E zBE7(NYSN^Jc6ESQ$mI@uKhC7cQc;EhkB%mfD58BVA2It_^l7#$p4uhrao9`mt~djp zl9<=qV(;W7v=-QBSPjcJ7z=w_J{N7E=kEkDu6PEQhJ-}1H<*~Z| z*S|dErnTB zF4)?#sN5lr;3z%jASH{+E=uv)1|M}x79Db9Q zW)_v3MdfBuxss$|$XK(e+$<_Li^?^rM_E*^!HvkGa+@BqHH)m8ED1cv^5$`!NTR%c(QZhmcq3u2b zhD=CM?!cj|%P~aJxGagZ<`x5l_t>&s;8|5|trOo)Q0*04mP# zgAe~L;7uPM66Cb=gQdUu5>d>Z?=Y14-}9HN&4K&!+s}?JHzalr2;L%Kk&p@l05-*p zoEN6#@}kPzl9Vwdc!e>(sc+BkE`o$PLeITC;^ARjnuQ4ZA0g6*{L}gS__aUz>9@Z1 z^6jm)`s&Ww%2vT??z9RUYt7Yyy|ubgSl!%SYi@7uY_IODe|h+0+6G&5S7KN1xUX(V68GlW%NddsGK1xD+Fu!WR>|uMCJ@pStI+IjPeXo88F!yqH-7T z^BJOYhNzq&DhuFLhNw(XunbW-LsX6-C!h9_po5S25YAuuavvD*eS z^{U2hUo3JxhtTcUjy)GhXY7CT!1wP}yUlX$#(d#UhUGUXf1Z=5Pyiw4P6;*q?Ip1{ zY_5|e_LJHC8EzB_XGj-B=Us@$M=A(oZDee&8Jp`+amOJi23$OvJUe7z#T+_=0yo2r z%5bAHHrI^JRWpmj+WD=-jXIB3UMW~CyK&}psMym^P}J`{M|ny%uW;oK2`V+Yoow|d z3l{<~8+>(s*BOq<9Tzb+Cv|*rlFQAIxRFN>wN+pjVAD<3J3*(e_{PXz$MJi0G&6km{ zNl_hIWlh#tyJre8$o~?C%OuToIQ*cFk=G+n z@@(FxWnmUv#IS(Uw2HjS!^P+3HI7(@LOO;)+Fh=6=AdF0h4=un%I}v$7H-z zkymvGRNObT*i}OUV4X;e_fp98glv*Dw5u2^?>j@1ID(8-7_voNRPRDC6__xLdoVUC zt~a4+?2XaY(-SiydAnvk@=5W_Rw?EY89%-#Ib?>ccNC1kxqV;g7S&rh>^E=T1T`fJ z%12YLs3hUp%JU+*+%Q;{^#C)j`@Um0_l9I>0G~ykKU-E_aWgLMTK7ek@?E#ua_r#< zDcI$Wm7T3+uDO#x)w_03z6XhRq;wRca42587{x93+Qr1C;cJ%#GWDthUUMOQ4N%-; zZwLbKM_!-_5$=W;spu?AW(T!hG{Q()S2|3OpR63Blr-C5ax7&=h-AI$ScXJydYCan zP2U@!U(kR%>QjDDUMa3DL%;?-8~j-D@w6_=t~p7wKItLI@cuHqzYOm$!~4rvxHA^+ zjD>rKX&ABDexvdJHV}nz$7_uGutITOGsQrm_N%0*SEf?MRXdgVrt`$dUWoQS>~+Nf zZ8bVh<7nW~qQ+kO7#CsUVsq2(Hf9>)@g4FtYcB{!eQsTZTRgI)u@h00h8;T)OC2om zvTp#ruCe5tZo4xKgkAoc>>1SNwb=z>{19AOJL?>K$fS=hx1)u32@)9s4Y+y&b_ zlFEE;BQ$lewg*vMH5dZnsM_o{5@vtwS0MZV1_{?gqfYiBX1_+m|7ph|K{fg0ZQ->y zyw_rzYQ~s&A>aYyAx8k$1AGB^vfCP~4x=LgY$^<=;E;g5+qbPFXUsj5+GTK;!}p-y z!jerB6iYWc*m=SImD4OnZWwNdq_fbO-2pP}^uCO|#>S6u+_lw9^uF`h?sY+z1V4nT zQWY+fDtKRX>4cOLj+6Y-#FjMTL7umWn>7)x4_t7qYxZT`N;a5sq@8rSZxxeTFYuIC z0^&e_fagL?q?NI)EUtw+R3pJau^A50$y0mRnUPI#5ubJfMU5RetzmUE?DjBR{ekBX zt+q3)>dYLyIfgjlx3EI`SL4;W=g?7u-M<2{546t-U7%!KW)-Q}K|bv@x)>Yf!;(fv z0NG0`2WXyrpt^Qg7BxTrpT9#zytCZ-TrQPCM>x-YU4`VV#`3WDC@vH|t@BH;-W(|6qI#yhoq80|2GF&~>c=%4wIkvgRMa$j59(Ia&pHkv_QBjMMxFogC zm~6Rnn2C?Aj*hjn-RYUT(~G)8HqSA0^z@-OKVM(s2xqw0UgKzY*Sey1aA=Nz+GxsI z|DnvpkKw8H4q@WJG!67=j>SN2YPxNxv?m_CgtSxqF3n?okEoK4eM|@9h*>Uj5Dp!H zXcJ7`I?T9M7pp2V?~TeRxd z*NOn)9P$zfoah`Ui&L+AeB~*hDj-`s`u%m@k8+?)m7h@J!7gxvD}@-+_EQcIpx~%kB+2 zwgn$IYz)`&(P!}5qZw__YhrZp$}UVfv?f428SE9gos(4e1uPS&?j?CS&OZ`|Zjo;v zt3B*Zi`6O=T-O6ErnSnC82?5U!&~KV)|y)FO@I(uPjef+g=HccjJ#I5eoJgtt5Q)b zfvg?$?(?*bwp{sHC8u2ZmE3YAr`+-KQMuIRW6UjH$vsaN#uk>>b)BT)<*g0+{&}8- z6|P(?$xEX?uC8(n_RtF$EWaDTqEg2qRzB!^G_0CSXd)J{#>hWLAJm=UiR0+8V(+kL zDK4~>DW{gl4GG6z9f@qNtY9DG3{Zj+c3^W+=y8r?hM?OA@&?pKNj62@MycCxPgRta zsH#d72LvUUTFnpePP>lR6*lzRdQ?&cmeSC5Jni@_>oOziQboR9r^I<+cJt=(eFgRH3?q`yS4! zF;&pgE`kN#d-M@hVTalO!Dt}cu3Ei?-Qy7I_C{wo90a?i(%fdp1@NUagk>9In!BmV z>=O{kWx`BD^vBRTeMqt3`c&%Lz*i#WC+SRANA?zmg&H2e> zY+7vrJCfVju3%4Mr@s1sZs`L9W$Aa&~rHmzH=={4q@gQe6rYIUxouiC<9(RwU?Cnxnyx~8_e#?hoVq~TUy&RA35h#x)P z(>@0%ikN>b^%ej5d>+8mw__DP&3Sy3wS|RGR5E1hoAf?Byf}=HT$;)&A7ydK#wMA{ z0q?+wr`?D)M?S%rzO4J{->2p(!voyqe6?J-B|Qa^~h(g3=z)iDNL_Z*c| zocG0r1s-GU(vzF|w(W%3Eph-PCY{>98B>qW(+HQl3Fu)Jfs*>By(=zjBvsIb?KIWc zg@@me)v(3U?z`#G(FSKy*9lVJz`uY$J!~B2Q*R_*=y2IheFMHLBlKu2UY+9QR`>Ea zl>YC3kv0yc_Ypk8LrdFg1jjgi;E@JhZJa!cfe+`U-Qm0Nv0~{OA{;Uh-&1$&AeK^$(0V96pJ6O5gHKC8>>G&}+*P3V;8^u#BIN-Z=e1tk+>u~VAc;n#i zgGbeS`}gnOM3fSgxU`+eag){HQ&fgV(Ma}IcUa89xtvz0l2_^KIFt$dfJi3Vy*I$} zKuaaC2F;4geE_-x!I6lVY_$3-Qa;hM2&uY;M5hy^&Z^L`#fM>Fn~$HR zPa9qjR6&gLlqHzu?t)OX*(wGdd%)DNYv3}Kd%|M$cXLwAXDozv@wuMk=JBj9bt(3^ zMKO%3az+`k=cBh<&EXiqqhTHH;HCV+~;G*OEo?mgF1;Zwe^Pl6>UEg;-YwbA#I+Qgl z^9|=SDv}LHw-BK^!>n_-yA(Z$Pblrxir|CbFU_W^W2tZIJE|c~4}*rG!4yTjpRt_?EzoTdoua2RB;ltx@GyG= zuXmh&`P8XT$ha9{H$q!ohi*D_zj^XTt7VC2A+w;r#ywICnX`)eNqT{f5V;EE4m|uvX zK}qca7lRS)@Em}If-|4K2&21eUXcDsnQa}`L&HfjYnUcAIhX1VEKQi0z)$H9n1zSC zQ$I>S#R7sIKb#&Gy+%0c!`SFJSVTG1YUv-GU#L9B1?|!B0`n>E+gMnj+DrX#{4*o~ z4m+u@=8xbRS}Xz9tc2)2Z1{tcUoU-n{Aubd{=?&w_V{pXeArwcZVXO>@y>81^_BiZ zzrTY2+HUEfH0%$Wjlof4C-t@dNwrm4-E4M#z3SiTx-BN>cy1AX#Knb$Zu)JDUCRU0 z7*i*^0aZtye`Izp?Jh7YV#+-l-jMpCDK1G1=JngAzCAa@W1a9U#~XNtHy9q})VJ(z+KZoILl`FF&39-Ou}VBH;y?xWJx3Q zKinK7y*a5LMjXr{;Z>#}&yOd(iL$9lxD%7j`>l-u_|5O7Ee7BO=sn`(eS~xP9^5@h zDWp(JE-v7BBvssLPQ?IZ$8TBkAL0XE{eUSuemm=MGCO{Q)ztaUMNFq}KRZhOvRQDw z6T~RC9UySoz=_GrEGRF|R=%lk&JWb`z~vq>Ee?V*Qc>mMRG#TSVqZ~c;g@ac;$ z4}T&L&mOsCzkC^tI&VMh{OoVB#o@z;e6JMvKXq~sNA<&hV$J>`x{2SVy88Ox;rqkG z|H!+ZMR#$xboi2gctzbBUHy0AZx={(zP#wj+`>1-GD>SiVD4x_`5>kv9`P5Fm(3&6 zZz2|LR)tKg**wvnlkLGdiq}&!&sxX%%g8+nfSz^h?tA+W8KF1(ejJPg(w@M5IRtag z5oC(ESF%n_GMNo%KUZ8Gp}K3G(u;(H(KazmK}h)*Z*ij`$P8u&AKPUwIuD2KxKnvgNpdgK-FCD(S#=yK&U^iSZ;S zxBOZ_xVuK9K-soGM2vtyJuv_mYzqL50kA@TZ+}V7fBSX=gcg9>#46=Ny$dcRoi0)R zxJkHu_X7Z!c>WP%ZHLwe2&&)Pmy8zI!UuG%ta1)PmiTno9NBT$eF8bj4w!Y7O`~J? zSrUUH>p;3WQhvO!Cf5 zij9nCYHB+P#_!hc>Pbw<4=@}LZ|%uw5b%o-N9d!yQJaJ+>&q6<5_d3ILWzTW`;HH+ zA`>oq%MOm5VVxZc;9LRpB-k#d>K<-HSdx{$wYR4vl3nsp&IS;a7klu&W4A|;+=sXB z6HRN*!N^ceAHNIJA{G0rvw~ssvz&=DjGy0HSMYv%UBO&yvC><5MbCV{*^#e80b(aK9MeFZWNPX}R~g!fw=hWBdBf*5-QQ`ij#mY&6!l3)}Yf zR-t8Y+Z$VJtM!%b?bF<-KbY!-%x8LzSJxT+=AWh4XL_Cqapj$)Qv#cLL?=C>-xOz& zcKDv>xyu~BnZq{@Mxn)K(uJB*hi~Q)%{-z$h|+0@qc)x!3z!alI- z{859TT+b3L7kS_75s*cgFL2d_dgKVbC8Um4$LS4PqaM!R103Vy_?^eO9|ew|#27

z29xiMsuZg^9uJ1zpo)`kkQRZ}179A?=OW@Qs$L63Hol7^)Y!L>FN6?jU|W*&R(#Bd zkZCtQ`e^^oO_VL?veUq6b;OF807Akm#lEuenK3;x+W#gttO+=&ctvK^D;)377sZ5F z+_e^GR15fBi|o@QTz~fYA|fz)4sTU!E@CkPt03dY8%KVR*9^-Ih?hn~k|fyx|LT|e zpzE;@KV#M1&xG z=60v+w5+fm)(0)b&>))OSDw?eer*pxRKh2C(|bJ+VGY(^tA*!-@XjZr0A<}rG>^LN zUe^Uh5gFIQvJeJ@B0uOM2q-KKaW#ngVSJ3a?REz=S%5@)VM==BgHHkwCgui25Bbgs zh`B~p>qNn3mcG{s=D_b z^ksP49Wu#1bvmFwGdCbC1|cA^qMmj!4R0emvVoAJWu%THhaA)IDRM)Cy} ziDv<-!5EZq0X7+ZYp+L+v#7fF?1oeKyd&#j7YK4Tq#M!)JmF649xYL~NU{a!9_u~C zcMYt)P9HtG*DKtyJ4A29+xSw`&+n;tEENqUatdUhM<~D^;a)P-Jwl8Ypc0`O8FjO7 zVbiLVX}p+wd;5<~Ocke20GtWV$(7>v>JE8Q@tbd-RHG^7j(WW>maW+Iea$)c+Ec!d z(J6cu&ha;_0{%*^D6*`4IC2pC^w=I3Zeg;^Px9w|Fq(aa-IaVnSIfU2Lv97FN4`C> zA&6X>%)L($TjzUTKTtn&Pza2HpeG+XiP}z>)yM`m0{Ge3deZR*>Ru^F)kT$!S&!M9 zD1Ks4hy_Z=t%^^?tZpRKU$k^0qDu(Ja4#B#*h3qb9bs4_qUS=1mJr7kFcs{()(4HD zM@nPFJg!2=8lm?cEF2JcVWN}j0X@TaT0KHCpM~}Py zaD)+nvCxw&D);)g?h8d%@}jE9D!nJX*y4hLmZgd;h@uXBFytRa%`{27jjNNGm2 zLf(Ed>LPIHfKiB+wcaKg&&N3S_8Nvmh6JP5N+Z+wew;5LYxbaB{wJ13S5F2XY8^o^|R`gTd>%oFoOPf(3z-}6N(0}YyyKNI&-l9?5!#+g<_$NkieP?xJW%K$x zLzvu0VV`!-!;UJLq2W0mmTlmQyP?Mq2!)$G;&lGyB&E$U#To&a|hPC4vnqA!FPxlG!Fo$(F-zW0D|4yFBm>uY=b)8b_cl<9fjHj z^@9`!(&Iw$W2k}wmpKJtZKiqAx_0fFTKMh&+Kf1xZ?9srp=A2Nvkv@Ge-O^)eHS)^ z;LhG7L-$k1If4|lIE0f;hM>i)_q$>(iSSXmHRWARz6&;ynm=B2d%=<0StFPp$tqx7 z(p6}o3Mz9#iw=DyRJc%dkS(mHT@SXEi(Mk=o#8bRL+h#2#12IXBCRKd*~s+^jXz{w z0JxjcEL)mIF`p&Vn3XDRKx)U`2LU0_2?e`w-);+_B{weE!$4DUhd#h51vfHvOa@dB zmKTg=OjcB?1viZkNoU2WqrRR&DX2lg3Z%?Cc(!_6B`N75lp_DTmhoOp%n3|UxGLb2 z@W*x&+d{Vlt+QTQ*(t4Usfhv-@jw|p(Z;3#rF9e(>}~-{1RBd87W$*$sL=1jG@|Ir zZ$ZJug60?69u!4k=oOUIm);FJ<*nq%9xwXq6k!scvE@cawH;a8vK zb9%jYs$A!6Is!?C3r}7?CphPLB><9WZsC%kqT?4qDGu@+CwdUd2j1Y3x%Nc=XdwUL z9U9^_Qwu&IiQ>rKR+*wNyn`zGZ|T*Pmez?`0NwPJ+1LYWN)y6USxD#T0Xf}-yH zZs+$p|Lpk$(QoH_4?ExQ{2-PE-1(!i6Nyt~qTyVmZ+q zkW>2w5p)0JAEfN)B0<3dhYJ=mI(W`zU%8$BGYaBY%t7uFKday)8RH0fP~wCougW;` z#!q+V98v89F5`Sf4$@$c3t4vRNLXfIk7)Dk9tIJw2G6EZJx-Xn=y zj8|BRWH1tUn%xk$p;(Oq?5tgt@&n9gr`LjewIzCk$EftzfV2*M+Xp?Ja&f?y%iLgcI1tLNAO!2w1n_5$Zdtd7(ZF z(Sd1wcf6DE{Y?*BTgfK}&RfNu$uFdTG&N+uU9;}Qt7ZtRDlRtqM42^4w8kWsT_u|A zSJ?=G6Ro($Fvb0*=ptb?DaF!V}q}VC) zlj*$}+m8_sF#c3r>7$DK2tF_Pq+!GMFoERJ8fsmWO_)t$t1!h{i_1rk@AD<>f{@)y z4bcoyAtX9Ii9A9wauQ$=;7t$lx8n>?OEn9d!-lvJ!WWCQP(aTa+}G{rN-i<3mE2d@ z(Y2|U)uwt{<|L+0va4aGzIJE;*~QL}et6Ua2Lul-=<-9l;^Al(Ppf_AtP%GP)sP=!DuiB?>q7qap~@7?|t;)UH4bvQgf-*`U^4fmMH1BJ)GtELo4?Q*1{ZCJMu_?nX1}z#hW?ws?7T2H6VCD%Ux+Kn4?K7e+Cld-r<`A1S>9S&y7Y=|6}bZDBeB$iVJ07rNtFzv z^TSK~mn*zwU6I^#o?alF&@bn_ob+W;0%7yHJw5R_Phsds^1QTgsd7+;AQoTr?7Gu4 zvyCE99P6LLiXwJt=;$`JabTV2naibC{X43I!83P~U%JeiB)~~K|M}(H*PX4k7Lw`< zFaeNKkGQ#ly|uYosIRPSY}c=E+AG`ZUv~b>;eY!bAcOu_V3Phn`0$(0zx}Omy@r)I zr=1qFl+LhKPPG=!S+6g&V!nYj>(y3`*VEf)XwFyDU9Y7*UTgj)W>AE7+xf4Z|J?a6 zdT%t2A>3jk65le-dxCTR=Hn|nIr@LUpPd|iE!iz|x;CUhkm`nud9rW<4tK$9XOg;hia*EH3_g>oHcV7D^r}>Ho}3%=mCCVFIn}cg-l)AB z=6&eqn1dtME8^h@p9*~(`hMkR$c(Iu8Clseb#_esd5+rrwMfTU0M)8Wf^xp$p~T!vfqr^eBxTYm|^OCA_Jsva)DqQ3{GMIw_gWAHG9p`mP)!ji-RTy8U0tn}f zW4)vbuS-`-yyD#PvzJuW?JyoQ48$~{t7pgUUQ&HmB~Ad6I!C(W++$l+(<9IKQ%J45F>T}S`C1;Q{uH3P7l|LF zCBlgp7fc-YtSIp?k}is(J3TY(HDl=F>?$fD?d6szE))BHT5S4MjNK*m>~7w4Wf&5F zYJ67Q*Ma(9QjLoyIAnHY*5o3|Sqlp)kL!}^V+mrbNj032 zKXys=+Ol3LZ|#z5`wonIQu!z)9vkUN^-=R|NoJjfg^^vA>}3Oga$L2n|WXI33Fnh1y@(3^-9161p9AJBIO z3=hAerbGNwo_ZWJ#sjVg*$k{r;O&mwqX6g}x9+~T|BxphlTB9l!)ps%`=D5HNxw12 zYah!4)+GPm_0`qw^@^+OylWA70@-VU$P@5J7$LW8?Gj03xAxaSt=6)|-;t6DWKdx1 zFgKRpY9^uppr(*I0Ka+wPVNqi#2AGXjw>#JzK1~9SDR7&7_cUR^m}5DiBqYtb%4a$ z=(fgItrj4}wc*ri%lORu1uG`tcY@yF`T(fRHDH~nH%Nt1m5M8n-H>`>X2D*&-7Kv|O{myIQBjxbZa&%S6WO?xr3=xa5-y``fFY!0_J=3|@keSN)j(AShwy>=b z1NMStL839NF4S3dH#UtDW2lERK6vV3@tat$Hb|z9TD;DykdeZKIx>w=!?kO16wGhY zQ0>ZOObnH|NrnmSCM>P_ZN?Cx1U*DEZ<68JwaoNp%P=Z{9CLPcvp&(VUjuLiP+vh) z0$hF!4j3RL`)yg^MZwj29^53lvDOWPr_~v?!SB!}sy{N$N;NVXSB+H)r%JKnKIszS_{6CIRhJm-03ip_2kI_b3A7A}2Xy~ng#aQL zG4;?N(DedWjgJ6JQ}FZ?mBNoG-5aR22&)JR^@*DYWonszdjLi*5DruTAHFN&l326# ztnI6tiqV8E>gNu;BL}Gbj$eZcVJr)26oBe%I)-PO;CrxPd06@LU!Y69jUoiD}lF|F#MI2LOF;TN^|3&w>2=asym=a2Bt1DZ@m7T5aP0Uc(L(z09IAm$) z61Gt{NTw1QO1iL-F}gHRxVe>gnSVp*L1Qn;VCfz~`6AD2O6a0iVg?wvx*pxQ&|R?7 z!9D}Yk?KnjPt!U9R~!q3#iF3T0d&pp{s>f7E|wtKHv&LVJ!M8BVZcSucZYyv=hM4T zX1l7JVoinMbO(Yu9$G3lWPH^HHM%!zsJbX)#{a|6S>so(T@VNUQ~Nkaw-Eo2O;<7;uIXn?bsZIFH|+tI z&H@R5n-C(d;8d+hc`?iCDSCi4!ODl72Q3?cro=|10EVX{=ywq;%{_sI$p-})?gZ>; zCM+ zuT7q=B`gQ3Ce-rHZh%d9fZDRjupsq7ql10#1=u%KqtAKIef?N9@fcntU2qG;VrrS- z;L3!RQOzSD(i?!uL|I$0dt~XS@e&h-B}flv9hV_$AW(~Out4^tH6+v}$_H}>$OSpb znC5k%ASF8^v#(6()X0&s?W&LL$I&6ECyjl&$T(t@Nrc59oI3cv$R@*%gvjJAP3Ms)% zuZzJWB7N||oe%U~chofy^T1?+w8u1;zJumdSX3)$4x}9XdJl9OB)r2)2@&9y!FmMc z1g5E;mB07o&LeD6aofK-_dorjJ+%Wti%gAKD>zKlx-NSRtHy%kgCu%i=8SBOATmJX zEwP@(&amGTI{>wqY6Y#vc`ePHwlp{J%pL8Nt-`99v@}0B&A(m%&9k7{EDhjhx z%~w5y(g7kA${>#$Y%(0u-k2uQO=ls-Y@JwLWAYmN$f3Q5)eizHjy`Ig0cIGM5-KO- zS(BFO*KtE6n<&%$;R~@csP$XdCe)_j$m@*if^-cx8t;cYN;^?YaIn=&8{1oJTg}y- zCd~Qm*3Mev`o_-2>T0Xr+-$A1THtj8ql~?_SyDv@*t5s>DF6{wN;qcraCr}{7jOXq z!`+xA)Weh+v0kuc6{AIM-Ob*Qn>^*2q%PNXm#kPcn#dZ>Me-Cw2c!3i*5G)LOWR&v z7!}Ahn#&UOH;7@ls83m^5D8U5npXklxQD6-g_W(X-JYbv~qRp zy<0@57x78BFkvHg_&Y_L+dHXPq2Rh$f&yz5D$T`e*Z}K{U*&Js8cc^+H^;RNZdL}c z@<^_guHO<-)$fhZ+}NOy4^2SE71uQ#;AWl2SovoTiFTn-LNSBD8>QzC7f`5C;DBE{9%CC=^V7!>UQh+Qh<_F2D!9%$HsSA|`QMTxF~ zE<|()Rf5vtyk~_dY`Rjqmx}a2!d*|qck2n(b~b)-QOTL=R}gYzj$ln!=5uXPs|NKh zu7KDtp&vxi37u7Z0}DwY!zg&hFwB%RRhvjVXm1hEPDD`R17?KRJcH_kbPeVPWYRd3 z5`t1gH9%D)y${nPZ^OZXha%HM#5SCb_AzubS07ju>^RmhUsum)BL{szCk|vqENl@D zuAd+>b)?D%D1U&Sh9QU^HuFg~o}6xzdp$LQjLxBJ2!2BJ?--Vq=xb2()uH!bY4kyD zYj)|eEuam$t|4B1AIBnMObF#Y20OFHq+D}s7X`fa@$mNR8Bo}*PmothkTvRw3Fc{=0) zp3s}?rER4*tI4}66?U==b1`AI&eH3Vu$(Fv(_NQnuo`9aqFrGZPt!4_+ral*1c;&EzAUmqkoXPFfPiJ*(v|xTk zL(BdBSebYLSMK))QeRLVN24#Y6ra82XNzj?E-o(~$;8D6HG>zQPe00eTwdLpz97@N zyuOyWVnkrN9;QdD92U7etH<7yC{A^Zk;zCKB^6rOCsx=gR@f^_yrn0VT2neqYdWph z*5UYM>81I+{G9 zi1x93#O!00{?2yA$&IoehrRUfitj$WL)+>6AeQGDF=g(Gz{gC5Fu{^au$X89N-mAS z?KZ@d+~?bJmP@Lzz z6_N0>@JJfP(gOFp1kO-|(eUKD_kkXo;HV}EDg1;WY3)u(!;`?ZC)~6U(?r`7N+l5q zcoRj_^Dz?e+!cP*Czz!VpFIIzsQ~W_S9`>PJV2{Ar z4NDw)00(h~d3G1^`K4*X&Q%q0o?^B5pCqRu9lVtr0pYY58b#GQc&i}3?_e)GFA7w= z-gF#N4f_t>s%IdfFU@=ggr31q28@M+x3Vvc581(6Jqd?xJ9w*uw>o$$;TR@zWDI!( zHXOVaCmIKD^&Gs_!CM`?HHFDKcx$q~vf|*a4&F+*aSD`j@K$C6z_ab(t#dP%valdy z>ozRt;H@hLR_NfZlJa9SE*!iS7#0U_WloNRw>o&MgSQI6$0E*vreSprf^ZzX)xldG zyw$;59lVvWV4LVOg-I@Ee4GclJcHt#g_SyZtKfburqsb(UD9U}-TL2tRPfg4q++$E z+KU0^&H-HeAy7>Zam@Y-SwKY)6=39X9zV4gNFdB(mKM;N_*wEJ>?J6QC)i3yAL;PF zFGU>b@V~$%{|Uj#@AXaq;r_w*m5TExhy-23Azog_#?!n6Q>O zm#lA_4R0~pCYe2jB=Q(Z??U>8D<PO6C{#`L)S4>#y52^aF^-%z5jI32%F@nDA6U+5GwX$CX_%VOLD}rYU=x<;b{V z!h&mX#e`ikVJ#i%iV3@7!mgO`*mK2%T`^%(cHb2fcEyBQ$XjC;Gca_AwvOGY_)R?( zKSwcPhqgWgZT*}b1YFWWhinWtP>l9h!?qC*UC3iohfNyl*t z9;F<;rI2?h6_MjObsVRT&vI6N z1lreO)CtYCAPFZ78|>gys`@*mawc0f>vrYtR;GB;)quoiKhi(@LI4l8tK%Tn z+CE;=8&3LdQV26F5RwaeXvwz)hArK48M$UNrD?XkyWqun0Pd}a=uW@Y3Pvof=MjiY zem5oMO6*X`aP>lPaGB@h5(=$gZ#-4v5pQLM_xOY|0NO&q+|>1nkJ{(jg`wsi(m|jKu|RYm{b5WE{Xp z4m#?v)4?*2#Du+RE~Q6K!mGpF!- z6a~%6LKB}R*K{yA2!stBZ0X4aOVCfej{=ac%kX}F6h!OZTK&o``EwN?mgF&bIm&_= zHm^@XI_`n(6FO-$8ph+9iJ-&QY@+W)-NC_1bw^;XYG+C|Nf|<$P3cC=noi&El0Mw% zZFFA@1sB$XSEi!90t@WS{C>&0UCWi6cBp`5`n26%It4F&N^YWDViR8LqNh{tX1#Id z4e}vhxm|C|6YGK&`!p8WIWO^LfDvnRGdgJ_5`CS3=vc_psl1`Cz&y_FLbN`#A-}aR zt=d4|NSSKEfKIi7Rn@{?!%J;z&&##Fi9WqOY)uB3UX5@zVax79g`6Z5?5~~r56ALr zdXCdjf-q_^z+gD&WhkZ_7c<63-OV@*#>ec9OmpZeuuf+zrXuCK z=Td>H3LR_t-qmWNV&`))7eySjJUb6jNV+$~_o4>k;UH_oCi}@uTQ8(plWTohY18#r z;a+DGm%Lk(5ax!F%|4z+nhd{gY`l_mpd@Gy`Zh6}tyY&*luO@@1nJiVI%V zjcP5tUvUcR7N(}5zKwZh+?9ZtoU>6DTH(D!BI)aNkXS1*9q+3Ame(gaqV9}}TE-Jc zodRn#_*r!~HLP{nkTzsYchZ?$oP;^m$LmP0-XC%xNh8Xgs;3M@d>a{KVY%b`>2{gZ zT4I;SJ~qCCejxAad0z&BVOl>3`op6gGwm8;74f=;G?3uAoMdJ}Vw0rZg*MWa8%Es! z#%cm-?_y?1Khl0afQc_=UaOB8(?6D5r;meJA3eJk?t}bRZMhCl18Pap7%EOhYt~N^ zm_K$2%2PS)H*Va3k%ES*+0v`)On9*Ru+EXhV0qrXNq-!E9Qf^<)_$$>YtO5yk-o%Z zK?JhhY8W*-0SR`4WOsA*`qgEcWz%0BgnqJn2LQD|T1PW#ufKFNYP`R6GrDxdj(_R4 zM#H3$Sz>7Ji{Ti?=KWz}=oUXr%`_@H&y&?b{gRDvg5#=8ubc{1rF0a8tZZH!%WQ?d z=vb!23TBuwLhX1sLcibzZtJJ&Xm_=~3KK0F^ckdcAdRV|73JK$%y! zVHoC0vPu&54VsvDu;gUbz=Zf*Hk1682c!yCFVD@}anRXr>J@tvXp#_%Vdq=vD4U6F z2?O$rcI+R*cE$EGJmkrVs~dX)H}>=ZrfX`WwsouaiQR=|XSb$}?i?0eZfM0=&r*e7?kN39l&hS=2bwmuBy!2lniS9I$)1eG#Rp!?tt ziT!bi^T=otV-g1N8*u-`LJwPVGi?F3YXwBTE)h@!PoM3DLRfUND#8(yIo1#JktLLhmOXZf^7^q?Pxa)BcIuj^#>t=|Bx4KZ}i2(~DXWNJU*;FQ4D z>>rDC&87(2Pk7o8vj*M4USvmbE0mFkUBK}b^em3wX6l&BYP`(DNjr|QNhaP-s~6LF;fdgj&bhI{Ty14&&XO;@>w4H>P!Q>MWB# zbL~p@yYBz{`??FvJk%)Ac@N|e%b8qr+J`=@FN}j|w&E(vBo*T*eYg%@vpM}L7*?Ep z+jhs(H7`Tn9v($~K52)4Hte5v#ix_NKfqYRYXX5HlJLm1lXGxR7HSv>EIJu4h&`Qt zlPnd9KSIHD=eWs~PEk z$n|||WO}_dYH+m}^+D*b0r{Ain|Bps%$UKl*W*c=?= zxW>_kc2V&;4#8viK{Ew}16;8Ob29-m;2hmV-Nz0|@FZ~?V)<~n>8;s=jl#?N+V(Tv zm^)xaZ^$+~o`!TVniXhp-4jJ)eHLMtO1*yAn4tXNcN)WEPDym>XH(0#vCubMF>PI| zqLTY2u9scWA9lO&A#ypuFou1t{mzpXLUfIS2Dn{B8Zo!%q1$HbK5A-fi`xfi(TpBH=}g%KmX*dpS;C?SSI-G z-XHefd58~xoGZe=0i`YB>V?^!&gxOclLFk{*v2_sFY>dO5{W^?88Ao6^WmcaWG2C5^j58VXf}r zTmdTpHZzrB6tsdQVUPo!*F%JO$`WpwdvL2i5i31)>DWy}&A@ftW9kbfb>Oeo(R+6b zmZ=d*Sy5EOr;U!Q$h zlB87}??yek-un}rix)OA-g|WX?>$G z4yPE4Fv-+3M+77$*{S^VP21f+jCXl3KIb)Hu+B`bzAKD|+8e2&g0>|Ff5d9txqSlEkSX z{;;rcYPhQ;$==7jQn&s>=IAfR*h-sezdTo5ucVIq^AqEVB?)vXoAQ`x^MjZriMDyZ z;3>tDf?%MvcdHq;lg@FI7RJOH31;VvJX7kE&X zHMIh3YGEN|awC)@gZa)mEtS-foAhd%<1L-o`J-Cl$OOAIwGT^@^{-BuhX*CeR6XZB zTrNqzU+8k>>3es}Sj=(~-d(%8gb^)CtoN}t5ayLrsMI0 z=Z%z?B;s9oE|AU|en(G_g;!*l?=(~{VZO7%>m|Jdjs=8TrLvw8*1u>eFN}oly{aRj zb0l;>b`rXScE`_Q2nke4iPL~FAYg9UGjQX7OkL`A1Efm|tWQm%&>RUJ^Dy9ka3pk! z!a2n?zEQ}I*l47iqXM`c3Ed#tt+au|9d;*%$QNj()%HeJ0Uj2__Q_tC_3!0IZDtJ~LdlB`tQlncK7V;<_WD zYj0oOTwhzunLPlYI}$p<^b@m{nt5Cz77dGaq9J#KU`X>fumT(j9RbjyHJDM?N0Jw` zjm7<6Mx_G$EKn7}RI~+20d+z!Fp}c6sz7^!B(tvVZ+y(|zX^OYtnx=;a6}x2v_!x$ zvRxvew)0?@?52+iv>QrR2Zqk#h{ee@m0mM*Pw;pY#32)aMVaPuZq1`vHpC|0+84zd z>LTOAkg4Ie_735B}X$wlsflO4p`)x*tCdAJvC(cf~(QR@T>6uhx+% zxOL@5vtfWae%l`*d8J0M0!vdMi&t`$_M;S0Rtq|vuoZF~%`)Z;6SO{dJ^PSQwUMfhiKU5mfc=kS4XTP`cZfojslzqWM1&El`jycXjGYT z<;M-b-wh68e+hF$mo$%|?Jz+YEs?y4j@L{F8WG=k_&CG}<0oWkSz~hkbMBh?(J0)8 z2h}-uZy~ow-PW96>CS+>6(sSX1_mc+ww3T28a|4IOD8LehwMkxp$wH%10fL@H!-=x zXh^6_+?#mq3HK;WzGQO1B%U!d6{Qr5q<<(xaX-pRgk;Z9;kvQk=Bhxt-`7lIQhkWW z(!LsqcUE3vfNC(&crt)s{SXN-&6{n1@O9Q#qvQRkf|@6LDCqcsreS^pE3!I19tFFL zEb};B?Qyz_(`xJbl~&FWapm^k)N=bLkkCzAny#FuE9dFTdCGPG8T4E)`{@2xsL>?Fu~0#Zd&u8^aq}L{Vc6ENxKZ9=?dnIjmd+@Jl*`1f)sV2r z4COTsAF&&@8W5?$@4R(I0ocP2(t>fa4pG|*J6SPHdwu1a(yMVJoXX3-$E?W&bso4~ zNwP6NaI3dzf0Q44UTn`+CSgw;$f?VKN$E^6#0G^7!Zxga-QEL01QAFC9>vr^+g5)^ zmKa#fZSI79RGfG)IM(_xxztw_=ot4NLO2tg%>A^B%jbPBx4^4HuN>@``Kg|KRU?$? zB}YQ%Na!31-7E>+v>_-Mkp0L+-cpZDA+unkF3^4wST$8q-i9L0yD#a@Ije~joS18; z*~Fcw0TBBF0&OdeiZCwO+#v~deo!RXq?$HP6k&@l+<$N+ zbb^c>4;=}eBcY=Tp>~_VMyZd2&bZFScUL?c?o|Ayo{C*r2oz@;_Te0Y$GnR2Dt(yN zL%39TcjSBdTxUIqZEw+)g?KZ{LcF=vAl`<}anXRx6ADqFYCq1eG)Q?U%y8J9Nu*VK zU=#Jlts5mrL0poQHIWWd#)wy-emV*j4I^O0zpv1zTiNz1R$iu?l_cak0S%PpFd829 zgLXG)B=G;YdXy=%O>xEd6{!JV*)B=aKl3Uk3`tK4^UGN->~2ZY{9L?B)A8#xd|HxJ zf5cv?Jb7}_kH0XW^#5LRKxt@+dn_K)4XU7(K=6lU>?JmZ2oMW%;ncUgh|jMXFYKNz zSpc`9mi(4@;O{R#tfgg}=7+uJfYLah&4+zUVmMvU3Qj|@KU*-| z2KdqerNN642w?`;BqSloF36&%&jF>Q3Zn1~Ht?T0lgR<4Ig^YB)B&Z5!E!)pjRz(m zWf(UZrNg?(kb4p`&^2XZbPgzOy^x>^azJU2zf8kd98lUK)WnlvH*5MWELMOA+_?u$ zK;;}z+5x3K2b3NsJ6V1CtjP8aNz!pZX$O=(bUvCvK9V_Zo1O$`Y9Lf*|1I&}ON+jZl4cHSvQB!+aIXfirLJ+5#xv1Z2#*v`4@}OF35<~S- zOcpzpvr&H}?&=N+C&*uEn4Q4j%XC#D{W_L_ynjxyDiB3kEH0`7d zEbHU|>C1x^l+>kN4JI82ly*RA!;j*C(!x+t}OUN(|d2`VCA|+fd)xZIz9Z=feSlQA969<%LP1tWIO!)jx zVMNS*ws;PuxQBZaY!4@9NCeu{ZBxyEnLk8ha7hW9rqx}ffWsz#mV&3WB z%tN5FawNac{e6u*lEzdhFOA^tH$2t{2Aa&vc9h?=wI+(jfRjwua&bWE+xNkS2*YIlNjU$l8HbxVTG5PZHuDL6fFY>eln6YrdFRX9 z_wza4ViQQpJuouK3Q#?;OIA8bdsOd@2Yn%pgcSI%k*XX1x-Q4C#q;HdKL=2H+514r z2G0jNvZk5@EY1VHOd*i8fl>@4yKp`V^7+w-^HG6wgC;3D&!FUf2nf|f49Qo3coq>` z=$|+b*4hhLqkyYa>Zq{$XfWDK9*=iFh2^~D*bE(P-NDu`n8fh=vY^(h^I+enDZGnD z@t%OLznpmx^RVw!(OT{G3UJ1ha9m`+eB687`du(dTV_vXdSF~wpO3@e*5%i(;)X}z27}~_VgVAwm*CNuECev7krjv+?l`Y z{igR@!=HKF`}gdJ;JpwAlB!zc76!^Kr*x7+paPt zr4hDw7k9ooR~=|S?oL=SDB1mfQRXK$hQ&SW#&!^El-PvXT|jHDhBvMx8QA)YzO1gL97|uO>AV^{%@Kro?6ci zVm+t<4%CJfv^_-1JmTNmO$7MIK576D@x!mzg2AtwT5OtubU_liTGX?h)<Mf+TfXOA_HLnCfjFJbr5R@v1aJtl6Mbf;rrfA8{y-ZC*l_ceJHh=*BjRkH1seJ zk+{G3Z38IzZ}t(j1PIW4p2Z?=<(ue_dcK7x*6V_F{~A^1L6aiHK2UM{(K$h9#!k30 z<&m1swR5$ogMJ+VgRCGn{R6=Jxmwhn?PiL3bP#J@!4(IwMjgsS(PpejX?rE7#2myr zt!#Zn+jOShzNqyAqS&Mb38q+-&)#RZKQnshcE(O3KjpGI%@u{F2u_xE@a>%m@;bdQ znK%Wf;%(4!|$ zrKd&r7F`U~@$t^^@ty_7a&)b(3X!Wq}f-YfqGlVFppV`U9Uw&3I+&K ziUNjoh>BLsF<$n9de=H?3$dn)s5-;L_I|X7Qhq20hW{h!HefVTTq`>t(3-bQr&d4Vs`Kl zKP8&8Vb}fWG92e~;;MJy4u62!U=K+!(rN`Gyo8U!K$Mi$Uc!H=;y%K!3MsN8PIUO0<(I0$kNdV0qWISmfM-(E1n@x?6 zoN(`9aD4Ke8c#XlPOZY09iOJ2I-HDAyHP?jCp3^ArdWcPbsp!m#dr9+7xvMihIw2H z&6y6w`(xZ#S4{}NP*@J-(!v4SL75xvR*cFd_FG&QD4axca{;U4z=#1KOZT;S{KQy< zQ43|65*$5EHKqw!mZV@Ez}pj4ck|L^hanBxatLG(&nXae3j~ZOy!XAk_c_7lpES|t zY>V1I+ukXS%G*jQIVP6P_NdGTA$La?Op*!WE;wrEyBwYQ2*$_3qz@ut%vrw`cvYx{ zI)&}~QFp@Lkmn>wLqUN$cIglk(45V&xVk7NnjGRpk8zOddZ_c)!7`8XgPV9Yuf;k; zVJEcrnqe_BK*mbvc2>4eZVBK3V7bBIu|F8~fj;Zor_u1>HDZ%Xh}3suxT7a!G-nUm8od2 zP>5@0e$Q6qno*9s4=Sp(D$8kv)&^*oD>>~@0SZM%v9RxCyS;P@UYv;zpmQ3GPzxs- zH@2ZM&3UOvU{n`T1QT;ku48$E-j=Uzc19tuIWO^LfStC@&FG|!NEA+jZ2z<}Bh(d& zKT`jQ)(1F_D&4+xZs*ZRHi}SEtzcEPu-EWX+uHMDaW>JXr)7uPUC7JF^5FB$g?#6H z(PJ7TexwK81#x9;Va zyjznH=7y2YKAuLJ48Lw{ob0S@*N|!8?Rse|RY1r2>m?8R1cgpJ{-h5Dq-CBH(OKE_ zrx?23!3heThgXFPqWVnR)3$)>5}VPIsi9r$sYZvIy%xntr4Xrzsa6ON>*zE}!y&hO zTG3OQ4nNq4V88Elf>AeH-)2xGM?U=}IlWmq;XioemPr>PFhL)zdU$233*q#H7n_VV?H^_6Y8# zrf5SpqzxI1>2{gZT4I;8<}FLm z$-8=TD%V7?g8=^Z9W(73ViobahBT1ixtwHXL1L4n-Gw&Nm5W3)n8af>f$((5gNZ5q zNc;H!Ccc^E-Q zfH{PQs@c-3>r8mC`moNO0fXgv_psu^j|0Db(*^^o{Mz%Xy5B8rdv}FPz8Xf2PT-Fx zaggk8u3o>oOtWnItAo%_cJE+D2huv4QG5NRn^EKarJK>EBX;~tw>26jjm#25b6*UR zQ+j-Vh*U@fRs8;kshLJa=XtU^s9&-XPH6KHVsyhveyf~KG3VqSBL?u2mo;u7J zp>{kRpf6XJ8x(oo2$q5x9G_|$X->lJ&TgO5YlwmSl;oY!o+Xh{>m!>y?<&DD)P zf!WjP0ZiA_Ms4d>?Gw8T%g%018{g9+wa`9~KuvEd%{(RRAunRc8vfbkNZL)yPWi?*r zF(nxoiXicJTK%wL|K!#K*AfoN0SeFZ6#42p&KzCXVc_p%0_tc8wI0Ov>z{#KMs4hfTRk>!w zh+Hxk!~LKuhyI6L-?v7l*IT0oSBvd)Ikt?B5j96kFi7AmG{yjhu~xncQa?|FT($6w z$rKO;tU3Z`#W{cnm)%Kb+8mxtRbZevWR^%oApy2wnrKU&Yc}vj^+* zppj&Tqpxj0W4cOINpGN9mn+0(*Nd7J&r)58#`-M6E|q%y6lns#(-~`Tp|^%|wf;&H?Y(u~(&`KA=)JqfAT3FlztyfVB1!+4NNT||S(0>rLvyL% zNUSexpwn)v?-XmGB*7}Wy=T5WSj#5jMN@!bgpwpP<_Xh^mBTBkFKnXA_ULEK*;B%s zQ<{wIq-k@^R=A*;_7GApO|@P6n8*njqpikjzxzs3d_dA1o}KFIZL92EUrQ>5CCE z3ciO$Y|qU$I#yCozAui&EQB*RDp!(hKU3Lcog!egaH%9Y7CpEc&k=$wNxY5up-;@S zljEKxiHej|<9j+i-dd7)m0X(s+&FJ(Q}8mUVCwBYHMm?-->p4&P`fli85;0otdDa= z(ii$A3HoOYrKt}O7>hJ~Uy?LG<<5}721=6RSL_fn{^bB%Ik*Bh*EASgl89>vM5JN< zb4B?}64VrKS~w9_P?B6#182yOr3P^r)W`+aOOmhXp*Gz&H|iQyrRBO!MQK85Gg>lpU+aJAV+;piQ&TA!)V3hO`7N$1iYDBLi z*p4`FIQ}~v$`F$lN-|+`T?W=**hfu7Ky;FzNDhn8e4p1NR4asV_{^^wOw-!kA$k~t z%-ic+*9`%-jABHjV=%x?f3S>lx(`UiP;8#+%V~Puaz?bC zb{9W<9JD4d4@D2<6OzCfYIGBKk^3mYILJvLhD}4a2F+i^=1^#uu5~s*r5@-*aEUSE z+LB|zJ0vqjiOZj0IX-;$xkZKhAUX{`Aw{yS+cnfAe1NFF=p`^ZZwD z_bT}JQbwR#$r0=RfFO%Ggu<74$Gv~d9$e(~z0gNLwK_4seJtd6k7tnWf1FRYm!KP- z&$RsX7rJ+?AZ=>}*bnI5WTo}p%A@1nwd1w++FGf?{q^JS*4A1-d7LD@sCA{aihsJ% z%HGO&FlseQ745$azx(#E{b=Q*qtCAn|Ld*IFha&Bmu;z1ZP#ImRF;gpC9^%UFCga- z#z^*sHF8Up`)!C+rT{a9<5#Y%UESR3Y}8uUS2t>#n?VPJ<9<+E?X0z12fpuL-RgjF z{G0#tlegX?#rQY>4l{n5u+-03Y^P55lP27Y4>>#iN6CPGZNZ%~-6``G7506R zGnqSOzAmRs=eszM?;_{TFa|{K8*4#0ABXdCFijChNghk#r^Fw69tMyFxuUx}^1Xbn z)42iPn)7iuABXdC{PKUoq4KWrhMehG;Zc6pvGVk7xOFZ%Fm%GBw>)^0nG?$N43wA( zk+zIvIiwU@nklcD`FWex100r>zwx(H^r=I)G}Fj|!^VI8@GwC3<3Z5!838FT%D!Sc zt7+3*C>;|vnH&$tJW~$$hKTDthLB-WR*3a|2_rFBX5^AkrH*qddPx(qg7`G^R!8AT zVe1R{l*%bn@!}-==l^);E%}H3()W5NteL-5?8(Q&BP8I)h^=%q=s1iP%Zl-@X~j42 zTMj}53t7l&n0A^?xyo|Iuu3kj6Ho2C>pImAqu~)&LpNw7z$&(SD15p{Ps-|9q#D8J{=t`juhCd87(@ll)ck${iP=OOkAHdUUN^8E^yAeP34YLXCaIe=1VDlO1IbLWsFrFhNDS@<~}jR-fbmZjyNp cn874wy_H-*2$@GEjqy(l%i@iNwM^>&AN-R%G5`Po diff --git a/tests/integration/fixtures/recorded_responses/invoke_tool.json b/tests/integration/fixtures/recorded_responses/invoke_tool.json index 7d56a829a..77995f72f 100644 --- a/tests/integration/fixtures/recorded_responses/invoke_tool.json +++ b/tests/integration/fixtures/recorded_responses/invoke_tool.json @@ -44,6 +44,15 @@ "metadata": null } }, + "()_[('kwargs', {'session_id': '', 'code': 'import pandas as pd\\n\\n# Load the CSV file\\ndf = pd.read_csv(\"\")\\n\\n# Print the first few rows of the dataframe\\nprint(df.head())\\n\\n# Print information about the dataframe\\nprint(df.info())\\n\\n# Print summary statistics about the dataframe\\nprint(df.describe())'}), ('tool_name', 'code_interpreter')]": { + "type": "value", + "value": { + "content": "error\n[stdout]\n[Errno 2] No such file or directory: 'bwrap'\n[/stdout]\n[stderr]\n[Errno 2] No such file or directory: 'bwrap'\n[/stderr]", + "error_code": null, + "error_message": null, + "metadata": null + } + }, "()_[('kwargs', {'session_id': '', 'code': 'import pandas as pd\\n\\n# Load the CSV file\\ndf = pd.read_csv(\"\")\\n\\n# Print the first few rows of the dataframe\\nprint(df.head())\\n\\n# Print information about the dataframe\\nprint(df.info())\\n\\n# Print summary statistics of the dataframe\\nprint(df.describe())'}), ('tool_name', 'code_interpreter')]": { "type": "value", "value": { @@ -71,15 +80,6 @@ "metadata": null } }, - "()_[('kwargs', {'session_id': '', 'code': 'import pandas as pd\\nimport matplotlib.pyplot as plt\\n\\n# Load data\\ndf = pd.read_csv(\"\")\\n\\n# Convert \\'Year\\' column to datetime\\ndf[\\'Year\\'] = pd.to_datetime(df[\\'Year\\'])\\n\\n# Group by year and calculate average inflation\\naverage_inflation = df.groupby(\\'Year\\')[\\'Inflation\\'].mean().reset_index()\\n\\n# Plot average yearly inflation as a time series\\nplt.figure(figsize=(10,6))\\nplt.plot(average_inflation[\\'Year\\'], average_inflation[\\'Inflation\\'], marker=\\'o\\')\\nplt.title(\\'Average Yearly Inflation\\')\\nplt.xlabel(\\'Year\\')\\nplt.ylabel(\\'Inflation Rate\\')\\nplt.grid(True)\\nplt.show()'}), ('tool_name', 'code_interpreter')]": { - "type": "value", - "value": { - "content": "completed\n[stderr]\nTraceback (most recent call last):\n line 5, in \n from bwrap.core import main\nModuleNotFoundError: No module named 'bwrap.core'\n[/stderr]", - "error_code": null, - "error_message": null, - "metadata": null - } - }, "()_[('kwargs', {'session_id': '', 'code': 'import pandas as pd\\nimport matplotlib.pyplot as plt\\n\\n# Load the CSV file\\ndf = pd.read_csv(\"\")\\n\\n# Convert the \\'Year\\' column to datetime\\ndf[\\'Year\\'] = pd.to_datetime(df[\\'Year\\'], format=\\'%Y\\')\\n\\n# Group by \\'Year\\' and calculate the average inflation\\ndf_avg_inflation = df.groupby(\\'Year\\')[\\'Inflation\\'].mean().reset_index()\\n\\n# Plot the average inflation as a time series\\nplt.figure(figsize=(10,6))\\nplt.plot(df_avg_inflation[\\'Year\\'], df_avg_inflation[\\'Inflation\\'], marker=\\'o\\')\\nplt.title(\\'Average Yearly Inflation\\')\\nplt.xlabel(\\'Year\\')\\nplt.ylabel(\\'Inflation\\')\\nplt.grid(True)\\nplt.show()'}), ('tool_name', 'code_interpreter')]": { "type": "value", "value": { @@ -107,23 +107,23 @@ "type": "text" }, { - "text": "Result 1:\nDocument_id:64211\nContent: .. _lora_finetune_label:\n\n============================\nFine-Tuning Llama2 with LoRA\n============================\n\nThis guide will teach you about `LoRA `_, a parameter-efficient finetuning technique,\nand show you how you can use torchtune to finetune a Llama2 model with LoRA.\nIf you already know what LoRA is and want to get straight to running\nyour own LoRA finetune in torchtune, you can jump to :ref:`LoRA finetuning recipe in torchtune`.\n\n.. grid:: 2\n\n .. grid-item-card:: :octicon:`mortar-board;1em;` What you will learn\n\n * What LoRA is and how it saves memory during finetuning\n * An overview of LoRA components in torchtune\n * How to run a LoRA finetune using torchtune\n * How to experiment with different LoRA configurations\n\n .. grid-item-card:: :octicon:`list-unordered;1em;` Prerequisites\n\n * Be familiar with :ref:`torchtune`\n * Make sure to :ref:`install torchtune`\n * Make sure you have downloaded the :ref:`Llama2-7B model weights`\n\nWhat is LoRA?\n-------------\n\n`LoRA `_ is an adapter-based method for\nparameter-efficient finetuning that adds trainable low-rank decomposition matrices to different layers of a neural network,\nthen freezes the network's remaining parameters. LoRA is most commonly applied to\ntransformer models, in which case it is common to add the low-rank matrices\nto some of the linear projections in each transformer layer's self-attention.\n\n.. note::\n\n If you're unfamiliar, check out these references for the `definition of rank `_\n and discussion of `low-rank approximations `_.\n\nBy finetuning with LoRA (as opposed to finetuning all model parameters),\nyou can expect to see memory savings due to a substantial reduction in the\nnumber of parameters with gradients. When using an optimizer with momentum,\nlike `AdamW `_, a parameter-efficient finetuning technique,\nand show you how you can use torchtune to finetune a Llama2 model with LoRA.\nIf you already know what LoRA is and want to get straight to running\nyour own LoRA finetune in torchtune, you can jump to :ref:`LoRA finetuning recipe in torchtune`.\n\n.. grid:: 2\n\n .. grid-item-card:: :octicon:`mortar-board;1em;` What you will learn\n\n * What LoRA is and how it saves memory during finetuning\n * An overview of LoRA components in torchtune\n * How to run a LoRA finetune using torchtune\n * How to experiment with different LoRA configurations\n\n .. grid-item-card:: :octicon:`list-unordered;1em;` Prerequisites\n\n * Be familiar with :ref:`torchtune`\n * Make sure to :ref:`install torchtune`\n * Make sure you have downloaded the :ref:`Llama2-7B model weights`\n\nWhat is LoRA?\n-------------\n\n`LoRA `_ is an adapter-based method for\nparameter-efficient finetuning that adds trainable low-rank decomposition matrices to different layers of a neural network,\nthen freezes the network's remaining parameters. LoRA is most commonly applied to\ntransformer models, in which case it is common to add the low-rank matrices\nto some of the linear projections in each transformer layer's self-attention.\n\n.. note::\n\n If you're unfamiliar, check out these references for the `definition of rank `_\n and discussion of `low-rank approximations `_.\n\nBy finetuning with LoRA (as opposed to finetuning all model parameters),\nyou can expect to see memory savings due to a substantial reduction in the\nnumber of parameters with gradients. When using an optimizer with momentum,\nlike `AdamW `), you need only pass the\n relevant checkpoint path. Loading model weights and setting trainable parameters will be taken care\n of in the recipe.\n\n\n.. _lora_recipe_label:\n\nLoRA finetuning recipe in torchtune\n-----------------------------------\n\nFinally, we can put it all together and finetune a model using torchtune's `LoRA recipe `_.\nMake sure that you have first downloaded the Llama2 weights and tokenizer by following :ref:`these instructions`.\nYou can then run the following command to perform a LoRA finetune of Llama2-7B with two GPUs (each having VRAM of at least 16GB):\n\n.. code-block:: bash\n\n tune run --nnodes 1 --nproc_per_node 2 lora_finetune_distributed --config llama2/7B_lora\n\n.. note::\n Make sure to point to the location of your Llama2 weights and tokenizer. This can be done\n either by adding :code:`checkpointer.checkpoint_files=[my_model_checkpoint_path] tokenizer_checkpoint=my_tokenizer_checkpoint_path`\n or by directly modifying the :code:`7B_lora.yaml` file. See our \"\":ref:`config_tutorial_label`\" recipe\n for more details on how you can easily clone and modify torchtune configs.\n\n.. note::\n You can modify the value of :code:`nproc_per_node` depending on (a) the number of GPUs you have available,\n and (b) the memory constraints of your hardware.\n\nThe preceding command will run a LoRA finetune with torchtune's factory settings, but we may want to experiment a bit.\nLet's take a closer look at some of the :code:`lora_finetune_distributed` config.\n\n.. code-block:: yaml\n\n # Model Arguments\n model:\n _component_: lora_llama2_7b\n lora_attn_modules: ['q_proj', 'v_proj']\n lora_rank: 8\n lora_alpha: 16\n ...\n\nWe see that the\n", + "text": "Result 2:\nDocument_id:cbc88\nContent: 06% of all params are trainable.\n\n.. note::\n If you are directly using the LoRA recipe (as detailed :ref:`here`), you need only pass the\n relevant checkpoint path. Loading model weights and setting trainable parameters will be taken care\n of in the recipe.\n\n\n.. _lora_recipe_label:\n\nLoRA finetuning recipe in torchtune\n-----------------------------------\n\nFinally, we can put it all together and finetune a model using torchtune's `LoRA recipe `_.\nMake sure that you have first downloaded the Llama2 weights and tokenizer by following :ref:`these instructions`.\nYou can then run the following command to perform a LoRA finetune of Llama2-7B with two GPUs (each having VRAM of at least 16GB):\n\n.. code-block:: bash\n\n tune run --nnodes 1 --nproc_per_node 2 lora_finetune_distributed --config llama2/7B_lora\n\n.. note::\n Make sure to point to the location of your Llama2 weights and tokenizer. This can be done\n either by adding :code:`checkpointer.checkpoint_files=[my_model_checkpoint_path] tokenizer_checkpoint=my_tokenizer_checkpoint_path`\n or by directly modifying the :code:`7B_lora.yaml` file. See our \"\":ref:`config_tutorial_label`\" recipe\n for more details on how you can easily clone and modify torchtune configs.\n\n.. note::\n You can modify the value of :code:`nproc_per_node` depending on (a) the number of GPUs you have available,\n and (b) the memory constraints of your hardware.\n\nThe preceding command will run a LoRA finetune with torchtune's factory settings, but we may want to experiment a bit.\nLet's take a closer look at some of the :code:`lora_finetune_distributed` config.\n\n.. code-block:: yaml\n\n # Model Arguments\n model:\n _component_: lora_llama2_7b\n lora_attn_modules: ['q_proj', 'v_proj']\n lora_rank: 8\n lora_alpha: 16\n ...\n\nWe see that the\n", "type": "text" }, { - "text": "Result 3:\nDocument_id:0c95c\nContent: with training with LoRA quickly,\njust specify any config with ``_lora`` in its name, e.g:\n\n.. code-block:: bash\n\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device\n\n\nThere are two sets of parameters to customize LoRA to suit your needs. Firstly, the parameters which control\nwhich linear layers LoRA should be applied to in the model:\n\n* ``lora_attn_modules: List[str]`` accepts a list of strings specifying which layers of the model to apply\n LoRA to:\n\n * ``q_proj`` applies LoRA to the query projection layer.\n * ``k_proj`` applies LoRA to the key projection layer.\n * ``v_proj`` applies LoRA to the value projection layer.\n * ``output_proj`` applies LoRA to the attention output projection layer.\n\n Whilst adding more layers to be fine-tuned may improve model accuracy,\n this will come at the cost of increased memory usage and reduced training speed.\n\n* ``apply_lora_to_mlp: Bool`` applies LoRA to the MLP in each transformer layer.\n* ``apply_lora_to_output: Bool`` applies LoRA to the model's final output projection.\n This is usually a projection to vocabulary space (e.g. in language models), but\n other modelling tasks may have different projections - classifier models will project\n to the number of classes, for example\n\n.. note::\n\n Models which use tied embeddings (such as Gemma and Qwen2 1.5B and 0.5B) for the\n final output projection do not support ``apply_lora_to_output``.\n\nThese are all specified under the ``model`` flag or config entry, i.e:\n\n.. code-block:: bash\n\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device \\\n model.apply_lora_to_mlp=True \\\n model.lora_attn_modules=[\"q_proj\",\"k_proj\",\"v_proj\",\"output_proj\"]\n\n.. code-block:: yaml\n\n model:\n _component_: torchtune.models.llama3.lora_llama3_8b\n apply_lora_to_mlp: True\n model.lora_attn_modules: [\"q_proj\", \"k_proj\", \"v_proj\",\"output_proj\"]\n\nSecondly, parameters which control the scale of the impact of LoRA on the model:\n\n* ``lora_rank: int`` affects the scale of\n", + "text": "Result 3:\nDocument_id:8892b\nContent: with training with LoRA quickly,\njust specify any config with ``_lora`` in its name, e.g:\n\n.. code-block:: bash\n\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device\n\n\nThere are two sets of parameters to customize LoRA to suit your needs. Firstly, the parameters which control\nwhich linear layers LoRA should be applied to in the model:\n\n* ``lora_attn_modules: List[str]`` accepts a list of strings specifying which layers of the model to apply\n LoRA to:\n\n * ``q_proj`` applies LoRA to the query projection layer.\n * ``k_proj`` applies LoRA to the key projection layer.\n * ``v_proj`` applies LoRA to the value projection layer.\n * ``output_proj`` applies LoRA to the attention output projection layer.\n\n Whilst adding more layers to be fine-tuned may improve model accuracy,\n this will come at the cost of increased memory usage and reduced training speed.\n\n* ``apply_lora_to_mlp: Bool`` applies LoRA to the MLP in each transformer layer.\n* ``apply_lora_to_output: Bool`` applies LoRA to the model's final output projection.\n This is usually a projection to vocabulary space (e.g. in language models), but\n other modelling tasks may have different projections - classifier models will project\n to the number of classes, for example\n\n.. note::\n\n Models which use tied embeddings (such as Gemma and Qwen2 1.5B and 0.5B) for the\n final output projection do not support ``apply_lora_to_output``.\n\nThese are all specified under the ``model`` flag or config entry, i.e:\n\n.. code-block:: bash\n\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device \\\n model.apply_lora_to_mlp=True \\\n model.lora_attn_modules=[\"q_proj\",\"k_proj\",\"v_proj\",\"output_proj\"]\n\n.. code-block:: yaml\n\n model:\n _component_: torchtune.models.llama3.lora_llama3_8b\n apply_lora_to_mlp: True\n model.lora_attn_modules: [\"q_proj\", \"k_proj\", \"v_proj\",\"output_proj\"]\n\nSecondly, parameters which control the scale of the impact of LoRA on the model:\n\n* ``lora_rank: int`` affects the scale of\n", "type": "text" }, { - "text": "Result 4:\nDocument_id:64211\nContent: LoRA to Llama2 models\n------------------------------\n\nWith torchtune, we can easily apply LoRA to Llama2 with a variety of different configurations.\nLet's take a look at how to construct Llama2 models in torchtune with and without LoRA.\n\n.. code-block:: python\n\n from torchtune.models.llama2 import llama2_7b, lora_llama2_7b\n\n # Build Llama2 without any LoRA layers\n base_model = llama2_7b()\n\n # The default settings for lora_llama2_7b will match those for llama2_7b\n # We just need to define which layers we want LoRA applied to.\n # Within each self-attention, we can choose from [\"q_proj\", \"k_proj\", \"v_proj\", and \"output_proj\"].\n # We can also set apply_lora_to_mlp=True or apply_lora_to_output=True to apply LoRA to other linear\n # layers outside of the self-attention.\n lora_model = lora_llama2_7b(lora_attn_modules=[\"q_proj\", \"v_proj\"])\n\n.. note::\n\n Calling :func:`lora_llama_2_7b ` alone will not handle the definition of which parameters are trainable.\n See :ref:`below` for how to do this.\n\nLet's inspect each of these models a bit more closely.\n\n.. code-block:: bash\n\n # Print the first layer's self-attention in the usual Llama2 model\n >>> print(base_model.layers[0].attn)\n MultiHeadAttention(\n (q_proj): Linear(in_features=4096, out_features=4096, bias=False)\n (k_proj): Linear(in_features=4096, out_features=4096, bias=False)\n (v_proj): Linear(in_features=4096, out_features=4096, bias=False)\n (output_proj): Linear(in_features=4096, out_features=4096, bias=False)\n (pos_embeddings): RotaryPositionalEmbeddings()\n )\n\n # Print the same for Llama2 with LoRA weights\n >>> print(lora_model.layers[0].attn)\n MultiHeadAttention(\n (q_proj): LoRALinear(\n (dropout): Dropout(p=0.0, inplace=False)\n \n", + "text": "Result 4:\nDocument_id:cbc88\nContent: LoRA to Llama2 models\n------------------------------\n\nWith torchtune, we can easily apply LoRA to Llama2 with a variety of different configurations.\nLet's take a look at how to construct Llama2 models in torchtune with and without LoRA.\n\n.. code-block:: python\n\n from torchtune.models.llama2 import llama2_7b, lora_llama2_7b\n\n # Build Llama2 without any LoRA layers\n base_model = llama2_7b()\n\n # The default settings for lora_llama2_7b will match those for llama2_7b\n # We just need to define which layers we want LoRA applied to.\n # Within each self-attention, we can choose from [\"q_proj\", \"k_proj\", \"v_proj\", and \"output_proj\"].\n # We can also set apply_lora_to_mlp=True or apply_lora_to_output=True to apply LoRA to other linear\n # layers outside of the self-attention.\n lora_model = lora_llama2_7b(lora_attn_modules=[\"q_proj\", \"v_proj\"])\n\n.. note::\n\n Calling :func:`lora_llama_2_7b ` alone will not handle the definition of which parameters are trainable.\n See :ref:`below` for how to do this.\n\nLet's inspect each of these models a bit more closely.\n\n.. code-block:: bash\n\n # Print the first layer's self-attention in the usual Llama2 model\n >>> print(base_model.layers[0].attn)\n MultiHeadAttention(\n (q_proj): Linear(in_features=4096, out_features=4096, bias=False)\n (k_proj): Linear(in_features=4096, out_features=4096, bias=False)\n (v_proj): Linear(in_features=4096, out_features=4096, bias=False)\n (output_proj): Linear(in_features=4096, out_features=4096, bias=False)\n (pos_embeddings): RotaryPositionalEmbeddings()\n )\n\n # Print the same for Llama2 with LoRA weights\n >>> print(lora_model.layers[0].attn)\n MultiHeadAttention(\n (q_proj): LoRALinear(\n (dropout): Dropout(p=0.0, inplace=False)\n \n", "type": "text" }, { - "text": "Result 5:\nDocument_id:1d70c\nContent: ora_finetune_label>`.\nFor more on QLoRA in torchtune, see our :ref:`QLoRA Tutorial `.\n\nLet's take a look at how we can fine-tune Llama3-8B-Instruct with LoRA on a single device using torchtune. In this example, we will fine-tune\nfor one epoch on a common instruct dataset for illustrative purposes. The basic command for a single-device LoRA fine-tune is\n\n.. code-block:: bash\n\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device\n\n.. note::\n To see a full list of recipes and their corresponding configs, simply run ``tune ls`` from the command line.\n\nWe can also add :ref:`command-line overrides ` as needed, e.g.\n\n.. code-block:: bash\n\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device \\\n checkpointer.checkpoint_dir= \\\n tokenizer.path=/tokenizer.model \\\n checkpointer.output_dir=\n\nThis will load the Llama3-8B-Instruct checkpoint and tokenizer from ```` used in the :ref:`tune download ` command above,\nthen save a final checkpoint in the same directory following the original format. For more details on the\ncheckpoint formats supported in torchtune, see our :ref:`checkpointing deep-dive `.\n\n.. note::\n To see the full set of configurable parameters for this (and other) configs we can use :ref:`tune cp ` to copy (and modify)\n the default config. :ref:`tune cp ` can be used with recipe scripts too, in case you want to make more custom changes\n that cannot be achieved by directly modifying existing configurable parameters. For more on :ref:`tune cp ` see the section on\n :ref:`modifying configs ` in our \":ref:`finetune_llama_label`\" tutorial.\n\nOnce training is complete, the model checkpoints will be saved and their locations will be logged. For\nLoRA fine-tuning, the final checkpoint will contain the merged weights, and a copy of just the (much smaller) LoRA weights\nwill\n", + "text": "Result 5:\nDocument_id:9dcb7\nContent: ora_finetune_label>`.\nFor more on QLoRA in torchtune, see our :ref:`QLoRA Tutorial `.\n\nLet's take a look at how we can fine-tune Llama3-8B-Instruct with LoRA on a single device using torchtune. In this example, we will fine-tune\nfor one epoch on a common instruct dataset for illustrative purposes. The basic command for a single-device LoRA fine-tune is\n\n.. code-block:: bash\n\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device\n\n.. note::\n To see a full list of recipes and their corresponding configs, simply run ``tune ls`` from the command line.\n\nWe can also add :ref:`command-line overrides ` as needed, e.g.\n\n.. code-block:: bash\n\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device \\\n checkpointer.checkpoint_dir= \\\n tokenizer.path=/tokenizer.model \\\n checkpointer.output_dir=\n\nThis will load the Llama3-8B-Instruct checkpoint and tokenizer from ```` used in the :ref:`tune download ` command above,\nthen save a final checkpoint in the same directory following the original format. For more details on the\ncheckpoint formats supported in torchtune, see our :ref:`checkpointing deep-dive `.\n\n.. note::\n To see the full set of configurable parameters for this (and other) configs we can use :ref:`tune cp ` to copy (and modify)\n the default config. :ref:`tune cp ` can be used with recipe scripts too, in case you want to make more custom changes\n that cannot be achieved by directly modifying existing configurable parameters. For more on :ref:`tune cp ` see the section on\n :ref:`modifying configs ` in our \":ref:`finetune_llama_label`\" tutorial.\n\nOnce training is complete, the model checkpoints will be saved and their locations will be logged. For\nLoRA fine-tuning, the final checkpoint will contain the merged weights, and a copy of just the (much smaller) LoRA weights\nwill\n", "type": "text" }, { @@ -135,11 +135,11 @@ "error_message": null, "metadata": { "document_ids": [ - "6421150d-d334-4163-a058-3818b2b742e9", - "6421150d-d334-4163-a058-3818b2b742e9", - "0c95cff3-5612-40cf-a73d-77644a2462d0", - "6421150d-d334-4163-a058-3818b2b742e9", - "1d70c86d-4cdf-4be9-a1f2-8a271b15ce2c" + "cbc884b1-9d88-4d5c-aff4-7a4b3a56618c", + "cbc884b1-9d88-4d5c-aff4-7a4b3a56618c", + "8892b092-6394-471e-b143-a23c6cc374f8", + "cbc884b1-9d88-4d5c-aff4-7a4b3a56618c", + "9dcb747d-0627-40cc-a23c-0bee2b6b05af" ] } } @@ -307,23 +307,23 @@ "type": "text" }, { - "text": "Result 1:\nDocument_id:7bdfa\nContent: conversational data, :func:`~torchtune.datasets.chat_dataset` seems to be a good fit. For any\ncustom local dataset we always need to specify ``source``, ``data_files``, and ``split`` for any dataset\nbuilder in torchtune. For :func:`~torchtune.datasets.chat_dataset`, we additionally need to specify\n``conversation_column`` and ``conversation_style``. Our data follows the ``\"sharegpt\"`` format, so\nwe can specify that here. Altogether, our :func:`~torchtune.datasets.chat_dataset` call should\nlook like so:\n\n.. code-block:: python\n\n from torchtune.datasets import chat_dataset\n from torchtune.models.llama3 import llama3_tokenizer\n\n tokenizer = llama3_tokenizer(\"/tmp/Meta-Llama-3-8B-Instruct/original/tokenizer.model\")\n ds = chat_dataset(\n tokenizer=tokenizer,\n source=\"json\",\n data_files=\"data/my_data.json\",\n split=\"train\",\n conversation_column=\"dialogue\",\n conversation_style=\"sharegpt\",\n )\n\n.. code-block:: yaml\n\n # In config\n tokenizer:\n _component_: torchtune.models.llama3.llama3_tokenizer\n path: /tmp/Meta-Llama-3-8B-Instruct/original/tokenizer.model\n\n dataset:\n _component_: torchtune.datasets.chat_dataset\n source: json\n data_files: data/my_data.json\n split: train\n conversation_column: dialogue\n conversation_style: sharegpt\n\n.. note::\n You can pass in any keyword argument for `load_dataset `_ into all our\n Dataset classes and they will honor them. This is useful for common parameters\n such as specifying the data split with :code:`split` or configuration with\n :code:`name`\n\nIf you needed to add a prompt template, you would simply pass it into the tokenizer.\nSince we're fine-tuning Llama3, the tokenizer will handle all formatting for\nus and prompt templates are optional. Other models such as Mistral's :class:`~torchtune.models.mistral._tokenizer.MistralTokenizer`,\nuse a chat template by default (:class:`~torchtune.models.mistral.MistralChatTemplate`) to format\nall messages according to their `recommendations `_ into all our\n Dataset classes and they will honor them. This is useful for common parameters\n such as specifying the data split with :code:`split` or configuration with\n :code:`name`\n\nIf you needed to add a prompt template, you would simply pass it into the tokenizer.\nSince we're fine-tuning Llama3, the tokenizer will handle all formatting for\nus and prompt templates are optional. Other models such as Mistral's :class:`~torchtune.models.mistral._tokenizer.MistralTokenizer`,\nuse a chat template by default (:class:`~torchtune.models.mistral.MistralChatTemplate`) to format\nall messages according to their `recommendations `_, a parameter-efficient finetuning technique,\nand show you how you can use torchtune to finetune a Llama2 model with LoRA.\nIf you already know what LoRA is and want to get straight to running\nyour own LoRA finetune in torchtune, you can jump to :ref:`LoRA finetuning recipe in torchtune`.\n\n.. grid:: 2\n\n .. grid-item-card:: :octicon:`mortar-board;1em;` What you will learn\n\n * What LoRA is and how it saves memory during finetuning\n * An overview of LoRA components in torchtune\n * How to run a LoRA finetune using torchtune\n * How to experiment with different LoRA configurations\n\n .. grid-item-card:: :octicon:`list-unordered;1em;` Prerequisites\n\n * Be familiar with :ref:`torchtune`\n * Make sure to :ref:`install torchtune`\n * Make sure you have downloaded the :ref:`Llama2-7B model weights`\n\nWhat is LoRA?\n-------------\n\n`LoRA `_ is an adapter-based method for\nparameter-efficient finetuning that adds trainable low-rank decomposition matrices to different layers of a neural network,\nthen freezes the network's remaining parameters. LoRA is most commonly applied to\ntransformer models, in which case it is common to add the low-rank matrices\nto some of the linear projections in each transformer layer's self-attention.\n\n.. note::\n\n If you're unfamiliar, check out these references for the `definition of rank `_\n and discussion of `low-rank approximations `_.\n\nBy finetuning with LoRA (as opposed to finetuning all model parameters),\nyou can expect to see memory savings due to a substantial reduction in the\nnumber of parameters with gradients. When using an optimizer with momentum,\nlike `AdamW `_, a parameter-efficient finetuning technique,\nand show you how you can use torchtune to finetune a Llama2 model with LoRA.\nIf you already know what LoRA is and want to get straight to running\nyour own LoRA finetune in torchtune, you can jump to :ref:`LoRA finetuning recipe in torchtune`.\n\n.. grid:: 2\n\n .. grid-item-card:: :octicon:`mortar-board;1em;` What you will learn\n\n * What LoRA is and how it saves memory during finetuning\n * An overview of LoRA components in torchtune\n * How to run a LoRA finetune using torchtune\n * How to experiment with different LoRA configurations\n\n .. grid-item-card:: :octicon:`list-unordered;1em;` Prerequisites\n\n * Be familiar with :ref:`torchtune`\n * Make sure to :ref:`install torchtune`\n * Make sure you have downloaded the :ref:`Llama2-7B model weights`\n\nWhat is LoRA?\n-------------\n\n`LoRA `_ is an adapter-based method for\nparameter-efficient finetuning that adds trainable low-rank decomposition matrices to different layers of a neural network,\nthen freezes the network's remaining parameters. LoRA is most commonly applied to\ntransformer models, in which case it is common to add the low-rank matrices\nto some of the linear projections in each transformer layer's self-attention.\n\n.. note::\n\n If you're unfamiliar, check out these references for the `definition of rank `_\n and discussion of `low-rank approximations `_.\n\nBy finetuning with LoRA (as opposed to finetuning all model parameters),\nyou can expect to see memory savings due to a substantial reduction in the\nnumber of parameters with gradients. When using an optimizer with momentum,\nlike `AdamW `.\n.. .. _glossary_fsdp2:\n\n", + "text": "Result 3:\nDocument_id:de2d4\nContent: ` module, which we swap\n out for :class:`~torchtune.modules.peft.LoRALinear` when ``use_dora=True``.\n\n.. _glossary_distrib:\n\n\n.. TODO\n\n.. Distributed\n.. -----------\n\n.. .. _glossary_fsdp:\n\n.. Fully Sharded Data Parallel (FSDP)\n.. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n.. All our ``_distributed`` recipes use `FSDP `.\n.. .. _glossary_fsdp2:\n\n", "type": "text" }, { - "text": "Result 4:\nDocument_id:64211\nContent: 06% of all params are trainable.\n\n.. note::\n If you are directly using the LoRA recipe (as detailed :ref:`here`), you need only pass the\n relevant checkpoint path. Loading model weights and setting trainable parameters will be taken care\n of in the recipe.\n\n\n.. _lora_recipe_label:\n\nLoRA finetuning recipe in torchtune\n-----------------------------------\n\nFinally, we can put it all together and finetune a model using torchtune's `LoRA recipe `_.\nMake sure that you have first downloaded the Llama2 weights and tokenizer by following :ref:`these instructions`.\nYou can then run the following command to perform a LoRA finetune of Llama2-7B with two GPUs (each having VRAM of at least 16GB):\n\n.. code-block:: bash\n\n tune run --nnodes 1 --nproc_per_node 2 lora_finetune_distributed --config llama2/7B_lora\n\n.. note::\n Make sure to point to the location of your Llama2 weights and tokenizer. This can be done\n either by adding :code:`checkpointer.checkpoint_files=[my_model_checkpoint_path] tokenizer_checkpoint=my_tokenizer_checkpoint_path`\n or by directly modifying the :code:`7B_lora.yaml` file. See our \"\":ref:`config_tutorial_label`\" recipe\n for more details on how you can easily clone and modify torchtune configs.\n\n.. note::\n You can modify the value of :code:`nproc_per_node` depending on (a) the number of GPUs you have available,\n and (b) the memory constraints of your hardware.\n\nThe preceding command will run a LoRA finetune with torchtune's factory settings, but we may want to experiment a bit.\nLet's take a closer look at some of the :code:`lora_finetune_distributed` config.\n\n.. code-block:: yaml\n\n # Model Arguments\n model:\n _component_: lora_llama2_7b\n lora_attn_modules: ['q_proj', 'v_proj']\n lora_rank: 8\n lora_alpha: 16\n ...\n\nWe see that the\n", + "text": "Result 4:\nDocument_id:c4fc3\nContent: 06% of all params are trainable.\n\n.. note::\n If you are directly using the LoRA recipe (as detailed :ref:`here`), you need only pass the\n relevant checkpoint path. Loading model weights and setting trainable parameters will be taken care\n of in the recipe.\n\n\n.. _lora_recipe_label:\n\nLoRA finetuning recipe in torchtune\n-----------------------------------\n\nFinally, we can put it all together and finetune a model using torchtune's `LoRA recipe `_.\nMake sure that you have first downloaded the Llama2 weights and tokenizer by following :ref:`these instructions`.\nYou can then run the following command to perform a LoRA finetune of Llama2-7B with two GPUs (each having VRAM of at least 16GB):\n\n.. code-block:: bash\n\n tune run --nnodes 1 --nproc_per_node 2 lora_finetune_distributed --config llama2/7B_lora\n\n.. note::\n Make sure to point to the location of your Llama2 weights and tokenizer. This can be done\n either by adding :code:`checkpointer.checkpoint_files=[my_model_checkpoint_path] tokenizer_checkpoint=my_tokenizer_checkpoint_path`\n or by directly modifying the :code:`7B_lora.yaml` file. See our \"\":ref:`config_tutorial_label`\" recipe\n for more details on how you can easily clone and modify torchtune configs.\n\n.. note::\n You can modify the value of :code:`nproc_per_node` depending on (a) the number of GPUs you have available,\n and (b) the memory constraints of your hardware.\n\nThe preceding command will run a LoRA finetune with torchtune's factory settings, but we may want to experiment a bit.\nLet's take a closer look at some of the :code:`lora_finetune_distributed` config.\n\n.. code-block:: yaml\n\n # Model Arguments\n model:\n _component_: lora_llama2_7b\n lora_attn_modules: ['q_proj', 'v_proj']\n lora_rank: 8\n lora_alpha: 16\n ...\n\nWe see that the\n", "type": "text" }, { - "text": "Result 5:\nDocument_id:0c95c\nContent: etune\n:func:`torchtune.models.llama3.llama3_8b` with DoRA, you would use :func:`torchtune.models.llama3.lora_llama3_8b` with ``use_dora=True``:\n\n.. code-block:: bash\n\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device \\\n model.use_dora=True\n\n.. code-block:: yaml\n\n model:\n _component_: torchtune.models.lora_llama3_8b\n use_dora: True\n\nSince DoRA extends LoRA, the parameters for :ref:`customizing LoRA ` are identical. You can also quantize the base model weights like in :ref:`glossary_qlora` by using ``quantize=True`` to reap\neven more memory savings!\n\n.. code-block:: bash\n\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device \\\n model.apply_lora_to_mlp=True \\\n model.lora_attn_modules=[\"q_proj\",\"k_proj\",\"v_proj\"] \\\n model.lora_rank=16 \\\n model.lora_alpha=32 \\\n model.use_dora=True \\\n model.quantize_base=True\n\n.. code-block:: yaml\n\n model:\n _component_: torchtune.models.lora_llama3_8b\n apply_lora_to_mlp: True\n lora_attn_modules: [\"q_proj\", \"k_proj\", \"v_proj\"]\n lora_rank: 16\n lora_alpha: 32\n use_dora: True\n quantize_base: True\n\n\n.. note::\n\n Under the hood, we've enabled DoRA by adding the :class:`~torchtune.modules.peft.DoRALinear` module, which we swap\n out for :class:`~torchtune.modules.peft.LoRALinear` when ``use_dora=True``.\n\n.. _glossary_distrib:\n\n\n.. TODO\n\n.. Distributed\n.. -----------\n\n.. .. _glossary_fsdp:\n\n.. Fully Sharded Data Parallel (FSDP)\n.. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n.. All our ``_distributed`` recipes use `FSDP `.\n.. .. _glossary_fsdp2:\n\n", + "text": "Result 5:\nDocument_id:de2d4\nContent: etune\n:func:`torchtune.models.llama3.llama3_8b` with DoRA, you would use :func:`torchtune.models.llama3.lora_llama3_8b` with ``use_dora=True``:\n\n.. code-block:: bash\n\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device \\\n model.use_dora=True\n\n.. code-block:: yaml\n\n model:\n _component_: torchtune.models.lora_llama3_8b\n use_dora: True\n\nSince DoRA extends LoRA, the parameters for :ref:`customizing LoRA ` are identical. You can also quantize the base model weights like in :ref:`glossary_qlora` by using ``quantize=True`` to reap\neven more memory savings!\n\n.. code-block:: bash\n\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device \\\n model.apply_lora_to_mlp=True \\\n model.lora_attn_modules=[\"q_proj\",\"k_proj\",\"v_proj\"] \\\n model.lora_rank=16 \\\n model.lora_alpha=32 \\\n model.use_dora=True \\\n model.quantize_base=True\n\n.. code-block:: yaml\n\n model:\n _component_: torchtune.models.lora_llama3_8b\n apply_lora_to_mlp: True\n lora_attn_modules: [\"q_proj\", \"k_proj\", \"v_proj\"]\n lora_rank: 16\n lora_alpha: 32\n use_dora: True\n quantize_base: True\n\n\n.. note::\n\n Under the hood, we've enabled DoRA by adding the :class:`~torchtune.modules.peft.DoRALinear` module, which we swap\n out for :class:`~torchtune.modules.peft.LoRALinear` when ``use_dora=True``.\n\n.. _glossary_distrib:\n\n\n.. TODO\n\n.. Distributed\n.. -----------\n\n.. .. _glossary_fsdp:\n\n.. Fully Sharded Data Parallel (FSDP)\n.. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n.. All our ``_distributed`` recipes use `FSDP `.\n.. .. _glossary_fsdp2:\n\n", "type": "text" }, { @@ -335,11 +335,11 @@ "error_message": null, "metadata": { "document_ids": [ - "7bdfad34-d546-4e98-9757-a0289696cd97", - "6421150d-d334-4163-a058-3818b2b742e9", - "0c95cff3-5612-40cf-a73d-77644a2462d0", - "6421150d-d334-4163-a058-3818b2b742e9", - "0c95cff3-5612-40cf-a73d-77644a2462d0" + "f76dc7f5-9648-4272-a579-c8387fb1408a", + "c4fc3cb6-6172-489e-90a7-b39d343e14c0", + "de2d49de-55de-44dd-9bca-6f4f6d633b0a", + "c4fc3cb6-6172-489e-90a7-b39d343e14c0", + "de2d49de-55de-44dd-9bca-6f4f6d633b0a" ] } } @@ -362,23 +362,23 @@ "type": "text" }, { - "text": "Result 1:\nDocument_id:7da0c\nContent: .. _lora_finetune_label:\n\n============================\nFine-Tuning Llama2 with LoRA\n============================\n\nThis guide will teach you about `LoRA `_, a parameter-efficient finetuning technique,\nand show you how you can use torchtune to finetune a Llama2 model with LoRA.\nIf you already know what LoRA is and want to get straight to running\nyour own LoRA finetune in torchtune, you can jump to :ref:`LoRA finetuning recipe in torchtune`.\n\n.. grid:: 2\n\n .. grid-item-card:: :octicon:`mortar-board;1em;` What you will learn\n\n * What LoRA is and how it saves memory during finetuning\n * An overview of LoRA components in torchtune\n * How to run a LoRA finetune using torchtune\n * How to experiment with different LoRA configurations\n\n .. grid-item-card:: :octicon:`list-unordered;1em;` Prerequisites\n\n * Be familiar with :ref:`torchtune`\n * Make sure to :ref:`install torchtune`\n * Make sure you have downloaded the :ref:`Llama2-7B model weights`\n\nWhat is LoRA?\n-------------\n\n`LoRA `_ is an adapter-based method for\nparameter-efficient finetuning that adds trainable low-rank decomposition matrices to different layers of a neural network,\nthen freezes the network's remaining parameters. LoRA is most commonly applied to\ntransformer models, in which case it is common to add the low-rank matrices\nto some of the linear projections in each transformer layer's self-attention.\n\n.. note::\n\n If you're unfamiliar, check out these references for the `definition of rank `_\n and discussion of `low-rank approximations `_.\n\nBy finetuning with LoRA (as opposed to finetuning all model parameters),\nyou can expect to see memory savings due to a substantial reduction in the\nnumber of parameters with gradients. When using an optimizer with momentum,\nlike `AdamW `_, a parameter-efficient finetuning technique,\nand show you how you can use torchtune to finetune a Llama2 model with LoRA.\nIf you already know what LoRA is and want to get straight to running\nyour own LoRA finetune in torchtune, you can jump to :ref:`LoRA finetuning recipe in torchtune`.\n\n.. grid:: 2\n\n .. grid-item-card:: :octicon:`mortar-board;1em;` What you will learn\n\n * What LoRA is and how it saves memory during finetuning\n * An overview of LoRA components in torchtune\n * How to run a LoRA finetune using torchtune\n * How to experiment with different LoRA configurations\n\n .. grid-item-card:: :octicon:`list-unordered;1em;` Prerequisites\n\n * Be familiar with :ref:`torchtune`\n * Make sure to :ref:`install torchtune`\n * Make sure you have downloaded the :ref:`Llama2-7B model weights`\n\nWhat is LoRA?\n-------------\n\n`LoRA `_ is an adapter-based method for\nparameter-efficient finetuning that adds trainable low-rank decomposition matrices to different layers of a neural network,\nthen freezes the network's remaining parameters. LoRA is most commonly applied to\ntransformer models, in which case it is common to add the low-rank matrices\nto some of the linear projections in each transformer layer's self-attention.\n\n.. note::\n\n If you're unfamiliar, check out these references for the `definition of rank `_\n and discussion of `low-rank approximations `_.\n\nBy finetuning with LoRA (as opposed to finetuning all model parameters),\nyou can expect to see memory savings due to a substantial reduction in the\nnumber of parameters with gradients. When using an optimizer with momentum,\nlike `AdamW ` alone will not handle the definition of which parameters are trainable.\n See :ref:`below` for how to do this.\n\nLet's inspect each of these models a bit more closely.\n\n.. code-block:: bash\n\n # Print the first layer's self-attention in the usual Llama2 model\n >>> print(base_model.layers[0].attn)\n MultiHeadAttention(\n (q_proj): Linear(in_features=4096, out_features=4096, bias=False)\n (k_proj): Linear(in_features=4096, out_features=4096, bias=False)\n (v_proj): Linear(in_features=4096, out_features=4096, bias=False)\n (output_proj): Linear(in_features=4096, out_features=4096, bias=False)\n (pos_embeddings): RotaryPositionalEmbeddings()\n )\n\n # Print the same for Llama2 with LoRA weights\n >>> print(lora_model.layers[0].attn)\n MultiHeadAttention(\n (q_proj): LoRALinear(\n (dropout): Dropout(p=0.0, inplace=False)\n \n", + "text": "Result 2:\nDocument_id:c4fc3\nContent: LoRA to Llama2 models\n------------------------------\n\nWith torchtune, we can easily apply LoRA to Llama2 with a variety of different configurations.\nLet's take a look at how to construct Llama2 models in torchtune with and without LoRA.\n\n.. code-block:: python\n\n from torchtune.models.llama2 import llama2_7b, lora_llama2_7b\n\n # Build Llama2 without any LoRA layers\n base_model = llama2_7b()\n\n # The default settings for lora_llama2_7b will match those for llama2_7b\n # We just need to define which layers we want LoRA applied to.\n # Within each self-attention, we can choose from [\"q_proj\", \"k_proj\", \"v_proj\", and \"output_proj\"].\n # We can also set apply_lora_to_mlp=True or apply_lora_to_output=True to apply LoRA to other linear\n # layers outside of the self-attention.\n lora_model = lora_llama2_7b(lora_attn_modules=[\"q_proj\", \"v_proj\"])\n\n.. note::\n\n Calling :func:`lora_llama_2_7b ` alone will not handle the definition of which parameters are trainable.\n See :ref:`below` for how to do this.\n\nLet's inspect each of these models a bit more closely.\n\n.. code-block:: bash\n\n # Print the first layer's self-attention in the usual Llama2 model\n >>> print(base_model.layers[0].attn)\n MultiHeadAttention(\n (q_proj): Linear(in_features=4096, out_features=4096, bias=False)\n (k_proj): Linear(in_features=4096, out_features=4096, bias=False)\n (v_proj): Linear(in_features=4096, out_features=4096, bias=False)\n (output_proj): Linear(in_features=4096, out_features=4096, bias=False)\n (pos_embeddings): RotaryPositionalEmbeddings()\n )\n\n # Print the same for Llama2 with LoRA weights\n >>> print(lora_model.layers[0].attn)\n MultiHeadAttention(\n (q_proj): LoRALinear(\n (dropout): Dropout(p=0.0, inplace=False)\n \n", "type": "text" }, { - "text": "Result 3:\nDocument_id:7da0c\nContent: 06% of all params are trainable.\n\n.. note::\n If you are directly using the LoRA recipe (as detailed :ref:`here`), you need only pass the\n relevant checkpoint path. Loading model weights and setting trainable parameters will be taken care\n of in the recipe.\n\n\n.. _lora_recipe_label:\n\nLoRA finetuning recipe in torchtune\n-----------------------------------\n\nFinally, we can put it all together and finetune a model using torchtune's `LoRA recipe `_.\nMake sure that you have first downloaded the Llama2 weights and tokenizer by following :ref:`these instructions`.\nYou can then run the following command to perform a LoRA finetune of Llama2-7B with two GPUs (each having VRAM of at least 16GB):\n\n.. code-block:: bash\n\n tune run --nnodes 1 --nproc_per_node 2 lora_finetune_distributed --config llama2/7B_lora\n\n.. note::\n Make sure to point to the location of your Llama2 weights and tokenizer. This can be done\n either by adding :code:`checkpointer.checkpoint_files=[my_model_checkpoint_path] tokenizer_checkpoint=my_tokenizer_checkpoint_path`\n or by directly modifying the :code:`7B_lora.yaml` file. See our \"\":ref:`config_tutorial_label`\" recipe\n for more details on how you can easily clone and modify torchtune configs.\n\n.. note::\n You can modify the value of :code:`nproc_per_node` depending on (a) the number of GPUs you have available,\n and (b) the memory constraints of your hardware.\n\nThe preceding command will run a LoRA finetune with torchtune's factory settings, but we may want to experiment a bit.\nLet's take a closer look at some of the :code:`lora_finetune_distributed` config.\n\n.. code-block:: yaml\n\n # Model Arguments\n model:\n _component_: lora_llama2_7b\n lora_attn_modules: ['q_proj', 'v_proj']\n lora_rank: 8\n lora_alpha: 16\n ...\n\nWe see that the\n", + "text": "Result 3:\nDocument_id:c4fc3\nContent: 06% of all params are trainable.\n\n.. note::\n If you are directly using the LoRA recipe (as detailed :ref:`here`), you need only pass the\n relevant checkpoint path. Loading model weights and setting trainable parameters will be taken care\n of in the recipe.\n\n\n.. _lora_recipe_label:\n\nLoRA finetuning recipe in torchtune\n-----------------------------------\n\nFinally, we can put it all together and finetune a model using torchtune's `LoRA recipe `_.\nMake sure that you have first downloaded the Llama2 weights and tokenizer by following :ref:`these instructions`.\nYou can then run the following command to perform a LoRA finetune of Llama2-7B with two GPUs (each having VRAM of at least 16GB):\n\n.. code-block:: bash\n\n tune run --nnodes 1 --nproc_per_node 2 lora_finetune_distributed --config llama2/7B_lora\n\n.. note::\n Make sure to point to the location of your Llama2 weights and tokenizer. This can be done\n either by adding :code:`checkpointer.checkpoint_files=[my_model_checkpoint_path] tokenizer_checkpoint=my_tokenizer_checkpoint_path`\n or by directly modifying the :code:`7B_lora.yaml` file. See our \"\":ref:`config_tutorial_label`\" recipe\n for more details on how you can easily clone and modify torchtune configs.\n\n.. note::\n You can modify the value of :code:`nproc_per_node` depending on (a) the number of GPUs you have available,\n and (b) the memory constraints of your hardware.\n\nThe preceding command will run a LoRA finetune with torchtune's factory settings, but we may want to experiment a bit.\nLet's take a closer look at some of the :code:`lora_finetune_distributed` config.\n\n.. code-block:: yaml\n\n # Model Arguments\n model:\n _component_: lora_llama2_7b\n lora_attn_modules: ['q_proj', 'v_proj']\n lora_rank: 8\n lora_alpha: 16\n ...\n\nWe see that the\n", "type": "text" }, { - "text": "Result 4:\nDocument_id:7da0c\nContent: from our Llama2\nmodel without any wrappers or custom checkpoint conversion logic.\n\n.. code-block:: python\n\n # Assuming that base_model already has the pretrained Llama2 weights,\n # this will directly load them into your LoRA model without any conversion necessary.\n lora_model.load_state_dict(base_model.state_dict(), strict=False)\n\n.. note::\n Whenever loading weights with :code:`strict=False`, you should verify that any missing or extra keys in\n the loaded :code:`state_dict` are as expected. torchtune's LoRA recipes do this by default via\n :func:`validate_missing_and_unexpected_for_lora() `.\n\nOnce we've loaded the base model weights, we also want to set only LoRA parameters to trainable.\n\n.. _setting_trainable_params:\n\n.. code-block:: python\n\n from torchtune.modules.peft.peft_utils import get_adapter_params, set_trainable_params\n\n # Fetch all params from the model that are associated with LoRA.\n lora_params = get_adapter_params(lora_model)\n\n # Set requires_grad=True on lora_params, and requires_grad=False on all others.\n set_trainable_params(lora_model, lora_params)\n\n # Print the total number of parameters\n total_params = sum([p.numel() for p in lora_model.parameters()])\n trainable_params = sum([p.numel() for p in lora_model.parameters() if p.requires_grad])\n print(\n f\"\"\"\n {total_params} total params,\n {trainable_params}\" trainable params,\n {(100.0 * trainable_params / total_params):.2f}% of all params are trainable.\n \"\"\"\n )\n\n 6742609920 total params,\n 4194304 trainable params,\n 0.06% of all params are trainable.\n\n.. note::\n If you are directly using the LoRA recipe (as detailed :ref:`here`), you need only pass the\n relevant checkpoint path. Loading model weights and setting trainable parameters will be taken care\n of in the recipe.\n\n\n.. _lora_recipe_label:\n\nLoRA finetuning recipe in torchtune\n-----------------------------------\n\nFinally, we can put it all together and finetune a model using torchtune's `LoRA recipe `.\n\nOnce we've loaded the base model weights, we also want to set only LoRA parameters to trainable.\n\n.. _setting_trainable_params:\n\n.. code-block:: python\n\n from torchtune.modules.peft.peft_utils import get_adapter_params, set_trainable_params\n\n # Fetch all params from the model that are associated with LoRA.\n lora_params = get_adapter_params(lora_model)\n\n # Set requires_grad=True on lora_params, and requires_grad=False on all others.\n set_trainable_params(lora_model, lora_params)\n\n # Print the total number of parameters\n total_params = sum([p.numel() for p in lora_model.parameters()])\n trainable_params = sum([p.numel() for p in lora_model.parameters() if p.requires_grad])\n print(\n f\"\"\"\n {total_params} total params,\n {trainable_params}\" trainable params,\n {(100.0 * trainable_params / total_params):.2f}% of all params are trainable.\n \"\"\"\n )\n\n 6742609920 total params,\n 4194304 trainable params,\n 0.06% of all params are trainable.\n\n.. note::\n If you are directly using the LoRA recipe (as detailed :ref:`here`), you need only pass the\n relevant checkpoint path. Loading model weights and setting trainable parameters will be taken care\n of in the recipe.\n\n\n.. _lora_recipe_label:\n\nLoRA finetuning recipe in torchtune\n-----------------------------------\n\nFinally, we can put it all together and finetune a model using torchtune's `LoRA recipe !Xz+B1(|@BNY8%i=zIh{a>u0e^N9E-g#`g+iXE+;K1DP zoOACv-#6!$7B_wJ!KT(i;O)CFH@VNawYzA*Q&Y*$_8n}8U&<{cqTqU&f>P`%5x1X> zoFm$zh{A8^zE>>ljkY=_4qenocXp-GU1_u{ok!c#Xh+Fex35rdlI`e!g$%{-r-FvS zYpOlVT?hwN&QMwV?BYFPxY8Mih2EV(O;2i^{Y~$;gpW@5{Soq4-+1Eu<_R}kFjBO{ zb0W0KJ0()?xq|*{33$(&Y8q2YIf>Rmn=58lx zI-N>k!*QBMONuJfyulf~#FihT_IT@OuUV}8_JmZ^uXjmCnKrYeHHW$ZxMOSsidSiHA4eE`lM**j4w zqqcNj(UH&lxK(V{hSmI_K9n2CXd@Ob7Pr_rHK!zKNfR*>T1us5!{BH^<`h;=@q9v5 zE%bG<$2}w?C25|OIGPg@I*oZ^X*tQNysEMSXNaz&doE6(HJag*0?jchPKljpM$z@8 z!YfQlHmoWYjtqBUfnF?pd|Tzl8z|Q+E?-=M%Y{)`dG+brMmN$uTz}1e;J*pLVR)VU zeLl4wdG@2HD6)>t?BsNrr2<;9RXJe0%aI>gqic-2?2*+euotrxSOXoBw9 z$Tqa1KB` zU!d^mjy;DOsxv&K$X@ju`(bwBT542ecHnQcX1{d$ITE%|5qNoF5-w8lfPvSsNDkVO znI57J`H}Pxcwqcz`Nx#{30Awf24N0i#&Sz1n&1Saa6R!)fmI(9K zy2dRthMn=j-EMoP6R$Mr`^5aOB)*Ya3B&1Oz{FngAo~!!a3%v++4teEBRg-sDhk;< z;EV1Se|au@I7H%MnMQb6x_8QS-%lYpzFduaYk4FL?D7~dVMT{g0A&=-1LWz8By$YJk#z3VL)UEIRNq$e8`Tb;<0XM$VRJ+yWAic)0*TuPKlrk!B=SX^e$}abFvOS`{a@SLN+)WJU!J=@ z|L6HV&-42||Leu`t1@q|vh|lAAN+FKcE|<1?uPddy$iQ=pK;240fR=}wdC-658^O? z(t)cRpl`$jQ?3PUlhIkXd7X_*NQz*bWo9dEEJIV2;g1I^;I`ifV=aU&B=Ql_m}~hM zE1VwPcE?`uzW(&o1AV!4Da?>kgkecW=A$IfML1Fj(NUh|SyAFSJsr$JM?w-Qg;6X+ zv0)SuiIU+c6;03yj-h29h2_dAN|=nW6iqTAQ6U8`ERh_?GK@eoEG>m}HKUHo-6^#; zrmlgRwsBYpXQ6z8DDD5#nJV}o;8<$>D?2=^S|fF-zuCK zfl_EPD$pF2pdzA7i#l9v^T2Zh<3*|v@cF^d?)klM@I5q3D|DRM3Sax{jJd-e+^mJC z2VpwkhV^gtBEJvL4$T!>XmF+-UGmXA`x(L(59=O_81viIJ!#Ck4 z3xGa6Jp*5yal`f_@0j>_1rC=2>kzEN_~GzRm{lq}v|MUpKIr^WT~rq>!ZZ3twMJcS zT+Zw=H>w6(3kxT2ReP|qvQgC;OC?fq1v_@G)o?)&3utSQUt4P#)&B5+egGjx7w779| zsC0Q!?oH}i6HJf1j5R^c5w|0c)Pzno(-^ZzKO9A%v)YogB}MoDbuQ9)wvg&9P2JEE zYliPew$zzL@}$cvD1=M>F87Mv&|X9-Xg%DOn#psX-MiV__`g%izoJaBQgD6z!lVC< z%^Y7jE(4JDZ@mv`aR&MsuZ@!gbP@gWhKfR5De)jo`U+74laJW%!(;ptbn^i%dm;4b zwrf`C3cwF&asrOeut2hVR&qN(O(aN Hr?&hF-r)t-