From bc5e842e5542459ad3a41d62eec7a781e3d7f644 Mon Sep 17 00:00:00 2001
From: Jason Dsouza \n",
+ " Employee Feedback and Insights Platform\n",
+ " Introduction: \n",
+ " In this notebook, we will demonstrate how HR teams can analyze employee feedback at scale using advanced text analytics with teradatagenai.\n",
+ " \n",
+ "The goal is to build an end-to-end pipeline that:\n",
+ " \n",
+ " \n",
+ " The Business Value: \n",
+ " Organizations handle massive volumes of unstructured text including emails, voice call transcripts, customer reviews, contracts and more. Traditional approaches to analyze this data often involve costly data transfers, building custom ML pipelines, and extended turnaround times. \n",
+ " With built-in support for GPU acceleration and seamless integration with VantageCloud, the library offers simple function calls that abstract complex APIs, enabling secure, scalable, and performant text processing. Whether you're deploying open source models in-database or calling hosted LLMs like Amazon Bedrock, \n",
+ " The
\n",
+ " \n",
+ "
\n",
+ "
\n",
+ " \n",
+ " \n",
+ "teradatagenai
Python library enables data scientists, analysts, and developers to run analytics on their unstructured data directly within Teradata VantageCloud. It's built-in support for open-source Hugging Face models through Teradata's Bring Your Own Large Language Model (BYOLLM) capability and cloud service provider or by using In-DB TextAnalytics AI functions to access models provided by AWS, Azure, and GCP.\n",
+ "\n",
+ "\n",
+ "
teradatagenai
addresses these challenges by bringing domain specific language models LLMs and hosted LLMs closer to your data.\n",
+ "teradatagenai
provides the flexibility to align with your organization's security, cost, and performance needs.\n",
+ "TextAnalyticsAI
module within the library provides over 11 built-in generative AI functions for powerful in-database NLP capabilities:\n",
+ "\n",
+ "
\n",
+ "classify()
– Classify text into predefined categoriesanalyze_sentiment()
– Perform sentiment analysisdetect_language()
– Detect the language of a textembeddings()
– Generate embeddings for similarity searchrecognize_entities()
– Extract named entitiesrecognize_pii_entities()
– Detect and label PII entitiesextract_key_phrases()
– Identify key phrases in textmask_pii()
– Mask personally identifiable information (PII)sentence_similarity()
– Measure semantic similarity between sentencessummarize()
– Generate summaries of longer documentstranslate()
– Translate text between languages
How to Get Access to Run This Demo in VantageCloud
\n", + "\n", + "\n", + "Gain free access to Teradata’s Open Analytics Framework, which includes support for BYO-LLM capabilities and GPU compute clusters. This enables you to run open-source Hugging Face models directly within your VantageCloud environment
\n", + "\n", + "To request the access required for this demo, send an email to Support.ClearScapeAnalytics@Teradata.com and include the Host name of the environment you are requsting access from. This can be found on the ClearScape Analytics Dashboard in the section Connection Details for Vantage Database. Our team will provision your connection with the required permissions for BYO-LLM and GPU-accelerated demos.\n", + "
\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f289f49c-7d93-4945-ad2f-69ef7c3f5510", + "metadata": {}, + "outputs": [], + "source": [ + "%%capture\n", + "!pip install -r requirements.txt --quiet" + ] + }, + { + "cell_type": "markdown", + "id": "c559d02a-c28c-4532-92ec-98abb8c7ea7f", + "metadata": {}, + "source": [ + "Please restart the kernel after executing the above cell to include/update these libraries into memory for this kernel. The simplest way to restart the Kernel is by typing zero zero: 0 0 and then clicking Restart.
\n", + "1. Configure the environment
\n", + "\n",
+ "Before we start working with our data, we need to set up our environment. This involves importing the necessary packages and establishing a connection to Vantage.\n",
+ "
\n",
+ "Here's how we can do this:
2. Connect to VantageCloud Lake
\n", + "Connect to VantageCloud using create_context
from the teradataml Python library. If this environment has been prepared for connecting to a VantageCloud Lake OAF Container, all the details required will be loaded and you will see an acknowledgement after executing this cell.
3.Load the data
\n" + ] + }, + { + "cell_type": "markdown", + "id": "cfdd9d63-da91-4285-873d-bb2b066cdb26", + "metadata": {}, + "source": [ + "\n",
+ "We will be loading the sample employee data using the 'load_data()'
helper function. To utilize the TextAnalyticsAI functions effectively, we first need to organize our data appropriately. We are particularly interested in the 'articles', 'reviews', 'quotes', and 'employee_data' columns for each 'employee_id' and 'employee_name' in our dataframe.\n",
+ "\n",
+ "
\n", + "To streamline this process, we will generate individual dataframes for each of these columns:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "84208668-f1e2-47f4-9c23-7eb2df2f632a", + "metadata": {}, + "outputs": [], + "source": [ + "load_data('employee', 'employee_data')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9bf4cd6b-c171-4978-b7d8-186bf8c31323", + "metadata": {}, + "outputs": [], + "source": [ + "df=DataFrame('employee_data')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fb2a89a8-0339-4c20-aec9-90dbc0d8256d", + "metadata": {}, + "outputs": [], + "source": [ + "# Create separate DataFrames for articles, reviews, quotes, and employee data.\n", + "df_articles = df.select([\"employee_id\", \"employee_name\", \"articles\"])\n", + "df_reviews = df.select([\"employee_id\", \"employee_name\", \"reviews\"])\n", + "df_quotes = df.select([\"employee_id\", \"employee_name\", \"quotes\"])\n", + "df_employeeData = df.select([\"employee_id\", \"employee_name\", \"employee_data\"])\n", + "df_classify_articles = df.select([\"employee_id\", \"articles\"])" + ] + }, + { + "cell_type": "markdown", + "id": "49ea3cfe-b271-4980-a667-1a78f770a68e", + "metadata": {}, + "source": [ + "
4. Authenticate and Prepare the OAF Environment.
\n", + "\n",
+ "The teradataml
library offers simple yet powerful methods for creating and managing custom Python runtime environments within VantageCloud. This gives developers full control over model behavior, performance, and analytic accuracy when running on the Analytic Cluster.\n",
+ "
\n", + "Custom environments are persistent—created once and reused as needed. They can be saved, updated, or modified at any time, allowing for efficient and flexible environment management.\n", + "
\n", + "\n", + "\n", + "
\n",
+ "
| \n",
+ " \n",
+ " ![]() | \n",
+ "
4.1 UES Authentication
\n", + "This security mechanism is required to create and manage the Python or R environments that we will be creating. A VantageCloud Lake user can easily create the authentication objects using the Console in a VantageCloud Lake environment. For this use case, the authentication objects has already been created and copied into this JupyterLab environment for you.\n", + "
\n", + "\n", + " \n", + "
4.2 Check for an existing OAF environment or Create a new one
\n", + "It's ok to reuse the same OAF environment. Our VantageCloud Lake OAF Use cases and demos will use a default naming convention for the environment names. If you haven't already created one, we'll create it now.
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d791a944-7e04-4b11-83b7-4e5fb3a0da1a", + "metadata": {}, + "outputs": [], + "source": [ + "environment_name = env_vars.get(\"username\")\n", + "print(\"\\nHere is a list of your current environments:\")\n", + "env_list = list_user_envs()\n", + "ipydisplay(env_list)\n", + "\n", + "if environment_name in env_list['env_name'].values: \n", + " demo_env = get_env(environment_name)\n", + " print(\"Your default environment already exists. You can continue with this notebook.\\n\\n\")\n", + "else:\n", + " demo_env = create_env(env_name=f'{environment_name}', base_env='python_3.10')\n", + " print(demo_env)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "35416e0f-92d6-4a19-bd2f-ea2ea1ff5ac2", + "metadata": {}, + "outputs": [], + "source": [ + "lib_claim_id = demo_env.install_lib([\"transformers\", \"torch\",\"sentencepiece\",\"sentence-transformers\"])\n", + "print(\"Libraries Installed\") \n", + "#Get the status of the libraries installation\n", + "demo_env.status(str(lib_claim_id[\"Claim Id\"].iloc[0]))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bb03c237-da21-4d6c-87dd-fea4d90be82f", + "metadata": {}, + "outputs": [], + "source": [ + "gpu_compute_group = env_vars.get(\"gpu_compute_group\")\n", + "execute_sql(f\"SET SESSION COMPUTE GROUP {gpu_compute_group};\")\n", + "print(f\"Compute group set to {gpu_compute_group}\") " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f3ece2e4-418d-461e-a6c4-89afa8412023", + "metadata": {}, + "outputs": [], + "source": [ + "def clean_env(llm):\n", + " ##Get LLM\n", + " llm_instance = llm.get_llm()\n", + " print(\"LLM instance:\", llm_instance)\n", + " ##Remove LLM\n", + " llm.remove()\n", + " print(\"LLM removed successfully.\")" + ] + }, + { + "cell_type": "markdown", + "id": "e8ad3c91-dd5c-4972-a513-0f04abf464c4", + "metadata": { + "tags": [] + }, + "source": [ + "5. Sentiment Analysis
\n", + "\n", + "First, we want to gauge employee morale by analyzing the emotional tone of employee reviews and quotes.\n",
+ "We use the Hugging Face model bhadresh-savani/distilbert-base-uncased-emotion
which detects emotions like joy, anger, sadness, optimism, etc.
5.1 Create the TextAnalyticsAI object
\n", + "Now we can execute the portion of this demo that will run in our GPU Analytics Cluster. We'll provide the TextAnalyticsAI object with the preferred large language model. This will enable us to execute a variety of text analytics tasks.
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "de1f4d62-c9ef-47c8-b612-fc9443a73bd7", + "metadata": {}, + "outputs": [], + "source": [ + "# Create a TextAnalyticsAI object.\n", + "obj = TextAnalyticsAI(llm=llm)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d561f8bd-36d9-4647-b535-4b08edc3c826", + "metadata": {}, + "outputs": [], + "source": [ + "# Using the default script\n", + "obj.analyze_sentiment(column='reviews', data=df_reviews, delimiter=\"#\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ab559276-bc4a-4304-baa2-7ae4a3f6d144", + "metadata": {}, + "outputs": [], + "source": [ + "# Using sample_script with output_labels.\n", + "obj.analyze_sentiment(column='reviews', data=df_reviews,\n", + "output_labels={'label': str, 'score': float}, delimiter=\"#\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9ae2b70a-578c-49ca-8d26-72c6b6d110b1", + "metadata": {}, + "outputs": [], + "source": [ + "clean_env(llm)" + ] + }, + { + "cell_type": "markdown", + "id": "09c61434-76f0-4aaf-b58f-c46c448ca2ee", + "metadata": {}, + "source": [ + "6. Key Phrase Extraction
\n", + "Next, we extract key phrases to identify recurring themes in employee responses, such as “work-life balance,” “salary growth,” or “team support.”\n", + "This helps HR quickly spot the main concerns and motivators.
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5fb2c00c-83eb-4e61-bfb0-00a3ba4fbbf4", + "metadata": {}, + "outputs": [], + "source": [ + "# Accessing the LLM endpoint and initializing the TeradataAI and TextAnalyticsAI\n", + "model_name = 'ml6team/keyphrase-extraction-kbir-kpcrowd'\n", + "model_args = {'transformer_class': 'AutoModelForTokenClassification',\n", + " 'task' : 'text-classification'} \n", + "llm = TeradataAI(api_type = \"hugging_face\",\n", + " model_name = model_name,\n", + " model_args = model_args)\n", + "obj = TextAnalyticsAI(llm=llm)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c2000e6b-9026-4747-806d-8031457949cb", + "metadata": {}, + "outputs": [], + "source": [ + "# Default script is used\n", + "obj.extract_key_phrases(column=\"articles\", data=df_articles, delimiter=\"#\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6ed30576-90ed-4725-bbba-21499fa4aaa8", + "metadata": {}, + "outputs": [], + "source": [ + "# Using a user defined script.\n", + "base_dir = os.path.dirname(teradatagenai.__file__)\n", + "extract_key_phrases_script = os.path.join(base_dir, 'example-data', 'extract_key_phrases.py')\n", + "obj.extract_key_phrases(column=\"articles\", data=df_articles, script=extract_key_phrases_script, delimiter=\"#\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5be6d656-57a2-4a77-aaa2-cc961763fbf3", + "metadata": {}, + "outputs": [], + "source": [ + "clean_env(llm)" + ] + }, + { + "cell_type": "markdown", + "id": "517d4fb7-43ec-4efe-812f-807dcd8b9d55", + "metadata": {}, + "source": [ + "7. Recongnize entities
\n", + "Employees often mention departments, managers, projects, and organizations in their feedback.\n", + "By running entity recognition, we can structure unstructured text and identify these references for deeper analysis.
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ea80aab4-62e4-4683-8425-42ba01e3ae7f", + "metadata": {}, + "outputs": [], + "source": [ + "# # Accessing the LLM endpoint and initializing TeradataAI and TextAnalyticsAI\n", + "model_name = 'tner/roberta-large-ontonotes5'\n", + "model_args = {'transformer_class': 'AutoModelForTokenClassification',\n", + " 'task' : 'token-classification'}\n", + "llm = TeradataAI(api_type = \"hugging_face\",\n", + " model_name = model_name,\n", + " model_args = model_args)\n", + "obj = TextAnalyticsAI(llm=llm)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e5972fc0-2088-4f16-afbe-ff114748a041", + "metadata": {}, + "outputs": [], + "source": [ + "# Default script is used\n", + "obj.recognize_entities(column='articles', data=df_articles, delimiter=\"#\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "612a4728-bae4-46d2-a56a-8f07ebc32e53", + "metadata": {}, + "outputs": [], + "source": [ + "# use user_defined script for inferencing along with returns argument \n", + "base_dir = os.path.dirname(teradatagenai.__file__)\n", + "entity_recognition_script = os.path.join(base_dir, 'example-data', 'entity_recognition.py')\n", + "obj.recognize_entities(column='articles',\n", + " returns = {\"text\": VARCHAR(64000),\n", + " \"ORG\": VARCHAR(64000),\n", + " \"PERSON\": VARCHAR(64000),\n", + " \"DATE1\": VARCHAR(64000),\n", + " \"PRODUCT\": VARCHAR(64000),\n", + " \"GPE\": VARCHAR(64000),\n", + " \"EVENT\": VARCHAR(64000),\n", + " \"LOC\": VARCHAR(64000),\n", + " \"WORK_OF_ART\": VARCHAR(64000)},\n", + " data=df_articles,\n", + " script = entity_recognition_script, delimiter=\"#\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0878a42e-4a84-4bf3-b353-87313db0070c", + "metadata": {}, + "outputs": [], + "source": [ + "clean_env(llm)" + ] + }, + { + "cell_type": "markdown", + "id": "6f880b17-52bf-4b3f-ba81-ea10fb58a4d8", + "metadata": {}, + "source": [ + "8. Language detection
\n", + "Since employees may respond in multiple languages, we first detect the language of the feedback.\n", + "This ensures proper routing and translation where needed.
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a7469bfb-8a89-45b9-9e5b-8e3fca4a5c7b", + "metadata": {}, + "outputs": [], + "source": [ + "# Accessing the LLM endpoint and initializing the TeradataAI and TextAnalyticsAI\n", + "# demo_env = create_env(env_name=f'{environment_name}', base_env='python_3.10', desc='BYOLLM demo env')\n", + "#demo_env = create_env(env_name=f'{environment_name}', base_env='python_3.10')\n", + "model_name = 'papluca/xlm-roberta-base-language-detection'\n", + "model_args = {'transformer_class': 'AutoModelForSequenceClassification', 'task' : 'text-classification'}\n", + "ues_args = {'env_name': f'{environment_name}'}\n", + "llm = TeradataAI(api_type = \"hugging_face\",\n", + " model_name = model_name,\n", + " model_args = model_args,\n", + " ues_args = ues_args)\n", + "obj = TextAnalyticsAI(llm=llm)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f89731ca-122a-475a-979f-2a6f7df3b8bc", + "metadata": {}, + "outputs": [], + "source": [ + "# Default script is used\n", + "obj.detect_language(column=\"quotes\", data=df_quotes, delimiter=\"#\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a199252d-575d-4c79-b076-31f97c168006", + "metadata": {}, + "outputs": [], + "source": [ + "# output_labels argument is specified along with the default script\n", + "obj.detect_language(column='quotes', data=df_quotes, output_labels={'label': str, 'score': float}, delimiter=\"#\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "15c6b7e0-f134-4019-a4b3-e1eb09252cd9", + "metadata": {}, + "outputs": [], + "source": [ + "clean_env(llm)" + ] + }, + { + "cell_type": "markdown", + "id": "0736981c-496a-4f67-8aa0-df74d450e4bd", + "metadata": {}, + "source": [ + "9. Text Summarization
\n", + "Some employee feedback may be lengthy. Using summarization, we create concise reports that highlight the main point without losing meaning.
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b6b277a2-dc06-44f8-8636-5783e46b5432", + "metadata": {}, + "outputs": [], + "source": [ + "# Accessing the LLM endpoint and initializing TeradataAI and TextAnalyticsAI\n", + "model_name = 'facebook/bart-large-cnn'\n", + "model_args = {'transformer_class': 'AutoModelForSeq2SeqLM', 'task' : 'summarization'}\n", + "llm = TeradataAI(api_type = \"hugging_face\",\n", + "model_name = model_name,\n", + "model_args = model_args)\n", + "obj = TextAnalyticsAI(llm=llm)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "948635ea-879f-46d0-a982-abf38ddbbd56", + "metadata": {}, + "outputs": [], + "source": [ + "# Using default script\n", + "obj.summarize(column='articles', data=df_articles, quotechar=\"|\", delimiter=\"#\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3c4a5ee7-33fe-45c8-8f85-034a2e6a0b3b", + "metadata": {}, + "outputs": [], + "source": [ + "# Using a user defined script.\n", + "base_dir = os.path.dirname(teradatagenai.__file__)\n", + "summarization_script = os.path.join(base_dir, 'example-data', 'summarize_text.py')\n", + "obj.summarize(column='articles',\n", + " returns = {\"text\": VARCHAR(10000),\n", + " \"summarized_text\": VARCHAR(10000)},\n", + " data=df_articles,\n", + " script = summarization_script, quotechar=\"|\", delimiter=\"#\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fd9e7eeb-9bc4-4cfb-a0ec-3d9fedd4ea7d", + "metadata": {}, + "outputs": [], + "source": [ + "clean_env(llm)" + ] + }, + { + "cell_type": "markdown", + "id": "d0a93f3d-e31a-4eaa-a035-e6ef5729c676", + "metadata": {}, + "source": [ + "10. Text Classification
\n", + "To make HR analysis easier, we classify feedback into categories such as:\n", + "
\n", + "This makes it easy to route feedback to the right HR sub-team.
\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8dd0b460-f177-4236-8d39-86cd44796920", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# Accessing the LLM endpoint and initializing TeradataAI and TextAnalyticsAI\n", + "model_name = 'facebook/bart-large-mnli'\n", + "model_args = {'transformer_class': 'AutoModelForSequenceClassification', 'task' : 'zero-shot-classification'}\n", + "llm = TeradataAI(api_type = \"hugging_face\",\n", + " model_name = model_name,\n", + " model_args = model_args)\n", + "obj = TextAnalyticsAI(llm=llm)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c6b20406-21a8-4517-8fd8-ee8908fa8661", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# Using default script\n", + "label = [\"Medical\", \"hospital\", \"healthcare\", \"historicalNews\",\n", + " \"Environment\", \"technology\", \"Games\"]\n", + "obj.classify(\"articles\", df_classify_articles, labels=label, delimiter=\"#\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f0657dcd-4033-47f7-8749-2d21fa2f43e1", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# Using a user defined script.\n", + "base_dir = os.path.dirname(teradatagenai.__file__)\n", + "classify_script = os.path.join(base_dir, 'example-data', 'classify_text.py')\n", + "\n", + "obj.classify(\"articles\",\n", + " df_classify_articles,\n", + " labels=[\"Medical\", \"Hospitality\", \"Healthcare\",\n", + " \"historical-news\", \"Games\",\n", + " \"Environment\", \"Technology\",\n", + " \"Games\"], script=classify_script, delimiter=\"#\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "892125c8-f023-4b8b-a897-e00bbbfa2ab5", + "metadata": {}, + "outputs": [], + "source": [ + "clean_env(llm)" + ] + }, + { + "cell_type": "markdown", + "id": "82b9e656-d8d6-492d-b913-8130e76689af", + "metadata": {}, + "source": [ + "11. Language Translation
\n", + "Once the language is detected, non-English feedback is translated into English so that the HR team can view all responses in one unified language.
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1692f21b-fb7f-48ac-a6b8-019b27b51bf2", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# Acessing the LLM endpoint and initializing TeradataAI and TextAnalyticsAI\n", + "model_name = 'Helsinki-NLP/opus-mt-en-fr'\n", + "model_args = {'transformer_class': 'AutoModelForSeq2SeqLM', 'task' : 'translation'}\n", + "ues_args = {'env_name': f'{environment_name}'}\n", + "\n", + "llm = TeradataAI(api_type = \"hugging_face\",\n", + " model_name = model_name,\n", + " model_args = model_args,\n", + " ues_args = ues_args)\n", + "obj = TextAnalyticsAI(llm=llm)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ca93cd2d-8d9e-45e6-b334-8b70547cc94f", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# Default script is used\n", + "obj.translate(column=\"quotes\", data=df_quotes, target_lang=\"French\", delimiter=\"#\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "994a36ae-b1cd-4eea-a368-f77b2af764d5", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# output_labels argument is specified along with the default script\n", + "obj.translate(column=\"quotes\", data=df_quotes, target_lang=\"French\", output_labels={'translation_text': str}, delimiter=\"#\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "17a1fd81-c732-461d-a13d-c4cf3797a5dc", + "metadata": {}, + "outputs": [], + "source": [ + "clean_env(llm)" + ] + }, + { + "cell_type": "markdown", + "id": "9f9f4384-9568-48c2-86c9-5e0982031708", + "metadata": {}, + "source": [ + "12. Recongnize PII
\n", + "In this section, we'll delve into the recognize_pii_entities()
function provided by TextAnalyticsAI. This function is designed to identify Personal Identifiable Information (PII) entities within text data. PII entities can include sensitive data like 'names', 'addresses', 'social security numbers', 'email addresses', 'phone numbers', etc.
13. Mask PII
\n", + "In this section, we'll delve into the recognize_pii_entities()
function provided by TextAnalyticsAI. This function is designed to identify Personal Identifiable Information (PII) entities within text data. PII entities can include sensitive data like 'names', 'addresses', 'social security numbers', 'email addresses', 'phone numbers', etc.
14. Sentence Similarity
\n", + "We can check similarity between employee responses to group together feedback that talks about the same issue.\n", + "This helps HR avoid duplicate analysis and focus on unique concerns.
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5b701a2b-9476-4f4f-84b8-011f35c128ed", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# Acessing the LLM endpoint and initializing the TeradataAI and TextAnalyticsAI\n", + "model_name = 'sentence-transformers/all-MiniLM-L6-v2'\n", + "model_args = {'transformer_class': 'AutoModelForTokenClassification', 'task' : 'token-classification'}\n", + "ues_args = {'env_name': f'{environment_name}'}\n", + "\n", + "llm = TeradataAI(api_type = \"hugging_face\",\n", + " model_name = model_name,\n", + " model_args = model_args,\n", + " ues_args = ues_args)\n", + "obj = TextAnalyticsAI(llm=llm)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4520a91e-cc01-4272-8d45-e89d6712dbfe", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# Using a user-defind script\n", + "base_dir = os.path.dirname(teradatagenai.__file__)\n", + "sentence_similarity_script = os.path.join(base_dir, 'example-data', 'sentence_similarity.py')\n", + "obj.sentence_similarity(column1=\"employee_data\", column2=\"articles\", data=df, script=sentence_similarity_script, delimiter=\"#\")" + ] + }, + { + "cell_type": "markdown", + "id": "36e02264-5fb5-4e24-a80b-9a33dfd9904d", + "metadata": {}, + "source": [ + "15. Embeddings
\n", + "Finally, we generate vector embeddings for each feedback entry.\n", + "This enables:\n", + "
\n", + "16. Insights & Conclusion
\n", + "By combining these steps, the HR team can:\n", + "
\n", + "This end-to-end pipeline transforms unstructured employee feedback into actionable insights for HR decision-making.\n", + "
" + ] + }, + { + "cell_type": "markdown", + "id": "b7e0da01-454a-4970-a651-c7f5b3553e5b", + "metadata": {}, + "source": [ + "17. Cleanup
\n", + "17.1 Delete your OAF Container
\n", + "Executing this cell is optional. If you will be executing more OAF use cases, you can leave your OAF environment.
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "241b7cf3-1eb5-47e7-b0c7-c2bf2bdae0e0", + "metadata": {}, + "outputs": [], + "source": [ + "#Remove your default user environment\n", + "\n", + "try:\n", + " result = remove_env(environment_name)\n", + " print(\"Environment removed!\")\n", + "except Exception as e:\n", + " print(\"Could not remove the environment!\")\n", + " print(\"Error:\", str(e))" + ] + }, + { + "cell_type": "markdown", + "id": "7e3c08dc-d6c0-45fe-bd6b-77a5f0298dbf", + "metadata": {}, + "source": [ + "17.2 Remove your database Context
\n", + "Please remove your context after you've completed this notebook." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dac8d030-2f89-4160-b2da-6a233c693018", + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " result = remove_context()\n", + " print(\"Context removed!\")\n", + "except Exception as e:\n", + " print(\"Could not remove the Context!\")\n", + " print(\"Error:\", str(e))" + ] + }, + { + "cell_type": "markdown", + "id": "cda83a5b-e9fe-4734-aa28-5d5332cbd873", + "metadata": {}, + "source": [ + "
View the full TeradataAI Help
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "edf9295a-2598-426d-b322-bba46a50c246", + "metadata": {}, + "outputs": [], + "source": [ + "help(TeradataAI)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "46975cbc-778f-40c6-9388-d2165b718cea", + "metadata": {}, + "outputs": [], + "source": [ + "help(TextAnalyticsAI)" + ] + }, + { + "cell_type": "markdown", + "id": "b8587ea3-ab30-4a63-9c86-6e11fddb79be", + "metadata": {}, + "source": [ + "" + ] + } + ], + "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.9.10" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/VantageCloud_Lake/UseCases/Employee_Feedback_teradatagenai/images/OAF_Env.png b/VantageCloud_Lake/UseCases/Employee_Feedback_teradatagenai/images/OAF_Env.png new file mode 100644 index 0000000000000000000000000000000000000000..1be627c311033a556cd4264f01dc9d5c0069ec90 GIT binary patch literal 100704 zcmeEu^a2c-`$?El|*mzNUSi1TkO?Atmh6BQjc9hv%rydgz!_WmKb_ zvS#-a@hz69P%B@yCsJq;3(8mPbKU$5qWpMA@_g58;ePOyuQVp|W9wb3M(8)IlK#8J`B%g*{?03mUGthE}k}_QDa}&VZ&urE{6l z`Aw6-Y&BPvZ39{7FTavT)upK64^O}lRliE&WvRv5GDUSBxAm-|lSKc+*y<=W(VlCX zTHz}oARk9n1n#wfVE5!MdQYkPGRx!@ukrNUhzaMp{JFLeC}|$bHR1(5_>?`lp~GcZ zBb&O=R_<`w*fuE1zXWO1wA2Y$FKI)RcQ!$-@q_I4 u-8Q|5`>#Q7=bAoBaSdU@P>YB zqi=bJf$~KxRZUIKJSFW;-_}dUgx}c#R#m>LOGNqNabxm*5rjqs*M#DK^2h?D57PC9 z^Zo33Mu4SwVx!K$hLe`h)nNd`=Yrw%SPUSmUWPEYJR4B1K&5&!nj3Og<)fj}r!kq5 z088$BEO{S8$2LDHOGqjwjV2brC&nN`eG!aK1=n0~=<1cXyZIWEU5kAB0kG>E0IlJ! z_c1%hd^cl!4(jvDK_gzIBXf4F>m no3%>vp7oZ2(e} z=p`I3MFAD(->-PUI$xd8>6m1^&Gz}Zcs^-E&22do?n^ru%M$m06M@P;k=^RF!wgIS zSLS-6iyq56XTd{%ae?vBxKGdD*B5-RAT?uHw$BzqulfeBuahSuz4~oOCSz#$IQ8nj zv1>=uMM{>A3y6``an4|StyZVno|kF*Q^vujX||Sgc4byKu8~1fut0|!ZPY`|f}6!A zfvcSd6pfTu^F~6(#e3BlJO+UFMmB#`o!K|k#3bvuyn3dXy=5s`J7>h{06PTyJC(Fy z1YKlk>xV?_J>EkaYcAAu%XNlymwko|muVup{-3|hFY4tGW0#S8CZmHTt1R2>WJwBr zN+m0bCZk96=)p@8Ght6MY)|j1jN%?R@2>%yd+~}%=O6j`0&8eIQ;M9fsqYy1#LdoL zj%$cAooi@sFSM(`XT^Or*)mwWXK+3O(+lHb1Dv` CePeX-p@u?yhG zsA*xMy)_v2%kEZcyuG1 r!uuErncSuYeTMfPI4;c!GuxUy0CN@w3NlRpyk>n z7rX?%Z9T8oV%vYRUlF|)Fq70jQbn-GUbi`u0q)s(NZbTN(3JvmMsX!gG99LaD)|C5 z8v$Yzl3bY~pF@z3vs@d*eNQq=3K2 xsmfM@niE-O->WzBf}@581%D z&_z8)*(e*Y-T$NNE&QU2w*KLvyQD!{x;qCEk?xZ2F6kIRN(4k2X$Fv%?(Xhx=`QK6 z-_d*T^M2mHVCL+z_u6ZH>l~t_H)?cDm*5Gwp#G~AkAO0C;N(H-@L#>Ie8Zu6Of>c8 zspg}odZWIdF~6E|W!1LoxT#CxP_f@_*sR+GrE#EccO&+D^7lBvzz=920ES|+WfN!L z^Vy&f`AXW_tptAXpj$;VE8E^Rm-$H(p@qc3>WR$HFKYJCI?jKNy^0Jz;eS~G+ZTib zmm??9c`lz6+4d%Iz@z6jf>*a>lRjg0Jxh~xqu;m~OFrQ>HHp85lpW=kTKVJdolFV| zAk{=X>9AY<8}K6c7ILO)2VEBzGVwtRJb0Dg1Z+u1@XFOcX>wYD>q@HSWe07GZ9{6H z%Kt^Q6_ytrY%T#=@*?!&KaEZXP==qExpn@jH>0Toq$9{&8fn7`6!(f_PK}GPS{A*O z6BfLCh2E5$0PC@7;05Jr-Or$#F$4gw{S5@%R;jo~Edo)zb1&ZdeY{VHD*LmI!hfj} zaWbir{%+Fo@i% JFy Hiubl~qEJVtTdNE2)2 kntBmJ=Ec8Mf@ni(RFih61J*NlIRl~77cT!i za{(eiPd(6;DjD~02hh=DqquK`(<@ozNOMiq&042JZ7a3%=@SE?jURo*nD| keTk|~1(o(xj0_K@-{@7T%Ob;h@jfDW-UCB|a zpVgik8LnoWa >P3{B*fbf z2)?w@dUV{FKOZEZK$u1zNG@4~l>qHYJ|H2r#f$jI#r nAL zeb6kRN5j0-SyyPEdW*M^)GiT(n_9|;k9o_pW?ifKo5W5uGuztT`rS^pYSC403SXO? z&D<)sIVZDfy3gK&^FdaI&G=Ld#~x=-lG2K;&1Loe`LU22U })Vv5a1q6yysCwc;iwrr&@yWG67IDBrZbK|54tWmy z@s)$Yhq-q5CaeUQ0C-5IX6_oU;!$l(pnXJN#{t51HjzY_1?*?EiikAfkm4-ONj2 z(pStSpDvr5XLOu?IjqAb*WRU*TsAY=7{f-#Vfh*AkUuXF(LnwHLkg{%&UdeSAI8EA z#?r>*je_E;Ks@em{a*yZO&NHfE;s>@s)Qz_bV{Rcbmm9HV2y%KV&638q $0*Ui?fRzvKkcPh404i?0Ioj9(D)m*xAagB zeK*Lk+s*=H8-o^UgFX3rt^xa!r**Sx!=Rb%*mvXsE$K&YEQ66 N zKH=e@e$9O;qN@AusXA*!p1hDbew5-A8E4`+j-s)CF!O74E#}Y3Cc{vDEamTl3R`Ie z{{Z=yzx>AubixF ~Rk+%mT?>0$gYIIeqH~+Vqd; zZxjkB)W8Bu@1o@LZ55`hb?pjqPirZrGIwd2_x6_`n$gqdX*8w|a%`@0Hw?;UWQ#~# zjTDs8X!#Eh^s!{dO6h5NI5K%Xe|3XRTW9wg mCP$J(a V+6$dwGNtrR`?hx5-i_`i->d-`(;}4uFH}|M0i`)xkK+QmT~46$Heg z7*%TL_rVL#8F)3!{OAwO5nFN+ysN>o{_$JvCtIGmp=J )ta z=BJ=!=+2>aOb0Hz?YPT} xz1!{`ojmdvh*_lbeOZ~R*F!d35 zsgy|Y^7Sq^PgpvvoHXvS3zHfQg3pU_B~zyNxD-d-8B5K7{>#CHt;i0w+987fOTVNf ze8#_!K~hSg9%i?huhNIyv}IEDkr$SgU`yF&OMhrlY?xGjpC5qG62vwCSyhDW_+Hg^ zNnPD4U|U |nz|%aVSG|0@hgwN|x8b{`3Vxu^~Mz1 JSLIHB|%Y>{=vez^7`w*2#AktOiw8H7maU #&C&YbAJ+TZ-t;tyr~cKHz!LPUgSe9qiLM9aaZ~$`QU5<)5ch6ACvrq`+;j>* zCeLrJtw%eXMt)wEZEa$LKdA3!FLsyxa8OscBzG3hS06%FmDAAG2rV=<6;I9N74Ng0 z`OV1-(ZguuxvO-^HGXmvqPFxJTuRu-MRXJNFjQhztK-5LyZSd3Isf(T?|#C;_)D-l ze{BE47(>D{P|FnuBcCUUMZ0v*x5X$~g|nP&{;=-q9h(g1B}|Z7zv+G3myTrhn~g z7b`0boGI-|P#Rn-4BD_4EJg_Pc6$@49XW`n=DznLSncoJhR#DVZh9R)l{b`eh@4iL z*8tcM>*>?}qoNJa`wI}%2#b6FU6t1a98?htCbmcN7Vz?XXteYj3hE+)6HbM{=h^`I zP4i*f72%~Llala;9srHF;>j%Aic;ere*LB#WrfVH%4VdXJ6Ya0=PUc3EXwV3>Q|B4 zSXJA>G()LKH~UrUWnuD|*wf5gvRpuU4_j#P8Or-J-)^TezK(H<-b_L%uczT3%_i0g zu |EkQ>z=*<{g#xq-@S(_ z$q{}=i-g`3@1C|-7LVPu$*@AWiPDe6u`ZZ0M16~cSvKO|P8qJPmqbHFyW8nG6aU7< zLSR;ssbSdtd(h9dD3guoTfO5@Ad+ZC8)IY-5U$`@nmNu4{Yu9y7X4 vDHvHnXqjos#vGPa$WKgMFjQZ;XpxVQ+(GiX;2DXH#MGwOsF<&7P1RQkFT&LlOYP z4R4a7`B!Hr|Bkb4+M|Cll&!4x +PRDrm_HoJtfN34j*mCYPRv9w>aM8r5arpkDwsQWFlg<7BdtZqmGduad zdv&QaxX{h(YS}O0PrA}UC{(u4(C^1|iFfdSKoI@e!~lwH?&g2wj=z`=P)H{`2W5a~ z3V6f|{qCP^bx4ofZuU!YOyVK7WYbqipzdjuT}C 8`g4-%kB6gVQx5pq0sTIVOLY07g0&&ac|43eneM|I%mSt3|;AE#4&T z6wrZ9Go9B`;GT3?c6kH|O5n6MhpMBZ}xioseO NUmf+42I`(&oNEP{iB@l&$78P!68WN=i`IDRy%Om zCrck;=d6e`d#2erKx+os-RB1q+KT;&f8c84A1*SpXE-XP$Rlvz5`*K1c-<$@K9KxR zFm+@j)3;CWt0-k3H*Ii3&Zz6Pk~7wU#7%=e4(P(qnsTlx4EI!zMpRX&3bH-(bl0UB zu*WAj0 oZldm2zgLT6;2Ebc&GRC;)U%(VcIF+OH7b&PUlQwcOnoc~ zRAzjRfG`vn15fKFy9hL|-otZ544+YhDjf%JAaaCEDECHzwC!d}ID0oqTA0S3heFXq zI2&VY02!dra9%h6?S{{lDEa0WnqJmIF@ZbEnQeNXvDV14TY>a5&a9z<_kSg7rN6cm zT%~)j7i9HR-S!W24t{>r9rCa|>eREEgtd@W>$|v-?Q`)soX*P@QW#=%|CmhRfEfnw zwy5S=?_U*pFfcdreXk-plb$F#Gx7lCU^V%CVJK%k?GO;Q(yHoA<#Z&>UU1U<6ZHqM zph*PAg~8Kp@(R8x$YGL~ks?)~0G^1nxHRWi`ewsv>$6e@=E6wTS>x}&-t5eJgkDtl z4RhxfWoNS#q7KE!bm1qVoVNCB(L1F5sf<&jlYM@!(_u|b+8?`y>>Br`b1^t}cQn|S zn6j&_mO0)xxBxi$tHutIXKO-5B(FBY{XI?W a8rG zipZLOZ2=+q>jIC~4>0SBo3~aX{hDu^obZVZ+G{?_J!{b!KY++c@q9}kN1}~qoo#KH zqhDc9QWmi@Us%n3ts_FA>z`?9N3rs+rIR$GR!gUjfC6}+C@G2&^{&j06IXVKd`1F` zPSWsx_;XV97<14Pc|0H~3OhL+t%k&p8q(q)vc*-pCEEJpe$*-J8JMEMo;9CCQX(H; z 15 zPu|k~IIPD)TScHPXTK|mF!CSi3w1z$DDl+xnRt3w`FH&2?;cR;)QzPJHrBMq(RCr- z&2&?)lPH4QHwSV*t#xAj>3^&%{`@STlO85I*183#k7DaKr2n?Xw6HNG!g1O-%xW;h z68T}tj3yQj a1J5f-#vIYJVhnYse@lMukTG1!T`MzLUB>elW zOzj_qpDJ9*sLIq}MIL9mSJ!V)v$&R9D;BL+9uC@k`EqHBsOOk_r2tD!^Wh~BGQ-7W zBp%oDfHlw>v~za(ODnE0gL?wh>*~q{T-v0zDOzvlljXI{M@Rl=hedwF9L N`gwMQR?iCm89!OpEXnQqFW=D)Z=g- zp4N1W7th(4v2%f1K%z4*O0#0W(4e8?4$gl&CUsMH okZi zuFaHrDP7*FXM86BrUQO582LwD>N0vY20{0~)j%Rv>Tgf`_toaKTU|NGld6KL&8rJP z#5~iXQoRZmF?`zC?Zrr;-j$y-{fSNMT%u=Xn8Qlv_%PllisNMsrgJ8D0 p`@d^8Ev|K)8QhObFbjG0X9dCwS~x7B6+fSx56U??gc?){~u z0)hU+T!04cE4(C{rz+W>@3ZL@;u-Ul8yklX DCLjoyRGGl zu%(7rlFN;|WYt z@*@%JDW`GNf=MF1-(^%=B(R_ceSiXiDhfr(*^A~#W_g)vFRbD<`&!tet>4sOmNmsr zHn5!CX#s#`EgB0pW&&ctWMQ`SdCr4cNlGN8oqnMlc$_h_yib6-Z44RR;J?oUg0;qz zRu8BDD4ErbM1O|fpnO3$nRi>e^S&R~+S_j4)CSF$wyDy2<4@Ce!jZ(yr}rDRz$# zjQgj!b$c0JsNs4f7mS?quKm%Y-7f4|H(GuzZUAIaEItrsC7&s=z9qr+Ki_VE9=5dl zAzfl;T&RjqsLA!Nj<9Kd+_ugVb!0ZUckYPlh*-hq=m{QtaM8Xi>L`gp4hyYl6KD<> z%R+mD>KBLNO-IsB)Hg6aM*Qg#yC)9qiB$IGKl?&DN-QTY{4Q9yvgLGgUx?jeb;0(l zX8pHj3hnj5@2``G6AH+c*k&5TPSlPHa4!tllokeaYkPzvuZ2X9vJA$oRI^Xm4>IW| z)LCJn6KyQbL1GmsNiUK~`}$`zK74)~q}h?@r0o7OW&*$!*s6%tp-8QL{U7m}f4dfJ zjPkDc+m tOazfU|?aK)X$+o4*UF zB+Z00-}zna{WmhDkWgA3iT>)Npl`4AsmoI8CvXe*j<%guELM%#M!v)LK`1dd6CKwi z(^uh7P_AE=Hg&%kf}j#qV^(d|3K5A)H2z{)$Ztrm%>c<`*8C*ae~+1Tn^+}`k{RA8 zB3TUX!l*$L-T5@cXT2v;vUx>FWQ3VZ+^Rd3lbxDb I=FUZoa7Q{SFlaYv4-r$f2fhX2nG zM=42}> `&ECG|0w_1~i(!$xy5`Qmhr_4eqtP#r>?=!R1ye+429JNW(z> z-)WK~y&BbrH@BR;rjkoU#M~+952m(P%JG7CC+}4dz-Lrgyk4;{KONuvHJ^rJd2hVv z#sc8GuE;`~*TB! <8soUa=FHE8Ra0+7{?1apgrQiGrcy|Bzoy=obGI`7FZZT>3qg_;*xoQoK4p@m z+op>)lJ@0P*f^mW5bB3vQ=gXn`5R9*Ri1ZBN9^WbM0~Dr#3=D$v3&l(O;%nA9;%;R zK>!IQ5E-| tS}psj;h4v$|7TWP0ll>CP{r zF|ey)E9||#A8; ppSU}Pf |Z;# e zZ2)ZJ1+{+fc<3Q##fd6V@#6yRAEi+%{wJK zdno_oWnrP;lmHyiy>YO#7m&B2{+m*Px@R2#TuQAhN}^B=GgmA*>nM5+krOF#v8hcA zAoI=RK)s}&;I37|K#DvZe8hNLsQY~<%xA_+0u *Ys z{|YByUIl#iA(`HpJo3Lg4tU$Iq^n&aS>Lyai&mRM#42IKU@59%Q E+O1&EXuQsiHA*J#J3qru zGDb5TG1eC9A&^~i*fXd5`Et29T)f;Oz`~sU&1dCc@b&fGxVpQ1>B0z~+Q+L~V%5+9 z;9!~gxMbZ<4M|{MgZnQ_RHEmB;FLH5B7usJ_t&B{(An%)m lqF0q?yK^dX4U77RNd=}wd67*%ga)_qqw2sD}9T`!jJJ!e!j_y@->l& z3b!`HdN&rTI~J~o%R!~&_u_wfeJv{`6;fSWD`V)_HX~m*L_0I1!DZTuo-EoTGdMKl zQgT w(>+x(D%{O~M zfI+zTqF$j+qYS`b&z<(A8@sWEh&iBiD=qv~c5+yz(1~k;tzdRf)+CUd2lQA?s{=nj zB@>TK&CQjqD;|z3>85@Kr;|Kdjc31n-=ECPudS7|7=zMQS&URdQ*lHsa+IhrEZOhb z#i1bOe0n7Zyb%e?4EV274Y!TDIo^FVlV?X1=4 E^ayFxJKEI-zHijdnfB?|V!3u*lLF*(hn z@Yg`dW1qsa-w$0})B)VMjoCdDM1jza`mxJb0rIF{;69_EyN1^t*SnrTB!n{Blzi-^ zx=U%a(r2bz xA5J(>H%j)3G>M8Ae`<6+1eTrTH1z1D;6 z&(EPPLcT>OuIuJxB@T0e5xMs-TeCAWI#gq63svS58y~nVN9_*ljg3wKXBO9SE)CNh%CdRTo`RelBWnkpb2s7514piHU)GfEZ}$>$X?N&+nT z=(D>M=CySG93wZIUpP<8Mg$Q3_3Z4_+KdxQG13)Z(%j(2!_x=9(FGM}AJrRwhgGz; zHNRT=Ce>7P?%cC^a(S6G1d{>)gMmz<_#Z#ylwY o8QcRh5y1hiiU6$vSQr29DW3m}9CG3vuCTe9 zPh&fz5Rm6IB|8 p=KeY^AY0f>Ib1REvL;L)F5{0_p?up> z3738ld7cCQ!|K v zSQ$Vc_C}#604T>_#QIOjP$4=|(z~@GfFo@FKF56qVZ*>HxZaXAZt|C;EsC>R_dFhV zZ7ehk2-c|=cgLzo=CJV$yM5kl`Wv(GH^%7vW#Iv{UEr7PaaD`;Oq1O}%S|B6CSo2E zGRm9gXjH1;#OUZmcvWcwNPk9R;+I5mwCEd-=r7UAutY%tAUZ_5-x2l$wRS~`Kiq3t z9# FZ* zw48R>GqEVw1=$Xa==@<>wC=+zGwvcOSg`ip1=&)#$=oj@g|vLk?4WAV2dQxcL}wu~ zOdD(K+&IT&A)oq$gTpKt5TuSGYX(14s%ThiL!^1trbZdVABsPeIMM8N(GSX!P0m5+ zU4nhJNBk*#=t2g~tPWu#fV}U|$HJ%d5wpoF<&Mr8Gi^uC1-f ({WLoitu6h}xm1+H$J;%%;yXkUq8 zocUkpjQX<26uBeq>mBEudG}{msGMnkRG#=YG@zvwaEO9^NWi#>^<8A`I(Ljwf;6wS zEv{aspcQE=p;~N5ORUn1Yu8`^Y5_%{gZ=wjiBFrhk_(~aiAGiBL$5;c`H9fQLo8U@ z$q}8Yu_e%veoGKpeegu_tQZNWFjj(jc4YX7=!5;N-aWMTE(hd6G|d^^YbAM!&O+2~ zt)OZCjy#=wdPBtjVpBxX5=*ZxbD|2(WcY;a8>Tt}g+55o=U6l&@#y+B)BEa@f$_a$ zZg0LM@JuIP5LB8Vnt;e0O*+#u9)l@0jv#4`V2@%i;BfZQWkBQvwo;u*ENb*ODMVze z$FpMsek2t!l(Y#S(IFO>b<@G2xvvJ%pC@VUteTAe Y8VJYErPjzh7?O+ia|r9&>P6bIU4GLKzd^vLm&V5*So8{a+YQpNI&xNud{OC zXn|kt$y{Uz+D_K%u^sH~Q39O-2)$~7 2Nyp+%y{+$G3Z=O9Vdv73LV8?%CtIW z_IpokP)}q)5&{St(M@EpyR-PUW0_Z{inhzx_*(-X(Tvc>8p|7UA>_=yeOHsW7IZ3f zc;>hjLz*%&706`<8X73?c5GnoL)}#r>8u0Js{P?1y;F B$QHcZ8Mwp~i;f&Rqjb*IV56dM}JrEt%>R=8;lxx@6vX&TF{o|Y- z&!CPB|6Z}#^L?|9PNM`P60~Tfxi205qjpqqL}1B!H)6D+epSsl-cq}LXFs#Is-^*+ zd{{S>y83derutr*)-XM=XT{K_&-ZXTjaKh8lO rMCDzaUcJ2DqV(30j;81B~I5p`4_TpEfP?&wHN-R+{BoE*Zqnx39S zFam;jk{3&oqLY4{wspW~R>}bA=MicTSu|-h^eNaN7_g?*WfCe=k3@J`Re;`=cfYT5 zTd2XdeKDNphWh9*E|W>1lyMJcm9VLr!m+9}u`aSE=gQ0PRb=B=D5h}kC$H?tpz#~; zNuGm@5$Pf?iQW@k3^C+ez|6n3#g4Iy5ukgKMl-8KaA vQ5hS;gz8w(PD zW0Hw#UP)m_bUmx<-n>#x%npBzZE2yYCM8AxdmbcaY}C(Y*U;e3)OS^dF&`|4#Y$QG zPSrj1ZOpJ7+V?<&H{;x>lJN@Cz$$mM0H5dL&X6~%EN7_5zhV%KvZJ4?@F?8fb2#Ul zRvX_$iX$jpp_9)!{qlYAAS|5 6u)ZT66;Z}g#H|Z9R1No2=MCFGa!^HzZ7qACGK-cqB&?Liex!=E| zU*aXih}MNxCnZnmc3e+%wV-8UG&yqC_sBy_OC30T7S}rwu~DBmb%!?^!%@)+%ge YKjs5WfYj+RW% z;L;P3d(ELBN%8BTH7rlkUafrMAqB~}%lEXJPmE$p%S~JMfKhX*x0AY_kBW 1R7y-kH>M_7s5j} zh8e4pZ3EJc&N-(1ahqbx<-+7AVJBftO#|!@HE74V`P!0k>IRR}^_$$MR$3k;LY>@K zO<*i6iobx;zHn;kR+@3L>ehb$RaAs9Zd@adD<$uB1qK5!4P=pV3%-04J~POze?}7i zTCp4L#dp1O`xQtDd83!4x@7Y#0rec21IeCAoviqW6Ez&zgb+@6g6lvO20qLg{aON8 z9C(Nlyh=k-;0WvpNxg&huzPXVGTfR}#z%QXWTpcc5OH|&wi=75#I22Tx`+XVE2MD% zD*=nXHe|vIFKb4-NE)cq>bhdE;KEio+>^(SQoi$}J9;l$kC>P4&*i*7b~hbavpC=V zc0U*4QZkfJ2)6BZ@v65UfY8*5sftB8E>FhQJqZXNx=0vN@A2$h77`{2`L{TqE>{ zIfCMSAwi4<;=ME{%eS?Z;)OKx?}_|#DM%##Y$6SW$Z)dib&T|AfFKFV9g}E`9=(HS z$4Mfo)$I(rlm;16jrI|hPUbF?uqXtf9;<_V>EtMvZ+;)SF4zH$Uft?vU4QV%$cT8T z06GLch;-Q5n7_p9VrTN_hj7rPeBQ>!tM%S#!abPs&X`KjIs8(jYWWp%u#lqB*PD0{ zM8LJs0NZVikOCp96J&ZT;uA@f*(Hf1hPk-eY;?>qpPiuMPY!*v1^LNDp&C_WZ%naa ziwp{T_XeYs3jSjmw(TS6af0UO*NU8P-?7zr6reIYgZnw`V)I&&Yr&OiNo06$NeAYJ z!to3Vc4GWg?SPIe=N3^udMX4bqQAHyAxx72B~CO@wapmM?T~P zSJ|bpa@b|=o-P?(roCwaC!RaKI9sNpMTj&J;Y!ROhtWHKalmSOe<#0zWjV=b?dmx4 zl@6;Z@n+f~|If1SK=2t(IFGIzz1pZN2VgH@NdjAY<5ZeX!pdj?Z(4>(h9HK3i1uHP zgD$u-Vs
d2g1oFAjKDO_*9$)-HsSuv`%0wy{1mYBIFnw zP--9i4b1x<^?F>&Sj5Ad`HSFC7gq_A62^~{u>0l#@}GBd5^2pp-B*dtFMk;2&!8eC zAef*S>mD9Tt74}YCMe aEvj@L<;A6*WIo(J^ct(>dJx1)<(KH@h^&d-2}~@og=5B59D=>MzZzdU9c3- zwp^ec2;;mk`tYuP@>JG5k**P8BRJ`#@gk(!b^S5S;g#1DP$De;w%N(neYNZI&wI{7 z`mV4sd65)v6|b(Yv=ouc>AyH;ALVt& 0x`PEMeO=@!^BrHO#`SbQ)JTn+&C*YXAeWp2BQ^MO*nSFu- zGjWF=o^~2xMbX0CgpzHrUpswaWk8`4BjoX+oFArmrQ^O0+tsJX8zhg sWR@Q7mm!0w9 zWbTeXjNkPUZ2!QoL-FlGiZn00@oc=5K;Xq_Lu4-Qz^-C4_kfLx^h!rWh0qQISA4RY zunNP+&!TZ4PtTEJGM0&BQLopVc(#VDGzSbw@uokMZoA&IXQ6$Gv4CgOH}+8`qAa&c z5z1gu+l4(%R 5PFb||vi;-vp$IRN5yE2Cv3im?Y_x2A0ZWV1wX=u;o1$$E% zi;MY}?22Yi8YBpvO3w#=m4U&c2UqSuf3(;7-0*~dltC;MRyPb)!eWp~yrT&*c^%7g z%2+Kzx8o&QvZah1s2V+tfKKLwn&j-S1+$E*Z+6InWx>LpU*MF*T$J53ObOZFJ5+?8 zF7y#Ozt^E0VZp|_><`toc6TxJs2l~Z*@1E0lmQC;*TzFwWQd7HAzGn#TLW=GpGF&v zizbnXhKgEX 8H%e zs %OS_V>OF|QbD1 ^EdCv`l+AerK j$b~+2*x)Os^tB4;P UNJ>U?hkjY( zY9|AU#PEf(2`f^oLlQIZY&ktQyHkXj_I^@wqXvBq`COdtvN(?^_FejW|LHpem>eA2 zn2%zlHLMo*r<^dzVJ?h)A5> j`IMMO#C6*-P*#e2G$c^VB z%xBDgK|kyaaCe)O6u@wOajcl=-aTfPEFq7v1;(@rF}k-dy?x^6ECX8Yt6EaWQBUZL zHW&kVN?ycd;#Gvcw|rdU9~JT@YT64xU_y>@xVe&oL)^N32LUlKNX~~0BeZ`1RZQ`u zC<) k_JM3l#2Tz!%oe`Tc zSw>aAW)(>1t@BSSSHHr_nu+Rm2?WS%{pCS^i9k-b$7Q$(ws6{CA5t8BSopxV*XPuW z?DW|aVtn$IL-FbVS@gNE^9g)sKDEp{%HR}C%1TYvV3=#GC*)L20ws9rzK(+SO4Rd$ z@5HSoBHr}1XCZDb-F_^}L 5S*)V#6)En;*J%S02)M3(5&M|+i&t9b(8m7XCW_A z+sN199ETHJdf&TxOx65FZ3GQmgpUTzJLO-8SYqj34DfgfC1{(aw))#~6GY>fjBrJy zBf#E1Rl7CqON56j)(REY3@MN)vb!}jZ(YJ;pNmQ_J7C>CQmtcJP1_FGO{zghB>1WV zoJ%B`%5@9gtcq_Vxc_3TQ}e=+(05`Xos#g{G23jB18BI{kPspArZ{S&OEc9;P&7OI zylHZcNL*w3wJ#Z3W=KH#C|I{(b9rRT7F=4-*YS$_Qb>#A5vm!R1d*X2<=iAhgHtv3 z`GUX+Lx9P^@+Pvs2S;cDEElxrs8d4Tg$#XM56hu+q##RX&Qn`yu8HS&L1@oZ^#>Cm zV9RDO$Ae=CunCev#iEMxLt5{iGN5OK?YPU_c?wx_?9Kjpv)?hf*|E_lXFslHeye zBjD$7^qBg54&QP&i&+7#$xCr)xyzg9OdeoEGrMTxFPw-QXq$ KxTXt)_tMucDwF zGe-5GauvGX$Cv;E;)X+X7y09wT?N?_FF#E18q}*C(F?^sQmcsa{o_*4&lNEaYv+>4FBYQc zI=QZvuD&|S>Q7eJr(}R$@DxCKx31YwqSX8a-Z9_b!$d6N;t+=8p!^h#xE^c&N~?=~ z%w#%_SnhLV*spIc)({PtkyKUr9xv=QO?@<}`4{z%iDF8>PQ)xS+ICBJ3oZ&*8L`?_ z>hYe}W`fMK5olDyv5Z)M;)d-q!{2p ErZ$_1Q1YWY}Ouk{H)O z0{z|!jZUp2HX>elSC6ZM_O}r;NC2LY{clYhhQ;MPNWfLaU%l^04j{kc+wb^u_d8!y zw#q{OqX&jTodcF*?&OM7feG_)M{pv8644aukf4Bz)Hv1Nl!=5mb45a?o0>4mTU8@K_+= zJ0kf +M$!&CGGVxboYIXw68Wo0IIwR>ldz+odjZABl7sGBCTMay*SIGu@;?;0V- zQqf~&&E-cIlC<7BZdWR#zX#Gr{ZXClY0p3$eDi7^gIC0? l0Fr#kG++y}inf8))31=2Fmw_pKrUUAK(&Jd;>v z>A2%x%pOzUET!U AT5nh 8sHD<8ha!n-HPXtFL|8nO zUCtzsQ$T=Dc0Cpqjp-jokcpvZc?og`om#=S!(~b-Ly3<9D1L$b%D-k(g_Bf*ei~h$ zwxePhij)2>6@uS_$pZOg5_S)hJ$tTkw2Mfa6Ml&v3nJbk_ZM Zc1vIP{3Fa-i@UPz*+HgSI)cCJ)&-E+ZIm8FR@2Z~>l<7=n8}8dE*) zYI+#zrJmRRhia!M5@S?y!#}@UqMje?@(YmIQf(TKhh7vl@VgQni7>~zeAk0Bcn9*Z zTP?LLtpu#!xP`d1hH28LUU}Ub$Y#=aeV(9hB#=nxid4h1n@3120poqe=JtX)C-Ra- zTMMVC(uVN|8y)X~7Wd@chvz#!E!!cz??c2!LTe|h=ygJLuSUP;@J8C`rPe_}^dfOz zH>qRA|830A=Kn#&jgH#Ii0lbM81&9!-RMhjG7pPZABcj(r}K3qzL+BN5%wdFt;L<= zB|6T=%<)g;1P-xG?0HeDMBJci2Z>iMDxhHsi^p=!C>${YTg)r}KiNHYX(+?whjt*a zOG0enYdC&y^3so(zhj@YFTkcH>21xBP=i(PZz)2M``>CcWC*P)&)>XDEwYtY$KOG< z;5O<^dG=r~)yK_uhkw#?Gf_5%>@f{m861mC7SoQ$;nXpf2|Ff3Wv^EIt4IT5^oX zf_YmX0=Mm7$e|O~rRpK#!tb^6+4xpr!%P41>?FqPeq+6k$~H3MP*aJJbA0N4tgjy{ z5dl0eGCR1Btk9bB?PD`m)}Srd$~pQqJhpc6?ljE#pJjA~pMJ6ICfU@F!UKlznMj?( zEGxyl(sL!>+ZKpDVVLTtD9YnJ1?4)p>Y0bM5X0vBm%_e7Ju{_PU$&~)#}g6_HTd`Q zqWmPJQJc^2Yv)^|3_URL3GsVtTW yqwGJHL&WcAa#7=pwidSerG$T|A9FH`W$JRFn;Z^l1t;} zrtW C0(9iG0-}(7{)ca%p)4mTF4OiqE^c z&)F=>WhDejd=6 W(U) Y$>g1u@VgUT#g5i2-9h-VVR@uGc6 zE~!e0Zm^)!X3Bq;*>D2KQ<34^GzaTo7!6(2luKO|!i+{TA|*}4T}pcQ{w(O*9~0~- zEQ#=fWbQx_-@$Vh>1wB38J;Wx|3h*jU6-}atK=fh$;(0UiV}jM_!@W!*S2D=)Y~9^ z`{~Ce_RTxQ#3kc5tiQFw-(Jz|C1_w}U$1GToroyu`#p@TAs{hiRqUuPjI_N0{|+!C zfg<#NoyZ1(izjgRj_@3G6MhlL^Ly~(m(;(CDWbzDtFqP{T3wce#yt$Q5H5afGNdv@ z78`R02K@#56y;?Z#5H515ZpwKDccuM@ezw-A>z#4{awSH5%!kXRUL#5_juYR1osPN zkY(tq$62uJ#GS3F`HGhZ7WlG1!(_?u`B7nd-_d9_!}MW;8~8$ UfICj`t05a>;rjKn+j6lV7Pnxe7DV+-uP*0&BnpH9dkkHg2x z)cc)`8g_rv(1@QX?44RJaIw>D+&rv{?O~y>Hti*OM+Y708Zp~!;|5TkH6*STjpPwr ztD;=7&Cei_6BQt%N99I_!!0v$^Zgb|$&XHuoj8fbc00llDvToO<8j5_anC&Bo@ua> z5E?dD6Ox1OxAAjNLz&LI_G=WFBb0y++`T{8MoQRgm~dd&%Y8fChxx1UBw~0f%Rsaw z1RZuZ3GYd&qs9gcOzpf8+K1vE>dVGa^a!ftQ7ae%H3#^5mtC4q6NP+)ca+t`VftHn znmbeXJ#hs;8KmlAT9KS~Mm|x{CL;au9G?G{HvtO_>c-I=b2fRjRYUtbMPpwhu|WL{ zvjtH0 K8ZxT-h8D4qdx Y zg}{%y98h{;*-`ba@W08XcX2SBy}FbKVZjLxzghc>s?FE !9du96_{t#i_c z2(4C~P(E#+D4EKCI|02R=U%yM`9w8Ygd#TfY0vC^-27On-qB=k-ouLr?(w3xm>t*D zt}sZp`^oc`vqn0j1{JS|8!`<$Jjm%EK#tYP(Y5oi`k2Dd>D%(+N09}7;6$NNKtJLj znmKkYZ0f#G7+YbW4n32k9`AY}(n^7!RaSFBqh8u*qE9JpIPeXW$#EFEI%UOv`NTrH zAYw<1a*6(O!&%CkjDhR^K5=(i@tne24F;k&5 P%10|ru$xWa=&WE(3DmAsj(Y@+w5Y(W z=8X&ZK+qxN)Ty9gsD+qmNxsc)`2O09IcrXBQYuZ*zLYycXd`fFb|u^XGQ6!B10>}Y z_WuAdLC?Mz;2Kv6aOe7s^Jv!OLVzts;VRb%m#%I5PSG>lj!;*RS6s#Dfjr!t!tBw3 zNmi6+p|4zb9?h;UA!~+(VV6Kp8vVf2yer*XAEWM<9v*ft3$FV*+2)@&?D|8g*!Jh2 zlXrJ7U4AHaxoqzF*Hi9>?4m;t)ds^YKR!T@EeiCU3)iO0$x=Q8k7T%i!}TfTcPpBE zaD@`C+5KDyzY8=7)}S-n$Y6!;4fOs}jnZ=nd4G2+c^Uxp?0=CQ`xxlSk*-_)+&{T% zY%Rc`0)J2@CKcd`2Y2Gj#D9d|2zQcCMZuu>GTD?*1bX<|SO+J5axwmTr%kD$FMs~i zV%ICLze$fj`AqEax4-sf;VQ)d$v40ElbGPL%GOZ}CaclI i%Ea$t6vgj z6M-IP?tJZ*o2ei_PXJgyzw37~J8W398ZKOy#Lgiz!?Qpln@0jY!?R;bYh}wvR|G7U z2nJgrgia6CZzo^ftEBBd0k {;_KhyM3Wg+%5Dk4B#gSrVqPx`CA&u+kogWjmOE?SWf|L zN1*3phMtQTA-|c~Q?P0y*_W&)Q`saDa$RG{Twz~fk}>?#;q=nB{f+d8XLlpA7T7$n zJ%>JD2CbYgUA;`WPN|HV05p->y4>{rKfX@Ko1qaUSUn0jque?*A6<(T|2ea}R)2NP zMgv`c(Gps}Y#NmofOVEZDO;X78D#Q|>}s$LdRYJSMS%1Qi*BeFVVbj&O0GZs!(piH zBwIe{?4;&jeg^LwXsit !Ts5596S~g00zGrrK%?ghq0!@Mt|RA>H_6+I zXr3PE 0vJFi34P8`k{+Jp)}AvuM8Zh0jucuA*1t>T%N@ zKl)kBwd(SVE})AqSbrLGhuJ*w`aQ`4Jq$Sg*AKrF6I5o#4r}VD>ASamg^CIb;8yku zJ^lO^vD;`g(tqCm6#)RL<^J))OG4*I-TvXXZxi}Ei9pX)aP7KaUGGHBPkwP1HG 8#~T=%XL{pxT6755oe9AdlKaHiA8p(WBnoG+sv#8Z-#O )wqWU5w;>) zghIEMfxS~gy4(tYJ(Z-*1;E33X!Edp7N*(K_{x&)S_I eT4nU7rp~5no z=lo?gblv%LS=YNy0uDr9yZa?Ne4;((<|PX70VNZ+8al|MHp3y-FIYK)KCo^+RhQ*Q z+s=%Y1bQ;#KBc;st$+9y`Htc_KFn0|g N@xuwf*Y}a-Td%L8k+HdVUakSf2vF zo%r7mm_H$30D&L$lmpl4()0d}^5?BnSUt&I;+T|@jGi$ut88=#7Dxnn24nCHq3NtF zIvCKyU`qi2o~4Tx(mLqd kIj{-Eb*U7T3VnDu$$ zQ?fu$Q9(X^_xAsYRXud1j{fJ~2V&c-n^OX}u)81lU)p!@kk~)9rkZZOx$pUEj~=66 z{r>(~y?_7oCu#P~>8H7FvB>no`Ez6Cm?gw)Ax (?+QW+1CsMJ#Xx5qz4)30i%bZnbHC)tywskZn$&-fS%ruK?Y$sV!^Gy*+R7q z9TXCb9#l}#8LrI@h{Tz}m^^*U$C^PsBN$rimQJN>FIYrV$_t`xX2wbaJ(+QzQrSxp zW$VG=vvKrQ)2aM(|DE(D1i&70Y<_?O4M!-9=OzRO;ObgQmL(e~_uQ+5%S|$k1tF5( z^j|k7Q*^*G#h?6vjKVdbb^1Rru0YR%^#FRVCPPjkweS1~!ms}yfSx+xy2X=5EYPpf z11QA8+ngeBL-0Gg0RlzHK4S)zuKfrVEI40;E|0K)Ki7-BOM2fa{a@|K_wu>IVI|N* z(Cr{k;~{ADfYBp0dSb>sQg>A3XH1(K+m{I$?sum2IT7SZmc^3^_hGF1m LKo3XvQbm}j)=UP_(_4otbCj=N{N|omJD>a1$7mkhyAl~a zH{bXPnllS7w9$0e-G89N(SNrR=uxdQymdUAhXEZ1cH-S6mto(pvna})1bT+|I~l)P z_@MST>>=-=mnhf-R65`mu2{NUuy{)5!d+<|>GLOvC|X*CNuMYw1Yzc2cc%b)+=q9Q z`^Y}>wKq}F&rUeGT*gT(>y-7AGSFu4~Hk z=&K)ENfm`T2y?F3uG{UW*Y=#CO)u`H_AXHP8JXclq`sidpdgQ^)>~I;M%`BWuzuNe zy5{_a66lFqSgx|i0xkD`o&5E^LXAVcvb-xlNA{JMB~{J2{Tb?d7K2el0qHO4E2dEK z$Nm#y{mC&On|^x>Sf$7MYbvRI#_Bm#dehI6Dw|lSskxPkiVE;d0?06d()a>B8>sj! z06n&RYW>&a)b!$mV9+*_)?yXxSiJ?V;8r`>J75!wu;dyFy4uNI{~kh_cVl9uhKg2Q zCET~T4SpA3#z}bxpWy>-^lm4BD4d6xM-hNMto7$@t_9HZ5`do9r5G~|eb+tsV5~ig zs6vP=bm4~4GyOQUlqr4x14Mq= ){(3efu8=ttDmWTmK6BzkAF^GPNygq zAGwM_q94Ic%3{GJcwCAHdOmQ)Wql%H#fvc~f;IyIJ l+ohpWmE!&k3SHiV@(d)w)X^`Y;}?!dPrjh@^HHh zHmzSiLjpa0?v~uh1`BxMuGI#&t&ya%Tkj!5Vfmm<1X@o}GwT4U?7IPKm=~_5;t$<6 zz|p?DJDAwM4i&2WV-tU&1XD$?hGJq(~H45qEG{RBA=Zi9B-NivmJQsMIV zf!VWCfI;B^0xYn*7k-0+-4mM}809+`ZI^X|xbM8?#A5_+%h4#KXJP|A@gJaUn@k3J zxc{8e@fs3A9?9fU?o~2>M+)@tIiCE-X4>+~KTkW|(na(86|?^8x4$1_{9JL#g%Dis z4a+_ppoayQe|!H!vGZ?Szm~4N^g^-S>F9z`^F8DMD9(w2pda0FyT~UpdL+;z%rdHf z5<#BCf18QNv&Dr=0zISpGa9|dA{ZcrdfF)54VFs#G3fIgK?rph=>hB*Di@KCSv-iQ zMTn%O)nmY$6 V&+Sp(nv$ZiI z4rc~)*Ww~-1+^@nG`de5Q(U(s(8G3-Dcda2@#mkDdj!#|G+ ( zHLW@KED_D5-wIi>GgUxO^Ba!>=(!(2Pa7HYa}jcV8no}`k$u_ js=)^B}5K z=g#NJef%(VqbjLr &e`1pyp5>ed8h^dtg2s@c;KBvJb|&{}2mBpy$fYmp#N;++}V z_Gkb-O)ahT EFogH?=;v|8dm|4aolL+D@f;{R;<6XG2h1Da0 z9`){~**XkRC*(LKB5j3Sts=BKMlxh5nL+x>#h}`kq*;$s-yL6jGk~6V$X$03oe5(W zvY3p; >s zH@)@ZL7l|9N;8RNm2KAOS-*T57(I)n>y|K_{F4n92zy-A__I&oqf`Y|hkjMY=@7ex z&dp$nb<7%n`mw=^#g5xA`Z(pSxhA$fP{y@uD>?p>ygpEW?Qk@vimyKecOZn|9zuF% z^NaNSi!b-7VKJL&?dr2>-Rg4?*~HrCShj4W3g~Is_9tq30YFb{D;PW+etinrXPr%j zOD`o` 1;*RdVcw*5)!soM{rr-F)CT}`%{MHFzfkgI-|VAS~A8z=x*>xdt} zeb)IIMRqN}pI9e|fgWr13@SeRYRW_OFdZU}276ee=kSDN^b7>>sQ)g~1sqZPlgxS` zphvBn>T8M@cpd0NQthi;pKgKC0D8Dp*1%yc95r#+^B;WcYq5w~>V97T4(yu)VBy54 z6-yUG?D(2t0X^JKN2f!$NHTacP+GNODP4c<2V#dM&=WJosAuBA8*cne|27j{xL*6m z6Qkar@orE8J>zZhB+nP|Isx<`(w4Ic`U+sJXmnuja2WM+EO6J7VZ%?eWEg`zPvbEW znJeUWiP=M@a2rc15cU;7Pfp%xbtdwTj&2UG&WxU20D3S0kKrzy83ec)N?A5?96%Jy zswWgXVhxf3Y@!V-SffV*Jrnu&nQhnJ^VW0J`Q&d$bXm65S5d(wHxAl{r}kZHfABkl zmQxE@mR~?c@BfmzIpErTU>kL8`pJODlRZ#y<;`SUc}cRxMY%J5xEdiaecm~%gm7nK zB$gqaBn=Cv1<+&90iy>%&&-unu=pY{W@ZV%(gU}xo?| DL_Bg=ufmYNg13mn1;fP@Dnk|5yRqqGTa~@pB?1D)&(SV*a{X2>O zd8Zl_iSJ9Y`N4o5wVhO4TRfZROdpbJALaUV3ox^W88&Kq|K*p^`D<6Jn@O) @P z%ahN<%CA4~T>8Kjm&Uf^GsjPyr2GE3iMqNKT^~NCiXA`t_>=U;_P0dw=~JiBmp<3~ z?yWmkPrroFvzk<`9d+B$-3>Rg=c)GSablM(H8Hd2ic2n{ 23g%hr_5F z0a74bx+Nb1h-P3u1~Ge;M%_(|uCN9`1frv12rve^I-zOQ3Nc2X5Ro*OPm(}S!d>bG zdcf%MVgN2u5+Dzk6Sz!#+1SoLpiXZ&<+uX!^nyAH0MvKe07j1lde~kvWs?QkHvI_9 zf`5(Zl8iGJlXVe7SKEsaVXzR)PJS<(&W!1L{RwhD_dwF;vMk>Spy!rB%e!`LCdU*1 zGibTN3Yh1vqT-KyYp`N{jz9n6EA-6fEq(SSZm{6y*(;XQ#`Wh3s(j+{Ox#X6&;!>k z140^GDyD+fGZSo`g=8$K!WcwDA$PZkYUSAdA_SRh$y_msiq5) x}y;;Ww|p}K@@t9h&;-!TP()xnE zrrv^$a;@sTYMm~Hm zRFsvH$plT$QA`Zt@KRn{LRPDkkQhbNCe@S*+$0OY# 7$ zI_TARPf#E(Do-5j5 =@wPBc5{cvB~YodY<6I-()9wSgEy z>T#}uGFS;Q<`pyOTFK~vHDt;L3$P$5ig4OT#7wo>Ic9)`CKn5s#p7he7+J@xG7q)KbS?pV2O z2>_opR8~@)RGoA!lomiwejZs$5db2u6fV*HF3kmF#w>)E{hf{EJhYvB&5a7sBQ$!J zfl&*gX0Up~evi<78&zGNgqtM j)RyuJ aTzx9i$>zF)q$}Paa z&AYqz^ee_aQ0L--+e~NmNT6q+yPV4X{K1PsQpDdQLWF9x2F%*#N*2#h?g<|9L01eboY!p{8G9qvkj!Mf1$-wC zQtLfmPuuG#zVXLop0Z%j{&hTaH@V;JrNj?f;S2>zKl}g4IO%k8%z>)B_{wYacTnMn zl9=VObkPDtQdvhFYBv+pxB@*3&!^&*R|7D~B^G0DeC}R^SBFLq^pA`MV2=Ty(_!Jz z>Z<#As0XYb1V9MjBg;CeT8X*^7cUOME~0MXJ;1;lYv|z57~BH9e4_6f4bExcs9Rt@ zv+#2WF7TeFBT=B|jjRf a z?6k%{@oyhG%}wgGLUM<+K!OES77*{wbXJc9dJ=AKT5O6z3lCnnH~7P}2_7Jcbz1Z= z{W}30s^MHUYD6-&UzXdDg(<`M$$0%i@*ym`BBVUQ`Xki%>^ Uy?A*PV_@huw*&yDkUP~seAA01^^v=7x`*eBvl122f4}VYrn)@7)8`1)2 zwm`i57MINAf7cS|IrF`iN5{YdOsQmFSU=b{3^W+Pv|()p9R`tN=5Gwnne9z7BPS3H z1K -z{@CKO4l&2a^K7HklV9s}I}+TMARnqK-Nc^i(4 z2@ U=7_p*PCOnL6lt_a$;Xo*eV%Ozo)0Ob8WU^2r~ln}e=j+qRwl z^tY!5EthP8X;Z4{;`7(j+}Sget&);*;|cWS&09-FE3P1O;bd~1*iDYTFOv_EwZZ{J zwc_V3w5DRO1I`FWC_jfoc;=eOTsD>L)0T^ (;o764 zYDo$7^qP}x!D%>v&n;l{>;S8WlXTk>W{`iR1+u~d@$Op^=t |kwe z9W^vG2qsS{l;{f!3n>>UJOe(=@R2Dw3owi4cuO~Je)||5tnZ)}hnrk(A3z=fgG3v_ zKwKmqkaMPYTN$*g+k8mPV;##Yb *dLi8BoJu 2r(8Qapu>c_n!Ejz7>I*D2`pL>WB|VDxa*tqf!Ij1|D6+DHODswH~Y!vTEa zXZ #nX>{9|jlv7NHmS@MW~cC?x-{{z z5JUz!Df`*osdvy7--dc=N;z&v8*882;WpV_iW9q0dA(i=Mx!t3bb0_Tda!IPecD&g z&*$O9_0=}Sj<`SSwW!y_01oeKZf>S`-`z!Zbw|ZHsxZ(lFE6K}q9Q6NC_wl@8vr0M zG z1C~|K%gv!ZQ5b(?yE&tr$7o>Jtyz76o(=##oTB|wTj*P#k7Lmq5v6W1z@7^r*)tXY zP{t29lt2&PB$*N|(D<`YP{`StxI1Or8i>=E-t<#4z 74%+mWCz38d)Pm(@C3Mk-^|Wm9g0y-kj4RMH`y47-dKp5g&l2Y2pb!l3 zaCr0(fFHa>6&6qYt64m{c|XPzCL6KamnMZw9`(LwD$q050FP>)nbW7jy#?>b5vC(Y zkB+c~ 4OxGTQ?2Iz5>z$Si@LH2NJf5Wye>gDsp_0SeZy z;e~+@6_8=Tg!h?DW&yOQn1}*q1OynwWq3c=Gs3@~K@nzpu (>o5W}|kqwbH7<^%ODmC%>)rH%&Sj++pQjhbR&&!K?Jps_Z`Mlf?@2{_~r)}Hb zq<#DLi#|-5QbUs`Po}c6QYtAaq5S*;v}+N4j&IlLbPAU*m&+w~n@mQOvkGv?ZqJD? zDs0I8 ~{SIhSH z$!K6kPdw1`8ihKx#Lla>ptL9c;t$#rO-9!Mdvrw?BINWrif)fuY>d|u=ow=JXK3@M ze)u7ZKpZw5lE!4E;!pj6OjR?J?oRVPU!}l_LrIrUrl1DzuBvbUiB2^(Q)eewBX~B1 z;r8rn^9;32aZw?{vah98%a;r|i80hRM^b)VfgXq`7cRR@ zxL&D!X10!q0*d!%@3UV$+IOwdVd8`}Z+K9V;*@DX&v*emDZVWkb^2rg9|`ni)Gd{r zl@>_a0uty++El44m}wtf%s^off)~y+ki$TX)oK+BgAwfZ)YjG}j@xWG06FrbU=N2b zB?02N5a!hDW%nILFNND+mnd$BK_rKxD+YEjprQah-2&)wyWMD;!4bW1rDE_!1$#J( zmCxrFePDeZE|;I5kK=`Xz#s;z7)(+Z-e!P@&(8qMv17;Sl~-P+UAuOP^VHPTP)$uW zRaRC~MMZ@;UtV6W0DJhF8L;7gb#^*%?X3coVyuC|E1S&*aHv=SMBKibn4QG7;x(U> zuZORlKPcF~43P1)m6nzY8>{s)W!(%Ht*tvx(54sn1LVPMDjOu4l$^SawVD-~UO+`H z-&;3YFxJ*^%5tmm?Zi$l`lxKF$JMfZ&%@!>H>{WeM$a<1Zoy@MUANj5M$e!ikJ=>q zpfOcKuV*9a^4H G2-=lvEQc3nwna$-+}Ry&?XmSkCQQDawI!D z3uCy{9QN(oFRiVuQcy5ircIl!j(I#DHHU_V1}Q5mlbV_ujMpkYpI6O2Gc!w_)7i6U zWaGxo^7h+rtNG>U=i^+)OMZSHKI7GxoNHQIni_-WbM|a8&bdiCI=tpw+tII2;^X5X zpDfAE%~f;A&d!#EgaoOptCv%!PD*KMnUba7?^o@bo10ZTwwXG$NG4C7EJ;a8BlRoM z>%7*zc~btl`G_1VsTDE*33vWO);Vl-R%HTaRjbfyt15Q674%b=GqdXVR=4Xo#vcA! z#msbX8|RLZHA|<-yRTd%ld_t{U%y#=RWGt;S9z#i{Lx!AC-V=>@ZEQ3Tqy4B>% TDAMgi+TYEY4lO~RrxLD(U)L;KR&M`J`-EQ_1 z= E5dI{7dWQtzEm#e$Y4iRCBk+FvjAT`q-B~ zf0vBKy)V>Mk9*%&zx{)5)ju1zOX7mRzujsLZh -EpYRaViXLm`U zy*1=Ep;mOoC&>7({#71*{7GE@ZJ{uma%OwH7H$$EL9c|)mtdZ7= zQ&PKYgH-K!LE>GFk}+qMB+R~Ck|xZN_{@B9xjoWaby6CR?U2S3Z%f0$t r`(BdTy{}1IAVsnlUnLpyFP4Nclf;vfDKW7_e@%HtM~)qr zXV<+VhmRf~*a xm-<6O|om(F4?nZuP{&0LEtfI(j*0R;^X7wjW^zu zS6+DqAfry^&YdeOR;-Zm #JP+^e;HCyQGq#Z!+Gve(1mb@Kq)UT4?t>y8jlbw zJw08)qPO093+Hq|J(Lm95aduk_4N&44FQas0@#xYIZTk5GiLxwjgj*53SqlLhYl&| zMJPq! z2!wPM2G+An0jQpvPPF0vmNEJwLtW5uI0C zqpB;h0I+AZxU(+rY&(cKf}X~>RB3T1%gRrEs}oufh}gh|0Y^Ha#>E$|kd!dKhs^-C zfB4JaAX)=}_y{KmUob|OJjXS`#q1f7>CM-Nb@q?`;|baP`u4EeeEIWt%eb*)LT=O0 z*eG9l@cSXxXT^o{=g5aY@ZPZ6{PpptWYgC0fImS`9_~${riR8QoXhvRRlhTKkEFPK z-O7imASNkQvTuJ-;>S%1dB_01JLM05NjgsM54lY^72T;>l6UX# &cVSiD?I!ApH7MOFf%;or9ddLsLsIH%qW z2(t|! C&aLX3ZKYEG)3JQqG(?1HiFU zY27s90g8}?;A7dcWdK8S0B36DrI%io&6_tXP{W&bN($a`0k-7kj!`!Y)~T$lvNU0+ z5j1=DY`GAN+?<>o*}8SBJoVJmQdL#0%2%#jfjJZ^jT~zAP%CN6maTH^*fI6+Nnpiu zA&}y>va(XaCIT%!oKjneT0;aq X?4jeeBepm_$3REA2Sk={4 zrpAy@&6_}s;A_g1Le*~5rp>Z@_Z~GKK@T;T2&1U|Lro;ggR<3t>zpp$5H{ZM_8EEl z^<%R8Sh*UtlWXW4wmPdaJp&bE%B*WuMp1ut*-F>%t*$=Ks;I*z{A(36(_34Scz~WO zR?L)J)-325^r(Jxe`cp$%G7|y9{?A3>LT&ve+X~0L)S8~^$=E;pyyb|EGbQ$7*@M4 zeGWijT +}ZMxe|ukFRk|G;$V2%3pZm1rLjy6?)P#S_U;5^E zL#?jr4dh(@4xq3hOrUVzXFnz5^TvfdH)>km|IP1otN&roKFNvc=vF=y1u({S`c~-g7IHCy@LC>sNGZjcVe*A>I_~MJura26)q*SGi zL|{eG!+n}l5j5@Iy;~7+0ve9b M_ z>~7h(>$FtXwWxoA2I??@M;JiGA}BFBX!>c4|N;6uY$R=X2{2G`+t2^>2_=&=kmq7@05w-Lq8Y3VY~P1-|jZ{t?t88 z=x**-KG+2@8M!j%!+<=Qp@TQhsea49r2d)T4C?gaix$Y3+a8pEKK;DBykXOzjx`va z$Ks{N1 LFXd%z%v+Qu+O0dJ*!~av{n+wO;xAUURN%@wnp){w}{`{hRFc<;N=nT ztDOn=bHE^K%X*UWdzvv$-0{P&B|B0;j{|r*zbT_JH!49-m@h>LzQffPj<)YYEi53u z{?NZ$)3$>izIc1;xtC )8`dXap>|7QVF9*<3N8^2(KL#Hg}`R--o46~&Dyos z$@J;d;V RJs`(y1d>C3sPow=oWzw~L`Emt&sIf!!cbb(E z6wyZyq0WpMGt@b9F4XR!md~kEr{u_yBMS5o;?Um^WifBwJY{wj1NBjYG0tTx%rW-u z+lRKfa^sCR$ORXyR2oSeHf(?<5bX1z&6AKo)3ID-enu0toSbY0!D#wIt*2;7_04Va z!@s^EI}ewM7bZCd>M(%^_jFceG*Gb$y8sn+&I*PwH;}qUyUu>Pj$`bZWopAedYs_4 zo%=~JQM~=em9lzakz^-Sh_7yg_-bD@&kcQ8eW~t@KdOv ahpTm}LZzVPXf%Ve07hMIVvx~GS8Src q-b)pjIR zCh++9SQ^eO?FU@6#rK7Gwye+i=J}nY}`7=Qep^i?} z_6d0556~Se2|1G_Wzu|!%M2Zk>V6`<9SNX^kmvBx6Y$0Ja->hs>2Cx`U|Lb3jD?2y zPkv=U@zLU^Cs_Mcn*?!LMH6(s4CXrBp2F4SwYQCie6at$J3sOvnK|76;_KGq1^lxw zsMFvx&QO7#M_^k2nrT{JIC-Lc?#_=zgD9hBj&JSWD|g-ZRW;wm@WJ(yDD}bRm~M@r zuN>jdb`W7Z=ph`Tf1FvfIzi9VPd}qT&*H_40eUV~S}OE`!$i=tYuD~Brdz?FhZ;Tf zkwcr#Y15|RQv}FUpnws}bfV+ufBy5IsJk87HhFUO)mN)|5CWY%c?y1T%GHPaG`%8V zDJq%@Euh1~InwDfedb(p$;E0*6D}sUqn{xHDf-7Dc;P$ I7c)Yl{L;))< zEUAG*%_0IHHyrlTu{1S)-hA^-<->=jXV+hUy_yHd*tl_%f=&EEqQ4(%49%ZEUzx!X zW<_J#1#_*3pV=*k&QeQ>bVCykY;{&;G*Gb$aa`wFSLZ2(e(I_!x_)nU^>KEGI&8zg zRxvZZwKeOSo7ALu`TEDMm6?;rNxbiff;|5EZMOc*PSpl~%w0BDNuQg!b;adKOvZBY zjD4@JF=$%_deWy$aauuGV^HOmZ)8GE?HwI*&sV<{YIRj_78WI+#Ns5JG?0hz&wuJ; zIG2eb57Pndy)S&_n<3X{#Q~kmvoFfJ^&7$(=W}=7A%)Na3^h>`@$)^L%Y0Y4ToYRo zYB%Rx&yzb*a$v6INy!MSug14uk=lR!m!Y{4R?F}!XWZ~fNm+iaJoWrKdEsS%+$c 8X@w3Hr}x