From 2272a9feb976773e8607d9f83cd96dfa06de24c7 Mon Sep 17 00:00:00 2001 From: JinhaoSong322 Date: Wed, 19 Aug 2026 15:35:27 +0000 Subject: [PATCH] Add OrcaRouter agent example Add a minimal stateful chat agent example that points the OpenAI-compatible openai client at OrcaRouter (https://api.orcarouter.ai/v1), using the orcarouter/auto model alias. Register the example in the examples index and the ecosystem docs table. Co-Authored-By: Claude Signed-off-by: JinhaoSong322 --- docs/ecosystem.rst | 3 + examples/README.md | 1 + examples/orcarouter-agent/README.md | 81 ++++++++++ examples/orcarouter-agent/__init__.py | 16 ++ examples/orcarouter-agent/application.py | 98 ++++++++++++ examples/orcarouter-agent/notebook.ipynb | 169 +++++++++++++++++++++ examples/orcarouter-agent/requirements.txt | 19 +++ examples/orcarouter-agent/statemachine.png | Bin 0 -> 25450 bytes 8 files changed, 387 insertions(+) create mode 100644 examples/orcarouter-agent/README.md create mode 100644 examples/orcarouter-agent/__init__.py create mode 100644 examples/orcarouter-agent/application.py create mode 100644 examples/orcarouter-agent/notebook.ipynb create mode 100644 examples/orcarouter-agent/requirements.txt create mode 100644 examples/orcarouter-agent/statemachine.png diff --git a/docs/ecosystem.rst b/docs/ecosystem.rst index fa8e334fa..ae658b491 100644 --- a/docs/ecosystem.rst +++ b/docs/ecosystem.rst @@ -40,6 +40,9 @@ LLM & AI Frameworks * - **OpenAI** - Use OpenAI models (and any OpenAI API-compatible server) inside Burr actions. - `Example `__ + * - **OrcaRouter** + - Use OrcaRouter's gateway (OpenAI-compatible endpoint, ``https://api.orcarouter.ai/v1``) inside Burr actions for a wide range of models through one API key. + - `Example `__ * - **LangChain / LCEL** - Use LangChain chains and runnables as Burr actions. Includes a custom serialization plugin to persist LangChain objects in state. - :doc:`Reference ` | diff --git a/examples/README.md b/examples/README.md index 9d4447cc2..a9536a0e1 100644 --- a/examples/README.md +++ b/examples/README.md @@ -48,6 +48,7 @@ Note we have a few more in [other-examples](other-examples/), but those do not y - [multi-agent-collaboration](multi-agent-collaboration/) - This example shows how to use Burr to create a multi-agent collaboration. This is a clone of the following [LangGraph example](https://github.com/langchain-ai/langgraph/blob/main/examples/multi_agent/multi-agent-collaboration.ipynb). - [multi-modal-chatbot](multi-modal-chatbot/) - This example shows how to use Burr to create a multi-modal chatbot. This demonstrates how to use a model to delegate to other models conditionally. - [streaming-overview](streaming-overview/) - This example shows how we can use the streaming API to respond to return quicker results to the user and build a seamless experience +- [orcarouter-agent](orcarouter-agent/) - A small stateful chat agent backed by [OrcaRouter](https://www.orcarouter.ai), using its OpenAI-compatible API. - [integrations/bedrock](integrations/bedrock/) - Minimal graphs using Amazon Bedrock (`BedrockAction` and `BedrockStreamingAction`). - [tracing-and-spans](tracing-and-spans/) - This example shows how to use Burr to create a simple chatbot with additional visibility. This is a good starting point for understanding how to use Burr's tracing functionality. - [web-server](web-server/) - This example shows how to use Burr in a web server. This is a good starting point for understanding how to use Burr for interaction. diff --git a/examples/orcarouter-agent/README.md b/examples/orcarouter-agent/README.md new file mode 100644 index 000000000..71aa2b33f --- /dev/null +++ b/examples/orcarouter-agent/README.md @@ -0,0 +1,81 @@ + + +# A Burr agent backed by OrcaRouter + +This example shows how to build a small stateful chat agent with Burr and have it +talk to [OrcaRouter](https://www.orcarouter.ai) — a gateway that provides an +OpenAI-compatible API for a wide range of models through a single endpoint. + +It also runs gateway-level, zero-trust security for AI agents on the same endpoint — +screening every prompt/response and governing every tool call on a default-deny basis, +with no application code changes. + +OrcaRouter exposes the OpenAI-compatible API at: + +``` +https://api.orcarouter.ai/v1 +``` + +Because the API is OpenAI-compatible, we can use the `openai` Python client and +simply point `base_url` at OrcaRouter. The `orcarouter/auto` model alias routes to a +default capable model. + +## Setup + +```bash +pip install "apache-burr[start]" openai +``` + +Then set your OrcaRouter API key: + +```bash +export ORCAROUTER_API_KEY="your-orca-key" +``` + +Optionally override the endpoint or model: + +```bash +export ORCAROUTER_BASE_URL="https://api.orcarouter.ai/v1" # default +export ORCAROUTER_MODEL="orcarouter/auto" # default +``` + +## Running + +Run the example from the `examples/orcarouter-agent` directory: + +```bash +python application.py "What is Apache Burr?" +``` + +This will build the state machine (`statemachine.png`), send your prompt to +OrcaRouter, and print the reply. The agent loops between a `human_input` action and +an `ai_response` action, accumulating a `chat_history` in state. + +You can also open `notebook.ipynb` and run the cells step by step. + +## How it works + +- `human_input` reads the prompt and appends it to the chat history in state. +- `ai_response` sends the full chat history to + `https://api.orcarouter.ai/v1/chat/completions` using the `orcarouter/auto` model + and stores the reply back in state. + +The state machine is small on purpose — swap in more actions (tool calls, human +approval, sub-agents) to build a full agent on top of OrcaRouter. diff --git a/examples/orcarouter-agent/__init__.py b/examples/orcarouter-agent/__init__.py new file mode 100644 index 000000000..13a83393a --- /dev/null +++ b/examples/orcarouter-agent/__init__.py @@ -0,0 +1,16 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. diff --git a/examples/orcarouter-agent/application.py b/examples/orcarouter-agent/application.py new file mode 100644 index 000000000..24317f445 --- /dev/null +++ b/examples/orcarouter-agent/application.py @@ -0,0 +1,98 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +"""A minimal Burr agent that talks to [OrcaRouter](https://www.orcarouter.ai). + +[OrcaRouter](https://www.orcarouter.ai) exposes an OpenAI-compatible API at +``https://api.orcarouter.ai/v1``, so we can point the ``openai`` client at it +and use the ``orcarouter/auto`` model alias. Set ``ORCAROUTER_API_KEY`` to +your OrcaRouter key before running. +""" + +import os +from typing import Tuple + +import openai + +from burr.core import ApplicationBuilder, State, action + +ORCAROUTER_BASE_URL = os.getenv("ORCAROUTER_BASE_URL", "https://api.orcarouter.ai/v1") +ORCAROUTER_MODEL = os.getenv("ORCAROUTER_MODEL", "orcarouter/auto") + + +def _orcarouter_client() -> openai.OpenAI: + """Create an OpenAI-compatible client pointed at the OrcaRouter gateway.""" + return openai.OpenAI( + base_url=ORCAROUTER_BASE_URL, + api_key=os.environ["ORCAROUTER_API_KEY"], + ) + + +@action(reads=[], writes=["prompt", "chat_history"]) +def human_input(state: State, prompt: str) -> Tuple[dict, State]: + """Pull human input from the outside world and add it to the chat history.""" + chat_item = {"content": prompt, "role": "user"} + return {"prompt": prompt}, state.update(prompt=prompt).append(chat_history=chat_item) + + +@action(reads=["chat_history"], writes=["response", "chat_history"]) +def ai_response(state: State) -> Tuple[dict, State]: + """Query OrcaRouter with the full chat history.""" + client = _orcarouter_client() + content = ( + client.chat.completions.create( + model=ORCAROUTER_MODEL, + messages=state["chat_history"], + ) + .choices[0] + .message.content + ) + chat_item = {"content": content, "role": "assistant"} + return {"response": content}, state.update(response=content).append(chat_history=chat_item) + + +def application(): + return ( + ApplicationBuilder() + .with_actions( + human_input=human_input, + ai_response=ai_response, + ) + .with_transitions( + ("human_input", "ai_response"), + ("ai_response", "human_input"), + ) + .with_state(chat_history=[]) + .with_entrypoint("human_input") + .build() + ) + + +if __name__ == "__main__": + import sys + + app = application() + app.visualize( + output_file_path="statemachine", + include_conditions=False, + view=False, + format="png", + ) + + prompt = sys.argv[1] if len(sys.argv) > 1 else "Tell me a one-sentence fact about the ocean." + _, result, state = app.run(halt_after=["ai_response"], inputs={"prompt": prompt}) + print(result["response"]) diff --git a/examples/orcarouter-agent/notebook.ipynb b/examples/orcarouter-agent/notebook.ipynb new file mode 100644 index 000000000..d8225efbf --- /dev/null +++ b/examples/orcarouter-agent/notebook.ipynb @@ -0,0 +1,169 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements. See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership. The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License. You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing,\n# software distributed under the License is distributed on an\n# \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n# KIND, either express or implied. See the License for the\n# specific language governing permissions and limitations\n# under the License.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Setup\n", + "\n", + "[OrcaRouter](https://www.orcarouter.ai) exposes an OpenAI-compatible API at `https://api.orcarouter.ai/v1`.\n", + "\n", + "Install the dependencies and set your `ORCAROUTER_API_KEY`:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!pip install \"apache-burr[start]\" openai" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "from typing import Tuple\n", + "\n", + "import openai # OrcaRouter is OpenAI-compatible\n", + "\n", + "from burr.core import action, State, Application\n", + "\n", + "ORCAROUTER_BASE_URL = os.getenv(\"ORCAROUTER_BASE_URL\", \"https://api.orcarouter.ai/v1\")\n", + "ORCAROUTER_MODEL = os.getenv(\"ORCAROUTER_MODEL\", \"orcarouter/auto\")\n", + "\n", + "assert \"ORCAROUTER_API_KEY\" in os.environ, \"set ORCAROUTER_API_KEY first\"\n", + "\n", + "def _orcarouter_client() -> openai.OpenAI:\n", + " return openai.OpenAI(\n", + " base_url=ORCAROUTER_BASE_URL,\n", + " api_key=os.environ[\"ORCAROUTER_API_KEY\"],\n", + " )" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Define Actions\n", + "\n", + "We define two actions:\n", + "1. `human_input` -- this is the first one, it accepts a prompt from the outside and adds it to the state\n", + "2. `ai_response` -- this sends the full chat history to OrcaRouter's `chat/completions` endpoint and stores the reply\n", + "\n", + "Note we're only ever touching the `openai` client and pointing its `base_url` at OrcaRouter." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "@action(reads=[], writes=[\"prompt\", \"chat_history\"])\n", + "def human_input(state: State, prompt: str) -> Tuple[dict, State]:\n", + " \"\"\"Pulls human input from the outside world and adds it to the chat history.\"\"\"\n", + " chat_item = {\"content\": prompt, \"role\": \"user\"}\n", + " return {\"prompt\": prompt}, state.update(prompt=prompt).append(chat_history=chat_item)\n", + "\n", + "\n", + "@action(reads=[\"chat_history\"], writes=[\"response\", \"chat_history\"])\n", + "def ai_response(state: State) -> Tuple[dict, State]:\n", + " \"\"\"Queries OrcaRouter with the chat history.\"\"\"\n", + " client = _orcarouter_client()\n", + " content = (\n", + " client.chat.completions.create(\n", + " model=ORCAROUTER_MODEL,\n", + " messages=state[\"chat_history\"],\n", + " )\n", + " .choices[0]\n", + " .message.content\n", + " )\n", + " chat_item = {\"content\": content, \"role\": \"assistant\"}\n", + " return {\"response\": content}, state.update(response=content).append(chat_history=chat_item)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Create the app\n", + "\n", + "We create our app by adding our actions, then adding transitions. The agent loops forever between `human_input` and `ai_response`, accumulating a `chat_history` in state." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "app = (\n", + " ApplicationBuilder().with_actions(\n", + " human_input=human_input,\n", + " ai_response=ai_response\n", + " ).with_transitions(\n", + " (\"human_input\", \"ai_response\"),\n", + " (\"ai_response\", \"human_input\"),\n", + " ).with_state(chat_history=[]).with_entrypoint(\"human_input\").build()\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Run the app\n", + "\n", + "To run the app, we call the `.run` function, passing in a stopping condition. In this case, we want it to halt after `ai_response`. It returns the result, and the resulting state." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "final_action, result, state = app.run(\n", + " halt_after=[\"ai_response\"],\n", + " inputs={\"prompt\": \"What is Apache Burr?\"},\n", + ")\n", + "print(state[\"response\"])" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.4" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples/orcarouter-agent/requirements.txt b/examples/orcarouter-agent/requirements.txt new file mode 100644 index 000000000..5e8f6fc0e --- /dev/null +++ b/examples/orcarouter-agent/requirements.txt @@ -0,0 +1,19 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +burr[start] +openai diff --git a/examples/orcarouter-agent/statemachine.png b/examples/orcarouter-agent/statemachine.png new file mode 100644 index 0000000000000000000000000000000000000000..15cc44d9236678468d994191a9a148d0bc05d1a2 GIT binary patch literal 25450 zcmeGES2UdO8}|)QiWDUXf<%bkC0dwhzlbh~GJ1(<(OdMI1kptgW=M3Sx6uiLXft6j zdS{3hMv4BM`9FK_&bxEpTko5-va;5UTyxEFok#l|-$TSJbwx7b`@|3kgiKjUP74CL z8VrG4`F!gtc%?F4!3_ej5LA|XuHy~gn(=~<$X(w2v-7g57d6GZAE>DKU!#s@`mOND z$jCQ44|&IW!XC=~x>@aNEz+-k+))y)fbT=Rn@pte-em*{j zQDkx-U9nc4$`iVGO*-J`dx+wCI_b0{em)`PW;gr}Uip+nRU2kb5w9W_Ey(Fh`M;NR zc-$MN*sp-=Ffs>&e~g16;G!;9uF^pu--&L$2LFxr(f_$O3O~Kus=Cg?@+O)R4;S=Q zsymIl&Fo;bne$H3ci{?Tp3AN9s=f+$$Sdl+f%?0$ca_m`^@n2kv*5hDvO)?@T@~7u za?$Q#+V6vuZ!xn&@i3=UB1o*nC$`|w&v0RRO}_q<^P`oZ^V(-JZNI8E|NE|2tQ$k6 zA^FYs04ewKmg_RZUwFqrMxFQSz{LCDEWvIcp4l(iE?F48YU|p6KW9DoyJ&?x2ug1e znayyq#h4fiFK2=0Bu_suOn;8t3jENRyG=|MjB%^?_3E=bv1=ehRstWYX)z>+3 z!{ce4(@b|VFRl++dDN7rz6eHgJJsm>i37+)zU>=()Y9yY}2PuD;Iy4K3Mf%_?~W& z-{bphJDe+4RlOljvRTW_^6U@lPKx6c5~-dpa&U2)rKF+ZcYZKrgYam?V$4?eRwm|J z=G?h^Geh7=D$3ueaR1pq zIM}q7{UGq-_~`W$mr)q)+&gTtsJ*T#zs1yHiGhst*`MnElyeW9Nt_aQSmA;VPztTSgm#Omrxqmxq5aMG9j83gI*UR+r&x6@MYv<6a%?b8d4Uh^C^825 z?@R3XSNI?I0lTDm&HC8R5lQ?(schS(b)g)MRJ4*zQu9J7@@*-V;}l`kUEIHCc~cWY zxX$0CSt-ScYg2diX1ZneB(+H&!T4owu`I%;P-=3gC!2>CU$ve2YAuV(W3-)5xihT{ zQmnWmvynXbfhxWNYNW5+eh=jP?$;03zPJbOw6KCN>Xn5#`hKm`sbR%#GMW8@l2A8| z{Q69jA2vS*Epz#shF4eS?9b1qj_RAgzIpK2!(cNlPZ!}C`L+fq3|`HVy*AfzsyFw! zTw|F;&sxj1DW9%mN0#^+MQP3Q?iAa~-4NnYdiCEZua z6FD`Gyd?_|o_+jv#t6GF$lr542G|-qT-ollJ9$>nh3L@Rv!a4-_4NHl>@z{qrBS_0 z+B=HB$4UcsyYS6>eG*h0%}g;0a{)(fz!zQ8?coHge%#;HB>H7@C9|ExK?rx7Z?c)od^Aoj7eHMQH@d|U# z0`)EMNJ}Pb?KcH7*xnRLmFkrrf)A%VZMwu7ICMqAwDbLwUvl^zN;bIT59LIhXS10C zzwE%LpLBDmrSDBS_lx6Gjoktj6qHmF+;FWyXS*Y|*w*8%x)ma#(D(m+RZhH7kTpwK zjKYkH#8tNyQQFJ}O7tvgKCYkVWAXjdUVtAk5P$pX5}y@RGk_isdX1zQz_?wR{tS9C+qocjuw+EOrQd@MK1Txr)mg z#d&!knF)?LERJ!;#o!_2PU0)Bq^zu+ecryH zcAwL{)L8~%(Lw{l4`6aiS^X5)YDbEdDtCGPBI;G)^O*bmw0!!D&8Ef-Wrnp-&9~o! zqoj|QNzlbNuTIq3A;j&+;J*HZZ zS1-4=8)jgcwf18B>%#iD4R1+Ndz{nE*LLO6;<{fohNjL40TZ--ljle5GmTRJk;2q~ z*2Yn!XqKc;V^WpQu^N_IR`O^%=-;cwb?|2g_BQl3Q8|in<=O=?$gz6O%QD z7e`$p{LDWJveb)>8w{R&A^f0vEMESpGk$fjNw0MBY&j9*FjA&i?9!_E&{aRO&Z7&yh6GK8v~U zabMZck*>wr@SKMnJ1CaKuE4o0Q+tGCNH>5&u1E^4uCzO*#9$8I|O= z{L}UQf1U~oIcUVG2K?`CqsIdhV&c@tW(SK=k2r4zKjrk9(9a>O8-{;U`Dn0hbNrlrLc>p8o2k{vbw>EN~K zY1Mu8iYr%UT88J=1Od(iOPBgPudSMTaqo`e;YBn2fJrCd*=5i|s2+Cs_a|90-$ThG ztVY{(m6cIo;KBzYnHkrfPFq{D$=VI~j@z7i$dTm%;mfk?_!!_MOIB)C8 z@22VLW?*CBQ=h8QjUrMl=D;EtnJm*Pp$xGd(;_XbFq&?%<#Ym8ocU+c{&K3`)&2SN zp|fMvusbb9z6Y!AuhCzhr%EiOE3tuEx6~%nr!w&TPBO2U<6J9dys})1FrW$ooYBRG zuqGt26o4@qpGc!)2oR;>}1F>!6 z9EJXY0R@vrc%{3|#r6RS_ez|MK#5kK0k}=(7iFq!3G90Hw%8QUtrJV@r*>1QIw~ct zK5`j2JZ+-TZgll=+nHz4RZ=<^S8MB~lLHBd@rqvVpd!e{a^mBc*q3Z~SLgV+tytnW z#~i=TWzAIMzgiBv+*u>6@|S6?g!Cn6cy2s(S?cD`L)E?=!l+Q1}E-|Q6%Rq@+ zk$hqWPlzn^KHRmt3!IAOUTiVUew#4*Q1rJ|!|B<7Dp05C>*aOowRVFxXt)XTqP)@W z3r0^&qG?9YEIvP7-@JA0%H5OWut`N<)VU2lRTB`-=ju+#`PjF z6Rke$!N$D2QJK@t{=@1W2!y845~4ToMT41*(s8^3%BaB=nSd}!J#6;NeK}gJH#jix zI@)o%zL);-3pw=6BRJtEBb{!MR=)WcbYH~VfiJkb5tb``$(eyC&rNVzSDfh-N)1Ip zwtCAFf3_4y1L_E`vIS5R;E0GMLgP54f;PgH^W`Q*}& zK+FCI=>T=t6FRuiI7;f>n$JTCRI=7f_+Moq+uSfdS9H$Mcu|38%WC>J6hGW@(hqyn zC=0y@JRaP4`|J4zJY$&-x3I?@^C^_$6wX+9f7%@rE|<;zNgL|SAiR3uBCb_!ePEM$ z99Oo1E{aPUelh?`zY25QvHvV6DmBvfV7;GA99_MM|{e1^736_=70TXUvb6sx%THHdDhpN zS$KGeGxCcz?o$dXbt172dlTtv+pyt<7jD^}KK-QmgOc z+)oX0a)3r0%gf8lvE@l#o>i+qD{|D;wdSH$iOF+A-6amqrA9d_=2Yq&du>Iq!C*2c zZ~J!IF4G#x^>4*zWPoT22R&1!n@Z{@rq*hsI(77yl7kJg!K_OvN{`G>FEslOl#~iR_{tRR$_3uk}AB@fafs5k$ZbqiJ=>i$f9}`GAj4&tu&#PVqn2M zmAv+kH}8ijvvqBYRDwe@k)v1#j<)&MBpK*KM)TE33cRB$uGcTv*ba-syvVPc>tMW+{$`4Lf3Hg{wXquMofWDGN3DRwAu#K_IJ_U_GsLB3Uwa1^Zk8+GPgG2of|qYsn%}vmk58n zk{pYs%?spj<*gE7u1Wfn3bvHsqxzw=M<-TVTms?<=cEQ+kuX91{x9CdnY*MF{)I;DbJrng0taYndwtHda<+g_;N8L^{nhhB{8E_X(Js7_r^0?5zSv+}G#oQTNnT`Ir0| zOd8+a3LR#N{|Sn4IK=Z%4<`k_?pHVXlZQG17bhE4N^Evh*)KkgTxz#x!czy7S^ zv+0eFe#MuH*hIc9cVv~v z#-To6*@o}dWNqKH+SI+s?2%HVev~7&=BeYP;rlC_H8WHZ%d3M%qH0lHZ!Ef-QMex( zKj<818asE6dfx1IbY$OcOF+jo-<%zIK89Z%oO)APk15bAH{~CF`53UH<$af=>D0lD zI{BQ+=;(cLvIEagV)C~6JrAu;4-xIJzZP;iq^D4QkB)bof*~!T0X%t|nV~Q81#BRY z`m#4y$DxaQrG^uDfj=Z$&^+verDb-pl7cQxsk4_>IdLduU+Y;5VyM zFyTPg{eoOd*mbdI3bpm;^!(uWsNE>i=Ly|ByxgGL37cPPl`n2#X)re5e(fmpw*BId zIFQJOMvHMRpyIha-@&T4FYbb-7x~-cP04_=FgGCF;O3~QS?L(15c8YqPyPC?H+AR~>S0{!!`E&&_mglzG@UDYyX~^bb&2Ep z#|r}bfj41L59K^JxpM@?kz@r0o_!>jUNJ5faQ9Lf3|Xn62JO%^_-oylL_ZfKQ~veq z6IRxbo?>(S_Igz*(6ET`#oZ8X&Qm8R6&qz6vIUnPBK+NV#8qM`+G9g2&Bg$viAw!!8%*M5yYQ1cC~3rcC0~DR*IgaY+E*-;bz5ycQc$A9(*Ptg zJ>PY!HZ{{lHmAh~mykf(DWWFK%Bq7Dg25(Q%)TgJgT%fAmVp1W#H(`Ct&WbxP?DfN z%;TQ}1LHX3ICM?YT!2^|a6enSp4ctV@`8a-dP*xRtF^`yCAz6Pe7*qbjzO4|b?M0g z&I-hG+eh;|(+!ms1@0C7LPQ*w`IOtDT zk503P*1BUdjw*T7zD-+2)^xxS*q%I5`oo z?QDHMfeZZ2ShR zL}%1-!6vEkI^XKWn=O0G;e>S2VzIZc;=-xrheXIJyWUi4(Q+WJsI;A-8pgJ;o#D9hf*rsbc$ILF9QN6Gh_Wyyx;t37yXJN(&QI_P2%mJ7|Zl`E%kH>of`dX@A*$17jo`Dy?16U%6 zFnIJ5`+K$pdw?_J2pPx3kN9{8M9zT z&AB!&kXj=O6=Lj6%dOK_v*lG0*WD%uBRl2*USJ9`rn~i*zh6M`%Fip}>?KBZx{oL- z9Q|e*W8{{jI~!M0ibd6``8H<#6dh)pVOUA^c5!_AszLK#yk?FmN48E9Mv0SWb~MR&>TC$IK|DkwUZG|TJX+`{|sE}DVR^BGBx|0p03D+#=% z{cBs`IS1&vcH1}Q>EX%v)zv(8-HR3CE0Df&mN;>^JM#}Hp49tncLC-2*l@r9>vKKH z^Zjx8sFdyLG^RU>W2IAndpXUFUD|8oqz?UEUF#jEQp%f!`gV?zn@g2oFuYG4J8rWk zrmXd3F;QciICQQU^%$fN-_}vYBe?O8`Zs?6;bmjP)}<&X~*@q;6>m zvd?cP;F;&9JqVS=pID3a%Kx?ZVdO#0R{hrM7@MMaZMb`!;*3-~Q8LdpN-N8d-?;MP zjmfN_GB%dD9@dbxk)oMD3t~M>5ddupdjA>SX*pU4A4EbDb$Mccp!&GQwU@olVJ?%G zUFu-u8d^9WuGF+YOh62_fNlvReL4&}@W`l6Kp6tJYQ4aeVWp&69Vaq)J4}Z%9Q4wC zaQC*kqwOXpwKO4%?P+=RK1@36sHk9DLzP6pV6XoeZ$A4_fWz! z5Hyjrrruj{C<(yCj&&we73S(Z&HZPSNoSjIB9%Ks!yZy#AO}n4H$nkBd;#@TJG4l) z?kR+UgXTaamztAY`qE#aC$<38J>f_lylYy6)6c(P*QG2L78e`sF9BzJE6MQ3}TB zm8&Dh4mP|BO zzFq|YFpH`r+4?cwONvYxrz%ZW6b9hr@}Vg&_a``&h;vSj}+ zV^q~}R!W*Ez|4clTjStk_vDMP%lsVG8wtd30IBWETZCD2C^bg`Ss4XpGHpQx21%id zZEWiNz>`~P^R7t((BS572T3_VlCKKiX7{0HlAuinlydZeYL zRV^}p{5`#LH$o1y?7u%Ttv&|9FZN+Wid8`#5g3G_9R1$31xih!q~Z_#4VwsG#{#6- z#cD|@TYw{C^8*O@EMDLr*RBMC&^^=S)%d65ISi@8vrFyO4!u0a%W%B>+m@#qG*@X+ zfJ6cux;EW#E{Y>%&)!{{i|tx0$edh>7FMT{eMWc$^8DW^XPb>iX_t9h;5~dEP3Y}U zBV}ol$Ew(xMz5V|FrZK`f?xhal*);4{1xZu9;)`&73Q6rpqbn`mYkOwduoIJ;5CQX z?_uKg+#bMsv?wQ@oSz=GZdQ@}n*mJNnB5PXsJ5vC|3QL8!swWQNp@~IxIj5dgisu8 z*vNoV5{VRN;>Y`MjBQbI1`64r&p=sDAC{J!JdrJrZ4K~)`#A-5*H>rW#ax@kqf?I4 zQre_d?3;aQ_S24 ze}TZbPrf~L6~e`dABVkq^%;Q(P`diXQ|+>5gUi|=MOdI{*`%WC2i@dH{zgKzu*HjB zkCZf*np43WaQAXOnRj(1Ns?(wYzeZrjtWlClQvz6@10Zd#6>GaYf6zi@Ws{ z!}L8hSwcx>&C5xg;oYyckv|y z8$Rkw3b&@945`MP_~wykhMMLM1p2CSIT14Ac6qn zu5A!%lRUkg+$iihr=QVp=xJ*xnAHWkX_Oa#VttWRZn!!xn z20p}DyTlIV<@?`V-h|$=k5j9dNz8r}aAn@*nGXMa!kr=4(z9Zzft$K`@4(N_Me}zr zJ_<1m^pRIscZVyP1|AdrD=dGHZZP?-tpjiY0R1}f1a~yZL(jkf0XXU`ia%A*cYmk} zp!S+9Q>$eb2t(qXQPJ1pXy{T!;OQ3TfipwvyLIQGw}31I1SitXbuUW73yNPJ@!PCy z!bt4AG{zDIFa21c3n7~K&v{e%w}(jsA?4Q&&P>i?z?=l`dy`~J7* zl~`IWmAWX%D|0#vC)z9Xg`XhOHUEZeRPo4cG$x)n!loM{2^zixkJOhg=?`=<~`68QxrlKS4g76Mvv=q;!l zrPVmd(DaSj3x(a#xUM&#rm!0;(d>zJ^gG%{(^d141V}<|Mup0L1D(BHXU+%$9cRWLNFiTbR=yok@{kKex7Znw)(o;=@!m&XLf>qCD`KD_Y0_| z(f=}COyU@^wE+srmM>ystW#@EEv{6b+&x(c$(S4QtMPyBVvP-hq43-MVD-qy}>vR#78Z!bEA;so!0Xg19+uJJHx2gzK-qi-L8NXIGn zPsZYJJ3<6yZ$-+TA}9SIlnoo z(PEe;%%i%(ba$ibii>C+Jk zc1^Mi<@V;jh85WQ)>L&w0lXBW)wNm(bFG%)XN_M?Ik%E~o8p%Rr2yyYBhbv}h!-`Wx?R2X7 zc+*6vB66ofuZj~t3clnoxP;z|0{vk@V;QX6^gR0gd52&}A+NallWxBLpM8JeQfn`< zA}D7JLfrN4);9gs|JjHX%r4C-C@lsy4jN4uf;&}Iw5a8AqM#=i4M0lzlR2n^Ku+KPUzH91e~nhst;*}3w;_;N?OXFp4=kKgA&`0TP>6J(E1KQ{ z&a^Xkg*%Tz_SS;ubIAN(w`L~)I1Q9z0nrG#%olHkwoFz=zdzpS*WAiDsrSM6NbMAL zyn=y-%T~ph6(a8WuuXAxDUDhdwpLEl541O*hzR&9Rvw=_tlXjb1OOAv0(*ba_B7`r z`zY^%u@H~JEKjn3`ZiQZu^a>P$9l9TCVa`)3p+|*P^b$O(}oZl8wLnB9NVd)r3?2n>U;~^j%D3 zC&0Gp`BwRU2^}q*$;R(HMw7d;8EPX0RYTX4xOs0_49w!i5l84H2qU-_|KC5Pk6fs47ksIF8wh27n+GJ`ip8L9ROl!Qk|4W6N zMqZh1@sj@FL;TA-t@GI&YWFkpl{l!#*;?8qM6+ zlfQj-Cgg9ing*;FbVY^M0CMAh5lZW|F$TRaiug_~d;Q~N7@1K|;1kz{4?f@zIDU>; z)HxCDol@-rYd&i?v^YLO?rcHRBBA%kFV%9=>sK+&(t*3#L=ke55(RV z*pjPwT0~ZpiAeA?_o#J>bxQ+2#p2=a&s#R{cXi#c(8;uu^!gLZul{zgi&oesP?+^z zoI(EaN%7+#8GD6KiH!$RrCuV|dv0ReSLV4Wh(q@X1O%h-?VFgQIv4TbT;)`N8lE~$ zTP>}2WQYIc71@g#U?sFYl(5k1J7w|?2}etxHcy4k$jg0u<$HcYhH#b#_wq+L zAT03EsGvBGt?4tl-Yw~aeFFNVy4sybuWYede1DiXGDjgWJ}u~L+#@j=bK>Kmoq)w= z*Yo`5X4w}i(9J`?@Isq%>AE>6JbZXq_TWKMS=#iOcW**;!20Mtes#8NB&^sPzbyWE ztVnx@P&CKJ-(ck@UORcNvoy66$d%XZF>WH4>nm9#Gd#6JCy+N?DZF|jW|K8n*j%6F z2EaY-B|A_2KOiP2=kwsSy4DgLE4ZRCE`o*3SpH{Rn zi!*z0^p}biS2lNYx+i*>@z?bc1^loJ-{O1tBzk$LU-x{Uu*0iY{@}@ciKWo-{J9q` zbqI|-jJmdv%eT`*ugs|K@cm6DlP2?x4)(Tk!|K-4A}L(C+3BV*Ym$k{VgjWq=I5W| zv&YeaPgz;rdogW~&po=#ipAmr)+Vo@%!9JFg)zVF#$@-dD$6MA7)Jj!SM)JJaeIJB`nEiyyv@vq z=r-*$#sVT9ejoWObcAmZ3t-Ry%hvrRmCWHWq}i`~l7a-<*aiN1lw%AiJJq2m2_eQ|E-D zU}<|aClsS|3(5+#lJ}=eY!A`R*KLwsa->lYs=s9p;o{8%2 zTLC7Jx(qaA_eF+10=x!4yH9@Of`#d%#-*fZ`=OFV9xb)Z-!L>B)vI04J<0 znynAueEljMiD*o|EeF5B-ZCgh=+{P`#R@9O)!L61X%}Q#ZAJ2S*O&RhK)o5DB6ilC&0#aqn1=CIw|O6rW}93bL$@df>wt`cX9M3-v&AlHr7y`tl)# z?_vvQmg+QH(~F`Cx;Un#oJeU<3|3~z9&?;@=Y(Ugo|J#%n^lv$fYEqrIh5BcfIc_Pn4Z2Baxfa4end%u$TuUpI1m;ck3gU zqXp6QldX^*Hjo4Rp(T37rZYLVS{G8I*YH7~`Y&)5N5&D+N}t)XUq4b4Z<`o>sT0mc zck5XlkwnIY-%ID;SA}ve{VuWi%z#CFo+{kSM>5@<&8xiWhi=HDY&%%-l$)2dG7F0- zrNK%`h3~=r$@g|)l_u=B^9ocO6tyOw0)b~F22Y~Mvf#2C`1BJu=apEEwGYyPP=kfh zmdI=+gKk81o@_gPN9qYDUWY*d#aF$rf_SuSb=@5KzFur9zeZ#SpB3NfWT%@l#5OUpMmc&fZkI8|+~V;H>! z>A6x99Ord&ZPpSk1P@P87)EW4h-fgvO3dn>derWjX;Bk@iW$nuV$E*)B=dI@8>dKR zNtaSq+_V}q`EZLpNIEy5dc~k2sp(mvyVoku*^VWRY#~y=EiizE^62#3V`GGs#fJKb zxl{on9{H7s^t3bldOU8!DjKLAW8i|FDWDR~-`i=;;Pz7E+AT-1uyeyZx)xx?7jL3H zwx>m%=;Y-Wyd}#hz%VE*oVtu5t)(WKjxvBSni>u882u~9sg8{W?E-(EJjo)9)JBgD z6_#?07sY73#5sSz>`l?{g14{u8}mYE3kGoXtk~>swRB}}5DW-iw29TjQfXJ1#9uf2%@5WI z3MF+e8&MTyVm&&GeA^Qd7*iCZZniMvvrfxz+DNgNccc_p ztMEA#BPX-1ip}dxj}G*(>KlHIJvoC}Vt7OyC&iEjYbK+MLYvF@D{51;9kncA-oCyH z=H~6ZOJh3V602I)s5nkv+5d(-|k}GxlA&*RsRFZRcn^$cUYGRWAOE>)bVR zcB+WFSzpHik|xwJNG<=;2nkxIxW14}My6cQ`L(jas_x1D zRO2Ia0h!@NIx|amxS-S2p;RXm{9p@L-tufaswfc=3aF*e_?B0e$Km(4BRbRqdA}rY zmMO4Q@$pK{1Q8s)B;Q@m%ms-NPIs(h1J-MwI;OKP%4&lBvYtElh(pIpjZ)Lnj?1?* zBx9im_afw`>SP@8=rfh%Dr=tSzP!H$$NHT)q@J!gj23s!(@ zzR6Zb2fwXx&f~#sD|kHB!`HldPjl^kpA-fhP9&9Eztq-&Z3EkNhY-d`0r?wn+00IO=&kUXBV$z)`|E_Jdt z<2CE^(aL})A9H;?k&2#(2-KGoe+lC1&@IU}nMZkiqR?zC+9KLv%JamK-X`Dne%L^7 zuhX=6M)=D_7Rrx;Dapz5I&XSgW}C7clMTNBG|s|+vIi@GiP}-&d{GI?sw(RPSMGXU$I~LwR}6Ud784@YT5DpJY6>AKv@Hp{2#b9Jjnr6dZH|^tAv9T&X^apJ{kx zxaVQ>M^nhQd#PjH%j3RhzJYIV%iRBNZ+s%s{7Y}Hi_>=xr-uS~T@@##18?Hav6&;u zC!4VgR@>4R%LgZLl9s%&pjVF&EhulWb+2z53ZQuTNUqLc9tfcB@=R4%Q1SZZ;Ci}o|m?bY-sg; z_~6eXl%U*=5DvR0Q&lH9sEn9kp96abGs9$*z&TGZ!fNX zfBqbD?Toh`djoPozyAfSQ`SSSkOCBO_4*SCB$$NaJHYJ%|3R+(f4<>DvLq;Q@b2MD zD%Uk7Ww|Cs?6Ri;WWEqI)hWs#HM^nzX_p^Ru`?2DsdOvBq~O|;nMpui3$R}H@nK<^~plCrxQs3&Oc9_XlIt!Nay`V}aq67ERKQTj@dmD3P^}mSMx&E8k(_+;n#C~HCG{f_O%c>aBn0fh zm00kFu53F?TX=tF`LE&8KawSMFA7Tj`RF*HjL9f3sj=*$`Q1S_5dp|@pr@YjA zz6Z~sUN**99TxxT%akN7O>z98BxG82z13Hkb=dZRK0355yunq9O;%Oqv2Oy7ti~>JbX8je2bxhZ${P z@xm@SKxUX=q{id<4e7AxBM1it1W0P&N|EGg+r1|6$$gNn7au29-|v+L6B zK_lt2pPgEa5<$M`gV@qrnC z@HJV89^@b1lJd)(1`}%+@hXd{*ruIEGhBls3C<`jGMkMIi?SVAqxIdFbnH3YihjHQ z(`LKv$P*okbbD~KFGy|NlWR??$iil-sxKN=knsamqM36!wUCRF?^1?&5ccGVgh+*1 zmk|dui$xss^2` zOp@i z3p94HCU121+g>Yc(R)ZWoDP&1e3Jd9rS~7yBFvmF%pk|^d+A->5|?OC2h78xg%pyk~2rmNpu+{AX6P(?nehN>AvNIAUsQzHgMrZBJA` zaFV(@-j=}s`nn5|yTA>1w9UX5kENJSpb0n&%(5~FGvCgn=nX*ee|R4(Gq0+FZ~tn? zR@!`a)+{N^m`cnk58IXhdo!1<4U>ULbeiIzq!f%(taRiNKnV*`qkZb@xgN{tzIv^y zjO>e>{hE-V0~_*~5#jHzLQ6NzjaO>q7JPCrdYvg6eEtH$O2Yr$IE5tHy(0zSTf*=F&@?w{E!BXhrYDW2Q zU3Ehk6Z+WCMe#<;7n ztu019_Hv?>c2n`I`J5nLCw;#EQHkvyF%eKZ`S)vyb22NzwvOh43ch|VR7q9=QyzXJ zPs!uu#GIiuO)_&tTW!GvkmcUg?oZaZMw7yvaht4w8jGI82hPn4>GoyZ$G)io4^0CO zM!^Q5rKKgv$BlaBP3cdi+Dm11sYU#+TnN?#lS2yvT-fI9`=NL^CQTThpW(FUE$QQP z4D>b+1mDP6TU!f76mTY|CV}O>j@H9Tdr>vN^}JMSc`FA!>?@T$ZyoOSF(cT6t zLm(-Mr5Db(!7!!>^X?B3aGZGr1T?*m)FtFUT9G7cy0Cm(8L+HRCN}*QiKOV*If`R| zR;i{6pw9=LX#cFu?@s}}Q5IN+xqahf-bKEHA8tRfZpL$Je;r$0Rn@WJk|iCG8Fb-O z(6+qxFog)R67os#Kil+tgOpLAOWIxP@oO<!clSWpbTI6wW=xlmIB9(+F8gQuH6cQ~#D6Muq)nZU!GQw2<{2fn!WaTmz3 zP-bDgI?2Qa(u5VUBFu+k<+X&|_niiltZCYMR)?I>+kl`Kc`5pJyh5}9xL8AO~?C&-0+VgjJ2_eTVY=toUb}G`< z@T{?X?wJRBi1@*X_T}l^CCA-}=;-J)VH;DQm1Hmlbz9YzfaeiG>gK=R_H)VHToxHR zIoxV;oO;?l4p!ww9mb#F547kvbDi1l0#TGq#I3D)w?%lt$=T9weKr@kLgQW^FCL93 zM)C;J&3gw!!iKf3efVdM)9oe=6@wOEkAjR5AE{Bb-;x{LjB#_GQ;r(a$82wwzKTDe z%2Q1hoAa-J@#zlA@zlR{#KQ~T2Vo#ke1CO=^CP{*KbwOOWdeCpHMwps&`+Gf)38_0 zGCd!Oq~cVEO9z|)${7_ECFs@jToX2m+Pd@bS@ZE~MvLzOSl`R|4utc z=t`{lt=C)`?nT2-qQSOK%h_K4uD2u|Y2fAg5wIab!mEq`zDgcg?#To111aJc>40bE zTszO*ZkXO?hD%?5_;A$(=iI!jP|)`NS24NErYxlMVsqm#7f8qK(+_97=4QN?V)AYO z%{|h<<*W?oVmvBb{O*3=z1^cC9^B%rG3;>;&Nf2OqC1?D)nRJPW2TC)ZLaO@5X-*o zrEtB}?RoK#w2C{4IZ}zB^AXUW^_;5scm6Fc^;7a}4SDEvV1xbre)~g;j~mxm@RJoy zMA9m^nW^Q0r}aE=s-N9Bkk5%%M?9Nx=_Gsj>|F)l#!nx&Yq2ztOVa#oNq@L&huk|p zqT#K&IcbaTXmD5)28HA`fgi*%N}2la%7fc@fHqqMzeA&}?ZTHk&o&)S_-7H|Qckpv z`(U>p<+Zad7sBZYNup}} zO3pupLOfmk8NbBw(mSX#Of6c_1Q#AV_S;HMRwaS@CBf3Fh%wH_?5NvCortI#jZofy zdEqBJ9_<>ZI5?nl78oihkQd&ydFDTb;^&SKUhP|F02L=6wnk*oy^q_(sqK7ndqzTn z(^5PPvdIKKkh#AK1_NH$?v9B8;M6*q$H27QiOyPAcWh|#%!(~k=l`kg%;TYK|GrOh zB}+w?Ng|?*eJfb?k#N+(*BA z`{#M?=a1)g|7pw|bIv()9>?+heBYnXX{e5`M{8u9=i9ISJB|`OjYpZ8@%~wcW4j% z{d9xvR?zP5!#>*BolW0Xi0~*!ue@wrIN0C92esEDzJbR4`76ibV9lE)`34+0Y$x&E+_m{YZjlV9vJ}Wu8oCG3;uZE0R#?^)9r2|AT9Z9 z&iSy@Qsw6`G`7hp^)qmYtq;3=CJovc7?Bt3dQvYw zkm@)Sz{jWege#Gj_VC@?=G`KTq>~!KOLY7!;o?QQecj#j8RJQ}{nkps)QIe0=KP*gB%hUi@Po`84v4lge8Fc5e&S-Y$5^O}v!C8fJOKfIH&Ro=j7O-Y~dLY(db@C-N%u4BaGZQR~U!^_Mgw@Z;#et(p!5<@*3uMDC^33im zE5S4Gy3HNT75mCn^fajIbVAPaX1Wa^B@GRO9lBzwIflxT%}QWNcC(zW?bRaP1bjr~ z4bUnZ&9!-N+qN{(s{GT0wbl(}G3`$kf42V_ko^ApZrdV#d}KHz@hb58NW%lo z8_VuTEX)K&7B(p@xQ0?Q@{JRssr)QezbxOROt0 zddk4~^ul9S?#L@icD()GkPF{rRewv< zs-70XTkw#d5k%(5_xCDgS^XTcYDrO`sp#St069K@#R6*}mX>Nng-cNQA^O(l%fRjH zEh_OxOHEV47hIqGA0(astJd?s{g31OFdg2I@d6O(Wy_nW5cR8*S6 zK+lo^sXQgXJ)SA+{SGDgn&TW0nnI|;f^QToWB^nA&bjQ-Qcc3escZ;68spq#CPwu( z4+#jmnI8fLpe@C0gWMVX0IL1TIuM&WXgXgnkc+b%04Z+$~#& z6>J~M7z*%7G3wlmii4WCQwqAUq%oNAPnj6pePCjZx1z(#Jji4(M!yI1^>~$t+3@Ws z$c=84t-En%0yboE;xR}-yZ$y;hBsuo;`}|QU!NvF2VApx(xf+;k?|K=r!u8e-UfLk zEHjDS(Mxsbr3`wtQAATZMN)@(9li7@YZ+sO_rhiqR)~A{FAAkK zoQ6Sz+^Y<=dDn9_(ex_wC`Ri6{#81FBdXlKH3IK^d(~$A=gvWK;2W~d_V6e^#a#FPP4~6w=-#jkKzPWGQInr>RugErqpcE z=n)4{Py2GJkHpQ7ADgD#1o0(j&ty&i0cWJi7{^i9nYZSYqpZR0kPKn*CJ}L$rgGsh ztNe3ATl40x20l$)tDCM5po~c$W&Z->T%o}CSK;Vt4A3OPRMSMyf-^)HS|eXg$ddit zQyAsAw>;ztM!Ys&Cs$&&bBjCBbOeLTqvw4BCJhvL^d%T_LcTgXV5K2!uavYgu=q*( zDC1|jFBY$N=(hjG^3i2g?$04G9s4};H2&Mx6`Gb&d#NA0t+(wpXk zc$0V6MunMUu;jjH)y+n|rJj(AL& zLj-VagEQI^b#*v<%B2M$TTl@ZKi`Q+B4t_uT+tMdZ4RVchaeC?zs)*7t21|<$^nqk zq-Q?`)MR2pLdToIq~?>AZUC?a$T_&ja2K(%3rI zWGYzx^4__6$MNNO%_$2@XU)euHb=u87B&4!&cn^lGLAXooHIVm|4#leOR`+Zdh9am zny(!%mMC-^#C>#k^oFW4#~Qy};7HXR4s19K&leEqazD>(=DW8C)48t&U0m@TFC8w{ zR=YeEFwH6@t76W|T$K4MM$+q)2BgDzuOZh1dlkGo@)N!h$ual}IB1c#GePr_0*eue z=>SMr+VW98_CY5M#tp{7bPf+b*oPO}6p8tUo`3dZK>W)?HBtRniN+}&%_R)U$GNL_ znWL_rzGzFZCLJ}PWM2LBIqceVC!r(wI;+ny-9%|br2%sqBx*cR#KO45osF*%eh^&v zu|$C5v_?dsNSS#Oe)=s;lp&&QFMS(7sH!KZyfXoT7C;LU+}Fb{!53GAnIgJd~ zEdG|9CmFUScYL)v-|*_NkwSDZSolruTRZaKnS*sP>wif|O1ez9faH?b({V^!;yszC zkvo!$jm^&Hp$~N}XKK=dg1iO;19$R%S*_zRx6Dh|wi<@*d0KU&T1P{$+3tV<>)O{Y zEjsPMn0Y0-z8L}%*@M$i6y|pxHTvZH8&pO=dM5++Zp&U!w*NaI_UZFiY;38qa+4n2 z>+*Y7MN(9}TaOPj2KLv-S=G<~6%>Fq;;O7$)Bu*;{U3Sy7rrh;{C(Z>sh6WTWMD@e z=`{Fx12ggR-aU76UrM1vjLOz4K_#2TF1C0T@=xO88kT^;pqKS-wet9F=26_)Ekn70MOWQ31vo(mYwu>0tfbyXFBOBC~4edvJem( zC!-2vdq@}58>jr>_s$`!h6`3{_HTIO2oa}bMulTIE3r1m=wifnvhh78kb=-XJyH4- zlqcZ8|7}*#{<%)-!<#3IH$N1+#TOc)jUId##ZL1?n@D31BP4&7ycwR;lHrW{KEDNK zT@w@jf`R7ynlU)QfKG=Ot9Kg#Yp00>arQm8kVsGW55}{>YklwypS?ZVekJ1Z%kP$I z8IpYHXX51i_`7Uj&LAcXShPhsZ*$80*qEX`=@^+4U|@<2IIv>3S?j6p)4nLwng1t7 zz;H;WOwgJnUlzD1WVo}vz0^-0SmlL!Md>TA*Wf94N0SQB-0HIryO2G9(uT4wsixei zeKqvLLg33x8*iu;nM`aRJGTQsm4$0WnGNS&xq-Utx#F0n$N!k4D3rBP6D))# zI;rVRdBt*-R+PI?J3T#`(%nowDG1{o#}OaO zW?J`J0nm%Uo6{zreSobqDt}%{^58msxYBF_1wmM99^ha>Sd0W?-uDV%vxVA$q__C6 z8WFIc2f~NmDK?zwPZ>()K^#nJ@-!QZD-d$ub7K$UA|oTLYZPWYb&cz-8Q>%aHJE!x zMt3EDfipu9w89}Rq2T>T$&N4P6(Dyf%4~>_mN`^)88h)!L%XDRVB@b+D-*kcK+-ch!?Z!f&Z8bR;+0+X%%U^-G18aHMwUD_p)zAh3;nj;DP|Ex_@K1A`nC$dV{N#oCtzQ zPA7XxD>&0)QwJ&n1IH%ak?q!)&zXA)yf}y~EgL(#L`PLsRnR>Pqk=Bbi3Uh1{q(%f z9h-@&p0aTai@}Q*?D7QqxDQ$eLlhZZd4h6wQ4fnbd`|$F8aF13^d&^s-@-Ygo@Lnh zIlrAh(^qT7!5d;xlq!wA6W8gre)qZ8;n2UXZ4AQR-~OJp=Eeo|?`DH>Oz=I6_?x#R zIs(Xh_T!j0-XS~NmwgYnz8tG<^o__9%>Su%BB@8R!xg)XrC$U{?sX42VQ#W$6zC-O zV`nD%iyp2{5tm~$3`Z>fWfIA^8 z4|fQcD$O1{vW#NNoL=>&0mOsS4sjW3EE5P%oX-fBd|~=a)}nvR`1~npV>}>xj?s2} zI!o;N0;#0_Dr83P9aR{swpy%K%A0aHB0?4E2Kt;v`_3lVlbGqifnOlue%(6iUZz&ZD*_tJ$EeYMP?LE2#Y0;#LD{k; z6_e9Sun;LYKCaeZ>LWLp+GWRADQ6ECRde8wGK_g|l3#-nB5{k<<9T|!!pKQ);x)3+ zpZfdO3jF8_c^sde{1a`4tFiUv5 zS>;UE{0^ISMlgtT+5mUX1t&x^tE;bMqvskzP{p1~4mQInv4#@V;kVx7aXtDNDTW}P zPBpAVL~_>?^|Jfxyw=k|1D3QJxb&Xq;dAWkGAkne48RS#W%6P_?0A`x)|`4VqL~ds z;7_|Wpf&WZBHhNTf*o27A3#ke zlZ~U}buN)=Z4M5(1dXV#vmIC4tibR4>GtAQg`eWeIikK|USNezqVW4cRZwW~qQ*Q| zlvR#^^sB(Zb`zm&rnAgCqIL6ufQ_R!t2*?;v*9UM3Qu={aCM06w7ZkRh@Sq%br*e? zW`XCgtk1Il%TpK_52J6zVULUeVTw@LDb-EClV1=j)_72L)rEV1Ra^x)A6*7_L)26S zBltq)NhYTxOM3-`)s9yd_89rGd{IBSj*SueigdK3i#$q4j{tFJQ5@4!*la`9`Y7ydL#e-AQsDujTRRJM2xD6%@OZ zp)D->zz5MPJAE`QkZh)e7)t@{*7&>@A$?jUz9#lY5Bln}@s4eHh*2i*~+Y?959lsxOtQUxlj9m03^ad0B z_?))3pp3@EjC=afbNk%SxTYHd z%$y;ycYK+c-!bi}#+Z zIx}VxkZzZ?bJ316)(NJaj1 zlo_W5&1`=ElXG9}u-T}-LV#qLA{G4RR3P7-2nGF~P25Gc>q8IuF@)YWq!x>D!nc3g z;^V%UTbP=fN~Cxd*U?gK5_#X|TGx-qJyyy>eek42)jf9`@36_I$q=dK~m3B`>pJiE&-)TOkIu`<76M>@R z1#zbhASis+)fR`j<~{9+Eq^o4&SD%qoALtkLgR)(@eq7`Q;sy*R#ICo*M*r8mFo)c;s1kW#I5d!F(J&wVes!o+Af$f3QP`z%G3-$q zXY@#tUG8m09HY9y6GJB2k-F-oC@%Tet;eBhh48OqRd#Q_m}k0DLo9jziy(5=V$(1H zl5u&{#vrKkJqPnkfM+P+xYC}z$HHU$^D4k9Qw`-q*r~as+a$*-mAoh3$9F_u%l^>r zQ86sl3!D~l_(SAYKh@$ps&WaWq`JXzz+PEh2g^VL)WWa?<~ubJ%D^sGV(_&q=S|-) z4>N09dalKg1m%jVm$TwKOJaf-G=o~-qWplParLq$X>C-O?%gh};4P1P#u5Z;34(tI z@~P~UoT993Kam8OG{{Zn#++G`>jEWc)M}%HX_8$g!V6nz1JdR%j$$6M=8LzSwe|Tzf8MxlZ}}_8$Ba;cP}x^TR3njQFZ0n zGC-*P>9m2vv{*>PqE(WC35*gX_WN6iWFa~NuiP@(;@SgP1ww{&2V{_AhUZ_{1vUtn zi@|LTT;$-i|BH83_0$6Jh{kY^m%CHzk}3fh>v+hz+vgxfqyEY|<{* z{&5=!74-D>-qr;~9V2+R|F|oKM}TFk<)r}z@Y#K|pf_TFoYHW|X%`gA$}<5Hl1f`$ LPpw?lGU(p`Tu