From 636478990fc3363310c88f8695a21d8741fc2630 Mon Sep 17 00:00:00 2001 From: IHAGI-c Date: Sun, 29 Dec 2024 22:11:59 +0900 Subject: [PATCH 1/4] [Team] Existing content development teams 3 [Title] Check Token Usage [Version] initial [Language] ENG [Package] langchain, langchain-openai LangChain Token Usage Monitoring Tutorial - Implemented token usage tracking using `get_openai_callback` in LangChain. - Demonstrated single and multiple query monitoring for OpenAI API calls. - Provided examples of calculating token usage and associated costs. --- 04-MODEL/04-CheckTokenUsage.ipynb | 325 +++++++++++++++++++ 04-MODEL/assets/example-flow-token-usage.png | Bin 0 -> 49448 bytes 2 files changed, 325 insertions(+) create mode 100644 04-MODEL/04-CheckTokenUsage.ipynb create mode 100644 04-MODEL/assets/example-flow-token-usage.png diff --git a/04-MODEL/04-CheckTokenUsage.ipynb b/04-MODEL/04-CheckTokenUsage.ipynb new file mode 100644 index 000000000..467cf1862 --- /dev/null +++ b/04-MODEL/04-CheckTokenUsage.ipynb @@ -0,0 +1,325 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Check Token Usage\n", + "\n", + "- Author: [Haseom Shin](https://github.com/IHAGI-c)\n", + "- Design: []()\n", + "- Peer Review: []()\n", + "- This is a part of [LangChain Open Tutorial](https://github.com/LangChain-OpenTutorial/LangChain-OpenTutorial)\n", + "\n", + "[![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/langchain-ai/langchain-academy/blob/main/module-4/sub-graph.ipynb) [![Open in LangChain Academy](https://cdn.prod.website-files.com/65b8cd72835ceeacd4449a53/66e9eba12c7b7688aa3dbb5e_LCA-badge-green.svg)](https://academy.langchain.com/courses/take/intro-to-langgraph/lessons/58239937-lesson-2-sub-graphs)\n", + "\n", + "## Overview\n", + "\n", + "This tutorial covers how to track and monitor token usage with `LangChain` and `OpenAI API`.\n", + "\n", + "`Token usage tracking` is crucial for managing API costs and optimizing resource utilization.\n", + "\n", + "In this tutorial, we will create a simple example to measure and monitor token consumption during OpenAI API calls using LangChain's `CallbackHandler`.\n", + "\n", + "![example](./assets/example-flow-token-usage.png)\n", + "\n", + "### Table of Contents\n", + "\n", + "- [Overview](#overview)\n", + "- [Environment Setup](#environment-setup)\n", + "- [Implementing Check Token Usage](#implementing-check-token-usage)\n", + "- [Monitoring Token Usage](#monitoring-token-usage)\n", + "\n", + "### References\n", + "\n", + "- [OpenAI API Pricing](https://openai.com/api/pricing/)\n", + "- [Token Usage Guide](https://help.openai.com/en/articles/4936856-what-are-tokens-and-how-to-count-them)\n", + "- [LangChain Python API Reference](https://python.langchain.com/api_reference/community/callbacks/langchain_community.callbacks.manager.get_openai_callback.html)\n", + "---" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Environment Setup\n", + "\n", + "Set up the environment. You may refer to [Environment Setup](https://wikidocs.net/257836) for more details.\n", + "\n", + "**[Note]**\n", + "- `langchain-opentutorial` is a package that provides a set of easy-to-use environment setup, useful functions and utilities for tutorials. \n", + "- You can checkout the [`langchain-opentutorial`](https://github.com/LangChain-OpenTutorial/langchain-opentutorial-pypi) for more details." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "%%capture --no-stderr\n", + "%pip install langchain-opentutorial" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\n", + "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m24.2\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m24.3.1\u001b[0m\n", + "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpip install --upgrade pip\u001b[0m\n" + ] + } + ], + "source": [ + "# Install required packages\n", + "from langchain_opentutorial import package\n", + "\n", + "package.install(\n", + " [\n", + " \"langsmith\",\n", + " \"langchain\",\n", + " \"langchain_openai\",\n", + " ],\n", + " verbose=False,\n", + " upgrade=False,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Environment variables have been set successfully.\n" + ] + } + ], + "source": [ + "# Set environment variables\n", + "from langchain_opentutorial import set_env\n", + "\n", + "set_env(\n", + " {\n", + " \"OPENAI_API_KEY\": \"\",\n", + " \"LANGCHAIN_API_KEY\": \"\",\n", + " \"LANGCHAIN_TRACING_V2\": \"true\",\n", + " \"LANGCHAIN_ENDPOINT\": \"https://api.smith.langchain.com\",\n", + " \"LANGCHAIN_PROJECT\": \"04-CheckTokenUsage\",\n", + " }\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "from langchain_openai import ChatOpenAI\n", + "\n", + "# Load the model\n", + "llm = ChatOpenAI(model_name=\"gpt-4o\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Implementing Check Token Usage\n", + "\n", + "if you want to check token usage, you can use `get_openai_callback` function." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Tokens Used: 32\n", + "\tPrompt Tokens: 14\n", + "\t\tPrompt Tokens Cached: 0\n", + "\tCompletion Tokens: 18\n", + "\t\tReasoning Tokens: 0\n", + "Successful Requests: 1\n", + "Total Cost (USD): $0.000215\n" + ] + } + ], + "source": [ + "# callback to track it\n", + "from langchain.callbacks import get_openai_callback\n", + "\n", + "with get_openai_callback() as cb:\n", + " result = llm.invoke(\"where is the capital of korea?\")\n", + " print(cb)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Total tokens used: \t\t23\n", + "Tokens used in prompt: \t\t14\n", + "Tokens used in completion: \t9\n", + "Cost: \t\t\t\t$0.000125\n" + ] + } + ], + "source": [ + "# callback to track it\n", + "with get_openai_callback() as cb:\n", + " result = llm.invoke(\"where is the capital of korea?\")\n", + " print(f\"Total tokens used: \\t\\t{cb.total_tokens}\")\n", + " print(f\"Tokens used in prompt: \\t\\t{cb.prompt_tokens}\")\n", + " print(f\"Tokens used in completion: \\t{cb.completion_tokens}\")\n", + " print(f\"Cost: \\t\\t\\t\\t${cb.total_cost}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Monitoring Token Usage\n", + "\n", + "Token usage monitoring is crucial for managing costs and resources when using the OpenAI API. LangChain provides an easy way to track this through `get_openai_callback()`.\n", + "\n", + "In this section, we'll explore token usage monitoring through three key scenarios:\n", + "\n", + "1. **Single Query Monitoring**: \n", + " - Track token usage for individual API calls\n", + " - Distinguish between prompt and completion tokens\n", + " - Calculate costs\n", + "\n", + "2. **Multiple Queries Monitoring**:\n", + " - Track cumulative token usage across multiple API calls\n", + " - Analyze total costs\n", + "\n", + "> **Note**: Token usage monitoring is currently only supported for OpenAI API." + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1. Single Query Monitoring\n", + "----------------------------------------\n", + "Response: The capital of France is Paris.\n", + "----------------------------------------\n", + "Token Usage Statistics:\n", + "Prompt Tokens: \t\t14\n", + "Completion Tokens: \t8\n", + "Total Tokens: \t\t22\n", + "Cost: \t\t\t$0.0001\n", + "\n" + ] + } + ], + "source": [ + "# 1. Single Query Monitoring\n", + "print(\"1. Single Query Monitoring\")\n", + "print(\"-\" * 40)\n", + "\n", + "with get_openai_callback() as cb:\n", + " response = llm.invoke(\"What is the capital of France?\")\n", + " print(f\"Response: {response.content}\")\n", + " print(\"-\" * 40)\n", + " print(f\"Token Usage Statistics:\")\n", + " print(f\"Prompt Tokens: \\t\\t{cb.prompt_tokens}\")\n", + " print(f\"Completion Tokens: \\t{cb.completion_tokens}\")\n", + " print(f\"Total Tokens: \\t\\t{cb.total_tokens}\")\n", + " print(f\"Cost: \\t\\t\\t${cb.total_cost:.4f}\\n\")" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2. Multiple Queries Monitoring\n", + "----------------------------------------\n", + "Response 1: Python is a high-level, interpreted programming language known for its simplicity and readability. C...\n", + "----------------------------------------\n", + "Response 2: JavaScript is a high-level, dynamic programming language commonly used in web development to create ...\n", + "----------------------------------------\n", + "Cumulative Statistics:\n", + "Total Prompt Tokens: \t\t23\n", + "Total Completion Tokens: \t661\n", + "Total Tokens: \t\t\t684\n", + "Total Cost: \t\t\t$0.0067\n", + "\n" + ] + } + ], + "source": [ + "# 2. Multiple Queries Monitoring\n", + "print(\"2. Multiple Queries Monitoring\")\n", + "print(\"-\" * 40)\n", + "\n", + "with get_openai_callback() as cb:\n", + " # First query\n", + " response1 = llm.invoke(\"What is Python?\")\n", + " # Second query\n", + " response2 = llm.invoke(\"What is JavaScript?\")\n", + "\n", + " print(f\"Response 1: {response1.content[:100]}...\")\n", + " print(\"-\" * 40)\n", + " print(f\"Response 2: {response2.content[:100]}...\")\n", + " print(\"-\" * 40)\n", + " print(\"Cumulative Statistics:\")\n", + " print(f\"Total Prompt Tokens: \\t\\t{cb.prompt_tokens}\")\n", + " print(f\"Total Completion Tokens: \\t{cb.completion_tokens}\")\n", + " print(f\"Total Tokens: \\t\\t\\t{cb.total_tokens}\")\n", + " print(f\"Total Cost: \\t\\t\\t${cb.total_cost:.4f}\\n\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "langchain-opentutorial-BXw0bE1H-py3.11", + "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.10" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/04-MODEL/assets/example-flow-token-usage.png b/04-MODEL/assets/example-flow-token-usage.png new file mode 100644 index 0000000000000000000000000000000000000000..039a0e236216733c89d11ab84ed3e405f024696a GIT binary patch literal 49448 zcmY&=1z1!;_rAcQAks>ABPHG4(nzOtce6A|ONX?yba#hzNO!k%H~jD7_x+#W=W}^> zS>~RZIp>`-bKm!@A@Z`~h;MP;zIycvQBp!g@zpC3@B>v32Mv6($FD>Hyg)f9iVM9e z9l_fJei1QJlQfo*dG!%^5BCZx$m|se(ggUy0e)V+g82#c3I=$Ef_(N9`oDh#DgK1{ z?|Z0vNJHLmCDvE31YSvs2r9Wk9i+iFD^1M@?H$D&$zHzlqr!O2_WDO3YkTYLjM&gV ztAb!TI_d{a5aTC-wLio}OH0}-%*`HQ!>ODO+o{aF&xf~GGsP`u>Rm%mqxYpQJ4q`vfg`tqrxsyR#{-!A7Q%^7`GB-^+LepwY1$ zS0z^AO?MS2|D3m@URqD-VSp}dI1vQa>Uq2#Zfsf5Q`pGB`d!*Bp)dV+!~0@AVc}7N zSi%p`R_Sk8^OI!uOX5*l~OiRKN z+Vl05S@Luo=a59k8hh;C-o&H*;$ZlRMmcsV3ydp9tf@tI%};WIIA-b7 zJl8TtmYJd&Vc|(hTZ=RMtp$5uT(;+u)S7pJ{>_$i_a+7TaoQMNu82Vx4f5r2+G(NK&Q2EFe;L_x^?pWq9Cm`J1k z5O~J$Cean0iN4@sJ-L0h!eGPQ14l~{{YNSvXTeTld#qGO+H8axd^q1x5d9qbwNwt& zKff9hopd5FIPOoEsFY}sF=;6U{)^BLcrxFWG())`E9mC3FK8ip3v$0cS}N7%=5l|! z-Ra8mKqLPv@P4)s0fL9VaG%sgCemz=|9~U-y)UtF;G*+_RW$+q7J7ki;gTU45oMjB zmhv!lKYZW(|Hqa98hZQoMjSGqjU>+(85xiWkrcFXutY{~3$J?C=P>}s)Qu;}wUA+v zy@AU22(~5Kip8@?rmB)KwaF0iEw&34zyj7l0BT+`+Do{Dp`hZBk!&1kx6onk;Agic z+w#1wwoSm-M@9!==VQ11q&kcd^&dXxf1&`FRf-E#Qi7Y6H2%#J2_9uxV1N>7hMX^m z;gKrjx>}73y&iG-oG*82?>DGqtW_x!d!un5^AlY_A!RCEr8-se| z=BWw6@%&1?^+v1b{eTM9zWqA0o^!ekE*oR>T_L%=>*g1DqEht&V^6RoV zf^&9$UA2J7z|Aaikf=hT26OnLOhq&iG9|LL=_Spd8pm|$tp|CGJ9fuP%fPuw1(Nfg zMux~O-{t6jLH9~&C;YgcWx+6zGHL=7($8r1!16G>+o+VJ$ma9=9HY&41!1{EnqXr> z6i@gKV#{hWLZwkshyPLCTAMA?{R^@L+@Si3MqEaXHiz2=;Yt-#`>FgA^1 zdD|O*DwzSZ9wbJ4__m3uLGJ60U2;&(!>8B8(G0qLLwpU# zRBz}GR@$C7dysnnFcwb!8sGdyA%SE`{pBgObE>qZQKd{1-vXYAR5LlK@c^gt zN-B=)tBe_=^mPSj|`6myt zn_TV}7eW(hN8Co!c~e`^*NlSSKow7nj|qoqLuC^1{a`5raG;CykHg4!%`@BsX z&Bx6<8ltZHcyK&AZKXT&)5BjXMb|vHiRH+Cr^2OjVdoOQjA5y|dPkKvgZr@|qK3i~))A6CRg3xpVp4 zd#k0>GK;C!DP?@mlJA7Pe7Kb+iE>vzYTi6^jdvTb7L%HTJl6BHxu2BJINR6aA`ywS z?kH~@LoqM*mdR5RT*E%l$zP-f?xgA*U*NVj=$(c3Gdy3~I~$Eg@NyfMB-OY)FDHms z(?&6{)y>^s9p9TQ@dtBRs^`8XWa@V}NlxCIEfzPgoGyL=EG)b$EId0G$|`-Y9Z|2f zotEqf+9JQ5>-|}6mrVRI14G=!23CT$CzA$nN;v>;>^oyQ-FX3=!iLJIM?J&*P;G28A=B5b>3tnAg+ zZqlbS3;b*EN9lF9P8laRXrQ4pcmH|eOTbyTT0k%UeVpISrOr~L8x4cZ)sLQ$_-OSbo9bx2cuQqYdzmAYHyc^ZqEs> z7)*~_Tlnd2%*J{|#Z~xX+C1ElA8pIccJhcPf*xu%%R*=K>A_MY$`{$zqbLW4@u`#mM55yFlsjF*7YLgKwj!32% z?d!eJP2WUsSIb1(c#n3Y70#nZ4>=gqqIqRiEtjeOR_Sr$xeK9L(i$B-%G@y)m-r6EBQWm2!>02bXVqug|a z1aB6n&inwe+6tw3#Y)rDC5SVM*LC3WZoh1y_O{UBrlsaVM*};}A7z!0LG{tA+16N- zkG@zS3d7#HKrK_hjrPH4vC{5gZ9%2@D1-p5|nrmtOo3vF%q!v>sifgPAg zwdHTlr$_fs-H=sLmA^FF?ooV5sc$4JZ}(t1%--p_5rL!A{j=$JRMJ@G-xsf5>!#ku zf4`=0!ug$sg|BqmjyK|94TNUD+vMHK-FABWAx!z<;dr#9fPDmsCYi zyZBJmLiu8$roT@F{(ZGU-tM!3ck8p5O{~YxGZiikjAWidm6UslYUuAF2O?ASPh}s_ zITxQ%W81Cv){LBCBUSleQ$v>Y8~ffg8}7VfmzFhBr;Cepvf6@Si#MX+Q&_zIQrxwN z&qQPCyY!ch?}qvBPs%rQBVGg9P`1}3=32*;U`$%2sMMt*zQBy-3D#VNQ<|iTtQMKfS8%ykKrNYvkaR1h}z;1Cg;ul=nL| z!?8@8i#3`G*_pdp?#-n?Ki;2ur$pxnWD2{WQXx8&raWJJJT+VCYne}0D)d%yx%W2f z4Zj|k{DoQgO8D}$_uzqNJ%a1%*Nj;6_F=@TB?IrxxGw+W7E^S@x6t=OTpAIa8%YJ` zz0>%H#_VSt$tGQah}p<^rHMmm%hxI3M8(;Z4E3eOP4ULZ#c(GdV<|Z zxn_=~p*BO6yE`59Vi6E9sVr-ncl4NplH`eFJCEhu2w|Ca4+O>IP7Y1(&977=9}XOZ zw**+%@UO3v+ivfz#%!JsFILQR3!|TRV))-g5C+>2gzi_2MdDMX?8LX}xUIcg!RVDU z_Rvq>8G3E9JpEK#DT;)UVfxKm`(j_4)PrOvD-UyuM)kPnVkS@;*Ixa6u-KCZeKWO{ zhqrGkpx$v8hK4w>Nbo<;mCR60U)F|*8upnwx*kJYhDulA?eeD6()?8`qUDX(I=^*D z89Ps@o4tJx_W&Cjj?HTMehS`U2pcBYjKGi9;X2aZ^|m9i0@m|%1QS!+1r^ro;X%AA zx%=?BB~9No zJNn8&h}2}*K4V{Y*URXAt-(^EQ*GIHGPsmD6o%ey6O(rLi?wsH`kqA+jHdiVc8X%2 zv43)Wp_0BBl=fLMkB+wr%^)+qUtED!mHkPK^g~ipI^(U&99<%-<(%zcAf1c0v+6V7 z<0+@e8yxHzIO1kWFy%VEQNr%C>+=vj?9g>9bIYF3w|MLTpT~Qr=g<06tn(?|SYIQB=!uKWw&huW=G*k0xLq8aG-s|#%2j~*;NXTyUf-;h|jf67U0 z?5H$J9~xNTS==5qgIA6)pFN@zU0mvM9flV#9S8{@ISRLZ2??xek29kx5Vk%L!+t_(x!WyjCPTqv;7)g= za*dla5%Xa3dw6a>$>4E2=kZwT;;9TwJW{K%j5mup2dC=(vLz179#+ON!5y!8ZkUeO zY8p2=6ilj5l}9seFgbR^xcrTgrgEr(8Z^xFcw(|4m;skr`C*_`t=TUxIhPgey4sal z9TJhH_WdqX13W~;3_i1bCnFfne9+7^d_Jogxh5!%X?&x9@-C%g;mc=*KsE`mmYJ9* zmf>3~uG%CPV>H;#4?V*zV1LI#sU%b%oslQelmo^Txv(P2!8ZPE$%C$xM%L zBj&CN`>46TMuCY`p?v(;>J3gtcT5>e8=G8|nn__PI$A}Jbe4QnNt$g<@zd@#M_W#x zx&)CBkRwbm*_*JUCvt>h^W{A67CUybGCAxkFRP?bR4^LAmZ$!ru=n*3M zg?ibAE|hnf5RuojnLMnZNU(c@nOogldn@EZc40G|A069opz8a1AMYn@s43O9_IO7JiP=u=E}^xKg|iV} zQ_FQvzb3jTe}AsYGdbX5$HsdkBYr2GUG?|JH!Y5|69*DoH1RG*LXxXLOzsfFCQ7ue zFIA`&tKo#g@Up0FufR+Nbve582eKbNs-6sv9*{T1&t||ZzbSJ&DK$B^2WLDCL_T(y zm>Hr+o25?;su-wMF|~O=b656~sNm9{9p?UaIJfv%m1q@VQ}uNlx-{K>fSMP4HB_t? zalVu?Oxq39jo%yUCO5Yqyh=QRLB;PtQGU z>>7WdX+OpZMinpABAp|cfreo43ERsJoH*-BrmvRhkDoZ6djSdn{xE<@P?pFb*rR<) z6xV~>ul8VGC7nbFy4o!w?o>RWIwCzU8*t zdK~4f%4Dk;*l_fqrizY7xP+<3b^6bR@&vqqIA4VAWA9~K!{P7_3)h>H%NfOt1xjZE zk11CkRI^R>mDqbOZ4udV!Wdr3w(jJg5DG~o>Q$XC68wq7y90qrlsXJ+K+@Dohec@AO#3Kd=_lwOM{XN4| ztV?{&>#wO=5?GT!rxr;4I>c#NdFQsrZuM&_D2%i}Y5DYNK$S>$u$C_JmsfWOn(x!~ zTuMe#Nl4hQ${umHJkOj6Ui{tdR(4JDF!c5V=$f^RUc>x{EwBg5DCJU(0p{B%xHq-1 zeQm#XF1OfqN2E_r{dsDcx`{R5ipKH~Q{e0c0^mJnCBDF{bYfU(u1a(4GOnZ}a{T;Q zA+POl%{n533I#6>J*@ERac_@u(y+dm*Xyx?y+lgQm-d+zc2Wq6`O*E|*?3Wn-}}K~ z@?)=jqQiP!dM)gmS!=??*b>ldjDaQ;*c{YX*ZAIq6`=H+OZZ~)6c?-3>w0j1ohNsE zsB&k!-!1H=Vy@wbfPnpoRU0+gKLlxiow*9GBxg16B99}#@6I!n9fB2grRjMPrsf+S zCI*lBpS<3`7o08LKWy^kS5p&U^P@qLA4%4(ahme6gZV_L7sZ*GaO{F&e}IZ0je20j}B zSPRa*(f^B!fJzLCh?kHycVL00DiQ!gAt<{C^- zl1DMQi?%x^_ZeNKx<3YD;dG%n2HN}gjPGXuZqzOknI#NqE7qB5cfXoK#jQo{+a4$- zFhsUPh1+^iveD%L(c+rY(Nd1ocH#3^nyel8YyO~kVmu9!^ZvnRolH${uKpzz{*~vx zK@hg>B6+$;sKWj}ax29fH{muovRK4myjb2}NCZ5ep}ruA$U02HP<-;%^Gdq87YU;| z5o|-&V$8c8*>wSEZ+I^Ei%aq095D~u>l-2(x638fjIqmb137MtHokPM!Hg}Jqv@n_ zFjfH(|6S8q+Q_ltEloo4*W80KVdJ>LSp)qo&;ussC*}(`qkp=d?uSA1F zeBq5mmNrmOoeO0fxB1hrz%870@gQ@OjF__2+t9t(C9q4Z!#-o3#(U5>k460X?ze1k z-M-AlUwT5P4j*B%z-eVo10$h_uWJpbDYzAfsZ*=PjllXOBT+(0ELTy8_SfK8jV9{! zJ$8Z<5190V;|*q5 z4tyOAa!Q%Ba{0{NwraK=8;H?4*?!n+MnEFJ@$Gk)o4lYl*h!TCL|hu01d7PjbV9#l z>E`6S<=ge}ogeH2=ShjFx5GgzUq9WRB0yllW0_x|m0gKBayP|CgT7Qj7etK80Y$v| zmgti?d*QGTwllzOX}9V^r-YahT)lV85ENlF2^8Y_aUkfA`ngoEDA4QsO-t(449f!M z=Gp0~FoyjVg3#exSM=XfAA0AGJ1ywRI2H~Hs)jEkf)dzlmKNDWGCgLE4A(jfW)JVI zyL%19r>Cy99yd$m#<`J^{@Q8;t%yI!;>>lGQ;T7RXcDyi)(UA}qQ)17UPi{o6$|#G zEYZ`T>gpkX$GNuTyJ3z>w_4+%dw=cnTw4cP-x+Lc>$dj`5Exxu2+Ry@Vcd3NJBZOU zF4CJp^ftu>O_h2!8JDJ;A(Gg*x>N5BYUrqNc18es0`vYfT3Y(CMaobjy}^ z;<{Li#OTRn?IQ$g{Q>w##c!W8J5E*%Ty3%Ja&4}^juX1w(oybF7Qp{|N(hMdVLr3P z)UTMY7tHj$kQ?&G9qC{JU;d3xPbaw3d9ZXkot24{xpfHT4SEyAa`iWkUUQzI5}WB2 zw*PU01vX~@YTym%TiEO104YWmWNYo&;Mt;y$J!$u1;g(rA|v;ujgc1!8O;JNSSDhg zd~cBfnhIuBXXVztL6(`KCjuu7yx?@Lvoj=L`i>o$f&YPt+v*N+f9E}BgdtsonQxx` zZzhUzT|F0)RF=pIJ@Mh_!$?{U9<|$WI#-7S0*Y)cVm{ny${}5O`>nlXs)d8{^%yxr zf~iSo5@LMD0oZr)Yk%F*N8(s)SK9-gwidVxZX|cq4nKXHF41%lyL!hnb}hd|i)@L1 zwVLKbZl~>#Zh4b~s`@?1w-J#|siQZ1XZfpy9s)|_k(&!RV!g>HaM$IW={qt5mdH%Io8>uoh(O_ zeUGNhs@yr%B%myxrO|C!UmRruo2)Wjk5+r5z#J&(O~@Mm78)IuMhjRLN+4H2^+KZ` z{3t08=s##-yN{L?SHrc!T#nwg2LtH`vY_vbE=!Bwa4{9^fU_BnlRI9U9~V`?BHwdIvX z606ZIwiQvw;LfV~Tk~{0dBylu(9PG=g+}4qn?=0f(|oUny9XmSQcI2pqh^gl32LUg zqxs}h#aV|?466BGLZnYj7T7fCIvz>dGDjZ$>6<#b!!LSXr$GC?u;n;3&|cN>D)0x^eta_y|X!$-#Du zvg~8UkDe$;M&is=Vyr(bT1iSzy?G*8-OF9&izLXe5 zIfB;bauUcb`_pMr3tn_}pd>()LE;Q{`hrA&DAVSNq+M7hQ~(+U5L|pj$5CGRYkLqh zS8cBB*SS7l<-vcfshudWXi5`={UHLo?=Q3yu3FTrc~K_$;J?4<{khPgP~ixDs{_s4 z*n-M9YvM!zEi1;9k@W*)^Mp(C$uQ9TEXn`}SD>y@<#Rg#A?kol6$y|8`zs=nzd=@o zp}&A}gjJ|c6k_nlT2mxz*Xwnh~_WQ~2tPUWFRF{H5`Q z1L`OK=$rk5%q)rqdZc0)6p7By6Uq{wAv`d8wYLYA&POniW=&t?FUEuS>0(R-z$=f^#q&l8Z}izP~<}i>okC{pUDN z3Y0$;h#lFxu-MVBl>|%GPKs1$iu-C-Mkv2|b8bmgd_=s);x{zaF zT>;Ldr&kOL8!z7egxTrRZ6d83v(T!Pdyts^lxzTHGX=?K<- zj=~FegF(%x3%}O!7T#CTiTHe^_=m(e2qNs&S*d~c@5$R`2_`s~DbGzQh^FNE(ic3WFPKlmq@;4v(?V(g9MjG3 z>v762@?HLA^|wd*utXA~{Kw}gzNrT1B|y$3uphQNCgD~?Miu^Jjj6Y zP7FzXpvamdw}^*h-2(o}zgeFi3*B1$kuZ3m)q6qRQ%?{uAhSK_M;(7DSzP1BK=>RHBurAxf``Ya)=E$8mO{uJ4A!c3fI^4 z;x8xU7a-6=>O9CvKD_*bg<_lHrnT}5|A1$l2PqispB)kaW}@~8Y4M+5z`_EzI;2vh zLWfz`-dG)MHO@1p_Ue-OA7sKIkg-!{r34@oK)#x##0(=65khFSEjfER*$#230BHRi zP=>N@M9zZrGIi^1yJ-T>+P&}pOb|ggK&qO+f#!mc#`aRLqR$`BM^h&4tn>~Q;>^W` z|2y_RM8M5kf$4u=Mui3U)0x)C*JVG#Y8zg7-(2V=xDZdu5x|yDH@$SNFWJsn>-Hv- zYDx#^^FM3`3mn1s_0#>g?rAehKx~+_w-zr;i4`(Di03{F$XW}Y?q)&aCKBkwSzD12 zw4G*?g10~dqgnC~Q^5iR>fj5C7cT;G#_+~WQI^s@)R@$NjgUee9>SAKvywv`rH&4_ zJDW!}rSAXb|IY>%z^zvM7iGu|eH2h(v)d&(!#w|IoB?pAHgW;&h3b$N9N|7;iig8f z#smzAx&QnsLSzp>Hv~_!h8EJt8+g#-P&U<+yZ1lD1q)2V_06NRPX3huoFWQep7dsg z?RayzVi?x;Tu1R=X${0*Xb>wPz7flpM~mHYwlb zc$u2fTSoCe9$ydfDds(`#=!{#@>?ZJUwzV>L^ja^*@Uer9w4H?g%%0qgY}XmF<_u5 zJ0NJjq@Y)??f5Ja|6B7G^8;vr#!#9EWFiz8==mXZnBBkswO>gB;Nt_aHYOyG{efGZ zy#nyzaD|~7Xa0YDp#mULUsUH22oKo@C;)(kTa$+Wx{rwftdG+bPylHK#R+2FY4h*D zWbjgI1XWzsEA`^k_DBE?!rg4JpH8xK692mzG@&c6x)a*mfdNQ-1#XXR56jQ|ho&4X zAd2rbZDmve??{8HlPIN$rovyc8-N{upkEfMB4l9PWTZfHD*-$w$tEN7k~!8B1l-*l zdyGNjXz zjggT(IP!$$cN$1Ok$Q>&o4Ngzh#C!zkCU2RAtPjB&JOOAWmD#X^g! zp$t5kssVub0NMW@O23OiAk_=HDdO!;X;wvlcIs72s=; z0VK$9{*J-@LO78iAncADMVOF45VgBF^t^fvfaVoVJ~6})Hc&5zl~{Y%J-427WJ?BC zbU9>o0Nlpl8=fpKw|#o1@Uk>3Mca!!6nodKhC^9x9*;|gaoJ76;@^q~`3T{N1XZ~M z8&t3bG&VbAo0vh!>i_~KlJ3KqKj${|gV77W)@Ehd{sgpr(qzss%saancxcH9g+M93 zy@>75hI^)65%arI+j|zhl$5tAIwNAS+H2z5j1Jab1X`nKe|mrpAEFN6@OPjG7UY!` zcP2TkatO=f3nKeU(n}Va%bXIhqRhvMD#QonSPwe;!q-RXr8H1HOxCwjXG2&e;49)r z4;1R0?L>N~d;XsL7WO{Eeg=LLC|-o7O9=c3gv1!y!|MF-=<#eDfxDqCrb}9W7?=VX zf^T?6&|EV16lZbhqy6SZr0T7FAkmvsOW6#5izlFj%zde4CLYk)H9^HErD;tP2g^0w zZ=4*ykn8fTw8rBvI7?iCI;iH*K@s#2d(2R+o^z)AX~eoylE*%4X=US(RozaRxl+cj zLqVb4{AB4oMUAJU-+tOk)*CMBkrh*mtUQ88Z~QI<&U5)_sVY&^Tbe$F&2qlhZK1Yg z;p$*n*m&z_=o!MywPXr}g7u(q;2Zg-3y#++*{HbZ3YX;MvSM$oM zGi9D&PF_#9t~ymF^*cfHqOmk@0nVj2$#L3D6wR@ zS&x~^@P7IbP|gc=^4(8ke#1C#CN`Li64-~vQ*9?6dvaO~6pyXkh_%`+iP^N~VslOn z;wy~29_o`ypiip!p(`6Q&X@V&kyq5K3-0FZS9Lb@wm3gC?y=7-FT412`x9d0{_h7KjnpSG}VYKOQ z^Po+`V#~W2fk->nU@;A#meXIAe^=wzM7?Ym1|p4e3CmS)1(pZ>ksG7;k@+tC7Z==_ zH-8i|+0pd-l?PSmw9BhC4$a?jcYm}~l&++d#SrQOFay*hhObbdYf8nU@g$J&4U1 zF9(%wa~S+pc*r;F+<4@?5Va^G!aRAp+Bth(93Qu^1$rOF$-gf>#^`ghFb+6~D}8DV zR<>Q<|3FVJ+6n(8T%6F$4$#dQv{-EGYnQl@0~LR60&K*0Y|huQs*&98^+_?2@n*MK zTi+ushcZHP!#xjI>M|Zh-%Wwxsc(9N`6(V5`>_jNKXY<;KRqln*`+5Ogq*{Up8%Uw zr*OOHUgLIkQg5a_aO5LufWPs4wY{7{*Hq7h&c92afw+6SQ-wQ=V=&Tw{Mugb*m~DW zB7l)7x=p|bY-hbC?#cJJ=(=q^FN4W6GT~4o-EA*PCc=EZ$o}S#TkOXh9XBH8W2Pbe z#mCXqPw2M_4PskW^xQ>XGyT|nN>b`#RvUP)m^QH6ni5-G;n~^Rs9;5Of7-T3$I3+# zUfh2jLN+KC40O4$6VF)L@W{WWUFkGoNUb`V64%{=7fO(<05sy59+C5lL%D?uH}w|l z%V)%=44Kqdj=Ig~qVuO_07ad~Y$e-vf4{cs;;@p!ojx~)<95Es4p1?R<3EeEs+i`- zk(0H*?*POPPgz6{WP2lkW_%t%9%Y#fg>0LKu|65`+;@Jx+&YwAmJ7({z1l{p7|Y*L z8;4dyDnEGEop}XWS)Wb_#dQdru0Jx!;<679u$zwgpuq9$2DTm5If>UznyVoo%Kx&> zbSj$WwSOet`WQbbef|z?F}tez8hoF73aRw74{jIBk{BadhW0Xxi_}G87?zG>Um=Ex zqd7lU<-hjMX=~|j|Hjgp^_#FM#rpa9@JEi8q&p$g*S>rkkIzWXIRq|OreJ-|Si`;_ ze7yIcl<=S{AoZuas=Ko1XGo3j{#(=P{zbhw+x zb@WU*{)ODG=4kqcq!#Lo^4YcPrCeAM%^Bo zZ7VV49-H$=&cm5oze51+IUop|I|$*9(_oZA3XXzzZLf1(uJ4;O&f^R$V&e}0{=VqA zVZLZ_8N9~Jg1pgOG5Y~dlYr~|$XZBL ziXtnuO?Rs|i>&=LMgG&iDsTN3kKv3a9ox(j*zDjxx3`M4taPK^P0PviLFz1k>VARm z91d>@Jr8pG1vh5hRH!J+A9}*G7=o_&-*62wA?#J;>o)R&tB^*I>Y{*6{wYK`Q8~%kr(cp zgD!13h6}L^_S;|E&`oG14jA;0|M))=@{|QJ%(63fa0(yvU#F9m!kDov*W~Mj$x!oU z_b_%61r_rOuI|PFGlWK8ZJKy|Z8iZn7#R#NEg}p#yCXs`%e6^>YsOk(yI2~azv9hu zn0RzjC+WOlQ(d-^X*PPG|8^Ghb%F{?n!YyWw=yHEA8+rmVAjzs&q&jd^PsB%43F3O zh6r8LcDe;^-vUq*Ttk^Lp4SjNhTvri$Va)TVVlM#GhixsW|X;UqPDXu+MjpBf5GQ- zJyl-A?)GO}mvf&!$8&CSTz5zjDwQbL42SSFMd3433=#R7&jS_9Y$W5RDe1@;hB_)f z`Ar&rp4`_h9)uUJVt>Wm_>$QTmf=m(+R4*J0+PA17qBy0PUrgM#F^}#KHY2CUcx5* zRxN+M@t1ZEU3DASupy-{evkO@vB~9G~y3F9q+$RZ?zWp^=CqP&E5ymH;DhE}_#dn9qie)A7=IhpM)ZFt+*y9!#{E3=G6$}bSuPa+b{SuOU-ka|`(C=pCB-%YxnX~O{vPt z$@5(3hQYm{<4f5Xl)5VVsbaA;WL(Gw6b}-4heARi7l;y_S z;#E#99OnUZVULYy=nJ z>l#BL%yv@u4wD%N)#^?5C8B0sCXu!dwG}~>ND39ww@iu4j?}1_QRE_J+mS<1D@g6s z5g@&HKZL?+>4t_Q@zMtxt%te7Rcou@;7ypf&^{yUgT8g;1)T2GQ0fRnIk&XZ2-b~h z@E-5G9mVhP-5yg?pB%2*Ff?xq6?Q)p&!InCjRgizo;83NQ~gv0*t zDE$bNex?S?p=_lFMJ#isMs4DcN1mt4*Y_=vXtt+|5&Y*j%=CQzzpR&$Y?TZ~-_36~ zfYYlyENLmzJxR~a`PUB68?TQdzTmMxn&wEh$?5yc&)b>ZbjmzHbtSvVqX^O;nsTcSR6Us~B8ylxedVdQ2C*>T<`H(~Ok9EXUvJAbRqXF`+KzxQke z@_Ahvd=UpK^*N6&HoWf6C@G$Hzem;{PqvyL7Sdpp{9yA+hHvxgx=Zs|?#G?BEdOO~ z-M&S}*IS{;={PO%^o{2yc($v>i1-D=qwwZD zc*cKl0ooXGp>;Ikd59pU%Jpd73;Cie!j~~0D8-*;Z-#;icJ^t>eL&r6Nm`Ue7l#@X zy1)5RQPZ>D>DGjlZY(u^5*e7`d}=00;1ueBgB$wx!^h1b)@8O~+6{ZG@dN6r)7>hG zm3JwtHvC?v*)x$5yAEkhPR7>}3-gk{={%hOS6@=1+apVzS zq>2>dIb=v)0i`He3H%ZsS1 znk(PTbII{|6xlQ^jsyxJ+o&I^ZL)X<7{1mX#~Kd>pdOGg1ciaD(uV|@cYMrf0WbF_ zB^6)<-{9&?!hsQFD$gi&LB8AOK|2N6rUKw^thPHk{ExjxP>)oGA)JyxIJ_(WBQVvT zu*@U$1Yla7^l7i@p{d0LQrr|RJ6N@Wr!9ZbVt$6#{uo#YWG^fL2HOkEIRRuwmI%-$ z3#73Gq<(;BxZX2?dS|#2QFS?Hiv}U-LaH@zir{i6pxTCc>`x?y>wEzjf?A^8^UjP} z?rmvn9-cG6LhFeaz6OkSO14|ATI7+WjW0pKh|zN*Fjs~wY{ z-#Jj@%NFp72vIbAy{^Z_7(1OO4o!&u-h89QyF^FR^h|{#UdPN2nt~s+JhsKm#opH& z%88s7+M)Kvrl+T~yazZs5-!YZ=KM>N-rC@Cl?@60RBGGYveErS%e+SFD$w;+78VVETjYfdGK61|_$ zTDmEeC0A>S5hJnre=|evVv^YzM(-|zz8hT~NFU!zCGZq)UhE|SFN?mI%*Fvq^#T;* zUT2$8g(e58oTwz_Rsb)dS=ZPz7)Sl3{Hx$KlPk$=TgNJEl{f3Sr)burM0JvLh?xO+qw$b#{pO{ZmGdH5*zm*x+I+_KR z`Wd;hBAdS%MlY@|6%ButLFrK_QtZYGA%A^*&JW_Z;RPu5)ia+v3EcaG5!nQ~IO`t= z1>;}gQ`%1xXQtX=EOr_Xh0Bf*SBbs0kaT?$)k<68eYTU4wcNetDMco3AxLX!$01m@ zO|8@HTA}}Y-8PDviHuM2q9BIEqQtBR9?C3TjZS2@PA)Ssd`fH5CK%+`Phg?H${F-{ zhAB^(!*Gp>3>Ef`gCaDS;l$?CMPoF5lFFs6T-DFVTxIwITPmwNR#qxc6mLQ9$hqIL zY3^r-9TO&&d`|<1D<2-fCg zfWeeJuv8)I0kR}A;Zdr;Kk~4_&bgtvQ?uR#kOCv?-=a?oAkBh$Nl72kgXM7TKb8e= zr%Qvhewu@csCNvL)3!;V?PQ6*P}Xq})&){R)B_R}9cX(wLMP1^ET2$s)ec{`Qi92J^y&1KAwR z5qVo{MEesD$b3|gJo`3^bXK%^>F2C#dXt;>fB!Fl&5!6EpVE|7(qU~k`1S7)l z`~z^BUeiEJLd5ZcgfFonn$X~@1C3S>=S3t26PWv*j5e=_(_zp1D@D)aq7)QS1gJ`jJd<8fNq z_WVSbw9R4A!$2x_!M?FvYn9^l{FtrRm2Qi^SZTEM^mxBGctT7}YBv+-siYm70tf zXKGhe&E``cMeDim-AO+}w(xq;LDN(Z1Gn6IX|`Cp2S_M%Goi$6RE^i*a(aq#l8@M+ zWX{55RD*kevN0cnTAplU%5+;=jW6^1WO>2){wPU9$^3K`9(kHhlRX&*&Oo<5J0~}H zt6q>VjkB05V}uNC429o(a=-22Yy=i_ai;bVmQyVHK6Fu0F7@V+|2aIn;2Q#^%dV|t zZ^Tl`oF6PgY`a)=icY=mj#!)NSWJUix2DTRk1{%iM~h+qkkGeKrZZe?*KCy%m1XFT z2@3nSnDnxYUt~l>uxK%yhO5S;{V|&(*$WN(wt=av z#TjNHs?Oby8 zL}<@_rPb46CnDc)Yv59dnlOY3m#w%x+-JK$sla-sG!hSN$?h(gRgXvj`}U@ocN;mO z3JQhU=XJsTQIpFb?GYTinpy9&jyKmo-980sdEI);WXt|IISl>K>fK390A!`S9QBO) zB}(mLHM627r+s%caw(PSL_PkL(Aj1;nW%)}^eU?qoBe2fwy)#lpX2VIn?F6T++K3_ z@8rJU9+^x9QWFpA>i+ouW9gd1>*}6vqsF$a#x@!oP1+=l8r!znu(7QsjcwbuZSyAi zPTt@5Joo88%{^z|y=Tv!J+sytZvjIk&#db;JjJ{jb->482Ws3$qzb_m19Xo@r8iL> zN+gH3R>6*Vc|NWt0$CFAOCS6eL(6_yZ%T(J`-yge=(p=b0Qr}n0dT%DR1fll_wd)( z0YL&}9!1b|Z*F9W_umO4U0AhOU(nTpkf*;xZ_}GbtLv8*_f!tPq0=ucr0+*X(X7F# z9Ga_+Gb@tBUh_={>vP#%ED?so@x+$=#u=BXKdSl0S&hEv+V#!s4S&yzy*o)VYG`iY zXJ~zYTiYdYSv6W~5n9RZqgB)1V|%az%38~4Iq3`v0kkOm1I62h6NwChF70TPAo=zj zc6=FJ2YYzNcbSCirbRcG>tt!T;2#3 zyrt`E*G>*LkvE(z&F4r!Um&G7P_=RBEd^rpbu>C$j8_(>4Q`JXIDrAxYqI9!`U3W}f0WcNXcH(VF1 ztJk54>)@l?MNmRHNl|5<6h2SaM5=#$=-(jVr)!D?G^WU;oiqeX0n(~Uji%WzJids-tNT)C3l~k>+llAX>%XsNT=k5FRGLFo1#z~htFG}&+Cc!XCZHp z+Tlt#rUjAHtcIT3d!x=rjTi3+aGsL~tbQXY&mO z-Iiv9iKtB7JBl~Igfi7uw7=QfPVb6v7=1lL0+zXleN{}(7VBr_1{c*|gvQ>(j(>A8 zwx7MMq$d=rZhZr25^#%rdI)kit1cj~19tv_3b`aI?HB=!!H>x$V`Z1s0LD<#5RNnL@$< zlpV&nB8lVYx=@$ko7LP(yjJI+-NFT~iZA&x9{?c4u)g;QScf0KhLx z@Ri!Q>)U*Z0|1$a4&Y_C_DsLqE->VYe}CKwk*D!~Is4rxrcdOUlt`aaWjwa+vfeay zhTfxDA^y9Q*y4w*3E(OKM8SR-sizYI_!1dlHU|9!kP$gQ_lb4da zINYq{eV&@Gl!m&Ff0nTUd^v4(-v491xXma9E9TZdgOwr>b6_Iacq~q-1H384!fNGofX^w`5z9avm^5 z&$6T;J29{rk0xtL2*TLmd=0;v;dW_A{z0Fq-uY({Zrydq_@Y4kcj4{fRj!6HfJwjZ zK@O-~bUeDwTF~v7vX&5fd(8RqPr*sYq1IO|Svyt01A*^orIv^Is9O(Me z&HD7`yUbVWx6(NO(JEz=fKmTdv)N7{IGJbgxEV`Z8xxqLRwSCLIVe4it|p2Vwdpu} z;rS%4S|9_#PTiewRcr3ljQLAk>91(WeH{%r&76wDkw&|xQ;Ru663rHTsjv4+yVvir z0*OfDAHEK@n;K~S0a09^ktymv`#jSs9!(4KAg)&%mHsSDLgQgGd6PMWM>|{A4qP*v zEnZMpX+?k3S`EJ{`%Ip+?nv*cMQS@u3cJpPI zz?ipoE+c)BTfsg>RJna^8_2C|VmE!`(bGhv%5(JVX%DHF&%g^HFw$L5z`rz!!*4TS zh&)ePPWA%^~vrO5?b-$XN7Dv)gY1Ais zl4}xf54c>K74zj|t+4SDnE!%CN`%k(nEpA-``L`{B7ugqK4wJ!b`VuF4cS|M6r3_< zNsAd9*g^M;0 zD9R(F!I+Tq_7?{gcnzckO+8DzWD*5|I_$X`0=Let)5WbB>SQr+9jBD!sYX7@23x-M zrW*zhi~3&ktL@)Oh=j|~e4p>J;2OIrNtW@^$(ElF@;$H9PId zP6qdS6Ft@U%^jOE1KH9Kvw{ugIoaPl+h3~_sc5-BcelCrpl~%s{^>6^6D}`w_I%`f z1+j>9dwZd1fO(WMj}E)li~Jcy42rU3Pyr{CE*$D}m#8=^&mx;aSPS23M!|lLVHE`9 z+tJ8O+XTk4Gf6$YL8Z1dq(LPoLnF9{(5Z8!q9QlfCc6QNaq9r|{lfN+Tgs4Y<4Q8Z;i{L;uhI`G_%i>b;Gcaz!Aihh*k@b6zHW7c6_>D!A|D$qhag-(XNySpcFuZ|`al)AYk<4aj$KqA(PUcIuCOvMabpvSb*W zU9dYj1No+KdBl38Qkz6iV_Zxzzs$L3SzLu=eBPdLlW3UTZ#@=ELWQL;*MFX87&!C8 zrMs-JP4nAMl7idG0(e8~Bnb#~zfqV#mHW-!zIF_)aTwK2CkjzETN4|*QYIU>CScN8 z>oSjTX92FS?%TEoRW~H6?T;%iLcI#f?bHuW z&4Zw>N#+FEM{E6Re&$M0)9%E?`y1#QD~VWn8-~uu{dHz(dgoYYvG;+GJw%{0XrI^;Vbo4I~oN|Zdzu>XDy!mOHv+v2?BEiuVs5^ z<#1t#{0$+*eMhCvXXI;Z^)3kcNsJj?+Jz2S+t80$KHe+Cn<@3qXJ`but2Mff0UgiB zNl#5}-mjeG61zEe5mJkur$}$Pzloevp>w*|zMLhm`L5V`cl(^xoh&(j>+sgJ5UOEo zQ93+)KH11-WXSWZkX)N4F(!JFM59o7ZHpWb@2s z(B;xzeGHyEfJ>(*PzVXJ5kBR=;^2;y0P+>+;9Kzmj(!zC0W}#rx@hXfp*qF=2!4{? zR1Fd4k>rpxMB}T%K1fE3A0P{;waZI~7tEb0q2Hp7TYU9tB^rv4S4asfmORz0s+F@#pkB$pGS0G&f(3acPER0d5 zg8wc2ar867_Pn{t60({G9w0aajQc{;TBU?P-&+;=INU^8gkBbCcRUA3tT6IgE~>14yV>D=7+5tlxa4`-Exlr@zH&Ud zPwt!T)(j)C#7kfLt>3VqP8}um2IpKqn#T3ku;IxvS@m;q?Te1OC2Ch_?|gP`twUpp z(F2UfGx8$twf(!i%c=ukkZ>y`I>hQ)E@iQ-MGiuOmsq?ZZ{u#23(eyoZOYPA)6JM1 zvBUgtCLRAFI)*dLT9mxLM!z7xBQ~a%9o=R}DiI|3QIjkI2@4z(=I+g;AOz67nl<4+GILa+w2tmb~V5?X6gSzU`{IV zYGD|C*0~j1fdH#0@*@)9nlpFD)m)uU?Lc{M72loKV58-O>2hx~G84A$n`ZqK@F1$4 zNo67{HS2+aa<%Q23ooqX)8i&n?WfMV6>p90VQznaOR(D!6uRmy1<`1za%}<$SR}5Z z0xQ*fPwFMNh~V)LbRG~FIcT$gK^^=foNP2fImYy4J?`?@ByfF09=+?cJH2g&5#%icl2=}bh$gDViwtr*bZe{o^nJb=|Kir}* ztbSe-X8^SlYeX0Su&ZOVK-+*Olx7Sq3o9&F2p3_dWs=W6n9ry;VA)ncf5 z{JnT85w8JFe|r7gawO!~XkF zpSqn#;I{Rfy&)Rnv(_1__I7^UTOV;l6UJud;Gy4S~or%OX9HF8XeBT9#OnAp(cxlXPcR1J1XtVY>Ga zqaoI%!S%AGu*CgwA}(eGNl0Bm6iE8tIrd3%ZiNPnIvP={dS>i zQXKKERc%7x!TSDdow*a9N`KPC>JyD{XO+Wv(~i&kNw+Vx0;t?-<>nvO%Ns0%m2vo7 zDYiNlqvs%zvyR?|utz1`(5Zpda=KcbIr(sMx7*1-&42tRT798zzP@@hvq0K>vMTu~ z#w1j3CZ(KWL}rxBLz=J6!$*woSCtjpDWN`eEGz=GJ&mOzlT&0MI6t=@{7+%_AnHu+ zfC9Zw?BhM=uuuwvaQh>x8Fv#jIi+??fDmD>A*~hjt^R7L?Jr^r4Cfuy50s!cjB5um zP3Cbl9*zijGyrMvKBh1T6wUEj^^7B83Hf%z1Uuko zjm)@eAwXDwefRCaRqQ7Hg%>822x9RZztr&bS2 z4|@1Wa_)dGF5bNWitpp2ll5eiepPrVnR^q!g4Du*#8-d8JL5WEZFE|gFO6=-(=YB# zTV6Hf{ZbQaGD;kOzQQwRH_mgQ`VVhWaR@HZdmrL8itqea#rPk}_7+CLnJfWYEzhgI zxl-bYD9l!lb+%Rq8iP#nF8G7DFZTpmIWQwwl_h&4CRz5wbrFyb;eEKJ-%BxLXBwM& zgKK_u?IzG2Y-a{;ZVfmQ-EXfE_=|&|AiBKcU{#LJmN>9iC6C0Hd~327IIpp);KzT} z#$3mY2QC4!H2oQL64Y;vb^{p^Ss>beD;B(fQZ?p^LOdq(v08|=Dv9;RJj;mk*Jxo4M!ml70%ad|Sym|H2Iriv5) zv2-KRk;Kk`4z9(J0JB)w>iO2LO-Ga$zMgwE``OQSu^I1bzD&8Z3^+&RtXboC<9nKS=CMBg(MK=JM+x8!0h^d8mE4N_#vyPcrjO+q)oQ? z$p`GWQDT$VgmdO;n90wjT%)#f-SumL)H;-n-kOrng1hEE`cGX5W;xg;rOB^}wK4Zj z=EP_Mp-()r^Ru2?FE!aNAP6Gv_iNYf?o^F!#aNUj*eYi?bVgXtN-Qc!rxF!SCM^VB z@1MwmUb0C2lfe3{d?2K}lY0ZY*X!hK$mvgypUCD`@^}2Uu4!Y|%P%(xbK;k~qbZRO z2p0r+q}#YYON7$n!#j_?gcOX5L2#IQ(Si?Gt27QmKU-bRJeVoRrA`(qIz>k_nRnc` ztTB6{JdTn&ZHBzvA4ZCLJ!ee1Gbsb_hdQDwt#YS8Vd^+F=~47v{U3ueQ4k!z)CSY*oT0L@=@&KT{ZcH=KTiy`(2T<|?{kw_dKqwgW2 zV>Gy{M=|=Zr>e19Px3^0+Cy{eLw_%qtsi`whNXrWt*s&-VjCG4X0Y5tkWUvmB>jyLb9% z2{PH}ZvNi{sX1;R%y+zM?3Bj3fhrvSBJ+U|DL9X>V0J`1DFMDz;Lk*!8o3`q{nCQ^3AyEoZ+_Yg}z`$oW)0bWG9QQ92YN#f73U5;rYSElReb(99?0@_)fNM)W z`8PrE<~8Qf=c{BEWC>{^RG3oF2Hw2te-KemX;K zAhI56XrRvA_>7nKA0tiJ8b<17_k)8foQpE}^PXZ@j$Pq@3$%)Ex~K$z7K)0o0I(Ii zBH6#h{x9H7AG~XL*T1QL!mB^CSR+(%|No6KlBtq5;HXlBA8+Gn>bq$n6*LO=W{5g? zkh71lnlGywVnH4I2wsALP*)#DSNpf{Ei8rGr<2>gp&Nwo+Akq)nU}0y8tLQZ%6UD( z!z;Yd$Phzc6X@Sx#d62!`M&!}p*-G9Y_YH8iVpx+;JwCIoO9vd3JW|Z1sZJcJ{>$% zW#J#T(Cl==>3rHntYqDCR=?inF>qtb!3pHPSJ8nVc6^;D zVV=aVyW_d?iV_vcI7R@1Gu|6*SV>+I2$PQoAa7JP?Z(s~Nl@hOZ%>yTCP~&>`|n-? zIl@b?j7E+aMcQp~t>jU~F>*8vU4Sc3h${J(^(`BcYfrFpi_69Rxbul0#MMme)73gi zy?`x>=Lh-F*AAS}RL+DtYUo{6%2;3lD5lNL%E(Xz!QBAlewLHP$aTIV-)PnsuVXzX zGtv=ojR!O?N|7cPWHsCl>5%C%UCcHNKUMNgr-26`J&38(KdfT(>VBb)#;09xsUNMI zhwVoKOtODxScvS=(VI*165e;qQfLBm#t@9ku~6gvO&#`;FJSPHqY;O*B5?wGgd&zn zLeHT+aEg%t$&7#kMGVv{^JHoT)LOUGfwkwSSE|ry)AyjmK}KN@j)44(M1XVDa*H#V z8F8Z;^`F^B`1UG}Hzar+Q=nD}W<1?+?< zVc{zSL7Q)aQGd|LVtOH!_!iw(A@@#?m3lc*HK`jG$F*i)C$OKxqMasb030Fk(B1`iQ+D8?depv;TOm3~HY3ZII|VtlFcj#(6dV4O z9}|b{mJ*I#?S@g22PUPL7A!s*AJ=~%ZJ#oHP_t9}`^R?M`Y^E7KW3dD$Lk*fWzm08 zz#8bwb(UIDcf zNQ5W=59=KgF~uQ^(FVU?&7=uz0sP}BW8^RZtfGJbtCjB$0cCq~V;nQ!VyQbwu>d%& zuJdQEFL&o%p+{5 zcnVnz3Sj%W^>X~supX{*-k8r%rCByS?}<7lx6jvWOaRLRtB&@dFt6(s+UI7AtI3QM z!Rh9Cc@faR#z~b4rvelJ^l>>p*r8hJF^@wWA{->(Q-Bjkm)|~T`80(sl*VOkT)5I; z<2dcSMo^Y(Z!e#Vz4O`_?A_-^{hH_=uD2t!Ls!E18aXm=RD=K5f5 z)p7zF`bQmw?{_o0IfEUZPhJmCeDxzT&bCJw(;EkDOp#I)GC8wZtF5z*?Oyu(J5iI_q-**~7JEWFB5C;+fMR~XcyZqVg#X4* zzdQkW^sQF607dp=Uth!M_0J#feN(aXVkKk5vqh7Xme@z#odLXx1eg!_<95MUK_X<+ ztkBFGsWNYUUZsm)+5~F`sGq@2l9g)u#gDZZ%-aNya5$afDjgm8AtM3 zO=-3;u5F=KK9l_86XYlAjN0X7OL8quY2s_FH}*{i>IKRVkm-i&tmaTPbP- zwlq_uMm$_pP=E+vP;bL|XlN}Ik+MrZK;dwxmoH{!(FuR*S`1r<( zOf{UPjd*SVdihfV%gIABi$R&Ym=Jyv(@%v9CwyY#XII{n=E%p^IcwFH zjn~(|b0zb2Y728CYI$U~I6ZK)=kcQC2kiv#a!)dQ@YrLS7bzR7Zed==07W~&;>Ue+ z)!oI6&nnXn2(E#@&sb0AQ)T{rc33Vv)OhQ!`xvw2} zaZDT=mBM4v2J#Hn?aQC8yV3Y^VAUvRMUxG7aXe_L{I#T2v+Uc(M8H@1mWI9zd4-d& z52*FSVSPFLV!c#r^cb_H@}A1;uq`*zdVF6x-h4{0MpBOUN5HO*01uEN5Kad+de}_R zROPn_z+GEot@egxOnqU;3|}59lT`V7hD@*yNRD||QY4=~okmW4Q7x%7dB`+^PyFDX z)fx2cM0MOyW;AsW-}K;!i2xkM2j`B3NYI>(E`wUh>R+Q$!NUhIDEbbC9bQRdm)j?S z@rQ6MwLZ{*oCk`+rxW>C}LbS3@URpzAxP{;g1RNp_31)9p;` zB%$2a2AsS-%5v)q!S`}D8bY7_tABj;RKyKT@pAxI-2A(a$9COE2L!L8`+GEj9xQTa zMO4BqfdBF4efY5HwS7j7B88#OYBTgIa85lNh*|!vMkZ{Ua(iZFQo?m{Sv_(5V~czM zKo=F$w6;Cg;9@q<{Vu#*Xn%r7X2cTxzO78(xh%eAZSgFJMz`5(^DcUIu^w6L=MMLGI+4;l+}RM8O$BF(2DZjKpY23y(@OJye{)QUmWR@~Dzf%T9R_}6 zox-|;*j}?tF5D9jk+j6^z87ohokuj$C6yDf*^g#StiqzJ!6!VPG<3AT&7Kr0Hm^;d zMf{$i(K*guGrOb<5b}9(fYbFJ*|QYYub2&C@(M*9qu4<1@y`AVP95>$Mvxk!FO?CS z70G`P?jW@@Xkw+m^%YOg(;=hZ1USb87sT^ESOqHJ>o(RdLVCKOby+)JcSKo8v_!y6 zX=DdXP(yBb;R|FsS#e*NOgVoIZKm9lni-kK1-#SKO|u_GVfNO*6*PN(x~*mvf(=+~ZD4{_sUZz$TI&Z%{_Xfa| zJS4`hVX%YsGbBGzFd>L=e+5(3Mh+3F_P#K+E5fU7cyZk0Mvy`f6NmaAKL`uOBey#s z{3)dziQjEC6D{wCJzcqAn}y^@u`hIEM%Q*+6EDW#-~P~+K7bN%-^oM1_nD+6uFV}1 zN6_NBYl79~Ti66?+{oX69s=Iy%~V4^#|oGh0lkC{cq#>;Gck-GFc{)~ng1d^^dHL1 z;|1w@9Dq@Ok3HK01N+KK^R-KPl!OeS7>7C6UqcyTA`opfo9-|?yg1ot)L%mt2OWOD ztk}2n7YWW+Nes$R$RWLTE`s`ddp@}bIhTpEbDxeU;8v))HLKS4a-QXIyjp)KaUABb z;v8bNa=tMiNigbfsL1>v{sRb(AX9zSwie%YUEXVt+At3}2DwqCh=J%t`5x};_8Tmf z4BG|6Zix0D#O}Ek88!5RP1P8>_`h}AcpF@Gu*j* z-)&CZ`NwwRna6q<#;3LHXDA8ex4OKh2ja8}15JVjdtl~W#NJ@8CDY=`Vj{R%#(T26 zV!o#%@gC3S*-mXPJ}qRtH}5{mPC~F1jxN^pWX>SUrxlsbg)<8h^QFWs z&_>q?bK)VT$GN8mx>)pjkzY=ec>Gm;+Hep|&3~VKGfqfbgCt6VtOPUMexck>#DHN` zwHex=)C(+h8*japBZHj~ytGWRKmu>9xqQlg9?a-`qEz@^w^R{{FO(<}kFZwd7+pH{ zZreL29|?p~K(vwGZTFr_dzGgf1Viz01EBeajt@ePQX$N-YUPkZ(zla$jhFOpWLYCA z-+X&Oi4#Et6xU(wFuAowUuY!H)=X=^))Fk8Np0M;(L!H55j5K#_DPg$l~7RDdR^v% z8j^ePm8bXvvT)>9u{EY_gGo5$0{%Uk^lb(YpF--d1y)#QYhaN_)Zldy3vQUOluI z;2%&;!uQ{JlZL<3y&oj93{{z~Q>ED@PX@(_*bNcgG*8B2zzdR^&~<+oUuM_j5D8V` zvT42ioVXdXl_rPaxf4j5M3_nE|2*ivaMo?TICMlfBZLqYUHstGb`_jsNUsLgb}D)d z14okr53Oa&K~MM6r0#Hw#9#H?89K+2|GU`bwS0}lZ>>yW-V{NrH@ePjBc@iSqv>5N@&s!_&69M#F zi2R;AYB`iDEuX6}T!%_H$i?f78lBsa1owZ5%!YEc>^90euREChAs&5m<}{xC)!7Ci zw>I@#77|C&ZqSYSHZ_NStK4Tzd=FE!eDOW>HP*A3u)0Az&L^2iGWfi@}m2Jp2|qj*}7#UJ<2%Chesc05z5Hw^7Or z#fwMpqMk3CaN=R*;-W3pj&^Sm>M#kp7Albio==8vbfw&I1%I_E;8 zSX^t0D4QpJ>wK`}dtP(Gque9PQeO_C1DBP$?jPe%#Ikb?rAQq{jg-+6moZzu0gU)* zNuDV>+nd94CR$brKzqY0H%qM@si4$4&OJ@|v(SaZ!Y!^ycS8(&B>6s=L&oh%?)+T> znbz*mXD_6s5E}y4F&)eM>&qmDAg)pgm92kd?_hX^x((ihNJqX8!H{;&jt83t$W-rO zsh345LR(DsSk>4x#6Q0o91428u)R(C5oG^tFeW@6!Q1hIOFbWKNG(6cpa{i5ocgju-7mtF3h|jD(D`3B2pHQakf4E;i=t zY1iu;Je1VV`cIdMqbVvTf4D|H7%43W?oQ?vUp>uBTYo5wKBn4HLEA{wna^o`HnD-I zu5FqDt-B9XaM6v^_WMpLM)s%KEp3j($fYBZ?MLQY>3PJeTHVIw9m(38MB$SncpCKE zON-&E#OX4AGpJTz(yb@Z4)hsv3(+!A)yQynYP~ar&~32JU<-!eS>*A$c3gmZ3WVf+ z-JY>SX_B$=``!|{NikQd*dBg*#o1Zm^ekTFKrpC@TOxPP{nq%Kf{4>nJ>M9%BJSaYTPYHlHsa zO4Cc@v^mE7ITa#PaH<@mdD}J#&}_g^X|Ta`7t^W<<9`?Ont=J8PVw(ghhcE;ubJOU z3={CJyJ_P>golT(8YN<%8hz!?*5CT|w5o5WQDtQtm2mKn@3F2%(j%!F8^B*kU57_f)LQ@krWW4gc=PE?>PejwB9^aY^;**xLq?zZeFR2mKsz zW}ur-mP-|Y>OdUIlzZ+nWdI&wCi*F(N9g2QD)71r`MsC!DvtAoS`=M|?`R4W=4#}7@Ys4aUkQ}JSzuHh~-A5 z2Z1z3I#tq~TGTtffMI7BUV&-{w_>0EU(Px7Zy@bdc`rH-q_hn2!74%|x2ad0bx+0+ z#>ng9tU3(WyN6^ws;%a5D|Lo45f;T5J_JY3V5LC$uUO__SLjkMz#pQ&XO@P*s8RrF zqVW8RrjKBuQ?@gVcvW!rWHcH(Y8Y37#ET<(Rw4Kmqb@z1a*~zF$&B=NJu`gGVho@p zlYn~zxsA5n0c7!o6meg*`Q-Wrqk@rGPRI!#-G-U9Ud6+D+h2-IE3kdJc&ISoz(@r-~^0H**ylIkoX@Go+Yt%AVd=2wREq{F7ED(=O2sIK;9v{<-}t`1T@7-gO2PQa^!4?@ z;z|Vo4+cK@!M=U1O--RyIrLXMzQri);5p%B+*MXN^+D4r6q+<~*R!>N{@F^~cOANm zf&_A-2e_3*r|8)cj=}uy(e9KgCKHLRh(-JX4*SDOyRp5qb&H(=&A7{IfNULWF8nbh zDJWp_$oJyl&Qr-1zz^X-{Obx7yrq{t%-{Id38n4a9{Ux;sqYl9wfWpM3k$W3Gh*;= zzHxp~aQ_G-87fx8TKv~`Rf-HOEQ_LhZZeES7@Ylr`RgQq`}@4>SRVaG6tdJcqgT;l zo^C2`JLgc1JbA;I1wK}Ha5`dnySxs*8WO{4LW7!VK|{Y&MV88jW>zaO!0SbG!~X_| z3btXOWlI)1-0=qY9(%+YF#X!3JX+I7(GfSr}xXu)HOn}wH8GQXICg!XDJ8iye^CF_` z*O9}P6jg{AfekM%KiZ!S=d~-=FO*J<7n^nrZjYDiOQ4%edld~xG%0}2>Br0w|6vZQ z%wSp9U8!46AnX0~(CA)QwPCsrL@ONbg|;3ecrJWeWRR3DQE=#`-e zgD@~LHS{ggP_BB0>~lB2vHEONPjz@wXO>7HFoV5rLbUR*GDHGhZ1b=7ha5k?7Ait= z)2kTYcbxd~THqrFNSC5#M4$iXB;A4Rr}V{Z+}(%20~n|uvXvw;ct9E$NVdw6to23f zdxL{^{+NCIe+&`e9H$Mk4F8iGkIw>Jc9MAELJBeECBu8W1>}FD1Ot-VhbI3$O+(B# zNu11EN$`l$yV^9QR`q{BWA{T88c8h@P}BpG6jZ*~ELS^qENeAwZVS29|3An_;3<#3 zhyU?vtAjob4$d8xHFI=vs>}oTLy8Z{PJcgh?vF1?NrHo63v~_c-uGcwc!I7}jvD)_ zmr#@W9$rdRHb8qx6MYcP+VDZc*QZjrKh&D8v2K61 zxf|uTgZP2)fcVII_!u4@UWGG>3OFZ8lqm7BN;p2&6{r))e!A+R781&$fG%e;5~S#$ zLgge@BfbQOGg)t4y4fGwzF5#LV)%LMp&sA@w0nsrLJn-(`%h>5@_nuDFFP z=!!I>?eqG=VKIL*1`q=i^vANHV1UQ=BHu5i`Iw?$Xo{ZFe0erLp5-zgeLT$a z!3tU(?Xn37F41hb!qSWfb#x=*b6VDYUz;>;$6F@x_)($r)n(&fz7EheS}|fGU+=(b z-V)gmd780=Gv4RY5SXH}zdCK4ZHY|pe3l!)48}eadnaFx^C3GO*}E-r{smSLSoJ>w zM~xQM8XqS9O{UWfUrWGR-)4!!)`hN>+2?H{nt!?{rE1N&#iqmSbH;!*L^pZrfLBT@0T)As8_nHrb601nD+h3#q5{we}nEhiXd||+BHp^+-|(PmyO4M z&KD~WxN!9)NiWB;mUY`QXg4!kZjeWx0!-EBp}2vVClX7D@4$lP(*kE8`x)#`nx1r)pVN38yZAp|U z>u>A{i^WQfe4L`Y6RthMeRWVgt%1+8nf*v2G(ZaW$B#>9Zh};sOaLjDZ9Mi|ly3hz zM6Ih<^6gREU`Dw^@2&`62?}t6pMatr>}KI0#mD}Fp#iI?yb8|>!xx%GdD^#%>okh# zX%_$8x(L0yRp;~05?Gbu)9+NvZ;7?I|3zEx{gsSxl-}R^YFjA%RHJe;$t1JMeydyepIx2=!}C3%8Jzjq@?4hZ^(c`CLG7Be z$EBE{{jL)MJMUR-*V(euo%~jtSpTA_eA@Z;KbJio2V*7c>HJ;BRI9~Gon4_yfE>&D zSKH%6+xd#PSHx~CLjZ@g~CS^y*N zo7dzLx}AhKU$8zj&iBp6<1i=baw@O(d9PB2l*V-qEb)1N<@@n4#&vOJf^Nrn*o$6~ z(`q`U<%rr``m+uX*hE5?oosF2498LvY+7R#yX{QYp|JT6_kN{?B6#ma=Iqwg8w;B* zRihhK?2}$V6?NaQJz#KN)h(Q7GH+4d-%iVBmH#;N@r$|yZH0v4giZXDPa_9dQNv@U zz(FZ24ESmQ*lhS;$M<~1|5k(;tCKS8IyCEittBr94i0WOi`DPoRH-nre(^=g!parK z`}MA6Alhe&5jI?OVv}L%k!ug2@9ixuN8UedIBa;>;Jgu-hi35YCwq^jU6{GVvJ@jd zpI48xdt7+2M-S4(RCIV_KZym1|MvEHf8F9A&T^dQh!*m$YSMRgGEU>n@VXuy6Yomr zfl02ka<%2kn9m4X-Dd&}Qy;za$g0-g#Jn)Z>z3fDzXL*!& zXbgVEwmh8N>IJA-$7MC=i{_=gttU4}MHP=v2Tb_vi|3P~6ImP#kp~1{7<^Ku#fq&R`sc-c^u(#~I-J14JGLb0kbz-pv(l=V6f~?MSc> z*CPP{i9W712RH1c9ds>UjlGB$&3~O6MW|S(Bs_oju;Ihaz-u;bdW)dL7s!Y&v+;Ce z;&atk3Qc(H!%2vCQjlcL8co1Kv1&1Gc)+#MYID)nve>T4<^@!0Rp~$C_q~dxkNBNL z8@89sn{(ge<^?yGKDpPPF!e=; z7^VTmm0UtA@{eADcC%Lf>%B+p%xU|}xaU#9*Om+KY!0eigfUTrTC9-l&hG`oiMGO! zfc@|dLWp!veqKbzQUwU_h_M2XdX~qH?c`@L0nGFpg>C>Rfl_iaFFKRrF;WvoA)T$U z#=7mU7@+)v6@=&%ysfzqbB;Moi7W2z*K1Vi4-vW$NIt_^Hz9BLqWRD4&8k3?s;>S6 zq%NW~JV&9r|L?bagy`NPR~zL;3|em$~4<)P%;6Y{`W(ljARom0(?5vURye|V@l zL?rng3boi4IBGE4p;-S*woWGtJ6`p4D+&7X-tYL2c}}i{y|YcUj72S3#6pAB)Je|dW{A7Ym!i#pg;$nZmqZ})0?p>_S}jn-=02Q?hYBa zNl;JIho7?0ir{1TtLd}AOsr-BiTrLI52yMYSwp7A_vJ51JQ%%51IQ}dw1D3EGyimf1v5=eg*kk|IyVj9hbo$ z9^Q11K+P&2vNIU+MsyA8bmmU8Oepwpxf|{`7@?cRPsE52lpr=op_@@sQzE$AwyXZ= z^xqTs+l@dl3^3r7i0A%(Z^&QR?(^X^uO$xx=sjsRGyDL{{s;^@9av51W~o8xxHp4T zXkBza=UU6PXBdzN#wFzSzv%ybj4DznA*<-ep)E$@1q)pFJ|f{C78fFy>nQh$X=(U< zaRz5z7ckdIe>$s=62F%wKJ`=351Wr_Z=PRI+}}%CF=AglCHniHOo^0JLK#AA zx>85|&UTyR1SBQiIaf}9jnQjGvLXc%2@v(lSKW*gHr5^(TcAJ78!pUi+9(Qy!L_=$ zwNu-|pMBl?3Z1cMZB-+Gu3@s~Jw!QS%Ne#=uBOwpcfS%%c_(6L$6_Uy3n&6~$f=@K z4%m^Oyv(UxDE(5d-?d(|cI@6+u@S0!Ahc@_m0MyLeg|ZZ3c7shp#>((*Q&;Y7vW=_ z15xRhAOaf9or>`%70{iI9iz+?!0!b?m#{4(e42K0RdO{Q;=k|9vAg?uPFky+9}NW` zH|_WicJOML;@1l4HR~s>w??~~B-u&yVY7&sWO9j+aW-7ZB7&%gZfo-Fnpn z2GOtMFow@hHq$34o5WZt@^Id;$(L(c^}R5OlLPL7xc9H}>v5^5YxMy$f&$U_x-D<$ zB52`XcdUXC6*8fB$1n0~ z%-op-S_D}0cl&8i?7y6Vv*Lnn;x-T08=+OgV!kZ9)p+dh`%4F(O_LF*QU!(6 zR%THtn)hx-t4=?r2R98?}SiLAu-s+WTnnpB5o%VIeLe4EKN*(KFoZJxzo}wnNFSwp#=a`IiV@&qodF1o0!q z&Pzt*I<8wkzeT2$f?y8$)1!3(~05jt-yJ^a7M-U6tq@B0I#L=b630SW0w>E@Dxbci$} zpmZbMEh*h0El76@NQWR@m+nTo-Uhzn@Be1r%$vExIG%gY*=O&y*Iw(hK5H%S(D{B> zsIv^k8&!cHs4V!Ld(i2sZevYXVRG|!ZHS9Gw$~uBSi2o!-AZg;9lU&SDe0u8wgJ^M zX$+NDqgYkGTm(GFFLJe8OZw{9fkl$YvO0u}t*P5!_XD%dY?MyHXt=vxPCrv)_r#nd zOS6umkKYwl+m}@IJODA07Tq1)pqScGXSR~(@;Fx`s0v}s`CMaxo{G+iKuNc%ka`3E zV4at7p)LbBo)B-~nC4(?#3^2D8Kz`6Y<{{Saf0pQW+hd4P+8vAY+g8$-t?Pl*$cCn z)q%y&^yS&DKb+6996pd)BG>&$`_6q@n-xfowQMRB-av# zdEnLB_;Mh-AC1R8d@&F)@YBIinz&_9?Jj}U@EU z@JF-0T7H82pIQ_ND|Z!n4wZ=>RGMO-XJZ<9GOdp8vOG%c+5nY_h~$g<5#P2d$Y=yZ z1P{$|vZWJ65ehNeywQExr=9jXN&?^Uk+Wzn_tx2WE{Ejx(5sfJ)jJ`ZZNH4PTgzcz zS|nIzrFP)#3=Tz$*PF|?aL`FZ{VvUS0_CVT9<8m_srj@S@Qdqw2c>-u^4fH6GL&Hj zSNd2o`O@9qQD4%IFbq^$82|J>>rJjuwr>3Cfg|QU{UX;W?%n~x7{81jU~aa^G&#!N zXYUnVRKQ|scdK(mzxwlg`3VCZaA?W3-R%bSLzWiu`GA-B@A0UCX~1 z+_4n~bB1Wa?0G6GbfM6vc_)bIK?RhL{JF9n5+T3KqiL8VB~nzer=vco>vnKx2da5m z4Z+IPwzWx^p|m`^`;x{g4V7f0$QJMA+cIY`aYG&?;VjqhNJ$|@u?KhAjyQ^A;N1_W zd7JN1LLx7Vdl)_(X#H_IIO2;rut!Y4=;SJ0c%s}hnMr&igBkbZYj3TyKWfctrjQ)5 zC!+I46h!!0$&8yN{THEy4T|xe_>GCFAVt4=QiK@ok1Nk{Ik0m@E!ot9QF}>I8J{0) z;u&`|E_atlZJ=3psde~Mu#ME=BJ)vA$UZWCELR@5;rc9^Yu4+MN^*oRA1-IsFRrVr z3wXlJ=<@2G*+sy+2dzm$(ES*0qqt!b#Gfw(HZe|GF^TDj1>m5_(YzfR6Rxk8Pw?-f zaJKD)oBOmK5nn=;Ixb`ou<9w`s_mQ#G#v2-`{@K!a6gbUA86PniWzGH2;jJS{%o!; zcLf4hU2FJjgf5rCUr-pkTG&cYxkgt8Hzg+kDdIImz%+wI{-#Ry7W}?0LTk~VIf#)=|*0I8M=J1!og>{mxjL$y%S!| z>0<~OMXT?z^jnvFj23AnQkFx|8hy~Yi+1%X+dFKc3Oj+{oM$#Qe6vK89^fXcS>A?Fun9?3P{-^p*rBE8#g*Kf7ns1x?L4ULJUSf=ECd3lX#fKOu%Vb@2P&o=8VX>drTX0DUK z{QB@dtYmk9@PY2pCjs@x?_}Mw$WnG|_xCoXULCFxHa~tBt`~=-d+qnrP1(__-553y z1QJYQ$a*)kS4^Tm(Zm;jjv z>!FE9b6xZfFd)9bZ1*95Rf#plHdEgmDVT{jo1U;=cAlCLWOnY?Qzu&OwNIwr=2oq? zcCW+C4urR_E;C3=uDkF1`8wPY#=9t*4SQ{4U7J}#$e|A0`L-b+sC<;8hidI}mE*r9 z0zKJ@Ow~@m*v^`I{ltGCh~YKv7*+A%wtk;qGC=6(K4uc$PEtI;#l{}`GTh!AP6U!w z4PQpUbb~YwL<8I7bSshWU#Y#Do$u!l{$Da?5ER|K9TGrn#NQRvMRd?d*0R1`!Up`^ zbKcY}AcXP@?$8%yG8vg^R0Ie=7P$x{%9VW*zP-t;vhnL(n;a2NU# z?EO;5=c`lU`SJXjQr<-jCWZt}l;?*h?i&EH3Qs)Ce{)kukPGuEU#+dORTqVC)8RKc z(v621id)sWO`)#^S~k%LxSq3N@DJrKmzp@rMxgPZ%ZkM>I8(@6TJJ4b1ctm+7D@fk z^Bs$CDiGHj8Mj2~yVt`s0q`U2;46CeypxMp@24}K}8zBTG4n^p6-8Bz?YMIF5EkJ?}Vpnv|!Uaa9W+$N9xDH}#9 z>ZE~KZws8)p#rt=qKsK~)hn$LSEei5h37gm=TMgou2=85K zKG*4G>n*OXi%PT;o0hJ4FHk2}Cb_)OnXC+xtq>zpmj{Ob`b34`6}Xp|JB$pBFMVl@~+riT5x5$+9Ju@9Fi8|DbZ_@>o{|5i>@PBW-X<>@ec980y`24HF~Yj0h<*Kc#&AfTKollU}sf zf&5FR&vj*wYg`@f>CG;?T`$mUn}(=)UjChxIFkCGN28T)>8|nzB?CMpg}7iKJ?1Mn zvEu8SrwAgYm+e`!D0|bBMUg@V_=DAc;$%w29nSwDlHoY=qAwr)`kuajLysaw(o|10 zEBL>S26AR7+}^z)cavz*75YXmHtB@FD3eD$V`pNtGs6AdTy<^-!6=m6$XJx{AARJ>!LY8R%+1Ol;xG1tV1o_ z(6mRVo<9B%SxDpQ!8)$f>Rd)gJc)*=%XZ|EC_gKgMqbc}^u4N|5|W$$DKF5=N(?5k zaitxG@6iU6|9*zyN@XyNwxW`EW9&|L_R|v9+z}Y3&9$iVXLp}Y?aaQRC!X1{H$jEmm0$YIVtRYODfoA$PW(Dy zCBp{&TV#Yl+h|-Ra5@yC4q5)yRzgU+{(D7JmZy~X({Nr_vq_gnlF2*-&?W0J4Y zPHbB~SYMAqIzzl=8_Fkak3f7P2PBUmS03imvDzH;w+Qi$R>E+rIEjU2jahp-a#Wco!9^TOEkiOoU+ z2~wPZ-%Qxk@#cV)@*1^eFO}+woGDP?{qEsR`l%r(BKOP-R>O3|Ce8MclFtq<(P}91 zEw3%qs!|=NTO*WbZ2zpUK?^$Xz71zOHyVIW>xc=(_qf zgF2LVf4TSSA{u%E`|i^QPE=Ngu8jRk4q!0dYBGo=vTo|01;m*lW#!aYvm+eh?d{$B z%@RkcK$Z8jBTQWze(!$FQfh6V_8GAw)p^~_wn_O^EBC$4FStSRtPHMAp5Cqu3$-qQ zf-;-1EA1XLJ3#4(^bY@O+RkJ6kni305`CQ7neTmGo|Ev7>H3JHaoYk7V0~TmPQ*9p zLz@p53+#l7%y7^~X9x^OvuC4N&)eLc;7OW~_s8aq6lye06ey+~KCN3zW>urEsd{F( zGKw5-6t1JyA5M44e~Cj&N2%n)JL@m)_|5ffa<&i~&C0V7r&iMS{IqS$al2P*v2#{I z2p;z6NoIBMBR}J3S6g<2X;$(<=kIk-*hjcU(m_m{jOp8*wSt7;Zmh&t4y$JcdvE{I zua9QVKDp^r?whLRMyoEGE6L?&73AKfN0|0YgR!JUcqbPlP&MY@&S!v~BNW0vc(8|K zC*P(Zmm}|=baHZ*jJ&evp!(|tBhMeWvDm5!yPDQlw)}DYN7*L6$8}7eA5VQvo!Zs8 zNVo9&GaRG$3;2@j`D6z5*tI@2%H8*JUO6%(oW$#cUY&a#QO5kR`=EU3znr+zd+)g~ zpY!_fW*MH^OSS|4;w z@N{hzI}RFL#{<$D+$!^w+fI9%PoU*Y#os#)r9uNtN%Q#Zp`b^vPVSdG?S~}<>1?yG zW=N4QAy$qqu5#O$5IuOzzDXTFsfMIay8v3(UDoR7y$IaAO7I{$2&iM_Y9M*YiGg-Ti~M}VM}t= z5w526_)&TNo7^`U14$c+F2oI!Q*WVC7hk4=7b<(ZLh8UOhb2C&anN^li+=XDDoQq&xAy?R@}wZM$*Wi+Qm6FNp?QF zX3sO*X`)*Gp5uWS1_Ma6~q((~wN^V*??L*GPj4R@P<9y$fmJbhseBh$fh`Dv}9k9TJ> z%glxA>gYra?-@5E&#_?ICf-3^8DpF;;ye`BRk0$?N1dxhRP<5oM(o9=@oye>ehcOY zYwP}6{B{?fE#GFNi3PiP@Oz)aH4@gH$T2u-jhyX-qiHpm@>Y9iIep!Jfml`cYJ#`Y zNHeF0`bGAiOfk<8vY_K1jU*fg>Qc@ZnW3!8Y zhNY5oJ(K?m+vH+6JoaY*{~1%Jy?*(t8eT*`jzXDeKCimnQj=wqP>7wSap)V`x2ScW zsL;oRWp<@PBZsVpy_=r55frP%Pf?}tGE}W%opW-qR44ThC9O^&Umj^WLlgLQUIprT z;VOLCiRo=Vm8Q2X?%$Yj@OExC82Uy|NLCtDmRDiJE6Q=yX$5fLv2=UvhcmxW(2~W8 zWY(N4KZeUB*InS+`nw7dPdTi9uPpZqo|g>|!k(|d{lNI{;1dv4EBpSVB}%i_@FfBS zZyg5WIVi_cOKdK#H?w|YKb_HsS&!r5%7sV2574zjj-LTDO3UT^-k2w9MNlPbSqG5; z{W15VheCD2G`Zd!Iu1h^ zy*!e!4|pB*&L&?Sy_|yPs}~X;Zb~H3_XYb8_VboijMjNqpx%G`i+NBnzjPHD$A9m@ zt3aw$RunT;hR|tKV0=ctus%T~6>>gQUACV0AzA3Ch=B}7xgtM(z$fE{$pB0J?*7ij zYz(>_ov^*e(Toia+N%ub?(f>M1v#@ZmsN?q1Dodl`HYW`~uIoc9V=gt1 z+4a=?km(sXyRCkP(uOiP+D^uIX}KJGZ&&hVs?mviR_FwZt+VDWJIrD?OUyG+o3r?t z{ZT7PjGO%~xSwL;CvBZWop6Ryd*!kNJ*dd<56~Ms++lM!4BQ?|3aN|oZ^~*uvcyS^`RhhaxSHN>?B9O z`?}{C=OX{{*B@F=$M?pNcCgHs?pFj--?xhSh3M*6g8jC+4t{G9tG`Lk?yXE}AFA^P zR)>J>vy+G2uXGE3y>u5CeR`4^;6jHyp|;Zo_nXrx-qGvz+}JVOkH#O7XPR{(S^I6% z&Ktv7ra$?0=4;HXWa;86+6||jPc(c~%XM+1fdvv2_IxS1X}nRo~KgSoTQAu zlGmhL`oXiMm%O4c2&4I(_Tixx&XR{51dFGwevhuOG#IL9NdiRIZ4Da$nI72TO-0Yv zq?%au2Vp2=oR0^Ebch^|gM2$gWFN&XArqmK9 zA!D;89#n8t$o7QqED~8Qy{!G_ovs;`(a7%dW5Huh?G68FX&UEr^KktD~9DSy-HH_bZ-?$;JE0B=Coz+6PL_5|oimedyM_+OjzxYlD9JX~JS> zwGiJ@t5QJbEOAJNoaY0Y_uTGrz%ERhvDaJ{*XYc87*Y4qI21t#IM%q7_u|^}7T?KC zz>m9JZY_uNCHz^JX~2>YjbfHp4BzVtlf8mIzIvsO`$f^uONEo13)aNbt9?CUnFal` zU(H8NONu@y2i4kOZu1Ede#82z1}9DP2`)oVQ1i>@Xpbzuc~xbTVIJCFarMcI5t%Q* zDl<6`SnHzOBV{@<-7^!1hMy6RE<)7VdA@{ez-S?0-CGU`f_`)M|3%V?LZHVAnDG`q zsSjeh1_(E7k6mexUi@H2 z>mgh4y;ZcDO}Fp|sq!XWhQbAPSDj~!{Fh8DhC}og+5~ok?g>KzdDBk2Jp>^uVtBl| zSXBqzRn}K4XX2JpTL@iiOPO2KS!cW#+bR{AWHA_WTsD`3uMqhKGx@OQUUqr#KT&4b zaE*#ER+8tB{2XwRLm0-DjCg0A0+1GSMtjQX(X;m!`GLZyN#ye_U+sO&&S7+a6$;Sr zUmn#b3P1lGRvdWD9t=&v5F}b${dvV%G|PeQx= zI!W$Tx~JGN*;1r*n(MBN;S@}s`pH^r~`i7)$n(*N8OBSKQwlwMl-2-_tlKa`+(R$AQ z;%8gA+n-G8)-&fNjfTT~f)!+@Ik*J(IEqDjx5S1mqdF#KkIOK;bStbZoY_$PpJDj6 z^5^wrC`}KZQFIl&Fdi+et*tHGBzJ6jFLy&)yg8*EFhcjJ`}nG?hx%=FiuGjdqht-C zYK%3JrT5Y64u7#pRZy1|88yOl#ZJmHa(s+iVne0P=kSvui)TNJT~8XjM>dwAVzq?R zbB{VdRaOMg`GiWoX-AC7-I)BhM)(J*_Yod)K8wx*=l#T=uSxWe+^TPp$7=?hHQcj$ z_Qf>)3MR8R);$VK+VBJYPEQUA`$nY%yGLmqzFNP$FBX9q>kt4DwtTEy?ZK3Xi7L*M z+I6MmgV{MO5;m$dX|mZ#-|QfnW~O!`u}37?$WGOR^5sGoR|H3o@Y{ws6?Q#+#Iwh#TXBz}i02 zS`04u9g_}G*-aP{?B4cIa8yJ>#EapZ{N6ny&|(d7G{gbz38Rl}4LP}V*W6K&`0pA2 zJq7Xs97i1+7xWWrb`uYC@>eAgONxV1G-Cw-?!$a2mwT%Yz~9l0GUmOLmHV?u>h^7s z7u%a={igZy-jXCUnkx8ua-g2U%*tQ(svjf{bEn>1p_8(QjnQB!>|+&3lNHC;gun0C zxRx;VCGX4sK%fBhF%XAzQqosQi3UKz06a~GTj+DQF~m4wsgol}N4&0AC5%@9`h4uR zBMew4SwuK_K0P;_90^U$q^UR+4rY1$p#aD|EI;zHYF(LorlFa4RtwN*)Hi%-l2B7H zV*@5_y8oQzZUkAri_?RWrA~7UW;WJG?$+dm6d$F?e&-5Tr#k$#d%)bnz=7;{y~jen zXp8uZ%{9)y1aS-V6&ZfqtIDvHkEiu)UVHD~^_q9*VUk=ir6>DaiCdT*%pcWruq4?~ zf$s^b2UcsY8pma}kV|K0hgoYg)I|gD-%hO4T`RVA^lyR#Aan%<)HaR6t3_T|#FSE$!V zexhZ%F^f=VJ3C4a=^-xLLVGP~GaI1h1&CY|>~BA~Vvx?P?szVz`K<1#AvpwjNQ#Z- zx})z@fDqG$I_TO}lzqeSy_RNTW?(y$ebNGaRvn@j`K|TZUB5@z6-T>tLx?^N=)TR| zkX5p$pb>&HS;LkAuDYukp4Q*60I@Pcx|2s4QL!k3ydVTQPr*Ya{Ps)-e-V6OaM2=$ zxL(ve7ZN5G0ShFLp!)mYWnZ@l8S_KIC_jiHAhMc-Q?g}m1AzCKY)wFcu%SChUo_hjtFrYyzWuNYbu!B%5 z-$v`+RH5`8ctJDQu{)Ol-ITw=1Q7wl$U$0*Q$Ps2?rEf=%bI_8ts1Ba@gstW3lNwQ zJG=(BZ(*kEzsYV9A<2IEBE-DcZ?;_DVR-jQMNIIs#|Ay5aN^hT8sSR3n-=u9q6DU2 zx0TQE@t7odTD+~6(cPZ+iv-J^mp&+s04ENvg-(#9{nMqd8nc}C_V+zMrqO{kZzM2d zlsr#{?zE;K1kg?QaJj6rBV?#ZhW!3-kn(!i5C~Wc1Zy4LC?sKWzt$E1J&LNk9z|NF`H(iekyrRL^7c;x;FP-exS8%y0CLZSZPj!YJB%Q7WN z!Q2^ee>=FF^z~+FW z7_SRS^_@z^aNoN=q|tc~9=ns>#L5!VQ&~X+#J{qkOAoZud8&}__#UQU!g+`4Bh^X( z!@0@hA!t9*_5AxqNG9eAh&_SukMWy?{Z&vYD)YPSI;MN+^(hSQBm zx*jJmme__i)w}Q}LUb6`g&|O^TcJ z8zBTXpc6_s(KW8?7~Os#U#}HhTy`tAdnGcJyUk?#AV|LY8`qp8pXo7_f<|k(s4y}I zMW>DjK(1>J{mo|k?-qFoPMsjoPMxegmXnAS5f2uq3eyngucUyWN)UJp8)j~j$UePC|nhjzQgN!-#URqqt za2e3;qZ$i0Zu+OULC6vda`F&F`^=1?6?(m1>$2kyq z5-Iwzo00#Wu4_f^_sOc$mwNXk#Z{igb|!0es-_}cY{u4r89qxgws_3u1;aOl=7%bv zBf;OnjY+^H&cES{$Z(o0(AMbX>a<0#skzQt!Zp)=(@UcjeREiXs%_yV6na*XR$rs+ z>F4ogOAoX9FXx*=&^x%v@`I`M>Bhq0+Hdm~Z`bejbGP1(zCOyCp7B(th=oR3P?hBC zPQd1VIpe+eJQcRR6P!s)hVh38G+7r9O8;lM+L7RNErr%9Gl<d2&mB30p-Q9fpVYC8T9zTqDdt@>~IAo4)Cynf>Eyjm+{`)Hz9mS7004k#Ni z>>?C*BB;yiF1y$)mz+l~&-tn^SEc5}U%k>r)IU9^=uQrWiJt?5g^bf&=*u)0JNrod z!uXW@b&?6wX z)|8EIlb3GZ#xDSpz1K1R$8_rp7lRwf(+UPe7NOL?aS*Uk0Dqz1^tCZTOVAf7gX^Q> zd$~mGoeI?@hb8B1?=%_tihZrTzp$|0nS~(Q~^wX}YxHtmoSta}?dXJqi8+p#$&BGH(}RWUQBK8%e_fcSzOn6GyEwPWZ9Q z<>m5QLf4GtGTwEz?D*`L3e0GdnKDV2JuPN9JzCbXBc7qWX@rD72k92tOGkuOf`}lqmwcaY8p!?~u^2CG*fWgjrAfX=$Fi$EpAsE%JzmW3>2+;4Y+W+8 zxvsMMv|X53RU8bHeXBh#_*sO0u+_EA=W;gh_t|K#06CJjCv6-+n z++OF{3bN>%JnLSNp+I-iPpR>C1R1?uKE683G0Y(XLmQ=S(g2y?>~ClTp^M|OiDX{e zD=X_0ho+Hp*6I9R?-9*WfTWm)S~CK>;0&$PR87|7zvlD2I>aNZY_! zL%QFa7hAHyWE(v>-^-Ujk4YfMt)v4*#bedCeaEef{w;6w(qtFuVt1XWLeqhk{!AU3 zCE9~G-D;p3wITjHD17XnvXUlNJc)VG$+L((FWs=)gr8~e!^5pxLr|VJ^4V1>(8+GW z>xe>~?YP)ZsN8tq#A^BKvTHkVNxIhQs^_TT@{iGMr6AsnQuT}yAkGU!l{cD8O^JO)tcm_ol68Ky~?bn*Lh+>_ewO2DPzt^a{uX* z6l*xDXK)j;+|y}%>L1c4D7k`%a+N|{ELltt7tmky2-zn$9||1G9y|VkP8in&*&>Wz zv2GW%_Tc#ju?zK?KU~V))vD5YLE7+CylV{FTVLOHFl|AFjoz9{I!Sjd?o?45ZL>D= z!)oBHdODKk?cQ(=Q*fH9jiE^OdR*)rS9X^G$Y^?p!LVzqLQW-l*nOe56*pv5OYgi0 zGGk`w%(e0zxLZw-P>s)lugIcdcWLrqkW6{ zcda7q>I-zpYK<3yyls|E(-(`rTG_UmiAh&mDz&M{`?ma)`kR@2?3;s@lUb&=*zGu+i4e}W~9z8b5mIB3;?KPwmcP}JNOaZ42KP|s; zXhE1I8=%us_HJr(0zYentza|SJ3fO7i69v-;29}t$#y<_5I!0zTtz~wGF^^b{&0p%xvRPvhE**YhS3G ztbE$ING9^1TK=SdlGJ2DaLKXItS(hy<^USTlVE-iaxPFS35F9eoqnxL$n=ot2}7m~ z^mI^V%OspZuOrENjCu@^YyKJn{Yb=*kL{Ri`?*+6iOd8y^(jnU`m(&8zWJ9KPuE7! z2Jim*3i3PU#_2UHN6ApN4d8vyAfvxx{=ocC49t^=XtLB^VJj?Sredt2j{o!`yq6!@ zH_%p6;Zd$qR6Bf2$dOXc;z+V%;xnT&!fM9T&#i#j@L+6za7rfC{ugCXxsmX=rwa22 zk!W5v6lbBVGppX@7^w@w&BL8(y^JRhD`)-$NMEg#g-qLBqVn)p9MxTH(DqW)xmVyW zx<;MP=jPPEIS6OuIQjA;BqeS@_3(H~t=?ws&ZoY1tAmhIa5zTiS)VR~vI+su_LL~f zCyR7mAquzJ@n=Z8_wKr=J0k8HCed)dykM^Da0}5o8x6u%B{uA$Ih!6HVL^|k@^VK< z6Sl!PJe=rj=wB+wtiVKWrMDzgA3bRTh0G;#1arHXA;9vIcpiD5T+ z&bI=KK?~ag|C&^hpX|-K@XOv>2umXj-*nU#PUHtR=rrQXC{C|t`^R|vu2=h1p^SXz zaBm+P^lzHeM1Q8@3Rd}6~BQ_F8N?nR{H`jJ!P z8=?r~#pL8;qa@CBzW6E+?0V3)B^Dd8jK~)8wgod#%*JQmqz^~4A41a1DnOFR4$lde z%hidkb#JNoZ&6;R&gq5uobWyjue`mo`swTRp93S)Yh9 zQPZ#KSmI^=e65@Q&zJFYi-wVY%2)rJkLAUtJJno%g>zV^aPdo0X#MUNcHuUum=`}x zBcX(ZNA@*n_M>zX?q<~<9rwI^37p6KpKVvocXFHCvW#Z_AhNm~wSJnpNf-^atn$w1 zWm|Zu`;d`m(^`_U_vFv1ZNYpW-(@+i>HJJjJSmh1gf5?s5q$rF+eG_1nc$Qza+AC4 zNNTOdxX=dPu=}x&ga1smDQ`{HhlI5s6U-&%6suD}@E}p;Y0|u(!`XC_3A&PxOrw9- zB>X;l7M+1AaIn%75=LR#&8&00U!E?R`2G6H%RJ# z%AB!`PZq>L?l_=dqWkUNWVA@VOFQ(Za*=c-6S@+X9T>8Rc|xm46Hh61LWHqS?0PC4?!keBV<|#j%Uel91LY z(5}nb&$9GOE;XY+)c@h0aL<*Y5m`vbb}pG`P*d7Io|6aHPxdG5`!^P0K&eJph4mAG}g zQDomQZnIgd{Ih5@Cudt96WAnQG0zZ^qvzU!n^NUC2p82R~F%<2^j!8Yk!Oepy~ z^NN8|S%6q_NJ&NiGnjyOFTyU&L#%(wJVG!lfXmv{_9iM7Lws{|hQf}@(OI@-UL@A~ zxD{Ok5f#5h!A_lG_Qy^=W!psbafQwLa4PIZMDWot2o8${?EtcYawn`UN@8=DC?<^( z^T*+Yv-{H_C`gYjfWbV2S8VHCeW;D1n;`V+O%7iFk=v5RR$L)zy10 zML1A8eXQR7XAVuN3!W6(c;o)eoY`>ENWJ6i(43P*#>uMpV-K|I%vhiqBNg*CdeJWp z3GsA3UVLXaC@d8EDKFllal{wzWLi`z17!nNPmOJ{`ai2@j^f>%uh}{MmU@ucqXGoW zidwW-vAtH-a>49xsX9&Y6Heh2YgktupSX?Nv?5@U69Odmg>he3gh>HMZOn_c{-3l0 zAFtCFoy$u`IdPsj?n8Z?Sahmko2mo+g!$zQ$8=0ZMmXeaMAbYU?=SBZ*eU})Fj(Fp z)EK(RpI%wQil|_bnn#x!gA4~(miAoxuS84!OkYg>A+Z1`jKEFg`ZtRZQOp;+I#B#X z$d%RhXg@)P>Z9Puw3TNgF@l0<`z`T(jYe*r)WnU5Dz7~sb-(eUCUfkBk-Fwn|Mwwo zMn3){84EuUDzo(hU1x5&!`xg|Qx;hf?VEP7#NTgSpS5+!7^6!p=)U&p_5+UGzb73) zQa=r+ zoY+i8neMu9!5y+kMG9N6B(6A6u4MncQ$MIW<1?i32((y#!;b*K&^r@nOaKNQ9c4&6 zX=8NrMQ(Rj7m9*f|C%PPA=8?NsG8ABRu&%u;v zTjLzkF;JQ{A#T-L3I zoI`@NIVazCXw94>6MD$pyfGc{y`ppsu*Yd-SwYA%0A4RN@D8@WnW|TA_qPDtS0nKl zPTGyd6jXUZN%``Bnbp^`P>6fY*q%Cw_SULq@}@s&xN>=I^IF&dV{zEkS7!c-jy1)&Dk!U`5rJ=NN17KiaOs{JJ-2M;b^L0c5sWkKdz8YpW6#!!%i)ilulk%G% lr27Ft@c+-F?rwk1UpvTDIu1&DfG5LLCe*i|X-m?Gz literal 0 HcmV?d00001 From b13ff2383684f2be445463b408320d11afc0b9a1 Mon Sep 17 00:00:00 2001 From: Teddy Lee Date: Sun, 29 Dec 2024 22:48:41 +0900 Subject: [PATCH 2/4] change suggestion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. .env 관련 내용에 대한 안내 추가 2. 예제의 korea 를 United States 로 변경 3. outdated 된 import 수정: from langchain_community.callbacks.manager 4. 따라서 langchain-community 를 dependency 에 추가 --- 04-MODEL/04-CheckTokenUsage.ipynb | 107 ++++++++++++++++++------------ 1 file changed, 64 insertions(+), 43 deletions(-) diff --git a/04-MODEL/04-CheckTokenUsage.ipynb b/04-MODEL/04-CheckTokenUsage.ipynb index 467cf1862..b676fd5fe 100644 --- a/04-MODEL/04-CheckTokenUsage.ipynb +++ b/04-MODEL/04-CheckTokenUsage.ipynb @@ -63,19 +63,9 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 13, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\n", - "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m24.2\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m24.3.1\u001b[0m\n", - "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpip install --upgrade pip\u001b[0m\n" - ] - } - ], + "outputs": [], "source": [ "# Install required packages\n", "from langchain_opentutorial import package\n", @@ -85,6 +75,7 @@ " \"langsmith\",\n", " \"langchain\",\n", " \"langchain_openai\",\n", + " \"langchain_community\",\n", " ],\n", " verbose=False,\n", " upgrade=False,\n", @@ -93,17 +84,9 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Environment variables have been set successfully.\n" - ] - } - ], + "outputs": [], "source": [ "# Set environment variables\n", "from langchain_opentutorial import set_env\n", @@ -119,10 +102,48 @@ ")" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can alternatively set `OPENAI_API_KEY` in `.env` file and load it. \n", + "\n", + "[Note] This is not necessary if you've already set `OPENAI_API_KEY` in previous steps." + ] + }, { "cell_type": "code", "execution_count": 3, "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from dotenv import load_dotenv\n", + "\n", + "load_dotenv()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's setup `ChatOpenAI` with `gpt-4o` model." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, "outputs": [], "source": [ "from langchain_openai import ChatOpenAI\n", @@ -142,52 +163,52 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Tokens Used: 32\n", - "\tPrompt Tokens: 14\n", + "Tokens Used: 24\n", + "\tPrompt Tokens: 15\n", "\t\tPrompt Tokens Cached: 0\n", - "\tCompletion Tokens: 18\n", + "\tCompletion Tokens: 9\n", "\t\tReasoning Tokens: 0\n", "Successful Requests: 1\n", - "Total Cost (USD): $0.000215\n" + "Total Cost (USD): $0.00012749999999999998\n" ] } ], "source": [ "# callback to track it\n", - "from langchain.callbacks import get_openai_callback\n", + "from langchain_community.callbacks.manager import get_openai_callback\n", "\n", "with get_openai_callback() as cb:\n", - " result = llm.invoke(\"where is the capital of korea?\")\n", + " result = llm.invoke(\"where is the capital of South Korea?\")\n", " print(cb)" ] }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Total tokens used: \t\t23\n", - "Tokens used in prompt: \t\t14\n", - "Tokens used in completion: \t9\n", - "Cost: \t\t\t\t$0.000125\n" + "Total tokens used: \t\t28\n", + "Tokens used in prompt: \t\t15\n", + "Tokens used in completion: \t13\n", + "Cost: \t\t\t\t$0.00016749999999999998\n" ] } ], "source": [ "# callback to track it\n", "with get_openai_callback() as cb:\n", - " result = llm.invoke(\"where is the capital of korea?\")\n", + " result = llm.invoke(\"where is the capital of United States?\")\n", " print(f\"Total tokens used: \\t\\t{cb.total_tokens}\")\n", " print(f\"Tokens used in prompt: \\t\\t{cb.prompt_tokens}\")\n", " print(f\"Tokens used in completion: \\t{cb.completion_tokens}\")\n", @@ -218,7 +239,7 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 9, "metadata": {}, "outputs": [ { @@ -256,7 +277,7 @@ }, { "cell_type": "code", - "execution_count": 28, + "execution_count": 10, "metadata": {}, "outputs": [ { @@ -265,15 +286,15 @@ "text": [ "2. Multiple Queries Monitoring\n", "----------------------------------------\n", - "Response 1: Python is a high-level, interpreted programming language known for its simplicity and readability. C...\n", + "Response 1: Python is a high-level, interpreted programming language known for its readability and simplicity. I...\n", "----------------------------------------\n", - "Response 2: JavaScript is a high-level, dynamic programming language commonly used in web development to create ...\n", + "Response 2: JavaScript is a high-level, dynamic, untyped, and interpreted programming language that is one of th...\n", "----------------------------------------\n", "Cumulative Statistics:\n", "Total Prompt Tokens: \t\t23\n", - "Total Completion Tokens: \t661\n", - "Total Tokens: \t\t\t684\n", - "Total Cost: \t\t\t$0.0067\n", + "Total Completion Tokens: \t735\n", + "Total Tokens: \t\t\t758\n", + "Total Cost: \t\t\t$0.0074\n", "\n" ] } @@ -317,7 +338,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.10" + "version": "3.11.11" } }, "nbformat": 4, From 774af75158c610dd518fa71de0f80c84bd80d51b Mon Sep 17 00:00:00 2001 From: IHAGI-c Date: Sun, 29 Dec 2024 23:08:03 +0900 Subject: [PATCH 3/4] Update CheckTokenUsage notebook to enhance token tracking functionality - Adjusted execution counts for code cells to reflect the correct order of operations. - Added 'langchain_community' to the list of packages for improved callback management. - Modified the callback import statement to use the community version. - Updated the example query to reflect a more relevant question. - Corrected token usage output values to ensure accurate reporting of tokens used and associated costs. --- 04-MODEL/04-CheckTokenUsage.ipynb | 43 ++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/04-MODEL/04-CheckTokenUsage.ipynb b/04-MODEL/04-CheckTokenUsage.ipynb index 467cf1862..39c227820 100644 --- a/04-MODEL/04-CheckTokenUsage.ipynb +++ b/04-MODEL/04-CheckTokenUsage.ipynb @@ -63,7 +63,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 7, "metadata": {}, "outputs": [ { @@ -85,6 +85,7 @@ " \"langsmith\",\n", " \"langchain\",\n", " \"langchain_openai\",\n", + " \"langchain_community\",\n", " ],\n", " verbose=False,\n", " upgrade=False,\n", @@ -93,7 +94,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 6, "metadata": {}, "outputs": [ { @@ -121,7 +122,29 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from dotenv import load_dotenv\n", + "\n", + "load_dotenv()" + ] + }, + { + "cell_type": "code", + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ @@ -142,29 +165,29 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Tokens Used: 32\n", - "\tPrompt Tokens: 14\n", + "Tokens Used: 28\n", + "\tPrompt Tokens: 15\n", "\t\tPrompt Tokens Cached: 0\n", - "\tCompletion Tokens: 18\n", + "\tCompletion Tokens: 13\n", "\t\tReasoning Tokens: 0\n", "Successful Requests: 1\n", - "Total Cost (USD): $0.000215\n" + "Total Cost (USD): $0.00016749999999999998\n" ] } ], "source": [ "# callback to track it\n", - "from langchain.callbacks import get_openai_callback\n", + "from langchain_community.callbacks.manager import get_openai_callback\n", "\n", "with get_openai_callback() as cb:\n", - " result = llm.invoke(\"where is the capital of korea?\")\n", + " result = llm.invoke(\"where is the capital of United States?\")\n", " print(cb)" ] }, From 87307c39bbbac9d2c8ac1dffbf0135fc4d76ff58 Mon Sep 17 00:00:00 2001 From: IHAGI-c Date: Sun, 29 Dec 2024 23:16:48 +0900 Subject: [PATCH 4/4] Refactor CheckTokenUsage notebook to correct execution counts and update token usage statistics. Adjusted execution counts for code cells, added pip upgrade notice, and refined output values for total tokens and costs to ensure accurate reporting. Enhanced example queries for clarity. --- 04-MODEL/04-CheckTokenUsage.ipynb | 58 ++++++++++++------------------- 1 file changed, 23 insertions(+), 35 deletions(-) diff --git a/04-MODEL/04-CheckTokenUsage.ipynb b/04-MODEL/04-CheckTokenUsage.ipynb index 1f712713e..b6f451044 100644 --- a/04-MODEL/04-CheckTokenUsage.ipynb +++ b/04-MODEL/04-CheckTokenUsage.ipynb @@ -63,9 +63,19 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 2, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\n", + "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m24.2\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m24.3.1\u001b[0m\n", + "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpip install --upgrade pip\u001b[0m\n" + ] + } + ], "source": [ "# Install required packages\n", "from langchain_opentutorial import package\n", @@ -113,29 +123,7 @@ }, { "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 1, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from dotenv import load_dotenv\n", - "\n", - "load_dotenv()" - ] - }, - { - "cell_type": "code", - "execution_count": 2, + "execution_count": 3, "metadata": {}, "outputs": [ { @@ -164,7 +152,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 5, "metadata": {}, "outputs": [], "source": [ @@ -185,7 +173,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 6, "metadata": {}, "outputs": [ { @@ -213,7 +201,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 7, "metadata": {}, "outputs": [ { @@ -261,7 +249,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 8, "metadata": {}, "outputs": [ { @@ -299,7 +287,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 9, "metadata": {}, "outputs": [ { @@ -308,15 +296,15 @@ "text": [ "2. Multiple Queries Monitoring\n", "----------------------------------------\n", - "Response 1: Python is a high-level, interpreted programming language known for its readability and simplicity. I...\n", + "Response 1: Python is a high-level, interpreted programming language known for its readability, simplicity, and ...\n", "----------------------------------------\n", - "Response 2: JavaScript is a high-level, dynamic, untyped, and interpreted programming language that is one of th...\n", + "Response 2: JavaScript is a high-level, dynamic, untyped, and interpreted programming language that is widely us...\n", "----------------------------------------\n", "Cumulative Statistics:\n", "Total Prompt Tokens: \t\t23\n", - "Total Completion Tokens: \t735\n", - "Total Tokens: \t\t\t758\n", - "Total Cost: \t\t\t$0.0074\n", + "Total Completion Tokens: \t596\n", + "Total Tokens: \t\t\t619\n", + "Total Cost: \t\t\t$0.0060\n", "\n" ] }