From 5fc8d072ec9dbd5de74a7506593185c804da7ee4 Mon Sep 17 00:00:00 2001 From: Cornelius Specht Date: Thu, 2 May 2024 14:13:45 +0200 Subject: [PATCH 1/3] update dev_environment --- src/sandbox/dev_env.md | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/sandbox/dev_env.md b/src/sandbox/dev_env.md index bd3447a..a7a4981 100644 --- a/src/sandbox/dev_env.md +++ b/src/sandbox/dev_env.md @@ -11,14 +11,15 @@ Please carefully handle the resources and follow the fair use principle and as w ## Getting Started Within the sandbox, the different disciplines of the IKID project can provide tasks to be worked on by the respective student groups. Both text-based tasks and programmatic tasks can be processed. For example, Markdown files can be created for editing textual tasks. -Currently, it is planned for the technical lectures that students get in touch with the programming language Python for the first time. Therefore, the Sandbox platform was created, in which experiments with Python can be carried out. +Currently, inside the technical lectures students (in the role User) get in touch with prorgramming languages for the first time. Therefore, the Sandbox platform was created, in which experiments and Usecases with Python of all User levels can be carried out. 1. **Sign in**, use your **HdM Credentials** at [Sandbox](https://sandbox.iuk.hdm-stuttgart.de/) -2. Select the image you want to start (two options) +2. Select the image you want to start (three options) 1. **Datascience environment** - 2. **Datascience GPU environment** (choose only if you realy need the graphic card, otherwise you block resources from those who need them) + 2. **GPU PyTorch environment** (PyTorch library with GPU support, choose only if you realy need the graphic card, otherwise you block resources from those who need them) + 3. **GPU TF environment** (Tensorflow library with GPU support, choose only if you realy need the graphic card, otherwise you block resources from those who need them) 3. Create or upload a .ipynb file: 1. . **create a empty .ipynb file:** ![sandbox launcher](res/sandbox_launcher.png "Sandbox Launcher") @@ -37,22 +38,27 @@ Currently, it is planned for the technical lectures that students get in touch w ## Technical Overview ### Environments -The Sandbox provides multiple scientific environments. If any additional packages or libraries are need, please open an issue on our [GIT](https://git.sandbox.iuk.hdm-stuttgart.de/). +The Sandbox provides multiple scientific environments. If any additional packages or libraries are needed, check if they are available on [PyPi](https://pypi.org/) and use pip to install it. If a problem occurs, please open an issue on our [GIT](https://git.sandbox.iuk.hdm-stuttgart.de/). #### Datascience environment * Available Data Science image is based on [Data Science Container](https://git.sandbox.iuk.hdm-stuttgart.de/grosse/-/packages/container/jupyterlab-datascience/latest) - * most common data analysis library's included for Julia, Python, R are available + * most common data analysis library's included for Python are available. -Please open an [issue](https://git.sandbox.iuk.hdm-stuttgart.de/grosse/jupyterlab-datascience/issues/new) if any additional packages are needed or issues occurred. +Please open an [issue](https://git.sandbox.iuk.hdm-stuttgart.de/grosse/jupyterlab-datascience/issues/new) if any additional packages are needed or issues occurred. -#### Datascience GPU environment +#### GPU PyTorch environment * Available GPU image is based on [Datascience GPU Container](https://git.sandbox.iuk.hdm-stuttgart.de/grosse/-/packages/container/jupyterlab-datascience-gpu/latest) - * support added for the NVIDIA GPU A100 computations based on python most common GPU-able libraries like Tensorflow, PyTorch and Keras. + * support added for the NVIDIA GPU A100 computations based on python library PyTorch. Please open an [issue](https://git.sandbox.iuk.hdm-stuttgart.de/grosse/jupyterlab-datascience-gpu/issues/new) if any additional packages are needed or issues occurred. +#### GPU TF environment +* Available GPU image is based on [Datascience GPU Container](https://git.sandbox.iuk.hdm-stuttgart.de/grosse/-/packages/container/jupyterlab-datascience-gpu/latest) + * support added for the NVIDIA GPU A100 computations based on python library Tensorflow. + +Please open an [issue](https://git.sandbox.iuk.hdm-stuttgart.de/grosse/jupyterlab-datascience-gpu/issues/new) if any additional packages are needed or issues occurred. ### Resources Each instance has following resource limits: From dc09353259c23dfc2cb537b5b8bb2de298171404 Mon Sep 17 00:00:00 2001 From: Cornelius Specht Date: Fri, 3 May 2024 11:23:17 +0200 Subject: [PATCH 2/3] add tf limits --- src/sandbox/dev_env.md | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/src/sandbox/dev_env.md b/src/sandbox/dev_env.md index a7a4981..0d7840c 100644 --- a/src/sandbox/dev_env.md +++ b/src/sandbox/dev_env.md @@ -5,7 +5,7 @@ ## Introduction The **Sandbox Development Environment** enables students and lecturers to create and work with interactive case studies. It also provides a development environment for researchers and advanced programmers. -The Sandbox is available at: https://sandbox.iuk.hdm-stuttgart.de +The Sandbox is available at: [https://sandbox.iuk.hdm-stuttgart.de](https://sandbox.iuk.hdm-stuttgart.de) Please carefully handle the resources and follow the fair use principle and as well as the German laws. ## Getting Started @@ -16,12 +16,12 @@ Currently, inside the technical lectures students (in the role User) get in touc 1. **Sign in**, use your **HdM Credentials** at [Sandbox](https://sandbox.iuk.hdm-stuttgart.de/) -2. Select the image you want to start (three options) +2. Select the environment you want to start (three options, GPU enviroments are limited to 10 instances in total) 1. **Datascience environment** 2. **GPU PyTorch environment** (PyTorch library with GPU support, choose only if you realy need the graphic card, otherwise you block resources from those who need them) 3. **GPU TF environment** (Tensorflow library with GPU support, choose only if you realy need the graphic card, otherwise you block resources from those who need them) 3. Create or upload a .ipynb file: - 1. . **create a empty .ipynb file:** + 1. **create a empty .ipynb file:** ![sandbox launcher](res/sandbox_launcher.png "Sandbox Launcher") 2. **upload a existing .ipynb file:** ![sandbox upload file](res/sandbox_upload_file_selector.png "Sandbox upload file") @@ -69,4 +69,23 @@ Each instance has following resource limits: For GPU enabled environments, 40GB shared (time sliced) GPU memory is availble. For additional information, please see the [official nvidia documentation](https://docs.nvidia.com/datacenter/tesla/mig-user-guide/index.html). ### Limitations -Please carefully follow the terms and conditions at [Sandbox](https://sandbox.iuk.hdm-stuttgart.de) website. The HDD free space can not be extended. The Sandbox should only be used for short running GPU tasks. For longer running trainings, please use the [Training Environment](sandbox/training.md). After GPU usage please stop your kernel/instance or free the blocked GPU resources manually. After 30 minutes of inactivity, the instanced will automatically removed. The HDD space is persistent, but will be deleted after 6 months. \ No newline at end of file +Please carefully follow the terms and conditions at [Sandbox](https://sandbox.iuk.hdm-stuttgart.de) website. The HDD free space can not be extended. The Sandbox should only be used for short running GPU tasks. For longer running trainings, please use the [Training Environment](sandbox/training.md). After GPU usage please stop your kernel/instance or free the blocked GPU resources manually. After 30 minutes of inactivity, the instanced will automatically removed. The HDD space is persistent, but will be deleted after 6 months. + +- **Important** Only for **GPU TF environment** use following memory limitation: + Tensorflow allocates in the beginning of each session all available resources. With the following chunk of code the memory limitation is set to 6024 MB GPU memory. If you dont limit the memory, all other users dont have any GPU support. + + ``` + gpus = tf.config.experimental.list_physical_devices('GPU') + if gpus: + + try: + tf.config.experimental.set_virtual_device_configuration(gpus[0], [tf.config.experimental.VirtualDeviceConfiguration(memory_limit=6024)]) + + except RuntimeError as e: + print(e) + ``` + At the end of your file you have to clean your session that the GPU resource is released. + + ``` + tf.keras.backend.clear_session() + ``` \ No newline at end of file From e55ca5c42cd10fb4c5e05cf97f3668bc3d2099bb Mon Sep 17 00:00:00 2001 From: Cornelius Specht Date: Tue, 14 May 2024 11:09:48 +0200 Subject: [PATCH 3/3] changes cospe --- src/architecture/hardware.md | 2 +- src/architecture/overview.md | 29 +++++++++++++++------------ src/sandbox/data_pool.md | 24 +++++++++++++++++++--- src/sandbox/dev_env.md | 16 ++++++++++++++- src/sandbox/overview.md | 13 +++++++----- src/sandbox/res/sandbox_datapool.png | Bin 0 -> 24292 bytes 6 files changed, 61 insertions(+), 23 deletions(-) create mode 100644 src/sandbox/res/sandbox_datapool.png diff --git a/src/architecture/hardware.md b/src/architecture/hardware.md index 6ca4e39..d15e904 100644 --- a/src/architecture/hardware.md +++ b/src/architecture/hardware.md @@ -14,7 +14,7 @@ ## NAS -Additional 20TB backup storage is located at IKARUS NAS. +Additional 20TB backup storage is located at TAURUS NAS. diff --git a/src/architecture/overview.md b/src/architecture/overview.md index 18641e2..582a040 100644 --- a/src/architecture/overview.md +++ b/src/architecture/overview.md @@ -2,19 +2,10 @@ ## Conceptual Design ![Sandbox Architecture](res/sandbox-architecture.png) -## Development Environment -An interactive, browser-based, development playground provides beginners and advanced users an isolated and safe AI playground. -## Training Environment -For long running processes (building/training) a userfriendly pipeline is available. + ## Use Cases -The sandbox offers the possibility to provide interactive use cases and demo scripts for online courses. -## Data Generator -In order to analyse training behaviour of maschine learning models, synthetic data can be generator according to the user requirements. (tbd) -## Data Pool -The Data Pool allows the user to exchange data with other sandbox users, advanced users, and scientific users. Therefore the users can use the storage for their assignments (notebook files), data (training) and other sandbox driven data. -## Sandbox Use Cases -The following scenarios can be derived for the system: on the one hand, the system is to be used for teaching and on the other hand, the system is to be used for training. -Therefore, a mixed-use architecture is provided, which allows the system to be used for these two different requirements, hence following role concept has been designed: + +The platform is a web-based, interactive environment runing on isolated and privacy friendly containers, designed to support an interdisciplinary user base comprising normal users, advanced users and scientific users. It facilitates teaching, research, and AI experimentation integrating four perspectives from Ethics, Law, Business and Computer Science. ### Roles @@ -29,8 +20,20 @@ Therefore, a mixed-use architecture is provided, which allows the system to be u * Provide/develop (own) examples/demos. **Scientific User** -* Data generation using synthetic data generator (tbd) * GPU usage * version control (GIT) * CI/CD for long running tasks * Storage + + +## Development Environment +An interactive, browser-based, development playground provides beginners and advanced users an isolated and safe AI playground. The platform is a web-based, interactive Jupyter Notebook environment powered by Kubernetes, designed to provide scalable and efficient computational resources. Users can create, edit, and run Jupyter Notebooks in their browsers, benefiting from the integrated environment to dynamically allocate computing power, manage resources, and ensure high availability. This setup allows for seamless collaboration, reproducibility, and the ability to handle complex data science workflows and provide a playground for AI, making it ideal for researchers, educators, and developers. + + +## Training Environment +The training environment empowers scientific users with a suite of flexible and advanced toolsets. This includes access to GPU-supported high-memory/CPU instances, ideal for tackling computationally intensive tasks and long-running training pipelines. For enhanced reproducibility and collaboration, the environment utilizes isolated containers with full version control, all seamlessly managed by a robust Kubernetes infrastructure. This ensures a consistent and scalable platform for your scientific workflows. + + +## Data Pool +The data pool caters to a wide range of users by offering a variety of flexible data storage options. Basic and advanced users alike can leverage the user-friendly Sandbox browser-based Explorer for intuitive data management. This web interface provides a drag-and- drop functionality and visual tools, making data exploration and organization effortless. For a more streamlined workflow, the Share UI provides a standalone interface. For power users, a powerful Share CLI is available, enabling them to efficiently save and manage their long-running trained models. This command-line interface integrates seamlessly with common data science tools and scripting languages, allowing for automation and customization. + diff --git a/src/sandbox/data_pool.md b/src/sandbox/data_pool.md index e2de15d..6aaf2c8 100644 --- a/src/sandbox/data_pool.md +++ b/src/sandbox/data_pool.md @@ -1,13 +1,16 @@ # Data Pool -In the following section we describe how to store data on the Sandbox. There are three different ways to do achieve: Inside the Sandbox, headless file upload on Object storage and Git LFS. +In the following section we describe how to store data on the Sandbox. There are four different ways to do achieve: Inside the Sandbox, headless file upload & user interface on Object storage and Git LFS. + +![Sandbox Data Pool](res/sandbox_datapool.png) + ## Inside the Sandbox To store the data inside the Sandbox, you just have to drag & drop or click on the upload button to save the file to your running instance. You can also create folders and new Notebooks. Please see the free space limitations [here](sandbox/dev_env#resources.md). ![file upload](res/sandbox_upload_file_selector.png "File Upload") -## Headless file storage +## Share CLI (Headless) To use the headless object storage, you can upload a file via REST-Interface or curl. The json response message provides you the destination url. **Upload Example** @@ -37,8 +40,23 @@ To use the headless object storage, you can upload a file via REST-Interface or ``` +## Share UI +[Share UI](https://share.sandbox.iuk.hdm-stuttgart.de/) is a web application that allows file transfer between all user groups. The user interface allows you to drag and drop files onto the sandbox, delete them and set passwords, which provides additional security for the data. Once the file has been successfully uploaded, a URL can be used to make the file(s) available to course participants or other user groups. + + ## Git LFS The following solution we highly recomment only for users which are familiar with git command line tools! Git Large File Storage (LFS). An open source Git extension for versioning large files. Git LFS replaces large files (audio, sample, datasets, videos) by a text pointer inside git. The files get stored on our gitea Server. -For further information visit [Git LFS](https://git-lfs.com/). +For further information visit [Git LFS](https://git-lfs.com/). +## Troubleshooting +- Files do not exist anymore after a certain period of time: The shared space is limited to 3 or 6 months. +- Impossible to curl from Share UI: The Share UI is mainly for UI users only, please use the Share CLI instead + + +## Useful Links + +- [CLI Share](https://share.storage.sandbox.iuk.hdm-stuttgart.de/upload/uuid/filename) +- [Share UI](https://share.sandbox.iuk.hdm-stuttgart.de/) +- [Curl](https://curl.se/docs/tutorial.html) +- [GIT LFS](https://git-lfs.com/) diff --git a/src/sandbox/dev_env.md b/src/sandbox/dev_env.md index 0d7840c..c07dc15 100644 --- a/src/sandbox/dev_env.md +++ b/src/sandbox/dev_env.md @@ -88,4 +88,18 @@ Please carefully follow the terms and conditions at [Sandbox](https://sandbox.iu ``` tf.keras.backend.clear_session() - ``` \ No newline at end of file + ``` + +## Troubleshooting +- when using javascript based plugins, it can happened that they either not load or run buggy: make sure you use chrome. Other browsers are often not supported by third party plugins +- Notebooks/Server/Dev Environment is going down: To avoid blocking resources, each environment has a certain timeout (frontend inactivity), so idling notebooks get culled to free resources for other user. +- my favourite xyz python packages is missing: use conda/pip (or inside a notebook: !pip install) to add additional packages +- all my data is gone after the semester break: all persistent storages get recycled of every(!) user each semester break. Please backup your data locally if needed +- package conflicts: common issue is to install a unspecific library version, please specify or upgrade all dependencies manually. + + +## Useful Links + +- [Jupyter Documentation](https://docs.jupyter.org/en/latest/) +- [pip](https://pip.pypa.io/en/stable/user_guide/) +- [python](https://docs.python.org/3.11/) \ No newline at end of file diff --git a/src/sandbox/overview.md b/src/sandbox/overview.md index 534ff3b..ee3162b 100644 --- a/src/sandbox/overview.md +++ b/src/sandbox/overview.md @@ -2,14 +2,17 @@ ![Sandbox Architecture](res/sandbox-architecture.png) +## Use Cases +A brief overview how to create [Use Cases](use_cases.md) on the Sandbox + + ## Development Environment A [Development Environment](dev_env.md) or Playground for beginners and advanced users. -## Use Cases -A brief overview how to create [Use Cases](use_cases.md) on the Sandbox + + ## Data Pool Details about how to store and manage data on the Sandbox: Additional information: [Data Pool](data_pool.md) + ## Training Environment -(tbd) -## Data Generator -(tbd) \ No newline at end of file +Detailed Information about how to perform a GPU supported model training on the Sandbox Environment. diff --git a/src/sandbox/res/sandbox_datapool.png b/src/sandbox/res/sandbox_datapool.png new file mode 100644 index 0000000000000000000000000000000000000000..a48c39c6b1e2ce68eeb7b216ac1945568e7c7c0f GIT binary patch literal 24292 zcmeIa2V9h0k}phXpvg^6BHd&qXAlY9WI+WLB*!L6Lz5)ujAW4{2&jmG3=)(qS)z#` z3J3~FP=X>L()YCDtMkt8?9P6BcW3T5KU?VMJSWzvs#Eo^I>hUr(xRqdryw98pw`h= zKSMx36al{PK}o^SIjycF@Qcvvj24QZeCW`70)j)&y)}%zUHu%KG4=#}QffcG@kxq1 zVZFThq}2H&C2ic@MbXYSj-EEIUZQUH-k=D)cg3Qe9h~jaKk7(|OG=A~%ZNxwpA(no zlR`?$fge)RqLPwwra$W2ING}%ba)aQ;Eci8@JVXQh>C-*1W(%7IlFmdy`1=@P~cg| z&D$OWeuHB0^YmHp!x;RR5Vw+$v64Fiz9QY-G4|)}ZFQZ&Y&2!0w{yYbo2WT?VqHOrri7%ls5t%~C_HQ9VB_ihTNn71`Ph4UIb+=p z7A7q!B`Wb_3HIJLjz3DpF-E@bXEi;v{3LCVa<2037vw7%^ks|nMB95F^oFk_rNJkT1Xb}LDYXN7g9kSoFzfFv&)PeC+lw5ucRnDz zGt$^i2IZ+?gfVop!D_o{h@f5n+}+PkUH!B?ZQPwsV$t8pi}w4`uY$b7k6EJqe-uap zg8nFR^!z!_!Lay(v(5oO*8*mXU!LPdXSBW7kH!ZTy|Gw~x3l|S7TRIm-0bZRxZt3o zji)Ep_b;nCU@-@)JE-FhnCCBg#}}OaE1Kd<&pV^N0UP1@RzgDdU}5+d+V;+lP6tEF z1NQvE#5O-GAFRa7$p($}{n7q=(eK;xgN{F`>50XH?ta^~-(UZ%Hg@>dzJRkpnUl9G20TfCuRx<<)UX)r4wbj$CL3tv!kHS0Ym)l72wtIpZG@VuQuzfoiktq zpo8&B^8eB8l9Twk6Mt*FB*hPQ<{xLfr2lHWP&QuwFYlDBoYcW4{LP(`_=npmnZMF< z_Goap94I}kr?(T<5$k4y(fC!0`b$0dtBxKP3zXn@?RUZ6+uQ%(q_nx{jr~jA_+w1` zK%hE!I8bz6*o&UuwJ9i)|53-=#?uj)T;FT`ahme}4oiV1H`< zAjW@Y;oqwR+wA9Y^0(U@)c$@v{6{ta>J$M+GXAXk?MVM0V0LgydHNdz78Vzkk(UO7 z@V&qUU-0um9e+Ikdcv!a?@xZt-ai`3%HXSl$M4NV6%_E61pfI~OZ>y{4fX9kox$n< z-N^o<>pvI%pvT`Uh!X#ehRHvlB+5xh|4G#=C>#|0eUkW(D<=o;!T+9|{1lA;jFkKr zdH7(<+-?5Rvtm%)Vh z4F3bi@keXCoA`gx50v}q&Hb_eKTXr${6N`%%dwC>5S*V@&i|+zcwhqlPI4z8z<3W( z=bwP;3O|Yb2h|l0nCLgEOW-XuyqWU5JNLgz^`Eo;jqF-@e~tKDq9 z@W1}?cR^0_&#s!nKgTW{SY5yE!r24nSJV3^;C?yrKYSp5!me1H2hM)u>yK?8go^G9T* zy<}pXfB;UQqmDf1XSsTfyy3Lr*L^Oj=rf3%n~C;LqB`Bu*Q1_>=^GSt-{4JqtY6H} zOMOP?R#E(AC-t1G+S&{h_DAnFM z^xe2X4-b!o9`b$Varta`@?6%?oofU=u|AYl!3MlDNxBs6f~Ez*b*I9@hmM^wT7(fM z)5a$DmCLJzp+?xwR`ak!#Ydbgi6#p(Kr5sEN(%#iRRpX3a?Qt4a`6!pt;ZCc+->V` zQY9vs9HIKqV|FKe)QJg6k5L<0bKIw&*&eyTRwwirA_%#O3Ep~r47^#^Ho2|_kykz> z$=^6jMM!~k)ay%jg14#OZl}OR8WA1hG8O6Y(a0f)w!Ts}++rrsrs~LfM94c1OhBz0 zeLfGNidalMGC@ZTVO^9q4tE_n5jLk*Vn1Fk$WRDNto}UVyA0lx^4Ley(9LYS_hzqL zk^&RBCc&q8BbjQO;LXLN(h&rh01aEZg+~lQ zbfHu+T1y&cUHHtJqz)+rXj7JH(|AKK3?=?})N#6u!Md;}`3lo9^{}}Pgk81J5Udd9 z-F;;xj+BVXo4vG6)`_oe{rU?@%=s(i`cTb@-Id0R;LT`SH7XWtmpod}r;80tU?}@C z=M&Yi@KcdY0ji%g;hh z8r*HJ?9_bZRVAW;J})_+;+00ESV_(cyGWFsQ0F?yFLU8}>Qxz+6Sq%Y3(}&`h6OE` z)feeziF$4h%ITJw))x7!zMSWxBnN_b@M*(Ah0W^pGDR(p_GgJ@ku&i37U`rHdCYaU zydhVI(r_L-CyN<}*EkGbZt~yU9c44pBLc(!_>{xO8+|M8V#p31;4Zbytt zvr8=+M=y*8Ger0)`t@guNIDF#mQXwVs>ut}AW{nWlzQgY37uFP&eDt1atN>jtn+AT zj`zy=6H_}Ay5DAyK`;f+R|#!NJf!fHooG4=u0C_$`Pp_nt4p!1#;@V|!-gNjIplpm zn7gnBF+{jd)@6`TG8?-H3UL$C!+(6j?=al4YHbXo5Vc zLgz&%?mMT~8W})M)%q^|K{f3*DQE3e8ucB?xaKx&m^xChzdrn^nJLkeK zoA|3}4>Vj9vl>11izO}q1#wS?nnUwf(LQMSDND>n;16mL)&f2D;%W>v&#$6T&~Udu zt2Uj0Tu`9WWlVJ9;l+|Gq82X$biaI@7TeB}!&>ev6om3xwFHe8v{UE+o`Q1%y1XBm zYX(HP&R1#ELHd5Wwe|RyS6;=m0{MP7yqBKqxV3)saS0Ci^hE33YW;L(m0iz?iE4Y2 z8#UJL5u;0v-}f<96sRa~@{JI1#^}>8zN{_5Ox6v?NypVp)HwFbjG6ObTXu@g-P=iw zcGVG1Bs@Y0Li)8dK*$t#6B+W24&Yq zuB)BQtP0xMaA=%h$nAyBn!sYU4*M6q@|_O$oUqTzactds=^|;}Mu5z$2J$8uvgdci zvZ>*|(-RcC%mrQ`HW?>#Wp#38UEh9a{FvFD#Ia1$pP5EL9(9Qz+WO8wSNCNC@^S94 zM0nII!}At=gI8tJ13oYHt@m&h7zAe=H7r6#l0Lnq%i_Pkvv9K5z3URw##G=(opk<_ zMTR9tPs_~Ycm_NdhD0ctg~i9NPa)J|dZ(HL2S=sKH|t^$f@Cy@1S^_0F6mu6W*D;l zhHT=2*KN9t=77(afdsQ5@H@#)xC`iWRruY~ixT^_nf8rmr&apMxPsvR8*i(k!#@KJ zrJe^S+sPUBS|I!m{djX=ySu&rZ|RPs>4o;j#&nl^}R*d#m(C99Y<^rDSphx9F~mj zrATIz(i|-{;n`dm&gx2F$qj7T-*vfbRCaZ5doE?(+yQR|-m2L50?_=c3YxfRneqtyh*3}lh74mgeF8zpkqmOG0 z3^U!*ytlhtF+Zh|z}%;>kjDc^m3l)X;qjFtXNxW_kIwt@XeCRxeu|=k8diK}vusj5`LT>`oxT*V9CF zykXc~WGaH^OD|7Kw%*h|!;-g`bwwp68^@EC<`Sg_a*ksdrak*b=8wOb4#l}j2APl} zp}mgz{@u_frNFIh7L`Fet6K+q!)4e1^jF5!mRLYo`RR&Jgr!gwGgXV zYT@BLj?PSR$&6mc*-~zPw;vma1RF=HF^U8mcZ`TDbg#-ffyJyv;}WC9YU|!c|Daj( z&gO#LjkP4XDRGsaghMbaEEyJVLf&2wx<6q~>=EnvM1v*g^t0oiM%3n;xFFMCKel2+ zV&x*&M(h=PE2M@@E&@fp8Wgq4gqTvhdvG>{iV|dd4ZZA5ya5{ zD*9KgpN0?w371Ayg0s6CoD1;mHMU>pDvX@y^YU00V0h!@Wse?C0ldJPb9-6?sT@7( z25bktT-lQs#>!pGP8q5HI`<6tD!t#Ic|USJ60d;p284Bia&VFJv*M>!c3Lh;_P=Zh zUYH?Ky1?m7|IPWn-ZY*v#M(*dsT@g-I=9zHZ)zr0j~f4F$0Ie4r;ixkyJGJ9`r;^T zn;-Jz5e3uH-egWi-q8KMQTBn~j0gAyh|h;tM}St#`q+w_0`?J8#K)Ge<$49m7V`r+ zcC}ARe>>7|sJAJ)jTIt^OI`zu>&7h}&BWB>{u{kO>y*jnWqEGE0uq(;+W@G2iLf$mR{8)^TdM>$=ak2^5SZfPd5x5TNgQK&;_ zksq7CP(hU?wwNE{*zbF916koC7j0 zqgT>T9qU_~Y&WSDaz|v-zz4q&6%EpQx_l6t%#FYCrTLC9GMODIQlAzvz@f?t4`GupcMngG$@aNjx- zu~;5y04;VjqiFxMZU5>d!igN+ThiC3s)bfQ^zsbShdx}k28PT;CQ4i>gfSv> z`@xx$r$~=cAkR1Tz7Bc&b{n{3V-{mH_1E!ZE_p35H=u5aSWE-#fXz!J#gMqjTK@~1A>5%esYKX;4 zd=s=P!1LWjW?Vc2EnXl76I#CsyWcsSaX}DbQN{c94H>X6Rqj-u0!s-3+U4g|siO;p zGSMn~;J8^NGaS`HWarcBLyLP-P$Tpz=kN9DAR2&W)|W1jA|yCLOGa)Tv@%(L8rTk; zP9L|cwF?`FLydu*g5Le~J`Z<>_cS7#yJ35Bn-i%ESF=2MiUQdpbLcy%jzD;<-yT}D z1@@c$>xUN^BaT$xhUw8A0&8$jHUw+PMow^+0MoK;7HyBy!cX!1_eIvn;0g988r10J zNX}!+$b#RtF>L^%3-^`T;76neyGPwS|MdhQ)%m8hvOLhuv$Od1upxE#%&*i2iUtqxiuRxaHBSL{se?#^f>*XZ-Jj_;q| zvY+ct3dg-iDM6mPkpFk>&V6V*F&T|}ZYR@i&pTX<5j1RP4bIP6jlSK>%JUF}q|aq| ze2yTYd>g~zmI}-?Xv>8U3bT}AP4GxE+Dt93;B(+)YGQO*aJAusU4i8R%j&+{Yf~Vk ze4L6t(l=-ePW!#fIRCc1@xx`{7U}?f^ypIBs?QYyD`t=9m4v>_z_OKIXYsOV^jVdh z{g@!u;xzkldwuQ}uuBQ+k2a;;gz0toFdaRY%B^up8`u%=#;ig!==n}$M~;Mk`<%7& zSV8v_6v78V*6CkIb>rYfp}<~J*c!JREcm!Pm!gs=h(-{)Ld2D~Rwj7xC-ce3R?>Ax zx}EAc+0)vsN=!mVR~|)E=3>eA_rHETQ;pV{I~}^eBe2lQyM6}BPcFRWiMBW#w1(u_ zpGk#~)ga7b zmcrK*eKUbU+?R3Q(pgdtEc7xkV5bJshL3M1ng_hU)$%19HR9VDt}>IRbvO+i;Z|E8 zUI*&$HGdv8y9F$$@Ops(TEHsL0*o`Pqn9&?NGN(~RrXRH%9@l)ArXub*52E1V*7`# zDN4D&>(4qJvbWw-IcwL*$*X_&3}1S)Cf*zBGq-z^NHU;;+hfp9IRYVWKeVlutg^oy z$^58S+DlH$}J=hyoQ>i zG0>IQjrD!d>eMi1qO-+%Y1h?a58t(} zzMm5%wfjswV+3|j2vLmpAW<_+RIMw>KN}=gQ3|O6NO_7DH`n#@kn^ z8*%>4CXGI2JN;tg)Fux+Zz*VQy!M@ro|LDlJ8U+-J&N#AzjwYuG|R##XC{R#s@8p< zvgF$WQ0VX*LUh~=s%pwD^RUJn1xadJ!llrmYo#FF{IPXsb zIa2mO(mxpU%qlrgH9feGomOTH?aAC<$ghd%!yVsc6@!KNHRkf=LDpO!0?%Bt_|!G_ zt2AJSNq6bp?pSRWRG=!&A9(V24Xw^Zt(NYi_GH3ryDpK}J-E-ZTi`>!xcbA zH(qX`_#W)R#{5_a9Z zFAOY83kZyQZk@=u4B)XluEO6=mpMOmGiKeRz1Ha?KGovLFYcONa+jdx{0(*T2m8Cr zFYX_yiE-aQ>zaR`eWB-je+3UO`~aOK%1&)M1Vh$H*Y|cd2Ynf8nRg3}`irK^#kaX6 z=eNDm0hvy;c9bHS!U1<#bSHBP0R?gXMfrF)=+WiseUAC>Jw`#*DXta7=}dlDI@;!F zpGw{N#{{F~vUd5cHBi3!{x`=YnH?>lPZ zm@~()r>^I&O!qu}%{gatSj7rx+C$HI(nDw#T8q-6mq;f!x$sy;#qFv(&L=*@@^mlx z@0BPI?#H(35nf*daL!Uh_oy+CKF~OLK;UI7RmaZo)w_m9=)nD(uyf81-;%0VoSQGgj}4ElP;?Qbreq_oO17!?=FTuT%oHS9l_mj z@UZw+yBf+E@ogc$S`XuLV*!`2|&If-|vDk_;by*BGsA(wQf4QYXfwb77KIwu{ zys?^m7W#dXy9J_w>SZ#YTJM;cpAU8Y3JfjLuQA0k_=WTwfw(ffFy#7nI!o!sDEqF} zbK&xm*1B&gDE+KpwP);;$xe-Pj1hJ5OZQUtZ}%TIaH0Mtc7b{9h1KM~7UE8S%XQ}@ zSFQW6Jt&Zq>K9*V;hx#2+^LP(XOT%*UaD}#-Gn{2pB}m2UB~nCgM4(M>y3v?H*xQ) zwVs=*;S#QPUHm*&hckdKRb!n@?I!75ee+QNSmcqRYzMYP-)NcHE#MlEUHl5%?lgdf zO=!MB1L6w|vR^&*1ou?#1vmxX^>BqsZ_e1na%P4^A9;?)0FM~lh+-7fhetPhePEv4 zXSskduCP?vS-hFDZzvxn0cI{#wZQ_yt; zz&JVLHW7Mx@&@3Tvv+fSaw8g?@2GnK>5ueA|x;L$jaA%%rQHLT&Q z>y5yfbzs+KC{cP)BF-{}$34d^eC=QP0n3O3ckJs*jXl6D9a@Gk5>W#N0BrHZAi1W` z?pk@)r8Ki|KA!DLc$edtpN2nSOX18N*<^I}Y1hme+^^>aEZucL;1S{e(<H4D4;J!;@UCf&ZCth?Pd8cr2F=~~|>Hyy+SCMZ=xFK-&uxAG8gpk}B6<2jMo z?d5%)m-n4{dZ&VS-epw-l+vUQljGr8dJMLfwvimX?^4n1@G`+ruOo)qes6pIOtBuD z|3;s{;88Z36sBD;3AdM_AhN^m*!(7jLobt*nD~pG`1K|*14+!dc+JC>mFj*ye(&x? zwwA^syr!^DLcu5*g-vaV5k|MNsn%)PklRlIds?p~_T5#Br6C;zz$qSSkPMjw;ntdf zuFMln)5n1c&YwWly1!h}`gW zWHpgxz)ITPdiugtgr6@n?6?$!7K_8jNt|WMMQRn zY};NO39LIT3lVE&GnI5LclFbFfhneEdV~_`T?pW5w);S&`KZ~YQ`;lSIBaA9Xi0@2 zy~!20Qq?_STJPp+^mwu!n*}h6Lue5_eG`jVL#jLmHs#~Qk5(gTl~Z%EEhdM9KN;|> zRFY7?8NI1R%doA4Xb8oH+%>ov18|T2qK6=WbQE|Qw}XJ;E*Z4#E(L?1LRh}pb5dD~ zQf-r+ZSa^&tU7R7?9}6&QK0XR^G9|9~4^`pq=Z%D9tsXN>WS8A3h#u zYagNXvmA-JmL`(}qE734P*i0%GdcfVsUi6eOl(^Ud<&*+_lsLIph@} zwuj4^!S6|)G6L#x@e#Q|FNo8<1;DTzb?07~24r3UlTeGDwk!wWaC%0E$q`}R)Och# zmu-t0KP~bzh|x)_s4SP(ye-akyPU?O^;oE)3HWJ@(M^T!KXU=n@|6OwDwF_yq3JYw z_v`{39*X-`Z;eRWVO4(5gw2If9v<*wjPThzGq)F;kMQsSY)xs4n3vgO*?*S-;G=8{ z==P)f=@1uN`22}iWLyIUDxr^1;zF)rB8~$!+hjPc8zjn{#a#>I)ZyZBkOkFht_ABO9gM?l5rFgni z366!waeJE%XSy;I1t3)s$grLZP?8cD#HFZPf{w@Urii@M9J$G9Xh6Dx(I7zKWl)S0 zT6)g`eE#q*ZE(lET$KKRENX8@PVp>esaCZJ*=ctsQpuole*H#!+2#>;dsy2u0i$09=P+|+GJJPz$A)>#Cu*1qqc zEhMFAXYK91gU;9=6y}L@rDIiWv3^=&QsdB_k|uHd`9(h@$#D0Hmy`{#h;h;wR<#{4 z+rgv6?OY4(O;p@cLc z?70BMLy*g7JwjX(G5$frfs{>AFFAYfxME=Jwv8j^)~mpe%^PbSw7IKNhxi0Rj3EY= z_?ZI|Qd(q3$^XEwU~P|KH4OThB3WsMt2+5OPxfwNIUkH?hI`z$J+3Y8DTwW+4|do> zP%uTxHKn{K7bfe<)|m#*!@PP`dGt|GTQ@d&_d>b|`O9I#hwHM^ke%GDj@y;nk8ZG= zwe{}#b>&KVydp_(rf7d2ER?2LyKNO@<~Wq+>@$~|*e*&oFO@f_){bJ?chrSC+@hZO zD1S7vVI>|VT#lfSu&hiSwFJNrECObNZT_6uS6(>d#c6zZHtE**6{(?foJ$WgMa-`1 zFrHdD83v2EGt3aPEyjNm!x_ki%u7OA_k`uSZ$05MDS9<(_Ns-*lL3 z6THJB6i9&#Mve3<_c$uT>%{4}BM*HYbuWcQtxD+FwujY3RVoe*`?0kfx3UZILg*#pns^Xz&-A;EsbNgM5xVeB1&?`yz^U8@F1E-HlXxxC10 zu&JXN)`d&MQVnk4xvxsQO+9v17NP?c9p^A}9ZzoS*8-s?Oufz1N0d79Gl@6JvwPh; z;Zs=H+bZ#}6hzpZIk#lUcu2BX@8MZ%S(?)~l`+(|_ABv*fJX$}sKZ&6BM02}%ranT z*u`;@_+S@#BPh2^T&V=JV6U>BvKqmcsKPHy5Nvr=?);a0@LG#qT*qBM1A=s+ zJZeJrF*r|TmWF=8m%B9bd@oZ(GPghWx0Ayu)-bQgBoa#L^SFqGYsTKYHr~XW9m+`z z2qGa#@!mE6bn3cc_bm#xwt*=4O5$oL`hxo?CCMz;LS<8;J5ZJHc%Hw%hU|djMxy$uW&0R)>Oh;1h~@E1O8j%d4C4C? zlIshU%@1J-9+omfh`0yLEtkfZm^xkZDpH1x1Wp|v7jo^H)^8QQd^7-ZE{?BMx!H>- z=S9Zi#Re7z5u>JTK@Tg3@UcKrWyMHW`%?3#JJ~{Y91=OUg>4eB%4UrIJq&&Ga2*f- z?kn|*XUFKcm%~@crV=|wO>b~L>+<0w;v2GQcU+SsulB22_*v%Z} z8Cbuvv7mh_b!VA`Pf2|(VhQ46(+GOkCM16|&Vu27KSRX2QpaTfxaM152t$oR`O{;# zt}TL|voOkahrpF5r2_%+E_Nz0`SS6l73$Zr6W*M!TdsT3qV~cja6h34_NhZVAJ$pK zbgq3zz4XS~4h)?nPB>SJFq#Nq!MnN5HrY_uFA67sZ%$t?n_T2);I-wi5i63B7J+S(nUo}*fS~i=qNY{0a zHI{I+S${uDj)xHN={o@PtG28!qfo$2aNn&stO79CzX%=&^G@8j55*_L%n#-Y0PI_@ zC_2|5P<}XDzD3}+Xc0gu{c-sm{J30c=gXL>CX>S< z+cvnc%6V0C@8!{xk26JFhO}M8@^JUf1b4P}WN;1kNZQ+_=Ml^kCdDj zYj;@&xh0e*wH8CKOBmKsQ{TiP#qr5iaJccKlh&^qJT~TYu@pm2(YFBXj0e4M7i<=Q z82D?Bzl?zowDdHgmvpQ4i^c3g4YhqO9If!%j!_|&if~2jh+5WVfTq+_r#{|~nS%=Be zNHEWela{jPs(Jc$#1v5vL%2Tev1G$OiOSVnx z05skerJths3}MBd+ARnn^L>HC$H*&McJJkUZP{HC+N1{%RPgO-IGu~li+hIlUp~Bc z_|S1E?lggOs06P8gU7z^m2*QDSs)xTgA!j@+vww+Q3=o6edbe#dz*?Y+J*#0s4rU; zuk|0ZVdXNopJ27+(ELXx69NH?QDvdOf+>!~XI@JmZDb4pDS+4I5Q>HIAn}>srBdW2 z$VhgofljIsaWh7IBBHO<207u}dPeUKfxPDhy~i{PsvxpU$Wu)j0CK|LSCN?ANC7F? z%DI&w9|NJy1t&}ZY1hJ!(1t_!wCkawl~iI7Q|1)sZY+!iV;nZC8R{fndiB^Up+3S`GI0YG}^H|7VIr-{#$`s4P$MTD|XX4+;2H73n<$laeX z+QX;kO7tA!A)#RG-7;+z+Xf-KcOZZB(^rX76(rDvMo%nSTY0$Qa{`lv6%xpJq=TXrvieD`O_G2g`zkmrkp^t;&BoKS=-Gp#q%!;JVE; zuDWEsPoUt+?fiffE#J1xypGI1YYQj71$;`AsjC>_OBGHa1*aP1(KaaZ^ z1Q1!zZZ=14aL=lGHOL6H2C&1dh5W!|l(<=hiIplyx;hT#olrBEU`;Um)lD@?7!h0@2oQTe+WBCZ0Wi z0#YnCr$PRZPHV`wA`o{ctCdXympO8=SM^AY>{!g*!>KrA^)4|UvCa1aH17k+&qW~j z+#%ZUsg6KS>A-lE-7R4LZGeCZWq$i*d5|{TY4Ya8HcvI#c=^j3$CTq6y*zA8O(3!^ z>Gnz%e^?Uc$WY&?RN{_tSouvAFZVuzQw zWfgVeLhHt3p)(J?ou!KFvD5nniNE$qTkq3{*JhP78+EoIni%N6T02&Bx{j7m4|`Mi#4}C*H?vd^+iM)S(VcW(Ksz@WAaa)1m$EvaCcwa=j!GqlxY( zj;a8VOzsJc{Ykl~4fZ3Dv(l*okXR}<+o%@+a(s&qivfD)FtJDm0ztXQ76r`7jISRW zhasZoDb`=!#B#A;mkZqwl7iz?_Zd1X=>uoN$=-r13vxO1RD$LyNYZsyvua9d{AC(& z-{@*Ph0UcxpDw2J*Jq8n5U3Z1V& z7~mx7H;`_A88B7Odc-4ILF-+T9<%BoHz{`Ds!TsrRd~RyaaEQ_l5XZIKIsjXIJ^CJTRSLdyn$Xh zIU6$F)0A8am-L!aXun+$@-k6mTP}*Zo3Yxb7tYO$%(G__N*#=>jQnWV$g)m8$9lv4 zX_1bmw@v?6ipsut1nq=Qr*@}YqDrCx)`b>j9QwV&QI}ZL z8j6P=pR*=pR4Q(wiY92?o~4xPh0~~fU6D#pQtKv;q`ey?Usm6hSYSi&rUe~koh54V z_WrX|QbQ>O@h_g1TQusesr#&@pH@x-Dg2MaiOKXvB8|IjZ1q@K<=5GI84Wa+WJw=( z4kp#8W&5Q?Yi3fnQ&7^QKjw$-`!nb@B}yAD^*%>JXW8=@P~E}cK7r;HgkpFh8CPt> z9=P0*1Opjf37pT928bmS}V%N#SVZI zXtuf*eYlaq>@d`!UO(aIPCTSf5K0tCWJ~0VJ1lIO%BUKIdPMjLO0r-fA)9(g^;P@! zz)>UXc2Y##<_10nuXEuQ{^G?POQX!8Kuwqj2|4MCzP}yCFp^)n#z(awfR7H5ZHVcT zvP(Y#%ZIf(NkzdW_u|qFL_jvFsd7!(n=-Tdt1HAt$3cEy3ta%z0eX}m$(0w1q|%h< zkI>uMct=7=m_vrv6c>a~xql!u=}=>e(eCMZ!T*JcDNMRSb$FH{yD2|6{!FtjqU9>Q{m5~HbVnn9AhLz;z&X4=VxOd$U z1?;=r>=i$il+9CVpL}e+dW>8k&zjg@a2X`qKEdRWBhN+4RaZWKbdMs32rYc!`5lCI zJI^u!B5w7(JlC1|-V5+&gj$^+;gBlH_6vi7xl37AArcF;2xdFVYA#k)Y}0y-!m|aY z;~dFW0cv8r*kCj2aYBIIk^p!2uib|eh7DA!fpAD zxN6V)TN=?!$ZQKy1i|bGL*fS@l8gDQ9sY(8&WaRPJFvg9V|G-Co5@t15S}QuAT~m( zi$K=QET@dpK{!fG^752d>bjaNol1vUoIExzLc}`J4812IODCTuf_y(&UtvwhDh5$d zJ_1Q+V+b)%ATewS+8KD%CA2L`VoPkx&`nhrqGY9+hkQhoz}v}nsJ-{75&U|X9=EOT zLln&JXpN8c?W1+@oN$j6SMv(*k5jK#&~L^KjjEVd)qS4y2iaoqu|)n5+f%Be8~Rv- zuQnVf@hRC()Tg1SrZ*V+AzGVdXOJh)FaCy)s;Hn!33A&7+$x$tX$G`_^owpn4`y;g zIuzZP87@*T2*=PCLWuAQDOrz^mqS5D`w22OracJXI^Th0O#pKYi;Y6m5O!6cUjwE)NwBxPaIyQ2!}Mm)C=U5X?@5=uh1XnHWF2*dI<7nPu5XQs0cf`L&&QLB&Zg4 zX8Ok;JW4~Xpb?Fvty;p5XwDc_&4N_o!81_q4@hsDCOC6IPDg27OtS>jbn-Tf9E^cZ zAk7%5NiRXk%{NV;k`!>2GVe$x|t9R!p7Wxp>!<}O)pU=;nPI&`ufts_8u2! za!S;z@m&p=DXT6kOU~eDV{4nLNQ;tz6Gy9v>>!FJ@rkq_b0%s#8fg@r8<^)LTLw+K zj5_T)Q3G`22<^9%(WBJY@1xwPg=DC5nNET0?{DsNm~m1OCZ|}-Zyw=I1%Cpd9qqJk zO5YnpK+I_o1*zt5TStC`69xnH=<`IB2!#Y8=|dPt%E>SIzg+M!Zij$g`zpBK__WuL zm|T1g$psHThj%4VNncXKS|K#_5&O!QYSUGvp>Lo2LT)0nnyD1QXq9HEtG;Oj-S*|g o3KGXGiu#m)yOh%l-BZB|oW6{Ct$q{y*?IyUjZ^C7DC>y-152A;$^ZZW literal 0 HcmV?d00001