From 226e042eec27fed7d95e3648a07c375e56691aa1 Mon Sep 17 00:00:00 2001 From: azizadx Date: Thu, 1 Feb 2024 04:52:41 +0300 Subject: [PATCH] feat:data_ingestion with google driver --- .gitignore | 5 +- RAG/notebook/10-langchain-multi-query.ipynb | 1022 ----------------- config/config.yaml | 7 + data_ingest/__init__.py | 22 + data_ingest/components/__init__.py | 0 data_ingest/components/data_ingestion.py | 46 + data_ingest/config/__init__.py | 0 data_ingest/config/configuration.py | 31 + data_ingest/constants/__init__.py | 4 + data_ingest/entity/__init__.py | 0 data_ingest/entity/config_entity.py | 10 + data_ingest/pipeline/__init__.py | 0 .../pipeline/stage_01_data_ingestion.py | 31 + data_ingest/utils/__init__.py | 0 data_ingest/utils/common.py | 124 ++ dvc.yaml | 0 main.py | 14 + params.yaml | 1 + requirements.txt | 16 + .../data_pipeline/01_data_ingestion.ipynb | 253 ++++ setup.py | 25 + telegram/frontend/bun.lockb | Bin 0 -> 151270 bytes 22 files changed, 588 insertions(+), 1023 deletions(-) delete mode 100644 RAG/notebook/10-langchain-multi-query.ipynb create mode 100644 config/config.yaml create mode 100644 data_ingest/__init__.py create mode 100644 data_ingest/components/__init__.py create mode 100644 data_ingest/components/data_ingestion.py create mode 100644 data_ingest/config/__init__.py create mode 100644 data_ingest/config/configuration.py create mode 100644 data_ingest/constants/__init__.py create mode 100644 data_ingest/entity/__init__.py create mode 100644 data_ingest/entity/config_entity.py create mode 100644 data_ingest/pipeline/__init__.py create mode 100644 data_ingest/pipeline/stage_01_data_ingestion.py create mode 100644 data_ingest/utils/__init__.py create mode 100644 data_ingest/utils/common.py create mode 100644 dvc.yaml create mode 100644 main.py create mode 100644 params.yaml create mode 100644 requirements.txt create mode 100644 research/data_pipeline/01_data_ingestion.ipynb create mode 100644 setup.py create mode 100755 telegram/frontend/bun.lockb diff --git a/.gitignore b/.gitignore index 0c8d566..43f1a71 100644 --- a/.gitignore +++ b/.gitignore @@ -164,9 +164,12 @@ cython_debug/ data/ +artifacts/ +.virtual_documents + + .DS_Store/**/* ##webapp and chatbot telegram/frontend/node_modules/ telegram/chat-bot/bot_flask - diff --git a/RAG/notebook/10-langchain-multi-query.ipynb b/RAG/notebook/10-langchain-multi-query.ipynb deleted file mode 100644 index ea35247..0000000 --- a/RAG/notebook/10-langchain-multi-query.ipynb +++ /dev/null @@ -1,1022 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/pinecone-io/examples/blob/master/learn/generation/langchain/handbook/10-langchain-multi-query.ipynb) [![Open nbviewer](https://raw.githubusercontent.com/pinecone-io/examples/master/assets/nbviewer-shield.svg)](https://nbviewer.org/github/pinecone-io/examples/blob/master/learn/generation/langchain/handbook/08-langchain-multi-query.ipynb)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "2-XDGL6Oi6h4" - }, - "source": [ - "#### [LangChain Handbook](https://pinecone.io/learn/langchain)\n", - "\n", - "# LangChain Multi-Query for RAG" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "id": "qi8B1fgywJzE", - "tags": [] - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\u001b[33mWARNING: Skipping /usr/local/lib/python3.11/site-packages/platformdirs-4.1.0.dist-info due to invalid metadata entry 'name'\u001b[0m\u001b[33m\n", - "\u001b[0m\u001b[33mWARNING: Skipping /usr/local/lib/python3.11/site-packages/platformdirs-4.1.0.dist-info due to invalid metadata entry 'name'\u001b[0m\u001b[33m\n", - "\u001b[0m\u001b[33mWARNING: Skipping /usr/local/lib/python3.11/site-packages/platformdirs-4.1.0.dist-info due to invalid metadata entry 'name'\u001b[0m\u001b[33m\n", - "\u001b[0m\u001b[33m WARNING: Skipping /usr/local/lib/python3.11/site-packages/platformdirs-4.1.0.dist-info due to invalid metadata entry 'name'\u001b[0m\u001b[33m\n", - "\u001b[0m\u001b[33mWARNING: Skipping /usr/local/lib/python3.11/site-packages/platformdirs-4.1.0.dist-info due to invalid metadata entry 'name'\u001b[0m\u001b[33m\n", - "\u001b[0m\u001b[33mWARNING: Skipping /usr/local/lib/python3.11/site-packages/platformdirs-4.1.0.dist-info due to invalid metadata entry 'name'\u001b[0m\u001b[33m\n", - "\u001b[0m\u001b[33mWARNING: Skipping /usr/local/lib/python3.11/site-packages/platformdirs-4.1.0.dist-info due to invalid metadata entry 'name'\u001b[0m\u001b[33m\n", - "\u001b[0m\u001b[33mWARNING: Skipping /usr/local/lib/python3.11/site-packages/platformdirs-4.1.0.dist-info due to invalid metadata entry 'name'\u001b[0m\u001b[33m\n", - "\u001b[0m\u001b[33mWARNING: Skipping /usr/local/lib/python3.11/site-packages/platformdirs-4.1.0.dist-info due to invalid metadata entry 'name'\u001b[0m\u001b[33m\n", - "\u001b[0m" - ] - } - ], - "source": [ - "!pip install -qU \\\n", - " pinecone-client==3.0.0 \\\n", - " langchain==0.1.1 \\\n", - " langchain-community==0.0.13 \\\n", - " datasets==2.14.6 \\\n", - " openai==1.6.1 \\\n", - " tiktoken==0.5.2" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "CPmfrdJ9_2YA" - }, - "source": [ - "## Getting Data" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "S4Py-rVqx-I0" - }, - "source": [ - "An existing dataset from Hugging Face Datasets." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "iatOGmKgz8NE", - "tags": [] - }, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "38d7ec92a08f42c6b89691e8270f7867", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Downloading data files: 0%| | 0/1 [00:00 dict:\n", - " docs = retriever.get_relevant_documents(query=inputs[\"question\"])\n", - " docs = [d.page_content for d in docs]\n", - " docs_dict = {\n", - " \"query\": inputs[\"question\"],\n", - " \"contexts\": \"\\n---\\n\".join(docs)\n", - " }\n", - " return docs_dict\n", - "\n", - "retrieval_chain = TransformChain(\n", - " input_variables=[\"question\"],\n", - " output_variables=[\"query\", \"contexts\"],\n", - " transform=retrieval_transform\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "SoD45Au1Eg-r" - }, - "source": [ - "Now we chain this with our generation step using the `SequentialChain`:" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": { - "id": "azqCwDwXEkDT" - }, - "outputs": [], - "source": [ - "from langchain.chains import SequentialChain\n", - "\n", - "rag_chain = SequentialChain(\n", - " chains=[retrieval_chain, qa_chain],\n", - " input_variables=[\"question\"], # we need to name differently to output \"query\"\n", - " output_variables=[\"query\", \"contexts\", \"text\"]\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "xpB2aWV4ESzf" - }, - "source": [ - "Then we perform the full RAG pipeline:" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 161 - }, - "id": "JvJbUaLqFRG2", - "outputId": "582caa21-777a-4a01-a618-9db64185ad5e" - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "INFO:langchain.retrievers.multi_query:Generated queries: ['1. What information can you provide about llama 2?', '2. Could you give me some details about llama 2?', '3. I would like to learn more about llama 2. Can you help me with that?']\n" - ] - }, - { - "data": { - "text/plain": [ - "'Llama 2 is a collection of pretrained and fine-tuned large language models (LLMs) ranging in scale from 7 billion to 70 billion parameters. These LLMs, called L/l.sc/a.sc/m.sc/a.sc /two.taboldstyle-C/h.sc/a.sc/t.sc, are optimized for dialogue use cases. They have been shown to outperform open-source chat models on most benchmarks and are considered a suitable substitute for closed-source models based on humane evaluations for helpfulness and safety. The approach to fine-tuning and safety is described in detail in the work.'" - ] - }, - "execution_count": 20, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "out = rag_chain({\"question\": question})\n", - "out[\"text\"]" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "bLmv01geK-ZS" - }, - "source": [ - "---" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "vAZVPhHzLDQQ" - }, - "source": [ - "## Custom Multiquery" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "rI-KVO6zjJZw" - }, - "source": [ - "We'll try this with two prompts, both encourage more variety in search queries.\n", - "\n", - "**Prompt A**\n", - "```\n", - "Your task is to generate 3 different search queries that aim to\n", - "answer the user question from multiple perspectives.\n", - "Each query MUST tackle the question from a different viewpoint,\n", - "we want to get a variety of RELEVANT search results.\n", - "Provide these alternative questions separated by newlines.\n", - "Original question: {question}\n", - "```\n", - "\n", - "\n", - "**Prompt B**\n", - "```\n", - "Your task is to generate 3 different search queries that aim to\n", - "answer the user question from multiple perspectives. The user questions\n", - "are focused on Large Language Models, Machine Learning, and related\n", - "disciplines.\n", - "Each query MUST tackle the question from a different viewpoint, we\n", - "want to get a variety of RELEVANT search results.\n", - "Provide these alternative questions separated by newlines.\n", - "Original question: {question}\n", - "```" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": { - "id": "4IlEnYeKLFzh" - }, - "outputs": [], - "source": [ - "from typing import List\n", - "from langchain.chains import LLMChain\n", - "from pydantic import BaseModel, Field\n", - "from langchain.prompts import PromptTemplate\n", - "from langchain.output_parsers import PydanticOutputParser\n", - "\n", - "\n", - "# Output parser will split the LLM result into a list of queries\n", - "class LineList(BaseModel):\n", - " # \"lines\" is the key (attribute name) of the parsed output\n", - " lines: List[str] = Field(description=\"Lines of text\")\n", - "\n", - "\n", - "class LineListOutputParser(PydanticOutputParser):\n", - " def __init__(self) -> None:\n", - " super().__init__(pydantic_object=LineList)\n", - "\n", - " def parse(self, text: str) -> LineList:\n", - " lines = text.strip().split(\"\\n\")\n", - " return LineList(lines=lines)\n", - "\n", - "\n", - "output_parser = LineListOutputParser()\n", - "\n", - "template = \"\"\"\n", - "Your task is to generate 3 different search queries that aim to\n", - "answer the user question from multiple perspectives. The user questions\n", - "are focused on Large Language Models, Machine Learning, and related\n", - "disciplines.\n", - "Each query MUST tackle the question from a different viewpoint, we\n", - "want to get a variety of RELEVANT search results.\n", - "Provide these alternative questions separated by newlines.\n", - "Original question: {question}\n", - "\"\"\"\n", - "\n", - "QUERY_PROMPT = PromptTemplate(\n", - " input_variables=[\"question\"],\n", - " template=template,\n", - ")\n", - "llm = ChatOpenAI(temperature=0, openai_api_key=OPENAI_API_KEY)\n", - "\n", - "# Chain\n", - "llm_chain = LLMChain(llm=llm, prompt=QUERY_PROMPT, output_parser=output_parser)" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "0CgduNJWLBez", - "outputId": "7ffee6c2-27b4-4bdf-8c79-7effd27e3cd4" - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "INFO:langchain.retrievers.multi_query:Generated queries: ['1. What are the key features and capabilities of Large Language Model Llama 2?', '2. How does Llama 2 compare to other Large Language Models in terms of performance and efficiency?', '3. What are the applications and use cases of Llama 2 in the field of Machine Learning and Natural Language Processing?']\n" - ] - }, - { - "data": { - "text/plain": [ - "7" - ] - }, - "execution_count": 22, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Run\n", - "retriever = MultiQueryRetriever(\n", - " retriever=vectorstore.as_retriever(), llm_chain=llm_chain, parser_key=\"lines\"\n", - ") # \"lines\" is the key (attribute name) of the parsed output\n", - "\n", - "# Results\n", - "docs = retriever.get_relevant_documents(\n", - " query=question\n", - ")\n", - "len(docs)" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "PSySsaDKMK1i", - "outputId": "e6f95abd-99fc-4576-d1f4-5fd4c21c70ab" - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[Document(page_content='Alan Schelten Ruan Silva Eric Michael Smith Ranjan Subramanian Xiaoqing Ellen Tan Binh Tang\\nRoss Taylor Adina Williams Jian Xiang Kuan Puxin Xu Zheng Yan Iliyan Zarov Yuchen Zhang\\nAngela Fan Melanie Kambadur Sharan Narang Aurelien Rodriguez Robert Stojnic\\nSergey Edunov Thomas Scialom\\x03\\nGenAI, Meta\\nAbstract\\nIn this work, we develop and release Llama 2, a collection of pretrained and fine-tuned\\nlarge language models (LLMs) ranging in scale from 7 billion to 70 billion parameters.\\nOur fine-tuned LLMs, called L/l.sc/a.sc/m.sc/a.sc /two.taboldstyle-C/h.sc/a.sc/t.sc , are optimized for dialogue use cases. Our\\nmodels outperform open-source chat models on most benchmarks we tested, and based on\\nourhumanevaluationsforhelpfulnessandsafety,maybeasuitablesubstituteforclosedsource models. We provide a detailed description of our approach to fine-tuning and safety', metadata={'chunk-id': '1', 'id': '2307.09288', 'source': 'http://arxiv.org/pdf/2307.09288', 'title': 'Llama 2: Open Foundation and Fine-Tuned Chat Models'}),\n", - " Document(page_content='2\\n3.4.3 Even programmatic measures of model capability can be highly subjective . . . . . . . 15\\n3.5 Even large language models are brittle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15\\n3.6 Social bias in large language models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17\\n3.7 Performance on non-English languages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20\\n4 Behavior on selected tasks 21\\n4.1 Checkmate-in-one task . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22\\n4.2 Periodic elements task . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23\\n5 Additional related work 24\\n6 Discussion 25', metadata={'chunk-id': '14', 'id': '2206.04615', 'source': 'http://arxiv.org/pdf/2206.04615', 'title': 'Beyond the Imitation Game: Quantifying and extrapolating the capabilities of language models'}),\n", - " Document(page_content='challenges described above) about how the development of large language models has unfolded thus far, including a\\nquantitative analysis of the increasing gap between academia and industry for large model development.\\nFinally, in Section 4 we outline policy interventions that may help concretely address the challenges we outline in\\nSections 2 and 3 in order to help guide the development and deployment of larger models for the broader social good.\\nWe leave some illustrative experiments, technical details, and caveats about our claims in Appendix A.\\n2 DISTINGUISHING FEATURES OF LARGE GENERATIVE MODELS\\nWe claim that large generative models (e.g., GPT-3 [ 11], LaMDA [ 78], Gopher [ 62], etc.) are distinguished by four\\nfeatures:\\n•Smooth, general capability scaling : It is possible to predictably improve the general performance of generative\\nmodels — their loss on capturing a specific, though very broad, data distribution — by scaling up the size of the\\nmodels, the compute used to train them, and the amount of data they’re trained on in the correct proportions.\\nThese proportions can be accurately predicted by scaling laws (Figure 1). We believe that these scaling laws\\nde-risk investments in building larger and generally more capable models despite the high resource costs and the\\ndifficulty of predicting precisely how well a model will perform on a specific task. Note, the harmful properties', metadata={'chunk-id': '9', 'id': '2202.07785', 'source': 'http://arxiv.org/pdf/2202.07785', 'title': 'Predictability and Surprise in Large Generative Models'}),\n", - " Document(page_content='asChatGPT,BARD,andClaude. TheseclosedproductLLMsareheavilyfine-tunedtoalignwithhuman\\npreferences, which greatly enhances their usability and safety. This step can require significant costs in\\ncomputeandhumanannotation,andisoftennottransparentoreasilyreproducible,limitingprogresswithin\\nthe community to advance AI alignment research.\\nIn this work, we develop and release Llama 2, a family of pretrained and fine-tuned LLMs, L/l.sc/a.sc/m.sc/a.sc /two.taboldstyle and\\nL/l.sc/a.sc/m.sc/a.sc /two.taboldstyle-C/h.sc/a.sc/t.sc , at scales up to 70B parameters. On the series of helpfulness and safety benchmarks we tested,\\nL/l.sc/a.sc/m.sc/a.sc /two.taboldstyle-C/h.sc/a.sc/t.sc models generally perform better than existing open-source models. They also appear to\\nbe on par with some of the closed-source models, at least on the human evaluations we performed (see', metadata={'chunk-id': '9', 'id': '2307.09288', 'source': 'http://arxiv.org/pdf/2307.09288', 'title': 'Llama 2: Open Foundation and Fine-Tuned Chat Models'}),\n", - " Document(page_content='but BoolQ. Similarly, this model surpasses PaLM540B everywhere but on BoolQ and WinoGrande.\\nLLaMA-13B model also outperforms GPT-3 on\\nmost benchmarks despite being 10 \\x02smaller.\\n3.2 Closed-book Question Answering\\nWe compare LLaMA to existing large language\\nmodels on two closed-book question answering\\nbenchmarks: Natural Questions (Kwiatkowski\\net al., 2019) and TriviaQA (Joshi et al., 2017). For\\nboth benchmarks, we report exact match performance in a closed book setting, i.e., where the models do not have access to documents that contain\\nevidence to answer the question. In Table 4, we\\nreport performance on NaturalQuestions, and in Table 5, we report on TriviaQA. On both benchmarks,\\nLLaMA-65B achieve state-of-the-arts performance\\nin the zero-shot and few-shot settings. More importantly, the LLaMA-13B is also competitive on\\nthese benchmarks with GPT-3 and Chinchilla, despite being 5-10 \\x02smaller. This model runs on a\\nsingle V100 GPU during inference.\\n0-shot 1-shot 5-shot 64-shot\\nGopher 280B 43.5 - 57.0 57.2', metadata={'chunk-id': '17', 'id': '2302.13971', 'source': 'http://arxiv.org/pdf/2302.13971', 'title': 'LLaMA: Open and Efficient Foundation Language Models'}),\n", - " Document(page_content='5 Discussion 19\\n6 Conclusion 21\\n1 Introduction: motivation for the survey and definitions\\n1.1 Motivation\\nLarge Language Models (LLMs) ( Devlin et al. ,2019;Brown et al. ,2020;Chowdhery et al. ,2022) have fueled dramatic progress in Natural Language Processing (NLP ) and are already core in several products with\\nmillions of users, such as the coding assistant Copilot ( Chen et al. ,2021), Google search engine1or more recently ChatGPT2. Memorization ( Tirumala et al. ,2022) combined with compositionality ( Zhou et al. ,2022)\\ncapabilities made LLMs able to execute various tasks such as language understanding or conditional and unconditional text generation at an unprecedented level of pe rformance, thus opening a realistic path towards\\nhigher-bandwidth human-computer interactions.\\nHowever, LLMs suffer from important limitations hindering a broader deployment. LLMs often provide nonfactual but seemingly plausible predictions, often referr ed to as hallucinations ( Welleck et al. ,2020). This\\nleads to many avoidable mistakes, for example in the context of arithmetics ( Qian et al. ,2022) or within\\na reasoning chain ( Wei et al. ,2022c ). Moreover, many LLMs groundbreaking capabilities seem to emerge', metadata={'chunk-id': '5', 'id': '2302.07842', 'source': 'http://arxiv.org/pdf/2302.07842', 'title': 'Augmented Language Models: a Survey'}),\n", - " Document(page_content='practicable options for academic research since they were acquired by Appen, a company that is\\nfocused on a business market.\\nThis paper explores the potential of large language models (LLMs) for text annotation tasks, with a\\nfocus on ChatGPT, which was released in November 2022. It demonstrates that zero-shot ChatGPT\\nclassifications (that is, without any additional training) outperform MTurk annotations, at a fraction\\nof the cost. LLMs have been shown to perform very well for a wide range of purposes, including\\nideological scaling (Wu et al., 2023), the classification of legislative proposals (Nay, 2023), the\\nresolution of cognitive psychology tasks (Binz and Schulz, 2023), and the simulation of human\\nsamples for survey research (Argyle et al., 2023). While a few studies suggested that ChatGPT\\nmight perform text annotation tasks of the kinds we have described (Kuzman, Mozeti ˇc and Ljubeši ´c,\\n2023; Huang, Kwak and An, 2023), to the best of our knowledge our work is the first systematic\\nevaluation. Our analysis relies on a sample of 6,183 documents, including tweets and news articles', metadata={'chunk-id': '3', 'id': '2303.15056', 'source': 'http://arxiv.org/pdf/2303.15056', 'title': 'ChatGPT Outperforms Crowd-Workers for Text-Annotation Tasks'})]" - ] - }, - "execution_count": 23, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "docs" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "F4q65OEiizU2" - }, - "source": [ - "Putting this together in another `SequentialChain`:" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": { - "id": "LTRjTIKzi2-g" - }, - "outputs": [], - "source": [ - "retrieval_chain = TransformChain(\n", - " input_variables=[\"question\"],\n", - " output_variables=[\"query\", \"contexts\"],\n", - " transform=retrieval_transform\n", - ")\n", - "\n", - "rag_chain = SequentialChain(\n", - " chains=[retrieval_chain, qa_chain],\n", - " input_variables=[\"question\"], # we need to name differently to output \"query\"\n", - " output_variables=[\"query\", \"contexts\", \"text\"]\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "Rda74xhpjE6A" - }, - "source": [ - "And asking again:" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "metadata": { - "id": "9UcBY71cjGgX" - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "INFO:langchain.retrievers.multi_query:Generated queries: ['1. What are the key features and capabilities of Large Language Model Llama 2?', '2. How does Llama 2 compare to other Large Language Models in terms of performance and efficiency?', '3. What are the applications and use cases of Llama 2 in the field of Machine Learning and Natural Language Processing?']\n" - ] - }, - { - "data": { - "text/plain": [ - "'Llama 2 is a collection of pretrained and fine-tuned large language models (LLMs) ranging in scale from 7 billion to 70 billion parameters. These models, called L/l.sc/a.sc/m.sc/a.sc /two.taboldstyle-C/h.sc/a.sc/t.sc, are optimized for dialogue use cases and have been shown to outperform open-source chat models on most benchmarks. They are considered as a suitable substitute for closed-source models in terms of helpfulness and safety. The development of Llama 2 addresses challenges such as programmatic measures of model capability, brittleness of large language models, social bias, and performance on non-English languages.'" - ] - }, - "execution_count": 25, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "out = rag_chain({\"question\": question})\n", - "out[\"text\"]" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "8jULksgk7gLA" - }, - "source": [ - "After finishing, delete your Pinecone index to save resources:" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "metadata": {}, - "outputs": [], - "source": [ - "pc.delete_index(index_name)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "---" - ] - } - ], - "metadata": { - "colab": { - "provenance": [] - }, - "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.11.5" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/config/config.yaml b/config/config.yaml new file mode 100644 index 0000000..116b256 --- /dev/null +++ b/config/config.yaml @@ -0,0 +1,7 @@ +artifacts_root: artifacts + +data_ingestion: + root_dir: artifacts/data_ingestion + source_URL: https://drive.google.com/file/d/1F7mxKqGxTn_y_IJT_o03Ub4DQr04buSB/view?usp=sharing + local_data_file: artifacts/data_ingestion/data.zip + unzip_dir: artifacts/data_ingestion diff --git a/data_ingest/__init__.py b/data_ingest/__init__.py new file mode 100644 index 0000000..addb1d3 --- /dev/null +++ b/data_ingest/__init__.py @@ -0,0 +1,22 @@ +import os +import sys +import logging + +logging_str = "[%(asctime)s: %(levelname)s: %(module)s: %(message)s]" + +log_dir = "../logs" +log_filepath = os.path.join(log_dir,"running_logs.log") +os.makedirs(log_dir, exist_ok=True) + + +logging.basicConfig( + level= logging.INFO, + format= logging_str, + + handlers=[ + logging.FileHandler(log_filepath), + logging.StreamHandler(sys.stdout) + ] +) + +logger = logging.getLogger("data_ingestLogger") \ No newline at end of file diff --git a/data_ingest/components/__init__.py b/data_ingest/components/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/data_ingest/components/data_ingestion.py b/data_ingest/components/data_ingestion.py new file mode 100644 index 0000000..862e3de --- /dev/null +++ b/data_ingest/components/data_ingestion.py @@ -0,0 +1,46 @@ +# ADD the code from the jupyter notebook to here +import os +import zipfile +import gdown +from data_ingest import logger +from data_ingest.utils.common import get_size +from data_ingest.entity.config_entity import DataIngestionConfig + +class DataIngestion: + def __init__(self, config: DataIngestionConfig): + self.config = config + + + + + def download_file(self)-> str: + ''' + Fetch data from the url + ''' + + try: + dataset_url = self.config.source_URL + zip_download_dir = self.config.local_data_file + os.makedirs("artifacts/data_ingestion", exist_ok=True) + logger.info(f"Downloading data from {dataset_url} into file {zip_download_dir}") + + file_id = dataset_url.split("/")[-2] + prefix = 'https://drive.google.com/uc?/export=download&id=' + gdown.download(prefix+file_id,zip_download_dir) + + logger.info(f"Downloaded data from {dataset_url} into file {zip_download_dir}") + + except Exception as e: + raise e + + + def extract_zip_file(self): + """ + zip_file_path: str + Extracts the zip file into the data directory + Function returns None + """ + unzip_path = self.config.unzip_dir + os.makedirs(unzip_path, exist_ok=True) + with zipfile.ZipFile(self.config.local_data_file, 'r') as zip_ref: + zip_ref.extractall(unzip_path) \ No newline at end of file diff --git a/data_ingest/config/__init__.py b/data_ingest/config/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/data_ingest/config/configuration.py b/data_ingest/config/configuration.py new file mode 100644 index 0000000..b39bd69 --- /dev/null +++ b/data_ingest/config/configuration.py @@ -0,0 +1,31 @@ +from data_ingest.constants import * +from data_ingest.utils.common import read_yaml, create_directories +from data_ingest.entity.config_entity import (DataIngestionConfig) + + +class ConfigurationManager: + def __init__( + self, + config_filepath = CONFIG_FILE_PATH, + params_filepath = PARAMS_FILE_PATH): + + self.config = read_yaml(config_filepath) + self.params = read_yaml(params_filepath) + + create_directories([self.config.artifacts_root]) + + + + def get_data_ingestion_config(self) -> DataIngestionConfig: + config = self.config.data_ingestion + + create_directories([config.root_dir]) + + data_ingestion_config = DataIngestionConfig( + root_dir=config.root_dir, + source_URL=config.source_URL, + local_data_file=config.local_data_file, + unzip_dir=config.unzip_dir + ) + + return data_ingestion_config diff --git a/data_ingest/constants/__init__.py b/data_ingest/constants/__init__.py new file mode 100644 index 0000000..de2d074 --- /dev/null +++ b/data_ingest/constants/__init__.py @@ -0,0 +1,4 @@ +from pathlib import Path + +CONFIG_FILE_PATH = Path("config/config.yaml") +PARAMS_FILE_PATH = Path("params.yaml") \ No newline at end of file diff --git a/data_ingest/entity/__init__.py b/data_ingest/entity/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/data_ingest/entity/config_entity.py b/data_ingest/entity/config_entity.py new file mode 100644 index 0000000..cc4fe72 --- /dev/null +++ b/data_ingest/entity/config_entity.py @@ -0,0 +1,10 @@ +from dataclasses import dataclass +from pathlib import Path + + +@dataclass(frozen=True) +class DataIngestionConfig: + root_dir: Path + source_URL: str + local_data_file: Path + unzip_dir: Path \ No newline at end of file diff --git a/data_ingest/pipeline/__init__.py b/data_ingest/pipeline/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/data_ingest/pipeline/stage_01_data_ingestion.py b/data_ingest/pipeline/stage_01_data_ingestion.py new file mode 100644 index 0000000..7275ad6 --- /dev/null +++ b/data_ingest/pipeline/stage_01_data_ingestion.py @@ -0,0 +1,31 @@ +from data_ingest.config.configuration import ConfigurationManager +from data_ingest.components.data_ingestion import DataIngestion +from data_ingest import logger + + + +STAGE_NAME = "Data Ingestion stage" + +class DataIngestionTrainingPipeline: + def __init__(self): + pass + + def main(self): + config = ConfigurationManager() + data_ingestion_config = config.get_data_ingestion_config() + data_ingestion = DataIngestion(config=data_ingestion_config) + data_ingestion.download_file() + data_ingestion.extract_zip_file() + + + + +if __name__ == '__main__': + try: + logger.info(f">>>>>> stage {STAGE_NAME} started <<<<<<") + obj = DataIngestionTrainingPipeline() + obj.main() + logger.info(f">>>>>> stage {STAGE_NAME} completed <<<<<<\n\nx==========x") + except Exception as e: + logger.exception(e) + raise e \ No newline at end of file diff --git a/data_ingest/utils/__init__.py b/data_ingest/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/data_ingest/utils/common.py b/data_ingest/utils/common.py new file mode 100644 index 0000000..8061f8c --- /dev/null +++ b/data_ingest/utils/common.py @@ -0,0 +1,124 @@ +import os +from box.exceptions import BoxValueError +import yaml +from data_ingest import logger +import json +import joblib +from ensure import ensure_annotations +from box import ConfigBox +from pathlib import Path +from typing import Any +import base64 + + + +@ensure_annotations +def read_yaml(path_to_yaml: Path) -> ConfigBox: + """reads yaml file and returns + + Args: + path_to_yaml (str): path like input + + Raises: + ValueError: if yaml file is empty + e: empty file + + Returns: + ConfigBox: ConfigBox type + """ + try: + with open(path_to_yaml) as yaml_file: + content = yaml.safe_load(yaml_file) + logger.info(f"yaml file: {path_to_yaml} loaded successfully") + return ConfigBox(content) + except BoxValueError: + raise ValueError("yaml file is empty") + except Exception as e: + raise e + + + +@ensure_annotations +def create_directories(path_to_directories: list, verbose=True): + """create list of directories + + Args: + path_to_directories (list): list of path of directories + ignore_log (bool, optional): ignore if multiple dirs is to be created. Defaults to False. + """ + for path in path_to_directories: + os.makedirs(path, exist_ok=True) + if verbose: + logger.info(f"created directory at: {path}") + +@ensure_annotations +def save_json(path: Path, data: dict): + """save json data + + Args: + path (Path): path to json file + data (dict): data to be saved in json file + """ + with open(path, "w") as f: + json.dump(data, f, indent=4) + + logger.info(f"json file saved at: {path}") + + + + +@ensure_annotations +def load_json(path: Path) -> ConfigBox: + """load json files data + + Args: + path (Path): path to json file + + Returns: + ConfigBox: data as class attributes instead of dict + """ + with open(path) as f: + content = json.load(f) + + logger.info(f"json file loaded succesfully from: {path}") + return ConfigBox(content) + + +@ensure_annotations +def save_bin(data: Any, path: Path): + """save binary file + + Args: + data (Any): data to be saved as binary + path (Path): path to binary file + """ + joblib.dump(value=data, filename=path) + logger.info(f"binary file saved at: {path}") + + +@ensure_annotations +def load_bin(path: Path) -> Any: + """load binary data + + Args: + path (Path): path to binary file + + Returns: + Any: object stored in the file + """ + data = joblib.load(path) + logger.info(f"binary file loaded from: {path}") + return data + +@ensure_annotations +def get_size(path: Path) -> str: + """get size in KB + + Args: + path (Path): path of the file + + Returns: + str: size in KB + """ + size_in_kb = round(os.path.getsize(path)/1024) + return f"~ {size_in_kb} KB" \ No newline at end of file diff --git a/dvc.yaml b/dvc.yaml new file mode 100644 index 0000000..e69de29 diff --git a/main.py b/main.py new file mode 100644 index 0000000..b86440b --- /dev/null +++ b/main.py @@ -0,0 +1,14 @@ +from data_ingest import logger +from data_ingest.pipeline.stage_01_data_ingestion import DataIngestionTrainingPipeline + +STAGE_NAME = "Data Ingestion stage" + + +try: + logger.info(f">>>>>> stage {STAGE_NAME} started <<<<<<") + obj = DataIngestionTrainingPipeline() + obj.main() + logger.info(f">>>>>> stage {STAGE_NAME} completed <<<<<<\n\nx==========x") +except Exception as e: + logger.exception(e) + raise e \ No newline at end of file diff --git a/params.yaml b/params.yaml new file mode 100644 index 0000000..621e088 --- /dev/null +++ b/params.yaml @@ -0,0 +1 @@ +key: val \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..3e94a7f --- /dev/null +++ b/requirements.txt @@ -0,0 +1,16 @@ +pandas +gdown +dvc +notebook +mlflow==2.2.2 +numpy +matplotlib +seaborn +python-box==6.0.2 +pyYAML +tqdm +ensure==1.0.2 +joblib +types-PyYAML +scipy +-e . \ No newline at end of file diff --git a/research/data_pipeline/01_data_ingestion.ipynb b/research/data_pipeline/01_data_ingestion.ipynb new file mode 100644 index 0000000..4c97721 --- /dev/null +++ b/research/data_pipeline/01_data_ingestion.ipynb @@ -0,0 +1,253 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import os" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'/Users/azizamed/Downloads/week7/AmharicAI-AdGen/research/data_pipeline'" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%pwd" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "os.chdir('../../')" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'/Users/azizamed/Downloads/week7/AmharicAI-AdGen'" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%pwd" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "from dataclasses import dataclass\n", + "from pathlib import Path\n", + "\n", + "\n", + "@dataclass(frozen=True)\n", + "class DataIngestionConfig:\n", + " root_dir: Path\n", + " source_URL: str\n", + " local_data_file: Path\n", + " unzip_dir: Path" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "from data_ingest.constants import *\n", + "from data_ingest.utils.common import read_yaml, create_directories" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [], + "source": [ + "class ConfigurationManager:\n", + " def __init__(\n", + " self,\n", + " config_filepath = CONFIG_FILE_PATH,\n", + " params_filepath = PARAMS_FILE_PATH):\n", + "\n", + " self.config = read_yaml(config_filepath)\n", + " self.params = read_yaml(params_filepath)\n", + "\n", + " create_directories([self.config.artifacts_root])\n", + "\n", + "\n", + "\n", + " def get_data_ingestion_config(self) -> DataIngestionConfig:\n", + " config = self.config.data_ingestion\n", + "\n", + " create_directories([config.root_dir])\n", + "\n", + " data_ingestion_config = DataIngestionConfig(\n", + " root_dir=config.root_dir,\n", + " source_URL=config.source_URL,\n", + " local_data_file=config.local_data_file,\n", + " unzip_dir=config.unzip_dir\n", + " )\n", + "\n", + " return data_ingestion_config" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import zipfile\n", + "import gdown\n", + "from data_ingest import logger\n", + "from data_ingest.utils.common import get_size" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [], + "source": [ + "class DataIngestion:\n", + " def __init__(self, config: DataIngestionConfig):\n", + " self.config = config\n", + "\n", + " def download_file(self)-> str:\n", + " '''\n", + " Fetch data from the url\n", + " '''\n", + "\n", + " try:\n", + " dataset_url = self.config.source_URL\n", + " zip_download_dir = self.config.local_data_file\n", + " os.makedirs(\"artifacts/data_ingestion\", exist_ok=True)\n", + " logger.info(f\"Downloading data from {dataset_url} into file {zip_download_dir}\")\n", + "\n", + " file_id = dataset_url.split(\"/\")[-2]\n", + " prefix = 'https://drive.google.com/uc?/export=download&id='\n", + " gdown.download(prefix+file_id,zip_download_dir)\n", + "\n", + " logger.info(f\"Downloaded data from {dataset_url} into file {zip_download_dir}\")\n", + "\n", + " except Exception as e:\n", + " raise e\n", + "\n", + "\n", + " def extract_zip_file(self):\n", + " \"\"\"\n", + " zip_file_path: str\n", + " Extracts the zip file into the data directory\n", + " Function returns None\n", + " \"\"\"\n", + " unzip_path = self.config.unzip_dir\n", + " os.makedirs(unzip_path, exist_ok=True)\n", + " with zipfile.ZipFile(self.config.local_data_file, 'r') as zip_ref:\n", + " zip_ref.extractall(unzip_path)" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[2024-02-01 04:43:42,359: INFO: common: yaml file: config/config.yaml loaded successfully]\n", + "[2024-02-01 04:43:42,362: INFO: common: yaml file: params.yaml loaded successfully]\n", + "[2024-02-01 04:43:42,363: INFO: common: created directory at: artifacts]\n", + "[2024-02-01 04:43:42,364: INFO: common: created directory at: artifacts/data_ingestion]\n", + "[2024-02-01 04:43:42,365: INFO: 1758446011: Downloading data from https://drive.google.com/file/d/1F7mxKqGxTn_y_IJT_o03Ub4DQr04buSB/view?usp=sharing into file artifacts/data_ingestion/data.zip]\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Downloading...\n", + "From: https://drive.google.com/uc?/export=download&id=1F7mxKqGxTn_y_IJT_o03Ub4DQr04buSB\n", + "To: /Users/azizamed/Downloads/week7/AmharicAI-AdGen/artifacts/data_ingestion/data.zip\n", + "100%|██████████| 28.6k/28.6k [00:00<00:00, 147kB/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[2024-02-01 04:43:45,999: INFO: 1758446011: Downloaded data from https://drive.google.com/file/d/1F7mxKqGxTn_y_IJT_o03Ub4DQr04buSB/view?usp=sharing into file artifacts/data_ingestion/data.zip]\n" + ] + } + ], + "source": [ + "try:\n", + " config = ConfigurationManager()\n", + " data_ingestion_config = config.get_data_ingestion_config()\n", + " data_ingestion = DataIngestion(config=data_ingestion_config)\n", + " data_ingestion.download_file()\n", + " data_ingestion.extract_zip_file()\n", + "except Exception as e:\n", + " raise e" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "data_ingest", + "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.11.5" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..b9a3941 --- /dev/null +++ b/setup.py @@ -0,0 +1,25 @@ +import setuptools + + +__version__ = "0.0.1" + +REPO_NAME = "AmharicAI-AdGen" +AUTHOR_USER_NAME = "azizadx" +SRC_REPO = "AmharicAI-AdGen" +AUTHOR_EMAIL = "craft@azizadx.me" + + +setuptools.setup( + name=SRC_REPO, + version=__version__, + author=AUTHOR_USER_NAME, + author_email=AUTHOR_EMAIL, + description="The project centers on an Amharic RAG pipeline, leveraging robust AI for text manipulation. It aims to craft compelling Amharic text ads by analyzing campaign data, incorporating brand specifics, product details, and Telegram channel content history. ", + # long_description='Redash LLM Chatbot: AI-powered Analytics & Insights Unlock the power of your Redash dashboards and databases with natural language queries and automated insights.', + url=f"https://github.com/{AUTHOR_USER_NAME}/{REPO_NAME}", + project_urls={ + "Bug Tracker": f"https://github.com/{AUTHOR_USER_NAME}/{REPO_NAME}/issues", + }, + package_dir={"": "data_ingest"}, + packages=setuptools.find_packages(where="data_ingest") +) \ No newline at end of file diff --git a/telegram/frontend/bun.lockb b/telegram/frontend/bun.lockb new file mode 100755 index 0000000000000000000000000000000000000000..e0211a2fb3f1510ae5ae4a71c1e5867e40f89541 GIT binary patch literal 151270 zcmeEvc|28X`~JpORA?X}$&knt8WbXAj!Yp@=6T2zg;Z#yd7zR88c3O&i4syY7!s96 zV=4_a=y%`te$H9%`J7W*=ly-Y|Gf97)wQ4Dy6*cK*R$5%rz0t@6c!S!19)ZFB&Y=q7(?_t=XtYBWOHQAkb@8d+K+}>%4N1#1D$Qq3 z@ZxwG?|Nl)NsMmlVl%8oqpe{Z1R56u{=isfnqxJy0xi@%By^>_3#}PSM$l-nm4M>_ zuL6z)3<+}$b`Ei;33JeB{E!av4t53(&3_d`svq*PUZ|IQfVW2^t(BSX0_1^wZon~s zo_>KY$f)LI)c5xe@D6eg37I;KM&pL^Q;?6?0%<-#mEklRFJKxo{}!Z2L;5Np>J~xM zu>NL1jN1hgh_;X(1=tH|LBKXZj8BA#%}@#Xa*&Djf2H$ReWK?IPB1>AOX?B)YdnOv z9omEKh=U+7u1F@X^zwG~g8uOiagT5Z90}ss56yrWZ;*4Smx8Z*Bn|o#niAU%1C8wy z1Ti7NZ%|nTa1Ep}|23oq0E68_0{z0>Y4>3e#2{S>i0!@vi1B+lhXk$+03R^u=qHq^ zn+ItucMS<~4{@c@JRl#_L4hHmkVm@;lL6~1Lq6&SI0poJyU}P?kjD8F>Fn=^zHx+_Keh^L`uyK&ac_t0z*gq4P^>~^5%n1xVmtbdCn1(b7Xgu=0 z08#HEAo?SIeY``xQP(>}VQ>nb5@yu@0t*23-vMHMfA?TdcNH3qlUd)*FC5*`UV|>i+R+o>=EJ~?j8^t6725m z=H?w7w0aUFUQHMj7>Zcp*Et{(*1M~hbFk;2P6Oy*9Ooc~?OQ*Yfi-~G&nF-s;|E>W zQ26X8&WMXH!N`w*G?oXrM_@7Sfh3IvT^M@_5V|V%2q1Jx>?US@Fd)t!J7&HXAl8!u z#BmV-gdvRW2Yqbcn5m3@B=h18 z?*M$p`kMg90=h$a07P6R&+t>i#5D?xbQlx;+`|KaLUV^S_LG~tdys;62+b7I7(?_e2)A_DIRU->y+djBs*G|o(80JpXE5Rk_Vy2U z_Mp+oemQX_qdYLc6}JW2%3$Z9Am~r;05A7o@6ZtM01rQJPp{B1P!IjV7BM&h3uiIX z9)8ZDq3&)pE%1Z=;2shd>J9O_hpY&5500e0p3U&<9ugGn4j$y89?mOgHAZ`!T?2!$ zgC|4&D9GP9hmk)D(l{U70$oFcy#w6c++D(O#`?pWM1vXZ=L`6JE~EcopHYBVJe_?Q z>mw}KTfqnF289Jgx(2$r7pgP#4g%tQ{3yqmhYf(RRAMg!!V-&Z(4^5|>BZ(k8t30p zK50C$OCCMZARRipgztEUqICTF^!Qf1H^V8&|#$0bQ%0EKpcN- zK-6&t90|BqkD;doX&iTr1q^-;Ag(XZz#!NS;f@Vy?5Ax|57&98J|i6oXtVaU)~!z^E7%Gmci0Wq%qP!I7Dq_Ll> z05Ohh%yM%;^y3eFTz5yHKDKu;q;Vh6Vxj`Gd>kN-&sV62?R*7@_n8Jjj1TtNV0TaV zh;m4yAMX(7;9%!S+672syUqfR09*%%?GFaTxa_c~_&EkNv#WYEERdDodye~AlYp5VF6-#aAKCnPWcwiKEf0MACZk4eSP){6C3-%h+-2#aHrNqQg=OAYnKX;lQ)WdZ;3^o-p zz$(}iv7OHVr2rMY{xdFej*N8n^Mmkdf8FnKKXr+u(L(&3Lx4(yd+^|a;HEdD-Ijp3 z4o-vqWI$2ykNwRFhyb1xXRv)fFa|iUmjR-_J|MQ+&z~`l zaJX{zb9QrI25Fp^CV)6DHo(VzfoVQiAI@B%kwNY>jX*}e93ak@c~FkJIxweD7s4In z*FhThNtk1U^DF}b#QucjV471-bAq8=-ipIhV&&!H-Cb62Mw&Rkt4}rVtMudSIc8mW zBWUD-g#y7H7OtxoZIOvt^QJRW!+8ARdzKI4-`R!fa(;Gu(eZrK^!L44?I)LAOHBV1 z;bz5K&SSZ$K6{d#@rYHA#70-UDnxqNCcY82H(L-tda0jZ9NWQ=VcVl!_s@-Zdp$bn zU__zc;R_U2aQkS~N=Z z%#=!x3RRWyyR4AX)E>#FcGvE7taq;)x_e~i2Dz>M3;%Z*$|N^G)e zY8|+pEi;2>zl?HvjYwPA=Wivm`)|2hxUE0uUNdcu`GsRX;bD;j4x)xyTevqFKdn8G zTqV51|NO}7*(-I%vgxfps#N4e8D_3_c z_^xm6(vVGt1NrGvQOnH5q$En~x0v^r6Wb~29H)qh-nFe8o!*O_TJt3P zbpg$+G|#&Jvde+#fi=lH1fyrpA6Y=lsxIBCYVzt+;d6_9drjA7ilcFR zdDJk+1DadY13LY$AFz9Eam!|T*N-pToj;ZEHx9d4_F7D{w^iFkCiu;j!Ek z>SBgYt9BZjY;oJ2bGfPVN%1)rFE%BfQt&L<>?oq8bn*Q5b%OD4Ha?aR z+b1L{VYx+*@7#&d#M;enTMHL^H>bWKe*41u<7_&27L2+f(O|L9LSmxoShXp&QirnL z_wjyDyeB?>Kw?4h+51VOPS@7Xr62TKJwg48_XcZ^?XMdj3vIu?o4sL0?7sOba&0F! z^VQc63$lEk;k(=A?BcbRA0BF1IvslW^>g`%?&tBIiDCD*?(m8=eRwL;z>-LNLe049jmiPx2-TggtF9eNi=MR8%sbZ9@$G;O_lcfzJsN)Dvd3P!Ua*c`eRlN8KAVTFa%06z zR!t5!J{QbyT%xvDVYhhM*vh=hH9K`Yv!aaQD!pGU1bB!_|O5UClXV|5E zUiwV+g+7)di-isEioMILOnSJ5um4yU zJ3HT-y2YiB%lWr7J+rC4k*>tY; zw(L#PdfJRu;i~fE`Pb_T8nzkMJYPHAbo|oB1!bZAE?UhQV% z`BQmf%a_V+PLQ4FvS~Iir{lwo(gX7xHgd;lJrFUjtuV+H5;M6rPICBMWfN=RwNJ7% z&4MCD<4ZN>ZL~PrzsxUcJg2>=ndtgT_n7vT!S<~u%+K6i+1(&C^KoG&pQ~khT34S- z%d&A?Gcv{Pj(&;%A=No*ve3wNQ&d_vJ_^k-tKtf|Y?GPI&i8I{=$lCU9|C31-b%Mj zn;rP*=(T5&()W{Q@{I3W@^l_kDnXag|6r@`)r?!+95yRAzuG(T)5vG)9VWYW@N_t5b83cW)Y0aA z2tR7DWi{v6(DP{r^ixjP*_|%maxP)*@v^Z^^h6E*`7?FGN^2h7?^xORT-f~V1nJk} zkGH2t25CoSmaI|dJ^4OjgI%(C(duL7#?IN*UPb!H4pzv|G>%Y^>x`Nv+&1oUbn$)H zIb&y;u98zc+@ttVaG&DXSdSMI;wzG`+MRmdY^#=)q;R3dKjpIc4(F?-DnANE%{Vt- zZgE4#O`w-!y4?oZLX z@okRQtreREj9xD0*(vp$-1ii+*YSv}mx^r@aCE+KF-1~NFlg6OtH?K9uXVU3jaHq^ z+mXZ0v;7Y3^GO%exQAk~){j=n$W2u9@bNO}TlrM|qOAkl#7mEh)(cEHBtM@0_B?^b zx1Y;PUU!Qut zRLL1+U0u!k@al(`NdglA1|L_y zqAeA5xeGqs5ip#8{DV&$iHn>g-|stDFB~QQ{;&IeQseS9q5(f1bRXj8mvv9P6LS5= zqg#7=yt11wb%}?_3*UKhC1`)r$0q@kdW-8CrRI!fGiv@&ae*9Nm ztH%z{9a>^XPH}MQ_t)^nY&6}s zsOQLuB^6OizxkDYU+56AtZ2fG=GxkU7oF*Xw1Gn_ zE&f)*?vwKCHd}oVk)D||Vx+1>z^onggVGaorY&K^2Y`QJ>`d-^Kn-}F-~{AgUd*DO z0^ut{AZEZP@eKbd>(4^MPX;19`^2JeI$T8O&zgV#iSTpb!)zvB^6#tuZ7$&}f@2Hd zVtsdamq{;~g&&*~TwU;lRh_`mM|f4l$u+x3k$P@_;s1<7EhGHBz}Khv zr`Gw|XTom>z7FtNZ8y;*d^z}12hU%>JASUf$NiU#AFE?X{2v0oG4L@ijDgj55dL)d za><;+hwm_1GQ!^rd@JB%+}H*Phb1HYcHm?DzuSMR@Z}edKl;au=>94QQZEkp`22@l zY&)yx0K$I{d=Do7S3arbgl`95I+Oc1mXmczt^0SM34b^67l40EyfbqHS=zWmi;w*Pnfe<|>7fsgkew4u(QYrxlI`bR#A3qSwNNIgFIk`>#}>bfDC zgs%&H^iSd+YX5HlKF&X!cesAUiGyDt@qY{WI>0A>N&YYBfAkX%d@)R&f4}09a^lAp z_@w`^4~IH`w*cP^;>Wh55nV>=pZ_NH9s++l@G*`4iOxSW86||z4T~Q4-`^g8;A8(0 zzhoR(^}iMPI>0CK43&Qe__+RY-LT5V*oZ%6!GAaY{=ld9|F7Cj%8CC&z+c4dKaxl4 z{0vFmZs6nj=Xb|X4t}hm_b>Q?z^9Hsc@F+r>{v$P&j&vB{R69GNceAnPu3q*msS7r z@M92+pRC)V`VR*__8)2YQ2AxR$MzHdzlxibllFgS@-fY-Z`2@s9bp<3;jW`KasS3NYLIorDxVX6OsCECPc(nU#d1>D8u&G8pS_Z!yxlZBk}hGANOBO zlR5ZHGE^XZGx$*@K7V1F(@7WlY- z{w_Zs_}ak7eq(j-gsOkU$|J$Je+`98hSHq$>#j+s#r|3$zj`wxyG$^U8a zlzQ)huLAy&hw%@UFC|N(%>@4M&OdwL>i{2I)6|F10VK}zz+d<;{LhkO#Lor(;T*xT z5&sY58S4j$B##vlQg^h%pM1P`5B2=FiNePW2ne4|k@5Zp{i6S& z@|A&a2;)ceSY1P;ekAbm`3e1_Z&v$&@XrDt&#$EYL-pSee0?ULRo@sZ@vo)y=kqg( z0n2}7gdYifvVS3esQX_P@Nxeq{!oJzBmRfM%R6o0W7~gc|Ii11Fth*A?@;}h1E0J< zVU>%1Nc`V`kIxSz&8h~eKLZYLdcY^^mLU50nGt>j@bUbPbKpY5zXSOA{$?n?seCE8d0_wXK;{H2V9|(w{BPyS{fi&CB>z`3q+S~Eas09ULoved z0zURXtNl)V5dJiHctJj^`^I1SUckrx``!4{fRF9Rv1fJeVhkkyR%ZN|_d9$sn0&Z@ zllHT!LHw@(KJGslKgq*ber2TY8Q{a8Kh__~XO-UyWY_`*pP!M->KY<`xN!{)HU4W%|76@*jf43A0etxL$Na@J94kinGvVP!pUFqxB#vKc5dLc5 zqkobfDnEzGN8dx)gNVO(z$ed-top{b5xxRU9-P0}Z#Z{`+W$VlH)Hl6jyM2GPGfe%Oc!TT@#6mxJ5kvcy^!mk28u0QmT z*HG8r05g8n!#OZi{w&x$aQ*@HxBMpne<|?MKdZjc7is@9;F|+~C}U6MD{C^|{}JB= zvChwo_)h@71+)FQfAIc{L@6WuUM8QU2~w*5?MG5i4{pA21Q>k(2J?_*Bm7967`%fBP{-J-IdqdfSi2pTAKC5wqn?WP|V&Ln5e-bxAQtzLT@JDF> z=kxzR)&FZg;p+k42>fIGBmP?HCuzb@1imGcKa@To{4c;?!sN4h_QS9UKWRQ={o(#8 zPRYkQKQqFAphKfMF#ThFR{MbPvve8rhm0GmeL(nMfWH9zBOjlEi4Ml{Gb4O0y+7v< z=8^oLaj}fl+YEf_`I*%8Fhg;Zh&tG^GA4tF}|yUkQA> ze-Xbp9KOl(7wQgm{49Wv_b=p;3w3^Fq^(DQPrg4#&QSgTp!i44p^m>fygamK#*bq+ zRR70-PknznRDK`u$^8AD{+k64-#V1>ABLUCf|34@06usPV4^KIwnd#C@0*BmN73Pv#HuhPwW_P5-m~ zME6%Qka~f@$NLwVcO;)x{s-Vw_b>Xdh|F^0M{(hQ@`u`gUciSb_(%Lh<(~sSS%26E zB(7gIgVg)-m-vU;{u!`&llg-_i7u=DgMkl2@JIWH>i;V6;TAB+$M%o&L3O2c~S45L*<_ZK3RX*r(7&Hfb>5b zJp54iKa&3|8B)&x__+UJ`|%p;{8iYSWUs6u|R|22<{%xrH-w)vHK>Qdt#y?d4 zeCT|5g#BauNn9k(e?n3(8u--xo8>oIOLp^^i0Ow@>qb6#wV#I$k@bxI;Kh*it z0({(mh#tXT#X#!G+Q7eIOz}_hS>)Ot-1~;=KLz-B{um8hp5Nd<0KN{h|IznQ z_wVtx|H&Wf`mqB(b^Z+1|8d}x`TINZw=v_#xbYh5{GSJtk37F2pNuPf{Hc+8M}SYB zUy(rae@dp*>j6HtAASE$`&I4#e1C~PaUQZ_B+g9Wlk*4qC;7k9AoX~b{OA6O_c2zC z@I!!4^^g6)iV^-Oc=YpDD zfB%MW2zgKMDJS*S9skomDgPA` z{tn=)G5wQ1_!Sq+3BMBfu!INOk9?Bf?^2!HJIKle|}V|5G(e=+c>>u0F@ z&t~A`{K0*X)q5XQ{bQb#0w4E(%tIS$`-eIIyYJt1fDex#gX>Qe{13JNxLp{}-`H=g z-g~f}r2k!kkLMp&`yIJxgntP5*#8(e<_)#~>VU7p|9{9NaFwJV;p*G>)2R`;62Q!b=H9+{BZj9##)I^P;?mz$5 z|G(Y;|E+&lXuk_{{IE~34_GnMe>Z^d!|Z>21{&)4o4C_x+Q6p+7srn1!pEN)sdoVQ zhRpbXO8845;XemHet(JQ_TSk*G|jV_jmZ4fUo~A z{MP^`R|S&{?EPe`3d_3`=3=K{ePX}pH(i_BYe6ayD@N)&03W`B7+k;DhY6(M7b2wE8K(cSP#^OUSuw(Y z3w(9(Px#YWAwwO)Hw|Rmzi{la@5ny5QYnp6(js@z{mAR<{ioZl?JKDwc^kB zFUTP}tn!_JZwUU09zj<5#lT-giGQf$&lmjX`I}WPi4DgLFEm7Ky8v9ckI2D=^FakJ zG%BJW_-bUZKAgPyGvL&UiSeLc8F zOaQUIDO_lX7?(LFz^I7zppOUZTVNp=BG$Kt3(IZbLPNxSxF-$f!@I3P`xzpC30#Qq zI(N_zQOAjq97Jr-a%LJ4%U$6@o*P_fh?sWA1lZpp^5EDz*gtUm7_`4btOwikpivR^ zVcQz?1IvHV5HUWOj)O);%nyMJ^}+{B{~mGwUBxV?BJ!h{`G{CA7A}lqEnH|nL*%a? zti?d&#leLb&%^{kw7)~Fw_&i9ftcP17tYH>WZ#P_M zKSM4kKR8&6fyg@q7h)!L{xG?_&6Hfx7A!7b1 zxNvP>feY=wff#4;pc(@)j#6ftis-+LnU9F+>&!G2G5-c!c<-r&OB$|EaG@a%gXcjA)?Rbjy-4bSb857Hyi2q6o@~W9w1Bm)}0g+b+h=z#ihk%&X#KcFK z07FEb$ISdEfT+_7h`g7~@-}99J2Tw{i06}DK&<}}5DgLa`k45YnU9G11Atf`|H3o} z6Ndq!zY$Et|4%$p`2ev$_yKtVC79`{fVfT-07n7N0YttgApD_e;a~rNsH+X-i1V4K z!$e&s>H(r({Qupf?m|GEr%ufBWq@c@M7`zA{J%picZPC&RtW(_-IdJxRK$7_%zP?h z{V2%C@@OW;0AfF`Wv16LaXk~`0I?mL0C9coWajSzL_@@ndzfiN?AHU#{6oxqM7*D- z1ET*7CZ1s8NkBA2EI-A>(}1XVj#-X~)m12`#Z#XHOz8E)W6T<)dOO?o0<3w5bLAi zc>pgoM9lx+xt}pE|2y~NtYAC`z?AvlxgYuf`{94*envn1@7&MWFY&yOhKTdyf9HNi zKS)7;VAuTb+|Rh5{O{b)m=FIu_cQuIn|TiV-?^W$U;OXfk9QHq^8oIf|NqYY1AO@G z``=fYaHV!Gq5s#6=(7e;uReXuNzIquMSf&cW|Bj0%4 zPaP_Fd~XNesIZ5&E0(h5x@}g8OuIW3-<=a(ytfjg2RLOMkG|iP_&`wP?5G8|ZYtHC zUpjx+-bZ(mo!`_|bXJ~I*~H`A;{WN`wMq8x&4)KV-LdYuYJbDgnehnd~=?U^2uI>Y-gjRH;(VHsHvS7H)8?_5nX%+B}RAs zlzHXCK=$R&QWEJO6s4>i?nlcO4miucu+Dp7B4o&+uPM7Id$-|>JA5+BGNf0`X;Mx4 ztovGX>TJs^j~0%a5eq^@7oQP{(Q}S=i4~+euYblDV8Z+C?t*R4z8-1P-26qvYWMDz z??;v=Yru?5-FYO9iUUVqr&0YXFpp9i*1int=~8?WeZ-yB-% z)SdUSchy4>BD(kvfEZn`d6C$cjlEx277A4I4VN#_J%797WaqZsw|->Jw4Q%6{&nNa zfjNi0wAwZuyz7%;;p^*RZS!oM(V3GrUPb0x_Us2CqKoe)h|w1;wiI_V6mcBBYvqZf zO|8Y6<36@u3=zMkIRD4;VFA-lM8yk@h@V(gW4p*gW+Z_9+j9q+difnVU&1g~E^DE4pw>@2I2|`2{ z-(?Y__s9nC=@ioKt$WniI(p7Zi@vt@Jzry|Z92PSwZ`d=kd~hAZ}+Nv!-gHCTUC}= ztk%fX=s7+9d0h4)58kas?_S{CBDy?86p$XBJ@?C_kL(NiHO^S6E46#%s`%aae;RbQ zdvb5t)Ms;&mE3YflFHqr#&wSh^NZjAD6&L`=C@wSpA5Xr(t!1*@7IVf9}xwlCvFy#zoY9D7~a#=vcs=q($)vZwjM~V_ZU%fGveC? z+ulc?>nd37F6I`TW*`qC1+Z`!IJ@uh<^8flcNK zRqS^6>eI)^-kRn2gcy0^cWnpUvC z>1f?9htcIN1_>OtGULo##O${vYJExpA<_@{u8*SS&*0o5y5oo_ zApLP%>Z0y(%1)Q!TC|f3y5zQ|oHFZ95`P)Uuj|%fP@8_GZ|c6*d~NS&+F_BQ!NG;>NzP~p08}Ewo0_W{T#Y~4;ek`;vC{HQW_owLM`!QnluQqOpwI8&{ z)*QK;ImO_#PtG@Mb|vkn6@gsQPP_U|WU|&2%IJ*bmg!w^^z;@ThpRSx-8ORK%9GO5 zdZ)fKKZM_XlYSUaL;>mQ70rnm4L-I>BDJ;mpN?_#n7^>UrqxwDQ~jt^_RD=qv;$){ z7rzfzjjP!lQxJJP7`d7zE{fX8u<~m9bd&;R$_2kBub06C& zx_D0_Mt5B!pef#bdcN<79iF<6-WWxmzS!A+BxLh(&t2_DGS9A>EmWhuXYoZT!3Ty< zPXvxha9dV6#0Ac?Aa6FF=UID?~&A>8GD9a6Deb6$rvQON$A>R_M@?4c)H4}_X7p1lTKfF`d+K~ z`tkZo_vu%pIyXy)3{Z4MsJb<>8LvC9o|7BvF!}q*`qV_nvhjU7vX#c+@{L}56ese{ z);s^`O=!08N=L30XYUEklTErdo!ig;*?Eh$xnrF6=}>ehQgxMO8gJi7RO6Xc!q#4+ ztDL?zu#`7sPGY|w){pXx7}lLPayp}iK@F`4Ewx_ubX?`1*VK}zQrjz&71#W*S3N1 zIo5Y&uc~ULOkKvg;K@vnbqG~YwzSIi@*a!4<9R|m%d}}tBQ@4vS%_x_(huTP-ObslHkNarg^pf0ep+Lu z-g?jQ3ud>*+F4Bi!q| zVG33Ezt|7bR9&TI99{UJ} zzP;kJa2hc?Pk-TB`-q2X8%~7#&;3zX1zMzk@jF~%bjg}=&U+4ijMy*Aul8f*oNTox z>kM0!rWEdN-5B2*w;*p(+bi`-jRQWRr+C7b^eWaZ`eCWd zR63uvu5S0;8uh9de(g0UCcj@>a-+bjJ;7 z)4JO}4LbtD?v!^@bd{;P^xWBIj#dsKJ^QXqc`~iYHCv)TOZM8TtO?`C?=;?87~Zfh zkK?P%*KC3Oovj=P49<9(F%?q+C?!=|?ta zJxP(}!v!*8uH?EU1fO~GB+GTJ&0@0&eW#B;GQHr_EhqU_?65eG-g)t1lHSI7Qj>7c zCH<>P)!iQD`)HQ8OM^#Nix2PI&Sjs%&WO5+l)U@GEh}enJ~HyGQ?+!^Lg$6c7dxB2 zJd-iK;al>F3`L%#uP%=s%{K6$o~vh2b$faajTc#ZGrIrr(+rrWIiGhBGjy>IWRcJ@guTUQgt z$FI#Rez9wb&J8EMckWH=HPV!GrrQ}=cr5#HQ&#cbl5^7^2EO&i-(He<=TddUq=h!* zv~sEIObZz8v*5$^C4PEyk0sSF8!)UG_aW&R;E^U!`goNP?mo@SVfXt{!uX?UM>h|O!kFGwER(0dmZ!6V1J*K)pQmnQKZ7A~+ zu|8HedHdDfr+o_^c+bjs^>&y~37c)xJ~qh_2d$>#S|IUiP<7MNQ#Is$(jUj~zEo~& zV|{-nYQv)E#SzSvnM;|q^Xv1kw}^Uo zt^QE6IGC+QzTKhct%{2Mz~u)e3im0x_$)_^F0T@zX+a| z9N(tiUKp&YYr@REGK6(Gr5S6t7-1quLmR?xT*4x2T{l4(q zs+IAldfz6WVw>%e!v54KvZB=)7Kfb{!?mZ%9;D}Ye;8nFvhGTlY zE0y0B8iE#y7oUxY(X;fWw4d{H>58ArsOrpg7-PQ3daFZROO%W3GY*=%%-p?)MY~c{^X5*Bel*7fgove1}=e%qhvu&-jN(eY`w4o;nU zFtXz@M@rkQ`A15)HYV=!o*dh~Xj7ezuJTFt>P>>PZcK>Mbo4s=LqU0T?}Uv3Io%-? zT|KJq_gO!tR8%!Mdd{3W?8sHqS&ydX-=FCvY0W!r{`Wc4-Ry#SFJ6D1pLFwkREgt( z0JVuN2TKjp3(S+dU+CXR8}(x`MRx&JcfWDO^-+O;v2)| zCPkR+<6b0blB$}?Ju;}*GuezcBK3@A!4Z5HN5&231~Gcwx3uiITf0|Z>{KgkUowvO zhl)OTzQD~%!M7BSJr~b8#PLmeZ&T&vaV3%tdDbs&tn?r2-zZ9cl@=gfyrH5{DiMT; zt`QLhq(@45XUygk&$O6aQec%nHTH*~K=n6e&V>1o!jz{k>Z*@T`B)ayyCUG@o+qNY zZBz9uD%Kg7+~gVN5TCI29h*!OMc0_B>p#W0V#k*IrlS_Ge^AY-eJDr9VcL#z!=BD9 z*837K8J?=i()G_gX>`q4GJC!1!$mQ=wue#_xnj=orJp+b(q=iHaY(#4mxR~H}l?yUL2@CCndpaGfvINm8*S_sao&tLV^@)QvFmWlC^b{7 zv{k`!uio?Tub;(zP~cs4S`}}#s^ywOqj&T`1)ObpZ>zEN}1X=eC`3uO_sK z2IQ2YD~iA_IL?TRAPJ|w@^n_6$r1zV^1)DIKhyzVY&5sM1Cd#2!|W@dBj9F3NM zsPg0SAH)p&0bP_^jz4fj|vG^N}{KY^|!>@ zm}r*!oQ!MldJ||C)(Ed6!=^8qw61O40UiBW^TL1ZpEurRW2wRL>G&*2;4x55>NBXgx!XACF(n}q)%MmS0H)yo+AITiypaWgSI%{dLmk4Icv7V z@+Yc>p&8rFUnPc8ba9U-MxU~em8*Ez&in{% zyB(8kTD7b^GMSr}+7??Id1XA__+#iIIlJ&$}( zLO`0NW^nYZYegC3_FNmm{#E*OM<%J66eVhe>2am2W?JGU-!Xo|6WZu@yJ33$YFL3|f*l66H z6vng7H+t6W&C_bp+C^LJonJktfWqx=X0K z&leqyF`T>l`ujc891G?;DOgRrGFi`dMtA<|>w5G08ag~ZOL&SG&Ukv=On;d6QOlEacb#<;EB_bx8~#96v;Yr7@h(}=DURo5u@0PP`9=fb)z8?So|Xezuk zQi)L!87Xr6piGvr%2>HG=UQG*+2EialNU2)Q#%{S@mGf9wYyWZjSPg&?u+Q6K4&eX z>Mone^;Y+Y4cGV+C)X==Ke|^ucg==XY%zI8W|5+ABPwg-E(AA(>{#mjJo`&zdCY_J zriO2RIQkZ?+oY*F*}wnnQ%bzcsk%p^GtaXvy7uEvww82HOykQFD|k5a`Y)fWMSI+e zawA*(MmBo-mmU24AyZXyj@}2k?S6gUO7_Pnx~^2+wB<2YLd)$dM(-RY^VX9tGCbpm zvVXHB@5hWLKcN&6&Wg0L$$f6`@9p~7yZ5m$@2$NuYi5eyvvn`Yv-iBSY9e($xKVXC zy*=r@nj`zBo4vZrj6MCAl*@99q+V(~kx6SlZ(${IvH2T+e$VN&(Hq(%6>K6?_H3E+ zWSV@IW?bv{;TsBr<(E_9b*JiDJ-pdlUKCyPc)NJmKJy1!mNL0=8@EZdz8M|pXf@o0 zb7_=sckkndb#0#(Ju8bynlIvgX`oBRtH7%LQ};;v`x=Ta{$_y~{py+X!_K@vu;aRp zf1=E^&y_)M6YunxT^koa`t{C3>*bolE*`zxr~D>6@b;X!Gh_m8E)P>*m169nSzVQ( zI9>1y_1uTg_QdF~oCGR&N3|8M*{xx}aMH1p#WenfJ8RdPO#gn7?R=NQB97}Toriy( zA!IWAtHO7Sw?|u=d*8M%I^Tc7YuDB^p4vHg!`|PJdGCqv-ljb^9WNi)3DEoT?DH@kTFj{MF^=y&@V~SAzQ` zHk)MFE?GNS@%6Uy+O|c88@jzkBR*#8?wo(zEak|O!|v~`bqpIyD7wB>-Sr~DF~=r% zx#Y%kAGn{ox$E}3JdNT5;@`@iMl8_UzLa17GRL8iu=goxWg1ao!#JMi)Y4u`NW^Sv z>aADMqnAK@)}}n%aF6c30}mZT&s$n^ z(J!k_Ob%P5VpFWVwE45J+WmD}ZVJ9aW=H1k0wL^Q96x^|3P^t~%n`ljuu@SI+nlC# z?%UFH{7c2|_7r4HuR1-^?cxiCp39;WCY|T(6SYe|)c4%MbX)S5#|vjQxZh4YsJd71 zi7rzYf6o;_)s1_R-`h0xonXMJ`qnGF_D{~u7$eh_Iq&o#L9v)J{wLca$G>PfC405| zywRh3fs;GgM$Mn<6Qet?$G>H+rj3wkHAOd&s_S-bjC1GQ;~IymT91a`yfpXPyMkPG zd)wV(w>~xKQ$N$9Y$>~cmcv6m^Qy)QA+wpeJpqQ%?Iw}7bk)bNQXc5zUQXs2K5G!8 zZ=J0$^}WFSLa(W^G7;gePP@`)2q(;}7L+>bwLUTKMNo|ueVkEasc7SoBu$RJ5l*^= zFa75on)vGQ46dE;H;p2hyv38i~D3SRafS^lYsGu;ag((p0C|GW2Nlovq!4J z9gpX!r&-G+MLlmu6?h$T%GN?A9rr*`8}*_KOtn<>9#Rc@XFke_)JXV#dik8 z=$aef^FOQ7ZNAWTptha8?OpBUS((!}l+DyDwF?^_V4me*FEirFu^*ma2Ts&z9KUmA zYnhnIjh44g8|(G7B=0^D1|g!0XG>yq%OV0#to&Px~x8~UbyFQ z@_Fv)3)44>sm5`KapwKf_$+pz*t@PhDJ`7lWn1O<%O~s^ z$c#@inrq(5-FQJrOxntCL4;CD^cz<<%WE$mvEQIR2dt#(hHYw{Bsx`ky;!QgUz>ME zoc&aqo3GNGJC~B1Ka>uPKB#~7@+z@QP8T{m7N=!vmR0@u{+RdTa~;7Wj!UD1BZr|D zi8q3(+qQmO_7v%>6*nza{YR@Ga{s!1zVUd+rN)zl^n_$J>SHDdC}n;-75$m>S*eX} z{#*Yk?QM6yZ~HP)H;>PWqoA#WqKnT)#OObQC6((xDLoM3tUKzkuShHK^$89(Z*z}{ zQtPZ#-4E;QI2VbTT{~c!@?cUnY%5e200lgrWY z`C;GZyQjU7tN1~1*u;j}(`4AC=^Af#BsIQR_FhNQac9!i=&_HlE}c1vL&b#mNvET= zc+!lwCMy<98$lg6e5NHvUvSSl#+Kf4Lv@=VL_NKW$ z`?(9JHmAv1eJoO*yO*tS`={-abB!)PeJY)u6Ig@aJ(B*#@2H8}Z?E{C zSSN*&JPB2f$iADCnr6$q9qDeg=YFC54c$1)tDRB$r?c0c+tGJsxlgOFMIl9vhiyIMZA`M)#_7Espb5`SL<#g_y`hjx!GmX9h&~x*2d( zgz}DEztY>U_H9ln?U3i`f^{KvHy%Ad|8h{5#uW<~0~ay+M`sZme(jTo8U>cbxox#R zZJ6}l(evo0Fh$oDRU`UEouk;U?>}ek8L8cxGE+dx^iCs>+L!g+?oHBx8a4Cuy4Qga z8~j&}v4CrcC?MT2SaJBGYkJ~AGv36Fo4#v$Xn%U1ysv2{mVhdwoWIIyh!U9pgSkAJj!{V)SEHk!Ix+-~G6G+;`=Nm!s49 zv}M-Drnl58zRrFl@Z!h!oXow^>Oy-uu8Yk&%>E`rdSko6@~3x%k1g~yxRUf)oH5U6 zT%$p7EfEEzpDEn9+#!5fy%4AL&2RF<*k@f639Qbdty|o^?|%E(s`!iT@GyLprI z){ZLf1_Qyn>FdVHwqNR~>B$QH>?B+W8gOeH)Wtp_Mz20}Ds`>haEpkm&H{Ui9~<@T z5zGF5Thk^i(q4AWsd3q9S#6U0j~d9H5bO2Q%5hdx<{h)k*_1BjxvYKF_nCILL5L0R z4jAuxA__<^KE?O`T4TBDWdpWXcBPh?1@>CrjU)7Ibd68$6;1CHZd?68GJrEGSL#uC zE61~L@x2S@70$T$T|M_%jO~cS>5O&E(2b+&>a9{=STT@fZ)=fzseEB#MQq#3aCnq? zSgyHPK0$fq6-`dw`U~TyG{4+EBXF<9msD**zYdd!F1Bio_l!&%&li9e_5+?D;;Fjz zYKozcoxS~B*d6cG+dVLGK74W4s})}Z9**ZewSTL$_W{m%rgcG2VrD8VFs*6zZ>F!7 zyJ~Pp;DLJmXt{_7d?a4fO`z%?(th2onh>-hS101)o*hrBn`AyJOu7*H=AN3LUs=ZV zJ!~-}r;eHGI{Wbp)grc2qwIZ4fB4mS9r$qJhi%A+f{WKci>$W|RNeG|HzVyM_K%Oc zIP9565m&B+lC7w9^6a8`&#Ap7yad94ktQ{)D}uvlWCy)AMZ6bQ*{^Q zMh?u054x`tG&Ay8!>)s4E5EH)wRhy}32*MR?K`B@DXq2NTXCa^Op?+9FV6UZeKwi< zBIiC9tIAq)BJPmj6-vBYsJbbQ{THvq^M6{(Wo#>`MB@oBqsb)-M9e)PpnE#C`}AhP z4#(coz(a3!+ag|U6d2tzsb<=x;(PK|38_;??zr{|`;?5^R;unh@kIfAAL98|+zR6{ z6`e44H4kUO;rM~Og;DKF`7ee^U0d*__QTSphv(HvS2{@_Jk?QP^8eU-3$UuXw%-?F z(OuFl-6=?Sh=8<|gdiZ&QqrJwcc(N+cO#9WbV?)Lf`G!F>;0Z}&OGOO_x`TE_p|qT zuCp1Je+P^;=WpHXKgX;wChKlTgh7@9$S&f?q?&=)Ho7P?9Sy=Q}QqrhA^Ic}=OHDZk)f68+;G47w%*{X%$PH1T| zQC>epKs>P5z>?T47w<1v8YrW6mUPpeZybj_q}oUn?#VYT=H;3NaihUpaZX;^sMV6)s5jYNSey^84?;3LM86E$Hg= zxr1up>zx=dm)vOuk*vZdb{v-+WpSk2*S^&Fv6|8bV5tdhOse6$OWXRKxseCQg`jw2!CVExbNBB(Ik-CL+0hCO;)>NXKOcKg;Y-dV zj63?@kC3L=&v`3+7L4EaW}*Y}O_qjHkJf712Q{IkdQwNRsb1(&pa2&lxtvT;)&}^t8*+ zfx`D4rJI|Prw6+W_*9K!9G+ot`$SgSNa^S=@xVSLfVm7@MMJ6H;l)4ezaiq2n|OQ; zbxZU5ffI_C>3kal?lvD#;Onk4K^moimR1=v%`fsZyz?&}dDG2hN_ z?3l;Ol|EN&8y&JjEpIdAX~1?KW+b{h_poEZ`D^?E9pn;mc(I~W%bHB!NpYHZe?E8C;mx}Wv?Azqr@ z?G_%*I0Z|$<=6qdSAgt;-|Z{3;f*Zsdu+JVvEyY19yauKK=0vUKBR%UlfiqltRu${ zH*l%GV7p>P5+({IULIkVAEL?3a_V^A#}5wiHqccgvsfDrIGBhEgjb8u;FC6fDBGz` z!18l}8pKTpbA`;LkGC4M$ED6GCwG;ye4G<UdGH#PD|`Y{LCIR}k7+wKLT zj4Qq+K}<`-vKDkFGxU)4<#*~+hRzYf;>`ea8Jj)66PUt_@bhtV^=P$(dEX$@vI?0s z8A9MbXG{uppNTA_bti4=oI3yDmKcSIK4lAZ@Gf7JZf8v_K|~0q0&$^Z;;;e|X0)7?Fs+bzL4g|bhvjf(o@)?6(mPnLP~39+{RNrmSh>Uw#QT-XmYjTjPQCUF z%NvIti*ABX<`LP#xDIoMSzMK_md^U~v3La~00ZVjHkkXh#H`p^tG%8Ft@mdQ#K(}Q zwyh#TN(N)A$8zr~@vzb{9L4e;jtK76=)`w17WF(}2;5wvTvmKWeaq2UIFAOz%>i=} zr?!T--_~M&A+dcIMI)~#eaW%x7^S(sjBn@}mp@g87gKg90_=^iaEabDrpt&e^*6 zvx><1sWRGNN|})b(yu7|bIRnNz5#|*2$Ty>ef`5O06GWaQHQ>-jZNEt83Qn$BuOYr1DA+V{?~x;7_v z=&>B;FZA32D-gV~%It&uPqcq@4;(_1gPx?QkC3$J)?Urm?x0^M$SxwYShw|z3e1H(r)ZlAP03tcz)V$(h&ziW)!>w_5--8v%;pnKLsC|5OkDo|SO$%M=jMM1jY3#ip*R4GH@{L~3+-NT? zijT{1&bU*lV(r}HUzf$3>KFGxk2NqKN?}l-hFGhr4aW;dyg%1RrW}s3 zYR3%CMize&{8*tT7U_k>5W*fADxvlwm3cW!#W?SkZ8<#`vRAyweRsd*u10p7mRk_F z49pEaSK8jBvm>zmzU=nL!WFLzg)2t62#u-0@Y}U;$v1@sc)JndT>q}+Wzo|M56#nh z|EPu1mztg$S!VKx)RW-xhjK8NJ)7_H=s1;z$bx+M z2Hvtd*D z5V=Faa`8fMbfJ(|ae-bzJLc>WyL>yQWm^p|`!`7>P`uDNUs!>l20{2gzN_m+@E7#@%HOG~%NjoQW z>>Jk4s$o!|hR~;=a;Lx%KUEdCU@=S>wHZ`KLgyY)MdA2D&-LzhE&~0hg#Fp!%=gGj zBJ91U{O|(=U6UuXVjSA2wcEN4^H(m{yx7Kaa@mis9-#dMacjZcd)h~fQZ8?& zc6P(YtT-jowy*QMrVtD#CRc z^|lUP3dDtuMZgLqek#N_s$Mz)SAvAxUMlDbLX?%OW}nM5JWYJ_2n<3A4ojuX3Dt<9 zUlgO~!2>hRFUNU>lk6sZ7=MiR;WWEm10a~c(6Js^fg}YM|K_vt2>sL99@u8suCmU! z>#7|6YxZWy%SeGnS#I*ISoN`iW>v<);R%j#ICou_G-Gkn|LD0B`0#%+K> zff^Eb-Dl-3ZmQj&FA|P+_EpG*lKSnAVCl;uBHPd0+h5{IM$jKH4LqCq7?@5R%e&C0 z+tq^5jpZUm9HYaBp7@@)B@(N)VU*`xuh0;RZeNwNmCV_zOhKl2@V@? zgmVuVBrkVL`M`H8jX@}D?AYaH`KA2>-rAy#r@dv0#hGmZ-76|ZP`s^R?owG5mbd)g z$}=hL+8b`glxnmmQxX#H%cwu(`sf()r$4>;%;qc~clnZ+9c_&@`#R4ecc302Q<+cR zQRy4{Pw?>!I(7mp5Fd}|^FW?+QQttK4ysA13j_4zY$;ULWsL11J|v_~GA`lD$1I|v z6kp_x7yj6rid~afVbD@z7L{v%et3`1a|Hmwwp%+43e=Doeez;=K|vOeV+Lmz1qicl z^X)+1(i1eq7lWlN_XoR5Tglu@0f~DD#O(lc zP2i{1QzSZ*;Rh##j{;DKk)#}USmN}M$29_FCw%EguQiN$l2BF@XnXMHDg!>h2^qt? zogUDL$s=nU@aGBF25~#VT&{izxeXaKum!tP~SpcE3@)C&Z}1~`k_deUbaZ!SCjh&9B;cfZNxnwEcZZ583&pG9)ZZ3y1q zx?xbDhIA*1vAgCDF_nF~l!;NE*cm=~tg}nKKN3Lv(`%tc%#JufkmD6a#DaDQ_IdWC zb=srUMY`SOT?B%p(YYDBT<~>N513o=(dJj2iH{WgdtvG4B<75bf>ZBbY%uH8XP{GI z_-^#)b$cJOm=>?b?S>UV+^)|>RhlZ%DgEm9X_+@M)TaFa7R-lFV6NHRH_w=+i0(*y ziLlTrumWLuImGF5MYgWfdW#7>O`=l%g7XUgKI%FD zyHE9bzkj!FGnZ&0__f+=>17*^X?QiDh!G9N`*{5-qO@WU`#28vw;u)tYKY350bj;6 zf`}{WN496=gI3yka-TVLa0HA|DeQDNXG5?@{hB=x5fP{#W~J@pyf^Z^6na)cU|3!8 zIB6(4A;TA7!2BHma|b!2H`!MZZ~Bnr-I(l1_m`jWo5`^Y1oj}^S7#b9{&HHOjle4* zYv8sfYNh>B(|BJl<4sa9mStPGVSj2-^gM_=2@wD&t0pJ70*F{AMp^*T>8k$4a13$uZK9cexwA#Br zqx)(5jq_A4seRek_`@4c41UTvk_SLA z?q?Vjs3G{wsH$iDEPPXrb5_2-)LwM8wI6KF6;^zQejX^rHJj0IAs;SC;U#Pc7bo!M z*!L>m8^_?leB{^hlJFtkr84-w@C%q5D=RoQ(WDm|?_lQ|JRL(?$LOiISgAjy8ui?G>KBG$6An*MZ_(dT8XVGNgx z;Oo?{U~XI3TQyP5pO%lNeb@q99zVK}XgNfv%8b=L~_hdPHj-E$v4)i_B=v??l zHf5R5WhjQUgWrfVlCSUDNmlfw-I&o*pqpMGU|)X`lDTLApD)J1+(aUu&gWrqOUM?1 z-St|pEZ;s4N|*`dp|jRnh-)ELpHI!8K4BYqNlB1|!(&Z_bDjFh6Z^4$YVnJ1u7p#v zBPvk5<6!QW4a562sG-XNlG5;>kpi}I&yNOvl;n9D*|P*IwTaAj1k#NwyxcXQ%jy=j z?D6llyM8ics@mP7ueG)?jcX0Pw}SPv2{6}=?7Pl8&yGa0Rae9(qPwC@B#<4c*oQ;o z986kTik)Erngq(29;1WKk1s}PH%h$HrhW`a(mlIu(vz^LyBLPfMZ>t0VD6$gdh~Yo zTC~=>I=r2cn#3^AQ~FZrP98s1dNTUHY% zw~MG)KSYpZh`uYE5sRngd|bbRMQP4`k?G)(m^P+_i?#%z!}L*?>=6kiMJXN?3C&>|X`f>ylC?%(GDA9ogDP@sm8UBz``vUaFJADnevcNim!{e@mvlFft=vYvmwwGR+y+U-X z?;=ZV6&*vTCZh3J=W9HUCiXOyjETc|UaCj$%rjmMqw}mz@P51u=4R^%(=PmxCU)r$ z#-w1iTObW7&4l#2XQ6M_32?E$stAT#64u+t{R7A98`xGe9s8n&n2}{Di%n`+p zuwi5V5auWiFQEUH14}f6(VGRZaYDj6q z=+N9d9RHx`m!@2yGt-J6*~xxLQ3~9y6d^s;UTh09s1oSMvwERpaS=}W^?s3#vppkC zNkBT@{*Hsn9}?)j3XHoB=5ChIO%l>Ft+AodJ=Rh43qFTTKjsY)W=vjq0T;DvK^(Aa z|86fdgTT1sx!_b}d^Yb6dE^n1!I zGf~0=7VgB~Mqe!c0&#zUxd%C7!MBl@jfg)7WqxchK@2|arhGu6H~T*3U!kG)b&D%a z!t8_iGHc)mcHfb~%9Ztqaa5i{k@MQ@u9gP^tnWcw=&=}9An5L2dyk)e($vaMMPkYo z8Fs?Li*Pxc5W5fIJ7LTGH7GbT^^9a@sYWGD>(LDc!3Ttj=-H>_JPI8S5>YFRrQq?B zZ5R}&A-payIpA`XeS67Cri`cc{if>aEy$hmo5@8}fqU3c-OvnBeP@T`nhl#(5(7HtwSE$x_1Slj}QJ+efNq51hCut@gT^ z1xz|Y@$P}S_$}{aMAqYUoRMk2D}G6-)NDD!Fur=N`bVGIbVS~tHU0ZH^{6#Eu5ii= zNvTy0-QVj3bHP=b+5+dfKB7pZ*%B6ecU& z7if>R^|^~t7k6GKjD9v~<3e&`)uH+0Mc2m66vg^5H}}a{b^-JmPnf?4U~cc=y{DdW zwE2Gy=IZ;6G3>VZcU>+Y7?hbl;a)9!LWHy=r5Irm97EAwCe9=J2hnx$Wks9zJ++*%JT5ce3&6Ci5+**gN>7gjkz=H9X z)O{yMmL}8+CjDxLGHC`rt1I}VTS?$SDq9fu6wLKtNj~M^mLuzwJ71MHR015TI>XI&%j*qxL2=~ z@|0XDnlwJaw;#XvbNAnMT>Hw3DZg_WC1mm8=pg;|YETH1Z+{~LF7)1U( zBwOE6DK_&RCt^91E-PSka@U%!E)@0mG|DPfmHzozq}~~oz-;U*zjL`j{EE8Own>sS z5Ept3f)&UFPA%e7lgC%iB@2%{JUrhXVqwd&vMM2R3af`Ntk`Ei)D;ft$H9KidmuKJ zA1){QR0*P|b$k2^&0|0Igi}!&0Kwvg9^+vJg3)=#Lg%)kR#kme{4CCspRfAI zfTDYz68dEIJAwK#gF0ki#jPoa)7QQJCAhr&8U!NM8Ik4G+W9VzpmP8)?j;Ng)R0|0 z)p+VZK^a=P4b_YiPdyloc%2ZKx(kCoCY-g2EP0t0R74-G=$HqWh!@}1RUNN>Q8-^W zabj#ns$UNix(6QrgKRIwv1?XMZ1ml{6;>q~S=t^rc(TCxHcG0k%>Dv{Sh zM-k28HU-@@pYyha4Ng!LWFLXJzy|!k3Z#y;o8{}P^Jj=(m7T3nqRy5gKN#_bS>N*i zXwsIEeqHi$DgLqX$b1)auVSM7n2fjV_l9wE)R)#iHqn7O6q7k1?maMVo<0*I@yu&EL1v?JPsaM>}Ies(Pc#6<;jPo3L(3g49)`a%44 z+j%+qKQ6|y%%2|c(&LCa;Y(_@Pn9MOBHAT=J`mB%_ben!-LE{jSK!+>spaZV5t(6# z2;xHXyTJ-1_RR2;Ft>%E(^D^D3&#^zzPcx>;|!V;&mOLG6!Bc@ z_T~(64ci&8T;PQs=F{GspYV-qgShBmuK5HX{pKH`Ytz;H`K_uu*HuQv&M>!)x1nXwc z#H)fRfmvdY)(trlAD8%^c~(pPGw^r`E|@#K;y6fkbaF8uS3xP+!;c$`r{W%DaFt55 zO8o_GZs_Z~(u9?hXXcpCd@Vv$85myI#eOHG#S{%7#mT&FGbe?P9m4iEJTSLXM`69y zFL&+P)C5vmbl6M zaKk1%R{-&0DgA`dt^Qmikr|B_Hm6koDo)4A!m;uDtqy@vMC=a_+5%tZfal2w!SPDa zeMm%7toy)pZkdeO-TjWAlze88$Z4iV%hXw{vzvx)N{*X(9p7=R^DP$^RicuN7xhdq zc2;gBvOoUG11s?H>^_+LGm!K#8C(b(c^mr$7s`Kw3U&PJF!^_XpefycPSj zxcebl`qOGfi}l50boAWe!$Ve1+A+q(DukbvjaaKw(h3aGPnkE-qaM6h?Bh1 z`U5dI-hob~f*9M67xR>dKHD{%$bHA>UIx4zKQkBm#&_0_L(^SK67~2-I>dx;c=1zPfb&*oePX5H@YX=Y@~m zj&-POcYeH%(dAvuh7^2;n?UQ$M{w0OJg?8@p0Vap7YV(FgvCn=<|0x~wsIwqAC}DH z$mk7nKh7S+*Ne$$@9F1f%|*JNpf6JVm5zL$E%;u>uVUv^>kgjOz6)wrIptDmf-l={ zBha}q7?%vp)u_uOdD>R#!`{x{q-2sNwVQhwV>-k|bZ9a?9eo5LNBlW%DjBZ^kNqa$wkQ7koKd1*=`l;dWp=_W(Ip0^I zO!B{SL;q65SmE3`sUfWqIF)eOA?*{S<45}&*`lZS0LYA{#r ze3ZQVsytn|e}w_n%2`c+6dxAwP?zY$_o^ zcmKWWcw;F-pWdkw z?EKWI(rJa8j($Khp5%sC8Hsu=U+~B`JGfW#H9su%~QF~>=o7z0>vO9>~g=e z%#{4iwN>FhlG`9QrYJ|A^p-q*zmvRL_UpCFFr{U^nG!?K@sI2;7R*o6nP_#-!Q*{& zV6Kb6y~}i$)`m*6PulTcu-@gW|qG({>7^kp-=Z|6eq@W%{Ty)s@@M!h$*D1yW zaf-hOV#n~y1~|QAxj#E#sKU|YJ6el{j-_;6!s1dWYe#U8i0{$apoN!6daxW#o=h!o z7sy`*aJ;0X#3!39u0@sVhWY+{o68ImJ|#?>CPRDpJN+I*0aT)kfn~!|eH2F7-X+m( zX+Ed;BE4&cUiMPnh4fs-sL-)wSU+O~b1^9{$a`3il#iP5ew%&0Xfalf8jUHY5&5C8 zM0(&A!?AB`HaucQlA@V4K%Jcn|uU9$!JNgiK90r!(_g~vhf5hmCGHId@?ZU?evuAzJAHLK|F?A*) z4WN^)C6eA$erXqYNSyzc@GSVTdvYOS>?9(5^YqYYH}Ns?QZ0oTbZ!^sFDp3S2AhQT zdHEPr_HL&q$poTDC^CEvs!zGb@n74DW#fE>*h?N~O5|%jmVVM)b^ZF`wOq@BwwKBy zU8E;swwR1lX9%;l$kx+-~@qx(|>{qUlVwMh|Pr=~7VkdWX&ynOfEzSi*7#O9gD z@S&V)^LJK3H{!1vuhb7EQR_PA`qi!}$idfr>|pNoOGafmBeV3|5Qj7l{9Qq$(BFL( zn<_>|AI+wHi)A0~mnumx?1y)0s#}n!=#n3Qk4!rJ{&+Oo$}ZoTxbWft6fXyuYriQg ziN>pPzs@Iso6TUuw*Xs}>3k6f|0KP(XE^KEDZLQtJu@31i!%fAk#9WCK4+QzJKEdbC*(LV-H9S$~iq*gK)UG8Zr$7 zEI(Uw&rSu|5gp8_wAd2f{E4MAK-zP-~(Q&{x0{0tw#Xo={3N(YLU56q=p zhbP~DG5IpJA^B8k3?9Phxv*eLJ;H*8y-5C;$^ASn>zAUOn3dLKx~NRCTq{k_eU&Pt zvdSUjhrgd1t0{x8fBC^&e2l7ZqpGP%Y{*RN`k^-$ToVUfd4!{nif`9h=3`NbOuU-- z6vl>Q@-Is+kTYn2_$vyx6%k zKkb`B)U|Y(-SB+uZ~q~JG)Sz`;%IV&^vpj8I>rav-(dO4fhIUe)dU^^dWcrjx82EmFPLGZtV)gn zPeBN8dnLq`UNNmM)fh_#H5=gqzH3$tg1c9MkoZokj|jZKLG!W03WQhcHPx26V7nDN z2C`s{uK9<9_r)I{4?+5d{3fY&eX$VYS~~ivlATSaEi0@B<-fb8Bpc4^h9+y5I#InQ~g zeXhx(ViV01PJD@}YQ)Q_brG^Q5LXP$wUa)piW_QRZKaftxp!3ZHE2RMwq0otBO*f6 zz*uv>l^OoQkpw(_X=boZK>N_FI0Iju=chL-KbmxLp0jW$Lg#j2{XrbeMXc%mHXPV5 zXv!0b=%c2gb8kCR`22|D>1B(CpoPB-#{|AO-_(vXeW88Kdj5ud#x{4u>Sp?v4O^;` z>fuC!eh^mz%$-3Nki+PCd%?KY^-*YlkbV9VXNX=o9xfHoGHqYe?75kg4 zKg#aWkS?ah+MFD@maTa_y*CA6eBkq@B$(S)+R07$#h362QSk|mV%P$g()3JB{zE1@ z#P%A97;05+OOshksW*e7#6;JT$GdW?8TRGC1ohtGfkzE1(*~WOc%{JHc{X49A;0Lw znP#F8>o?509GZ*um${uMonJlWxhCU95Gb0-;nKdB6#Z-&jnx!ei+S;D=o%RGcw@^ab>~Wzwtg+4$P%2 zh_285QFwbV%P(xYknR^fv8{*EWTUgnH&VUdX*FDZt25jvX)zz36O!(Jwv2cV?}=Cl0^9LYJvI@Z;k_n(^@IlabZJ8#L*~zL{zXdt(UlR}swB z)jba#IiE?)QNQ&&9L0~{|Gdj{kv=A;(V1>uGu!s`0pvWyncl5~!+r?m^>DljVP#C_ zYuCBkdy2zNw`yw8Ib+y-FW>YB&b3fui&%V_&woa(;};GoBZy9w>~)oLacJSQt0O_DSmLh=Z7lz zkG^$LG3KS#Yl)|YqvxrBwwo%L+r7p%8e(KEW@2MWy&Tq~A-6+c#O(d8DJhAF8hz_z z^Hqr#CPNv!_m0NHCxn?YsG{AtAMdlKX;IF<-_K{#n*njvz}%|!dKJ-TWkMBnGX*E> zFK=z?UmSe*!NaeuHz1)aBzIDguFMaSc-|w$H9PpIPl`qyeuZgl>HfiK)x^5z+7GV>3N$~c*Qn`|;Xc?W|%vEi;%-)c-bTGX;NQXp|ndc`j4YMAZ~>`%yioyStTS?Oqw9B z4w&0HPFXU}yFPFKL44wcg^;!8jkbS=QctA#B@4L@fxgDA7P0(1yxZyW=UE$qL^^%x z?^n1Y2%J(>uI5_pXpHS3t}d86Ss9B-{R7Ljf zryB*X$7fz=8!>N|yOP^I$~DofqdS?r-CBr+d@IeC-h`Rx1qHu>NW=Gs#symJ1%u+% z19O*<G^xbJ%3vNv*wfRP(KNr#mmR)c(=43bj{dfgE@{hQ?)W_l z{$oH6TU&#y|_% zFO5j6F6~jcAtIhrkIheGo~5r6nW*U&m

