From f37a4ec9c862a9f744c7ed93627557d5a3c78dfc Mon Sep 17 00:00:00 2001 From: Manohar Joshi Date: Sun, 17 Sep 2023 02:33:23 -0400 Subject: [PATCH] 1038 - Streamlit bot with LocalAI (#1072) **Description** This PR fixes #1038 Added Streamlit example and also updated readme for examples. **[Signed commits](../CONTRIBUTING.md#signing-off-on-commits-developer-certificate-of-origin)** - [X] Yes, I signed my commits. --- examples/README.md | 14 ++- examples/streamlit-bot/.gitignore | 1 + examples/streamlit-bot/LICENSE | 21 +++++ examples/streamlit-bot/Main.py | 70 +++++++++++++++ examples/streamlit-bot/README.md | 54 ++++++++++++ examples/streamlit-bot/cmd_windows.bat | 31 +++++++ .../streamlit-bot/install_requirements.bat | 81 ++++++++++++++++++ examples/streamlit-bot/requirements.txt | 2 + examples/streamlit-bot/start_windows.bat | 81 ++++++++++++++++++ examples/streamlit-bot/streamlit-bot.png | Bin 0 -> 32815 bytes 10 files changed, 353 insertions(+), 2 deletions(-) create mode 100644 examples/streamlit-bot/.gitignore create mode 100644 examples/streamlit-bot/LICENSE create mode 100644 examples/streamlit-bot/Main.py create mode 100644 examples/streamlit-bot/README.md create mode 100644 examples/streamlit-bot/cmd_windows.bat create mode 100644 examples/streamlit-bot/install_requirements.bat create mode 100644 examples/streamlit-bot/requirements.txt create mode 100644 examples/streamlit-bot/start_windows.bat create mode 100644 examples/streamlit-bot/streamlit-bot.png diff --git a/examples/README.md b/examples/README.md index 960daba4..7f6dccb9 100644 --- a/examples/README.md +++ b/examples/README.md @@ -159,14 +159,24 @@ Allows to run any LocalAI-compatible model as a backend on the servers of https: ### Continue -Screenshot - _by [@gruberdev](https://github.com/gruberdev)_ +Screenshot + Demonstrates how to integrate an open-source copilot alternative that enhances code analysis, completion, and improvements. This approach seamlessly integrates with any LocalAI model, offering a more user-friendly experience. [Check it out here](https://github.com/go-skynet/LocalAI/tree/master/examples/continue/) +### Streamlit bot + +_by [@majoshi1](https://github.com/majoshi1)_ + +![Screenshot](streamlit-bot/streamlit-bot.png) + +A chat bot made using `Streamlit` & LocalAI. + +[Check it out here](https://github.com/go-skynet/LocalAI/tree/master/examples/streamlit-bot/) + ## Want to contribute? Create an issue, and put `Example: ` in the title! We will post your examples here. diff --git a/examples/streamlit-bot/.gitignore b/examples/streamlit-bot/.gitignore new file mode 100644 index 00000000..0fb83220 --- /dev/null +++ b/examples/streamlit-bot/.gitignore @@ -0,0 +1 @@ +installer_files \ No newline at end of file diff --git a/examples/streamlit-bot/LICENSE b/examples/streamlit-bot/LICENSE new file mode 100644 index 00000000..e6200f0f --- /dev/null +++ b/examples/streamlit-bot/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Manohar Joshi + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/examples/streamlit-bot/Main.py b/examples/streamlit-bot/Main.py new file mode 100644 index 00000000..0063289a --- /dev/null +++ b/examples/streamlit-bot/Main.py @@ -0,0 +1,70 @@ +import streamlit as st +import time +import requests +import json + +def ask(prompt): + url = 'http://localhost:8080/v1/chat/completions' + myobj = { + "model": "ggml-gpt4all-j.bin", + "messages": [{"role": "user", "content": prompt}], + "temperature": 0.9 + } + myheaders = { "Content-Type" : "application/json" } + + x = requests.post(url, json = myobj, headers=myheaders) + + print(x.text) + + json_data = json.loads(x.text) + + return json_data["choices"][0]["message"]["content"] + + +def main(): + # Page setup + st.set_page_config(page_title="Ask your LLM") + st.header("Ask your Question 💬") + + # Initialize chat history + if "messages" not in st.session_state: + st.session_state.messages = [] + + # Display chat messages from history on app rerun + for message in st.session_state.messages: + with st.chat_message(message["role"]): + st.markdown(message["content"]) + + # Scroll to bottom + st.markdown( + """ + + """, + unsafe_allow_html=True, + ) + + # React to user input + if prompt := st.chat_input("What is up?"): + # Display user message in chat message container + st.chat_message("user").markdown(prompt) + # Add user message to chat history + st.session_state.messages.append({"role": "user", "content": prompt}) + print(f"User has asked the following question: {prompt}") + + # Process + response = "" + with st.spinner('Processing...'): + response = ask(prompt) + + #response = f"Echo: {prompt}" + # Display assistant response in chat message container + with st.chat_message("assistant"): + st.markdown(response) + # Add assistant response to chat history + st.session_state.messages.append({"role": "assistant", "content": response}) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/examples/streamlit-bot/README.md b/examples/streamlit-bot/README.md new file mode 100644 index 00000000..6588cbde --- /dev/null +++ b/examples/streamlit-bot/README.md @@ -0,0 +1,54 @@ +## Streamlit bot + +![Screenshot](streamlit-bot.png) + +This is an example to deploy a Streamlit bot with LocalAI instead of OpenAI. Instructions are for Windows. + +```bash +# Install & run Git Bash + +# Clone LocalAI +git clone https://github.com/go-skynet/LocalAI.git +cd LocalAI + +# (optional) Checkout a specific LocalAI tag +# git checkout -b build + +# Use a template from the examples +cp -rf prompt-templates/ggml-gpt4all-j.tmpl models/ + +# (optional) Edit the .env file to set things like context size and threads +# vim .env +# Download model +curl --progress-bar -C - -O https://gpt4all.io/models/ggml-gpt4all-j.bin > models/ggml-gpt4all-j.bin + +# Install & Run Docker Desktop for Windows +https://www.docker.com/products/docker-desktop/ + +# start with docker-compose +docker-compose up -d --pull always +# or you can build the images with: +# docker-compose up -d --build +# Now API is accessible at localhost:8080 +curl http://localhost:8080/v1/models +# {"object":"list","data":[{"id":"ggml-gpt4all-j","object":"model"}]} + +curl http://localhost:8080/v1/chat/completions -H "Content-Type: application/json" -d '{ + "model": "ggml-gpt4all-j", + "messages": [{"role": "user", "content": "How are you?"}], + "temperature": 0.9 + }' + +# {"model":"ggml-gpt4all-j","choices":[{"message":{"role":"assistant","content":"I'm doing well, thanks. How about you?"}}]} + +cd examples/streamlit-bot + +install_requirements.bat + +# run the bot +start_windows.bat + +# UI will be launched automatically (http://localhost:8501/) in browser. + +``` + diff --git a/examples/streamlit-bot/cmd_windows.bat b/examples/streamlit-bot/cmd_windows.bat new file mode 100644 index 00000000..606ff485 --- /dev/null +++ b/examples/streamlit-bot/cmd_windows.bat @@ -0,0 +1,31 @@ +@echo off + +cd /D "%~dp0" + +set PATH=%PATH%;%SystemRoot%\system32 + +echo "%CD%"| findstr /C:" " >nul && echo This script relies on Miniconda which can not be silently installed under a path with spaces. && goto end + +@rem fix failed install when installing to a separate drive +set TMP=%cd%\installer_files +set TEMP=%cd%\installer_files + +@rem config +set CONDA_ROOT_PREFIX=%cd%\installer_files\conda +set INSTALL_ENV_DIR=%cd%\installer_files\env + +@rem environment isolation +set PYTHONNOUSERSITE=1 +set PYTHONPATH= +set PYTHONHOME= +set "CUDA_PATH=%INSTALL_ENV_DIR%" +set "CUDA_HOME=%CUDA_PATH%" + +@rem activate installer env +call "%CONDA_ROOT_PREFIX%\condabin\conda.bat" activate "%INSTALL_ENV_DIR%" || ( echo. && echo Miniconda hook not found. && goto end ) + +@rem enter commands +cmd /k "%*" + +:end +pause diff --git a/examples/streamlit-bot/install_requirements.bat b/examples/streamlit-bot/install_requirements.bat new file mode 100644 index 00000000..534091ee --- /dev/null +++ b/examples/streamlit-bot/install_requirements.bat @@ -0,0 +1,81 @@ +@echo off + +cd /D "%~dp0" + +set PATH=%PATH%;%SystemRoot%\system32 + +echo "%CD%"| findstr /C:" " >nul && echo This script relies on Miniconda which can not be silently installed under a path with spaces. && goto end + +@rem Check for special characters in installation path +set "SPCHARMESSAGE="WARNING: Special characters were detected in the installation path!" " This can cause the installation to fail!"" +echo "%CD%"| findstr /R /C:"[!#\$%&()\*+,;<=>?@\[\]\^`{|}~]" >nul && ( + call :PrintBigMessage %SPCHARMESSAGE% +) +set SPCHARMESSAGE= + +@rem fix failed install when installing to a separate drive +set TMP=%cd%\installer_files +set TEMP=%cd%\installer_files + +@rem config +set INSTALL_DIR=%cd%\installer_files +set CONDA_ROOT_PREFIX=%cd%\installer_files\conda +set INSTALL_ENV_DIR=%cd%\installer_files\env +set MINICONDA_DOWNLOAD_URL=https://repo.anaconda.com/miniconda/Miniconda3-py310_23.3.1-0-Windows-x86_64.exe +set conda_exists=F + +@rem figure out whether git and conda needs to be installed +call "%CONDA_ROOT_PREFIX%\_conda.exe" --version >nul 2>&1 +if "%ERRORLEVEL%" EQU "0" set conda_exists=T + +@rem (if necessary) install git and conda into a contained environment +@rem download conda +if "%conda_exists%" == "F" ( + echo Downloading Miniconda from %MINICONDA_DOWNLOAD_URL% to %INSTALL_DIR%\miniconda_installer.exe + + mkdir "%INSTALL_DIR%" + call curl -Lk "%MINICONDA_DOWNLOAD_URL%" > "%INSTALL_DIR%\miniconda_installer.exe" || ( echo. && echo Miniconda failed to download. && goto end ) + + echo Installing Miniconda to %CONDA_ROOT_PREFIX% + start /wait "" "%INSTALL_DIR%\miniconda_installer.exe" /InstallationType=JustMe /NoShortcuts=1 /AddToPath=0 /RegisterPython=0 /NoRegistry=1 /S /D=%CONDA_ROOT_PREFIX% + + @rem test the conda binary + echo Miniconda version: + call "%CONDA_ROOT_PREFIX%\_conda.exe" --version || ( echo. && echo Miniconda not found. && goto end ) +) + +@rem create the installer env +if not exist "%INSTALL_ENV_DIR%" ( + echo Packages to install: %PACKAGES_TO_INSTALL% + call "%CONDA_ROOT_PREFIX%\_conda.exe" create --no-shortcuts -y -k --prefix "%INSTALL_ENV_DIR%" python=3.10 || ( echo. && echo Conda environment creation failed. && goto end ) +) + +@rem check if conda environment was actually created +if not exist "%INSTALL_ENV_DIR%\python.exe" ( echo. && echo Conda environment is empty. && goto end ) + +@rem environment isolation +set PYTHONNOUSERSITE=1 +set PYTHONPATH= +set PYTHONHOME= +set "CUDA_PATH=%INSTALL_ENV_DIR%" +set "CUDA_HOME=%CUDA_PATH%" + +@rem activate installer env +call "%CONDA_ROOT_PREFIX%\condabin\conda.bat" activate "%INSTALL_ENV_DIR%" || ( echo. && echo Miniconda hook not found. && goto end ) + +@rem setup installer env +call pip install -r requirements.txt + +@rem below are functions for the script next line skips these during normal execution +goto end + +:PrintBigMessage +echo. && echo. +echo ******************************************************************* +for %%M in (%*) do echo * %%~M +echo ******************************************************************* +echo. && echo. +exit /b + +:end +pause \ No newline at end of file diff --git a/examples/streamlit-bot/requirements.txt b/examples/streamlit-bot/requirements.txt new file mode 100644 index 00000000..ae527c76 --- /dev/null +++ b/examples/streamlit-bot/requirements.txt @@ -0,0 +1,2 @@ +streamlit==1.26.0 +requests \ No newline at end of file diff --git a/examples/streamlit-bot/start_windows.bat b/examples/streamlit-bot/start_windows.bat new file mode 100644 index 00000000..fd76ab15 --- /dev/null +++ b/examples/streamlit-bot/start_windows.bat @@ -0,0 +1,81 @@ +@echo off + +cd /D "%~dp0" + +set PATH=%PATH%;%SystemRoot%\system32 + +echo "%CD%"| findstr /C:" " >nul && echo This script relies on Miniconda which can not be silently installed under a path with spaces. && goto end + +@rem Check for special characters in installation path +set "SPCHARMESSAGE="WARNING: Special characters were detected in the installation path!" " This can cause the installation to fail!"" +echo "%CD%"| findstr /R /C:"[!#\$%&()\*+,;<=>?@\[\]\^`{|}~]" >nul && ( + call :PrintBigMessage %SPCHARMESSAGE% +) +set SPCHARMESSAGE= + +@rem fix failed install when installing to a separate drive +set TMP=%cd%\installer_files +set TEMP=%cd%\installer_files + +@rem config +set INSTALL_DIR=%cd%\installer_files +set CONDA_ROOT_PREFIX=%cd%\installer_files\conda +set INSTALL_ENV_DIR=%cd%\installer_files\env +set MINICONDA_DOWNLOAD_URL=https://repo.anaconda.com/miniconda/Miniconda3-py310_23.3.1-0-Windows-x86_64.exe +set conda_exists=F + +@rem figure out whether git and conda needs to be installed +call "%CONDA_ROOT_PREFIX%\_conda.exe" --version >nul 2>&1 +if "%ERRORLEVEL%" EQU "0" set conda_exists=T + +@rem (if necessary) install git and conda into a contained environment +@rem download conda +if "%conda_exists%" == "F" ( + echo Downloading Miniconda from %MINICONDA_DOWNLOAD_URL% to %INSTALL_DIR%\miniconda_installer.exe + + mkdir "%INSTALL_DIR%" + call curl -Lk "%MINICONDA_DOWNLOAD_URL%" > "%INSTALL_DIR%\miniconda_installer.exe" || ( echo. && echo Miniconda failed to download. && goto end ) + + echo Installing Miniconda to %CONDA_ROOT_PREFIX% + start /wait "" "%INSTALL_DIR%\miniconda_installer.exe" /InstallationType=JustMe /NoShortcuts=1 /AddToPath=0 /RegisterPython=0 /NoRegistry=1 /S /D=%CONDA_ROOT_PREFIX% + + @rem test the conda binary + echo Miniconda version: + call "%CONDA_ROOT_PREFIX%\_conda.exe" --version || ( echo. && echo Miniconda not found. && goto end ) +) + +@rem create the installer env +if not exist "%INSTALL_ENV_DIR%" ( + echo Packages to install: %PACKAGES_TO_INSTALL% + call "%CONDA_ROOT_PREFIX%\_conda.exe" create --no-shortcuts -y -k --prefix "%INSTALL_ENV_DIR%" python=3.10 || ( echo. && echo Conda environment creation failed. && goto end ) +) + +@rem check if conda environment was actually created +if not exist "%INSTALL_ENV_DIR%\python.exe" ( echo. && echo Conda environment is empty. && goto end ) + +@rem environment isolation +set PYTHONNOUSERSITE=1 +set PYTHONPATH= +set PYTHONHOME= +set "CUDA_PATH=%INSTALL_ENV_DIR%" +set "CUDA_HOME=%CUDA_PATH%" + +@rem activate installer env +call "%CONDA_ROOT_PREFIX%\condabin\conda.bat" activate "%INSTALL_ENV_DIR%" || ( echo. && echo Miniconda hook not found. && goto end ) + +@rem setup installer env +streamlit run Main.py + +@rem below are functions for the script next line skips these during normal execution +goto end + +:PrintBigMessage +echo. && echo. +echo ******************************************************************* +for %%M in (%*) do echo * %%~M +echo ******************************************************************* +echo. && echo. +exit /b + +:end +pause \ No newline at end of file diff --git a/examples/streamlit-bot/streamlit-bot.png b/examples/streamlit-bot/streamlit-bot.png new file mode 100644 index 0000000000000000000000000000000000000000..7b69ba9919d13d96e29da50e4ca5195f09650a16 GIT binary patch literal 32815 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 pH3xIYN+T*&kX&3K(y!3O!Ebt8SG93U(LkP){ zZ|_cGFgT_Qy)i`u)yeLik6bZo%;xL~IB3spvv;I`XC%MPt90`cshsdDyED_+3|8To z+GbxqSHG(@i|HmbW3b)oWw$40?&lN(TB=I!Wb^Q`gS)--xSUA_-CuHJ++n9jd{e^q8Mc}jYhE!bpJDICLK+z92QBX!m_m2-ac zj)U2SPWxNARWs|}W_MZ3H~VMWqD^}m945yk&elnJg%fn0{S^u0uR$E8H<+c z99QxL2Sk>*>Y82p`|Jg;Wl|i4s$W@KuJ>&)GzjT4LGkLP2z!YJ=ib;5wbep4s99BW zi@{{oVvJ_gTZm;$sNgPLe>w?GdFTWKoMy;Zleg3+?aSWSwqTyO6Opod;62g7lMeV1 zdyDpmp0sOSSZBT(xQh(#x+S)>BEz}u9Qv{ThBnJMvt%$z^~?1Z@nK3mTl3O&t!;9i z^ln{}%phH1USM@aeO{D3bMC4=XZu=~w-yFW&A3qf=3xp~*iDd<8w{b5@Gj4c!{X@N zrQAPi8*v<1+5hR!0~T9D+yid=mV*)YF+tnjOUW>6r-5(ed5d175=8`)1DSIq52NJ2=@%I=BTCJwuuiXuxd*!Akxe z*u|QX-7hI^RFPmos+<2Ez=1=0g$SpR*1L?VimREa^#ZU^qEL0=B+Tu&e4-1(o!&TE zDXDkJBpc>dpti3N%l#Nq{<<_*Y_)e8^IKpM#oHrW)Mhp&)`CY$Fgm){QVAnzIY3t$ z3ltf;wB-bFKI%2Fbbs^f%IYiN1c)acC$NY?E5HP)sz*t^OKyJMm+9~2at0oj*}%U% z@A@UvFkoshe;k`_^2>kldD^LBY1#l7k5V2Q9+$aY@hQ))-aV%|D5UdtK1VD0Ic2MuQkl~n9qMMpykv^5D~+!wf7~19sAZ&teR6%-=m3qIAW!^i z{~Z0ypWQe1EHiO=ORvjRQc0+JE#M>qcL8Tt{^{F-rW=X~BZViIt){x}Jo^t!jFzK< z5`(D8d#>}hFo~{$d+frAwOc-w_%8q99JE)@;`K_NLD?(HAT2%D*!o zFn>Ykpzrt>-Giompot?;a6PMaQ)S!{s&VAvwkGNM<6q_7wcS*+<$E~0OIzCM-HyiBQTVFzIcN|>2Ofr-Revx*2e^1U~ zYY`5=zQu_@l;!oIzfPWK#Yl(<8vnXbeMcf4U*NCSfiPsGh?0ZP>h!Jfuvh8d#Y4UQ z1D(B(hR(80-_nuq{Ko7jWv?X)LL+$5(ry2O*#6;-qpw5Ht^7YBc)@GOIu?H+kDgBk z$))-J-ub_1LSKJHtEp+peMV=%m@dmIQ$Vuu4F7Q4J%uxyyX{#Hx#Lf^=IF6k2P0o} zhIiX7MG;&<*D25_`u+PvbeBR_ytDYss%`%uiNB(yWq739W!3sja8x#Qb@gTA=^3Ns zsE@a_c&&hCQU8#h8}G_0@)oF9$BFv{kY4QO04uo7YBTWg$n}8WQ~~-mX07Ra67Vm| z8RBXMs>QY9F^nv*)?Vpf^`&_B8y}FojejQZsamLtkOki2=m|8C+^qz<$Y&BznDGN% z4&lcI%tw}L@gpK;D+_@f$PSk?IsG@4g&Gl5MBzQdqeMl;AOxUd#1U+=!isR%(&sHM zKI5lUu2&7XpBf(bMvF%Haa@#|rOf1FMHnoow8wr5g?%*4BiEh~Vc?~YP`Rz|ogkFs~xhA-hr z8Dxp1lEP2z=eyf;7H#On^q86I!G0}wdp8-?gV2ZPCfo4mcvQY%1b1h*jx^T8R}*;( zvWtz3*97=QxG6yNFMn+^-rgW6TauRCwU`3FYn0$F(SM_Jazn&(xW0&LC_C}obj9z| z|51M%@GUd(%+0hsQ6@)?aCOfyer3j%H~J!LsIcL9mwq8t2LDNH7Fh2o8J}g5kF3GA z%_6RhhtEAe-M)}J1T{F%$0o1x$0V)zZ~tm#`wMgTTJ zWCK&YcMCNWb$S=-4S0;ncrmKU1wgO0o+XkX+=%l0(%KqTP3jQUh$3_ zCw9d{{kU?ryk*fSUu7)mZjvJy#1{{|w=SY_MTFZ(K3FL*bHw2)D~$@$XcL(KZs@x* zf->iIn?s1oWk#vxxMUuHjc)`saH;-GU0AqK6A`rhv6T*EH>(`;=Bm@yQ5n3|^T z5ceDJ0bm~S0?az)_SqX|o(RUngDO5H4UAm)&ic6DO)`u$I1rlyD=wd@9lN7z7{hIpfO>OXUPpSr%PfV03QN37*sB%3xM>Uv^-uGZFbW?Y+(IX%w z;zj`x6}gc0+>}!DeO~zaQ^kFJEFQ6}gJDbo^7rBRVKuVf;_30L!%e>;y)u=litBYfU)jC<%?~PvlWg6b|AAo0n?F@XeSH6`4_%NJRj@JAeo?PnKMVgvH{OEa| zNtWc$Vj(U{-RbYu!^i@ia5}qnfwJm!G_GMg@nU&~)XvRd<%)GcAg_xmFjXE)+I;de zebibGso-bTMKHFrr}ArY(f!ouH+9@S#{zXL^B%a}1-+EYMbZ)XSDL74pQZ<}tR^vP zips`EeWAUH6{xG09&4mKXgk|A2GOe)1>iH0Qk&u4(3Zwa3`p$qfZj6@iE-Aydvn2a z38*{X}XN3gfT==N6B zMBz7Y>YPB_X(f9#{$V|d{1Pzp%r8+wIl?ms^3)&g=$$1b9wQvaPAA=tPi`|O_epV- zj?o6%qeKhf!K`D=oX4d&oJPl2B!v-sn9@LNHqesI+}33wFM)+0afwD~XjIJ_ibW355SxQ2~EG zz?v+BmZb1)Do`;K*HvmfMIoZ<&>aLAQIsFaC;CKb!@5c}3p@Qw)6K%RW47NP_wow) zy;yr{8`)nMvbO0yBWFepnJ47U@Sk*P%%pV6lNO{`FQ|>_bC!H+Jx!DMCGVCyvDNGX5xg$rC{d_yg^pEMF1M^NB@<^>H!@XT}An&6j>u$c82XQ&CJVe z3Nozu%%DAhiij6gUnEc!#v;}b#O_MtrJ=3&&jbp-fluW%M-4(dC>V>nVoSdJ_^3r; zjh93wIg&`P;K8>|J+co8p+E&oHzZyxOu1kYFXn4W&)HAS9){p4Gk>+`8(63Z5;~^rQlxSI_{?sNXg1XbaLS(xprH6`Yd1 zHp>Q}B_Y^WR4Z+>BTN)^HzeiN_BY`~B);?7D-;;3nOfasZH(Fe-mr_YE! zriPT*Pz{4OeC*U}0?aA!Cw>;b zO)0G`%k0(4F)YW`pH&og67#yxFw`u@F=~26k;+HwfMEsPvg9(H%B%aXys*1rr3uxa z^Qp(1*Qe0cc63_uK1yju%^MHr zLq&C@0~))l`#_9UK8I_nyKOmtKX!e@N@V4pQ2ieowhVJYbp2+jl04(c>|_bGsUz!F!H_2b*SIFqgorC@Bvb4Z-f@7D^rw z11^};wiO;>M8B?ZP%OO>VOPT!8XEU+E8>SPD23(7C=-T+&eoaTdnP%`{Ts?H2Krbr zg{cd6_77eSRznErO^fuyuBE~NNowCb@k@}x8{>77Jp?kp{!(C!b#@H+Adklk_++}h z?glYF8}@@x7JGm%Yp5+-^#wslk!}KIO^46D#DxnM+Npd_Kc6sQ#lq<;ODyS*;Goxz zR_f7F&86VwfLYJj1Mq$VV|_P;yYJX=I%0z)@KOI-EpH-ohqzqGaxmj-on6Z%N@2C8p8sVv=rCAa5H)E7;%}tH3J=Uq@`fi4`KlphU-+v?R}{n z?K#UXvp;EWYnE5Eqt|PDX9He~j*<{74!zyODGcv%MrCBg|U#lvUy(@riR%b zqwv63txsXHew!lD=_B+DDl6sOw#0h&yW}xNaOL(2_}9AWWYum>N@bK^@0!u_OnVF& zGC1#~C#=%Sc%mt9(LG%7IML{)D=c(#B|xPVS>7?Y`;IAZ0J?ROxn1VE5*$08MG#ijpesKN@-y8b9?z#l$s zMY#K(a;++{)nhHSKfa4rqi5Te4&yYg%GzzN{PpVAdu?GP(YDS0Ns^jYZeDkj|8;5H zC5zngKOwr7|1o>_<5q_#QBQP90eyU!YHbrB?bO9r_eZ&a1`A%cM2oTg6~15VE>7Nt>Oiu8wBS5F#c}^(?J@cMUv)@71qdS?P*ML-jv}tv`Jlh$Ji*s3 zu2#2i@}1XLCJx67@po1ZQ7`|~DZnwX2w3kj{69lJp(I}O