Pi%ICao0hSi6lynR?KDeOrXDze(!h3uo4ytgbR)nfX(+uzj}NZvf_?!|7`6yZtbiPzxPJD~q6 zjw*Ci_6^w=iRBSrXI@(HJi~J^S5IlG@LSCChb1NpUcsigMsw3i*>^tZ4-cFEIDB!x znYzN-sU|8hkd7t`c3^v#y=^vsm6KmOYabBut$-KVi5e8IF_`PilXhI7jJbSUmr!jo;``c{{<+ zy_$fzoXeE;XA{cZ*x%nUET14D&Znexux z465%HHjJh`C{h^8m~e099zLn9;PSsOKHSKQMfj<;%G@>p`b;W}YX;_qRz7LS5M4dq z$Sro077&r04n7vzo0BZFru9iH`owSJ^@;5^?byvXpWhiNH~v{MrxeBc%zcgm{U_3m z3IWQ0K-?E#Zoi*iTaApnr_bx`+Y!z&mzMPihLaQfmq&&0GD`W|k1IRS;6zhWbw2f? zpcnlavTP;Lpowfrb~8H7!;!MPf5hpV@ohM%`Jl8 z+VH%|HS&4^>21q6v$9Lw{_!*GWfxMHH$pzhSoN29l4hGx^#xBm$L9)A4jRj9xXkFH z322nK&qO^6K>k{Rx#8*}G#G;KM&>wu(Ww`#*<`=Ieu)_wn4kE*k)|}ufcDikQY9ms zaQ(Vt6&Wl3h(O^DHA$Hg?b6C~kDA}_d%)wg)?jWqrgzN1P5rmNuiXj6ghX9s{wRi) zK|Yd1(UG+APK`92MRbhf6~zLv#FgXL=Hzd* zeU1;0kyuXB!1u8>VD9U=2Y=oUQAhkxPod8+ikc&T%{A9;8<2Nz#IFf;3J8Z%Gp_^W1$K3ucjAE*$AVz^nGzo;-q&ERMd#9|gEyVVL^5(h8xO11 z?K>tMXzSsSn(PGC%&E?D#60$^Tr1RqrkU~*LV6secSPs~2HW`>c}E@Jg1EL|?l%SU ziZcd?@GSY$3={dBGCGA?CQeKdeTvxar*$IoklyL~6|S=N``wM+ zL~-{U&8u8CjNkd+7FUurg;O7;Z=q}Ls?dO+d$k9153uym*^)MiJlJLW-yO0WV6~n{@1pr9vWsIh{#T7ARf^Fn8FH zOX!v7V5+r|S+-o{^|PE$srPY=%_Md?1SU?(nBN7m_9b2p`4-&YDvw?%{vBFgFY|EG z|Do17bA6WCD`7Jb*AdKZ6MP{pWlI!kt@@{yxz?CB^Mg(`2kG~*$orMjZC)bWr-8SE zObB(lsib{yMfWa-$SZ{Jn=6SwwGI<`iw<9>0OC4QX{rnl z2RHb&zHBV#Uw#&2yQQll_f|O=<7lk$Pp?D(&+EB>xzA!(yO>NmYc1T3YN%H7ZB{h4 zGZSLfg6k_+^9UI`b{jdKx3(6(8)QKo_;}_xjhnw+3C{>&zpSp&M{qi`2lroBFxT%R z&-tzG;8vJRY=#TDu9WfD? z`gU^#h5PentX)nm*~ZW#<4nmT9D0tg#1U(bmul3#els?*vcCSr8bonqtrMePEZ+%J zIa_y*sq-v(y=GN@2!2k%3(Otj z@N6Fe;uPGNoTg@vv_@p^-~5g2B-QbYb(d1u6N&qcp{A7Go$f8w#2%WhRB{=jLLmRvrx zV})Vvv+EBtq)y=Py^Zs;oSLgfX`&IH4krXxJOsG^u0Z~3gw_9U8E6~yb(mnwK!1mh zd;VwZ!j}Ih)KE)RfQS5m=PP{w3Gv*;aOc4Pj05n%%A{CuaA-h(egM?KKi~fu-alzw z=)UTX3kQe(5B*Hg_z(&H!~6eLzCqtZk?{Xt+x35ySARDb>it8~e{TQ#yFc$8?|+X2 z(0*lRW5r?Z^xyw}&~^QRhi5SVp~uAk{!jFO#v0J=#ti(?%H4MR&$l>Yu5V?f=m6<=+$UTK}B`P@ge`;NXB~4t@XK>vwH;4%|6#=fIr{KQ^xhUHAVz9`^6r{=S}aN4j(1&Vf4z?i{#t;Ld?N2ksoWbKuT_I|uF@ zxO3pnfjbB89Jq7f&Vf4z?i{#t;Ld?N2ksoWbKuT_I|uF@xO3pnfjbB89Jq7f&Vf4z z?i{#t;Ld?N2ksoWbKuT_I|uF@xO3pnfjbB89Jq7f&Vf4z?i{#t;Ld?N2ksoWbKuT_ zI|uF@xO3pnfjbB89Jq7f&Vf4z?i{#t;Ld?N2kspBhdZF~S56|gzjFPci8wi$aah?p zIh)wnaM;+Hy|S>fG3U^9G&dKc=Ha4tvhpyuvtXmNe@E=WZ(42_SHsHIB;aL7^gXS}Y zwn0Bj4fM@`0?kDTZ3A+2z$N|F2F)V~`wU@!wLx?BL6-x*a}tgn5R?nevj=Sha+bhh zKz{%VG)ErvM{Gd#z`D@)g66k_wgEYN;BtXB=zBqP(?Q#S^dN9~f3-pL%0b)k00Cdi z{IB7!Wl77<64|e}T4<0MY>jeJ^O=fvyYnT>}u50nPCQZ6gDu z2nfpX`Kztyug+E!09^v`LgWoEj~LLW{;R#~KUmQBg>HA~XN2|#==O(hZ|L@g`VRFJ z>LIj`LAM9gf2iM3f1!Rt{eymnDF8GL=qsQvfQA8$0QwB56;KCyfQA4K1A^`^p8*vE zDgjgqs2tEoK(&DC0M!F(0MrPm2~abj7C^0loB+K6Q~)R+5FsFFpMh>)==Oy60q8cT z07MCh3J^6Q8bA*K(F0-t#0ZE95HlbaK)HZE0iN~(>I1|BbOU}sEPx_`*P;M106#MV zVgf`9hz^i3&~5_A6c7#YI|U$0KqP=j0ignd073+W0O&oi96V4%bH?2Ox&?F&=)W{~ z9`I2W+v86n7DNFN6cMD^VM7X4DG?O~6r>4?f}71IS=j7`-3>_)H5L@X0*VUuE|wo+ z?}}KSVsBvY&w{&Y3f3&YbCUHvzu^V*#n} zmjIUnQqPwIrvZxqspIDZL7*H60Tn<5r~zU?9H<560ONoOz(imYFd3Kv91BbXjsvCx z!;xtea3mn#q<;!I)&h?Kw*bq4OMuIO%YiF^g}`Fq4B!-C9#9X&fm&cT5C!@GeSt!t zA5a7o1OFi1fuuDExQO>9zyUmu=XY;@EBFloJM!EH5Wlq@AeA^DxEK2SfCqpFfop*q zfn~r&Ks%s4unW)u*cCVjh`}PsZwjab<^m@H9f8iko>F5fDb?~0!Z->ZNoAPiIjRX_>Q9~exWi}^hU*q!I?ftfs)0fzuXf!pAHJ8&l; z-%b{vD&MXY|0v%=6rU*mPQI@v{;UZ&8#o782%HNn0?q@@2QC0E29^Pr0G9%n0n33E zz~#Udz?Hx%U?0+blV52s&O)AQU;xmT_jW*gpaZZgumdm>+$dl*bhiLs5cVbT7;qDC z3(%MF1;p8n=PCT20IcNsR^T?EANXRR1Q-Mi0S*EV28IHU0IQ%mmESN>35#MYa6%YcHg%q|D?yj#7s5eNXvzsOUKYR0CogQV*5_QlCVxjX(oX z2W$f%x|qLuPVp=LQ0kb}wOPPPfY_AeLGKuJ<)AT#BW{O@6Wr?_XK(Y`vLm`djtCb;`_zdhz(e@;%mg`3;;?2@jF(1 zJeX&(jlsY{=6M9aVjIJNGT;zEY~)ZtbR@bHdk{T}&4?|G1teU0o8!#$M1G~7i%tb6 zwj}m-EFgAt93VC}1CX+c03o0p2m(@O5?%>Z0AWDlQ~}jM0uX+4fH)v=rHo@h4It^% z0#>-Z&jsp%dBA)?Y)hU`Hor^wy#P25SPU!z&IQf^BySR5Y*C)i=63;b7H}qT25>si z1e^w(3M>SK#;LFKdB4zvOJ6tyh!2&zJPwe0Ep5Ul#Q7Mw7~oa)S3czTZD0fN7Vst@ zI(q|n8F&GZ@_rt84)_P~46qh>5_kf59C!>^4crDuU0Dg-0^AJT1c=UV1g;0J1C|5V z0#^Z70+#@tfn~rIz~#USK;m5nTxx!;=c{>_I&cke18^&F2XH&^Kfo&BPT(%!QQ%?V zZr~o^A>cva0YK8f54ab&-#p9jBfuKqY2Yb9@+;5J0&5INzSjZWfER(6fX9H>f!Ban zfLDR_fap)s5}nGk=uUJb`gs=+y$Jpt;Cp0tzF zURwN}@=0EH0k?@?X;-D6BW>(|c`x8s+FZ$(q$%x}`(b|1UsvBk75(QnBRyci>N83-AXZ>Hh~1oX`kJeEAg`c@~}`V|F@{ zKMA+uINwDd7S1YHiRbn#@kJ+A+VU%5BA4_9En0aO9m%@|R$9W_qO;MQ$U>GnDXah+9-%00|H!ED~NpC>PSL%V2R{FqY z@N|ZW98x|qK5>SN-5o->;Kkm=RxMi-JKK*iu^mZQ;)u@n=Ur^u$;YBU0G!yc=%bil z(Nhu750Eku+mtd8+c}V5v4cW>13+J(4DZAw5NW#V6j^S5$4h7`h^25&fR{q7;P9VO>auUzu z4Xwx{=}Oyp46umjiTsuWQ-EWE$$-#HJPBKCey#8m2@^ik`JDz#1^7SjIQ|?DoB-^~ zdywCmz)3vcEbqV!c?X2A@CyTlgm(lgd2YvVTcC<(;W3Nf7_gY<8h)d|kvvZXMgbC@ zAZ!j02WkyoXi`8uFc+u;8s(YzC-W<~MxN!}`Fx7ONq<`K4JMBCwI!Z2T=2^;B#?hM zzpH|aiV6pb)S+ln)RZ^r!|9(*|DdUjlDb$h z;bb%tOVRU~+;sAt?N|O*kUzL^z(B#AOZ*OS`(bEw?g2OaGekP1BA6?{hy+jPeLd;t z^Q-!(bV`c{6c)w84e+9G`24T$jF>p%Dx0P@o=k<3$-EPSFR%Ods2xt1bov*TmSP*> zU`U9TeEIf=dn|c+naL^X+(Kw;(mA>F!M{h&nOtdOR)fI?n^uJ{Yx~FfulH2>DJd-0 zHBNLr=C|jg+x~FFCK)|anJ3S zkDaP8*dlEp5{Pz+N8Gs2{4;myqPQs={T+-*ef8Oo9J=z4wl{;JM1@-<8K{cJ%k%2b zs{EpGeBA&r{lUO(RwNaXbk4nU{nS>+?zBdyGX%|TTcFcv=o)$TlZ7*W27{(0r)|NA z)Zf%ReZ{mdC%j;|4bbx{Qa~vo=QN1cY1i z+#|Q#d(+@@1rN8 za*83yyqJ{W_{~q<_h_r~%WX_07~yu@?Y%edykPF5U_@`w$lTHHV4hx8Ke9vqVJBOd zVyrhAkIoI}?O%M;D|>!bw+T#fVTlx7vM!VeCc}C6KU3T0ilaLvz+hBjB3~PBS9E${ zW0wVw&IUsnNcrS#qjkN$?T}c9PGd)dk@7(Ys@RB7IraSSyBs&}a7jmqii=u9vkS7# zd#`)@7ej$Y!JvYHcw_0N@bC4BZ!Y+0THT>wO0++yjUv&zXFhp;LH@{A+N-#yvt(Oc=l1B(Av(Et zyEoy60z^C4f|0tgrprFtJu>s8kHM6n94zrxgXv!I>5K{Ae_sn`h%VEbNGwttOeT}t zEjcB${Gf({{JV+U1uif0D>+@z{)A}sto$pL)M&dnZ@=wyIzK*rO6`>!UVNhXxz z`|jL6AO>w_({WFHzwMPDez(7pO<7gR_S)X2PI&X^6MugG6P1qA=;L5SqgUT{(Koww zdVK+y!AOmTya1*>n3auN;-%N_c}Oc&KB9!FJ81p=5zSv++v~7*p^>Tp%{(wd^V{zy zSFfG6?52YJ5FujEi};l~*R9tlz1Otv^$;|)7h>_Zf|0sVaokgDuWonkwgvgi2$7cW z0e(f-Q{MP??|Jd|$0^xVDZB|rq%Pj^r*94%)v;AU{u)BWn)ZZ1G&-)|+UxgN_f$t{ zj9urD+O#q`WRu!RX_v!Iq&`0X%J)WXx<<;BwnwD?%B1sc#qm=<7`o;#C7Yu81&rkQ zj(G9C(eFdz{f$R*Ne6E4lZfP}e9qp(%G$IW42`t)VET|5k>Isyx4k<0*K7V+kbkPw zx&Dl5o9A?(w$U6pHB#r0z?4FcoEnc5q5)RE>e+!4H;&o-EwW)BqMaN%7y<@6*qU^5 zNMNMSfibe>kU*>#*|w$>8Yu#?onuaoKKlM$_uN5FMLTdi%U~X#7qY=ja#O7gNAlnItb5$5$ip3b@-J7hm4n6FR~3{ zZVgO#F#laMX!8r<2^9u|cB+HPczukX{fNb_&mHsetBRY->CQB!qJt||tm`tT=0WLO zN?pL-=q{AI|8QKYW-pKt*|{?WQFd zxAvaN>mMz@LUGg9o7GoVIi-W@Nl zJ)H>f24nnNH5jpjR?|u*zqH+L z&ww%BuZC;DFT?!i+!j{$@2N{={4FWR)HHQ_{6m>mClbB8MnE~*s2V@8KA zJz^}xrRR;*gS+bf=u0~t{pRua{cr%IL#hv5m%PegGBtm{A$ITiON+%}VrjM~oG{(!5GzTxg$6gSngJG`6ri3fK-a>l%i z#*8&OAcw(NV@)s>s{XBR^I22Ax#&LHIq^GSn%e;wrP1bkJJsmz zc3<%Q!VgOmo?07*CNi9Y*P_ zp7hZ9*=goR{|s_`LeYQc+Jt6rMhS1T8_Tfcrg`c=Qe zU+Rs!1ZxbY*U~z_MTq$6@A;Kpz~C|KzAw3=3%zwpfs!k3=Ecm+ z0%f`x8u1hbH~+YvCWZ(iZ=2qFZe#lD9j1jNXGJ^eHcMMo#%zSGw_BhSU0bse zHYUj^0%YFAFGnugWodPT;wFWV*NJp+^G#PzJ7|5uQ=z?DrRPxkfDuoAdhuJSj(skk zW@AQx!TB}adD>}Tb!h#=avL)ZjEql?JUeep-&>|#Y-18&XaJfvoUz+ot>5U|%Ep`v zM&^W;{J8SPQFCAHZDX!8+>UzZ*2W_y7C2;k1dK>fb$;C&=Pj*nvT5El+}`=mre}Bj z?z06pW|#eR`8*dpe#Q8g_M0cAts1i&me`fJJ>c)sZZmS-ns$5k{@UK=e*N;23ogFv zE4!AYnByv^d`4aK!EM*?{>X1&m}8UjXhJs~IZD}BE3dAlBb(F^x5!=y(1 z+mt;6 z*gn5=AMFd@M`t?{!}< zTd;O0G#C|ixO4*;k>H@>v6H);{*jCdO#j-YMIX$H1T<1|ckj`C?326pmR^mt^++9@ zHJ7{+WBjtVW$%wU1Pn4`Bzd9gV01Q^S3Wzv=&0RJcpHrAak-33D7lJod0iDW7o3^b z|C283WR8oePASuhcqo;K#KMcF955>I>QmCnm=WmdPA{j$t??|%5K-5y<70%iy< zmQn~O=hTH0jd|-!|Mk_*_v{}ALm3FSaI!8Hi6*hgkN2Fv=4qL;lNJ!n2-1-;(;m+) zZT-Q5)wip3)EwkEFjA%^(R+Sb_eymY7&8W}jKnGeb+vhIzlgN$a^Hj`80p!e>*oCf zMMF9=#}!0^!p9#h99goz)CI;X#dMcvkdFA?r;jVzwBvdAUnm$|gJlbFf}C!g`0Vp< zhi{fSZ!-^D1x*`h`nB7ky!+C7HiE%+#NJ$5bYx3FBfX7|i{Jfp%8Sq31dWsr8l9C4 zsP6v-?<{V&`Gz|Rz?gZ8CTRA7=GZPrzSjMxd$3;15~Ja{F|n%B9rihT^ik94?;wGi zjJ^q)ouG+r9`f7KvnKATxD6Ct=a{cDJ+8Z;ky7Z?{;o&nT^Q3NO6A4YfRXysWA2#M ziH>7r?v|m4NS$NEZ^~z#p_%f|Cw)3}AB(?+M%9I*0=fo2Sa!|JWAh&U7Z}qct_X)~ z1CeCjJH21p=d2^YEmJhg4#Log9W*@juR+@$G+Hb~YzP15u7f&gMCyBqQ6T=LE`CtoO+d2mfp4Q5U_S^1~8PN#1%eVxz}S zcwt@Q(v#Hr0Pp+0M`qS{V(d zQsIic*RK8O%~khzzfECEWHy3{73D6seAVmMO{q>YuJ5ncF%prQM6ePo{%v0LUl)v} z&u2-HWB!^JOKfx(1}7rhwqIT{Ft&WvPSA)aN47|;k}dw#sZKZbUHi?augZL{V5A1e zs>6v$D!I$$8+Y&g(VO@kGO7N#)E`PA9t+7NPTq5?N3K}j5ZqC5Q@ymVNYEY$o_S&8 zeW%VmYK|>IeIi&}+sOW!E8lr}zxi|jLoYxlpfPy)CIpY6aeS z@6&JHx8cGg^=Ma0FUQQO@vxsAq`mUtPlZA+?e|Lp*~E5`jajJxc3O4u`_&KcJng-8 zN@`_0E^QV%xbk3~+#z$_%+ zZ|A0GPw2Bq>YVg<5WBW6))-=f=YZkm=MHMSt&Gvln0CW3_Bp|A_`(U-Z=M;QZ_-`#sCF5F1Rr58X>-CJ7s_Vl6Qy3P9V{@dGyCf;-{`N7)6zqz-KIrF3D z51xVBu4rfc|GZZJ-G)5|C~j(SR>=m6ox$ARbK3R4FZgqBFvcGw!APt5?Qi8D%-nT{ z{$Pwx%rDc{`^`>0_Goj)KGNTjszpw7)&*tP&HKF{!A14bv)07h=TAOF?HO(QfM4k! zbn1Ln-`xsclKD4jovGK~fRVoCcZW=$Heh_mAxdiLD(4l9)FX+<@A&nLk7_ngQW%xf z9KAtfJ6)g=?Q}Z!rO*2Iep+T4MF+(txoe}!&oF32Z8 z5JU2_X=V9QXT8(C$;d{2rh(}I=ANZ@73{p^mQ&Kqqov^|Yrc7t2*(?%We%eOsb zb&Lr>vEB>8h-|Cdyj#<-;C|K{Enjsl7^w?8@AljAKc4rowCG|Xw2dw~gFD>m>tJhE5pqhc{LawBbuIbv zfrU#}?C{UQN(ZWDT?Ixw`CDDryg%vQr*E_|?)h;^2Mei+*Rs06Zpjf7o`10VGU@NA z+Q=SW(&mVnaEsRPyB_-2&WPGZaLzpwxF zJgetj>Y5+8xmcBF{c*QmciCJtiUi*sp=)FBj*nk;&4$-x)FWvm z%RGhgu|kr`?eFym?%r~m z(N4|fkM>*|e0(iZOIt7X6pZ-mHt+m;$+Y|1=zcsqUKrPdX%FW8se|vhAn?!!(1@;~ zVJ;vMt_n9iFzSXYpX)ndjL|55^bBZ3Z=DxBx8m_>w@UjXbsL)HU|NIe_~vMgy0x#!yrt+G363?G({FsL!@I4{ml;5VsWIHP z?T~u#+ABs`wGkbh21fGp<4(KJs($_VqYVuucL5mD!L&P0__=3vq8?FFLZyGb29r)@ zJP}}-r8=+I*9#Uu{_3TqBU`dO>(53b+oVw2^?k0Kp*5;<>e6Z=bxylhEryGCfoA+s zx-R4m`E~B~M=Uc5inBcwwY4D=!;9c%6hPr9C~x9KlsFNOgh)D*l}R@htB)K z&>)+O)a2A%qwW}Yy}8r4XcQf|b91*47f-<`+|5Rd|GJH$9d`-b{k4m1>`>X7oc_J( zxU_SW!q!N=HGO|~9sGaGjhf}6H!Q@x1$57;do6LH@sz-&Zd20v+(|lC+j{^*HNd>{p#%kH5WjcQa&!;-_ytE%&D50bGK3VQGt8k|L@hCi`3}A zy?5*0A9a__g&XPoy}JW*?hjEbHaYi(D@#;s?<^->*y+UJLl5hIB1@EXeBJZ2H8#36 zG=HxIe=j%pImiR2>2dw6>LY%u|M*}%o>Oy>?&AgbIlI4C>I;x@WY-b-_DHQmSPE6`g9O8bz)g6e41rmjkFYL3`_6zWn>J#*?V+a@HC(R<#j z$2|SV5uaJ3ciNu|bI+-g&R;H5tk=Cvx2Al8$7{Vkci0oJJaFOgaYk?SgnBaGmJxE+ z%nv;w_jc|Hxa|VX$(w!-JUR1bRs^isW0y7#Ev+_i!s&#Wt83 z2D9bF3#Web`lt;y#@%*u+JR~T-Am4$n>&qrU2tEGbx+5oHhNmTyN}PQ12v=hza_z$ zECR{QT=u@(lDrpY=+Zv&rr4^tyKlEWWh%!%$*D_AOS|B*+D9#U3vQCmJ&z^Nopt$f z(qb^XBQs{fhH!wz{P1h_H~iVDZ4c%xhxON|@jf#&U4Lt8bMF&(oDPjyS^Wu&w3=UU z_wqNp?>b-Yh|=70oUt*deB9O!2Y9r!&DRc*K%Jj!HB-+tF7ESMmm3F+mz7ni_0+7t zysC)aTvipqxUbwzLIRm-EZ*ksC%>9`w#?niEL%wt>*#apf>Ca`JE{NVbNYX_5RBAQ zyrnzFy-Y6->YblE4jp#-o%u^{RXJ5B0bKf3l(xGaOd0e?(3tjW^8S9>JoKXXf)VY!& z>`aKqXw>o!N|etS*7^2&BO4_r=QV30$<&Gumfb($>@SKGrbO1NkB6Jgbw0Rs{zoIP zt(Vgsvc7<>U1-4kyll7>l&Fcd7K>f?!HQqko!YnrV*{gI^@T+;3^imeD?AqmQ1^Gz@ zYlG#{aNcv9`?pyZc;jhkm|GF4Z)2BV5AqY+>z60qdV6p7yD)Z_>jLuDff0Yb^u5vf zcfWShIX31~Fnfc!wc7{Jy><8DtO!^%+p%4`JD7s^&z`^h+|rnhaW9|dI@kv;Qey5B zjN+Nxge zbmSp7{yNLCrk88)zTTqW{0zIb=d_U)bsRk(d^fT|haLEs{-Y6ax+sRpf)SgrKeQ7yQsHJOnzlm{)ja*E<3qXpM;`O zr*mh4k#*WrN(#HL-E|xBNLYc4HQmqu!f&ii###~&J> zElB(Lp-f-TH%_?x z5zbL^f?^=?N9TwRzJaIceuEx z^Y?PQd5+#UIN+`w+m!Z-4b)PLhjmY93Ruyobq`ZZ@^cF`t)a0`3i{_%%2q7VzCB7b zN>%t@ldXCAOik$W`SIO+OVQ z176H;XuBm9j6~}>S#-qo*Z2Lt&t3b;)m}S-zidnC$mr^^9UdpX_!{f>r)+%oojh{C zw#0vL%E>oQy}idCm+~&@oxb~&wtsf)|DoI~ET#XPLR7=t?9S3uCo4vyz4J zL{&eVpkKi85>S_I6{f1@dC@jcUzjux4M?>aB;4ezBCS@B`SW}5H3{;XkYk|zLeWU! ztYpiQ%1T1rBqprO=qSZQ{pQp~LbC(WL|sLsqA^}q6As4Y$iC{^NS`3Uc_7ZAMBUrtAD8`VX6pI0KL~`^#F$c~ z{?S)8*INZJ6t7(AORyxCWX68Oisc*_2@D_BL;4U!J%;w^@6XA>MIF@j$&N#MC>?L4 zFO|nzg&7%!KI0vA%7Dk4Lo=&@OS3R!k<;36s=%Z43ny#(VYG#K6%Tz#^@EwJg{Ctu z9M}yNu1dt~#15+?(TZ8Y(ClPwI5=BP?MTgJjBlKVK9wr&gVRQYsXK*|p}It((Ia6; zEYf$pkqx;*Or+o}E-#8RLHvgc353{481`T+63TUDaJ3!-BA3#P2VI)C=+;UnK)TYM z^)8;YQcRl4bp_O@R4COIAc1g0Z4mbwk9o+D6%%$@Ayg=%8x8gi>C*-_!1CKK-@ zqInCJkuu~;f`Hs8q_RZAigOLrM=Da)w66y_-^-X+LYvN@Kxh^%I4v~}I2o}B^jn!S z^I{tvd0618+~WUyZGabhb-5w3~Pis+5xOs-efMd_tdHZ*p0v1;SA zbRH?VP>`4lCZIYtJ|^T42~LhTWk!Am=qMdaWxA}$vuPPrH${3N^w+(zmk|$U8Si$* z*TJ!1jh7R&Bc&M$h4@xqN0_!jNYl?K!@oA#b_c2bf-U>g+SUfG{bC!ihhcb`p1M*= znI1jPV3O{>vN#WJ4ii8W#~U79CUw0%QaB?SVUQ7kTk~&E+>MH>574Ez1lesjGGqr) zF-)g}jy5BeWNok>H&ey1ly)lOWu=Z-Fm}ADj*MS*aU=(|<4yTHR;qoA!!*q#d zP!~{F4oVN)e)A|m6&v>IS5+LpLQ@wPLZN;YgW zQ@toI9e~(+v`gAUVd>Eagz4uNbxd7`Gw^W?Zm@ajWMj3?=q*-%(&7ZR0aJfz5o2cL|0yNEqFxJ-eFLiE*|?EK1@9MR3O zvShggDNqrnbVE#Xc_fk<5#E^rO5tf+WZsO`0S|6E0$lV%%lx9rjGp&#>Mp*C%P%}+&xi-7jCWfP9vtjxFA*d?2c~G1!K+46UGrM#J?hYR%E3iH zphuRPd@R;73dfY1Lm!S%+7ACgrCbvQx%^=JGG~Y?J@THO9)u|U{Flm~VX1A|T*e_% zs#+SNZyXJA34H*o@(>{-9=tN%RR#8|^p*NS8D7{p-da@7nX|<( z$P8!^4}0zzdizD$it>9>>-^?i(s4u=R(z#UKl{+v#X_bZl*r0C@^R;AAVJ62%hlSE z;9$R~&b3N871x7rUrw13;g%U-&j`@+#p-IxJtw8pap04Fwr4mz>@i)>p-excNHd-k zZzmt*@Ls5p7|_cPm7v6bEQ*X~Uer9P(pNoL0$39gtcTQgB%NVHq2%^605ua!ZD&0M zV#k|mrIaanq?}$>fj0e&5y_THd`g*&pJZ{TGFixIIOTk==l(_y&U*IvGwvYd*9R94(bFv0p1ON<^8Shr=XZ0d`%$)_3FdeBJ|Ecb6iXFZa-zv*QP26bkD zvLUO_C*tE}!fJuRs|RDUYR83dvoKiuH`T0ysb&xc)+5>SFG$t|gd|a=+7Q2@%U(f- zG`*S(1Aj5CrEk4b4|!&Q%Bu2XW#zKHK&nF~_ChWmD9S5%IXVp6U^;FY2g);ptv$1BD zUagr*e?si-KY)8b|DOowhAQ&li3(-~at;J?aNmzJe`!!$E+>sewK%{UUa zbqq}&v8W85cJTiV+iXcS*R7D%R3H>;q_hM6s(jA6n8{2_XFCNCtF)`Vut@s=S~P22 zCK|yT1mdx1BRgB@sIsOluCjPgVMAeq-V!0p+(m&Rk7QU5x44jw;|<5>zoP3h<>lM! zx4j#QI((g)0bo%df9WN&!%>RRj#t_amJ*ah9qi}t^|v!%pdTPLJuVgt!@(Nao8Y-^ z!Wj)N&R2N(k0G560raLxK=0CN@z#L)3Al}T0IrH7(pd(V03IJU<1ha#jr%S>Xj&{r2@%d4eS^;LuBShf6E zTWb&|aw25C&q|h6*Rgl8zMB1*73{(_WviF=GEsVo$P`34QC1hL3f4;1stcv+5_E$? z(ReH@rvqxkYv~;+|78OygDJJ>qqn@u`A1TeGh8NNnE|b5B|Ki2qIVXTZ*WHA6%ZDx36NM2 ziCHa2i!xaguayNG>F=kcW2hK;)D1flC1k%ycN9zZuIqME(AqE1@+AXRz(J&Bt8=oN z0Z4VEUwu4L5s-}>N=tlaKy|Uh>~BhhqjjvVM`?gixY}ImC3HHH2%UZ*Vbh`aptX~N z)_%d0`tN6uFC#!DKPoN11|&P1&}IkWRQ>m`ny)xOZk|ZpfA>t8oA%+8E(w)yzdf{B zCI)?02weO%pL=hj4AlJ^m8`9Yq@NX{+Ckl(Q|Va+loc=!Bd{aE%YH$v{(TW=-Gkcs zO1Hwlg=|p;hjEMIk#QrjxMRklvWDgDk4+?%f{KpR{+$TxQyGw1kIHoYsz9c5gE}*S zc^cW0;q7M}zET+2p0h>OKp#UCLiODlI<{t}MWYF>%5Bc@&9!0tQ<7X;J-?-bJk}9P0;_hF`X= zPt!nUJu2Vkw++Dh*o~so-@Q@k`8B5wjY8^pQ`CNDCZFW{YdUI0+)aFSQkYB@L zzMQ70sQYxn)khjcVL0JLkZsUOuSIM-l44;|w5SQuUvg1&^fJTj*yZK~Nm+f+N2Xal zl$K*)p*X40qjR`{@?>|ncl()65gzGhl?hcd^j!jKU}q1i(?dK(;32BQrx~+1yCsFG z@}Y)McDB^3tX$}JE}UdLSDjz^m^g}yd8ShMH}JVec8W>!0bh$6JnM!acvz3BPWe@4 zbytQE$@d49p;ehHNk*YO+7NEKMn+VNM$g7h2=620^{td5j?4XA0%r&CTr3Ku2~_f{qt*v zvY0w2dEn@Lm0lYYq^d?`QJMW*viw#P^e_}JGE&Q6qnaeYzJ@(n1vx`8dp68V3f&&0 zXS^WQA&HPGR+U4uZLgA9MW!g_=$JAwnOtK6%B!!RBQ`1I2vtqBU->xYfQ|DNdgGe) zwj#4r+suOoDmj(wp#^6&7&~8E;f^OrK23PAv~&|4|2b#*!BtQRE2u-Q1k3_QJCRR-EQ6w2&xgqePI zV?d$UcxH&+b8paUn<`%dj@Jf6q@=pRrbw+l6!w=I8LM(grgptxt}{xNM*C~Ms=ou( z-$Cl{V2_e@<%up`ajLpuqgbd|zd9XI!EF{Xb_XLmhYQKDTpmyk3$}e!aoU4*52Q~< z=!V1aUAH^W3K9j3!xe zP^qe}T&8i~h*itI3m#g^j0nHX064bbltqRX;F0kT3+qH5`cXFNA&*0cFmk-9y!nj> zB)&?)(5h!e>F3+ir442JSy8Gjb{T~g4acfHcd_M&4ci={N;k^djFD9YQ$fqp8clA* z>KYkVCe^YVw{iHW&lqY3iLH-j+*+g_`34s}Gt6D#;g}l%PuY{;t$}7<$X2H*a6FTe zPH{5TSQhR)GVX{4JI7m#3MIqIL7(vs2mj?ChbM*J@g^BDvvjJ_3g{W2KzU<|wKP@# zRJaayxK@^-L*d|D?&4AFjMCIp=p&Hgw#AHS^i*q;3RV%q+-WWIh-_P*%Wg64jUDX7 za>Scyx1O$qtV8NaaMu2kGHs|@Uo8x;;y@&M9%JFEpzsdN3n${dC#zY>G!mIiNvM*D z2Zy}8)pHpLcPZ&|Db$y_B!iV)rKHl+%R4GS8CHOa}(Ob$VQvsS$W*D5rjJ%r_B+@!H98`fS z8T_;$6~&Z4w2n7L?U$~j;v0Vsljeafl7u`sD0N000ZI={w0SGSNuXL8?Z>jDa$uBb zex9KjSM3XPan+c=&Q&dqWHVHOE#l?g1i;fBsd)RDdroqi9XHOPww|vWQ#hJ~Odif4 zs}U7m($3n=s*=mkhA>1$0lD=Eo&SE8W^KBazO$WIoc!#~e91%!poyhV?C13}IvCJq zyvwAGF9)(~Ix9Nw=B1@t%h4;+d~zUK$}^+qrMYDUwP;e4d^!7envF9=t%dm6h22+# zf&HR#;y0Ga-TM?iIlHBbr=OL$baY|rf`O~-?e+GcS-okvWre`S>_kJYjC8}Mwf3l& znGs=`8K83OXWh;F{aUoF!9a`bK^1-OK?h7duu4)tJIOFC$56*&onsWF_^R@jZBpj? zTki`J!ZoZ8!%|0P5z2q1$IM7WWX(;BTQReDe)^Z;sh;zL-hPo|_;TTuw^8YRx)E6# zv>pR&mTtkMlyPEu-VySQchpww+rc&zbZz4GvO6;4U2*WMyoSOtHEOeQ1S-?>YfKF< zGsSB2F##>gQN}DTEHd8J8ip!NWrvPYuuLC&RMK40VV)}(Da|oysg>1{nm}Dlmd9nZ z>@`u5BQ`1I2qgjk?PR*1S(D|KsOi~rwcO!X9HgB+XRam64pkEAi;05C##qS0+xl%D z;-T#3kx90BpfU&LZtzaQFQ|NaK_Fh~kwR_)Qpt@_`BQ@hGkmLyL{pq9kgl&s zD$OI4Li0eC4^_>iDHi>uC(Q|9VqR`8W`-pmqvxeAc_!FC7;3d=nlZZqL={B#70iyB z7RwIOMJk?)#H6dk+KPFiQSsnyN0LI*w9*WTH}z{A?4)d3xeX^h>FJ#=$!NO2kRI$c zjg?LdWNfZ`&7yg@)}miug>2_4Wz94fMzL*ypqa*``DKPF)%wZjQm5hPf>HAMakaME zz{Yw+nwD&4W*N}-EQQtzpNJ!KhB;8k<3CN1O>7nvbFeiSxEe?AVV0Q-ovJb7kPl3A zBj~EgaxT?Qu9TNOuZc!klN3)QTXEv`!3Nz*YFq`Aw~1gK^9$+Y7~JPuRma3Hr$;<* z&CQ61KpF3<1l8`qba1k+9F8*jQ$ENe&u%2nM6$T4xkP=5o(JO`xrJwrP$j;)*~5cd zrY2#O89)>1f2c%%_)dgSCx%pY^6N2KA0|{OvK$)c);slOLZ5zOrX2`%hGC#WzI*7$ zBW+bepMGiKrbxB(FXIdwTrv&W>=^NAY+07h|u@yrue>ZuR`4+1-c<9|3jRc*q%8@A> zv_{cf<1Xj9yhc9RQQ?^#q^!%YN0FT!QASn{adcMg_Q;_53?KC733K#s3tSHl!-suI z+`A{cVU1hN5n1n{<_s*2cOnN~m7rU=bzYgBIOgLuR)|=9Kj*e{eXYFSTqM59LlHSr zb8;eM&R0kF{u)n}Gtsu{<=9Hv3NBWzMGqE7XP84q?v!Orqqlo`q~wey93523D*fuL zo`ZtYOh&0s3Htcj^oJuLOFtvJe@kM%DF~f;Qro@!YK~0UmP@ZxKLljwEs0spH!~RC z14{MfKgpte0kB0ap7l*ah^$9Nr&(qq@z$c@M~*6y zQE^2Ja=aX;rz*0;;5>5UayJ3YjLRpBp=#_+?!fnMr`@hUaPYG4L{JY zA|1JX6-)8R{lP36SlK`7owZCkOl6QsVdp2gJhbeLhAhrk`9ce;K&k^#o`~1ut=VUj zOgS%K8eA#+A*l(R(Y3Dx^}9?nD<cZv(*BP*VC{!(pQrk9pfvMxG$fc*oi)9KUS>xl|=$$V6P02FVl~tNZ({ zGifJdmIHEL!N&b*-uZH}Kp4HUpl)63udlq+jjp{|VF=QfntAA&+l_@9w&qD`+OHwZ zP5|Z3(@vSo&a{UWO^xJSPNH)2RRL#~ROw|Hp484WJZ zSGt&d&C_qiDA)G~VWf*mc2q0#SJg5*s@xS4=L$IHs<|5ut*NdYu1k-7DPymC;>9g3 zfHMhQ5B*9e>%)uc8;fan>P^+9oEd7#eyVJ-(=_Qs(jiJ