From 3178b77723dc264f527b11605e3e5667ced437ce Mon Sep 17 00:00:00 2001 From: Eyal Danieli Date: Wed, 25 Sep 2024 12:36:48 +0300 Subject: [PATCH] [Infra] Align master with dev functions (#828) * [onnx utils] update onnx utils packages * [Noise-reduction] Add new function to hub (#765) * [Noise-reduction] Add new function to hub * fix test * added multiprocessing and silence removal to function * delete `load_dask` (#822) * [feature selection] update function yaml * [feature selection] update function yaml * Revert "[onnx utils] update onnx utils packages" This reverts commit 88727986ffa91662593958023be8ac3ccef2cab0. * [feature selection] update function yaml * [feature selection] update function yaml * Delete unsupported functions from the hub (#824) * delete EOS functions * bring back validate_great_expectations * bring back load_dataset * Update feature_selection/test_feature_selection.py Co-authored-by: Eyal Danieli * Update item.yaml * Align to master branch (#826) * [Category] Fix and add categories to functions (#808) * [Category] Fix and add categories to functions * bump version in structured * test is not valid in huggingface_serving * Fix duplicated footer * Fix duplicated footer * revert python version change as it will be done in another PR * comments * comments * Bump python:3.6 to python:3.9 (#810) * [Describe] Align describe to new pandas version (#812) * [Describe] Align describe to new pandas version * minor test fix * update mlrun version * add dask to requirements * remove dask * update numpy version * debug * debug * debug * remove dask tests * remove debug code * [get_offline_features] Updated to mlrun 1.6.3 (#813) * [Feature-selection] Replace matplotlib with plotly (#815) * Iguazio-cicd user token updated Iguazio-cicd user token updated in repo secrets: https://github.com/mlrun/functions/settings/secrets/actions MARKETPLACE_ACCESS_TOKEN_V3 new token gh...Zmf was set around April * forcing iguazio-cicd auth forcing iguazio-cicd to deal with Author identity unknown * checkout@v3 to v4 and echo * [Mlflow_utils] - mlflow model server (#811) * mlflow server * small fix to test * small fixes to ms and nb * small fixes to mlrun version * update requirements lightgbm * added req * Added xgboost to req --------- Co-authored-by: Avi Asulin <34214569+aviaIguazio@users.noreply.github.com> * [Mlflow] Remove mlflow tag (#825) * remove mlflow tag * remove mlflow tag --------- Co-authored-by: Avi Asulin <34214569+aviaIguazio@users.noreply.github.com> * align feature_selection yaml --------- Co-authored-by: Avi Asulin <34214569+aviaIguazio@users.noreply.github.com> Co-authored-by: Yonatan Shelach <92271540+yonishelach@users.noreply.github.com> Co-authored-by: rokatyy Co-authored-by: Katerina Molchanova <35141662+rokatyy@users.noreply.github.com> Co-authored-by: nashpaz123 <44337075+nashpaz123@users.noreply.github.com> Co-authored-by: ZeevRispler <73653682+ZeevRispler@users.noreply.github.com> --------- Co-authored-by: Avi Asulin Co-authored-by: Yonatan Shelach <92271540+yonishelach@users.noreply.github.com> Co-authored-by: Avi Asulin <34214569+aviaIguazio@users.noreply.github.com> Co-authored-by: rokatyy Co-authored-by: Katerina Molchanova <35141662+rokatyy@users.noreply.github.com> Co-authored-by: nashpaz123 <44337075+nashpaz123@users.noreply.github.com> Co-authored-by: ZeevRispler <73653682+ZeevRispler@users.noreply.github.com> --- README.md | 1 - bert_embeddings/bert_embeddings.ipynb | 503 ---- bert_embeddings/bert_embeddings.py | 41 - bert_embeddings/function.yaml | 42 - bert_embeddings/item.yaml | 28 - bert_embeddings/requirements.txt | 1 - bert_embeddings/test_bert_embeddings.py | 32 - catalog.json | 2 +- catalog.yaml | 9 - concept_drift/README.md | 132 - concept_drift/concept_drift.ipynb | 793 ------ concept_drift/concept_drift.py | 147 - concept_drift/function.yaml | 112 - concept_drift/item.yaml | 27 - concept_drift/requirements.txt | 1 - .../concept_drift_streaming.ipynb | 480 ---- .../concept_drift_streaming.py | 157 - concept_drift_streaming/function.yaml | 48 - concept_drift_streaming/item.yaml | 29 - concept_drift_streaming/requirements.txt | 1 - feature_perms/README.ipynb | 788 ----- feature_perms/feature_perms.ipynb | 1106 ------- feature_perms/feature_perms.py | 174 -- feature_perms/function.yaml | 63 - feature_perms/item.yaml | 25 - feature_perms/requirements.txt | 5 - feature_perms/test_feature_perms.py | 134 - feature_selection/function.yaml | 56 +- feature_selection/item.yaml | 4 +- feature_selection/requirements.txt | 2 +- feature_selection/test_feature_selection.py | 1 + get_offline_features/function.yaml | 127 - .../get_offline_features.ipynb | 1536 ---------- get_offline_features/get_offline_features.py | 143 - get_offline_features/item.yaml | 26 - .../test_get_offline_features.py | 239 -- hugging_face_classifier_trainer/function.yaml | 370 --- .../hugging_face_classifier_trainer.ipynb | 2533 ----------------- .../hugging_face_classifier_trainer.py | 832 ------ hugging_face_classifier_trainer/item.yaml | 33 - .../requirements.txt | 6 - .../test_hugging_face_classifier_trainer.py | 145 - huggingface_auto_trainer/function.yaml | 327 --- .../huggingface_auto_trainer.ipynb | 195 -- .../huggingface_auto_trainer.py | 855 ------ huggingface_auto_trainer/item.yaml | 27 - huggingface_auto_trainer/requirements.txt | 5 - .../test_huggingface_auto_trainer.py | 42 - ingest/function.yaml | 87 - ingest/ingest.ipynb | 762 ----- ingest/ingest.py | 84 - ingest/item.yaml | 27 - ingest/test_ingest.py | 171 -- load_dask/function.yaml | 75 - load_dask/item.yaml | 25 - load_dask/load_dask.ipynb | 309 -- load_dask/load_dask.py | 68 - model_monitoring_stream/function.yaml | 267 -- model_monitoring_stream/item.yaml | 23 - .../model_monitoring_stream.ipynb | 178 -- .../model_monitoring_stream.py | 768 ----- model_monitoring_stream/requirements.txt | 3 - noise_reduction/data/test_data.mp3 | Bin 0 -> 27972 bytes noise_reduction/data/test_data.wav | Bin 0 -> 179672 bytes noise_reduction/function.yaml | 194 ++ noise_reduction/item.yaml | 29 + noise_reduction/noise_reduction.ipynb | 942 ++++++ noise_reduction/noise_reduction.py | 625 ++++ noise_reduction/requirements.txt | 5 + noise_reduction/test_noise_reduction.py | 75 + pandas_profiling_report/README.md | 26 - pandas_profiling_report/function.yaml | 40 - pandas_profiling_report/item.yaml | 25 - .../pandas_profiling_report.ipynb | 794 ------ .../pandas_profiling_report.py | 41 - project_runner/function.yaml | 53 - project_runner/project_runner.ipynb | 340 --- rnn_serving/function.yaml | 46 - rnn_serving/item.yaml | 25 - rnn_serving/requirements.txt | 2 - rnn_serving/rnn_serving.ipynb | 285 -- rnn_serving/rnn_serving.py | 35 - rnn_serving/test_rnn_serving.py | 74 - slack_notify/README.md | 1 - slack_notify/function.yaml | 48 - slack_notify/item.yaml | 25 - slack_notify/slack_notify.ipynb | 293 -- slack_notify/slack_notify.py | 48 - snowflake_dask/README.md | 38 - snowflake_dask/config-template.yaml | 5 - snowflake_dask/function.yaml | 81 - .../img/iguazio-project-secrets.png | Bin 105122 -> 0 bytes snowflake_dask/img/snowflake-dask.png | Bin 58722 -> 0 bytes snowflake_dask/item.yaml | 25 - snowflake_dask/requirements.txt | 2 - snowflake_dask/snowflake-dask-mlrun.ipynb | 437 --- snowflake_dask/snowflake_dask.py | 125 - snowflake_dask/test_snowflake_dask.py | 24 - sql_to_file/function.yaml | 47 - sql_to_file/item.yaml | 24 - sql_to_file/requirements.txt | 2 - sql_to_file/sql_to_file.ipynb | 1567 ---------- sql_to_file/sql_to_file.py | 45 - sql_to_file/test_sql_to_file.py | 31 - stream_to_parquet/function.yaml | 45 - stream_to_parquet/item.yaml | 28 - stream_to_parquet/stream_to_parquet.ipynb | 698 ----- stream_to_parquet/stream_to_parquet.py | 96 - tf1_serving/function.yaml | 48 - tf1_serving/item.yaml | 28 - tf1_serving/requirements.txt | 2 - tf1_serving/tf1_serving.ipynb | 567 ---- tf1_serving/tf1_serving.py | 87 - tf2_serving_v2/function.yaml | 45 - tf2_serving_v2/item.yaml | 28 - tf2_serving_v2/requirements.txt | 2 - tf2_serving_v2/tf2_serving_v2.ipynb | 545 ---- tf2_serving_v2/tf2_serving_v2.py | 71 - virtual_drift/README.md | 56 - virtual_drift/function.yaml | 129 - virtual_drift/item.yaml | 28 - virtual_drift/virtual_drift.ipynb | 935 ------ virtual_drift/virtual_drift.py | 206 -- xgb_custom/function.yaml | 241 -- xgb_custom/item.yaml | 26 - xgb_custom/requirements.txt | 7 - xgb_custom/test_xgb_custom.py | 50 - xgb_custom/xgb_custom.ipynb | 922 ------ xgb_custom/xgb_custom.py | 239 -- xgb_serving/function.yaml | 40 - xgb_serving/item.yaml | 29 - xgb_serving/requirements.txt | 7 - xgb_serving/test_xgb_serving.py | 67 - xgb_serving/xgb_serving.ipynb | 421 --- xgb_serving/xgb_serving.py | 33 - 135 files changed, 1897 insertions(+), 25585 deletions(-) delete mode 100644 bert_embeddings/bert_embeddings.ipynb delete mode 100644 bert_embeddings/bert_embeddings.py delete mode 100644 bert_embeddings/function.yaml delete mode 100644 bert_embeddings/item.yaml delete mode 100644 bert_embeddings/requirements.txt delete mode 100644 bert_embeddings/test_bert_embeddings.py delete mode 100644 concept_drift/README.md delete mode 100644 concept_drift/concept_drift.ipynb delete mode 100644 concept_drift/concept_drift.py delete mode 100644 concept_drift/function.yaml delete mode 100644 concept_drift/item.yaml delete mode 100644 concept_drift/requirements.txt delete mode 100644 concept_drift_streaming/concept_drift_streaming.ipynb delete mode 100644 concept_drift_streaming/concept_drift_streaming.py delete mode 100644 concept_drift_streaming/function.yaml delete mode 100644 concept_drift_streaming/item.yaml delete mode 100644 concept_drift_streaming/requirements.txt delete mode 100644 feature_perms/README.ipynb delete mode 100644 feature_perms/feature_perms.ipynb delete mode 100644 feature_perms/feature_perms.py delete mode 100644 feature_perms/function.yaml delete mode 100644 feature_perms/item.yaml delete mode 100644 feature_perms/requirements.txt delete mode 100644 feature_perms/test_feature_perms.py delete mode 100644 get_offline_features/function.yaml delete mode 100644 get_offline_features/get_offline_features.ipynb delete mode 100644 get_offline_features/get_offline_features.py delete mode 100644 get_offline_features/item.yaml delete mode 100644 get_offline_features/test_get_offline_features.py delete mode 100644 hugging_face_classifier_trainer/function.yaml delete mode 100644 hugging_face_classifier_trainer/hugging_face_classifier_trainer.ipynb delete mode 100755 hugging_face_classifier_trainer/hugging_face_classifier_trainer.py delete mode 100755 hugging_face_classifier_trainer/item.yaml delete mode 100644 hugging_face_classifier_trainer/requirements.txt delete mode 100644 hugging_face_classifier_trainer/test_hugging_face_classifier_trainer.py delete mode 100644 huggingface_auto_trainer/function.yaml delete mode 100644 huggingface_auto_trainer/huggingface_auto_trainer.ipynb delete mode 100644 huggingface_auto_trainer/huggingface_auto_trainer.py delete mode 100644 huggingface_auto_trainer/item.yaml delete mode 100644 huggingface_auto_trainer/requirements.txt delete mode 100644 huggingface_auto_trainer/test_huggingface_auto_trainer.py delete mode 100644 ingest/function.yaml delete mode 100644 ingest/ingest.ipynb delete mode 100644 ingest/ingest.py delete mode 100644 ingest/item.yaml delete mode 100644 ingest/test_ingest.py delete mode 100644 load_dask/function.yaml delete mode 100644 load_dask/item.yaml delete mode 100644 load_dask/load_dask.ipynb delete mode 100644 load_dask/load_dask.py delete mode 100644 model_monitoring_stream/function.yaml delete mode 100644 model_monitoring_stream/item.yaml delete mode 100644 model_monitoring_stream/model_monitoring_stream.ipynb delete mode 100644 model_monitoring_stream/model_monitoring_stream.py delete mode 100644 model_monitoring_stream/requirements.txt create mode 100644 noise_reduction/data/test_data.mp3 create mode 100644 noise_reduction/data/test_data.wav create mode 100644 noise_reduction/function.yaml create mode 100644 noise_reduction/item.yaml create mode 100644 noise_reduction/noise_reduction.ipynb create mode 100644 noise_reduction/noise_reduction.py create mode 100644 noise_reduction/requirements.txt create mode 100644 noise_reduction/test_noise_reduction.py delete mode 100644 pandas_profiling_report/README.md delete mode 100644 pandas_profiling_report/function.yaml delete mode 100644 pandas_profiling_report/item.yaml delete mode 100644 pandas_profiling_report/pandas_profiling_report.ipynb delete mode 100644 pandas_profiling_report/pandas_profiling_report.py delete mode 100644 project_runner/function.yaml delete mode 100644 project_runner/project_runner.ipynb delete mode 100644 rnn_serving/function.yaml delete mode 100644 rnn_serving/item.yaml delete mode 100644 rnn_serving/requirements.txt delete mode 100644 rnn_serving/rnn_serving.ipynb delete mode 100644 rnn_serving/rnn_serving.py delete mode 100644 rnn_serving/test_rnn_serving.py delete mode 100644 slack_notify/README.md delete mode 100644 slack_notify/function.yaml delete mode 100644 slack_notify/item.yaml delete mode 100644 slack_notify/slack_notify.ipynb delete mode 100644 slack_notify/slack_notify.py delete mode 100644 snowflake_dask/README.md delete mode 100644 snowflake_dask/config-template.yaml delete mode 100644 snowflake_dask/function.yaml delete mode 100644 snowflake_dask/img/iguazio-project-secrets.png delete mode 100644 snowflake_dask/img/snowflake-dask.png delete mode 100644 snowflake_dask/item.yaml delete mode 100644 snowflake_dask/requirements.txt delete mode 100644 snowflake_dask/snowflake-dask-mlrun.ipynb delete mode 100644 snowflake_dask/snowflake_dask.py delete mode 100644 snowflake_dask/test_snowflake_dask.py delete mode 100644 sql_to_file/function.yaml delete mode 100644 sql_to_file/item.yaml delete mode 100644 sql_to_file/requirements.txt delete mode 100644 sql_to_file/sql_to_file.ipynb delete mode 100644 sql_to_file/sql_to_file.py delete mode 100644 sql_to_file/test_sql_to_file.py delete mode 100644 stream_to_parquet/function.yaml delete mode 100644 stream_to_parquet/item.yaml delete mode 100644 stream_to_parquet/stream_to_parquet.ipynb delete mode 100644 stream_to_parquet/stream_to_parquet.py delete mode 100644 tf1_serving/function.yaml delete mode 100644 tf1_serving/item.yaml delete mode 100644 tf1_serving/requirements.txt delete mode 100644 tf1_serving/tf1_serving.ipynb delete mode 100644 tf1_serving/tf1_serving.py delete mode 100644 tf2_serving_v2/function.yaml delete mode 100644 tf2_serving_v2/item.yaml delete mode 100644 tf2_serving_v2/requirements.txt delete mode 100644 tf2_serving_v2/tf2_serving_v2.ipynb delete mode 100644 tf2_serving_v2/tf2_serving_v2.py delete mode 100644 virtual_drift/README.md delete mode 100644 virtual_drift/function.yaml delete mode 100644 virtual_drift/item.yaml delete mode 100644 virtual_drift/virtual_drift.ipynb delete mode 100644 virtual_drift/virtual_drift.py delete mode 100644 xgb_custom/function.yaml delete mode 100644 xgb_custom/item.yaml delete mode 100644 xgb_custom/requirements.txt delete mode 100644 xgb_custom/test_xgb_custom.py delete mode 100644 xgb_custom/xgb_custom.ipynb delete mode 100644 xgb_custom/xgb_custom.py delete mode 100644 xgb_serving/function.yaml delete mode 100644 xgb_serving/item.yaml delete mode 100644 xgb_serving/requirements.txt delete mode 100644 xgb_serving/test_xgb_serving.py delete mode 100644 xgb_serving/xgb_serving.ipynb delete mode 100644 xgb_serving/xgb_serving.py diff --git a/README.md b/README.md index 9a1e74821..1136c963d 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,6 @@ it is expected that contributors follow certain guidelines/protocols (please chi | [feature-selection](feature_selection/feature_selection.ipynb) | job | Select features through multiple Statistical and Model filters | data-prep, ml | | [gen-class-data](gen_class_data/gen_class_data.ipynb) | job | Create a binary classification sample dataset and save. | data-prep | | [github-utils](github_utils/github_utils.ipynb) | job | add comments to github pull request | notifications, utils | -| [load-dask](load_dask/load_dask.ipynb) | dask | load dask cluster with data | data-movement, utils | | [load-dataset](load_dataset/load_dataset.ipynb) | job | load a toy dataset from scikit-learn | data-source, ml | | [model-monitoring-batch](model_monitoring_batch/model_monitoring_batch.ipynb) | job | | | | [model-monitoring-stream](model_monitoring_stream/model_monitoring_stream.ipynb) | nuclio | | | diff --git a/bert_embeddings/bert_embeddings.ipynb b/bert_embeddings/bert_embeddings.ipynb deleted file mode 100644 index cb6d55841..000000000 --- a/bert_embeddings/bert_embeddings.ipynb +++ /dev/null @@ -1,503 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## BERT Embeddings Serverless Function\n", - "This notebook presents deployment of pretrained BERT model that outputs embeddings for given textual sequences as a serverless function. Embeddings are meaningful, contextual representations of text in the form of ndarrays that are used frequently as input to various learning tasks in the field of NLP." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Embeddings without bert" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "[One-Hot Encoding](https://en.wikipedia.org/wiki/One-hot) is a general method that can vectorize any categorical features. It is simple and fast to create and update the vectorization.
\n", - "in case of text embeddings, each row is a sentence and each column is a word/char/[n-gram](https://en.wikipedia.org/wiki/N-gram)." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "# some sentences to do examine\n", - "sentences = ['the quick brown fox jumps over the lazy dog',\n", - " 'Hello I am Jacob',\n", - " 'Daniel visited Tel-Aviv last month']" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "lets see the difference between bert embeddings and one-hot encoding" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "['the', 'quick', 'brown', 'fox', 'jumps', 'over', 'lazy', 'dog', 'Hello', 'I', 'am', 'Jacob', 'Daniel', 'visited', 'Tel-Aviv', 'last', 'month']\n" - ] - } - ], - "source": [ - "# constructing a list of all the words (will be our columns) - make sure no duplicate words are set\n", - "tokens = []\n", - "for sentence in sentences:\n", - " for word in sentence.split():\n", - " tokens.append(word) if word not in tokens else \"\"\n", - "print(tokens)" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "# constructing the one hot vector\n", - "import pandas as pd\n", - "import numpy as np\n", - "\n", - "one_hot = pd.DataFrame(columns = range(len(tokens)))\n", - "# filling our empty dataframe with each sentence encoding\n", - "for sentence in sentences:\n", - " vector = np.zeros(len(tokens))\n", - " for word in sentence.split():\n", - " vector[tokens.index(word)]=1\n", - " one_hot = one_hot.append(pd.Series(vector),ignore_index=True)\n", - "one_hot.columns = tokens" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
thequickbrownfoxjumpsoverlazydogHelloIamJacobDanielvisitedTel-Avivlastmonth
01.01.01.01.01.01.01.01.00.00.00.00.00.00.00.00.00.0
10.00.00.00.00.00.00.00.01.01.01.01.00.00.00.00.00.0
20.00.00.00.00.00.00.00.00.00.00.00.01.01.01.01.01.0
\n", - "
" - ], - "text/plain": [ - " the quick brown fox jumps over lazy dog Hello I am Jacob \\\n", - "0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 0.0 0.0 0.0 0.0 \n", - "1 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 1.0 1.0 1.0 \n", - "2 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n", - "\n", - " Daniel visited Tel-Aviv last month \n", - "0 0.0 0.0 0.0 0.0 0.0 \n", - "1 0.0 0.0 0.0 0.0 0.0 \n", - "2 1.0 1.0 1.0 1.0 1.0 " - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "one_hot" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The table above represents the one-hot encoding of our sentences, each row is a sentence and each column is a word.\n", - "this representation is very slim and will be a very weak learning dataset." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Introducing Bert embeddings" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "from mlrun import import_function, auto_mount" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "# importing the function from the hub\n", - "fn = import_function(\"hub://bert_embeddings\").apply(auto_mount())" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "> 2023-02-02 09:29:59,002 [info] Starting remote function deploy\n", - "2023-02-02 09:29:59 (info) Deploying function\n", - "2023-02-02 09:29:59 (info) Building\n", - "2023-02-02 09:29:59 (info) Staging files and preparing base images\n", - "2023-02-02 09:29:59 (info) Building processor image\n", - "2023-02-02 09:32:09 (info) Build complete\n", - "2023-02-02 09:32:35 (info) Function deploy complete\n", - "> 2023-02-02 09:32:36,059 [info] successfully deployed function: {'internal_invocation_urls': ['nuclio-default-bert-embeddings.default-tenant.svc.cluster.local:8080'], 'external_invocation_urls': ['default-bert-embeddings-default.default-tenant.app.cto-office.iguazio-cd1.com/']}\n" - ] - } - ], - "source": [ - "# deploying the function\n", - "addr = fn.deploy()" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [], - "source": [ - "import requests\n", - "import json\n", - "# sending a request to the function endpoint to get the sentences' embeddings\n", - "resp = requests.post(addr, json=json.dumps(sentences))" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "import pickle\n", - "output_embeddings = pickle.loads(resp.content)" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "embeddings per token shape: (3, 11, 768), pooled embeddings shape: (3, 768)\n" - ] - } - ], - "source": [ - "print(f'embeddings per token shape: {output_embeddings[0].shape}, pooled embeddings shape: {output_embeddings[1].shape}')" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
0123456789...758759760761762763764765766767
0-0.733322-0.2235400.3424620.383463-0.1647960.0405220.8028450.1528420.331639-0.999779...0.2065640.2314150.1964330.7979080.4351750.7493700.2460980.427603-0.5773840.842063
1-0.953005-0.535132-0.7438220.8939340.646276-0.2793880.9435130.275504-0.555109-0.999992...0.582386-0.0046140.9760790.931517-0.3914420.5303840.675933-0.682721-0.7463390.957809
2-0.843678-0.453405-0.8260110.6508050.494036-0.1541170.8216420.349507-0.650629-0.999978...0.618286-0.3367000.9362620.857577-0.7874890.2461370.676243-0.612532-0.7087860.840879
\n", - "

3 rows × 768 columns

\n", - "
" - ], - "text/plain": [ - " 0 1 2 3 4 5 6 \\\n", - "0 -0.733322 -0.223540 0.342462 0.383463 -0.164796 0.040522 0.802845 \n", - "1 -0.953005 -0.535132 -0.743822 0.893934 0.646276 -0.279388 0.943513 \n", - "2 -0.843678 -0.453405 -0.826011 0.650805 0.494036 -0.154117 0.821642 \n", - "\n", - " 7 8 9 ... 758 759 760 761 \\\n", - "0 0.152842 0.331639 -0.999779 ... 0.206564 0.231415 0.196433 0.797908 \n", - "1 0.275504 -0.555109 -0.999992 ... 0.582386 -0.004614 0.976079 0.931517 \n", - "2 0.349507 -0.650629 -0.999978 ... 0.618286 -0.336700 0.936262 0.857577 \n", - "\n", - " 762 763 764 765 766 767 \n", - "0 0.435175 0.749370 0.246098 0.427603 -0.577384 0.842063 \n", - "1 -0.391442 0.530384 0.675933 -0.682721 -0.746339 0.957809 \n", - "2 -0.787489 0.246137 0.676243 -0.612532 -0.708786 0.840879 \n", - "\n", - "[3 rows x 768 columns]" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "pd.DataFrame(output_embeddings[1])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "we can see that the size of the first dimension of the outputs is three since we passed in three sequences. Also the intermediate dimension of the first output is the maximal number of tokens across all input sequences. Sequences with less tokens are padded with zero values.
\n", - "Note that the first input has an intermediate dimension of size 11 that corresponds to the number of max tokens in the input sequence after addition of two special tokens marking beginning and end of a sequence by the tokenizer.
\n", - "The last dimension for both is of size 768 which is the embedding dimension for this default configuration of bert.
\n", - "Now you tell me, which encoding are you gonna use in your project ??" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "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.7.6" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/bert_embeddings/bert_embeddings.py b/bert_embeddings/bert_embeddings.py deleted file mode 100644 index 109081b1b..000000000 --- a/bert_embeddings/bert_embeddings.py +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright 2019 Iguazio -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -import json -import pickle - -import torch -from transformers import BertModel, BertTokenizer - - -def init_context(context): - tokenizer = BertTokenizer.from_pretrained("bert-base-uncased") - model = BertModel.from_pretrained("bert-base-uncased") - model.eval() - - setattr(context.user_data, "tokenizer", tokenizer) - setattr(context.user_data, "model", model) - - -def handler(context, event): - docs = json.loads(event.body) - docs = [doc.lower() for doc in docs] - docs = context.user_data.tokenizer.batch_encode_plus( - docs, pad_to_max_length=True, return_tensors="pt" - ) - - with torch.no_grad(): - embeddings = context.user_data.model(**docs) - embeddings = [embeddings[0].numpy(), embeddings[1].numpy()] - return pickle.dumps(embeddings) diff --git a/bert_embeddings/function.yaml b/bert_embeddings/function.yaml deleted file mode 100644 index 15319c160..000000000 --- a/bert_embeddings/function.yaml +++ /dev/null @@ -1,42 +0,0 @@ -kind: remote -metadata: - name: bert-embeddings - tag: '' - hash: ecf6647fe4716e0df54ce50278b735034536a568 - project: '' - labels: - framework: pytorch - categories: - - huggingface - - machine-learning - - data-preparation - - pytorch -spec: - command: '' - args: [] - image: mlrun/mlrun - build: - functionSourceCode: IyBDb3B5cmlnaHQgMjAxOSBJZ3VhemlvCiMKIyBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgIkxpY2Vuc2UiKTsKIyB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiMgWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0CiMKIyAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wCiMKIyBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlCiMgZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gIkFTIElTIiBCQVNJUywKIyBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KIyBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kCiMgbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuCiMKaW1wb3J0IGpzb24KaW1wb3J0IHBpY2tsZQoKaW1wb3J0IHRvcmNoCmZyb20gdHJhbnNmb3JtZXJzIGltcG9ydCBCZXJ0TW9kZWwsIEJlcnRUb2tlbml6ZXIKCgpkZWYgaW5pdF9jb250ZXh0KGNvbnRleHQpOgogICAgdG9rZW5pemVyID0gQmVydFRva2VuaXplci5mcm9tX3ByZXRyYWluZWQoImJlcnQtYmFzZS11bmNhc2VkIikKICAgIG1vZGVsID0gQmVydE1vZGVsLmZyb21fcHJldHJhaW5lZCgiYmVydC1iYXNlLXVuY2FzZWQiKQogICAgbW9kZWwuZXZhbCgpCgogICAgc2V0YXR0cihjb250ZXh0LnVzZXJfZGF0YSwgInRva2VuaXplciIsIHRva2VuaXplcikKICAgIHNldGF0dHIoY29udGV4dC51c2VyX2RhdGEsICJtb2RlbCIsIG1vZGVsKQoKCmRlZiBoYW5kbGVyKGNvbnRleHQsIGV2ZW50KToKICAgIGRvY3MgPSBqc29uLmxvYWRzKGV2ZW50LmJvZHkpCiAgICBkb2NzID0gW2RvYy5sb3dlcigpIGZvciBkb2MgaW4gZG9jc10KICAgIGRvY3MgPSBjb250ZXh0LnVzZXJfZGF0YS50b2tlbml6ZXIuYmF0Y2hfZW5jb2RlX3BsdXMoCiAgICAgICAgZG9jcywgcGFkX3RvX21heF9sZW5ndGg9VHJ1ZSwgcmV0dXJuX3RlbnNvcnM9InB0IgogICAgKQoKICAgIHdpdGggdG9yY2gubm9fZ3JhZCgpOgogICAgICAgIGVtYmVkZGluZ3MgPSBjb250ZXh0LnVzZXJfZGF0YS5tb2RlbCgqKmRvY3MpCiAgICBlbWJlZGRpbmdzID0gW2VtYmVkZGluZ3NbMF0ubnVtcHkoKSwgZW1iZWRkaW5nc1sxXS5udW1weSgpXQogICAgcmV0dXJuIHBpY2tsZS5kdW1wcyhlbWJlZGRpbmdzKQo= - commands: [] - code_origin: '' - origin_filename: '' - requirements: - - torch - description: Get BERT based embeddings for given text - default_handler: '' - disable_auto_mount: false - clone_target_dir: '' - env: - - name: MLRUN_HTTPDB__NUCLIO__EXPLICIT_ACK - value: enabled - priority_class_name: '' - preemption_mode: prevent - min_replicas: 1 - max_replicas: 4 - source: '' - function_handler: bert_embeddings:handler - base_image_pull: false - affinity: null - tolerations: null - security_context: {} -verbose: false diff --git a/bert_embeddings/item.yaml b/bert_embeddings/item.yaml deleted file mode 100644 index f96e54eae..000000000 --- a/bert_embeddings/item.yaml +++ /dev/null @@ -1,28 +0,0 @@ -apiVersion: v1 -categories: -- huggingface -- machine-learning -- data-preparation -- pytorch -description: Get BERT based embeddings for given text -doc: '' -example: bert_embeddings.ipynb -generationDate: 2022-08-28:17-25 -hidden: false -icon: '' -labels: - framework: pytorch -maintainers: [] -marketplaceType: '' -mlrunVersion: 1.4.1 -name: bert-embeddings -platformVersion: 3.5.3 -spec: - filename: bert_embeddings.py - handler: handler - image: mlrun/mlrun - kind: nuclio - requirements: - - torch -url: '' -version: 1.3.0 diff --git a/bert_embeddings/requirements.txt b/bert_embeddings/requirements.txt deleted file mode 100644 index 747b7aa97..000000000 --- a/bert_embeddings/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -transformers \ No newline at end of file diff --git a/bert_embeddings/test_bert_embeddings.py b/bert_embeddings/test_bert_embeddings.py deleted file mode 100644 index 7ad9101cc..000000000 --- a/bert_embeddings/test_bert_embeddings.py +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright 2019 Iguazio -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -from bert_embeddings import init_context,handler -import nuclio -import json -import pickle -import numpy as np - -ARCHIVE = "https://archive.ics.uci.edu/ml/machine-learning-databases/00280/HIGGS.csv.gz" -ARTIFACTS_PATH = 'artifacts' - - -def test_bert_embeddings(): - event = nuclio.Event(body=json.dumps(['John loves Mary'])) - ctx = nuclio.Context() - init_context(ctx) - outputs = pickle.loads(handler(ctx, event)) - assert (True if abs(np.mean(outputs[0]) - -0.011996539) <= 0.0001 else False) is True - assert (True if abs(np.mean(outputs[0]) - -0.011996539) > 0 else False) is True - diff --git a/catalog.json b/catalog.json index 6fff9830c..4bcc4022d 100644 --- a/catalog.json +++ b/catalog.json @@ -1 +1 @@ -{"aggregate": {"description": "Rolling aggregation over Metrics and Lables according to specifications", "categories": ["data-prep"], "kind": "job", "docfile": "aggregate/aggregate.ipynb", "versions": {"latest": "aggregate/function.yaml"}}, "arc-to-parquet": {"description": "retrieve remote archive, open and save as parquet", "categories": ["data-movement", "utils"], "kind": "job", "docfile": "arc_to_parquet/arc_to_parquet.ipynb", "versions": {"latest": "arc_to_parquet/function.yaml"}}, "bert-embeddings": {"description": "Get BERT based embeddings for given text", "categories": ["NLP", "BERT", "embeddings"], "kind": "remote", "docfile": "bert_embeddings/bert_embeddings.ipynb", "versions": {"latest": "bert_embeddings/function.yaml"}}, "churn-server": {"description": "churn classification and predictor", "categories": ["serving", "ml"], "kind": "serving", "docfile": "churn_server/churn_server.ipynb", "versions": {"latest": "churn_server/function.yaml"}}, "concept-drift": {"description": "Deploy a streaming Concept Drift detector on a labeled stream", "categories": ["ml", "serve"], "kind": "job", "docfile": "concept_drift/concept_drift.ipynb", "versions": {"latest": "concept_drift/function.yaml"}}, "concept-drift-streaming": {"description": "Deploy a streaming Concept Drift detector on a labeled stream. the nuclio part of the concept_drift function", "categories": ["ml", "serve"], "kind": "remote", "docfile": "concept_drift_streaming/concept_drift_streaming.ipynb", "versions": {"latest": "concept_drift_streaming/function.yaml"}}, "coxph-test": {"description": "Test cox proportional hazards model", "categories": ["ml", "test"], "kind": "job", "docfile": "coxph_test/coxph_test.ipynb", "versions": {"latest": "coxph_test/function.yaml"}}, "coxph-trainer": {"description": "cox proportional hazards, kaplan meier plots", "categories": ["training", "ml"], "kind": "job", "docfile": "coxph_trainer/coxph_trainer.ipynb", "versions": {"latest": "coxph_trainer/function.yaml"}}, "describe": {"description": "describe and visualizes dataset stats", "categories": ["analysis"], "kind": "job", "docfile": "describe/describe.ipynb", "versions": {"latest": "describe/function.yaml"}}, "describe-dask": {"description": "describe and visualizes dataset stats", "categories": ["analysis"], "kind": "job", "docfile": "describe_dask/describe_dask.ipynb", "versions": {"latest": "describe_dask/function.yaml"}}, "describe-spark": {"description": "", "categories": [], "kind": "job", "docfile": "describe_spark/describe_spark.ipynb", "versions": {"latest": "describe_spark/function.yaml"}}, "feature-perms": {"description": "estimate feature importances using permutations", "categories": ["analysis"], "kind": "job", "docfile": "feature_perms/feature_perms.ipynb", "versions": {"latest": "feature_perms/function.yaml"}}, "feature-selection": {"description": "Select features through multiple Statistical and Model filters", "categories": ["data-prep", "ml"], "kind": "job", "docfile": "feature_selection/feature_selection.ipynb", "versions": {"latest": "feature_selection/function.yaml"}}, "gen-class-data": {"description": "Create a binary classification sample dataset and save.", "categories": ["data-prep"], "kind": "job", "docfile": "gen_class_data/gen_class_data.ipynb", "versions": {"latest": "gen_class_data/function.yaml"}}, "github-utils": {"description": "add comments to github pull request", "categories": ["notifications", "utils"], "kind": "job", "docfile": "github_utils/github_utils.ipynb", "versions": {"latest": "github_utils/function.yaml"}}, "load-dask": {"description": "load dask cluster with data", "categories": ["data-movement", "utils"], "kind": "dask", "docfile": "load_dask/load_dask.ipynb", "versions": {"latest": "load_dask/function.yaml"}}, "load-dataset": {"description": "load a toy dataset from scikit-learn", "categories": ["data-source", "ml"], "kind": "job", "docfile": "load_dataset/load_dataset.ipynb", "versions": {"latest": "load_dataset/function.yaml"}}, "model-monitoring-batch": {"description": "", "categories": [], "kind": "job", "docfile": "model_monitoring_batch/model_monitoring_batch.ipynb", "versions": {"latest": "model_monitoring_batch/function.yaml"}}, "model-monitoring-stream": {"description": "", "categories": [], "kind": "remote", "docfile": "model_monitoring_stream/model_monitoring_stream.ipynb", "versions": {"latest": "model_monitoring_stream/function.yaml"}}, "model-server": {"description": "generic sklearn model server", "categories": ["serving", "ml"], "kind": "remote", "docfile": "model_server/model_server.ipynb", "versions": {"latest": "model_server/function.yaml"}}, "model-server-tester": {"description": "test model servers", "categories": ["ml", "test"], "kind": "job", "docfile": "model_server_tester/model_server_tester.ipynb", "versions": {"latest": "model_server_tester/function.yaml"}}, "open-archive": {"description": "Open a file/object archive into a target directory", "categories": ["data-movement", "utils"], "kind": "job", "docfile": "open_archive/open_archive.ipynb", "versions": {"latest": "open_archive/function.yaml"}}, "pandas-profiling-report": {"description": "Create Pandas Profiling Report from Dataset", "categories": ["analysis"], "kind": "job", "docfile": "pandas_profiling_report/pandas_profiling_report.ipynb", "versions": {"latest": "pandas_profiling_report/function.yaml"}}, "project-runner": {"description": "Nuclio based - Cron scheduler for running your MLRun projects", "categories": ["utils"], "kind": "remote", "docfile": "project_runner/project_runner.ipynb", "versions": {"latest": "project_runner/function.yaml"}}, "rnn-serving": {"description": "deploy an rnn based stock analysis model server.", "categories": ["model-serving"], "kind": "serving", "docfile": "rnn_serving/rnn_serving.ipynb", "versions": {"latest": "rnn_serving/function.yaml"}}, "send-email": {"description": "Send Email messages through SMTP server", "categories": ["notifications"], "kind": "job", "docfile": "send_email/send_email.ipynb", "versions": {"latest": "send_email/function.yaml"}}, "sentiment-analysis-serving": {"description": "BERT based sentiment classification model", "categories": ["serving", "NLP", "BERT", "sentiment analysis"], "kind": "serving", "docfile": "sentiment_analysis_serving/sentiment_analysis_serving.ipynb", "versions": {"latest": "sentiment_analysis_serving/function.yaml"}}, "sklearn-classifier": {"description": "train any classifier using scikit-learn's API", "categories": ["ml", "training"], "kind": "job", "docfile": "sklearn_classifier/sklearn_classifier.ipynb", "versions": {"latest": "sklearn_classifier/function.yaml"}}, "sklearn-classifier-dask": {"description": "train any classifier using scikit-learn's API over Dask", "categories": ["ml", "training", "dask"], "kind": "job", "docfile": "sklearn_classifier_dask/sklearn_classifier_dask.ipynb", "versions": {"latest": "sklearn_classifier_dask/function.yaml"}}, "slack-notify": {"description": "Send Slack notification", "categories": ["ops"], "kind": "job", "docfile": "slack_notify/slack_notify.ipynb", "versions": {"latest": "slack_notify/function.yaml"}}, "spark-submit": {"description": "", "categories": [], "kind": "job", "docfile": "spark_submit/spark_submit.ipynb", "versions": {"latest": "spark_submit/function.yaml"}}, "sql-to-file": {"description": "SQL To File - Ingest data using SQL query", "categories": ["data-prep"], "kind": "job", "docfile": "sql_to_file/sql_to_file.ipynb", "versions": {"latest": "sql_to_file/function.yaml"}}, "stream-to-parquet": {"description": "Saves a stream to Parquet and can lunch drift detection task on it", "categories": ["ml", "serve"], "kind": "remote", "docfile": "stream_to_parquet/stream_to_parquet.ipynb", "versions": {"latest": "stream_to_parquet/function.yaml"}}, "test-classifier": {"description": "test a classifier using held-out or new data", "categories": ["ml", "test"], "kind": "job", "docfile": "test_classifier/test_classifier.ipynb", "versions": {"latest": "test_classifier/function.yaml"}}, "tf1-serving": {"description": "tf1 image classification server", "categories": ["serving", "dl"], "kind": "remote", "docfile": "tf1_serving/tf1_serving.ipynb", "versions": {"latest": "tf1_serving/function.yaml"}}, "tf2-serving": {"description": "tf2 image classification server", "categories": ["serving", "dl"], "kind": "remote", "docfile": "tf2_serving/tf2_serving.ipynb", "versions": {"latest": "tf2_serving/function.yaml"}}, "tf2-serving-v2": {"description": "tf2 image classification server v2", "categories": ["serving", "dl"], "kind": "serving", "docfile": "tf2_serving_v2/tf2_serving_v2.ipynb", "versions": {"latest": "tf2_serving_v2/function.yaml"}}, "v2-model-server": {"description": "generic sklearn model server", "categories": ["serving", "ml"], "kind": "serving", "docfile": "v2_model_server/v2_model_server.ipynb", "versions": {"latest": "v2_model_server/function.yaml"}}, "v2-model-tester": {"description": "test v2 model servers", "categories": ["ml", "test"], "kind": "job", "docfile": "v2_model_tester/v2_model_tester.ipynb", "versions": {"latest": "v2_model_tester/function.yaml"}}, "virtual-drift": {"description": "Compute drift magnitude between Time-Samples T and U", "categories": ["ml", "serve", "concept-drift"], "kind": "job", "docfile": "virtual_drift/virtual_drift.ipynb", "versions": {"latest": "virtual_drift/function.yaml"}}, "xgb-custom": {"description": "simulate data with outliers.", "categories": ["model-testing"], "kind": "job", "docfile": "xgb_custom/xgb_custom.ipynb", "versions": {"latest": "xgb_custom/function.yaml"}}, "xgb-serving": {"description": "deploy an XGBoost model server.", "categories": ["model-serving"], "kind": "remote", "docfile": "xgb_serving/xgb_serving.ipynb", "versions": {"latest": "xgb_serving/function.yaml"}}, "xgb-test": {"description": "Test one or more classifier models against held-out dataset.", "categories": ["model-test"], "kind": "job", "docfile": "xgb_test/xgb_test.ipynb", "versions": {"latest": "xgb_test/function.yaml"}}, "xgb-trainer": {"description": "train multiple model types using xgboost.", "categories": ["model-prep"], "kind": "job", "docfile": "xgb_trainer/xgb_trainer.ipynb", "versions": {"latest": "xgb_trainer/function.yaml"}}} \ No newline at end of file +{"aggregate": {"description": "Rolling aggregation over Metrics and Lables according to specifications", "categories": ["data-prep"], "kind": "job", "docfile": "aggregate/aggregate.ipynb", "versions": {"latest": "aggregate/function.yaml"}}, "arc-to-parquet": {"description": "retrieve remote archive, open and save as parquet", "categories": ["data-movement", "utils"], "kind": "job", "docfile": "arc_to_parquet/arc_to_parquet.ipynb", "versions": {"latest": "arc_to_parquet/function.yaml"}}, "bert-embeddings": {"description": "Get BERT based embeddings for given text", "categories": ["NLP", "BERT", "embeddings"], "kind": "remote", "docfile": "bert_embeddings/bert_embeddings.ipynb", "versions": {"latest": "bert_embeddings/function.yaml"}}, "churn-server": {"description": "churn classification and predictor", "categories": ["serving", "ml"], "kind": "serving", "docfile": "churn_server/churn_server.ipynb", "versions": {"latest": "churn_server/function.yaml"}}, "concept-drift": {"description": "Deploy a streaming Concept Drift detector on a labeled stream", "categories": ["ml", "serve"], "kind": "job", "docfile": "concept_drift/concept_drift.ipynb", "versions": {"latest": "concept_drift/function.yaml"}}, "concept-drift-streaming": {"description": "Deploy a streaming Concept Drift detector on a labeled stream. the nuclio part of the concept_drift function", "categories": ["ml", "serve"], "kind": "remote", "docfile": "concept_drift_streaming/concept_drift_streaming.ipynb", "versions": {"latest": "concept_drift_streaming/function.yaml"}}, "coxph-test": {"description": "Test cox proportional hazards model", "categories": ["ml", "test"], "kind": "job", "docfile": "coxph_test/coxph_test.ipynb", "versions": {"latest": "coxph_test/function.yaml"}}, "coxph-trainer": {"description": "cox proportional hazards, kaplan meier plots", "categories": ["training", "ml"], "kind": "job", "docfile": "coxph_trainer/coxph_trainer.ipynb", "versions": {"latest": "coxph_trainer/function.yaml"}}, "describe": {"description": "describe and visualizes dataset stats", "categories": ["analysis"], "kind": "job", "docfile": "describe/describe.ipynb", "versions": {"latest": "describe/function.yaml"}}, "describe-dask": {"description": "describe and visualizes dataset stats", "categories": ["analysis"], "kind": "job", "docfile": "describe_dask/describe_dask.ipynb", "versions": {"latest": "describe_dask/function.yaml"}}, "describe-spark": {"description": "", "categories": [], "kind": "job", "docfile": "describe_spark/describe_spark.ipynb", "versions": {"latest": "describe_spark/function.yaml"}}, "feature-perms": {"description": "estimate feature importances using permutations", "categories": ["analysis"], "kind": "job", "docfile": "feature_perms/feature_perms.ipynb", "versions": {"latest": "feature_perms/function.yaml"}}, "feature-selection": {"description": "Select features through multiple Statistical and Model filters", "categories": ["data-prep", "ml"], "kind": "job", "docfile": "feature_selection/feature_selection.ipynb", "versions": {"latest": "feature_selection/function.yaml"}}, "gen-class-data": {"description": "Create a binary classification sample dataset and save.", "categories": ["data-prep"], "kind": "job", "docfile": "gen_class_data/gen_class_data.ipynb", "versions": {"latest": "gen_class_data/function.yaml"}}, "github-utils": {"description": "add comments to github pull request", "categories": ["notifications", "utils"], "kind": "job", "docfile": "github_utils/github_utils.ipynb", "versions": {"latest": "github_utils/function.yaml"}}, "load-dataset": {"description": "load a toy dataset from scikit-learn", "categories": ["data-source", "ml"], "kind": "job", "docfile": "load_dataset/load_dataset.ipynb", "versions": {"latest": "load_dataset/function.yaml"}}, "model-monitoring-batch": {"description": "", "categories": [], "kind": "job", "docfile": "model_monitoring_batch/model_monitoring_batch.ipynb", "versions": {"latest": "model_monitoring_batch/function.yaml"}}, "model-monitoring-stream": {"description": "", "categories": [], "kind": "remote", "docfile": "model_monitoring_stream/model_monitoring_stream.ipynb", "versions": {"latest": "model_monitoring_stream/function.yaml"}}, "model-server": {"description": "generic sklearn model server", "categories": ["serving", "ml"], "kind": "remote", "docfile": "model_server/model_server.ipynb", "versions": {"latest": "model_server/function.yaml"}}, "model-server-tester": {"description": "test model servers", "categories": ["ml", "test"], "kind": "job", "docfile": "model_server_tester/model_server_tester.ipynb", "versions": {"latest": "model_server_tester/function.yaml"}}, "open-archive": {"description": "Open a file/object archive into a target directory", "categories": ["data-movement", "utils"], "kind": "job", "docfile": "open_archive/open_archive.ipynb", "versions": {"latest": "open_archive/function.yaml"}}, "pandas-profiling-report": {"description": "Create Pandas Profiling Report from Dataset", "categories": ["analysis"], "kind": "job", "docfile": "pandas_profiling_report/pandas_profiling_report.ipynb", "versions": {"latest": "pandas_profiling_report/function.yaml"}}, "project-runner": {"description": "Nuclio based - Cron scheduler for running your MLRun projects", "categories": ["utils"], "kind": "remote", "docfile": "project_runner/project_runner.ipynb", "versions": {"latest": "project_runner/function.yaml"}}, "rnn-serving": {"description": "deploy an rnn based stock analysis model server.", "categories": ["model-serving"], "kind": "serving", "docfile": "rnn_serving/rnn_serving.ipynb", "versions": {"latest": "rnn_serving/function.yaml"}}, "send-email": {"description": "Send Email messages through SMTP server", "categories": ["notifications"], "kind": "job", "docfile": "send_email/send_email.ipynb", "versions": {"latest": "send_email/function.yaml"}}, "sentiment-analysis-serving": {"description": "BERT based sentiment classification model", "categories": ["serving", "NLP", "BERT", "sentiment analysis"], "kind": "serving", "docfile": "sentiment_analysis_serving/sentiment_analysis_serving.ipynb", "versions": {"latest": "sentiment_analysis_serving/function.yaml"}}, "sklearn-classifier": {"description": "train any classifier using scikit-learn's API", "categories": ["ml", "training"], "kind": "job", "docfile": "sklearn_classifier/sklearn_classifier.ipynb", "versions": {"latest": "sklearn_classifier/function.yaml"}}, "sklearn-classifier-dask": {"description": "train any classifier using scikit-learn's API over Dask", "categories": ["ml", "training", "dask"], "kind": "job", "docfile": "sklearn_classifier_dask/sklearn_classifier_dask.ipynb", "versions": {"latest": "sklearn_classifier_dask/function.yaml"}}, "slack-notify": {"description": "Send Slack notification", "categories": ["ops"], "kind": "job", "docfile": "slack_notify/slack_notify.ipynb", "versions": {"latest": "slack_notify/function.yaml"}}, "spark-submit": {"description": "", "categories": [], "kind": "job", "docfile": "spark_submit/spark_submit.ipynb", "versions": {"latest": "spark_submit/function.yaml"}}, "sql-to-file": {"description": "SQL To File - Ingest data using SQL query", "categories": ["data-prep"], "kind": "job", "docfile": "sql_to_file/sql_to_file.ipynb", "versions": {"latest": "sql_to_file/function.yaml"}}, "stream-to-parquet": {"description": "Saves a stream to Parquet and can lunch drift detection task on it", "categories": ["ml", "serve"], "kind": "remote", "docfile": "stream_to_parquet/stream_to_parquet.ipynb", "versions": {"latest": "stream_to_parquet/function.yaml"}}, "test-classifier": {"description": "test a classifier using held-out or new data", "categories": ["ml", "test"], "kind": "job", "docfile": "test_classifier/test_classifier.ipynb", "versions": {"latest": "test_classifier/function.yaml"}}, "tf1-serving": {"description": "tf1 image classification server", "categories": ["serving", "dl"], "kind": "remote", "docfile": "tf1_serving/tf1_serving.ipynb", "versions": {"latest": "tf1_serving/function.yaml"}}, "tf2-serving": {"description": "tf2 image classification server", "categories": ["serving", "dl"], "kind": "remote", "docfile": "tf2_serving/tf2_serving.ipynb", "versions": {"latest": "tf2_serving/function.yaml"}}, "tf2-serving-v2": {"description": "tf2 image classification server v2", "categories": ["serving", "dl"], "kind": "serving", "docfile": "tf2_serving_v2/tf2_serving_v2.ipynb", "versions": {"latest": "tf2_serving_v2/function.yaml"}}, "v2-model-server": {"description": "generic sklearn model server", "categories": ["serving", "ml"], "kind": "serving", "docfile": "v2_model_server/v2_model_server.ipynb", "versions": {"latest": "v2_model_server/function.yaml"}}, "v2-model-tester": {"description": "test v2 model servers", "categories": ["ml", "test"], "kind": "job", "docfile": "v2_model_tester/v2_model_tester.ipynb", "versions": {"latest": "v2_model_tester/function.yaml"}}, "virtual-drift": {"description": "Compute drift magnitude between Time-Samples T and U", "categories": ["ml", "serve", "concept-drift"], "kind": "job", "docfile": "virtual_drift/virtual_drift.ipynb", "versions": {"latest": "virtual_drift/function.yaml"}}, "xgb-custom": {"description": "simulate data with outliers.", "categories": ["model-testing"], "kind": "job", "docfile": "xgb_custom/xgb_custom.ipynb", "versions": {"latest": "xgb_custom/function.yaml"}}, "xgb-serving": {"description": "deploy an XGBoost model server.", "categories": ["model-serving"], "kind": "remote", "docfile": "xgb_serving/xgb_serving.ipynb", "versions": {"latest": "xgb_serving/function.yaml"}}, "xgb-test": {"description": "Test one or more classifier models against held-out dataset.", "categories": ["model-test"], "kind": "job", "docfile": "xgb_test/xgb_test.ipynb", "versions": {"latest": "xgb_test/function.yaml"}}, "xgb-trainer": {"description": "train multiple model types using xgboost.", "categories": ["model-prep"], "kind": "job", "docfile": "xgb_trainer/xgb_trainer.ipynb", "versions": {"latest": "xgb_trainer/function.yaml"}}} \ No newline at end of file diff --git a/catalog.yaml b/catalog.yaml index 2b9d7c6b0..c3364fefa 100644 --- a/catalog.yaml +++ b/catalog.yaml @@ -128,15 +128,6 @@ github-utils: kind: job versions: latest: github_utils/function.yaml -load-dask: - categories: - - data-movement - - utils - description: load dask cluster with data - docfile: load_dask/load_dask.ipynb - kind: dask - versions: - latest: load_dask/function.yaml load-dataset: categories: - data-source diff --git a/concept_drift/README.md b/concept_drift/README.md deleted file mode 100644 index 92e6d893e..000000000 --- a/concept_drift/README.md +++ /dev/null @@ -1,132 +0,0 @@ -# Concept Drift - -**Concept drift** is a change in the statistical properties of the **target variable** over time. - -When deploying our models to production, we must ensure our models perform as we expect them to - reaching the same level of performence we have seen on our test sets or at least performing in the same quality as when they were deployed. - -However, often this is not the case. there are many factors that can affect our model's performance like seasonality or any unkown root causes that will change the laws underlying our data and invalidate some assumptions made by the model. - -We offer this function to help combat Concept Drift with implementation of streaming DDM, EDDM and PH concept drift detectors. - -## How to integrate - -This function is made of two parts: - -1. Kubernetes job to instantiate the selected models with a provided base dataset (the test dataset could be used) -2. [Nuclio serverless function](../concept_drift_streaming/concept_drift_streaming.ipynb) listed on a _labeled stream_, which will be deployed from this function after the models initialization and run the models per event and provide necessary alerts. - -There are two steps to integrate sucessfully with your workflow: - -1. Provide a stream where each event containes the joined **label** and **prediction** for that specific event. -2. Add this function to the workflow with the following params: - -```markdown -:param context: MLRun context -:param base_dataset: Dataset containing label_col and prediction_col to initialize the detectors -:param input_stream: labeled stream to track. - Should contain label_col and prediction_col -:param output_stream: Output stream to push the detector's alerts -:param output_tsdb: Output TSDB table to allow analysis and display -:param tsdb_batch_size: Batch size of alerts to buffer before pushing to the TSDB -:param callbacks: Additional rest endpoints to send the alert data to -:param models: List of the detectors to deploy - Defaults to ['ddm', 'eddm', 'pagehinkley']. -:param models_dest: Location for saving the detectors - Defaults to 'models' (in relation to artifact_path). -:param pagehinkley_threshold: Drift level threshold for PH detector Defaults to 10. -:param ddm_warning_level: Warning level alert for DDM detector Defaults to 2. -:param ddm_out_control_level: Drift level alert for DDM detector Defaults to 3. -:param label_col: Label column to be used on base_dataset and input_stream - Defaults to 'label'. -:param prediction_col: Prediction column to be used on base_dataset and input_stream - Defaults to 'prediction'. -:param hub_url: hub_url in case the default is not used, concept_drift_streaming will be loaded - by this url - Defaults to mlconf.hub_url. -:param fn_tag: hub tag to use - Defaults to 'master' -``` - -## Algorithms - -We offer to deploy up to 3 concept drift streaming detectors - -### DDM - Drift Detection Method - -Models the **Number of errors** as a **binomial** variable. This enables us to confine the expected number of errors in a prediction stream window to within some standard deviation. - -- Good for **abrupt** drift changes - -
- -![$mu=np_t$](https://latex.codecogs.com/svg.latex?mu=np_t) - -![$\sigma=\sqrt{\frac{p_t(1-p_t)}{n}}$]() - -
- -**Alert** when: - -
- -![$p_t+\sigma_t\ge{p_{min}+3\sigma_{min}}$](https://latex.codecogs.com/svg.latex?p_t+\sigma_t\ge{p_{min}+3\sigma_{min}}) - -
- -### EDDM - Early Drift Detection Method - -Uses the distance between two consecutive errors. - -- works better for **gradual** drift changes. -- More sensitive then DDM for noise -- Requires Minimal number of errors to initialize the statistics. - -**Warning**: - -
- -![$\frac{p_t+2\sigma_t}{p_{max}+2\sigma_{max}}<0.95$](https://latex.codecogs.com/svg.latex?\frac{p_t+2\sigma_t}{p_{max}+2\sigma_{max}}<0.95) - -
- -**Alert**: - -
- -![$\frac{p_t+2\sigma_t}{p_{max}+2\sigma_{max}}<0.90$](https://latex.codecogs.com/svg.latex?\frac{p_t+2\sigma_t}{p_{max}+2\sigma_{max}}<0.90) - -
- -### PageHinkley Test: - -The PageHinkley test is a sequential analysis technique typically used for monitoring change detection. (The test was designed to detect change in avg. of a Gaussian signal). In this test we use: -x*1*, ..., x*n* - labeled dataset -δ - magnitude threshold -λ - detection threshold - -
- -![$\hat{x_T}=\frac{1}{T}\sum_{t=1}^{t}{x_t}$](https://latex.codecogs.com/svg.latex?\hat{x_T}=\frac{1}{T}\sum_{t=1}^{t}{x_t}) - -![$\sum_{t=1}^T{x_t-\hat{x_T}-\delta}$](https://latex.codecogs.com/svg.latex?U_T=\sum_{t=1}^T{x_t-\hat{x_T}-\delta}) - -![$m_T=min(U_t,t=1..T)$]() - -
- -**Alert**: - -
- -![$U_T-m_T>\lambda$](https://latex.codecogs.com/svg.latex?U_T-m_T>\lambda) - -
- -## Additional resources -[A Study on Change Detection Methods](https://pdfs.semanticscholar.org/bb6e/8a44c0efcd725aae1c0b1817561f6e278c2c.pdf), Raquel Sebasti˜ao1,2 and Jo˜ao Gama1,3, 1 LIAAD-INESC Porto L.A., University of Porto -Rua de Ceuta, 118 - 6, 4050-190 Porto, Portugal -2 Faculty of Science, University of Porto -3 Faculty of Economics, University of Porto -{raquel,jgama}@liaad.up.pt - -[MLOps Live #4 - How to Detect & Remediate Drift in Production with MLOps Automation](https://www.youtube.com/watch?v=66_Q7mJZOSc&t=1296s) diff --git a/concept_drift/concept_drift.ipynb b/concept_drift/concept_drift.ipynb deleted file mode 100644 index e9c063b66..000000000 --- a/concept_drift/concept_drift.ipynb +++ /dev/null @@ -1,793 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Concept Drift - Deployer\n", - "Deploy a streaming Concept Drift detector on a labeled stream. \n", - "It will initialize the selected drift detectors with the base_dataset's statistics and deploy the [concept_drift_streaming](https://github.com/mlrun/functions/blob/master/concept_drift_streaming/concept_drift_streaming.ipynb) function from the hub.
\n", - "adding [V3IOStreamTrigger](https://nuclio.io/docs/latest/reference/triggers/v3iostream/) in order to listen to the input_stream." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### **Steps**\n", - "\n", - "1. [Data exploration](#Data-exploration)\n", - "2. [Creating the input stream](#Creating-the-input-stream)\n", - "3. [Importing the function](#Importing-the-function)\n", - "4. [Running the function remotely](#Running-the-function-remotely)\n", - "5. [Testing the function](#Testing-the-function)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### **Data exploration**" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "In order to know about the performance of a drift detector by measuring the different detection metrics, we need to know beforehand where a real drift occurs.
\n", - "This is only possible with synthetic datasets.
The scikit-multiflow framework allows generating several kinds of synthetic data to simulate the occurrence of drifts.
\n", - "[Harvard dataverse](https://dataverse.harvard.edu) provides futher explanations on the [used dataset](https://dataverse.harvard.edu/dataset.xhtml?persistentId=doi:10.7910/DVN/5OWRGB) along with different kinds of drifted datasets.
\n", - "mixed_0101_abrupto has 4 concepts and 3 drifts at time steps 10000, 20000, and 30000.
\n", - "Our dataset will be train-test-splitted, the train part (first 5000 examples) is used to train the model (that is generated easly using [sklearn_classifer](https://github.com/mlrun/functions/blob/master/sklearn_classifier/sklearn_classifier.ipynb)).
\n", - "The test part (which is already predicted by the model) will be pushed to the input stream in order to detect drifts." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
X1X2X3X4class
00.01.00.4601010.5927441.0
11.01.00.5887880.5749840.0
20.00.00.4016410.6793251.0
31.01.00.3060760.1821080.0
40.00.00.9628470.5792451.0
\n", - "
" - ], - "text/plain": [ - " X1 X2 X3 X4 class\n", - "0 0.0 1.0 0.460101 0.592744 1.0\n", - "1 1.0 1.0 0.588788 0.574984 0.0\n", - "2 0.0 0.0 0.401641 0.679325 1.0\n", - "3 1.0 1.0 0.306076 0.182108 0.0\n", - "4 0.0 0.0 0.962847 0.579245 1.0" - ] - }, - "execution_count": 1, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import pandas as pd\n", - "data_path = 'https://s3.wasabisys.com/iguazio/data/function-marketplace-data/concept_drift/mixed_0101_abrupto.csv'\n", - "predicted_train_path = 'https://s3.wasabisys.com/iguazio/data/function-marketplace-data/concept_drift/predicted_abrupto_train.csv'\n", - "predicted_test_data_path = 'https://s3.wasabisys.com/iguazio/data/function-marketplace-data/concept_drift/predicted_abrupto_test.csv'\n", - "# You can find the model used here\n", - "models_path = 'https://s3.wasabisys.com/iguazio/models/function-marketplace-models/concept_drift/concept_drift_random_forest.pkl'\n", - "original_data = pd.read_csv(data_path)\n", - "original_data.head()" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
X1X2X3X4classpredicted_col
349950.00.00.0101060.6472690.01.0
349961.01.00.2936510.7372911.00.0
349970.00.00.8485460.5523370.01.0
349981.01.00.6147540.8598961.00.0
349991.00.00.2653060.8437160.01.0
\n", - "
" - ], - "text/plain": [ - " X1 X2 X3 X4 class predicted_col\n", - "34995 0.0 0.0 0.010106 0.647269 0.0 1.0\n", - "34996 1.0 1.0 0.293651 0.737291 1.0 0.0\n", - "34997 0.0 0.0 0.848546 0.552337 0.0 1.0\n", - "34998 1.0 1.0 0.614754 0.859896 1.0 0.0\n", - "34999 1.0 0.0 0.265306 0.843716 0.0 1.0" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "predicted_test = pd.read_csv(predicted_test_data_path)\n", - "predicted_test.tail()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### **Creating the input stream**" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "import os \n", - "\n", - "container = os.path.join('/',os.environ['V3IO_HOME'].split('/')[0])\n", - "user = os.environ[\"V3IO_USERNAME\"]\n", - "rel_path = os.getcwd()[6:] + '/artifacts'\n", - "\n", - "base_input_stream = os.path.join(user,rel_path) + \"/inputs_stream\"\n", - "base_output_stream = os.path.join(user,rel_path) + \"/output_stream\"\n", - "input_stream = os.path.join(container,base_input_stream)\n", - "output_stream = os.path.join(container,user,rel_path) + \"/output_stream\"\n", - "tsdb_path = os.path.join(container,user,rel_path) + \"/output_tsdb\"\n", - "\n", - "stream_consumer_group = 'cg45'" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "import v3io.dataplane\n", - "\n", - "client = v3io.dataplane.Client()\n", - "response = client.stream.create(container = container,\n", - " stream_path=base_input_stream,\n", - " shard_count=1,\n", - " raise_for_status = v3io.dataplane.RaiseForStatus.never)\n", - "response.raise_for_status([409, 204])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### **Importing the function**" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "> 2021-10-25 10:27:04,105 [info] created and saved project function-marketplace\n" - ] - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Importing the function\n", - "import mlrun\n", - "mlrun.set_environment(project='function-marketplace')\n", - "\n", - "fn = mlrun.import_function(\"hub://concept_drift:development\")\n", - "fn.apply(mlrun.auto_mount())" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### **Running the function remotely**" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "> 2021-10-25 10:27:04,567 [info] starting run concept_drift uid=fa07c222e77d4eac86d2ce9317aaded1 DB=http://mlrun-api:8080\n", - "> 2021-10-25 10:27:04,709 [info] Job is running in the background, pod: concept-drift-ggxgb\n", - "> 2021-10-25 10:27:11,199 [info] Loading base dataset\n", - "> 2021-10-25 10:27:13,227 [info] Creating models\n", - "> 2021-10-25 10:27:13,227 [info] Streaming data to models\n", - "> 2021-10-25 10:27:13,347 [info] Logging ready models\n", - "> 2021-10-25 10:27:13,487 [info] Deploying Concept Drift Streaming function\n", - "> 2021-10-25 10:27:13,490 [info] Starting remote function deploy\n", - "2021-10-25 10:27:13 (info) Deploying function\n", - "2021-10-25 10:27:13 (info) Building\n", - "2021-10-25 10:27:13 (info) Staging files and preparing base images\n", - "2021-10-25 10:27:13 (info) Building processor image\n", - "2021-10-25 10:27:15 (info) Build complete\n", - "2021-10-25 10:27:21 (info) Function deploy complete\n", - "> 2021-10-25 10:27:21,797 [info] successfully deployed function: {'internal_invocation_urls': ['nuclio-function-marketplace-concept-drift-streaming.default-tenant.svc.cluster.local:8080'], 'external_invocation_urls': ['default-tenant.app.dev39.lab.iguazeng.com:31143']}\n", - "> 2021-10-25 10:27:21,868 [info] run executed, status=completed\n", - "final state: completed\n" - ] - }, - { - "data": { - "text/html": [ - "\n", - "
\n", - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
projectuiditerstartstatenamelabelsinputsparametersresultsartifacts
function-marketplace0Oct 25 10:27:10completedconcept_drift
v3io_user=dani
kind=job
owner=dani
host=concept-drift-ggxgb
base_dataset
input_stream=/users/dani/test/functions/concept_drift/artifacts/inputs_stream
consumer_group=cg45
output_stream=/users/dani/test/functions/concept_drift/artifacts/output_stream
output_tsdb=/users/dani/test/functions/concept_drift/artifacts/output_tsdb
tsdb_batch_size=1
models=['ddm', 'eddm', 'pagehinkley']
label_col=class
prediction_col=predicted_col
fn_tag=development
eddm_concept_drift
pagehinkley_concept_drift
ddm_concept_drift
\n", - "
\n", - "
\n", - "
\n", - " Title\n", - " ×\n", - "
\n", - " \n", - "
\n", - "
\n" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n" - ] - }, - { - "data": { - "text/html": [ - " > to track results use the .show() or .logs() methods or click here to open in UI" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "> 2021-10-25 10:27:23,031 [info] run executed, status=completed\n" - ] - } - ], - "source": [ - "drift_run = fn.run(name='concept_drift',\n", - " params={'input_stream' : input_stream,\n", - " 'consumer_group' : stream_consumer_group,\n", - " 'output_stream' : output_stream,\n", - " 'output_tsdb' : tsdb_path,\n", - " 'tsdb_batch_size' : 1,\n", - " 'models' : ['ddm', 'eddm', 'pagehinkley'], # defaults\n", - " 'label_col' : 'class',\n", - " 'prediction_col' : 'predicted_col',\n", - " 'fn_tag' : 'development'},\n", - " inputs={'base_dataset' : predicted_train_path},\n", - " artifact_path = os.path.join(os.getcwd(), 'artifacts'))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### **Testing the function**\n", - "> Mark that we are testing the deployed function - concept_drift_streaming" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'data': '{\"class\": 1.0, \"request\": {\"instances\": [{\"X1\": 0.0, \"X2\": 0.0, \"X3\": 0.0634475073, \"X4\": 0.4136568818}]}, \"resp\": [1], \"when\": \"2021-10-25 10:27:23.152584\", \"model\": \"sklearn.ensemble.RandomForestClassifier\"}'}" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import json\n", - "import datetime\n", - "\n", - "# Reshaping the data to V3IOStream format.\n", - "def restructure_stream_event(context, event):\n", - " instances = [dict()]\n", - " for key in predicted_test.keys():\n", - " if key not in ['when', 'class', 'model', 'worker', 'hostname', 'predicted_col']:\n", - " instances[0].update({key: event.pop(key)})\n", - " event['request'] = {'instances': instances}\n", - " event['resp'] = [int(event.pop('predicted_col'))]\n", - " event['when'] = datetime.datetime.strftime(datetime.datetime.now(), format=\"%Y-%m-%d %H:%M:%S.%f\")\n", - " event['model'] = 'sklearn.ensemble.RandomForestClassifier'\n", - " return event\n", - " \n", - " \n", - "records = json.loads(predicted_test.to_json(orient='records'))\n", - "records = [{'data': json.dumps(restructure_stream_event(context, record))} for record in records]\n", - "\n", - "# showing first record\n", - "records[0]" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [], - "source": [ - "# Creating v3io client\n", - "v3io_client = v3io.dataplane.Client()\n", - "\n", - "# Pushing some undrifted data to the input stream\n", - "response = v3io_client.stream.put_records(container=container,\n", - " stream_path=base_input_stream, \n", - " records=records[4900:5100])" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'SequenceNumber': 200,\n", - " 'Data': 'eyJjbGFzcyI6IDAuMCwgInJlcXVlc3QiOiB7Imluc3RhbmNlcyI6IFt7IlgxIjogMC4wLCAiWDIiOiAwLjAsICJYMyI6IDAuMzMzMTYzNjk4OSwgIlg0IjogMC40MjE2NzY1Njg3fV19LCAicmVzcCI6IFsxXSwgIndoZW4iOiAiMjAyMS0xMC0yNSAxMDoyNzoyMy4yOTM3OTgiLCAibW9kZWwiOiAic2tsZWFybi5lbnNlbWJsZS5SYW5kb21Gb3Jlc3RDbGFzc2lmaWVyIn0=',\n", - " 'ArrivalTimeSec': 1635157644,\n", - " 'ArrivalTimeNSec': 395309631}" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Getting earliest location in the shard\n", - "location = json.loads(v3io_client.stream.seek(container=container,\n", - " stream_path=base_input_stream,\n", - " shard_id=0,\n", - " seek_type='EARLIEST').body)['Location']\n", - "# Getting records from input stream\n", - "response = v3io_client.stream.get_records(container=container,\n", - " stream_path=base_input_stream,\n", - " shard_id=0, location=location)\n", - "# Showing the last sequence that is written to the input stream\n", - "json.loads(response.body)['Records'][-1]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Make sure some time has passed - the function needs to be triggered by the input stream, then it'll write to the output stream" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [], - "source": [ - "# Getting earliest location in the shard\n", - "location = json.loads(v3io_client.stream.seek(container=container,\n", - " stream_path=base_output_stream,\n", - " shard_id=0,\n", - " seek_type='EARLIEST').body)['Location']\n", - "# Getting records from output stream\n", - "response = v3io_client.stream.get_records(container=container,\n", - " stream_path=base_output_stream,\n", - " shard_id=0, location=location)" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "sequence number : 106, data : {'class': 0.0, 'request': {'instances': [{'X1': 0.0, 'X2': 0.0, 'X3': 0.9628473804, 'X4': 0.5792453402}]}, 'resp': [1], 'when': '2021-10-25 10:27:23.291145', 'model': 'sklearn.ensemble.RandomForestClassifier', 'ddm_warning_zone': 0, 'ddm_drift': 1, 'eddm_warning_zone': 0, 'eddm_drift': 0}\n", - "sequence number : 122, data : {'class': 0.0, 'request': {'instances': [{'X1': 0.0, 'X2': 0.0, 'X3': 0.4969765505, 'X4': 0.9784738351}]}, 'resp': [1], 'when': '2021-10-25 10:27:23.291558', 'model': 'sklearn.ensemble.RandomForestClassifier', 'ddm_warning_zone': 0, 'ddm_drift': 0, 'eddm_warning_zone': 0, 'eddm_drift': 1}\n" - ] - } - ], - "source": [ - "# Showing changed detected\n", - "import base64\n", - "for instance in json.loads(response.body)['Records']:\n", - " seq = instance[\"SequenceNumber\"]\n", - " data = json.loads(base64.b64decode(instance['Data']))\n", - " if(data['ddm_drift']==1 or data['eddm_drift']==1):\n", - " print(f'sequence number : {seq}, data : {data}')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can see that the system detected a change in the 106 instance, which is 10006 instance in the real dataset -
\n", - "5000 first instances are for train, we started pushing data from the 4900 instance of the test dataset (9900 from the real dataset), and we pushed only 200 instances.\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "[Back to the top](#Concept-Drift---Deployer)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python [conda env:root] *", - "language": "python", - "name": "conda-root-py" - }, - "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.7.6" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/concept_drift/concept_drift.py b/concept_drift/concept_drift.py deleted file mode 100644 index 03355d3b5..000000000 --- a/concept_drift/concept_drift.py +++ /dev/null @@ -1,147 +0,0 @@ -# Copyright 2019 Iguazio -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# Generated by nuclio.export.NuclioExporter - -import skmultiflow.drift_detection # We will grab our PH, DDM, EDDM algorithms from here -import numpy as np -import pandas as pd -import os -from cloudpickle import dumps, load, dump - -from nuclio.triggers import V3IOStreamTrigger -from mlrun import DataItem, import_function, mlconf, MLClientCtx, mount_v3io - -import random - - -def concept_drift_deployer( - context: MLClientCtx, - base_dataset: DataItem, - input_stream: str, - consumer_group: str, - output_stream: str, - output_tsdb: str, - tsdb_batch_size: int, - callbacks: list, - models: list = ["ddm", "eddm", "pagehinkley"], - models_dest="models", - pagehinkley_threshold: float = 10, - ddm_warning_level: float = 2, - ddm_out_control_level: float = 3, - label_col="label", - prediction_col="prediction", - hub_url: str = mlconf.hub_url, - fn_tag: str = "master", -): - """Deploy a streaming Concept Drift detector on a labeled stream - This function is the Deployment step for the Streaming Concept Drift Detector. - It will load the selected drift detectors and initialize them with the - base_dataset's statistics. Then it will deploy the concept_drift_streaming - function and pass the models to it for streaming concept-drift detection on top - of a labeled stream. - - :param context: MLRun context - :param base_dataset: Dataset containing label_col and prediction_col to initialize the detectors - :param input_stream: labeled stream to track. - Should contain label_col and prediction_col - :param output_stream: Output stream to push the detector's alerts - :param output_tsdb: Output TSDB table to allow analysis and display - :param tsdb_batch_size: Batch size of alerts to buffer before pushing to the TSDB - :param callbacks: Additional rest endpoints to send the alert data to - :param models: List of the detectors to deploy - Defaults to ['ddm', 'eddm', 'pagehinkley']. - :param models_dest: Location for saving the detectors - Defaults to 'models' (in relation to artifact_path). - :param pagehinkley_threshold: Drift level threshold for PH detector Defaults to 10. - :param ddm_warning_level: Warning level alert for DDM detector Defaults to 2. - :param ddm_out_control_level: Drift level alert for DDM detector Defaults to 3. - :param label_col: Label column to be used on base_dataset and input_stream - Defaults to 'label'. - :param prediction_col: Prediction column to be used on base_dataset and input_stream - Defaults to 'prediction'. - :param hub_url: hub_url in case the default is not used, concept_drift_streaming will be loaded - by this url - Defaults to mlconf.hub_url. - :param fn_tag: hub tag to use - Defaults to 'master' - """ - - mlconf.dbpath = mlconf.dbpath or "http://mlrun-api:8080" - mlconf.hub_url = hub_url - fn = import_function(url=f"hub://concept_drift_streaming:{fn_tag}") - - context.logger.info("Loading base dataset") - base_df = base_dataset.as_df() - error_stream = np.where( - base_df[prediction_col].values == base_df[label_col].values, 0, 1 - ) - - context.logger.info("Creating models") - models = [ - model.strip() - for model in os.getenv("models", "pagehinkley, ddm, eddm").split(",") - ] - models = { - "eddm": skmultiflow.drift_detection.EDDM(), - "pagehinkley": skmultiflow.drift_detection.PageHinkley( - min_instances=len(error_stream), threshold=pagehinkley_threshold - ), - "ddm": skmultiflow.drift_detection.DDM( - min_num_instances=len(error_stream), - warning_level=ddm_warning_level, - out_control_level=ddm_out_control_level, - ), - } - - context.logger.info("Streaming data to models") - for i in range(len(error_stream)): - for model_name, model in models.items(): - model.add_element(error_stream[i]) - - context.logger.info("Logging ready models") - for name, model in models.items(): - data = dumps(model) - model_file = f"{name}.pkl" - context.log_model( - f"{name}_concept_drift", - body=data, - labels={"framework": "skmultiflow", "workflow": "concept-drift"}, - model_file=model_file, - model_dir=models_dest, - tag="latest", - ) - fn.set_envs( - { - f"{name}_model_path": os.path.join( - context.artifact_path, models_dest, model_file - ) - } - ) - - context.logger.info("Deploying Concept Drift Streaming function") - fn.set_envs( - { - "label_col": label_col, - "prediction_col": prediction_col, - "drift_stream": output_stream, - "tsdb_table": output_tsdb, - "pagehinkley_threshold": pagehinkley_threshold, - "ddm_warning_level": ddm_warning_level, - "ddm_out_control": ddm_out_control_level, - } - ) - fn.add_v3io_stream_trigger(stream_path = input_stream, name = 'stream', group = consumer_group) - fn.apply(mount_v3io()) - fn.deploy(project=context.project) diff --git a/concept_drift/function.yaml b/concept_drift/function.yaml deleted file mode 100644 index 071111c78..000000000 --- a/concept_drift/function.yaml +++ /dev/null @@ -1,112 +0,0 @@ -kind: job -metadata: - name: concept-drift - tag: '' - hash: 935da41196802875e19948974f32b6f00c29feb2 - project: '' - labels: - author: orz - framework: sklearn - categories: - - machine-learning - - model-serving -spec: - command: '' - args: [] - image: mlrun/ml-models - env: [] - default_handler: concept_drift_deployer - entry_points: - concept_drift_deployer: - name: concept_drift_deployer - doc: "Deploy a streaming Concept Drift detector on a labeled stream\n This\ - \ function is the Deployment step for the Streaming Concept Drift Detector.\n\ - \ It will load the selected drift detectors and initialize them with the\n\ - \ base_dataset's statistics. Then it will deploy the concept_drift_streaming\n\ - \ function and pass the models to it for streaming concept-drift detection\ - \ on top\n of a labeled stream." - parameters: - - name: context - type: MLClientCtx - doc: MLRun context - default: '' - - name: base_dataset - type: DataItem - doc: Dataset containing label_col and prediction_col to initialize the detectors - default: '' - - name: input_stream - type: str - doc: labeled stream to track. Should contain label_col and prediction_col - default: '' - - name: consumer_group - type: str - default: '' - - name: output_stream - type: str - doc: Output stream to push the detector's alerts - default: '' - - name: output_tsdb - type: str - doc: Output TSDB table to allow analysis and display - default: '' - - name: tsdb_batch_size - type: int - doc: Batch size of alerts to buffer before pushing to the TSDB - default: '' - - name: callbacks - type: list - doc: Additional rest endpoints to send the alert data to - default: '' - - name: models - type: list - doc: List of the detectors to deploy Defaults to ['ddm', 'eddm', 'pagehinkley']. - default: - - ddm - - eddm - - pagehinkley - - name: models_dest - doc: Location for saving the detectors Defaults to 'models' (in relation to - artifact_path). - default: models - - name: pagehinkley_threshold - type: float - doc: Drift level threshold for PH detector Defaults to 10. - default: 10 - - name: ddm_warning_level - type: float - doc: Warning level alert for DDM detector Defaults to 2. - default: 2 - - name: ddm_out_control_level - type: float - doc: Drift level alert for DDM detector Defaults to 3. - default: 3 - - name: label_col - doc: Label column to be used on base_dataset and input_stream Defaults to - 'label'. - default: label - - name: prediction_col - doc: Prediction column to be used on base_dataset and input_stream Defaults - to 'prediction'. - default: prediction - - name: hub_url - type: str - doc: hub_url in case the default is not used, concept_drift_streaming will - be loaded by this url Defaults to mlconf.hub_url. - default: <_ast.Name object at 0x7f48eda946d0> - - name: fn_tag - type: str - doc: hub tag to use Defaults to 'master' - default: master - outputs: - - default: '' - lineno: 15 - description: Deploy a streaming Concept Drift detector on a labeled stream - build: - functionSourceCode: IyBHZW5lcmF0ZWQgYnkgbnVjbGlvLmV4cG9ydC5OdWNsaW9FeHBvcnRlcgoKaW1wb3J0IHNrbXVsdGlmbG93LmRyaWZ0X2RldGVjdGlvbiAgIyBXZSB3aWxsIGdyYWIgb3VyIFBILCBERE0sIEVERE0gYWxnb3JpdGhtcyBmcm9tIGhlcmUKaW1wb3J0IG51bXB5IGFzIG5wCmltcG9ydCBwYW5kYXMgYXMgcGQKaW1wb3J0IG9zCmZyb20gY2xvdWRwaWNrbGUgaW1wb3J0IGR1bXBzLCBsb2FkLCBkdW1wCgpmcm9tIG51Y2xpby50cmlnZ2VycyBpbXBvcnQgVjNJT1N0cmVhbVRyaWdnZXIKZnJvbSBtbHJ1biBpbXBvcnQgRGF0YUl0ZW0sIGltcG9ydF9mdW5jdGlvbiwgbWxjb25mLCBNTENsaWVudEN0eCwgbW91bnRfdjNpbwoKaW1wb3J0IHJhbmRvbQoKCmRlZiBjb25jZXB0X2RyaWZ0X2RlcGxveWVyKAogICAgY29udGV4dDogTUxDbGllbnRDdHgsCiAgICBiYXNlX2RhdGFzZXQ6IERhdGFJdGVtLAogICAgaW5wdXRfc3RyZWFtOiBzdHIsCiAgICBjb25zdW1lcl9ncm91cDogc3RyLAogICAgb3V0cHV0X3N0cmVhbTogc3RyLAogICAgb3V0cHV0X3RzZGI6IHN0ciwKICAgIHRzZGJfYmF0Y2hfc2l6ZTogaW50LAogICAgY2FsbGJhY2tzOiBsaXN0LAogICAgbW9kZWxzOiBsaXN0ID0gWyJkZG0iLCAiZWRkbSIsICJwYWdlaGlua2xleSJdLAogICAgbW9kZWxzX2Rlc3Q9Im1vZGVscyIsCiAgICBwYWdlaGlua2xleV90aHJlc2hvbGQ6IGZsb2F0ID0gMTAsCiAgICBkZG1fd2FybmluZ19sZXZlbDogZmxvYXQgPSAyLAogICAgZGRtX291dF9jb250cm9sX2xldmVsOiBmbG9hdCA9IDMsCiAgICBsYWJlbF9jb2w9ImxhYmVsIiwKICAgIHByZWRpY3Rpb25fY29sPSJwcmVkaWN0aW9uIiwKICAgIGh1Yl91cmw6IHN0ciA9IG1sY29uZi5odWJfdXJsLAogICAgZm5fdGFnOiBzdHIgPSAibWFzdGVyIiwKKToKICAgICIiIkRlcGxveSBhIHN0cmVhbWluZyBDb25jZXB0IERyaWZ0IGRldGVjdG9yIG9uIGEgbGFiZWxlZCBzdHJlYW0KICAgICAgIFRoaXMgZnVuY3Rpb24gaXMgdGhlIERlcGxveW1lbnQgc3RlcCBmb3IgdGhlIFN0cmVhbWluZyBDb25jZXB0IERyaWZ0IERldGVjdG9yLgogICAgICAgSXQgd2lsbCBsb2FkIHRoZSBzZWxlY3RlZCBkcmlmdCBkZXRlY3RvcnMgYW5kIGluaXRpYWxpemUgdGhlbSB3aXRoIHRoZQogICAgICAgYmFzZV9kYXRhc2V0J3Mgc3RhdGlzdGljcy4gIFRoZW4gaXQgd2lsbCBkZXBsb3kgdGhlIGNvbmNlcHRfZHJpZnRfc3RyZWFtaW5nCiAgICAgICBmdW5jdGlvbiBhbmQgcGFzcyB0aGUgbW9kZWxzIHRvIGl0IGZvciBzdHJlYW1pbmcgY29uY2VwdC1kcmlmdCBkZXRlY3Rpb24gb24gdG9wCiAgICAgICBvZiBhIGxhYmVsZWQgc3RyZWFtLgoKICAgIDpwYXJhbSBjb250ZXh0OiAgICAgICAgIE1MUnVuIGNvbnRleHQKICAgIDpwYXJhbSBiYXNlX2RhdGFzZXQ6ICAgIERhdGFzZXQgY29udGFpbmluZyBsYWJlbF9jb2wgYW5kIHByZWRpY3Rpb25fY29sIHRvIGluaXRpYWxpemUgdGhlIGRldGVjdG9ycwogICAgOnBhcmFtIGlucHV0X3N0cmVhbTogICAgbGFiZWxlZCBzdHJlYW0gdG8gdHJhY2suCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBTaG91bGQgY29udGFpbiBsYWJlbF9jb2wgYW5kIHByZWRpY3Rpb25fY29sCiAgICA6cGFyYW0gb3V0cHV0X3N0cmVhbTogICBPdXRwdXQgc3RyZWFtIHRvIHB1c2ggdGhlIGRldGVjdG9yJ3MgYWxlcnRzCiAgICA6cGFyYW0gb3V0cHV0X3RzZGI6ICAgICBPdXRwdXQgVFNEQiB0YWJsZSB0byBhbGxvdyBhbmFseXNpcyBhbmQgZGlzcGxheQogICAgOnBhcmFtIHRzZGJfYmF0Y2hfc2l6ZTogQmF0Y2ggc2l6ZSBvZiBhbGVydHMgdG8gYnVmZmVyIGJlZm9yZSBwdXNoaW5nIHRvIHRoZSBUU0RCCiAgICA6cGFyYW0gY2FsbGJhY2tzOiAgICAgICBBZGRpdGlvbmFsIHJlc3QgZW5kcG9pbnRzIHRvIHNlbmQgdGhlIGFsZXJ0IGRhdGEgdG8KICAgIDpwYXJhbSBtb2RlbHM6ICAgICAgICAgIExpc3Qgb2YgdGhlIGRldGVjdG9ycyB0byBkZXBsb3kKICAgICAgICAgICAgICAgICAgICAgICAgICAgIERlZmF1bHRzIHRvIFsnZGRtJywgJ2VkZG0nLCAncGFnZWhpbmtsZXknXS4KICAgIDpwYXJhbSBtb2RlbHNfZGVzdDogICAgIExvY2F0aW9uIGZvciBzYXZpbmcgdGhlIGRldGVjdG9ycwogICAgICAgICAgICAgICAgICAgICAgICAgICAgRGVmYXVsdHMgdG8gJ21vZGVscycgKGluIHJlbGF0aW9uIHRvIGFydGlmYWN0X3BhdGgpLgogICAgOnBhcmFtIHBhZ2VoaW5rbGV5X3RocmVzaG9sZDogIERyaWZ0IGxldmVsIHRocmVzaG9sZCBmb3IgUEggZGV0ZWN0b3IgRGVmYXVsdHMgdG8gMTAuCiAgICA6cGFyYW0gZGRtX3dhcm5pbmdfbGV2ZWw6ICAgICAgV2FybmluZyBsZXZlbCBhbGVydCBmb3IgRERNIGRldGVjdG9yIERlZmF1bHRzIHRvIDIuCiAgICA6cGFyYW0gZGRtX291dF9jb250cm9sX2xldmVsOiAgRHJpZnQgbGV2ZWwgYWxlcnQgZm9yIERETSBkZXRlY3RvciBEZWZhdWx0cyB0byAzLgogICAgOnBhcmFtIGxhYmVsX2NvbDogICAgICAgTGFiZWwgY29sdW1uIHRvIGJlIHVzZWQgb24gYmFzZV9kYXRhc2V0IGFuZCBpbnB1dF9zdHJlYW0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIERlZmF1bHRzIHRvICdsYWJlbCcuCiAgICA6cGFyYW0gcHJlZGljdGlvbl9jb2w6ICBQcmVkaWN0aW9uIGNvbHVtbiB0byBiZSB1c2VkIG9uIGJhc2VfZGF0YXNldCBhbmQgaW5wdXRfc3RyZWFtCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBEZWZhdWx0cyB0byAncHJlZGljdGlvbicuCiAgICA6cGFyYW0gaHViX3VybDogICAgICAgICBodWJfdXJsIGluIGNhc2UgdGhlIGRlZmF1bHQgaXMgbm90IHVzZWQsIGNvbmNlcHRfZHJpZnRfc3RyZWFtaW5nIHdpbGwgYmUgbG9hZGVkCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBieSB0aGlzIHVybAogICAgICAgICAgICAgICAgICAgICAgICAgICAgRGVmYXVsdHMgdG8gbWxjb25mLmh1Yl91cmwuCiAgICA6cGFyYW0gZm5fdGFnOiAgICAgICAgICBodWIgdGFnIHRvIHVzZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgRGVmYXVsdHMgdG8gJ21hc3RlcicKICAgICIiIgoKICAgIG1sY29uZi5kYnBhdGggPSBtbGNvbmYuZGJwYXRoIG9yICJodHRwOi8vbWxydW4tYXBpOjgwODAiCiAgICBtbGNvbmYuaHViX3VybCA9IGh1Yl91cmwKICAgIGZuID0gaW1wb3J0X2Z1bmN0aW9uKHVybD1mImh1YjovL2NvbmNlcHRfZHJpZnRfc3RyZWFtaW5nOntmbl90YWd9IikKCiAgICBjb250ZXh0LmxvZ2dlci5pbmZvKCJMb2FkaW5nIGJhc2UgZGF0YXNldCIpCiAgICBiYXNlX2RmID0gYmFzZV9kYXRhc2V0LmFzX2RmKCkKICAgIGVycm9yX3N0cmVhbSA9IG5wLndoZXJlKAogICAgICAgIGJhc2VfZGZbcHJlZGljdGlvbl9jb2xdLnZhbHVlcyA9PSBiYXNlX2RmW2xhYmVsX2NvbF0udmFsdWVzLCAwLCAxCiAgICApCgogICAgY29udGV4dC5sb2dnZXIuaW5mbygiQ3JlYXRpbmcgbW9kZWxzIikKICAgIG1vZGVscyA9IFsKICAgICAgICBtb2RlbC5zdHJpcCgpCiAgICAgICAgZm9yIG1vZGVsIGluIG9zLmdldGVudigibW9kZWxzIiwgInBhZ2VoaW5rbGV5LCBkZG0sIGVkZG0iKS5zcGxpdCgiLCIpCiAgICBdCiAgICBtb2RlbHMgPSB7CiAgICAgICAgImVkZG0iOiBza211bHRpZmxvdy5kcmlmdF9kZXRlY3Rpb24uRURETSgpLAogICAgICAgICJwYWdlaGlua2xleSI6IHNrbXVsdGlmbG93LmRyaWZ0X2RldGVjdGlvbi5QYWdlSGlua2xleSgKICAgICAgICAgICAgbWluX2luc3RhbmNlcz1sZW4oZXJyb3Jfc3RyZWFtKSwgdGhyZXNob2xkPXBhZ2VoaW5rbGV5X3RocmVzaG9sZAogICAgICAgICksCiAgICAgICAgImRkbSI6IHNrbXVsdGlmbG93LmRyaWZ0X2RldGVjdGlvbi5ERE0oCiAgICAgICAgICAgIG1pbl9udW1faW5zdGFuY2VzPWxlbihlcnJvcl9zdHJlYW0pLAogICAgICAgICAgICB3YXJuaW5nX2xldmVsPWRkbV93YXJuaW5nX2xldmVsLAogICAgICAgICAgICBvdXRfY29udHJvbF9sZXZlbD1kZG1fb3V0X2NvbnRyb2xfbGV2ZWwsCiAgICAgICAgKSwKICAgIH0KCiAgICBjb250ZXh0LmxvZ2dlci5pbmZvKCJTdHJlYW1pbmcgZGF0YSB0byBtb2RlbHMiKQogICAgZm9yIGkgaW4gcmFuZ2UobGVuKGVycm9yX3N0cmVhbSkpOgogICAgICAgIGZvciBtb2RlbF9uYW1lLCBtb2RlbCBpbiBtb2RlbHMuaXRlbXMoKToKICAgICAgICAgICAgbW9kZWwuYWRkX2VsZW1lbnQoZXJyb3Jfc3RyZWFtW2ldKQoKICAgIGNvbnRleHQubG9nZ2VyLmluZm8oIkxvZ2dpbmcgcmVhZHkgbW9kZWxzIikKICAgIGZvciBuYW1lLCBtb2RlbCBpbiBtb2RlbHMuaXRlbXMoKToKICAgICAgICBkYXRhID0gZHVtcHMobW9kZWwpCiAgICAgICAgbW9kZWxfZmlsZSA9IGYie25hbWV9LnBrbCIKICAgICAgICBjb250ZXh0LmxvZ19tb2RlbCgKICAgICAgICAgICAgZiJ7bmFtZX1fY29uY2VwdF9kcmlmdCIsCiAgICAgICAgICAgIGJvZHk9ZGF0YSwKICAgICAgICAgICAgbGFiZWxzPXsiZnJhbWV3b3JrIjogInNrbXVsdGlmbG93IiwgIndvcmtmbG93IjogImNvbmNlcHQtZHJpZnQifSwKICAgICAgICAgICAgbW9kZWxfZmlsZT1tb2RlbF9maWxlLAogICAgICAgICAgICBtb2RlbF9kaXI9bW9kZWxzX2Rlc3QsCiAgICAgICAgICAgIHRhZz0ibGF0ZXN0IiwKICAgICAgICApCiAgICAgICAgZm4uc2V0X2VudnMoCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIGYie25hbWV9X21vZGVsX3BhdGgiOiBvcy5wYXRoLmpvaW4oCiAgICAgICAgICAgICAgICAgICAgY29udGV4dC5hcnRpZmFjdF9wYXRoLCBtb2RlbHNfZGVzdCwgbW9kZWxfZmlsZQogICAgICAgICAgICAgICAgKQogICAgICAgICAgICB9CiAgICAgICAgKQoKICAgIGNvbnRleHQubG9nZ2VyLmluZm8oIkRlcGxveWluZyBDb25jZXB0IERyaWZ0IFN0cmVhbWluZyBmdW5jdGlvbiIpCiAgICBmbi5zZXRfZW52cygKICAgICAgICB7CiAgICAgICAgICAgICJsYWJlbF9jb2wiOiBsYWJlbF9jb2wsCiAgICAgICAgICAgICJwcmVkaWN0aW9uX2NvbCI6IHByZWRpY3Rpb25fY29sLAogICAgICAgICAgICAiZHJpZnRfc3RyZWFtIjogb3V0cHV0X3N0cmVhbSwKICAgICAgICAgICAgInRzZGJfdGFibGUiOiBvdXRwdXRfdHNkYiwKICAgICAgICAgICAgInBhZ2VoaW5rbGV5X3RocmVzaG9sZCI6IHBhZ2VoaW5rbGV5X3RocmVzaG9sZCwKICAgICAgICAgICAgImRkbV93YXJuaW5nX2xldmVsIjogZGRtX3dhcm5pbmdfbGV2ZWwsCiAgICAgICAgICAgICJkZG1fb3V0X2NvbnRyb2wiOiBkZG1fb3V0X2NvbnRyb2xfbGV2ZWwsCiAgICAgICAgfQogICAgKQogICAgZm4uYWRkX3YzaW9fc3RyZWFtX3RyaWdnZXIoc3RyZWFtX3BhdGggPSBpbnB1dF9zdHJlYW0sIG5hbWUgPSAnc3RyZWFtJywgZ3JvdXAgPSBjb25zdW1lcl9ncm91cCkKICAgIGZuLmFwcGx5KG1vdW50X3YzaW8oKSkKICAgIGZuLmRlcGxveShwcm9qZWN0PWNvbnRleHQucHJvamVjdCkK - commands: - - python -m pip install scikit-multiflow - code_origin: https://github.com/daniels290813/functions.git#82bbfde4afa2eae77059e05c70bbebacf530fd0d:/User/test/functions/concept_drift/concept_drift.py - origin_filename: /User/test/functions/concept_drift/concept_drift.py - disable_auto_mount: false - affinity: null -verbose: false diff --git a/concept_drift/item.yaml b/concept_drift/item.yaml deleted file mode 100644 index 2ee37e386..000000000 --- a/concept_drift/item.yaml +++ /dev/null @@ -1,27 +0,0 @@ -apiVersion: v1 -categories: -- machine-learning -- model-serving -description: Deploy a streaming Concept Drift detector on a labeled stream -doc: '' -example: concept_drift.ipynb -generationDate: 2022-08-28:17-25 -hidden: false -icon: '' -labels: - author: orz - framework: sklearn -maintainers: [] -marketplaceType: '' -mlrunVersion: 1.1.0 -name: concept-drift -platformVersion: 3.5.0 -spec: - filename: concept_drift.py - handler: concept_drift_deployer - image: mlrun/ml-models - kind: job - requirements: - - scikit-multiflow -url: '' -version: 1.1.0 diff --git a/concept_drift/requirements.txt b/concept_drift/requirements.txt deleted file mode 100644 index fa0fddd88..000000000 --- a/concept_drift/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -skmultiflow \ No newline at end of file diff --git a/concept_drift_streaming/concept_drift_streaming.ipynb b/concept_drift_streaming/concept_drift_streaming.ipynb deleted file mode 100644 index b916cb7a2..000000000 --- a/concept_drift_streaming/concept_drift_streaming.ipynb +++ /dev/null @@ -1,480 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Concept Drift Streaming" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import nuclio" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "from pprint import pprint" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "%%nuclio cmd -c\n", - "python -m pip install scikit-multiflow==0.4.1\n", - "python -m pip install v3io_frames" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "%nuclio: setting kind to 'nuclio'\n", - "%nuclio: setting spec.build.baseImage to 'mlrun/ml-models'\n" - ] - } - ], - "source": [ - "# Define function spec\n", - "%nuclio config kind = \"nuclio\"\n", - "%nuclio config spec.build.baseImage = \"mlrun/ml-models\"\n", - "\n", - "# Add V3IO Mount\n", - "# %nuclio env %v3io" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "# nuclio: ignore\n", - "env = {'label_col': 'resp',\n", - " 'prediction_col': 'prediction',\n", - " 'drift_stream': '/bigdata/network-operations/drift_stream',\n", - " 'tsdb_table': 'network-operations/drift_tsdb',\n", - " 'pagehinkley_threshold': 10,\n", - " 'models': ['pagehinkley', 'ddm', 'eddm'],\n", - " 'window_size': 10}\n", - "config = {'kind': 'nuclio',\n", - " 'spec.build.baseImage': 'mlrun/ml-models'}\n", - "cmd = ['python -m pip install scikit-multiflow',\n", - " 'python -m pip install v3io_frames']\n", - "v3io = True\n", - "config = nuclio.ConfigSpec(env=env,\n", - " config=config,\n", - " cmd=cmd,\n", - " v3io=v3io)" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "# nuclio: start-code" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "import skmultiflow.drift_detection\n", - "import numpy as np\n", - "import pandas as pd\n", - "import os\n", - "import json\n", - "import v3io.dataplane\n", - "import v3io_frames as v3f\n", - "import requests\n", - "from cloudpickle import load\n", - "\n", - "# For testing\n", - "import random" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [], - "source": [ - "def split_path(mntpath=''):\n", - " if mntpath[0] == '/':\n", - " mntpath = mntpath[1:]\n", - " paths = mntpath.split('/')\n", - " container = paths[0]\n", - " subpath = ''\n", - " if len(paths) > 1:\n", - " subpath = mntpath[len(container):]\n", - " return container, subpath\n", - "\n", - "\n", - "def create_stream(context, path, shards=1):\n", - " # create a stream w/8 shards\n", - " container, stream_path = split_path(path)\n", - " context.logger.info(f'Creating stream in Container: {container} & Path {stream_path}')\n", - " response = context.v3io_client.create_stream(container=container,\n", - " path=stream_path, \n", - " shard_count=shards,\n", - " raise_for_status=v3io.dataplane.RaiseForStatus.never)\n", - " response.raise_for_status([409, 204])\n", - " \n", - " \n", - "def push_to_stream(context, stream_path, data):\n", - " records = [{'data': json.dumps(rec)} for rec in data]\n", - " container, stream_path = split_path(stream_path)\n", - " response = context.v3io_client.put_records(container=container,\n", - " path=stream_path, \n", - " records=records)\n", - "\n", - "\n", - "def construct_record(record):\n", - " label_col = os.getenv('label_col', 'label')\n", - " prediction_col = os.getenv('prediction_col', 'prediction')\n", - " res = dict([(k, record[k]) for k in ['when', 'class', 'model', 'resp', 'request']])\n", - " res['feature_vector'] = res.pop('request')['instances'][0]\n", - " res['timestamp'] = res.pop('when')\n", - " res['prediction'] = res['resp'][0]\n", - " return res" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [], - "source": [ - "def init_context(context):\n", - " # create a v3io context object\n", - " v3io_client = v3io.dataplane.Client()\n", - " setattr(context, \"v3io_client\", v3io_client)\n", - " \n", - " # Setup windowing for TSDB writer\n", - " v3f_client = v3f.Client('framesd:8081', container='bigdata')\n", - " setattr(context, \"v3f\", v3f_client)\n", - " window = []\n", - " setattr(context, 'window', window)\n", - " setattr(context, 'window_size', int(os.getenv('window_size', 10)))\n", - " setattr(context, 'tsdb_table', os.getenv('tsdb_table', 'concept_drift_tsdb_1'))\n", - " try:\n", - " context.v3f.create('tsdb', context.tsdb_table, rate='1/s', if_exists=1)\n", - " except Exception as e:\n", - " context.logger.info(f'Creating context with rate= faile for {e}')\n", - " context.v3f.create('tsdb', context.tsdb_table, attrs={'rate': '1/s'}, if_exists=1)\n", - " \n", - " # Setup callbacks\n", - " callbacks = [callback.strip() for callback in os.getenv('callbacks', '').split(',')]\n", - " setattr(context, 'callbacks', callbacks)\n", - " \n", - " # Setup drift stream\n", - " setattr(context, 'drift_stream', os.getenv('drift_stream', '/bigdata/drift_stream'))\n", - " try:\n", - " create_stream(context, context.drift_stream, int(os.getenv('drift_stream_shards', 1)))\n", - " except:\n", - " context.logger.info(f'{context.drift_stream} already exists')\n", - " \n", - " # Load models\n", - " models = {}\n", - " model_types = ['pagehinkely', 'ddm', 'eddm']\n", - " path_suffix = '_model_path'\n", - " for model in model_types:\n", - " model_env = f'{model}{path_suffix}'\n", - " if model_env in os.environ:\n", - " with open(os.environ[model_env], 'rb') as f:\n", - " models[model] = load(f)\n", - " setattr(context, 'models', models)\n", - " \n", - " # Columns to check\n", - " setattr(context, 'label_col', os.getenv('label_col', 'label'))\n", - " setattr(context, 'prediction_col', os.getenv('prediction_col', 'prediction'))" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [], - "source": [ - "def handler(context, event):\n", - " # Construct event\n", - " context.logger.info(f'event: {event.body}')\n", - " full_event = json.loads(event.body)\n", - " record = construct_record(full_event)\n", - " \n", - " # Is our prediction wrong?\n", - " is_error = record[context.label_col] != record[context.prediction_col]\n", - " context.logger.info(f'Adding {is_error}')\n", - " \n", - " # Process the {is_error} element with our algorithms\n", - " for name, model in context.models.items():\n", - " # Add element\n", - " results = {'timestamp': record['timestamp']}\n", - " results['algorithm'] = name\n", - " model.add_element(is_error)\n", - " \n", - " # Detect warning zone (if applicable to the algorithm)\n", - " if hasattr(model, 'detected_warning_zone') and model.detected_warning_zone():\n", - " context.logger.info(f'{name}\\tWarning zone detected')\n", - " results['warning_zone'] = 1\n", - " full_event[f'{name}_warning_zone'] = 1\n", - " else:\n", - " results['warning_zone'] = 0\n", - " full_event[f'{name}_warning_zone'] = 0\n", - " \n", - " # Detect drift\n", - " if model.detected_change():\n", - " context.logger.info('Change Detected')\n", - " results['change_detected'] = 1\n", - " full_event[f'{name}_drift'] = 1\n", - " else:\n", - " results['change_detected'] = 0\n", - " full_event[f'{name}_drift'] = 0\n", - " context.window.append(results)\n", - " \n", - " # Return results\n", - " # Write to stream\n", - " push_to_stream(context, context.drift_stream, [full_event])\n", - " \n", - " # Add to callbacks\n", - " if context.callbacks != ['']:\n", - " for callback in context.callbacks:\n", - " requests.post(url=callback,\n", - " json=full_event)\n", - " \n", - " if (len(context.window) / len(context.models)) >= context.window_size:\n", - " df = pd.DataFrame(context.window)\n", - " df['timestamp'] = pd.to_datetime(df['timestamp'])\n", - " df = df.set_index(['timestamp', 'algorithm'])\n", - " context.v3f.write('tsdb', context.tsdb_table, df)\n", - " context.window = []" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [], - "source": [ - "# nuclio: end-code" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Test " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "init_context(context)\n", - "event = nuclio.Event(body=json.dumps({'prediction': 0,\n", - " 'when': 'now',\n", - " 'class': 'ClassModel', \n", - " 'model': 'tester_v1', \n", - " 'resp': [0], \n", - " 'request': {'instances': [[1, 1.2, 3]]}}))\n", - "out = handler(context, event)\n", - "out" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Cluster" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "%nuclio deploy -n network-operations-concept-drift -p network-operations" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Save function yaml" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [], - "source": [ - "from os import path\n", - "from mlrun import run_local, NewTask, mlconf, import_function, mount_v3io, code_to_function, get_run_db\n", - "mlconf.dbpath = mlconf.dbpath or 'http://mlrun-api:8080'" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[mlrun] 2020-07-14 13:49:22,720 function spec saved to path: /User/functions/concept_drift_streaming/function.yaml\n" - ] - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# create job function object from notebook code\n", - "fn = code_to_function(\"concept_drift_streaming\", kind='nuclio')\n", - "\n", - "# add metadata (for templates and reuse)\n", - "fn.spec.default_handler = \"handler\"\n", - "fn.spec.description = \"Deploy a streaming Concept Drift detector on a labeled stream. the nuclio part of the concept_drift function\"\n", - "fn.metadata.categories = [\"ml\", \"serve\"]\n", - "fn.metadata.labels = {\"author\": \"orz\", \"framework\": \"sklearn\"}\n", - "fn.export(\"/User/functions/concept_drift_streaming/function.yaml\")" - ] - }, - { - "cell_type": "code", - "execution_count": 120, - "metadata": {}, - "outputs": [], - "source": [ - "stream_trigger = nuclio.triggers.V3IOStreamTrigger(url='/bigdata/network-operations/inference_stream@cd2')" - ] - }, - { - "cell_type": "code", - "execution_count": 121, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 121, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "fn.add_trigger('labeled_stream', stream_trigger)" - ] - }, - { - "cell_type": "code", - "execution_count": 122, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 122, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "fn.apply(mount_v3io()).with_v3io()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "fn.export(\"function.yaml\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Stream testing" - ] - }, - { - "cell_type": "code", - "execution_count": 40, - "metadata": {}, - "outputs": [], - "source": [ - "fn = import_function('./function.yaml')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "fn.deploy(project='network-operations')" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "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.6.8" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/concept_drift_streaming/concept_drift_streaming.py b/concept_drift_streaming/concept_drift_streaming.py deleted file mode 100644 index ebcbf8a1b..000000000 --- a/concept_drift_streaming/concept_drift_streaming.py +++ /dev/null @@ -1,157 +0,0 @@ -# Copyright 2019 Iguazio -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# Generated by nuclio.export.NuclioExporter - -import skmultiflow.drift_detection -import numpy as np -import pandas as pd -import os -import json -import v3io.dataplane -import v3io_frames as v3f -import requests -from cloudpickle import load - -import random - - -def split_path(mntpath=""): - if mntpath[0] == "/": - mntpath = mntpath[1:] - paths = mntpath.split("/") - container = paths[0] - subpath = "" - if len(paths) > 1: - subpath = mntpath[len(container) :] - return container, subpath - - -def create_stream(context, path, shards=1): - container, stream_path = split_path(path) - context.logger.info( - f"Creating stream in Container: {container} & Path {stream_path}" - ) - response = context.v3io_client.create_stream( - container=container, - path=stream_path, - shard_count=shards, - raise_for_status=v3io.dataplane.RaiseForStatus.never, - ) - response.raise_for_status([409, 204]) - - -def push_to_stream(context, stream_path, data): - records = [{"data": json.dumps(rec)} for rec in data] - container, stream_path = split_path(stream_path) - response = context.v3io_client.put_records( - container=container, path=stream_path, records=records - ) - - -def construct_record(record): - label_col = os.getenv("label_col", "label") - prediction_col = os.getenv("prediction_col", "prediction") - res = dict([(k, record[k]) for k in ["when", "class", "model", "resp", "request"]]) - res["feature_vector"] = res.pop("request")["instances"][0] - res["timestamp"] = res.pop("when") - res[prediction_col] = res["resp"][0] - return res - - -def init_context(context): - v3io_client = v3io.dataplane.Client() - setattr(context, "v3io_client", v3io_client) - - v3f_client = v3f.Client("framesd:8081", container="bigdata") - setattr(context, "v3f", v3f_client) - window = [] - setattr(context, "window", window) - setattr(context, "window_size", int(os.getenv("window_size", 10))) - setattr(context, "tsdb_table", os.getenv("tsdb_table", "concept_drift_tsdb_1")) - try: - context.v3f.create("tsdb", context.tsdb_table, rate="1/s", if_exists=1) - except Exception as e: - context.logger.info(f"Creating context with rate= faile for {e}") - context.v3f.create( - "tsdb", context.tsdb_table, attrs={"rate": "1/s"}, if_exists=1 - ) - - callbacks = [callback.strip() for callback in os.getenv("callbacks", "").split(",")] - setattr(context, "callbacks", callbacks) - - setattr(context, "drift_stream", os.getenv("drift_stream", "/bigdata/drift_stream")) - try: - create_stream( - context, context.drift_stream, int(os.getenv("drift_stream_shards", 1)) - ) - except: - context.logger.info(f"{context.drift_stream} already exists") - - models = {} - model_types = ["pagehinkely", "ddm", "eddm"] - path_suffix = "_model_path" - for model in model_types: - model_env = f"{model}{path_suffix}" - if model_env in os.environ: - with open(os.environ[model_env], "rb") as f: - models[model] = load(f) - setattr(context, "models", models) - - setattr(context, "label_col", os.getenv("label_col", "label")) - setattr(context, "prediction_col", os.getenv("prediction_col", "prediction")) - - -def handler(context, event): - context.logger.info(f"event: {event.body}") - full_event = json.loads(event.body) - record = construct_record(full_event) - - is_error = record[context.label_col] != record[context.prediction_col] - context.logger.info(f"Adding {is_error}") - - for name, model in context.models.items(): - results = {"timestamp": record["timestamp"]} - results["algorithm"] = name - model.add_element(is_error) - - if hasattr(model, "detected_warning_zone") and model.detected_warning_zone(): - context.logger.info(f"{name}\tWarning zone detected") - results["warning_zone"] = 1 - full_event[f"{name}_warning_zone"] = 1 - else: - results["warning_zone"] = 0 - full_event[f"{name}_warning_zone"] = 0 - - if model.detected_change(): - context.logger.info("Change Detected") - results["change_detected"] = 1 - full_event[f"{name}_drift"] = 1 - else: - results["change_detected"] = 0 - full_event[f"{name}_drift"] = 0 - context.window.append(results) - - push_to_stream(context, context.drift_stream, [full_event]) - - if context.callbacks != [""]: - for callback in context.callbacks: - requests.post(url=callback, json=full_event) - - if (len(context.window) / len(context.models)) >= context.window_size: - df = pd.DataFrame(context.window) - df["timestamp"] = pd.to_datetime(df["timestamp"]) - df = df.set_index(["timestamp", "algorithm"]) - context.v3f.write("tsdb", context.tsdb_table, df) - context.window = [] diff --git a/concept_drift_streaming/function.yaml b/concept_drift_streaming/function.yaml deleted file mode 100644 index bf1171680..000000000 --- a/concept_drift_streaming/function.yaml +++ /dev/null @@ -1,48 +0,0 @@ -kind: remote -metadata: - name: concept-drift-streaming - tag: '' - hash: dc41ff41149be69f19b91a6d78a06571937063ae - project: '' - labels: - author: orz - framework: sklearn - categories: - - machine-learning - - monitoring -spec: - command: '' - args: [] - image: mlrun/ml-models - description: Deploy a streaming Concept Drift detector on a labeled stream. the - nuclio part of the concept_drift function - min_replicas: 1 - max_replicas: 4 - env: [] - base_spec: - apiVersion: nuclio.io/v1 - kind: Function - metadata: - name: concept-drift-streaming - labels: {} - annotations: - nuclio.io/generated_by: function generated from /User/test/functions/concept_drift_streaming/concept_drift_streaming.py - spec: - runtime: python:3.9 - handler: concept_drift_streaming:handler - env: [] - volumes: [] - build: - commands: [] - noBaseImagesPull: true - functionSourceCode: IyBHZW5lcmF0ZWQgYnkgbnVjbGlvLmV4cG9ydC5OdWNsaW9FeHBvcnRlcgoKaW1wb3J0IHNrbXVsdGlmbG93LmRyaWZ0X2RldGVjdGlvbgppbXBvcnQgbnVtcHkgYXMgbnAKaW1wb3J0IHBhbmRhcyBhcyBwZAppbXBvcnQgb3MKaW1wb3J0IGpzb24KaW1wb3J0IHYzaW8uZGF0YXBsYW5lCmltcG9ydCB2M2lvX2ZyYW1lcyBhcyB2M2YKaW1wb3J0IHJlcXVlc3RzCmZyb20gY2xvdWRwaWNrbGUgaW1wb3J0IGxvYWQKCmltcG9ydCByYW5kb20KCgpkZWYgc3BsaXRfcGF0aChtbnRwYXRoPSIiKToKICAgIGlmIG1udHBhdGhbMF0gPT0gIi8iOgogICAgICAgIG1udHBhdGggPSBtbnRwYXRoWzE6XQogICAgcGF0aHMgPSBtbnRwYXRoLnNwbGl0KCIvIikKICAgIGNvbnRhaW5lciA9IHBhdGhzWzBdCiAgICBzdWJwYXRoID0gIiIKICAgIGlmIGxlbihwYXRocykgPiAxOgogICAgICAgIHN1YnBhdGggPSBtbnRwYXRoW2xlbihjb250YWluZXIpIDpdCiAgICByZXR1cm4gY29udGFpbmVyLCBzdWJwYXRoCgoKZGVmIGNyZWF0ZV9zdHJlYW0oY29udGV4dCwgcGF0aCwgc2hhcmRzPTEpOgogICAgY29udGFpbmVyLCBzdHJlYW1fcGF0aCA9IHNwbGl0X3BhdGgocGF0aCkKICAgIGNvbnRleHQubG9nZ2VyLmluZm8oCiAgICAgICAgZiJDcmVhdGluZyBzdHJlYW0gaW4gQ29udGFpbmVyOiB7Y29udGFpbmVyfSAmIFBhdGgge3N0cmVhbV9wYXRofSIKICAgICkKICAgIHJlc3BvbnNlID0gY29udGV4dC52M2lvX2NsaWVudC5jcmVhdGVfc3RyZWFtKAogICAgICAgIGNvbnRhaW5lcj1jb250YWluZXIsCiAgICAgICAgcGF0aD1zdHJlYW1fcGF0aCwKICAgICAgICBzaGFyZF9jb3VudD1zaGFyZHMsCiAgICAgICAgcmFpc2VfZm9yX3N0YXR1cz12M2lvLmRhdGFwbGFuZS5SYWlzZUZvclN0YXR1cy5uZXZlciwKICAgICkKICAgIHJlc3BvbnNlLnJhaXNlX2Zvcl9zdGF0dXMoWzQwOSwgMjA0XSkKCgpkZWYgcHVzaF90b19zdHJlYW0oY29udGV4dCwgc3RyZWFtX3BhdGgsIGRhdGEpOgogICAgcmVjb3JkcyA9IFt7ImRhdGEiOiBqc29uLmR1bXBzKHJlYyl9IGZvciByZWMgaW4gZGF0YV0KICAgIGNvbnRhaW5lciwgc3RyZWFtX3BhdGggPSBzcGxpdF9wYXRoKHN0cmVhbV9wYXRoKQogICAgcmVzcG9uc2UgPSBjb250ZXh0LnYzaW9fY2xpZW50LnB1dF9yZWNvcmRzKAogICAgICAgIGNvbnRhaW5lcj1jb250YWluZXIsIHBhdGg9c3RyZWFtX3BhdGgsIHJlY29yZHM9cmVjb3JkcwogICAgKQoKCmRlZiBjb25zdHJ1Y3RfcmVjb3JkKHJlY29yZCk6CiAgICBsYWJlbF9jb2wgPSBvcy5nZXRlbnYoImxhYmVsX2NvbCIsICJsYWJlbCIpCiAgICBwcmVkaWN0aW9uX2NvbCA9IG9zLmdldGVudigicHJlZGljdGlvbl9jb2wiLCAicHJlZGljdGlvbiIpCiAgICByZXMgPSBkaWN0KFsoaywgcmVjb3JkW2tdKSBmb3IgayBpbiBbIndoZW4iLCAiY2xhc3MiLCAibW9kZWwiLCAicmVzcCIsICJyZXF1ZXN0Il1dKQogICAgcmVzWyJmZWF0dXJlX3ZlY3RvciJdID0gcmVzLnBvcCgicmVxdWVzdCIpWyJpbnN0YW5jZXMiXVswXQogICAgcmVzWyJ0aW1lc3RhbXAiXSA9IHJlcy5wb3AoIndoZW4iKQogICAgcmVzW3ByZWRpY3Rpb25fY29sXSA9IHJlc1sicmVzcCJdWzBdCiAgICByZXR1cm4gcmVzCgoKZGVmIGluaXRfY29udGV4dChjb250ZXh0KToKICAgIHYzaW9fY2xpZW50ID0gdjNpby5kYXRhcGxhbmUuQ2xpZW50KCkKICAgIHNldGF0dHIoY29udGV4dCwgInYzaW9fY2xpZW50IiwgdjNpb19jbGllbnQpCgogICAgdjNmX2NsaWVudCA9IHYzZi5DbGllbnQoImZyYW1lc2Q6ODA4MSIsIGNvbnRhaW5lcj0iYmlnZGF0YSIpCiAgICBzZXRhdHRyKGNvbnRleHQsICJ2M2YiLCB2M2ZfY2xpZW50KQogICAgd2luZG93ID0gW10KICAgIHNldGF0dHIoY29udGV4dCwgIndpbmRvdyIsIHdpbmRvdykKICAgIHNldGF0dHIoY29udGV4dCwgIndpbmRvd19zaXplIiwgaW50KG9zLmdldGVudigid2luZG93X3NpemUiLCAxMCkpKQogICAgc2V0YXR0cihjb250ZXh0LCAidHNkYl90YWJsZSIsIG9zLmdldGVudigidHNkYl90YWJsZSIsICJjb25jZXB0X2RyaWZ0X3RzZGJfMSIpKQogICAgdHJ5OgogICAgICAgIGNvbnRleHQudjNmLmNyZWF0ZSgidHNkYiIsIGNvbnRleHQudHNkYl90YWJsZSwgcmF0ZT0iMS9zIiwgaWZfZXhpc3RzPTEpCiAgICBleGNlcHQgRXhjZXB0aW9uIGFzIGU6CiAgICAgICAgY29udGV4dC5sb2dnZXIuaW5mbyhmIkNyZWF0aW5nIGNvbnRleHQgd2l0aCByYXRlPSBmYWlsZSBmb3Ige2V9IikKICAgICAgICBjb250ZXh0LnYzZi5jcmVhdGUoCiAgICAgICAgICAgICJ0c2RiIiwgY29udGV4dC50c2RiX3RhYmxlLCBhdHRycz17InJhdGUiOiAiMS9zIn0sIGlmX2V4aXN0cz0xCiAgICAgICAgKQoKICAgIGNhbGxiYWNrcyA9IFtjYWxsYmFjay5zdHJpcCgpIGZvciBjYWxsYmFjayBpbiBvcy5nZXRlbnYoImNhbGxiYWNrcyIsICIiKS5zcGxpdCgiLCIpXQogICAgc2V0YXR0cihjb250ZXh0LCAiY2FsbGJhY2tzIiwgY2FsbGJhY2tzKQoKICAgIHNldGF0dHIoY29udGV4dCwgImRyaWZ0X3N0cmVhbSIsIG9zLmdldGVudigiZHJpZnRfc3RyZWFtIiwgIi9iaWdkYXRhL2RyaWZ0X3N0cmVhbSIpKQogICAgdHJ5OgogICAgICAgIGNyZWF0ZV9zdHJlYW0oCiAgICAgICAgICAgIGNvbnRleHQsIGNvbnRleHQuZHJpZnRfc3RyZWFtLCBpbnQob3MuZ2V0ZW52KCJkcmlmdF9zdHJlYW1fc2hhcmRzIiwgMSkpCiAgICAgICAgKQogICAgZXhjZXB0OgogICAgICAgIGNvbnRleHQubG9nZ2VyLmluZm8oZiJ7Y29udGV4dC5kcmlmdF9zdHJlYW19IGFscmVhZHkgZXhpc3RzIikKCiAgICBtb2RlbHMgPSB7fQogICAgbW9kZWxfdHlwZXMgPSBbInBhZ2VoaW5rZWx5IiwgImRkbSIsICJlZGRtIl0KICAgIHBhdGhfc3VmZml4ID0gIl9tb2RlbF9wYXRoIgogICAgZm9yIG1vZGVsIGluIG1vZGVsX3R5cGVzOgogICAgICAgIG1vZGVsX2VudiA9IGYie21vZGVsfXtwYXRoX3N1ZmZpeH0iCiAgICAgICAgaWYgbW9kZWxfZW52IGluIG9zLmVudmlyb246CiAgICAgICAgICAgIHdpdGggb3Blbihvcy5lbnZpcm9uW21vZGVsX2Vudl0sICJyYiIpIGFzIGY6CiAgICAgICAgICAgICAgICBtb2RlbHNbbW9kZWxdID0gbG9hZChmKQogICAgc2V0YXR0cihjb250ZXh0LCAibW9kZWxzIiwgbW9kZWxzKQoKICAgIHNldGF0dHIoY29udGV4dCwgImxhYmVsX2NvbCIsIG9zLmdldGVudigibGFiZWxfY29sIiwgImxhYmVsIikpCiAgICBzZXRhdHRyKGNvbnRleHQsICJwcmVkaWN0aW9uX2NvbCIsIG9zLmdldGVudigicHJlZGljdGlvbl9jb2wiLCAicHJlZGljdGlvbiIpKQoKCmRlZiBoYW5kbGVyKGNvbnRleHQsIGV2ZW50KToKICAgIGNvbnRleHQubG9nZ2VyLmluZm8oZiJldmVudDoge2V2ZW50LmJvZHl9IikKICAgIGZ1bGxfZXZlbnQgPSBqc29uLmxvYWRzKGV2ZW50LmJvZHkpCiAgICByZWNvcmQgPSBjb25zdHJ1Y3RfcmVjb3JkKGZ1bGxfZXZlbnQpCgogICAgaXNfZXJyb3IgPSByZWNvcmRbY29udGV4dC5sYWJlbF9jb2xdICE9IHJlY29yZFtjb250ZXh0LnByZWRpY3Rpb25fY29sXQogICAgY29udGV4dC5sb2dnZXIuaW5mbyhmIkFkZGluZyB7aXNfZXJyb3J9IikKCiAgICBmb3IgbmFtZSwgbW9kZWwgaW4gY29udGV4dC5tb2RlbHMuaXRlbXMoKToKICAgICAgICByZXN1bHRzID0geyJ0aW1lc3RhbXAiOiByZWNvcmRbInRpbWVzdGFtcCJdfQogICAgICAgIHJlc3VsdHNbImFsZ29yaXRobSJdID0gbmFtZQogICAgICAgIG1vZGVsLmFkZF9lbGVtZW50KGlzX2Vycm9yKQoKICAgICAgICBpZiBoYXNhdHRyKG1vZGVsLCAiZGV0ZWN0ZWRfd2FybmluZ196b25lIikgYW5kIG1vZGVsLmRldGVjdGVkX3dhcm5pbmdfem9uZSgpOgogICAgICAgICAgICBjb250ZXh0LmxvZ2dlci5pbmZvKGYie25hbWV9XHRXYXJuaW5nIHpvbmUgZGV0ZWN0ZWQiKQogICAgICAgICAgICByZXN1bHRzWyJ3YXJuaW5nX3pvbmUiXSA9IDEKICAgICAgICAgICAgZnVsbF9ldmVudFtmIntuYW1lfV93YXJuaW5nX3pvbmUiXSA9IDEKICAgICAgICBlbHNlOgogICAgICAgICAgICByZXN1bHRzWyJ3YXJuaW5nX3pvbmUiXSA9IDAKICAgICAgICAgICAgZnVsbF9ldmVudFtmIntuYW1lfV93YXJuaW5nX3pvbmUiXSA9IDAKCiAgICAgICAgaWYgbW9kZWwuZGV0ZWN0ZWRfY2hhbmdlKCk6CiAgICAgICAgICAgIGNvbnRleHQubG9nZ2VyLmluZm8oIkNoYW5nZSBEZXRlY3RlZCIpCiAgICAgICAgICAgIHJlc3VsdHNbImNoYW5nZV9kZXRlY3RlZCJdID0gMQogICAgICAgICAgICBmdWxsX2V2ZW50W2Yie25hbWV9X2RyaWZ0Il0gPSAxCiAgICAgICAgZWxzZToKICAgICAgICAgICAgcmVzdWx0c1siY2hhbmdlX2RldGVjdGVkIl0gPSAwCiAgICAgICAgICAgIGZ1bGxfZXZlbnRbZiJ7bmFtZX1fZHJpZnQiXSA9IDAKICAgICAgICBjb250ZXh0LndpbmRvdy5hcHBlbmQocmVzdWx0cykKCiAgICBwdXNoX3RvX3N0cmVhbShjb250ZXh0LCBjb250ZXh0LmRyaWZ0X3N0cmVhbSwgW2Z1bGxfZXZlbnRdKQoKICAgIGlmIGNvbnRleHQuY2FsbGJhY2tzICE9IFsiIl06CiAgICAgICAgZm9yIGNhbGxiYWNrIGluIGNvbnRleHQuY2FsbGJhY2tzOgogICAgICAgICAgICByZXF1ZXN0cy5wb3N0KHVybD1jYWxsYmFjaywganNvbj1mdWxsX2V2ZW50KQoKICAgIGlmIChsZW4oY29udGV4dC53aW5kb3cpIC8gbGVuKGNvbnRleHQubW9kZWxzKSkgPj0gY29udGV4dC53aW5kb3dfc2l6ZToKICAgICAgICBkZiA9IHBkLkRhdGFGcmFtZShjb250ZXh0LndpbmRvdykKICAgICAgICBkZlsidGltZXN0YW1wIl0gPSBwZC50b19kYXRldGltZShkZlsidGltZXN0YW1wIl0pCiAgICAgICAgZGYgPSBkZi5zZXRfaW5kZXgoWyJ0aW1lc3RhbXAiLCAiYWxnb3JpdGhtIl0pCiAgICAgICAgY29udGV4dC52M2Yud3JpdGUoInRzZGIiLCBjb250ZXh0LnRzZGJfdGFibGUsIGRmKQogICAgICAgIGNvbnRleHQud2luZG93ID0gW10K - source: '' - build: - commands: - - python -m pip install scikit-multiflow==0.4.1 v3io_frames - code_origin: https://github.com/daniels290813/functions.git#d96059851b5d51fd4583e982483eb973fccc47d2:/User/test/functions/concept_drift_streaming/concept_drift_streaming.py - origin_filename: /User/test/functions/concept_drift_streaming/concept_drift_streaming.py - default_handler: handler - disable_auto_mount: false - affinity: null -verbose: false diff --git a/concept_drift_streaming/item.yaml b/concept_drift_streaming/item.yaml deleted file mode 100644 index 91dcb9f4f..000000000 --- a/concept_drift_streaming/item.yaml +++ /dev/null @@ -1,29 +0,0 @@ -apiVersion: v1 -categories: -- machine-learning -- monitoring -description: Deploy a streaming Concept Drift detector on a labeled stream. the nuclio - part of the concept_drift function -doc: '' -example: concept_drift_streaming.ipynb -generationDate: 2022-08-28:17-25 -hidden: false -icon: '' -labels: - author: orz - framework: sklearn -maintainers: [] -marketplaceType: '' -mlrunVersion: 1.1.0 -name: concept-drift-streaming -platformVersion: 3.5.0 -spec: - filename: concept_drift_streaming.py - handler: handler - image: mlrun/ml-models - kind: nuclio - requirements: - - scikit-multiflow==0.4.1 - - v3io_frames -url: '' -version: 1.1.0 diff --git a/concept_drift_streaming/requirements.txt b/concept_drift_streaming/requirements.txt deleted file mode 100644 index fa0fddd88..000000000 --- a/concept_drift_streaming/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -skmultiflow \ No newline at end of file diff --git a/feature_perms/README.ipynb b/feature_perms/README.ipynb deleted file mode 100644 index 0929a6f6a..000000000 --- a/feature_perms/README.ipynb +++ /dev/null @@ -1,788 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# feature importances" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "There are a number of ways to compute feature importances and **the default estimates reported by scikit learn can be shown to be biased** under certain circumstances. In addition, many non-tree algorithms do not provide conveniently calculated feature importance estimates. The following demonstration is based on material that draws heavily from the following sources:" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## references\n", - "\n", - "\n", - "### repos\n", - "\n", - "* **[Feature importances for scikit-learn machine learning models](https://github.com/parrt/random-forest-importances)**, [MIT License](https://github.com/parrt/random-forest-importances/blob/master/LICENSE)\n", - "* **[Scikit-Learn ensemble module - forests](https://github.com/scikit-learn/scikit-learn/blob/0.23.1/sklearn/ensemble/_forest.py)**, [BSD License](https://github.com/scikit-learn/scikit-learn/blob/fd237278e895b42abe8d8d09105cbb82dc2cbba7/sklearn/ensemble/_forest.py#L40)\n", - "* **[ELI5 - Permutation Importance](https://eli5.readthedocs.io/en/latest/blackbox/permutation_importance.html)** \n", - "\n", - "### articles\n", - "\n", - "Strobl, C., Boulesteix, A., Zeileis, A. et al. **[Bias in random forest variable importance measures: Illustrations, sources and a solution](https://link.springer.com/article/10.1186/1471-2105-8-25#citeas)**. BMC Bioinformatics 8, 25 (2007). https://doi.org/10.1186/1471-2105-8-25 \n", - "\n", - "Strobl, C., Boulesteix, A., Kneib, T. et al. **[Conditional variable importance for random forests](https://bmcbioinformatics.biomedcentral.com/articles/10.1186/1471-2105-9-307#citeas)**. BMC Bioinformatics 9, 307 (2008). https://doi.org/10.1186/1471-2105-9-307 " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## what we'll do\n", - "\n", - "* demonstrate an issue with default feature importance estimates \n", - "* provide alternatives and compare to the default \n", - "* create a new function `feature_perms` that implements a computationally simple algorithm \n", - "* create a new function `dropcol_importances` that implements a computationally intensive algorithm that is more accurate\n", - "* test our new functions\n", - "\n", - "It should be noted that although we are developing this notebook using a classification example, an almost identical presentation can be done for regression." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## imports" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "import pandas as pd\n", - "\n", - "import sklearn\n", - "from sklearn.base import clone\n", - "\n", - "from sklearn.ensemble import RandomForestClassifier as SomeModel\n", - "\n", - "import matplotlib.pyplot as plt\n", - "import seaborn as sns\n", - "\n", - "from typing import Union, Callable, List" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## default feature importances\n", - "\n", - "This is a function that plots default feature importances from an estimated model object when available. It is taken from mlrun's current source-code implementation:" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "def feature_importances(\n", - " model: SomeModel,\n", - " header: List[str], \n", - " figsz=(10, 5)\n", - ") -> None:\n", - " \"\"\"Display default model feature importances\n", - "\n", - " Only works for models with attribute 'feature_importances_`\n", - "\n", - " :param model: fitted model with a feature_importances_ attribute\n", - " :param header: feature labels\n", - " :param figsz: matplotlib figure size\n", - " \"\"\"\n", - " if not hasattr(model, \"feature_importances_\"):\n", - " raise Exception(\n", - " \"feature importances are only available for some models\")\n", - "\n", - " # create a feature importance table with desired labels\n", - " zipped = zip(model.feature_importances_, header)\n", - " feature_imp = pd.DataFrame(\n", - " sorted(zipped), columns=[\"freq\", \"feature\"]).sort_values(\n", - " by=\"freq\", ascending=False)\n", - "\n", - " plt.clf()\n", - " plt.figure(figsize=figsz)\n", - " sns.barplot(x=\"freq\", y=\"feature\", data=feature_imp)\n", - " plt.title(\"features\")\n", - " plt.tight_layout();\n", - " \n", - " return feature_imp" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## permuted features\n", - "\n", - "A proposed solution that has general applicability is randomly permuted features**[refs](#references)**: \n", - "* loop through the feature set \n", - "* shuffle one feature \n", - "* run predict\n", - "* compare the (marginal) change in accuracy (or other metric of interest) \n", - "\n", - "This approach is computationally more demanding than relying on the default values, however it can be easily parallelized. To perform the estimation we only need an estimated model and a held-out test set. The following was proposed in **[Beware Default Random Forest Importances](https://explained.ai/rf-importance/index.html)**:\n", - "\n", - "( the following 3 glue functions will no longer be publicly visible in the sklearn package from 0.24 onwards, consider this a temporary hack while we refactor these away)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**the following has been refactored in final version of function:**" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "from distutils.version import LooseVersion\n", - "import numpy as np\n", - "from sklearn.utils import check_random_state\n", - "\n", - "def _generate_sample_indices(random_state: int, n_samples: int, n_samples_bootstrap: int):\n", - " \"\"\"\n", - " Private function used to _parallel_build_trees function.\n", - " taken from:\n", - " https://github.com/scikit-learn/scikit-learn/blob/2253807bb488b6de73796aef2de38a6dcf282d86/sklearn/ensemble/_forest.py#L116\n", - " (public availability to be deprecated by sklearn v0.24)\n", - " \"\"\"\n", - " random_instance = check_random_state(random_state)\n", - " sample_indices = random_instance.randint(0, n_samples, n_samples_bootstrap)\n", - "\n", - " return sample_indices\n", - "\n", - "def _generate_unsampled_indices(random_state: int, n_samples: int, n_samples_bootstrap: int):\n", - " \"\"\"\n", - " Private function used to forest._set_oob_score function.\n", - " taken from: \n", - " https://github.com/scikit-learn/scikit-learn/blob/2253807bb488b6de73796aef2de38a6dcf282d86/sklearn/ensemble/_forest.py#L126\n", - " (public availability to be deprecated by sklearn v0.24)\n", - " \"\"\"\n", - " sample_indices = _generate_sample_indices(random_state, n_samples,\n", - " n_samples_bootstrap)\n", - " sample_counts = np.bincount(sample_indices, minlength=n_samples)\n", - " unsampled_mask = sample_counts == 0\n", - " indices_range = np.arange(n_samples)\n", - " unsampled_indices = indices_range[unsampled_mask]\n", - "\n", - " return unsampled_indices\n", - "\n", - "def _get_unsampled_indices(tree, n_samples: int):\n", - " \"\"\"\n", - " An interface to get unsampled indices regardless of sklearn version.\n", - " \"\"\"\n", - " import warnings\n", - " warnings.simplefilter(action=\"ignore\", category=FutureWarning)\n", - " if LooseVersion(sklearn.__version__) >= LooseVersion(\"0.22\"):\n", - " # Version 0.22 or newer uses 3 arguments.\n", - " from sklearn.ensemble.forest import _get_n_samples_bootstrap\n", - " n_samples_bootstrap = _get_n_samples_bootstrap(n_samples, n_samples)\n", - " return _generate_unsampled_indices(tree.random_state, n_samples,\n", - " n_samples_bootstrap)\n", - " else:\n", - " # Version 0.21 or older uses only two arguments.\n", - " return _generate_unsampled_indices(tree.random_state, n_samples)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The following function estimates classifier accuracy and has been borrowed from **[references](#references)**. See **[breitman on oob](https://www.stat.berkeley.edu/~breiman/OOBestimation.pdf)** for details on out-of-bag estimation:" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "def oob_classifier_accuracy(rf, X_train: np.array, y_train: np.array) -> float:\n", - " \"\"\"\n", - " Compute out-of-bag (OOB) accuracy for a scikit-learn forest classifier.\n", - " \n", - " https://github.com/scikit-learn/scikit-learn/blob/a24c8b46/sklearn/ensemble/forest.py#L425\n", - " \"\"\"\n", - " X = X_train.values\n", - " y = y_train.values\n", - "\n", - " n_samples = len(X)\n", - " n_classes = len(np.unique(y))\n", - " predictions = np.zeros((n_samples, n_classes))\n", - " for tree in rf.estimators_:\n", - " unsampled_indices = _get_unsampled_indices(tree, n_samples)\n", - " tree_preds = tree.predict_proba(X[unsampled_indices, :])\n", - " predictions[unsampled_indices] += tree_preds\n", - "\n", - " predicted_class_indexes = np.argmax(predictions, axis=1)\n", - " predicted_classes = [rf.classes_[i] for i in predicted_class_indexes]\n", - "\n", - " oob_score = np.mean(y == predicted_classes)\n", - " \n", - " return oob_score" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Putting it all together:" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [], - "source": [ - "def permutation_importances(\n", - " model, \n", - " X_train: np.array,\n", - " y_train: np.array, \n", - " header: List[str],\n", - " metric: Callable = oob_classifier_accuracy,\n", - " figsz=(10, 5)\n", - ") -> np.array:\n", - " \"\"\"calculate change in metric from permuting feature columns\n", - " \n", - " modified from https://explained.ai/rf-importance/index.html\n", - " \n", - " uses a pre-estimated model\n", - "\n", - " :param X_train: training set features\n", - " :param y_train: training set ground truths, regression targets\n", - " :param header: column labels for X_train\n", - " :param figsz: matplotlib figure size\n", - " \n", - " \"\"\"\n", - " baseline = metric(model, X_train, y_train)\n", - " imp = []\n", - " for col in X_train.columns:\n", - " save = X_train[col].copy()\n", - " X_train[col] = np.random.permutation(X_train[col])\n", - " m = metric(model, X_train, y_train)\n", - " X_train[col] = save\n", - " imp.append(baseline - m)\n", - " \n", - " # create a feature importance table with desired labels\n", - " zipped = zip(imp, header)\n", - " feature_imp = pd.DataFrame(sorted(zipped), columns=[\"importance\", \"feature\"])\n", - " feature_imp.sort_values(by=\"importance\", ascending=False, inplace=True)\n", - "\n", - " plt.clf()\n", - " plt.figure(figsize=figsz)\n", - " sns.barplot(x=\"importance\", y=\"feature\", data=feature_imp)\n", - " plt.title(\"feature permutation importances\")\n", - " plt.tight_layout()\n", - "\n", - " return np.array(feature_imp)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## drop-column importances\n", - "\n", - "According to our **[references](#references)** a more accurate measure of feature importance would have us re-estimate the model after dropping a column. This is considered as being close to \"ideal\". Unfortunately, the entire model needs to be re-estimated for each column and without some approximating shortcut this is likely to be infeasible for large datasets.\n", - "\n", - "Here is the suggested implementation and **don't run this on big models!**:" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [], - "source": [ - "def dropcol_importances(\n", - " model, \n", - " X_train: np.array,\n", - " y_train: np.array,\n", - " header: List[str] = [],\n", - " random_state: int = 1994,\n", - " figsz=(10, 5)\n", - ") -> pd.DataFrame:\n", - " \"\"\"drop columns and re-estimate model\n", - " \n", - " modified from https://explained.ai/rf-importance/index.html\n", - " \n", - " :param rf: model to fit\n", - " :param X_train: training set features\n", - " :param y_train: training set ground truth labels\n", - "\n", - " Returns:\n", - " pd.DataFrame: table of diffs vs baseline metric\n", - " \"\"\"\n", - " # cloning makes copy of model pre-fit\n", - " # calculate a baseline with all features\n", - " model_ = clone(model)\n", - " model_.random_state = random_state\n", - " model_.fit(X_train, y_train)\n", - " baseline = model_.oob_score_\n", - " \n", - " # now drop each colum, refit model and calc metric\n", - " imp = []\n", - " for col in X_train.columns:\n", - " X = X_train.drop(col, axis=1)\n", - " model_ = clone(model)\n", - " model_.random_state = random_state\n", - " model_.fit(X, y_train)\n", - " o = model_.oob_score_\n", - " imp.append(baseline - o)\n", - " \n", - " # put it all in a table\n", - " imp = np.array(imp)\n", - " feature_imps = pd.DataFrame(\n", - " data={'feature': X_train.columns,\n", - " 'importance': imp})\n", - " #feature_imps.set_index('feature', inplace=True)\n", - " feature_imps.sort_values('importance', ascending=True, inplace=True)\n", - " \n", - " plt.clf()\n", - " plt.figure(figsize=figsz)\n", - " sns.barplot(x=\"importance\", y=\"feature\", data=feature_imps)\n", - " plt.title(\"drop column feature importances\")\n", - " plt.tight_layout()\n", - " \n", - " return feature_imps" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## demonstration\n", - "\n", - "In this demonstratuon we are going to take a fraction of a fraction of **[Kaggle's RentHop rental listing interest competition](https://www.kaggle.com/c/two-sigma-connect-rental-listing-inquiries)**--the complete dataset is presently >80GB, we'll be looking at 5K rows. \n", - "\n", - "The competition's **[goal](https://www.kaggle.com/c/two-sigma-connect-rental-listing-inquiries)** was\n", - "> to predict the number of inquiries a new listing receives based on the listing’s creation date and other features. \n", - "\n", - "Doing so would help **[RentHop](https://www.renthop.com/)**\n", - "> better handle fraud control, identify potential listing quality issues, and allow owners and agents to better understand renters’ needs and preferences." - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [], - "source": [ - "data = \"/User/artifacts/two-sigma-connect-rental-listing-inquiries/\"\n", - "NFRAC = 0.1" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "sample dimensions (4935, 6)\n" - ] - }, - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
bathroomsbedroomspricelongitudelatitudeinterest_level
182351.001800-73.996040.71972
421401.023000-73.987940.76533
46771.011350-73.899640.85492
\n", - "
" - ], - "text/plain": [ - " bathrooms bedrooms price longitude latitude interest_level\n", - "18235 1.0 0 1800 -73.9960 40.7197 2\n", - "42140 1.0 2 3000 -73.9879 40.7653 3\n", - "4677 1.0 1 1350 -73.8996 40.8549 2" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df = pd.read_csv(data + 'rent.csv').sample(frac=NFRAC)\n", - "print(\"sample dimensions\", df.shape)\n", - "df.head(3)" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [], - "source": [ - "features = ['bathrooms', 'bedrooms', 'longitude', 'latitude', 'price']\n", - "dfr = df[features]\n", - "\n", - "# drop price column\n", - "X_train, y_train = dfr.drop('price', axis=1), dfr['price']\n", - "\n", - "# insert column with random values\n", - "X_train['random'] = np.random.random(size=len(X_train))\n", - "features = ['bathrooms', 'bedrooms', 'longitude', 'latitude', 'random']" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "RandomForestClassifier(n_jobs=-1, oob_score=True)" - ] - }, - "execution_count": 18, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# define model\n", - "model_params = {\n", - " \"n_estimators\" : 100, \n", - " \"min_samples_leaf\" : 1,\n", - " \"n_jobs\" : -1,\n", - " \"oob_score\" : True\n", - "}\n", - "\n", - "model = SomeModel(**model_params)\n", - "\n", - "# estimate\n", - "model.fit(X_train, y_train)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### to run this the model needs a default attribute" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "default feature_importances [0.01683784 0.03215169 0.29983429 0.30418813 0.34698806]\n" - ] - }, - { - "data": { - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "if hasattr(model, \"feature_importances_\"):\n", - " print(\"default feature_importances\", model.feature_importances_)\n", - " feature_importances(model, features)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## permutation importances\n", - "\n", - "No need to check for default attributes or functions, this can be run on any kind of model:" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([[0.06545086119554205, 'longitude'],\n", - " [0.06160081053698076, 'latitude'],\n", - " [0.053495440729483285, 'bedrooms'],\n", - " [0.021681864235055734, 'bathrooms'],\n", - " [0.0004052684903748799, 'random']], dtype=object)" - ] - }, - "execution_count": 20, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "pi = permutation_importances(model, X_train, y_train, features)\n", - "pi" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## drop-column importances" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
featureimportance
4random-0.042756
0bathrooms0.001824
1bedrooms0.023100
2longitude0.049240
3latitude0.051874
\n", - "
" - ], - "text/plain": [ - " feature importance\n", - "4 random -0.042756\n", - "0 bathrooms 0.001824\n", - "1 bedrooms 0.023100\n", - "2 longitude 0.049240\n", - "3 latitude 0.051874" - ] - }, - "execution_count": 21, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "dc = dropcol_importances(model, X_train, y_train)\n", - "dc" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## conclusions" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "So I would say location is a prime factor, then the number of bedrooms. Bathrooms often is gte bedrooms, and is likely correlated so one of them should likely be dropped." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "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.6.8" - }, - "toc-autonumbering": false, - "toc-showcode": false, - "toc-showmarkdowntxt": false - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/feature_perms/feature_perms.ipynb b/feature_perms/feature_perms.ipynb deleted file mode 100644 index 77da7b553..000000000 --- a/feature_perms/feature_perms.ipynb +++ /dev/null @@ -1,1106 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# permutation_importances as reusable function" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## function code" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "# nuclio: ignore\n", - "import nuclio" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "import pandas as pd\n", - "import numbers\n", - "\n", - "import sklearn\n", - "from sklearn.base import clone\n", - "from sklearn.utils import check_random_state\n", - "\n", - "import matplotlib.pyplot as plt\n", - "import seaborn as sns\n", - "\n", - "from cloudpickle import load\n", - "\n", - "from mlrun.execution import MLClientCtx\n", - "from mlrun.datastore import DataItem\n", - "from mlrun.artifacts import get_model, PlotArtifact\n", - "from typing import Union, Callable, List\n", - "\n", - "def _get_n_samples_bootstrap(n_samples, max_samples) -> int:\n", - " \"\"\"get the number of samples in a bootstrap sample\n", - " \n", - " returns the total number of samples to draw for the bootstrap sample\n", - " \n", - " private api in sklearn >= v0.24, taken from sklearn.ensemble._forest.py\n", - "\n", - " :param n_samples: Number of samples in the dataset.\n", - " :param max_samples: \n", - " The maximum number of samples to draw from the total available:\n", - " - if float, this indicates a fraction of the total and should be\n", - " the interval `(0, 1)`;\n", - " - if int, this indicates the exact number of samples;\n", - " - if None, this indicates the total number of samples.\n", - " \"\"\"\n", - " if max_samples is None:\n", - " return n_samples\n", - "\n", - " if isinstance(max_samples, numbers.Integral):\n", - " if not (1 <= max_samples <= n_samples):\n", - " msg = \"`max_samples` must be in range 1 to {} but got value {}\"\n", - " raise ValueError(msg.format(n_samples, max_samples))\n", - " return max_samples\n", - "\n", - " if isinstance(max_samples, numbers.Real):\n", - " if not (0 < max_samples < 1):\n", - " msg = \"`max_samples` must be in range (0, 1) but got value {}\"\n", - " raise ValueError(msg.format(max_samples))\n", - " return int(round(n_samples * max_samples))\n", - "\n", - " msg = \"`max_samples` should be int or float, but got type '{}'\"\n", - " raise TypeError(msg.format(type(max_samples)))\n", - "\n", - "def _get_unsampled_ix(random_state, n_samples: int) -> np.array:\n", - " \"\"\"\n", - " future-proof get unsampled indices\n", - " \"\"\"\n", - " n_bootstrap = _get_n_samples_bootstrap(n_samples, n_samples)\n", - " random_instance = check_random_state(random_state)\n", - " sample_indices = random_instance.randint(0, n_samples, n_bootstrap)\n", - " sample_counts = np.bincount(sample_indices, minlength=n_samples)\n", - "\n", - " return np.arange(n_samples)[sample_counts==0]\n", - "\n", - "def _oob_classifier_accuracy(rf, X_train, y_train) -> float:\n", - " \"\"\"\n", - " Compute out-of-bag (OOB) accuracy for a scikit-learn forest classifier.\n", - " \n", - " https://github.com/scikit-learn/scikit-learn/blob/a24c8b46/sklearn/ensemble/forest.py#L425\n", - " \"\"\"\n", - " X = X_train.values if isinstance(X_train, pd.DataFrame) else X_train\n", - " y = y_train.values if isinstance(y_train, pd.Series) else y_train\n", - "\n", - " n_samples = len(X)\n", - " n_classes = len(np.unique(y))\n", - " predictions = np.zeros((n_samples, n_classes))\n", - " for tree in rf.estimators_:\n", - " unsampled_indices = _get_unsampled_ix(tree.random_state, n_samples)\n", - " tree_preds = tree.predict_proba(X[unsampled_indices, :])\n", - " predictions[unsampled_indices] += tree_preds\n", - "\n", - " predicted_class_indexes = np.argmax(predictions, axis=1)\n", - " predicted_classes = [rf.classes_[i] for i in predicted_class_indexes]\n", - "\n", - " oob_score = np.mean(y == predicted_classes)\n", - " \n", - " return oob_score\n", - "\n", - "def permutation_importances(\n", - " context: MLClientCtx,\n", - " model: DataItem,\n", - " dataset: DataItem,\n", - " labels: str,\n", - " figsz=(10, 5),\n", - " plots_dest: str = \"plots\",\n", - " fitype: str = \"permute\"\n", - ") -> pd.DataFrame:\n", - " \"\"\"calculate change in metric\n", - " \n", - " type 'permute' uses a pre-estimated model\n", - " type 'dropcol' uses a re-estimates model\n", - " \n", - " :param context: the function's execution context\n", - " :param model: a trained model\n", - " :param dataset: features and ground truths, regression targets\n", - " :param labels name of the ground truths column\n", - " :param figsz: matplotlib figure size\n", - " :param plots_dest: path within artifact store\n", - " :\n", - " \"\"\"\n", - " model_file, model_data, _ = get_model(model.url, suffix='.pkl')\n", - " model = load(open(str(model_file), \"rb\"))\n", - " \n", - " X = dataset.as_df()\n", - " y = X.pop(labels)\n", - " header = X.columns\n", - " \n", - " # this will be paramettrized next version, and include regression\n", - " metric = _oob_classifier_accuracy\n", - " \n", - " baseline = metric(model, X, y)\n", - " \n", - " imp = []\n", - " for col in X.columns:\n", - " if fitype is \"permute\":\n", - " save = X[col].copy()\n", - " X[col] = np.random.permutation(X[col])\n", - " m = metric(model, X, y)\n", - " X[col] = save\n", - " imp.append(baseline - m)\n", - " elif fitype is \"dropcol\":\n", - " X_ = X.drop(col, axis=1)\n", - " model_ = clone(model)\n", - " model_.random_state = random_state\n", - " model_.fit(X_, y)\n", - " o = model_.oob_score_\n", - " imp.append(baseline - o)\n", - " else:\n", - " raise ValueError(\"unknown fitype, only 'permute' or 'dropcol' permitted\")\n", - "\n", - " # create a feature importance table with desired labels\n", - " zipped = zip(imp, header)\n", - " feature_imp = pd.DataFrame(sorted(zipped), columns=[\"importance\", \"feature\"])\n", - " feature_imp.sort_values(by=\"importance\", ascending=False, inplace=True)\n", - "\n", - " plt.clf()\n", - " plt.figure(figsize=figsz)\n", - " sns.barplot(x=\"importance\", y=\"feature\", data=feature_imp)\n", - " plt.title(f\"feature importances-{fitype}\")\n", - " plt.tight_layout()\n", - "\n", - " context.log_artifact(PlotArtifact(f\"feature importances-{fitype}\", body=plt.gcf()),\n", - " local_path=f\"{plots_dest}/feature-permutations.html\")\n", - " context.log_dataset(f\"feature-importances-{fitype}-tbl\", df=feature_imp, index=False)" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "# nuclio: end-code" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## save function" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[mlrun] 2020-06-07 19:58:25,298 function spec saved to path: function.yaml\n" - ] - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from mlrun import code_to_function\n", - "from mlrun.platforms.other import auto_mount\n", - "\n", - "gpus = False\n", - "\n", - "# create job function object from notebook code\n", - "fn_params = {\n", - " \"name\" : \"feature-perms\",\n", - " \"handler\" : \"permutation_importances\",\n", - " \"kind\" : \"job\",\n", - " \"image\" : \"mlrun/ml-models\" if not gpus else \"mlrun/ml-models-gpu\",\n", - " \"description\" : \"estimate feature importances using permutations\",\n", - " \"categories\" : [\"analysis\"],\n", - " \"labels\" : {\"author\": \"yjb\"}\n", - "}\n", - "\n", - "perms_fn = code_to_function(**fn_params)\n", - "perms_fn.apply(auto_mount())\n", - "perms_fn.export(\"function.yaml\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## tests" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "from mlrun import import_function\n", - "from mlrun import NewTask, mlconf" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### get some data" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[mlrun] 2020-06-07 19:58:25,352 starting run tasks arc-to-parq uid=e9bc67f2189c418d96bfde754d369956 -> http://mlrun-api:8080\n", - "[mlrun] 2020-06-07 19:58:25,486 Job is running in the background, pod: tasks-arc-to-parq-xqkr7\n", - "[mlrun] 2020-06-07 19:58:29,118 starting local run: main.py # arc_to_parquet\n", - "[mlrun] 2020-06-07 19:58:29,169 downloading https://raw.githubusercontent.com/parrt/random-forest-importances/master/notebooks/data/rent.csv to local tmp\n", - "[mlrun] 2020-06-07 19:58:29,535 destination file does not exist, downloading\n", - "[mlrun] 2020-06-07 19:58:29,898 log artifact rent at /User/artifacts/rent.csv, size: 1492462, db: Y\n", - "\n", - "[mlrun] 2020-06-07 19:58:29,917 run executed, status=completed\n", - "final state: succeeded\n" - ] - }, - { - "data": { - "text/html": [ - "\n", - "
\n", - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
projectuiditerstartstatenamelabelsinputsparametersresultsartifacts
default0Jun 07 19:58:29completedtasks arc-to-parq
v3io_user=admin
kind=job
owner=admin
host=tasks-arc-to-parq-xqkr7
archive_url
key=rent
stats=True
file_ext=csv
rent
\n", - "
\n", - "
\n", - "
\n", - " Title\n", - " ×\n", - "
\n", - " \n", - "
\n", - "
\n" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "to track results use .show() or .logs() or in CLI: \n", - "!mlrun get run e9bc67f2189c418d96bfde754d369956 --project default , !mlrun logs e9bc67f2189c418d96bfde754d369956 --project default\n", - "[mlrun] 2020-06-07 19:58:31,666 run executed, status=completed\n" - ] - } - ], - "source": [ - "data_url = \"https://raw.githubusercontent.com/parrt/random-forest-importances/master/notebooks/data/rent.csv\"\n", - "\n", - "fn = import_function(\"hub://arc_to_parquet\", \"a2p\")\n", - "fn.apply(auto_mount())\n", - "\n", - "params = {\n", - " \"name\" : \"tasks arc-to-parq\",\n", - " \"params\" : {\"key\":\"rent\", \"stats\": True, \"file_ext\":\"csv\"}\n", - "}\n", - "acquire_run = fn.run(NewTask(**params),inputs={\"archive_url\" : data_url},\n", - " artifact_path=mlconf.artifact_path)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### train a model" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[mlrun] 2020-06-07 19:58:31,704 starting run tasks random forest uid=57af834167264641905a5bb5e6b0e263 -> http://mlrun-api:8080\n", - "[mlrun] 2020-06-07 19:58:31,861 Job is running in the background, pod: tasks-random-forest-vkjk5\n", - "[mlrun] 2020-06-07 19:58:35,390 starting local run: main.py # train_model\n", - "[mlrun] 2020-06-07 19:58:36,310 log artifact test_set at /User/artifacts/data/test_set.parquet, size: 24484, db: Y\n", - "[mlrun] 2020-06-07 19:58:37,153 log artifact confusion-matrix at /User/artifacts/model/plots/confusion-matrix.html, size: 27401, db: N\n", - "[mlrun] 2020-06-07 19:58:37,598 log artifact feature-importances at /User/artifacts/model/plots/feature-importances.html, size: 19685, db: N\n", - "[mlrun] 2020-06-07 19:58:37,806 log artifact precision-recall-multiclass at /User/artifacts/model/plots/precision-recall-multiclass.html, size: 74009, db: N\n", - "[mlrun] 2020-06-07 19:58:37,936 log artifact roc-multiclass at /User/artifacts/model/plots/roc-multiclass.html, size: 73053, db: N\n", - "[mlrun] 2020-06-07 19:58:38,079 log artifact model at /User/artifacts/model/, size: 10346780, db: Y\n", - "\n", - "[mlrun] 2020-06-07 19:58:38,106 run executed, status=completed\n", - "final state: succeeded\n" - ] - }, - { - "data": { - "text/html": [ - "\n", - "
\n", - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
projectuiditerstartstatenamelabelsinputsparametersresultsartifacts
default0Jun 07 19:58:36completedtasks random forest
v3io_user=admin
kind=job
owner=admin
host=tasks-random-forest-vkjk5
class=sklearn.ensemble.RandomForestClassifier
dataset
sample=-5000
model_pkg_class=sklearn.ensemble.RandomForestClassifier
label_column=interest_level
CLASS_n_estimators=100
CLASS_min_samples_leaf=1
CLASS_n_jobs=-1
CLASS_oob_score=True
test-accuracy=0.6902857142857143
test-error=0.3097142857142857
auc-micro=0.8567196734693878
auc-weighted=0.7077200281488216
f1-score=0.44361444815007395
precision_score=0.4969837043184901
recall_score=0.42733978329897576
test_set
confusion-matrix
feature-importances
precision-recall-multiclass
roc-multiclass
model
\n", - "
\n", - "
\n", - "
\n", - " Title\n", - " ×\n", - "
\n", - " \n", - "
\n", - "
\n" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "to track results use .show() or .logs() or in CLI: \n", - "!mlrun get run 57af834167264641905a5bb5e6b0e263 --project default , !mlrun logs 57af834167264641905a5bb5e6b0e263 --project default\n", - "[mlrun] 2020-06-07 19:58:41,115 run executed, status=completed\n" - ] - } - ], - "source": [ - "fn = import_function(\"hub://sklearn_classifier\", \"skrf\")\n", - "fn.apply(auto_mount())\n", - "\n", - "# define model\n", - "params = {\n", - " \"name\" : \"tasks random forest\",\n", - " \"params\" : {\n", - " \"sample\" : -5_000, # 5k random rows,\n", - " \"model_pkg_class\" : \"sklearn.ensemble.RandomForestClassifier\",\n", - " \"label_column\" : \"interest_level\",\n", - " \"CLASS_n_estimators\" : 100,\n", - " \"CLASS_min_samples_leaf\" : 1,\n", - " \"CLASS_n_jobs\" : -1,\n", - " \"CLASS_oob_score\" : True}\n", - "}\n", - "\n", - "train_run = fn.run(NewTask(**params), inputs={\"dataset\" : acquire_run.outputs[\"rent\"]},\n", - " artifact_path=mlconf.artifact_path)" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "

Feature Importances

\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from IPython.display import HTML\n", - "HTML(filename=train_run.outputs['feature-importances'])" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "data = acquire_run.outputs[\"rent\"]\n", - "labels = \"interest_level\"\n", - "model = train_run.outputs[\"model\"]\n" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[mlrun] 2020-06-07 19:58:41,152 starting run features-permutation_importances uid=89235b15ac2a4213aefc906c178a1c5e -> http://mlrun-api:8080\n", - "[mlrun] 2020-06-07 19:58:41,312 Job is running in the background, pod: features-permutation-importances-dwxmt\n", - "[mlrun] 2020-06-07 19:58:44,871 starting local run: main.py # permutation_importances\n", - "[mlrun] 2020-06-07 19:58:48,714 log artifact feature importances-permute at /User/artifacts/plots/feature-permutations.html, size: 25694, db: Y\n", - "[mlrun] 2020-06-07 19:58:48,770 log artifact feature-importances-permute-tbl at /User/artifacts/feature-importances-permute-tbl.csv, size: 167, db: Y\n", - "\n", - "[mlrun] 2020-06-07 19:58:48,785 run executed, status=completed\n", - "final state: succeeded\n" - ] - }, - { - "data": { - "text/html": [ - "\n", - "
\n", - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
projectuiditerstartstatenamelabelsinputsparametersresultsartifacts
default0Jun 07 19:58:45completedfeatures-permutation_importances
v3io_user=admin
kind=job
owner=admin
host=features-permutation-importances-dwxmt
model
dataset
labels=interest_level
plots_dest=plots
feature importances-permute
feature-importances-permute-tbl
\n", - "
\n", - "
\n", - "
\n", - " Title\n", - " ×\n", - "
\n", - " \n", - "
\n", - "
\n" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "to track results use .show() or .logs() or in CLI: \n", - "!mlrun get run 89235b15ac2a4213aefc906c178a1c5e --project default , !mlrun logs 89235b15ac2a4213aefc906c178a1c5e --project default\n", - "[mlrun] 2020-06-07 19:58:50,488 run executed, status=completed\n" - ] - } - ], - "source": [ - "fi_perms = perms_fn.run(\n", - " NewTask(params={\"labels\": labels, \n", - " \"plots_dest\": \"plots\"}),\n", - " inputs={\"model\": model, \"dataset\": data},\n", - " artifact_path=mlconf.artifact_path)" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from IPython.display import HTML\n", - "HTML(filename=fi_perms.outputs['feature importances-permute'])" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "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.6.8" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} \ No newline at end of file diff --git a/feature_perms/feature_perms.py b/feature_perms/feature_perms.py deleted file mode 100644 index 13caae32e..000000000 --- a/feature_perms/feature_perms.py +++ /dev/null @@ -1,174 +0,0 @@ -# Copyright 2019 Iguazio -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# Generated by nuclio.export.NuclioExporter - -import numpy as np -import pandas as pd -import numbers - -import sklearn -from sklearn.base import clone -from sklearn.utils import check_random_state - -import matplotlib.pyplot as plt -import seaborn as sns - -from cloudpickle import load - -from mlrun.execution import MLClientCtx -from mlrun.datastore import DataItem -from mlrun.artifacts import get_model, PlotArtifact -from typing import Union, Callable, List - - -def _get_n_samples_bootstrap(n_samples, max_samples) -> int: - """get the number of samples in a bootstrap sample - - returns the total number of samples to draw for the bootstrap sample - - private api in sklearn >= v0.24, taken from sklearn.ensemble._forest.py - - :param n_samples: Number of samples in the dataset. - :param max_samples: - The maximum number of samples to draw from the total available: - - if float, this indicates a fraction of the total and should be - the interval `(0, 1)`; - - if int, this indicates the exact number of samples; - - if None, this indicates the total number of samples. - """ - if max_samples is None: - return n_samples - - if isinstance(max_samples, numbers.Integral): - if not (1 <= max_samples <= n_samples): - msg = "`max_samples` must be in range 1 to {} but got value {}" - raise ValueError(msg.format(n_samples, max_samples)) - return max_samples - - if isinstance(max_samples, numbers.Real): - if not (0 < max_samples < 1): - msg = "`max_samples` must be in range (0, 1) but got value {}" - raise ValueError(msg.format(max_samples)) - return int(round(n_samples * max_samples)) - - msg = "`max_samples` should be int or float, but got type '{}'" - raise TypeError(msg.format(type(max_samples))) - - -def _get_unsampled_ix(random_state, n_samples: int) -> np.array: - """ - future-proof get unsampled indices - """ - n_bootstrap = _get_n_samples_bootstrap(n_samples, n_samples) - random_instance = check_random_state(random_state) - sample_indices = random_instance.randint(0, n_samples, n_bootstrap) - sample_counts = np.bincount(sample_indices, minlength=n_samples) - - return np.arange(n_samples)[sample_counts == 0] - - -def _oob_classifier_accuracy(rf, X_train, y_train) -> float: - """ - Compute out-of-bag (OOB) accuracy for a scikit-learn forest classifier. - - https://github.com/scikit-learn/scikit-learn/blob/a24c8b46/sklearn/ensemble/forest.py#L425 - """ - X = X_train.values if isinstance(X_train, pd.DataFrame) else X_train - y = y_train.values if isinstance(y_train, pd.Series) else y_train - - n_samples = len(X) - n_classes = len(np.unique(y)) - predictions = np.zeros((n_samples, n_classes)) - for tree in rf.estimators_: - unsampled_indices = _get_unsampled_ix(tree.random_state, n_samples) - tree_preds = tree.predict_proba(X[unsampled_indices, :]) - predictions[unsampled_indices] += tree_preds - - predicted_class_indexes = np.argmax(predictions, axis=1) - predicted_classes = [rf.classes_[i] for i in predicted_class_indexes] - - oob_score = np.mean(y == predicted_classes) - - return oob_score - - -def permutation_importance( - context: MLClientCtx, - model: DataItem, - dataset: DataItem, - labels: str, - figsz=(10, 5), - plots_dest: str = "plots", - fitype: str = "permute", -) -> pd.DataFrame: - """calculate change in metric - - type 'permute' uses a pre-estimated model - type 'dropcol' uses a re-estimates model - - :param context: the function's execution context - :param model: a trained model - :param dataset: features and ground truths, regression targets - :param labels name of the ground truths column - :param figsz: matplotlib figure size - :param plots_dest: path within artifact store - : - """ - model_file, model_data, _ = get_model(model.url, suffix=".pkl") - model = load(open(str(model_file), "rb")) - - X = dataset.as_df() - y = X.pop(labels) - header = X.columns - - metric = _oob_classifier_accuracy - - baseline = metric(model, X, y) - - imp = [] - for col in X.columns: - if fitype is "permute": - save = X[col].copy() - X[col] = np.random.permutation(X[col]) - m = metric(model, X, y) - X[col] = save - imp.append(baseline - m) - elif fitype is "dropcol": - X_ = X.drop(col, axis=1) - model_ = clone(model) - #model_.random_state = random_state - model_.fit(X_, y) - o = model_.oob_score_ - imp.append(baseline - o) - else: - raise ValueError("unknown fitype, only 'permute' or 'dropcol' permitted") - - zipped = zip(imp, header) - feature_imp = pd.DataFrame(sorted(zipped), columns=["importance", "feature"]) - feature_imp.sort_values(by="importance", ascending=False, inplace=True) - - plt.clf() - plt.figure(figsize=figsz) - sns.barplot(x="importance", y="feature", data=feature_imp) - plt.title(f"feature importances-{fitype}") - plt.tight_layout() - - context.log_artifact( - PlotArtifact(f"feature importances-{fitype}", body=plt.gcf()), - local_path=f"{plots_dest}/feature-permutations.html", - ) - context.log_dataset( - f"feature-importances-{fitype}-tbl", df=feature_imp, index=False - ) diff --git a/feature_perms/function.yaml b/feature_perms/function.yaml deleted file mode 100644 index 713981fdf..000000000 --- a/feature_perms/function.yaml +++ /dev/null @@ -1,63 +0,0 @@ -kind: job -metadata: - name: feature-perms - tag: '' - hash: 2e32234a73e2e48f029cf6c957b150ec2ffd4bc7 - project: '' - labels: - author: yjb - categories: - - data-analysis -spec: - command: '' - args: [] - image: mlrun/ml-models - env: [] - default_handler: permutation_importance - entry_points: - permutation_importance: - name: permutation_importance - doc: 'calculate change in metric - - - type ''permute'' uses a pre-estimated model - - type ''dropcol'' uses a re-estimates model' - parameters: - - name: context - type: MLClientCtx - doc: the function's execution context - default: '' - - name: model - type: DataItem - doc: a trained model - default: '' - - name: dataset - type: DataItem - doc: features and ground truths, regression targets - default: '' - - name: labels - type: str - default: '' - - name: figsz - doc: matplotlib figure size - default: - - 10 - - 5 - - name: plots_dest - type: str - doc: path within artifact store - default: plots - - name: fitype - type: str - default: permute - outputs: - - default: '' - lineno: 93 - description: estimate feature importances using permutations - build: - functionSourceCode: IyBHZW5lcmF0ZWQgYnkgbnVjbGlvLmV4cG9ydC5OdWNsaW9FeHBvcnRlcgoKaW1wb3J0IG51bXB5IGFzIG5wCmltcG9ydCBwYW5kYXMgYXMgcGQKaW1wb3J0IG51bWJlcnMKCmltcG9ydCBza2xlYXJuCmZyb20gc2tsZWFybi5iYXNlIGltcG9ydCBjbG9uZQpmcm9tIHNrbGVhcm4udXRpbHMgaW1wb3J0IGNoZWNrX3JhbmRvbV9zdGF0ZQoKaW1wb3J0IG1hdHBsb3RsaWIucHlwbG90IGFzIHBsdAppbXBvcnQgc2VhYm9ybiBhcyBzbnMKCmZyb20gY2xvdWRwaWNrbGUgaW1wb3J0IGxvYWQKCmZyb20gbWxydW4uZXhlY3V0aW9uIGltcG9ydCBNTENsaWVudEN0eApmcm9tIG1scnVuLmRhdGFzdG9yZSBpbXBvcnQgRGF0YUl0ZW0KZnJvbSBtbHJ1bi5hcnRpZmFjdHMgaW1wb3J0IGdldF9tb2RlbCwgUGxvdEFydGlmYWN0CmZyb20gdHlwaW5nIGltcG9ydCBVbmlvbiwgQ2FsbGFibGUsIExpc3QKCgpkZWYgX2dldF9uX3NhbXBsZXNfYm9vdHN0cmFwKG5fc2FtcGxlcywgbWF4X3NhbXBsZXMpIC0+IGludDoKICAgICIiImdldCB0aGUgbnVtYmVyIG9mIHNhbXBsZXMgaW4gYSBib290c3RyYXAgc2FtcGxlCgogICAgcmV0dXJucyB0aGUgdG90YWwgbnVtYmVyIG9mIHNhbXBsZXMgdG8gZHJhdyBmb3IgdGhlIGJvb3RzdHJhcCBzYW1wbGUKCiAgICBwcml2YXRlIGFwaSBpbiBza2xlYXJuID49IHYwLjI0LCB0YWtlbiBmcm9tIHNrbGVhcm4uZW5zZW1ibGUuX2ZvcmVzdC5weQoKICAgIDpwYXJhbSBuX3NhbXBsZXM6ICAgTnVtYmVyIG9mIHNhbXBsZXMgaW4gdGhlIGRhdGFzZXQuCiAgICA6cGFyYW0gbWF4X3NhbXBsZXM6CiAgICAgICAgVGhlIG1heGltdW0gbnVtYmVyIG9mIHNhbXBsZXMgdG8gZHJhdyBmcm9tIHRoZSB0b3RhbCBhdmFpbGFibGU6CiAgICAgICAgICAgIC0gaWYgZmxvYXQsIHRoaXMgaW5kaWNhdGVzIGEgZnJhY3Rpb24gb2YgdGhlIHRvdGFsIGFuZCBzaG91bGQgYmUKICAgICAgICAgICAgICB0aGUgaW50ZXJ2YWwgYCgwLCAxKWA7CiAgICAgICAgICAgIC0gaWYgaW50LCB0aGlzIGluZGljYXRlcyB0aGUgZXhhY3QgbnVtYmVyIG9mIHNhbXBsZXM7CiAgICAgICAgICAgIC0gaWYgTm9uZSwgdGhpcyBpbmRpY2F0ZXMgdGhlIHRvdGFsIG51bWJlciBvZiBzYW1wbGVzLgogICAgIiIiCiAgICBpZiBtYXhfc2FtcGxlcyBpcyBOb25lOgogICAgICAgIHJldHVybiBuX3NhbXBsZXMKCiAgICBpZiBpc2luc3RhbmNlKG1heF9zYW1wbGVzLCBudW1iZXJzLkludGVncmFsKToKICAgICAgICBpZiBub3QgKDEgPD0gbWF4X3NhbXBsZXMgPD0gbl9zYW1wbGVzKToKICAgICAgICAgICAgbXNnID0gImBtYXhfc2FtcGxlc2AgbXVzdCBiZSBpbiByYW5nZSAxIHRvIHt9IGJ1dCBnb3QgdmFsdWUge30iCiAgICAgICAgICAgIHJhaXNlIFZhbHVlRXJyb3IobXNnLmZvcm1hdChuX3NhbXBsZXMsIG1heF9zYW1wbGVzKSkKICAgICAgICByZXR1cm4gbWF4X3NhbXBsZXMKCiAgICBpZiBpc2luc3RhbmNlKG1heF9zYW1wbGVzLCBudW1iZXJzLlJlYWwpOgogICAgICAgIGlmIG5vdCAoMCA8IG1heF9zYW1wbGVzIDwgMSk6CiAgICAgICAgICAgIG1zZyA9ICJgbWF4X3NhbXBsZXNgIG11c3QgYmUgaW4gcmFuZ2UgKDAsIDEpIGJ1dCBnb3QgdmFsdWUge30iCiAgICAgICAgICAgIHJhaXNlIFZhbHVlRXJyb3IobXNnLmZvcm1hdChtYXhfc2FtcGxlcykpCiAgICAgICAgcmV0dXJuIGludChyb3VuZChuX3NhbXBsZXMgKiBtYXhfc2FtcGxlcykpCgogICAgbXNnID0gImBtYXhfc2FtcGxlc2Agc2hvdWxkIGJlIGludCBvciBmbG9hdCwgYnV0IGdvdCB0eXBlICd7fSciCiAgICByYWlzZSBUeXBlRXJyb3IobXNnLmZvcm1hdCh0eXBlKG1heF9zYW1wbGVzKSkpCgoKZGVmIF9nZXRfdW5zYW1wbGVkX2l4KHJhbmRvbV9zdGF0ZSwgbl9zYW1wbGVzOiBpbnQpIC0+IG5wLmFycmF5OgogICAgIiIiCiAgICBmdXR1cmUtcHJvb2YgZ2V0IHVuc2FtcGxlZCBpbmRpY2VzCiAgICAiIiIKICAgIG5fYm9vdHN0cmFwID0gX2dldF9uX3NhbXBsZXNfYm9vdHN0cmFwKG5fc2FtcGxlcywgbl9zYW1wbGVzKQogICAgcmFuZG9tX2luc3RhbmNlID0gY2hlY2tfcmFuZG9tX3N0YXRlKHJhbmRvbV9zdGF0ZSkKICAgIHNhbXBsZV9pbmRpY2VzID0gcmFuZG9tX2luc3RhbmNlLnJhbmRpbnQoMCwgbl9zYW1wbGVzLCBuX2Jvb3RzdHJhcCkKICAgIHNhbXBsZV9jb3VudHMgPSBucC5iaW5jb3VudChzYW1wbGVfaW5kaWNlcywgbWlubGVuZ3RoPW5fc2FtcGxlcykKCiAgICByZXR1cm4gbnAuYXJhbmdlKG5fc2FtcGxlcylbc2FtcGxlX2NvdW50cyA9PSAwXQoKCmRlZiBfb29iX2NsYXNzaWZpZXJfYWNjdXJhY3kocmYsIFhfdHJhaW4sIHlfdHJhaW4pIC0+IGZsb2F0OgogICAgIiIiCiAgICBDb21wdXRlIG91dC1vZi1iYWcgKE9PQikgYWNjdXJhY3kgZm9yIGEgc2Npa2l0LWxlYXJuIGZvcmVzdCBjbGFzc2lmaWVyLgoKICAgIGh0dHBzOi8vZ2l0aHViLmNvbS9zY2lraXQtbGVhcm4vc2Npa2l0LWxlYXJuL2Jsb2IvYTI0YzhiNDYvc2tsZWFybi9lbnNlbWJsZS9mb3Jlc3QucHkjTDQyNQogICAgIiIiCiAgICBYID0gWF90cmFpbi52YWx1ZXMgaWYgaXNpbnN0YW5jZShYX3RyYWluLCBwZC5EYXRhRnJhbWUpIGVsc2UgWF90cmFpbgogICAgeSA9IHlfdHJhaW4udmFsdWVzIGlmIGlzaW5zdGFuY2UoeV90cmFpbiwgcGQuU2VyaWVzKSBlbHNlIHlfdHJhaW4KCiAgICBuX3NhbXBsZXMgPSBsZW4oWCkKICAgIG5fY2xhc3NlcyA9IGxlbihucC51bmlxdWUoeSkpCiAgICBwcmVkaWN0aW9ucyA9IG5wLnplcm9zKChuX3NhbXBsZXMsIG5fY2xhc3NlcykpCiAgICBmb3IgdHJlZSBpbiByZi5lc3RpbWF0b3JzXzoKICAgICAgICB1bnNhbXBsZWRfaW5kaWNlcyA9IF9nZXRfdW5zYW1wbGVkX2l4KHRyZWUucmFuZG9tX3N0YXRlLCBuX3NhbXBsZXMpCiAgICAgICAgdHJlZV9wcmVkcyA9IHRyZWUucHJlZGljdF9wcm9iYShYW3Vuc2FtcGxlZF9pbmRpY2VzLCA6XSkKICAgICAgICBwcmVkaWN0aW9uc1t1bnNhbXBsZWRfaW5kaWNlc10gKz0gdHJlZV9wcmVkcwoKICAgIHByZWRpY3RlZF9jbGFzc19pbmRleGVzID0gbnAuYXJnbWF4KHByZWRpY3Rpb25zLCBheGlzPTEpCiAgICBwcmVkaWN0ZWRfY2xhc3NlcyA9IFtyZi5jbGFzc2VzX1tpXSBmb3IgaSBpbiBwcmVkaWN0ZWRfY2xhc3NfaW5kZXhlc10KCiAgICBvb2Jfc2NvcmUgPSBucC5tZWFuKHkgPT0gcHJlZGljdGVkX2NsYXNzZXMpCgogICAgcmV0dXJuIG9vYl9zY29yZQoKCmRlZiBwZXJtdXRhdGlvbl9pbXBvcnRhbmNlKAogICAgY29udGV4dDogTUxDbGllbnRDdHgsCiAgICBtb2RlbDogRGF0YUl0ZW0sCiAgICBkYXRhc2V0OiBEYXRhSXRlbSwKICAgIGxhYmVsczogc3RyLAogICAgZmlnc3o9KDEwLCA1KSwKICAgIHBsb3RzX2Rlc3Q6IHN0ciA9ICJwbG90cyIsCiAgICBmaXR5cGU6IHN0ciA9ICJwZXJtdXRlIiwKKSAtPiBwZC5EYXRhRnJhbWU6CiAgICAiIiJjYWxjdWxhdGUgY2hhbmdlIGluIG1ldHJpYwoKICAgIHR5cGUgJ3Blcm11dGUnIHVzZXMgYSBwcmUtZXN0aW1hdGVkIG1vZGVsCiAgICB0eXBlICdkcm9wY29sJyB1c2VzIGEgcmUtZXN0aW1hdGVzIG1vZGVsCgogICAgOnBhcmFtIGNvbnRleHQ6ICAgICB0aGUgZnVuY3Rpb24ncyBleGVjdXRpb24gY29udGV4dAogICAgOnBhcmFtIG1vZGVsOiAgICAgICBhIHRyYWluZWQgbW9kZWwKICAgIDpwYXJhbSBkYXRhc2V0OiAgICAgZmVhdHVyZXMgYW5kIGdyb3VuZCB0cnV0aHMsIHJlZ3Jlc3Npb24gdGFyZ2V0cwogICAgOnBhcmFtIGxhYmVscyAgICAgICBuYW1lIG9mIHRoZSBncm91bmQgdHJ1dGhzIGNvbHVtbgogICAgOnBhcmFtIGZpZ3N6OiAgICAgICBtYXRwbG90bGliIGZpZ3VyZSBzaXplCiAgICA6cGFyYW0gcGxvdHNfZGVzdDogIHBhdGggd2l0aGluIGFydGlmYWN0IHN0b3JlCiAgICA6CiAgICAiIiIKICAgIG1vZGVsX2ZpbGUsIG1vZGVsX2RhdGEsIF8gPSBnZXRfbW9kZWwobW9kZWwudXJsLCBzdWZmaXg9Ii5wa2wiKQogICAgbW9kZWwgPSBsb2FkKG9wZW4oc3RyKG1vZGVsX2ZpbGUpLCAicmIiKSkKCiAgICBYID0gZGF0YXNldC5hc19kZigpCiAgICB5ID0gWC5wb3AobGFiZWxzKQogICAgaGVhZGVyID0gWC5jb2x1bW5zCgogICAgbWV0cmljID0gX29vYl9jbGFzc2lmaWVyX2FjY3VyYWN5CgogICAgYmFzZWxpbmUgPSBtZXRyaWMobW9kZWwsIFgsIHkpCgogICAgaW1wID0gW10KICAgIGZvciBjb2wgaW4gWC5jb2x1bW5zOgogICAgICAgIGlmIGZpdHlwZSBpcyAicGVybXV0ZSI6CiAgICAgICAgICAgIHNhdmUgPSBYW2NvbF0uY29weSgpCiAgICAgICAgICAgIFhbY29sXSA9IG5wLnJhbmRvbS5wZXJtdXRhdGlvbihYW2NvbF0pCiAgICAgICAgICAgIG0gPSBtZXRyaWMobW9kZWwsIFgsIHkpCiAgICAgICAgICAgIFhbY29sXSA9IHNhdmUKICAgICAgICAgICAgaW1wLmFwcGVuZChiYXNlbGluZSAtIG0pCiAgICAgICAgZWxpZiBmaXR5cGUgaXMgImRyb3Bjb2wiOgogICAgICAgICAgICBYXyA9IFguZHJvcChjb2wsIGF4aXM9MSkKICAgICAgICAgICAgbW9kZWxfID0gY2xvbmUobW9kZWwpCiAgICAgICAgICAgICNtb2RlbF8ucmFuZG9tX3N0YXRlID0gcmFuZG9tX3N0YXRlCiAgICAgICAgICAgIG1vZGVsXy5maXQoWF8sIHkpCiAgICAgICAgICAgIG8gPSBtb2RlbF8ub29iX3Njb3JlXwogICAgICAgICAgICBpbXAuYXBwZW5kKGJhc2VsaW5lIC0gbykKICAgICAgICBlbHNlOgogICAgICAgICAgICByYWlzZSBWYWx1ZUVycm9yKCJ1bmtub3duIGZpdHlwZSwgb25seSAncGVybXV0ZScgb3IgJ2Ryb3Bjb2wnIHBlcm1pdHRlZCIpCgogICAgemlwcGVkID0gemlwKGltcCwgaGVhZGVyKQogICAgZmVhdHVyZV9pbXAgPSBwZC5EYXRhRnJhbWUoc29ydGVkKHppcHBlZCksIGNvbHVtbnM9WyJpbXBvcnRhbmNlIiwgImZlYXR1cmUiXSkKICAgIGZlYXR1cmVfaW1wLnNvcnRfdmFsdWVzKGJ5PSJpbXBvcnRhbmNlIiwgYXNjZW5kaW5nPUZhbHNlLCBpbnBsYWNlPVRydWUpCgogICAgcGx0LmNsZigpCiAgICBwbHQuZmlndXJlKGZpZ3NpemU9Zmlnc3opCiAgICBzbnMuYmFycGxvdCh4PSJpbXBvcnRhbmNlIiwgeT0iZmVhdHVyZSIsIGRhdGE9ZmVhdHVyZV9pbXApCiAgICBwbHQudGl0bGUoZiJmZWF0dXJlIGltcG9ydGFuY2VzLXtmaXR5cGV9IikKICAgIHBsdC50aWdodF9sYXlvdXQoKQoKICAgIGNvbnRleHQubG9nX2FydGlmYWN0KAogICAgICAgIFBsb3RBcnRpZmFjdChmImZlYXR1cmUgaW1wb3J0YW5jZXMte2ZpdHlwZX0iLCBib2R5PXBsdC5nY2YoKSksCiAgICAgICAgbG9jYWxfcGF0aD1mIntwbG90c19kZXN0fS9mZWF0dXJlLXBlcm11dGF0aW9ucy5odG1sIiwKICAgICkKICAgIGNvbnRleHQubG9nX2RhdGFzZXQoCiAgICAgICAgZiJmZWF0dXJlLWltcG9ydGFuY2VzLXtmaXR5cGV9LXRibCIsIGRmPWZlYXR1cmVfaW1wLCBpbmRleD1GYWxzZQogICAgKQo= - commands: [] - code_origin: https://github.com/daniels290813/functions.git#55a79c32be5d233cc11efcf40cd3edbe309bfdef:/home/kali/functions/feature_perms/feature_perms.py - affinity: null -verbose: false diff --git a/feature_perms/item.yaml b/feature_perms/item.yaml deleted file mode 100644 index bd909d3ee..000000000 --- a/feature_perms/item.yaml +++ /dev/null @@ -1,25 +0,0 @@ -apiVersion: v1 -categories: -- data-analysis -description: estimate feature importances using permutations -doc: '' -example: feature_perms.ipynb -generationDate: 2022-08-28:17-25 -hidden: false -icon: '' -labels: - author: yjb -maintainers: [] -marketplaceType: '' -mlrunVersion: 1.1.0 -name: feature-perms -platformVersion: 3.5.0 -spec: - filename: feature_perms.py - handler: permutation_importance - image: mlrun/ml-models - kind: job - requirements: [] -url: '' -version: 1.1.0 -test_valid : False diff --git a/feature_perms/requirements.txt b/feature_perms/requirements.txt deleted file mode 100644 index 70a079c7d..000000000 --- a/feature_perms/requirements.txt +++ /dev/null @@ -1,5 +0,0 @@ -scikit-learn -matplotlib -seaborn -scikit-plot - diff --git a/feature_perms/test_feature_perms.py b/feature_perms/test_feature_perms.py deleted file mode 100644 index a59891ea8..000000000 --- a/feature_perms/test_feature_perms.py +++ /dev/null @@ -1,134 +0,0 @@ -# Copyright 2019 Iguazio -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -from mlrun import code_to_function, import_function -from pathlib import Path -import os - -ARTIFACTS_PATH = 'artifacts' -DATA_URL = "https://raw.githubusercontent.com/parrt/random-forest-importances/master/notebooks/data/rent.csv" -FEATURE_OUTPUT = "feature-importances-permute-tbl" - - -def arc_to_parquet(): - from mlrun import import_function - - archive_func = import_function('hub://arc_to_parquet') - - archive_run = archive_func.run( - handler="arc_to_parquet", - params={"key": "rent", "stats": True, "file_ext": "csv"}, - inputs={"archive_url": DATA_URL}, - artifact_path=os.getcwd() + '/artifacts', - local=True, - ) - - return archive_run.artifact('rent').url - - -def sklearn_classifier(run): - cwd = os.getcwd() - file_path = str(Path(cwd).parent.absolute()) + "/sklearn_classifier/sklearn_classifier.py" - fn = code_to_function( - name='test_sklearn_classifier', - filename=file_path, - handler="train_model", - kind="local", - ) - - fn.spec.command = file_path - fn.run( - params={ - "sample": -5_000, # 5k random rows, - "model_pkg_class": "sklearn.ensemble.RandomForestClassifier", - "label_column": "interest_level", - "CLASS_n_estimators": 100, - "CLASS_min_samples_leaf": 1, - "CLASS_n_jobs": -1, - "CLASS_oob_score": True, - }, - handler="train_model", - inputs={"dataset": run.outputs["rent"]}, - artifact_path='artifacts', - ) - - -def train_model(data): - from mlrun import import_function - - train = import_function('hub://sklearn_classifier') - - train_run = train.run( - inputs={"dataset": data}, - params={ - "sample": -5_000, # 5k random rows, - "model_pkg_class": "sklearn.ensemble.RandomForestClassifier", - "label_column": "interest_level", - "CLASS_n_estimators": 100, - "CLASS_min_samples_leaf": 1, - "CLASS_n_jobs": -1, - "CLASS_oob_score": True, - }, - local=True - ) - - return train_run.artifact('model').url - - -def test_feature_selection_run_local(): - data = arc_to_parquet() - model = train_model(data) - labels = "interest_level" - fn = code_to_function( - name='test_run_local_feature_perms', - filename="feature_perms.py", - handler="permutation_importance", - kind="local", - ) - fn.spec.command = "feature_perms.py" - - run = fn.run( - params={ - "labels": labels, - "plots_dest": "plots", - }, - inputs={ - "model": model, - "dataset": data, - }, - artifact_path='artifacts', - ) - - assert run.artifact(FEATURE_OUTPUT).get() - - -def test_feature_perms_import_function(): - data = arc_to_parquet() - model = train_model(data) - labels = "interest_level" - fn = import_function("function.yaml") - - run = fn.run( - params={ - "labels": labels, - "plots_dest": "plots" - }, - inputs={ - "model": model, - "dataset": data}, - artifact_path=os.getcwd() + '/artifacts', - local=True, - ) - - assert run.artifact(FEATURE_OUTPUT).get() diff --git a/feature_selection/function.yaml b/feature_selection/function.yaml index aca1f0c0c..44cdd9894 100644 --- a/feature_selection/function.yaml +++ b/feature_selection/function.yaml @@ -1,51 +1,35 @@ -kind: job metadata: name: feature-selection tag: '' - hash: 5815ef4c27a1f08c9d8d3f88ad6bd4c9cb5c7f4a - project: '' - labels: - author: orz categories: - data-preparation - machine-learning +kind: job spec: - command: '' - args: [] - image: mlrun/mlrun - build: - functionSourceCode: IyBDb3B5cmlnaHQgMjAxOSBJZ3VhemlvCiMKIyBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgIkxpY2Vuc2UiKTsKIyB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiMgWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0CiMKIyAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wCiMKIyBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlCiMgZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gIkFTIElTIiBCQVNJUywKIyBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KIyBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kCiMgbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuCiMKaW1wb3J0IGpzb24KCmltcG9ydCBtbHJ1bgppbXBvcnQgbWxydW4uZGF0YXN0b3JlCmltcG9ydCBtbHJ1bi5mZWF0dXJlX3N0b3JlIGFzIGZzCmltcG9ydCBtbHJ1bi51dGlscwppbXBvcnQgbnVtcHkgYXMgbnAKaW1wb3J0IHBhbmRhcyBhcyBwZAppbXBvcnQgcGxvdGx5LmV4cHJlc3MgYXMgcHgKZnJvbSBtbHJ1bi5hcnRpZmFjdHMgaW1wb3J0IFBsb3RseUFydGlmYWN0CmZyb20gbWxydW4uZGF0YXN0b3JlLnRhcmdldHMgaW1wb3J0IFBhcnF1ZXRUYXJnZXQKIyBNTFJ1biB1dGlscwpmcm9tIG1scnVuLnV0aWxzLmhlbHBlcnMgaW1wb3J0IGNyZWF0ZV9jbGFzcwojIEZlYXR1cmUgc2VsZWN0aW9uIHN0cmF0ZWdpZXMKZnJvbSBza2xlYXJuLmZlYXR1cmVfc2VsZWN0aW9uIGltcG9ydCBTZWxlY3RGcm9tTW9kZWwsIFNlbGVjdEtCZXN0CiMgU2NhbGUgZmVhdHVyZSBzY29yZXNnaXQgc3QKZnJvbSBza2xlYXJuLnByZXByb2Nlc3NpbmcgaW1wb3J0IE1pbk1heFNjYWxlcgojIFNLTGVhcm4gZXN0aW1hdG9ycyBsaXN0CmZyb20gc2tsZWFybi51dGlscyBpbXBvcnQgYWxsX2VzdGltYXRvcnMKCkRFRkFVTFRfU1RBVF9GSUxURVJTID0gWyJmX2NsYXNzaWYiLCAibXV0dWFsX2luZm9fY2xhc3NpZiIsICJjaGkyIiwgImZfcmVncmVzc2lvbiJdCkRFRkFVTFRfTU9ERUxfRklMVEVSUyA9IHsKICAgICJMaW5lYXJTVkMiOiAiTGluZWFyU1ZDIiwKICAgICJMb2dpc3RpY1JlZ3Jlc3Npb24iOiAiTG9naXN0aWNSZWdyZXNzaW9uIiwKICAgICJFeHRyYVRyZWVzQ2xhc3NpZmllciI6ICJFeHRyYVRyZWVzQ2xhc3NpZmllciIsCn0KCgpkZWYgc2hvd192YWx1ZXNfb25fYmFycyhheHMsIGhfdj0idiIsIHNwYWNlPTAuNCk6CiAgICBkZWYgX3Nob3dfb25fc2luZ2xlX3Bsb3QoYXhfKToKICAgICAgICBpZiBoX3YgPT0gInYiOgogICAgICAgICAgICBmb3IgcCBpbiBheF8ucGF0Y2hlczoKICAgICAgICAgICAgICAgIF94ID0gcC5nZXRfeCgpICsgcC5nZXRfd2lkdGgoKSAvIDIKICAgICAgICAgICAgICAgIF95ID0gcC5nZXRfeSgpICsgcC5nZXRfaGVpZ2h0KCkKICAgICAgICAgICAgICAgIHZhbHVlID0gaW50KHAuZ2V0X2hlaWdodCgpKQogICAgICAgICAgICAgICAgYXhfLnRleHQoX3gsIF95LCB2YWx1ZSwgaGE9ImNlbnRlciIpCiAgICAgICAgZWxpZiBoX3YgPT0gImgiOgogICAgICAgICAgICBmb3IgcCBpbiBheF8ucGF0Y2hlczoKICAgICAgICAgICAgICAgIF94ID0gcC5nZXRfeCgpICsgcC5nZXRfd2lkdGgoKSArIGZsb2F0KHNwYWNlKQogICAgICAgICAgICAgICAgX3kgPSBwLmdldF95KCkgKyBwLmdldF9oZWlnaHQoKQogICAgICAgICAgICAgICAgdmFsdWUgPSBpbnQocC5nZXRfd2lkdGgoKSkKICAgICAgICAgICAgICAgIGF4Xy50ZXh0KF94LCBfeSwgdmFsdWUsIGhhPSJsZWZ0IikKCiAgICBpZiBpc2luc3RhbmNlKGF4cywgbnAubmRhcnJheSk6CiAgICAgICAgZm9yIGlkeCwgYXggaW4gbnAubmRlbnVtZXJhdGUoYXhzKToKICAgICAgICAgICAgX3Nob3dfb25fc2luZ2xlX3Bsb3QoYXgpCiAgICBlbHNlOgogICAgICAgIF9zaG93X29uX3NpbmdsZV9wbG90KGF4cykKCgpkZWYgcGxvdF9zdGF0KGNvbnRleHQsIHN0YXRfbmFtZSwgc3RhdF9kZik6CiAgICBzb3J0ZWRfZGYgPSBzdGF0X2RmLnNvcnRfdmFsdWVzKHN0YXRfbmFtZSkKICAgIGZpZyA9IHB4LmJhcigKICAgICAgICBkYXRhX2ZyYW1lPXNvcnRlZF9kZiwKICAgICAgICB4PXN0YXRfbmFtZSwKICAgICAgICB5PXNvcnRlZF9kZi5pbmRleCwKICAgICAgICB0aXRsZT1mIntzdGF0X25hbWV9IGZlYXR1cmUgc2NvcmVzIiwKICAgICAgICBjb2xvcj1zdGF0X25hbWUsCiAgICApCiAgICBjb250ZXh0LmxvZ19hcnRpZmFjdCgKICAgICAgICBpdGVtPVBsb3RseUFydGlmYWN0KGtleT1zdGF0X25hbWUsIGZpZ3VyZT1maWcpLAogICAgICAgIGxvY2FsX3BhdGg9ZiJ7c3RhdF9uYW1lfS5odG1sIiwKICAgICkKCgpkZWYgZmVhdHVyZV9zZWxlY3Rpb24oCiAgICBjb250ZXh0LAogICAgZGZfYXJ0aWZhY3QsCiAgICBrOiBpbnQgPSA1LAogICAgbWluX3ZvdGVzOiBmbG9hdCA9IDAuNSwKICAgIGxhYmVsX2NvbHVtbjogc3RyID0gTm9uZSwKICAgIHN0YXRfZmlsdGVyczogbGlzdCA9IE5vbmUsCiAgICBtb2RlbF9maWx0ZXJzOiBkaWN0ID0gTm9uZSwKICAgIG1heF9zY2FsZWRfc2NvcmVzOiBib29sID0gVHJ1ZSwKICAgIHNhbXBsZV9yYXRpbzogZmxvYXQgPSBOb25lLAogICAgb3V0cHV0X3ZlY3Rvcl9uYW1lOiBmbG9hdCA9IE5vbmUsCiAgICBpZ25vcmVfdHlwZV9lcnJvcnM6IGJvb2wgPSBGYWxzZSwKKToKICAgICIiIgogICAgQXBwbGllcyBzZWxlY3RlZCBmZWF0dXJlIHNlbGVjdGlvbiBzdGF0aXN0aWNhbCBmdW5jdGlvbnMgb3IgbW9kZWxzIG9uIG91ciAnZGZfYXJ0aWZhY3QnLgoKICAgIEVhY2ggc3RhdGlzdGljYWwgZnVuY3Rpb24gb3IgbW9kZWwgd2lsbCB2b3RlIGZvciBpdCdzIGJlc3QgSyBzZWxlY3RlZCBmZWF0dXJlcy4KICAgIElmIGEgZmVhdHVyZSBoYXMgPj0gJ21pbl92b3Rlcycgdm90ZXMsIGl0IHdpbGwgYmUgc2VsZWN0ZWQuCgogICAgOnBhcmFtIGNvbnRleHQ6ICAgICAgICAgICAgIHRoZSBmdW5jdGlvbiBjb250ZXh0LgogICAgOnBhcmFtIGRmX2FydGlmYWN0OiAgICAgICAgIGRhdGFmcmFtZSB0byBwYXNzIGFzIGlucHV0LgogICAgOnBhcmFtIGs6ICAgICAgICAgICAgICAgICAgIG51bWJlciBvZiB0b3AgZmVhdHVyZXMgdG8gc2VsZWN0IGZyb20gZWFjaCBzdGF0aXN0aWNhbAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uIG9yIG1vZGVsLgogICAgOnBhcmFtIG1pbl92b3RlczogICAgICAgICAgIG1pbmltYWwgbnVtYmVyIG9mIHZvdGVzIChmcm9tIGEgbW9kZWwgb3IgYnkgc3RhdGlzdGljYWwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbikgbmVlZGVkIGZvciBhIGZlYXR1cmUgdG8gYmUgc2VsZWN0ZWQuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQ2FuIGJlIHNwZWNpZmllZCBieSBwZXJjZW50YWdlIG9mIHZvdGVzIG9yIGFic29sdXRlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbnVtYmVyIG9mIHZvdGVzLgogICAgOnBhcmFtIGxhYmVsX2NvbHVtbjogICAgICAgIGdyb3VuZC10cnV0aCAoeSkgbGFiZWxzLgogICAgOnBhcmFtIHN0YXRfZmlsdGVyczogICAgICAgIHN0YXRpc3RpY2FsIGZ1bmN0aW9ucyB0byBhcHBseSB0byB0aGUgZmVhdHVyZXMKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoZnJvbSBza2xlYXJuLmZlYXR1cmVfc2VsZWN0aW9uKS4KICAgIDpwYXJhbSBtb2RlbF9maWx0ZXJzOiAgICAgICBtb2RlbHMgdG8gdXNlIGZvciBmZWF0dXJlIGV2YWx1YXRpb24sIGNhbiBiZSBzcGVjaWZpZWQgYnkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlbCBuYW1lIChleC4gTGluZWFyU1ZDKSwgZm9ybWFsaXplZCBqc29uIChjb250YWlucyAnQ0xBU1MnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdGSVQnLCAnTUVUQScpIG9yIGEgcGF0aCB0byBzdWNoIGpzb24gZmlsZS4KICAgIDpwYXJhbSBtYXhfc2NhbGVkX3Njb3JlczogICBwcm9kdWNlIGZlYXR1cmUgc2NvcmVzIHRhYmxlIHNjYWxlZCB3aXRoIG1heF9zY2FsZXIuCiAgICA6cGFyYW0gc2FtcGxlX3JhdGlvOiAgICAgICAgcGVyY2VudGFnZSBvZiB0aGUgZGF0YXNldCB0aGUgdXNlciB3aXNoZXMgdG8gY29tcHV0ZSB0aGUgZmVhdHVyZSBzZWxlY3Rpb24gcHJvY2VzcyBvbi4KICAgIDpwYXJhbSBvdXRwdXRfdmVjdG9yX25hbWU6ICBjcmVhdGVzIGEgbmV3IGZlYXR1cmUgdmVjdG9yIGNvbnRhaW5pbmcgb25seSB0aGUgaWRlbnRpZmllcyBmZWF0dXJlcy4KICAgIDpwYXJhbSBpZ25vcmVfdHlwZV9lcnJvcnM6ICBza2lwcyBkYXRhdHlwZXMgdGhhdCBhcmUgbmVpdGhlciBmbG9hdCBub3IgaW50IHdpdGhpbiB0aGUgZmVhdHVyZSB2ZWN0b3IuCiAgICAiIiIKICAgIHN0YXRfZmlsdGVycyA9IHN0YXRfZmlsdGVycyBvciBERUZBVUxUX1NUQVRfRklMVEVSUwogICAgbW9kZWxfZmlsdGVycyA9IG1vZGVsX2ZpbHRlcnMgb3IgREVGQVVMVF9NT0RFTF9GSUxURVJTCiAgICAjIENoZWNrIGlmIGRmLm1ldGEgaXMgdmFsaWQsIGlmIGl0IGlzLCBsb29rIGZvciBhIGZlYXR1cmUgdmVjdG9yCiAgICBzdG9yZV91cmlfcHJlZml4LCBfID0gbWxydW4uZGF0YXN0b3JlLnBhcnNlX3N0b3JlX3VyaShkZl9hcnRpZmFjdC5hcnRpZmFjdF91cmwpCiAgICBpc19mZWF0dXJlX3ZlY3RvciA9IG1scnVuLnV0aWxzLlN0b3JlUHJlZml4LkZlYXR1cmVWZWN0b3IgPT0gc3RvcmVfdXJpX3ByZWZpeAoKICAgICMgTG9vayBpbnNpZGUgbWV0YS5zcGVjLmxhYmVsX2ZlYXR1cmUgdG8gaWRlbnRpZnkgdGhlIGxhYmVsX2NvbHVtbiBpZiB0aGUgdXNlciBkaWQgbm90IHNwZWNpZnkgaXQKICAgIGlmIGxhYmVsX2NvbHVtbiBpcyBOb25lOgogICAgICAgIGlmIGlzX2ZlYXR1cmVfdmVjdG9yOgogICAgICAgICAgICBsYWJlbF9jb2x1bW4gPSBkZl9hcnRpZmFjdC5tZXRhLnNwZWMubGFiZWxfZmVhdHVyZS5zcGxpdCgiLiIpWzFdCiAgICAgICAgZWxzZToKICAgICAgICAgICAgcmFpc2UgVmFsdWVFcnJvcigiTm8gbGFiZWxfY29sdW1uIHdhcyBnaXZlbiwgcGxlYXNlIGFkZCBhIGxhYmVsX2NvbHVtbi4iKQoKICAgICMgVXNlIHRoZSBmZWF0dXJlIHZlY3RvciBhcyBkYXRhZnJhbWUKICAgIGRmID0gZGZfYXJ0aWZhY3QuYXNfZGYoKQoKICAgICMgRW5zdXJlIGsgaXMgbm90IGJpZ2dlciB0aGFuIHRoZSB0b3RhbCBudW1iZXIgb2YgZmVhdHVyZXMKICAgIGlmIGsgPiBkZi5zaGFwZVsxXToKICAgICAgICByYWlzZSBWYWx1ZUVycm9yKAogICAgICAgICAgICBmIksgY2Fubm90IGJlIGJpZ2dlciB0aGFuIHRoZSB0b3RhbCBudW1iZXIgb2YgZmVhdHVyZXMgKHtkZi5zaGFwZVsxXX0pLiBQbGVhc2UgY2hvb3NlIGEgc21hbGxlciBLLiIKICAgICAgICApCiAgICBlbGlmIGsgPCAxOgogICAgICAgIHJhaXNlIFZhbHVlRXJyb3IoIksgY2Fubm90IGJlIHNtYWxsZXIgdGhhbiAxLiBQbGVhc2UgY2hvb3NlIGEgYmlnZ2VyIEsuIikKCiAgICAjIENyZWF0ZSBhIHNhbXBsZSBkYXRhZnJhbWUgb2YgdGhlIG9yaWdpbmFsIGZlYXR1cmUgdmVjdG9yCiAgICBpZiBzYW1wbGVfcmF0aW86CiAgICAgICAgZGYgPSAoCiAgICAgICAgICAgIGRmLmdyb3VwYnkobGFiZWxfY29sdW1uKQogICAgICAgICAgICAuYXBwbHkobGFtYmRhIHg6IHguc2FtcGxlKGZyYWM9c2FtcGxlX3JhdGlvKSkKICAgICAgICAgICAgLnJlc2V0X2luZGV4KGRyb3A9VHJ1ZSkKICAgICAgICApCiAgICAgICAgZGYgPSBkZi5kcm9wbmEoKQoKICAgICMgU2V0IGZlYXR1cmUgdmVjdG9yIGFuZCBsYWJlbHMKICAgIHkgPSBkZi5wb3AobGFiZWxfY29sdW1uKQogICAgWCA9IGRmCgogICAgaWYgbnAub2JqZWN0XyBpbiBsaXN0KFguZHR5cGVzKSBhbmQgaWdub3JlX3R5cGVfZXJyb3JzIGlzIEZhbHNlOgogICAgICAgIHJhaXNlIFZhbHVlRXJyb3IoCiAgICAgICAgICAgIGYie2RmLnNlbGVjdF9kdHlwZXMoaW5jbHVkZT1bJ29iamVjdCddKS5jb2x1bW5zLnRvbGlzdCgpfSBhcmUgbmVpdGhlciBmbG9hdCBvciBpbnQuIgogICAgICAgICkKCiAgICAjIENyZWF0ZSBzZWxlY3RlZCBzdGF0aXN0aWNhbCBlc3RpbWF0b3JzCiAgICBzdGF0X2Z1bmN0aW9uc19saXN0ID0gewogICAgICAgIHN0YXRfbmFtZTogU2VsZWN0S0Jlc3QoCiAgICAgICAgICAgIHNjb3JlX2Z1bmM9Y3JlYXRlX2NsYXNzKGYic2tsZWFybi5mZWF0dXJlX3NlbGVjdGlvbi57c3RhdF9uYW1lfSIpLCBrPWsKICAgICAgICApCiAgICAgICAgZm9yIHN0YXRfbmFtZSBpbiBzdGF0X2ZpbHRlcnMKICAgIH0KICAgIHJlcXVpcmVzX2FicyA9IFsiY2hpMiJdCgogICAgIyBSdW4gc3RhdGlzdGljIGZpbHRlcnMKICAgIHNlbGVjdGVkX2ZlYXR1cmVzX2FnZyA9IHt9CiAgICBzdGF0c19kZiA9IHBkLkRhdGFGcmFtZShpbmRleD1YLmNvbHVtbnMpLmRyb3BuYSgpCgogICAgZm9yIHN0YXRfbmFtZSwgc3RhdF9mdW5jIGluIHN0YXRfZnVuY3Rpb25zX2xpc3QuaXRlbXMoKToKICAgICAgICB0cnk6CiAgICAgICAgICAgIHBhcmFtcyA9IChYLCB5KSBpZiBzdGF0X25hbWUgaW4gcmVxdWlyZXNfYWJzIGVsc2UgKGFicyhYKSwgeSkKICAgICAgICAgICAgc3RhdCA9IHN0YXRfZnVuYy5maXQoKnBhcmFtcykKCiAgICAgICAgICAgICMgQ29sbGVjdCBzdGF0IGZ1bmN0aW9uIHJlc3VsdHMKICAgICAgICAgICAgc3RhdF9kZiA9IHBkLkRhdGFGcmFtZSgKICAgICAgICAgICAgICAgIGluZGV4PVguY29sdW1ucywgY29sdW1ucz1bc3RhdF9uYW1lXSwgZGF0YT1zdGF0LnNjb3Jlc18KICAgICAgICAgICAgKQogICAgICAgICAgICBwbG90X3N0YXQoY29udGV4dCwgc3RhdF9uYW1lLCBzdGF0X2RmKQogICAgICAgICAgICBzdGF0c19kZiA9IHN0YXRzX2RmLmpvaW4oc3RhdF9kZikKCiAgICAgICAgICAgICMgU2VsZWN0IEsgQmVzdCBmZWF0dXJlcwogICAgICAgICAgICBzZWxlY3RlZF9mZWF0dXJlcyA9IFguY29sdW1uc1tzdGF0X2Z1bmMuZ2V0X3N1cHBvcnQoKV0KICAgICAgICAgICAgc2VsZWN0ZWRfZmVhdHVyZXNfYWdnW3N0YXRfbmFtZV0gPSBzZWxlY3RlZF9mZWF0dXJlcwoKICAgICAgICBleGNlcHQgRXhjZXB0aW9uIGFzIGU6CiAgICAgICAgICAgIGNvbnRleHQubG9nZ2VyLmluZm8oZiJDb3VsZG4ndCBjYWxjdWxhdGUge3N0YXRfbmFtZX0gYmVjYXVzZSBvZjoge2V9IikKCiAgICAjIENyZWF0ZSBtb2RlbHMgZnJvbSBjbGFzcyBuYW1lIC8ganNvbiBmaWxlIC8ganNvbiBwYXJhbXMKICAgIGFsbF9za2xlYXJuX2VzdGltYXRvcnMgPSBkaWN0KGFsbF9lc3RpbWF0b3JzKCkpIGlmIGxlbihtb2RlbF9maWx0ZXJzKSA+IDAgZWxzZSB7fQogICAgc2VsZWN0ZWRfbW9kZWxzID0ge30KICAgIGZvciBtb2RlbF9uYW1lLCBtb2RlbCBpbiBtb2RlbF9maWx0ZXJzLml0ZW1zKCk6CiAgICAgICAgaWYgIi5qc29uIiBpbiBtb2RlbDoKICAgICAgICAgICAgY3VycmVudF9tb2RlbCA9IGpzb24ubG9hZChvcGVuKG1vZGVsLCAiciIpKQogICAgICAgICAgICBjbGFzc2lmaWVyX2NsYXNzID0gY3JlYXRlX2NsYXNzKGN1cnJlbnRfbW9kZWxbIk1FVEEiXVsiY2xhc3MiXSkKICAgICAgICAgICAgc2VsZWN0ZWRfbW9kZWxzW21vZGVsX25hbWVdID0gY2xhc3NpZmllcl9jbGFzcygqKmN1cnJlbnRfbW9kZWxbIkNMQVNTIl0pCiAgICAgICAgZWxpZiBtb2RlbCBpbiBhbGxfc2tsZWFybl9lc3RpbWF0b3JzOgogICAgICAgICAgICBzZWxlY3RlZF9tb2RlbHNbbW9kZWxfbmFtZV0gPSBhbGxfc2tsZWFybl9lc3RpbWF0b3JzW21vZGVsX25hbWVdKCkKCiAgICAgICAgZWxzZToKICAgICAgICAgICAgdHJ5OgogICAgICAgICAgICAgICAgY3VycmVudF9tb2RlbCA9IGpzb24ubG9hZHMobW9kZWwpCiAgICAgICAgICAgICAgICBjbGFzc2lmaWVyX2NsYXNzID0gY3JlYXRlX2NsYXNzKGN1cnJlbnRfbW9kZWxbIk1FVEEiXVsiY2xhc3MiXSkKICAgICAgICAgICAgICAgIHNlbGVjdGVkX21vZGVsc1ttb2RlbF9uYW1lXSA9IGNsYXNzaWZpZXJfY2xhc3MoKipjdXJyZW50X21vZGVsWyJDTEFTUyJdKQogICAgICAgICAgICBleGNlcHQgRXhjZXB0aW9uIGFzIGU6CiAgICAgICAgICAgICAgICBjb250ZXh0LmxvZ2dlci5pbmZvKGYidW5hYmxlIHRvIGxvYWQge21vZGVsfSBiZWNhdXNlIG9mOiB7ZX0iKQoKICAgICMgUnVuIG1vZGVsIGZpbHRlcnMKICAgIG1vZGVsc19kZiA9IHBkLkRhdGFGcmFtZShpbmRleD1YLmNvbHVtbnMpCiAgICBmb3IgbW9kZWxfbmFtZSwgbW9kZWwgaW4gc2VsZWN0ZWRfbW9kZWxzLml0ZW1zKCk6CgogICAgICAgIGlmIG1vZGVsX25hbWUgPT0gIkxvZ2lzdGljUmVncmVzc2lvbiI6CiAgICAgICAgICAgIG1vZGVsLnNldF9wYXJhbXMoc29sdmVyPSJsaWJsaW5lYXIiKQoKICAgICAgICAjIFRyYWluIG1vZGVsIGFuZCBnZXQgZmVhdHVyZSBpbXBvcnRhbmNlCiAgICAgICAgc2VsZWN0X2Zyb21fbW9kZWwgPSBTZWxlY3RGcm9tTW9kZWwobW9kZWwpLmZpdChYLCB5KQogICAgICAgIGZlYXR1cmVfaWR4ID0gc2VsZWN0X2Zyb21fbW9kZWwuZ2V0X3N1cHBvcnQoKQogICAgICAgIGZlYXR1cmVfbmFtZXMgPSBYLmNvbHVtbnNbZmVhdHVyZV9pZHhdCiAgICAgICAgc2VsZWN0ZWRfZmVhdHVyZXNfYWdnW21vZGVsX25hbWVdID0gZmVhdHVyZV9uYW1lcy50b2xpc3QoKQoKICAgICAgICAjIENvbGxlY3QgbW9kZWwgZmVhdHVyZSBpbXBvcnRhbmNlCiAgICAgICAgaWYgaGFzYXR0cihzZWxlY3RfZnJvbV9tb2RlbC5lc3RpbWF0b3JfLCAiY29lZl8iKToKICAgICAgICAgICAgc3RhdF9kZiA9IHNlbGVjdF9mcm9tX21vZGVsLmVzdGltYXRvcl8uY29lZl8KICAgICAgICBlbGlmIGhhc2F0dHIoc2VsZWN0X2Zyb21fbW9kZWwuZXN0aW1hdG9yXywgImZlYXR1cmVfaW1wb3J0YW5jZXNfIik6CiAgICAgICAgICAgIHN0YXRfZGYgPSBzZWxlY3RfZnJvbV9tb2RlbC5lc3RpbWF0b3JfLmZlYXR1cmVfaW1wb3J0YW5jZXNfCgogICAgICAgIHN0YXRfZGYgPSBwZC5EYXRhRnJhbWUoaW5kZXg9WC5jb2x1bW5zLCBjb2x1bW5zPVttb2RlbF9uYW1lXSwgZGF0YT1zdGF0X2RmWzBdKQogICAgICAgIG1vZGVsc19kZiA9IG1vZGVsc19kZi5qb2luKHN0YXRfZGYpCgogICAgICAgIHBsb3Rfc3RhdChjb250ZXh0LCBtb2RlbF9uYW1lLCBzdGF0X2RmKQoKICAgICMgQ3JlYXRlIGZlYXR1cmVfc2NvcmVzIERGIHdpdGggc3RhdCAmIG1vZGVsIGZpbHRlcnMgc2NvcmVzCiAgICByZXN1bHRfbWF0cml4X2RmID0gcGQuY29uY2F0KFtzdGF0c19kZiwgbW9kZWxzX2RmXSwgYXhpcz0xLCBzb3J0PUZhbHNlKQogICAgY29udGV4dC5sb2dfZGF0YXNldCgKICAgICAgICBrZXk9ImZlYXR1cmVfc2NvcmVzIiwKICAgICAgICBkZj1yZXN1bHRfbWF0cml4X2RmLAogICAgICAgIGxvY2FsX3BhdGg9ImZlYXR1cmVfc2NvcmVzLnBhcnF1ZXQiLAogICAgICAgIGZvcm1hdD0icGFycXVldCIsCiAgICApCiAgICBpZiBtYXhfc2NhbGVkX3Njb3JlczoKICAgICAgICBub3JtYWxpemVkX2RmID0gcmVzdWx0X21hdHJpeF9kZi5yZXBsYWNlKFtucC5pbmYsIC1ucC5pbmZdLCBucC5uYW4pLnZhbHVlcwogICAgICAgIG1pbl9tYXhfc2NhbGVyID0gTWluTWF4U2NhbGVyKCkKICAgICAgICBub3JtYWxpemVkX2RmID0gbWluX21heF9zY2FsZXIuZml0X3RyYW5zZm9ybShub3JtYWxpemVkX2RmKQogICAgICAgIG5vcm1hbGl6ZWRfZGYgPSBwZC5EYXRhRnJhbWUoCiAgICAgICAgICAgIGRhdGE9bm9ybWFsaXplZF9kZiwKICAgICAgICAgICAgY29sdW1ucz1yZXN1bHRfbWF0cml4X2RmLmNvbHVtbnMsCiAgICAgICAgICAgIGluZGV4PXJlc3VsdF9tYXRyaXhfZGYuaW5kZXgsCiAgICAgICAgKQogICAgICAgIGNvbnRleHQubG9nX2RhdGFzZXQoCiAgICAgICAgICAgIGtleT0ibWF4X3NjYWxlZF9zY29yZXNfZmVhdHVyZV9zY29yZXMiLAogICAgICAgICAgICBkZj1ub3JtYWxpemVkX2RmLAogICAgICAgICAgICBsb2NhbF9wYXRoPSJtYXhfc2NhbGVkX3Njb3Jlc19mZWF0dXJlX3Njb3Jlcy5wYXJxdWV0IiwKICAgICAgICAgICAgZm9ybWF0PSJwYXJxdWV0IiwKICAgICAgICApCgogICAgIyBDcmVhdGUgZmVhdHVyZSBjb3VudCBEYXRhRnJhbWUKICAgIGZvciB0ZXN0X25hbWUgaW4gc2VsZWN0ZWRfZmVhdHVyZXNfYWdnOgogICAgICAgIHJlc3VsdF9tYXRyaXhfZGZbdGVzdF9uYW1lXSA9IFsKICAgICAgICAgICAgMSBpZiB4IGluIHNlbGVjdGVkX2ZlYXR1cmVzX2FnZ1t0ZXN0X25hbWVdIGVsc2UgMCBmb3IgeCBpbiBYLmNvbHVtbnMKICAgICAgICBdCiAgICByZXN1bHRfbWF0cml4X2RmLmxvY1s6LCAibnVtX3ZvdGVzIl0gPSByZXN1bHRfbWF0cml4X2RmLnN1bShheGlzPTEpCiAgICBjb250ZXh0LmxvZ19kYXRhc2V0KAogICAgICAgIGtleT0ic2VsZWN0ZWRfZmVhdHVyZXNfY291bnQiLAogICAgICAgIGRmPXJlc3VsdF9tYXRyaXhfZGYsCiAgICAgICAgbG9jYWxfcGF0aD0ic2VsZWN0ZWRfZmVhdHVyZXNfY291bnQucGFycXVldCIsCiAgICAgICAgZm9ybWF0PSJwYXJxdWV0IiwKICAgICkKCiAgICAjIEhvdyBtYW55IHZvdGVzIGFyZSBuZWVkZWQgZm9yIGEgZmVhdHVyZSB0byBiZSBzZWxlY3RlZD8KICAgIGlmIGlzaW5zdGFuY2UobWluX3ZvdGVzLCBpbnQpOgogICAgICAgIHZvdGVzX25lZWRlZCA9IG1pbl92b3RlcwogICAgZWxzZToKICAgICAgICBudW1fZmlsdGVycyA9IGxlbihzdGF0X2ZpbHRlcnMpICsgbGVuKG1vZGVsX2ZpbHRlcnMpCiAgICAgICAgdm90ZXNfbmVlZGVkID0gaW50KG5wLmZsb29yKG51bV9maWx0ZXJzICogbWF4KG1pbihtaW5fdm90ZXMsIDEpLCAwKSkpCiAgICBjb250ZXh0LmxvZ2dlci5pbmZvKGYidm90ZXMgbmVlZGVkIHRvIGJlIHNlbGVjdGVkOiB7dm90ZXNfbmVlZGVkfSIpCgogICAgIyBDcmVhdGUgZmluYWwgZmVhdHVyZSBkYXRhZnJhbWUKICAgIHNlbGVjdGVkX2ZlYXR1cmVzID0gcmVzdWx0X21hdHJpeF9kZlsKICAgICAgICByZXN1bHRfbWF0cml4X2RmLm51bV92b3RlcyA+PSB2b3Rlc19uZWVkZWQKICAgIF0uaW5kZXgudG9saXN0KCkKICAgIGdvb2RfZmVhdHVyZV9kZiA9IGRmLmxvY1s6LCBzZWxlY3RlZF9mZWF0dXJlc10KICAgIGZpbmFsX2RmID0gcGQuY29uY2F0KFtnb29kX2ZlYXR1cmVfZGYsIHldLCBheGlzPTEpCiAgICBjb250ZXh0LmxvZ19kYXRhc2V0KAogICAgICAgIGtleT0ic2VsZWN0ZWRfZmVhdHVyZXMiLAogICAgICAgIGRmPWZpbmFsX2RmLAogICAgICAgIGxvY2FsX3BhdGg9InNlbGVjdGVkX2ZlYXR1cmVzLnBhcnF1ZXQiLAogICAgICAgIGZvcm1hdD0icGFycXVldCIsCiAgICApCgogICAgIyBDcmVhdGluZyBhIG5ldyBmZWF0dXJlIHZlY3RvciBjb250YWluaW5nIG9ubHkgdGhlIGlkZW50aWZpZWQgdG9wIGZlYXR1cmVzCiAgICBpZiBpc19mZWF0dXJlX3ZlY3RvciBhbmQgZGZfYXJ0aWZhY3QubWV0YS5zcGVjLmZlYXR1cmVzIGFuZCBvdXRwdXRfdmVjdG9yX25hbWU6CiAgICAgICAgIyBTZWxlY3RpbmcgdGhlIHRvcCBLIGZlYXR1cmVzIGZyb20gb3VyIHRvcCBmZWF0dXJlIGRhdGFmcmFtZQogICAgICAgIHNlbGVjdGVkX2ZlYXR1cmVzID0gcmVzdWx0X21hdHJpeF9kZi5oZWFkKGspLmluZGV4CgogICAgICAgICMgTWF0Y2ggdGhlIHNlbGVjdGVkIGZlYXR1cmUgbmFtZXMgdG8gdGhlIEZTIEZlYXR1cmUgYW5ub3RhdGlvbnMKICAgICAgICBtYXRjaGVkX3NlbGVjdGlvbnMgPSBbCiAgICAgICAgICAgIGZlYXR1cmUKICAgICAgICAgICAgZm9yIGZlYXR1cmUgaW4gbGlzdChkZl9hcnRpZmFjdC5tZXRhLnNwZWMuZmVhdHVyZXMpCiAgICAgICAgICAgIGZvciBzZWxlY3RlZCBpbiBsaXN0KHNlbGVjdGVkX2ZlYXR1cmVzKQogICAgICAgICAgICBpZiBmZWF0dXJlLmVuZHN3aXRoKHNlbGVjdGVkKQogICAgICAgIF0KCiAgICAgICAgIyBEZWZpbmluZyBvdXIgbmV3IGZlYXR1cmUgdmVjdG9yCiAgICAgICAgdG9wX2ZlYXR1cmVzX2Z2ID0gZnMuRmVhdHVyZVZlY3RvcigKICAgICAgICAgICAgb3V0cHV0X3ZlY3Rvcl9uYW1lLAogICAgICAgICAgICBtYXRjaGVkX3NlbGVjdGlvbnMsCiAgICAgICAgICAgIGxhYmVsX2ZlYXR1cmU9ImxhYmVscy5sYWJlbCIsCiAgICAgICAgICAgIGRlc2NyaXB0aW9uPSJmZWF0dXJlIHZlY3RvciBjb21wb3NlZCBzdHJpY3RseSBvZiBvdXIgdG9wIGZlYXR1cmVzIiwKICAgICAgICApCgogICAgICAgICMgU2F2aW5nCiAgICAgICAgdG9wX2ZlYXR1cmVzX2Z2LnNhdmUoKQogICAgICAgIGZzLmdldF9vZmZsaW5lX2ZlYXR1cmVzKHRvcF9mZWF0dXJlc19mdiwgdGFyZ2V0PVBhcnF1ZXRUYXJnZXQoKSkKCiAgICAgICAgIyBMb2dnaW5nIG91ciBuZXcgZmVhdHVyZSB2ZWN0b3IgVVJJCiAgICAgICAgY29udGV4dC5sb2dfcmVzdWx0KCJ0b3BfZmVhdHVyZXNfdmVjdG9yIiwgdG9wX2ZlYXR1cmVzX2Z2LnVyaSkK - commands: [] - code_origin: '' - origin_filename: '' - requirements: [] entry_points: show_values_on_bars: - name: show_values_on_bars doc: '' + has_kwargs: false parameters: - name: axs - name: h_v default: v - name: space default: 0.4 - outputs: [] - lineno: 43 + lineno: 54 has_varargs: false - has_kwargs: false + name: show_values_on_bars plot_stat: - name: plot_stat doc: '' + has_kwargs: false parameters: - name: context - name: stat_name - name: stat_df - outputs: [] - lineno: 65 + lineno: 76 has_varargs: false - has_kwargs: false + name: plot_stat feature_selection: - name: feature_selection doc: 'Applies selected feature selection statistical functions or models on our ''df_artifact''. @@ -53,6 +37,7 @@ spec: Each statistical function or model will vote for it''s best K selected features. If a feature has >= ''min_votes'' votes, it will be selected.' + has_kwargs: false parameters: - name: context doc: the function context. @@ -99,17 +84,20 @@ spec: type: bool doc: skips datatypes that are neither float nor int within the feature vector. default: false - outputs: [] - lineno: 80 + - name: is_feature_vector + type: bool + doc: bool stating if the data is passed as a feature vector. + default: false + lineno: 106 has_varargs: false - has_kwargs: false - description: Select features through multiple Statistical and Model filters - default_handler: feature_selection + name: feature_selection disable_auto_mount: false - env: [] - priority_class_name: '' - preemption_mode: prevent - affinity: null - tolerations: null - security_context: {} + command: '' + build: + origin_filename: '' + functionSourceCode: IyBDb3B5cmlnaHQgMjAxOSBJZ3VhemlvCiMKIyBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgIkxpY2Vuc2UiKTsKIyB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiMgWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0CiMKIyAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wCiMKIyBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlCiMgZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gIkFTIElTIiBCQVNJUywKIyBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KIyBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kCiMgbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuCiMKaW1wb3J0IGpzb24KCmltcG9ydCBtbHJ1bgppbXBvcnQgbWxydW4uZGF0YXN0b3JlCmltcG9ydCBtbHJ1bi5mZWF0dXJlX3N0b3JlIGFzIGZzCmltcG9ydCBtbHJ1bi51dGlscwppbXBvcnQgbnVtcHkgYXMgbnAKaW1wb3J0IHBhbmRhcyBhcyBwZAppbXBvcnQgcGxvdGx5LmV4cHJlc3MgYXMgcHgKZnJvbSBtbHJ1bi5hcnRpZmFjdHMgaW1wb3J0IFBsb3RseUFydGlmYWN0CmZyb20gbWxydW4uZGF0YXN0b3JlLnRhcmdldHMgaW1wb3J0IFBhcnF1ZXRUYXJnZXQKIyBNTFJ1biB1dGlscwpmcm9tIG1scnVuLnV0aWxzLmhlbHBlcnMgaW1wb3J0IGNyZWF0ZV9jbGFzcwojIEZlYXR1cmUgc2VsZWN0aW9uIHN0cmF0ZWdpZXMKZnJvbSBza2xlYXJuLmZlYXR1cmVfc2VsZWN0aW9uIGltcG9ydCBTZWxlY3RGcm9tTW9kZWwsIFNlbGVjdEtCZXN0CiMgU2NhbGUgZmVhdHVyZSBzY29yZXNnaXQgc3QKZnJvbSBza2xlYXJuLnByZXByb2Nlc3NpbmcgaW1wb3J0IE1pbk1heFNjYWxlcgojIFNLTGVhcm4gZXN0aW1hdG9ycyBsaXN0CmZyb20gc2tsZWFybi51dGlscyBpbXBvcnQgYWxsX2VzdGltYXRvcnMKCkRFRkFVTFRfU1RBVF9GSUxURVJTID0gWyJmX2NsYXNzaWYiLCAibXV0dWFsX2luZm9fY2xhc3NpZiIsICJjaGkyIiwgImZfcmVncmVzc2lvbiJdCkRFRkFVTFRfTU9ERUxfRklMVEVSUyA9IHsKICAgICJMaW5lYXJTVkMiOiAiTGluZWFyU1ZDIiwKICAgICJMb2dpc3RpY1JlZ3Jlc3Npb24iOiAiTG9naXN0aWNSZWdyZXNzaW9uIiwKICAgICJFeHRyYVRyZWVzQ2xhc3NpZmllciI6ICJFeHRyYVRyZWVzQ2xhc3NpZmllciIsCn0KCgpkZWYgc2hvd192YWx1ZXNfb25fYmFycyhheHMsIGhfdj0idiIsIHNwYWNlPTAuNCk6CiAgICBkZWYgX3Nob3dfb25fc2luZ2xlX3Bsb3QoYXhfKToKICAgICAgICBpZiBoX3YgPT0gInYiOgogICAgICAgICAgICBmb3IgcCBpbiBheF8ucGF0Y2hlczoKICAgICAgICAgICAgICAgIF94ID0gcC5nZXRfeCgpICsgcC5nZXRfd2lkdGgoKSAvIDIKICAgICAgICAgICAgICAgIF95ID0gcC5nZXRfeSgpICsgcC5nZXRfaGVpZ2h0KCkKICAgICAgICAgICAgICAgIHZhbHVlID0gaW50KHAuZ2V0X2hlaWdodCgpKQogICAgICAgICAgICAgICAgYXhfLnRleHQoX3gsIF95LCB2YWx1ZSwgaGE9ImNlbnRlciIpCiAgICAgICAgZWxpZiBoX3YgPT0gImgiOgogICAgICAgICAgICBmb3IgcCBpbiBheF8ucGF0Y2hlczoKICAgICAgICAgICAgICAgIF94ID0gcC5nZXRfeCgpICsgcC5nZXRfd2lkdGgoKSArIGZsb2F0KHNwYWNlKQogICAgICAgICAgICAgICAgX3kgPSBwLmdldF95KCkgKyBwLmdldF9oZWlnaHQoKQogICAgICAgICAgICAgICAgdmFsdWUgPSBpbnQocC5nZXRfd2lkdGgoKSkKICAgICAgICAgICAgICAgIGF4Xy50ZXh0KF94LCBfeSwgdmFsdWUsIGhhPSJsZWZ0IikKCiAgICBpZiBpc2luc3RhbmNlKGF4cywgbnAubmRhcnJheSk6CiAgICAgICAgZm9yIGlkeCwgYXggaW4gbnAubmRlbnVtZXJhdGUoYXhzKToKICAgICAgICAgICAgX3Nob3dfb25fc2luZ2xlX3Bsb3QoYXgpCiAgICBlbHNlOgogICAgICAgIF9zaG93X29uX3NpbmdsZV9wbG90KGF4cykKCgpkZWYgcGxvdF9zdGF0KGNvbnRleHQsIHN0YXRfbmFtZSwgc3RhdF9kZik6CiAgICBzb3J0ZWRfZGYgPSBzdGF0X2RmLnNvcnRfdmFsdWVzKHN0YXRfbmFtZSkKICAgIGZpZyA9IHB4LmJhcigKICAgICAgICBkYXRhX2ZyYW1lPXNvcnRlZF9kZiwKICAgICAgICB4PXN0YXRfbmFtZSwKICAgICAgICB5PXNvcnRlZF9kZi5pbmRleCwKICAgICAgICB0aXRsZT1mIntzdGF0X25hbWV9IGZlYXR1cmUgc2NvcmVzIiwKICAgICAgICBjb2xvcj1zdGF0X25hbWUsCiAgICApCiAgICBjb250ZXh0LmxvZ19hcnRpZmFjdCgKICAgICAgICBpdGVtPVBsb3RseUFydGlmYWN0KGtleT1zdGF0X25hbWUsIGZpZ3VyZT1maWcpLAogICAgICAgIGxvY2FsX3BhdGg9ZiJ7c3RhdF9uYW1lfS5odG1sIiwKICAgICkKCgpkZWYgZmVhdHVyZV9zZWxlY3Rpb24oCiAgICBjb250ZXh0LAogICAgZGZfYXJ0aWZhY3QsCiAgICBrOiBpbnQgPSA1LAogICAgbWluX3ZvdGVzOiBmbG9hdCA9IDAuNSwKICAgIGxhYmVsX2NvbHVtbjogc3RyID0gTm9uZSwKICAgIHN0YXRfZmlsdGVyczogbGlzdCA9IE5vbmUsCiAgICBtb2RlbF9maWx0ZXJzOiBkaWN0ID0gTm9uZSwKICAgIG1heF9zY2FsZWRfc2NvcmVzOiBib29sID0gVHJ1ZSwKICAgIHNhbXBsZV9yYXRpbzogZmxvYXQgPSBOb25lLAogICAgb3V0cHV0X3ZlY3Rvcl9uYW1lOiBmbG9hdCA9IE5vbmUsCiAgICBpZ25vcmVfdHlwZV9lcnJvcnM6IGJvb2wgPSBGYWxzZSwKKToKICAgICIiIgogICAgQXBwbGllcyBzZWxlY3RlZCBmZWF0dXJlIHNlbGVjdGlvbiBzdGF0aXN0aWNhbCBmdW5jdGlvbnMgb3IgbW9kZWxzIG9uIG91ciAnZGZfYXJ0aWZhY3QnLgoKICAgIEVhY2ggc3RhdGlzdGljYWwgZnVuY3Rpb24gb3IgbW9kZWwgd2lsbCB2b3RlIGZvciBpdCdzIGJlc3QgSyBzZWxlY3RlZCBmZWF0dXJlcy4KICAgIElmIGEgZmVhdHVyZSBoYXMgPj0gJ21pbl92b3Rlcycgdm90ZXMsIGl0IHdpbGwgYmUgc2VsZWN0ZWQuCgogICAgOnBhcmFtIGNvbnRleHQ6ICAgICAgICAgICAgIHRoZSBmdW5jdGlvbiBjb250ZXh0LgogICAgOnBhcmFtIGRmX2FydGlmYWN0OiAgICAgICAgIGRhdGFmcmFtZSB0byBwYXNzIGFzIGlucHV0LgogICAgOnBhcmFtIGs6ICAgICAgICAgICAgICAgICAgIG51bWJlciBvZiB0b3AgZmVhdHVyZXMgdG8gc2VsZWN0IGZyb20gZWFjaCBzdGF0aXN0aWNhbAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uIG9yIG1vZGVsLgogICAgOnBhcmFtIG1pbl92b3RlczogICAgICAgICAgIG1pbmltYWwgbnVtYmVyIG9mIHZvdGVzIChmcm9tIGEgbW9kZWwgb3IgYnkgc3RhdGlzdGljYWwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbikgbmVlZGVkIGZvciBhIGZlYXR1cmUgdG8gYmUgc2VsZWN0ZWQuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQ2FuIGJlIHNwZWNpZmllZCBieSBwZXJjZW50YWdlIG9mIHZvdGVzIG9yIGFic29sdXRlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbnVtYmVyIG9mIHZvdGVzLgogICAgOnBhcmFtIGxhYmVsX2NvbHVtbjogICAgICAgIGdyb3VuZC10cnV0aCAoeSkgbGFiZWxzLgogICAgOnBhcmFtIHN0YXRfZmlsdGVyczogICAgICAgIHN0YXRpc3RpY2FsIGZ1bmN0aW9ucyB0byBhcHBseSB0byB0aGUgZmVhdHVyZXMKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoZnJvbSBza2xlYXJuLmZlYXR1cmVfc2VsZWN0aW9uKS4KICAgIDpwYXJhbSBtb2RlbF9maWx0ZXJzOiAgICAgICBtb2RlbHMgdG8gdXNlIGZvciBmZWF0dXJlIGV2YWx1YXRpb24sIGNhbiBiZSBzcGVjaWZpZWQgYnkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlbCBuYW1lIChleC4gTGluZWFyU1ZDKSwgZm9ybWFsaXplZCBqc29uIChjb250YWlucyAnQ0xBU1MnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdGSVQnLCAnTUVUQScpIG9yIGEgcGF0aCB0byBzdWNoIGpzb24gZmlsZS4KICAgIDpwYXJhbSBtYXhfc2NhbGVkX3Njb3JlczogICBwcm9kdWNlIGZlYXR1cmUgc2NvcmVzIHRhYmxlIHNjYWxlZCB3aXRoIG1heF9zY2FsZXIuCiAgICA6cGFyYW0gc2FtcGxlX3JhdGlvOiAgICAgICAgcGVyY2VudGFnZSBvZiB0aGUgZGF0YXNldCB0aGUgdXNlciB3aXNoZXMgdG8gY29tcHV0ZSB0aGUgZmVhdHVyZSBzZWxlY3Rpb24gcHJvY2VzcyBvbi4KICAgIDpwYXJhbSBvdXRwdXRfdmVjdG9yX25hbWU6ICBjcmVhdGVzIGEgbmV3IGZlYXR1cmUgdmVjdG9yIGNvbnRhaW5pbmcgb25seSB0aGUgaWRlbnRpZmllcyBmZWF0dXJlcy4KICAgIDpwYXJhbSBpZ25vcmVfdHlwZV9lcnJvcnM6ICBza2lwcyBkYXRhdHlwZXMgdGhhdCBhcmUgbmVpdGhlciBmbG9hdCBub3IgaW50IHdpdGhpbiB0aGUgZmVhdHVyZSB2ZWN0b3IuCiAgICAiIiIKICAgIHN0YXRfZmlsdGVycyA9IHN0YXRfZmlsdGVycyBvciBERUZBVUxUX1NUQVRfRklMVEVSUwogICAgbW9kZWxfZmlsdGVycyA9IG1vZGVsX2ZpbHRlcnMgb3IgREVGQVVMVF9NT0RFTF9GSUxURVJTCiAgICAjIENoZWNrIGlmIGRmLm1ldGEgaXMgdmFsaWQsIGlmIGl0IGlzLCBsb29rIGZvciBhIGZlYXR1cmUgdmVjdG9yCiAgICBzdG9yZV91cmlfcHJlZml4LCBfID0gbWxydW4uZGF0YXN0b3JlLnBhcnNlX3N0b3JlX3VyaShkZl9hcnRpZmFjdC5hcnRpZmFjdF91cmwpCiAgICBpc19mZWF0dXJlX3ZlY3RvciA9IG1scnVuLnV0aWxzLlN0b3JlUHJlZml4LkZlYXR1cmVWZWN0b3IgPT0gc3RvcmVfdXJpX3ByZWZpeAoKICAgICMgTG9vayBpbnNpZGUgbWV0YS5zcGVjLmxhYmVsX2ZlYXR1cmUgdG8gaWRlbnRpZnkgdGhlIGxhYmVsX2NvbHVtbiBpZiB0aGUgdXNlciBkaWQgbm90IHNwZWNpZnkgaXQKICAgIGlmIGxhYmVsX2NvbHVtbiBpcyBOb25lOgogICAgICAgIGlmIGlzX2ZlYXR1cmVfdmVjdG9yOgogICAgICAgICAgICBsYWJlbF9jb2x1bW4gPSBkZl9hcnRpZmFjdC5tZXRhLnNwZWMubGFiZWxfZmVhdHVyZS5zcGxpdCgiLiIpWzFdCiAgICAgICAgZWxzZToKICAgICAgICAgICAgcmFpc2UgVmFsdWVFcnJvcigiTm8gbGFiZWxfY29sdW1uIHdhcyBnaXZlbiwgcGxlYXNlIGFkZCBhIGxhYmVsX2NvbHVtbi4iKQoKICAgICMgVXNlIHRoZSBmZWF0dXJlIHZlY3RvciBhcyBkYXRhZnJhbWUKICAgIGRmID0gZGZfYXJ0aWZhY3QuYXNfZGYoKQoKICAgICMgRW5zdXJlIGsgaXMgbm90IGJpZ2dlciB0aGFuIHRoZSB0b3RhbCBudW1iZXIgb2YgZmVhdHVyZXMKICAgIGlmIGsgPiBkZi5zaGFwZVsxXToKICAgICAgICByYWlzZSBWYWx1ZUVycm9yKAogICAgICAgICAgICBmIksgY2Fubm90IGJlIGJpZ2dlciB0aGFuIHRoZSB0b3RhbCBudW1iZXIgb2YgZmVhdHVyZXMgKHtkZi5zaGFwZVsxXX0pLiBQbGVhc2UgY2hvb3NlIGEgc21hbGxlciBLLiIKICAgICAgICApCiAgICBlbGlmIGsgPCAxOgogICAgICAgIHJhaXNlIFZhbHVlRXJyb3IoIksgY2Fubm90IGJlIHNtYWxsZXIgdGhhbiAxLiBQbGVhc2UgY2hvb3NlIGEgYmlnZ2VyIEsuIikKCiAgICAjIENyZWF0ZSBhIHNhbXBsZSBkYXRhZnJhbWUgb2YgdGhlIG9yaWdpbmFsIGZlYXR1cmUgdmVjdG9yCiAgICBpZiBzYW1wbGVfcmF0aW86CiAgICAgICAgZGYgPSAoCiAgICAgICAgICAgIGRmLmdyb3VwYnkobGFiZWxfY29sdW1uKQogICAgICAgICAgICAuYXBwbHkobGFtYmRhIHg6IHguc2FtcGxlKGZyYWM9c2FtcGxlX3JhdGlvKSkKICAgICAgICAgICAgLnJlc2V0X2luZGV4KGRyb3A9VHJ1ZSkKICAgICAgICApCiAgICAgICAgZGYgPSBkZi5kcm9wbmEoKQoKICAgICMgU2V0IGZlYXR1cmUgdmVjdG9yIGFuZCBsYWJlbHMKICAgIHkgPSBkZi5wb3AobGFiZWxfY29sdW1uKQogICAgWCA9IGRmCgogICAgaWYgbnAub2JqZWN0XyBpbiBsaXN0KFguZHR5cGVzKSBhbmQgaWdub3JlX3R5cGVfZXJyb3JzIGlzIEZhbHNlOgogICAgICAgIHJhaXNlIFZhbHVlRXJyb3IoCiAgICAgICAgICAgIGYie2RmLnNlbGVjdF9kdHlwZXMoaW5jbHVkZT1bJ29iamVjdCddKS5jb2x1bW5zLnRvbGlzdCgpfSBhcmUgbmVpdGhlciBmbG9hdCBvciBpbnQuIgogICAgICAgICkKCiAgICAjIENyZWF0ZSBzZWxlY3RlZCBzdGF0aXN0aWNhbCBlc3RpbWF0b3JzCiAgICBzdGF0X2Z1bmN0aW9uc19saXN0ID0gewogICAgICAgIHN0YXRfbmFtZTogU2VsZWN0S0Jlc3QoCiAgICAgICAgICAgIHNjb3JlX2Z1bmM9Y3JlYXRlX2NsYXNzKGYic2tsZWFybi5mZWF0dXJlX3NlbGVjdGlvbi57c3RhdF9uYW1lfSIpLCBrPWsKICAgICAgICApCiAgICAgICAgZm9yIHN0YXRfbmFtZSBpbiBzdGF0X2ZpbHRlcnMKICAgIH0KICAgIHJlcXVpcmVzX2FicyA9IFsiY2hpMiJdCgogICAgIyBSdW4gc3RhdGlzdGljIGZpbHRlcnMKICAgIHNlbGVjdGVkX2ZlYXR1cmVzX2FnZyA9IHt9CiAgICBzdGF0c19kZiA9IHBkLkRhdGFGcmFtZShpbmRleD1YLmNvbHVtbnMpLmRyb3BuYSgpCgogICAgZm9yIHN0YXRfbmFtZSwgc3RhdF9mdW5jIGluIHN0YXRfZnVuY3Rpb25zX2xpc3QuaXRlbXMoKToKICAgICAgICB0cnk6CiAgICAgICAgICAgIHBhcmFtcyA9IChYLCB5KSBpZiBzdGF0X25hbWUgaW4gcmVxdWlyZXNfYWJzIGVsc2UgKGFicyhYKSwgeSkKICAgICAgICAgICAgc3RhdCA9IHN0YXRfZnVuYy5maXQoKnBhcmFtcykKCiAgICAgICAgICAgICMgQ29sbGVjdCBzdGF0IGZ1bmN0aW9uIHJlc3VsdHMKICAgICAgICAgICAgc3RhdF9kZiA9IHBkLkRhdGFGcmFtZSgKICAgICAgICAgICAgICAgIGluZGV4PVguY29sdW1ucywgY29sdW1ucz1bc3RhdF9uYW1lXSwgZGF0YT1zdGF0LnNjb3Jlc18KICAgICAgICAgICAgKQogICAgICAgICAgICBwbG90X3N0YXQoY29udGV4dCwgc3RhdF9uYW1lLCBzdGF0X2RmKQogICAgICAgICAgICBzdGF0c19kZiA9IHN0YXRzX2RmLmpvaW4oc3RhdF9kZikKCiAgICAgICAgICAgICMgU2VsZWN0IEsgQmVzdCBmZWF0dXJlcwogICAgICAgICAgICBzZWxlY3RlZF9mZWF0dXJlcyA9IFguY29sdW1uc1tzdGF0X2Z1bmMuZ2V0X3N1cHBvcnQoKV0KICAgICAgICAgICAgc2VsZWN0ZWRfZmVhdHVyZXNfYWdnW3N0YXRfbmFtZV0gPSBzZWxlY3RlZF9mZWF0dXJlcwoKICAgICAgICBleGNlcHQgRXhjZXB0aW9uIGFzIGU6CiAgICAgICAgICAgIGNvbnRleHQubG9nZ2VyLmluZm8oZiJDb3VsZG4ndCBjYWxjdWxhdGUge3N0YXRfbmFtZX0gYmVjYXVzZSBvZjoge2V9IikKCiAgICAjIENyZWF0ZSBtb2RlbHMgZnJvbSBjbGFzcyBuYW1lIC8ganNvbiBmaWxlIC8ganNvbiBwYXJhbXMKICAgIGFsbF9za2xlYXJuX2VzdGltYXRvcnMgPSBkaWN0KGFsbF9lc3RpbWF0b3JzKCkpIGlmIGxlbihtb2RlbF9maWx0ZXJzKSA+IDAgZWxzZSB7fQogICAgc2VsZWN0ZWRfbW9kZWxzID0ge30KICAgIGZvciBtb2RlbF9uYW1lLCBtb2RlbCBpbiBtb2RlbF9maWx0ZXJzLml0ZW1zKCk6CiAgICAgICAgaWYgIi5qc29uIiBpbiBtb2RlbDoKICAgICAgICAgICAgY3VycmVudF9tb2RlbCA9IGpzb24ubG9hZChvcGVuKG1vZGVsLCAiciIpKQogICAgICAgICAgICBjbGFzc2lmaWVyX2NsYXNzID0gY3JlYXRlX2NsYXNzKGN1cnJlbnRfbW9kZWxbIk1FVEEiXVsiY2xhc3MiXSkKICAgICAgICAgICAgc2VsZWN0ZWRfbW9kZWxzW21vZGVsX25hbWVdID0gY2xhc3NpZmllcl9jbGFzcygqKmN1cnJlbnRfbW9kZWxbIkNMQVNTIl0pCiAgICAgICAgZWxpZiBtb2RlbCBpbiBhbGxfc2tsZWFybl9lc3RpbWF0b3JzOgogICAgICAgICAgICBzZWxlY3RlZF9tb2RlbHNbbW9kZWxfbmFtZV0gPSBhbGxfc2tsZWFybl9lc3RpbWF0b3JzW21vZGVsX25hbWVdKCkKCiAgICAgICAgZWxzZToKICAgICAgICAgICAgdHJ5OgogICAgICAgICAgICAgICAgY3VycmVudF9tb2RlbCA9IGpzb24ubG9hZHMobW9kZWwpCiAgICAgICAgICAgICAgICBjbGFzc2lmaWVyX2NsYXNzID0gY3JlYXRlX2NsYXNzKGN1cnJlbnRfbW9kZWxbIk1FVEEiXVsiY2xhc3MiXSkKICAgICAgICAgICAgICAgIHNlbGVjdGVkX21vZGVsc1ttb2RlbF9uYW1lXSA9IGNsYXNzaWZpZXJfY2xhc3MoKipjdXJyZW50X21vZGVsWyJDTEFTUyJdKQogICAgICAgICAgICBleGNlcHQgRXhjZXB0aW9uIGFzIGU6CiAgICAgICAgICAgICAgICBjb250ZXh0LmxvZ2dlci5pbmZvKGYidW5hYmxlIHRvIGxvYWQge21vZGVsfSBiZWNhdXNlIG9mOiB7ZX0iKQoKICAgICMgUnVuIG1vZGVsIGZpbHRlcnMKICAgIG1vZGVsc19kZiA9IHBkLkRhdGFGcmFtZShpbmRleD1YLmNvbHVtbnMpCiAgICBmb3IgbW9kZWxfbmFtZSwgbW9kZWwgaW4gc2VsZWN0ZWRfbW9kZWxzLml0ZW1zKCk6CgogICAgICAgIGlmIG1vZGVsX25hbWUgPT0gIkxvZ2lzdGljUmVncmVzc2lvbiI6CiAgICAgICAgICAgIG1vZGVsLnNldF9wYXJhbXMoc29sdmVyPSJsaWJsaW5lYXIiKQoKICAgICAgICAjIFRyYWluIG1vZGVsIGFuZCBnZXQgZmVhdHVyZSBpbXBvcnRhbmNlCiAgICAgICAgc2VsZWN0X2Zyb21fbW9kZWwgPSBTZWxlY3RGcm9tTW9kZWwobW9kZWwpLmZpdChYLCB5KQogICAgICAgIGZlYXR1cmVfaWR4ID0gc2VsZWN0X2Zyb21fbW9kZWwuZ2V0X3N1cHBvcnQoKQogICAgICAgIGZlYXR1cmVfbmFtZXMgPSBYLmNvbHVtbnNbZmVhdHVyZV9pZHhdCiAgICAgICAgc2VsZWN0ZWRfZmVhdHVyZXNfYWdnW21vZGVsX25hbWVdID0gZmVhdHVyZV9uYW1lcy50b2xpc3QoKQoKICAgICAgICAjIENvbGxlY3QgbW9kZWwgZmVhdHVyZSBpbXBvcnRhbmNlCiAgICAgICAgaWYgaGFzYXR0cihzZWxlY3RfZnJvbV9tb2RlbC5lc3RpbWF0b3JfLCAiY29lZl8iKToKICAgICAgICAgICAgc3RhdF9kZiA9IHNlbGVjdF9mcm9tX21vZGVsLmVzdGltYXRvcl8uY29lZl8KICAgICAgICBlbGlmIGhhc2F0dHIoc2VsZWN0X2Zyb21fbW9kZWwuZXN0aW1hdG9yXywgImZlYXR1cmVfaW1wb3J0YW5jZXNfIik6CiAgICAgICAgICAgIHN0YXRfZGYgPSBzZWxlY3RfZnJvbV9tb2RlbC5lc3RpbWF0b3JfLmZlYXR1cmVfaW1wb3J0YW5jZXNfCgogICAgICAgIHN0YXRfZGYgPSBwZC5EYXRhRnJhbWUoaW5kZXg9WC5jb2x1bW5zLCBjb2x1bW5zPVttb2RlbF9uYW1lXSwgZGF0YT1zdGF0X2RmWzBdKQogICAgICAgIG1vZGVsc19kZiA9IG1vZGVsc19kZi5qb2luKHN0YXRfZGYpCgogICAgICAgIHBsb3Rfc3RhdChjb250ZXh0LCBtb2RlbF9uYW1lLCBzdGF0X2RmKQoKICAgICMgQ3JlYXRlIGZlYXR1cmVfc2NvcmVzIERGIHdpdGggc3RhdCAmIG1vZGVsIGZpbHRlcnMgc2NvcmVzCiAgICByZXN1bHRfbWF0cml4X2RmID0gcGQuY29uY2F0KFtzdGF0c19kZiwgbW9kZWxzX2RmXSwgYXhpcz0xLCBzb3J0PUZhbHNlKQogICAgY29udGV4dC5sb2dfZGF0YXNldCgKICAgICAgICBrZXk9ImZlYXR1cmVfc2NvcmVzIiwKICAgICAgICBkZj1yZXN1bHRfbWF0cml4X2RmLAogICAgICAgIGxvY2FsX3BhdGg9ImZlYXR1cmVfc2NvcmVzLnBhcnF1ZXQiLAogICAgICAgIGZvcm1hdD0icGFycXVldCIsCiAgICApCiAgICBpZiBtYXhfc2NhbGVkX3Njb3JlczoKICAgICAgICBub3JtYWxpemVkX2RmID0gcmVzdWx0X21hdHJpeF9kZi5yZXBsYWNlKFtucC5pbmYsIC1ucC5pbmZdLCBucC5uYW4pLnZhbHVlcwogICAgICAgIG1pbl9tYXhfc2NhbGVyID0gTWluTWF4U2NhbGVyKCkKICAgICAgICBub3JtYWxpemVkX2RmID0gbWluX21heF9zY2FsZXIuZml0X3RyYW5zZm9ybShub3JtYWxpemVkX2RmKQogICAgICAgIG5vcm1hbGl6ZWRfZGYgPSBwZC5EYXRhRnJhbWUoCiAgICAgICAgICAgIGRhdGE9bm9ybWFsaXplZF9kZiwKICAgICAgICAgICAgY29sdW1ucz1yZXN1bHRfbWF0cml4X2RmLmNvbHVtbnMsCiAgICAgICAgICAgIGluZGV4PXJlc3VsdF9tYXRyaXhfZGYuaW5kZXgsCiAgICAgICAgKQogICAgICAgIGNvbnRleHQubG9nX2RhdGFzZXQoCiAgICAgICAgICAgIGtleT0ibWF4X3NjYWxlZF9zY29yZXNfZmVhdHVyZV9zY29yZXMiLAogICAgICAgICAgICBkZj1ub3JtYWxpemVkX2RmLAogICAgICAgICAgICBsb2NhbF9wYXRoPSJtYXhfc2NhbGVkX3Njb3Jlc19mZWF0dXJlX3Njb3Jlcy5wYXJxdWV0IiwKICAgICAgICAgICAgZm9ybWF0PSJwYXJxdWV0IiwKICAgICAgICApCgogICAgIyBDcmVhdGUgZmVhdHVyZSBjb3VudCBEYXRhRnJhbWUKICAgIGZvciB0ZXN0X25hbWUgaW4gc2VsZWN0ZWRfZmVhdHVyZXNfYWdnOgogICAgICAgIHJlc3VsdF9tYXRyaXhfZGZbdGVzdF9uYW1lXSA9IFsKICAgICAgICAgICAgMSBpZiB4IGluIHNlbGVjdGVkX2ZlYXR1cmVzX2FnZ1t0ZXN0X25hbWVdIGVsc2UgMCBmb3IgeCBpbiBYLmNvbHVtbnMKICAgICAgICBdCiAgICByZXN1bHRfbWF0cml4X2RmLmxvY1s6LCAibnVtX3ZvdGVzIl0gPSByZXN1bHRfbWF0cml4X2RmLnN1bShheGlzPTEpCiAgICBjb250ZXh0LmxvZ19kYXRhc2V0KAogICAgICAgIGtleT0ic2VsZWN0ZWRfZmVhdHVyZXNfY291bnQiLAogICAgICAgIGRmPXJlc3VsdF9tYXRyaXhfZGYsCiAgICAgICAgbG9jYWxfcGF0aD0ic2VsZWN0ZWRfZmVhdHVyZXNfY291bnQucGFycXVldCIsCiAgICAgICAgZm9ybWF0PSJwYXJxdWV0IiwKICAgICkKCiAgICAjIEhvdyBtYW55IHZvdGVzIGFyZSBuZWVkZWQgZm9yIGEgZmVhdHVyZSB0byBiZSBzZWxlY3RlZD8KICAgIGlmIGlzaW5zdGFuY2UobWluX3ZvdGVzLCBpbnQpOgogICAgICAgIHZvdGVzX25lZWRlZCA9IG1pbl92b3RlcwogICAgZWxzZToKICAgICAgICBudW1fZmlsdGVycyA9IGxlbihzdGF0X2ZpbHRlcnMpICsgbGVuKG1vZGVsX2ZpbHRlcnMpCiAgICAgICAgdm90ZXNfbmVlZGVkID0gaW50KG5wLmZsb29yKG51bV9maWx0ZXJzICogbWF4KG1pbihtaW5fdm90ZXMsIDEpLCAwKSkpCiAgICBjb250ZXh0LmxvZ2dlci5pbmZvKGYidm90ZXMgbmVlZGVkIHRvIGJlIHNlbGVjdGVkOiB7dm90ZXNfbmVlZGVkfSIpCgogICAgIyBDcmVhdGUgZmluYWwgZmVhdHVyZSBkYXRhZnJhbWUKICAgIHNlbGVjdGVkX2ZlYXR1cmVzID0gcmVzdWx0X21hdHJpeF9kZlsKICAgICAgICByZXN1bHRfbWF0cml4X2RmLm51bV92b3RlcyA+PSB2b3Rlc19uZWVkZWQKICAgIF0uaW5kZXgudG9saXN0KCkKICAgIGdvb2RfZmVhdHVyZV9kZiA9IGRmLmxvY1s6LCBzZWxlY3RlZF9mZWF0dXJlc10KICAgIGZpbmFsX2RmID0gcGQuY29uY2F0KFtnb29kX2ZlYXR1cmVfZGYsIHldLCBheGlzPTEpCiAgICBjb250ZXh0LmxvZ19kYXRhc2V0KAogICAgICAgIGtleT0ic2VsZWN0ZWRfZmVhdHVyZXMiLAogICAgICAgIGRmPWZpbmFsX2RmLAogICAgICAgIGxvY2FsX3BhdGg9InNlbGVjdGVkX2ZlYXR1cmVzLnBhcnF1ZXQiLAogICAgICAgIGZvcm1hdD0icGFycXVldCIsCiAgICApCgogICAgIyBDcmVhdGluZyBhIG5ldyBmZWF0dXJlIHZlY3RvciBjb250YWluaW5nIG9ubHkgdGhlIGlkZW50aWZpZWQgdG9wIGZlYXR1cmVzCiAgICBpZiBpc19mZWF0dXJlX3ZlY3RvciBhbmQgZGZfYXJ0aWZhY3QubWV0YS5zcGVjLmZlYXR1cmVzIGFuZCBvdXRwdXRfdmVjdG9yX25hbWU6CiAgICAgICAgIyBTZWxlY3RpbmcgdGhlIHRvcCBLIGZlYXR1cmVzIGZyb20gb3VyIHRvcCBmZWF0dXJlIGRhdGFmcmFtZQogICAgICAgIHNlbGVjdGVkX2ZlYXR1cmVzID0gcmVzdWx0X21hdHJpeF9kZi5oZWFkKGspLmluZGV4CgogICAgICAgICMgTWF0Y2ggdGhlIHNlbGVjdGVkIGZlYXR1cmUgbmFtZXMgdG8gdGhlIEZTIEZlYXR1cmUgYW5ub3RhdGlvbnMKICAgICAgICBtYXRjaGVkX3NlbGVjdGlvbnMgPSBbCiAgICAgICAgICAgIGZlYXR1cmUKICAgICAgICAgICAgZm9yIGZlYXR1cmUgaW4gbGlzdChkZl9hcnRpZmFjdC5tZXRhLnNwZWMuZmVhdHVyZXMpCiAgICAgICAgICAgIGZvciBzZWxlY3RlZCBpbiBsaXN0KHNlbGVjdGVkX2ZlYXR1cmVzKQogICAgICAgICAgICBpZiBmZWF0dXJlLmVuZHN3aXRoKHNlbGVjdGVkKQogICAgICAgIF0KCiAgICAgICAgIyBEZWZpbmluZyBvdXIgbmV3IGZlYXR1cmUgdmVjdG9yCiAgICAgICAgdG9wX2ZlYXR1cmVzX2Z2ID0gZnMuRmVhdHVyZVZlY3RvcigKICAgICAgICAgICAgb3V0cHV0X3ZlY3Rvcl9uYW1lLAogICAgICAgICAgICBtYXRjaGVkX3NlbGVjdGlvbnMsCiAgICAgICAgICAgIGxhYmVsX2ZlYXR1cmU9ImxhYmVscy5sYWJlbCIsCiAgICAgICAgICAgIGRlc2NyaXB0aW9uPSJmZWF0dXJlIHZlY3RvciBjb21wb3NlZCBzdHJpY3RseSBvZiBvdXIgdG9wIGZlYXR1cmVzIiwKICAgICAgICApCgogICAgICAgICMgU2F2aW5nCiAgICAgICAgdG9wX2ZlYXR1cmVzX2Z2LnNhdmUoKQogICAgICAgIGZzLmdldF9vZmZsaW5lX2ZlYXR1cmVzKHRvcF9mZWF0dXJlc19mdiwgdGFyZ2V0PVBhcnF1ZXRUYXJnZXQoKSkKCiAgICAgICAgIyBMb2dnaW5nIG91ciBuZXcgZmVhdHVyZSB2ZWN0b3IgVVJJCiAgICAgICAgY29udGV4dC5sb2dfcmVzdWx0KCJ0b3BfZmVhdHVyZXNfdmVjdG9yIiwgdG9wX2ZlYXR1cmVzX2Z2LnVyaSkK + code_origin: '' + default_handler: feature_selection + image: mlrun/mlrun + description: Select features through multiple Statistical and Model filters verbose: false diff --git a/feature_selection/item.yaml b/feature_selection/item.yaml index ced618e00..99675b4e8 100644 --- a/feature_selection/item.yaml +++ b/feature_selection/item.yaml @@ -12,9 +12,9 @@ labels: author: orz maintainers: [] marketplaceType: '' -mlrunVersion: 1.6.3 +mlrunVersion: 1.6.4 name: feature-selection -platformVersion: 3.5.0 +platformVersion: 3.6.0 spec: filename: feature_selection.py handler: feature_selection diff --git a/feature_selection/requirements.txt b/feature_selection/requirements.txt index a13fc8ce6..e4d79d180 100644 --- a/feature_selection/requirements.txt +++ b/feature_selection/requirements.txt @@ -1,3 +1,3 @@ -scikit-learn~=1.0.2 +scikit-learn scikit-plot plotly~=5.4.0 diff --git a/feature_selection/test_feature_selection.py b/feature_selection/test_feature_selection.py index 3032b3193..6ae949aab 100644 --- a/feature_selection/test_feature_selection.py +++ b/feature_selection/test_feature_selection.py @@ -66,3 +66,4 @@ def test_run_local_feature_selection(): ] ) _delete_outputs({ARTIFACTS_PATH, RUNS_PATH, SCHEDULES_PATH}) + assert run.outputs['feature_scores'] and run.outputs['selected_features'] diff --git a/get_offline_features/function.yaml b/get_offline_features/function.yaml deleted file mode 100644 index 5a1780d98..000000000 --- a/get_offline_features/function.yaml +++ /dev/null @@ -1,127 +0,0 @@ -kind: job -metadata: - name: get-offline-features - tag: '' - hash: 22cc15eacc16e61f2fc1a9579fabde9ef7a2fce2 - project: '' - labels: - author: yonish - categories: - - data-preparation - - data-analysis - - feature-store -spec: - command: '' - args: [] - image: mlrun/mlrun - build: - functionSourceCode: IyBDb3B5cmlnaHQgMjAxOSBJZ3VhemlvCiMKIyBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgIkxpY2Vuc2UiKTsKIyB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiMgWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0CiMKIyAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wCiMKIyBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlCiMgZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gIkFTIElTIiBCQVNJUywKIyBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KIyBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kCiMgbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuCiMKZnJvbSB0eXBpbmcgaW1wb3J0IFVuaW9uLCBMaXN0LCBEaWN0CgppbXBvcnQgbWxydW4KaW1wb3J0IG1scnVuLmZlYXR1cmVfc3RvcmUgYXMgZnMKZnJvbSBtbHJ1bi5kYXRhc3RvcmUuc3RvcmVfcmVzb3VyY2VzIGltcG9ydCBpc19zdG9yZV91cmksIHBhcnNlX3N0b3JlX3VyaQpmcm9tIG1scnVuLmRhdGFzdG9yZS50YXJnZXRzIGltcG9ydCBnZXRfdGFyZ2V0X2RyaXZlciwga2luZF90b19kcml2ZXIKZnJvbSBtbHJ1bi5kYXRhc3RvcmUuYmFzZSBpbXBvcnQgRGF0YUl0ZW0KZnJvbSBtbHJ1bi5leGVjdXRpb24gaW1wb3J0IE1MQ2xpZW50Q3R4CmZyb20gbWxydW4udXRpbHMgaW1wb3J0IFN0b3JlUHJlZml4CmZyb20gbWxydW4uY29tbW9uLmhlbHBlcnMgaW1wb3J0IHBhcnNlX3ZlcnNpb25lZF9vYmplY3RfdXJpCmZyb20gbWxydW4uZXJyb3JzIGltcG9ydCBNTFJ1bkludmFsaWRBcmd1bWVudEVycm9yCgoKZGVmIGdldF9vZmZsaW5lX2ZlYXR1cmVzKAogICAgY29udGV4dDogTUxDbGllbnRDdHgsCiAgICBmZWF0dXJlX3ZlY3Rvcjogc3RyLAogICAgZmVhdHVyZXM6IFVuaW9uW0xpc3Rbc3RyXSwgTm9uZV0gPSBOb25lLAogICAgbGFiZWxfZmVhdHVyZTogc3RyID0gTm9uZSwKICAgIGRlc2NyaXB0aW9uOiBzdHIgPSBOb25lLAogICAgZW50aXR5X3Jvd3M6IERhdGFJdGVtID0gTm9uZSwKICAgIGVudGl0eV90aW1lc3RhbXBfY29sdW1uOiBzdHIgPSBOb25lLAogICAgdGFyZ2V0OiBVbmlvbltzdHIsIERpY3RdID0gTm9uZSwKICAgIHJ1bl9jb25maWc6IFVuaW9uW3N0ciwgRGljdF0gPSBOb25lLAogICAgZHJvcF9jb2x1bW5zOiBMaXN0W3N0cl0gPSBOb25lLAogICAgc3RhcnRfdGltZTogc3RyID0gTm9uZSwKICAgIGVuZF90aW1lOiBzdHIgPSBOb25lLAogICAgd2l0aF9pbmRleGVzOiBib29sID0gRmFsc2UsCiAgICB1cGRhdGVfc3RhdHM6IGJvb2wgPSBGYWxzZSwKKToKICAgICIiInJldHJpZXZlIG9mZmxpbmUgZmVhdHVyZSB2ZWN0b3IgcmVzdWx0cwoKICAgIHNwZWNpZnkgYSBmZWF0dXJlIHZlY3RvciBvYmplY3QvdXJpIGFuZCByZXRyaWV2ZSB0aGUgZGVzaXJlZCBmZWF0dXJlcywgdGhlaXIgbWV0YWRhdGEKICAgIGFuZCBzdGF0aXN0aWNzLiByZXR1cm5zIDpweTpjbGFzczpgfm1scnVuLmZlYXR1cmVfc3RvcmUuT2ZmbGluZVZlY3RvclJlc3BvbnNlYCwKICAgIHJlc3VsdHMgY2FuIGJlIHJldHVybmVkIGFzIGEgZGF0YWZyYW1lIG9yIHdyaXR0ZW4gdG8gYSB0YXJnZXQuCiAgICBJZiBmZWF0dXJlIHZlY3RvciBkb2VzIG5vdCBleGlzdCwgYSBuZXcgb25lIHdpbGwgYmUgY3JlYXRlZCBhbmQgc2F2ZWQgd2l0aCB0aGUgZ2l2ZW4gZmVhdHVyZXMuCgogICAgVGhlIHN0YXJ0X3RpbWUgYW5kIGVuZF90aW1lIGF0dHJpYnV0ZXMgYWxsb3cgZmlsdGVyaW5nIHRoZSBkYXRhIHRvIGEgZ2l2ZW4gdGltZSByYW5nZSwgdGhleSBhY2NlcHQKICAgIHN0cmluZyB2YWx1ZXMgb3IgcGFuZGFzIGBUaW1lc3RhbXBgIG9iamVjdHMsIHN0cmluZyB2YWx1ZXMgY2FuIGFsc28gYmUgcmVsYXRpdmUsIGZvciBleGFtcGxlOgogICAgIm5vdyIsICJub3cgLSAxZDJoIiwgIm5vdys1bSIsIHdoZXJlIGEgdmFsaWQgcGFuZGFzIFRpbWVkZWx0YSBzdHJpbmcgZm9sbG93cyB0aGUgdmVyYiAibm93IiwKICAgIGZvciB0aW1lIGFsaWdubWVudCB5b3UgY2FuIHVzZSB0aGUgdmVyYiAiZmxvb3IiIGUuZy4gIm5vdyAtMWQgZmxvb3IgMUgiIHdpbGwgYWxpZ24gdGhlIHRpbWUgdG8gdGhlIGxhc3QgaG91cgogICAgKHRoZSBmbG9vciBzdHJpbmcgaXMgcGFzc2VkIHRvIHBhbmRhcy5UaW1lc3RhbXAuZmxvb3IoKSwgY2FuIHVzZSBELCBILCBULCBTIGZvciBkYXksIGhvdXIsIG1pbiwgc2VjIGFsaWdubWVudCkKCgogICAgOnBhcmFtIGNvbnRleHQ6ICAgICAgICBNTFJ1biBjb250ZXh0CiAgICA6cGFyYW0gZmVhdHVyZV92ZWN0b3I6IGZlYXR1cmUgdmVjdG9yIHVyaQogICAgOnBhcmFtIGZlYXR1cmVzOiAgICAgICBSZWxldmFudCBvbmx5IGlmIGZlYXR1cmVfdmVjdG9yIG5vdCBleGlzdC4gbGlzdCBvZiBmZWF0dXJlIHRvIGNvbGxlY3QgdG8gdGhpcyB2ZWN0b3IKICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9ybWF0IFs8cHJvamVjdD4vXTxmZWF0dXJlX3NldD4uPGZlYXR1cmVfbmFtZSBvciAqPiBbYXMgPGFsaWFzPl0KICAgIDpwYXJhbSBsYWJlbF9mZWF0dXJlOiAgZmVhdHVyZSBuYW1lIHRvIGJlIHVzZWQgYXMgbGFiZWwgZGF0YQogICAgOnBhcmFtIGRlc2NyaXB0aW9uOiAgICB0ZXh0IGRlc2NyaXB0aW9uIG9mIHRoZSB2ZWN0b3IKICAgIDpwYXJhbSBlbnRpdHlfcm93czogICAgVVJJIG9mIHRoZSBkYXRhIGVudGl0eSByb3dzIHRvIGpvaW4gd2l0aAogICAgOnBhcmFtIHRhcmdldDogICAgICAgICB3aGVyZSB0byB3cml0ZSB0aGUgcmVzdWx0cyB0bwogICAgOnBhcmFtIGRyb3BfY29sdW1uczogICBsaXN0IG9mIGNvbHVtbnMgdG8gZHJvcCBmcm9tIHRoZSBmaW5hbCByZXN1bHQKICAgIDpwYXJhbSBlbnRpdHlfdGltZXN0YW1wX2NvbHVtbjogdGltZXN0YW1wIGNvbHVtbiBuYW1lIGluIHRoZSBlbnRpdHkgcm93cyBkYXRhZnJhbWUKICAgIDpwYXJhbSBydW5fY29uZmlnOiAgICAgZnVuY3Rpb24gYW5kL29yIHJ1biBjb25maWd1cmF0aW9uCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlZSA6cHk6Y2xhc3M6YH5tbHJ1bi5mZWF0dXJlX3N0b3JlLlJ1bkNvbmZpZ2AKICAgIDpwYXJhbSBzdGFydF90aW1lOiAgICAgIGRhdGV0aW1lLCBsb3cgbGltaXQgb2YgdGltZSBuZWVkZWQgdG8gYmUgZmlsdGVyZWQuIE9wdGlvbmFsCiAgICAgICAgZW50aXR5X3RpbWVzdGFtcF9jb2x1bW4gbXVzdCBiZSBwYXNzZWQgd2hlbiB1c2luZyB0aW1lIGZpbHRlcmluZwogICAgOnBhcmFtIGVuZF90aW1lOiAgICAgICAgZGF0ZXRpbWUsIGhpZ2ggbGltaXQgb2YgdGltZSBuZWVkZWQgdG8gYmUgZmlsdGVyZWQuIE9wdGlvbmFsCiAgICAgICAgZW50aXR5X3RpbWVzdGFtcF9jb2x1bW4gbXVzdCBiZSBwYXNzZWQgd2hlbiB1c2luZyB0aW1lIGZpbHRlcmluZwogICAgOnBhcmFtIHdpdGhfaW5kZXhlczogICAgcmV0dXJuIHZlY3RvciB3aXRoIGluZGV4IGNvbHVtbnMgKGRlZmF1bHQgRmFsc2UpCiAgICA6cGFyYW0gdXBkYXRlX3N0YXRzOiAgICB1cGRhdGUgZmVhdHVyZXMgc3RhdGlzdGljcyBmcm9tIHRoZSByZXF1ZXN0ZWQgZmVhdHVyZSBzZXRzIG9uIHRoZSB2ZWN0b3IuIERlZmF1bHQgaXMgRmFsc2UuCgogICAgOnJldHVybnMgZmVhdHVyZV92ZWN0b3IgaW5wdXQKICAgICIiIgoKICAgIGlmIGZlYXR1cmVzOgogICAgICAgICMgQ3JlYXRpbmcgYSBuZXcgRmVhdHVyZVZlY3RvciBhbmQgc2F2aW5nOgogICAgICAgIGlmIGlzX3N0b3JlX3VyaShmZWF0dXJlX3ZlY3Rvcik6CiAgICAgICAgICAgIHByZWZpeCwgbmV3X3VyaSA9IHBhcnNlX3N0b3JlX3VyaShmZWF0dXJlX3ZlY3RvcikKICAgICAgICAgICAgaWYgcHJlZml4ICE9IFN0b3JlUHJlZml4LkZlYXR1cmVWZWN0b3I6CiAgICAgICAgICAgICAgICByYWlzZSBNTFJ1bkludmFsaWRBcmd1bWVudEVycm9yKAogICAgICAgICAgICAgICAgICAgIGYicHJvdmlkZWQgc3RvcmUgdXJpICh7ZmVhdHVyZV92ZWN0b3J9KSBkb2VzIG5vdCByZXByZXNlbnQgYSBmZWF0dXJlIHZlY3RvciAocHJlZml4PXtwcmVmaXh9KSIKICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgZmVhdHVyZV92ZWN0b3IgPSBuZXdfdXJpCgogICAgICAgIGNvbnRleHQubG9nZ2VyLmluZm8oZiJDcmVhdGluZyBGZWF0dXJlVmVjdG9yIHtmZWF0dXJlX3ZlY3Rvcn0iKQogICAgICAgIHByb2plY3QsIG5hbWUsIHRhZywgXyA9IHBhcnNlX3ZlcnNpb25lZF9vYmplY3RfdXJpKGZlYXR1cmVfdmVjdG9yLCBtbHJ1bi5tbGNvbmYuZGVmYXVsdF9wcm9qZWN0KQogICAgICAgIHZlY3RvciA9IGZzLkZlYXR1cmVWZWN0b3IobmFtZSwgZmVhdHVyZXMsIGxhYmVsX2ZlYXR1cmU9bGFiZWxfZmVhdHVyZSwgZGVzY3JpcHRpb249ZGVzY3JpcHRpb24pCiAgICAgICAgdmVjdG9yLm1ldGFkYXRhLnByb2plY3QgPSBwcm9qZWN0CiAgICAgICAgdmVjdG9yLm1ldGFkYXRhLnRhZyA9IHRhZwogICAgICAgIHZlY3Rvci5zYXZlKCkKICAgICAgICBmZWF0dXJlX3ZlY3Rvcl91cmkgPSB2ZWN0b3IudXJpCiAgICBlbHNlOgogICAgICAgIGlmIGlzX3N0b3JlX3VyaShmZWF0dXJlX3ZlY3Rvcik6CiAgICAgICAgICAgIGZlYXR1cmVfdmVjdG9yX3VyaSA9IGZlYXR1cmVfdmVjdG9yCiAgICAgICAgZWxzZToKICAgICAgICAgICAgdmVjdG9yID0gZnMuZ2V0X2ZlYXR1cmVfdmVjdG9yKGZlYXR1cmVfdmVjdG9yKQogICAgICAgICAgICBmZWF0dXJlX3ZlY3Rvcl91cmkgPSB2ZWN0b3IudXJpCgogICAgIyBQcmVwYXJpbmcgZW50aXR5X3Jvd3M6CiAgICBpZiBlbnRpdHlfcm93cyBpcyBub3QgTm9uZToKICAgICAgICBjb250ZXh0LmxvZ2dlci5pbmZvKGYiQ3JlYXRpbmcgRGF0YUZyYW1lIGZyb20gZW50aXR5X3Jvd3MgPSB7ZW50aXR5X3Jvd3N9IikKICAgICAgICBlbnRpdHlfcm93cyA9IGVudGl0eV9yb3dzLmFzX2RmKCkKCiAgICAjIFByZXBhcmluZyB0YXJnZXQ6CiAgICBpZiB0YXJnZXQ6CiAgICAgICAgaWYgaXNpbnN0YW5jZSh0YXJnZXQsIHN0cik6CiAgICAgICAgICAgIHRhcmdldCA9IGtpbmRfdG9fZHJpdmVyW3RhcmdldF0oKQoKICAgICAgICBuYW1lID0gdGFyZ2V0Lm5hbWUgaWYgaGFzYXR0cih0YXJnZXQsICJuYW1lIikgZWxzZSB0YXJnZXRbIm5hbWUiXQogICAgICAgIGNvbnRleHQubG9nZ2VyLmluZm8oZiJQcmVwYXJpbmcgJ3tuYW1lfScgdGFyZ2V0IikKICAgICAgICB0YXJnZXQgPSBnZXRfdGFyZ2V0X2RyaXZlcih0YXJnZXQpCiAgICBpZiBoYXNhdHRyKHRhcmdldCwgJ3BhdGgnKSBhbmQgdGFyZ2V0LnBhdGg6CiAgICAgICAgY29udGV4dC5sb2dfcmVzdWx0KCJ0YXJnZXQiLCB0YXJnZXQucGF0aCkKCiAgICAjIFByZXBhcmluZyBydW5fY29uZmlnOgogICAgaWYgcnVuX2NvbmZpZyBhbmQgaXNpbnN0YW5jZShydW5fY29uZmlnLCBkaWN0KToKICAgICAgICBjb250ZXh0LmxvZ2dlci5pbmZvKCJQcmVwYXJpbmcgcnVuIGNvbmZpZ3VyYXRpb24iKQogICAgICAgIHJ1bl9jb25maWcgPSBmcy5SdW5Db25maWcoKipydW5fY29uZmlnKQoKICAgICMgQ2FsbGluZyBnZXRfb2ZmbGluZV9mZWF0dXJlczoKICAgIGNvbnRleHQubG9nZ2VyLmluZm8oCiAgICAgICAgZiJnZXR0aW5nIG9mZmxpbmUgZmVhdHVyZXMgZnJvbSB0aGUgRmVhdHVyZVZlY3RvciB7ZmVhdHVyZV92ZWN0b3J9IgogICAgKQogICAgZnMuZ2V0X29mZmxpbmVfZmVhdHVyZXMoCiAgICAgICAgZmVhdHVyZV92ZWN0b3I9ZmVhdHVyZV92ZWN0b3JfdXJpLAogICAgICAgIGVudGl0eV9yb3dzPWVudGl0eV9yb3dzLAogICAgICAgIGVudGl0eV90aW1lc3RhbXBfY29sdW1uPWVudGl0eV90aW1lc3RhbXBfY29sdW1uLAogICAgICAgIHRhcmdldD10YXJnZXQsCiAgICAgICAgcnVuX2NvbmZpZz1ydW5fY29uZmlnLAogICAgICAgIGRyb3BfY29sdW1ucz1kcm9wX2NvbHVtbnMsCiAgICAgICAgc3RhcnRfdGltZT1zdGFydF90aW1lLAogICAgICAgIGVuZF90aW1lPWVuZF90aW1lLAogICAgICAgIHdpdGhfaW5kZXhlcz13aXRoX2luZGV4ZXMsCiAgICAgICAgdXBkYXRlX3N0YXRzPXVwZGF0ZV9zdGF0cywKICAgICkKCiAgICBjb250ZXh0LmxvZ19yZXN1bHQoImZlYXR1cmVfdmVjdG9yIiwgZmVhdHVyZV92ZWN0b3IpCiAgICBjb250ZXh0LmxvZ19yZXN1bHQoImZlYXR1cmVfdmVjdG9yX3VyaSIsIGZlYXR1cmVfdmVjdG9yX3VyaSkK - commands: [] - code_origin: '' - origin_filename: '' - requirements: [] - entry_points: - get_offline_features: - name: get_offline_features - doc: 'retrieve offline feature vector results - - - specify a feature vector object/uri and retrieve the desired features, their - metadata - - and statistics. returns :py:class:`~mlrun.feature_store.OfflineVectorResponse`, - - results can be returned as a dataframe or written to a target. - - If feature vector does not exist, a new one will be created and saved with - the given features. - - - The start_time and end_time attributes allow filtering the data to a given - time range, they accept - - string values or pandas `Timestamp` objects, string values can also be relative, - for example: - - "now", "now - 1d2h", "now+5m", where a valid pandas Timedelta string follows - the verb "now", - - for time alignment you can use the verb "floor" e.g. "now -1d floor 1H" will - align the time to the last hour - - (the floor string is passed to pandas.Timestamp.floor(), can use D, H, T, - S for day, hour, min, sec alignment)' - parameters: - - name: context - type: MLClientCtx - doc: MLRun context - - name: feature_vector - type: str - doc: feature vector uri - - name: features - type: Union[List[str], ] - doc: Relevant only if feature_vector not exist. list of feature to collect - to this vector format [/]. [as - ] - default: null - - name: label_feature - type: str - doc: feature name to be used as label data - default: null - - name: description - type: str - doc: text description of the vector - default: null - - name: entity_rows - type: DataItem - doc: URI of the data entity rows to join with - default: null - - name: entity_timestamp_column - type: str - doc: timestamp column name in the entity rows dataframe - default: null - - name: target - type: Union[str, Dict] - doc: where to write the results to - default: null - - name: run_config - type: Union[str, Dict] - doc: function and/or run configuration see :py:class:`~mlrun.feature_store.RunConfig` - default: null - - name: drop_columns - type: List[str] - doc: list of columns to drop from the final result - default: null - - name: start_time - type: str - doc: datetime, low limit of time needed to be filtered. Optional entity_timestamp_column - must be passed when using time filtering - default: null - - name: end_time - type: str - doc: datetime, high limit of time needed to be filtered. Optional entity_timestamp_column - must be passed when using time filtering - default: null - - name: with_indexes - type: bool - doc: return vector with index columns (default False) - default: false - - name: update_stats - type: bool - doc: update features statistics from the requested feature sets on the vector. - Default is False. - default: false - outputs: [] - lineno: 28 - has_varargs: false - has_kwargs: false - description: retrieve offline feature vector results - default_handler: get_offline_features - disable_auto_mount: false - env: [] - priority_class_name: '' - preemption_mode: prevent - affinity: null - tolerations: null - security_context: {} -verbose: false diff --git a/get_offline_features/get_offline_features.ipynb b/get_offline_features/get_offline_features.ipynb deleted file mode 100644 index d97402a2e..000000000 --- a/get_offline_features/get_offline_features.ipynb +++ /dev/null @@ -1,1536 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# `get_offline_features()` from MLRun FeatureStore\n", - "\n", - "This MLRun Function has the following `params`:\n", - "\n", - "- `feature_vector: str`, feature vector uri.\n", - "\n", - "- `entity_rows: DataItem` = None, URI of the data entity rows to join with.\n", - "\n", - "- `entity_timestamp_column: str = None`, timestamp column name in the entity rows dataframe.\n", - "\n", - "- `target: Union[str, Dict] = None`, where to write the results to.\n", - "\n", - "- `run_config: Union[str, Dict] = None`, function and/or run configuration see :py:class:`~mlrun.feature_store.RunConfig`.\n", - "\n", - "- `drop_columns: List[str] = None`, list of columns to drop from the final result. \n", - "\n", - "- `start_time: str = None`, datetime, low limit of time needed to be filtered. Optional. `entity_timestamp_column` must be passed when using time filtering.\n", - "\n", - "- `end_time: str = None`, datetime, high limit of time needed to be filtered. Optional. `entity_timestamp_column` must be passed when using time filtering.\n", - "\n", - "- `with_indexes: bool = False`, return vector with index columns (default False).\n", - "\n", - "- `update_stats: bool = False`, update features statistics from the requested feature sets on the vector. Default is False." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import mlrun\n", - "import mlrun.feature_store as fstore\n", - "from mlrun.datastore.targets import CSVTarget\n", - "from mlrun.datastore.sources import CSVSource\n", - "from mlrun.run import get_dataitem\n", - "from mlrun.feature_store.steps import *\n", - "from mlrun.features import MinMaxValidator\n", - "import pandas as pd\n", - "import datetime\n", - "import os" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "> 2022-01-31 14:41:48,288 [info] loaded project get-offline-features from MLRun DB\n" - ] - } - ], - "source": [ - "ABS_PATH = 'v3io://users/{}/get_offline_features/'.format(os.environ['V3IO_USERNAME'])\n", - "# Initialize the MLRun project object\n", - "project = mlrun.get_or_create_project('get-offline-features', context=\"./\", user_project=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Generating the Same FeatureSets and FeatureVecotrs Based on the Stocks Example" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Create Sample Data For Demo" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "quotes = pd.DataFrame(\n", - " {\n", - " \"time\": [\n", - " pd.Timestamp(\"2016-05-25 13:30:00.023\"),\n", - " pd.Timestamp(\"2016-05-25 13:30:00.023\"),\n", - " pd.Timestamp(\"2016-05-25 13:30:00.030\"),\n", - " pd.Timestamp(\"2016-05-25 13:30:00.041\"),\n", - " pd.Timestamp(\"2016-05-25 13:30:00.048\"),\n", - " pd.Timestamp(\"2016-05-25 13:30:00.049\"),\n", - " pd.Timestamp(\"2016-05-25 13:30:00.072\"),\n", - " pd.Timestamp(\"2016-05-25 13:30:00.075\")\n", - " ],\n", - " \"ticker\": [\n", - " \"GOOG\",\n", - " \"MSFT\",\n", - " \"MSFT\",\n", - " \"MSFT\",\n", - " \"GOOG\",\n", - " \"AAPL\",\n", - " \"GOOG\",\n", - " \"MSFT\"\n", - " ],\n", - " \"bid\": [720.50, 51.95, 51.97, 51.99, 720.50, 97.99, 720.50, 52.01],\n", - " \"ask\": [720.93, 51.96, 51.98, 52.00, 720.93, 98.01, 720.88, 52.03]\n", - " }\n", - ")\n", - "\n", - "trades = pd.DataFrame(\n", - " {\n", - " \"time\": [\n", - " pd.Timestamp(\"2016-05-25 13:30:00.023\"),\n", - " pd.Timestamp(\"2016-05-25 13:30:00.038\"),\n", - " pd.Timestamp(\"2016-05-25 13:30:00.048\"),\n", - " pd.Timestamp(\"2016-05-25 13:30:00.048\"),\n", - " pd.Timestamp(\"2016-05-25 13:30:00.048\")\n", - " ],\n", - " \"ticker\": [\"MSFT\", \"MSFT\", \"GOOG\", \"GOOG\", \"AAPL\"],\n", - " \"price\": [51.95, 51.95, 720.77, 720.92, 98.0],\n", - " \"quantity\": [75, 155, 100, 100, 100]\n", - " }\n", - ")\n", - "\n", - "stocks = pd.DataFrame(\n", - " {\n", - " \"ticker\": [\"MSFT\", \"GOOG\", \"AAPL\"],\n", - " \"name\": [\"Microsoft Corporation\", \"Alphabet Inc\", \"Apple Inc\"],\n", - " \"exchange\": [\"NASDAQ\", \"NASDAQ\", \"NASDAQ\"]\n", - " }\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "def move_date(df, col):\n", - " max_date = df[col].max()\n", - " now_date = datetime.datetime.now()\n", - " delta = now_date - max_date \n", - " df[col] = df[col] + delta \n", - " return df\n", - "\n", - "quotes = move_date(quotes, \"time\")\n", - "trades = move_date(trades, \"time\")\n", - "trades.to_csv('trades.csv', index=False)\n", - "data_uri = os.path.join(ABS_PATH, 'trades.csv')" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
timetickerbidask
02022-01-31 14:41:48.260566GOOG720.50720.93
12022-01-31 14:41:48.260566MSFT51.9551.96
22022-01-31 14:41:48.267566MSFT51.9751.98
32022-01-31 14:41:48.278566MSFT51.9952.00
42022-01-31 14:41:48.285566GOOG720.50720.93
52022-01-31 14:41:48.286566AAPL97.9998.01
62022-01-31 14:41:48.309566GOOG720.50720.88
72022-01-31 14:41:48.312566MSFT52.0152.03
\n", - "
" - ], - "text/plain": [ - " time ticker bid ask\n", - "0 2022-01-31 14:41:48.260566 GOOG 720.50 720.93\n", - "1 2022-01-31 14:41:48.260566 MSFT 51.95 51.96\n", - "2 2022-01-31 14:41:48.267566 MSFT 51.97 51.98\n", - "3 2022-01-31 14:41:48.278566 MSFT 51.99 52.00\n", - "4 2022-01-31 14:41:48.285566 GOOG 720.50 720.93\n", - "5 2022-01-31 14:41:48.286566 AAPL 97.99 98.01\n", - "6 2022-01-31 14:41:48.309566 GOOG 720.50 720.88\n", - "7 2022-01-31 14:41:48.312566 MSFT 52.01 52.03" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "quotes" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
timetickerpricequantity
02022-01-31 14:41:48.288476MSFT51.9575
12022-01-31 14:41:48.303476MSFT51.95155
22022-01-31 14:41:48.313476GOOG720.77100
32022-01-31 14:41:48.313476GOOG720.92100
42022-01-31 14:41:48.313476AAPL98.00100
\n", - "
" - ], - "text/plain": [ - " time ticker price quantity\n", - "0 2022-01-31 14:41:48.288476 MSFT 51.95 75\n", - "1 2022-01-31 14:41:48.303476 MSFT 51.95 155\n", - "2 2022-01-31 14:41:48.313476 GOOG 720.77 100\n", - "3 2022-01-31 14:41:48.313476 GOOG 720.92 100\n", - "4 2022-01-31 14:41:48.313476 AAPL 98.00 100" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "trades" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
tickernameexchange
0MSFTMicrosoft CorporationNASDAQ
1GOOGAlphabet IncNASDAQ
2AAPLApple IncNASDAQ
\n", - "
" - ], - "text/plain": [ - " ticker name exchange\n", - "0 MSFT Microsoft Corporation NASDAQ\n", - "1 GOOG Alphabet Inc NASDAQ\n", - "2 AAPL Apple Inc NASDAQ" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "stocks" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Build & Ingest Simple Feature Set (stocks)" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
nameexchange
ticker
MSFTMicrosoft CorporationNASDAQ
GOOGAlphabet IncNASDAQ
AAPLApple IncNASDAQ
\n", - "
" - ], - "text/plain": [ - " name exchange\n", - "ticker \n", - "MSFT Microsoft Corporation NASDAQ\n", - "GOOG Alphabet Inc NASDAQ\n", - "AAPL Apple Inc NASDAQ" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# add feature set without time column (stock ticker metadata) \n", - "stocks_set = fstore.FeatureSet(\"stocks\", entities=[fstore.Entity(\"ticker\")])\n", - "fstore.ingest(stocks_set, stocks, infer_options=fstore.InferOptions.default())" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Build Advanced feature set - with feature engineering pipeline" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "quotes_set = fstore.FeatureSet(\"stock-quotes\", entities=[fstore.Entity(\"ticker\")])" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [], - "source": [ - "class MyMap(MapClass):\n", - " def __init__(self, multiplier=1, **kwargs):\n", - " super().__init__(**kwargs)\n", - " self._multiplier = multiplier\n", - "\n", - " def do(self, event):\n", - " event[\"multi\"] = event[\"bid\"] * self._multiplier\n", - " return event" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "mlrun-flow\n", - "\n", - "\n", - "\n", - "_start\n", - "\n", - "start\n", - "\n", - "\n", - "\n", - "MyMap\n", - "\n", - "MyMap\n", - "\n", - "\n", - "\n", - "_start->MyMap\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "storey.Extend\n", - "\n", - "storey.Extend\n", - "\n", - "\n", - "\n", - "MyMap->storey.Extend\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "filter\n", - "\n", - "filter\n", - "\n", - "\n", - "\n", - "storey.Extend->filter\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "FeaturesetValidator\n", - "\n", - "FeaturesetValidator\n", - "\n", - "\n", - "\n", - "filter->FeaturesetValidator\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "Aggregates\n", - "\n", - "Aggregates\n", - "\n", - "\n", - "\n", - "FeaturesetValidator->Aggregates\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "parquet\n", - "\n", - "\n", - "parquet\n", - "\n", - "\n", - "\n", - "Aggregates->parquet\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "nosql\n", - "\n", - "\n", - "nosql\n", - "\n", - "\n", - "\n", - "Aggregates->nosql\n", - "\n", - "\n", - "\n", - "\n", - "\n" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "quotes_set.graph.to(\"MyMap\", multiplier=3)\\\n", - " .to(\"storey.Extend\", _fn=\"({'extra': event['bid'] * 77})\")\\\n", - " .to(\"storey.Filter\", \"filter\", _fn=\"(event['bid'] > 51.92)\")\\\n", - " .to(FeaturesetValidator())\n", - "\n", - "quotes_set.add_aggregation(\"ask\", [\"sum\", \"max\"], \"1h\", \"10m\", name=\"asks1\")\n", - "quotes_set.add_aggregation(\"ask\", [\"sum\", \"max\"], \"5h\", \"10m\", name=\"asks5\")\n", - "quotes_set.add_aggregation(\"bid\", [\"min\", \"max\"], \"1h\", \"10m\", name=\"bids\")\n", - "\n", - "# add feature validation policy\n", - "quotes_set[\"bid\"] = fstore.Feature(validator=MinMaxValidator(min=52, severity=\"info\"))\n", - "\n", - "# add default target definitions and plot\n", - "quotes_set.set_targets()\n", - "quotes_set.plot(rankdir=\"LR\", with_targets=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Ingest Data Into Offline And Online Stores" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "info! bid value is smaller than min, key=['MSFT'] time=2022-01-31 14:41:51.377248+00:00 args={'min': 52, 'value': 51.95}\n", - "info! bid value is smaller than min, key=['MSFT'] time=2022-01-31 14:41:51.377927+00:00 args={'min': 52, 'value': 51.97}\n", - "info! bid value is smaller than min, key=['MSFT'] time=2022-01-31 14:41:51.378103+00:00 args={'min': 52, 'value': 51.99}\n", - "info! bid value is smaller than min, key=['MSFT'] time=2022-01-31 14:41:51.578640+00:00 args={'min': 52, 'value': 51.95}\n", - "info! bid value is smaller than min, key=['MSFT'] time=2022-01-31 14:41:51.581692+00:00 args={'min': 52, 'value': 51.97}\n", - "info! bid value is smaller than min, key=['MSFT'] time=2022-01-31 14:41:51.584351+00:00 args={'min': 52, 'value': 51.99}\n" - ] - }, - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
asks1_max_1hasks1_sum_1hasks5_max_5hasks5_sum_5hbids_max_1hbids_min_1htimebidaskmultiextra
ticker
GOOG720.93720.93720.93720.93720.50720.502022-01-31 14:41:48.260566720.50720.932161.5055478.50
MSFT51.9651.9651.9651.9651.9551.952022-01-31 14:41:48.26056651.9551.96155.854000.15
MSFT51.98103.9451.98103.9451.9751.952022-01-31 14:41:48.26756651.9751.98155.914001.69
MSFT52.00155.9452.00155.9451.9951.952022-01-31 14:41:48.27856651.9952.00155.974003.23
GOOG720.931441.86720.931441.86720.50720.502022-01-31 14:41:48.285566720.50720.932161.5055478.50
AAPL98.0198.0198.0198.0197.9997.992022-01-31 14:41:48.28656697.9998.01293.977545.23
GOOG720.932162.74720.932162.74720.50720.502022-01-31 14:41:48.309566720.50720.882161.5055478.50
MSFT52.03207.9752.03207.9752.0151.952022-01-31 14:41:48.31256652.0152.03156.034004.77
\n", - "
" - ], - "text/plain": [ - " asks1_max_1h asks1_sum_1h asks5_max_5h asks5_sum_5h bids_max_1h \\\n", - "ticker \n", - "GOOG 720.93 720.93 720.93 720.93 720.50 \n", - "MSFT 51.96 51.96 51.96 51.96 51.95 \n", - "MSFT 51.98 103.94 51.98 103.94 51.97 \n", - "MSFT 52.00 155.94 52.00 155.94 51.99 \n", - "GOOG 720.93 1441.86 720.93 1441.86 720.50 \n", - "AAPL 98.01 98.01 98.01 98.01 97.99 \n", - "GOOG 720.93 2162.74 720.93 2162.74 720.50 \n", - "MSFT 52.03 207.97 52.03 207.97 52.01 \n", - "\n", - " bids_min_1h time bid ask multi \\\n", - "ticker \n", - "GOOG 720.50 2022-01-31 14:41:48.260566 720.50 720.93 2161.50 \n", - "MSFT 51.95 2022-01-31 14:41:48.260566 51.95 51.96 155.85 \n", - "MSFT 51.95 2022-01-31 14:41:48.267566 51.97 51.98 155.91 \n", - "MSFT 51.95 2022-01-31 14:41:48.278566 51.99 52.00 155.97 \n", - "GOOG 720.50 2022-01-31 14:41:48.285566 720.50 720.93 2161.50 \n", - "AAPL 97.99 2022-01-31 14:41:48.286566 97.99 98.01 293.97 \n", - "GOOG 720.50 2022-01-31 14:41:48.309566 720.50 720.88 2161.50 \n", - "MSFT 51.95 2022-01-31 14:41:48.312566 52.01 52.03 156.03 \n", - "\n", - " extra \n", - "ticker \n", - "GOOG 55478.50 \n", - "MSFT 4000.15 \n", - "MSFT 4001.69 \n", - "MSFT 4003.23 \n", - "GOOG 55478.50 \n", - "AAPL 7545.23 \n", - "GOOG 55478.50 \n", - "MSFT 4004.77 " - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# save ingest data and print the FeatureSet spec\n", - "fstore.ingest(quotes_set, quotes)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Get an Offline Feature Vector" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [], - "source": [ - "features = [\n", - " \"stock-quotes.multi\",\n", - " \"stock-quotes.asks5_sum_5h as total_ask\",\n", - " \"stock-quotes.bids_min_1h\",\n", - " \"stock-quotes.bids_max_1h\",\n", - " \"stocks.*\",\n", - "]\n", - "\n", - "vector = fstore.FeatureVector(\"stocks-vec\", features)\n", - "vector.save()" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [], - "source": [ - "target_dict = CSVTarget('mycsv',path=os.path.join(ABS_PATH, 'my_csv.csv')).to_dict()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Using `get_offline_features()` " - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [], - "source": [ - "get_offline_features_fn = mlrun.import_function('hub://get_offline_features:development')" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "> 2022-01-31 14:41:52,066 [info] starting run get-offline-features-get_offline_features uid=956663b9a9ba448c9ea65e8e9245718e DB=http://mlrun-api:8080\n", - "> 2022-01-31 14:41:52,214 [info] Creating DataFrame from entity_rows = v3io://users/yonatan/get_offline_features/trades.csv\n", - "> 2022-01-31 14:41:52,292 [info] Preparing 'mycsv' target\n", - "> 2022-01-31 14:41:52,294 [info] getting offline features from the FeatureVector store://feature-vectors/get-offline-features-yonatan/stocks-vec\n", - "> 2022-01-31 14:41:52,708 [info] wrote target: {'name': 'mycsv', 'kind': 'csv', 'path': 'v3io://users/yonatan/get_offline_features/my_csv.csv', 'status': 'ready', 'updated': '2022-01-31T14:41:52.708534+00:00'}\n" - ] - }, - { - "data": { - "text/html": [ - "\n", - "
\n", - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
projectuiditerstartstatenamelabelsinputsparametersresultsartifacts
get-offline-features-yonatan0Jan 31 14:41:52completedget-offline-features-get_offline_features
v3io_user=yonatan
kind=
owner=yonatan
host=jupyter-yoni-647b99c95d-w4jlc
entity_rows
feature_vector=store://feature-vectors/get-offline-features-yonatan/stocks-vec
target={'name': 'mycsv', 'kind': 'csv', 'path': 'v3io://users/yonatan/get_offline_features/my_csv.csv', 'partitioned': False}
entity_timestamp_column=time
target=v3io://users/yonatan/get_offline_features/my_csv.csv
feature_vector=store://feature-vectors/get-offline-features-yonatan/stocks-vec
\n", - "
\n", - "
\n", - "
\n", - " Title\n", - " ×\n", - "
\n", - " \n", - "
\n", - "
\n" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n" - ] - }, - { - "data": { - "text/html": [ - " > to track results use the .show() or .logs() methods or click here to open in UI" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "> 2022-01-31 14:41:52,896 [info] run executed, status=completed\n" - ] - } - ], - "source": [ - "gof_run = get_offline_features_fn.run(\n", - " handler='get_offline_features',\n", - " inputs= {'entity_rows': data_uri},\n", - " params={'feature_vector': vector.uri,\n", - " 'target': target_dict,\n", - " 'entity_timestamp_column': \"time\",\n", - " },\n", - " local=True\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'store://feature-vectors/get-offline-features-yonatan/stocks-vec'" - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "gof_run.outputs['feature_vector']" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
Unnamed: 0pricequantitymultitotal_askbids_min_1hbids_max_1hnameexchange
0051.9575155.8551.9651.9551.95Microsoft CorporationNASDAQ
1151.9575155.91103.9451.9551.97Microsoft CorporationNASDAQ
2251.9575155.97155.9451.9551.99Microsoft CorporationNASDAQ
3351.9575156.03207.9751.9552.01Microsoft CorporationNASDAQ
4451.95155155.8551.9651.9551.95Microsoft CorporationNASDAQ
5551.95155155.91103.9451.9551.97Microsoft CorporationNASDAQ
6651.95155155.97155.9451.9551.99Microsoft CorporationNASDAQ
7751.95155156.03207.9751.9552.01Microsoft CorporationNASDAQ
88720.771002161.50720.93720.50720.50Alphabet IncNASDAQ
99720.771002161.501441.86720.50720.50Alphabet IncNASDAQ
1010720.771002161.502162.74720.50720.50Alphabet IncNASDAQ
1111720.921002161.50720.93720.50720.50Alphabet IncNASDAQ
1212720.921002161.501441.86720.50720.50Alphabet IncNASDAQ
1313720.921002161.502162.74720.50720.50Alphabet IncNASDAQ
141498.00100293.9798.0197.9997.99Apple IncNASDAQ
\n", - "
" - ], - "text/plain": [ - " Unnamed: 0 price quantity multi total_ask bids_min_1h \\\n", - "0 0 51.95 75 155.85 51.96 51.95 \n", - "1 1 51.95 75 155.91 103.94 51.95 \n", - "2 2 51.95 75 155.97 155.94 51.95 \n", - "3 3 51.95 75 156.03 207.97 51.95 \n", - "4 4 51.95 155 155.85 51.96 51.95 \n", - "5 5 51.95 155 155.91 103.94 51.95 \n", - "6 6 51.95 155 155.97 155.94 51.95 \n", - "7 7 51.95 155 156.03 207.97 51.95 \n", - "8 8 720.77 100 2161.50 720.93 720.50 \n", - "9 9 720.77 100 2161.50 1441.86 720.50 \n", - "10 10 720.77 100 2161.50 2162.74 720.50 \n", - "11 11 720.92 100 2161.50 720.93 720.50 \n", - "12 12 720.92 100 2161.50 1441.86 720.50 \n", - "13 13 720.92 100 2161.50 2162.74 720.50 \n", - "14 14 98.00 100 293.97 98.01 97.99 \n", - "\n", - " bids_max_1h name exchange \n", - "0 51.95 Microsoft Corporation NASDAQ \n", - "1 51.97 Microsoft Corporation NASDAQ \n", - "2 51.99 Microsoft Corporation NASDAQ \n", - "3 52.01 Microsoft Corporation NASDAQ \n", - "4 51.95 Microsoft Corporation NASDAQ \n", - "5 51.97 Microsoft Corporation NASDAQ \n", - "6 51.99 Microsoft Corporation NASDAQ \n", - "7 52.01 Microsoft Corporation NASDAQ \n", - "8 720.50 Alphabet Inc NASDAQ \n", - "9 720.50 Alphabet Inc NASDAQ \n", - "10 720.50 Alphabet Inc NASDAQ \n", - "11 720.50 Alphabet Inc NASDAQ \n", - "12 720.50 Alphabet Inc NASDAQ \n", - "13 720.50 Alphabet Inc NASDAQ \n", - "14 97.99 Apple Inc NASDAQ " - ] - }, - "execution_count": 18, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "mlrun.get_dataitem(gof_run.outputs['feature_vector']).as_df()" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "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.7.6" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/get_offline_features/get_offline_features.py b/get_offline_features/get_offline_features.py deleted file mode 100644 index 1a8b8ff03..000000000 --- a/get_offline_features/get_offline_features.py +++ /dev/null @@ -1,143 +0,0 @@ -# Copyright 2019 Iguazio -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -from typing import Union, List, Dict - -import mlrun -import mlrun.feature_store as fs -from mlrun.datastore.store_resources import is_store_uri, parse_store_uri -from mlrun.datastore.targets import get_target_driver, kind_to_driver -from mlrun.datastore.base import DataItem -from mlrun.execution import MLClientCtx -from mlrun.utils import StorePrefix -from mlrun.common.helpers import parse_versioned_object_uri -from mlrun.errors import MLRunInvalidArgumentError - - -def get_offline_features( - context: MLClientCtx, - feature_vector: str, - features: Union[List[str], None] = None, - label_feature: str = None, - description: str = None, - entity_rows: DataItem = None, - entity_timestamp_column: str = None, - target: Union[str, Dict] = None, - run_config: Union[str, Dict] = None, - drop_columns: List[str] = None, - start_time: str = None, - end_time: str = None, - with_indexes: bool = False, - update_stats: bool = False, -): - """retrieve offline feature vector results - - specify a feature vector object/uri and retrieve the desired features, their metadata - and statistics. returns :py:class:`~mlrun.feature_store.OfflineVectorResponse`, - results can be returned as a dataframe or written to a target. - If feature vector does not exist, a new one will be created and saved with the given features. - - The start_time and end_time attributes allow filtering the data to a given time range, they accept - string values or pandas `Timestamp` objects, string values can also be relative, for example: - "now", "now - 1d2h", "now+5m", where a valid pandas Timedelta string follows the verb "now", - for time alignment you can use the verb "floor" e.g. "now -1d floor 1H" will align the time to the last hour - (the floor string is passed to pandas.Timestamp.floor(), can use D, H, T, S for day, hour, min, sec alignment) - - - :param context: MLRun context - :param feature_vector: feature vector uri - :param features: Relevant only if feature_vector not exist. list of feature to collect to this vector - format [/]. [as ] - :param label_feature: feature name to be used as label data - :param description: text description of the vector - :param entity_rows: URI of the data entity rows to join with - :param target: where to write the results to - :param drop_columns: list of columns to drop from the final result - :param entity_timestamp_column: timestamp column name in the entity rows dataframe - :param run_config: function and/or run configuration - see :py:class:`~mlrun.feature_store.RunConfig` - :param start_time: datetime, low limit of time needed to be filtered. Optional - entity_timestamp_column must be passed when using time filtering - :param end_time: datetime, high limit of time needed to be filtered. Optional - entity_timestamp_column must be passed when using time filtering - :param with_indexes: return vector with index columns (default False) - :param update_stats: update features statistics from the requested feature sets on the vector. Default is False. - - :returns feature_vector input - """ - - if features: - # Creating a new FeatureVector and saving: - if is_store_uri(feature_vector): - prefix, new_uri = parse_store_uri(feature_vector) - if prefix != StorePrefix.FeatureVector: - raise MLRunInvalidArgumentError( - f"provided store uri ({feature_vector}) does not represent a feature vector (prefix={prefix})" - ) - feature_vector = new_uri - - context.logger.info(f"Creating FeatureVector {feature_vector}") - project, name, tag, _ = parse_versioned_object_uri(feature_vector, mlrun.mlconf.default_project) - vector = fs.FeatureVector(name, features, label_feature=label_feature, description=description) - vector.metadata.project = project - vector.metadata.tag = tag - vector.save() - feature_vector_uri = vector.uri - else: - if is_store_uri(feature_vector): - feature_vector_uri = feature_vector - else: - vector = fs.get_feature_vector(feature_vector) - feature_vector_uri = vector.uri - - # Preparing entity_rows: - if entity_rows is not None: - context.logger.info(f"Creating DataFrame from entity_rows = {entity_rows}") - entity_rows = entity_rows.as_df() - - # Preparing target: - if target: - if isinstance(target, str): - target = kind_to_driver[target]() - - name = target.name if hasattr(target, "name") else target["name"] - context.logger.info(f"Preparing '{name}' target") - target = get_target_driver(target) - if hasattr(target, 'path') and target.path: - context.log_result("target", target.path) - - # Preparing run_config: - if run_config and isinstance(run_config, dict): - context.logger.info("Preparing run configuration") - run_config = fs.RunConfig(**run_config) - - # Calling get_offline_features: - context.logger.info( - f"getting offline features from the FeatureVector {feature_vector}" - ) - fs.get_offline_features( - feature_vector=feature_vector_uri, - entity_rows=entity_rows, - entity_timestamp_column=entity_timestamp_column, - target=target, - run_config=run_config, - drop_columns=drop_columns, - start_time=start_time, - end_time=end_time, - with_indexes=with_indexes, - update_stats=update_stats, - ) - - context.log_result("feature_vector", feature_vector) - context.log_result("feature_vector_uri", feature_vector_uri) diff --git a/get_offline_features/item.yaml b/get_offline_features/item.yaml deleted file mode 100644 index 00d9c34c1..000000000 --- a/get_offline_features/item.yaml +++ /dev/null @@ -1,26 +0,0 @@ -apiVersion: v1 -categories: -- data-preparation -- data-analysis -- feature-store -description: retrieve offline feature vector results -doc: '' -example: get_offline_features.ipynb -generationDate: 2022-08-28:17-25 -hidden: false -icon: '' -labels: - author: yonish -maintainers: [] -marketplaceType: '' -mlrunVersion: 1.6.3 -name: get_offline_features -platformVersion: 3.5.0 -spec: - filename: get_offline_features.py - handler: get_offline_features - image: mlrun/mlrun - kind: job - requirements: [] -url: '' -version: 1.3.0 diff --git a/get_offline_features/test_get_offline_features.py b/get_offline_features/test_get_offline_features.py deleted file mode 100644 index 21913e011..000000000 --- a/get_offline_features/test_get_offline_features.py +++ /dev/null @@ -1,239 +0,0 @@ -# Copyright 2019 Iguazio -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -import os -import tempfile -import shutil -import datetime - -import pytest -import mlrun -import mlrun.feature_store as fstore -from mlrun.datastore.targets import CSVTarget -from mlrun.feature_store.steps import * -from mlrun.features import MinMaxValidator -from mlrun.run import get_dataitem - - -REQUIRED_ENV_VARS = [ - "MLRUN_DBPATH", - "MLRUN_ARTIFACT_PATH", - "V3IO_USERNAME", - "V3IO_API", - "V3IO_ACCESS_KEY", -] - - -def _validate_environment_variables() -> bool: - """ - Checks that all required Environment variables are set. - """ - environment_keys = os.environ.keys() - return all(key in environment_keys for key in REQUIRED_ENV_VARS) - - -def _set_environment(): - """ - Creating project and temp dir for the project. - """ - artifact_path = tempfile.TemporaryDirectory().name - os.makedirs(artifact_path) - project = mlrun.get_or_create_project( - "get-offline-features-test", context="./", user_project=True - ) - return artifact_path, project - - -def _cleanup_environment(artifact_path: str): - """ - Cleanup the test environment, deleting files and artifacts created during the test. - - :param artifact_path: The artifact path to delete. - """ - # Clean the local directory: - for test_output in [ - *os.listdir(artifact_path), - "schedules", - "runs", - "artifacts", - "functions", - ]: - test_output_path = os.path.abspath(f"./{test_output}") - if os.path.exists(test_output_path): - if os.path.isdir(test_output_path): - shutil.rmtree(test_output_path) - else: - os.remove(test_output_path) - - # Clean the artifacts directory: - shutil.rmtree(artifact_path) - - -def create_dataframes() -> (pd.DataFrame, pd.DataFrame, pd.DataFrame): - """ - Creates all the necessary DataFrames to the test. - """ - - def move_date(df, col): - max_date = df[col].max() - now_date = datetime.datetime.now() - delta = now_date - max_date - df[col] = df[col] + delta - return df - - stocks = pd.DataFrame( - { - "ticker": ["MSFT", "GOOG", "AAPL"], - "name": ["Microsoft Corporation", "Alphabet Inc", "Apple Inc"], - "exchange": ["NASDAQ", "NASDAQ", "NASDAQ"], - } - ) - - quotes = pd.DataFrame( - { - "time": [ - pd.Timestamp("2016-05-25 13:30:00.023"), - pd.Timestamp("2016-05-25 13:30:00.023"), - pd.Timestamp("2016-05-25 13:30:00.030"), - pd.Timestamp("2016-05-25 13:30:00.041"), - pd.Timestamp("2016-05-25 13:30:00.048"), - pd.Timestamp("2016-05-25 13:30:00.049"), - pd.Timestamp("2016-05-25 13:30:00.072"), - pd.Timestamp("2016-05-25 13:30:00.075"), - ], - "ticker": ["GOOG", "MSFT", "MSFT", "MSFT", "GOOG", "AAPL", "GOOG", "MSFT"], - "bid": [720.50, 51.95, 51.97, 51.99, 720.50, 97.99, 720.50, 52.01], - "ask": [720.93, 51.96, 51.98, 52.00, 720.93, 98.01, 720.88, 52.03], - } - ) - - trades = pd.DataFrame( - { - "time": [ - pd.Timestamp("2016-05-25 13:30:00.023"), - pd.Timestamp("2016-05-25 13:30:00.038"), - pd.Timestamp("2016-05-25 13:30:00.048"), - pd.Timestamp("2016-05-25 13:30:00.048"), - pd.Timestamp("2016-05-25 13:30:00.048"), - ], - "ticker": ["MSFT", "MSFT", "GOOG", "GOOG", "AAPL"], - "price": [51.95, 51.95, 720.77, 720.92, 98.0], - "quantity": [75, 155, 100, 100, 100], - } - ) - quotes = move_date(quotes, "time") - trades = move_date(trades, "time") - return quotes, trades, stocks - - -class MyMap(MapClass): - def __init__(self, multiplier=1, **kwargs): - super().__init__(**kwargs) - self._multiplier = multiplier - - def do(self, event): - event["multi"] = event["bid"] * self._multiplier - return event - - -def _create_feature_set(): - """ - Creating all the necessary FeatureSets for the test. - """ - stocks_set = fstore.FeatureSet("stocks", entities=[fstore.Entity("ticker")]) - - quotes_set = fstore.FeatureSet("stock-quotes", entities=[fstore.Entity("ticker")]) - - quotes_set.graph.to("MyMap", multiplier=3).to( - "storey.Extend", _fn="({'extra': event['bid'] * 77})" - ).to("storey.Filter", "filter", _fn="(event['bid'] > 51.92)").to( - FeaturesetValidator() - ) - - quotes_set.add_aggregation("ask", ["sum", "max"], "1h", "10m", name="asks1") - quotes_set.add_aggregation("ask", ["sum", "max"], "5h", "10m", name="asks5") - quotes_set.add_aggregation("bid", ["min", "max"], "1h", "10m", name="bids") - - # add feature validation policy - quotes_set["bid"] = fstore.Feature( - validator=MinMaxValidator(min=52, severity="info") - ) - - # add default target definitions and plot - quotes_set.set_targets() - return quotes_set, stocks_set - - -@pytest.mark.skipif( - condition=not _validate_environment_variables(), - reason="Project's environment variables are not set", -) -def test_get_offline_vector(): - # Creating project: - artifact_path, project = _set_environment() - - # Importing the marketplace function: - gof_fn = mlrun.import_function("function.yaml") - - # Creating the dataframes: - quotes, trades, stocks = create_dataframes() - - # Defining features for the FeatureVector: - features = [ - "stock-quotes.multi", - "stock-quotes.asks5_sum_5h as total_ask", - "stock-quotes.bids_min_1h", - "stock-quotes.bids_max_1h", - "stocks.*", - ] - - # Creating the FeatureSets and ingesting them: - quotes_set, stocks_set = _create_feature_set() - fstore.ingest(stocks_set, stocks) - fstore.ingest(quotes_set, quotes) - - # Saving the trades dataframe as a csv to use as entity_rows: - trades_uri = os.path.join(artifact_path, "trades.csv") - trades.to_csv(trades_uri, index=False) - - # Creating target for the FeatureVector: - target_dict = CSVTarget( - "mycsv", path=os.path.join(artifact_path, "my_csv.csv") - ).to_dict() - - # Running the getting_offline_features function: - gof_run = None - try: - gof_run = gof_fn.run( - handler="get_offline_features", - inputs={"entity_rows": trades_uri}, - params={ - "feature_vector": "stocks-vec", - "features": features, - "target": target_dict, - "entity_timestamp_column": "time", - }, - local=True, - ) - - except Exception as e: - print(f"- The test failed - raised the following error:\n- {e}") - - target_df = get_dataitem(gof_run.outputs["target"]).as_df() - vector_df = get_dataitem(gof_run.outputs["feature_vector"]).as_df() - - # Asserting that the target and FeatureVector dataframes are the same: - assert mlrun.datastore.is_store_uri(gof_run.outputs["feature_vector_uri"]) - assert vector_df.equals(target_df), "Target and feature vector are not the same" - _cleanup_environment(artifact_path) diff --git a/hugging_face_classifier_trainer/function.yaml b/hugging_face_classifier_trainer/function.yaml deleted file mode 100644 index 65f5aeb10..000000000 --- a/hugging_face_classifier_trainer/function.yaml +++ /dev/null @@ -1,370 +0,0 @@ -kind: job -metadata: - name: hugging-face-classifier-trainer - tag: '' - hash: f9d8aa4a2c66e24fa418bb163829adc3e2ada06c - project: '' - labels: - author: davids - categories: - - deep-learning - - huggingface - - machine-learning - - model-training -spec: - command: '' - args: [] - image: '' - build: - functionSourceCode: aW1wb3J0IG9zCmltcG9ydCBzaHV0aWwKaW1wb3J0IHRlbXBmaWxlCmltcG9ydCB6aXBmaWxlCmZyb20gYWJjIGltcG9ydCBBQkMKZnJvbSB0eXBpbmcgaW1wb3J0IEFueSwgQ2FsbGFibGUsIERpY3QsIExpc3QsIE9wdGlvbmFsLCBUdXBsZSwgVW5pb24KCmltcG9ydCBtbHJ1bgppbXBvcnQgbWxydW4uZGF0YXN0b3JlCmltcG9ydCBtbHJ1bi51dGlscwppbXBvcnQgbnVtcHkgYXMgbnAKaW1wb3J0IHBhbmRhcyBhcyBwZAppbXBvcnQgdHJhbnNmb3JtZXJzCmZyb20gZGF0YXNldHMgaW1wb3J0IERhdGFzZXQsIGxvYWRfZGF0YXNldCwgbG9hZF9tZXRyaWMKZnJvbSBtbHJ1biBpbXBvcnQgTUxDbGllbnRDdHgKZnJvbSBtbHJ1biBpbXBvcnQgZmVhdHVyZV9zdG9yZSBhcyBmcwpmcm9tIG1scnVuLmFydGlmYWN0cyBpbXBvcnQgQXJ0aWZhY3QsIFBsb3RseUFydGlmYWN0CmZyb20gbWxydW4uZGF0YXN0b3JlIGltcG9ydCBEYXRhSXRlbQpmcm9tIG1scnVuLmZyYW1ld29ya3MuX2NvbW1vbiBpbXBvcnQgQ29tbW9uVHlwZXMsIE1MUnVuSW50ZXJmYWNlCmZyb20gbWxydW4udXRpbHMgaW1wb3J0IGNyZWF0ZV9jbGFzcwpmcm9tIHBsb3RseSBpbXBvcnQgZ3JhcGhfb2JqZWN0cyBhcyBnbwpmcm9tIHNrbGVhcm4ubW9kZWxfc2VsZWN0aW9uIGltcG9ydCB0cmFpbl90ZXN0X3NwbGl0CmZyb20gdHJhbnNmb3JtZXJzIGltcG9ydCAoCiAgICBBdXRvVG9rZW5pemVyLAogICAgRGF0YUNvbGxhdG9yV2l0aFBhZGRpbmcsCiAgICBFdmFsUHJlZGljdGlvbiwKICAgIFByZVRyYWluZWRNb2RlbCwKICAgIFByZVRyYWluZWRUb2tlbml6ZXIsCiAgICBUcmFpbmVyLAogICAgVHJhaW5lckNhbGxiYWNrLAogICAgVHJhaW5lckNvbnRyb2wsCiAgICBUcmFpbmVyU3RhdGUsCiAgICBUcmFpbmluZ0FyZ3VtZW50cywKKQoKCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLWZyb20gTUxSVU4tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQpjbGFzcyBIRk9SVE9wdGltaXplck1MUnVuSW50ZXJmYWNlKE1MUnVuSW50ZXJmYWNlLCBBQkMpOgogICAgIiIiCiAgICBJbnRlcmZhY2UgZm9yIGFkZGluZyBNTFJ1biBmZWF0dXJlcyBmb3IgdGVuc29yZmxvdyBrZXJhcyBBUEkuCiAgICAiIiIKCiAgICAjIE1MUnVuJ3MgY29udGV4dCBkZWZhdWx0IG5hbWU6CiAgICBERUZBVUxUX0NPTlRFWFRfTkFNRSA9ICJtbHJ1bi1odWdnaW5nZmFjZSIKCiAgICAjIEF0dHJpYnV0ZXMgdG8gYmUgaW5zZXJ0ZWQgc28gdGhlIE1MUnVuIGludGVyZmFjZSB3aWxsIGJlIGZ1bGx5IGVuYWJsZWQuCiAgICBfUFJPUEVSVElFUyA9IHsKICAgICAgICAiX2F1dG9fbG9nIjogRmFsc2UsCiAgICAgICAgIl9jb250ZXh0IjogTm9uZSwKICAgICAgICAiX21vZGVsX25hbWUiOiAibW9kZWwiLAogICAgICAgICJfdGFnIjogIiIsCiAgICAgICAgIl9sYWJlbHMiOiBOb25lLAogICAgICAgICJfZXh0cmFfZGF0YSI6IE5vbmUsCiAgICB9CiAgICBfTUVUSE9EUyA9IFsiZW5hYmxlX2F1dG9fbG9nZ2luZyJdCiAgICAjIEF0dHJpYnV0ZXMgdG8gcmVwbGFjZSBzbyB0aGUgTUxSdW4gaW50ZXJmYWNlIHdpbGwgYmUgZnVsbHkgZW5hYmxlZC4KICAgIF9SRVBMQUNFRF9NRVRIT0RTID0gWwogICAgICAgICJvcHRpbWl6ZSIsCiAgICBdCgogICAgQGNsYXNzbWV0aG9kCiAgICBkZWYgYWRkX2ludGVyZmFjZSgKICAgICAgICBjbHMsCiAgICAgICAgb2JqLAogICAgICAgIHJlc3RvcmF0aW9uOiBDb21tb25UeXBlcy5NTFJ1bkludGVyZmFjZVJlc3RvcmF0aW9uVHlwZSA9IE5vbmUsCiAgICApOgogICAgICAgICIiIgogICAgICAgIEVucmljaCB0aGUgb2JqZWN0IHdpdGggdGhpcyBpbnRlcmZhY2UgcHJvcGVydGllcywgbWV0aG9kcyBhbmQgZnVuY3Rpb25zLCBzbyBpdCB3aWxsIGhhdmUgdGhpcyBUZW5zb3JGbG93LktlcmFzCiAgICAgICAgTUxSdW4ncyBmZWF0dXJlcy4KICAgICAgICA6cGFyYW0gb2JqOiAgICAgICAgICAgICAgICAgICAgIFRoZSBvYmplY3QgdG8gZW5yaWNoIGhpcyBpbnRlcmZhY2UuCiAgICAgICAgOnBhcmFtIHJlc3RvcmF0aW9uOiBSZXN0b3JhdGlvbiBpbmZvcm1hdGlvbiB0dXBsZSBhcyByZXR1cm5lZCBmcm9tICdyZW1vdmVfaW50ZXJmYWNlJyBpbiBvcmRlciB0bwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWRkIHRoZSBpbnRlcmZhY2UgaW4gYSBjZXJ0YWluIHN0YXRlLgogICAgICAgICIiIgogICAgICAgIHN1cGVyKEhGT1JUT3B0aW1pemVyTUxSdW5JbnRlcmZhY2UsIGNscykuYWRkX2ludGVyZmFjZSgKICAgICAgICAgICAgb2JqPW9iaiwgcmVzdG9yYXRpb249cmVzdG9yYXRpb24KICAgICAgICApCgogICAgQGNsYXNzbWV0aG9kCiAgICBkZWYgbWxydW5fb3B0aW1pemUoY2xzKToKICAgICAgICAiIiIKICAgICAgICBNTFJ1bidzIHRmLmtlcmFzLk1vZGVsLmZpdCB3cmFwcGVyLiBJdCB3aWxsIHNldHVwIHRoZSBvcHRpbWl6ZXIgd2hlbiB1c2luZyBob3Jvdm9kLiBUaGUgb3B0aW1pemVyIG11c3QgYmUKICAgICAgICBwYXNzZWQgaW4gYSBrZXl3b3JkIGFyZ3VtZW50IGFuZCB3aGVuIHVzaW5nIGhvcm92b2QsIGl0IG11c3QgYmUgcGFzc2VkIGFzIGFuIE9wdGltaXplciBpbnN0YW5jZSwgbm90IGEgc3RyaW5nLgoKICAgICAgICByYWlzZSBNTFJ1bkludmFsaWRBcmd1bWVudEVycm9yOiBJbiBjYXNlIHRoZSBvcHRpbWl6ZXIgcHJvdmlkZWQgZGlkIG5vdCBmb2xsb3cgdGhlIGluc3RydWN0aW9ucyBhYm92ZS4KICAgICAgICAiIiIKCiAgICAgICAgZGVmIHdyYXBwZXIoc2VsZiwgKmFyZ3MsICoqa3dhcmdzKToKICAgICAgICAgICAgc2F2ZV9kaXIgPSBjbHMuX2dldF9mdW5jdGlvbl9hcmd1bWVudCgKICAgICAgICAgICAgICAgIHNlbGYub3B0aW1pemUsCiAgICAgICAgICAgICAgICBhcmd1bWVudF9uYW1lPSJzYXZlX2RpciIsCiAgICAgICAgICAgICAgICBwYXNzZWRfYXJncz1hcmdzLAogICAgICAgICAgICAgICAgcGFzc2VkX2t3YXJncz1rd2FyZ3MsCiAgICAgICAgICAgIClbMF0KCiAgICAgICAgICAgICMgQ2FsbCB0aGUgb3JpZ2luYWwgb3B0aW1pemUgbWV0aG9kOgogICAgICAgICAgICByZXN1bHQgPSBzZWxmLm9yaWdpbmFsX29wdGltaXplKCphcmdzLCAqKmt3YXJncykKCiAgICAgICAgICAgIGlmIHNlbGYuX2F1dG9fbG9nOgogICAgICAgICAgICAgICAgIyBMb2cgdGhlIG9ubnggbW9kZWw6CiAgICAgICAgICAgICAgICBzZWxmLl9jb250ZXh0LmxvZ19tb2RlbCgKICAgICAgICAgICAgICAgICAgICBrZXk9Im1vZGVsIiwKICAgICAgICAgICAgICAgICAgICBkYl9rZXk9c2VsZi5fbW9kZWxfbmFtZSwKICAgICAgICAgICAgICAgICAgICBtb2RlbF9maWxlPWYie3NhdmVfZGlyfS9tb2RlbF9vcHRpbWl6ZWQub25ueCIsCiAgICAgICAgICAgICAgICAgICAgdGFnPXNlbGYuX3RhZywKICAgICAgICAgICAgICAgICAgICBmcmFtZXdvcms9Ik9OTlgiLAogICAgICAgICAgICAgICAgICAgIGxhYmVscz1zZWxmLl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgZXh0cmFfZGF0YT1zZWxmLl9leHRyYV9kYXRhLAogICAgICAgICAgICAgICAgKQoKICAgICAgICAgICAgcmV0dXJuIHJlc3VsdAoKICAgICAgICByZXR1cm4gd3JhcHBlcgoKICAgIGRlZiBlbmFibGVfYXV0b19sb2dnaW5nKAogICAgICAgIHNlbGYsCiAgICAgICAgY29udGV4dDogbWxydW4uTUxDbGllbnRDdHgsCiAgICAgICAgbW9kZWxfbmFtZTogc3RyID0gIm1vZGVsIiwKICAgICAgICB0YWc6IHN0ciA9ICIiLAogICAgICAgIGxhYmVsczogRGljdFtzdHIsIHN0cl0gPSBOb25lLAogICAgICAgIGV4dHJhX2RhdGE6IGRpY3QgPSBOb25lLAogICAgKToKICAgICAgICBzZWxmLl9hdXRvX2xvZyA9IFRydWUKCiAgICAgICAgc2VsZi5fY29udGV4dCA9IGNvbnRleHQKICAgICAgICBzZWxmLl9tb2RlbF9uYW1lID0gbW9kZWxfbmFtZQogICAgICAgIHNlbGYuX3RhZyA9IHRhZwogICAgICAgIHNlbGYuX2xhYmVscyA9IGxhYmVscwogICAgICAgIHNlbGYuX2V4dHJhX2RhdGEgPSBleHRyYV9kYXRhCgoKY2xhc3MgSEZUcmFpbmVyTUxSdW5JbnRlcmZhY2UoTUxSdW5JbnRlcmZhY2UsIEFCQyk6CiAgICAiIiIKICAgIEludGVyZmFjZSBmb3IgYWRkaW5nIE1MUnVuIGZlYXR1cmVzIGZvciB0ZW5zb3JmbG93IGtlcmFzIEFQSS4KICAgICIiIgoKICAgICMgTUxSdW5zIGNvbnRleHQgZGVmYXVsdCBuYW1lOgogICAgREVGQVVMVF9DT05URVhUX05BTUUgPSAibWxydW4taHVnZ2luZ2ZhY2UiCgogICAgIyBBdHRyaWJ1dGVzIHRvIHJlcGxhY2Ugc28gdGhlIE1MUnVuIGludGVyZmFjZSB3aWxsIGJlIGZ1bGx5IGVuYWJsZWQuCiAgICBfUkVQTEFDRURfTUVUSE9EUyA9IFsKICAgICAgICAidHJhaW4iLAogICAgICAgICMgImV2YWx1YXRlIgogICAgXQoKICAgIEBjbGFzc21ldGhvZAogICAgZGVmIGFkZF9pbnRlcmZhY2UoCiAgICAgICAgY2xzLAogICAgICAgIG9iajogVHJhaW5lciwKICAgICAgICByZXN0b3JhdGlvbjogQ29tbW9uVHlwZXMuTUxSdW5JbnRlcmZhY2VSZXN0b3JhdGlvblR5cGUgPSBOb25lLAogICAgKToKICAgICAgICAiIiIKICAgICAgICBFbnJpY2ggdGhlIG9iamVjdCB3aXRoIHRoaXMgaW50ZXJmYWNlIHByb3BlcnRpZXMsIG1ldGhvZHMgYW5kIGZ1bmN0aW9ucywgc28gaXQgd2lsbCBoYXZlIHRoaXMgVGVuc29yRmxvdy5LZXJhcwogICAgICAgIE1MUnVucyBmZWF0dXJlcy4KICAgICAgICA6cGFyYW0gb2JqOiAgICAgICAgICAgICAgICAgICAgIFRoZSBvYmplY3QgdG8gZW5yaWNoIGhpcyBpbnRlcmZhY2UuCiAgICAgICAgOnBhcmFtIHJlc3RvcmF0aW9uOiBSZXN0b3JhdGlvbiBpbmZvcm1hdGlvbiB0dXBsZSBhcyByZXR1cm5lZCBmcm9tICdyZW1vdmVfaW50ZXJmYWNlJyBpbiBvcmRlciB0bwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWRkIHRoZSBpbnRlcmZhY2UgaW4gYSBjZXJ0YWluIHN0YXRlLgogICAgICAgICIiIgoKICAgICAgICBzdXBlcihIRlRyYWluZXJNTFJ1bkludGVyZmFjZSwgY2xzKS5hZGRfaW50ZXJmYWNlKAogICAgICAgICAgICBvYmo9b2JqLCByZXN0b3JhdGlvbj1yZXN0b3JhdGlvbgogICAgICAgICkKCiAgICBAY2xhc3NtZXRob2QKICAgIGRlZiBtbHJ1bl90cmFpbihjbHMpOgoKICAgICAgICAiIiIKICAgICAgICBNTFJ1bnMgdGYua2VyYXMuTW9kZWwuZml0IHdyYXBwZXIuIEl0IHdpbGwgc2V0dXAgdGhlIG9wdGltaXplciB3aGVuIHVzaW5nIGhvcm92b2QuIFRoZSBvcHRpbWl6ZXIgbXVzdCBiZQogICAgICAgIHBhc3NlZCBpbiBhIGtleXdvcmQgYXJndW1lbnQgYW5kIHdoZW4gdXNpbmcgaG9yb3ZvZCwgaXQgbXVzdCBiZSBwYXNzZWQgYXMgYW4gT3B0aW1pemVyIGluc3RhbmNlLCBub3QgYSBzdHJpbmcuCgogICAgICAgIHJhaXNlIE1MUnVuSW52YWxpZEFyZ3VtZW50RXJyb3I6IEluIGNhc2UgdGhlIG9wdGltaXplciBwcm92aWRlZCBkaWQgbm90IGZvbGxvdyB0aGUgaW5zdHJ1Y3Rpb25zIGFib3ZlLgogICAgICAgICIiIgoKICAgICAgICBkZWYgd3JhcHBlcihzZWxmOiBUcmFpbmVyLCAqYXJncywgKiprd2FyZ3MpOgogICAgICAgICAgICAjIFJlc3RvcmUgdGhlIGV2YWx1YXRpb24gbWV0aG9kIGFzIGB0cmFpbmAgd2lsbCB1c2UgaXQ6CiAgICAgICAgICAgICMgY2xzLl9yZXN0b3JlX2F0dHJpYnV0ZShvYmo9c2VsZiwgYXR0cmlidXRlX25hbWU9ImV2YWx1YXRlIikKCiAgICAgICAgICAgICMgQ2FsbCB0aGUgb3JpZ2luYWwgZml0IG1ldGhvZDoKICAgICAgICAgICAgcmVzdWx0ID0gc2VsZi5vcmlnaW5hbF90cmFpbigqYXJncywgKiprd2FyZ3MpCgogICAgICAgICAgICAjIFJlcGxhY2UgdGhlIGV2YWx1YXRpb24gbWV0aG9kIGFnYWluOgogICAgICAgICAgICAjIGNscy5fcmVwbGFjZV9mdW5jdGlvbihvYmo9c2VsZiwgZnVuY3Rpb25fbmFtZT0iZXZhbHVhdGUiKQoKICAgICAgICAgICAgcmV0dXJuIHJlc3VsdAoKICAgICAgICByZXR1cm4gd3JhcHBlcgoKCmNsYXNzIE1MUnVuQ2FsbGJhY2soVHJhaW5lckNhbGxiYWNrKToKICAgICIiIgogICAgQ2FsbGJhY2sgZm9yIGNvbGxlY3RpbmcgbG9ncyBkdXJpbmcgdHJhaW5pbmcgLyBldmFsdWF0aW9uIG9mIHRoZSBgVHJhaW5lcmAgQVBJLgogICAgIiIiCgogICAgZGVmIF9faW5pdF9fKAogICAgICAgIHNlbGYsCiAgICAgICAgY29udGV4dDogbWxydW4uTUxDbGllbnRDdHggPSBOb25lLAogICAgICAgIG1vZGVsX25hbWU6IHN0ciA9ICJtb2RlbCIsCiAgICAgICAgdGFnOiBzdHIgPSAiIiwKICAgICAgICBsYWJlbHM6IERpY3Rbc3RyLCBzdHJdID0gTm9uZSwKICAgICAgICBleHRyYV9kYXRhOiBkaWN0ID0gTm9uZSwKICAgICk6CiAgICAgICAgc3VwZXIoKS5fX2luaXRfXygpCgogICAgICAgICMgU3RvcmUgdGhlIGNvbmZpZ3VyYXRpb25zOgogICAgICAgIHNlbGYuX2NvbnRleHQgPSAoCiAgICAgICAgICAgIGNvbnRleHQKICAgICAgICAgICAgaWYgY29udGV4dCBpcyBub3QgTm9uZQogICAgICAgICAgICBlbHNlIG1scnVuLmdldF9vcl9jcmVhdGVfY3R4KCIuL21scnVuLWh1Z2dpbmdmYWNlIikKICAgICAgICApCiAgICAgICAgc2VsZi5fbW9kZWxfbmFtZSA9IG1vZGVsX25hbWUKICAgICAgICBzZWxmLl90YWcgPSB0YWcKICAgICAgICBzZWxmLl9sYWJlbHMgPSBsYWJlbHMKICAgICAgICBzZWxmLl9leHRyYV9kYXRhID0gZXh0cmFfZGF0YSBpZiBleHRyYV9kYXRhIGlzIG5vdCBOb25lIGVsc2Uge30KCiAgICAgICAgIyBTZXQgdXAgdGhlIGxvZ2dpbmcgbW9kZToKICAgICAgICBzZWxmLl9pc190cmFpbmluZyA9IEZhbHNlCiAgICAgICAgc2VsZi5fc3RlcHM6IExpc3RbTGlzdFtpbnRdXSA9IFtdCiAgICAgICAgc2VsZi5fbWV0cmljX3Njb3JlczogRGljdFtzdHIsIExpc3RbZmxvYXRdXSA9IHt9CiAgICAgICAgc2VsZi5fYXJ0aWZhY3RzOiBEaWN0W3N0ciwgQXJ0aWZhY3RdID0ge30KCiAgICBkZWYgb25fZXBvY2hfYmVnaW4oCiAgICAgICAgc2VsZiwKICAgICAgICBhcmdzOiBUcmFpbmluZ0FyZ3VtZW50cywKICAgICAgICBzdGF0ZTogVHJhaW5lclN0YXRlLAogICAgICAgIGNvbnRyb2w6IFRyYWluZXJDb250cm9sLAogICAgICAgICoqa3dhcmdzLAogICAgKToKICAgICAgICBzZWxmLl9zdGVwcy5hcHBlbmQoW10pCgogICAgZGVmIG9uX2Vwb2NoX2VuZCgKICAgICAgICBzZWxmLAogICAgICAgIGFyZ3M6IFRyYWluaW5nQXJndW1lbnRzLAogICAgICAgIHN0YXRlOiBUcmFpbmVyU3RhdGUsCiAgICAgICAgY29udHJvbDogVHJhaW5lckNvbnRyb2wsCiAgICAgICAgKiprd2FyZ3MsCiAgICApOgogICAgICAgIHNlbGYuX2xvZ19tZXRyaWNzKCkKCiAgICBkZWYgb25fbG9nKAogICAgICAgIHNlbGYsCiAgICAgICAgYXJnczogVHJhaW5pbmdBcmd1bWVudHMsCiAgICAgICAgc3RhdGU6IFRyYWluZXJTdGF0ZSwKICAgICAgICBjb250cm9sOiBUcmFpbmVyQ29udHJvbCwKICAgICAgICBsb2dzOiBEaWN0W3N0ciwgZmxvYXRdID0gTm9uZSwKICAgICAgICAqKmt3YXJncywKICAgICk6CiAgICAgICAgcmVjZW50X2xvZ3MgPSBzdGF0ZS5sb2dfaGlzdG9yeVstMV0uY29weSgpCgogICAgICAgIHJlY2VudF9sb2dzLnBvcCgiZXBvY2giKQogICAgICAgIGN1cnJlbnRfc3RlcCA9IGludChyZWNlbnRfbG9ncy5wb3AoInN0ZXAiKSkKICAgICAgICBpZiBjdXJyZW50X3N0ZXAgbm90IGluIHNlbGYuX3N0ZXBzWy0xXToKICAgICAgICAgICAgc2VsZi5fc3RlcHNbLTFdLmFwcGVuZChjdXJyZW50X3N0ZXApCgogICAgICAgIGZvciBtZXRyaWNfbmFtZSwgbWV0cmljX3Njb3JlIGluIHJlY2VudF9sb2dzLml0ZW1zKCk6CiAgICAgICAgICAgIGlmIG1ldHJpY19uYW1lLnN0YXJ0c3dpdGgoInRyYWluXyIpOgogICAgICAgICAgICAgICAgaWYgbWV0cmljX25hbWUuc3BsaXQoInRyYWluXyIpWzFdIG5vdCBpbiBzZWxmLl9tZXRyaWNfc2NvcmVzOgogICAgICAgICAgICAgICAgICAgIHNlbGYuX21ldHJpY19zY29yZXNbbWV0cmljX25hbWVdID0gW21ldHJpY19zY29yZV0KICAgICAgICAgICAgICAgIGNvbnRpbnVlCiAgICAgICAgICAgIGlmIG1ldHJpY19uYW1lIG5vdCBpbiBzZWxmLl9tZXRyaWNfc2NvcmVzOgogICAgICAgICAgICAgICAgc2VsZi5fbWV0cmljX3Njb3Jlc1ttZXRyaWNfbmFtZV0gPSBbXQogICAgICAgICAgICBzZWxmLl9tZXRyaWNfc2NvcmVzW21ldHJpY19uYW1lXS5hcHBlbmQobWV0cmljX3Njb3JlKQoKICAgIGRlZiBvbl90cmFpbl9iZWdpbigKICAgICAgICBzZWxmLAogICAgICAgIGFyZ3M6IFRyYWluaW5nQXJndW1lbnRzLAogICAgICAgIHN0YXRlOiBUcmFpbmVyU3RhdGUsCiAgICAgICAgY29udHJvbDogVHJhaW5lckNvbnRyb2wsCiAgICAgICAgKiprd2FyZ3MsCiAgICApOgogICAgICAgIHNlbGYuX2lzX3RyYWluaW5nID0gVHJ1ZQoKICAgIGRlZiBvbl90cmFpbl9lbmQoCiAgICAgICAgc2VsZiwKICAgICAgICBhcmdzOiBUcmFpbmluZ0FyZ3VtZW50cywKICAgICAgICBzdGF0ZTogVHJhaW5lclN0YXRlLAogICAgICAgIGNvbnRyb2w6IFRyYWluZXJDb250cm9sLAogICAgICAgIG1vZGVsOiBQcmVUcmFpbmVkTW9kZWwgPSBOb25lLAogICAgICAgIHRva2VuaXplcjogUHJlVHJhaW5lZFRva2VuaXplciA9IE5vbmUsCiAgICAgICAgKiprd2FyZ3MsCiAgICApOgogICAgICAgIHNlbGYuX2xvZ19tZXRyaWNzKCkKCiAgICAgICAgdGVtcF9kaXJlY3RvcnkgPSB0ZW1wZmlsZS5nZXR0ZW1wZGlyKCkKCiAgICAgICAgIyBTYXZlIGFuZCBsb2cgdGhlIHRva2VuaXplcjoKICAgICAgICBpZiB0b2tlbml6ZXIgaXMgbm90IE5vbmU6CiAgICAgICAgICAgICMgU2F2ZSB0b2tlbml6ZXI6CiAgICAgICAgICAgIHRva2VuaXplcl9kaXIgPSBvcy5wYXRoLmpvaW4odGVtcF9kaXJlY3RvcnksICJ0b2tlbml6ZXIiKQogICAgICAgICAgICB0b2tlbml6ZXIuc2F2ZV9wcmV0cmFpbmVkKHNhdmVfZGlyZWN0b3J5PXRva2VuaXplcl9kaXIpCiAgICAgICAgICAgICMgWmlwIHRoZSB0b2tlbml6ZXIgZGlyZWN0b3J5OgogICAgICAgICAgICB0b2tlbml6ZXJfemlwID0gc2h1dGlsLm1ha2VfYXJjaGl2ZSgKICAgICAgICAgICAgICAgIGJhc2VfbmFtZT0idG9rZW5pemVyIiwKICAgICAgICAgICAgICAgIGZvcm1hdD0iemlwIiwKICAgICAgICAgICAgICAgIHJvb3RfZGlyPXRva2VuaXplcl9kaXIsCiAgICAgICAgICAgICkKICAgICAgICAgICAgIyBMb2cgdGhlIHppcCBmaWxlOgogICAgICAgICAgICBzZWxmLl9hcnRpZmFjdHNbInRva2VuaXplciJdID0gc2VsZi5fY29udGV4dC5sb2dfYXJ0aWZhY3QoCiAgICAgICAgICAgICAgICBpdGVtPSJ0b2tlbml6ZXIiLCBsb2NhbF9wYXRoPXRva2VuaXplcl96aXAKICAgICAgICAgICAgKQoKICAgICAgICAjIFNhdmUgdGhlIG1vZGVsOgogICAgICAgIG1vZGVsX2RpciA9IG9zLnBhdGguam9pbih0ZW1wX2RpcmVjdG9yeSwgIm1vZGVsIikKICAgICAgICBtb2RlbC5zYXZlX3ByZXRyYWluZWQoc2F2ZV9kaXJlY3Rvcnk9bW9kZWxfZGlyKQoKICAgICAgICAjIFppcCB0aGUgbW9kZWwgZGlyZWN0b3J5OgogICAgICAgIHNodXRpbC5tYWtlX2FyY2hpdmUoCiAgICAgICAgICAgIGJhc2VfbmFtZT0ibW9kZWwiLAogICAgICAgICAgICBmb3JtYXQ9InppcCIsCiAgICAgICAgICAgIHJvb3RfZGlyPW1vZGVsX2RpciwKICAgICAgICApCgogICAgICAgICMgTG9nIHRoZSBtb2RlbDoKICAgICAgICBzZWxmLl9jb250ZXh0LmxvZ19tb2RlbCgKICAgICAgICAgICAga2V5PSJtb2RlbCIsCiAgICAgICAgICAgIGRiX2tleT1zZWxmLl9tb2RlbF9uYW1lLAogICAgICAgICAgICBtb2RlbF9maWxlPSJtb2RlbC56aXAiLAogICAgICAgICAgICB0YWc9c2VsZi5fdGFnLAogICAgICAgICAgICBmcmFtZXdvcms9Ikh1Z2dpbmcgRmFjZSIsCiAgICAgICAgICAgIGxhYmVscz1zZWxmLl9sYWJlbHMsCiAgICAgICAgICAgIGV4dHJhX2RhdGE9eyoqc2VsZi5fYXJ0aWZhY3RzLCAqKnNlbGYuX2V4dHJhX2RhdGF9LAogICAgICAgICkKCiAgICBkZWYgb25fZXZhbHVhdGUoCiAgICAgICAgc2VsZiwKICAgICAgICBhcmdzOiBUcmFpbmluZ0FyZ3VtZW50cywKICAgICAgICBzdGF0ZTogVHJhaW5lclN0YXRlLAogICAgICAgIGNvbnRyb2w6IFRyYWluZXJDb250cm9sLAogICAgICAgICoqa3dhcmdzLAogICAgKToKICAgICAgICBzZWxmLl9sb2dfbWV0cmljcygpCgogICAgICAgIGlmIHNlbGYuX2lzX3RyYWluaW5nOgogICAgICAgICAgICByZXR1cm4KCiAgICAgICAgIyBUT0RPOiBVcGRhdGUgdGhlIG1vZGVsIG9iamVjdAoKICAgIGRlZiBfbG9nX21ldHJpY3Moc2VsZik6CiAgICAgICAgZm9yIG1ldHJpY19uYW1lLCBtZXRyaWNfc2NvcmVzIGluIHNlbGYuX21ldHJpY19zY29yZXMuaXRlbXMoKToKICAgICAgICAgICAgc2VsZi5fY29udGV4dC5sb2dfcmVzdWx0KGtleT1tZXRyaWNfbmFtZSwgdmFsdWU9bWV0cmljX3Njb3Jlc1stMV0pCiAgICAgICAgICAgIGlmIGxlbihtZXRyaWNfc2NvcmVzKSA+IDE6CiAgICAgICAgICAgICAgICBzZWxmLl9sb2dfbWV0cmljX3Bsb3QobmFtZT1tZXRyaWNfbmFtZSwgc2NvcmVzPW1ldHJpY19zY29yZXMpCiAgICAgICAgc2VsZi5fY29udGV4dC5jb21taXQoY29tcGxldGVkPUZhbHNlKQoKICAgIGRlZiBfbG9nX21ldHJpY19wbG90KHNlbGYsIG5hbWU6IHN0ciwgc2NvcmVzOiBMaXN0W2Zsb2F0XSk6CiAgICAgICAgIyBJbml0aWFsaXplIGEgcGxvdGx5IGZpZ3VyZToKICAgICAgICBtZXRyaWNfZmlndXJlID0gZ28uRmlndXJlKCkKCiAgICAgICAgIyBBZGQgdGl0bGVzOgogICAgICAgIG1ldHJpY19maWd1cmUudXBkYXRlX2xheW91dCgKICAgICAgICAgICAgdGl0bGU9bmFtZS5jYXBpdGFsaXplKCkucmVwbGFjZSgiXyIsICIgIiksCiAgICAgICAgICAgIHhheGlzX3RpdGxlPSJTYW1wbGVzIiwKICAgICAgICAgICAgeWF4aXNfdGl0bGU9IlNjb3JlcyIsCiAgICAgICAgKQoKICAgICAgICAjIERyYXc6CiAgICAgICAgbWV0cmljX2ZpZ3VyZS5hZGRfdHJhY2UoCiAgICAgICAgICAgIGdvLlNjYXR0ZXIoeD1ucC5hcmFuZ2UobGVuKHNjb3JlcykpLCB5PXNjb3JlcywgbW9kZT0ibGluZXMiKQogICAgICAgICkKCiAgICAgICAgIyBDcmVhdGUgdGhlIHBsb3RseSBhcnRpZmFjdDoKICAgICAgICBhcnRpZmFjdF9uYW1lID0gZiJ7bmFtZX1fcGxvdCIKICAgICAgICBhcnRpZmFjdCA9IFBsb3RseUFydGlmYWN0KGtleT1hcnRpZmFjdF9uYW1lLCBmaWd1cmU9bWV0cmljX2ZpZ3VyZSkKICAgICAgICBzZWxmLl9hcnRpZmFjdHNbYXJ0aWZhY3RfbmFtZV0gPSBzZWxmLl9jb250ZXh0LmxvZ19hcnRpZmFjdChhcnRpZmFjdCkKCgpkZWYgX2FwcGx5X21scnVuX29uX3RyYWluZXIoCiAgICB0cmFpbmVyOiB0cmFuc2Zvcm1lcnMuVHJhaW5lciwKICAgIG1vZGVsX25hbWU6IHN0ciA9IE5vbmUsCiAgICB0YWc6IHN0ciA9ICIiLAogICAgY29udGV4dDogbWxydW4uTUxDbGllbnRDdHggPSBOb25lLAogICAgYXV0b19sb2c6IGJvb2wgPSBUcnVlLAogICAgbGFiZWxzOiBEaWN0W3N0ciwgc3RyXSA9IE5vbmUsCiAgICBleHRyYV9kYXRhOiBkaWN0ID0gTm9uZSwKICAgICoqa3dhcmdzLAopOgogICAgIyBHZXQgcGFyYW1ldGVycyBkZWZhdWx0czoKICAgIGlmIGNvbnRleHQgaXMgTm9uZToKICAgICAgICBjb250ZXh0ID0gbWxydW4uZ2V0X29yX2NyZWF0ZV9jdHgoSEZUcmFpbmVyTUxSdW5JbnRlcmZhY2UuREVGQVVMVF9DT05URVhUX05BTUUpCgogICAgSEZUcmFpbmVyTUxSdW5JbnRlcmZhY2UuYWRkX2ludGVyZmFjZShvYmo9dHJhaW5lcikKCiAgICBpZiBhdXRvX2xvZzoKICAgICAgICB0cmFpbmVyLmFkZF9jYWxsYmFjaygKICAgICAgICAgICAgTUxSdW5DYWxsYmFjaygKICAgICAgICAgICAgICAgIGNvbnRleHQ9Y29udGV4dCwKICAgICAgICAgICAgICAgIG1vZGVsX25hbWU9bW9kZWxfbmFtZSwKICAgICAgICAgICAgICAgIHRhZz10YWcsCiAgICAgICAgICAgICAgICBsYWJlbHM9bGFiZWxzLAogICAgICAgICAgICAgICAgZXh0cmFfZGF0YT1leHRyYV9kYXRhLAogICAgICAgICAgICApCiAgICAgICAgKQoKCmRlZiBfYXBwbHlfbWxydW5fb25fb3B0aW1pemVyKAogICAgb3B0aW1pemVyLAogICAgbW9kZWxfbmFtZTogc3RyID0gTm9uZSwKICAgIHRhZzogc3RyID0gIiIsCiAgICBjb250ZXh0OiBtbHJ1bi5NTENsaWVudEN0eCA9IE5vbmUsCiAgICBhdXRvX2xvZzogYm9vbCA9IFRydWUsCiAgICBsYWJlbHM6IERpY3Rbc3RyLCBzdHJdID0gTm9uZSwKICAgIGV4dHJhX2RhdGE6IGRpY3QgPSBOb25lLAogICAgKiprd2FyZ3MsCik6CiAgICAjIEdldCBwYXJhbWV0ZXJzIGRlZmF1bHRzOgogICAgaWYgY29udGV4dCBpcyBOb25lOgogICAgICAgIGNvbnRleHQgPSBtbHJ1bi5nZXRfb3JfY3JlYXRlX2N0eCgKICAgICAgICAgICAgSEZPUlRPcHRpbWl6ZXJNTFJ1bkludGVyZmFjZS5ERUZBVUxUX0NPTlRFWFRfTkFNRQogICAgICAgICkKCiAgICBIRk9SVE9wdGltaXplck1MUnVuSW50ZXJmYWNlLmFkZF9pbnRlcmZhY2Uob2JqPW9wdGltaXplcikKCiAgICBpZiBhdXRvX2xvZzoKICAgICAgICBvcHRpbWl6ZXIuZW5hYmxlX2F1dG9fbG9nZ2luZygKICAgICAgICAgICAgY29udGV4dD1jb250ZXh0LAogICAgICAgICAgICBtb2RlbF9uYW1lPW1vZGVsX25hbWUsCiAgICAgICAgICAgIHRhZz10YWcsCiAgICAgICAgICAgIGxhYmVscz1sYWJlbHMsCiAgICAgICAgICAgIGV4dHJhX2RhdGE9ZXh0cmFfZGF0YSwKICAgICAgICApCgoKZGVmIGFwcGx5X21scnVuKAogICAgaHVnZ2luZ2ZhY2Vfb2JqZWN0LAogICAgbW9kZWxfbmFtZTogc3RyID0gTm9uZSwKICAgIHRhZzogc3RyID0gIiIsCiAgICBjb250ZXh0OiBtbHJ1bi5NTENsaWVudEN0eCA9IE5vbmUsCiAgICBhdXRvX2xvZzogYm9vbCA9IFRydWUsCiAgICBsYWJlbHM6IERpY3Rbc3RyLCBzdHJdID0gTm9uZSwKICAgIGV4dHJhX2RhdGE6IGRpY3QgPSBOb25lLAogICAgKiprd2FyZ3MsCik6CiAgICAiIiIKICAgIFdyYXAgdGhlIGdpdmVuIG1vZGVsIHdpdGggTUxSdW4ncyBpbnRlcmZhY2UgcHJvdmlkaW5nIGl0IHdpdGggbWxydW4ncyBhZGRpdGlvbmFsIGZlYXR1cmVzLgogICAgOnBhcmFtIGh1Z2dpbmdmYWNlX29iamVjdDogVGhlIG1vZGVsIHRvIHdyYXAuIENhbiBiZSBsb2FkZWQgZnJvbSB0aGUgbW9kZWwgcGF0aCBnaXZlbiBhcyB3ZWxsLgogICAgOnBhcmFtIG1vZGVsX25hbWU6ICAgICAgICAgVGhlIG1vZGVsIG5hbWUgdG8gdXNlIGZvciBzdG9yaW5nIHRoZSBtb2RlbCBhcnRpZmFjdC4gRGVmYXVsdDogIm1vZGVsIi4KICAgIDpwYXJhbSB0YWc6ICAgICAgICAgICAgICAgIFRoZSBtb2RlbCdzIHRhZyB0byBsb2cgd2l0aC4KICAgIDpwYXJhbSBjb250ZXh0OiAgICAgICAgICAgIE1MUnVuIGNvbnRleHQgdG8gd29yayB3aXRoLiBJZiBubyBjb250ZXh0IGlzIGdpdmVuIGl0IHdpbGwgYmUgcmV0cmlldmVkIHZpYQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ21scnVuLmdldF9vcl9jcmVhdGVfY3R4KE5vbmUpJwogICAgOnBhcmFtIGF1dG9fbG9nOiAgICAgICAgICAgV2hldGhlciB0byBlbmFibGUgTUxSdW4ncyBhdXRvIGxvZ2dpbmcuIERlZmF1bHQ6IFRydWUuCiAgICAiIiIKCiAgICBpZiBpc2luc3RhbmNlKGh1Z2dpbmdmYWNlX29iamVjdCwgdHJhbnNmb3JtZXJzLlRyYWluZXIpOgogICAgICAgIHJldHVybiBfYXBwbHlfbWxydW5fb25fdHJhaW5lcigKICAgICAgICAgICAgdHJhaW5lcj1odWdnaW5nZmFjZV9vYmplY3QsCiAgICAgICAgICAgIG1vZGVsX25hbWU9bW9kZWxfbmFtZSwKICAgICAgICAgICAgdGFnPXRhZywKICAgICAgICAgICAgY29udGV4dD1jb250ZXh0LAogICAgICAgICAgICBhdXRvX2xvZz1hdXRvX2xvZywKICAgICAgICAgICAgbGFiZWxzPWxhYmVscywKICAgICAgICAgICAgZXh0cmFfZGF0YT1leHRyYV9kYXRhLAogICAgICAgICkKICAgIGltcG9ydCBvcHRpbXVtLm9ubnhydW50aW1lIGFzIG9wdGltdW1fb3J0CgogICAgaWYgaXNpbnN0YW5jZShodWdnaW5nZmFjZV9vYmplY3QsIG9wdGltdW1fb3J0Lk9SVE9wdGltaXplcik6CiAgICAgICAgcmV0dXJuIF9hcHBseV9tbHJ1bl9vbl9vcHRpbWl6ZXIoCiAgICAgICAgICAgIG9wdGltaXplcj1odWdnaW5nZmFjZV9vYmplY3QsCiAgICAgICAgICAgIG1vZGVsX25hbWU9bW9kZWxfbmFtZSwKICAgICAgICAgICAgdGFnPXRhZywKICAgICAgICAgICAgY29udGV4dD1jb250ZXh0LAogICAgICAgICAgICBhdXRvX2xvZz1hdXRvX2xvZywKICAgICAgICAgICAgbGFiZWxzPWxhYmVscywKICAgICAgICAgICAgZXh0cmFfZGF0YT1leHRyYV9kYXRhLAogICAgICAgICkKICAgIHJhaXNlIG1scnVuLmVycm9ycy5NTFJ1bkludmFsaWRBcmd1bWVudEVycm9yCgoKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tIGZyb20gYXV0b190cmFpbmVyLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KY2xhc3MgS1dBcmdzUHJlZml4ZXM6CiAgICBNT0RFTF9DTEFTUyA9ICJDTEFTU18iCiAgICBGSVQgPSAiRklUXyIKICAgIFRSQUlOID0gIlRSQUlOXyIKICAgIFBSRURJQ1QgPSAiUFJFRElDVF8iCgoKZGVmIF9nZXRfc3ViX2RpY3RfYnlfcHJlZml4KHNyYzogRGljdCwgcHJlZml4X2tleTogc3RyKSAtPiBEaWN0W3N0ciwgQW55XToKICAgICIiIgogICAgQ29sbGVjdCBhbGwgdGhlIGtleXMgZnJvbSB0aGUgZ2l2ZW4gZGljdCB0aGF0IHN0YXJ0cyB3aXRoIHRoZSBnaXZlbiBwcmVmaXggYW5kIGNyZWF0ZXMgYSBuZXcgZGljdGlvbmFyeSB3aXRoIHRoZXNlCiAgICBrZXlzLgoKICAgIDpwYXJhbSBzcmM6ICAgICAgICAgVGhlIHNvdXJjZSBkaWN0IHRvIGV4dHJhY3QgdGhlIHZhbHVlcyBmcm9tLgogICAgOnBhcmFtIHByZWZpeF9rZXk6ICBPbmx5IGtleXMgd2l0aCB0aGlzIHByZWZpeCB3aWxsIGJlIHJldHVybmVkLiBUaGUga2V5cyBpbiB0aGUgcmVzdWx0IGRpY3Qgd2lsbCBiZSB3aXRob3V0IHRoaXMKICAgICAgICAgICAgICAgICAgICAgICAgcHJlZml4LgogICAgIiIiCiAgICByZXR1cm4gewogICAgICAgIGtleS5yZXBsYWNlKHByZWZpeF9rZXksICIiKTogdmFsCiAgICAgICAgZm9yIGtleSwgdmFsIGluIHNyYy5pdGVtcygpCiAgICAgICAgaWYga2V5LnN0YXJ0c3dpdGgocHJlZml4X2tleSkKICAgIH0KCgpkZWYgX2dldF9kYXRhZnJhbWUoCiAgICBjb250ZXh0OiBNTENsaWVudEN0eCwKICAgIGRhdGFzZXQ6IERhdGFJdGVtLAogICAgbGFiZWxfY29sdW1uczogT3B0aW9uYWxbVW5pb25bc3RyLCBMaXN0W3N0cl1dXSA9IE5vbmUsCiAgICBkcm9wX2NvbHVtbnM6IFVuaW9uW3N0ciwgTGlzdFtzdHJdLCBpbnQsIExpc3RbaW50XV0gPSBOb25lLAopIC0+IFR1cGxlW3BkLkRhdGFGcmFtZSwgT3B0aW9uYWxbVW5pb25bc3RyLCBMaXN0W3N0cl1dXV06CiAgICAiIiIKICAgIEdldHRpbmcgdGhlIERhdGFGcmFtZSBvZiB0aGUgZGF0YXNldCBhbmQgZHJvcCB0aGUgY29sdW1ucyBhY2NvcmRpbmdseS4KCiAgICA6cGFyYW0gY29udGV4dDogICAgICAgICBNTFJ1biBjb250ZXh0LgogICAgOnBhcmFtIGRhdGFzZXQ6ICAgICAgICAgVGhlIGRhdGFzZXQgdG8gdHJhaW4gdGhlIG1vZGVsIG9uLgogICAgICAgICAgICAgICAgICAgICAgICAgICAgQ2FuIGJlIGVpdGhlciBhIGxpc3Qgb2YgbGlzdHMsIGRpY3QsIFVSSSBvciBhIEZlYXR1cmVWZWN0b3IuCiAgICA6cGFyYW0gbGFiZWxfY29sdW1uczogICBUaGUgdGFyZ2V0IGxhYmVsKHMpIG9mIHRoZSBjb2x1bW4ocykgaW4gdGhlIGRhdGFzZXQuIGZvciBSZWdyZXNzaW9uIG9yCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBDbGFzc2lmaWNhdGlvbiB0YXNrcy4KICAgIDpwYXJhbSBkcm9wX2NvbHVtbnM6ICAgIHN0ci9pbnQgb3IgYSBsaXN0IG9mIHN0cmluZ3MvaW50cyB0aGF0IHJlcHJlc2VudCB0aGUgY29sdW1uIG5hbWVzL2luZGljZXMgdG8gZHJvcC4KICAgICIiIgogICAgaWYgaXNpbnN0YW5jZShkYXRhc2V0LCAobGlzdCwgZGljdCkpOgogICAgICAgIGRhdGFzZXQgPSBwZC5EYXRhRnJhbWUoZGF0YXNldCkKICAgICAgICAjIENoZWNraW5nIGlmIGRyb3BfY29sdW1ucyBwcm92aWRlZCBieSBpbnRlZ2VyIHR5cGU6CiAgICAgICAgaWYgZHJvcF9jb2x1bW5zOgogICAgICAgICAgICBpZiBpc2luc3RhbmNlKGRyb3BfY29sdW1ucywgc3RyKSBvciAoCiAgICAgICAgICAgICAgICBpc2luc3RhbmNlKGRyb3BfY29sdW1ucywgbGlzdCkKICAgICAgICAgICAgICAgIGFuZCBhbnkoaXNpbnN0YW5jZShjb2wsIHN0cikgZm9yIGNvbCBpbiBkcm9wX2NvbHVtbnMpCiAgICAgICAgICAgICk6CiAgICAgICAgICAgICAgICBjb250ZXh0LmxvZ2dlci5lcnJvcigKICAgICAgICAgICAgICAgICAgICAiZHJvcF9jb2x1bW5zIG11c3QgYmUgYW4gaW50ZWdlci9saXN0IG9mIGludGVnZXJzIGlmIG5vdCBwcm92aWRlZCB3aXRoIGEgVVJJL0ZlYXR1cmVWZWN0b3IgZGF0YXNldCIKICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIHJhaXNlIFZhbHVlRXJyb3IKICAgICAgICAgICAgZGF0YXNldC5kcm9wKGRyb3BfY29sdW1ucywgYXhpcz0xLCBpbnBsYWNlPVRydWUpCgogICAgICAgIHJldHVybiBkYXRhc2V0LCBsYWJlbF9jb2x1bW5zCgogICAgc3RvcmVfdXJpX3ByZWZpeCwgXyA9IG1scnVuLmRhdGFzdG9yZS5wYXJzZV9zdG9yZV91cmkoZGF0YXNldC5hcnRpZmFjdF91cmwpCiAgICBpZiBtbHJ1bi51dGlscy5TdG9yZVByZWZpeC5GZWF0dXJlVmVjdG9yID09IHN0b3JlX3VyaV9wcmVmaXg6CiAgICAgICAgIyBmZWF0dXJlLXZlY3RvciBjYXNlOgogICAgICAgIGxhYmVsX2NvbHVtbnMgPSBsYWJlbF9jb2x1bW5zIG9yIGRhdGFzZXQubWV0YS5zdGF0dXMubGFiZWxfY29sdW1uCiAgICAgICAgZGF0YXNldCA9IGZzLmdldF9vZmZsaW5lX2ZlYXR1cmVzKAogICAgICAgICAgICBkYXRhc2V0Lm1ldGEudXJpLCBkcm9wX2NvbHVtbnM9ZHJvcF9jb2x1bW5zCiAgICAgICAgKS50b19kYXRhZnJhbWUoKQoKICAgICAgICBjb250ZXh0LmxvZ2dlci5pbmZvKGYibGFiZWwgY29sdW1uczoge2xhYmVsX2NvbHVtbnN9IikKICAgIGVsc2U6CiAgICAgICAgIyBzaW1wbGUgVVJMIGNhc2U6CiAgICAgICAgZGF0YXNldCA9IGRhdGFzZXQuYXNfZGYoKQogICAgICAgIGlmIGRyb3BfY29sdW1uczoKICAgICAgICAgICAgaWYgYWxsKGNvbCBpbiBkYXRhc2V0IGZvciBjb2wgaW4gZHJvcF9jb2x1bW5zKToKICAgICAgICAgICAgICAgIGRhdGFzZXQgPSBkYXRhc2V0LmRyb3AoZHJvcF9jb2x1bW5zLCBheGlzPTEpCiAgICAgICAgICAgIGVsc2U6CiAgICAgICAgICAgICAgICBjb250ZXh0LmxvZ2dlci5pbmZvKAogICAgICAgICAgICAgICAgICAgICJub3QgYWxsIG9mIHRoZSBjb2x1bW5zIHRvIGRyb3AgaW4gdGhlIGRhdGFzZXQsIGRyb3AgY29sdW1ucyBwcm9jZXNzIHNraXBwZWQiCiAgICAgICAgICAgICAgICApCiAgICByZXR1cm4gZGF0YXNldCwgbGFiZWxfY29sdW1ucwoKCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSBIdWdnaW5nIEZhY2UgVHJhaW5lciAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKCmRlZiBfY3JlYXRlX2NvbXB1dGVfbWV0cmljcyhtZXRyaWNzOiBMaXN0W3N0cl0pIC0+IENhbGxhYmxlW1tFdmFsUHJlZGljdGlvbl0sIERpY3RdOgogICAgIiIiCiAgICBUaGlzIGZ1bmN0aW9uIGNyZWF0ZSBhbmQgcmV0dXJucyBhIGZ1bmN0aW9uIHRoYXQgd2lsbCBiZSB1c2VkIHRvIGNvbXB1dGUgbWV0cmljcyBhdCBldmFsdWF0aW9uLgogICAgOnBhcmFtIG1ldHJpY3M6IExpc3Qgb2YgZGlmZmVyZW50IG1ldHJpY3MgZm9yIGV2YWx1YXRlIHRoZSBtb2RlbCBzdWNoIGFzIGYxLCBhY2N1cmFjeSBldGMuCgogICAgOnJldHVybnM6IEZ1bmN0aW9uIHRoYXQgd2lsbCBiZSB1c2VkIHRvIGNvbXB1dGUgbWV0cmljcyBhdCBldmFsdWF0aW9uLgogICAgICAgICAgICAgTXVzdCB0YWtlIGEgW2BFdmFsUHJlZGljdGlvbmBdIGFuZCByZXR1cm4gYSBkaWN0aW9uYXJ5IHN0cmluZyB0byBtZXRyaWMgdmFsdWVzLgogICAgIiIiCgogICAgZGVmIF9jb21wdXRlX21ldHJpY3MoZXZhbF9wcmVkKToKICAgICAgICBsb2dpdHMsIGxhYmVscyA9IGV2YWxfcHJlZAogICAgICAgIHByZWRpY3Rpb25zID0gbnAuYXJnbWF4KGxvZ2l0cywgYXhpcz0tMSkKICAgICAgICBtZXRyaWNfZGljdF9yZXN1bHRzID0ge30KICAgICAgICBmb3IgbWV0cmljIGluIG1ldHJpY3M6CiAgICAgICAgICAgIGxvYWRfbWV0ID0gbG9hZF9tZXRyaWMobWV0cmljKQogICAgICAgICAgICBtZXRyaWNfcmVzID0gbG9hZF9tZXQuY29tcHV0ZShwcmVkaWN0aW9ucz1wcmVkaWN0aW9ucywgcmVmZXJlbmNlcz1sYWJlbHMpWwogICAgICAgICAgICAgICAgbWV0cmljCiAgICAgICAgICAgIF0KICAgICAgICAgICAgbWV0cmljX2RpY3RfcmVzdWx0c1ttZXRyaWNdID0gbWV0cmljX3JlcwoKICAgICAgICByZXR1cm4gbWV0cmljX2RpY3RfcmVzdWx0cwoKICAgIHJldHVybiBfY29tcHV0ZV9tZXRyaWNzCgoKZGVmIF9lZGl0X2NvbHVtbnMoCiAgICBkYXRhc2V0OiBEYXRhc2V0LAogICAgZHJvcF9jb2x1bW5zOiBMaXN0W3N0cl0gPSBOb25lLAogICAgcmVuYW1lX2NvbHVtbnM6IFtzdHIsIHN0cl0gPSBOb25lLAopIC0+IERhdGFzZXQ6CiAgICAiIiIKICAgIERyb3AgYW5kIHJlbmFtZXMgdGhhdCBjb2x1bW5zIG9mIHRoZSBnaXZlbiBkYXRhc2V0CiAgICA6cGFyYW0gZGF0YXNldDogICAgICAgICBEYXRhc2V0IHRvIHByb2Nlc3MKICAgIDpwYXJhbSBkcm9wX2NvbHVtbnM6ICAgIFRoZSBjb2x1bW5zIHRvIGRyb3AgZnJvbSB0aGUgZGF0YXNldC4KICAgIDpwYXJhbSByZW5hbWVfY29sdW1uczogIERpY3Qgb2YgY29sdW1ucyBybyByZW5hbWUgOiB7PG9sZF9uYW1lPjogPG5ld19uYW1lPiwgLi4ufQoKICAgIDpyZXR1cm5zOiBUaGUgZGF0YXNldCBhZnRlciB0aGUgZGVzaXJlZCBwcm9jZXNzCiAgICAiIiIKICAgIGlmIGRyb3BfY29sdW1uczoKICAgICAgICBkYXRhc2V0ID0gZGF0YXNldC5yZW1vdmVfY29sdW1ucyhkcm9wX2NvbHVtbnMpCiAgICBpZiByZW5hbWVfY29sdW1uczoKICAgICAgICBkYXRhc2V0ID0gZGF0YXNldC5yZW5hbWVfY29sdW1ucyhyZW5hbWVfY29sdW1ucykKICAgIHJldHVybiBkYXRhc2V0CgoKZGVmIF9wcmVwYXJlX2RhdGFzZXQoCiAgICBjb250ZXh0OiBNTENsaWVudEN0eCwKICAgIGRhdGFzZXRfbmFtZTogc3RyLAogICAgbGFiZWxfbmFtZTogc3RyID0gTm9uZSwKICAgIGRyb3BfY29sdW1uczogT3B0aW9uYWxbTGlzdFtzdHJdXSA9IE5vbmUsCiAgICBudW1fb2ZfdHJhaW5fc2FtcGxlczogaW50ID0gTm9uZSwKICAgIHRyYWluX3Rlc3Rfc3BsaXRfc2l6ZTogZmxvYXQgPSBOb25lLAogICAgcmFuZG9tX3N0YXRlOiBpbnQgPSBOb25lLAopIC0+IFR1cGxlW0RhdGFzZXQsIERhdGFzZXRdOgogICAgIiIiCiAgICBMb2FkaW5nIHRoZSBkYXRhc2V0IGFuZCBlZGl0aW5nIHRoZSBjb2x1bW5zCgogICAgOnBhcmFtIGNvbnRleHQ6ICAgICAgICAgICAgICAgICBNTFJ1biBjb250ZXgKICAgIDpwYXJhbSBkYXRhc2V0X25hbWU6ICAgICAgICAgICAgVGhlIG5hbWUgb2YgdGhlIGRhdGFzZXQgdG8gZ2V0IGZyb20gdGhlIEh1Z2dpbmdGYWNlIGh1YgogICAgOnBhcmFtIGxhYmVsX25hbWU6ICAgICAgICAgICAgICBUaGUgdGFyZ2V0IGxhYmVsIG9mIHRoZSBjb2x1bW4gaW4gdGhlIGRhdGFzZXQuCiAgICA6cGFyYW0gZHJvcF9jb2x1bW5zOiAgICAgICAgICAgIFRoZSBjb2x1bW5zIHRvIGRyb3AgZnJvbSB0aGUgZGF0YXNldC4KICAgIDpwYXJhbSBudW1fb2ZfdHJhaW5fc2FtcGxlczogICAgTWF4IG51bWJlciBvZiB0cmFpbmluZyBzYW1wbGVzLCBmb3IgZGVidWdnaW5nLgogICAgOnBhcmFtIHRyYWluX3Rlc3Rfc3BsaXRfc2l6ZTogICBTaG91bGQgYmUgYmV0d2VlbiAwLjAgYW5kIDEuMCBhbmQgcmVwcmVzZW50IHRoZSBwcm9wb3J0aW9uIG9mIHRoZSBkYXRhc2V0IHRvIGluY2x1ZGUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW4gdGhlIHRlc3Qgc3BsaXQuCiAgICA6cGFyYW0gcmFuZG9tX3N0YXRlOiAgICAgICAgICAgIFJhbmRvbSBzdGF0ZSBmb3IgdHJhaW5fdGVzdF9zcGxpdAoKICAgICIiIgoKICAgIGNvbnRleHQubG9nZ2VyLmluZm8oCiAgICAgICAgZiJMb2FkaW5nIGFuZCBlZGl0aW5nIHtkYXRhc2V0X25hbWV9IGRhdGFzZXQgZnJvbSBIdWdnaW5nIEZhY2UgaHViIgogICAgKQogICAgcmVuYW1lX2NvbHMgPSB7bGFiZWxfbmFtZTogImxhYmVscyJ9CgogICAgIyBMb2FkaW5nIGFuZCBlZGl0aW5nIGRhdGFzZXQ6CiAgICBkYXRhc2V0ID0gbG9hZF9kYXRhc2V0KGRhdGFzZXRfbmFtZSkKCiAgICAjIHRyYWluIHNldAogICAgdHJhaW5fZGF0YXNldCA9IGRhdGFzZXRbInRyYWluIl0KICAgIGlmIG51bV9vZl90cmFpbl9zYW1wbGVzOgogICAgICAgIHRyYWluX2RhdGFzZXQgPSB0cmFpbl9kYXRhc2V0LnNodWZmbGUoc2VlZD1yYW5kb21fc3RhdGUpLnNlbGVjdCgKICAgICAgICAgICAgbGlzdChyYW5nZShudW1fb2ZfdHJhaW5fc2FtcGxlcykpCiAgICAgICAgKQogICAgdHJhaW5fZGF0YXNldCA9IF9lZGl0X2NvbHVtbnModHJhaW5fZGF0YXNldCwgZHJvcF9jb2x1bW5zLCByZW5hbWVfY29scykKCiAgICAjIHRlc3Qgc2V0CiAgICB0ZXN0X2RhdGFzZXQgPSBkYXRhc2V0WyJ0ZXN0Il0KICAgIGlmIHRyYWluX3Rlc3Rfc3BsaXRfc2l6ZSBvciBudW1fb2ZfdHJhaW5fc2FtcGxlczoKICAgICAgICB0cmFpbl90ZXN0X3NwbGl0X3NpemUgPSB0cmFpbl90ZXN0X3NwbGl0X3NpemUgb3IgMC4yCiAgICAgICAgbnVtX29mX3Rlc3Rfc2FtcGxlcyA9IGludCgKICAgICAgICAgICAgKHRyYWluX2RhdGFzZXQubnVtX3Jvd3MgKiB0cmFpbl90ZXN0X3NwbGl0X3NpemUpCiAgICAgICAgICAgIC8vICgxIC0gdHJhaW5fdGVzdF9zcGxpdF9zaXplKQogICAgICAgICkKICAgICAgICB0ZXN0X2RhdGFzZXQgPSB0ZXN0X2RhdGFzZXQuc2h1ZmZsZShzZWVkPXJhbmRvbV9zdGF0ZSkuc2VsZWN0KAogICAgICAgICAgICBsaXN0KHJhbmdlKG51bV9vZl90ZXN0X3NhbXBsZXMpKQogICAgICAgICkKICAgIHRlc3RfZGF0YXNldCA9IF9lZGl0X2NvbHVtbnModGVzdF9kYXRhc2V0LCBkcm9wX2NvbHVtbnMsIHJlbmFtZV9jb2xzKQoKICAgIHJldHVybiB0cmFpbl9kYXRhc2V0LCB0ZXN0X2RhdGFzZXQKCgpkZWYgdHJhaW4oCiAgICBjb250ZXh0OiBNTENsaWVudEN0eCwKICAgIGhmX2RhdGFzZXQ6IHN0ciA9IE5vbmUsCiAgICBkYXRhc2V0OiBEYXRhSXRlbSA9IE5vbmUsCiAgICB0ZXN0X3NldDogRGF0YUl0ZW0gPSBOb25lLAogICAgZHJvcF9jb2x1bW5zOiBPcHRpb25hbFtMaXN0W3N0cl1dID0gTm9uZSwKICAgIHByZXRyYWluZWRfdG9rZW5pemVyOiBzdHIgPSBOb25lLAogICAgcHJldHJhaW5lZF9tb2RlbDogc3RyID0gTm9uZSwKICAgIG1vZGVsX2NsYXNzOiBzdHIgPSBOb25lLAogICAgbW9kZWxfbmFtZTogc3RyID0gImh1Z2dpbmdmYWNlLW1vZGVsIiwKICAgIGxhYmVsX25hbWU6IHN0ciA9ICJsYWJlbHMiLAogICAgdGV4dF9jb2w6IHN0ciA9ICJ0ZXh0IiwKICAgIG51bV9vZl90cmFpbl9zYW1wbGVzOiBpbnQgPSBOb25lLAogICAgdHJhaW5fdGVzdF9zcGxpdF9zaXplOiBmbG9hdCA9IE5vbmUsCiAgICBtZXRyaWNzOiBMaXN0W3N0cl0gPSBOb25lLAogICAgcmFuZG9tX3N0YXRlOiBpbnQgPSBOb25lLAopOgogICAgIiIiCiAgICBUcmFpbmluZyBhbmQgZXZhbHVhdGluZyBhIHByZXRyYWluZWQgbW9kZWwgd2l0aCBhIHByZXRyYWluZWQgdG9rZW5pemVyIG92ZXIgYSBkYXRhc2V0LgogICAgVGhlIGRhdGFzZXQgY2FuIGJlIGVpdGhlciBiZSB0aGUgbmFtZSBvZiB0aGUgZGF0YXNldCB0aGF0IGNvbnRhaW5zIGluIHRoZSBIdWdnaW5nRmFjZSBodWIsCiAgICBvciBhIFVSSSBvciBhIEZlYXR1cmVWZWN0b3IKCiAgICA6cGFyYW0gY29udGV4dDogICAgICAgICAgICAgICAgIE1MUnVuIGNvbnRleHQKICAgIDpwYXJhbSBoZl9kYXRhc2V0OiAgICAgICAgICAgICAgVGhlIG5hbWUgb2YgdGhlIGRhdGFzZXQgdG8gZ2V0IGZyb20gdGhlIEh1Z2dpbmdGYWNlIGh1YgogICAgOnBhcmFtIGRhdGFzZXQ6ICAgICAgICAgICAgICAgICBUaGUgZGF0YXNldCB0byB0cmFpbiB0aGUgbW9kZWwgb24uIENhbiBiZSBlaXRoZXIgYSBVUkkgb3IgYSBGZWF0dXJlVmVjdG9yCiAgICA6cGFyYW0gdGVzdF9zZXQ6ICAgICAgICAgICAgICAgIFRoZSB0ZXN0IHNldCB0byB0cmFpbiB0aGUgbW9kZWwgd2l0aC4KICAgIDpwYXJhbSBkcm9wX2NvbHVtbnM6ICAgICAgICAgICAgVGhlIGNvbHVtbnMgdG8gZHJvcCBmcm9tIHRoZSBkYXRhc2V0LgogICAgOnBhcmFtIHByZXRyYWluZWRfdG9rZW5pemVyOiAgICBUaGUgbmFtZSBvZiB0aGUgcHJldHJhaW5lZCB0b2tlbml6ZXIgZnJvbSB0aGUgSHVnZ2luZ0ZhY2UgaHViLgogICAgOnBhcmFtIHByZXRyYWluZWRfbW9kZWw6ICAgICAgICBUaGUgbmFtZSBvZiB0aGUgcHJldHJhaW5lZCBtb2RlbCBmcm9tIHRoZSBIdWdnaW5nRmFjZSBodWIuCiAgICA6cGFyYW0gbW9kZWxfbmFtZTogICAgICAgICAgICAgIFRoZSBtb2RlbCdzIG5hbWUgdG8gdXNlIGZvciBzdG9yaW5nIHRoZSBtb2RlbCBhcnRpZmFjdCwgZGVmYXVsdCB0byAnbW9kZWwnCiAgICA6cGFyYW0gbW9kZWxfY2xhc3M6ICAgICAgICAgICAgIFRoZSBjbGFzcyBvZiB0aGUgbW9kZWwsIGUuZy4gYHRyYW5zZm9ybWVycy5BdXRvTW9kZWxGb3JTZXF1ZW5jZUNsYXNzaWZpY2F0aW9uYAogICAgOnBhcmFtIGxhYmVsX25hbWU6ICAgICAgICAgICAgICBUaGUgdGFyZ2V0IGxhYmVsIG9mIHRoZSBjb2x1bW4gaW4gdGhlIGRhdGFzZXQuCiAgICA6cGFyYW0gdGV4dF9jb2w6ICAgICAgICAgICAgICAgIFRoZSBpbnB1dCB0ZXh0IGNvbHVtbiB1biB0aGUgZGF0YXNldC4KICAgIDpwYXJhbSBudW1fb2ZfdHJhaW5fc2FtcGxlczogICAgTWF4IG51bWJlciBvZiB0cmFpbmluZyBzYW1wbGVzLCBmb3IgZGVidWdnaW5nLgogICAgOnBhcmFtIHRyYWluX3Rlc3Rfc3BsaXRfc2l6ZTogICBTaG91bGQgYmUgYmV0d2VlbiAwLjAgYW5kIDEuMCBhbmQgcmVwcmVzZW50IHRoZSBwcm9wb3J0aW9uIG9mIHRoZSBkYXRhc2V0IHRvIGluY2x1ZGUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW4gdGhlIHRlc3Qgc3BsaXQuCiAgICA6cGFyYW0gbWV0cmljczogICAgICAgICAgICAgICAgIExpc3Qgb2YgZGlmZmVyZW50IG1ldHJpY3MgZm9yIGV2YWx1YXRlIHRoZSBtb2RlbCBzdWNoIGFzIGYxLCBhY2N1cmFjeSBldGMuCiAgICA6cGFyYW0gcmFuZG9tX3N0YXRlOiAgICAgICAgICAgIFJhbmRvbSBzdGF0ZSBmb3IgdHJhaW5fdGVzdF9zcGxpdAogICAgIiIiCgogICAgaWYgdHJhaW5fdGVzdF9zcGxpdF9zaXplIGlzIE5vbmUgYW5kIHRlc3Rfc2V0IGlzIE5vbmU6CiAgICAgICAgY29udGV4dC5sb2dnZXIuaW5mbygKICAgICAgICAgICAgIid0cmFpbl90ZXN0X3NwbGl0X3NpemUnIGlzIG5vdCBwcm92aWRlZCwgc2V0dGluZyB0cmFpbl90ZXN0X3NwbGl0X3NpemUgdG8gMC4yIgogICAgICAgICkKICAgICAgICB0cmFpbl90ZXN0X3NwbGl0X3NpemUgPSAwLjIKCiAgICAjIENyZWF0aW5nIHRva2VuaXplcjoKICAgIHRva2VuaXplciA9IEF1dG9Ub2tlbml6ZXIuZnJvbV9wcmV0cmFpbmVkKHByZXRyYWluZWRfdG9rZW5pemVyKQoKICAgIGRlZiBwcmVwcm9jZXNzX2Z1bmN0aW9uKGV4YW1wbGVzKToKICAgICAgICByZXR1cm4gdG9rZW5pemVyKGV4YW1wbGVzW3RleHRfY29sXSwgdHJ1bmNhdGlvbj1UcnVlKQoKICAgICMgcHJlcGFyZSBkYXRhIGZvciB0cmFpbmluZwogICAgaWYgaGZfZGF0YXNldDoKICAgICAgICB0cmFpbl9kYXRhc2V0LCB0ZXN0X2RhdGFzZXQgPSBfcHJlcGFyZV9kYXRhc2V0KAogICAgICAgICAgICBjb250ZXh0LAogICAgICAgICAgICBoZl9kYXRhc2V0LAogICAgICAgICAgICBsYWJlbF9uYW1lLAogICAgICAgICAgICBkcm9wX2NvbHVtbnMsCiAgICAgICAgICAgIG51bV9vZl90cmFpbl9zYW1wbGVzLAogICAgICAgICAgICB0cmFpbl90ZXN0X3NwbGl0X3NpemUsCiAgICAgICAgICAgIHJhbmRvbV9zdGF0ZT1yYW5kb21fc3RhdGUsCiAgICAgICAgKQogICAgZWxpZiBkYXRhc2V0OgogICAgICAgICMgR2V0IERhdGFGcmFtZSBieSBVUkwgb3IgYnkgRmVhdHVyZVZlY3RvcjoKICAgICAgICB0cmFpbl9kYXRhc2V0LCBsYWJlbF9uYW1lID0gX2dldF9kYXRhZnJhbWUoCiAgICAgICAgICAgIGNvbnRleHQ9Y29udGV4dCwKICAgICAgICAgICAgZGF0YXNldD1kYXRhc2V0LAogICAgICAgICAgICBsYWJlbF9jb2x1bW5zPWxhYmVsX25hbWUsCiAgICAgICAgICAgIGRyb3BfY29sdW1ucz1kcm9wX2NvbHVtbnMsCiAgICAgICAgKQogICAgICAgIGlmIHRlc3Rfc2V0OgogICAgICAgICAgICB0ZXN0X2RhdGFzZXQsIF8gPSBfZ2V0X2RhdGFmcmFtZSgKICAgICAgICAgICAgICAgIGNvbnRleHQ9Y29udGV4dCwKICAgICAgICAgICAgICAgIGRhdGFzZXQ9dGVzdF9zZXQsCiAgICAgICAgICAgICAgICBsYWJlbF9jb2x1bW5zPWxhYmVsX25hbWUsCiAgICAgICAgICAgICAgICBkcm9wX2NvbHVtbnM9ZHJvcF9jb2x1bW5zLAogICAgICAgICAgICApCiAgICAgICAgZWxzZToKICAgICAgICAgICAgdHJhaW5fZGF0YXNldCwgdGVzdF9kYXRhc2V0ID0gdHJhaW5fdGVzdF9zcGxpdCgKICAgICAgICAgICAgICAgIHRyYWluX2RhdGFzZXQsCiAgICAgICAgICAgICAgICB0ZXN0X3NpemU9dHJhaW5fdGVzdF9zcGxpdF9zaXplLAogICAgICAgICAgICAgICAgcmFuZG9tX3N0YXRlPXJhbmRvbV9zdGF0ZSwKICAgICAgICAgICAgKQogICAgICAgIHRyYWluX2RhdGFzZXQgPSBEYXRhc2V0LmZyb21fcGFuZGFzKHRyYWluX2RhdGFzZXQpCiAgICAgICAgdGVzdF9kYXRhc2V0ID0gRGF0YXNldC5mcm9tX3BhbmRhcyh0ZXN0X2RhdGFzZXQpCiAgICBlbHNlOgogICAgICAgIHJhaXNlIG1scnVuLmVycm9ycy5NTFJ1bkludmFsaWRBcmd1bWVudEVycm9yKAogICAgICAgICAgICAiVHJhaW5pbmcgZGF0YSB3YXMgbm90IHByb3ZpZGVkLiBBIHRyYWluaW5nIGRhdGFzZXQgaXMgbWFuZGF0b3J5IGZvciB0cmFpbmluZy4iCiAgICAgICAgICAgICIgUGxlYXNlIHByb3ZpZGUgYSB0cmFpbmluZyBzZXQgdXNpbmcgb25lIG9mIHRoZSBhcmd1bWVudHMgJ2hmX2RhdGFzZXQnIG9yICdkYXRhc2V0Jy4iCiAgICAgICAgKQoKICAgICMgTWFwcGluZyBkYXRhc2V0cyB3aXRoIHRoZSB0b2tlbml6ZXI6CiAgICB0b2tlbml6ZWRfdHJhaW4gPSB0cmFpbl9kYXRhc2V0Lm1hcChwcmVwcm9jZXNzX2Z1bmN0aW9uLCBiYXRjaGVkPVRydWUpCiAgICB0b2tlbml6ZWRfdGVzdCA9IHRlc3RfZGF0YXNldC5tYXAocHJlcHJvY2Vzc19mdW5jdGlvbiwgYmF0Y2hlZD1UcnVlKQoKICAgICMgQ3JlYXRpbmcgZGF0YSBjb2xsYXRvciBmb3IgYmF0Y2hpbmc6CiAgICBkYXRhX2NvbGxhdG9yID0gRGF0YUNvbGxhdG9yV2l0aFBhZGRpbmcodG9rZW5pemVyPXRva2VuaXplcikKCiAgICAjIFBhcnNpbmcga3dhcmdzOgogICAgdHJhaW5fa3dhcmdzID0gX2dldF9zdWJfZGljdF9ieV9wcmVmaXgoCiAgICAgICAgc3JjPWNvbnRleHQucGFyYW1ldGVycywgcHJlZml4X2tleT1LV0FyZ3NQcmVmaXhlcy5UUkFJTgogICAgKQogICAgbW9kZWxfY2xhc3Nfa3dhcmdzID0gX2dldF9zdWJfZGljdF9ieV9wcmVmaXgoCiAgICAgICAgc3JjPWNvbnRleHQucGFyYW1ldGVycywgcHJlZml4X2tleT1LV0FyZ3NQcmVmaXhlcy5NT0RFTF9DTEFTUwogICAgKQoKICAgICMgTG9hZGluZyBvdXIgcHJldHJhaW5lZCBtb2RlbDoKICAgIG1vZGVsX2NsYXNzX2t3YXJnc1sicHJldHJhaW5lZF9tb2RlbF9uYW1lX29yX3BhdGgiXSA9ICgKICAgICAgICBtb2RlbF9jbGFzc19rd2FyZ3MuZ2V0KCJwcmV0cmFpbmVkX21vZGVsX25hbWVfb3JfcGF0aCIpIG9yIHByZXRyYWluZWRfbW9kZWwKICAgICkKICAgIHRyYWluX2t3YXJnc1siaHViX3Rva2VuIl0gPSB0cmFpbl9rd2FyZ3MuZ2V0KCJodWJfdG9rZW4iKSBvciBwcmV0cmFpbmVkX3Rva2VuaXplcgogICAgaWYgbm90IG1vZGVsX2NsYXNzX2t3YXJnc1sicHJldHJhaW5lZF9tb2RlbF9uYW1lX29yX3BhdGgiXToKICAgICAgICByYWlzZSBtbHJ1bi5lcnJvcnMuTUxSdW5SdW50aW1lRXJyb3IoCiAgICAgICAgICAgICJNdXN0IHByb3ZpZGUgcHJldHJhaW5lZF9tb2RlbCBuYW1lIGFzICIKICAgICAgICAgICAgImZ1bmN0aW9uIGFyZ3VtZW50IG9yIGluIGV4dHJhIHBhcmFtcyIKICAgICAgICApCiAgICBtb2RlbCA9IGNyZWF0ZV9jbGFzcyhtb2RlbF9jbGFzcykuZnJvbV9wcmV0cmFpbmVkKCoqbW9kZWxfY2xhc3Nfa3dhcmdzKQoKICAgICMgUHJlcGFyaW5nIHRyYWluaW5nIGFyZ3VtZW50czoKICAgIHRyYWluaW5nX2FyZ3MgPSBUcmFpbmluZ0FyZ3VtZW50cygKICAgICAgICAqKnRyYWluX2t3YXJncywKICAgICkKCiAgICBjb21wdXRlX21ldHJpY3MgPSBfY3JlYXRlX2NvbXB1dGVfbWV0cmljcyhtZXRyaWNzKSBpZiBtZXRyaWNzIGVsc2UgTm9uZQogICAgdHJhaW5lciA9IFRyYWluZXIoCiAgICAgICAgbW9kZWw9bW9kZWwsCiAgICAgICAgYXJncz10cmFpbmluZ19hcmdzLAogICAgICAgIHRyYWluX2RhdGFzZXQ9dG9rZW5pemVkX3RyYWluLAogICAgICAgIGV2YWxfZGF0YXNldD10b2tlbml6ZWRfdGVzdCwKICAgICAgICB0b2tlbml6ZXI9dG9rZW5pemVyLAogICAgICAgIGRhdGFfY29sbGF0b3I9ZGF0YV9jb2xsYXRvciwKICAgICAgICBjb21wdXRlX21ldHJpY3M9Y29tcHV0ZV9tZXRyaWNzLAogICAgKQoKICAgIGFwcGx5X21scnVuKHRyYWluZXIsIG1vZGVsX25hbWU9bW9kZWxfbmFtZSkKCiAgICAjIEFwcGx5IHRyYWluaW5nIHdpdGggZXZhbHVhdGlvbjoKICAgIGNvbnRleHQubG9nZ2VyLmluZm8oZiJ0cmFpbmluZyAne21vZGVsX25hbWV9JyIpCiAgICB0cmFpbmVyLnRyYWluKCkKCgpkZWYgX2dldF9tb2RlbF9kaXIobW9kZWxfdXJpOiBzdHIpOgogICAgbW9kZWxfZmlsZSwgXywgXyA9IG1scnVuLmFydGlmYWN0cy5nZXRfbW9kZWwobW9kZWxfdXJpKQogICAgbW9kZWxfZGlyID0gdGVtcGZpbGUuZ2V0dGVtcGRpcigpCiAgICAjIFVuemlwIHRoZSBNb2RlbDoKICAgIHdpdGggemlwZmlsZS5aaXBGaWxlKG1vZGVsX2ZpbGUsICJyIikgYXMgemlwX2ZpbGU6CiAgICAgICAgemlwX2ZpbGUuZXh0cmFjdGFsbChtb2RlbF9kaXIpCgogICAgcmV0dXJuIG1vZGVsX2RpcgoKCmRlZiBvcHRpbWl6ZSgKICAgIG1vZGVsX3BhdGg6IHN0ciwKICAgIG1vZGVsX25hbWU6IHN0ciA9ICJvcHRpbWl6ZWRfbW9kZWwiLAogICAgdGFyZ2V0X2Rpcjogc3RyID0gIi4vb3B0aW1pemVkIiwKICAgIG9wdGltaXphdGlvbl9sZXZlbDogaW50ID0gMSwKKToKICAgICIiIgogICAgT3B0aW1pemluZyB0aGUgdHJhbnNmb3JtZXIgbW9kZWwgdXNpbmcgT05OWCBvcHRpbWl6YXRpb24uCgoKICAgIDpwYXJhbSBtb2RlbF9wYXRoOiAgICAgICAgICBUaGUgcGF0aCBvZiB0aGUgbW9kZWwgdG8gb3B0aW1pemUuCiAgICA6cGFyYW0gbW9kZWxfbmFtZTogICAgICAgICAgTmFtZSBvZiB0aGUgb3B0aW1pemVkIG1vZGVsLgogICAgOnBhcmFtIHRhcmdldF9kaXI6ICAgICAgICAgIFRoZSBkaXJlY3RvcnkgdG8gc2F2ZSB0aGUgT05OWCBtb2RlbC4KICAgIDpwYXJhbSBvcHRpbWl6YXRpb25fbGV2ZWw6ICBPcHRpbWl6YXRpb24gbGV2ZWwgcGVyZm9ybWVkIGJ5IE9OTlggUnVudGltZSBvZiB0aGUgbG9hZGVkIGdyYXBoLiAoZGVmYXVsdCBpcyAxKQogICAgIiIiCiAgICAjIFdlIGltcG9ydCB0aGVzZSBpbiB0aGUgZnVuY3Rpb24gc2NvcGUgc28gT05OWCB3b24ndCBiZSBtYW5kYXRvcnkgZm9yIHRoZSBvdGhlciBoYW5kbGVyczoKICAgIGZyb20gb3B0aW11bS5vbm54cnVudGltZSBpbXBvcnQgT1JUTW9kZWxGb3JTZXF1ZW5jZUNsYXNzaWZpY2F0aW9uLCBPUlRPcHRpbWl6ZXIKICAgIGZyb20gb3B0aW11bS5vbm54cnVudGltZS5jb25maWd1cmF0aW9uIGltcG9ydCBPcHRpbWl6YXRpb25Db25maWcKCiAgICBtb2RlbF9kaXIgPSBfZ2V0X21vZGVsX2Rpcihtb2RlbF91cmk9bW9kZWxfcGF0aCkKICAgICMgQ3JlYXRpbmcgY29uZmlndXJhdGlvbiBmb3Igb3B0aW1pemF0aW9uIHN0ZXA6CiAgICBvcHRpbWl6YXRpb25fY29uZmlnID0gT3B0aW1pemF0aW9uQ29uZmlnKG9wdGltaXphdGlvbl9sZXZlbD1vcHRpbWl6YXRpb25fbGV2ZWwpCgogICAgIyBDb252ZXJ0aW5nIG91ciBwcmV0cmFpbmVkIG1vZGVsIHRvIGFuIE9OTlgtUnVudGltZSBtb2RlbDoKICAgIG9ydF9tb2RlbCA9IE9SVE1vZGVsRm9yU2VxdWVuY2VDbGFzc2lmaWNhdGlvbi5mcm9tX3ByZXRyYWluZWQoCiAgICAgICAgbW9kZWxfZGlyLCBmcm9tX3RyYW5zZm9ybWVycz1UcnVlCiAgICApCgogICAgIyBDcmVhdGluZyBhbiBPTk5YLVJ1bnRpbWUgb3B0aW1pemVyIGZyb20gT05OWCBtb2RlbDoKICAgIG9wdGltaXplciA9IE9SVE9wdGltaXplci5mcm9tX3ByZXRyYWluZWQob3J0X21vZGVsKQoKICAgIGFwcGx5X21scnVuKG9wdGltaXplciwgbW9kZWxfbmFtZT1tb2RlbF9uYW1lKQogICAgIyBPcHRpbWl6aW5nIGFuZCBzYXZpbmcgdGhlIE9OTlggbW9kZWw6CiAgICBvcHRpbWl6ZXIub3B0aW1pemUoc2F2ZV9kaXI9dGFyZ2V0X2Rpciwgb3B0aW1pemF0aW9uX2NvbmZpZz1vcHRpbWl6YXRpb25fY29uZmlnKQo= - base_image: mlrun/mlrun - commands: [] - code_origin: '' - origin_filename: '' - requirements: - - onnx~=1.14.1 - - onnxruntime~=1.16.1 - - optimum~=1.6.4 - - transformers~=4.26.1 - - datasets~=2.10.1 - - scikit-learn~=1.0.2 - entry_points: - add_interface: - name: add_interface - doc: 'Enrich the object with this interface properties, methods and functions, - so it will have this TensorFlow.Keras - - MLRuns features.' - parameters: - - name: cls - - name: obj - type: Trainer - doc: The object to enrich his interface. - - name: restoration - type: MLRunInterfaceRestorationType - doc: Restoration information tuple as returned from 'remove_interface' in - order to add the interface in a certain state. - default: null - outputs: [] - lineno: 146 - has_varargs: false - has_kwargs: false - mlrun_optimize: - name: mlrun_optimize - doc: 'MLRun''s tf.keras.Model.fit wrapper. It will setup the optimizer when - using horovod. The optimizer must be - - passed in a keyword argument and when using horovod, it must be passed as - an Optimizer instance, not a string. - - - raise MLRunInvalidArgumentError: In case the optimizer provided did not follow - the instructions above.' - parameters: - - name: cls - outputs: [] - lineno: 79 - has_varargs: false - has_kwargs: false - wrapper: - name: wrapper - doc: '' - parameters: - - name: self - type: Trainer - outputs: [] - lineno: 173 - has_varargs: true - has_kwargs: true - enable_auto_logging: - name: enable_auto_logging - doc: '' - parameters: - - name: self - - name: context - type: MLClientCtx - - name: model_name - type: str - default: model - - name: tag - type: str - default: '' - - name: labels - type: Dict[str, str] - default: null - - name: extra_data - type: dict - default: null - outputs: [] - lineno: 114 - has_varargs: false - has_kwargs: false - mlrun_train: - name: mlrun_train - doc: 'MLRuns tf.keras.Model.fit wrapper. It will setup the optimizer when using - horovod. The optimizer must be - - passed in a keyword argument and when using horovod, it must be passed as - an Optimizer instance, not a string. - - - raise MLRunInvalidArgumentError: In case the optimizer provided did not follow - the instructions above.' - parameters: - - name: cls - outputs: [] - lineno: 164 - has_varargs: false - has_kwargs: false - on_epoch_begin: - name: on_epoch_begin - doc: '' - parameters: - - name: self - - name: args - type: TrainingArguments - - name: state - type: TrainerState - - name: control - type: TrainerControl - outputs: [] - lineno: 220 - has_varargs: false - has_kwargs: true - on_epoch_end: - name: on_epoch_end - doc: '' - parameters: - - name: self - - name: args - type: TrainingArguments - - name: state - type: TrainerState - - name: control - type: TrainerControl - outputs: [] - lineno: 229 - has_varargs: false - has_kwargs: true - on_log: - name: on_log - doc: '' - parameters: - - name: self - - name: args - type: TrainingArguments - - name: state - type: TrainerState - - name: control - type: TrainerControl - - name: logs - type: Dict[str, float] - default: null - outputs: [] - lineno: 238 - has_varargs: false - has_kwargs: true - on_train_begin: - name: on_train_begin - doc: '' - parameters: - - name: self - - name: args - type: TrainingArguments - - name: state - type: TrainerState - - name: control - type: TrainerControl - outputs: [] - lineno: 262 - has_varargs: false - has_kwargs: true - on_train_end: - name: on_train_end - doc: '' - parameters: - - name: self - - name: args - type: TrainingArguments - - name: state - type: TrainerState - - name: control - type: TrainerControl - - name: model - type: PreTrainedModel - default: null - - name: tokenizer - type: PreTrainedTokenizer - default: null - outputs: [] - lineno: 271 - has_varargs: false - has_kwargs: true - on_evaluate: - name: on_evaluate - doc: '' - parameters: - - name: self - - name: args - type: TrainingArguments - - name: state - type: TrainerState - - name: control - type: TrainerControl - outputs: [] - lineno: 322 - has_varargs: false - has_kwargs: true - apply_mlrun: - name: apply_mlrun - doc: Wrap the given model with MLRun's interface providing it with mlrun's additional - features. - parameters: - - name: huggingface_object - doc: The model to wrap. Can be loaded from the model path given as well. - - name: model_name - type: str - doc: 'The model name to use for storing the model artifact. Default: "model".' - default: null - - name: tag - type: str - doc: The model's tag to log with. - default: '' - - name: context - type: MLClientCtx - doc: MLRun context to work with. If no context is given it will be retrieved - via 'mlrun.get_or_create_ctx(None)' - default: null - - name: auto_log - type: bool - doc: 'Whether to enable MLRun''s auto logging. Default: True.' - default: true - - name: labels - type: Dict[str, str] - default: null - - name: extra_data - type: dict - default: null - outputs: [] - lineno: 421 - has_varargs: false - has_kwargs: true - train: - name: train - doc: 'Training and evaluating a pretrained model with a pretrained tokenizer - over a dataset. - - The dataset can be either be the name of the dataset that contains in the - HuggingFace hub, - - or a URI or a FeatureVector' - parameters: - - name: context - type: MLClientCtx - doc: MLRun context - - name: hf_dataset - type: str - doc: The name of the dataset to get from the HuggingFace hub - default: null - - name: dataset - type: DataItem - doc: The dataset to train the model on. Can be either a URI or a FeatureVector - default: null - - name: test_set - type: DataItem - doc: The test set to train the model with. - default: null - - name: drop_columns - type: Optional[List[str]] - doc: The columns to drop from the dataset. - default: null - - name: pretrained_tokenizer - type: str - doc: The name of the pretrained tokenizer from the HuggingFace hub. - default: null - - name: pretrained_model - type: str - doc: The name of the pretrained model from the HuggingFace hub. - default: null - - name: model_class - type: str - doc: The class of the model, e.g. `transformers.AutoModelForSequenceClassification` - default: null - - name: model_name - type: str - doc: The model's name to use for storing the model artifact, default to 'model' - default: huggingface-model - - name: label_name - type: str - doc: The target label of the column in the dataset. - default: labels - - name: text_col - type: str - doc: The input text column un the dataset. - default: text - - name: num_of_train_samples - type: int - doc: Max number of training samples, for debugging. - default: null - - name: train_test_split_size - type: float - doc: Should be between 0.0 and 1.0 and represent the proportion of the dataset - to include in the test split. - default: null - - name: metrics - type: List[str] - doc: List of different metrics for evaluate the model such as f1, accuracy - etc. - default: null - - name: random_state - type: int - doc: Random state for train_test_split - default: null - outputs: [] - lineno: 647 - has_varargs: false - has_kwargs: false - preprocess_function: - name: preprocess_function - doc: '' - parameters: - - name: examples - outputs: [] - lineno: 696 - has_varargs: false - has_kwargs: false - optimize: - name: optimize - doc: Optimizing the transformer model using ONNX optimization. - parameters: - - name: model_path - type: str - doc: The path of the model to optimize. - - name: model_name - type: str - doc: Name of the optimized model. - default: optimized_model - - name: target_dir - type: str - doc: The directory to save the ONNX model. - default: ./optimized - - name: optimization_level - type: int - doc: Optimization level performed by ONNX Runtime of the loaded graph. (default - is 1) - default: 1 - outputs: [] - lineno: 799 - has_varargs: false - has_kwargs: false - description: Automatic train and optimize functions for HuggingFace framework - default_handler: train - disable_auto_mount: false - clone_target_dir: '' - env: [] - priority_class_name: '' - preemption_mode: prevent - affinity: null - tolerations: null - security_context: {} -verbose: false diff --git a/hugging_face_classifier_trainer/hugging_face_classifier_trainer.ipynb b/hugging_face_classifier_trainer/hugging_face_classifier_trainer.ipynb deleted file mode 100644 index 2768d2dc1..000000000 --- a/hugging_face_classifier_trainer/hugging_face_classifier_trainer.ipynb +++ /dev/null @@ -1,2533 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, - "source": [ - "\n", - "# MLRun Hugging Face Classifier Trainer Tutorial" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, - "source": [ - "This notebook shows how to use the handlers of the Hugging Face classifier trainer.\n", - "the following handlers are:\n", - "- `train`\n", - "- `optimize`\n", - "\n", - "All you need is simply **HF model type** and a **HF dataset name**." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "scrolled": true, - "tags": [] - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Requirement already satisfied: onnx~=1.14.1 in /User/.pythonlibs/mlrun-base/lib/python3.9/site-packages (from -r requirements.txt (line 1)) (1.14.1)\n", - "Requirement already satisfied: onnxruntime==1.16.1 in /User/.pythonlibs/mlrun-base/lib/python3.9/site-packages (from -r requirements.txt (line 2)) (1.16.1)\n", - "Requirement already satisfied: optimum~=1.6.4 in /User/.pythonlibs/mlrun-base/lib/python3.9/site-packages (from -r requirements.txt (line 3)) (1.6.4)\n", - "Requirement already satisfied: transformers~=4.26.1 in /User/.pythonlibs/mlrun-base/lib/python3.9/site-packages (from -r requirements.txt (line 4)) (4.26.1)\n", - "Requirement already satisfied: datasets~=2.10.1 in /User/.pythonlibs/mlrun-base/lib/python3.9/site-packages (from -r requirements.txt (line 5)) (2.10.1)\n", - "Requirement already satisfied: scikit-learn~=1.0.2 in /User/.pythonlibs/mlrun-base/lib/python3.9/site-packages (from -r requirements.txt (line 6)) (1.0.2)\n", - "Requirement already satisfied: coloredlogs in /User/.pythonlibs/mlrun-base/lib/python3.9/site-packages (from onnxruntime==1.16.1->-r requirements.txt (line 2)) (15.0.1)\n", - "Requirement already satisfied: flatbuffers in /User/.pythonlibs/mlrun-base/lib/python3.9/site-packages (from onnxruntime==1.16.1->-r requirements.txt (line 2)) (1.12)\n", - "Requirement already satisfied: numpy>=1.21.6 in /User/.pythonlibs/mlrun-base/lib/python3.9/site-packages (from onnxruntime==1.16.1->-r requirements.txt (line 2)) (1.23.5)\n", - "Requirement already satisfied: packaging in /conda/envs/mlrun-base/lib/python3.9/site-packages (from onnxruntime==1.16.1->-r requirements.txt (line 2)) (21.3)\n", - "Requirement already satisfied: protobuf in /User/.pythonlibs/mlrun-base/lib/python3.9/site-packages (from onnxruntime==1.16.1->-r requirements.txt (line 2)) (3.20.2)\n", - "Requirement already satisfied: sympy in /User/.pythonlibs/mlrun-base/lib/python3.9/site-packages (from onnxruntime==1.16.1->-r requirements.txt (line 2)) (1.12)\n", - "Requirement already satisfied: typing-extensions>=3.6.2.1 in /conda/envs/mlrun-base/lib/python3.9/site-packages (from onnx~=1.14.1->-r requirements.txt (line 1)) (4.7.1)\n", - "Requirement already satisfied: torch>=1.9 in /User/.pythonlibs/mlrun-base/lib/python3.9/site-packages (from optimum~=1.6.4->-r requirements.txt (line 3)) (2.1.2)\n", - "Requirement already satisfied: huggingface-hub>=0.8.0 in /User/.pythonlibs/mlrun-base/lib/python3.9/site-packages (from optimum~=1.6.4->-r requirements.txt (line 3)) (0.20.1)\n", - "Requirement already satisfied: filelock in /User/.pythonlibs/mlrun-base/lib/python3.9/site-packages (from transformers~=4.26.1->-r requirements.txt (line 4)) (3.13.1)\n", - "Requirement already satisfied: pyyaml>=5.1 in /User/.pythonlibs/mlrun-base/lib/python3.9/site-packages (from transformers~=4.26.1->-r requirements.txt (line 4)) (5.4.1)\n", - "Requirement already satisfied: regex!=2019.12.17 in /User/.pythonlibs/mlrun-base/lib/python3.9/site-packages (from transformers~=4.26.1->-r requirements.txt (line 4)) (2023.12.25)\n", - "Requirement already satisfied: requests in /conda/envs/mlrun-base/lib/python3.9/site-packages (from transformers~=4.26.1->-r requirements.txt (line 4)) (2.31.0)\n", - "Requirement already satisfied: tokenizers!=0.11.3,<0.14,>=0.11.1 in /User/.pythonlibs/mlrun-base/lib/python3.9/site-packages (from transformers~=4.26.1->-r requirements.txt (line 4)) (0.13.3)\n", - "Requirement already satisfied: tqdm>=4.27 in /conda/envs/mlrun-base/lib/python3.9/site-packages (from transformers~=4.26.1->-r requirements.txt (line 4)) (4.65.0)\n", - "Requirement already satisfied: pyarrow>=6.0.0 in /conda/envs/mlrun-base/lib/python3.9/site-packages (from datasets~=2.10.1->-r requirements.txt (line 5)) (11.0.0)\n", - "Requirement already satisfied: dill<0.3.7,>=0.3.0 in /User/.pythonlibs/mlrun-base/lib/python3.9/site-packages (from datasets~=2.10.1->-r requirements.txt (line 5)) (0.3.6)\n", - "Requirement already satisfied: pandas in /conda/envs/mlrun-base/lib/python3.9/site-packages (from datasets~=2.10.1->-r requirements.txt (line 5)) (1.4.4)\n", - "Requirement already satisfied: xxhash in /conda/envs/mlrun-base/lib/python3.9/site-packages (from datasets~=2.10.1->-r requirements.txt (line 5)) (3.3.0)\n", - "Requirement already satisfied: multiprocess in /User/.pythonlibs/mlrun-base/lib/python3.9/site-packages (from datasets~=2.10.1->-r requirements.txt (line 5)) (0.70.14)\n", - "Requirement already satisfied: fsspec>=2021.11.1 in /User/.pythonlibs/mlrun-base/lib/python3.9/site-packages (from fsspec[http]>=2021.11.1->datasets~=2.10.1->-r requirements.txt (line 5)) (2023.9.2)\n", - "Requirement already satisfied: aiohttp in /User/.pythonlibs/mlrun-base/lib/python3.9/site-packages (from datasets~=2.10.1->-r requirements.txt (line 5)) (3.9.1)\n", - "Requirement already satisfied: responses<0.19 in /User/.pythonlibs/mlrun-base/lib/python3.9/site-packages (from datasets~=2.10.1->-r requirements.txt (line 5)) (0.18.0)\n", - "Requirement already satisfied: scipy>=1.1.0 in /User/.pythonlibs/mlrun-base/lib/python3.9/site-packages (from scikit-learn~=1.0.2->-r requirements.txt (line 6)) (1.11.4)\n", - "Requirement already satisfied: joblib>=0.11 in /User/.pythonlibs/mlrun-base/lib/python3.9/site-packages (from scikit-learn~=1.0.2->-r requirements.txt (line 6)) (1.3.2)\n", - "Requirement already satisfied: threadpoolctl>=2.0.0 in /User/.pythonlibs/mlrun-base/lib/python3.9/site-packages (from scikit-learn~=1.0.2->-r requirements.txt (line 6)) (3.2.0)\n", - "Requirement already satisfied: attrs>=17.3.0 in /User/.pythonlibs/mlrun-base/lib/python3.9/site-packages (from aiohttp->datasets~=2.10.1->-r requirements.txt (line 5)) (19.1.0)\n", - "Requirement already satisfied: multidict<7.0,>=4.5 in /conda/envs/mlrun-base/lib/python3.9/site-packages (from aiohttp->datasets~=2.10.1->-r requirements.txt (line 5)) (6.0.4)\n", - "Requirement already satisfied: yarl<2.0,>=1.0 in /conda/envs/mlrun-base/lib/python3.9/site-packages (from aiohttp->datasets~=2.10.1->-r requirements.txt (line 5)) (1.9.2)\n", - "Requirement already satisfied: frozenlist>=1.1.1 in /conda/envs/mlrun-base/lib/python3.9/site-packages (from aiohttp->datasets~=2.10.1->-r requirements.txt (line 5)) (1.4.0)\n", - "Requirement already satisfied: aiosignal>=1.1.2 in /conda/envs/mlrun-base/lib/python3.9/site-packages (from aiohttp->datasets~=2.10.1->-r requirements.txt (line 5)) (1.3.1)\n", - "Requirement already satisfied: async-timeout<5.0,>=4.0 in /conda/envs/mlrun-base/lib/python3.9/site-packages (from aiohttp->datasets~=2.10.1->-r requirements.txt (line 5)) (4.0.3)\n", - "Requirement already satisfied: pyparsing!=3.0.5,>=2.0.2 in /conda/envs/mlrun-base/lib/python3.9/site-packages (from packaging->onnxruntime==1.16.1->-r requirements.txt (line 2)) (3.1.1)\n", - "Requirement already satisfied: charset-normalizer<4,>=2 in /User/.pythonlibs/mlrun-base/lib/python3.9/site-packages (from requests->transformers~=4.26.1->-r requirements.txt (line 4)) (2.1.1)\n", - "Requirement already satisfied: idna<4,>=2.5 in /conda/envs/mlrun-base/lib/python3.9/site-packages (from requests->transformers~=4.26.1->-r requirements.txt (line 4)) (3.4)\n", - "Requirement already satisfied: urllib3<3,>=1.21.1 in /conda/envs/mlrun-base/lib/python3.9/site-packages (from requests->transformers~=4.26.1->-r requirements.txt (line 4)) (1.26.16)\n", - "Requirement already satisfied: certifi>=2017.4.17 in /conda/envs/mlrun-base/lib/python3.9/site-packages (from requests->transformers~=4.26.1->-r requirements.txt (line 4)) (2023.7.22)\n", - "Requirement already satisfied: networkx in /User/.pythonlibs/mlrun-base/lib/python3.9/site-packages (from torch>=1.9->optimum~=1.6.4->-r requirements.txt (line 3)) (3.2.1)\n", - "Requirement already satisfied: jinja2 in /User/.pythonlibs/mlrun-base/lib/python3.9/site-packages (from torch>=1.9->optimum~=1.6.4->-r requirements.txt (line 3)) (3.1.3)\n", - "Requirement already satisfied: nvidia-cuda-nvrtc-cu12==12.1.105 in /User/.pythonlibs/mlrun-base/lib/python3.9/site-packages (from torch>=1.9->optimum~=1.6.4->-r requirements.txt (line 3)) (12.1.105)\n", - "Requirement already satisfied: nvidia-cuda-runtime-cu12==12.1.105 in /User/.pythonlibs/mlrun-base/lib/python3.9/site-packages (from torch>=1.9->optimum~=1.6.4->-r requirements.txt (line 3)) (12.1.105)\n", - "Requirement already satisfied: nvidia-cuda-cupti-cu12==12.1.105 in /User/.pythonlibs/mlrun-base/lib/python3.9/site-packages (from torch>=1.9->optimum~=1.6.4->-r requirements.txt (line 3)) (12.1.105)\n", - "Requirement already satisfied: nvidia-cudnn-cu12==8.9.2.26 in /User/.pythonlibs/mlrun-base/lib/python3.9/site-packages (from torch>=1.9->optimum~=1.6.4->-r requirements.txt (line 3)) (8.9.2.26)\n", - "Requirement already satisfied: nvidia-cublas-cu12==12.1.3.1 in /User/.pythonlibs/mlrun-base/lib/python3.9/site-packages (from torch>=1.9->optimum~=1.6.4->-r requirements.txt (line 3)) (12.1.3.1)\n", - "Requirement already satisfied: nvidia-cufft-cu12==11.0.2.54 in /User/.pythonlibs/mlrun-base/lib/python3.9/site-packages (from torch>=1.9->optimum~=1.6.4->-r requirements.txt (line 3)) (11.0.2.54)\n", - "Requirement already satisfied: nvidia-curand-cu12==10.3.2.106 in /User/.pythonlibs/mlrun-base/lib/python3.9/site-packages (from torch>=1.9->optimum~=1.6.4->-r requirements.txt (line 3)) (10.3.2.106)\n", - "Requirement already satisfied: nvidia-cusolver-cu12==11.4.5.107 in /User/.pythonlibs/mlrun-base/lib/python3.9/site-packages (from torch>=1.9->optimum~=1.6.4->-r requirements.txt (line 3)) (11.4.5.107)\n", - "Requirement already satisfied: nvidia-cusparse-cu12==12.1.0.106 in /User/.pythonlibs/mlrun-base/lib/python3.9/site-packages (from torch>=1.9->optimum~=1.6.4->-r requirements.txt (line 3)) (12.1.0.106)\n", - "Requirement already satisfied: nvidia-nccl-cu12==2.18.1 in /User/.pythonlibs/mlrun-base/lib/python3.9/site-packages (from torch>=1.9->optimum~=1.6.4->-r requirements.txt (line 3)) (2.18.1)\n", - "Requirement already satisfied: nvidia-nvtx-cu12==12.1.105 in /User/.pythonlibs/mlrun-base/lib/python3.9/site-packages (from torch>=1.9->optimum~=1.6.4->-r requirements.txt (line 3)) (12.1.105)\n", - "Requirement already satisfied: triton==2.1.0 in /User/.pythonlibs/mlrun-base/lib/python3.9/site-packages (from torch>=1.9->optimum~=1.6.4->-r requirements.txt (line 3)) (2.1.0)\n", - "Requirement already satisfied: nvidia-nvjitlink-cu12 in /User/.pythonlibs/mlrun-base/lib/python3.9/site-packages (from nvidia-cusolver-cu12==11.4.5.107->torch>=1.9->optimum~=1.6.4->-r requirements.txt (line 3)) (12.3.101)\n", - "Requirement already satisfied: sentencepiece!=0.1.92,>=0.1.91 in /User/.pythonlibs/mlrun-base/lib/python3.9/site-packages (from transformers[sentencepiece]>=4.26.0->optimum~=1.6.4->-r requirements.txt (line 3)) (0.2.0)\n", - "Requirement already satisfied: humanfriendly>=9.1 in /conda/envs/mlrun-base/lib/python3.9/site-packages (from coloredlogs->onnxruntime==1.16.1->-r requirements.txt (line 2)) (9.2)\n", - "Requirement already satisfied: python-dateutil>=2.8.1 in /conda/envs/mlrun-base/lib/python3.9/site-packages (from pandas->datasets~=2.10.1->-r requirements.txt (line 5)) (2.8.2)\n", - "Requirement already satisfied: pytz>=2020.1 in /conda/envs/mlrun-base/lib/python3.9/site-packages (from pandas->datasets~=2.10.1->-r requirements.txt (line 5)) (2023.3.post1)\n", - "Requirement already satisfied: mpmath>=0.19 in /User/.pythonlibs/mlrun-base/lib/python3.9/site-packages (from sympy->onnxruntime==1.16.1->-r requirements.txt (line 2)) (1.3.0)\n", - "Requirement already satisfied: six>=1.5 in /conda/envs/mlrun-base/lib/python3.9/site-packages (from python-dateutil>=2.8.1->pandas->datasets~=2.10.1->-r requirements.txt (line 5)) (1.16.0)\n", - "Requirement already satisfied: MarkupSafe>=2.0 in /conda/envs/mlrun-base/lib/python3.9/site-packages (from jinja2->torch>=1.9->optimum~=1.6.4->-r requirements.txt (line 3)) (2.1.3)\n", - "Note: you may need to restart the kernel to use updated packages.\n" - ] - } - ], - "source": [ - "%pip install -r requirements.txt" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "pycharm": { - "name": "#%%\n" - } - }, - "outputs": [], - "source": [ - "import mlrun" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "pycharm": { - "name": "#%%\n" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "> 2024-03-24 17:10:17,091 [info] Project loaded successfully: {'project_name': 'hugging-face-trainer'}\n" - ] - } - ], - "source": [ - "project = mlrun.get_or_create_project('hugging-face-trainer', context=\"./\", user_project=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, - "source": [ - "### **Importing the hugging_face_classifier_trainer function from the Marketplace**" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "pycharm": { - "name": "#%%\n" - } - }, - "outputs": [], - "source": [ - "hugging_face_classifier_trainer = mlrun.import_function(\"hub://hugging_face_classifier_trainer\")" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, - "source": [ - "### **Training a model**\n", - "\n", - "Choosing the `train` handler" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, - "source": [ - "#### Define task parameters¶\n", - "* Class parameters should contain the prefix `CLASS_`\n", - "* Train parameters should contain the prefix `TRAIN_`" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": { - "pycharm": { - "name": "#%%\n" - } - }, - "outputs": [], - "source": [ - "model_class = \"transformers.AutoModelForSequenceClassification\"\n", - "additional_parameters = {\n", - " \"TRAIN_output_dir\": \"finetuning-sentiment-model-3000-samples\",\n", - " \"TRAIN_learning_rate\": 2e-5,\n", - " \"TRAIN_per_device_train_batch_size\": 16,\n", - " \"TRAIN_per_device_eval_batch_size\": 16,\n", - " \"TRAIN_num_train_epochs\": 3,\n", - " \"TRAIN_weight_decay\": 0.01,\n", - " \"TRAIN_push_to_hub\": False,\n", - " \"TRAIN_evaluation_strategy\": \"epoch\",\n", - " \"TRAIN_eval_steps\": 1,\n", - " \"TRAIN_logging_steps\": 1,\n", - " \"CLASS_num_labels\": 2\n", - "}" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, - "source": [ - "#### Running the Training job with the \"train\" handler" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": { - "pycharm": { - "name": "#%%\n" - }, - "scrolled": true, - "tags": [] - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "> 2024-03-24 17:10:21,025 [info] Storing function: {'name': 'hugging-face-classifier-trainer-train', 'uid': '514d8d5530c842238b1cc81983cd943e', 'db': 'http://mlrun-api:8080'}\n", - "> 2024-03-24 17:11:03,727 [info] 'train_test_split_size' is not provided, setting train_test_split_size to 0.2\n", - "> 2024-03-24 17:11:03,882 [info] Loading and editing Shayanvsf/US_Airline_Sentiment dataset from Hugging Face hub\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Found cached dataset parquet (/igz/.cache/huggingface/datasets/Shayanvsf___parquet/Shayanvsf--US_Airline_Sentiment-1319c42f87c44b2f/0.0.0/2a3b91fbd88a2c90d1dbbb32b460cf621d31bd5b05b934492fdef7d8d6f236ec)\n" - ] - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "f43b1388d0b344888323bec590baadee", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - " 0%| | 0/3 [00:00 2024-03-24 17:11:08,938 [info] training 'huggingface-model'\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "The following columns in the training set don't have a corresponding argument in `DistilBertForSequenceClassification.forward` and have been ignored: text. If text are not expected by `DistilBertForSequenceClassification.forward`, you can safely ignore this message.\n", - "This implementation of AdamW is deprecated and will be removed in a future version. Use the PyTorch implementation torch.optim.AdamW instead, or set `no_deprecation_warning=True` to disable this warning\n", - "***** Running training *****\n", - " Num examples = 100\n", - " Num Epochs = 3\n", - " Instantaneous batch size per device = 16\n", - " Total train batch size (w. parallel, distributed & accumulation) = 16\n", - " Gradient Accumulation steps = 1\n", - " Total optimization steps = 21\n", - " Number of trainable parameters = 66955010\n", - "You're using a DistilBertTokenizerFast tokenizer. Please note that with a fast tokenizer, using the `__call__` method is faster than using a method to encode the text followed by a call to the `pad` method to get a padded encoding.\n" - ] - }, - { - "data": { - "text/html": [ - "\n", - "
\n", - " \n", - " \n", - " [21/21 00:15, Epoch 3/3]\n", - "
\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
EpochTraining LossValidation LossAccuracyF1
10.7389000.5153110.7916670.000000
20.5259000.4815630.7916670.000000
30.4908000.4716750.7916670.000000

" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "The following columns in the evaluation set don't have a corresponding argument in `DistilBertForSequenceClassification.forward` and have been ignored: text. If text are not expected by `DistilBertForSequenceClassification.forward`, you can safely ignore this message.\n", - "***** Running Evaluation *****\n", - " Num examples = 24\n", - " Batch size = 16\n", - "/tmp/tmp0c1aawrq.py:561: FutureWarning:\n", - "\n", - "load_metric is deprecated and will be removed in the next major version of datasets. Use 'evaluate.load' instead, from the new library 🤗 Evaluate: https://huggingface.co/docs/evaluate\n", - "\n", - "The following columns in the evaluation set don't have a corresponding argument in `DistilBertForSequenceClassification.forward` and have been ignored: text. If text are not expected by `DistilBertForSequenceClassification.forward`, you can safely ignore this message.\n", - "***** Running Evaluation *****\n", - " Num examples = 24\n", - " Batch size = 16\n", - "The following columns in the evaluation set don't have a corresponding argument in `DistilBertForSequenceClassification.forward` and have been ignored: text. If text are not expected by `DistilBertForSequenceClassification.forward`, you can safely ignore this message.\n", - "***** Running Evaluation *****\n", - " Num examples = 24\n", - " Batch size = 16\n", - "\n", - "\n", - "Training completed. Do not forget to share your model on huggingface.co/models =)\n", - "\n", - "\n", - "tokenizer config file saved in /tmp/tokenizer/tokenizer_config.json\n", - "Special tokens file saved in /tmp/tokenizer/special_tokens_map.json\n", - "Configuration saved in /tmp/model/config.json\n", - "Model weights saved in /tmp/model/pytorch_model.bin\n" - ] - }, - { - "data": { - "text/html": [ - "\n", - "

\n", - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
projectuiditerstartstatenamelabelsinputsparametersresultsartifacts
hugging-face-trainer-avia0Mar 24 17:10:21completedhugging-face-classifier-trainer-train
v3io_user=avia
kind=local
owner=avia
host=jupyter-avia-6454bdd4c5-xz8cg
hf_dataset=Shayanvsf/US_Airline_Sentiment
drop_columns=['airline_sentiment_confidence', 'negativereason_confidence']
pretrained_tokenizer=distilbert-base-uncased
pretrained_model=distilbert-base-uncased
model_class=transformers.AutoModelForSequenceClassification
label_name=airline_sentiment
num_of_train_samples=100
metrics=['accuracy', 'f1']
random_state=42
TRAIN_output_dir=finetuning-sentiment-model-3000-samples
TRAIN_learning_rate=2e-05
TRAIN_per_device_train_batch_size=16
TRAIN_per_device_eval_batch_size=16
TRAIN_num_train_epochs=3
TRAIN_weight_decay=0.01
TRAIN_push_to_hub=False
TRAIN_evaluation_strategy=epoch
TRAIN_eval_steps=1
TRAIN_logging_steps=1
CLASS_num_labels=2
loss=0.4908
learning_rate=0.0
eval_loss=0.47167453169822693
eval_accuracy=0.7916666666666666
eval_f1=0.0
eval_runtime=0.5186
eval_samples_per_second=46.276
eval_steps_per_second=3.856
train_runtime=17.6054
train_samples_per_second=17.04
train_steps_per_second=1.193
total_flos=3327208489680.0
loss_plot
learning_rate_plot
eval_loss_plot
eval_accuracy_plot
eval_f1_plot
eval_runtime_plot
eval_samples_per_second_plot
eval_steps_per_second_plot
tokenizer
model
\n", - "
\n", - "
\n", - "
\n", - " Title\n", - " ×\n", - "
\n", - " \n", - "
\n", - "
\n" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n" - ] - }, - { - "data": { - "text/html": [ - " > to track results use the .show() or .logs() methods or click here to open in UI" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "> 2024-03-24 17:12:01,880 [info] Run execution finished: {'status': 'completed', 'name': 'hugging-face-classifier-trainer-train'}\n" - ] - } - ], - "source": [ - "train_run = hugging_face_classifier_trainer.run(params={\n", - " \"hf_dataset\": \"Shayanvsf/US_Airline_Sentiment\",\n", - " \"drop_columns\": [\n", - " \"airline_sentiment_confidence\",\n", - " \"negativereason_confidence\",\n", - " ],\n", - " \"pretrained_tokenizer\": \"distilbert-base-uncased\",\n", - " \"pretrained_model\": \"distilbert-base-uncased\",\n", - " \"model_class\": \"transformers.AutoModelForSequenceClassification\",\n", - " \"label_name\": \"airline_sentiment\",\n", - " \"num_of_train_samples\": 100,\n", - " \"metrics\": [\"accuracy\", \"f1\"],\n", - " \"random_state\": 42,\n", - " **additional_parameters\n", - " },\n", - " handler=\"train\",\n", - " local=True,\n", - " )" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, - "source": [ - "#### The result of the train run" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": { - "pycharm": { - "name": "#%%\n" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "{'loss': 0.4908,\n", - " 'learning_rate': 0.0,\n", - " 'eval_loss': 0.47167453169822693,\n", - " 'eval_accuracy': 0.7916666666666666,\n", - " 'eval_f1': 0.0,\n", - " 'eval_runtime': 0.5186,\n", - " 'eval_samples_per_second': 46.276,\n", - " 'eval_steps_per_second': 3.856,\n", - " 'train_runtime': 17.6054,\n", - " 'train_samples_per_second': 17.04,\n", - " 'train_steps_per_second': 1.193,\n", - " 'total_flos': 3327208489680.0,\n", - " 'loss_plot': 'v3io:///projects/hugging-face-trainer-avia/artifacts/hugging-face-classifier-trainer-train/0/loss_plot.html',\n", - " 'learning_rate_plot': 'v3io:///projects/hugging-face-trainer-avia/artifacts/hugging-face-classifier-trainer-train/0/learning_rate_plot.html',\n", - " 'eval_loss_plot': 'v3io:///projects/hugging-face-trainer-avia/artifacts/hugging-face-classifier-trainer-train/0/eval_loss_plot.html',\n", - " 'eval_accuracy_plot': 'v3io:///projects/hugging-face-trainer-avia/artifacts/hugging-face-classifier-trainer-train/0/eval_accuracy_plot.html',\n", - " 'eval_f1_plot': 'v3io:///projects/hugging-face-trainer-avia/artifacts/hugging-face-classifier-trainer-train/0/eval_f1_plot.html',\n", - " 'eval_runtime_plot': 'v3io:///projects/hugging-face-trainer-avia/artifacts/hugging-face-classifier-trainer-train/0/eval_runtime_plot.html',\n", - " 'eval_samples_per_second_plot': 'v3io:///projects/hugging-face-trainer-avia/artifacts/hugging-face-classifier-trainer-train/0/eval_samples_per_second_plot.html',\n", - " 'eval_steps_per_second_plot': 'v3io:///projects/hugging-face-trainer-avia/artifacts/hugging-face-classifier-trainer-train/0/eval_steps_per_second_plot.html',\n", - " 'tokenizer': 'store://artifacts/hugging-face-trainer-avia/hugging-face-classifier-trainer-train_tokenizer@514d8d5530c842238b1cc81983cd943e',\n", - " 'model': 'store://artifacts/hugging-face-trainer-avia/huggingface-model@514d8d5530c842238b1cc81983cd943e'}" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "train_run.outputs" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": { - "pycharm": { - "name": "#%%\n" - } - }, - "outputs": [ - { - "data": { - "text/html": [ - "\n", - "\n", - "\n", - "
\n", - "
\n", - "\n", - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "train_run.artifact('loss_plot').show()" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, - "source": [ - "#### Getting the model for evaluating and predicting" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": { - "pycharm": { - "name": "#%%\n" - } - }, - "outputs": [], - "source": [ - "model_path = train_run.outputs['model']" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### **Optimize the model**\n", - "\n", - "Choosing the `optimize` handler\n", - "\n", - "The result of using this handled is an onnx optimized model." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": { - "scrolled": true, - "tags": [] - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "> 2024-03-24 17:12:02,020 [info] Storing function: {'name': 'hugging-face-classifier-trainer-optimize', 'uid': 'fbee1ead18444824a4b5c0308a677bf4', 'db': 'http://mlrun-api:8080'}\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/User/.pythonlibs/mlrun-base/lib/python3.9/site-packages/optimum/onnxruntime/configuration.py:726: FutureWarning:\n", - "\n", - "disable_embed_layer_norm will be deprecated soon, use disable_embed_layer_norm_fusion instead, disable_embed_layer_norm_fusion is set to True.\n", - "\n", - "loading configuration file /tmp/config.json\n", - "Model config DistilBertConfig {\n", - " \"_name_or_path\": \"/tmp/config.json\",\n", - " \"activation\": \"gelu\",\n", - " \"architectures\": [\n", - " \"DistilBertForSequenceClassification\"\n", - " ],\n", - " \"attention_dropout\": 0.1,\n", - " \"dim\": 768,\n", - " \"dropout\": 0.1,\n", - " \"hidden_dim\": 3072,\n", - " \"initializer_range\": 0.02,\n", - " \"max_position_embeddings\": 512,\n", - " \"model_type\": \"distilbert\",\n", - " \"n_heads\": 12,\n", - " \"n_layers\": 6,\n", - " \"pad_token_id\": 0,\n", - " \"problem_type\": \"single_label_classification\",\n", - " \"qa_dropout\": 0.1,\n", - " \"seq_classif_dropout\": 0.2,\n", - " \"sinusoidal_pos_embds\": false,\n", - " \"tie_weights_\": true,\n", - " \"torch_dtype\": \"float32\",\n", - " \"transformers_version\": \"4.26.1\",\n", - " \"vocab_size\": 30522\n", - "}\n", - "\n", - "loading configuration file /tmp/config.json\n", - "Model config DistilBertConfig {\n", - " \"_name_or_path\": \"/tmp\",\n", - " \"activation\": \"gelu\",\n", - " \"architectures\": [\n", - " \"DistilBertForSequenceClassification\"\n", - " ],\n", - " \"attention_dropout\": 0.1,\n", - " \"dim\": 768,\n", - " \"dropout\": 0.1,\n", - " \"hidden_dim\": 3072,\n", - " \"initializer_range\": 0.02,\n", - " \"max_position_embeddings\": 512,\n", - " \"model_type\": \"distilbert\",\n", - " \"n_heads\": 12,\n", - " \"n_layers\": 6,\n", - " \"pad_token_id\": 0,\n", - " \"problem_type\": \"single_label_classification\",\n", - " \"qa_dropout\": 0.1,\n", - " \"seq_classif_dropout\": 0.2,\n", - " \"sinusoidal_pos_embds\": false,\n", - " \"tie_weights_\": true,\n", - " \"torch_dtype\": \"float32\",\n", - " \"transformers_version\": \"4.26.1\",\n", - " \"vocab_size\": 30522\n", - "}\n", - "\n", - "loading weights file /tmp/pytorch_model.bin\n", - "All model checkpoint weights were used when initializing DistilBertForSequenceClassification.\n", - "\n", - "All the weights of DistilBertForSequenceClassification were initialized from the model checkpoint at /tmp.\n", - "If your task is similar to the task the model of the checkpoint was trained on, you can already use DistilBertForSequenceClassification for predictions without further training.\n", - "/User/.pythonlibs/mlrun-base/lib/python3.9/site-packages/transformers/models/distilbert/modeling_distilbert.py:218: TracerWarning:\n", - "\n", - "torch.tensor results are registered as constants in the trace. You can safely ignore this warning if you use this function to create tensors out of constant variables that would be the same every time you call this function. In any other case, this might cause the trace to be incorrect.\n", - "\n", - "Configuration saved in /tmp/tmp79wjp8m8/config.json\n", - "Could not locate the tokenizer configuration file, will try to use the model config instead.\n", - "loading configuration file /tmp/config.json\n", - "Model config DistilBertConfig {\n", - " \"_name_or_path\": \"/tmp\",\n", - " \"activation\": \"gelu\",\n", - " \"architectures\": [\n", - " \"DistilBertForSequenceClassification\"\n", - " ],\n", - " \"attention_dropout\": 0.1,\n", - " \"dim\": 768,\n", - " \"dropout\": 0.1,\n", - " \"hidden_dim\": 3072,\n", - " \"initializer_range\": 0.02,\n", - " \"max_position_embeddings\": 512,\n", - " \"model_type\": \"distilbert\",\n", - " \"n_heads\": 12,\n", - " \"n_layers\": 6,\n", - " \"pad_token_id\": 0,\n", - " \"problem_type\": \"single_label_classification\",\n", - " \"qa_dropout\": 0.1,\n", - " \"seq_classif_dropout\": 0.2,\n", - " \"sinusoidal_pos_embds\": false,\n", - " \"tie_weights_\": true,\n", - " \"torch_dtype\": \"float32\",\n", - " \"transformers_version\": \"4.26.1\",\n", - " \"vocab_size\": 30522\n", - "}\n", - "\n", - "loading configuration file /tmp/config.json\n", - "Model config DistilBertConfig {\n", - " \"_name_or_path\": \"/tmp\",\n", - " \"activation\": \"gelu\",\n", - " \"architectures\": [\n", - " \"DistilBertForSequenceClassification\"\n", - " ],\n", - " \"attention_dropout\": 0.1,\n", - " \"dim\": 768,\n", - " \"dropout\": 0.1,\n", - " \"hidden_dim\": 3072,\n", - " \"initializer_range\": 0.02,\n", - " \"max_position_embeddings\": 512,\n", - " \"model_type\": \"distilbert\",\n", - " \"n_heads\": 12,\n", - " \"n_layers\": 6,\n", - " \"pad_token_id\": 0,\n", - " \"problem_type\": \"single_label_classification\",\n", - " \"qa_dropout\": 0.1,\n", - " \"seq_classif_dropout\": 0.2,\n", - " \"sinusoidal_pos_embds\": false,\n", - " \"tie_weights_\": true,\n", - " \"torch_dtype\": \"float32\",\n", - " \"transformers_version\": \"4.26.1\",\n", - " \"vocab_size\": 30522\n", - "}\n", - "\n", - "Could not locate the tokenizer configuration file, will try to use the model config instead.\n", - "loading configuration file /tmp/config.json\n", - "Model config DistilBertConfig {\n", - " \"_name_or_path\": \"/tmp\",\n", - " \"activation\": \"gelu\",\n", - " \"architectures\": [\n", - " \"DistilBertForSequenceClassification\"\n", - " ],\n", - " \"attention_dropout\": 0.1,\n", - " \"dim\": 768,\n", - " \"dropout\": 0.1,\n", - " \"hidden_dim\": 3072,\n", - " \"initializer_range\": 0.02,\n", - " \"max_position_embeddings\": 512,\n", - " \"model_type\": \"distilbert\",\n", - " \"n_heads\": 12,\n", - " \"n_layers\": 6,\n", - " \"pad_token_id\": 0,\n", - " \"problem_type\": \"single_label_classification\",\n", - " \"qa_dropout\": 0.1,\n", - " \"seq_classif_dropout\": 0.2,\n", - " \"sinusoidal_pos_embds\": false,\n", - " \"tie_weights_\": true,\n", - " \"torch_dtype\": \"float32\",\n", - " \"transformers_version\": \"4.26.1\",\n", - " \"vocab_size\": 30522\n", - "}\n", - "\n", - "Could not locate the tokenizer configuration file, will try to use the model config instead.\n", - "loading configuration file /tmp/tmp79wjp8m8/config.json\n", - "Model config DistilBertConfig {\n", - " \"_name_or_path\": \"/tmp/tmp79wjp8m8\",\n", - " \"activation\": \"gelu\",\n", - " \"architectures\": [\n", - " \"DistilBertForSequenceClassification\"\n", - " ],\n", - " \"attention_dropout\": 0.1,\n", - " \"dim\": 768,\n", - " \"dropout\": 0.1,\n", - " \"hidden_dim\": 3072,\n", - " \"initializer_range\": 0.02,\n", - " \"max_position_embeddings\": 512,\n", - " \"model_type\": \"distilbert\",\n", - " \"n_heads\": 12,\n", - " \"n_layers\": 6,\n", - " \"pad_token_id\": 0,\n", - " \"problem_type\": \"single_label_classification\",\n", - " \"qa_dropout\": 0.1,\n", - " \"seq_classif_dropout\": 0.2,\n", - " \"sinusoidal_pos_embds\": false,\n", - " \"tie_weights_\": true,\n", - " \"torch_dtype\": \"float32\",\n", - " \"transformers_version\": \"4.26.1\",\n", - " \"vocab_size\": 30522\n", - "}\n", - "\n", - "loading configuration file /tmp/tmp79wjp8m8/config.json\n", - "Model config DistilBertConfig {\n", - " \"_name_or_path\": \"/tmp/tmp79wjp8m8\",\n", - " \"activation\": \"gelu\",\n", - " \"architectures\": [\n", - " \"DistilBertForSequenceClassification\"\n", - " ],\n", - " \"attention_dropout\": 0.1,\n", - " \"dim\": 768,\n", - " \"dropout\": 0.1,\n", - " \"hidden_dim\": 3072,\n", - " \"initializer_range\": 0.02,\n", - " \"max_position_embeddings\": 512,\n", - " \"model_type\": \"distilbert\",\n", - " \"n_heads\": 12,\n", - " \"n_layers\": 6,\n", - " \"pad_token_id\": 0,\n", - " \"problem_type\": \"single_label_classification\",\n", - " \"qa_dropout\": 0.1,\n", - " \"seq_classif_dropout\": 0.2,\n", - " \"sinusoidal_pos_embds\": false,\n", - " \"tie_weights_\": true,\n", - " \"torch_dtype\": \"float32\",\n", - " \"transformers_version\": \"4.26.1\",\n", - " \"vocab_size\": 30522\n", - "}\n", - "\n", - "Could not locate the tokenizer configuration file, will try to use the model config instead.\n", - "loading configuration file /tmp/tmp79wjp8m8/config.json\n", - "Model config DistilBertConfig {\n", - " \"_name_or_path\": \"/tmp/tmp79wjp8m8\",\n", - " \"activation\": \"gelu\",\n", - " \"architectures\": [\n", - " \"DistilBertForSequenceClassification\"\n", - " ],\n", - " \"attention_dropout\": 0.1,\n", - " \"dim\": 768,\n", - " \"dropout\": 0.1,\n", - " \"hidden_dim\": 3072,\n", - " \"initializer_range\": 0.02,\n", - " \"max_position_embeddings\": 512,\n", - " \"model_type\": \"distilbert\",\n", - " \"n_heads\": 12,\n", - " \"n_layers\": 6,\n", - " \"pad_token_id\": 0,\n", - " \"problem_type\": \"single_label_classification\",\n", - " \"qa_dropout\": 0.1,\n", - " \"seq_classif_dropout\": 0.2,\n", - " \"sinusoidal_pos_embds\": false,\n", - " \"tie_weights_\": true,\n", - " \"torch_dtype\": \"float32\",\n", - " \"transformers_version\": \"4.26.1\",\n", - " \"vocab_size\": 30522\n", - "}\n", - "\n", - "Configuration saved in optimized/config.json\n", - "Could not locate the tokenizer configuration file, will try to use the model config instead.\n", - "loading configuration file /tmp/tmp79wjp8m8/config.json\n", - "Model config DistilBertConfig {\n", - " \"_name_or_path\": \"/tmp/tmp79wjp8m8\",\n", - " \"activation\": \"gelu\",\n", - " \"architectures\": [\n", - " \"DistilBertForSequenceClassification\"\n", - " ],\n", - " \"attention_dropout\": 0.1,\n", - " \"dim\": 768,\n", - " \"dropout\": 0.1,\n", - " \"hidden_dim\": 3072,\n", - " \"initializer_range\": 0.02,\n", - " \"max_position_embeddings\": 512,\n", - " \"model_type\": \"distilbert\",\n", - " \"n_heads\": 12,\n", - " \"n_layers\": 6,\n", - " \"pad_token_id\": 0,\n", - " \"problem_type\": \"single_label_classification\",\n", - " \"qa_dropout\": 0.1,\n", - " \"seq_classif_dropout\": 0.2,\n", - " \"sinusoidal_pos_embds\": false,\n", - " \"tie_weights_\": true,\n", - " \"torch_dtype\": \"float32\",\n", - " \"transformers_version\": \"4.26.1\",\n", - " \"vocab_size\": 30522\n", - "}\n", - "\n", - "loading configuration file /tmp/tmp79wjp8m8/config.json\n", - "Model config DistilBertConfig {\n", - " \"_name_or_path\": \"/tmp/tmp79wjp8m8\",\n", - " \"activation\": \"gelu\",\n", - " \"architectures\": [\n", - " \"DistilBertForSequenceClassification\"\n", - " ],\n", - " \"attention_dropout\": 0.1,\n", - " \"dim\": 768,\n", - " \"dropout\": 0.1,\n", - " \"hidden_dim\": 3072,\n", - " \"initializer_range\": 0.02,\n", - " \"max_position_embeddings\": 512,\n", - " \"model_type\": \"distilbert\",\n", - " \"n_heads\": 12,\n", - " \"n_layers\": 6,\n", - " \"pad_token_id\": 0,\n", - " \"problem_type\": \"single_label_classification\",\n", - " \"qa_dropout\": 0.1,\n", - " \"seq_classif_dropout\": 0.2,\n", - " \"sinusoidal_pos_embds\": false,\n", - " \"tie_weights_\": true,\n", - " \"torch_dtype\": \"float32\",\n", - " \"transformers_version\": \"4.26.1\",\n", - " \"vocab_size\": 30522\n", - "}\n", - "\n", - "Could not locate the tokenizer configuration file, will try to use the model config instead.\n", - "loading configuration file /tmp/tmp79wjp8m8/config.json\n", - "Model config DistilBertConfig {\n", - " \"_name_or_path\": \"/tmp/tmp79wjp8m8\",\n", - " \"activation\": \"gelu\",\n", - " \"architectures\": [\n", - " \"DistilBertForSequenceClassification\"\n", - " ],\n", - " \"attention_dropout\": 0.1,\n", - " \"dim\": 768,\n", - " \"dropout\": 0.1,\n", - " \"hidden_dim\": 3072,\n", - " \"initializer_range\": 0.02,\n", - " \"max_position_embeddings\": 512,\n", - " \"model_type\": \"distilbert\",\n", - " \"n_heads\": 12,\n", - " \"n_layers\": 6,\n", - " \"pad_token_id\": 0,\n", - " \"problem_type\": \"single_label_classification\",\n", - " \"qa_dropout\": 0.1,\n", - " \"seq_classif_dropout\": 0.2,\n", - " \"sinusoidal_pos_embds\": false,\n", - " \"tie_weights_\": true,\n", - " \"torch_dtype\": \"float32\",\n", - " \"transformers_version\": \"4.26.1\",\n", - " \"vocab_size\": 30522\n", - "}\n", - "\n", - "Failed to remove node input: \"/distilbert/transformer/layer.0/attention/Transpose_output_0\"\n", - "input: \"/distilbert/transformer/layer.0/attention/Constant_11_output_0\"\n", - "output: \"/distilbert/transformer/layer.0/attention/Div_output_0\"\n", - "name: \"/distilbert/transformer/layer.0/attention/Div\"\n", - "op_type: \"Div\"\n", - "\n", - "Failed to remove node input: \"/distilbert/transformer/layer.1/attention/Transpose_output_0\"\n", - "input: \"/distilbert/transformer/layer.1/attention/Constant_11_output_0\"\n", - "output: \"/distilbert/transformer/layer.1/attention/Div_output_0\"\n", - "name: \"/distilbert/transformer/layer.1/attention/Div\"\n", - "op_type: \"Div\"\n", - "\n", - "Failed to remove node input: \"/distilbert/transformer/layer.2/attention/Transpose_output_0\"\n", - "input: \"/distilbert/transformer/layer.2/attention/Constant_11_output_0\"\n", - "output: \"/distilbert/transformer/layer.2/attention/Div_output_0\"\n", - "name: \"/distilbert/transformer/layer.2/attention/Div\"\n", - "op_type: \"Div\"\n", - "\n", - "Failed to remove node input: \"/distilbert/transformer/layer.3/attention/Transpose_output_0\"\n", - "input: \"/distilbert/transformer/layer.3/attention/Constant_11_output_0\"\n", - "output: \"/distilbert/transformer/layer.3/attention/Div_output_0\"\n", - "name: \"/distilbert/transformer/layer.3/attention/Div\"\n", - "op_type: \"Div\"\n", - "\n", - "Failed to remove node input: \"/distilbert/transformer/layer.4/attention/Transpose_output_0\"\n", - "input: \"/distilbert/transformer/layer.4/attention/Constant_11_output_0\"\n", - "output: \"/distilbert/transformer/layer.4/attention/Div_output_0\"\n", - "name: \"/distilbert/transformer/layer.4/attention/Div\"\n", - "op_type: \"Div\"\n", - "\n", - "Failed to remove node input: \"/distilbert/transformer/layer.5/attention/Transpose_output_0\"\n", - "input: \"/distilbert/transformer/layer.5/attention/Constant_11_output_0\"\n", - "output: \"/distilbert/transformer/layer.5/attention/Div_output_0\"\n", - "name: \"/distilbert/transformer/layer.5/attention/Div\"\n", - "op_type: \"Div\"\n", - "\n", - "Configuration saved in optimized/config.json\n" - ] - }, - { - "data": { - "text/html": [ - "\n", - "
\n", - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
projectuiditerstartstatenamelabelsinputsparametersresultsartifacts
hugging-face-trainer-avia0Mar 24 17:12:02completedhugging-face-classifier-trainer-optimize
v3io_user=avia
kind=local
owner=avia
host=jupyter-avia-6454bdd4c5-xz8cg
model_path=store://artifacts/hugging-face-trainer-avia/huggingface-model@514d8d5530c842238b1cc81983cd943e
model
\n", - "
\n", - "
\n", - "
\n", - " Title\n", - " ×\n", - "
\n", - " \n", - "
\n", - "
\n" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n" - ] - }, - { - "data": { - "text/html": [ - " > to track results use the .show() or .logs() methods or click here to open in UI" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "> 2024-03-24 17:12:22,721 [info] Run execution finished: {'status': 'completed', 'name': 'hugging-face-classifier-trainer-optimize'}\n" - ] - } - ], - "source": [ - "optimize_run = hugging_face_classifier_trainer.run(params={\n", - " \"model_path\": str(model_path)\n", - " },\n", - " handler=\"optimize\",\n", - " local=True,\n", - " )" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'model': 'store://artifacts/hugging-face-trainer-avia/optimized_model@fbee1ead18444824a4b5c0308a677bf4'}" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "optimize_run.outputs" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### **Running the training remotely**\n" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": { - "scrolled": true, - "tags": [] - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/User/.pythonlibs/mlrun-base/lib/python3.9/site-packages/mlrun/projects/operations.py:276: OverwriteBuildParamsWarning:\n", - "\n", - "The `overwrite_build_params` parameter default will change from 'False' to 'True' in 1.8.0.\n", - "\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "> 2024-03-24 17:14:22,792 [info] Started building image: .mlrun/func-hugging-face-trainer-avia-hugging-face-classifier-trainer:latest\n", - "\u001b[36mINFO\u001b[0m[0000] Retrieving image manifest mlrun/mlrun:1.6.1 \n", - "\u001b[36mINFO\u001b[0m[0000] Retrieving image mlrun/mlrun:1.6.1 from registry index.docker.io \n", - "\u001b[36mINFO\u001b[0m[0000] Built cross stage deps: map[] \n", - "\u001b[36mINFO\u001b[0m[0000] Retrieving image manifest mlrun/mlrun:1.6.1 \n", - "\u001b[36mINFO\u001b[0m[0000] Returning cached image manifest \n", - "\u001b[36mINFO\u001b[0m[0000] Executing 0 build triggers \n", - "\u001b[36mINFO\u001b[0m[0000] Building stage 'mlrun/mlrun:1.6.1' [idx: '0', base-idx: '-1'] \n", - "\u001b[36mINFO\u001b[0m[0000] Unpacking rootfs as cmd RUN echo 'Installing /empty/requirements.txt...'; cat /empty/requirements.txt requires it. \n", - "\u001b[36mINFO\u001b[0m[0047] RUN echo 'Installing /empty/requirements.txt...'; cat /empty/requirements.txt \n", - "\u001b[36mINFO\u001b[0m[0047] Initializing snapshotter ... \n", - "\u001b[36mINFO\u001b[0m[0047] Taking snapshot of full filesystem... \n", - "\u001b[36mINFO\u001b[0m[0074] Cmd: /bin/sh \n", - "\u001b[36mINFO\u001b[0m[0074] Args: [-c echo 'Installing /empty/requirements.txt...'; cat /empty/requirements.txt] \n", - "\u001b[36mINFO\u001b[0m[0074] Running: [/bin/sh -c echo 'Installing /empty/requirements.txt...'; cat /empty/requirements.txt] \n", - "Installing /empty/requirements.txt...\n", - "mlrun[complete]==1.6.1\n", - "onnx~=1.14.1\n", - "onnxruntime~=1.16.1\n", - "optimum~=1.6.4\n", - "transformers~=4.26.1\n", - "datasets~=2.10.1\n", - "scikit-learn~=1.0.2\n", - "\u001b[36mINFO\u001b[0m[0074] Taking snapshot of full filesystem... \n", - "\u001b[36mINFO\u001b[0m[0078] No files were changed, appending empty layer to config. No layer added to image. \n", - "\u001b[36mINFO\u001b[0m[0078] RUN python -m pip install -r /empty/requirements.txt \n", - "\u001b[36mINFO\u001b[0m[0078] Cmd: /bin/sh \n", - "\u001b[36mINFO\u001b[0m[0078] Args: [-c python -m pip install -r /empty/requirements.txt] \n", - "\u001b[36mINFO\u001b[0m[0078] Running: [/bin/sh -c python -m pip install -r /empty/requirements.txt] \n", - "Requirement already satisfied: mlrun[complete]==1.6.1 in /opt/conda/lib/python3.9/site-packages (from -r /empty/requirements.txt (line 1)) (1.6.1)\n", - "Collecting onnx~=1.14.1 (from -r /empty/requirements.txt (line 2))\n", - " Obtaining dependency information for onnx~=1.14.1 from https://files.pythonhosted.org/packages/ff/24/0e522fdcadf0e15fc304145a5b6e5d7246d7f2c507fd9bfe6e1fafb2aa95/onnx-1.14.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata\n", - " Downloading onnx-1.14.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (15 kB)\n", - "Collecting onnxruntime~=1.16.1 (from -r /empty/requirements.txt (line 3))\n", - " Obtaining dependency information for onnxruntime~=1.16.1 from https://files.pythonhosted.org/packages/de/ab/ed3ae0d649cee41e870f8b1653cf4a1c1fc321e0ded4e3e1a3d4a25c0131/onnxruntime-1.16.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata\n", - " Downloading onnxruntime-1.16.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (4.3 kB)\n", - "Collecting optimum~=1.6.4 (from -r /empty/requirements.txt (line 4))\n", - " Obtaining dependency information for optimum~=1.6.4 from https://files.pythonhosted.org/packages/31/72/a7e3b2c57d6368c5f4bb6fba54a85cbf07d25c385a2db3f1a638f3c0ddb2/optimum-1.6.4-py3-none-any.whl.metadata\n", - " Downloading optimum-1.6.4-py3-none-any.whl.metadata (17 kB)\n", - "Collecting transformers~=4.26.1 (from -r /empty/requirements.txt (line 5))\n", - " Obtaining dependency information for transformers~=4.26.1 from https://files.pythonhosted.org/packages/1e/e2/60c3f4691b16d126ee9cfe28f598b13c424b60350ab339aba81aef054b8f/transformers-4.26.1-py3-none-any.whl.metadata\n", - " Downloading transformers-4.26.1-py3-none-any.whl.metadata (100 kB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100.3/100.3 kB 6.2 MB/s eta 0:00:00\n", - "Collecting datasets~=2.10.1 (from -r /empty/requirements.txt (line 6))\n", - " Obtaining dependency information for datasets~=2.10.1 from https://files.pythonhosted.org/packages/fe/17/5825fdf034ff1a315becdbb9b6fe5a2bd9d8e724464535f18809593bf9c2/datasets-2.10.1-py3-none-any.whl.metadata\n", - " Downloading datasets-2.10.1-py3-none-any.whl.metadata (20 kB)\n", - "Collecting scikit-learn~=1.0.2 (from -r /empty/requirements.txt (line 7))\n", - " Obtaining dependency information for scikit-learn~=1.0.2 from https://files.pythonhosted.org/packages/57/aa/483fbe6b5314bce2d49801e6cec1f2139a9c220d0d51494788fff47233b3/scikit_learn-1.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata\n", - " Downloading scikit_learn-1.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (10 kB)\n", - "Requirement already satisfied: urllib3<1.27,>=1.26.9 in /opt/conda/lib/python3.9/site-packages (from mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.26.18)\n", - "Requirement already satisfied: GitPython>=3.1.41,~=3.1 in /opt/conda/lib/python3.9/site-packages (from mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (3.1.42)\n", - "Requirement already satisfied: aiohttp~=3.9 in /opt/conda/lib/python3.9/site-packages (from mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (3.9.3)\n", - "Requirement already satisfied: aiohttp-retry~=2.8 in /opt/conda/lib/python3.9/site-packages (from mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (2.8.3)\n", - "Requirement already satisfied: click~=8.1 in /opt/conda/lib/python3.9/site-packages (from mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (8.1.7)\n", - "Requirement already satisfied: kfp~=1.8 in /opt/conda/lib/python3.9/site-packages (from mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.8.22)\n", - "Requirement already satisfied: nest-asyncio~=1.0 in /opt/conda/lib/python3.9/site-packages (from mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.6.0)\n", - "Requirement already satisfied: ipython~=8.10 in /opt/conda/lib/python3.9/site-packages (from mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (8.18.1)\n", - "Requirement already satisfied: nuclio-jupyter~=0.9.15 in /opt/conda/lib/python3.9/site-packages (from mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (0.9.16)\n", - "Requirement already satisfied: numpy<1.27.0,>=1.16.5 in /opt/conda/lib/python3.9/site-packages (from mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.26.4)\n", - "Requirement already satisfied: pandas<2.2,>=1.2 in /opt/conda/lib/python3.9/site-packages (from mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (2.1.4)\n", - "Requirement already satisfied: pyarrow<15,>=10.0 in /opt/conda/lib/python3.9/site-packages (from mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (14.0.2)\n", - "Requirement already satisfied: pyyaml~=5.1 in /opt/conda/lib/python3.9/site-packages (from mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (5.4.1)\n", - "Requirement already satisfied: requests~=2.31 in /opt/conda/lib/python3.9/site-packages (from mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (2.31.0)\n", - "Requirement already satisfied: tabulate~=0.8.6 in /opt/conda/lib/python3.9/site-packages (from mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (0.8.10)\n", - "Requirement already satisfied: v3io~=0.5.21 in /opt/conda/lib/python3.9/site-packages (from mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (0.5.23)\n", - "Requirement already satisfied: pydantic>=1.10.8,~=1.10 in /opt/conda/lib/python3.9/site-packages (from mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.10.14)\n", - "Requirement already satisfied: mergedeep~=1.3 in /opt/conda/lib/python3.9/site-packages (from mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.3.4)\n", - "Requirement already satisfied: v3io-frames~=0.10.12 in /opt/conda/lib/python3.9/site-packages (from mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (0.10.13)\n", - "Requirement already satisfied: semver~=3.0 in /opt/conda/lib/python3.9/site-packages (from mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (3.0.2)\n", - "Requirement already satisfied: dependency-injector~=4.41 in /opt/conda/lib/python3.9/site-packages (from mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (4.41.0)\n", - "Requirement already satisfied: fsspec==2023.9.2 in /opt/conda/lib/python3.9/site-packages (from mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (2023.9.2)\n", - "Requirement already satisfied: v3iofs~=0.1.17 in /opt/conda/lib/python3.9/site-packages (from mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (0.1.18)\n", - "Requirement already satisfied: storey~=1.6.18 in /opt/conda/lib/python3.9/site-packages (from mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.6.18)\n", - "Requirement already satisfied: inflection~=0.5.0 in /opt/conda/lib/python3.9/site-packages (from mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (0.5.1)\n", - "Requirement already satisfied: python-dotenv~=0.17.0 in /opt/conda/lib/python3.9/site-packages (from mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (0.17.1)\n", - "Requirement already satisfied: setuptools~=68.2 in /opt/conda/lib/python3.9/site-packages (from mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (68.2.2)\n", - "Requirement already satisfied: deprecated~=1.2 in /opt/conda/lib/python3.9/site-packages (from mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.2.14)\n", - "Requirement already satisfied: jinja2>=3.1.3,~=3.1 in /opt/conda/lib/python3.9/site-packages (from mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (3.1.3)\n", - "Requirement already satisfied: anyio~=3.7 in /opt/conda/lib/python3.9/site-packages (from mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (3.7.1)\n", - "Requirement already satisfied: orjson~=3.9 in /opt/conda/lib/python3.9/site-packages (from mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (3.9.15)\n", - "Requirement already satisfied: adlfs==2023.9.0 in /opt/conda/lib/python3.9/site-packages (from mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (2023.9.0)\n", - "Requirement already satisfied: aiobotocore<2.8,>=2.5.0 in /opt/conda/lib/python3.9/site-packages (from mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (2.5.4)\n", - "Requirement already satisfied: avro~=1.11 in /opt/conda/lib/python3.9/site-packages (from mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.11.3)\n", - "Requirement already satisfied: azure-core~=1.24 in /opt/conda/lib/python3.9/site-packages (from mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.30.0)\n", - "Requirement already satisfied: azure-identity~=1.5 in /opt/conda/lib/python3.9/site-packages (from mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.15.0)\n", - "Requirement already satisfied: azure-keyvault-secrets~=4.2 in /opt/conda/lib/python3.9/site-packages (from mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (4.8.0)\n", - "Requirement already satisfied: boto3<1.29.0,>=1.28.0 in /opt/conda/lib/python3.9/site-packages (from mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.28.17)\n", - "Requirement already satisfied: dask~=2023.9.0 in /opt/conda/lib/python3.9/site-packages (from mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (2023.9.3)\n", - "Requirement already satisfied: databricks-sdk~=0.13.0 in /opt/conda/lib/python3.9/site-packages (from mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (0.13.0)\n", - "Requirement already satisfied: distributed~=2023.9.0 in /opt/conda/lib/python3.9/site-packages (from mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (2023.9.3)\n", - "Requirement already satisfied: gcsfs==2023.9.2 in /opt/conda/lib/python3.9/site-packages (from mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (2023.9.2)\n", - "Requirement already satisfied: google-cloud-bigquery[bqstorage,pandas]==3.14.1 in /opt/conda/lib/python3.9/site-packages (from mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (3.14.1)\n", - "Requirement already satisfied: graphviz~=0.20.0 in /opt/conda/lib/python3.9/site-packages (from mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (0.20.1)\n", - "Requirement already satisfied: kafka-python~=2.0 in /opt/conda/lib/python3.9/site-packages (from mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (2.0.2)\n", - "Requirement already satisfied: mlflow~=2.8 in /opt/conda/lib/python3.9/site-packages (from mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (2.10.2)\n", - "Requirement already satisfied: msrest~=0.6.21 in /opt/conda/lib/python3.9/site-packages (from mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (0.6.21)\n", - "Requirement already satisfied: plotly<5.12.0,~=5.4 in /opt/conda/lib/python3.9/site-packages (from mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (5.11.0)\n", - "Requirement already satisfied: pyopenssl>=23 in /opt/conda/lib/python3.9/site-packages (from mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (24.0.0)\n", - "Requirement already satisfied: redis~=4.3 in /opt/conda/lib/python3.9/site-packages (from mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (4.6.0)\n", - "Requirement already satisfied: s3fs==2023.9.2 in /opt/conda/lib/python3.9/site-packages (from mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (2023.9.2)\n", - "Requirement already satisfied: sqlalchemy~=1.4 in /opt/conda/lib/python3.9/site-packages (from mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.4.51)\n", - "Requirement already satisfied: azure-datalake-store<0.1,>=0.0.46 in /opt/conda/lib/python3.9/site-packages (from adlfs==2023.9.0->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (0.0.53)\n", - "Requirement already satisfied: azure-storage-blob>=12.12.0 in /opt/conda/lib/python3.9/site-packages (from adlfs==2023.9.0->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (12.19.0)\n", - "Requirement already satisfied: decorator>4.1.2 in /opt/conda/lib/python3.9/site-packages (from gcsfs==2023.9.2->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (5.1.1)\n", - "Requirement already satisfied: google-auth>=1.2 in /opt/conda/lib/python3.9/site-packages (from gcsfs==2023.9.2->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (2.28.1)\n", - "Requirement already satisfied: google-auth-oauthlib in /opt/conda/lib/python3.9/site-packages (from gcsfs==2023.9.2->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.2.0)\n", - "Requirement already satisfied: google-cloud-storage in /opt/conda/lib/python3.9/site-packages (from gcsfs==2023.9.2->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (2.14.0)\n", - "Requirement already satisfied: google-api-core!=2.0.*,!=2.1.*,!=2.2.*,!=2.3.0,<3.0.0dev,>=1.31.5 in /opt/conda/lib/python3.9/site-packages (from google-cloud-bigquery[bqstorage,pandas]==3.14.1->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (2.17.1)\n", - "Requirement already satisfied: google-cloud-core<3.0.0dev,>=1.6.0 in /opt/conda/lib/python3.9/site-packages (from google-cloud-bigquery[bqstorage,pandas]==3.14.1->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (2.4.1)\n", - "Requirement already satisfied: google-resumable-media<3.0dev,>=0.6.0 in /opt/conda/lib/python3.9/site-packages (from google-cloud-bigquery[bqstorage,pandas]==3.14.1->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (2.7.0)\n", - "Requirement already satisfied: packaging>=20.0.0 in /opt/conda/lib/python3.9/site-packages (from google-cloud-bigquery[bqstorage,pandas]==3.14.1->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (23.1)\n", - "Requirement already satisfied: python-dateutil<3.0dev,>=2.7.2 in /opt/conda/lib/python3.9/site-packages (from google-cloud-bigquery[bqstorage,pandas]==3.14.1->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (2.8.2)\n", - "Requirement already satisfied: db-dtypes<2.0.0dev,>=0.3.0 in /opt/conda/lib/python3.9/site-packages (from google-cloud-bigquery[bqstorage,pandas]==3.14.1->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.2.0)\n", - "Requirement already satisfied: google-cloud-bigquery-storage<3.0.0dev,>=2.6.0 in /opt/conda/lib/python3.9/site-packages (from google-cloud-bigquery[bqstorage,pandas]==3.14.1->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (2.24.0)\n", - "Requirement already satisfied: grpcio<2.0dev,>=1.47.0 in /opt/conda/lib/python3.9/site-packages (from google-cloud-bigquery[bqstorage,pandas]==3.14.1->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.62.0)\n", - "Requirement already satisfied: protobuf>=3.20.2 in /opt/conda/lib/python3.9/site-packages (from onnx~=1.14.1->-r /empty/requirements.txt (line 2)) (3.20.3)\n", - "Requirement already satisfied: typing-extensions>=3.6.2.1 in /opt/conda/lib/python3.9/site-packages (from onnx~=1.14.1->-r /empty/requirements.txt (line 2)) (4.10.0)\n", - "Collecting coloredlogs (from onnxruntime~=1.16.1->-r /empty/requirements.txt (line 3))\n", - " Obtaining dependency information for coloredlogs from https://files.pythonhosted.org/packages/a7/06/3d6badcf13db419e25b07041d9c7b4a2c331d3f4e7134445ec5df57714cd/coloredlogs-15.0.1-py2.py3-none-any.whl.metadata\n", - " Downloading coloredlogs-15.0.1-py2.py3-none-any.whl.metadata (12 kB)\n", - "Collecting flatbuffers (from onnxruntime~=1.16.1->-r /empty/requirements.txt (line 3))\n", - " Obtaining dependency information for flatbuffers from https://files.pythonhosted.org/packages/bf/45/c961e3cb6ddad76b325c163d730562bb6deb1ace5acbed0306f5fbefb90e/flatbuffers-24.3.7-py2.py3-none-any.whl.metadata\n", - " Downloading flatbuffers-24.3.7-py2.py3-none-any.whl.metadata (849 bytes)\n", - "Collecting sympy (from onnxruntime~=1.16.1->-r /empty/requirements.txt (line 3))\n", - " Obtaining dependency information for sympy from https://files.pythonhosted.org/packages/d2/05/e6600db80270777c4a64238a98d442f0fd07cc8915be2a1c16da7f2b9e74/sympy-1.12-py3-none-any.whl.metadata\n", - " Downloading sympy-1.12-py3-none-any.whl.metadata (12 kB)\n", - "Collecting transformers[sentencepiece]>=4.26.0 (from optimum~=1.6.4->-r /empty/requirements.txt (line 4))\n", - " Obtaining dependency information for transformers[sentencepiece]>=4.26.0 from https://files.pythonhosted.org/packages/0a/fd/280f4385e76f3c1890efc15fa93f7206134fefad6351397e1bfab6d0d0de/transformers-4.39.1-py3-none-any.whl.metadata\n", - " Downloading transformers-4.39.1-py3-none-any.whl.metadata (134 kB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 134.8/134.8 kB 40.1 MB/s eta 0:00:00\n", - "Collecting torch>=1.9 (from optimum~=1.6.4->-r /empty/requirements.txt (line 4))\n", - " Obtaining dependency information for torch>=1.9 from https://files.pythonhosted.org/packages/98/04/95a12556d068786d6505c609daf2805bed91c9210c5185499a7c121eba47/torch-2.2.1-cp39-cp39-manylinux1_x86_64.whl.metadata\n", - " Downloading torch-2.2.1-cp39-cp39-manylinux1_x86_64.whl.metadata (25 kB)\n", - "Collecting numpy<1.27.0,>=1.16.5 (from mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1))\n", - " Obtaining dependency information for numpy<1.27.0,>=1.16.5 from https://files.pythonhosted.org/packages/4c/b9/038abd6fbd67b05b03cb1af590cfc02b7f1e5a37af7ac6a868f5093c29f5/numpy-1.23.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata\n", - " Downloading numpy-1.23.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (2.3 kB)\n", - "Collecting huggingface-hub>=0.8.0 (from optimum~=1.6.4->-r /empty/requirements.txt (line 4))\n", - " Obtaining dependency information for huggingface-hub>=0.8.0 from https://files.pythonhosted.org/packages/ab/28/d4b691840d73126d4c9845f8a22dad033ac872509b6d3a0d93b456eef424/huggingface_hub-0.21.4-py3-none-any.whl.metadata\n", - " Downloading huggingface_hub-0.21.4-py3-none-any.whl.metadata (13 kB)\n", - "Collecting filelock (from transformers~=4.26.1->-r /empty/requirements.txt (line 5))\n", - " Obtaining dependency information for filelock from https://files.pythonhosted.org/packages/81/54/84d42a0bee35edba99dee7b59a8d4970eccdd44b99fe728ed912106fc781/filelock-3.13.1-py3-none-any.whl.metadata\n", - " Downloading filelock-3.13.1-py3-none-any.whl.metadata (2.8 kB)\n", - "Collecting regex!=2019.12.17 (from transformers~=4.26.1->-r /empty/requirements.txt (line 5))\n", - " Obtaining dependency information for regex!=2019.12.17 from https://files.pythonhosted.org/packages/05/9e/80c20f1151432a6025690c9c2037053039b028a7b236fa81d7e7ac9dec60/regex-2023.12.25-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata\n", - " Downloading regex-2023.12.25-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (40 kB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 40.9/40.9 kB 217.5 MB/s eta 0:00:00\n", - "Collecting tokenizers!=0.11.3,<0.14,>=0.11.1 (from transformers~=4.26.1->-r /empty/requirements.txt (line 5))\n", - " Obtaining dependency information for tokenizers!=0.11.3,<0.14,>=0.11.1 from https://files.pythonhosted.org/packages/d6/27/07a337087dd507170a1b20fed3bbf8da81401185a7130a6e74e440c52040/tokenizers-0.13.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata\n", - " Downloading tokenizers-0.13.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (6.7 kB)\n", - "Requirement already satisfied: tqdm>=4.27 in /opt/conda/lib/python3.9/site-packages (from transformers~=4.26.1->-r /empty/requirements.txt (line 5)) (4.65.0)\n", - "Collecting dill<0.3.7,>=0.3.0 (from datasets~=2.10.1->-r /empty/requirements.txt (line 6))\n", - " Obtaining dependency information for dill<0.3.7,>=0.3.0 from https://files.pythonhosted.org/packages/be/e3/a84bf2e561beed15813080d693b4b27573262433fced9c1d1fea59e60553/dill-0.3.6-py3-none-any.whl.metadata\n", - " Downloading dill-0.3.6-py3-none-any.whl.metadata (9.8 kB)\n", - "Requirement already satisfied: xxhash in /opt/conda/lib/python3.9/site-packages (from datasets~=2.10.1->-r /empty/requirements.txt (line 6)) (3.4.1)\n", - "Collecting multiprocess (from datasets~=2.10.1->-r /empty/requirements.txt (line 6))\n", - " Obtaining dependency information for multiprocess from https://files.pythonhosted.org/packages/da/d9/f7f9379981e39b8c2511c9e0326d212accacb82f12fbfdc1aa2ce2a7b2b6/multiprocess-0.70.16-py39-none-any.whl.metadata\n", - " Downloading multiprocess-0.70.16-py39-none-any.whl.metadata (7.2 kB)\n", - "Collecting responses<0.19 (from datasets~=2.10.1->-r /empty/requirements.txt (line 6))\n", - " Obtaining dependency information for responses<0.19 from https://files.pythonhosted.org/packages/79/f3/2b3a6dc5986303b3dd1bbbcf482022acb2583c428cd23f0b6d37b1a1a519/responses-0.18.0-py3-none-any.whl.metadata\n", - " Downloading responses-0.18.0-py3-none-any.whl.metadata (29 kB)\n", - "Requirement already satisfied: scipy>=1.1.0 in /opt/conda/lib/python3.9/site-packages (from scikit-learn~=1.0.2->-r /empty/requirements.txt (line 7)) (1.12.0)\n", - "Requirement already satisfied: joblib>=0.11 in /opt/conda/lib/python3.9/site-packages (from scikit-learn~=1.0.2->-r /empty/requirements.txt (line 7)) (1.3.2)\n", - "Requirement already satisfied: threadpoolctl>=2.0.0 in /opt/conda/lib/python3.9/site-packages (from scikit-learn~=1.0.2->-r /empty/requirements.txt (line 7)) (3.3.0)\n", - "Requirement already satisfied: botocore<1.31.18,>=1.31.17 in /opt/conda/lib/python3.9/site-packages (from aiobotocore<2.8,>=2.5.0->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.31.17)\n", - "Requirement already satisfied: wrapt<2.0.0,>=1.10.10 in /opt/conda/lib/python3.9/site-packages (from aiobotocore<2.8,>=2.5.0->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.16.0)\n", - "Requirement already satisfied: aioitertools<1.0.0,>=0.5.1 in /opt/conda/lib/python3.9/site-packages (from aiobotocore<2.8,>=2.5.0->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (0.11.0)\n", - "Requirement already satisfied: aiosignal>=1.1.2 in /opt/conda/lib/python3.9/site-packages (from aiohttp~=3.9->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.3.1)\n", - "Requirement already satisfied: attrs>=17.3.0 in /opt/conda/lib/python3.9/site-packages (from aiohttp~=3.9->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (23.2.0)\n", - "Requirement already satisfied: frozenlist>=1.1.1 in /opt/conda/lib/python3.9/site-packages (from aiohttp~=3.9->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.4.1)\n", - "Requirement already satisfied: multidict<7.0,>=4.5 in /opt/conda/lib/python3.9/site-packages (from aiohttp~=3.9->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (6.0.5)\n", - "Requirement already satisfied: yarl<2.0,>=1.0 in /opt/conda/lib/python3.9/site-packages (from aiohttp~=3.9->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.9.4)\n", - "Requirement already satisfied: async-timeout<5.0,>=4.0 in /opt/conda/lib/python3.9/site-packages (from aiohttp~=3.9->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (4.0.3)\n", - "Requirement already satisfied: idna>=2.8 in /opt/conda/lib/python3.9/site-packages (from anyio~=3.7->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (3.4)\n", - "Requirement already satisfied: sniffio>=1.1 in /opt/conda/lib/python3.9/site-packages (from anyio~=3.7->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.3.1)\n", - "Requirement already satisfied: exceptiongroup in /opt/conda/lib/python3.9/site-packages (from anyio~=3.7->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.2.0)\n", - "Requirement already satisfied: six>=1.11.0 in /opt/conda/lib/python3.9/site-packages (from azure-core~=1.24->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.16.0)\n", - "Requirement already satisfied: cryptography>=2.5 in /opt/conda/lib/python3.9/site-packages (from azure-identity~=1.5->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (42.0.2)\n", - "Requirement already satisfied: msal<2.0.0,>=1.24.0 in /opt/conda/lib/python3.9/site-packages (from azure-identity~=1.5->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.27.0)\n", - "Requirement already satisfied: msal-extensions<2.0.0,>=0.3.0 in /opt/conda/lib/python3.9/site-packages (from azure-identity~=1.5->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.1.0)\n", - "Requirement already satisfied: isodate>=0.6.1 in /opt/conda/lib/python3.9/site-packages (from azure-keyvault-secrets~=4.2->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (0.6.1)\n", - "Requirement already satisfied: jmespath<2.0.0,>=0.7.1 in /opt/conda/lib/python3.9/site-packages (from boto3<1.29.0,>=1.28.0->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.0.1)\n", - "Requirement already satisfied: s3transfer<0.7.0,>=0.6.0 in /opt/conda/lib/python3.9/site-packages (from boto3<1.29.0,>=1.28.0->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (0.6.2)\n", - "Requirement already satisfied: cloudpickle>=1.5.0 in /opt/conda/lib/python3.9/site-packages (from dask~=2023.9.0->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (2.2.1)\n", - "Requirement already satisfied: partd>=1.2.0 in /opt/conda/lib/python3.9/site-packages (from dask~=2023.9.0->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.4.1)\n", - "Requirement already satisfied: toolz>=0.10.0 in /opt/conda/lib/python3.9/site-packages (from dask~=2023.9.0->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (0.12.0)\n", - "Requirement already satisfied: importlib-metadata>=4.13.0 in /opt/conda/lib/python3.9/site-packages (from dask~=2023.9.0->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (7.0.1)\n", - "Requirement already satisfied: locket>=1.0.0 in /opt/conda/lib/python3.9/site-packages (from distributed~=2023.9.0->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.0.0)\n", - "Requirement already satisfied: msgpack>=1.0.0 in /opt/conda/lib/python3.9/site-packages (from distributed~=2023.9.0->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.0.7)\n", - "Requirement already satisfied: psutil>=5.7.2 in /opt/conda/lib/python3.9/site-packages (from distributed~=2023.9.0->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (5.9.8)\n", - "Requirement already satisfied: sortedcontainers>=2.0.5 in /opt/conda/lib/python3.9/site-packages (from distributed~=2023.9.0->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (2.4.0)\n", - "Requirement already satisfied: tblib>=1.6.0 in /opt/conda/lib/python3.9/site-packages (from distributed~=2023.9.0->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (3.0.0)\n", - "Requirement already satisfied: tornado>=6.0.4 in /opt/conda/lib/python3.9/site-packages (from distributed~=2023.9.0->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (6.4)\n", - "Requirement already satisfied: zict>=3.0.0 in /opt/conda/lib/python3.9/site-packages (from distributed~=2023.9.0->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (3.0.0)\n", - "Requirement already satisfied: gitdb<5,>=4.0.1 in /opt/conda/lib/python3.9/site-packages (from GitPython>=3.1.41,~=3.1->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (4.0.11)\n", - "Requirement already satisfied: jedi>=0.16 in /opt/conda/lib/python3.9/site-packages (from ipython~=8.10->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (0.19.1)\n", - "Requirement already satisfied: matplotlib-inline in /opt/conda/lib/python3.9/site-packages (from ipython~=8.10->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (0.1.6)\n", - "Requirement already satisfied: prompt-toolkit<3.1.0,>=3.0.41 in /opt/conda/lib/python3.9/site-packages (from ipython~=8.10->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (3.0.43)\n", - "Requirement already satisfied: pygments>=2.4.0 in /opt/conda/lib/python3.9/site-packages (from ipython~=8.10->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (2.17.2)\n", - "Requirement already satisfied: stack-data in /opt/conda/lib/python3.9/site-packages (from ipython~=8.10->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (0.6.3)\n", - "Requirement already satisfied: traitlets>=5 in /opt/conda/lib/python3.9/site-packages (from ipython~=8.10->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (5.14.1)\n", - "Requirement already satisfied: pexpect>4.3 in /opt/conda/lib/python3.9/site-packages (from ipython~=8.10->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (4.9.0)\n", - "Requirement already satisfied: MarkupSafe>=2.0 in /opt/conda/lib/python3.9/site-packages (from jinja2>=3.1.3,~=3.1->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (2.1.5)\n", - "Requirement already satisfied: absl-py<2,>=0.9 in /opt/conda/lib/python3.9/site-packages (from kfp~=1.8->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.4.0)\n", - "Requirement already satisfied: kubernetes<26,>=8.0.0 in /opt/conda/lib/python3.9/site-packages (from kfp~=1.8->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (25.3.0)\n", - "Requirement already satisfied: google-api-python-client<2,>=1.7.8 in /opt/conda/lib/python3.9/site-packages (from kfp~=1.8->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.12.11)\n", - "Requirement already satisfied: requests-toolbelt<1,>=0.8.0 in /opt/conda/lib/python3.9/site-packages (from kfp~=1.8->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (0.10.1)\n", - "Requirement already satisfied: kfp-server-api<2.0.0,>=1.1.2 in /opt/conda/lib/python3.9/site-packages (from kfp~=1.8->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.8.5)\n", - "Requirement already satisfied: jsonschema<5,>=3.0.1 in /opt/conda/lib/python3.9/site-packages (from kfp~=1.8->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (4.21.1)\n", - "Requirement already satisfied: strip-hints<1,>=0.1.8 in /opt/conda/lib/python3.9/site-packages (from kfp~=1.8->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (0.1.10)\n", - "Requirement already satisfied: docstring-parser<1,>=0.7.3 in /opt/conda/lib/python3.9/site-packages (from kfp~=1.8->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (0.15)\n", - "Requirement already satisfied: kfp-pipeline-spec<0.2.0,>=0.1.16 in /opt/conda/lib/python3.9/site-packages (from kfp~=1.8->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (0.1.16)\n", - "Requirement already satisfied: fire<1,>=0.3.1 in /opt/conda/lib/python3.9/site-packages (from kfp~=1.8->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (0.5.0)\n", - "Requirement already satisfied: uritemplate<4,>=3.0.1 in /opt/conda/lib/python3.9/site-packages (from kfp~=1.8->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (3.0.1)\n", - "Requirement already satisfied: typer<1.0,>=0.3.2 in /opt/conda/lib/python3.9/site-packages (from kfp~=1.8->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (0.9.0)\n", - "Requirement already satisfied: entrypoints<1 in /opt/conda/lib/python3.9/site-packages (from mlflow~=2.8->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (0.4)\n", - "Requirement already satisfied: pytz<2024 in /opt/conda/lib/python3.9/site-packages (from mlflow~=2.8->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (2023.4)\n", - "Requirement already satisfied: sqlparse<1,>=0.4.0 in /opt/conda/lib/python3.9/site-packages (from mlflow~=2.8->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (0.4.4)\n", - "Requirement already satisfied: alembic!=1.10.0,<2 in /opt/conda/lib/python3.9/site-packages (from mlflow~=2.8->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.13.1)\n", - "Requirement already satisfied: docker<8,>=4.0.0 in /opt/conda/lib/python3.9/site-packages (from mlflow~=2.8->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (7.0.0)\n", - "Requirement already satisfied: Flask<4 in /opt/conda/lib/python3.9/site-packages (from mlflow~=2.8->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (3.0.2)\n", - "Requirement already satisfied: querystring-parser<2 in /opt/conda/lib/python3.9/site-packages (from mlflow~=2.8->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.2.4)\n", - "Requirement already satisfied: markdown<4,>=3.3 in /opt/conda/lib/python3.9/site-packages (from mlflow~=2.8->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (3.5.2)\n", - "Requirement already satisfied: matplotlib<4 in /opt/conda/lib/python3.9/site-packages (from mlflow~=2.8->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (3.8.3)\n", - "Requirement already satisfied: gunicorn<22 in /opt/conda/lib/python3.9/site-packages (from mlflow~=2.8->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (21.2.0)\n", - "Requirement already satisfied: requests-oauthlib>=0.5.0 in /opt/conda/lib/python3.9/site-packages (from msrest~=0.6.21->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.3.1)\n", - "Requirement already satisfied: certifi>=2017.4.17 in /opt/conda/lib/python3.9/site-packages (from msrest~=0.6.21->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (2024.2.2)\n", - "Requirement already satisfied: nbconvert>=6.4.5 in /opt/conda/lib/python3.9/site-packages (from nuclio-jupyter~=0.9.15->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (7.16.1)\n", - "Requirement already satisfied: notebook<7.0.0,>=6.4 in /opt/conda/lib/python3.9/site-packages (from nuclio-jupyter~=0.9.15->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (6.5.6)\n", - "Requirement already satisfied: tzdata>=2022.1 in /opt/conda/lib/python3.9/site-packages (from pandas<2.2,>=1.2->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (2024.1)\n", - "Requirement already satisfied: tenacity>=6.2.0 in /opt/conda/lib/python3.9/site-packages (from plotly<5.12.0,~=5.4->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (8.2.3)\n", - "Requirement already satisfied: charset-normalizer<4,>=2 in /opt/conda/lib/python3.9/site-packages (from requests~=2.31->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (2.0.4)\n", - "Requirement already satisfied: greenlet!=0.4.17 in /opt/conda/lib/python3.9/site-packages (from sqlalchemy~=1.4->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (3.0.3)\n", - "Requirement already satisfied: nuclio-sdk>=0.5.3 in /opt/conda/lib/python3.9/site-packages (from storey~=1.6.18->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (0.5.9)\n", - "Collecting networkx (from torch>=1.9->optimum~=1.6.4->-r /empty/requirements.txt (line 4))\n", - " Obtaining dependency information for networkx from https://files.pythonhosted.org/packages/d5/f0/8fbc882ca80cf077f1b246c0e3c3465f7f415439bdea6b899f6b19f61f70/networkx-3.2.1-py3-none-any.whl.metadata\n", - " Downloading networkx-3.2.1-py3-none-any.whl.metadata (5.2 kB)\n", - "Collecting nvidia-cuda-nvrtc-cu12==12.1.105 (from torch>=1.9->optimum~=1.6.4->-r /empty/requirements.txt (line 4))\n", - " Obtaining dependency information for nvidia-cuda-nvrtc-cu12==12.1.105 from https://files.pythonhosted.org/packages/b6/9f/c64c03f49d6fbc56196664d05dba14e3a561038a81a638eeb47f4d4cfd48/nvidia_cuda_nvrtc_cu12-12.1.105-py3-none-manylinux1_x86_64.whl.metadata\n", - " Downloading nvidia_cuda_nvrtc_cu12-12.1.105-py3-none-manylinux1_x86_64.whl.metadata (1.5 kB)\n", - "Collecting nvidia-cuda-runtime-cu12==12.1.105 (from torch>=1.9->optimum~=1.6.4->-r /empty/requirements.txt (line 4))\n", - " Obtaining dependency information for nvidia-cuda-runtime-cu12==12.1.105 from https://files.pythonhosted.org/packages/eb/d5/c68b1d2cdfcc59e72e8a5949a37ddb22ae6cade80cd4a57a84d4c8b55472/nvidia_cuda_runtime_cu12-12.1.105-py3-none-manylinux1_x86_64.whl.metadata\n", - " Downloading nvidia_cuda_runtime_cu12-12.1.105-py3-none-manylinux1_x86_64.whl.metadata (1.5 kB)\n", - "Collecting nvidia-cuda-cupti-cu12==12.1.105 (from torch>=1.9->optimum~=1.6.4->-r /empty/requirements.txt (line 4))\n", - " Obtaining dependency information for nvidia-cuda-cupti-cu12==12.1.105 from https://files.pythonhosted.org/packages/7e/00/6b218edd739ecfc60524e585ba8e6b00554dd908de2c9c66c1af3e44e18d/nvidia_cuda_cupti_cu12-12.1.105-py3-none-manylinux1_x86_64.whl.metadata\n", - " Downloading nvidia_cuda_cupti_cu12-12.1.105-py3-none-manylinux1_x86_64.whl.metadata (1.6 kB)\n", - "Collecting nvidia-cudnn-cu12==8.9.2.26 (from torch>=1.9->optimum~=1.6.4->-r /empty/requirements.txt (line 4))\n", - " Obtaining dependency information for nvidia-cudnn-cu12==8.9.2.26 from https://files.pythonhosted.org/packages/ff/74/a2e2be7fb83aaedec84f391f082cf765dfb635e7caa9b49065f73e4835d8/nvidia_cudnn_cu12-8.9.2.26-py3-none-manylinux1_x86_64.whl.metadata\n", - " Downloading nvidia_cudnn_cu12-8.9.2.26-py3-none-manylinux1_x86_64.whl.metadata (1.6 kB)\n", - "Collecting nvidia-cublas-cu12==12.1.3.1 (from torch>=1.9->optimum~=1.6.4->-r /empty/requirements.txt (line 4))\n", - " Obtaining dependency information for nvidia-cublas-cu12==12.1.3.1 from https://files.pythonhosted.org/packages/37/6d/121efd7382d5b0284239f4ab1fc1590d86d34ed4a4a2fdb13b30ca8e5740/nvidia_cublas_cu12-12.1.3.1-py3-none-manylinux1_x86_64.whl.metadata\n", - " Downloading nvidia_cublas_cu12-12.1.3.1-py3-none-manylinux1_x86_64.whl.metadata (1.5 kB)\n", - "Collecting nvidia-cufft-cu12==11.0.2.54 (from torch>=1.9->optimum~=1.6.4->-r /empty/requirements.txt (line 4))\n", - " Obtaining dependency information for nvidia-cufft-cu12==11.0.2.54 from https://files.pythonhosted.org/packages/86/94/eb540db023ce1d162e7bea9f8f5aa781d57c65aed513c33ee9a5123ead4d/nvidia_cufft_cu12-11.0.2.54-py3-none-manylinux1_x86_64.whl.metadata\n", - " Downloading nvidia_cufft_cu12-11.0.2.54-py3-none-manylinux1_x86_64.whl.metadata (1.5 kB)\n", - "Collecting nvidia-curand-cu12==10.3.2.106 (from torch>=1.9->optimum~=1.6.4->-r /empty/requirements.txt (line 4))\n", - " Obtaining dependency information for nvidia-curand-cu12==10.3.2.106 from https://files.pythonhosted.org/packages/44/31/4890b1c9abc496303412947fc7dcea3d14861720642b49e8ceed89636705/nvidia_curand_cu12-10.3.2.106-py3-none-manylinux1_x86_64.whl.metadata\n", - " Downloading nvidia_curand_cu12-10.3.2.106-py3-none-manylinux1_x86_64.whl.metadata (1.5 kB)\n", - "Collecting nvidia-cusolver-cu12==11.4.5.107 (from torch>=1.9->optimum~=1.6.4->-r /empty/requirements.txt (line 4))\n", - " Obtaining dependency information for nvidia-cusolver-cu12==11.4.5.107 from https://files.pythonhosted.org/packages/bc/1d/8de1e5c67099015c834315e333911273a8c6aaba78923dd1d1e25fc5f217/nvidia_cusolver_cu12-11.4.5.107-py3-none-manylinux1_x86_64.whl.metadata\n", - " Downloading nvidia_cusolver_cu12-11.4.5.107-py3-none-manylinux1_x86_64.whl.metadata (1.6 kB)\n", - "Collecting nvidia-cusparse-cu12==12.1.0.106 (from torch>=1.9->optimum~=1.6.4->-r /empty/requirements.txt (line 4))\n", - " Obtaining dependency information for nvidia-cusparse-cu12==12.1.0.106 from https://files.pythonhosted.org/packages/65/5b/cfaeebf25cd9fdec14338ccb16f6b2c4c7fa9163aefcf057d86b9cc248bb/nvidia_cusparse_cu12-12.1.0.106-py3-none-manylinux1_x86_64.whl.metadata\n", - " Downloading nvidia_cusparse_cu12-12.1.0.106-py3-none-manylinux1_x86_64.whl.metadata (1.6 kB)\n", - "Collecting nvidia-nccl-cu12==2.19.3 (from torch>=1.9->optimum~=1.6.4->-r /empty/requirements.txt (line 4))\n", - " Obtaining dependency information for nvidia-nccl-cu12==2.19.3 from https://files.pythonhosted.org/packages/38/00/d0d4e48aef772ad5aebcf70b73028f88db6e5640b36c38e90445b7a57c45/nvidia_nccl_cu12-2.19.3-py3-none-manylinux1_x86_64.whl.metadata\n", - " Downloading nvidia_nccl_cu12-2.19.3-py3-none-manylinux1_x86_64.whl.metadata (1.8 kB)\n", - "Collecting nvidia-nvtx-cu12==12.1.105 (from torch>=1.9->optimum~=1.6.4->-r /empty/requirements.txt (line 4))\n", - " Obtaining dependency information for nvidia-nvtx-cu12==12.1.105 from https://files.pythonhosted.org/packages/da/d3/8057f0587683ed2fcd4dbfbdfdfa807b9160b809976099d36b8f60d08f03/nvidia_nvtx_cu12-12.1.105-py3-none-manylinux1_x86_64.whl.metadata\n", - " Downloading nvidia_nvtx_cu12-12.1.105-py3-none-manylinux1_x86_64.whl.metadata (1.7 kB)\n", - "Collecting triton==2.2.0 (from torch>=1.9->optimum~=1.6.4->-r /empty/requirements.txt (line 4))\n", - " Obtaining dependency information for triton==2.2.0 from https://files.pythonhosted.org/packages/6a/5c/01d9f062f719581cf6e60053e1a005d666ec67dcb59630fffaa3a3e5c9d8/triton-2.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata\n", - " Downloading triton-2.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (1.4 kB)\n", - "Collecting nvidia-nvjitlink-cu12 (from nvidia-cusolver-cu12==11.4.5.107->torch>=1.9->optimum~=1.6.4->-r /empty/requirements.txt (line 4))\n", - " Obtaining dependency information for nvidia-nvjitlink-cu12 from https://files.pythonhosted.org/packages/58/d1/d1c80553f9d5d07b6072bc132607d75a0ef3600e28e1890e11c0f55d7346/nvidia_nvjitlink_cu12-12.4.99-py3-none-manylinux2014_x86_64.whl.metadata\n", - " Downloading nvidia_nvjitlink_cu12-12.4.99-py3-none-manylinux2014_x86_64.whl.metadata (1.5 kB)\n", - "INFO: pip is looking at multiple versions of transformers[sentencepiece] to determine which version is compatible with other requirements. This could take a while.\n", - "Collecting transformers[sentencepiece]>=4.26.0 (from optimum~=1.6.4->-r /empty/requirements.txt (line 4))\n", - " Obtaining dependency information for transformers[sentencepiece]>=4.26.0 from https://files.pythonhosted.org/packages/a4/73/f620d76193954e16db3d5c53a07d956d7b9c800e570758d3bff91906d4a4/transformers-4.39.0-py3-none-any.whl.metadata\n", - " Downloading transformers-4.39.0-py3-none-any.whl.metadata (134 kB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 134.8/134.8 kB 115.9 MB/s eta 0:00:00\n", - " Obtaining dependency information for transformers[sentencepiece]>=4.26.0 from https://files.pythonhosted.org/packages/b6/4d/fbe6d89fde59d8107f0a02816c4ac4542a8f9a85559fdf33c68282affcc1/transformers-4.38.2-py3-none-any.whl.metadata\n", - " Downloading transformers-4.38.2-py3-none-any.whl.metadata (130 kB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 130.7/130.7 kB 126.3 MB/s eta 0:00:00\n", - " Obtaining dependency information for transformers[sentencepiece]>=4.26.0 from https://files.pythonhosted.org/packages/3e/6b/1b589f7b69aaea8193cf5bc91cf97410284aecd97b6312cdb08baedbdffe/transformers-4.38.1-py3-none-any.whl.metadata\n", - " Downloading transformers-4.38.1-py3-none-any.whl.metadata (131 kB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 131.1/131.1 kB 138.2 MB/s eta 0:00:00\n", - " Obtaining dependency information for transformers[sentencepiece]>=4.26.0 from https://files.pythonhosted.org/packages/91/89/5416dc364c7ef0711c564fd61a69b03d1e40eeb5c506c38e53ba8a969e79/transformers-4.38.0-py3-none-any.whl.metadata\n", - " Downloading transformers-4.38.0-py3-none-any.whl.metadata (131 kB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 131.1/131.1 kB 186.3 MB/s eta 0:00:00\n", - " Obtaining dependency information for transformers[sentencepiece]>=4.26.0 from https://files.pythonhosted.org/packages/85/f6/c5065913119c41ecad148c34e3a861f719e16b89a522287213698da911fc/transformers-4.37.2-py3-none-any.whl.metadata\n", - " Downloading transformers-4.37.2-py3-none-any.whl.metadata (129 kB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 129.4/129.4 kB 236.8 MB/s eta 0:00:00\n", - " Obtaining dependency information for transformers[sentencepiece]>=4.26.0 from https://files.pythonhosted.org/packages/ad/67/b4d6a51dcaf988cb45b31e26c6e33fb169fe34ba5fb168b086309bd7c028/transformers-4.37.1-py3-none-any.whl.metadata\n", - " Downloading transformers-4.37.1-py3-none-any.whl.metadata (129 kB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 129.4/129.4 kB 156.4 MB/s eta 0:00:00\n", - " Obtaining dependency information for transformers[sentencepiece]>=4.26.0 from https://files.pythonhosted.org/packages/3c/45/52133ce6bce49a099cc865599803bf1fad93de887276f728e56848d77a70/transformers-4.37.0-py3-none-any.whl.metadata\n", - " Downloading transformers-4.37.0-py3-none-any.whl.metadata (129 kB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 129.4/129.4 kB 102.0 MB/s eta 0:00:00\n", - "INFO: pip is still looking at multiple versions of transformers[sentencepiece] to determine which version is compatible with other requirements. This could take a while.\n", - " Obtaining dependency information for transformers[sentencepiece]>=4.26.0 from https://files.pythonhosted.org/packages/20/0a/739426a81f7635b422fbe6cb8d1d99d1235579a6ac8024c13d743efa6847/transformers-4.36.2-py3-none-any.whl.metadata\n", - " Downloading transformers-4.36.2-py3-none-any.whl.metadata (126 kB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 126.8/126.8 kB 108.8 MB/s eta 0:00:00\n", - " Obtaining dependency information for transformers[sentencepiece]>=4.26.0 from https://files.pythonhosted.org/packages/fc/04/0aad491cd98b09236c54ab849863ee85421eeda5138bbf9d33ecc594652b/transformers-4.36.1-py3-none-any.whl.metadata\n", - " Downloading transformers-4.36.1-py3-none-any.whl.metadata (126 kB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 126.8/126.8 kB 140.6 MB/s eta 0:00:00\n", - " Obtaining dependency information for transformers[sentencepiece]>=4.26.0 from https://files.pythonhosted.org/packages/0f/12/d8e27a190ca67811f81deea3183b528d9169f10b74d827e0b9211520ecfa/transformers-4.36.0-py3-none-any.whl.metadata\n", - " Downloading transformers-4.36.0-py3-none-any.whl.metadata (126 kB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 126.8/126.8 kB 267.8 MB/s eta 0:00:00\n", - " Obtaining dependency information for transformers[sentencepiece]>=4.26.0 from https://files.pythonhosted.org/packages/12/dd/f17b11a93a9ca27728e12512d167eb1281c151c4c6881d3ab59eb58f4127/transformers-4.35.2-py3-none-any.whl.metadata\n", - " Downloading transformers-4.35.2-py3-none-any.whl.metadata (123 kB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 123.5/123.5 kB 130.2 MB/s eta 0:00:00\n", - " Obtaining dependency information for transformers[sentencepiece]>=4.26.0 from https://files.pythonhosted.org/packages/92/ba/cfff7e01f7070d9fca3964bf42b2257b86964c3e6763b8d5435436cc1d77/transformers-4.35.1-py3-none-any.whl.metadata\n", - " Downloading transformers-4.35.1-py3-none-any.whl.metadata (123 kB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 123.1/123.1 kB 183.6 MB/s eta 0:00:00\n", - "INFO: This is taking longer than usual. You might need to provide the dependency resolver with stricter constraints to reduce runtime. See https://pip.pypa.io/warnings/backtracking for guidance. If you want to abort this run, press Ctrl + C.\n", - " Obtaining dependency information for transformers[sentencepiece]>=4.26.0 from https://files.pythonhosted.org/packages/9a/06/e4ec2a321e57c03b7e9345d709d554a52c33760e5015fdff0919d9459af0/transformers-4.35.0-py3-none-any.whl.metadata\n", - " Downloading transformers-4.35.0-py3-none-any.whl.metadata (123 kB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 123.1/123.1 kB 177.3 MB/s eta 0:00:00\n", - " Obtaining dependency information for transformers[sentencepiece]>=4.26.0 from https://files.pythonhosted.org/packages/c1/bd/f64d67df4d3b05a460f281defe830ffab6d7940b7ca98ec085e94e024781/transformers-4.34.1-py3-none-any.whl.metadata\n", - " Downloading transformers-4.34.1-py3-none-any.whl.metadata (121 kB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 121.5/121.5 kB 270.5 MB/s eta 0:00:00\n", - " Obtaining dependency information for transformers[sentencepiece]>=4.26.0 from https://files.pythonhosted.org/packages/1a/d1/3bba59606141ae808017f6fde91453882f931957f125009417b87a281067/transformers-4.34.0-py3-none-any.whl.metadata\n", - " Downloading transformers-4.34.0-py3-none-any.whl.metadata (121 kB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 121.5/121.5 kB 133.4 MB/s eta 0:00:00\n", - " Obtaining dependency information for transformers[sentencepiece]>=4.26.0 from https://files.pythonhosted.org/packages/98/46/f6a79f944d5c7763a9bc13b2aa6ac72daf43a6551f5fb03bccf0a9c2fec1/transformers-4.33.3-py3-none-any.whl.metadata\n", - " Downloading transformers-4.33.3-py3-none-any.whl.metadata (119 kB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 119.9/119.9 kB 163.1 MB/s eta 0:00:00\n", - " Obtaining dependency information for transformers[sentencepiece]>=4.26.0 from https://files.pythonhosted.org/packages/1a/06/3817f9bb923437ead9a794f0ac0d03b8b5e0478ab112db4c413dd37c09da/transformers-4.33.2-py3-none-any.whl.metadata\n", - " Downloading transformers-4.33.2-py3-none-any.whl.metadata (119 kB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 119.9/119.9 kB 274.9 MB/s eta 0:00:00\n", - " Obtaining dependency information for transformers[sentencepiece]>=4.26.0 from https://files.pythonhosted.org/packages/13/30/54b59e73400df3de506ad8630284e9fd63f4b94f735423d55fc342181037/transformers-4.33.1-py3-none-any.whl.metadata\n", - " Downloading transformers-4.33.1-py3-none-any.whl.metadata (119 kB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 119.9/119.9 kB 274.2 MB/s eta 0:00:00\n", - " Obtaining dependency information for transformers[sentencepiece]>=4.26.0 from https://files.pythonhosted.org/packages/e1/9d/4d9fe5c3b820db10773392ac5f4a0c8dab668f70b245ce2ce09785166128/transformers-4.33.0-py3-none-any.whl.metadata\n", - " Downloading transformers-4.33.0-py3-none-any.whl.metadata (119 kB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 119.9/119.9 kB 185.9 MB/s eta 0:00:00\n", - " Obtaining dependency information for transformers[sentencepiece]>=4.26.0 from https://files.pythonhosted.org/packages/83/8d/f65f8138365462ace54458a9e164f4b28ce1141361970190eef36bdef986/transformers-4.32.1-py3-none-any.whl.metadata\n", - " Downloading transformers-4.32.1-py3-none-any.whl.metadata (118 kB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 118.5/118.5 kB 144.4 MB/s eta 0:00:00\n", - " Obtaining dependency information for transformers[sentencepiece]>=4.26.0 from https://files.pythonhosted.org/packages/ae/95/283a1c004430bd2a9425d6937fc545dd49a4e4592feb76be0299a14e2378/transformers-4.32.0-py3-none-any.whl.metadata\n", - " Downloading transformers-4.32.0-py3-none-any.whl.metadata (118 kB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 118.5/118.5 kB 150.3 MB/s eta 0:00:00\n", - " Obtaining dependency information for transformers[sentencepiece]>=4.26.0 from https://files.pythonhosted.org/packages/21/02/ae8e595f45b6c8edee07913892b3b41f5f5f273962ad98851dc6a564bbb9/transformers-4.31.0-py3-none-any.whl.metadata\n", - " Downloading transformers-4.31.0-py3-none-any.whl.metadata (116 kB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 116.9/116.9 kB 156.7 MB/s eta 0:00:00\n", - " Obtaining dependency information for transformers[sentencepiece]>=4.26.0 from https://files.pythonhosted.org/packages/5b/0b/e45d26ccd28568013523e04f325432ea88a442b4e3020b757cf4361f0120/transformers-4.30.2-py3-none-any.whl.metadata\n", - " Downloading transformers-4.30.2-py3-none-any.whl.metadata (113 kB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 113.6/113.6 kB 263.7 MB/s eta 0:00:00\n", - " Obtaining dependency information for transformers[sentencepiece]>=4.26.0 from https://files.pythonhosted.org/packages/b8/df/b01b5e67cde3883757c9212455cbb9169385dcab5858b7172199126b756d/transformers-4.30.1-py3-none-any.whl.metadata\n", - " Downloading transformers-4.30.1-py3-none-any.whl.metadata (113 kB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 113.6/113.6 kB 263.8 MB/s eta 0:00:00\n", - " Obtaining dependency information for transformers[sentencepiece]>=4.26.0 from https://files.pythonhosted.org/packages/e2/72/1af3d38e98fdcceb3876de4567ac395a66c26976e259fe2d46266e052d61/transformers-4.30.0-py3-none-any.whl.metadata\n", - " Downloading transformers-4.30.0-py3-none-any.whl.metadata (113 kB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 113.6/113.6 kB 266.5 MB/s eta 0:00:00\n", - " Obtaining dependency information for transformers[sentencepiece]>=4.26.0 from https://files.pythonhosted.org/packages/17/aa/a89864288afe45abe1ab79f002140a20348140e86836d96096d8f8a3bac0/transformers-4.29.2-py3-none-any.whl.metadata\n", - " Downloading transformers-4.29.2-py3-none-any.whl.metadata (112 kB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 112.3/112.3 kB 272.7 MB/s eta 0:00:00\n", - " Obtaining dependency information for transformers[sentencepiece]>=4.26.0 from https://files.pythonhosted.org/packages/e8/b5/ddb16f9de207e6571ab7cc5db0cc538fa2d6d91cf024565496462af4c1ce/transformers-4.29.1-py3-none-any.whl.metadata\n", - " Downloading transformers-4.29.1-py3-none-any.whl.metadata (112 kB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 112.3/112.3 kB 262.3 MB/s eta 0:00:00\n", - " Obtaining dependency information for transformers[sentencepiece]>=4.26.0 from https://files.pythonhosted.org/packages/45/e4/4914b11df70954d95a7c36b74bf9010c8594fcec960471479449b0deb4f7/transformers-4.29.0-py3-none-any.whl.metadata\n", - " Downloading transformers-4.29.0-py3-none-any.whl.metadata (111 kB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 111.9/111.9 kB 269.5 MB/s eta 0:00:00\n", - " Obtaining dependency information for transformers[sentencepiece]>=4.26.0 from https://files.pythonhosted.org/packages/d8/a7/a6ff727fd5d96d6625f4658944a2ae230f0c75743a9a117fbda013b03d3d/transformers-4.28.1-py3-none-any.whl.metadata\n", - " Downloading transformers-4.28.1-py3-none-any.whl.metadata (109 kB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 110.0/110.0 kB 245.6 MB/s eta 0:00:00\n", - " Obtaining dependency information for transformers[sentencepiece]>=4.26.0 from https://files.pythonhosted.org/packages/8b/13/1ce598763b3669d43f192a7911bf2bf730a328012ab8801b93187a4f70d0/transformers-4.28.0-py3-none-any.whl.metadata\n", - " Downloading transformers-4.28.0-py3-none-any.whl.metadata (109 kB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 110.0/110.0 kB 256.3 MB/s eta 0:00:00\n", - " Obtaining dependency information for transformers[sentencepiece]>=4.26.0 from https://files.pythonhosted.org/packages/87/f0/2a152ed10ab8601431e87a606d397f7473c5fa4f8162f4ec5bda6ddb2df4/transformers-4.27.4-py3-none-any.whl.metadata\n", - " Downloading transformers-4.27.4-py3-none-any.whl.metadata (106 kB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 106.7/106.7 kB 254.4 MB/s eta 0:00:00\n", - " Obtaining dependency information for transformers[sentencepiece]>=4.26.0 from https://files.pythonhosted.org/packages/52/ac/9dc5a17ba60bc354d99250d9d1629f99d76f6729cee438fa91c8cc74bc5d/transformers-4.27.3-py3-none-any.whl.metadata\n", - " Downloading transformers-4.27.3-py3-none-any.whl.metadata (106 kB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 106.7/106.7 kB 251.5 MB/s eta 0:00:00\n", - " Obtaining dependency information for transformers[sentencepiece]>=4.26.0 from https://files.pythonhosted.org/packages/73/f0/4a795505387a3e7cd7f0c2a2a87f876658f9a07947a38fb67bffceff9246/transformers-4.27.2-py3-none-any.whl.metadata\n", - " Downloading transformers-4.27.2-py3-none-any.whl.metadata (106 kB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 106.7/106.7 kB 246.1 MB/s eta 0:00:00\n", - " Obtaining dependency information for transformers[sentencepiece]>=4.26.0 from https://files.pythonhosted.org/packages/6d/9b/2f536f9e73390209e0b27b74691355dac494b7ec8154f3012fdc6debbae7/transformers-4.27.1-py3-none-any.whl.metadata\n", - " Downloading transformers-4.27.1-py3-none-any.whl.metadata (106 kB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 106.7/106.7 kB 114.0 MB/s eta 0:00:00\n", - " Obtaining dependency information for transformers[sentencepiece]>=4.26.0 from https://files.pythonhosted.org/packages/4d/3e/1378ed266cf991f5ab5fcb29e953d97d793c7f9242ea5dc52f856415ea3a/transformers-4.27.0-py3-none-any.whl.metadata\n", - " Downloading transformers-4.27.0-py3-none-any.whl.metadata (106 kB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 106.7/106.7 kB 247.2 MB/s eta 0:00:00\n", - "Collecting sentencepiece!=0.1.92,>=0.1.91 (from transformers~=4.26.1->-r /empty/requirements.txt (line 5))\n", - " Obtaining dependency information for sentencepiece!=0.1.92,>=0.1.91 from https://files.pythonhosted.org/packages/5f/01/c95e42eb86282b2c79305d3e0b0ca5a743f85a61262bb7130999c70b9374/sentencepiece-0.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata\n", - " Downloading sentencepiece-0.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (7.7 kB)\n", - "Collecting protobuf>=3.20.2 (from onnx~=1.14.1->-r /empty/requirements.txt (line 2))\n", - " Obtaining dependency information for protobuf>=3.20.2 from https://files.pythonhosted.org/packages/38/b1/d9b615dceb67ac38e13cbd7680c27182b40154996022cbb244ba1ac7d30f/protobuf-3.20.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl.metadata\n", - " Downloading protobuf-3.20.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl.metadata (679 bytes)\n", - "Requirement already satisfied: future>=0.18.2 in /opt/conda/lib/python3.9/site-packages (from v3io~=0.5.21->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.0.0)\n", - "Requirement already satisfied: ujson>=3 in /opt/conda/lib/python3.9/site-packages (from v3io~=0.5.21->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (5.9.0)\n", - "Requirement already satisfied: googleapis-common-protos>=1.5.3 in /opt/conda/lib/python3.9/site-packages (from v3io-frames~=0.10.12->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.62.0)\n", - "Requirement already satisfied: grpcio-tools!=1.34.0,<1.49,>=1.30 in /opt/conda/lib/python3.9/site-packages (from v3io-frames~=0.10.12->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.48.2)\n", - "Collecting humanfriendly>=9.1 (from coloredlogs->onnxruntime~=1.16.1->-r /empty/requirements.txt (line 3))\n", - " Obtaining dependency information for humanfriendly>=9.1 from https://files.pythonhosted.org/packages/f0/0f/310fb31e39e2d734ccaa2c0fb981ee41f7bd5056ce9bc29b2248bd569169/humanfriendly-10.0-py2.py3-none-any.whl.metadata\n", - " Downloading humanfriendly-10.0-py2.py3-none-any.whl.metadata (9.2 kB)\n", - "INFO: pip is looking at multiple versions of multiprocess to determine which version is compatible with other requirements. This could take a while.\n", - "Collecting multiprocess (from datasets~=2.10.1->-r /empty/requirements.txt (line 6))\n", - " Obtaining dependency information for multiprocess from https://files.pythonhosted.org/packages/c6/c9/820b5ab056f4ada76fbe05bd481a948f287957d6cbfd59e2dd2618b408c1/multiprocess-0.70.15-py39-none-any.whl.metadata\n", - " Downloading multiprocess-0.70.15-py39-none-any.whl.metadata (7.2 kB)\n", - " Obtaining dependency information for multiprocess from https://files.pythonhosted.org/packages/6a/f4/fbeb03ef7abdda54db4a6a75c971b88ab73d724ff09e3275cc1e99f1c946/multiprocess-0.70.14-py39-none-any.whl.metadata\n", - " Downloading multiprocess-0.70.14-py39-none-any.whl.metadata (6.6 kB)\n", - "Collecting mpmath>=0.19 (from sympy->onnxruntime~=1.16.1->-r /empty/requirements.txt (line 3))\n", - " Obtaining dependency information for mpmath>=0.19 from https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl.metadata\n", - " Downloading mpmath-1.3.0-py3-none-any.whl.metadata (8.6 kB)\n", - "Requirement already satisfied: Mako in /opt/conda/lib/python3.9/site-packages (from alembic!=1.10.0,<2->mlflow~=2.8->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.3.2)\n", - "Requirement already satisfied: cffi in /opt/conda/lib/python3.9/site-packages (from azure-datalake-store<0.1,>=0.0.46->adlfs==2023.9.0->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.16.0)\n", - "Requirement already satisfied: termcolor in /opt/conda/lib/python3.9/site-packages (from fire<1,>=0.3.1->kfp~=1.8->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (2.4.0)\n", - "Requirement already satisfied: Werkzeug>=3.0.0 in /opt/conda/lib/python3.9/site-packages (from Flask<4->mlflow~=2.8->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (3.0.1)\n", - "Requirement already satisfied: itsdangerous>=2.1.2 in /opt/conda/lib/python3.9/site-packages (from Flask<4->mlflow~=2.8->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (2.1.2)\n", - "Requirement already satisfied: blinker>=1.6.2 in /opt/conda/lib/python3.9/site-packages (from Flask<4->mlflow~=2.8->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.7.0)\n", - "Requirement already satisfied: smmap<6,>=3.0.1 in /opt/conda/lib/python3.9/site-packages (from gitdb<5,>=4.0.1->GitPython>=3.1.41,~=3.1->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (5.0.1)\n", - "Requirement already satisfied: httplib2<1dev,>=0.15.0 in /opt/conda/lib/python3.9/site-packages (from google-api-python-client<2,>=1.7.8->kfp~=1.8->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (0.22.0)\n", - "Requirement already satisfied: google-auth-httplib2>=0.0.3 in /opt/conda/lib/python3.9/site-packages (from google-api-python-client<2,>=1.7.8->kfp~=1.8->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (0.2.0)\n", - "Requirement already satisfied: cachetools<6.0,>=2.0.0 in /opt/conda/lib/python3.9/site-packages (from google-auth>=1.2->gcsfs==2023.9.2->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (5.3.3)\n", - "Requirement already satisfied: pyasn1-modules>=0.2.1 in /opt/conda/lib/python3.9/site-packages (from google-auth>=1.2->gcsfs==2023.9.2->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (0.3.0)\n", - "Requirement already satisfied: rsa<5,>=3.1.4 in /opt/conda/lib/python3.9/site-packages (from google-auth>=1.2->gcsfs==2023.9.2->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (4.9)\n", - "Requirement already satisfied: proto-plus<2.0.0dev,>=1.22.0 in /opt/conda/lib/python3.9/site-packages (from google-cloud-bigquery-storage<3.0.0dev,>=2.6.0->google-cloud-bigquery[bqstorage,pandas]==3.14.1->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.23.0)\n", - "Requirement already satisfied: google-crc32c<2.0dev,>=1.0 in /opt/conda/lib/python3.9/site-packages (from google-cloud-storage->gcsfs==2023.9.2->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.5.0)\n", - "Requirement already satisfied: zipp>=0.5 in /opt/conda/lib/python3.9/site-packages (from importlib-metadata>=4.13.0->dask~=2023.9.0->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (3.17.0)\n", - "Requirement already satisfied: parso<0.9.0,>=0.8.3 in /opt/conda/lib/python3.9/site-packages (from jedi>=0.16->ipython~=8.10->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (0.8.3)\n", - "Requirement already satisfied: jsonschema-specifications>=2023.03.6 in /opt/conda/lib/python3.9/site-packages (from jsonschema<5,>=3.0.1->kfp~=1.8->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (2023.12.1)\n", - "Requirement already satisfied: referencing>=0.28.4 in /opt/conda/lib/python3.9/site-packages (from jsonschema<5,>=3.0.1->kfp~=1.8->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (0.33.0)\n", - "Requirement already satisfied: rpds-py>=0.7.1 in /opt/conda/lib/python3.9/site-packages (from jsonschema<5,>=3.0.1->kfp~=1.8->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (0.18.0)\n", - "Requirement already satisfied: websocket-client!=0.40.0,!=0.41.*,!=0.42.*,>=0.32.0 in /opt/conda/lib/python3.9/site-packages (from kubernetes<26,>=8.0.0->kfp~=1.8->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.7.0)\n", - "Requirement already satisfied: contourpy>=1.0.1 in /opt/conda/lib/python3.9/site-packages (from matplotlib<4->mlflow~=2.8->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.2.0)\n", - "Requirement already satisfied: cycler>=0.10 in /opt/conda/lib/python3.9/site-packages (from matplotlib<4->mlflow~=2.8->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (0.12.1)\n", - "Requirement already satisfied: fonttools>=4.22.0 in /opt/conda/lib/python3.9/site-packages (from matplotlib<4->mlflow~=2.8->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (4.49.0)\n", - "Requirement already satisfied: kiwisolver>=1.3.1 in /opt/conda/lib/python3.9/site-packages (from matplotlib<4->mlflow~=2.8->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.4.5)\n", - "Requirement already satisfied: pillow>=8 in /opt/conda/lib/python3.9/site-packages (from matplotlib<4->mlflow~=2.8->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (10.2.0)\n", - "Requirement already satisfied: pyparsing>=2.3.1 in /opt/conda/lib/python3.9/site-packages (from matplotlib<4->mlflow~=2.8->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (3.1.1)\n", - "Requirement already satisfied: importlib-resources>=3.2.0 in /opt/conda/lib/python3.9/site-packages (from matplotlib<4->mlflow~=2.8->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (6.1.2)\n", - "Requirement already satisfied: PyJWT[crypto]<3,>=1.0.0 in /opt/conda/lib/python3.9/site-packages (from msal<2.0.0,>=1.24.0->azure-identity~=1.5->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (2.8.0)\n", - "Requirement already satisfied: portalocker<3,>=1.0 in /opt/conda/lib/python3.9/site-packages (from msal-extensions<2.0.0,>=0.3.0->azure-identity~=1.5->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (2.8.2)\n", - "Requirement already satisfied: beautifulsoup4 in /opt/conda/lib/python3.9/site-packages (from nbconvert>=6.4.5->nuclio-jupyter~=0.9.15->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (4.12.3)\n", - "Requirement already satisfied: bleach!=5.0.0 in /opt/conda/lib/python3.9/site-packages (from nbconvert>=6.4.5->nuclio-jupyter~=0.9.15->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (6.1.0)\n", - "Requirement already satisfied: defusedxml in /opt/conda/lib/python3.9/site-packages (from nbconvert>=6.4.5->nuclio-jupyter~=0.9.15->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (0.7.1)\n", - "Requirement already satisfied: jupyter-core>=4.7 in /opt/conda/lib/python3.9/site-packages (from nbconvert>=6.4.5->nuclio-jupyter~=0.9.15->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (5.7.1)\n", - "Requirement already satisfied: jupyterlab-pygments in /opt/conda/lib/python3.9/site-packages (from nbconvert>=6.4.5->nuclio-jupyter~=0.9.15->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (0.3.0)\n", - "Requirement already satisfied: mistune<4,>=2.0.3 in /opt/conda/lib/python3.9/site-packages (from nbconvert>=6.4.5->nuclio-jupyter~=0.9.15->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (3.0.2)\n", - "Requirement already satisfied: nbclient>=0.5.0 in /opt/conda/lib/python3.9/site-packages (from nbconvert>=6.4.5->nuclio-jupyter~=0.9.15->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (0.9.0)\n", - "Requirement already satisfied: nbformat>=5.7 in /opt/conda/lib/python3.9/site-packages (from nbconvert>=6.4.5->nuclio-jupyter~=0.9.15->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (5.9.2)\n", - "Requirement already satisfied: pandocfilters>=1.4.1 in /opt/conda/lib/python3.9/site-packages (from nbconvert>=6.4.5->nuclio-jupyter~=0.9.15->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.5.1)\n", - "Requirement already satisfied: tinycss2 in /opt/conda/lib/python3.9/site-packages (from nbconvert>=6.4.5->nuclio-jupyter~=0.9.15->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.2.1)\n", - "Requirement already satisfied: pyzmq<25,>=17 in /opt/conda/lib/python3.9/site-packages (from notebook<7.0.0,>=6.4->nuclio-jupyter~=0.9.15->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (24.0.1)\n", - "Requirement already satisfied: argon2-cffi in /opt/conda/lib/python3.9/site-packages (from notebook<7.0.0,>=6.4->nuclio-jupyter~=0.9.15->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (23.1.0)\n", - "Requirement already satisfied: jupyter-client<8,>=5.3.4 in /opt/conda/lib/python3.9/site-packages (from notebook<7.0.0,>=6.4->nuclio-jupyter~=0.9.15->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (7.4.9)\n", - "Requirement already satisfied: ipython-genutils in /opt/conda/lib/python3.9/site-packages (from notebook<7.0.0,>=6.4->nuclio-jupyter~=0.9.15->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (0.2.0)\n", - "Requirement already satisfied: ipykernel in /opt/conda/lib/python3.9/site-packages (from notebook<7.0.0,>=6.4->nuclio-jupyter~=0.9.15->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (6.29.3)\n", - "Requirement already satisfied: Send2Trash>=1.8.0 in /opt/conda/lib/python3.9/site-packages (from notebook<7.0.0,>=6.4->nuclio-jupyter~=0.9.15->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.8.2)\n", - "Requirement already satisfied: terminado>=0.8.3 in /opt/conda/lib/python3.9/site-packages (from notebook<7.0.0,>=6.4->nuclio-jupyter~=0.9.15->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (0.18.0)\n", - "Requirement already satisfied: prometheus-client in /opt/conda/lib/python3.9/site-packages (from notebook<7.0.0,>=6.4->nuclio-jupyter~=0.9.15->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (0.20.0)\n", - "Requirement already satisfied: nbclassic>=0.4.7 in /opt/conda/lib/python3.9/site-packages (from notebook<7.0.0,>=6.4->nuclio-jupyter~=0.9.15->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.0.0)\n", - "Requirement already satisfied: ptyprocess>=0.5 in /opt/conda/lib/python3.9/site-packages (from pexpect>4.3->ipython~=8.10->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (0.7.0)\n", - "Requirement already satisfied: wcwidth in /opt/conda/lib/python3.9/site-packages (from prompt-toolkit<3.1.0,>=3.0.41->ipython~=8.10->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (0.2.13)\n", - "Requirement already satisfied: oauthlib>=3.0.0 in /opt/conda/lib/python3.9/site-packages (from requests-oauthlib>=0.5.0->msrest~=0.6.21->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (3.2.2)\n", - "Requirement already satisfied: wheel in /opt/conda/lib/python3.9/site-packages (from strip-hints<1,>=0.1.8->kfp~=1.8->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (0.41.2)\n", - "Requirement already satisfied: executing>=1.2.0 in /opt/conda/lib/python3.9/site-packages (from stack-data->ipython~=8.10->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (2.0.1)\n", - "Requirement already satisfied: asttokens>=2.1.0 in /opt/conda/lib/python3.9/site-packages (from stack-data->ipython~=8.10->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (2.4.1)\n", - "Requirement already satisfied: pure-eval in /opt/conda/lib/python3.9/site-packages (from stack-data->ipython~=8.10->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (0.2.2)\n", - "Requirement already satisfied: webencodings in /opt/conda/lib/python3.9/site-packages (from bleach!=5.0.0->nbconvert>=6.4.5->nuclio-jupyter~=0.9.15->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (0.5.1)\n", - "Requirement already satisfied: pycparser in /opt/conda/lib/python3.9/site-packages (from cffi->azure-datalake-store<0.1,>=0.0.46->adlfs==2023.9.0->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (2.21)\n", - "Requirement already satisfied: grpcio-status<2.0.dev0,>=1.33.2 in /opt/conda/lib/python3.9/site-packages (from google-api-core!=2.0.*,!=2.1.*,!=2.2.*,!=2.3.0,<3.0.0dev,>=1.31.5->google-cloud-bigquery[bqstorage,pandas]==3.14.1->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.48.2)\n", - "Requirement already satisfied: platformdirs>=2.5 in /opt/conda/lib/python3.9/site-packages (from jupyter-core>=4.7->nbconvert>=6.4.5->nuclio-jupyter~=0.9.15->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (3.10.0)\n", - "Requirement already satisfied: jupyter-server>=1.8 in /opt/conda/lib/python3.9/site-packages (from nbclassic>=0.4.7->notebook<7.0.0,>=6.4->nuclio-jupyter~=0.9.15->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (2.12.5)\n", - "Requirement already satisfied: notebook-shim>=0.2.3 in /opt/conda/lib/python3.9/site-packages (from nbclassic>=0.4.7->notebook<7.0.0,>=6.4->nuclio-jupyter~=0.9.15->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (0.2.4)\n", - "Requirement already satisfied: fastjsonschema in /opt/conda/lib/python3.9/site-packages (from nbformat>=5.7->nbconvert>=6.4.5->nuclio-jupyter~=0.9.15->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (2.19.1)\n", - "Requirement already satisfied: pyasn1<0.6.0,>=0.4.6 in /opt/conda/lib/python3.9/site-packages (from pyasn1-modules>=0.2.1->google-auth>=1.2->gcsfs==2023.9.2->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (0.5.1)\n", - "Requirement already satisfied: argon2-cffi-bindings in /opt/conda/lib/python3.9/site-packages (from argon2-cffi->notebook<7.0.0,>=6.4->nuclio-jupyter~=0.9.15->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (21.2.0)\n", - "Requirement already satisfied: soupsieve>1.2 in /opt/conda/lib/python3.9/site-packages (from beautifulsoup4->nbconvert>=6.4.5->nuclio-jupyter~=0.9.15->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (2.5)\n", - "Requirement already satisfied: comm>=0.1.1 in /opt/conda/lib/python3.9/site-packages (from ipykernel->notebook<7.0.0,>=6.4->nuclio-jupyter~=0.9.15->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (0.2.1)\n", - "Requirement already satisfied: debugpy>=1.6.5 in /opt/conda/lib/python3.9/site-packages (from ipykernel->notebook<7.0.0,>=6.4->nuclio-jupyter~=0.9.15->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.8.1)\n", - "Requirement already satisfied: jupyter-events>=0.9.0 in /opt/conda/lib/python3.9/site-packages (from jupyter-server>=1.8->nbclassic>=0.4.7->notebook<7.0.0,>=6.4->nuclio-jupyter~=0.9.15->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (0.9.0)\n", - "Requirement already satisfied: jupyter-server-terminals in /opt/conda/lib/python3.9/site-packages (from jupyter-server>=1.8->nbclassic>=0.4.7->notebook<7.0.0,>=6.4->nuclio-jupyter~=0.9.15->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (0.5.2)\n", - "Requirement already satisfied: overrides in /opt/conda/lib/python3.9/site-packages (from jupyter-server>=1.8->nbclassic>=0.4.7->notebook<7.0.0,>=6.4->nuclio-jupyter~=0.9.15->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (7.7.0)\n", - "Requirement already satisfied: python-json-logger>=2.0.4 in /opt/conda/lib/python3.9/site-packages (from jupyter-events>=0.9.0->jupyter-server>=1.8->nbclassic>=0.4.7->notebook<7.0.0,>=6.4->nuclio-jupyter~=0.9.15->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (2.0.7)\n", - "Requirement already satisfied: rfc3339-validator in /opt/conda/lib/python3.9/site-packages (from jupyter-events>=0.9.0->jupyter-server>=1.8->nbclassic>=0.4.7->notebook<7.0.0,>=6.4->nuclio-jupyter~=0.9.15->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (0.1.4)\n", - "Requirement already satisfied: rfc3986-validator>=0.1.1 in /opt/conda/lib/python3.9/site-packages (from jupyter-events>=0.9.0->jupyter-server>=1.8->nbclassic>=0.4.7->notebook<7.0.0,>=6.4->nuclio-jupyter~=0.9.15->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (0.1.1)\n", - "Requirement already satisfied: fqdn in /opt/conda/lib/python3.9/site-packages (from jsonschema<5,>=3.0.1->kfp~=1.8->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.5.1)\n", - "Requirement already satisfied: isoduration in /opt/conda/lib/python3.9/site-packages (from jsonschema<5,>=3.0.1->kfp~=1.8->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (20.11.0)\n", - "Requirement already satisfied: jsonpointer>1.13 in /opt/conda/lib/python3.9/site-packages (from jsonschema<5,>=3.0.1->kfp~=1.8->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (2.1)\n", - "Requirement already satisfied: uri-template in /opt/conda/lib/python3.9/site-packages (from jsonschema<5,>=3.0.1->kfp~=1.8->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.3.0)\n", - "Requirement already satisfied: webcolors>=1.11 in /opt/conda/lib/python3.9/site-packages (from jsonschema<5,>=3.0.1->kfp~=1.8->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.13)\n", - "Requirement already satisfied: arrow>=0.15.0 in /opt/conda/lib/python3.9/site-packages (from isoduration->jsonschema<5,>=3.0.1->kfp~=1.8->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (1.3.0)\n", - "Requirement already satisfied: types-python-dateutil>=2.8.10 in /opt/conda/lib/python3.9/site-packages (from arrow>=0.15.0->isoduration->jsonschema<5,>=3.0.1->kfp~=1.8->mlrun[complete]==1.6.1->-r /empty/requirements.txt (line 1)) (2.8.19.20240106)\n", - "Downloading onnx-1.14.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (14.6 MB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 14.6/14.6 MB 274.2 MB/s eta 0:00:00\n", - "Downloading onnxruntime-1.16.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (6.4 MB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 6.4/6.4 MB 277.9 MB/s eta 0:00:00\n", - "Downloading optimum-1.6.4-py3-none-any.whl (227 kB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 227.8/227.8 kB 291.3 MB/s eta 0:00:00\n", - "Downloading transformers-4.26.1-py3-none-any.whl (6.3 MB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 6.3/6.3 MB 242.4 MB/s eta 0:00:00\n", - "Downloading datasets-2.10.1-py3-none-any.whl (469 kB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 469.0/469.0 kB 185.9 MB/s eta 0:00:00\n", - "Downloading scikit_learn-1.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (26.4 MB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 26.4/26.4 MB 275.9 MB/s eta 0:00:00\n", - "Downloading dill-0.3.6-py3-none-any.whl (110 kB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 110.5/110.5 kB 282.3 MB/s eta 0:00:00\n", - "Downloading huggingface_hub-0.21.4-py3-none-any.whl (346 kB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 346.4/346.4 kB 311.7 MB/s eta 0:00:00\n", - "Downloading numpy-1.23.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (17.1 MB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 17.1/17.1 MB 269.6 MB/s eta 0:00:00\n", - "Downloading regex-2023.12.25-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (773 kB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 773.4/773.4 kB 311.9 MB/s eta 0:00:00\n", - "Downloading responses-0.18.0-py3-none-any.whl (38 kB)\n", - "Downloading tokenizers-0.13.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (7.8 MB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 7.8/7.8 MB 264.1 MB/s eta 0:00:00\n", - "Downloading torch-2.2.1-cp39-cp39-manylinux1_x86_64.whl (755.5 MB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 755.5/755.5 MB 204.0 MB/s eta 0:00:00\n", - "Downloading nvidia_cublas_cu12-12.1.3.1-py3-none-manylinux1_x86_64.whl (410.6 MB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 410.6/410.6 MB 40.3 MB/s eta 0:00:00\n", - "Downloading nvidia_cuda_cupti_cu12-12.1.105-py3-none-manylinux1_x86_64.whl (14.1 MB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 14.1/14.1 MB 43.0 MB/s eta 0:00:00\n", - "Downloading nvidia_cuda_nvrtc_cu12-12.1.105-py3-none-manylinux1_x86_64.whl (23.7 MB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 23.7/23.7 MB 46.9 MB/s eta 0:00:00\n", - "Downloading nvidia_cuda_runtime_cu12-12.1.105-py3-none-manylinux1_x86_64.whl (823 kB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 823.6/823.6 kB 51.0 MB/s eta 0:00:00\n", - "Downloading nvidia_cudnn_cu12-8.9.2.26-py3-none-manylinux1_x86_64.whl (731.7 MB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 731.7/731.7 MB 58.2 MB/s eta 0:00:00\n", - "Downloading nvidia_cufft_cu12-11.0.2.54-py3-none-manylinux1_x86_64.whl (121.6 MB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 121.6/121.6 MB 69.0 MB/s eta 0:00:00\n", - "Downloading nvidia_curand_cu12-10.3.2.106-py3-none-manylinux1_x86_64.whl (56.5 MB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 56.5/56.5 MB 36.0 MB/s eta 0:00:00\n", - "Downloading nvidia_cusolver_cu12-11.4.5.107-py3-none-manylinux1_x86_64.whl (124.2 MB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 124.2/124.2 MB 52.8 MB/s eta 0:00:00\n", - "Downloading nvidia_cusparse_cu12-12.1.0.106-py3-none-manylinux1_x86_64.whl (196.0 MB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 196.0/196.0 MB 45.9 MB/s eta 0:00:00\n", - "Downloading nvidia_nccl_cu12-2.19.3-py3-none-manylinux1_x86_64.whl (166.0 MB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 166.0/166.0 MB 19.6 MB/s eta 0:00:00\n", - "Downloading nvidia_nvtx_cu12-12.1.105-py3-none-manylinux1_x86_64.whl (99 kB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 99.1/99.1 kB 27.7 MB/s eta 0:00:00\n", - "Downloading triton-2.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (167.9 MB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 167.9/167.9 MB 41.3 MB/s eta 0:00:00\n", - "Downloading protobuf-3.20.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl (1.0 MB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.0/1.0 MB 42.8 MB/s eta 0:00:00\n", - "Downloading coloredlogs-15.0.1-py2.py3-none-any.whl (46 kB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 46.0/46.0 kB 192.0 MB/s eta 0:00:00\n", - "Downloading filelock-3.13.1-py3-none-any.whl (11 kB)\n", - "Downloading flatbuffers-24.3.7-py2.py3-none-any.whl (26 kB)\n", - "Downloading multiprocess-0.70.14-py39-none-any.whl (132 kB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 132.9/132.9 kB 100.7 MB/s eta 0:00:00\n", - "Downloading sympy-1.12-py3-none-any.whl (5.7 MB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 5.7/5.7 MB 41.4 MB/s eta 0:00:00\n", - "Downloading humanfriendly-10.0-py2.py3-none-any.whl (86 kB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 86.8/86.8 kB 253.7 MB/s eta 0:00:00\n", - "Downloading mpmath-1.3.0-py3-none-any.whl (536 kB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 536.2/536.2 kB 45.4 MB/s eta 0:00:00\n", - "Downloading sentencepiece-0.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.3 MB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.3/1.3 MB 46.1 MB/s eta 0:00:00\n", - "Downloading networkx-3.2.1-py3-none-any.whl (1.6 MB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.6/1.6 MB 43.7 MB/s eta 0:00:00\n", - "Downloading nvidia_nvjitlink_cu12-12.4.99-py3-none-manylinux2014_x86_64.whl (21.1 MB)\n", - " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 21.1/21.1 MB 43.8 MB/s eta 0:00:00\n", - "Installing collected packages: tokenizers, sentencepiece, mpmath, flatbuffers, sympy, regex, protobuf, nvidia-nvtx-cu12, nvidia-nvjitlink-cu12, nvidia-nccl-cu12, nvidia-curand-cu12, nvidia-cufft-cu12, nvidia-cuda-runtime-cu12, nvidia-cuda-nvrtc-cu12, nvidia-cuda-cupti-cu12, nvidia-cublas-cu12, numpy, networkx, humanfriendly, filelock, dill, triton, responses, onnx, nvidia-cusparse-cu12, nvidia-cudnn-cu12, multiprocess, huggingface-hub, coloredlogs, transformers, scikit-learn, onnxruntime, nvidia-cusolver-cu12, torch, datasets, optimum\n", - " Attempting uninstall: protobuf\n", - " Found existing installation: protobuf 3.20.3\n", - " Uninstalling protobuf-3.20.3:\n", - " Successfully uninstalled protobuf-3.20.3\n", - " Attempting uninstall: numpy\n", - " Found existing installation: numpy 1.26.4\n", - " Uninstalling numpy-1.26.4:\n", - " Successfully uninstalled numpy-1.26.4\n", - " Attempting uninstall: scikit-learn\n", - " Found existing installation: scikit-learn 1.4.1.post1\n", - " Uninstalling scikit-learn-1.4.1.post1:\n", - " Successfully uninstalled scikit-learn-1.4.1.post1\n", - "Successfully installed coloredlogs-15.0.1 datasets-2.10.1 dill-0.3.6 filelock-3.13.1 flatbuffers-24.3.7 huggingface-hub-0.21.4 humanfriendly-10.0 mpmath-1.3.0 multiprocess-0.70.14 networkx-3.2.1 numpy-1.23.5 nvidia-cublas-cu12-12.1.3.1 nvidia-cuda-cupti-cu12-12.1.105 nvidia-cuda-nvrtc-cu12-12.1.105 nvidia-cuda-runtime-cu12-12.1.105 nvidia-cudnn-cu12-8.9.2.26 nvidia-cufft-cu12-11.0.2.54 nvidia-curand-cu12-10.3.2.106 nvidia-cusolver-cu12-11.4.5.107 nvidia-cusparse-cu12-12.1.0.106 nvidia-nccl-cu12-2.19.3 nvidia-nvjitlink-cu12-12.4.99 nvidia-nvtx-cu12-12.1.105 onnx-1.14.1 onnxruntime-1.16.3 optimum-1.6.4 protobuf-3.20.2 regex-2023.12.25 responses-0.18.0 scikit-learn-1.0.2 sentencepiece-0.2.0 sympy-1.12 tokenizers-0.13.3 torch-2.2.1 transformers-4.26.1 triton-2.2.0\n", - "WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv\n", - "\u001b[36mINFO\u001b[0m[0238] Taking snapshot of full filesystem... \n", - "\u001b[36mINFO\u001b[0m[0463] Pushing image to docker-registry.default-tenant.app.app-lab-2-b688.iguazio-cd2.com/mlrun/func-hugging-face-trainer-avia-hugging-face-classifier-trainer:latest \n", - "\u001b[36mINFO\u001b[0m[0493] Pushed docker-registry.default-tenant.app.app-lab-2-b688.iguazio-cd2.com/mlrun/func-hugging-face-trainer-avia-hugging-face-classifier-trainer@sha256:691d0bb3c23487b4b5d2f84ab323c24735626ee81681475f53a4158b72d4cfee \n" - ] - }, - { - "data": { - "text/plain": [ - "BuildStatus(ready=True, outputs={'image': '.mlrun/func-hugging-face-trainer-avia-hugging-face-classifier-trainer:latest'})" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "project.build_function(\"hugging-face-classifier-trainer\",with_mlrun=True)" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": { - "scrolled": true, - "tags": [] - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "> 2024-03-24 17:22:42,252 [info] Storing function: {'name': 'hugging-face-classifier-trainer-train', 'uid': '53252ce7aacb4b1aacf86bf3b862daa2', 'db': 'http://mlrun-api:8080'}\n", - "> 2024-03-24 17:22:42,536 [info] Job is running in the background, pod: hugging-face-classifier-trainer-train-dqqfr\n", - "> 2024-03-24 17:24:43,288 [info] 'train_test_split_size' is not provided, setting train_test_split_size to 0.2\n", - "> 2024-03-24 17:24:43,847 [info] Loading and editing Shayanvsf/US_Airline_Sentiment dataset from Hugging Face hub\n", - "Downloading metadata: 100%|██████████| 1.03k/1.03k [00:00<00:00, 6.77MB/s]\n", - "Downloading and preparing dataset None/None (download: 265.13 KiB, generated: 1.50 MiB, post-processed: Unknown size, total: 1.76 MiB) to /root/.cache/huggingface/datasets/Shayanvsf___parquet/Shayanvsf--US_Airline_Sentiment-1319c42f87c44b2f/0.0.0/2a3b91fbd88a2c90d1dbbb32b460cf621d31bd5b05b934492fdef7d8d6f236ec...\n", - "Downloading data files: 0%| | 0/3 [00:00 2024-03-24 17:24:47,076 [info] training 'huggingface-model'\n", - "The following columns in the training set don't have a corresponding argument in `DistilBertForSequenceClassification.forward` and have been ignored: text. If text are not expected by `DistilBertForSequenceClassification.forward`, you can safely ignore this message.\n", - "This implementation of AdamW is deprecated and will be removed in a future version. Use the PyTorch implementation torch.optim.AdamW instead, or set `no_deprecation_warning=True` to disable this warning\n", - "***** Running training *****\n", - " Num examples = 100\n", - " Num Epochs = 3\n", - " Instantaneous batch size per device = 16\n", - " Total train batch size (w. parallel, distributed & accumulation) = 16\n", - " Gradient Accumulation steps = 1\n", - " Total optimization steps = 21\n", - " Number of trainable parameters = 66955010\n", - "huggingface/tokenizers: The current process just got forked, after parallelism has already been used. Disabling parallelism to avoid deadlocks...\n", - "To disable this warning, you can either:\n", - "\t- Avoid using `tokenizers` before the fork if possible\n", - "\t- Explicitly set the environment variable TOKENIZERS_PARALLELISM=(true | false)\n", - " 0%| | 0/21 [00:00 2024-03-24 17:26:00,230 [info] To track results use the CLI: {'info_cmd': 'mlrun get run 53252ce7aacb4b1aacf86bf3b862daa2 -p hugging-face-trainer-avia', 'logs_cmd': 'mlrun logs 53252ce7aacb4b1aacf86bf3b862daa2 -p hugging-face-trainer-avia'}\n", - "> 2024-03-24 17:26:00,231 [info] Or click for UI: {'ui_url': 'https://dashboard.default-tenant.app.app-lab-2-b688.iguazio-cd2.com/mlprojects/hugging-face-trainer-avia/jobs/monitor/53252ce7aacb4b1aacf86bf3b862daa2/overview'}\n", - "> 2024-03-24 17:26:00,231 [info] Run execution finished: {'status': 'completed', 'name': 'hugging-face-classifier-trainer-train'}\n" - ] - }, - { - "data": { - "text/html": [ - "\n", - "
\n", - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
projectuiditerstartstatenamelabelsinputsparametersresultsartifacts
hugging-face-trainer-avia0Mar 24 17:24:39completedhugging-face-classifier-trainer-train
v3io_user=avia
kind=job
owner=avia
mlrun/client_version=1.6.1
mlrun/client_python_version=3.9.16
host=hugging-face-classifier-trainer-train-dqqfr
hf_dataset=Shayanvsf/US_Airline_Sentiment
drop_columns=['airline_sentiment_confidence', 'negativereason_confidence']
pretrained_tokenizer=distilbert-base-uncased
pretrained_model=distilbert-base-uncased
model_class=transformers.AutoModelForSequenceClassification
label_name=airline_sentiment
num_of_train_samples=100
metrics=['accuracy', 'f1']
random_state=42
TRAIN_output_dir=finetuning-sentiment-model-3000-samples
TRAIN_learning_rate=2e-05
TRAIN_per_device_train_batch_size=16
TRAIN_per_device_eval_batch_size=16
TRAIN_num_train_epochs=3
TRAIN_weight_decay=0.01
TRAIN_push_to_hub=False
TRAIN_evaluation_strategy=epoch
TRAIN_eval_steps=1
TRAIN_logging_steps=1
CLASS_num_labels=2
loss=0.5215
learning_rate=0.0
eval_loss=0.4750453531742096
eval_accuracy=0.7916666666666666
eval_f1=0.0
eval_runtime=1.0524
eval_samples_per_second=22.806
eval_steps_per_second=1.9
train_runtime=55.1543
train_samples_per_second=5.439
train_steps_per_second=0.381
total_flos=3327208489680.0
loss_plot
learning_rate_plot
eval_loss_plot
eval_accuracy_plot
eval_f1_plot
eval_runtime_plot
eval_samples_per_second_plot
eval_steps_per_second_plot
tokenizer
model
\n", - "
\n", - "
\n", - "
\n", - " Title\n", - " ×\n", - "
\n", - " \n", - "
\n", - "
\n" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n" - ] - }, - { - "data": { - "text/html": [ - " > to track results use the .show() or .logs() methods or click here to open in UI" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "> 2024-03-24 17:26:09,792 [info] Run execution finished: {'status': 'completed', 'name': 'hugging-face-classifier-trainer-train'}\n" - ] - } - ], - "source": [ - "train_run = hugging_face_classifier_trainer.run(params={\n", - " \"hf_dataset\": \"Shayanvsf/US_Airline_Sentiment\",\n", - " \"drop_columns\": [\n", - " \"airline_sentiment_confidence\",\n", - " \"negativereason_confidence\",\n", - " ],\n", - " \"pretrained_tokenizer\": \"distilbert-base-uncased\",\n", - " \"pretrained_model\": \"distilbert-base-uncased\",\n", - " \"model_class\": \"transformers.AutoModelForSequenceClassification\",\n", - " \"label_name\": \"airline_sentiment\",\n", - " \"num_of_train_samples\": 100,\n", - " \"metrics\": [\"accuracy\", \"f1\"],\n", - " \"random_state\": 42,\n", - " **additional_parameters\n", - " },\n", - " handler=\"train\", \n", - " )" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, - "source": [ - "[Back to the top](#top)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "mlrun-base", - "language": "python", - "name": "conda-env-mlrun-base-py" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.9.16" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/hugging_face_classifier_trainer/hugging_face_classifier_trainer.py b/hugging_face_classifier_trainer/hugging_face_classifier_trainer.py deleted file mode 100755 index 29d070395..000000000 --- a/hugging_face_classifier_trainer/hugging_face_classifier_trainer.py +++ /dev/null @@ -1,832 +0,0 @@ -import os -import shutil -import tempfile -import zipfile -from abc import ABC -from typing import Any, Callable, Dict, List, Optional, Tuple, Union - -import mlrun -import mlrun.datastore -import mlrun.utils -import numpy as np -import pandas as pd -import transformers -from datasets import Dataset, load_dataset, load_metric -from mlrun import MLClientCtx -from mlrun import feature_store as fs -from mlrun.artifacts import Artifact, PlotlyArtifact -from mlrun.datastore import DataItem -from mlrun.frameworks._common import CommonTypes, MLRunInterface -from mlrun.utils import create_class -from plotly import graph_objects as go -from sklearn.model_selection import train_test_split -from transformers import ( - AutoTokenizer, - DataCollatorWithPadding, - EvalPrediction, - PreTrainedModel, - PreTrainedTokenizer, - Trainer, - TrainerCallback, - TrainerControl, - TrainerState, - TrainingArguments, -) - - -# ----------------------from MLRUN-------------------------------- -class HFORTOptimizerMLRunInterface(MLRunInterface, ABC): - """ - Interface for adding MLRun features for tensorflow keras API. - """ - - # MLRun's context default name: - DEFAULT_CONTEXT_NAME = "mlrun-huggingface" - - # Attributes to be inserted so the MLRun interface will be fully enabled. - _PROPERTIES = { - "_auto_log": False, - "_context": None, - "_model_name": "model", - "_tag": "", - "_labels": None, - "_extra_data": None, - } - _METHODS = ["enable_auto_logging"] - # Attributes to replace so the MLRun interface will be fully enabled. - _REPLACED_METHODS = [ - "optimize", - ] - - @classmethod - def add_interface( - cls, - obj, - restoration: CommonTypes.MLRunInterfaceRestorationType = None, - ): - """ - Enrich the object with this interface properties, methods and functions, so it will have this TensorFlow.Keras - MLRun's features. - :param obj: The object to enrich his interface. - :param restoration: Restoration information tuple as returned from 'remove_interface' in order to - add the interface in a certain state. - """ - super(HFORTOptimizerMLRunInterface, cls).add_interface( - obj=obj, restoration=restoration - ) - - @classmethod - def mlrun_optimize(cls): - """ - MLRun's tf.keras.Model.fit wrapper. It will setup the optimizer when using horovod. The optimizer must be - passed in a keyword argument and when using horovod, it must be passed as an Optimizer instance, not a string. - - raise MLRunInvalidArgumentError: In case the optimizer provided did not follow the instructions above. - """ - - def wrapper(self, *args, **kwargs): - save_dir = cls._get_function_argument( - self.optimize, - argument_name="save_dir", - passed_args=args, - passed_kwargs=kwargs, - )[0] - - # Call the original optimize method: - result = self.original_optimize(*args, **kwargs) - - if self._auto_log: - # Log the onnx model: - self._context.log_model( - key="model", - db_key=self._model_name, - model_file=f"{save_dir}/model_optimized.onnx", - tag=self._tag, - framework="ONNX", - labels=self._labels, - extra_data=self._extra_data, - ) - - return result - - return wrapper - - def enable_auto_logging( - self, - context: mlrun.MLClientCtx, - model_name: str = "model", - tag: str = "", - labels: Dict[str, str] = None, - extra_data: dict = None, - ): - self._auto_log = True - - self._context = context - self._model_name = model_name - self._tag = tag - self._labels = labels - self._extra_data = extra_data - - -class HFTrainerMLRunInterface(MLRunInterface, ABC): - """ - Interface for adding MLRun features for tensorflow keras API. - """ - - # MLRuns context default name: - DEFAULT_CONTEXT_NAME = "mlrun-huggingface" - - # Attributes to replace so the MLRun interface will be fully enabled. - _REPLACED_METHODS = [ - "train", - # "evaluate" - ] - - @classmethod - def add_interface( - cls, - obj: Trainer, - restoration: CommonTypes.MLRunInterfaceRestorationType = None, - ): - """ - Enrich the object with this interface properties, methods and functions, so it will have this TensorFlow.Keras - MLRuns features. - :param obj: The object to enrich his interface. - :param restoration: Restoration information tuple as returned from 'remove_interface' in order to - add the interface in a certain state. - """ - - super(HFTrainerMLRunInterface, cls).add_interface( - obj=obj, restoration=restoration - ) - - @classmethod - def mlrun_train(cls): - - """ - MLRuns tf.keras.Model.fit wrapper. It will setup the optimizer when using horovod. The optimizer must be - passed in a keyword argument and when using horovod, it must be passed as an Optimizer instance, not a string. - - raise MLRunInvalidArgumentError: In case the optimizer provided did not follow the instructions above. - """ - - def wrapper(self: Trainer, *args, **kwargs): - # Restore the evaluation method as `train` will use it: - # cls._restore_attribute(obj=self, attribute_name="evaluate") - - # Call the original fit method: - result = self.original_train(*args, **kwargs) - - # Replace the evaluation method again: - # cls._replace_function(obj=self, function_name="evaluate") - - return result - - return wrapper - - -class MLRunCallback(TrainerCallback): - """ - Callback for collecting logs during training / evaluation of the `Trainer` API. - """ - - def __init__( - self, - context: mlrun.MLClientCtx = None, - model_name: str = "model", - tag: str = "", - labels: Dict[str, str] = None, - extra_data: dict = None, - ): - super().__init__() - - # Store the configurations: - self._context = ( - context - if context is not None - else mlrun.get_or_create_ctx("./mlrun-huggingface") - ) - self._model_name = model_name - self._tag = tag - self._labels = labels - self._extra_data = extra_data if extra_data is not None else {} - - # Set up the logging mode: - self._is_training = False - self._steps: List[List[int]] = [] - self._metric_scores: Dict[str, List[float]] = {} - self._artifacts: Dict[str, Artifact] = {} - - def on_epoch_begin( - self, - args: TrainingArguments, - state: TrainerState, - control: TrainerControl, - **kwargs, - ): - self._steps.append([]) - - def on_epoch_end( - self, - args: TrainingArguments, - state: TrainerState, - control: TrainerControl, - **kwargs, - ): - self._log_metrics() - - def on_log( - self, - args: TrainingArguments, - state: TrainerState, - control: TrainerControl, - logs: Dict[str, float] = None, - **kwargs, - ): - recent_logs = state.log_history[-1].copy() - - recent_logs.pop("epoch") - current_step = int(recent_logs.pop("step")) - if current_step not in self._steps[-1]: - self._steps[-1].append(current_step) - - for metric_name, metric_score in recent_logs.items(): - if metric_name.startswith("train_"): - if metric_name.split("train_")[1] not in self._metric_scores: - self._metric_scores[metric_name] = [metric_score] - continue - if metric_name not in self._metric_scores: - self._metric_scores[metric_name] = [] - self._metric_scores[metric_name].append(metric_score) - - def on_train_begin( - self, - args: TrainingArguments, - state: TrainerState, - control: TrainerControl, - **kwargs, - ): - self._is_training = True - - def on_train_end( - self, - args: TrainingArguments, - state: TrainerState, - control: TrainerControl, - model: PreTrainedModel = None, - tokenizer: PreTrainedTokenizer = None, - **kwargs, - ): - self._log_metrics() - - temp_directory = tempfile.gettempdir() - - # Save and log the tokenizer: - if tokenizer is not None: - # Save tokenizer: - tokenizer_dir = os.path.join(temp_directory, "tokenizer") - tokenizer.save_pretrained(save_directory=tokenizer_dir) - # Zip the tokenizer directory: - tokenizer_zip = shutil.make_archive( - base_name="tokenizer", - format="zip", - root_dir=tokenizer_dir, - ) - # Log the zip file: - self._artifacts["tokenizer"] = self._context.log_artifact( - item="tokenizer", local_path=tokenizer_zip - ) - - # Save the model: - model_dir = os.path.join(temp_directory, "model") - model.save_pretrained(save_directory=model_dir) - - # Zip the model directory: - shutil.make_archive( - base_name="model", - format="zip", - root_dir=model_dir, - ) - - # Log the model: - self._context.log_model( - key="model", - db_key=self._model_name, - model_file="model.zip", - tag=self._tag, - framework="Hugging Face", - labels=self._labels, - extra_data={**self._artifacts, **self._extra_data}, - ) - - def on_evaluate( - self, - args: TrainingArguments, - state: TrainerState, - control: TrainerControl, - **kwargs, - ): - self._log_metrics() - - if self._is_training: - return - - # TODO: Update the model object - - def _log_metrics(self): - for metric_name, metric_scores in self._metric_scores.items(): - self._context.log_result(key=metric_name, value=metric_scores[-1]) - if len(metric_scores) > 1: - self._log_metric_plot(name=metric_name, scores=metric_scores) - self._context.commit(completed=False) - - def _log_metric_plot(self, name: str, scores: List[float]): - # Initialize a plotly figure: - metric_figure = go.Figure() - - # Add titles: - metric_figure.update_layout( - title=name.capitalize().replace("_", " "), - xaxis_title="Samples", - yaxis_title="Scores", - ) - - # Draw: - metric_figure.add_trace( - go.Scatter(x=np.arange(len(scores)), y=scores, mode="lines") - ) - - # Create the plotly artifact: - artifact_name = f"{name}_plot" - artifact = PlotlyArtifact(key=artifact_name, figure=metric_figure) - self._artifacts[artifact_name] = self._context.log_artifact(artifact) - - -def _apply_mlrun_on_trainer( - trainer: transformers.Trainer, - model_name: str = None, - tag: str = "", - context: mlrun.MLClientCtx = None, - auto_log: bool = True, - labels: Dict[str, str] = None, - extra_data: dict = None, - **kwargs, -): - # Get parameters defaults: - if context is None: - context = mlrun.get_or_create_ctx(HFTrainerMLRunInterface.DEFAULT_CONTEXT_NAME) - - HFTrainerMLRunInterface.add_interface(obj=trainer) - - if auto_log: - trainer.add_callback( - MLRunCallback( - context=context, - model_name=model_name, - tag=tag, - labels=labels, - extra_data=extra_data, - ) - ) - - -def _apply_mlrun_on_optimizer( - optimizer, - model_name: str = None, - tag: str = "", - context: mlrun.MLClientCtx = None, - auto_log: bool = True, - labels: Dict[str, str] = None, - extra_data: dict = None, - **kwargs, -): - # Get parameters defaults: - if context is None: - context = mlrun.get_or_create_ctx( - HFORTOptimizerMLRunInterface.DEFAULT_CONTEXT_NAME - ) - - HFORTOptimizerMLRunInterface.add_interface(obj=optimizer) - - if auto_log: - optimizer.enable_auto_logging( - context=context, - model_name=model_name, - tag=tag, - labels=labels, - extra_data=extra_data, - ) - - -def apply_mlrun( - huggingface_object, - model_name: str = None, - tag: str = "", - context: mlrun.MLClientCtx = None, - auto_log: bool = True, - labels: Dict[str, str] = None, - extra_data: dict = None, - **kwargs, -): - """ - Wrap the given model with MLRun's interface providing it with mlrun's additional features. - :param huggingface_object: The model to wrap. Can be loaded from the model path given as well. - :param model_name: The model name to use for storing the model artifact. Default: "model". - :param tag: The model's tag to log with. - :param context: MLRun context to work with. If no context is given it will be retrieved via - 'mlrun.get_or_create_ctx(None)' - :param auto_log: Whether to enable MLRun's auto logging. Default: True. - """ - - if isinstance(huggingface_object, transformers.Trainer): - return _apply_mlrun_on_trainer( - trainer=huggingface_object, - model_name=model_name, - tag=tag, - context=context, - auto_log=auto_log, - labels=labels, - extra_data=extra_data, - ) - import optimum.onnxruntime as optimum_ort - - if isinstance(huggingface_object, optimum_ort.ORTOptimizer): - return _apply_mlrun_on_optimizer( - optimizer=huggingface_object, - model_name=model_name, - tag=tag, - context=context, - auto_log=auto_log, - labels=labels, - extra_data=extra_data, - ) - raise mlrun.errors.MLRunInvalidArgumentError - - -# ---------------------- from auto_trainer-------------------------------- -class KWArgsPrefixes: - MODEL_CLASS = "CLASS_" - FIT = "FIT_" - TRAIN = "TRAIN_" - PREDICT = "PREDICT_" - - -def _get_sub_dict_by_prefix(src: Dict, prefix_key: str) -> Dict[str, Any]: - """ - Collect all the keys from the given dict that starts with the given prefix and creates a new dictionary with these - keys. - - :param src: The source dict to extract the values from. - :param prefix_key: Only keys with this prefix will be returned. The keys in the result dict will be without this - prefix. - """ - return { - key.replace(prefix_key, ""): val - for key, val in src.items() - if key.startswith(prefix_key) - } - - -def _get_dataframe( - context: MLClientCtx, - dataset: DataItem, - label_columns: Optional[Union[str, List[str]]] = None, - drop_columns: Union[str, List[str], int, List[int]] = None, -) -> Tuple[pd.DataFrame, Optional[Union[str, List[str]]]]: - """ - Getting the DataFrame of the dataset and drop the columns accordingly. - - :param context: MLRun context. - :param dataset: The dataset to train the model on. - Can be either a list of lists, dict, URI or a FeatureVector. - :param label_columns: The target label(s) of the column(s) in the dataset. for Regression or - Classification tasks. - :param drop_columns: str/int or a list of strings/ints that represent the column names/indices to drop. - """ - if isinstance(dataset, (list, dict)): - dataset = pd.DataFrame(dataset) - # Checking if drop_columns provided by integer type: - if drop_columns: - if isinstance(drop_columns, str) or ( - isinstance(drop_columns, list) - and any(isinstance(col, str) for col in drop_columns) - ): - context.logger.error( - "drop_columns must be an integer/list of integers if not provided with a URI/FeatureVector dataset" - ) - raise ValueError - dataset.drop(drop_columns, axis=1, inplace=True) - - return dataset, label_columns - - store_uri_prefix, _ = mlrun.datastore.parse_store_uri(dataset.artifact_url) - if mlrun.utils.StorePrefix.FeatureVector == store_uri_prefix: - # feature-vector case: - label_columns = label_columns or dataset.meta.status.label_column - dataset = fs.get_offline_features( - dataset.meta.uri, drop_columns=drop_columns - ).to_dataframe() - - context.logger.info(f"label columns: {label_columns}") - else: - # simple URL case: - dataset = dataset.as_df() - if drop_columns: - if all(col in dataset for col in drop_columns): - dataset = dataset.drop(drop_columns, axis=1) - else: - context.logger.info( - "not all of the columns to drop in the dataset, drop columns process skipped" - ) - return dataset, label_columns - - -# ---------------------- Hugging Face Trainer -------------------------------- - - -def _create_compute_metrics(metrics: List[str]) -> Callable[[EvalPrediction], Dict]: - """ - This function create and returns a function that will be used to compute metrics at evaluation. - :param metrics: List of different metrics for evaluate the model such as f1, accuracy etc. - - :returns: Function that will be used to compute metrics at evaluation. - Must take a [`EvalPrediction`] and return a dictionary string to metric values. - """ - - def _compute_metrics(eval_pred): - logits, labels = eval_pred - predictions = np.argmax(logits, axis=-1) - metric_dict_results = {} - for metric in metrics: - load_met = load_metric(metric) - metric_res = load_met.compute(predictions=predictions, references=labels)[ - metric - ] - metric_dict_results[metric] = metric_res - - return metric_dict_results - - return _compute_metrics - - -def _edit_columns( - dataset: Dataset, - drop_columns: List[str] = None, - rename_columns: [str, str] = None, -) -> Dataset: - """ - Drop and renames that columns of the given dataset - :param dataset: Dataset to process - :param drop_columns: The columns to drop from the dataset. - :param rename_columns: Dict of columns ro rename : {: , ...} - - :returns: The dataset after the desired process - """ - if drop_columns: - dataset = dataset.remove_columns(drop_columns) - if rename_columns: - dataset = dataset.rename_columns(rename_columns) - return dataset - - -def _prepare_dataset( - context: MLClientCtx, - dataset_name: str, - label_name: str = None, - drop_columns: Optional[List[str]] = None, - num_of_train_samples: int = None, - train_test_split_size: float = None, - random_state: int = None, -) -> Tuple[Dataset, Dataset]: - """ - Loading the dataset and editing the columns - - :param context: MLRun contex - :param dataset_name: The name of the dataset to get from the HuggingFace hub - :param label_name: The target label of the column in the dataset. - :param drop_columns: The columns to drop from the dataset. - :param num_of_train_samples: Max number of training samples, for debugging. - :param train_test_split_size: Should be between 0.0 and 1.0 and represent the proportion of the dataset to include - in the test split. - :param random_state: Random state for train_test_split - - """ - - context.logger.info( - f"Loading and editing {dataset_name} dataset from Hugging Face hub" - ) - rename_cols = {label_name: "labels"} - - # Loading and editing dataset: - dataset = load_dataset(dataset_name) - - # train set - train_dataset = dataset["train"] - if num_of_train_samples: - train_dataset = train_dataset.shuffle(seed=random_state).select( - list(range(num_of_train_samples)) - ) - train_dataset = _edit_columns(train_dataset, drop_columns, rename_cols) - - # test set - test_dataset = dataset["test"] - if train_test_split_size or num_of_train_samples: - train_test_split_size = train_test_split_size or 0.2 - num_of_test_samples = int( - (train_dataset.num_rows * train_test_split_size) - // (1 - train_test_split_size) - ) - test_dataset = test_dataset.shuffle(seed=random_state).select( - list(range(num_of_test_samples)) - ) - test_dataset = _edit_columns(test_dataset, drop_columns, rename_cols) - - return train_dataset, test_dataset - - -def train( - context: MLClientCtx, - hf_dataset: str = None, - dataset: DataItem = None, - test_set: DataItem = None, - drop_columns: Optional[List[str]] = None, - pretrained_tokenizer: str = None, - pretrained_model: str = None, - model_class: str = None, - model_name: str = "huggingface-model", - label_name: str = "labels", - text_col: str = "text", - num_of_train_samples: int = None, - train_test_split_size: float = None, - metrics: List[str] = None, - random_state: int = None, -): - """ - Training and evaluating a pretrained model with a pretrained tokenizer over a dataset. - The dataset can be either be the name of the dataset that contains in the HuggingFace hub, - or a URI or a FeatureVector - - :param context: MLRun context - :param hf_dataset: The name of the dataset to get from the HuggingFace hub - :param dataset: The dataset to train the model on. Can be either a URI or a FeatureVector - :param test_set: The test set to train the model with. - :param drop_columns: The columns to drop from the dataset. - :param pretrained_tokenizer: The name of the pretrained tokenizer from the HuggingFace hub. - :param pretrained_model: The name of the pretrained model from the HuggingFace hub. - :param model_name: The model's name to use for storing the model artifact, default to 'model' - :param model_class: The class of the model, e.g. `transformers.AutoModelForSequenceClassification` - :param label_name: The target label of the column in the dataset. - :param text_col: The input text column un the dataset. - :param num_of_train_samples: Max number of training samples, for debugging. - :param train_test_split_size: Should be between 0.0 and 1.0 and represent the proportion of the dataset to include - in the test split. - :param metrics: List of different metrics for evaluate the model such as f1, accuracy etc. - :param random_state: Random state for train_test_split - """ - - if train_test_split_size is None and test_set is None: - context.logger.info( - "'train_test_split_size' is not provided, setting train_test_split_size to 0.2" - ) - train_test_split_size = 0.2 - - # Creating tokenizer: - tokenizer = AutoTokenizer.from_pretrained(pretrained_tokenizer) - - def preprocess_function(examples): - return tokenizer(examples[text_col], truncation=True) - - # prepare data for training - if hf_dataset: - train_dataset, test_dataset = _prepare_dataset( - context, - hf_dataset, - label_name, - drop_columns, - num_of_train_samples, - train_test_split_size, - random_state=random_state, - ) - elif dataset: - # Get DataFrame by URL or by FeatureVector: - train_dataset, label_name = _get_dataframe( - context=context, - dataset=dataset, - label_columns=label_name, - drop_columns=drop_columns, - ) - if test_set: - test_dataset, _ = _get_dataframe( - context=context, - dataset=test_set, - label_columns=label_name, - drop_columns=drop_columns, - ) - else: - train_dataset, test_dataset = train_test_split( - train_dataset, - test_size=train_test_split_size, - random_state=random_state, - ) - train_dataset = Dataset.from_pandas(train_dataset) - test_dataset = Dataset.from_pandas(test_dataset) - else: - raise mlrun.errors.MLRunInvalidArgumentError( - "Training data was not provided. A training dataset is mandatory for training." - " Please provide a training set using one of the arguments 'hf_dataset' or 'dataset'." - ) - - # Mapping datasets with the tokenizer: - tokenized_train = train_dataset.map(preprocess_function, batched=True) - tokenized_test = test_dataset.map(preprocess_function, batched=True) - - # Creating data collator for batching: - data_collator = DataCollatorWithPadding(tokenizer=tokenizer) - - # Parsing kwargs: - train_kwargs = _get_sub_dict_by_prefix( - src=context.parameters, prefix_key=KWArgsPrefixes.TRAIN - ) - model_class_kwargs = _get_sub_dict_by_prefix( - src=context.parameters, prefix_key=KWArgsPrefixes.MODEL_CLASS - ) - - # Loading our pretrained model: - model_class_kwargs["pretrained_model_name_or_path"] = ( - model_class_kwargs.get("pretrained_model_name_or_path") or pretrained_model - ) - train_kwargs["hub_token"] = train_kwargs.get("hub_token") or pretrained_tokenizer - if not model_class_kwargs["pretrained_model_name_or_path"]: - raise mlrun.errors.MLRunRuntimeError( - "Must provide pretrained_model name as " - "function argument or in extra params" - ) - model = create_class(model_class).from_pretrained(**model_class_kwargs) - - # Preparing training arguments: - training_args = TrainingArguments( - **train_kwargs, - ) - - compute_metrics = _create_compute_metrics(metrics) if metrics else None - trainer = Trainer( - model=model, - args=training_args, - train_dataset=tokenized_train, - eval_dataset=tokenized_test, - tokenizer=tokenizer, - data_collator=data_collator, - compute_metrics=compute_metrics, - ) - - apply_mlrun(trainer, model_name=model_name) - - # Apply training with evaluation: - context.logger.info(f"training '{model_name}'") - trainer.train() - - -def _get_model_dir(model_uri: str): - model_file, _, _ = mlrun.artifacts.get_model(model_uri) - model_dir = tempfile.gettempdir() - # Unzip the Model: - with zipfile.ZipFile(model_file, "r") as zip_file: - zip_file.extractall(model_dir) - - return model_dir - - -def optimize( - model_path: str, - model_name: str = "optimized_model", - target_dir: str = "./optimized", - optimization_level: int = 1, -): - """ - Optimizing the transformer model using ONNX optimization. - - - :param model_path: The path of the model to optimize. - :param model_name: Name of the optimized model. - :param target_dir: The directory to save the ONNX model. - :param optimization_level: Optimization level performed by ONNX Runtime of the loaded graph. (default is 1) - """ - # We import these in the function scope so ONNX won't be mandatory for the other handlers: - from optimum.onnxruntime import ORTModelForSequenceClassification, ORTOptimizer - from optimum.onnxruntime.configuration import OptimizationConfig - - model_dir = _get_model_dir(model_uri=model_path) - # Creating configuration for optimization step: - optimization_config = OptimizationConfig(optimization_level=optimization_level) - - # Converting our pretrained model to an ONNX-Runtime model: - ort_model = ORTModelForSequenceClassification.from_pretrained( - model_dir, from_transformers=True - ) - - # Creating an ONNX-Runtime optimizer from ONNX model: - optimizer = ORTOptimizer.from_pretrained(ort_model) - - apply_mlrun(optimizer, model_name=model_name) - # Optimizing and saving the ONNX model: - optimizer.optimize(save_dir=target_dir, optimization_config=optimization_config) diff --git a/hugging_face_classifier_trainer/item.yaml b/hugging_face_classifier_trainer/item.yaml deleted file mode 100755 index 332902b3e..000000000 --- a/hugging_face_classifier_trainer/item.yaml +++ /dev/null @@ -1,33 +0,0 @@ -apiVersion: v1 -categories: -- deep-learning -- huggingface -- machine-learning -- model-training -description: Automatic train and optimize functions for HuggingFace framework -doc: '' -example: hugging_face_classifier_trainer.ipynb -generationDate: 2022-08-28:17-25 -hidden: false -icon: '' -labels: - author: davids -maintainers: [] -marketplaceType: '' -mlrunVersion: 1.6.1 -name: hugging_face_classifier_trainer -platformVersion: 3.5.5 -spec: - filename: hugging_face_classifier_trainer.py - handler: train - image: mlrun/mlrun - kind: job - requirements: - - onnx~=1.14.1 - - onnxruntime~=1.16.1 - - optimum~=1.6.4 - - transformers~=4.26.1 - - datasets~=2.10.1 - - scikit-learn~=1.0.2 -url: '' -version: 0.3.0 diff --git a/hugging_face_classifier_trainer/requirements.txt b/hugging_face_classifier_trainer/requirements.txt deleted file mode 100644 index 9d0db7b43..000000000 --- a/hugging_face_classifier_trainer/requirements.txt +++ /dev/null @@ -1,6 +0,0 @@ -onnx~=1.14.1 -onnxruntime~=1.16.1 -optimum~=1.6.4 -transformers~=4.26.1 -datasets~=2.10.1 -scikit-learn~=1.0.2 \ No newline at end of file diff --git a/hugging_face_classifier_trainer/test_hugging_face_classifier_trainer.py b/hugging_face_classifier_trainer/test_hugging_face_classifier_trainer.py deleted file mode 100644 index a5e0fee9b..000000000 --- a/hugging_face_classifier_trainer/test_hugging_face_classifier_trainer.py +++ /dev/null @@ -1,145 +0,0 @@ -# Copyright 2019 Iguazio -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -import os - -import mlrun -import pytest -from mlrun import import_function - -REQUIRED_ENV_VARS = [ - "MLRUN_DBPATH", - "MLRUN_ARTIFACT_PATH", - "V3IO_USERNAME", - "V3IO_API", - "V3IO_ACCESS_KEY", -] - -ADDITIONAL_PARAM_FOR_TRAIN = { - "TRAIN_output_dir": "finetuning-sentiment-model-3000-samples", - "TRAIN_learning_rate": 2e-5, - "TRAIN_per_device_train_batch_size": 16, - "TRAIN_per_device_eval_batch_size": 16, - "TRAIN_num_train_epochs": 2, - "TRAIN_weight_decay": 0.01, - "TRAIN_push_to_hub": False, - "TRAIN_evaluation_strategy": "epoch", - "TRAIN_eval_steps": 1, - "TRAIN_logging_steps": 1, - "CLASS_num_labels": 2, -} - - -def _validate_environment_variables() -> bool: - """ - Checks that all required Environment variables are set. - """ - environment_keys = os.environ.keys() - return all(key in environment_keys for key in REQUIRED_ENV_VARS) - - -def _set_environment(env_file=None): - if env_file: - mlrun.set_env_from_file(env_file) - mlrun.get_or_create_project( - "hugging-face-classifier-trainer-test", context="./", user_project=True - ) - - -@pytest.mark.skipif( - condition=not _validate_environment_variables(), - reason="Project's environment variables are not set", -) -def test_train_sequence_classification(): - _set_environment() - - # Importing function: - fn = import_function("function.yaml") - - train_run = None - - try: - train_run = fn.run( - params={ - "hf_dataset": "Shayanvsf/US_Airline_Sentiment", - "drop_columns": [ - "airline_sentiment_confidence", - "negativereason_confidence", - ], - "pretrained_tokenizer": "distilbert-base-uncased", - "pretrained_model": "distilbert-base-uncased", - "model_class": "transformers.AutoModelForSequenceClassification", - "label_name": "airline_sentiment", - "num_of_train_samples": 100, - "metrics": ["accuracy", "f1"], - "random_state": 42, - **ADDITIONAL_PARAM_FOR_TRAIN, - }, - handler="train", - local=True, - ) - except Exception as exception: - print(f"- The test failed - raised the following error:\n- {exception}") - assert train_run and all( - key in train_run.outputs for key in ["model", "loss"] - ), "outputs should include more data" - - -@pytest.mark.skipif( - condition=not _validate_environment_variables(), - reason="Project's environment variables are not set", -) -def test_train_and_optimize_sequence_classification(): - _set_environment() - - # Importing function: - fn = import_function("function.yaml") - - train_run = None - optimize_run = None - - try: - train_run = fn.run( - params={ - "hf_dataset": "Shayanvsf/US_Airline_Sentiment", - "drop_columns": [ - "airline_sentiment_confidence", - "negativereason_confidence", - ], - "pretrained_tokenizer": "distilbert-base-uncased", - "pretrained_model": "distilbert-base-uncased", - "model_class": "transformers.AutoModelForSequenceClassification", - "label_name": "airline_sentiment", - "num_of_train_samples": 100, - "metrics": ["accuracy", "f1"], - "random_state": 42, - **ADDITIONAL_PARAM_FOR_TRAIN, - }, - handler="train", - local=True, - ) - - optimize_run = fn.run( - params={"model_path": train_run.outputs["model"]}, - handler="optimize", - local=True, - ) - except Exception as exception: - print(f"- The test failed - raised the following error:\n- {exception}") - assert train_run and all( - key in train_run.outputs for key in ["model", "loss"] - ), "outputs should include more data" - assert optimize_run and all( - key in optimize_run.outputs for key in ["model"] - ), "outputs should include more data" diff --git a/huggingface_auto_trainer/function.yaml b/huggingface_auto_trainer/function.yaml deleted file mode 100644 index 702a84016..000000000 --- a/huggingface_auto_trainer/function.yaml +++ /dev/null @@ -1,327 +0,0 @@ -kind: job -metadata: - name: huggingface-auto-trainer - tag: '' - hash: 55c9aa4a822780f7388819ccf633dfe26b31f02e - project: '' - labels: - author: Zeevr - categories: - - huggingface - - genai - - machine-learning - - model-training -spec: - command: '' - args: [] - image: mlrun/mlrun - build: - functionSourceCode: aW1wb3J0IGltcG9ydGxpYgppbXBvcnQgb3MKaW1wb3J0IHNodXRpbAppbXBvcnQgdGVtcGZpbGUKaW1wb3J0IHppcGZpbGUKZnJvbSBhYmMgaW1wb3J0IEFCQwpmcm9tIHR5cGluZyBpbXBvcnQgRGljdCwgTGlzdCwgVHVwbGUsIFVuaW9uCgppbXBvcnQgbWxydW4KaW1wb3J0IG51bXB5IGFzIG5wCmltcG9ydCBwYW5kYXMgYXMgcGQKaW1wb3J0IHBlZnQKaW1wb3J0IHRvcmNoCmltcG9ydCB0cmFuc2Zvcm1lcnMKZnJvbSBkYXRhc2V0cyBpbXBvcnQgRGF0YXNldCwgbG9hZF9kYXRhc2V0CmZyb20gbWxydW4uYXJ0aWZhY3RzLm1hbmFnZXIgaW1wb3J0IEFydGlmYWN0LCBQbG90bHlBcnRpZmFjdApmcm9tIG1scnVuLmRhdGFzdG9yZSBpbXBvcnQgaXNfc3RvcmVfdXJpCmZyb20gbWxydW4uZnJhbWV3b3Jrcy5fY29tbW9uIGltcG9ydCBDb21tb25UeXBlcywgTUxSdW5JbnRlcmZhY2UKZnJvbSBtbHJ1bi51dGlscyBpbXBvcnQgbG9nZ2VyCmZyb20gcGVmdCBpbXBvcnQgKExvcmFDb25maWcsIFBlZnRNb2RlbCwgZ2V0X3BlZnRfbW9kZWwsCiAgICAgICAgICAgICAgICAgIHByZXBhcmVfbW9kZWxfZm9yX2tiaXRfdHJhaW5pbmcpCmZyb20gcGxvdGx5IGltcG9ydCBncmFwaF9vYmplY3RzIGFzIGdvCmZyb20gdHJhbnNmb3JtZXJzIGltcG9ydCAoQXV0b01vZGVsRm9yQ2F1c2FsTE0sIEF1dG9Ub2tlbml6ZXIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgQml0c0FuZEJ5dGVzQ29uZmlnLCBEYXRhQ29sbGF0b3JGb3JMYW5ndWFnZU1vZGVsaW5nLAogICAgICAgICAgICAgICAgICAgICAgICAgIFByZVRyYWluZWRNb2RlbCwgUHJlVHJhaW5lZFRva2VuaXplciwgVHJhaW5lciwKICAgICAgICAgICAgICAgICAgICAgICAgICBUcmFpbmVyQ2FsbGJhY2ssIFRyYWluZXJDb250cm9sLCBUcmFpbmVyU3RhdGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgVHJhaW5pbmdBcmd1bWVudHMpCgpzdXBwb3J0ZWRfdGFza3MgPSBbCiAgICAicXVlc3Rpb24tYW5zd2VyaW5nIiwKICAgICJzdW1tYXJpemF0aW9uIiwKICAgICJ0YWJsZS1xdWVzdGlvbi1hbnN3ZXJpbmciLAogICAgInRleHQydGV4dC1nZW5lcmF0aW9uIiwKICAgICJ0ZXh0LWNsYXNzaWZpY2F0aW9uIiwKICAgICJzZW50aW1lbnQtYW5hbHlzaXMiLAogICAgInRleHQtZ2VuZXJhdGlvbiIsCiAgICAidG9rZW4tY2xhc3NpZmljYXRpb24iLAogICAgInRyYW5zbGF0aW9uIiwKICAgICJ0cmFuc2xhdGlvbl94eF90b195eSIsCl0KCgpjbGFzcyBDb25maWdLZXlzOgogICAgZGVlcHNwZWVkID0gImRlZXBzcGVlZCIKICAgIHF1YW50aXphdGlvbiA9ICJxdWFudGl6YXRpb24iCiAgICBsb3JhID0gImxvcmEiCiAgICB0cmFpbmluZyA9ICJ0cmFpbmluZyIKICAgIHRva2VuaXplcl9wcmV0cmFpbmVkID0gInRva2VuaXplcl9wcmV0cmFpbmVkIgogICAgbW9kZWxfcHJldHJhaW5lZCA9ICJtb2RlbF9wcmV0cmFpbmVkIgogICAgZGF0YV9jb2xsYXRvciA9ICJkYXRhX2NvbGxhdG9yIgoKCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLWZyb20gTUxSVU4tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQpjbGFzcyBIRlRyYWluZXJNTFJ1bkludGVyZmFjZShNTFJ1bkludGVyZmFjZSwgQUJDKToKICAgICIiIgogICAgVGhpcyBpcyB0ZW1wb3JhcnkgYW5kIHdpbGwgYmUgYnVpbHQgaW4gbWxydW4gMS41LjAKICAgIEludGVyZmFjZSBmb3IgYWRkaW5nIE1MUnVuIGZlYXR1cmVzIGZvciB0ZW5zb3JmbG93IGtlcmFzIEFQSS4KICAgICIiIgoKICAgICMgTUxSdW5zIGNvbnRleHQgZGVmYXVsdCBuYW1lOgogICAgREVGQVVMVF9DT05URVhUX05BTUUgPSAibWxydW4taHVnZ2luZ2ZhY2UiCgogICAgIyBBdHRyaWJ1dGVzIHRvIHJlcGxhY2Ugc28gdGhlIE1MUnVuIGludGVyZmFjZSB3aWxsIGJlIGZ1bGx5IGVuYWJsZWQuCiAgICBfUkVQTEFDRURfTUVUSE9EUyA9IFsKICAgICAgICAidHJhaW4iLAogICAgICAgICMgImV2YWx1YXRlIgogICAgXQoKICAgIEBjbGFzc21ldGhvZAogICAgZGVmIGFkZF9pbnRlcmZhY2UoCiAgICAgICAgY2xzLAogICAgICAgIG9iajogVHJhaW5lciwKICAgICAgICByZXN0b3JhdGlvbjogQ29tbW9uVHlwZXMuTUxSdW5JbnRlcmZhY2VSZXN0b3JhdGlvblR5cGUgPSBOb25lLAogICAgKToKICAgICAgICBzdXBlcihIRlRyYWluZXJNTFJ1bkludGVyZmFjZSwgY2xzKS5hZGRfaW50ZXJmYWNlKAogICAgICAgICAgICBvYmo9b2JqLCByZXN0b3JhdGlvbj1yZXN0b3JhdGlvbgogICAgICAgICkKCiAgICBAY2xhc3NtZXRob2QKICAgIGRlZiBtbHJ1bl90cmFpbihjbHMpOgogICAgICAgIGRlZiB3cmFwcGVyKHNlbGY6IFRyYWluZXIsICphcmdzLCAqKmt3YXJncyk6CiAgICAgICAgICAgICMgUmVzdG9yZSB0aGUgZXZhbHVhdGlvbiBtZXRob2QgYXMgYHRyYWluYCB3aWxsIHVzZSBpdDoKICAgICAgICAgICAgIyBjbHMuX3Jlc3RvcmVfYXR0cmlidXRlKG9iaj1zZWxmLCBhdHRyaWJ1dGVfbmFtZT0iZXZhbHVhdGUiKQoKICAgICAgICAgICAgIyBDYWxsIHRoZSBvcmlnaW5hbCBmaXQgbWV0aG9kOgogICAgICAgICAgICByZXN1bHQgPSBzZWxmLm9yaWdpbmFsX3RyYWluKCphcmdzLCAqKmt3YXJncykKCiAgICAgICAgICAgICMgUmVwbGFjZSB0aGUgZXZhbHVhdGlvbiBtZXRob2QgYWdhaW46CiAgICAgICAgICAgICMgY2xzLl9yZXBsYWNlX2Z1bmN0aW9uKG9iaj1zZWxmLCBmdW5jdGlvbl9uYW1lPSJldmFsdWF0ZSIpCgogICAgICAgICAgICByZXR1cm4gcmVzdWx0CgogICAgICAgIHJldHVybiB3cmFwcGVyCgoKY2xhc3MgTUxSdW5DYWxsYmFjayhUcmFpbmVyQ2FsbGJhY2spOgogICAgIiIiCiAgICBUaGlzIGlzIHRlbXBvcmFyeSBhbmQgd2lsbCBiZSBidWlsdCBpbiBtbHJ1biAxLjUuMAogICAgQ2FsbGJhY2sgZm9yIGNvbGxlY3RpbmcgbG9ncyBkdXJpbmcgdHJhaW5pbmcgLyBldmFsdWF0aW9uIG9mIHRoZSBgVHJhaW5lcmAgQVBJLgogICAgIiIiCgogICAgZGVmIF9faW5pdF9fKAogICAgICAgIHNlbGYsCiAgICAgICAgY29udGV4dDogbWxydW4uTUxDbGllbnRDdHggPSBOb25lLAogICAgICAgIG1vZGVsX25hbWU6IHN0ciA9ICJtb2RlbCIsCiAgICAgICAgdGFnOiBzdHIgPSAiIiwKICAgICAgICBsYWJlbHM6IERpY3Rbc3RyLCBzdHJdID0gTm9uZSwKICAgICAgICBleHRyYV9kYXRhOiBkaWN0ID0gTm9uZSwKICAgICk6CiAgICAgICAgc3VwZXIoKS5fX2luaXRfXygpCgogICAgICAgICMgU3RvcmUgdGhlIGNvbmZpZ3VyYXRpb25zOgogICAgICAgIHNlbGYuX2NvbnRleHQgPSAoCiAgICAgICAgICAgIGNvbnRleHQKICAgICAgICAgICAgaWYgY29udGV4dCBpcyBub3QgTm9uZQogICAgICAgICAgICBlbHNlIG1scnVuLmdldF9vcl9jcmVhdGVfY3R4KCIuL21scnVuLWh1Z2dpbmdmYWNlIikKICAgICAgICApCiAgICAgICAgc2VsZi5fbW9kZWxfbmFtZSA9IG1vZGVsX25hbWUKICAgICAgICBzZWxmLl90YWcgPSB0YWcKICAgICAgICBzZWxmLl9sYWJlbHMgPSBsYWJlbHMKICAgICAgICBzZWxmLl9leHRyYV9kYXRhID0gZXh0cmFfZGF0YSBpZiBleHRyYV9kYXRhIGlzIG5vdCBOb25lIGVsc2Uge30KCiAgICAgICAgIyBTZXQgdXAgdGhlIGxvZ2dpbmcgbW9kZToKICAgICAgICBzZWxmLl9pc190cmFpbmluZyA9IEZhbHNlCiAgICAgICAgc2VsZi5fc3RlcHM6IExpc3RbTGlzdFtpbnRdXSA9IFtdCiAgICAgICAgc2VsZi5fbWV0cmljX3Njb3JlczogRGljdFtzdHIsIExpc3RbZmxvYXRdXSA9IHt9CiAgICAgICAgc2VsZi5fYXJ0aWZhY3RzOiBEaWN0W3N0ciwgQXJ0aWZhY3RdID0ge30KCiAgICBkZWYgb25fZXBvY2hfYmVnaW4oCiAgICAgICAgc2VsZiwKICAgICAgICBhcmdzOiBUcmFpbmluZ0FyZ3VtZW50cywKICAgICAgICBzdGF0ZTogVHJhaW5lclN0YXRlLAogICAgICAgIGNvbnRyb2w6IFRyYWluZXJDb250cm9sLAogICAgICAgICoqa3dhcmdzLAogICAgKToKICAgICAgICBpZiBub3Qgc3RhdGUuaXNfd29ybGRfcHJvY2Vzc196ZXJvOgogICAgICAgICAgICByZXR1cm4KICAgICAgICBzZWxmLl9zdGVwcy5hcHBlbmQoW10pCgogICAgZGVmIG9uX2Vwb2NoX2VuZCgKICAgICAgICBzZWxmLAogICAgICAgIGFyZ3M6IFRyYWluaW5nQXJndW1lbnRzLAogICAgICAgIHN0YXRlOiBUcmFpbmVyU3RhdGUsCiAgICAgICAgY29udHJvbDogVHJhaW5lckNvbnRyb2wsCiAgICAgICAgKiprd2FyZ3MsCiAgICApOgogICAgICAgIGlmIG5vdCBzdGF0ZS5pc193b3JsZF9wcm9jZXNzX3plcm86CiAgICAgICAgICAgIHJldHVybgogICAgICAgIHNlbGYubG9nX21ldHJpY3MoKQoKICAgIGRlZiBvbl9sb2coCiAgICAgICAgc2VsZiwKICAgICAgICBhcmdzOiBUcmFpbmluZ0FyZ3VtZW50cywKICAgICAgICBzdGF0ZTogVHJhaW5lclN0YXRlLAogICAgICAgIGNvbnRyb2w6IFRyYWluZXJDb250cm9sLAogICAgICAgIGxvZ3M6IERpY3Rbc3RyLCBmbG9hdF0gPSBOb25lLAogICAgICAgICoqa3dhcmdzLAogICAgKToKICAgICAgICBpZiBub3Qgc3RhdGUuaXNfd29ybGRfcHJvY2Vzc196ZXJvOgogICAgICAgICAgICByZXR1cm4KICAgICAgICByZWNlbnRfbG9ncyA9IHN0YXRlLmxvZ19oaXN0b3J5Wy0xXS5jb3B5KCkKCiAgICAgICAgcmVjZW50X2xvZ3MucG9wKCJlcG9jaCIpCiAgICAgICAgY3VycmVudF9zdGVwID0gaW50KHJlY2VudF9sb2dzLnBvcCgic3RlcCIpKQogICAgICAgIGlmIGN1cnJlbnRfc3RlcCBub3QgaW4gc2VsZi5fc3RlcHNbLTFdOgogICAgICAgICAgICBzZWxmLl9zdGVwc1stMV0uYXBwZW5kKGN1cnJlbnRfc3RlcCkKCiAgICAgICAgZm9yIG1ldHJpY19uYW1lLCBtZXRyaWNfc2NvcmUgaW4gcmVjZW50X2xvZ3MuaXRlbXMoKToKICAgICAgICAgICAgaWYgbWV0cmljX25hbWUuc3RhcnRzd2l0aCgidHJhaW5fIik6CiAgICAgICAgICAgICAgICBpZiBtZXRyaWNfbmFtZS5zcGxpdCgidHJhaW5fIilbMV0gbm90IGluIHNlbGYuX21ldHJpY19zY29yZXM6CiAgICAgICAgICAgICAgICAgICAgc2VsZi5fbWV0cmljX3Njb3Jlc1ttZXRyaWNfbmFtZV0gPSBbbWV0cmljX3Njb3JlXQogICAgICAgICAgICAgICAgY29udGludWUKICAgICAgICAgICAgaWYgbWV0cmljX25hbWUgbm90IGluIHNlbGYuX21ldHJpY19zY29yZXM6CiAgICAgICAgICAgICAgICBzZWxmLl9tZXRyaWNfc2NvcmVzW21ldHJpY19uYW1lXSA9IFtdCiAgICAgICAgICAgIHNlbGYuX21ldHJpY19zY29yZXNbbWV0cmljX25hbWVdLmFwcGVuZChtZXRyaWNfc2NvcmUpCgogICAgZGVmIG9uX3RyYWluX2JlZ2luKAogICAgICAgIHNlbGYsCiAgICAgICAgYXJnczogVHJhaW5pbmdBcmd1bWVudHMsCiAgICAgICAgc3RhdGU6IFRyYWluZXJTdGF0ZSwKICAgICAgICBjb250cm9sOiBUcmFpbmVyQ29udHJvbCwKICAgICAgICAqKmt3YXJncywKICAgICk6CiAgICAgICAgaWYgbm90IHN0YXRlLmlzX3dvcmxkX3Byb2Nlc3NfemVybzoKICAgICAgICAgICAgcmV0dXJuCiAgICAgICAgc2VsZi5faXNfdHJhaW5pbmcgPSBUcnVlCgogICAgZGVmIG9uX3RyYWluX2VuZCgKICAgICAgICBzZWxmLAogICAgICAgIGFyZ3M6IFRyYWluaW5nQXJndW1lbnRzLAogICAgICAgIHN0YXRlOiBUcmFpbmVyU3RhdGUsCiAgICAgICAgY29udHJvbDogVHJhaW5lckNvbnRyb2wsCiAgICAgICAgbW9kZWw6IFByZVRyYWluZWRNb2RlbCA9IE5vbmUsCiAgICAgICAgdG9rZW5pemVyOiBQcmVUcmFpbmVkVG9rZW5pemVyID0gTm9uZSwKICAgICAgICAqKmt3YXJncywKICAgICk6CiAgICAgICAgaWYgbm90IHN0YXRlLmlzX3dvcmxkX3Byb2Nlc3NfemVybzoKICAgICAgICAgICAgcmV0dXJuCiAgICAgICAgc2VsZi5sb2dfbWV0cmljcygpCgogICAgZGVmIG9uX2V2YWx1YXRlKAogICAgICAgIHNlbGYsCiAgICAgICAgYXJnczogVHJhaW5pbmdBcmd1bWVudHMsCiAgICAgICAgc3RhdGU6IFRyYWluZXJTdGF0ZSwKICAgICAgICBjb250cm9sOiBUcmFpbmVyQ29udHJvbCwKICAgICAgICAqKmt3YXJncywKICAgICk6CiAgICAgICAgaWYgbm90IHN0YXRlLmlzX3dvcmxkX3Byb2Nlc3NfemVybzoKICAgICAgICAgICAgcmV0dXJuCiAgICAgICAgc2VsZi5sb2dfbWV0cmljcygpCgogICAgICAgIGlmIHNlbGYuX2lzX3RyYWluaW5nOgogICAgICAgICAgICByZXR1cm4KCiAgICBkZWYgbG9nX21ldHJpY3Moc2VsZik6CiAgICAgICAgZm9yIG1ldHJpY19uYW1lLCBtZXRyaWNfc2NvcmVzIGluIHNlbGYuX21ldHJpY19zY29yZXMuaXRlbXMoKToKICAgICAgICAgICAgc2VsZi5fY29udGV4dC5sb2dfcmVzdWx0KGtleT1tZXRyaWNfbmFtZSwgdmFsdWU9bWV0cmljX3Njb3Jlc1stMV0pCiAgICAgICAgICAgIGlmIGxlbihtZXRyaWNfc2NvcmVzKSA+IDE6CiAgICAgICAgICAgICAgICBzZWxmLmxvZ19tZXRyaWNfcGxvdChuYW1lPW1ldHJpY19uYW1lLCBzY29yZXM9bWV0cmljX3Njb3JlcykKICAgICAgICBzZWxmLl9jb250ZXh0LmNvbW1pdChjb21wbGV0ZWQ9RmFsc2UpCgogICAgZGVmIGxvZ19tZXRyaWNfcGxvdChzZWxmLCBuYW1lOiBzdHIsIHNjb3JlczogTGlzdFtmbG9hdF0pOgogICAgICAgICMgSW5pdGlhbGl6ZSBhIHBsb3RseSBmaWd1cmU6CiAgICAgICAgbWV0cmljX2ZpZ3VyZSA9IGdvLkZpZ3VyZSgpCgogICAgICAgICMgQWRkIHRpdGxlczoKICAgICAgICBtZXRyaWNfZmlndXJlLnVwZGF0ZV9sYXlvdXQoCiAgICAgICAgICAgIHRpdGxlPW5hbWUuY2FwaXRhbGl6ZSgpLnJlcGxhY2UoIl8iLCAiICIpLAogICAgICAgICAgICB4YXhpc190aXRsZT0iU2FtcGxlcyIsCiAgICAgICAgICAgIHlheGlzX3RpdGxlPSJTY29yZXMiLAogICAgICAgICkKCiAgICAgICAgIyBEcmF3OgogICAgICAgIG1ldHJpY19maWd1cmUuYWRkX3RyYWNlKAogICAgICAgICAgICBnby5TY2F0dGVyKHg9bnAuYXJhbmdlKGxlbihzY29yZXMpKSwgeT1zY29yZXMsIG1vZGU9ImxpbmVzIikKICAgICAgICApCgogICAgICAgICMgQ3JlYXRlIHRoZSBwbG90bHkgYXJ0aWZhY3Q6CiAgICAgICAgYXJ0aWZhY3RfbmFtZSA9IGYie25hbWV9X3Bsb3QiCiAgICAgICAgYXJ0aWZhY3QgPSBQbG90bHlBcnRpZmFjdChrZXk9YXJ0aWZhY3RfbmFtZSwgZmlndXJlPW1ldHJpY19maWd1cmUpCiAgICAgICAgc2VsZi5fYXJ0aWZhY3RzW2FydGlmYWN0X25hbWVdID0gc2VsZi5fY29udGV4dC5sb2dfYXJ0aWZhY3QoYXJ0aWZhY3QpCgoKZGVmIGFwcGx5X21scnVuKAogICAgdHJhaW5lcjogdHJhbnNmb3JtZXJzLlRyYWluZXIsCiAgICBtb2RlbF9uYW1lOiBzdHIgPSBOb25lLAogICAgdGFnOiBzdHIgPSAiIiwKICAgIGNvbnRleHQ6IG1scnVuLk1MQ2xpZW50Q3R4ID0gTm9uZSwKICAgIGF1dG9fbG9nOiBib29sID0gVHJ1ZSwKICAgIGxhYmVsczogRGljdFtzdHIsIHN0cl0gPSBOb25lLAogICAgZXh0cmFfZGF0YTogZGljdCA9IE5vbmUsCiAgICAqKmt3YXJncywKKToKICAgICIiIgogICAgVGhpcyBpcyB0ZW1wb3JhcnkgYW5kIHdpbGwgYmUgYnVpbHQgaW4gbWxydW4gMS41LjAKICAgICIiIgogICAgIyBHZXQgcGFyYW1ldGVycyBkZWZhdWx0czoKICAgIGlmIGNvbnRleHQgaXMgTm9uZToKICAgICAgICBjb250ZXh0ID0gbWxydW4uZ2V0X29yX2NyZWF0ZV9jdHgoSEZUcmFpbmVyTUxSdW5JbnRlcmZhY2UuREVGQVVMVF9DT05URVhUX05BTUUpCgogICAgSEZUcmFpbmVyTUxSdW5JbnRlcmZhY2UuYWRkX2ludGVyZmFjZShvYmo9dHJhaW5lcikKCiAgICBpZiBhdXRvX2xvZzoKICAgICAgICB0cmFpbmVyLmFkZF9jYWxsYmFjaygKICAgICAgICAgICAgTUxSdW5DYWxsYmFjaygKICAgICAgICAgICAgICAgIGNvbnRleHQ9Y29udGV4dCwKICAgICAgICAgICAgICAgIG1vZGVsX25hbWU9bW9kZWxfbmFtZSwKICAgICAgICAgICAgICAgIHRhZz10YWcsCiAgICAgICAgICAgICAgICBsYWJlbHM9bGFiZWxzLAogICAgICAgICAgICAgICAgZXh0cmFfZGF0YT1leHRyYV9kYXRhLAogICAgICAgICAgICApCiAgICAgICAgKQoKCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLWVuZCBmcm9tIE1MUlVOLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCgpkZWYgX3ByaW50X3RyYWluYWJsZV9wYXJhbWV0ZXJzKG1vZGVsKToKICAgICIiIgogICAgUHJpbnRzIHRoZSBudW1iZXIgb2YgdHJhaW5hYmxlIHBhcmFtZXRlcnMgaW4gdGhlIG1vZGVsLgogICAgIiIiCiAgICB0cmFpbmFibGVfcGFyYW1zID0gMAogICAgYWxsX3BhcmFtID0gMAogICAgZm9yIF8sIHBhcmFtIGluIG1vZGVsLm5hbWVkX3BhcmFtZXRlcnMoKToKICAgICAgICBhbGxfcGFyYW0gKz0gcGFyYW0ubnVtZWwoKQogICAgICAgIGlmIHBhcmFtLnJlcXVpcmVzX2dyYWQ6CiAgICAgICAgICAgIHRyYWluYWJsZV9wYXJhbXMgKz0gcGFyYW0ubnVtZWwoKQogICAgcHJpbnQoCiAgICAgICAgZiJ0cmFpbmFibGUgcGFyYW1zOiB7dHJhaW5hYmxlX3BhcmFtc30gfHwgYWxsIHBhcmFtczoge2FsbF9wYXJhbX0gfHwgdHJhaW5hYmxlJToiCiAgICAgICAgZiIgezEwMCAqIHRyYWluYWJsZV9wYXJhbXMgLyBhbGxfcGFyYW19IgogICAgKQoKCiMgZGVmYXVsdCBjb25maWdzCiMgd2lsbCBiZSB1c2VkIGlmIHVzZXIgcHJvdmlkZXMgIlRydWUiIHdpdGggY29uZmlnIG5hbWUgYXMgaW5wdXQKUVVBTlRJWkFUSU9OX0NPTkZJRyA9IHRyYW5zZm9ybWVycy5CaXRzQW5kQnl0ZXNDb25maWcoCiAgICBsb2FkX2luXzRiaXQ9VHJ1ZSwKICAgIGJuYl80Yml0X3VzZV9kb3VibGVfcXVhbnQ9VHJ1ZSwKICAgIGJuYl80Yml0X3F1YW50X3R5cGU9Im5mNCIsCiAgICBibmJfNGJpdF9jb21wdXRlX2R0eXBlPXRvcmNoLmJmbG9hdDE2LAopCgpMT1JBX0NPTkZJRyA9IHBlZnQuTG9yYUNvbmZpZygKICAgIHI9OCwKICAgIGxvcmFfYWxwaGE9MzIsCiAgICB0YXJnZXRfbW9kdWxlcz1bInF1ZXJ5X2tleV92YWx1ZSJdLAogICAgbG9yYV9kcm9wb3V0PTAuMDUsCiAgICBiaWFzPSJub25lIiwKICAgIHRhc2tfdHlwZT0iQ0FVU0FMX0xNIiwKKQoKREVFUFNQRUVEX0NPTkZJRyA9IHsKICAgICJ0cmFpbl9taWNyb19iYXRjaF9zaXplX3Blcl9ncHUiOiAiYXV0byIsCiAgICAiZnAxNiI6IHsiZW5hYmxlZCI6IFRydWV9LAogICAgImF1dG90dW5pbmciOiB7CiAgICAgICAgImVuYWJsZWQiOiBUcnVlLAogICAgICAgICJhcmdfbWFwcGluZ3MiOiB7CiAgICAgICAgICAgICJ0cmFpbl9taWNyb19iYXRjaF9zaXplX3Blcl9ncHUiOiAiLS1wZXJfZGV2aWNlX3RyYWluX2JhdGNoX3NpemUiLAogICAgICAgICAgICAiZ3JhZGllbnRfYWNjdW11bGF0aW9uX3N0ZXBzICI6ICItLWdyYWRpZW50X2FjY3VtdWxhdGlvbl9zdGVwcyIsCiAgICAgICAgfSwKICAgIH0sCiAgICAiemVyb19vcHRpbWl6YXRpb24iOiB7CiAgICAgICAgInN0YWdlIjogMiwKICAgIH0sCn0KCgpkZWYgX3VwZGF0ZV9jb25maWcoc3JjOiBkaWN0LCBkc3Q6IGRpY3QpOgogICAgIiIiCiAgICB1cGRhdGUgY29uZmlncyBhY2NvcmRpbmcgdG8gdXNlciwgdGhpcyB3YXkgdGhlIHVzZXIgY2FuIGFkZC9tb2RpZnkgdmFsdWVzIGluIGRlZmF1bHQgY29uZmlncyBmb3IgZS5nLgoKICAgIGdvZXMgb3ZlciBhbGwgY29uZmlncyBhbmQgY29ycmVzcG9uZGluZyBwcmVmaXhlcywgY29sbGVjdCBhbGwgdGhlIGtleXMgZnJvbSB0aGUgZ2l2ZW4gZGljdCB0aGF0IHN0YXJ0CiAgICAgd2l0aCB0aGUgcHJlZml4IGFuZCBhZGQgdGhlbSB0byBhcHByb3ByaWF0ZSBjb25maWcKCiAgICA6cGFyYW0gc3JjOiBkaWN0IG9mIGFsbCBjYW5kaWRhdGUgdmFsdWVzIHRvIHVwZGF0ZSBkaWN0LgogICAgOnBhcmFtIGRzdDogZGljdCBjb250YWluaW5nIGFsbCBjb25maWdzIHRvIHVwZGF0ZS4KICAgICIiIgoKICAgIGZvciBjb25maWdfbmFtZSwgY29uZmlnIGluIGRzdC5pdGVtcygpOgoKICAgICAgICAjIElmIGdpdmVuIFRydWUgd2UgdXNlIGRlZmF1bHQgZGljdAogICAgICAgICMgQ2FuIGFsc28gYmUgRmFsc2Ugb3IgYSBjb25maWcgZGljdCBnaXZlbiBmcm9tIHVzZXIsIHNvIHdlIGNoZWNrIHNwZWNpZmljYWxseSBmbyBUcnVlCiAgICAgICAgaWYgY29uZmlnIGlzIFRydWUgYW5kIGNvbmZpZ19uYW1lID09ICJxdWFudGl6YXRpb24iOgogICAgICAgICAgICBjb25maWcgPSBRVUFOVElaQVRJT05fQ09ORklHCgogICAgICAgIGlmIGNvbmZpZyBpcyBUcnVlIGFuZCBjb25maWdfbmFtZSA9PSAibG9yYSI6CiAgICAgICAgICAgIGNvbmZpZyA9IExPUkFfQ09ORklHCgogICAgICAgIGlmIGNvbmZpZyBpcyBUcnVlIGFuZCBjb25maWdfbmFtZSA9PSAiZGVlcHNwZWVkIjoKICAgICAgICAgICAgY29uZmlnID0gREVFUFNQRUVEX0NPTkZJRwoKICAgICAgICAjIGluIHNvbWUgY2FzZXMgd2UgY2FuIGdldCBhIGJvb2xlYW4gdmFsdWUsIGluIHRoYXQgY2FzZSBubyBuZWVkIHRvIGxvb2sgZm9yIGFyZ3MKICAgICAgICBpZiBpc2luc3RhbmNlKGNvbmZpZywgYm9vbCk6CiAgICAgICAgICAgIGNvbmZpZyA9IE5vbmUKCiAgICAgICAgZWxpZiBpc2luc3RhbmNlKGNvbmZpZywgZGljdCk6CiAgICAgICAgICAgIGZvciBrZXksIHZhbCBpbiBzcmMuaXRlbXMoKToKICAgICAgICAgICAgICAgIGlmIGtleS5zdGFydHN3aXRoKGNvbmZpZ19uYW1lKToKICAgICAgICAgICAgICAgICAgICBjb25maWdba2V5LnJlcGxhY2UoZiJ7Y29uZmlnX25hbWV9XyIsICIiKV0gPSB2YWwKCiAgICAgICAgIyB1cGRhdGUgYnkgY29uZmlnIG5hbWUKICAgICAgICBlbHNlOgogICAgICAgICAgICBmb3Iga2V5LCB2YWwgaW4gc3JjLml0ZW1zKCk6CiAgICAgICAgICAgICAgICBpZiBrZXkuc3RhcnRzd2l0aChjb25maWdfbmFtZSk6CiAgICAgICAgICAgICAgICAgICAgc2V0YXR0cihjb25maWcsIGtleS5yZXBsYWNlKGYie2NvbmZpZ19uYW1lfV8iLCAiIiksIHZhbCkKCiAgICAgICAgZHN0LnVwZGF0ZSh7Y29uZmlnX25hbWU6IGNvbmZpZ30pCgoKZGVmIF9nZXRfY2xhc3Nfb2JqZWN0KGNsYXNzX3BhdGg6IHN0cikgLT4gdHlwZToKICAgICIiIgogICAgZ2l2ZW4gYSBmdWxsIGNsYXNzIG5hbWUsIHRoaXMgZnVuY3Rpb24gcmV0dXJucyB0aGUgY29ycmVjdCBjbGFzcwoKICAgIDpwYXJhbSBjbGFzc19wYXRoOiBhIGZ1bGwgY2xhc3MgbmFtZSAoZXguICd0cmFuc2Zvcm1lcnMuQXV0b01vZGVsRm9yQ2F1c2FsTE0nKQoKICAgIDpyZXR1cm4gdGhlIHdhbnRlZCBjbGFzcyBvYmplY3QKICAgICIiIgogICAgbW9kdWxlX3BhdGgsIGNsYXNzX25hbWUgPSBjbGFzc19wYXRoLnJzcGxpdCgiLiIsIDEpCiAgICBtb2R1bGUgPSBpbXBvcnRsaWIuaW1wb3J0X21vZHVsZShtb2R1bGVfcGF0aCkKICAgIHJldHVybiBnZXRhdHRyKG1vZHVsZSwgY2xhc3NfbmFtZSkKCgpkZWYgX3NldF9tb2RlbF9hbmRfdG9rZW5pemVyKAogICAgbW9kZWw6IFVuaW9uW3N0ciwgTGlzdFtzdHJdXSwKICAgIHRva2VuaXplcjogVW5pb25bc3RyLCBMaXN0W3N0cl1dLAogICAgdGFzazogc3RyLAogICAgZnJhbWV3b3JrOiBzdHIsCiAgICBsb3JhX2NvbmZpZzogZGljdCwKICAgIHF1YW50aXphdGlvbl9jb25maWc6IGRpY3QsCiAgICB1c2VfY3VkYTogYm9vbCwKICAgIHRva2VuaXplcl9wcmV0cmFpbmVkX2NvbmZpZywKICAgIG1vZGVsX3ByZXRyYWluZWRfY29uZmlnLAogICAgZGV2aWNlX21hcDogc3RyLAopOgogICAgIiIiCiAgICBnZXQgdGhlIGNvcnJlY3QgbW9kZWwgYW5kIHRva2VuaXplciBhY2NvcmRpbmcgdG8gZ2l2ZW4gdXNlciBpbnB1dHMKCiAgICA6cGFyYW0gbW9kZWw6IGEgdHVwbGUgY29udGFpbmluZyBtb2RlbCBuYW1lIGFuZCBjbGFzcywgb3Igc3RyIHdpdGggbW9kZWwgbmFtZSBvciBwYXRoCiAgICA6cGFyYW0gdG9rZW5pemVyOiBhIHR1cGxlIGNvbnRhaW5pbmcgdG9rZW5pemVyIG5hbWUgYW5kIGNsYXNzLCBvciBzdHIgd2l0aCB0b2tlbml6ZXIgbmFtZSBvciBwYXRoCiAgICA6cGFyYW0gdGFzazogYSBzdXBwb3J0ZWQgbmxwIHRhc2ssIHVzZWQgdG8gY2hvb3NlIG1vZGVsIGlmIG5vdCBwcm92aWRlZAogICAgOnBhcmFtIGZyYW1ld29yazogcHQgb3IgdGYKICAgIDpwYXJhbSBsb3JhX2NvbmZpZzogbG9yYSBjb25maWcgb3IgTm9uZSwgdG8gbG9hZCBtb2RlbCBpbiBhcHByb3ByaWF0ZSB3YXkKICAgIDpwYXJhbSBxdWFudGl6YXRpb25fY29uZmlnOiBxdWFudGl6YXRpb24gY29uZmlnIG9yIE5vbmUsIHRvIGxvYWQgbW9kZWwgaW4gYXBwcm9wcmlhdGUgd2F5CiAgICA6cGFyYW0gdXNlX2N1ZGE6IHVzZSBncHUgb3Igbm90CiAgICA6cGFyYW0gdG9rZW5pemVyX3ByZXRyYWluZWRfY29uZmlnOiBjb25maWcgdG8gbG9hZCB0aGUgcHJldHJhaW5lZCB0b2tlbml6ZXIKICAgIDpwYXJhbSBtb2RlbF9wcmV0cmFpbmVkX2NvbmZpZzogY29uZmlnIHRvIGxvYWQgdGhlIHByZXRyYWluZWQgbW9kZWwKICAgIDpwYXJhbSBkZXZpY2VfbWFwOiBhIGRldmljZSBtYXAgZm9yIG1vZGVsIHRyYWluaW5nIGlmIHVzaW5nIG51bWJlciBvZiBncHUncwoKICAgIDpyZXR1cm5zOiBtb2RlbCBhbmQgdG9rZW5pemVyCiAgICAiIiIKICAgICMgaWYgdGFzayBpcyBub3Qgc3VwcG9ydGVkIGFuZCBubyBtb2RlbCB3YXMgZ2l2ZW4gd2UgY2FuJ3QgY2hvb3NlIG9uZQogICAgaWYgdGFzayBhbmQgdGFzayBub3QgaW4gc3VwcG9ydGVkX3Rhc2tzIGFuZCBub3QgbW9kZWw6CiAgICAgICAgbG9nZ2VyLmVycm9yKCJ1bnN1cHBvcnRlZCB0YXNrIG9wdGlvbiBjaG9zZW4iKQogICAgICAgIHJhaXNlCgogICAgIyBsb2FkIG1vZGVsIGZyb20gc3RvcmUKICAgIGlmIGlzaW5zdGFuY2UobW9kZWwsIHN0cikgYW5kIGlzX3N0b3JlX3VyaShtb2RlbCk6CiAgICAgICAgcGFzcwogICAgICAgICMgVE9ETzogbG9hZCBib3RoIG1vZGVsIGFuZCB0b2tlbml6ZXIgYW5kIHJldHVybiwgbmVlZCBndXkncyBoZWxwCgogICAgIyBpZiBpdCdzIGEgdHVwbGUgdGhlbSB3ZSBhc3N1bWUgaXQgY29udGFpbnMgb2YgYm90aCBuYW1lIGFuZCBjbGFzcwogICAgaWYgaXNpbnN0YW5jZShtb2RlbCwgbGlzdCk6CiAgICAgICAgbW9kZWxfbmFtZSwgbW9kZWxfY2xhc3MgPSBtb2RlbAogICAgICAgIG1vZGVsX2NsYXNzID0gX2dldF9jbGFzc19vYmplY3QobW9kZWxfY2xhc3MpCgogICAgIyBpbiB0aGUgY2FzZSB3ZSBkb24ndCBnZXQgdGhlIG1vZGVsIGNsYXNzIHdlIG5lZWQgdGhlIHRhc2sgaW4gb3JkZXIgdG8gY2hvb3NlIHRoZSBjb3JyZWN0IG1vZGVsCiAgICBlbHNlOgogICAgICAgIGlmIHRhc2sgaXMgTm9uZToKICAgICAgICAgICAgbG9nZ2VyLmVycm9yKCJ0YXNrIG11c3QgYmUgY2hvc2VuIGluIG9yZGVyIHRvIGRldGVybWluZSB0aGUgY29ycmVjdCBtb2RlbCIpCiAgICAgICAgICAgIHJhaXNlIEV4Y2VwdGlvbigKICAgICAgICAgICAgICAgICJ0aGlzIGZ1bmN0aW9uIHJlcXVpcmVzIGVpdGhlciBhIHN1cHBvcnRlZCB0YXNrIG9yIGEgbW9kZWwgYW5kIG1vZGVsIGNsYXNzIHRvIGJlIGNob3NlbiIKICAgICAgICAgICAgKQoKICAgICAgICBfLCBhdmFpbGFibGVfY2xhc3NlcywgdGFza19vcHRpb25zID0gdHJhbnNmb3JtZXJzLnBpcGVsaW5lcy5jaGVja190YXNrKHRhc2spCgogICAgICAgIGlmIGlzaW5zdGFuY2UobW9kZWwsIHN0cik6CiAgICAgICAgICAgIG1vZGVsX25hbWUgPSBtb2RlbAoKICAgICAgICAjIGlmIG1vZGVsIGlzIG5vdCBnaXZlbiwgd2UgdGFrZSB0aGUgZGVmYXVsdCBtb2RlbCBmb3IgdGhlIGdpdmVuIHRhc2sKICAgICAgICBlbHNlOgogICAgICAgICAgICBtb2RlbF9uYW1lLCBfID0gdHJhbnNmb3JtZXJzLnBpcGVsaW5lcy5nZXRfZGVmYXVsdF9tb2RlbF9hbmRfcmV2aXNpb24oCiAgICAgICAgICAgICAgICBhdmFpbGFibGVfY2xhc3NlcywgZnJhbWV3b3JrLCB0YXNrX29wdGlvbnMKICAgICAgICAgICAgKQogICAgICAgIGlmIG5vdCBhdmFpbGFibGVfY2xhc3Nlcy5nZXQoZnJhbWV3b3JrLCB0dXBsZSgpKToKICAgICAgICAgICAgbG9nZ2VyLmVycm9yKAogICAgICAgICAgICAgICAgImdpdmVuIHRhc2sncyBkZWZhdWx0IG1vZGVsIGlzIG5vdCBzdXBwb3J0ZWQgaW4gc3BlY2lmaWVkIGZyYW1ld29yayIKICAgICAgICAgICAgKQogICAgICAgICAgICByYWlzZSBFeGNlcHRpb24oCiAgICAgICAgICAgICAgICAidGhpcyBmdW5jdGlvbiByZXF1aXJlcyBlaXRoZXIgYSBzdXBwb3J0ZWQgdGFzayBvciBhIG1vZGVsIGFuZCBtb2RlbCBjbGFzcyB0byBiZSBjaG9zZW4iCiAgICAgICAgICAgICkKCiAgICAgICAgbW9kZWxfY2xhc3MgPSBhdmFpbGFibGVfY2xhc3Nlc1tmcmFtZXdvcmtdWzBdCgogICAgIyBsb2FkIHRoZSBwcmV0cmFpbmVkIG1vZGVsCiAgICBpZiB1c2VfY3VkYToKICAgICAgICBkZXZpY2VfbWFwID0gZGV2aWNlX21hcAogICAgZWxzZToKICAgICAgICBkZXZpY2VfbWFwID0gTm9uZQoKICAgIG1vZGVsID0gbW9kZWxfY2xhc3MuZnJvbV9wcmV0cmFpbmVkKAogICAgICAgIG1vZGVsX25hbWUsCiAgICAgICAgcXVhbnRpemF0aW9uX2NvbmZpZz1xdWFudGl6YXRpb25fY29uZmlnLAogICAgICAgIGRldmljZV9tYXA9ZGV2aWNlX21hcCwKICAgICAgICAqKm1vZGVsX3ByZXRyYWluZWRfY29uZmlnLAogICAgKQoKICAgICMgSWYgcXVhbnRpemF0aW9uIGNvbmZpZyBpcyBnaXZlbiB3ZSB3aWxsIGxvYWQgYSBxdWFudGl6ZWQgbW9kZWwsIGlmIG5vdCBhIHJlZ3VsYXIgb25lCiAgICBpZiBxdWFudGl6YXRpb25fY29uZmlnOgogICAgICAgIG1vZGVsLmdyYWRpZW50X2NoZWNrcG9pbnRpbmdfZW5hYmxlKCkKICAgICAgICBtb2RlbCA9IHBlZnQucHJlcGFyZV9tb2RlbF9mb3Jfa2JpdF90cmFpbmluZyhtb2RlbCkKCiAgICAjIElmIGxvcmEgY29uZmlnIHdhcyBnaXZlbiB3ZSB3YW50IHRvIGRvIGxvcmEgZmluZSB0dW5lLCB3ZSB1cGRhdGUgbW9kZWwgaGVyZQogICAgaWYgbG9yYV9jb25maWc6CiAgICAgICAgbW9kZWwgPSBwZWZ0LmdldF9wZWZ0X21vZGVsKG1vZGVsLCBsb3JhX2NvbmZpZykKCiAgICAjIGlmIG5vdCBzcGVjaWZpZWQgd2UgY2hvb3NlIHRoZSBkZWZhdWx0IHRva2VuaXplciB0aGF0IGNvcnJlc3BvbmRpbmcgdG8gdGhlIG1vZGVsCiAgICBpZiB0b2tlbml6ZXIgaXMgTm9uZToKICAgICAgICB0b2tlbml6ZXIgPSB0cmFuc2Zvcm1lcnMuQXV0b1Rva2VuaXplci5mcm9tX3ByZXRyYWluZWQobW9kZWxfbmFtZSkKICAgICAgICByZXR1cm4gbW9kZWxfbmFtZSwgbW9kZWwsIHRva2VuaXplcgoKICAgIGlmIGlzaW5zdGFuY2UodG9rZW5pemVyLCBzdHIpOgogICAgICAgIHRva2VuaXplcl9uYW1lID0gdG9rZW5pemVyCiAgICAgICAgdG9rZW5pemVyX2NsYXNzID0gdHJhbnNmb3JtZXJzLkF1dG9Ub2tlbml6ZXIKCiAgICAjIGlmIGl0J3Mgbm90IGEgc3RyIHRoZW4gaXQncyBhIHR1cGxlIG9mIGJvdGggbmFtZSBhbmQgY2xhc3MKICAgIGVsc2U6CiAgICAgICAgdG9rZW5pemVyX25hbWUsIHRva2VuaXplcl9jbGFzcyA9IHRva2VuaXplcgogICAgICAgIHRva2VuaXplcl9jbGFzcyA9IF9nZXRfY2xhc3Nfb2JqZWN0KHRva2VuaXplcl9jbGFzcykKCiAgICB0b2tlbml6ZXIgPSB0b2tlbml6ZXJfY2xhc3MuZnJvbV9wcmV0cmFpbmVkKAogICAgICAgIHRva2VuaXplcl9uYW1lLCAqKnRva2VuaXplcl9wcmV0cmFpbmVkX2NvbmZpZwogICAgKQoKICAgIHRva2VuaXplci5wYWRfdG9rZW4gPSB0b2tlbml6ZXIuZW9zX3Rva2VuCgogICAgcmV0dXJuIG1vZGVsX25hbWUsIG1vZGVsLCB0b2tlbml6ZXIKCgpkZWYgX2RhdGFzZXRfbG9hZGVyKGRhdGFzZXQ6IHN0ciwgaXNfdHJhaW46IGJvb2wgPSBUcnVlLCAqKmt3YXJncykgLT4gRGF0YXNldDoKICAgICIiIgogICAgbG9hZHMgdGhlIHNwZWNpZmljIGRhdGFzZXQgcHJvdmlkZWQgYnkgdGhlIHVzZXIKCiAgICA6cGFyYW0gZGF0YXNldDogbmFtZSBvciBwYXRoIG9mIGRhdGFzZXQgdG8gbG9hZAogICAgOnBhcmFtIGlzX3RyYWluOiBib29sIHRoYXQgaW5kaWNhdGVzIHRoZSBwdXJwb3NlIG9mIHRoZSBkYXRhc2V0CiAgICA6cGFyYW0ga3dhcmdzOiBvdGhlciBrd2FyZ3MgZm9yIGxvYWRpbmcgdGhlIGRhdGFzZXQKCiAgICA6cmV0dXJuczogbG9hZGVkIGRhdGFzZXQKICAgICIiIgogICAgIyBpZiBzcGxpdCBpbiBrd2FyZ3MgdGhlbiB0aGUgdXNlciBkZWNpZGVzIGhvdyB0byBzcGxpdCB0aGUgZGF0YXNldAogICAgaWYgInNwbGl0IiBpbiBrd2FyZ3M6CiAgICAgICAgcmV0dXJuIGxvYWRfZGF0YXNldChkYXRhc2V0LCAqKmt3YXJncykKCiAgICAjIGlmIGl0J3MgYSBkYXRhc2V0IGZvciB0cmFpbiB3ZSBzcGxpdCB3aXRoIHRyYWluCiAgICBpZiBpc190cmFpbjoKICAgICAgICByZXR1cm4gbG9hZF9kYXRhc2V0KGRhdGFzZXQsIHNwbGl0PSJ0cmFpbiIsICoqa3dhcmdzKQoKICAgICMgaWYgaXQncyBldmFsIGRhdGFzZXQsIHRoZW4gYSBsb3Qgb2YgbmFtZXMgYXJlIGFjY2VwdGFibGUgZm9yIHRoZSBzZXQgYW5kIHdlIGNoZWNrIGFsbCBvZiB0aGVtCiAgICBkYXRhc2V0ID0gbG9hZF9kYXRhc2V0KGRhdGFzZXQsICoqa3dhcmdzKQogICAgaWYgInRlc3QiIGluIGRhdGFzZXQ6CiAgICAgICAgcmV0dXJuIGRhdGFzZXQuZ2V0KCJ0ZXN0IikKICAgIGVsaWYgImV2YWwiIGluIGRhdGFzZXQ6CiAgICAgICAgcmV0dXJuIGRhdGFzZXQuZ2V0KCJldmFsIikKICAgIGVsaWYgInZhbGlkYXRpb24iIGluIGRhdGFzZXQ6CiAgICAgICAgcmV0dXJuIGRhdGFzZXQuZ2V0KCJ2YWxpZGF0aW9uIikKCgpkZWYgX3ByZXBhcmVfZGF0YXNldCgKICAgIHRyYWluX2RhdGFzZXQ6IHN0ciwKICAgIGV2YWxfZGF0YXNldDogc3RyLAogICAgdHJhaW5fbG9hZF9kYXRhc2V0X2t3YXJncywKICAgIGV2YWxfbG9hZF9kYXRhc2V0X2t3YXJncywKICAgIHRva2VuaXplciwKICAgIGRhdGFzZXRfY29sdW1uc190b190cmFpbjogVW5pb25bc3RyLCBsaXN0XSwKKSAtPiAoRGF0YXNldCwgVW5pb25bRGF0YXNldCwgTm9uZV0pOgogICAgIiIiCiAgICBMb2FkcyB0aGUgdHJhaW4gYW5kIGV2YWwgZGF0YXNldHMgKGlmIHByb3ZpZGVkKSBwYXNzZXMgdGhlbSB0aHJvdWdoIHRoZSB0b2tlbml6ZXIgYW5kCiAgICByZXR1cm5zIHRoZW0gcmVhZHkgdG8gdXNlIGluIHRyYWluaW5nCgogICAgOnBhcmFtIHRyYWluX2RhdGFzZXQ6IHRoZSBuYW1lIG9yIHBhdGggdG8gdGhlIHRyYWluIGRhdGFzZXQKICAgIDpwYXJhbSBldmFsX2RhdGFzZXQ6IHRoZSBuYW1lIG9yIHBhdGggdG8gdGhlIGV2YWwgZGF0YXNldAogICAgOnBhcmFtIGRhdGFzZXRfY29sdW1uc190b190cmFpbjogd2hpY2ggY29sdW1ucyB0byBwYXNzIHRvIHRoZSBtb2RlbCBhcyBpbnB1dHMKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChuZWVkIHRvIHBhc3MgdGhyb3VnaCB0aGUgdG9rZW5pemVyIGZpcnN0KQogICAgOnBhcmFtIHRyYWluX2xvYWRfZGF0YXNldF9rd2FyZ3M6IGt3YXJncyBmb3IgZGF0YXNldCBsb2FkaW5nCiAgICA6cGFyYW0gZXZhbF9sb2FkX2RhdGFzZXRfa3dhcmdzOiBrd2FyZ3MgZm9yIGRhdGFzZXQgbG9hZGluZwogICAgOnBhcmFtIHRva2VuaXplcjogdGhlIHRva2VuaXplciB0byBwYXNzIHRoZSBkYXRhIHRocm91Z2gKCiAgICA6cmV0dXJuczogdG9rZW5pemVkIGRhdGFzZXRzCiAgICAiIiIKICAgIGlmIG5vdCB0b2tlbml6ZXIucGFkX3Rva2VuOgogICAgICAgIHRva2VuaXplci5wYWRfdG9rZW4gPSB0b2tlbml6ZXIuZW9zX3Rva2VuCgogICAgIyB3ZSB0YWtlIGNvbCBuYW1lL3MgaW4gYSBsaXN0IGZvciBlYXN5IGdlbmVyYWxpemF0aW9uCiAgICBpZiBpc2luc3RhbmNlKGRhdGFzZXRfY29sdW1uc190b190cmFpbiwgc3RyKToKICAgICAgICBkYXRhc2V0X2NvbHVtbnNfdG9fdHJhaW4gPSBbZGF0YXNldF9jb2x1bW5zX3RvX3RyYWluXQoKICAgIGlmIGlzaW5zdGFuY2UodHJhaW5fZGF0YXNldCwgbWxydW4uZGF0YXN0b3JlLkRhdGFJdGVtKToKICAgICAgICB0cmFpbl9kYXRhc2V0ID0gRGF0YXNldC5mcm9tX3BhbmRhcyh0cmFpbl9kYXRhc2V0LmFzX2RmKCkpCiAgICAgICAgcmV0dXJuICgKICAgICAgICAgICAgdHJhaW5fZGF0YXNldC5tYXAoCiAgICAgICAgICAgICAgICBsYW1iZGEgZXhhbXBsZXM6IHRva2VuaXplcigKICAgICAgICAgICAgICAgICAgICAqW2V4YW1wbGVzW2NvbF0gZm9yIGNvbCBpbiBkYXRhc2V0X2NvbHVtbnNfdG9fdHJhaW5dLAogICAgICAgICAgICAgICAgICAgIHRydW5jYXRpb249VHJ1ZSwKICAgICAgICAgICAgICAgICAgICBwYWRkaW5nPVRydWUsCiAgICAgICAgICAgICAgICApLAogICAgICAgICAgICAgICAgYmF0Y2hlZD1UcnVlLAogICAgICAgICAgICApLAogICAgICAgICAgICBOb25lLAogICAgICAgICkKCiAgICAjIExvYWQgZGF0YXNldHMKICAgICMgaWYgcHJvdmlkZWQgdHdvIHBhdGhzL25hbWVzIHdlIGxvYWQgZWFjaCBzZXBhcmF0ZWx5IHVzaW5nIGRlc2lnbmF0ZWQgZnVuYwogICAgaWYgZXZhbF9kYXRhc2V0OgogICAgICAgIHRyYWluX2RhdGFzZXQgPSBfZGF0YXNldF9sb2FkZXIoCiAgICAgICAgICAgIGRhdGFzZXQ9dHJhaW5fZGF0YXNldCwgaXNfdHJhaW49VHJ1ZSwgKip0cmFpbl9sb2FkX2RhdGFzZXRfa3dhcmdzCiAgICAgICAgKQogICAgICAgIGV2YWxfZGF0YXNldCA9IF9kYXRhc2V0X2xvYWRlcigKICAgICAgICAgICAgZGF0YXNldD1ldmFsX2RhdGFzZXQsIGlzX3RyYWluPUZhbHNlLCAqKmV2YWxfbG9hZF9kYXRhc2V0X2t3YXJncwogICAgICAgICkKCiAgICAjIGlmIG9ubHkgb24gcGF0aCBpcyBnaXZlbiB0aGVuIHdlIG11c3QgY2hlY2sgaWYgaXQgY29udGFpbnMgYm90aCBkYXRhc2V0IG9yIGlmIG9ubHkgb25lIHNob3VsZCBiZSB1c2VkCiAgICBlbHNlOgogICAgICAgIGRhdGFzZXQgPSBsb2FkX2RhdGFzZXQodHJhaW5fZGF0YXNldCwgKip0cmFpbl9sb2FkX2RhdGFzZXRfa3dhcmdzKQogICAgICAgIGlmICJ0cmFpbiIgaW4gZGF0YXNldDoKICAgICAgICAgICAgdHJhaW5fZGF0YXNldCA9IGRhdGFzZXQuZ2V0KCJ0cmFpbiIpCiAgICAgICAgICAgIGlmICJ0ZXN0IiBpbiBkYXRhc2V0OgogICAgICAgICAgICAgICAgZXZhbF9kYXRhc2V0ID0gZGF0YXNldC5nZXQoInRlc3QiKQogICAgICAgICAgICBlbGlmICJldmFsIiBpbiBkYXRhc2V0OgogICAgICAgICAgICAgICAgZXZhbF9kYXRhc2V0ID0gZGF0YXNldC5nZXQoImV2YWwiKQogICAgICAgICAgICBlbGlmICJ2YWxpZGF0aW9uIiBpbiBkYXRhc2V0OgogICAgICAgICAgICAgICAgZXZhbF9kYXRhc2V0ID0gZGF0YXNldC5nZXQoInZhbGlkYXRpb24iKQogICAgICAgICAgICBlbHNlOgogICAgICAgICAgICAgICAgIyBvbmx5IHRyYWluIGRhdGFzZXQgZ2l2ZW4sIHRva2VuaXplIGFuZCByZXR1cm4gaXQKICAgICAgICAgICAgICAgIHJldHVybiAoCiAgICAgICAgICAgICAgICAgICAgdHJhaW5fZGF0YXNldC5tYXAoCiAgICAgICAgICAgICAgICAgICAgICAgIGxhbWJkYSBleGFtcGxlczogdG9rZW5pemVyKAogICAgICAgICAgICAgICAgICAgICAgICAgICAgKltleGFtcGxlc1tjb2xdIGZvciBjb2wgaW4gZGF0YXNldF9jb2x1bW5zX3RvX3RyYWluXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRydW5jYXRpb249VHJ1ZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhZGRpbmc9VHJ1ZSwKICAgICAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICAgICAgICAgICAgYmF0Y2hlZD1UcnVlLAogICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgICAgICAgTm9uZSwKICAgICAgICAgICAgICAgICkKICAgICAgICBlbHNlOgogICAgICAgICAgICBsb2dnZXIuZXJyb3IoInRyYWluIGRhdGFzZXQgaXMgbWFuZGF0b3J5IikKICAgICAgICAgICAgcmFpc2UgS2V5RXJyb3IoIm5vIHRyYWluIGRhdGFzZXQgZm91bmQgaW4gZ2l2ZW4gZGF0YXNldCIpCgogICAgIyBUb2tlbml6ZSB0aGUgZGF0YSBzbyB0aGUgbW9kZWwgY2FuIHVuZGVyc3RhbmQgaXQKICAgIHRva2VuaXplZF90cmFpbl9kYXRhc2V0ID0gdHJhaW5fZGF0YXNldC5tYXAoCiAgICAgICAgbGFtYmRhIGV4YW1wbGVzOiB0b2tlbml6ZXIoCiAgICAgICAgICAgICpbZXhhbXBsZXNbY29sXSBmb3IgY29sIGluIGRhdGFzZXRfY29sdW1uc190b190cmFpbl0sCiAgICAgICAgICAgIHRydW5jYXRpb249VHJ1ZSwKICAgICAgICAgICAgcGFkZGluZz1UcnVlLAogICAgICAgICksCiAgICAgICAgYmF0Y2hlZD1UcnVlLAogICAgKQoKICAgIHRva2VuaXplZF9ldmFsX2RhdGFzZXQgPSBldmFsX2RhdGFzZXQubWFwKAogICAgICAgIGxhbWJkYSBleGFtcGxlczogdG9rZW5pemVyKAogICAgICAgICAgICAqW2V4YW1wbGVzW2NvbF0gZm9yIGNvbCBpbiBkYXRhc2V0X2NvbHVtbnNfdG9fdHJhaW5dLAogICAgICAgICAgICB0cnVuY2F0aW9uPVRydWUsCiAgICAgICAgICAgIHBhZGRpbmc9VHJ1ZSwKICAgICAgICApLAogICAgICAgIGJhdGNoZWQ9VHJ1ZSwKICAgICkKCiAgICByZXR1cm4gdG9rZW5pemVkX3RyYWluX2RhdGFzZXQsIHRva2VuaXplZF9ldmFsX2RhdGFzZXQKCgpkZWYgZmluZXR1bmVfbGxtKAogICAgY29udGV4dDogbWxydW4uTUxDbGllbnRDdHgsCiAgICB0cmFpbl9kYXRhc2V0OiBVbmlvbltzdHIsIG1scnVuLmRhdGFzdG9yZS5EYXRhSXRlbV0sCiAgICBldmFsX2RhdGFzZXQ6IHN0ciA9IE5vbmUsCiAgICB0cmFpbl9sb2FkX2RhdGFzZXRfa3dhcmdzOiBkaWN0ID0ge30sCiAgICBldmFsX2xvYWRfZGF0YXNldF9rd2FyZ3M6IGRpY3QgPSB7fSwKICAgIGRhdGFzZXRfY29sdW1uc190b190cmFpbjogVW5pb25bc3RyLCBsaXN0XSA9ICJ0ZXh0IiwKICAgIG1vZGVsOiBVbmlvbltzdHIsIExpc3Rbc3RyXV0gPSAiaHVnZ2luZ2ZhY2UtbW9kZWwiLAogICAgdG9rZW5pemVyOiBVbmlvbltzdHIsIExpc3Rbc3RyXV0gPSBOb25lLAogICAgZGVlcHNwZWVkX2NvbmZpZzogVW5pb25bZGljdCwgYm9vbF0gPSBGYWxzZSwKICAgIHF1YW50aXphdGlvbl9jb25maWc6IFVuaW9uW2RpY3QsIGJvb2xdID0gRmFsc2UsCiAgICBsb3JhX2NvbmZpZzogVW5pb25bZGljdCwgYm9vbF0gPSBGYWxzZSwKICAgIHRyYWluaW5nX2NvbmZpZzogZGljdCA9IHt9LAogICAgbW9kZWxfcHJldHJhaW5lZF9jb25maWc6IGRpY3QgPSB7fSwKICAgIHRva2VuaXplcl9wcmV0cmFpbmVkX2NvbmZpZzogZGljdCA9IHt9LAogICAgZGF0YV9jb2xsYXRvcl9jb25maWc6IGRpY3QgPSB7fSwKICAgIHRhc2s6IHN0ciA9ICJ0ZXh0LWdlbmVyYXRpb24iLAogICAgdXNlX2N1ZGE6IGJvb2wgPSBUcnVlLAogICAgZnJhbWV3b3JrOiBzdHIgPSAicHQiLAogICAgZGV2aWNlX21hcDogc3RyID0gImF1dG8iLAogICAgKiprd2FyZ3MsCik6CiAgICAiIiIKICAgIEZpbmUtdHVuZXMgYSBMYW5ndWFnZSBNb2RlbCAoTExNKSBvbiBhIHNwZWNpZmljIHRhc2sgdXNpbmcgdGhlIHByb3ZpZGVkIGRhdGFzZXQuCiAgICAgVGhlIGZ1bmN0aW9uIHRha2VzIHZhcmlvdXMgY29uZmlndXJhdGlvbiBwYXJhbWV0ZXJzIHRvIGN1c3RvbWl6ZSB0aGUgdHJhaW5pbmcgcHJvY2VzcwogICAgIGFuZCBhZGFwdCB0aGUgbW9kZWwgdG8gc3BlY2lmaWMgdGFza3MgdXNpbmcgYSBwcm92aWRlZCBkYXRhc2V0LgoKICAgIDpwYXJhbSBjb250ZXh0OiBtbHJ1biBjb250ZXh0IGluIG9yZGVyIHRvIGxvZyB0cmFpbmVkIG1vZGVsCiAgICA6cGFyYW0gZGF0YXNldF9jb2x1bW5zX3RvX3RyYWluOiB3aGljaCBjb2x1bW5zIHRvIHBhc3MgdG8gdGhlIG1vZGVsIGFzIGlucHV0cwogICAgOnBhcmFtIGV2YWxfbG9hZF9kYXRhc2V0X2t3YXJnczoga3dhcmdzIGZvciBkYXRhc2V0IGxvYWRpbmcKICAgIDpwYXJhbSB0cmFpbl9sb2FkX2RhdGFzZXRfa3dhcmdzOiBrd2FyZ3MgZm9yIGRhdGFzZXQgbG9hZGluZwogICAgOnBhcmFtIGZyYW1ld29yazogcHQgb3QgdGYKICAgIDpwYXJhbSB1c2VfY3VkYTogdXNlIGdwdSBvciBub3QKICAgIDpwYXJhbSB0b2tlbml6ZXJfcHJldHJhaW5lZF9jb25maWc6IGNvbmZpZyB0byBsb2FkIHRoZSBwcmV0cmFpbmVkIHRva2VuaXplcgogICAgOnBhcmFtIG1vZGVsX3ByZXRyYWluZWRfY29uZmlnOiBjb25maWcgdG8gbG9hZCB0aGUgcHJldHJhaW5lZCBtb2RlbAogICAgOnBhcmFtIHRva2VuaXplcjogYSB0dXBsZSBjb250YWluaW5nIHRva2VuaXplciBuYW1lIGFuZCBjbGFzcywgb3Igc3RyIHdpdGggdG9rZW5pemVyIG5hbWUgb3IgcGF0aAogICAgOnBhcmFtIG1vZGVsOiBhIHR1cGxlIGNvbnRhaW5pbmcgbW9kZWwgbmFtZSBhbmQgY2xhc3MsIG9yIHN0ciB3aXRoIG1vZGVsIG5hbWUgb3IgcGF0aAogICAgOnBhcmFtIHRyYWluX2RhdGFzZXQ6IFRoZSB0cmFpbiBkYXRhc2V0IHVzZWQgZm9yIGZpbmUtdHVuaW5nIHRoZSBsYW5ndWFnZSBtb2RlbC4KICAgIDpwYXJhbSBldmFsX2RhdGFzZXQ6IFRoZSBldmFsIGRhdGFzZXQgdXNlZCBmb3IgZXZhbHVhdGUgdGhlIGxhbmd1YWdlIG1vZGVsIGR1cmluZyB0cmFpbmluZy4KICAgIDpwYXJhbSBkZWVwc3BlZWRfY29uZmlnOiBDb25maWd1cmF0aW9uIG9wdGlvbnMgZm9yIERlZXBTcGVlZCAob3B0aW9uYWwpLgogICAgOnBhcmFtIHF1YW50aXphdGlvbl9jb25maWc6IENvbmZpZ3VyYXRpb24gb3B0aW9ucyBmb3IgbW9kZWwgcXVhbnRpemF0aW9uIChvcHRpb25hbCkuCiAgICA6cGFyYW0gbG9yYV9jb25maWc6IENvbmZpZ3VyYXRpb24gb3B0aW9ucyBmb3IgTG93LVJhbmsgQXBwcm94aW1hdGlvbiAoTG9SQSkgKG9wdGlvbmFsKS4KICAgIDpwYXJhbSB0cmFpbmluZ19jb25maWc6IENvbmZpZ3VyYXRpb24gb3B0aW9ucyBzcGVjaWZpYyB0byB0aGUgZmluZS10dW5pbmcgdHJhaW5pbmcgcHJvY2VzcyAob3B0aW9uYWwpLgogICAgOnBhcmFtIGRhdGFfY29sbGF0b3JfY29uZmlnOiBDb25maWd1cmF0aW9uIG9wdGlvbnMgZm9yIGRhdGEgY29sbGF0aW9uIGR1cmluZyB0cmFpbmluZyAob3B0aW9uYWwpLgogICAgOnBhcmFtIHRhc2s6IEEgZGVzY3JpcHRpb24gb2YgdGhlIHNwZWNpZmljIHRhc2sgdGhlIG1vZGVsIGlzIGJlaW5nIGZpbmUtdHVuZWQgZm9yLgogICAgOnBhcmFtIGt3YXJnczogQWRkaXRpb25hbCBrZXl3b3JkIGFyZ3VtZW50cy4KICAgICIiIgoKICAgICMgVE9ETzogbWF0Y2ggZm9yd2FyZC5rZXl3b3JkIHRvIGRhdGFzZXQua2V5d29yZCAtIGNoZWNrIGlmIHJlbGV2YW50IGluIG5ldyBkZXNpZ24KICAgICMgVE9ETzogYWRkIHdhcm5pbmcgZm9yIGxhYmVsLCBhbmQgYWRkIG9wdGlvbiB0byBtb2RpZnkgZGF0YXNldCBjb2wgbmFtZXMgLSBjaGVjayBpZiByZWxldmFudCBpbiBuZXcgZGVzaWduCgogICAgIyBMb29rIGZvciB1cGRhdGVzIHRvIGNvbmZpZ3MgZ2l2ZW4gaW4ga3dhcmdzCiAgICBjb25maWdzID0gewogICAgICAgIENvbmZpZ0tleXMuZGVlcHNwZWVkOiBkZWVwc3BlZWRfY29uZmlnLAogICAgICAgIENvbmZpZ0tleXMucXVhbnRpemF0aW9uOiBxdWFudGl6YXRpb25fY29uZmlnLAogICAgICAgIENvbmZpZ0tleXMubG9yYTogbG9yYV9jb25maWcsCiAgICAgICAgQ29uZmlnS2V5cy50cmFpbmluZzogdHJhaW5pbmdfY29uZmlnLAogICAgICAgIENvbmZpZ0tleXMubW9kZWxfcHJldHJhaW5lZDogbW9kZWxfcHJldHJhaW5lZF9jb25maWcsCiAgICAgICAgQ29uZmlnS2V5cy50b2tlbml6ZXJfcHJldHJhaW5lZDogdG9rZW5pemVyX3ByZXRyYWluZWRfY29uZmlnLAogICAgICAgIENvbmZpZ0tleXMuZGF0YV9jb2xsYXRvcjogZGF0YV9jb2xsYXRvcl9jb25maWcsCiAgICB9CiAgICBfdXBkYXRlX2NvbmZpZyhkc3Q9Y29uZmlncywgc3JjPWt3YXJncykKCiAgICAjIGNoZWNrIGdwdSBwZXJtaXNzaW9uIGFuZCBhdmFpbGFiaWxpdHkKICAgIGlmIHVzZV9jdWRhOgogICAgICAgIGlmIHRvcmNoLmN1ZGEuaXNfYXZhaWxhYmxlKCk6CiAgICAgICAgICAgICMgQ2xlYW4gZ3B1IGNhY2hlCiAgICAgICAgICAgIHRvcmNoLmN1ZGEuZW1wdHlfY2FjaGUoKQogICAgICAgIGVsc2U6CiAgICAgICAgICAgIGxvZ2dlci53YXJuaW5nKCIndXNlX2N1ZGEnIGlzIHNldCB0byBUcnVlLCBidXQgbm8gY3VkYSBkZXZpY2UgaXMgYXZhaWxhYmxlIikKCiAgICAjIGdldCBtb2RlbCBhbmQgdG9rZW5pemVyCiAgICBtb2RlbF9uYW1lLCBtb2RlbCwgdG9rZW5pemVyID0gX3NldF9tb2RlbF9hbmRfdG9rZW5pemVyKAogICAgICAgIG1vZGVsPW1vZGVsLAogICAgICAgIHRva2VuaXplcj10b2tlbml6ZXIsCiAgICAgICAgdGFzaz10YXNrLAogICAgICAgIGZyYW1ld29yaz1mcmFtZXdvcmssCiAgICAgICAgbG9yYV9jb25maWc9Y29uZmlnc1tDb25maWdLZXlzLmxvcmFdLAogICAgICAgIHF1YW50aXphdGlvbl9jb25maWc9Y29uZmlnc1tDb25maWdLZXlzLnF1YW50aXphdGlvbl0sCiAgICAgICAgdXNlX2N1ZGE9dXNlX2N1ZGEsCiAgICAgICAgdG9rZW5pemVyX3ByZXRyYWluZWRfY29uZmlnPXRva2VuaXplcl9wcmV0cmFpbmVkX2NvbmZpZywKICAgICAgICBtb2RlbF9wcmV0cmFpbmVkX2NvbmZpZz1jb25maWdzW0NvbmZpZ0tleXMubW9kZWxfcHJldHJhaW5lZF0sCiAgICAgICAgZGV2aWNlX21hcD1kZXZpY2VfbWFwLAogICAgKQoKICAgICMgTG9hZCBkYXRhc2V0cwogICAgdG9rZW5pemVkX3RyYWluLCB0b2tlbml6ZWRfZXZhbCA9IF9wcmVwYXJlX2RhdGFzZXQoCiAgICAgICAgdHJhaW5fZGF0YXNldD10cmFpbl9kYXRhc2V0LAogICAgICAgIGV2YWxfZGF0YXNldD1ldmFsX2RhdGFzZXQsCiAgICAgICAgdHJhaW5fbG9hZF9kYXRhc2V0X2t3YXJncz10cmFpbl9sb2FkX2RhdGFzZXRfa3dhcmdzLAogICAgICAgIGV2YWxfbG9hZF9kYXRhc2V0X2t3YXJncz1ldmFsX2xvYWRfZGF0YXNldF9rd2FyZ3MsCiAgICAgICAgdG9rZW5pemVyPXRva2VuaXplciwKICAgICAgICBkYXRhc2V0X2NvbHVtbnNfdG9fdHJhaW49ZGF0YXNldF9jb2x1bW5zX3RvX3RyYWluLAogICAgKQoKICAgICMgSW5pdGlhbGl6ZSB0aGUgZGF0YSBjb2xsYXRvciBmb3IgdGhlIHRyYWluZXIgdG8gdXNlIGluIG9yZGVyIHRvIGNyZWF0ZSBiYXRjaGVzIG9mIGRhdGEKICAgIGRhdGFfY29sbGF0b3IgPSB0cmFuc2Zvcm1lcnMuRGF0YUNvbGxhdG9yRm9yTGFuZ3VhZ2VNb2RlbGluZygKICAgICAgICB0b2tlbml6ZXI9dG9rZW5pemVyLCBtbG09RmFsc2UsICoqZGF0YV9jb2xsYXRvcl9jb25maWcKICAgICkKCiAgICAjIEluaXRpYWxpemUgdHJhaW5pbmcga3dhcmdzIGZyb20gdXNlciBrd2FyZ3M6CiAgICB0cmFpbl9rd2FyZ3MgPSBjb25maWdzW0NvbmZpZ0tleXMudHJhaW5pbmddCgogICAgIyBJZiBkZWVwc3BlZWQgY29uZmlnIGdpdmVuIHdlIGFkZCBpdCB0byB0cmFpbmluZyBrd2FyZ3MKICAgIGlmIGNvbmZpZ3NbQ29uZmlnS2V5cy5kZWVwc3BlZWRdOgogICAgICAgIHRyYWluX2t3YXJnc1siZGVlcHNwZWVkIl0gPSBjb25maWdzW0NvbmZpZ0tleXMuZGVlcHNwZWVkXQoKICAgICMgVGFrZSBhIGxvb2sgYXQgdGhlIHRyYWluYWJsZSBwYXJhbWV0ZXJzIGluIHRoZSBtb2RlbAogICAgX3ByaW50X3RyYWluYWJsZV9wYXJhbWV0ZXJzKG1vZGVsKQoKICAgICMgUHJlcGFyaW5nIHRyYWluaW5nIGFyZ3VtZW50czoKICAgIHRyYWluaW5nX2FyZ3MgPSB0cmFuc2Zvcm1lcnMuVHJhaW5pbmdBcmd1bWVudHMoCiAgICAgICAgb3V0cHV0X2Rpcj10ZW1wZmlsZS5ta2R0ZW1wKCksCiAgICAgICAgKip0cmFpbl9rd2FyZ3MsCiAgICApCgogICAgdHJhaW5lciA9IHRyYW5zZm9ybWVycy5UcmFpbmVyKAogICAgICAgIG1vZGVsPW1vZGVsLAogICAgICAgIHRyYWluX2RhdGFzZXQ9dG9rZW5pemVkX3RyYWluLAogICAgICAgIGV2YWxfZGF0YXNldD10b2tlbml6ZWRfZXZhbCwKICAgICAgICB0b2tlbml6ZXI9dG9rZW5pemVyLAogICAgICAgIGRhdGFfY29sbGF0b3I9ZGF0YV9jb2xsYXRvciwKICAgICAgICBhcmdzPXRyYWluaW5nX2FyZ3MsCiAgICApCgogICAgYXBwbHlfbWxydW4odHJhaW5lciwgbW9kZWxfbmFtZT1tb2RlbF9uYW1lLnNwbGl0KCIvIilbLTFdKQogICAgbW9kZWwuY29uZmlnLnVzZV9jYWNoZSA9ICgKICAgICAgICBGYWxzZSAgIyBzaWxlbmNlIHRoZSB3YXJuaW5ncy4gUGxlYXNlIHJlLWVuYWJsZSBmb3IgaW5mZXJlbmNlIQogICAgKQoKICAgICMgQXBwbHkgdHJhaW5pbmcgd2l0aCBldmFsdWF0aW9uOgogICAgY29udGV4dC5sb2dnZXIuaW5mbyhmInRyYWluaW5nICd7bW9kZWxfbmFtZX0nIikKICAgIHRyYWluZXIudHJhaW4oKQoKICAgIHRlbXBfZGlyZWN0b3J5ID0gdGVtcGZpbGUuVGVtcG9yYXJ5RGlyZWN0b3J5KCkubmFtZQogICAgdHJhaW5lci5zYXZlX21vZGVsKHRlbXBfZGlyZWN0b3J5KQoKICAgICMgWmlwIHRoZSBtb2RlbCBkaXJlY3Rvcnk6CiAgICBzaHV0aWwubWFrZV9hcmNoaXZlKAogICAgICAgIGJhc2VfbmFtZT0ibW9kZWwiLAogICAgICAgIGZvcm1hdD0iemlwIiwKICAgICAgICByb290X2Rpcj10ZW1wX2RpcmVjdG9yeSwKICAgICkKCiAgICAjIExvZyB0aGUgbW9kZWw6CiAgICBjb250ZXh0LmxvZ19tb2RlbCgKICAgICAgICBrZXk9Im1vZGVsIiwKICAgICAgICBkYl9rZXk9bW9kZWxfbmFtZS5zcGxpdCgiLyIpWy0xXSwKICAgICAgICBtb2RlbF9maWxlPSJtb2RlbC56aXAiLAogICAgICAgIHRhZz0iIiwKICAgICAgICBmcmFtZXdvcms9Ikh1Z2dpbmcgRmFjZSIsCiAgICApCgoKZGVmIGV2YWx1YXRlKAogICAgY29udGV4dCwKICAgIG1vZGVsX3BhdGgsCiAgICBkYXRhOiBwZC5EYXRhRnJhbWUsCiAgICBtb2RlbF9uYW1lOiBzdHIgPSBOb25lLAogICAgdG9rZW5pemVyX25hbWU6IHN0ciA9IE5vbmUsCik6CiAgICAiIiIKICAgIEV2YWx1YXRpbmcgdGhlIG1vZGVsIHVzaW5nIHBlcnBsZXhpdHksIGZvciBtb3JlIGluZm9ybWF0aW9uIHZpc2l0OgogICAgaHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kb2NzL3RyYW5zZm9ybWVycy9wZXJwbGV4aXR5CgogICAgOnBhcmFtIGNvbnRleHQ6ICAgICBtbHJ1biBjb250ZXh0CiAgICA6cGFyYW0gbW9kZWxfcGF0aDogIHBhdGggdG8gdGhlIG1vZGVsIGRpcmVjdG9yeQogICAgOnBhcmFtIGRhdGE6ICAgICAgICB0aGUgZGF0YSB0byBldmFsdWF0ZSB0aGUgbW9kZWwKICAgIDpwYXJhbSBtb2RlbF9uYW1lOiAgbmFtZSBvZiBiYXNlIG1vZGVsCiAgICA6cGFyYW0gdG9rZW5pemVyX25hbWU6IG5hbWUgb2YgYmFzZSB0b2tlbml6ZXIKICAgICIiIgogICAgIyBHZXQgdGhlIG1vZGVsIGFydGlmYWN0IGFuZCBmaWxlOgogICAgKAogICAgICAgIG1vZGVsX2ZpbGUsCiAgICAgICAgbW9kZWxfYXJ0aWZhY3QsCiAgICAgICAgZXh0cmFfZGF0YSwKICAgICkgPSBtbHJ1bi5hcnRpZmFjdHMuZ2V0X21vZGVsKG1vZGVsX3BhdGgpCgogICAgIyBSZWFkIHRoZSBuYW1lOgogICAgX21vZGVsX25hbWUgPSBtb2RlbF9hcnRpZmFjdC5zcGVjLmRiX2tleQoKICAgICMgRXh0cmFjdCBsb2dnZWQgbW9kZWwgZmlsZXM6CiAgICBtb2RlbF9kaXJlY3RvcnkgPSBvcy5wYXRoLmpvaW4ob3MucGF0aC5kaXJuYW1lKG1vZGVsX2ZpbGUpLCBfbW9kZWxfbmFtZSkKICAgIHdpdGggemlwZmlsZS5aaXBGaWxlKG1vZGVsX2ZpbGUsICJyIikgYXMgemlwX2ZpbGU6CiAgICAgICAgemlwX2ZpbGUuZXh0cmFjdGFsbChtb2RlbF9kaXJlY3RvcnkpCgogICAgIyBMb2FkaW5nIHRoZSBzYXZlZCBwcmV0cmFpbmVkIHRva2VuaXplciBhbmQgbW9kZWw6CiAgICBkYXRhc2V0ID0gRGF0YXNldC5mcm9tX3BhbmRhcyhkYXRhKQogICAgdG9rZW5pemVyID0gQXV0b1Rva2VuaXplci5mcm9tX3ByZXRyYWluZWQodG9rZW5pemVyX25hbWUpCiAgICBwYWRfdG9rZW5faWQgPSB0b2tlbml6ZXIuZW9zX3Rva2VuX2lkCiAgICBtb2RlbCA9IEF1dG9Nb2RlbEZvckNhdXNhbExNLmZyb21fcHJldHJhaW5lZCgKICAgICAgICBtb2RlbF9uYW1lLCBkZXZpY2VfbWFwPSJjdWRhOjAiLCB0cnVzdF9yZW1vdGVfY29kZT1UcnVlLCBsb2FkX2luXzhiaXQ9VHJ1ZQogICAgKQogICAgbW9kZWwgPSBQZWZ0TW9kZWwuZnJvbV9wcmV0cmFpbmVkKG1vZGVsLCBtb2RlbF9kaXJlY3RvcnkpCiAgICBtb2RlbC5ldmFsKCkKICAgIGVuY29kaW5ncyA9IHRva2VuaXplcigiXG5cbiIuam9pbihkYXRhc2V0WyJ0ZXh0Il1bOjVdKSwgcmV0dXJuX3RlbnNvcnM9InB0IikKCiAgICBtYXhfbGVuZ3RoID0gMTAyNAogICAgc3RyaWRlID0gNTEyCiAgICBzZXFfbGVuID0gZW5jb2RpbmdzLmlucHV0X2lkcy5zaXplKDEpCgogICAgbmxscyA9IFtdCiAgICBwcmV2X2VuZF9sb2MgPSAwCiAgICBmb3IgYmVnaW5fbG9jIGluIHJhbmdlKDAsIHNlcV9sZW4sIHN0cmlkZSk6CiAgICAgICAgZW5kX2xvYyA9IG1pbihiZWdpbl9sb2MgKyBtYXhfbGVuZ3RoLCBzZXFfbGVuKQogICAgICAgIHRyZ19sZW4gPSBlbmRfbG9jIC0gcHJldl9lbmRfbG9jICAjIG1heSBiZSBkaWZmZXJlbnQgZnJvbSBzdHJpZGUgb24gbGFzdCBsb29wCiAgICAgICAgaW5wdXRfaWRzID0gZW5jb2RpbmdzLmlucHV0X2lkc1s6LCBiZWdpbl9sb2M6ZW5kX2xvY10KICAgICAgICB0YXJnZXRfaWRzID0gaW5wdXRfaWRzLmNsb25lKCkKICAgICAgICB0YXJnZXRfaWRzWzosIDotdHJnX2xlbl0gPSAtMTAwCgogICAgICAgIHdpdGggdG9yY2gubm9fZ3JhZCgpOgogICAgICAgICAgICBvdXRwdXRzID0gbW9kZWwoaW5wdXRfaWRzLmN1ZGEoKSwgbGFiZWxzPXRhcmdldF9pZHMpCgogICAgICAgICAgICAjIGxvc3MgaXMgY2FsY3VsYXRlZCB1c2luZyBDcm9zc0VudHJvcHlMb3NzIHdoaWNoIGF2ZXJhZ2VzIG92ZXIgdmFsaWQgbGFiZWxzCiAgICAgICAgICAgICMgTi5CLiB0aGUgbW9kZWwgb25seSBjYWxjdWxhdGVzIGxvc3Mgb3ZlciB0cmdfbGVuIC0gMSBsYWJlbHMsIGJlY2F1c2UgaXQgaW50ZXJuYWxseSBzaGlmdHMgdGhlIGxhYmVscwogICAgICAgICAgICAjIHRvIHRoZSBsZWZ0IGJ5IDEuCiAgICAgICAgICAgIG5lZ19sb2dfbGlrZWxpaG9vZCA9IG91dHB1dHMubG9zcwoKICAgICAgICBubGxzLmFwcGVuZChuZWdfbG9nX2xpa2VsaWhvb2QpCgogICAgICAgIHByZXZfZW5kX2xvYyA9IGVuZF9sb2MKICAgICAgICBpZiBlbmRfbG9jID09IHNlcV9sZW46CiAgICAgICAgICAgIGJyZWFrCgogICAgcHBsID0gdG9yY2guZXhwKHRvcmNoLnN0YWNrKG5sbHMpLm1lYW4oKSkuaXRlbSgpCiAgICBjb250ZXh0LmxvZ19yZXN1bHQoInBlcnBsZXhpdHkiLCBwcGwpCg== - commands: [] - code_origin: '' - origin_filename: '' - requirements: [] - entry_points: - add_interface: - name: add_interface - doc: '' - parameters: - - name: cls - - name: obj - type: Trainer - - name: restoration - type: MLRunInterfaceRestorationType - default: null - outputs: [] - lineno: 70 - has_varargs: false - has_kwargs: false - mlrun_train: - name: mlrun_train - doc: '' - parameters: - - name: cls - outputs: [] - lineno: 80 - has_varargs: false - has_kwargs: false - wrapper: - name: wrapper - doc: '' - parameters: - - name: self - type: Trainer - outputs: [] - lineno: 81 - has_varargs: true - has_kwargs: true - on_epoch_begin: - name: on_epoch_begin - doc: '' - parameters: - - name: self - - name: args - type: TrainingArguments - - name: state - type: TrainerState - - name: control - type: TrainerControl - outputs: [] - lineno: 129 - has_varargs: false - has_kwargs: true - on_epoch_end: - name: on_epoch_end - doc: '' - parameters: - - name: self - - name: args - type: TrainingArguments - - name: state - type: TrainerState - - name: control - type: TrainerControl - outputs: [] - lineno: 140 - has_varargs: false - has_kwargs: true - on_log: - name: on_log - doc: '' - parameters: - - name: self - - name: args - type: TrainingArguments - - name: state - type: TrainerState - - name: control - type: TrainerControl - - name: logs - type: Dict[str, float] - default: null - outputs: [] - lineno: 151 - has_varargs: false - has_kwargs: true - on_train_begin: - name: on_train_begin - doc: '' - parameters: - - name: self - - name: args - type: TrainingArguments - - name: state - type: TrainerState - - name: control - type: TrainerControl - outputs: [] - lineno: 177 - has_varargs: false - has_kwargs: true - on_train_end: - name: on_train_end - doc: '' - parameters: - - name: self - - name: args - type: TrainingArguments - - name: state - type: TrainerState - - name: control - type: TrainerControl - - name: model - type: PreTrainedModel - default: null - - name: tokenizer - type: PreTrainedTokenizer - default: null - outputs: [] - lineno: 188 - has_varargs: false - has_kwargs: true - on_evaluate: - name: on_evaluate - doc: '' - parameters: - - name: self - - name: args - type: TrainingArguments - - name: state - type: TrainerState - - name: control - type: TrainerControl - outputs: [] - lineno: 201 - has_varargs: false - has_kwargs: true - log_metrics: - name: log_metrics - doc: '' - parameters: - - name: self - outputs: [] - lineno: 215 - has_varargs: false - has_kwargs: false - log_metric_plot: - name: log_metric_plot - doc: '' - parameters: - - name: self - - name: name - type: str - - name: scores - type: List[float] - outputs: [] - lineno: 222 - has_varargs: false - has_kwargs: false - apply_mlrun: - name: apply_mlrun - doc: This is temporary and will be built in mlrun 1.5.0 - parameters: - - name: trainer - type: Trainer - - name: model_name - type: str - default: null - - name: tag - type: str - default: '' - - name: context - type: MLClientCtx - default: null - - name: auto_log - type: bool - default: true - - name: labels - type: Dict[str, str] - default: null - - name: extra_data - type: dict - default: null - outputs: [] - lineno: 244 - has_varargs: false - has_kwargs: true - finetune_llm: - name: finetune_llm - doc: "Fine-tunes a Language Model (LLM) on a specific task using the provided\ - \ dataset.\n The function takes various configuration parameters to customize\ - \ the training process\n and adapt the model to specific tasks using a provided\ - \ dataset." - parameters: - - name: context - type: MLClientCtx - doc: mlrun context in order to log trained model - - name: train_dataset - type: Union[str, mlrun.datastore.DataItem] - doc: The train dataset used for fine-tuning the language model. - - name: eval_dataset - type: str - doc: The eval dataset used for evaluate the language model during training. - default: null - - name: train_load_dataset_kwargs - type: dict - doc: kwargs for dataset loading - default: {} - - name: eval_load_dataset_kwargs - type: dict - doc: kwargs for dataset loading - default: {} - - name: dataset_columns_to_train - type: Union[str, list] - doc: which columns to pass to the model as inputs - default: text - - name: model - type: Union[str, List[str]] - doc: a tuple containing model name and class, or str with model name or path - default: huggingface-model - - name: tokenizer - type: Union[str, List[str]] - doc: a tuple containing tokenizer name and class, or str with tokenizer name - or path - default: null - - name: deepspeed_config - type: Union[dict, bool] - doc: Configuration options for DeepSpeed (optional). - default: false - - name: quantization_config - type: Union[dict, bool] - doc: Configuration options for model quantization (optional). - default: false - - name: lora_config - type: Union[dict, bool] - doc: Configuration options for Low-Rank Approximation (LoRA) (optional). - default: false - - name: training_config - type: dict - doc: Configuration options specific to the fine-tuning training process (optional). - default: {} - - name: model_pretrained_config - type: dict - doc: config to load the pretrained model - default: {} - - name: tokenizer_pretrained_config - type: dict - doc: config to load the pretrained tokenizer - default: {} - - name: data_collator_config - type: dict - doc: Configuration options for data collation during training (optional). - default: {} - - name: task - type: str - doc: A description of the specific task the model is being fine-tuned for. - default: text-generation - - name: use_cuda - type: bool - doc: use gpu or not - default: true - - name: framework - type: str - doc: pt ot tf - default: pt - - name: device_map - type: str - default: auto - outputs: [] - lineno: 630 - has_varargs: false - has_kwargs: true - evaluate: - name: evaluate - doc: 'Evaluating the model using perplexity, for more information visit: - - https://huggingface.co/docs/transformers/perplexity' - parameters: - - name: context - doc: mlrun context - - name: model_path - doc: path to the model directory - - name: data - type: DataFrame - doc: the data to evaluate the model - - name: model_name - type: str - doc: name of base model - default: null - - name: tokenizer_name - type: str - doc: name of base tokenizer - default: null - outputs: [] - lineno: 784 - has_varargs: false - has_kwargs: false - description: fine-tune llm model with ease - default_handler: finetune_llm - disable_auto_mount: false - clone_target_dir: '' - env: [] - priority_class_name: '' - preemption_mode: prevent - affinity: null - tolerations: null - security_context: {} -verbose: false diff --git a/huggingface_auto_trainer/huggingface_auto_trainer.ipynb b/huggingface_auto_trainer/huggingface_auto_trainer.ipynb deleted file mode 100644 index 847fa98d6..000000000 --- a/huggingface_auto_trainer/huggingface_auto_trainer.ipynb +++ /dev/null @@ -1,195 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "a2c5dc6d-33d0-4e74-a875-6eab556e3b2d", - "metadata": {}, - "source": [ - "# Llm auto trainer" - ] - }, - { - "cell_type": "markdown", - "id": "cc7aa261-17b2-4362-bf6a-34af79b0230b", - "metadata": {}, - "source": [ - "## Notebook Introduction: Fine-Tuning a Large Language Model with Ease\n", - "\n", - "Welcome to this example notebook that demonstrates a simplified yet powerful approach to fine-tuning a Large Language Model (LLM) effortlessly. Fine-tuning is a crucial technique that allows you to adapt pre-trained language models to specific tasks, making them more contextually relevant and useful.\n", - "\n", - "In this notebook, we will walk you through a step-by-step process of fine-tuning a state-of-the-art language model using a user-friendly and efficient method. You don't need to be an expert in machine learning or natural language processing to follow along – our approach focuses on simplicity and effectiveness." - ] - }, - { - "cell_type": "markdown", - "id": "425249e9-f43f-45e6-aa25-9f53099049cd", - "metadata": {}, - "source": [ - "### First, we will select the model we wish to fine-tune and take the matching tokenizer and appropriate config" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3410e9c2-0557-4961-995e-0ef0cc07bf82", - "metadata": {}, - "outputs": [], - "source": [ - "import os\n", - "from transformers import AutoTokenizer, AutoModelForCausalLM, GenerationConfig\n", - "from transformers import logging\n", - "\n", - "logging.set_verbosity(\"CRITICAL\")\n", - "\n", - "model_name = \"tiiuae/falcon-7b\"\n", - "tokenizer = model_name\n", - "generation_config = GenerationConfig.from_pretrained(model_name)" - ] - }, - { - "cell_type": "markdown", - "id": "f33f3c35-cf61-4b0f-8da9-1c30d3b53230", - "metadata": {}, - "source": [ - "### Then, in order to use with mlrun, we will create an mlrun project and create an mlrun function" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a8ee7c35-adf7-4ed8-9e7e-e659b9461cd5", - "metadata": {}, - "outputs": [], - "source": [ - "import mlrun\n", - "\n", - "project = mlrun.get_or_create_project(\n", - " name=\"auto-trainer-test\",\n", - " context=\"./\",\n", - " user_project=True,\n", - " parameters={\n", - " \"default_image\": \"yonishelach/mlrun-llm\",\n", - " },\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d56b834f-adf6-4736-8de7-3348e050f561", - "metadata": {}, - "outputs": [], - "source": [ - "project.set_function(\n", - " \"auto-trainer.py\",\n", - " name=\"auto-trainer\",\n", - " kind=\"job\",\n", - " image=\"yonishelach/mlrun-llm\",\n", - " handler=\"finetune_llm\",\n", - ")\n", - "project.save()" - ] - }, - { - "cell_type": "markdown", - "id": "f42315db-6ddd-4dc1-89f3-c732f92d0d47", - "metadata": {}, - "source": [ - "### we can set the every config or parameter we want, including training arguments, hyper parameters and more, and pass to the function" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8e62e577-15fb-477d-9c56-fa9fb4c2669b", - "metadata": {}, - "outputs": [], - "source": [ - "import transformers\n", - "\n", - "training_arguments = {\n", - " \"per_device_train_batch_size\": 4,\n", - " \"gradient_accumulation_steps\": 1,\n", - " \"warmup_steps\": 2,\n", - " \"max_steps\": 10,\n", - " \"learning_rate\": 2e-4,\n", - " \"fp16\": True,\n", - " \"logging_steps\": 1,\n", - " \"optim\": \"paged_adamw_8bit\",\n", - "}" - ] - }, - { - "cell_type": "markdown", - "id": "284a5772-f88d-46c9-87bc-fc14e434c1b4", - "metadata": {}, - "source": [ - "### Now we simply run the function" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "11ab5888-5870-4bf8-9657-db930adecd77", - "metadata": {}, - "outputs": [], - "source": [ - "training_run = mlrun.run_function(\n", - " function=\"auto-trainer\",\n", - " name=\"auto-trainer\",\n", - " local=True,\n", - " params={\n", - " \"model\": (model_name, \"transformers.AutoModelForCausalLM\"),\n", - " \"tokenizer\": tokenizer,\n", - " \"train_dataset\": \"Abirate/english_quotes\",\n", - " \"training_config\": training_arguments,\n", - " \"quantization_config\": True,\n", - " \"lora_config\": True,\n", - " \"dataset_columns_to_train\": \"quote\",\n", - " \"lora_target_modules\": [\"query_key_value\"],\n", - " \"model_pretrained_config\": {\"trust_remote_code\": True, \"use_cache\": False},\n", - " },\n", - " handler=\"finetune_llm\",\n", - " outputs=[\"model\"],\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0e674d25-5f1f-4ea8-af02-7d22c2fb6760", - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7a4dfe9b-407a-43c0-9c5e-56de106477ac", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "mlrun-base", - "language": "python", - "name": "conda-env-mlrun-base-py" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.9.16" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/huggingface_auto_trainer/huggingface_auto_trainer.py b/huggingface_auto_trainer/huggingface_auto_trainer.py deleted file mode 100644 index d1166318c..000000000 --- a/huggingface_auto_trainer/huggingface_auto_trainer.py +++ /dev/null @@ -1,855 +0,0 @@ -import importlib -import os -import shutil -import tempfile -import zipfile -from abc import ABC -from typing import Dict, List, Tuple, Union - -import mlrun -import numpy as np -import pandas as pd -import peft -import torch -import transformers -from datasets import Dataset, load_dataset -from mlrun.artifacts.manager import Artifact, PlotlyArtifact -from mlrun.datastore import is_store_uri -from mlrun.frameworks._common import CommonTypes, MLRunInterface -from mlrun.utils import logger -from peft import (LoraConfig, PeftModel, get_peft_model, - prepare_model_for_kbit_training) -from plotly import graph_objects as go -from transformers import (AutoModelForCausalLM, AutoTokenizer, - BitsAndBytesConfig, DataCollatorForLanguageModeling, - PreTrainedModel, PreTrainedTokenizer, Trainer, - TrainerCallback, TrainerControl, TrainerState, - TrainingArguments) - -supported_tasks = [ - "question-answering", - "summarization", - "table-question-answering", - "text2text-generation", - "text-classification", - "sentiment-analysis", - "text-generation", - "token-classification", - "translation", - "translation_xx_to_yy", -] - - -class ConfigKeys: - deepspeed = "deepspeed" - quantization = "quantization" - lora = "lora" - training = "training" - tokenizer_pretrained = "tokenizer_pretrained" - model_pretrained = "model_pretrained" - data_collator = "data_collator" - - -# ----------------------from MLRUN-------------------------------- -class HFTrainerMLRunInterface(MLRunInterface, ABC): - """ - This is temporary and will be built in mlrun 1.5.0 - Interface for adding MLRun features for tensorflow keras API. - """ - - # MLRuns context default name: - DEFAULT_CONTEXT_NAME = "mlrun-huggingface" - - # Attributes to replace so the MLRun interface will be fully enabled. - _REPLACED_METHODS = [ - "train", - # "evaluate" - ] - - @classmethod - def add_interface( - cls, - obj: Trainer, - restoration: CommonTypes.MLRunInterfaceRestorationType = None, - ): - super(HFTrainerMLRunInterface, cls).add_interface( - obj=obj, restoration=restoration - ) - - @classmethod - def mlrun_train(cls): - def wrapper(self: Trainer, *args, **kwargs): - # Restore the evaluation method as `train` will use it: - # cls._restore_attribute(obj=self, attribute_name="evaluate") - - # Call the original fit method: - result = self.original_train(*args, **kwargs) - - # Replace the evaluation method again: - # cls._replace_function(obj=self, function_name="evaluate") - - return result - - return wrapper - - -class MLRunCallback(TrainerCallback): - """ - This is temporary and will be built in mlrun 1.5.0 - Callback for collecting logs during training / evaluation of the `Trainer` API. - """ - - def __init__( - self, - context: mlrun.MLClientCtx = None, - model_name: str = "model", - tag: str = "", - labels: Dict[str, str] = None, - extra_data: dict = None, - ): - super().__init__() - - # Store the configurations: - self._context = ( - context - if context is not None - else mlrun.get_or_create_ctx("./mlrun-huggingface") - ) - self._model_name = model_name - self._tag = tag - self._labels = labels - self._extra_data = extra_data if extra_data is not None else {} - - # Set up the logging mode: - self._is_training = False - self._steps: List[List[int]] = [] - self._metric_scores: Dict[str, List[float]] = {} - self._artifacts: Dict[str, Artifact] = {} - - def on_epoch_begin( - self, - args: TrainingArguments, - state: TrainerState, - control: TrainerControl, - **kwargs, - ): - if not state.is_world_process_zero: - return - self._steps.append([]) - - def on_epoch_end( - self, - args: TrainingArguments, - state: TrainerState, - control: TrainerControl, - **kwargs, - ): - if not state.is_world_process_zero: - return - self.log_metrics() - - def on_log( - self, - args: TrainingArguments, - state: TrainerState, - control: TrainerControl, - logs: Dict[str, float] = None, - **kwargs, - ): - if not state.is_world_process_zero: - return - recent_logs = state.log_history[-1].copy() - - recent_logs.pop("epoch") - current_step = int(recent_logs.pop("step")) - if current_step not in self._steps[-1]: - self._steps[-1].append(current_step) - - for metric_name, metric_score in recent_logs.items(): - if metric_name.startswith("train_"): - if metric_name.split("train_")[1] not in self._metric_scores: - self._metric_scores[metric_name] = [metric_score] - continue - if metric_name not in self._metric_scores: - self._metric_scores[metric_name] = [] - self._metric_scores[metric_name].append(metric_score) - - def on_train_begin( - self, - args: TrainingArguments, - state: TrainerState, - control: TrainerControl, - **kwargs, - ): - if not state.is_world_process_zero: - return - self._is_training = True - - def on_train_end( - self, - args: TrainingArguments, - state: TrainerState, - control: TrainerControl, - model: PreTrainedModel = None, - tokenizer: PreTrainedTokenizer = None, - **kwargs, - ): - if not state.is_world_process_zero: - return - self.log_metrics() - - def on_evaluate( - self, - args: TrainingArguments, - state: TrainerState, - control: TrainerControl, - **kwargs, - ): - if not state.is_world_process_zero: - return - self.log_metrics() - - if self._is_training: - return - - def log_metrics(self): - for metric_name, metric_scores in self._metric_scores.items(): - self._context.log_result(key=metric_name, value=metric_scores[-1]) - if len(metric_scores) > 1: - self.log_metric_plot(name=metric_name, scores=metric_scores) - self._context.commit(completed=False) - - def log_metric_plot(self, name: str, scores: List[float]): - # Initialize a plotly figure: - metric_figure = go.Figure() - - # Add titles: - metric_figure.update_layout( - title=name.capitalize().replace("_", " "), - xaxis_title="Samples", - yaxis_title="Scores", - ) - - # Draw: - metric_figure.add_trace( - go.Scatter(x=np.arange(len(scores)), y=scores, mode="lines") - ) - - # Create the plotly artifact: - artifact_name = f"{name}_plot" - artifact = PlotlyArtifact(key=artifact_name, figure=metric_figure) - self._artifacts[artifact_name] = self._context.log_artifact(artifact) - - -def apply_mlrun( - trainer: transformers.Trainer, - model_name: str = None, - tag: str = "", - context: mlrun.MLClientCtx = None, - auto_log: bool = True, - labels: Dict[str, str] = None, - extra_data: dict = None, - **kwargs, -): - """ - This is temporary and will be built in mlrun 1.5.0 - """ - # Get parameters defaults: - if context is None: - context = mlrun.get_or_create_ctx(HFTrainerMLRunInterface.DEFAULT_CONTEXT_NAME) - - HFTrainerMLRunInterface.add_interface(obj=trainer) - - if auto_log: - trainer.add_callback( - MLRunCallback( - context=context, - model_name=model_name, - tag=tag, - labels=labels, - extra_data=extra_data, - ) - ) - - -# ----------------------end from MLRUN-------------------------------- - - -def _print_trainable_parameters(model): - """ - Prints the number of trainable parameters in the model. - """ - trainable_params = 0 - all_param = 0 - for _, param in model.named_parameters(): - all_param += param.numel() - if param.requires_grad: - trainable_params += param.numel() - print( - f"trainable params: {trainable_params} || all params: {all_param} || trainable%:" - f" {100 * trainable_params / all_param}" - ) - - -# default configs -# will be used if user provides "True" with config name as input -QUANTIZATION_CONFIG = transformers.BitsAndBytesConfig( - load_in_4bit=True, - bnb_4bit_use_double_quant=True, - bnb_4bit_quant_type="nf4", - bnb_4bit_compute_dtype=torch.bfloat16, -) - -LORA_CONFIG = peft.LoraConfig( - r=8, - lora_alpha=32, - target_modules=["query_key_value"], - lora_dropout=0.05, - bias="none", - task_type="CAUSAL_LM", -) - -DEEPSPEED_CONFIG = { - "train_micro_batch_size_per_gpu": "auto", - "fp16": {"enabled": True}, - "autotuning": { - "enabled": True, - "arg_mappings": { - "train_micro_batch_size_per_gpu": "--per_device_train_batch_size", - "gradient_accumulation_steps ": "--gradient_accumulation_steps", - }, - }, - "zero_optimization": { - "stage": 2, - }, -} - - -def _update_config(src: dict, dst: dict): - """ - update configs according to user, this way the user can add/modify values in default configs for e.g. - - goes over all configs and corresponding prefixes, collect all the keys from the given dict that start - with the prefix and add them to appropriate config - - :param src: dict of all candidate values to update dict. - :param dst: dict containing all configs to update. - """ - - for config_name, config in dst.items(): - - # If given True we use default dict - # Can also be False or a config dict given from user, so we check specifically fo True - if config is True and config_name == "quantization": - config = QUANTIZATION_CONFIG - - if config is True and config_name == "lora": - config = LORA_CONFIG - - if config is True and config_name == "deepspeed": - config = DEEPSPEED_CONFIG - - # in some cases we can get a boolean value, in that case no need to look for args - if isinstance(config, bool): - config = None - - elif isinstance(config, dict): - for key, val in src.items(): - if key.startswith(config_name): - config[key.replace(f"{config_name}_", "")] = val - - # update by config name - else: - for key, val in src.items(): - if key.startswith(config_name): - setattr(config, key.replace(f"{config_name}_", ""), val) - - dst.update({config_name: config}) - - -def _get_class_object(class_path: str) -> type: - """ - given a full class name, this function returns the correct class - - :param class_path: a full class name (ex. 'transformers.AutoModelForCausalLM') - - :return the wanted class object - """ - module_path, class_name = class_path.rsplit(".", 1) - module = importlib.import_module(module_path) - return getattr(module, class_name) - - -def _set_model_and_tokenizer( - model: Union[str, List[str]], - tokenizer: Union[str, List[str]], - task: str, - framework: str, - lora_config: dict, - quantization_config: dict, - use_cuda: bool, - tokenizer_pretrained_config, - model_pretrained_config, - device_map: str, -): - """ - get the correct model and tokenizer according to given user inputs - - :param model: a tuple containing model name and class, or str with model name or path - :param tokenizer: a tuple containing tokenizer name and class, or str with tokenizer name or path - :param task: a supported nlp task, used to choose model if not provided - :param framework: pt or tf - :param lora_config: lora config or None, to load model in appropriate way - :param quantization_config: quantization config or None, to load model in appropriate way - :param use_cuda: use gpu or not - :param tokenizer_pretrained_config: config to load the pretrained tokenizer - :param model_pretrained_config: config to load the pretrained model - :param device_map: a device map for model training if using number of gpu's - - :returns: model and tokenizer - """ - # if task is not supported and no model was given we can't choose one - if task and task not in supported_tasks and not model: - logger.error("unsupported task option chosen") - raise - - # load model from store - if isinstance(model, str) and is_store_uri(model): - pass - # TODO: load both model and tokenizer and return, need guy's help - - # if it's a tuple them we assume it contains of both name and class - if isinstance(model, list): - model_name, model_class = model - model_class = _get_class_object(model_class) - - # in the case we don't get the model class we need the task in order to choose the correct model - else: - if task is None: - logger.error("task must be chosen in order to determine the correct model") - raise Exception( - "this function requires either a supported task or a model and model class to be chosen" - ) - - _, available_classes, task_options = transformers.pipelines.check_task(task) - - if isinstance(model, str): - model_name = model - - # if model is not given, we take the default model for the given task - else: - model_name, _ = transformers.pipelines.get_default_model_and_revision( - available_classes, framework, task_options - ) - if not available_classes.get(framework, tuple()): - logger.error( - "given task's default model is not supported in specified framework" - ) - raise Exception( - "this function requires either a supported task or a model and model class to be chosen" - ) - - model_class = available_classes[framework][0] - - # load the pretrained model - if use_cuda: - device_map = device_map - else: - device_map = None - - model = model_class.from_pretrained( - model_name, - quantization_config=quantization_config, - device_map=device_map, - **model_pretrained_config, - ) - - # If quantization config is given we will load a quantized model, if not a regular one - if quantization_config: - model.gradient_checkpointing_enable() - model = peft.prepare_model_for_kbit_training(model) - - # If lora config was given we want to do lora fine tune, we update model here - if lora_config: - model = peft.get_peft_model(model, lora_config) - - # if not specified we choose the default tokenizer that corresponding to the model - if tokenizer is None: - tokenizer = transformers.AutoTokenizer.from_pretrained(model_name) - return model_name, model, tokenizer - - if isinstance(tokenizer, str): - tokenizer_name = tokenizer - tokenizer_class = transformers.AutoTokenizer - - # if it's not a str then it's a tuple of both name and class - else: - tokenizer_name, tokenizer_class = tokenizer - tokenizer_class = _get_class_object(tokenizer_class) - - tokenizer = tokenizer_class.from_pretrained( - tokenizer_name, **tokenizer_pretrained_config - ) - - tokenizer.pad_token = tokenizer.eos_token - - return model_name, model, tokenizer - - -def _dataset_loader(dataset: str, is_train: bool = True, **kwargs) -> Dataset: - """ - loads the specific dataset provided by the user - - :param dataset: name or path of dataset to load - :param is_train: bool that indicates the purpose of the dataset - :param kwargs: other kwargs for loading the dataset - - :returns: loaded dataset - """ - # if split in kwargs then the user decides how to split the dataset - if "split" in kwargs: - return load_dataset(dataset, **kwargs) - - # if it's a dataset for train we split with train - if is_train: - return load_dataset(dataset, split="train", **kwargs) - - # if it's eval dataset, then a lot of names are acceptable for the set and we check all of them - dataset = load_dataset(dataset, **kwargs) - if "test" in dataset: - return dataset.get("test") - elif "eval" in dataset: - return dataset.get("eval") - elif "validation" in dataset: - return dataset.get("validation") - - -def _prepare_dataset( - train_dataset: str, - eval_dataset: str, - train_load_dataset_kwargs, - eval_load_dataset_kwargs, - tokenizer, - dataset_columns_to_train: Union[str, list], -) -> (Dataset, Union[Dataset, None]): - """ - Loads the train and eval datasets (if provided) passes them through the tokenizer and - returns them ready to use in training - - :param train_dataset: the name or path to the train dataset - :param eval_dataset: the name or path to the eval dataset - :param dataset_columns_to_train: which columns to pass to the model as inputs - (need to pass through the tokenizer first) - :param train_load_dataset_kwargs: kwargs for dataset loading - :param eval_load_dataset_kwargs: kwargs for dataset loading - :param tokenizer: the tokenizer to pass the data through - - :returns: tokenized datasets - """ - if not tokenizer.pad_token: - tokenizer.pad_token = tokenizer.eos_token - - # we take col name/s in a list for easy generalization - if isinstance(dataset_columns_to_train, str): - dataset_columns_to_train = [dataset_columns_to_train] - - if isinstance(train_dataset, mlrun.datastore.DataItem): - train_dataset = Dataset.from_pandas(train_dataset.as_df()) - return ( - train_dataset.map( - lambda examples: tokenizer( - *[examples[col] for col in dataset_columns_to_train], - truncation=True, - padding=True, - ), - batched=True, - ), - None, - ) - - # Load datasets - # if provided two paths/names we load each separately using designated func - if eval_dataset: - train_dataset = _dataset_loader( - dataset=train_dataset, is_train=True, **train_load_dataset_kwargs - ) - eval_dataset = _dataset_loader( - dataset=eval_dataset, is_train=False, **eval_load_dataset_kwargs - ) - - # if only on path is given then we must check if it contains both dataset or if only one should be used - else: - dataset = load_dataset(train_dataset, **train_load_dataset_kwargs) - if "train" in dataset: - train_dataset = dataset.get("train") - if "test" in dataset: - eval_dataset = dataset.get("test") - elif "eval" in dataset: - eval_dataset = dataset.get("eval") - elif "validation" in dataset: - eval_dataset = dataset.get("validation") - else: - # only train dataset given, tokenize and return it - return ( - train_dataset.map( - lambda examples: tokenizer( - *[examples[col] for col in dataset_columns_to_train], - truncation=True, - padding=True, - ), - batched=True, - ), - None, - ) - else: - logger.error("train dataset is mandatory") - raise KeyError("no train dataset found in given dataset") - - # Tokenize the data so the model can understand it - tokenized_train_dataset = train_dataset.map( - lambda examples: tokenizer( - *[examples[col] for col in dataset_columns_to_train], - truncation=True, - padding=True, - ), - batched=True, - ) - - tokenized_eval_dataset = eval_dataset.map( - lambda examples: tokenizer( - *[examples[col] for col in dataset_columns_to_train], - truncation=True, - padding=True, - ), - batched=True, - ) - - return tokenized_train_dataset, tokenized_eval_dataset - - -def finetune_llm( - context: mlrun.MLClientCtx, - train_dataset: Union[str, mlrun.datastore.DataItem], - eval_dataset: str = None, - train_load_dataset_kwargs: dict = {}, - eval_load_dataset_kwargs: dict = {}, - dataset_columns_to_train: Union[str, list] = "text", - model: Union[str, List[str]] = "huggingface-model", - tokenizer: Union[str, List[str]] = None, - deepspeed_config: Union[dict, bool] = False, - quantization_config: Union[dict, bool] = False, - lora_config: Union[dict, bool] = False, - training_config: dict = {}, - model_pretrained_config: dict = {}, - tokenizer_pretrained_config: dict = {}, - data_collator_config: dict = {}, - task: str = "text-generation", - use_cuda: bool = True, - framework: str = "pt", - device_map: str = "auto", - **kwargs, -): - """ - Fine-tunes a Language Model (LLM) on a specific task using the provided dataset. - The function takes various configuration parameters to customize the training process - and adapt the model to specific tasks using a provided dataset. - - :param context: mlrun context in order to log trained model - :param dataset_columns_to_train: which columns to pass to the model as inputs - :param eval_load_dataset_kwargs: kwargs for dataset loading - :param train_load_dataset_kwargs: kwargs for dataset loading - :param framework: pt ot tf - :param use_cuda: use gpu or not - :param tokenizer_pretrained_config: config to load the pretrained tokenizer - :param model_pretrained_config: config to load the pretrained model - :param tokenizer: a tuple containing tokenizer name and class, or str with tokenizer name or path - :param model: a tuple containing model name and class, or str with model name or path - :param train_dataset: The train dataset used for fine-tuning the language model. - :param eval_dataset: The eval dataset used for evaluate the language model during training. - :param deepspeed_config: Configuration options for DeepSpeed (optional). - :param quantization_config: Configuration options for model quantization (optional). - :param lora_config: Configuration options for Low-Rank Approximation (LoRA) (optional). - :param training_config: Configuration options specific to the fine-tuning training process (optional). - :param data_collator_config: Configuration options for data collation during training (optional). - :param task: A description of the specific task the model is being fine-tuned for. - :param kwargs: Additional keyword arguments. - """ - - # TODO: match forward.keyword to dataset.keyword - check if relevant in new design - # TODO: add warning for label, and add option to modify dataset col names - check if relevant in new design - - # Look for updates to configs given in kwargs - configs = { - ConfigKeys.deepspeed: deepspeed_config, - ConfigKeys.quantization: quantization_config, - ConfigKeys.lora: lora_config, - ConfigKeys.training: training_config, - ConfigKeys.model_pretrained: model_pretrained_config, - ConfigKeys.tokenizer_pretrained: tokenizer_pretrained_config, - ConfigKeys.data_collator: data_collator_config, - } - _update_config(dst=configs, src=kwargs) - - # check gpu permission and availability - if use_cuda: - if torch.cuda.is_available(): - # Clean gpu cache - torch.cuda.empty_cache() - else: - logger.warning("'use_cuda' is set to True, but no cuda device is available") - - # get model and tokenizer - model_name, model, tokenizer = _set_model_and_tokenizer( - model=model, - tokenizer=tokenizer, - task=task, - framework=framework, - lora_config=configs[ConfigKeys.lora], - quantization_config=configs[ConfigKeys.quantization], - use_cuda=use_cuda, - tokenizer_pretrained_config=tokenizer_pretrained_config, - model_pretrained_config=configs[ConfigKeys.model_pretrained], - device_map=device_map, - ) - - # Load datasets - tokenized_train, tokenized_eval = _prepare_dataset( - train_dataset=train_dataset, - eval_dataset=eval_dataset, - train_load_dataset_kwargs=train_load_dataset_kwargs, - eval_load_dataset_kwargs=eval_load_dataset_kwargs, - tokenizer=tokenizer, - dataset_columns_to_train=dataset_columns_to_train, - ) - - # Initialize the data collator for the trainer to use in order to create batches of data - data_collator = transformers.DataCollatorForLanguageModeling( - tokenizer=tokenizer, mlm=False, **data_collator_config - ) - - # Initialize training kwargs from user kwargs: - train_kwargs = configs[ConfigKeys.training] - - # If deepspeed config given we add it to training kwargs - if configs[ConfigKeys.deepspeed]: - train_kwargs["deepspeed"] = configs[ConfigKeys.deepspeed] - - # Take a look at the trainable parameters in the model - _print_trainable_parameters(model) - - # Preparing training arguments: - training_args = transformers.TrainingArguments( - output_dir=tempfile.mkdtemp(), - **train_kwargs, - ) - - trainer = transformers.Trainer( - model=model, - train_dataset=tokenized_train, - eval_dataset=tokenized_eval, - tokenizer=tokenizer, - data_collator=data_collator, - args=training_args, - ) - - apply_mlrun(trainer, model_name=model_name.split("/")[-1]) - model.config.use_cache = ( - False # silence the warnings. Please re-enable for inference! - ) - - # Apply training with evaluation: - context.logger.info(f"training '{model_name}'") - trainer.train() - - temp_directory = tempfile.TemporaryDirectory().name - trainer.save_model(temp_directory) - - # Zip the model directory: - shutil.make_archive( - base_name="model", - format="zip", - root_dir=temp_directory, - ) - - # Log the model: - context.log_model( - key="model", - db_key=model_name.split("/")[-1], - model_file="model.zip", - tag="", - framework="Hugging Face", - ) - - -def evaluate( - context, - model_path, - data: pd.DataFrame, - model_name: str = None, - tokenizer_name: str = None, -): - """ - Evaluating the model using perplexity, for more information visit: - https://huggingface.co/docs/transformers/perplexity - - :param context: mlrun context - :param model_path: path to the model directory - :param data: the data to evaluate the model - :param model_name: name of base model - :param tokenizer_name: name of base tokenizer - """ - # Get the model artifact and file: - ( - model_file, - model_artifact, - extra_data, - ) = mlrun.artifacts.get_model(model_path) - - # Read the name: - _model_name = model_artifact.spec.db_key - - # Extract logged model files: - model_directory = os.path.join(os.path.dirname(model_file), _model_name) - with zipfile.ZipFile(model_file, "r") as zip_file: - zip_file.extractall(model_directory) - - # Loading the saved pretrained tokenizer and model: - dataset = Dataset.from_pandas(data) - tokenizer = AutoTokenizer.from_pretrained(tokenizer_name) - pad_token_id = tokenizer.eos_token_id - model = AutoModelForCausalLM.from_pretrained( - model_name, device_map="cuda:0", trust_remote_code=True, load_in_8bit=True - ) - model = PeftModel.from_pretrained(model, model_directory) - model.eval() - encodings = tokenizer("\n\n".join(dataset["text"][:5]), return_tensors="pt") - - max_length = 1024 - stride = 512 - seq_len = encodings.input_ids.size(1) - - nlls = [] - prev_end_loc = 0 - for begin_loc in range(0, seq_len, stride): - end_loc = min(begin_loc + max_length, seq_len) - trg_len = end_loc - prev_end_loc # may be different from stride on last loop - input_ids = encodings.input_ids[:, begin_loc:end_loc] - target_ids = input_ids.clone() - target_ids[:, :-trg_len] = -100 - - with torch.no_grad(): - outputs = model(input_ids.cuda(), labels=target_ids) - - # loss is calculated using CrossEntropyLoss which averages over valid labels - # N.B. the model only calculates loss over trg_len - 1 labels, because it internally shifts the labels - # to the left by 1. - neg_log_likelihood = outputs.loss - - nlls.append(neg_log_likelihood) - - prev_end_loc = end_loc - if end_loc == seq_len: - break - - ppl = torch.exp(torch.stack(nlls).mean()).item() - context.log_result("perplexity", ppl) diff --git a/huggingface_auto_trainer/item.yaml b/huggingface_auto_trainer/item.yaml deleted file mode 100644 index b7c9bbcca..000000000 --- a/huggingface_auto_trainer/item.yaml +++ /dev/null @@ -1,27 +0,0 @@ -apiVersion: v1 -categories: -- huggingface -- genai -- machine-learning -- model-training -description: fine-tune llm model with ease -doc: '' -example: huggingface_auto_trainer.ipynb -generationDate: 2023-08-21:17-25 -hidden: false -icon: '' -labels: - author: Zeevr -maintainers: [] -marketplaceType: '' -mlrunVersion: 1.4.0 -name: huggingface-auto-trainer -platformVersion: 3.5.0 -spec: - filename: huggingface_auto_trainer.py - handler: finetune_llm - image: mlrun/mlrun - kind: job - requirements: [] -url: '' -version: 1.1.0 diff --git a/huggingface_auto_trainer/requirements.txt b/huggingface_auto_trainer/requirements.txt deleted file mode 100644 index 1376b1d00..000000000 --- a/huggingface_auto_trainer/requirements.txt +++ /dev/null @@ -1,5 +0,0 @@ -peft -transformers -torch -datasets -plotly diff --git a/huggingface_auto_trainer/test_huggingface_auto_trainer.py b/huggingface_auto_trainer/test_huggingface_auto_trainer.py deleted file mode 100644 index 53576e4e7..000000000 --- a/huggingface_auto_trainer/test_huggingface_auto_trainer.py +++ /dev/null @@ -1,42 +0,0 @@ -import tempfile - -import mlrun - - -def test_train(): - - model_name = "distilgpt2" - tokenizer = model_name - auto_trainer = mlrun.import_function("function.yaml") - - training_arguments = { - "per_device_train_batch_size": 4, - "gradient_accumulation_steps": 1, - "warmup_steps": 2, - "max_steps": 10, - "learning_rate": 2e-4, - "logging_steps": 1, - } - - params = { - "model": (model_name, "transformers.AutoModelForCausalLM"), - "tokenizer": tokenizer, - "train_dataset": "Abirate/english_quotes", - "training_config": training_arguments, - "dataset_columns_to_train": "quote", - "model_pretrained_config": {"use_cache": False}, - "use_cuda": False, - } - - try: - with tempfile.TemporaryDirectory() as test_directory: - auto_trainer.run( - local=True, - params=params, - handler="finetune_llm", - returns=["model"], - workdir=test_directory, - ) - - except Exception as exception: - print(f"- The training failed - raised the following error:\n- {exception}") diff --git a/ingest/function.yaml b/ingest/function.yaml deleted file mode 100644 index a05ca6698..000000000 --- a/ingest/function.yaml +++ /dev/null @@ -1,87 +0,0 @@ -kind: job -metadata: - name: ingest - tag: '' - hash: 7e28700a86ebdd18d887fe588492201a1e3ef2f6 - project: '' - labels: - author: yonish - categories: - - data-preparation - - data-analysis - - feature-store -spec: - command: '' - args: [] - image: mlrun/mlrun - build: - functionSourceCode: ZnJvbSB0eXBpbmcgaW1wb3J0IFVuaW9uLCBMaXN0LCBEaWN0CgppbXBvcnQgbWxydW4uZmVhdHVyZV9zdG9yZSBhcyBmcwpmcm9tIG1scnVuLmV4ZWN1dGlvbiBpbXBvcnQgTUxDbGllbnRDdHgKZnJvbSBtbHJ1bi5kYXRhX3R5cGVzIGltcG9ydCBJbmZlck9wdGlvbnMKCgpkZWYgaW5nZXN0KAogICAgY29udGV4dDogTUxDbGllbnRDdHgsCiAgICBmZWF0dXJlc2V0OiBzdHIsCiAgICBzb3VyY2U6IHN0ciwKICAgIHRhcmdldHM6IExpc3RbVW5pb25bc3RyLCBEaWN0XV0gPSBOb25lLAogICAgbmFtZXNwYWNlPU5vbmUsCiAgICBpbmZlcl9vcHRpb25zPU5vbmUsCiAgICBydW5fY29uZmlnOiBVbmlvbltzdHIsIERpY3RdID0gTm9uZSwKICAgIHNwYXJrX2NvbnRleHQ9Tm9uZSwKICAgIG92ZXJ3cml0ZT1Ob25lLAopOgogICAgIiIiUmVhZCBsb2NhbCBEYXRhRnJhbWUsIGZpbGUsIFVSTCwgb3Igc291cmNlIGludG8gdGhlIGZlYXR1cmUgc3RvcmUKICAgIEluZ2VzdCByZWFkcyBmcm9tIHRoZSBzb3VyY2UsIHJ1biB0aGUgZ3JhcGggdHJhbnNmb3JtYXRpb25zLCBpbmZlcnMgIG1ldGFkYXRhIGFuZCBzdGF0cwogICAgYW5kIHdyaXRlcyB0aGUgcmVzdWx0cyB0byB0aGUgZGVmYXVsdCBvZiBzcGVjaWZpZWQgdGFyZ2V0cwoKICAgIHdoZW4gdGFyZ2V0cyBhcmUgbm90IHNwZWNpZmllZCBkYXRhIGlzIHN0b3JlZCBpbiB0aGUgY29uZmlndXJlZCBkZWZhdWx0IHRhcmdldHMKICAgICh3aWxsIHVzdWFsbHkgYmUgTm9TUUwgZm9yIHJlYWwtdGltZSBhbmQgUGFycXVldCBmb3Igb2ZmbGluZSkuCgogICAgZXhhbXBsZTo6CgogICAgICAgIHN0b2Nrc19zZXQgPSBGZWF0dXJlU2V0KCJzdG9ja3MiLCBlbnRpdGllcz1bRW50aXR5KCJ0aWNrZXIiKV0pCiAgICAgICAgc3RvY2tzID0gcGQucmVhZF9jc3YoInN0b2Nrcy5jc3YiKQogICAgICAgIGRmID0gaW5nZXN0KHN0b2Nrc19zZXQsIHN0b2NrcywgaW5mZXJfb3B0aW9ucz1mc3RvcmUuSW5mZXJPcHRpb25zLmRlZmF1bHQoKSkKCiAgICAgICAgIyBmb3IgcnVubmluZyBhcyByZW1vdGUgam9iCiAgICAgICAgY29uZmlnID0gUnVuQ29uZmlnKGltYWdlPSdtbHJ1bi9tbHJ1bicpLmFwcGx5KG1vdW50X3YzaW8oKSkKICAgICAgICBkZiA9IGluZ2VzdChzdG9ja3Nfc2V0LCBzdG9ja3MsIHJ1bl9jb25maWc9Y29uZmlnKQoKICAgICAgICAjIHNwZWNpZnkgc291cmNlIGFuZCB0YXJnZXRzCiAgICAgICAgc291cmNlID0gQ1NWU291cmNlKCJteWNzdiIsIHBhdGg9Im1lYXN1cmVtZW50cy5jc3YiKQogICAgICAgIHRhcmdldHMgPSBbQ1NWVGFyZ2V0KCJteWNzdiIsIHBhdGg9Ii4vbXljc3YuY3N2IildCiAgICAgICAgaW5nZXN0KG1lYXN1cmVtZW50cywgc291cmNlLCB0YXJnZXRzKQoKICAgIDpwYXJhbSBjb250ZXh0OiAgICAgICBNTFJ1biBjb250ZXh0CiAgICA6cGFyYW0gZmVhdHVyZXNldDogICAgZmVhdHVyZSBzZXQgb2JqZWN0IG9yIGZlYXR1cmVzZXQudXJpLiAodXJpIG11c3QgYmUgb2YgYSBmZWF0dXJlIHNldCB0aGF0IGlzIGluIHRoZSBEQiwKICAgICAgICAgICAgICAgICAgICAgICAgICBjYWxsIGAuc2F2ZSgpYCBpZiBpdCdzIG5vdCkKICAgIDpwYXJhbSBzb3VyY2U6ICAgICAgICBzb3VyY2UgZGF0YWZyYW1lIG9yIGZpbGUgcGF0aAogICAgOnBhcmFtIHRhcmdldHM6ICAgICAgIG9wdGlvbmFsIGxpc3Qgb2YgZGF0YSB0YXJnZXQgb2JqZWN0cwogICAgOnBhcmFtIG5hbWVzcGFjZTogICAgIG5hbWVzcGFjZSBvciBtb2R1bGUgY29udGFpbmluZyBncmFwaCBjbGFzc2VzCiAgICA6cGFyYW0gaW5mZXJfb3B0aW9uczogc2NoZW1hIGFuZCBzdGF0cyBpbmZlciBvcHRpb25zCiAgICA6cGFyYW0gcnVuX2NvbmZpZzogICAgZnVuY3Rpb24gYW5kL29yIHJ1biBjb25maWd1cmF0aW9uIGZvciByZW1vdGUgam9icywKICAgICAgICAgICAgICAgICAgICAgICAgICBzZWUgOnB5OmNsYXNzOmB+bWxydW4uZmVhdHVyZV9zdG9yZS5SdW5Db25maWdgCiAgICA6cGFyYW0gc3BhcmtfY29udGV4dDogbG9jYWwgc3Bhcmsgc2Vzc2lvbiBmb3Igc3BhcmsgaW5nZXN0aW9uLCBleGFtcGxlIGZvciBjcmVhdGluZyB0aGUgc3BhcmsgY29udGV4dDoKICAgICAgICAgICAgICAgICAgICAgICAgICBgc3BhcmsgPSBTcGFya1Nlc3Npb24uYnVpbGRlci5hcHBOYW1lKCJTcGFyayBmdW5jdGlvbiIpLmdldE9yQ3JlYXRlKClgCiAgICAgICAgICAgICAgICAgICAgICAgICAgRm9yIHJlbW90ZSBzcGFyayBpbmdlc3Rpb24sIHRoaXMgc2hvdWxkIGNvbnRhaW4gdGhlIHJlbW90ZSBzcGFyayBzZXJ2aWNlIG5hbWUKICAgIDpwYXJhbSBvdmVyd3JpdGU6ICAgICBkZWxldGUgdGhlIHRhcmdldHMnIGRhdGEgcHJpb3IgdG8gaW5nZXN0aW9uCiAgICAgICAgICAgICAgICAgICAgICAgICAgKGRlZmF1bHQ6IFRydWUgZm9yIG5vbi1zY2hlZHVsZWQgaW5nZXN0IC0gZGVsZXRlcyB0aGUgdGFyZ2V0cyB0aGF0IGFyZSBhYm91dCB0byBiZSBpbmdlc3RlZC4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRmFsc2UgZm9yIHNjaGVkdWxlZCBpbmdlc3QgLSBkb2VzIG5vdCBkZWxldGUgdGhlIHRhcmdldCkKCiAgICAiIiIKICAgICMgU2V0dGluZyBpbmZlcl9vcHRpb25zIHRvIGRlZmF1bHQ6CiAgICBjb250ZXh0Ll9wYXJhbWV0ZXJzWyJpbmZlcl9vcHRpb25zIl0gPSBpbmZlcl9vcHRpb25zIG9yIEluZmVyT3B0aW9ucy5kZWZhdWx0KCkKCiAgICBjb250ZXh0LmxvZ2dlci5pbmZvKGYiQ2FsbGluZyBpbmdlc3Rpb24gdGFzayB3aXRoOiB7ZmVhdHVyZXNldH0iKQoKICAgICMgaW5nZXN0IGNhbGxlZCB3aXRoIG1scnVuX2NvbnRleHQsIGZlYXR1cmVfc2V0LCBzb3VyY2UgYW5kIHRhcmdldHMgcGFzc2VkIHdpdGggY29udGV4dAogICAgIyBUaGlzIHBhcmFtcyBoZXJlIGZvciBkb2N1bWVudGF0aW9uIHB1cnBvc2VzIG9ubHkKICAgIGZzLmluZ2VzdCgKICAgICAgICBtbHJ1bl9jb250ZXh0PWNvbnRleHQsCiAgICAgICAgbmFtZXNwYWNlPW5hbWVzcGFjZSwKICAgICAgICBzcGFya19jb250ZXh0PXNwYXJrX2NvbnRleHQsCiAgICApCiAgICBjb250ZXh0LmxvZ19yZXN1bHQoImZlYXR1cmVzZXQiLCBmZWF0dXJlc2V0KQo= - commands: [] - code_origin: https://github.com/mlrun/functions.git#886a88217c2a2570c81a14877f9c1dfb1ac8a244:C:\Users\yonatans\projects\functions\ingest\ingest.py - origin_filename: C:\Users\yonatans\projects\functions\ingest\ingest.py - entry_points: - ingest: - name: ingest - doc: "Read local DataFrame, file, URL, or source into the feature store\nIngest\ - \ reads from the source, run the graph transformations, infers metadata and\ - \ stats\nand writes the results to the default of specified targets\n\nwhen\ - \ targets are not specified data is stored in the configured default targets\n\ - (will usually be NoSQL for real-time and Parquet for offline).\n\nexample::\n\ - \n stocks_set = FeatureSet(\"stocks\", entities=[Entity(\"ticker\")])\n\ - \ stocks = pd.read_csv(\"stocks.csv\")\n df = ingest(stocks_set, stocks,\ - \ infer_options=fstore.InferOptions.default())\n\n # for running as remote\ - \ job\n config = RunConfig(image='mlrun/mlrun').apply(mount_v3io())\n \ - \ df = ingest(stocks_set, stocks, run_config=config)\n\n # specify source\ - \ and targets\n source = CSVSource(\"mycsv\", path=\"measurements.csv\"\ - )\n targets = [CSVTarget(\"mycsv\", path=\"./mycsv.csv\")]\n ingest(measurements,\ - \ source, targets)" - parameters: - - name: context - type: MLClientCtx - doc: MLRun context - default: '' - - name: featureset - type: str - doc: feature set object or featureset.uri. (uri must be of a feature set that - is in the DB, call `.save()` if it's not) - default: '' - - name: source - type: str - doc: source dataframe or file path - default: '' - - name: targets - type: List[Union[str, Dict]] - doc: optional list of data target objects - default: null - - name: namespace - doc: namespace or module containing graph classes - default: null - - name: infer_options - doc: schema and stats infer options - default: null - - name: run_config - type: Union[str, Dict] - doc: function and/or run configuration for remote jobs, see :py:class:`~mlrun.feature_store.RunConfig` - default: null - - name: spark_context - doc: 'local spark session for spark ingestion, example for creating the spark - context: `spark = SparkSession.builder.appName("Spark function").getOrCreate()` - For remote spark ingestion, this should contain the remote spark service - name' - default: null - - name: overwrite - doc: 'delete the targets'' data prior to ingestion (default: True for non-scheduled - ingest - deletes the targets that are about to be ingested. False for scheduled - ingest - does not delete the target)' - default: null - outputs: - - default: '' - lineno: 8 - description: Feature Store ingest function that runs the transformation graph on - the source of the featureset. - default_handler: ingest - disable_auto_mount: false - env: [] - priority_class_name: '' - affinity: null -verbose: false diff --git a/ingest/ingest.ipynb b/ingest/ingest.ipynb deleted file mode 100644 index 7da398b4f..000000000 --- a/ingest/ingest.ipynb +++ /dev/null @@ -1,762 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Feature Store Ingest" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Read local DataFrame, file, URL, or source into the feature store\n", - "Ingest reads from the source, run the graph transformations, infers metadata and stats\n", - "and writes the results to the default of specified targets." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Creating Project" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import mlrun\n", - "import mlrun.feature_store as fstore\n", - "from mlrun.datastore.sources import CSVSource\n", - "from mlrun.feature_store.steps import *\n", - "from mlrun.features import MinMaxValidator\n", - "import pandas as pd\n", - "import datetime" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "> 2022-01-31 13:52:16,939 [info] loaded project ingest from MLRun DB\n" - ] - } - ], - "source": [ - "# Initialize the MLRun project object\n", - "project = mlrun.get_or_create_project('ingest', context=\"./\", user_project=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Create Sample Data For Demo" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "quotes = pd.DataFrame(\n", - " {\n", - " \"time\": [\n", - " pd.Timestamp(\"2016-05-25 13:30:00.023\"),\n", - " pd.Timestamp(\"2016-05-25 13:30:00.023\"),\n", - " pd.Timestamp(\"2016-05-25 13:30:00.030\"),\n", - " pd.Timestamp(\"2016-05-25 13:30:00.041\"),\n", - " pd.Timestamp(\"2016-05-25 13:30:00.048\"),\n", - " pd.Timestamp(\"2016-05-25 13:30:00.049\"),\n", - " pd.Timestamp(\"2016-05-25 13:30:00.072\"),\n", - " pd.Timestamp(\"2016-05-25 13:30:00.075\"),\n", - " ],\n", - " \"ticker\": [\"GOOG\", \"MSFT\", \"MSFT\", \"MSFT\", \"GOOG\", \"AAPL\", \"GOOG\", \"MSFT\"],\n", - " \"bid\": [720.50, 51.95, 51.97, 51.99, 720.50, 97.99, 720.50, 52.01],\n", - " \"ask\": [720.93, 51.96, 51.98, 52.00, 720.93, 98.01, 720.88, 52.03],\n", - " }\n", - ")\n", - "\n", - "# move date:\n", - "max_date = quotes[\"time\"].max()\n", - "now_date = datetime.datetime.now()\n", - "delta = now_date - max_date\n", - "quotes[\"time\"] = quotes[\"time\"] + delta" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
timetickerbidask
02022-01-31 13:52:16.905388GOOG720.50720.93
12022-01-31 13:52:16.905388MSFT51.9551.96
22022-01-31 13:52:16.912388MSFT51.9751.98
32022-01-31 13:52:16.923388MSFT51.9952.00
42022-01-31 13:52:16.930388GOOG720.50720.93
52022-01-31 13:52:16.931388AAPL97.9998.01
62022-01-31 13:52:16.954388GOOG720.50720.88
72022-01-31 13:52:16.957388MSFT52.0152.03
\n", - "
" - ], - "text/plain": [ - " time ticker bid ask\n", - "0 2022-01-31 13:52:16.905388 GOOG 720.50 720.93\n", - "1 2022-01-31 13:52:16.905388 MSFT 51.95 51.96\n", - "2 2022-01-31 13:52:16.912388 MSFT 51.97 51.98\n", - "3 2022-01-31 13:52:16.923388 MSFT 51.99 52.00\n", - "4 2022-01-31 13:52:16.930388 GOOG 720.50 720.93\n", - "5 2022-01-31 13:52:16.931388 AAPL 97.99 98.01\n", - "6 2022-01-31 13:52:16.954388 GOOG 720.50 720.88\n", - "7 2022-01-31 13:52:16.957388 MSFT 52.01 52.03" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "quotes" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Build Advanced Feature Set - With Feature Engineering Pipeline" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Define a custom pipeline step (python class)" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "class MyMap(MapClass):\n", - " def __init__(self, multiplier=1, **kwargs):\n", - " super().__init__(**kwargs)\n", - " self._multiplier = multiplier\n", - "\n", - " def do(self, event):\n", - " event[\"multi\"] = event[\"bid\"] * self._multiplier\n", - " return event" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Build and show the transformatiom pipeline" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "mlrun-flow\n", - "\n", - "\n", - "\n", - "_start\n", - "\n", - "start\n", - "\n", - "\n", - "\n", - "map.MyMap\n", - "\n", - "map.MyMap\n", - "\n", - "\n", - "\n", - "_start->map.MyMap\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "storey.Extend\n", - "\n", - "storey.Extend\n", - "\n", - "\n", - "\n", - "map.MyMap->storey.Extend\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "filter\n", - "\n", - "filter\n", - "\n", - "\n", - "\n", - "storey.Extend->filter\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "FeaturesetValidator\n", - "\n", - "FeaturesetValidator\n", - "\n", - "\n", - "\n", - "filter->FeaturesetValidator\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "Aggregates\n", - "\n", - "Aggregates\n", - "\n", - "\n", - "\n", - "FeaturesetValidator->Aggregates\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "parquet\n", - "\n", - "\n", - "parquet\n", - "\n", - "\n", - "\n", - "Aggregates->parquet\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "nosql\n", - "\n", - "\n", - "nosql\n", - "\n", - "\n", - "\n", - "Aggregates->nosql\n", - "\n", - "\n", - "\n", - "\n", - "\n" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "quotes_set = fstore.FeatureSet(\"stock-quotes\", entities=[fstore.Entity(\"ticker\")])\n", - "\n", - "quotes_set.graph.to(\"map.MyMap\", multiplier=3).to(\n", - " \"storey.Extend\", _fn=\"({'extra': event['bid'] * 77})\"\n", - ").to(\"storey.Filter\", \"filter\", _fn=\"(event['bid'] > 51.92)\").to(\n", - " FeaturesetValidator()\n", - ")\n", - "\n", - "quotes_set.add_aggregation(\"ask\", [\"sum\", \"max\"], \"1h\", \"10m\", name=\"asks1\")\n", - "quotes_set.add_aggregation(\"ask\", [\"sum\", \"max\"], \"5h\", \"10m\", name=\"asks5\")\n", - "quotes_set.add_aggregation(\"bid\", [\"min\", \"max\"], \"1h\", \"10m\", name=\"bids\")\n", - "\n", - "# add feature validation policy\n", - "quotes_set[\"bid\"] = fstore.Feature(\n", - " validator=MinMaxValidator(min=52, severity=\"info\")\n", - ")\n", - "\n", - "# add default target definitions and plot\n", - "quotes_set.set_targets()\n", - "quotes_set.plot(rankdir=\"LR\", with_targets=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Saving the feature set in the feature store " - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "quotes_set.save()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Creating the data source of the feature set to apply the ingest on:" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [], - "source": [ - "data_uri = 'quotes.csv'\n", - "quotes.to_csv(data_uri, index=False)\n", - "source = CSVSource('quotes', data_uri).to_dict()\n", - "source" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Import ingest function" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [], - "source": [ - "ingest_fn = mlrun.import_function(\"function.yaml\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Running the function locally" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "> 2022-01-31 13:52:17,201 [info] starting run ingest-ingest uid=4bd5d12691a8439d90bf53847f59df1a DB=http://mlrun-api:8080\n", - "> 2022-01-31 13:52:17,354 [info] Ingesting the FeatureSet: store://feature-sets/ingest-yonatan/stock-quotes\n", - "> 2022-01-31 13:52:17,427 [info] starting ingestion task to store://feature-sets/ingest-yonatan/stock-quotes:latest.\n", - "info! bid value is smaller than min, key=['MSFT'] time=2022-01-31 13:52:19.466055 args={'min': 52, 'value': 51.95}\n", - "info! bid value is smaller than min, key=['MSFT'] time=2022-01-31 13:52:19.466072 args={'min': 52, 'value': 51.97}\n", - "info! bid value is smaller than min, key=['MSFT'] time=2022-01-31 13:52:19.466085 args={'min': 52, 'value': 51.99}\n", - "info! bid value is smaller than min, key=['MSFT'] time=2022-01-31 13:52:19.671677 args={'min': 52, 'value': 51.95}\n", - "info! bid value is smaller than min, key=['MSFT'] time=2022-01-31 13:52:19.671692 args={'min': 52, 'value': 51.97}\n", - "info! bid value is smaller than min, key=['MSFT'] time=2022-01-31 13:52:19.671708 args={'min': 52, 'value': 51.99}\n", - "> 2022-01-31 13:52:19,915 [info] ingestion task completed, targets:\n", - "> 2022-01-31 13:52:19,915 [info] [{'name': 'parquet', 'kind': 'parquet', 'path': 'v3io:///projects/ingest-yonatan/FeatureStore/stock-quotes/parquet/sets/stock-quotes-latest', 'status': 'created', 'updated': '2022-01-31T13:52:19.649303+00:00', 'last_written': datetime.datetime(2022, 1, 31, 13, 52, 19, 671753)}, {'name': 'nosql', 'kind': 'nosql', 'path': 'v3io:///projects/ingest-yonatan/FeatureStore/stock-quotes/nosql/sets/stock-quotes-latest', 'status': 'created', 'updated': '2022-01-31T13:52:19.650044+00:00'}]\n" - ] - }, - { - "data": { - "text/html": [ - "\n", - "
\n", - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
projectuiditerstartstatenamelabelsinputsparametersresultsartifacts
ingest-yonatan0Jan 31 13:52:17completedingest-ingest
v3io_user=yonatan
kind=
owner=yonatan
host=jupyter-yoni-647b99c95d-w4jlc
featureset=store://feature-sets/ingest-yonatan/stock-quotes
source={'kind': 'csv', 'name': 'quotes', 'path': 'quotes.csv'}
infer_options=63
overwrite=None
targets=None
featureset=store://feature-sets/ingest-yonatan/stock-quotes
\n", - "
\n", - "
\n", - "
\n", - " Title\n", - " ×\n", - "
\n", - " \n", - "
\n", - "
\n" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n" - ] - }, - { - "data": { - "text/html": [ - " > to track results use the .show() or .logs() methods or click here to open in UI" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "> 2022-01-31 13:52:20,045 [info] run executed, status=completed\n" - ] - } - ], - "source": [ - "ingest_run = ingest_fn.run(\n", - " handler=\"ingest\",\n", - " params={\n", - " \"featureset\": quotes_set.uri,\n", - " \"source\": source,\n", - " },\n", - " local=True,\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## View of the targets' state after run" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'created'" - ] - }, - "execution_count": 19, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "fstore.get_feature_set(ingest_run.outputs['featureset']).status.state" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "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.7.6" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/ingest/ingest.py b/ingest/ingest.py deleted file mode 100644 index 1412cbaf5..000000000 --- a/ingest/ingest.py +++ /dev/null @@ -1,84 +0,0 @@ -# Copyright 2019 Iguazio -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -from typing import Union, List, Dict - -import mlrun.feature_store as fs -from mlrun.execution import MLClientCtx -from mlrun.data_types import InferOptions - - -def ingest( - context: MLClientCtx, - featureset: str, - source: str, - targets: List[Union[str, Dict]] = None, - namespace=None, - infer_options=None, - run_config: Union[str, Dict] = None, - spark_context=None, - overwrite=None, -): - """Read local DataFrame, file, URL, or source into the feature store - Ingest reads from the source, run the graph transformations, infers metadata and stats - and writes the results to the default of specified targets - - when targets are not specified data is stored in the configured default targets - (will usually be NoSQL for real-time and Parquet for offline). - - example:: - - stocks_set = FeatureSet("stocks", entities=[Entity("ticker")]) - stocks = pd.read_csv("stocks.csv") - df = ingest(stocks_set, stocks, infer_options=fstore.InferOptions.default()) - - # for running as remote job - config = RunConfig(image='mlrun/mlrun').apply(mount_v3io()) - df = ingest(stocks_set, stocks, run_config=config) - - # specify source and targets - source = CSVSource("mycsv", path="measurements.csv") - targets = [CSVTarget("mycsv", path="./mycsv.csv")] - ingest(measurements, source, targets) - - :param context: MLRun context - :param featureset: feature set object or featureset.uri. (uri must be of a feature set that is in the DB, - call `.save()` if it's not) - :param source: source dataframe or file path - :param targets: optional list of data target objects - :param namespace: namespace or module containing graph classes - :param infer_options: schema and stats infer options - :param run_config: function and/or run configuration for remote jobs, - see :py:class:`~mlrun.feature_store.RunConfig` - :param spark_context: local spark session for spark ingestion, example for creating the spark context: - `spark = SparkSession.builder.appName("Spark function").getOrCreate()` - For remote spark ingestion, this should contain the remote spark service name - :param overwrite: delete the targets' data prior to ingestion - (default: True for non-scheduled ingest - deletes the targets that are about to be ingested. - False for scheduled ingest - does not delete the target) - - """ - # Setting infer_options to default: - context._parameters["infer_options"] = infer_options or InferOptions.default() - - context.logger.info(f"Calling ingestion task with: {featureset}") - - # ingest called with mlrun_context, feature_set, source and targets passed with context - # This params here for documentation purposes only - fs.ingest( - mlrun_context=context, - namespace=namespace, - spark_context=spark_context, - ) - context.log_result("featureset", featureset) diff --git a/ingest/item.yaml b/ingest/item.yaml deleted file mode 100644 index 8665e88f4..000000000 --- a/ingest/item.yaml +++ /dev/null @@ -1,27 +0,0 @@ -apiVersion: v1 -categories: -- data-preparation -- data-analysis -- feature-store -description: Feature Store ingest function that runs the transformation graph on the - source of the featureset. -doc: '' -example: ingest.ipynb -generationDate: 2022-08-28:17-25 -hidden: false -icon: '' -labels: - author: yonish -maintainers: [] -marketplaceType: '' -mlrunVersion: 1.1.0 -name: ingest -platformVersion: 3.5.0 -spec: - filename: ingest.py - handler: ingest - image: mlrun/mlrun - kind: job - requirements: [] -url: '' -version: 1.1.0 diff --git a/ingest/test_ingest.py b/ingest/test_ingest.py deleted file mode 100644 index 224f520b4..000000000 --- a/ingest/test_ingest.py +++ /dev/null @@ -1,171 +0,0 @@ -# Copyright 2019 Iguazio -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -import os -import tempfile -import shutil -import datetime -import pytest - -import mlrun -import mlrun.feature_store as fstore -from mlrun.datastore.sources import CSVSource -from mlrun.feature_store.steps import * -from mlrun.features import MinMaxValidator -import pandas as pd - -REQUIRED_ENV_VARS = [ - "MLRUN_DBPATH", - "MLRUN_ARTIFACT_PATH", - "V3IO_USERNAME", - "V3IO_API", - "V3IO_ACCESS_KEY", -] - - -def _validate_environment_variables() -> bool: - """ - Checks that all required Environment variables are set. - """ - environment_keys = os.environ.keys() - return all(key in environment_keys for key in REQUIRED_ENV_VARS) - - -def _set_environment(): - artifact_path = tempfile.TemporaryDirectory().name - os.makedirs(artifact_path) - project = mlrun.new_project("ingest-test") - return artifact_path, project - - -def _cleanup_environment(artifact_path: str): - """ - Cleanup the test environment, deleting files and artifacts created during the test. - - :param artifact_path: The artifact path to delete. - """ - # Clean the local directory: - for test_output in [ - *os.listdir(artifact_path), - "schedules", - "runs", - "artifacts", - "functions", - ]: - test_output_path = os.path.abspath(f"./{test_output}") - if os.path.exists(test_output_path): - if os.path.isdir(test_output_path): - shutil.rmtree(test_output_path) - else: - os.remove(test_output_path) - - # Clean the artifacts' directory: - shutil.rmtree(artifact_path) - - -def create_dataframes() -> (pd.DataFrame, pd.DataFrame): - quotes = pd.DataFrame( - { - "time": [ - pd.Timestamp("2016-05-25 13:30:00.023"), - pd.Timestamp("2016-05-25 13:30:00.023"), - pd.Timestamp("2016-05-25 13:30:00.030"), - pd.Timestamp("2016-05-25 13:30:00.041"), - pd.Timestamp("2016-05-25 13:30:00.048"), - pd.Timestamp("2016-05-25 13:30:00.049"), - pd.Timestamp("2016-05-25 13:30:00.072"), - pd.Timestamp("2016-05-25 13:30:00.075"), - ], - "ticker": ["GOOG", "MSFT", "MSFT", "MSFT", "GOOG", "AAPL", "GOOG", "MSFT"], - "bid": [720.50, 51.95, 51.97, 51.99, 720.50, 97.99, 720.50, 52.01], - "ask": [720.93, 51.96, 51.98, 52.00, 720.93, 98.01, 720.88, 52.03], - } - ) - - # move date: - max_date = quotes["time"].max() - now_date = datetime.datetime.now() - delta = now_date - max_date - quotes["time"] = quotes["time"] + delta - - return quotes - - -class MyMap(MapClass): - def __init__(self, multiplier=1, **kwargs): - super().__init__(**kwargs) - self._multiplier = multiplier - - def do(self, event): - event["multi"] = event["bid"] * self._multiplier - return event - - -def _create_feature_set(): - quotes_set = fstore.FeatureSet("stock-quotes", entities=[fstore.Entity("ticker")]) - - quotes_set.graph.to("test_ingest.MyMap", multiplier=3).to( - "storey.Extend", _fn="({'extra': event['bid'] * 77})" - ).to("storey.Filter", "filter", _fn="(event['bid'] > 51.92)").to( - FeaturesetValidator() - ) - - quotes_set.add_aggregation("ask", ["sum", "max"], "1h", "10m", name="asks1") - quotes_set.add_aggregation("ask", ["sum", "max"], "5h", "10m", name="asks5") - quotes_set.add_aggregation("bid", ["min", "max"], "1h", "10m", name="bids") - - # add feature validation policy - quotes_set["bid"] = fstore.Feature( - validator=MinMaxValidator(min=52, severity="info") - ) - - # add default target definitions - quotes_set.set_targets() - return quotes_set - - -@pytest.mark.skipif( - condition=not _validate_environment_variables(), - reason="Project's environment variables are not set", -) -def test_ingest(): - artifact_path, project = _set_environment() - ingest_fn = mlrun.import_function("function.yaml") - quotes = create_dataframes() - - quotes_set = _create_feature_set() - quotes_set.save() - - data_uri = os.path.join(artifact_path, "quotes.csv") - quotes.to_csv(data_uri, index=False) - source = CSVSource("quotes", data_uri).to_dict() - - ingest_run = None - try: - ingest_run = ingest_fn.run( - handler="ingest", - params={ - "featureset": quotes_set.uri, - "source": source, - }, - local=True, - ) - - except Exception as exception: - print(f"- The test failed - raised the following error:\n- {exception}") - assert ( - fstore.get_feature_set(ingest_run.outputs["featureset"]).status.state - == "created" - ), "Targets not created successfully" - _cleanup_environment(artifact_path) diff --git a/load_dask/function.yaml b/load_dask/function.yaml deleted file mode 100644 index a0f73c5fe..000000000 --- a/load_dask/function.yaml +++ /dev/null @@ -1,75 +0,0 @@ -kind: dask -metadata: - name: load-dask - tag: '' - hash: 2af86b4c6ce0bc3e3d0468c1b66a5358482f383e - project: '' - labels: - author: yjb - categories: - - data-preparation - - etl -spec: - command: '' - image: mlrun/ml-models - env: [] - build: - functionSourceCode: ZnJvbSBtbHJ1bi5leGVjdXRpb24gaW1wb3J0IE1MQ2xpZW50Q3R4CmZyb20gbWxydW4uZGF0YXN0b3JlIGltcG9ydCBEYXRhSXRlbQoKZnJvbSB0eXBpbmcgaW1wb3J0IExpc3QsIE9wdGlvbmFsCgoKZGVmIGxvYWRfZGFzaygKICAgICAgICBjb250ZXh0OiBNTENsaWVudEN0eCwKICAgICAgICBzcmNfZGF0YTogRGF0YUl0ZW0sCiAgICAgICAgZGFza19rZXk6IHN0ciA9ICJkYXNrX2tleSIsCiAgICAgICAgaW5jX2NvbHM6IE9wdGlvbmFsW0xpc3Rbc3RyXV0gPSBOb25lLAogICAgICAgIGluZGV4X2NvbHM6IE9wdGlvbmFsW0xpc3Rbc3RyXV0gPSBOb25lLAogICAgICAgIGRhc2tfcGVyc2lzdDogYm9vbCA9IFRydWUsCiAgICAgICAgcmVmcmVzaF9kYXRhOiBib29sID0gVHJ1ZSwKICAgICAgICBzY2hlZHVsZXJfa2V5OiBzdHIgPSAic2NoZWR1bGVyIgopIC0+IE5vbmU6CiAgICAiIiJMb2FkIGRhdGFzZXQgaW50byBhbiBleGlzdGluZyBkYXNrIGNsdXN0ZXIKCiAgICBkYXNrIGpvYnMgZGVmaW5lIHRoZSBkYXNrIGNsaWVudCBwYXJhbWV0ZXJzIGF0IHRoZSBqb2IgbGV2ZWwsIHRoaXMgbWV0aG9kIHdpbGwgcmFpc2UgYW4gZXJyb3IgaWYgbm8gY2xpZW50IGlzIGRldGVjdGVkLgoKICAgIDpwYXJhbSBjb250ZXh0OiAgICAgICAgIHRoZSBmdW5jdGlvbiBjb250ZXh0CiAgICA6cGFyYW0gc3JjX2RhdGE6ICAgICAgICB1cmwgb2YgdGhlIGRhdGEgZmlsZSBvciBwYXJ0aXRpb25lZCBkYXRhc2V0IGFzIGVpdGhlcgogICAgICAgICAgICAgICAgICAgICAgICAgICAgYXJ0aWZhY3QgRGF0YUl0ZW0sIHN0cmluZywgb3IgcGF0aCBvYmplY3QgKHNpbWlsYXIgdG8KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhbmRhcyByZWFkX2NzdikKICAgIDpwYXJhbSBkYXNrX2tleTogICAgICAgIGRlc3RpbmF0aW9uIGtleSBvZiBkYXRhIG9uIGRhc2sgY2x1c3RlciBhbmQgYXJ0aWZhY3Qgc3RvcmUKICAgIDpwYXJhbSBpbmNfY29sczogICAgICAgIGluY2x1ZGUgb25seSB0aGVzZSBjb2x1bW5zICh2ZXJ5IGZhc3QpCiAgICA6cGFyYW0gaW5kZXhfY29sczogICAgICBsaXN0IG9mIGluZGV4IGNvbHVtbiBuYW1lcyAoY2FuIGJlIGEgbG9uZy1ydW5uaW5nIHByb2Nlc3MpCiAgICA6cGFyYW0gZGFza19wZXJzaXN0OiAgICAoVHJ1ZSkgc2hvdWxkIHRoZSBkYXRhIGJlIHBlcnNpc3RlZCAodGhyb3VnaCB0aGUgYGNsaWVudC5wZXJzaXN0YCBvcCkKICAgIDpwYXJhbSByZWZyZXNoX2RhdGE6ICAgIChGYWxzZSkgaWYgdGhlIGRhc2tfa2V5IGFscmVhZHkgZXhpc3RzIGluIHRoZSBkYXNrIGNsdXN0ZXIsIHRoaXMgd2lsbAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmFpc2UgYW4gRXhjZXB0aW9uLiAgU2V0IHRvIFRydWUgdG8gcmVwbGFjZSB0aGUgZXhpc3RpbmcgY2x1c3RlciBkYXRhLgogICAgOnBhcmFtIHNjaGVkdWxlcl9rZXk6ICAgKHNjaGVkdWxlcikgdGhlIGRhc2sgc2NoZWR1bGVyIGNvbmZpZ3VyYXRpb24sIGpzb24gYWxzbyBsb2dnZWQgYXMgYW4gYXJ0aWZhY3QKICAgICIiIgogICAgaWYgaGFzYXR0cihjb250ZXh0LCAiZGFza19jbGllbnQiKToKICAgICAgICBkYXNrX2NsaWVudCA9IGNvbnRleHQuZGFza19jbGllbnQKICAgIGVsc2U6CiAgICAgICAgcmFpc2UgRXhjZXB0aW9uKCJhIGRhc2sgY2xpZW50IHdhcyBub3QgZm91bmQgaW4gdGhlIGV4ZWN1dGlvbiBjb250ZXh0IikKCiAgICBkZiA9IHNyY19kYXRhLmFzX2RmKGRmX21vZHVsZT1kZCkKCiAgICBpZiBkYXNrX3BlcnNpc3Q6CiAgICAgICAgZGYgPSBkYXNrX2NsaWVudC5wZXJzaXN0KGRmKQogICAgICAgIGlmIGRhc2tfY2xpZW50LmRhdGFzZXRzIGFuZCBkYXNrX2tleSBpbiBkYXNrX2NsaWVudC5kYXRhc2V0czoKICAgICAgICAgICAgZGFza19jbGllbnQudW5wdWJsaXNoX2RhdGFzZXQoZGFza19rZXkpCiAgICAgICAgZGFza19jbGllbnQucHVibGlzaF9kYXRhc2V0KGRmLCBuYW1lPWRhc2tfa2V5KQoKICAgIGlmIGNvbnRleHQ6CiAgICAgICAgY29udGV4dC5kYXNrX2NsaWVudCA9IGRhc2tfY2xpZW50CgogICAgIyBzaGFyZSB0aGUgc2NoZWR1bGVyLCB3aGV0aGVyIGRhdGEgaXMgcGVyc2lzdGVkIG9yIG5vdAogICAgZGFza19jbGllbnQud3JpdGVfc2NoZWR1bGVyX2ZpbGUoc2NoZWR1bGVyX2tleSArICIuanNvbiIpCgogICAgIyB3ZSBkb24ndCB1c2UgbG9nX2RhdGFzZXQgaGVyZSB1bnRpbCBpdCBjYW4gdGFrZSBpbnRvIGFjY291bnQKICAgICMgZGFzayBvcmlnaW4gYW5kIGFwcGx5IGRhc2sgZGVzY3JpYmUuCiAgICBjb250ZXh0LmxvZ19hcnRpZmFjdChzY2hlZHVsZXJfa2V5LCBsb2NhbF9wYXRoPXNjaGVkdWxlcl9rZXkgKyAiLmpzb24iKQ== - commands: [] - code_origin: https://github.com/daniels290813/functions.git#55a79c32be5d233cc11efcf40cd3edbe309bfdef:/home/kali/functions/load_dask/load_dask.py - default_handler: load_dask - entry_points: - load_dask: - name: load_dask - doc: 'Load dataset into an existing dask cluster - - - dask jobs define the dask client parameters at the job level, this method - will raise an error if no client is detected.' - parameters: - - name: context - type: MLClientCtx - doc: the function context - default: '' - - name: src_data - type: DataItem - doc: url of the data file or partitioned dataset as either artifact DataItem, - string, or path object (similar to pandas read_csv) - default: '' - - name: dask_key - type: str - doc: destination key of data on dask cluster and artifact store - default: dask_key - - name: inc_cols - type: Optional[List[str]] - doc: include only these columns (very fast) - default: null - - name: index_cols - type: Optional[List[str]] - doc: list of index column names (can be a long-running process) - default: null - - name: dask_persist - type: bool - doc: (True) should the data be persisted (through the `client.persist` op) - default: true - - name: refresh_data - type: bool - doc: (False) if the dask_key already exists in the dask cluster, this will - raise an Exception. Set to True to replace the existing cluster data. - default: true - - name: scheduler_key - type: str - doc: (scheduler) the dask scheduler configuration, json also logged as an - artifact - default: scheduler - outputs: - - default: '' - lineno: 7 - description: load dask cluster with data - remote: true - nthreads: 1 - min_replicas: 0 - max_replicas: 16 - scheduler_timeout: 60 minutes - affinity: null -verbose: false diff --git a/load_dask/item.yaml b/load_dask/item.yaml deleted file mode 100644 index 3d923e370..000000000 --- a/load_dask/item.yaml +++ /dev/null @@ -1,25 +0,0 @@ -apiVersion: v1 -categories: -- data-preparation -- etl -description: load dask cluster with data -doc: '' -example: load_dask.ipynb -generationDate: 2022-08-28:17-25 -hidden: false -icon: '' -labels: - author: yjb -maintainers: [] -marketplaceType: '' -mlrunVersion: 1.1.0 -name: load-dask -platformVersion: 3.5.0 -spec: - filename: load_dask.py - handler: load_dask - image: mlrun/ml-models - kind: dask - requirements: [] -url: '' -version: 1.1.0 diff --git a/load_dask/load_dask.ipynb b/load_dask/load_dask.ipynb deleted file mode 100644 index 3dfcdddb5..000000000 --- a/load_dask/load_dask.ipynb +++ /dev/null @@ -1,309 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# load dask cluster with data\n", - "load a parquet dataset into a dask cluster" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# nuclio: ignore\n", - "import nuclio" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "%nuclio config kind = \"dask\"\n", - "%nuclio config spec.image = \"mlrun/ml-models\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import os\n", - "import json\n", - "import numpy as np\n", - "import pandas as pd\n", - "\n", - "import dask\n", - "import dask.dataframe as dd\n", - "from dask.distributed import Client, LocalCluster\n", - "\n", - "from mlrun.execution import MLClientCtx\n", - "from mlrun.datastore import DataItem\n", - "\n", - "from typing import List, Optional\n", - "\n", - "def load_dask(\n", - " context: MLClientCtx,\n", - " src_data: DataItem,\n", - " dask_key: str = \"dask_key\",\n", - " inc_cols: Optional[List[str]] = None,\n", - " index_cols: Optional[List[str]] = None,\n", - " dask_persist: bool = True,\n", - " refresh_data: bool = True,\n", - " scheduler_key: str = \"scheduler\"\n", - ") -> None:\n", - " \"\"\"Load dataset into an existing dask cluster\n", - " \n", - " dask jobs define the dask client parameters at the job level, this method will raise an error if no client is detected.\n", - " \n", - " :param context: the function context\n", - " :param src_data: url of the data file or partitioned dataset as either\n", - " artifact DataItem, string, or path object (similar to \n", - " pandas read_csv)\n", - " :param dask_key: destination key of data on dask cluster and artifact store\n", - " :param inc_cols: include only these columns (very fast)\n", - " :param index_cols: list of index column names (can be a long-running process)\n", - " :param dask_persist: (True) should the data be persisted (through the `client.persist` op)\n", - " :param refresh_data: (False) if the dask_key already exists in the dask cluster, this will \n", - " raise an Exception. Set to True to replace the existing cluster data.\n", - " :param scheduler_key: (scheduler) the dask scheduler configuration, json also logged as an artifact\n", - " \"\"\"\n", - " if hasattr(context, \"dask_client\"):\n", - " dask_client = context.dask_client\n", - " else:\n", - " raise Exception(\"a dask client was not found in the execution context\")\n", - " \n", - " df = src_data.as_df(df_module=dd)\n", - "\n", - " if dask_persist:\n", - " df = dask_client.persist(df)\n", - " if dask_client.datasets and dask_key in dask_client.datasets:\n", - " dask_client.unpublish_dataset(dask_key)\n", - " dask_client.publish_dataset(df, name=dask_key)\n", - " \n", - " if context:\n", - " context.dask_client = dask_client\n", - " \n", - " # share the scheduler, whether data is persisted or not\n", - " dask_client.write_scheduler_file(scheduler_key+\".json\")\n", - " \n", - " # we don't use log_dataset here until it can take into account\n", - " # dask origin and apply dask describe.\n", - " context.log_artifact(scheduler_key, local_path=scheduler_key+\".json\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# nuclio: end-code" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### mlconfig" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from mlrun import mlconf\n", - "import os\n", - "\n", - "mlconf.dbpath = mlconf.dbpath or 'http://mlrun-api:8080'\n", - "mlconf.artifact_path = mlconf.artifact_path or f'{os.environ[\"HOME\"]}/artifacts'" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### save" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from mlrun import code_to_function \n", - "# create job function object from notebook code\n", - "fn = code_to_function(\"load_dask\", handler='load_dask')\n", - "\n", - "# add metadata (for templates and reuse)\n", - "fn.spec.description = \"load dask cluster with data\"\n", - "fn.metadata.categories = [\"data-movement\", \"utils\"]\n", - "fn.metadata.labels = {\"author\": \"yjb\"}\n", - "fn.spec.remote = True\n", - "fn.spec.replicas = 4\n", - "fn.spec.max_replicas = 8\n", - "fn.spec.service_type = \"NodePort\"\n", - "fn.export(\"function.yaml\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### test" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# load function from marketplacen\n", - "from mlrun import import_function\n", - "\n", - "# vcs_branch = 'development'\n", - "# base_vcs = f'https://raw.githubusercontent.com/mlrun/functions/{vcs_branch}/'\n", - "# mlconf.hub_url = mlconf.hub_url or base_vcs + f'{name}/function.yaml'\n", - "# fn = import_function(\"hub://load_dask\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "if \"V3IO_HOME\" in list(os.environ):\n", - " from mlrun import mount_v3io\n", - " fn.apply(mount_v3io())\n", - "else:\n", - " # is you set up mlrun using the instructions at https://github.com/mlrun/mlrun/blob/master/hack/local/README.md\n", - " from mlrun.platforms import mount_pvc\n", - " fn.apply(mount_pvc('nfsvol', 'nfsvol', '/home/joyan/data'))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from mlrun import NewTask, run_local\n", - "\n", - "task_params = {\n", - " \"name\": \"tasks load dask cluster with data\",\n", - " \"params\" : {\n", - " \"persist\" : True,\n", - " \"refresh_data\" : True,\n", - " \"dask_key\" : \"dask_key\"}}" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "run = fn.run(NewTask(**task_params), \n", - " handler=load_dask, \n", - " inputs={\"src_data\" : os.path.join(mlconf.artifact_path, 'iris.parquet') },\n", - " artifact_path=mlconf.artifact_path)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "func.status.to_dict()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import dask\n", - "import dask.dataframe as dd\n", - "from dask.distributed import Client, LocalCluster" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### TODO: this client dash board wont work -- wrong port!\n", - "\n", - "...even though its the correct client" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "client = Client(func.status.to_dict()['scheduler_address'])\n", - "client" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "list(client.list_datasets())" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "client.datasets['dask_key']" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "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.7.6" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/load_dask/load_dask.py b/load_dask/load_dask.py deleted file mode 100644 index 76c53c216..000000000 --- a/load_dask/load_dask.py +++ /dev/null @@ -1,68 +0,0 @@ -# Copyright 2019 Iguazio -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -from mlrun.execution import MLClientCtx -from mlrun.datastore import DataItem - -from typing import List, Optional - - -def load_dask( - context: MLClientCtx, - src_data: DataItem, - dask_key: str = "dask_key", - inc_cols: Optional[List[str]] = None, - index_cols: Optional[List[str]] = None, - dask_persist: bool = True, - refresh_data: bool = True, - scheduler_key: str = "scheduler" -) -> None: - """Load dataset into an existing dask cluster - - dask jobs define the dask client parameters at the job level, this method will raise an error if no client is detected. - - :param context: the function context - :param src_data: url of the data file or partitioned dataset as either - artifact DataItem, string, or path object (similar to - pandas read_csv) - :param dask_key: destination key of data on dask cluster and artifact store - :param inc_cols: include only these columns (very fast) - :param index_cols: list of index column names (can be a long-running process) - :param dask_persist: (True) should the data be persisted (through the `client.persist` op) - :param refresh_data: (False) if the dask_key already exists in the dask cluster, this will - raise an Exception. Set to True to replace the existing cluster data. - :param scheduler_key: (scheduler) the dask scheduler configuration, json also logged as an artifact - """ - if hasattr(context, "dask_client"): - dask_client = context.dask_client - else: - raise Exception("a dask client was not found in the execution context") - - df = src_data.as_df(df_module=dd) - - if dask_persist: - df = dask_client.persist(df) - if dask_client.datasets and dask_key in dask_client.datasets: - dask_client.unpublish_dataset(dask_key) - dask_client.publish_dataset(df, name=dask_key) - - if context: - context.dask_client = dask_client - - # share the scheduler, whether data is persisted or not - dask_client.write_scheduler_file(scheduler_key + ".json") - - # we don't use log_dataset here until it can take into account - # dask origin and apply dask describe. - context.log_artifact(scheduler_key, local_path=scheduler_key + ".json") \ No newline at end of file diff --git a/model_monitoring_stream/function.yaml b/model_monitoring_stream/function.yaml deleted file mode 100644 index aa285638b..000000000 --- a/model_monitoring_stream/function.yaml +++ /dev/null @@ -1,267 +0,0 @@ -kind: remote -metadata: - name: model-monitoring-stream - tag: '' - hash: 33f4d6de0858b3dfc9d150fc82fbed6feb05534c - project: '' - categories: - - monitoring -spec: - command: '' - args: [] - image: livsmichael/mlrun-api:automation - entry_points: - consume: - name: consume - doc: '' - parameters: - - name: self - default: '' - - name: event - type: Dict - default: '' - outputs: - - default: '' - lineno: 293 - compute_predictions_per_second: - name: compute_predictions_per_second - doc: '' - parameters: - - name: event - type: dict - default: '' - outputs: - - default: '' - lineno: 311 - process_before_kv: - name: process_before_kv - doc: '' - parameters: - - name: self - default: '' - - name: event - type: dict - default: '' - outputs: - - default: '' - lineno: 316 - process_before_events_tsdb: - name: process_before_events_tsdb - doc: '' - parameters: - - name: event - type: Dict - default: '' - outputs: - - default: '' - lineno: 325 - process_before_parquet: - name: process_before_parquet - doc: '' - parameters: - - name: event - type: dict - default: '' - outputs: - - default: '' - lineno: 362 - set_none_if_empty: - name: set_none_if_empty - doc: '' - parameters: - - name: _event - type: dict - default: '' - - name: keys - type: List[str] - default: '' - outputs: - - default: '' - lineno: 364 - drop_if_exists: - name: drop_if_exists - doc: '' - parameters: - - name: _event - type: dict - default: '' - - name: keys - type: List[str] - default: '' - outputs: - - default: '' - lineno: 369 - unpack_if_exists: - name: unpack_if_exists - doc: '' - parameters: - - name: _event - type: dict - default: '' - - name: keys - type: List[str] - default: '' - outputs: - - default: '' - lineno: 373 - do: - name: do - doc: '' - parameters: - - name: self - default: '' - - name: event - type: Dict - default: '' - outputs: - - default: '' - lineno: 702 - resume_state: - name: resume_state - doc: '' - parameters: - - name: self - default: '' - - name: endpoint_id - default: '' - outputs: - - default: '' - lineno: 475 - is_valid: - name: is_valid - doc: '' - parameters: - - name: self - default: '' - - name: endpoint_id - type: str - default: '' - - name: validation_function - default: '' - - name: field - type: Any - default: '' - - name: dict_path - type: List[str] - default: '' - outputs: - - default: '' - lineno: 495 - handle_errors: - name: handle_errors - doc: '' - parameters: - - name: self - default: '' - - name: endpoint_id - default: '' - - name: event - default: '' - outputs: - - default: '' - type: bool - lineno: 503 - enrich_even_details: - name: enrich_even_details - doc: '' - parameters: - - name: event - default: '' - outputs: - - default: '' - lineno: 511 - is_not_none: - name: is_not_none - doc: '' - parameters: - - name: field - type: Any - default: '' - - name: dict_path - type: List[str] - default: '' - outputs: - - default: '' - lineno: 536 - is_list_of_numerics: - name: is_list_of_numerics - doc: '' - parameters: - - name: field - type: List[Union[int, float, dict, list]] - default: '' - - name: dict_path - type: List[str] - default: '' - outputs: - - default: '' - lineno: 545 - get_endpoint_record: - name: get_endpoint_record - doc: '' - parameters: - - name: kv_container - type: str - default: '' - - name: kv_path - type: str - default: '' - - name: endpoint_id - type: str - default: '' - - name: access_key - type: str - default: '' - outputs: - - default: '' - lineno: 717 - init_context: - name: init_context - doc: '' - parameters: - - name: context - type: MLClientCtx - default: '' - outputs: - - default: '' - lineno: 743 - handler: - name: handler - doc: '' - parameters: - - name: context - type: MLClientCtx - default: '' - - name: event - type: Event - default: '' - outputs: - - default: '' - lineno: 751 - description: '' - min_replicas: 1 - max_replicas: 4 - env: [] - base_spec: - apiVersion: nuclio.io/v1 - kind: Function - metadata: - name: model-monitoring-stream - labels: {} - annotations: - nuclio.io/generated_by: function generated from /home/michaell/projects/functions/model_monitoring_stream/model_monitoring_stream.py - spec: - runtime: python:3.9 - handler: model_monitoring_stream:handler - env: [] - volumes: [] - build: - commands: [] - noBaseImagesPull: true - functionSourceCode: aW1wb3J0IGpzb24KaW1wb3J0IG9zCmZyb20gY29sbGVjdGlvbnMgaW1wb3J0IGRlZmF1bHRkaWN0CmZyb20gZGF0ZXRpbWUgaW1wb3J0IGRhdGV0aW1lCmZyb20gb3MgaW1wb3J0IGVudmlyb24KZnJvbSB0eXBpbmcgaW1wb3J0IERpY3QsIExpc3QsIFNldCwgT3B0aW9uYWwsIEFueSwgVW5pb24KCmltcG9ydCBwYW5kYXMgYXMgcGQKaW1wb3J0IHYzaW8KZnJvbSBtbHJ1bi5jb25maWcgaW1wb3J0IGNvbmZpZwpmcm9tIG1scnVuLnJ1biBpbXBvcnQgTUxDbGllbnRDdHgKZnJvbSBtbHJ1bi51dGlscyBpbXBvcnQgbG9nZ2VyCmZyb20gbWxydW4udXRpbHMubW9kZWxfbW9uaXRvcmluZyBpbXBvcnQgKAogICAgcGFyc2VfbW9kZWxfZW5kcG9pbnRfc3RvcmVfcHJlZml4LAogICAgY3JlYXRlX21vZGVsX2VuZHBvaW50X2lkLAopCmZyb20gbWxydW4udXRpbHMudjNpb19jbGllbnRzIGltcG9ydCBnZXRfdjNpb19jbGllbnQsIGdldF9mcmFtZXNfY2xpZW50CmZyb20gbnVjbGlvIGltcG9ydCBFdmVudApmcm9tIHN0b3JleSBpbXBvcnQgKAogICAgRmllbGRBZ2dyZWdhdG9yLAogICAgTm9vcERyaXZlciwKICAgIFRhYmxlLAogICAgTWFwLAogICAgTWFwQ2xhc3MsCiAgICBBZ2dyZWdhdGVCeUtleSwKICAgIGJ1aWxkX2Zsb3csCiAgICBGaWx0ZXIsCiAgICBGbGF0TWFwLAogICAgVFNEQlRhcmdldCwKICAgIFBhcnF1ZXRUYXJnZXQsCiAgICBTeW5jRW1pdFNvdXJjZSwKKQpmcm9tIHN0b3JleS5kdHlwZXMgaW1wb3J0IFNsaWRpbmdXaW5kb3dzCmZyb20gc3RvcmV5LnN0ZXBzIGltcG9ydCBTYW1wbGVXaW5kb3cKIyBDb25zdGFudHMKZnJvbSB2M2lvLmRhdGFwbGFuZSBpbXBvcnQgUmFpc2VGb3JTdGF0dXMKCklTT184MDYxX1VUQyA9ICIlWS0lbS0lZCAlSDolTTolUy4lZiV6IgpGVU5DVElPTl9VUkkgPSAiZnVuY3Rpb25fdXJpIgpNT0RFTCA9ICJtb2RlbCIKVkVSU0lPTiA9ICJ2ZXJzaW9uIgpWRVJTSU9ORURfTU9ERUwgPSAidmVyc2lvbmVkX21vZGVsIgpNT0RFTF9DTEFTUyA9ICJtb2RlbF9jbGFzcyIKVElNRVNUQU1QID0gInRpbWVzdGFtcCIKRU5EUE9JTlRfSUQgPSAiZW5kcG9pbnRfaWQiClJFUVVFU1RfSUQgPSAicmVxdWVzdF9pZCIKTEFCRUxTID0gImxhYmVscyIKVU5QQUNLRURfTEFCRUxTID0gInVucGFja2VkX2xhYmVscyIKTEFURU5DWV9BVkdfNU0gPSAibGF0ZW5jeV9hdmdfNW0iCkxBVEVOQ1lfQVZHXzFIID0gImxhdGVuY3lfYXZnXzFoIgpQUkVESUNUSU9OU19QRVJfU0VDT05EID0gInByZWRpY3Rpb25zX3Blcl9zZWNvbmQiClBSRURJQ1RJT05TX0NPVU5UXzVNID0gInByZWRpY3Rpb25zX2NvdW50XzVtIgpQUkVESUNUSU9OU19DT1VOVF8xSCA9ICJwcmVkaWN0aW9uc19jb3VudF8xaCIKRklSU1RfUkVRVUVTVCA9ICJmaXJzdF9yZXF1ZXN0IgpMQVNUX1JFUVVFU1QgPSAibGFzdF9yZXF1ZXN0IgpFUlJPUl9DT1VOVCA9ICJlcnJvcl9jb3VudCIKRU5USVRJRVMgPSAiZW50aXRpZXMiCkZFQVRVUkVfTkFNRVMgPSAiZmVhdHVyZV9uYW1lcyIKTEFCRUxfQ09MVU1OUyA9ICJsYWJlbF9jb2x1bW5zIgpMQVRFTkNZID0gImxhdGVuY3kiClJFQ09SRF9UWVBFID0gInJlY29yZF90eXBlIgpGRUFUVVJFUyA9ICJmZWF0dXJlcyIKUFJFRElDVElPTiA9ICJwcmVkaWN0aW9uIgpQUkVESUNUSU9OUyA9ICJwcmVkaWN0aW9ucyIKTkFNRURfRkVBVFVSRVMgPSAibmFtZWRfZmVhdHVyZXMiCk5BTUVEX1BSRURJQ1RJT05TID0gIm5hbWVkX3ByZWRpY3Rpb25zIgpCQVNFX01FVFJJQ1MgPSAiYmFzZV9tZXRyaWNzIgpDVVNUT01fTUVUUklDUyA9ICJjdXN0b21fbWV0cmljcyIKRU5EUE9JTlRfRkVBVFVSRVMgPSAiZW5kcG9pbnRfZmVhdHVyZXMiCk1FVFJJQ1MgPSAibWV0cmljcyIKQkFUQ0hfVElNRVNUQU1QID0gImJhdGNoX3RpbWVzdGFtcCIKVElNRV9GT1JNQVQ6IHN0ciA9ICIlWS0lbS0lZCAlSDolTTolUy4lZiIgICMgSVNPIDgwNjEKCgojIFN0cmVhbSBwcm9jZXNzaW5nIGNvZGUKY2xhc3MgRXZlbnRTdHJlYW1Qcm9jZXNzb3I6CiAgICBkZWYgX19pbml0X18oCiAgICAgICAgc2VsZiwKICAgICAgICBwcm9qZWN0OiBzdHIsCiAgICAgICAgc2FtcGxlX3dpbmRvdzogaW50ID0gMTAsCiAgICAgICAgdHNkYl9iYXRjaGluZ19tYXhfZXZlbnRzOiBpbnQgPSAxMCwKICAgICAgICB0c2RiX2JhdGNoaW5nX3RpbWVvdXRfc2VjczogaW50ID0gNjAgKiA1LCAgIyBEZWZhdWx0IDUgbWludXRlcwogICAgICAgIHBhcnF1ZXRfYmF0Y2hpbmdfbWF4X2V2ZW50czogaW50ID0gMTBfMDAwLAogICAgICAgIHBhcnF1ZXRfYmF0Y2hpbmdfdGltZW91dF9zZWNzOiBpbnQgPSA2MCAqIDYwLCAgIyBEZWZhdWx0IDEgaG91cgogICAgICAgIGFnZ3JlZ2F0ZV9jb3VudF93aW5kb3dzOiBPcHRpb25hbFtMaXN0W3N0cl1dID0gTm9uZSwKICAgICAgICBhZ2dyZWdhdGVfY291bnRfcGVyaW9kOiBzdHIgPSAiMzBzIiwKICAgICAgICBhZ2dyZWdhdGVfYXZnX3dpbmRvd3M6IE9wdGlvbmFsW0xpc3Rbc3RyXV0gPSBOb25lLAogICAgICAgIGFnZ3JlZ2F0ZV9hdmdfcGVyaW9kOiBzdHIgPSAiMzBzIiwKICAgICAgICB2M2lvX2FjY2Vzc19rZXk6IE9wdGlvbmFsW3N0cl0gPSBOb25lLAogICAgICAgIHYzaW9fZnJhbWVzZDogT3B0aW9uYWxbc3RyXSA9IE5vbmUsCiAgICAgICAgdjNpb19hcGk6IE9wdGlvbmFsW3N0cl0gPSBOb25lLAogICAgKToKICAgICAgICBzZWxmLnByb2plY3QgPSBwcm9qZWN0CiAgICAgICAgc2VsZi5zYW1wbGVfd2luZG93ID0gc2FtcGxlX3dpbmRvdwogICAgICAgIHNlbGYudHNkYl9iYXRjaGluZ19tYXhfZXZlbnRzID0gdHNkYl9iYXRjaGluZ19tYXhfZXZlbnRzCiAgICAgICAgc2VsZi50c2RiX2JhdGNoaW5nX3RpbWVvdXRfc2VjcyA9IHRzZGJfYmF0Y2hpbmdfdGltZW91dF9zZWNzCiAgICAgICAgc2VsZi5wYXJxdWV0X2JhdGNoaW5nX21heF9ldmVudHMgPSBwYXJxdWV0X2JhdGNoaW5nX21heF9ldmVudHMKICAgICAgICBzZWxmLnBhcnF1ZXRfYmF0Y2hpbmdfdGltZW91dF9zZWNzID0gcGFycXVldF9iYXRjaGluZ190aW1lb3V0X3NlY3MKICAgICAgICBzZWxmLmFnZ3JlZ2F0ZV9jb3VudF93aW5kb3dzID0gYWdncmVnYXRlX2NvdW50X3dpbmRvd3Mgb3IgWyI1bSIsICIxaCJdCiAgICAgICAgc2VsZi5hZ2dyZWdhdGVfY291bnRfcGVyaW9kID0gYWdncmVnYXRlX2NvdW50X3BlcmlvZAogICAgICAgIHNlbGYuYWdncmVnYXRlX2F2Z193aW5kb3dzID0gYWdncmVnYXRlX2F2Z193aW5kb3dzIG9yIFsiNW0iLCAiMWgiXQogICAgICAgIHNlbGYuYWdncmVnYXRlX2F2Z19wZXJpb2QgPSBhZ2dyZWdhdGVfYXZnX3BlcmlvZAoKICAgICAgICBzZWxmLnYzaW9fZnJhbWVzZCA9IHYzaW9fZnJhbWVzZCBvciBjb25maWcudjNpb19mcmFtZXNkCiAgICAgICAgc2VsZi52M2lvX2FwaSA9IHYzaW9fYXBpIG9yIGNvbmZpZy52M2lvX2FwaQoKICAgICAgICBzZWxmLnYzaW9fYWNjZXNzX2tleSA9IHYzaW9fYWNjZXNzX2tleSBvciBlbnZpcm9uLmdldCgiVjNJT19BQ0NFU1NfS0VZIikKICAgICAgICBzZWxmLm1vZGVsX21vbml0b3JpbmdfYWNjZXNzX2tleSA9ICgKICAgICAgICAgICAgb3MuZW52aXJvbi5nZXQoIk1PREVMX01PTklUT1JJTkdfQUNDRVNTX0tFWSIpIG9yIHNlbGYudjNpb19hY2Nlc3Nfa2V5CiAgICAgICAgKQoKICAgICAgICB0ZW1wbGF0ZSA9IGNvbmZpZy5tb2RlbF9lbmRwb2ludF9tb25pdG9yaW5nLnN0b3JlX3ByZWZpeGVzLmRlZmF1bHQKCiAgICAgICAga3ZfcGF0aCA9IHRlbXBsYXRlLmZvcm1hdChwcm9qZWN0PXByb2plY3QsIGtpbmQ9ImVuZHBvaW50cyIpCiAgICAgICAgXywgc2VsZi5rdl9jb250YWluZXIsIHNlbGYua3ZfcGF0aCA9IHBhcnNlX21vZGVsX2VuZHBvaW50X3N0b3JlX3ByZWZpeChrdl9wYXRoKQoKICAgICAgICB0c2RiX3BhdGggPSB0ZW1wbGF0ZS5mb3JtYXQocHJvamVjdD1wcm9qZWN0LCBraW5kPSJldmVudHMiKQogICAgICAgIF8sIHNlbGYudHNkYl9jb250YWluZXIsIHNlbGYudHNkYl9wYXRoID0gcGFyc2VfbW9kZWxfZW5kcG9pbnRfc3RvcmVfcHJlZml4KAogICAgICAgICAgICB0c2RiX3BhdGgKICAgICAgICApCiAgICAgICAgc2VsZi50c2RiX3BhdGggPSBmIntzZWxmLnRzZGJfY29udGFpbmVyfS97c2VsZi50c2RiX3BhdGh9IgoKICAgICAgICBzZWxmLnBhcnF1ZXRfcGF0aCA9IGNvbmZpZy5tb2RlbF9lbmRwb2ludF9tb25pdG9yaW5nLnN0b3JlX3ByZWZpeGVzLnVzZXJfc3BhY2UuZm9ybWF0KAogICAgICAgICAgICBwcm9qZWN0PXByb2plY3QsIGtpbmQ9InBhcnF1ZXQiCiAgICAgICAgKQoKICAgICAgICBsb2dnZXIuaW5mbygKICAgICAgICAgICAgIlYzSU8gQ29uZmlndXJhdGlvbiIsCiAgICAgICAgICAgIHYzaW9fYWNjZXNzX2tleT1zZWxmLnYzaW9fYWNjZXNzX2tleSwKICAgICAgICAgICAgbW9kZWxfbW9uaXRvcmluZ19hY2Nlc3Nfa2V5PXNlbGYubW9kZWxfbW9uaXRvcmluZ19hY2Nlc3Nfa2V5LAogICAgICAgICAgICBkZWZhdWx0X3N0b3JlX3ByZWZpeD1jb25maWcubW9kZWxfZW5kcG9pbnRfbW9uaXRvcmluZy5zdG9yZV9wcmVmaXhlcy5kZWZhdWx0LAogICAgICAgICAgICB1c2VyX3NwYWNlX3N0b3JlX3ByZWZpeD1jb25maWcubW9kZWxfZW5kcG9pbnRfbW9uaXRvcmluZy5zdG9yZV9wcmVmaXhlcy51c2VyX3NwYWNlLAogICAgICAgICAgICB2M2lvX2FwaT1zZWxmLnYzaW9fYXBpLAogICAgICAgICAgICB2M2lvX2ZyYW1lc2Q9c2VsZi52M2lvX2ZyYW1lc2QsCiAgICAgICAgICAgIGt2X2NvbnRhaW5lcj1zZWxmLmt2X2NvbnRhaW5lciwKICAgICAgICAgICAga3ZfcGF0aD1zZWxmLmt2X3BhdGgsCiAgICAgICAgICAgIHRzZGJfY29udGFpbmVyPXNlbGYudHNkYl9jb250YWluZXIsCiAgICAgICAgICAgIHRzZGJfcGF0aD1zZWxmLnRzZGJfcGF0aCwKICAgICAgICAgICAgcGFycXVldF9wYXRoPXNlbGYucGFycXVldF9wYXRoLAogICAgICAgICkKCiAgICAgICAgc2VsZi5fa3Zfa2V5cyA9IFsKICAgICAgICAgICAgRlVOQ1RJT05fVVJJLAogICAgICAgICAgICBNT0RFTCwKICAgICAgICAgICAgTU9ERUxfQ0xBU1MsCiAgICAgICAgICAgIFRJTUVTVEFNUCwKICAgICAgICAgICAgRU5EUE9JTlRfSUQsCiAgICAgICAgICAgIExBQkVMUywKICAgICAgICAgICAgVU5QQUNLRURfTEFCRUxTLAogICAgICAgICAgICBMQVRFTkNZX0FWR181TSwKICAgICAgICAgICAgTEFURU5DWV9BVkdfMUgsCiAgICAgICAgICAgIFBSRURJQ1RJT05TX1BFUl9TRUNPTkQsCiAgICAgICAgICAgIFBSRURJQ1RJT05TX0NPVU5UXzVNLAogICAgICAgICAgICBQUkVESUNUSU9OU19DT1VOVF8xSCwKICAgICAgICAgICAgRklSU1RfUkVRVUVTVCwKICAgICAgICAgICAgTEFTVF9SRVFVRVNULAogICAgICAgICAgICBFUlJPUl9DT1VOVCwKICAgICAgICBdCgogICAgICAgIHNlbGYuX2Zsb3cgPSBidWlsZF9mbG93KAogICAgICAgICAgICBbCiAgICAgICAgICAgICAgICBTeW5jRW1pdFNvdXJjZSgpLAogICAgICAgICAgICAgICAgUHJvY2Vzc0VuZHBvaW50RXZlbnQoCiAgICAgICAgICAgICAgICAgICAga3ZfY29udGFpbmVyPXNlbGYua3ZfY29udGFpbmVyLAogICAgICAgICAgICAgICAgICAgIGt2X3BhdGg9c2VsZi5rdl9wYXRoLAogICAgICAgICAgICAgICAgICAgIHYzaW9fYWNjZXNzX2tleT1zZWxmLnYzaW9fYWNjZXNzX2tleSwKICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgICBGaWx0ZXJOb3ROb25lKCksCiAgICAgICAgICAgICAgICBGbGF0TWFwKGxhbWJkYSB4OiB4KSwKICAgICAgICAgICAgICAgIE1hcEZlYXR1cmVOYW1lcygKICAgICAgICAgICAgICAgICAgICBrdl9jb250YWluZXI9c2VsZi5rdl9jb250YWluZXIsCiAgICAgICAgICAgICAgICAgICAga3ZfcGF0aD1zZWxmLmt2X3BhdGgsCiAgICAgICAgICAgICAgICAgICAgYWNjZXNzX2tleT1zZWxmLnYzaW9fYWNjZXNzX2tleSwKICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgICAjIEJyYW5jaCAxOiBBZ2dyZWdhdGUgZXZlbnRzLCBjb3VudCBhdmVyYWdlcyBhbmQgdXBkYXRlIFRTREIgYW5kIEtWCiAgICAgICAgICAgICAgICBbCiAgICAgICAgICAgICAgICAgICAgQWdncmVnYXRlQnlLZXkoCiAgICAgICAgICAgICAgICAgICAgICAgIGFnZ3JlZ2F0ZXM9WwogICAgICAgICAgICAgICAgICAgICAgICAgICAgRmllbGRBZ2dyZWdhdG9yKAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFBSRURJQ1RJT05TLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEVORFBPSU5UX0lELAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFsiY291bnQiXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBTbGlkaW5nV2luZG93cygKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5hZ2dyZWdhdGVfY291bnRfd2luZG93cywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5hZ2dyZWdhdGVfY291bnRfcGVyaW9kLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgRmllbGRBZ2dyZWdhdG9yKAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIExBVEVOQ1ksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTEFURU5DWSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBbImF2ZyJdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNsaWRpbmdXaW5kb3dzKAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxmLmFnZ3JlZ2F0ZV9hdmdfd2luZG93cywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5hZ2dyZWdhdGVfYXZnX3BlcmlvZCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgICAgICAgdGFibGU9VGFibGUoIm5vdGFibGUiLCBOb29wRHJpdmVyKCkpLAogICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgICAgICAgU2FtcGxlV2luZG93KAogICAgICAgICAgICAgICAgICAgICAgICBzZWxmLnNhbXBsZV93aW5kb3cKICAgICAgICAgICAgICAgICAgICApLCAgIyBBZGQgcmVxdWlyZWQgZ2FwIGJldHdlZW4gZXZlbnQgdG8gYXBwbHkgc2FtcGxpbmcKICAgICAgICAgICAgICAgICAgICBNYXAoc2VsZi5jb21wdXRlX3ByZWRpY3Rpb25zX3Blcl9zZWNvbmQpLAogICAgICAgICAgICAgICAgICAgICMgQnJhbmNoIDEuMTogVXBkYXRlZCBLVgogICAgICAgICAgICAgICAgICAgIFsKICAgICAgICAgICAgICAgICAgICAgICAgTWFwKHNlbGYucHJvY2Vzc19iZWZvcmVfa3YpLAogICAgICAgICAgICAgICAgICAgICAgICBXcml0ZVRvS1YoY29udGFpbmVyPXNlbGYua3ZfY29udGFpbmVyLCB0YWJsZT1zZWxmLmt2X3BhdGgpLAogICAgICAgICAgICAgICAgICAgICAgICBJbmZlclNjaGVtYSgKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHYzaW9fYWNjZXNzX2tleT1zZWxmLnYzaW9fYWNjZXNzX2tleSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHYzaW9fZnJhbWVzZD1zZWxmLnYzaW9fZnJhbWVzZCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRhaW5lcj1zZWxmLmt2X2NvbnRhaW5lciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRhYmxlPXNlbGYua3ZfcGF0aCwKICAgICAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAgICMgQnJhbmNoIDEuMjogVXBkYXRlIFRTREIKICAgICAgICAgICAgICAgICAgICBbCiAgICAgICAgICAgICAgICAgICAgICAgICMgTWFwIHRoZSBldmVudCBpbnRvIHRhZ2dhYmxlIGZpZWxkcywgYWRkIHJlY29yZCB0eXBlIHRvIGVhY2ggZmllbGQKICAgICAgICAgICAgICAgICAgICAgICAgTWFwKHNlbGYucHJvY2Vzc19iZWZvcmVfZXZlbnRzX3RzZGIpLAogICAgICAgICAgICAgICAgICAgICAgICBbCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBGaWx0ZXJLZXlzKEJBU0VfTUVUUklDUyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBVbnBhY2tWYWx1ZXMoQkFTRV9NRVRSSUNTKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRTREJUYXJnZXQoCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGF0aD1zZWxmLnRzZGJfcGF0aCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByYXRlPSIxMC9tIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aW1lX2NvbD1USU1FU1RBTVAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udGFpbmVyPXNlbGYudHNkYl9jb250YWluZXIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWNjZXNzX2tleT1zZWxmLnYzaW9fYWNjZXNzX2tleSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2M2lvX2ZyYW1lcz1zZWxmLnYzaW9fZnJhbWVzZCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbmRleF9jb2xzPVtFTkRQT0lOVF9JRCwgUkVDT1JEX1RZUEVdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgU2V0dGluZ3MgZm9yIF9CYXRjaGluZwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1heF9ldmVudHM9c2VsZi50c2RiX2JhdGNoaW5nX21heF9ldmVudHMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGltZW91dF9zZWNzPXNlbGYudHNkYl9iYXRjaGluZ190aW1lb3V0X3NlY3MsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga2V5PUVORFBPSU5UX0lELAogICAgICAgICAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWwogICAgICAgICAgICAgICAgICAgICAgICAgICAgRmlsdGVyS2V5cyhFTkRQT0lOVF9GRUFUVVJFUyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBVbnBhY2tWYWx1ZXMoRU5EUE9JTlRfRkVBVFVSRVMpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgVFNEQlRhcmdldCgKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXRoPXNlbGYudHNkYl9wYXRoLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJhdGU9IjEwL20iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpbWVfY29sPVRJTUVTVEFNUCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb250YWluZXI9c2VsZi50c2RiX2NvbnRhaW5lciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhY2Nlc3Nfa2V5PXNlbGYudjNpb19hY2Nlc3Nfa2V5LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHYzaW9fZnJhbWVzPXNlbGYudjNpb19mcmFtZXNkLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluZGV4X2NvbHM9W0VORFBPSU5UX0lELCBSRUNPUkRfVFlQRV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBTZXR0aW5ncyBmb3IgX0JhdGNoaW5nCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF4X2V2ZW50cz1zZWxmLnRzZGJfYmF0Y2hpbmdfbWF4X2V2ZW50cywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aW1lb3V0X3NlY3M9c2VsZi50c2RiX2JhdGNoaW5nX3RpbWVvdXRfc2VjcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrZXk9RU5EUE9JTlRfSUQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAgICAgICBbCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBGaWx0ZXJLZXlzKENVU1RPTV9NRVRSSUNTKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZpbHRlck5vdE5vbmUoKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFVucGFja1ZhbHVlcyhDVVNUT01fTUVUUklDUyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBUU0RCVGFyZ2V0KAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdGg9c2VsZi50c2RiX3BhdGgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmF0ZT0iMTAvbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGltZV9jb2w9VElNRVNUQU1QLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRhaW5lcj1zZWxmLnRzZGJfY29udGFpbmVyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFjY2Vzc19rZXk9c2VsZi52M2lvX2FjY2Vzc19rZXksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdjNpb19mcmFtZXM9c2VsZi52M2lvX2ZyYW1lc2QsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5kZXhfY29scz1bRU5EUE9JTlRfSUQsIFJFQ09SRF9UWVBFXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIFNldHRpbmdzIGZvciBfQmF0Y2hpbmcKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXhfZXZlbnRzPXNlbGYudHNkYl9iYXRjaGluZ19tYXhfZXZlbnRzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpbWVvdXRfc2Vjcz1zZWxmLnRzZGJfYmF0Y2hpbmdfdGltZW91dF9zZWNzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtleT1FTkRQT0lOVF9JRCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAjIEJyYW5jaCAyOiBCYXRjaCBldmVudHMsIHdyaXRlIHRvIHBhcnF1ZXQKICAgICAgICAgICAgICAgIFsKICAgICAgICAgICAgICAgICAgICBNYXAoc2VsZi5wcm9jZXNzX2JlZm9yZV9wYXJxdWV0KSwKICAgICAgICAgICAgICAgICAgICBQYXJxdWV0VGFyZ2V0KAogICAgICAgICAgICAgICAgICAgICAgICBwYXRoPXNlbGYucGFycXVldF9wYXRoLAogICAgICAgICAgICAgICAgICAgICAgICBwYXJ0aXRpb25fY29scz1bIiRrZXkiLCAiJHllYXIiLCAiJG1vbnRoIiwgIiRkYXkiLCAiJGhvdXIiXSwKICAgICAgICAgICAgICAgICAgICAgICAgaW5mZXJfY29sdW1uc19mcm9tX2RhdGE9VHJ1ZSwKICAgICAgICAgICAgICAgICAgICAgICAgIyBTZXR0aW5ncyBmb3IgX0JhdGNoaW5nCiAgICAgICAgICAgICAgICAgICAgICAgIG1heF9ldmVudHM9c2VsZi5wYXJxdWV0X2JhdGNoaW5nX21heF9ldmVudHMsCiAgICAgICAgICAgICAgICAgICAgICAgIHRpbWVvdXRfc2Vjcz1zZWxmLnBhcnF1ZXRfYmF0Y2hpbmdfdGltZW91dF9zZWNzLAogICAgICAgICAgICAgICAgICAgICAgICAjIFNldHRpbmdzIGZvciB2M2lvIHN0b3JhZ2UKICAgICAgICAgICAgICAgICAgICAgICAgc3RvcmFnZV9vcHRpb25zPXsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ2M2lvX2FwaSI6IHNlbGYudjNpb19hcGksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAidjNpb19hY2Nlc3Nfa2V5Ijogc2VsZi5tb2RlbF9tb25pdG9yaW5nX2FjY2Vzc19rZXksCiAgICAgICAgICAgICAgICAgICAgICAgIH0sCiAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgIF0KICAgICAgICApLnJ1bigpCgogICAgZGVmIGNvbnN1bWUoc2VsZiwgZXZlbnQ6IERpY3QpOgogICAgICAgIGV2ZW50cyA9IFtdCiAgICAgICAgaWYgImhlYWRlcnMiIGluIGV2ZW50IGFuZCAidmFsdWVzIiBpbiBldmVudDoKICAgICAgICAgICAgZm9yIHZhbHVlcyBpbiBldmVudFsidmFsdWVzIl06CiAgICAgICAgICAgICAgICBldmVudHMuYXBwZW5kKHtrOiB2IGZvciBrLCB2IGluIHppcChldmVudFsiaGVhZGVycyJdLCB2YWx1ZXMpfSkKICAgICAgICBlbHNlOgogICAgICAgICAgICBldmVudHMuYXBwZW5kKGV2ZW50KQoKICAgICAgICBmb3IgZW5yaWNoZWQgaW4gbWFwKGVucmljaF9ldmVuX2RldGFpbHMsIGV2ZW50cyk6CiAgICAgICAgICAgIGlmIGVucmljaGVkIGlzIG5vdCBOb25lOgogICAgICAgICAgICAgICAgc2VsZi5fZmxvdy5lbWl0KAogICAgICAgICAgICAgICAgICAgIGVucmljaGVkLAogICAgICAgICAgICAgICAgICAgIGtleT1lbnJpY2hlZFtFTkRQT0lOVF9JRF0sCiAgICAgICAgICAgICAgICAgICAgZXZlbnRfdGltZT1kYXRldGltZS5zdHJwdGltZShlbnJpY2hlZFsid2hlbiJdLCBJU09fODA2MV9VVEMpLAogICAgICAgICAgICAgICAgKQogICAgICAgICAgICBlbHNlOgogICAgICAgICAgICAgICAgcGFzcwoKICAgIEBzdGF0aWNtZXRob2QKICAgIGRlZiBjb21wdXRlX3ByZWRpY3Rpb25zX3Blcl9zZWNvbmQoZXZlbnQ6IGRpY3QpOgogICAgICAgIGV2ZW50W1BSRURJQ1RJT05TX1BFUl9TRUNPTkRdID0gZmxvYXQoZXZlbnRbUFJFRElDVElPTlNfQ09VTlRfNU1dKSAvIDYwMAogICAgICAgIHJldHVybiBldmVudAoKICAgIGRlZiBwcm9jZXNzX2JlZm9yZV9rdihzZWxmLCBldmVudDogZGljdCk6CiAgICAgICAgIyBGaWx0ZXIgcmVsZXZhbnQga2V5cwogICAgICAgIGUgPSB7azogZXZlbnRba10gZm9yIGsgaW4gc2VsZi5fa3Zfa2V5c30KICAgICAgICAjIFVucGFjayBsYWJlbHMgZGljdGlvbmFyeQogICAgICAgIGUgPSB7KiplLCAqKmUucG9wKFVOUEFDS0VEX0xBQkVMUywge30pfQogICAgICAgICMgV3JpdGUgbGFiZWxzIHRvIGt2IGFzIGpzb24gc3RyaW5nIHRvIGJlIHByZXNlbnRhYmxlIGxhdGVyCiAgICAgICAgZVtMQUJFTFNdID0ganNvbi5kdW1wcyhlW0xBQkVMU10pCiAgICAgICAgcmV0dXJuIGUKCiAgICBAc3RhdGljbWV0aG9kCiAgICBkZWYgcHJvY2Vzc19iZWZvcmVfZXZlbnRzX3RzZGIoZXZlbnQ6IERpY3QpOgogICAgICAgIGJhc2VfZmllbGRzID0gW1RJTUVTVEFNUCwgRU5EUE9JTlRfSURdCgogICAgICAgIGJhc2VfZXZlbnQgPSB7azogZXZlbnRba10gZm9yIGsgaW4gYmFzZV9maWVsZHN9CiAgICAgICAgYmFzZV9ldmVudFtUSU1FU1RBTVBdID0gcGQudG9fZGF0ZXRpbWUoCiAgICAgICAgICAgIGJhc2VfZXZlbnRbVElNRVNUQU1QXSwgZm9ybWF0PVRJTUVfRk9STUFUCiAgICAgICAgKQoKICAgICAgICBiYXNlX21ldHJpY3MgPSB7CiAgICAgICAgICAgIFJFQ09SRF9UWVBFOiBCQVNFX01FVFJJQ1MsCiAgICAgICAgICAgIFBSRURJQ1RJT05TX1BFUl9TRUNPTkQ6IGV2ZW50W1BSRURJQ1RJT05TX1BFUl9TRUNPTkRdLAogICAgICAgICAgICBQUkVESUNUSU9OU19DT1VOVF81TTogZXZlbnRbUFJFRElDVElPTlNfQ09VTlRfNU1dLAogICAgICAgICAgICBQUkVESUNUSU9OU19DT1VOVF8xSDogZXZlbnRbUFJFRElDVElPTlNfQ09VTlRfMUhdLAogICAgICAgICAgICBMQVRFTkNZX0FWR181TTogZXZlbnRbTEFURU5DWV9BVkdfNU1dLAogICAgICAgICAgICBMQVRFTkNZX0FWR18xSDogZXZlbnRbTEFURU5DWV9BVkdfMUhdLAogICAgICAgICAgICAqKmJhc2VfZXZlbnQsCiAgICAgICAgfQoKICAgICAgICBlbmRwb2ludF9mZWF0dXJlcyA9IHsKICAgICAgICAgICAgUkVDT1JEX1RZUEU6IEVORFBPSU5UX0ZFQVRVUkVTLAogICAgICAgICAgICAqKmV2ZW50W05BTUVEX1BSRURJQ1RJT05TXSwKICAgICAgICAgICAgKipldmVudFtOQU1FRF9GRUFUVVJFU10sCiAgICAgICAgICAgICoqYmFzZV9ldmVudCwKICAgICAgICB9CgogICAgICAgIHByb2Nlc3NlZCA9IHtCQVNFX01FVFJJQ1M6IGJhc2VfbWV0cmljcywgRU5EUE9JTlRfRkVBVFVSRVM6IGVuZHBvaW50X2ZlYXR1cmVzfQoKICAgICAgICBpZiBldmVudFtNRVRSSUNTXToKICAgICAgICAgICAgcHJvY2Vzc2VkW0NVU1RPTV9NRVRSSUNTXSA9IHsKICAgICAgICAgICAgICAgIFJFQ09SRF9UWVBFOiBDVVNUT01fTUVUUklDUywKICAgICAgICAgICAgICAgICoqZXZlbnRbTUVUUklDU10sCiAgICAgICAgICAgICAgICAqKmJhc2VfZXZlbnQsCiAgICAgICAgICAgIH0KCiAgICAgICAgcmV0dXJuIHByb2Nlc3NlZAoKICAgIEBzdGF0aWNtZXRob2QKICAgIGRlZiBwcm9jZXNzX2JlZm9yZV9wYXJxdWV0KGV2ZW50OiBkaWN0KToKICAgICAgICBkZWYgc2V0X25vbmVfaWZfZW1wdHkoX2V2ZW50OiBkaWN0LCBrZXlzOiBMaXN0W3N0cl0pOgogICAgICAgICAgICBmb3Iga2V5IGluIGtleXM6CiAgICAgICAgICAgICAgICBpZiBub3QgX2V2ZW50LmdldChrZXkpOgogICAgICAgICAgICAgICAgICAgIF9ldmVudFtrZXldID0gTm9uZQoKICAgICAgICBkZWYgZHJvcF9pZl9leGlzdHMoX2V2ZW50OiBkaWN0LCBrZXlzOiBMaXN0W3N0cl0pOgogICAgICAgICAgICBmb3Iga2V5IGluIGtleXM6CiAgICAgICAgICAgICAgICBfZXZlbnQucG9wKGtleSwgTm9uZSkKCiAgICAgICAgZGVmIHVucGFja19pZl9leGlzdHMoX2V2ZW50OiBkaWN0LCBrZXlzOiBMaXN0W3N0cl0pOgogICAgICAgICAgICBmb3Iga2V5IGluIGtleXM6CiAgICAgICAgICAgICAgICB2YWx1ZSA9IF9ldmVudC5nZXQoa2V5KQogICAgICAgICAgICAgICAgaWYgdmFsdWUgaXMgbm90IE5vbmU6CiAgICAgICAgICAgICAgICAgICAgX2V2ZW50ID0geyoqdmFsdWUsICoqZXZlbnR9CgogICAgICAgIGRyb3BfaWZfZXhpc3RzKGV2ZW50LCBbVU5QQUNLRURfTEFCRUxTLCBGRUFUVVJFU10pCiAgICAgICAgdW5wYWNrX2lmX2V4aXN0cyhldmVudCwgW0VOVElUSUVTXSkKICAgICAgICBzZXRfbm9uZV9pZl9lbXB0eShldmVudCwgW0xBQkVMUywgTUVUUklDUywgRU5USVRJRVNdKQogICAgICAgIHJldHVybiBldmVudAoKCmNsYXNzIFByb2Nlc3NFbmRwb2ludEV2ZW50KE1hcENsYXNzKToKICAgIGRlZiBfX2luaXRfXyhzZWxmLCBrdl9jb250YWluZXI6IHN0ciwga3ZfcGF0aDogc3RyLCB2M2lvX2FjY2Vzc19rZXk6IHN0ciwgKiprd2FyZ3MpOgogICAgICAgIHN1cGVyKCkuX19pbml0X18oKiprd2FyZ3MpCiAgICAgICAgc2VsZi5rdl9jb250YWluZXI6IHN0ciA9IGt2X2NvbnRhaW5lcgogICAgICAgIHNlbGYua3ZfcGF0aDogc3RyID0ga3ZfcGF0aAogICAgICAgIHNlbGYudjNpb19hY2Nlc3Nfa2V5OiBzdHIgPSB2M2lvX2FjY2Vzc19rZXkKICAgICAgICBzZWxmLmZpcnN0X3JlcXVlc3Q6IERpY3Rbc3RyLCBzdHJdID0gZGljdCgpCiAgICAgICAgc2VsZi5sYXN0X3JlcXVlc3Q6IERpY3Rbc3RyLCBzdHJdID0gZGljdCgpCiAgICAgICAgc2VsZi5lcnJvcl9jb3VudDogRGljdFtzdHIsIGludF0gPSBkZWZhdWx0ZGljdChpbnQpCiAgICAgICAgc2VsZi5lbmRwb2ludHM6IFNldFtzdHJdID0gc2V0KCkKCiAgICBkZWYgZG8oc2VsZiwgZXZlbnQ6IGRpY3QpOgogICAgICAgIGZ1bmN0aW9uX3VyaSA9IGV2ZW50W0ZVTkNUSU9OX1VSSV0KICAgICAgICB2ZXJzaW9uZWRfbW9kZWwgPSBldmVudFtWRVJTSU9ORURfTU9ERUxdCiAgICAgICAgZW5kcG9pbnRfaWQgPSBldmVudFtFTkRQT0lOVF9JRF0KCiAgICAgICAgIyBJbiBjYXNlIHRoaXMgcHJvY2VzcyBmYWlscywgcmVzdW1lIHN0YXRlIGZyb20gZXhpc3RpbmcgcmVjb3JkCiAgICAgICAgc2VsZi5yZXN1bWVfc3RhdGUoZW5kcG9pbnRfaWQpCgogICAgICAgICMgSGFuZGxlIGVycm9ycyBjb21pbmcgZnJvbSBzdHJlYW0KICAgICAgICBmb3VuZF9lcnJvcnMgPSBzZWxmLmhhbmRsZV9lcnJvcnMoZW5kcG9pbnRfaWQsIGV2ZW50KQogICAgICAgIGlmIGZvdW5kX2Vycm9yczoKICAgICAgICAgICAgcmV0dXJuIE5vbmUKCiAgICAgICAgIyBWYWxpZGF0ZSBldmVudCBmaWVsZHMKICAgICAgICBtb2RlbF9jbGFzcyA9IGV2ZW50LmdldCgibW9kZWxfY2xhc3MiKSBvciBldmVudC5nZXQoImNsYXNzIikKICAgICAgICB0aW1lc3RhbXAgPSBldmVudC5nZXQoIndoZW4iKQogICAgICAgIHJlcXVlc3RfaWQgPSBldmVudC5nZXQoInJlcXVlc3QiLCB7fSkuZ2V0KCJpZCIpCiAgICAgICAgbGF0ZW5jeSA9IGV2ZW50LmdldCgibWljcm9zZWMiKQogICAgICAgIGZlYXR1cmVzID0gZXZlbnQuZ2V0KCJyZXF1ZXN0Iiwge30pLmdldCgiaW5wdXRzIikKICAgICAgICBwcmVkaWN0aW9ucyA9IGV2ZW50LmdldCgicmVzcCIsIHt9KS5nZXQoIm91dHB1dHMiKQoKICAgICAgICBpZiBub3Qgc2VsZi5pc192YWxpZChlbmRwb2ludF9pZCwgaXNfbm90X25vbmUsIHRpbWVzdGFtcCwgWyJ3aGVuIl0sKToKICAgICAgICAgICAgcmV0dXJuIE5vbmUKCiAgICAgICAgaWYgZW5kcG9pbnRfaWQgbm90IGluIHNlbGYuZmlyc3RfcmVxdWVzdDoKICAgICAgICAgICAgc2VsZi5maXJzdF9yZXF1ZXN0W2VuZHBvaW50X2lkXSA9IHRpbWVzdGFtcAogICAgICAgIHNlbGYubGFzdF9yZXF1ZXN0W2VuZHBvaW50X2lkXSA9IHRpbWVzdGFtcAoKICAgICAgICBpZiBub3Qgc2VsZi5pc192YWxpZChlbmRwb2ludF9pZCwgaXNfbm90X25vbmUsIHJlcXVlc3RfaWQsIFsicmVxdWVzdCIsICJpZCJdLCk6CiAgICAgICAgICAgIHJldHVybiBOb25lCiAgICAgICAgaWYgbm90IHNlbGYuaXNfdmFsaWQoZW5kcG9pbnRfaWQsIGlzX25vdF9ub25lLCBsYXRlbmN5LCBbIm1pY3Jvc2VjIl0sKToKICAgICAgICAgICAgcmV0dXJuIE5vbmUKICAgICAgICBpZiBub3Qgc2VsZi5pc192YWxpZCgKICAgICAgICAgICAgZW5kcG9pbnRfaWQsIGlzX25vdF9ub25lLCBmZWF0dXJlcywgWyJyZXF1ZXN0IiwgImlucHV0cyJdLAogICAgICAgICk6CiAgICAgICAgICAgIHJldHVybiBOb25lCiAgICAgICAgaWYgbm90IHNlbGYuaXNfdmFsaWQoCiAgICAgICAgICAgIGVuZHBvaW50X2lkLCBpc19ub3Rfbm9uZSwgcHJlZGljdGlvbnMsIFsicmVzcCIsICJvdXRwdXRzIl0sCiAgICAgICAgKToKICAgICAgICAgICAgcmV0dXJuIE5vbmUKCiAgICAgICAgdW5wYWNrZWRfbGFiZWxzID0ge2YiX3trfSI6IHYgZm9yIGssIHYgaW4gZXZlbnQuZ2V0KExBQkVMUywge30pLml0ZW1zKCl9CgogICAgICAgICMgU2VwYXJhdGUgZWFjaCBtb2RlbCBpbnZvY2F0aW9uIGludG8gc3ViIGV2ZW50cwogICAgICAgIGV2ZW50cyA9IFtdCiAgICAgICAgZm9yIGksIChmZWF0dXJlLCBwcmVkaWN0aW9uKSBpbiBlbnVtZXJhdGUoemlwKGZlYXR1cmVzLCBwcmVkaWN0aW9ucykpOgogICAgICAgICAgICBpZiBub3Qgc2VsZi5pc192YWxpZCgKICAgICAgICAgICAgICAgIGVuZHBvaW50X2lkLAogICAgICAgICAgICAgICAgaXNfbGlzdF9vZl9udW1lcmljcywKICAgICAgICAgICAgICAgIGZlYXR1cmUsCiAgICAgICAgICAgICAgICBbInJlcXVlc3QiLCAiaW5wdXRzIiwgZiJbe2l9XSJdLAogICAgICAgICAgICApOgogICAgICAgICAgICAgICAgcmV0dXJuIE5vbmUKCiAgICAgICAgICAgIGlmIG5vdCBpc2luc3RhbmNlKHByZWRpY3Rpb24sIGxpc3QpOgogICAgICAgICAgICAgICAgcHJlZGljdGlvbiA9IFtwcmVkaWN0aW9uXQoKICAgICAgICAgICAgZXZlbnRzLmFwcGVuZCgKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICBGVU5DVElPTl9VUkk6IGZ1bmN0aW9uX3VyaSwKICAgICAgICAgICAgICAgICAgICBNT0RFTDogdmVyc2lvbmVkX21vZGVsLAogICAgICAgICAgICAgICAgICAgIE1PREVMX0NMQVNTOiBtb2RlbF9jbGFzcywKICAgICAgICAgICAgICAgICAgICBUSU1FU1RBTVA6IHRpbWVzdGFtcCwKICAgICAgICAgICAgICAgICAgICBFTkRQT0lOVF9JRDogZW5kcG9pbnRfaWQsCiAgICAgICAgICAgICAgICAgICAgUkVRVUVTVF9JRDogcmVxdWVzdF9pZCwKICAgICAgICAgICAgICAgICAgICBMQVRFTkNZOiBsYXRlbmN5LAogICAgICAgICAgICAgICAgICAgIEZFQVRVUkVTOiBmZWF0dXJlLAogICAgICAgICAgICAgICAgICAgIFBSRURJQ1RJT046IHByZWRpY3Rpb24sCiAgICAgICAgICAgICAgICAgICAgRklSU1RfUkVRVUVTVDogc2VsZi5maXJzdF9yZXF1ZXN0W2VuZHBvaW50X2lkXSwKICAgICAgICAgICAgICAgICAgICBMQVNUX1JFUVVFU1Q6IHNlbGYubGFzdF9yZXF1ZXN0W2VuZHBvaW50X2lkXSwKICAgICAgICAgICAgICAgICAgICBFUlJPUl9DT1VOVDogc2VsZi5lcnJvcl9jb3VudFtlbmRwb2ludF9pZF0sCiAgICAgICAgICAgICAgICAgICAgTEFCRUxTOiBldmVudC5nZXQoTEFCRUxTLCB7fSksCiAgICAgICAgICAgICAgICAgICAgTUVUUklDUzogZXZlbnQuZ2V0KE1FVFJJQ1MsIHt9KSwKICAgICAgICAgICAgICAgICAgICBFTlRJVElFUzogZXZlbnQuZ2V0KCJyZXF1ZXN0Iiwge30pLmdldChFTlRJVElFUywge30pLAogICAgICAgICAgICAgICAgICAgIFVOUEFDS0VEX0xBQkVMUzogdW5wYWNrZWRfbGFiZWxzLAogICAgICAgICAgICAgICAgfQogICAgICAgICAgICApCiAgICAgICAgcmV0dXJuIGV2ZW50cwoKICAgIGRlZiByZXN1bWVfc3RhdGUoc2VsZiwgZW5kcG9pbnRfaWQpOgogICAgICAgICMgTWFrZSBzdXJlIHByb2Nlc3MgaXMgcmVzdW1hYmxlLCBpZiBwcm9jZXNzIGZhaWxzIGZvciBhbnkgcmVhc29uLCBiZSBhYmxlIHRvIHBpY2sgdGhpbmdzIHVwIGNsb3NlIHRvIHdoZXJlIHdlCiAgICAgICAgIyBsZWZ0IHRoZW0KICAgICAgICBpZiBlbmRwb2ludF9pZCBub3QgaW4gc2VsZi5lbmRwb2ludHM6CiAgICAgICAgICAgIGxvZ2dlci5pbmZvKCJUcnlpbmcgdG8gcmVzdW1lIHN0YXRlIiwgZW5kcG9pbnRfaWQ9ZW5kcG9pbnRfaWQpCiAgICAgICAgICAgIGVuZHBvaW50X3JlY29yZCA9IGdldF9lbmRwb2ludF9yZWNvcmQoCiAgICAgICAgICAgICAgICBrdl9jb250YWluZXI9c2VsZi5rdl9jb250YWluZXIsCiAgICAgICAgICAgICAgICBrdl9wYXRoPXNlbGYua3ZfcGF0aCwKICAgICAgICAgICAgICAgIGVuZHBvaW50X2lkPWVuZHBvaW50X2lkLAogICAgICAgICAgICAgICAgYWNjZXNzX2tleT1zZWxmLnYzaW9fYWNjZXNzX2tleSwKICAgICAgICAgICAgKQogICAgICAgICAgICBpZiBlbmRwb2ludF9yZWNvcmQ6CiAgICAgICAgICAgICAgICBmaXJzdF9yZXF1ZXN0ID0gZW5kcG9pbnRfcmVjb3JkLmdldChGSVJTVF9SRVFVRVNUKQogICAgICAgICAgICAgICAgaWYgZmlyc3RfcmVxdWVzdDoKICAgICAgICAgICAgICAgICAgICBzZWxmLmZpcnN0X3JlcXVlc3RbZW5kcG9pbnRfaWRdID0gZmlyc3RfcmVxdWVzdAogICAgICAgICAgICAgICAgZXJyb3JfY291bnQgPSBlbmRwb2ludF9yZWNvcmQuZ2V0KEVSUk9SX0NPVU5UKQogICAgICAgICAgICAgICAgaWYgZXJyb3JfY291bnQ6CiAgICAgICAgICAgICAgICAgICAgc2VsZi5lcnJvcl9jb3VudFtlbmRwb2ludF9pZF0gPSBlcnJvcl9jb3VudAogICAgICAgICAgICBzZWxmLmVuZHBvaW50cy5hZGQoZW5kcG9pbnRfaWQpCgogICAgZGVmIGlzX3ZhbGlkKAogICAgICAgIHNlbGYsIGVuZHBvaW50X2lkOiBzdHIsIHZhbGlkYXRpb25fZnVuY3Rpb24sIGZpZWxkOiBBbnksIGRpY3RfcGF0aDogTGlzdFtzdHJdCiAgICApOgogICAgICAgIGlmIHZhbGlkYXRpb25fZnVuY3Rpb24oZmllbGQsIGRpY3RfcGF0aCk6CiAgICAgICAgICAgIHJldHVybiBUcnVlCiAgICAgICAgc2VsZi5lcnJvcl9jb3VudFtlbmRwb2ludF9pZF0gKz0gMQogICAgICAgIHJldHVybiBGYWxzZQoKICAgIGRlZiBoYW5kbGVfZXJyb3JzKHNlbGYsIGVuZHBvaW50X2lkLCBldmVudCkgLT4gYm9vbDoKICAgICAgICBpZiAiZXJyb3IiIGluIGV2ZW50OgogICAgICAgICAgICBzZWxmLmVycm9yX2NvdW50W2VuZHBvaW50X2lkXSArPSAxCiAgICAgICAgICAgIHJldHVybiBUcnVlCgogICAgICAgIHJldHVybiBGYWxzZQoKCmRlZiBlbnJpY2hfZXZlbl9kZXRhaWxzKGV2ZW50KSAtPiBPcHRpb25hbFtkaWN0XToKICAgIGZ1bmN0aW9uX3VyaSA9IGV2ZW50LmdldChGVU5DVElPTl9VUkkpCgogICAgaWYgbm90IGlzX25vdF9ub25lKGZ1bmN0aW9uX3VyaSwgW0ZVTkNUSU9OX1VSSV0pOgogICAgICAgIHJldHVybiBOb25lCgogICAgbW9kZWwgPSBldmVudC5nZXQoTU9ERUwpCiAgICBpZiBub3QgaXNfbm90X25vbmUobW9kZWwsIFtNT0RFTF0pOgogICAgICAgIHJldHVybiBOb25lCgogICAgdmVyc2lvbiA9IGV2ZW50LmdldChWRVJTSU9OKQogICAgdmVyc2lvbmVkX21vZGVsID0gZiJ7bW9kZWx9Ont2ZXJzaW9ufSIgaWYgdmVyc2lvbiBlbHNlIGYie21vZGVsfTpsYXRlc3QiCgogICAgZW5kcG9pbnRfaWQgPSBjcmVhdGVfbW9kZWxfZW5kcG9pbnRfaWQoCiAgICAgICAgZnVuY3Rpb25fdXJpPWZ1bmN0aW9uX3VyaSwgdmVyc2lvbmVkX21vZGVsPXZlcnNpb25lZF9tb2RlbCwKICAgICkKCiAgICBlbmRwb2ludF9pZCA9IHN0cihlbmRwb2ludF9pZCkKCiAgICBldmVudFtWRVJTSU9ORURfTU9ERUxdID0gdmVyc2lvbmVkX21vZGVsCiAgICBldmVudFtFTkRQT0lOVF9JRF0gPSBlbmRwb2ludF9pZAoKICAgIHJldHVybiBldmVudAoKCmRlZiBpc19ub3Rfbm9uZShmaWVsZDogQW55LCBkaWN0X3BhdGg6IExpc3Rbc3RyXSk6CiAgICBpZiBmaWVsZCBpcyBub3QgTm9uZToKICAgICAgICByZXR1cm4gVHJ1ZQogICAgbG9nZ2VyLmVycm9yKAogICAgICAgIGYiRXhwZWN0ZWQgZXZlbnQgZmllbGQgaXMgbWlzc2luZzoge2ZpZWxkfSBbRXZlbnQgLT4geycnLmpvaW4oZGljdF9wYXRoKX1dIgogICAgKQogICAgcmV0dXJuIEZhbHNlCgoKZGVmIGlzX2xpc3Rfb2ZfbnVtZXJpY3MoCiAgICBmaWVsZDogTGlzdFtVbmlvbltpbnQsIGZsb2F0LCBkaWN0LCBsaXN0XV0sIGRpY3RfcGF0aDogTGlzdFtzdHJdCik6CiAgICBpZiBhbGwoaXNpbnN0YW5jZSh4LCBpbnQpIG9yIGlzaW5zdGFuY2UoeCwgZmxvYXQpIGZvciB4IGluIGZpZWxkKToKICAgICAgICByZXR1cm4gVHJ1ZQogICAgbG9nZ2VyLmVycm9yKAogICAgICAgIGYiRXhwZWN0ZWQgZXZlbnQgZmllbGQgaXMgbWlzc2luZzoge2ZpZWxkfSBbRXZlbnQgLT4geycnLmpvaW4oZGljdF9wYXRoKX1dIgogICAgKQogICAgcmV0dXJuIEZhbHNlCgoKY2xhc3MgRmlsdGVyTm90Tm9uZShGaWx0ZXIpOgogICAgZGVmIF9faW5pdF9fKHNlbGYsICoqa3dhcmdzKToKICAgICAgICBzdXBlcigpLl9faW5pdF9fKGZuPWxhbWJkYSBldmVudDogZXZlbnQgaXMgbm90IE5vbmUsICoqa3dhcmdzKQoKCmNsYXNzIEZpbHRlcktleXMoTWFwQ2xhc3MpOgogICAgZGVmIF9faW5pdF9fKHNlbGYsICphcmdzLCAqKmt3YXJncyk6CiAgICAgICAgc3VwZXIoKS5fX2luaXRfXygqKmt3YXJncykKICAgICAgICBzZWxmLmtleXMgPSBsaXN0KGFyZ3MpCgogICAgZGVmIGRvKHNlbGYsIGV2ZW50KToKICAgICAgICBuZXdfZXZlbnQgPSB7fQogICAgICAgIGZvciBrZXkgaW4gc2VsZi5rZXlzOgogICAgICAgICAgICBpZiBrZXkgaW4gZXZlbnQ6CiAgICAgICAgICAgICAgICBuZXdfZXZlbnRba2V5XSA9IGV2ZW50W2tleV0KCiAgICAgICAgcmV0dXJuIG5ld19ldmVudCBpZiBuZXdfZXZlbnQgZWxzZSBOb25lCgoKY2xhc3MgVW5wYWNrVmFsdWVzKE1hcENsYXNzKToKICAgIGRlZiBfX2luaXRfXyhzZWxmLCAqYXJncywgKiprd2FyZ3MpOgogICAgICAgIHN1cGVyKCkuX19pbml0X18oKiprd2FyZ3MpCiAgICAgICAgc2VsZi5rZXlzX3RvX3VucGFjayA9IHNldChhcmdzKQoKICAgIGRlZiBkbyhzZWxmLCBldmVudCk6CiAgICAgICAgdW5wYWNrZWQgPSB7fQogICAgICAgIGZvciBrZXkgaW4gZXZlbnQua2V5cygpOgogICAgICAgICAgICBpZiBrZXkgaW4gc2VsZi5rZXlzX3RvX3VucGFjazoKICAgICAgICAgICAgICAgIHVucGFja2VkID0geyoqdW5wYWNrZWQsICoqZXZlbnRba2V5XX0KICAgICAgICAgICAgZWxzZToKICAgICAgICAgICAgICAgIHVucGFja2VkW2tleV0gPSBldmVudFtrZXldCiAgICAgICAgcmV0dXJuIHVucGFja2VkCgoKY2xhc3MgTWFwRmVhdHVyZU5hbWVzKE1hcENsYXNzKToKICAgIGRlZiBfX2luaXRfXyhzZWxmLCBrdl9jb250YWluZXI6IHN0ciwga3ZfcGF0aDogc3RyLCBhY2Nlc3Nfa2V5OiBzdHIsICoqa3dhcmdzKToKICAgICAgICBzdXBlcigpLl9faW5pdF9fKCoqa3dhcmdzKQogICAgICAgIHNlbGYua3ZfY29udGFpbmVyID0ga3ZfY29udGFpbmVyCiAgICAgICAgc2VsZi5rdl9wYXRoID0ga3ZfcGF0aAogICAgICAgIHNlbGYuYWNjZXNzX2tleSA9IGFjY2Vzc19rZXkKICAgICAgICBzZWxmLmZlYXR1cmVfbmFtZXMgPSB7fQogICAgICAgIHNlbGYubGFiZWxfY29sdW1ucyA9IHt9CgogICAgZGVmIGRvKHNlbGYsIGV2ZW50OiBEaWN0KToKICAgICAgICBlbmRwb2ludF9pZCA9IGV2ZW50W0VORFBPSU5UX0lEXQoKICAgICAgICBpZiBlbmRwb2ludF9pZCBub3QgaW4gc2VsZi5mZWF0dXJlX25hbWVzOgogICAgICAgICAgICBlbmRwb2ludF9yZWNvcmQgPSBnZXRfZW5kcG9pbnRfcmVjb3JkKAogICAgICAgICAgICAgICAga3ZfY29udGFpbmVyPXNlbGYua3ZfY29udGFpbmVyLAogICAgICAgICAgICAgICAga3ZfcGF0aD1zZWxmLmt2X3BhdGgsCiAgICAgICAgICAgICAgICBlbmRwb2ludF9pZD1lbmRwb2ludF9pZCwKICAgICAgICAgICAgICAgIGFjY2Vzc19rZXk9c2VsZi5hY2Nlc3Nfa2V5LAogICAgICAgICAgICApCiAgICAgICAgICAgIGZlYXR1cmVfbmFtZXMgPSBlbmRwb2ludF9yZWNvcmQuZ2V0KEZFQVRVUkVfTkFNRVMpCiAgICAgICAgICAgIGZlYXR1cmVfbmFtZXMgPSBqc29uLmxvYWRzKGZlYXR1cmVfbmFtZXMpIGlmIGZlYXR1cmVfbmFtZXMgZWxzZSBOb25lCgogICAgICAgICAgICBsYWJlbF9jb2x1bW5zID0gZW5kcG9pbnRfcmVjb3JkLmdldChMQUJFTF9DT0xVTU5TKQogICAgICAgICAgICBsYWJlbF9jb2x1bW5zID0ganNvbi5sb2FkcyhsYWJlbF9jb2x1bW5zKSBpZiBsYWJlbF9jb2x1bW5zIGVsc2UgTm9uZQoKICAgICAgICAgICAgaWYgbm90IGZlYXR1cmVfbmFtZXM6CiAgICAgICAgICAgICAgICBsb2dnZXIud2FybigKICAgICAgICAgICAgICAgICAgICBmIkZlYXR1cmUgbmFtZXMgYXJlIG5vdCBpbml0aWFsaXplZCwgdGhleSB3aWxsIGJlIGF1dG9tYXRpY2FsbHkgZ2VuZXJhdGVkIiwKICAgICAgICAgICAgICAgICAgICBlbmRwb2ludF9pZD1lbmRwb2ludF9pZCwKICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIGZlYXR1cmVfbmFtZXMgPSBbZiJme2l9IiBmb3IgaSwgXyBpbiBlbnVtZXJhdGUoZXZlbnRbRkVBVFVSRVNdKV0KICAgICAgICAgICAgICAgIGdldF92M2lvX2NsaWVudCgpLmt2LnVwZGF0ZSgKICAgICAgICAgICAgICAgICAgICBjb250YWluZXI9c2VsZi5rdl9jb250YWluZXIsCiAgICAgICAgICAgICAgICAgICAgdGFibGVfcGF0aD1zZWxmLmt2X3BhdGgsCiAgICAgICAgICAgICAgICAgICAgYWNjZXNzX2tleT1zZWxmLmFjY2Vzc19rZXksCiAgICAgICAgICAgICAgICAgICAga2V5PWV2ZW50W0VORFBPSU5UX0lEXSwKICAgICAgICAgICAgICAgICAgICBhdHRyaWJ1dGVzPXtGRUFUVVJFX05BTUVTOiBqc29uLmR1bXBzKGZlYXR1cmVfbmFtZXMpfSwKICAgICAgICAgICAgICAgICAgICByYWlzZV9mb3Jfc3RhdHVzPVJhaXNlRm9yU3RhdHVzLmFsd2F5cywKICAgICAgICAgICAgICAgICkKCiAgICAgICAgICAgIGlmIG5vdCBsYWJlbF9jb2x1bW5zOgogICAgICAgICAgICAgICAgbG9nZ2VyLndhcm4oCiAgICAgICAgICAgICAgICAgICAgZiJsYWJlbCBjb2x1bW4gbmFtZXMgYXJlIG5vdCBpbml0aWFsaXplZCwgdGhleSB3aWxsIGJlIGF1dG9tYXRpY2FsbHkgZ2VuZXJhdGVkIiwKICAgICAgICAgICAgICAgICAgICBlbmRwb2ludF9pZD1lbmRwb2ludF9pZCwKICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIGxhYmVsX2NvbHVtbnMgPSBbZiJwe2l9IiBmb3IgaSwgXyBpbiBlbnVtZXJhdGUoZXZlbnRbUFJFRElDVElPTl0pXQogICAgICAgICAgICAgICAgZ2V0X3YzaW9fY2xpZW50KCkua3YudXBkYXRlKAogICAgICAgICAgICAgICAgICAgIGNvbnRhaW5lcj1zZWxmLmt2X2NvbnRhaW5lciwKICAgICAgICAgICAgICAgICAgICB0YWJsZV9wYXRoPXNlbGYua3ZfcGF0aCwKICAgICAgICAgICAgICAgICAgICBhY2Nlc3Nfa2V5PXNlbGYuYWNjZXNzX2tleSwKICAgICAgICAgICAgICAgICAgICBrZXk9ZXZlbnRbRU5EUE9JTlRfSURdLAogICAgICAgICAgICAgICAgICAgIGF0dHJpYnV0ZXM9e0xBQkVMX0NPTFVNTlM6IGpzb24uZHVtcHMobGFiZWxfY29sdW1ucyl9LAogICAgICAgICAgICAgICAgICAgIHJhaXNlX2Zvcl9zdGF0dXM9UmFpc2VGb3JTdGF0dXMuYWx3YXlzLAogICAgICAgICAgICAgICAgKQoKICAgICAgICAgICAgc2VsZi5sYWJlbF9jb2x1bW5zW2VuZHBvaW50X2lkXSA9IGxhYmVsX2NvbHVtbnMKICAgICAgICAgICAgc2VsZi5mZWF0dXJlX25hbWVzW2VuZHBvaW50X2lkXSA9IGZlYXR1cmVfbmFtZXMKCiAgICAgICAgICAgIGxvZ2dlci5pbmZvKAogICAgICAgICAgICAgICAgIkxhYmVsIGNvbHVtbnMiLCBlbmRwb2ludF9pZD1lbmRwb2ludF9pZCwgbGFiZWxfY29sdW1ucz1sYWJlbF9jb2x1bW5zCiAgICAgICAgICAgICkKICAgICAgICAgICAgbG9nZ2VyLmluZm8oCiAgICAgICAgICAgICAgICAiRmVhdHVyZSBuYW1lcyIsIGVuZHBvaW50X2lkPWVuZHBvaW50X2lkLCBmZWF0dXJlX25hbWVzPWZlYXR1cmVfbmFtZXMKICAgICAgICAgICAgKQoKICAgICAgICBmZWF0dXJlX25hbWVzID0gc2VsZi5mZWF0dXJlX25hbWVzW2VuZHBvaW50X2lkXQogICAgICAgIGZlYXR1cmVzID0gZXZlbnRbRkVBVFVSRVNdCiAgICAgICAgZXZlbnRbTkFNRURfRkVBVFVSRVNdID0gewogICAgICAgICAgICBuYW1lOiBmZWF0dXJlIGZvciBuYW1lLCBmZWF0dXJlIGluIHppcChmZWF0dXJlX25hbWVzLCBmZWF0dXJlcykKICAgICAgICB9CgogICAgICAgIGxhYmVsX2NvbHVtbnMgPSBzZWxmLmxhYmVsX2NvbHVtbnNbZW5kcG9pbnRfaWRdCiAgICAgICAgcHJlZGljdGlvbiA9IGV2ZW50W1BSRURJQ1RJT05dCiAgICAgICAgZXZlbnRbTkFNRURfUFJFRElDVElPTlNdID0gewogICAgICAgICAgICBuYW1lOiBwcmVkaWN0aW9uIGZvciBuYW1lLCBwcmVkaWN0aW9uIGluIHppcChsYWJlbF9jb2x1bW5zLCBwcmVkaWN0aW9uKQogICAgICAgIH0KICAgICAgICBsb2dnZXIuaW5mbygiTWFwcGVkIGV2ZW50IiwgZXZlbnQ9ZXZlbnQpCiAgICAgICAgcmV0dXJuIGV2ZW50CgoKY2xhc3MgV3JpdGVUb0tWKE1hcENsYXNzKToKICAgIGRlZiBfX2luaXRfXyhzZWxmLCBjb250YWluZXI6IHN0ciwgdGFibGU6IHN0ciwgKiprd2FyZ3MpOgogICAgICAgIHN1cGVyKCkuX19pbml0X18oKiprd2FyZ3MpCiAgICAgICAgc2VsZi5jb250YWluZXIgPSBjb250YWluZXIKICAgICAgICBzZWxmLnRhYmxlID0gdGFibGUKCiAgICBkZWYgZG8oc2VsZiwgZXZlbnQ6IERpY3QpOgogICAgICAgIGdldF92M2lvX2NsaWVudCgpLmt2LnVwZGF0ZSgKICAgICAgICAgICAgY29udGFpbmVyPXNlbGYuY29udGFpbmVyLAogICAgICAgICAgICB0YWJsZV9wYXRoPXNlbGYudGFibGUsCiAgICAgICAgICAgIGtleT1ldmVudFtFTkRQT0lOVF9JRF0sCiAgICAgICAgICAgIGF0dHJpYnV0ZXM9ZXZlbnQsCiAgICAgICAgKQogICAgICAgIHJldHVybiBldmVudAoKCmNsYXNzIEluZmVyU2NoZW1hKE1hcENsYXNzKToKICAgIGRlZiBfX2luaXRfXygKICAgICAgICBzZWxmLAogICAgICAgIHYzaW9fYWNjZXNzX2tleTogc3RyLAogICAgICAgIHYzaW9fZnJhbWVzZDogc3RyLAogICAgICAgIGNvbnRhaW5lcjogc3RyLAogICAgICAgIHRhYmxlOiBzdHIsCiAgICAgICAgKiprd2FyZ3MsCiAgICApOgogICAgICAgIHN1cGVyKCkuX19pbml0X18oKiprd2FyZ3MpCiAgICAgICAgc2VsZi5jb250YWluZXIgPSBjb250YWluZXIKICAgICAgICBzZWxmLnYzaW9fYWNjZXNzX2tleSA9IHYzaW9fYWNjZXNzX2tleQogICAgICAgIHNlbGYudjNpb19mcmFtZXNkID0gdjNpb19mcmFtZXNkCiAgICAgICAgc2VsZi50YWJsZSA9IHRhYmxlCiAgICAgICAgc2VsZi5rZXlzID0gc2V0KCkKCiAgICBkZWYgZG8oc2VsZiwgZXZlbnQ6IERpY3QpOgogICAgICAgIGtleV9zZXQgPSBzZXQoZXZlbnQua2V5cygpKQogICAgICAgIGlmIG5vdCBrZXlfc2V0Lmlzc3Vic2V0KHNlbGYua2V5cyk6CiAgICAgICAgICAgIHNlbGYua2V5cy51cGRhdGUoa2V5X3NldCkKICAgICAgICAgICAgZ2V0X2ZyYW1lc19jbGllbnQoCiAgICAgICAgICAgICAgICB0b2tlbj1zZWxmLnYzaW9fYWNjZXNzX2tleSwKICAgICAgICAgICAgICAgIGNvbnRhaW5lcj1zZWxmLmNvbnRhaW5lciwKICAgICAgICAgICAgICAgIGFkZHJlc3M9c2VsZi52M2lvX2ZyYW1lc2QsCiAgICAgICAgICAgICkuZXhlY3V0ZShiYWNrZW5kPSJrdiIsIHRhYmxlPXNlbGYudGFibGUsIGNvbW1hbmQ9ImluZmVyX3NjaGVtYSIpCiAgICAgICAgICAgIGxvZ2dlci5pbmZvKAogICAgICAgICAgICAgICAgIkZvdW5kIG5ldyBrZXlzLCBpbmZlcnJlZCBzY2hlbWEiLCB0YWJsZT1zZWxmLnRhYmxlLCBldmVudD1ldmVudAogICAgICAgICAgICApCiAgICAgICAgcmV0dXJuIGV2ZW50CgoKZGVmIGdldF9lbmRwb2ludF9yZWNvcmQoCiAgICBrdl9jb250YWluZXI6IHN0ciwga3ZfcGF0aDogc3RyLCBlbmRwb2ludF9pZDogc3RyLCBhY2Nlc3Nfa2V5OiBzdHIKKSAtPiBPcHRpb25hbFtkaWN0XToKICAgIGxvZ2dlci5pbmZvKAogICAgICAgIGYiR3JhYmJpbmcgZW5kcG9pbnQgZGF0YSIsCiAgICAgICAgY29udGFpbmVyPWt2X2NvbnRhaW5lciwKICAgICAgICB0YWJsZV9wYXRoPWt2X3BhdGgsCiAgICAgICAga2V5PWVuZHBvaW50X2lkLAogICAgKQogICAgdHJ5OgogICAgICAgIGVuZHBvaW50X3JlY29yZCA9ICgKICAgICAgICAgICAgZ2V0X3YzaW9fY2xpZW50KCkKICAgICAgICAgICAgLmt2LmdldCgKICAgICAgICAgICAgICAgIGNvbnRhaW5lcj1rdl9jb250YWluZXIsCiAgICAgICAgICAgICAgICB0YWJsZV9wYXRoPWt2X3BhdGgsCiAgICAgICAgICAgICAgICBrZXk9ZW5kcG9pbnRfaWQsCiAgICAgICAgICAgICAgICBhY2Nlc3Nfa2V5PWFjY2Vzc19rZXksCiAgICAgICAgICAgICAgICByYWlzZV9mb3Jfc3RhdHVzPXYzaW8uZGF0YXBsYW5lLlJhaXNlRm9yU3RhdHVzLmFsd2F5cywKICAgICAgICAgICAgKQogICAgICAgICAgICAub3V0cHV0Lml0ZW0KICAgICAgICApCiAgICAgICAgcmV0dXJuIGVuZHBvaW50X3JlY29yZAogICAgZXhjZXB0IEV4Y2VwdGlvbjoKICAgICAgICByZXR1cm4gTm9uZQoKCmRlZiBpbml0X2NvbnRleHQoY29udGV4dDogTUxDbGllbnRDdHgpOgogICAgY29udGV4dC5sb2dnZXIuaW5mbygiSW5pdGlhbGl6aW5nIEV2ZW50U3RyZWFtUHJvY2Vzc29yIikKICAgIHBhcmFtZXRlcnMgPSBlbnZpcm9uLmdldCgiTU9ERUxfTU9OSVRPUklOR19QQVJBTUVURVJTIikKICAgIHBhcmFtZXRlcnMgPSBqc29uLmxvYWRzKHBhcmFtZXRlcnMpIGlmIHBhcmFtZXRlcnMgZWxzZSB7fQogICAgc3RyZWFtX3Byb2Nlc3NvciA9IEV2ZW50U3RyZWFtUHJvY2Vzc29yKCoqcGFyYW1ldGVycykKICAgIHNldGF0dHIoY29udGV4dCwgInN0cmVhbV9wcm9jZXNzb3IiLCBzdHJlYW1fcHJvY2Vzc29yKQoKCmRlZiBoYW5kbGVyKGNvbnRleHQ6IE1MQ2xpZW50Q3R4LCBldmVudDogRXZlbnQpOgogICAgZXZlbnRfYm9keSA9IGpzb24ubG9hZHMoZXZlbnQuYm9keSkKICAgIGNvbnRleHQubG9nZ2VyLmRlYnVnKGV2ZW50X2JvZHkpCiAgICBjb250ZXh0LnN0cmVhbV9wcm9jZXNzb3IuY29uc3VtZShldmVudF9ib2R5KQo= - source: '' - build: - commands: [] - code_origin: https://github.com/Michaelliv/functions.git#202b4c489e4c02c3025742ea237f1a042b7c6043:/home/michaell/projects/functions/model_monitoring_stream/model_monitoring_stream.py - default_handler: handler -verbose: false diff --git a/model_monitoring_stream/item.yaml b/model_monitoring_stream/item.yaml deleted file mode 100644 index 219fa5286..000000000 --- a/model_monitoring_stream/item.yaml +++ /dev/null @@ -1,23 +0,0 @@ -apiVersion: v1 -categories: -- monitoring -description: '' -doc: '' -example: model_monitoring_stream.ipynb -generationDate: 2022-08-28:17-25 -hidden: false -icon: '' -labels: {} -maintainers: [] -marketplaceType: '' -mlrunVersion: 1.1.0 -name: model-monitoring-stream -platformVersion: 3.5.0 -spec: - filename: model_monitoring_stream.py - handler: handler - image: livsmichael/mlrun-api:automation - kind: nuclio - requirements: [] -url: '' -version: 1.1.0 diff --git a/model_monitoring_stream/model_monitoring_stream.ipynb b/model_monitoring_stream/model_monitoring_stream.ipynb deleted file mode 100644 index 93d8c92e4..000000000 --- a/model_monitoring_stream/model_monitoring_stream.ipynb +++ /dev/null @@ -1,178 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "source": [ - "# Model Monitoring\n", - "\n", - "## Initial set up (and pre-requisites)\n", - "1. Make sure you have the `mlrun-api` datasource available in your Grafana instance, otherwise add it by:\n", - " 1. Open your grafana instance\n", - " 2. Navigate to `Configuration -> Data Sources`\n", - " 3. Press `Add data source` and configure the following parameters\n", - " ```\n", - " Name: mlrun-api\n", - " URL: http://mlrun-api:8080/api/grafana-proxy/model-endpoints\n", - " Access: Server (default)\n", - "\n", - " ## Add a custom header of:\n", - " X-V3io-Session-Key: \n", - " ```\n", - " 4. Press `Save & Test` to make sure it works, a confirmation message should appear when this button is pressed\n", - "\n", - "2. Import the available dashboards `(./dashboards/*)` to you Grafana instance\n", - "3. To allow the system to utilize drift measurement, make sure you supply the train set when logging the model on the\n", - " training step\n", - "\n", - " ```python\n", - " # Log model\n", - " context.log_model(\n", - " \"model\",\n", - " body=dumps(model),\n", - " artifact_path=context.artifact_subpath(\"models\"),\n", - " extra_data=eval_metrics,\n", - " model_file=\"model.pkl\",\n", - " metrics=context.results,\n", - " training_set=X_test, # <- make sure this is passed into log_model\n", - " labels={\"class\": \"sklearn.linear_model.LogisticRegression\"}\n", - " )\n", - " ```\n", - "4. When serving a model, make sure that the Nuclio function is deployed with tracking enabled by applying\n", - " `fn.set_tracking()`\n", - "\n", - "## Configuration\n", - "The stream processing portion of the model monitoring, can be deployed under multiple configuration options. The\n", - "available configurations can be found under `stream.Config`. Once configured it should be supplied as environment\n", - "parameters to the Nuclio function by setting `fn.set_envs`\n", - "\n", - "```python\n", - "project: str # project name\n", - "sample_window: int # The sampling window for the data that flows into the TSDB and the KV\n", - "kv_path_template: str # Path template for the kv table\n", - "tsdb_path_template: str # Path template for the tsdb table\n", - "parquet_path_template: str # v3io parquets path template, assumes v3io is mounted\n", - "tsdb_batching_max_events: int # The max amount of event to batch before writing the batch to tsdb\n", - "tsdb_batching_timeout_secs: int # The max amount of seconds a given batch can be gathered before being emitted\n", - "parquet_batching_max_events: int # The max amount of event to batch before writing the batch to parquet\n", - "parquet_batching_timeout_secs: int # The max amount of seconds, a given batch can be gathered before being written to parquet\n", - "container: str # container name\n", - "v3io_access_key: str # V3IO Access key\n", - "v3io_framesd: str # V3IO framesd URL\n", - "time_format: str # The time format into which time related fields will be converted\n", - "aggregate_count_windows: List[str] # List of window sizes for predictions count\n", - "aggregate_count_period: str # Period of predictions count windows\n", - "aggregate_avg_windows: List[str] # List of window sizes for average latency\n", - "aggregate_avg_period: str # Period of average latency windows\n", - "```" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%% md\n" - } - } - }, - { - "cell_type": "markdown", - "source": [ - "## Export function yaml" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%% md\n" - } - } - }, - { - "cell_type": "code", - "execution_count": null, - "outputs": [], - "source": [ - "from mlrun import code_to_function\n", - "from mlrun.runtimes import RemoteRuntime\n", - "\n", - "\n", - "fn: RemoteRuntime = code_to_function(\n", - " name=\"model-monitoring-stream\",\n", - " kind=\"nuclio\",\n", - " image=\"mlrun/mlrun\",\n", - " filename=\"model_monitoring_stream.py\",\n", - " handler=\"handler\",\n", - ")\n", - "fn.export(\"model_monitoring_stream.yaml\")\n" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%%\n" - } - } - }, - { - "cell_type": "markdown", - "source": [ - "## Deploy Stream Processing" - ], - "metadata": { - "collapsed": false - } - }, - { - "cell_type": "code", - "execution_count": null, - "outputs": [], - "source": [ - "import os\n", - "\n", - "from mlrun import import_function\n", - "from mlrun.platforms import mount_v3io\n", - "from mlrun.runtimes import RemoteRuntime\n", - "import json\n", - "\n", - "# Set project name\n", - "project = \"\"\n", - "\n", - "fn: RemoteRuntime = import_function(\"hub://model_monitoring_stream\")\n", - "\n", - "fn.add_v3io_stream_trigger(\n", - " stream_path=f\"projects/{project}/model-endpoints/stream\",\n", - " name=\"monitoring_stream_trigger\",\n", - ")\n", - "\n", - "fn.set_env(\"MODEL_MONITORING_PARAMETERS\", json.dumps({\"project\": project, \"v3io_framesd\": os.environ.get(\"V3IO_FRAMESD\")}))\n", - "\n", - "fn.metadata.project = project\n", - "fn.apply(mount_v3io())\n", - "fn.deploy()" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%%\n" - } - } - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 2 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.6" - } - }, - "nbformat": 4, - "nbformat_minor": 0 -} \ No newline at end of file diff --git a/model_monitoring_stream/model_monitoring_stream.py b/model_monitoring_stream/model_monitoring_stream.py deleted file mode 100644 index 90c8b92c2..000000000 --- a/model_monitoring_stream/model_monitoring_stream.py +++ /dev/null @@ -1,768 +0,0 @@ -# Copyright 2019 Iguazio -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -import json -import os -from collections import defaultdict -from datetime import datetime -from os import environ -from typing import Dict, List, Set, Optional, Any, Union - -import pandas as pd -import v3io -from mlrun.config import config -from mlrun.run import MLClientCtx -from mlrun.utils import logger -from mlrun.utils.model_monitoring import ( - parse_model_endpoint_store_prefix, - create_model_endpoint_id, -) -from mlrun.utils.v3io_clients import get_v3io_client, get_frames_client -from nuclio import Event -from storey import ( - FieldAggregator, - NoopDriver, - Table, - Map, - MapClass, - AggregateByKey, - build_flow, - Filter, - FlatMap, - TSDBTarget, - ParquetTarget, - SyncEmitSource, -) -from storey.dtypes import SlidingWindows -from storey.steps import SampleWindow -# Constants -from v3io.dataplane import RaiseForStatus - -ISO_8061_UTC = "%Y-%m-%d %H:%M:%S.%f%z" -FUNCTION_URI = "function_uri" -MODEL = "model" -VERSION = "version" -VERSIONED_MODEL = "versioned_model" -MODEL_CLASS = "model_class" -TIMESTAMP = "timestamp" -ENDPOINT_ID = "endpoint_id" -REQUEST_ID = "request_id" -LABELS = "labels" -UNPACKED_LABELS = "unpacked_labels" -LATENCY_AVG_5M = "latency_avg_5m" -LATENCY_AVG_1H = "latency_avg_1h" -PREDICTIONS_PER_SECOND = "predictions_per_second" -PREDICTIONS_COUNT_5M = "predictions_count_5m" -PREDICTIONS_COUNT_1H = "predictions_count_1h" -FIRST_REQUEST = "first_request" -LAST_REQUEST = "last_request" -ERROR_COUNT = "error_count" -ENTITIES = "entities" -FEATURE_NAMES = "feature_names" -LABEL_COLUMNS = "label_columns" -LATENCY = "latency" -RECORD_TYPE = "record_type" -FEATURES = "features" -PREDICTION = "prediction" -PREDICTIONS = "predictions" -NAMED_FEATURES = "named_features" -NAMED_PREDICTIONS = "named_predictions" -BASE_METRICS = "base_metrics" -CUSTOM_METRICS = "custom_metrics" -ENDPOINT_FEATURES = "endpoint_features" -METRICS = "metrics" -BATCH_TIMESTAMP = "batch_timestamp" -TIME_FORMAT: str = "%Y-%m-%d %H:%M:%S.%f" # ISO 8061 - - -# Stream processing code -class EventStreamProcessor: - def __init__( - self, - project: str, - sample_window: int = 10, - tsdb_batching_max_events: int = 10, - tsdb_batching_timeout_secs: int = 60 * 5, # Default 5 minutes - parquet_batching_max_events: int = 10_000, - parquet_batching_timeout_secs: int = 60 * 60, # Default 1 hour - aggregate_count_windows: Optional[List[str]] = None, - aggregate_count_period: str = "30s", - aggregate_avg_windows: Optional[List[str]] = None, - aggregate_avg_period: str = "30s", - v3io_access_key: Optional[str] = None, - v3io_framesd: Optional[str] = None, - v3io_api: Optional[str] = None, - ): - self.project = project - self.sample_window = sample_window - self.tsdb_batching_max_events = tsdb_batching_max_events - self.tsdb_batching_timeout_secs = tsdb_batching_timeout_secs - self.parquet_batching_max_events = parquet_batching_max_events - self.parquet_batching_timeout_secs = parquet_batching_timeout_secs - self.aggregate_count_windows = aggregate_count_windows or ["5m", "1h"] - self.aggregate_count_period = aggregate_count_period - self.aggregate_avg_windows = aggregate_avg_windows or ["5m", "1h"] - self.aggregate_avg_period = aggregate_avg_period - - self.v3io_framesd = v3io_framesd or config.v3io_framesd - self.v3io_api = v3io_api or config.v3io_api - - self.v3io_access_key = v3io_access_key or environ.get("V3IO_ACCESS_KEY") - self.model_monitoring_access_key = ( - os.environ.get("MODEL_MONITORING_ACCESS_KEY") or self.v3io_access_key - ) - - template = config.model_endpoint_monitoring.store_prefixes.default - - kv_path = template.format(project=project, kind="endpoints") - _, self.kv_container, self.kv_path = parse_model_endpoint_store_prefix(kv_path) - - tsdb_path = template.format(project=project, kind="events") - _, self.tsdb_container, self.tsdb_path = parse_model_endpoint_store_prefix( - tsdb_path - ) - self.tsdb_path = f"{self.tsdb_container}/{self.tsdb_path}" - - self.parquet_path = config.model_endpoint_monitoring.store_prefixes.user_space.format( - project=project, kind="parquet" - ) - - logger.info( - "V3IO Configuration", - v3io_access_key=self.v3io_access_key, - model_monitoring_access_key=self.model_monitoring_access_key, - default_store_prefix=config.model_endpoint_monitoring.store_prefixes.default, - user_space_store_prefix=config.model_endpoint_monitoring.store_prefixes.user_space, - v3io_api=self.v3io_api, - v3io_framesd=self.v3io_framesd, - kv_container=self.kv_container, - kv_path=self.kv_path, - tsdb_container=self.tsdb_container, - tsdb_path=self.tsdb_path, - parquet_path=self.parquet_path, - ) - - self._kv_keys = [ - FUNCTION_URI, - MODEL, - MODEL_CLASS, - TIMESTAMP, - ENDPOINT_ID, - LABELS, - UNPACKED_LABELS, - LATENCY_AVG_5M, - LATENCY_AVG_1H, - PREDICTIONS_PER_SECOND, - PREDICTIONS_COUNT_5M, - PREDICTIONS_COUNT_1H, - FIRST_REQUEST, - LAST_REQUEST, - ERROR_COUNT, - ] - - self._flow = build_flow( - [ - SyncEmitSource(), - ProcessEndpointEvent( - kv_container=self.kv_container, - kv_path=self.kv_path, - v3io_access_key=self.v3io_access_key, - ), - FilterNotNone(), - FlatMap(lambda x: x), - MapFeatureNames( - kv_container=self.kv_container, - kv_path=self.kv_path, - access_key=self.v3io_access_key, - ), - # Branch 1: Aggregate events, count averages and update TSDB and KV - [ - AggregateByKey( - aggregates=[ - FieldAggregator( - PREDICTIONS, - ENDPOINT_ID, - ["count"], - SlidingWindows( - self.aggregate_count_windows, - self.aggregate_count_period, - ), - ), - FieldAggregator( - LATENCY, - LATENCY, - ["avg"], - SlidingWindows( - self.aggregate_avg_windows, - self.aggregate_avg_period, - ), - ), - ], - table=Table("notable", NoopDriver()), - ), - SampleWindow( - self.sample_window - ), # Add required gap between event to apply sampling - Map(self.compute_predictions_per_second), - # Branch 1.1: Updated KV - [ - Map(self.process_before_kv), - WriteToKV(container=self.kv_container, table=self.kv_path), - InferSchema( - v3io_access_key=self.v3io_access_key, - v3io_framesd=self.v3io_framesd, - container=self.kv_container, - table=self.kv_path, - ), - ], - # Branch 1.2: Update TSDB - [ - # Map the event into taggable fields, add record type to each field - Map(self.process_before_events_tsdb), - [ - FilterKeys(BASE_METRICS), - UnpackValues(BASE_METRICS), - TSDBTarget( - path=self.tsdb_path, - rate="10/m", - time_col=TIMESTAMP, - container=self.tsdb_container, - access_key=self.v3io_access_key, - v3io_frames=self.v3io_framesd, - index_cols=[ENDPOINT_ID, RECORD_TYPE], - # Settings for _Batching - max_events=self.tsdb_batching_max_events, - timeout_secs=self.tsdb_batching_timeout_secs, - key=ENDPOINT_ID, - ), - ], - [ - FilterKeys(ENDPOINT_FEATURES), - UnpackValues(ENDPOINT_FEATURES), - TSDBTarget( - path=self.tsdb_path, - rate="10/m", - time_col=TIMESTAMP, - container=self.tsdb_container, - access_key=self.v3io_access_key, - v3io_frames=self.v3io_framesd, - index_cols=[ENDPOINT_ID, RECORD_TYPE], - # Settings for _Batching - max_events=self.tsdb_batching_max_events, - timeout_secs=self.tsdb_batching_timeout_secs, - key=ENDPOINT_ID, - ), - ], - [ - FilterKeys(CUSTOM_METRICS), - FilterNotNone(), - UnpackValues(CUSTOM_METRICS), - TSDBTarget( - path=self.tsdb_path, - rate="10/m", - time_col=TIMESTAMP, - container=self.tsdb_container, - access_key=self.v3io_access_key, - v3io_frames=self.v3io_framesd, - index_cols=[ENDPOINT_ID, RECORD_TYPE], - # Settings for _Batching - max_events=self.tsdb_batching_max_events, - timeout_secs=self.tsdb_batching_timeout_secs, - key=ENDPOINT_ID, - ), - ], - ], - ], - # Branch 2: Batch events, write to parquet - [ - Map(self.process_before_parquet), - ParquetTarget( - path=self.parquet_path, - partition_cols=["$key", "$year", "$month", "$day", "$hour"], - infer_columns_from_data=True, - # Settings for _Batching - max_events=self.parquet_batching_max_events, - timeout_secs=self.parquet_batching_timeout_secs, - # Settings for v3io storage - storage_options={ - "v3io_api": self.v3io_api, - "v3io_access_key": self.model_monitoring_access_key, - }, - ), - ], - ] - ).run() - - def consume(self, event: Dict): - events = [] - if "headers" in event and "values" in event: - for values in event["values"]: - events.append({k: v for k, v in zip(event["headers"], values)}) - else: - events.append(event) - - for enriched in map(enrich_even_details, events): - if enriched is not None: - self._flow.emit( - enriched, - key=enriched[ENDPOINT_ID], - event_time=datetime.strptime(enriched["when"], ISO_8061_UTC), - ) - else: - pass - - @staticmethod - def compute_predictions_per_second(event: dict): - event[PREDICTIONS_PER_SECOND] = float(event[PREDICTIONS_COUNT_5M]) / 600 - return event - - def process_before_kv(self, event: dict): - # Filter relevant keys - e = {k: event[k] for k in self._kv_keys} - # Unpack labels dictionary - e = {**e, **e.pop(UNPACKED_LABELS, {})} - # Write labels to kv as json string to be presentable later - e[LABELS] = json.dumps(e[LABELS]) - return e - - @staticmethod - def process_before_events_tsdb(event: Dict): - base_fields = [TIMESTAMP, ENDPOINT_ID] - - base_event = {k: event[k] for k in base_fields} - base_event[TIMESTAMP] = pd.to_datetime( - base_event[TIMESTAMP], format=TIME_FORMAT - ) - - base_metrics = { - RECORD_TYPE: BASE_METRICS, - PREDICTIONS_PER_SECOND: event[PREDICTIONS_PER_SECOND], - PREDICTIONS_COUNT_5M: event[PREDICTIONS_COUNT_5M], - PREDICTIONS_COUNT_1H: event[PREDICTIONS_COUNT_1H], - LATENCY_AVG_5M: event[LATENCY_AVG_5M], - LATENCY_AVG_1H: event[LATENCY_AVG_1H], - **base_event, - } - - endpoint_features = { - RECORD_TYPE: ENDPOINT_FEATURES, - **event[NAMED_PREDICTIONS], - **event[NAMED_FEATURES], - **base_event, - } - - processed = {BASE_METRICS: base_metrics, ENDPOINT_FEATURES: endpoint_features} - - if event[METRICS]: - processed[CUSTOM_METRICS] = { - RECORD_TYPE: CUSTOM_METRICS, - **event[METRICS], - **base_event, - } - - return processed - - @staticmethod - def process_before_parquet(event: dict): - def set_none_if_empty(_event: dict, keys: List[str]): - for key in keys: - if not _event.get(key): - _event[key] = None - - def drop_if_exists(_event: dict, keys: List[str]): - for key in keys: - _event.pop(key, None) - - def unpack_if_exists(_event: dict, keys: List[str]): - for key in keys: - value = _event.get(key) - if value is not None: - _event = {**value, **event} - - drop_if_exists(event, [UNPACKED_LABELS, FEATURES]) - unpack_if_exists(event, [ENTITIES]) - set_none_if_empty(event, [LABELS, METRICS, ENTITIES]) - return event - - -class ProcessEndpointEvent(MapClass): - def __init__(self, kv_container: str, kv_path: str, v3io_access_key: str, **kwargs): - super().__init__(**kwargs) - self.kv_container: str = kv_container - self.kv_path: str = kv_path - self.v3io_access_key: str = v3io_access_key - self.first_request: Dict[str, str] = dict() - self.last_request: Dict[str, str] = dict() - self.error_count: Dict[str, int] = defaultdict(int) - self.endpoints: Set[str] = set() - - def do(self, event: dict): - function_uri = event[FUNCTION_URI] - versioned_model = event[VERSIONED_MODEL] - endpoint_id = event[ENDPOINT_ID] - - # In case this process fails, resume state from existing record - self.resume_state(endpoint_id) - - # Handle errors coming from stream - found_errors = self.handle_errors(endpoint_id, event) - if found_errors: - return None - - # Validate event fields - model_class = event.get("model_class") or event.get("class") - timestamp = event.get("when") - request_id = event.get("request", {}).get("id") - latency = event.get("microsec") - features = event.get("request", {}).get("inputs") - predictions = event.get("resp", {}).get("outputs") - - if not self.is_valid(endpoint_id, is_not_none, timestamp, ["when"],): - return None - - if endpoint_id not in self.first_request: - self.first_request[endpoint_id] = timestamp - self.last_request[endpoint_id] = timestamp - - if not self.is_valid(endpoint_id, is_not_none, request_id, ["request", "id"],): - return None - if not self.is_valid(endpoint_id, is_not_none, latency, ["microsec"],): - return None - if not self.is_valid( - endpoint_id, is_not_none, features, ["request", "inputs"], - ): - return None - if not self.is_valid( - endpoint_id, is_not_none, predictions, ["resp", "outputs"], - ): - return None - - unpacked_labels = {f"_{k}": v for k, v in event.get(LABELS, {}).items()} - - # Separate each model invocation into sub events - events = [] - for i, (feature, prediction) in enumerate(zip(features, predictions)): - if not self.is_valid( - endpoint_id, - is_list_of_numerics, - feature, - ["request", "inputs", f"[{i}]"], - ): - return None - - if not isinstance(prediction, list): - prediction = [prediction] - - events.append( - { - FUNCTION_URI: function_uri, - MODEL: versioned_model, - MODEL_CLASS: model_class, - TIMESTAMP: timestamp, - ENDPOINT_ID: endpoint_id, - REQUEST_ID: request_id, - LATENCY: latency, - FEATURES: feature, - PREDICTION: prediction, - FIRST_REQUEST: self.first_request[endpoint_id], - LAST_REQUEST: self.last_request[endpoint_id], - ERROR_COUNT: self.error_count[endpoint_id], - LABELS: event.get(LABELS, {}), - METRICS: event.get(METRICS, {}), - ENTITIES: event.get("request", {}).get(ENTITIES, {}), - UNPACKED_LABELS: unpacked_labels, - } - ) - return events - - def resume_state(self, endpoint_id): - # Make sure process is resumable, if process fails for any reason, be able to pick things up close to where we - # left them - if endpoint_id not in self.endpoints: - logger.info("Trying to resume state", endpoint_id=endpoint_id) - endpoint_record = get_endpoint_record( - kv_container=self.kv_container, - kv_path=self.kv_path, - endpoint_id=endpoint_id, - access_key=self.v3io_access_key, - ) - if endpoint_record: - first_request = endpoint_record.get(FIRST_REQUEST) - if first_request: - self.first_request[endpoint_id] = first_request - error_count = endpoint_record.get(ERROR_COUNT) - if error_count: - self.error_count[endpoint_id] = error_count - self.endpoints.add(endpoint_id) - - def is_valid( - self, endpoint_id: str, validation_function, field: Any, dict_path: List[str] - ): - if validation_function(field, dict_path): - return True - self.error_count[endpoint_id] += 1 - return False - - def handle_errors(self, endpoint_id, event) -> bool: - if "error" in event: - self.error_count[endpoint_id] += 1 - return True - - return False - - -def enrich_even_details(event) -> Optional[dict]: - function_uri = event.get(FUNCTION_URI) - - if not is_not_none(function_uri, [FUNCTION_URI]): - return None - - model = event.get(MODEL) - if not is_not_none(model, [MODEL]): - return None - - version = event.get(VERSION) - versioned_model = f"{model}:{version}" if version else f"{model}:latest" - - endpoint_id = create_model_endpoint_id( - function_uri=function_uri, versioned_model=versioned_model, - ) - - endpoint_id = str(endpoint_id) - - event[VERSIONED_MODEL] = versioned_model - event[ENDPOINT_ID] = endpoint_id - - return event - - -def is_not_none(field: Any, dict_path: List[str]): - if field is not None: - return True - logger.error( - f"Expected event field is missing: {field} [Event -> {''.join(dict_path)}]" - ) - return False - - -def is_list_of_numerics( - field: List[Union[int, float, dict, list]], dict_path: List[str] -): - if all(isinstance(x, int) or isinstance(x, float) for x in field): - return True - logger.error( - f"Expected event field is missing: {field} [Event -> {''.join(dict_path)}]" - ) - return False - - -class FilterNotNone(Filter): - def __init__(self, **kwargs): - super().__init__(fn=lambda event: event is not None, **kwargs) - - -class FilterKeys(MapClass): - def __init__(self, *args, **kwargs): - super().__init__(**kwargs) - self.keys = list(args) - - def do(self, event): - new_event = {} - for key in self.keys: - if key in event: - new_event[key] = event[key] - - return new_event if new_event else None - - -class UnpackValues(MapClass): - def __init__(self, *args, **kwargs): - super().__init__(**kwargs) - self.keys_to_unpack = set(args) - - def do(self, event): - unpacked = {} - for key in event.keys(): - if key in self.keys_to_unpack: - unpacked = {**unpacked, **event[key]} - else: - unpacked[key] = event[key] - return unpacked - - -class MapFeatureNames(MapClass): - def __init__(self, kv_container: str, kv_path: str, access_key: str, **kwargs): - super().__init__(**kwargs) - self.kv_container = kv_container - self.kv_path = kv_path - self.access_key = access_key - self.feature_names = {} - self.label_columns = {} - - def do(self, event: Dict): - endpoint_id = event[ENDPOINT_ID] - - if endpoint_id not in self.feature_names: - endpoint_record = get_endpoint_record( - kv_container=self.kv_container, - kv_path=self.kv_path, - endpoint_id=endpoint_id, - access_key=self.access_key, - ) - feature_names = endpoint_record.get(FEATURE_NAMES) - feature_names = json.loads(feature_names) if feature_names else None - - label_columns = endpoint_record.get(LABEL_COLUMNS) - label_columns = json.loads(label_columns) if label_columns else None - - if not feature_names: - logger.warn( - f"Feature names are not initialized, they will be automatically generated", - endpoint_id=endpoint_id, - ) - feature_names = [f"f{i}" for i, _ in enumerate(event[FEATURES])] - get_v3io_client().kv.update( - container=self.kv_container, - table_path=self.kv_path, - access_key=self.access_key, - key=event[ENDPOINT_ID], - attributes={FEATURE_NAMES: json.dumps(feature_names)}, - raise_for_status=RaiseForStatus.always, - ) - - if not label_columns: - logger.warn( - f"label column names are not initialized, they will be automatically generated", - endpoint_id=endpoint_id, - ) - label_columns = [f"p{i}" for i, _ in enumerate(event[PREDICTION])] - get_v3io_client().kv.update( - container=self.kv_container, - table_path=self.kv_path, - access_key=self.access_key, - key=event[ENDPOINT_ID], - attributes={LABEL_COLUMNS: json.dumps(label_columns)}, - raise_for_status=RaiseForStatus.always, - ) - - self.label_columns[endpoint_id] = label_columns - self.feature_names[endpoint_id] = feature_names - - logger.info( - "Label columns", endpoint_id=endpoint_id, label_columns=label_columns - ) - logger.info( - "Feature names", endpoint_id=endpoint_id, feature_names=feature_names - ) - - feature_names = self.feature_names[endpoint_id] - features = event[FEATURES] - event[NAMED_FEATURES] = { - name: feature for name, feature in zip(feature_names, features) - } - - label_columns = self.label_columns[endpoint_id] - prediction = event[PREDICTION] - event[NAMED_PREDICTIONS] = { - name: prediction for name, prediction in zip(label_columns, prediction) - } - logger.info("Mapped event", event=event) - return event - - -class WriteToKV(MapClass): - def __init__(self, container: str, table: str, **kwargs): - super().__init__(**kwargs) - self.container = container - self.table = table - - def do(self, event: Dict): - get_v3io_client().kv.update( - container=self.container, - table_path=self.table, - key=event[ENDPOINT_ID], - attributes=event, - ) - return event - - -class InferSchema(MapClass): - def __init__( - self, - v3io_access_key: str, - v3io_framesd: str, - container: str, - table: str, - **kwargs, - ): - super().__init__(**kwargs) - self.container = container - self.v3io_access_key = v3io_access_key - self.v3io_framesd = v3io_framesd - self.table = table - self.keys = set() - - def do(self, event: Dict): - key_set = set(event.keys()) - if not key_set.issubset(self.keys): - self.keys.update(key_set) - get_frames_client( - token=self.v3io_access_key, - container=self.container, - address=self.v3io_framesd, - ).execute(backend="kv", table=self.table, command="infer_schema") - logger.info( - "Found new keys, inferred schema", table=self.table, event=event - ) - return event - - -def get_endpoint_record( - kv_container: str, kv_path: str, endpoint_id: str, access_key: str -) -> Optional[dict]: - logger.info( - f"Grabbing endpoint data", - container=kv_container, - table_path=kv_path, - key=endpoint_id, - ) - try: - endpoint_record = ( - get_v3io_client() - .kv.get( - container=kv_container, - table_path=kv_path, - key=endpoint_id, - access_key=access_key, - raise_for_status=v3io.dataplane.RaiseForStatus.always, - ) - .output.item - ) - return endpoint_record - except Exception: - return None - - -def init_context(context: MLClientCtx): - context.logger.info("Initializing EventStreamProcessor") - parameters = environ.get("MODEL_MONITORING_PARAMETERS") - parameters = json.loads(parameters) if parameters else {} - stream_processor = EventStreamProcessor(**parameters) - setattr(context, "stream_processor", stream_processor) - - -def handler(context: MLClientCtx, event: Event): - event_body = json.loads(event.body) - context.logger.debug(event_body) - context.stream_processor.consume(event_body) diff --git a/model_monitoring_stream/requirements.txt b/model_monitoring_stream/requirements.txt deleted file mode 100644 index ef238930e..000000000 --- a/model_monitoring_stream/requirements.txt +++ /dev/null @@ -1,3 +0,0 @@ -storey -nuclio -v3io \ No newline at end of file diff --git a/noise_reduction/data/test_data.mp3 b/noise_reduction/data/test_data.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..a330f9804f67205e2af72652151f4721ec16ff74 GIT binary patch literal 27972 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%0A^>F%daWyb@oIFn=mD;f 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 literal 0 HcmV?d00001 diff --git a/noise_reduction/data/test_data.wav b/noise_reduction/data/test_data.wav new file mode 100644 index 0000000000000000000000000000000000000000..a3a993c20c707b19bc4a38596e555ccb544390ea GIT binary patch literal 179672 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.1.2 + entry_points: + reduce_noise: + name: reduce_noise + doc: 'Reduce noise from audio file or directory containing audio files. + + The audio files must be in .wav format. + + The cleaned audio files will be saved in the target_directory. + + For information about the noise reduction algorithm see: + + https://github.com/timsainb/noisereduce + + Notice that the saved files are in wav format, even if the original files + are in other format.' + parameters: + - name: audio_source + type: str + doc: path to audio file or directory containing audio files + - name: target_directory + type: str + doc: path to directory to save the cleaned audio files. + - name: sample_rate + type: int + doc: Number of samples in one second in the audio file. Pass `None` to keep + the original sample rate. + default: 16000 + - name: duration + type: int + doc: Duration of the audio file to clean in seconds. Pass `None` to keep the + original duration. + default: null + - name: channel + type: int + doc: Channel to clean. Pass the number of the channel to clean. To clean all + channels pass None. + default: null + - name: silence_threshold + type: float + doc: The threshold to remove silence from the audio, in dB. If None, no silence + removal is performed. + default: null + - name: use_multiprocessing + type: int + doc: Number of processes to use for cleaning the audio files. If 0, no multiprocessing + is used. + default: 0 + - name: verbose + type: bool + doc: Verbosity level. If True, display progress bar. + default: true + outputs: [] + lineno: 388 + has_varargs: false + has_kwargs: false + clean_audio: + name: clean_audio + doc: '' + parameters: + - name: self + - name: data + type: Tensor + outputs: + - type: torch.Tensor + lineno: 276 + has_varargs: false + has_kwargs: false + save_audio: + name: save_audio + doc: '' + parameters: + - name: self + - name: audio + type: ndarray + - name: target_path + type: Path + outputs: [] + lineno: 256 + has_varargs: false + has_kwargs: false + load_audio: + name: load_audio + doc: '' + parameters: + - name: self + - name: file + type: str + outputs: + - type: torch.Tensor + lineno: 268 + has_varargs: false + has_kwargs: false + update_to_wav_suffix: + name: update_to_wav_suffix + doc: '' + parameters: + - name: self + - name: audio_file + type: Path + outputs: [] + lineno: 125 + has_varargs: false + has_kwargs: false + remove_silence: + name: remove_silence + doc: Remove silence sections from the audio. + parameters: + - name: self + - name: audio + type: ndarray + doc: The audio to remove silence from. + outputs: + - doc: The audio without silence. + lineno: 134 + has_varargs: false + has_kwargs: false + reduce_noise_dfn: + name: reduce_noise_dfn + doc: 'Reduce noise from audio files using DeepFilterNet. + + For more information about the noise reduction algorithm see: + + https://github.com/Rikorose/DeepFilterNet + + Notice that the saved files are in wav format, even if the original files + are in other format.' + parameters: + - name: audio_source + type: str + doc: path to audio file or directory of audio files + - name: target_directory + type: str + doc: path to target directory to save cleaned audio files + - name: pad + type: bool + doc: whether to pad the audio file with zeros before cleaning + default: true + - name: atten_lim_db + type: int + doc: maximum attenuation in dB + default: null + - name: silence_threshold + type: float + doc: the threshold to remove silence from the audio, in dB. If None, no silence + removal is performed. + default: null + - name: use_multiprocessing + type: int + doc: Number of processes to use for cleaning the audio files. If 0, no multiprocessing + is used. + default: 0 + - name: verbose + type: bool + doc: verbosity level. If True, display progress bar and logs. + default: true + outputs: [] + lineno: 322 + has_varargs: false + has_kwargs: true + description: Reduce noise from audio files + default_handler: reduce_noise + disable_auto_mount: false + clone_target_dir: '' + env: [] + priority_class_name: '' + preemption_mode: prevent + affinity: null + tolerations: null + security_context: {} +verbose: false diff --git a/noise_reduction/item.yaml b/noise_reduction/item.yaml new file mode 100644 index 000000000..8ddc63f4f --- /dev/null +++ b/noise_reduction/item.yaml @@ -0,0 +1,29 @@ +apiVersion: v1 +categories: + - data-preparation + - machine-learning +description: Reduce noise from audio files +doc: '' +example: noise_reduction.ipynb +generationDate: 2024-03-04:17-30 +hidden: false +icon: '' +labels: + author: yonatans +maintainers: [] +mlrunVersion: 1.5.2 +name: noise-reduction +platformVersion: 3.5.3 +spec: + filename: noise_reduction.py + handler: reduce_noise + image: mlrun/mlrun + kind: job + requirements: [ + librosa, + noisereduce, + deepfilternet, + torchaudio>=2.1.2, + ] +url: '' +version: 1.0.0 \ No newline at end of file diff --git a/noise_reduction/noise_reduction.ipynb b/noise_reduction/noise_reduction.ipynb new file mode 100644 index 000000000..e4fa0a534 --- /dev/null +++ b/noise_reduction/noise_reduction.ipynb @@ -0,0 +1,942 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "4e0abc60-b718-4f45-a82a-0b8759f19d3f", + "metadata": {}, + "source": [ + "# Noise Reduction\n", + "\n", + "## Table of Contents\n", + "\n", + "1. [Introduction](#Introduction)\n", + "2. [Project Setup](#Setting-up-a-project)\n", + "3. [Noise Reduction Techniques](#Noise-Reduction-Techniques)\n", + " 1. [DeepFilterNet](#DeepFilterNet)\n", + " 2. [Spectral Gating](#SpectralGating)" + ] + }, + { + "cell_type": "markdown", + "id": "9af33629-965f-4f73-9e4a-89cc4c3dacf1", + "metadata": {}, + "source": [ + "## Introduction\n", + "\n", + "Noise reduction is a crucial signal processing technique used to enhance the quality of signals by minimizing unwanted or irrelevant noise. This technique finds applications in various fields such as audio processing, image processing, telecommunications, and more. The goal is to extract the useful information from a signal while suppressing undesirable background noise." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "f9cd530d-36a7-47b1-96f8-498d338b3a1a", + "metadata": {}, + "outputs": [], + "source": [ + "import mlrun" + ] + }, + { + "cell_type": "markdown", + "id": "c659289f-01f2-4e02-b843-b39cfc0c1d63", + "metadata": {}, + "source": [ + "## Setting up a project\n", + "\n", + "First of all we need to create a project with the `noise-reduction` function" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "c4217272-85b8-4af7-afee-bc97c6c73bd9", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "> 2024-03-04 15:54:53,561 [info] Project loaded successfully: {'project_name': 'noise-reduction'}\n" + ] + } + ], + "source": [ + "# Creating a project\n", + "project = mlrun.get_or_create_project(\"noise-reduction\")\n", + "# Importing the function from hub\n", + "noise_reduction_function = project.set_function(\"hub://noise_reduction\")" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "f7df4c3e-4e5b-47bd-a298-527d9c6fcb8f", + "metadata": {}, + "outputs": [], + "source": [ + "# Audio source can be either a single file or a directory of audio files\n", + "audio_source = \"data\"" + ] + }, + { + "cell_type": "markdown", + "id": "6c1c5109-6380-4364-b016-728523ed0ea1", + "metadata": {}, + "source": [ + "## Noise Reduction Techniques" + ] + }, + { + "attachments": { + "e48ce103-14f3-421d-82a4-823344895241.png": { + "image/png": "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" + } + }, + "cell_type": "markdown", + "id": "5c81ecee-851c-4ee8-ad3a-4d372a1bfd97", + "metadata": {}, + "source": [ + "\n", + "### 1. DeepFilterNet\n", + "![image.png](attachment:e48ce103-14f3-421d-82a4-823344895241.png)\n", + "\n", + "In order to use this technique, you simply need to use the `reduce_noise_dfn` handler.\n", + "\n", + "Reduce noise from audio files using DeepFilterNet. For more information about the noise reduction algorithm, see [DeepFilterNet GitHub](https://github.com/Rikorose/DeepFilterNet). Notice that the saved files are in wav format, even if the original files are in other formats.\n", + "\n", + "### Parameters:\n", + "\n", + "- `audio_source`: path to the audio file or directory of audio files\n", + "- `target_directory`: path to the target directory to save cleaned audio files\n", + "- `pad`: whether to pad the audio file with zeros before cleaning\n", + "- `atten_lim_db`: maximum attenuation in dB\n", + "- `silence_threshold`: the threshold to remove silence from the audio, in dB. If None, no silence removal is performed.\n", + "- `use_multiprocessing`: Number of processes to use for cleaning the audio files. If 0, no multiprocessing is used.\n", + "- `verbose`: verbosity level. If True, display progress bar and logs.\n", + "- `kwargs`: additional arguments to pass to `torchaudio.load()`. For more information, see [torchaudio.load()](https://pytorch.org/audio/stable/generated/torchaudio.load.html).\n", + "\n", + "\n", + "In the examples below, the function is running locally, for running remotely, it is required to build the function's image first (need to execute only once):\n", + "```python\n", + "noise_reduction_function.apply(mlrun.auto_mount()) # required for local files\n", + "project.build_function(\"noise-reduction\")\n", + "```\n", + "\n", + "#### 1.1. Example" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "16113524-8597-48d4-8172-76b897fee3f2", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "> 2024-03-04 15:54:56,999 [info] Storing function: {'name': 'noise-reduce-reduce-noise-dfn', 'uid': '9732dac831784a6a8b53acab5ff83a08', 'db': 'http://mlrun-api:8080'}\n", + "> 2024-03-04 15:55:07,525 [info] logging run results to: http://mlrun-api:8080\n", + "> 2024-03-04 15:55:07,702 [info] Reducing noise from audio files.\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Noise-reduction: 0%| | 0/2 [00:00 2024-03-04 15:55:08,437 [info] Loading DeepFilterNet2 model.\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "`torchaudio.backend.common.AudioMetaData` has been moved to `torchaudio.AudioMetaData`. Please update the import path.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2024-03-04 15:55:08 | INFO | DF | Running on torch 2.1.2+cu121\n", + "2024-03-04 15:55:08 | INFO | DF | Running on host jupyter-yoni-d56767c87-678n2\n", + "> 2024-03-04 15:55:08,464 [info] Loading DeepFilterNet2 model.\n", + "2024-03-04 15:55:08 | INFO | DF | Running on torch 2.1.2+cu121\n", + "2024-03-04 15:55:08 | INFO | DF | Running on host jupyter-yoni-d56767c87-678n2\n", + "2024-03-04 15:55:08 | INFO | DF | Loading model settings of DeepFilterNet3\n", + "2024-03-04 15:55:08 | INFO | DF | Using DeepFilterNet3 model at /igz/.cache/DeepFilterNet/DeepFilterNet3\n", + "2024-03-04 15:55:08 | INFO | DF | Initializing model `deepfilternet3`\n", + "2024-03-04 15:55:08 | INFO | DF | Loading model settings of DeepFilterNet3\n", + "2024-03-04 15:55:08 | INFO | DF | Using DeepFilterNet3 model at /igz/.cache/DeepFilterNet/DeepFilterNet3\n", + "2024-03-04 15:55:08 | INFO | DF | Initializing model `deepfilternet3`\n", + "2024-03-04 15:55:08 | INFO | DF | Found checkpoint /igz/.cache/DeepFilterNet/DeepFilterNet3/checkpoints/model_120.ckpt.best with epoch 120\n", + "2024-03-04 15:55:08 | INFO | DF | Found checkpoint /igz/.cache/DeepFilterNet/DeepFilterNet3/checkpoints/model_120.ckpt.best with epoch 120\n", + "2024-03-04 15:55:08 | INFO | DF | Running on device cpu\n", + "2024-03-04 15:55:08 | INFO | DF | Running on device cpu\n", + "2024-03-04 15:55:08 | INFO | DF | Model loaded\n", + "2024-03-04 15:55:08 | INFO | DF | Model loaded\n", + "> 2024-03-04 15:55:08,635 [info] Reducing noise from test_data.mp3.\n", + "> 2024-03-04 15:55:08,636 [info] Reducing noise from test_data.wav.\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[32m2024-03-04 15:55:08\u001b[0m | \u001b[33m\u001b[1mWARNING \u001b[0m | \u001b[36mDF\u001b[0m | \u001b[33m\u001b[1mAudio sampling rate does not match model sampling rate (16000, 48000). Resampling...\u001b[0m\n", + "\"sinc_interpolation\" resampling method name is being deprecated and replaced by \"sinc_interp_hann\" in the next release. The default behavior remains unchanged.\n", + "The MPEG_LAYER_III subtype is unknown to TorchAudio. As a result, the bits_per_sample attribute will be set to 0. If you are seeing this warning, please report by opening an issue on github (after checking for existing/closed ones). You may otherwise ignore this warning.\n", + "\u001b[32m2024-03-04 15:55:08\u001b[0m | \u001b[33m\u001b[1mWARNING \u001b[0m | \u001b[36mDF\u001b[0m | \u001b[33m\u001b[1mAudio sampling rate does not match model sampling rate (16000, 48000). Resampling...\u001b[0m\n", + "\"sinc_interpolation\" resampling method name is being deprecated and replaced by \"sinc_interp_hann\" in the next release. The default behavior remains unchanged.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "> 2024-03-04 15:55:16,701 [info] Saved cleaned audio file to clean_data/test_data.wav.\n", + "> 2024-03-04 15:55:16,706 [info] Saved cleaned audio file to clean_data/test_data_mp3.wav.\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Noise-reduction: 100%|██████████| 2/2 [00:09<00:00, 4.51s/file]" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "> 2024-03-04 15:55:16,791 [info] Summarizing the results.\n", + "> 2024-03-04 15:55:16,792 [info] Done (2/2)\n", + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\n" + ] + }, + { + "data": { + "text/html": [ + "\n", + "
\n", + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
projectuiditerstartstatenamelabelsinputsparametersresultsartifacts
noise-reduction0Mar 04 15:54:57completednoise-reduce-reduce-noise-dfn
v3io_user=yonis
kind=local
owner=yonis
host=jupyter-yoni-d56767c87-678n2
audio_source
target_directory=./clean_data
use_multiprocessing=2
silence_threshold=50
atten_lim_db=10
successes
errors
\n", + "
\n", + "
\n", + "
\n", + " Title\n", + " ×\n", + "
\n", + " \n", + "
\n", + "
\n" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n" + ] + }, + { + "data": { + "text/html": [ + " > to track results use the .show() or .logs() methods or click here to open in UI" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "> 2024-03-04 15:55:17,976 [info] Run execution finished: {'status': 'completed', 'name': 'noise-reduce-reduce-noise-dfn'}\n" + ] + } + ], + "source": [ + "dfn_run = noise_reduction_function.run(\n", + " handler=\"reduce_noise_dfn\",\n", + " inputs={\"audio_source\": audio_source},\n", + " params={\n", + " \"target_directory\": \"./clean_data\",\n", + " \"use_multiprocessing\": 2,\n", + " \"silence_threshold\": 50,\n", + " \"atten_lim_db\": 10,\n", + " },\n", + " returns=[\"successes: file\", \"errors: file\"],\n", + " local=True,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "a71ba944-1fc2-48be-b789-d57c59201939", + "metadata": {}, + "source": [ + "### Looking at the result" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "19b04cf6-5a4d-4d74-b66e-193540a900a1", + "metadata": {}, + "outputs": [ + { + "data": { + "application/json": { + "test_data.mp3": "clean_data/test_data_mp3.wav", + "test_data.wav": "clean_data/test_data.wav" + }, + "text/plain": [ + "" + ] + }, + "metadata": { + "application/json": { + "expanded": false, + "root": "root" + } + }, + "output_type": "display_data" + }, + { + "data": { + "application/json": {}, + "text/plain": [ + "" + ] + }, + "metadata": { + "application/json": { + "expanded": false, + "root": "root" + } + }, + "output_type": "display_data" + } + ], + "source": [ + "dfn_run.artifact(\"successes\").show()\n", + "dfn_run.artifact(\"errors\").show()" + ] + }, + { + "attachments": { + "68c16acf-c28e-4bb8-a453-abbebc0137ce.png": { + "image/png": "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2rO6epfhrqU1aI20pmf3uN1te4L2NNQ61G7Zq7u3bB/YJ933fH/a/psHIg40HWQerD1keajyMP1waR1SN62urz6rvqMhpaH9SPiRpkafxsNHHY/uOGZ6rOK4zvGlJygn5p8YOFl0sv+U+FTv6czTT5omNt07M+bM9ebY5tazEWcvnAs5d+Y86/zJC74Xjl30vnjkEvNS/WWPy3Ut7i2Hf3f//XCrR2vdFc8rDW1ebY3to9pPXPW/evpa0LVz1znXL9+IutF+M/Hm7VvjbnXc5t/uvpN759Xdwruf7825T7hf+kDjQflDw4dVf9j+sbfDo+P4o6BHLY/jH997wnvy4mn+0y+d85/RnpV3mXRVd7t0H+sJ6Wl7PvZ55wvxi8+9JX9q/ln50ublob8C/mrpG9PX+UryauD14jf6b3a8dXvb1B/T//Bd3rvP70s/6H/Y+ZH58fyn5E9dn6d8IX1Z+9X2a+O3iG/3B/IGBsRcCVf+K4DBimZkAPB6BwC0FADo8HxGGas4/8kLojizyhH4T1hxRpQXDwBq4f97bC/8u7kFwL5t8PgF9dXHARBDAyDBC6CurkN18KwmP1fKChGeAzbHfk3PSwf/pijOnD/E/XMLZKpu4Of2X5JOfJCem+crAAAAOGVYSWZNTQAqAAAACAABh2kABAAAAAEAAAAaAAAAAAACoAIABAAAAAEAAAR6oAMABAAAAAEAAAIoAAAAAIFlXtUAAEAASURBVHgB7J0H3BS11odXBEVRERs2bFixImLFLnbFXrD3ig17ufbee78qdrFivfbesIANO6CgICpFRQTF79k33ny5yezs7O5s/7+/ezGTOTlJnpmdyZmcnEzz999/Z/QnAiIgAiIgAiIgAiIgAiIgAiKQNoFWaSuUPhEQAREQAREQAREQAREQAREQgSwBmVu6D0RABERABERABERABERABESgLARkbpUFq5SKgAiIgAiIgAiIgAiIgAiIgMwt3QMiIAIiIAIiIAIiIAIiIAIiUBYCMrfKglVKRUAEREAEREAEREAEREAEREDmlu4BERABERABERABERABERABESgLAZlbZcEqpSIgAiIgAiIgAiIgAiIgAiIgc0v3gAiIgAiIgAiIgAiIgAiIgAiUhYDMrbJglVIREAEREAEREAEREAEREAERkLmle0AEREAEREAEREAEREAEREAEykJA5lZZsEqpCIiACIiACIiACIiACIiACMjc0j0gAiIgAiIgAiIgAiIgAiIgAmUh0LosWqVUBERABESgsgSGDx/++++/e3V26tSpXbt2XqYOK0Bg6tSpn3/+uVfRNNNMs8QSS3iZOhQBERABEWhsAtP8/fffjd1D9U4EREAEmoHAQgsthMXl9fTLL7/s3Lmzl6nDChAYMmRIly5dvIoWW2yx0AbzZHQoAiIgAiLQYATkTNhgF1TdEQERaEYCY8aMCW2t2WabbZFFFmlGHDXQ54EDB4atWHnllcNM5YiACIiACDQ2AZlbjX191TsREIGmIBA5uO/evTvea03R/9rr5Ntvvx02iisSZipHBERABESgsQnI3Grs66veiYAINAWBXOZWU3S+JjsZaW5pdqsmr5UaJQIiIALlJSBzq7x8pV0EREAEKkBA5lYFICev4o8//hg8eLAn37p16xVWWMHL1KEIiIAIiEDDE5C51fCXWB0UARFocAJEPJK5VVPX+IMPPpg8ebLXpGWWWWaGGWbwMnUoAiIgAiLQ8AQUCL7hL7E6KAIi0OAEMLeeeuopr5Os2ppnnnm8TB1WhkCk9StPwsrAVy0iIAIiUGsEZG7V2hVRe0RABESgMAKtWrXq2rVrYWUkXU4CkQu3FCejnMilWwREQARql4CcCWv32qhlIiACIiAC9UhAs1v1eNXUZhEQAREoEwFtc1wmsFIrAiJQfwReeeWVCRMmuO2eaaaZ1l57bZODzx57W7377rvvvPMO/3799dcLL7zwUksttdlmm2200UZuqbzpKVOmvPbaa3gAshnuDz/8wK5Z008//ZJLLrnEEkuYf5dffvm2bdvm1WMEXn755V9++cUT7tGjR/v27b1Mezhp0iTWF3311Vfsg2z+Ro4cOcccc8w333zzzjvv/PPP36tXL9YaWfmEiT///PP5559/4oknRowY8d13340aNWr22WdHj/lbY4014JlXFbYKTFyxdu3arbPOOibnt99+u+6661566aVPP/10gQUWoJv8rb/++mHIe64XfXzwwQe/+OKL71v+kPlvW5ZZbbXV6KlbS5L0hx9+eMcdd3zyySfffvvtuHHjOnbs2KlTp0022WS77baztLmFZp11Vmp3FbJqi3yiZbiZ6Bk6dKibQ5obINfO1MZrdOrUqV6RjTfeeNppp/UyvcOJEyc+/PDDQOO+5Q8etJxtl/lbbrnl0MAcqVck/pB7+Nlnn+Uettd6rrnmsni51jPOOGO8Bp0VAREQgWYhwONbfyIgAiIgAn/99RejZO/Rv+mmmxoyn332GcN676w93H777Rm/JmH4448/Hn300TPPPLMtG5lg5HruuecyQM+rEwsnUtvYsWMjy9KA0047Df2R9bqZ66233iOPPAKWSD1eJpbVwQcfjMHmavDSCy20EMaYVzA8xIL1CtqrcNddd2HheGcxdz0lBAY8//zzsV09SfcQ++eKK65I2Dv0v/766yuttJKrwU1jG19yySVGG310T5k0N4/XSA6xaUPJ+++/P5Q0Odh4oTwr9DDAchUhn1LHH388e16HZW1Ot27dsGBjlLinsK/233//eIWLLrooHy/cUkqLgAiIQNMSyDRtz9VxERABEXAJYFDZ0adN/Otf/8KeufDCC/PONTEW53u/q9BLMya+/PLLZ5llFqs8b2LxxRf/6KOPPD3e4ccffxzqoaAnZg4ZATN/FcrH5GBExY/mOcuET/zg29V/yCGHMBcX2Twyx48fH85TnXrqqdRy3nnnuXps2hvWM/fIdI09G59g6pIpvlyNMfncAGeeeWbe6SMq2nLLLQlIiKUXVnrkkUeGtUTGMvnmm29CSZPzwAMPhJqpNJc8N+QRRxyRpOVGLV8NsFRzaSOfq/Dvf//bzuOFjXFzuI70mtnIGIU6JQIiIALNQEDmVjNcZfVRBEQgPwFsBnewaNIM8ZMHlLvoootyVcMofJ999gn1583Bjy7e4rr11ltDJbvuumvYEly/ko+8XZ0MmnNZXMzn7Lnnnq5wknSMhRA5NfT4448z1xepGac1t6e33HJLoX1kugwbz1XipQ877LDIqiMz+/Tps+2224anmJfz1DJHFIrRmFyoKX7ccceFRc466yxPszn86aef8LEM5eNzDj300EhtZGJ27rTTTvHFw7M77rhjLoXKFwEREIEmISBzq0kutLopAiKQh0BBo+pwWEkOS54i62CcijtcZJEkmaussgoaIjWTyexTqIRpNE8eH8KYpUqsHAuVuDkYPJ5CDjEMsMRcseTpSIXojJzCuvfee3OtLHr00Udtw3B9zCUW37DIqSejFpLxZcOz0003XZjJAjnbTpNgUVkotvnmm3ti7iHunWGR//znP66MSTNViztfKJwk58477wwVcq0PPPDA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gAg0MwGZW8189dV3ERABERABERABERABERCBMhKQuVVGuFItAiIgAiIgAiIgAiIgAiLQzARkbjXz1VffRUAEREAEREAEREAEREAEykhA5lYZ4Uq1CIiACIiACIiACIiACIhAMxOQudXMV199FwEREAEREAEREAEREAERKCMBmVtlhCvVIiACIiACIiACIiACIiACzUxA5lYzX331XQREQAREQAREQAREQAREoIwEZG6VEa5Ui4AIiIAIiIAIiIAIiIAINDMBmVvNfPXVdxEQAREQAREQAREQAREQgTISkLlVRrhSLQIiIAIiIAIiIAIiIAIi0MwEWjdz59V3ERABERCB8hH4+++/R40a9dVXXw0bNuznn38eN27c2LFj+dcmxo8fj8y0LX+tWrUyCfPvTDPN1LFjx7nmmot/3QTpGWecsXxtlmYREAEREAERSJeAzK10eUqbCIiACDQpgZ9++um999774osvsK/M39dffz1x4sTUccw333xLO39dunSZZZZZUq9FCkVABERABEQgFQLT8GUxFUVSIgIiIAIi0FQEfvvtN+yrt99+e+DAgfw7dOjQanW/U6dO2F/LLrtsjx491lxzzQ4dOlSrJapXBERABERABDwCMrc8IDoUAREQARHISWDSpEnPP//8Y4899sorr3zyySdTp07NKVqlE9NMM03Xrl3XWWedddddF9Orffv2VWqIqhUBERABERCBLAGZW7oPREAEREAE8hBgzdXjjz/+yCOPPPXUU7/++mse6Zo5zXowTC/sLv7WW2+9tm3b1kzT1BAREAEREIFmISBzq1mutPopAiIgAoUSGD58OCbWww8//PLLL//111+FFq8p+ZlnnrlXr1477LDDhhtuOP3009dU29QYERABERCBBiYgc6uBL666JgIiIAIFE2BB76BBg4yVNXjw4ILL13wB4mpstdVW2F09e/acbrrpar69aqAIiIAIiEB9E5C5Vd/XT60XAREQgVQIsAqLKawHHnhgwIAB33zzTSo6a1zJrLPOau2u1q0Vp7fGL5eaJwIiIAL1SkDmVr1eObVbBERABFIhQIDBfv36XX755Z999lkqCutOyfzzz3/QQQftt99+c845Z901Xg0WAREQARGocQIyt2r8Aql5IiACIlAuAiNGjLjqqqtuuOEGImGUq4760Ytj4U477dSnT5+VVlqpflqtloqACIiACNQ6AZlbtX6F1D4REAERSJ0A22Rddtll/fv3//PPP1NXXu8KV1llFYyu7bbbThE16v1Sqv0iIAIiUAsEZG7VwlVQG0RABESgEgQwrh566CEMrddff70S9dVzHR07dtx///1xMpxnnnnquR9quwiIgAiIQJUJyNyq8gVQ9SIgAiJQAQLjxo276aabrrzyyuqGwcBhr0OHDsSoMP+SIIcQ8wTq4F/7N3ny5DFjxvzwww+jR4+eMmVKBfjkqoKtug4++ODjjjturrnmyiWjfBEQAREQARGIISBzKwaOTomACIhA3RMYOXLkBRdccPPNNxMSo2KdwY7q/L9/iyyyCIEoZphhhoLaQFR6DEWMLmN6YSt+/N+/SnanXbt2hx9+eN++fWebbbaC2i9hERABERABEZC5pXtABERABBqTwK+//nphy9/vv/9e7h7iete95W/llVfu1q1buUP8MRvmml4DBw4cMmRIufvIhl1YXEcccQSJctcl/SIgAiIgAg1DQOZWw1xKdUQEREAE/iGAVx6x3U866aTvv/++fFAWWmihLbfccu2118bOIpb6NNNMU7668mpmBuyll156seWvrKYXE1zHHnvsoYceypRX3lbFC/zU8rf44ovHi+msCIiACIhAXROQuVXXl0+NFwEREAGfwAsvvHDUUUcNGjTIP5HS8YorrsjuwL169Vp22WWra2Ll6tCoUaOM6fXUU08NGzYsl1gp+SzlOvHEEwmkwdqz4vRMmjRpgw02WHrppa+//vriNKiUCIiACIhAXRCQuVUXl0mNFAEREIH8BD7//PNjjjlmwIAB+UULlGjduvU666yDlcV0VqdOnQosXTVxln69++6797X8DR8+PPV2LLXUUtdccw1kCtWMMyR7fBGInymy7777Tt6JhQKUvAiIgAjUEQGZW3V0sdRUERABEYgm8PPPP59xxhlXX311uvtozTzzzJtuuikTWZtssgnRL6Lrrodc7C7Wdxm769tvv023ybvssstFF10099xzJ1d79NFHX3zxxUaeq0bww+RlJSkCIiACIlBfBGRu1df1UmtFQARE4H8IEDOdCRZsrbFjx/7PiRIO2N63d+/eO+64I/M2DbbVL9NKbPF811133XbbbRMmTCgB0v8UZXrq7LPPxrdw2mmn/Z8TUQeE4z/ssMPsGXwyBw8eXJtumbaRSoiACIiACBRNQOZW0ehUUAREQASqTIBlWgcccMAXX3yRVjsIMHjIIYegs+G3mSJs4x133HHVVVcRWD4tel27dr322mtXWWWVGIUPP/zwNttsw2ybK/Pqq6+uscYabo7SIiACIiACDUNA5lbDXEp1RAREoIkITJw48YQTTrjiiivS6vMKK6xw5JFHMqPVYNNZ8Xwwe4hlyHTTI488wsRXvHCSs0xS7bfffueee27kDl1vvvnmuuuuS5AMT9Wuu+56++23e5k6FAEREAERaAwCMrca4zqqFyIgAk1E4I033thjjz1SmdTCPCD6BXtJEc+9mf3Z2MWLiakbb7yR2Oyl30lzzDEHS7N22203F+lXX3216qqr/vjjj6F+whuyGzWlwlPKEQEREAERqHcCreq9A2q/CIiACDQPgT/++INJrR49epRuaxETr0+fPgQzxL2NNVquYdA8PG1PF1hgAaakRowYwUxXQUEvrAY3gU2FPbz99ttb440cwo1E2loUZAHerbfe6mpQWgREQAREoGEIaHarYS6lOiICItDgBN5///3dd9/9o48+KrGfRHJnOmvvvfeu62CDJUKIKY6jJjNd5513Xi7rKKasd2reeeclJgfrstZff33mJL2z7mHnzp0xfVu10jdQl4rSIiACItAIBGRuNcJVVB9EQAQam8CUKVMY/RN+sMQ47wR2P/nkkwmL17Zt28YmVnrvfvnlF2a6LrzwwnHjxpWobdFFF/3yyy/zKnn66ad79uyZV0wCIiACIiAC9UVA5lZ9XS+1VgREoOkIfPLJJ3imvfPOO6X0nGmT/fff//TTT2/4kIOlUArLYmtdcskll156KZEMw7Pp5my99dYPPvhgujqlTQREQAREoOoEZG5V/RKoASIgAiIQTYC4eZdffvnxxx/Pkq1oiWS5G2+8MfvwLr300snEJeUTwKvw/PPP51owzeifS++YPbuGDx8+33zzpadSmkRABERABKpPQG7i1b8GaoEIiIAIhASYTiEsO8HZS7G1unTp8mTLn2ytkHDyHGIG4lX44YcfsgQrealCJf/666+bbrqp0FKSFwEREAERqHECmt2q8Quk5omACDQjAaIm4FqGG2HRnZ9zzjlZ67Xvvvu2bt26aCUq6BFgvvG+++7DBv7++++9U6kcMrU1bNgwXbJUYEqJCIiACNQIAc1u1ciFUDNEQARE4B8Cjz76aPfu3Yu2tdjE6bjjjiNS/IEHHqiBe7p3FeHymXL89NNPCe1YjiiC7L712GOPpdtmaRMBERABEaguAZlb1eWv2kVABETg/wlMnTr11FNPZd/hCRMm/H9uISk20v3ggw8IY9i+fftCykm2AAKzzDILwTPefffd1VZbrYBiyUSvu+66ZIKSEgEREAERqA8Cciasj+ukVoqACDQ8gbFjx+66665PPPFEcT1t06YN3oNHH320ZrSKA1hEKcxjtic+9thj7XbGRSgJixA1nm24wnzliIAIiIAI1CMBzW7V41VTm0VABBqNAGEYcCAs2tZafvnliRRPDEPZWpW8M/AnZLfoIUOG9OrVK8V6b7jhhhS1SZUIiIAIiEB1CWh2q7r8VbsIiIAIZO69915G7RMnTiyCBdHDTzjhhFNOOYUlW0UUV5FUCBBC48YbbzzkkENK3IfaNIZAiCNGjJh++ulTaZuUiIAIiIAIVJeAZreqy1+1i4AINDUBhunnnnvuTjvtVJytteSSS77++utnnnmmbK3q3kaE0CBwfyq2Fh1hm68HHniguj1S7SIgAiIgAmkRkLmVFknpEQEREIHCCLDPUp8+fU488cTCirVIM74/6qij3nvvvZVXXrmI4iqSLoH+/fv37ds3RZ3XXnttitqkSgREQAREoIoE5ExYRfiqWgREoHkJTJo0icAYxU1iLLDAAv369Vt77bWbF18t9fy1115j++NSdqOO7A3L+ZZZZpnIU8oUAREQARGoIwKa3aqji6WmioAINAiBcePGbbTRRsXZWhtssAEhyGVr1cit8NlnnxG4P3Vbi94pInyNXGI1QwREQARKJKDZrRIBqrgIiIAIFEaAKAibbLLJRx99VFixFmn2Lz777LMJj1FEWRVJncDo0aPZemvo0KGpa0bhzDPP/N13380000zlUC6dIiACIiACFSOg2a2KoVZFIiACIpD55JNPGKAXYWsx7L7//vvZv1i2Vo3cRr/99tsWW2xRJluLPv7yyy933313jXRWzRABERABESiagMytotGpoAiIgAgURoBFPj169GB2q7Bimcziiy/+1ltvbbvttoUWlHyZCBDmpHfv3gMHDiyTfqOWgBnErixrFVIuAiIgAiJQbgIyt8pNWPpFQAREIEuAiO2s1xo7dmyhONhC9+233+7SpUuhBSVfJgKYQIcddtiAAQPKpN+qff/998tt0dm6lBABERABESgTAZlbZQIrtSIgAiLw/wTeeecd1mvhfvb/WQlSRHs/66yzHnzwwfbt2ycQl0iFCDDT+NBDD1WmMgXMqAxn1SICIiAC5SOgUBnlYyvNIiACIpAl8MEHH6yzzjqFzmu1a9fuvvvu23TTTQWxBgkwwfXpp58+1/L3wgsvjB8/vkyNnGGGGUaOHNmhQ4cy6ZdaERABERCBchOQuVVuwtIvAiLQ1ASGDBlC0PYxY8YURGGuueZ64oknunXrVlApCVeFAOu42G/amF6vvvoqO6ql24zLLrvs8MMPT1entImACIiACFSMgMytiqFWRSIgAk1H4Msvv1xrrbW+//77gnq+6KKLPvXUU507dy6olIRrgQC21htvvGFML5ZdYYmV3qoll1ySgJZ4lpauShpEQAREQAQqT0DmVuWZq0YREIGmIDB8+HBsrW+++aag3nbv3v2xxx5jdqugUhKuQQITJkx46aWXjOlVROh/t0f4K+KP6uYoLQIiIAIiUC8EZG7Vy5VSO0VABOqJAOttsLW+/vrrghq98cYb9+/fXzvbFgStLoTZEPn55583ptewYcMKbfMOO+xw7733FlpK8iIgAiIgArVAQOZWLVwFtUEERKChCDC2Zr3WZ599VlCv9thjjxtvvLFNmzYFlZJw3RHACDd2FwZYwkV9rVu3Zru2jh071l1n1WAREAEREAGZW7oHREAERCBNAj/99NO666774YcfFqT0hBNOOPvss7U+pyBo9S48depUnAyN6YXb4a+//hrTI26PE088MUZAp0RABERABGqTgMyt2rwuapUIiEBdEhg3btz6669PnLqCWn/yySefeeaZBRWRcIMRmDJlCqE1jOlFsI3Jkyd7HVxwwQW/+uqraaed1svXoQiIgAiIQI0TkLlV4xdIzRMBEagbAsxO9OzZ88033yyoxX379r3wwgs1r1UQtMYWnjhxIgHljemF6c4eX6a/xFDZbLPNGrvv6p0IiIAINB4BmVuNd03VIxEQgSoQwDFsm222eeSRRwqq+5BDDrnyyitlaxUEramEf/755xdffNGYXostttijjz7aVN1XZ0VABESgAQjI3GqAi6guiIAIVJ8Ai6/OO++8gtqxzz773HDDDa1atSqolISblgAbuM0zzzxN2311XAREQATqlIDMrTq9cGq2CIhADRG4/fbbd99994Ia1Lt37379+mkpTkHQJCwCIiACIiACdUdA5lbdXTI1WAREoLYIvP7664QiDGMbxLRy2223veeee4juHSOjUyIgAiIgAiIgAg1AQOZWA1xEdUEERKBqBAhFuMQSS/zwww/JW7D55ps/8MAD0003XfIikhQBERABERABEahTAlozUKcXTs0WARGoCQIEuijI1iJ0Yf/+/WVr1cTFUyNEQAREQAREoPwENLtVfsaqQQREoEEJ4EBI6AJixyXs31prrfXkk0/OOOOMCeUlJgIiIAIiIAIiUO8ENLtV71dQ7RcBEagagZ9++im5rbXqqquyb5JsrapdLVUsAiIgAiIgAtUgIHOrGtRVpwiIQEMQYOFWwn4svvjiTzzxxMwzz5xQXmIiIAIiIAIiIAKNQUDmVmNcR/VCBESgCgQ6duyYJLrgrLPOyu60HTp0qEITVaUIiIAIiIAIiEBVCcjcqip+VS4CIlDPBGabbbaNNtoovgfsrEVsDGa34sV0VgREQAREQAREoCEJyNxqyMuqTomACFSIwOGHH96qVdyD9Iorrthggw0q1BpVIwIiIAIiIAIiUGME4kYJNdZUNUcEREAEao4Agd2JBR/ZrGmmmebSSy89+OCDI88qUwREQAREQAREoBkIyNxqhqusPoqACJSRAAbVvffeu/TSS7t1LLroovgQHnHEEW6m0iIgAiIgAiIgAs1GQPtuNdsVV39FQATKQmDq1KmvvPLK999/P2HChG7duq244orMbpWlJikVAREQAREQARGoHwLpm1sDBw5kUXj79u3rB4JaKgIiIAIiIAJlJ8C+2G+99VaPHj1kipedtSoQAREQgZohkLIz4Y8//rjyyiuvsMIKNdNBNUQEREAEREAEaoLAYYcdttZaa1188cXXXHPN6NGja6JNaoQIiIAIiECZCbROV//ff/+Nwl9//TVdtdImAiIgAiIgAvVO4Pfff6cLl1xyCU6n48ePP+GEE+q9R2q/CIiACIhAXgIpz27lrU8CIiACIiACItCcBMwXyebsu3otAiIgAk1LoCzmlt4oTXs/qeMiIAIiIALxBMzCrU8//TReTGdFQAREQAQag0BZzK3GQKNeiIAIiIAIiECZCPTr169MmqVWBERABESgpgiUxdzi0x1b0Jx55pnpdvW5554bNGhQujqlTQREQAREQASqQuDPP/+sSr2qVAREQAREoJIEymJu0YFPPvnkX//6V7o92WCDDbp27ZquTmkTAREQAREQgUoSsFHg27Rpw15tlaxadYmACIiACFSeQMrmlnmL2LVb8k2v/BVVjeUgwGztpptuWg7N0ikCItA8BMzL0b4i6fh7773XPN1XT0VABESgOQmkbG65bxGAvv/++82JVb1uMALM1j755JPffvttg/VL3REBEag8ATu7VfmqVaMIiIAIiEDlCaRsbpkO2HdJ7969t9pqq1R69fnnn6eiR0pEoGgCgwcPLrqsCoqACIiACIiACIiACDQhgbKYW+4c1+OPP85q4HHjxpUId9llly1Rg4qLQIkEtthii/vuu69EJVUszv7j+Pf+8ccfVWyDqhYBEXAJDB8+nLBS77zzjpuptAiIgAiIQCMRSNncsvNaLqP11ltv3nnnHTVqlJuptAiUSGDXXXfde++9S1SSt/jhhx/evn17K7bLLrvYdN0ljjnmmKWWWqpnz55113I1WAQalcCll15KWKnu3buX2EG+cvIxaPLkySXqUXEREAEREIHUCaRsboXtY2qLyEu///77lClTwrNF5CiOUxHQGrLInXfeecstt5S1a999990VV1wxYcIEW0tdB242jdcvyF5NJUSgkgT++uuvp59+mhojv0uW2JK77757xx13PPTQQ0vUo+IiIAIiIAKpE0jZ3HLdCFNp6/HHH9+6dWscLexHux9//DEVzVIiAnkJzDfffKHM2LFjw8z6ypl99tnrq8FqrQg0AAHeYj/88EOZOmI+aE6aNKlM+qW27giMHj06rc/cddd3NVgEao1AyuZWzEe74iwxvsTzRfDCCy+04IrTY4sr0RgEpk6dWq2O3HzzzdWqOq16f/7557RUSY8IiEChBEaMGFFokbzyuJDklZFA8xBgpe7cc8+9zjrrVKDLX3zxxR577FHXC5srQElVNDmBlM2t//znP+UAqp9xOajWtc7ddtutWu2v3++FMV9DqgVT9YpA8xB48cUXy9fZgw46qHzKpbnuCGBu0Wa2MKlAy/v379+vXz98Wav4GbQC3VQVIlAKgTTNLVaGEL2glNaorAgkJEDEy4SSqYudddZZqeusjELNDFeGs2oRgUgC5dgqHYexr7/+2lb34IMP2rQSzUxgmWWWofuVeebbWhZccMFmZq6+i0AMgTTNra5du8bUZH+QMTJJ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2Ai9S0ImyhEBERABERABCOgVqdtABERABJqEQH2EymiSi6FuioAIiIAIiIAIiIAIiIAINBIBmVuNdDXVFxEQAREQAREQAREQAREQgRoiIHOrhi6GmiICIiACIiACIiACIiACItBIBGRuNdLVVF9EQAREQAREQAREQAREQARqiEBqgeDDPj366KMTJ04M85UjAiIgAiIgAk1O4O6779bOKE1+D6j7IiACTUKgjJEJm4SguikCIiACIiACIiACIiACIiACkQTkTBiJRZkiIAIiIAIiIAIiIAIiIAIiUCoBmVulElR5ERABERABERABERABERABEYgkIHMrEosyRUAEREAEREAEREAEREAERKBUAjK3SiWo8iIgAiIgAiIgAiIgAiIgAiIQSUDmViQWZYqACIiACIiACIiACIiACIhAqQRkbpVKUOVFQAREQAREQAREQAREQAREIJKAzK1ILMoUAREQAREQAREQAREQAREQgVIJyNwqlaDKi4AIiIAIiIAIiIAIiIAIiEAkAZlbkViUKQIiIAIiIAIiIAIiIAIiIAKlEpC5VSpBlRcBERABERABERABERABERCBSAIytyKxKFMEREAEREAEREAEREAEREAESiUgc6tUgiovAiIgAiIgAiIgAiIgAiIgApEEWkfm5sp8Yrs1p5vun5M//pgZ9Xtm5pajFzKZvRbM/D4xezBkTKZtJmP0Tmg5O/90mVGTs6mpmcwcmYzRQM4CM2VaTZvNHzc+M12bzIgpGSM/byYzfSazSKfsqcHfZjq1y0w/febLn7OHs7fK/DE107FDNv3t2Gwtxl78K5OZsVWmw6yZ33/Pnhr9e6bjDJk2LU2db95M27aZv/7KTJqUPfXp55m/M5kuS2bTUyZn6MW0LW2gIA2baabMlCnZU/PPn+nQIfMXLc5kHn0xM1fbzNSW9IjJmU84m8ksmD2Tocc0daY22fSfUzKt22RemJL5IXuUGZ/JHNE+8+uv2fTff2d+mpr5OpvMUNvcmSw3CvJHUept1dKN3yZlaP4HLfkbzpRZaKFsd4yGEaMzY6i3palzd8y8+V3ms0ym73JZURr26WeZeVCK8haBWWbJpn/4ITNyVObDTKZFKtN2uszPk7MN5m/GTGaWaTPtW8QgA97RYzK3tpxaLJPZuF2mY8fswYgR2QsHZLrP36eTspdvzhmyaSoa+Wu2j/wt1S7z7W+ZdzKZaVoOudQ/ZjLdW9Ld22WmmSbzza/Za80fPR3zc2ZkyykoLZLJfNeSXrNDVuzPPzMz0jKu8uzZxv/4Uzb92dTMZotlJrTcGaNHZ++Q+dtnL5z5m3feLFv+Xv06s/FyWWLjWySB9sPoTNeu2VNcU66ywfjFFxngzDFHZsiQ7Kkllsz8/FNmwZZrSdUjR2a+/Tab/9tv2ZtnzjkyXw/NHo6bmr1qi3Nf0sdWmQ9HZLrM/U8pejT8m8wnw7OnOrbLdpAm8QdStPXsmWkzU/YufO+NyZMnZ+9D/ugpzAcOzqY7tMvM2iHzy4TMnHNmD8lH7OsWKHRrjnaZGWbIzA70TGbMD1l0T2WTmR3aZeXbt8+mKcJNMnRYZiq/gUz2/lmmc2YMF4COt8ve85Tq0HKhuWR0vHXLL/PjIZkFO2XGjs2KUUWbNpnx47O95g8N/I1u+XccLc9ktmpJz8bvhTuhQ7aF/P30W4az5tfHv4t1yAwfm1mwQ/YUVfwxOTPrrNl0m9ZZzZNbflMztM3+QKafLnuWv4m/ZeaeO3tpzN93YzKrrJhN8rsbMTLb37d/zh7CAXF+JvzRj1UXyhI2v+WH3sv+DM0ttFi7bL65T14bnZVftqXXlPpgQvbm3KZFAz/H9q0y88+XPRj2babrclmM5iqPH5dZfPHM/XSYp9k62Rvm1Xf+uVf5vdOMTi0XYrbZssBNs0G3+BKZv6f+c9tw9af+nRkHF4Tnz+LlUn6cPcos0fKjaElmFm2T+WVK9ofJ30KZ7C3druUnySFXgNun5UpmRoDivz89AHZeJHuBPmjp7eKzZX+AE1t+zBN/zz5b5m37D3AygYBO/uCHNrrMHwyX75i92f6YlD38eWz2hjGPnc8nZEa1PJnJn6tFkmcLYPn7IpO54ZVXWpL6JxGBLddcswXwP7+jRGVKFuKhzfPV/BB4kHzUct3RanJma9HPj5QnN/8zP+3xPK9abj9OLtMqM/NM2Tvqn1fk79l3zfItpf5ouYvMr4/HO7WgoXXLz54fEb8F8/efwdlHgek4N0/LQ/SfU95/eAQaMS+/iMOlWu5SfgTc5/x93nLrtvxGsz8rfvL89eGnxYNrSubzydn+8kcv+C1M15KmnZQyQMiY9r8/vZaTtfXPipnssIo/fqH88ewfyQu6Jf1pJrNyJtPyLM/+YN2/zjwG//tsuSuTuXz5zGKL/fOc5zHO+7Rbt6x4q3Ztf/txknlwffll9k7g/fL++9lTyPOsm48nIA2YPvuy+2h4Nk11YKcZw7JH2QfOLJnMki1p2EJ1dd7vi2SPebF+823mU264lltuhukynWkW+e0yY8Zk1t98xuwrOZP55u1RNInXGX88l3iODXwvm+Z9NEfbzI+T/hl48O6Y8tc/QymuIzcg46i5Wy4nYxVuBm5+/tbj1EzZVz9/PCHHjs8+h7/LHmX/XSaTfeLxx3uACrNVtBwivvC0mRm5xTOZL3/NzP5fqjzR6SD9bulEi2jh/6CVijq1FKS9KOR+44+fGDB51PNHM2gSb86Wt3T2LbbAnJmxLS8U4I/6NdOVnzoCHTJDv84M+zHzfPbo/9h77yDPruvO73SO0znHX+fuyTMYzGBADAiAAcwmJQZRlmRapZW8W2vX2uva1R/rKrtc8m6Va2VX2a4NtbsySxTFsCLFIEoMyMAAmBx6Yk93/3o655zDz5/zve83GoIkMANgoHUtTs38+r737rvv3nNPvPfce93cugP0yHFZmBQL/EwfXUo+5umbNOHDysbX4Kwa5Ag0NmmH97pGDioSCx96+Orr/ugfPOW21k/PRIoM4qRkvWTVMvU9k9rV0ejdekPESuH00Vk9QqW+K6IgSCcsxwMq/LwKbxd6Q8OXMZ90CdoBeuHdhZfuWUWmJIK5em/f/0ZnCq4RMDRv4xD3tj0OakEuVD9pfXo0s26NGba66fehg1ie7azas/JVFs3g7npR2fC2ZaZbOcIPit+0V1PsQ0U2DQ1C1tsu1o+LMLdSbWHKnZ9MboGpeTt9y1KE4KVNa82LfIZro1aX64Zj8DSg1qU5e05kOp9tn0p3OxjbDhgbcx8PkxfAE4PD10WYyys2N+tyORbzR8gIrP8tMf/IuJUVRUIqPup8UpFvvepJeg4KK1BpRVjY61ZabFtq4NS8s27wJ/E3QMBlL9hpkV6HOl3GyO+ibsHuIXNappcP5G94ha+M2fUtv9y3bttpVipvZHnTisqspN4OC0VYV/EBKyn2bNjNIyOWJx3zw2uWtW7tMavW5cK8La7Y4Ixng/4ebXLjG8CsPNVnxTs2rcLT191vPKCSqVXPgF3ctk7p13M7zofjat3eFNtJsYvqZTy3+oQN7rj9DVBf5KAKsAZUeIpVFtmWaJyKra1bj+gEH3Vh076pV76UYYUplr1jj6E3BDdv2iLkguBotYpcGx319HVx7GCGZYqcYiiDxkik/skl+4MjriRaWj1nRnba8vx2cLGQ6ThRFRV+v6zcXTWcLjoaoH+vTlpDjqf377P+fk8AZwe9R9oKI7+lvNpNahAI5GXb0rq1Jr9LNnd4VFpOhk3PRFgdH7N9+6yz085fdNyVley88kpEWt1XDEcyTaU1x9yxxL0MvhO/+CorEkIXL1lNpd+/2Ovfzd52LTgryj9Y469856Lf/1CjXeu12ytWjfRCupW5Xx1cr8Ulqyh3v3FNyEebQtXdSDuzx+vcKMcnBKDzFyfs2qaNbvslP59Lujdwxq2ku46bPbtqpfL0yHYy7h6I3rCuYquvtO0UyxAj0Mtg/nLcSxtNtdpNK5CcW9+05RQ70m4FSH0cmJ2o1aRxYPBj29R38OPX/qM1VtrrajhOzgxcLwx/jA9VWD+O2R4v4fptGx+wbDESDNXaZhvi5dPX3PhbTImUFhT5l2af9zd8ZASPsUektb7q776UYf+XqA4/BBcxIWIoyLAbN+xSt2Wq8PRN13lFu7wEkEYfBYLcTLW0PGuvjIhwYMDOLdke9RGC6OyU7d5lw/rWuEZSYuIdZEFqwjaUbWfTtdSsWYuX7Vqhx+xJpeFUWtEgrqTr9+yx1TU7KyGykWZd1e7HAv1zPnRSVmizcDXKe9vGt5wBgbpUK8u3hD66tGwJRjQybJd4BzJmmCYYNzMrDArYuuoJRWzteJWUy3n5X9+PgtBn/7P+yU9JCTZEYI0HigvRpptopbJ0Jebdu/6RzA4+TU2KkwY6sq1Z3So54f0L1YU0dP1UuuWlRDJkUPQT6l8peX6HGBAkUFO7voQtG9QoH+ofM8zoWZHdi3K34FeR5xsRAElDY/wCItg3ZriX69DwRinf7qTRRsOpZ43ed2kATvLtYRogHTcwaUVibZj31rw7jQCIum2GLCE/gJIZ+/layehwbgoMpVx/Nz+YGRhZtO5xyY3EpvsPN1QX7Brqj9wAwh0l/YfWf1ZOEelrZr97wF2gjr1exE5+wfrieop05Nhk2vDt7TBAhg5F816/Hulfnt9csmIhaH+9XbwVqfKXzeJC8ghlyb5PT6KuQh3xcGpkjOXv8iHRYBTlosJmraHeX8GSPP6Ide5N677Oq1ZZuP7yy1Zb64/w9BjKnxYB1RfY5JJl7ViBJCFUh5kUKOfCqFtfuzLssogVyUa3ylyy/RhIRfb8oJfWlmrdq97XoTe5g5oK5A39V8u9CYa4X6bYpATmsWxbWHIeARCNf6NxK6j67QEE3yVjT6rPbT/KvKSykPkUq151y5BsH0Dsw7cYG3lWX+1GHYCaTs20xjpPoyL/97+yug37a7/yt1AWfUo/yrvS2g/rEnp4Mem8IQ2QFau6HxCopP9QAo0OeqeTvsizIeExsW75BfbjDPt3lAsXbPgIyyYMDNLS7cJFO3vRppWTIekrQiyPoDoaKFvAmwbfVSUsR9d0BJgMkgFsB8Hixb0DCB9qlnNB686oKBqLBAgWKTxOlcFiuAxd/w4++MZX792HckK/d2D8OBjBGHBUmiaFSafjZbaUZ9sTXlIPIwRS2KShpOo1W95xQQ9AECt4HWoufFKabrki8/Obthcrc8nShX4eleXY4Li/wkQWNMd3g2n4wnVrq4466bVRm1uz0iLP1llni9Nuf4RsK7PuX3WJLKYXLbXUHfQwt1BZZc/esEchSViOYZI+G9NHd5fZrRUb2baMYX+E6MFMDzZ6aaHNzETzDzE9wljfGPBsVzadfJchHOqcblUMC2XbKNY0pLllU5vWRGMQRgm7sBx5IPALPAwP1PsTe1IYWJA4z4PkE1YpqTC/4spsbtlHvoF1FGe6vSReebrc1pcsbcZWULMojNs+ejQFrjUvBCuGQZ3KhPdRW4W3HRjLsFtXrVRyM3PN29590+/jsRSl2siGdaT65SbaaM1ujnq6s9Zqyy1lyUZQZeSEgsutlKrQogLb2XItC6Rsu13bhh8CQUiOIPWUyxLbVlJgeZn2AvIAYmCIMdM5ENiUUj+o9PCmmwXV1ZHre7bH8nciXT5921XgjvCD1b69ZVjtzRJADF/Rp8Fx6kxz0+H06cilKc7ZWZgxfDaAvsM5gYqA9DQ7dd4/FGYGkPjlmdHEF1MH+DZXkU+MPG0bwwF5s7ZL6CrO9zzzal1VhaWvuMENeQBMO4wtWmuVp2N17hGduurpwjQnIURkeamTF/W8M5MDUWUuW5Zsd7QLdjmOUOgycuIFMWoASOZbcYlVipzODNtwms0LresDtmfJHqrxbPDj8LK76CrPCjbs9rw9Lwl0eNOHQvNy7YJo9VCjc8cJ0Vtz1d/6lukZVnbbZVO1l+dMzfeDmuHyeLalCPmvb9gTZT6aQBsBPgej7FZVl5d8hJg2hprTcNpYml55xQAAQABJREFUI5k6MeJ1yxKD8HVy4lnRHQA9AoUHNDLBiDtaV+v3yQbX062P7/XLlIQzVBCUUBX+bTqE1++PinNtvdBnyYC5hDE9Fbp1YseaUqwg39YQNxpG/dym1YqtYvXeL+mDfh9iyM6xvfnRXO7sjDNFo+rGEO9A3B46GE3l/c1FK9iK+ohqQ1H14t6ZOVtadb8l4IT7N7atVfKEmsBlOzlWqLZD/hRcKnRNL1lRnn8d+PamT3zxSLLTabgJxaBHhduuRAN5Q2/w9Xdv2SF189RcNKlLCS+bfWbHJ/b1HVtasdItYyIRYFTIqVpmyrV5jwto2vTpYqB1w8eYcb8BSmac8ofqLwQ1vY0CjchJjOaZ3od7w0AsObcD2T9oEHW7qQ39NELMEuAnEY/JKc3rSgS+RnrD2vBsuITesPz0hpeANKbH0wPZ7NjLO9au2kMJN5LOG3dO6mY+BWH9r9tSwqrEVtXFNjFvVSLvtlWP/sAMEEHphbt+oD6Jk7tu3X8yaBAwXKKvrN9VwpTSh9RwGJBRVOD2nA3s2ISqXZ7q5B3sHuxChEcDsihZQjyZCH/1httq77zOP1/wfV9Ny6WhvcvUXkO3KHcZOG5lgeogQO6Uq65w/NDSQCd0H5Lq+eeta7cXkZWbkphbu3LT35ic3EYmBx2EgCX0gzTKC0A3IYj49fQuK8mzizJCQAjfhYQkL92OX0yas0gwvWpxeogMyzaUarslamLtHu/AiDlQleWWyc7GdnkBTXH1wWAog48AldlJusT1VbZr2UaHouohaRFWTPUAQTihnSukrs7LeQ5dubFg7SvWoovlWTchqF6oFTROdmlIN5Aw0JCcfV6ePYIVl7B6yT4UQd+ATYvUuEFL9RHlu/+fQPbgQ2U7vWG3hgJHVFogaQQ/9SQd6LO82OV8UGponFOnrELoRkW2Z1v/hk8hAvT+c0rww7s0k3Ku6A5Y50MyvvyanNTkF6FW4zLIDeBgs/tUBfQuqjPLcvKsq8BNJgAFd0dFYjnf6rF9nRFt/Nlt/y70BtA6UApbAViOmxpLDbKF6t2pjJ6/Cz9B8VEQqDuVJEj4mvo4YckWhVQqkqNL73oF9JF7+gndek9ZyUQ3MNEEjE+5IYIVNy1RNznlZp84xe02bA7RudvczPzSPOQagCikzUE4Ig7KdkWOezUm5pZdTkS0iA7gI3OScESUxRqd5pj4Boh/K4LwBcfSbGbUDV/gpXF7vMxdrL5Bv1zasppd1lHlaew5PC6slhD/Q55GBU7waGzczi5GZLFR4AFvFYw6q35p6fbimv2W1A+z3tA6JA5AcBQFHxbrknm5XoxOf+LTCNuKMsqWGMCIgaUDqxAlCJtJMbl8R17VJC8ZukCC5KoVOVlugPIiML1hrVl2tMUHgQAmjmnpfn2UWcGZZWMoncoAmI9gLEzE9catvCSqanmeR1AwmIQABUhkMF/nSe+4ijnbFoax7/Fb4qt2DWqFZBPO6gOqQ/6wXWSsJT8S6/gecPsuCW/qnJJlzcIPlHCbwSfix7wAizP8qV/SxfBelrsQS+Ly1R1LZER24cmEC8H9/oZLh0Icp3U7c90vS3ItPh2N/fSs+ehjYOPWVJvZsd0ZFkNGEhXAgOVyZOLXFzot0Uehl6enE+iMMD2ya9uJNrhe2JcIDmJmUDwA5ITVuyDRCzKZ7huTgkVG0IRqhI76jB65Nu0uPXB2wh6PuejXsKCXgPsXepmvUzJzSkBDoxMeggDxFAAPJHRlDXNlY3Z1yG83xbza8fEoLIdZym+t21eER+qMJ8ZMYzbYwTnPtqHVKBziwqZlrttHjvt9ZmsbCj0CIUy+oahw+3OkEbNX7JlR+3Su7W30nAA08+RTnsAHA0ITeKUBvk6N4jAvb1hhps9dAxDO/Ibtqfb0xoyNLFgFoxJQj2QZ7JWK+ETTb1lRwgksDL5g4tc3WKaoDnpDx+CZA7Ecb0v3YOQqwEdMADKYCoTwPOgEAI3Vla5382QyTE97hN4Bf+JDnl25VlkaIZxg19FNS1PhUDuXS8J2V6ldmrLjWT4XB1B4Jf6z+uXxBu+jSmGYGM7Du72b8OEBhBuPzpzxNBq9tMxHeUAvsGvLVhMRW0EMr8/YRwr8PvVksIPeD5wI/ewbj1oHgYGnxIJtitLI3oNqV/VK8YJWo7kycDiqYTmmtR0SLl5G9Ao9cI0ZeL1C3WjFnjzbUisQMDfHfewD2D/njis1ZxAayNxyqzpV3YfEmF1zqQg05zunILXSJ/3y367aHyEN1HBEN1EigXl/ppFOBFowCxCk78N9YaAuacl139drbytz6BwUCtTFXPG4yAYVUZa0RKkMYka33dFq0b9+fQspzlv1SiP/sPwQM2F6KmXHbVCxr+t0GIIXAV5BKnI/6Boo9sKGfU5MCo3V1PrgGrB4w4Z33sw2VS7P+bZBQtotOUj7cDKYCv6ibsHwoC1zzLlt2dyUf6Rw00VxqHbftg8nSZF6M2nddNIO45U31O0/HfKnE2FJuuA8LVGa9t72ZGRhv6Gq+XpEBjR5aOwuBqrS3auZmfEitmbm4j1bJ097vtwMn1bq7fU0eZDJqIag1PCIkEhMpgEhEEOGmPufXQrmlAngX7mhwEWyvW72abom07LVT7n5Vpwsja+jHxdkQnRWuuwFQr+QYJUEY14AaxkQTa/qS40ETchiKVJpt9fsu5v2WaWrUn28nlCO0MAaIWTQC7BzG5bYsA9VeBqtUbZqH0yGF+WIO1QFf3rT7IgGuUjTShhhn1wahGpiKyJjTE7uxT372wdoEixdVwF0QHVyRPUNJaK63TSQMbYV9wCZMFyO/B+diLQ8fcSSiiHiU/QyXc9blA/wbhsEr4ZwSXNc/+oRP+rG5MVdf8EJFkG67mB48K06hAi1WLSH9rpNFTQFCo7IzHPn/RH2BloJsgkWDmQASYT6wFCjWMVwI0Im04bXPGLiurqMbDScp+86UDL8S8Nl+3jx9Gxj8jO0DiwhMf5uIWD4XutAFNZpGVtwfiWrBdI9UBDAGUDN01QACQipVMEiOBU5trpg1amWp+9gl9djgAtOz9oP5u3TSHq90pNwPyRgB+bHv1IBvgSCvu/ts1HJzY4mlwJYYIDPHuTatTFPV27a16fsSyU2IoKCvAqXI5M6J9cuztvlTZvWt3491RoLvEzg8oTtK7HOek9DNKxnoE8YAwY62u13qixD/cP8e35e9FEw8Mqmta34VAPwQUzn9MjHY8Zvdd3qa6MJQJgfkr0u8YHJBcZEbz4PgJ5DK6jitrBm8yketwZg5M1t2U2J/KO77HK/Ry1n6UMQKI7HYTVhI8cXDmHdBiMPex3bTk+scJddmXafDUC0dTNDNR3Zfz2jni1ImZNEUKxYXC1dH7WGCufVYQlsMkCaQomNrbuWem3HcvnDiPi2nVuxM3rraML21FuteHJwyPoxMnYiZsNug+5pL0Drp+csTdGhXF7BR8LV0aMuCYiDMDqGeKNlbzmGpyACZle2PbDww2CQKJccy+NSSBjp9WLLc+2qCGBs0+p3Io8dG/2ZK/Zrx91EBqA0pEZJlacrij0PngaAIonFvFFTEvSETKBLOjr8UbzfZ0cf7vR0apadu2i11UmfqtCeZOZNErBcy8Aov1v999HDrhsw9AG8BXy5R4X85UUf9fnWefvsHn9ET7GUi/VIAB5a95AdxnIBS7ucnvvX7aCQQvUO9no5ABUbGLfaUl+ABzA2sXfVHi7xdE2ZVeTYc7jCWOpNtq/Dp+zgO+DUmLVk2MqGpwnvrE3YuX7zWVMateXO0o9f9jT+FQp1UDzVN21pm+7udjT7o4oNG4tHfcR7LF8M7jpBHdup3orb4h16nk5YFM0wQ3h1yY7X2q4gzrc9opWJLKBJ69kW5z0N+TU22I7i8rm8NeFC/IeoILO/3+arCIKrfPWaR5uA1bB4D7FONGyZSl7a8LWXK1uGxwLQ1zsTdlOPBtd8TvIpWIveX/Au7p+1Akn81/C1duw3IGshnJKb1FIs1NKqjLy8za993x/lpFlLrZ275mnWvzGvSHALdAVQ8476qHq4zR/eHc1ToY3QyvQafjLQt2iNOdG01dCSjxnlbntNAIjiNFadGvvBPHfj0VtAV5r9PywrZa2jMDmVsGfMPq53wDD4h3SB0+O2t8BKM+xZvfWBcktj7ANrkYB1WBK/MdU6xYzECOTl26qQjwTYSthfKL2SYh9ft9ziyKR+itoO2UvCT9GWjcJHXpib1/QVNIvLDQRXzVPvw71h4EbS+r+37O8ol0SdK02Edn8iGotpkFU3rIIRA/SwaNMTt2Q1ioL8McKZzACPnDhJSArt1mig6NFfQTpyB0Av8Qp0Ignn0a1lG5Yv7ovFnFSC9cyI2HNJB0bvvfs/4g/3mqh2nWbjwzeovojdzUqqTUsJ1gWoMI/CW9lyDHTb74O6ST0lW9zz/hIAFZgtWAd/JxB0cZOmKeBNaQMfrqXy6FCABHWTiHXrIkC4JI3IofIAY52v99gXPmRFRJiAja3ExrJ9/CP+qLgsLSdjOx73NFEYwYZmIAm4etWD21tjnu6L2/UpeyjP02lZ9sqMIxnsAejlj6VGQ0sQCfUhJkJa0TpK3I8Kw+WoNmR7jqQ3xIb/9rWX7Tcf9RJwtAYHffQKYGDo2dt2gjZrFAxrjdtdULOQ0EYgA7SopvVteLD6iF+583xAGUjHCqwiz54XsrD7DxUbBqeMUEcglCBK97egogtaMUUapIHSr4l5WNC4lvAxMgCFHAwnXb3NH8yHPclXC2UNBiJEbIMuNcgfY7NkwWhiv4lF27hup1Tv32bxyMHICr1w26ccY3nWL3uJ5sMFiG6A7u4WF6iX3Jaj9+9QhbL8kp+4/LSPSuazMAzzEssESKSmFlXnFIws/9m3/TI73ZpjduGSpzvafBLie69brawL+ro5SYRUhmijUAJrN2hsZYnNQRYMFgjhBZ50rL6LENcEBr0ZGssnwIAa4ZM9YBisNup7WD08EuacJCbfxUq8VVGBAt8qV/L5yZtRA1g+hP6e2rJmke3cttXnWLn44dK2u5V7RS6dRNQw5ICZpcsTJZaRGllvJeCFdVMqGZqgHoiVZhkQZaV+F3MTwNrgn5smKgEzd1dBNO7SP25ZWDO631pt1bmWSSigv+TREZgawWydWHBSvpXwaWKAIUDGS7CTgFihFWS5LQUwYDC6bq8l7IuSBVhRnTmWInud6W+Ci0LgDSslmjLd0OTTwBSBaiwl8qTXs7jU7bNgIeHmZWV6XCWAabu1EfFDW5qlb7v4aPMnPgmQzeiR6ja/YmMJ2y/pWM7Cobi7WKzTAKjv9e1IvN6esRNEABZF7hZGKitD0oX866l2JMN6A+el2uMFXu2gBUM8hHJ5cDCtrlW9d2X59FpXuVVLDxOvjLMk1vAKw7oMDZ7wKtjktg0kolHwzDQfVWJMHUA60QnIrJhfuTNZmmm1ED5CasW902OpVqiOubVpjTtRYAZShm5qhA5g3VpHGqi7ClsQ00xzuKnqMVX44qi1iE4ry514fjptXUIXeMJkPyze9d4Z9SCE4GrSopFRX44FoDwQ6yFSgtUvff1upl+54o8Q63x3Gv6TWGd4j34H8OpxbzZW7Me0jZ7KsEf3+5QpwLzBC+O2J932xfySOkNm1TWefuWMNddGFiroRXk0ZLhXDGxsWk/cauF7EXZbjVXRfpQWaNyxvSWRN9jVZYeWIx+PXq4u9PbmgibcrTKn/ALJD5y3qgYbGvH76CccS3xyppEBYtu+t+aTtACduDvFVjYtK9UvccVdpUlvpK26SA0DYqzqIU9aumMJwP/HxQKdACKJbgyRJDfWLZ2p1w37gR79Po4Z4ali0lYmk5nZW7eLkI7Z0+0+KTeIWkMCZtpp4h7V++CW8bBL192xAcoIBVy346KTP7xsf1gXzesyXoAjQX+FkU46K285ct6y1uzyor1i9hX1BesVMxIW98KsZNttx3yVtkhM4LZVFHkYA7C47kPgVZIqLMHq7nZLEWDmKit7C5rp4E1oddHdPxQDEGazx/BbVAIBLVnpHmcL0KG8cjbu6SO73cGGv8LquKvrVpIeTcuf0gx/a9L4prc/ipSXNIBzS0qjV0bH3MnHYJrSI8rs0uwECUadHqEVFf4h/MashPfRYZEQa+QmpjxGF8Cva822BvxYlXBlwkMxIQ+A/YcKRyLJgLJhjvHmtK2KTqgPC02FLZ8MgcQQ2gA0Q5ciJVgABtzcsX/if9+He8XAUNKsv9cX3m4+eFoU7X2HVKC7AgWhUunWQhWLhOCmSNhtDu5zKdngjyGfcWUjQb9DF+JL10310jg8RAHCu+JyfwqRoPv+nt7CnGLXGdQcgKaDrcICVCRrLXtcKc8D+pHId000KmcyNDx8K1QVSXZIbiScBdA6+kVy1If8eBTXfbQqkgCFT37gV5nUoJpWgqUFZQv4VPK9+JFA8glG6olMvaZvUmGY9GGlqRiNCg2/UyGeAlDI1aRe5g6jP0zaZ8hmSklPMCi2/4Bn21WdszqxFHQfOj0ed3XDyFoAxGwY+SKwiJBRVhEDLRW2K9eWR+2HukSZPI77pBcQkz8y+wRxKNQYvGV6SDODXMCLN6yjKNLFvNfXZ60FkYpE9jL6ibIGMPMOV1tMKhLDDOtoL5pOTWrNtz3E7HguH+StZTRQJgeXlSxhZdMX0IEzs+JfLIE+INpUi226qRnI+w3dBzuAOhl6TiEQPxutAfR4TdJAHxAJ+d13ADApH5pSCZ1KdyuNxQFPBSBNHZ5nHF/XVHhh0ZcgAv+sx/5xWXKeYN5YPF+yy001oFxvBQKg7jfE5kE41IkLlOvNfqD8x1BPWZ6H8c3eW9EeKuMTO/vy1kvKUjsVIs8jpiUqKzwbGgfbiamLKdEJHQSvBQahVtU79s1lz/b3qq0xz53tQJAQMCCzUal39YeuRAwirwDwwPeDZKA+yMPGpE9LFyM6wAxAnYPo09UD/4E17gMQcwWQAwQBwhI2lDTL6CZWCzBpGIDLmzQdKbblQjwmU49LPvbn896vAMV8gcFvyRL2GCD8CVNpnW4XhbGJBS4K8PW4taS4A70OInl90H6jPvJnGCrOyrM6iV54El8fu/BQzLMR1cDefS16hai89jz77W3bpbaWMClXEMUIQTHIFMwdAHs9L+F0QFEANjS2YFW1p9ErhHVtqjSmBfjKVcUw8IjIQ2YS9MRdi+UNl4Yfg03pacbUx6JN4f50y76Y4VNwAPMSDPxDfEGMsrEB0WjBVPpmwncpKEZ+QBlbvinNlUnrFsmgIRA+EAfADhNYgYxChfEDdySGojH1KgbOt+3VQc8GSeGCIj0ZIwGYEmEjB1Y0As1mX92JtCZxRGfX7EiN9UqGtRRa9nw0RsgXkV2IgFBVfC1a95gXYOd3bGnEqgNKFUXA58gJ8LWcdPdVgMkt12dMgoUGPjLlUkxPHIcNcAVsIYMeWU8XtBb75fisa+swqYIPwHKU82o564iwdI8wjSZKY8kZMjp4qrx+dK+L6f/xW17Cf3vMzdngesHqFy7Iu0CuYW6ueGWClYD4QL6HgTcUDPkpAeCjoJc1oNXqsrSEGxPhFXzvlkwbXbYOyabRUcdwB5hi9q/R91dojnkav4JvtdRHs/+4SSwECiF8Z8/Y3r32T895tv9tv3tlzCRckeHTzCYcrZGem130yShgWviKZbplz8QFQN2oZ79k255ST2NJh7mOBMsX19zjBbpYX7dsU9vOpwA7IlzddHUCfB53C15Wh/3f4/b3td/ghXl/9OKOfYh39WnW5sISqUJ+7qKrAURrp+fyzcce2mVpKDE6kZDODTfui4U9FlNheIk0nFXbcVGULWXenQc8w8Elf6u11P1eHE7gU1t2qt9yJDSgHzoIr4Z3AVgvJdWuj3i6o8q6iFGZj0Lqs4Z9R7UakTdNbiqwadEwoz8IFsZrwh5Tj7LANyOKeehnV5hie+EFLw1a2lhPUO0C7FD034rbARWVnsYjgq6CpueyusJNkHnRKgvDCBHcJ0KFZqgeVksgQihiVrF8vNKkgUaIXCLETSVwOeple2Y8fD4BgNsvy5Dq8ys3qhCYeWr4hS07mhuJo9Is+37cjuW6+wqwWJx8TE8B2xvWyx4zRRG106c/HLOng6ipsJSEb00WgFeZ5A9AVeEhNg4FGHK6MRMZoyekpei7EAOZEOVE77z/5x4wUKd+J2Po63t4421mgeDV/86JbTK5Qt+e1KUoKFJMIU1P0umweCBIMs8ljT/I/2FpZIwSAFotld1JmsyUP5m8T1HiML9GbyJ5CHYCEL8svAmDDtygYuIVf/QgIBgaUGmXbG7sKgC1eYdaZ2TO1tIo7Ayqt+aWrljHdRkNvOy33TIrV1UlfV1sgpNfBIqdktLkF7j7Q7+Y+V2/E1pHi2gvPYXcBuiFW8kv8UgCNXl9118aCwKCfcKyq1iDez5f/5rj6ckn3cIJKnJxfO3iuWg96sSk30exBkOILZEbqqORa6Q3OzxtIKHQSlPukrE2tUPfRiAh6yAwgF9kDpQWthAbHvLxu2Cjt5Raz4jtU6cghxdTPbQkWHrIw2PHokHtS5eNAfRvqpM+1ezjWTQEkwOoXbWWMhtQT/CJCr8XuSvNadE4HXdQGev4jf7QTf+1HedH2WXuEoC9wBT0PoQBefMUANU8Vfscb3wUkgD6hXwl3/4PBeJx0VkAHyUd2A1ywigKvcwvjSLniLLtpYHF0XjrU3N2ctSypSKpJEqEhf28CxS7MR5Jg1bRJxn4B/QkrTJd/ZIf2gjwxXbMHlkaLLEhAOe55/w+1tHW+tYOGyzl+yWKnpU1e8AalS90lUqYSZzGYBVk24U1Nw8Aipln2kD32d4ZrYqZHYgQfPYpz7v+A3XAvJgqwpB3Iv/G9BkqAjbQt+ERpg3oRcQBaHuRlS4e/A8sfB/QWB1F1MBiLVg/LPiW5IvjzCxaulpD/9G20LBmWpXnszffVkc2sUHNlof2Aij6T1VGoV+w0yvTdmLLl1ECNyZ8kWWXOOnjMZ9HwiDIgIlhkrjduh1xNWG7WLrsqAaUL/vueWGygsueXn/rO0Lkw+B9zU50RBQzSdxjplvDAAb9AFt+q64HKuyRWl9KPiMx9uen7UsPRczPBMK5c1HcFPukUUcmteAWYBFtlPCxHOBpAhFFU6dEdJU7vqDzW9JOT2RaBV+UjMC8Q7hXJUmhLsVXWw2AMrPfZMc5xu9hODIs2rEDVtNgJTf8spRpEMSKHvH6c702O2THZAczEs9o96hKOEY63R4SF14Z8AYiIjMR0kjkeZvfiTwi3ns60y7JOO5g+UeDx0AmhOGFCe+7dX/DxVCnyBEfFWA/wLwN+74n7ctsu5/qcykAxSC8hsye8CtvWjfTU0I+zw/luWLuFpLpdCRLkHTgg3qxSRSw02vL9DIehZggiy3UZrw3AeYhEeVNvIaEyrfBIVcGa5KIzDlg2Z+K+yOiMRFAzGh9os0v/+3z9pVHo30FMQJY/HPpkt/HmcFXYV+BEEB4+pR9+6p1qDSscyZ8+vo9GwNjeGjQybpagbecs2AfV2Ohq4pC34Dug2oREmd8InIaqTBuVfASETGEpONXHzjgBZZ2lqetLYejEvCL8Mx/v8vvjzIFt98vz0gw4HqxgUFwQbF3IW+aHyh8uNfSB+3TMX+Lwr9xyerVyzQHkwIaGJCEnty047HIx7u+aDUptrcwmstlywTke70Qztwpk6KoXqB5w27N+Y52QfBQX6at2MsB+JNx+7Vs3y0TYKVQ6qITCUvCgLVNx2SuqO78sp3cts/N256YPwJ7+KsY+gA+Hk5UcPKJI03tte9t2G5hdVg7JYZRT1hvrcbXQwMr414xkM9IKlC37pGf7PoADLLOatseqbN+5Rxesdc37cPQh0YuCRwKDmpJqs0SqcgKb6GIptVgasSULc3R+++F7d81++Pv2xN10ZTma3E7yo7qaiweFBYkFgAmBUCsIB0RBu8X8QPxuMTpCC4GaHELQ+Fj162cdaGibxZYnpq0TzZahqhrZsS31g0HOVAg/tKP+7zkpm17mG12ZyOZBmofZscR1aFxyQbWLG3as4GNBOs/KyKJhC+KqCmhO+Emth/MdhL6016/7FpxPzOcgZGV5WOQ67r/M4a3CqxmIXKD4S36J0sdMcHcO8MoYrdRETkYDfLtoBDo5b4P94YB/JNgut1b9rfOJQKMBsXvzg3vtuuaL2L/kC1djEAQxMWftyFEqm6LoLWRo5LlrqO5L1Z2vufmEQqRdTmz4GYcYhyAEuEVcblPCj2pbabjejTYY7+916AxABV54ZrNSxcjwilZ3K98D+BHissNU+qMvL+uTwRDdlxpkPM3UjRHlLVBNuigHj2iuh1W+jXZIcVJQ7xfN3/pT7P8nKC5bj6w4flf+ulQ7TVhtTbpYIB1mi/c/3IXMRRF0+h0Kgy0IUwGXTgH3ffPvm//8yeiyJeV5S2kZVCRiLLyOpczHv6Agu6zbxKgrp5dnbTaPLslrVG+ZRdHPEA9wAWRXKcuoCXQdRs8iwgYO5tYt/Uef7YrxcOw8YUApCu6Eh138IgTblpbcyrm/CL1pZILRHB8TNJpfsw3H8cl++s+f2uQFQQsBfekGx6ghfQtXc5sWuq0fRqbTIN0352MTGq2ic/KsOblKDKQ/LRsNryiqtYkRwcgXaS1zDS3zlEyd7wjyUW983Z/QAB8elyvNxK7xOlHSkNUaqhfYHeRDbQJx86GZUtWK7I7wABiho0OezYW9NJw6qori6nOJf7E0U5ftSW9L7THm9c8YJIKIPB3N3sJWFko2a+OePq/ybH/41v2eHJTpTM9vrU4FizgsSFZbooc3OOXV6/5uEyFJ91upOYgE8DRootRSW3S4N/CIkpu4wH18nUMjdD8N6+nCnuzH1AXyklRLpGeoyIAlYFfruoCoUdmqTuXe3UaUUpmfLB/0++r+FtjlgmNi4Gr6NQUO6cmtmhq62WVdUyeWLWQm5/q1gDG8YZTh89y0rwzyvZppGFGFA43BBtvWQpBehL/19gEjB0ChCrfN6/YnewwDMPKBMJVp9Uz+5rcjmfZOvBZggpYm5QuKoSFimyK8fuAcrC5be1b9k/5vNn/VOt8zrA6wJRFLkatJ2Vbb3h44Yr6YZNd6Qgno1vYh+M1a6yxrQlPE3lVWmIfW7IU4QGu4PUg9dBkSDcCpbb1VlmlT0d8Ti0ibA/rdkGyqbbQitdsgIVeXp51rVrGho3q0SOrLoDCvgKIRabRqOehmGdzs3sk0pSdBb5KklmaddnELtSYABS3YZgCgY0HMJF3HMPBb2FVWEOZxzQCpxbsgwU2Lp6eW7UGLZrH0QKwdMfMF5AAD2tQ54dsIAv3oHQ5OYqYAU9azo5/5YJ6n1YjLyFoVcfbhYSVKeijCBgBODwVyskAGzKS7RwBeuMzaezY7unZBcd/LkFWakWYtbstPQPz076wNzp5uGB3vrDL3Pycz1Q0qARsaDZEYYeGIIm/8JifmvXaq144xMNAHZYxgPX575+zT+2JtrOjU1h8mF/hjzBYKZ/JCgBlA+Z5RT3plY/j66raWMxMMX28KNoKfH7JjzEYU+Fsrj2wZWPq8c/EvAQovP6gi50Mtt0YWRuQk4ApTzUeEbJmdMQZuuRojFzGHko9PZHDxqdfH/OI1iZ/4ivW2EIwTMRRAvtAQpN+v9xrwmRs2KY8Y9NXiDmi8Mro8SZ3NcP+H03VvlcHU0xAmTYY7FeP03p2/3f/SmIUcmLrFOLWgKcKbXnGrolOWrH4N1yelpb7o5Q0H9v+SzW8UyxPxC/9DjANyKjKpNKV6e53Fbk+tV2FHq7w5IqV6UPcAz90AYDnxpROXszTuEygFBkdguWQ1ExDJZRtYdYPb6CG7EYFwDjHU6xONMPXby1YW5nfR53PTfguo2ETVIiwfNELBIgXZTL5STkT+Opp7LqZ6hIGIC6CjgjBn5iPhw65EwX7ANAGQchhs42jSKSCaPky7YVhgzAhG0gD+egqAC7GH67TyWlczo74RsagBeAXaVYgOlnn/AO2r0hat/AOvXZL2VgMCd4I7gVY3glpU3JAF4k/2bGv6BGT9nh00Oo+YRV01WIloGalODl9LgSjnmA/nlz37obUmzA0fzGDAMaewQdhokB7gXNrz6YP+wF16msl3/+5Jwxg7qtb7inzvWRa+BWZkEbBZOyQGddaZmkyNBYnXVj16C04Y1HmF1fkD/+4A4gjIwMFzoBeILo/FU1+IdWtqBANfpWtX5SfHwkVi6VGm1vurLi0hDWAn5yzFo50k68zrIHktuQwtrghWcTP/4VgMWqDjIX6giL++SxvdoWKAQMxhn2V63bSjOOKYsc01L1HUojCaZ1kg1uovJWlV0iQE9ESsPEmFaAYGiLWcSv/vYSAn1FpWDAm0eUTdNwPvSyV9cYahZt0K8iRsPSlraxFR1EidYF/8GHXHa++6mkMFVRk2BYIafZnP7YTu32jV4BtLVYxxjzpmhf/KpSWneOTRSMzUa+BHxSL3vCBeARqBXskIM7AW8JVAGM6AKfCTHFip/TgoYPW1GT5RWkFh3hDOmBkZFo6icAQKDDs8DTMEQUKXHps0HPhU91MdgDFv6gDvrr8iYfQp6D+hC+2x6jftGqRLPt7MSQ6EOk3RyB6T0rDyaBV7g06AmjSyAJsAoQM/UrzQdGRLt7uT+gyqX1fKc3pJmqQ+2C5SacIDqZK5KnVVzAdtjY92AdgnQLh5TkgHUpe86VQs5uRxUX1eCWwJ5WvE62GbuJSCt/f+qUQcAl3QPwhuOyn436uz1Nqv1MLpzKOeXcA9aW2tGizVJGuH/FjKhnnDc1AicD9gQA+KK5kUhQg0Ax9B4EFtfiFJXfGbvmTiHKoNs0HYMx3Anc66I68urs0iILqBRQFhISqgreFu/M94LSsqnv+RlfMxoSVsgVrYZ+rYisXFxFQh1lyROUg1EBohkQXLUFCXduJNhaDzXPkeZMxjfGnSdsl3KDpq+g11hJINrfhlXEIrzoBKQDv0VUYZAADzMVEu1GKzGimbn5LjFK0YXPsM4HFTLmQY6mVV1gTwoYw4iF7ksOIsu2/2+2X6xNungYPpG/GijKspsjvk+H8dZvItB9LRvyezg56+RV/xMRUaZl1dXmajWVHR3ybuHV5IFD26TX7smRbR6UvbmE1akyX+C0X+zzEGaAVWHuVhZ6+OGbl2mZ3yq+sb9vFE0gDzrJ7aYp1IKvABhuO5Tihh0OKcK4yMev9iR1nWIiFkpnWHvNLpCcjJf2qz0M5bvOFzRsbIa9MH80KngY5MzksSwhHZaImt8VqqEt8OZAcbEFseo4tHqY7pcWRsyA7mKobO/aCfDAescaMZSpHZZQtzVj/pn2oJGL+RXZdo3yppk6UGSNWOhCDt1hjxg7v7eq+wlV7acc+pf5K4FPhv2F3ih6hK+BfXfDf/7LcHiWcYNTTJwd8UwcAmxIgXBN6YMsWAMc7Nd1nkx4+6pfc/+Nv2AGhFa8AHyZwO7MuByrt5CnfOwFgxOjxXLuJomYer8ZxEtwtpAzYIKziAB1Mk/NtI90Guj3N+jEW/tK5y9J7hJsOcPST6kA87eiAn0AF4DcyTsdU2ILOXVobWC3JX8eaB1Ae+PlhQRSTJ89estJE5KjQXxQ1OubZIP9D7e5FcwAIgLxjwu3aoKdbKv3s79Ap+APdPS6+g89QmWWvXbN21e0bZv+cWZQh+1htVAIfDfM/tA6Gahapswbs7I61cI6k5/LNFW4uWJ6qylENHMgbBNmVLV/9OLJuBUL+0qyvWGuUbmuq9OllgoFpGgCDUFsxn8fEXoVUUCM0Z8FS8vzM6yldHtSeV0H300eg9FLcsx3f494jNMkEEfBsn++ayApDgG3oqT+9c1L0wH4qTHtyCYwtW1NxtGUFHj7baUDpSBLgaJ4tLEdcQL/U1fsGPAAk4evWlqOtsZiZxE+DqABmUKGEv37G9qgIgisyJq1adDs44ZtwdOqjnALZxd6hc5GlQltg2zAjOp7wGL+qkWiQGIFzY9QtD4BpYfIIVS6pOO4P9bPPn7hR+Arrx5SGeJlPZvMM4Htmv6UKgxZgdts+Q48LJ9xhBxHIJlciF8Qgz+Kh+5b8PufSABUSQZvJjWoIc61kCYRkUKGOqB5Qwyu3/OwHzDLWwQKBxjz1PtwbBqCRoM7vLftb5wr20C/NF6wHaGYIUlnwhSsATIOeCRYMOhNJIJkRcTGZAyASUFMiE9fRNZTA+JdU4Sr7DDMpLdYeULYgGSjzDCS6E4Ut/Vc4adP2V2e9vIps11aPPOTpkWnruek0LLHqXsodCF+JJ90bKoOFEDJID9zJ+BYJUbRXgyoNJz0QGEqSyd9FgVB4czJyEgkWT9pzXXoUcsJA8DGtw2IBxGpK/cLPhBA7p/t3DLtfyPUAb4Al6sxv6EGEA5fSkHZQQZW9+vgdagmVRNA2oLOEL8JeoA2E3u7dnhW74p//B3u0xdNBRYbBspFR66j2DVrPC0dtO/bBfLsiQukiniW56xWqlsqM68hgStjP/6QfXo/rlO/jTQkRKOtUBweiMHg/nG3GDjT5RxHFiJcNdvBgBoTmDI5n5GZsILhljLGOa0AExMqxZ674sTqoEoAW0WuQJQBtHyvwBQiF8g04U/HiRbsgumU6jh3awnLrcZ3PwYsBdY3asKFOJVAOZPOijrriBoxDQwO1QxjVydBNFPI7ZGr6i9pC/1LmNjVrxTlWwTc0w3zH4qfXqAC31Qgf3JwGmeoIdCKDdOHYzEdZTcAaew60VCu65bqEHqfyfIUSevSIPoKz+P1VEBpL9WhgGKxvrbRDndER1ShE9u/FbgmKAJ1IHQKdYHHRg4R9hfltplVYRycL1xkTwiiQDYkebNegKkcNAXhtp5JiJ9QKhRbk2K+q4btyH86FuwNWw3cDL9MdAW/vylfeshAY8D6AQ9bCmTAf6LaSHLczQCvAOm9YOByn62NsS/ZtkTbNOyKK6VA2zuVg6DS4GTQybz0K3UklfoZlM5w8LUzg02NIwc8ABijdyXj2z17xy44Gn3TaVEdCAfF4NEVTXqrzhVk4oe+yxyBzUAlR8wk2o6uwn/TZlx/2ElbK7DvnfZ8PoCUhcyTX05DU4ppv0hAEFi3C+M4SITDBgoUNnQGsBmGQ+NyKHcrxS0ZT+AibSQDL8163EwdtCw8GgpuwnQV3A4A+zuPDZFfRffhdWdbKzi1qbBW7h637LBBQse3nFzNeDrDn26VR35bgn4ghsALRmgeUxpeA9+YYmNdrDBFVl9n4qL/FcqPlVNujutVku8kI9oaEcebWWnJtSHV7ZsfqmA2QenmE7qOerGgS6qrKHdttXpiLJ+pYy2iQSBLebpIm49EEIRwcrasW9WpTSo4CC3TMjhrVGXZOJVAp9jCA8z+hS4R1kQQcV2CdMM6AE4zC55ftxHgUTYrljd8VXHF4mzmxn+pDTJO2M3hTEk1B9CPChu3wYS+aaZ84W1ZURuujGD97Yn8044dDMrzgjiLwOzO2t8bmcuymFOwH6t3rCGZ9kY4HGEJUMHl7039xcYNdzvoE5jnX6QCYE8pctn/Va/9QNP18rz3ZEi3rgrb3ot7qPBtabXzMHbaj7K3BYM++zIyUjLIyxxB9R8eF4SJ6YGrCToJkhCKz+bn2o0V7MsvTTnur3hfBDcaTYauMhkp/xFgR3RpQxy8b9E8tRmOW+Xm2l3MzEO1m/325b6l/bNO+h7ow+1K2j1OEk7KhMTAc5scmR9wwoptY0grggVzZsBPS0Gw/BYMHDVGebkTS5nBmpfriMsdDp9uxFn+FKPnUhN2Yj8LtqButO17vj64POhX1itLKOapbJNXnT+xoptc5TB8xadPUbMf2+X0kDB4sbWSpIRDb5Q7DgqQjSwEb2eY038pVINF07GwRxte3iZVd8n3hgX2sHEuxfdWWL9ZmGSF76MOPAJ48+pvNRYC0wrzFseXv/IUfHwywsg79EUJoGPdlKGdfV3RyF73JkkuG8wH4iH3hA/I5/Rx6wN8LjjSdNcy4j+fyEXT++bntA345RVw73p0nrTXF97yqFVrxDFm9VrMd8c6PQIsEJtkQg2AyHJoLD0I6Y8w0qoEvJeyznEsufmMjonZilSujGS2OBKW3s4QfRBajLaF1jFWzaRAH05dKvDDLjfRmSBLgULvTEIAnvTnUZ5tBJZXQWaG77//cMwbEoJ4bO+lBQ7Ae4FT++aad+h4kH/5xBb0h59TJb6wLVEo2sbIvr61hB1qzXxdFreXb95gGgVVlepJN4sQjD1F2N5IlwZ1otxzxTj7jILRcNMNRtsxLc46LSDWZW395hVx8TpxtaIfQBB7qyz+X+U0uVDUfHe+W/d2prNykpThaALyFYbeM76dL2AdD8IrScY3Bx5QGb2h1aj2hyzf5gY9pe/jum2R7oI+oA6wt3e5th48DhvlFq95dt7IkhodliBM6Dpyf9Tz72HRH+mXwtj19zE+TB3CbUUnPqfs+N+FbTE1mWw/fo7M4BbEkskmYbGdRw4jMiZvstC4CCxICDw0t4Hs7C5+cwPkXO/aPEGFmfzlhX2qORuIYxiKepbPR7zNmin68cTNxnGMooTGilVKttNoNppXeTVywELSGEMNDezHpoqN1X0+unKcdRLZv50V0vKvEA5daVIdqHAOeijixlBaFENlibs8ckRfKh5oUVvCw2fNcmH1SlBOoHYVMCaF1Be/Y3cLOhuZRpjF9iL7blWfHISk5e6Ef9cT7lH+BLyBjmC4oFI7TZB9sHC2A+Pzrax6ajkUElKuXZZ545lYNkUADAE2gIXGlf/EHHgEDAHmoUtiM5GiKo7GqHuZACZWWjU78x2/thKAPLE8eNekdQk7QkrGYLz4HGIsHV0ue9JZCVmHBNtJjS4cbjYlA6RC0/920SjpIA736oH7AEzwSZLLIPBI4oBokQB7vDdyfu8W4ewj0OtRoV0bceBI9O5YpKER8Yehw1G+VHpzWUMTepP96iz2mpRtoWxtUQviB+octChdS3ESg1wGwv5AwMgNlE374KdZhWCOOHTa17rPbQNaoWwYZIlnsNtLVVdGpR/9iwv5rjGyVcKTa67yP84J6/S2Mrf2VPtoNxFjGlxdtCjfLyhqNh7GzH8AEAnwOSQE4A5jI1655mqKwvXLxauADRDCnEkOsqjeWHFYmVWWZIHBqyVi+VSA8cB5X/M5BqxhgzAIn7FXPZb+LRcXG7pIR5MUIxpoHGPRpKLLPy8HjsjvuYwBlkIaGnJkiIORy95RfsmM1DkNYv0hw1xMZxvJWYIRwJh3jE85QhtQqFnzjBAB+KWHOwZM+S8kSLLw7NchWZnzqP7ANNTySHOwhJ333SI6fLQag2FgSg/UG0PW3GTsksgvxgDOQbaeJ6/OkKznYGIyW6bJA2rpasoTPIS6DL4GRx6TzDRoV93ysZ2Mn7kfBLHmyHKU6CNErjGhlo4XOWn+UzbwEFCgMw/bp2vgu9IXP3rDtJJ/n6xm2v9XtCWA3/hhzdwsukgCECPZoNeKKudYL9onDjkwAH4BozwPVHvUHsJkpcwjB9cIbucC+PZgUVIXFDHt9RxPIEsD4YOrjKCiTLjl/xfZ2RNv9deIypqXlsoKHbASCEl2JcBLlsCZqczKaVOHmp7ONADyAsDcM4vb26EMnT/q0TNj74dIVa26MnG0WRLWXeSRYMJ2JgtsgEkyt2DVlOaXWWGzFqh5uSS/RieqY/lFr4ywpdSXkfZxpvSSljS67yRIO08xcdbmv6ni8KxG/sCGUCZAHnIRZ4p9M2gfYxWE1muSBKY4fsgK9NqThzzDnDMHgirfiW4pOYC5eDwRAgYxo4GIBdAohCjhgnAAGfDTPOYJ5UaC6yPfcp7EfOOiXAFN5bLcFELdcmOeiE0AuZXEySUXkgl4Ztf4d+0iVP0Jb/OWL9psoAdRSwRa0AXWxlg8gcf2mr+4D0CsuTyr9ZEnAx5U4oVtsztcuwXrqfTBA10P5e0Wr5NwHe6o++H7Dm77hxMsLXkIaJxEnRd/1hAeRf0GtOzfjW/pS8HOey911SDtYVKAZ/den+81iHBqul1wU9O14owAwUVqgfUr4AAw1Yj80+4on3Xe6FI/m7s6y/SmbSiGK9RaLHPAbw8ldzO/xxTm9gqe9F9sreeBMODtFT97/uScMxJMmGrQ8ek9vvP1MEv9uQ2C+0qsSq+5gIP7vWDCBYH7xG4hfhLZINRoCq0fmiFbLEL8aLOAtpJQTm94nP3YJilvS1yq0UxHz6gB8hIq8qXzsaZmx5YPlIjS9mTQAaiQ3MLBSott/+yfYQH97/aapkJmm1Uk6iS+jCCVVxx0t0MI/SThXNKghcbZng9p7VT4YIz+N/lVYulMLEBVwdefOe5+gAmNJPk3XhBJ9AdAc+igggUsStAhBBNBq52uh+6F6FwVEvmDYAHg7HE7NgCxARMzursi16NB5x6Pz1uFPbGrTg3E4xRT4wYR9otQjKQAC1Hskr+okdhiOROLV+xP3Fk5u+Uq/UPjnynz/4aAiEZhzi26me7ZNO3fWjh716X2g0APc0zMVLT07u4nsCiOSkFZdjrWzWMBzuSHx4aQ5QQWwW3YXRQL8JXYGrnZrDTg/6rIuLhKEDUEXRkigOggglpSxlNkuc+iSv+TWbDw5o0WiQR479++mZC7fBsCPLeoX6TE/76ciy8c7ALoVtUX1AGHCL2UdOGOSBp8AIR6YByFwHRXZVeIq8qIewa10dMAPYmdINx/SL4T9ohK/9KckeRe+hhcIDwEwcf/0OfsfiHPA9itJpGWmZmTshC6Dcph1ZCkdEFQk4TlhyV+/cBUwTBtpLzgHKDa+4UIpaEgwyduTeoSYChAamLx6IH9hCuoGMoH5u75Afe6+vOvJA0mmJBiSvWd4/skU5hYBfA+O34kV28ySX06wviIpj8Asx9ESPwZcl0nNo1q/cikArdcpTePXMqK9JZYS7qAjSsT7Li8gGigAYEuxhWx3D9IgKDFwdr4fTwysLvrONnUSBAwSX16wR6qjUefviOKCfPz1GrdZMUPDuhf2gMYeDWYiZZ65ZBPIZkZx6vwoCeLBwrIQvClmJ0ZVCc4Xv6Kxc7ItpzvDVzAAoK5jUvhZNglQvaHIICPCjNbPbju7fpPGECdNrEWxrcii6V5yJOAIBJp7NN1j/C6J4hBwTxzwQoCrNzwwkngtYgCA67esojo6bogIw/9zzn6n0DpQXxhbhW55I8iAtTx3g9v1SmqOnV+3pjTfwQYoz/BVqvmSdOurNjgSzcjXpFn+tj1r9kWQDpOk+KZDwVOlIuwxUIg4V5WuzPiu9JyCBTATkptvo+qIZ1jQlWptrVae5Y/YnW8qObRZw1ba6z7rXSY8QGocgvSUuHps1ukhrDcYSvX9qdk6JZzIMT3sJwLt0YeaC9zfWIJrYYw5PxKAhk5IpH6Mc7FYkxMeMfeS6x4RzjDAamAmHEALgEGPExvkBTY0pvPVm376B0CwMlbCgQOenmbdzpj1Dnt6X5uxG88WkWZS1xR765Y7aQCeXoLYttxoWgZvjXG4sGslRMgmiiXISOIPH7aBQXvoUDT3Ut2QubmdcuuK1xX/kPDOMItCZfAl2O2Hc8MBTpNEu1zu8zRqjDrzNEyk4AzghDAMCaA1mfVlMg0Yn7XBeV/rWCUJjeqaXLPjCGC8es0RISJ7B/zyyEEbHI32Rh9hCHN31AR3OTLsu33OawC83AnDqo/YSP3UWrRovqbAKne59xucNCaLYBa0HXBu3TrSrVN7kHBZU+dDd6dP+6OdPNuYs9vwtoZXcop84jpMVTFLzOpBxjUAOisr2wdWgOeu2X55SnE1dmrSvfqw3It9/5hkA3XIegAHkuZnIUqYkBx0XRuEGQx4Y90qWO0tpwhss4PWk0c9G41lr53WBk9nZqVUVSXYG3BInY7XQT+GVU/HjjnNQBvxuOdEVDP1nRClwamvX7cnhGFQ0dtvWfnWWOW5GLulg9iiDWCu7MUrrkS/7lduEsGsH+cPOMm2wVlXpQB9yD0YdFSXKODSpGSAzrtgEJF6Ys1HQ6gmwgdAiULmkhmevynfd1o7oRInZ+3Ksj2iOkDkbK5ztddfAZeVOqflWb/yXUmbm6OJSpa8D+y4+AUeQ3On+HkPJbosyrR/sX4fCkIv/Wf986GUFDoOuCRT4z3ABcoHGkGrSvJFVCEREg2GvmUdPsE4lCaCxEm2l4AL1vmIVpFIp1jLpyIgeeiZyLRy6VxOt5tLs3F9lU3hulOjHbTRcliNVEkizYU8kKlf+BtiQjuN6zIgSsn7+KG9oTRIGplHmVJ3Hk+B0BK7+GwVzAoTtKhgEpA3/wAqQEJyyy9pEZaFONsv/xMHWifB7AjMT/Y4XY8QCHY82MaumFfbacsTahpbHwEFbBfB3r+tkfBsanLlgi0BILjQjJjOAbDjz16wEl2ic8fn7YDwyJDTzKB1C3d7Mz3AfnPJZlR4jHNsWVmq9/eBUo6mKPSwHQAbBlMK5wpgCx9EdCzm6aMPu4LufKw0VZosu64U5T18jq5DSW319UX7QiP/EcJpub44H2AkFFOi25Peuc1EN3BCiSiA+7H6yMxjuBCZyQouYEjRg1BLIBs+0EwUoj9xr/uQ6Oe8LlERZIaAAb4GU/AWcFsWkOSort/WT7XZRxDpUklNrb5h/YtSkXyO3nxBZcJz6MOsZPkIYVpwWJfMEcUKtFaKzIPWgX2yYxdm/NkFZVPSB8r5EA2UhnROvJmc491JFnvnL+QkxeVc80H82D3+BCd5bM4O03j6KzejrmprPSVrkuOlNRKKNSWP2LeRhJWwFc+e9ZxjizbODIcnvQ589GmlIRZIjBYV6RLKBNX8AnTaiBLvwQ+SjTpQYeBuZod3wD8Vfidw7z6U6PSeP0VIWxilgD+hy7oVa1F3lSzY8mK0dzALxAvzfWNoAIq/qKCFEILI6tvMpejUnRxs6DWbFgJqU33pTmqSRDLZYINFC6oVE1ks19nO8aNggceq/PigdcwTWG7GX4mpG4mSyhh3QzZLpPpUmc0RFqhXGCPBYMW2C/MJ+O4YScFsZSBkmU0avDDrnrDPPuKvX7/hlzAwrxRLsmDVLSf3RkcPQSKTqbZfaqSy1PZPRA4bLgExQrnp0Rl8SEDqEpwTKpCYtW4xP2QbE3vk+nfsNEtiJPRJM1nv4/1SYOw9zUD+a8P2KBQBiexYz1R0pgSlHaDkDZuSrMRBwvgORjkbP+xl0kCMhdvmQlK44i9xzDkr1rzLS/vRsHM12ANub9uBVD9mN1+0AE6IFuM0Q2A3LL3mJ0fXqa6uHbejt9i7n1DAwOEILLyyHY4zrvG3mLWYZZmKJz2qhKH38k2fRQSw5KgDZh+AKU/hYSaQYCr4gWhmdpsA1nMtlx0+EJ+8guu+GE0zLs/5pm2Z7NfvvO9RxXhiOM8AJxqxq/vP5u2TEk44XT97yfa1+6OfXLZYdiSRcQUZ5j/KDBIamA+tuaYJkWAEUNHj7lsiBUbcYWMKKIzPoSp+PBGdKwD9VBHLx+aWdDAW8JCdY0N8oRJ3iKY1Nfl9iI3SIKeirmouU3MyU0dGQx9RAiqnUHTLEAAjVbhVbLMJxEesZ9nqRcMs/WKTj5Pd1iNUfhI3L2H/b49n+4eHfDUanwOW+u0yC40wxIUHwuR2MVmhVrAMDzrHOWms9ZwAjBMY5KEDnifUhwQuWQPzsSqBZhWyDab4d5BzyZO6bX+u9U3ZvsZo0JFdc4hzu6m6kYdIVATx9QH/ChjAq4nWkkHGLPkY9ftQR+qKFZZ7XwOnh4wAg3DuORWgL8AYcKzdD6aD6VIkBdzckukAAEAASURBVAkzZnPzsH0o0gLqgkFOXvGc8W3bTNhDolsWI0EbFwf9PtsGdhS5Lz0pMmYNVS1rixGr8N2q759ehR5Dc99OcOwyCCFaGMDdYno8pNEortfT7A8lDX4rxZfkhfEa8LknGehI8Axt6YhFxgT7DWLNhOFV6Iq5o/hk1NhiGcTMcQE5GvuX/HDhA8mPMNwjagedWC0iDWsgRBBm1CswGjt5ZC9YzKnJR2R6xn21IYCRxN48S6POKUAK2zBqhJI0dMs+inm6z06h5RynkVTefG1xJiIGeIfq4c4BiAeEGOQk6rYBkYGevP9zTxjA+JRU/jmlfk9vvt1MEBL/4PgJlYD4oQ78AyQmlfoVP5LEbvfQz3S9pK/Laqg37ApNpAMKRBzmTtdnM32JZr8Yk1nl9OTGCZzKCpsHq4VEoBopz+jDEi1O57Aw9PhOyIrX4RqACk9LvzXrks8FnuIKOg+/40rwUeoW8APDiqX0AB6J/v7/4w94k8UUTWGVqdah16TQ3DqvkUsWGguuSrBD1Mj0TY/v+mG3/c7j/hrC4a9/bEcOe/qVs76wHCEMEEjPGvImNj4Fv5CEBigZeAISK67QS9R5SAaWct3CulPhfPdVtLDnck+mTRuShYFjPLpTM9ZCVRBiJU5dzdAoEqYqo7BwM4fAOIbAAbYMGh7e1ubOqEjkPIFIwNioL2ZuZXM86Zpus/5kKCA3kGOvMyrqGe1jEuM/xcMgXeYHpeib/nRArmmoXoMGrQKDoGlpWW1y5hMEQEWBurBqQGwoGdzSwHcIfIsKvyae7Epxg6RYFWJVLftX3elWsEt9hGOP8aZND4UPa4E3mAEeidmWFqpIabj0lsL3R9SZ2vKh1/3KW0dRdxO8bkc/1AWWBIL8R+UB6D6GsJcbPb08sdnSgHGyuVHol4xjEoES6kBmhlzR2i+Lx1AiKFi6BuDV+uRSyfD1jqQsGhWqJ5UtfFrJB/uDOqMabxCGgQDo1jfcf6BVCYL0Xj+BwYchBbCEDjuAcYUw98L2Nbjat1XMwRxf2vRkpV/gXKUtegDSRcm/R1OcPcLEV9qKL62pE2lPjviBTjX0ugonCAc6DBKT/LWEyqRHc5HYpqdGrEs0x34VsFMwH1nmjmkCe4/SnxBfjmHlBp9qYMheGLXPdEZUwqgJxvozIqxH8W3ILJqtLfWmYeRdQl3Iyj/WamNK766z/Wy9KKqKs9kogn4nCoLCtIox2yY9k5Xt6/WfJabOC7D6Ao9S+6KYf4J5IbwdsRSzSZvBZwvZNJ4xqHQaDgw7H4gM99X6pG1l8kguvDjf3VECEeeqY8VbMSpKIRIg1hj5DPBDbsL+SsKxI2GjO/ZktSMW4FWsTCxCoD7To5uOS1rj0C5Mut4K82OY1OxmsVvcVZBm12d83zPG4wH6Cq7ulFwvL3L0qh98Tnxw1Y8tClY+ZjctaPI3rA+PiL0cWcxT4Zegl3NmOQQZ4IwyBHWXRCoOHrL+FgEAkpgjiy418kSbhGiCZF7011nsV+mRD/lCOCtt6P0Q1Ym1TZ6RG1Ev42M310f646lDfjZxkBHYyqnzvo9LcMWxp/G1Ll7ywrGzW1qtg8Yw4DHnlvor43ZEVMhXnm6zMlUbQ4Td57BxCSgH8JS6FiJPFe+IQgLVBYcqJz81PUsYh0DTUzuXnEVef2WbOTFGFgEmzfAM8Z3y1HD2d8lh/SuCGUi40QOPhNUR4AHyflpCkARuFZUHWLW4Z8y98cAIrO8CXYELOOoErGKFD4sp8L6QlWH2Dz+BhfX/67CX8MVUN9z5frVfuay8Cm2IExszfbK3WeniLOMosPhgNH1XUWCpnKay6K9ABoiznmlrE23wiW89Y5+VUsclfnXAWkVOVBjyhjzwJIGwm0XoF9Q5xBMGRHBxf/pT9xIDOTGRBdcHdHEH4r90Oxp8QabDv+NiiqaYIySsK0PZlDErW+NnRAJrI8Ye8adveJoFVM2JiBjAIfwC8lta/BGFs9K6vd3T+Nsnb/hGKV8W3WZMua+LKwVQGRo1S4MZdtm0A6UejxqOAaW/7oigbvhoy/Uc4gLAe0Gm9eutAwXWib8kAkDcX9QsFuYOQKAp2ZxKcMAY7NiMXOL2Zj/zZJ2nog2QQM0JxgbgCDh3otcKhQesKAo+AwdSbIH1zHmVAPqX/fppDZ8D2vA2F6xCJNQjJS3h5MOT9RhY266zAXGDUu//3BsGEMnQ5HsMEALdJ/nkkxsIy3uxIaA09b+vCh7QMdxhVxVCCgmC/S5chGGnohD7AMRD/gXO3lALMWKOJqPy9iquLNAtGg/+foOFF6iL91Sqinu7PxROA4EymYlQfWgszUdaB3ZDYqFcyAl/AfgeMSX4uRfMJPO+o7+osHf9W2AVTQ0EGgv9AqsiXsK30JmghW4Kwpz7sLAEg7XXe1T86HgUnc5IZUtTpCJPHPPNYMNoF1Jxfcy2FfHOh1AfzBRdAoNISLb1qrTdMgZGZ3w96kthkwyh/eFksBZmNwqUiSzEF4DS2b8V7evDECFOVFCRGalb6awtDqOS5EPup6VVHvAe6391DL0QBlVx/xjlv9QbDSLTLtRNiRfse64icluSREWgOLLuSBisIk+OTUEBGvVG+kGWoAXgXfAW0NigIX5oRsrcmQjsBZqhFRD8Sb0C0QYjSldv8wfJ/WN2PBIDMND53V77ZMyLYoLo5LyrXQACBmdjSaeaNFXlWE6A82OxASIVuWbP37SC/Mi/BQNXkxwHU/PKecw5f8mHXd6ECMlJfoAE+DmL7EAUJOxjrJcGy+YjpxhIV65sB91HX91RkcMjduqSFWdbKxSGztIelZ2ejOZXbyoNQT6KlZJn06gl9RTUqGQ0oaJcD/aHptCnb8BD4KD5JCs92BokS5dJm7x4y7+vXrKOOs+FRdXGvoJ5boUApbvs6owfBA4wlHJj2R5Ta9iCk3+4MRli17kF+ymzlnoFVoE3Zqb8FYzjkQWXC+EYB0gfMVHoTzyoqRQuSkTrJul7ZnVegCrpRXapXrbvjnu6fdrWMNln7KoMmkfZKn04Wg+DdV6TsGev+yIlAJLFgPtMrafxx9mcmlYA8PbXT1kK56tC45pjxQTcHfP0a0zd5thP1SJo5aMZtqfdVsXJREmdYY8Bz+U7jxeUWCHGt6pXvMu+OmZfEvPD25xPF3wJAqhoIN/crbcuMBpE0KDqRvSzf7TeH7DQgiAoFkCH08NubtmnIVPRaW2dT60gg3rinnNvlr1ww36ihhPcxZ48hM4DNyQ7/uWM/SMUIwS3ai+ynEzIryyw/7AU3WfM/ifSWz1iUIL31pbshhQadYdMb+IQilSRPjS/vtxLQ1gz+RZMNwTIcRazYaTKrCcwqZmYTMkIxNzSgp+VMdTvbxVxFNW6XVSXVWZaVXFkIsyy32im73rXXOnZYjmWM+05AQQ3NMZ4G/CBBt/JDVM4LuQX5Lprejjmj6AlGoJ/iA8G0Js5WbZ3nx5te+xrmJXdt8/2ar/HftUHwsNLqarybFi6UBdjacBrc7Y7zel5A3ZkX7gb7rXOCyf9k3aG1YkZ9pjIJhazx49G8XUhpAF/EgA5ew+kpmVnBC92c3z2xo2dUo4dwCrK9A8xegcQc0gvnz9v48hFjSLjjZchPsUUqKXcDNtQp1MgpNur6u1MerXZ+B7AbeYslCuLPvUEsL0sm0bGhHyYFGxMELiIVoF4lnwadkJ0cqTNe/D3m/3+6BX7XwbtQ8kx7Dr8q2J7SR9i4vTAmn2XXjf7PfalKLPzA/a6qOthEUO5PsRR3WxlxsjLC9Jah3bsiYeiXfhRgUyNZnkBzndgL43t16X3TrS5H0goJoCOp2vCvBA9RetwfthlGGird9EfVpUcZfOPEmOzrCyR0PKq77Q+Ivz8Wb9vCg+tAu0aopuYi+YqcfDgsmJ1H0dUt7dGhgW+H+yGNRBWeA/EndLoDoAQ+adLnWgj93uX3R60ppg/YvhmdSNyexAXNxetbdHO6MPtVe5MBi+RjbnZMicxE81v75c6pGsAPKL5tUj6Q8hdMgjOqTdZx0U11S12dc3a2G1f6pkD01mZxjgFlANAQlhO3XFPMxiJU02IF4sigBUnscgcYRpwiUNv/IYbJUT/s3Rzjy6xMKZx2tUxDYSCF1ij5J7PIhKBDKuKvCsll/TG+z/3hAEoTdR9T5nfrUxISvotmIkQiEjmrcu+Y3/wOoL6+8SjirWLOLkh274oAsDshsXF5U6Z/4Z1oYziqWxoB17pUPpHWkN4TmnYkfyxpEVLnjuA3QN5SpbfuXffCeqIewlQH2qOcBLJRx4INwHUO3iggWIXN2GR9yJwPX7AP8F0gXWwm991uLsV0pBuWENyZ/Slp4ScwSTywQA6+gvSiUgMgsQ4hCpY0ozRoP66ZIVsb/lmuYg4oL3NYjHf4vXaVb/E3WIUGKUAEKmOwBxXDdhtq4W9u5JW7A80CSOB7YbHDxhUXbYvS6nhRj3xcDRsRNg8agIBCEyMJSoOl7gsDkJtfHzy2mRxllMxchhTh+oBhPqzEuSZ63aRnlYnQnKIMqCA6CRWGnPUkChgdMq/MijywnlAM/Z4Lo8YhJa5E4iBm6Brrx7xBV4dSXqnaHu6LJD3Q3JCPqBs583iSryTH/oCjH1HRTyyY081R2He2Hj1qh5PIOzXFYAApwB0DuzDqmmAYW5QEVQkCIHhg3vMI3i/hpB+z+Vj/WVkTq7gomlvAtgCQcCDnFdkxZGZYT6mHzEPAJQLdIJ25ggZIBhR3ARYa/3ko3a125fQA5TDtwo96bjiHm0BEAUDzGitRWde0W+Qa2BYvv7eAPUNX7z7cyANEGrvvv1g0/fnbnEMItgHsOSgag5rD1tBEHyLac72DwAH17ZB4uK8mhUbwxvJtW+L0veyBoPBCbEKcTswVTq9IYt8WgOuWSqhFHs3SQddmr/qjbsjBDAJwPaGm+p7xncxyyokXwnkg3OwR9nuDCjO9RizP4aI2MyAlbtsewheRRZMuLH848Tj/ogjIJAyDBIAJ0d8CQQ+TNg2hyN3uR/cmyONvuDkkdDwTWuu8QVOPbJiNtlsDeGuEljKcvG2R1X9udTdH0zZk+XR3prZGrEukn5DeCH9qFqDf9btJE4c+pkexXSHaSIAPGO+L845sQLVGoGmvQB2M1Yd/u0HYn65K8dShyK1x5cpnM8BfVJsnesWFx7i27710G/oES7Tl5N7MEwu2KFMD9+aUbW7l+wQ8XLyGdgUAbQ1IlIlH8E6Yi7ELOG84UWzOwJAnzItzuTPDX2oF295xzYlHDmriu5mPjNMT/GFOB0tPmNRSkWRD9ID2N/I1qZtuyqsUv8i9q0WbfIVdqfYzzdg2pbo62wuAjw76AeLhcF7r4zC/CAqgEqiVMLqJpDGlGZY7cOjeNwz4L0A7OZP3Z6o8DQHOn3/gh1RuolOyfbjp1YRzEiWEZ/TYHt0YIgVxjQ503JUJaxzJjfYXx5AQrGQ9MgRT8dillZX7XYx3iHK/so6tvuYSkO5xDRoxH0cKrJwngkzigCLbZg1CiIVZ+BMvx3mnFwpLdxOZs/y9dFclrpp9R2voIRa2Nouw/dvBKj28pRlKI04pig8T+bigGt9vsUfK5qAJY5x67fWWk/vFNjBBTfKA9n4QQuZFlN9XDWu23ml2bahjhhdcCtigBsusmZP7DaxZi+ifQnZFQmhTcs0yELhF/rcrGfzDOCzNT5ZR0A/Oz0CuCXL0/YjUdpHNt3dCmoYaU6f0t6wtRHamlbUifu+MWb/uNay2K5dJASBsAFpOIWZRVz0T4cwzJnLH111FpsUfbJLFRstbindWeeTkx3tXgGiXOg70MtAHfCDPj/A4IsNnk7hILtyW1+0y5ejS7aTCTTDFGscy0MVGErYhxhBWPYT7QDCEakP7wIQBqsBGXP5L9b9kn0FbmoPEtJkKOXASuGKvGwVyGTCirBKL4DRUn/DV6tyyAwnVQDsF5pBKOCabzQPbFMCUbVCPuS0QBcXWlwNbCq3PtaqqXr4WmjruL/h0oYYURbmnRBtZKfYS2w5o4/C42nrNizNw17/cBBJgrEBxkfeh/vCAPLs/nTqfZX+KzLT81DZ/fbVnfyDEIAUbthBFOFKwNjjKBJsYoKF2D1F3z0FFSVczzbrEiotSJqwD+l1MYFXg1dBguSlsiZ/0PxLyfQ7+RsKQSxR1TcUKOr2yXa+LrkVfUdK9Z18877fFQPd91v39YKknfcIvX9Mb7aneTgxUkVi3s6aNWGOq6cz2duWPcy0wpy8YbkEu+8CqEgmkTCuAEwLBi6xMfoX/RJ5w78PSjhwCt8Pp2yvhHmLXPTC5CwKahNR0+tvuOBtI6SZj0p2oRwZvSLwDKgo96XdTzzh6ULO+sWQJ4ZQa/FXrg1M9WxMqnBeQdmh4wA2vqOq2G7BvET5Mv2ObARml+ylbft0oZ+eCpCf8sLqdNYp4BxekxV60x86qBE+/6m3/Q5UCg5BV7FfuUvAZaXSIIbLRqVp3ZAS7+RnTMNqgT7RdOUF1ss3mInSiVW3VfSHZAYXJcfi0dfYsezxCPz+giSz2oDZgGOJ3rmitw6oZOk0H1j8jNye63p0Nwvoxs/90EWBSQ/KwmTxCNBV68o3AJRA36F/w/Lmv7nqW1J9XkhBixFZw1D1X2EHaOwDegnvgXXEYEiDarQ9W1IjE4ABKTiZb7p+T36kgd+TL73VR+5PNUxMRVYd/AndsL3BdfwkiJXdCGRGkK4rsplJPygTYBEF5uO3Z+0JWQYZHELHKJpI4LfZcrDO+RxgIvsxwg5hYFl87FyMsGgTT2AMYeUMa9qanB9jLLncwhnKF2fdMWA3TOCr2/Z7mTZJDJjeus7eShx37U/cBGyHR1nKOe6XmStWUWhXuj0NJTG7HTayPFRrVQX23W7rkpicY++HxsjFx7vLzPWtYABsROybkxyiKlnAHYipptwf4TCwyTh7x1XpUcqwbU9FZ4yyx2ARQWKqasqcn2UEBYjXLJOFHExQSCDuJfCvOjI6mRbAZ8jKsV+HcsGk9jZkQg+A+tnCYXDIHhb2ME/hZJQfwB4+xPVdVrpDQ1xoI3oB6Mzz43rL9aE/GrU/yLQ+1YeN1Lpq7HkmT/QWk5OvLlqJ+oj30FuUfFFCkAyzO3a+z/OlJNzsDmxDZ2H5UdvnVcIJpBirQVQcsdoIuZ4+e0H2Xz01lG4gI+b71kC03TDD8DSqpsTWR7wIgi3xc5h2AHCTmNtsa/E0n8AJicdd/gKf2u87JmVKRoAEFoadHIz27sOMRviG4R9+Dx6MhgmQUIwU/NFl+7zEHhFc+Ww0MuqljWB96nw20u01/iEESrBoy7K8Go1IZWz0KZ+7Y56nb9gvD+8xJspCdATuFh8KSgIHL21iev/h9EntOgI29uUbe+8C1AEVg1YD8AnJiRYkJAxYWbS86mjy51yvlTCJsRntjkicIY5T/w3PRpQg7ivSDWClDdtAfSTFF8IB+aXWnhuVQKDFhZt2oM0uiCBwif9iwb6ifgHbzL2EmRxWCZ7IsR+PO28CkDcfiikbbjB7Lf6a7hfplF6WWfaJNp6XgAaZwCL7pPMHx8OvXH1RvRBfl7rma6b1ht/Zv8efQ9sAeCAU8/MQBDPDac7mocdbWUZMbHCFFYutECZEYsZEDEwzUjeehgBg9h7snXTXBYC+cDWjlWCs8cPNWLU2MQgDHGML9pmHPBsBuhAbbiTAodgDcfdFf3TVLz972EcuwgAe2cA8BBAm4uD6mrroKLlNFoalWUGZv7K8bcXsot5rXeq+56fstjY45VGc0VnGpIi3VONhdjoflgQojaEBpuKB9GzL2vBTyyX53FRFlxXqonfdN93KVlUHiJJHp264yAWgROapcI0AJrTZ8jE/z47V+CXs9ieT9rQ+emnD+xThAJCXSbkqNlxRzbuHPVywX0QIIRVsWINwBecyCk4/ckg0MKRfT70P94YBiFGq795yv0u56Nx30lEwCxYbElF84BTI9pVXpNmLtnyPu37Vs0vS+3tJyx7N0iY7j4cQKRQXLCrUAQZ3X1LO391E8oji7r5332mcgqB3IGS+hVXH5wAYBLqVaHFbApAyUeq9/QEz7w0Eji8Q8vdLDBL5PyG3R7LTPl5oTewlmOnV8YFyVr2OWKHUASuQGR7KFNejIjnVPagDshGf/+9uWTghmnUHHQVRoAFLeVs4O0dt60zzkXQE0f/H3nsA952e950PeidANKLjD4AEC8BOLskt3KrValVsyXJLnLPnbOcS301u5uZmcpObG8/dZeZmzpfkLpmLHceZnGPFkktUs2qr7bvcyrLsBQTRCBAECBC9A/d5vs/vv5Y2W0BJlCzNPoP541ff31ue/j7v86oAHxG+H53fL+cOEiGW/yGLseX864iMGtu/32UrkNczWzB1oWJvow1e99ONBU27CyZ7JzimJlQpXLSEgXRddexq5Iasa+wuODNwUlu6Y3qhSQIII0TeVQlZHGc355IIAhDj+6FE9Yyqgjy9ioc8pido2ptKGsEZ7eLFIV1H7UJwnfv+Uu78GLZAH7TqRVxatA5HJJCp8MgmXUdzvJ/qEfgj0xebitCDvye6qs3zWT5i7AFEJBIcneTTjD0R8t1eiFQkz9CDIgBdBI0wKIiADwBVwbkHEmzvZn9w7x5XZRFSQEuL6yeIyBff8NNfvM8V2iHRFcozK1NwjGaJ9TAgvB2yZlSlqaZeMTDheLp6V9UJPzoT8NrcOQTqSlG685d/HG9ImK+7oA1kpBBVd4051eVlJfYSmSpYuhcaJIs9mghtUpuKcBJX2i9WWqMG7+pVOzXnoZwAiuzQUKJgodkw2KAjKjhQQRa1YtsmBORzaNKpHFsSTyVEDVoNHaiGratIlSZW8tkpq2FxPItBh70EsJbsGkwuOZDGbdnTcJUJNVkB9coNa4ExwyCw5YYsB4zg04Tr5No+woGc3n35U+Y1q6/1Y7zgBAoSmwSUsMeOVPZ6P3NqbNqYJF4DQZs3yTGvOvzBou1YtUPCRbKm9rFRtzgTS1a4RnQi6QEBws2QDaHWbCQrNLuXihOgtcNomGeI5BakVj/U4FP5AFRH1u9PdvgSeYAtiUltT+YJAB2aagaiQwCwEjo2xpgdTmlopBkjMcb/M2+/xhOa04B5sSP7636m6UdtJqYzp9sNmVYpoqReXTg/0BwlyeiBlMQa+iuLZFi29Ih6kokavlus8aJkLI2yEjsh4U2vd2p0KAHLrWLWKsVKUPHfmLBPs3svpImoHvLdn1k4BBDoxVIZDC3grbd8EeB+AhKEhCvjtqEumXPAH0PnoIAyGQLAzuDXXVSXAQKRMtxIA746Y/9Nq92X4zFgQP6cPch+xOog4gYrahM+DrtB+0cgxVwZ+Eky8R1Cho4ZT0qZl2+VGibmrjAMqD+AKwjGBB8Ezp+3Xbvmu89k1B9u4DSbdk5Ojo643oJgo/xXX/XHcA4xynwlqo1/kZZGCR0p1024nie0wTuIkRaTgejOMOvgWTSuINO+uerTPgAU8dJFu3+rH3f3OM7DENkuD6DkBweSmS63H2oSO5OOYpHhE8RYSgqenLK8DE9oCazp7wFwCK59y9jA+vZquCzdbOYvlHJQ7jIbUhdZHujCkI25QdiS8uPnzlobCX41fBjJdBFyFwEMsGKKEAUSHgL0wBeP22/d58dEKdAnSNxRMW9EDi6MGPHP1nrwoUfNUTP4T46VZCW4wYIoPLI5GlbMZpChEHErLvTvzf5RerNv+AApVVolmqprMmtrViG3X33IS5tmSV6RZUuFgfrA6n9+1n6n2W+RZhCH65qogKBldq3YrpYi3ZlV2781iYImDpkUkcSpA2RnxQqqSacwnZ6yFohRbJDWwf3oCoDFZsyv0vHqBtdrwXqMIoANjjEUo+FZrFxnxn7Z2kUg1IQYUdASwFnTg6F+0zrVWGQwvUSed4DN3+npVj90Zwpu1I9VJHoPRiPaagDEhEcDLQT4o2X73RyfzQ6ZJByPpz76XVcPoCaJSTuTvyNggICwHO7oxR/lYSl1jiQc7Mq1evEUQjmQBdUSLqAYylW0BeREot4jFOWjz4oKa/T5fllrIj5X9+kBvf3uqsEmoYC5d1++s3MwUxTmPAD8RBxJhjjtNOqU4iAomgLDhjUBP+IXVcYd/Nzp0N9B0T/4qMSgr4GBaWRo7HCMvibjWSzEE1NtqEnMG1gicWvl2ckukSysQgpc7fIScTqjU6GeAX+4YP8jPrvFJDCbOMNHFz0wD4DdRVdzzL7zTM5wGo2lhxH6Yk7Oyvg6VcrUPdQ8VPNQXWB6uNhCw7nes9RZPDF7eqHwvr0UmFVZWYQaMf48x3vvycnPWz3xhr+P1ID9NiQs3xE1IzMxBraDTmvuE8fZBMAS8aOxwBhYYCk4+PGDgNUE0GlgRXTdKbnLQfJG3UIR2JJGJxC13py1ArxI03hMEikhcN25gx86ZKcMUd5BRMLYG8T0uyadAMFkAFEP+bC9ZKY0CnLtYvoSMA/w/B9dsX+iAWAtCXyejh1ThSABiIJ3gQOq5LD8j5x+qH6vgfUOoQIvQsYs1zzkmHDvw9TXiptLNtTMbSjL+IUnXWOeuOWTcuQqA9BAwIfnrljkvdxI6Cbmrt9x6uPl3TrOEDLs06QrF3iAb/20QObFT+vj/t0PHY4fqFwXeQW9231iF40TdeeMOFmz2FyPOrKM/OxkrdF7LADAVoHYQmVMpey3SDIjrK8scY0q9CE2acWvjHMikrDjR2eSB9UTOHnSbpGKutgOQnBodUPWxWyVeMmMAnxjJyKSX8M72BeV0QX4HZmwFamMVQW+KHxvabJaBmP9gRb3HwCEFT3DKhr1AW48TlnHeUMIyNe+OGd/V9hMlCAbFuEbBlgbtpHNebH7VcKmTP9WucgG04KJchSp0JCO4NhOh+FRXxS8pWCBa45wOMXVkZ6mDHsrhuGNBZtl3159iOZgvtJFsbIotcHDwCLBAwo0rW4sT/QtEgQVkfP9nFcPtQweQbAZ8PKqu2TYcZiIPj/Vso3gMpDVY2h4QaD4qAi2TCegg7QfF3/hFWp4BsUxyw6JG90c8vWawcRoGhpdvfrqi1DUsj0x7eINOGGWgmsIMfqHbceSb6P8Md1CR6WrNLCu/5HkChUZYBsKJgHQuVmZA6BWtpQkVgdLqlpaEkseY6ZzxhrSW07Tz+BMBBmjwWOYZWcla0m//bSL2JjrCIuFNgKVt900qs0wHHVAKTtCDCXzY9UbfeD4BICKz9/xy7Yf7stjpbY0mUyptTf6/P5zA3ZAaIwZ2bGQTKO93WMtk76RCPDYp/JL2PFqdS2vrcnPMYNmNmx+wjEyb3Tg2oV5GgVgb1y67Hp8KN9M74BC+K4AZqtoGgiwXbREenHMzvARIoHoqyKp1N4DhNQys1/lb8EEN5FCJjC/yvMrMF0TXUR4xoGmxJ7k4tBYEhRexKLnUTcCCTYDbrELM+gqROFDRNuThRJg5hn2yoo7eiaADjirI/rsySJL1SRkTkQl6dT5HHCw3W5eT2aTiMNkC5eJxYQSqXllRRK3wAwh++MFbnGMJQbfoO0AogXj53ifH7PWiBAXwlMx54BeQh3K7Yoeq2ZlNna+iAp0wsMCbo5L3n+23H0xWaIxGBG6xYZSp5CF+dV6smXc9gzywEiWo1zMZ54+7ZVsnErWf4JC2PPYpQDNr00vNyDElNHB44hxDlAMpFYnxRniffGG7QWjdPoyG8KSEVRd14R4pK0iJPgJ4wZFsH8osHfFFyRED8NUoXSwGiADKnODvbiNRDygAbaTMMiQrFzLJOZT+NCJx7fELwIMEFVu0ysU3zjtwjv2eEAngabhGwArJy/D0FS3+/FW5tq5pWRlKZuzfwR31APwMzHFO3rJHxaRuafs+9WRiTsu5s5eCKN6QS7nTWXWnO+v9/TZYXYuEUIOzbjpJd7pNUSRgvL4BaD6l6XecQyagUJDug4Jvl8PIOtCfOjBH/KHQiRbnHCoGMTEAYBIAlvpf0BC1fE/8HdS2qcoSbd/Ln5oXSgU9HYr3Ew9i/hGekDa4lUuYeEzwbhQwyZgnkXJLlV/9bIn10mp7+B7mFvhxU5N2HiGlcoHRD+R5XhoOtFP6GEkLPHSALIAXncsjQAVuIfS494prfqm+pwnz8zYx0YTaX72srWSHpnqUskjDQWt1Wt4jkPgMeM/PVXw2H3cyhwauH6sLzQfVH82rQG1KB9oIoPuit0vZsW+IJUFHudPUAmAxMEdydYXgK8jmLMuqii2DAKAlugeAHfoOmG3L3kCVbrlBYgnd6R7tVd2S79e4eeCHA2B2JT2QwCk3Za25dhC+ha2q3TIbfJiS9P0ZjbQyfB2NZC1LTj6Q+hfnnfXMGIFuHLF993B3OqXKEGyQcjPqE70D5RI6zRK1qOLH/rDR0GfdnUQQn/HDsvCR045c3PlTcVYhylQCqVOyi0PAPiLUZYyZ9z5CJCpLnMumflEDvJycAOO23OtodwG1EK+AGL8tCCG76f1db6rnlv39z9Brv0Vf3ppxlPMfXnQdmj46Ul4GRkRAOR9nhCa47fmfMvRx8ipBUeHIW6yo632bTCXx+Z8vogJCmBZ+wiNTdmKmOUkmd+x70UQgxNWSnL2CbsPgmZqpdnWeozc0ADrI2+MJ3Mgzdl2RTGHzH0DKZa5DyWbeuH1aVH4aYKpvXbvgWQ6gkmGQ2zaID5FuBGqKop1bHT7YIXtZg9laTBUbJpFFKoPa3uYQbow4bNSADUB+YrF21DIKOHShHvcge3sc1XmTQPmxgx1MLzR0Oo1NEVyjfgdG111i0hV8C0g8knvLvURFnTxkivKoXuhLy4v2RWhLFMKpQs2eDqR0F9a8fxRW1Sf8iqrYsNiEWHDjG3O922v2AYXYCfW7Dl7DtaitZgDsCGRNFZrLkGP4tHc6hLh6Y6P4335xqo5IsoANsb4+JJlw7eYQCMTIHEL/X6MfYhUw1+uO3aoCiq1AQ0lcYwkPCCtYpFwg4Y/7W84UCk075j9g0fks2Cvx7ZJN2UqCIQJI4GwLubNokUo6PNj1k16Q/XqRKZnYH/wHi8NUfG9S5bKTKzT/Xvt0pVk5h2tnaFPRA4TiQOucH+i3t8iwzhTVWHy8QAmbkyj4QUgPqGyJtldjbC3rpvJuPAhwg7vqbdGIWRzu2UsuLkCtNV6goGY7t94TzMd+S9/v/eXPnOWW/VPdBIAGi2yoob5E13kWg2AKLCimSUDvtVnu7UDAccscOrp8eZEdCIGEtUIZKBFYGn4C9lK4XszRmLZFiEhk2AsvopW4CYYlmcxks4zLzQ1nWwR3lRr5aC0erujzdV6vhWBwewEzZ4KQSxk5WVVT0zDkuuZsD0iEiN479a4+0rur/NqF+fY3KTbWmEtY7XSS1HVTfgv+pOhTKHfs8sc6Q17/C1U/41lSdf9wS37t+3JpBOjfPKE+/8weADcLgxQrDHoXrDdzTY+YvmyE1hKOjBmt8SCWMxdwiaMQkEkU4oXJXgooWDauU0TA0KYTbfHQmwlMyDxITucz+ATFTtxu66Y/QzEknft9uPPMosoNB66YS8O2MfavATwhDxdEUHBwktw5qWXk9DZqkxPTRHSiCFAqHN8UTSLYjQF4Qtv/7cBKyQRiygC8YP4x2sTKQez5t0vSOgyUDLpWeAa1MN9N33ganMT67SLJe9pJfhjW6y00NPbsAIQeHPQziH2VPgmEXWFmAs4UDHte7IV6xTxjFoPtwFgclBfbH+MdIQqN6cL/+N5+8f+yEew3h6AlYn72tB630ieCx2uUYzx9B2++0M/LtJxSqHawSEpqpuIJiWe5RhsRDcGRYFeHSDchJLuXKClIBJAYyGUoCNkQbRFd979Iwp498U7PReNuvi7IrUylBhqRXOoPAD6U5m+dLl8NF5JX/h5+A/N8gfA2MpkTnDMSDEol9Jm7fFZ295vj8m84e63btiBLBd/wNFOG+pPItXxbcH3YOBAC2xqyppK7FOgBSKSzVFgO2N+XIjak50IF6RSA5o0mcaEQyQAY9DDU8BwINzvB3PK/a0Dm7x6aEcAkY1EhlemvOic/ZuRE7//e2/9r78nWvn4E4j5TJJQA01NGcd6Y0U0jBTmSYHio/YN9A35+nlqT7UNDfiiDwKOABg7IjKC6q/NWu5KggAMfWCpGuGe5XqhCq/QgRRLf4C0ABgOE42HQScYeLuuww/h/dc008sFmPYHYLjeePcPRfHHVzapT3CuEVQF0wbKaSAOdL1B51drKK/qdJ4JALZ8VA+/smL/c1kixVAFcQiSN8tNItWZklSY62875RChmQAPRKt19r4/Z5Q/kLx0AJGf3T32sU94E5u2FSIjb48uhz6A1oGjP4737XMTGvXy9Dl/6wYp0CRzOWYI6cloEcjJdhGvsx+JP+U9QJ9HD+vCT+KnQ98dT1vs6+mQu1QtIfe6yx4dSGYPSDyNS34XbnX1Ik76mrTzgAGG2ullAHcsKtM7uleQNHvvANcXLI+4KVE4Q0W+sutsXi4cYTaGHR5u+lO2gYR+2Va65BF0ALop2j8zxQCIhTqYOeLHBBmS1o/c1tEe9lBCBYzxJjapvd2nQWJVBpu9Up8Ll/2tS6v2RCrxZ1cSnDNn5NFubPBbsB5I9+WX/RgWg7nVJYb9IBFrrMPJsp4Jv0WreTISbWOIcgwb8rQccHyWsxOkV+XHi3x9yokKgCGiWkPwso98SgGNrQUq13QwamQ4dVCOqSelRZgZnhsWCN2E4hVDvJ1FcZEanudXfGHiMcQgMYpjPmtE5lbg/mYbHbTMNd/PCqhlpnHKOQsA0oPx9CRA7NPzs84Q9/uZG4FE8cHggDcX7eNF7lyJlAMEmYys2SENLZbqwi17TR8Cj58goQVu9U3+Vi7dO56smmV4WR+yn1yF4mc3p52ba/R8fMk3HYRHIizcZhlkSANdNG8Oqqz5ob12wfa3uZYMlJX6brNDC7ase2DaXKZnFARysu36bZ+dJ4oPYHqksS4xJ0BUxEl0I9p/Kbv43UiMoi0pt4evqXDY+rEL9kCnv07x/3TQ/tWmhLMww/PNFfufxCjdIMeY7LNSodrlUXv8gGc+BB55xG2MCAUkxeHsxNKnH1quiMT5xE8wvYJ2D8zNszaYrBgAMzkwL4xJJoSBzcU2MZN4s2BtWLAIklde8VtjZGjUrCbHFydt66rn/AQmBl1dZvgy1K3MceXlOscEyKyA5cPwUX8A6UXlo4cHBj2fexhyGG84Pon5bEBJQZeq9iQxoyK/SH6Yv+LXmfVlNzxs7Al9iNTqTKOxUBOAsl5c8PlSqAw4ecN3PyMwBMAkq1TsHMesP+RDBeP2HAyCMdrspm9Yhr9eZX961v5P+CKPkUFH03ek4wN4gLjHSI2Vy6o5tpVjwlYsk+STiEd905VFvs6eYwDERAc8lm8H0BZhskpqzCwW0NXlvtVTp/x4a7ubrF992lIIcyR6pa/sAvEAkIRxbE3Zl7/hp7WVVpben+1NQovTiVIhVaYllxZdhwA2p+w/dtshkRu9/V1eZA9r0VK/dJED/pTlyjGMiQXg6/mi2WfhaeIAF1Zt76J1C006tM9BLE0kFVCPlshmQGxoLVU2PuoUBxBl3bLZsSg4JMN0Cdbqd1xX4CPX4DjYloV+vIKm4meuRsOGh9R3MLHhtP5RIf8OOXJivcdnkI0fwZ30ANwo9J47eSlZaMErcHH4igb2jgr4IR+O4YVtt8ulhTsGONzsSPK2KgF/hmMLVV1f5ACu09LgjzFzQqTAa0N+DIPhcQl2P73bIE7sttZmETvqL5BiglqnOvMfJKyoKvl95/rPxwEkLMq2HhmTcBgA3nNd1C15YvvxgS4njjmYKhvVzGR6AAXQSt4pNqZHXVDsBfoGegjg0xREfRPDJgG3dbO7iUNEEmPMvPd+CV/Cj//a7LeJKBPDBAFgySkvwIURA/R1s98TOlGBpu1JQOOeXc6lc9hZFUAKTkz8+ufYFqPVT6kKvD7ckLOz/f1J3bDTiKmhpUI017i6WD2okskPjPhmRuvlt7wAshnBvQm8Ai6vOosLPOHFkBFiq36Rz7/tTzneQnGoT2q640+l/rjVJwMpXoE9oseBZmLzrljmCdlUxrp+IA2agKKxUTW/mmEPNiSWIblkKTbGCyKCtpBUGiLbuuw6qlRID+J9qsc6pZ/QTLd5SOuvjw+oYnU6ptU8z9Cd1alk9YfXEDJnGENDvtJr+3baidec/pva15ZvT37ta8mqH3SSLZI13MK1iqRuZGvQk17+TVmMdBowqQoEVRbTk6T7XnCsANq1/zuVBKLJOry7PzCBbUJLmgmAqD8tEEmt++MoTz09/jQTPqyPZ3PbmLFhgEkXAQUCJKQGoUFHANRpyZLKBRbLf/bC27az0Y9RCjPIz67xgeTzMb3SVi8OexLlxZCAiJAhyTNCaVgjqA8DAz6KusZmSggJoS+JBCEJJnPGxIFweEN15DMA/vmo/fsdjhnhyycBHTpWKLsERmI2hIwhH+C1GaucSfRybC2sna1bvQSUaZSuGrWObODszcqyMXwSAEk+/nDCtokowZ4DzAIXJTYkKzcujtv9SCcYway9kiablDwlIF9QApQDk1GDnI/QN3uEmKwI4joqVKwLop7AdrWIDBzQ7a4Mq6z2i3VDTmAsnQfYIxWEjtyP+FFqK/z1mGdgArpnJiHjVuEc4hMgreJOzJ5534IQwF1BHCB+dGBvsY8vWp362NV9wqiYdgCYPCQer06stlYWNcGNEeLlfqxl26b+8R8ym6eX2LFoCv4YWv4x5U1R99jbi57Wn3qS7gLAKqFbhm/4cXu9a6JZKo1AL6ZlMtM52Qg6pdrXYTYIj1Z7uNUqCt3GAK5e9c3sIzUFJgc2Rqize/f4K6jC0Qp4FpFvAdhjuwodT4AvXLLfrPdFotF1GPm/XJvEiKLWMy3DuMeTh3a4gzCC0RmjoSGPbQCOvTbV0rzW0pqRwYZuAHnusYfC7pmexigCuwBeRF9/YdQeqffTarbzmkik49ANe27Ydqbj1Du2uy+AygODr9s3p+0fNvsx/fnJYbfT6DGgb8i9fSxPAt7EKsh0MsHKAohb+2W2ENAoI9TIdBevYPNgIO1lWRQDh17uPkd7rtePm8AllrFp+BllJCvR/0J2t7Ww98K+YkAPlrnfC3cDcN8OX2E1OOjHXMHZEb1NS3mS4dgqAcLUFrG7IV4Hj9v+9Dwej2EB0o0vS33bK/M7XBVVpU6eZEl6UZ38ySbbxuTnLf8Q48KItKt/yiZc+SvMS7gTrYeco6qT0z5eHR1J3SjtyN4kjx8PPPecXZ3xW1tKbEeHYyPp1wFaUaU0jxzvgOjmvEAADYY+5NNhzDN7+ZnsZL4O4oXF4wVgrReAhK5BRImKM1A42ClBJU+z6HTC0171i34hXjA98rMTScJqOlIIArVsPjbh+6GFl55t8SqKff4WAK1gaJB5+B0Qx3xLA+4pvCYoRIhRNO6ck24Rati3xaLFLO13oDIi8vWhsWlfVEnmEsWS2DYq/RHcSQ/AHTWSd/KONI8WvQFSHE9Hx0FoUB5DdvcAmQuAfqwSdBEpvCEnJypsm0QAoaegT+AMtDWqhO+xSQC0zFTEZqExSRfE9e9eTX+g5EDvFO5XqcWixcTkg00BQ/oNouMQwUprAtt15+fhB7ZHA4E2DRA6JQADTon8pUTYdjQ0cqOjG6GJ1dsDxe4fj1CR7queKyh8NDArJFGIJPaVgZ/c7E5yf8MV0RyQdwCz6KxcWBFD+/9W7CEwBz+433GGs0WmC8cwOZABzhGsb+sWZ7kR9AGfhLHPjjpnP/lc977dy9u2p5K4c3glvCwiQKam8GSF8IW7sonOnxGe49/xEUebH1V9WLV+zOzjhHmL5Ha0ewqiuSl/rOuyr2Hb4YeuHfXrIEiJutWlQ9rAbeQwlQ/b4JLQe6MeBlt4XgLNfcdnJA15F6BpMMsRHa/zB/Tjo5Qc7TtY7mLighCX5lCgOtUpke8yrCmVi1q7p9gydO9bk3aU6AnJYhSY/uvOHF7QY5AghBxyGfzndFBDwE1ax9+HciSEDqVFLDGBG7gdi2NpQV5uVokdPjwZigf60osv2hlR104CZMp9rgKtAKDO9BXNfOeYLgL4pRuxZvkD6ISDaVtXF+7WD2Ma/cAHaB09zdiJDu7WF9dTbvZ6HnrnGTJkMEULMJPDWo4+tm5QX7PegIheeDTA6IJVkVmFhFfkMuY6CmvA5jrDegY6U05cRN8CFMmWoGUMBpSBJbrBzl31qFyAjMbDI46jOSqccspW7RkcOJog+tK8/S+tfkxmdpRCNm4iByCQV2Cz7H9V4sePTblKzQLKWGEFUbOOhgw5wNBxWyJjtfqgd9LOkBO8MFmG8eoZHy1Cg4BUnf3vFR7GBpBcgaKuazdSTmlsx7JPlwNs4bU27mp9bD96qs/aq+xKj98iPHKPLH6OycSzEyHRn4gE3Nun2fwHjKDfVp1VvQ1xM2PezgoT1/NitoQ1bExThA60u9JWR62XfbTEP/47NlzP8m3vADAewutRtSt6jayDLHIdEbkeW7Rda47uAEv2SwgF1HXW+u9pscJim5d2i2aMD+y4bpFwkmWRzI+Jg/kKzp7ZJGERxiQfCSZFfr+ZKRuE62nIsNAcR1SHmiJn4iz5C8Fwc83965uEQluZv670RUfA2yOuuTJFAB8BWD5UowQSHA8r9q+lxa9jWnT1WjWbm0neQu3YUQgD4GunHNM+3ZKwbswtJlXQ5gFaRI6NWFKFlszoHz6cGEusm+K7wUpQ8Ylbg9kBn9/l0yngbWjVHFQu2UXh7UuD9qQyW0R0BKUhP0JQHT/uggrxAJSWrNXs2JiRs7Rw8jyneXgOKWVIjCora+vO3L4r3sWYJXyCpJHRXTyF8UM2F4Ci3p53z8Vj2/30Upd95pN24oQff+JB2zlnb5zz4/I1O9Ls2w+8LqLASw3KBc58ktSaBTZ5w2KaCCR1w16WfcVGI4w+tH9cVqU59pc9yX5x1BGh2KZW5C75dCKrHwF2AGvf7tWM9PpsUXCSHTNFFEz87p32mIcwY6DrNUhMig/NibSNlHBjzrKu+ZRdjxDg3En77OZkKNkL4ZWbdmTEP4TVikLw9GQyE1uQ62YzbB34T4P2SQzsEfsFyAkOvqSkVuquL123z1VZu/Ck4pZ9p982zTqHAfjJzvGBBn7l886LYsTRF1EmCpnLhWbUOXh2aoTrtVrIB2qNIwwZi2m33CJklChThj7qg+HHZDgzz2HMU+0Lg7ZNpTHhfxjNZs5zwQOVhfbqkJWrqktrdmLZ9gjVmBD+VI71jSaCCjHJnHOVHkN/YvExCADsIHXYJt8aKzaCQzOmOcIF+7VSbw51u4QuzNZJuzwldOzVRsMHSd/il21Bcro8x13XAInywb+LfuhhLXgQVtVX7LtFdDGLB9hSGcD58hHcUQ9AXsLuO3rJXwlNBfqqY0JSbzMgyBfx+Dsrbf1P4zoAunApztnQoh2UGIKbwUDqxdyvjf7NnFWfKgN293LEHg+sGs2waUlwcOy3c5NMVyBV/12udrd/345Ko6I+qrWnVUQUIEAB9Ah4yS2p5pzeo+59Qbd+bn7gH8NqDNwCYSrFx6NF6Icjmu7gJmEj1U3W0+PPfXXIJfhvlibrk5F3yMcM8RdY9ItvuuMJgJWheDywNzGr4IEoIaFSI5hA1Njk6hc2+HamBA5o/F2ZAVF7vQAf/QbNLEX14JbvMEzkMpyqutpJpLlmJXfndjfZT57y1woKXcWJGRZbq9tdNXja5QFRc3yxPW0/1MjmjxFHlKAvkCDxkUYv4OSg/cr9SUj8fc1Wd9vektIIVqAvcAhxAUi2y+mlE/XSlxBiwmhHG4gudGJ0h5fTGg44xt+l9GQp6CcFRMWt7we2QP+AnMR3AAimzGZfyQycOW9D+Nz9MPELQPU3dIob+tcmkx2iqdtX5u2A+hQdgwUIf6G28CDP0yJqDmAWIsGupk3N22lTUzff92ebKCWWfx86pACriH2am8tYXUUigwOAe2Rwktb68aYyl57Eicz4mTtiEF4S4D769GGFrp9V2BTdNatTpApVpSvuNsC9VGX/DqQBljLKP3VpFqi13rbjb0ihtYE3RTZ03SaV/53T0UWrnksym+GIrWAJnTDpFTR+Mocu2jNgKEwh184v22YpfOg6DCE4DUCleUw4mrWoOsSxkGUgpNbQvLH1J5FmYv6uiuUtWUqYxUA+QtCL+Cul8R9XLutqgDpm3pgGEQo/usXdJCw0j3mPp4/bLx5Ngn/QCNFaUIkAKtACUeUn2uEghlNaBB7qdDv+dcnA+WXrIikcqUj9JZeR4BnZfoAlJcd7YdmOCpva6wxnfGg5JGffnZvMbcyyt3KJz/gzFwfkkTV7LiE2dOWz07ZVrz97yY5qUU0EZU1N+i4TNB+YmbT2Ak/dEfspV2GljPimYQDppAjJg/wAHCFnmYCCJnVeojgiWAbQwMRglk+RAczUwwHJFBIeemQtA0HcIEDwGDiKuqgxtykSai853wGgOOaBgtIwkzC/SVkT1YNfvygWwGO/Tma2MqtisY20CfKCLGA/86Ymu3+DjVYhTU1grsxrdktDhtp6esX2iTGh5l7pNrawAgj3SjU4kYdF+ok6n1sIi2hhwhnNkxiBqrnH1KWTrbNqZdeuJFKC4D2uMxWGogxc6/ZluhQLsGQX503gDLtOY6GBTkgdAGsfgUREKLAN27jNte03UStQWFnHNWGplB+DJCi+0Y0tHYVrKOkdqRyy2gOgC0isVCdzIzMLM8vRV8ghAi872A282p/KU17Kkz1+3LzBPpnlqSkiuBSjCDQOZo3JhJ1TpIJJr/JLeZa3IVlcS4YY0qU0NHkJ7GrVtsem8+3LCEOzY5R5zZ7VqD/c4lF54bNkDoc0U01M+vlT3oGgU+xzjVsRE/ew+ocakmkdVKEdAP5sFvsGMnQUG+G7JI2ItiOhH3wwMXUgqHPnHAeA5iobuOnhc8SrAEzs0CLtuWL/hr0fiHsRPtGNlMNeZ7s06GD7m+xnJRLLW/aB2EqkqNhBzOdcEv0eYD/0imT4CAXcWuAa5FZVtQkcW3XzFaBw8PP11/34Fz7rU4ebpmbiu4wIqNWc8ltQaG+PP1mPeGfosn3CzeM3QHuWMg5ZkfCZlFlgAj6CQBuqXZuVxIJSFCTGEMGIAJ4BncO1CQmk0lOO3vkiMQKhgSur/kqzjtkjCyjwHw8f3cRsJCQs9KYyOIxZHQpQN7oXRSW4UF6ux1EPQMPQS5XXtrffj1+TDkoGEZK+Auhh7IhdotLA/DdX7UGVhoMJCT3Jh/T16vi8v/ERrKsHGLogChTf9wM6FV0kHkB8BPToH/oK6CxEc+0wpEzyxF34V6Qy7+NXocJRpW8M+xZ5EVoG4YKQwiZXoeAEMO8kDZL016ghqEisQUREL6TrfxfqmxQptLVXZXGBp1Ft6JvODB2L45SqMaA36qULhhQbvnvV+smWzEBIArghcSkto2EmTVJn+1SZvdnOtcYX/QTf6wX6ZDlxNcIJEYUhLmFc+3d6AkCg55pfbG1LwhN6b9mW2mTFEc4XYt0lva2KRTvL7hfY5y85rlKNUKnBFngeNeFzwPFh++1FnzAB+BDhDOEtzU41ZLE3FrI5KgEmwUYjG9jo6NLoRHBLrj0rs6fRC3DdBgb2zrAe0WKnsBOOVHv0ROAtWQDY8gfDA+CXV8o1gcMpGiIEWKNbHG+WOv41ndK0q2bP6/geXQ/UgiShlGgdN0G5kJV6cF0/4B7ks6Mx0ZEwKo8eTbebtNVdSXwTlenSCG5UqQR1E04yqWGGgQ+yuIAaUzGyPZc8J6XbAABAAElEQVQageXqVCfPnrTGBfXB75E1NBmg7TFeOnuPn2BW4AwQXmNkH3L51Cl/74FfZtOV/MqJvgliHqQeo4/hXgSyC3OvX1vE11wnUUiKXXo4iIv63lJ7eYxnGTIIkz+AWtH5wU904W79oEpUadT4AD2PvhC87m59b33lUpM7AHhZrBg522Nbm+zWlUThZptOEL0GZowFkuPLP6BkgC3nUKpYfvOWUBWdjHmVLqEwYU7XFhKX3m5xRob3MqPEeNy2jdkefgW4hpFrJyYTIw11tnvQU5AB95Z72oYL0Af2Q7WHDqKRZEppKAWJMlw1BFj53VRlm1uTaYfZK/baa8kkBpuuEvIUuuDBXVa0wa1EOALADwou4Y4Ay4EImQ1chAV05nuqHJGAP9w+af8WIcne7TmuGd/Lag3dI5YPG+mraviD+S6KIsfAMmnxRhwFB8UEO0qsaM7+gxdgvzpvLdh7us7DLDFCsUavBWAiMLsBfYiZH5Qt6nNEtMLeU2iKhTf8MYgB9f72gB/D1B6psCXSCqkVzDTy3R1+x4PW0PO2wSDl17wJ05vy6SDg9C3Xt2LRCxMLQ9POSdXfjr5HMj0VOFAvo5rRAeYmvA+pz/d6/JT00/elH5vACL/pST6+Lg1i+6pdW/Vt+IAOvjVpF7v9mA5bIxlaQdLJl1numZnYvb0Lnk+2QIjB6OPXQW/e3OhvoWgOpYP37t3mTUOExDwq/JeuQCsFrl2zY9PJipozI3afjCU0coB0FPRkTPgwCUbMatgSsBsQOEWqJHE37AeMDeLWgIoRF1co2Z2tfppXYstT9vybfkz6HdYihvGWubyQVZzHsGVu0pfQ3AFZTrkrN1bmxmMej2jV7GLP8R1v0Z2M2uFOf/b2iO0pcRMi0Bi+tlyX2DDHT3j2CBAb2F/hXPtLrAFDCCjClt8QP60y179+Ph28t+yF75FMpTQCDl9QCVmTdiDTdjUmRPHUDbufNPEaWSLc4KFhjRDjd7nHXeARRsu40CQ2PQRqYdB5bmqG0Uh/MhmLHQtgT/I6YwF89bbvCdFQ5zYAgG0JEoY34bMlvliIySWA50kZwspDApyAzBK7NWN7ivyYhbuLzEIzY6aRZV6akRrXY2UgKj5C6EpzhkyrZjOVJ0pknXcqlcy2gTMbyjLvP+qPfeup1aOPLPh0rmiHEdm9O4mIZqKS/qSGTD8COAUY2bCQuYKLJ9wHIA+ECU7SXmAlx784oqFG3Xm0yJWbGD7M4Em8a+IG1aTmZ7c3zqEdBS1DcTGRTm+Tdn8zlIZqe9uOsRC81o//esi3amDPE6bQAdAPhDqy3Y8vX/FOOHfDp/2B/3jRdmf4fgnA0UXv+ejtPTl2G+awZleQwNAOPa9NzDkegxizkj24qqVkoGSLj9rbqrC/8BGsrwcQbtF17/m4BtZ1DtQvMW83FeAxZ9PKHKeoIxpJ15OE2u9Z0o/n4hUVs08Wyx42dhdzYGHk6zdsULdASCiACgP3So2DlItFZbDl9rRBeIHtucQqeYxX4Ar9euUu/YhveT9TN7pIcswP6DoxBk/v0SEFK/Qbup1bYgYuedGeQ+GjnqA6+P8zCkGd2Ckz6RZh5PA3zAI8NQmePIwXWC0/XOxk7hP4NX4PLg1zCDHU0+Obnh+SxvXWmN1b46ZXiKS95KOqcj8UgLKUxVJViXK0ETzpsIvoyVPq4W3+VKJzg97bdUroKWnVvnPGTzoVkJJXLm6+OOuOebhnRKHghQLCobi8nFdw66Je4cLD0zaAWuW3Xegw7owvwAscsBNPcOmZeZtLx7efGLazbAukx6gJo3wz7QWAuECVoES4KS17Jl1gFA5WA2gcYDQIBvAMqKJK+yn4ExTqJ+sDKMi/lbZVaDT+3HZ9icgCkDZad1HRjFxWf7t6zAFR5cBuQhI0fBwTYPLctD2WZhogMGOiYXFSpdr0zA1VTHJAR+/zEwQC29lbkKgNRIIU1JZ2KHn3a98aP/xQ3tjoar/omV9EJO454PVnlknKhW32J6N+elSViV5FwiDJK/yyR7rScBrSrdPTPylyY7wY5V36aK+GrEvHP92f6O311oEtMsMTQfwYFNhUaU+rr9HOoag2EQGYhO2OIgvgHS8us+211ghLUIRhJogw6Meos+T+vgjmSvZcY/1App0QxdFH45lJxhsSOaA7HkDBlcaGAk0EFF524Ma0T6+1y66jtC9et/+q3G6rPrw+gzKhVwhWxvWLXcQELkA+jLomd9IAaJAtLcl2E8x4QP4k7cFuBHbgQW9MLDSiwAA0VIB8LLcv+FL1EigYN/C4b5JzDwMrXZoPobyG/rdxwq5et1YRAXs9L7MBsUqAHkaWbAs50PUhaoUkADkAMn+QGzR6GO0TtL5Oc0RsmAF9+Db0IXIPzs3aNwbs0w3+FsnxUb/+qXr1/94lVUwNnxi3ylyf1gtPPPFj3zP7XJ2/gnX0L6/ab0i75dv0BjZtOO/HmKhEgRat3Bhxx9IvpsUtrIf8sOp7y2P1WkmyJmdq2t32TEkNS+LSYgisDbHGHD1Z5shtjfBTK/h4LRwVgQzTHLMBggH0ytZc99bMT9mwuouI8/F5nzwByrO88ONQMJooy/0xw8b/hj9zGq6yhhqbPGcbUr7ACbh8yU2vGLg/77fH0znKWU37fLfvtMhwA0gOpl8CMWAloG4Y21hop8Zs95qxWRmAOotGXl/vx7z4716xz5HUTrhKpuzVIrsC+oJOi658x/DNT63Mjy3M9V9tfbjJ71H0pUtRxOUT04RHx2QLXycjHK0IqwOMBf3CYsxYdtFITb425gUcIVf+puStQdIkEBcKJtHVSuDbkWP96knomei4AKL2z571TSrZ4QBAiSezZWfKj4l5Y487IseAZ+Th28xODCqhmGlG0res+q0UCZTY/UlD2TPqljzjM+R3PG5nN7ipx84y1UaMqLCOW9EJxI0Ax856PTFygKMbfJ/l/2Nv0uFodVx/CV6IHVVgFSCNACWggc1252xSBIJJ8wBrpaRZ1JTasXlvUa/6JCPTNmZZi97KWPThTkh10vO1vI2PVg0kLKI9N2nFG2/ak0+ubmp0rrFvcWFuapnBDSsR3oJpFJZqB+O74knYI7kJVnegGW+NjtsVZh3FTBgRSIkRj8jJPigk2zffA7LHHJdw5RKsC+BaRg2KKAoWbsEoysS4ynFSskJs2n0cAN1bU5DkXRzqMkJicAkBn2HxWK5T/TUkM5Isz8k8rFN0FfBnU6F9AQUBPMEDzYBKNWDgQLNA6cocnx4fYttAkRilUp9Qe9iEg1EmGBi4vuLSGhqK0P3gCX7jI1hfD8DixDPeO3AF7gcwOPB1cSBX3bgInoqSXC9hHEQT6/vej/aUKN4tEDjELqohLg0dVy8nk/kQcU164T4Vpp6Vxclj+5g9rvO1ncAw/HnKnlZx96af/9Gq9kFvq5peGT6LWplmPK5lxi06k1F4VVogBdEKHr6oImEXSNsYIzpfPOaDvvW3+V40NmoosnZThAHp0goZrnvgzJorGEBNid0YdW4QDAFxBGsNhvkX1+2RqiQEfWbBnr1hRJSFubV6yR3fCCyAtLekNiV9PHB1zd7QPIyUI+9GWPJ+v+Pc4zlYVrqTWUGaV2kXJTZYRwC/TebXJiaWpxdWBm/lPQLKSEQSCNHcxGHvC72VhUvjlAhdrPquOYxgNBZuylCiogCMO1bKG+RrEfE8xAoXpW/hFtLtLSVm4LhMrg0oiy8DjD4ESCEAaHBBMzDSnpwkz6VbcUm2lnQQPaq3Am2CVJOr6/uHZKBbmLqDVwOoAxyEiLzIKoZ0IVQAg+T+dPXE0T3lEvAg5qtojWNEZPWSM4rAXgYEVU5yxttFt8Sv3lvXD8hDvEP4hEGMg6055eWONVuX2RdyEtUuxCLebexzNCtg355Vhoa/x0b9lKXFtCKQEGaCuI7jrbK16EaaDzAE0Yc6u4s/oGWluoVvMPR0lDr+Ln5xPUXfmbn11KT9PZAXaTFmPSB9tu1XL1axB5c2tOEWyjEKxFPH/bENy7a9zXa2J7oOw0ZmsI1S2NFCSgtsH6IGDxmekjHfC4uIJgA0Kie2Ac4BErB30aqvfPg2bJUeXLKdLKPSY4QSMYMUujslP1hkTHyTMA2oRolZ9J2mgE9pwoFZAmoIQM4geoEKBye4GNPcTFlQCH/BgM7fsF27fdMDAL6DvsWkN4CWg0HPWyjKALn1cKJ3Vvgx11EfUUCTFPbX7csLbqsA0MOz09auunG8pdJXR6yKVmgLpP6oHqPhG+cTdNxQ6ppcHkHV/X6vccXtHJawA2+Me2LrHSV28rKfXmcLpiz3fADQIW8RJwYMDBuJRDHtjtT5KXW+vzJZ/wrD/VyTrU36dWIsh5H9eTbE5+UpbJA9xjHK1oERz1N3TXL0rHwV4cAYnrSFK4kaHRyELlKXOLtHCqI1Ao2L1susWjqSmGtlwhBuoQtm3LYT6hOy/BFpNpZlC2P+FlFYaPZqtyuCW6utTNxx4oZswrVk2ooWneizx/b4K7Q6lXJb5Yr6BAWaWrFPMfDraJ8bEw5P3vmMbM8RCJYCzFcw3D09fsy7gQMcf+uGeQr7UbspGj2/YrvnrUNYh9r96FbXxWlvvMX0yJ5OP6Y0kDa/xHErr3pTwcBQ1tiMG0wA06PNKTdq6ZOthaNdE8+c9Mtbq7xFTAEtpnEDbA/UooY0Ck/kI/6SNRY6WXEXYBViPfXXK9fGfGO0TnJgBCmv+TquVXUXxZ4et4+R2F34wKDvYpmWGk7kT5FiBiitlPDIUnuuPzFO4NrMSU6ohEplBw61PivP3ROQjKrjQ1xB56g+JIvHA0rzw4bEbnnxbBKPijhkoP9fceR/0mYpVgkSmanTSxdd8G9X3bBaOf7yy966z95n2xvsYo8dUK9yvY1wC+QVa/yGrQNkIFeKGvu9ETuclbjxOvLtylAyY7xzgxPjVr6iIWsjRae+SAkM0NCg5bHqC5Ew63WDZMKjyqwaHsdY0t2yJWttZW1mZrW7hwctSzGx8BCAGe9yJj/90NGAmU9GkFlToJ1U8sX+B1SV+8Q+Fu81caFuSfFev2PlbAe5ZFtTfgw6YRIPcOBnRg4M3DoUC7TWeapPOhPYyHbhZXZz2F5f8NMHl90ZROUB8JYuJb3BIdEOcc5XyNzld5wEehacdQDLmFvs8aU5Lk5B3quEU4piEanDJIhXaehViHx6J3LGbodcP4I76QHIR7LlPd5BS4G1AshMnnldxxi94MuOtDbA66DKTxhAZjglqAhHBZrJ8LaUqICQOFVtU4VQlZAYzCHgygRA2iMbEj2M+d5bufakWCKcQ8xD79zNH1RMUaSJ5SdfCu7UJ0Wc3j6hy+h/0RDOICDeqtR1RIw4hM/IATRQLdDJz9QP3EPk6wPEAf1/Q/XPYsUpNic9BdYRiUNq2dlE3sH0sKOC9f1qhm9GH2znfgY32zGB5+MtPOmDYr+jpN1aswE0GPNcO3AJWAtfBOg61Gt+AXjGAU24CU2cQY3P2P0pv9VWr02Wo+hNm7JGRjIJuX9HROLLxK8M89xdm9195dnT/gpuRyJfkDthe9wWQkqI+TgSJFWGhuMPWrN8nXwOoI6H09OevEtNGtMzn0Ge1BaAZZ4Xt6zRKZTYKXrkDMmFqgM9AnLOu8oeLdK1O/uho6gtEjy89oTEHxu0Aq7yCS3QeEHl3SvXJ5sMRST5KREmVQIa8z1f7tOYgySC3mU7q+wrbMrqZ06hYHhUlUpScyCqqi/o/H1+wBygmR16pqyZnpKKuzA8kZs/xXHm3OqsrTHvGLnlmJxgu61YANLYmrM8t4QbOl9vQUrQTpR2NRrrhTlKII8wfgIhIU/QKnBG9+/WD8jJt4IRQfL8wWl/At/94PZIbfngR77v7u/eaxnCeuIAWxTQ0o5wllzvH3BtDEBHxHe7TAdzvMlT32BRgGfAd4bsSHpjIpL14XRfm/fr12ccOdAycUIDpyb9dFyjSAjcXskodjoCLne7coPNA3Sw5RHJMXv9eFemba+2S+OJa/82ueNW7ROqG0YFr/ynE/b5/f4k1Aia7hYyEvnz5gVrrfbr8Bp3RQ8ne67XFjuL6bnmt9DObwx5WBeAdkWOxOcy7HG1KAtELE9Hgq1Z94DnzKnULcywjxd7ADGABtYEZQvocUzBPJJ/iO4HFFH5im79eqmHVC2ph5mIyL7lmyCHecP9LRuN/XYAPOv/ecZ+u9pGQSL6JHYrl6RkXrGnN0lZwa5E7KbHZYwHYA+ov2zdoCGKZq/dzrSDdX7cmmusXH1lxPaqV/dkeWoEd0Ehiubd9B2ct4e2+elBROxlu6quw5Am/eOSeDy64IVhq82zQ2X+2AKZx1lHq+7C/mzF4hq18cCNHCOZ7Cl4g5gyhgF0DvTP2zd67dcKPUMGgJ3AVmmRJwe7lN5ji2dgboNbROBJVK+nx/dtfONtv7VrqztdMAzC9YKiiRsG9RQY7LLOB5Lhg8+/8ILrwRG/wKqz733PZzgBZipQbU/Qm+qoT7a5FyBHHc4UyhqbP+qYknH8I7Se1ymvghhhZqRSHgA5xnpkOHUqJ7uqJDt7ymLTq94+t5yqHNWKH9yYU3Aq7y99mHEa0ckYA0OqakuzNzakDwewZpZRLWmUp6r8K6FhE9ZINQjtAMrZ+XfE/mrSfkNoTHwdeBU6Om38+AEjt80UvBBWWGzN2k6A41STIzwdCDza5luK1eKqbPJTIsLZr7BGsnZy1HGbOgBDcqc1kQJUuAEysIIZOx+ozLLbTOqOJ64KLFh2eMsr8Ftj7DHAHuVqAp3WssmDY0OuE21Ii7rUClwwGEhPHPFXyJcFAyH1ZQQxQuwYz9wF6mZ9QobRD4v0UxU2NWCHqTrolG09/ZYSnrDhGJUpXEx0KSKEmcY8ppH9+5+z8obCTFwIMJyS25Mji4h4uhoIE51JTqCnb7Vswxo+yF2SdbCFiwM2IhLe3GZZvVa7yR9jHg98A11JzgG8ScDnpB1SabhL2J6L5Q3B4i9gWmuigMeY1KVvzlz3V5aHbXuVdU4nnJBoQ5KzR33GbtjMhKeZAejyUmYXZ+wTQTBj9mKPtaLwSjqSwxO6iKDBmlzLW/ybaXn2z2FZo5ewZOX5dn4+WTKKNdVGGLM41fnrelfHyMsNmZ4CkfkN4O001/KTj2AdPQAyjr7PY4xk3KKnkXtwZoDn0ZM4Vvfbm1IR6nQLlvCh2pIe/OF/tutVKgBavXbb4/OB2WX7q7WEM6/J/S9m4Oom9Qd7hfte52t91j3kr0BifellvWd+UrNziBFQ+/s1GLB3yqvj5hPkfhTmr1Ox6sRPNKNZi2gRDaGTARHZD69Mq4yf5g9suFLfR34yLrCXIFzi/c6DUWreUbaVr/J5+FCXESU4CkNSDHXbzgeS1M1Y3c8+67w3vGx++rKxgQrQXGt9g3YcnJDxcx8SWX+c5kuXjc6nAvzxzbf8QTuwxPIfy9NbsHHiONYIGwDh29oy1lYzyK/FNwA4L/JR8rvw0XvX8tY2ZHRxeUO53VzwCdUYKYab1r3sL3iwIhHR8EZpLp76i8gXFhsDW1Sxi37oMz/wWsZd8s1f5/nQ/um0+2WKi0e6tZBKdx1vIUyE3SolbcAkJ3f4j5JpzO5JFxYA4ilj1nsJYKTKZIRwTAe2Q2XEMelWSnZCtOLebJfFH6dh5toRasPqSIKx6Jj0v2jXDQwaSJ9ITXMvAw3/ANDAupAi5+S5K/7g3/8ty2nYlEE0FJ7xscmM4aFU20p+ASWh6iyheKBkAn39ywTjgEXskgI0Dnlu/SC3PfIZbfXLztZ0P/Ei0e13m6e90yKsPtXUWQQN9Ab8tOH7mdWH16WzNkmUDLeqr3YZH25jVFWCfXt6vAQwJnMxyUw4edttd5SSi6J+NufN2pCYGVgjkHR46/FVwBxZfVEsrwXjQe+8LHn/K9qV6KVxe6zGC9/O7rpE1AgZ8XNDWhvBNcY+04gP2pLyu8DXb9pRNCF1MJRNJR9oT1Q0NKeiBWcTQKrRkTI4Doovit05toXVPSLHqF60jsBI2ESEM6FbX+vyMKqYH7u8bCUTjvoAneDZ8JXtmtOWRt8u7Lqqir1XR6i0EI21Tzh0MuaTrIw31tzy7vACjFhN5jRQ8oDVLK8A+pYUWmuo8nm5ZpAX0sqwLSy1z0yma+kzKC14KGG+X+011mkAezs8r/2N63ZTBDdPxFGVLQz7ratzniQ6tN4Lo76V1kF6SbeKM+wb03avunFwyYUuimyeak5kfx9xU16A01UdDgP18LNLxj5g+aXJZohvr1gj/EKst4Zk9LVS4BgGvrtknaUeFgXkZbrmXaYSpuYsBTKkd9C7tGBHcw3kAQpKfUyxVgA8X+jEYc9zyvUONq+g+/C0EZd4031yEZiOkY/fJQzaba1eB3AVQE0nHJTrMWQwC0Y2/GE8wOtjGspDrExjZVFh0vl86FUa2+Ml4GE6f8k3sD5Q4adMXyAgMA+A77zoiTSr2JUJCXdqsHpTRnbW2tB5b/n508uP/i7Gonhgbm5eXeU9e11D56Pnu6wOhqTqYUggepi4ADDsYW1nZmxMt+5btZ2dyaTc26etoT7Bk4Z821FurdhCYi10EcMakpKSWdO4lpd4Lv6kz/6gyIkxvousvahRbi3yWPCh4SRFZ9as2zPkGgXyWYTJlmhiEhnTbvmzYYPa6oiBzdIn1CKSEJyllwKjwHbm0GLSGBfG1SuJJKB7v37CdlckBdL5GGaEdwJMx0FZUW2mDbGK8fD9sQb970z7jBMZDoGL856jj3JOyrwh6PT6nG2XB4HtAeYwY4Sos5k2wMZ9a5byl1y28cp+CSrQ46kvL/zS7/tJ7raW3MGR1SvdLM4E+KUO0di5qTU2tsYSi+5iYz3iQCaFae1tvvcIK1QBEImSGf0LQpsiJioRkLoFZ1shIY30aZ6sl5g57i/Z3jXfaIEaAsUIJDZAm7YxoUYGmRKZvpZWXk+KsBJrQRTD34a9AkxA4YQGFpnJP2+FIkUqDAITUbNft9jmKwcbv9Qfw8nFBobiQD6gMKjJfruGKEYHKvR1d1QeqCiwv2R1nNCM0SC6lVSZuMOAM7roRx/B+noAGkF4vSfQ8Rd1A60GAaohcrqPPn5Ft3gdfiHiu+vaP3gqUeO2H3S8XXlfqMUQCaggZ9WnTSh6XccgCzIZpSqk1V6qms5GsI30NjOerAiAmYV41dld/IGTQe7vfIvvtqq2fBKZyC1aIfGS1GGT/vM85CUu6JOKLdK8e5JHnOGLhaTPf0b+g3LiQK7dNkkfEJV7WxisTHFIQsT7r1tLKvHZ4a1DBHy/iIyYCNQPsvjCGUJEwkPIQY0qAsATEN031Se7hTygRLAXvs4Xe3SLbn9T00TbdDrH0uv0rM4zr/tU1e5dzkmrC844S0IMiP9eOrO09beOeIZrICsro672wE4sFPfX98um8utCVGikWsenZKhQgRjlBwhCYT8hWCrhrEzEpZEBNrlF1ZM88T4BjcU7feIFFk0rAsORKiCG1BOnQSTdjwsZEKHUBwkVeojLaOb6mr2qZfN2hhVxfugN+TJ+bXxnOkUm0FOB4YwUvYXFBTAc6C0Q4J/pMd6ltBgIXgzKjQLBhw8GyXZvPksnyBMJlNfn/4N/NvrHf07xlr0tDzO48Pz57re9+LNnXPsKETk1tYZf2AdQ36CvwJH4HHWEv2kgfeYNmgI/e71sb87dBglMH1aGGz4A0PPRG3f70x9afvT2hz6WPIC6CHUA+PvRJ1CMRjTIhAj3ksWOZkGEa7ZroxWLkaN4balxt3qR+p6ZCvDopXP+GHMjJex9xmjg9K2wWba8IzWZSqMY0lE0CuvL5uwyOQM2JRMarEfCLpqFLMy+xH6jGkuO9ylhAO7kAw1+6yCzJTP22SE/JvNEZ5O1NySchfxpG8eNXbYAtEzQl5TWADFF51kr32qTKhxrAQdwNJaARrSuKdWN+pde82jACHNfmbTnFzy2GNi56Ps/omNd8TOrIdUyefB1zE5Zt1mKIxqq22CXJ+2pxQQ1nxR514eAVTW+K372iynf5iK33n32AD4gsJwIJYAZjJmr3qWRraFk2ErIKypMz8iy3SXWSr9o5oQxWqv0WCwAS4xBwaID2JyX3Xiq1NIGVPBCa8q0kUE9lmmtjKwfOt2Cr8xmLIhRUXN2QQ3jDfImiD9SiWxZ8pT30D8dGDDINJo+mjlvn8uzq4O+CRLATBpWa55orqLG/uSWfV4vYDbzONj1CnQJ01FAZky2oEqyc0BjjV9Hx2U+5MKYNQhtIHVqfvKi3yq55f0DFxvSoP/1c3Z6yT6vtw4edOExIhWWyEnw56WXkkkwbFSkSywXhp1hlR1o89K+x1zUhK+1i6U7m0qM5PsbhPnd3W5mYKJH9ZjOQrUNCzljyUoKk7mpoaGFzp0ZtXs2bVx19OrcTkr+rGSeiJDC3NyYwsLCZwu7VF2SogPzgwJDzpVXuIbdWWCjE16lW6Tx0B4GHGONkBc+Sd1R4UZC45L1CwGY22QKlIVPwJ4K62NfchAACUzaxnH72iW7TwjQzUrLMs85DkDFNLxgQzp0m3w2zNMKGbrFNFtFy8ziDo95v+XoFu6GnEzf2gv4ZRCj1Ppv2A5xNa6xouOdjHxQgYbLrYJSpRaM2WmaQ3tVBadEAscjXSTHGJz87b3khXOdkP5heDmykBhjdh2YSSaN8d0gW0OAPdvvefbyNUYY1Vnsza1oEN6qz7OuCV+wB0DmR54sS9LCFBblTE333rB/94LfAu3vvTdxWxBVz0Bzq17d1TNrz5r99yIrHCInuuyQJNOx07azxa3iWjWjgDVdOQlqoaZ85ft0DuoFAoaWUJ/pCypQSoDKIp9Rxw0hynYPLi3aIAIhzgeair6q2OBLPZlvj8bCtXY0GMwQwAvDxV0IY8kZcn2RPTUe67vtCKxetMe1JUNzhS2LSL/A3oMzdlTiKDfDWZYa6roaVSVgbEgjGxf9Mx/BunvgA2QqSglA19LPoQow7ogs/FaxpQq3rmpCKR7T43frB6WzX2WjYqKd1JclEaTtRW47TesWSAuiiuJd7UNn2iq9ipvc4i2hiTuhkEpjQi2QF2VLjPxu1TzK5dNQJMxpQOf0J6hbp2NahBygeiJTd2/T89wFYJOwo3odb5LxwLEEuDczmqObP0s/DGVomegRiAuGNfohJbp+Wk3ZvOhLGGCAMYH/pdesd9l+Wc8dOPADIhLBeuzY38z5s5tIrzDg5opzsAMqDZZJ955Nd12tbF0JCp/HoGNhv3wdIBExyaVhkgALQJo3efg0UD8+uXXPou3bH073+h3EdrOOXIiDIzY3B1kP4Mw6xsJgGUWcgmIwSdoLgGa0l4/GyEI4+9AqqZaG+C3hKscpdc5S2sZGl+nV7By3Nqu0XM3ucoqoflUWOMc9aiAHPxaAq6OM0CD6P4AVsxHJmYEvL21TQTtUn86WPPHWYe+BzAACBUmKExlAQ0CN2VZr9WC5DC1IIHCYU3pj/VZiiGZoHElRI/mUubz03/7XbUn8D4EWk5Ozo3N/9JRTRoqQqHt87xMAEYkf8w327NFggHKIaPoToMLH04HTL2pRKKzjJwaBDCiocDCpTon9/BOrwAd8CEZ0BwChohkDZCa4MmJnlu208OKhOZcZbdAcuDLky5lisgUrhfEibVc47FGbWE7Trse+cdnlDdORwGm281p10yvUVrdbqpOJr9wqI2/e0qhNqKabN7u3Qyjn0U307DYvwHfZKmq0HbUJOpLRoWLFUs1+q5OkeWvuyAmtmmkrvnL5st+ies/32m6oVlS9u8WIngoXO7GqPAZOA+jo+F+iRafP+uZXRMHFZBcH9MfeCn+sYaNP13Rst1qIhkZd8x3Bt/qhWynsc3VN7INon6PbLEWcnrSljQs2y8KJPH8M7fPUjD2S8mMsB6qHncDqTwAHP7YTqQ4B9LPN7O5anLjeGQtUUqgRQKOtJrurxgjFHa0LrTeM2OduGYSNVQywdx6qvObtXdvu7/MIrl3qSpJ/+G7v/pTj6xZS8JNFTVbjv2F9XZrTQVpH0oFJ5Qw6BuS0PaCqkhiUOY3L817CzlL7Yq8dJh2IOhmJDeG9qludQ9ZC4nVYHU4UBahkZLqFAGxkNTbptqFglBI2auR5iUEMG7TPFOxb3cUpfCdT1I4tQ3NyNdXAW2was60uieynH+i68PffnLeXX/YJfdASoIdRzb8GC4d3Z1j9mH1irx8/ROaJbutatMe3+CnJJ5gVodsBdH2QmTJPI1UIEO/0DoQPArXVPkxbNeQMxyrewrW1/D3buZXH0IK4j33Mn1tdufXc88ycAHwdl+FxtmijE3ksz0cwJBPChmhAdsTa0+63WJNz/pyNiJfsr3ffwdmrfn1frn+dt8KeZFi319u31HUPsyqancRmEwRg39Jbq4ktl0d62UnbiRATziDSYP3F6vxKknOs2WMaI9AfAyYkBPOHNZXe/23SE8kU34Gs9AI84d4L9FXKN28BGqt8CpEERwDOMIR393U/HiJRxzYvLcIgMfkObbEODURFiXddJowDl/mtVZCf8Xq4w99iZGld7FjFgjoa2DNpHSJtd76U2uu3/DEyf9ZlJsZJ/4RBDSloX4+xRvStW963ALNkHXunuoktRj+4p/rW2wOs19oBb0ZBKXUTmjk6gArwUTgANiHw0G7bn2fNahEV29KQ2DN7tvl8JihRITSGDEnCHsMH0zgAZ2AVmRdgQ5MeFE1eZoCsP5QfIe/kqvrGgu8LtEm92j/jysrjKq0Pt8JasnyUzdwhavyIgWm4sTB388SdGMdhdpZn0z+RNpWpLrdr6vActjhL764OK2AfQrfYhe1MR2OVKe7V9eaatH93J0jItDNxR17TxCbU4Uc/6+qBs+m5KShVbPgH3gpkgIujIzpfgGmQ8qTArky4Ax54Sd63EGondeXu/cBTxe189KkYAfNTTn++8X1hhp2B+8ss+XpaGUUo1Ckm6ojf8fltNv+oSMud4xOu/gLPpf3rOnuPH9BWEvJHNcmwoOCadLJIxxfnQDeh2NHDZA8iG02JWoHGgc6AMg2A/gheCQ1fDsRAwAWjPoNpNfc9Kv23/pJ4hk/aIIs4jj7hgDbSMwD8AQYOO0VgAe1ldm9jsvAB7QgRiRcPIBkGIjKe4RRhBxt8WqhMr8ICn/CnPHPDN2Q/7NIpikFKFjhn6AZN6m1xGr9O4itSoQLYWp07rPOIM/1cvFPR8XscDYsRkXDnhx/251AgvvqVMJxq6+zIuL2SpibaAh6G2jomWgMn2/wdr9s3yQtCLXVlB8tS/NB1MLCCIeb5AATLCR1hZlAU1yXbvd8gihHdohUSBckr8U/08cNMOyNOGRdieb5y1Us6XOjJSEJnQ6BASpK9BskfwCRLc+NBJSojRAhIpTxgBIUB8CUG+OszPBIS6FPhYDjAu5ID7rYDNNQ6ep+f+C4deG7NPi+k6b6ysvux5am/+g5vlNy3y94+dfrE8p56f5+lLnj3wh2MJELBKSbfgUpmxKkaHQhQX7gZowvsU+dTjaiVrt3dn+AADOs7bQ/qvrtfXV/pgbfre9bsu6ftAToS2iAVslIPx2h1y2nUrsLyq+xPx+0fg62osMoHiB4clNzCbj9kkINcEDP8gewiY2JpEPkEhbdq6NiqmCTs4dtAIa4WfwzLBy0T90d0H0MLo6wNvsL2Mr2KBRJqkhj089sTGw+ccO1tQ6Jv5Re4/ofRBYA3xUPJDBuvo7ijKk2IK09vdMwmagvYv89tMLgBMDhh53Ps0xt95TqAS/I+8vIJlfhEQZ61tCYpB/KyrGzISAgGkHMPDQbPN3B9wvZWuZ/gaTU2e8VdRE+o6/g6WzxHi/oHnJzotzCK0PX7mM2jx2Lain7LSFoE3kOxod1iWdF2NEUA9wOTPzs7DTMG6Cw20jyuTvpxY7k7gSLzKiYK83joYayYBziAeiFa4N4N1ljmPowhndaSqy0tzxgUlm/BowHkK8kSYGq5BX767Kw9nGX3YX/zTK5tnbRXluwe9arHFawm3J8lSR1ZyV5kX1i0f0R+cPbNVIG8RfRgg8aIetKK7mteGs1Efad1qJsBoAfWJsBFEObaS8kkRlujtbHGRhR/4YIbJ9GNmWTjWDDmu8ABgAIxvWrVWlKHb6lP5mSYfxrvt3oiAzf6Y+AeMXVgDoAazdQWmNMOjxQh4E1g0AHdtyrCRoHamuXu/vMvj+34tCNKBlXBUqG6wOzs8uQMvQqAh3U1vr01igsAErI9brgJsCuo6uCw/wJMaPBwEWwbJkifsCEyzFi2N8sUkYjPaJAerfWI3MdUt6s91ptpT7Y7XQCO4fN2WqVdXLHfqU/659Uey1faQzR1gBU+O5ngElkR+EFX0+fAKwNWs2IvTNk9Qqc+PI4Ltk39g1lYAxZlW7WeJMkkHUu3Azgp4BUb1G5IJuxeagsU33L0jhy+F656htkC5UMkzzsNBKtBReD0ZdveYv09frw9ZXNZdu9Om4BfMEk7bQ1ZngwGoO7e72t+PLno2gZ/88L2rlG7r9VZClBVk5VRUV4TCewnJkoKlsCTMlQSWYaoHS+84MfUH8/OVy/a5xDvWCAYmWTk12P4F1P1idmDegDNgl3RRTh0aCBWJUAnTPEiy1bz/BS8ZtVZ0EtmnhucQaSMHWoBeWVIpQhsgcMwCVbpx+QLZco69B4qNr7iuy+EM4ieASueFQqRnrSy3N4ctcPCO/CEr6jnnIPVsxjMC/NdtjAmqap6zvayjRuYKKpkkhNuLMzyuBqW5NECVSEJHFUBH/2sqwcYBJGyC3ux4R94S+jpfXsxrSNCCjmENKNvibfvmzI22xFlu+51V6EjPQdCHYhBBeeDLIhEYBFNpXjs7IQtBgJJeQWlwVOaBvCLE+QlNemhRctdSNRZHk+z53dXH84BJ0AySOz7CoLAunc/t75zCgF/kURiJy62IPeDereGei5bFvsT6hTR/c5j1OFaugmIs1bZjTFkVAw6jc5fXxX+VjwF4qDpBl2n4F3qVQlzbw6ds1XVpNUV03bxYpJ/fGujewZDROIH5yB4CwwN3rJnT6Kz4e4kIaH4uv/SRXjTgNxb1ohL9J0ZeziePs0txvSmzJtmfRde1E2SWB3n5bgyVs6ekgDyrLd36pXTJahTADWAPSElAVaa3r4dogHtpQWuxQ7vfsMnphh0SW/XAxkskE3vuF7BVyIghVZDiRl6hcrwDFfO6XS/uuuAjntkjtI/eTqlOZQZOMkriM1A1HHd5UfqSfpkff9DK4DB8sfsYrPoBYmMQhIi0nW8fNugrzbJcIIbtKlw6kDXTInenu2yhx5KNAj2hSbOHJ8vNQSeUj15GKArwHlkHWS4Hgha/rrZ/9CY6EglbHpbVlZASnEAbTg3F09oOCsZHzyz//m7foe9OltS9s3LiclHMyG6Hr/jdWgPcSxTdkZBkpW6dV2/d/UnkIGRAmECAdTld/Wb6y085PJ6nz60NQmiY1FTZakbBmilAHvFsL9TN3gtzP7NbckiE0gLtQnFgsgcAPvhleNGeglgO3phgZ3u8+N2VJM5e3Mx0Zzy2BFozqc+gF3aYOrPp+3T0AFkttGDFp6s8+NS4rtYpKGS+crQuN2eSfRj1LUl0nWoBJQPdFP+iHgEentc7WBhDMAMAwnxvnjMjw/XuEEFx8ENDPSgg7IqZrsfoxu9CZpIq2urs82ltjRsX4OFSynJW7Yh1a3oppeMj/DCNb8FV2IZzFUN+Czb/JFtOcuvE36Jg59a1fuZr/VMgdUICjgCXHMtoS5UfObKMJnCn9HdZ+XsFyxOB1967XX7sxz7TXAKNpXhGxDPZPrx/jqvQ/ApxCdzMnTFvUf8FhcvXbIRdX7eTS8KVQ+YnrKuMTt20x7XLcKcGE2tZfX6l7d5bSsRswpxeYSU5XqLrt1ASgbxiGYJUVjSbfVDiogv0sSJ/V8l7c+yG1HEfwO+l8OKrYh70WIyXMXMG6SILx9mNKHCn5m2g2y2K3TquuHThrWQssweEO/yoC/hA6gYXbFzpx/TS1ik372YKJ34gYAoAeX+qWP2gHoY5fXwYc/IFB4apjJ45vFd/jAzJ61tdumyH18fsLINvidS6MRvvGFza670A5hJ6NYwoDAGCEYnd3+kVGGNHxbLmtAuo64+e2N5Y83kreM9vFXx0C6PSn/1VY5XJ6bL2zY293ovMCLgG1iHTQIwKCDGF3r8+FPlbtcxmdwz6Ke0AsMghBED19eb+AtfG7aaNTu8x37tXn9sZcJegwMKb69OekZ1SINyAEquqrA2SaqWcesdsn2dfn1fyl647HfBc+Ak82O5dlsjS91qmB8T4ZSu+ZaLrOoRotnDG43gUuYhAdCMJxkLghIBBDakFO4SxuhSn2WLdsC0r9725HhP6rH2Fh813gKqeAA01hihBFBhZAmoC7BrHPLel7fBx/NcRjOITw/7aXWW761MlYDLXXaMqGPhMLta4ewoZePjUr+FlUjCvcTGY03e/HwBO6wB+WXL88vffjVZ/veph9wuZYNmAKUEu2UnNolQenTE/vSyHRA/Qf9ghKmeP3bT7tnsegnmEMC4hDvAT8zuw8WzZrfkVUGqXeizHvGWnTiY5xJucB3SQOSzhYBqjkG1mTlJtegdJyJFnVm0XUVevVelMpBbH0w4IGHLbhO1G62K4dMos3CZ/sfvA5xXfvmQc2yxwJQ+A9QgVeeEVuKF+lCuyY19/oavzbtA3vx8K5RkqI3B1q2PftbTA5AU6iAgxHn3G8IFp6DDdLVuosFAAmBW4Am2bjcKlm5BGaHtvbuUOznnW+Kp7/EOoklk4EoJj8HQIq6e3Ts2l/scMkAYWHuO/bnoF+QFjRFB8dYbeEwI1FczCB3/ZtrKAnHe76PUBOyDr6vsRIF+j5qt+xJCGLoRC3H1ugGxq3ep1Ntrdo5NI3TKMwhwiR3XBZG8Il+fVYAdQm179Bj85pV1f/pvz4MgFXgiiefTj7CBvvT6OpCQDsfTCmyotKUx+9JN+4P9fhqZgUJEwtO+/Ko9IsSdnvGJF0RkcGNEZFdXktuQOCN2ExnQ4L2w6t8aSOP5caFZdCODwke5Gxj+LVlBQQ6wJuRRYhLhiquqKrg1YW/xttlDD7kP+7iO0c9qa3fu7Ofyv/iuNRMdLcTjlHIoX6zOR5zToTTiMXydmQmfx5nbq+gnXjmvmtyPSOVEffVaOncrp73CZ/+SygEfqnUMtnCxVscQyJgOfogf+gFokuGE2hBCDTGBFIvIQOyuy8hoPQYqvi1DJbhxB4ZTseVxlYMqw/KM4Iudnf4usjVYDRU+m3ga3XHTKjoNIuVFkFzSwLr+C1ZA3YJetmf5CpSwqYpqiVyfzuZjQGEZxvdXnkrWLf/S4y6DHnvI71y57Hzj8SrfzRVAR3gmPR8I0SF0wEngilCRFkRVde3u/oAPAHUDQJu/VXBn5tbkzb9xgaC+gDqfUGs2smsT+/OqR7Fq8idsVs0FOaBqRijURFdGh5JEF0wdrLJFLHJG2JCZbVcXPQUFAEGmQFBhPbMQRNEcvOb5zQBwtG/ZOiSOanH2F1m/epTyiXoigO34qD9WCPGyGbFoiCgpcsrxobAuqMPQUBIYRv1RE7MhX5Cjyh/jczENEvoTCA1g0OdOJ2F4bShDBOGseto6AAwuSHuPePitszZMNggZRZTA8qEgXaQUjSqAFOD16Ql9phQAKJ+WvaQP/abvi2ux3QSlURmqF5YY62TQ/sP0ghXSnIdwaKnmYBZ2WujEZIyEpIkaArqHvS3ffsH2gP4wpgU7O2O31V2sHkG3DlzsnnI7pwZSFH3dxAEz4zuAAZXkrlDgE/0JPJrvsyshKWFD+FeY1AJww/MAnDciSyEtFIgy3WKUS0rt/kJjCy+gpdh1wYuSeyAIE495avhGBPC81yf0jF42zcz0rTOAQzCPVV+1BcAOMLfenLfOrOT0W+fs0wwAAp7kgWvOf+lAgAgE/DIxfOj99+/1XcKA55XpG9smD6krQxpkwEwCQCF06++c92OiQ0Fa9A/MXQAVP0xEjuleqsHD2ABAA5MJi0lKFU5BthFSNLgl4KlOSrJmFtuEAlgzVy6PdIMIxH2t5JSXUj4A26U0voJjAsDMYIiJvQQ4QOP/7pDtkLrEUPJkIACKOMf0JDC46A4wBreGf0gOQt1q/EUAexuswz6s0CmB8Xwl6Gh1xk7PJhZRdakdaSXRkFULbw/murCcmvUSmGojyec3dLwLvkkwZ4Zd1SBRcp1ChXkM1g9CYjS+Y+VSnzCDIdhjc/aYEIitKpkTY2nWXJkXjsmDF4aOAc5M2b7dVr2llOPsmYmXX/FZx+s3/Nb2djfeoHRgU7Wj1rnznhUXyFvx2UiuACNkBOaKji/M2r4SO3vDHlffI2wwCJnCdeBfQUEGBQHgytUbTGnWIGM1Z0j/h5XIuIAkD+6TcoAYXrbUmOUJtZjePHkl2b5ss6a20JjPqKrELkIvtMVLm/YcnhQcI4so+gWWrvkdX0f+KmnTRH50Oet2bmlDM25dJvJz0T4h2mGFZx0+LL2yrcS9iaxti836bpLWNSsJF6kudixqowdu+aNnRl1F6Favkhl5S1GS4Z2IZfIVsSYngm9ZZ0sXqhddOe5IS6ZFdrlhCNi1RhzgfnW7qvDRz7p6YCat/GkE3v1KqCA8A56G/gHfA7dbWYaqwSgat7FJn/YB3rOEd5f4/rZNPMngvl85aEgwbaDdPD1G9kgiIlnQ33/T5SxQDmJkJI/BFqgzKhoXAfgfKLwiLs36HBhqlEbT3u+LvIXaSifEAx/wmL7w4T8UhVoZ5aRkeomtevdycTPpalTGiBwK0auwAQQuDwAoC00K4GzTKUXFoOjsZ+YHyQbDiEGB0SJdGVnJN/99hqkSqd4kFZtdct9TOJ5q6zOnJlfhbABM78FdvlYceP6Eh1fAGkPWwNvJb9wpCVJY7pzwmLgTfQg+gDlX/SVf04Fsi4+mpNFxTPcC9C29LabovNrjSmDuAEJ95GY27rQQG0gC3JYx44MsLy0LEbkl33KIzNd2NbzEx6mmtIbEfqYFEBQAd0WTCT8RkdIspQ7+xl2QgRdRcgBQYrNmruIVeo96xi2IhVfK9Bh9BmrTKEACWUd3/hPvwpv7mDzIStak0AH0JGYtgJL8DJlgVTI0FR0lqnKnwNq8jam1tXP2xJyVEWUBMs9OHju2NIXXVW9RYa4GFdC7fLEnjeEcxxUejAf0RvID/dJ8oDnLRWRo6T7w7F5KyApAVE/31e1brFL1Q6PAPo81w+TGY/pkT4OHxgDnxr0bAwFoBVriDr9sLboIAgRl1Spu87+siZ798fwI2X88Rf3YS8m+0xLRn4AvTtgOwopW7CYYgcKtzV7ugQTZTmTKpm/Yx5v9GKXw9bfsM59MSJehYgriL1RCDRPWGiceO0vysTX7FBsLiDtiexxctkKGSCUwnXW0PfHQgxBQ5V9o6P7OFadTCBPAJQP6wkmPCTWpSMstK1TdQB5MLJS8IJo3+m3rRGKoFA25UkUOAIBiv7Bg/6wgYQWwGyofmhy/TFVFHBfod7LPmopcKQF4FUTfAkbD9+dtYdq2NlidTplNgi/0+h3nSoQanhYltTBBNGPnyYGumkPhkHrwBcyDZxbtU1LKqA8GGzQQjnhYU119ojczXU6U0aFamxVjIOHh/KyN0kCkJvux3k4CkFgQhV+Knvn2Kb+1tdR2VtuUOBMXx0askm/jSmGdGyuI0OBFK2y1dI5dj1U30jPkDFjvTBKSkdrgGdigJcCF1lQyGUVXFOb4rmLB9egQUi8OiqTgccxIsDlGTPHD1uH48Vgze9SWJZOldaQBxK5j67OgFdYvZdgO+gXvS51TNX8APYzxQAgicz4A5nTFapKzDrvryQ4jTR+KPgALQ4mJFYPou1hBwUoePuKdg6nQAhug7XItR1zfhQF77JB1aOyuDXtv89jzs/7YPyixVCqRUowLlioYheEHNDXb2C17Ux9tI2R01tr3MuzCp7Ky1e6e3IY6P705fOvqRKypY5SXb03HDCSoBVFgHWH5A5yCxpNSW8ZwWxDXV2rtqhKhjKdPJ3VAXvJWmFvIPEYEo/GUUO2eLfZ/3bB/3eCl0WpQiAm0lBrL+BIcG2Y5W1SxYuRqjx7b5EGqY9eTLiKBDUSN2g30IL3WfGURkGIKpdRXgkX2v+MrdiDDqwGQz7Oj1js2Op9exfSqVx3OnHapHFVt3Ohz1Gy6HadM0EG8UR92YGPEc1g+jICZnvjSRTvAokHxE4xeOie6ixfBBL7S2ujfxQTlWzEQL485JYabgIm4cbZAWE3moMA6pnxZowU8Wjv3h/9q5h/+a/XIwjxY8dijWXlE9LKTzLe8ZCwugOEGK8AfOhaAFdyLQiGgmSVLydzmpVERabntQ4Aj7Ffs/JBdFwvaJTn3jJQDbnXiAig2Jde1U/1uEZ0XiX0cAmGDuFwnQICSm5VpkGM2gVjGnamBIHnMGluWzyUBq1S7fNXGRfL5ssOZbYuJa/AT+gq7jp0qS4kZFnIOTFsLs3Ak0pAk389q0rwkrruf2Ywc61G1qRToe5a1jvpujI7X7CNYXw9cAA0+7Enk3lh67RY5PJnnfvRgIiKLrvsyPyFd4g77sMJci0JUiiO+x7Pvd51Hr4t1cIAYAfvIJ7ya4SUcw/xeTmwnZHU+G835ZVc9Q2KL8zme8N0l4QkoBrdG0Qdo2gcAT/KWKDvx3H3Aw+u5RWmqgot3vAbkngHgtCXzTmXi304O6H+641c4DqBz3lbXXdM5D8CGoxXpR34G/lf9oJGAckTDA/o1uF0aNuJHyJOUqwxe3J2bXS0uSrR/JB0yKOI1Hjzo7i1czCEiwULiEUYm/n/23jy48uu67zzY9x1o7MBDowF0N5beNzbJ5iIuEkVRluPIsh3HseN4Jqmpman8kZpM2VUzlaq4ppKZKY9n7KTsip2yHasc2bEki6IoiuLebDabvS9AN/Z935eHB2A+53t/r0lRZNhU5LJs8hTq4bfe313Ofs8918u7lGKPkIhLRX+dmQ2Z+pIAHlG2P6m706tIMAY6YEKj5hJv6q1DJFuGPYXAblYDl1cYEqJJRU5P+RL5INrh8nOzQS4X7Nh43FE0jDISggMxy3dxPqbC+e4bSGSpl7m4N99DiVQGbA/1QRm7ohlOXgJpUcpuJc0t1LDx5Id6ZU/SmQCoha4UKqALH+NHwtxLOEnhrLqXpICBY3YioIErV7wad1SkLvjUEJUHkGhs3lOg4cMXjPhLD/tmri787k03GgOfpzcgKBoIMBw0E8kQiqKErKTdq/s/8MOLgZbxejP63/ym3/1y+8azv3/rs//f5/0EzEhJOfHUrkxNL7z1nQUEDfoPwAY36SwGYdIFJ7cI7WiS3CBJxku8xBsCfqYns2hAXIG5+TufPKAfPgaQwSY49e+fseI0d4qEaG/C5JrY8JduxrRgD3JJdI5Z29BY7xrJb8PVmHFScvP7pOXXVfrCpwsTfp0khMNr9iqLzqWCfCnVNwhCcwVeOG9bKVaZFrmZQTjk2U+LPHM3XQENCkEIjRuYsKdluBTmWja+ZDH1/n4PoYF9/JWwpI4caFme1QAI/pvIrZhn/6jF/uy6PVHnt0gdgZIHJQAwCLQ64msBOBSpPr4+7NMvALFAp/d5EnwAzMwYtzgbEGX6aVm5rYzYiUI/nlm0/2fZ/rFU6qoiX91BLrJjmClmXyrxrAz6juc2PJArfoQM2PLNAXtX7L9IDXpiy7Kmo3XztIi7bw5FKhEbAa9vRcRWvWMvT9qS6JPkCrXLVptmqTA41Lu47SOcQLdu7lhHhmczJ4eT+AAAQABJREFUB3bm7FLc55SpP8A8dRVBdJJI2EiTCx7yx+JpAIJEIKkbnNNd2owWJ8DciajkDTE6nxZ/JNva1VgGkZDI+eSsNzMqhLepS4xka3NkttSIE76IfYvLJwvSRE9d89wn8SU/xkIgYOzWTT8maqutzQpZEQcXgYyxUtjnSuIxlm8XrthnzkRReVgFBTVplWysprkXslQEFX9h1udwYjG3agCC+zhGmQauX7GHt7SeEGY3YC/esPYy+1yL3/p2t52pj17pmfEVUGR2CTNIdBEHp1QaMgLzOItFAwArpTbjKVuJKSZZHG12CIlOYWoMbYN4zZ6esXHHb4xwqANjgMcBuouRDabXpRGLMdUgmuIWARfk8cfrBJCmErQPc3ddOx5jQCFk1fNbGXaA7Mzqur4+O3fLMlbtIjSDLtJs40u2p9mP2zLc3p7XKDOslMYsNIUA32VWMB4Fx1elukVUK0SlA//1uH1F8fo81sTGiNP2hOiIjdrQ6ZkDZJUdQHN4GDMPoEP+0QPeXQCWDNOq5PkMEXr0G65TxhR4qMLKsZWDwGdn6hO2PGIkGwTurHhlPM5Ws5FY0SyLCiYW4oqDYImRfwJJfFboBP2BkIfTI8FA02gFohy47/71z5wgLFKourSYVlFSlNhc0HYN9512p8DZs/4YhhZMg+EIPUklu7sjFGKUry/Yk53+GGsQWO/NM3BCAFHa3mLVoiNsZrwwXYwv9GD2H8fsszlRztxDjVaDqwIVAGRYsd/bsl/B5QFpgQ/bHjdY6Gjr3d435/FRABQ9xxQfKQ3Vk7C7S0O2B8JDicxzm5Cd62pUQgmZGxeNcFxgFB/qsl3UK59jnpnd5+Pu1ADG1+2XEbE6pntXiKTVQOAcmZiy/flWKxJbkZrlL3wK99YDbUmtThjxoe+AI4Gyz63aA2Vu2/975xP2EDlsmPnUexAxnPvqh5bx7g2N8Lun7z3SCL/3QnQMjYBlpTq7Le1zkB0I9DQjP5NUnbkACohB+kXqfCcZzYEQRgZ2qwREK+iM9nYvQG2d9/03qLDv/QriMTQfdbMdGaRK9BE3oWnkcj0a6h+qh9C7a1BBJfQwwk206Hrqx9OH3luPv7lj2CRj8boq0KHkBHRFvU5TJJQDDuTCQ+bsy2cinx1MOL88uyzLec3o6CbCIgBSAPaCrRXkC3KnBixhpGH4Y84hq/QcFy7KrpPY8SDMU8npTdAJPKHPYSwBYFThLcTELq4G6dvf7z42BN7lS/5YHp7vBle8ACTQtesziq9NS/f1CxQ47Dd8vGideNW7/ohQdwaRVofZe8aRWosLumecfgBPDqsEMJ/SAmPjlVdFsIu6RTfySrOOqT+mC58DOA4HOvt4P+5BVAmISrRHJoiA1lZ3bgYRSWzCLzbbO9CVmsb/GiSLn9mBPJtlh+guP26KWSEsPsT5pKX9wyMJdvX4NwN+izrPJ6kA3KaxANQK0O3TH27hwGEwh4AjuT7cwTGH//jIcQKLuYngIei8IrcobgwWHqKjeYnV+IU3XSVF7uBUxfoaEznRyRSl6rh9RR1CN+7V7BaVgbiAAk2EhrrxC+WCSIF+df/v+M/HYy/oxPwB7NVzfdr2l0cziRdn7SQBV9IzoZRBAtLU8dgh2GCoknvAawhmwaoqIjMDJCO6j9VWQD+OfMYyucK7JtcD54ilAZgUZjDOEbQjJNpn9kSlJ9UBsBzAj0lhRSb5KKusi7UTqh76KKrSOOQCaaU4WrAYo0o8np9ry9Yg1kv0YE5yA5yDuZ7ZjPkc975Q+Kbj0yCUTcBYtceqhSzVFAtbYEu4UkgQW4VZtU27JJzt2O1RPRgtvAhQwulK2xBmQSbHWVem61h3Y3EnJ6Vhs4qsd9kHmtyldV+BChyssMpc333ri8LmQrZmZ9NbtQjnE3rpnuIoA0HKjn21x46LA72zaGusWvYCPPKYPssnyZj6ZGHNXic/m1OKI/0OwY26Xg7HGbN/mumrlQKsTtu0+gc2R2whvOk1nR6Le5mBhUHGY/IS8cpx5vdyrW7dLjrr9s6BpwSFmPVKrM4ilXwgNtRuPhJMdOe0cRd1AP4S7Ci6jpECxshfUhxVLz3DzbAQfcAMDxYy/BkXPoAazWCBb8CBfT5xx4twbAC9PzUtJTjyOeUtpsKA1+7YZ9Kd0wVZgvnj0yMao32FLgWC6UWT2UC5MGbNcA58RfOurwdzNBWLCLua3bpjfosp90uX7NuwNLOfS7NTp7CzUVfopuXZwWWST9a2OImRiCRlbTmVlClAeRm7SoX9RZiv6+hwO+RNelNBjLQI8xLIL7UUdvTO8PkcAGxhZjhMty5m2P/eb0+p4YRPQHaxSiuAhGSl318ZGW+s9arIN8adcgDqH6uKvBiLc/4VnG0A8pVOwAAJfRJTUv5y4RB9OwrfVMk8cGrd7b0ujRllTmhrY0rYyx7TNHrHpSdAH2Lf6tD77fZ131UZWCQoN8MPuAgQus9ccXB5ENx3+fzmkTMuBFMyMzobNq8u2VUxjYc3rJJEFyJ5eD49xqRWGAvIHzQLptN9Mdsge/WUl8xH6BvI8FviIT+/5aP/yCN+K2VnJyvDEte7OU7Pz06Jb1x4I45zB4Aw6QrYCMCkN73BHzgGIHr4Sqg2D7DXQpCa7SRKHbC3luyAuAF1I4Vg0DoPHfKBAyGDgdSFtTnvcWLAJjvg0ckiFur56I5H1S6IxJiP2rUV7SSOIU0/9fkb7oM/s2l7ayODlKaRm5HAToBjjL1bSFaVkANPLrVjCDFUBJLHJD0dfA3y6UzmM6jAO8a6Z9ER85wpaSbz30iUirzPXbccsRoY6afwsXoA1iEc/4iXBpLe6GLmMNfdZdAmxoroBNOF7K4nwTb7VVLguh9WqOjpw26+ez3IhcByoWnwJbBlnmgRM5eAckUNOryrKyMPYQIAopMP8da8TuFloHO4xQXY3Jquf+QPhYQKC/s+8vGPeIBCxJ98to0KTIisOIAhnSQuOtzbsv97xR5QSRgDkqh+omd9fqNIt+gNiUed/O35oYkjEddx5ZVBBAPDWJdLAxZzsv0Vns1oazkyt+AbJHDakesLkQrThrsCL43a5zN97daO2C9eJ3yXiB4gJkMplIxghEO0J1c6MQp8JfQnPIMDfpv9JU9n92Zyx/mmNbflorB1uO3KyubMYkYrBaN3y6ceuDl6QHYWVQLm2Sil0AMaL/uZL8ajAjU6BuWoAyw0VAkaAXXRbQCG+LXkaILAcMpGWVncom4N0o44rtYtBj2UgJwEbQJaUnIngsAL8+6lkB8NAgJ2UAF2D1JADeWgejEVEQQuWkd8OsJhCIqqUnk+7Y/BDVItT0UwQ3D1rY2DRWArxJZxuGHjanIanEEHgcF/AKYBUO3QIqgVkRgIk07jgMLvAu0N7UJywYIeelh3NjbyofKbiBQKdTts+I3hOsQSxWZsLGxtIX8BZDfNQQSzugxgg2lqBosAwEC+xTgD3BxWZqAwZJRCb9NMoPUHGYiu/R3/cV3w3gEXyKUb/jhKXnbcbs1YI10L1aH4srpJMmGUfOUEqo779aUMa8x0tSMGOjBpO2sTc9YgKmJ0cYcHX9QrW/YEzLHENoQXw+setJbn4+tDghmQjmLnZwrAzYjix8aWPFUXyTOA1+ftkSVPj5EhaoM7wEGC/3hPjetne/faLsmWq932HLtCSQHl5/S61UFhJAYdss4qT8gW3O1coUXMJwDQA90UjMnlTXdy42yuFXaT0An9OGzOA7uAgcCeYGQAOvSeKp+eCoDa1gfi4wJPcyri8hXXLa11w5joWxc7G962B6sNlQugVvAcWpGnIcLEYikLVAFQZizH7j+qMGjQd9OKG6Kl9uk3bGw66isolu6cJdsBKoDY8TfiUeImeNabLBcZ9evNtfarNdZMdnuxmVdvW2uhTahuX5eftY531V1UH8KO+UtWlmFdrC7TMb/MVGQsWL3kMGONEjwjZs2OqyipUL4UWmdk4Ahr8YEza06HrdyD6lbckkS1DZ2PwUJlsGwBroA/QbutUwL04bloFp4lT3BkTAWAGSHeov9R9AH048rqrTBvOUOWW/JzCJ0ON3lReJWwuBxS/Hn6FiAgE94RWDzsFe7AK+Gxo/v9VghNxEKjdf9vtz2CKIMd5fgwhV2h0Xp9eiZYsbl5Bfkl2VupWUTjAalpO/39O7L5UhYXh2+uoNAD6xvedVSAHXIBbEW+yLcA0r++rTD6MC/3u1g7m/b1Pr/1ZIo9xTIqIcPopmvkNRBjt9/qm/cgzBCGAR52kHaiJEIbuvSdWXu6yh+jqwlmCL3NAqpgxofGssLqVIkzfeD7cReZ4fqlVR/60VXrqvdbWJIlqZG7hJLpah4Lvce4XL3queABrmBrfV+se4O1y6QyT7HP7PFb9Dzd9bW3/PgX2FaOdBZydYwM79DztFqk7JpfMNJ4zNGM3KQLNi5aHp5wk8MXA2hmCUxrmPbjETbznfBxeUiC6tq4bzT3KxL+mcW5FYXpaZXiR1RudLS5LT1FMYjuoJmIDHuKOn/J86OQDsRhx0bXPc4EeITRiUemVzq0nGNPdtiaSJtUn++M+Y7qAF/H80c6xzSNP+iEZycmpjHJ1mp4mvwp5wNk1PD2xv10inldbHi9gqSr37HvCznBNf64gv0GBO9w94wfl2S44Xp4zv0swOvjVpRi+8S4+hdd8QpKDzTnPppCuyZZV8KjO1EdCBPY3rTbwkC4XCN3EnZOp+1/G9VP74a/Mbghfe4jP484u62HsKxKlqwgzTcrBwhPBb8kkeyr4EbSMvnIAu/lAZgTPCNgNGgFKw7DCzHw1wVeqZTrWmciCvNzMEcsNlJDkd5iXV5PChGFucQB+4S291KRaBJJLPmenv+vPETd8nQbNkCdm3QMjjeYPdwp5R45uGbpQ7Yj5pAhXSIplv1pqnG35ncPVMzfjh8GkWpLHLmOG9TuwMAHYDvS4GkJ+0MgEeDSQUTyW1qxnqUJbvg/LCXInQO7nM+4iNSo401Gmoww2EIeVuZnSXQOxyPLJHT+MeFSvTSN3Sj9W/aXZo/pSdL2IJ7CWF9hPRUIFOQE4WipKE0sPZfGgyuxr9fdV8D8/Oz18eCJY6uMAnyvagh3GNZGmRAcQztIe1BaktDfAw/7/b9PbSE+RnUckBxsB7EBsKA26eygl1pkKIbu4i4F7tNjR9WlkAwAtlDyjwaBz1P/VKy7KpdrAML61s1o0TidgTLQCy3JrbYmMgzddYeEz3n2VdWbBcZZxGzIHJ0f32C8KKrJX/J2Qb+hmZwybnSIpIHrBlyv02MxoXqQYndE1xByjW6dZZuiHnvwQZ2UlGYxCYBTGKByK8tlLSXBkRlf2pyajGQQAu7Vi3aVtNjqfbp6JGmp8h6jSAcCfB2G81Ryto1aXZGVyy3GKDAcPfiJ+AnodK9NZYyrIWjmke+4QoY9AxID2BVoKuxcBNChE3BkiIqOzrYmtsNqt0IFRXUNbaGqBpsKWiJUb0j9DZEyZCTFIvUZcI1ILbFyjrlVV2ENrL0RWeOeGU3qx9VlHmL07Ul/5TCmGpPj+REGg5NwkFyYLlFYLEQ555Pj/SK+jlY7VBMt8CUOLZWoniBYaMuy82XCaQAmH9Dyw4Zu/f3WP2NziB2Z7Mxu+4aqkjNoMCj6QW1F6cTqa2U3qip/kvVRqGKNMT9G3W/KjjYZw+WMmkQvsuUrwMqoIuwl8SnWfhBgHRzqmKMYt+iX7wz5Y+B+W4t1dfpxx1HrueI8MfBHIuJQbbE0gMSiR1qTrgM4lO95Dnq2XYcDGJT9SVbSWmMlK7YkCse9xR6+uLoD02sh8cO4Ha73VyqJlKOqbGccRpZE8OROkNCaS7j2GRgTKIHeyQRFqXADlHqpx4hDA1BbaQ4e3GAUkfaD9B6ogwBh281znq4XuLhjsRRXB4PeDx9hOgvZALzW5/sdBeOEAeKZZz4bYRdxX5RPFwH4ipgfw5QK/dDbR5rBnZBbaWzU3p6yh5v9MUK/6DQebm/3UxItLC/5i0AWE2I70bxQCRyh0Hs4VBu9Gcxnwg3AuO0fsqeSc7no6CBACMS6PeBewNFvOZ6tbaSe/FJ1BvfIQQEUF6fQEWFyimU4qYmQqxNJBkPjzhP3+VOD/Z7InrkOAMWXYDka+Ec9fvoMm4xNRRvg9pLvuMwyav16zoLdF3PjP0wAstQehNmlzgeF6MPz/VYi5s20zPGGaO4NPOdu8K4F24w+D5ifsuLbyoVJnlOkcJwyzBWgIcPTfi5Ne3QoAP4juWclTIgJhK4Zo5Aeg+sXe6LZJGrFV+o1lEw5QhFMOQavARuX3ddlnznopdFMJqwSG05jZXvKCsdnmDM8LKJI3bJzgxYTuVFUa6t7NHIQFCKr5cXIFMdiYSs8NvIGcKB6Wosdy1ZVK7K9hy9e9Fu7WzZydhVEQ06Ny8qKxscGXxnkVlVd2tb21isv+2OnT1tlmQ0MuSMDYIw6+Bz9LtWtaXdE8hQAVoByJXoMD0vJQOQmoE8Y4mIypvpL1lHom97QTACGRkR+kzCfLbOGV414YDXd94sDy66LMAdn7OFiO61jaAqF54+HLV2y7Qwb2THT64U5/qM5LbMToE5HN9yIatJjZB8pm7JM8b3WCqd3hkbpSPwTvx839b3jtrMX9TarKlannKvvowNRMsQ6VPCnP/fUAyAC/Q+Ecf+wd+hsobBrfm0xO3owIsy+Id/7YX7K3/tVIveGI8/0h5Xz3utwLYCSxaGjOwxjGEOUVKQrA31Yd0ArVLGgRIL9ECg1D/pouwLDVvXYsLQoydioQPAwIB6vbCcnEwaSRUUPfdS/zY964N7vQ0aS8y6qDkG5rf7qmUIbuObcD9wGzl/xbRinhNJwjBg6hl92JT50zpJOw494pwtoukhk9J57P5GHED4SdZfqRp0Z4qdggGI1b017GwOm4aXCM4UICn5MGFR9/VZIxIUT5w9m7ZclSXFgIWdxDLbt9RLxieO7PFrtx2k5tjlvN4f8uE5qdAmYI74Rkv2EoHEwB3xAoCFHgHVkNA5QP7SGbNdqbKqHY5bMtv6DE6mISEQRwP6e6AQhWCWRyE/fICIJYHBX5t2G/IyfeXwN4jqMEXoU1++OXaZmVwLewsEYQaoHQImoM1hfYaxB4ItJE5ROovfoNDXCG3VAHchbPEy1QmnjKudH+wkodAOBPm/7CLnnG/LSvtoXxf8jf8lyJBHtHcVBcZKEE9IzH5dwQW9xU006X16sojF9/No1d8cASIdrelFnbsNkhCPNcfFSwA0wgcZSOIB5Bjeg+aGBMRpebFcpBdpp20xjxQWCFnAJV5IzOrrwXedn+ZX5tVvLL74Y3SnPty0yJPuZM5AmzWJxTNcd4YrIjVxiZB0fmLYmhofhi9ubyc6n29/Lqfz233UIfXWvrWQCAc0DACcwc1lVHxZ/o3CgGqaM+i2yHRzNtHrEiCuZ/oednMWEDtwty68H4wSFr7/fFzUBzSKJqgXfrBOoYfdSBk/D0x+3hlUbXDIyaQOM/nJhFEo0O215dfYYL4M9O66phzkQTikc5lJe6rfatoysoKiDcWEW9W9lPkEicfa2ZzUdgP7k4cCWoGG8CBAWRSGhsZye2/A1YwDk/cVF3+cUPz1wnYU3GxFPR6V7st0n64NxQpwubCTwLDw6VCChD2GV8QU2YQwpdF5as1O4mb173Ay7QhpuaIIPyZqCJ+ZINE2yYnIhqk8RIVidns6Ou4C7GV6N9OOmRs9Ez4J7LyHTtvgiwWYiZXjuPvidejiFPXzybEU85tykfa7cRzOYN/npdpvwLdUnlmrfnLanSGOoPiF+iQKhFqAr203Ecbgaw5fjCi4sG2UOYJYZSg4xVEg7eMSe3R5I5rBt7LH259ymJmStzA/zGfZAqeMJyqhHGuCkJAtcVtSNKWv27XU7o65DTrB/6xOPRAgAMhAfNaFOwGSiAqjswVY5eMATJwa5AtI+wIhPeclUhtQjjFQYI7YLRPUPj4W8CDe6/bFaEtmvWi2J1MUcsT1QnUNABaotUiQ+aefO+ZNUm6JuCvNjSheRLo24Bg7HDZoRJsXAJwaG7WyAmWlkXugrBBu2H4vQmH0FyPXPabCCMFSoOYP7Gdgn2gxJ/KQfcPw9LOEpO6RX6LR6bXgNugLo7uQdYY0cgIHEV1KWbDvbTyGQ13hYRPHd6/ZAc7QOk8/NLtscGn/oZARkUssA98ZJC6nrC/jScny2p0+GfU+qnUw10BIoZ/Jn1PPUB0yrrbCvfCkqje7quRPZEiRlQZvfTPdVtkB6tucYbG3x4+J6R+ZgjWTFl9LYg6HdN18B3u72dZiF6jnmD3Hr4LxgBAGGmy4KQHdhzg0P+RlGMqzmt/rtaeSJmAaBMeXiSNubWwNvze1m0+IAPZRO2IqfLMxuI/r3QiSwgS3HnxWyZYoQOC4lnY9oh0/jmKBdAMcsRQB/oG4gl+wsu6Lty7Hk89jpbtPyVQdMwcBY/LFc31krmMd3mFNN2NsSV9xqUW7SBZHV8oZdmfOAbQAnMGYqARsaPVmt61HSi+sTtld7ToRkkljLlapJ+BALwIhVAwj+HIlbXUrEhSax7Xcizbu5xDYJylVvwx8uT/ksQZaIFI70KXysHgDLxFY9zCmoUB/4OnK3UTdgnqyhBY3hZkBJgYfNN4vtNEzZyrBT/T1CwGloHaGq0fP3QJhAIuhDjCYoHB4DK+GIYreusPI8gx602BxYB6v79NUeXX9vQzgWA3A9nrqFW/ze/eK91PbeG/WRpdGQUNqE9M4caTQlbHC8z/r6bVySC5PgXK+ROwpoS64347hQpcM4dcdP0FPFWrxdH083UlF/Iz+h+WL/PjlDW9i/VFzHhxu0kuhzBAsOXFyrAK4x2B0CCGA97VeKbWnEjwm4gP+7E1NF4EJSzIHf2l1qI7P2qr7H/ctmaNhZ6iay1PaxakCvwIMDkpzTk4VaJHLBC7D/WaEcdQWu4pSQoQtAXQjrtThGRMI0AbkA3bqQPcDabz7SIroq3vI5K7F5x0OqTylBXt0dRN6CmdHqMJQgKq/zdngAwgw0wmMFukXX8QwwpujE3To+K72U/gQkAHX08X/CQKAZEVG1n6UxIhgExy8+FemNWLZfJ5hLJVM3qBWalVT0al+YjxZIowm4yJDikrG5kpblPsNJyZ2LE065Uki9jXzxbldwAI2HW6tCeO969QaDQ7uksjnxEq8URZFsJpYu9hYcP+7PIZJRNNPS8nK8Heuz62BRiyoHkpC2g16l0wDqDLLxC9AERpFkAUCX1Bh09XHViRbRvcN+x+WUMEAnn4wfmv8xILj5eWFw1JeLoKAHpYHrqFBBg2yNWUFepDfjAkeLQr0owh4ye/llJ/ILojyGjRi/k6L2cwv2YIUl2KtHp4eZLQFjJP7BTnZwyty05694PY/VvzubBKdAQcwQqf35jE3Gbf+64RIGstluCBNr0Y+ZJWBi6mtr9gQoKYUbx/kF8BqaXDZUDWZ4HbZsbMhlTJooDPODak+pBLagPVloe8TPCIhiKdSbbJwqUu6o88x+t8SnqAwtenPcumq8POxPKCTs6XybGdglD/sBYCL0BSppmJZhKvbqbc//BnSxLC3DRqkEjrpKD8gkEilMJ2bketzU9Rt+ixLI1UFeODzcAAp696xdUcNB6XPrUYzf6KItbDmxXfOn3N+Amhh0spurVp9qb+ujR7PtjR6Di82oTypSFSQtDl2N2bxh5yctJjRBXyc8STqn9cftcJlNarwYCGIPsE9Yiw+QV0Ms048JvUMJPncpmsUiuTBp0x9SaZAr6+4yxX3IutFR7/jT3e1voflhkwdjsq7IWC4VtF5yQpTk2muv2U29dYQ8/sy/q6rtHY5yvPgvvusl/N6X3QAIyAnKTU3buQG/jq+uqtrDIdDUAaa/sIaCHQVWoGSjpgNoxuwV9pcD0VwZ63BYm9R7x29RST7EvknBNcAr2G+5fsczUqI2hem1muN1fmlsbPKWW/YlxTsZmWk7o86aUrYTSJMwbxaWaaGv//rz/vjP1jo7DnVDw8atyFiHxERZVZY2YzfU4V8stM6GqNrQIF9kaII3qousG4PWrArdwvMkERVS6ncV21PsXgpC4MHqNOzqAfXJtWWrZiaNkDa/43kavsqpBNr+TW+aXBMeAYtRMblpGeKb9PyrSX2FtmCXMl6HQTJZOzvEPX7DjyFDDA/aAkxP2uvddqLZRkUvVLi+JgpNQaJ3HoE8nObfeClOq+EPIXy33zxuM9jhZ0etkBBfzQfyJAN3mclYYd1BLJZ0uyYiJe0eCdMPkd1U+hSrQJ/c7WvkgNSaqsoCJLZqMDF5+eW5kYmMYnVXcfFOQCEeA3M4PnHE8IUD3zrnsdMkdwHQURi+W31+3EG2mDV78YJnvgH2Z3jCYvatBugT2k5cdGe1n5KV5Op8pBY0rVoxWf7L/HpbgyNqxqZlqYtI1s+Q1YjG6LS32H9MFVhPcRJozfEpMgDCB/GCmvXHi1Y66VhdowL3pDn2Yt0DuHvgzN2qGwSOdlK7Y8M6pcVfCt0NA1m2083RtoS3R1w230ayChvEybyoT+EeewCdRvQRjc6HvbUvaQWhsuAjqKt12QGQPzMWixaa3mBmUjktuX71wwp6z3XGF2hSFINYrJPTUtL8uy6LaEIzDzwGn4OXhKqi6sHb+pMrRkq06v28F+YxET+sa4o3uDpbnDS9hFN64eP8QPBgWUDjj/Ne9CyERfXA+lZdEGOzbhEmCR7fQmcljarUyck1e5vJcz228h5zC1RHDkB5gfWh/+XI4uJB2sjx3yIQ53NxDx69xH6SqvphKd+3dPx0pnNpWMcfv+Lnv3Hc+SeCAzh00Nc+vAQSoDQXuUxEzAUxBDNBaGISAG9e8wVdDDoAAwVPLjJ8GvtOlognO5YuR6WGEMKTjC/Cok5vIUbvehbyTnQ4F0Ns3LrpN5ndQjDDDYGNdYRacCDi+kxDrzP7AyHKEXkTKBxA5eGAQQzA/UiESPVnNKVJ+RBTKOi6R8+BMBwz6ACtD68HJN8lEytoOAfFHsP1HxlF9RH/AZcYmjHW1Qsh8bembNh/QYJSyRX3bgSg/qB0q2iTK6fw2ZVG65ZRL9uP5dqWj/PbL63swP/Z61K1Z3BoY7OK6Nbv3QrzNAVKN3RmwpAFLoEuzKBQKwQBQAloXMHni2TKKdyxoWG/MTkx9v1bvYPpYf1/ZmbirogEc3CeMu15y5Ua+7a+QgcCBZq26hFRlS3byqa9rmy33OKLsJ1AqnkfxFtUwN/Zn8CW77V5f3rdnmnyh9l1FJc/lAm9AAh1dIswcT+4YEf2RKm60FqI/gK3goOECC6oCMIGUN1usQQCNMGIQkHfsX5iWoSLLIusARtUMgk9s/JsgzR9yA2UgHX/bgjkwxzCckMtA3azphCzivhjcR2mZcZ2bI9s5wzil7QSsRg6o9gde6XfisUjsKNad0ds5fotR0RyJbOWSc95czLBDvB1zJrKrUyYjR8IoyWO2lfot5idhx9d7vdjXO90SFu1/wKQB+oszAWgwlsTNg2Oc5xih4pseMZ7BiCOiK0DKyVrySqG7VQinEWNJnISmzN4nXEuoH6FeRgUtfYsnxyjBwDUayaaJld0LPpBDgHkmj9r9vcIolUXlaVZP2lmVAfyp/cSwajHspkAgdgKXAUEyObQQr5piaa3Eu5lGSfeWv1AapPtjWjF6sktd4xhrAJ0KTZFVY5nZQBwY8yZxfTRl0bsSJH713kXwGUOm6tStXkd62u/Sj5W7CMLLoEVAJuDHa2Iuo58J+wkG3xCz/bZo2wdm2kxfSiNyNIRa1EPY6fl53lQ5b94wksgowN9BeIB2L3uxhP+UD7bmsHyQrAcv3w0cECmOJidD+i0QUQoJg05DDUuDMGfXzZSUAA8TLEY0mEsGPrd5VYM54DlxX1MQ6bXdPKdg+uZmUXtjk9phMQND770HefeR476mAaKAItAMyTOAfUDc2hUYLdIjNK4BQUFsmJSlC56UEO7r863VgvbX1AgXI/68AfQnLlJT7gCtLCkKt+VjDbVfHTWDlf5ikTgN27aryfnmRu3PA8kOWbeFFfen22HVu2KSoCDgxRwTwCBhw0D+ohk3YPOX6NuDUzacKpVrzsTAKAIkP+2uDArtfbwWMyvp6f63gP0XhhlBD+WcMhA08JmwZU5O9veCzU1i5ASDQ89vC/bmxZQ/WFWSbFAjpoI2+nGShISqkJUho+zsRvA3Vc27IHkur6DjR5/GKbOUkqK8xJTIfx8dWB6sN/euroZVm8++qgbt8HDx4ggV36/274CJ6KH0yyvxHYJ01ACenojVYB60ljy5YQpaNSVdtLlV/groPe/n7WnyA0jRrGZ8Cli7ECAHdJwOiDtAGicSacyNjfXOTmHWC51Qbh6X4WdbLS5CX+MXaexwaDfbRFIU60jF+voALSc82u2Z9RO7PVTGM4SEaSX/BgcpIum1T/VbEyH9Ny0ulAH9mxZi9LKlUHgvvmzv8ImaQdYsZkX7cNRJB7lNz6Fe+uBK9JpeJaeQ4Ld1Xve9zYsUGLQZ00Jw8Y4D9iOxgNSkRkVwLWHOgvdfSQwpHxLA+jfBWfFy51Ue4QhlAAv5AE+KoSShE1aFLAHuAJMO+jEIOz1pNs7lPm+CgjBvUC0QzFIrySc4cMa+77X757CmgIV3L1yjwfighaTQkydQyGIM6pEQDgAF22cNfaVQLoBZDeFTEKHj6vVMb/s4ZT0G/ytQacwj4WkAtp4bz2v9/7mf+D9NBDoVbBoCXEiOqVFk0krmqh2mMZDD9k//JzfQybCJ4N+AntE3whuR3w0HCANsbIAHkD0aE7FPXSXlqLZUTg1owCm1Uuab6/aH7FYzt9wrAAJqY/4k53TssCAWggIWE0+4d0An0QXxE+/v91PcTUNj9x6cZTD3U0+ingbARaYpGh70iqNLPRFsbv9jgethT+d+Q8YFXCjXg4FiSAfYlCav0AUHPANygRUpB9IbnhfURVwAHhVBgxY/WOBYa3L+iwZkkRROOyYRQyL+W9LcgU6ahIRbSZDc9l2fHeja9dAc7MV7KIFEpHVM6gxiNER3TohH4pE4rsGZ6g2JEkbGQ4g/Ib+gd5n1ScMFsCGYOBD0KuRWOlkDxsa9BuDg303N948uwGGACzuorTgKe5B4pTaGwTS+x3vQKgvtGJeWBe6jqiZWQKI1EYeo75gJgwHoCeQ2p8oCENwr01+cp9BV0CKOCvjHVRV0mo15XpgFcAex5gZPaAMqL9jD592HbS/308PHHAtBFUM+N51WyakTWOys27bmY5HOMKBlHl7Yy4akn1FjgRDi/ZnfsdqJhxfg0JDXkFUGRIhAOgQsRJbY3caVYycGeTWq1FVCSFlB+TarQiZmFPCv37jpr+VgxMdtVXkRcwwc+UtjREDQn2HN1XDTuC/2s41aHiYOjxPaFCIdKIy6IUBsdDD4FNczxIpX2aaqyrKP0GF6ZxpVbV/yPOLTBEpJGYAg2DR2r7dqk+Oy9qg8aNkI4Yxt4K2ze3/Y8h++7Q/hh8UcsUEeuuWnxZmudcqpobXzHoPsFMKkEcudRZlsmKVbzAWdbYxatNiYVD4kXzX+YDnSX6QYjj4SVUAkH0ea5GEhACMNCPN9jBlDCWZfXPR947Y64fO1tkFiNkPgOBsFPqCTFsZ8tOlLU8/iuYKoA27bk20pApH4NHoA9A6Uj9h38EkUAltpXatx/Y1Rxs0E3dOG4PVipZM/weOc7hSUVWEX3Z6CaiwpL4M6izMCwmBYGAfagB76a6hAtem/qE+nnBpx4c44C0aP8MaSkChBzcCN/zduP3cvD19KEIGYjAS87YouQICjI35fDrZIIE95FdI2LfUXU+tebq/YEuUtS14YzLSs9isCuCrw4NwTCCnIKO0dDP4KRhHGBnoEbyMV5bsKTbyQvFBJIy6ADq7bD/VordI/o6vQfyM+t++HeEt6IE9iTUbvBj8srb4WY34Z0irW2/rm5ap4RvQrs3Bzjy9Zi/ctmZRP5Gx27WWme7Lk4CFad/sqwI5BgKwwcCWT6oAPWueapyiXhCPLFNsqijeF1LX5nh+QiY5ATqcHRrCNuWvT1j6vJXold8etX91yNXK4BooW3UpXiBBB+EUjawWt+3i9brOtImbcwxEDOGD3c7eBpci3wQtJfXLzW5nHQAOhcfYbkFy5g5zdPk2BgtH0BJtKG31++rJX25yWVK0mypDFbm2mLU5gmAlcd9WXr67LYb9zMuB+sJCPmZlMVT2rEciH8wkj3ys3h+D/C+wd40fej73+QVnL4SEATv4lZYjgoXL7U5YrDZyl7DgrQbKlcDPybDbRLFu+Ct97E/NArn1KAd3BflCSYOp1oGxhWRYlTxkDp/Mk3syo1U9VJXq5YnM92sy6jbhKELItoRnEksXCyLrSWuF3S9KzGEoJ22S2XLhKohEbpt0USIZ+Gl4gMOkRmQTPDIl6tZcYG3RzU//fXQPQO1iaa75wTCCDvS+1yBH5I9oxfJYOqsF9COuZ/rSTVAoCLU/uuHaSdBmkuPzvpL8NE+6TtAROYXBX9NiFY5Bf7BOLN8tCsgdsg6nqER8UOTiZlKpassvQAAqmVde1/EP//CMUykZj2Ri1eqYSoKnobFg5Qe2Wg/+wI/w9weu3ONJlp6jexFGFVIoucApXXqqzu/hBoUAofrXh/2U6uH+WxNZ1a95q0Uf3up+hTaFAltlYiGvAETV0aRp2q0rP2k/kKZI2esFsgWsO6TegBudjPl1RGQZAl1sBw7PviMAW9EAQXUJRj6h/nCb94lIvJkAYhGOR8SfH5OYWgnoOL6uSdQHs30zRgBPEKMZUIsRoQ8RDX/hd9wlh9AXc7L2UWdcb7KzKqvsupZd9OZQRECoHdY517LtIIp7YUbO4kLQ/vtYFaLgugkvzJGWQQ/YznHgw7rjj4HwVTqhDnxxNdzQY/AzngcW9XsX95A/UFCBLoK3jHWoDRhyKdmruvnf9DOiBM6kw3ntnJdzqNPeuRrtr3Nr2c6bnVDxd7T+kGEVqroyyaAEVyMTjJV1S7ltjt+7OjPSr4+jFOF3A0qYQZqOgpjAhPdBZbKXoFCOe3WbT/C3pllKLjxZ4MZvVjWEgvjET4kXkCqzVG+V6CQu9Pf7naNHXSAiHIHHWDOy5uuJYGVAi0xiuA0AGtD5QXS0abD4lmrqX0QLDpVEAIZm6qVPxI9I6p5bmrFm/6bfn/7njfbyFcNtHMg1bdte6rceaXWNCdfVSGIOsGCACaiHHooyE6DO4jYm7guYWfH1QkTiASz3IuBnZtuT7wGP4rwvtdF+P35r1Q5veaqMX9j00y1MiLi9LP6XmrCxNDsjDAEP0EG51T/gj/3eG3aCdH8yb35r2R7eMcw2XOkA6FucaScP+TEbjLKIiykFoCmWzBsDnekx+EKAkSV7e90+3+RnMKkXh6xqM1J2h0d9d68D4JqMe7RnLMYy6B7vzoxz/KswHrw++6y7PzJv4PV0Wn6u9ah6MHro/+w1f4w5NNTrL4phYKPCi7KkinHrfK/9fH00EYe639nlEqVTrcBqImSRaTGAlNYkPAjZfS4v+lJ4vj8PXiOWKtzc3RSbGZ234eshQNp+tt3SWUd3J1qGB4XzeLmGMgMWjKW0aqmZXsIZrBF2cfVDn6bHqJtWF0F9DxV5Y/t1C+bVQKNgXajOnk7HlbkpFAfx6GY6StQGTT4Khqi3fYop1S7dcVMB6Gx2D8rz6pMT9R7/QGOBddKLo3TuiZRvuvFrA/aze/wWzALvHSs8A0ISGx2MUm5RMWySEKSwe7ebXhjGG+LTWLOYwbwLgDzYROAn8N+RHWTUbTy8AwBim9whixqvzg73M7HCuEXsBBWcFTtfEttY6PFAx6ef9lf8qrvy2OOZEcZHR9xkZs0Tjihpg71ra5s0CsA6AiGbmizItu/P+6C8PeW3ju7yOHZ2UPj1Pj/9H8jbi9wa82Pg7cFoX9qTmpegRcF+uzlsBan2T6v9GUo+d91HcFSDzkQizQ+KdWOK5TF3J8ECnmPs8Tq+NIDcNqj7tyU5G4qtCn+E+uRgoe3Ks9GpyIM1KbGnfYltZM1OtHs8W3B2MHZ8CGIH2JthadaWEYNmT4v8/3DcHhTXIUST7g12JoPyl3+S+LVnHEvSUrcZRMzC0EU32AAtFpnELJ4mTI59t7KE0u1xH8rQwbvZi5NdxUQ7TNaNwCi27VhAm3Wn1oy4xhLDbmH+G3/hKHjsmB05ldl2IH1hyuVyQa6ruUHGgzNgQktp5C6h/0DUYP9jTjP1Wq6uI+kLA0f4X8A6aHaduXQo3N2CvjcDXfH7g376uQyL4WSRqAfr2NQ7I9+v428aWfBQrnY/8+Vh7BWXrZq+M2UxnKAqrb7cbs3ZZkrU+RemvWIH0RZxZtfZEU0LL0ofQSqzpXuQ0LtZuBW3b6q0p7P8K9BKSBm6OG2l7K3sBdhc3JdtaJCtIWELCRvasasi0v164NOfe+8B+K1kmit/Yhgf8CoPFEgN5d74jnX3+OoVArqAosrswYF1lp4CvdN2ZcqjdAAYsDiWTvQD0xKLdeMhJi3NkVjKTZEscI6hM1TMn9L1+1p9aSja0rUbfv6X0pCEXD7fBaGcNLt/n98ign1sLsphmy3jTeTrtwAqL3biqhJ14A8YVmViOoY0Q8V09uP/oUqtKhUpwzFJHTfFfl9FoOQ7twdg3aw9QQp0rvnpDp7Q8Sgjw16cYJnWO+DXn1+wUzJWxaOtvcgei1mCXmNc5mywN1LQH5T1pW7zWz8hwEDcBUac3gCQnyWEMxA0GJq0bd9Do1CLcgo8JhDOHBy4yGVEZJAa/C6vun8ZwMkLwNBIQgjguIQPN+/2Y9h1NVuGSEYfVp8465CGU5RjJ9ei+cPODNtTaksT0TDFZMw3S4W4tWSvv26f+3uqHDWAu+FdDhEF+JC2t/MfAw2x3vpnLi6EWRT40DDO4qSJxfAiJFxOyFrQ/+gHbkZDAx/ja4yw8CJ6ElQX9333YniN6zQoGIqYiPyFwrkOQKeAcEpHP+oPA3Qq26pJDqkSkRQN1R5SBBAV0t5vA6ocX+9VtR/Xh9pa35X4uPh/4w83//lPuwaQnr6DnoBGF+TO0i0nSTQr4Kp+3/tDc4JwodPpohO6x9cgalAFNgWQ1w33tO+yBeD4WVr82h/48cNndtqOF1XvT92AI0jLQvyhJgH5uPuvev9IkXELihdoJsB4dSWnyktlXPGGsMZ7kuMwEGGk9MYn5UeEeM+NZdXcUxof1KOyLFfxg0qEIIfFhu7DzmIDq91VXihcD50Pqq7azWX2h11Fuw0KDamY4ZVBmVgY9eVVvJEuvEYzxisflzry1oJNbvnszUGN8YwyIx8Q6eYXWcl25DzmASKOeLEPbEW56fA0iddBNCyBbQ8xYs1SmMSAhoMOza3vXbKTLVEdsP1ItXnusnW2+luo4LubI29Q9az1T3tDALj5pMKX4RUAStj3Z+xL4BREQl7BBc/lHRZOdO11zMoWAoLKa0tR2rS2eivM81W8UsPcRwhT+LIQkHVKj+6JJvEhyGr8B3H7d6964awTzV+wsAiH+RC6cXgoshNo+3xeVD3in/koSboBUvAjorGbwlbC1B/OhpYGbK7Z5bmI2iuZlYJpbnogJVCz7WlkwmO3t52czu/YGb1VTrrqJEXR+hhKAKUzs1/t9g+vtDCifG7dHS13xOp+lfUzuTawZOW6dWDd+XWgvL0Z7mYLqVZQAr7H3sEJO8pdmSrYIWRZBDAGoPDA+uEv/6HH/mVTJFPp6i9s2c0r/thGup3scIU4jPLUtEc8V2vydHlx+52L0X5cPIBQOf+2q+wA3Xv//WI0wlV0dwLzgFMEozLxktxeCaaWl2VDEj9UjKktKsxiM4ACuXu80o9XyFiQFhmxlWl0VcZGz1BWpSgBB15+QRrWM5DYSL/ZfaPfD+kBxoUqhRyYXyCobNw21/0WiIrjD5R4UjwwK5sUGxG5IS8xF1vUVxAXOHmj1zrclLN9Tba+bBem/Pg6fBZcLbJikVV5ndc2OBHm1q2BNfqi5ckJ+81Jd0mwpglATvPp3dKYGLuSQtvW8cS8a1E9iSgko0H6H+0FDpEqMMcuvB0ZJNg2VC+YW2Uks2LPugV/bG3errAteKHtb/JTuhfyB3OAV677zM/cuFeUKayUPB90ZvAAKJEuCuSG9Qrx0oRCMQdyDHT3R/t+EMhaQCSnBoUxwtdQVmR1iC9UB00737ioXkifrKlMBOudQazvyC5MS1uccE2VyviW3KIdSAx7D3oJiwkxkFCI4WYAt+jwTakmTP68Q1qXFGuDTmTfYooHDYZ3e2d8NvJ+VTWxYqROTlEP40OcW4wcDVPLVl9ka+zPJvYCU8ULI0TzLbBWNiIu8UCeoa+w0zHBhwDurbfXIrHH/DNxvPFZT+gKxJesKyfKf0VbiGA8KY24rNTOsAUi6fslHqdXbIvk46IC1mPgzdwQmjGezGcSclznhUUyUoef/txTD0C76lSDQ2q0P+AtRBndG0xZ9DwmXPETlTX7eynxOIIsyJomohimIjW6V+T23rLg1uImrjaBvs3SNXkAJL2VXKZCidRBuOkSGd4IEj6rUg5Jf31bx0c0CQaelotesEYa5mwII0xlimz0nH6osHDfLbTq5Ao0cKcn2fD3Pf/umz+OI6ikA5eQiiL/KstltxP2m2J399PYdRtTtfe2SkQm9ZPaWndc0i4AfgiFhv27HycEQaq2WKnlZdiunEj2keoJ9hOogF6hk3+SYVrimBru1kCcyHMeDqBHfanA+kAILPBle6DFcSBwZoQOsqOk0p9bW9j87mtRgD2cFt579k601gD/7MG2aJL/zpDNJyL1OpYMzwsLX1Fv0PDE5j1/ErxrPrnssDTVgy8OgCtwyFxftZ4WkoZxzpDc6bUgIlnXhcshyIOV1by83hBrBzOEgY3LNuCNRk05SkJ6ge8FHsMlEbR/2CR/d1FRrPGD6TGRnGyhKApHTwmFo31QgnSi937kYx8H1IpRbNyeH7H7pWBc6XO3WpvwmC0uS1bdOAQYR8ySEwycBCtSlXEMcuflMatLs5kRrx2eTZyMszP2HWQ8FrJSiYjN++n7AKldoUsXtID/oKiACPabmgms0a2RTWtetEvn3SYqKB2vLN+qqfI+wzlb2pmfu8tGppwCsIj507yXG3uoE7CdblEcX2lI+lngbDwtSeUW+GsalMCFaCCPBQg9kzz7RPwPfXKvTUUTQgUEMGzKS3y9uBS2aDL0MQ0ke9qSnz24VzHBIXjkx0ivYz6vkPydJMsAegm+luBrz8TjvOWO27CugI3t0IRQcYBaiE1xpZQDUODqzUieod/XVPioA6hK12+4+59oLgBx1T/gZjRwpNza91tKuvX0+ClfZ4oAPRuoL3bvOLwY6Lnjb+3bY3fgsuBKup+iowAkq9i/Eil8fBQaAYdCOuzMTGsi2R0swYxUmffXuDp4ViWcanHURB4Ab/f73F1jmR+j0BMuQr7mIIzBQphU8Fz2TVoLuibNYFrvvD1wv3/0eJWfzg/ZKzP2uZgf059E7uIT1YMeFwd/RMUE6E9UyXB8uM3OXvGSmxEpcrfDYcMsirus0G4lQwaXfUUNoYDBciar4Z9OW536ji6HJHh7WezqAqn2xREo7QAWYEnkCcMS+GaP7/RaJJURPkujA9dLVQq+/fUecAVkT/jWq91+aId4vjBCAGqyknDz4Li+S4IibBghmh/g4kW/BB6vtb/fgUri5jdQ25BaUbH9GvwSn9CAK8fvvGOswAFw0bm8CVYjk+8kxpV5DOdiUGh7yJRYQYI4UttTY0Zh3rE6PLZ3rz07aL+ksePWn73pPOKy6rBx059BZmOfA6AfNQxv8UvnY0U4rK2N35wvyNjIAiEAvoqtEObOtrcYYvxJQFalK838hUEvzrBzSxEyUCwZh0gSc0j4GWtytYyLABh7Jst1CwCWx5wPSxbDLYwT5gn3ISsQFUWaLcmwi5f8lP4BMYIYZmtCUOW2KAIB/FSWLaxEWhTIjD0zrlpfWbGTGxEtp8665dPJBI5ukSkEdAo4w5wqffjKuH1WmAapMu4B04jDxGoKVlkq84dbxrrBEI3AtBVVCrKkpsBiNV5hgK5AH6LbwugRmYx5SUpcAPf8DTYPoASdYsPOMsnD2DDVVuDuDDdyhep7ctw18OyAn54q8gmos2/48dbWJtZy6G3Mwu2lVVhH4AauhaRYf58/hkuIxtI6HEwA9EW/MUMJ4DJ3g1C0R+qTHKJY4VFSJrCZ6boQUYlVNkY21LiVis57NowAbBRoAILlySLhCUvC4JrIMnbiAhiUNxKeQRQgzS79ViEV5va4dcRYtxypAg0VdqbYFmf8sbM33OtBx4cQ4uIdr2pwYNMEWPErwpkTTc6d6sYjsrp5x6pZRyfGdTlhxzI8VSkwsmJ72SgZFjrtp0JSP/gU7rEH7ksy8yuBc/7ga6IPdwMjCgKfADvgZrjPxklSiQJUsQVddHX5a1zvvm11wh9h5Q+UBUMVsrtJsAclJt9qa/yBecK6RiPRsCmDoVnXwUyIEQR7UlRGYirQZ5eK7GCOdK8r4uA5wLQzmlwQIqT2Fo7oOf1QnTEdUAy4Wa9jfvlWiY6FsDr6a/iBSmh1EC7f37ZfYs/6XPspVZHZ63cS9oRaR38Skk3cCq0GoDiaA/kAiE5meMI8/BPN9sYd57d0IIBvYvmabxYC4L5B1e73Q2tSKhEd/oT+IAokxOw0U3/smphiDY1e1ZiWrb6mThgY8SF+80175hm/heSiW7axViUnkSnB0oGrw3uJY5JC4cvCuRJiEGBidOG4vx0Fj3UwHpK/32KjlGSqDFI45C/5Ovxeehb1KdU2WYEPl+SjrNdosTzkHLC8vHq9Pxc3G9oewC82cX+/Hyc23XGZtJYoBsQM9ALfTV72BwPAuYFWdYKUUEdL8ASLAgBjZ3XwgT9UhVcCo4PvDeHt1XOwQ6olgvjA9+71YigNrBzYttfW7IhwtVF75wTpSRzE90jgrPK4yQHN2SU0ZrVIY0lEifjj9qFHSStiKTsIjNbEHkLAnQ2fL7r+ITUCjZt1q63IGsgupqbeYO0MSoqMc27SddDLcy/5c2V5m2jRQcDxidjC/PZ6ImgX4Ay6SnBBourwlyBFisjqWzJNJZFcfFB44AbwCrpXOOKF7xWjuO2HznykQ+nkk/Hz8cytBx/wBSQA4vz/GrLHmQkRpTxDoFGm3RZSn2nGRRdF6CH4W1sdRcq19Q/bth48GDmZKAHFLhgqIOITMUss29fEM47iwJiyUQ0RalP/uj3KlgwiKQosux05/yjhq4P2M1JTUCxwOaMbNcEaURpGfIqpQaIAFgPzdRVHUqeoKrtiav2Pn/XHmPJG5QpZHPDvQu8of1L47dysna6MdFMoH03xxi1/hQzObGzFmpaXVdWHSq2zMWJGbTl2bdJON9kRkFeBziArE4BAXb3PMMyKgaF4g7LVJE9b9luwj0dxq0AT+J8WrXY1khBNMfurV+3BA/bgIb81F7O2Nfutd/z4X8W8B0B9EkUAiGe4YXBG3nfU3fBFSlm9OLQAm5slkA+Up0snjMRuRyr8+MQJH5ezZ/24odxWWS6y46lyAXysn2UJCixKZM/vF4ku06BTf1pT63e82pvxaHqNFpWt20usLNKtGJxiy95S6749YwdYIpLiW3YCv5ZjO7m2LoJnKLFM8qXkoZXeh5gnTFlMeWjSjnRYrRAAK2htI0r2SEAIM1rIy5A5o6FxG/x5TbTLBAsDTW8HjYE+oX8wRYALF9w+AT0ApC/GCbfaY36KXYdiAb8D0KFhH7yVVJ4AAEAASURBVGG8QAM6CgT7jhjQ/W2WumGPasRT8NuxjotsLuoIVCIeA4sAXucr2GzA3Nuz95/YzGaySRXaHJvOKMwOPGz4xvIbr0eTUdnatPdmr3W2+Vu83lXrNQGWp6x40dtbLZ2o947jMG0E8GWwqmdm1Y+RkTx/9VaUPoQGolgEcdZS6f5LyqxTVUFjOpyaA8RAcj0cMxDsCtWP48rv+HVw6XlEnNyTNC0YjNhXtJTcCXghgcuznuufBAzAzW5rrLdnjhn5l4GQXDGQNqL3mwv2OYnK+irLJSNLEJuaJqJviAEG6DrGJRbz4699xw40OSW+KtppzbKpeatVJ4D2ZL0nHVOPxoLlT22VkQ17ps0NIXZEAAg3LZmx37oRbXNMw6lMkB/Q+DfOWwoyDfRmg83cREenIz/Ab093ZHqhmLpgS4l8MRcvWt+WPdrij4UePnnSj3mGyAufmVQJ0PubA+xb4rfotIpi7/9gNCbS7EXStIgo9hA1kxJNozEarEZjNilY6aT5+pmYZanzWVnKJGGlRjyn0Ec/K83e0K0JtmtDnukYtKLDZ9dcUQBqpFxCKcB43P9mRUf9/bZ/v1UW2+UbeizNbdrbKgGWgDSllwB4wL40t2lZUQYUoYx8Ch+nB+5LKr4MtThT9DIdWZlUGUEQRlVairuxm4mdzkkrIQE8ZHVxm6D3oIeBaXgTNETvt3sZHFA4KDTtmtGCS0CDQOmSs3qSSwGoU8+ZfWXWj6fzHHWvsP23cJW6Yfs3+B1PCMSWeoQ2EfsN4C5Bw/6dq36cLo9bqIOfC8LpnKwUsViPMMxX5gnuQ6kcC9Oj53+8/8D8HJV4Ks+n5f91i/3MCT9f2rCpFfsLVbtzxxsLVwmeeBREROSwmMaZI747S12nd97y0BzZsHbPW79YzRq+EtxbIgSWJ2wmbPJtLxlOQGMv+eFPKIBdYSCoO/rJXR9izj6XVt+VSDpT6uKDDhkTc0BZKi+D7Tg2nDvnPtzAqVbXPNccBXahMqMQj9jghA1oyBGhYJ2wySiyRVFhb0lsgIRo/ofVPf4MiY53rFnCvbHKxkYjEYkgRlu4cJZnLfH27RNncqytNbKDEZwINoaNobw+/N0XIrOnRrO1g0zpq3CYGTUGwYC7OBZOr78HIREy/DlFJWerdPgBP/QbtAICAxROlYMcpEy0nvdh/ge8/1GXQmk3iNQ1+8UKy6B3RFZoQXHhMd2OEk2HA42aMUaPCmOBbra84OorUJ3jkg7CBP7kBdtf5oL+D1S//ejhMg793g9Bk/gAl9kOh2QEL5z1Jwizr5uyf0ewiZ6nrybnLB9ER3ket6tay8dxHXElOav7ujKQvAC1QkHSEHleMdS2Sc0Pc4t+G9Fybo6nZbK2q3VZa/a67L3A7rjFAVUCoKlPGsBOPwb8xfP22Cl/HsXiaNxqKy0Fxg8lbNnz0/a4erG8wK7dtDdAVYzmdKeuMK3EKfKe1ZYhTQWuJnSg4FBhb5mGUhtatjvguzDvSHIbcpIvV9V5CUFbYqRRcAP+sX7mWG+UsoIJKxRT5liDahiYbJPqwydYuH/seLQgc3lmE02uI+YfYvVXULU5rqt1nYPXw7QDVjsv4n0HUEC/vmW/Kn7GlRaSJqOdTPktWuexQyl+3FJlzWR/XokWj8LOWGUYZvn+qtcnptKQb7jeh2wtxZp2RUm6wVfcP1kqAVICg+GPAItzjrW4K6gs5pXYim8nFlcT6m2aQwq+q1ejEqjz2IzNJBkDC+WrWpw4SnZV5OVOff/7Nqxebai1NwairACf0cpIegxA56aB/IUS9lVYV5HdEVXzHnbgDstgnAc6+0OW7fdDn4dEyw9qAR3ViQU4HC3Kwgxgtb1YupupJEajh0IMKlbxFtkOxTjpOhR9tdv+87L9dL5PSQVzYnHZuX+gap4ns4jSn1qxMq0zHRGmOlkbRduZXgDg4yjuKMHBDcMQgyTIS4BnUFVDigiELqgLCoV5S/qKaoTWwUoGR4woO6CMhCUknS+xg+1+yqQKCnfYYZYmY8UxTMgqgK/QjVh0AP3wraueKhdYim8e6bK85YUE3mY8W93x8xfWv/wVH5fMnQS6NdsHA2VVPtzPLtk+VZXhRoMP2n8/sQd99k+wAXr8SS52j1u+ug41AntyWh/qQFMvtCP19qz42WMlPtPL1ApAyfQG1QsNRJyxa8qUhrJT+5/cQh0ziy1ZJalc2JJbLWK7tr6JSHDWptmrm1HifjJI0eHkeGCDDoBB2Vb0P8d0FBT3xBNR+gcsWMwMHKsA04CfxaCVNlOyaecXPPI2+EoZEcYlEAidf+ZM5Cv5LPvFMVl93colA+lnGAUFAhhLq8uefyJTgmF23JPCBySEHL7wBc80AFAaouh0fpTvgRVZkHMdcpsxyrClmUi43jJ7hGjbnMw9R10ykMavtXWVgQbATEYTrkJRAImku0iiU+7H+HGQPWi0AD6gznaXQJcX/TQ/xY61uZIH0EaGjAYGIJ875LMkIk3DxiahjroR/ouJNQCr1FjgCMBIC5YPnwaBQVEAXgfekpRFneruTDAOMwl4klUWzI7iWNEpY0jNg/EGjl1hSYaud5Pg54otMpWqAlkGxqQ0HiLgGivWSJmllpIhk95mOWgWEpiRVbf70adwbz1wPmnDLEl746WgB6MjgrMHVAhj1C3NlbM400drdqd7OyOTR6ypJS0va4spCAD6ZWWX9Bxnoe8FuAXDFS6CEvvzrHssmkCAkzfWRJILRrrNdnZ6DoSEbdbl27wQol9q6xkVirlOHjIMjMA3YImgdAg66iHb6ocondShUDYbZVDJ57T6i2NQvlXzQgHx9IUf5w/dOKbycPD9WrMvya5tFFvc3llZ2kbEADeu26HDvq1fmO5GxrERS0jXBEnCvStj/kppTXVR0di3n4smMRoqrXfCBtVdeHgR3ycHvbTrU5F+7yc/kcAYOfbAgog/r3OGH9LbJliJvWHVkhQu9co8uieISFyN8F4YHcAVGCwyFEBMsLyTuLUiGBZIyMTgUrRgG2EN2xPn88/tkd3bLL6B8YpuoO84X0JlgX1VuOZipSU+Cjf7/Dh/0M5ftj+Kexef3lm97wQrhpVuCN54c+SlV1M//3PgFItKVohHCMIOy42KSCx7CXWEhCh6lmOXrALJUtclbmremGvVcOCkQi/RGj35w//g3FRY/Nv6RVZ3n7978MNv3fsV2UqR6dhZ5i5LAAnCWAQ1JjvHTkzYiyqROjOU9GQG7IM5IrYsSyagZnqQuYowRo+metA4Dkr8/gAUp/9+/MNw1+zEM4gG/uAxfwShMzPhUYv9eoHu6ku4vxtAwBFfFtCJu5+J76TkZNcecDaWtrlaM7+C7gEg3WgF+tKMn7nFyCtCmcjQJcwNIKnvcVbZaNqQU5Cljot+xy32TxowuB8DTh2Kgn9QYY+zBVa+qy8A0VkN41bIsDNaJE3OsZ/r8uPjHbarNm99dmVJ6FxWnbm9kUhXZBiW+vBElAAdDeByt6Ws2z+r97fYKrS2wOLCyymcx9XuGgmKOFodaIdSAhC9+vmqiF/AQ9H5wODP/pnf+l8qXd6E3VRx9KKQEWgRzJjuW1u8SA4P4MUB68p39hTghWvWkGmNDX62iwko7ePEMeLnCzV25kG/DhfAJT80ZNXSWq7OWuGaVUs1gU/hp0wvi+bDxyatuck5O5BHPkbczJI/09u2n1xwmzamEhgAqorEBU5X29aK80fgiVN28EhuXnlOfHqB05vXdlip8vkHXM08n7qODo0wuAV3kelL/NixvX7c3+8EGWdFKkykMrXq/j2P1SzsOe/siMRE2eW+ww9A/QnoYjEx4AMx4mve6mTmpREtth45HqAf1opgXXAFwIj7JxlWrOPXSfwYj1xWTA8yQGThD2rs8QZn+ifu+CuYTMyAM0+dqbdYkwOJhk3GUD0v3YycOo9gtLAdVlbUdiRBrCFpbm17mFmowMXbbjxQ7YAMMGrG4svP+IcQMNSBx4Kqiv+StVsMNPDMF91W777lx7xICbCwoWE/Hej3Uyxtv1XkH80W50ZZB6OICkPfBVBHwKWYGCeKLGPKd8PU0He+YxOLliOrETQjL+KRQ/5KXmVuYX06TUor9nvVsaUHcuNjQy6aqAyWRlCI0dppxS90RUFrvSPWVGNXRryEQ432ayesYN1u9frpmfusbD5SlWgjw1cuPAFzIEaCA59p98fSluyFCc/mB/QNe4b6QfQwaSPfHrX7if8U7UxyqzjKtdBU7XGOiN5b/f5Wf4rd32LzMH54KBs9i6tyfHXMlneM3EpBDFPJXnZAVjcyU0oAErSZJ/lK6+4SLHZvZbqtiTPgQf8yO7osRl3HHBSoFUwvWkHQYJe0USbBvv51a23zaUwAtv5i3C4P+HENSwGREzORiXWgyxWF31Qd/tdGDxANvYqBilQrTdh/kBT634q8w4NV1tZmRb3W1++ltZY5JkyOJHbVe1devbCJ6zF4WPChvPSGp+ukksAXn/BEKW/KEgMj9je4bw+4/34PTMJ33qexoJuPrvtwAN9gpTh7Jc9GU6ysmDpTGQnFiWGfdrgl1OrKta4KTwcaUIjGsvV2iHSaXiauQ5NsZn8+Z79QYxWoPqKjavAh6WYm8QyICZKJAVhbqTMT+h9gWrgce8wPDS/26JI/5iiIJYD7n/B9cYN9JUYg1oSOi6HKuK+9zBd3isX09Kc/99wDaItCVdf2wHrs2Ta9y0BcMovpmLW78PlTwvbDB8nAmb81v7yy4kRbWOnCID3dERcu/V1NV+ql6Oeo/neAvYTsSj3KQ1cu9vW3QZDxFjzcZ1wlGhrrIpsfxRrcRkr+n6/4rUacBbARMAnrZcz5CWMd0IZ8Pzwc9MKx92i6/qigJPlblUQnkOokmCbewvRI77JjuMg3euXH9S9GbfmW+Mm/PGI/dcQKKnNXZ1x89vTs4ER78iGJyPR1XFeIAFRSAFdFVWq0Ax5ieg/8rd8ppLgivezBjsdr5/edFRPZtkqSBomWeQXmf+Sgv557x9ZhGj/BCmJT0gIZJE6EzWyafaofQHWBQ/4DiUiEI7IG5hBMLPoHaQgDBB5/3AXotat+jBTGwcu+55jcwKurrh97n8q8AUdTdDwu9RpMkObi5gooK2bpQS7SCv3rwPO3bIKlImJ3KBul5fZvT/v16roK3xOGGkic5zTGj6WuzffOcYshQDTsoVVQ022fckewLPuZG8awWRXmp3wIvhU+hzoD09I3vZK8UuOPRPSoww/4QUGjTAkK/wQqAyQMoAiIvD7glY91KRhyhxQrdH3QWkRxGLcMRJA1qIXUNtAUJe/V9Lg78XHcNDjBBsUVVYoRaZeUZyuRf/u6bzpynKrref334/cBZI459Lyu/uqOfzTsF0qEP/2G30fMwEAQvOf1nNNvBVY6GM04FjEdl2GzQ6ul9T7s3Zc3WEoQlDGuv0hmL6EBt/ZpElIY5D3fZfaGmvAAm7bLgFz3sh1gC2G8Qs+Ei5+QX1HbPbe1mPXf0kdvbPiGMHXJrscz/UBXtGjhySfdDMPyAchTmVqWscEWMaN+WlqeIG8B+8kCkCIpAYLAYIfcm2w/xWS0aLez1u3+oB5NodeyQDzp8gf5uA7XAAgcwrQrL/VjPppflrmyEv9nEm6Zq44lQVXCyw5as2XBrW4fcUgb6RLCuNEd2UDsldtewundvtClKDvKysAV+BRreACsu4OpVsvGwNB5fBv+ANcIDWzPttkJOy9OwDZHfBQ2/aq66IjyCr4Dq8BLUeIZflgWD1TmuBIMOZUK3YqVvvxlcN/s8+Qry4uI8PiRtOzyjKmBpfkp5y2X33FpWkFKRFS6hwszy/Irtrni3coqMvwNTBMDuJGgqJ0df6WUCsRXd7UUjrP4SR3+uc8XbuPnx/HTtwKRh/7BrsCfAQlVa8hYXv9n2nuHx5rIk5Zhd8atsZwzG123ZrZbhduxHqbUFfRrd/y4TBk42BOZqQyAVcjxVauVowPuTNgblB1MzavjHuXSLqk8v+hSudLf8HUjVOPiTd/ZA8hX6nkxYXv9vDWL6fj1Ig9fHBr2dVbAfWcyOo6k5DCDJk/wc9+xUyddOwdwrX31e3Zc/PrUfd7AsKIG/9DxE95LYVYTqwnU6kF0gAAE2i3YcxqUp4t9fOH4IdA0nWhSctCp4Yixd97xeRgqDBCGkVfomiuA7cRb2EtAya5N9ypvpKdQFVbivZE4fdK20v2dF56NH+iKgnIxD0B1cObbQula1g71++7bwCzLmWLGvlUVwnDnhvVR4Bxa0WsDVucM0PucsaMyIY8/rW9Kc5EJ7GvxfFy0cbeqVJuwrHSLid3j0QADGVwA9OYAepQbxPZCBZnurAJSdqy93HNvAsWptkKCjV2OYMBW3LkqPmMg7Y5bHdA408sAMcM0MAwERh2FX1H/lM3az7dbPMvbC2B2QstYtgAUijgJaSq8JnQ1m7mN6BZTwSSulPbPFFxxuQ3MeCgFQKuZi26WgO0ZsIKLbh8CofnQyy+ocA7oOhRKgLXZfOglkXznqrelMH87sewa1tbmTt+A1wqgBOx/T3wM9mI857kvcFJYRw+fjRsrMwEwhOHF/BYuuF7C7hShVx9tsAR5KUoinYPdbAmpvaX6ECVYk2GLkj/0D21nUXio8zBba+xYlor7nRX7+TVrkBwm/yp1YCNjsuoDsCBW67HcESCAcwLJrVg1Tlsb3Wfxh9f9FjKPjnT8k4TjmJUYM5KCMbxRhVaL6IM6ySOccJ3GYctiOZ7eN2R7o4GfwsfqATBJngrXZhAYoG0QsYwFamg4PtRh++LRdth4o9JKM8H8EOJVVLq+tLAdZstntbxKmP5uFSgE2Jdjx5PJP0E/RBXWUUA8ZqiQqoH63r5l2+m+NBdApWY0cRJ1ZvvpJPupkCtFAg5qbYpZYVXu4KCTGSwOdj0svAHbqbPI198KIP7kiikISNZ4oD7TDhFBUOjHSGfi5N9Xbb/x4wB4IcTRuMvL+lyn+4zGhjbmCVzDmr3oNF7bIBH5eEl2ZTHb2dXsHuPW5kr85vVtmABAL8Gut9nUDNhOTdmK79pfvt4zzBm86MmnS7axPOBsPcs3rru+C5BCA/ixKN9e0F8D0NuSEr4LJZwEkxvvFXDiTPa+wtTMhA8rgoAIPZJeBkMaRvetl62t1h87cMB5DhHUAH14YJ/7jFCTABLngNKSkG6NcBCQAfEOHnEsqehGF48FNliaYZc37bH6aAIfFQhUkdCwyVUPizhe4yXn1bGP547beczBEcZ8frZ1b+pmqruub7w2B+cMDk2shSZZRP7ODxn/YCDjQvlAoyowrWNkwsXkbJsu/Nd+nPsLQCP+pJ64D2shScvJ+z/K/9BdMNrbdNeqFYk7kLCa5Q/BpkLEUP8llQ0WnlYYZCAxhAvoGoYSCw0yD95JDgoWPQvuc3oLErzbhPdVkdGhKJGLvRq3wku2LKmRnvCB251mX5Q4qGNNXX1ky4E/hBQ9J+H7ZNzz3BYUpuwseY02VreIIgnmlotvoqKSI0K/gWSOZ/oiHzmk46wdF0A+wElARIu1RL/Jy5+I/4H/32tT72q6C2zutOZxYkfK/V3QAn0rxAXB02FSRL8ASIK02WXsq6C1nDu7HfQqbqExkJUueKNZ3o1xvLfaU18ADCQO7Lb9zt8Sie0XvmsPPBCFVMViPntDPB5AAr09ZF0XX6e0tcWEW/+aaMqpdJYalPK9BzK31+KpWZl7TzhVpi0vgOXPXfESnmhwXXO/OAE8qLLIzg0a+fcAWkFzIvdhngdDryhfRF+v1xyBFJROpq36RnyXUgBujkrENMjT0lHIs0x9wlK36pg/EHL4jK1buTbXqq/0i8jF3iGfNwBQozs6fFUVkJ2fnphf6e9hMtBPobpXLtHJXrndh1MtJxN1qUx7XpRsbhXvW8pgT1NaV1QQn5xNnZrgeHZ6K3NjquxY0+7H93BKqwvr2e7XldON2W4UU/gvgP8P65HNH2IiWYiNCY0Uv2PVih9D/7sTNIiEza7Yed37cqn3CZMqADX8oznPNrsuXRBkYATnRVKNpdY95EEFWDUAC8nAl6AW+PbKuOH9suUo6QKxnSFPfd+M1c9G/jlmZrBUgwJaiepf5JZSoeR66naiqCznP/2eM7THHnPrEU0dxx7Aqp4T+2xL1A8aMC7MLgKoAsxvhApwSodT22Mdfov+gYuV6THQFVWerkA1B1hyvasymqjkGdR3kDAU8uCDbmXBgwDYEDZkh/e9fevZzVP3pZSWbeWwQTXW4IwL8bxdCCk7djTOd0M0Y7mwFzIJOzLRTEy+dHXda6NeDujBtCRAfWh1cFUgEYn5jIvEqCGvXxsz9hMEDhT4PIZsak/ojNCisEBlVQve3iBreQvCeestf4UOQTy3tPq6RKB/xpZIEbHsxyjlM4uRQKVjwXxw5k8H/dYDRfbmgrXn+THDffWGPRu3/17jUlHmk8nEqgHUDSWmTccwXUrAhiF8Ahgb8xYFhQbJSpWCU4aW0kAaXuq95YvrOioihKTOjBdZPYKFDAdoqbEnGv0x8GRk2PrV+Uf2R3jy+S6/RauZjOo8rkrkFzTNTP2i5DN9zjjy6Qz2GpcjBj9i0MmoGGgOrfwnhKTZlxo8WTGR9ADejXEyVarh4AB8AAX3IdEOhv9zs7ZX43J0t1V0OEr0D/hbxGES0xuSsFeRC4SVyioNrLs06NPjpPYCMknQn2t9Oj5KFyWsQKbpcpplVNuNaWuX5GQUWJHVXu2vwKYKVuziqO91AaQRSZhpT4oKMllnOGwv+2Xf7pwUWCiZQhPfXZ2al0iPfA4rOik1IehqFuJuefYOAHb9KXysHnhbGlt4BdLjT5jiuump+ij8G/HBdCucJEBidhEGkqeufv0VjzQOE6RMcjKM4fXwZB1SRkdrZLlkZwJUQqEWDiAmWnt6/BSUxjXT3+/HQ0tuPJeLQCAruN84++CJxbWwmwKMQroXU9McpOZmNR9xhKifXCCaUXf8F5qe9sLehaA8IW9oXVAgMEgwsZYkGtjeDVUN2hWVR3r2uy/rumTs+6249z7zYccQLjRNGwEwH8fNUP8WXAWAab98GQ+pl11/OM2Iii4pLakUh93czGtfypQATivKi08vps+4SFubmkvtHsg62ln52AFOSza2C1hUDb9AQZy7AQsKjiH40vUfh+ZNsX9NwFhMqWjcYdDswGAU0py+s1lQlv/tP/V7RF3ieobdNTX5KaxpT21oq3N1em/RVQPfDCMWc70I1g20zXvgq/ilT2XAmQIDCUMfxpHHEFYgqjifxyURpVxTFfH50+z4N+Bzg8DtHds1YGQYAm6+vHD6waXSGnb1ovo2M8zmrWkZuxynm5rmCCaH1QMH8+waDjg//ACgMvzpQTf2YIHn9VSrgtaufsAbH3GJRocG0liq4ljy4wCaj2ii5EPLXhzz23AAFAyAfp6F0/qhOymgGr4bRhMRyVwT+gYAuwAb+/v9GG0qVuYay16V9ppf+2CAEjuSqTJIUtUzY0RXAQfyPBtH/6I9VOOni3Nu1D3yiB+nFeTuWVz9H6WKozDWNqStryTwRXIL1nQbt6YEKURHVS8hpPwlN7SCRc0xX4BjSHq7GMWvGI71oN9VraNRCxc/Ib+BW95rY/8n9hsVG2YUfwkCbrUsDR5xRNgJ+/Z5OSDB977nujjw018iuXOCPEvBIMZphyRgegG4fMmpMbCzPzf7x+Qynrdd7X4LNoeaOKLIK7ScJ7+YvbWyfvILrmjkFGcm+oa/Jg2iIMN3ygozreDK9vb2q2943mqANRVgRsg+t7mWyKquWBqaK6zXvR2v4X17/TGCxFDQF6ADOPh+N67g0iIBfxcPH/IJAOlxKlx8x49BetRT3uqFgIR/rXW2ALmwDfG0PbZkv3LGjqkfsLXQxkICdNgZ0pHEjABxkvNTdnPIdiScKoiNLLVq0FMKH1wvBBN+42ubRQXbfCjE07MqKTZtv/OsP/Yzc8v1TWvvXJ1uYPskyHh859GHtzbxAmHJ7Kxl7N1trS6OUgfG13uGyEWeupPqpySNeGPy8DFnXKWxwtGRxTDjhJintyfHLCuYW8r0XSn2huqPTnZl05i4A1rZUnbZ934FbkzY7uIoHzf9U8siE1L5i0TpIkT7sOqDxlC3yz8devJgtZEROww6K5tBJT3laegzSZpHuLa4TkWBc/+gc3CRuY6whgQlmPocOZaaIAcI5L26Mz28EaQC14kRR+3A7AcY/UP7/QCgD5//rnv1ALyh7F/xJ39lpzRGWGgo4vPqfPfqHbDCYX+MiUFW4GAgXbzop/B9MIpPAHwO3H7hBddvAAoEnYLphVMABYhKAnuaraohK6OuMk2JSm7c3iKN3ukS17BoGhZIUBGwc0AtuGdHm79FtYnODbFk7MW+pt5BQAI4JlnbFhg0svBYVuSMpHXFJTZ+PerJ1+ftsbooxT+rB7EKvrNoD/pnbZUOJ2eUepgR58XAx3GbgXLPvmMnGvyxwVF7edziEqR5uMApAclDDHePazn4QQoCW02zz1b6InuAEujVvDXfSgEI1BfmD0EhOrZZbAYmgOWMcR4mjc+/5SYfvQd881VrKvGpQoAa0uHY1W3NfrrT7CkBAzKAWtA72wSHDax4FeOnpMgfiylzY/YVP4YdYTXx3SOnXTJsbKVN3Fl5S/m5WvYudHfbfU8j12y2ZwaSL6rOTWXWj/yT/3mRqcIQHc24QHfsH9CFEoF3sMJrxcwYwOhsp9plSXJ2wyORMnXLcgqzDJJtztkFaaMIQrACLbZDPG2KLIVDnnAFYEFOR0E0EefLrjCYUUTEV1lSdSLDJ8ABcrVTy+DxYZ0e6NfV5EFoABfLk76A/5+99w6S+7rufE93T0/3pJ6cc8BgBoOcA8EAZkriUhJtymtbllUO63VtbXnL77190eVXta/2j+fyPu/zWrte2/Kuo2QFSiIpUiIJgABIgiBIhMFgMDljcuoJPZ3e55z7G4oUQQmg9cosiadQg9+vf/neE77n3HPP5RHZeH1YaOvlVJcyGAUJoakZaS+XiAlsigqcPIJVIvSIvhinwQMQT2mKSBEvgWtqdRoJErnBDUIJH9MdtQDNq8Bkkw5tQg0SMRobvCALUkw+AlwKIYOLs4mO3cGkjbcQMkC60SQQ4tA0954J5XmbsKyiTJ0NVyoJVn/0M9nJldUjn1XoFM4PpfoHnn5d74DBYR4XQgdhIpG1k31idlVqV2V7oZfDzMTm7PrSlYn5HEuLJ2jNuzGLD7rKIKr+/x4ygVMkit2bWNZDMeLucY85KXpW865hkPdcaTvYlhLbGHn/sR/3C4+mERyc+L2vaK1a0ILTYyjkpmn5D9/RW/zy0mJt48rb1yYaG9VEToynjz2YJVNmp/2V4e0t4gOQi29gyHf9OhGREOEQcyp6L/haWlWYC+rzi4sXHbpYjGo8wpQTRz6KxEfu23wvjC9oweViJGLJ6ZsrLoMA5YkSe/G0hygwQEznThvaRoN983UBOEAgLizO37Myh+mThoC8nvSQMcD6Hd42nlK/etiei2pp3GROTmKmwMluuc9QFvk76xHpMyv28Bad5k12CdRUl8gjmRUGnVHn4no3Ebrk3qPaR3wC5sOpvoV1ubI5+KOX3YqMB+Ulyx50+C3bfIxxO9l6/VaX3eo3PtAxZ635PEE7x8UXbnX6j//NkJSmNQKO4F6mhEA11WqaBwd1GwBQwSfrpp6AGkbytpjdYRmk3HHPRP63Wbk7riumQBTPTFHpitLcuqfpypdt4/1/YGsa20RZ9tVrbsiV63oW9eRrKFNSKfffo7tk8UyMy5tv6nZDc4zZHMc/Wcb2ct9UKJjy5eWksW3MvvnLWZKTnWXnDlFznLTzNj1e21TxR0hP284Fe7qhKndQ/yp6+5kkw0G3/eVh0k7sZLoQvmxgCoqhN1Qe3ON0E9s6Nk3GDAGPgsDISLy+PTsRVfHck06Vbsln9S22r3fFZygDaA2Pc4AlYAKYEzCk3UFSTmNUYevx/Fi8MNSkLgQgZXlQNmZ08xDgOOJdggFDZbC8j0P83AEI6GZh+UFHsdUsFn8FPgO+o4rkik1AndZ2YUU8IkAeVVkO7NKbg0d5BwfycJwYLeFCCBcFTIwu67+pu5VrakFjJiv3MkAUUX/MXcUrIUiMMECM9eXmeGqO3S8tyi+VaxgbIqOSUH273YEZirSAU5TlpfiPcvoN2YH8WS3BXNZrNuh2oyuRiici/tg1s6n4DDcueZUbEjc3ykqKNTkd4zEzM7nIpOE1Z9dRr4CnvZZKEiwtbe1Yu2LAkDQ5fIYtftV7EINO+TM6VxLitXW8hSk62pkyuqRVrb6nm/JgTO3cixO6XU/tClStpWGzO7omTF3eyU8016SGpnZG5E8MaP5hqSwEPZyRl6Wt12BqJRnXhdFifjmnXSRPZKs3e3Net5FyXLU3TZ00WZUUsr++9S09BJs982zyMIiGyS3fkc9+SjudfoTA8QBKosgQ/YgbgE8I4fkDgg9t93JQsVKs+eFWhWZ0BQTjFuQl2xMKZmjLQPzOAKCrjQ5jUMIrEfe6iRl0FUFN1IFwb8DoPBeifEU2I/QhWE/37zqsw1bKYbxPWW51KnrFvgjoj2nJzvEEAUeUpFCCCFByQL41JvuzPedkOaryxUtCyBpsBoNBdC4fWFskAQtw9Cb1xTgB4h3ovuMgMxU+mccjyvTaBAfv974v/8Nh/Z3mpSu3WzF3dlnmODgvncZ15xPyWELuMicqO6Al3XV9NjMgPGVlQVhFAAJK0pLxcbloQvHUk2rXmYMEscH4FS0DEZHhnYF9TsyZtstruOACiykjhqS3QXwmJ/DPDYLhnuHbECuFaD/WXx71y36TF7IcGbS8OqiHcLNpfNcmOMnIOM/NtdXWcxPJmSFZs2qbM+NahT9kc2OK99T652YzmItmInfP3UtoIY5CCVYbS5mEqq7Sr6CJnByhpijI4abD9Q7rOsJXFqXfBOSwX1qoVWitTZuo87ypX4nsMEq8v1XvNsUydNTnNInoQrfAYPCeKYoI69cl5Zt2h90268DygtVewoHLDEkZAxCoKM0SJo5CxwvVE8PCuamz/PKNWfkE5g4pKJKbuMemY3thvJTGUK2NNR/ycFRm7W6VIIxcWbW+A6DDTjfhNKe4jKn0Xh/T7bVA8l2QFKxGv2wL65UkbryjnZBxZKF9rxqAzGJ/dCza3FGQZKFZEsX3r0RqIr7oEttEgtY3F2FjF6JXjT2VOTEuLlRBYKjhYFEsXe6ZyIXFVURMbyB72iTPVAHbKDGGbZjaXq1H1BjyS+tW3UabZSdYG5tSmMqUKARelcAKNLn5RN3ZJFM8CvWKiJepetOxVhz+JVMaKGBEHyVBU9ySONMuuuXBH/Mj8CMHi24sTXU1htCfviiPWKMQDIpE5aEdeocbnXF/Ml4UWOu5oLsoh7FLq5UM2uqw1VqoqtJl0gdmZ9ei8Ykbc0MDeoiCpX290vKvkRLJKCzYs2fx5ZfZVFmgFYHCH1lpoOERcKhwQKfRokhdPiqu+JkziVZTO8QimflTU+FNyiIohqlyBg6lx/KbzBqAHjqqWmtbthcOJue5fhM6m8bScyB6ABaDg4kvQKhnXsAxJz2gASOfF4VEeRJBoC4i1Elt5FYv04QXCBKLxcpa1OcuW6HHmc9gXri9fd1F306ik9/HMKZuPdSOlDXpvZXlYFfHWpwAhHHvYwdv9w93Qx9CMPk5NL9t0+/GcbZzh3/chbwP7bOXv2YxdxWrmnXZHBifhnIZ4tVt5JZ57yRAZZkJaLZ1t9wDm1iGJyz5KGhM+YwCywABDjtmv7mzbvF3HENgPxO5JqMqz6T3Wo/OwSYi6fL/weG4WA7Az04lYQyXnOLf1xJYnPWTkWI2mwEV3nnD3m2DGjzmHL6/ZeATeoRPhng6HWFW1PZ/tv9swoHbawVW1nJmeIERjypN2HMjFfQZQSJXFozw8PPflc/8holXMNi4MuELBTOswFbV/sqMsiIZHORp2dlxakC01OmDH8+SJH78ZsUIEC263iFL4srxqfnQob0OB6UGR3B4PvsJvQpfizuR4wSB50BXD98lAzd0l2u5CWAOmp6SrOhqYZEvsaTMCcAl2GP4Sk8DlpFsBhEmXyacXOw5S90DcvyQzsSAuDkrBZNYBQGheAH0Ub1h0OUFtXnDMBRLylJE0aqoAYWh4hK9Gx8F8TlkcVzv1+2QTx4o0AUl0TMQtWsp1tyClKPQ81UTvXxStx97VOEd9cG3bdXdoqb8cHgRywq9OKZou6HBi+rxMoy8O2+wttYAo8OMeXmvntOxOMwnNHpT7j4qN62ka0Xeek5R5sCAoi3M9oEDsmeLl0bF3SiuiKMFMZBNFm+LDV+wyyo9mT55wr6oielw5GJZ+6DUWit1hg9IGlokLyVgU7bQxX6Nj9al5be26CE+kOZCz0K841srWuwEoiunZ+SNQWnQPe0CcplwFaDSCrX9TPqHqABOl/kqKw5/Srsyc3H6xAmCMQr/S2r8QV8c59x5GnjIr73mBYmp2M5HwQ8QcBxVQje5gB9/YZK/ndJD/6pEm2LWvggr1d+vFc+32GvTgCzGyFJpEO925pI8fp+Xa8GkCz7K2TOYio5wba9DuGCX1dX1VVVH++/OiU6u3BzV167YE8lZil6+rHfD/YOjuCePg3g9uMJ5hgQj9pTo4qS8DEQEARf05Jhu8y1AJfQ1BI/xbiXFkmP4mHfEn+R7IVAUwzWhGck3dcvEsfY2tXwQwKsu6sE1HsqQHV5f17AeIlRcsi77rPEnyD9ckz3oTvOpyHrNZFFdu8PAjA50O/SPcOPZ4oVet9fjbhhQF0nBnKPEnbtFmxCdQWadWqfdiHe4CQNoBdoBYYfwmvg0eMmNveBmFEQ8OSIDtozAiq0ax5k4e21lXjASNxuL4PrrxEOBpbkkPZuysMH8bJqA3GudevNP32/jnwZUM7NJbaxQFWYSAhPyvxvD5G7sfmVSHgjqVXwRrOLqKX+yUR9EKoj7HdGOpeQ17WQ5Ah+WyR4Dnbk52tSw6z+c1kONOeb+mewgL1yVYXdmm9PxBBtAc/BGicYO65VNpD5Lcte89AGCRXyOPylLZq0pm8l8Lbd6BGc+M6mLR19a0av25MkuarHaaaSGaTDV3u1wni5uPjChReehoKt5Za/KzBd0GhURIZzJ5/DW6qTdgkHmlurvH9NttoBJoXcuTUifpBw/5OosCOQdYprxs9/cePJ3y3QnI1i1Pg7HB4zzyvbW+JnMjpWijzLjRJysVz3vJbSJJhEQ2BYHA1J1OjcbemdEY+TKzLR8xkwkqoBYklMg3BJdcV+zXOzTqxQG4VaZVkQ8m/yryG98ScEqHEhgbtHUHaJvcqOXvEMWB9NX4mMNJQq3xPc3FtbQAArVINk7V7xnA+42Bn/Pjz92x9jW8L1Vo+Z8vhhVeU+H7NiuV+e3lGblzFaSZSHy0k01kXhZoAIIWevuTriOqK7HPlk4hwN5eRfOJ7e2esNl6Jy9e8lqwx+U4lAoUhRYMsxgZk3dy0W92UeR0NZmVIV10uj0QF1Vq3VGeHacViomIog+aUouzad0AN+sA51+elCON+jnEOADu7t4DUcxkSz3fN26djStgxjGC3rmuwmnGg6vtZ/objrIOF05tnNdfrHJa1UsF7Gqpko9DxP5d2flHriK+faP+bWT+Les2qrxrqrykblLb+qjdt2TW1KyTgF6qNUy0/oBdbrnkak0b5sT6m2Tp/NKPbYN5OGbtSPvhPiE/ZstCRDgtWhY6N2Pu5P76blOIfBVfDR/z9tnPL6hH41ZgbCDGJcR3dSPzQ2Kf11mTEJq4tqGpPdDtDN2sChPt8ttRnR3j7ypLXfr3tEDRqWbGb/kxtPpBKkhrDw2DqPvbDGxYBI63pjRQ79RY7EImIA2BOTlVWmts1k9BprlfCwR9JWUjqo58df9dxH6gYvNnihL2Ou/6/DP8KZJ3m1//1OPeBiIWbwDvfKXl+UpcwbIath7MODqKRGNPvpwbnxGAXv/oI9JAlkrK5VHAO2SQTrUtWsT/aqK4bbWJm9wbLZP32B81gMxYCZN/DPcmhNf9HPe6MjKuN7Qt7JGZ+9g4ghUVla6kZE9M6zbsgJqnJ+Shgbd6ekxg2HaEWC6vpb2hUMbpGchkNOKMru79TT8Q2Di/gO6jS0EAwFkDYnJyKJcuqzOBoS5oq7R3IRuc38E4PyAJBFNIm0b0lYoR4yzhmxBMBSK4+Cn++XBCjeipp/Sm5C0yUaOTyPi+PtNZm3xr7gDbhtUzBgxy7aaPMDtINEnPhfOssWMgnlZwdrKXDxCRpb8I5ksmTuhCBXicaRlo2Qh/i5fGcpzQLWl5Z7fPxFZGvH5VAVVTamx97NYEq7X5fnRkTSmBaKtbvRoihdjFxAmeWjeK+H6JhNbWVsprKgR4sP1f9WHMrIuKz4vs5QZZJQB4IUJlkDpCc0cOGc+Zz9TLdHCFJY1zXe1U0+jDh5Ef+2rUF0D4W+Q8b+3SSxzW7+I4CtIFGIbveAWudqyVVcV8xVEKoqVb5ODa5GmUAYxH3ghNc6ENXpqAMVsKoyXcR3By9MpBGYgDCqwAyPtHCSABfb4aI4e4jT8q4OoW9ZB75QTexTQ9NzQXcZh9u6ROvNaaa7qEtU7ZdTvV0c0NTgop0/raaiw053y27+g2wUtpbqImN+fw5xWkVMvx+47LvH8Ej02P8dNXAKMa9jePi/LiJgFEMqhKPzGKgszY64g2JJ3rrTgAmMgxAhcJ8MD4KThOak05HSYcvYjnh7nJd9mquGa3LAuYwLVq5c9l+all+X+3Z4fzh3wTrGIbjAQ84fPSZ4JRGU8HO//ak36W3j+rfJmj3SjTZmsTylbW+KZbRjj2S55YhcWXQ99//u62HR1jW739sgfnZNfMDxEsy8zuTHfy92nU+ijxkY9DWZATiMlysRUZh/rXqHveCuI2dSEQvqt8efi0pBUiODSxxdvSGmJ+kUQ7dPcHsTlZnttOYUhoQHTsBE3JLGkSYpN3BAQoGRmlnJnBTXdkqnZgeVwUOUcJqRfYDDo6lVtjceY22lifupVYbbMMUMWDEVimVynPNcn26kQYI4WV9EwftZkUwlTTkOWUSksPAKtW6Ks6zJ8Gz4KdQedsVSQQgrkmA2D1fmQKj0i0xtSERZTlrK/XMf6vjMqnzPlwBLJnd1eCbUbw9IeVNCyu1yvYqpgbMkr8XJjQcgKZtgZCsdV7mhfV/0lCyQR9ObKpqa1BxF8iN45QndkeOsZBDnvY/qwLYCyvsrwo0E2kgg6dgU2VhVGZWelj3220oUqxwbiWpl8dTKfyabwDz5617WhXmVIwm3bGNW0p08adsQEme7UxA3uFo7oXg5dSyXWsfHUBGfhEyzB+eWtKhXpopLqeEbW1DDbqdQ6Zije5XnpI0syTGExk2U6fS2ayi8Jb1AMx6aqxhMyZmyMEs43V4rf3yEVKoO21zfRJNoCVMfrQajmIpFB2/4J/rHXUUyvEN8kEVl+5ob8wb/JzibjGTGPZAfrq8JLaiLvyxxGA8xNbBCqg4gute0OOxPpJ9LAQM+miez4P5+KLAwf8L/KaYjAzoNhnyVfTvcuvvhCysX+dyzIf5r7MaBWH/NPR2NUsbOn79ymqMBXVFRgLpYMx6sbMvxZyidybbC3W7/RhfZwOZlzjsaDqKiE9mvZotvYR+aIXmOZH1AKTCiay2da8Ie9DtgArWxn6dObbPSVS+iAOgrDFnlwjieSOvvMNb1buU3/dnH5YIOtJMMwis08ef3ZuWPH0o371USmFnXulk9lRZMV6XGVh3eRWWz1heC6BvOLOMgu22Zi9cUQHOXmOyF4DJY2RSiv290G7+TyH3EuUBRRehT5zdWzvnJVPtvutQ+46/9mXSW7eJxvX1VHxUyfrJBLkidNpkDIBqIlnY3GVuI4zax7/r9y/AcQVgVZoWsgIoAd2zXUAGEvnIl0EJcf29qk1lxD7DKaJ1KssCOfiQqp5PLATMrmvmOUzzH8awaX7+j8AE+PzoJn+F6Ibcchtvez/gfdeAfU0OjliwPOFgqldkKRELRjuxS3lQEUIN/8bAXV9uLaq9/7zvqJ+/GpEt6IRkTnRixYbSwAFqHugD2f0rHAphm0tXURN88v8Lv63Om1Ul8ysdo/ee2SSpzLFwoRAYCy/KECUFUlm7UrvcgnIzkOojFDDNZ0eUpon8LyoC8rHLWERgANcHbQPLF92LB1OXdZb1ZboJmEnOyIxYUSVoSA3ZISxUBMOoJAyfBcXr/cNFFuteGU4S7vELM7GCFxA/QPlijEYaI/xEPhzioMF5SU16NSFvNG2AaAROAew4KovK9fl9/7OT2rrLUw0uiPRFZX5hQaZmysTfZFKygawCGcv4ryRHzCgXWGdEiGLijSBu/rTWFv8gqtWS9dqnjgAVnJ2To3w6HmmcXs0uy1qSjbWcHElbd1oSSIOP2/v6whDYwxpHHuHKHcJ1RP0Xa/9FDvxAxsKWuZo1Kt7Sm9ywYSCw2tStaabK/zhoyYqX8lqjNSIL6ajyZ8njLUQM4JsrfH8N/ItMaiMk0WRyg7uy5t5PLZcyn8QA4VDgv0xqTkJuX75jD8wU4tKVkPhrUHz42tlx6sWLOiUuuraX7DbMBXECE6znJDEHgdqH4HLGASjC67rulI6QE9H3VfNCf9m8tkM3KLAuIfuVhQ/pjOOfTbF+GywloAmjBNw6ctpS6+JX8zqKd9keW8Q8qiUKAw78v/buwLv1efYZ7B1PgqWjVSqmyXXNsgTci5f0S0f/u0/O+t6u1AYH1+cakyeApOJ7pxMAIBPNQhhud6ZFe1Oq4QP+po0obH7V+NyW+X64UQqpkshYkRb9Wy7CIp3lzmeN9ezaI0XKG6lejv34/Kr7XpVcS8AejIAsQXsuxJjn04kAUaTku59cWbfnksQ5cgh4rjUp2rMhLFyuFiTcgJZkja69EpDzV7Q2pEOghqMA3PKQqa8R1x46txfcuZZA3X7c7Nzl7Bn3FypHqeJDq788SGpBmRCnppGGT+3+iTwwf0obRnpDCwzAwSrO9yGpmlWRyYQA/gqbpnnTql4u9Pq6paHZnLplxG0hUm1BAM7h+BDAgHm+ZlwVBX6iaTChbkLVurXp3SMV6b7SXlSQ3QgBZOGEuTYZgTlvYSvQM1NvHKnp2VDt2TSnW9PfZ+HePKyLy16iWr/EvwwoXeL8WlZXOppa25UklBmgG9fGJOcMnKNlRPQsg76WY6F4u5oPlaNpOZkBHcSmwbTlqWNyZyMSH3khZi7N09Kdk+zQTeq2dpxLFgxTO9syldAMPFvOmFmYTGLCvsbsRxPqYP3QL0TzHMa92k/NlYshEA/4BB1ipBT2uqcE8+N37/CcnGRLqxXVyfjIypSVUHhFFYgM4Fia03NAQeti2Ys6xmc9ESFHcykeob7L6ikolyIyIZQgtDOYEwlXZyKthsjg6SGseAjxOKJjhns2wmerKI8oVZ4bVVleeLrJlOLShTfUM8UW90C+KzzODrIVQ17DxsZ9Ubd93ign/cT+41aAFg4JMNeq/WneHfacrMy4vHZlU3BeJaRrygXfVvMWGSqur0ep8zByXl/jDGmMLwuF4Dc+HluVCpBTgvXy4iMrRSWGwmMqdqMlxZkB7U78iKJ/6uR349j00pYUL1/z8fpXf/SVD/O5CaENvbct/2OTfTdPXmYva+NpddwLoaMAYAyRlZ1NHAqrRbs4KwMXBuKuAga7VRusnamVdT55ap2h/wkvgnFk1SVA3L4nRBbayaHdGFarC8EAbl8pRgmKAnUe/Ep6oxLPB3/gt/0v/Q/7LfBd0XJ6eGbvgyc7Qr56OJFy8KU7ihnQvy2qZXr/tGjvEACzXma3Xaj42G/vkR6jNfi9f7EAQsgfhq9KjKIQjH/v5j/iBM8CV3s5i/DCbUXjv4hDU8SpqV3R3Fy1JarNAA5oGo84LZcsCMiBiW2mctR0Qeuz9EdTe7asD+3vIP1ozWO2TKgMgyNpdsLwjzyjbGot8uJoNdgY19LWVyMJfgXz2PuaSFRf7EhrODr74qHazqZk28dbOIvJ72PjJz/b5ff+Z/uDN3CzzqCFCOIju41fO24Zvn/mbu0Z83+WhpAnf/6R+rGP6zp8LFVZmZIE4T5XT3DV9srbJK78HlxDwY2oaamzTY1NbghZwUR1LazMCyr69/9sp4RjLhsBc4snwXy/rAvfLa96OJZAClynZTdSAcTjZszYxEFL9/6WmhsobLtoJNA4uJgD9a0KZW54FyCc7dXDDkdOZNufeQlFiopA+0V6wo3E2I396qDO0YHY6nXA+GCjr9mhzYLdtaJHNQd5kizNsSGIDgSCwZaeEu9gYrk+dKHAJCnW2rlALTPkhXIcZsxoPL1O5bZRa7Kf9vxuV39koF6+DQPg2VWTdvLg/HUglVGr7y/Jy5xXNfU4x29BBL2+YVHitI5WqcwU9JDUov2krA1SfK/NHl2RfO8Xs4M5nz4otkCoafeJRd9YyXlsPUzsMbefWCS0dhm2jWPbnSMyHdPj2rNiUMgDGZCqov0MJ0D+zwFPF3Z1RfPGgySd3FCRaCMKXwVLsu5sBVtBhEg9wdkambus3MtBJwPynIpibm4/LAPi9pAWg9jBtobdLM9IOAwlNqzUOkJnKrkF3yOEOgFMozHQFeb99mDW3YP0L9+OVlrWhENGhUOQomAf5CjGDAUbi+EJ4M3erGQOga3B6cfMdOODZwlBvq5DT0kRsob65Vl4CrjE2UkZ6/JJ85pnfbsTtAb/Z1J+ds1UwGKouL5HPGxmmiBgXe6iW+/vH7v0AB+6J4l8rM/v2q4F5mASn6Jay2jRw56Ox1eaJE3+HMoO4+0K6eybpZJlyyfJsKaHEldQPwtfAhoeO7pLpUHWOIX/Af1obkrL3rfVnSPSOt1gi8/zImNiSsLwyRGUuw1j2XD+cqltiG+PCGBvnVGomO6u4wQYeQDFtHYBp3NGraIcQl6HoMqvkj8kpKx2cixgAsAv67zGDc8Fyaxx/WVRMCrLxrY4a7fF6Gnhr4Af26A/v1hjV1/thayrleHKKC39atxluZSLF+HW8I9Yxo8XreEGpY0UFmPoSVNyF6E2/51Ju6TV8vv7BRAkwQ+csR+WKD4s7GRt3lETBDRa26HccfC2UXhLLMVV7sm84uyMwvCaZsxOfw/eFc/8rQoF6C2OIBgktw5yCcK1xQooNQXaNWiHEjtDQmNwdVJKyFYYbLq7LNuq+iQ8M0jSzgphfJ387JY9ScNHXLFBLYu35Ffz9KiTkc1IQ3ooWOAU5TJh7a2qgzSYqw+WDoEnltXJ66y2thTCb5P0FTGiyjvaVeofnIhJ55OiWfiki9NV111JvRx+/f35Cfz5Fj1HW0V+U47+A0ZHORMEwyYgz5Skw+Wa4zZtPGAE4B6n0/pjtvAVQflgGJhtCK555dOPoU+BAY1YLG/+ofjrF54hcqiiuDwVzK+YO1ALbXiRa4FDj0TPe3dXgBwmYO27pG/QYh78esYB9drHt0dOXqYGYy5lQcTFvc4ZnI089QTteHtoFaqpQhCeg4kPffXpGWpMeQSMfsdCo/Fc1nLRSRL3wxvjCyOoJypvLYildTTnc2ybSLIFu1YGb7Ea8S9kE3Qyhd+xLb+YA/1iSqXU0IPuCk9/6sqtMw9D+v8Qxudm1RO8UsJmLM5tdjZfnZs9Pnv6onHjyCiczNvXefzxCGD0cLeIsKg+0fKPGvLie++zzbGVTdwUTu2+979FPsZq3pauK++ga2s8+cvbsq6Qaxb8zoCLYZE4585AgNQ8ubzlAbeu+9NpyHWkeCWIvoAABAAElEQVRx1ZSQR7Q4rs385pvKhKg1xydYTCI+ftO4pWgh1tQxVUVh234bz6RzIa50Ct/2PvAPT8cT/qzZQSbVMxQPVtTpyvYukZQ8aJdiSdoLZHBAO2K5Z3D3L29XS9x9nd0jxwOzk8lnn9HuW0vrwusuU/27t3J0TcUqGuFsuAhBg2BFdKk9U1uDr3GOkx283T9gz047Fz2MNjYVe7vX/ojzULp1NhhIWVqoo0HDstZF2gC4lCyKA/mtGckIPYLiQL4qPN+YbWDDlV5vaUr0NmEZyHT5j+ogmgg5/Zq5TqFLcvK6EDSH/mJDvhhSE+lgLXoeJbClnY+W+ypzIlW5VNxhOzUw4M9PZRVnBwIKLwhNgFRdQWNMmSEOfv6YbrcFzP7f7sna0C54/8INKUnL3fvkNcM64J68YCxNJBz4/vb61mPFdx1UYFjbUdx1bq6d+mA20uQDjySTkQ4V5FDPyKVLnj+D4X9mUA5ky5JxtyIwONFckLW+8ZtDMeYs4bpAB+8OB6k+vqhy1HM5jkH6d6/q71//NV9DS4ABB5wraGuZfOOi/GaZbje2ZfqDGd/4m9Wf+11loDL/Coqg84YeYpAMoAWah9appm3Y1OE/ZAB069AGTDkx4QGslgaFVojMmKoF2V+i4I/YAESCEIcIkLt8JCa0oN4JFUD8eL3PyxfCK8hPybVVWTKd0cgizubGcNqTdXJsh4TKC/Sa9djJp5ea61M0DrR8cxUXY5kKZXD5ku/yV0da2zOKqsN6rHBXgCmQ5ihkM364vOS/qY0Vu9Y7fGG6rmHaW5OLlz5zJmAD+f6mmp07R92wCWCxOCGsSWYfoWHv5rDO2oJYErea6hSgSTOqe5a0wrhrH8rBhag66NgnJkGfnOySCtt9ISb7Uzre4qgXC8eghO00AuwyvYlhYNaUpU5xZNl8hgJmFqkzqAtMMzYC/oa2cEmWxM2Aj8V0TKa4In7pTdUf23aujvavuB5HWdAAbLurqI1x9Kj3qoOD+nTXleCT339JfveQN0z0Vy9LnZU04G5XRqV4xYP4YHfnJ1v76nqXuOpuVajZqVTd1nBR0ZqPRanwYeZ1TM/BnnWmythqXfxeVLwe2R7B+Qvs3cVuQ9nEyPkJZ7z7pvU05xZmJfQFeBY5AxAJ0jXVcuWKbgOSaAScQ5dsjZkkTAgOhsjCgHBRIJAZsgKQoqAuFFyVs/3SrcKn+X4oZQTHTtRPBoptadFDZHBwQ6wvpMl1mUK+STagCbiPUMRZVkG3eU8yOiiSAU1O6bPgvxpT9J9IymzUs3O/0ibb2xS6kaQDPXkXwpIaxfxaFI0Lm1D5hjhpK0YgDx7Q3dh66r//g5cxcni/ljPhlaD81bXlqHqnrlVxLPsmvIl81N+ZWpErK3JURVn6BuVtnxy2TgI95OSmMPPQp5tl3ZYLR3IhHLzXX5PaVv2M8nxGwJYzGAfHPOfmznUOb8RSzi0PhmI5tV4BZeSdVqUL8Mwh5BrBojsgwigMVrtk1OpqjVZgsZwGoCW7JuRVk+uyacXZ99kgOVeFFyU+rYUKIGwk6jBbNzXkOfguQEPTcgrrnkHIK7riRVOJvxiRB0ibzPUGkFEsA6A/ex+qVKEG4UVTsVpNQfG0CXNjROaTAliEDtMX6zqhzu6tFhon3zH5SFT2sYCYmW7aL59VENLylTG9as+EPKT/f0wfpgXoQRiwz8IiRzNklXUAbGQhNjYb2tV27C6OS+X24unX+0sPNipjQajXdLpkl0m4jMPaTnPCuxweJlBt+wrUsDeIE/14Y2x8IIb4wIrQ4XsyMyj1Q/VbFjrviqP3/txs0B9/QUeA4We0GbRX5D8syZ/aNmyM4Dz9jcRT/1JlpLFy9ZUuTTeAeP9u/f89ZMhQZZ/XM50hVXAmGQ12FiykaPqDCZ6vt6PAtcHNUZQPPt07Umr/b2chjXrRQWloeemFp9dbW1JOl6YnFqkxO2uVatbmA5f+qnffwQwtxgCpo1nu2D2DcWos6HiH/t51beWNrhz0WocpVuqmf+3bQSZto13ra491DLoscSdZev5HkuhD+sq6S5eluZeXXF+/Oa6dUNHkm+qedQs5Umw5xGIAlFxa0s9gKZn9DO3bZYyTIP2sYwFRLf+5uKa9WSBUvopi0Z9/DKF2QC0uio1iIQkoanW/uAzTzIC5GQ1lZrRiDixifRJpwxAW6IQ5UEzJSODsFU6G+lY0PusG2Gs2M+v0wCaZECgXoUXxrA7a72hKbI5xhmo5FOSHIJ5fbZdxB9pp+UPc4laX7DFzrEnapmb3NquWJuEcwtKdX/cKgbI0DtqabCAm8UJEMP/2uiyaMv/5Sqkp95Q8DIm2mNzsI2szPf/9xCGUxlETSObDUxy7yATiKZZaHVe85GSHjeFh2XFArV1l2C+JRWnYx3Y6P5K4ei26mDr5ot4bHIsCc5cEb/4EpjLylTCd8aPe/6eeDE3c9leSW+KgSblPC53RSbt36MX0/Z4Thb6WCrarW7KlIGPr4yZSyVhZ4RQC97W/UVH+7P+6lZiqn6LRKoQj8JmLtGE1SpBpavfpDTTetOUwKTvIkVx6I0ZZFO6/8yE9lsXKu2NjKzY9AiwI4vyNBn6mwEA6g9V243GH2JjEHyGYZUI5P5Wo2F5w7JMsjq0gdHV2nYkZu9v1qsS6YnTnQA6NaOWG1mU5Y53/K5U6kyc3R09jdAvcMzio2ygLykMDvxrMA9mI6zwuHA8o5ZMK6o+RiW/6iUswY6SrQfAok2EYzYduxoS8P2zempm60QmJJqW6SA8x0qU216mc2EZDTeKVV7yC44tjcV7DYeXu7vT8xNqFm1JeqYZvl++Kvh8z3iDGm/MLMllSgaqdfyp3U9sEMTJPTOEw8IoKDCC5irLWHVPTzA6x4BMPpF19htdRmiUR+YaBvF8tUQva3S3X9DmyvUABsSvQF4gKxdhd1YS+EQV8LFiyhKpAWVAqfRMloBAxrlRdc8twoW6YWdRpp1UFpIW1X40B6UfekbZ1fQGc/dJV+XSp3g3C5RhW8CBdC3LsGDakvPE+vSwQn5t8c1GRB41PJdMJHRKhHB8EUudubiSHxue2+M8QYOZfPyQ76tzyY0IUmLXCHOjcZkPtjAhBPJEXY03GXAOnZL1W5m52y3qa3LuSkjXn/8NjuDFOAQ0MaI/zDwpWla682Z1zd65zivwVRdV1k27iHHURwEC8HnRoj3z1dfn0Pl1kEOJkWhiGh0Dw8NLBg94N6QX8becgYbUwaU5ZaxFn3FH8fPtAjN7dWV6eKvmcFwflQtyzRq+vyF2zsl+1qKKrzqsaCoWIktNEvQPefK3VqH778WY9hG8M26NkIS5hUIXsWZemRPbT01Fd/guipCyfQwu7duBMRNjNwseZb2nWN4d4STwT+sgJKd+yvuRVIyQCggPj3NHAoM7D5MPdB87M6wJcbliPV60G3y3pQDSEI5cFsykXy4P36M2zC1RpTI3G//xpObDpY2cVZZeWrq4t6nlZjcVZWC8T0WBhbl5hYG0h6cqmDw0lwlQZUcCp8kQfwdXLpg1oHwINrl/4CnjV5WGCYHjJQ8AzQ5qavwpusHfjEj6TQLLj8L01wjxGxrSh/ICcn9f1ZKC8DXmTKLutjqL7JjiV67qBA8kLNJqthclXZ2TK51UWgeWCSek3Xt3q13f4u7R8wXRI45y2lYP4DFvxGi/YHe5nWgIDtsBxey6BL8i9W0O+Dm67NfTuZmCTchpr0hHSE3pMZenWx3TnLYCCp5ndHF0U+4FPVcoWlatgkAno2VVPGEpMJCIFPuT57DcmOXTsX+6G+QJmqmIxHZWYt+cumw8DOnFeOibsLibvWv+deznGqDXz4Hc+gq6FwyOEWFjoj21EEhZ6slFvwbmUR9pY3nDxMrig3QbwOURgs6Em5/gD8bSVSJq5mfj2BakzLQQ673/faFWu3k+rzNcRFTKuy2VpbGoI2e9NP25MgE/w25kgY+TFJMz2f+QfdwmyhaqPUSAVZZ6IVVelv/c9eeQRvXJxZAMT6eIgXZ3JxamVN1+SogoFG62My6PEW8xEpjGREV+JSunZF2OHPlkqo2MeEPEHAuVU87yptysoICZDRBgaXZVeG3Y2SdJfPlJETw/Q7/ZOf7khv442qakprDEB3lieu+CF+UjkxqY8Pyv5pjdYn6w000snQS3Vgr/cFRvySxFpzJI5s7l1zHT7kV9r6kRHXzG8LikGZ8BZc8AIBONhMxvNDcIXRiVqqie/N5fJ5Sty/C4vFFpakltXWFyi/N4D36ckO08v37uoDr+TAt1/F4FKtpnr7uap9ZKaRLjfTkBSzOa86+zb26Qx3Rdh+Xkuuz8R4lOYo4H9yjHhwb68dEYLBUPg3ENlsqDSr2akhdgZQW0DhwwGMK1DgS9e05i0t7L4jW4zcYskrPtL5LoZlBH97dYEx3JPx7cHd0r7Vm9sE9P/B72yz+pLcyVYGjyTWlfO8POW+HmGhBgWDkRyQyvzDQ16f+ZiADxc5BrNRi/epkRw5rtb0vEqn4jsO4Wmd/8ZIIWtt080OsoOWutUAPr2dWmt0929uyWnuUJqkFmyThMrJy/k7G/TA6urhcX+/s61I0cNxdjYy9q1fo6wFNLZCdlq7ALe3VajdedeNsbZmS2nv7WQxH2hMzLVZhTvqAyVo97B8rPLEys3WbkG1JKv6JNlrKC3LsofXV/53T1ph+R275ZWlqw1S1BQxQJ+i5V5qf6rysLrK2nG4hwuBMIy3u3G1klD+q0DUkThNWPo0iKpq/X8FJjsj67Lr9mXnulWiHl1SB7arc8lpygwJm/16HaMt43o0MT587pLWzGpo8GgKjYPAWOCO1SaEBZ5p2y3874YI0FHYCcgTABN0X1OMQ6raW1p0nhkWa0KZdGeymBGauxVbaA/OyVHSuTZcfmilZnvfW2GKP7cG6qRcrLTmh9lyHvvp6qyfNR0X3jjP6vCjBT4i/LiI2N687Zt/vR6wqVWXyBJulSXJCmzLqplsfOEt9ovDgxlzFmvqdJkAkmbXpc+bXtJxGQ36NbkZsUGJahyEdIek4epmoi2M/pKj+wAcMAXxmgodGBBNpLKD3nqubll3AgvMjLAWmR7WvUQwzioUfPK5aW3ZUuxtDfr7684VRoMRlikCZrYaO1YdY5LbGCcgURcTpcfRcoxjeBQPqqEMSjnlXHCPbWqgEZG9QbgeBIa8e4gTijc6kWPOincjwUq0KroEBxICzuYAtJdGFstKM8ut1f3j25QG/P5N/Q03pOjzlkuyMwM1eWl3nzLH7Rm9ftDrfWPPIJZlLNvyKvdLlVW63lSWYv2d34Ub4LPBkSGYG9wPKt1ufg2g5w4Y7QS9PTb8ki7l7PKeIXzM50SRDzRk7wGxOBM06o0U2PdGjx7Wi7Ny54pPUSAA1/OObddN4T1o8dXJWyHuE8/Of3WwCyJSLNYqp2OSsEwfzErv8Yr2eudYE6tmeTnbmiBUJ7rRmIZoxsa1KxaCFkjKONcU7oGicCV3b1HD/Fpn35czp71TuMOLo8Xa4PB5vXcV7AyQXODU/5yuV/yfIrzOArxiIEhHViD+Jby7aU+85xmJ0ZYRBgl4CeEy8eOx/CBNaUZKi3JQC9Y0GhhOBrJTOSWZUetBjdfSkTWdd+5N4Qc3hrKnRjnK4DYzPaid3Dmp41ncCm583+5KA85VQOfzHiDt/hU4AyA7KCdOUesY12qrFVh7wjh3nx9nbKofDIpdaUSNvuKKDEGNemM2LxE/VJo7PPaoBxpUq1F60F8Pg7n+Qnd3p2tzX6CXHx7B1TNxWnN7IK+MyO/EpCnqnQ7xPpsCbm24gnp2YQ8kOeVfmZqCpkjvUAcpDImpSkVwL1IILvuTXTzY7rjFsBH+jbG0Zxn+DO/tcwVkPHDaq+9phW7odWVUFHuQtdE+15UDk4MdZOWEjfURJ45I1/bHPk00dRu5Reodln+5i9iVdUq2LAZglnUsWkip6fnhqOjTLI0PsHuFAOEDSp982riHlKITYdsb5ImJoaZpcACrs3HCnJSXZdTnHlzUraUeJp5jkCDXu0RMs0VZgn1L+r6HUt6cXPpp0s2PjC4ecn7/x/bHHnAepiqe/8pt/jF3lQniaGHn/668iUShNJgzklppQpJYUc5UdfB11Qq/vyUDth+qVP+7TFFkGNnB5icNnta1S+mNjsSDBYpqG7/RFNGYIkW6f6uHgpn+fOzN4aHtBFKmTPOws10oY0ib/ngpY30jH9qApGbulW3RyO2WVmhYrPBU+m65mAiT/VOScnU335Ftoe88dLBDVUIigbMU6JTQsaoFEI4WKowr9f4BFsZ3Exas3Pf8wcd5pgBm1BDkjzdY2E1FjLGqKGLIJD9tiIvgHsQiJKDz6AtnEcCNCnyVKx3in51zd/c+NCD8xwa+kth3sGCaaRFYxLu9H5VVIP2C2qNaCbNQmUpCbGOpW7KuDf2bzt3+GfIzsdDANH9pAihuH9N7aDlVagd75+TfbV6eyxIZFnXqYfopxjrOlpwk12mc34hU145o4daDA2+Y490YGrTM/zR7wkf7DbVUsR6P9sz/Ta2OD292OLXxBnX9oODKko+N+xIBlFGwIGn9PCoL5UIl+aWzauknntVq5FPWL+cvpMW1v42ostAXqq2YBiUH2z546Izdu5PyR9Dwbf9LaA0hwVryzQHr7v/Bxg0PTQcNQHNu/9AaHebl4UzOXX1aoppD2lXP56Le3svnFJ4DkzcXyNJU2dX5+V4kyKqsPapTiH2pZJuhvG1Xh1d+fyOldUuPGG5eiE2OZ52DhLQGaXgFsAl2PybeYmcDBmzOwCOSR9w2LSgJNbbnWjpCBcVqOb9xkvqurt0JsLwEOYKamzUIshMvuoyDTQVtHJ/zE+HLZZWvrhX6gx4JQJaeKCtXtkOSrD0wZIXDoF1rq3KPQTLTE+hVsCpDgSTm4fP5gY6YOtYWFXehFN1CR03d04CrI8hnp1SA8esJzw38hLDzJeHWHZsnaqMI2ze1SxE6B9scY4GZybxVJML2pTdXYo78+8uZ7t0T60sRRbPd799RuWRsN9MhlcxIrCuaWkuEAh0A68TxVzkA5Bz0sxWNdYFXYkKmdy0+x5routL0re5sh5NybphzloDAflMnDH+QXUROTcux039P9gg6UU1yYyxQcWGm5dN+FIrunYQcxYgMAHA9MU5qXdtghBSN8m+25epowQur+yxg1r17hfrx1PU2eCqopy87fUuEMQMW1oPS0PzQrwPEPnqFd3mJfkoVyqDEQO+FDvtBmk5h6scdkd/YR78prgJEEdZw41lnU2z8Bfj4biODmIprYnBdCY1Ny0shEkOGTNwiO2cBrM5lZUZ0Wgaz7WsWF+CN9gs/dfaoOuf8AP076fk7/aoL+ccklNXdbiDgRSIGBPtSTzSZc6E81Pl5RtMd4R2V+nlvX26jU+FhzY5r3N+oMtpZaF9toOrs6td29ZlGdGV7SwrbI0Pv8H2jjnLUHiMrtQLSQQQHzu5IMWzut1UryLmOoLu5kEsLeXYmNOen5GjyqpSGFM9wNs6UaJJYULXqv396knyC0RM7sqY3GU4nl0anK/g2902vjF5udAbF+STj6lVps0hDAyH8Jkh2ozbvkx1GTNO+Jx5Qyq2EEa9cfeGZKhh4doMsv/DMtKv78eC6Ri5ACsVQGBJwrwWY8xpKvMtza7PrrhXhSsQBJpLKSm1VdJQ5w124QYzZETDQgOL8qVV+Z+r7aykfulOShqO6u6JIzqa3aPITdNp+GruFjS9wQw+qnjk2x0IUgQZFjNcwJoEqKWCLK0vApG6WRP0MvJJGfVnyjQ4CLlelQ7kqMBLtXd9t0uRiXIIg/CBmypBkLbbZmSXOXuZWZoPBr2yKkdZUMFybtm9t0DXxkmYpkK+aOSYdaU/IbM+2VPjBYAKrW3tBh//ueMWoEXpZBemUeg5OOipSBKdCQZY+oYMz/a/tVCWv5FYMeZAroaGOs+r3iE28QAX2WMdBAT7GuPLJK57Shbm9BJOY8T4M9uXVzqX2L1yYX2wP+2EAg2PFDjZQdc9Hk5lbKgUQyQ1kSTseAat1dub2LffCwH89XNa2YUVSiCeiC1xaIm/sBgGNk+PKFJHR2FnIRTvQ4OSqYZdfOs6HpK5Car0p/cS/GlMrSE4UznvPfwj90gnRhvwvRCKCM3GO4RdUYXmKprX71NB2k3moF8etjqo7K4vbgQBp1amoLdLdWbl3S38XrS3gYBr4o23rr6i2KC6RqaZQmyyPMWy5sFNEzmmC0iCmD+yBKepyUeNl8rfPyf/07ah9Ji2g6+4KHt7o8vlSBUJZVOYHd0W0TMLKcO+JONma3BlQzSPbYOgWHYlj7JVepZwF/SmaRrbf+8fHjpjvyzS5nlaqRyi3YhbgSKcOcD+Uru4zLrMcU4WMyggWGfdLIfjIVBCMuXMQWuDJLHgxk4nWX3EOND29Lp3COVElhAxZ8fhCFrlprtlsvTOiXe28f4H3dn1tzqbpl1PAGvNGbYmKiOeyIcxbDWsLI2gQYjmtbTWLXOeKpCYxHI3gExCBqFqhxOAMRRzomFdqx5KyRubQmq3+cEfOoSuyTEBxhYfvycRAG6amUDhE0Mk4AshUIS8qSenO2AjcK31hI9pALMz6wM33fswERLtMW2Wgi+6zUYGZb/TpHUijZt+bLM+TDs33zYufrDGsOM/DX/QeHdAyI9DTm0tCp6ugvZMiq51SfnsSlW9oc7R0QxUIHELqK6u4VAgFF9ON1rbglizstcx7zjrW+T0KWVBqMTWU0Jlt1XpLuMB5AXlNSjCaouC15cun4ueeVVZ5q+X5EmfrhMFkTaWVZGfYSM82QtLRwr9aysphyx5Aj7AFYP423oSuFKLM3HH0KxIe+HCJvq36oXOScAsAbaQWLfAXCCk1b3zi9RRaayTbaXM79SH7u1QownTO4gGx4NUmMgODU3I0JzCnUP7dRdkc2VAnoXZqVnXKiWlXpIh1wLdyG5wk+ApNZaxOWqBN4pXBt9DYOXi2uws3/rENdV1fS907tmVLLUaCEcT83xCe7WnZcCCRDd5E0jziPok7tdLtiOg9Q05u7fcPX6DXV64sDIcndUQFt/Caxw5wqbKLd9OdkqTPZd1VzdS4lyGOpb6wf2b9xD2pZTclyOFpiNozJf6ZZ+BYD7tBgXWU8KKJlD3mhRsSNeIbrdWSSoiz/RKuXliMqjrBTVac31/Rh7K8HL/MJxg68/XS4adxlcQVS207StTksc8LgUScmSrem7X315PkAaKE0iq5Ep0mCEbUgguq0NFNtr/26Vn/mKFRm4cXocZwMQuLERf0324GRRSh4AjaGqX8wCYZljSFiWWP1uV/3hQm4WEHQjozHMLKBiEYppKfvWbcv/dSVQkBEejie46pNvkSeIWdr2uB3Y2p9GgvnjM82lQnBkZBVUKvfeV+jNZZWdCT/utVtV3DLE6y9TC6lVZXhIsR2kHGDLep1BgZibd2+PNEedVQyFvQhRSw+cQwHZ3YB0zsmaoqwmhnb97Re5RXKFEWHeCdbf1I9QFoimcu9VJVmpAo27OzaMvTuR504eIieCEuFgAPEa0hWWXXUvihh3fkFwLiH5mi2a+8bvLBkR4YSrXPqgLLnTGhFvtCqmA6C9o/LxAMCOpmXgG155/3mOzhx4NFNVn/eevRp88YaflqDE4d06327foS/5yh84vghiT6ZhT0wBpyeZUarl7nO2iiszduzcQ5+ERVRrUiLl8Rb7w69rloYKs1MKS37zqIOHrjRhVCt1rP/2aHGrQvoZ27VC/lGE6Qo8QwkjCngtP1DbLjrhYnW11wIDHzOtbNotBq9JEW03VvdYlv/S4uoIO0U4yYkwzmA7iEQ1hefstvXM8S8hg5AMpPAPBbrtZDblDt+ElWHe0X7cPF2rjINpdBoIrULwlWgYTgrfRAJSSc+n+iDm81qPNoLD4LXrZ+qg5JD3zOseG+0BToCSErky3e4f0xfbX6nYqIVcnpOump1tcT+mBj+nDtsC06S6C+NvjSzUuwkfwH8jvTEhNTcXxjfD6QtKtogCiCYVcPdvmJrk05fne7uHI7k7bWkzp2jjYUIg18yiV9MbJlVMXFf98eVk+uS5WVV6NQklddkamsl324goaABNDeTEln9yYlW+Y+b6vX/ZvV253AYWfe4RlgmXIFOkanLY5BoV2R2ft2szXaif62ekFO8g3xjR9yVTiE4VUJ1ZnzNCAPeu9fxCpRvuFkE73ew/9iL1BO3aF9KohrYMK0YSoGvTeUKdKxfVnujvaUrWU00WIFlNETregTiN6JqYhIxzMzVUZA0x2dspSQj2+rUdYxLc+sK3t4MEr7CLyRWXBQqsshEF8pU8OmjYoyZfqSfUMVZt8JAmv/ll7sQO8ZVyuXWBqMV0n7SeIqcS7z2h0suuSllNm5sL/s6ynbgNHsQSlbuoMpQZgmCmxOCZyVTBcFg4SlBk3etNO+6E/e2AqG8nk9x0R7Qu3Lihm6+m35XidZw4wowSYHjT1wrwDemTOcp3LqKEEEfx2MU70uM9PCJXfHnpIp2S72GLNiAwSTdNTf0DW/2pVWBYsPC1jJmIDFLC1dTU4D040xfmDS/5pt7ZbHb8DKYUfEKakrckzkVhkXBvnerHiVkOWlBWqVodoK0TYJSvRPGfPeUnsn/ykNjXtY8MBsm1Zh4mUg99HxaAXJNGMC+MTrBA+1avdD0I/cUBBIGnkUIgVHb8tv1mv7egLkP25rnYawp2NxzPSCWciXx+TCebp6AEVYRc0sb1b/HGncRekhndAd0H8Bf0Zo2mfPlqoC41GlT3lvP75Kac7c7cATC6wBIqCFWrHZQC1SvN1y5nz8vnPoZAlfqavYsukNDbpgbXVYHSO6mNZJSYgiwtrU8vbd+gRYApT3gEE0JZCVYLzVDZTValL3WMYIlnKIzP96+XFibWltMuIOEHN6zlvaGJkWHKWVuu3KVv4MoO+WByEBwqE8LWIdqMyoAlbk/T0y0liV9DOHdLQoMAFAs1886qQXwFRmCvA0E217EMyYIuAom0GUtnmZXIKgmWl+j78CDpHfbswDLoeBw+9D11n3VgYl6QjU1Qa4FnXcXkIADQ4LJUGbkbHNQjE/d+O6iHqyGG3rtmrFi7JoWbPceKhRTmxSxdT16/rseVobGulJKwCPvD37nv94erikK27UrCSwKP1o+TMiWWCzcvPq6VLrGxs2d2Ts2dL88OKuNMrq0GyGBEk5GRMp+KcOsWm5itiZRE/55ykfdI56FWMpH24K3XPwJHQsVWNqu40vamKYEGTu6AmsrEjskSlaQuOkJkGjl0yXHhjXLO/mKYFnoNoPQaOXHoKXY+rcMWkvX5RXorJr26VlPkJgDxyx53/QIMwAkYUDOKhrn/dbCJVUTPTr5/Sl+N3eJJ2frBcz4RR+VB8JIhPgNkctuE0UAXd57qMRkbVE/eFeCj8U4t+EvnfwlJfoTn8AFmouVmKqsIZaEGGs0KLhw6sYpjdgBs+hpMFDgFkuVVTmwV9aDLUFt2MOdHLUKg4F/qkvPzclalVIsrQPQ06oAqfOPePZMsLw/L4YT3E+7g4dF4ebKUxiMYG74vwwbicOkXQvm3qIVAgZNAk8TGyT8u8GDqfmWnr9iJcEB/b0ebNlWJKEj1iLCO+ValuV64DYUD00eVpOWos/fSo3Jcv37uovx9r10lcjLginhBfvXxDntVXk/8rW7uS1nOuBQ/Ch2ScB6Kd0djuzs/2yxcOaxPhxUGgwJlJr5fpr3vu8UbE63bk025PPBB1DsmRwxqqaGvTS2hUpn1TDoSnQ4zpXZuS7dbedD310bNqtP8yZifpbga3XbRudESuzsrnKYYDFVb6YJuQxQyiyytzG+RN6LXQojq3zplEimG/lHl6HGFElBs6E0irFhNfN4nACDU2arM4nHqjRy/PMVWXWNJtmK3fwjQRgwLWk9ryhXlSWqTPBP5OpaUlX1eqgbC15ZsheR6EEnM83Luoubv8Ejd5Ka3XhnXvwzuwCuWB/R6HX7qkfWHeqC4dwwTRx/TGOnTJZNT8sAyM6i7zvhpLvaLALLlOoZSbxuoTKdlZozPWXNwKP/Nj+se0APCi23q2rBfuSheVq5Rmrb7ma90idfV657W17PU5hgP8pl6AqPGBMaIVEAw8uVknTfcxmpvDQeAVGNINjw32JmoYCJV0prHx/mXFmi6bgO6bX4ptI0aCcGT6NzZSDCDD5NDEMmsyid9UH9lBBF++/321AhCBqiij5V26jZzN8ya6qcTnNGzOM+RclLrT0nApBvFXDUblrsoIebB2/i3/gLcMX6knaW1zy7N++EeQNHQdg7XhDamhIZFT/Njr1/XLb0bjVXmyYZAC0TtwQErrs7PLVBrz1xHs9BqrE1rsDK38V9/U+/3C6kTrnsWMXdurT7Sym1yIBjei0QW9G43PEPQpE94iaqsaRqQpPoIEaOrACtubYYMobcVf15VqgGZmrl9W1cfUD2JVfNt+/T4d9OZ/U0I6aElHsOKTUkK9L0a97CwFx66z7Jj+MaOqg2mYCM40TSr5GRomdg8ll+fAsiaduFEryjKhbp0eY24INqKV9dchjCh6HLgdW9ddNcZ+PwNwZugx33QBxINC73N0q/WI5k9e4TWI+hkbUdCP7zSQ9ZPMA7RH/WP/ICmIHSo2YYKRNyE9yzoUqV/BVKmYXLyp2xkpOdqg0IVWgYicovPdlA0KWR3fnObW0ka/Jhsa5AYui8UsrEF1+4eIu9K5J6x9AD/+zEB+rUpIamaemWNDC5LFmxFAiUloktwK6/MSy4FxtjOxjEaCnYCCSpRxJvZnm2Z1besD/jhu4qsx3Wg6OhEaNDmqMZzPguToPHq5zw4ZKLCtn94/1qu3/XkABTeKQngOQpP5TXeDSmvJP6lQtZ4mva+CtBXrn42NTAaS4Q2i33osnVlRVGarLoxfGN9bJStYBtglqjOa5pkOrnvi79Pp9SUMD6HQE0nm4YCHSPSF9jJzJsuDRIgqlYS8dJ+6Wt/Y+KlT6w4Eg/ZAjQ6OdA8ry0I5+nYSyAlXVKy7Emo49+UprXWhR2Na+AH+BrxCcDxjr6hsCJ3uy0yTngTxpWh5PP8XbujuI37N9+Mq6L42XQwHGETuKwTSikzp+r9QL1MbrQAd2/W1OnyBpcwwbbK6pglQ1CqEaEuCFixZCTGPf7QninProgxwPKn8dXUqD3z4zuO5UpLnUF6QWkKhcEGuqkH/+kr+1HycTEREY1XGbqy0Ni9ngKegQOrqs1MJ6xYEjzvPG0DHMLOWHS6cc0gojcvMqwkTfhwwcDC+mdOVW4vl+pg3NQXFWkllLGvSv16U/7FdPlMixWF9DvS3k96iQOtplbS2LKlp1t9XGLPK87xlGomgy1UTcJBwS4ZcuS7HrMG5OU4ILwnVlXk9zDagltc+dCzgZSNIemos4dqHPgK5EvF1bjDXfv07cniv3oHe/86gPLVdt8kj4+awMewB4SFMTHh80tOrOJX8Zqi1WH0tXBrGviD1x2BBc5yC6VhhREt0PvigHuKhvJKH10X+02n5w1bTbYyGoLZyckYvTnFaYdlCzt4tPiq7Q/H46lIcFoXA03AULe98XXp2F7Xs7Ab85Vt4VV4DOn1J7t0jly/rNhw4Nq6ltiDyD3GEBue9At+Dgyptz7+ph/Y36NpotI8ThJd65BOl9i28T6Gyt3PDWMsYhc7juC3E5SQrOseJOg1vzXpfx9wtqq7DJ2SvQSR74Eg/YM3F52M6z/bIZ+7SQ9yWX/gWiOaFhbgndO8WlQ7Gf3g0VLKcZMEoN3SGtsBpyUBXIDgDy8U1WVRucFxHLjEjV+5VaShMOFgqw26Op0EM94bxav516TgQz2ARcR46kiSED0s4lkaWWYbBKaSsklIfBTS5EsrJCaV8o1cWn35R9+4/pi9Dv0E8xb32jR7dRXUwCo0MQvQ4fOL6CMa4cEGefNIFMdR9DbDeDzBE5JeeUq+S4stugWY6npQ/h6hBqNgY7gP1UD4krB4ybwvxlzs7N5vTwId1BoiYigbxOcZAUsxYa4H3PtyKLobhXZf1L2nSgRNEbjmmJlLpbEw+HdSmGzGJA5TQ3XwjRDvzadmmDdojUhHRDyFiBbkG1K2P6UO1APbVPBot87MrIiHLDPdVUmufoIgaOAsLFWh8y5nIjVigoqS0TI3NwsujjcR67LmX7C+SZ2ZHx7gGBj3BXI+liB7CAK7E7i4ypS2zmivgpTQQ2xjXV10VGp88dzZOVgj09pwCZYfREUcyEjkrYvwAY6AxHIyGl1DD7hO4qhoIiMNj7EVm1NCy3I1+h28JTTKwYEi8B4VmU3pMyvUo5BgSBQM719pRfgTHoxiM0Txwb+f+qD/gDgZh2tr0HASNoIAD5ewWZ2sA0ek61PsDD0iIZcItdSrIKEBWVlGmYojA+mpewewDNn1odio5eHm5pXbWj0RhPX3p3hemJpEZs56o4S41pOproS/McuruR5AQZ8cnGH0ATEOTP9RMXynNjsVcWA2YwDTsDsrl5ujvzL4me9+dhOifp6KsaQY4D8PCd8/qWdqt8ICpW6+PXFeikDrN8TYIoGfCbG4UhUsiQXmrV04c1d/RtQQT0ZlQpl++dUHuuteaFTNAPCA7O/bWNT2WEQwd2etwnn92EavHXG7o+ubgqu5skooHT8RSm9PopidwZqX1FIcMbtpJH40/IFD66GWR38zSFxqc1uX4gmYpMJEo82JaDXDYoBiG8JkzAWqzMJHWxERJMJG5Jdr8w32xijIV2EWawDwZpx90573EDeDsqLVXX7/cm0q5SOPgpLxySdZXJWmHEMMmXdBYL/aDQTGEy1HdweQnkxM3Bl34ZnutBKel23qPL3o/Od6w457Ic86ADYnbm2oUBpVIBB+icjNzg98Gpr7/Rj+lv/Dtd0CkujkQfK5TNlj5Fw1bo5e3bRWidZkRa20KJsxQarBUD0xPBxKJieFEZbOxTHNzgDC/oS3gLCuBPGMuR0WmNJA7tyIv2+4oM7xelgpqbwEZa/XOSDKYCQK3oU1wk6C36Ua//HO/IqeEf21qOM4QLQAaevRRjbrxCIhhFsAfnAquhbaGMos7Co5H9RhWCqzc2au/tzTpWl/wvQPiqC0QsEO62MHYRpIoOPQOhmu0D+JxqBgXiqAp+DJcAmbmQHiJDAWQowXhz/D+gEsIDcNgCxrw0T12qEgXUM43jsvL16/jbSGG9RAMPtzBMoAd8uYAMbhqIbq6tDY+M62ycuiIP5QdyCDtDy0zlIhkJRyy5PMRyO9/eTScp81aW5nIDSUGrOlonDJsP1bRtOFLw3JfjTcMs7QsG7YWLYdAY+4dWGsYamT2P8rXgl1MY51iSr2ZoCMBFc/4krxmLQmarWS1VrPcBNRLidCMa74cxPv39nuDYPAK4v1Yg/4eoHxIlIWD5buXdPdooza+G9GiIybGFVBCDJjQngFqQC6asFOLnTKBxsKoiOoa+dpLGpuH0Fn1mz7Dvn3SkJBtZlhok++dlPYWDxNjqk9fk4ez9BImxgAxXXyOF6MN8YS5P4SHcPLF5LfH9RueqE3SfY2N8vWv66HPfU7ZjF8g+ORYLQO6ek0ObMQ/n49159gNrkf7n7sxP6k251tvpR7eIl+zLw1a8kDPoMSsL3bXaRkVEDPEx8IJ4AmXXNrK+/u8eCFvRZR6hzmQTVt02d/WKbk0qFf1jiqQKzNB5BOoBBUk0bdCD+2tU/Ex6KWvBljZ0qq/k7mEQCELVu5LGIfGzVswbj/UJis6RURP41p8HmZQjtrHDpF+Bpw3Xr3WJUcOyyOHPZ+BF4a9Ha9yYec1XTgVevCoNi8pssnlVXYzcoL++IaTyjNn5alfDPqY5QmeK012X1z51vfk4Da9CsSPOnGEw8ttkQXnrOIMt1TKW0AwJjQeh71YxVn7CL4lUPLKK55vubgmh5nl1WQaaXkpNT7pr8Yuy8m/Hrv3iYLy+tij96lyyQ1rKu/L9qrlYaHBaSXnl9GSCKYzgZwJdOgc538hp+tYnU05Mz5BRcBRDC9DKBzMJC2ZNaS7mJlahq0M6cIwKBbHWiynESGfMMtrOhiJJ04RkATw+YWxprBtU+39+WV0l6IfSF/g2uaculzJW5VOKnebsSwISAc1Le20DpZG8Em9edHE989MStOMN9EU/HRqQg4Bfk0qkd8++yLWX6YR6B+KlkPOyurWx/ShWgD5MEylC+mo7nIuEYyCyDnPAPGLrqyNzWYRWIJqqv1Nzc7Z7esbLQmKJVX84NkqOZY5NnZD0sZaj/s0QwGhcI4HJV4Q4W6VAzl9XnZnSChHJTYViI0PJJDNV8/roROmPRbMRFKTljABh1wALjMkNW05J+41Ob8gvqhCXqjBotToV9byhmDC8pBnIsk0gXV5B4gIEYrBAXTdN7Ir1NEidsQ2mRrQyKR8l3RlO8GMs219wJ82+32LTZd1Vp7HIUQYrClTmDQ1q4+4dxhNqd2MxpftG+SufQFSl92oOksmUhRkzdoHhcbbdv3HobwSVSJVZQl/IuEiOwoAclkbWp8K7L/8Lp/TXuQj9Ad/mC7tsDfCCO7dy8TyVNgSUtPxJGu+o7ohcmoQ8/8yJcetm6oD6lZZM8jRsOzLlO0lehqli19eVN/A2FGhMK3r1I4e3mwHQk+0LdE2ng6RMYuv+33r9U9ZMtrWRp2FCz34gKa9OXeL0Gd7uWxYyn6I2I9CEF+wyh61uLhy6kJvp6ri82clL4dKWHp5NzfX/99DCdtDscFOw5sixufwi+vxwk2/6z2X3cYObWDNoCoUdOO+bmBz4zZucOtT+ARCG3dhzux4Q5O8eMPLIeIH2mfUPokSaKTStGSHkzHV5pm5DEmvTcDNWKuT8vnPU2AM2ZKKqvj1q8l/uOA5wD8ka5zwDvEtBxUmK913n0YYNeaNkc2T+w7Js9/z2paWbm8SH6PkECYZUGsDF13/cLX9geqSxtxm877AWlMTckZP+kEIxva8P9ZjGmGnF527jmFE1ummHDul1Pzn/drJivGw5q2D8oy+kbqFt3Th9NhPC92ZuwWOcTp9LSqN6N2kN50ReMrYSwtr4sKsZcvVO0s8tFVQEOsZ3limzQ3SYmBoYAucEvBACxRyhGXsGVVYFCpQr1qz1gGYliRkV7zUqaWraxoC1dXKf0BwYsbIqZJNORi2mS0rK3HYFA5xiphsV7QtQwcQUQS8HQCNU6OMK2WEM778kh66t0mVdbHGvLTKGZ4kcQWH7KkNu2O7F/1FI6+tpd1UcrY5Ad0BAIL6R3Wj1/Do48c0JReA5Zw0WBPIBbSC0ICMBzI+ANGGb1ERMSYH7SsYzJ1c8eaftDQo6nItHI8nZtblhauyCw6lOP6E1Po8rEzofWwo8UdDiYdNb3KHUzOyxTRiS638FVOq0DrImF/HQC6vxkKWMnKPJSC5EDi2nn7gWRDYbmueehTuw7G4S3HpNejGYAg+3o1lrd8AJahFgaDaIeb0s+ySvZo0lctr16WY9Es7LcLysj7pMUXOQsRM1scE8s6OGK9O23PpnMKUtFkj9FBxDt0b9CbOTeCKN8vfd+oVn2lVwA3whXhh3I+DB9NeQwQCfM6Fq3poK2B0q5w4JCwHAPHE+Ia0m4lWYzMmcVPpdHFzvfKJ6yNGYDJJUp/SS5ilQ5GrxkbdpnFwdVjbmulv0DOvyr5GKbNQ0kqROiqkNR4/bmcWBDp2s+q6NsqWLSn6ztkVfQP4b309i8p6NPK4RAIrpFZCuXDmqOyr0u3leV1hNr3oVZznIhjMFJ2Oc9Jo73QTi6FxlLmtjtxQLduxqOQUasTXSXKKbFsyJ+0kPmF/q4T8Xs9e75TdW72P5TNRdiRSQgjv6xekqlxWzawR5yZoTf9CLCqNt/h/9Or2rzer819FzUC7KhDXdnCGnKN0EI9jTBLi/SnjDp9DzkVxCbrIAp8w0BvbST0piOGeRHi+R5XG3j04tIn2naqiWbW7IC/J7PdLYBw852YVUt4WwkhgCJAsh1QHB6WuRtp36CFttJXoG1aGZ//hYH6+rjjkYkNAXKRSM2mhRJ6vtFj7j/kGD1E/e3phKt5lLMT4PHWwHWNQwqetVh/kZAR9gg65fElvAM/wMmXmBelkkLSu0kk3QfAPjc9LQsA1qtEwn4EZdFBWROebue2BWU0KWDCBZSHpqWUJDHnuTU9CyvlAM72oRrgP9QUVsAL7irrNLa26S2mcV9+QVrsz8cfJWWFQmigJdNUnj21OC6K/np/QSRoQAsRI/hwspHt650O1Um9SSbQIt8qSCVTe0a6kW1ZW62kbTiPr5sf0YVoA9WbQQvuUKUOpzAnuEgxPFR/TNVH0jsQIhocTFP6qBG9YuQaEHCOHfRuygX147H0ELllcl2K79QWmKoU1kOEYDx4jjys8o9dkEfWISE+X8tDycgJ7RDxx9049BMeSMjprYk7KPCOcMJKzDr5QZig76CwXtcKBSvZmgl2GxWBLF7IZWddYQ7GxEO8LsznVR2yCPCVXDVWfZBS1v0hdrU34cVEMrmonbOqd8mP+c5pvGxKc8GbbonPYPjkr9dZEmHRUDrFLqMAvF3rkK8n4w3ZX/0L8y2n5hG1T8uqPF+S4NrD6jacvyNBaLIOKnKzoZSuROAgxSJ1VKxrM729hX+yvXvORJLCSax/8F1waTcpAknFl/D4iX+dv6kvzhR2Z8qlSIboNsQIKXNRhKAuAQEu6NbhSa9JgPW4azpuAZzBNnRlYtkWvVkiN/1BJ1MzudnpDHl2VImPIWIkGp1CxxK8hNDPbWAcI9cj7uO0QEWgMYSzmN2OWGl0OpdKTQ3oe7sGlfvXlILSpMantbP4psg2eTn15otgWmVf/cJVyi3YInTe0efLt/8+nwJ/9dsFB05kGDdRzcK1x+7f6oTP5BD4KoSRtD6pOyb3tzgopHEYTHMJZxBantN9u9sW3sQothC6OZ27001FqUk+elLbtyt+ZgRTyq1m7epJMbioZ23vPH1DBNr/sgH1B5sWSXl0/94pqg0MHtbYtW85Vg194B5+DO3Q2asJMZO19W2RtbnlqHUgGoROYu+VsgmE9/dERfMRNRm0HVmwQGbdtNAbfjgQdsN1DmZKH+TUTyXOwy+11cvyaHuO2/D9hp/20/nEg7Xa/Dj0LiIFaahgtUSxFlTBo8qLcu1OyMlRUimstjxvBgpaWOq+kkeSKGdW3IZAdMAR9TIz/stxdJzkG3cqYJOnT/t1nGH1WJ/8KngNUsqYQLacwM2VoggEHjBF/obJC+ZNr8i9MvBDsugZyAVIvoXRRIh0aMHAGAzbClQIHu8QwBe85OZ+7X09juhFf5HAh0Jb37O2TDjQ6/Javaguug5CHq52yy6wUCJVD4DD3fSFCZlTKxiKZGSB6BMZmdBgCLmMPQGkQUXkyRzgKcSHLDcGC/SbWSNfgoACzIFZMYoTEWc3lqIyPSXnQQ7RNQS0V9V/tzv/K5jVtI/txU0QpOzGmN5CwT7Zkq+8E0eJLG2ozqOYEfbNPDt/0ACi7DOsxBATt3KbLp+KA0TPQ+Q3N2HRCyDm0CQs6W59LeUKX56qp0NPA2SvMRjCZA3aXUIM14I1HYZCxWBRyhcan9cPpcDfdc4KpXHneGspZc7pUlyMSLLETvMDdB/UHEC2PRqFDGGYud61NEJdMywDJ6Qbz43NREEnMGv8bPfLzQS33VVmn7z45GqdnaX8IxMzljhnoHRqnvk4dUQg9z5qWOGYQgIMuc4ADC0En8vfky3rort26FhlJlRCMynuSJPYJs97LiylW0yq0fOj8iuTU1IpLout6fensudSv/ZsCV2whvziWMdhXSqlaW/iIl8m1Timu0sT1zklvxRJfQi6vy+esWzFGSERDgzfxidgz3OjGgrjJ9g4nRqqducPZXqlSD0IXr+SXUQNbx/Yp26fD+mnQPYc058eBCQbH4NuLaEG7Fbx9tlPa7Lm8P1VlYAkIBoMBHrIed44T9mzJuIGqNrSw+1gk9PXX1VN1+VC4rwgImhTi0cxMo9gyVNuqYdLkRjJumTzrS9G87XVN27T1V2bX8/LSkZBuZ4Yzi8v87VtSXdf1qvPXZCcjz9W6jZ1+4aTWucKcQzAeVqfSAN+zz8j+A6s1VehwQEYGL0AcoR6DbOFwuGiBUvfIdWrCx6iTpcOTspi4HL12NcmAM0SggYjw4WbdJlrP+8Orr1/S3cfuV+GlYSEahK5pMe6Er2AnTnPIGWOJMnGtDYcGMgNlZckae3NanoE3N3pA4JImjOmbSj/r76W0GqpLJ6bfaOwcEz/uth1AaXqU7S3V2uMN9lxYmko5pBE4otgGaJtC81D5kvJnym4OY7RnybAaaxmjXiUFGzdXDON9KGNDD0IIEeUxnOvFp4GHUJX5Zu4TIT3hY/rQLUCfdNrFdUPqLYfS2kk5VPxEmF3ewtJi76VVHI+8UoN2uEqrSeeXk0rK8OktLTR6hK4zXtAT6Gh0BX0HEZuAPVat0xsi8uUF+R0Tf7QZUoME9fXqaexeoLyNWdL6CmlolIH+TRMJyItEdmxX084ABVmmpXqFDoZgphACx+GFy/oFzqpiy95clK1mzVkfuZiAmF3yzh8uhLAJmYbJLputYRsNbVL1zokfuAHkhQAMVHo/bHKNULMoX17cG4KosoGOrxnnP8U0lbQib1OKqtUHkvJndodfWJFmplKrJpb0hswn9OsyzQQ8Mya7pj0xxzRRx8tgofppZkk8IL5o9/lI/UEdOja7J6SKKyfCVD5tiOX5BJEUK49lpQg25FiBmj9o1C+Zi96qR0xnuMZKEmY1hjcUxNPX7jNhSthsyL62wqLm1nLKdcAZCltQ+wr6RK2uvjhxQ7fRvaigM4Py+RO6SzfxS12jckQ6kTp1SnehS8+N9/bJZ/9tq3PLfHmRjP7+srJpDqFsJ1lNRM/SHsx/37iHMZoGMqpsFYReEx1MVi7wzPgJD+SOyMydepI8zvEMvMoHdtldDLjd0f1++GTAWJ9l0tp6eIoS6aYkrWySSBOBK6Bt2xTaxIneUhkDcZuez2hvqevQ7fnhKIYmO6SSpJM2mfFb5aW+c/MPEiIYAyztJtUzA6K9PeHsUUamPxNMTUeboNZWqO2OTWqfh0DIBE7MpOWyGM5bg2+9kXBQCkN/dXMc1bADp3uEEPHP8Kk3kEVjQrxbL9+46dehQapCXvCde6KpAN7uTBCZ2Rzvhj+V/xnj3/aX/f2r6pdDVj9J1fd+4xIW8Th42J9JtSx6Ky84dHKgvsm6MRAAhH31qwzvKJfI25cSy2tpDIJoPYD4ojY3VJlUZEy7O56LTclz1HUb1kOfukf5srdz49TLutvcpACLvxAs8fu7AvX4E8QeZlN/9t9Te9q9KDiADzPg3J7HHtOblz+wI8iMMijHN/fd841oDpHXh3TozAk/5g9zBapz1boOloTT6+sZJtYIAFAJJoR4OmlXzNF3q9XDk6g1PAcI9wx2dD6V2+XbXVTg2delMKmQCLrcrcsc9c8ouIcwbWTc5YzqNqDq/2PvvYMsv677zvtSv9T9XuccXueZ7pme6ckzGAwGkQBJBIoSRZGS5ZUlW7a8LrnWW/a6SrX7h9dlbfDu2t7VSmuXXFKREiVREhNyxmAATM7TPZ1zzt3v9cv7Oef+egBCADEkd7ewFE4BPb/f++V7T/iec889l/tbY8Y2G9gz2yZtVWaJNDyRO7mEt310x6SlM+af9ZqwtrdrXRZ+pZotRLX30welsplKrqH4amXQuRtGF+zIcBDE54+MihnGYEN7CyXxWvPmRFHykvfXO7VxqbPPoMe4eh2xBlNHb+tDwWeATdLp7AAAQABJREFUeD7Wjr1g22hJNfesL2kubsiK6TQaxASYmxPmWINs78ddn3eG8hguALhzB3gAAtm73OZgh2zznv92zPyuumHATXDyyvS2Bb5D/RmwL1kH0H6qz/fJSjYeHQ7gBFrPDlvRKfhyfX1y2okTJlASKvLGbabiK2+Lf9IRk0Ms88WZuHkQ6KGjQ9ywzz0hXxhpiG5OrNgVovg0BkBoK0AqhJPAVaEZgQ9VOmhm2am+JvvolyKJhc2ZPjmv5WT11es5cm4h5l9xBztcAw/Txc1lpmuPHJocNEd0bhLb16+LxoMhcbQgBo4A97Z9+Gp40saSeWH6LkmBb+Xum+uGRaQ6VUA4H6ZljM7iOjiK1etxXSBe3tUkzQKhZ/9o0PzyXvOn12X38zUS9F1V0/v9VwylwG0RhdW4mJ+/NOa/UayD/8yoiG2EoS1Tq66X5Sj6mpbnDSHcj/ExRxIZ/MFIdByKeNrqOBRc31y4Ol3B4i8sT/SapDpYbeApCq2NrbI6Wat+OBm2dviF04AOi4DAlExqgjJuWevMXoX0ra3mW3qUG3JpTAvVU+2IDW9CXD8cUV0X1iKesBe0tobr3tW19uabsodaAhDb8gO+Rumjb14xX9R+uXpFesHGZfDxyLexuqWtXfoRp8WGTjhEl9kohnBDOrG5uXHjhtyc4rllnKahAUx7FXVK1ULOL0urki1SrW+EaSwNmDGNgKJZt7ZNp7pejDyMTQo0HFO5evSIrEp8U2VqO28atIQMC1RALbrKnGYSSd4y0/3D2l/lYNMlk9o2harAGZqoW3VmRQK7ScH16PvQjKwogV1H1iB45jP6aVoACKIcKUEBQiQRao+imYv8U9+7VNetwTy3u6Y58Ee/H2/fpSby0qXc0uoGhSyIQO8zV2+a4e2PeD42D30W0SNfLBcxv3TJvDUh+/WUDos4A/sYo39N+T5Fi0Rq/uQHhmISVl5Q2szW8JfJJY8/pomvjx3y1+h+IJN+7W0sEYQO6dLCYmzje/CKKARrueB2bB/MDxFPHEmYNn0QK2ESjleDJoc+SINwlE0uEqMtwX58JNEF6inpvx/7xzo8yZyp8TqSiFyj59cX5K2gmCQxOLlkfhZRDJoHE844fyJrfj1q7GI0Bevyo3XeWPbgsV1mesiOJkoMpUxVInfDohFaAoZCpF/1jcr4Rr3sOX6Ibn5a/oCbd6miQNXTJiwdlssJVui/naejVbKlH89STpbidCrUnEZnT6mqYXlbevtd7oLjFDP3gcTWzPqA7J4lNUP+FdpSBhDWRGUZ8yUNPn7ulOzSdNiRS3dkm/tLTDPsTPqAGzGRKyvyVDgHQ48NhZo7fZV7xUjP65pTlae7NibXOnYLP92+kWPxevvaiM+mnP4+0UW2x19gkc+EFBlqQswYOJoz1wjn6YkL759+T1tWyIaVIQ/oFahf2mSPbo/e0z1+1Em8MDe3/MN555PGvZNPhFmhYKNiZ7EmtF77A7VmdxOneVY35s+NVFbxLuY5CucedTR2qMg9P5+7Nu/Me0TBD33Mw0fVVSY0DwEhyLZoYMoUlEtfvZogZro0K3vUxWCIwhdUEwlcBjzJMzUqHw4dPOJ59SVpV/quY8cF5S4aRNXTgJHq8j2me+3KMyO6zfngXMx1v+4W52SwxCJhUlRgQjSMvoJ5leiAc7Of2X+0fe/566iHPg3X0NDborXxBJgUAaFzkeKp2+IcszpwRUvJ1uwc2+GKYHF9+PTprX5t7Jqt2ZLifCad41BXzPyLb5leVdbMdMTloJetImitMp4tWXATIqec6PjWetbiG8LtsZiTSoRV8TPNX4dyblzNWYhpjcRrr5mnn5EzIRAqp1Q3l5hOul70aFGZLzEjm+gm0Be4CgJnoL4ZfrOv6vGlZ6ecO4B1wNA2UYrxE+KCAZYtVvUPrMxkzYwKa8WWHJpADymhWazwsFfHqrtBZ8qjlFvNaVqwNIOodQzhgVbZJibExAkiHBDcjzdLw9rhiFsDIFVzQJsLd4v/mFEzom9+JWd+vdUJew9tSnCa1xCaN80kyHU6yKmugaV2vdMjolNHR2W2MTAdAinyAtzQOooUz6UpmLEDEfHi9+Si+QvZM/9U56Lg3UEYWtTEwqJsYwIRT55LQSrIzVhlRsQSqtC5W9SOn1QoAMP0tMmiHBA1LSvD5gJGDKVZ5mR+MiMFao4JsEYUIVr+l2LOMCPviRdUVBVKanFlVgpFbjUKIxN/yYLgi6YoDcsCr8+aOWoDPCB3QJ5pQ/wWiPcsqUhOjDieIasn4wy8q0YiNGI6VP45DU7gWbTSQw9LQxRG3d4Nhxn+etg8pDl+77wnNzzjMfuy5vHj0igs8th7wJnIFy5y5zbjrzyfefAJdTs2N5u7wyE3BktS+OANHGYI/YXS4a8NEhfrhC/aHKKFyemCezkK0Q6ExKyeQlLwuHg9iF+wXo3OmLHZXS44Q0ulmOtU6+BDkrIyiVDOREIOUsFZ4g60BoTb9nO7ZSm5r2NeeO6q+MbWGwxlpSna1JixHgA5bF+lpoK+z+8Nmd/aKUyCpDJgS+PzzhCMhN/LS0Lk0N7qMw+dlu1wQ4lrY92DYIP6aYfiogir/OpQdT4nNfetk7A7sMm8x64Ox7TALUT837std2CVbd5lnL/aqNShuTYpecIQvjp+vseWOsnlystnXjxndNBR2pb/RgaljzrIwEDMrCpYWnRFo1XHSh8IiTqYHd1mMNC6W1QohVefCMqYEsTaaQiF9UBocDjT+pnkH+LuMvpt1Q4tCQbFbYNKqb60nf39583JBtlNjUsuh09beG3e1FQ4jj1akvn8LD5BXBYq4QR1zNjmTRgHu6riVpGUEQzmX02rVnwwKw9y6SULy2Z4zuwplBeG5hdEieEvQWiPISo06EOJd5MMiy9n8wOpCE/ZGPtF+6ji3egIIMqQkkVVKcGX0HrefFX+/Yx+whaAXWN6KTKIgFw/IyZy/8lsWVupmZmSI6Wl4ZrI5x6LD/aLqilfG49Gcpkt0X2szPH8ZSd1R878AGEHEC8LQwmBod+wcXdUl2JeAFX1ynX1daa4JrBFVrqR+u/1pbLUEpoEOr9gfvmkoxXRRSjJCka3bahgZdkT9idhOAl1S+DMOie8LqzkSTmmEAFnnfqmMrkbnIZdsWGCarL3ZRj7Iwhe5uGoW78ehEmRXVVCMgPnR5NysZmlnta2adAv3btHcLz7pplVh6Bfi+mp8ZTbEjNaTDhTU7AqvxqXuvDQCHEHIKDKDgLVWWuO7HbWwAC6ePye8WFpfDI/D/Y60UDSTLhDy06D0/LSNJ8mwmIUqKLAKKB7CWvaed2v33DWXOJl4RlOwVjYHIRn58SV+qoa+m3K6+8MlpLcXuoTN0yN+ftDW9yBdrvbrWDoWbw1psWqOcCUoEwYb4HeWDAPEAXzCZiBXiGZLWce2y/bGL69e50k9kipN7S5ePZ76YOPq4HZ3AzWFHs3QOZ47zl6sE7vvJCWLNYhudohOA4Gg4jNMrWhrMapQEvtsaG849Jo9zrn38s/2njiT9L3dDQEo8Jl1bptmwIXThGT/vTj/0FzE8JSmZdJXDUhR2OTWESE9NAhuWOwuZrRCE8QZSFv5CovjTavSkRBPVvOHB6R03p7cyBPVu7azR0Rbfnz0URr0mtk4EMAS+7Q/JDGZXO56prxM/2G2aEQIASksTQr51WUxiVcWtwuB0iD8XrLjrY+IAUvTN+19OiEzGOEECbrbjXpbkxzGlE+UAcghKQkNALbQbOQMBd2quPAhOgNG/8tIFF5w5zpcybL0Zs/rpMsD/j/Fanqvec3fvCYGVf8MTAoLQWIsRFfECFYJ6we0tKMcQdXSlhcD/Lkbz47gYFHeUFP1WddlMNWlOdbXeoplHQ+COX7r4bMP6t1UALGI0ZlFJWA33vbfF5XPUKhQ4xRoCyIVUOBonhLe3J2TJQjcdyqOs/cVBZ1A2E18NNqOwtlp6yspBy0knQi0tvb6zPxnKIWgvGwk4Up2BsYTqC5qvJgMAu6BUhB3PyZZ0woKozpzqaBMqcfcEZOEnFxOzdVhmQQn/T3FTOg1ontu686vWiK6hx/BkDIIX+ROTsuN4fJeDUXqgve1gut2xOuLgxup4IDKRoWwnhU550ING+FQwXOY11HqKVIoBhIEeITaBzrbgEKAe7VbeFcBbrRFCzPjvdvtzwobVeT8qxdHqamIoQzyTtzOcMp0CQr66VNV71sM7CA1sOP+rKKEZjSQ40NNVqgTxwSGACyDgOXX9uUXUT2VNgcVD4BCoOVwaa2y4D41yfNLr1Dd70UsLTBe0oacnOai1tB9AIvT7NAtHa1DiGyHYsJ+t9aiNuxl++tmdNJWb8CutJv9ncI5rC+ysMPmv4Rx3OmxH99lcOoAOL56SxNak8rDMrkH7c2XRHJ0DuY9cZN8x5phzSFfnjz2lpzV+FDvy7v3TmxEl5YKSovWJ0XdbJ/y9QzXgJwQDszkezi3XWWc93HCo887gv7BWDRW5FySmpKh3Vnlxcmtm2ED/+ErNf+OdOhbWJbyTr89EhdvaB86+czHMdR68MgIPxuXS+qNnMmiY62znl22XRQx1k7gpLiFUw62nHMjh6R9wSKQUVR9+ZGzro3r7wiQzc0+KLaNPoUiaCpIezlH7JAgmya32wVlwaMbqt64mTSX9Yre/CEWFCQmU04RFSRBfuqpGs+cL/peUI+3Lu7WXAZiW7WRS7w+fP5q98SW0ZlCxq/MKZ2t9jjcs3SL1oJUpyjaMT0dso7XL8ta21Rpg/vDiIeEYg4qzPvO12SKyXOLwYDTNH75ZbaI/EQng0fW8aw67YNrwq7k6HOF8JmC4lgMuOuqarWirzJ1Qlyym3TMYEN0aYu/1kgCQ9qkCts7xCshYt+/msF/B70pGA52t9qp/NDUkRbbm3Mi3+6FGvI7qmUIWKolAGH3Y7SODclyvO7gitkqgD4lUuo2A7dYf4DpQ5UK5MiuALoycvvIHX408sq3ipxxJ6AhhlhQNOl9R5ZLceudFfI3L8KaRmIaTzIDm8I4XXT0C1ksChLw37cZEBF7NFO6S8rbleGBd8jdCFlaT847jP6KVqA3hNGoZc9EtiqrZUWn7mdKa6mXKYCGrdr+Ll+xHlwUHr68cfTrrwrChYTxRv3KQ5m+0MESIZHVLOY/3XdPHPHsFiUImcJeC8ROZqWK+oph7MrPT2h2/UirdjHS1dkt7VIxsSaOuTt3PV1PEiyIIBZUHyLlSocHUKVsimHpTFEGNRZynernQq5zK2suQi7YHdy1BCSEh3QJiu1zMkE/Yuy90PDXNhwTucNLeyAE+98fB6UXv3+n1Hd5DXJFiMYD2EskERa1Zb/DWt1PhUXw8kpaj7pL5zZTuXVhBPgqKuSVbztRDnmHZEc0b43kGOeJThkZW7sTrLj0Sa2a+/3JG6S28amFGz0jZuhAWdtKxU7+f3TQ5M0qeodvgPRltCVqpe3tmVsQU2xpIHtwyVeMkReoKMVpmDSvK3fgGZAYbTpNhfCjax0r20sXc+GdS/RrXqpnIdSeZlLsubtc7KLlUeHl3WLe3JycYNF3kJlgeSqXHeYoiO0s19Ow0Ri7yzwqI1v1h6q2fW43x9Up2FxgQw3O3LatXsKG3dLQWOA5Qrk0vcJPrS4vFjBBtGl2wrAeL3mu+L2/un3tNWhZ3VLPM7sRynDZhGzSF0oBWZU5uKhNOOonvaT/SnVlszoxZjUcpY59skOurep2XQ8TA8Yd88ugSakc9j6oV4v8zjHvymfR8UvRiOiBOewO1GRJFYFatCmOW8lnwMfINtoj1NtjqJo2vgnnyzJltHretJ2sufnO8oPbfrxwEhCKedd0pssygbxAsyHs0Mf1H3C8kUilbvE8EyNzLazHsmwnHVG/gipypCWb8cYqQYgtI1B/FV+QgzXzFKfBIa0j8VFPwHgVM31v33L7K2QIfpROVGGtrhakYvu/yz+sXrvXr8MObTRX8paMBsL0GDp+/Pmnz/kTCVioPOFZ5NP9SKnRO8LmtoLcpuZmgbBbIVA7PIS16Zctra2RNpbVOH1zLSpYznjvEgjdG3dEBpuEAUog0IYKsAcYBEaGZXaaxYr5+czq4sZ5ByCPdLZHFUJNFYuA2I4S42tqiXSKf8uQt8M2UhXJgcmiqIujRcIImRm0di43OGbS+a/v19Ap60xjWNwY9ocUyksKxcsEtYnwSjAShww4C/E+UBMuyaYOFF+iTrntVGRIrY5AWIQDkNmBxNoNJR4fYHpVgZksQsmSCDb0KaOJll3K8dCf/EccN/W/vZRcKzdGTqjnkd5hUipTVk+wjobhBBUA4GV7ztpfI21crtsZuDMfMlqMlyoiC+VTiZygWpBW4GKSp7iHRe5IU+SdkC72aGJbyTMbzP9VFuV1Ca3Vz62Vr8CS0Zk1MIyLhxhAQ1tH76Lz+QmVsL5eqAzcSx5kI7DYABeG5PdJq2tki+Xbeb+MTC4JsJuiurF9rNboHqBESfxi7DM2FSfiK4Nw2NfAQHf/37GWsFDLFJUJs+CerulZg4PsmODfB0MUCDf6mSHAlghTsAzQcOwWgGEaWEcw/YR86meWzZf7pXfubwqa7oanMrIY0OslL1dUiqNUnKsNjsf2Bicazkl+rFucDJQUZhTX+fcWynm/Oi0IPHTvNntysai/JRgExfKC5yO6wCvZtM4KjbgROPDNoQp9IgwCf1oPaJYTFQumsuyDeD4P74qyzdboi9sC9MjfNTSlsGXgWjAu9C5skT6S26ifVHDFLsyU67J2u58jpolvBHU3CzvQPtYxuNB/GKJr3iAPJOw7CF6952QjrgDRAKbrZpFSpPpnUHncAV3a22TQ6houtJOlsNFQSgC5KFCtHu4UGZSYk4g3qylufkott7kZ2c54tWVJChYwSfTDvjzEKfjsWypZuhqlmFPitOERfnLsm+Hdzt6PFziI1n29ndEmOtrckXHqlqKXO9+QwxRTyTp9uUad+tnMI7WwlJuwjT+qH98YLsuM+drla4EjAIF+BaIEi9wBbsWf/LVGB3SHSHaCkkp0RzIC+cFmsCW9lUfOWpKKzxpYuaw1my6sdpMj+uAlRYdQWPA5BDOLexwUj8BI4Nm/Heb5pcVJwYykr+uywhJFYFzOwnDvAwR67OjZr9KInATpxfFaO9GNAE/384XT+RFLdsRjMUF42MUWlk9t2rGUjJeWqjvMDlnimkPRY7IGuLPfxA1w0aRpnVHzBkD/4x+mhYAi/Tr9YE54RMrYiXR7F9/c+ur/1r1pc9b3VhQHEzZ8ajCXfUsnORVPLKyGofrBV59FKHTu/T3IBM94lKR6KRqQlIMWMi0gkA96o4Kk0tZq7HRJMgRuhQfHqopMC+cM8dPqqLPpTx79oputVbtxvVgoWebDDNV+DPEAeUKweuoH76oWuEd1pRP26t3K3Wb9KLZ1O3lNRmqQjH8zTfnjpwC34kl1ukcAE7ufy9kfUuUKbbNwkc+BzlCV1wfkRsgOM3E7PTWtBvVbpEwRYbmSErCr/MJOQ3RYE3nqjZpLNTglbPx7Y10UVQwCRYzn8sH60rYDFZUJiNmS1eWRN5xGLBUqrYct1bO/9SQdJV2Cos4YVyu3TGUGoI6NePUr+/ZrfO76tNSgw7CNI9qpJvtJh22UhVrAAtzGcMIn3KGGXCUhFwC8RDlWnHA0CsgbIr0QK+el3pglRF+NpWdDdmlNdf8vPuA2IPavkFPJJxVE3nrxTSpE6hQqKgw48plSynYOqmuIcoR7lRmxaK5sCPaX4M6PiMX7BA/a1hORr2KFYxVKN7hw1+Zc1YSUzW5c8En/YsZ5FYQf7srJQILwVqAwLQ2Y9eKaEpYF28Bko/8GOLLVPI+4jB6FxZVfCF3IEQOA0PoWBjMr0uqygTKZp2pbHE2RrG5ueLQJKdlBkd4pWiNdCaVdWBjgGgf/QFIlj8fJj0izbgWt8iX2aF+Ux0afrafU5ubcqED+9si3tffgq9Nb3GGab0lTM2HWNQFBGBBdrhw5spcKLIdJUldTSRm3aaWCOTTptBeksbhzRg/hwBXSCjxQehiv8wqjOnYF7unYUjqpihvrU6bRKEkS6MuIPrQqgXd+9n8YxXIvX7bufMAJDmZ6Kl/RTITYHEosibcY7f3Plh67MsFFrzfeWkMRL62aQqD0vseousgODCm5jZgAF6Trje7ys2TgC2vWVCdOpczZ7LmHynb9nYIJs6kpQoCxHMLrzrrFwMQL/aZetGNMqqTTjPZyslZR3KBR8lN6dVsfDFEYJliGgppfRtx98wk4ycQpzGAYIHvIwpTSKtgvSyIbKvd9Q6aBD7+H+8wNCeAiHEzOBh37p3Lchr4j7uOqvw1LIqIcs9K5Tk8H5ArnwuR70HeRasyGS+GXYNrlRsl4QGxyat6AAwBfTgBYvFK5p/s2SO/QEBwONgWdXiPMutZQdWkpEOU9WuqNzdUE8SUYb0MakCpVGHh/O0bmeKZFfZeej37d395pxC4zxeoKx06M8zvfDLQFuXLy0O/Wm48cXMFs4aXuGrKqFpBujyDXMb8h03zjFuKzECPeQxxdPQRxHsCVXFTG2RP4C/wFBgKcWe0Ceq1Ql91QrM7WvQlGbQhFeGWNt2XdP0ltI91nvk0YpY6bGmq5wx5qXaoncfhkNPCnAA9cUSQpfVGsotmetmcoHK92hY4gYfabXwzuvjuIjdcvmu36bstd+DbGX6xCJunNO/U4z52VHqBnvUqopVOzGRmr0gTV58Me3a1hcsr3ZpUF8hkXCXFnuEhDqE0ucT6MPC27C8uuEiegOg5WkS9RmYc4IfbRAuMC2xcWmTOz8hZR91yBytHjJOQiVdYGSpSvRUMzp8YNa+ck9Pu3y/g27IW3uPgoFnIOvCdj6VN7B34Uh4IuG8Sq2eee9U015rPf0G6+c0zYtqs1wqr3+kXxrYKlvAB0mEFhHGb3mZnqMSjZfr6+pzmqoIlMg6v0ikMYNLg5FJCNbVujztHfAOiGeVWcDwUKdq6MhCenMjlhMXdRw+zxGOks4rtjflZRpXL1Gvpv7LN5EaAKQgJYnAVz9laaH7ktWki/kKLLDe8IuIjhPrPpBv2iDoIULMHYc1kO3uwCGZlcZsLk+Sb0uPJZBB7xhgX4Il5e2bbg7jaULBLyqxZ8UfceAoSQetB9BdiT/Iq9OSTrKLmW1sUhEO70QtwoPX5mwi1ZHOW6x55goHN9Kn7nCIoNMDL/aZS1S3Mia6z8w0C5cIXT6YM3iLEHDySoutl06Sp9a8zu9iGUdEDEfKWVTvRGvxiGwERY5vgZLOK3/KqWduQRoMQ6juLZo8iBirZwJKwIcusQ8xw5Oge7D8P1Uons6pn+jSIiyNnLaJ9hJz0Gf1ELUA/XNALq5MiBAgUVLOn7NTXnNIrM28P44alKayivOEh3xcNogw5OGCafOZdYbSPICI3KgQyvQSziaZixXOobc30jZvcumzTs+/MOglRmEg4DT9u/y45VMHsDD+TG1Xpj80HTxSZWMzJ815a8qbHExg51eQdPnNB3wGhxSlBFy7IDWQDsajQbRYF+WbC9CoLNStS5/kKDfTwzh+0ADqUv2o3xO+CnT/m+3au2flXrK8al0KxbLJN3AfN0N5umKkFNdUQyTJ9qmkAcB28G0Pp+n3jWRPTUTVOC25JnCKoYUcMQyQSv3M7G9UiAW+fyX71VwNOrMLv99dXTr05zCVMw5ycMNFCM2HV2E4aFYc+JQSb2Wakx+llb85JPHmUCj1MKdfmwg9H9B8Ahimnod+gSv0AzCmXi1ImTkQxpLzoiqu6y1nYQG1F3acB9V+UTZv6D2SYQ03MVE2b/gvitXY+U+/Zuzu/0SAqBs5EM4eClMFgmxll0wnzqKh8zc6gI0mx2Nsj++imCeaniuvFV6BRN7LyMy+gvCzbd0mNvPAeRTURH6t+WRm1d07Wdoes63j3/B+9UY2C1TMGiAXMOEFk4lloP4twOHpDGd4+VzHL+7dEDBt1T02iOKgfSXzYKMBJjxFrxh+2loI2ACk4JrK4JP/eOVdbi8RQoZ59ANdguxiEjYERImIBAqvE425KDAXcoi30sQ4eZ14CXRN3EF9JxSaXr+qRPncByF1uPKu9x8QUJla3gKA5wjNY6cS2l7wvu9pXwJ/J5MOAbB0jYX47CHx8grNMPiEDU7zlPtmTdQiYufD2vGw3N4vFtCHId7QcCwqqRo4YlmMADzBcDD181DBA0rZg0iuyO6WaQbZ+dkkl754/b/8+Jz4Hiro4YHpbHa4IF5kfvGWeflBuNHtnvSDoPvMt2e49QQKVOxxJZZLKGDMz8xcnEivCSTgSADuLP7gbAyloRrQ2hOQ/XSIjuRACyyB1qNAd35RjoFh6cQEljTItF9loi8k2oUH4AQhrISPnAIPANJCX2C8RlUcftcEEd2EIGYLToFdeMd17JC0Ham0RyMiFApTVw2+scSL0R47g9xsCeBCaGnR7eUjmREGM4IPkepWVQDzIAF4E6gVCBZAEZQ3DgYOmdNKJH/PLX902X2h1fLnRMfPOkCEXCGIoFm5WvSQVDkhtAjd/+R+IrIRrovnVtQK/wKhmSpxTg5v5ctflqlu3BfDJIkgEGFxySfsBtT9VVdX3uyJ9YzcuirrtaDaXL+bC46INGlrGSmv8Nc8cZbsgHY+OzfnOz9MdkA+fx2Vc9AEBibSpCJieZjOrAvZkSOrY7FGTg+PEsPYduZm8J1oJKaIUBxSixLzHXB2SbcrlXb0qK6v+pWr8/7LcHGHOiWgMARVlWRNV041fmnex5Mz7KF8kVruvlkQOvFCByuK+giMZMLFDWHTG7FT2D56VQyebzZ4OCc46wxEUtNgUJxzC6wC9WKDDtSgpXrWxSQ7Z5RdjMdlGJcGHln84gZEYGK9Yez2fy+Fm+P3yDcuXRksfKfO1oWDFzrhCwdz5S2712ILBZfzAfQ8LAvEz2ETG2/R0ng7mNBe1X9yih3iflbWxt2dsGh4sevmamcibmAJfXpKk+V/o5SwB0PCkK5d54c9QVqa7TUJHNiUDFmKSGydADFgx9kuI0H7gm0OymrCmxghEmNs0hyqdjzrYY8ZGjQ9Njxp/OpAZGLFyVEoN6JDIzqD2S4sy7d1JYi8PmV+PyYNoHDifj7g4KruFSZngZ31ddrF5tDalpaGteI4Aoc2GYES59QiTlrQvUyn/qSNEI1w+ZdZsJvP9F7xV2HpRI/hs20kRg8W5PLXmubP1SPEe6SA79gJvI26CGpU/8SPwi2LalWK7EtvTt0Vzl5XkE6OD9aeaSx4XDg8tbrivXcFtZdsX8EppNsvrXg/95U4z6iTv4y8OJUbjfCZEVQn8c/x/0oAhXoD/mKll6dt/lsFVhO67T0SeN3/unOwSWZify3//Rdn+2lcyBIkSzBTTVoUDYbY1vXkkT4EpaU8IfobZ2v3mZdUAT9XLrlVcyZxp8JmEfunlWdNVIgsBxVrkKpYNg6tpBwiUwwvwqvQjxDh535ppUzyLzaPK3dic/F5baihoRC5oQ53skg6ANMHzsu0xQ6y0I9DIHKHUR7UUJrVozOoiOfAZ/UQtQD+ovpTo+NCwk3y7MLzh9209+78LsnzocerAkmLvqL782MT42ZmxO2Ii6Z2EatGPfPJ9O+NmXyw1R9ukXCdsAGEQcdoTAqKIZpjwrGlXA1dXLWpw7G2n0BQMQyihgJFiCBEix6O11el1AhiZDIIGnb9kxjNO+BmLd5H06R2Mjj2sRSfLWeZguYmkjFs/lU8eZ+RZoZgefP8PhpF35K+lURAguG1n917+RVkA8hjihlbzhnVXUYa/8U9wwUygMkKVkdr3RJBmmY/AIqoec+2mnDmwInFVLoQ4FcFpUE8A3NAcLE7dGe2/xovI2ps3L6cLp/rYrosNh6PemqcOse3eXC+pGrn4Tvq4ivl5fvqUER2hUi4qGuxOtl43+FeVNjrzf35TtttR+zpQeVNbj/Vtz2gPcogewcaoBjIdjLRoNykHiUss5ucDJKypvjTqkOFEmxlYUiyGvhSLjv6/Phyur3d1tDs6DhhETrYGzIoKt2sipuP+Sk4L7GmXScZ0BmYJwimkL9UuVufWXnt9XfS1wnTpjw8Qikp1mPiBHW1y4NmX5W+ECRc6AMs2raGKU37/RAL88x/EbakYTHBetlsKJodS/f2yzbs/PiGui+py+QUq0L/wDcCU50K8D6+K3CR090N/aBqMvLa9CZFWU+rk8gCEWilBix6XW3hcDz9kautNVi2mNxX/wz8LsbikumPE6ONbiJeE+TgdE6kqXzJyP4520e/U3dAvEpuRSg69M8/Ju3eZ+Nhq9Hh32TMxdlPzK+7Ll/LFcj9PqMAQ6bEm0uUCYHizTJF0c4heBle/NcimjIjqv85YH4LJbI6QIi5M8ctnTL1uP9gmkJhWOisXmQM5kx40z2nb/csmGTiZ3zRDemhpJwqjez+bf7RT7/nTAFVGUQJeB+APkF2rjA827dK659wpuZE6d8bBYeGaSvrYu7zsKYHTzMbE6tpU1tYBIxUVjLVHpQWJg5Pwc+xgJrc83O6UC0dZUNCswJ9bFCYRiIlRwS5AJIiDnSykZgAKOcU+Ac4geBEE6SlTIWIRPfYJLdrMp82t1eV80GILCnzB9Nr33BYH6a7Zu3FD1kq2h7hzwZJkFkHAO3CSnxW+62WXbVSEBb7gJCzH9UVzPCaHCNPgEY2MyjbNRdNNT8k2X32wSkC/DbxxjTdrZKxAQ4kctcjy2DH5IlddTdkBhZOg1431QzJmawYvb7Z2FSRWnCVirasjFTjUtZDygPwE+Qp8XW1RX35PdoS9lcXsynK+Spe8XBneKq0oC5XqU11BxrFbtzfnNXuv702TdDkjb2PqSlWyapka5eiKeJLMDoJezRtW/SrYlm3ek9ZOEGjUfqEZUfohEU/xqc4MmFKPeVIfVVViqAZB6iPEJXmqyendypn/RuvlpVYkVJaWtDSCl1B5p3SrbStcKRxn7m9tyfXrudZmcwIUgB5cEfd7U+cTsksyG11sB8EAjoxcWU8gEJTlpxmOs1mL9XXSd/bmb1w0zzziKD0ejb9B59qyLuQHgqrfe08edPp0opTDFAma0HfFrtTX2pgcnMCrFhbBBUCSYjOxkVyJ+2OiK/EEMvPLXlYJgWeiuba2GesW0lED26KFqYkHgYCbmWaqSpSni4pLp0u19iaCwHv6VPpkKClkhqflEgA0Ve9YAAoeg5ilyoXW4Z/YMh1AZ590B3Shz3zhAeMuk7uX1xbMDkjUFoIVuQRvrUqtBK/4J5fN4/rWDH+5qVSprJVOyevhCVA/A7qWMfuooafWAz9ExglZXLVPDhFJQdqGhenMnvuiBbXFG9Sj5EEd1V6GmLAotqDF2rpIKB+mAlLXFXGDjzitKuXzuxLzm9wT4lto/G8Py/bDpdIvtMOWyIF49STu81ZQFa1eVVV3VO7gi6/NvbMglkEHp/zeqa1zuXCDst3qysZCslCbdHbB863vmqceXU9n5aryElnAGlUB/eEL5kBIkMBVRZB75mQksPGIdFLO67vfu1YaFta/eDZF8/Kco11yFSES5k3txcRhVkfzHHr2krELvI+sGZpgTVkDhqUCtXWPaXkEAWjbpB+IoIUj4v9AXH5rzcmNcTPzJC9C4azvTcSk3mHvM6psYdH/U9XLl1iUrMBZTxlujCfMtDSwIAZ0C9Ec64qTYYCzzS8Q1vF+4mj6UHqDRZPA5TaVd2rL/CM55TP6yVtAJUnwH9YEBoPmJlJgU9sRgVIpleOZXYWL5NBoYmHSvPy2bDOB9u7Uf4ts5FelVg0qP1AhO8+vmX9FRc0CJz7OL2g8ZBDCLhOuaiY0xKQdKtGzlF+ZSBOEIKNIPaX61AZiYJp0YTVmWTkLM1itWM2SGKOSkwbBXyAoWEZlwqD+Pof1VFBc5jfuGfMqwFOnS/Gv6nXZ/RCp8nB+s/j+Qyf86F2UF3olpnz74Cmzq9UEGyvK9qkxLgxTpubhoNjp21dSWGpiGTZqEGSFv5SJVcm9aSgJvMiAAtA4GOjpCITcuwqQTrO9uLW6lq0pku9bGzHhnrIg5goKuSrbi3etLNx3S/bO2u+XzU8L8ZZq8s3omqkPm0sj5shheTciVijME/rhW9OmIifQ/LQakWTatOwMVa1pnqGygngptAXesnamdLe21PtfanuQNsA6oUDyeh6mivgmq4lAv1YRDzMfAI05Nir7zEYgHI7d1fNJ5QjZMsolLK6yKfFROykWIzk+H9QkT3+kAP12R6/Wl5Xb3CU8QOsK8mQ0Jz3p1WNjMwLrFc0pTrp7wSdtwKsv6TkIzUMdJqIL1ET8BVMjKclr0KdQ+CE55zy3X/0ubVR5HA68lXGezivx9yOJl0T6L+mx/SDDEcGEEEivuMp/Tbmq52u65p7XTcEKOba+4m+qljFcHQDYtdvt0Sl6wVCWbDJcQUUKjsMj53+A6B0ILI3JsJBS4tbV1bFH/fzucW1lzg+K2Y7F2C1g4bn3Mv6Imsj19dzspgxLgNgXt7/9Z+bo8U038TnAyLaokRrt8RuqCvhxgf/V/T4ZNMf3yTYGJcTImzYEig5W4ZHakFLqxp8wexNyGm6Yx2vOpp2QDRryZ54so97rZyK9RMUgtHl3p0x6t8L2HyfNb/md3CR/0J3N5ipqfXIeim14mGqknd2i4/OZLDCXwSJ7BE/J2vuhOcmlQWxuqwL++R6pfPDbvymnkYfoq/Kde2HFDjqNjkryQGOPaIb6TEHO7S0k9Q2AvrAG7oSrMDAQQoIcrk7JoeIurYRCagQSDEUiJAX1KFsAp7BAeHoQY8fD8+bR446CPnnS1DZ6vEShYYurcT5c2VKw0ZVb5mivIHgIiL9rt0BeiLSuiUmzp9aOYcgvYBdOgIAvoFXytSAQNv/9xVUTU0XCIst7YxLthnBOyP6yAwttR8s8TfVuVBIoHsK5DBeGCCBgz0qX/PGFvispounQ7r2e1cWsPYsHIUHLV0U+g6SIsNZSS2uUXwkm7a2sDEf8ayIdUTRTOrP2ush+tDHKsEKgvDAUkuZCa5NLUKPCeqJavFlCiaBnCDuNkWYlBujBTfkiBXhme9I8Wi7I1vYR1UcWVk0RFgDtkzMkixXkxchBIGPc2jeFF8wXKwTODuk2Y59M4gfp1omMm4ZKCUzadI8/v2U+v5PbNrtqDu+VUA0mltN2lbqS4/PWiObVp66rN0FV5eurOZCNRmTEkevvM6dOyZ1RGnQKv+OuQHwOn2abrrNJfPU/fld+/3yHwFPUGT0C4f+gFywDcHmsgxCtMhl/vb5v/dvpr/6KcDv9K+f49ctpc7fbR2oQ7wQtL/e/vtBNlSEowVR0ZxSOVQF6qgzVmCzYwmUanXIYksaUUEIgWEqlIJDTjBSds6lumCdw827tlIkxU5SUpbot55OXgVdvncnGEimph4i9dVke29agq8DZSEM2R19Yr7WgrHDirU1a1Qoj5u+pA8JFEA1S4ncyKgdGpQYgcG1/lxxK3pJCybArhEeEbwCCt7sIPS1sG9+XisNdQYo8QLTj4uJ3/qeBp/9xg+zWVGfGpn0FIgbYnoM122ZXN9sBl8vcvnVnwlE1MAnMsyptYDZ0GbrmZpMmFKbhCcIiDzwg28mpRf+Rw2HtsOQLr8eO63CbBVU3bvjb6tMz85yWS6aDe9tsueDQ2nAdJT282VKy9BSAIZgWjEbWzb9ZNb8ZMgeE0QRwgE2tF+QuCtbu54WkK6url3gBuoPAKsQ0y309Tn1FAkCdneZwqxnuk0ONpaaQAjAq8hVhmUA1o5qKRW7hNJTV8VY5rapC2Me+A21SF3AKBMOijI8SvkHlQkwRZAQCXQRxLU1Ea9cqBmVVtCmXM6MGuIlH3QGqIhmGhbYzwp98oyVUE9dCNC/3t0ib7Wevmn3lTnqz6NnP6KdrAVG+irSe0cQnthF2xA1/QCgUyo1PwUXWOiBBSNMhkQNDchQKYKe75Je7BC5EQz+uVuw0OqbO/Nmfy6ImEGxz6JDZTbSA4EvO7/Z5wy4RnlCI2cCitM+NyGmUMBUZt+4IzITWxjW36LK0dGggZ2UZVuQFlLOcSWhARI/cwCAEsTqRC+j8VfNe0hlzKNb67Ei4xWH2WjnppyN9jsTUUXsAeOjECZ+/M+YpK3ZiJMQPgsHC/WJlu0qX/SuzKHBitdAhFhNnQS1tSkACQXyWoOD3svkl9+lTZI8V6dcGe3dFwkX+dVEuvuFJ/k49d5W/de3hqVtrqBaq9kF2EE+2PjXEx4jJp0JP3vwvDebBLlPZHGY3WOlam9xsVmXuLjGr1w0Tnu1sqw3tGMuc2PHFHUCMXhsjcqR3+9F/OOcKRdi5UlVxWbnZqyw9NmpqUEmYcNtPBQWDL420dcKwon8kyqBqULxh7DF53RbxLC+fPzt6qgLXj4nBmxgB5VPnrzxjh3AI9ZmyRjOdghJDbUL04XVGyPQ0zrl3oqf369nVGCX4206/zuXwELE1ELqROO8uFjtRT4P24Sn6TBkShDOL9PLXNKsQkziuux/ifF5pENCih0jfQNPSABARQ8Iwsaa87GAi5+ef/W/Pff53VJjLyz0LzmKpOLB7e3JhXUMlEMuv354mVmg/Vl9Krv4g2R9B628mzBeUbyXYU18foZ+gV1+JHt8t5sGGaW/e8LXFcoohSDF0oZ4wNvDPynUsvt+XJZQBLemwhW6+zyFeOSKNgCGzHQsA6Op04onoOr6STpV+ZTQCydrp/+8nzFGXpHEqPPlYN1Wv+xn5Y9vqXj8GzraBc6QJ/wXdrajDHEDwhszn9Waz0zlEpagnJjclMB4I1NYmElrzJNxZ7y8IMsGBI/mRkYmJrGZaSbUxwgL0dbFKCbM+PvegCXaL7AbBODPTQITKJkE0kbJsoKmqQJZ8Io11WdAfQA+IOza+9O4suMfOr6Dbj3+xzNfSxiERHjeL47icd02lCLtcvSJHcBrhwLfekm3x4lrE5tnwNkzo8+Tiq+INgKIOHXbGxp5/zvziL3pC3uwf/7FcxThbe4eNPpi+fpkdyPoJtolw5C5eFEcfQrRw0o7RTDoN4+U3ZELqO7Jn2hJmf6ODTdFOPNciXR9lxXHCJiZyLPiHii8vlceoQxM+0g3HthxmNXaRKXdqOxJPZ3Vmc10gEk4ubbx2gd8LwkXz33uv8lCjOXacXT84m1QwfwfbQUoX3bjpm5llOzcZx9PdTntsesXBmHQEZTkgdBkqDMhqv+KPl8wvgb/UaHWVyXJMiB/EGBc5GwPGPKPoDc8kmZGy7BBuW1WxKESLe8kH3mJlzAU5lGEovMQ8orKPqLGkPZ5PUJvrhUnTO++0SZtOA9ROlnoYaOaaw/UUSOUOpWtrqZq2SJh3Mp7B/u9+YxNujOsSur/3qvmlXkeNY1wffdRZd4tvxC3kFxaOg2BjuonPlDt4xM851iTbxF3Ir2FwgORSSNZW7mxv0RS4dJ75b2uCMmyC49j4/V9ihWxRnCUN4ctvbRVXyedtj65EY8VupsiMjrILVzW2+sbfFRtfVSFLwltv5OgBMzxoGjsd6CzgJmkuXpIr8OsAPwcOJ21x/AdOidIHZ0PAKbj03DnZhofxaeE0a9qAFPCIVaGM9aHsiAI8er+cSWEUwUa4UND6etsjTYlhDIcpKCw8eCw5PpS22v/mTanViwhDoHBuZUE5GpiySAvj2+IEgniKDVWT5uSDzJ/cND+fFiZHHCAADdvyLCz3YDq0OF95RPkJ/yMQPNqwbVSWGX/0PMDid+9ymngOfIaG0GQwrqCgtHTbDp2hxPtGJBMGQlpjMdlgwhIki5zq4gRs+w71yLuyUgTbR3v9/bel86xvUVGRuj6Ut4VpYWbESn8v6m54tCYTriv2siQqsYDX+niWdZZbKs3vtJm9xU5ckLm/Z8+akwHp5VJeBRHlVPHBlvjSb79lTnexJzxDt8JgEL+vMel8wrRpmwwOycQSig1CqZwZzJpLKjusShyMm2nERI6Y8KKhTiDXQpm0DJHa8oPwO1j5JVgF2wx36bp5GkWRiBaMQZv3qPSxvtPChMPSCAu6CJMKRcsl05jTeBOovk5YiF3I4n7b++iYJi3RaTPQtKapnPMZ3WMLAFI+hH7EhOi4EAnYVg1euCBsHO2qlQNBKvzl0IS2/WtbA+XN3q60KNnhW9sV5536fnKmkkqVQey+slvKYELoRvQevGejbwDE6K4apuZyKMzURrxqotoisOM3Xp1nCvTsm3IVXV/RHjU9u2UHtVhbI1jJTrhMJGBjG3xBhrC7d+Qkic036OCV6kvD0irwnj3t3bh5nBxm1d5v3DSnWKY2Yb6hV/2IPzCsWokfccr7h+yHNwNtI2KsoVADSNCDWbQrebrKSiUoqdg9fKInb/Z1P+BRMTWUryllsUZdeCsdLCpMLmfOvscdXNHytWffjh7uMMfFRHqDQS9fHtjDtr9tkvS4qGuE7a3RRHorM0dyh9o+5GmFXz9NhE5X1WKeYVWJoOk5XuKtLOEF/fF4UU1R8XGxdvlbff2D5uWUqVSQ/m5e5kRZtYNjAN9iwaEZjJVufOIf+JxnnJ+TE3/rKdNwrN4NHoP/ifYVsiCmzjFg/+bNmhPNyf6bbGKkXnzJ1A6olze2UcraAzAQCh/KZPbsNTfO8lLG55ZEA/tFtPbYD8sUfHhGLgD5GNc183DECVB2U9B/yLyyKIdadqqkyM4nETCxQ8/BshGBtXPd8vH4/U+XJKakq+Ei/PaBUcfH4BWRFYlnaCSON6zR7ZOaZ4t+1e/Rnz7wh+bycH/9ZSZhqljBXHdu3UZLZ2oeURMCmvQXHvydA6Zd+R32Pn7MIlQBUdzCK62SmpxFe3fEzF9Jo0qWrLTaR9EooQe1V3IQBQECJFILHT/hHbgjAAgLAVVV5S5dz2yIrsICusBhYhKNt7vjVOmWvyToZZIcwZk3hpEP++EVyjC7NKuQQ3UFko5kMSR+KRNMrBUjRIsCubiTqgojortsc/Ee43mZ2qqf+rHj4fIePytke/9ev+b3r5qvNMrJaGGgM6ExG4g9SFWJOjM3K4eqd0VdAFUW0tLzzr+2yepGdBLkWV/27NsvoAkRmsxxE4t6cZMIyY+Mmw760Jg/mjR/+CCYQqMDydTSRKLnaCCrkxgidRETI3dLZOA//w9zf/cfrsvoElRfX92+uT61adVrlISccNDN2AIEim+KCXh5Q+1MPr/7ZFntsCAnOBhYSUUdiMk5oBZgnIWq/C1tLhq6KmxM4hg15XNU/FB0W1+VYxpGnTItj2NuBqgUwgywrCrGz/IzLgqav191GDFpKs1Y7EcSEULEklOMukAM6/Ghfzkl279dIzoK0yuUzcbP30ptJFNx0X6VZSXxqZWQFVDQXh7XjjlSat8Cfkq6efXL/Vy/tlaoMXBP/60oWY8MvU1O6B2xsevOiEZ5BX4P7Q/FxzP4VM9dzLYo14PwWK3Lis25C1KV7q1l8wRmFgnVdRKsFIEbXs84IBgFwFpD1G5C3iDQW8BtdOUYUSj9Y5IyqnETQdX9S4bV2yA4h9buUD03sSRPpLlAe9ASRljrOsppI9KkMBTEJxKw7H5Iy06wHwgU7O4qsBg9s97VPcC3alDGPNghkBgAD9HFbJ/rl238AZqX+zgfeE54QH1Y4Uq211EG8HCVcDi+CjFRCGYI7WqQinYQ349Rp0gt/gdUVVnHBMWZAtkeHGFoyKeZl57mFin9lssndOpMsMhXRB8Vixgwxc/rzdgv5WWADvh7tidpVQJ1F/ShWwkZkQvHKo59QRhgYXiJmRh+fQ4DUwiU4grz8nlZT4YPtMlphCCA1xZ48SONzPtSvxEqcItr87k2kR2+ucgfyARVLN3Zso6yxZlZ4uIQrc373G06XK8QzIrBG9+KBNI4yXALhOsE3+pkK9Osy0MTxeA/iAjJjeuO18Gt0ulUfkqa1UVDFxVVExxeU8CW8LtLSzJrIgbC8ziX1tcJhhKTi8iU/SJw4NWkUz1iNSOvRxT+eWVd1huA8Sxrlft94iVrp7iZYxotEn+C1QmgaPHQje2u4/pQjyc/NLyi5dVLD7WEpwd9LmfcCpbg/dWciSogOgFL2G6CSwESWyvSEaWIMREFtUb0ApccpNG0XxjR4rVHx+WZhw9KArzVb+zeTJqDUWesmzk8P8g70wBYuJw6bx7WN5OLpBwrIsOLQ9IefjMwKNsEBejNbs5UpUjvkNRhdS8zWFj8kKtY+Bgil7itxNG3RMQuXnAmOo72a+vmnUWKLCNpJEc+Acbj/nJ50CSWRUBoAciygWx9Rj9dC9SBinRonduQSF/SWuICkkAL889/L9Pe6tidreV0Wbd6z6jBJUlBVCvhPBtNqxIrJSswbhYpwQYwKkbKVkSoagmbllpJqDDm23+w+OW/k5CIIMippbFteWtlYqv6qtwNE+krAgoFZQeJgsUJs5OZCm1utewJxXXgq3JWhmEF4imhOzCcKkiikxkKIO8D+tUTprNaIjsQi26TzoAqrpY9wcp/kyzKx3qprPzN4x/xi2od+XzG6mQIAkokxq+vRYMpt1aaKqosTy+s+ayJLC93ZbJR+BidDhUW+7FkGEcoUkwJYA/aELp9O0xhRwJnBLeEXBKNsoP+iFwqrVAFW5BBkQzMmRWBAAaYA4JUQZTdTwPxPir9JsyKeXfMky6Wf4ZHpJv9e1v96ibm45NtLZt3bjrjDHw/3RrXt1/F2dnxsvhFm+YTPotz4AS0ll0c+V9GTJSJdPt65DLyoclg67/jWPfa2nCY4r3CkNt3JkCJRUGehovTYphdkEomBoVvghFfaTljsYL+LQxTbpLZUGrG5QpLnGEPTWfNV7tkAAorA42OmtICx3FSU+ac/4n/0A5i4XBLAuZbZ0zvIZE5V11tBdO18Q9ombkV2KGlyfypcjMsxX9qAWSM60ChUwcyNyNNiilTVfoR/gN6XWOVsqAig05faZabQwIgHfu9ZIpSVdGMocIstE7xbifmB7wM18noBT8XeLI0kZfZ1HKSVOD8OHeL16etAQxQHbbzyhVz+rTs7D0g1gjBJ/YDlZZefSfe+7BATxcSNDKa2RQG9+7fE+HiHON64imgErBKdtWiynUJvrh2WIgwH1I5oWIEygJ0WdtBNhw+HPI+wPU6xjXEt+o2l/NeqBS59d8O+vG+9J98TlbkhOg1ENKG2wwrNNzfao4fNi4SvXH6yygx7jIDAr1z61vtsTRWISxVh41IRiKxcVmYZGE+jya0bhiqHwyHC6CxaVO+LvNkhifk1gvzuSef9iQ20wX37ZM7UFCJa3B3jHnoRDI5l/K7kEeKcvQG7jvkHR5/pF32mJU8fG6hxZoj9CyA4vIVR0m7XcHM+LSqGWAN3GuHBeB2BjfgNOssyZw0l9tuR3tbkoPjt6/LjVG7L7+Vp8is9Z0A4tzBqvFb/aaxTobQrZ/IKAH4nBOgjU0ZY7O/89XwOZdPDMshBnZwHpvUYUMc2g6QMyzKKD8+4Q94GbyeV9VSMjnvceWvvio6q33xSiJOapEnlZG7hwpd0TJPziVd6abY2r79nt2dbKML/bwuWSJ8GCpjK8395Quhzg68zIr4RTazxeXZ8cm6PsnzhJ4fNKfrd77OLQUdP19r/uKmHPqFJoFlNgqLVXq6xRSqTmBJE5wTpu9TQRT6d3dMGRVLZdMwfELCCR+L6wKhFlnFxRZBuZQzT5SaF1UKmQhzrMtcGDb7YnIaWY1MrrGjBOmMtI/Vp7z/ydMelNPgOYTUtH39CF70zF+fY9uTjGM06a+SakG+VY0U20nxkhBlDwjasrwyREoAioAQr3Ua8VhAtFYZwQCoCY1yypnwBtzroygAAEAASURBVIe847KdiJsQ3ek03S5ROaAZO3yzzYBUBobitFQ8A9p3M+BCRxT68dWGzy81VmMdiOc08B53LgvbZZK5VMLx92jMCdYboCaHamhujObde0yuSCyZuv0VnqO9lTQB9uCls//d/7VFni0E1Ibs0EQf02y2TM5jTsCxaF5i2V7xSSBeEKXMd9l2QPjwBp1CnMPD6ZTL194k56EXl5ZoCjvMe9994jDb9sE9jtRH7MsVewu25la44SD6EnvDgrmUlVI136s2D7m0lRXwxLp7faEwqthsr6W4ycyAGLDauikZjIPPdMBubXgperrXg9HltbODudkFF7xK9Gs4efVcht4/eR970vtf2G3KFSmRT056JNL/VJccos3Q5hZQCfak+eynUjuptUUiKAxLQaurBHQ8MdS7OjGZbJHFTfmklCVkaEDMnWBW2MP63pgRKmbBdTQaVFbt81aVXXle5KhhbW1hLEFfs53blscyO89GLmAkkDRvAfFivAvdishA+ypMPxm2qjzBqZRutX0EcI54hSdvqgnaWJWAwoxqg8ZC4TJbAIMenwSm44ypHuV9zw+LlYUY+CLdl7vNrMkuKIuKXnwTxG3h2XNXdDttmCHJAADpixAS0YfLqryJBuPbLVOdWTBHtciQrUZwadUppSXXfEb30ALA0A+hQ3sRgJA4odVpQDe/N7F0SZRLaitdVyOZe/wIFdUVMgP1xgVhlNu3BfgqwpdDEG7TLt2gD1/ppyaN7OAlUS1T+vrIAdmvZtyZmIQcO3E0S/UIt0ctTc/ewlMH/TfufLUqzaGFvqXZW8vV+VtySSwmHHD9muNkh0Kh1ZWREVVW2KkddMuJMCaSXKzqBaOKhiEfBOrYH5oejKudMVfiYgjedphLjn6IuFpvIDXlUUCiOnew/ofO/OCubYfqEnPiuPPz1uxmRRUDxp5xBotpuvl5wiA33hTT0L56haKLObdjIiPF7lDFzrKySDUGoHuP3MVX4CVwtrrmgF0alLCo1fMokD17itVWhRt9wdDSe3/kgFoEWgVUbvApIWCyirKpKTaPPSS461afdN+ev78LezDznXNsL4xuozdwVEP60rAWOMw2PnZStZQcgHs/koH1ovf/YM/3az8+oZaduRUNo6OiX6D9B0xQ12yRpAUN4UzPuHVRUfQk4UWfnSfKaPvk5PD5xYZy0aWmtIpeeOddeTg58+dnHHddtZocv0undioBcveD+03J0fYo6TR8wisj/+miE7dS/Xf3ik/YAIMc1VNw2/2bJpeWttwYWmR+VGWbqEtveXh5eYtIaIVaXiQCgIVEQzAwbc70dchbIMFl+O+DMisHdgi2mdftduBroxNYx35hgef7hG8rW8dlHA3AdOWSnDgybPbstQi1dHpwcy7uXRelMTmYee5VSSCyotDPiXL2D1Gt7nH250utfdN9TLvFDROTprNdMrJsJHtzC0vnpsIVRBmxfN5jIw28GYG3rXieiRwwRt7cZLJDUs6aAllhDXdGt8AP3OHNN+UQkOPKVVkPBpqcEnYqkE0h+glYLwpIwxY0CEc/bdKkb/f/yh8F3/d8585KQQPQwKwAJ5q4olp2wUBoqvKEiMbt19dDgXzTIXHjXYVFxb6F8b54XCOxNXuYZ7A6PyLYC01NMMx2PSgQeEdfEhKDvG5B4V8ukk4BDrlzufB9Bzy9qh9RhRcuZEZgeNMYczNFJzstfBBqWcfp8cbXy3VZmVyFOxSgaA7MgHEolr/E6IiTQ/jg0zM255BxAHjdlrkLYzmKRNP+i1fkrH/zsOkIbRbvEf5zRYsK/LJyEgS68lBYLORw8PCQjPAC5qDmmKkoE14FnUPgNvjPJZsSQWDimIWwoFKEk/YoVtElL4hdkD1EWnNhPbmuy7LjKfD4vO7EVv0ReW0SG8+dSe7tFa3oz8U3VrPwtEVyOHtLTEYRhcOaDS4vcrK7y+4Is6+tTg2LfLz1Rj5c6Oo5KOLahGtSWxu876CchqbNrTVWr9rBDdQNw4HfU1F5KCwzAXBCnlIjX1UksNI6kDQtDWIHFmjROywlTAUR/QpWOmd0K0r8h0HkLdPsEehpu4JvZwWmFrXQpdvGlzQdqqxrqdNYaY4GTY1CSGbxAFUt/oNPCNhbvc2PlTFKoHhq6rRdSQpcX/dvIPUCrW3z+nWJp3x8u2/McRrB6xSisP4+mAanl3yG+0/K62F5eXkF+eKZdHVLg0HkSdO2zN+z3hefnJ5aGL70Doc6/36B2dMti3lZ3iXqMD6WXBaW/u53BU5V1IoUhPOjbz+33lKfssxQxKtnMnUVwtLcmRbW6LP8bWqUdrPgG06AW4ljQdN+48F5ZtwEnkMossmuqIAiiCy78jIzrQCdH30eM7/sJFQwqEyn2Hw/VCuwm9ekByFuIx2kYSr63JOnvIZbDiwtDr63RFl727N8AqcVRAIcee+97X2++FK/6MOWzoLnXxEL8W6fXMR8AFqP1EeIlucSLue7oNFRs7c3l9T4HF3Py4AFhXgDoungffUGwqvSCi6V+fW1nHczAXEW66d977r5hYDj6nB5/raJqD27fdMUHhQm9OqDymNOCEVuDjvSdrZTGHEmbgfraDFrfH2c4ogNkCAtMzO+vL735FRyYYM855KIyDbvBQ/gsUOptIQVYFfaExoZzHSUJNuO60uUegvXZlIKGLdS5tIlMVg0BTS1ah4pgb2lVacnc3Q0vKfhSFObNq8tmH1qZ8bWpWxapaqliWXj0mIbfu1Nkk/HmX4ZkrtxLQsZ2VqUOP+sDUbzyjCghPXNRs60i4qVtqWJeIpwCVctSqSAEANEgZISj7mugOWM2/y9OYnj22agK8gc0fkdImhcovjcVGakCXmQdWLTomg/o/8HWgDURpjAsueLL7KwaXLXLpGKXIDxVkkMtgrhgdZcemXrvIJOjBHi/kEsgu5WFpTg+tCm2atSgE7jTN/xg559Oyby0mVbvK+mwZtaT7pmxaD4mjeY/evLbdcUC/P7alntkHGwZvk2KhkgPozwOMxay/Z/UATXlZUBEDXLcmJMhz4m1NagchkS231IAgDBsmB4Jm61NN4coQEshtoQJ5ItF+8QVpnvgng20ubR7WH9+yP+KLMbIrq8sm1Gf8TnDXlNJl9zf6Nc6Epc+/5Ua48YHrLREltxisRYzZMtZm3WlYwmEzbt0uiCdbdwFomRrK6uDonAvHMmEwh5unvl7SpRteVl/kN72fZvbgbiS+UBM6PhEhpEsQBHPi2EFbV8woKopL67PKZJ57cLVl5b9ycEI73wommsNjMgIH1rtALCrR/0k3wOrAd2jBU6JZoxKBS6WOo/w73rscttXaKVLE+jHLcT8UVBRf/qB+aYnzcUBip3jT773fTBngy2ESrd2EhuZW1Y1l9gmjfNlv4ux36YeP82ZRrcImZ+uX0ed0YUK3EHloxXbffjDZjQdBhGiJWDqqIM74gCD3sy/iwmUhQu1WvffFO0rsAv5W3OV/0tYYXKBTOpT21iipcO3XxQZvUK5w+XC1jRIZ3DzBtXMfBQbJmVGDPKUzjEpHgARq2in/RJzhhJSRpd9cXTCfAijsq0+cay+byOsrIreuRvkBUrAjDRnXQJNRWUytG3IxGLdkfL24ySXF4k5a6JnJyUMS4InbC8vDYTt1FakjVIr2BZBahQh/jgH6uRMCLEGYljQOgB+sJ2K7lH7+r3ygEl+l6wxU5T6Obflj/apvf8sThIFuKzEoCFN5YrCFhTiM+3IHq8QFbk9NlBEBeotLS0vDzutpNM6YGVZUAMhCRevONUOUNmQDmYfAWWgs4P1DkrT6PQPVUVLkLgtvtJRveTrSUdPj+bu3DRfO6XJKCy9u7t6MOHQLvx966zOzGS63x8JzTNK+IVYZRAWhDYMBhg0AYC44LQ+BAISGo9lp+TKIO8g+SCIwfQwMDMeMYiXXAY41Tcw3Lm/DYziBzXC3bl/YmOrSuoQtGhZ6ybAUA8c920qsXg2r5ps6+ZIXW5N/fJZM151SxfhYWRHRsqiW8xhO1riYVshr6Lyc0Tkdlbcg1XZVl41UHO7CIUzTH+5bf82IXFpjLFbtil+06QDlW2el6OyYhNPq/CduZbM4dPLftPHJJfPSKO9IwMfWjQ4oDPPNEq26l5c2dZ0GS1Bq04Z3jEYQCrSwHZ0Pik5EZymtWujQHRtHYQ7HitAGx+VyAtgw3U4bFWOThvzt8wtaq0WGeJE6g+b1uVHgHw2VgpDQjDWPAHGhYu2bcvvE/DJVwzO0vpG4hG4vW4/M41YcJ8Jseu+vgy4FNe5izPDRfwmXv3OPiYm8MDVsXDaWS0oughziGUwFgNKToQCc+L87m6WmWUgQEJ0OEdWrW1udn/3TstVXIaTgT3778h3R+ZWtl9IBxpYn11UYbxgTGW0Cw92CznUe7w0qQdZOAFCALgX9ODEA4SqNe6PQwvdPOx5LVrKfHMdmaGgBTwhKD1ccHiNrbNMgZ8Ne7WX2AAyeoZlU+znio351b4a7b1+FKJZNEcUDg8+O1rHY3KqW5PYiNdVicz3CDcUVyIh78or919KLC6sB1m8V05kKOJaJNKdQZoNJrFRjORMDqL+IvNJqWFdndlt8W8yrtRO6fcrllOhABJIIdqU9id1GIzEh++LuflkiZ2ojYQEOhWODr1C9vxfNwJldHYjBlaQyd6Roc67dgLvyNx9JQQXLK0PPWdC2zWMQzE7EQawjZlUWG0KrBxY4xDRcTkaQ77e0NDQW3em8q6mDhIl41PtbXFLTOwe/mSnGVPLC/P59fWi0JqJnzlgdZa/7o099K1dRQIbMhf6HCPsJOPVW94h9YAMyItB7JLdx+NGJa+gXxpc3vVYfWbW+YhnT1o1w/EnpGzTCoQNLNqakrMnMZeWEivoVwyG61YoZ2Yd2Oh5Cur5gsB4WFb5BMojADElFXpqJV1CShCLTkBi7dIllbI0OkyRyiyqv1/Z9o070R8FufMmW0TmXeUZbU12nqHz/7cSwuocfuhEy22oKVH8ZaH5RD6raMjv7wkPVFSmodPUZiWhdKr8aWFnBVY0pAxZqLOlDAXNXCpbmMoEBWUJHTkiCmoq3C3NjsmEjWE16RqZ2M+ffmiOfmVSk7LXb/lPnTAxGLLr4vGZAD4wMEiJ0EaESKuhmjY0WBMlNf75Sa5+fAdce3uEnqOnzPKQui68saQj9RzXrJP8qhRuRCKA2nge+86aXcvtxuwpd5APgcw26C/IpzK9R869/1d0UeK5GB7inSz7fXk4wtboUNdQYvy3K7mitGi6T45L53KZOKoBD4FosEX5nJoVyXXwqWJCj4Wamu1JjK8/h57Htd6PpPxpkRirn1nuLl9ouh4t5zm9YIN7jCYLzuOQOnmp+UPTaffIy3rZa7CgQNFNlCEbpqf+8u/lPc8dUKge43HDGhDD+owlyi+n4joXxh7Yts8hE2x2ncuW9akyga41dZpiisMeS/Q5satP7/Voqi8fF1Wtr16Rfq/dj5x+ESorKMmjyHBRA5PjAzl9/bI9nY8BztdmmZT0mTUl5FtS7zztuq3V435r1ImMziW1AnbmE64SF0Yydmb3Tn/E/8FxVje87tltNalidTewvCt74311Fn5y2MIQIDHVR9ezoqn2qH33Ucwjti1nrVORjdo8eOfR4zOvtWiYkWLdgAnPNBlBwMI/VoTyRx3OnNx2bW62n9VHKTNNbPnZDSrJrKiavafJnNz18011QAf+UQrL+A4VkH4MgYUAk4sLa/+AA/RFN+/V8wJ8m4jLKFQYUVg7eooh6J1rOJS5Fi+WIyBgnADgVGJR3j6xxpryTtjU9qZh/ejf2RPYANdhh6zhEbhaRDr3OBjxJ2fnX/sLm1lBeqHD/4s7/147hYuj9VfbTGJZ1NPya66AOZj1/otOESte1hTs16aLZEYvrAYyJv5IeHH8tlRCuJZjM6t9nc6KwIPDglkiTU7haRBdezueVAENNpa5qqI/vGvv/4r/0BQHtFonytDjQg59Nj+Q4+XeDaG2A4Hk8KzuZxfq2gUTM6s9c1Em+FqRXx4FBgHm+t25szV11dsDBv+IE4GdoHYALLwdQ1qHnf3sG5os6RMQblsWYUrviU6gjB5Z4dIhM1ZZwF6ZIZEMwikldZi2YyKQJhPzKEFvnxseUiCzdBeln5C5bEWgUYZLmRN57KUAoMuXzZHi+a++deicf7h7+7yHDlmaqqcwReTLz3dY7J75LyFhcS1Z9t6wolF0S3hqCefz1Z3iCFmulpFuXv50ijbpV6fuIukWRJtMubREww2hsI5EdCii31jVyarUpfZ/s9/5frKfQnesLeXPVOyJJWL/kd91d/dbYpKzY1xWd8MYg2fGwnz9S7ZliG1Jel0iMVtcTLPvmOWVYx2NYns2aQsGQQCNdaY23fkzNaYCKFtcNbrY42pDoCDGEf5keayYUvWZvVTVF0+SOfS5O1wiLnvYU39pDctHnn7bdz0nq9LANJz+zpA/Nl3zdefEM1ZyBjRTrE+fn/5gnn6lNwNdE62FXrT3oBfeB8F/+IEEsGyyoeEOt6fC8P72uSy5PbmxcmwR3UqPtkLzwvGgRWgXLYOyK6j8F/6O6sbM5u3b8nPtbls20O6VIJKhasykk8k3bbsciq9ujZJNpelvzpnjjXIbBmIl8GJs5CaF8gtrbgB4IqqkIiH7jcNGiYg+eXCRdMnnW8iqzKgurfdNHhktzYkbcWbQ3g3aNR3R2TeInR22fzyIX0GO5lMbUVm6/oIm+HWKuQpUipcxC6XE6Y6+7p83YlHC8Oe7T/5JpukAqaPHJY72+UVwoXme7fNMbW1vCqCgzawsAfrSSKB7Uo4wV1V4bYFH2g00oVREDqS4iqKrI0sVu2t4eaEJ72lRV5uRKCxsepE5ej0uUnLJ9wWEbNe0PCiLKc+mzF7quWVcGbwu8QZg2i7VGprUr/8F08K29FBhdqsQ8P+hkqPxrZFbpk+aqNENbWebPa1f/7SI1+RcMLQ7SQ8gCBAPJE35+b6Ruadd5hHl/333xP+/o0vzkairqKQAIuaWMEDwRRBKEYnIBTXb7xo/kC91vLKNLYMzsdfhl6izOC23BaqjpjVdbOkagf0Q9OhJWwLXZgzp3VBc04rXJZaObArRH15GICWs6MR4MiLC0ZTU83JrPiVKB8bpdmg4FC5GdZmONRiRgEgCiUOIrMos21TXCA3rK8xVOPv75ftsEeutUGQdQpJrgurnFBzTUrsZ/RTtoCqefE9pvKmUzXkmxsGE2Gnbm2s5V9+WRofiwCNjmUBWtZLZwgWVImHA6G1MRExXW6VXRK5yTI9fL+wd2lXjbsq8vLvvPHI02IWM8sbXqqyEMIk/Pz4oe4nit3rIuZ5woQYQZerqF5jA8MrS7fmyroV8HiJyvjE3YKxoAsXvv3vp/erqjlz54cGCjiMN/O0iIsIuyw/qHzDyg0EdywAILGZ0bIL152Q/2Vhuh+iYWMe1h8q9ZDKwScPsDTqJe8NiFlO6/jagV/b729sltwScnAhtyv6QK/ZVhO5NJe59RfNvdH8imB1T1EoGIxHOkXVmEhhpMqVuSo220ssChO5v9enzsnR4ylXIfWnRORiF27NvHFna0tOYxyPGV6MJ+t3f+ombvGG48Y8wT9Y+UdQHIWSsE2fQucv0emP/df72Az0Xx0bMZOsgCwHxI3hO9Usmyv6y4/1BwZu9Ym33nVEdWwyRZyxvkWZfXTUPPd9MZE2RJ3JNLSQZyd65+tfTKEPLV7C1HY/VkLqnh05cUcD0Wg8VCQc6MpLeq0qp4+YSAb/xASLmQcjYiuj0URc+58hfaaXr+krXJXj90rIpvWCYGABbCQsQZksVoKKlGxWledI+sAelQl6ksFbkKVCJNOjjsc35GdZs/QBdWJ17yP+oP4VZEnjY51ZuBICixZQF82Gvg6dEF2PotfQtaukePbqbF2btHB+2+Vneq6mqofqSn8uPPziZnz0utxBbyMbHyRFT+Zl5oBI8ESPgAMyGf/avOx0tMuAhs2YZ/fWTV91WTipd4LdwYIYFQgDls2k/ujbIYyWFo2jbbS/ZdSalg7qFD4OZTD0t80lZbrDPmfpIH4HUzRqW33wJaVNkUr9+7fqj+2He/1kVCrhbQjYCj8gVna9IGAE6tqOMxw65lmaTpXVqkCEQ75McnQCVwhOM4XejC9ofJqnNDW1TaqUjaZFdXFh3A+qZUCnTpmi3fWRg+2yg1FaXnnwVM7Ow02vZAoO77YJ4/7W1kp8/RFY13gZdiFRJhr1hAUg1LaHGBOTEU344KXXvLjkRLsDwme5qdnSgJSGg+A3TrEmBncc5wGEBvqB7tzOHNi3avMCl0Y2zryee/xroqaq9/vGz80ScbcWceIN08GyYHoJSVyAZiCaxXLRmtDgNQmwQUDBxhpHirlwZNPsijoIu33FRAtMellOw5yG/Zkn/p5++N49bqwWqJFWhpYWk2tJ/y99SbaLi+t+7XNUtPIvrbDnyWdqUhdtlBF0FioJ33ppmt8X5u50Pp4Wtw8YyKgGusTvLM7inxrKl5mJm2LpnjxK4mWOnrXAbvG6yReaL0mjCkxnFC2/7SRRIB6HS52vQ58D0azHSHgG3+bgATOlSouJScBpnGeIJiUVkKinXWmJVyB8Y90bLS7o3A3nB44iwMr8PYiQPAORuq611LaEBSxmPX4ynWOq0/Sc2xbOR/U0N5e1ithmtufG35hnDqHtWXGidEkPDv2n2+arrY7fa/EuQzHWIYGZUaP25gxvWn+bS+bmBWd37PF5WmPs4pyVh4vWL9xmc2lwq6WGDJu447GtrhUyNKB2pSC7zUPJYoekWAVsQbgMV5I+4vPS26usdEHv7Wui6MXZt+U02qdFUwRpQIjX/sFF8yuYTIK+DeIeE2RK6KQcBo5ocPx8iFoLOEgdynW8JxrwOuOl6oEw+Az+eUGhW9uy3L83Zmq0VZ9plcUNndfWism2Ncz2Zh2D1elcka50m81u8zIVLNFCtGQpjhsg3yJx5TzdjeJG0qFL/aZ+p1wH42w8lP/oXyhSKJOgFvRV4d/9920QSJcD7R3SJnCA/Vq3O1we9yr8TwwvJgc2U4MioUUtFYHMBnewMRF6iq/mQ6BKlvZiFD1nFlVvAbQQW9vgEYIpTY0N//gpOa+kWIJzXKnH0v3DSyuu6kP1eqhI7qXtmB8Ycu3ft+9JDKnIi9dkv/OKOab2EAHn6fSm/SJagPs92C06zZVKTgw47l9BwI295x26u+XeZIE+syrzWqFwOEuWclmZU32giThOjWMXyZb8a2p56SeQGwLv0CrqgcpasbaLuQNRfE/IWZUY35W3Rh7DqrhwBb1po2Db1LplwHmGdQK0wSl7WFviuMT0FHOt1deWLJdizbRp1u4DZ5JcQJ0eaDEh8MyG+5vWzcy6OVhtgvp65/WectJndG8toPr+h061OAMFX4LHpUDjid1S7da6x/AVBMKxVgNtgYjVStjBoPgnd9wtdjE/F3Z225oQq3Dk6G45jzjj2tq+PRlrIjMbGS/LZQCnYOnWXWW+IjMnlsuFBiFWEY36ND+VlDNfk7MIV+LbzwaJfRKbof4VNDZW6E1bRYqDoUpdfoYQAMAWGXwQ4hVDs6fFsq8uZLj9gRMBtpv2Fkz3rXu7JbANlWyaGfnXIdoHl7NR96oD5uK2cem2woWdkz7qX1oPIv8cLR3d3yQ7+/Z56sjdZ42/YdldXckvLrm+9jXZLu0o/S+eKihw5UGuKkq+M2+729QmbW75Q6GBF+/we2jmUh0mkmoEbWIio63UomFlccHUkelxU21efVm2sZ9AeZaiZY1E6BNfVU76/5Z4Lxl9UO1+9ezW/83eewBJelx3nlmmy3RVtfe22tvxfgYzAw8RJECABChSInWU192tNmRC0sbuxkkRexe7ESudVnt31Gp35UmJFClS9CDcAEMA4zCup6ene6a99767urrc/d7Lb0CAGJCDlS4OEZoXg0Z+9bn8Mp/5v5eZL3e5uh09DydFozV1woPJxPDGt1dKbu9StaG3aE/qne/zD5xJQundrSbcrMwaiTRXLs72DPGY9NRcWXmFo9c4XlmJFAc3B4X1wVewjY00ScQTXnezBZC82+PdAiz9xX8XzPaRDws6soprTU6+g8aUCflpT7U+wOMEKIeHjD/pDP8qQ7zjrh9xAGsp3pHp2Xv3UhWVyWCgfGdJUjO0xWaXqC1w0dq+SqaTEOzTJ1LgajUtknsWdqFh34v4UNW4cs1qTCIXUPWwIq0D++WgvkEUPSbSKvrtbdSCPywiMj2bTPXPp0ekPQrKsrLS8f9t2Dwl97xj/Fl/kD+WS6vB6lvOoo8CWjtaG/iVz8ppeJ6wKBYOtw/gcf3WzHSmar9iCHmlz7FDtGl7h7+9wYxKz/L535xzRndtC9NbincMe6kAIK0nhq5bd5kRVYU5ymbCf28j6WMnDPi2X/8ZFN+fuIGoABAQIXAkB9eXkBl07ZrYe+AFlBMt3CaSYYMr6+vgFQaRuFFOFftcxUXgFcrh8JaE4ekZQKdPpntx5aEDcoiiz9ld5ywS5+aZ2T/96trv/pro29T8nAvvH4wJcZuPlUANUsaJIcgM3tGogJ9QQX7EQhgPWy1jZlZXbaDL5XGV7y1fvC4mgDgi9sKiSSALfM7dtwQSmyefyLzxN8NHnyym7E4lDj1b6z8iGtnv80WLBrOXJ6deEPXR0S7Gbk10suRqw4IC1BiR49CTG84dGbHg6Ys95tlWFqHJZaibvVGTGzDsuQTlkGNQt4+gTE0S2+nofbVyAoXFR507J1YQWl7OKiwxN29Juaoq2FqDtHiiemUqFSwoclamAdinp5ub5dGxWFy8NdCfXcqFTaJ+pCWBmpryM56AJiMJ57hTc0sg6X+4IGdaiyTdXEZh1mTC/P6i+YWAs0EkyPsNrI6qk8vXZeW3nQADSH3yQWEGACJEP/AesAJ0a8WcbBVX56q0lrkv21xeNntUt7kyJj/ozD+hTYD+oGf7QHIxZrnMptq2sVFpYZshcHQoVVu7wcWldcpPTF9Da+ggiLeqdM/eWYadUrvkRaLTF+wZcyhPdp61HIhCh6H6STSvD6+rk2vsSBeQlwqgfyA4QfwptoHmBqiigvnhrkvibm2sZ5LD415svh05YT+s2OZC/zKn/sOXkgyAkRQBwoVrZuFQfv7gKyMc1p+sQVeF7A7IW1uE7uwwGvBmlHSs5I+8XZ/6PKdN4My+VzcPfHzbx/JwqcIsXg0/Qi/cNJ1hpwzWp+nCKcfkdE2bR3eb+9VBgpnt4A+fCaFdBUJpDEJWKdXWerWTNkcX0KDrsUyhXwwc3UdTWPB9+uUkXh/LoCDGMJkkgpDaBZYkm2CTNDv7nKVukbDcYud/wraE0a2ikPmftKHFbjgNuJ03b8YHJ3igP8cvYXjagpj9pW2G8WbIHs2OQEsbAW+SBraxUX4hpmMbm56iURl91Rif8BvPthwt0ZbSMjYp43pZplBRnnzzijefD5ZVam7idsonAp3S6e6/ucbvne1pxhSKO+rWvtXLIY+Cpe2H8yKie4UkVaf+ug6TNrGjmyg61I+t2wsvpPfvlzaxzhJjuffVW9ArT6PB6Ro7bulLiIDyECgRN8fWnagtyomu//ayeUQtVTAm/WizUm25THBVNqqG0E7UB6duXutDcz68z5lzCMyFK27OOiuYWekJWrD7w8BjQOuodh/W15OWMZZtRTEsKRxcN/Vq/HMI99zeQo1mb6rQhGESJTCdRfL3Hv3jWwCNTOe3auO3ah+hqiHYXwJweLzKGyhA0I7KhKgIcgjpeJhcSUDmIE9QKAiX5rRJnk85AY+uLH/jb9d//tdFUcTn5wJiIhUBktCZdTzljXIZr+ntE3bUcWf4U9Zn2jhRbbm8EiYGUXLhWuLII+EhnajE2yblZiFUIfyDOtsvLowo+S/959mf/JellDfW0m2P1wV21VDG5QoW3yzunXr5vFwGfL1kzFseF5qJQa16qanJi5iJ0R88X356b1K7ZdoapZo1O9Xw0QrE9s6ekVSx0MqKi7a7JX4UCsLXgtZzuewMwkzGTXUJrUHJFLHXijZ5nmdjVUzkVUxkh5wCXDLMZYcdo3WR/etHU0P8nJ2VQEizM2ZQLnrHajr94QPxR31bUfjRaHLk6kptp6KNnaWCoxRSe4vymptXXh2V6aAQPQ0DqtmRQzpE+v49hkr0jPPHOgwoBlhGdK9Feg0Nkfz8tS5pro2VZNnIsDSj9d4xD6srI0NSn+9+37y2aR4Qr1xmQ+x/fBN2v/JtYbHdx8OFJbH9++QyrDANrqb4DqNbq8qKXIaBI5UmcTEbpcUUDk87XpByKJfcFfHtgtjgB7sznl0msLDorar0sk7amPOXxdMYZzmwSy6jBZBKBAHqMTLAJSEHHbkahomk+J50Xc80w/wEtZvkgISlot8t9OGTkMyBgWS3mCRvANhhMmqAz5/LVFbGWSfO7x073YGs9JNsq6N4wDaUPOttZF0a5BeJx88SSgO5Klw68mHePCcW+gbVl0/yuEiErSFqDphBsZ348m+cofjsL+QgHR4A5HXhLyxL8bbTL6qH+M0Z5WtQdrKuF41DqrMtrcFpHUSV6+4RHfq+GuHsWQePwnx0Ia1PWA76Xq95eq/wCTR1Y5m1hmPj0ousgwTmRqNvhbNNbHIxiHlXRAuPAYshhjUglCEjIVC4tUoAr+oIceO83k/+JNu1CmeFqvOF8S9elOt4A3JmYR3WBfOFZ4KYIgyriWw8OZ2w5cIPIJZLmgg1M0xn8q6v54GS1WAgota28WlPPinOkmX7/Lrc1mOdprGAyyLN7flAFQsZh4fCsFK44uhR0U74MgiILmWUbV5xrhiGXR2Xqha40kV14WXyAbBxeJn5sxtmr+o2phnnY0RJ+S3PFm2Cq2ObzptlfFWlToW++13xJxnIsHByaSk+OT984Ry3pLKu0PSde3wjAyLmtS0BFyrHzm4Eh+ZEcj56P79n8+rp8eSN/oFT8rHRkg1/AyMmFLmn1lNbGbb+39w8cA3XNy0ug+kjY3Wt8Sv4Y1HW8aQZTxnXrJw6dtQUrpmxASnjInIXFhxqqBATSG/yiyUKQyp5e3cKeoBVChTzJRm2SjiuxRsr5j6SW+otQMyetHmKUJnAY8NKFTzhqAKG1y6bTfLFq4kAXhNLzStl1EhYSBbEjI0Nfl0UQWJ9O74oT7NDVfDIjl3ulkMCRzIbm55UghpCoHFsNBv1Wg4CK//1a6QekVPPFEo94QcIDYXnEOzZrM2Wh0v3MIP5Fz5FsX521TN8Y+H09YJiUTiLU3EmmkZwmo15uMOsrZgOFI/VYRiN+rqyljwOE4NjPdfTa6tyyuvNZGLinENIB5PF4RwrR1+7anborkecAuuHGotwXDz4LiD+eKL3jSVMFAQIm02aBm2T51819x8xJw46gyqXN8wJZnJiQDQWxfcC4+gaiJ0zEKaKdikr6mLwVnrFH4btsscurqTwhYQ15Hr8BAjO5AllugdIoNhTvLrC/E0cMOiFMXOiwXFhcMDEOSkUZwpirggvbcak4Ds9XCH7AOhKklf+zQv3fzYKpsnCL4GS2wsT8Wz2eCaAoPulFu2qoBzK8cT7x3iU9Y+QL2axsp5YLisxfpeMXVkhxdMAcJKHBvrwoz4ZXt+F7TPm5EfI/uL5/msmLXyciKelsyyrgUdqo7WHy+WyqG6t7fEED8tdZVeutWwmrC4ChfLt1EHmlihSpaespoHpiip9eW7hwMOJddLH8bt1/xjfRgMwOwnielgxy+uwNHLcd9UcrJRTOJbwxLKibQ94DxufMMvKhH1pQyTayig8z1Jt2whwZvewaam8LXGkPPWa1xXOjpM+y2OuxJ3IIusAryyb4/p9/0+f+aVmiYtBzFVDSVQxwOVAU3Ok1hRky6nVZXO+33RoGIVrKkvNqZvmu1ofMNtvyCX36G5bQG3gHS5G/SBS03rGSvFXL8nB8WrhtOqwKB8I0YOLbJlD2NciGMoYEjRirvZLtE5VDJdCOAzB4COfKDQxUaaSLRp9Zae3wn8l7FWv4kb8jujIrZvpDbFDGMMgQXT1+TyELDG4BCuZA4LeaGzyLy8Gborlqg6Z8Q0n9s/T0W1se9GsmrmsPvv44U6zVzRmSctOPy6+DVwNDwc3F/212Uf3is4dOC+3y3OVMPidQDR5tiQwrg6KqwkBYVUgpHxHUssg2L6a5Eu6ksRgIhnln5p29lvgk6amRs6LrYq7/Bm3t2VfmDRdHNbsLZIYiYBLGrEaExn66MNSRrmg6Ht6xl+6JWdK4xK9teJXUuKqqizBLtLyg7MSv9t28m6rNpW7P1AU1dpQX7z04iKd5MAvtM/YeN/nL1BcmowRaoTpCvRKGvyBcpMQI2Z6xs0wybT09x/7p1CvQIP1pcy1blNWz60mCBJrbCj69c9Qzl9lA42+5Rcv5hWKNEwMbAVc22BFiCR+7MlmxyaFWTCR0bq6nWKmZ/tXuy6l3xyQy/LS5rllZ8gI7TUkv/2AoreLGGsAm6cw106Saltc6btlzqoeUym5fd2P+z9Vs9cjDXCE2lVFqPPz6VXhVCqPfBT7zecVwqFcuUVlT5iWcpu+Am3KB+v77/xKbQM5dRb7vmXaVeSPPs1eIrp7JpNC/+9v1Dy5GxPpIfsctLmBQbGT/FmwQ8SgqgNhMuFc73zfQlVahrsh4dF3kRouU48AbjroohW10Ntl2vfLtU0PG/+qcZ+1Kw221pPgtIxGW1xj46YxcOxnGuSyjhKJttIuOn+jfOzqjiJzfl7OWIlGdifkSPiKSIpVVrQA7GE/lgbRNtOL/tn/eX/uFqjC+iwwwTdYg1vnhHXZ5RMAZCUK6zF009k60+XOAkCDWr75grT0rx0r8AXDZlm6iyfgIOwUnCP4G6UHLIClIE+azWtGrErdnN3Ijpas9y7GW0Qb+w/vBoBkGE3D3OCHxGJd//0c5Z2/8yFZpjc4uDgjlzFhNBsjBiSBwM7jExq1Vj1JRfv6knKVTEvgKnQQ5FaJQgUgb5CrqLCgPm/5e/LwvIf2brz8ppcBFyqQx67sgeTYlA1G8skUrKdTp60xPIzRkcgwaXaKSlx/fYqiebBZ5neVCJg06CIUooS9FesQmHtrVIcwUEXLhl1R0fXqYlOrJxgt2xwSG911IRmtTeS5hXV7rwtOZhr+1dfli4rTnsFTs52a7Udiew2NdpzRm72weaFrc3k7yDAX9sydNXtxbH1VFEv9Y1mCmnFEobX1np5VgLh+t8nR+Lr8jt6MmPC2eW1DfoSAAp015tUhKRM2pctoWogVNWTA5+zvXJfDX/SbAZKdRKWcwCXLFXeagSioe9qw9nhZ30Tue9qBuyAcigK2Rgw77DQwJLnRbb+UgE01fyCXwXt1TR7P7QUDMqDBRgHz8rjpcbkeRoILoPKmUKQmf7lXxN+TlfyTL5uf/Zj8Dj6Bh/lu9DyEGjlQY0IBKQNx4AcLdOABRiw3V5MXvzPHqebpNyIPHfTouplQLjPjk5HtjGtJHr69vm1Kgz7Nh7m3JXbmrKnfncPvLnABef/i8Wxd/ZW+3ptYnZse5owgZr73zctSrtZkPgwN2bgDCqsoz/zWaTn1hUqTEyLLe8hm+cgixJpwBltQr99Imn+tHlFDjTyQvrDSt9MjYQq2s4Q62+Rj4TRcDEvi42myvvjE+FYsHdHhLKoJJquuWWOBMpchEYTLmVoJRaMaxOgWrstqc9F6zLWwjuujbfJeWx5dlbA4/GzHfHAAOkodx7WOhZtwmnbzjieiMkrV0ODmS6D11Mhwpq5OyrR8MFri2q1ckk57VhY3Nzfsaha+a3vDVJTKHXwOt9JclvC1EFuBnhD+DREWPC7o6IMmFXadPGEmxCa6zKQ35Jselq8oK3XDNt45tZXbbPzH4oGMF9wnE9OTpDJjqAqiEfg6PsryyVeuiq+CnDqUSHo1VIG6oIlcLuFkCD+KkK712JFQQgb49tQL+nrMtG+aq2p52qpNKR+lrikSlNqQ5Drj2iSoIqCHNVS7wtKtduScCDXJL2ES2+B0BOiRLRagwKK07rECE1eW9nvNjgInueVDzLrE/dNqb1WbKzNmX4WZ0Q9kmSUJOR7qkCegdkaZ/aswgVfQ4CVec0SiSabAVkWK9+gf2wJoYYtR+qfNcMbsU9gLn4CCVrZMtyhpc0zm8Tqqb3FboIyyiZxC6l9k80ONpMBavqHRLR0GTcRTuXUFiwMrhbr+L8SOKSsr6avd3OIuyoePb/6ZKJTm33pKdiDp6+u/JTpX1AWyxFAPBI8yi4CQJZMFuIt4xuiIHdctyjHeDeOXiyQ0i+TVB+xsO+MtzK1ojUhKGczigYOx771qo6UuIvI+78oESxXlLrTL20EG+nQEd0u5neAU2vqCXCUu2bwW7vgnqJ4np14cJCFbeuWiKLibPckDx0lgWm/jtTcuxWorEsW4EUbUAIJTnPbePC+VqPbPDL04WL8zJOeIfCC0He1SDgTNhQuxxVg4plLhytu81Lu0KOXKE3GRZDQOxm5u4ebN1CRLiOWeDyLRPtJzOjcBXZrdUC42BhLbMJWcW6I43m/ODoivVU5bG1MXlf0YiRZB3E4zacuJ/8AhZVUnd1gXpFhAxjnlX8x880vyw2OpS7nhsI+HQuQX9qdCpG1VNbsyG/cXO4O3tZVmrVtWdUE+uArNFdvM1bHK+KXudaK0KiGIAjW2rS3o550EO/XqL7u25QGbs5tYASgYMP4soxjknTf8uCPu7tNr/DGNMzL0T0sObJG0NhwQAQHBEsCtLDG1akn5Q3Mpx8htM7cHcGDmW2JunIl8cu6dxC1qASTskpUU5QzlFXolb7Xa7+ITLJePsETChe2BkglUvbUgxD1LG0Jepm9CzJxfWKDxeTVUfLuz9Ogdf+B4AACz+IUANwtzZlA0g6l/QEwNPaGB3nRqCEtEAl450+iBbSq2h+QypidhIu0kNAVgYPM35YTDHrSOVVD0iE9rwil+ofukEW93ohbv/XmHJvzxzYGN19EjGUY6UC/a++XX5K5bc+ZjcSdrNt3WvjcQYT9iOG9rY24uARx56tNqJba3r31/qqFKDAtGBSawOqG9XTp9924H6zz/xcWhyeXj+6TvC/LS2/GZhifaswrpTZ7I3MS5uVFh2qW15Mrm2vSwSPvONy9SG5KPRTRvGom5WfESLFO9gvoBYmI92pRT5+c3JlYmxuVhTFIiMmi5mWQPeGeALVWw6gJevBhqqZLrmO1dXuAeG6GY3lpzR0KplQ3rYgFklzeckQqwLCEQPvaFF+WmcDjFgqVn4WoEcsQc1mE5yoX5IlCMBlwUOyUt8Fcj5udV1cmi/3j8xpvCqNGGLG9ia/DMTO2HOjhsebA2Oza//HUxnDQXbyF5G90BbcdSUzfXpxF0RKV+ixhePd0D5eX5D+70bqdzyQ6L2Zsazc1NB92oUzP44lB24VRZHXoVkucIXtSjBYbj42ZEsVdTviGdfsmGwyV9feb4cWeZChCBr3j1htx/oFEmBrDI6hPoG75g3uyMmoaolLkMfQHotG4MXUw/ELOHQvPm9RlTJ0XDlKqBSRMtcjaZZU4pSMC6W4DCatJUqurlLfuOka3FTyp/7orfHPUk4wB4aMcOWS+UHTK19W4O/XVFuB1To/ImvLj9bY4nwNtRa3/3sjmqCoiWfPiow9L8TvcxzgbhbsEJqLNbN0WZRGtWN0+dS5BcEljATKC6Ol9J7uAZtK7J5e0ut90TcHxcBlf8LVF+l8EpvEGakln/cNPMCvqaXoPwz4kk6TYkhr2g+FIanygdxIgQZwtUUbH3SDoVL8pftileFkfXaBDaH9p6zXxGXXfKTKelzuQZq6qUU+mMeWHGVGkLs9SIuATszesg5rahw2dfkKbL9sQZmD12TH4vjQZHz07VVLi7rogFQVyQTev+4ZdSvWzdCM6bMWx+mqQlTsldjCUGSAurdu7YblOAZ3572+2UB6c3y85a+8J/mv/pjlkZkKJJyrySu5CH0lJQfn7TQ9WBWeFVj9/jwouyj0smPYEsOhQZgf7V8+ZXdzlxc8ABXIfXbS/EJ8T9aGyWHhcmI8ipWRzN1fMMYYlHogYtq70J+DgxJiiz7IibOvgqlFNZPsjUysmJ8RvC7tWVmaJCh+voBfx2VAEODzR1SWLoNnZPgzS0uNLbop3QdXAU3Wf9THr78lXZYBnqXjNVOkcUEYA+u9PEyOiLFdI+CrjMX0rRtKya+1OmMMuc0i5DryGFjap1qENdnXVU5ZPLiPPg3anACP8smgFtRS6GAWpyjOaFlZYh8yHABQqz2wRTnbVMEo7GHHNhwpkDk0ybh4kbqE4VL5EMGQoE/vSWJELID5h60RnSp/fofbWA9vad7xjUADDn8HH2EKhWqUTJjM8ZuOkj++QuGIlxKastUclcIlyrw2L0z2GWb2m/xL5iNrO2HmmRU8hTKrVY92irv9Avx+DAycnJATGLy9dInLFC+j7KzQxMFxctXhq24QAEfGFss3C3+nzI/FaxDG016xMXFgYvLdmwIzeW6fxACgQR0YYoMausMguLsh4MKYM21n015a6hfoqxNRGN1aXUjV45M4G5kf8LoS3Qc9g6NX0mPyWWZaeeEt363gSfzujZj7WQkTizwR7wPKoFzy+2+OZAwWMHOKx+qNofW8h889uUO3a4aeRELGmt+fba9uSN7dlhaYeGBpfpninGvYRwL/fv9yUyfvxXaGrcn+sqdAs+GT01kPSOlxaISvTG0wRpS2adQYzrcukHi+ia81qjwphYMdECQ9Lq8Zsjqc0tMe7wXqtZogGGTWujHDbUSxTabnROH6F21DrJKZ6GNpIvvxNJ6+j1xJGwywygQutT676XXk96pWMjO6KmLkrqhcHTAtlTSXWK1KihLYmw5zWX8Lvk4sNb4rQq2cWZJKpVVb75C3J+sKUQF6lTp///wR8YslyPegYFdYTDCTwKCHwyuS5jpxD1WNHC3fxRBakX6nSGFNk7xNMxl66w1kl+Z3IuUzaYLGWbaPidjXNLYwpcVqze1Hu1G2fR69XyPNNRZO5rAMJJ+T//x/l/eXjdTtgIklENKEzL2GkVLnfzyXKyvnEZdtwbJuOoKphtAdWgha1heQK7ibyb7IsKqZXHSbAkJhK4ie8IjZ6VFFtlpTZFT7CtLjM4BBgW4hXXumQQGAIKMNF8dnbuxhxH6ARiMp09cuam/PkBwRX8rIwmnMM/fY0zt/MH1/3zLqms3HUTEGIvKhJeJNabSAokrbaMzxKhPmeoih8LixNuhj+glaVvfcs8+6wp1r6bvbV69qVk9bNyBtgEoAGLQ2AmEnnDTxbsDt5MMuM6oFAgvyrbXViQlb1tRtEJpr8rVpSzrfNpQVAs8EhKbB4CirJ/sYmtzMoXMQLxf/5F4rd/Vx+BEIs4Zhy4FAz6C7MjOscPtBSIZAUC8kWwL/B4muEEIszMJA7MhSrzslYFK3d9q39nRyqhW+n9u7/K/PLjKcZbLMBC3Xh0oIjLwEY8BLGsqpQn4Inx/GE1OTBtS40DMpkxyJwODBwyBTER8f4iJxpNTYG31fXSdK5EwhstK91b6yHrnEDTApOpyFfd5l2YnX6xm2hHUb1op/nBVSyo1TjY6Zef2/RuixzXNC15DhzcvHItcnQHh8bv9hcW+hT9uy/2/uGfbf3mL4ieSabcTFhiLkCRfnherQyPdK/KHWGij9kSxLImn4cT9bezmwB8vPQ+ZZ/pEXNqlVl2pklAtdl0g+adrkTRNzYKyr9wQU7h3tAUNqizlDTLGXNafjY/h4uuWUZwUiCUMN4vngOEE8t2ZEPDUpa598nkwptD6/NIN/mLUtUHywsZPMEiri4tX5wjr6+fd/OE6Rl8cmtmMD8kZbEIBpODp5brcgZ8YDMg8nmtG6CToRsOIdibl/ffcpYjAolW+9d8Pmmu3EBcviEvr6xSXjTclyo8UOLJldsiA5PyFuupUPv5+bmhtSRBPgBH7/aZy+bDD1MUzgfkWz0Os9nI2Q1xOszxPSYaNa0qOpcYPT6O/iY9mSjwSHaaSWvWzXjwqLTP916XW2gfLsGdsdCZeneGnfglEIGHw5PWWWWamcwMZMKMtrCNMsgjUqmQe3tz1WV/4WN5oXWIgFLIJjYSohmLSuM8jfpDMAmPZToS1LlDDBL8wBgpRB6T0uK0zmwy+9lqChtlr2PxWUWljAHxFCg/PwKcXJYvz6TTX/6jyWd/XZqU9Uk959abZEd0OXqsXLiOFWUQlaGSOK62N+F5Ug7UMf0Oi8g4FM7BmxflOqBEX69MTWb1LnwSDs9OJJp3WIVCzl23h+wikAj8NKJYmC2szxGM+gdn5cxvH5Wvoy8sXNu9JjmU7ao3mITEWVYKeCf2C3a1vgo6IcJgpL4H36YkIs6qDX3AMiy9ZD86iHpNpMwxKZoxnQrPlj6XRAmZTxNWzzEr81J26bbd1rzyfObW8jrsI8T6K/iLPCyQaBKddKAjeWZpS7a/bJYzUrHrI6Y0JOUIbKvZff2KW2GkaLlTNxijNiQNCzWuieTidhYqDp9W/1BO3KN/dAuglFWtmi7SQTGRByikszz+Nm5+KV92SIPg52/NmeOqAfweA9oflZ+F6G2c32VRJ2Zs2rSxc7fegtxlledn+bcMOamAQdeTOYHt4WG5bHw8kZvL7h9SFlbPpLPN5pgyAMtqnn8u9al9+gjYlHg5UmkjCj5fWWlmTGOVMEOJ25SruGALcUrmVp0kim1t8bI8Tf+MT/VSX2UdSwCFif/9X6ae3i8o3ArpFfhQ388fvhjlgSiDO6FhdcAmtayyrqU7/YEZs/R3mBRtgH6G4qw22VEfqSAxazuHYUIL2zWZLPminOmp5RcuFBS58xqllZf651BlLhcwQHKmnfpe4j4WKBPMZbHA/n2Z1897jh/h0PizPIUFHjWRxW9c/vrfrxw+JD/zWQAVam7RpPz0ASMqNqhVKg6Jlhg/PSvNBGVM8+H8yn3al9PTly6Z5nLRGBDQGaWKUwHV6PCObeEKoMttrCzn3kUaJRC3odwt9qVD2l5seiq94veJjxNhiTKR+JzcskrBB187nWxtdwcCwkNMWBDdb6dI+bKSS6vz06nVeanq5QtpHhLFKQEP4IXNO1NY1fjIj28RKOOGHrRjqnR/p7fAD6NOto9Sb119FwX484xeVqc6M6wKk08jAGjDd6kCaa6+dcFCkGIELemft1iXz1DD9oNTby8hvLCtvZcVUITdE/xE1IBcB9xmwxv0GiiHQKOV7UhOJDeTnpjiMurzb/7T6v/x6/2U2cSMyCPmrkhtjaIwedTbSdW5JFDpTpv/RV3PIJP+wTcgVAi02k8+lYD16zwlJQOjpqlTHwe2oz5+LfNWRoNzcoIZ0UMcIQvKMm9/lVPe+JETKe9wwz+/n+7YU+/ZDCyCtFwBpOwfNa31prlRLq5m282YbMoE3XefmRhLRXPoaMFoLS0J8Fl8XnDP8EASBGxVOuxESm1rCSyKYvWUImczvWCefsoBW/7KYtZ6Jrp6X/6uMGpBfmYraGPlwhJ0v+P2jKzk5ecBomYmRaUWdLo//mxYcBkEe9nIt4WQ6bQ36LNLZUBUtXUSU4GIJlA3kCVuJBRbTYRwexSWRdKrPecdz5D0uD3XUgxDgZ8gAgyoD9wqyIJCgJGdiMVj4W2LTfGv+OqycrlsZNiMMcHaLxOmIQLbjWXOctOhIWB85vJVqdDxT5a7WptCLAShdSBik4cO+vZ0SLlbtmrJri50qU9LBsYiZk4gfFiv1PajT2cNdcP5eLPb2aurwbaooGyIdHj+gItwEFH5vt6nHzbjI6KUVpbyjwaVAABAAElEQVRT+L2ore4euQpPktY6qe/MxcKnZEw/Rz/wwozpuP11mGG+ugPNx8g+U63YYzbL0aIszAGMSowN7eMS5c5fAKJc2Ss+udbUYBjyCKMoAKFxKgvM8LDzrTyZ2y/pqd15ohOam+R2gMX0RGpt1dlPk7Z1lRZnWaseW+PJuUwlKVSPbXKKcm4NMTvjiW0MDqYsPi6vD3iztpqmnQaX1TVZzigKzgntb10L3EKW+zEWV9qqxiUef+Hrm3YPri/+t7VPVjFgV5qdI7JTjOIMh12aR7i6Zbn7/Gbq/DS/x+JzLftCOZFMxiW2pH1/dmV0q7xaVdjWFpxv2wdponNwuvh8iIEI4RkN8eFHhXM9jCbFt+RUMCAR1m8/J+WD+yQWZjepRjdSVXSjnRYim5+WmB1tchkP52lfHDE/o60Hz2BcC3ZgTwk+uXcmxm3LZbYTkpt9PGMBN6INx9mIBnUDpPEu6LvPsQVCii6gmyBkBxHAW4CQYuwoGMhyO4GGmtqUbUm0ulgO+0l0PKl1yBZox61gRV6pCx/Xu4aOPYaaEBlfGVmuKhOpteLbViwrrpF0iPtseM4aI6ws/whqQiUAIpZV2Row0AlPg7BsHH51NTc342fwFKLdeYQd/eHipeXMpPQXhLFnxO+JBinDsUgB/GB5lU+D4a0Y8eo//NPMzz4tl1F9XFN6zfpUXddErhltgKJMjyT8Q/Z2DT3iC7W1OsOMfEVLielR1PuhAlOcTT5S83N62MiedQWIqTyBPkW52Wbk1ehGVApfBqFkCN7b6f3UEHnB+4pG5dTcTdOTYgsBKTfmmYl1ccAg6kk3leWZPxfbbX6pSNhG547JsCfvsqqYBTjjZGdddaYg5qlLIDfco3+KFpjQh3SyeINNCrQjaHZEH1ViQxXdCzIPx6tOkJc4EYkrb79XkBPhFT2Ep3brdikcZVfkmqKcle6xU8+J+BCUWfA6cgDfwjPwJ7QwuFKYkwOfWDOICbv/AfCyOlIIG8E/VAlCBG1tZef5ZmcFRk7OmGmUhfwqblI1nh6rZ/G6cL34izBoMMiztjx43jM+KlLKzg7IEXEBm0br6KqA4zG5Q4AaZeRD9ZOAV35Ryf4xCzwQXQUXYqbhcxuwq2R347bWLGJmm1JVc/37Zv8BV+dOKbtdobA7i+3+VKnlu0zhdsylysGdTh5+yjNzXaS+oGCRiIynrdmRTDSD2AMxkcG+3oMHEmg56BTre8EC62ZOjj6IFNQVcdSsKFdmNHg82xZKoRw8RSw8l15O6rxiUQKl8gkodoJ06CsoZ8b0rDhdgEuA/bmpAzVy7l1kcTyWjB2BOzuc/WNgs1dfhaPk6m/++cITZWNiIjXrbHPzVlbY780RJmpq2rjWzcoIYdSkmdl70Jsf2Eqrutu3T0TAOom5U+YMGzTKw+5AMEyl/lymOAHN7LhvPpPtNkvK0Ypf7nDvHX9C+jBTENAPfmlsy6KcdnsSiS2rb/k6AobdrE7Xy97rj2Kc9zoprM4XCWjQuCGi8/1zUv61X1XxwmBB9A3WjoawJhLw5PeHG0Wbj5yb/vSDuiEp0tQbw7ggtaOLcpPaZym8neQbMAfGHPKbf/U1Kf/FE9NiIq1ZHRwU24atAuVAy8vojXC1ohB4naEt64gjMoCYkVFrcDHdc7OOzyl33aP32QK29+/2pt/7QmaveuR0U0QX1djgKz3INnaif2GFUcEZPW+KBtxOegDBLpdZXRQnprXTU3ewIOAWHhkdFJRvh5LARYSEMQOqFszRA4KZk02qk1ObV77cv724ZePR9D5GIU9T/1WmTSonv9GNqgFwMFYy56ks8wyKGk0l0vWFm2ZVrRbYBJCYTk8918UpeLStfsuiKKZgjY1lGH6BADRAN5CHS47M975nPhScA5FAlYeq4pupEn+EMnu2slwntDq9vCISjdFCI9sPv3pVgBzKP69OMHrG5+dcbq6AHXiba+ywh8yAuiFrTh44xBkzO2m6bponH5EyfH7mjDnwiDSxt7KM0eupl28U5YoUb8yu54ERmf4I5eWFnn2cVrXx9gDmAU+Rm6HYZkVvXyjvFkW/a/Prf9B/6D4vQ19yColBmdlw/X33tYW6NqZX+fmlF2XrYVr+i6pLTsYEpu6Oyh30DoDsOHFKUY+SYxD6m9Pydyf4r0YyOUE4J4x1ACtz1QWlgy5edwa94YS//I7ZXWnOK28cJ/fHgFwMAakxCfVqwWh5Im00keJtMzwlG0npGmzznYvmEDuVSduLrWU+4QHYQ1Ggr62eNh28CD4x3tT2yC32B0vuDYuFdOXnrg+uhtkrV/zJNM/X5X5mdiFx/KHA/n1bFsWizRh2A5RAtB9a2+oi/I3vPY8eDHjUEjDh4fCH8n0b8qLjjwbEHWHsCeSCVcb4yLCClJMbcYYugx7prwJyugXcfoZLSsRqeJc38mvoTzmVmyMACFaB4BbeK5BLFR0+IdNzbPQRbnF70nX7Cvxu0ZzzN6aHh8UZhihQTz4KmvFJf9E+9ivq2wyrC20zXiL1E5MbVwWgQORbaurwuXXU2B0MljzQZlgkRwh8aGugX/yZI0flMtiEMjspQ4CxRjJtlomFDUc2UbXkpbCjN6wI4o0N7XIZgTqUM91n/Tc+CmYoZkspYtLt9dKs0jzw0wxPXLg4XHiyQw5Z7476gHVpxpysSFEmxsauyHJBgJ06A5MbVhvQPrS3XiUNdaXHPPGYSDHU3GwefdSBj9IocAZGG+q9IS+F23VAqufvukMpU1uiJhhtgEW19UEI19eY07LQP8hN+Fd7dguDQd99zeysE3crpOruxHFpFhxgyJftuf9AyjYCdaOSNKxH9SgNQhPheUL0CP2C0RQOofsWpFW5HqJ/97CZRYOUywtkSO0fLkrAAlpnG9BNWQAGnd8yj1c5OJBHwRs9/SZHGZIXUYGzl+Qy9A/peWhIBjyhlirTEjbzI1I+Rc6MUtknEAKRugn9+s3TlXLIFtNw2g6AP+okVxjG+nhX+82TFYYQge3KQsUActE9ursWsJ7Je107oCeAR/TwS6pvSSKzQ12XNdWQu2vMQVJdiGI258cEnylfyCGGBBB8QIqSQoNgRzF7XaN61jfPvTq5uRAHFEJIClxX3SyMQkK+ZGFxMiD8JDvFzU34C0LBoHhwXBwIpp2cE5g9lk0nknat8ksvZdprJQM1NBaXsTjeC1EZRBqwawXzL543v1OtidTQAEeaIrFU7hHh9d3u5Mb4cmpy2o5Iw2JYjzF9Ap/VhNIjhbuyMRZyBpWrp6Z/ZGgcK/G0XofsooI++UuiB/1kzllYWHjhciG5YlC/M/NepN6m4cnPy/rEU4I8VNL9RIw8JGgTqGDSmyVDfSG7B0Jm/fnfv3roWBbzHYQQcvRDaYmUDx6s9Vyd1zlUrGCY3JClZfz7YBKqzTLemQWRZSC0NZG5JDZdWDj9vIAQ7NKlq4bBP2tfuICJHnwuhM5ZvO339mLjFMGrnZdYAKfeTqrPDDYvsm6eaXRW/7HtzZEP+0MuMZEH2E0L9rpy2ZooRmtW5rbXN6SJUWIAOat9G9p8Lp8nldwqKZO6z0ylmcFjYwHwHhyuytJU4PO//fXqscNCEJXPvSFT4q1vgpPflzbDeuotqdGjH/MHeTyolyBO2LsAy6qgUKD9qD8QWKEIy51NmKsqd3rhD/8J6w8qwT986q1jDD4Sv0fZmPAWobQHaGiwQXO9BNWsRdFAwtrpK5EH9ss5DuPbHtbjqh9YXZQeuSlQDFiFfgYAxLblKtueUnobKWQz92eZliKja9gVmjNcCxiGwGEYaWy2Rxr/b/5tD/su5dUIaBe7iZhZeMFrpqddlRVbE2LVigrF0DPp6R79j7XA+3O3hiZNmXIW6gvsC1ymv6CRKcF/DxyTMiqOQYxwWHhgcDDJPFigpHVvcooDpjIv0SNaq39Als1bD4R7gaw8DTaCEB5mqXq9yvTzi2M31rmABBDQzT7z2MdD3pBUu+f1pfbH8sLVCr1RGIlNN7u/Yw3QvAnclSKZFgwBo3ji5ubyuNR114H8SI7f716gvL4hETjrMcLw8Bi+oo3lc1MkmHRpdgRvU50vNycCOIMYa0BnDCQyVwW9ISOgJTu6BQBFhaEvSpPaKBGfqSiILYmuIIIP8CMBHcQsMvL18aV2u9i1JVnjDqCEgI88KpjSg8nJ7teWGjsDHp1AGCrwL745mHRNcJk/L5B7gNjmZnJYDr0felgshIVLCEk4kmvnKfb3N167sTRiisL98nRjzp1J7zkq9ck+vs+9qzMcGaK8a9fUl06bj+w3z9TKNWmWDOHHajMi7Ph3tZq/jVNVso+0ydNTiCFNjpmGaDH618alOGTo5q30ilSH23nahxSXs1kkNtgG3pB6HhLUJ9CiDJi7MjpdEGRPMGnJxNS4rcTMVqmDU/+w2/z7B2U+mqQwhtMY55paKSDHNuhhWyI1mUxmeUpURl5ZZnoqkxcTBsANpjcxxFBhYcqV9uQWkXZC7iosdu/Zk2bgEAIKw6jWr8PstkbBFmwn55Nz1QVFBQWp7hsUyV4Ox6yNrSwuS9Wr6nyxqeVrV0W9r69l4IdAPUUTZobqwnrX5WRBsfRmyJ/Kr88L5Wm142slJY4v8eUz5kM7pOtoAQhpwsXtkfcI5m5tzbDtplfRDRMBmDTYqoj//HnhHwt6aExC0rTzab3r2fslIZ6F+C0N4td9bL/jYsNjIUKMdjiY/BCR8LiubSOXLuOuJGNQRpMWYKCMKXMQCjmEdVXvDRb7d98xn2lzEsPQpxMLxu4DB9vjDwSy3RNj0g70LC954zUpP7THL0+3dSW8EQxGDrTI0BPEN8zNJweGKY4OJxnzzQ1KfxU2M98P2viPpzgyP9Usw5vEYiFW7bKFHhG6XbvkkC+iG4luCvEWrDQ9B01MLNyYK1SG4Ki6Jdszt2oH2P11uiuwlXkcFKyr11uk4cP04goMaTEiS835KFrVQhOEGl8rO1+YYWMpkYw5iouWp/3xW06r+9dSKM6P9dCYHcoEXRw2q+JoXvqiZ1Zq17wg8mJFbN0nMYsd7HMlZ+Rb2JpJLaDZrRWwo+j4mXwsK94nlB/nN82RXaZMW3HIycZq+kSaTW2FKWbfLW2GrHnTVCML1yHWnl3sNdXFTl6pzrjMdbTNgGjwcGQEYnAvkjJj88YHwlVVLP+7R/9ELaDg1owr8MpRSMifSpArW1/oK9oipqLM9ErIyJxJOlzx1svBhRZFVRMWZFaFLkdfmk1cOZOA92FRiHjBM88gjIJuL7weP/BRkl2CmWHcdbOe7fGn3G5xt5DpktqAw4VVCFWYFc4pdjwk0cyJ/EiWP50QxYWhhTPBvhByRm2xJa0K8hqx1yG3XRfi7WjNys0NYXeh1dWcssnU1UWfX66DYS1vU+Y5xQQIeLs+IeIxFeiAmNxkW0ZKdyKqVZiREwxXI/IenS3PjPCR7rXytjwbJPMU5CYuXttMiYQE8oL+/Z0yuMxQO/Thj5jy0tsVSTLlN4RygG7ebO86szbCesseOcTFPR23u4d5D+/3tDUVogIIYTQtvXheXE2BHR9IognVeTe34uZDjeKK+9RZca8uTU8kIrovBJa0RBcU23AncdfhYSdf1+ss0L09XZMu5lYgeZV+qTLpO77Z9ibsRW+il0L0Ira4uqqE+ce9fZTLSFvs8yUm51fXhAkxKLFY6ltfl4cwnZzp1s6Qmj++MWcuvknufXkJAAke9qv1pIZFIVk0Dt2QP++gMV6nPyyS7IcddTXxGD/A0ud1AJaymot33PUjDhCrGmVxUiYBCFdY5ABGSm5mh30W396YlMFVGGjyPZ5iuRdA8F7NxWc1ok7xaYWhTE6RmANrAiRfC1lDbcRukAlOuZIpF/MDYQmGhtcGxGxgSgYHM8Gg1A0PFouKtRqUiyQ/x7tJJBmx0oQce6J6wDOxoPZFI8MLF4YKnz5hcdvJR/wEYTZnBbhmo1kAzGBuiL8MKRhXJE9elZ+fYi6JmiA5eY/ebwu8PwUCM9kwc/d14UuiC3aSGBiIVRJ0E8Q4JJ0FUodgCzAVoJy/QjgTieTmhnCMIJUq06X4o2JJptAglvg/EJiVrT9WL4qijK0k0B1o55oO8fPyO/O8VYFvfW6E8slHfNMXx8tgOghXSeZFpBhygYARsamlYLHcIq9ndUJ+Xu1PHuKIBG+AvOUBwWhE24kD2WpTYRb2dHY6wyBstcxaT9PWJE/AewHqWm/JGbp22S9Cwgm022lmGCxOVta459iviq9YXswt9duH8zu+5S2xX6aNLcHyBbPalmSaFemjGD2GDt8fqCj0pjWR4MbgbG2Fi6VlNn2Ea2WprzuZlyfCGlrcSK51xTZSMZ0n1NRwU9ScdRRQWgw22Uw06fTQ0I0HnwitzUuz0qol+WZuQOpW2zKDI+UirI3X2jN1olMgY5320eUtMVJ2EgX9CERrKne6j425Hmk3Nm26hbnfuswDzKFKEX7Ut70LfImEzqrl5TIQ3kuXzMcflCtRXkD5jg4pY8g+f8k80y5lXgSu5SHWZ5tnB7WIg/+YlDU5It0LPV2nw0F1FaJpGCi/PPGFr6YePyGncAz4jah/qEQVZ064qmoL1QDxOeg11oVCYJHjJxJs9Dmr9fMH0rzIItpXzpk2ElZp3eCfiVEzO5EMri9xV6Q1Gw/Gs3uHPIJZXOxsQ7JdcqSiD0vDvtmFnIhchv9JHZ7/nly1//ByOJhkRZObMQU1S5m1jSxfnPLavMxRwWWCHttv6iulWazLRyPAV4x/QvQXzYLjMnhVLCnzzZhYanUgbjnsarcfoNFwBhi7sHt64bbxRXhcEE/j+uZKB1XbOILj2OHhDQ7msF0XZqBRsBZTeeV12NqANKPtCHwPpsldvSGXMab0mSMml10yVeAWl4WNrRPLk3OquDkTWZaq+ovCWbnp+jVld9xHfCO7VxcyUFDoY70vo71QfsHyhVsr6h6TbHNwKFkXlZ8/XM9mXJuMOrarXqcdYBWbXo8BRVJE4Ba6lR8YCkayEFshnDwkXVSLWPhINC1+tmYIjhT5u85i4+Urmndsydeq9Kaff9G9bw+NFUhLVdl+DDG00w95GM3Iq+0Hgkto87Su3vzudzK4WNZSwvM0OCuqyZcDpfPlFjx/iAwW2ErmvTP5CjrRKLd4bJPoZlx2YB9h4evy/U4f/e2moJx2hccN9dL49C9EAGt+VZNB6cMLikRrbauRz9b2Eb9OHx5k9tesaYjKXbui4qbaADacwDpy1MlubVW2Vse/IsYEjU9IgFSBpSEhUd+44K11hW8otwfkknt0ty3gvosLYV7+KcuIK0IP03VVAbmToA+iZ0FejzF173wa+vp5/aXdI3GZ+XlRsnQcQ+Xc2NIpCKm0IydQ6fnS58QAP/aoGTw7U28tDX9RxyZjgRx8NT+ZqGzQt3KKx5WU5D4tatq7ucoWez6f8NOsLliKUIJPCG8r6NxUliZHGskJTYeKHyqDQCQQEkImp6Y8mSTiDiF1FvlR5vUAuhZWCilX4wAwrKRFZ0qh3HAn4rkJEV/5UmTXw6YWKNKBueKybF8+OQTkw13LS/3X46GQ6NgUebRWL5BqdXtFvqK8oVdMZA64muZOS52rmm15YuLM7kdL4ioJCG9lYWb2pshVRe0k8RJvgejETGZpT8hc3LjzMII85/9vQu0p1pHVcZUVoi2zQtImfV3xn3/F/Fu1fQS7GFlCs/EPAng0NTqaGDCEUq/Wr8CZoaU5VM74wdJBPSl/tFfF955ISlcbxv54aT0ZYyMshJMrMJ+zs56AN1IqASE2j/JNzVZWiOa61S8nrbFLJlPgQdxei5GAUgTprN1BZfXd3v+a78I/fzshMpV6jBDBuWhg0AvEve2Ett9+6d2VUXcp1av1TfKQNeXXSDg1Nbhl1S/rzmgzQKfw1p1IBeJOJ6iV/kxVeYJUWLpFsmnic9IUQtiYt0aTiG7CdXyVNZGh7GT/0FCfPIMdWOfZQ0hv/9THxbe8PCXZKSABH++iKf1lKGO+vmX+XHtcXDi+x27/Ew5HWiskJYb65ZVR7xt/DwAQGes8wfqIkPQmdPq0LIQeHl5dkV5Gf5xlSoqcuEf/Iy2g0Omub8RSE8aG0HpI+Jk3ZP6OHGqqBoaeIBQXWcWiLWLVy1e3mdHL+E97m5xK9S3HtlZqiBJomOoUE+capZyJCzRBdMksBzFudu5aam+r9D2yRFrBhx/3+XchSmB91g6PHjgJ35qNhY2JkeTK8jDlFtbBF0lase98myOpZCoVP/nLaq0AUHhKy8vZ1cp0YDKXO79KrFFd3SbhmVnFHCAnhB+v6pGPieIqyI4LfLaSNxjDqbJOVNfFRHFBqrY6UxWVoM7ESOrkSScEjiNBsxDgt74B4yff/kayWT8QQF8XdRZRgP65DJVnhY2A4DwwyEpMIuEmLKSozl+S5yUrXzr9xjekfkcfCrU9XpC1IEI0O0LCxw1uty9a+P6N9ZV0RJdaF1QEer7e3/6U2pKOjoP/+xPZY5eysqWX47MroHy8Yijv8mAof8JuAvsT/1NZnm+99831Gyq7nQ0C8vpiclknS2XypJ4WsZG4hlPdqoy8MVM4Zcqlk0Vd0neAWFQAxD5CuMe2PKw4dVeDM4Hw1E1Tcnuk4sVZU5VwxmGmJsXc0xd2InFdnY5uaR0AhYRZQfZQgV3Lvba2MI3hNi88l/qJkw5D4nJwF5xTRv5svK/BZdK723AvcITKYFqg/DzmOGTKK7etiwW3wKt25OS+gyafFXHCWaLrsFiUAzViMCSY1qW5wClH61BLWaOjWfjt0Mzs4ljMVq+y3jc55Dy5uNLn9Xg9NVUZ6yEtLbvoTZ3vFVybwDm0LjquC2U4vHdSHlYXZ/WBk2qF+yKlbCS8fuZV0bZMGKOdbawWL4iBOF0vJkwLyLm5IJlCIZiQFrNTE/tGTLRMPB1cKYjm3Xdgu6RFMQdbLS/GbJwLpIRjlpPn3lwXlbo8I6NJqFmIoMMcgnJNyniq+IE4clfUoNV6JZkNDQ7ZSPH0YMymxyhKxN3Z2dV7i+UclX7jDWe5AMM9yBQ+jW2vRIIpPdtqS3fslO4r3FkhtxT4zGSMz99TLkcICx2EHrDEZXCj4EYuJBPhpjNYKsNSr7wiE+P0hA+upbGsjG1siKsj8srnKRPrdD1Xk24clp+3ch2MIXARMweHQ1QQ5xPU+8dX5PDn2gTOLmuGaGAKLWk/HE9PKpY2H7lPLgOmov2s1zpB7h4NQNYobLk5ZkiJ71VoSafTKm99EfEpPtb2bCk7E7CQUi+DMU6Nm5NaHpiTvO2kZS/Q7wMcAE3mVWl4XFhDCXBU1EgdEqwWI5m7SLy00tVJUzwjZbaU3R01k2Nmb4ccgllhGxoDqosKyEAvQXzyjhYRBAFSxvxhr/kX8v979E/ZAqOIzG3IiMq8obPUdiouG+9j0Qjb78rrWhiTfOdr4c0q/eWrSfPCefMzygyIA7zNiFaQ5Vz0LPGg4aHjJ4XdF+cTMzPbW8/xQtPc5vHmR+KTC195QR5Boku3O/WZ+/V5YiLZzGHZa/eC3CbwuV5QIOy1I8ecwQTLHZImkRfurXX2BJYpFNhH6xqiMXtvLA4IP432b7viW4uzaatj8fBdCScivqW+Jepkhz5wK20QLxVlPX7vP4CNNf5TJI+wWHsUrM73+t1IS99zQ5xqOV5c/XiFd36a8sbwXGxuDSlDouXw9EU2Ys4vFqnIKi8a/9bFKpsIcldny+99yj/alVYT6ZqZ3tjIWJ8xt2sw7R0P+6RXdu0W8Y+fMa8KJPkgEl1jET86AO2E8E5elx/eeN38Sqes2ISYTo9RQ5dazIbCEfeyUk7tuCXLAlUxSNoM2AXuUcvnbDUmF90m5U3p0CJNm1TYoE8XE9klQSkoGmURgnt01Gd9jXRW/y3ZfxXCoAz0y3mIV9Oq3tqKTJafw9TEVGp9y7pbKK6ZlGzyBiEC41p46w98Z6WgWrfhwZ68OiIn/eyHioPw1nV3XTjHKJBy4RS7IVTqcI5OnZiRHJjyFFbEeRZliZTy4Dueywcjwvp++T10O4zy1kWWZegM/P5LpDbQfkoScy+THGBC83PiSxGahZj3wSj08LAz7OhyefxZJMvnDNCI1DBN9XIV9ho75dlyQjZRzQooJ95G0qb60l1qzuSAuNoLzzspBAoKfIgHUX9dU0d0DRNp4bcA4rFxJ0ECXUVkN5g9NyufjmEqSd5hvFEefo/uogXULN/FdfaSYe1pyjAlaAA4+3foS+DIfaIBmeUFyWjsignnCFsBweEfUJHFFqur2+hKj2IqnKOdrWwGJbe82WVQm0Bhq0bRCExqKDgqpwA0eGs5rB6xgjg2euPsalGxi1NTk0mWSeRp/uOFqfjRj4fT6zGr4u2omjMgi08/P7d2oS+yXx4o8C2+lZVCRsx3Lphf+bjIPASTA93qdoazGcaGNpn2zUYbyxS7vjmysyUeVoi3q9njzqSYzJhISR2I62PqLEQD2vGPcLXu6Soo8MA+ZrfJw0BgXLm7RcoMlKMNwcQ2QM5stT3tJlutAgNW7vjG6LDc0xRiWq0HNN36MwfltvayPGYz9lyX8kj3K6+YJ54wf/hlOUpkYp86YvrVWdq5J17mSiXPiVPlbW8veaDT9PuzEGYMVXawpbUouY7Um9DapGdzreeKlLFY5dEUI43WtSRQ1Lvm2DaWE5AnDXRo0S1aeMemqVW9OUsHMdyvmvbrQ+anOiUawvVQwTJzwxxEjavDFLwxt6mTM2Zj1WSx7RmoAXtPDj0SA2KBlegFtL8NqfDdGHFrKWk3husQeQj2QD/0/sP6U09KEzFpu3pXvlunJuwzC4lN0nChEQWfkuj8v3zefPopuYv648vt197naWjnwvy0j6meTFI/vk2nW0w+N21u9Tr2ArRq3+5l7ABKJMW5sa4qYybE8GB9tBUU384xy+6YaOXV2S161q4e8jdXCR8wVGSbVTfztWk8vHnhhoZ1MnZCY2whmDbZGWdjYtxChieZ9wVx34kGkEXKvgdOBMrbjmBBHTJSr5qXWxDGxO2EgVyMtkS45Alx88q0jN1ZRATLuWgcRojg7qmlr37FPPSQXPaFb5rf/EVUbfrzfy2HNBHuE8O8UH5ldigvvpdJGxo75Dm03oriQtj/pUVzXMtHjrAV9YbXpHgFxN53GfdGYaME4uLTS/7ipFMDHDs6w+9z9vFIp7IqS+fOi/dG9IGAWn6ltPZs10w4K8kvTLKA0BgAINsmTFd5a2UUpxCl09PmhOoQEWDWn1wXMUhvbbtr2dGbHZHBITLsePFN85mf08AgugnB0xwRLoLiiGsgEGoX9qzKnx26tmGdJXwPWBc18lm9qUFHk6ws1zHLlE9VK0rj9/aafXsd2/Rmv+g6FAzkC5oMuVuZQqxNlOcXH8ampjgza8q2ne5j+AvPh39TIouSQoCtwL+ovuX9C+ZwjeyNA7los3mZZoZGhWhFmJZ9JiDqCSfAAzMYc7Ws5wbkvRCVaSkzHlVB+ITMKmysvc0ba+Zr18xR7S+ednHINGhT9c6bsg25DGGEHtYfpXSP7q4FLDP+6GtRFqhA1aMGJYIKRP2fF71litcE6Tbp/fARl72dgF2T9hQQbMUUqFaFS+HD/FK2XhBWS49OXnkjXggW1ikk6POCGTF2Q73mw590J7eSYa0i4UUk3YnZEH1AlrqvOSPFWEx2YheMZ7wsj8FmSlFSZRQZYTY7V100JKwDDiA+9b3++iZX9tYy5TodNY2HHc1HVth8cgPLAwStAjgwTlI5fSx8OqXlitufpkfv+EMFGsEStIuGXxHrdVG3pkkai90M/JU/fb8ct7FZNMBTTOTa4Nz3v28+8hHzub+SM6nM+tMPmfGbUm7duSW77144Kwc72vL27zZVITcbJkLZwcr2wvSqiKJ/fji9vNp1RX4mkgPluJwRJJVU+eWDQzRjr9Zmp0xXMRe6zIPHROwJ0jH/nF6CWJqLTUEnWEKbfaHPnFAupIWhqP6l2/vVr7Z9xANH3jlkJP2tvlkuC5WDJsCEUgizgvegzCChIKxg5w5BVFBss7JpPRQQcABSAgrCsRDp4NmfTYKaig6X1xLrOjWDU8QQn2w2L2h/9cm17yD455r+EEqLdYD5dZRX/HZESczJ+yRaz/JnWNW+1fPj4+Z7p2VfZogPejdQtkLRwKffnqWK2kYClTd/uAa8gmZEl0cUbX63xzwTEqUNjfRu1Ybn7A7jhrgjLYlydxDzmqsgL74l9oAvRXLLVGMj1NgxcGpUHqCzHrTw9j+WSy+q7FgIIS1FazNvBIInUAEgKtsZa2uvX1r/9ROq9Fl/3NxkE8YIBCVCmkxVdwqPBPtXynNMj5qnt7/rXvkuW+DdXPSjbvyDT5kcUd3CDGAObP9B5RgiJaC6uqicApPBGdOTYj2IBNfViUxawCenbxM8Tb47i3SBFMWsepoQtoam180TDzmopeBAfW7KPX52eFCFLy8Q6+nO2PAMiuONYfOvPyu3CAzNzSPDc0HBOIc8RyLuI8OUv/NH/Y//z9VBFh4xd1AoA2YcG4b/zYldAlttHRjlANNno9QVHzOJMXhop80/EH2CQPfk2gTyQlwh7QsSUM783p/IB37ysPCwje6L6mGOGRF8NVTYPtA/aAzCfnGZRfDgObAa19gA+diS2VnvhJmxFGtrqb175RYZ/kAeskMFFtmRw/W+Y+bESc6Ul9bmXft25ImTn94nF6ZnZ6tnbzC0Qrnn8vaxE+5zr4qsFc7/Q/On9su4IckiiVe5PTlU0UWRlhk1589duSDWEbnrOi8+JzWEgLn7gs5Q9t9smycnTUetgGzoQFiwnV1His7dfXvp3Ykac73XkNqDKW0Qj2J+2h/fkvJv75ORLjcthyLkFpa35ZgGhdErmojWxteRepoFVG2n2KEBYBgLfGklfBj0LwQ+mGHzk1YnAFld53FnedZGlziVW+hZiCXAiOkF+SjcnJOHbju0Wea+RwJBlkcYMzyc4hO6utizRRQsTcuLbIPDM/Ck7SO+l0cJerF+nkQFZ9Ym0fMm0lYpOujwESeL1+qqXzw2LjUba5sMAR35qGpEWmF1ZfnaeF6p6NfketxbUy7pcaFQKHvyptVyzXDWhhkZMHswazoyLOetQztj/vz/2vjZz6YffVyARn9vilvsuAceH8xvYxPWASPDuO0+mBmuwXWBHr3PDE6aSzdMowopnwZuKGYeEu1TGOroXJHptwyc7hEryLcfPy6HNDh8a3n4+qV4a3N6524xqKlkGnligOspjAZVHTW7XE4gkFtSqRSREfXrpQLV1Umb4jOLDbloLmvkaVOmn8PiOn7rzfINXpiH3yA6he5e6RM+y63MGTgb43eLEvgivDgugFA4VIx5yNasc00jHG1ZuqPT1EXlM3jaqTd8zQ3CNBYoLS7gPfrD6jmxGpPn2gAJHYd/v7Xl1SQomUQct9y+iDfyIi5sR42oX4dfRk4t6OhR2YpanVYZNScVEDzCoCJEj3QRaxAGNJ+uMAxwRaNO3BRnng/RNCWmjuy747LXHIRj3D1imIlpQXBj1LwyaO7XlwY3TdjluD0MbaGWAnUOA8CrzI/u7JAn9Nww52/IZXYsF4V2pFN2YoBoqD6cNIVDfDftsb4myTwgWrIh21yblnLNiumMSppZqHjWfO2cmbplDtbI4WH9UUr36J+0BdC1qiBlZg5KAZFSqZK5hegLVbcS0343sLFgjr+fub1Nfft9+XjX1y8tz7wySh1z/XEA96FDIgjMOvn7V81v/YRUXTRtTk7A5SktEESKBWdMi00aKY+/OlDFtuXECWxUA5U9P/f663IXPDPC9CopmgfBfDq+ZJUicVXT2iYjJrzowwTbZpKk3NV4F4oaoT9/Tu6a3HIWfVGu1jE9tr6LqMzmZJmsLScPh3U+5YZ3EcasgDZRZcUQDXrsyY9TEaJlJ3S5Qm7YI9bcYCIRzoNiIvNKKstufSnrqcc/uk/OZGZmKuZvFLpEFd+6tLTr/ryuUzJ6Wzj3+cpP3C+xXjWRiGiIp1u1ONifef3Mi5+Ty5bj5nWP2dAkvRx+AAl+iGq1sEMDM7LPpNWQ6B8MkZ1UTzgbHYJOI2wHoY6OsQmTeico18dyDenGoNMb4vyP3A4H8AvtD5dC9ADtzlkIAEBAmUHNsmYxrDKtALbAhEPtHdL9Bw6xj5kcTk6GShdcCgG5fnTWFFYIVnEx14NR0P5FaxzSyVRRmcfO3qzNXq0fT8Vvyt3NpDd7pw9DNS23vJExE4PmZ6rNg8KD5rURqSH+DzSgf+/yDx9YoZd6dF94WgzCBKAS7U6JGFk8+UtvexztoIhG1nQdJQahpxDqayqz9MIPEfWh2jsYWtBzlSnxl6xLRTJqAUk2XyTmB5u1tLSmW91EavL7zi3bEBs/U7ATVWh5BAH9YD9W5eyHXug4kE2azpS+FmqoF4NkTdeZMxI1KSzMML8TL3E13tkMatLrSJPACDldBWFp6Er6jlV3RDE0c/IZOXGHFCb6870/P6oF3p+7dbhRNiOCgOuwB2iV3U4hV6lIr4XOQC7QtgqX4GM8DZKgECqAPvFJdyY3167HvXEt9cVL5qcPyO+NpHLdFCxq72oMC+DL3YFyZplR1Lu8FN9IBokVGxkc39FpKtrF1fY2RP9Fe6rEK7ap7/UF2MIVDMAbEAKMn1OwOEO5Ppw0KzleNzyNOKiaWd+w9TmwS35bVRXBHh3Z7I3rSdy8KHK0sZ7Zc0gwJuUc0h4sp0goBzG+XHOgiOlWn35cPskXT4G0rK4GCn/5q+YTz5j8qF6aHfLPzI5qblzcHIb+gETQ0LCkg+LQDq+nxgXh2WEB8D1NGmFrDKixSfa+wQe1czR5Opl3du7iTGBP+4n/VuBtLW9OqaZjgtetTEiRZWdtjbvY0zDTx2WhrDmxQBhMC8SQFRxOddjEsrpcNvQP4PzaqxLbXtB2aAOmEkSRBjbjrKEnL3nYyUwA4ny53xzS2h1kZ55C54s216QHR0ec7sP+Anp3qHXUSVvmT66Zx9QBYEvy7mFxL6G+SeNmtqZIsTmdMQdjhq1xreZFE700Yj7SKqdgDCquKFqwMdZQHHj2YaUnw1krIytBrzZCKgtldP06tZJDhsWZdW87nDbYvS/hYsWPwPoUegaX2G+XoKm3iW6BYDnan0gBhMLljTnMz7QdE48n55b6uuS6/ftl/aHoIOsocB3ukdavtDZ++PAWk1WFSLricoeI9KaF6xCNopagM3tgdga0b51J2gq7ePGC05IoQx5sGwEVLxvFeH1FZS6egLzwEsJaEO49qNpu1QVP1ZGnzu+kCIev0MU2w+zJI6aFWbWEgFUoaDqGl2wYw+Pzt2/02IxV/bdM1n7xaRmkggoKJSJBsBt67fVUXY0JNalLtLHx8l+u7mXHYTkj3NuoC+wp0180KRqA+lsKEvlkcI+w95W1ra1M+y7wAB020X9ts6IkFWpUHlqYT69vxvVxCAg4ICtXDJ034qOeuC7W8wH2EQW0zQXb8t45tmRR/qTH97Y6uQRruV+EWQCqNxKQlcXcpv1C5pzW1g074nPhK6MHfrFAXgZh76n03OpIl9zFXEreaF9Ef1ElxtWtfwteoVVRaxCDc8yOJHoL0REwD06aZRt6sw6XJiOn4tOShJ2lMTwH+uKQaU+YPTVSLg2zz6oZnpbyUXzwjDk1b35CtR0zSk6SSj5PTrHWAp/KdsR0zNRqsg28Jgj/Ft1gh9Go8+yi+I/II0SVhoeNDr2LeS4lnq3aCKf096+aX211hBTuYptd5BFiULow7sweKGU/Pbfp3zI7FU3gQt+j99UCVvrv5hbQkiVsDJpFtZh5HEUEj+mJywrRbl/l/N9KH11dGZbNfPnVT7rz1dXk9pJPVQ32l9BhzU6REHdd9H/dly7zzVAe+QZ+tsxNsgEalAxcvRkTBwk+MSuVFJzhCHhrK35K4dahMtO5JHgXgvXqo8I//QNyiCAUqoxTJhWQWUkH8J9AujcSqOhIoa9VU2psdoscqVoVNDzKrL+0aVU2RtZkDrkYcDn1XkTLIFKae0vkFYbPbqqQi7FraKvpGTOgatGayI6dnMlq37nrj/Jc9dV17PsHjfWbfm9AUsjyCbWm2B+dpnVRAGum+7KIqF3tDLgkRIHPBpWWYjLCiusZlH5uxPTp2IWc+uAR/KPqRJIxrKVkVTzQC8L421AaZZonFDa3boqutocgo5iahn5ic3So2ujQhvgV8KQ6ZXIl9Fbv8LvlcBoGSydBQ2siWUm8unbz0hoXNx/Ilvi3V+NkHNOqoRCJlChWV6f37zJZ2DU4bmAut8gXqSs2KdE1m5tbBSSzrSilTJ7hxaWNCCUduoE91X7osf4p0b9IQeGG6N4KZS8eCp/YdvjBpXdR4kb7gSyQxqoHS2SUNBgI7lqd+69fkvsH0vLYJY2McEh8BNvGIQQ/P8JAKz/ph56PSRfMy9E7iPpTN9RtgK7S22E6C3cRgYHn15/5jLRJZmR6qDdWlJfMIcMYtZpbWJlxNnG26NFiA6QAO4iWsNqAyrwXYWjbdDWlXMD0KCLiNgdBMCCIoajIpd5XVnKxrSVhbcDsuaGSj7BPiLYpqiFBuGVtsE/kiKxaTNbQb3Xcufd6773f79gCCjvueOZOP2aQWJXJoUEZNQENWMzJta+fNw/cJ/eAiRF1+zsYDiEHMRMUh9LJdNb2ZkqjR8CIAxUOmmFwrGtOoq1fEdhjfu+oQGqP3exJ5NZb2Rx66Y9F4vbtNQTzgnua5bqKyuY9AbMSpVhTMiUZt8+dK1c9TN1AsUnFazJGwZIs+HR8TO4CqZWXde6WcnYgRfUWVDiKi9MRRu7iieVFgUssqIh39fnRFGDla+N+T8JqmWI23opWYyVa60RRrc3LmANjGhBvrKuVkZP7yxSqkBZ9w7dvn1hViZonnBEDgDKE1iN8Dm2j8mKOmQMSMUPXVSSSJkspJyYH/8sL1WgU7EdBJHZjKGhHNI4cyWuvELNjLSf6joQze0Rc84H+y8tFLJZHuLye0YtzNe2x9Ixozp6uZGd7yskEQvfk5x99QJ68OrddX2LCftmvGcKnArVaJPfLZBxhJ3WXM+BM13euOSOQn9syn4s6gJi7mMbFiIp1BmgzUG6LfgRdj5o4VmDOq/JuZwZUvjPkEPGa0non859/3bA1CrElG1j67oDpvJ2GAXmnPnihUEeHmIpIccBD6nEmKYzNxVbJEid081xyR6dp3BWS4RS+fXNte3jDOrQPPGBc+Mq6YSFNRQsTqbEtB38S4gXXQrhjp6+aox1SvtJlTtyHnkl7QdBQIuFJppv8YkvADvEXv+9vq3Pm4YyP9b00XlUm6pq8fzg2aV1S42a41u3OSsXEKCkDFOHuKEOCjejxixflYdQHE1gfddwtRroIQNJoEELEMBENlNHAEoc0go2Hae+Zdf1y2hPGY081NtuB6CO86D2E0XSyPk/A6tlNhrG71KXINnFODimhiwqFUWleOo4Zm9QEIgn7wkxKpEZlWYYWa/TA73/gpMwzt02HhHLjl8/JZaUZ88hJCZpaL4ivlHTzGum8fjmJl7KtGfBfeUW8lEC0TOKa2Nf5GDrfJvxAG/C0HXvky72eNKEDTJHtdNgPrrcMyTV8xfCEqa+W957uNh97wC6II4Y6IV1IeILed7vGry1XSZOpGU0msU9pTZrbdFB3hbOqgEQapLLsYfs/uYyHU2XJw6T+DJ9J4G/3LjksIstpyg51SwyXJnxTu48RaOr2Z+dNnYK6w3vFxbPO7XS2yc4R+2X7vNNrXtw2LSJw4nQHZ5w5mXxdTrapWRQpgwgDUWvrDOJZIUraiqaSZYS6ybggYyxom0Bk2xG8Yt9uWaFnNTMcwnzLdbnKHOpAMZpuy94L5kShfAU1hPCQGcK9porqySZpOUcd6Ya34BgmL0BY53v0/3ULxBXalulrYBBkg18g7Tctve1PQMs4/njXVmCFcYOBplb3H/1XYeOHDpnO+3KDduZ6ZVUj2FdlrC13goBW8txFayLZ1BsGQC4g+roGBkIccF0g3KCcnCcOCbPGFgXVWfiIcUaxw2DWYmLohdVYeIodvDoYCafZlpNy1aGKrIKAa2rSapp85pyvOFPdMAINgDamOSh3oalgb9VVMiww/t7+jIdAJ49WEixhs70jJxPjE3/8jcoyea9kAr3e7WTlOXgk1FYtERYrJOhZHDPCZOi0AAtil3MwyZDHu3xxIK/ZGdYbvLZe3+Jz5gbwtJzIww/Ja9E5xSMGX00NgNz3AaSg1qkkSwQcK8nnQihFJF0NiHn5gtndILPEbZhV/KNVWaYLHS2QfF1WA6AeYD/6YkHOyNy83NsMwCHYaFF/B4GxllsUPrYfQs3l51cGxXsX9/qll2UsxXbTyMha7+TcqDAnYIC494rujRUqJY2vX0wkbgBti85CqakqTq5vYa5tBW7e9oXkyUr4OarWxdmgtnCBwjSDD0bd8HYgVbRaurs/CsrMkmapsXulsHMCAlEpQMNsTAkD8514L5bgZNgfogGoj60QS0JaSFqrv7/7D8zDXU16wt5L1Ay60mcOdKbmhqTKREBqoyZSmSuLEvmcoQQ8u65sNzkl8+UdIM3OBJMy9H1dHnCHMXD9Wf4gZx2WMzjgHpyo4WE54XLfPLfUfIwYpRr3eJyRhfimtGtuDcsjVgSzQvRIPL7WK6vNIdDyUsbskqIj0Vq89+duW0DV3t1ebP7DX5mjUbkaGIfmBWFbMIG/VMZuuyoEg4Py45h2z6c/JjEwfrdOOWu4F/rjjO1AdDqOih1leo08B0GBJh9Sm4MN+I0vm98khbkx9U0TWYURwmbWuSduF+gkkYJI9cqlQdnW9sBByqFju5klszK1aeszPiU1RMdCzOGWFUKYCJJaQInEys2ZZFzqiqdOBSxGRDOP9qx/+cWMHV7/jQNu96428Z94eNtOqsTyX8rurU0NSmTOv5bgkFoh7YQJIDAZD0F/Xb0gHFy1NFGYm7TiwcivBUP8vrwkqpB6cj1UU2ey2b0HNcZmVifz83bXWaOT/vt/cKcTA28uZPgBGxxIpBKpzDhSb3wXpqfms6or05cvyVc8+CAIz+VtilKWj1nfcN9/Qso3elNxNntP9V8UeX3tZfOnr7p+96e6KK9u99U0+3NbRXt4kiNovECug/h7ByXVkO6aJksz94XNmT4B9BDIsqHSmQP5qFs8JeuMoKbZVohAp36EuTgnI2A21g6M/sqMeabUkD4KWpkw88umNSplMkiNTps69CWhtT3SpQxDyfwWNGa36dzrhNthLbrSwj6ALFiBjz37HanQgb2ZgsrA/Jj0S15uhjnJjz7FDHIFpKuZ4lhsW3tZrH5ie3NF+ovpCnnR8PbyZmJDDrHFdERTI0UJF23JInMpA7L53RdwJy9c4dD7zEddtdHc1+AkYoCBLPQRiMTODFxZCblifrvONR3PyYndvC5Pbt2zLHsXLCyQD5dD7N+pPxs5eFScAb/Zopf8aucYmOweMOxNhZ6FKsmsSHZncTqkbXGib1yKhdkeRyd5MuQCvof4IgyMvYyxRybAQ4AuiHTtL7/s4HW2pX6iRKdKuvSCLUlaJeYXFNU9QDo+644ylMRINQ+fUZtTWpb+xjeciYW0AwC9+3W5paLKxYxucLkNewHMBodNgcI18uci49QKAAcRt8MBS2oWfmw/Ym5DDHtP/L/svXdw3Vd253lewgPwkHPGA0ASzGCmGCRSuSW3Oqu73fZ43JO8nhqvxzs1O7vr2tpa/7Oznp31eLwzXo/HM+223cnqdke1uiW1ssRMggkgCQIPGUSODy+//Zxzf1DLVjBVW1tW1fKUBP5+75duOOF7zr333EhVY8ELzyw8/kmtfLitvrZobuaSNldZuWWit6jn1O04YsWD7m0wAP6JM6h8Bf3P9r7OZHzsQZW4N87qR9u2xEp5ZosGYnKnzy4v5U99e6KzQ1ny8qWcZlDboccVZaRUX8sTKMKYxVZpgUhlYZEt16xZSTQ3rzkTSO/TTjSbGx4j9n1rIz6CsMOHKS21jhZT2c4gmXX09GeXZdeMFzIgN0YVi7KK1UZCBRnZT7Ob94In2c1YmWIMhT5UKjgi/86a7tcqlCfP9uqlMb+caJYLoDy2hWmXgZhcZrDT+hop4FVuUtD3r8sv2QbRrrlw22iD64AUdTs1af6ayodsrheGgWkCRck0UV6PGw2mgrqYCgSzQbBBJ6FxQIRdQhyO6c/36G5bwATibm9++z4k3HnIb9E16CW7YAL99i3egQNqXHr2CpymmmHbnglmZ0Uqw5GAshezW4t2dSlgAiZeHorUFcn+AxxXHN+JRE0Mpx16Q6yiUS9f68ULsGaCZEryyMPcCXOP9c7bnoVq625suBmAxe9OySa/1Js+aWgOqN+PlkPkd+8D2UXmQYAkNlzSpfa5HJ+A+uY0vaHKHtwuEsNgEZwd1dMeW57M3FpohNFs/fc9qEp1pg4UQ48/LiX7tyibQt/9Lupp+up0wbK2emiMXL2p7Ng5jgvODkxOB1uac+fP6ZdPPhJQc+WsCyscMOInT/I7JtKXvIWQT15Q3ffWi9k//FHwt3/xPMfZQLgsFG/fpoK9uBiv2HA/OP0IErrEgepgXrZ2qdJmY0ioo1MVlE18EXbMuXJdPvaoBzwIvWGVgGRQYFVy5V4sj816moplbF7HbSAAPfrD2l4n1GHM3IcA8QPzNveeeQTQk0+iUyKnT+kxn8R64aw4EzlXO3LjUnQLYQTNOE04iWk60InH0tLQjuHPWXSYIdUffn1lV48Zv0RWg5N6lw78Wmfbif1BOkwLSidmsVKusd9mgV6IloiPBbx2DyzHg3dJUXOluJlURiDVjLHx4MU1cm9Y8FaKJlV7g5zK7I311iwP2jGtwccvKONr++CSwdpq5t9FFKmWDV3t9y9YBNZZ8LKwGjhgM0RAuaw68KNvxZ94QtuhtNwfbc+98opeQicTZnXDyaAF9gvh0yaI7zGYxv0t+pCm9+hLScIMyoGrw6WMe9pcp/y5C4m13KvfmauvUwG5cDaLJXKItMqXArck2fSJ7l4I+H35knCqk7ZGxEJSAGKxolIRuMJsi166R3fTAo5v7+ZOvad3VA5ZN+JF4KjQ+gS/IRAbvyBlEGFvuq0OYGeuBXiFOIpzt159RUW6s0svtUd1ElZQZVAO85TObvNWysBMoPzMshoPTZ1cGu47s/oLv6YfLuwhgWDx4uvq1ZdUheIDs8VFVziW7q3Azx/+QD75ST2jAKCiTcfqOD6ymR15bftxoAc0P+9LrI+P6SGFB9i5FOHYlZmpbCsbRG7VS8GudgWnhLJhMvALUXMX0xsaGu5bb+/0R8hvwG0WHQAwQZSfmTyIhANVF99MHL5PE4dAmyzXtgu0oe1JtbyYk0OqyXU9/b+7JZ+w48d+OaRbtY+pLfqLfzv1uad1k65G8u9AmSzeyI4d2Fnxrd0pnpd/811vpfsL4/r+7BlVSs3RUDnr+tGjUM/uptIamZ9kJjBnW7dKVSLvW1/juDaSkniODaP0Ns0YoSDPcLh0siPwbU0GCNE5KfyXjTz1tCpg1822Kp/XJHUMqkAoUFogENRph9CxWp2OyJ0Q7lYrH69nuzU9za/IxLQ3e5NnaUHXPuhWTqmsc6o/+6gqF4fRAfFgYl4O8Qs3tHcku7er/g8Es4GCQM0+VJxUjU/pVlqZ9PqA6rqrl7IHD/ivXtGO4c3kUBkd1v4qKc017ysqDOf/9N8rpPnMZ7SHnScMNi3a2DsY1Y9HFCguzNvcBg2/VZZ6LghDJYNDOofM1bCxsX5b5fqUgpvSCj+z0M+F0AAAQABJREFUGd3wiPqm+OcMyowojqbYW9vWYihsZrb3KNMTXYZ+wHham+pQWgC6PaDRR+d7w0UIwr59WSdWyBEaGTsKEZigTfqNh4sCEvZJPCubonqJD+HouttalzSehSq3tMn6u8Y1LZpVUFE8c2WJSkDAL0SAArjGx2tmANAtogO69fXJ2Qk1fL/1eRpEXnxJdu3Qp/oG5MWE/HKzHhMIvnhRHSTHG6iF/LpmDYGIb/IGFgBDRS2F63eW9+7OOQkJ+P2BrtbNIb0vv7BUUh/pO6fM2dkdqKwLTo+mHEogjTxhHfwxiFAF/LCXxPLOhbCdiBmPhVZmkqXIcKHKG9FTvPcXTiV/MaKXWBpKGzqpLCAkW9TgQ1Dpr8ACO0hOxeLNHWqulxdSNIJrbdyxrk718eAKiAgRTYfkQkgBAMMhN3qB/47v9qb8FZaoLLjxqExczpAYJihRe0NtuWyrkTITCpBwJuVFE/zVetBUI3sAs+aWEyRKaLhGoQPiY3Ijr7NGIitkeHMvL7M901388UCznL8g/WnN0Q/tVWkQtJcjZoJsM42NRBNN4NTZ+N5LGhiqtg85F86tbGXAhDwZtIN7OcOt9+j/ZQuotFsUHGa09hbVCO8i527x14zJuy5v/ABog4BCwY21H1kmfGcC5AP8wr/QXi/ay4rfosU3rnFcUleYHJgLuw7GL1pdgXWRIAh+Roii3cr5lftbFBnDys5Ezs4W+pMO/02uabTeOEvxdyP5evHo7tM3hLpa1dCY5xPsVhOpGeShvv4ffGXu6L40BhEiYU+1/quEFt8Dc7Is1irZR/J5skGZiSxMqE+lJv9dRJtgEbus7eob8RKKdYNecuL/xcxjHw8RoiprU+3gz6ZvDSW7tul9/rXpssX0//E1OR7lTF7+qm/zFn/2zBTHTe0h3Vh2w0SWlDGNfnpxXm3uju1Stpjxr2tXFBfFfVm24lPji2VkLgtTQy5y8pEkmrPJCnYmK1smtYujUT2nS+mEnv1aCzZNiq+qtsFwQ89ekPs3e54YxgVdN2pGH7tIRuLmIvmOdQb9dceLvXiDe8Y+KE/pbLfoj1P6aiLL5PgJfbXPbBUhK2dZGxrb91beubXIFWYsMRXo2HG9K72aCoEbWlt9pmsoc8+2dO9ZtctMtcC6EgSAMFnabe8gFKpZS/PEVqWzzZvgQDfFVj1P7IOF6B0v00MkVC0cloLNJzFezDiiPasyLEjBpECUqYZSESPWM9XJDxLHt+PHLbNIzJ7/Bayr/WdX/uYf+BIoZBZAvRTAjBMQ2o+FGMBmCPMxO53r7szGFVCoRa7vKD5qaAxbQKQMEAhhpFiPPTDqpQwxM66/v5Oc0NH7s1mptrexHuznJnIugyl55q3Mx3v0IdAOfeUQV2XdvK8gzCAHv1dnFghoMgk3axVkqI1NYc0Mal1AfyqH9+iuW8Bg7F3fvTPihZkRJedXOE1OABumcRgoih8VUfwNEcbgNlx251YB+JAiGBqanND/HJNtRWAsM4EDfOA2hH/ShAz+K0kstT65u2S38SMu2uhYpFpFnk8vxfMLb2EFpGZsNtzVfPSoF41GdHmJ2xurGk8O0MSMMQdjE+uRUv+q5bx+9bwwLdEFqpnE9VxMTtSTtk6Lp4YHrORUCdjt3FknefMTifxKfvKm3w3Qu9UfbvUXVQPSIQk0DoQLygtcsBw2ZYDI4XNGEpJZ6SyWm8N62xbWoxd7I2yq1/FHTQoffJic8Dnc1GI3XBPt2NmVKB7u5xE2skgksp0bSQJo6pdeYtxDtWNyZv3mSHKLa8f7j4ePEDYp3/4Lai79S/OXXlkqsbyfLzyfOXxk9WafFpRm5CsU71tqoOUz3dI4L2XoA5Pq8kLV3Tdn9bTMskW7nh1mycqEHLZeRoPjofVsli3dehuY+NtX5WPWXWcmZM42Tf6DG3rpMxGNltUasgRDgyx6B/V3OAc3A1ZxBecvvzifgc8xkAJIhkD/6Ijv/VXus583Z6WmjpRwBc5TWZrx+9NzU5nZGdXXANPFWR+LgyH0u8+XQ6FA5Pllul4+kTp+XE+pGta377I+QleTg4eoAUQn0iD1S4kwO25BrD2nU5wjBRymm2PDbmoKbwwVBrxUGXM+7nU6FFwboqzZbHD3Nn6MxJMF/YNYNb1BctR03z49rpmV9Tl54ao8slNPEQe6w5YYqO8KJECU3Cm8BP+4QR43QGGT4eXsqpxgh9N2XT4HAaZhdjeJg35xrOj+cko4+FNfUMAWrKvkzW//jiqvqdZ5pBBOK0LHiCJEmyBTW80Mv/iiPPKIdG/RG6AcufUMtHHMVE2wOwEO6gW9+SZRD11pBuG4qoxow6jxLyher2NFnDNifL6iImL8lCOWXlra2qWvDpcE4/MJKoIEQcTIZ2a81YNUnNsVFprVgk8YJGxp1tuKWVJ36XpoDzZRSjrrBr4/fZBFnlYLGo0pvlE3nBQp+fXfGfvDf4n1lMlYun1bsJodLm1GasifoYmcu+XWLXPqdBp/Ce81qI+mvh/yMmMSwSwjdBpFuhDTSyd26f2u2LRhw4yW3LZkV1DauMPcXZihRFWf1VtrN7eqm33vrdI30CkMnW02JiwcFWbV7jBtyQjVEDON6+U587E/G5Ezt2S3eVY0xeSAkJCFBWvQAMu6yr30g3wCHmSyItQ3KWz8TjFcL8P5yNeUaar6nLwek4z1EfCbmT5sou68MmztPfpQLQAWfJtwZeg9U0IqLNDo29fedXCXANEYX4EOr3IuMQGj0opk7aN7dFALgoeGhyN12uvBQH5lNTd/Wj8bvjFbFS1FQgGREFYYaXKL4+vYQpC4F1rAoaqlJdgDPQX1pmSScIMeqt8FhntN5O87E4niRVsxagShLk+fchE75vE2V2UZXUFNQiC9t9sERQKICwM6nP5ma8GITJtuxz5Qtfd0t8CpfLrYGmhlOVeKPPNdPLcjhRIKVFcnA4xxQB0d7V0r4aGrelwYrk4sbKr0tLEvn3/phezRo0BEyRYTgUzWOUtz//HAviYZu9X+CdU8gYWZsjMTEdvNfOB6Cg18/oIKwJ/elB05rx85/QgSutZEWRirADTTG489psWsqg2gxENM00eZzy1hlbgKw0D+Je1w7WjGapaFvU9dC48QgFvViT+79Yp6L+hXeACi+wIbwyZYAZL7glbKXUuS5ouhfKw4FK6UxnWdaOqgVTIB6ojb/rzoH/Sbi7Fm0vmQzUT1Yddh2+W1SF+/C7FhO4htfdE463bK28xX32xEZWAJiLIxxZrp9OhhCJWFuFmFPpwnQB8bPyoAePE1b2IOxlehkXktjWsSs0yAxqraCGjrw/pNaQvJZmYUmZ4cpw3tx/f7QzGjdu0N1MKaxkkhjBTC6OJ6wQJMZY5fHLykHSIl4dZ2RWNrazlsijMuRMEKVmVow8fus3f+jT9mN7Q1iGawWhjiE5ne68EeNZGsKp96cfpg1Hsh6Lev3wM/vmDwm38w/YUva1WGYzqEAI7CkEHwD0UKUX/AWPZ9p03q5Xv0Xi2gauvu6UJCHjT+A1Vgy4EaTqXSB7gkVy7rm5Dh++7zfkfzg06Z5gTkhQitDazI43v0mOEiIJqbAQXEwRv68YgUG9d+6ZgmMHXqvqwqFNyzK0jYwWXUGkuS0v0//6kCwM8+lCcOxT5VHF97c2lfebj9cEPOvDRwEsXwv6keW8fioq+dnG7ZxVe1fP19BNdzbrRkk4XnHFwHfHxin07pcLGfOqZ0A6wcSEc/+QNrM2oLAj4dsRgdzTk/CkY8168zuCBG54E+bCUUtOQNtU2B1YUsiZ4hQomjJJbReIFGx9FLUBlygJzHZXhedtTqMbs0dvn7fZXqGbQcbcVqln/yhLQb6iwuriAFfb/iWd/iYnXL8heaVn22HmludA2kS32ht87IF59Ouohj/Js/KH78AVahlboPp5K7jmUDtqXL3lzvndtzTtVSue+dlk72tcMwmt1MxeWHpryfYL1KrWqxdYPOp+bl5bgcMzl+cq9KL1OkIF5/7IAUBLzxPzr95GYhlxrkT8gTu6W7RX6zW09ZhvtAWjqMhWhaRavWCMD651+Rw/ZObmNoBcZoj+oj8AacVmnHcB0OCbYkznJgFOvqyl/+lxXaE6oqTOnwWmm+0BLQZdbTxTVFxc2qe32+BXCJW/zDzRfeWN+9U3eqhbArVc2BaFRZ6Ctfk2iT56jwO7UIVZV4cBs3eHLSrf7SVX0wPezyNm4NBEPkWyR2FVsmLFffrd0X6GJP4gDQxnfgIKdBdlRLrJdkJjlGY0UqQp3sC0mPD+jYflNKZsb0CmAo2uVvwL7pYEuOkEGoqbahQo1l7MJcLOZghvqfWKwOq8J4v+rr2IgUaV01eKkOg/UXKapYvfP6KTmENIn8+DW5fy/WTq9l7swx8OU8kKKi7LPPSv392rAQNaOVnFrnVaj4xjb1Wqo35fNTk+TV0Pezf8hR2bUma8YzdB8cTiM5bcDID/lInHOK+SSq7neTLUMhAmz/+ru+f/6olqGuMd7/Vze7ospDYdDC2mrK9k+dWsoy1xeXZszapBesoxstcpfs2KkWnOEyM9Aay2C2G9EciDG6stbA4hvXOa5oLn7s1ztLw+mIBa3DFYWdq4mRIW3Gzsrkr/+jqDDJFp6pyL76k/XeIf9927QMTBxGft2gHJwJh0Sjnl8H18HtztcFLmCJnQjfuqnMCWZgUYQjWNS5o85V9ic9QMNw2akrYkBOMQncSHNBuFuprMwwpKjsIMnrkgvozuAQ3XosK32mQHawdJnN0Gbk0Xa9xFd4FekNIfaXo0g3Up5mriKr58aO84g2/1EpiClGxLZfn5Jd1n0IF7azBNRAnHVElhLeAoCX1uSTtoDzW/byh+1mvekeffgWQClEsXr2YIVhxDsf/iV/4wnnkMAgjx8iE7peZN5Wwb6dgUZMpGGisfH42at/8l/URH764TydHjJ7NDqY3iXryLWzFIj/6WsSLlLgejh3PbyZxcrJpZcvcfrS85mKQhlR30SnP00Ds/RQISas1GGLQjmtf2W4nQgEggqhOwLBzDRuEYtzcgx3Y997edIG4q7ov0rLSL3mS3BnqmOBDc+pLOrLufp+hN508BGMsSs8WhpVE1J3uIPKBB552Ntyrrg4QrLUQdOei4vh1oWPNy37LGyQHJlisM55p6imz30p5UykfPOb8viT0tpe7EwkKcuPJQKZVV7eXHj+4o+n1vRQGojxoYH18CNKcJpaHeMxrAZ6GL2kp+u573xrlVkadqy6CLRjQ/sa2aT90dvQ+i0ZYrsdPVSP+gUS8+S9F8JSwBY1ALagCwfB2ld+mJKjrB4sI2Pjml7DZNKXBkikpV23YKcETpky8FVYVNWgHbi4mD5wQJq3qkoqQCUxsnmjX1PUYyLL4vnEWtcCLok+StkegNWYwocj/g5C0R5iAq2VlRE29sZg2g76GWI5NHvYmI/mBQje8dwHHVIyx3t/mJT/pQHAoDcjJtgXF8tjHf33z8mj4FV1fLBWmksWjxLC5yRvl0MXc3G53Kdp9N+PcOqG7RrFH7CtkzkDR9AjYGmI9L9Yvf/5kvyPW/SU1/ZeW2lvtr5Uj8uzsEODMrum436U5P3IzIt8V+SX6DKFjWqYAr7c0ltqIsvrix74Uksws748OMcpcALP+aJKv1TXpe//OMNa8xxj9V5/Xa5OiGEQlXXK6ZZb15B0w7jOfUifvEd/WwsE/7Yb/tr1rRup2ugGDDkS6/wRbkLQ4E4I1if87IjZUNGodpiLlYLA9pZ7SYqZqQeSc7qa9+B61cRl2fQ6EVnxSe3BDl7iI+WAzz/4l+dXFxUStTVnB6+t379bX880PPq+xMJ4FXA6s6TW1r/3Pb1EqB614pJpro0nSwJjOEsRGw7Y3LwOY4FKoV3b1Bt08GhiUg7uUtYnTA5FKoIa/B+Kcbx0bay8toCwEIRjA6RGsRg3ar4QsBHr1iBCIyiWYGGIzW059fl9/oHh873qGOxjPn2RFzrkE4BsAieX1SDKEaBb0hv9w78bvr5W36qFK3r0ODMkg8y1xY2jDF//UfkvP+U7eFCfmZoMXblS01K//spZzkr2Ve8cnnOgikRnqNo3f6gidHhfWkepURu0NZRMki9CIqqW6/Y0TlyZc52CavMvy2sL0uEMGi8skWV9gTzLwvoVGZ7TmQMQC6GvrmreC6i5Sut+86YeM/yyeZMk83Lpmp42VOvQzdlzeszHWK/FUBg2AFomaX6ht7aWBgFrWr5JNdYk16YLHDtxCQTptN7vjMlT7P/To48TjuWGY59pKK6wss5MLI1nlyf0UrpV2Ykc/X6bCfDjF+SpTybD+Euojxp13t54Q29jm8WuLp/Pl3d11wkz/pRt3CXsvzLGzo/2YpBueaU/MRcvLl3Ux3BB0un1i/0cFg0PL87lKg5v8ZZboREBvxYVdtHecJvpNmJuly7qRksWiCVM5K+ujLgFWzNTicUEFYTwr1xlF+279EXInwsYxmVFH35FzX1lxbadTJSFaNnVn/5Un2LCxaGwt3X4w3t1E4WFJS9MgO9BK8VieluZGdQ9O1UWoFxc/SiXjzKwwrKldMbm9JBD/+ix7O8/K7/2kN5GM9LINkVIentVxh8oX+D3porQ4JDcnpaT+/U2qoVH/eK4Hj9qOaiQKYf3MOGwEHwOoShA/xFmPnEc8l+5lP3YNqlkQbcKSK6xdHXBuo8GTqbjRbYWxXU930VOoZqNvaf1DaSQLtW/rnjc6QCE3ra9zt9YGckrxJsfWGjcHclNzPoQH4BaKjU2ntiyWTEHS7F3t/tkSY0yzbK2nC3JZyetFhVlmqG4pkalj7nJ4QIVdufMo5FoFjebmDFy+taEUmEBTv6r1+V4t76bFni76dCBeKGjOMbWs0RkbrPhW73eRmVpPccA3BMHGwFO9LNyJ6WRSMf5/G2CpTv19zBJa9blcK0Oi+lpDUlx3C5uujaMiuxKyYSBbcrJxEvaHIKN+YoLMTNon2cjS8KTxgykp+KFDnj5GiVMSMUKEFiQooAGv3ZZsSnePfpQLYBYW8upi1Jq/+2059FE6FTnLH3AC+ntChtG4B5VN+8iMxoKdFpLZQdpMNBIm9GtmeFnzi0wbYhFep25watr9++xJ9kaG2E0E1lYGM+n00jl5St66eaatBWg8RTJ7ZpaDodixLAiQX1Dd7veZg/J7JLq8Fl9QoP6GLotBR66rS1nZmFc+tSFTMfGQ7UVczP6tgsXNRzOZOkXjKNQZtRa5Y2iojcwCuXeol8GxgZvSwoljMwiF/rvexM4FdsKIRS9pxPHyxUL6v6Hu3u8PE6c/uUz8vTTsg00DjKd8l25XNnaLK+8wln2QEfP2JCDJQzXE9bpZ7NIZtmhRkdjcoeR3yZ9KpMJZ8mDrhLCCHkBNt+MPudrGDK94yNKtKqaOuwywZpW6dzkd8Ob69OrY4NptnaE2Oic1kNhYq+g5yfkkUbPT2BXQEBGn/6s/nBLXme0mqepM/o2gR3sEn/QofAn9GSzoi9mvjXoagEjsq0wpxyKxZLTy+Eje3XBK4Q9SKfdDD26gOnehSTwgVBJmEhMoDPAE+O+iooq49vM4ChjsKavvfl7er8RMgW7u4E4AnkgB6BFwLbHTKdTsyvCjvDQ2wV2T33wXz7kvjVCoapU1UP4j5QWXQ3xy9Ob5aXbss9Mc3WFBrlux/TSdeDTjJw0vyfEdizGKnrhfcjaXlkdmfIUBXs6sxOjoQbsAhMxHiv13GCGMQqDGTd2h7oGcjseph+RL4Tfve09P6WGEL/UZjA6K1YXLfZVVUZyi/w+1b/QwCKIyZXiFpUrEtgxQ6rDbE0unW1qSudZ7mJWfnJSFscl4eNMoTLOrbPLrWMq1+i0e3T3LYCcfgj6jV8rDjL2YRmJ8BkIF+3cpY+3tPpZL+FCzoR1QbcOTOzbr9ho6zZ5+SW9bc9eBcTLtmsqs7ZAJ/A0xN9rLAQqkSI7JQLHOL5bZSQja8PX46mZ1ZlxvXN9WlOoNzylKjVXVaOoJaMsF46NrFyJTY1nXBidCIHCQWORzi6kszhcFwoyt5goWnBCxuIAfQjQRpAPYAdhOGBr4MUXntPTP5d49Uo/04s4nh9PZlaCDj5u2aI14inKD4G6Qqu65AZiTA9dNj6YvPqTO5w+9JCEigKH9qu8EncBE7uhPMI2BLbRidtNRG8Z1xKkh7q3aGEKWMkB8eqpyeHv9wZ8qgrqfXd00MetZ8c3ZUVOfV1BFeZPAkUFh/et+81rLGCi4tR0UUxlLVC4Pv7Ta6Riz4Wvc1oeIbhBlvFqjlmMgpJy7jFivG+7FMYU20GMa4+v6NRkCCmlQSILcsf0NdPmV5gZqG6vzhR4e3kV7Yyri4ndbqATVU0T7TW9SXa1K1f0Q26kAmeABnTo//dOydNsBYyaxw1blokpWWIBklZIOw43GHcO+i2Soyx6fHLoEEl7yphDKiG9LxnPtke9RVCxmKrds6dyjQ3aXPjb589k27oU8pcX61gEagKi2Hfu5HgP7AHRFyOxHCobAgQwB88pJvqROFO4utjTgjjes7NJS7ZRVBpiQiuAdOqGqq2GE7woPzWkTMgeHUDnvd1ml1GfKGks21VDN7x9YT5grjwp8sZG8652L1+V+7fpXS/HeIG2DAzgwoWUhLi19ocx63B/AnAM7oee6JFOllpYXIB426tnpbPR2ymbpkYM9UFbHokwIgTXtf91ZdrzP5Otjynb+Roa6gIjD/2ets9rv1XU1LT6pZMe+C5qKMstLOPVQLTPn7/B6KWiRH8gSaS8p1teMBu6q1zN7VP79DZ2LsDxQECcoeq9rF7rpGni3Vula2vIx0gKSeHPzO98oFJtmO2Nls1LRZU/5VPxe+W5xJbuHKwI4So/+ag2grNA/KUNXJz0d34gv7hV93H+ekzv/GK7rjr73ot6/K8+X8/ng7biZGYyLf6JymLCGNbN6TQGHd8Jqqhd8y/HUgll6FBOeYb3Oy3U3OYnvYdm3wGHFaRBAlyFryDaAeDlfI8XX5f6jcyr0ajK8qY6bw4zH38rJ18yzYB7v32H9LAFlra3ViEUlmcn9Tjfr4LoHH5YnbIxuMToAhRkb7QRT1i4B2M/boCvu11lJL+qSzshnoVVcAihxk06a4Al7yQsgegFIPL2zXqMuz6bkOdUA8kvr8g8eyqgAC1cgiE/NSc91uCjGWkmZajhtSNVsm2zftdtP+HiA/r8Pbq7FkD7qAIyordhJqdLSa8zteytQgFpTWzc4/5FXvkRus8eccgeHo2BhOz3t/9Yx0qNX/son1BUSdq3yYlceml9wRDWjSV1s2ueOsIlTCRM5Exk3Y3bU6eHX3vNQ9tX1uV2Rk5aOdQwFRaFA9lAKapNNqXHL/eK28sKobGgh34ffYcPOZeRc9f0tKYu1+K/HsprARNLycjy+gWwua2AAhig03bqmdYLi2G8qeMScBzI4VRML53cpurOEITcsvfrr+9Dl80GHVpRB9JbeUVDj40t/uA1YvY8xBIBOXdGSrjMie26QZDD7F2gqGjb3kWfM5H+NLkZOoassYrTaz99k4yyarmhAtX7nmKdvoM2cwrtMhtdUGy94yNK9JFZAzm0U01YwJ8rLNA2WWAWNMPacS02CV2ZpbIKFCnRU2aaPD8qm60ZAkllVFMMmpOwzxLoqUkzP5nefpul6ze6MqopkGXTVnLdGqIgCjV9Z31FwUFROBwiyBQbXrul7BU5tJ0XYPI4JvaLHms7Ch+h7AJqQlBz1/kgXVYq68uAGQ7Zx4KXu6Ey01563RG1GqUMVqMapgXtkHBpaNZmRYOPmIzTZO4WAoXqN935t2cpRE4VsRHVZf3LLXnqKT0ON1X3+OZ+/2t6/MWHZWejhherzZ5giLFH9QbTEjPyoyxpWvQ2aoWlpRkNUOgv70fciazQ5tCmZQ1Pu0hlLKYwEt3uTjFfmB7HhD/5iRpoNyfiMnswIt0bPjbvsQb9a18zpKCuKSrgAsViPPwfV4Ny1m5qXVl2kc8t+HIZ9jvgFHtIPzidz3Zcwenl5LryD9JAt7D/mJtbRmtj6AEV0EFeMqZjoW/rB/31Hn1gCxj7fOAd77xYX5GchjdpaFs7jmlHoUGFtSXp5PLz1qnsiYUlcHFT9D530j2MIEN03rnTOZwFCHECgjhOwvZv3yLlzMQznQHUZsS/wZIbppO5mencquMd0bha4+66YAtSjxwX6xIay0Pqy2bX3xogP56bKcFaMkwIqhwaGpTd+4qDDMeY1rl9PXn5ojdvCpOAa+eQ3OUJXZsB4LvPXL5Cf9q3li4CcAOpH9waKCnu3q/8VxTO5qdmdq9PuZkJqBDcDFdZXg94OvVWtoZxOqzgHSYQ+twu4HDwxZg0WHmAO6Bh1Pua4VFmIu1q1CFpCOmiSAEmoUHXrk1eX6it9BHy4SzkK+/9et/ohF7afzhYUh4o7enwjYzrndHWUp50OrW2LtQdLawp5ef0qfPVNUUzg6sDA2uc4uDVNvhnLmr12Gd2ctyLoDDNiTGAK1fFzfynBQpwe8q4S9P+IN7Pp3TtK7QrL4eZZmZtT63xBx2apcw0NQqCPoXoVvC9m40WjWo0a4qJeNokutzJbYjM8cO28xgtBvF3nRXVOM92ysuJqZBpAGLGAq6KC+rgm82OxhnnbO1URZphgdairm+G0FAU40a/58bQ+3RK7JZqIeZu0cVqpG21A0Ph9J2bDPa1l+VzR73hTTwZ1kehsiECAZ/4hBSTQ925g5YJriRkrF8QIoaWmF+vJOUXhCdWVbXE6BLuFm4g/ejYDhmgKXGPYW6IU+IEpkQT61mkBtmBju3SWWRUtkMZTe/ig2g0iDJUVvsJfI2wdS4wZSWfKZNPf1ovUfgb/dosUEW9akMwulOCuI6nT3sLw1CgOHW80/lOmDYGbbStoVAo1Fj7r59SxmD4o6C1YU/ZyqTxSWltcmnda3A2OP6l4hzzXaGXT+e62+TmmMybgIwB19ihu0Uv+ZtV3AhAuA8x/Rz0X6tsq2N3BB3y5LgkWn81/WgbGyaSO1PbJJ6XmmgkbF27fUeCwKgz3CWWSgvD02tN9PRhHStzpT4Slz87r1tU7dV3awuwuGiHuTfKdpESH8OJDEEPzFSUJ9MhWezVLstlczA/bj+Ujmfya7pKGKJBNvcU468T2+MU0La8KNVbsSBs8jOXy+XoSdf/SCuc5gaQ4f8VUq9h8220jb+JJUmb4lK1M+tNtuSLLGeAnNPIG6oq5KRJNul/zk170zNK/Rq2AKQ4vHdxQlqKvKVuCBdts2JdBGtRAOCiY2P2mKDupP6C6E6Eay7hPdVWJEzbuWjYcHOjNBYJgxBQTV4Cy5qEw/mWKNK9WU06AAWYh1nguWF4ucMxibKG0LCA8Yrec4/usgWIEb0NENHCYdSz8UZDlSSXPVSnymKDUCKNhpVNknRCF1zDU45gDAs6KbRy1GH/sNjv2YsInX4qn1+jT9HGbmQeMazZ3bhhIkvUF7eViIGWxswbw3D+hXV9RZSvpEmDpsfow4ZIcQDPxCbPjY5ofNBNvkDPvu3vIcPgyNdz8in+sYLF76w0dKupCO/cHCgpPNiqrFYRXq/tH1pYyDbc1ttwt2gHhzMQaGr09QU5ZErxTpUuynUVpF5Devt7EyJeYI+golGMxvUsLLu0ODAXaSj1MTCtvxUOf/P00KjK2P7DIRIX6YrPUQPC7e1FaCVnhOrr/d2bymoq9ZFTp8K1petDY4ThoOq6IJMVxie0RMl4+o9+JvvtxRTs7R7R+z56RKuaD6V6EuNLYGhHXt0lNsLA/myi+ZjsUC4jY3J6XieBQ/RLc1KumXKIvsPXhTsmrH0Nkuj6HLtFH4H40EV3MCpbu+0DTkVi0lLJgslpvRgMZSdmsjPzYQbUIGKxZWWJhF5CjynGC9u7M1nNOKUm0rgbJAROwhbiUI1q9i8HJ5rQXRvBCC5RTXqOXWQgDBxWb3k+c+WyMgd2E/W13RoisaqJBJ0k8oOZLH3kPQmbYYpZ50x28b9xWjDkq2kueOKYchtGHn0OxnDTeWhkWtWZgx4enpQF+8B3ragf/K23C4ASOGAnhEHR84AFiJy0YGb4lIaCKMjmTZ4tJl7MkhyqDE2ktajPbwyD0ynvJqcx0OKEyLvMUugAcUmJW5p45QeZvXszmJh+2/cIDQBeIrczhD+cy2WdiQSsEr2lbK48lJMQHssfoBTR+zFPePX8Ht1FC3w4d4v1ptGovlUnwAB0dkjEWex0GoX1YI9eCtlWofSZI2A3YuPABMyay+Zdz715VY7u9JjszBU5YOvIEUwIUAoSGo0pF/HIEusf8vLxj+slhlM7WR3JHDkIrl+xmTR2UtlYOPl6wkWg0QDkiHPbthKi1g3ChCEY1RtBXxYD9Iwx92906gp4B3wJMKMIgKcnO/V1cHz93sZAc6M+AmIqKipwKJhZOGvL4N0/OKO3nSjUNSqIIqQOmK3scqNGVDxSlHcLicmgvZIQLC7E0DrIEkZ308VbamRtXtrAwRZ4JmWcm7Q0MpAujWSLWcdVon2UHImnV9IlPr1t6JLQC+nlOC4Gp/N9S2txf8jmgdS3xiJdDW62R2BfT6iooLZyfH19lNtomRvXc+fOaxOj1pAcC/apLuaAwQq0CYQxQz7dqgAahDbblvWGjMGorPt305d5hLEg5x6j4/iRVWoXTTGfqFEs6F7OoBbf5VtOTcAVTMIET0NbuuWvzskLeij/1341DFx6y9T1E5aWumlRLzGDKzYjx/foMZlXUqkM+1T85j/RWsAMJx4vLGtQONMWT45eX0UJ4tFBeN2YWrA+RBUY88TrgCgYgBXvy28vX2U/tIxqdkcwlK3dFYK7OG/58bWKOswNdrgGr9ENYbVE07Hbme5DZW6YV7czbmxsjaqFnjmbU5+Hb0CwIDXn3Kagjb012vLFDmdmwqnMq3864UwMJaTNQEuu8dFrPO2KjV5rbcuFcktLbHVhtaD1nD8DU9FcNDsEIzGXFSVs3C0Ly7KT2XqGJbjEbF5ubmzQO7XW8I/twzB5da6xu/RQjTbW9Uv57SeyzMfIZPSNM2Opylpi1oArCdWUHAwuv/wyh9JiizCDKQ2YQbMwQECeGdJj4iOMHRGiYwYIRM9OjHvTVPBAMmupNXNv4JbFmTTldAJCHz0UTlTY5L3Gbay4XnJjvNu3aR/BMIE7+jYmV9AmzraRdJO19fi5nl/HlmILG1n4aER8LRvdPnx0vqyljGl+/gHtvr5r2krwA1RcAy/6w2z0ZlH2nQ+EZSWFbYZIeRJOMalRmXh1OYcg0IcOoeFuw1qwBFQa0cz7rrUR5Jt+ebLz5+XZxT4QV/U2HdcqljPjMmPOaqFf2puk09BtvEiicc3kq28DWyxLCxsvm3tTE1Sf01UWrYMLuX+H3hYOKVegSKkIdH5YPvOAAmmIzuX+RF52t+kpWoo2r6nXY3J2wVdbrADnz+mON8w7c2O5xHCO13sTUNmkoSPqSWjvDVkF9jQJKgtyAq5H9+iuW8D5D+gbDtDrdQ7r5HXQYLe9JGb4z7hbM0fT0nBWnV0aMUDprDLHkEO9xnp6aipWYkTE2Hjgkv4CEZbBchEhgmZmpa0w5LkZADYmvjtdk8+hFqbmJGSakD/XCWaZhoRRVTsgMMzxMBNw9o78xPCaqUl9rSMUxPaNYySidnN5cHOH/kDErqi4ptnM6vR0yXgMRjX2lF4DhR7eM7+lkYEQewlaAv4sNgTZltVZiyYTGx94x7+0pHG0ajasbd5WaI8MZZuafaFy1AEVYMbBSG55tcKeGu9VKQgtnWJgnR+Wro/F474C8nzTVq22qXGHFfvggWBhka+6us1SZRcW54Zu5V59VV8BYmn2edFbquzqohc+quQ45KWbmjEfo7Zzp1YWpfjQI/7icmWi1HICA1pAyjDDZsl5nY3WRssy/y2nisjsiTr2WA86yK54/OaOuZTf8Hz61vUr+DkHtqiOVUsXKpi+rZq0sTMzcivZcajWnzJ+QN3X1TqMxPi/hp+cgmN0i6fURM7xVPrazdDHmBGkRW08sHL1JxPMYoDgQHzeWT1UwneiA5nLB+GaoYexj05LoyE5iFtDwG+wthMWQwR6//tRLUExu4ZIMlDqRpam+heZl2v5+eS1V+XkSQVs8DzEgmRMniMU6e68/GRAz2BgDJ1hWO/qB/zDRx3uAOJh2R1eYp9lGgMYDHyFZtn4JOLNuGEzEsJ/noWFjSNykAQe9gE66/0I4BvJ6wo3JZB3dXXQ9NHh++Ik+cxnci7QwOfwfPfu07sQMYyvMzTA75MPSmAjCSrmgKvO9jGbsd/EWZ+5R3fXAk6x39298Mcm1cnQftsWCXm7ekFZeue2HLETTiH6Lxr1PHIEzWEU57ujW4lbuNvwr0AzbiTggftYsqLTdZznQ5QNH8nJJ73euaMgGPDXHYry8gSj1UsTk9fgIkV4JJrr2qrMtrTsb65I46D/xWnO5LEuhWguOgIoH51Y/OMrq//iAZUVRixG4vIprBwjBqz2W/bKc+KIgEj+fFV+96hegjLT86t3VAUVRIbj6/6lJX387FuZjvr1m1e9jU0Hl2XXLn0JBI4BrxOEACRB6GtAoRNdZJI0DJQEgpWB/j9elRp9txpgWhWdAyHGnZHknE22ZPIh6gjWnhkxnZVM479xA4RsIDhVVQmLBNFo62hVwnJQd3eip4iM0T6O/VjR5pbClZVoD/pK/I314a71YVtfj5/MIy+/po/sZvBnVupJLI70ADoLhBT3rtg6wFIpj5Iy2LQMPvb1YS/gd+aa7IxbRhN7hHAV37x0Qd9AxamvcwZWbZ/W8zclo8pfIgTUN9IwACufPCi1Mf0dLYz5o7wHTY3Snrxkm/URB+m8V3GOuWcaxNCs2q5uS1Xw9q2Upbkv6aytvrNK27oBybra+De+J5//hL4cHkO9Ox0BjzHIROu4MNXOdkWxTlmD/uFMB0bRfbTtjoNhr2t7e5lfV92GeULZ17cnJvovxEsLld3bu1Ng0uKuRo6bJ8YZcFi6OMhxQVGwqDbiAR2UI0k7lJU7uRQoL98XW45dUcuEzuJDPOVGiSkk8uLYiSk3pCd64P5sp2W9X5xKPP+8l4u+tjGwf59OtoZYzceLm1u8mNzAbW06V1mGubAKNBWdCCFWvPPQsQTHlTXFK4Ozq7bdJAHmP/m3C5//nD4I3bqZ31+eYZ0PtDAUL494g7etbZpc4e3QyRRuc1geMasDP2OHQP/OC2L4mgktbr7uX10F1uc08w0eSA9pNiOZxTWXP4anei9mCKxA3TvydbsaiisV3X3vW4mnP8+G0TkMAFTSroGMS1f0eHOnXB+T+n2ebwAP03249NCmgRFy1OiIpw5B577/9VXWWKZNxPA54QHFlBiwheTlKz7Ws0E04NX+lc9+KlvSroXwJ1d+/Fz2Y0/qM2RF/+EV2YpfFOVM3T8qZahAeQlpcNYRyQ3qznYuJivEdhfzYkvtVA2i7u7fIUnz5fqGxTfmzQVF2Ifi3gByNiF7N+sG3w6BYER/NCHtpmO3W8YLAhkQTlSM7TSw6AYnmUr65ilvDSRaBdkpr/YyEKIZGMxAACEYG695bFSPT03KLjIOL8kB86N4IQO5hIqga9d1drTr/dm4bGtS8Xf65LWLcr/eco/utgXQ/eA8CH2McKAjrhtq3FIp7SzAMzXIj9xj6k3j7hwDZ83p0JGuW3S3vWGP4UWHpfBDjI+81M/sz7EDFKV6XQ0l+TiZvlV/tIvTdfYqXZycuqrG5ubN/OpSrjl6h2PC1Wgssla+ZuXBqCDuLoaNJY0Nx1+bGvvMXlX0cF+tz9tv7YzNs1KhMkIKT6D0wJXmoC1PxtcnbnNc0zQ6O08yIC34UD9DqNk/uyYjepcOj/BSUDKEhXmULDu1uvsihIBESiRlZhGUTd2p5nsSjWkDJQoSEJ+JIUUdtU2FIdoumcr00WaAg0RTi58ktBwyDgCWqKpambyjpnBpIfG2idzSvdrGV/VnilVC8wXia+U97Zz5amuaNse3TvdxjM7kW195Xe8a3HB69eQjSZjN81awYyyAJ4Ewc8DaVemHt1UyvWeB2Bgx1mhhy2wCBR5p0Ft9k/Lvh+Vzxmo8zn+uSfAWUB6cTupdHtldegzScX1Eh9I+e/ZIHt0BLSxm4im3KJdAbOOm3I2zS8WE3uGWTUGUSySqEKd1cAY9vHZJeSZSNUJAkQMHVwKNdaqmmWJEUCwU3Dp+58rVLMdkBdS76W77i6SwzNUmLUoirdOgmH3n7Av7Rn7lOW/Xk+YC2ZFSVx/ikQ8m6mtNok5mbNQbA6gsydy+5QEhgMFvPy9f7vDQL6bNqWtei+zQcDQXtN2ExZrDzj/wT7GNY3PL+QX51Quyd6vefd8hVbzzCzpYDaWW5dw5z91CV5ODygHmP3hRfpt9dMblJbMO+xjo3RjK08feQfQmguPg3HjfcnPRhMO7vOcH38thKdzgB4AaG1RB/eniJWE+zR6zyz8bEiYnf/qIQy6KK35/QP5xk97Giv2hDa2l5/foLlrADPtd3OduId1QR1QP8ShwlgiWfHVCReKrjbrWlKxlEOyCG/PSq3pMdAMuoWsd/oM1ETYwMVTALJoKj5Ow9F/9K3lgrxfXP3defXoirNDuXVK7p0aHF/gJ9REf/MZ/Xd+5HQUuk0OKtEqCqnnBrPMsEF/VRQgQucjBYcw0hBCVYDD7WHO2HrSCLYkU/v1PJ9zEdDK8/fpZ+b8P6e+oV0r+BGtOTM3A8fl8srZWXz49rIAP26C3YU5uqH+yv1NPiQTjVzgkx+P4opQB+AXxe44JPFZZcA9o/rS9edO0otI9WS8zIflR4fgt3foIQxZBZlyacWMgAltY1VRa1qaqwBcKESsq6dcqfeen8ag5tHwR4i+A0vkMX3uZ7WjjoWkEQSo6KzXEt2lzgdMNVVXl23yPVKoYlSTnxk6PnbOw1AEmYUUU4rvIDTM0uzvlrL5A9lagJ3W866sxPf1n3bpxUAKNi7CxonjAWyPEElkf+nZBPrVfLzVVqTJyfguz/Bn3Z7/X1bheYiEZvOHcYL6IM7BNe1U9PVzlH/XLMavR5XFhOj0OJwT/0A5f6dfjLSGNoj71sPhY0KqoOjy3mPX7tbkja3EGvk+dkp092mXA/d1b5bnnONRVZPSFczkYjsDlwWDTHVChba6tvop5ifzoynbgoM6t8uEMhVDFkh65Mz+brWcrbqi0pKS2KHt5rdyK6s0+p5nMey9NS4FNOS9gAJF+BZUjJxS1riz+8pnih4/oG1Kp8lAiZJJHTPrSsDy8z+MuGIYBf68MB/TdZVsaCuoU3YRLxvfNrVJyqMCfo4VxJyB+AVLDgfgDkM5My3hdCScTSmQNkksKzD3oaxcMKEzHf/fPMv/00/oILVNRnGHMuLBFX5HPJzKpvHPs33orc+KEJ5UwNu4M3cQBxEZStGrSmnFkTaefPXNeHtukl1Du9L7jfFah985548xEQHyB7FrSmxGHmzc74+LpFDvdXLBQElbz/NCDzOrUBXU1xgC8B7ve2qxvpjq1jVJS7CXHZygLUXLRjQBGmFiOuSOhYJ79NP+HH8mXzZrfmJFomdcm5MYYGWRlsL6NmE5tbYbuii+tcNrYVXTf4dQqKwjNiG6rFrLT16vwqYDwIRoWwmVlY81xk/GD9XJgq75ZR7ZpWjIJhbxiIzWwOinB2NcHujYsVDyhYVzFx/fhIGkYV1NCEaeA8UCAEK8Kr8slPZQ0GViIZIHZ6fECXcnwrE8+N6anHS1SXC2Xb+vxpgbtQfqF2kM4vehV40f1D/mPkuhtZdoj5OGgF5R8+pRD2ygc4qlORdez5qVae9CFybD39+hDtQCWad0eoHuR/Isibyb0/F+uSGu5XDOVixDTs9fttkbDr60GcPkBE9puv/Nn0bw1h3TRFs7dmreroKsnyHVhArKpTaK7SjQrjOm40NDQX/7Xte1b9bmpQbk+KPelVSWCEVm8R8Y4Y1X1A2HtUb6Bn3IVTZ7fW5tyJhKt+NB9Un9TL8mM/BhWtEP+ICcUI2biM30RtiTEqRfHbM8Db/7HlAwMyumEruuAaAQq67Ay4oilSPEWEyUMJREcZ3d4i/GpPfOuPzixDPBCmDnkBc0DNfrS8YV8cXtpAO0DFRQEk4nGfjVdzzwzyYbIiG0zQ2nc+Q4T+Y0fyG+2ThSYxPqY2qEmcpPPiV9ZaWSr7DWkEZqeyP5sYkWf1oYywdXjjyDRwjSdKQN1kslo9fj9EqxSXzzIvoJLwDB6gFkG2iCAIre+nVxgh9j40eqz17IOmqZRDqQvDCv9vK5OZyxZv5md0TAx3Y1x8zHNCYx0axFlwjJdfaa4uLgsuL641thpbyDOR6fZBEI6Dv3jdjaTSjbjXlStaqbCz/ROFrwepQZwTJbk9RgIiFJRQciVAbwAm2PyoK2tQs7p1u7icI1qz0jx9J4oExP0UpIUhSlPlGgcQ176+3sS4mHWWDmWxoHBIEz3n7wkn6KeZmTrr4u/y0tUyKIY1OOoqeLvxuUIqyr0Lh2jNlm3k7/tD4jBKYq6pNxOygntLq0aRpZPu3gZeySMk5XNuB1AS8HcaMc/2iKscZtPSY99BWFyWuLd30QL4W457Eqrro/MFFUqjCGUjwT8ryPy9+zJMdIRewFbNQpjU5I2TdXCRrBhFTrsCAR2erqDDdP0+Bo7tWxwnZ5/tIk60xQw8N8tOT652zIgAM4bRkwAfHTDZzSgpqa6oiawZYsKHrIDku4G2IEybVwbHgK8QqA9DpyuvDWgoz3wFgSU6W5TZnrbb4nFPFigkgi+Y8m2fXhlaK6uJv/tl/WpQ/ZpB3R4lixqcEOjce2rE7KvzINKaARgPR+NMI8IKi3d1JZwERng7K9vBAzgv2hU/uNVKTXm5ptwmHO93rgqLaWqliFKwR4FYFxXC8IDNIUDN7g9rBXev98reUeHzusg4gIBpwA9bhI/8WwqRR6w/VG9hLEBS1F46OGHJFgcqrSc0IgcBrLqoaawQ3yECIOhEsvi/emP9RPm779BYiWFbD7Sn+fn3CzKNhYm3cnVmZc40zdb2zWjLoWTXeQ1L5Vus56RXO+lsaeP6kdVY/rkmzPyq1ZB6gL2arCmoneu98tQVo5X6J0Um7lkOhkATMzG0eZSckxT0OMrq54DQE0VH7fqbT3bZGJUkwG4WdzODbsd00skJ6XpzBnRAjKRbF+jt+VleUhmV2Uv0gwLWYpSxB5Sy9gl2/eSTkQrjrdN6wENoUx+mZwEMGT/NWVCGr+qXIZMlaDP8b5cj1NUDigGKxygW7e0s9xcG4faHWJg1AKeJFVXmen1G31ZOndlRnVpaVcGfmpsmC2r1TIkJ+bCvNSYo73Df7M/t3sfLEsGF/al6kLBfeN/H+Y02po7+DgjX2YK+q7fGfeWD2H/jvao+Lx0nbvkIRb+stvjYbVoBaHcD76d2vRp9g1Q/Zhauk2lnRPb15en6VxkkAKz1I1mdEyId4pudbXgBmrqho94Aw4edYwvYH0knczijNuLtXEYOMV+lEa0veBwMIYLGfAXSbzUx8/C8ivGYf7jICvp9ZQhUB+BDGvhAy0abflsoZSYYayuUUl0eL2GvY+LiBpojSZHEpXVSWI0TqyQSu5x6J+vZDJJug/StmRzj5A3ykd5kHHGYyFaAD5n1EvVAi+c1NIyvAwtL+Zun1/duVeRJW3fOy67bWIGp60VMrIoH6/U22AGRG9oXI9b0vLACYk0lYVt0fL86BJy7cbKKM+1JXmqR4e5IOwvbeWKd75fSINabaCDwlAF0l47+UUbnBsUtgCAUCBIPbOYW5r1lDxAaBgniHRQckTCJiCwGUEopgYQMYGGCd9srI7oSOuYQGxWf+/pki5wwKqkzURTCzihywSku0tFHMzzwlm9szCpn+YGiPaBKxxjsHYVPp2f9S7hNDqtyG3oZ9qTwkPUheimDl2a+9dYqz/eo7tvAYRDFZD9petoP7NIyjwEELcbiOH3CXLS2m1wB7qNzSNwCaDdeOwRNTHQpZu61uuqHnp4jgPD/4quZrJSid9iuDCzktBd/uhgPKLB2Zqq3Ddf0ktkSidoDR9CsMTPljR9hXGujpIBZIHmEIYJdY0iZX445CsqrKlJFA3qMVyA6TZx0VOIwv/MNMCDadXzbhB7kDTFGWkx08DnbiAU75icxlOuTaKGeBrYDZzLaGn7qOojC8+7Azv7m38o5pgV9VC58rODj6lElsWWxU1NbtdyldJAIEwEi01iPjvZsCkycXMtesA4uLTE5xtyqibaJcszyZq8Kopc/y0/6e2IeTjJxCXIZIvZBhQKpmZmJphwC/Xe+flkNj3/iBHMgCnCVYD4u22z5aly9sy6x/hCBm5mMehYihdH9c49xRo7ps0glArayH5WjxqCAc3kquuFn+McHrvifQieYeK9DiFW831d9oNJnRxRzmiMJsB5lVVLZdX6juTkfO7OclG7dkQ0ql5KK5tGQ3BkRwfA6M3/cIGzmsrsloda3OpBuTUwEssTroIwuoY+NPoAwf9o6WiHHtNpTPs/+OkqF2tcW5tmoiz7y0P9CTmzwXWO9/TX9yHe6SoYQW+vOKSpwlSZ8oAGGrI9oqre6VIULFctrKrbig5kvYHcgQ8MGbzz4y02hRjJgtjko73Zm0ICOAEhX7sqbyFmCEiBWiu3cSJmYnnFs+xM48/RlTlPt6D4nVrQZzbImlgTcmylK60vEfDLVzKHDmsD0fbXlmU/q9/t/kYR7M9nTSpBnslxGVf5kLqsPNilissZFOQ9SkLpGb30Vl6FghebMtBfPsqE0nP8/HdbyA/nbjEdCJwHEYYHpcF2Jw/oKQj763+Re+ikHjNEA1g5H9Pjx/brottHHnGGQHkXZNkMrxl2f/NND6aAOXC0QE5Od4O30KduYiH8l8quFhQlgkHlqLnJDFPpPvOovqGlXgugAXsLtMBSLjbAaQdRgXkvGR1L/SK7OtNVzLAx3TI+jtg45MQ5a5Y4hZ59VoekD+FFhPWUwmA2YC/Ivy5x3UJJj8fwM32G+TJ6iuQTI9elYbj71xQpAtcOH9bT4vqSeJx023oM5L06oJtTQeOkIkzoTsdUDQJHAtpoCoibSWJRUK/AMFBd29XtX+sdTJsanJzKd2/1+3fv4NLu/66dLaG2pcLFJarpGMfv2ZVigzwOu3KSu3FrsXeY46qSzB/988sHenyV5KZBwPJ+3J62zWhmNGLj0c82Tl2a5JAF/bTGl/fLFpN+upK6M6seOj+hhnMbcSN7iAJj09l/EAKTsaCF5drQ3kZd6YGawG2DdIjGFtVwjK9FBeGHMf2UNLGLtKVl5xhmIB6PYwPRhnR3W638hb1wu08TzV/t00sAQZAlsVKoYFT1NenjNH8w2LQv0bytPJ1e4vjUm9kOU+X3H+dMV3ChyZk3CBWXBtaWsowaQXwIBsYrZgYCBOPh82v0zXqcv46d4Cuy9GxhS9+84iOmXT34IPsZKAdGLt5+7HOlVYc2+ceGOP3hM9lPfyblr1XLEKmP+G6sBIoNzxAliw2tLObuP6ravnhP93zfzdp6+5LPhyGhnaHXeqW5TJHuoW49xRzOkO2zRbt1eiJz/wOWN4MiwnixzM9+pjoR2lss56ele0CPyRTDUyhEtCSUSGpru8Wsx44qb+MGs/wJAkAjIGELbhVkco8cj3u+brW/5E6OUZESm3NCg98e8BQ0hQSXh0yXRyzr+qeQTfvQ6pI8e0e+2Klvxt/D3wCxOd5gtJOxPSdicEUlQ0tmmpDQgurS3buXna/LhwZue34dLAf6B+tDlJYZJVSKGyBcQVgFvxTinSybZAP61I4AAEAASURBVGyZcUcIHxhxc4oCaS0szI8OarN+5yUpZwOeVak0IWXkh8cd2Ipsb/8Hnen8mMoeo/G3bsr2oniQGcYorkRmfsVLZQwb9JDmeFS1nJJPnSLXwpSBDt6/XX+mzPD8H78qn9upp3QrY03O16VsBCb+9JTUWUdn0xJPelNGMdXgWqoMES+A2RCrbwFwRP5BVPaXyGF7xD8rI/NyxD4UDrAHhlQrnFZC7bBSzoFODKEb2NzcpJcIaqNFnbdMLdBIyCNEOIPmhQFcXAbepk3clNrrU5q9yrlbBNTgisoSOTemT9Xbs3p0j+6uBcIbt8EkOC8goV+xX0jG/ccz8rAdw1NIpIFJnYDEAYncQqY8S9KKF9usK8mE9txtL7uag4Mb7xbEboRRF4PG33+dnzPBG9POQ164k7l8VT75oN7bblk3UQ4QPHYCWzHjrb28ZV79YyV6CV7acbI2UdMacNw+HMvldJ9xCIxikqfHjtDExp5abPIJO4fNl1ahIFgAEZd5npkIBuA4xVwAl427NZTQHtKg03ELkSBcaBgTZenibe4D7/pLoWgbVh46oiJtNinC19Za6Q/nL1zMB69yCQ3QuLXMbckX/e+/QP6MptVQCEUArS619+zV/eixxWYi00R9qF156Nu/8fLeff4KUj1q1JgtXvO1dfZIdfXeB0pW0J4iZBqmpassUwinH0FCzxkGUTd+p60yTd5WAR4fSLTurvT71YoxtxyRn1qTXdbLqSXpqJI6Yyy8FLSoc0ueEsFWXzDu5SlanTc3Wp31LeaB8/fVhOwY1ilH67Yp54+vyRfL5ZVX9Yby06Nf/JVQ06GWrMGIb38r//jjyaIqNYsoLhaY+JmfAIGKwEysvzhYyll4xya5fVlhBJTPEedEhULnxjU0ABfBIRDlAUNicSAUneZgQ2ExGQl3cVTeYrc3M0/jOa2Fow3G2Tj/6//SAIQjeu3HIxS+zItCYnSIhDplTrsxbaT/loSDeh8F6KfFDXyBjKi0azrT6H/97e9zxlM0qbWCmgwWdHjixuSIGoVMFQazmblFGC5pmmIlJWEyZJqJBN+x4hHBdJ3eiVxvRDfe/qBTRO1AI+Yo2ht4FSZgaFAL+7WzUsl+j/Ygp61EsFOesdu8s6D7QObOhFbvxjUNSWNzLYih2In/flfxiHYHVRjc8NL1p48qwVJRGMwG5ymjNcbfTVmNfe760yzsAR9AJEFiQANz7lQ8PxYW5J3xDlvwqcZ6G5a9/wE18C54xKpd5MtBATD0qzE51KBvY4S0t08O7PZybSFmMLTzgshbUxbJRWqDCWZCwNZ42w/KtvsUtgYaah9mH0PzWgCLsCnvvGEY9M8S8s9YD2Piinau8SeKyii3qdGCAobK4CGoo0MBnybYseg14nqAdAZWcoAU8WyH5HqiOjvR/d7UppmdASW8FroBXNvmjdGxIoVHQHUgVKh6JUGqUBcVoC5MeXM14gaC2SfrJGvdrqdluh8UxFrMVCIfNCwZqCwrvXNndmYF3AmxzZwPkTJ/tAA3IltYpkF5VWHovAjwlhA3RAOVBYPkPqeP4os7mibDScmaeIAseVXBGupFGvz+ugZ/HB1mDgbdyjQ/OhSiZVCDi1a2wpz0FAo7YbqSo3RQhg7k8Z1vD24sm857cfRrffqG/fu0I1wLA8HpeprFAK06S2Bul+gE/QJUdXEXCsabaYpOzDu6niWdAWm3ymFEcTeips9iNlFzZSl364YCTx4JlpfUHlDVe7hyLhhfZWjR6ccx8iZtleEYV3ALcziHrhmpAoOWdKUbTMAxJjqQNJQAuOcqeBTiiz+9rGVbuYxa1RnqDBSc6ddLx0Lx5HgqvKnYLeqtq1sfGc5XJEe5FMhnMeJ7Hnasr0v3imS9dLOxeFU4GWjzRuL8flwIN4qCzcuwFUmhpI2d1OZlpdMyzvuxLD5J3xhy2+mAzuGlLoNHMMyugCaQhFh4Q5duX1RPEoJRYWPCIhDOJK1H+9t0D2XLc73yG91JLrGPMJ3iujWTzeHnw1k3bqhsA8RxeJw7yjHt5gINOXbZWZdXRuRxM3XkfTlKMgnTBvQjrcrngtZ9V69oLmVmpUJMSqyqi7sZephFtjLjTieYNC9emNMMdD0fcrEJvBT8B5ZLORHj74WrsnOLvo1C7rQxzD5tb40IIkqux7fv9BOD8OG7wAzbc2VFMkN40roCxmYb8bJ65adgSbC9y5fUXtWR52ffoFIZe0i7Hv4kjyVEGXgt+1fCEhBNd/a6DuhBO5kCw+58VrsfnZGHd8uj2zwfhgn3u7fqPRB9yhse6HRKRyd++AgHYt9E3hiXo41eBIrupluZzHi/fYg9unPrUmeGvG9VOmuFxdMQjYMupb6kHYMWl1TdOZZG9/IfLLF/j15CeaAREQ2IGlF+14z0DqxOEIEvQm/ckY9t0ndCEYudwSrQS8NyolU6ooa58N7N6uuFe3R3LYB6NSFQo07j7UAM7UFsDykiTYWoZ9Ji4zxcYYy8olqzKLnYEKzlVBOXGOPCbzH1odH34XcUAM19m5eb38NqfiSrsTrtOhpmeOC47Dqkyp31MI/WLsRH5zh+5RVdVXhrxpsXh5x08/VyfSm66FAoFSE44bOyhwrglpsqST8fVdMTI/i0ww4omIb4DN1uapGVRcmah1ZbJI+v6ZRFhz4DBLnwweyR0zzLsqKIZx1QBfBtp/Hq4rybYOg+8tf+YthQe01m3ygYqrhjqwlwaXF4fmF9csGZPo2tzGd0zzgsPS5mrqSoig12TX4kE0Y/mrkkgiUVJTnWpHJbfGV3y+WSpPgoLhNxzX6tNNFX0rknwU4SwA+IIUfWU9PY83r2USQURr2VixLCDEwHuHo1wQ8gtFB1aZV5J0fKplen1nYg5tZ45+5Ie0Biag2kNu8NanFMjSfo2Q0gjt6lpYwX9E5ITS9MnpUrJEDvl7IBPd3Xqjnrzkzp8THA2kiyakthzswDK5NhsKW4sgMxc6zJfZ9QVazD/Wj5bK5qi5WdZYXBbi+cn0pHo3IGdjGUzJMwm5VU89QzSuMGvpyOXbp5Z2VBq0St2VbeuEmrA9O/s9j6rncR/EvTOQnl4suczsgh+xIQFAtFOADiGBs3wSZzeiY7fBLLe6N8GEPMgrWBXbu7P3QCEkEjQxpuW9ZPQKh0hIJf2MVeTy2fGZYaopxcpRgQcytyGSkok3bDbDPvNYnRNRdAmaczJqSHDmmI3A3KHSdX81bZs+7NT1mZkR3l3vqdyrIsm3MxkwKajsgzN8kkLGtmNZazGpR/0MwTmmPCJIK6QC4EY4cfoT8oHwgEjQKp2WglZaG/ozIalr/rb4NiQaUQuBDAAbp13c+afsYTHFTF82HIosdsPxnAv/Gm/KsvSSl70yA5C2uLC2tIC4RSePKQtMIOGJIRnXEUi2m/QoAt1IRjMuSKsYUTDyXLGpF6KV1ca91THXBrL6Ymq9iXsU0txuYaWRpewt4UmXb9h42SGJfXXte3PfGEDJ+daQdzmcO0OB6/fMmbEcf9gMKfnNXbyjK6Egmd7AQMqERgGG8Bqq4lK3yBn2nvGDA0VExD3c5PmJxQ9nVDNIzw0Bp8xOmC6vIMKbBTKeVTQgIPHPMkiigyg8JuG28uETIH6LhcbVQZM5GdXuf33jf6S8PJzLrObof4BCA4MjzO8e3RmaLy0MRUIJ1DXcgvPJGragxrCAIChc3OhHds12Off3/w+uVnbvGbIwbrakZVVuaXphcWfc7Wgn3ZKImsgEwAg1BzOBu2baD8UUKeTglx2W12KRTULqYu0MSslCc0LAqBlWk0uhUvFMLRirZ7WJBWoiUvjkin2XVUCXV0gO/OjGzZ5KVAoHHw22m3rVhm2iSl68cKTbNwyuTGPeZm+Gw7bH6hp6ASEl0vLQZR54Ti9rflhoYXFtZclAh/77XXVG3ppbo80/zINcfxH35HE13e3+ZxGmzMd198UW87eVJhq1uzhF5j7TT1chM52QWO20rN9F69JP/wK5k//vIEWwLwFL9raGBRlRvNq7PUnOLk1YWFQdorZaquvz/cHpWWLv0SSVeGZi9e1sOioDq3AG4HfGE/OiubUVyP8QBbkDCwnO1IgSzxGXrK8Ukqovk/3VgQIYwxy0tuzaCzbunHwSF9OY1AU8PG7k6YtrVJ3nxFy0OMoKQyNB7TYwbN7juixXD+Nl3GgLDjYZ6lKdw4DIWhfZiCctNsanOpNBV7AsINNDUQ37niVPqrP5GPH9Ay8Ia5OxnHM1Rz8+YMV93kFqpz+EShSx02FrN8oT/TR778Sc2AzwasLLSDXh+XPew6YMwAL718SncEsnmd8t9ekn8S1LgjVAGWrK7O3FL7c+2S7np3/5FKHzuFiVw5n4Yrzryuld28MF5dmackEDX94lNSV+NfJzMXutjWYVJfd4lKwa6TVlkqvr1TsiaJoziQFZ7jfLBb22d7sxdVmSDrCc6tvsx2Ql+wvey0M6WlWp4np4UZ0fvoZeYW2oeux3R7jMaNMPPtUW//Kx5h3RdJCysNCOKf81pmCqA6IJbMwahOyhm2pZx0uoViVKExodQ1+JUrqlucRBA/QmPv2q3j0hCbWyKnjjHYSBqH3DmW26pkaEzTq7ACE1r+cPZBH/n/OcEjxlw6J6ED5xyrZxYT/oVvm611AGc9fmmN6sl0TK7Py8Fd3oi0ipKlF+ISHPI0uErNjg5rD+u/Hg3aXERSSEPcwHp6+tdN80YVd/aUOBOZHZusKsqVqO2VY8c0alAw5E0f4hdw0uVZvfTxNjnz4uqug7cKSTCPbh9OY3O3N+qlN9+V65mKGBerV9neItsMq3KAjNgwvMpRwTX5Hjt36wv0b8wSbHCMNBIkxPQ7DYB5RQaZ7gi9CehHherh3yTK2MtvJn3tAzppbfCGngy/frO8KBUJedloCZsO9i6XDF/j0sDoreKy0OS0P5nW1v/Ex3N+kgw79cQAwfy8f9cOfgcqd4SKRv/ytJuY7arg5tEsv7rCIJ8Liu1olp+MaC0+mgSe3mI+LcU7UqUeLNbETbGu6sEPXgnarIOava0V/bdr+9PYKSWS5bAnhzU+7s6Wjfwlf5xWhwpc5nxLsAg9PGJPuD/X7R8YewFOyHgJltmgvqpFHq7Ra7duyn/zzfx/+PyC409C86ijHP6BmUiskqeSGJLCsmK33LQBIklYi2p7xcxMeHBs0FQf6Az0gRDgcUGbbIqKM0+YSMxlpDhfYLCvqyseuOgt8cIMmNzYM+//x7EonzQbootmA+yB+bI+wNJoTN5QTI//bFh60j8f5p3La5tc0Ss6yAOHvVM27ee/5Q++1k9FfsnuIkgHmwFyoHCBsjeqWFvJpm8AS1zzoK5ZhPyfECGRv8eOZVUyOOnNdrm5Mbym1zZI0Yl1HGLlEFdnl4TqKtO36DcZ7ZemQ/LkfaHEippFFr2jeV59VR/Zs5KtqfYMLnD3F49ITYEsmt1hjhK3sV8lxPspCxV36k5/+uiR618qTHOWbQSA7oYx/j+qyoczp3T5kSNaEiaoYLxxLQptxXcknd3TkyWsDoGisBNufgua7VPHpaShxGdGfmYkSw46UCzEdBrSuWEbIDArC31xftzaFnAD7ha8DjECDoxbnMs216DnNb47P7zCYkKOS0sSNwYCqbT+vu9QIGurwHehBmyoqi8lgyYEAMHCcDq/nPbZRknsachsbc2IzTj1Of1iStnPJmcPq7dzyryvh08qoAF3QqVt5eySfl5VvtYO3IOz5HQWFg6s4zA69oyKA24c3sKQxFdyDvdwDx4CZgZClriNloxN6Om+nQqsnURR8RffYB8hBWiTk6vtUa0v2goCw//az+R/6tSKL6+kL09KIWvAjJsWNslMv6+lTd8e6YqruXZfbWkt2rt1WzxTNDvCpXw+SxkoP9Tbm0Yjl7XqMc1+7aoKpHMT2tqFDCIT1i+fjEgH2xyHvTKcui11QZ3UBDFw10JaD5NphnQOHtRudRUE8YMOnWnjBg62t8ifW1+EF3Tb+4fb9Q18jks1huqAv+BCeAONAJF0K8NyJmufx7fpNCeHJOCZqjYdwaBtoVBtqSzl06MaXgl1BNZmk+AJlz32vsP6fpQFpBq5Kry+pk4sseQO28jLvQEPBGwKs0FocJqNlFYQar+2TLvJ9qHRGFxVfcjv18afrJaPVYqf8tnL6U2kAB6DXn/djTAYbyEecAkG3DUrzjCtg2aFMhmUqVuqMTujwTGq72Z8YWvgARdoQOn/yq+Iv60lzOabOI0ri5WVaScvDMuArlB8EIumwhGdjOSKemNY96HKWL/g2PBxusAVD2HkAMUKAcpLlzJuyJF3Ev3iTroA4ik0vlP3lAGP2h1zCZ5nuGNNm0FrTSs5L4gCs6ETjORsBm1bZAsUuQ02Y8y21JL153P5gkCiKpRzEQQKFvalIyaV+aHVty5JszEntscfyPEScAPUfEfb3w2C8csdsmg2sUOOXmpgyCjuBT5U8IqL3UAljUNsYiuaqk5tdPfqKCFVl+gwsZAl1k8dIYSuIsDskZwL/vEI4uaqQL8hs793Sg460xJQQOycNHqcYtC9EI0GSICNXb+QdZNOQbQhKo77ygudaMdZzsrgnmn6lrCcI8RrmqpsUmaS8uqyPFihTzEdi21kTSFJV1bYn8wBCxgVrUIBeC3EPOrCAq9bQa7MHaUAzu388RtynGkCVsE/uSC/yeodY1T6i7JR+HWTnZllOdLt1YL1acOLnr5lQBv7e3FSjhTqhzDw9+hDtQAG1YRcH6KvaMV68I7F6fbMyLDp1U7EhyEWs73FbbpwiziLE1JMyeiIx9Kw2ZZCmTCegd3oN5M8fRseiPKLefK9cdnjU1fHDWnyly0ryNHJ9aKizMBt3+0BfeT4cX0tT9XomTp+WIXLST1+KK7WIbmwXoTuBmqXpaIdUrmol5iSZppbjx2N2gAIx0yavjQmnz2hP2M3sWJn+/S4kYkSKZ1ICcRxBLg0Yy4na6WtSufSE7mD0BvwpHO9eK2Ju/fIO/9BcQP2Zk2nXRiRiTmpK9ear62tMoxfH1VdBNGAn/te5vd3a8WXluMv3dLhaGeSVrol3jffyERGiIzahEgXm/S4pSW4r6dhLR1k3rCGgGdQkhgv6MqVHB3h7A6CDCgwHa+XPmpEh6I4T1q/Ht0jHZ0ar2Q+NqQh1RVfZnSS42BrQ3ItQzT8FTMcDzRKNRNMrDLVBWq+1+33EmMtXDhrLOHJLuMWbnSc4LQT/gz9xfJdl22FbOYwHhnDoVG0JfmEExlbaa69jJlwsbzXrsrBTdyyYSIVNPg8wKT3mZxwPZdDtTbj88FakzqiBcM79mhCr654ivTFW8KIDVvMBc1ENi8MEJNfx1m04Qvlg7sj+NMRzQgLk9sJCt5UPe/sMu8018+b74oYwt6msOW08bZ903vJ3fwD+1Ij1/hIMU3nDBwSirqmVThwhCVyTAg6usJGeaYCxt0u55gDu8la/b0/i97gW85aYSHLk0lnj1jr0Ncvh49kImyuSlRodQEUR5tDK8saN3cxeixOGamXKz0zRMSwJyU2CUYd8pgJporiR5Vc2WizgLWD00Kxv7vSmtq768+fOOEZb5ZnTKxptPWhR5SrCTCATR3RT8AyZ+NBG7VdZYGiYN8bqqxAhFgFmAn66Suyb7ucvqrHjxxV/Hf9hkxafx82Nwz1DW0jxuCyeBuiKSwJXL6ccqxQURWoKss4MR7s0317/7fz8k9VmBWXMByUMoEjcIvY4ApW2yKfSEOkpmbNrYDv6NB95F3JcVLYnQBwQzIGCM5DR6ABlFZX56Z1mSlEAICX19V7l6gLbqHzYQB5ZON97gfpo8f0zps3QVp5pAWC3TEG37ikx7/xqDbC+SHdLAVC/SFaTqLAu7MT8kOTHr7CprQtO8sD66oNZifT/+envQzRzJAOY4OzXhlobZ8/77P5w62hmbnpXEvevsSg4YMnyx7cL5f0S0efWizwpd1WXWfPpsCIDkZTL4wlleU/CFTH9GW3OHp7iQbybw17M3cZ0CDhDwWDhmflF457lvLmgmxe1ElorrJ0HKDQ2X7ehkFtqpXPW0uC7yuKvM1VYR6YxLnlDNpQGBqQ+QUQI0P/ZlZ+1QAfN+BB7Ua9/T/svQeQZed13/m93N2vc47Tr3s6Tc45ASA4SAwiKVKkJFKS5V1La6lkS+tVlVRbK6+9W2Wvt0q1W7uyrcSSTIoUI4hAZMwAkzE598TOOcfXL+7vnHMbBEEAamhFauzCqamee9/97ne/cML/nC9hyNeVBIoLsn2Ldi4tWadGp0b6BcLU5Y8uzqWoMeM2EJ4Acyx9iuvvdyYbggnrvtYG+QrAGv8QQvUATF98Ua7xMSgGuAcCAfA71TGfn+okFlN4U1As5spZIz7ozaImDFxX7y5el0cb10rUwDburyiYWrzTHwllpnRbf+aIlkzMR1ahz2USW+WqnMICgVGwPe0GmfeOtwBP2kcp4Z27bvNe2kjajpjrm9fcmmpJfJ5FrsuHdsLntZXu+53uqag8Ki+WrMyBxHNAieM22PQksD51Xw3W03BXfCGbr68QceALfNTGDAEopDRmICpK99nwCG2Fg4SEqgPiudOnL0huhAy2bpa3/ss1uV2Tcc31rqtLrnmdyHHbLrML7sRzC3v3epac5o1wHJUKCOLWUMVqaXmFIAhZwWYMmEMssT7d6Q6r0kCQp1JuYwmHP8ujTawDVMni+urFVMf6cVM7+LbCADCTWq2CslA0miRPiATiCBcKn4XDaZxPmI2RPSOAILNqIfaIRyQPs9eIlgHDSGPagkaLBJUpuMHvPTrs2tmhURUXZcZbHlFrvX6NNNf1Hpen7cV3WWw9pqJNa+/a6J3ozWIANp70LXq+5XrEOOnK9KNXOGQihyaS8qDlCGfSBToHyk2OCyi0Fv5B3P2GzvG2WBVZoXmkkZ37p4/IhjQGbcHxDGIzBd8Ek+1DUKjG7WTLFjiWW2fSXc+4ny8RFQdtWrb6cvMRraAFIngRmow+vK0XBYpPsRSBlOMpVBVyI0kPgDbFRKUEOGD9tDxCKLAUZlDuDskUdPAfNKhxfbvmFnUIK80pn2yqdE26Y5NpZhT75TMpM5HNq1GwWX6BiAug3zp1ChC3FGrt20uq5oXbZfQ7BTKRLWFrqr3zAyqZaRKXlWbvJJVFN5KQjS7f5k/UTr5q7/OYMJzJd7xQseyh4WtRtW+ecZ/dIo8pz80hz4mkjCpD73jtHZeoeNwA6E22m0u4NO4XAbKs25PnKtcw22WR28TUwv/1pei6iJiDk28kZaAu7QFN5h/6/YlIQGpXGupamFi0icEirocO5T68212Unln/yXzfwnwOG5JSqPNzEQ43V4Flgm6TLlPh9weQMNc0PGf3QVixirrQ5HDS9n/yEQMbGxtVE1mTOzY3m7077jZryoYat5pDB3GbUJ53RFmZ8qzVVWoocrVLDj0KZJ+QVB4ZhAXPodg4ojNXmRC3hGDl91X/76uWrIBYpmqOnZWh8isauFkjm8G6+THpr2jxuKxUFkUv/ZJJpP3c6hyb7LXruVX59dUCGqsHvTMVhvX7aHRWTjCHHDrQIfCp7gDRfZE5PnqeMwM1mXxgZYRlAoQq9nEbNERSpS9SHWCAgVV4T7nJc/lUwXuxD+QIZtQ2WNn33pFKm8SdGpCvYMchzO53v+seesiLINAwBMiMaCdkynzOlzJuC/Oelufo8uOUl+rd/2HZqJqFX9846g4/vmiOHLzd0cGmOLm+kAgtncKYhzEACdAYmFqIr+Mhrx7wMEn9osxhrtePvAV29QI+ev9g/+lTtTyvhVSD/I9TXPUhVvxpWJBegYAXWAVAwNHXpfD0CuZ/x055lFOUEwrFAXlGkZmF2TkZX4aIwn7yy0W2E2XzzqXCxGQYUdb1BmQ1s+AObZfbVp3rxX4G0IEDwosgg5F+kUk2pYAbjC2+9+0M8/dUVN23Xs2uqXJf2eiKFdchhExUOHRQcgB0URg8nIICUcTx+xlGJmwQA9vGI2LSEHkCPmAyg2UwHPvnBNkfACjcnXjmGVnAA2GWAK8Xb7v1MbkFiUpQXw0FuW3emtq5P1RYJsIbZD7H8lRAAt5HTru2EnnlxAkpTGnIWwFJe/JdC1qzhur/7XK/HZNkfAjkFyGOrS1etsFXXVaQGUO63cdL77RcmcduBYtFFvPzsr508mt/Ke2zbSqJxxifF3PUsibuzp2X6U2MWKFD86LJS9eDnFbr3MGnZm6fn7NZnegUGUMLS0UgED8N3qjCRlbIPx+50y+P4BWWWWZ75bqGI+p7xE+DdrSJc0JTGG9QawYoXlQTfS/rPlvtbrOkFU2mW2DTNXgRELAeZ8Bg65HXZbkRv1iRwMq/Ve4tU2mfkIN5geDQ1uBcTd1i7118GLkN3B1vjaXKdPvywTsL7EECP6BHIBq5rGoppPv9sw1yf2/axj2wu9gVBi0NYTNdDR8jFpNXXmZPl63C1RBGC/cbrjNOwzP0+7NWWRoK3YRzAlaA9uyVmW9R3bMExaWNqWHYiYl/+R8Tf/Iv8guUUTKBUCjiHz9xg1fKDq7LmRj3+Xu4ZhXsd95wnztoC8Fsxa9XBdbLipakD9TdySbTv/oF/3CPiNuaMcHQ67VJCWH09rnH1skJthD4AHBgtTOnhQLbiA11QWWvXSfJsFjUlFpATz7pXn1NTq9/u4LEJkzbIhoEvdQCSq1xpLciFw3yFidEkQObI0HfvOoO17k/6nF/2CG3bHDIViZNMbmGSxHY6T7hrYEBkZTxMc8tp3iR3JRfs8DPObTfC6HRQXhBfNRsKoCgTn0DckCT7NogLpyNuhD0waIjTRD73AQaav0qSHtCw7fPzkj56ELsTTr1gyPu8G5JBijctDcaSIo5xgOHE2gEawd80fiSx4HsRQYP8N0/PypvfaLDvXndfVwxIs4/4sxUEwiR+bntIj76HRnlZg7PNkW3sCixBpZ6zqklRCLq6r3Je3AOps44jaXeXV1u5I7X6fO9btd29y1F3g+vdkSd4SgI+Ev34ZmburMO4rvQulvScWhgxAfatU0cSPOQNzZKj7+FYdQABLEAVrlIMIXtqnLliwgjxOs5E95+P01FbmONywx6393QLgk+opW3AAKh/SBz37oUko6pdaidcG0Zt1s0sWNpbcGYmB6IkAd9xL+bnXK7b6/7lV9xOYXi5k5PJvt7XUQh7Pkx73iAZkkly67wCW5l5ZquRGPDHvhLEHErJIh/0N9+UzoXwwT9AeO9RBOWRyrQPlgCViVBSBB4FXksLpbXcObROm91yaPpxI9BbX5RaymPynPdDlXaXBN6/6srbpNqg7DuqHlLkngEpOdz0Ole90Spe2Krt9UBhayac5MaB2lPy6b570coKgvY4Clgfz6hPLyqWaoWqim37CKB0P7yMjvGfU/Z3barg+xWRXiOPDGR/mz6hb8e5XrT1PTSYqZqvovr0rVxd/6cNJ/OJiwg+Hr2LRto2Pto5tRrC9ak/bNi+1Cc2hW892BRl3MxAsEgShhj0AVCKUyhxe9y+oZaGhOlOpV/vHeG2R871rhFNfTXbzsmWjIbEJphPjxbtiqfXFE/HEUuQIFtQhgXXR6c1B+8PzAO3QociWunv0g4e9Ct0ugMOgqrSlTrjjLk3u2CZHLUXDLDD8OaYqMwaGTkr7+a+fL/VG2uhi8YlpM0FPb51q0NTk0tLAgTncTuK6y3yM9MXPw6i0dwVpWM28CsZKoxqS8fcF3aSaHRla4mogEwBgKedLkXX9kVlWumWjDb0ZTqlqj7T0Rgl8MT1J3aaB0kpTahXHxYUqzhGtgecEom+kKYSMSQsDu2A6JmGDQDIbfH3bYSNyAA0A06OZ6BYkbkzltNp5fv/jOtuuKqit+vfsaFVtUURQRzHyocYeatmBMdr8BGv3HV7VIPG22we7dnaKj+1jYZwyQeBNVH3dS8TgTT6IMqtnd/8cG8b1BP1Xq54r+WtVv/4VX3W/ukPWF3cACIEDgOHWMK3DpXpFtjL84m8VVEDNRZx5Jw0KdxLb9XV3N2gNS6KOZ/8Wvemv6XXxbGKit0Ec2Np6Ts7ZccgClsR4FWjasyYOoXjGiOQU4ky+IECWMrwovFxEUxYi0ZbMpmXBBhA8LkuDQFFYKDMuEIq7y6uuQRWTU1eSFeMAplBoEB5iCuozmZkX7RQGB0FDKgFkrrKREj016NgDWIig1QYDLnZ7OdnalVjVKNgE/SWFGBqqzhypcQjEgUX2lt8sYHcFGwVd1qeh/Z6X5nvzvYLsnKVhf5MMUMtesgVKJvMnRom791NY8q6msLHlnMWZoZffUyt0WcGH3t6scelbfYACObzthqSBzUa0dv1cVC/ONRNJK8fD61LSryWtZYlJ6e01AmsyYEbmJXFKmKmqYl2ZkUotZ4gDxiUzUohpvBdBRVez1DoqIMiG/skHeZrwXmg2gTWntni1y3AP0LXFePQECID9G8xLAgAL2gxiK5Zh4mt8+8Iod0QXi2j9a7BoWtzLqhGY/clN/XrUsO3k9OTwrAhZLJVKQsGiiQr557ZsS8IJxACCzLRBqbHUchGSC0snGNXuOvoVj8PdIYNt3cIr8bTKFHZDce1KoSyujls+5TB+SGnPEt6Wvj/Ni2skA6MX9BLBi9TufSaFAwlHiq3U0PxYuL5RF73vlrKwsOqsuOC724QJ4QE8D21Ajz4+xBLSWOWV6bsHUgIbZFYmC2r3dWz9f2JbKN1dkF9TPb6qSFzSNigfKfz7j/dcmrIJzPyBuoGmIQj2NJaPP16+SWZqRxLOzNLS1gZWA64rq1ouWNV+F8AgrG0ogh/GkfQjODycpTLqZSxjoleNMmSp2878LN7nfWuWrFRFgpFqhbbjQ7TtGV82KSyPnsRbGc5lTTjDt2ZhcXxGyRnsxNpyOw37ng9td6LQmXMqBE8SB6hwkq2FbbHfHstONY3k9jBmFpppvPzfpU0ZS2lHYk40NdS9W7quSZz7d/q2zyDpXU5ARC/ktnxJo1N7nvfc996Z/k2NRif1ccUTt/W5I9tlOYgdtHtenaVnOQqytQ40YbYpDMx3v5tvu1h93TrzokF8IdldE8VDvlKZf6omFsnSntgOoQvYBYFUuTmrKiXjDSrk3eRErEAa7brxpgfszNsTG1GnPSkBVSZmP+MAxMS4QLephN7XRTVhMx/E++ZV4ZXUwPwiqQNG9A+HNOwRZZkdLCzyhzvPRLlyRZ74LbVe4W89xrKnHse/kRfagWwGAI9FNHi2sUVb7eHku5HQzsq3KgX+ClrAopDAsPEKIyfYIPjIOU0oUuRbnu0jm3Wv2bO2Me86B3ob2av+pU1zXohjglkriY8idhAnjGmAG7efqabH0GlRNW05AZfiDk14i4nkssjEEB6Gub0cQtEYEulThCGfZFfcn7YzCRQyAore4RK5itfNaNKH9jdZFIawR7gXYQIefvgkDYSyNus2J52Ji9E4YUWaLE9X97491/scnX9LfDCh93qobcvs2FmfNNJVUqfOiFyr0yV5ACrGoseGQmmFhIHTnGbXDHPnbg3ftIDtf5TGxOZ8Lz0niZgaHLr03UNoYq2ZoNikRunFtoXSsiV1qbx1ogs4nZW7LFSKmkeBAJBgMr5S9I2ZDuu7ezKASbqpBKsd9cRUSH7C8dnQZ4sDnumbuSshvE9Y7ORQ0r+7gdiqRhFYlIEfZVbKpmR++X/2Bmt+uoVz29SwvH3QnUpho1tnGGhYisqTJ227YIQ144L8mIZ3ECYatig1AouTrmsqPjPrVJvplh0Ym2HBztmfDOBdmnkyGooFpIV592x3vdr+lHCZZBS/3jM2oiQWL1hW5QIQT8NbjMdZLo/QmuI7OYJoBv4TRbuE754U+UNuSPy4zK7mWYjuyYEOlLf/8/JkfM3waEqNcjGv4SMzwvuhEVBqIfO7Z7to8JCDlRW8EggnxcAx+Ksj1f8T3LQbshxzEtLnrePz3pjyZJWdZeFvKluu8sNII/aOHAzN6N85XUX0OxyDXTuCCE6Tefd//HQYnhQp03ZVKlSSJhDNrtH6QdJOufDik/CmOja5FfY2O6j1tj75/OZ983V+XN93367gdPdngYCF4U2Lrai5Xu2S0CNtQrvDnQn8lmvLFRDAmYAwBqE114Oj80Z9umr1qbz4CGAT623ACBYSGCCnAN5G3aIF9/5ZwbSrptywvQGR8bG/c2WgFZgsyISUOAQkwFgxW2QpTgMZgePQwhhEdPOkIsldXCZ9FYIcMRRUXCzpQZEGbYPRhykbD705fco63yFuXJzc2yywLXfMJkj2sQ2NUZMR6Gy4Ey5HDsirzCinnURXVVdmJM3kLX8A98A4HR0wm2nZVrmJ64JgzNBQRuI8+gFE0g/h4mNKqdy60pxiqc+VbPet2FyZdMjr9wtuxhbZSm5pwqlhsvFEbgeWIOlcD21ZvltQBFm5zMF2fIff3PFtasXeq6tnQR0SREtEVi8LO6D0c0kS6rYd8JMfh50WkW1qEQRzGtBHXqpMvQyxCAmLPDaZ/ssNziGzQ1eY7KUtJVV3pBffwxugy4gHqCQJNAbYYoIb5At1aWe9qEVj3f5Q5qJehrXrxxXZIxSZUvdjS5uNoM5rDxYh5igVQQD5tzmxvlGhCJYvJzNE2TuFiZ+cUAE1/oeyJSn/bnLoy//lLScAa/0LmwB0RWFM+8IFgC9xKyonKBu0I1oc3N8te6FW1Pm4DCzW+hiwcZM9R+gZ2+fdb9z192jRsLSR9gAlxvrw2dMf+qMebx8P17bkOD43ytvn5xLnMCyRZ/OqxmT9giN5e5YRA4obpQmjFfeZU2bIl5RR3k1Pb7TKqOH1XFB7bAo7AhNTJALxukpt0+XSYc1dMrGZKGR8+dlWv8dnwVHlllEQ1qimxCjO4y5cyIXTGRHRZJmidGW90YFcwH0Y9gd/OOvt3vPlsjTGu5CQ8v78/+8ZicLlWTdn+KyQUPyclkHpSHt6kjRYLoiJpK98J5t6VObt+6JEcm8CPER/EfrPHxIn7tSZEFZATC16J9EEDI3JUQh4nLnazZ3RzyRgm4XRicxoGH2vf5ixqKcqLzHh8HAn980f1v2sv1IWLvJU075av54fjefTNIVkCn6BUWxvOn3OMHJQdCmxSM6m9TYAfzcGuNj8pCzG9o662vErY/sNMb14U3Ts65J9UE0QKg6ltdMpQBjcJOgFoFoSAhaor7BGFlCXBs2+4hXfTk0xfdx5RvA4VSa+sUGRyrc11dsq5S3poWh00ZX/YbhCghYgudPOWeetLrMspP3zEcB7Wslt5nYxUygfrYzzDsvrhTrmlnFojah1AoDH+Rv4VLqMJH9KFaAE4XvaCBf8whKr9abwXpZyTABA2yiELjgFyjkUrZmTDkOUiINvwwOirqACuGvkVJQs1RNzIvuMpyQ4Byc1yfaqSvssplSU7xmlGFCXcRCjHnDS+6mfn85ZLDJ5MuOeM62VZH7mTOVT8TxlTtdM+44/Pui/melkYA4S6VUXGBAOXKdPqaTp3S77jbS3KMmOlVBLxjwc1reQiHGSDzXlBceF9vAKxtozKX0piQE8WxM69qGfTP22+8+wKRGtTfEGImAqMBoJKKgM+/cOOlnsY6DLLLDaUSL70ReWSvPGteHaTai/FAnlgKEZ6S4qqtWj5u2RhKw3Ivf3WgoyMxeN1dPCKp1m0KLi1mZ3U4MmcpjbyYTNGYyO85lWtJ94ARct/n3OcVXViwGOVT3FpBMTP4N1VskiON0P5YOjA6/MZLcdM8JEen1onxlFkDECfnQszVxHrQ74ZHYTn6blyeyELE5RaUW9LwT9tXEO1VogCkBvlMuTfecp970m1UQ59bmT/ZM4cugtgZb816j81gdbpluDue6L/Fo9xgsoLhUQKEEIo+GIT5oale4VX0tX06hJu3vIctUVFUbjyetAF8QsPM2rDINdWibCskeE+9KkHkcLsV9fqcO8smRtrpTF7h0VvLyVaY7d+ZzGoEVptjDYvesEqZPdu+NS3xFOgYp8suL2kp0MW6Xfo7hdmiF1Zs5HtMb3/yD+BjO6hV24Jo5njf4siYVGnNw6HChqJgWPd2o8tCwVeuu89opiCKUH545x7JOzec+fUNgnxsg0/UAvtpr9PP4LqgmYwxfvK7D8gvYuaVb2EoTJvdUnJE5r8Cdys474Eb5IQRCTCljuLK6AF2fWFBehXAh1NkKApbwgSb4yfc4cNSbax4d3eKsDGUmppDR5s3AqzESADLdNabYDXAnFn6+mIXmhQ/2haCowFrVwWyioKTE3NFtdEg+4cixkPD/d1pcAO4BOLrz51wT+yWa7DRxx8SENzbLUq5o3TmzOmMGQn0DsWzwY2LN9xnP+E+sdvb7pm3wKM2ywi/jjQ7DojFTCxl/NHE1cviA0AUmzTb18p1S6Ng06NHvQE3MqdGhk0JeINTTYwZOmDjPlJiViEMMPzNMVMQSA62CKg1++v/MPzFz2eaaxLTKkk0SCIxMz56iWTZ3NtFxb6ue5nSEmnwkrJARVM0gLIh5vHdoX07U6ENHVw/+q/zSpaGL37rNo4xZOEKa9VVqxKMg8WT4twk2OVzXiAXRYIoAMW29mESHYOWSBpiBhELx0jROxDhV6qTUPV6o8tV6BgIvQPhBrAk6ZqaXPiErUde41hYaXv3mUr31CFZAAaxKxpNdPScXPe/7Ko1JGau798cc4+0uOs35NFk0t2Ku6+oLYm1h2sXUv5wMLBBWjwASGeiobqJFayMmSvZ83g8FUKUnG905O7tDB4XhENL4xtjcA2IoTr0KZSTEriD3ofu3Zf4rk1hjcXE0OLa2YLjyvrwry0k/v1JSfb7W91n9knJ33xesjj0aH84nbDdw1MczV7uwk31/F6ylAlNDA/3pwvB90AEdiHPZ0aFyvv0dN/rd+xDCBGNTzkf2kcqGUd9+GMh1CL0xitJRvnolMO/JC1e7Js6dyJhi9EnfK62161pkGQA9z2NUiN6EGKBWXmZC8zI9anb7vHtAsqN0/AW4DTsEwTKh8NtChwfRWDZAod5gxAQPyftjd7g6rA3IwmgF2bc40Xy+6Urcntz0TX53eomueZIlR+eEnF7cr3cMpmdBuRbELXjKzYOA+egHFYNi22G6jlToTLq00LkTcnaKvNnMKKw1kzI0y2264nxLXJNyZMp7+Q9Ghztb5Ao0NEaycmriwiv3zo1UVnlLy7121B1ZnLmMd3ShkdDA+mXvzmxT63Znak0E2W/+fX0hi3SlSyBQzaRaIihHorK56wWiP/tOwLSIH6Hq038kW6UGOEO80gpZNnyBi1kRQRnfNqVouZBckzJ4PCuabmmPelxkyly4LCvt87JxgMQmmFnTEAJRFZvKxBKRUqkzzzSvgU3cNcr29p1gqcpJ4WEdu4Q5ny7x2kcG9YjrACH8K9f7TqYldXSJuYUhga3SYZUgWv+mTawmKvk+xGtrAWAbmoZBJvS87dZi6gvAn4zRA1UYTaAKqs8vkVb9vW6+2xdu0HSIV9YQ0aoIBof1YTmh9iKk9wQnM1yJ0cUSthRr/fLPAMJe+crXKZPa+u8NbHwDzrZehk9wCQUEPZlfYs/XOsbMi2wkQ1R014IBp6Beyv12Sss8HuHu8VXUK8q9K65WJSqFRWlgdnaulGyboPBTnt7ptmn0ATVerVGFcIFDh7g2xoax7iB5iFg9AdTjT5GsZWwLmhEbv7kzzOffZwxwtSwGn0EJBiciI4c41E293xJie/+/WxVhZhIVEGoiY3gpUqdz9xq31FoawM2/y/bMZGJvz2NdECv/DAlAoIbKrBBrk3MEVhGOcBnak9+NItM0j0AhHr2MVEfR4HVBNukH4tXFfo2b+I2gAqDgbS9AEsuWrZ7/9DGbWLw2Jb2taNsaCFvodhgLZbFQnAs6AFmU10lCLUTOC5PfmwoQ42PoPzSfHmEofzFu+5vFdb/XlQgEFroO9+XR489Hk/jmYvFlp0nYg2utEXKGggH/DOTcxPJghya1gWryyTqZgH46emJk52E6qCHq1znsDh1j8udjBV/Zr8nO2AM5pDD3o99WrTn0nScXXafF2/C9Qhm/BCkDCWbDcKo1g40DKw+q7mc0DFVyqBs+yGy/YCklFgVtsQyaF6zYhiXgmIZiGaDCqhWdtv14qosCmHFsioDdx0jomN32t7vPZtRbYgcmkpv7tsjueV2NIYjeZFb3VzfO81Gx/5oCVtszXObmZnfWOUZfRTF08+nNrICmwG9HhmQ/49nXK2yfiNWBuXDA53kaeXXuwf0j5UQfWXsKnymkSZT0T/7QismWvFn0d2Ge0CrTU0CC0w34W4BOxAwCHlhqITlDRBamMEEQBvToiBci3PXvNhG4b0U6ZEvCDQG6uX6Wfjauf+ezdBZlA9DaWy7vVlyhgkgLFAgmKkuEyVx9rKrqlvyqRLIBjIoR0yXwSO05J0Jb3QLhxBlFFvtT+crZs/zrW6O96FdNMh1+rwgIYgZXnOzEjkznEEoGpVhH80pzatYHSyo1rLOzzXXJjovemNiIPJ7Xe5bWvF/p5s7MywQ1aLireGoMElDPjT5I7PHFCZEiPEEg2hnht2OSk+ijh+T7T2KUHUycS7ef1/iCjQm1NUl0DF4W/gkm51jQ578RXfujDzC53nyU8FogQhEa8WSi+j5QQSuxD3K67hy2zQYOTBqBJCCGAbMz+fkJSk3bUt58Kys4mdG3FPrpLQQiJALXreeBcOhFCwZnfVin6zYgTDzcALozZDBtauiBOEHCAZgj9YdqBNVH/zYoidB84jWPn1TjjaCaIpAvYTYTelwiAe/sAs2VKAn/YIIobyqgjyyoI8NQoJNhkcGr4sDUdOy6IpLyjlTVjPs65Nze40ZCB7T2lZxnA1+BEwfVyP/6FrhPQZ2IHADpbUqYDwY2uJTNgaVTaQqOepKeViKoYOcm9dJx1w+laKDbL94zszJj3IKtlQ1OzMTKQhXbymGkSCmtcz2TBYUjMpN46qyluJDh6QrgeCUB4/da1U82zIOAxbssXnzdGUsj8SBqFQpc2GMXmM2DgT3M54WiMk1LYbVaYzJpyFGmWirtavl+sJdcXWIjtsoH6FuFLO1JENh8KHNJYOv4E8qa3zCK8fJf0hyoGA0CyFD6N9kXDThvnHPPV6qjyZdY4fne6MEGsukTwzY/atn3b9p9RwD4qp47IbawY71sUBhYdrGCUXA40tLcWnW+11SfnMSaAq+S73YiBICRdkt13QiWSHpJpjcjkx6o8S+aF6gpCQ/V3KbGU9Njrhd+4MWDzh9PLWr2VunhGIpCC0FtSvZwYVVbdSaaRW8RV/gdvItCLeZiCmyzNchuP3Oba/pcNcRCg8Ea39SmBdek2R0JfoUhAMhUzRsR8xF9fb1HpmkZ5NyaaVjt9xDayUZLV/Ibh+zEr+AcJle7hYwDZEbfWfuH1+kWWi3F3rl0VtZ1zjvDugrDFcST0FUqRqEvsWR/qubcp2zIAezWHiL1ykzm2XCvRBb33Pclg22ICA8MveP6uPUsUkDu9pATdXy9yNaeQvQbKr+Ba2uYuI33KgvAzBLszIVFoLF6MpbaiKxTT0LboOusuNRX7+7NSpPITQ2BIdDzNOfXnQxjlyXO1axinEZV+ZkG5oK9FXGFeqHEQqMqTnPCBTMaRYE9kavpDjtQHOwP2oNJPZUk5XlSzYOhkTABrq3tmtN/NhQFQaDAlsFmZFRWOaxDfEs8IBxPlpZ1vAkf/SZYYnACKGWxnHM5EBBIRqAxjEIYkhIf37vP2P68wvE9ZNuoktuNq/KMkoP31I1CC2EhgncFnPg801hIoswkW/JI+DHxz81GdLZwHVsRJPD7iJN/F6xqdQN9NRfuxHQABWKFNm0aQII5o1JF1NrcoqF3xk5q4fqP4AEs8B1qAuoOpaTzYsGCB2ZiUSwx8bm9ZjCKFtGFheVlmRLi0VxDHS7u1hLVRrFON4Bx6lKEHab3G7olEK7LV+ec/jO6gMQyAXoVA5n0zLMaGDbDLmUiWdz06Kot2yWW5Yw4DjZ4Dm8QUQpPyBmbH4ik1uey4Jb/C5uibtlunv91pcN9QWVefUNYiKBWBSp0LkYN3RZvmSFNoPWrJHgqb+xIZQnlR9/6/5p4gvyxPNk9HJFf7TqMt6LejSGvK7yy3eNbi2HUZZ/+P/7PyjBRCQCbGM/MBX5BkxkpSua8yZwIb/gbWAt9PqU6JNu/SzGWZN/UBkUKYj+6UPzaHMF8nMDZaXh3ru8dm8iOTfhNu4EqQiLv/pSam2Tt8oXOzI/nTGcD/6JA+GmvTGApXzx30xUK5e3AvqgQvwMn6Fy6Du07jtJLaS0M3WGyUf0GYJsv78z5c/m2lhrpd9CR1lUHjxKxARwYNOjWBzij4RYtUVGnTfFJ2Y0CQLbYfvZyNsCFYS3P9vMwiHh4cTYDE6aKWiCZKREwbXXyluAD5AK+A/C8MSaZNghGNX73NzBG9MvPivNRYz5b/46VbtK1GthXhZIzWFfKWVNRPQL+735ORgeoFt8IXPxLZFeFp1nlrzykLi+xosKdw8LwkCSDbXAbegLcybLq5YW44m8+8Lho0Npzu5DtR1HIYFu2So95n5T7Q/YhfEB4LuFxK7cc9X5bstWScbEDypivgTGjzToCxtUiScF1WncTeSKBrGZEhQbVUlW27dLDjXthcmpuTgoSadHEn0EKz/8uLRJOhAOZuYunJI2IWeJ6rCOCsP84uTOLzUXf+6R9VMiIKtn00EOWZiVAE0qnvQN9N+6IblRMCqLS8xYAfQIMyfjnr0HZVJIvEeboM9EpmtsnacSv6rS/fphCTRCk0dlihptQq9BVAfra+JKFYgLdlR6zvN1FhKsFgUK/cEd94cN3sqWdWtlPjfT50yz5DHEXelapaRyqDzl0iEQl52e8ZWXDV0ZrS7QQkxNTndNXrko5a7Bkgf8o/fmwjkCJyj21uUdzIlc3tezcfmd9oRt6NaD67mT3bTx62xsik/T47wFnTgh0U84ypBKXjjDwMtnD+grOm2SlOsOC7PmFo+99sOEbfDOIqii0sDSoATlblxJ1TUEKnbmmdM/e3X0z/5L6l/+vganamtzS3LMrHz3Fcc6BEplg07iFyXZ3Vw+BAaaG18q2phvOaQSmYcfZlGHPOoZcEM9HnszZraaQ7SXo+DgJPz8vXslGXEybg2vc8saSAyhrSxCYO2C32EAEDbOmNkwHIztIW/FCOMzSCXiCaXHXRxwErfiyApagM7XLsojJhH98wMyytgpfCdnDf3RUfffURcdKWWmKNwFHTnCAV8ZlpaZaKNMAmF/RHG9z5dAfKwZCR9QHqY+Gtyk6xEKG/YEEQIfKY95hpQcRWS5JW/cCa1Z3cMMJ+J56wJydhlcWAZUcB0/txSZHq7TIyFT8fT165I/xMw6eLW7VwbqIapPp1jgnI/u2SOqwBiAp0QQWHYCfeOo27/a8zNRF7T2m2/KppRQJOSu3hSnHYJ5wBacX7xnl9zu4khPguWKOmGtjoybUfx4q9+11koFLbpEP27R7ft5hdpRPPOCiApt3SDbtPo1ZNQx5hpKPc/w5En3yrj7+dVeO5zsd+0T7pPt8lFOfGIQzJxqpBjlALdvV86PFrueO144E4VxetDVYYVQqhWiQjlkDM6Buu/J349o5S2g9keSI6mgN1hGZdG15rqyYm+X6p4Zx94xuLsQsRQWnBQtnznOzK/NO9hVRRT7wqQIxc5tkuz0OQGdQKg2uZMBXkJgwtzgYyZHsMH6Kk9+2SoQNfsXz8ujplz3V29IAgi9AlAClACxoDMKYckQCvnEzUD9stoTQtbYgOe6PgNA98pvHlFk/qkcOKa6zPWLzoTNWZDvAABAAElEQVTgMRSF8czrPwFnEAjF5O5ZFGZWnC7lfVmNAw6kXBAQX+2P3rzXHwN5YEM2Fcyxd9ISpsFFfOQReaFpK/s1zWc5kkLjMqh9KrL9iUpuM8FwIDV445RY8PpVAXG/1ETee/FO8xd3RD7zVP2YoIiSyaXg7FT7kFQpPTu/8ebgmTe4dMUJaYRSdTW51X6T3x8comyGW7DwecX+qUs9xURoILqnp/vKOVFJuz8lC0NnpzPspwoB3jbXer4lWpxDZe7Iz+Js0Migm1q95U06S82O3i//oSlRRdXL3wUqwBWfgr3U8UOTozm37hIoX34v/vTTnmXH+JJy8J50xMhwtj6WLtursXZ4807/97+59KVfV8teWBDKDTIZCjo+yVipuOXW7LUafrX4L3YTgFG7mcV4wjvUaGejaxbz6/yT7lX5f6VkFeQTfF7hiaBzmFNAlTpaXPxkI6w09/dKR2739Hd8ACK5gAfoWI/bl5XDHi14io3GJIGsoFa2EVmO3aiFkR8/gOb0GV/ZUi6tBKXudgdDoXtsPgsa3JCXYRo6aJi4IJGLL5XnTfQV4edpiPxopytWEwkqAIxgtWq18jQ7CmGARMt/9fKB+EMHUZNGILoWZ/Adhbqv1/CmsN2ywtHLn/Uf7ckVf/R3X3D/9qCkRr2CD2h9i2eDgXzRkG20ioADvNi9HQLBEB1nsZZNBWSvv0h1aaCliUfpqZn0wPBop6huIAtjzfS74XVuUZTgGwgPrW5jGdN/faAAKB4HfxgGIsgNJksD55370yPuM+sFWbJ+BgIygo8XVMcjhERBiBOz2oVHTDwA3BiS4yssQDLsxZgpyJXCG1oic3bD239AcovPp9nqByQEMdMJ5Q4ov6dWaI7gdIGrzpNHnSkRDHIwLLh3q8StrR2IOJIbn4MAgZglUtq4x7oSacavXpNHmxn0rFrWm3FpPeKU0QbRm1EC7wuLIy9f4hqQh12kFtW2wLeyIt2TqKoSM8OgYl7h7Bt/LS7H1nUJdyfr378vF6HCzqG92N1xtZgfWjDzZu9bqs6IoOBvHLngPqE9y27XPg5tUTUD6KSXcQUNC05PuamkN1UmW+EaULdKNC9xQdQo6g+ig8CaDGtATBZFw9KJcIgReQJDobXTLrbHgwhwEaCZrWMN8dM+gEhjrbKsY5WZjcncuposqRwvYb753TvkcOl8Zt36wLbtomrPvbm47Quhwpo8PzvZEdHhhFmQtKqMvl6poOUGG1AAQmLm+gaC7pk33T/7OG+If0hrq/IRbqRZqMgbF+TRb/7yj070hnP4va4t6lMYWxzwN93sk0SKjyfHMwW6DIsQg0wgJFNcFhq/IHhwp7fjLRvB43H+8CV5ZVO7q28QJMRYnCRTRrLa1jax4EsXrqlUEMfFgALBoeYGAVjWpBSGaQZ4IObfYjCMu0jW2CDxbEIAdBDEbB8GOsw5QY/j4FkAFIY8ccJ1Dnp799GPiM+IGq2OZlH39gqjl0C63650EQU+fJRFetulscV/puMQEGu9Q7jKCRmDskewtxUVFmbDG1IaO9F+izMp25NdhkY5XFurTwfSd3zXRpbuDsgQKNwOwUhkC5DCF4IwsnSr7bzSTtw+N69iXzu/+293LrBpzfHx9n2SrIT5fIHcOT0ghgHDffsWEFIIk4YY7tjuiTb+NrJv7hZVfuktmd9lKfk6/BCLyVsNQ+KuUymIZFTn/A3PnyRNdfmPWJ3cWls0AqJxEG5paggzF8p6yVigiHJgYxKEGqIfx0fckibDN6YFrPHbW+Q4UOQ4qk2UZWcCJtKK7hT1VR+Ss2iAyNDeNtdW7330zBk5Xd0+Spismb0Wda0pyWCkN8/INmUQa/CYyssYCwQb7C50FXxLlRXH135EH6oF4FPQCYR2pEX5q3IgmwwV5row4AUHZkaOB1DrJPMpmOaGMNogJAEXjk4JrW4gWWpyrupmN2Pa8grnUOMIIcVyJzyDjt2nOpZDF3Dg88rz/AnRDpzZLVpU3AcX97ka4pgqy8fT8sXuZc+HpxRPgbdoe7Qi3Is4QMTyGAU9L2pVJuEsyf8eoctQdvpEtrjILLhyLQO+FuuFFxXVfTvpntIVI2eX3+J/axP+gmJRdagpqFEvVJ14Y4D68wf96ddGsPWKvj63ZpVwciFnKUKcAZJIzL5yhkt2xLl+PY5yaFllioMT4pO1k8M8utuZ2lTS/fJfiNLev31JwMe+/UFVhUVMTb+/JKNAEEuj5wefVlOFNaVh0BniBNOq+vfB+VNqBVPWOvpa+uAjU9G6ctsWkN3nmjeXdOyWNn7l21OP/kZ5bkV+7rRoClioLFcm3UF3ceOzrkmv4RAety5XE9TznvWFB7DBHc79pxF57Xeb3FY2mlIdcnfUNeZKOC9SJO5W/epMLJaAwSAUGta/SI9Nw1gUcM4Amktnc4RzA2KnTOn39bEBxpnL8koB4Wl1+QzlF5cIr6rtFZERK8P8JaAJ5bkjG1Nz5htUof9G5XJFZAxJUlpRDDY4jbIsMz/9rrnqg3+4P9paIoYYMpQDxPZg9AvSR1wMoolweLiFQBPsn6+M/u7NQuXxT5AysXAsGuZqpzz+ZJo14gXVj6zjOuf+jdl5d+PI8JpDUvWK0rDz504rY9CqD29xo4pvWWyMWa9dFljWmKWWR9hMbCXff2wylYhurAYhaBSJEg2+o1RW1AehwKpf31GyD778vUdc8ypJgoLGjRFuULUu3nNgiXXwEFOAXr3kDiA54MJmEYwrVwUoQHm1Ja4pZi5IgB0K+3tQ0xCYBkUP2AJtQKBhjD3IGIrtrAxVlXI8xPgt0eXJeJpFDiaSSB3JFrQVP7fHMTMOrh1UoWStMDDUiKIi4eQPWIR4C1YGdkBMGEMj79ot14g8NSKaaPiGYDC+nNWORxTMsClzo8GO2DOgOfRMr9ub62Hle32uETwU9aBhG5uJz8nxYtDuLfJ1ECREPjLmo+f/cru6XtyzgDbjLcRgGbOiVhjgqqxhxA3Vgd0uIlRf/JjY7tBATzY7JOZZ9RTDUoG8yKoWKVA4nOy9n6IYkGgi1BBW1KzT6Mj8naHoLhE2F8mhHcyHwRUB6u1nH200q87rGxl3ReodnVl0+4tkppwhNqYOo/jq4GvEjxjMoPvGFbn+Hw4JxOdzVkGajvCMNSPJyFy6SVULkVc+asjySTYoXx5soYNoEJqLfCD+0owvDMv1Jwnbs65My8PvuCDD9+bKCsRzLmH2ZqypbG2U68CQDLtEQtmE9gueSUGxf/06AcXlZQLT9WcpBoxBg9tkVxY5HGzz/F7cFVjFHAMamyKReOcGMhCNQ5nxtCFqBNuHM0um4vEyO3bkD94SAwYbj49ly7B+QHkaJC948ZXxZEp6feO6NPtS3rokrVA11jXUk2hrkWSrakU0aAdBSOoAdN9NF5UIT4fD2XBpdPZKV1yP1wFVUIDrNyQZHj4OoYUJmpplzAofyZoO14ziWdiiMeaY30jd+QViyIt9R25qDjAPrWo+Ax2HdHSskkwgOpHbGmU6EjMkYmO8+/eLFGxbLwvxhbJSDM5RgQjP0934ijaSxlB2nc8bsKU9kVZzBWlVhJqWsQzBi5mhTIuu1qcMNL7FSnC38N8ojAkpm9jmspU/OIuK6+xWCm91x3/DVcDKQvs/FkCx5CrbZbpvDQ5mm5vjy1v0+Og2s/EMwndsCh9/TaxnrEk0ADJuY++oBRjD/F4u9nGCqi4vJCVtQmH4EWqqEfm18tyYco+sdft2yO+QDZDSekaw/TrGo1SsYCfY23Kw2lmncC4WdUcY+QeRgOO4FTyIxMMYpiHJmUFvghd0NwTAYHJjjpphvgLxUSZGQkz3p31MXhgYR3ItCEL+ZMsjuyU9Q1iYdohY2MZWx4HLQhG3hiNuS7zjsD/xCf3xoz8rbgFEDQwKEcvCFqGJb+utf97lsg5KmaHBue8692X9nXAkggAPI9FQ1apwAPdLhTmYTuPnG6fBevxDSah9E25k2oiF/zmgL78mPzWzePeuqDvCFuhYhr/kmqm2FbLfN9SBcYRF1V+Se3UhFCo7tnYiJCq4qlZ+R9VgNKwWoGqKLPkqkSsSj+MBtTNzL+AdJcc46n3lf35/grCRVhxXE9KYnhek4xb8R26qacSaUAC1DJ5+1jc+6M+8rj37nCbhLArYu6mJ6G+J/ED4Jycn9wmRiuDoUCTSuRodi3RBotmjha0CUFZHJgfuLq6lDwAkEZ+oCOJ8Jn5ojZudvjVadQ46zLjFJUnWwe5WE7Jll35GmvGBInpktaoOSoU2yCSSk/cmKkvpOlfNBNZYrLhD2ntTLVPG2QoyiTaDaBhWUtWXy/WuMZmtB29AWDJsJcx2Wm+XlZnevOMPuZOGlA9pX8I8JXnudr+k4BQDFDVclFH4HowEQU06mih8hfI0KAXeA79cemnYF5QCtTel+OWiBhdKB0aH+1JRPqBcSjdi/xXoyUShp4+4L8JkWmUA0ujV4YVpKTtW726X69Iu61vmUkm3YsJ0UxTFYtIaIE5jzviKc/h7JOSjM3CaVo+m4xTvvIC7p/JbNOgWuhxIEgJ49ABmVvwBRVLCseT8l1qNPwiKicxjFjK59d0aHkw0sMeO7WKHHc1mDebRlRta3RvK5RgCZPwSEU/97hVOblDnnLu3dcKKS/TTSmglQU0h+d26yo4vNS8PHv60vvr3yvf9pOm9M9u2yjP/IEuwEbPOzNgzLedrz6Rj2ieHHnK/8WV/CdtbgpsLnT8n3N6eYAIPlArMDL7eue8xhZbBYGp20ZQhGhP70bQxv7RUYGtbhz9Ump/JiFb3zUxPj86/8EwiTzfv6+1zTzzuWSaACAAUNAkxUQcQA4YwHAbfMP+QWacQgA+swyMDl2w6D8wy9++rr7tPbvQWMMBk2C3+ohEg1qu0rMuJT4mggRFHJ7xpZuCef/9Dt409cNQyddQKBrK5Uu0M0BUL5jbNAkCvqgvkRkXr3bgmq0jAvtCRfvdYs7h85v6xEw9Q+5fVKBSVcDqWt+M8U5yBjm+dyRR2ozrY6nd0915/cYHk5tu744n/Z1spYZ98fQ1sFeDAIbmuTWZKBqdDd29IMsb9gumlM5dmpsTXeO77icMPJS/+Z+mJ+lX+hqqc3Z8SlzSyNHPvejwacV1d3AkCqyjz7Ncjfp6KI2TBpA3rpUl7EXp1pPFGWvX7JCAoCxYPKDdhvKipIX5AM5oXibW+YJUIlcLBg/iFkz2xgxCeG/auZ8KtVfxHR9C8uxUlAIWPJd3vNUoyGpZhjYqO8hCTbzAtOKLs9qEOd/HmGKA+des+o4gQDNk6n6EBIAoA3L9zV6677rsvfEHQM1+EgNocV2XJ4BBKCxdB569ItIk5ZjgbECxB45y4JtesN4blCtk/yAJQuXlsqWRb7YcHknzIKk535zeuaspdSl69xVtUhQHS165J9+1YlabrK1Rx0tpvvCFeCk0EAYWvXcsePizlJoeh+0shf+rkCXnENp7ozW8ek+tfWCPlMa/1wnl5BIebDWtrk5FG093PveQqdT6h+brEyYBihisoO42JBocoM6KEIMPJEBEHuobROejZCfevttiZNLKMDVcEaeL4Juj5H7qzN12TemVn+6TkGzZ6IjY7J1vwWUsSd0emrE3gItwJwL0gJPVOGbKzTdjwK0ivLCz1IjeEwhzILzzlMMfm65KM4lFg8xNAqFTtwAHJbXQgWXHnjh1M5y8vjcXGeGXTdpXSSMTd6rx7R5K5+/OFBRkirxAybk4+swEhJj3Cjde1EX7uISkqvMpR4xBDXim2bJGelDTwj6md9dvFNDJayWgz9NyU+/Jqd65Trp88KOxERWyYl7cYX4IVIZiKHOhBiN/pOBjsYq/cDmRce654WdD/fdMd9onnA1Hg6pZoOpkdvi+WE4u5eYvAdOj+Penx+Ji3zpAOwh9GnUIkQHysI47dcf9Mz+2wTgcM3ehzu1olGf1Om9tWopQZ3hgZ9ViINlRGkGQf0UpagO7S3hPYukkFf5W+xkbbT6fdbgGW7mOl7vfrXUzRJEwInxM4uHhRHuUXpsZO9xz8mGpSfwD2Ns3AcEFZiatpkMXPEPsgEI/rU55BuIbG4s+/ls7iizDayUa+1a6xRq67B9zzzDRRHM1DWBvj9jZ2BKCoHAhy6hp32DJTDseZyrHoVvOYpYAZQVrgTiP4hYwjetMOTy7vowsTXqJe+jvK63s6GiCcukyKycW/4h92XbWsjHSVqg9JKtT24nLi9/xfQYPbpwHsgKZY00bYUEbmJ+P9/NA1PPH4k4Eow77Q3j07/nhbFHNpSiQnnwmFvkyYJwXJdGhhItzTKcl8eszIqdOpKTE8rz6f2LF+seucmEjUVmuV+/IvyCUBIGADxVZ9Kb88UHRfV60QjoFgBkQ4zArpyiJu8+ghOhVzSJx3b6s8vnz5tdclJTYazySSkGvaFvZQBhQmUYUqv0PKU3b5Y3+7FNe2l3qchtJgK78LyvpwTuuUAKGBHnjB5UYzQC/DS2g2jItZToGOdXVNOcnZS/dItrQgSv67N+UrteFUHfsMCRiUOYqwOSwqeeleMkBLEwrAGBuGccCpGX0UaXPMDd2QZCha2kOLI7crJD5IF6u4SJQESUnrm/Z3hZmsPBk+JAQa4qNmsgGuQyOuFDA8LY8mpty5tLtKUegjTveGyeVyRUSeEO2G9fujh+R6fjIZ7ey0L/mqKuvnh/u6km1bVcGHQ9nrNy3UiM3CZGNHIEARLIOQItHQKpXctxWI/vaP/6dai7AVhmTIhN3vtLeoODxgHfeePKzIQDgfXYRo/2xIZXTFn6InTFSYqgfoIfbJKhTezs+PszvfvAi19NPSUsZ6a3DAVdemABPm6syMJsoJ8U2oiJeXBXJC5RVyDayBinKWCDxzEWFiXyaN1oBuXVkqLllivoRJVH2dRE0sPeFhUJfhMBAM5QGUGOg0p7wHV1eRCgEVpibaTK2NGyW+brppX5uMRJmNMXYnogyHQWjpTDJpUAnmC+rpKPwOCGtTa2PpWXyL1rDywKzVO8XDNBwMlK+oytQoM4+PCroiH4jZg6AukJAN3wHykAdvRVyp4CRbx0XoGjdAxtw4Wogoy9DC3TNu5141NLOzlSFQHlscqMUGdZaVSy6qYgoYZCzXBqXRh4ZCA8OFetJCQ1USWDY5KTossOjOHgl8+udFppmNyT4ZsZg3AEUFWW/6cY2NDDOTeK/syUZICWLccozjRxA+7BR7447KgbYQNaU6tOTdO3LbOe926rmrXFMXIvEUTUMq8gpTntatk2SDOgKJMEOcgxwNykCfee8oZcyEAU3854pOb/vyTVv8ExOZuh2lUlwhn2xzUaCKARwTDHKkkokYLYzXZ4QrCKpmqBBiFiicScNQfujCFbexw2NOqgBrmR5PLLrTc+4J5pcWS4PPzKQBqeub5ZXxIZnMJnidTCH+5hdM9wogoX/hCvNt4DHyLarMyW5UuY4v1dSM19yXN6gd4mMfIp6HpwTDMOwAwYrwZ5g9X2nV3sTkWAp+3rVLHiF6fPSffkauObgOljO+pS7kQG7GhLgBpASCQDkhYWZ42IbyfnDdfWWv5yecPuM62j0Vjy1Gds7edVub5C2ajm610bafR4cB2rrkLx1HASg8iSFCDHS+HiLq9rB8mYHHHK+bsB7UCFsImR9oIzmRqqK1mWly+P4z8qikUEbbTNz4iwjnK6SiAWlUVppRQoh6YYTMZ6CaWHHIvB3EnyLRhlCAvdvTaZtyvDC5SCS7KV/HK3mWzVy/sGQRH6w2U1ZMHYmXwuEwPm9qOwWGN5hVAcF7dCWNYN1EA0pUVQ35x1hHGvTKwzg8zUVHWKc/XiTSsQ8UqYPYsBMMb3VHRliMZ5qBNoGe6ZO/v7pJEuDOxRVbcB5pmJPE1VQGmGXjibW0eTi9NDufNfTIFwnlG/qzrkftWAiJWty+5UV28L2PHfOc2530l25E/uJJ+e7D29y+jZzFJ9c0I49siA+5QPRwAi0G0dsnO4x/RCtvAfSFKkXBaui27QxYqdqP40ijIrRn4aXceZcH3FR8DIfT+LAiNDGWKSqYz0zItb+0iM6F+SF6hJ4tznWHVRswA5neN87H1a+oSLG37YleSclmm6RcVHYqyGErcPe8/OzadPZXrjpC+sOP/C5EChNBv8PM0AYw8YJLqZgnZsS/0iCYzKeq0Nq1qNlB4fMhm+lEOfmggZtF9ceG7BvLf9XkyyogtCGcq6UTJF2OrGkarIr4TO9PBvJQq2jKENVAv6nCQWYn+vkmuxMt3n/LrT9ETsLTxViywWkveN+xxhXxKWV3IsAM0dXZZzn2a5AYbUA3tKkumr58BedKak6nnDjiDmlrMwo0mhaf04C45P8gEW1yRZExhUK5MRwae7TGydAeatHvmFJstkFNJMY4C09o682Mew4JnhlNUykvyPRX1LC1NreG2vXJj/2hxcElhD0ND6AAQyNOB2jdVEaWhGEgDCOFwxkY1eLg6BnMjel5gWqpVGFZMG+N9sX8fH5+gl0ZIP5MB70R2h4dH65j52f9PuaDcC28BxEnQi4QEEbPIABYfZ3bJLzghglHvr+vKCnei+BSWFsZSJjz/er+Xq/+fX6z/HEjURpmJoB/GBfE6jlFL/lp6YhqAYCe9Knp8MbcPviT2pCSM+3TTlvQxbWlskBfcQO79ea11dUVzEoLQpn0lQvJ187KJQME2CkwM5Twu5tJketBuRNRVdHXmwfmj0klWhebxbUJOYgVXDD6/oVUFSs8T/1V7f0snC71Ld6/TO96cuWqHFoKEauAP6JsonBLKltf6w7ttW3ARMAZALHFWqQJ+jObtwV8ik0Bgvz/nW+IYfncL03evZla0twA2c89x+S9JHhacieLTNpiyYAwkDqSaRIViwmoNaxsIqdehkw3JwFcwgVEhjCVoZY7dwQ8oXByovAeQwFpYvnKco65jczlmJ2TV/pspT6TaNE3at6uXUtrVMit6XDtbQIcIUry0Fa5tkmMixOChKw8fP3//K77yn4BkRBaLpqfta1ERMtMul6VgLU5IlFocPM6wEk0KW4eBOpioMP8BGwJM8mJenIBdXVJCDyTFFOeuXiFUZqW5rR5kCNneyv3tXoz9FFszJDbsFXecczHDUwOnigrk7cYUWFkwHDqqVNUJN17R+wjMw0NWZp7c/ae2x7zYoI4KlSN8TdT1zgJtJshS8ay+A4dDaFJyRmptvG6CCsTct3ZLnmU9rmZbveV7Z7mBfpjHU2S6RcytwExH3sQp9zmcu+7oFvClqwah8jz0RwvkF9W6Y+XsY9smZfdqI5aanaZ0Ql/VUXPvZSVgU4BwViNaMBoRV4O27RxQp+O/FAF45MtG2RuJHFiCFl9e4uX4kK3RXcvsPPZyIdJXOa9szkPoASFeIORdVRzxcIqHLa0aM6bneLUmVNNFGDrmgkmePmA81BuDg5YlQJxZr7gM1iTgp5hA8AK7QlRFaxUbb1owOLavGhpKlxRHMqKvGRuTOcVhVbXibj9zd84Dv1mtxLorX53b8Sta3TXrsst/ENH2JQzFoRfUs/Qln9sr5OeOnhQku3Nk1pcuiTXcOO1Jbe1TH1INcMEAhBVqCxHjPe/uyfXv8vGaDFxNW12E4aBDwFpIAQNy0c+OBgQMoKjwi3E76S3yq6q9UdrC/1DM2lVkDQUDGacD//gOL14XF45tE1qgRWwt/hLfxnPoHZIRuudA1/o+BjfsrDFrk35OPfZ3gF+j/jTvrKyQgph3nxeXjIh+0xAjNEhIkgTxAEVNH40zy0qThwaduvL3ec+LY/QLVeuiD6xCjbFdCIlwFNxGHtwwwAQ+TTGZNzSVE25X+b4MesSMpGnjtaS3FIRc5aIXxCB21styXDyUYkUU3QTk05121I6Dno86zoavfahzGPDssGXxWL+4oh7pMkd65Zk+xulkClmG2pfgH7QTmgbiFZFv5l2Gul1d8GfxDi0X46edIf2eLvjoKXfuO52AmNZA3lDIj5Uhz08oNVaSLn6iFbWAkD1+5pyzfKEOt2QSObmHWKoP1+eoUXpcaQJQkxQUIznwyFG9NfXvy6Xv/BL88gOEgTRuUd7xNbYLjhYSAhhhBAWhoU5/28L38CBKRKOMgNXgPbul9VWEMwSJhi6vNEFv/DBKX3UqwvxKQnGCNrQIsh1Xj8RnnExhb/8TjJYjH/lWguLJthSmVi1e2TK2wDjLmws2cgX3yblaGHyC2xWjpLRB2gsNB3eAqRAQK/e54/lQDJUbZd6bzviohZoEGwKxAx2icUkVDLPXxjpXqxsKbBnqXOXgrt3ehEFFDFnUNQvm8haf6pvOFghNgDdQgujUqAXTrgAu0fekmu6ppO50+Qtdw8QaXhKBgwfVr1EyVBZ8foWUStsRAYxCZJ+NTV46jSzVmbHk80q6fCVr99rfIApIe6Q4pNT6kfN/l2VhQ0a8ZD1kBW+Q/SnrcbdG5RvonvgYZT2SfLSJXXEfcz1YhER+70bERP8fMdwZinlV3DoD/rQclYjtiq8znpCTUdJ8H+4hnMgNo0v7vPmN8H5fCivpjDIwl1ZB5GgrtXafde6PJdeX/oQf2BIPgdRkpllzv8Q73+YpHQcBF8hx20oDu1EmBCkl6AcyuqrQLNqG55NiyRqA8ujv5PUgIuAY6rOnZXk6z+p6yiAlXQQGqSsLIrk2NqA3Fzs1OZ2ScaedDC8scxzesYsEsc/6J4Obitckl5+QMgUCCXsZYWLqjgK1qO6xZTG2+VUlSb9O6baj99h+djyKCjd/dMmtb0r/sh3z7qn1nup0XScgZunOy/fX5Ijs3I1s1BOoHWtf2ZCtF71ujIfe4/OzSX6RrhFGxJC27xB+y4QqFlTNHVPeg1oxbADcIT9A7kdvzQxPp4FikGvv+4eekg0YFUDAu4iTDENha+/JbwJQ4AMzEoBsuHRqA5c8OjoUfEGTa2AeAjfgj+CnIoKkKopCubM3bkpHcEkARCJobpIRCbQX77htmoFS9g9bEd+IiJdWVyYPRQdAuNCYCmUAsMqFAzi7GBmRlkZiGRzGCW5mYvFoAua31bev9HtPrXJrdZ6c/oKSA61HmuSHHD2mLhlBgP8SlENzmLMmIgF7GMOGMQEy9JSZsdJFq8/Pc9GBayADEakkU8dTa8dmp9gajmsVhRY+8Wgi97mWhZdNa4p+K1fcT1y27A1UxWM+nSTQZ/vDkL4teclVUVQlDNF7eqS21ZmWM26ObWHoHa80Gfvuw3Kp7GYuNlmjRDOb1xz65SdwawMYb1w0f3cbskBjw5j/5AqLV/A3e7yADGPGBbPMJ1Mc+Ojpi75fSnjPv+w+A+GEmgE9Kb5dQwL0J4gSKFAgLVbt759KchewlAy0dwSmBoQS82GSw2F+dG8rAVraE8qePy4pHriCVecXeJMTK7LytKwDezBqgaIkQr4xADxH7/sNgQc2wdDu3eLZyJB6FIJo/l9Gd9YHA6B8P/pGmCrQexZDulILFlRfTjtfd64kEzGGx8f6ktXt+Tz1rNfn4nVMMNFcuBz5rhyjcNzMek4G6ZJdQYRSdjJdn5PTC0deyP7scenXYNg3vK6xWuXk7ZwjlPsmHIw2C+5MVDZEhNWx2eDQGAU73kNOvzCNjkJh+4wlybik2TGaZSBJsU2QwD0ts3iWSFBEONIYDurLI154r7bq43NDn5EFnGDezTwhuiRA7POIAIiNEhPv+tolVs+wYtIFgTPIJXm947fn8X6V5a4L/6KsBdTWNfvjgY14B+OLOD2PHZIXgn75aAChqONGSgq37WgA0/hB4ap1+iHJsZkSqRBol1fYSeQJrHYaNJTZ4WBGB2joVEvnfeIv5iDjT+MTJk3wnxd4qyERZ56jFSupEi6j/eg5191e7ZKFTDnELlSkXo1gTAG8GCDagkagYZijMsmwOOlwB5WbPQAv6N8zBu8fFN2gTcRg+0rWUij7XOCZatZYQntMbdtUYpEHaHKfCkAPjyEnqHMyIWV55M7pb82a3laW1xCD1cwBqDGlMqGqpiftm+f1/gfPyzqDhWHPw8l0pIVCgdqqEe7Or/mVlnjmholAJRVdlr4GZggKcJ/O0SDiZnRICu4Bv4T+dcL9o/RKfauir0o2clNVRDeAsGgwNKCqBTi8fMSKzTvPRDI1jUGBgZEycIJaznQIuppRXoWMScYB715zB08ILJs4owxSqa8Hef+dkpW9RhspWBg0iV5wyMKtlYvGxDhoHAXyhCC1ZERm06ChjjxjrGOC1qvjQrlsLnwUo4C5NyIC0Xc01fl9a3q11Eb6m4EAA7pFTwFVsOwW5Gw4ugP1S6uS3HnB7Cbfkfcgwk8NLU7+IRs1kpQxdYmt67PScyyYEia/9QzoxWl6aLQQjh3jNuzR+OtA6+PD8lni8uClb982OWpiSytcTntgV/+HbfI913R2smNLteHkEig8CoS+lW5FOeQGtNcJqTy04NB4mRonzarYuSatal5gfitvzxuzBDIJIvaqkxNj3fNlu2IZFPevCGYpCHX/ZkYT/ckVoD9J7STCtlnn7jkMhvL4x8nehOCZ+ClcpaXV8otygR055NLGcBkU4e3bRwQqJq9LulsnGq2Z0h5g6jEnka75lnpwCky0A9f9PXD5KqdRvCcZz3vXXtAmGS9pHINAeFPM098kfjpwx9fiOhYZVPz6OVL3ryDj4XdscSPJsHqqyv6A8MXa8IudTtX9M7fNxGOFhTDca3whJcoLZXCXv+q4pDOa7Jwy6eauf+6TOykeJBCQr16/z+mhS4jbt1uRnMQbNrWbkLuY0YTfQbg8Iuinz97o46txbokO2ZNEaQbX5Br5BGDeknH37iFWfrfnzHkhX8MUtgivId400SmT4reyzW1NsHCdyDgWlTSNy2/Ahv2vENr/TSqouBixRkzL8KgAJgbdQ/2Mhj06qvuS1+S7oOY7lVeIZtMQj6GOdLpZ782BXaBUOiNOypjxSp54bBvfMbCvYhi21pOzsplejXJUsMLbEtaViGofP8TecXVoeGbk/VshAkxEpFM5OVJDgasrTzgufiSO37MGwa5PyhPYS2IIjCUBGBKJaUjIhXlHJOb34dKkboAnkxfUAbyLi9+uxYuuBAvrxYfJpwKA0BB7UI+qUU248bVMqDU2DHsxnV5grsVSYn2r20ijMgu3glgGXgLqm6WDXCPHZNr1rxdG3Q1HKfYJ7eYTBwPs6+gdlo1FpPfaRngL/ZsjvAOTlFztLqtyj8o76xZE2dmF4mLQsIzwKxwatE60kdUZGRkiplhNNXhHW5VU7ix2umMxhyXzmFYQXdR3JFeGjjdy/mqEEYFsEhR8XghWhKBp74QExrp08iEK4Alwcf3xNu0GuFpt3Ios/YybcsqqhwYXIk4Fpn4MVB4iUyvz8qyBPNI2XY/wFvK6WhMvmKN/4ufdwVRd/WKpIcYeKFB6DWIDlrLMQPajFKaufnFwelWTebYbrZtc3S9IOzIFKh8CuhMcAgi264uwZ0QY2V+fzqco9yJTCbE5zcPhGwxBuYSP77WhTg9XRwBEV28MnzLYKmqxFCodKzX8BA/EheEB8yeiSORSBjSpePgKJoCKq7JY/J4SZ1uXcd6rU3TDLCg7iD4BFhjNYJLNy245Jw3tR2wXlkX8um0sMhC15bNGTZBEZ4ArxRHU4lJ82HwZ0qLXfd9ya25wrXoCVpWBsrGRI6tNfKIX5pjEvmmvhBuCSEMXBeILsYdlcLT46Wy1Ir6mvyCtDjIuLxUHlHOeg5RUO3OUKhvWJztfbvkEV4SfYpehuhxjOvUgjdGB+vitFAX6PUj7hd/ken70n+dN1PEaFI1bu0uYa+CvHR+VU6W+ekw4aCspKrUj3JNs8D85sTSXMiUWWvcAzqLdXO4RtC1q9KM1qpyH4n4dM5ogKPPid6xd4TGBgLTswVzfdbLTLbhFes7moVvIWIVijJhY3jDuG73NnHyjxzx+BMEzB6Vh/fIR0iDrwWLQjQmX0d2tMeEeWjYZ5+TR5s2yqQXvkX5ofuzMnTGnGQI4cXbj6iIsSyNbvrPKfcpeSJqihzMQ4NF7/S7ooj8jqTQF/S7fZcG4XqfdZ9uHE8Cawf6EeakEyEG/JEya7rGmKzyAtlYuITeJ73pFvqdYrBnPcQ1YXEiPqdUp21QCZIHH9HKWgCltU5TopVALLgHop5wAECKzPtVq0EnElwwE4mw+FJL3/++N9kBzi9sLmuvEBTsz/FP9c0zlg8h1+3Ehtj3Ut2Ou/fkqBVTnk8+KWceEmexW1iICB38ABUuSRk0PCIXaGvDXfJMQYYhS/gI7oIxjIXKqwOBQBoGszT3lqEJtyj1GAwsVlGYHz5papJrgmi+rNuqqm9qVNa9vP0hCoKwqq2TfdUGiFiFPM2M3UFpZNG2aOxFeeuSXL43qW5wQCuatE1vUPWIHo2JyEA5jZU56DJV0+3rkumFdGoxGQmLiUIM89PT6lm4MKCM1ZZvnZF3Dj/uqpt8bOGaFI0ZiC3IkVAVYgO2xWe7j3YfUNV3oU8ALu1hZRiUNx8IUkMq+DLk9zbOkUkaM7Pz3dNNuqzWF47K8tN14qoUcILbwhQgxHoZtZNOeBMIz/GYNRpaJ/oWE6H1fu86Kl8IrsXSMgPFjAiqj/CB/668Us9eWbpFuy0ARs0SvrEgFOFCgBPqC8JcJhNZXrT5H9WVWaawsu0TNLoooQGz+fSadKHu0cJfwkz0e2m1FDbRkyAkzfmWYsDonYoA0/77tHuW0l51+P1DEdU31oWnuP7pEUKhki2eLRuSIbYQUryQcqWz3gqCcKsAFYvLXH6HMll5qahFHzP27QWUO5FRgz4IPDqCjmG+B5azrqxwbvB4t6TbHxOTgTcOtWiIAdWhWEx+0f6RiweHTK5hElQNragGU/jnJ0mqqkqsROM+XKOreaVHf6/T6I9e/rT+eB2xwux/7Z+XJYfGJTEnNgYEXtiKCDQ1ISFDclu3iticOimpPtc0StI1zQkDEAKm44s+S7emNZLqPfkdyQ07McXmLP54q26vV7OhIjM9PTSAXnQ1O4sxBb7OyYun5ba0aoKNbu/c5FJsD4MD4AkIEAx976o3ZPTko8JXJtURUMWcKyoLpBBBaGiI80zuKVRlWIboOBvuQbcnXMWwK2KnCrlz27ZT8NQn/kyY7n/fnNy43jUzCxBrcS8O5AXNHNwjyUA2+BK2MdIrb7i2mJQnvSRv4UThn3RsFTEKhRZ+8ANPITJTqKNeNvI2KcJiwfAwP4SPQY1YvQPxumx/f2h7jR0emJoLAgDX0oKuvrU/kQ74FubMGdjrzkZXV5dnRTvJ9hg1NdHSKsliYWHxG9/NfWiXN9CAYWccGTgGhzXXNZQUFRdd5ZrGYRoGP5shx2HA0BroZFN4ivcLh71V+Hg+2DKNhogB2xhzpy/Id4ACm9lQgb3RVBapBSnhDYiGookef9xzt/gKwv7iS/Jo317R1HARxJ/qWn9OJEN3QDc7ZScJw4XsAwHsrovJ77Lqbn4ONZ23b6vcomvD4dCzz3IZ2r7N9Ye2HxiaGRZBS6WlIwx0gmDg0hB7b6trQe0YXjCikJTZXMEMR70VeOp+YdGdGXD1F93NH06Q8lOP+Wsb89flSLfOjcXJkCIZZEdLjo5kTQr27lPvVK1WemGJ7VWmpn2tHaK06XRgt1UW/jFXhN+BC2VhV8QhvIAaYlcVLsamkMpPgWSi0t/nOtq814aHg6HJ7i5JRk/CPMb5gA+gM71mY1PUiBYbH5Nk9BFfpH+tLzB7NKlxHY1Axc2fQQnDw3gyNp5MeqSbkRmIziLZ0bNyzSEtzTWuq8uxQh2i0U6e9MIE9EhkjywSsxN+GCNi4AsXBSJ4j5sXi4nFhMl5xNhUagYF7m5czXRkZwrY5QaGzF34g1fc/6i9SsOyoBGNbzWiqDS4zUWB/Wg95sCYxDEIyciMGSqpJCZCp/9ODywUl0zPX7kfrRLDjsKJ5PkbVkkZGOOCIbcj3XBTvnwFdmXMDeKEWbrJunV0mM01hH94CtFEnAL5nTflervubWOsxS2FZCjJWvjsHVkDM6y50Ue8y1ChrW34zS+48QHP9aJTXueYaVW969ukWX69xzXpLY/e9lTJc33WcwXJDf7hQ9Z9KMwjR2QGGkR1qAUNa+1AweAHq8XzJ9yXPym3EJwjdjbrCQWJ6XTrI95FIqyFQa4BTodmDWGzvOX7qSIO+cJ/a7Td7/qF0WSKF40H+1xfruJlgmuiQqQLEL1bXXKN3vL50iBIFitChw46/8LcEpgLndbSWrY08Cffm+G6Udd3wU4IFMQg/FLcC+Rv3hX2lRSH747YnGFAFF35MoZ3GTdPyqWHWfVS/pTrZDCdMuLqK0RLMFqlgR03OSaHnLKeFmLHgj1Jd0QuhagZkGybXqNMUkn3r4/JzeMhOdCiIybXF6bc2aS4WIVyJ+u+BggX6jWtsYHZShE5lBliy+H4rMeE/n6nByhqup/4g4Fo0B+B1X1MWKiTG4x+46ai8IFtJeyEATEKgCxt4AuupL8vlcVEzltgZp3vZKS1tiojMsaJUBJ/Mi+B0MLTX3fbdzsD6SyVnhi23Y1zaktjh8OfDdzmlU397uRV9zK70XDj3KD+fRD+WJvUEjjOyJkTQgj2wkLbxpzQIQUo9Zsd3sir3+NJGHPZ27f9oejlE7SisCbRHxsnhFnOZz33hv5CI4dxZiTRe5BVH7vDW290ue8rp32+FiXvHlLm7L4vu1xMsupPTQDeHRrmeJdktZsNzJZdL6AFyhwLaNaQsfebA063GHQnsLDLLrpyiryr2tdt11PvgwTUwI3ZabYi9tmcClBEf384PGaxgBvLc3rlzQ9DUZ1pxhsf0AIfJr/3TUsFTSjWhCSsZnE09PDlW9KHNl3i+j2ZuGvKvM25H7wj8PG++f74g/1omGbPZAsgIASpJiQ5NBEqLl66cD1SQo1dcGYCc7NRxepunxvKev42WuLWT6iOH//Cg3IH9iRwi4YRHLzsM7+rcIpJJZiOY2bi8opzX9C+JiU1rdfglCnMd737D3IrCmjlVNtRmC6mXuJRjPXFGf2QsqMKG8TqW3QttzRn4k7cpqywcp2tYxqb/eW1KExXsKpkaWAsXKNaq6wsMDtbUDDO71iRvLxsIpHq2CjOSdCf4DgP9k7hWt2OXPivWJctpeaXlnTrBZ6gGxkaAthB4CEC5w895K1tIEZCdNugyfptOYXV/kC+38/sHHktGElNrlEQbLExY/Tmdtnqg/U5piPw1ny5Ob+9RbD76FAmywIbjXrgwoEX798XSwMFA27zNv+SzoEsyJVw8uXLPBUVsX2Ha2kLmAuC9SJb3BIIkEeZC1s8AWOTDELjNqsHZIYJYWEV9Mv/oiLI6Sv5BTm8jOW+cC3EKUjisLpAS0tugMEqdvAQqFqyZbNbWgxbgSjf4FAIjAxdvBCur5NWoGmg+/eSUwu93VK25kdzI6sawrmbuC4dHZ1+YYD6Mi4PAQWYxwXAhTDbwG6grXlB2Pjvfc+bjETgCsSwZ4ckY3CAtxjxAw1DqFc+CBS2670HAoXRNGPXEGMLIDm8LyikrAfbQDTImo1+WSil7IThZywInw3C7yX6JRviQ2j0gL+wecHDy7VslKljHzyixHV1lRWXTx2RhODpGzdlG26IL6LQ7UMMdQKC8fq+ekke/dGnxW2YUPHCUb11xz18SH6XyWyr3IlzrqpMjE7/XVdXFZzXDR4Z1qOy8BvMA4Flb9/yzogDrLNszyBLtDQQ9LHRqj8AIzIXqE+a0aKwNA4KlEygc3dcadBt0BVc3NbVuUvH5jZV4vHQ+nHhldGx5QBylmIbrCcH0ILBaPiHvqMwBr7JlmTmbsFOZBAMycFcljljUCakwoTjsjMkhHsGXbniHc/FWzSzRcf5EG7/utWS4EK/O7BdnAGEEaIFOHpuWln6n8RkolrT8lunTgtLWwSE8hCxo2UgPo05QWTGR+SeI+9Einxhrhkl231dzIH8Xi1eIiyBDwlRL0I53+6V6/3dcmwDboNlyC+IVV6VyPUn/vDus99qs9MioxvmFm51nXg98fGfV34qK2OLFSt2ip3W571QK1ICh/PX7BlfQeUwYgrh9wJAwyyErJVbkCXNYvOmanV3TXPDnn+FcUtJaRRccsWETtSKohtpQxqQ6gjhAlV4jjNV29fsqovkZ7abI35xuMPrzbJyibxbH9Xp+Z8mU/QXDU7vo14gRixJY33EqB3Fg8NNfhFSfDNGdKHHD0jIybxWnHNeAXHR71BTTIqtqkXqSC8ff0t+Z0szMNAYR2VgeSie1kWuPqKVtUALG9Kq8mRfbIAL/Cf8DfM7d5I939QEYXFgttaY/I7eQtFhyCwGVNxcsjg0GdZt5eCYnJmZxkJxt77R6zaCQafdUwRmsb+cUEqv1QlU8pfmMzcR9jYOR91haGrUAoxgP3W5BclUgORdI3iWIi1qUQk7wkuIagXeFRlynsbAQkujJMyk3LO35RQmCJ5CZ2/B3FuVOBGxxh1WIWWubEurKAGovMxtHZL9OUR1KgBar+9yvZn4S447DmIekkcdAdn1lIE+6HSvi+lEQa41XiE/vk18UEsqZ0azxQ6NBrVtzou216MOghYquHBerIUhj+r2oJ+ZNZhIKWu0cSuLfkKeyxl1s5wZCjATEymmd3bSTQ3LLXOjx8cG74rRr9majNQ3xA5JK9Tc6p7jyPIxOZdZbh8Yj0vMPwqcZTjE6Er1ZnULsasoCmItjc2QX7MASFuPDtSuralsLlh6fZ4nmGlUsS2jDWCOYQbNgKYFldq1/vDuP6pSxZemZW/MswOwJLinZ7JnVc+PTIjDRjJsK4Rtwu7sVh4C2aFzTGHCrmATNI+ZZryv8Xmvh67q69INy1TuvD170NXAxRo9AwEUKttKoQFjMUno9x3p9PZAiU26Y8vvrvx/pHNseRgN6YCBjYdXnsPKU2J1YSQoLyUeguEBTBuzDNAPLM6HmDwMqxuiWJPrTi7KCWkrJNUTMh5bV+ba4QLGcI52rdq4yTR7YF0809l5/IX4I5/QKpaWpscGdfNvGXI4P+ppLSRRZfqDvik6SPuLC1MM5Kji9EFv/YM/o+NguQ/oLzhWMZcDmWJ7UVDQZ8OyNO5ZZfd6DZBtZC2SPkIK3smB+tv/x96bAFd6HHee9e4LwMPDw30D3biBBvo+eXaTFC+ROkeWNLK19tiyYyIcsTGxsTMRs9r1OLzr2Vg7dic2xvbYY48syZJsihQlkRQlNs/uJvu+u3Efjfs+H4B37i+zHmRZptigLWkZMczoQH/f+66qrKzMf2ZlVf1z/yjm3fZLXvjzicf+dR23u9yeaGjCnd4sL5PmAAeIui8UxenIy4nHN4BlUDKRLi53ra2kwlFFMaGAZ0+Ho5i+gwoMkf9Xv0MOXbkhl9+dXt901FbLOXFyj9tvY++MEO3dl9tRk5OQrpyaW0jHU9EC4UN+gdMTzS0bX+IY3VFS7vTl+XkJpyuLKWQUjAJ5Kos9/kDsWn/QoqrSMtfcfFGniHoy5ThYtoY3wDGL2iUXVtZm1/N0Wb/hwdXaLt8jD9JGZm1y1ZvH1qRShbzd1U3VqxUNqxlmOxEHKo3k1xckVuSjnypeLazLzevMNMxL8cKetVB1fkZTRkp8K5Gd7tii3OZLxtrb0wXFLqdiRroWQzHWXsDG3Y8U198rQuturRL5wbGDURSPcA4Ojb0PPEWmvMi2QrY8lhJbzSJQ+M6sVYvrnQ5XQjawHLuE2TVl0fhAj9oYTkbvoOdkuiTf8Ht37o844ptl5TFOCZqWNoczLilDYfVaZi0GbwtYMQ3HrNT3tG85viy1A/yBUy0u5IBBBWClnWm9tCguDS4ThA6trkl7iiLNR+VbYffand6NhlYx6kM9CR783qty2wMH0JVOTD5ZMRBDW8TDrBvMLx6fc2REvUSErKrSgQNhldM8q89etw6tfJJEsta2Q5+UyrJSy8cCi7m6zG18JZ5XmZdclWJ7gh6UcjgS+1KJvJBpoqBbAAqEZ8r8Q5sdV1zm8rpSU6yurjaMdmEKYkQ7azB/zcWykOlM92VhF03Rui8YZudlhHNiGtNipc7pdUeqPO5ccoYEGjQ1xv0Rf1Jdi9LaeDDsdukqMb6cFFN3UKmtrdxlGNP3VzPEL3Jy+dVFdKOzIG3Llx6bbN8flCgCOmVuFV4x3AFhe/BSwD24ahAWjqE29cqlbC+9ZB5/POu4Aqr4JVik4uRzOZ3Lq+rrwrm+QUPPg69QKM/V0JCyyAkEzyNMXIYePSSfoIn5BXJ7nU89kY5JJxCTSWMhm7aH4b+xDUO0SrTBne5Y1wFPqK6EY9f0eMPhKKlT1g67Ar7ZnrlcXCsZtfZ84r4E75HbXDKGJlKnzK/d4SqqdJU0SSMVBT3RxqgnL5BWFiXGZtha/eIpadl//2ldUVvjFp61tZvP9ly4bB76NBqYCEdoeCgLZxF8RNcOtlNgbD9PlCvr8GBpO69G+1BnO7vWU4urFsLyDvRJRafEiVypxGTPMiIBPXCPCeqOZ6RVQ/gt9AJrHa1Q0R0t5gBS1O8w9c3SrdYX40zPs0PTtB2zKVyZRFr1mzc/VL7p9LD7Hko1s16zumAfhxtYYt5vX0vv2El6vTpOMK2+xZvJL6g6pF2sNJh2OMsWROqipNwkk95FEVT35pq3OL9mp6tYVzoNplba29eU9+KqUZ37jnKXjLIS8R/f8vHlpw/p/XDg6pJ5Go8EzZAn6Qwst30HIKAQFsBZt2XfUH0+kQXp+wQrkUO6MOTMzfFWVLrwwiE0/+YmaAn6Ig6/yziY+FojJikVyHGH/bksdskU0d756N6a6uZgSYmckqyB0IZHOTTuO2xUaNa1k9K5ReVtpQPRt/AkGoAY+NjE/sKGWb1FdVqmoqLclaHd4EHJkDBPzJnb83KMAW7EX8oxTVoLPP+Pf8I8fUQu7aqVrFdVdWIUHD7jGs5CLnpGE1Ez1S31BbKoD2osoKeeuORN2P7ywJxZmTUZVcVvKO6R924RxVJdZZqKJJRWVy8XQq3VOoI8KbMaIGYIEb6xr4ugpDCR/BN2KXNxCywDXCZI+j7+Jv5fRuL98c3507c5QwuN3CK7Uazk+vB0IDeXhb7kNp84cdhS34Cc+eMflAEuUeXUO0eUQzbogwprYAEi2YJML86YARZgVThJvUgP2VF/+ITwMja7hhFZuCZ3XSbBXpOsOAbPUWfkT8VWrv4Utel5O6tY5bC5pWniSSCbX1awsgBAlvPJCBdJ1YFQsJ1d4oRDBAKIBlq1gx5GW1JyGzdExVWGsgCnKy2+vaj1LeIjB7W22CDswvqSCMqpt8x9DyQ9UYdVsktDi0/fb+JL8ozzlumekQze90V0QYwWwAvCcvDBG3ps5UYPfz5/gBJ4wyUqmyQYExezy/CSv0DsDOXAAUQDEem2WDocMl3rkgcEjW81lp69+5+d+nMZ63bOCwyDmu7DeOeIDMCfjY2eZ668fcE8+Kjgaiwf7WIxG95raMa8JL9K4i7feg9CjagKEb7BrmK9dZHB0l+6x4WSw/6Bw7Rj/3SR+X2vKiIudAJOImaPsrKNhKa4CUzL/Wymwj7OG4msmpjQpVx/+kX/vPP3527tPbS1m+bikmt1CTG3sVtfNLQ5t+bTxM7kbBLgUlInYMuZiQWbqpKBcDYrhQHrJQIa0t7m1GXEStEQs0ccb78e6+xIZ/E7K4739ky8Jbotz7UW6umZ7V506ZR65r9m3Glvp3RxpPDsi3Nd2vu9Ic/GdGJ9cdO6N0jYD980v/kF+U5matrR0uzL89l0VBk/ra50anRk5vbSwmyq/YCo17nR+FBfqroiFZuTzgVuPv3DczFt0AAAQABJREFUtYYm6fKF+cnkuuzwBPm8C2+fjLU2JSPgYHTW6lLPyVhdtRyvjiX9qVjQn4nWqLGMe5f6ZmKr8nJ2Z16LOQr1kc14msETjzdNKB3CYhLXJMcJqmOZhNmlcrQOmzl+8+YuFtgWVSQuSPcbUy2d7KEjcjH3g/Nn3nY88RtlE5fmOC1jUog/i9Gf+bPZT/wvTWbvUX430Roz2bv21eeiDXQKsz46UVkDF6V3jfZtRhO3wFWQM5OMr6cDvjSKDzp93eQXxcKFos78ofjypujxQJ7cujSy0XMjaTezxqgBJnAGIQJqff2ShmdD70xfptTf+JZc+sTHjMvLDITV8Qlp6vwm+fr1S4IFGZOBNXZSHzZicUbE3NoIMOgllkpTe8/YSDyRbm3hCcKec3iVIyf7q/eox84v2FfV1gNffbv+qTYgQ3Gl6PUv/f74HzyeHBmQdqkqZ1ZXLOiT45eeT2MS2prTbaokTvYIzxOodjrbpuShWEe1pDRNHgqza6wNm5gwQ2+tPP0rYsAmJxMVVcmFxQx6H/r2t80XfzvNaiocu00mMTOTTepb2WSRjOTc0pKOiRE/da4mKquk4iupTL4/eb1byyaCLOMP9rursys5eY48HWGpO1bmKPSxAKWu+W0czcvu8zeDOgNt2Wu++10ZSoUwZvhd+EXoaAisg7pEdUJoz9vDpmMka95wzGji138g9+3ZJ4vF71IOMxRGSl5bazaR8uLrabZGdannw3Q+2mIVoIIMx82LLwoCnJ2R04XFNBZi8KoeT4rXR0kYGIFoE/FStEAMs5RVJN17OuRCosWPhfR6Rm5LtyqvjEfqI6+9sMIx/Q7rG6kQpZFxOv2Tq1TKJjeyfA5LhuzdzRWcXNIFF86cXD58ULj3/LPJJx4zlaXC1RKy8a5ft2t1sqFv/WPNv7Ivbpxofvg7VVTtTzKNHojZ4AnnJ1ioAAJKEgzJ2Vp+ACiASLfq6P3UcIKUKh/bxdL/6DusytjgWZ6WohL1QEHb1qcX4Lnh/FgfG1/95ZfN8eNyFy+n7kgvPIQAE4zG0304rq9lOZBEghk2CmHz8zMD/ekFRTeJTBKXtaBQOsvsQur11wWOQ4xNASkZEsEYQ7QjAkPmlD1mQc7BOwuPfEziAWujS6zx5YuJ2nE7HOuxTIil5ZmJ/t3Uo5/3r42sel3yxv7BFMvA3r4pbCQplNeeUWTRyNoBflO/UwwSZBME5OhD2h4HIsnsmCENl4qb1WUZK4BUW2R74sS4+Ax4uRAxjvKOokRuvgTQIK/HxTOM4EBXrqTnl1A+UHOLee6CebLTuJlezFO4FoOD3e+IeJNPldM3Ong7nlRfBctFa1q5ZUSdYXzpVGpFsBaAJ4VX2fUA0ireFNUfCZaV4WnInetDU77CHBa44nhoSEJ5C/KzmUTVI/6s1zcipy215v9+wXx2nxyX5ovA23AJ2ixGxI2qyBXJSnoVrKxi3LdItBHAb2p4kRpZ+oil8Xmxz5f1RO/N/m7/QwOBpaD55WyP4FiW5K1wyzmAgxGn04NlXTEbhUrP/PD0Kcex32yNkT8AhmYbbxKdUUzGfP1/7f3sX9xjag5xLJ5uvN985a9y22rldKi7qD7XyTYgaOm5RObmMOvyc7w0I0kGGJ+owiWa9QNCotFYnDZmjm7tC6LaOTN/eaRgf6Ncw4bhBOtQ3uK3Xs4/sQ9lWFAjAOzK6TViQCxcAWEShtXT4PgCTYwakZ/fnWztAS/jG+aIM7tiEzG4y73mqRPyCEiAU1QHOzFCrKH1xcey+0wiloQ4b6r85I6b9haxVsMq4fPr5krcRITf2bVJ5GiLUHuXtLapHtF+NuTX9WDEVZsny0YzzwK437FQMNwzboU1mRX7rRds638+jg5VLCYjuvNbrhfM+fkS0Qb+ET+HkDZ0fuEh8Y/yEo7pU72YQjvih19KetGrb8ttywnpSqqVJUv5XZ0KuW+LLBsSG9I/LKwK5Lolbyeq2Gl5qeLxrs+RveWbkifGxrAmNgpZX2/qh02bNvPgVnRm660//T93WVGhAeq3pvxhJhEr2/1/mX0Fdtoe8dOl1N8xsK16YWjWpNatMjDTZYJTHLQ0djBmOlKy8bqe3cXP/Mef2M4v78/dKmlksJNGp7VX2DULCGYbcqh7s6rMnHlLNPnhe0xeeUim+OMY9MSiwSAbCWSnRzAoAcYHSUHgXACOis3azLrflWK6dnZlYrylmZmpAWnHdJH5xh9OP/xgakLhSF6r8dVXum3+wfJyw46Um/EKsjbnkkCi4qIU+AZCqA7v3QqicL625mqsty/3VFSZxflTzwtL2aCW8r/6vBS7rDR97rQZLsZmSCfYvcdE6kOhsMiMIxJ0MaKBYoBSyZamJE7axXNyRvrr0tJmUkUbSNR9KT6PltkjOqwgkvEkEglFaGR8gR2H+uUR1nm/eNsU+DMYXehry+Y/BrJwTXIZ5jYLpuXx2mpdQI2OqCHMQCa2Oe1Y6JVe1nMrJQtR3JiNxOXO9fMjGYczWBTk+HAXAy8Mgi1zLNC4cofv8ePuN05yltrX7mJVRKVoLOOdm8AL4uyZ75pPkVPnNOeuyDV8v5H+RN6svHlqMsOoBUXouyWGCkhN3outBSoPU2XHH0CBjJNgjSwGxe7SFih5iK7uJNFlY81OAnnjVen5dmdbIi43E+bX75XbgAin3swwheypj8ophr6jORvgQUZQPZUV8nse700kikA05GNBDMGQmKiDMiW1xIVyRTmp5/pU7cbMJJ6k3MXbSnOyWw7EVtLsSBPSKVtcIrcKJsWlclI7EK0dNtvcyDB0gENos60o3v6ueGZV5CScm2K9IDyZYHUepw99zm9qdGFHnNgbSyzHbIGOl8xVl7PnehycDfHaS5dSdmURTmOkBervTFxm0IlRC6teve54JM+TWBKPKByevXnS2Yojh2AhhMEArvLVixyaZ98x9zWIoYLoTLQFeXcWGSP/QH+Le7jqTss2ymA7CN8A9zicIw3Te9PU1ma52H1bGgWIZhcZZ6lAXmL7NY8w7MYAM4QkMLsJu9atxrKpWjSBFQDWoOd++GzHXijMSz/gfmEXLpm3oVYS6SAqiSfpceeRP8EwkcdPpk+Fpl5dOC9+XUm5VDydkWWTmMGIIEMTExm292XqI9TQkCma3SzNk/ROCN6werudkC1jm1PTsRERjOtX0wd+pT6XtSBvSDfH7QjWlSZHgYvmxec2F+bNU0/Jz2U7gum12PVr2WEi7I3Pa373v0rZfmufhBWRXnxIiLo7h5IlhSJPSAutaeOFRHy4xKkN68I3snjsoNOPXheDSkNc1m517Kik2jrUwGLVmNLt9wt/vnrd/MY+GVuYGJUPORzJzKa5claO7ZttQ/zpefNkuTCZUkF0PYLHtsUpQyaT3lm1efOMlDyxmTp/ITvU/fDDItJx8cLM3k7T9/bc3FSSOD1UUesPBpLBoLCYhsPAx+bk94GYyA8CaQENaPtDel8cKM7N5lTTmxiKRoQkeKYTURqc2UzOlmbpfbJzGv132rjzWCNqU1aNgNBHaBBUIVRZ4VhfLyoS60KMA7WHpGVHb+bmmH0xNigtTh98/r+sH27PTkImcxgdbiPi9NwaZtLKuwQV0bsqdYoCp/STMLjWr5e45nCE2ytthrc3J+ycHv/ys2Id9rnNWDybREf5rmHTk2avXDEPlpnPtWW3CiCnK53M3BkQTYr8E21BxSlKlPxDrFGJqmL6d2/cDDB7R1UuyoRyWjH+Bivx6rgKb9B75RM/Juqp3DK3Nk3O2Wyx2zo3TIx0QbfdesWfWDbTjvUeQVzD3ZvuRaqa9mUERZjLGAOnjVXc9zAb22EH1US6mBuwwzz+hOf0Kblt3/4APVQL54wlnaNDKd285dw56Q7YwdPaR+CZc6uo8tT/f2TdgBX8qUVzUJxEOvMa1pQxDDOnKAsP85GPmIzAvFAF20pg7eJ20UniNX3DRhWApKghWWpP3iWTU9/703/g7gQuTTBrudAz+1hwRJsVBcJ83ZaW7GhJ1Q5TXe93bkq7AMwQ+yKVnwKdGHylz2jSj0QBwG4WoNBmPwXTEV079R5EhhNiY4ue1dXbr2+0SgKMVNAd9KHHrGY+Se1+ush3P0cHoxDFruvUrwq4ePeH/il3UMEh+r72+I+1SCzPqTlf/tVVwAa90qpfRBvjH8WVIf4+Jb5Er37NqhQ9/Jl/7uiV0aTJXbYIQnXLxOT65W6uDPZnWj/ZEqouMJe12b1ef5nvyBFRNQCG3qS5ro8X3k3UqQGSAFn5KdBjyotukXf90kkU4rsRv1PO7+il2nUzvWl07MPcwzoirHqvj6Gj0G8I4YTeBurS9nm31/1TfxMx3T6NXZ7N0ZXfwy1lWIKVoVg3pRNkkEQy7BC/IxR0+Xzf/Wvxyh75VBRvITk2aZd7Juosa1nU1+kzYVKlz5+Xw+rqFFKFnMXPXOU0lO+eG1oFtUNAuspS9KPZuZcWNB4ErSCSuCldaWEmuTyfnpsV5VxT42DNbk9mw6mj/4y5MSrgCbi4FFtKbFy5U/DUvQJLkR4U0OpyU70oBmwhtmFCpzazI0pjo6gJBnChtVVTeW911g1KZ5zLy5PDUqDShtxosWt1MWXz6DB1HFgtA8okzs2cpQKElM6fSrhKw26NYVMXaqeJYGIuczzSo2z2yK9Wiu54XTHZ48ckkT3oExyWV+BeurMcLnbatwsajoTcy6KoAFuRcj/VWRud4pQIHO7c/sMiMvVNbuMgcnWBY1mBu3O3e9deUxzlzMUgMrpEQ3OB8bHh/3dwSXUJ+2DgxeAV2Bqhy/Bl1taEq8DjmzdlcrblCb7WzFxWKVfPSHSWukAkzAD9AccYJOivXjZPHzAvKdBtvG72BDbCec61NQF2b52VpWPvqKWjMcoDWVjA17GGjLFYhH3tumlsyHrlf3bK3F8ky8JC631jNFlu1JdksVI4/OA9poHV30T5hCqnZTQByJwU7u2IyiZaJFxBiBYWHf5DTAQ6dUr8KLAsRPMBgnWkU+Y74b5ZDATKBM42tThTrNmMCt6Iu+am59nqkonvN4VXXCUDltPyDdZtrLL2PhKKg29sGsCxjzphIpsw2zlssI7wgh3CojCSxaFaCjFgRIXP2fwKorS+HE86R9rLZFJVlWsEjUf/5i3OKltyGDmxzhtlTtRJO0McV1ZJHQWKadYMYm7HhahySaHMTAPCQbycBoWBEH4XnoD1r+A8ppGnbJF4IZfsqDWCgTtnBZVP0CjIRmVE3kBLvflmduI+x5g8utLVG3JpPWkaiGmouqVerppK+RWanVma2sjLj+fp8pgOj+vyGyssqwjhIyM8sRXhMHMXMdi0uO1WMIdaW9bBLqwpzgAeAkR1aAjbssLB6iofq60TyM+ZlF+phl12Rhos7Ub5EJEdQ0VkZ4UZ1+Yws7rnskkvH/uYyMOTLfJm1A5NiTS9eVlOH9jHEHMmEBbV4NtIXLkqIgTRZfhI34jZpRxGqNh8wVrKfbsZ+hbOU0KI4gDarNTBLvwrizIPFInAwFViinJbWrJb7RtoUJw9Wg162Gl6bpp9XdmIBr8QhrDNRyFhHbin94pwDy3EXEeNwwh/vv6i+R+/KG8AZU2NJWlleAhlEonugTRaBcLhp0hWAqkOTzGSacl28OzJh/9tgwPPrpmPqmzAW7i3nBb7DVWh0nWbEI7pUDTul78pv//Bv5K1DdanlgMh7dCgUkSBLg3l5DjGx/v7pSPh5JDDhqXoPi2KtaR8aWIoSUtBSHc5AZ+4rLoBIWmIBL0Y+kG3OAaiPjQPkName/TraZDRDKc1iaoNohtFndUywRRLwWfmph5plPvmB0XPqK6S0xl1247KoQhM1/6wTcUXwV2YZ4wdQmK5hJQVy5mk9xBZ0uCSoVClGXOCiYslcomi0oOswtxHvsvWGKBqDrnhJ0nhgKwDjh1DF0G+kHtsIF5BarqGefJKmOEd9uoKm/Cvah/bNudmRsa5c242wcIwuw/LOyrIR6ROPWoimY5ZvcdUHjQPaGFpFXoCAQ+QxuzI8Cs39cXyOVgNVzUDXRxXMWYfAFLzK7xdS2ZVIgk1K6uOyoPl2bD48QdNfpuCYeNh0sGoZoerSkK74udghSGqg1QJp7ZBSBT0nDG/6hKjhjaGXG6JI9sFHlCPONLoGTgGxVhaLOLPKACoq4s/e844BXyZ8mIp42ubRmVB3C3gmkr0u8wXGtnygpghD64hcVHIy8qLLKW6fur/PMPZ0RP+f3fS7BNoYN5I3X38R+7bIq2E4W/+VuMOq/+pylJuotYYWJr+50JUdoxBLRUjEmuD7ACLpwjNz9EdkDdbQXz/r75pjqr9LJgSTdKqn1ejdJeCiBBrUAHTYG1NHe8tjHqTQ/xeiP2wJpJETwiNH4vVj0rP+/qz5iXgjfwqkZr3FnWuKr9Fv2Ed4Z6lm3d7cOvGX97/uJVbZs2wEISN6cxuiot1SEtBXc7qPehGyIqiHv7c/rw/dyvaUe5mdABBvD4T8Kbm1dXhFOQ9NJSNvD5eGye9bP8XyvjdW4pe63bl5iSmxUh4mNS7qyOrGIA5ebl23jY2ns7JIMn4uNTxweOO3NqS9lrRqa6Qrzov4inK9zmUV6CtO3duXFjnEvNzwILzc8I3hpIK6jyLwzG0JYRD8oMfmAcelBP2YsoNsjwC+/Vo3zl37st/vPy53XIb+Bw/wY5gYJ8YsgAWUxeosJoEc1W+iOKVW/G1BPvx8fuL31qprUqRbcVFCJyE0NqACj4VAy1lNR4nIBdAE8px+H2F6VGO72ednmVJt4AuDZodxMlY+Vq7uHfJrLtMW61cYuoqap2ZGBzPD6/mtdeaRnZiquc0cCLg9DrzJwc5Dn7j28FDLSyHl1srWscfXQ8VJtNronsHbiTTo+/srFcusKYHNdzDDpqq3ujHwGfr6za1FP1aJvD153mk+kilf3Px5WdWwbjQyqq53W/6te8fzBO9SZGsJ4ZuZQiIMCqExwjkVddGQCQBe1wIPAfoUKNgwd99VI4LHGZkMJVIyksg9pANMZ9BsTIjbcARSgQBTci5AuB++zk5JTjH2yzo7CoQPKELvTJ04PR0spJ32mV517ZfuvgAXRtpCMkDb75hU+IANIUlJFUJH4DywOjKGhSmmRxLkzFIQ9vORjlFE2ll+REnxFahMCrNynZb3pJceXluXnqhwNk/xGGbc+PVk/LbwUMCTRylZbGL3S++KO871iVi3Ip1I5h9cwWTf+992UUd4VttbdaZBENTUj4NiduQkR0I7EqeTzyBELiZ98Wllf75XFK70mkmZsitZoNwACWE9uhOiHg4EAN0d0bEbrHsOIRGZV6yFWkKA7zG5jHkAqF2wVFWbuEPXod9G+NXMOEPv2Y+c0xuoyFAS3RnCM4j4fZtnH5l2vxOfdYucAquun5DboN/SAgcU49Gasojg0AzhfJVdC0babh6FffDkUpcuiDtwtdPPO4LkuUL6x51ONdWkSKIDkjZyEvkL8SQEQMyrFUIURe8R363DiQ+YZxot8qtVDU/3zU4xG14uXUfSUt/t/fR8fr7J/tE7OASj5MEBbV6UkwzQ/lQZYhQC3JYqQ1Ojz5wQHgV1mbid6I0f/2XogE6OyT/kJshyoMKam82p1UGH9onhbEcZkVJeAgnaREIIeTgJgaTxdnaxcO3fm9NgUjF0LA5p3U/3CQVtzCF3kELsrQ1dH/U3GT8UN1LTmlKKmJ9zq+eNZ/YZepqhe0QCo3qWh+PBjpxWGJA0AYpEw5xxsi4hNLpFGWj4SAYQrDMOtV8ER1IuyOxkLJTDj6kbXLgsC/bzd8YMeGULKOnutjUEilgvdNJec0T+Sa/tfw3ysWsByrTyYERb1HErCluYZwUAGRNBR2HllYixQGIdua88Wgu6Kc+nqxq8Bc3i8J1h0PtufmO3GBuWuJY6b6B8aH4G2fkseSamdgKMyP9tTToVnm42ps2tfKErhBDkjkhRtQ9dPHid7++qiuomzenZApWRn4VokcC4xpL5JgO58oN2pVqJ67NkQ1uowm/f820bchtqp8kyI1lUjUvA311TBWrzBpZ1CB63pqAh0GyU9mYurz9HxF4DiKaipW0aRTTo4noA7tkmZGinVxyHQ0ar9O1IR0p5+tfM4c72FrEVV3BaW7BRmc0GYxNczx/YzIz+kLUbnQIe1mBdPc+jDyXSHuRHlJfK8dVLUW/80nHt5/hsKClIDm3+I2/EgsLqc6zhx+Iv8Aa6mwhdcgT9xIcyvNk7VDZAWnwRVVPeWyzLXvbb87DazGCqLPbqsdyE2ZAW3Y79bFcOILo0hZuU16tyLykJG8tkxhB3ESITp8WPdb1kVJOy+ty5nuGnn9W+gFL7ufFJa4KvdNvAFnIg0X2fSonMbny9/KmZ/IHi2gvITMoUh3NAnclKw+VSMLRwyod3pXPNJsLb8r9NYxoyv/bJetWlascaOkkWACbXtEXNCuHs82/3Vfe5T56Hq+F6OXJ2UV3AP/LTF6bxYKgvYnNQW+tmU92GhuHeWS3Keg1Z8WIbWvUxXKVJsYu2zi4mLpogWvkDm+4dFFGPWWVBFAiRMrH8DCaH2Kz4EO0jhze/UPwSs2L1AU7rLZF0jjjWxEWDj4ghEbSGLsoMUqo1Zbj+q2F4IGoyCh/+RFSjfBzLjti/D7In1hZHBcNHfbHu28LZJxWUIXtL22N5JYqb9k9J1pQWqdxE1IlEglHONcFVITwkCBMOhRfBpRZvfnVt027X0CVtfGkcoWK8jZviliEOvbLGkzA7Ru9nL7y1cmGqvVvvsah+eyDMulF43GKGzY2uMuaJ/okH8ykxUywNoAr6BVYZIUuHP6VQxNqsyRZHJhogS+iVlsnIMbajLnxzQowLECYks4t9/dlA4HhYJLFfIgMgUgg4Nz5C2ZoSI5Bd1QhtZEcOjvHaV3jsmlq8LKDmBHtQ5GoB/TQEVn9tnBrQ1W0Ho/X1solCshr3Ww5iYV4sNPdvEPi20xHFQlABjxucB/HjKuMjjg6O71aW8erb5V3lU+dHeFShOmrJLStTHI8NzQTZePeIUbrFzmVgZs7IxmG88HHTz8d7GryBZ7mWJJCe/uarl/qReHh398yc+RoyCGbfWWxo60sTgtc1XoLnoZvFs0CTHF/xJ8UNW4GbpuHTmRHlnChKSMOgMV8TG7hJfR/CAMMwrOgEzbz7JmzplKcdPEKQPmoAgiPknaw8FGKWiYrxDuUDyzKbkges9HRPmZ6sm1tDjn3PEXBnvl2+p5j8gZavo6RJdbKpTulpTy8kAxyqLZGrJSVOhbT400Wu+PJ4KiCA8pTw9yWX+J1HjjoZdMQTO/U5D3pboe8SLCOo6DAV5K/t0l0DoVkNcF6mgBhcAQJ8Ho809b/p4LUmqk40BNPiltiOwHAGtDMnDd4CDkcWkQVwUB1eubGVCTiCLQ1ybWpRbhnR4N3tQjf3lGNfO8x4S3wDJwNwV5gkHVUMHi8kONZ7aQs648nACsgsuoZyoPPlv6nc+aTvix85yt//g2zR/sr0cqBwewYJui8bEPeYL0vik0U3kIl+MlVvnvsiLwPCBVPmGZ1/9Dw4iVoQCK9sOwuKqAn7AiIoihtTeb55seHqLN4bjMLWfePEr7wltmxtY4fb6CBbFIflokwHJy0Eo10UVpWUpGv8hNc1kYR3uJekPtIWhXETnQXB/7qW5ge8+lHxFofV0WVXJTuj9xaTwNnjxak8BDRgd27hXt0W6i+0ZWJFj1YIqAxsLnEI/ioEAWj//ISG0G4eNmAtrUI8n1UCvrNMll8MIesIALRm/C+GFOCELPaWsn9C0jppAloQZgJwU8Kg7cJMa5YUmxeuSyDBtCBVmlWnchpvrVg2NgcntBlIArMACzDlRBgqIglEAbkmPewI3fYlfXlYDiyRzNBaDPaFN5C7ArIMcWwHNa4lvz+IW2TAzN4GqJpZEfj25p9Z+06WHdXo3GrOCGn7oriti4QncSzXcPDDvrF7g45pflpWp9qWYYp19akBxnzLXqrMSeWsguv0d8rSoLTVySIVb+nRgZV6c9XRQud/JEkTver74beRyv8GD2gnnnAloeCYB2REAj5J4IgAoQoQ+Hwzup5lDaU3pTv/pi4jDJSAyVaq/nIpsmTosYWNq9ezhqLjpgs5w021Z4kEnuDV+orUPyoZAqPQYQYe6b/WpM9uCj4RuzWzyCxxMDoMunTLH3EcaK5w7evnUwP4yvUi1SGwmgVPs8SAXdwXO2+597XXivsrE6dhxnkIhRmmBy+MsdxcmjUvatVUpOtuNMwLAl3UaHmU58MdjSZwMe5LcByGt23Oy7cnHpTviOG9oNERLKpsx2Ic/uc7mqCRlWmTBV9SrePWF2Q8g7MysKtgQCj3JyJkUlm06horJ9s5e1Ujgb9TsbsGmRPRRH3+sx8aP+uTINAnJzp+dzcQcrDqmmchqKF3rWFthZhOMReoXbdTdQgw1w5s9mEPZp+6mdjXF7UqY9j5tCl9s1Rn3O+eyYUchR0NMrFvumjTeYNbSMU7WW9f5t/xvW+ShUgK2mNEVnLfkyxik9Y9S5O4DZf/q637SAWiVFAugiDrsSdo6J/15cTxBC9OZ5gUFRzK/MhneaK1gQjW+yQJSggVTB69LP/2Htgxj12KjV3otaxIgpxGBgQ7Y9dthB8eWX47Uly+KEy7bnoAyjbZnr8rn9yMUZ6gbowZF2rCPDOjAqk/n7XN7zra39BP6q5k6YEEFmVwTGMOqffw5OlF/DLL45U3W779S9/c+GeIyKARBcsdLMwCGDRuCsWsuv2g0Gw8NhztOdb/aW7G8z+Ayy4JB+ZmCRyZlOoaftXvjKep7r/ib1mWJeBJtcL8nc0gGICQVGp5PrMvHE7P5S4cxtu4OgnllkED/FXGP1ij/nITjlGfa+sxgEQoDHIOncWyrsYfgZhSQx5SK45nfNjWWhCFV65adoL5GekGQcS1W9ha2fnFqajPNFQ3jQr0Mtt4HjeRGDeJv+UVTjbN9LWOHIJr2P0TmaF9SUIjYQ3cwpmrDE5dHjptVez2C8vYN4+yxprFoKaywNmf1O2aGhAAWEHD/K4p36HILVXXsmwJSpQja2KiXC2i85xlhWZ4nLjpO3Qk8ZV28AQXsG94lt6Aj5G2Fl1iOPc3qG5F09FqZg20mtfuXr/I75rJ+VSS/xZT0Wxy87pofRlZfVN12/pBK08t9l3QPKRoNV5sb9Yf6YYQTQpjMRAQuBswKiFAngpz/eYg2Hb5ubwIUFsskIrka2K+HpMeGVHt4B0uDf4PxDmnIraNiLTA9N75FCWD9wPDJX6SAKaSJpNU9m1Z80HluQc6AotL/2HP4l/tEsEsvOhYhkGrKwKzIIxDHMPdtQL3oXAzZSTnHYIh/aVkwY3jEgu9J3nZagBxAwRcgO+n1R9BvI+ekxWM2eDHLm2kaFkY1eEdRUHKoqfPJSenF46281p+NEjrrrqanX6e5+9VtsaskwJzM/P9ScHaVwV6cbOoDe9UVsnOnBsVPjzx69yaH59r/QJNJ71J2Gv4GWQE0ioIJznD7naGyXBFFpff/75SQujQeEI6iHVczCWZ0H/FqPDqHPr5jPt8gR4nblsWDUr0jRfjMUDywUFeSuKfCPjNoS2e6/zj3aG65Jrfh1A5p49rYZOAzGGgw4lUQSiHVkcn+R/6y3ztncuGgIC0KVh6dMWtXPaO2yO36OuIw3hMud+ML//URe/O1h+AR86lfavz3Mabqk0JY3RaamsZ6R//EJ2WhHOzJ5mUoj5WWiFQdStfbe4hLGASzAQQpbEdrgUT5KfR5lYWJrNiz7NHmqeldPXcq0jVVTIwpsnjsgj8ASI2SiowMTyzedfMl97VEoOMSTOh/7yFTl+cKfIJ/jTMtxfwrKAhVV+gWvJMWG1fYS3UQakq0mxDavA4eLa8A1sR075FimXEMoBC2dbkm5NimltrfyOcWUUC71hOwgagBCSfTnSC1ftOEcRWyS7zYkDpq9Hnnqn2zA00rVbjv+oXqQahthhK8pGo8MJiE70lWvmsy1yzJsXx83OzqzjChjioxZtp5KyWgYvgYhy0h1+LDOPoo4+pPfDAUTIKi66Opa7gqbXx99aNYej0jQQ5rGxctJmIK91j4X2dImaEPyrHjzwys4FXFl++WszqFmIdriGp+SU7bOhShbJrK4qzRH9j4nse2UkkpPovShKjS3jULAWNIDgrm9B2CHNX+IBewktuaSRbx7By/CFmeQXlwxsyOVCchh8gHCWtHfJMcSzV+lfqsAFp9EhtfdhYRiURnShSqZjJSQ5TVWI7G/DSyzxREFAtIpVVjZgZ4+bis3UHQmQQ6Id/hHd0F/2x0XXObs6OPM1Nkl+xSsvmhWJg5jKcrO2bjoUlrOvZb6OkjuURVGWR89xdj3JXS7gLQEaliHjeLI/+dLLblSMxu8u/vHrex4rHXh1mEv15hkZWe7St9F7o4WkRXxZ+3IrGo87PjAEuxAPG21ZnE/nnz0rGdJnz0kBHebf/8HEl06I3ak4VidzoEtLi9rxzsxi9zTMW1BhpevTWMpEeei9SbijaPXTrPDGZrkufQVabGJ88Kr6/weKKp7el56ai/WMcWfwRLWneccutsjA6P+o9/DhbJQ2PmrODhtEVG7CBID/9eBd/2ACRfkScagSQGJxQyAacVeWupobsiGupcW/++PhWlV9swvv+pqf+aMUjmwFHZJtV6OG9Qcw9mvhHmcEWGMBo3qb/auH//Q/tME5rfBuMhdIFN8nRgh7pakoSakjcwmbnPGi8kiFVObmuTXmQVAMiA41pQfv8cdqIZoV86Qelh4RaNgh7bz/MzoFGZuBaYGiBQW5spABVFMoex6ARLZD6Iujeh+TRMrZJ12VFfqnbKu9tvOSX9o9qgtk2mq+hc66+zzKTNHE+444/BOKrUhq289NjaesHAACwAQ79+ZlfHQEFi+Kmc3lWD99hy10yUz3W9ARaSwStAtkGxySj1y7Grs1EiwTQEwaUFl006LtXSjGDQGFdqqFq4rGcrz+F33cdfyJgGN2+sZl89235KHju2UI4smH5ZgC1F03b8tdJpf9QMMZ1ju1wx7WNXrhBbn0Wy3roqGZ6KCTNfGrsA3WMJAvcWCnbCQHgTZsTqB1IV57zXy8ZD6mQULml5P5xpQSiOAjZhHEiRcDFVd76jvcGZ2Pi0yjc772gvk8vVNhYvzWlN3+vKIj+qBjzqJecFUxCypsJUEV6o6LNrQMV10VpVnoDRamGjNM/hUhWeyZXFtOVUxLL5ue9xR/4h6zEV8/c4HTwIljZmXeU4otg/vsixQwugmgd2V5eWZzenSz5VO1XOl4mMy0WbfgXjNyfnoHi1dc0dYnyDE56cnxNuteZIAwXCniINDbI+IigiktesPPBDJaWIY+B6sByyBu3ltiyiLZECH+GM3afV3MekOLhxyXlYUUQxYQwkPzWebDB/awKkTDaVPCXu5pw5QRHssVTmLKoaSOJZIwAnnozbQ6AEThds+ZuX9xb05pIYpa8SwVdxa67VrLCzNtXXBFVNhtXfPg3Hm56+nP+I98hNW22RdOVB1NhjBYbBPOE5kty5PbGGpjgCsv4uy9LYbK7Y+XrgxGnVIjM+kye3Y7V1ZCAAcITF1W5tSNcqt29sruxjfpvyYVi8fWMtTIggmPY7OvP93XK0/AOlj0SKMcUxtSAeE5DjyE9AZwcG1Kz+qqL1qQFWiu5eXW1mYHCYllwxzVy2IS0JKYPStCPh97ksjixhAsJcoJ63BfIRorN+Ly7qiSE6cTmMQLISz0IdbAnN+cGpDHWA964o7xiNsiC4I35WaVNWUpLJBOavU4fkJjTC0f+YcN0vR4Gnawy84Bw9GCcGsbDhXKsK91ka9cYfM3T0jlhi5UV+8Piqj13NpExizgRHjwJ/Hw9+yVN3TfloXaL16T48pi8bUQG1sIWCXs1WiCFIVuqXIWIeLDVKvDXeqZIzfunKi3ViMxlNO6i7wNeX4sKCWX28GRvbLYWlpaz4wGZCSK5qCa0Pr0SmZhMJgjVXL5XHle55Lux0mB7eio9ZYZLOXl+OoQaoRWRoyt6NJHuvtk9g5Ee8F5ZiRDJI7xBj5k38AlvmjZaFUNhYRgFY1IK29op2Bcq749u34MyRzoDR63nZG+A/BCoiB6ScFi9vd77hH9BiamvhCIn7dZXccBDH8erhpTi42vFTxkb7Peplz4kLbHgR/DFMK6dwgtA3MVyvnzpO/YUHJFk6acMtyMz9BUI2uMlpSRdS1fuHY1feO2U1c6Rf97HQkCK1BLWJMN02KAoEAFw+Xps98W4Hf/fRkzv3bpovnzq3LpHp8ZYRBMlaIrIUMxqsuzCQtyhxLICtgxJEUwDv7trJdAj+aDMO0Sl1uzSWS46SchAkitlgdS8tT3u1laIrnCsBQO0pRI/rcH5Pe6TdmRFpXD+yEcIyyTiq2pYKOnlLk2Y+5TfU6nwPWy/mRdufTrBn3zO/rgT/6h31h3izIWVnilX0FE4yk6ExK086RP9a+vJEPzE1xJLK17Hn9CHMgzihvuf5D0Boc1kT5Yw0r5gsodZnVzdnVyeLjy87Wc7ngUpbwcYlwSLX1hOLorQXNwjD5NDwzxkfsVyvcuyLilgNYPBmGWcjWQRHEInQiL6b2KgSYuTHzu8bIoHIMIeaM9I/kBsjm5a3wald6l+H2c5pM7tkXKA1HAXaWCqqy2R4m1mskSr5rIWYezutq5tuJgOzAolIOJ9IXFXSq93os5xgJC/TgzLKmlPjynVkrlwrsRT6jeMp9nxZNKZiuqgkskPcwAY8SGKkN5eWwb+BcX5ZBuSDOL+d8GwR19nayG38Vu3SqciCUm5RF9nKI3aDdRK7SNN27jljhNpqVGrhqbjKNhJw/RK9eu9C0sZJBzaHUlHa5zBwrlvu8NGKazyE3Mzde/7/1HgYz0X+CNj3AhhGXlY2qL85gbTQ2J8lj94vHkRDzhsDAMawi3rQfy3p/gav7WMBELQmKGbPyOpoSTZ+/68C/9Bgtd4PwSwqJfp2VRTWgRCOarWtGTX8yfn9Sld//CIx9FMimtJDUBI1ja2IawfGsxfBlfjlYH7AAMSUjH8zFkAIyie+nwxHf+00jIkzhyjzjr8c30jq6cVFweWZlcA7XWdJm8RppJsdTiQmej1H3g7Fp8VYY4jnXKlaEhQZDVnSI9KXfg1/Imuwfl95EBmRQESrCZqL/3mvnd3aJboKXJ9TBeAnmMb9+S81BOda0zkRSVChwZuyS7rkMAEaAbsMOGmZHJge5EQYHI36VzIpYW/bNuBK8lM4eSQLnhROm+klrV3cnBUcYBHj6SRdgATbcrscTyPdwWSZQ15QUCYnQYQhmaNp07suASyMjAC5IKwQRH0L/+liiMxanNYCATJoitBvbkV0fxGU9/V0zY3v1Oc/bt2Nji/CBiw2yTM8Jki48yacmpI9IP5eSUfeqY7DdVKH036lpIXFq2jiiFj5asbAzc5vfZ6XRlcXw97mK2M0QZKKENh+CLWgyH2YJgTnlZNncPJvCj/SZ869ppvndaNjSAEAx6XUy3fp6byvAG9t+wXGW9RyQHAYFq6+TAvrmnTyap8U6LbmmXF66bj+6W27D6BE5URcj6k7npeU995aYOiVQ80BjaUZZNJ+VWZsBQROs0Fxf74gmPQvmGVIwRBgscnUF/cdBM3E7aQA4CYwEQT2PB0TwH9KO8BhF25IQqqqVhWO2t90aqcz/irg43lRkedsa0b5KxhgOqkAFsNDKZevMtafGVNXPssFyxS+odPZrCjbGajSZA6TF/D3rzLfGO6R8TE3IK/D183JG9D3TGeCaQhFWfoFgMUdGFVwSv+4FfKjNDo+bYIVGkg8NyV2uLOVFnGC2EGK7Bu0aVWHCCl3u4OZB1nfv6QPDqyBsvmpVmCOXkR+SNMITqW4eNTkxbvKFl23CZz+oqhcwWgzBFbIG6qT2+vkZuQ3J4J9SoS4noEJ0EXvI7mLeukrGwkJhbcTlSzopauY9igfrhhTG///3U//5xG7KUUB9oDymyY0HwBI+0Tl/gcUk3vHDL7FQ7Xlengsp4HIRMUya6MUSIJ5l0IwnWcWGLO7ZlV/QHqxFIKgghvacnzaFKcXohlntezDe7G+UYx7u9TQQS9kOXLycqKhKtR6RbOYqLnZOTM/o22EatiSYPKBZg1iKltc4tVaDjsu+Z7XG1tZLMy3IsEC+nv6PHIDxrRpLJ8D07Kqf3ZESJWd8bEE6FbAGuXpXC8GY7XIcCgKPKOVmkAOHBZbKX+BzYg5shPtpgPVJt1uK2ItI8cwDjuKhVbO6VoPAQnZ1B9YwWgF3ZvE7RANb1pagf0vviwDmdN8Ij6NZaxXy6A4WJzxg300xS8rJQXbFkbdJpcWYaasU2LczZeZBv/OktT3KjvVMk0utJ78AJUlFHDPKITtRmcaaM6iwsNJWLdN487yTjA2E/onp1dliyGVsquCLrEG7cyc6N6Zcf/p5AVACOi5KHIfonH4lBdhFlKDcP6QW5QpkRc1W7gJxo4k0B1lYtxQO1Epop1pVF0S0I2z6Nnfni5pP07KVsNhfSdqTE2FSVBV13JzifNSsoAHqi1WnMZiwImtIV/cw/+qOqVn5FLNnM5LX/LJaraYfsmuCpLhVAz+oIXxtrajb9zw1w3H4ox1w8A1Niw9LlggzWM1SlCYTiKLBGX16E3xF9/6eejK7FbdgvTH+71G8DHL3dqWjZ9PRNeZy9KDIbmwx3h9UOOsEe8vAHiHBHsQ4QDfhomUJltayRh/aWNVZn1/7GFZN8D4csaqGGniazIWCExbHt2uBIQ7vhalCMhUUI5D703EzuPqCKFdlG8Y6NuVTCJUaIzdD7UFn8Oy9NZL69aWqVk4gipCEvPXq3PyinUv2dkRMf2xJaDU7pMZ98G4AHrawykaJQlfkYcbFtu1twr0df3g4bC7IWkughdl5NrzAHCeQ2WwaK+hN9Qp98/394IVgfgiFhUuetA8nGMYsS9MitEHcgHdtgDMPP5tDok3HxHhmIgE7q3/f+o+jAPAwfwABMcYaIbQC56NsQmU0oI7SGhZ4u5rkn0QMQppzaqUGT0/em9FZU5fW42R03hy2W9pqR+Lusd/Ler/plXoUdVuq0vDZ4K9+nibXz/KLK4n5fLw64kx6S0AV5bwhojseTbAxGcGsyWdha7NQV8MQ+0AFmVJbojszMQ2w13+7gp2vd7c2+yqC8YXzSw8rrIcEFnhJPhz8RDHviUwucLoxfjq+npoak35QVp0r2l5bsSvsW5YUrD9cFCkPuKekdl05t7N/jys8X1dexO+hgS8Kl1Z5ezsznOiUXqFuL8D9/Pf1/5J4PH2yxyyBkhoc9hXmF6iiA51DQ4jSq7gCq3bwlsRIIZOM/1OVtquX4/s/68pNznyx6m2Nq7YhE8opnpkfoL+Qupk9/Z/rIY/kcp2uKhs7NdB0vzUQL5XR98/qzvZGIoMnF+XiAiczzHIpCLNMubQMYdDawFBgLEqw4NbXClGoy91p0VRIskurRI0dNXtSzcUN4sr6avvLtMVbQtsb7e/95tGv/NLs8c4k9nQWQopOgZNJ/3/0C+fkGtLnhauto+LS0ePViLLQ4EnjnPMehphr/3Ohc9wYOM/R3p00Z0VItKkoSGIfOtN4XSI5jOzbFK0GTIgPKE/psfXE2VQZcawvGpfW1DMktAEEb4yeVDMcJEA+xtpuoeC1aNb6uW9Ty86fl0pFG89EjZkyb8vh9xCXNrdvy++6uDFnO3S+Pt/7qYU59Ha1iJm6rF00RQQwkwbAgPYTfFpd92DikzMTeeDk09/1VxkJKC9N2t99QeIM1A2zOIWxG49mhCbQ38YFA7nrjiRqeSq/GQjOTyQ0p95Xn7nTuHovPrwZqS+SN+LfMcMJOo9eKCjZvzwDT5WdHdtDFOorwh3/gGQjRQqPhgkIsBXT/DrmEGw+JGDAEhnsB8c5GMglzsq7q4CBTv9idBmLf4YfuJ3dDjln2jxaBwxF1sRlIZkDSvhwfnGGQ506aX/u43EnK0NLkRjhf7Vr9jlB4uTk8ye/JhdXRq/OVO32+IlHxc9eXcT9siz96XL6yOyCPR8GHCeHxSZEa8/RxaUrr8pHkUFsr9tQGt05Om9aUDIpCfp5Fi5PsC62tuvJDTkaZ7BhrJF8C+bpjxL/5AuvhLGMOoHeGpSGQQN4Jtbeb730vG9RH3vDoSnQyHpeoNa329g9AdObQl+rE9Ga9kyuy+xVSaGMk42MuR7qqXvr5+kaCMXDbEHzlCxlZe/BIB1fM4QMy3mVFmoEp2gIlQd+EKAn2PYMPDda8vcGOcTh3UGWFDKedOCGLMUIs10KjWSQQyPe6At6jx1ZHGeNAca1I1gbDXxAv50PWmUT23r5s1kiQVg2ArD57zXTlyG00K1JMv4BgAnkfdBxrN3mcGKQdlKN/U2/KY515Wp8C2GPakcVXgnkADwICqTvXl5raXBHdcf7mzSSTbchphFA7JLlZc//KK9LEWGSrM+zAodz0IW2PAygjtBKEWaI7AXrm1IUozpfebLejlL6Be2HDBGgwQjaMp6sNaPt4s7O5KVDo5Q3O0ZHgc6/bPoWb0RARuUUMoMLF8fhGZl66L70g3dLhqqlJWc2cbGE03gz3y6UfdstfrApEqA8hFfuqRJ/R3iYnf/SS+XJpT/GRlJWbtb7JcNRlN3Iox41n30V9BLPEP3QYy+VCB9pM8X3N/rYdHOfFfcG16ZKqdzg+dyrR5DOsMcz+rRAaq3vR3KtWNVzLNGHz5OM6QIGSjCdf+VEamYcuTUsm0qwcvgvBzEf1Z5TYxEiySGe2RJqrXMRi6RWqrToOhRjE3rwpVUwvr95+5lZV0WYqKQbm9H+6tfuAN1ohYEPCkfRGayJR2vffF/ChycGNsDJuqjsKHpJHgjgMscHwq6c4zs2PpvsHmQZBh4L6to3j5e5fPDVo49rICKv+xBYTZ//6zv1/KAzz13UIW4e0qVHQRO6uX1/rn+ISmwryw7QiBaRUa7atsopoKl29JgLZ/lgVZzD8zlXW/5W2vPj86O6948nFNY912fkM4q1qMVQVudm3UKV2sHNKIvd838okx+9BQXIo9PI7k+a+23HfmJjIiuK4WDWAlMb5EkPjf/lONjWRbvjeL/zJb2EY8B4hOiwAwGpCFCldz6HA49a4dBaEsFRvG9a//8w/9KEKfQVpIJvTSxuzAgjcmSQsJd/I6ZE+5oyGZ67OsGo59Oh9goLOqNHfkB/uQraoB1guK8+89SN5xbF/UyeRWtAGdO2aeeghQS820DsyuLaSwcpAdI70+nYz6+iw5+Uh2RAMhk+rGF1ziHeq3VqvfSD/qHL6B5nSlN/xCy7q+3S3In6nTx6pqNggeuJOJWPMv2ZUtMjjLC02IyqHrGEJMLdoC1zA4DHIWhfYLj1aZna3Sxuj5txO0x2+8EPpa62tacRgdjI5OyOarrEtObGQstvpFrG+XGop1LjDjIrEBKtzeXzmonQlZGJi1DE4wKFpbtvMDznYR9yunFERMPR9F8YBIVg3199aOloyKHN7YCh9aGZ6VU0gGgCfgekKELgK5LSjXtAGlF8edBexWLvE60r4aWSt3M7xQjpXF1iHfUT39wAMVxVuDLwjEN/tlQUUvB7SelR3h/Maj1e6xgXmI9szM9l8XEAqBub6jSyHCMQDPmEYhG810r2+ooJQXDNvamon3+gu3YUkm9JH96DsmyRmyv1pfC34zzgAFM5LXDmTsLb2kY/GK2vG07ocNuti1LRMCwB0WCnKgHRzajAtJod105aYlCPl9M3MmpinoGDD2vU9tWZ52vSNyZsjCnwJ86AwIfwoUpXsgME7g6ajJOvD7NwpHymJZCenEXKigswGgejA+DlUeXBITsle4FX2bdxGUJ8QPkQroDORgTL1lXhbU012UjgsnZ7M+nh4wjvuq6xpzXeWSy0kNAfeRz1APB+LJfpGFmelxxflriVnFm5dR0PKLsygSeI4eldyjqXblk0xSxmIM58G/FtkCTj/m2fNkw/JbYw3IogVHQV20Tqnx1NVPeK6LQoxx7E6dltwMOOQnM6c6inCZKm35KisCIdnbJelqCx3PtYbw0hD4Ncr/TLyCeEhMDpqB4KO7BGEQz3sQBMSiCs2eltgfWUTC235BIThnEGpFLWIKn8oKuMSpBRCXEcMeL91aAllcemRR+QS4sTQB0vZ20EMJCTgT2a5v7nhnplIrggT4PD8VIJU1ab9mBvT0OadHYtbkWFmtYtl0xXh5TtkLIv3N4l5lSAFeeD4sRA+FSusHGjJOkWPs3BOadblxtVKvn6nTFdQXpxLlVa6JsYyZbkCq5Ir6xuLcVdMFMjEeeeKP+vj3btLxAlhsC4fHtOlFcOcOAgRpbGIVtji8XI41nREOqn4XrSx9ZZwNDFZ9Tus4zrxN6+V1UdCrEdB84USOaGsN0LF20rNM2+a4wF5AdW5fCk7qsNH8bUYeyvUgAICjBUkVUne4E2SBWY9YjJOkWEmdUyrdPmqZFzowAF52w9fSN5/PA2o5isQLQ4Ssp2Ue6iabuIg6jDXL9uAEJeFsPRHXOYb3XL8b9uED99X+TneKuqCwbGrQ3Lpnk6pqIaMRHXwFJhzaVEuoZ9aWrKaAejw4INMn5MSjM1StfjlM45EQnQszKApLdhCAvkJhkOIFlqRb9mAi20CufAhbY8D/5JlM7XFgZT02zBQWOTOHKyT+MuFM9LjjjRtiFig9SAUECYSRkcEhEaPsodJh9F4Nu5IuMT/B18Huph61krCavTJehtQRYb9Hv8+2sU+9aV1/jh7mmowG9B7SRXFJXa42poKhVXRcsnjEMcKu+SYeUyvfm/tX1SP2bVcfA6va25ynn1nubQpQOrHKKQW+Temtliews8PRz2GWVIYESZzDywF2CsS03kjQSAgF7Mjd0kBMEfn++U4CsRnydk8k+OTruSLOI8eSXf3yKV0nyDaa3L47gQnIXRh9+1sqpWf1bbq6mdeu1GkODH62EGiERUOMYouV7qqeAWPlDVpoGhw49Y7G1PTUqLjT8bya8NW4a5MrOaSD1DMog1aWP76Uj6F26zFbTZKfLQONDZOU6IBsqPBmAz59YNCtBMg444CceCEb0dlR3OxNA+0yExQtnRT1YDhwXj39928KszHmpACb7d+QnvBXtXld6kUatg2K9oiN8fs2JPnPqAm3Oup7Jg2PWIqIuzpyaTfao/ABVr//E1/T5/zxAMcu6vL25sXJlRb4k9gSbAE8PautEqb6k0kEk6Np4eGRDg/8yvGgbZCc6nucyQ29xSZ0JLcx+Y+Pynt+ujP/ENJ1ALICFudS7QuBKtg26a+jY/BwV6u6jvoqGLAlHiQLr39b209J1+0nBwcMJfPxnNzRdJwhWprRYcHc6mxWV51gg3QydC5q7LhuMbuxEm46xe1+c18XFRLdYc0hMTVbt4wuzrlmDg6obv87ELDa3/7oi8SLN8UlcD9OLfKA/Ew35sAW6J0NNmyBDikHYPZfEP64wf5j63aT1bwriz951fn/blbbiYFqXMMuAWLRAtTf/ZdKcMXH01WdzqtP4O0zp++XUBiDTQ7s94zEqgvzw51AwmRYp6EdF+ewX6p79SEgIZ4PMMEA8hXHCnLScnmyPQx5jJBgEo8G4httuYXNIYiQXOHM2Mzrf7rN1KffVJgq4XOKExiBl1t8sRHmL5CAA7rZK+BTFOpcR0moF9h6b6nuqgZbJoS5GSHQarrNq/+6Y2j/0YAKChv+BtnarB4xrz6MqVK7jvo2tEgpx5Xmtr8yStSVAZC8Mt27o6ZQXWY6uvD7dWZlCixG2mVzPEAAEAASURBVN9YA/vaLCwmojAe861589tqbfE92jtksx0I24BK1DCQuXlho7XOGfnYA0bDh7LGwMJCwEKqhYWS1GrSG1xlypx2IirXsVvUkSe9OTNibojSk35rLpxfXHb19Eq/PnDIIQlMFqiWYz2KWMJE7iPrf3Hh8uWss8RMtiWMpfqc7P5OBuOPoTNOFPaIb0EOSRYwK6oweCWxwsceM8FC+qmp8MYYEiGED4EsARXMwzmhbgwKGpBnfUvwRkVlVi6A0XRyQJ715TQPYutDDgGphJogGtBVEs0tLbO4df71a2zqHC5VVQkfFxbmJjYjVQLMlwbmv/N3ifvuk6fyykJ7Qokqduuk2A4JEZHBtaY7263niGrTsLL4ayfuzbLn7Dvm/gdMaNeO7A5WrgJfYdTMiuccDK4W1uV4Wb5cE+Ty8gAdweywTn4YEappEN/UG2BB9zSeIGoNwhd4rMDUVsoxbQhbbKCUJTP5Lrmfw0NyidES3P57H5I3LE5s5DNSN3rH8mugO4lUW5f4jTdMe2t2hhdjkoANcICVW1jHgC2chGAJsXCYgOxB+Px8K1/TBCfOj4/2bdjfSf3ANM/OpTfnRMXn5Tkvvp0NW1BIQAY9BgKUIwC0vq0RCW9UVu2pgLTbo9IfreeLs0NL8ReileOr8YwygThCYkDyf5aGpFPklfj9NcUO9YLKiuZ4s7VzBATOnRM/AVGB8Hww3Navo3dQU/wiuAJRHQQmJ6gSyUmkzSandv+3t5so65OfMNV13BZhz72ZO1e/3ctxfZU5+apMzINoehDwCZYwVSMBshoaz2Jg+iC1wzzZyqJ76NoMnUIw5Auvmd9vkmMKA5MpA3+h739f5MViGzZjWFtMgw55D8Qw/1+/ber1eH6V4KWgIMjNZMgCMzmR1Z1UkI7g3JJoGqhGDSVjrQRluESKsiU+TfkhxvNgNaV66ZSctupueLYfweq/+L55sE2qx4MI7MULGfIGIbw1akSbQqhNhIKXQ0AXfqfV7DCh1UVy4UPaHgd2sneCdjfaDSEFlllkdnhVhKT5gBqUVOqFP7nz2L9V3AP3e3pk9gYD01AtG10kxBJAd+64Hcn0vBw+5zJ9GXMkbY5oMyG3NK7tIMHKSGo97gj5/H75MEExwgHWkebR6a3EJzFR/5AoSrP+8mCLadhp1icXA6rT3DUVJrkRiQii7R6UteO1QnIrGA4BtDYE8bvx3/qPYR4gp/OVPzx/XDe26uk119mCKZEdVQPan6UYYqnM4xqmIfdloE+wTf2OTPnO4MqKXOvRr6jhlDt/kjC0rQTd9Sd6CpbFKoqR6yvVTd48FhvtaJGLLAYbX/DYAe2FhdxMOukOVK7BAFNU4dlYTtTvFeYH0kubI5t0KIh0RMluj7050Cs9s/5wiaTLW5AZTRs/y0XulfvicX+u59LVxLp6BtoC8vMHhKZ05EdXAZTOi4mMkvOg9mDzzXO+0NZqpETOZmenB2MEjyA2iH/5tNHJHAL9QQSilO9G3Hlb72lXo5bbWpU1kb5iX9WUWaAsaJK53PoiZzSY9d4jUQdNaIU1HGZ+iUthA2tDTM7KoOt2YC7Sq13CgNPICACWQOeZ5dE2J2tPER/FxWJuKsPGFBGIpi0lR9sgxFvxl3it+9kQQZ9lYmD3khlU0b9GZVUC1U/8B842qAJ5UL0uFZE+sz1CKdeogcPIgiHxkyE+DTagS40Ni0uMVscGcQMUCZgLs9lyetTHk19/Ngk8pU9hf9HtTu1+wK+DhyyG6Pt/Xtj5qQ1z5BMmLCbS95H73X3d13/UxzED6egu+fz2CMcb4i9MeEWPG3XQUg8//PMPOPD+3K2Ry/NV5SJa4bKgL7gJVrinTU77ezNlt/o9YeH82KkhNsheuyjYJNRS6WXVavahQp1DiNXCwuQPkV5TWixg7b775eczp6WrgFSKy1UAXS5fa212J1EmYwJYhofe/t4sd1ZVpEcHJXgG8bJ/12t+T6TFVEbFBqBH7JD6Mz804+wmrL36y08YXyXgwpP1Y0AiJSVtewWvDdzaAML+eou8gfSE+RkBGSAeyJlJtdxTaNEbIYFLry4UB4RXjJ699HKmuzf58afkNizo3/7INCgkwv6B8RjQCOg+xbE7A5X7yxwK5R57yjM7IUt8QkAc9EWXQ5Zcg/A6KXNAZXb30aAvx+08dpTfk6E8E0z5cG7t4C/ziAGkpEhBHr87tuaOrTbeJ8rAk+PJdRFdlA6STDpSgyPtul5o7m5M6GKoqaKhMShPYYz7ek99fZjDo7/VZtaJqEfld1qRNXm7nCtLovf4CLps85JcuWe3IFHM6jlr/UGwjaZX7JdpqDStTSatfXpqTFiLW2VThFEZwETLRjwZVMbZ87JvOk+h8EOLCQvK55lbuSYYHSIMD/6De5hqCLVAUpNdNwW8y4EFxCBq0T3nz4/2b3Ib2xLkNRbPdcsroiRUlZRGPnLANyMqcej6GCbZeh2udDK2nLQAFCeB2X04IRa+MxABsrTHvDgnmN3vAnBMUYW4FaKeHc3moYc5LG6b8+F3zc+PfF/EuPoL90ug1ErkjRvFTZHUvKB/d8iZjMnyD7wfomqsYM+wPvS975oZtvuulGP4hgdVWSGjDRBlrq1ljq805ZWb6YMlvQ6WxqJkDLGWjr1+MhvPbmyU7LydDfIIHIZ18McaCXQlQPzHKWcDI+YQi7KofB49qmzUa5HgRgZMJd8RC40DzDjMhXfkvK3DsXOHGRqSS7CLF1rHCSBOm8JS7AGEEkee8ashfqGr0U2tN0inQGYuXJRLPq8Mu/nJSaLzdpTDa7835cXMgo4Ko272RmDwFKugE+csxKc6iLn1BLgEQz77VHZcCOEEaFJT6ghduS45w//yCyIMkulIEVEK+DbHm83CtBnstZnBflYMcLnKCqV2PIu/MSh3iYNB3ZursvzBG7z3CD69XMLp3btHKm5Bwis/kmFYK6vpjPlXds6YuoKUnHdSZoi2QLZpGghQSONSox9ekNPHD5tOJnNqSZta5JE/Uslq0XX20Y79ylXKwBfthPPbMzJsaCc5TzEBs0iSBrtUUaBqEArbfMgMQ2cU4LCidxbphie2IWisg4Hs5B8CJSiSdyaEnxDrC1waMkea5Rg+0IJ3FG3tqpdaUFPb+6zukZs+pO1xYCou4zlQGfKA/OtfTp8bMl1MMM4XpX/qRxsHDjuXztzkOLy/QeLNgNAa7c/jAyRfbL7xDpdmRjfDnuRDBzk00+/Iohf0IitpNHpuc3mGGJwoDYebTVD6J77ynNzpIuthw9xUSRvWwSXVQHLppwhUad2bZt3c0RtmJU21v7R6QUF7u3jzt3tMYOHvAfEtXYjMdgr+thzR/ZW5r7d3/NbSqBo4kmZvD8m+Pfv1ewDQ23gyeoz+o5viXdrwRG9v5sDhTauZn6wxV9l9Tm9TXahH+ofyU/ePS10lQljbnuO6R0ykk0BF2OtDoVk3aOYOG6Wb+0/IfQkfqxW5kyvlDwjQdAc9AbcngpKifydSmZGRHU5RT4F9jYbc4oaKkkYwM+Y8SbLjxf8il/Z86YBZTxiPfQY8kGxpMmekWbbllsh9dyPtyn/vyt7t9ne5Dj+hQ+hSBElPUNco0/QbpxZmRd1FXCukSVitKEzPzw+f2OcbRy5QUzNji9kZLEjpirzp7oRtUzUjgi3Sh3mzJjIn37RhIj/CK/J37fHMTYFs5l86y2nBrz4pelDd4OSl6zXV2XwiOI5sTN79m//gjuWkID1yFyBG4NO9A05Cj+hxOBCe7iETXzBRduMBOdoGUXcVLllkD9m3A/toV/e6OB4Qcq3+SnZGk8pE9r3Iqlc7JueYDk6xbRr/y97ws/57FWOkPXPPumzerYEOU3agkp0lAZArbCiB58OeLsVFa8MzHN+alREn9QS3lfnZox8uMea7b+PLiTCImDC4zAQDtNOT+8zSnJnrsfP63Oy17MjGFgFjERC1PiC2+W5kJedNnbOqxlP6u7bP3Z787+/6+3O3vv7M5r/+gjApp60ip9JFGC0dE91I+oorvtZ3VmTS68542qodqCpxvYYrvvSk4DILsQG2M9MRxu4hJ1py3RqP+nrz+jVzlAUDGQOmpQ8yI7jMBpMz5LVnMqmVWFGevNCRFBxmFTSp4e2Z7AZKHe0CGfHZgA4Q/k4dQF+PgSyZ5aX5RUeBjVTzsaVl8pu5jbSiVIGMPEC4QCAnTIgdlgmEnKGoIwu619bQZSsLIrK8v4g1eGsM81UghnQevZf4vRyfvWAePm5WFlPXhuR01671WM/oqiZblhVnSDeyVgpkDpRnZUGyjiFGJ97pMR+7T44LSj2G1SQ6G+WEiBAhuAvn5xfoZaaAKWrRwuygA8tYbQirfT4V76pKJ8BQo+gskuiuKvU118kb8E5GRz0ryxHyKSFC9MlkS7O2OLpvfMIM9vMzrBjtYYfCNIAMgr3UsVN1al2NKEmC+i21cqlMo/g1iiwLdOG1hPbim1dlTWqcxqkpEQY0MMd2s3ICmSC//+E3PT6vFPWZv009hfcrulHejGKyx41NAiVB8DhgUF2t4FGbjnjvvYIwbIsLyIYtkfzN2T5uCxUYd015bmOzPONMJC7d9N170K7dxoAYjrRl+P/1p/Hf/nQmEZa7eA/tj3NrR2zQrTSH9Xvxa6xzKPfhVlV5CZs98x9ucPyJ3y4xLPKNmqfArDuSW88QRlG5ijHMgs99wkmaYHZ4tbReVbTfO9a9QS3qtCmQMW60i5EQVgjkmKad8gTWEcHDjQGaQ/ANIFVeLr2gptY4cO6dLlkokMqW5eXmLloYzRtgshZHGEV8nFrgRUCY1OEhGbOF6BH794jnwEgRRHaHiL36NDj5qHKdMi3WBcnnJaSXQIP9GTxni4coG+OKfAIC4lNavnthTE4PVEsB7JAahWc5UsC9+MM65kNXs84AsXYed2qWQgDRAdA4nW4rajQG5VZPmkAJ8mDBPf45q13BCltB7BDSbWej8Qmu8pAlVschrEmKHVTOHFHS9TDmdFLcsnMD5uJ5mRAMUfTLl/AAIYSK4T7b+rAakaPipD9DSD4NYZfCxpkhuglLrd5CAhmzsuXBL3XQIK3yyOmrZmepcBQPB+K1sIiPQ7Qb74ddbIQBwZC2ZNaQj92R2MQn6/U2XU/x1ki27lQWIaTJIAYtSSa1Di3MRGgJYT12r1yiqD5/dsgX8Ip3RD8aVdto38AAMLSybCr8crMcsyBqiWmhBVRsKeR3ZswTuJfoWx0QO9crx0c6hYXIKqyGSJVUDsrxh7QdDsymszuEPqm5UgidSx9rDYh5Gj4tdqejI1HSUJ7UrM7Nqz2+L34W1W+SqqVJbZ+YwDngtqh/nlazoxYVxryEkG9NTgzUlTpKSxxDQ9w2MbjJ1MTZ0YRH3i0zXTEFKux3gfJ8o0CekJwFhKcouVFaqf4X5m1+LqbFYTmcYr3nx398xtTWyhndIVpGGp6YJzo5AmPjVgQ9UGbHyASRC7ItT5c6nxzTM/Br0AmD2mc7almSNGV1SCguCJ5/kNi2f0gUq0A1ZGWFydvfbDpVeyL0DANeu7apSdG+/IDEJKyVZ8HfpQ2Mhdv6S+wP4Y3amJbDkXGUVYeJeUAI+iT7csRCeIEQDkR8c0erlmJ1RdZeorcTEp1ODFyWdY/n5Kafm7ulfVTaaEKFRGzn+yQ1v7J0ZNPW1hRi8jweR0mRd0RsgBPvi7oTn4NSqeGvvlXzyX1mWeB7MiWftg4bmmObbg9ssjLDAepu8/bQ//Z7o7ztD36v1gRpITGRnmJG23PImsmtUCUCk1FqN29xieKRXW81EgLjmt2WZ8KD0IL+vYbrPpENOqCWHdgACGuhzomErTVZSZWcPrCNP3BedaRszI0LZEeGR5Yl6mk77008dn3Pu7YR3xSG4txSd3iux3f9w80k3UHDKdNkIzR4ibXsySBym+8QDEBiSHJ8CRAFNRYzd8bkaAnk2t2oRG/oJ/C3aF1dU4i9L+4QYAScoA0w5JfOZqEedmtxUR0xc2rCvLjFkLt9RK5rz5GugcKw/LG/bOfZ/97usVK03Vo312RT/ME487OZkCuhQyNmaMhU1HnKqqWzbS7Hsf9uhTDRx3QLp9deE68a0nQcH4MIEKM3s7OaUWiuXDVPnxDVF7WTcAGVw8Ps2cVdYd8GqIwfRI9IeoVMSwDEQOQKtqdsxrvcgHloZX0tvVRRIhioSiWOpQcqKuK5ZBGBoSCGiebmBvpEMPjijZsW7wmkA3RaXc0lJ4VkxAjTAZWV7du3iNMPEap/8innd55NP/ywnHpLI13uJVYu4rjyUHlxYHWye5lUQ06ZDDPUE7dFxTlBNWBuIVQ6ZQPiWATJFx/cL6dCRM756MsvyzFweGz05lvzdlVw54Kj57X1tdQ0V0qrfc07EhcvOvbeq7pmYiIxteDRHHqxtFgkpitBuSWmqJRM52x6E0aypbPAWse5CfavvfymBCY6ukjYTGcyzjvDUgs4iW606J+XwQCeozNCoGHgaYu+G5BMimC0UH4HpsvaWgvGgjzWAOBx9hmDAKw87i8NJufEkDftzLxy0jQ1yiUQJFCewDxEmiWgnF8sFuQAh2H/frnEDXgXVkFjXteuDYaaKyue3MMld0uD8Tm9BOqhQL5rZy0DX2uayoP/Txm++U25UuDPUBEbsqI6eD7VTf47OvWO1gHaXhWTKpJDzIwxDYikSx/pgv7AkeMqM7Oz88+8WqBLvCTWEp4Hjpm29oBTi46Kqq+TgAI0NxcZXRi8LtrR41lnqDYdT+kS8eI4U1nLRjA9atZGswSaeMx3vmc62+UFQH8G1iwRCxDrhZdgN8edmIhEFtWsyG0w1s4KY8NiakEfsViH5qU3DaukHdkvviW/22GZjCN57SrT8jGy5uB+aWi8KQizB3Nc7qyYwJCnn85C+d952fyxLizKbRQeGabAu0flKeLIJ183sliJ+ngwANjEVYgq/Ng54ccTj5I5p2zEM3C6MjOzdpNKhKnv3P/H3nsGyZVdd543fVZmZbks7y3KwXsPdKMN25JskmqRkiiRozUKjY3YnZjY/bAbsRsbszsjzexOjJYxomLEkcSRRNM0TbYD0OiGaQANb6tQQBkUynuXlVnp9nfueUU2yTaFFhWhiMUJROG9fPfdd++5557zP+e6B9rip46bxx5zhOHdUxJVYITNzhCRbkK702UgeAUHaFx6LsQFVStqxUpaipaaQitbcz3Ubfx0T6meLI5zE4+r/4BHBkLTwTE4gFxduukYb5gAEGRhCbR/n6BJhi31Fq6SEk8Pwol9ZdLUY1ssE4L1ojr4B/EX1x2/EaJeMOF7F81vAzytn0+rqTuKD0hF2kRZShqUZ1GJLm4VlEKDq9+LhDDohOhCE/OmZFGiHqfPyu2OLfIXdkL0RDpsXb3zFrxiKubO/aJvUy5/en5JJb+NlXUV/q80FeWsCB750/8Q/8bvu1ubBA8Fwt6toamxKen+TLOkKSm8guCz98wX+fURrZkD+BG2YWW4AJkFsVnwzjIMMWHNLZIRbcSUYi+KAEPDoVu08Zl3Zf4FhHlLJd14Oai0ysLlezPafL3GHLZIjugh5Mkks3fuXj8ngZBkPINoIZYsSYWuZ8ypVWwq9x9NYDwr0eadU+bpJ4xMw1YfCxd/YvLse/ImRbNgz8kF3c+ZVXQcSGSeDo/wQdVVBx5bnJsSYeXpHz5p/t1bzkzFOus+bbAdpJNtPFJiRw43yksLczKv4e6oXBf5ZQzNjsnJ7QcJI8N3tf/SKynT3J+/QoL8zQ2I6d13hkqj8l33jK/31OTc3/RxXdXgr2rJ6X5/ofWAVQ50qpEJsYwQ6rKuxjTYluAco2CVWRkWJxUqqDMl6/MVL/NjV/f3vikgf8/ODIaPf9JDmBRj/366P5p3rcXxwzYLsAKdEI6qL/dQ2Yoqt8Mp9VGnUUSdjo65aqrDn39KntU2GvY2Q69Bfl/JgVb06UiXCAqMPLjOHLc65IYdBZU0ayAbmzLrWeXOFq95wd/5jH1naDjWMxzSWCz+weNHWCPh89vcMZGEcFgHzEfHayoqbqri0v0nEHqr4T75w2M2CRL/rD2WnTtmlcuEGkChtb/udNrvX9Led/mT8/uFFD32jndfRcItt7YkpV3esr/DVPvbz19BJnPtXT86c7Xt8J+RNvhz+ucJP/KKDLX3FbHX9Dax6VADxiCTmZtIBuknaI+kOXFiRW1fL0viM45b+JGZrj6g5NvtNbsYMKckDy8OwqAGyk3AXgf7TdmDxNtnAmqTiEhmMmqlO4tN94izAcZqfmv6/4OKYk0v/P8vkVWca672f75rjhyU1OxvsjydDUfN1r1BbtPxZDaZ8osuNPfH2HM15gK+kawzKIH/B4PiPECEZKEmq2u5TiZdrjl+2LRR9DyR1Iz1llpbR1j0NccEGvRvUFbrMsdBgSa4B/9E1T2WoMWGk0kGOgd4NTTwBVFoNTUZwrdqmcBMoJYNrRY98WwludT1AM8KIg1uIGtaIHAYrhRRamsEzfRwvKgl5LhfY2ORp/c02bl2Oe5Yzv2BRGIelwCKTy4uzzvjQnUNXhMoq8zLDVTSGU3uxEL8dh+fhig8gLu+Xq6B0cAptnjAQEL0L6CzQjTxtdAd6lkS5pybJz7d1CZm2F1S3BKce3BH2FXJhjnhyqbGpW//saigQM7kpvZE8yarEOobbH2szimNmWiBqVlnKqxFDDI4hp235S68zebWDXirVGFx6ejR7K5djj2Dq3g+CrbAl+zb1lTqgG9u7/U6E7GoCziAwkLPPCMAAgT8rdfl9vc+I8F7ZSODCfgb6zcv5bF0mghNaxoDrWMvzAqDdM4SzNmwQRC/urtwhrZQSA3KJzeFs8iXZ0ubaaoPajos/dUrU29dIp9oZ0Xm/rC7IBwgTApSse6TzvDmFgOP5EBEi1FepbkW/YNU7FZ7P7J3pUzpZCmYtah86PRby/u+kq7Y2yCv9fcP3xwpKsBLAugwvXLYHkeA0bTzx9lvTt3lSfbJ6C6wmbPGoDTqAkyrU724IEFG9UaA2kAHtYDwGY9oyybHy6LliT2JySQsMGQiTezPHnK8tPl5mPDWUXmEmPCW8gDO4wkwFxFhhvwB01AvGydANCVyhSemqrzNnaU8d+5ILfbtlcKok0iCm7fNvj2OO0HODB/xF/q3XzTz95zy0PrhfM/UVLqpSh7BSZoJBxVCnikDhX/zhNziWHILboSee87kttqVlNzMzZ4/trhzR9ZpDI+HNSfqw5ADXRJQBJXZTXFpGl2oSHvhHSEDEH2cW9xv9ZeoDi0bLLbiTQOLXrChnKI6ZsTm08cVC/IoN9LXJ30ezr/dbT6/S3KDdTicHM6oZgYu0SuZ1QUBrZBw/gZt3qQkb6oMUeCv7TKvWaXBJn/UmsjSuXPy6NBB8/55x+0BUsDDIxucTflx8vmKKi7iyogZcgTRRqeHzJEmdsuUW9Dn9bvmM4fkmpxpU7a9hBbTUhgqzqaUkK60VJGG1czLpV66SxBiQyxb56MGinKzwXTARkSJi2VWUqV581kO3DOyY2FZJLMys8j11H0XG4kszEjO9E3EjE9jf6EXD8vfR7R2DkTsSVOkh530SLpRlRWhSEj6S9hiNKKObe3LPp9AfI6mkCgkmlSDMbDewwC37WPZbN7kjGoklGU3DnbCtA1IWer75zgVo/u2XLMRFWoEe3RDNJ/4eKi6D/Vb5PEHCCVpPR1TnxaJat9j55uSIJ2a651S+bwR/4XlKOS8zLg6/9k+ItEINgWCZmcLn9sbmlvmMjs8Gr35YP0JM2iVw01MDIDSaiRmxtJZsOZldYIEFibjGP0r9yUDzhTq58ty+cuEyFMdNBsk3BgcDLMHKMS49sI8Yc3QpkLu3KXFVaG5nC7BrVEvZ8IUVTWtvPrv78ojb/+OjfGSzSLtghKuX3X2xiiKmQhD+etM0OoNL7t8okMs81I36QN79wiHUERE/YYmnEC+VPLTkjUv0kA0qOaDzuOTrk+VoXgwdpcC5KqzQ64jbF4CnmhsdJfYh8yj6L6a+MlRHgXa6kMLE+iRwrBUEPOKSkEGIMsXe/VJf6z6kUTsv/O9H5l/vDXQfsh+aGh4snu01i7eFmuEKidKqLMI0InYR0KY0MhIInETlQUxWmhVjlyvhVQ2kCmUv2rsJA7w4rIbS6ZYIRisqFg6YcXJGsO15OqkGbb/8wmkRzNXd1xQrJ1z+0uSiVbebB+12Y5poYDsNIjWXCMzKaH0AZzeTRIeT/uFKZnZhaPH3Tu3Z7wWAyTdYnTU2HG+wlBW0Zt97WP/kLPtcHJ0AYrdz1k6EO3tWjWRgWrC3r6ZOScEyFN/4H+lrxrzZY8MEIqxfES/bg6oOK0116OzDuZ48CB75oz5zGdM1Q6Lg1ZW3vj25KaNgiDwXiors/nbmiXT2PLUuzeDrpWw6pOmJmdOEo9GRpYHxv/oO5LqHz0p2B3Yx5Eacj/i7K3HJQs6mWbGZAFWtELsXIzMEGWHensFrCjKZDIS88fsjABRaPQ+JiHyFOJ3GUsnCKwewEoiEMyqacO5AmOpew+iApvRc3XGV6Q4IDqC+TcQ6iGVjuiXeCc396XfzeSwTQxaMpnEI1LnbfnKWEVnYYATgixUCQanFq/3aeZ/zfBFk7P3LAgY1AVUGp6QvBuqxYQompy9vxC/t1Reb7uhx3v+7SWguU7DM3WVhdG8B3e6eSWvSiawFVRm9+0SrZJKpSj80oRob3e8Pwc4zA5rLFv86bkjX68123eb8i3cWpqGN3IRLGEQOXy3n8vhySwGGw9Ch8TQNcyTtDO8BHUtTZl0VBgA4SHwfUX5OJAwWa9pkWMnZCmX9XRE0wL37ZC1+b/fkdGkxZnUN/9WDMo//S3B4soumFQQdeuo58pKBoakU84GfTx674Jz+hCjiKB/VafhHe1uPgOzbEsLyujtm+aEF2rlXva31LH6ymvb79aFRb7b1yfF3s8p0AuOZ4iDgTzE4+L1QTQmOPV/QkcSl1oxEQ4dsmru+DHc75RMxiIXKDcMrE9ML3EJrAnjSTBGitmGKCtod53NorAwEM39y78Swfjyyya1ksXb5LgXCNFjJTxeHIQ3C6YHYkEMPSHYVAivCiIzmtJvQwbl1WwFuCLjINanSd0dIDFjPhD6F+jGE4gQIxkixkqhsPBKN4VH9uhTpLQjzXLBYHJjvSSkxZE6dfkA6MX2oFv1fPATKBIlgQ5sDs82uuITUiPktjIYTKeXVBgog9sjJhOiXjQFxdjUKbdUgdZUU0tzy1geP0E+3/iDlel61+B1ieRu2huu3VaSHpVugB9FeXRPP6RO2ijhVIqxMr6FZwUhOXDy9TfMY4fllrckjEPbQHwpmzY978l1dYVpbA7QzSYm5ZbGLsjPzZUPkXPzarxGdU4N05OsMULyo4QJbI9n6xoGb9FvGlWhHRlrUveGAuxoND3XJOOFjLQjJWSAE6KB0Bna5ckNqassMNEOeQRzuNVH7HQyuBo3/Z8rzKYKCUkpwOYrGZfTsrROI0N81scrZTKqdY/VYQNnUGntFOozszuCLv9D/dJAt2+LIt1zcIGTGHTEv6KclZvZxMoyp2/ziOgGrp2ea4lgLNO4FjXBqnPnZbmX4FqmTNrCy9UjWhsHMKiKVLpQrcbUI5hWopDq926YjVZOkIT4ctaHNYRmZ6ePXiyKJB2dyzgAs8zxuKD795FDHYJGc6B9ZlcXmg4PpuYXnH1ThtilZsm4suZdeUcwH1reY69/CSPa337+h3JaJWS2JGxzo/TVd8KgeEd1VoUv8wujLmA48iTcAxUzFYU5/wwxQPhd8XhAd3yKz89lzf4N5pINuEzFZTFbr+hOU37XbImY+g6ft5R+ixbKeK6u6CzBe0lzW5J8CCGvaOscq7GPHzd7Vmaqm2x28dCtswuoQW/AVreuJrekeKlPVGGwhqnP+bnGtWM3zABBr4RZYEA4DErEpV9dvcLlmVfe2PsHW81W9g9Q8IzQk95+yRvlEMOK69LPb98UVfPOsjO2gEa3mUpmn47GYBhayr6MkCQ/XS4gAftiGPYOS6wH8nask6iMKAUrQhMPiI/GB6Xi7tiir60RVB20CjMeT6L5VUJEia6tGDS2uG405Yg5vB7fgh1grG63JtJZlYXuwD0l4lhvxR24NjFumgBh+MHFSD0PISwtj23YSm4/kaxCEvFGJ6sHwt/lWDaMTgRw0DsG5vkyqhXqXD0X29598h/ts6OrXgovYPNgjjaNlbZfyASRtlJiNrrNpgjHasvTt4z5PAE4LegvJP+Qm+hqJ62wJ6yEisWcZxc9/b3pliaZyg6hpZkKoTCGaP+J1Zmc8uxjCaNhLZ9gYFxxB3IJekiYUWsiOfK7sMG9M+NE1uFhOPSMlafYxC90+Y/9zqOHD8eBh3O33vhvPNFGerfJm1067E8DLybftshpu4+xYqwIdOiZUHgXs7xsJ3zwIFIedoeKDFsaQiyB6u/XqPX0wGJsNP74BvmZtESCQXuKe+hMruW4okkMPziAXqS+E+a/eR1rP0SiGR6hAOhBCJ3PhDRwP2ARQgk0NTqAj3dBivJRNSDxuLc0GsyhZ8mIFhkqWgOjMMZCB14SbGnYCAQ0euZP/prrvc9HBSgp8JmeHro6xUSFpQeSDPQGQMHxg358PPHSc5Oxc7G8onvcLs4kK2XxlDx68UnD/vm6ppRPgERBk7rnIrWmhA6ELfClRmJDt+jLpqol1HKgzL9+nbPjB1xIrDQWoG2Mq+uiVCmxonirYEdLJp11WYjtopB4J5ZZmzYEhEF9HKtsVdDAoClj909RsAOn79d9foOno43r4tgNqgAcVD4A0OG8AnF+ZEIaXijzr6CbA+bgVsfXhdX8zl+IJgDfstX/F16QWxo5pzQ3y+wZY/7bJ01pQLyyZ/YJyMO9oWn+zPb3f7QHgJEBhUBwQHOzmyGLJGSSZuM2ecQ1wVQ9vVqcs9OnM4mkO1rIo+zwyPLEog5OVlSsBDhaAERs56eyUyJKXrmKM8CtOpDoerxBfHg13m9cN795yDTbTsB8SNimLEUOKZKUCfgMlZW1e4t8gyAoc+GN+bLyhdy8WLlWHsNGHcgR8no5aqmlWS6xKDj5oGfdSRyuUs6du+QRgWwY4rYVZzocEsIZNeq7ofR46gXjSLDJJaXBi7ATdj2R0PT0ku5fVFDkdmUzxDsg1hqBfn503oyAyNg9/GlpPo0MUFl6Gwy0Y8ayIGofp7cVyYcnRtI41Rq2YCARAeDTOuq4jnFFu1kCyW7fSTzxrDdtN/4qmEtkxgZQ/drNUeKMv9bXk8r8y9fNy2x8H3ECCt/uMx21zuw4BDAanXe2vclk9v5+eyQ27h2ynXbFnxNwf/9NyYGN9PFPtAA4wPQ2bh2HrV6GoCkeRN+B2bSUupf4YCx1dGZA0Ry3b/Z+8zjJ2GEsNrYYOrzTEdyNG3CJ2o+I0aztGcFfUqcaNxYG07F05JwZHXQd2AXhuuBE4Y+hmiA4ya2K0FtvSTGePmCTueGkXKh2opXx1vSawgMNDxwQgYc0nqLzXmn0jpBzjEwJG3wsmrBLToyFWK9VU2nYHgiijnxIB4Enbpi5FemkOlqO4iIN4gmhr+ADJecphO9Es+rnhgdSVE1FeHRYJH9oSCbWQkgg3eqvX5PrZrsyTR1sOAPzUZY4YxAjXQC3R7R2DsAuGTuwaAxflVD7FSshW6tltTIKEPr8501OB1DTUl9vpDJPdjfVNkP6OU/FTkFmJvnUfacvI/5NNAf4zwJAWll2iFiWHPjrzYpCa7YCELIo1ips/cBH/kX7P2PNMuftIeepuSVvoYWdy7FAUdjjkezaCk0OmznZPB6s5qSxD1Ymovd6v3OJnxsPVYuwIoXQ5NTZs6J7o1Y+b8ZlUtZFUWlSM7Dyre5USfkMtyxsRjWNC1QWz6GOIX25/GWilvRC7YkI88Ro2mNHhira/TWPN3vWNTFfXN6pkk3cCkutxubQDuxZOl1WYFtj65YsM7GIpkAE0VZNZNuWkJmaMP1dJtknj9BumMi4sPj8X9za+fUmnfOdlzcYWxb3RYtnO7Qk/xTUYt+ptNMjVU56cF3QtJ8iL2y3fQs2s6AYHa6UffUnLuyjxo2wfGNjR4/Kk89/JSvawR+YGhWOoy9RTdYKieNnXWPN4OP+0hCP2edR1ne4MJHWQvFLXW1tUbUZvstl9/Gh4vLh3PzRQMrqGnx4CjdhZSOTzqvOWya6A7OBT6v+jM1yTX8Qwu4FU27dG/Rzy3q/mEiPmIdwIIkF4aQp6DwHba+OH64lX0EntudSQcEW7JZkHVa8UMgKr71a/ZOz6s6NZczXg6batmvjspm4KfVaC0VWi4exJowYsoFnVzj0wr8oK1ge6bXxCbo2DL58U/IrDZp9y87Wf5+YP13GxidFaDdtNAv907wSofVvX5z+/jGui7Y2mJkFs3uro5KisjL7609LxszU2H7DmUVp1YH8+Ih+LRwQMV077d9TlbovujcQcYU25g51Ld68KUpj0w5/y77SjEUTOYy9BD3f+h+v8/tvfSHhZx1VZ4fdxUbGRzKcwJCDSJvl8QXgiALinDbRwidOyzmh0FcbEkw+riySvpr1BwMcYzU+0ZgWyR+hg5qM7uOsAF2R5Y9/ZL7wRTld+Z2TJGDbQ5mNppmHo8GZK/GBm0t1OdbhZ1JXKn3bapfDhwW9ffOEvPKHT0v6/n7H6nHGTuT69TYizxBOFeVj8AXX4sZotCADyldThwCDz3RtZXONBF5y3fPTonPMyZPmpZcEpUEoNcAQ0BPiK5jUCbZ/saaOa2ywgHtUz2IC32BkWPp+1ePVhR2dgrYIZSt5vOH9fAN2txkXR61m82KidTxmxYOpA01DDFuQnWVTcUG8+/hw/dBUoAgTbLJjE3/7bwJV5cLVrYcirGR18RYQtig4OBgHfulIBfXCfaJeEJDxdrfZtMFxq/ia4w+jrJOymY9CSfAr6pT11sB0iDVOrtKirKuE64NVy5nZ+WAg1ZZHxzfvvBEHzG20Vg91D4a2RZDhEXAerFDIwaKgzRsd1lEeloGxJQlU0nXXWxZdvjccXhJ97fL6mJG6/3cEuOQE2Q8xIQWyUHrzY+GQP3n4acu6xAqoEXmAwJr4xuSJLwRtYgfzLvPUk3JNwWhnhdTUCN+7haycKkUjtH5K2q/jpUr/7Jg3HDQNtfJabsScPuXYOsB7fv7wkKg2ADFs5HN66vLgA5nrpW7PnseCOa64Cid846OVRc7ICQw5ecZB2/cHsp/dWygOgRVxVyoJFleHpLyCIRApMHTzhoQMDqw348ISgdQ0pUIT4uIEOvmrtxinEpSqPRUoWSC4ja9DdfUi2oB7FUIEVcdqePTK66knjqQ99jyfcHL+6tU0TrXmpi1Ow0HPsWaaU4AapTdB873WA8eG2/VF2wvnfcr9xqYiPOyj92gOoXQ6NTW39zHxLUqLUmyTc/GK/MxkQkAV3UrdCUSOHqBRFfUoaCOEB6IkhE0jm8vkhsZKxMtLpSOxc2igpo7/xRJD1C2YE873cYlnyx0hQ4jXxc6FnOl/uKmqUnjU1S17qdJ5Falcipl/Uu7IBs4MRdJliqkkh3GJt6PlwbtGTyjOoZB0n5+JNGmY28wYMjQ0ap583HRYJly/IVXjW0SaIZLRgogfhLqgufUINbgBesTR5RMQDGSBJ6gdQmb4FuEXJAWiEem82q0oFa2vW/KcPy8DoeSjXQzxZkCizuI1EuDtqzCgPHiXr1gf38lT8n1Ea+NAaY65Ddixo0wRv7nHFCB7uydgdm1z5AQP35td6f5hF8lqylZCHXVyGIhGgCYnk9e7OV+ER8m5lfMXzAO5FMBHVzuB4p2Q29ZFEUJ6txKCQZjGJpSzg4Ckeu08/oj/KFetWAYZ06IjXzqf2plvTVRFhWtlRWMQnrQ4QmL5LA1QABtf446QXEVXV1kTzgIDeSMiWxmxXLfOzCL5ROgWrfuH2eYVywOZQYAyS6WyU+PSgd+dNns4vkEsgxkUu/ThxBMcINVOKLH6eie+WfF8U4SlqwS89BkWyOf1b7B9u5rD+ziYPGt2j0um+VQwwK5Qco2gY+bpZhIESYwev1XOIXoabBgdfe3fJ2bY7QRH9AWPOe8YQmrGb2R0R96X6nxqgpkQnbiOreAs+GL7O4qFzbDuyMNlrDyjJrnzMp0HKhsdddGxiTorT+jGXu++fy48cYcXJDK1vLySkGYiwI3BzPRzae4vG1p2US4/gWjSMpskIIOvoJkcJ4pdXB5C+7MTEpL/UrV/ZtwbtkF07lFM59+XlBBsj+QmODDNztADL0hRHoYowHLaXOiXd7Djez9vTeSsACEADD0i3S2P6ALiND8kURgaV+z3atDkozJAcVqIJLvwYUQsNjSRmDlrc7Ca+BP4SeNHbe54U1j2Io3LVlRUZLOxN/p1zgIWCoXMxqHQGBuEWFH5qCJ98HcqouJEXbACrAKVp3SHZCwSsrqhm8NDy4SDag8YikynNfyKkUXV/F2E/IMleXT9QQ7YHv/BHz7+2ufzADSh5Zg7KSctsomRkNcbSC1nvLYhCbd63I//pvRKj39cJioBAFHH0MT48txKOCgAi+kSjU2OKwE+QAcy9g9YEeLe7w9y/CeEiCwvZ9EQtl8SUEfLE3yFEJVzN0xnvVyPjMnBo/R31tFAzMggQ/uGYW+D2gb3AvMw1DNbxwDWkgIavsN+AxvoOvTPB2IvEE06DwSIQUMXtdgeMboi/cni+EiRb3lm+U53Vk9JweahTPbtlVfQJKB9/CNF0gS2mW4R5fgO4jHdUieNK3PLNR6jnRgoryPw6rdEXOn8En9rnf1ofYOANbBYX6/kPjo6NbwS/YMvyXXlep1H4FMrlswYd9AU2Q5CE5SPm8Ebkmx6uqr/pC+9bKalSpxqm5xNVXXKk5A3MHJhJicirV9Q6t+2Lf69nzoeCGALnWXrKhP6GbSkjoqqt3qFPwBEKBwSdhIohGgIxABfQttodCBRYcZdLet4FCRdcmF8IFXKgjM7SgCgrC+St4CPP4P4VJROnlsSrK2VojJWdOG2AzoJROLREHaEyjeyL2RxkHNamhvkvqwMeF8KByG4CehAT0jLmfycBNF7XXFOhEcD/PwO52lfZAMtBjH5DUygbjCFB/LqvDtyEmtFg6l/w7BUS7tET0G6YH+GrmAQ8wkhxlXtKkS5xrYtLGzaJJcNrb5MKuNypXWUAFszwUKDBXmUlyfnt8BVyON3V1VliM2pbPDRxw7JYA4Eq0WCceXtwMdQ10Jlpbu+QcSJwlNR5g1CuAREMJnBGrKuDvKCLKkKpdXoeeVVbpc1veCnu3cpuHQLPseAko4Z0iJ0WWJaOpBy7bTMddQcvviizNa48YpY8sqy9HffNi8/4Sy95ENkQmeESpgY0ylMthySqtG4b70rj1582kyNp8vhO0SmS0uuqoqSClvW5bn07FR5uWiD136YwUFta5FUNAQDpBQVVArBN3DUu5g15hI3yuxOIBcCA5ErBwY0PiE8kcHnQCDUXi/X16952HSC5sC/hN55F6lYsjud19cLx7R2OJwUlUZXpwwZg3XNtgw7d8gj8ic9lIsjv2DuD8o1vRtFoUvy8EspLWpHDRXXOM/kD3GBmBAw0aqDf8BD2rL4k2RCYmhyQlQWzaSjFhQGV0qvGanFS9UZjCTA9LKvT4stHjLMAg0SQ0giYyGDI44nhmZDi7IIDaLz8VSFH0iNS0arAYUhikdH0f6LKoPVWh6GTJkmQP4aGlD/Vl54RGvjALJaYFMChTMpgVxWimUImv6iEQS6ts/lrmoXFRBYmROlQzDGOgCMRaQW454g/VskMC/XFAMwjelPS5cHSRZYNU8XINqiUkdjoYHnOMxNEso4ifo29u7j/oCYnVaOGfZlRfiTHAnHXMEmFsekRP/Y8WR2ALaD0XLrs7O/HrOax9qsbFhdduQJsbPyTUSPqnxvwFTYTo9rQcmVCdhtJIruo0u5t7hQ1M4S657Bj9ykDpNA/AFjAbW1SXiobEuF3CDKcAGZ7u+X28mJ5NCE7w/+e7kuwc7BXjSDLYTMC/MbZqxA7AfXvs5UXpfrmZnCPg4CTum4POcBzg6kYAVUGAo+uDqvUyfQh5XsK7v4C7uGSKKHJ/UBLjEelTL2UGjTmDLdSWcs4mHzswrJ0I7VCWdWjmgWFBBS2N4huaEAM9lyFTtsWc8dk3ahryD6O1ZJWxnuoLSsjf0EnE3578nbpsplJw3BOjWRhytNzXpTJkY/15Uw/XckuqMakzJgcdXK0l4PhhQg7QibsSUJ2loBt5mu4Q+wEtdhRWCCjM9LNcbHs7393KJjmbqvdY3GnImyku5h6GcS8/EvobwbbQqwzOSiuXtHbiIp2dMPabcA7uPcLaAtPLftYJrqZEZ69VPS5UUPMCm3rryxWLqfd2aytzdjp/KYs7dk9x0bYv3IniI5rFK7vTjJRm/nzJ7P2RsMQCTiY80FdO2awylahLlfb5xFGCgGhO3GJGPToU8RArDvPfrz4RwQbLp2+g//21BHpbhElWWZ0tIM/VpPthU87uXwD0EQoUK29h+rqUEJAIjXy6Njx6YfiP1PxZLR+pLpvmmuo5X+vGh2fkr0D/0EFZwfMXsPiMmYnkgvDg8XC5ZmOUZGzoNKpHVJVW+v4CFmGELswPbYHpl1Bq1rESlBlau7RX8GCCqEDYfTqOXoofXGjYTb1eiVFR0dghMJ8aLECS1AgBJwJy/WNMh3A6V5HPKl2P39V8d2PF+uEzwWJhP5hd76uiSxcIj03qCnslkqW1CeGe2P4x507pbyFawL+d1JhU41sUXWBG/fLq/gHaDjiB+zMgQCMxElUkE/8EzYu6kzYtFW9vz7rpKoLOkANUJeb6Qmx5w6LdfNM2JdIZ3iX1ZObMRxJi9fNAd2mybb19jQmRUbYHM78BWavMZefzWtId6b6Fucn06n4tKU89Op77xrjux1zD12E9IdLJh7pspLI50UlcEzhY/tbYZd35TDt2/Jfrn4q+ppJJPp2ZH0pHUScBZSC/HNGzLJmLST5gZwhNiviIisRuvhPB5Bz73kknVI2A6eX2hQ6Pg18/ufs9uyo8jY9bW52bMTR8HCbX8xWx3JQekQdnhyauG1k2EbYJuZTEdL3It2d5OyKo+HU96yos5cvcNMDIMlCjrxGPEt1Q1nRQ0Q1jom5odvmq9/2cTuDAUZiSAuCJII5TqnuzCfjwKcYyjWwiram1+APNBA/9CN2XXbpPX7bixVW1jPqALEYBqi8sabcv3Uk2laXOWnoTEDB8IslbGyiWvB/GpsEyQDFFOTU5cGoq2ivaM1ORNDi5gwiCYg4gDk0msis1RBkTEQDacOdA4BtWnNjo6Mlo5r2uvbP5ZHh7ZKB6FaEAYLyWSNnAJuZqm9846clQxRKtqi3HryvT2mqURcCI3CI8a0oNYCr0C/29Utb+GEtG8NlpYLT/CaDv/e6n6mx49dOZ/cvCHlU0eqsNI3PnXxPREM2oazrThUB2LKD90cv8IaAqkOAvPFJ+RR2A5A0XZaIyrId0cvDfGoHDdFYwDcMF7DbIyuoTA7dkFMc8xmAyERAF6he6n3Dl7kK+SAvwoh5LQRYT6ovl74z1wYjTL6p6Ui6pUxSIXZUseJeAR8IE6sfEB4yEGn3RNt2LlTTtNSj1TwxrRspQihasCj2l7UkSJRQdgOoSxpIxsxMP33TXur+XfH5PdI2uSkzY5mmUgJ0dzoE3QDREx3alKONgRzQ7BBXH07IQpXH/HW7f4R0qQv1H05prutPPMZETMFXpSBymrrHzwo2hjFrh2EbviIHooDF+LmjH1hPzo7Y1pxd60Mugn922WWPEQCM6PjuQUWO3VukLY/enTuvkTo2de3uDYaGxQHh5F1Fm+omrlyS3yeemO28MCYn3J01X3DSSUQAgNeP5tyDtFao6/Fi+hXa4rFpUduqw81egJiwVO3erzlxfv3i4l55U05C8vaWO7kE6D4+ga5lugMoixvmBN/NXT4t5h9K8gZQ0Buj9WYwR55VINvjwKUSzFly3YOm3YEFAUgXPUYGPC4TfOrf0DA/LPenYzkBze3BQVoGznhjj5JqE/Votfn4YDm90CYBFzZaIry21gIt5jIgqhZFg5ztoo5uNsU44+hKLKBL5eaYUzkDHfhoXG6SXO7GNyJwcTtW1ndOXmETQo5Xk9e+LvSgM0AzrFj0Xs2xwmOFLcK8FNkre0C6za2iKgI0RwY7y1PmnCp3KqJHLkq19a0LP/gdYsvxEXFjij+Q6lgzAT3fNKsQr54xSZrXTbP7jd3T481ToodcmPDAmFdQ2W2bzEt+8zdM86YIcqOImlop6v7/o15rCEEePlm70NvyUDbADBpTwjpS03MjN6ar7YHBnP77kljj738e58CPW69PsqAB8/h9XqM8A07DgxLP9FLwVXbtdrohDw2HWF1gYh08q13Ll/MEN3NYakuVFRTNjDwk1flcjYh2VpMJLefSMU2xdYcmac8cFnEu65oQKY0KMIL5WS77gyevF/bJNIejniyi0uq7bEjD2xg5RM/8SjBw3JAu9ta3zq8Oc4YFESsF9R144bZkm8jRmk/O7IHJqVRx3uXrl2PPfF7VZKOuP3o6NK9MRtSN0tzxlPZFImKJHDub2p0TqPUoA2QNzi4tE6cgWTWkzMXyy4JXAP9EEjGT9DxKNZXAL80qvfc8+6gP4Nyh/buEXedNIo5iKp4PU4InH0NiH/tPFIkyAgCWy0u8EUIuAkwxQpCmDwKA8CaRv/Rk9sKpPC4Eez8s6Nw6uZotFB+Fxxfwcn1SYVEwCN/xOO2I36h+Bz4Zt9z+Z5SAeKuB6zr8p56S/iTFxaEBIiB+ChQibIo1gGicb2uVR5h5GThqXVulu5PDZ6fb/9amfPa/JyfpBa7ZXp/2t+Tatxmt3miw58+JdMF0XfQQL+JMcmjWq73HzT1m0xZg5kTCBnKK2jIur0MdlGeizfu3VliQAMqLEy1sxA/xNozud23WcqjJhC+iXkLOgNfDKeAADClEHwD5avixmGgLg3YYGv++RGep+y57itJFuibkiIyEbOMSjnznrOx+YNB6fs64EM/p0VYVtJto0TA4yf2izKFvvo5YUA2az2Dhka2QDDBelglzzjugkXAWgiUiNvDeF0fe2lZRcwQid8vAunl5NfkipfwMgWojm5KT8FIPG2ImVo0h1YW9ID50Z0tmmulYPF4nPaFKvP7iRGe+qmM5e3/3zm9qEP4gk8AXbgomN225dm/ure5LeN3S1GratzH3kwzUMBsFyhpZ05ustcqbzr3A5jLJ3C28RYlWVLEU0fYRPf5/ZH1hAalEMHA5Fvnna0ycDb4oIoTpQAoY9HUOwVeQ9oLEFFAM1KszglbdLKy3W2lnQTMYRgXiZZt+mhTPq2RzvWdUjNYAeH5EI/QFmeE9vys+cIG2b8DQhIpoRpOOg7pcTlQCxD55HiSxXYM0+MygWhEQ6/ZkbHUWNbsKBdPHfJ63cOjszPi6+DAkIP6EkXF7lhMdhaFFRC+MaKlPKENES08CtUblJlR89paW1YaEnmKSIdduP2AUejMxMTZ03Jb1+ipqHJ588Nch8NxMsSjgOA87CIEoMNEMLC+wTlYgipguakgogKx+AuACGKGcHSRfB10IgEpmaFDYohDqxBDdVRwcnhK5hpiwFvDcxMX2gZ86GKcNAjVRUTvqRLgFrECPX/nHXm0p1WEs14upQnSjMoGnEZHYskcRxHimv0F6Y/UC8L3K8jPZqyxRk/S9EwZgvAwC4sTMFkDHIzIUgUNTDMURnlQ5hCdHS3KI9W3Kgby4BGR2HjeAABAAElEQVStjQMlGWdVHlyP5pqBmKm0oJgOy5iqDtHA6st3Ev/kX9n2o/cOD8e6HwRdImqcp+iuaNCdV4ODQ+k7S9rK6MJ+O8hjtbyM06zEnNXwBBveRizXVrwPpsINtMdPiuePzampKpAeRL8IBVkBq13s3ooTqtcXUWAAPpWK3FI7RGs1+IZD0fGLD0qrBLrhBLHvZdRj/k/7Dm4NxlZUGL5AShb84BiodGEu0VHf7ZdHYAJR1h9GKBKKqsGOfA7thJV9/STMLCwN35yv/u/YAQ+Pg5LF3ARliT1AvT+e65vK39TgeKsXjsscCQ3T0k9Wxk1prSTbvM+UbTT5dSY5zB1rbxv3Z7wx4WXe+SvU7NigpGILqK70h68rk8cPQ9aMiY9xyQazeJXi0vDWfXyYjGzaBvu3Lc8U5DkwRgbEixuMuwlv3T4cN8lJJ5g3Ihf+vMAPviEmkqkEePI6RaNoVoqkbWTf+sg/NKV140x32jzLFNB7K0G32IPq6rtoje4TgjRaa8pNedQ0MMG9TzI6fVo0OFqbgawrPX5PWqPEqNN1BLkkxUMQLmqMsxutWsbcsFg6yvpCu216Ts7S5IS5bc3TWuryEF/9laR8RHtcuY0mIJ+QxVMGAyvBko8lmpuepg48sceiMr8dKzSZ8cnkGHa/QiZoQVlT3TQSCkmVVmZEAq0u+disVx+qpNF/i6fNwrR9D1sVDqkRuv/+aE15Kj22+OYZET23x11X7QQN6V6U39re1bwe/f9r4oDC1rVm1r6rMD4iWpF1ujltdeuY2NMzwK17brEkJ8g6Cuju3VRdpeGQe64HTk1XFifu3DLb9iKExtdeyw64PsK8UCToX7o9bU8BwsaD/4CD3VdEESwnXGXRlEZ/Ca6jZ4FHGj9myQQQ5P33JYPy8sz6bf5G9qNAUc5O4W4BNRYW5RHGI+WSlBBGbt32PBkDeeppuQez3LyJdwddumH27XCQE+EtgA4rbTo2i82QAoGbrGNXsKtgJc7+vFK2qrtDZuJ+6cSde3clFTCxeDlZVLrAtd+d7ugkVcwEiF4ZF2t7xkYT6Ab0dZnsg6pDWMyGIvj+Z68Ye4yTjK2B+TT003tmLOWeWdcpjRLc0lbDcV6USd0JJq3JEmqxJWyy74ot9p4hb2mLhrLYa3/p2r5Hit3fk/QGe3c/A1SHw2Ezuyhb0eUI89lx2M/rFpQFmms6zERZmagFxivKIwL4NqyTlwSgr267z4/0UCCCU4RiwY4abQXtMUSjc0IYQgNH4sAoEGenLHiuDi3pifFzjT8A4RsDW3XSGu9eumhuWDYGMpItKJZpGxBNz6Al7+o1K9HyIqJfw+Ry/ZpJ3zL5ortNbCp16uzl94XDODmRPPePX4v//kvyJMCWw8GcxUUrq33JxMrcj0+KBv7c467ZSdmT3Sp/OXoRtQbWhKgRFcefhDrbTH+/2bPXGevoPT/FCED7butAjIzE3r0Y+tKzMlEMAl/fvCFuOmZmg3+4b7nRFjU3lMHXolKK0RPxn0Nq+EmUF6ZBfJR/wP2uXrllS0JYTUwBqq+XkVD/0uLtYxPcluXFG+qNnaMuvQ/fQD0r+s70jDSTjsNcvGTa2xx34sknxTmRALS4ujIND56DyyHSP/OkYZoQdPeO4CeCx5ohXhw9Tj9Ew4H9PMXC7WcrU+u7J66edlqWzkWliPtCDLBQHr6F5YBwzO7dSytM/OMe8+ou9mixPaKzs73RtdR9Z4B4A64Fg8DRok2bpHasrafzaouPjmRgKnJ6877kRvfGIVELTUvh21JldVlJj+Cp2zsyf3f973HsAcF0Q7Bm4FTfhXNgDzFUyXlzZ8LE02JyRu/LFMoro1yaJZfZOSetr0Ul56tXzKK8IeMStDjTinBLIObmUDW7IlLiJnz3rTPye3OFaAA8z0Ibg6AwJFN/BqyGi4UvpJX6yZR5wh5vILm5pU+98JjkQMAdAYBsjEVaB1YdANXSLkwdbDYdtkfgGV6w7pCqQQQVDihmpRs+85TxeRwNiY+6GEsv2pYlDd+iwJL/kCkYS9/pccb/Jycc6M+jgN/8q++ZlxslGekpCd4d1Ye0s8vVI1obB+rYDs/aIJT4xvWmhU3aRNhFkzBRCGUrhMux2QzdlIafOX+runSl61pm1xOihorW15gN670aafC6m5q7GGqGCmhBpMWYv5A7U8mc8VVIhGYVxPTwhNGqt6oPuW3rdGe777ieepJsZE3v5Rk1kZQdjWg7gSBy+s3z3FuSI49wz+ypgNE90cSC2/gpoHm2pKd45FpN33xjl6RDM+J52q5stgVFsWPT1DqgcNDoGEwIJU7GVmzl9oOEYKK00AnQibdSJV296/fmc+1qaYmmmKOZWbVPpRK1VdZ5PC4COScTyykxi7Wl8bePZzduk+ve7qQ/Z2zTc2JJTQBoOSfOQK48ImTpnxvS2fuBkrwNG+bnxLaYk7cFgNqohdz+XQgeQlQFa/RB7GXdh4fO2GodMxYz3h6zdYu8HsbE33zf5LA03Cr65Rlz8b0H50VNL82sAGf6b8R2bJOUTB5DjWTth6nlvVVxkmcfTbQRoggxBIjmOXLEifJ4zt0n86pdVonQVO+cNr/xG6ayU5I2DpueuxqKCxSGjv5wSU1VOuXszShp1kxIyF9nzT+zXYzZKK68SE584fZ5ETxW92O88i0KvbPmDD91QpVVGNLECHaZZFOYMsDe760hR6w9DnGFTYnR2Xd4yl0jttO3c/PGDZ7UvRv37emdVZXZQGF4wwaxSffHzb2kHBoOEStWV83effgfFdcdTJxhXuVdSTP2F8NH/nG+AoWSltmrpyZ+9J5pyBUJcLky3bfMpKAY82Oc2F+TtEt2j+gDHPhgl//Azx9x6U0ud1sdCiBz+b0Fxdm7FyVpYiVVUrtUWEIzmYLJNDhgsEeauyAvceuS6dgRdrfWcxtY1yr4COwDMfQf9F+/LvoHo07EiyCr2w5isG/NvNdBD+AM0BXYTneCwCUDMdgxJwHlhdFUTgSrwTRFCQwz/IKXBIEs+Y6G/0Ol4dyOKkE95AXxsWBQ49lMPQDf6CgKnkAo15RvMrqiSRAH4FThRkWln8VRs9KPc9y9BMFyi/x1ddIHALKXLmUPHxYkB6blu8ux5MTFQW5L6hlbT+qsCfYQAYMSI4fwZ2pIzu5/ogOlwOAhLcPrP4hv3hyvKZZGyWHXDQb1IFVOROZYY2FRsKvrdmVNLJXOrNgRjWBd6a4XTEEai4CVzE5NpuqZSsF7RXekyr3dOjs+Ozn5k1dWntwvDA8UFuZVhnNX5BUQIUxgTpx6PiXsRVbugC2QH2zEhKGXIbwvGkKdE6ZRXR00vyHWWVoKsM7IE74xNETh2bljRq7RyPCEELtG0fgQMxrE1NgBH3yeCet645NI9J3D6K0u//F18zsHHBAcCHtmJtJ2VM/MvdXXTCHwyQalLQZ+crN2X23LQVES7nDIMzK4d/0cz4UoqNerbobfmynIzzx/QH4uipiQT6aFWj9amg/+wwEIm6tf4ZrDjhAnsipvF08jFc7zzk8F2MENCocDs2Pypg6EMWns8uX3fyTeZGd7RrPluvdulmalRjifEAwBiKsA4uoM9DssrbQTDnHWdJxhlq2Nls1Oy21hBeMmtTU1+2RMJDA3WZmeUL1JVgQXNFIuuWelqABliHrTHKyDgkD8yBVRavgPjbFcB/tqXS/6VD1+prS/Yd0yrc/0HF1t9aUXpWb9A/JoaRHfPlldIaCjsjwTWjKjbGdvP8QoLAW40y/JDu+VhmOChxYJpI7TqIjq68h8InH7TekR7V/bHV5YGJtOZKasLcDdmZ//7o8kh80dsghOOy8jgbALkWsUA2Su9UjtkBwIoIZcKRu5RT6r69yF1cIfN9vjMMOPboxqiS+Eg2ncHpVVrD9jibW10knhBj37CQs44mmRc0RXYwFBu2XovX5SySHO9H6KoZ0PDwQeAlAg+Iwbs75Zrk9dN9sbJYDDgdsQ3EaSddAYpzeca968bZ63vtMzTabE6/AHqaivl43doTy7Keg3z5hn6+X22BWzZ52DGNFYNOW52/L7gU1m20YRWnWDWbFG7agI9Pjj0sWohXpihAmWJ7Pa4qSHYwrxuxbMJk4VCjlMZuAaH1u5ijL8XKdh62wIR5jcqKCuWqFTPKKH4kAyISusoEOsFcoxOVljp1GLt4A/T0wBomPWVuJOi0A2Nib7uk3bnkJXh8iQD/1Iw9+9J+kSCYaX++0IwbfpPnbdVJ48MFNZcYH89hqpxGBYdWvv1/aHd2vERkhq1EU+C2oJd6lqppPkhi/iafHIAnHyh4CUKO+SXGcjeBfdjWC5joKVVQbKmWUrarCKZScTWSpxyPaXgWVzGsVrc8D3YtEyDhFiCSFpKMOd4jqZ8bmPnCiFoQVdM1ECOnE+83LJ8vKIaPkclyvn8GH0vCkul2eUhO6qLO7qClfNBLBWS1bVVFVteCodSYm+w+sgkNFYf5/rCP2fUMrx2wIyoPGJ7/z54p5NgiGKSr3wo9KWzYdzYn1atS2S8tOSrbe4oLDUVmhNm5p81NdsoU3EJQEv1b3B091R5jM0uZxzZk6+S/QuekisWIHLFxjpC9+ZEeBioQsqWjVkghNPVt0tsawfTbBChaHITp1AG3ceErMYqCvzLE7ltiFTEiWUiUyuLDhDbhlwu3R59PWrXOb4UxgvbAeEGFggKNdrJ1gHykCFQrbRsiCPGnuEHWhjcjJdYXsFMoj0WTD4CXmTnJRzn5DqQx4L7jQGicc81lvJqGbLIgylMf320cf8IcIAJy1eFluQiq2k7o2SPvRCZ2R2NnYlERsVufWV+zNzWRAvlEPID9Uhl2uagXnFpjy0YuqanL2vqhoBcGkBH+Qcm6MP5mUda44FPLMkfIAw75+CG/bVR38+gQPadz4h0c8f+3x1dYLdQKjFw8OpFWcj72PHTWt7LMB2pOIdzOYWeKrzpEu547H2nbn5ezucEQ3cA/4pLpiazi7FdFoCflFRiYclWydPyqcYDymu8o/dF7WACs1kBczpXBfizdgji6lEZV98PxOJSDIMGLOuieDqCBJId9MmJ2ycwzp3r3UI9Nm6deCg9aBApGpWNH7ELvCoz10CKmVj8WvnRdDn4yP7/1nFpW+c43rrvzgsMGrSKodbNxOzy9PDqbKGsGSRyW7JxhTi41Ch+YE4OTbI9+4PV0D5He2SSsD/6uyvgprcTDKz1RO7Z6UbSMdToB6Eb7Z+V9jfWSs32OrGJhNpYOtAuWWfRkbQ09In4X6AtSg+3+ib97grLIlWlBGUFj70982yBcLMpODjsr5+Vzg8d392gbgjzklvSmy/9YgCU1OjvTEfqouMiwS/AryiFr29c84c2CFuErRvn4wWghK0mdCtqEiUp75VLVuiyDV9lWkhe/Y4lpeZYgw/qkLkKToRiN/UKCnx0lHx3/iWXO/eLN9tbZZrJALDBxOy1vMZjgnCpk2hSB4bTjiuV0GlR8ZTGJDCP0Bb/fbTruaaAmMjtKlJ8+pkZ6vx11rTy3roVEqdN74ORC62jhwzSsiZbQM083fOmEN7pYIQDYFsghIgRhUYtYhWBz0NmCETqKqW4Jwz0uH27NslclZZLUnXtQJgW3pENgZ7l9btzE9OoXLlPGiYg/9mPWIRDAQY0YNAuhs3OStq8JSoOAx86kl5xEDHjS7H5/QXhGT8oromV6vx7gjeiDir1lICKrQKmDZSkT+ZQNyClfUNqsC4DWaYC30LUK7oSBDdXWcJE6J9dsRsLzGN1lbCWhpCF2jRjkND6acLBcuRf9pueae+t7gWLmPn7Qt7KQNv0TgQTS8Mt/B9a2nuwmSs5qkt8oBCj44W7mqJ9In3hUd19/xMveUiLgGxEhVOSosI0Z0pLcTINhpAPWGkEUmjvdRDRjCKopn8KqvEGGrnntgAY2VvzFeUiLejHRNtgIbBdYTuD8ruL+vq5JpdFnHtXnnVbLSdlCAO7Gq34s2+OzTc2yfM5z4rKfGKu7ucsTuxjnRYrCUdtlpiJdTdyqP030ViQBYK0CJNTWZvSvoXRCvT7o5IR+RH+A/pBN3dVY5woYqO3jZe6cpmW5NUqM0qA95FGeDE3rguj4gF0I++fUqu//AFqeZrr8mZhBDXb14yv/mEXNPKf/yqOQBMBpqPiRig7lQL0joIG0EuCMnnvAm+BeHB0mGRH5gDaYvI1SNaGwfgXqvF0TMpcbFUc/Lq0aTZuiQiASGk8L8YpU1fTmUKGgoj+zb+3EQi99rHZmfp8v1ib2WlBwYVGNQrd+ZxdOnqqVkICB2A1rOozD5ewx/kl/EdbXQpJPJEp2LDIai5BUS8vkMuPT1meNrZGhujQmdldovGYsJ5yda2Kc7VJFn0S0+IDrLzW7I3bk7cj//kpKm1GmB+0FDCIcnMLCbND6bNv+TcRPIy5o2jZjQte81DDPNif6yiktsPEs8RRjxPiKkDDVvy/Z0tcsPa5rpm42oyAfvMz3YiHJ5oTeTMjCe54vF4R167SsKcXcXFJS4zJF+9cmWRCMX0CHU2EbRJKGepb3J2QaT/7KmUJ5vt7+eSFkhhBHkO4eLO2il/cvNrImyvDXz9nbKzBty4QBfWyJJXxJ9wotEYLOj5l01xS46aSPeY+elIfbOHiBxPlqbiGHQ1B75hAdnq/slbH00ks7pTDA3M2b7Lk8uKUgiVjRip4UF69+2VVQTNVfKooNWsWyq8KaxMDY1iBHSawPucPSOPH448NI2FhbwmqpXQYE11rlZjegBkyE7+UNWIVPIT3S1aln8CJh6elPk34GTGlFpsOJoVB5J++olEwUnW2iAJGaOjm+c+vU1umjCRY4E9WxsLhF3uPO+dM1Mam2A+INECixPFXf9E0kpNxk1NxjFJxc2FtNFc1wjvvvajVLTYRALO3IcLMQmIiO20MyHtyK+9efTn18oBFPXDUEtLUUTCH96bco69x+erbBaQ/tkXYgN96aagdJ+C7c0edyZ+aYDrwl1tOUTRAXQMXmC8uwbpiXMzGa7v3kp0NKV0SwZM1MhQhkjZgaclt8JAjJmAFdsquHbPzaQX4+AG7ch0KywEARIIuAAk0og4EsnvYBrd9wJFCQxS25aTZ/eEAkeAAaELF8avDLM6CFqOGXYy2BcSxXTrRnrHLleatbxLIszt63FNYk0l8ujK//UWS0eieaKO5keWQsFMYUXIDdhEQy3GgVBqHGvbQi6v+/vfWvzt35UPRQtklA8PEMITowo6Xyi2Ep8Yz168YKqkfmLjmPSlEC3aWRFmU+Bd++SBu8KwM8TSoLl2RW4LC2Rbof12MHnbVkGg/mDFBtvL4RkctlPBPv8fl4pzljK9/bzhyi5N3ZubmcoEg8JwCgPSArdBoci8K5Ges64Xlg9fCyRXbctzkOX47Ihlo3qYYLA7S/91nBA8zfXlu5IDey3IdvSWo2yoAGJjTteKVdggCbZeKC6RZDLK4Tc3bjoz74H+8OH5l8I88iwu3b7lJNPZa4ze+aw8/g/sjREWAAC5jJxJzUFeXPs4vU1GNKoFSlOL9Z8zXmyxtJHJ9Jg9u3NKSibfvs5dCbNkVlZ0XglVoIF0+Ah8iY0B7lAXaNd2Qdg6bRVjgcDoNYMDeIAe9j/EMkNBltcQBbPaO3ZXhhiYG6TLqAsazMZMQa7UyHfs3NVTY8X5YkYxdrrDm44zUGSKwebd0G98NRguC0ej0hLMqwVwY4HAKhBVfuyAiDF0+WxiWydrHTzOuVJlZZkbszoqSztSWm0UGpQhi/9yw7wIFCL6y3RNaW0h9Cm+CggbTwmiBwG4VVaZTkmXYRoO1FBvWjbIoUCUBKLk33vFrG+XaxA8fTObFJgS8ptv/cQ8d0AnTor3yGgtQgUhwwwYpuwxVtwyBMfMFhgrlIr72uq8B7fINeNfhWX+5WW/HvgwNpofyVTbvsxfxXukopB4yFSQyAX0hRfFyf9/LOu+uF5mWtKPFSbyClEMh/r7Cd+wXT63jbUp9A3LuvCrIfhz6ZLZvk2uUTj0fWLqEI5WXYWpr3FG/2hVvqhSxxA0cjK/4Ph1/kUZ9iEfiAR0eY0lM4cE/vAPYA3ROqCQVy7K9VeC4i5WFDieGMiAMvMLBLsQP1xH6HKP2dBg8LIUgGL/9rHni+3W/GXcjI3mIT7NWAIaT+fr0qb0oxf3yiO+SIZ4eurLIcCPb3dUHV/86hNm2eb2fIWoTTArogiNjonXqpWlVGhRRAX60S3z2U5RCBx2DDVaQCBXj2htHGARZrHVsfeHRYbpbuw8BvmXTH+/DKFDu5/KYxbeSNc81+WPt3tbm6T/22neAlJpnUER45kHsaV5c8TK7fUr5lZaINFWHuBIM0uCGYBWvDnQaCYuDol1qwXC0t3VrqOecdYUPP0SRON3BAHRhcS24qYjHzqAe+3q+R+NoWih9y7LbF4rQfJRiC3cb1lR2b4tjdyzIJMfr/zr15mjW2RN5Nz9JWzB9g4zaTsFHfQBw7P23Yqo+XKxqCMUPoTFbwsZu8jXnFkts034C3+oRX2FzAqB2vcV5uzdbLYclhsfe/BQKE7ytV0O5H3lkjm8Xx51bDDN2KdgYZvVPGG36BQ77/GlP5ktCy9ke3olmUlMdU2yZy/mFGLLUEqu/Qid19drhm1Tdv86XCP5wAfIfvAD95/q0qoQk8iKnlFzIANH9Q2i+BQk5b+EV7LqxroJoAby8tzvvMfX5jOikdByEH8wqEjOrxJmzypL5wkmEM8TQmNgtnI3N5ndh+Tet07ysOuWTbbXpDGRNL9ln6fRVG0MfElE0vfWsVvf6SUmBV3KynaID0t8hu9NWJkWQUJu0WJJ+6GS0tKy0dNWFtCa9iMfmX2xfVJvu9JGepy95S/S/Es95aOygDNQM54mRtPyCN6/jRNlf+HRiE3woX9oEgCIGhSsWw271GxaLyk5WDVUjc8f0skP4+OFRVPWppl920y4x5ybk1QI/cfXjjRaCw4V6kg4AMB9fWYlNeex1hyMceWqbLGTsumQ/7OrAYXxtTneUo5H9JAcULW85pcybLYgAAfPweVhtUyGBdxQXWtwpC/+/35DhO4P/igIlOu6Kc2477BdlTU+0f1GH7fNG3FIvKyrl+vaFawROhACxEejWaI9tS1ILBDNm1lc8qVFoi5dSvL0pc+yRYJAe1fAP3QvrpoE/Aqa12AtaEYDHBoFB46AJxSbzi0my+N9+V9qEWACTU65F+c9Fjlh43hrekyKXc5EnUkxPLqoJsoJQd138utB86YhMTI8mGH1FoRfhGvhD3I4goDvhdk0r+DsQKeOJT7zjOvIi2G3Wx4ByMRPoFdh2GpkdRY4EopGU6GAaahzwt7oCpCWovyijhzZY1F3I4nPmekhMz9uLpyU1zCEBYXm0gUu5WCWPduIP6txlKGoxia1CNXrwGX5pjQir4yNR9zDORXJiW7RqWBrXA5Vyr6AOxhMnzkjqeAYwIu5SQrE1xEu9HnmF6T5GHOgvryixaM6+FE6OwMOs5WfOrfANQAfk8F0eh3THoOrvi21w2+hgjQHxOozRniq7dGT71wSdCsFJxbFatGomDpt2cCwud0lgBJiegiOwcK4yFkRyIXhQsYaymx0k9M9CfguYQ1N4r/8eeDAttTtu3ktFoME3dnBIfVhyMGX46mrlxrRKMTkqA5VhoCVSKAOTdTXm0hZyDslRocEAn+xXRpZkq1QUKpWwYbKTH6PbN63abNkAYXqTIGo+7BZKi1MqkBSTdQo+pSvQ6xrAr4wAAgtzSQ9ZuHdE3INc5qaxeaRGMJ7wZdQt7yhNi2FoAC4odDsDDmz1wVEJBFxwq2FSMK/g9WOk7bbjh+eOyePXv6Ku6i5MBRIZbOipNXTVl+OWAHdBwQPlVe6S8syXbfxbIVwVNh+WsO6L78sv/zMU33mkLnf73z3j26Yv97uwDVMHpYvSWTZyh1rVHCH1SHJZFLVeyucbxMV38jeLeVOT2hrL/LlhAfEKvkyK9euZMgHAlfRt2CCtsu+/SJddqqsdQ9csneOwkR4i0eU02z7NWejwwice5bd16Tfey+OlUI/QNSUsLte4/3CThJCOO+oBMRexRtppO4aoyHcQK9icQqBEgh0SOflKUR5D+52nMmT18xTu8wPzpgjG+SR9qAnNsk1Hh3/2IDnhs3h2SclNoSagpAKCqDCGfaYW3fNEwcFmkMkePe22Y/Ftrn9DITXIZwRc/S4nEcHwRAyyVi0RRrEBhuqu79sWC8irW1NeThkxQ+Yto4Tu8h6MskpuxksWhzh12kC1BFO0lWhMrsQhq6nM58BZI/ooThABEq7VQ/dwW7XbuGNaSmSFkejQq37RUoJCELV7OCCDz04OPCWOFp1W4tQO4VZ0UJMybp53Vk3RYgSmcVqdVqD4vHL0cb5tnWurpjXjXnSzvTjLYwZ5kiMpY0PoQ21DYGSaDFrruVRpV3Z/4ItA8GI0uqpAkRHxzSnppenYkkLDeIrBrnQtygAEgdE1t2AkefpnqkC9sQgQXxquNfMWmuOmcCqosemrM7nC5TBdjgzMW+2VpmSrU60i4BV3urs9A1uE8hIRX6VeJfciDVA0Vp2Am0wedZ+g/yTrP2aMtdPyTNiGPSKq+BGVrewXnybySsI2v1IxfBgg61+ISpqvIwvW6UxMhxZGQrmpfpuCcOR9otDptpWvLxCQpo9ViO9u8oByfkfHkmLe0QnQGVbCEeygKnSeNShoAIw7o48+/E3zfb1bJbqKRGNUJSdWVzIjE3KE4wh9bdmRo4XU7KCJq2PLP1MbGhspAiajtmzB2GZWGG8B1oE0bA2m5wyd82tY6ZpvTwC+XurTal8yT07hXg4it2JX9oka/5DzxGrr8IQlQm3gmywiNDU9OLCqCpSWhdda43qh2etwcAdFLpQxsGuW7cTJiBsP+PAh7+5+qtWtd3CAst7wzDiM8tyPrLV5avpPux/eAu/ADwQdtxbVqTzMszsApF+wQrOfImOoqz7M3FpPuR/lNi77bDUVpTFx5J0SwaQOfvUbtPFtS+7wgb6KdtcKPxTF2RFpbKo0GaoSiNpX3z05++DA1a1rDnjhYt3xuyIPH3myuXswSc8gWJFEP4S38IzFmxJ1L+oqPOrNigXCY389EpFrS+PMW6UQkEZO7UF0qJ7S+71pu70XX5fGhe4gCn67k/MP60jKmG8uTnH38rs2m3RRDoTs4srzp0TzffsS9myap/qe0wXMEgRDPiMyTlcX7pMKjF4TEZSunY5HfTF8onGaLS8pLigxOfOCvjmUCymS2k0i6jk6VNm5y4n1dL0SnyZqfNSu/yG6MzkhFpHQCSBSY83waaIPMLkgPwUJoKPR5iq1OQ1fjo7nts8EK2iXixrXoV3fiT29ttcymgDeIhHivjpRSBLDbfv35AQ9fHuOySbOtsTZfCX4R5gLD3zxERFwziHIHGdnV+MulKx+VSoo55bmTwwMZmxUUa3zy0uC80D1VT7S0v9fb15o6JLAPRsPc8ubVzPTKQYklJXgvJzgdpUV4dqpjMZ+00HMYs/aTsiaYBoTXRNYvwsX7HAjmtgKLAVOMgMcoixI7wI/kEg3dbNwfz8eFe3c8u3+vtFALAQaBX+QeGSkHs6du+uA+XxKwG76oGQDH+7wi4fKtpt5xrT2Ew9gS69LmN6o/1c+sJetqtiWNUXn5dHkRJXJkXrQHzRvZJROQF2wxuMsmozSk67K3Zn/urybEIXR8EcfpeNSSbESJjhY2bTLuMql2sP64oazHPP9/7rv+Wu8WuPm1ZnndnswHxpZ0lOiXw1lF3iWxReWYdHevSs+frLkkEmlV6eT6vfi+QwggH3kH+IQmI1daiE2KFICX7ValJ2e9HJhFXV5sGgqa+XV6gjcNnPusd8uX1v2Gxskp08oUBBKFAu5+Oqu4Wck/OkOIYSVsBhZBoDNDebQcoA6OqQIIolxeI8Q6FcpgNnVJr8FdENvtmjr6fZKxz65wcFrDvOSZ60F14ZA3oQkoCrow4b23hUfyHt+Fdw4cZ1kTN1yyqrPF5vkDchV8ZrTyXlEp4w6Ef1NVSBKMojSSQEP6iF9h14KxEHmgkiNSafvW4w6pk0NoyepR47vCU94AlChnFudSCh64GprpRkekoVKI4m++lJSfb8Ifu6HFstt7giDB+pSLPgE6lW1kXZ9iZkNtU7DhttwYTTHGvo0Df0a6D2/j2SAzXmLeQBogzXrkv+EEffEqDPXd3wAzcvN+3kRgSExlKlxbvk8MTjzggk3jLMV7VDXRAbGK6OPTzBpVRxQq6Qjf5++RAYLD2ZmJ7MaK9HBSHa6kjTqWl6/RCH1hJhgW+6SMwO4cvrj2iNHOi5Y45acLreY67OmydKOKJAXmV2Ar637r2ZnJjzNdfWf6leHuTlLRw9F6nKK9E9fmmMzs6AjQcE7t3r9F7/T/9R9H9JwIzGZU/2p6wIEf/pmnQEkh1zsTejaCnJzmB3a6xfxDWaKLwKo1HhpPkZUagtNq7EL+8yvbl/pSCeMGUWSxcWomGYTwtxAvtdxZIWiT4wpoHhkxJ5RERsZia156BorvJqz9RUWkUaE8lCazrmyUFJRtCU71bLpfiCSCNTDLRrEzxCekXRGbNh2fiHftndsnUVd3GUPWjFiJnnEV/k+9SbXINGIls4hMGvm29OnOwurg6usCITnT+7GIovL0zEIxvquZUh+/uDqaExuQZgVJXqHowcFOgvLPTf6/V2i9Km5LvbTJ5YbNkHaHLCWSoDEJFM/+GRVSHmLhpvwkSthW1/mugmcbpFk7DGuP+sHIY4ZduSzYEB+FkTHxeUFcpBIjJMeYWw1eAzxYLqzwDLROzsQIcAnVVCid6y120BqxtRQ9NW/fa+atY/syprIeNuMLtfWP6Tb5A256XPmfKDxmsxSTbLbEa3PZLn0Iw53/sLIYDVj3zc/8gUZrjKVk7UKTKHWVHs4nIR9UPeIGBF7aov8avZodStLTcVPtNQLOiryEoXALbPupe88sFa/2oO/GI7gcxFhFeKfNncLzRl3pl2TtzikcUiH/I2XKcrjVqE2zABr5OO0gf+9XoEECte4WTRbKbo2h2yoJD4lU02M0eOPyTjn/+k5S+245AKpeh0QB3FsWIjbIujHyA8zEde1s959/d2pV1srdmfO7605yl0u/FXVoZq513BFQ9rInEGrmYbN+XWE4+ndQfGc3z+AsALFE8UtpaAdkvsbnvm0GFT0a7xEVftbd/CQihnhFTgZ7ACmwR6dL9vl6uxIfvTVwUf7d8vs4CAAiV2rVTv7RjeDlvuQSCqgjJ/MChqgY6XihT6MonHfKI3AdPIEwAX2tEu8FqcAIu3wJVnTqa2bZEbQAxCrLMU5DkbJ7DJj9XxnHwPKhq5ihyaijof+TdvkYqvsO/7wszcaFwxMTAO5UZ0EML3E0CGvWT7BEKYLens1LR3QSrodXuK0omqKuEPXwHw0ZtOneJOlimDjYC/Qjgx778/clk+Gm3Mkwcer4ady2v8/uTSeyelE/GVvJGJ9bvDyaui+nw+JhYGYkOie1kyFC5a9OWIr1PXGpBRhmAgb/8mblurxnJy3d5IjrwyNHH5xPxjT0myyZEkE6UotUK0O3fokNnWVp7I+jfQP3xQZA+8w/NhyAei4nBYATpDXlQHjaEnYNFYIDbqCFGv21eTHDCDJYM6O2TIUSeG/fZ2+ZHRCSh/mBiVKAL8H4jhKwYcNAdgKwNfHPEEjZ7tW3xvIuPxRTiECKm7PLvvK2NZuwuHmyXYyaQ7nBPrR3sR1M9cvOAMYvzlf2U1XXbXLskBQAxslUEkvzTzxGgaTXTygjzajD9VVtCQFjZeu5SmJB1socrnIcTi2A/MstVgZVXi9FStK/vd53gy+q3vlf8fG01uLdfhLzztHR3Mn73N9SvfE6x8PWu+KLIgMnYk6GybAYcfe0xKAjUQqGUb3wKnshSGaX4UD4IbeVzxUym2Q2AZg2PKE2A05VK9CabH1gBZcAmgJbsTnQg8cGQ8PtY9PD6a1m234CqfC5aJ2csvcO2IzWmj0Gr/9qb5SqHjExEOoGdpGfruZWjK2o2YJ97J8+GGmlk1be35shvzn3xHnuxtkZgF7oG+BSJCtjXKuBtng/gL40QQ9QTI809rRMi5rMy1Z6c8unZt6MGS+jbIEr4uZhRnE+JHLl7YK9eMxMJJ/HwkFiKkAlxL3JHMi0uTda0JHGau8eCqwYuru5ThBLKgEVQGsT/7a0fNeiveG5tFUPFP4CF0+qzZvcP0WmRy164QQymphJNmPRjRYlH6L5w/ekxe2blTJNaX4etyS/XpLNpGvMgwHkixrkYewQ26rbo6166JEFJCCI4ym5E8//QncruO7RA7nPPrvD7RTjq9lhanJ5IJjQiBZeGiEjzhH61vPU2J++Ly6TbCyBjFoKtC12+Y97rTRzY73Rxc0t7huMdcE6vSLo+MSVargr/b9hrnS4/+WwMH/nbWfNkyvLPCDM+afJ8Ad4jow/4DNjqAEA4lqziBoEZiechETmutCXhCOsH94JMm0mKy1ghV3codH6+sGCTVrR7Zne+QnV7BLTqWsE8vkA2lyuB6zKwsG5eodjPERhSraJIPVKwuTQEUbzRmhJJIKkHYYL4TVgs9p5OZ6TAqoJOT/8tb5jNWwAiHWw1t32EJgPXlAla3MyZHj/ibb/M188LzotA248BhIn3hpbEltNyY1Z2oJXqboAQ+6pZoY1Wdx8M25MZ8ZrNBXceHJESCQgMGVE9LMlstubDCLivHmFa/dbv8It317beXx0Q15NRXiX3kFzuemFee44otXH5H8ICojtPDjx9xTb8rkDYYyAR9mXG7GpwQgz93MZfDm7BinYFQKOPyeOp2CfwuLBxVtcw1jsn7TNjmyk4Y67YX/9D+0BwQuKQ0Yb4rmNyse3ts8Z3XqhoDBWyDACd7Yq0vb3IUHOoXdZAXmZvA/zXJXBcLWaNWp32fvazgp2Qgoy78q7SLmrhFbK7Z3/VPnTH19upvVsy+QdPQkVn1E5bMxe+z/as8rKiRWSsl6/zPvCy3r/1X8zUWaiOJuMvPB86cyZ/q55IjLflPWuthCJFe73bwkhhn5iqwBxTwBcrLIwp24x25RN4+BtrSu2wHI8pnLgyZMBMS5SXZjYYWV1mFIZaj9sGH/dEcMBedzF2tlxT0SkBU/bSx9lL6l4jph1G/DYhsto8Ef4KKCJhBDRhyIna5ToyVmEc4N/D4Pp5UnrtYWBCvmZBUfPrjy0YaaX7rNL61YHpuyPWOMQFy6Hbo+oAsP55Jyqno0MO2gn3p0Z+H5sDHyOSH5CVgqYzeDbrJc99ha+FwYlK0cRnyFfeppzLQk2zbnm8GBLZM3RobG850/N52r8KE2o3GS3+hC6P4lwHsBCYgECf2vueOYe90KHclBsY68ITgI/b3K6hYzsTiERv8W/K4VuIZP8edEjBr9fvSyw9sZuDL8jq38eVXsUehXRIDXm+0HRx0yOyjI9W9Lp0zlJ/fuSUQsO4NXhMzDkBFEPAOyAju0RBddZPflZefSlqEXZJX+lxboE7ShfnS0HDw+Kkf/EDe4sAPVH1fr1wDp4rp9biDDFigs0KUJ/nDPxFF/dmXc1gSrUMBWDQADThPB3bgAOVSbFpKeH451ndTAjQVDf4Tf3bv8GNmeVb6ArvMe3zu6mopDyEKD4dXJGKuqI2wpFOjt6bTtscQ6K+vS/jsWGJmfPGNY3NPPuvzstsgNDOTmHdNxkRLlNf42nbk5nvlQ0hA/azYWXX/GBgBMtroqgDHBbvjGbAPIjoCAFWDhP+J4VSiIsRd+LSibVQfK3k8xM4sMZBIz9e5SXzl6FFzBPOLvMQlKzAlNMeZy3ZSHNlCGFD8B/UZSAZHmYwHrZtaHh9Z5ra2Q15r3+BH27rq6uVZPtvhya58vsExuU0kmjbn6voYj8/krM4KpHHxsUlY3i4K2p0ZZ3HdgV3yRnIpubKw4LWn3yCQfLHjqULhBTQ5eeJPew6/KI6KGX9g7neZ3fvCZeLTeJ/fZ4buGdATArB9szkbu34FNSuT52EX57toLeAVulgHVWAXLahDasDoYFGIqSy6EFzYvrrloehLBhfY3IMSQ8Ul+PNnbQSBaAItooDb7RFxosB64Phj7hhzDs+ckTdKSlLF4RQTO7XJrl+TMmwtkw4S8ARoC4QQunLF/E6nyQNXSVeWEQ9aOWsFn1/A4vnj8krFVILliIcPOxPBqRf7+NfZHLAxtCMQX3sYsW3GylS8xYefmOy+KpCz9Xd2zv74ZMFXX3SsJV/Ky3MxPgklk7v2XuZQOy6ROlZYYXSGHsgTxmdwlRln47qnW87jQjkoS+ADRdU4YEGxC453dWGBTcv2fC9HXK/uZwijSK8NwUV8yZnLhJdCGro8MgbhsJOVLv3Qeci3bzvDd8dOmuefcvwoFiWSifowb58wmzaIOOnkPbxE5pKpAgHwgdhm406noO0COW45sR3ZKBN3S71W5Tn9/sgWKcO9W9KyNChEwd64bFQDbWEHsA7pFPl27tbRN9J7djtTAWl6XqHA9/rlLary3GE7tceKD7zSYUbeJQT7s26LRx0t80yMCMMpJ/Kpq8JYk4hg4AombZcvLF7txpL3I/pkDuwKmA0WpNPKhORy8pyoAVqRWR0Sj1Na3f2TzQMmx7PlX3uGESJ5UggGw5oKIJYJW8kkcBBqLDGvjsmvz1pAi71gNlzzQXnEnNgGNrm4I1gaCuaa7KKzuUXEb7AL4/KzDF9UWvg1YG/5BvKwEWsMDmsTWWroG/Kpy54b+c2NxmehIipLnKFVmqN74hqRF0Px1RKXKSsTXBeI+DtfqM7TvVuDOdH7D1ZW7ua/J8nQ3Hzofbk0iD8qKMj4UVhEPJrrivqCZ67YZzb0YM3yz90tW1dz2pgjaDk0CYSHt7x845xYLvZouPGti+v352v3C+Aaut10B4ge5POlEkuuCP4uHSGV7L/jDL6h2PfvX/EwSxLNdGfp5Emz54C3uEwMD6EtcIjqFuzyOr+Ztr1A/RAS/EMjUXZ2XGIWbW9vuq8l4v8fe28CJOdx3Xlm3XdVV1Xf94HuRjfugyQIEDzAmxRFUbIsWbZle8ez9s54HTOenYmNidjdmdiJ2I117EZ4J7yyJ0ZjyR5LtmxaBymSIkXxBkjcN9CNRt/o++6uqq57f+9lgbpILihRG5oYvkA0vq++78svv8x3/N/LzJeb81HGKfdJQzSRWRcVCcqG0IOM45eKidphzsaGix3tN5MJnzaj2rP8Dhrne+myrZwY+f28Htg/dIJymdmv4VEJnFmsMD93+e+v9H+iU25bnTJTl83+w64ONQ+u+036mgm2yqWObYTBZr49yiEbx8EEohA/DGELmXRqLZcYFww02lOOJJwnQqel0esw3vsRrG1Zi3hYd1I2ylmFrZmCuiT1GdDHBO19IAljqaAiQ26VMfLZYtDxvr6ul2r173v+oa9oZx6EQDvpG8uOBYHCgdbWuf/0bO2//K3Kwgym+JfLsoYc1b22tGPHFQt3Z5YN7aC8KSV8AFGv7qLxiLiYsiaq/btrcvxYm2GXHLCS9cosI8mF/+qJhm3RRkAKaBwRFTSe/v35/1gddqvlSECdGBQ0eWN2IhcNlzzNwpY+PGWgFrxGXZ/awvru438/zvHuxxq8d7TJzBu7OvLED2QnKLtJDaikXOoQRhLliEdk1+XLqadE9KoDMA2Vc54dncVNZFwEJDQz88yX04fvEUQ7caPc0lCyUPLkSdO/ulpd65IRco2Ig66275QT3x27k9XtDvSpTltKn7gYD+VHleeuXxPg51JRITaPLQS42HkOE8OFC1dWLQhO1Kb7962YTjWHCLbPR1gFPw168Xsy9mJnFqHWeHbpzJhvaJpLoSYWqeWWZkQ7TV4tXRsoWx2BUcT0ohesdcTOMQxi9aGEskdnt/3unTySv3h8x5E2s6vZ6/Fz6nQ5CJO2V0m9n/6/p4jWo2KcGRWjcOTyhaKdPLn3NifzhRBgCC1UX13YmC/k56QOQ1cLdJ/9Or9xh8LGjh8+/Lhr58EAsy+AnlBTkxhR6wzQL0ujslrKWqBvfst8/vMVZMnIBN8LaoQoFuRKw1AmRONQAhPSIODd6KjMnLdVgkEeeKBSOFgE0PD2GbntyEFBnzhpFrbyOgq3ioCrmIkN9QQaesLJltLo5bT/4F5+97OFcLRFJuJDpCJcH8YVcHfYbnJVOZ3lUg1XdiSmXdFIbgGTRGXy2NfP/xp8JV/LTp3xeNqO1y3Ml8ORXFBzcmyJe+o7GHJVJ4n7NjM7fsVtVq9zOHNpqb5xVroQAAt3ka18fcO8/QOOJcyWy1rN39Mj396zLLvJQceOyReBuaG2PfFAcaNHF174A05HPrvAVBBVvdwMGrBuOQxJYmJEqxKPKhaxLKSkg2hGGtnOwuNFQCJ6KqgjSHgOYGXbyxzD3pGdHfk1kdm1NbFEzEHlL7ifjvaw4bz0V5qYGnV/+zhnhnlKr7wpCRshUDhd6XYL/wTEznoonGpY4i3LKjsbYRmPIoqPhwDhLLU0y0pcqLpF9lVs2q84qr4+dJB9z6dlMTfU3CTtYlVAsRTwlcL9wkC+6xv0EULR2yN3gf753mB9iOPEwjofDj/ce69coqmpg4WwuUwpP7ne9dAWfg/7s+W5bH//pm0HBvG4U5WTDI7dd4/stwaNqbcGxrqu3IW8MMz12iW5dN8OeYRADL4rxOQjfEO+EWI+GOMQuFgQ+8GCz26sms88LKeoNHjY8irthnT4yC6ZlEt4rZFIiTlXHFfPFwGdqBqIWCMagHUlbJAD0Y8sQ8DDhBgufvRgZQ4kC2MQMRofL5JLOHus1OJmiPbjMy2ncBqvFsG33jK7LCB3tr+4f/8uKcF6p/jtHm+pgTFKpK/J+HPrpJnluK49WE6nT56ojLBJsu+P6cO0gC9XwZ/EAvCB4TprHWyzR2x8oq0DLhn43igF9zy1LX5Pu+ncIU4SNKSsH1OEPzdBWXcq17GPa+2seayhEsdHk8A/qoEkmNLZ7+/q2uSNEMOt37psdsuhmS68u+RUVvCMKkTTomWb3f+lzuxVfbL1oZbNtl4XOwiPjfDUlWevt0fMeTk0f12s5CuTEwXHF3UEgOOXp81frphPKIKYXyzceWTW9NTJTS6X0+cGhG9TnXZ2SWL898sF014nwnv6WK5lYYhTZiwT5LLTVpGd44T29LZ3/6julDQb/3nNfLZdf4ahS6We3zsiJ1eOtR3qMf06OswpBmx1pdM5yOGf/fEiyQsTibJjI8tpoqrEeDg2F2IqI8JoNRWCg5iPXS9cvSjy/PZ1cyFj4mo9qwm8FsTTgyb07y/tH/iGhmpUuGSBBI3vJn0umrCHBWxbKibSUTSxQbLH2gzSzb7S5tyaZc6ZOcMyDvQYNMVYiw6EankyZY5mU86SqyjoA41ysKNL1xRjIWzcKJttIQPW0jiXMsPTAbYLIKBgdTuWDJ048KY8NnwNFWYDUrXVpnvB7DJGDYVcvBUaNeYfjPmjjNwr5aA90XcocWhzE6HYrvy9npEVg6rX5cqPEtdvM2a/aGKTLpoDOl3Chr3ob/aR1f6XRvhgsrwKEGkOywYzEFILdGn2mntVty/cHEn+6XJQu9XasFwCJ2DkvJhMKJmM3btHTaQYMkEMzz0nOa8gh4wX2A1I5k4ZneckP38wIXrpm77l6Ix410/ulCcSLpPdMEj/oj6PNviYaIHtOi8grm2BhkKsHtFjtANIRzSLjliKK/IzkSrLW36SoY/zR5Fu2UoV52HwcmHrXpXRlGP+Rr6mUYQgtK/NnB/s7hbk5W2p9+7pl1QSjH1A6TUzOXL2a/CA2f1AdXYxBYaAgJQ7d5merS4XSSRgjvV0/QPbTULlRoLwVS4M13pKb/XdfX8+tSL4LxYqIF3WMUDkL5wufPpz7AAsWmJ9I4e7xaIUjltDTn89W3NUC2DBjVlOffu5yswZoBsAa0k+yPw3v8FoiWzxVAlAbpaqgrmgihTbpOZnMx4dWUitFryOPDraahKUP4AJJA21drrIgejIpjPsO0g7eHMrM7nHPyVFMCDjdRdtVbkfsWHiho0KEW9iCjtJGrgte2nIt6svdrvYytLO9iSjZC6Xy7plfOr6mrcF1Wfu+XQ20RQwyZBMRWL+2OXx3Xd4o70NHLscxekXJ+2YIaME6COqygx7LgE0KcMiuXy+wOk+3RnZFfEH8/nzo4JrIT6fdrIxQnQpwBR1gEKDDh3S8UuF1JRD4RZDAENB9nydnfgETGzq9HsUMcxcXibsikq0yOCtk+Z3vlAZbAEEA1WDyoAAR1qSFAs2pj49YzraxVWAZHEO8Pc++esPuvwttV3xdMVy8r55QIEqzs5uU8Xs0irHpBrHpVXa14G/BDtl8r54aVXdDPgEN6OQNydeQlWb7dvKjGBYz5kpXhwE0mLig9U+piPKWxoU7CQ6kk1D5/+V2AVXuVjfFpIlRFZDexPMsBx+XZRzJ1s/ZjKUD+E3duwIRWvyF0+J6iWaQMNawxQubrhD/vKK8LPT6bkxUgSC2E4GE2M4aHaIjvv+VyYf+FymMmaUSFCChc527AhnEwpHnJmMLMhJrUr/0cX0i31RKOr0JMLOni6XzK0xPeMz9JpyMa8rMRGuOS5YhK+cnpLq3baPM9m0mc0/LQuB5FD4zrB0Px2UXs4wWmK/mz5FpGwfcZWOA8qXlDcojdtsXnJwV/bGQvjAHim6VPS0NcpgigXxTc2yrkAn+aVOnPeH3E5NvMOraQFs9LuQiD7aGVDdouNUfA1jfhDd+8LNBOhhZzlWz9vEfIwdTzfVFZBQO2wlSfl1oSCXaBwUV1h8N7O9W7767IjZrd7fxqLI8o52uUQ782kMyYst1K8bHa3wLWJLDW37wPPY1903QTBfTd3syBj6hwNWfFkQTOsRlahvUJemTgqnQAgJov0B5ZZtuJ/TJXW9zp8zjR7ZHg3yO0QQ8KlIBccp1WNo0bbwCy+YJ56Qp8ZG5c7WRlPb6HIxnku182lk2fYXjck9MNiR++U2XlQqlYtroqmqA2Y1Xfrud+X3X/9i1pEMBi6mbWyonM075OeP6VZbYEurOSF6QnLr0+D0vp05S0fAG83dihPj4cLRy0394us6Otp8fbtkm+rpJXmM/CeLo5NPD3PYvK8GPvNZmZoz91fLKsGkQi9yC0V6G32620ostekPOl35G5bx0NWMyo8pC9ULu1UmiWFULlM8Gl5+k0kNlGxhajDoCCZYmMvKUTGR6eUcERzLt0QbfgJbIGCi7ODJNNqyMnTmdZS2dKaM4wK/b6RdjkIO2xpWwM57r+JoyROmvVlCbPX1xcUJ0X7MZFtbrigrJLFvyaQVTZzRm/mjqFVmUfaTLDcqv6auTITuuz3Gkkdod1eEWYYIQ0bYWBg9l/NrmqiHjiwm2cUxTtxBqj/M/INmm5hQbmSGxbwCj3VGtEqmf8lMKQYIukyICKDcIt4pImThkdT1l5iw7vzzab/SSnxpkfWgVoDJFJIeNg69Fms3nhrJhqLGxpPPnr2q66/0WXaFUWaR0H6XMsk39JMP/LjTQlNEVSVirCXcg9qK9cmNW7dEukfH/uVbHLpL2SZSJTKHfEOZlftOnkq9LbwRirHqo4iehDCwEZdpLX44d4ueHtJnKQGdduKV1J7cgNsyayLOqxaVaaijdqm86CeI62F4T7+if6dEMGt31levy+3bxzeuj1XygvCWDybbXFiSpqoKAoSHiYGSxiWudRCE8T7EV9SgeNUMYc2x18G48nep5NvCyuxJ067Ao6HZbO2TYXHo7FkggbVH5A3Qn96n9B/5mUriAU/rLw9syqZ5aueiAwAAQABJREFUxSU5eWvWFNilXJdW/sjt/1Uf0hud6vw/pc1Qpb6o1QD85arlKNvvP1tL2dJu9dlko9etm8IUcoKaGD5auiH2Az5jaLImLl6QoIydu+KHFBABmgBfBO2t0QaDBAMdzF2DnA4Pjos+AQjYuUtkyCkp4BDdrZ7uLlmFAI2MCsZfW8uMi4J87rvlz/xWyGaMcAbIDyi3QA3G1b2U8zV5U8OznLINKLbDrulnhdDwyyOd//h+mccg3mDP3YXxDKlzCQg1iROS1TrgEs5NlxiTsYM8RLVBk1aKAZ1Mk0vp1rqnT5XIvMdQkn01uBBtbx+ZnynhZvjb6zxedREigVBsqWpZ6sNcK5DZ8qy8ifvxNAS8qo0AoTILy24DUtXXILHQZDO3OZO1EmucmyufOClPeVzUOUBCW6p9W5MAQyJGOhUPZzXUxmqbBJfQpG19S0uTUjSqh69DtVm8BSInsGcdJH4BL/Yw8Rp5m8usLBdR0zGVd+AjIzdVCXlRMV9ihIGqnjnNmWBE0Co+EgS25oBLEB+Cw8CH2MJfe93svN0h8wt1esb3r5q9uikTp7u3CQIGPUM4usARGcPREl55yzx4j5QDAUz/4iXz3z0hx2gewmR2kKG5LVWVSITqw3ZkZ+WFd6LBQl4Vj++JR6w5LashdTgdr7yQu/dhAQa0D65XpEkYstu79swzZttuT4dD+uIbX/thBm3mhVI3xgD5PVy1ur5a7PtCDRsNckoiDuNztD++nUPnBfGchp8f7Ogb59Tx5CdNe3udQ+sNfEhnool5fvdem1iZySZqnLZNaHwiqQzaQPF4fvuu8sSotM+Wnhz8wD2WGVhPf+5KZSyRPqojhSO9aJ2DuTkO7W30AgWyyguany3RaEwEtX1BjzNseOqUXPrVz5Wc2/qkdHUOUOu4WxZg0X00smNMsAh8jixzi3WJrStkoRuPwAzXzotXdvtB1/JiGcfATonE6yBIbAMNDOPwdfyznIafTyds3yZ1SK/kvawt1GdWTlyrIq0104HsZ9SQZz9iZia5zffOycXZwsqyyDP3IgTkmFm4IVYLrkPKBi5JvyDBDEVixy0/1Dxk7n4sZHEFSiK/vnn1lHB+S1OpSF64+pB3SZAS41EUMqU25/g7EmqhJeV3shd4zJEDRgf5zExEWtWvGpEP4Wq5VJlsQx/ROHwydPSoyL5NJYLTAnx8F5vi/slTqpS4GS3BUMP/eV6e+nf3SEs+/5xce+wTToaSbLXxG7GgDqezzy38QGwCZWITVHADhVjR692qLir5JBU4kdCF0mhwiLd8/Vvms58QkYR4Y11DyVclirS5JT10XVA+hKmm4WWADgkHbXT6i+uZ8esiBVYXoZuhjdVixJnlNvx2iJnb2lRy/DHdSgskqyoRQPqRHW4euE3YFYJ1aeH1eRGlyOKC68g94eZGuVDdZuamDAbV9jrJ0cPhZLO2OpyB4lJD+tY5U+0XBWWD4In9ne4tbWIF6L4Z0gSHeZ2emdeumm1J0wCiJJJChkCPyYuUSx6jpknZRf3v5UwmMg0tC/NA+YmZ4eOrvb/DzolgDNN7Z7xUWp4QuZRNlobl/x8SNRPFR8UVnagRMxcWzY5pRoAFkLAshCpjfy00hK1gelX55sGyaJvG3bV5n9TPUeWNTi/G1kRhon/YDuGUulucWrKFw4kNN5dE1u2pEiYOatORJHZpTHZxOndW7t/YWJ9OlTalhXt3hzYXU3C+Sy0U7cZUYUQGwg9EUix7l9YlRIh0MzIPpVzyvQpHxUWkAdRhlEu/zEQ9O/Gl9RMOTEsg2IklGh6hzukX3wpWeeULoQcfN8B38ibNqM9fLKFtgD0QU6ChJjVipZSks9vB+I/8Zl5VoGk7gtagWcbn5PfEmE6ohq2d9XIejJiyp+YTd3DoOnMSPTX8jROdh8T+SjSotdWnTGicsvK1ext+LuAq/923K76N3HbLBHfRoRBGiozWLgICunyD9MdIQVBfdP3muM1Pl8p1/Pk6RX2HyOLcn3TWVZMSijvhCrSwNBxCob2vWlDPf/wPzaYSJvdjAmhJaC8b9JQkLjCt0PUDAlUUzj/LdXhoWO2k7kzgJCpz4E5JiJTXJmerg9uYMTVE4aXX38I8HbskL6L5kKlbIcwAXC/AVys8umaOqTlozMms4Pj7t9KtFP4z3AOjoUCU/2TONDqEnvolIcwpWvEeBnJUKOq8ppr9UbRyqCXUirKMhKvswc9QbQUXt/5cbW3MJ91FuoKtjtTKwmZdq2gk4ELDvl5TECl65v+ZfOI/7DbdfVJqnhX9ovPmnhfAXnt3L+mzYzYqWyg46+q6yxf4PRbbwB/L5coexYxwvwCN8QkuzZ0cT9RNvfhMbmeffKPXacavpICbUF9/1rMVPSOUujCMuA8cc9STp8mYBx50etwlO48rODETB3zh0rW3c8mdy5x4K79nF4ckVxTIQqYHiBGP1EaZCVlgOwigCYq1EIRKscvQ+rqUjHYGvuKGNSm4waJgDi3SJcPEtZfy9/5P7e6dB6QIsuSdOmbOLHK4PpvZzBRnp+VnEB4fx6iRRU7LKUmDbletJHZuE7z28vNyXyaduTZx/Wou4RQTlN50dGz1mU3pLz5WllkzLraxwKmrVJBl8iq7+fVseTOrgEoq1rynxpHN5PNiBWvYVbNU6u0TzXrpgkzjnBwVzUQr8VEMuIG/IbAjjxcK8rGtXZ5t+10eV8l5TdQOUJsy8dkg1AoAlMpC6JcXXzQPPSwOIHR9yDz99Wx3jzyCGjzYY7a2VzwxMB9m1Zo6mpc5bH17BBfSIKHIJu+1CBIQ/0RdxTGgudig1noCk2MFb3AqX1LjQANvZspB48GQQqdOmmFAaLWje4ucLi1v2zZjd2GanynHcileATGt8Z5Hg57meDKAtmFRUPrZH5gHD8klpkk/9ilPVVY+nPSbhE3Fcdl4Ua6FoqajKfrkfXJcH2S4sM6Xc3Qpo9AQO/eFGqfk0sjo0smLIY1HkC1yZqbg9zqsQ8IUSnjJRvWw99//XuEVtUT/LFBu7w+l51Ojo1KAoGGn+b9ekeN//ajp2ReWOMWk3Hr2uzcKaz/M/oL3zqQ8CMPDuBytZF9EH3H7Iw/LJV88ZABNYhGlxep21R8oztj0GNSBB22wAyUOS8MA6hOJ6cX/p08hogzh/pbuPrXDkWJ1YP3SKzO2jy5ckFJxmCGKQiTx2ewH0tR4I+ri4ZKVKXz9uiCq5saCZFT0My1R9VW4ShiIKfxQoRBrCoV0fWYmk0es8pkC3wXhWuCTW5aOt0fdnjWc0p5+0YjRGlcunR3U27rY93m1kFIORNbhUl+pgBRD+C0EYa0ryMwlUJe1VawNI6zIiNq5a3IbzMn38hciYEJr8HU2wQaIGV6gqyEeoXHsF4DbaElQndVIJDas7Yk92J/kNp8jF1yb3tws/mOfPLVli/HVxbbnRMbGxkorS5WmAyteucxe2SXbfV1donZslIcX8UbGiiHkCGCEfNl+IXsQ3UQ7QHzXHbulk63/xu+XL5YzZ6QhTl8x/a0V/cZkKioJIl9PiST4g2mvq2hFnk+goayInTnLHt9FirJuOTETBVPyoo/pVloATkOgIFg7hO9dMG3tcgrXBXb3+EpYbfPmV4fv+vI9pkZNpDNrJtfFGLz4styHcdy+I9C3V47LGUrZs3iUw7klERSk26pcdz1AReN2xowOENYpfvsfKhoAbXm9YLKK9eLszdVZqQ/5nDCDsEW3FC2zDXsbKyOxbVM5JzsHMQSv0a+wJ3vylBkQoyFzvYbl/x8San1Sz2bhIgyBHjfkzZsnKmu6AswqrxZOs6LEFEXWSbXqbagI2Lu/r8uzT3C5cZQ9x45WT4pyIIBC+EawxY8QOhhCt6LurHZq+p0dokmf1aEXhgRHh5g+EHXIc6PXS/1bS2Bf6MRb7r4eWWzJPwjOZzoJ/yARgfXKrPXJgjncLe0TlCpIxJBPi8uhjNrxdm0DPf8l/oPrAQ6oVq47dVo4xDO6Vj8jwNxfJIlKqIJpLpwyl88xyz/U3y5fc2Oyvj5ntTQxmnVJViVEtz7CoFOosniP0zP6O39QHIBRdlWG0IcsqRUGyr8m50Fy6zcG7zsix8kAM2Tq9wTEwEPYg9Y9bnQrdOniua+eaa+WIkQdlX9YuFy9NaJTvq56/vfJmt5nCul8YVhs4Xf+Ps/0KQGamEutrR6+x5+7SO+kMAF16kSrOpoE2TDJ8LY11K1fXZpLKcP/fD4kUObHqQvjqL/0NJiDt1fUMqURTfjOs6ZHLz3z44/8xBks+4a2+JE5CeGNjaW4Yc++dKJOhURHZc32oGCPsrAke7pW1xRJ7wSdOXdT8OTsgwgzPnDzKzheyFUyN46pa4HnMPNBT3/019p0TaAiJ7HCiDbyavUJGMUqk4/+rR9YIo1rPWfaB76kr2e0Ht6cgC/BGercrt7caQM0pjb5Awt9n4vu9/n9fX4OheYvSAfV7GmuCvjW5qc8dtZqsehm/WtOWfazZEpiR1XVczg0LMLYvTv2a49KiaS4aOqvzCQuzTE5JuSVmpP6bHZglahweZmPMg725yEVtA7dxAJZlz+476BxpuVOsFc8XrDB6cnhQp0Ztx6RL+x+/u9SZNKzYe/W1hK6PhQRlOmKhmIkWiZsYGM8heLOHbJ2Atq3X5as2BIIuKPue3oqwI6DH/xAhBmyoZRoTI7hEZAWcuWSsk22INjIBuuxhTu2s0tSg0lgCyF2uOxKf/8YR9OTRVaXHTokv1Ia4Lg6WUnx19Qq2ZUaO7FcaqLxfogAoe5fufjOGzlwj6RyJCAaKW8s5WMkLgXJRdz5yVn2ZY4ERG2xeaM75J65ssJxKFB6401z92EOTbQpzPhhaW2TikGBGDuZZV1AcOaV3eEObC7bNfTUH5RM29goOAMgIAa7j0Vhs8AgDJF1csFBWDIesUkCfV7BnVZZ17V4Dt7nyKQruhvcRhoo2//lsAm7K+FeShCDx0YdynSC1Mnrrrg14jfM/UCDWyh/4oTZs9cOj0m/YWvtIBh20VXITo5XlqZQAnWOV2WkcgDSdbLfksVcu3ZpGbyYSIrc4JaEw4WBK3IXOH5zLZsaW5ydFHai5AfvltVKEEg3s16wI0lw0f0PuVZfOIYPINd4k2tvZcoK7BIKhVqdFcQNWO7oZixGbttIReLe+SvCw9/+tghBdXXZchesBS9ZtxwGADo0SU8KnvYE3Cwha9OddhCB7i7z20m5BD4bvbI5+tLUw09JHTqasmsBc9c+uYRhpEC7duvxx2WZDSFdwskQVuPOA6alU0oX6EGDzsyKw4pBTPrbexhllQ+ncbiIrYRoBEIMjBoR/4bAQzhIFprwiub+lfj2ZrlQLLFmEa8AlxXiK3iX9ZxhgzwbMjvF2EAwAN6RZSc+kNvWdCZnqIqUmrrXFZ0KnTslrK9dS6Yy98T42LjwM6N2zJB0lEu2tIlJKaq9nyg5KcW8hAZkqkWH9Oyf/UX5936t1E5fiFB4c5sFi66uDsgndAVyfAv0zjsSiLVSLI6Kw1w4L78jF0gif+2LQAWXrlYSCZLviq/gTsuQTIWmiewxfinfC/NDMC+vwEm2nhgwLj+ablJjS47EV19h1zHTqm0C6zrS6VZ1XBfHU2PgG0UMtDPaDLDNmDkEC4NCrH6jbXkX3QTRTtSTagCMIGZ4MrGQwTeIOtRoJneL8pFlnMPjx6WX/3rO/O/tFRRO5JXM3aw6s7vMDw+VKNDWAXcLZrNSyRALBSImtcqgJTv0L+/5mG6pBWjJZ5+VO3/7t1WERyvjUb6IxxVnzxAvl/o+w/yBKlNUE3npollelHnMD39eHmNhc4AZBXKbKU+ZxKTl2907ZJYvQlpQiOZFgxAgVIWCjQjFnHcerOyODfi+tCnrbSAiL3QrvQnBqAMsmtdpcpzyAt/NzT8oASEtz8w5dEpCYT2D/DZpmOCn+5/3axUEJ42Ct6Vs8wkClAQyVNxYEADfMqfRTvELy7JSI3BYeRXWFXWaVKmgOt1bnK+d4BJMeCJTwTHgHvGfUDL6t0mvErAQ4jMIEoh6M/Mvnbx4YhOdGeqQU9YCodYsGyerCky+OHGeLdrlEhO1aG+iMBAC9acZ85v6ewvT1/NiYuxXMPeSgu1LCSoiahvyxH8BhEpWE10Jm46czd+tC24dLE3f2HTzkRB8QDgqk3ZXK5SZnfyzq+bz9XKFXEioV1WKwhiLJZkmOi5XpCM6iRDpMZfomohoYiEs7Sv/9vX7fn1IThrqmTRSGa/B5jU2BFtcAqgh3Pi7Ooy7RY5r5zq6nOPn5cK/YVI5PSu/fjjqAbIrC6KxsQXfO1b87MNSTHWVGZwz7VoYyvXk+5eK8m5RI4sCdPi9olhVFSYbPK0N+d0apJu+LihcD3/S3aLaXLLQ+ftL5gjbqHaLjMGKxNfAY8vX5N2W59+vFsB6QWwSSRfLQoADOny4bJiNg5WcX5DziycY2TD1UldHZ2ds7trIsPyMubmDi0Te5eyDiFd03xzdcmid4WoIjILPQ+crZ3xQCR/VNQufES78B4W0IlyndaRO9ZO0p9q6j+qFt1oOLN2h9wZ0EB42Zd9waJhlTDc9VaoK10f0No6titCzD/fH8swtP5NKR9sTcjeKvrq6bg8oXtuKJXgDV60Ore9ho0avzCGERkcFthSLvv575bREzIT+VTaDN/F1wBHogep4Yn4VhQu+EcKQgAGJuCqKIo16XYLot4Di22/bBDmhzSEQFbki7FSNUNR9+/3hhD+TZvEje3u/Imr0N/4pQkHf9jrW18/+7WBXr+Dg1SVJEuDVXQ5rljd4owU0pChAjRMUp14Qwfvb75DVRBDfCjQBw0HNupyDpyx05gCUY2dxANok9gyCGx+UWwnn1NX7tnVxOH9yEP+Nb4K+9z0JdQsM1dqhmmitQAwRRnpSlTxivLSQY4Sa+mgziDNw5UqRrAbcFU86hwfyBJloAcgV9M6NZfO60t1FuqotN4e2D+ZvXFxemCnYMes9sfz8rGkMi3yFPMUbIxVniYqhhwF5NvzEODaTr6yFPn+uHI0WybdjxxkAxtgwuxTBzfhDodJfGyuF6piDwm2b3H+/1ErHJsWI8hRN9LfflR/39oi5fJeY8xaPS39xwOoseAEgC9EjwFCS+0HARxrWzj9kuZE36m9u3iyHpO18/VvKrIrDV4NomQHmRtAx6hvkshhXa6EZqadnMfEQIGB9vfjAfyr+azUzh+6S7kJrQ0xuXF8vk+YBYo2iZ0tbiN+tfCSSxAKHvi6wIB4tJve24qMPfPMKpzIDh70QNDRAWZ5E6IUX5vl9t2bcpnMtEKen/v3z5mHhBcH9OEiW1T2Un8uOXcszbAvh/9Dy+7bLsTfibQq7411hVgFyurq03NjiqulEJ5jVGxskVOTTITizock5NlKCiyD+YjiGh+STwsFy7Q6Zm1TBILmcOxr0eEQK8JpoatsXDLBgIQg8d2+REqiArRvHlFZa3XDaGEYoPHNhrrbeOXVDYP6r8+Z3SHanGgjG/h9fNH/6GcGXEBIE01rPh1fQCNZbdrmZd1uUXOyWcfGN08u2Eg7kamL8medF9v7w943HR6y6wgzb+kWs8rrkvZzLM3qDHzJ8Xe7sbiyDPqO6WdDg+Sz7DUxMSgUYWsQdZR7u3n1yetddwlFvvCHHsKLPV1m6SeU3UnInrQHBcovrpkM7AtCG9AHRrGMGY8MYIt1g2UuCH6xT//3v64Cko7IfGmy2upr3u4EotHq5vlYak0IgFjw3NeXvOCTVhqX5HdUIgT45pVZ2RIt5swyw2xeBHWlJGgaCS2Eb/EbG0yAaHO1hhcLKF/rK9trbZGE9KGEj6ItJaSvEAsLRQrvw1+o3IkQUeOm6XGJvNuTJts9O5cyrV8nkLCzECrHDcsvHdKstAKcdPCQ3w0LBmlAglAnERIkQg3cRqFDPPrmtVUSLSYDQxKjOyqKnH5BTGTECic3IoUNmXtn+4jmEBumx+kRULaKFowA7xZ3OoNfjyVne2NtsWJGXURtLd6OB3w187IubxWUzKkXLNqmxafPoo3Ls39JcTmde+OvF3u1ic9eXy0xprJH+N7OqkOXovQjnxCIV5nfz9gEKZRIaqECNJlAYQij4fhUdYTm0kVR+SK1pnaTi8ZNtSLTi1Lu3+eQ5Ia2CgB6+wuoWUSusxFJ968hunj4j77Wqr71DpqtwJ4S2RyIYQ2YTaUvXR82YoqRw2fSWKmnrtm+Yd9JmPl8B/bxO0aw8gRrQJqw8/kv+HxpZmcncGZeZaGCu2haxB+5d211Mb40r1iWSO3RNGEitZyGT785WtHRD3Ewvi1sFkVB5tmS+xgCpntKZRAXoaAjwkdcD/hCBddcldxDIRpdBqLnZyemvvcph2F+M7OlC71/++nlO+//wflNeYXSGYzou2hCefE5s0KN+M5EVzK1KSC7eIgF821VLW7yxp1f0JwSfoyd1RaTY5JPvXxwdDeCBkFYH2hbpUkvmWFyqqZm35qBj3GzkZbYbdPRmiEHPDPzJ+5FSaEtJiroxLjYRTf7WWxJeOaWC0PIj7KT3/tgfJFxsuUo51d62TY6lLVHZmE/L7oRRpaIqB/X1Xs+1dWk5GQ6isz7gA+UmJRoGE20H4s6qfyXoREuc0CFci7j1t1/sn2YtHj1A61nJomJ3KXdZ7+X4L/b9P1m6cq38iDMxpBf7dHIjEEYBZaV3buglGhAROKPHP49PqDKgpdzKn5lzs/V7GuROGOTGpA/GZGoQBCAj8mZZpKebCWr5l16Xux66x7TvN6564xLhNxuDsjP2dcGpkhq8vr5EPBne3dz0dbe4p+enkT/c7r01Ykt0ErZYGDDI7t1uRsnA62tn0a1VO6Tv8sOTVtI5HhsuxGs2F9ZK7XtRzmxMbMrF0sBpcct6ewosYug4kltVIQCpeH1OttrgEvkO2tsrCxFRUvg2CPDrUnGBy/mC7BDCcT5TRCx37JNPCNy+E6hVnpvfeFW4nQEZcKr9bmAu0K2VcyuvMzewkC6NBSHLqCOCiNBjT7j8nuK2Xa7NDVES5GajcA/RJBkWmGDyUJbkOIp0P/c5KbCpVyyGs7XaOTC2NC+PlPJFslGD1APKF2RVCngrQwFYOCA7Him0Op9Lr5bPnTUPPiinJKPj02IXpIVx3jyuyrAeg3h4F1TPGiqMOtPqDt8tj4DkwKYbLCJSX4W/NIuF0XwR7hmmFFpfLYerA4mabF633QDJEa2xH8t8Lewrv9gUWDVx9aO0NJ6l8S3i37tP1rNRAdx2iPbr7LDIREAkXWMNKki3rq0c3NdXCY4y4kDb4ZxDjiDQdfw7Z1r1My6+k2ZZgqdarPzSxFrLgUaX5ntwbKYjDs8f12y0qheLrkFFWndr/yGvq6464JIahFZXly7PJPrrb5ya5rSpWMjMrDboVDdPVSh97low5imvrnPJMHuDgQY7MXRhYfHiDOAeEgcjFFqfSZ1QpYhM/PbDldxj4NpwRPJ6Qy9939xXys5MlxWGVVxTO+o4v1TYt6+IY5wZlztnZ8ouF+Iiqumeu8SjUKwl3V2aKCF8ulpHFDW2NtIoPOMKBQoD190PtVX6DyEtlhItcimzmEo0eN0lMRl0Fhq+7+ZyHYwWoWd8JIi8Gtlc+dB94j8wVhjva3DPT1ih+9ydZu+uivQXC+b3D5qmFqcrFubG4vIavUarQB0EWGJBd1L1DCOYGxszx0bq798u1xh2xMO2X86UY2OeekJ+ZgCno6OEgrHWlLrBKmfOCOfv219kFBP2/tu/lTsREJyTgOalbtpW5fG7PvHEAr+z4giuw38+pY1Pg8CBMvVFUvoL3rD+DMKLHOFHWXnF86lKyi5YEP417ii6AoaH+BxayXpE//6c+R9urzxCIpwLp/OIP8EaCDbmmxiI5pjdzPr24W0Xjr0ijYznD0s4aCkMzIrUwb4UvwgRI6CJnoNGR4XV/+I1Of7MHtm9xkrE669JRtje3kpr8Wm0jy60EcnFDx8Zkh3kIPKnMsvYVvX2bvPdN8wXtFVrttdvj9d43WUXifCpj/GQBmOPLjLwJ6PeQrrhjDzf0ef3VQUcA8s3JuUraPyP6UO1wOUrlbw+9OnidLamSxcOgm8ujXhQdnbBJRxMeOjZZ6TkT3/eRPYZV+NNTDtoVkbNGy/JJRJChMO4bRDj0/Q+skkgHgo/iOoM61IaAnPsoVGsf3Kbe3GOS3smRiQotkVuQ5TgLlgXujJlSAUBsHhMsTfau6vOfOXbculf7XM4Wpv3PeycvSQ8gBGB4e0wmkVCctN7ERZR9QQSZzwO8+C9ctPu++IOltQsLG58E6BuzowInr5TrphMUabl142NV2JpOJyhsIs83LRPQVwy/VZJWK+8rM8Ygwomg4VdHtO3ZQxwnRoXMID2/sTjwurWz6xp9vqv5N718ZCjsL9iHN5eMGzIF9HyqMw5XZPG2XBexnCwH2AsiAKn9K+e/dC1sKe/zH99WGGt3wzJsVxm9+Gwf2ur/NDZarfnkWNURnv7jW+drGsUs/1XXy331VYSCJ+9YPb2VdYIp5kjwnjIghlUTkMB4HKocjJVRLiilWkUGIgbV9eb9ofzgyNSdj4PKIoHxRa7I8H8mUueqK9EnlaIySrgAFQ9ND9/4vkFq363RU0AyFT60O7WAFwn3o1ZmjP/wiVq8JIaKNh+sWgu6yWRhPehPaj3m9vYwDnjZxZbv7C1Egu/cQP4IAOwTBofNG42x1YBQGPChLSHQg0B4p0324T5C9jrhgbRloGw6+57igRVGgR3mCTLaDSuISc/RTTyqP5ImbQNYwCQE1mYnGT6Q/JBqslbp0UOsUPQ4gIIc8d2OZxhRFy9AoVL8sv7Ue9NtcINu0CVug06xzRY5uYizPd79uf5nSYK6fMwDxCf96oSklyI1HlbjVwbmTcHYiZXNt/S7qOtYDBhzZttq4cf/R8qE9fYAUXT1SDvR/ClSAW3y7BRNVmprM01PpPPmhFlYcAVMLj9nNxGgIBKHtc2lPMPQ1a/3eoT8Rp2FUQpSfBWZiowT4lpNxDgGqWuENZkW4Farp4O+X3rHuPtkUHCkTfklLVGzIIAIEAEuVOpuWkR5Gqz6A773AFPfIdGE8KaV8e+qL1TNrcCk+WE1dlcKLeS9jEjGakOOUk4GyalDgVvFE++XcAfaNgiAKGhyW/IARvVHkdP7wnH+hr9JRjMuFYWHKVcmbC24GGBrZaZCfC3tjsnx0u2duAMPtETFSbJrG/A9o3NApXchE22tBtn0Ub88a2omvU6cM92IhdoO22HwvHT7o4Wax4JhxO9sFHG7p4Sc6JOHs0TBYFQW+CkbdukcDnKbJ59U+qGIsBg9z/eESLxDeRydhzM5ceReiGC5SQCsQVeHyyx/MxODAOHMaxnR9sGB8tMYANlWs9HAjlM5NOZikS78JrsJxCnP37cHDli2rYI05Fzn0FHQC0USXgya3lCkji8EI+QkuGee+SYMmO13pkZaW00hSNA9v5CPit9wYt45Onn5baaoFylX6yyhXVK5YrhBGhSiA29s1hoShfLOYEQOsjHIwInAHxZqQzIGAI3S5/RLlZhT06e/ZuBuVl56YMPOhx7dtfsasqwMyByy9jC1hgz0jimg3wMjdrM9OlU4dLQoari4CRXZJgCOKKBLdPSVmhMspWslPbNb7KAIp3oLSZ3t8h93vLJl1dHx8X3/s1/yrrFUmZu3cLl4Xfm21fW7KbJXC1sbFrkzVKZx57I0hGs54FIpt8YNQP6FQAdOt06kIy8Pfd8mZlCxKGhumbP4kyeQQzIHyjVJIAWlYmvCAGp6v0khFYWo33YLwuCBxhvbIra2RAS9uWldZ1icwYvrHaTLJGXqci+9d2VQ59Mbs4KUgHcXzpbgPkhBjM7OiVkYIcWiYGyEhAvFKKPmCRSkm0YjHNx0ReJpNZKPcLlpmNj86+eNo/eLbdhBu7uNx6/M78ugomI88+yN5PucutZn7p/xuFkbCXo2Kx4ij292grSR0yMGxtkYwk5PHpUFkYyjLaxIV9B74Co3roolxCi6hpnNluCXSHqzAhPYk26rOBa7+z1NGjy6cLMAnNieRDGhnCxcMyJKUBrZC/THYc5RlIYxuntMdEqJ6d+fwl4aoWCZqNw5AU/DcI7Qkt09KKozf/c4O4JptktjeN40BeOZ/FVrKvj8wqrezXzRudtAV9dYH1gys75vPdeU9sZsosJR8/k8CTt+BhjFyyq4XO+8hXKM089JZHaPeBNHOxZcSxnFUYheqgjNAzsCoEJcLDtrgCJOE607Idhh6D50VaD2+D8zz1hOjQC5SHTAulPHc7pF4a51HBkK+q3urdLiiPp4cJiJC62AEiWn16AE2gcCIj/MX2oFkDN0P6QE25e2MgvbXgIrhDT7Wo2dTUV1cx8A/TC7j1yX3K3LmfImuzrcpqalWTZzbVyvDiHKGr4SGIHGCZiYaGtajZQg+iR0RG5DbWYTAaQ2JNi4GD1ed2Wg2N+Qwosz9SQ5WhDJkFVK7ZgSRWTrw7vkwJWr83GwqHavkQoL+Ainy+OblamAqr2knvekxYUw3HpbwrmiVFzRC1VaW0j1sb6SI81Sey6yEvFpCGkDHOBRMslGw9YPT4Ya6gk2HllUjDZNb1NZU6Pbv5h+wMricyawVE98TpgVQIWKKu990ZFvQuszPX352yAAJEX9zJvRlW7TJTFYbAu3KhOEAIzQdRHCrpZPe5Vrtef/ov6Q7cpW8hyDbSspPO1sGZw8Ft/PmtNFXGl4P7+ZG/1xqjYIRijsUmUIQSrMjXApv9B9jFeiWzFkT6qraRaR5xSMjgsqzVh8LBQzDXtLbkAOZDHdezZxbPXRYf8k39O5rx8ZiotMUe892MTzb2LZZQXrqzX68xn0XjQlzfEa5JfPyQBzk/oI4zOnZ8y6RlTo1WitGHWO+il0fcvE8WdYbakwn9mNOzdy6eG7ASQp/8q/ejD5uIFeRgJG1isjIKOCUaV1A76HhmcgdOt904iTAQRAwGtrZSQvlMnjVWrd50zr+vvcu29qF5/xKFDH1ilISo+k0nNpZJof6ijQ5CTDcVlBU4QlYCQymPGtDPVQs7em9r1Z3pAfYTKPYB17ROD4uCjPrB2713sB/xKi7br5bg2lKAldbQQ/yLuq55SAV/ANMFJcCzz8z1mcKAyuMTjNIh9yoqqPvHR/6F64Fn1DWSmZQODbB1an6jZUi9BXibHQXcdFhdrS5McE/NCmxVEO5rpeXNms6I3OFWPRX6/Ffpw7pav7+agA85PODx/eb4GfAF1s+PgRdO/TY4JVEfCzp0H5dhbbVbOnv+339j5iDbwyCi69sQ36GtZZVQdy1sHraoqn1orxDqT/icelKeq+oybROd9clzSLV0Zh2I1F279WDYSMunRVbmr1scSKLf6OnUdRX8g7Q97Bs6IyUltZoGh1ex8SjfXFU68cHpixvm7vyG+wfmz+apoaUVzxDM6BKr46vP8bO7sMj17g3UHamrUE8uOz+EzzGtwI94QamNjmiVRxasXxrBMQFhWNEHYP4Ddvn1yTJQl0REV8Kvxf/6UBoecjLaz68iv1wuaUTeolEu/+lJha085sYV+N4dbPPkZPEDh/Muvzvc/0ND7Ben8QJGFIHlfbUzmAEGY5+VMpEVQcLm59e6WfNKxkhoRvUlQ5+FP+SNdUY5rW1YKqRzgDELfUjcQG2gYsujNrjnBA8UTswAUc04T8n5J0krh3jzRHVAXNHytQKwL6Dw5Lac+tzxlPR3KvD5S6L9DXupn5+vl5T/+83ynaqD72VmrOvzkI2LRzp0WM4nmIuQDAQxwPKz5t3/lV4UFIGk+dEU6VkA4jW/tBQ4tnqeFs/sPuNIz65tTgyubUlwylO1IbjZWSbUdsQZCQYHscpFMzMhtZF42LNbxkWicrX+ngtooi1O5G4OSq90O0TAC5ot68fN5xF/OzIxu8joIBdpC7mEmujAOCE1M1NZe67gLwcQlCrvci+yL6KtSeLq7zcFuMjY0sLCYcE8fCAsHlgrlzEYKiIxXDIGWkBjL7XQB9ZqclN9xhnt6RJ0yIgFNTxSYxoOOhTB7eG6snLfdRy/TJtwMASYYqGQwFmKuAV7rt75nHjosp4B1erN2Eh2O0+J1bO0VvwGPi0m1X7xt/sSpuLIQbV21tJmVmgoPW/xj2SavgYZ/+Ae59IV/EmPvAQerMSAyuuTz2VMjEyMiCDR6X2elGb/6mvkX1UzMK87PlbnECzHtdoIHVW3rMlmCrvBPkjB8nupFF1SdbusXmbExg7m5muoSQAo6eFA4JJWSSb8Q3js8/JAKAby0sS4jV3ZMnZkb+KvWMDkcuZX5fCgmdRu8KH4C7GSbiL7GCiovGIf6TugqCNmno/Gp3j4m0sdwO6uwrLuFsrk6IAu04D0I6aAXgl61ddPF4AGrq83xlzf27GLvwRpfSLTT6mKRMtPLAmGiTUHGzclAODwlJbSwcdZKlmQ1HFMag10M50Kjo3IAe/PVEFWlZ9sxO9qVfPufvirHv7pNJkehWixKoJ5IJTWHaL9iqYzASjBCwzR0qHa4WAhEz8oyVjx7+jKN4NbcJHNvDJLRi7UKPFIoOgcv5dtb5Os8QfxwUcu2BBy2j+lDtcCefU6/Xa5nilVVGyOD+R5dsOfsaBfn3uZlWt8QIWl7QEvGCpy58b/+SdNn1XpeH2JIcegNUezFXJFkhINX5C76EY3B/lruT1oTuZ0J8aZqp1zzz5uNNdEXqikYUSA+ZccVcOmB2nZfgR19poGBi6wZnpCHSF47Nl3ZSzLsyQ2+PPrKhvOP7hD+RGZRg2dVOagLKPe/J8H0WpgMXrGy3MoO2/Td4ZkIBkpWdy6w/8Gm2a8S01Gjyi1ZbRVHyHF2+HiKTbEo/BN7TW7DuFUwX5EfhB7Tv7ezM7KnMqvi+9/N3vdEeMenRDWQB6KYyoSrvSW2/cBaDRcZ7rACgtpsZW34lFnW1jujAEuUoIJmjKjaGT3XP4IMfjHk12LR6EjXNUWf/NCGMmRwRi+pevh53039NSIq80+ZALyRzsw/M0ihu/rz/XVZG8vzBWtZ7+tYWQ7XSWfs25dC4VstTciGIRqr/2/MmwtrprFccbeO0M43a0e3vF4wuxVO4MlvJe1WTY2TeBU0QeIN9glUE1kdcpaK3sKaLyaGw9vQZjobHHa0dG5269ZVRVjm00Pm2oT55s3Cb/1/TI91yGm6H+RkO2bbkhecMuZje1aZ972LvGDMvWXhcOjOO014Z6fEpQB1mJ4/2Hv6b07a0S206/SGKRJRUFeW7htDXcuZ2attQvwUeuxR07gt7tV5NK56tlPcaDh59UsqNvD1gNzyvqQWQL4FU4U+hxKJktOTFjm2Vg07gVtM+ARaWMBYYOshOPl+9aNsp9vPlws3qVldMntG+4hRROS1oexLaR/bhvaej+QvlbEuKLa6XxmeYo9pMAlx1YqLFCB9aCGoRd1UklGt6ev5nTawVdUfPvo/1pp1g2V0kIoXUB/eaKEm+IpVLWAPO6/u2FGRDhsV5YC8UxuWq3Ql6rsaw/thqimQ8dbp3HfGdtmF/ATGN9ajUSJX+K46dwodaunSRVOoMbvEzTBzA2buRnt8zqT0tK6ucO5Sq6yJYZ8BrzfgLiXlru98xzz+OCteWTaknRKtkbFHL7KDfA8IJ/r9k0fHOatpDbs2Vk8fxVs2hz8T4ZHVqzMcx2o81ez3tbBQpzv/rq6W0qtmbIgr5s1XzZH71rZ2ek2iltP22wqe1fmpG1ICG17RxB7lO74ju7rpjxesmnnmRUnrWaWDCaOsZGgrTghiRCvlDrVMMvJi9RRjNSBgTCcEQHFHApJPXZEd29eagI/oJpcam4NsiXXxbeEyVmaWCrLShhU4nNbUu9LBEu4kJBkOEokqne2zfnlqeqpUXTOfZQYxArmc6+goO2LyCY6VxUZvvry6NqSqGp+BhBOhqLTqtaFCTbLCzUBJ5JYPtA4SISuwIEYZam83sXp/VKd3Z+fWMOR8fp7kVMw5uWx6d/mZqQi5ZjcxvTLQ4ZBTxu0Q+G3b5ZhH0hslO8yYn8l5wt6nHi2GylICkQB2UOzaJvorEkgB3bD3FmY4Sem/WuFgYCJz1exERxAhcSZgaDNyoNF26mPDmWBu6o+bB6XWS6PDxeHhfGuroO+m7cYXIQGBQHzunjw5Ew/lQlZ0HIX5sWyxJPX2ukpfe3rzD35P6ubNl5iR2NZescr8gjilycokoWRJr2LVGW8Mhp0GX8VGE9bX2x/sLlicUmCGSgFYfP60PLXz89JllTDz8nJpZdWry80JRRdz0hHWr+O3eJWAe4iPpffflXAJh/tl1gDkcpbpIPtOSmVghNvsnTyLZ6WxBamzGAgreR28ofjI/Sah2v/pp81DD4G+LGDJh2hlSkSyUOW9NZM/yLkbEC6Mkje5NG1LxvdgIj6FW3Mrc+riMt4CSXIL1lUD8yEqNDfHMONmSmQHDwHQb8ENozF8USBQ1pFF6UdEFksBUbmF2dLbx+SRA4fWMqkSDBaKiMgl0G1M2rOfEYkGO4respPfxfvdSDtG5l/4Hmfmyc/5PVWR253zHDMPE7eTJXx2uP/a0A89IkIZTPIt0ugwRpPMoWecR79bUC5k3TqMKNJ5+Zr8QliWWDgfi7cJMap2770VDw33mF4APtoPpCjCijA8t1XHzbNPZ+8/IlzX3lR0hUOl5VWyokkRrHP2mZdekI994qmV11537OwzOzF3eIADNEjB65Nj2WcvIkoPwssiKwytSoAVgjkhVhhCAADq/NkDctxZI84VTMIkW4gwCp6kCqWICbzBXAE7BI1gkraRQVFuo2nJl2Nnvc7MOs6ezN95wIZxzYk3N2Ch6xfFgOBSDp2T3WOEAl56lo9Nqjq3naMXPv5zSy1w8kTp3lZp/MLiGvpW9ImdL9HeIdM0rDqg/xAYErgJDZK4NtlyUzUj2xcvJQoCirwRj7OUH/fLTawb/fRO42bglGX0UBSRjBk/uIwsbEMyshkMXnxR7AEBiCL7856TK5/aIjyAyEAYqY4OEcyChGJkXIiNd+wA1DsT5qHtm59EpSjjEWWAi/LqSMmXvD9hcs7q1W0aRECHQN88DUdlET07LjeWk6zizaqdKD9eQzJfEq4K8zLhnw0I7fRIF3uyh0xWxcjCL27QTzeeglkmpUGnFE7cxBUJJQurHE9e2zhzqtTTkybOwilChFiJtdIg1Mqi2LvrciaSgn61WHCMb9cf///5I/pIfYC9ijvVVsnEPzpYUYO4B2LMPiKayJgvTZjPLBS314ilL7SJ2rbL/1yp1cFTy16Tr22UXoUT0Zkjo/Li1IZ5bt08hR/DI5uGecTdHtYsyCl/Ol1mXPlgQCYhmzptR1BylDl5aHk7dra61vLQVtcErcszvKSALTtxVEzkbV90SlhtbFQuLS8TQ9TON1UpGfa07SOXbo2ID8F1FuPy7AioSQdPeHq5VJkj98EloWj5GmtwMXmtTIQlzqcgqWFnzbWvyVpoSvB4SrUXzA5lwb/blMFDDKdwrbpbTSyZrpdjzES0LmBaG+QEt5Vc9CUTUw6mixVtyZX3JIl1qdszNG1OisSLrS+VighpUruv3ndStAe4BHK5QEFWxO7rMrNTZiTzw6WGcsOPEF1khWhW93S2ioaupIdV+n9ssu6PPPfzHqr4yqzglwkla2G0C70Mk6t9M7QsKnFSgStm+ivnxXc9rHee/AV4gD/xPdpjMmO512Omlb2J1TP9fn5BbmSO86WsuUej4Zy+MqjDueNyqcFnLhPGkkPT6JKvQJDVQor3eOukHXnLt3c05SRQDxEwSSR8qYnKnAPgJJnRgPZyKSaoeWlGjkcHmVgYva23spKD/t61vUaTK4O88QaqvaLU78xvBKLMYilUVqbvYbFOwEyNcql04pTT75k5M51sESn3eQrPPi+ZBoQCfgYFxoeRPrOjLQbSKaxvsm6Y01CMHbhlLym5tMfVsKPGw366KGNql1syrkB/vwgCQQWw7z0H5Das1NxUoSU0Vy4Iz8D3QFsbX/d4CqAZ+3EdnWbszEptwxoz7iDxH9YrIHjvbZpSAyNjQcq27Y6JcRf5AOQ+J/nCHDoozHZiaEBA0syMdPj5U/n9+ypYsO6Q4lYNvFw7uwFfzo+K/wNhKTFLvrwIZazGh9+NO0flISrGyo2Ern6prZYJUW+clt8fPChrtBi9cTJggbGJSPoKa3oZjiO/++KUoF525SMuTpWzDLGDDWCfXN66f3gLIDnwNxoEQjsDxez0A1oGg/rKi9L4HR2Fzp7Clr6IcUgLz1xenJsrxOLySE29M8KGgmWzPCcfW9/sCjaE8wQ81Su745BragrVJzaSdwGmv/hFzuR1/KJuCwuQ/C5H6c//s3zCr91WZijAxt05PXnKHDrsYHMwjgeOLYf8hVLApMaWOD17urhlS5l51RA5kT/xpN9uunn99NqRR73hGvfKsnw72GZyOP+9F8QI8pk42F27RC0sswsnr6HJLDyqqvLt2upqaeSSyWXKI6Pp9WL7rgRnN14baoJ1cJig6qRnfvH496RkmhQ9iSdDsRC3gOm/c0KOH9klMkTXQMAduBSDxZofiK8G+1p4hpdExJESrKfKKWwD2rAkI4EKbsi+yOwRPPRqLfCTv+KpieVtaGxshExkE9H55z2PPyBPBQI1d26pzBNdZJOrSlHwOd3KuxhEguAEFhcuLkp/VY+tuheuhrboraTcLJepgB2jQ0BoG+uNMODOAQ3GmBKEdadA6+TgzwwNle3v2XQRHsZAX70sDR6fm19PLze2CRM3b4uWccrVPTbd7YxynjxRqY8n6GWdog1G4uoX8oJULQ/gq9f3xrxExfGWF4vVPfHcjFQVacOXsOLPKQJCbW1VMZhASZuLki+lHPSWn90fEZDqnKvKWwZ6oGfYs44EU8uVOvhj3tXVyrIQWmBbb+HaVe6SYmtNefByzgIauo8HD/wKptk4akr1ySl6bcd2uTPdIWu3LDdRf0TJMgByhGeEfQ1JFUQF0h0UAtGJVNX2OL/AGJTGsxBfB1zYd0CarpjNL8zLyq5qhW+1t4XcrYmaWmlhZ2bdDWhKixh4HTIIH2Y/JkXBW7YUaxo9LJfnUiDhP1jjDbHRLeRxbtueI7BCtkzO/EwL+pg+TAuAuFjnKU3HTFOXI5NhKx9RcfKXlYI2SofrU9uEppTf54aw9v47dsrMfAj+3tpb1dzKoZPR5+mprmVRDfemVC2gJYGr0IFa4wyZpRE5Jmrl802+cq2tS6y5I5PFm+ttlyswJE/gh0DInYi2yzThqXGbQ1Z2tbfLMeGS7V1yyfInbA+bWWiCNbC4Te57LxJp0bB0pmyaVN/2Nck8Z1jUjt8yyYD314hWlsnALq9LjJ8KsKurPVYYsbeha6nngtxl20UOXpU/pnNNthGzzlvXVoJLxaVh0X1HXxETf+msOTEqt7FXGd/LEgcIK4aq4T2C93VdEzjDpccfoW+j5f1//LHyg/VCVluQNb19CM1/c+UMtQKy/PxiNqwlkzCL5A15/LlqOSdgRChtXTtpYiJLpztlp0Ppp+PHxVVgMgWU3TSPtVe2G7q0YB5tNHGHWdSW7InKlKqjcpdU8kGv6e2UYwESdCIgAPMDxWKeHVvLDbVynE6lL48SWeveJUpt+s3hBpSXxRB+Pwrt6X+Qu/5kzWxT30lObpmoQyvCpffzWcgGESrLq3zV5i2U06Ow3poDRKe2ab5q5fuBx++XR72+PQ8k3V7hGtfihgiCFkj3IcMXbroQfFVNwoxMyrWRUbNZWmhQiGXWa4lUwZOL+hRV/WASoKAJGAaz5knFS9a2Ah5e/YE83TO1sLS6kiBCgYfQVUQ8bTyO0CqvuCpPvwdREtBEoJgx7USESTSlAYZv580ndViV36/LxY+G8EIhjE+UETg93qN8bvEFqrBDX7dbm5IvAe0wqQdC5G+fMsNjhvshBJPus+KJxriVrtTnPsQfdC5ETdhKul3NHavXSeCVVxbGn7ij1pDgyqZoZvJZbVzyRkKkV70raTIqR+kV05qRkI3gP41H6P+39EcU9K1TlE2HWPWIen3H3XZbDSM7pUHpOGcnE4bIYK61vuM+E6CHteX5nfTDn/ods6mXynOOlTmHjTMTBtzIlPVrmrf4HQT/mXFs2e1vv0r2hbV5+dBGT6qw6Y7vavctTUk903m4uUEhmtifq1ct/hB/xR9wOYp2OUomwyRh0/kre3nC30janZnStetO6/msrrz1eolFyBAgGShGr0MWx//Vf8wevktOcTNQEf6wMPrqjSIj4SBmiNU+q2uFJ341mEyKAwBuxrW0YGtuplQfmTPnzpfm5NudLgejkqB5juPr86Vc3laVFwHBeSm2ASIMjwjtPqhqD/01PT18Tnq1vc2EmmPFdH5uVqQSM02MY/SqKILIbGFywnR3Vtob3Ab2OnNGdChGDnV23yEOxRHezBJaKIypXqBs8JY1/WBrM7qZrEKHyBJnNCHVsDKASV5bLto2YTHb+GgJxIycQy+9JInv7exhYGLb3mS8RfroT7+c6j1R2LV/w88yQ/yRtGaOIMQKsaUJP0ajpaxIHwl8quvTdmqsOCRxuymlmboiVoEZIGQRgJJtYXchu6YeWqIhuD6+8uTt8jsvpRfAoMRfIXdzvWn0BbUjmvyLZ98R9ykak/f27QtFqr2Stw4iHfcaOYalbp27o2RGwhSTvJ5TX2tdcnKhrU2+Yu9hNg5IedjPQFwOccRf/sNvkw6eU0kCGI3mzg9x6N7Z5di9y5crzrx8mdPqA12lN446O9WpMo5SJst3QQw1RJOsjc/jF0H4HjDJkd1yzD5hbe12bqx55qh57ID4/HaAlHAsFGblA3y7mW+bWuN7rZ8PCodhLNbq6JCBLxt0KBbKc4syuGGnaxpHwVdbUcqHHwmx15Orhc130cAyPdEXC5QG5CuK6Wxto8uBscSEONZw7Bu6Q3PDUlfw2fBAwaJ8vyvvYg30qLTP8qWZRFc81hwOjwp/wgYMSOInQFhxoBLVYywUohcY+LLfgkAziGWr6mmqja+l8RyqV6SPSNSxtJCLukSOVgazU+MFnBDoLu8YJpzSKAc6+v10W8cmtYIa+ojoB8uzsxkNDdTVE6lK25nyHYHFy8fX7JoXRofwTJh9Zz1SimJ8rr5DRKxcVcU+1ImENLSdcMUI3sKUfODiQok5vUV90eCgJMmgEWB+yBX0JXckY8TY4RlHLryjyY50OVcWJ4fSTTuTssQZUaoKO1wOmy8EB6hzz8bA8TU2jZUiolHv2sL5o9aamP9w1PzzB+VnxA3hxZFGciHAOvoVyYWsR20/HNlvapZwQI3mZ49G8+zkvq7NyLoLVCJLaBv2NvCUf32eNevPfUtK2N5XzGWKbEcHseQSKXYHvSUdGUS0FxYKHuVuf9Dlj5g8+eyggIvhVlfY73SJw1YZaJOjj+mWWgCRmhwR9l4+n779bn90e136hCiK4NY+8QCsV93BfOub4CTWLWNTh/9b2coXKpH6ZtKp8ZLy915auLEJ5oNakzp6Ka75qJxf/VJm05nTdJ2xgAyjJ2/vDKiJZMYLDG9TcmDCANxofgi5IzqQZEhT+QGd395uDj8lMuZvjntnJgfPphFkaGLSvHXDnJJDiUzfCh0jDSavUHaamTOTJfPgzS3sQBgdrCYSdSuhhLnJfO2pU2zOzqmHJFQp8+XX5NLOoDk6X0lZpjInP6r6NmeLJps2d9XKL85SaW5w5biOliMyQDfmn0fV65xVL/HavNyGx0YnRIsVX5FyRMJ/AQTuv5WScVlfRwZpIq0DkobBqNJjmnyOBJEAAEAASURBVBw/G2EDmELc+bOR2AwMHHmwomaSdEd6jh7Gx48q0iAog3cBS1hPA2WC2iGGBnHJanKO93SYpmrdvqdLLrWRMvaGBOOgvmrJWQJ3QYxXYZku/h/P9eoWiLIhUCRcGBzlkqe9yben353Jzh0b5rR6X2v52DuOhH5usQRItKZhb1Hm/gkf3BpZVqShcFlb9BHaCq9j4uaqPBDwrZRGOdw2oGL1j54ga2OR7O+ViRClYqQ+NH1SumJtRawYUgOVRkwxY+4IWfBrWOFxec7cu1MuMXHXVcylJ8R0bVxfTyQctGp/Qi69viQz6PQ9cvrTpHeJiOFd7O+X65h72gf0RTdBHk+5XMx7imKthq7KKt9BRcHM7nfkxMm03ztyU1K4jUrBWgidAm5ZMeXKmo52rpgvTpnrqcpwNJKKUPz8hNmzHHuPelxWcjFlTKtc1ZPrBHPZCDdktrXL2wCrQGsWZnOMDb1ru/mPw+Z31fZFMmYkVZlc+q4GkGc+ItrP0IsWxV6III1jirWaiwLMVvT3u+pk1yK0pbW/bfUCq2yUwMvKRpe5PC73sTcGte9WmdXnPsQf+uXDkD+QnZW61cDynkb8FUdnuzyPwceZsNVkFQ2DqOfExph995hH/sDEek0MuUCjLC99+QeJO6iqsNLS+HyC7fSAa/W1pXHmWa86m2AhM3N8orrOmSLLDJf646540k2oWVeMzJ8c23sk5u5U1cv8mwY8L3QX3ct+PiFHOhXSTcX9mVxVb5W/RbtRLJyDMGN+SFrr2kChkQTNahncVVXupZWlJXkRkTC4vG9rxZ1AZjCco8PCz0yBSLQEPUlRMzsbHUXSGjZ4EmVkBIWTRq/ZkCUK69K3N/YduBYLi7kFSZGQo6YBxmazVMfEjZJMLEEMGFqPmf/t782/+y05xQWCvGVFeSCv1ZWAT16KL5nfSAebqtva5AOB18Bu+6JcusjCVkyjVYI4b9Z/4zbuIbSJJoXAvmBiDNuXXpDTu1sEPlotzKnHU7RhKUBYW6fT6y1xM0RP/sVfmt/8ghxHajytvQ5c4q99TU5Zroamtp2M/9DWn6lhrRoJ4h5NLZCiI5NfnpPbqAALlmIMatHuAd9bL6cP3Z+x4+HLS+VCPm8BBAkhvN6ydZwollArXoS1BMWNTRYC4b8LZbOBkGNHlxzSIwRH3Z6iDT/4M8vzl2hOaa7chuzGxj8S7nHqY8YD0X6aAKa7vljYLAY1A/7yZH59PtvU7PCz4ArK5wP+8oFfFe0dzi3LLAhdLxxihDOT3rXPX/naTGbgxfEtOrGgcP5yatMVu2tn8g6pk2Ny0uGVfM0cn3h2dm9v0a4P9oY9jkKBaC58BfF1RGcP3CbH7rDf7Sz6dMe57W1mZFhisTYEQePjIcwzYMptzhI6t7rRs7YgiuHqNfk6HE4IjH7wUMWI0uNkfkJN2xbOZsvUhclvUKSRZbxJU52o5JyipwOBs28J4m9vN4ntjFbJbaHptUhrPJLaCG0RJej2OgpuZsFucPylr5pDu83e+5EgE6kig2F2bXbT+jD0BTJiQ84oL+ufa3vLoBAwaAtxaGWz226vOJCmv8eXzZVOng555MWeRDifXbPuaHVPpKm4/Oqr/MwS1Qy90HfY79ZNc/zJonsz9e135FL/rnSgGcwYS6r3zkBxMkIif5Hf6YF1ptRqP4hzi3NCy9M4EN4smMZrt6xwFXzRQlE6XOqPM+MM+mP1Uh+vc2N8rIQzDzE6h3wxVL4wJ9xVTmXOnc71bpEXhQj8OsuRgGrrnClHS6GYe/CEmNue20srk6mqTpHz9ZHFSFMkFluzg2+OJBstM+rLFQGI/WEzOirHKHc8OhQCaWnkPJ+Hf/AVIfx2GhlpsgQmL+TNbo1i1NWKNzhwRaoN6ERw/HG/V/UGzUo73HG79HLUny+5vQGfGK9gc1yi2ekNR1hUjTvH1hFkc+WQCTG1ZmqaHC0c1jfK3tDV7rzTLve2gRa96+M/t9ICMJsdTQoxZ5707F6ns1+VFwodd8e2p1dN5I3LUmDTfWbfPzO+XuNTE0mA+C9l0wCuOIKB65dWsXKQdZMi0VzSPcXp5JWNhq6g03rIzT2IXwCRGxZ+GHx19Z4jTiwzx3BFez5lPfmqxiDJbFLpDXcvV0Q6UC8xVhhCBG9ra5qbxxhLh+A0Jlhh4SHlRD36wD9thEIClT3ronFRUDVxSfwL1U7BhyKDEKrjL58ufzq94EdnAgQ1B9IOZUIH+/FuyhS7HyXV0YJZSexhFcXYaDmdLlgbxLg0vApTN2kJb43IJK6cymUqL1POkH4LdqXJfjHEZwGhPqCVtut7aWVgEzfjEkCzxOMUsXGMcHKKHRVFcxO86uGH+ENpYokRZZADo3w3t8REH+K5YzggepxeAA0BpqCqapczUVUoCNcRpEaTcwlamZWwwHaSJMGkGlbDKnx+vxyvgSjYgiIix6yhWF/ItSXWXYuiT0x6ZehaubNTuG79zNBa2t10qD25Q4rIjs16HCmXTjW5fCaXXa/kgt7hMa9qZ8njN0lsBr6cjnpZHH/zijVW4pzwkEqOjITQerTbTxXz7kPvccAH48t06FcgZ/4oWX0jFeTBS4LBN18TJMTnA3hsePqVU+ZAv0Tk63kSboyZ3UBzARrm5EmRo3seE3FxgU5SyzCqLhMRo1N7kwPl1p8irkLcdh9V0pI79gjIHDmziuaHQIwAA4sNuAHf+LxgWMMaF7JuHikay9g0gv4slzimWKIAllaVJax/yzRRMGtaL1hmu3nXz/4/nGX9fBrjWQY/tSQkwlc2fuV1vgdRD22aQa0iHixw5b4j8n4GSDHBn64zoyqlGHbE31bvZ6/Q+zwJXyk7y+VGAJHf7NMm8JfFcdH0YeQvF72LbrHjIi5N8W+VJy4iWn1IOR3pQd75KFXrH85r/ZDuVvcWj0seKQ5O5K9PLK84ax/ZrV/AMvoc2FCOcXcZb+t+VA6d/aaORHWn7cxAMzseSZDp8oZcCsvyJ1KVybHb7Ugw/L+4eln4J76r1d3VlIxVy6WmOoeffbICpl/cm2jTGd+VcxblDX7z0sJM/uBTqpOZCEVx09M3LghUbesLmlYSN41xPPT2QjRcrq0tk42DU6p5bZA1TtLYTt96LFiyygiUA9YHftltfBEzWCHG4jS0JIuR3KXsnCCqZMQr2DYccavr4xkbY8mHtSXAo0KhvLmarWqs4k6G8FnlEmCbDzTOpqOeCY2kDUImr05dvmwe3oHngB7jLaW33zHtOUFyidxSsKM2tjLNsdPtHLua79nf0HC/lBabXPaHnLFmUUFsyTU7LimYbNgSNUrNLYvglZGlALMO4ckwBQvf/a5uOd3aLi6cjdYTmgol/FPDgkYTbVFnuVCbSwfqRGOTn/7xJ10BpmVDhfyVs2bPbZ7ublFoLGViIG7/EbktXzDn3l6vbZQm7d0Xb+3IOCKRPElb6KOowMST70gLe/1ZPrazM0sbQoxXMNBy+LAcs66MJPhWp6NWqBiBBKsXgkHH9ETZrisYHs0wvmLnPNBT7B3g81Y+9ugrWWbI6AYBMjhGDhV8L9/+nVI6JYL6lVdD29rLmOW4GJOa9oRzaT59YybYKBW6+NLM9sNckHbIzGQC1cFT35rkuKM5l2h3VRMnLIjaWz01VBsuuELSESwvChGqnZ0NtNZzWnIXHYwRaL27t3mnxlMW4vsCBUZogUCWu+AruIa+gI6+yjhnqVc7Zafkh5MfbcgQ2R5mP7R1dKZIfhzhXy9YNxjnE4G3PU4L08V/8w158NABlizL3F57G3qBJPXhWuG07PSSL1713L858djvCUcx3vrMnwzffacwR7AuMnR8acundnAcDUSGXxupiedHRjkzr550/Pf/aNNBtkTWrzf6EmTt6xe59tDloyOTL89ZD/nMGUk3XNqUqr7zeg7Pnzaw3g6CgIU4+qYwwM7tMrQ1eEqksnrhYuKR2x133OZixBvq6ozsCAfnVzj0TF6ji+xCPmY5BkorwZDL7rEbD8hsOHZzhl58Lv/k59dgFIQOokn9oWwoICXkNnJkgAOBQXsfiDtXlxnFsW4nE+1efNG0XxdNfvsdmUiVpyou1aY9Yb8rpzPtHfJUrNqzfikPW0J0HPLt8PvitcLhVy7kG5MFZWFWhDoC89Nk+uH3118tHbkH1skEnaKJB48ukjqyqlUEJLC9a/X0AD7w1fMiO33+0cWJDCoFAq8UR81XzsrxHyVElOCBLP9prJT4nw060KG4r3QuRLeiZHAFbTISpAmO0ieE/7kacuVPv7TEnXufaCShagPqDGK+wPyCp3SdQ1dD3fqVSWK3DrtpQUtzbWjZF9JvokKFyn7xDLzGWz2utcUbx2/wFBMCOj8nJX1Mt9gCdf1Jnx9EJ8PXk5fXHe5006+pqEdJegXPqLUS7L1uksrTrCqPo39Om9VBecWMhlWuDsix28X8C53cKpO+UA5LCyz6FX2R3NPi2rPVyb5VUKxFQp+wWqfori3Rd6LnXrOK/sSb2ekJ88TnQPvG0dONPv9/2XvvIEuv67Dzvpxfh9c555menhwwAWkGIAJBgKJIWiIpybJkebVarb1r79Z6Xa7dKm+tQ2155ZXl3VKJkixqLXElymICSAAcAoM8M5iceqanp8N0nM6vX877O+e+hkkRIAYk9R9OAT33e1+6370nn3PPbV67cWdcbupAe2t3bujK53MXlqlsQY013H0AsZHzmh9IWxUM+fHHQy1MMm+uC8qYY1HJV6TnEgABB93mLP4T1b2eGZDKr2vLFfg2AMnPUT9QKEk2qIUmVeTLMg9litXYGqPJxs011+QyrALrhqANp33lkvntL8piTiDSaEh9rV2RNvkl7qSkmSnHva8AlNx238C4o2gCEK3oJR8MHXoKzcwNH+0xy4IapiYuuV639RSzfg/yRCXVQxptmmrIkQ6M/vphf9Ae7NMa4TwkO7VXb3jllOlSxxPHOGERH/AK6+921kape+n1SodYFIR3yYqnkR3CUhA31qz6C2og7xNuA4wvi2fwO8p793STM1ihlC7MW05d2PR5kI0iXAKOvIc9B+bmApjCnC7lnBWvXW5LJPZ7b5pFfRovvsjpHwb7yaizP/rtLXqlHRw75jCvH73sh5/3PkegBBZCCxaqavwHY/nv//trj/+CPtLp/Bf/auFXDskpJPIrr5jnPiNK2i9/tnzyRdFqlpbl1F9umD85aGL4K4mzfTLmqwu6tO1Cubx1684rE/Vykyji5+TfDwQ+E9jH+Edl1QDg8Ka3PdbWfjRanprh0N/d1DdUW1yUOdq4szo1aQblnWZdkZwvUGFV1fhF6qiLAfuN95/XQ4brHvJH6XqhJMaMdq1KF3rJT/6H2d2xZcacNOZJlEl9GDZeZqNqVL+AzOWwZOv4SAormioLK4CBvaHJq6nGsrmdl8M4kXv5928FvHiRtlwSOzUfZERHklnGtarOH2GwhH8HB6o6myiluaqqiUSG84gGiSxuNIdLUiDeYq/2/X77rOL2fi8WTcFJNVt4zdr65TeTos2MiyyXLYFDLGKF+cA4r5v+nSbIOYDPvGlunq0WWllbI85jjSV0Jj5gTdN4/KmZ+DrLQlwhatzBmLLsubvPM/ygPMDTQ9U58RGUlzjyEbP2B6xq2d5Sagjkqkt8kgmhhkCgnNc+sPgAN3ARRDM1xdXEjFmfctZE5HnfesPgfb53T/jw4kb+MLX2u+V39EVMNlIvrIf+9UXzj2qrSc+XL5lDh3NdHXLLmTfyhx6ZCuzfLiUxlCaxYSyfwg995OkaRyBQoJA25LFSPP0OC28Es4gpBbwl63nDrsAQYGoxqDhVyktBNuv2djhKwQca/RG+F0GXaQ/jPK94sMR5UXuI230BlWDiStykqEJdG8PLgqkIkZCSKl9N/aX8apKBBRgP1Dh+TokaZsYwh7f2C/7lXzZOD3vmymg72StpZQVuy0Y8cp3H1d1WLGSl22++U9r5YNTZHD5wYJ5D8BKrJqp7a2DJeLor3oCMtrNSvjdb6HuUeIfIoO1tKI9UhhTt9vJliURhhVo9mJdSLB7fJwDfRylHrwVI1iNuiwmhC9BMuFa2XaL/QGNTGSZmNUvJELtSQX23VgedQaiLd4jRIsmhNVSpqSmO3ubQTR0u7sH8or25uraQrMdZgeyn5sBGvtRAiiXM0HTvi6Xm1th/Si5zlOILmaAIUMq7kBmxmV3ORXb1cBhqr8vOLi/ppjQ4aJtbHZ6l9SATz7d3d6IFz50RRaO1sZj3VSWTx8U2WTLRPbvla/c4kuxkndkQ2iwXS75QNVBJXAKtmu/iSgBEwvVoAyyoPkirtVVZLgU8+QnxDdvL+Fi3x3S2y+8YpYwhigs5e8BTT1Gg3yGVvOib183TD+wtnvwPtzgcHHIcOkQYVYjCE4u07pFludKuCzfHCmiHZ05zZNg72oE6ry6E3uEwRpFp0h7gfM7lMpnrOIGAE0+4GLd4SoaLmeJy2Kg1J8B2frl1S+gFxGZal2blwxuieXDYUVvr8En3+B63qbg1JpNZy7QMhm+dFwHUcyAm+Xj57BvfRQ+RFFOcr12Dgur+lkAuvun1VHZ/oonDUHHj5uX8vrqU3LUz9NbLqcdO0ER3SXp760YiqWJa39sgFSlYzMkp+F0x47x2VS6jw/zncxfV70FmtqOnR8LIAEQqFrTb7YZs1fTF9fvC83Lq0UcrgUCOCwDEHhmVgfUUui4wca0o1T7JCOTWcDDkL6WcVV/M5beS7W3i9QempiQJ+XiXtIG32XmP5cIHZbgIYjBie3bL788/LxxpZlbakAAjzEttdAQyCWjdUU5hVUJiu3eX+hXTxFZLpqrilDzhuQW7BpL8iUCNBwvc7o5AnquPjTEq2qGNjXdPl3p7eJigoHNh3uEqXXpLmMiLU+b3/h/9/eM/9zcCvvpQQ14QslLOnjxZ/MxnSLrVKXwQWutQvRrN4rqpYdM6taQFJafM4jtmXpUNZAdcwPotvB6EGO4qgAAyiPHggyYQEp6WnF0JPNfh6HxIzjkGVJFYMz5RGSmOYm4HrQOot7NYS1kKq92AJcEgyxQTCaEyKLSQKztUj65oYbQZCrspF4LXg90b8uj7BVSZ+pJpl+823xo1T7OP3w4tR648jWwPEQzKDR47Lq4w+BVA4OXrV4xfWAhCX0wsCAHA+rSggkt0RDZ07NK+uabEnzgwKOeRmw/vE6PLurQ6G4WRNgsZGb/bOBbMZqqqXCIiuFu4yc8CoBm6bK2jBQ0mwJumPuDJvBqA36XLpqvRdDTIYfsqGfsmoZ/H0PHVPM2aEzyc6RG+/FGgZ8tS5UVnCgbWYsvtwLxxuVjuxECh6tS0BleviTRv3IdlV+VIxNtRe+xlCB3UBu5CJQCOHza5lIh+AKfePCvilPWtagkWlIv27cJDWpoqWM5j12QCkVlNLZXy3Y2B43JKijPNzr78gsgdbD9kTkrniK9nZn8Q4Jto6oC+oXqGRzC84I/FjSi6EM/Uk6CoKIUfEfgsvtx+HZ+cSZU6axIv/6H0pbPL8YVjRdUUTH2b/+ETBZ/uM9TfbaYHxRmxpKj5iQ4hH7u/YqQzIMtzrYhksWUq7XROsG004NVFPkKTHwAyDYob0yRijEu7o6MAlw/VBRNTckjJzRBC0yV9O31Tlj6+9bb8PqArLVfWzGXwj0lkNtVKp92nqHjUaT6hqmIubkaJaujYWVvoo6KWvOADIAgm63Rw/nNeMRovr8illGBD+bKmIEQ9pgPeqw+ZnjcPHUbBE9xzR4SVAbZjb+OIscd/C38ZAEiDUQLQCglR8B+APEXdsl5+1s/jTcAQULVInLk0bBv8vzJXRU4uXk0Ls3pXHvDRSNXird53H3/+4z84/Wv/1y4udNVGZ2eT+w9UdQs2YTWo/lQhBa5eMUOHt0hm1CyNinJhXSWwQzRrDiGe6UVio04W0tJOZuuogRYIurVsumhtaDcoiwIBHaj4xu9/lQNvJVvYSNnNo0K17lA4OH1GuGj29Pq2R1tMc0vbUbln9dYcu+ZYbbu+ryZSdhdXN7xq3vydT5ZZe49yCYyNi5OPWAGA1st/aPBW0rUkRIstK0FwQYlN/JSyb45W+vtS7WFQSCDQFB6qdZbWNmnDpCiowAeW1XkfLc/7/VIYGiDK1F7cvH1bxscjmw+pEqYziRzF8Ojrl8u8PaKROcPK5xKb7ukxM1dao2wD3cuV5ucqSBpgZtbRvSsyN7nZvgMuJGqs1BGvgE4m1OBcXE/yIcDrr4uqioo2rzTJL3hQUOAALMNYYzZflBe1lwrx5cLCvGnSSAXXh0OVrG5YPLzXWzvUjOJgcQ4E7R3yUL9RHuFwItdPPS+S+9ETyZpwSQwY7Dk+ML5ZYC1BTK6Cv+OMbGr3eGuYR5O+l6Bkun0ag4BrAeUQIL8u5nMWN9PwOA4zSVmrM7RNTiGSO7ucJa/8zq5Wdydls2a0Z2BsTHLqvv7X0ia3alc45+mpdal2OfGtq31PDdlkssJyPIhBZYXJ9HT8brymPbx6Q9Amtrcjv7Ho0tASKVh/+Lvpp/TJvbvDLmq3zK5bOeOuC+XuUFk+zy3lrKlkjI9y6jOqmPPJlcq9KdFNK2nBuI5B6SppBZXJFHqAW7GuZqQDS6OUlpfCNKFeq6/D9BkBpsN+rL+5xtnUGNEyHvnFtbAn6wu5XE7R+MFMzC1rU4FUDC9eFgB3EQEZBsSOCbbNqy8X+geFrGAcJ37dNA/VrE7NcdgYcwWHmwrqKiNsEWqOvvlHt/j9oc82hrobL11cPnGcI/kEimE6r8kpT1OtTCFp7AASOBCAXqwqj409ejEbVGMJowXkh16Q5VzISifWZQ07BW+hGrBRKd4cedgjFjaLzOgl+PlnM2Xn/PFfEevNu2PAldjoH5YR9pBuEqinDOVO4TRivvKBrS5hzc2RdLm22VETaUBlA1ZXO1bvTNyEl5q+o637H/c6a2SsvBubsFHqtp+/LFftGDGD+0L5svATyhiwCYS9m2mn5zAbm5t69mwFemGNEwDW8d7VmXSccldEO7d5manDj8gpjyeP00utUcFkPg1DrleFCaj+tb82//Vjyrhy+T/6SvnpE+Yb35O7Dg7LBl8aEZcZ50pFOglBM+wOl7F7BLLKomkgGtL0vwMHZA83Rh2AfRK7Y/AtH6Vv1GJ99BFhLnQAExFMO9Yh4wD/mr2EMiuk3dHvuXo2bWui7DdrXr9j4lZBZpDYxVtL9Ka7T2iZnbtxTFm+15DPu6gM6Q329glK71A+KTd8DPc3Av/dv7n3u/+D6A+R9QX0M9aDao0LKGHOED+yMHmD1bpbCiSEdt0sUCxFFXgSZFn3WScUd+GlZZDEMlIUYjgNPMyNJQGf7+0Q3HV49XmgCMw/Zb725xympla8ueSqLo6KqB93/IYgxuaF6f1HfY6mxoefEpSeHk0XipRClQcQCuXh9NaGdkEQpl25WzXKJBf9WKC7CBnhMnDIlOm9JaRhsR1aO0yxG5VpBLXaD7W6oyHP6CRXsltmKFlNiEJkvYVbQZ8gNKywqH9RzbbDvqJywBMgvRr73Sy6uGUmyizNllM4ZVZyplFYi5lNmFqcTlvKEJYMgkrPyFkVYNL4yYDRhE9Z7aRbzS1IZeoDnmWVTq7nK4BWugKNbkj4SGwRGLvqrPAPnX4Zefppv0+44X0A1yNsD+pURkgLxUSnjo7yDRQudIaXlA0eyAguxWrDUcxroh9/NXnguVbLx5BHYJNFQLRPjGF0Tbuai8AXaoNlVji6v7VoDmqXEAtYdDOTxYYG0QHCdZ78ZKFcFg2HXES/r9LVVcpNiebhi2HZ5xfn5VQ2bd5ZMh36eZhtTVs4wymMKDsCtOl7fCvCCeIw1AzLw5zQDC4KG/XIO6VWBMQzI82PAPNkK0Ces3ILjmkkLyJgZlaQLkb14B2NmTn4p8Ev2TIQ/vK/oyPm058SxIPNPo7GC90mRFlfZVsuboHzovlYEckgBvwso73JC3gC+RHy7weCkKUGwTJFswgBKJ/Hs5KaWbfaype/nKs483/vF2TomEe8IYSoAaQoggPZ2iZHsnpqais3lbFiDcRgW5XrsD55c0ooC2DiQFeLVBP6y0/5Z1H9DqL7YpY3y98H+uQvKbPMvGV2dJ0BBzeH9ExTvWRIPfGMDkyhgPaCHqjqhcwm865oW8251Tt+Nn9gefRTxpEoyz1znj1y70mbHLhXCMboicc0lnV91XT75NT0ukniQlI6h4nN5qrW4CCbUsI5t4y3Kbn2fkEfdr8Xm8c/V1NV3stltkw1uzuqXgKX28xMVbn10aMS5Lzwp/JUFgxcuyIJZNbs6OmRhQtDMvIe48yOz/p0dOHykfoKWF/RCpHvvBg/ML3o264oscYi2UdMdsNu7+gcv+Xtis2eZQYxLXzlRGZjSfA0kcj1tOZ8Oz0+ImMkHb1ebByLHzkhT9+Yz3l9js21sp88TXrULN2kChqwf6/wEeswPj8qmzBEWkNLp4UZ7ekXaXFZ+RThFIlpKD49/JCUsWU/dWsnXL4mA3j8IXlacJsWlaurd5J1B5eZn6X4hBU5fPT3Xy5+bUou+6ePSQyNOs7f/oaIPaiIR51TSzk8uVZ5M2kDPhQNnhzNbW8oR1SAFO+txvBTKq2wWbTJekkyKW5IVyvJfCFbGr8jD+/udsR6wrXK293uONxWlGA4marRnR2mvkG48vpqOZ0soagB+bSUNefKNvbaYCS1cHxdl8gCX9S3dHGOSte2uAU4Nz9TtGXlXpoqHarPsmc9wP4w4rZHwNpBaW11rN2qHWzk1K4hnzOx4cykiroBbiFfwcyoH5JTlBnoG/F6G5UqU5vn3851tZk2DZ1RkR7WH+wQi63Fj3WddTtEEPuaQn3RSt3OaF2riM6R7cY91PBkv5d21Jd1YYhfmw49fljuas+bzQWJzIj2H149M9kSy9A+/2ZuzyNU6gffFPMdDj68fqiWU9Q2+Pm/G24eElUpFF+AUwY7t2yapqZowSGV/WEHyHuf04XS854l3dw8eKKDU4vnZmHfNXXSVS+bIQw3OqkYqKaFqL/sosbm5FBpky/SlLtyRoS+fCZLMxG9UZkXh99VXlwoElYnMPhu4fAhE6hxVcpyKhQL+2tSjXcFA+gzrBYDDICYUJWYYjvLnCJ1lnVjnBroVWW8PtZ/qI7DxdGN7n1+z4E9ctvsTGVyani/kh/EUMiP/OLOSJN0r3jnrmN5yWXrlyXiZvy23eUqfuZmTSDH11idbG6uEgxVRpVGe3tl8v/5N83//IQMUXdvYX2zsgGW6hJEhATyDNhcL9aTpIs9p0HMkeGSIczlFd7mchZ4RLSvQa5D8Z+bS6/nrYMDPOelqTX58FCwfOvM+vDeLd9UYjM20hLyKAo5sygTG3fFZ5VJ4ORJJDekygvwxuvm4OFcfYMcFCgluilL6QA0BgYf1NUouLQxbluiohdNTkodwqN1pQbBQeNgiEPBlnaZl9LEdMVNtU+ZPox8gEm0qgkPfBDmp4ixemH66WcD3kL6xDG55h6+Mdavt3ho9+Zl+aLlJ1hxcAsYAiY3sGMEn0I6qWUqGAa6xMACpLnfWzG7R6rBt1/8kjOVLP7r1+QUu/Rhg2Efjl2VwY/WrZw/XcDfCsTn84x8WLWYcqF445ZoUdYXwy6C5FKyiRmXFUoJdAaMc6CpY+XM6crDjzj6H27jsHlYnvkx3P8I/OrhXFHTzlFkv/jrfsfIgCgUAAkXy7clOxPoPyL65NxXpN1eb8avCPUSfQCwhnGPYY5z1b7sq1+P2/r+0AJzB3+9Oy7s5eIL85/OfNOxQ1XN9aw5/rhhNSN5qDDJVNbpiuamBcUb2725RD6j0YTEWm7jbr42GAx7ZE6vXDUrKfOkSi5QHfXunVumSZniuCq42hsuvF9AmAgT1OSitZw5fbuq3LyDfHSah3bJKRbDuKmEy6bMAzoON+/uGzQeRbxT5eo6K7luC2wf2kmsIGij3uiNUfPXk2bIIVewfdRrM+YZrwwtAClRMt5Kc9iAzylKG2o6gMrME2TgFLhcKPkHQERI1Wb9gV8/oMlzEPBCHmoaXdky6t73cp0hSRiDiUN6VkK2t0sms4pBM8Biv2VDWShLaXDq02gF+iyGlP8+FHBxIeFtTuZwv3ADVnW0KuMC82oGmv7BAfm+qLMYdSYo6lh/QkRAf0+FypYOFZE9qKCLaaurvPGueUrL6ugqZuW9KcE9AC3oyR6zTRWh6bvmIInrATKXRWqYpoa+5ExOMwioSwQ6wRWtT3FprAiPfUgxjXU75NBcFoFmFrb8DXKgMwL2Cd6r9YhmY40EZkqGbisGgsRazVYr4M1ulcLTm+73D++9x9sVneDrE3ckpRyrErgzbpoOBQNHOmkTrVsbX3nyMfkdHzEc8tO/FA6qxyR5e4Ev8g+1yDnY+tSUndeFl6601GRgxVYWf3X5Qwz7VrlfsJShssjJCCM+PKUyKAEM9pDGwu4m0qYDCJZeHSCc46iUuDg1BCB/QR5GCYAyns+bXlZC6hOJK/RFq0VZ0iwD05HUC38Gf5C7/KcecgkYEBqy1IcfvOIQ9wdwKCVVEMFD/gLNyLvtqivCgi7m0GEuXa4uO+TLRpUG9cKf/R9Ywdv61Pa0ebViYkpv6HTkkNmhW9owVxxmsGSWdMBZbwTx4hEACA8mtpDtelG+BVzdoaei+vc+/3DXR4BY8d7496UvFAim3oAWlVbOxzCjszDeQGu/KSZMVH9fmEu8djHymceruzVRrI+Qs7ronSE/eRcOAtUwAlYKwYdcLqvR9jfmPBQ0XYCa1KdeXDfryx7dSM4ER5BYzXPQi0mvZAI9TQN5UesW7ubZmcpXqZw9ybCIA0yS9zzydZGRJmcm7fFtFLAkxDATz4Stuw0WUGXbckDiUoi0aH0O3RGgj9CMJUJoAPdPTFXBgRGpq/6ev2d9uUhs6rXX5JbWvpWe9bM+chpwRAMdHdGG3OhrQhGojJdvmgGf/IwDGw86po6gHadS0iWre2Uy2XI2q7ukmpjX0bmvESXP45MBd5toa23JoYmFvf3rszdTGD92p3aXB26Qt0yP6nwPPlryMs6iMooEQo2z2xnTJmGAYoCcInEL1h+LiY+I0YCSYY42k4S/Pdu8rh6VJouLd66mud2qlUT5pqZkYyjgkX7THavWr5Na7YHA7MXljjq1W3I5uOqhB4XagoM9Jnlv9HalPgbDFK9ez5DHUxeUR+STIeYJF5C4i/KuSuXmTSZODknQGtoGHxKOuHavwEJWt0eYR2a9Unt4qIUvx58EA4KXFAsdNSqUGcRgyGeNN97b12zi1SwK59jtOmy/ZkHO/iObbnx7FGiz2wwFApGeWHFW0MntKvexgUadTpKrnoXeLgSXXX8QCnv6O63m68azwbvQgF8c529PW85dV4i4pauL4ADlYxpgnsYRDnqKhe9+O/fIcflwp9ucebt8/HMqA2trQ5FEwx2RpIw2zJStn2/fknnxhzfT8SKjB2Ank0LmzxdgXsC2vbmVhSKTBYCZ+NEsa4O5o+V//etVdMKWoeq6LyAMZGa6fO1seueBkq9e3tu4LzR9aqpbo0nY1hPfm+x/QCVllr3mQrUtlOmE8xtXW6xSF3KAsgAjgOTU9cKh7Krx+CN1LqqYcAZk6OlztjRLt8GlK2zCuyE1LTmcc5Twj9poCdTx8uvmAZHv+DIiYlxhFS/IAMbqyqO3cjU1E7QL+fKZNwvHf1EFGC5Sh1lbkh2fAdx4BD/LWsKUwxCFlvy14kHFZryTX9rI7z8uLwV1CquJkEaGF2ZMpVgETXDYA2R9xteKCSSZEgUPtOSG0sN+cWzzlVsVLkRNAvZCSCZVOd6qNIMmCuxpWC0uxz0tYjVSvfDUycLjz0jnwuE0SjI29l3VqqDlT/9mq63IHhkuxuanTr0su0MDM3mpHEBRU9rrq3KL9SsLhY5JZiAjDUBcozeKliPBfFjrqGVT5F6itjzfGq5sQJdMmCbVJdc1+xz3TVDdSXduFshAE7Et2FVh9lQJl/oHBDEwXJ9/QU6hJ0Hy9qUpnHi62pG/t2/kWZn41qvm+NPy9FifVQlofgz3NQJTl00CR6gSyK69BeMjXdWyFNbbpaqLCwM94pGMqZRfmzGvnZJli93b5AXukhD2O6dp1kTF7LJTCTIjzeAVNtw62JpypBxmQWhHYhbOVZNesw5t914qfyda5kTu5JIZ30Bnn64li95NL8xXavcHr1LpD4WnZIiE2GpJeO5RGsmzXlbtntP8q0Qlj79PgPt16aWdGj5iV0L1scgaEn5pvCXnEIzthbn2riUfS+mVMMmdtr6Pa8JI3h9W1bZJqPp4c0N0o2t6YdJjRnQ/OnRfAIKC0i3t7M6bV9g3ZStCwsvgdPYNPEZVkx96l6V5FSQ/9PsHHaCEqZogej8fLk6UDwDlYaKVkh89estWYhIz5FradKvC19dp4kUJDIqygi2hcQDlg6JD8/APHpjqK7mM53MlsMshDtyGDr9LFgqafCLvK8V7qHVNO1cJ1HrcfKrGNGsHqTTitN6XgHMacQNLF9DsGxw9ltXAJciIIT0HoNuhQnWEMVHIUW1kQWIoIOe83lBPU0ATZHhTeTOJUvLii3KmtbXMxTA6AA0EDhjVT4JFibzZAiTbwpYK26oT16inGBCvjsmreginxsF+Z6utQ7j1iPv7l3HmQ+1ojy+Zv37F/NunhDcCgYOhk/9p8RP/Sx9talsvv7HY20NTZBk4VtfmKkNloPHOGETqTK3LOcrjWgKHhWbmHQ4nJhxCWc5U5EUlaZrJLVTUo+ofEQa6RRX2/2/xkZYJO52plGznA1DNEel/XdELW+sbl8yvPCy/MzvWmuqSI4kI0WOLabR3l0U9sHxjjFKE7mpgkLFikC2e6H0/7R+wlK+zFQjhJ8hKmzwF5twYl6QroD8la5yY2WZ925118/nPk5Alc9szsDY3Wbiio8gh1MqAKGropT/rPzxceCKeF8pjbI0Dqxz8dFJ/hwWp/mq+p52Az8AQ8nqK7TxAPDuV5/V3S6ecxD9y/2Cx7n6vx0CqWRG7G388vqTV12/Enj0iNyPGyRGy/nY865cuVZf+PfRQ4LlPyOqzsPYqTubv1oZBpuKqjSxf4ytMYzfb4gTRJjDZ5HBvmwPTxxpvaBzomGgQWDwA6mQ2G9gh9IDsccRqQ5pE1RnPOLk5HW9m5R08a1lU9sF7ojIGiRMVA8mJ5ZToeMLcoQeeCsCgkTduxWZ2jEBH3Dhd3LdPTqFBotx090h77B2x1Mn6A7bthIZqurvjNj7Gy+mGzdarD2YLS1lPLrmRkifWN7nAenQ7gOE5RqQChMJcbpSqzVQ8t7YJ4VSkXayJyZU66Rhy1p7p7KzUNwfRti68IUO0d1fp8gVz4JOCwsGIc3G+yA1WEQ+EZGtjZDOAGseuGtadivWCRYdmaXV0bAQSOQMR6dvY5eyOo1G/U0j8P/1e/olHRYO3A8wg5JLFoGrYJGsPDGy6G2o6W6TrzmzaE873jMgT2M7LU8m7lI9LmZONDWoViMsFWF5ieN/4viDqic4cuTGd2xIuSvmKVk2akseuz66llFUqdf4s7J9dLCr0HI4PcwcYEBjW7dtgO3X2KwwvtdMAt7MomBfIWvX28pubTc3OGmXev/pnpa/9o4iJk2auNIXzEF3SVttob/N5vDJPMO70TCpfCPXXlOeF7Ti3DXpC3umr0I448BxeX1qrvQebwws3N8+cS33mv1LKm50RE6tPqTKTHj85PbA/YncjcDXWoVHNvgs/kQGEa7u1lPjCaK61pUwtu7SGqujLroNsW6vjQx5JIKDd4SZxc5JeqPEek1gv4qllJwoAI4rVO1/6pUp7LwyBxLbMd56v9KqQh/VDBzZ0g8MYXIXBga4A+EY8ZHRUuj0w4i95sDnzN14X42TH8abG/R1iPgHhcMuRbkM5MHSXc9lYU6G1iOtdhVdLq6O1JX5SbL6aXSHT02MXCMuir84WdzxuB5i3gIck03LZ+pRsQ0cpSiYRoNgMu/pCdgB8f3hAvgWQ1ETshs3NHCtn8ZWyAV6l+Pb3ROigMd69oyTNARSyvNKwo8mlCXYeEkFzecqBcoblJq1NPtNcrXqWTFTGr+f8bqHMnn5XJV8MxWSsWtsKqKze2lBLiwyKL0gsCj8GTRawySpBXgcwKcl0sZwvBzWi5XKVKESRUnMLWUViIRdAnsC2bblyJefhvYjhgb49uXtWZWEfudV7JUbeJmV947b5LIVX2ju4zIvyMn2bRD7sIgABCV07NN2auaMDFgHIrKBg/ZGjVWuZH5lBe4qJwli1kpvL2lrFH2QlO88kz/DRXfJkUA6+S+Fvi1woNNAyrwNgWbzI4gn4C1ViyYaVxHg4TMlWzajoxVZPHSOWKRmw5oX/LOP17N9ZUDVJnvYx3M8IEG1mmgD0SzZanPjOrb7ffEKOoYTpKdM6JG30itlLmLbSPHrEPP2Maeg1PpX1xQXZvkOT3RMLSZABaxwAm0BpJtRyyK4hPwVjHdYZ1NYuLB4uYDk4lJlK+4iqQU/5EgwqdPxh2t7NbD6eMdnVSGSCQ8JsY3HTeZemQeTBIAkHTSsDGN8KCsm5+wZEt36POaDe+lZS6PXeT8JssN+U82EFzY9n8xvVPPaVJfkoK2pQE9XB8z7vAxGhVx4I4J6HcaszwVBrti8ozGmOX2F3TebionlSiYJ8M/+KaEjClxVqsDK0AbMQkfPDINIX7qLXqCB9n1DbD96hXyM/QExYlcjRZT1tlbP3ruSxXXrA2G7il9HiN/wAC/UVzXeF85m/rzl+O9dkl14AbkFXdVpQseT5yj/k1AcBTJf+qKIhTAbuUcoW5hbkK99ipXpfztpR//Et87/+UnF5udLXrQiq3KQ4Nctlrmi4b1s6Tz1HVAgUtDWRxcSvgOHtstbOKj/wIniLjcPzTKQ5boFf+JLMhms+yUZbjQ3y0mym/PIL4uTFygJgQahY189J++a6mKb63TJiP2hu8fVcrj2T8eQ/VQZF/2YEECBWVWVCeYdw/J8UQAPEoUWMwzWmp0W+zupI+44U9zzN3qei4eB/7TzS4U5xrZm6nEWn6nek8OJx2FBHNZi2au4T/BSniGrFCAJ/Q7CxMXljWh4A+LbidXyCymf7c/WvNTT6cK0yfQ3yI/6I+FoJ6WOl1cKCdOy778gpxOu8Omdpw8mZaKRqmwhSs7Ju7pIOCrYxEQ4pVMMFMHyAl15mRwRpmikNgv0NFNUzP+Efeh7DIFG8RfQzRFbuUNMBZWFhTh7b7DWteTHz7Oe/XjD/Bj6n+lzU550amykVzLf1/aA9oA/T1s/6D/MuOp++AmKxLwIJt2/hIWe7FDkt4sFUoD4LDDO4ajEQPQXCzGkuK2ffu2br2h/3r33Cj7viB8+5h/rqHzjEL2S8mJX5yK3JahED1CvoT2jNmJPfFUKUlEJ0gR538qoUZsa9D1y7Ii4RlAXA4Ri7UWzUMc5sZPHiX71a2fVwk5yhrgIy31IAn8bH7dpj8jBtgHgIC+7nablwuaDTtQ3T9pWjrCs05062/9xBDiMP5qiZ4cvp8JLoE42uLJXgIMDO3U7q/ZOFLJehbyVNuEb48Pa9nlI6y6qMF16QUxgqqLBR3TS5UinDwqxoEz03GGw+XFs3LQQ7dSvPDzhyANSa+m1NDq8rsiAkmlrMJNIuim8CBDEu3zAHdkr77bfF3sPljEEI4GJHEPtq/NLuSIOydybkd8Jf9W2L0+PFJl2O4giG+3uS0+fFMIDMUKrOXdDMJZDAWYZfEDYAQHSkrc396+kVEwL+AE8EUNdQ091R+fLO7Sa3vOnTiNizn3VfP5NGD3v0CVicKdQ0+ChhTMYVsd0zm8SEChtpFwuZmRefK1JHdQOZ5kI66Qm4UmvCfYrrhfnpQu8+NDuQ0GTiUjVx94M6X+ihjY3hdHrqKmdM+0iNaWsKlWT6bp1LhnzF/gEZfF97S7Rl0+8u2CVeS7c3r1xG35UXxbpCgeXUl/+CptndY55glTG+JsIBxvRu97Euy6fLun51G7shOJzEhu3WXb09cKyJt2WO+h6n/rLbRluWZ3PtexspZjD2ivRh+34iGrmm3fKi5OxixJ/z1QlGLlxdrWtyBxy63zzHKLmlUuLsKE1M1tYeQkvu0DC0CbVR0nty5Z6wPbQdsWUIX+LzIDuuPtgVLRVmBAm/+lUKV+QO7Zfh6uzKpXLprn7h6dlkAWqATVt7EmXq7miK4l0AmhYYCL6xoQCHFJR+8hmT3JBzqNokuFp+itIMocDwrVbN7BOdV3w06/cK7YebMuPzLfUq4JLJ4EiXlD4EikXpvzL1bnedY2zsypssC5YXhWPz7U/Xhz77lFxGzZtatk24RtMF5qidN3hE9ML8wur0nVJLB4xUmCzxTzQn2yXyoaB+a3pT7h+hCz8AJt5Z6hsJII1JggdQTGPbG2MZ6awv6G7YwRa/IrnHxsxQb2F2otjaIQoYWwiHmoLOpLBrFvdvJJyNuURZ12tz5fEnPdQgkSeYzNsXzO698ibCYszFpbdytjrO4ED51Knq2jYIWXP9uEpILB5n/4Nyb5/0AYcF/cfdADAjsA0+BMsf8FLHCgm2JnTt8HgatsWscVMpSV1TSBgmAEhVNBKnrdGJI6ehsaFhyUb58HqgtViThr8lt9dVlK7yRsiZra4st2OA4Qy2D2yFBxeyMWdoDnJmlkk7BOgearedcSgVi4tgJLs8c+qhgZA7s7lyR+h3114X+aslfBAohfVi0pNdNmwXyHkEV+k8wH7HG8uF778i7ZEd8uFECWz60NV3s7vl54/hfkdg6JGWrtZeribb2BlfbC6zClBlAI405smqmpeep16b2XVEHurrNf6UmblVxaHzp+GiabVOWK/70kui4AJU82WiQYYvfEEOcRKRDy3OCwvMZTubsqnor1AmihoR05xxjd8y3V0mNiK3lCOe0oq58GLPc2KRfKZ/MbmeyOvafyw6vDx3ZkyqLI9DBgtz/OigXEZ0WRCxf+t2HoU5L4StchDTDpY1r8YAaiVb2UwK1xE76scA9KkUJk9GYKgCIXXM2mbN2yXzlKqqSNXdnmocBmLl+puw662HQmwiM1SnR50SSlZgyHi4cDF9BQ8XFURhfavx3r/2Ce1qQNon8ApkHv2x3/7elbbBw9/VVqxsrpfNbzTbqLxE3bn+YU4Lg5eQJ76Smzr4vWpuKb+UbDoRqB8G3PKGfgUXNq1IWIPtAy3rs+sgRCrhM0JBK5aQkNY2kO0jstk7l4THdvZ54EcLyvpw/3EXev/L35O79ux3BTIleDUAY7u7ZtpUeb85ZfYNi6kM6+BUOIxGYF4+I5exPg0TC4Ym+A431lzrMzekfbEkoRj9UDO+1ZATCtha1tzi89FuRczo1CDzuHibHjZrW5s/4R+ejDyTTiODNswDveb0GXPwgB4X8o17GqtubJ8/uIsau41yWWgjfmnywrtFLY9lio6NFrj2Zz8r97SyIoWamNdpRmIsK6xJpZLH9GnhW+bicnUGu3SNmf1wrgSRwMxluV+UeDBZFS7Z/nTXzgpuT8vnkSwIjmbta03Q9BNjEV4uy5/A9ndIAoK0EKyUHPObtay0Sw4zJX7M6pW3oPQtO4HpVcErl/1MwMu8U5VZVBJZHUPZ26zmiaDQbh+qEiyaKhuj9ikT4LJtraQWeaqKQrkCbkBu+k0/LkT8M+ktg9+hDwIrQWHttaxna/AaIgVAvdpj9AccA9DP+EBLiaAio8tgAjAWHemqs8C29cyH/1FC/PDLtq7w+13sewfLQ5m4Ubr2F7f311+WcwcOSFDVahZ3xuWwXwk0z/ayBXP12ti7ca4aOhBOjC/Zguwtu5vbt5f8QXgdIsfL8zruzTo0tUy0QHyDJPfIPYMmMmCCsBTlqfL509Rx50z53EUnqu3C63LZkUdkuHaMuM+f46g+tClVV6dkSNNXbgdDobYu14Wzcrhtu+C8jQUx2ZI/hYoKIt4pRILiSwZvgPY+LyvIJWJGZGlPcmpKbDMAHz/xYrfH6VbZtvRGHnyyeUFnzpr/5hAF9YK3vi8a9tBApTZcvDAmd6HWnHioWkqOL/PWh4K+Qhu7JzCpPofD7drQ2qizdyUQiFwGxI3icDQO1XprhaQcna21O/BQyi2k50Uic08/abVlYW1WzeVM23D0+tubsAKAeCHhXVRGEjYA9C2unCCJQbM4nM7i8j0+3vSMRCMB7MlylJLfwlLXNlYq7I5KuykqeU0uv4c+C/h8s9c28wURj2M3y488WvT55ZbUUq5zIOhvrZaZ99aHu+sDqMhyCwpCKp1ZS6PaAj3bSKJi3ywRIpO3i+i+n3hCBt8XhDvnvDVlJ74iuIN7k2VvzV1gu3E31Ebqok8/ukDbjzBEkKKAYKNAMx3OYkPQ1SBs+YnWoimn2UOp6ppiTjMZyiVxih0LPAf32Eybpg7P2mS8qa2x49m9nMLW+rf/28yT++Rje9t4mWdjWhC1rtXnb6k9+mx2Y0oOvX5nsDUaiNE0iZmVSLubVez7vwh5qpRzOG2+Fio+s+ZGm6CrYNjSkrtcdol5K/7jfL6ITgzcHpPNx4ZHZEwx1LFVqDbmqhP0okh3R0fqqcfkMqwULBZcA2fOCskfO0r2HfJSTqF249yA4QKYLqjdICeTC4CoHe3iRACotYhq4x3syl2a4DC3kvCRgmBdnejvkBy2Inw/upl1MzUYLMI6Zudy9RdvBnbpm/bsNiTlxuRNzocfktmsrYto2Llc3rz+SqGzS6YPtoSrlOQ3azMwrTADpD4AEtJPrF2goak8cXGz70hj/0FBgLvX1rf3u/0O6Ws5WwhDUBlBp/YHu4y30Jq5m6EAkNpyizcLxGxpk6tJhmkunpublZk9eowSjMXshrTPXynv3m1CfukP3UBi/U8Xi//7do5Mb49s4c0XA0wQVG8JFicFgVNMncSmnMOgY9zgAAAEy5By8eioHO5gcxAoc1Is5LlT4+37mqzRNnu3wmVISkwpAAWGF69943Xa9Ycpep3jRRY38K0gO+s0f4w8n1tjEpEGMKjoD2dtxi9oSwfEzEYH6hS5TxEcACcVghacspQIo0UfshU++FgQgJ43tctIxrpr49fSMCWAzOHb53KsZAPOXDTP1pjmtpJV31HymCAbzgxFiijcNjWhISZcHHXQOqdwLnwMH2kEvO0N3m2wEji719wsTp+c23H5ihwSLSWFJq06/My4YGRDv/yORGMib15dPD3JQctwfeH29Pmzgu34LMh1t8Y7eh4IDBcVuQCXXk0HUNKVfknKMd5h4x4wlkOJJj9u1oTkzcULkkQx+5q09z9MEVI2FvCpBR+txFt31m3cEpJ/6WVZQEgFqTuqO8BqrQIkd30UEHGiSiRshU4Ic9E1GzQuart4R4YBjnfuXTkGz0kqtIqvcIQPALg+HHBMz0I0SLNXtM3rHigZnD8jqmvgGdnnqeogkHbzdfOQ6rhcCw+GwpVViTca1VjpQ57CF3dtmVtILHi3PaUcVF/zA3+EEesFXKPkK5/JY+mhffgPXCtN+IUIJ73lIJwWP4uIGvFMDdahpUgbMoR4SZCblSN5FE9WXnW/s9DHVvVbow2ewHvDTSG3LtOAI8Efwrqn32ebS05XGVdU1bCH+BMJmA9w+VzhgQeqTAwBi0yBWT39SeHG5Fd/5a9kwRVQpiJu0dwSkWh2t8j1CJ3Ll+WQuwjFa01W8a7DPU5+3/z8Z+QUCiA43KYcsiUjMU++EVBc09bWH2V1cnBb8cenvzPCjAY+B32AmO60LYBX7ztNW+ff/1+dgWqgI6PVEZByZ8/Lxfv3V0KieCnWAABAAElEQVR0ly8BkAHILRxgvLEhlfGa/QfZgkfmeWOlELty04NsA3YyyVT9kt55H38YlQtjQ3VkLjOnlqu1H7joBzEEROIr4nK/4P8wGK64BXPG4mLb0t175NRLZ82zx6ocgJg3CGNDwTAPUGglaebuyGWRkhlnIZ40TU+F2Ka5uQzvkUMQg/fqxwk6WVqTEz8L4KPI2OpqlGe1bQ+7+7rzM0u0J84sozda0/QsWzioFf2AvnEYOzxefPHrog4++ylJiaSlqlg1GK5X/a38AYssWdHt01s2FZJ2olg1iS+qSQ/WWT7GcC0qHtIbeA44aXmUfch7Xfwbh+/9/r6Nj2huEQUnbQjo6UVP6f/kttz0LY58BEdI1BV1A9ProCwfGb0m7StXqN8SCyTbexhzrMvOQBGVEp6GOdIdQkez0sPnxXSoG4hR+JIzhdWkb//OKmdaWTWT86aHZVVKbhLnzdgFDY4otUhvX3t+mlt2Ls6gMMqAQOsAyIiLWOnhjdcqzRPL7U1lOIKAVtnFgwug0eLE/e4LMmLHjpXwKMA+rP+gxIKWtWQxL6dAHQJpzz0ntziIq0CQlUpaMxXJVd1xKOT0yTCmsYUISWSzG2vVKcBRhMIEoMr0dlUpqpXE31zum18tfmtFCPA3dzp6+ypXLkl7/37j3bP9wR6+0QSIYntyqYlE0K2EOFvOrKaCI/2cMq6aUGiucySaYeE/EqLW7yWc3NJK2+0q9X8i5vBIfyoUd0gXA/HFWEz4GEMicrYgVHjlvLCU2lrhPMX1RCZe6RgOLd4W3tUQK2c2qqQSbAii3q0t5Owy+t7+QqyBUB9XmXBzOJ9NlopygBK5vp678fX5/fvk0FUphSK6MRAHTIHP522qHTkI9sK1s5OvTmVXpQ8ofPTHU6f8HtZfKpGOGtdqPyNDTicbBpLSDiupyzl8vu3HhANSpFoQBu2ErZSApiY3a1B0HdfL/+HKc7/RJEmnSBsAUVAsBTtEb506t9LsGg3sHKDNbkjJ129uXJysZT9zwO359OH0i9+SZvsvSZ8iIRkTr4d11tmoJ12gxA8/b6ym5zYouEI70NNMma3+vd6Jl4XV9T3ajnVoVaIHnmlcm15u02VFPOrsq+mGWAVtHtixz5vbzOOUskCeBsmitNE8yEpFClYIFxNOHDW7tptDz8jHBkopdw1OqvSF83LlQB8ZdjZ8KOjkrw+6FOv6PJvnz0nONBoGAL9GUlrzG/KK3JoJtlRVZk9zvSg41m0AxS0vL37zLLe0jNR7HznsDwVv/8GrHPYcbPQWEqIsAt/9tilWzKBiXaWSevdGwJkbvyRTGcIbukDmicw4BIG1EOsM+nzyFbwhGAtuHxHuhG2N49yaeAQzmw91mja2Jl7mlKz0c+Y1IGgcHaxSilu0Cw21k+oUKpW8M2L6uPJpl9/hkbE34aHWmvkFNsuGcgGCYRRfie2W4dpVk3El191sYQ6RTixxwR/8RnBbrRBCfnkT1s9oAMzUwDZnPiPdplcMF3Sh5qTwG3Cb6BQQCcvv6CIP/UqvHGMWg6w9PTRjTZOJ8XsUmKGNE2djpYRTA0sPYFtkfDcRcoDxav/J9ba6LKbmaVi72tusntoxIu+Fn7D21RpODB19g/PYKWvoDbcWk7YNpjOV3xPbzTx1QpbuANYZFI15XOFAWTNQ/+mXzT8fEpPvd74swvS3/u48ycB2cRqrNXKpoo3kd7Wab33PfKpc+sYb8pxf+aQQIGYecO1aBb5nc5tRzvhq5D2YCcBNhQA+hvsfgYXFwl0RkZ59lIdu7ny03yxPy91Y0uwkgHkNoNvWbzPLo9K+drl4/Rq1V+o6RLFjyl2lykhFCMQ90tYfmL43KTQFoqKXk7xwEaVAarQUA8yT5cVxqo+9bgbXjFPYHRQjWqh17UDvk5MT3xS+0zc/bbr7TTlTuCIispzLf+fP1vfskBu+RqGzUdOWlRUmAPJGmOBHByEJtazoPWxPHReSq3MwYB5VNthZJ4wZnL+kxHiEEjjpqi74Y94GzYCnoqCx3y68tMP8trY3lmTl7+pmtcoLijHKAnYjwHDBv3b4TWtWDil4PJMx3TrAy0mxuPQqUYUVzeWTAb56E1rXtkzAj4BQr14DR0YtA7CmYK/2S/WH//KnWa04a5XxFvr/hwvmuJ5ny98gS4D1cfAZ4zChihnRUzBNuPDd//KYD2/xmCGXZU6iZqDhlDM5u4oq2MQSeb+t6/MHX0n92uf1aVYRhsLTaevZQTC9+WZ14U3/gPn+SUmQeeJJ6R8oRobL/6uo2uUwVDTzarepG41jCMfuwKA8Ey/Y1FTV/wvTA9lZMfE735BTvyybcJjfV/H0q42msFy1luXcB4BKdzFlAYYa4G5rM8AFmVk7Vgt66if4w5DrR4jhHbtsjj5AHVx5jBRRhBXaVBPoa2k5991X5Pf2WP0nH/CGfRNfeYPDzsOtrOKqcuST3zYkYVKBTWHhzAwqn407YLXObUVUQLlOZOtWFBecQSG25JpUs9yKyGJBeAPCy+7e8dgDMqTWUYiTE7PcFs7B38rv5Au71H7idQ1ukxZ5awbapFDnHBs2Kh4vl2UYlcolcjjxk5K2ftwP/elG7kNH28zeffK7u8j+ujkvpVr40sXVWV0XQ/t4j7kwIXaLEp8gxuZmZaBLCO6bX5NM4EYNNnK4wv9/y8B0ABuKTpYDQJWoMFAxgE5xBXczMQI9pIsMnUU/NB64sEN/t79o8yP/URl+33dV7kw68H8CWB2xWM0DQ+Ua7YPLKSlx/AVw58L58A0A6XSktGa6BrIXhIGEGhvdMVsSDqLxsUFD+hoIYIJHdmOBfOvPEru2CYkFg8WWZMLuXxu/erdmmL1IL586KaeOf6ZWGCpKAR+PArK6ujEjhLL25o2NV6b69kbHzjKYZugEKXosBKYpoYB4XOqM4Q0E6tqD2Eo2Y5AFD6iGyDCAgLt0POrMFSFGc/7dwtEjZTwKANrP8ePstiRfl17POTYLgRCWjGC604XLIeemRhLARuWoZXV1uz8nHMhd3Lj9mlj5AEpeTXdNKRCRg6AsP2tvLT8FDxaVsTJ2s9LTI+3a7S2kKkXWpmm7SjlWTEY7oqZeEdXr867Hq2lGDjb3Mmuz6dGb8oUPPpL2YB7oZi+rk5uFkrNlUF/ETDUETDnos+WwyhX3esqhnKBQSGEKoqMDy/NFSWtyOusGRSS6c5vRaJbhArbrxlyRBIUBhTsVMiU24LVj0rW9XCywYFMG6C/+vPTkE4iuzCrIq0jZ5C/Y+vX1jex86E8uZN44JRL86SeMv5SxleQeOOosOP1ObGYgm4VJoYDe1cp71GC8O1uxsSm3b+Ott51Ts/Klv/HfR4WTMcjWFwSPh5GrYnjoE1HhQADCHOD3yUn2XqR5GneRK9EVFQwkjlrX5KkUMtWlprl8V4tBwABT0xgMxdNvyZc+8tmIrCAqFj0ME+Aok9eekYeZwtp6y96Wmr6oOyOuAel0Q6xGy+76Ao4KES5re7lckxNlPg4WCZQdxUhzaMQpcmRxvuy4W+WnoXpvR8SZXsumdSV4O7WegsReBNVNpObOq/ecFfPgMTlCKmO3aLV/+VBfNlfUacUZ1tsjbjjLlG3GkfU5YANsLmaCIQdWCk9wUuYWIrVhi7ffIupUp7WxClMzHgyO9va2X3uKy4LJe5KtyNgCuM9BhQWdV7fHZ7IOp6N9O5LCuHKuffuSNkzkbYxG3Q5nqdixv0lOeV3pqaVSQUZy2w7XpXOlgnBX+YYQCJlOrY7C+U2ARIQaz/gVedHAiTrpm/0G7f3E2dW+AaE4gjOBzlovyzsZbKzr9Howmw11CRfKlT3uMKvuZd59deViW4ctOE2JftSIY/0sL5Un5J0uJ2HDmPA6dqUL1vvj4/LS1nann+odRQxCYaGN5RR8CyPEAiti8AVUFkSVYsFDY9ucTZD2H93rnprz3Vvm98XJDOFYPBfWR7N4r7xzuOiRIKx5/sXU5x431OG1rlLQgJll4xrA21wXaMjfuQwPNwN7QhGP+4grbq1gzDWCozaxhAYBrs+pKKCmKOm1GGDMDPDznyuSQ+qo89D+7Z8voBjAbg8MySmGw9vk8awLFZCWTKj8xGPye0+3iSdEeXrqqBxOTIhzzHqgQGHcRNbG41EMQmuXp6L2dv2ydPJjuP8RuHxqfddhZfrMX0ND5KDLzCij5xFQi83rahowDmq0q4jMJl1o310DnovIerS/A876+vpWZTsV4w7Mv/Gm/ExhNzSVv7ph9ulNiKoYqoqNb7JClRWcE5fPPy84eeDz/e+JSMnbW19f14h96p3LG6+NtW8L2d3ttg+bnUN5ngk81WguLIuKrypxNY1ETvxEsKrJdSiX9mkQqi9vtgnPkG2XwGE69UuflMNs3Jye/vAYDsSJRFRhZRDC7IuRUYUoyY6FZTNcU40G4y5BW7XRaRgJInmVnZflPeZQXpbHaLklSUuDNkSc4C5BG3aaKG4fIVlJi1pNmAYVIPwZ20qJvCMnBdCSAUgCYWZ1Mh7LrUiCH6UT2E3f1i2X1EKgvtmUPoFbOktmQjQXKZjip+iJWlkc7tUnaxfErrCMU2/6wD8XYSNUBVaUwdzCL0Tqip1ZfzpXSBQCPhG+j2JUaF2uKrdyuxN3li+ek8deuc7mmSJiABgg9hJ4anka+iZMVPUb8/WK+QVjviFXmSNBsbUw3Kybj1+43rpvsBxgXMiZXv1ApBVc5df65a7GnGlavl9j/gf1Wli8cHkFMMqOj4iEnwiYLPsEOngtbvZlzaefkwe5iT+SQkASBYDF2dPtGeiW9uy0l0Hp7W35DUGBYHpVVidbfYM0g8VxsyAjjC876MiIRiCalCgCD92uziADeEzDIzvljBj5kwy1trfpbsia5SM0zr2M5Ltn5RzDi3v89Rlpf1GTh3I6Cuw0xJV/8o5hBzAAR0zfVsEO/Nsl1kpRkrpJTm2WycCX0pfAlCK8PkwOf0rgE7f5ZVUeIwEsLxWGkjORR5gcEzq4vTM0PUTlUyO6AzyGi0Xkc7ggudV2cdw/u22e0ciS2vL3her6jB/6g2YDmQC85UM/LadXIjVHtjjAhqYI/pz+Dk+AhsA6VUmFJN8DURe2TK/3fvwJGqKC3D84WACE9Q+g7+IuLpXQY+QQWU2cyEbKsZREuVCR09Li5cdCMfKpR+QyqBB2OzcrbTz59xbZkFva3LK5efhAcRaWr0EnyexR/1wol8uNZny1gX6/cO/y6D0nVpYtgbCPvWTWBgdlWOanCguL8b6OfPvDStZUTKcmh7oCegZc507L/lc2LYfM0fp2/7FjgrbTU7IZTkePi/apkyX8CvcWyh39MibD2wWhLReGreAhXlsV0cRzKpXSezk2BGSmp4qHHxbe+wdfcX7pixuRQ9uig4rp01nifFZrQZ9zZdPuZh26ubmx68URtnHOCskzVDip7UoeBx7mDeq2iV6PWQHDevdk4qEvKJPP5YqJrMujTN7lQnCXisW0KvzUhY+Qf6omKMGZxGo2TR00qOv0Znuns2ag0WFVSLfLH/XG7wrK9eyJNvdwjQwCnnWgqy/paxUPzV/8UeEQqwAa5UcQjErEB/eU1aKheLj4Jm17/GqWHatbmmRMsAcIcGEcWl6AKXjqxey+PcKAUqvmr75eGOovD+m0uOqijXVaihvh5yWRzjNxTqa1vaU6tqQ+WujtqcD3ACrUdbWQySVzJFYF//E5atJMnIRlVfr21nDGn44vXivjUUtfEOIN1vkyC3GTlz5gdYKki9S0woSJOm7fFO3/UN0dDoligLkPP6J8j+3F0rmebsgNqzpl8ojxmJXeq7PZms6aikvouryZkHias0DkUK4Eq9xuX05NsWgDGwncvSVcpqu3jFsA/xY2D8BGVKTA2WAg0wonv6rKVXsHmyo6CMROTclllKwE6+ZG5Wm19anOfk9mrdTTK6fs2CK3AJSJ1GYJtg5YikTvskUdmCBwA5+TBYzYlh0+d0WFi+ggIVMLg9Joy9htH2XQ+KKhPqmAu21baLhTThVaZb0HfBRYW7t7YSU6JUNHZX+3z1XJsgmjDlFTY6+zYmv6hVml63SszWTrd6ucyeeS8ZK1H/gefHWs4AKee6BNSPL2WHxJkLAAk3C5WhulDxIzh8ZUGZ27uIQnr3mEoldinRbyqcTteJM66+LXVmqa/OHaQn4NQWlCe4fEEmK7R+GeZTcLPldk6DAeGAS2UHe55UUYfvW9fjcRePAkxGLEPPMCNDeX3aX8W6cKuhzV/Pmfm6eerurD//4l8zu/CX3kTn1HZplw4tRo5tCIznJ7hxsjPCTj0xBL02U4H5UhAaLTwrh0kn71F12lVGnXzuoDETNciVEEuMr0qmADUOwxDXZ6Z+MUzAC6erJn3jFzC9ImWxhMHz4ozP/eeBKzDc2mp0dOTU9WXnqn+PmnBQMGSDrdEAc/ISkA3d0R8EbUe9tG6mBUVrIBN67LpsyoYnA5gAaEbF0TZGRD74wYwBt5GszF8gxrH8qJj+H+RqCzDXeX8n8YMs4XxLcdSg5BFEu0RRApaXyqLrJtBtOQTjueUROECcahZWNT587F51PwNACGhBFOeGEWa0Y5ABKikBT09iBS4SaNjf3hOTl3h/pxHtk6AAAjV1a37ZT25C38d7laV7L7kHTPnV0SAScXGQronFsWjFFSlFwauK1t6/mP9gcyo1szW3k4aDBjJdOi3R6T1ZISoR3ulWfiO8DY2CG8X5Ste/Lv+wMP7NMzcJrZFXNF+VlSQwfTSTOkWgycnPG2Ogi0Bm2wX60IQph0SRzY1uvIx0+qQcjv0NzjZbM3u2Vp4I11m7f14Qc1HMErAGaRCYP16rxWy+JZzYmPnYaY9bK/8Ye7oDx7akjLITCk9oERzYfERgIWWWuN0aX/cQhODGgPaU/x/30AOgGl/q24hIpBN5i3zbG4cqUI2pCSClAHnK1akbATF0VvCEeTrGS2y0SZe1LLbVogt89QrNhRXayOX53dPnbz8YxnSgxLFWiit4DLuGZs3jL8jXX0NlZmDTBEdIK5R4Y0S98wtABEUN1PgVo8AYxV4pGn/cTAROjYmwv4lG2v6BZA/zAWg+3SPnyU2r5Om74/NCRux5GdweFuOWV6ZJGL5eZra4mb8y6vfGow6MCVAP+06hOC71DBvDklNzCtDRrA0ZpoWmZ2S60HhfaRo85XoUp1yZCSe2VzMcBnvF6dypkxZVE7GXbgrXdMQ705PiiZ/gATcWvc7NohbWiKtXNkqs+Afzx5WJTlFWmKwaPyRw9+6j+wCPbKxbM5rj1/7og59VLuuf3av7a24Mpqfb0oQjAucBtiUQlpWuMyPjYI8fe7zcwdGZld2plrW9TxkboGiSkvqS6sup97QSEI2Wq43L5tayLgknwKHAMCBMCQH8OR7udFP3qNZRo/+vsH/IKiChIBa6v/+n+88c/+SW3VE4BKKzEC5d4ZLKWtfchZs/LA46ay6bXaIsR98yb38oCJ00tEGPpOdMnTQNz29haPJ9SV5sgPz8OTr+5Vd2vUGSI5ydf2ACNjHGzGDi7blJoYCOxqaBAeGLo109bVb6LFkC3JXPJL4OvSFKdqm8IjxyV1StUtM3Yh1d5aGdARRePxBl1TE0J6ex+PBfxZdy3LSKQPID2MG6UEAD/gQei1QE1H+M3vJvE12iKnpNdjNp56WZjqDvZFKeeWXrvJRqVyaTarm1yJupZJVxxu3/Lledq5jRy5DbdHy3bxBvRJiOjGVblsT8NKeWNTZLQOCeK4JZY/+adyF2lpu4eLhTXB5oV7jpqQFDTjXgEES6Fgt7ygTPDEHbBZnsZfD2srxwoBXSDHXe2dJGXJqcU7aTZu3tTpwpvS2h9MrKeTuEuxM4dKME0pzQ/E492teTzi1tEF3aLNI9yB73yn/Bv/OOppEF2wO7hMyYfWXr9VLKgdv2uPM6xPKKXzxx8uo3lX2cd0+k+/4zjQIQN+4gkXOnqLxgzv3skz1EyKDQWQWgizXlFRCSuBOM+ellvWN1b3HsLtlkwsyhxlN0o9gypeQABPAYdeKu7wNzAcUHma6GbHk8M0m47kAq58WbMrNseXEAwYIXX1CU7VN2Vr2kNe3aMkPXqXBWm2A4V4xoOTk5nQIY4canNTVS8t2r/kvLnd5cm7G2vSpVrUB4w5tRMYLmriJ1C44dulMjZPR7+XDX85fOcd6KaoRqLZc8T/7D/p9BblaY7KUoGIIfk2R4Wn+hoDlUSSrDza7pDPXRfOnJ60s+yJBtlZ5ewp+fA9e42/Mfp//q7wuf/2S0I9KGyPPi5T5nOVeIv1uzFfDN2Vt5O7H1KEBM9Ik3DLmJj2YRM5bda/Q9OJTfB6XEq42NR71kxSdqlnv1yWTTTG8+7rl6QdCW9cyWM+1WqgiTqNnvrY2gvnOBPmlezOXJ9J3RGpw7K9+uGmb/7BEu0nnqig5Vh6NYnk6uvXY/WV1t3C65zEGIvp0Ihyy0I+PXHPH5C5q48W8VKH0yuSj4IMe2zAlym8+vtXaD/8xU7jqaRn4kEtHyJpEz7v2HWhPkys86+tsWEvbcaHisvXX1jq6ORIVmdllpMXzkt79x6MkdL2EUH9TKZcJmU0WFmYlVOI1FdfEQwHvvSIOJSW54rDOlq9nz9QIDTdrOcY6527zNQUl22MXn7jDbGoCaEDcInv/PFii4rH/TsqJHlh0ljUwBgmjwxkAXLLUsXJ5jM7p9frGxxYnjaZZGGuvHuP2fdsG5c1h1OOTNq9fZB2zHk3urjaNhSavCrYBQ9+7guNMa2A4kyso/H09lbtpdHr5R2HnO5B6VBTZ9ER9JcjqJrm2JH8vuVEdP2uR9MLGih0JYMm8rec5+NAP5kvKuOHdzQ7KFnJHPDe3gB/P4b7HwGxWnHTAPPzv/d/LP/DfxgWKwuAq3aPkIwubfTWUt4sihw0Q3tN93FTXHH4hbTF90a+oG5UcumV9ZujFZt+yBkw8+A29mKQq0iWw2vgwvgAkIPCsqO1x/ThMChcop1oEdqTjnJY8zp63rxU7h/0uXLuidtyaslfqWQnJ6WJJfhMn7k1US1Bgd4jrO2nA7RrFSHiKn4R1q1CbafueI4ssHo5eEt4Sonq/S2WH+zChB7EEMoVydEC0F3wFy7mzT+9JYfHneZATVX7p4Ybb7+85fmm8mgIjUBIR27hUSrYRVGjn5MZE1GhgaCFMdXLVWZBrQIrYBlKhP89dFk9hX4M2K9bU6WHWzj7N4ALjkLF4AMjXBDzdURlNYdo+YNbgS9YwnZ9yE29n0+7A2vStleVvw+diy5WZkK5dAX+PyYOSYSmjfIhwXp6qiYopgQTzeC3a/bERka2FUGBAQiWciWheOD2mLlBkUt0X2WYnV5ZMk1FcmAqZV7fUkZnF8R5jsVuGRdtSjGnE3yllH6FR2LvLylGM8uojfBGgIovzBrICyhGaOv9/thv/9EzjMaHDsiP3vWjvwh309m/S6+2KpiLNcOiDOcOOde02wTfrY7j/n2ygAUmjqILENHq7TF1iBk0gM3AJzOZv/6utNvaF64l8dFbm5+RZ3BuTckZxqU9ZNwsD9bek1X7mNe8pEjDDyGIWGS+qJq4YqF0KzExlRET8HYAvevWLSV8RkC3+mBI2/vlFLFtJP6XRZibX3xQJA43UpACQAdAmwKZAf6C/D8roM8302bEZQ6oLr33i8PZIGxHFEJxGG3f3pMWQpmeWoLHIJWH9MUsoPnj100nSIBO66H+ljm/WS1NIZrEfQMkA/A5jI3OlqyTnNmyaX/8Y6Lqu9nbIVcF3BIGDCtGHs+YySUzTi6o3g9Rw5pE4YaX/4ywTr9bn3hffywecanPd6Jnw2T8VsgXX3/H3d4uZYYB0ptwpwzvkXaI1f2sAx4vvPoWRx4WEKRT8ZuLtKdvF9H9bHbcxNm1vse7aQc0ScxRN4DVPHFDcKM+lpuaTbe0mRa71TOMhBTAjkc4hQJIbXLXPmGJYY/LNMWEyu26ZFYUNjSEqIINrCxEUeM6omWNVVXK61MTNjoi5dRIZmvpFx4RbCKXyeNeWRm9KV+BFx6XDEuBAJzmGAzWIr83ld33TKu3xXuksMKpU99J4UC0UXjoFK/5/FwqyT588JQo9ejLVnuDihtKhaW78iJ0SLSujrYKK6M4LCfThIyjjUoc5dLaYt66mTEFeTtUNNCJRJAG64qMT25pdMRdRQk687kA5lAhVxnHhaiAcIfhAni1MZOmpvJkaQGoxGFPtUz65mZxcLA6CHDhGn+uHAm62FEa7tFvTp6kEqRwhVy2hJkMuVpvDWRMbhLKJfDsM+yp1V4NdXpc//lfzTz8aMEWb8Q8iNUW7045uKyzXYaOVXnFougWrCR57pgJ++QJ58+U6hqTnbq3Mk8+e0P00SgkCG/KlfLZsrXx6Dblto8ela8DmzJrGQRDm9Ira8/87mLhnkgJghsEFTKZSqisg+JyuXo6XbqtsJhGiVI4KNPKizComErpHAgUMVLdWw0amFe+UFWOXR0tMutTU3Zq3/hW+vFfc1THi5mIRByNsRavzMvinY0WXANW5oAH8U27mHV5yTS1UWTE+Y2vyouQZ0QRGXPA2Rhri7hS1wR/zl8pwjrffdf8vV8XVHP4vQ5PjXdDTMGN2Wx90FPbFjyvG3yurOcee6zq65DSGmHfpx7lKukgi4KYdCd4oO45tDWr/fNZ4FIkWqhsbMqliaRDMEO6bZxsO7/PnFB5eOo12Rbv9OnCNFzFSFkRKMUnTzO+hsAhFoppe2kptLNHEJEV/wCS1uWytR8KqbwnHN5YXggHFAm7d/jK5YceE5XG5yvAM3A8AxtTG3dGS7EnawKkyAOsXVhNimMFuLfmcxcdfvk9QImPUI2DfWo0kO5uaaTiyK7PCN9zt9fx0kA671qSrqZm1t0Bd7uudfR7SsMDsmE34MBujIS2HYt5E4J1+G1mJ4t29Rc7C4EHlioXKVg/VvnEJ2yJEJkjtEBRZFGS2l3zd0tU5DlwQA5DhJDIOV5ZloMrVyXJQ6cZEUjoG4lILS+gpreuYSlT2BS1Lr5ONij7e1cL0CMyWVRocePcOanIZGHyZj5L1qLX7N4lP4DtWKftA0qxnrDoKT5p+5ujXpNzRsI9CXk4aNy3M2L7XSlSLpz0Zme16KiTPbNBa6EjN3QbCroIGyKHalImivel1TpInUTRydIMCadysme3N+gnt1OQs07q9eeDNlHNY7U2TnwM9zcCAfQmWCrgdAxG4lL9BZkFXLhgegdgbdI+e06CjHWKND7K9ifMYty8+H05hQebakU3RBE7/U4FfLaOKuKpZLeiF1o9DMZFmRavV17U5F+mElVHlyM4pBoEyIGbwfegPA1jx5c0g4IMYfgpDDqbrbwl8je5IRvTwfEAOCq2Xj2hVCV0+OmG/FwFFCj9nvfJl9u65G/+C3Z3qTLEiTFceIgVlaTw47PzZpVSOrNyS7hk/lKDSLStiiO/vh+AmhH9PVGRhB/ttdhF8BX6tk1oQjTaUFvVBZkvmZzbDMSrMTqfasComwCMA2dGq7bb1Z9NqR2rufDVcGhr6jBndFt7LSoXIovBVbKUrMvprcuYTjpAf+wD6QisVjQSjQINhwySBJi/Z/5d0hxnHORITFA0uTltczFP6NwKuPFjA95sPcVfnRA9+OA/fE4PEXiGA32pTqwdsoVwPwEYVHACG26Cc/t8onBZ7gdqoWPgVgZu3pI8wGVhlmaDzVZAXvqsmmYNMXlYj6Itv9O9EbnK1AqeSm6YdSb836fNv/i5MqEMwL4IOXtAL52bFjZm1Sd0EoxefbBc+WPAjvyPueCnPPXewDLpaJ3W+dXRmXcKtVr8opTzfnNMReTNs5LhgEdyAfTRynBoEARPgVC9e/eO4OqytGem4Li9PVWKhw3wHysjgMmkGagx76bMfkUOVB3GZFGoXMxOhu2evgfZQrrMkQeqGhdzBMlbpRsOgF5gdTlmDR8LSoedSiIBaC+fOyFP69Ytzph3qz6NrYh9q1JR8GpcLvnZAMj57ZLZ5zX9EAa+gx2dUYbIBlXPnSNaGox6+P118p/rzLfWTa++toPkEmqTK6at4wSpCDIs6amPNONRvQWig7ygTYCv6/4wegnplT1q8Ku4E+zFG2sztqKbxrFm4Md3lBlByHApnb37IkN99of8YS4+ClhPO3eEI/s/1Y0Ml2JJTCe+IxYKWM0JihcxD7/l61fMV/8cZYTiDnKYTKTG5h0omOpEgQLLqpo0UzkHPXUz5bKJL/NzRFv9mBQg8+7tvY92+Fvrqq5llgg1UWOySZ4mK12rG+DIWgSoH0mDJgTgtWtt9VjVKbmOCkPehWdbH2dqPJ5bt5asegwbamr1uHTV09rtPK6F5rrq1r2kwHpqQq3E2dDecjm2ErZhZXYxCexoYWFYs6pOu2dT3z1pfusfy6S4I8HA+hIfldV9YFvwqaerC9DFtVMmK4x/WJQpe9g9+CCCATZr7twWI+3ELrGj2KeV4bQkhI5EnAplzhIYohUh6lRBHogEN69MDwyaUkDee+NMEj3eBp1QtT/1KZtEaVyRkHMlxXgwKgCNUEvU7QKLRK0M7+gMOIQeSsmMI+hye9yhOtG9KoXC4WPrs9PCSuDUeK1gtbZLzCp4aRWwo494hK1aw66+fv9+dpYtXb3ETXJxLlOpjcrXOcKhSFezw++sb4KtmZI/5G2JVTRMlHxj8faNIuVNAexGioAw/ve0AF1jYyVY5/XVyHCVKk5fJdM2qPgTrfnjfzn/xV8Pupl5eVHB4XXLZsTyojB14D1rG3dvyItgP1272FBDyPrb/1+K8bGmTqTW2dZa9veaYL/IRw/r6Ogm1jD+znUJYOIWAthVgB//6PfzX/wCzNfs2RkAz21Rx5Wlys69Gy5nxd8lSFjHdK5vvvptYZYPPez0ecsW6Yg97iiXozV5tHQAwUbZPyu0hLsnkuPXZLR9HkNCEOMcx2dLf/xxasSNHJYvCmfXGRFvQ7S1VR6ObUlk1yZbutjoLJe3a8kQk/3bXB5HCT2Ky5ggNHvrPAbr4NG4ttkq2p4KcHUZdYX4/RPipow9Ju2HKMx8m23uXAmEqQydJP9ZOqImPWaKhvw2vn+hdkeb6WpDj+Sqt3/v/LFHXNTYpF0m/pxIRHe0ech9B3jl8opDMRLPArshlzQP09/esI290Sub1skCysKcYxGROenVjJT0sEnzt8eoAyFfYtUE+tzRYbPhy9dHnYcOuFnOpYzIF/ZlF+LhFunD+OUUKZCWChjopUsLTcOxCqmDaHIzcUxRO3QIKuJRVHYCeAMOl0SyOlys9GDo7DvJ/kViBdh9eFiFCTeTYdKiyMoMobPo+DQf62tMZ1nPSa4pD3T73cG2QnFd0IlrMFrZOe2ESkEeO7jduTArZIVAR4haqiR6RjcmJquH0A7cQHaa4zIYaaVSvHyDtjtWM3Uz27fTZRkwlAd+rk0IqucSRXwitdQBwMrChXl1PtKUmrspeNy+PYprwPojPLHIjVPLOw4GXvpLObVvZwF5DOIBXn+B/MzZKenbUG2hcmeiUq7YfbcHu/JChB/DfY9APpFzq9OQnNKHHg8Knti8PtaCElaKqPjGR44I86mIRNl4/k/M0YNVzRcpNnOX/bJ4IfwWdmQjomALe7iRf2AzEMkdhSKqRvvISPtDnb62GPWLtJuYWINYYdpGFUEsahNHN+zA7XGokF27vQ4t2GA+0pAX3StXww49W2EcbgOt6z9i5Qbu+v/Ze+8oSbPrsO9VzqGrOufcPT09eWd3Z2YzZiPCIoMgAEsCDknRpOSgI0s6lo8ty7Ys80jH0jm0GExKYDBBEgSIsHmBDdidtJOnJ/V0zqm6urqrunKVf/d+NRR5zAVmKezRH8Y9s73vqy+9772b7333YZZgyRT0tRAnjGmv8u9YyMysyKFVNo3vh7qu62Xywe8PoKalYI3rYy2zB15zB+4FIeuNw2xo2SxJcQAjQ/kHNkHWyK65OWGillKmt8CShVQ0loWmC3MU1FdbqAvC1TbPHGXPeuVn7DrBlObTsk81wMVJNato0+1uVWcZJYBPhoeiiQIYVBCmNUfNDebRtLx0Rk+h/nKlDomM1QEHS7Vr2U38GL2rgL6tF1sKH8qQCIy/DrgeHjraLeeQPvA3ynpZdZ0RBLAXSySBTijubIpIkARgxr/0pRq7+8PzZjZnhnmH2oporvSqT1/MLhuIx1U+WC1n5k5dZ+LknZkxizVObB7rIB+8aq0svbRiqIiEi431okBmW9rfW5P2IOvu7gY6rsgP7wvWjLzv6Z/eCUYPTmill+9JVOsRN57X5PHtT8ravehJaQ8HTOqWaDbWQhio8fQp86TwfBYQo/k4ukBks/LqZTb+AQmtrKj/42XzRH3N9OqNiZLzkV7TE5eboDusYmHfikiME/EugLx+ODyqpaVlIc7YqaEKSoESu4ZNJUmzB67Mi+OVmbV8MUwQCka94hNojycHdLWcPM1BMR7AcODHk5he8gH+wFR4Ib0dOajkSApjqN14LKSZkOUJqph9+RMmwXqtiyakNl9DSMIARAqB8QVBBgbh5gd4be3SZf1/t95uESz0zaN+DNrQSx1jIT2uhBEB+FnwTVjzhafr30+boyyQ1ocjxRkxi5b1h5/CH1tVNfh7fdJLD9b4B75tBMON6xQ64l58ohLRtFwlQw9KNf7XXpZnLs0wIdmFTZ+V8zo5VbK7bU0NnDn9W9f2Hw+GnAy4sZG8FA5Xb9ycmxNm2fVwOzW8in5hsC62H8b0cUp5CQ5Ze4Ej3NgYWxSOzBv/yxt1UVFGD44UpN55pVph53b6k8+ubPuae4RZJia24k3OhTvZXZuw5cHDwaVLa7EWQRFbLOapZCssIYdqsuKH5psuXOBIKne393mswms+PP3ENjQ26g04fu9PvAcP2Q4M57ms5PIvurq66qUP2VuzbLqKQ6K7T77CN9CxO73qrki3K7F4cSXBwwEWteVDccgmsyA8jOQf0jDj7dLV5clsaH+PLOdAEXeWqIaH+8jXLgRq28YWbKrVUEtsQIfOBmWlaJMlf8BdyielD6m0HWPdVZG+wQ53V3cQsl0DLnlCteJqbbzxA0HU4cP+G9cxG5QCAgEKQt6ZsPX1CK46vY5XvrWrBgilYI2vtQ5zwhGVLmUWU7AM2DTAHpt7DrhvTIqvZuTR+lKuUl5f38UzBqd2sy1bzinvNIGeJjjE5pV5Fp5xaHM52PlnJymE7w550v7GcFBeWpxbun4+N/xwg1VmACccdlRNs2DUMFsJaQIu13wy0NFhs9RqdhGhzGVNUSX3SVw6u9iOcmVjo89deu9f/Yhm1JtrHgyzhpV2PlP8+u+bX/yacfSqKMAwWFranReaqhaK3niASne0EytFfMnzyWBbWFTna1cqkjWBM1Z1dLST737H/PyvKvE2NlbTmasvLHBq3xMN9lJ+7poMECmmhD3r6u1r5OajKxCIDQUqmmcYjLkJLPyLfwfVm//u74jw4+EHj8lIuhwS06OoBu3J80mP19ba5drVbdtZnQVqXb7MGbP/iCsWrWyHWmljGOQmFuuiVYs+QFSsVofqHPEmqjuWoW9sV6501MfETqNbwNBx+VvjP5Tj3DaZGTP1hvw2M83wrk3Khzd+4TH+Vl55nb+IaldDRIpnaLxlc2a7bmPC1i59EMUwkSgtrTvVq0JJSb+rOH9LdBPCoc88Y+y93XJZT7cUsMGRaC3xD4UL86vuqiBGmZ2GibFA6QBTuZmcvbnb2ijo5OrrFLOAYCNzFAjaHI7Fb7yd2JQvpNZFdrvY3iVo/OL3ykSimh7soW0PePMLGxtTbHous4m1SdTU2dokp3KZtVtJyypr2tvgKGWLKXZRlznCYwNd5GPNtL3l3d1NOEM6eKifQxGhhFaP3ift5Tnz0su1qhe4G+bnp66lex9TdEKS7OwkLgsyxAcwcxOXzxX3nmzhcLfotC/Ok+luAQk2zCaAuEKIY+GC8wA/ggyWhh2IODeTJhaSQYg0uMfHCsmUYxiFhS/axFPAxk5yChseEjn2uIdhA6Zu5gcPeHNbMqpev2Mt4ViaFUybWXCFvMWWdkdE0ZhpfPGF2qIOEcz8k6Fi73ksuxJ5QSwO5BBl0fY/6Qk5+TP4ySNQ/t+DjrjqRBBepbp2JxV0y/jLqo+DB2oOhcgDxu0w116Vx81OSM0MPHBW1iBYmEgU44KEV/9oDIPf8rujuqDj4TXeYaaM+Xu/EvA+cNDRIdRn6+w2PpZsgkCWWhU0Oxumoui1m539jT/3+YQSG92bEt0qFG6eEnaXWC6OsX3fPprm9TOGkjEXF2X7JgBRNKneYtrgLg+VD1C9ELU+pe0f/wdVDH7doReNwGz6jE+kk5ndNLepQauv4LCftR9FyU8DoPwZRLq2/79/6IYKALGFPgLbUs3SVjQLVDbl+aIpiMWCe10j4uIPgab+InqDe58taeboPX3Ay4DnS/uztmAwpdZxhynD3MUpEzCXZLTMwaCh0nBPg7TRa9BrX98yHqEJuf6Samy0B/QffYjKGYl6MXQqfeWXJ9EKtKtPtlFASGrVWKVnKKhI/vCyThd9D9jMpbuFvBkB5Mq0Pg00alPLh6M1PFwacENTBJb1r0w/C34oXNFlPs7/LBM91tXU5hKKVlbqsFWcbFUKpHdK6yl4CxwGqETqWgOp//C7cjC5ZnbLtVDnhE7EERKu+Cr65jCUr7qtPICv49Osl7Y6zcM+U4+OLZqLFsmwSaAAsLNBo8v811fMvz0kh/gF0Bl+7x1pP9gqu5u8rCN85i5eyYn/TIBaw7A9Ha6lJzz0Ebe7o9k8+6x0p+URPuXuxEYNy7PTk2b1TTk1O4PxlJ1lTozv+adFNL7yMm3y4RG+CGLQD7i5aLbmau5y0BKmjRXEaABIeVQp1tMALxrzVVaKKSUinLGNsfgsLYv2jXGzNC+XgcN4Pi0xgTLFopAxu3lE0W7/AfEMWto37n4YBWuJ31MUQWmlapJ2R7aAszBTH/ef+uej0EjEHOkyn/oytAsRDpmewVrwfXnefPe7YseA/2vp8XHz+y/UsmqxMyFM1nACeECWU+Y335/q5aL3AdUuhVMxQ8rpxJcxpxcrdv81t3Glddf9SkeNegnYC0NbVPpYIw6cq62y4yS0Ds5a5MYz3++xXHnvNpSS1F/Tt/f7qbr20gXONT4xik62s5S2FBd/IeEhi3OPklegxeQmjC5NKU3OLiYD7Yfq1390m7saHtnjxE+sisbhp1Z8uWRWU1m9K+t2r9fW2dEQVHxA1fX5XBnGATrOTX3zYu9Hhy1tQFDp8iXzwINyamur13l7UR5s1uyuRlRnlO282jROR12Tp6aUF4oXTpW9btQaZbG2cGOHu5ARTcWfT33j6wVr40jKqb/6J7mHHzbd3fLAxSVygQqvvCRs5vN/tw69wz65QLuQrjx2uEgO1eayjH9spK7rcJuQDmwxm+/OzDo8Diupo7K8FuiKW7vuVrI7GImQBMAynpPETEJBz6pQAUQ4yPLfO6IeQcUnHnWZJqWhlWV/vY+MxYtvCdYeOQK22KxYbWZ6PYBGvuO03FYRqr3t7DjLouUHGkOSg2hFxHp7Pe3l9r1ltzJEIfFAsL1dqNAeDXc9Xm+8OtosclvJ3bxo+ts4g98vgsufBS40A62+xTvptvvarPQYb7boLeSDmvf47uu5psZ8R4eHyyqzC87OdueePg98Qp4QpjqbDe8NBHAl2XnUHXIXSrrYJp0uVXZKWqABpd3t6YsUr9ziMp+jOHLYGwjbVsaTHDKTmV1blBkEUEjhUurGWZvOdDx3nzh2NGZtIxS4nrG2BPWH2C0yzrpwH55jAF/KZmpgnzwhWMo528Jjr8ow7jngfe5zzmqV+iSKXU5nfmlzYVqmDyEUL+RZWUTbViqTddYQS1vbYfUM51LLijwap6JLIyO5zJIOeF2MWp1Dj4kcps4iarXFEGE+oKqzoyXulRc5K6XNtTwGBbAwWfjnL5lfeVrawQZvXynHLR4NE5XWkkL/C9JVcGpnp+r1FJaX5UqSQ0JtwX1V6Qb2QzzmiLTBYXA27mQrVbvT7o3LNFMQkowOshOBT366Eh5qYUuDjXHBtOZg2tg18iwnIZ+pmtNy6IQJdJjAIRNWBG26YF58KRJWcc2wu1y2giBnIVl0BVyVxRW7evICW0skfK68t86prkd8uOOuncsfekDGwWNzrs/uNo3IRPjbKjMzyV6KBAIkLVFlhHGxSs309brxs6hlTyV88YdhhQDKIhq6fA6ENkAVDZTNYoCmbX2DEKTTXu3ukTOeiLucK753Rl7Keq1Yb4RxkBOlkjuXAh3yaZlZsPJQQ8lu6Rz5LLabFbpjnVJxIZlMVCzrD3Elm1RQ4RfweTNriXiksn5BePhOeqH3qX6D4QdgHrW2rr9+mWY46vD0tjXv89cCl2urVFuRxWqA3U4xFb7VpZtHR7IJikRxq54RHRrBA8A/MWkw96BOgOvbBvzBZhkuypBcOS/hZaA1W7h1C1FdRlYBGPwej+yJB+Aewtq9fLbQ0iyoC7kklgo6Y6bBUZ64UbZyUcAnZwgtsxxslruIhJFxin8UsBwals+7s7PEkrrF5cqbikJf+kRtfyG57mdwDyPgqBTe/qYQxSOfiKDAJhayDp1oP/yQiEPdfnmGE8t/2jhUVC3PZG9kfcPd698/y5mGZ47g6rMSX/dMzMzdSFteauJSbe2yaVVZESDYFjVwky0xnAQufUcCtbioAPT6905R/0fayWRD7saYTuVG2DZytIrbq0BFP0jJZno0NZg2Wy5PrxtUIEUocVrTP6VYkbrX0ZK5SCNdQgz3ALyAG6/olY/bzZBWBueIWtW6waTpVE6zkRclqU8vQ60BMVUgSU+4/S/rN5Ax3QBAWPoWF+kktd1b1A5ZUJLtY1eiivAYgOGCcPC/WXF+1FZYS1kvayaFedtE9VMblUsXyfdUkl2nfozbxKfkCaTBR+NsXShtnN/rVAUu1yJsMY34qZgR6uAS6xO4kn4yqTpFskCL6bHqYYzNmyeOmE5NB+UyWBDjTwkK4PdS5hNVGXmMKwA2wOipBiCGTS8Kg/6Olv6A6ouremj9UQEgBmdU9+vjxx/8yPzdf85Cc12xAIdcWmRt8Pi4cMigt0xSJeNg6eUdofR2srbYwbMgJv+YMEsJ3PHAC8gHQRPTXDJ087w0a6mV1ktJQ5nbNU3VGh/jmVgIlgsJK5cY7FfWa3MBd0J4fe6YPKGQNjtJsSGBEWOEh/5nBT4RFIJnqn6B3C+Jq9LKludzi9NmDcTE6j1uPJ3Gc9CEFW8QkS+84MbhBaCEULxN4yO4tnnUt142lHACNmfMCjuqqTXwmN+sbJrlkjkWllMkPiyumB5F4+cLEqQ9oqPNE5CHMHlLQpHcBKufAuFwc6TM9RsSxgR6qXJUMv3s2KndgbXQoO8AC/Aweonx6i4/ZBqbRFHqmwMWcWnzp/CHp5GBTBr8zUvy4MVXbp781YpRB5BQXVfX1itn+f3Xvmm+dMzs7aQCtrx0Tjf4XtKusEsLXca/IL78D2h0KarW3EsWp0LN+sscQx/5V/5wVgSkvoiLLRJDOOKNVOo3abYp1d8tDIcNMlfWZah6a3/lYX/DA8WYe7/X74+cGJXLC/mtM7eCzWFL6XQ996QZOWYCcEKw7JZs5qhrMB12R0P3k476nvCWflEjIYslsypsxt/fsnt6Xe0U48P5D55WKn5dLrxzesw4b4WsEvNebyy9YC7nrT1PfSM9wi1wAQKZDGVtY63CSqitLEgaDGCzyamVlZXxna7nD9CM7sdLXHCtL3nWF+SUjbyrUg5HFvZrKUsW5MS4/NzSWnzgqXA4zoa/IIDAzFSVVB+BciU1uVESHRjlVrIU/IEKHASojm86Vs9E64XBpubSsTbWe5UzUzI1/n19EjfdkafZ3O7GfbHC/Artgw8HS4mtciL99lscSRgtEIEi5Sv2HvWvvDfXPAgycL+vurQyM2OaYzJ02R3b+vxGpy7qIG8kM79+483M0b+lhAjnnhV3i9wFIyfpRLPWEiul+EiTr71FshLBxY3kzHyitwcsgok2h8LhynswVVLDKmRMnWgoTemauh5nBuXWP6os0eON+/OGfYThKWjLC3mnvdLQKkOHCnviSb+LTagYBLRIgg/Xr7/0xzJGz/7TQVITzZpYCV42VtrednU2OwlrMC0/mKo/3OFhwSzAaxYXp8ZUzUShZN5KRTGSGa7M9taKWVsQohzcl99NFsZPS5s01Mb716k8SkCJw/RGrrBbjvjlw0uUFVjaCTX6irenOXRgFYT80ZB0dYK1TL71riHhTGffyY/sLZ06ZY6dkK6yf7Mr6hePH5bYQXdpt2DlQ8Iu0EEnJ4rXJ+WyT39c8j+J0QOklU7cLuK+GlWNQa7L57yjKnBZCTFxJ9apI1wuUxBy7UaisV5mFo2Y8C0hA5p2e4Z7O1XrzW0Xo13h/Nq2FbyVNWO7mUBQqLIrkifPs0pdf5XeKOjDoZzLKV+Epk62Z5NthvY7b5YuXzdf+mSFDco4jAy3BLZ2bLp38MJ8dfrsZmN9dc8hZWhoY5byznWzV8zmem0xUg4G75fNUq3Mm4795lN1nhUZxoXff7O13bY2K09220sBj8eW26WmCIcXT+VQ8BrqpT+SitHe0fvZsPHmOHIWS5GWqifopv3Ob4wf+7kBY+WMYmtBP3b73GX0EEagCWdD6rK86M+/Vfnkk5mAeo+Ty7M81o/LDi0JgNiXQT9lquhT9Q3xTz/qXJrlTOLSAj8MPotOwp7XYcfCbC2f2e22hSPujURFsMkMjLptxOWidXLgcOQml0E9gXLJEfZH89vb+myM3lOvZY4/rnRUKG4sF+v7G8Jr0lVbtrx75Y4fSQwcPsL6xXBWhNsf/P3zP/8LiyQP+9vQA/FPBGz1jdGCfBE+AsfocE9P1WzMcFTN5gIhu79ekCa9tosDwVJ6qH7hCzmL6ymlUZlZIpxbbHpKrsUtySXe96Qgiqc5Gh5M+QopP9WgeFqlurOwbVE8WbIyTj4PpienwOVQs78Sa6C9dW165Fj42juCdawuIxWNIHHgAWHgjlKu7s6EJa0R7SwaXFkVPoPONDODXVelaDUA3cfl/z+Dex0BLPy9BwUZmNMbY5X+ATa1Vg7wsY+b9kfV0OLkTdLoTc8xeSi73nsfYRuu8Iiy/RaHcc+ZtWuc8Q93Jt+5YbnDmSPWBvMkKxnl9W9s7Dm406ZxXVG1cNpVSTwQZiUhHtwZLBUFUil/Y3B4WGVQgLSKvK1cQoED4GA3bpmPPiPtL3SbjS3TN2lOX5dDpBf0ZrE3yBvhtCI/CyYchCfoP/3hx/3ZsEQa8W3KA96sPe12TkJeENgdwTVZUybZ1CoBYKBwPaFqHOXa0A/QY4ZCrSwOejSy1KcfygZQ6MLnwW1VNDk7fsf0cgVPHhCL65Xr5hdUQvILDLyWMhQS9x2WGLCZNwcHTFezrIQAljdMgrXhyizx6bF++/qY/E4o+AEi55vmkvaJ0YC69CqJRHUhvNgVTWcvoSZWi9wkVmsjPVE+395jWuol5eE3ZuTU//aIWCYoEkA/dKrfZXlFK1lJsJyRM/IWTmlPpfAav/M6/gL8CLVbH8frwIoX3pPf9yKQCbC/NebVLZlwpKa3K5bRmErLzo0sKSeTGbh5UzyD1jgsVcT1uiw/S2ZXFe51N4Dm0RfVVCK9YEb/olqdLxu2O3XzzcZ87YCoBMePSxvuikBYWDNH98kh6MnI37df2owSbWvlHhgCjvEVylXlW2j/5RfJDR8y5DUkcqQsnBYgxck1OCTLqoCtK2b7FGcP0wAAQABJREFUrojE9W8PkBZvXFE5FT9gnoo4tgVp5v7di5099gunQWqpmYXvrKvJvHNVrrq2I94Ey+zBZ3pov3ms3kQYUL40Z+INJq04w57ne32CkwB0THwMXclyfn3i40KnbysSUjCTzWJU3JqX0+Y5HDr9UtMK4BrkqmVugVcd7aJ9M9HAi2MiOPUqQR6LvuTEfzJcMeY5v6wV3FwX/lYfLG+dG49iRwIE6fbuDWxnaR45fYXU+OsrRus6yfY6SCuvKoAsKhpoMX9/x7yns35a7vybgFK8sAiemnz/B0CwOskyIAfqTI8S5hwRjm5zZkZuY1HFQs60U/zjkBxS4yx9tRbdgt/QR53V983plXt+EsDiPgjY7B5cYUCmUNnJVJ3O4NMnOLIPD5JrpekG/FkXmd++l99tDz3oDzIaDo+m24lLb3pq6v96kVO9n9jrObTH7RSdzEZkFHQrFDcnZbjCoerOahkbhTY8L3wfu3im2FGKo/bWLeyQ9/4A5mOOfqrN6XeHivL7wu3N9lKGeuGCsEBTU0O9x8I4p9sV9bmkgC5vAXI5yn9ZEYOjD9iPHq1YaW+eiGd1atdZ56jrEjxlyyZ6ZIk6cp9WZwuW0MRlTmIR9oUVQFqdL8QyiUyaGTSJxerKXJFsNIr7cWijENzqslXQ0MZStOUlV4s8OeyyV7cqEzdzKEAAnpSJyUr/g3Bmk5lLFKntU1VCKZaIKrSO1nl8wo4wqRpaPInJVdrxR3swbwbCd5dDonLirMbCAXz+hTcnWBhM8/atymNkNK2sEGfj0Oa0N3d6p26JpOp1TqH12vpETzVNDS6n0/3dt1ofkkOHs+BZXq0pg9MzG7OV9m62phJzgg2HbSvL1oZjGCSS9KgZbDZcBHBuu2OwR5gOTxaGzUiJPHCaOniOsWnScfNzh20e7BAZLhFid8YRikBPj5GcyfqoJygkWi0GmmM1r3w1s46S33NCiIMNlGXcd3YmKWcDMrSb23eklD+wm63GWxiHoG1NUKiazKdW0pFWRJ6Q97Xz+d4BYQSUpHvjtSKvq6D6AzYMDd/wcRnhYEe0vLBcn4bnm/pOf8UXiCV3W4fkqtCB1n2jfq8d2YdS4Nw6OwkCsFBHDtlql/G3zBiWDN3ZZiSABPXJE+i4VUl/Bcjk3E5++0/lpZ/+tP2xgxXMNCCEl8DnoRqZr1m6Z/N5r7y+fuBJQQaIaH6hUhcxb7wlR8cfNBsrJTV7xTUxdMSPqcDv+w7udPc4wuFyQQ0An7PCgjRLo2JyKIISZaNpS7XnGJZsCdjZSeHrVs6ow5k5fTVwZMhUZByE2T98wtSJpyH+bNo2MVa3P0bbsb15+63VoV57VivBQBosIClrndzDT0ShuEh9XNAA2N11vP6mUa/+gY80UBtPRDHg8cim5z3hhtEmOaQSRYA8WMGZkda0x15zjiaXsg2knPMokkgBlruUG2uL2RHdW0kn3gT9wlDUBkbUVVTgBxpN/4DQCcCXZnZsDtvZd+XoxFPE0wghKflvbSERLdnmXN+cmKi2NshIADzS7ymZkg5CIND5IGVLjKdbRNX49fmRbufUCzdo95KRRdx4oJv2k1+Y3FxINsrcgfFgZAf5yU4i6Thu/3j84H/REXAWdm4i07FkHbtb5ZBX+oDSQweslw6F7VXSnN01VZnoFk6HcKcI9RHXNkUX6zoUfyJ+2e48UyUnmVNurz1S77p6QYYOZIDgZq4XT3xKaMRZRCXwWZlp9p5Odz59wC/CzefMu28l2XTOwQcDdkfnsV1XCp2HEpGFYrn04CPSbVxRhbKDmCGjBOhXSeNncI8jQKTUj4sK1S1dLubAKJs58ZDcS91VWXKqGlZ+VciwblR/v8/h6mESPNQyEZg0qeVT/+R7tI5/pY9MVEdRqKC4lgJhMLBRrYB4MJ9ZZk2tMA2KcEqS+XYqNSWzGWlLghPj37hAe/DJLlyDLreoM4tz+flcBWvEstLBdrQKizGAP9Sn9t+u6RbQMDwUcQ6MQBfQvrZhN3Br3mEdKgPVE3/dH1Azor//CIzerj0NRJzW+E+bqo1JuFHZDOqbeOZU+j9mDPLwO3/psbx6VA+hwBYYiZIy+AqSPh+jDJac6yCLHuEgkkHkFfInQHxbpkL4AZyDqAuAuH/9ei0tcLZs4NCoDNaSHB7Y4jK3les0z0ogaITvF1esrFdNvW4Oqd46sSRqq9KHJGjRl5GwiaPMopPNiCGkcyw6Lv2y2C3F/aBTqHu0IJfhFIUTE/YBRpfl4WgXjfrEk1HciEaZooS8+F6+Hei6m06pny6vYHgP6qnzxjzVbo5yBWEY0gi9Hl9hw0o7Hx42Eyu1ABQ9gQVC1xMTciXh9IlN0yucRpT4C5WaNin6gYL29O7BX/q/Ci6xvfd4TVer6eqWcwfuc/ceDcX8Ij3tTtviYvpErwS1AHkvqzGUMfOlJEhbr9hUo44hCslVYnQpG5Y2H269RQ4+TIC/MV/MC+gBIJSDTupdaUfQEUVEKlXa7MV3zkoRqbLivi8ggeb4MLc0fHzTTF/ve1QmD5/+C9+tQFnr+oWQwJW7ePLliMHvjVGnvnWTS5cT79bEb5tbypROC5M2sZS5mjVPdtfMPyQkLJh6EkBhR2xgUW4gIpREERSiaAOMLVaWlcXA/BLgSm7KRwFsUscHLEiz5vLQ5k/hzx4mLiR2/uCgPI1le4E69/ifX6c9iMrV1urqaaf95ENX/vVvmmZPLVWVxQeobWg1wMvnzOEW050xt+RIMv1Enn1w4EaACbQa7/cALrB4CPyG0ld4pYC9e0QWs8YCcKE/TrGY3AwpKaHWMbxjkLrmD/Nh+6UpmZngzLK2P+gfnZN7v2nsGjWyudw1Ohge7bC3NNlZ3AewKAGdnr0AAHS4vmPogdIOtokNlnldqBw48xpJhk0Nymv9AUd/by2HZmZm/Ecrg4+1hvpFYzj77UV2wkltyOBHWov2aKQyPVPfKoO5O7kMZg0cFgrdGluM3j9gkldpxxtcY2d2RnsrtWrdgYC/s8lMz3Cqsp6QvXQpWkf8FW/EtR2wxCJ+OC/9sjjy9nq+ucuHbTD5zjqXdfS6ql6pkUZ7bWG3fTgoVaL48HRqZgbTXauDcOq9HE9jn2xOwVZ6+8nrcmxsyF2t6R1RxC2fA7wtk7HWuW/NFyNBoclGay1qodDWZezUBgBj2uPuwFZqVqg9crCHrLBAT7TGtOx238qKowB3wu6JOpsao56p5XPzHGUL9t6nBiSSBlQq8Q7fzBWROUGGHH/82tqpt+XDsS1drnRzq2iTy7e2KWf39P+ghNLdDcEGHn/AyTJPYGnJ0dNhiEYDlbKP7DUGS2Pb3rb4hdeWDx0XlfrEM1Qzc+9MrNLevrbZdnIPJkeXXRF+ZaW4tOGK4LoyM9d2+p9EC6fmgEyZj9IjVOiyPLSYiM3NB06KPAzEvc6tNQoCWB5IW3u7twLD0Ke1Dzhstohl3WLkJbew0+rr5QOJ8g12RKjrTdtN0b1qDsNSOg+wqcBO9tSLMpUPPORfWNj16VLNUNB7/KEyq6h++EO56snndsbvZEae65YDl9MRDeeQzDzZlmeVtO9Qd12jiujWlhgOY4ufFYvD7DhFnGp9Tu4ikB+L15xRpRKlF73a66ahujqHzxOzXX5Zhmh0f25xunjsmTratkZPOLyi7zHUTmj3Zwju8jP/Yer0jPjyC9Jte6nk95pI3PHR5+QD6yiGV6nlxiAbfPSwLG+qb/fWU/aLNTeUtaAs6Hc3T3y6KdojuLo9m9x3LMhyuNS8DBf9j2AmopwBIPOlSwvvyie0n0QnLNz4o6s93UKYYHCgrcnyEvseup8tcjyWgra42BaYpqT66qoIEzqDB65FC0uKmEJfIIXx2HFOYbILaVMAlJHMlCtz1W0SGmCmFTtbIYOovqzof/mppKe/w9qMbv+DFfIPrYQ6EdLw64WFqz+UcaB0uwSmNqQNFpVmF995u/zYl2Asxj3YHb0zU9S9tornrvtHe6Q0PAxxLhMPlbDw99wn2PXSt3PPPr/ym78jRPrl5/OIfMvM3KWIYELWHnzjVc6Yf/QrrkCgyBI+2rbNRMDnS4xvx+/r5rD7Syccjd7mRpnK5e+db3mmYLp7aHc+0JK/lnY5SzU+RggSPG8TMdPzeGHr7HgkXPF65L2QQGorU9T1VSQVY9IqO5HCpMVcmYojDz4ul7GQrFIoe6gZzB0+x0i8WtstaGrq7Vdy7a2VeEi65y3Y5hdEgQcgJsatv1fXMYLFjRHRNOEvjA+IslYJNwrBmozs9CXZMvqB5O+yO8L4uHAGkkN3dyt1JAYxra6KPRYqu3ybSRlJDxroz+CDjMB3vsM2AUKJBw479hxw2PYO1ioGsBtoc7621B1REUREqsB3tRCP0H2YRASYiVdNKTXcgY7E6HvCeztku0OE3VqKMtTsy6cTa27cFB3a8ivHussixqYmA9TtBCbuQMJt++I0d67OhI4OW5VOG/K7PIHkD4vKQBvaxHwA4sd4T8insmb7pmrAyiZEFYaVWEoetARe9mn4i7uUIOX2vxb4mAY9cUNZ26K2eRs4i2AY18PGirzRWmhcZscjsFd/H+PTtfEXfzAKVPKZ+1SvQt0B2uvN7Q3zmSZjJaHA2ygwoLzUNDbb4+1ujydn7deyXjHPHLVEkKj+g43mtmqgPBYSwYI9IwzJ9LA2pmRUQpo3FgxJhv/zIfm9odPPxh779+emhaWZ2SVJMbL6QAN9CAmp8s3g32N1lk6D/OXUpYTcMnXO/O2npAzaE3IkBf1gQct6aqJi9pH0w67X1heiTJdqC/QHMOTsZlRnhajIGhtJ3h0iZueOMX9H3wSLYvk3hYIA13AHISRWXPdTIUzUp8CBjojbKaRN/ZXy8toPfiD+YgABVHWZ8zoOTBaTm5Kf7xW4HtP0/iEzqjv0+Pf3RyU0rxNYKh5tWz9CrSC1YsEuKp1ZVTQw78nKt4auV9EJBnRR30n3QRhh64py4IDSgB5/mH/AZ5ii5ccU9zpqiS7fFXfw5Usrb93m5c1PughST/zh2V6yFSRs63A1RUyXiADf8aOmvzWKxxS4dfOB1Rt8r9XzTX7AwysnxPiB7iC3vfsq+oPQr2X3XkJ6V0xAeIbw5gE29bxbqWBuViR+A0hGmDQpVMOwAGAK43ZlxiQgTlRtr/h7reoaMHk68C9WzddUoWj3mulcLWYINv4UAQxEJr++Y45REAgxfbjP1V/fFlumvfna+di+dstHH+pp6GtfTyXMugguwXzixt3d0n64aL59XbbdY5QARtNiC3p0r39AOAtvefGP/0DGXTms+HeYaOYZwLgmoaNe29hdzTExByydHd8NSd2va0eOKq5a3Mki0z0aB77XXt69znm3cU//z8wmiLdyaexYaPvdm7EjBwyRQgDTYm7efOUr0vY/YwLdNZ6ceo+VBKawbi5fkVMEwdLVwKDSFDlvdybWZmWIGru8bQ/1mN52l1rre0aXXfsGAhMzcgu+7dF9toPHvQ752LIs4XD6tah3kYUZMXx0j/O7r7rddeb6S//2+rOfhpnDCVrEm6TuIxL5xOoolWweeVdDR5Mn5IkwlkBd0O/0WmWucWm4NpaZhLZHZOyhNeF/1PGBmbKQvS0uOiXKTe/wQ+0uT7vbBolgxw+5fGGHc0aY1vqr8yGkYzDonlAexqY+a+mSFvgMdcXwO1kaVqDBZUuuBXe21+dEs28YbcQJZ+UcOgN+Z7ApT6I3kM97uqmUt2O0WgPUuXZhofHxvXKKfZ/eu7iztlunuld+sTzx8sS5C0J5P/eFqq+zsUv3IqO22p/+m+WPPV20nEzE9DofbHK55LLs1gL+v52zN2gHZuaujZl9Q0UTZmzN299cGx512uyrtBuaHGJi3LyxtSW0ixHS99ygPSrtaD5HMUlfVIYxv5MWv1lrm9Oqm1MsOjBOVDRFAxK0FCeqsCllJ+yGaJlbCDqvJ6pRHUk3nl8o3Z5wxoW1ZG7MBTzFqlogtlBw/IeLgz9/RG5HqvCgpeXwU5/gyMbmU8T0dDmTs7LDXp87N5YiXtUNGhqdjspgj2iTDrevp8e8pvvV9vbvDu3H9gvXE95GiVkvhUiooEQOaMvXx+tbHhukbdwlooKsPCzPyGWezuW5sZ1OgoqAyxmkWhOBlA2VdcsrY396c/TZdjnldDY6Aps35JagK336VPa5Tzh6HkCIEN4tNB7y+LQ0Khc0PzpYpcAdX5rGeRX0tbTJdoB828ysq1Rw6TouW3N302DVNTfZfVg0p6rPV3W4Ah6ZIwdu87Wl2bEd2gRBW5vK/o44K9I43DOQoEKDC283srZatmd37Q1tLMUWAA98vhv//R/QHPlnnzfHHok3dsnv777mHB3uaMq6tTZqFWwg60XX6lau3RBHQHe3XMZHpVfZx6CrX/CWZfeNj9V7G5X5NFFZnywcrHQ5w2qr0sSsq05OOdeXb16WPeKABx+siDcd3FDPm4vIthiOwgMpHF8fjUa1TknAU5o4s8F+0y1BtAvKdUId+aSmutlcRQKP338rfeSQ0Ag7nt+5Uto7Ih9e3NzJXr3jo9Qk3KCS2Unatpd2Alr8s6ezXMmUn35Ghs7T4sdntbUlxIvCMXwk4LIXP/WUvMjTWp+/vfy//q487W8/tRtvyofCRNycHIYIlfcP+Pceom0fGJfdu8myBxIJz+G9ElienuEoM7PhTJ339LTSprhFMd5ru33NFeObIblsQ4sDSw8INXhOeHevKEe0Vcouj31zMR+/H/XDlLfT3/+tpWOPC/W9/FL1574Adek9+UJiMbd/UEvS04f8bosjT0EaLhMNZlmWSdxi0xDIOboZrFto7RTSRkckJbILLV80mLKzpaGKPmQFlDfWd9cy9XUyDq54ONRIUpcQzptvmid+sd7h9vQ+JCNpt5a10foZ3PMIWETgiIbsq9uyDtVCFcxrjKTP/KI8JnSfcTLd6/rI92RBPUGj0+/J4f4hkyrHcCMCIOid8Xdf3aW5b8g88rQ3PhizqYhcXMw0Hu+XiQeaGmXl4sjDTqtga9Fnw2MSkJktbbN6KeQ4zPNNeHX2vt4bv/wvJ76iRD/IHqnu2hIRCNdKUBBGQ347SEVKUpO0e1oMZUeVLs3mhhm7Lj+m5c+PA0Q1L+nUS47Q8JpF5RlnicNouMajp1DAwDmX6mFD9abZZ8lY83jZLCbFGLWUS8gJkSxkicD1Sb0PNn0CKDr1eJ+4j6wwUX2zI5UqDz+gbCfsuHNme3GutiXG9XPCgl4SAW4+3yhJbgd5ug7wP7lovuY3Hfr0lao5TjVCkZAmMWsop3XqlLRnF/Ik4MER/drvdzToJHyB/og72VxZNTOwKThATiJO1vggexbw1IgIMlfYEYCVZgymMCGJmsACrSfQKUJ8IQrf6Dig8zV4TExxiEp0za7agk9cKDOL5ruztdQ7jIB+WJboRGwMI65eJ5EmYO8oOW22bK7+kzLNdncsKqmEW3JqY8W8dz79nWlpK1TZT1s4n4ytUPsHAXjKG7umi0q3OP5AW8f0m7+9+NwXI/IMlyvCVp9dPZVuEZGDrau//q/WvvK8nEGXffKYeU1H9Q5eeqwInJ5yRoJ4dFS1N6kecfyuOssYfqiAwkG8xVor1cCG35Xy7m9/Xfrzq181Bx+ta+iQt595yz7Y31JXq8NluzJmrly2As3VK9dsRDYRAQp8IIonywiByYyUzTwhYyD5O8hnvIglpSV48A/Okugkp7D/T98d//uw5ESPUHMKfSQuBqxVQAo1AhVBJlUZx7fI06OIqR56ds0yaxpkHszylon5DMmPbykKYTAoW5FTatBJ46cCvLo1bx4bxS8sL65r8ZHCG9h3mLYbs3JxxloPl11NUXWVQLFDiXmcnTKv1xQKBOPnHjALN8zBdekRT4FPKZ+Qw3sEyEsp7ydHxlKIVH3ofM5884r56m05yFApuWxaReuUBXVME7au5ZBaHGcNs7lfzsiyUjB7SdsXFDmZIgtXlYD0xD38qWHJPVwpl3iOHSKMIC2XK3RivyDclFIvoVUiGF7FLBsImjTLoBCMJyHF4l77kY8CNwCGC+vItc5B6fakM+iNwGKBaDRAEij4omu3Y/f3mwP7nZStAHxxE2phhY3SI7joloePv8UZF4Y8u0LklJ9R6G5P25ETk2LVAOS5k8uHCsg7oSTEEuqsKnnksgtdw/kAjxvDQHvGU70Up1t/Z5ztgDmzZ6jq6rVZkSVPKFi8NeXyyYUkCzXtb5SvUGdCkBCS3UGklFPd3Wb23FrXx5u8gyJoVt68NXmraKWS200iEGarG3ky2pXrQF8gkvIklAli1K1vZNl3BX/VdHr/F/YETrbTJt7sYPKxvlFPAY8n8snHa3scsDdEuUL0hiqCnGnZzkPDjw6KVLZRaNvl9A8pj3jjjROPsPNgDj8KgN5oj2hWNagTs+cLFfZ+5fegr9QTqdggZYplobZmCpsLBWsNvan3yYKXUqmyIZr9nQWz/zMUlNDHLS7eOLM9clKGMQpXYDScrj/7tUkOP/PViB1JTs95EX3PZVfeWt/OCD8fxA/T1fn2bwmmP/K1AamOcPAQbQF2ygoHdxc2adqZO4+LtU/yezbXhjvCWgFNHKmv18Rb7H6YD+Ay1BK5qnRDBcu6WIBM/F3xM61dWmzs8dMvAJ2DxLQjh0X/8Df4JG6Ty1kRcEJe3t2yVQbDf6iZPlenlKYeHEX6zb8173DIEDVtbzf4/MUzEBp5F3Y2cPM9+VAN02KxrpyrOneDU7b6mKfOZ/X0+vXiYHfx8ru2g4/IOFS2c772UGVJLLHQvh4pn4DHD8ZK6iOrvLCB0Zl4QrW6M7t84fwu7aMPL3n62+G1tl3pw/ZKJtJd5wgqjYdCYy/lrZRRBok9vrq6bEZt7BjqXTY7cUo0b7eTxYml3sacs1c1H1SqXK7jPp0+ls+1d9TqhXqeQP6HmAuK3AAHRkWz0OibDZRAkqtncu5aqvNwE9pNwPILud2EqWruTFlYNixRPkFwmTIH3jd9Ao4icMFyvOFVdRAMdzhuvC7q0sizneL4x1ZHftxYb+gJZpKCZrZ9vS3tGYffHrd2Q8SGr1QjLrkMXsgg/9KvYriq6hQK9TwYcmrJkAAF2W/N+5TGEXjlcpWqFw5F6b72BlvA1R0Q1DK2imlravLLCJdLVX/MN/bG+ghlfgC3m7Si7pA0JydIlC5dvWZ/2DbDoW95SdzRVOqEyR45bMbHSi++QptkZlGgYALTcpnLURatif1iacfDLr4OAatcCE6SvbYQxaox5vf/ff7Lvxw5HBbGVSxmbLaKVAxid1qIwOe7/yGXVa7zvn3Fb33DfOEX8/zOcoIBAvlJE80o0+jtDTQVShMznLF7Xc3NuzMzcAi5siueR2+ryvybQAMbtxV/57dFj3v4QbP3RNEGz9TJuH02hZId7Rb1yF4uip6ogOYh6wCcWX9R+lNL+7DO/ezvPYzAcx+z+3RDRfw3bmwIFCsNaZqHHhLL2CZUb5yMctKU3pV2dsPkUuYHP6xFEoka3xWR1c0tkmX3EPtgKv3VMIshWU+gDqk9z9a7jlIc5qQ8IcgGQey7B7NTYWq8lFQyK29xxtnKcko4sLA+UrjreqNfPmg61fxHAGIAWH5cPE04x0AbYU/qj6cXXaqC4PdFllq2znzJJCPmTEoMjB8PYDYS0VJE6H3p7mL0YXR0Yz6rVgpP+CFiDZ1Sn5Vkt1O3mdVHz1dFrcQgUjVMwkTnyTfRyy4VzC/0CYsCICykfbTe4WuNceiM+Hq6/P4u5W82W4d7sXFj261q2OCBbUehPKAspI1FBhET1jzzsTOZXxw2gaQZUsYVz5hWAl/j8nBW4CazZmZW2k5nmUqG5DEgP4Gymi8qnEQ7xE5I5WUZGHALvs2ESFOCNrDdwzonj4XlUSjcP+BL+PxmHG2yWS0A62ETkKtsQCg8yXRWpf7E+aq0H7Gb9K4YAwAfC+9gKFTfkifXy88CcCCErY0nArDr7j3GF7L7muUQm664ZnR9rHHYwEC0qukZOfFr583DpVpeHzzluvz2AQCDYrNsLt8BwRkP47LvDMbN1FvCNJwuOyuc2z7isevSokBd5LP/pc+L/cpApWQnkaiyWzI5mfqpu4VYuLOXFRDahWc0eKiDrccf5h/kPXFRVC2ALA90bfGtA/D8pjbPMJ3i86jBshagxJ5HRtVxcJ+IyAkMRsMaDVFOyN4jX3dBPOoodNa6oOFJsai1HIEkrBKD5UUWIExyDLpQtsT6EGaKPoZedLcLJb6k0/zxAUmVUMlgvqNrGlU7ETpnsvlnzTEbgJHzKFweFkCszCsW7LSiEDvz6Uv03E/1zxyaJzSeMd//c0GApx03XMjdJ07SdoWOsDf2wm+9SDvsKKB9EaOTeBzdq4pnx4olykC1m1y9aVI6h12A1Up8cuU9Al9pffhPvJ73W1c6KOudkqKIAHnCxHF+j48x5nGbaGFoyxiHwJtTpilv9oalnd4W3mixV766okzALWeE/O8dPthc4AWv5R8sLLjQutLZmtKJ9grntmQJPp3iknnle9IJzLBw2M36ByQ6gCCHbXR303QcipGQ5NF46tr5+cbnGuXs0JBctmfYRKluo/wehkxemQyU9XUBU1w0M7fksrNvm55utAxpE0IpFhp7AzUnGJYbHiQCaIDdkTgzESeKYsX7Z+c2l7KxE3bObF2cit4/KPogcH2MYH+4I+zphpNQNZuCeNnaE1gzm8vlc3KLp6Uka1bCEct4Ewse0yQnxIJNHCSAhrdeM/FS60WbprRy6uGHC6ZjIKBF6sbfWdt7zO+ob7C9+TanJN884P8fvy4z/E//QTN9cEhkDf06Jbos6uO6Tn5dnYcKCsT6FGx9vU4UbU2P9JSKHhbiD+sIMw50wEoXOHmyNZcrLqzlz13hJl9vi4wJ9foh81IpXp+wKx3bgr4wRgg+FlZ6GnPfCf5XcjQpMy+l+dY9Q/Vh3U6hJ5SUXM1bN6UL0WiR7DVVqZ2Iblh4InH8oyL2zOrSVqIsezTxIlSH5hbKlIc2VZCWU4z23s+PyGVs6N3dUzx3maZrqLtya6KcL3qI5sLCgmwVWv6H/2yB9q/9o7ydYkbLECN+jE1JFimxwS7ID8qX17/5esOD/dJemqMDTkhZs0kiByImtWatja7r9NmRPj1KF5A4o4qzYAiqQUWpc66s524LuVc3kxQZZ+MseRrqRjTa1Lb03mlhJZVKMdqwyxoX2gwIMt6Ht5POAAMDoeOjxpmjmb9229Ma6z0sKmxbKu81uSSClNfxReT5xOM2nVkXk4hvTP1p5Evm11KeQp7gK5c5ezqiLclugldgIFssgEjIUjqDTMX/yQ6IGnQyvX1dh+NUO5AnE2WtVueubHWOas8P7If7//AlGbqTJ4W1FVc2XZYPAi6e3gl1qyzZTr39S2898t8e4TL5HhRB9gXDswrwwLkNa6GDDZKZnrp8Wl7U21E0nlbhlEQygWj04jfGD3+2R9q4XZAnd+7U8rgzGXapEy8fkxx1d9a5PirWvPHiKu9uQ+9gnwa5i+kB+UmtgynHnWx7QHxJfseQ62t+6Tfnnn1OxkS0ko5OT1BGuzTN0uzmgftDkrsIBIIRXtrQTdNZrrgm57M70jdfY9jux9KgNJx+ESoIrACvOFCplNY2PR0y+yIbk8l4XcVhOV/CIXY3Poyrmeh9TCr+tbVW3B7pQ3Ftq7h51X/0PrmroRP6crQ00Vw8PVu3dc1/dMQMC+Ny9fXZoKnlVbkM8mSyeAVsDWhpDXTVm5KoVI9/LmaLuOq80rediUygjjplUoaSw92lLUqSOFRSDhwKuD2ZxGya34P+MpQH71wYl6FrZy78/qyWmAvVR4rF3cOHjbdBmEOwNVyeW+KLAZaPBjobnv1b8gmxqNlZWguFtizEo7YizKA1LoyLUjS76dp+cTMzJpXZPPpsbb+Y3bmNDyRO5K3//4b6+7pS1+ZlDDwlB2hUcdUiLO3DppV5VektYY9l86MX5DJmDocaNAitAswKDFjC+Mb2QD1CJXbmNO25q9nOI1QfK4q/CcRHB+9kj54G2qreoztA/paIBA3mzIxyabKRmltrrve5OYr6HO6SNwBQBuhpRTphM7A1UPVgnZyCLteqplV1oG8sml/ICpkCf3TN7CmLzqEILb+8H/Cda3etjlmWGFVkxRfAX8hGCqAKRxHLAUkgrAH8jMg4eXV4pm+JAgovEOzUr+qUNW0CX+gWzdgqA4DGgeHkC1a3lkR1igZcfjfpmkrm1WqwrxSkjrvKOCkek9ppL+gI8+XRqFNXMA6FdoZ20uzIQoY70E8Zt0RtdwSY3PKa0axnEcJ47pCQlkIxgOqhATduSei4ozF0ywNkZBASZ7QN379gzKPKgajgi3JOcJuiGgBaz0TRNCgf5Xo+erAqJekB/pDB8LBeVmeXkT83Lr8jTu+smFt3NWzwg+drpFOsOMh2UAuiONl5A53RkTJOuibMPPu9l3xW0eFlMjEShEqsJbFPUqhophb66NanyfX3DB61mbN5s6u2E6/dt994VSGZmpQ5asPHfVdE9p4cKl2QybxzZwUm1t8nr3mE6AG8WuMGHLLoDE94RKfIlTVn8RnJVYIwq9r4kP68acwvFyw/vzgKEbKOpri8K7n59j9+8ZF/fELaDCl6Jp5BZCiESdfmZ2tBVUTkxJ0rZ0BYGViUdXRPPh2Aca+gxykSF6fEbKY4CvWlACaODWI6VWJzyHioqmo6fTgDRZDalSoobsRIqiCVgvVv3GUfTD1s+bIaYNaLWnG+6ngtVIw/Y9gCiZorAH9AJSVlOfwpAs9kXmAm1vrGq6fSI6ULPtQPIN5lWprjw1CwufitDBoQrEYlJGEUkWI6ivIXnZlxFfkET7tLU3r0ofwZ0qe26mhbbAffCW7Hr3XLCSLJuCLxPcFVgP3UmJsx6sMUHsUEiXzVGBfMjemgw8B5/XuPfz7YvlsT/6C5/5N75dFICIaNf+QjA4QjQDtrhSDZYmhIN0XFF+71wFMmCy40yKGT73ATHpC2Z8WUN8TJA1fdXPKEXKJwWPwDxhYMbb4MszKx+yi/0iA+m6SwVNPZbXY2RbcD5hdkAx8xnKFaP96IKpuralDl69/wPv9cMXryiJxir9lbU+4MjutuOdzYKG7nisvC/99+KdPQFThyUkc3k0klShEKZ6rulR+f9dy3r7bpCbU7MlnUcW6xHz4gQUdEIx59IM0CLTilzF3e5nPWBcXzoXi/m8xVsoX8krwodnzYBsNG4HHH9LptdiYw2m090MYAjl27eUeIcs8njwi9avRv59wtMQnQgyE+ACxoad68CoMyMfLQSVDZ3i5tyJikd6rRrkjNc0LV7L17JdIIjF2TkJbPV47J4DvYo5EO4C0BiIGID1U58tLi1IWt3vvJZlX8wbTHetRKPbsXb6Hqs/nUGy+omvhoVUSiGjGZpVQ2mauXQkh8eX5nacfhcWrkUHhT0el3Td6UUxATmgRgLRlivrAZCMcASMuDBysZ4Qp2Sq1NTJQW10pO2Lh59QfO579Wfz0Zor3XzF0/vb33C4p1ZEqgxWIY8xfIF1beuNn8qBDRyrlZWZZGWgnTASAh5+dSGyrQnM4IxeutDuRzr387ffJ5CicIX5+bKHSOhrfZIAM0OTIgptHUlNyOgbi9YwsE2MWAI6o8ObdJkxa8zSxvv/rnuw885ouTwwHeNUckk0ft28rsvP3i+fymIMPVy5UjH4mWVhPLG/BG9idxbmw5u0bli8SCAoGtDBiX67V/fa2rxzZwUAbfdvgQU1bekSfYk5s21n0z4A79WBatzUxvLYueQjHD1EoupduXMWmxrmCWnL+yakEoanbbwjuCnO7UOhPOUB3+WAuHYofjzOnplnYkkvj+GavqvVRaZxkQTgfL6gDlUO2Xl+Qy4lq7u1b0L8RuNV7ftUslK3891NdAHyIRHW3qvWDlwnrBUgB7EqvMMm9Q4koUYpCfZfNiJh1da1PQyUsWKAPequgxNVnOFnfV41SsOmN1lbWUt3EAPQRchWtXraQ+FAsbCTR8lZUg66UA/UpxWrrqam+k6E36nGCdTCVfwV2skQI2E9lrEz5rG8jm5q3zkz84LQTS02MLe4vsEnbgozLLZnCA/NjcrRmaS9cSeBJ6++3ePpizqTS3VhNJR1klZ1OrGR2pfcjZK8XzV3KuIAFKLpPFUYcP1igRJoYyu7Z644VpTp296v/EcyVrLWhkXwdJwtZ2f8uzhWidbW62ms3LLA8OVDx9HdaiRdv2djkcLQdFfcS9zlZ2TnuZynIc+nDh53KrLwiHbBqtL2xss+OZvbWZQ0HFrVSJMsNwhttL2YqnZUQV0AMHSu9ddrY3CQ4AM9M758dD/UK/5Xgjng7nmgzjZsrhbIxH4w4r2LL19rXo/6lTLPf8DH7yCFz8ucD+x0Vdc7KBD+4VxOKg8i5CPNGWmu0d6hFnb0JFJA67oZMmy16CjfJ0J4KVBGnFNA9Vk2fN5jI/Z2fmfNWsiBvL4YLUi9YtaO2W9mcPGKaV+CQsAmBJCUklusO7yA5ugRkC5Up2bm3iegEGD/xwwgx68QNKGwsFtoeOiIwCxqdMmuwNTEJjvl42A37zlHIgqlq/ZzeFihgbPxGgBzRCAEsNhVy/TTS/LpKgIiJCgTw1PtzGcnA9jmM25piZFLZ85bZ5dUyk6B/JVVJzAqT/tLY/9ZCIJivbh5QlbFX4OgIB6N/jirYFpubk0b2Pd8P/M5uF1WWhl4Xpcm9nydIUVhbLvUfqLPRevpkq50suG26+Oi6zJZOnT9d8lcybKB0i84WZnV40fWgooq2YuaL5rbv2CTLgsKqJ1+SMhBJ7MSq0zTDDgz6n7W2PwRKM+EwHw8HIkO5VNbrwWWzOAW5kM3kVDnx/LmO2hJ0YdOj7jhjdsdJQMOXqDfNuRUwUgBn9asz0MZqQeVr88X/vXwoTEwkCx5+estx8qLTT373W81g3p+ZOL5A8j+5uKRSw9hu75vc5oTMFwhW0fY9/DulUfmZQCu4BPJZ/lp5KZ/7w++ZTTznrFZ18DYHQSLsGSc3OzYXNU7f+nz+VW/jMbc23FGGAPwoKwAHLrGOyls04NqQ0xao8rY0P6Q/Y9Q+j5jOKXo0tDs8jD9Sqb9XXJ753Oh5TZXV9Q+r9wZctuYPQxTBbEcKUYOjG+vod0cQwtMDJc5eMbmcjkToY9Ge1390Oc/SwYFRNKtrNjWkzpnNZqorRTjeA+7uFYSC7rG3zsN0JQVtUiYn+ynwt+IPVDUBfWN0AWEDypm61I+YrawdW7IaaawDaFUxBOyp/T96160BUBv8dxIdc9TcxaCGYR4350l7z2GPyBNdQb7CUdISU6BGRe4ctakm+cfntr0/zFWw1AezvNSdOEHUXflCu2qvLK2Djn70op05p0VGlMDn8MOCL+tBeu6ljo1A14tsbpbqjlevUtT88eXEbvSyMn4MU4qnKt74rZbmB+iaJdc/PSHtC6YQBZKiBN1G00UvuDZz3dlntqpY9kbsxohlhdSiOVtFM9DPR7JUrwxuTazWXXtse42G/AtQm5SXi+qGzwtrU1cUsCfvxkKnNP+zfuXk5g6ioqwvtVQy0lwwxXHDd55FTCzOi2CGiQO7Z5dWFYtUuHLHr04fRF1dn881DoqL1xzYDGISWW8DhcPd1mCIltpWuk1uu5iY7wo9IzrFCOpnJz4tsczhsAexAZ9BS5V244bFGrDAR9XMLOZsWYWMt/sr1RCRUxgDjLtnuqanZKmXjcVZ3lwr+9o3ld6Y51fLEkOmMBe36UuYQ05Stc2DBg4MlZzFx5k7cyurYTmVW0nWcBSYnzNKiUC2G6niCsubiAVCVcXdiye90hFpUncVpxPx6PA4qLkJduymTYi9bnX24wMyM5bTcmt32BeysJHFYVU4Ta0S6HBtqNOLrJjnJApIhq7n8/JpH09uyq9u+wyNSmYE39LWzQpTwWsAhXTKe4Kk/nj/+tEylx17wtgcSE/K0+GDcFyuefzOzTyvyBurqXBCdZU5Q+ZV/eCMthyRzR81dywGJau5y3f72RZ6w5/kBmxp7E2PyoiNsIb3r39sKSiNMQm1t25KoBrC4G2tqeWnzpbMcRUPV+FCDpcFcfDf31DP2O9dXh3SjE3s0hJoeLAmJb1JWm4RpXSNEkuGBgdLClRx7WHPKTY7IdjWwDxGJP3ZVkNZacTw3l1zMxY421bUr3m5tLZzZbMf5CR73N574+WqksF5KycxOTWV76xesj5VczfY2V0R+H6ir2L0Fl5ddp4Vfu1vqGlzbeJdpC7Z0o28pxOOHPj/gS6+997aYWPcP7NBPh7WdDgEcEBhzRQslbV2ejYbKtXWPHlugUL1xCYap9RIKBR/161KiWKAgXH5t/eAJ4XqlVJBkSIRxaVnGoVhx+Ig2t/fJZbntOAl1GgtioEpnL+ZLDqtEOKuzZAFAg1pBGOcL8xFrHXA+X11actvWrIoquDYiewZq4SPcenhusastNGZ+rYgxL0L2X7rk6NERxvZeX8eqdywvSB96O2S1nqX919c71tZ9gx387F1ZuXo229xeys7KcPlSqXPvFO//iEyEzUNyUFGeCcPB9D1/K9Be57AWLaS27HtH/FohigRZqYWIY9sSbvEYwciBZuV1a2uoeh318uTNBRKStWzGXwQWMrtWAWUkHL9RG8Yyq8SSaWsxVn0Vrzf/Z9/3PPcET/AeHqFuu+P8NYu1bKZN3HujFqLHgkXNXV62AtIhx27IZ7dbJZlcLvS8Ok0mfOttc/xYFVq5QGkwMfNND8lj1pjMzbJIz9GqmF8uh3kH9lu7zgs5vnfG6w7IcJmBLncyufzmOFsYyyEqPs57XKmwmqG0FzvQyo1paXHiCKNL1gKycinABk293VzmiNU54DmzEdqhUxc9PX3ilNHAdbBFWNnP4N5HoG9fgN32uH7z7Hjsyx8V27ugIgA7uZKuiWjCNtWEiev0eXuNnV3vEFso5wAiEtxWIU+IqIqRJjzfl9mQ0jRUs7XcfCj+2Wz8iCJDNSebmYAYrEMFVmbEV78hJF+dX5i8Wbh0SX7+3H/T5vY5X3yj8MQxOfSljTcqAhwAKcBWyBdeAUA6DVRMVa3i+YRJ7EpxcIBr8SFAOSJ1FBA52gMp7bAKy9cf5cX6GcKe1DDgY+5oe0gjWm3UxFNN4RNRQ0Eri3aguKqtcuO6XBcLmeGIOUt6h961ollGU9rGLOR6eACAFUSCFq5O3BzA5O3i4dBOs7WaFDvJ6fL4S81R+YxqvFgpUthWLsMfS+kgK715frrEUPHhTSGhvmRC7BbLl4vlgCFnvQgfEWGucw7TLVeZcxrYsfRCvpFPmWPU5Yyov1cRWdpmoBiccW0P5kXveTNr9gjjMb05w4YO+hESeaDRiydTBTg8kkpb9aoiQbg4Tl/miRh1zQZp78yLag6ALtFgzewkAMIM2pDpQGuL2LI4mN65wJFkugzXic5uzLe+XWI9Hi6187flQsQXBqHq5D85XCk3/FW4pTGZBqx+fS1+M+y3Q4fkovbhwBcbCLwmiZlzOD+WGonX3J2hmMvZaB4+LpcRBJuekVwKxQVTHzZ4jy1H8RSbSmEw6GjrH7n+/YChkM/TYXy/a97vd1B6RLc+e0yHNV8o9/d0m1YVkcXteJjNFUQuS73z997bzTv994/KIRizZ2+Nfts7zNxsvFUkWiWX9/vvvPbDGpXvaIRWpbJZJVuchZzs5KZSiLpmrXWicQCrRcnkPKzMm/lC5sMzrJSI+lbzyqs1JTReb+LzZo/cId6HMQ2rWoQ5iWSs4pgWYDRQDpe0dCHNGWMg92d0iCtus6+5tnFfZtvMbgjiSb91MRI4bLX1h5/8ByQHSZEzlvV+7DMsAAW3zsudENUrr1gVbOpGWk48Ovf2D8vz8Aj6nJV4XVcgRTsy1Fr1xd2ziTjTgBjKCNezaEeOPwSwcIntPPtbzOFheQFFA1ra7P6+ZtpUPRjszOMSlbXxfFph7vD+WiovSVFMn27CYhLXxZhpbjA55eudiiDyrHuADxbdMhu/anwqJFgsPj0mThQ6AiCeUW7Q0gCoXTRpdeMU2GLtlhkYNhHlH+ltc/2K0RXnJrWC42vu17/HHZ1feUSIFUwkesqULK3Yyc4G6QCMDSJgM1hZog0IdfKLmluVYDifLVslB/xDnZhh+c1dj+5Smu0cFu1aEwlkx2L0M6wRSwXEoiOCpMoEjyvGmh1TwhIXbqZnZm0PPe6yW3l0CCJ855Y4mpiYupCMhmWyYq2e6etZutDcH+TQwZIhLAErZym5uXN9PtRTn0vJbHnv389QpN64SDvQFHT2dRqKEAC83eMuLG+6R5SqEwkSyS7+yQRn7j/JJsVlq2ZKNmdL3NlsPxBTP73Zem8iepTAhdDN1s2VKPti0TcrLwTSZLQtVxKWGA1IE+6zW3Csr5bvTLkGVbnv6KiUKzYNxKlWbMPDzWUseSpOzFIXLkTZQCilrc5BYoemTaxN725tVQc/OpgpiuALVDOTL9zqe6JT7sKadTgK6TxN2e9vbX3LVhf0IFPYWqZeLMY03Eaj5lAkIwmqGMOOtL3NufjJA3KKGfJ401raPri1QAyk2tGVdgg6BSs7tmtXJBkO6OisFm021TkEExCtu5Hi2iJnnLtztoZBlXdmY3EpnhjPYLRlhIfZ7qB/1DbULhLb4nYNe+bPX/NsLmfr2qz1FSUSNPkyPAUAPiUS21SPJ5GguJVxoXRYkjybzSazPosrMEGIxNOnyo98hJvyuYo/qEuVOUAJ5qsp0AcwI/AVjEyLvyJYAJQagK/A8CaDB9hYt6rkJO8I5kdLCdujj5BcKqe4EfJhJLHAmc2FNRebR6FMA0xioZDaEvXB7y67iruV7TSFpzh09bSlSsFIdUsuW6csXV3Z6y/jr+bUEw85Hn3YeA7LqRLFjM8bzVOCmqpNzQSXnCMMJgxvh2Q1a1SFpePpICEKID48NZ1bSTrVWHKmt8zeESnmDmAFsXYL+lL8FJ2FUVJyK96YcFVymZyMcIBMGrSY+nhFuYF9ebGaLUi0CojHZEDw4AH5/PbtJSKgltHxO98wX/68q043tkrMZuJ7myV7RsPgpVT67EX3ieeUM2DWMFbWPcw1QyeFW9SLsZ1KvnahZpygYZQpqit4m8+UXZkkTizKWnDI/lexFo9lllfWNyoONIN4DY0/+UnT0G+SylkLS5WVNTZfk67y1TZ79fbtsg8ObCqTU+6mmIwGY397s+G5o9ByUdNo03Ob2y+ftnYClBjadt6+vMRlCXcLtOwuZrap2AXTCLl8OCctLQ/WCjYmNvidgWUDZbbIq63kxDfBIKgPIjs24fvEU7nkrpdSwcDKyit/uPH0VxqlzQhQygiRApD7jQ6KojCpgwzuENU8ZCEDFqzDIvkK5SMhfzYx4NMAlPvnhYP9DO51BG5+wbR0c3ExselampZBthxP2LoEq/cp66ti9ELjynawX25OSEjKH5NX5LfMxXPmwBFpbyzgF9n55is0Q/t7yEAuVR3UruRwd9cWf2SkFrGHyeBlw0iyNN9SUVgHtggQCFKMJ3VK5E5rt6Dl9JwtvSJPiLf7CS/rkhMhJpgxHMtK0eVWHmCZXgSSG9vMLRQ69PWkLM0HcVQzFOvrKJJfnmqmC7IIR+lQ/oKI8CzlYnIZHFl4k/6ChoeCy4/AE7q28XvCnMzT7aaru8aQsqRA5823727P+iC+yxolm8NuSf6xvKDwErS7L37RkpAiXQ89jLdUejc3nusc9stukPAiTN/VEvZAUHdHTicKBLrzMR5Jkae8Y31l6lbRclXEG+ybO65tHR+0K/5Z9WzQkifnzRkMNu6BZvUDtdei+EL5A6oBywO1iobwZYVuXQhHM85EwmHuapPIY/b6u67XoTHfp9G/WzqSe+GCRfPP7pf7kUiImrk1ac/eNqd2kIxwZAEM64NN5uMfk3bd8eF8uDE2wEuYG7vp7jaVhrJ67x3pWVPfq5NmZi/N+G5d8WytTI6lufAPvy3ZaD+Uez4YKMswWM4jQfOpZ0z/fplnKlrtuGMRLckvIhUN8NzZ4hPPcKqQq8huH1agkK4sryy/K4P37rsiIqIxoxtnSHyV8bDyDMlyuHDKzGq/ztw1WfVIpgCsYwAB8hVA1CxboeqggGZo8TqKtRoS1i0/5i9I8DWv8TeZzz0kV7U+e8D/ueeNW6mvvGg2rplT7/I7RbOcFFzazjhG+G6mf1vSrGroUJLNpPBDAMvL1XffnX53+dx5OfoPNyX5U4hNY1yPsnZLTVMOyd3dyBhre+4LVfnwj9nksv4ecdahJtjaWzn0JFeW5iuWNEBjpQTv2bNy2QtZ2SFgW5r/EYLatFAUPaxdD2l4iUGproGSDkFY3AgPAjk0RZZVCy6YqTuSVrqstyTvYqkeve8fhu6X3LKd2rFjck3sq8+bvtGaz7eyJkXmzjJ1qlzlc1feSmmal1meN88+XZNvCwnvg0crWWdo7SYkJZv+/dkF8y2550MBxsAak2G71DJ5mA8gG3NIkuTuf5hBYiW2C892R3t1dlrY1dpMFpzEAw8QeYFDXhU+aohG4nxZ9JhBHdWprPmNDym6JTaPW5lqIGI250WEWxokDZSDcKd0B9zJLJrxS9Lu7ZZqFigQrEEElm8bdo+ZUGSsrzeXbzac3C+/Yw0PDsp3q71PlloAf4ylupGnhIMfxmNloLFPZ1+fOSozbHdTEC1pNg7JE0hR8/s8cN8mGR5f2MvwWDGQ2GiLOLlJiLcS1VEjEEtWIBgdVFzj0rfStTFqv9ls1bWxdQ4bO3TplA72zuzmZ79bPvtfyZTcvpzrenKQKg6OuKI3ejOYK7adKDT+mJdx8PJpAFZQIHjzvKhogUBmX30ko8tpF64vDX2kzX1guKYaUtCvkB/+OX0aq2URz7AQvi61EX9ojyFDTE2+YKNf5KGOSSDmEZ0xna7MIo+NvSE+9sba6NeUBXV1S06garou4kh4yfyjRkvHkOJlLxTe/XWZlxOPOcXqs+ZONmZxx+3TDpsgmWR8CUUyixSjbyQ8xmZnAUsPzuU6jzZPnYKtmd7HPASC3OUV2mJmdHVH8ZqTjwKAm8nNmxeEz+x5ukt2VWSIsFARS/2Yc7p/JAfI9rFrQSYUWBT7gQo/ISsgObMu3bMq8kSjNn9UVpMDbLDb0mVCPa5QhxyWeo0TwS0cpp4F3en6YCppNnUkGQTGX1m8a2BQ3Htq/nko+peoerZWTdcodznRVK5ere4iCo0N44FUAEuSh8MuckexOa2M4/Y2n9dvHIIApsxeXQ5cIhQh4cjfpFm1lt2LD4xUACu9FgWIzEk0Xctfh8RGcnIWYHYYYfRg3HJLyZmL2T0nYlrGj5HsFeetFQlkxBBaq6tTr01yZVsj9oNf5h3gUaVSpFf9EXwp0dfNpAMVWU55I6680XWGiaVCPFCkrrdjpJ8z9p4u40Ex0AHHx9hFvWG9Zd9+2/ycs6uupq5dOC9krg5RKUIN6V1QhfvQARQQbzy4+AYM2bQdYoWA7iYjL3WLqQMtYGECCBNwWGnH4Wb5WVzKTALQIILKVO0QO9BQT5m1zT96hWbsi0/x4SsXl2g3DwTD9W6Xt8xXAh97qlq3hyomQhQhKNXjzk8seBrCHDrronvwiVmuEyKHRHHVNMXdsHNtJnTyfmuQX/yNuWeeC1s+kanLqd59wTvnZe7GrlZ//ov21taKV80tRz67fDvf3C54u7pQajncIB9lcdKxMfNgnWk9yClT6rE33pn93ddodqwl7PcfoQiBlR1hutqEDdITvIyBZbGNM2mXJk7Uue2eZ49I1P5e994AAEAASURBVAAolrw726syiqbluM9E2V5xo86mx4GmV/7vhae/pAyE2S8Jmct1Xu/WQjpGLFche3uuVHGERmVM3AdGMCq9+ZS1Rcy5b0wfGrTlr4ss9nQ2Em/8N/8ve+8dJOl1Hfbezt3T090z05NzDjuzM7M5YpEDQRAiKFCkTElmmQou2ZJKlF3vlVV+9V75PUlVtvVctkpWsGxRpCiKFCQSDIAQF9iAxeYwu7M7Mzs559gTOr3fOfdbiiJAaKEn6S+cAmbv19/90r0nn3PP/aJIiV/5VdnoeeQrp2pqVbCT/o0/y6IT88h04xMBSchYQ13ykc+mU2ZNNU58BPc5AtA4KiSSJa+UCrCCDDaPAJrCPpA6UkDWJMdsBRpTX2NCOyaQcRSzmdsmJ23uXpReSNWrV0J4EgEUpbo6z8Dg8hIGiwocZIH1J5IyQBsZaoUa5gik165KUCAezi6FD7TJHfBRplJ1ubcTJaImkJro8vkvXhDZV99gSis8bp9nZVYOu7qMN+CZHBNWQzI5Hgwni3ZJyj/U3EtAKkbhDkptYIB0FlD2UUXP7TVTze5eLFpUnn1mTLKqFJlEFYYDcqG1xOCR0LguTjSvD5hP5DjhmldTplSNNzUgJD2vhQUVSjpFYYdD81C++JnPsPX6hjcuL1FUyPaF4LCgd1E8IZ7ZnZ0FNvCEGCOy/8ihZ+UW4cYidzjkxfyijVeuONgYDvm3hF58BdGSwMaLX6MpT4ETW2ULocQ4zA47iXwIGD5ERK8aUXi2iK5s6yE/2i/VI/lzXluPK9vl5eb1cAKDkPIY2obJoZTfxYSQsZeReYbMO74fTpMSHLEeP5xRREiQQAwgMENDwtjSDheGwlX5TkWWviHT1mE8tZ4oEwWrqTU+LhKcqWHsWHl+eatmSVhKU7m5K+z2Q4OdFPCYapNwjkCZYDtGcBz/ps3XZLx4aEODD4OVUS2LOXyGg2yW5R5FbGrG/MbS8DYqTViZj0hEMILyQGFS9jEbVI4onPoHADqJ6X/8Vpkx+STmbxv1b4sewNQs/kDnv7NJf/7rKnVGMqe50vhBN6U4T5kp9prd8gmeDnZxHvHwgXbEQSbW81sRybKOA/vNqVPyrK7u+b5FpNB5bBfN4mPGRf9THYXNkthdYD9vj3tizpzKOqmAIEAnPyneMNfEXdFwC1geAtTl1Vcv3dTKUpB1YM5sKZKA0xCRvNkPgMqJvzlGMQKOolNQmVtvjvONd0MrBMige7HXfHaf2VmQw6swgXuodev+zC3QIOwzN2855pZUM65tMJVdcrt0iykZWPjKSzS9Plcwx4V/v1EH9cBeT15HJYgN5C5uugo9meEFawFW5zv2q5z7RwAwB7oDFlnetmb+h1Lsz/KGXvOHXxOR/cwhFkeY3/g981izdLt9R2I0isKSmYtWm6tsiwbu3BDxalE8BRvvH0RgfwjA+lublv71e8VRiiZd1yqHSVV6vNAgsGLGzzl7cBH2wdRZmLPxFkEppLjNTcKDXt8QUnG+8Dtfi//M03JDDVsFH2gSMx90B/w7JoPaETHb+qqhfHZTo7qfnBJHz5KJKgdLLRsXy2TZ6VBkibiEc8KRvU00+17pb/7FXcI7NaYjCrTbvX3yHU4FaqkQxDYZwi/K95eVprIu92YsL8GhIf2J9A9oCUnnS/+XZ4xvt3xpxf6CIFtbMEX6qqbvzt/kvHt902PJiu64MCEAXTYeb/30bppSqC3oC8RgfGZ7QLcnRpOzC9WQlG5XtEC/bmJVFh6iZsGklt91d7dIoEO5kfcAtR9zzKIMvg9zDrI/9bbrqSc4xCqooTiV9etzt+kZJwK6szPxyk1RizvapRtP7Otv2yVNeTRqQVKxnlJNmbTorzbtqQKO47c73gc6OgIkK2O3oJwBW5u+cLCE3VJwtp0arcFX09omvzOwGDM7aUFJAEMlk67aC0NQPxBcCa0OewPKJ78YIWxjhosLs1cmi+3SHTQSpiyVHvzyWbqJkAOjLQvjzmzArgl1onpukwQzJ3cGZu6IfOX1APgHFfzwRtpII3o/NfRVpoo7HzvwHlNPJlLeOLaTDvjCwpt/PnfsiHyR9+r18aGd6nZFJ/midUk3t5kl6AXhLceXvLpsyij9VGwS+rHEkb79ohicALoDn6Y4I5ae6q9OaZk4mOm1W+jI+PAyqun693dVrbLNnt+xynhhTD7rc8ZhhpD3eUubRZnwkVSWTW9e76Mdqi5KjU+ffleQ4aEv7gOHKUvlsmmQggDTNsU8AqXAEXtvYVLQU00dMFAZNu5Rb5dpVxLzLZj1b4uno7JCunV2Xv29c92/+rC0uRDtxS4KQvVnxfDbb8drkFCGzcECpB1qsFRmH7rG0hgc4tTVU+vdT4iiT1uydktqpYQJwC+QG23GFoAbFBdHnjwmbfxIBfH8BqFEU0xGXV2ItYWsLocQOwKYfKNvDdOu7i7Abvfl+id6RdZUHMgtaMgXhAdQviABO8uZTKihjIXaJ//nXc7sa9l2Z0JmXd6htDoAL6o9EqEdb9zaXJ8GffLQ5oCU3zO/+MZL0u3YY/g8Q8z+xpS86vZUTwF+n4M6XF5W09UV/cxT/O6aGBAeiKFr0RgKgqyqGjgVqGk1qzNsTmDZXfLyjZx2ymYKb8kODQ/1brtVBMqAzMyMnJ2seRSkB6VnW6o3iZ7RlKQ/iJHvQp+b34iU50qep1rpFB/y5UbthiweImCkW0PLSqRNe3KWRlZ9TBbvUCd1sh7bN0bbZDAD8ooOUJtlSQ63/K98bfGJf4OiCEbspO4MekkNBXgfSBUiogFAO0jsj+D+R4ApPn9auh98UjwvHJa0yiFZ5TlovUpirmVDSkWhSmoSccEZdh3MFw4pS2oZfBsKaMtDJno1IXb7my8F2htc1VWxlMym59ghs7tDoz5MM5lD+aYBO1/lDiIS/xTlcgUg9jkTqZFm1bTZEpGUA/8B4DMuFs+O0MSZ1ngchraxrNst5HVWsURw9dYUp2BpOJ3QQgCkCFTHr1aG4MYENRWjTVXQdJaYB9QdARuQ2lKbTqz69pijB3OHYTRS6NvtKC4gOJ0/qzJE6/46knMjJRYarEqIXPkEhY3x0wJjy+bJJ41bFZ+e84n2n2rOhCO2fmbJg35ZHaXcIFQ2y63XXnkn8jFhL77FmZa8DVMtg++GUxG/q62ljePs7OubeLgjLKcENjZ6rydRSYG5OfHBW9mC6485gcXzwgBSE53eki+HNAZUF6GtYlL6WECWKMuQS6B8iG1QT1zWnqpniCXEZ3LnB/UUYqmIuvDCn0TV4zUgRwD51rwk3f5SjmTJDXL13Xel/UhJnwsWpD5WiW7BjWMqxTi3MCi/WHSKhjD+EyNzNvsLXAnJ1R8ahvSKQvEaiU7hMHNeFCxhOgE0n4Yuk8sWb4wTA7Rq/vIFx4JEPLEbWkIE7vCwZOfAZoYxWOHtUfkC6xLvn5SiQoyS/K4op035w3gyCMq2RLz3LZi8tDMvx2DYm+al73e9j4bitQh5qzVoeNd/bxqpI9otHjSe6GFB+4vC6sn1ALo6b/3hmV2//Ji0sYzRBmHUwOpqtK1i6epgivnWN3/9nunSDyluyIBfF8VeApugzYo0xXDqxlDVV6mrE5QTli8jy98td0Vp/VH6mplr00kKrik+tYybG3L6g0CuQXSDKmRCyHhLGg16FpoIwK2e2ScDODoth52K0taZx9jyLvbd5NyPAO5PBglhbRgJMLM03Fbfaw7JcCEfjac68vyTNN2XLk5en8MjqnIMfTbjzSPdWsgNAme+585M2fxo+lznl39MEKGoM3LemD3KT6Bx/Mnzs/o7Gl+pebjD7Kh6At1cnTD7VE9kuL43aQ4FpNt4ysRd4u8I6u306+X3+wG92f10tH1iVSZHeTqMhTfdf8jc6ZEzDcQZ+F1nlZnCh01NJLClfzRwgNoSbnP5onTb1S7+by4EULlQ5qBSrGpi0OhbaMAnHuDQU7zbBKAyyAqAFzGF6EMWfyAGMEEfyqPnJi0PlY0GWK5DjMByFug4ludjsTIXl+IvDMuKRutTR3XOZHwdLXJvXCjZzNpb12hGDrbJJ6ysBKr0uTgZRHkS9uFrDD5QuGxZYK7fxVoUyeW1rwf+Li5loUOOGxriT+03zQ2OY7i2hhBzntUslylyuOGNQUY44XS9JK+hK4tkcIaHkprd5Gujxm2XiUCAxt3QJr4iH8ETHdXkkgkUmGgdp2QJLZtpFO1x2QU228lIdt0QRgAYJAoehXKlHdsVrztOJU4T00M0sMqqgi5lxKhomIvWdQ2nWV5ZuTuXQ+FBZMnIHFlVQpoAkunSpalbS86yELTtSDSMzsfHji6IIc3LA0gvCJcZ1FoLy9dG837mE7lgMYDEIEgFtqryLf3JF7XKt98fe+a4uKcArCaSzufmS3JEwg5eM/X7nSxK4YUZp76f+ONPnzLrr1hjaeLcUAXkDdEDpzZhmWuD8xEtCy7ETX4aXk2AKcA3WFsrbRa8FURdME3NluTmu5+u8mqtVl6w6MEmQ7QK4LXv3GZPbSokyiHDspLwsqEhgBGFUcFi0CpYGchRbU78K3ZZlnbulrl92qK0fOPu3TKD1iyHduGj1s5kVEF7XFgMcM/t1FrWBDRBjmNEED1tZgKdKyt4fk7OlNwcWeQyfjIAAGJZNVW725S1ZbPbN/oCzbVimwGQ3toaFURoEiYy0UrJCsNHCkBfvu+aWsV8Cs9U11IXX35nJ8bOGrO5aqLKDQon6ggeDlyRMyxr/d73nA3YbXpSNLpxE1Zj8tmAG63qxIPSbX5Oss4IVKrnom5vWnDGYldHh8TKrAHJJ0xMJpfWfegvADbq2KgPzAF4+YF+z+qitGHD7C4doyCNSi2SgaemihpVHCHIa2qwQ+J+FdG0mCmCZkCbRq37+qTtcXtBG1d8t27BGS/KzS4ujo7KHNUcLV/pGYsh21H1yjPppVBwNbExJpgf3tOIMVegRSa8LPVgjqhUiUuYsaeCC4VnxHeOoXLB7OvKOdgl7cvJhRfejHeUS1AaoM/DD5vLOnTtuw1V+1FXhTEaz8G9ZnJckr6gHb93aX6jvV2ukLD89k5RmduZPvwUjf7pEZG1o+emD/9ckcUZPz5hkhZfHm55AsaoXkDYwt27cgd/4Pd/c/oXfjV25rsyJof2p70F6VCdiOXF3pmC/eHWT++VbtkkYUD/JNsJKWm73N3PxSUDDVhZWZ/adK3doRn0pQJrq9/+07VP/GsZrpWbEzru0usjuK8RqKyRjZMElOntOmTYwAVg3amIDBXRLF/HuzQ0yM/J/hFf9y6JKNrlRHgDcTtaJzoYiONXfVjbM8sBH3Wog77jh+Ru+x8wOW1wH2nLPbk5wkW5kPwIJijJj1wVu46ly8DchAl4HDcTBEdCbGtTUavo8v7QErJ4+q+vxU9wT1h1kngB4gtAB8KgeuklabPa5Pi6uc5OrMrav7VovtjuOJpwTfCavDgA48frxRdYS+wQfstBWZQPPMkalQJz5F5FbJRzEQuCd8KkSTfSGLYZ3TYPaPhIZYPUBHtnw2gtYfP4YybvQJOrRr6o4whhr1I3PBb2zljwvMK4KRW+KlsUe6lGu8eLzAK2tvIoims9HLAaNBDSc4Ddna37VnKxV+2yc/bJKJ2sUn9ZYmx+8u6WDWDwbjBvmJESuRQehIcm5HoHNu81fuhfmPWk/gRfs5qWvWrtB/qp9BJ9t1PpsqpClq5ZuYoEePRRR5vAQfrAjnmLwut6bZ4mkVgzeKhno7pu2+4XL/nD3/hz42UndTQlc+f8Yku3rgDH73wrFQ1svf7CNqYZMLrx4QJB+liJbT6mLdhzblgMkMoh/ZqxhH9wLnJYmRqK09jLBkJwRGSNefSXnBF2TZjL5yhqxj0GZs1uIrvU0LNMKCtV720AYXPFnMLRpg9SRm8fLn/T4D75N3w/JFVsHmuVbbKL1fgIu6Uo7FHRIGSyxuXfvwMgVDQdiMy6dj+z94rJKzeV6vnaTpuCWuO7JyIbq0w5zn0lsbyJqli1GVEt9OBB842vS1lGYGw0sDK75XcSwN9VM4YXBrbV0ua+aZ1v3hGmsF9PddSb2mJnxomfsUITlaGmVgU9dDU55V2DAsTqfv11p4LBFIqMEr9FHr3N3/pToCmX/MTmESAJ2Y7Ann3ucEVsdVXuRikOyg5Afa1KLpVQ35L5nXXp1o0SoUU+5OBHwxA0mzSdlZKBARTn7WROnXVbF3Pqgulo9cPWgKWZxLk56NpZ+LKe3VM9P3VlhjNlByogeAJ6pJUCuDn2OcxADv9RAQYW1wf85ZT5fNR8/LgcwEUY+ZuXTYNiHpoFVZwHhuXUREZ2qHthR9rw2cvUudFFcRy+I7/dL1gmcL+9zZvfZdKk9+yqmZ02Bw6amhY5DLjFgt5WuRIIiZWiWpQvN+YYOUv6dWWVgr52YcmV8+Kf0QVafvy+Y+PiO2f7ALnbiCF3DqcIMAO/ui1Kr9XYCDj0XhP0BPouic7KjrRAzx2tkJua/YNvcVT86QfVXw7WmfC//OeEZoWKctU2uH0b88Cti+GEk5WVhY6CYCgaXqlbirVmY1OFcfH4NtXKKXb7QWey2YwUxthYXzh/N36oUU4hW7YmXfU6P5WVQWgCbi5LX6AGKoeuCPUAiFK+VH8vwkbKDSSv9JA9x5lwu7CcMy/AkNkzziOdE8pheq4Ij6+qdUIiFaWSbFtULh3yC00YN96w8a3JIfbMxIizBSMjT/Awv0l+D3qD+ZW8vTIfjnEqhg2rLwF8Rwy+1XRZwdXaGm5sc7Mah06UtyL50ErOVOr8X4y1NKaSc4Invr17hXY1wT9nbl48QjaPizCX2qXW3Ar/WEzuzNgC12+YRx4x40tO2jKX475FjeAr371BaZrApx6XbvQ/f35leDFG5BA7oSK9PDSd97h8RebqdfeBfY7BcPyY2aRA/7atZRv3rWZvrria9WPRa1lnsJU8/S1hQcef2DS1tY7tjecJF7LVlTPZmcFE2T4KbChrGRgo7OycfvWGPLSzJOTaFPsEiEZllVdZkRN0ymbT0yNe64RBMeIFkptmtF96tnSaCsR+ibRJFcnLu/auqNRdjxTKE5nBjt1yBifejeu2OpPQNG+rEtWTTYXzAtDOmT+Wu7XW7sQf3i2MB+Bz8Ecwwtbjh2QLBSn/yJmpvvWyUDBeXyvdNrd8bjZH9NjZvPTCyL5jwYDNvfRjcLIORyK90pPBZ7OPjHBbyWqb7TVbvdIuZm/udpPLQ0VCm0BVrLvdVByVdt6a0DgmLrB3n+SrLCyEPDscuUuLk2cv+j6u0wcVwFCxtXRmY00lAe+kPBqA0y8s3nrhNs1dP72PUmgecYrKEAmGwOGsbUkoEiuiUpGT1MTFhe2BscDuZumGPPR6QvZunlrBMY8naPUR0AbNyap12FfxQsdNMDY6N7BSFInG8XwC0Rgl0W/1yIzXHPeESaNhpxKA/cHCgfyChJamJqMx7s3Pb3XJCHsol4atztYCWjBalEE+kJEE0Jup/Navsx/OiTy0X3zq9h14GRazWaKYnzEXhqTaoZqg5PFuv3l6R/eIjzSVtJwIvfQVUZye+xdEvlPJjeT4mVEOR4dShQWZ6hrhA6GWUg3WCZeQqpjRWEXjhvOB8BOMVVgNkMk++cu7TO5qXkBu6HF5cpvKXC0ydJHKTTM/5SkKSrdYHLPKg7OWtDTsqHO9xdjYI4IMd65tN7QHraYjC7e2Ewc+yW6v0i1rfRm0PoL7HIGLF0y9cqS1SYNm03HUePSQy1nPLoljAEoQASiZZU+z7Ichv5HIAMB4Q4VmR0XAuXOipKjenFNXPHFjtqIJU0Goz8yMmrq47t2jFru3T+jISiikTP8tw45bwK3zkungVnIbuSsPjUbO/LfLnDn6TDF+aZfmcucdOQzPya9pDgSUaZOTv5PU+Re+xQ327JGb4caegH+gJ6n29kmfudRvfvIZOQVjsLyKNuYPTuK3T4k8B4SABk2tNM1eygC4hA9Zz2conpNJbE1NCRqD0YyH9cN8nhKn1AHbcoIY3GYrbb6rDPuzpUZ2OlLunbo0mBm56a4o2xwTgSK7b8FSisvkSRBdKMc7MmS2lKXAikco1iekLV5U1IzGRmn7PAVN+jEE44BQKLeDVdCC+bkFvmjJckbdW6P9OyimyYzRgggmZ0yWBilnkYveCzKv2oHRVIXG+fvent//BQZNcUIAFzFzjjsUuH5NPI0H9kubL8vsGJiO6hZi9lBh3AbBqErwE59OpVVBKmaTDPRfVrCrNM/bXli85ikoFcZekZMevbsDo7qiyDWXlcVRPrm3QNL+83f9ZWjsHr6E85H/hG/Zo4KLXDm+meGVSJ2o0cIn4c9koI4PymFTB3kITIm0UVZjvTYegnWEU5RQq9X40UdmiKOqgxR8xT7RiXRqjei18ge0bqt08IeH7OrKySRTrCLnFMIHeRtTtZFrx7Uzv+sPcu17gdmBr5+7aT73Y/YkYYthU60oESkxKz1GlTRTSKm2drJKnAHzVUXwppUMyzWxNfPQQ5d/42Wae3/+AMx/8cb6gj6SeQtJ/pUAY8RQM8MWH8CQNmNqlUarCgTzeQ0gWFXUeKDeE0CurcgxX5jY9EWFga8vbMMb+AFoHIKkHOeKHL8HUEcK9Ud848gx6+bdWM9EfJ5CzSUeHcqA8pEih0hZvoDTslZJLE8tClUFnEyY99xefkC3BidjPqe4GKjoYhEeuT8AMnptzqa6oJZU7yvKLiyusE2belU2RhY9q6q0T3uSywl0k+PH5SIcCtzznwawRkr1SdSnOUUas5IYWgxIiL/DDvLimqDsrPLOF4x5GCtUGJW8JL/V6l8OF+W3+wWd5PvtLAay1EoCqOIJrbhYTDKrV1NYAo6hzHoaKhbOxR93+1HZGyS7bVI35UdK/5RqHQXa0GTfO+b55+V32DOqAze0PB57Y/SS0aVE5rXXhN/DgegDZBbMZJ8Zkbulhie89fXOJShesKhAMHa4VbrBUuWG8g6mmDwuqKXB8TTFpkSA9ffJKa7a2rJuobmvvVFEHDG3ztHLYzEPduMEfFUKGcXayp3wLh65+oaIK+A8lyQ3Jkdjo6LfE0WmEIKNA4BHmDca8FENLGu1f++ebkwOT311YFa9TBhyBcCEvE8qnfqLb3qJjzG1b19eX0pFS4ZCLplwNwPOR40PSDf2aVtOmzMnnbAD9hWhZ1VhN+a3wmURsyrixwwNmypqkfmcBS1IVl7e8rMrl8yhgyJLAVKw6oJeSIfQAUAyxqWLjlD3eJs+3simJY6gIlMLY5WQC5Cft3LySuyAKsR1tSJjAb6dQaUuBcLWWkGEVlAC7tyeuCPPqviYBnx0TAJPFWaXVxIvvsbvOT/2OC6mMC4XQlIc1sd8RM3Vxevq7pKbt6unhMgYqumlvvCDe+kWPJEv7jUbdq+rx82fMzXTsjnJqZPfXnvo57cdPcbnnbq7WdasX5dMSskEBD7yE2DKgsH8dv2izM7CpeG4Nfj37fOdOOLe2RKbB+js9E1NSyACgEsxkqA3urUem8vfNHt/XNtUtvRWVSgVgBKoqlRfsqoKnwAaW0UcJMEwUOR0+X2+MjhitO1huSo8MyhUILFTzB5W6FEaIeJsbJGXl3rtJLME5BOGwb5lLgCf311XK2EKXWXc0JWLghNtUA0vP5p596J79y5ZMweoaqU5apAnqaRLZvyu/L65ZLZumNZOE4DTApR/KDLFiBZgQ6ri5h2QZn7WXHkVARuKqy5QXeXx+p168U1Nkk2HZ8EunWpuCYIkcC8AG3VpueohQWnJxKjudONX2lH8HL4oMlid9xLTKy6WTat4ZO94uKXch3KBkcPbDU6GDnffeaGHdsvPnRAcY8btNC3MpzaTPVeFj3cf3hZrVi0QirYH/Vn5UqtgMRHFxQcPyt0Ab32VCAoA02hjw0s1ZTuV/OjxhtJKFJR9hUuAJ9b0pc2EBuDSYGdWuIfNorzS5z94QJIJMfYAvC1cYj18YC/Cn7Ydh7ExX2ujZwstAu4Uys1NHf6kNM3O6ubydrg4vNa3yhHhByL0QcrqgN7ozZr8Q5sCNijiufWO01rMMMKYNue9IF4Lqty4YZ9DvplovroGwocMhxh5eYbxrXdDlXEXQ6fR6XBrNfJtpE+YecWJei8mqM04IQQ6M12K71pzU3OfjNDhI/gQI9Debuy2cthFwsHChiUXAggjRKQyjZUZQVRlQe5jD5qgGBQmeUt6oTMSN8Y9BIyPj1yYZakwTW9pUZyK4KQwWB6CYKKhzhdz9qwYaSAbMWEgM2cm7ppbqq7BzGG2iDkANABpA/6244LGLuxqiM7G/3nPwupAvNWkxGKXZe4FBYtXz9PEu8iKMCvfTp6TvX0OIgDrpReqNpu0axaLPGH/fkdl9FSUVhYkD+8sWBcEnAm/i1gwODvIP1R8hG0DlZ7tSJ6HEk60UbZQ3ylPDzzcKPHyBjaIliPxQ4f9jp7KsF395khHl4ffr7y6gR4ZL18KahXFarK7oYGpKbkGZpjJLrzVYzf/Sa1uptc3t1R1npj2NtSmAnaV+PBMqKoIBwTLQbkoUEnNg7S1ewfPTNfvYkWkvAJ0xn8MsA2PpVfNgo6uPOj9QLUyCdKL5L4HDMIHXIRw6lNNtW5JZkxCoTDH8pzt5cRAv7Rtmh43VFklfynKo0qW6dwt/MDLCnmAkQ3nzg6uFe+v4Sh+pCA7PmnUuRwuidZk02uraXZVBBZ2xBF7SJqySZrqQ3rwgX9g/Qv6VScahNUxm4GosBciAvkrvY4sZuIbGpyl13Juy7z+J+bRz0oTu8Pne+uGtI7sFjNj8I7B1QMwlZReZJABTBQsEWHrjk6pLf3D78hS8B3gEo/X5YnGGvcLHyubWCEwqRhkkDcMuIp8c0UvfN8/fLXbY6jEXFMvGCW5V0gBa/r4wuLUntHR35hlV03TtMu4Vc+R2ihxU6iTBGI2NTT82y65vD6N362keOSoDmvjkrnTb27rZ9TxIIShcZIAIaBObqHy9r/fMf9mr2Q1AXDv3KP78RywOZIck8Dl8bp7hTOgCOCksKolCAZecsMfBZyVEUGbmxPatJEl5qt0VwZUARCtUBzqDwYGQJso08dUl393XUqMCo8wRmlJW+/5w7ujaT1SBufI4aSnocYFC7D5Vr4sKp/cFLP5yq2ckrzsRmZQJwPcJmEkUA0nBL+jnrUNWB1VhAC0zg8gEOnxDwdINaUWE3eb8hKrNZjfP22e0KUzyE8ABjm34gSvHkMrCpsaHSvKbcKdIVYQDDiof+/zj/c++znd2JulRXWvCAprnXE1mbDSLjHiM98xx3krzL050VEuCLM2RdPmwhkp5CE+LrV6U0uOb7tDs4ysowMUJ4kCpFDPq5SDJxbE/AN7umUbqLJSRyUiGwfOpyLHQ0IUOofGJWXRMKlHbncgqoydO8A3rSh4iJS8FbM4aQqK5YZVj5jsrEPWHXsp3mnDR1EsBwyn272Ohw1huKvVxmTC7j75IqvWw0r6+/14Im2mE5EldGKbwjQ3j0U0+sqd6odVuUSa8hXXr8tDEU0YMzrDyTdO72xlw5UxN5YnwFa4i0vNTzdK2+3ytOgqJoRzjttXXsZ2Oq4qnXyPZ+3Vc6Qc0StMCA7bkqCNzcpbXzv5lYmHHhN+sXg7EQ6m7E7Eg6/crX9IU61sJGd54dbpxWBURG/9ESK4Z+3iWsmteuqIiFhr65KNAGsfHKLbysxWfnHA+FiTC5dTomRIrYSORsMH252gPqduktg57zhoV9dW+mdieEuA/Pzv/d7YA3vWzUJSDplKpD4WBfRZV2wybhehDFb7/MdXu/dQaXDTWVAZifoIgrEuDqrAjmK0rQXCFBTEAw0HpWqsnNsyXdsOV2a5wsKIp2SykIIQJIkU3GI2N969STv8QHf+04dNsVJHYiMIw2TWsEIBpHcwFGhSvrm8LIudqLKoIIUlcB+okb/5+tnQYw9ab7TE2TCcuNCqp0PDvX9yoe1fKHODc0e8+Xa3N8HYHbGUROVS05fFP3wIAONkqK3a9NRTghVj4wVUcgfaj4m8tEOHbUnGI8/qVE5cUe6h8r2+j299FepIvHGOK3wBN5UnF4ZW43vgISbv8QM816Maf/Ktd7wHu8VKtzEKomSIqd5eedDBIgp1mVoVBWSBEp/8zlcMC4KBxdekMFqfIIDpflDC0ZUPSJsarZ1b5u6XXNZ4c7nc0VzHREdHRA5giGJGAuNCv8snr9HMq4pg80Q0JU9sQrYIoCaHLf1U32VIgt0ZlktSlIGatk6QAPmcZWVu0Bv9Cy3xSKFZWag4Xkd78TtnC/ZUQ7yDZ2D1gsaeuLfuMI5CTLE6wz7gPAK8KCkJv/nW9si05FgCMJbNjJQ0BBDR5ODpncXZTwOdhakBcJ0Q37biiFljBulsGdSRI6a4/V6dA5Bw3snPAEshRvDZ2nUUs8GmLaiUu1FYBeuLZ1mLPRBwN9S6rQbKE12uMqsrbcf9mzuekL84JPJ16eSUvBquKCTl7ZUzb6V+7DEZhJ5TSx2B0c35RIhYKOBVdyguAIBkSxZ2rK+XsuIb4H14eRtt3kmmrvZ4jwjH9pNDiGXbUC/9uYFEbiuLcoUl5rB3XG2t8wn4AuBa8NVwrnRryefvR/AhRqC/z+x7RPpnWJQL0lJlTDUnIiLn/twcflJODZGL0Wi+8x1pl5SZm2+L+5IymADR4MVZ2TwDqKsrIhqAywZFbSBVsy8uiKE8P3v+guvYUccMohQQ8XZ0lpTyWEShMli5A7EDcmLUtBCnAA4Ir7egRFkfNAu/5T+gucWkE2Zq2JTpO+x9nM3Roy+LBA89sL9kfDFxY5B2dakZnzBnE+aYKtyYNmXdpatToiCnVzbCLZVizAOse51ag1GpuiU+vd215vywnIEQkZb/9ZT5xSNyODuV3trMvCNsTDxC6MrNim49Q+YOG6Dcy7baIFmg0vFaiIpfGUprQhRWX36xzx8LesqF5xtf6s5r49saQK6cupVYz+LAsSsn07Mrv/0VQ8oLwNiXUvpi+zbtd97cPnBs0Rtwby3JJ+3MLP3BN7KHdsn4VORtDl5PrrKsntyhS+I0g3atg4vomvILzrwPoM2W6898CjeS6/XvsMQ0HRCS/tswgm2gs4f6S2TOMiGUhEwWQTpF3298w8ywcwfSQy/kdYfXTY7aAji7oNqwzYeE8BsbYvuLTIHSL9yEYnrCU4BsztBwxVw/vk2B101sS5agAHzO6N82DvXn9/mDiq8MSHhbdXMwg5XgUSEyMxN++kEtBqu7NWKgS7qT4sPwyGu/dfYxm0WHYJoZ/8LnRQ5mVxJoEzG/IwlvT1G+xdFBwtsSnBGcE2xy4FH9d7dbLAQQCUBCusa2SiuSxQ3ysf6meG3vwucVhW9fMS0ec14RVa97/z/7EQg5smudJ4d5U+YJVsG0AfJs2QSvslraQxoZfumrpqVdDhdfNnsOmEHGDLlzzHgKY7uPSxsl/NBSzjtnm1QBzJ0yN+44myjMIRC4Dje69uN1h415dVYOfr1T6DWvWKkSGY282Ftjwkfl3O5DJrVo9tyk6Z8YqLpxZ/mbMiq1eBXWJfYimPF+gBS0M0txXFSV9s/upleUWgaBpOUGbPBY9uZFdAEylgCkHA7MbR2uxyvNGWz297vtD/1W7RcJefp1meWHjpcalit7VY9lz6T4vE3r8LFh0uiwq7ioqkq+li/1shS8rpY2qqAbsbh47dpVOfrjdz4oDik9/uHgltIm98NvUrFpWBoKFLOhxoAIz1d75DCPVKeQ6Yb7wA0g+bBR3dnMLKMJSWRpVc7c10BpR/njKJffP/47GjWPU75H+vhaNYEKXdzOS9i0PctgyqmaNhPMOHWE2VqXDdjIJLYONiZndsrxBGNf7zkoexYD67rUHue0zZSA2ajtJKdwk6AloMjSB5gaEfe2VkBmCoX/4Y4F4O647uABVoudHJPIhrWCuHYN62vdfPt16fmJX2JgnYKjYViH7+pvv8nP3c/VStYW3pUkrgFeaUMYPCYTQJ49yZCqycmP1vSyrAQfPA9FgQYwOXLCRZ5FM6uH+CLAXxQjABmJ8EEbg+qyyUBdlakuF0Eox25XaWkQfgnEYi5cN323aXqJNy3Oewmq7++WU4lNMpYcjZ/OZFghL1XjX+md3H2IkRekh2yq9hOkl0kpOUCABT6bTU4IovvikaqOfA9LPoDZ2ambS2XNwqTCJIJSPQ/l0jo6MlnNC5G7hUtIX47IgA8jDtTcwvC3Nt7t215sCetKjMUy5y8NDyTrn2qRbqMjK0vZmI0YzM62lS5duaDrujkFLmPn2Fxd7KiiYo8Wzamr3Bm5tFazN+5MWcdu9PjsiLAzF8E3Ztk6bjkuKvbW4ftRdWSL3LY5wQ2AxWwYiuzdorlbwZMXYTOB1lo5NTYurHRbR9tlzr8wfvDn3dZ6/w//9ta//8/tNooyenKwuiXHJFQm2uj+o0+aTDOX+uOPmzJ+l2GUlHQ49Oiwo9xcv1FFBQWS9ABeMpNx+fR9SO1goGprHVHHu4HVdoQxOJllqxJhWZFQ13vbcS4wralU9uIlbuaqqxVbi2G0kZPSUtcDx10WIdU5LL5YumHz5Iapou88CCUeY1IR0vPAYVnUMDTk7I79y5+TXRxWh7hKluZr0EPamAogJ4c4SgAM72to20rXQ2+YLHUU1X6I1IqlDX3Z/QPg4nyC9YnwVqBQZ62IfQCsyGbDroS0A4VgderqDZreJx41o4NCYh1PyqmcJkl5CKt4ROL7rtrSsd6qchlJXkktQ7zfIGSubuGanPeIT8TlCtuF836/q7k5huNG7obx5pKUD4Etd2WV1JakUiXAJfhorH8EUQoG2uAYo8SKQXI7rTuTUz7/HDlMeAkKPV7IHN3QjtLIsMmwOZHllpWm6LhxK0XkDMi1zDUTCmCiMD53YeboXBVma33662+XdopJI1yC4dIvkgIzuK/tEopUysP+pn7/xT8ZoFdXp98b9E0PCo+Hcxzp1FgcPDUoW5n6CSfOKxsEryAliwyoHmiCPm+gq0YexEDhLrG+gHTaEwtT3Y6fPXyIVeKsUg4K1dbm+FTFw1RG8YHoAO4GE4Zdn39XDltaTb38+xHc7wi0PEtZG+2Mxlgq2qlLxQHRjpbniVnKqYa9JrjjaDq4TthbkrCVSy+CfienHCf26GjOoUNmTC4pMhPCCqAFnXQX/i8r6TgHMkAsIDkiFWBmMaI0TUDcKDitrIgEA3H5QQhq82/cGAqTlQWxA3CAqXEYyMbvfoej8K/8sskWiQ8OcGdzymJ3X5Fmbo45z5tmHWUXWve5U/FSURNHZ4wrtTM7IGy5uMxNhrx7fCyr0R30fxw+3YqbZ8bMYZ8p2ZCXlZ7F5HlkEeMAHBeOUpYn7fUlsy8uGb7kyAPsSVbBHrNKfNRwzymK3H1D6BoWtbqYyk0n4p3KrDY3iXVb+cZQxCOexSk8KkhAc+2KOdZxT/kflkBcDAc8q7+o2st2KRlHjkUi2x8/bHJ8cglc6kZPKldvjKjnWbwhxh4AP2ZKlMs7vj759R6UIeW0zWRAOvPajiI8NVwDQgCT+vcH/yBuVd0WsoZAv/pVOfnIxxY5tEkVTP7ZbcqeOGvG4CkjFBFTnRre099vyhLy2hX1q2BIgGpDVtZgh/O6NmYEavl8dLZu1XhA4lSo7ADmhVx8HwCSImkBtI+5xeThL1ASY5ccb7hcrGvyqBysbpC40MhdR1W4crXrE1UmoSKb8H063VAq2sW1CU2rRztTlsaHsT/CigoNzqKZKd/8GxVc0cS0FImg+0+qyv3GT5hQQcDD5pmK+e6S0u69S1VzouHkJsV6jwgvl7S9vnuxMjn+AcCjj7ORkMu2FjcMPNNpqhrNgs7PtqqdNmOLS1ACIb35KbmaoDE5+TbgOP6mWUuK0wQooFZTgOn70qtydKTGvMmqc2lCvULftFX9knlsJ8Clr9dVIT6WhMZRwx0lEmxIvWUOhuSy3Ab+l4rEQGE4sLAQi4m5xctWoG/Kr+8PdTgw9QwrMIuaYtGHVDFr2WPSXtMsT83NJsLN5YG7izGqiKPUJIcoYhoKi9wZHjRfvw9zi7uw5hFeEg6n5VFkA/ffNG3K61w1pvSYcQ3zs5t1nOVlyZsDsRJlfVA+jAuNDkDb2djAfW319PSyk3gpp/6RYQEE1kdMp6R2/eyoHMCGl9Jmg0peSgzQFnumqtZoVjOmZ9lUC88QO5Y5AGf1IgnD3j98SHOr9zVz8LDevUqtO4wl5ScJ2B8vAA7gEHObxXnz5klps8c5Gl/XHrOhJPW1PzOf+nGH12Ig3b0jmX4AnPvCBfGxWR0dNgxYlwyEVF4tq4msQlPSZNJk1ChDS7O7Ttq49ROCpCynTDRr8pTgG6bM7ctyE4DQWWJV6l9aPrHWayKljht+bIToU92P75VuVVHRS9o7nPQh+BTe97TQuKf6WROGfwmaGm/SRNImtWnWIGFjvv51WdOiLzzxzc2KulSIWqL3dB3hnUePSje84Cjf+rvb53UjTyY02YlTsPCJiQsvyTAe+D+fMdUtjiIeCLLxq2j2GHhAONdLNSrLKVGJxInVyO5PcqYi33ug25w+Q3v3Fx8zMdICmRcTri6UOAmZzbZ6qBvusyIyDUi78iPJtWHpFvnxx8WfjQ8VvziA3owMxpTiW5HiPB1RY2NBkAoBATsRLW5pjI3TbeXy3ejuOinMAP0BsVjxoZKet4SMOx4tqT5eFZtKRKpUUhGuId/M8fcHxYRWR75UPo9KJp6z7I38Q6prox+A2d+8Vt+Z67h7OUaVb2aLJxV2zCmS0MrAlUXxozLIehjY08pHejPC1oWZMWJsWglsbTURSGQQlEF/5jOFQvzDw5wJpdavv7nZ+YX90o2FMQgnP9wYXk0grpTBcBKBgmiom6Z61qSV85a35RJO9CpCutbEPQK+AfxhuFCpCfUQvnttofvRAoMfGiCNEN3XdkPTxeFHUQ27eIDByQ27TpyQbo2tYpr/7h/6kBvAiQdFOmHAA5BGNOKpr6G5cuZG7KG9BQcbnQqvfl9mLeFWT7kbSxUPQjwe8es4FPA5rSagWjWGBKXSfKLim8YcM0eGre5BbG/OSiorA7G9x8cnLnyLnyuePyFxd/g3egeAhE/BnIRBixZIXJpvQZkDQKR4gU+rM0tnypMUqjVCiLK/D5zM/tH/TS/X7gOmuU122AHCbPSDG7xT2uQf4ongQut8AUOYLNwBiCsW/Q8PZ9Y34yX6DpjWRJOUCkw3ZTPWHB20vtpUVLlL2p1sHvYW3RmUZAWk3ewCC918hMIA1oPx2qA0VAYwXFtbUfbUZsYpI4X1BQba9EhEKN36hNwk2IugjddKu+PjxrNuVkccxoU1BQ6DvcDMBJ71/K5qw5ISEOAPLnT/wiEroTdPXww94HKy5uEqmK+FRXaOwof3k0iWXyVE6gkHvWwprdW9Iw8fYKglF9EW+yZMgQFvHUO8G8OVTE399Q2uKqtwUaDIVvvd1ekV943VGEA5UrLGxkeui96T3Eo34kaBjQCJjY2RhdSYfPjmamp2hi2+PE2Vgmkjry7uPSRdPoL7HYGtu/dUO/g21IFQRrgDpLox8kogkYCY6DdkviTDFlbQ1W0pbuFPvhv/zONOhgVoOYRkF8gJZRf7FgrqUg7fQFZiCliXH4o12RO0rf6HP15EpGCdaFc7ULpf2gHyn6mwum3qpuWotlE2+LJeFV6AeObYeICSrcDQLTQhT32ttM+/mxiatWIZ50/eLfPcIVhRmDOxhkLz8DETFi5U9FTYRGKxDRUuwYSPLdS3ZnNVqcr/6luoVWi0wCjMu9nU7jiPhcTzqqMHK0UPc68spdJJ8BqAPcPI4dkaWzIE/iEpLC7A1dJMenNZhTBSbySUml/ykuHnVbkTCNa1U3LWzans6noomHV3VEyfF/aL96D7WOzkNwXzP/lzRQUFqRSpMbx2pT8dDLuTO0XKx3g6SoSVkHA+KEylhMjwCjYfu+1ISMb7EuTJ9Qr6bKedrwJD51g6gAHKCySL7ACTeE/b9qm2JNKXsB7OHY0sVfEryu6w+HUxZoCBm2ybKxFFYJzUUYmeOOERmCbcvF+fvXzXdI6ZmkoZ/PzerZbpG5XdTiXejbvT2JOME6eSWe/SYmZYkzM4rKN63JTpR3lUr8BhY5S7yeEHAJOAGwqArxTtJoZGJE4FitSdByv0hRCIGE81syajr17aWMT2zPjcgcUZEpFGB6UbAha8Gt8w17NyBnWKUm/N2oYTgQh2fBg6C/b1jqWkvN6uj4k6UfgxkkpTA186O3hWFOQnPre5mcgMDUl3LCNe7bCi0/qM2Lcy3++BN415gGJGXpNYk1cKoJTmthm/6gCUR0J+uG/LRXWN4o8gicD6yNBb5tBy9QXLtpmz0a/IOFYfqTHlxZ786DNar4OUXhDA2o86Lt833WTGawgqK0qjFRbVheV1ATTJK1cgj9Qf/GeOvA2tsiMfVawA1qdNTljVmAv/bFiG6AcBfAD4TBg3N68TOpAwRLi1XFwwAKoyCrPVNGoqXSXFBSBBqosz+UdWvUP9ObfP0cYt2ULpMbngg4APnkiLkWWZQ/fNwRCqI2wEiJWKGlaqn3fsWeNa9pSUuSgcDeBKXlzYmBPhsro1uzCXQUOxnmdUqKvS458CIJ9b+hzmBXzxqA7CeDJmOHLtZKHnFaYdmx+EHtixrjLh6ZuK6HqRHN4/oER+CJj7q5eKDh6XC+bOmaIHlMBUliwOyYJ7uwofTI+WO8vf4H2EdKYmTakqu/BXRAisFIAFws/gqQC8bc9esQ0wS4Cier2zvluYrAKCY4o7nMrlWuhWFHFuoUzPfgIIzOGkWb4pZ4oKJETT2CTtQMy88VcSKMCoACbYTm9YVkgAp0+ji8eKIQrWMN+WmAAOYGwkoKjGBLEehQZceIidoeaI4YWvsUxVXwkxiYOfm/NOv8hiLa9ElqyaiAyDOKzRODyyce1uuLuBbvKlmDHXr/dekpmqbfKFGiqanu+WU3XtJthp6g5KGz9+yaLoxFk7rZS5jzvr2bickWR5ht7cC2ZTS6dSPjY/nww9CG5N7rCzJNqwP+C2a9gQeuh2Klf++t+ffvJf1g6/2E+vVnESrkrSBYYxME/q/7gT/aONCBctX95hc2A8xE4NBE8AzDCerqQbriqklEiQLI3GWjlVUEDJkJppQYyVgdnYg3sK/NNOJUDSSsnVJQiAROzrdzU12mQPPPmRQr+gBI5QgDXizIKylvze65ujm2zryc+iZPPhfO/NHulW3zD+am/lwXKa116f7/pYmUw6NA/NsHsYlo8uUxGNHHtA7ToKW+djUQNK4s37c1OXr3u1gmV+XlEA1qhpeIKiMJKRa6amVDqLcwpuZpGQNyEDjfdslTO5/L5sZuHbUGexIIMVlcz+0LCYVUgVJrZiW6Jw9hRE0dfvWCbYnxAIRIG1Q6r2n11p+dx+qzGYgkbexvOTnzFz03Lz4WEhFqv9g8ks7GH7NeikphjDYOHOytKUsLCJSdeu5lR5VkmMT6Cny+VrF+1EInJU5HPL+Bg34gqHrf7uw01NvdABpyIT1Xtff8PZcAyTI5WKV+mMJxOG8g9oPaAHgOrPRPAfgH2FkgKCgUhAQLYFE6c7ADclZvvsc9JmX76H8NYuuqxPHUNl6tbCX57kTLzESxUN64jJ9g+4mDgiOQgDhO5bPeCgF14BLMz/199e/ulnWR0t+FAMLjG8XXvlFDvUpVZkz0ue+R9fKT3RYqIElCJyqvmowW7BhIaWqyo8M3OX/mqM9r5ncGctsjxl+rooRaWPtoPqAWss8WhW1IBsmJQAFIcphVILgHuwuJ/6grSjsAg2iCuUpwPIbXDYihwSOGdmAhTRUZOm7nn4m9+yIH/uohjhltehNDNopWVNn1e+ijdnZycQFXU2ST5nLRs8lMmduS3kBj3aPHdejF/sHcA0Pm1mWsO6lDtdWprLFsjwkBGGb8frBLWSkmvNGxZFBU92AmZleMmXIywoJyfrdWcCWtc2uLOZU+VN+/2ZRUSM2Zha4e9HcP8j8NIvfPljL/6m9J96yZQ9ryr3khwmhliNpwozBxnD1h0HVKsjEgXjxVVBoBXnlw+LiDJRWbkENMMZRIKrtN2Rw7slHc0SQnOTJAO7BU8kBovQCbkcbQ4UEs1cBa404FpcBiDXQIsRM36VA29hvtCXxa5odOGPvhU/2CA71APjo+ZWj80FuvTNiYaqbV4EmJqWrRBQRwpJZgL2tAs2BkT2kY8LMRDIk9/FIwyOFanhY0o6bsVicx51AFV3Z2Jl4Wwo5NecbV826SmIRTTaZgaXMTP4LODhh8X2vHzZ/Ic5ORycM/+uzXQc1o9tazV1B3JqhPVBnv7ksskuOMJlYyOHRzJijO/CMjpDIBwubhaOVNgVDrZUHigVWo435EERGYad4VhbZdNLeG+B/y6H2eKS0PoOm2rQvvA/Z48cNu+8Q1PEOzQKh4OYAESHe1Uq2gO9xOKslqCH7XiYSZb3yQHZNsyisi35C9u9Bs/RbtyGD72ubZDjITWixoTgzMqUIQXS6iA4/hFccHFgMiW6CB+g/Eh888j5ETljgptmfNOE5LvNp2Ta10pjm3eHPbSYu3ffdjjxX7+5fWSfcCAb5OYRVGuWT8Xhhs6ycV/mFl8RUGxigpqySxI77eSjAb4D9vh9EbmteoLKl3ChzNGiDiXyoqQURgiA40SJZtNOwXewHMOZu8gpRSDwGLDaDw3LiXh5ONnech2slga0oLJ0MNonImm6d5CYDs46gM8US1BlXc2MeUV+ex9A3WRO4azWpy1ZPLFy41flUJRMUE4xMiclSICn3rLfxRpz6rQzrIRmtreKCpgNpiSJO9gVi1YWCtZdfVd+0yGQSBRDY+eOH3n7iqhpqZcOeFO7i/LNo4/IQaEy/NVVj1UVMmtm8s65373MmbJyV02pUyqTlCBmG6SqlWvMsGKg0KHemVPoXnAFQHwHDIRNDsLgQTVdkzm/81vnWw6xbIR7CHgRvsnNmmaZmNHRnfao0aXEYor8KChivqPij7CzSVZIVei2S93By71nA7m+0E/9hFxbjHpW6N5/0CyrpYBxtrkZWLrFGddWqveqeF5UjRVW9f3x+VEP/Yf6nVGxmM8NhRH8CADl5vVUjSbx6ogKQiZ+oL8i4g8cf2BT+ccH9vjBk9Ev/DO4qvwS26UUgbTWxxXWSD098iLkFCsHdplS/RyyF9iFBv9rsFBOPf081ceMyntz9kVJiLZrclw+w5IalnXB+wAEBm1frbTZs3XqhikDaZWdkAQFtRXVySkq2yJmrDSqfkwFTFakDjA7IRpzqWVuMfPgZ02uy0zcllMoi6i2OUwuaBC/9KWb+34G6oZpadVmeIn1blGOYqHXbFhid5tQ2KpK5pWXzNPPijyzW8e1twu+RKBMvDxFovBRkDArPM9kWKlPqUOl/vr6wNElswST5DWLRMitr5cNnOdoe3Yz1NGQxxZbQBCJiBKsOiKLqqXoIjhq34FdrWD5ipDwEsJNaGwIZgA1l9djuxUgtWq8cTY+lHY6LlovThG7o0sgKuxAt8LY8+sR01ZY1bJXuuVTsI5FUF3SGUChxzCw2VbcmTwTtGcF/6E9VmeVI5iEaMEiWLz5ucvn+2OdVU7MEPdIODeiZcpTN/skmEOxVGvt0Htp+au/3sO//+xfFUhIrbaWtglXutHLrZDhEJ8MN9cVNbHju7OJzUzPgHRLa0Uv3rZBDVefP84eLqr919UF+l4Zbv5JwtOKeKi8PNcGW+iP39JyBV6Y+UVlsfyV9Aeq5Kty423CnxJBAABAAElEQVRrjhKxwcAAcnJmL4+b033F/5diGiVh5s7KQggAs5xIy579bH8mh6zNIJ0+1iZN1FmK6ZN1ANjlQDyIMYQm+BEvFlMGEGfjd5ZYoHyd78vbXZW52Tu7INKxgrq2zMLwMG2zj+kod9c+acpuyOGt66J+sVciwHch7nic0MrG2tBifmFOrhZ4KkxkRWPLKg/BSOZZqytT5+SqwsFx32NLUmAL6B82j1CeBGsBIAoaNz4WFMkNTXTNPHEPvTFZc3OD1qbC5CDBDAatFCaMG1PHBsHId8HhB4O3GSyNDVIK2pq19EFQFR6QOxP9Ji9x/bt2SaS43IjqUNkFcOPnHO/9C+HCbZ/owJZLvH0pp4uxxVpxyV7J6pdJjkzlZDOoZ6TaylVY/vyOnx5Y0XJYDBEYzR6EQ4Nm57akDQlAFBr9hsVXVrry8hq2hvkVo2tf1861sxutB1XqsMSFQJO1WjAgyQbkP5vKgycIPoPFBVlPzbqDbI92h7ZZvmgaWkxZnXErVywhcLoqO9XLKdaLLv7+r938hf8iMxsri0pglv9QJjhF2S6dPrGgiKFls8FivQN4YskQZdKVOv3l4eNPKo0jI8FYiEjTRJNDE75qUliVJeLywKEwPR3E18DNt8PBtXGr6QqqLyxcuCTTGg5lG5rcK8vZ4pZSDoPzC309yVLN6smpqfD7Vuxm396IL8CDWlpS04LGXUWq69H6CO5vBPb9Hz/JbEvf/IMqs5gj5asBkIRN2HU8ianmtJkyFZeDg4IwTGU+Cozxf/ZTsgSfTaKAl78nkgIZB5SX+2CPMA3r7UJDwecdV0EjOuZNFvs7bj5KI+AKqVE1cXZe4reWmdc8oFoZEkRpB+pDRDZ1ys09+ZGf+pyJe82AYvXIsASK1bZo2OV797Vt6yBFU2JLW3GCYeoDWPsE6CIT0ib4T+lLUhz5+X99JfDPPyNfrZf5q4r9RPNCovmGG3SlDqaXVVt5xMKC3V7PtO06/tTA/JBw76KanAKPb3t75SeEbxlCIwxDtEE/FrnA+gWfCjse4SfXelIsGwB2hzNRP9bNrjDcfHIyRP07gKhdMBRv0tdGf4hG3bZsIkYXL0lCL1mXQCTqha1pBOPE53PxAT3cmODnmHt5ZWydoIqVIYi+By6bUyqKT6hChsxQHiQZYhS1sd2mduQV/MqJed23tMR2lTxGAl8otlZ7Qyeo8kskYFvNizALKTbNK7PS7cGoGA+Wyjtjpk8khgNcu3hPPV1TU2RZ1QS+BldMYjVVUSackBdArxnRYWS15qVLsrWHvSG/49QipwTYWZXFg/cDoKw1BBjpl65vt7385o+/vEsuzMk1E+844b87dyRm28GapBK9Z63k00aqpe1eR4zaAJQIeSTnhmOR8jm8i6rkImF0dPXqe3+Uq4rtgGtipFeGtYaOeZXhEwXhqh4Ot/3b7omxsjL5JGgFFm7FEVOrFHjvRj/wL/IPNnz5ipXSpv61t2RrZpLSASrTHX9IrQUO8k2AdRAU99BTEQSKz8lOx9zKDYfq9Es31rcHJ9JbKUQlcHtOcmP+VJpmD5VdNPIpwgAMxw3Dgl/FRyxq0YIqlRK91SZnydx6xWW9KlBiLNZSh1VoFscTExsulhECUD9v/pLW2+AQ0oKklelIPI0xRB9lI1UH6G3vxmuhm4EfYGnusplY37g1Gu6ok27I8TDOCWE18fhOU62puy4/n5M/PwwWh0FguEFTozN0RYUUU0z47g7Re3lwk0wRh5ncvC46A0kxOBaBunrmz1tbSTPunSktTb5wgcQiOQOjpMf9oaH0/ycAKDKkj2GMYEy92mZshUn9vcD7oa4KNB52vAxEXcRbxvgokwiy2LDYBBkxSBz9iRpfilfxejPcI86n/VyI/2HEBHyydSZAGOHaNdR0mnlUh9170KwuOKXkbvVKOmc9uGoSl27lHGwSellSLZYFDXC7zEW5AxwcQ86i9sy46R+VCrWlOqmwGZzKG8pm5pekHCLxsdqjclXpqknPOFswJhINFBiwWE+QAeMwVmlVIlFtZ6bFwwbs3Ss2HoojwIe/9hdSn13lh1TDRyUtF+yRL7p1PZvOuj77M3KIxGL9sUWyF7/lfe6nzKbykOyi8L9dbTEN8qR9QSqVyaOB0e+a3IsOp4GwMzsQmVOaAuY0OblyUt4nVlcg5blRvFS5FI2NBRtsewqwhnjpquPVQXWjMGChVrGTc8wI2dsyPsUP1+BKCudP689eKa0BD6ZUAADhYRCqBbL8xpW8R/aIcszncz28/JVXHG37+ANif1qhtbYeDsdcLDi1pm9lhRi0igDbF297GTcEtVXleaXCwgc/rbypuVZYnQajSAH+H781+7O/lHAcHTW1olzqzLpxee0kZNdaoKpCIpYMqRZeM7hJ+UD4IzaCx+O5OSJsRbgXzCyX4NLca8IzTr7t/vQvU+dQ2VFl5Zd/7epP/+/lslQdmJjYnFzK+cwxaaczE++OVbTpMAb8sThbxAZNv5o6+YVmbEiifMDmirCEG6ecisOrZ2T7MtK0BKjPGRLWCcv7zrn40RYZUtVtRALDoG3uFtYLeKuGSngfOyZ7t6725WP1YcQXsv8YZQ8QoKD+lNmclo8NVMhhsM+Qc3n8uLQZ3rk50VSAbDZUGnGvrwV213OUy2RxZxs0JsBCtC2Tzt9yccrDjnlXLosJAeQHTc85s6EEu5JYnknnkY5o54gcRbiCrjM0j+Mf8Tmr47Ju09hhhm/bACm4d/bLd48+LFqUmMfgBtJbP/bLX7zy0z+NL/eqnGLxjwyIfpEkjLA+Y7eJw74Qj1T1TPutdXFHMnV2phf5ee1yX6QqPxAhKi7GCemweF5Rvmh7muo++ZOTW/PrBXtq5AbXbgfI8iETEsDPtrGRxenIFM2sBXJcg+cX68PKIYfwWeabMlXXeNDoaJ5ftKiGQxSO99YVBgIRkdBirrO8mhsCuJQXF9Yu3pHt+AC8QjhWXGhNxpVkT7brVrHYPHkuhGLHqvRNfYd3z671jkQ65N2UapJPPZS+/uVrHHU+XioY2NxM29NMICIjFimAXoBl7nKN/vk7HFUfLNkengqgW8Fp9u9rIygaU6aBoxtyq6xcuDDIqTtXt44+F7Bkvjm+ENq7T9QoG75zmUjrLlFJuAMp3JXlTdE52p70du/JsbbnO8ySUL27tbnqQBkFW2gbikqhLVnyx3iDKhMJLys/IatOVeKk00dwXyNQLBb+hHQNwmkhJKRhUg6Rj2hZVJcG3AEhBBvCqm41JHiB6jiAARZusUNx/x1pI8Vu375zQYQ7k1/cWZIZn5RdMYB37q4NL0S6BJ0G3x6rP8YmxWvOXikQFLN/UTUlhBSEo5EcU96z1jsboU5GrlX5ECQxpzZpIumHOsjQZpcwoLbJTI/aIk+ZjS18O6Q+AAR6MePhT1my3CEEHEl4PmDpQGeXmR60COnLd5tXvy3+MpAcWFwcvLhUUCgsyOVx37yejsbnO7RYgjA6/Aj4Z43569/pf/LXD+Zui3Xkmhs1/UMNB+P/W76wuIzxFJW67YO2v/6tQP0Nk7WfALtJJodHMjA6mGdpwfbg+KmT8tBYoffAYQoXRa2TPzs2np6c80ZFgpNrnfEFvBqBYst7H14qqNsasZxGcMBdSWbgO3e2C339tM161j+zjpyHxwA4PVqKTVQp4+qibPp8PNfElRHmQNasnZRvNSe6RGXIn5E2jtboqqmi1LHeoZVvpEKrDs9rPDNoPElnH2dEaCUFXEXeih8Go8h6+VAQTspvfwPKF+SQ2/BhlXqG1Wjth8I5lQVey+4iuZ3N68m5JU6608mNgem80oCnoozDvKX14uIpCj8D7+iuYvKrIqvOqB685w9ThT4FUHjocIlpb1o1t1Uxx0uFAW9TnZE+ng2zMW3KhYeYTWr/o2WpbAh5YS+2Nub4NVYimZqE2avYNSRd5Vu+D35twUwZTobNvhVaDxJ+6K50rAHPJ2dEXVGmHSgbMKmNwx+XB5GWQKmhU6fkFlUl5ukZWW+jU/G3FgiVKmXBOK2F7NlJbL59PlSPrYABGTLnXpO9wBBJc+l02p1H9qyVcK1NxptxROSzn5S1kRYft7Z8jVPeS5eyd4T9PrTX/Na75hNyL9NG7uWiOQGn10N2Lphgwa9wYujeLXnsWRWRKda8uCXLyYohfNCJRL6qCoM9Ce961mq7PQtiCO3WeCJ3QFowHPAXgFeHxXCqrloOT582Hzu8ITkmAJxha3vllMidlZlUbig9dDu9K1eU5Mzct3tumO4DObQLi5a+dMqWYeDoh2Gvmo78+lUoe8FcWTNf+IL0CZVEM917XJoAUrqy5b/ba0Xkwts340/sM0tRq9pl3jj5zsntIl1RmUfFgpRYtTv6EFgeupdKX/kixp1fgBX9+w/yh9sCQY1oKdJ90F1hhQ06tnTqQt/PNcPCjcz4lLzYpb+XZYg8+FAA2iuZIxLWhk1kD7xCr88T77hPkMws9puCKpZm6+/k7LrN9atOKWryUOfGJSoFEJJfWQkX8u2iUkmwCMFgFU3UStRoVlvCQ5tKxRwCmx2jyCvutZ4euaogLsa6upxFFCTmDVgcbJRTONqRBBcvSBuNc5blkOWmRBEwn331WHg7LKfW1m69PX+0TfkMfJacRpzZ5DQASAsMBqQcAM8rubdrI8ETyJ2sKgu8FRbgrRtyBKsLU43VbYZuyyG8FiFqjTTug7JLUQrgttYALCx0qbnlpQ9Wk9W9WMMzP+ioszARnJTs3MVoCGRR98N2I1q8Q2ixCGMbiolEBv70fOOvfFx64Z5HuNpkWKh0jl102MxcRlKEK7Ul5pRr8QlefT1+x/nBWPHVOCEAGpWVmZvyCWHSLFHreUOmA+i5Kaq8DUji7+dZauog8rx9vbLhOUMBkCqG20q7BY7toz744sBS0Cdok1NTCB+peLpTugFYzqShAjW1j3+2cPDSZP0RRRsUUNbu28Hn3WIxN7YrgFBE4KOhoh0CBEVD7D8HToKG4fBhxj+Hl5ZDRHhiM5o3QPPY4dTomwO5+SAZ8tf98GfUKsCLCWzvBPZ1OA/a3Io3x9meT37f2MjcHmGHLyeaxMvwqnV1cgphiz6KqcOLAeSzLec67Axn2qc/bR23EddrkhiJHXJX3kH6E2jS0IQckvYNUoHUuVR7Twc6mjxUvAAYVRT9ejGcxIrAQYc3yJZ7xojlboGInCK/9KbOhbRzvKnV7K42Z2+DtjbpwP0BG6hxe7LkSCBuUc7QJOIFcgr7HN0B3ynAtm9/Nv7xjnzH5l+dTt0d9j54XE6BJHjHoSaAmtBV5WQ7OR874Wvdt2QqVH00rgsvLxzAligQzenEboo33FucBoUSw1y5zu/f+3/vIES6fu1JbAC5YQTicsv2xABJCEtLjZ9CTJgAewrNTHv4cCsDwdDbYz4VGO7GpsLcrW2q5+vu2BnrgsHdAOBSbWpy4QYHb1MSDSh5pMTGcgVLWbc5pVovwQTwilRMFA5wqb8/Gi80rPwESLWNljrprMSFlpb+/L/N/uzvKdOAClAu1VJ1sR8MqoMSrx87nPoiGbZ/0AHfWme7sAiZJwC60s5OzcHSVbeMiSnwLpzujR9ppumC+nh0S4v8DsZSIiiVKjqo2IXLMxJ0sC7UHK9nCzulCGwh0N7jjtwV7kRTIleKkP7qOnkWs4mLCtjd4WGvQsqRAfQZG8tr0TlKp+sp/NVaazaUQPz+MEFavAMAJv32DuvrpQ2Bk2AJM1QVVhwlH8GHG4EZUFivQLbe1TU7YT0ExxCRKj03eonnGxxtArob8vXrDnuh/v7EmFNTl1SLlZWKYkEnX9ADObgwn2DXQHFxKJc1h2oYtOQKR0onHXc7Rk4kksVjD6bhAcmkN4aE54c3E6GF+cyyi42q5A741/LyNs9doxlqqhSZhapUWSunuC1tZRpgJuF8692CoyOpQJCV2W165e3S3eetrOEvjh6162T/jCLKciw60iGVgmaHeuXG7Z2ehvJ0iLw3bgqg0aIxa/bEno4duJ9NwzN3V9gQz1tZVI7QRN+6O4eTduKO8PmyA3myIh+uAmAIrq975uY91pXGHiFzm3hpgOmB7WwbJo1nql/c5bmh1G9+Y+v/+Vm5w+QoL4B8cNHeSmSF3NA6rNcPukIBhNgBWBVEqn6rtdFlyEuC8YVyRmQ+c7sgbTg1coWSDNRvAt4ZNnmU9lR2EmbJGVr1pPyOanM1Y3CzWIUPZkFJj0p91YM7ZjBh3toyR5TLFqRMWcbsbZCrmFXEzl+pfNvDcl357f0BlblDz/BpOe5tLyXG7ZgEg7klpOgJ08Cqix2uEimvnxFYWQmuz1dXC4F3J82FOWetFMYK+DGld/uhP7wAxk+jSie+yEU0karYpCQCHk9qeNxrt9CCdYBdDB2yEmBI0abImmEcEpnA8f153bW0x64uoGG1Npqlyxy9D1gqgkhg1kjHQsEFCVjB1boOK+1gAZMP5e5wFpug4+XlR2VukODr1d6bLWwPC/6w++mMFOwWktCsR/1X/kCZOD3QVqwrtbI65SetSdgrMRqp/7zQM00TZ91rL6ef+gI2pEZfFicWxxIFx1XUomkgpyxVoqiQB15VUdsIE+A9089NG3JXAajz/KJpjDu6htRnZ9dJwUECZhnJxXj3HO1vvpBlM+Ka5w+KZxlg3NATIEaSEnfPnHptB4IGggNitrWCpKLUmI2kZP3pWEs8jUaEJReKLmKrY9mDRgBh27bWcGWcpp/9nCpLaklVWR7nMD2ZqMv3Lfa5aaMZ5VNghZbkvcjdalEl9JAB3M1z9c5fJMa8LXqEVc1GJxMtB712+UYQBILR6TBGYkVmFvSrse4811ZifnBjWacINQfVssqDF0bvvmMu6kRzgCiCGpRXmoF/CIuLJ4DYyjWkftFNDTDyoASjpw9/7x/0pCYMYR1w4nggWpFSKPz3rnDtvw/od9//hSlyXVQAY9WElnUhqLIZSddm6/VhudPqtAm6zRuvSrulWZY6WG2AQ7aBYg06jAyAzxbEfTYrjOAJfWBO3zcMKtitWh7kuXnL+DBhPI4JAbUxixhaAJkV4Dq+IGBtbeLafMXuuJPpDOGhKKhSJX53jBkUTXYNBIgCnXjatLVLe32t9WFVSmjfvmNQVVdXL78o+LeXN0fLtJ4lVLRu8uiUbnByb25tvHLWEnWgvkL0V3sAf4U8IO6Tb8rNHzgh76BatSRDoAOBXMA7Z+UUSIphA0DoaOEHD0kbi4gMDZsaceFCNpVxIRqtaOE+RUVswyrdMDDI8evvk3cGykrLThCaUNqlG8aYVdF4qzOnRS9sgzCFIUquNG/IF7/xmvupJ0WAcLNzPeH9rZKyomulpGdyx0UyACQTz5c6OSCqlUbMEfLeBlUGh+TF7JL8nW1XQ52YCgglAO12lXqGYLKRKnMzngjhg8tX5VRph2QD2GQCtFuYsh2T8vKaGneioEwqDQLW3Yi0AeBlDMsoAgU2EzBvvGGOHXe4I3wE9jMyzJnly0N5z57QzBDpyBbPmTPvBJpraebM3AhUhb1qtOD0qoSXlFHaISjdcnI8CE/rMspkg08+5AQtJ6fcmZSL9J6+fnpND6yX7lGznwNMQb4UFcEabC5Xzx+d63hSkZBYH8iWCw83/o4meW1GDOUVsJ5sfgH4m0mPvigDUt0R3ZxdC7XWOpNObAHOaENY+Lkx1bgwT+/w9lvmuU/J1iRAKqssGAbCy8lSUxepCdbqGB+ffne0dL+SGChx4zor3PxtKiHX1wQxrMqAng0W4cEFMpkDn4+IHLOVPNIpD3zZWmKgGT0tap181Tz6qMgVJC2wvFRAHYhKfdDmVtNTSdG36MxHfaLLoHJZ2sFi5BP08/ftS4UaykXOnFIC4cdGEnSUBbUK6YXtkErC+qRMcV0td8PsQcPz+zZp+hDh4fDG3KpdJeJua5ERZtAA+re16V7nJtPTh04U3lVlLuvQgSS8Ns4UoLZO8NNm4WazvZcSbT8WskRR/QA1Jz0SXgAgydzwkz9fYz30E2/frdi1y6RvySnovRjPgsyyJ1whWx4PUjVEmBWrW2KfesSgwAGMIU8sKRZzDliYXxxZi9eK8rXRMxzuJPVLLwGHGaL8vO1b8HATeqjLzYJsHBkAnhFGXp0gr/zx1BP/jv0XPSx34Qx6piQQaljAg48DHLt+w5kLfDS8IdmzALwOrw2PALY2o5Tgh/qs7ox0Rw0C+aVbrhARPBbgF0jS7Vq4I+pk0J8J75efP4L7HYGNGRNmegBIY0Vd6sh3gDY+o2FpsgNywGVOn5Q22QdojXA80BLAFEc06DouoYKi4twmlTukkRcWybIiJgvIy/PCDHEyojLeuGGWsNmYLaE+YcLRqMtKChAjlucUwFhefv3VDJInOyhR+nBlHuzXX4pSoTosk87UcysAQvnEJ+w6qujo5K7RKeQz8PJZ87lnhFm+/bYcPns8LawA4gTAn7wuR8Wj4M3a2sArgwURxXCTZaF0XZ308hbGirKLfOhVzZbrfihGorhL8yCKqRaAn07V3jtnFmRhSSo5fYdBMztr2Ug4HT/QSNvNLhFwCc3EHr8wvZNIkbkSsp6v0uJIgW/XLnkoCipbjMwOrN65JUOEn+rpPaTSS1uYYg+sRbgBQmDm9LQvMFvTEuAQ+2ZxNmVf+/pL450PF25PChX8yZdSjxwXr4hN5uB9UVWalKf62Dlq0AT8ViWWMq47a+aWULmId+TbtIpEPkMKBueYpI7WMkMBY9NRbaOULMExnyRFAoUsqIlYyWxm10xi28yokgd30FeUPu8F7mZ3EoGLXz6fOhifXLg6SrdYnttbmLc9JWyw55Z733GbMa6cMBDkY22SBxwIr9Hn9L7TUiLe8HGD73lMNTE06tQqP2MYkYG86sr1YToit+s6JDYigJ8R2c3XWq6YTF7445sHKEkBd0EbgRWr2xFWJKmyOaZoQC5qW3WSteRAQbFZwiwwJmjA5j2+Q60lv2lqkVkePDnKxtwVUATp2UiAU3eKH9eQIgc7O77Kks4uoalbN81zCN4VSa74IXCrtsLL4pMHqNxQ2hIVQQagPq2vRY7K13qzW/t3psTWsjrSznZke16KRQEweZQiUld40JmlXUcI6po09Wkk8GqONjnLpnAnfj7P1BfJwABEPglpWr0Dfaq0T7cpZxu0pkwM/s+ijzfflH4kWDU2WoEbqSvct2+S9ZMAbnC2UEECuRSFMBhAK9UtRBHnVSZ0w056NjcLrxBZDzDNHo+3sYbmyo3RkN+fu6vEXBUM98UCgUxqrl+GkeEkIZbMegDugLnFvAvtqUkf5Vmi2RkupRwPIhc7BPiF76VOPr/oBEJgX5L+S1/KjZWbhUohEr3jH/337ec+X2R1p42JFVTm9gZHgGfGzLfUnueqN9DAUTHkxvI5//+B+QDpa/VGzGiLxks50nd//9uf56uJ2qgGgQuLSlLDOtpg4yUNAr//ZR/4K3T6YeDUSXNYDYONQSrfqadA8F7GZO2mlJkGSqtlhGo5i495n4k1kRzgYBlfhzCo52PVdQOOW9NibFyEDc4kG9MHrUFfq2F3d8tAFbOHOUhFwZRT+P4z13to/n/snQd8XMdx//cKOkAQAEGCBAmCvXdVUtXqlixZllxiO7bjxLETpzi9OM35OM2J4zTbcey4xnGVHUtWFyWqkBRJsXeQIDoBEL3j+v87s8f7n+8OIFhAUdbuhx9w7719+/b9dnZ2ZnZ2du+O4Ib7EXeUgW3cVDZ3iTm2T7qZhEDPgoydmVAq6H6MbYgXJAi/8Vj8hLmcnFJOjLXFEEMR3RYuWMDeJxJCTENtPK4g5hS4ghVNKPbEEzkP3O0dVaKzvrwohyRsdShLTE0EwyAhGmLDu+UWyXd2nvnSj/2RUcn395derx60tqlYoWgtzSP19YW37/IvqiYb7ewRvxFmXzWwYSUb2vJawTole/A5dFh4mRXfi6YUoPlYeyHjCsmV9QQS1gOGAqPZIjlrVmz/gZhqYp41q4RHqIU+Zymhb0ZlvrfyH186FPMgZ5OgUMYrXfMC9M+McbWAYBUV2oDtCo5L4kVwKAqTIZ04KZIijJ+0eg1yQNb0GbG1q+TnwX3yOdanDjG0uUnqJPEhpWX5e/eYFdfIT0Devj2+QQtk6CBx0TEDz79WtAiXxa54XzDv8YHKKQs2FYv9bMcOc8MmqSEnByergg0QjylYXJmFP8GAchzGN3MzgMAnSEwXzBuo4iQBzXPy2VNkF95alf3gvfIitGtMOyPRke98N++Bt0ux/v7wd3/ov+/uOFynTs2d2h9X8jEosSSPtESCbn1+s29f3B6GvsocI2Iyq9FN1Fy+fLrkA33ZS+YZJm0rj6CB4GhqjQ5Veq5hf1/3tx6nYCmnMz/6aBzhrKzQzr09bcIrpq+YJoo0PWhXS/z+kumtcQMtF+nN0y2++QvkXeiB6AB212zHIRrW8eIRLpffd930RSUio1ttZ9YsD3IbNE/q7Ox7fnfxLeskX1ra+pXHZ968KL4KCgGAvG0qKuFqPSxYJXsPGtQg+zxUyuR1KIQQG8tjNy6R6Qoy24uZDGGHUMRnt7mz9Ad6dhRAVEBHv1grxlVXlVQP+IZkJhDZdMWKolUB09shP+nNCk4m0AH7tpWcXWJiMsSySheYKZyZzmKCkvGceaaxLl4bYqVV5inX3z/n+jmi3+q8l4vHC0MShZkEbQ8OzqnCkVKmx7Lpvlf++oUbPiQw/uBzze/85JK4ASLAoai56PZxVO++OwtOZVfvmYYZOzSAN5KiscqlhRaunMpCgZoPJMGd8Mm4/vqCFdXyEzmOV9t1ZrBi+bqykstr37VIWjI4KKdfMIEGcNSRs7bIH/3uvmVrJNJd82GBaPaSehzAegek2YGQbyamSOV7oTO9WeU4mg7Gw8zwyYxQrUHOFaLH7ZTMCh6SeihYdPU0avBCmS6dFwL4Uy2wkk+DuvYg/9ifhL0jcKVOT0ia4Grtz3MJbAuPbYxbMeBOrG8v1imSMci4sNYELGXI77g98SwJ5s+ot5tyVq8SmQ86GeBdZuC5HUXrFx7YKsSwd2fo7Q935ebIWPavXb7ufaH6l44uhlVipTnWW7Fsqg/LEamdyTEi2h3rEiSY/P59dm3cnyMHMVhefuN6U7mkYMasqspWZXEoGTDz6zfKI3B/5gWaRIKTbN8288Frs3ECJnV2eQKDUxaqlphP2GJPQbRr3lppQ7Sr72SNWbxJzRN9fS99+XhhdpDro0NhGV+FhRLYk6ojkXDdqdxhkQtNQ8+BrQOrlspU3t4QXbrSlzO7QqKbIZS3tb24ObxqpZSC5E8eDUfDUWsjZWLPGZQ5kwR3WbkiPqnOXFlGxPBoR1dbjfDSipme47uiYElatT4iM5dXoCNcKIwZJcKKAADCjGRlZbpodqWw1af2yFMP3SgqVpF2EfHlGc2KlFnI2R+YiDxmoUoKI80SsNLqD+tnyxRxw1oTWi01bHtZLF0nVNJEPfwJbFIumy3jSnjIZByCTYLZVBNtrrO3CGkETOijSCRLTz1dMNUX7W1prhmtulFQxZrMTk7lLuKXA6+FB5BONJgFw+YnQ/HTw1QHlOskaOVbYVOkMD78sJk6vySPo4hWyyTrj/j2fuG59bcLh0QZHnp6a8F6JP1s+VlfX14w3NcspFW8KI9F+KGmHvLTl5YUl/Tt3xt9RiWppUmLBrxovbpyUWwq3mscgMqikdoG2Vc10IVjvNDtjNXTfKw+DHYefQo4kSv9Xc/sLrNH6EajNbv792/jssw51842B/vEN4y0F8LTDH9oHxYDBJx1GwXm6OwqWSqw1nyGYV/fzp/KOLrhgdJpM9iYXRSXV8vLsxafPbmho3PLj7pveauomrPz+l79Qd+cKm8uOyCoTf0PZHs5YAejeIdgM7FC6PRe0To55YFUUlUY6BzImSWz2MzrpsmQHxjs2nqMn6N9AW/NIFoSqbM9PLMk7qFPBH/ArQOluXLrmtmml70gOiXyimvYqIgNWZiBnp7MND1DaWvDzRIIRBdmioisVky0gjwrBHqZVhoap5bKVNW/qwbTIitmpEaOs1G7kUpIZn25bJQmDBmpu1OEC1QqK819aAneKzVvfWcTtzb/o+e2h0utuiWsCXkAwYBBaMwdf7yhjON21J7o7e8j3DKLiNZBDTdaDrlSAVfWM5m50SdJ+/l2zVzMH6gIFIVKNME+hGXAKPRvxj+wG8qwhEtq7pS+q9VyU3RdEXTHeTZjhVxUcWSsm+nXV99ocpRooz6MGGbopHX5Q9c1eWxOLZYn8B6kRxcrVtkc7doudvdiERrkddNXakAIY+Yh4NYc+eIWri7/yA3xRSp0IdK0NbrRRUHmmCMiTxDWaeoMubXpXjafem66geyCdTi56hZGfpTNz0XfJ06GXUxYuFBEW3RS0rKlwiyxf6DOkcS4G4473uzcKWxdF2iHD53KJ2x9aVnxDfoV6IFzVpmpOjtG+zSMqU4eeMbeUeovn2F6jkptyCtqM5B8hS6IQYNwdBKDuLpaMqTBweJYz/aXZS7Z9JGVInUhOl+jqgVC5+w5Rz73NLeW/9ZtvmWLbLM9d9wuxjTYJwfqkcKjObdvMtXQoVjK4xqCFXb5W4fxQEcb8iLSkrVtrwElv2k/FhewAsEDO0ZW3ylf5yG8xMbrrYenbA5G3eUgILg+CeMKAnGHgs/U0dIyXNOcv6BCbtGPEopKeShyGz+ZdkgsheFRwIfj0mYTCNipCZZDvniKx2qGTVNFarTecUw+2NbsDI04jpo6e3bcfkinrFguFZIWsVlLDiYim7ekat9Patf+UjkcXG7RoSoNk81iPRMLCg9atXPJ0tyr2KYis1bWVWtkqrQecfxGKLFYkUfRQlO1H06d4Yj1eMeC51m9wYxmi3cZM7THG/kAroDKCvL6fW+7R5qKKExaubIIArOVA9err1q2opNzdmI5UbgszBohiQQ1TpuWt0jn5NbTPjgRAlOZkvdgn3nLW+Jkk50vLv/4j1VrSeiEeUP1h1PfeLl6fVnxlBGpDW7HLcC0Yllefk5WJMZx6GL6CrPJh2jic1FfSWvR3hkv+iLeHmmbks1Y0O7DGoyaUXtSfvJdOOapEssgymUbtVVa5s4tqWk4+aODC++olmL0LxOS9guwD2/Zmc/xmS9ukVtMLNCGGreE1NEo1ii755aVJhFYSAiOaMhYnkmY1Zl87KosVgBmfojQUld3j6wh7xdha2j38YL735IVDLa8fIqfldfhkYWmUU9etoQJl46Q9VZTJ8pMVjz2ExSYV2X2PSXFoEPaZnWq3p7Cq5eKpqoW+uiRY15rcaUYcifA4sJXIHwsd92yZdNwypUpedPbSmXHprpn1ByJLCbMBj1oZ05s89Chtfcj7jASoX+rO3V05hP5RhVIPwUqCZUL38YG3ixQe71Zi6rlJ+aDvPyOFw6SLd9QIjaj48fIT9+4SXRRCEyfkqgJTJBIeXxzGc7DxM7xlY3KT6ZxNn0WFYs4kj8SaH6lYfYS+YSG/b0LH64WVLUNA839RUvVDs09r+/oC21LF8r04YEpAUJ/fzbCPUkDZkjGpQkiMJP5UYUgkRaKTEz9fuTZFca3HhlbstkQ57BZ+jbJE+KoiBgqR+MBtmHdq1aZQp2DYBd19S994RClbvrttbKAwgCxzGruOuGcVqTCZsQZD6fZuYpQYfIevJtDfKrXtZMvqY4WrCj1QmykhQumD/TnRwdjPXoLaw4cSa3y4rFMYiJA1SdRIQPkRA3ZUzvOcMiLZdKnG01OWVFOdXnBMpXXoZOrrydWgTxChBgcj61GlDfT3J9TgFHjmLRcLPBNA3G7zLJlvDGrIL9Ya4w19ooBSgmyrTFUNS2ENZX0wAeLGTunnqmdv0pIF0Uuumjetu83kN34C3Or12VF8KDBEnhNccGM/OGm7ryrAFZcA9fc2jGFjc2w2L6BCNs3ZYIAaviTp+hwTZc2h/kNT47CuSL8ZW+6Gsfk2NFj4V0n+DnQFzt0SCVUCL85PGWNz6syfnVXM3MLY9GmvLL8kvJAZ5uwGuZn5n8m5OuXy01GNnHSmRxIaE3wg9wByVcUmVN9st0L26ZN8G4lBZkZ4JSWWXILfgmPtJHtkQ4R27v1gf4kJSFexdn/mBqZKQtlxEuXtp6G3Ub2vzrKzznVQZ+/30pVMyo8TY2xadMCODxzK2fFIjjDmTqZ9BetLaisHOK9JDq/HG/uWrNNfv1MgiBuIvgOTYHdVnr9KFTomgsX8dPv8S/Au7Vaxbze3pw1OM9Pi/u3r1hZuTafY9nksZHB3hf350nwTDYbZvljotxWCOMRSZSPtQmiuAqhVmcqtlPMLRX+mqPBhAgmifLvJfQC4jgSPCwxa+qc8mZ+5uQXe1jrlMFlDvz45NzKiDX/IkfA9ubNNYeEgv6/rkWeLmzsMzl15nb1GjBrlopLVBHvB4gpGEaX9R+XPFyXiYNaoAM0tDN9p05Eq+ZIe5ms2ppCVg2bUlkY2j/4jz80H7hWHiJhTizRoIV5hd66uuiSlVkH98i3W3UdgzMpJ9fb3xnL0YlGlD+mp1C4gPgwVF6Ze/LQkBWd0HwImq86i/HVS+yNnIL4miqzKEYPmSd0G0FZsRDeAf1YpEiRDaxQdBM/IE1pdnYRkq1Ppsg1Ovahoemzs4af5RavY3Sy+k6qpccxGvlMWYn83NtvNpxdqe4qk8agNBaViWz28C34M2EDKiK/Zjnx7Vpbt9eTP3Y0du1G71Awq3ytjIpSpk7C86iDDNNyfkm2zxtEriGhdFXTCsnKlmKIolpHf3hIluyUMem98/9DNfybd5bA0BbP6JIdNZ1GqBi7QrqKwiTiZwKv6g/iw8nI5cHX9JZIWhNOnhjC33mkL+JZJcUrlon3Y7jV+HWMyqojbejRmuhFhr8Oyu4G2UceJKi5fhTyWXtnfF4pIzpfZKABtmOK5uOllmdiELSwMJPNfMBROUKXcv4jhrfIkMmR3pIDi7GZ2SmH7eOLOTFdH5mPIZljZMXdVooREoeJxA4hxnaUWPoeE6Bh0FiW+JUe3SP5unqxyUHfDLzS6b61K+EiaHtyi/0YsnKlilOgWcwALQ1yfUq5bnXg/GLtiPCgCbO1TIjM5OFJwIkh0AnUQg0400cknjVplFXJaHen9FfpXM4bZWkIPq2MtBpjVGigVXGYt1pCloGqPDJkSqeZ083yl8RZYZ118dHGgWM+ggWHjFdZGBuvBzploxcJOoY1eHVwFMwQoTPUblq0y8IhDoWcQvxRkgcvWxiWX/KDnSYQNvkEs1Z8cqHKQLwjaP9od6S11adGPlOJtxWu8wfkKXgzUrU1jqJY4qKOocwqSPTLmjXCaUhYTPEXRduxGg6fDOC2qbCzgYGh7VKbHEiP+I5J1a7/UICxaBPWD9w4WFUndXT2LVxfvI6Tr3X0UcZrhwMdlSPfLlNOoZTkdCyGLwIBCfaMKZK1HRIrb1jxUT9se5D1ITyrWiDpopOfOCHF1q4x1fMNYRVtuCgOjqs/aUYUYdw7c6GloHWQE4ZHWL+ojkSoF5tPDgRAR/SL7AII1ljKwt0118bX3dl2Bbu1G6swDy9b1vLM4cpPvEueghnV1IT1WGr/3bebCk411a0F3Oo7Le1UWiWQQX40rglIF6Pzg5KdsfkcftoVtpHhwVih+OHa8FyoyrNXxqebk4dMQZbJp7MBbLYGjOqKr4nRZrCaWS23cvMRzsSpUlIAVwF2RxTMUhLCBMj4AAfS6ZaIP9e3bnX8yCmQB3D0ZxLz8bx5plyFEQwiwV5RTpTbShya6zbFQ+Cg2KDe2FVZFGzUYIQ/lGdS3hSDAIdJExY82O4vZvIMj3bLeBGzfSPRoxdKsa2vmeIZcT1q7WqZYPC4V6cjs2EDlljTVyfFnv8/8ZlEQSXh7wqkqKmn5FZsaMgzf15cx6OFzFIlBH0Rsczg6U7YG5ULTYRz7RrtvtChmYsKinFQjZ/2JvonmDAcSDzOdErldDEJuwAdpB62MjczKOws+vIrQqUoZpYIZa4NBYJCTrLsDIzPb5bHGR1rOcMQFqu1AdeGq2RYkdCL9u2X19nlTaxwR87GrC/IH9m2L2/FfEoNNXQWlGYLA9GBGR4KSngolR6gwMGOkcKADliWkUPBlm8+X7lUeRrSzEeZWVyaOAKfM73KnaYy1uDDoJeYImFByvOlMmibSR+/nwaTjU0K3UknbmwTrNXMrZZbsBqfv6tJsmULp5l8tKlpIuCQ8jolFDDzGglaZa5ELLXRUGG59fV2LLfubZuJg71lg9i2YNdtbdEeoU8vHn7Qs+VO/EaURFRXg4KIkFDa3n1cHj5wMhoI1dXKJFuC5/5tS2TNdpGOOGwi2bBfJcKBFlmRbm6gmMkvlsC/WLVU1RGKRW/UOC4y7mAL7He1nsbdXdFwzMuqMh/hL/CVFXcOIjkIv2eMDDX3FHRqhTCuaLS7WwSV0vXVxB6MMXEzwjrZJDwl0tTqQ8gmMXdgKrIfS9sKCsRwiTGFxKBobBxqFoRzkQdmVvgWyqAQ7s3AbG6KHDzKr1h//5m+3OIZyhzy8oXRwaxgO529IyF/4awpMaoFupicNxgKRMkHhiKBnqFge/cUv3CkUMVs5sAAEclhSK+I/tukndxab2p7zNziuBfzq61y7nNQyWSUsOarpOuUtcsSHOGQD0rd4rPE08pG1Ywk1zIkJNQ1LAFJS81dm8zqOyvK1s7uG5TZPK+8CKcbVvnI2xkyNycWU3diL52yd+9IVD42b7TnzMF2MiQcRL52zMweNj/Wn836Vzm+uYGJ0Wc4uJD0H39m/IvmNxwZmrtcukwksePHoiqMSVhIK7zBtUgYYTFC2XwYD9FO/5B0RKSu2dTX1u4dPKJT7v/ulqOQTsoDQn0flKU5ya8isPTNwllvfRD6N8OneyFwTtUh/9Bvz5HJBYGHKZ7EhAvp6DjqD+YUDbYFRoVmQLZrbxMT++Mvyi/4KXLqKsmam2fIcQYcBLNoqcKHVrdunYhDpJ3bxVsbaYGEqIMmTSM0Fki4Z3C0oCx3HmRqWP7tqBsor1QxLxDo3FnX3GPmzxNMvKy85eTkeUVs8HW0MRcXzisb4CRdxNg9JxjHSk2mrNzn2XS9n6D2ckNPIo1EYhp17Nn/qNn0/nnZxDuAcbSMIqp/7rtSaoPCyaRhz0DLnVVSuqhsuENk7GB9K3XAEuyiU9Vc74C/pGh1NbcCTZ05SF+IsqTVK83RY7KOZ6FbuthUzzJ1Cv8Pf3hgVxBjAen7e8watkRwPqVOxcRk2Ljel1ch5BCJerOm5kfmLxKnCRIjBQnKluNnS8vojv38PzhrSUlxNDwatpN5uLndFw6EB6S/utpCufne081R633FPFY4jSmeO6Z3QOojhBzp1XrzVb5LsuedZukTcIdWFtaweCmfQKo92CPBV0joGDvjuor+TvrDF69D/9Ar9A1mE6FaHWt0IVRUoT/JPzthHcqvj0z4T9cJk6sU/Ny3ze33S9xzu0+pmgMQppr6GqkIkwIeNXYm8BAkjWD/sA2hmLbvvVSxkg7ulWKF9RwkVbSwUvItB0TMveshk10sPwPt5tgRs/8Q2ZHBUN7GNeLko+q+qT8h3oNqxmOGaPvqExVvWU6xzZ/actsfXXP0f3Yv+9S7pQY/OzXb42fCtraYGeUi3SoL06Nycswi5kIxYPR969Hiu64j60MsRdqeVRXnby3Hhh99Jv+Wa6UYh4ScrI2zQwyB8C0mEhsjnhARxATn20kH9pqVa8UxrEM5Fx6MTGaMCdLIICO2dLaSj6hwOXKqcplOwzhuR2NFpcIc+XKJbNGhbBiH/oW4tWq0DO4Ew2JQf/IJsmHijyxeGDpem1U9Qx4qrzBNDXFpu6FesCpVSmCeI084AUJOkQ4fmrJipantkDyLEtRv7XUMEubawV7DSjrJE5OlXjtpgXPYI6HS7VfgrIVFxNpkPGprRxoj1Z7a9e2aq3/prL8wIh1GfSZnUscZUY2am8x+UaukHmY4a0ZDKs3OzlkwW65jIWSagnlYa2u+nD4kF0mo1ugSTcr2y8qK55WJnFqkQrA32xCi3SqNMitB+fB34XQS54eYR6w1kdADWRlg9iVhS4Qdw/pV4g/vP+yfjcalvARMgMIul6G0n6jZ/Pdbr7+GOtFKYojUe77M9GfWf2ClWC+bmv77r4Qh/fIXOVBiwEzRj62czem60rmksLoL8DkoPyTwrK+nWZKHHXo8vSekl7O8kYJpZRLD0CoGtLOmRk6zJcGEkGAIHoh8QypaJLZtkURMfjaxDdi/pzXv3iGVI6xDliREKDQuLYZYUwgz5Z/dknH4kLk1aDQEorQRg4JF+HSnqauRNcyZOvpoHtomWg3J65MICqPK6+Aps2YVVOA4qMWmQNjZZ30jyn01J6TTUZNIILl8RRxJNDeGjFfnXQ5sb2OXQJcEeiGtWS2HEBTpizzVMrGx6Epia8jcakPMgFe3y88bbzE5o7Kvg487fthuHci10hs6Rm523F98Kq6DI6L5kF58XFYCj6Mh6xAjTNZq/CqVc1IzYqW9jvAHAeOmhYwL4dMFrIprF8mVOVW6z00/VqiLwatfR1ECWyt5F/C9xOq84Yb4pIUexSynRofo9p1eAofMmH7q8WM8Mf+tHDCtRyrzg8gruBlBiiQKy/XiOBFqgK+mR49wZyFv82NmVOJkOGCxRMtiqJKmz5Bz4ReoyMgnc5eVcLuGiZoKwWOjJnk8HDJhKb+gEqsTxiBOfJJbflQvvp2ZhzQ8VEgg45iOKX4GQ3I2kRXzGK0unRcCeKrjyEp65LPmoQ/IZp0XnpGf7Fvm4MSmWsnDKKZXGA6yIwUJKaHhyJXFHf3RkYWVo1nwAdIpibNaNlM5JPbBoRFz6z1y5gepr93sfa1vzymywZFI+eIS6X2rih8/dubAmeJCoS6ckb7092d+8X1d5Dd/ofltD/oO7Y+svEvnXJgw850y8JGOgbwKdClm7SglxZ0JsUlnh3yv99B3Dy5YJmMnizmd8nBLS4T79oeO1mZhZJF7HnEYsc3mcczjSPPK+joaR8rnFoiHIQs+207PvZq73lhDEz89WeTY2ClCUY6vn9jVFZUq9cKr8/MKEHYHp3HLhsIvrda2oa1xCCM8BHi2nq6efyYGd/IoGY+Mhpradz8ut3IL/LNm+06fjuFnz8/Sklh3W/DEUcEkGokuX9dZxVBFFtx5tGh6XqCjP9wvffHi5sjqdaGuPrmVW9DXc6x9drVMnb5AKC/m8YTyPFhJSKBUX5ela+9ZRUWFKLpTR4ThkMpYzzQ+PS16zpxhALbCDst7j3MOzrCZon1eDo8cIYqsPNGKCRoxngjH2ud1xBnRU5XkVnwQSrFxEhwBBZqgFSR42zS816aVTV2otcN+aaed1MLhPASSvDxPrtLniJitj39+K0+t3VRQXy9+JCR07WnEmwQ0+WWUIyOXSKJG3lJVKHnm5Nje5sf+J/iWt6AcmeWoOqHQ1z8v8sB9D2ZNn5vbfTrw708I2//LT7EQ8Frci2FGRRZO5qVFXPfDvfs7p00bnE3rGRPqNqY8UTT447RE31rQa26KibujZZiQHry5ICZ9JHIF1Mhy3spV8hMuysKluk5MgYB7Z+fCM0nbWpiRkGWsnXAakd6ZfFQmqiQuLA/lmyceE/jW9x2ogCUCAQnQsJTBcunwU42nG0MHdwcrZ0gD0RaXrx3wW4YZySqf6Y9bkIOB0pnZpXOy4tFoMOYyVyJYknrnFCLi5uQWFSC3mxh+5XPKo0pCvqJcL0IIEzeJSYFJuanJo04fa++eIWKLTzhzeXGQ9ly9UPj/v9SYdxB2pdj8i7KWz/7aoD+cO6LmewwOtBoKXbtW6hseiuZldw3vEShziznRmTUAFRteeEIEuYMn4qbP9jrTuyZuH8nNzc8PWr2JiZ/QjBj2AZDExFJUyPFzku8+NTC9Yqp3OtsQdOKgN+kbO1sBXQ6fKlpZbk728BMv5m9ca3f9+EcJS5Pj07n4yJFQQUGU2Y82kwCAOFz2vICsVhF/7LDmg2nGhSVLTiAOi2F8zjorAxJdU1GQRTM74afXz/TbCO/RG8jTM8/qV/r1hqlXZZq4J0P64xmv2Gcz3sp0cf9rbDOQG/Nmm7YTolfs2SU/4TidHXEDLR5QuXl7HjnF5fUPzw8dqgmHonmlomkUjZzp3t1fai0fcGQ2rO8SJPuOtxUvrzS7nzXTVH/objOMfk4mhSuxLwJFXw/T4Gfvc7sKciBwlW6nFpeUcppWC9fXrPGY2hNzlhfJuXskgoAfatu7W4bQnQ8X7/uvV9feXxWfSzZcI3HtqJaUm1tw3eq4qy5Eylyyf48h2hipsz0nJyQraSRGHBoIDIWj655qX/ueJaKrKD0OHG8tys2t2Sa3Fi+KmoHurvrBsmWwUxPevt3PurYdRdXzzJ7R1gNSbOb918o8hDIGayDhcgvFqdt96Klns7LOHqaIiWd4qOHl5rk3V0kx5LCe7t59IuJjoPIHBkQ/VJ91saYjMkLujIGT3UVN7Vl2AzQtJPJ+b29ft0w5xVXFZtdOuybTXBeevawwtO8A17Oml4w0daKA+Jct5KfYpeBfa9dJHrmQSsAfbzfSKOEH2aIjQxc9anjn4fxy/YSy0kVLvOKKZgclIhq9sGyZFMOU3tzy6qPti2cJeecWDeYPDo50Car1p2LL1mb7GfOwsx21YgoCK2VAYgRl8lbROdQzmIXGpVxPvhHGTR4dlURT0XPsfj+O8KOdiMiWV8JB8ebC9EUCGKpFiyCdaR84PVjE16olGEe+oWNNBSjwSEffDT70XuImC0FGd+3xzpqx5o7pORwhKU+dQTBdUK2DFz3txRcRYW9fqaycqTIYeOnf91DqpndMkxUG4iiQcHDes1dmPzucw+GBk2eKSoTzRkNRbyjceEJgZGooiERypxUa/FpJ06bt3jJYUiZdOb/0sBzBvADvTeXXGA5x6rOyF6KwDz1KOUaOHmBw5Kh4gZL6+mu2nln84RslHwy0/Wh7BUeCokZKYpM4e+dUiaWPWGyh8SRxSYqxDtlaK/TpM5Hp6L3bt5HHtp1f6BkZEPrJW1oVq63zzKrghBx+mnYOjJp2tr/yTHW1XLTyFswe6cqSN8Oc6dHGnzjTvuUbDbd8oCoerQHFgOswARIdRyNVURFZjbEG5VjybmmUWG0HhVZFUe84M9DQY+M4t7Z65l9ddkQd95ffNUc0NLu4jffM6Za+o62BEeEA0yFLet9OIIxxelDDZEnPdHYEekdbaqWX52+skB2DOOmRKI9Ks3tb3K2LJh3aZ+bpAAE31r1ZyiYhtC1dIuhZ/Q3NlpGuS74eJBsU+0g0Mqgk1NW178d1az9xizzFWD5wIM4ZsLsz9mlSl5I0NN/cnK1u+N1PbC9dWWmjfYZbeur3DS6cH4lLTsYTbWqJNgjr8xfltRzsrrwmN75UlZcbPnTMxrxmvIT7R/xlMu0RHbR0+YyXvl530/3CPLvr+0uXlh95RUS8RQyx6fg0qrw4ylGhYYkj2trKrbiQJDmXJobA3p3mppul6LIF4iLYeaZ7swzt0jVtwrisUN7ahCWl5TVBuHLF1N2Pt1VMj+R6hPMEOoZfPGrWXyu3fP724uamAVyaWZU/NLr+nhlm+9OmVLuJSba2tmBAxm8uK/AtCMhddpgf2DbY0x5Sa5IMcXbAH9gpjGt6dqBxj5nqNSOHhRvUN3hrj4X2tskAefu68I79w/c92GWpq+LO4bh9jXt5eXNXFOUr44oR2wEKZ1EaIid1dPg47I6jRzRFj5/sbBdG8eNn+z76sezW+iDLYvx8bWf0xlu6d+yR1/Rs1QAAQABJREFUL1paHWh9ofvIMc+iOdKGba96EfF9+cLHFi+K+Woat7wsvO6uj1SJ8QUTkuUhmFqYEXSVuPWF43701A7RWppPBgFg12ucIChtmFrS198ZPLRDasYYMtgidqcB5m4mrjPChE6ekDwc4vjJkes2yKjEuN8Q9o0MRnbvk1u46r+8OT6JYZZcXW12bBZWPLsyxgxQPmNo/gp5Lxrf6RNDK1ZLs+tbOrNNaLAvsni1MM/BYz3TK7wxtZfBBV/dab6jo39tWFYzD4Ti0hucurfbLMrhCTm/GJ+Gx2NmhU4v9Gi9mF0lWWFRs+P9gX3zEis1Mmo7jnaW59fGDS6wPuY+y1eRE5giOUlaDS4yPxYWzLt5jlSdNUxHYLQhMT8gPu9QbyX5rUnvyKJQgHaKriQRxpcuC27ayKQkb+5rHhgZ9QI4aaQ/9OpzkalToqun6HMslERjX/o7odX3vu9Y0cLpos+T2JLX2sn6up2ZebSLyVFu4IMr79L3mLyI9AgfcWiXQDl3jtm9N+6WcergcODw8WVL9Jhv7qHhU46phISeiZRlDbsQwKg4AfRJ78las8ClbzrcJMLXI1vN/dfIrVDvUOC1g/3DIkhjYy2Y4m2rk2eOHQhR8ZYd8fWWAvZUlge7ehu41djkRaYa6JXqqqpiTXWRBYuiy/KEr8p4n78gbndGLWRWJdFDGBfYbDFjatxEjgCDj0bnXq6PnO7+8tdG33/XyJRBkX4Lccrb2YXNloRSFwqE5+jsdPURMxI2u/YZG4zmTHMo1tZxcI/QC3ii7ACpXTJavlysbUePCq2+833BvAVF8U0H/f2xkUDLyRGJLcnoW3p6tL3PHlLXcGSYx7EHkmjEdog2ZK6SoSw1H9gfKy0XeYlYYiKAbd0qS38kn3fkZEs8hj7GPkQ1uzVgYDBnUZWokeqSFugbzVk2y6uC4trbOsLtXWiXekfmw83HzEPXSWWY5XcfN01KPofVFVBExvNP2g0ivzP6oK7WNqkCwkdpKdba6AwligxV80boRMa/jsTZuo2QPByKChk2tkk6iLXQBP6cpzNh1x9zbgXVPvfr/7dsSSTXG+xijZy11rm52bFAwCuSk/Yf07x8RdXyglgg2N8Zau8WkhnuCyHo2vVr1OD+Ae+CuUIi+PJOrSoaGfUEojK19HWG5q4oaNgjWCFfzJjpLyjxd7dLh3/4qwO/Xm1aO4Qp33pXtjcatTyissoLKYQ9/rxiFYMi0fbjPU88TinzoY/m9A/5wsGIlTmDuVOQen2sQcE7hiPTyyLClUkYknH1Qfqxey0YjtRo88PDsdrauuPSACgjkle4aOagRHaiGwZG6+tiM8vlKwpKsrrawg21YR9BZ+jaU6NIpO94O1njLSrI8YWHuoWLNg1OXbkumwG3dYtQ06aNMeE+sEJ4zZlOLzvfdKsMXlv9A57YyOjReqntuhuy8rIjLScEVYwBpeW+7n7/ipX8wmzj6e0MNzYI11uxNIJkeKZblMmYz88jhGMa6JMRVVxB3NfAaEDoB+8MhtZQnzZ71tTRtt6ckvxwUIoND8WKi2Udg7woqAipDBVrBR8NhEYjcC7SYOdosXfgCz+UF/3CA7mB/gAWRF3GN3NXEbZnoGNYxMeKklE2iTafClo/Fwh9OOArgIMykiPZdPTRWumvm68LZBVm9/Z6slQNzi/yRvqHiAvALU8s0jfEcrg0FQcJvDPnXjVNdouRRkfDDaf9OWoQ9XpbaoZnVOc+s1malJPvu2lTxJozl99YJmYbu2TU2xPGLyQWajktT8EymBqLOShGBO/o3GX51ha1f+vAnIU5pZUEjRKSDp3pQXWfVS4EIDthMFkhTOt6FOJHXpG/q0/Iu2wuEaZK49N1MDiy85A/19/bL1+x7flASVFIzpeTPRQYZH0vbBYQkMzf9pEZwhGtd82UohObGyvXlHMrv6os1tfvYc7ACZ4E/+Lw3yHpZQKZ9PVEWRkjv+WZ4C03hMvyh8/oEAuNhAqzgiN5pdwqmRpFlXrkR573/q4wRE7LCUa8OawCkWg/nUH/Mgpae770PV9JaER5oLnxRs6txmYrtwbbhuCZ1mKQX5rnZeUTU5bOVL2tgakSR1YqQzDkEMaSkpiHOknBYFdrMJ9gtAxt/BgZRM1Ncj0np6txmAEbwv2V6bwwsve16A03SzFfYR58I6rLaPme0aw8H9ZoRje3pi5ji3E0rjGijXg9o6d7LCdHfsoqyPbrQnosK6d4Zt7UKYKJMPriKYGjdawAkZatyS6bT0Az6b7m2mAwlp0dEyIW0/XoaFtL9LHHpNhH/qJCvo6ZkIQRB8DD4aF+aUNBVSnLa61t8rUz5xItJm+kXwYvHKKtzXPwkLntJqHPYP9IMavWqNz23snatkOdUDK/fHkEDgjOWSv9IoAy27FeTVcy3nkRLCi+ioVjWHD4jDxCVOyskkKrbsVCkeHOIX80ZEuxPBtTYwTF8Gyiptzp6nEvNXogm8iINI8R1NUZqWuUEeH3hGfPzwkNBtg/wE8cOQ7X5vzNTuFI/3CDmVLim7tIRmIWK/m4ccBE1MDR2lcw85+ENbk0UQTafs06IH39/ZtZG8/yBHtqmZ1NcXl2ni8Y5rgUkWhxXI1h2iE/fXY2pA77t4b4+tOiueNWTyJWOdPl6qWSZ2wuXJU7HPATLp2fLY3h69eOHFABq70tll/og7e0tQjxf/NQbHrE/FSIy9yebfpDZo70v1k6TUgb0kMHI7HMScS2F7Rv31EtojbDmmV7EsGsp8/0+7KEKzJHFHhHPOoWWJATCsWy4FUlM2VKys2KZhFXwK519/U1HBzYv18e7+qBnL2zKqKW5xOQDGOgDWCNPZ6Bha1SVUhZzwkUmLcKc5KRxyI93I4Uyc5dtyocy859/kVhDjdsjE4t8w5qIL/upiEIv0tUG3GIOYUvf68JKIO8qli+ruaU3ILkZ+LBkGXm67eD3uke87TOXNdFxORod63OyjFYq1DAjooUY4qKTdewbF8gzYzKAr9yIFmMxK6Chcr+BCtAwHGExNwIqvy1t5Ag+ARcOkhH201Ht/mpZEVuY+Zm4GndclQXNBFV5jmT5T2kgrPyHw3haWFV+pT+f+4/C3EC0FKDeebts83tb82WSI+kaKSlKepFtoEFxcL1NaFZi/Kf2yKg5BX5rl4bPrJPGMXGa0J4XaKRklCO9u43hyNmm/yKr25pVsJXrIWdasVfD5u/XCin11pywjL28hFTJJUZRHz8OmEhsEfS8Khn/nxvrzrRzV2c64enySRGlKiRY7uHDh00Te3y8/MDplXkPUmwYMbJfM2v85iPvVUYpBXKMVU9/bS5aoPcg9GiT2EgnVopbcrxR0dDvr6gECdsc7gv0n1GgDx9cqSzPRgg2r5S1xaFVyswq43B7280Zt73sDyEjgGDZdchCZUjFGYZVdqK7feLGvRcCc1cx7AlHqaUEoIBTV1LZk1RxinOKH71J/L7ozOq870aetfn9zQ3xfJyY2X5ojQGh0InWvJKpklHTCn2lk0NdzQLN0AgOXZSLBg6A5ipfvPUkHmbtocB3nkmVqOE2sh+6qjpjRnrAnnVKuHZduxgdUGGxW1WuDzLnuzv4jwj7TI8QhYuz5mqh0yWl4aLSvz1J0KozSS6DKUJKyWJSfN5HD5UC3k1IItCC9AulFY/dJcos2iyJPiVNx/Ig70c+iKqpgeZsPGMzJ4Vc/w5OZ6+AaE6Nue1NJvXWmJ3LJa+CA+OTqvKW7hIKMOLzfD4CEbpV5Rv8P0IquuU9TElNvTKoCDVaNx2Sxh64bz/0L41+hVT9VEoszFilOjEf1WJ4hx10k98mIhldL2qf/yVDtOF5c2T5UxYkm+dkWdET9e9KqZPXcCE/Y1uPmwWFoqUwAAog7NLF8Bbhwj0yspQAD2YFmtMb7+6BcI0WUQ50yDF8GEtPDjAQr3ahfEp8Ebbhnvb5BFMWp5hc7rNUzVb6P49C2Ult0N3qX7/+yOcF4LVgEQwMGxOCHXr1gtdVC/w1Z2SpU/S0X0BJrqao5Ed+q61FR1sjdmv1POOOcLlXz4qZPGee7yxUPhkrSmYIrMjkoov27do8Wny216O3n5TyCplHZ1moH1wz0tm7VXSTd2dscqZkZCea9hyKvDDR2NlBSxpCNmilhQVxG0ML24bWrkk7oJRXNx7MujDpl9CWDNYKic/d/Vuf0XyWJhO1Xnsi1AwGD+w8uJsqa3l2Cgj2VosvvyauSYrksU/EQWlF8QjQ+fXo0fFvvPUc/JjRlkYDsWcd7JRiq1bMcpyQi9jVJiwyOLWAtrVM3C6Cd/lwJlWaQOAo+aNRlrIz5jpm1LswRa2Z4dUWDEj1tEaZu4h7dopMR2uXSLXuxoG4U2vvhzXW1tberEM1dULjIsWiiPbK73mHYvlqXmcu9YRsfuzPL7wju2xnFwh2vp6mGnwqZ1mVaX8ZNbEskmdJAxzT+8IP3yH5IunRELDkVPb2uevkMqHB6MvPD7C1lZSdo5n56ux6uo+Gy+gL2B2d8XbM3KoF0+QbDXCHTkcZW0wEoxs3yo4QCF8bygkOO4KmGu2jq7fIJQB38yJBWK9+MMM87P7dBCfkG3HyRI8Z6ByfqggP7p7pzy1dg0qTezfviXM7VN/lCM8T9dketsDubFAd2eAjVqkuhrzzYj57avlpfUio0fsIhPkN9zY5fF12+k63DrIXG7DH88JDSPNHH9tsFidTn/8pGfFvOiBo9JHG1bIJHcEVoHTRY1By6uNegYHZK5jwsDvoqRETBVPPyVOedddrWY2fgeDUXxsdanqJz8KL18xUDZdPtYfDeO2gY+SdSBlwWnoxID1/GYQMWW2YBdibps7UjrNVzKto0KNC5GhaN9AH7YGbs2e4wkHInVHzA+2Cg53sY0/GtLFYPFIKp3ZsVdNzqvW+glMVn8i7PcLowgWmEivOfASWVbFer9RbzZJZeL6OqfKg/YOFKTpXW2ffcn85vXS1Oe2x95+u6k5El86xQhwaEfQTup5eYGrswPIPSR/Be6sseyywunTZZDW1QR9nl72iZB/6vHowoUjViHqa0OMZLN23O9ipKkrp2/QSpaRodGRQeryPP2kPHXzHQPD/dHtWwV8nLZWrvE1NUg+ogFQwKNLaaO21pSUDU8/IYSbnettOzUCDijkpNOng2xVqNon/fJol2cjsl2hfO38BSLmDo2ESqdJU19+NXLzdXJOIWnx0nA/C1/MPEjezLXtkZfrYveskFt9fcHBIU/ZNMkzB8+a7ckv6H9ur1SI+XkeMUdzpdn17QYS7hgSUOb5zA8PBm6rxMwvfBVbr88XKNbJ+5svGa8/8pZqaWhPnzca8+TmebyqVK9ZPTCTqy5NHAFYdmsrxedmt+5/VixpdiCMHAluHjRrowJybUgkGN2gh21NrFzIWgPC+QzRRqfC9JRmGtTGf0ZYnehd9fWjTJFkSOWcAd4gLuSkPYdN9cwIO0bKxTRkinpNx1kp+bscm4J8LJdN57DIZAzlVSLjGaLJ1A3GF1t2togL/Gn8bfvk1ozoUE2OOSV0Zx7EtcpnNkvWvK8ME3aoAU+qWUJCTHBo6VVKNscPheHDyDGkITniJPrTZrNKRC/ZW43eaOUBgHkCGYqPFfIUFzgO/92tHz7UZBYgM4gYht/UKGeJFxYOZgn3NV31ZrTTLrcLj4K/fkXp9tph1qb0E1T72tsjpgnCFpCeDpkqAiowb+pXcEhyX0R0HtIeFZhe0cll3YAZ8hliGbystyr7RClSrmNWc1x4v5mi7Wni0JOYzEpWMUBTHURJOyTP4Lg3neOUi8wOZZJU1RsU3ZV0OCzLU3wTSTvKaFvk516V+KmTRGcxwYNHi/ySR3ha7+jvif1p1kooOycoy5yH9gSXWeliOPrkU4goUovPb16uMUv3Bu3G3tZhE26O21FP5kmb1eQrZ7s8r/5ibWmvPqb9YzvlDrh3WB6x/A1VDSXT0szQfrNysWBy6pRUsW59rK8n8sgWyf/uvBAzfddpAajhVORMh7SWo3JJjBlhqZqgCLrRCsQcekLljCpL+Zh0gRFOS0JuZNXzCHu0G2RCeeaEqY6ZbSFhpLfpNjk9E95sHzXz0UA8cdVR32ZOSAXiLXbvsLmuWsQAElIqYuSglvjNveZdkZiiaPrwluA4tbMSNt031BkXvnkZ77Z1rj7DyoHUUFoin4IkNjo8xE4zEuZrgKrrMy+iTKPeiFlsxPo9LF8i0s62bXIdZ3YWjY7WGl1cMMUsIUCcSu2D3tjRkPwkMYaUMJln5efQMfOcx9wqWfN4xNwalS1wOjmImaAe24EOsepOMUL6KqRYeanMXpg/7EIjPkPM1JZTbTtlfhCMa2tMVxTnJXlKkYxfRE275QzpMcz5ezHzxGtS+93rxZf5pRrJl+cG1iHKau8PEkyA01KHjHrzmNp2M+vISHONtCE334OAgaPJsH4FxVG7apUF8YEMBPuNfH2CMOSx809UxQsZoEIlpIh8keUG8Sv2+th/qYF/QrUwUgQM/WcHqcV57Ed/5s55rm6d+qBVsNq/8lN6CFHYyjr004lGc1KZYwUrIpzuUyyvQZ9mqLCS2amcZjbbmpClfHKLU7k7g3LcBIlVhOpqkVSt6Lx+vZhW2cFBQodmxYsImHa5BZLlitU6kBsr8IzVmrdEhWlOGTXvv1ueQqCnsy2hM5CgqoMt5oQCjCxyhnh7UsrcmmfO+M1KKI+m5psadlpmx40EAyHDLlPxBdOpDsdfO9qpk2NLynQi4RaqEf5gjCsSrOeF7fKU3eiEQAwpExuJdPS4GLrsGY4iYQ/LU3Zt+VSdbNFSy7tY/ur4uVAeEbG7TcyNtvIX95o5xXE+/kSzODfP9ZkZMACkSSZUglGr2omzAPqnNYFjVsTb35NtamHnWDcLRR0/pbPR9cUSFtHOjgwh3ovzYLypR82hJjOXWVq/jgYA4GswWiS2cuF6+FiRMMGihmmYNLFWPnnG1A6ZLp3IfyXLEN8vPiZHzSv1ZnvYXFcgT900S/Rbu3sZU8rxU0YdnURGxE46itlSSYhPqTp7zFUrfnwxs1pFBuZaQMayaAM00P7jx2T8k/h8MASrXYxUppaImVtkYyZJIyFC25UFhXKELC5vL+kMPQdTVsT0MpLoo4gpp7OUbn/rFnH1/t5mcxN8UZQBc/B43ETUPGo2LZE+sn4KsswSE1GGtGhediTm7WoVjvPRV2KfWysz9GMvyC1O867vN/O0csx8OQED6yRtYqvuerEyWK8ZFtYf2yoSEunuOwhy7unqiNlNq3uIhhAzX0JCMeb3ZspwYKIiba83A2zIjpj7FAfis4AwhlgSLYSKli3DeVYGCQon6NmEHZpuxR2VxIoUK3+gZJHEfEhp5jBSM65D+LTKB5lfmSU7hxfMl48iQQn4+OxEeEHnXCFDDEreonTywLUS59K69fFptEFVBrkCb6UjKExCnebT7GLpZjYcjcS9R0B0YZXWr/MtU9Gg3+QrqxvmbMYKMXNazZBqcdTSMSrh3Lj4lDb7g3dm5Rd6s72RUVGZZG8XtGFf9MlD5g/nxB8HAWpA5Ub3ICGQweBnKqECINYNWmhNEtiGQPWEThKoZ7b98gxTke5ls8XgTvua4nvEVnCUul+GmIUL3Rirv0+he4JOwZyv+VVVUoaWdCo9eDiVsCI+zDsRf+M7rUQlQ84QBqZPEQvqhT5hs6SKoBzhEvZhLZaffMpOr7lJiw0GRWSZIpdlxuphWwUxGrXTaSpBfBq1ZxF0Goy5XnlameLMgnGv8tUP3GfW/FgJSytxf86NwI632inyyFd3YDmmc+2wImTCQQ6T1efXMKd42H8iP6BewOefyntiamVKtNML3Chf7bIU48q1ZaKlVOn0vmGDOH299IrUsGvItBHdNmBKdTLlCIa9jF+5I50Ojej8FhdZ+PluvcUUVkdIBs1DGMgfcETtc9lFU6dXuHmziqRLtBhn/rG+u5CDIbV9xWGDdV6CZcB+WWKF1KnFmPohw2FXXNapT2KCsbfFTvS4XGEvh8S0pVJgFs/KQyKwQqvVmq/Eud5rFvlFKiA1nxZ+Yp1T6hrNFmQ85dgw3XrmwbMfCLYzVSrikQOKGIx0tlRgTjMjMMA1D+o0v1zzXOEn06OVuijDTyvb0ez12jsU5C4dsQHs9L21UXP4bM0Ug9f2ZJmXdPwCFBjq4JMOPXn2pSA8VgIEhW2s+xO9foMWXOExIz5zM9vGtVIkgWO1Jqz95We1Hg3Zb3ZpN2eFZdlzjnYf8yY2Il3Il9hnz+FaflaFSHk9nWXlyw/70YrNl0LmvVoCwfsnnGep+UY08zwzf2p8IzaLIYhJIaWGBXNEz2htAWbzh8fMXdDJiPmeIn4iTcm0RPIA80uemSpWbKmdKexJgkzrJ7ynWuZBZucGXol+qx38A8kahBCIUwOQmUdUeYN5au/ZOGbxPoI3rsM+yNlfShCIB8Q2sja75xql3+0AoSUtSc1D+uJrrIpF2/mnXNPMU7q602esBwl1iuSg0tfqfJlhUTae0Z/3QD+VopiRENjgxra/epgi1TNdGbPYI+gIdB4Sedqj3x1fVyFfordm64BSFKVYsbZN+1xI/aQeM0XBm7GkFJluyBglc73giXnCigS7dxss1LAO0iOjopzoLCGfBuoVZ1caSziWPEtOkCPN5/BRlZZZG5QUM8V55sgZm5WVBq9MV/Jd4WzR1kb1KWSJ3T4zUxvHBhQf3pLsJpOCErLi2FluoI/+/zbo/Yv9w6i0BHCxFf3s8/NRES2L/9nrGX+dp7r1/RXWU+L09sa/+455wWPuVBAXEAUQtqh08e2omQExKcsp8JttAfNwzHxZXw6RNehaOb/uVRLZrtdx7FqaJ4HfPqDjFWYNP31N5x8RsFgHzDVTdfD9L52HQUuJcSlzCdFQtLPPIK8rLd5SKjV+jwOZguZ+pWyGQj17gkIibZAalf4s7r+oK4l9ynEORMxyBk1WXO4ROvbHR9R8gt7FzIBSel9IikFnut5jluJYlGW2Kgh4KRwdMi1e86B+e6nf/ITVPG1eKe4HeJ1psWd8ZiPSW2587cUzKKzk+/rIQ4Pm0YB5CNbOfIltLGg6ONxYb8X6zFYy2gZUQWpaz9jWCl+JSmC8RTo+asIiQa7RGQzbCZtuGWz1Up+E4mHk7NL8Ro+ZUWxm6eMdhCEImhWFcSeKxiERMbfomLyKZ3NlnrOOeBv9ZlWRadQxecZr2Bl3u76UCAVfYRM1UrJWvoDGZ5sS7a+ekFkSFLcEmCbp5SxzX655UmtYEDU4ZAEXqTIqyt4A9Svfep4ZNCv+dZyxxAyxw45Pv5kdNgf9RpegxIfqUNBM08Ea85rHfebDHlOnI/UAC74+o5478l3Fo2aZNnUwx3x/xDwYNMe1X17l1ViUpQkyVSw25knNf7LE/AQ9vMNUA5n2BYzbSrdZRD7NMx358W5Cjn82aO7RLhsNmS0xc6f214EesyXLPOA1X1MyvlfDYdpp9WkCFmj3UTNe4m/BydxjntSnrg6Z7t64LLKs1DyWYzYicMNljXksYKrD5jFt9m1+wwL+GVvdqMhJSGkMOtLNaMKcx6NwocHewu62PHNYv/1anzlMADMloUMcGz9ibtPaDmDz9krIqYP6854sc8Zj8nUyOa6DtENrDnEGlc9clWfytdhCPfMspiPx27DgLPMqxzhp9xGLlF5G1iFhjWsMm91KDBASESv25Zjr9GNxCkcF8uhXMEnM1S7gEWYLZMGXEGK08luyzf4cs1zzRNvCt4SXPKFkgxZJJAKt29xZZE54zDNUBPOZZtbi5eQ115fKT5SZzRzeps3+OjBmxbnWyyxe0un48SnNjEalDTHFakq+meM1x1SgpIaTQXMsx1yjbSiOCsEwZ5DWszUlaqbRAiXCtZQcjs/Q7841T/vM7cZs0ZKY99gPVSUPyYy476xMdje+mh5R+BFYSQRxP04kSf26+qBh1TyoWKFusZR3D7Yq/doORGqUdnlCXkezNxgxD5P4Ir7GStsUgCoK9Dpk2KRWVdub9A4s7pDeQtKYiS1W87QNdrhfBRQuPHqvueqnCpzedX/OiUD0n6aODsv0cmDb0O+/INp4h4641ZyzrV3Prb0qYVu6hTrorzKdGbllx7Q+IT3CWFBLjjB82CBR7H5ZH9tVbKaHzLY+aU6XKgP0mlKKcAPGrpKq3CUpNcVrpsw6vdiuZShJsm2g0bP0Z482SclWZg3qt7XBtmHySKg6ymXcMUvYBrPCA3lb0uJzuEWzlaKlVVCanYp5BcyMR3SCkluUsc0jA03qeJVVCAos4JbyVRQAvBe3aYNmDYksCFykWn0LH26RpNkQvIXOvo76dR6TxvAW21R9NE7tNJXytMo+lULofKkFgbaRWXQW4UZttsWEankpgDBwSDRmydl1Kr6U9+pc9zOvtg245H/t+AWwDTQgy9wgNEi8R9kwZlHl647qBNGg7+YvzWaOIMFncBjiA0kn9VtAZqykT4hXYY/PEMygSstRM71PR5MgGPgJ6zz30gH0eEwEpLcBk75xX8ysUwIiKPV27bszcidOVJr9mT/0tRAhR0tqZ3jYBITBS4ssJsoCYcuwk+ogOUwcELUUcLNCa6bjSDTM9oL++pk/UM4CHWVRbepSvzmOr4HSAZIevNR2K2+mqgT9UBYQ9CN+pjaIjX+Q8QKlJ84kK9BRT6EdHlPoN4hDOmSFgKtzztpBYuY4zqjaALzpIV2etqRIsyEz23j7LT/zvrM/gJbxkiBInqWp2gRpJ9joMBLxrPfsSGRVYBr2eq9Zo2/qHjTfO6v2wECS4aIeUNLek9qYLGya7ZEA8bRcPSLNCehNGRR3Z+kwH9By0B74WwC5QG2Qhx2V0BtcCLpl5JKA2g5b/fWG+TPXmPrJUrfad9nl58BwuK5NOLtFv1D9dNmpSGrQvkl0Dx08R2d6bk1TmrAjebr2AdCTIAjGCWkWHQv6IekVuBUJYuAWxKRjLb4qpaVEeaCYHQMUs3kukpr1b6X+tVXRHkuvlgnqHWEKPGhfBHEwTihjSY3y1GzzNIC8si8pQDGe4rtIBWcJiDyExafxj6FOYvicPjsTUBv/LJ+Cwhhs9nNsMa7bBgMUpAkyJIY6Lac2+7EQKLcSiVt8qb3FAKZtdkSBJMlyXhrJS7liiZimUt6yDyYSXmrnPJ6FcfA4dZL4ZDI0ksSX0gySvQWPYz/OsOJInbyXDiXxpW2aseBTM7e4SKJyKuGl9qMoBsHYD6E9oGqJAYRJvLpEMxQAHzsmeZx8l17nEdpJ5brZSgwnNI9vJPGxVF51tssoQ5upn0R7KGMx4UspVnkWE6rlLZZvUjP182rSbBVeabPtJiiED7EJDHmX9DL1aupg46wCxCocFc4427V1rL6eRQaguMyDJEYNDYMGSMDIJ1O5BRASslBzizZDP1yxH0jDaB7fRSIDVrbZtIfHbc3colp+WpKmgaBNhbbTeRFEbj+EAnQjd0nUSVWQhC3GRRi3fSnEk8CHPG9JiCCWYFAVSPVYts62TX5rzZY4eYRvtPyU67SBPH1K6tW/9nv5S/lcvQLl2B5XQhMEeIT6STSeDOhZuGxJvSPF+CiLD1doJ3cJv0eCTro48krLWUKyH061VAjtJZrKR9mXAh2NoUJ7i+6mZttlXOGLbONpDNe5Yr+Cl4KkhXGGDiJeZCmKMtRp6ZzCvNom6uQnzbAvIkMfWQqiF8jY9tjCEKTVxNAMaZJ9KS2hWiDlCgnAeapb8/aN/CVRM82mW+2sDDC80Y5uvhSKssm+NAHj2hJTuOKGszfd/+dGINbwijVUswZ7XKnEAk4H0RG2L+AAKYkuoHdSEv0I0drHE7dmaw6i4hFIhcRwoDfpd0sPli3oncx/eJCU/DpaZVmlvcUbqc0mRgS3kgufvfMz/0NLtNY2lWf5CYNKJL4C8ktOFgcanEzevN1eh9XwCD/tXWrjnx25sHHewrtI52xV8hsvPm/BoR4QpgHJH5hcOUPJNiz505ILTHa+RFmQnZppA2NcuaC8FtYEw7F9AXNLdIrtIDtFWp5wzkZaTmJnAQpTG8l2n6UlfsKvSLSBvrN5bsFbaCEJDFs1c84/QEqn29ZCMzxIg0lQBUOAKzSDRBvSKU3vjPfHdqttMy9KwJL4ivEeHuOebQ/tpIX8JTFgE6PMPsR7uWsTL72Y152t5hz/QwbJzIG304lMYST6qO0cT8dvM9fYjrCP26HKPWafxCfwaVRoB0jKS5NfQjFGyjgFkgtfsXkwvPqGGybYvPNc3Zpgra6YQ8Ah4BBwCDgEHAIOAYeAQ8Ah4BB40yNg7RFvehgcAA4Bh4BDwCHgEHAIOAQcAg4Bh4BD4FIj4NStS42oq88h4BBwCDgEHAIOAYeAQ8Ah4BBwCCgCTt1yhOAQcAg4BBwCDgGHgEPAIeAQcAg4BCYFAaduTQqsrlKHgEPAIeAQcAg4BBwCDgGHgEPAIeDULUcDDgGHgEPAIeAQcAg4BBwCDgGHgENgUhBw6takwOoqdQg4BBwCDgGHgEPAIeAQcAg4BBwCTt1yNOAQcAg4BBwCDgGHgEPAIeAQcAg4BCYFAaduTQqsrlKHgEPAIeAQcAg4BBwCDgGHgEPAIeDULUcDDgGHgEPAIeAQcAg4BBwCDgGHgENgUhBw6takwOoqdQg4BBwCDgGHgEPAIeAQcAg4BBwCTt1yNOAQcAg4BBwCDgGHgEPAIeAQcAg4BCYFAaduTQqsrlKHgEPAIeAQcAg4BBwCDgGHgEPAIeDULUcDDgGHgEPAIeAQcAg4BBwCDgGHgENgUhBw6takwOoqdQg4BBwCDgGHgEPAIeAQcAg4BBwCTt1yNOAQcAg4BBwCDgGHgEPAIeAQcAg4BCYFAaduTQqsrlKHgEPAIeAQcAg4BBwCDgGHgEPAIeDULUcDDgGHgEPAIeAQcAg4BBwCDgGHgENgUhBw6takwOoqdQg4BBwCDgGHgEPAIeAQcAg4BBwCTt1yNOAQcAg4BBwCDgGHgEPAIeAQcAg4BCYFAaduTQqsrlKHgEPAIeAQcAg4BBwCDgGHgEPAIeDULUcDDgGHgEPAIeAQcAg4BBwCDgGHgENgUhBw6takwOoqdQg4BBwCDgGHgEPAIeAQcAg4BBwCTt1yNOAQcAg4BBwCDgGHgEPAIeAQcAg4BCYFAaduTQqsrlKHgEPAIeAQcAg4BBwCDgGHgEPAIeDULUcDDgGHgEPAIeAQcAg4BBwCDgGHgENgUhBw6takwOoqdQg4BBwCDgGHgEPAIeAQcAg4BBwCTt1yNOAQcAg4BBwCDgGHgEPAIeAQcAg4BCYFAaduTQqsrlKHgEPAIeAQcAg4BBwCDgGHgEPAIeDULUcDDgGHgEPAIeAQcAg4BBwCDgGHgENgUhBw6takwOoqdQg4BBwCDgGHgEPAIeAQcAg4BBwCTt1yNOAQcAg4BBwCDgGHgEPAIeAQcAg4BCYFAaduTQqsrlKHgEPAIeAQcAg4BBwCDgGHgEPAIeDULUcDDgGHgEPAIeAQcAg4BBwCDgGHgENgUhBw6takwOoqdQg4BBwCDgGHgEPAIeAQcAg4BBwCTt1yNOAQcAg4BBwCDgGHgEPAIeAQcAg4BCYFAaduTQqsrlKHgEPAIeAQcAg4BBwCDgGH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" + } + }, + "cell_type": "markdown", + "id": "4576b576-4ac0-433a-9d1d-f39225a6648d", + "metadata": {}, + "source": [ + "\n", + "### 2. Spectral Gating\n", + "![image.png](attachment:68c16acf-c28e-4bb8-a453-abbebc0137ce.png)\n", + "\n", + "In order to use this technique, you simply need to use the `reduce_noise` handler.\n", + "\n", + "Spectral gating selectively filters signal frequencies based on amplitude, offering targeted noise reduction or feature enhancement in signal processing applications.\n", + "\n", + "Reduce noise from an audio file or directory containing audio files. The audio files must be in .wav format. The cleaned audio files will be saved in the target directory. For information about the noise reduction algorithm, see [noisereduce GitHub](https://github.com/timsainb/noisereduce). Notice that the saved files are in .wav format, even if the original files are in another format.\n", + "\n", + "### Parameters:\n", + "\n", + "- `audio_source`: path to the audio file or directory containing audio files\n", + "- `target_directory`: path to the directory to save the cleaned audio files.\n", + "- `sample_rate`: Number of samples in one second in the audio file. Pass `None` to keep the original sample rate.\n", + "- `duration`: Duration of the audio file to clean in seconds. Pass `None` to keep the original duration.\n", + "- `channel`: Channel to clean. Pass the number of the channel to clean. To clean all channels, pass `None`.\n", + "- `silence_threshold`: The threshold to remove silence from the audio, in dB. If `None`, no silence removal is performed.\n", + "- `use_multiprocessing`: Number of processes to use for cleaning the audio files. If 0, no multiprocessing is used.\n", + "- `verbose`: Verbosity level. If True, display a progress bar.\n", + "\n", + "#### 2.1. Example" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "f10a5ecd-bf90-4650-a42e-d3fbfff78e52", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "> 2024-03-04 16:07:39,378 [info] Storing function: {'name': 'noise-reduce-reduce-noise', 'uid': '6e6d6f7c3f8243b995dc1bbcf66f7544', 'db': 'http://mlrun-api:8080'}\n", + "> 2024-03-04 16:07:39,541 [info] Reducing noise from audio files.\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Noise-reduction: 0%| | 0/2 [00:00 2024-03-04 16:07:39,565 [info] Reducing noise from test_data.mp3.\n", + "> 2024-03-04 16:07:39,566 [info] Reducing noise from test_data.wav.\n", + "> 2024-03-04 16:07:46,174 [info] Saved cleaned audio file to clean_data/test_data.wav.\n", + "> 2024-03-04 16:07:46,175 [info] Saved cleaned audio file to clean_data/test_data_mp3.wav.\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Noise-reduction: 100%|██████████| 2/2 [00:06<00:00, 3.31s/file]" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "> 2024-03-04 16:07:46,211 [info] Summarizing the results.\n", + "> 2024-03-04 16:07:46,212 [info] Done (2/2)\n", + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\n" + ] + }, + { + "data": { + "text/html": [ + "\n", + "
\n", + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
projectuiditerstartstatenamelabelsinputsparametersresultsartifacts
noise-reduction0Mar 04 16:07:39completednoise-reduce-reduce-noise
v3io_user=yonis
kind=local
owner=yonis
host=jupyter-yoni-d56767c87-678n2
audio_source
target_directory=./clean_data
use_multiprocessing=2
silence_threshold=50
successes
errors
\n", + "
\n", + "
\n", + "
\n", + " Title\n", + " ×\n", + "
\n", + " \n", + "
\n", + "
\n" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n" + ] + }, + { + "data": { + "text/html": [ + " > to track results use the .show() or .logs() methods or click here to open in UI" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "> 2024-03-04 16:07:46,389 [info] Run execution finished: {'status': 'completed', 'name': 'noise-reduce-reduce-noise'}\n" + ] + } + ], + "source": [ + "noise_reduction_run = noise_reduction_function.run(\n", + " handler=\"reduce_noise\",\n", + " inputs={\"audio_source\": audio_source},\n", + " params={\n", + " \"target_directory\": \"./clean_data\",\n", + " \"use_multiprocessing\": 2,\n", + " \"silence_threshold\": 50,\n", + " },\n", + " local=True,\n", + " returns=[\"successes: file\", \"errors: file\"],\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "699615d7-bba1-4147-ad3d-d295d794f866", + "metadata": {}, + "source": [ + "### Looking at the result" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "47c4f66a-d5d0-47e5-9842-abbe6653526b", + "metadata": {}, + "outputs": [ + { + "data": { + "application/json": { + "test_data.mp3": "clean_data/test_data_mp3.wav", + "test_data.wav": "clean_data/test_data.wav" + }, + "text/plain": [ + "" + ] + }, + "metadata": { + "application/json": { + "expanded": false, + "root": "root" + } + }, + "output_type": "display_data" + }, + { + "data": { + "application/json": {}, + "text/plain": [ + "" + ] + }, + "metadata": { + "application/json": { + "expanded": false, + "root": "root" + } + }, + "output_type": "display_data" + } + ], + "source": [ + "dfn_run.artifact(\"successes\").show()\n", + "dfn_run.artifact(\"errors\").show()" + ] + }, + { + "cell_type": "markdown", + "id": "6eeae1bb-c714-491b-91dd-f22148cd0970", + "metadata": {}, + "source": [ + "The output of this function is the same as the first one." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "mlrun-base", + "language": "python", + "name": "conda-env-mlrun-base-py" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.16" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/noise_reduction/noise_reduction.py b/noise_reduction/noise_reduction.py new file mode 100644 index 000000000..f0fff5504 --- /dev/null +++ b/noise_reduction/noise_reduction.py @@ -0,0 +1,625 @@ +import logging +from abc import ABCMeta, abstractmethod +from multiprocessing import Process, Queue +from pathlib import Path +from typing import List, Tuple, Type, Union + +import librosa +import numpy as np +import torch +from scipy.io import wavfile +from tqdm import tqdm + +#: The value to send into multiprocessing queues to stop the process: +_MULTIPROCESSING_STOP_MARK = "STOP" + +# Get the global logger: +try: + import mlrun + + _LOGGER = mlrun.get_or_create_ctx("noise_reduce").logger +except ModuleNotFoundError: + _LOGGER = logging.getLogger() + + +class ReduceNoiseBase(metaclass=ABCMeta): + """ + Base class for noise reduction. + This class is aimed to be inherited by specific noise reduction algorithms. + You must implement the following methods: + - clean_audio: The method to clean the audio, where the noise reduction algorithm is implemented. + - save_audio: The method to save the audio to a file. + - load_audio: The method to load the audio from a file. + + After implementing the above methods, you can use the reduce_noise method to reduce noise from audio files. + """ + def __init__( + self, + target_directory: Path, + verbose: bool = True, + silence_threshold: float = None, + ): + self.target_directory = Path(target_directory) + self.verbose = verbose + self.silence_threshold = silence_threshold + + def reduce_noise(self, audio_file: Path) -> Tuple[bool, Tuple[str, str]]: + """ + Reduce noise from the given audio file. + + :param audio_file: The audio file to reduce noise from. + + :returns: A tuple of: + - a boolean indicating whether an error occurred + - a tuple of: + - audio file name + - target path in case of success / error message in case of failure. + """ + try: + if self.verbose: + _LOGGER.info(f"Reducing noise from {audio_file.name}.") + + # Load audio data: + audio = self.load_audio(file=str(audio_file)) + + # Perform noise reduction: + reduced_noise = self.clean_audio(data=audio) + + # Remove silence from the audio if necessary: + reduced_noise = self.remove_silence(audio=reduced_noise) + + # Prepare target path: + target_path = self.update_to_wav_suffix(audio_file=audio_file) + + # Save file: + self.save_audio( + audio=reduced_noise, + target_path=target_path, + ) + + if self.verbose: + _LOGGER.info(f"Saved cleaned audio file to {target_path}.") + + return False, (audio_file.name, str(target_path)) + except Exception as exception: + if self.verbose: + _LOGGER.error(f"Failed to reduce noise from {audio_file.name}.") + _LOGGER.error(f"Error: {exception}") + # Collect the error: + return True, (audio_file.name, str(exception)) + + @abstractmethod + def clean_audio(self, data) -> Union[np.ndarray, torch.Tensor]: + """ + Clean the audio from noise. Here you should implement the noise reduction algorithm. + + :param data: The audio data to clean. + + :returns: The cleaned audio. + """ + pass + + @abstractmethod + def save_audio(self, audio: np.ndarray, target_path: Path): + """ + Save the audio to a file. + + :param audio: The audio to save. + :param target_path: The target path to save the audio to. + """ + pass + + @abstractmethod + def load_audio(self, file: str) -> Tuple[Union[np.ndarray, torch.Tensor], int]: + """ + Load the audio from a file. + + :param file: The file to load the audio from. + + :returns: A tuple of: + - the audio data + - the sample rate + """ + pass + + def update_to_wav_suffix(self, audio_file: Path): + target_path = self.target_directory / audio_file.name + if target_path.suffix != ".wav": + old_suffix = target_path.suffix[1:] + target_path = target_path.with_stem(target_path.stem + f"_{old_suffix}") + return target_path.with_suffix(".wav") + else: + return target_path + + def remove_silence( + self, + audio: np.ndarray, + ): + """ + Remove silence sections from the audio. + + :param audio: The audio to remove silence from. + + :returns: The audio without silence. + """ + if self.silence_threshold is None: + return audio + + # Get the indices of the non-silent frames: + non_silent_indices = librosa.effects.split( + y=audio, + top_db=self.silence_threshold, + frame_length=2048, + hop_length=256, + ) + + # Get the non-silent audio: + non_silent_audio = np.concatenate( + [audio[:, start:end] for start, end in non_silent_indices], axis=1 + ) + + return non_silent_audio + + +class ReduceNoise(ReduceNoiseBase): + def __init__( + self, + target_directory: Path, + verbose: bool = True, + silence_threshold: float = None, + sample_rate: int = 16000, + duration: int = None, + channel: int = None, + ): + super().__init__(target_directory, verbose, silence_threshold) + self.sample_rate = sample_rate + self.duration = duration + self.channel = channel + + def save_audio(self, audio: np.ndarray, target_path: Path): + # If the audio has more than one channel, transpose it in order to save it: + if len(audio) > 1: + audio = audio.T + + wavfile.write( + filename=target_path, + rate=self.sample_rate, + data=audio, + ) + + def load_audio(self, file: str) -> np.ndarray: + data, sr = librosa.load( + path=file, + sr=self.sample_rate, + mono=False, # keep channels separate + duration=self.duration, + ) + # set sample rate: + self.sample_rate = int(sr) + + # convert to int with scaling for 16-bit integer + data *= 32767 / np.max(np.abs(data)) # re-scaling + data = data.astype(np.int16) # change data type + + # select channel + data_to_reduce = data[self.channel] if self.channel is not None else data + return data_to_reduce + + def clean_audio(self, data: np.ndarray) -> np.ndarray: + try: + import noisereduce + except ImportError as e: + raise ImportError("Please install noisereduce package") from e + + reduced_noise = noisereduce.reduce_noise(y=data, sr=self.sample_rate) + + # add channel back after noise reduction + if self.channel is not None: + # putting the channel back in the data + data[self.channel] = reduced_noise + # updating the data to save + reduced_noise = data + + return reduced_noise + + +class DFN(ReduceNoiseBase): + def __init__( + self, + target_directory: Path, + verbose: bool = True, + silence_threshold: float = None, + pad: bool = True, + atten_lim_db: int = None, + **kwargs, + ): + super().__init__(target_directory, verbose, silence_threshold) + self.pad = pad + self.atten_lim_db = atten_lim_db + self.kwargs = kwargs + + # import required packages + try: + from df.enhance import init_df + except ImportError as e: + raise ImportError("Please install deepfilternet packages") from e + + if self.verbose: + _LOGGER.info("Loading DeepFilterNet2 model.") + + # Load the model: + model, df_state, _ = init_df() + self.model = model + self.df_state = df_state + self.sample_rate = self.df_state.sr() + + def save_audio(self, audio: np.ndarray, target_path: Path): + try: + from df.enhance import save_audio + except ImportError as e: + raise ImportError("Please install deepfilternet package") from e + save_audio( + file=target_path.name, + audio=audio, + sr=self.sample_rate, + output_dir=str(self.target_directory), + ) + + def load_audio(self, file: str) -> torch.Tensor: + try: + from df.enhance import load_audio + except ImportError as e: + raise ImportError("Please install deepfilternet package") from e + audio, _ = load_audio(file=file, sr=self.sample_rate, **self.kwargs) + return audio + + def clean_audio(self, data: torch.Tensor) -> torch.Tensor: + try: + from df.enhance import enhance + except ImportError as e: + raise ImportError("Please install deepfilternet package") from e + return enhance( + model=self.model, + df_state=self.df_state, + audio=data, + pad=self.pad, + atten_lim_db=self.atten_lim_db, + ) + + +def _multiprocessing_complete_tasks( + noise_reduce_type: Type[ReduceNoiseBase], + noise_reduce_arguments: dict, + tasks_queue: Queue, + results_queue: Queue, +): + """ + Complete the tasks in the given queue and put the results in the given results queue. The function will stop when + the given tasks queue will receive the stop mark. It is aimed to be used with multiprocessing as a process. + + :param noise_reduce_type: The noise reduce type to use. + :param noise_reduce_arguments: The noisereduce initialization kwargs. + :param tasks_queue: A queue to get the tasks from. + :param results_queue: A queue to put the results in. + """ + # Initialize the reduce noise object + noise_reducer = noise_reduce_type(**noise_reduce_arguments) + + # Start listening to the tasks queue: + while True: + # Get the audio_file: + audio_file = tasks_queue.get() + if audio_file == _MULTIPROCESSING_STOP_MARK: + break + audio_file = Path(audio_file) + # Apply noise reduction and collect the result: + results_queue.put(noise_reducer.reduce_noise(audio_file=audio_file)) + + # Mark the end of the tasks: + results_queue.put(_MULTIPROCESSING_STOP_MARK) + + +def reduce_noise_dfn( + audio_source: str, + target_directory: str, + pad: bool = True, + atten_lim_db: int = None, + silence_threshold: float = None, + use_multiprocessing: int = 0, + verbose: bool = True, + **kwargs, +): + """ + Reduce noise from audio files using DeepFilterNet. + For more information about the noise reduction algorithm see: + https://github.com/Rikorose/DeepFilterNet + Notice that the saved files are in wav format, even if the original files are in other format. + + :param audio_source: path to audio file or directory of audio files + :param target_directory: path to target directory to save cleaned audio files + :param pad: whether to pad the audio file with zeros before cleaning + :param atten_lim_db: maximum attenuation in dB + :param silence_threshold: the threshold to remove silence from the audio, in dB. If None, no silence removal is + performed. + :param use_multiprocessing: Number of processes to use for cleaning the audio files. + If 0, no multiprocessing is used. + :param verbose: verbosity level. If True, display progress bar and logs. + :param kwargs: additional arguments to pass to torchaudio.load(). For more information see: + https://pytorch.org/audio/stable/generated/torchaudio.load.html + """ + if verbose: + _LOGGER.info("Reducing noise from audio files.") + + # create target directory: + target_directory = _create_target_directory(target_directory) + + # get audio files: + audio_files = _get_audio_files(audio_source) + + noise_reduce_arguments = { + "target_directory": target_directory, + "pad": pad, + "atten_lim_db": atten_lim_db, + "silence_threshold": silence_threshold, + **kwargs, + } + + if use_multiprocessing: + results = _parallel_run( + noise_reduce_type=DFN, + noise_reduce_arguments=noise_reduce_arguments, + n_workers=use_multiprocessing, + audio_files=audio_files, + description="Noise-reduction", + verbose=verbose, + ) + else: + results = _run( + noise_reduce_type=DFN, + noise_reduce_arguments=noise_reduce_arguments, + audio_files=audio_files, + description="Noise-reduction", + verbose=verbose, + ) + + return _process_results(results, verbose) + + +def reduce_noise( + audio_source: str, + target_directory: str, + sample_rate: int = 16000, + duration: int = None, + channel: int = None, + silence_threshold: float = None, + use_multiprocessing: int = 0, + verbose: bool = True, +): + """ + Reduce noise from audio file or directory containing audio files. + The audio files must be in .wav format. + The cleaned audio files will be saved in the target_directory. + For information about the noise reduction algorithm see: + https://github.com/timsainb/noisereduce + Notice that the saved files are in wav format, even if the original files are in other format. + + :param audio_source: path to audio file or directory containing audio files + :param target_directory: path to directory to save the cleaned audio files. + :param sample_rate: Number of samples in one second in the audio file. + Pass `None` to keep the original sample rate. + :param duration: Duration of the audio file to clean in seconds. + Pass `None` to keep the original duration. + :param channel: Channel to clean. Pass the number of the channel to clean. + To clean all channels pass None. + :param silence_threshold: The threshold to remove silence from the audio, in dB. + If None, no silence removal is performed. + :param use_multiprocessing: Number of processes to use for cleaning the audio files. + If 0, no multiprocessing is used. + :param verbose: Verbosity level. If True, display progress bar. + """ + if verbose: + _LOGGER.info("Reducing noise from audio files.") + + # create target directory: + target_directory = _create_target_directory(target_directory) + + # get audio files: + audio_files = _get_audio_files(audio_source) + + # Create the reduce noise object: + noise_reduce_arguments = { + "target_directory": target_directory, + "sample_rate": sample_rate, + "duration": duration, + "channel": channel, + "silence_threshold": silence_threshold, + } + + if use_multiprocessing: + results = _parallel_run( + noise_reduce_type=ReduceNoise, + noise_reduce_arguments=noise_reduce_arguments, + n_workers=use_multiprocessing, + audio_files=audio_files, + description="Noise-reduction", + verbose=verbose, + ) + else: + results = _run( + noise_reduce_type=ReduceNoise, + noise_reduce_arguments=noise_reduce_arguments, + audio_files=audio_files, + description="Noise-reduction", + verbose=verbose, + ) + + return _process_results(results, verbose) + + +def _create_target_directory(target_directory: str) -> str: + target_directory = Path(target_directory) + if not target_directory.exists(): + target_directory.mkdir(parents=True, exist_ok=True) + return str(target_directory) + + +def _get_audio_files(audio_source: str): + audio_source = Path(audio_source) + audio_files = [] + if audio_source.is_dir(): + audio_files = list(audio_source.glob("*.*")) + elif audio_source.is_file(): + audio_files.append(audio_source) + else: + raise ValueError( + f"audio_source must be a file or a directory, got {audio_source}" + ) + return audio_files + + +def _parallel_run( + noise_reduce_type: Type[ReduceNoiseBase], + noise_reduce_arguments: dict, + n_workers: int, + audio_files: List[Path], + description: str, + verbose: bool, +) -> List[Tuple[bool, Tuple[str, str]]]: + """ + Run multiple noise reduce workers with multiprocessing to complete the tasks that will be created on the provided + files using the given task creator. + + :param noise_reduce_type: The noise reduce type to use. + :param n_workers: The number of workers to use. + :param audio_files: The audio files to use. + :param description: The description to use for the progress bar. + :param verbose: Verbosity. + + :returns: The collected results. + """ + # Check the number of workers: + if n_workers > len(audio_files): + _LOGGER.warning( + f"The number of workers ({n_workers}) is larger than the number of audio files ({len(audio_files)}). " + f"Setting the number of workers to {len(audio_files)}." + ) + n_workers = len(audio_files) + + # Initialize the multiprocessing queues: + tasks_queue = Queue() + results_queue = Queue() + + # Initialize the multiprocessing processes: + task_completion_processes = [ + Process( + target=_multiprocessing_complete_tasks, + kwargs={ + "noise_reduce_type": noise_reduce_type, + "noise_reduce_arguments": noise_reduce_arguments, + "tasks_queue": tasks_queue, + "results_queue": results_queue, + }, + ) + for _ in range(n_workers) + ] + + # Start the multiprocessing processes: + for p in task_completion_processes: + p.start() + + # Put the tasks in the queue: + for audio_file in audio_files: + # tasks_queue.put(task_creator.create_task(audio_file=audio_file).to_tuple()) + tasks_queue.put(audio_file) + + # Put the stop marks in the queue: + for _ in range(n_workers): + tasks_queue.put(_MULTIPROCESSING_STOP_MARK) + + # Collect the results: + results = [] + stop_marks_counter = 0 + with tqdm( + desc=description, + unit="file", + total=len(audio_files), + disable=not verbose, + ) as progressbar: + while True: + # Get a result from the queue: + result: Tuple[bool, Tuple[str, str]] = results_queue.get() + if result == _MULTIPROCESSING_STOP_MARK: + stop_marks_counter += 1 + if stop_marks_counter == n_workers: + break + else: + # Collect the result: + results.append(result) + progressbar.update(1) + + # Wait for the processes to finish: + for p in task_completion_processes: + p.join() + + return results + + +def _run( + noise_reduce_type: Type[ReduceNoiseBase], + noise_reduce_arguments: dict, + audio_files: List[Path], + description: str, + verbose: bool, +) -> List[Tuple[bool, Tuple[str, str]]]: + """ + Run the noise reduce algorithm on the given audio files and collect the results. + + :param noise_reduce_type: The noise reduce type to use. + :param noise_reduce_arguments: The noisereduce initialization kwargs. + :param audio_files: The audio files to use. + :param description: The description to use for the progress bar. + :param verbose: Verbosity. + + :returns: The collected results. + """ + # Create the reduce noise object: + noise_reducer = noise_reduce_type(**noise_reduce_arguments) + + # Run the noise reduce algorithm on the audio files and collect the results: + results = [] + for audio_file in tqdm( + audio_files, + desc=description, + unit="file", + total=len(audio_files), + disable=not verbose, + ): + results.append(noise_reducer.reduce_noise(audio_file=audio_file)) + + return results + + +def _process_results( + results: List[Tuple[bool, Tuple[str, str]]], verbose: bool +) -> Tuple[dict, dict]: + """ + Process the results of the tasks. + + :param results: The results to process. + :param verbose: Verbosity. + + :returns: The processed results as a tuple of successes and errors. + """ + if verbose: + _LOGGER.info("Summarizing the results.") + successes = {} + errors = {} + for is_error, result in results: + if is_error: + errors[result[0]] = result[1] + else: + successes[result[0]] = result[1] + if verbose: + _LOGGER.info(f"Done ({len(successes)}/{len(successes) + len(errors)})\n") + + return successes, errors diff --git a/noise_reduction/requirements.txt b/noise_reduction/requirements.txt new file mode 100644 index 000000000..30934ad7c --- /dev/null +++ b/noise_reduction/requirements.txt @@ -0,0 +1,5 @@ +tqdm +deepfilternet +librosa +noisereduce +torchaudio>=2.1.2 \ No newline at end of file diff --git a/noise_reduction/test_noise_reduction.py b/noise_reduction/test_noise_reduction.py new file mode 100644 index 000000000..a77377565 --- /dev/null +++ b/noise_reduction/test_noise_reduction.py @@ -0,0 +1,75 @@ +import tempfile + +import mlrun +import pytest + + +@pytest.mark.parametrize( + "audio_source", + [ + "data/test_data.wav", + "data/test_data.mp3", + "data", + ], +) +def test_reduce_noise(audio_source): + # set up the project and function + artifact_path = tempfile.TemporaryDirectory().name + project = mlrun.new_project("noise-reduction") + noise_reduction_function = project.set_function( + func="function.yaml", + name="reduce_noise", + kind="job", + image="mlrun/mlrun", + ) + + # run the function + noise_reduction_run = noise_reduction_function.run( + handler="reduce_noise", + inputs={"audio_source": audio_source}, + params={ + "target_directory": artifact_path + "/data", + "sample_rate": None, + }, + local=True, + artifact_path=artifact_path, + returns=["successes: file", "errors: file"], + ) + + assert noise_reduction_run.outputs["successes"] + + +@pytest.mark.parametrize( + "audio_source", + [ + "data/test_data.wav", + "data/test_data.mp3", + "data", + ], +) +def test_reduce_noise_dfn(audio_source): + # set up the project and function + artifact_path = tempfile.TemporaryDirectory().name + project = mlrun.new_project("noise-reduction") + noise_reduction_function = project.set_function( + func="function.yaml", + name="reduce_noise", + kind="job", + image="mlrun/mlrun", + ) + + # run the function + noise_reduction_run = noise_reduction_function.run( + handler="reduce_noise_dfn", + inputs={"audio_source": audio_source}, + params={ + "target_directory": artifact_path + "/data", + "atten_lim_db": 50, + }, + local=True, + artifact_path=artifact_path, + returns=["successes: file", "errors: file"], + ) + + # assert that the function run completed successfully + assert noise_reduction_run.outputs["successes"] diff --git a/pandas_profiling_report/README.md b/pandas_profiling_report/README.md deleted file mode 100644 index 40e0c9b22..000000000 --- a/pandas_profiling_report/README.md +++ /dev/null @@ -1,26 +0,0 @@ -## pandas_profiling_report - -Creates an html report with various graphs/statistics/correlations for a given dataset. See sample report [here](https://pandas-profiling.github.io/pandas-profiling/examples/master/titanic/titanic_report.html). Link to GitHub page [here](https://github.com/pandas-profiling/pandas-profiling). - - -Usage example: - -```python -import mlrun, os -mlrun.mlconf.dbpath = 'http://mlrun-api:8080' - -# Load pandas_profiling_report function from Github -func = mlrun.import_function("hub://pandas_profiling_report").apply(mlrun.mount_v3io()) - -# Build MLRun image (only needs to be run once) -func.deploy() - -# Create task -data = 'https://iguazio-sample-data.s3.amazonaws.com/datasets/iris_dataset.csv' - -task = NewTask(name="pandas-profiling-report", - inputs={"data": DATA_URL}) - -# Run task on cluster -run = func.run(task, artifact_path='/User/artifacts') -``` diff --git a/pandas_profiling_report/function.yaml b/pandas_profiling_report/function.yaml deleted file mode 100644 index ffdbbf837..000000000 --- a/pandas_profiling_report/function.yaml +++ /dev/null @@ -1,40 +0,0 @@ -kind: job -metadata: - name: pandas-profiling-report - tag: '' - hash: 79fe77fb2920a8ffecfef2f614a0be494c2ea43b - project: '' - labels: - author: nicks - categories: - - data-analysis -spec: - command: '' - args: [] - image: mlrun/mlrun - env: [] - default_handler: pandas_profiling_report - entry_points: - pandas_profiling_report: - name: pandas_profiling_report - doc: Create a Pandas Profiling Report for a dataset. - parameters: - - name: context - type: MLClientCtx - doc: the function context - default: '' - - name: data - type: DataItem - doc: Dataset to create report for - default: '' - outputs: - - default: '' - lineno: 10 - description: Create Pandas Profiling Report from Dataset - build: - functionSourceCode: IyBHZW5lcmF0ZWQgYnkgbnVjbGlvLmV4cG9ydC5OdWNsaW9FeHBvcnRlcgoKaW1wb3J0IHBhbmRhcyBhcyBwZAppbXBvcnQgcGFuZGFzX3Byb2ZpbGluZwoKZnJvbSBtbHJ1bi5leGVjdXRpb24gaW1wb3J0IE1MQ2xpZW50Q3R4CmZyb20gbWxydW4uZGF0YXN0b3JlIGltcG9ydCBEYXRhSXRlbQoKCmRlZiBwYW5kYXNfcHJvZmlsaW5nX3JlcG9ydCgKICAgIGNvbnRleHQ6IE1MQ2xpZW50Q3R4LAogICAgZGF0YTogRGF0YUl0ZW0sCikgLT4gTm9uZToKICAgICIiIkNyZWF0ZSBhIFBhbmRhcyBQcm9maWxpbmcgUmVwb3J0IGZvciBhIGRhdGFzZXQuCiAgICA6cGFyYW0gY29udGV4dDogICAgICAgICB0aGUgZnVuY3Rpb24gY29udGV4dAogICAgOnBhcmFtIGRhdGE6ICAgICAgICAgICAgRGF0YXNldCB0byBjcmVhdGUgcmVwb3J0IGZvcgogICAgIiIiCgogICAgZGYgPSBkYXRhLmFzX2RmKCkKCiAgICBwcm9maWxlID0gZGYucHJvZmlsZV9yZXBvcnQodGl0bGU9IlBhbmRhcyBQcm9maWxpbmcgUmVwb3J0IikKCiAgICBjb250ZXh0LmxvZ19hcnRpZmFjdCgKICAgICAgICAiUGFuZGFzIFByb2ZpbGluZyBSZXBvcnQiLAogICAgICAgIGJvZHk9cHJvZmlsZS50b19odG1sKCksCiAgICAgICAgbG9jYWxfcGF0aD0icGFuZGFzX3Byb2ZpbGluZ19yZXBvcnQuaHRtbCIsCiAgICApCg== - commands: - - python -m pip install pandas_profiling - code_origin: https://github.com/daniels290813/functions.git#55a79c32be5d233cc11efcf40cd3edbe309bfdef:/home/kali/functions/pandas_profiling_report/pandas_profiling_report.py - affinity: null -verbose: false diff --git a/pandas_profiling_report/item.yaml b/pandas_profiling_report/item.yaml deleted file mode 100644 index 13d374369..000000000 --- a/pandas_profiling_report/item.yaml +++ /dev/null @@ -1,25 +0,0 @@ -apiVersion: v1 -categories: -- data-analysis -description: Create Pandas Profiling Report from Dataset -doc: '' -example: pandas_profiling_report.ipynb -generationDate: 2022-08-28:17-25 -hidden: false -icon: '' -labels: - author: nicks -maintainers: [] -marketplaceType: '' -mlrunVersion: 1.1.0 -name: pandas-profiling-report -platformVersion: 3.5.0 -spec: - filename: pandas_profiling_report.py - handler: pandas_profiling_report - image: mlrun/mlrun - kind: job - requirements: - - pandas_profiling -url: '' -version: 1.1.0 diff --git a/pandas_profiling_report/pandas_profiling_report.ipynb b/pandas_profiling_report/pandas_profiling_report.ipynb deleted file mode 100644 index 61aeba265..000000000 --- a/pandas_profiling_report/pandas_profiling_report.ipynb +++ /dev/null @@ -1,794 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Pandas Profiling Report" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "# nuclio: ignore\n", - "import nuclio" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "%nuclio: setting kind to 'job'\n", - "%nuclio: setting spec.image to 'mlrun/mlrun'\n" - ] - } - ], - "source": [ - "%nuclio config kind = \"job\"\n", - "%nuclio config spec.image = \"mlrun/mlrun\"" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "%%nuclio cmd -c\n", - "pip install pandas_profiling" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "import pandas as pd\n", - "import pandas_profiling\n", - "\n", - "from mlrun.execution import MLClientCtx\n", - "from mlrun.datastore import DataItem" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "def pandas_profiling_report(\n", - " context: MLClientCtx,\n", - " data: DataItem,\n", - ") -> None:\n", - " \"\"\"Create a Pandas Profiling Report for a dataset.\n", - " :param context: the function context\n", - " :param data: Dataset to create report for\n", - " \"\"\"\n", - " \n", - " # Load dataset\n", - " df = data.as_df()\n", - " \n", - " # Create Pandas Profiling Report\n", - " profile = df.profile_report(title='Pandas Profiling Report')\n", - " \n", - " # Save to MLRun DB\n", - " context.log_artifact('Pandas Profiling Report',\n", - " body=profile.to_html(),\n", - " local_path='pandas_profiling_report.html')" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "# nuclio: end-code" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### mlconfig" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "from mlrun import mlconf\n", - "import os\n", - "\n", - "mlconf.dbpath = 'http://mlrun-api:8080'\n", - "mlconf.artifact_path = mlconf.artifact_path or f'{os.environ[\"HOME\"]}/artifacts'" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### save" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "> 2020-10-15 19:21:40,986 [info] function spec saved to path: function.yaml\n" - ] - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from mlrun import code_to_function\n", - "\n", - "# create job function object from notebook code\n", - "fn = code_to_function(\"pandas_profiling_report\", kind=\"job\")\n", - "\n", - "# add metadata (for templates and reuse)\n", - "fn.spec.default_handler = \"pandas_profiling_report\"\n", - "fn.spec.description = \"Create Pandas Profiling Report from Dataset\"\n", - "fn.metadata.categories = [\"analysis\"]\n", - "fn.metadata.labels = {\"author\": \"nicks\"}\n", - "fn.export(\"function.yaml\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## tests" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from mlrun.platforms import auto_mount\n", - "fn.apply(auto_mount())" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [], - "source": [ - "from mlrun import NewTask, run_local\n", - "\n", - "DATA_URL = 'https://iguazio-sample-data.s3.amazonaws.com/datasets/iris_dataset.csv'" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [], - "source": [ - "task = NewTask(name=\"pandas-profiling-report\", \n", - " handler=pandas_profiling_report, \n", - " inputs={\"data\": DATA_URL})" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### run locally" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "> 2020-10-15 19:21:41,030 [warning] warning!, server (0.5.1) and client (0.5.2) ver dont match\n", - "> 2020-10-15 19:21:41,031 [info] starting run pandas-profiling-report uid=0894aed4f2854d96b776e25bdcaff80e -> http://mlrun-api:8080\n", - "> 2020-10-15 19:21:41,062 [warning] warning!, server (0.5.1) and client (0.5.2) ver dont match\n" - ] - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "86c3397cc7384565815af90bc5a6d10b", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "HBox(children=(FloatProgress(value=0.0, description='Summarize dataset', max=19.0, style=ProgressStyle(descrip…" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "e7dece2ab7184c909611cf0aed3ef474", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "HBox(children=(FloatProgress(value=0.0, description='Generate report structure', max=1.0, style=ProgressStyle(…" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n" - ] - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "7153ac93afcd4e77a4b5a312766af995", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "HBox(children=(FloatProgress(value=0.0, description='Render HTML', max=1.0, style=ProgressStyle(description_wi…" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "\n" - ] - }, - { - "data": { - "text/html": [ - "\n", - "
\n", - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
projectuiditerstartstatenamelabelsinputsparametersresultsartifacts
default0Oct 15 19:21:41completedpandas-profiling-report
v3io_user=nicks
kind=handler
owner=nicks
host=nicks-jupyter-76668bdd46-g9sxf
data
Pandas Profiling Report
\n", - "
\n", - "
\n", - "
\n", - " Title\n", - " ×\n", - "
\n", - " \n", - "
\n", - "
\n" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "to track results use .show() or .logs() or in CLI: \n", - "!mlrun get run 0894aed4f2854d96b776e25bdcaff80e --project default , !mlrun logs 0894aed4f2854d96b776e25bdcaff80e --project default\n", - "> 2020-10-15 19:21:52,944 [info] run executed, status=completed\n" - ] - } - ], - "source": [ - "run = run_local(task)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### run remotely" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [], - "source": [ - "# Create MLRun image (only needs to be run once)\n", - "fn.deploy()" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "> 2020-10-15 19:23:17,199 [info] starting run pandas-profiling-report uid=0ab5c8dbff95471da6018c1a7afd3b22 -> http://mlrun-api:8080\n", - "> 2020-10-15 19:23:17,303 [info] Job is running in the background, pod: pandas-profiling-report-xr48m\n", - "Summarize dataset: 100%|██████████| 19/19 [00:05<00:00, 3.78it/s, Completed] \n", - "Generate report structure: 100%|██████████| 1/1 [00:02<00:00, 2.22s/it]\n", - "> 2020-10-15 19:23:33,779 [info] run executed, status=completed\n", - "Render HTML: 100%|██████████| 1/1 [00:00<00:00, 2.07it/s]\n", - "final state: succeeded\n" - ] - }, - { - "data": { - "text/html": [ - "\n", - "
\n", - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
projectuiditerstartstatenamelabelsinputsparametersresultsartifacts
default0Oct 15 19:23:25completedpandas-profiling-report
v3io_user=nicks
kind=job
owner=nicks
host=pandas-profiling-report-xr48m
data
Pandas Profiling Report
\n", - "
\n", - "
\n", - "
\n", - " Title\n", - " ×\n", - "
\n", - " \n", - "
\n", - "
\n" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "to track results use .show() or .logs() or in CLI: \n", - "!mlrun get run 0ab5c8dbff95471da6018c1a7afd3b22 --project default , !mlrun logs 0ab5c8dbff95471da6018c1a7afd3b22 --project default\n", - "> 2020-10-15 19:23:36,481 [info] run executed, status=completed\n" - ] - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "fn.run(task, inputs={\"data\": DATA_URL})" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "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.7.6" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/pandas_profiling_report/pandas_profiling_report.py b/pandas_profiling_report/pandas_profiling_report.py deleted file mode 100644 index c3d3d4d32..000000000 --- a/pandas_profiling_report/pandas_profiling_report.py +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright 2019 Iguazio -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# Generated by nuclio.export.NuclioExporter - -import pandas as pd -import pandas_profiling - -from mlrun.execution import MLClientCtx -from mlrun.datastore import DataItem - - -def pandas_profiling_report( - context: MLClientCtx, - data: DataItem, -) -> None: - """Create a Pandas Profiling Report for a dataset. - :param context: the function context - :param data: Dataset to create report for - """ - - df = data.as_df() - - profile = df.profile_report(title="Pandas Profiling Report") - - context.log_artifact( - "Pandas Profiling Report", - body=profile.to_html(), - local_path="pandas_profiling_report.html", - ) diff --git a/project_runner/function.yaml b/project_runner/function.yaml deleted file mode 100644 index 21a2f7346..000000000 --- a/project_runner/function.yaml +++ /dev/null @@ -1,53 +0,0 @@ -kind: remote -metadata: - name: project-runner - tag: '' - hash: b7888996aa9a7833972928fa06fa238f674099b3 - project: '' - labels: - author: orz - categories: - - utils -spec: - command: '' - args: [] - image: '' - entry_points: - init_context: - name: init_context - doc: '' - parameters: - - name: context - outputs: [] - lineno: 8 - handler: - name: handler - doc: "Imports the latest project version and runs the \nspecified workflow" - parameters: - - name: context - - name: event - outputs: [] - lineno: 11 - description: Nuclio based - Cron scheduler for running your MLRun projects - min_replicas: 1 - max_replicas: 1 - env: [] - base_spec: - apiVersion: nuclio.io/v1 - kind: Function - metadata: - annotations: - nuclio.io/generated_by: function generated from 02-07-2020 by admin - labels: {} - name: project-runner - spec: - build: - baseImage: mlrun/mlrun - commands: [] - functionSourceCode: IyBHZW5lcmF0ZWQgYnkgbnVjbGlvLmV4cG9ydC5OdWNsaW9FeHBvcnRlcgoKZnJvbSBtbHJ1biBpbXBvcnQgbG9hZF9wcm9qZWN0CmZyb20gbWxydW4gaW1wb3J0IG1sY29uZgppbXBvcnQganNvbgppbXBvcnQgb3MKCmRlZiBpbml0X2NvbnRleHQoY29udGV4dCk6CiAgICBzZXRhdHRyKGNvbnRleHQsICdodWJfdXJsJywgb3MuZ2V0ZW52KCdodWJfdXJsJywgTm9uZSkpCgpkZWYgaGFuZGxlcihjb250ZXh0LCBldmVudCk6CiAgICAiIiJJbXBvcnRzIHRoZSBsYXRlc3QgcHJvamVjdCB2ZXJzaW9uIGFuZCBydW5zIHRoZSAKICAgIHNwZWNpZmllZCB3b3JrZmxvdwogICAgIiIiCiAgICBjb250ZXh0LmxvZ2dlci5pbmZvKCdQdWxsaW5nIHByb2plY3QgYW5kIHdvcmtmbG93IGRldGFpbHMnKQogICAgaWYgaXNpbnN0YW5jZShldmVudC5ib2R5LCBkaWN0KToKICAgICAgICBkZXRhaWxzID0gZXZlbnQuYm9keQogICAgZWxzZToKICAgICAgICBkZXRhaWxzID0ganNvbi5sb2FkcyhldmVudC5ib2R5KQogICAgY29udGV4dC5sb2dnZXIuaW5mbyhkZXRhaWxzKQogICAgcHJvamVjdF91cmwgPSBkZXRhaWxzWydwcm9qZWN0X3VybCddCiAgICB3b3JrZmxvdyA9IGRldGFpbHNbJ3dvcmtmbG93J10KICAgIGFydGlmYWN0X3BhdGggPSBkZXRhaWxzLmdldCgnYXJ0aWZhY3RfcGF0aCcsIG9zLmVudmlyb24uZ2V0KCdhcnRpZmFjdF9wYXRoJywgTm9uZSkpCiAgICBodWJfdXJsID0gZGV0YWlscy5nZXQoJ2h1Yl91cmwnLCBjb250ZXh0Lmh1Yl91cmwpCgogICAgaWYgaHViX3VybDoKICAgICAgICBtbGNvbmYuaHViX3VybCA9IGh1Yl91cmwKCiAgICBwcm9qZWN0PSBsb2FkX3Byb2plY3Qob3MucGF0aC5hYnNwYXRoKCcuL2xvYWRlZF9wcm9qZWN0JyksIHVybD1wcm9qZWN0X3VybCkKICAgIHByb2plY3QucnVuKG5hbWU9d29ya2Zsb3csCiAgICAgICAgICAgICAgICBhcmd1bWVudHM9e30sCiAgICAgICAgICAgICAgICBhcnRpZmFjdF9wYXRoPWFydGlmYWN0X3BhdGgsCiAgICAgICAgICAgICAgICB3YXRjaD1GYWxzZSkKCg== - noBaseImagesPull: true - env: [] - handler: project_runner:handler - runtime: python:3.9 - volumes: [] - source: '' diff --git a/project_runner/project_runner.ipynb b/project_runner/project_runner.ipynb deleted file mode 100644 index 04bebea12..000000000 --- a/project_runner/project_runner.ipynb +++ /dev/null @@ -1,340 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Project runner\n", - "Imports the latest project version and runs the specified workflow" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [], - "source": [ - "import nuclio" - ] - }, - { - "cell_type": "code", - "execution_count": 61, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "%nuclio: setting spec.build.baseImage to 'mlrun/mlrun'\n" - ] - } - ], - "source": [ - "%nuclio config spec.build.baseImage = \"mlrun/mlrun\"" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "# nuclio: start-code" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [], - "source": [ - "from mlrun import load_project\n", - "from mlrun import mlconf\n", - "import json\n", - "import os" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [], - "source": [ - "def init_context(context):\n", - " setattr(context, 'hub_url', os.getenv('hub_url', None))" - ] - }, - { - "cell_type": "code", - "execution_count": 37, - "metadata": {}, - "outputs": [], - "source": [ - "def handler(context, event):\n", - " \"\"\"Imports the latest project version and runs the \n", - " specified workflow\n", - " \"\"\"\n", - " context.logger.info('Pulling project and workflow details')\n", - " if isinstance(event.body, dict):\n", - " details = event.body\n", - " else:\n", - " details = json.loads(event.body)\n", - " context.logger.info(details)\n", - " project_url = details['project_url']\n", - " workflow = details['workflow']\n", - " artifact_path = details.get('artifact_path', os.environ.get('artifact_path', None))\n", - " hub_url = details.get('hub_url', context.hub_url)\n", - "\n", - " if hub_url:\n", - " mlconf.hub_url = hub_url\n", - "\n", - " project= load_project(os.path.abspath('./loaded_project'), url=project_url)\n", - " project.run(name=workflow,\n", - " arguments={},\n", - " artifact_path=artifact_path,\n", - " watch=False)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "metadata": {}, - "outputs": [], - "source": [ - "# nuclio: end-code" - ] - }, - { - "cell_type": "code", - "execution_count": 63, - "metadata": {}, - "outputs": [], - "source": [ - "import json\n", - "runner_event = {'project_url': '/User/demo-network-operations/project.yaml',\n", - " 'workflow': 'main',\n", - " 'hub_url': '/User/functions/{name}/function.yaml',\n", - " 'artifact_path': '/User/functions/project_runner/artifacts/'}" - ] - }, - { - "cell_type": "code", - "execution_count": 46, - "metadata": { - "tags": [] - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Python> 2020-07-01 14:36:45,368 [info] \n", - "Python> 2020-07-01 14:36:45,369 [info] {'project_url': '/User/demo-network-operations/project.yaml', 'workflow': 'main', 'hub_url': '/User/functions/{name}/function.yaml', 'artifact_path': '/User/functions/project_runner/artifacts/'}\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/conda/lib/python3.6/site-packages/kfp/components/_data_passing.py:168: UserWarning: Missing type name was inferred as \"JsonArray\" based on the value \"['cpu_utilization', 'throughput', 'packet_loss', 'latency']\".\n", - " warnings.warn('Missing type name was inferred as \"{}\" based on the value \"{}\".'.format(type_name, str(value)))\n", - "/conda/lib/python3.6/site-packages/kfp/components/_data_passing.py:168: UserWarning: Missing type name was inferred as \"JsonArray\" based on the value \"['mean', 'sum', 'std', 'var', 'min', 'max', 'median']\".\n", - " warnings.warn('Missing type name was inferred as \"{}\" based on the value \"{}\".'.format(type_name, str(value)))\n", - "/conda/lib/python3.6/site-packages/kfp/components/_data_passing.py:168: UserWarning: Missing type name was inferred as \"Integer\" based on the value \"20\".\n", - " warnings.warn('Missing type name was inferred as \"{}\" based on the value \"{}\".'.format(type_name, str(value)))\n", - "/conda/lib/python3.6/site-packages/kfp/components/_data_passing.py:168: UserWarning: Missing type name was inferred as \"Float\" based on the value \"0.3\".\n", - " warnings.warn('Missing type name was inferred as \"{}\" based on the value \"{}\".'.format(type_name, str(value)))\n", - "/conda/lib/python3.6/site-packages/kfp/components/_data_passing.py:168: UserWarning: Missing type name was inferred as \"JsonArray\" based on the value \"[1, 0]\".\n", - " warnings.warn('Missing type name was inferred as \"{}\" based on the value \"{}\".'.format(type_name, str(value)))\n", - "/conda/lib/python3.6/site-packages/kfp/components/_data_passing.py:168: UserWarning: Missing type name was inferred as \"Integer\" based on the value \"-1\".\n", - " warnings.warn('Missing type name was inferred as \"{}\" based on the value \"{}\".'.format(type_name, str(value)))\n", - "/conda/lib/python3.6/site-packages/kfp/components/_data_passing.py:168: UserWarning: Missing type name was inferred as \"Float\" based on the value \"0.1\".\n", - " warnings.warn('Missing type name was inferred as \"{}\" based on the value \"{}\".'.format(type_name, str(value)))\n", - "/conda/lib/python3.6/site-packages/kfp/components/_data_passing.py:168: UserWarning: Missing type name was inferred as \"Float\" based on the value \"0.75\".\n", - " warnings.warn('Missing type name was inferred as \"{}\" based on the value \"{}\".'.format(type_name, str(value)))\n" - ] - }, - { - "data": { - "text/html": [ - "Experiment link here" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "Run link here" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[mlrun] 2020-07-01 14:36:46,646 Pipeline run id=cf85ec1b-2df7-403c-b7b4-b9bdb8fcf92f, check UI or DB for progress\n" - ] - } - ], - "source": [ - "init_context(context)\n", - "event = nuclio.Event(body=json.dumps(runner_event))\n", - "out = handler(context, event)\n", - "out" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Deployment" - ] - }, - { - "cell_type": "code", - "execution_count": 48, - "metadata": {}, - "outputs": [], - "source": [ - "from mlrun import code_to_function, mount_v3io\n", - "from nuclio.triggers import CronTrigger" - ] - }, - { - "cell_type": "code", - "execution_count": 89, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[mlrun] 2020-07-02 09:30:36,014 function spec saved to path: function.yaml\n" - ] - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 89, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Saving the function for import via hub://project_runner\n", - "fn = code_to_function(name='project-runner',\n", - " kind='nuclio')\n", - "fn.spec.description = 'Nuclio based - Cron scheduler for running your MLRun projects'\n", - "fn.metadata.categories = [\"utils\"]\n", - "fn.metadata.labels = {'author': 'orz'}\n", - "fn.spec.maxReplicas = 1\n", - "fn.export('function.yaml')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### How to call from your project?\n", - "> **After** importing the function" - ] - }, - { - "cell_type": "code", - "execution_count": 90, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 90, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "cron_string = '* * 1 * *' # Regular cron string as in https://pypi.org/project/croniter/\n", - "\n", - "# Set defaults\n", - "fn.set_envs({'artifact_path': '/User/functions/project_runner/artifacts/',\n", - " 'hub_url': '/User/functions/{name}/function.yaml'})\n", - "\n", - "# Set project and workflow event\n", - "runner_event = {'project_url': '/User/demo-network-operations/project.yaml',\n", - " 'workflow': 'main'}\n", - "\n", - "# Add as a trigger\n", - "fn.add_trigger('cron', \n", - " CronTrigger(schedule=cron_string,\n", - " body=json.dumps(runner_event),\n", - " headers={'X-Nuclio-Target': 'project-runner'}))\n", - "\n", - "# Add mount for access to the different directories\n", - "fn.apply(mount_v3io())" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[mlrun] 2020-07-02 09:31:16,905 deploy started\n", - "[nuclio] 2020-07-02 09:31:19,021 (info) Build complete\n" - ] - } - ], - "source": [ - "fn.deploy()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python [conda env:root] *", - "language": "python", - "name": "conda-root-py" - }, - "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.6.8" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/rnn_serving/function.yaml b/rnn_serving/function.yaml deleted file mode 100644 index 0078e4028..000000000 --- a/rnn_serving/function.yaml +++ /dev/null @@ -1,46 +0,0 @@ -kind: serving -metadata: - name: rnn-serving - tag: '' - hash: 548cd27edfdc49aed0b069d94bd049435d484722 - project: '' - labels: - author: Daniel - categories: - - model-serving - - machine-learning -spec: - command: '' - args: [] - image: mlrun/ml-models - description: deploy an rnn based stock analysis model server. - min_replicas: 1 - max_replicas: 4 - env: [] - base_spec: - apiVersion: nuclio.io/v1 - kind: Function - metadata: - name: rnn-serving - labels: {} - annotations: - nuclio.io/generated_by: function generated from /User/test/functions/rnn_serving/rnn_serving.py - spec: - runtime: python:3.9 - handler: rnn_serving:handler - env: [] - volumes: [] - build: - commands: [] - noBaseImagesPull: true - functionSourceCode: aW1wb3J0IG1scnVuCmltcG9ydCBudW1weSBhcyBucApmcm9tIHRlbnNvcmZsb3cgaW1wb3J0IGtlcmFzCmltcG9ydCBqc29uCgoKY2xhc3MgUk5OX01vZGVsX1NlcnZpbmcobWxydW4uc2VydmluZy5WMk1vZGVsU2VydmVyKToKICAgIGRlZiBsb2FkKHNlbGYpOgogICAgICAgICIiImxvYWQgYW5kIGluaXRpYWxpemUgdGhlIG1vZGVsIGFuZC9vciBvdGhlciBlbGVtZW50cyIiIgogICAgICAgIG1vZGVsX2ZpbGUsIGV4dHJhX2RhdGEgPSBzZWxmLmdldF9tb2RlbChzdWZmaXg9Ii5oNSIpCiAgICAgICAgc2VsZi5tb2RlbCA9IGtlcmFzLm1vZGVscy5sb2FkX21vZGVsKG1vZGVsX2ZpbGUpCgogICAgZGVmIHByZWRpY3Qoc2VsZiwgYm9keSk6CiAgICAgICAgdHJ5OgogICAgICAgICAgICAiIiJHZW5lcmF0ZSBtb2RlbCBwcmVkaWN0aW9ucyBmcm9tIHNhbXBsZS4iIiIKICAgICAgICAgICAgZmVhdHMgPSBucC5hc2FycmF5KGJvZHlbJ2lucHV0cyddKQogICAgICAgICAgICByZXN1bHQgPSBzZWxmLm1vZGVsLnByZWRpY3QoZmVhdHMpCiAgICAgICAgICAgIHJlc3VsdCA9IGpzb24uZHVtcHMocmVzdWx0LnRvbGlzdCgpKQogICAgICAgICAgICByZXR1cm4gcmVzdWx0CiAgICAgICAgZXhjZXB0IEV4Y2VwdGlvbiBhcyBlOgogICAgICAgICAgICByYWlzZSBFeGNlcHRpb24oIkZhaWxlZCB0byBwcmVkaWN0ICVzIiAlIGUpCmZyb20gbWxydW4ucnVudGltZXMgaW1wb3J0IG51Y2xpb19pbml0X2hvb2sKZGVmIGluaXRfY29udGV4dChjb250ZXh0KToKICAgIG51Y2xpb19pbml0X2hvb2soY29udGV4dCwgZ2xvYmFscygpLCAnc2VydmluZ192MicpCgpkZWYgaGFuZGxlcihjb250ZXh0LCBldmVudCk6CiAgICByZXR1cm4gY29udGV4dC5tbHJ1bl9oYW5kbGVyKGNvbnRleHQsIGV2ZW50KQo= - source: '' - function_kind: serving_v2 - build: - commands: [] - code_origin: https://github.com/daniels290813/functions.git#97b63199864dd95681bca5af86835d177bf9d67b:/User/test/functions/rnn_serving/rnn_serving.py - origin_filename: /User/test/functions/rnn_serving/rnn_serving.py - secret_sources: [] - mount_applied: false - affinity: null -verbose: false diff --git a/rnn_serving/item.yaml b/rnn_serving/item.yaml deleted file mode 100644 index 5cc7b9367..000000000 --- a/rnn_serving/item.yaml +++ /dev/null @@ -1,25 +0,0 @@ -apiVersion: v1 -categories: -- model-serving -- machine-learning -description: deploy an rnn based stock analysis model server. -doc: '' -example: rnn_serving.ipynb -generationDate: 2022-08-28:17-25 -hidden: false -icon: '' -labels: - author: Daniel -maintainers: [] -marketplaceType: '' -mlrunVersion: 1.1.0 -name: rnn-serving -platformVersion: 3.5.0 -spec: - filename: rnn_serving.py - handler: handler - image: mlrun/ml-models - kind: serving - requirements: null -url: '' -version: 1.1.0 diff --git a/rnn_serving/requirements.txt b/rnn_serving/requirements.txt deleted file mode 100644 index ff480e35d..000000000 --- a/rnn_serving/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -tensorflow==2.8.2 -wget \ No newline at end of file diff --git a/rnn_serving/rnn_serving.ipynb b/rnn_serving/rnn_serving.ipynb deleted file mode 100644 index dbdf3b874..000000000 --- a/rnn_serving/rnn_serving.ipynb +++ /dev/null @@ -1,285 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# **RNN Serving**" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The following section we create a new model serving function which wraps our class , and specify model and other resources.
\n", - "Deploying the serving function will provide us an http endpoint that can handle requests in real time.
\n", - "This function is part of the [stock-analysis demo](https://github.com/mlrun/demos/tree/master/stock-analysis).
\n", - "To see how the model is trained or how the data-set is generated, check out code folder in the demo repository." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### **Steps**\n", - "\n", - "1. [Setup function parameters](#Setup-function-parameters)\n", - "2. [Importing the function](#Importing-the-function)\n", - "3. [Testing the function locally](#Testing-the-function-locally)\n", - "4. [Testing the function remotely](#Testing-the-function-remotely)" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import warnings\n", - "warnings.filterwarnings(\"ignore\")" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "# Following packages are required, make sure to install\n", - "# !pip install pip install torch==1.6.0\n", - "# !pip install tensorflow\n", - "# !pip install keras" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### **Setup function parameters**" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "# Setting up models path\n", - "rnn_model_path = 'https://s3.wasabisys.com/iguazio/models/function-marketplace-models/rnn_serving/rnn_model.h5'\n", - "data_path = 'https://s3.wasabisys.com/iguazio/data/function-marketplace-data/rnn_serving/stocks_data.pkl'" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### **Importing the function**" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "> 2021-10-17 10:43:46,363 [info] loaded project function-marketplace from MLRun DB\n" - ] - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import mlrun\n", - "mlrun.set_environment(project='function-marketplace')\n", - "\n", - "# Importing the function from the hub\n", - "fn = mlrun.import_function(\"hub://rnn_serving\")\n", - "fn.apply(mlrun.auto_mount())\n", - "\n", - "# Manually specifying needed packages \n", - "fn.spec.build.commands = ['pip install torch==1.6.0', 'pip install tensorflow', 'pip install keras']\n", - "\n", - "# Adding the model \n", - "fn.add_model(key='rnn_model', model_path=rnn_model_path ,class_name='RNN_Model_Serving')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### **Testing the function locally**" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "> 2021-10-17 10:43:54,256 [info] model rnn_model was loaded\n", - "> 2021-10-17 10:43:54,257 [info] Initializing endpoint records\n", - "> 2021-10-17 10:43:54,276 [info] Loaded ['rnn_model']\n" - ] - } - ], - "source": [ - "# When mocking, class has to be present\n", - "from rnn_serving import *\n", - "\n", - "# Mocking function\n", - "server = fn.to_mock_server()" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "# Getting the data\n", - "import cloudpickle as cp\n", - "from urllib.request import urlopen\n", - "\n", - "rnn_data = cp.load(urlopen(data_path))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "model used in this example take inputs with the shape `(None, None, 11)`.
\n", - "whereas the first dimenstion is the number of instances, the second dimenstion is the number of timestamps
\n", - "and the last dimenstion is the number of features the dataset have.
\n", - "our testing dataset has `(1,10,11)` means one instance to predict, with sequence length of 10, each step has 11 features." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'id': '1bf6a3dc4d204e6e8bfd5834f5d691f1',\n", - " 'model_name': 'rnn_model',\n", - " 'outputs': '[[0.43563252687454224]]'}" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import requests\n", - "\n", - "# KFServing protocol event\n", - "event_data = {\"inputs\": rnn_data}\n", - "\n", - "response = server.test(path='/v2/models/rnn_model/predict',body=event_data)\n", - "response" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### **Testing the function remotely**" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "> 2021-10-17 10:43:57,192 [info] Starting remote function deploy\n", - "2021-10-17 10:43:57 (info) Deploying function\n", - "2021-10-17 10:43:57 (info) Building\n", - "2021-10-17 10:43:57 (info) Staging files and preparing base images\n", - "2021-10-17 10:43:57 (info) Building processor image\n", - "2021-10-17 10:43:58 (info) Build complete\n", - "2021-10-17 10:44:10 (info) Function deploy complete\n", - "> 2021-10-17 10:44:11,677 [info] successfully deployed function: {'internal_invocation_urls': ['nuclio-function-marketplace-rnn-serving.default-tenant.svc.cluster.local:8080'], 'external_invocation_urls': ['default-tenant.app.dev39.lab.iguazeng.com:30255']}\n" - ] - } - ], - "source": [ - "address = fn.deploy()" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'id': '1bf6a3dc4d204e6e8bfd5834f5d691f1',\n", - " 'model_name': 'rnn_model',\n", - " 'outputs': '[[0.43563252687454224]]'}" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import json\n", - "import requests\n", - "\n", - "# using requests to predict\n", - "response = requests.put(address+\"/v2/models/rnn_model/predict\", json = json.dumps(event_data))\n", - "json.loads(response.text)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "[Back to the top](#RNN-Serving)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "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.7.6" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/rnn_serving/rnn_serving.py b/rnn_serving/rnn_serving.py deleted file mode 100644 index d7e783d7a..000000000 --- a/rnn_serving/rnn_serving.py +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2019 Iguazio -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -import mlrun -import numpy as np -from tensorflow import keras -import json - - -class RNN_Model_Serving(mlrun.serving.V2ModelServer): - def load(self): - """load and initialize the model and/or other elements""" - model_file, extra_data = self.get_model(suffix=".h5") - self.model = keras.models.load_model(model_file) - - def predict(self, body): - try: - """Generate model predictions from sample.""" - feats = np.asarray(body['inputs']) - result = self.model.predict(feats) - result = json.dumps(result.tolist()) - return result - except Exception as e: - raise Exception("Failed to predict %s" % e) \ No newline at end of file diff --git a/rnn_serving/test_rnn_serving.py b/rnn_serving/test_rnn_serving.py deleted file mode 100644 index fb2f49974..000000000 --- a/rnn_serving/test_rnn_serving.py +++ /dev/null @@ -1,74 +0,0 @@ -# Copyright 2019 Iguazio -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -import os -import wget -from mlrun import import_function -from os import path -from rnn_serving import * - -DATASET = np.array([[6.9955170e-01, 6.9952875e-01, 2.7922913e-02, 2.7853036e-02, - 6.9955170e-01, 7.0086759e-01, 7.0118028e-01, 7.0142627e-01, - 2.7922913e-02, 0.0000000e+00, 0.0000000e+00], - [6.9955170e-01, 6.9998503e-01, 1.6527303e-03, 2.7853036e-02, - 7.0000792e-01, 7.0085293e-01, 7.0118028e-01, 7.0203447e-01, - 1.6527303e-03, 0.0000000e+00, 0.0000000e+00], - [6.9955170e-01, 7.0025057e-01, 1.6904050e-04, 2.7853036e-02, - 7.0027345e-01, 7.0014298e-01, 7.0190376e-01, 7.0128226e-01, - 1.6904050e-04, 0.0000000e+00, 0.0000000e+00], - [6.9955170e-01, 7.0144778e-01, 1.6904050e-04, 2.7853036e-02, - 7.0147055e-01, 7.0178574e-01, 7.0236105e-01, 7.0295709e-01, - 7.3906886e-03, 0.0000000e+00, 0.0000000e+00], - [6.9955170e-01, 7.0324355e-01, 1.6904050e-04, 2.7853036e-02, - 7.0326620e-01, 7.0308524e-01, 7.0490342e-01, 7.0427048e-01, - 2.4815742e-03, 0.0000000e+00, 0.0000000e+00], - [6.9955170e-01, 7.0324355e-01, 1.6904050e-04, 2.7853036e-02, - 7.0191067e-01, 7.0173001e-01, 7.0354480e-01, 7.0291305e-01, - 2.9976186e-03, 0.0000000e+00, 0.0000000e+00], - [6.9955170e-01, 7.0324355e-01, 1.6904050e-04, 2.7853036e-02, - 7.0166123e-01, 7.0148063e-01, 7.0284635e-01, 7.0249581e-01, - 2.7904075e-03, 0.0000000e+00, 0.0000000e+00], - [6.9955170e-01, 7.0324355e-01, 1.6904050e-04, 2.7853036e-02, - 7.0133996e-01, 7.0143080e-01, 7.0297277e-01, 7.0250750e-01, - 4.1491759e-04, 0.0000000e+00, 0.0000000e+00], - [6.9955170e-01, 7.0324355e-01, 1.6904050e-04, 2.7853036e-02, - 7.0150572e-01, 7.0251614e-01, 7.0281982e-01, 7.0370042e-01, - 2.1256472e-03, 0.0000000e+00, 0.0000000e+00], - [6.9955170e-01, 7.0324355e-01, 1.6904050e-04, 2.7853036e-02, - 7.0272487e-01, 7.0258951e-01, 7.0429617e-01, 7.0376801e-01, - 1.4207334e-03, 0.0000000e+00, 0.0000000e+00]]).reshape(1, 10, 11).tolist() - - -def download_pretrained_model(model_path): - # Run this to download the pre-trained model to your `models` directory - model_location = 'https://s3.wasabisys.com/iguazio/models/rnn/rnn_model.h5' - saved_models_directory = model_path - # Create paths - os.makedirs(saved_models_directory, exist_ok=1) - model_filepath = os.path.join(saved_models_directory, os.path.basename(model_location)) - wget.download(model_location, model_filepath) - - -def test_rnn_serving(): - model_path = os.path.join(os.path.abspath('./'), 'models') - model = model_path + '/rnn_model.h5' - if not path.exists(model): - download_pretrained_model(model_path) - - fn = import_function('function.yaml') - fn.add_model('rnn_model', model_path=model, class_name='RNN_Model_Serving') - # create an emulator (mock server) from the function configuration) - server = fn.to_mock_server() - resp = server.test("/v2/models/rnn_model/infer", {"inputs": DATASET}) - assert (resp['outputs'] == '[[0.453309565782547]]') diff --git a/slack_notify/README.md b/slack_notify/README.md deleted file mode 100644 index 9bde32995..000000000 --- a/slack_notify/README.md +++ /dev/null @@ -1 +0,0 @@ -# Send Notification to Slack \ No newline at end of file diff --git a/slack_notify/function.yaml b/slack_notify/function.yaml deleted file mode 100644 index 95af087c0..000000000 --- a/slack_notify/function.yaml +++ /dev/null @@ -1,48 +0,0 @@ -kind: job -metadata: - name: slack-notify - tag: '' - hash: 3de7e78ed9b7928af192badf988055086431fb58 - project: '' - labels: - author: mdl - categories: - - utils -spec: - command: '' - args: [] - image: python:3.6-jessie - env: [] - default_handler: slack_notify - entry_points: - slack_notify: - name: slack_notify - doc: Summarize a table - parameters: - - name: context - type: MLClientCtx - doc: the function context - default: '' - - name: webhook_url - type: str - doc: 'Slack incoming webhook URL. Please read: https://api.slack.com/messaging/webhooks' - default: URL - - name: slack_blocks - type: List[str] - doc: Message blocks list. NOT IMPLEMENTED YET - default: [] - - name: notification_text - type: str - doc: Notification text - default: Notification - outputs: - - default: '' - lineno: 14 - description: Send Slack notification - build: - functionSourceCode: IyBHZW5lcmF0ZWQgYnkgbnVjbGlvLmV4cG9ydC5OdWNsaW9FeHBvcnRlcgoKaW1wb3J0IHdhcm5pbmdzCgp3YXJuaW5ncy5zaW1wbGVmaWx0ZXIoYWN0aW9uPSJpZ25vcmUiLCBjYXRlZ29yeT1GdXR1cmVXYXJuaW5nKQoKaW1wb3J0IG9zCmltcG9ydCBqc29uCmltcG9ydCByZXF1ZXN0cwpmcm9tIG1scnVuLmV4ZWN1dGlvbiBpbXBvcnQgTUxDbGllbnRDdHgKZnJvbSB0eXBpbmcgaW1wb3J0IExpc3QKCgpkZWYgc2xhY2tfbm90aWZ5KAogICAgY29udGV4dDogTUxDbGllbnRDdHgsCiAgICB3ZWJob29rX3VybDogc3RyID0gIlVSTCIsCiAgICBzbGFja19ibG9ja3M6IExpc3Rbc3RyXSA9IFtdLAogICAgbm90aWZpY2F0aW9uX3RleHQ6IHN0ciA9ICJOb3RpZmljYXRpb24iLAopIC0+IE5vbmU6CiAgICAiIiJTdW1tYXJpemUgYSB0YWJsZQogICAgOnBhcmFtIGNvbnRleHQ6ICAgICAgICAgdGhlIGZ1bmN0aW9uIGNvbnRleHQKICAgIDpwYXJhbSB3ZWJob29rX3VybDogICAgIFNsYWNrIGluY29taW5nIHdlYmhvb2sgVVJMLiBQbGVhc2UgcmVhZDogaHR0cHM6Ly9hcGkuc2xhY2suY29tL21lc3NhZ2luZy93ZWJob29rcwogICAgOnBhcmFtIG5vdGlmaWNhdGlvbl90ZXh0OiAgICAgICAgICAgIE5vdGlmaWNhdGlvbiB0ZXh0CiAgICA6cGFyYW0gc2xhY2tfYmxvY2tzOiAgICAgICAgICBNZXNzYWdlIGJsb2NrcyBsaXN0LiBOT1QgSU1QTEVNRU5URUQgWUVUCiAgICAiIiIKCiAgICBkYXRhID0geyJ0ZXh0Ijogbm90aWZpY2F0aW9uX3RleHR9CiAgICBwcmludCgiPT09PSIsIHdlYmhvb2tfdXJsKQogICAgcmVzcG9uc2UgPSByZXF1ZXN0cy5wb3N0KAogICAgICAgIHdlYmhvb2tfdXJsLCBkYXRhPWpzb24uZHVtcHMoZGF0YSksIGhlYWRlcnM9eyJDb250ZW50LVR5cGUiOiAiYXBwbGljYXRpb24vanNvbiJ9CiAgICApCgogICAgcHJpbnQoIlJlc3BvbnNlOiAiICsgc3RyKHJlc3BvbnNlLnRleHQpKQogICAgcHJpbnQoIlJlc3BvbnNlIGNvZGU6ICIgKyBzdHIocmVzcG9uc2Uuc3RhdHVzX2NvZGUpKQo= - commands: - - python -m pip install requests - code_origin: https://github.com/daniels290813/functions.git#55a79c32be5d233cc11efcf40cd3edbe309bfdef:/home/kali/functions/slack_notify/slack_notify.py - affinity: null -verbose: false diff --git a/slack_notify/item.yaml b/slack_notify/item.yaml deleted file mode 100644 index 6bdfd2c83..000000000 --- a/slack_notify/item.yaml +++ /dev/null @@ -1,25 +0,0 @@ -apiVersion: v1 -categories: -- utils -description: Send Slack notification -doc: '' -example: slack_notify.ipynb -generationDate: 2022-08-28:17-25 -hidden: false -icon: '' -labels: - author: mdl -maintainers: [] -marketplaceType: '' -mlrunVersion: 1.1.0 -name: slack-notify -platformVersion: 3.5.0 -spec: - filename: slack_notify.py - handler: slack_notify - image: python:3.6-jessie - kind: job - requirements: - - requests -url: '' -version: 1.1.0 diff --git a/slack_notify/slack_notify.ipynb b/slack_notify/slack_notify.ipynb deleted file mode 100644 index 8119bb8cf..000000000 --- a/slack_notify/slack_notify.ipynb +++ /dev/null @@ -1,293 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 33, - "metadata": {}, - "outputs": [], - "source": [ - "# nuclio: ignore\n", - "import nuclio" - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "%nuclio: setting kind to 'job'\n", - "%nuclio: setting spec.image to 'python:3.6-jessie'\n" - ] - } - ], - "source": [ - "%nuclio config kind = \"job\"\n", - "%nuclio config spec.image = \"python:3.6-jessie\"" - ] - }, - { - "cell_type": "code", - "execution_count": 35, - "metadata": {}, - "outputs": [], - "source": [ - "%%nuclio cmd -c \n", - "pip install requests" - ] - }, - { - "cell_type": "code", - "execution_count": 36, - "metadata": {}, - "outputs": [], - "source": [ - "import warnings\n", - "warnings.simplefilter(action='ignore', category=FutureWarning)" - ] - }, - { - "cell_type": "code", - "execution_count": 37, - "metadata": {}, - "outputs": [], - "source": [ - "import os\n", - "import json\n", - "import requests\n", - "from mlrun.execution import MLClientCtx\n", - "from typing import List" - ] - }, - { - "cell_type": "code", - "execution_count": 38, - "metadata": {}, - "outputs": [], - "source": [ - "def slack_notify(\n", - " context: MLClientCtx,\n", - " webhook_url: str = \"URL\",\n", - " slack_blocks: List[str] = [],\n", - " notification_text: str = \"Notification\"\n", - ") -> None:\n", - " \"\"\"Summarize a table\n", - " :param context: the function context\n", - " :param webhook_url: Slack incoming webhook URL. Please read: https://api.slack.com/messaging/webhooks\n", - " :param notification_text: Notification text\n", - " :param slack_blocks: Message blocks list. NOT IMPLEMENTED YET\n", - " \"\"\"\n", - " \n", - " data = {\n", - " 'text': notification_text\n", - " }\n", - " print(\"====\",webhook_url)\n", - " response = requests.post(webhook_url, data=json.dumps(\n", - " data), headers={'Content-Type': 'application/json'})\n", - "\n", - " print('Response: ' + str(response.text))\n", - " print('Response code: ' + str(response.status_code))" - ] - }, - { - "cell_type": "code", - "execution_count": 39, - "metadata": {}, - "outputs": [], - "source": [ - "# nuclio: end-code" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### mlconfig" - ] - }, - { - "cell_type": "code", - "execution_count": 40, - "metadata": {}, - "outputs": [], - "source": [ - "from mlrun import mlconf\n", - "import os\n", - "\n", - "mlconf.dbpath = 'http://mlrun-api:8080'\n", - "mlconf.artifact_path = mlconf.artifact_path or f'{os.environ[\"HOME\"]}/artifacts'" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### save" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from mlrun import code_to_function\n", - "\n", - "# create job function object from notebook code\n", - "fn = code_to_function(\"slack_notify\")\n", - "# add metadata (for templates and reuse)\n", - "fn.spec.default_handler = \"slack_notify\"\n", - "fn.spec.description = \"Send Slack notification\"\n", - "fn.metadata.categories = [\"ops\"]\n", - "fn.metadata.labels = {\"author\": \"mdl\"}\n", - "fn.export(\"function.yaml\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## tests" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from mlrun import import_function\n", - "func = import_function(\"hub://slack_notify\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from mlrun import NewTask, run_local\n", - "\n", - "\n", - "#Slack incoming webhook URL. Please read: https://api.slack.com/messaging/webhooks\n", - "task_params = {\n", - " \"webhook_url\" : \"https://hooks.slack.com/services/xxxxxxxx/xxxxxxxxx/xxxxxxxxxxxxxx\",\n", - " \"notification_text\" : \"Test Notification\"\n", - "}" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "task = NewTask(\n", - " name=\"tasks slack notify\", \n", - " params = task_params,\n", - " handler=slack_notify)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### run local where artifact path is fixed " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "run = run_local(task, artifact_path=mlconf.artifact_path)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### run remote where artifact path includes the run id" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "func.deploy()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "func.run(task, params=task_params, workdir=mlconf.artifact_path)" - ] - }, - { - "cell_type": "code", - "execution_count": 42, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "function: slack-notify\n", - "Send Slack notification\n", - "default handler: slack_notify\n", - "entry points:\n", - " slack_notify: Summarize a table\n", - " context(MLClientCtx) - the function context\n", - " webhook_url(str) - Slack incoming webhook URL. Please read: https://api.slack.com/messaging/webhooks, default=URL\n", - " slack_blocks(List[str]) - Message blocks list. NOT IMPLEMENTED YET\n", - " notification_text(str) - Notification text, default=Notification\n" - ] - } - ], - "source": [ - "func.doc()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "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.6.8" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/slack_notify/slack_notify.py b/slack_notify/slack_notify.py deleted file mode 100644 index 3208ffee1..000000000 --- a/slack_notify/slack_notify.py +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright 2019 Iguazio -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# Generated by nuclio.export.NuclioExporter - -import warnings - -warnings.simplefilter(action="ignore", category=FutureWarning) - -import os -import json -import requests -from mlrun.execution import MLClientCtx -from typing import List - - -def slack_notify( - context: MLClientCtx, - webhook_url: str = "URL", - slack_blocks: List[str] = [], - notification_text: str = "Notification", -) -> None: - """Summarize a table - :param context: the function context - :param webhook_url: Slack incoming webhook URL. Please read: https://api.slack.com/messaging/webhooks - :param notification_text: Notification text - :param slack_blocks: Message blocks list. NOT IMPLEMENTED YET - """ - - data = {"text": notification_text} - print("====", webhook_url) - response = requests.post( - webhook_url, data=json.dumps(data), headers={"Content-Type": "application/json"} - ) - - print("Response: " + str(response.text)) - print("Response code: " + str(response.status_code)) diff --git a/snowflake_dask/README.md b/snowflake_dask/README.md deleted file mode 100644 index 70fa3c927..000000000 --- a/snowflake_dask/README.md +++ /dev/null @@ -1,38 +0,0 @@ -# **Data Preperation Function** - -## `Snowflake_dask` - -![](img/snowflake-dask.png) - -This function query the data from a snowflake database and process the results -in parallel in a Dask cluster. -It will publish the dask dataframe in the cluster for other process to use. -It can also write the results dataframe to parquet files. - -```markdown - -:param context: the function context -:param dask_client: dask cluster function name -:param connection_info: Snowflake database connection info (this will be in a secret later) -:param query: query to for Snowflake -:param parquet_out_dir: directory path for the output parquet files (default None, not write out) -:param publish_name: name of the dask dataframe to publish to the dask cluster (default None, not publish) -``` - -To use the function, you will need to either have the password or key pair authentication to Snowflake configured. - -To get the password, or generate key pair in Snowflake and configure Snowflake for key pair authentication, please follow Snowflake [documentation](https://docs.snowflake.com/en/user-guide/key-pair-auth.html) here. - -After obtained password or key pair, please set up the project secrets in your Iguazio cluster. - -If you are using password, you only need to add ```sfPassword``` secret to the project settings. - -If you are using the key pair authentication, you will need to add both ```pkPath``` and ```pkPassword``` to the project settings. - - where: - - ```pkPath``` is the file path to your private key file in the cluster, for example ```/User/rsa_key.p8``` - -```pkPassword``` is your private key encryption password. Please see the screenshot below for your reference. - -![Secrets Screenshot](img/iguazio-project-secrets.png) diff --git a/snowflake_dask/config-template.yaml b/snowflake_dask/config-template.yaml deleted file mode 100644 index fb46ac2e6..000000000 --- a/snowflake_dask/config-template.yaml +++ /dev/null @@ -1,5 +0,0 @@ -user: "..." -password: "..." -warehouse: "..." -account: "..." -application: "Iguazio" \ No newline at end of file diff --git a/snowflake_dask/function.yaml b/snowflake_dask/function.yaml deleted file mode 100644 index c9cc8d746..000000000 --- a/snowflake_dask/function.yaml +++ /dev/null @@ -1,81 +0,0 @@ -kind: job -metadata: - name: snowflake-dask - tag: '' - hash: a002c7743b4a7471c7befe00f5497de050ebe902 - project: snowflake-dask - labels: - author: xingsheng - categories: - - data-prep - credentials: - access_key: ec09bfc8-1cb4-466d-9049-852081973ce3 -spec: - command: '' - args: [] - image: .mlrun/func-snowflake-dask-snowflake-dask:latest - build: - functionSourceCode: IiIiU25vd2ZsYWtlIERhc2sgLSBJbmdlc3QgU25hb3dmbGFrZSBkYXRhIHdpdGggRGFzayIiIgppbXBvcnQgd2FybmluZ3MKaW1wb3J0IG1scnVuCmZyb20gbWxydW4uZXhlY3V0aW9uIGltcG9ydCBNTENsaWVudEN0eAppbXBvcnQgc25vd2ZsYWtlLmNvbm5lY3RvciBhcyBzbm93CmZyb20gZGFzay5kaXN0cmlidXRlZCBpbXBvcnQgQ2xpZW50CmZyb20gZGFzay5kYXRhZnJhbWUgaW1wb3J0IGZyb21fZGVsYXllZApmcm9tIGRhc2sgaW1wb3J0IGRlbGF5ZWQKZnJvbSBkYXNrIGltcG9ydCBkYXRhZnJhbWUgYXMgZGQKZnJvbSBjcnlwdG9ncmFwaHkuaGF6bWF0LmJhY2tlbmRzIGltcG9ydCBkZWZhdWx0X2JhY2tlbmQKZnJvbSBjcnlwdG9ncmFwaHkuaGF6bWF0LnByaW1pdGl2ZXMgaW1wb3J0IHNlcmlhbGl6YXRpb24KCndhcm5pbmdzLmZpbHRlcndhcm5pbmdzKCJpZ25vcmUiKQoKQGRlbGF5ZWQKZGVmIGxvYWQoYmF0Y2gpOgoKICAgICIiIkEgZGVsYXllZCBsb2FkIG9uZSBiYXRjaC4iIiIKCiAgICB0cnk6CiAgICAgICAgcHJpbnQoIkJBVENISU5HIikKICAgICAgICBkZl8gPSBiYXRjaC50b19wYW5kYXMoKQogICAgICAgIHJldHVybiBkZl8KICAgIGV4Y2VwdCBFeGNlcHRpb24gYXMgZToKICAgICAgICBwcmludChmIkZhaWxlZCBvbiB7YmF0Y2h9IGZvciB7ZX0iKQogICAgICAgIHJhaXNlCgpkZWYgbG9hZF9yZXN1bHRzKGNvbnRleHQ6IE1MQ2xpZW50Q3R4LAogICAgICAgICAgICAgICAgIGRhc2tfY2xpZW50OiBzdHIsCiAgICAgICAgICAgICAgICAgY29ubmVjdGlvbl9pbmZvOiBzdHIsCiAgICAgICAgICAgICAgICAgcXVlcnk6IHN0ciwKICAgICAgICAgICAgICAgICBwYXJxdWV0X291dF9kaXIgPSBOb25lLAogICAgICAgICAgICAgICAgIHB1Ymxpc2hfbmFtZSA9IE5vbmUKICAgICAgICAgICAgICAgICkgLT4gTm9uZToKCiAgICAiIiJTbm93Zmxha2UgRGFzayAtIEluZ2VzdCBTbmFvd2ZsYWtlIGRhdGEgd2l0aCBEYXNrCgogICAgOnBhcmFtIGNvbnRleHQ6ICAgICAgICAgICB0aGUgZnVuY3Rpb24gY29udGV4dAogICAgOnBhcmFtIGRhc2tfY2xpZW50OiAgICAgICBkYXNrIGNsdXN0ZXIgZnVuY3Rpb24gbmFtZQogICAgOnBhcmFtIGNvbm5lY3Rpb25faW5mbzogICBTbm93Zmxha2UgZGF0YWJhc2UgY29ubmVjdGlvbiBpbmZvICh0aGlzIHdpbGwgYmUgaW4gYSBzZWNyZXQgbGF0ZXIpCiAgICA6cGFyYW0gcXVlcnk6ICAgICAgICAgICAgIHF1ZXJ5IHRvIGZvciBTbm93Zmxha2UKICAgIDpwYXJhbSBwYXJxdWV0X291dF9kaXI6ICAgZGlyZWN0b3J5IHBhdGggZm9yIHRoZSBvdXRwdXQgcGFycXVldCBmaWxlcwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoZGVmYXVsdCBOb25lLCBub3Qgd3JpdGUgb3V0KQogICAgOnBhcmFtIHB1Ymxpc2hfbmFtZTogICAgICBuYW1lIG9mIHRoZSBkYXNrIGRhdGFmcmFtZSB0byBwdWJsaXNoIHRvIHRoZSBkYXNrIGNsdXN0ZXIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKGRlZmF1bHQgTm9uZSwgbm90IHB1Ymxpc2gpCgogICAgIiIiCiAgICBjb250ZXh0ID0gbWxydW4uZ2V0X29yX2NyZWF0ZV9jdHgoJ3NuYXdmbGFrZS1kYXNrLWNsdXN0ZXInKQogICAgc2ZfcGFzc3dvcmQgPSBjb250ZXh0LmdldF9zZWNyZXQoJ3NmUGFzc3dvcmQnKQogICAgcGtfcGF0aCA9ICBjb250ZXh0LmdldF9zZWNyZXQoJ3BrUGF0aCcpCiAgICBwa19wYXNzd29yZCA9ICBjb250ZXh0LmdldF9zZWNyZXQoJ3BrUGFzc3dvcmQnKQoKICAgIGlmIHBrX3BhdGggYW5kIHBrX3Bhc3N3b3JkOgogICAgICAgIHdpdGggb3Blbihwa19wYXRoLCAicmIiKSBhcyBrZXk6CiAgICAgICAgICAgIHBfa2V5PSBzZXJpYWxpemF0aW9uLmxvYWRfcGVtX3ByaXZhdGVfa2V5KAogICAgICAgICAgICAgICAga2V5LnJlYWQoKSwKICAgICAgICAgICAgICAgIHBhc3N3b3JkPXN0cihwa19wYXNzd29yZCkuZW5jb2RlKCksCiAgICAgICAgICAgICAgICBiYWNrZW5kPWRlZmF1bHRfYmFja2VuZCgpCiAgICAgICAgICAgICkKICAgICAgICBwa2IgPSBwX2tleS5wcml2YXRlX2J5dGVzKAogICAgICAgICAgICBlbmNvZGluZz1zZXJpYWxpemF0aW9uLkVuY29kaW5nLkRFUiwKICAgICAgICAgICAgZm9ybWF0PXNlcmlhbGl6YXRpb24uUHJpdmF0ZUZvcm1hdC5QS0NTOAogICAgICAgICAgICAsZW5jcnlwdGlvbl9hbGdvcml0aG09c2VyaWFsaXphdGlvbi5Ob0VuY3J5cHRpb24oKQogICAgICAgICkKICAgICAgICBjb25uZWN0aW9uX2luZm8ucG9wKCdwYXNzd29yZCcsICdObyBwYXNzd29yZCBmb3VuZCcpCiAgICAgICAgY29ubmVjdGlvbl9pbmZvWydwcml2YXRlX2tleSddID0gcGtiCiAgICBlbGlmIHNmX3Bhc3N3b3JkOgogICAgICAgIGNvbm5lY3Rpb25faW5mb1sncGFzc3dvcmQnXSA9IHNmX3Bhc3N3b3JkCiAgICBlbHNlOgogICAgICAgIHJhaXNlIEV4Y2VwdGlvbigiXG5QbGVhc2Ugc2V0IHVwIHRoZSBzZWNyZXQgZm9yIFNub3dmbGFrZSBpbiB5b3VyIHByb2plY3QhXG4iKQoKICAgICMgc2V0dXAgZGFzayBjbGllbnQgZnJvbSB0aGUgTUxSdW4gZGFzayBjbHVzdGVyIGZ1bmN0aW9uCiAgICBpZiBkYXNrX2NsaWVudDoKICAgICAgICBjbGllbnQgPSBtbHJ1bi5pbXBvcnRfZnVuY3Rpb24oZGFza19jbGllbnQpLmNsaWVudAogICAgICAgIGNvbnRleHQubG9nZ2VyLmluZm8oZidFeGlzdGluZyBkYXNrIGNsaWVudCA9PT0gPj4+IHtjbGllbnR9XG4nKQogICAgZWxzZToKICAgICAgICBjbGllbnQgPSBDbGllbnQoKQogICAgICAgIGNvbnRleHQubG9nZ2VyLmluZm8oZidcbk5ld2x5IGNyZWF0ZWQgZGFzayBjbGllbnQgPT09ID4+PiB7Y2xpZW50fVxuJykKCiAgICBjb25uID0gc25vdy5jb25uZWN0KCoqY29ubmVjdGlvbl9pbmZvKQogICAgY3VyID0gY29ubi5jdXJzb3IoKQogICAgY3VyLmV4ZWN1dGUocXVlcnkpCiAgICBiYXRjaGVzID0gY3VyLmdldF9yZXN1bHRfYmF0Y2hlcygpCiAgICBjb250ZXh0LmxvZ2dlci5pbmZvKGYnYmF0Y2hlcyBsZW4gPT09IHtsZW4oYmF0Y2hlcyl9XG4nKQoKICAgIGRmcyA9IFtdCiAgICBmb3IgYmF0Y2ggaW4gYmF0Y2hlczoKICAgICAgICBpZiBiYXRjaC5yb3djb3VudCA+IDA6CiAgICAgICAgICAgIGRmID0gbG9hZChiYXRjaCkKICAgICAgICAgICAgZGZzLmFwcGVuZChkZikKICAgIGRkZiA9IGZyb21fZGVsYXllZChkZnMpCgogICAgIyBtYXRlcmlhbGl6ZSB0aGUgcXVlcnkgcmVzdWx0cyBzZXQgZm9yIHNvbWUgc2FtcGxlIGNvbXB1dGUKCiAgICBkZGZfZGVzY3JpYmUgPSBkZGYuZGVzY3JpYmUoKS5jb21wdXRlKCkKCiAgICBjb250ZXh0LmxvZ2dlci5pbmZvKGYncXVlcnkgID09PSA+Pj4ge3F1ZXJ5fVxuJykKICAgIGNvbnRleHQubG9nZ2VyLmluZm8oZidkZGYgID09PSA+Pj4ge2RkZn1cbicpCiAgICBjb250ZXh0LmxvZ19yZXN1bHQoJ251bWJlciBvZiByb3dzJywgbGVuKGRkZi5pbmRleCkpCiAgICBjb250ZXh0LmxvZ19kYXRhc2V0KCJkZGZfZGVzY3JpYmUiLCBkZj1kZGZfZGVzY3JpYmUpCgogICAgaWYgcHVibGlzaF9uYW1lOgogICAgICAgIGNvbnRleHQubG9nX3Jlc3VsdCgnZGF0YV9zZXRfbmFtZScsIHB1Ymxpc2hfbmFtZSkKICAgICAgICBpZiBub3QgY2xpZW50Lmxpc3RfZGF0YXNldHMoKToKICAgICAgICAgICAgZGRmLnBlcnNpc3QobmFtZSA9IHB1Ymxpc2hfbmFtZSkKICAgICAgICAgICAgY2xpZW50LnB1Ymxpc2hfZGF0YXNldChwdWJsaXNoX25hbWU9ZGRmKQoKICAgIGlmIHBhcnF1ZXRfb3V0X2RpcjoKICAgICAgICBkZC50b19wYXJxdWV0KGRmPWRkZiwgcGF0aD1wYXJxdWV0X291dF9kaXIpCiAgICAgICAgY29udGV4dC5sb2dfcmVzdWx0KCdwYXJxdWV0IGRpcmVjdG9yeScsIHBhcnF1ZXRfb3V0X2RpcikK - base_image: mlrun/mlrun - commands: - - python -m pip install bokeh snowflake-connector-python[pandas] mlrun~=0.9.1 - code_origin: https://github.com/xsqian/functions.git#6b31040e2ad762602f335b0589823a1c61a09975:snowflake_dask.py - origin_filename: snowflake_dask.py - entry_points: - load: - name: load - doc: A delayed load one batch. - parameters: - - name: batch - default: '' - outputs: - - default: '' - lineno: 15 - load_results: - name: load_results - doc: Snowflake Dask - Ingest Snaowflake data with Dask - parameters: - - name: context - type: MLClientCtx - doc: the function context - default: '' - - name: dask_client - type: str - doc: dask cluster function name - default: '' - - name: connection_info - type: str - doc: Snowflake database connection info (this will be in a secret later) - default: '' - - name: query - type: str - doc: query to for Snowflake - default: '' - - name: parquet_out_dir - doc: directory path for the output parquet files (default None, not write - out) - default: null - - name: publish_name - doc: name of the dask dataframe to publish to the dask cluster (default None, - not publish) - default: null - outputs: - - default: '' - lineno: 28 - description: Snowflake Dask - Ingest snowflake data in parallel with Dask cluster - default_handler: load_results - disable_auto_mount: false - env: - - name: V3IO_API - value: '' - - name: V3IO_USERNAME - value: '' - - name: V3IO_ACCESS_KEY - value: '' - - name: V3IO_FRAMESD - value: '' - priority_class_name: igz-workload-medium - preemption_mode: prevent - affinity: null - tolerations: null -verbose: false diff --git a/snowflake_dask/img/iguazio-project-secrets.png b/snowflake_dask/img/iguazio-project-secrets.png deleted file mode 100644 index 29f48aa338e3639981cadb6c31cac31cfb96d2bf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 105122 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 diff --git a/snowflake_dask/item.yaml b/snowflake_dask/item.yaml deleted file mode 100644 index c12d3aba0..000000000 --- a/snowflake_dask/item.yaml +++ /dev/null @@ -1,25 +0,0 @@ -apiVersion: v1 -categories: -- data-preparation -description: Snowflake Dask - Ingest snowflake data in parallel with Dask cluster -doc: '' -example: snowflake-dask-mlrun.ipynb -generationDate: 2022-08-28:17-25 -hidden: false -icon: '' -labels: - author: xingsheng - framework: dask -maintainers: [] -marketplaceType: '' -mlrunVersion: 1.4.1 -name: snowflake_dask -platformVersion: 3.5.0 -spec: - filename: snowflake_dask.py - handler: load_results - image: mlrun/mlrun - kind: job - requirements: [] -url: '' -version: 1.1.0 diff --git a/snowflake_dask/requirements.txt b/snowflake_dask/requirements.txt deleted file mode 100644 index 0bca2c92f..000000000 --- a/snowflake_dask/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -bokeh -snowflake-connector-python[pandas] diff --git a/snowflake_dask/snowflake-dask-mlrun.ipynb b/snowflake_dask/snowflake-dask-mlrun.ipynb deleted file mode 100644 index 03936f2a5..000000000 --- a/snowflake_dask/snowflake-dask-mlrun.ipynb +++ /dev/null @@ -1,437 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# This notebook is to create a function to ingest data from snowflake with a Dask cluster" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The dask frameworks enables users to parallelize their python code and run it as a distributed process on Iguazio cluster and dramatically accelerate their performance.
\n", - "In this notebook we'll create an mlrun function running as a dask client to ingest data from snowflake.
\n", - "It also demonstrates how to run parallelize query against snowflake using Dask Delayed option to query a large data set from snowflake.
\n", - "The function will be published on the function marketplace.
\n", - "For more information on dask over kubernetes: https://kubernetes.dask.org/en/latest/" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Set up the enviroment" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import mlrun\n", - "import os\n", - "import warnings\n", - "import yaml\n", - "\n", - "project_name = \"snowflake-dask\"\n", - "dask_cluster_name=\"snowflake-dask-cluster\"\n", - "artifact_path = mlrun.set_environment(project=project_name,\n", - " artifact_path = os.path.join(os.path.abspath('/v3io/projects/'), project_name))\n", - "\n", - "warnings.filterwarnings(\"ignore\")\n", - "\n", - "print(f'artifact_path = {artifact_path}')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Load snowflake configuration from config file. \n", - "This is for demo purpose, in the real production code, you would need to put the snowflake connection info into secrets use the secrets in the running pod to connect to snowflake" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Load connection info\n", - "with open(\".config.yaml\") as f:\n", - " connection_info = yaml.safe_load(f)\n", - "\n", - "# verify the config\n", - "print(connection_info['account'])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Create a python function" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This function querys data from snowflake using snowflake python connector for parallel processing of the query results.
\n", - "With snoeflake python connector, when you execute a query, the cursor will return the result batches.
\n", - "Using Dask Delayed it will return and process results set in parallel.
" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### write the function to a py file" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "%%writefile snowflake_dask.py\n", - "\"\"\"Snowflake Dask - Ingest Snowflake data with Dask\"\"\"\n", - "import warnings\n", - "import mlrun\n", - "from mlrun.execution import MLClientCtx\n", - "import snowflake.connector as snow\n", - "from dask.distributed import Client\n", - "from dask.dataframe import from_delayed\n", - "from dask import delayed\n", - "from dask import dataframe as dd\n", - "from cryptography.hazmat.backends import default_backend\n", - "from cryptography.hazmat.primitives import serialization\n", - "\n", - "warnings.filterwarnings(\"ignore\")\n", - "\n", - "@delayed\n", - "def load(batch):\n", - "\n", - " \"\"\"A delayed load one batch.\"\"\"\n", - "\n", - " try:\n", - " print(\"BATCHING\")\n", - " df_ = batch.to_pandas()\n", - " return df_\n", - " except Exception as e:\n", - " print(f\"Failed on {batch} for {e}\")\n", - " raise\n", - "\n", - "def load_results(context: MLClientCtx,\n", - " dask_client: str,\n", - " connection_info: str,\n", - " query: str,\n", - " parquet_out_dir = None,\n", - " publish_name = None\n", - " ) -> None:\n", - "\n", - " \"\"\"Snowflake Dask - Ingest Snowflake data with Dask\n", - "\n", - " :param context: the function context\n", - " :param dask_client: dask cluster function name\n", - " :param connection_info: Snowflake database connection info (this will be in a secret later)\n", - " :param query: query to for Snowflake\n", - " :param parquet_out_dir: directory path for the output parquet files\n", - " (default None, not write out)\n", - " :param publish_name: name of the dask dataframe to publish to the dask cluster\n", - " (default None, not publish)\n", - "\n", - " \"\"\"\n", - " context = mlrun.get_or_create_ctx('snawflake-dask-cluster')\n", - " sf_password = context.get_secret('sfPassword')\n", - " pk_path = context.get_secret('pkPath')\n", - " pk_password = context.get_secret('pkPassword')\n", - "\n", - " if pk_path and pk_password:\n", - " with open(pk_path, \"rb\") as key:\n", - " p_key= serialization.load_pem_private_key(\n", - " key.read(),\n", - " password=str(pk_password).encode(),\n", - " backend=default_backend()\n", - " )\n", - " pkb = p_key.private_bytes(\n", - " encoding=serialization.Encoding.DER,\n", - " format=serialization.PrivateFormat.PKCS8\n", - " ,encryption_algorithm=serialization.NoEncryption()\n", - " )\n", - " connection_info.pop('password', 'No password found')\n", - " connection_info['private_key'] = pkb\n", - " elif sf_password:\n", - " connection_info['password'] = sf_password\n", - " else:\n", - " raise Exception(\"\\nPlease set up the secret for Snowflake in your project!\\n\")\n", - "\n", - " # setup dask client from the MLRun dask cluster function\n", - " if dask_client:\n", - " client = mlrun.import_function(dask_client).client\n", - " context.logger.info(f'Existing dask client === >>> {client}\\n')\n", - " else:\n", - " client = Client()\n", - " context.logger.info(f'\\nNewly created dask client === >>> {client}\\n')\n", - "\n", - " conn = snow.connect(**connection_info)\n", - " cur = conn.cursor()\n", - " cur.execute(query)\n", - " batches = cur.get_result_batches()\n", - " context.logger.info(f'batches len === {len(batches)}\\n')\n", - "\n", - " dfs = []\n", - " for batch in batches:\n", - " if batch.rowcount > 0:\n", - " df = load(batch)\n", - " dfs.append(df)\n", - " ddf = from_delayed(dfs)\n", - "\n", - " # materialize the query results set for some sample compute\n", - "\n", - " ddf_describe = ddf.describe().compute()\n", - "\n", - " context.logger.info(f'query === >>> {query}\\n')\n", - " context.logger.info(f'ddf === >>> {ddf}\\n')\n", - " context.log_result('number of rows', len(ddf.index))\n", - " context.log_dataset(\"ddf_describe\", df=ddf_describe)\n", - "\n", - " if publish_name:\n", - " context.log_result('data_set_name', publish_name)\n", - " if not client.list_datasets():\n", - " ddf.persist(name = publish_name)\n", - " client.publish_dataset(publish_name=ddf)\n", - "\n", - " if parquet_out_dir:\n", - " dd.to_parquet(df=ddf, path=parquet_out_dir)\n", - " context.log_result('parquet directory', parquet_out_dir)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Convert the code to MLRun function" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Use code_to_function to convert the code to MLRun
" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "fn = mlrun.code_to_function(name=\"snowflake-dask\", \n", - " kind='job', \n", - " filename='snowflake_dask.py',\n", - " image='mlrun/mlrun',\n", - " requirements='requirements.txt',\n", - " handler=\"load_results\", \n", - " description=\"Snowflake Dask - Ingest snowflake data in parallel with Dask cluster\",\n", - " categories=[\"data-prep\"],\n", - " labels={\"author\": \"xingsheng\"}\n", - " )\n", - "fn.apply(mlrun.platforms.auto_mount())\n", - "fn.deploy()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### export function to local `function.yaml` file for testing\n", - "in the real usage, we will import a function from hub" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "fn.export('function.yaml')\n", - "# print(fn.to_yaml())" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### import a function from local `function.yaml' for testing (Need to change it to import from hub before PR)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "fn = mlrun.import_function(\"./function.yaml\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# fn = mlrun.import_function(\"hub://snowflake_dask\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "fn.apply(mlrun.platforms.auto_mount()) # this is a very important line" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### create a dask cluster and specify the configuration for the dask process (e.g. replicas, memory etc)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# function URI is db:///\n", - "dask_uri = f'db://{project_name}/{dask_cluster_name}'\n", - "dask_uri" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "dsf = mlrun.new_function(name=dask_cluster_name, \n", - " kind='dask', \n", - " image='mlrun/mlrun',\n", - " requirements=[\"bokeh\", \"snowflake-connector-python[pandas]\"]\n", - " )\n", - "dsf.apply(mlrun.mount_v3io())\n", - "dsf.spec.remote = True\n", - "dsf.spec.min_replicas = 1\n", - "dsf.spec.max_replicas = 10\n", - "dsf.spec.service_type = \"NodePort\"\n", - "dsf.with_requests(mem='4G', cpu='2')\n", - "# dsf.spec.node_port=30088\n", - "# dsf.spec.scheduler_timeout = \"5 days\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "dsf.deploy()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "client = dsf.client" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Run the function" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "When running the function you would see a remote dashboard link as part of the result. click on this link takes you to the dask monitoring dashboard" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "p = 'my-local-test'\n", - "parquet_path = f\"/v3io/bigdata/pq_from_sf_dask/{p}\"\n", - "\n", - "fn.run(handler = 'load_results',\n", - " params={\"dask_client\": dask_uri, \n", - " \"connection_info\": connection_info, \n", - " \"query\": \"SELECT * FROM SNOWFLAKE_SAMPLE_DATA.TPCH_SF1.CUSTOMER\",\n", - " \"parquet_out_dir\": parquet_path,\n", - " \"publish_name\": \"customer\",\n", - " }\n", - " )" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "client.close()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Track the progress in the UI" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Users can view the progress and detailed information in the mlrun UI by clicking on the uid above.
\n", - "Also, to track the dask progress in the dask UI click on the \"dashboard link\" above the \"client\" section" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python [conda env:root] *", - "language": "python", - "name": "conda-root-py" - }, - "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.7.6" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/snowflake_dask/snowflake_dask.py b/snowflake_dask/snowflake_dask.py deleted file mode 100644 index 8846e821d..000000000 --- a/snowflake_dask/snowflake_dask.py +++ /dev/null @@ -1,125 +0,0 @@ -# Copyright 2019 Iguazio -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -"""Snowflake Dask - Ingest Snaowflake data with Dask""" - -import warnings -import mlrun -from mlrun.execution import MLClientCtx -import snowflake.connector as snow -from dask.distributed import Client -from dask.dataframe import from_delayed -from dask import delayed -from dask import dataframe as dd -from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives import serialization - -warnings.filterwarnings("ignore") - -@delayed -def load(batch): - - """A delayed load one batch.""" - - try: - print("BATCHING") - df_ = batch.to_pandas() - return df_ - except Exception as e: - print(f"Failed on {batch} for {e}") - raise - -def load_results(context: MLClientCtx, - dask_client: str, - connection_info: str, - query: str, - parquet_out_dir = None, - publish_name = None - ) -> None: - - """Snowflake Dask - Ingest Snowflake data with Dask - - :param context: the function context - :param dask_client: dask cluster function name - :param connection_info: Snowflake database connection info (this will be in a secret later) - :param query: query to for Snowflake - :param parquet_out_dir: directory path for the output parquet files - (default None, not write out) - :param publish_name: name of the dask dataframe to publish to the dask cluster - (default None, not publish) - - """ - context = mlrun.get_or_create_ctx('snawflake-dask-cluster') - sf_password = context.get_secret('sfPassword') - pk_path = context.get_secret('pkPath') - pk_password = context.get_secret('pkPassword') - - if pk_path and pk_password: - with open(pk_path, "rb") as key: - p_key= serialization.load_pem_private_key( - key.read(), - password=str(pk_password).encode(), - backend=default_backend() - ) - pkb = p_key.private_bytes( - encoding=serialization.Encoding.DER, - format=serialization.PrivateFormat.PKCS8 - ,encryption_algorithm=serialization.NoEncryption() - ) - connection_info.pop('password', 'No password found') - connection_info['private_key'] = pkb - elif sf_password: - connection_info['password'] = sf_password - else: - raise Exception("\nPlease set up the secret for Snowflake in your project!\n") - - # setup dask client from the MLRun dask cluster function - if dask_client: - client = mlrun.import_function(dask_client).client - context.logger.info(f'Existing dask client === >>> {client}\n') - else: - client = Client() - context.logger.info(f'\nNewly created dask client === >>> {client}\n') - - conn = snow.connect(**connection_info) - cur = conn.cursor() - cur.execute(query) - batches = cur.get_result_batches() - context.logger.info(f'batches len === {len(batches)}\n') - - dfs = [] - for batch in batches: - if batch.rowcount > 0: - df = load(batch) - dfs.append(df) - ddf = from_delayed(dfs) - - # materialize the query results set for some sample compute - - ddf_describe = ddf.describe().compute() - - context.logger.info(f'query === >>> {query}\n') - context.logger.info(f'ddf === >>> {ddf}\n') - context.log_result('number of rows', len(ddf.index)) - context.log_dataset("ddf_describe", df=ddf_describe) - - if publish_name: - context.log_result('data_set_name', publish_name) - if not client.list_datasets(): - ddf.persist(name = publish_name) - client.publish_dataset(publish_name=ddf) - - if parquet_out_dir: - dd.to_parquet(df=ddf, path=parquet_out_dir) - context.log_result('parquet directory', parquet_out_dir) diff --git a/snowflake_dask/test_snowflake_dask.py b/snowflake_dask/test_snowflake_dask.py deleted file mode 100644 index fc2d4c93a..000000000 --- a/snowflake_dask/test_snowflake_dask.py +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright 2019 Iguazio -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -"""Snowflake Dask unit test""" -from mlrun import import_function - -def test_snowflake_dask(): - """An unit test""" - fn_to_test = import_function("function.yaml") - - # a fake assert to pass the unit test - if fn_to_test.to_yaml().__contains__('job'): - assert True diff --git a/sql_to_file/function.yaml b/sql_to_file/function.yaml deleted file mode 100644 index 10b332a58..000000000 --- a/sql_to_file/function.yaml +++ /dev/null @@ -1,47 +0,0 @@ -kind: job -metadata: - name: sql-to-file - tag: '' - hash: 61f616fe697994e05cf018f2ee94c4ea25ed8863 - project: '' - labels: - author: adih - categories: - - data-preparation -spec: - command: '' - args: [] - image: mlrun/mlrun - env: [] - default_handler: sql_to_file - entry_points: - sql_to_file: - name: sql_to_file - doc: SQL Ingest - Ingest data using SQL query - parameters: - - name: context - type: MLClientCtx - doc: the function context - default: '' - - name: sql_query - type: str - doc: the sql query used to retrieve the data - default: '' - - name: database_url - type: str - doc: database connection URL - default: '' - - name: file_ext - type: str - doc: ("parquet") format for result file - default: parquet - outputs: - - default: '' - lineno: 9 - description: SQL To File - Ingest data using SQL query - build: - functionSourceCode: IyBHZW5lcmF0ZWQgYnkgbnVjbGlvLmV4cG9ydC5OdWNsaW9FeHBvcnRlcgoKaW1wb3J0IHBhbmRhcyBhcyBwZAppbXBvcnQgcHloaXZlCmZyb20gc3FsYWxjaGVteS5lbmdpbmUgaW1wb3J0IGNyZWF0ZV9lbmdpbmUKZnJvbSBtbHJ1bi5leGVjdXRpb24gaW1wb3J0IE1MQ2xpZW50Q3R4CgoKZGVmIHNxbF90b19maWxlKAogICAgY29udGV4dDogTUxDbGllbnRDdHgsCiAgICBzcWxfcXVlcnk6IHN0ciwKICAgIGRhdGFiYXNlX3VybDogc3RyLAogICAgZmlsZV9leHQ6IHN0ciA9ICJwYXJxdWV0IiwKKSAtPiBOb25lOgogICAgIiIiU1FMIEluZ2VzdCAtIEluZ2VzdCBkYXRhIHVzaW5nIFNRTCBxdWVyeQoKICAgIDpwYXJhbSBjb250ZXh0OiAgICAgICAgICAgdGhlIGZ1bmN0aW9uIGNvbnRleHQKICAgIDpwYXJhbSBzcWxfcXVlcnk6ICAgICAgICAgdGhlIHNxbCBxdWVyeSB1c2VkIHRvIHJldHJpZXZlIHRoZSBkYXRhCiAgICA6cGFyYW0gZGF0YWJhc2VfdXJsOiAgICAgIGRhdGFiYXNlIGNvbm5lY3Rpb24gVVJMCiAgICA6cGFyYW0gZmlsZV9leHQ6ICAgICAgICAgICgicGFycXVldCIpIGZvcm1hdCBmb3IgcmVzdWx0IGZpbGUKICAgICIiIgoKICAgIGVuZ2luZSA9IGNyZWF0ZV9lbmdpbmUoZGF0YWJhc2VfdXJsKQogICAgZGYgPSBwZC5yZWFkX3NxbChzcWxfcXVlcnksIGVuZ2luZSkKCiAgICBjb250ZXh0LmxvZ19kYXRhc2V0KAogICAgICAgICJxdWVyeSByZXN1bHQiLAogICAgICAgIGRmPWRmLAogICAgICAgIGZvcm1hdD1maWxlX2V4dCwKICAgICAgICBhcnRpZmFjdF9wYXRoPWNvbnRleHQuYXJ0aWZhY3Rfc3VicGF0aCgiZGF0YSIpLAogICAgKQo= - commands: [] - code_origin: https://github.com/daniels290813/functions.git#55a79c32be5d233cc11efcf40cd3edbe309bfdef:/home/kali/functions/sql_to_file/sql_to_file.py - affinity: null -verbose: false diff --git a/sql_to_file/item.yaml b/sql_to_file/item.yaml deleted file mode 100644 index 2f6ae4c53..000000000 --- a/sql_to_file/item.yaml +++ /dev/null @@ -1,24 +0,0 @@ -apiVersion: v1 -categories: -- data-preparation -description: SQL To File - Ingest data using SQL query -doc: '' -example: sql_to_file.ipynb -generationDate: 2022-08-28:17-25 -hidden: false -icon: '' -labels: - author: adih -maintainers: [] -marketplaceType: '' -mlrunVersion: 1.1.0 -name: sql-to-file -platformVersion: 3.5.0 -spec: - filename: sql_to_file.py - handler: sql_to_file - image: mlrun/mlrun - kind: job - requirements: [] -url: '' -version: 1.1.0 diff --git a/sql_to_file/requirements.txt b/sql_to_file/requirements.txt deleted file mode 100644 index 822eabb88..000000000 --- a/sql_to_file/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -pyhive -pymysql \ No newline at end of file diff --git a/sql_to_file/sql_to_file.ipynb b/sql_to_file/sql_to_file.ipynb deleted file mode 100644 index d4a084adb..000000000 --- a/sql_to_file/sql_to_file.ipynb +++ /dev/null @@ -1,1567 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# SQL Ingest - Ingest data using SQL query " - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "ename": "ModuleNotFoundError", - "evalue": "No module named 'nuclio'", - "output_type": "error", - "traceback": [ - "\u001B[1;31m---------------------------------------------------------------------------\u001B[0m", - "\u001B[1;31mModuleNotFoundError\u001B[0m Traceback (most recent call last)", - "\u001B[1;32m\u001B[0m in \u001B[0;36m\u001B[1;34m\u001B[0m\n\u001B[0;32m 1\u001B[0m \u001B[1;31m# nuclio: ignore\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[1;32m----> 2\u001B[1;33m \u001B[1;32mimport\u001B[0m \u001B[0mnuclio\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0m\u001B[0;32m 3\u001B[0m \u001B[1;33m\u001B[0m\u001B[0m\n", - "\u001B[1;31mModuleNotFoundError\u001B[0m: No module named 'nuclio'" - ] - } - ], - "source": [ - "# nuclio: ignore\n", - "import nuclio" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "%nuclio: setting kind to 'job'\n", - "%nuclio: setting spec.image to 'mlrun/mlrun'\n" - ] - } - ], - "source": [ - "%nuclio config kind = \"job\"\n", - "%nuclio config spec.build.baseImage = \"mlrun/mlrun\"" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "%%nuclio cmd -c\n", - "pip install --no-cache-dir git+https://github.com/v3io/PyHive.git@v0.6.999 \n", - "pip install sqlalchemy==1.3.11\n", - "pip install PyMySQL==0.9.3" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "import pandas as pd\n", - "import pyhive\n", - "from sqlalchemy.engine import create_engine\n", - "from mlrun.execution import MLClientCtx\n", - "\n", - "\n", - "def sql_to_file(\n", - " context: MLClientCtx,\n", - " sql_query: str,\n", - " database_url: str,\n", - " file_ext: str = \"parquet\",\n", - ") -> None:\n", - " \"\"\"SQL Ingest - Ingest data using SQL query\n", - "\n", - " :param context: the function context\n", - " :param sql_query: the sql query used to retrieve the data\n", - " :param database_url: database connection URL\n", - " :param file_ext: (\"parquet\") format for result file\n", - "\n", - "\"\"\"\n", - "\n", - " engine = create_engine(database_url)\n", - " df = pd.read_sql(sql_query, engine)\n", - "\n", - " context.log_dataset('query result',\n", - " df=df,\n", - " format=file_ext,\n", - " artifact_path=context.artifact_subpath('data'))\n" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "# nuclio: end-code" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### mlconfig" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "ename": "KeyError", - "evalue": "'HOME'", - "output_type": "error", - "traceback": [ - "\u001B[1;31m---------------------------------------------------------------------------\u001B[0m", - "\u001B[1;31mKeyError\u001B[0m Traceback (most recent call last)", - "\u001B[1;32m\u001B[0m in \u001B[0;36m\u001B[1;34m\u001B[0m\n\u001B[0;32m 2\u001B[0m \u001B[1;32mimport\u001B[0m \u001B[0mos\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0;32m 3\u001B[0m \u001B[0mmlconf\u001B[0m\u001B[1;33m.\u001B[0m\u001B[0mdbpath\u001B[0m \u001B[1;33m=\u001B[0m \u001B[0mmlconf\u001B[0m\u001B[1;33m.\u001B[0m\u001B[0mdbpath\u001B[0m \u001B[1;32mor\u001B[0m \u001B[1;34m'http://mlrun-api:8080'\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[1;32m----> 4\u001B[1;33m \u001B[0mmlconf\u001B[0m\u001B[1;33m.\u001B[0m\u001B[0martifact_path\u001B[0m \u001B[1;33m=\u001B[0m \u001B[0mmlconf\u001B[0m\u001B[1;33m.\u001B[0m\u001B[0martifact_path\u001B[0m \u001B[1;32mor\u001B[0m \u001B[1;34mf'{os.environ[\"HOME\"]}/artifacts'\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0m\u001B[0;32m 5\u001B[0m \u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0;32m 6\u001B[0m \u001B[1;33m\u001B[0m\u001B[0m\n", - "\u001B[1;32mC:\\Program Files\\Python37\\lib\\os.py\u001B[0m in \u001B[0;36m__getitem__\u001B[1;34m(self, key)\u001B[0m\n\u001B[0;32m 679\u001B[0m \u001B[1;32mexcept\u001B[0m \u001B[0mKeyError\u001B[0m\u001B[1;33m:\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0;32m 680\u001B[0m \u001B[1;31m# raise KeyError with the original key value\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[1;32m--> 681\u001B[1;33m \u001B[1;32mraise\u001B[0m \u001B[0mKeyError\u001B[0m\u001B[1;33m(\u001B[0m\u001B[0mkey\u001B[0m\u001B[1;33m)\u001B[0m \u001B[1;32mfrom\u001B[0m \u001B[1;32mNone\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0m\u001B[0;32m 682\u001B[0m \u001B[1;32mreturn\u001B[0m \u001B[0mself\u001B[0m\u001B[1;33m.\u001B[0m\u001B[0mdecodevalue\u001B[0m\u001B[1;33m(\u001B[0m\u001B[0mvalue\u001B[0m\u001B[1;33m)\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0;32m 683\u001B[0m \u001B[1;33m\u001B[0m\u001B[0m\n", - "\u001B[1;31mKeyError\u001B[0m: 'HOME'" - ] - } - ], - "source": [ - "from mlrun import mlconf\n", - "import os\n", - "mlconf.dbpath = mlconf.dbpath or 'http://mlrun-api:8080'\n", - "mlconf.artifact_path = mlconf.artifact_path or f'{os.environ[\"HOME\"]}/artifacts'\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Save function" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "def mount_secret(\n", - " secret_name, volume_mount_path, volume_name='secret', items=None\n", - "):\n", - " def _mount_secret(task):\n", - " from kubernetes import client as k8s_client\n", - " vol = k8s_client.V1SecretVolumeSource(secret_name=secret_name, items=items)\n", - " return task.add_volume(\n", - " k8s_client.V1Volume(name=volume_name, secret=vol)\n", - " ).add_volume_mount(\n", - " k8s_client.V1VolumeMount(mount_path=volume_mount_path, name=volume_name)\n", - " )\n", - " return _mount_secret" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "from mlrun import code_to_function, NewTask\n", - "import os\n", - "\n", - "fn = code_to_function(name=\"sql_to_file\",\n", - " handler=\"sql_to_file\",\n", - " description=\"SQL To File - Ingest data using SQL query\",\n", - " categories=[\"data-prep\"],\n", - " labels={\"author\": \"adih\"})\n", - "\n", - "if \"V3IO_ACCESS_KEY\" in list(os.environ):\n", - " fn.apply(mount_secret(secret_name='presto-tls',\n", - " volume_mount_path= '/var/run/iguazio/secrets/'))\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Build the image" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[mlrun] 2020-06-29 12:42:44,100 starting remote build, image: .mlrun/func-default-sql-ingest-latest\n", - "\u001B[36mINFO\u001B[0m[0000] Resolved base name mlrun/mlrun:0.4.10 to mlrun/mlrun:0.4.10 \n", - "\u001B[36mINFO\u001B[0m[0000] Resolved base name mlrun/mlrun:0.4.10 to mlrun/mlrun:0.4.10 \n", - "\u001B[36mINFO\u001B[0m[0000] Retrieving image manifest mlrun/mlrun:0.4.10 \n", - "\u001B[36mINFO\u001B[0m[0000] Retrieving image manifest mlrun/mlrun:0.4.10 \n", - "\u001B[36mINFO\u001B[0m[0000] Built cross stage deps: map[] \n", - "\u001B[36mINFO\u001B[0m[0000] Retrieving image manifest mlrun/mlrun:0.4.10 \n", - "\u001B[36mINFO\u001B[0m[0000] Retrieving image manifest mlrun/mlrun:0.4.10 \n", - "\u001B[36mINFO\u001B[0m[0001] Unpacking rootfs as cmd RUN pip install --no-cache-dir git+https://github.com/v3io/PyHive.git@v0.6.999 requires it. \n", - "\u001B[36mINFO\u001B[0m[0027] Taking snapshot of full filesystem... \n", - "\u001B[36mINFO\u001B[0m[0039] Resolving paths \n", - "\u001B[36mINFO\u001B[0m[0046] RUN pip install --no-cache-dir git+https://github.com/v3io/PyHive.git@v0.6.999 \n", - "\u001B[36mINFO\u001B[0m[0046] cmd: /bin/sh \n", - "\u001B[36mINFO\u001B[0m[0046] args: [-c pip install --no-cache-dir git+https://github.com/v3io/PyHive.git@v0.6.999] \n", - "Collecting git+https://github.com/v3io/PyHive.git@v0.6.999\n", - " Cloning https://github.com/v3io/PyHive.git (to revision v0.6.999) to /tmp/pip-req-build-ycqhuolw\n", - " Running command git clone -q https://github.com/v3io/PyHive.git /tmp/pip-req-build-ycqhuolw\n", - "Requirement already satisfied: future in /usr/local/lib/python3.7/site-packages (from PyHive==0.6.1.dev0) (0.18.2)\n", - "Requirement already satisfied: python-dateutil in /usr/local/lib/python3.7/site-packages (from PyHive==0.6.1.dev0) (2.8.1)\n", - "Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.7/site-packages (from python-dateutil->PyHive==0.6.1.dev0) (1.15.0)\n", - "Building wheels for collected packages: PyHive\n", - " Building wheel for PyHive (setup.py): started\n", - " Building wheel for PyHive (setup.py): finished with status 'done'\n", - " Created wheel for PyHive: filename=PyHive-0.6.1.dev0-py3-none-any.whl size=46402 sha256=63dca405cbae83da4cfcabfd61fd00f1683bc008c8bfa2272eac7054ec283166\n", - " Stored in directory: /tmp/pip-ephem-wheel-cache-mwb52l_u/wheels/05/11/cd/4ac4df0fcee76e5ceb614c39c56fca1eead41c0ac32ff6285d\n", - "Successfully built PyHive\n", - "Installing collected packages: PyHive\n", - "Successfully installed PyHive-0.6.1.dev0\n", - "\u001B[36mINFO\u001B[0m[0048] Taking snapshot of full filesystem... \n", - "\u001B[36mINFO\u001B[0m[0048] Resolving paths \n", - "\u001B[36mINFO\u001B[0m[0053] RUN pip install sqlalchemy==1.3.11 \n", - "\u001B[36mINFO\u001B[0m[0053] cmd: /bin/sh \n", - "\u001B[36mINFO\u001B[0m[0053] args: [-c pip install sqlalchemy==1.3.11] \n", - "Collecting sqlalchemy==1.3.11\n", - " Downloading SQLAlchemy-1.3.11.tar.gz (6.0 MB)\n", - "Building wheels for collected packages: sqlalchemy\n", - " Building wheel for sqlalchemy (setup.py): started\n", - " Building wheel for sqlalchemy (setup.py): finished with status 'done'\n", - " Created wheel for sqlalchemy: filename=SQLAlchemy-1.3.11-cp37-cp37m-linux_x86_64.whl size=1216921 sha256=9dd22e89acfbb68df0c1d189d36907a16c9393e4174598eb4bf377ce57132f3c\n", - " Stored in directory: /root/.cache/pip/wheels/0a/60/60/f26cbd183a3bb0031ace108156036dd925ec0138ee1c496a16\n", - "Successfully built sqlalchemy\n", - "Installing collected packages: sqlalchemy\n", - " Attempting uninstall: sqlalchemy\n", - " Found existing installation: SQLAlchemy 1.3.17\n", - " Uninstalling SQLAlchemy-1.3.17:\n", - " Successfully uninstalled SQLAlchemy-1.3.17\n", - "Successfully installed sqlalchemy-1.3.11\n", - "\u001B[36mINFO\u001B[0m[0057] Taking snapshot of full filesystem... \n", - "\u001B[36mINFO\u001B[0m[0057] Resolving paths \n", - "\u001B[36mINFO\u001B[0m[0063] RUN pip install PyMySQL==0.9.3 \n", - "\u001B[36mINFO\u001B[0m[0063] cmd: /bin/sh \n", - "\u001B[36mINFO\u001B[0m[0063] args: [-c pip install PyMySQL==0.9.3] \n", - "Collecting PyMySQL==0.9.3\n", - " Downloading PyMySQL-0.9.3-py2.py3-none-any.whl (47 kB)\n", - "Installing collected packages: PyMySQL\n", - "Successfully installed PyMySQL-0.9.3\n", - "\u001B[36mINFO\u001B[0m[0064] Taking snapshot of full filesystem... \n", - "\u001B[36mINFO\u001B[0m[0064] Resolving paths \n" - ] - }, - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "fn.deploy()" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[mlrun] 2020-06-30 01:58:41,604 function spec saved to path: function.yaml\n" - ] - }, - { - "data": { - "text/plain": "" - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "fn.export('function.yaml')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Test" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Reading from a public MySQL DB" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [], - "source": [ - "mysql_url = 'mysql+pymysql://rfamro@mysql-rfam-public.ebi.ac.uk:4497/Rfam'\n", - "mysql_query = 'select rfam_acc,rfam_id,auto_wiki,description,author,seed_source FROM family'" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [], - "source": [ - "from mlrun import NewTask, run_local\n", - "\n", - "sql_task = NewTask(name='sql',\n", - " handler=sql_to_file,\n", - " params={'sql_query': mysql_query,\n", - " 'database_url': mysql_url})\n" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[mlrun] 2020-06-29 12:43:59,253 starting run sql uid=b0914edaa58e45ee97c132200c6b60be -> http://mlrun-api:8080\n" - ] - }, - { - "data": { - "text/html": [ - "\n", - "

\n" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "to track results use .show() or .logs() or in CLI: \n", - "!mlrun get run b0914edaa58e45ee97c132200c6b60be --project default , !mlrun logs b0914edaa58e45ee97c132200c6b60be --project default\n", - "[mlrun] 2020-06-29 12:44:02,344 run executed, status=completed\n" - ] - } - ], - "source": [ - "sql_func = run_local(sql_task)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Run it on a cluster" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[mlrun] 2020-06-29 12:44:02,350 starting run sql uid=46ff7ef67e314be49353982cdd8d073a -> http://mlrun-api:8080\n", - "[mlrun] 2020-06-29 12:44:02,622 Job is running in the background, pod: sql-mplpz\n", - "[mlrun] 2020-06-29 12:44:09,070 run executed, status=completed\n", - "final state: succeeded\n" - ] - }, - { - "data": { - "text/html": [ - "\n", - "
\n", - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
projectuiditerstartstatenamelabelsinputsparametersresultsartifacts
default0Jun 29 12:44:06completedsql
v3io_user=admin
kind=job
owner=admin
host=sql-mplpz
sql_query=select rfam_acc,rfam_id,auto_wiki,description,author,seed_source FROM family
database_url=mysql+pymysql://rfamro@mysql-rfam-public.ebi.ac.uk:4497/Rfam
query result
\n", - "
\n", - "
\n", - "
\n", - " Title\n", - " ×\n", - "
\n", - " \n", - "
\n", - "
\n" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "to track results use .show() or .logs() or in CLI: \n", - "!mlrun get run 46ff7ef67e314be49353982cdd8d073a --project default , !mlrun logs 46ff7ef67e314be49353982cdd8d073a --project default\n", - "[mlrun] 2020-06-29 12:44:11,893 run executed, status=completed\n" - ] - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "fn.run(sql_task)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### SQL query from Iguazio Key Value via Presto" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "You need to create a table and set the sql_table path accordingly.
\n", - "you can find an example of creating such table in https://github.com/v3io/tutorials/blob/master/data-ingestion-and-preparation/basic-data-ingestion-and-preparation.ipynb" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [], - "source": [ - "# nuclio: ignore\n", - "import os\n", - "sql_table = os.path.join('v3io.users.\"'+str(os.getenv('V3IO_USERNAME'))+'/examples/stocks_tab\"')\n", - "sql_query_string = 'select * from '+sql_table+\"\"" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Done.\n" - ] - }, - { - "data": { - "text/html": [ - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
securitydescsecuritytypetimeisinminpricedateendpricenumberoftradesmnemoniccurrencysecurityidmaxpricetradedvolumestartprice
UBS I.ETF-DL G.SEL.DIV.ADETF08:27IE00BMP3HG278.4182018-03-26 00:00:00.0008.4181UBUMEUR25054508.4184038.418
GILEAD SCIENCES DL-,001Common stock08:00US375558103659.72018-03-26 00:00:00.00059.843GISEUR250649559.8474559.7
3M CO. DL-,01Common stock08:00US88579Y1010176.512018-03-26 00:00:00.000176.511MMMEUR2506577176.5139176.51
DIEBOLD NIXDORF INH.O.N.Common stock08:06DE000A0CAYB266.32018-03-26 00:00:00.00066.31WINEUR250428666.36066.3
XTR.II EUR.INF.LINK.BD 1CETF08:13LU0290358224218.972018-03-26 00:00:00.000218.971DBXKEUR2505840218.97110218.97
UBS-ETF-MSCI EMU S.C.EOADETF08:33LU0671493277100.22018-03-26 00:00:00.000100.21UEFDEUR2506045100.2180100.2
ASMALLWORLD AG SF 1Common stock08:23CH040488012912.72018-03-26 00:00:00.00012.711Q7EUR308912212.740012.7
IS.DJ GLOB.TITAN.50 U.ETFETF08:42DE000628938231.252018-03-26 00:00:00.00031.251EXI2EUR250502931.255031.25
ISHS IV-AGEING POPUL.ETFETF08:17IE00BYZK46694.9262018-03-26 00:00:00.0004.92612B77EUR25055524.926254.926
PORSCHE AUTOM.HLDG VZOCommon stock08:00DE000PAH003864.682018-03-26 00:00:00.00064.768PAH3EUR250481664.7669864.7
" - ], - "text/plain": [ - "[('UBS I.ETF-DL G.SEL.DIV.AD', 'ETF', '08:27', 'IE00BMP3HG27', 8.418, '2018-03-26 00:00:00.000', 8.418, 1, 'UBUM', 'EUR', 2505450, 8.418, 403, 8.418),\n", - " ('GILEAD SCIENCES DL-,001', 'Common stock', '08:00', 'US3755581036', 59.7, '2018-03-26 00:00:00.000', 59.84, 3, 'GIS', 'EUR', 2506495, 59.84, 745, 59.7),\n", - " ('3M CO. DL-,01', 'Common stock', '08:00', 'US88579Y1010', 176.51, '2018-03-26 00:00:00.000', 176.51, 1, 'MMM', 'EUR', 2506577, 176.51, 39, 176.51),\n", - " ('DIEBOLD NIXDORF INH.O.N.', 'Common stock', '08:06', 'DE000A0CAYB2', 66.3, '2018-03-26 00:00:00.000', 66.3, 1, 'WIN', 'EUR', 2504286, 66.3, 60, 66.3),\n", - " ('XTR.II EUR.INF.LINK.BD 1C', 'ETF', '08:13', 'LU0290358224', 218.97, '2018-03-26 00:00:00.000', 218.97, 1, 'DBXK', 'EUR', 2505840, 218.97, 110, 218.97),\n", - " ('UBS-ETF-MSCI EMU S.C.EOAD', 'ETF', '08:33', 'LU0671493277', 100.2, '2018-03-26 00:00:00.000', 100.2, 1, 'UEFD', 'EUR', 2506045, 100.2, 180, 100.2),\n", - " ('ASMALLWORLD AG SF 1', 'Common stock', '08:23', 'CH0404880129', 12.7, '2018-03-26 00:00:00.000', 12.7, 1, '1Q7', 'EUR', 3089122, 12.7, 400, 12.7),\n", - " ('IS.DJ GLOB.TITAN.50 U.ETF', 'ETF', '08:42', 'DE0006289382', 31.25, '2018-03-26 00:00:00.000', 31.25, 1, 'EXI2', 'EUR', 2505029, 31.25, 50, 31.25),\n", - " ('ISHS IV-AGEING POPUL.ETF', 'ETF', '08:17', 'IE00BYZK4669', 4.926, '2018-03-26 00:00:00.000', 4.926, 1, '2B77', 'EUR', 2505552, 4.926, 25, 4.926),\n", - " ('PORSCHE AUTOM.HLDG VZO', 'Common stock', '08:00', 'DE000PAH0038', 64.68, '2018-03-26 00:00:00.000', 64.76, 8, 'PAH3', 'EUR', 2504816, 64.76, 698, 64.7)]" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "%sql select * from $sql_table limit 10" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [], - "source": [ - "sql_task = NewTask(name='sql', \n", - " handler=sql_to_file,\n", - " params={'sql_query': sql_query_string,\n", - " 'database_url': os.getenv('DATABASE_URL')}\n", - " )\n" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[mlrun] 2020-06-29 12:44:14,406 starting run sql uid=d32a57bb990d4142bb1f63862e8906bf -> http://mlrun-api:8080\n" - ] - }, - { - "data": { - "text/html": [ - "\n", - "
\n", - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
projectuiditerstartstatenamelabelsinputsparametersresultsartifacts
default0Jun 29 12:44:14completedsql
v3io_user=admin
kind=handler
owner=admin
host=jupyter-b9c7995f9-4fblj
sql_query=select * from v3io.users.\"admin/examples/stocks_tab\"
database_url=presto://admin:8278ee8e-0f31-4aea-a105-2eab202bec93@presto-api-presto.default-tenant.app.cs-mlrun-test.iguazio-c0.com:443/v3io?protocol=https&requests_kwargs=%7B%22verify%22%3A+%22%2Fvar%2Frun%2Figuazio%2Fsecrets%2Ftls.crt%22%2C+%22cert%22%3A+%5B%22%2Fvar%2Frun%2Figuazio%2Fsecrets%2Ftls.crt%22%2C+%22%2Fvar%2Frun%2Figuazio%2Fsecrets%2Ftls.key%22%5D%7D
query result
\n", - "
\n", - "
\n", - "
\n", - " Title\n", - " ×\n", - "
\n", - " \n", - "
\n", - "
\n" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "to track results use .show() or .logs() or in CLI: \n", - "!mlrun get run d32a57bb990d4142bb1f63862e8906bf --project default , !mlrun logs d32a57bb990d4142bb1f63862e8906bf --project default\n", - "[mlrun] 2020-06-29 12:44:18,102 run executed, status=completed\n" - ] - } - ], - "source": [ - "sql_func = run_local(sql_task)" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[mlrun] 2020-06-29 12:44:18,112 starting run sql uid=db9507007f6d452e9ca020e4f483e33b -> http://mlrun-api:8080\n", - "[mlrun] 2020-06-29 12:44:18,387 Job is running in the background, pod: sql-g7p4f\n", - "[mlrun] 2020-06-29 12:44:25,033 run executed, status=completed\n", - "final state: succeeded\n" - ] - }, - { - "data": { - "text/html": [ - "\n", - "
\n", - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
projectuiditerstartstatenamelabelsinputsparametersresultsartifacts
default0Jun 29 12:44:21completedsql
v3io_user=admin
kind=job
owner=admin
host=sql-g7p4f
sql_query=select * from v3io.users.\"admin/examples/stocks_tab\"
database_url=presto://admin:8278ee8e-0f31-4aea-a105-2eab202bec93@presto-api-presto.default-tenant.app.cs-mlrun-test.iguazio-c0.com:443/v3io?protocol=https&requests_kwargs=%7B%22verify%22%3A+%22%2Fvar%2Frun%2Figuazio%2Fsecrets%2Ftls.crt%22%2C+%22cert%22%3A+%5B%22%2Fvar%2Frun%2Figuazio%2Fsecrets%2Ftls.crt%22%2C+%22%2Fvar%2Frun%2Figuazio%2Fsecrets%2Ftls.key%22%5D%7D
query result
\n", - "
\n", - "
\n", - "
\n", - " Title\n", - " ×\n", - "
\n", - " \n", - "
\n", - "
\n" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "to track results use .show() or .logs() or in CLI: \n", - "!mlrun get run db9507007f6d452e9ca020e4f483e33b --project default , !mlrun logs db9507007f6d452e9ca020e4f483e33b --project default\n", - "[mlrun] 2020-06-29 12:44:27,645 run executed, status=completed\n" - ] - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 19, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "fn.run(sql_task)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "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.6.8" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} \ No newline at end of file diff --git a/sql_to_file/sql_to_file.py b/sql_to_file/sql_to_file.py deleted file mode 100644 index 6d5e152ba..000000000 --- a/sql_to_file/sql_to_file.py +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright 2019 Iguazio -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# Generated by nuclio.export.NuclioExporter - -import pandas as pd -import pyhive -from sqlalchemy.engine import create_engine -from mlrun.execution import MLClientCtx - - -def sql_to_file( - context: MLClientCtx, - sql_query: str, - database_url: str, - file_ext: str = "parquet", -) -> None: - """SQL Ingest - Ingest data using SQL query - - :param context: the function context - :param sql_query: the sql query used to retrieve the data - :param database_url: database connection URL - :param file_ext: ("parquet") format for result file - """ - - engine = create_engine(database_url) - df = pd.read_sql(sql_query, engine) - - context.log_dataset( - "query result", - df=df, - format=file_ext, - artifact_path=context.artifact_subpath("data"), - ) diff --git a/sql_to_file/test_sql_to_file.py b/sql_to_file/test_sql_to_file.py deleted file mode 100644 index d636b86ca..000000000 --- a/sql_to_file/test_sql_to_file.py +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright 2019 Iguazio -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -from mlrun import code_to_function - -mysql_url = 'mysql+pymysql://rfamro@mysql-rfam-public.ebi.ac.uk:4497/Rfam' -mysql_query = 'select rfam_acc,rfam_id,auto_wiki,description,author,seed_source FROM family' - - -def test_run_sql_to_file(): - fn = code_to_function(name='test_sql_to_file', - filename="sql_to_file.py", - handler="sql_to_file", - kind="job", - ) - run = fn.run(params={'sql_query': mysql_query, - 'database_url': mysql_url}, - local=True) - - assert(run.artifact("query result")) \ No newline at end of file diff --git a/stream_to_parquet/function.yaml b/stream_to_parquet/function.yaml deleted file mode 100644 index 13a76a2cb..000000000 --- a/stream_to_parquet/function.yaml +++ /dev/null @@ -1,45 +0,0 @@ -kind: remote -metadata: - name: stream-to-parquet - tag: '' - hash: 78316bfbe731714715c19f0bc6deabf8652f15c4 - project: '' - labels: - author: orz - categories: - - machine-learning - - data-preparation -spec: - command: '' - args: [] - image: mlrun/ml-models - description: Saves a stream to Parquet and can lunch drift detection task on it - min_replicas: 1 - max_replicas: 1 - env: [] - base_spec: - apiVersion: nuclio.io/v1 - kind: Function - metadata: - name: stream-to-parquet - labels: {} - annotations: - nuclio.io/generated_by: function generated from /User/test/functions/stream_to_parquet/stream_to_parquet.py - spec: - runtime: python:3.9 - handler: stream_to_parquet:handler - env: [] - volumes: [] - build: - commands: [] - noBaseImagesPull: true - functionSourceCode: IyBHZW5lcmF0ZWQgYnkgbnVjbGlvLmV4cG9ydC5OdWNsaW9FeHBvcnRlcgoKaW1wb3J0IG9zCmltcG9ydCBwYW5kYXMgYXMgcGQKaW1wb3J0IG51bXB5IGFzIG5wCmltcG9ydCBqc29uCmltcG9ydCBkYXRldGltZQppbXBvcnQgbWxydW4KCgpkZWYgcmVjb3JkX3RvX2ZlYXR1cmVzKHJlY29yZCk6CiAgICBmZWF0dXJlcyA9IHJlY29yZFsicmVxdWVzdCJdWyJpbnN0YW5jZXMiXVswXQogICAgdGltZXN0YW1wID0gcmVjb3JkWyJ3aGVuIl0KICAgIHByZWRpY3Rpb24gPSByZWNvcmRbInJlc3AiXQoKICAgIHJlY29yZCA9IHsidGltZXN0YW1wIjogdGltZXN0YW1wLCAqKmZlYXR1cmVzLCAicHJlZGljdGlvbnMiOiBwcmVkaWN0aW9ufQoKICAgIHJldHVybiByZWNvcmQKCgpkZWYgaW5pdF9jb250ZXh0KGNvbnRleHQpOgogICAgc2V0YXR0cihjb250ZXh0LCAiYmF0Y2giLCBbXSkKICAgIHNldGF0dHIoY29udGV4dCwgIndpbmRvdyIsIGludChvcy5nZXRlbnYoIndpbmRvdyIsIDEwKSkpCiAgICBzZXRhdHRyKGNvbnRleHQsICJzYXZlX3RvIiwgb3MuZ2V0ZW52KCJzYXZlX3RvIiwgIi9iaWdkYXRhL2luZmVyZW5jZV9wcS8iKSkKICAgIG9zLm1ha2VkaXJzKGNvbnRleHQuc2F2ZV90bywgZXhpc3Rfb2s9VHJ1ZSkKCiAgICBtbHJ1bi5tbGNvbmYuZGJwYXRoID0gbWxydW4ubWxjb25mLmRicGF0aCBvciAiaHR0cDovL21scnVuLWFwaTo4MDgwIgogICAgYXJ0aWZhY3RfcGF0aCA9IG9zLmdldGVudigiYXJ0aWZhY3RfcGF0aCIsIE5vbmUpCiAgICBpZiBhcnRpZmFjdF9wYXRoOgogICAgICAgIG1scnVuLm1sY29uZi5hcnRpZmFjdF9wYXRoID0gYXJ0aWZhY3RfcGF0aAogICAgaWYgImh1Yl91cmwiIGluIG9zLmVudmlyb246CiAgICAgICAgbWxydW4ubWxjb25mLmh1Yl91cmwgPSBvcy5lbnZpcm9uWyJodWJfdXJsIl0KICAgIHZpcnR1YWxfZHJpZnRfZm4gPSBtbHJ1bi5pbXBvcnRfZnVuY3Rpb24oImh1YjovL3ZpcnR1YWxfZHJpZnQiKQogICAgdmlydHVhbF9kcmlmdF9mbi5hcHBseShtbHJ1bi5hdXRvX21vdW50KCkpCiAgICBzZXRhdHRyKGNvbnRleHQsICJ2aXJ0dWFsX2RyaWZ0X2ZuIiwgdmlydHVhbF9kcmlmdF9mbikKCiAgICBwcmVkaWN0aW9uc19jb2wgPSBvcy5nZXRlbnYoInByZWRpY3Rpb25zIiwgTm9uZSkKICAgIGxhYmVsX2NvbCA9IG9zLmdldGVudigibGFiZWxfY29sIiwgTm9uZSkKICAgIHNldGF0dHIoY29udGV4dCwgImJhc2VfZGF0YXNldCIsIG9zLmdldGVudigiYmFzZV9kYXRhc2V0IiwgIiIpKQogICAgc2V0YXR0cihjb250ZXh0LCAiaW5kZXhlcyIsIGpzb24ubG9hZHMob3MuZW52aXJvbi5nZXQoImluZGV4ZXMiLCAiW10iKSkpCiAgICBzZXRhdHRyKGNvbnRleHQsICJwcmVkaWN0aW9uc19jb2wiLCBwcmVkaWN0aW9uc19jb2wpCiAgICBzZXRhdHRyKGNvbnRleHQsICJsYWJlbF9jb2wiLCBsYWJlbF9jb2wpCiAgICBzZXRhdHRyKAogICAgICAgIGNvbnRleHQsICJyZXN1bHRzX3RzZGJfY29udGFpbmVyIiwgb3MuZ2V0ZW52KCJyZXN1bHRzX3RzZGJfY29udGFpbmVyIiwgTm9uZSkKICAgICkKICAgIHNldGF0dHIoY29udGV4dCwgInJlc3VsdHNfdHNkYl90YWJsZSIsIG9zLmdldGVudigicmVzdWx0c190c2RiX3RhYmxlIiwgTm9uZSkpCgoKZGVmIGhhbmRsZXIoY29udGV4dCwgZXZlbnQpOgoKICAgIGNvbnRleHQubG9nZ2VyLmluZm8oZiJBZGRpbmcge2V2ZW50LmJvZHl9IikKICAgIGNvbnRleHQuYmF0Y2guYXBwZW5kKHJlY29yZF90b19mZWF0dXJlcyhqc29uLmxvYWRzKGV2ZW50LmJvZHkpKSkKCiAgICBpZiBsZW4oY29udGV4dC5iYXRjaCkgPiBjb250ZXh0LndpbmRvdzoKICAgICAgICBjb250ZXh0LmxvZ2dlci5pbmZvKGNvbnRleHQuYmF0Y2hbOjFdKQogICAgICAgIGNvbnRleHQubG9nZ2VyLmluZm8oY29udGV4dC5pbmRleGVzKQogICAgICAgIGRmID0gcGQuRGF0YUZyYW1lKGNvbnRleHQuYmF0Y2gpCiAgICAgICAgY29udGV4dC5sb2dnZXIuaW5mbyhmImRmIGV4YW1wbGU6IHtkZi5oZWFkKDEpfSIpCiAgICAgICAgaWYgY29udGV4dC5pbmRleGVzOgogICAgICAgICAgICBkZiA9IGRmLnNldF9pbmRleChjb250ZXh0LmluZGV4ZXMpCiAgICAgICAgZGZfcGF0aCA9IG9zLnBhdGguam9pbigKICAgICAgICAgICAgY29udGV4dC5zYXZlX3RvLAogICAgICAgICAgICBmIntkYXRldGltZS5kYXRldGltZS5ub3coKS5zdHJmdGltZSgnJVktJW0tJWRUJUg6JU06JVMnKX0ucHEiLAogICAgICAgICkKICAgICAgICBkZi50b19wYXJxdWV0KGRmX3BhdGgsaW5kZXg9RmFsc2UpCgogICAgICAgIHRhc2sgPSBtbHJ1bi5OZXdUYXNrKAogICAgICAgICAgICBuYW1lPSJkcmlmdF9tYWduaXR1ZGUiLAogICAgICAgICAgICBoYW5kbGVyPSJkcmlmdF9tYWduaXR1ZGUiLAogICAgICAgICAgICBwYXJhbXM9ewogICAgICAgICAgICAgICAgImxhYmVsX2NvbCI6IGNvbnRleHQubGFiZWxfY29sLAogICAgICAgICAgICAgICAgInByZWRpY3Rpb25fY29sIjogY29udGV4dC5wcmVkaWN0aW9uc19jb2wsCiAgICAgICAgICAgICAgICAicmVzdWx0c190c2RiX2NvbnRhaW5lciI6IGNvbnRleHQucmVzdWx0c190c2RiX2NvbnRhaW5lciwKICAgICAgICAgICAgICAgICJyZXN1bHRzX3RzZGJfdGFibGUiOiBjb250ZXh0LnJlc3VsdHNfdHNkYl90YWJsZSwKICAgICAgICAgICAgfSwKICAgICAgICAgICAgaW5wdXRzPXsidCI6IGNvbnRleHQuYmFzZV9kYXRhc2V0LCAidSI6IGRmX3BhdGh9LAogICAgICAgICAgICBhcnRpZmFjdF9wYXRoPW1scnVuLm1sY29uZi5hcnRpZmFjdF9wYXRoLAogICAgICAgICkKCiAgICAgICAgY29udGV4dC52aXJ0dWFsX2RyaWZ0X2ZuLnJ1bih0YXNrLCB3YXRjaD1GYWxzZSkKCiAgICAgICAgY29udGV4dC5iYXRjaCA9IFtdCg== - source: '' - build: - commands: [] - code_origin: https://github.com/daniels290813/functions.git#3605c9b8dcadab89a5a45f7d16dcd2fcfeca8697:/User/test/functions/stream_to_parquet/stream_to_parquet.py - origin_filename: /User/test/functions/stream_to_parquet/stream_to_parquet.py - default_handler: handler - disable_auto_mount: false - affinity: null -verbose: false diff --git a/stream_to_parquet/item.yaml b/stream_to_parquet/item.yaml deleted file mode 100644 index cbd59376e..000000000 --- a/stream_to_parquet/item.yaml +++ /dev/null @@ -1,28 +0,0 @@ -apiVersion: v1 -categories: -- machine-learning -- data-preparation -description: Saves a stream to Parquet and can lunch drift detection task on it -doc: '' -example: stream_to_parquet.ipynb -generationDate: 2022-08-28:17-25 -hidden: false -icon: '' -labels: - author: orz -maintainers: [] -marketplaceType: '' -mlrunVersion: 1.1.0 -name: stream-to-parquet -platformVersion: 3.5.0 -spec: - customFields: - max_replicas: 1 - min_replicas: 1 - filename: stream_to_parquet.py - handler: handler - image: mlrun/ml-models - kind: nuclio - requirements: [] -url: '' -version: 1.1.0 diff --git a/stream_to_parquet/stream_to_parquet.ipynb b/stream_to_parquet/stream_to_parquet.ipynb deleted file mode 100644 index e47c6be92..000000000 --- a/stream_to_parquet/stream_to_parquet.ipynb +++ /dev/null @@ -1,698 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Stream to Parquet" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Part of the [network operations](https://github.com/mlrun/demos/tree/0.7.x/network-operations) demo pipeline, this function listens to a labeld stream and writes it as parquet files.
\n", - "This function also deploys the function [virtual_drift](https://github.com/mlrun/functions/tree/master/virtual_drift) from the hub, which computes drift magnitude metrics between base dataset t and dataset u,
\n", - "in our case (as well as in the demo) - base dataset (the one that the model trained on) and the dataset the model predicted.
\n", - "virtual_drift writes the output to TSDB." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### **Steps**\n", - "\n", - "1. [Data exploration](#Data-exploration)\n", - "2. [Creating the labeled stream](#Creating-the-labeled-stream)\n", - "3. [Importing the function](#Importing-the-function)\n", - "4. [Running the functioh remotely](#Running-the-function-remotely)\n", - "5. [Testing the function](#Testing-the-function)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### **Data exploration**" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "In order to know about the performance of a drift detector by measuring the different detection metrics, we need to know beforehand where a real drift occurs.
\n", - "This is only possible with synthetic datasets.
The scikit-multiflow framework allows generating several kinds of synthetic data to simulate the occurrence of drifts.
\n", - "[Harvard dataverse](https://dataverse.harvard.edu) provides futher explanations on the [used dataset](https://dataverse.harvard.edu/dataset.xhtml?persistentId=doi:10.7910/DVN/5OWRGB) along with different kinds of drifted datasets.
\n", - "mixed_0101_abrupto has 4 concepts and 3 drifts at time steps 10000, 20000, and 30000.
\n", - "Our dataset will be train-test-splitted, the train part (first 5000 examples) is used to train the model (that is generated easly using [sklearn_classifer](https://github.com/mlrun/functions/blob/master/sklearn_classifier/sklearn_classifier.ipynb)).
\n", - "The test part (which is already predicted by the model) will be pushed to the input stream in order to detect drifts." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
X1X2X3X4class
00.01.00.4601010.5927441.0
11.01.00.5887880.5749840.0
20.00.00.4016410.6793251.0
31.01.00.3060760.1821080.0
40.00.00.9628470.5792451.0
\n", - "
" - ], - "text/plain": [ - " X1 X2 X3 X4 class\n", - "0 0.0 1.0 0.460101 0.592744 1.0\n", - "1 1.0 1.0 0.588788 0.574984 0.0\n", - "2 0.0 0.0 0.401641 0.679325 1.0\n", - "3 1.0 1.0 0.306076 0.182108 0.0\n", - "4 0.0 0.0 0.962847 0.579245 1.0" - ] - }, - "execution_count": 1, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import pandas as pd\n", - "data_path = 'https://s3.wasabisys.com/iguazio/data/function-marketplace-data/concept_drift/mixed_0101_abrupto.csv'\n", - "base_dataset = 'https://s3.wasabisys.com/iguazio/data/function-marketplace-data/concept_drift/predicted_abrupto_train.csv'\n", - "# The predicted test data is pushed to the stream\n", - "predicted_test_data_path = 'https://s3.wasabisys.com/iguazio/data/function-marketplace-data/concept_drift/predicted_abrupto_test.csv'\n", - "# You can find the model used here\n", - "models_path = 'https://s3.wasabisys.com/iguazio/models/function-marketplace-models/concept_drift/concept_drift_random_forest.pkl'\n", - "original_data = pd.read_csv(data_path)\n", - "original_data.head()" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
X1X2X3X4classpredicted_col
349950.00.00.0101060.6472690.01.0
349961.01.00.2936510.7372911.00.0
349970.00.00.8485460.5523370.01.0
349981.01.00.6147540.8598961.00.0
349991.00.00.2653060.8437160.01.0
\n", - "
" - ], - "text/plain": [ - " X1 X2 X3 X4 class predicted_col\n", - "34995 0.0 0.0 0.010106 0.647269 0.0 1.0\n", - "34996 1.0 1.0 0.293651 0.737291 1.0 0.0\n", - "34997 0.0 0.0 0.848546 0.552337 0.0 1.0\n", - "34998 1.0 1.0 0.614754 0.859896 1.0 0.0\n", - "34999 1.0 0.0 0.265306 0.843716 0.0 1.0" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "predicted_test = pd.read_csv(predicted_test_data_path)\n", - "predicted_test.tail()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### **Creating the labeled stream**" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "import os \n", - "\n", - "container = os.path.join('/',os.environ['V3IO_HOME'].split('/')[0])\n", - "user = os.environ[\"V3IO_USERNAME\"]\n", - "rel_path = os.getcwd()[6:] + '/artifacts'\n", - "\n", - "base_input_stream = os.path.join(user,rel_path) + \"/inputs_stream\"\n", - "base_output_stream = os.path.join(user,rel_path) + \"/output_stream\"\n", - "input_stream = os.path.join(container,base_input_stream)\n", - "tsdb_path = os.path.join(user,rel_path) + \"/output_tsdb\"\n", - "\n", - "stream_consumer_group = 's2p'" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "import v3io.dataplane\n", - "\n", - "client = v3io.dataplane.Client()\n", - "response = client.stream.create(container = container,\n", - " stream_path=base_input_stream,\n", - " shard_count=1,\n", - " raise_for_status = v3io.dataplane.RaiseForStatus.never)\n", - "response.raise_for_status([409, 204])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### **Importing the function**" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "> 2021-10-26 14:37:45,224 [info] created and saved project function-marketplace\n" - ] - } - ], - "source": [ - "import mlrun\n", - "\n", - "# Importing the function\n", - "mlrun.set_environment(project='function-marketplace')\n", - "\n", - "fn = mlrun.import_function(\"hub://stream_to_parquet:development\")\n", - "fn.apply(mlrun.auto_mount())\n", - "\n", - "fn.add_v3io_stream_trigger(stream_path=input_stream, name='stream', group=stream_consumer_group)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### **Running the function remotely**" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "> 2021-10-26 14:37:45,513 [info] Starting remote function deploy\n", - "2021-10-26 14:37:45 (info) Deploying function\n", - "2021-10-26 14:37:45 (info) Building\n", - "2021-10-26 14:37:45 (info) Staging files and preparing base images\n", - "2021-10-26 14:37:45 (info) Building processor image\n", - "2021-10-26 14:37:47 (info) Build complete\n", - "2021-10-26 14:37:55 (info) Function deploy complete\n", - "> 2021-10-26 14:37:55,689 [info] successfully deployed function: {'internal_invocation_urls': ['nuclio-function-marketplace-stream-to-parquet.default-tenant.svc.cluster.local:8080'], 'external_invocation_urls': ['default-tenant.app.dev39.lab.iguazeng.com:31445']}\n" - ] - }, - { - "data": { - "text/plain": [ - "'http://default-tenant.app.dev39.lab.iguazeng.com:31445'" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import json\n", - "fn.set_envs({'window': 200,\n", - " 'save_to': os.path.join(os.path.join('/User',rel_path), 'inference_pq'),\n", - " 'prediction_col': 'predicted_col',\n", - " 'label_col': 'class',\n", - " 'base_dataset': base_dataset,\n", - " 'results_tsdb_container': container[1:],\n", - " 'results_tsdb_table': tsdb_path,\n", - " 'mount_path': os.path.join(container,user),\n", - " 'mount_remote': container,\n", - " 'artifact_path': os.path.join('/User',rel_path)})\n", - "\n", - "fn.deploy()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### **Testing the function**" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'data': '{\"request\": {\"instances\": [{\"X1\": 0.0, \"X2\": 0.0, \"X3\": 0.0634475073, \"X4\": 0.4136568818, \"class\": 1.0, \"predicted_col\": 1.0}]}, \"resp\": [1], \"when\": \"2021-10-26 14:37:55.864974\", \"model\": \"sklearn.ensemble.RandomForestClassifier\"}'}" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import json\n", - "import datetime\n", - "\n", - "# Reshaping the data to V3IOStream format.\n", - "def restructure_stream_event(context, event):\n", - " instances = [dict()]\n", - " for key in predicted_test.keys():\n", - " if key not in ['when', 'model', 'worker', 'hostname', 'predicted_col']:\n", - " instances[0].update({key: event.pop(key)})\n", - " instances[0].update({key: event.get(key)}) \n", - " event['request'] = {'instances': instances}\n", - " event['resp'] = [int(event.pop('predicted_col'))]\n", - " event['when'] = datetime.datetime.strftime(datetime.datetime.now(), format=\"%Y-%m-%d %H:%M:%S.%f\")\n", - " event['model'] = 'sklearn.ensemble.RandomForestClassifier'\n", - " return event\n", - " \n", - " \n", - "records = json.loads(predicted_test.to_json(orient='records'))\n", - "records = [{'data': json.dumps(restructure_stream_event(context, record))} for record in records]\n", - "\n", - "# showing first record\n", - "records[0]" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [], - "source": [ - "# Pushing some data to the input stream\n", - "step = 500\n", - "for i in range(0,20000,step):\n", - " response = client.stream.put_records(container=container,\n", - " stream_path=base_input_stream, \n", - " records=records[i:i+step])" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
class_shift_helingerclass_shift_kldclass_shift_tvdprior_helingerprior_kldprior_tvdstream
time
2021-10-26 14:38:08.027000+00:000.0017590.0000250.0024881.010.01.0some_stream
2021-10-26 14:38:08.699000+00:000.0017590.0000250.0024881.010.01.0some_stream
2021-10-26 14:38:09.599000+00:000.0017590.0000250.0024881.010.01.0some_stream
2021-10-26 14:38:10.759000+00:000.0017590.0000250.0024881.010.01.0some_stream
2021-10-26 14:38:11.561000+00:000.0017590.0000250.0024881.010.01.0some_stream
........................
2021-10-26 14:39:42.037000+00:000.0017590.0000250.0024881.010.01.0some_stream
2021-10-26 14:39:42.191000+00:000.0017590.0000250.0024881.010.01.0some_stream
2021-10-26 14:39:42.586000+00:000.0017590.0000250.0024881.010.01.0some_stream
2021-10-26 14:39:42.816000+00:000.0017590.0000250.0024881.010.01.0some_stream
2021-10-26 14:39:49.180000+00:000.0017590.0000250.0024881.010.01.0some_stream
\n", - "

99 rows × 7 columns

\n", - "
" - ], - "text/plain": [ - " class_shift_helinger class_shift_kld \\\n", - "time \n", - "2021-10-26 14:38:08.027000+00:00 0.001759 0.000025 \n", - "2021-10-26 14:38:08.699000+00:00 0.001759 0.000025 \n", - "2021-10-26 14:38:09.599000+00:00 0.001759 0.000025 \n", - "2021-10-26 14:38:10.759000+00:00 0.001759 0.000025 \n", - "2021-10-26 14:38:11.561000+00:00 0.001759 0.000025 \n", - "... ... ... \n", - "2021-10-26 14:39:42.037000+00:00 0.001759 0.000025 \n", - "2021-10-26 14:39:42.191000+00:00 0.001759 0.000025 \n", - "2021-10-26 14:39:42.586000+00:00 0.001759 0.000025 \n", - "2021-10-26 14:39:42.816000+00:00 0.001759 0.000025 \n", - "2021-10-26 14:39:49.180000+00:00 0.001759 0.000025 \n", - "\n", - " class_shift_tvd prior_helinger prior_kld \\\n", - "time \n", - "2021-10-26 14:38:08.027000+00:00 0.002488 1.0 10.0 \n", - "2021-10-26 14:38:08.699000+00:00 0.002488 1.0 10.0 \n", - "2021-10-26 14:38:09.599000+00:00 0.002488 1.0 10.0 \n", - "2021-10-26 14:38:10.759000+00:00 0.002488 1.0 10.0 \n", - "2021-10-26 14:38:11.561000+00:00 0.002488 1.0 10.0 \n", - "... ... ... ... \n", - "2021-10-26 14:39:42.037000+00:00 0.002488 1.0 10.0 \n", - "2021-10-26 14:39:42.191000+00:00 0.002488 1.0 10.0 \n", - "2021-10-26 14:39:42.586000+00:00 0.002488 1.0 10.0 \n", - "2021-10-26 14:39:42.816000+00:00 0.002488 1.0 10.0 \n", - "2021-10-26 14:39:49.180000+00:00 0.002488 1.0 10.0 \n", - "\n", - " prior_tvd stream \n", - "time \n", - "2021-10-26 14:38:08.027000+00:00 1.0 some_stream \n", - "2021-10-26 14:38:08.699000+00:00 1.0 some_stream \n", - "2021-10-26 14:38:09.599000+00:00 1.0 some_stream \n", - "2021-10-26 14:38:10.759000+00:00 1.0 some_stream \n", - "2021-10-26 14:38:11.561000+00:00 1.0 some_stream \n", - "... ... ... \n", - "2021-10-26 14:39:42.037000+00:00 1.0 some_stream \n", - "2021-10-26 14:39:42.191000+00:00 1.0 some_stream \n", - "2021-10-26 14:39:42.586000+00:00 1.0 some_stream \n", - "2021-10-26 14:39:42.816000+00:00 1.0 some_stream \n", - "2021-10-26 14:39:49.180000+00:00 1.0 some_stream \n", - "\n", - "[99 rows x 7 columns]" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Reading from TSDB\n", - "import v3io_frames as v3f\n", - "\n", - "v3f_client = v3f.Client(os.environ[\"V3IO_FRAMESD\"],container=container[1:])\n", - "v3f_client.read(backend='tsdb',table=tsdb_path)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "[Back to the top](#Stream-to-Parquet)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "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.7.6" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/stream_to_parquet/stream_to_parquet.py b/stream_to_parquet/stream_to_parquet.py deleted file mode 100644 index 175c12822..000000000 --- a/stream_to_parquet/stream_to_parquet.py +++ /dev/null @@ -1,96 +0,0 @@ -# Copyright 2019 Iguazio -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# Generated by nuclio.export.NuclioExporter - -import os -import pandas as pd -import numpy as np -import json -import datetime -import mlrun - - -def record_to_features(record): - features = record["request"]["instances"][0] - timestamp = record["when"] - prediction = record["resp"] - - record = {"timestamp": timestamp, **features, "predictions": prediction} - - return record - - -def init_context(context): - setattr(context, "batch", []) - setattr(context, "window", int(os.getenv("window", 10))) - setattr(context, "save_to", os.getenv("save_to", "/bigdata/inference_pq/")) - os.makedirs(context.save_to, exist_ok=True) - - mlrun.mlconf.dbpath = mlrun.mlconf.dbpath or "http://mlrun-api:8080" - artifact_path = os.getenv("artifact_path", None) - if artifact_path: - mlrun.mlconf.artifact_path = artifact_path - if "hub_url" in os.environ: - mlrun.mlconf.hub_url = os.environ["hub_url"] - virtual_drift_fn = mlrun.import_function("hub://virtual_drift") - virtual_drift_fn.apply(mlrun.auto_mount()) - setattr(context, "virtual_drift_fn", virtual_drift_fn) - - predictions_col = os.getenv("predictions", None) - label_col = os.getenv("label_col", None) - setattr(context, "base_dataset", os.getenv("base_dataset", "")) - setattr(context, "indexes", json.loads(os.environ.get("indexes", "[]"))) - setattr(context, "predictions_col", predictions_col) - setattr(context, "label_col", label_col) - setattr( - context, "results_tsdb_container", os.getenv("results_tsdb_container", None) - ) - setattr(context, "results_tsdb_table", os.getenv("results_tsdb_table", None)) - - -def handler(context, event): - - context.logger.info(f"Adding {event.body}") - context.batch.append(record_to_features(json.loads(event.body))) - - if len(context.batch) > context.window: - context.logger.info(context.batch[:1]) - context.logger.info(context.indexes) - df = pd.DataFrame(context.batch) - context.logger.info(f"df example: {df.head(1)}") - if context.indexes: - df = df.set_index(context.indexes) - df_path = os.path.join( - context.save_to, - f"{datetime.datetime.now().strftime('%Y-%m-%dT%H:%M:%S')}.pq", - ) - df.to_parquet(df_path,index=False) - - task = mlrun.NewTask( - name="drift_magnitude", - handler="drift_magnitude", - params={ - "label_col": context.label_col, - "prediction_col": context.predictions_col, - "results_tsdb_container": context.results_tsdb_container, - "results_tsdb_table": context.results_tsdb_table, - }, - inputs={"t": context.base_dataset, "u": df_path}, - artifact_path=mlrun.mlconf.artifact_path, - ) - - context.virtual_drift_fn.run(task, watch=False) - - context.batch = [] diff --git a/tf1_serving/function.yaml b/tf1_serving/function.yaml deleted file mode 100644 index e9f9ef904..000000000 --- a/tf1_serving/function.yaml +++ /dev/null @@ -1,48 +0,0 @@ -kind: remote -metadata: - name: tf1-serving - tag: '' - hash: 20cdeb2119a67fc51e55474ac84d386c7b658db3 - project: '' - labels: - author: yaronh - categories: - - model-serving - - machine-learning -spec: - command: '' - args: [] - image: mlrun/mlrun - description: tf1 image classification server - min_replicas: 1 - max_replicas: 4 - env: - - name: MODEL_CLASS - value: TFModel - - name: ENABLE_EXPLAINER - value: false - base_spec: - apiVersion: nuclio.io/v1 - kind: Function - metadata: - name: tf1-serving - labels: {} - annotations: - nuclio.io/generated_by: function generated from /home/kali/functions/tf1_serving/tf1_serving.py - spec: - runtime: python:3.9 - handler: tf1_serving:handler - env: [] - volumes: [] - build: - commands: [] - noBaseImagesPull: true - functionSourceCode: IyBHZW5lcmF0ZWQgYnkgbnVjbGlvLmV4cG9ydC5OdWNsaW9FeHBvcnRlcgoKaW1wb3J0IHdhcm5pbmdzCgp3YXJuaW5ncy5zaW1wbGVmaWx0ZXIoYWN0aW9uPSJpZ25vcmUiLCBjYXRlZ29yeT1GdXR1cmVXYXJuaW5nKQoKaW1wb3J0IGpzb24KaW1wb3J0IG51bXB5IGFzIG5wCmltcG9ydCByZXF1ZXN0cwpmcm9tIHRlbnNvcmZsb3cgaW1wb3J0IGtlcmFzCmZyb20ga2VyYXMubW9kZWxzIGltcG9ydCBsb2FkX21vZGVsCmZyb20ga2VyYXMucHJlcHJvY2Vzc2luZyBpbXBvcnQgaW1hZ2UKZnJvbSBrZXJhcy5wcmVwcm9jZXNzaW5nLmltYWdlIGltcG9ydCBsb2FkX2ltZwpmcm9tIG9zIGltcG9ydCBlbnZpcm9uLCBwYXRoCmZyb20gUElMIGltcG9ydCBJbWFnZQpmcm9tIGlvIGltcG9ydCBCeXRlc0lPCmZyb20gdXJsbGliLnJlcXVlc3QgaW1wb3J0IHVybG9wZW4KaW1wb3J0IG1scnVuCgoKY2xhc3MgVEZNb2RlbChtbHJ1bi5ydW50aW1lcy5NTE1vZGVsU2VydmVyKToKICAgIGRlZiBfX2luaXRfXyhzZWxmLCBuYW1lOiBzdHIsIG1vZGVsX2Rpcjogc3RyKToKICAgICAgICBzdXBlcigpLl9faW5pdF9fKG5hbWUsIG1vZGVsX2RpcikKCiAgICAgICAgc2VsZi5JTUFHRV9XSURUSCA9IGludChlbnZpcm9uLmdldCgiSU1BR0VfV0lEVEgiLCAiMTI4IikpCiAgICAgICAgc2VsZi5JTUFHRV9IRUlHSFQgPSBpbnQoZW52aXJvbi5nZXQoIklNQUdFX0hFSUdIVCIsICIxMjgiKSkKICAgICAgICBzZWxmLmNsYXNzZXMgPSBOb25lCiAgICAgICAgdHJ5OgogICAgICAgICAgICB3aXRoIG9wZW4oZW52aXJvblsiY2xhc3Nlc19tYXAiXSwgInIiKSBhcyBmOgogICAgICAgICAgICAgICAgc2VsZi5jbGFzc2VzID0ganNvbi5sb2FkKGYpCiAgICAgICAgZXhjZXB0OgogICAgICAgICAgICBwYXNzCgogICAgZGVmIGxvYWQoc2VsZik6CiAgICAgICAgbW9kZWxfZmlsZSwgZXh0cmFfZGF0YSA9IHNlbGYuZ2V0X21vZGVsKCIuaDUiKQogICAgICAgIHNlbGYubW9kZWwgPSBsb2FkX21vZGVsKG9wZW4obW9kZWxfZmlsZSwgInJiIikpCgogICAgZGVmIHByZXByb2Nlc3Moc2VsZiwgYm9keSk6CiAgICAgICAgdHJ5OgogICAgICAgICAgICBvdXRwdXQgPSB7Imluc3RhbmNlcyI6IFtdfQogICAgICAgICAgICBpbnN0YW5jZXMgPSBib2R5LmdldCgiaW5zdGFuY2VzIiwgW10pCiAgICAgICAgICAgIGZvciBieXRlX2ltYWdlIGluIGluc3RhbmNlczoKICAgICAgICAgICAgICAgIGltZyA9IEltYWdlLm9wZW4oYnl0ZV9pbWFnZSkKICAgICAgICAgICAgICAgIGltZyA9IGltZy5yZXNpemUoKHNlbGYuSU1BR0VfV0lEVEgsIHNlbGYuSU1BR0VfSEVJR0hUKSkKCiAgICAgICAgICAgICAgICB4ID0gaW1hZ2UuaW1nX3RvX2FycmF5KGltZykKICAgICAgICAgICAgICAgIHggPSBucC5leHBhbmRfZGltcyh4LCBheGlzPTApCiAgICAgICAgICAgICAgICBvdXRwdXRbImluc3RhbmNlcyJdLmFwcGVuZCh4KQoKICAgICAgICAgICAgb3V0cHV0WyJpbnN0YW5jZXMiXSA9IFtucC52c3RhY2sob3V0cHV0WyJpbnN0YW5jZXMiXSldCiAgICAgICAgICAgIHJldHVybiBvdXRwdXQKICAgICAgICBleGNlcHQ6CiAgICAgICAgICAgIHJhaXNlIEV4Y2VwdGlvbihmInJlY2VpdmVkOiB7Ym9keX0iKQoKICAgIGRlZiBwcmVkaWN0KHNlbGYsIGRhdGEpOgogICAgICAgIGltYWdlcyA9IGRhdGEuZ2V0KCJpbnN0YW5jZXMiLCBbXSkKCiAgICAgICAgcHJlZGljdGVkX3Byb2JhYmlsaXR5ID0gc2VsZi5tb2RlbC5wcmVkaWN0KGltYWdlcykKCiAgICAgICAgcmV0dXJuIHByZWRpY3RlZF9wcm9iYWJpbGl0eQoKICAgIGRlZiBwb3N0cHJvY2VzcyhzZWxmLCBwcmVkaWN0ZWRfcHJvYmFiaWxpdHkpOgogICAgICAgIGlmIHNlbGYuY2xhc3NlczoKICAgICAgICAgICAgcHJlZGljdGVkX2NsYXNzZXMgPSBucC5hcm91bmQocHJlZGljdGVkX3Byb2JhYmlsaXR5LCAxKS50b2xpc3QoKVswXQogICAgICAgICAgICBwcmVkaWN0ZWRfcHJvYmFiaWxpdGllcyA9IHByZWRpY3RlZF9wcm9iYWJpbGl0eS50b2xpc3QoKVswXQogICAgICAgICAgICByZXR1cm4gewogICAgICAgICAgICAgICAgInByZWRpY3Rpb24iOiBbCiAgICAgICAgICAgICAgICAgICAgc2VsZi5jbGFzc2VzW3N0cihpbnQoY2xzKSldIGZvciBjbHMgaW4gcHJlZGljdGVkX2NsYXNzZXMKICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICBmJ3tzZWxmLmNsYXNzZXNbIjEiXX0tcHJvYmFiaWxpdHknOiBwcmVkaWN0ZWRfcHJvYmFiaWxpdGllcywKICAgICAgICAgICAgfQogICAgICAgIGVsc2U6CiAgICAgICAgICAgIHJldHVybiBwcmVkaWN0ZWRfcHJvYmFiaWxpdHkudG9saXN0KClbMF0KCmZyb20gbWxydW4ucnVudGltZXMgaW1wb3J0IG51Y2xpb19pbml0X2hvb2sKZGVmIGluaXRfY29udGV4dChjb250ZXh0KToKICAgIG51Y2xpb19pbml0X2hvb2soY29udGV4dCwgZ2xvYmFscygpLCAnc2VydmluZycpCgpkZWYgaGFuZGxlcihjb250ZXh0LCBldmVudCk6CiAgICByZXR1cm4gY29udGV4dC5tbHJ1bl9oYW5kbGVyKGNvbnRleHQsIGV2ZW50KQo= - source: '' - function_kind: serving - build: - commands: [] - code_origin: https://github.com/daniels290813/functions.git#55a79c32be5d233cc11efcf40cd3edbe309bfdef:/home/kali/functions/tf1_serving/tf1_serving.py - default_handler: handler - affinity: null -verbose: false diff --git a/tf1_serving/item.yaml b/tf1_serving/item.yaml deleted file mode 100644 index 6a5648ab0..000000000 --- a/tf1_serving/item.yaml +++ /dev/null @@ -1,28 +0,0 @@ -apiVersion: v1 -categories: -- model-serving -- machine-learning -description: tf1 image classification server -doc: '' -example: tf1_serving.ipynb -generationDate: 2022-08-28:17-25 -hidden: false -icon: '' -labels: - author: yaronh -maintainers: [] -marketplaceType: '' -mlrunVersion: 1.1.0 -name: tf1-serving -platformVersion: 3.5.0 -spec: - env: - ENABLE_EXPLAINER: false - MODEL_CLASS: TFModel - filename: tf1_serving.py - handler: handler - image: mlrun/mlrun - kind: nuclio:serving - requirements: [] -url: '' -version: 1.1.0 diff --git a/tf1_serving/requirements.txt b/tf1_serving/requirements.txt deleted file mode 100644 index 8d3d19557..000000000 --- a/tf1_serving/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -pillow -tensorflow \ No newline at end of file diff --git a/tf1_serving/tf1_serving.ipynb b/tf1_serving/tf1_serving.ipynb deleted file mode 100644 index 1d42ee606..000000000 --- a/tf1_serving/tf1_serving.ipynb +++ /dev/null @@ -1,567 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Image Classification Model - Serving Function\n", - "\n", - "This notebook demonstrates how to deploy a Tensorflow model using MLRun & Nuclio.\n", - "\n", - "**In this notebook you will:**\n", - "* Write a Tensorflow-Model class to load and predict on the incoming data\n", - "* Deploy the model as a serverless function\n", - "* Invoke the serving endpoint with data as:\n", - " * URLs to images hosted on S3\n", - " * Direct image send\n", - " \n", - "**Steps:** \n", - "* [Define Nuclio function](#Define-Nuclio-function) \n", - " * [Install dependencies and set config](#Install-dependencies-and-set-config) \n", - " * [Model serving class](#Model-Serving-Class) \n", - "* [Deploy the serving function to the cluster](#Deploy-the-serving-function-to-the-cluster) \n", - "* [Define test parameters](#Define-test-parameters)\n", - "* [Test the deployed function on the cluster](#Test-the-deployed-function-on-the-cluster)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Define Nuclio Function" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To use the magic commands for deploying this jupyter notebook as a nuclio function we must first import nuclio \n", - "Since we do not want to import nuclio in the actual function, the comment annotation `nuclio: ignore` is used. This marks the cell for nuclio, telling it to ignore the cell's values when building the function." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "# nuclio: ignore\n", - "import nuclio" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Install dependencies and set config\n", - "> Note: Since tensorflow 1.14 is being pulled from the baseimage it is not directly installed as a build command.\n", - "If it is not installed on your system please uninstall and install using the line: `pip install tensorflow==1.14 keras`" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "%nuclio: setting kind to 'nuclio:serving'\n", - "%nuclio: setting 'MODEL_CLASS' environment variable\n", - "%nuclio: setting spec.build.baseImage to 'mlrun/mlrun'\n" - ] - } - ], - "source": [ - "%nuclio config kind=\"nuclio:serving\"\n", - "%nuclio env MODEL_CLASS=TFModel\n", - "\n", - "# tensorflow version 1 requires a different version of python than \n", - "# the default (3.7), so we override the default tag here:\n", - "\n", - "%nuclio config spec.build.baseImage = \"mlrun/mlrun\"" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Since we are using packages which are not surely installed on our baseimage, or want to verify that a specific version of the package will be installed we use the `%nuclio cmd` annotation. \n", - ">`%nuclio cmd` works both locally and during deployment by default, but can be set with `-c` flag to only run the commands while deploying or `-l` to set the variable for the local environment only." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "%%nuclio cmd -c\n", - "pip install tensorflow==1.14 keras==2.3.1 'h5py<3.0.0'\n", - "pip install requests pillow" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Function Code" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "import warnings\n", - "warnings.simplefilter(action=\"ignore\", category=FutureWarning)" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "import json\n", - "import numpy as np\n", - "import requests\n", - "from tensorflow import keras\n", - "from keras.models import load_model\n", - "from keras.preprocessing import image\n", - "from keras.preprocessing.image import load_img\n", - "from os import environ, path\n", - "from PIL import Image\n", - "from io import BytesIO\n", - "from urllib.request import urlopen\n", - "import mlrun" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Model Serving Class" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We define the `TFModel` class which we will use to define data handling and prediction of our model. \n", - "\n", - "The class should consist of:\n", - "* `__init__(name, model_dir)` - Setup the internal parameters\n", - "* `load(self)` - How to load the model and broadcast it's ready for prediction\n", - "* `preprocess(self, body)` - How to handle the incoming event, forming the request to an `{'instances': []}` dictionary as requested by the protocol\n", - "* `predict(self, data)` - Receives and `{'instances': []}` and returns the model's prediction as a list\n", - "* `postprocess(self, data)` - Does any additional processing needed on the predictions." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "class TFModel(mlrun.runtimes.MLModelServer):\n", - " def __init__(self, name: str, model_dir: str):\n", - " super().__init__(name, model_dir)\n", - "\n", - " self.IMAGE_WIDTH = int(environ.get('IMAGE_WIDTH', '128'))\n", - " self.IMAGE_HEIGHT = int(environ.get('IMAGE_HEIGHT', '128'))\n", - " self.classes = None\n", - " try:\n", - " with open(environ['classes_map'], 'r') as f:\n", - " self.classes = json.load(f)\n", - " except:\n", - " pass\n", - " \n", - " def load(self):\n", - " model_file, extra_data = self.get_model('.h5')\n", - " self.model = load_model(open(model_file, 'rb'))\n", - " \n", - " def preprocess(self, body):\n", - " try:\n", - " output = {'instances': []}\n", - " instances = body.get('instances', [])\n", - " for byte_image in instances:\n", - " img = Image.open(byte_image)\n", - " img = img.resize((self.IMAGE_WIDTH, self.IMAGE_HEIGHT))\n", - "\n", - " # Load image\n", - " x = image.img_to_array(img)\n", - " x = np.expand_dims(x, axis=0)\n", - " output['instances'].append(x)\n", - " \n", - " # Format instances list\n", - " output['instances'] = [np.vstack(output['instances'])]\n", - " return output\n", - " except:\n", - " raise Exception(f'received: {body}')\n", - " \n", - "\n", - " def predict(self, data):\n", - " images = data.get('instances', [])\n", - "\n", - " # Predict\n", - " predicted_probability = self.model.predict(images)\n", - "\n", - " # return prediction\n", - " return predicted_probability\n", - " \n", - " def postprocess(self, predicted_probability):\n", - " if self.classes:\n", - " predicted_classes = np.around(predicted_probability, 1).tolist()[0]\n", - " predicted_probabilities = predicted_probability.tolist()[0]\n", - " return {\n", - " 'prediction': [self.classes[str(int(cls))] for cls in predicted_classes], \n", - " f'{self.classes[\"1\"]}-probability': predicted_probabilities\n", - " }\n", - " else:\n", - " return predicted_probability.tolist()[0]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To let our nuclio builder know that our function code ends at this point we will use the comment annotation `nuclio: end-code`. \n", - "\n", - "Any new cell from now on will be treated as if a `nuclio: ignore` comment was set, and will not be added to the funcion." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [], - "source": [ - "# nuclio: end-code" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Test the function locally" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Make sure your local TF / Keras version is the same as pulled in the nuclio image for accurate testing\n", - "\n", - "Set the served models and their file paths using: `SERVING_MODEL_ = `\n", - "\n", - "> Note: this notebook assumes the model and categories are under /User/mlrun/examples/" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "from PIL import Image\n", - "from io import BytesIO\n", - "import matplotlib.pyplot as plt\n", - "import os, requests" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Define test parameters" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Test image:\n" - ] - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "# Testing event\n", - "cat_image_url = 'https://s3.amazonaws.com/iguazio-sample-data/images/catanddog/cat.102.jpg'\n", - "response = requests.get(cat_image_url)\n", - "cat_image = response.content\n", - "img = Image.open(BytesIO(cat_image))\n", - "\n", - "print('Test image:')\n", - "plt.imshow(img)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Define Function specifications" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "from mlrun import mlconf\n", - "import os\n", - "\n", - "# Model Server variables\n", - "model_class = 'TFModel'\n", - "model_name = 'cat_vs_dog_tfv1' # Define for later use in tests\n", - "models = {model_name: os.path.join(mlconf.artifact_path, 'tf1/cats_n_dogs.h5')}\n", - "\n", - "# Specific model variables\n", - "function_envs = {\n", - " 'IMAGE_HEIGHT': 128,\n", - " 'IMAGE_WIDTH': 128,\n", - " 'classes_map': os.path.join(mlconf.artifact_path, 'categories_map.json')\n", - "}" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Deploy the serving function to the cluster" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "from mlrun import new_model_server, mount_v3io" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[mlrun] 2020-05-04 21:22:18,924 function spec saved to path: function.yaml\n" - ] - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Setup the model server function\n", - "fn = new_model_server('tf1-serving', \n", - " model_class=model_class,\n", - " models=models)\n", - "fn.set_envs(function_envs)\n", - "fn.spec.description = \"tf1 image classification server\"\n", - "fn.metadata.categories = ['serving', 'dl']\n", - "fn.metadata.labels = {'author': 'yaronh'}\n", - "fn.export(\"function.yaml\")" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [], - "source": [ - "if \"V3IO_HOME\" in list(os.environ):\n", - " from mlrun import mount_v3io\n", - " fn.apply(mount_v3io())\n", - "else:\n", - " # is you set up mlrun using the instructions at\n", - " # https://github.com/mlrun/mlrun/blob/master/hack/local/README.md\n", - " from mlrun.platforms import mount_pvc\n", - " fn.apply(mount_pvc('nfsvol', 'nfsvol', '/home/joyan/data'))" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[mlrun] 2020-04-30 20:52:15,886 deploy started\n", - "[nuclio] 2020-04-30 20:53:46,385 (info) Build complete\n", - "[nuclio] 2020-04-30 20:53:56,566 (info) Function deploy complete\n", - "[nuclio] 2020-04-30 20:53:56,573 done updating tensorflow-v1-2layers, function address: 3.135.130.246:30961\n" - ] - } - ], - "source": [ - "# Deploy the model server\n", - "addr = fn.deploy(project='cat-and-dog-servers')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Test the deployed function on the cluster" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Test the deployed function (with URL)" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Sending event: {\"data_url\": \"https://s3.amazonaws.com/iguazio-sample-data/images/catanddog/cat.102.jpg\"}\n" - ] - }, - { - "data": { - "text/plain": [ - "b'[0.0]'" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# URL event\n", - "event_body = json.dumps({\"data_url\": cat_image_url})\n", - "print(f'Sending event: {event_body}')\n", - "\n", - "headers = {'Content-type': 'application/json'}\n", - "response = requests.post(url=addr + f'/{model_name}/predict', data=event_body, headers=headers)\n", - "response.content" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Test the deployed function (with Jpeg Image)" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Sending image from https://s3.amazonaws.com/iguazio-sample-data/images/catanddog/cat.102.jpg\n" - ] - }, - { - "data": { - "text/plain": [ - "b'[0.0]'" - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "# URL event\n", - "event_body = cat_image\n", - "print(f'Sending image from {cat_image_url}')\n", - "plt.imshow(img)\n", - "\n", - "headers = {'Content-type': 'image/jpeg'}\n", - "response = requests.post(url=addr + f'/{model_name}/predict/', data=event_body, headers=headers)\n", - "response.content" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "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.7.6" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/tf1_serving/tf1_serving.py b/tf1_serving/tf1_serving.py deleted file mode 100644 index d9816c684..000000000 --- a/tf1_serving/tf1_serving.py +++ /dev/null @@ -1,87 +0,0 @@ -# Copyright 2019 Iguazio -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# Generated by nuclio.export.NuclioExporter - -import warnings - -warnings.simplefilter(action="ignore", category=FutureWarning) - -import json -import numpy as np -import requests -from tensorflow import keras -from keras.models import load_model -from keras.preprocessing import image -from keras.preprocessing.image import load_img -from os import environ, path -from PIL import Image -from io import BytesIO -from urllib.request import urlopen -import mlrun - - -class TFModel(mlrun.runtimes.MLModelServer): - def __init__(self, name: str, model_dir: str): - super().__init__(name, model_dir) - - self.IMAGE_WIDTH = int(environ.get("IMAGE_WIDTH", "128")) - self.IMAGE_HEIGHT = int(environ.get("IMAGE_HEIGHT", "128")) - self.classes = None - try: - with open(environ["classes_map"], "r") as f: - self.classes = json.load(f) - except: - pass - - def load(self): - model_file, extra_data = self.get_model(".h5") - self.model = load_model(open(model_file, "rb")) - - def preprocess(self, body): - try: - output = {"instances": []} - instances = body.get("instances", []) - for byte_image in instances: - img = Image.open(byte_image) - img = img.resize((self.IMAGE_WIDTH, self.IMAGE_HEIGHT)) - - x = image.img_to_array(img) - x = np.expand_dims(x, axis=0) - output["instances"].append(x) - - output["instances"] = [np.vstack(output["instances"])] - return output - except: - raise Exception(f"received: {body}") - - def predict(self, data): - images = data.get("instances", []) - - predicted_probability = self.model.predict(images) - - return predicted_probability - - def postprocess(self, predicted_probability): - if self.classes: - predicted_classes = np.around(predicted_probability, 1).tolist()[0] - predicted_probabilities = predicted_probability.tolist()[0] - return { - "prediction": [ - self.classes[str(int(cls))] for cls in predicted_classes - ], - f'{self.classes["1"]}-probability': predicted_probabilities, - } - else: - return predicted_probability.tolist()[0] diff --git a/tf2_serving_v2/function.yaml b/tf2_serving_v2/function.yaml deleted file mode 100644 index fbe986dce..000000000 --- a/tf2_serving_v2/function.yaml +++ /dev/null @@ -1,45 +0,0 @@ -kind: serving -metadata: - name: tf2-serving-v2 - tag: '' - hash: 8748deb1d9804f9b436c913322c84d5b46c82bd9 - project: '' - labels: - author: yaronh - categories: - - model-serving - - machine-learning -spec: - command: '' - args: [] - image: mlrun/mlrun - description: tf2 image classification server v2 - min_replicas: 1 - max_replicas: 4 - env: [] - base_spec: - apiVersion: nuclio.io/v1 - kind: Function - metadata: - name: tf2-serving-v2 - labels: {} - annotations: - nuclio.io/generated_by: function generated from /home/kali/functions/tf2_serving_v2/tf2_serving_v2.py - spec: - runtime: python:3.9 - handler: tf2_serving_v2:handler - env: [] - volumes: [] - build: - commands: [] - noBaseImagesPull: true - functionSourceCode: IyBDb3B5cmlnaHQgMjAxOSBJZ3VhemlvCiMKIyBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgIkxpY2Vuc2UiKTsKIyB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiMgWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0CiMKIyAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wCiMKIyBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlCiMgZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gIkFTIElTIiBCQVNJUywKIyBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KIyBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kCiMgbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuCiMKIyBHZW5lcmF0ZWQgYnkgbnVjbGlvLmV4cG9ydC5OdWNsaW9FeHBvcnRlcgoKaW1wb3J0IHdhcm5pbmdzCgp3YXJuaW5ncy5zaW1wbGVmaWx0ZXIoYWN0aW9uPSJpZ25vcmUiLCBjYXRlZ29yeT1GdXR1cmVXYXJuaW5nKQoKaW1wb3J0IGpzb24KaW1wb3J0IG51bXB5IGFzIG5wCmltcG9ydCByZXF1ZXN0cwpmcm9tIHRlbnNvcmZsb3cgaW1wb3J0IGtlcmFzCmZyb20gdGVuc29yZmxvdy5rZXJhcy5tb2RlbHMgaW1wb3J0IGxvYWRfbW9kZWwKZnJvbSB0ZW5zb3JmbG93LmtlcmFzLnByZXByb2Nlc3NpbmcgaW1wb3J0IGltYWdlCmZyb20gdGVuc29yZmxvdy5rZXJhcy5wcmVwcm9jZXNzaW5nLmltYWdlIGltcG9ydCBsb2FkX2ltZwpmcm9tIG9zIGltcG9ydCBlbnZpcm9uLCBwYXRoCmZyb20gUElMIGltcG9ydCBJbWFnZQpmcm9tIGlvIGltcG9ydCBCeXRlc0lPCmZyb20gdXJsbGliLnJlcXVlc3QgaW1wb3J0IHVybG9wZW4KaW1wb3J0IG1scnVuCgoKY2xhc3MgVEZNb2RlbChtbHJ1bi5zZXJ2aW5nLlYyTW9kZWxTZXJ2ZXIpOgogICAgZGVmIGxvYWQoc2VsZik6CiAgICAgICAgc2VsZi5JTUFHRV9XSURUSCA9IGludChlbnZpcm9uLmdldCgiSU1BR0VfV0lEVEgiLCAiMTI4IikpCiAgICAgICAgc2VsZi5JTUFHRV9IRUlHSFQgPSBpbnQoZW52aXJvbi5nZXQoIklNQUdFX0hFSUdIVCIsICIxMjgiKSkKCiAgICAgICAgdHJ5OgogICAgICAgICAgICB3aXRoIG9wZW4oZW52aXJvblsiY2xhc3Nlc19tYXAiXSwgInIiKSBhcyBmOgogICAgICAgICAgICAgICAgc2VsZi5jbGFzc2VzID0ganNvbi5sb2FkKGYpCiAgICAgICAgZXhjZXB0OgogICAgICAgICAgICBzZWxmLmNsYXNzZXMgPSBOb25lCgogICAgICAgIG1vZGVsX2ZpbGUsIGV4dHJhX2RhdGEgPSBzZWxmLmdldF9tb2RlbCgiLmg1IikKICAgICAgICBzZWxmLm1vZGVsID0gbG9hZF9tb2RlbChtb2RlbF9maWxlKQoKICAgIGRlZiBwcmVwcm9jZXNzKHNlbGYsIGJvZHksIG9wZXJhdGlvbik6CiAgICAgICAgdHJ5OgogICAgICAgICAgICBvdXRwdXQgPSB7ImlucHV0cyI6IFtdfQogICAgICAgICAgICBpbnB1dHMgPSBib2R5LmdldCgiaW5wdXRzIiwgW10pCiAgICAgICAgICAgIGZvciBieXRlX2ltYWdlIGluIGlucHV0czoKICAgICAgICAgICAgICAgIGltZyA9IEltYWdlLm9wZW4oYnl0ZV9pbWFnZSkKICAgICAgICAgICAgICAgIGltZyA9IGltZy5yZXNpemUoKHNlbGYuSU1BR0VfV0lEVEgsIHNlbGYuSU1BR0VfSEVJR0hUKSkKCiAgICAgICAgICAgICAgICB4ID0gaW1hZ2UuaW1nX3RvX2FycmF5KGltZykKICAgICAgICAgICAgICAgIHggPSBucC5leHBhbmRfZGltcyh4LCBheGlzPTApCiAgICAgICAgICAgICAgICBvdXRwdXRbImlucHV0cyJdLmFwcGVuZCh4KQoKICAgICAgICAgICAgb3V0cHV0WyJpbnB1dHMiXSA9IFtucC52c3RhY2sob3V0cHV0WyJpbnB1dHMiXSldCiAgICAgICAgICAgIHJldHVybiBvdXRwdXQKICAgICAgICBleGNlcHQ6CiAgICAgICAgICAgIHJhaXNlIEV4Y2VwdGlvbihmInJlY2VpdmVkOiB7Ym9keX0iKQoKICAgIGRlZiBwcmVkaWN0KHNlbGYsIGRhdGEpOgogICAgICAgIGltYWdlcyA9IGRhdGEuZ2V0KCJpbnB1dHMiLCBbXSkKCiAgICAgICAgcHJlZGljdGVkX3Byb2JhYmlsaXR5ID0gc2VsZi5tb2RlbC5wcmVkaWN0KGltYWdlcykKCiAgICAgICAgcmV0dXJuIHByZWRpY3RlZF9wcm9iYWJpbGl0eS50b2xpc3QoKVswXQpmcm9tIG1scnVuLnJ1bnRpbWVzIGltcG9ydCBudWNsaW9faW5pdF9ob29rCmRlZiBpbml0X2NvbnRleHQoY29udGV4dCk6CiAgICBudWNsaW9faW5pdF9ob29rKGNvbnRleHQsIGdsb2JhbHMoKSwgJ3NlcnZpbmdfdjInKQoKZGVmIGhhbmRsZXIoY29udGV4dCwgZXZlbnQpOgogICAgcmV0dXJuIGNvbnRleHQubWxydW5faGFuZGxlcihjb250ZXh0LCBldmVudCkK - source: '' - function_kind: serving_v2 - build: - commands: - - python -m pip install requests pillow tensorflow>=2.1 - code_origin: https://github.com/daniels290813/functions.git#55a79c32be5d233cc11efcf40cd3edbe309bfdef:/home/kali/functions/tf2_serving_v2/tf2_serving_v2.py - secret_sources: [] - affinity: null -verbose: false diff --git a/tf2_serving_v2/item.yaml b/tf2_serving_v2/item.yaml deleted file mode 100644 index 72d48b2f0..000000000 --- a/tf2_serving_v2/item.yaml +++ /dev/null @@ -1,28 +0,0 @@ -apiVersion: v1 -categories: -- model-serving -- machine-learning -description: tf2 image classification server v2 -doc: '' -example: tf2_serving_v2.ipynb -generationDate: 2022-08-28:17-25 -hidden: false -icon: '' -labels: - author: yaronh -maintainers: [] -marketplaceType: '' -mlrunVersion: 1.1.0 -name: tf2-serving-v2 -platformVersion: 3.5.0 -spec: - filename: tf2_serving_v2.py - handler: handler - image: mlrun/mlrun - kind: serving - requirements: - - requests - - pillow - - tensorflow>=2.1 -url: '' -version: 1.2.0 diff --git a/tf2_serving_v2/requirements.txt b/tf2_serving_v2/requirements.txt deleted file mode 100644 index 8d3d19557..000000000 --- a/tf2_serving_v2/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -pillow -tensorflow \ No newline at end of file diff --git a/tf2_serving_v2/tf2_serving_v2.ipynb b/tf2_serving_v2/tf2_serving_v2.ipynb deleted file mode 100644 index 6a15b11a4..000000000 --- a/tf2_serving_v2/tf2_serving_v2.ipynb +++ /dev/null @@ -1,545 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Image Classification Model - Serving Function\n", - "\n", - "This notebook demonstrates how to deploy a Tensorflow model using MLRun & Nuclio.\n", - "\n", - "**In this notebook you will:**\n", - "* Write a Tensorflow-Model class to load and predict on the incoming data\n", - "* Deploy the model as a serverless function\n", - "* Invoke the serving endpoint with data as:\n", - " * URLs to images hosted on S3\n", - " * Direct image send\n", - " \n", - "**Steps:** \n", - "* [Define Nuclio function](#Define-Nuclio-function) \n", - " * [Install dependencies and set config](#Install-dependencies-and-set-config) \n", - " * [Model serving class](#Model-Serving-Class) \n", - "* [Deploy the serving function to the cluster](#Deploy-the-serving-function-to-the-cluster) \n", - "* [Define test parameters](#Define-test-parameters)\n", - "* [Test the deployed function on the cluster](#Test-the-deployed-function-on-the-cluster)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Define Nuclio Function" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To use the magic commands for deploying this jupyter notebook as a nuclio function we must first import nuclio \n", - "Since we do not want to import nuclio in the actual function, the comment annotation `nuclio: ignore` is used. This marks the cell for nuclio, telling it to ignore the cell's values when building the function." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The history saving thread hit an unexpected error (DatabaseError('database disk image is malformed')).History will not be written to the database.\n" - ] - } - ], - "source": [ - "# nuclio: ignore\n", - "import nuclio" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Install dependencies and set config\n", - "> Note: Since tensorflow is being pulled from the baseimage it is not directly installed as a build command.\n", - "If it is not installed on your system please uninstall and install using the line: `pip install tensorflow`" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "%nuclio: setting kind to 'serving'\n", - "%nuclio: setting spec.build.baseImage to 'mlrun/mlrun'\n" - ] - } - ], - "source": [ - "%nuclio config kind=\"serving\"\n", - "\n", - "# tensorflow 2 use the default serving image (or the mlrun/ml-models for a faster build)\n", - "\n", - "%nuclio config spec.build.baseImage = \"mlrun/mlrun\"" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Since we are using packages which are not surely installed on our baseimage, or want to verify that a specific version of the package will be installed we use the `%nuclio cmd` annotation. \n", - ">`%nuclio cmd` works both locally and during deployment by default, but can be set with `-c` flag to only run the commands while deploying or `-l` to set the variable for the local environment only." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "%%nuclio cmd -c\n", - "pip install tensorflow>=2.1\n", - "pip install requests pillow" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Function Code" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "import warnings\n", - "warnings.simplefilter(action=\"ignore\", category=FutureWarning)" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "> 2021-01-29 23:47:50,165 [warning] Failed resolving version info. Ignoring and using defaults\n", - "> 2021-01-29 23:47:51,342 [warning] Unable to parse server or client version. Assuming compatible: {'server_version': '0.6.0-rc9', 'client_version': 'unstable'}\n" - ] - } - ], - "source": [ - "import json\n", - "import numpy as np\n", - "import requests\n", - "from tensorflow import keras\n", - "from tensorflow.keras.models import load_model\n", - "from tensorflow.keras.preprocessing import image\n", - "from tensorflow.keras.preprocessing.image import load_img\n", - "from os import environ, path\n", - "from PIL import Image\n", - "from io import BytesIO\n", - "from urllib.request import urlopen\n", - "import mlrun" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Model Serving Class" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We define the `TFModel` class which we will use to define data handling and prediction of our model. \n", - "\n", - "The class should consist of:\n", - "* `__init__(name, model_dir)` - Setup the internal parameters\n", - "* `load(self)` - How to load the model and broadcast it's ready for prediction\n", - "* `preprocess(self, body)` - How to handle the incoming event, forming the request to an `{'instances': []}` dictionary as requested by the protocol\n", - "* `predict(self, data)` - Receives and `{'instances': []}` and returns the model's prediction as a list\n", - "* `postprocess(self, data)` - Does any additional processing needed on the predictions." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "class TFModel(mlrun.serving.V2ModelServer):\n", - "\n", - " def load(self):\n", - " self.IMAGE_WIDTH = int(environ.get('IMAGE_WIDTH', '128'))\n", - " self.IMAGE_HEIGHT = int(environ.get('IMAGE_HEIGHT', '128'))\n", - " \n", - " try:\n", - " with open(environ['classes_map'], 'r') as f:\n", - " self.classes = json.load(f)\n", - " except:\n", - " self.classes = None\n", - " \n", - " model_file, extra_data = self.get_model('.h5')\n", - " self.model = load_model(model_file)\n", - " \n", - " def preprocess(self, body, operation):\n", - " try:\n", - " output = {'inputs': []}\n", - " inputs = body.get('inputs', [])\n", - " for byte_image in inputs:\n", - " img = Image.open(byte_image)\n", - " img = img.resize((self.IMAGE_WIDTH, self.IMAGE_HEIGHT))\n", - "\n", - " # Load image\n", - " x = image.img_to_array(img)\n", - " x = np.expand_dims(x, axis=0)\n", - " output['inputs'].append(x)\n", - " \n", - " # Format inputs list\n", - " output['inputs'] = [np.vstack(output['inputs'])]\n", - " return output\n", - " except:\n", - " raise Exception(f'received: {body}')\n", - " \n", - "\n", - " def predict(self, data):\n", - " images = data.get('inputs', [])\n", - "\n", - " # Predict\n", - " predicted_probability = self.model.predict(images)\n", - "\n", - " # return prediction\n", - " return predicted_probability.tolist()[0]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To let our nuclio builder know that our function code ends at this point we will use the comment annotation `nuclio: end-code`. \n", - "\n", - "Any new cell from now on will be treated as if a `nuclio: ignore` comment was set, and will not be added to the funcion." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "# nuclio: end-code" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Test the function locally" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Make sure your local TF / Keras version is the same as pulled in the nuclio image for accurate testing\n", - "\n", - "Set the served models and their file paths using: `SERVING_MODEL_ = `\n", - "\n", - "> Note: this notebook assumes the model and categories are under /User/mlrun/examples/" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [], - "source": [ - "from PIL import Image\n", - "from io import BytesIO\n", - "import matplotlib.pyplot as plt\n", - "import os" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Define test parameters" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Test image:\n" - ] - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAQUAAAD8CAYAAAB+fLH0AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4yLjEsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+j8jraAAAgAElEQVR4nOy9SYylWZbn9bvDN7/RzNzDY8iMzMqsAXW3uoCmG6k3IARi16tGwAYkpF4g1lBrJKTes6KFkNggYNOClkoMQmLDILXYMDRZ2VkVmRkR7m7mZvbGbx4ui/uda8+CiKpqqgIcya8UCrdnz77h3nPP8D//c65yzvFhfBgfxochQ/9//QAfxofxYbxf44NS+DA+jA/j2figFD6MD+PDeDY+KIUP48P4MJ6ND0rhw/gwPoxn44NS+DA+jA/j2fjelIJS6l9USv2BUuoXSqnf+77u82F8GB/Gn+9Q3wdPQSllgJ8D/zzwFfD3gX/FOfcP/txv9mF8GB/Gn+v4vjyFvwr8wjn3R865DvhPgb/xPd3rw/gwPow/x2G/p+t+Cnx58fNXwF/7ri8XeeaurzbgwLlp/lQBDgdopbHWME2OcRxxzqG0AudAqfnvHNM0Io6PUqC1YZompmlEKY0xBqVgmvw9tDZorRnHyd9rvp7Cf0cphdYa5/xzuMkBDqUU4mEppf1TzvfVWgEqPIvWCqXU/DsdrjmOI9M0hnfVWjE5h0KhjUZexDmYnAP39HzWmIvnmadAfj9/oOb3UFrjpmn+nWJy03xtf8/L6zg3hWf0w4X3H4bx4nMwRqOUZhyHeT6f3lGe3/lLhOV009PcOeevDcqv+fy8MuRW/vt+PSbnmMYJYw1KKYZhJE0S+r4PEoNinh/HOAz+AZRGacM0juGa0+S8jBiDnm/mnH8+kTEvO9PTM84yY4whiizOOfph8J8rjXPT/Hfze4pcKP975nXy31dYa3EOuq4N99Zag1K4aWKaHDayaJkzYBwGL/ZaYea1cvNEh/+HuZhlYP6OPJ+a5eP17bt759wLvjG+L6WgvuWzZ3GKUupvAX8LYLte8W//m/86wzDQ9z3WWpIkwTlHWZZ0XUcURSyXy7BoAGmacjweyfMcpRRv3rwJnzvnsNYyjiN1XQOwWCxIkoSmaQCIogSlDOfzmTiOGceRrusAMMaEZ+26jiRJiKKItm2Zpomu64IwGmOePVsURYDfINZa2rbFWstqtQJgGAaGoaGqKsZxpO97xnEkjmP6vn+mRMCwWPhrx3Ec7q2UwhgTvt+2LeM4kqYpaZpirQ0b/Hg8MgwDWZYxDH4Tr1YrkiShrmuapuFwOITnnaaJKLKsVgVZllGWJdM00TT+meM4pigKuq7jfD5zfX1N3/fEcUwURXRdxzRNxHGM1jq83zRp0jSlLEsOh0OY02EYiOM4zHlkIJoVn9aGrh9o+4GmbWnbDrRhGEestlxtrqjKE8YosjQBN+KmAa0BN9F1DcOkaHq/IZfLJUmS0HVdeOc8z7HW0jQNTdMwTRPX19cMw0BVVUEGqqpCa816vSbP86A4RGacc1RVxTAM5HkelEvXdWEunHNhHbMswxjD6XQKMqm1Rms9y8jAer1+9ndt6xVI0zQkSUIcxxwOB5bLJcYYyrLEOcdisQjy5Jw3pm3bcj6fiaKINE359/79//BX37Z5vy+l8BXwg4ufPwNeX37BOfd3gL8D8KMffOoWiwVd11GWZRDuoii4vr5mt9txOp3Y7/dBcIZhYL/f0zRNmLzlckld12Gh2rYNm2SYNfo0TYzjOE/6hFIG5xxpmoaNFUURRVEwDEO4Xtu2YRMOw4BSiqIoSNOUruvouo5hGIJCE6V2+dk4jpzP5/laXuGlaUocx5Rlyel0Iooi4jjGWosxBuc0p9OJ5XJJ0zRhg+V5zmq14ng8cjqdAIIH0rYtfd/PnpEKgm+M94yapmEcx/BcxhiqquJwOATl6zdPFJSZCHGapuG6dV1jrSWO47BBmqYJn0dR9GT95jW7VPLWWtI0vZQJv8FGsKlFaY2xEVmUMNU1/TCRZpZzWdH3PWmRst/vcW6iKDLiJMWNPU3Tk8Ypxij6oSe2lm4cMMZ7jlVVURQFm82Gsiw5n88YY4IiBcKmj6KIJEmYpondbhcUZNu2NE1DHMcMw4DWOijFOI7JsoymaViv1+z3e9q2RSnFYrHAGBM+y7KMLMsoiiIohiRJOJ/P9H1P3/dEURRkNo5jlsslAPv9Pqx9WZYsFoug+MVgiZLvuo5xHDHGBEP0XeP7Ugp/H/hNpdSPga+Bfxn4V7/ry9M0hY0mgn04HIIlFSEGqOsaYwxpmqKUCpv5dDoFyyMT0Pc90zQ9UyTiDfgJijDGMAwDbdsGS3C5CLLY8mzW2iA8YonFexDN75wL3kGe5+R5HjyUw+EwhxbumcsfxzGr1YqiKLDWXlxXkecFdV2HuWmaJiihruvC5pqmKWxSUSpt25IkSbCE8ty73Y62bcO7xnFMkiRh0/t71BRFQZ7nHA6HZ9ZsHMcgZFVVh1AMHFmWU1U1p1NJFEVorWfB7GmahizLuLm5YRiG8P6itJ1zjA7GyTENA00/oJTmeDzTjyMozeQUaVagjMVqGPoOlFd2iglrY7I8p+9bnANjLEWRoLWmbdvgaV3KyzRNJEnCYrEICjXP86D0jTFhQxtjguWXtRflIfNprd9aURSxWCxI05S+76nrOhgqWSdZW6VU+L7sCWNMMChikB4eHnj58iWvXr3i9evXVFVFXdc451iv18EDHIaBJEnCHtNaB5n4f10pOOcGpdS/BfzXgAH+I+fc//Fd35+mkdPpFIRN3P6+74PFB55pyjiOg5DL5hJXTzZY3/dB0MUD0VqHxTMmoqoaHxvOGnm73ZKmabi23Ge/34dri4IoiiLcw8eZUbiOWMW2bWnbljzPw6I4B1Fk2Gw24d5XV1fBGwCCO3g++9Bns9kAzErFW7vT6RQ2NhAUQpZlQXGJAhElF0URWZYFoVutVkH5ikDJJjFG8/j4yO3tLeBd6KIoQngTRdHsmk5EURwsatM0wULJXDVNM2/OgqurKxaLBQ8PD0EZSBg0TRNKGxyKfhzp+wGnFHXTgdY0TU0/DOS54XB4YL1a0bUdcRLTdS2RVcSRYRgnxnHCOfzzxH7+ZcOdTqfgHSwWi6Dkrq+vg5yI4XHOUdf1s41UFAXL5TIoV8GpxOubpimEWCLTIt/isS0Wi+BNiQFSSoUQROa6770ydc5RFD6kk/uIchvHkePxiHOOzWZDnufh70RGF4sFdV2Hv/mu8X15Cjjnfh/4/T/Nd2WyBAART0A2lSykuGt93wcFsF6vvYWYJ1Z+Lxr7fD4zTVPYlM45siyb7+nIMm8JJZYcxzFoXvEy0jTl5cuXgMcPJMwR70RiO9mAErOJoIsWl3eQ+DBN0znWnoLSkvff7/fzezaACpZJLK+1lq7rWK1WIQYVD0WUkwi3uOryHPKzKA8gYCoinKCw1gR8QoDBzWYTBFDmNUlypslxPlcByDImIo7NLNw5ceyvI96Nd/u9lxBFEdfX1zw+PvL4+Mg4OLJsQdNUpHkBShH3jtPpjEMxOTgcTxijub27w00T2iiur7ZU52PATazVDOOEm70uUdzynufzOWwQ8Y5ub28DvlGWJUCYx0uDoJRiu92SJIl/5tnbEhmRELSqquB5dF1HmqZkWRZCVSC4+yL/4vGJ0hUlIwpkHEceHh44n8/BOEmIKGFNkiRsNhvquuZ0OgVFKPN9CRp/c3xvSuEfZUzfiEe11mRZFgQMCIsiIIvWmtVqRZZlHI/H4L4Bz7wNsYjizmutKctyttoR00TYKDLhl2GGKIaiKABvdcSyiEsmsblsNrGUAkhd4hFieRaLJyskLr3gGTIPAF3nsxiXSkTmQ4YIY9/3nM/noJhEocm7yVyI0GjtPQHwlk/eyc9BT9sOwWLKM4r1F+vpvTQTnkvuK0IsClw2hayhrMHl3IvndDpWDKMjijOU8la/7weO5xKlNE3TYqzFaIWalUTX9TgHbd9jJ4VzI3meoYzBTR6rkNCzKAqSJOF4PD5TCoIBiXWWtZFNLv+epom+7zkej3Rd90zRTtMUgO6Hh4dgmUXZn8/nME/fFhovl8tnSl4UhFznmyGA4DuiQOSZBecSEL6qqgBSernqvnM/vhdKAQhovmwyiW0FW7gE9gQjEI1+dXUVwMRLIEjiRHGhlssl4zgGzZllBUqZILQCel3GzLKYu92OcRxZLpdUVRVc5UtFpLUOIJB4D5eAFBA2Z9u2YaML9iEosSyst6wtxtgAwolQZFn2TDldAkiiMOR3l8r1m0It4ZRsdJmDpqmJoieA0DkX1kNibZ+5aLGmR2lFkRdB8fZ9T9f2DP1I28wCqPzmEeV06VLf39+H+WhbRxQl9MPE6GAYJ7p+pO9HrNWgDaOD6lzRVGcWy4Km7bh99471asE09LPhMGitGOf5EY9HNpQoOpnv1WoVFIJsNsETLvEpMWBiaCREWC6Xz5S8yGKapiRJwnq9pq5r9vt98BgOh0PwzpbLZVAokg4tiiLMy/F4fCaTElKKMpOwUry7w+HAZrMJsh3HccCgJGz7tvFeKAWZRHGBgLAAMgEiTNPFAkv8K0JYVVVwhyV1Ji6UoL/W2jCZUZSgtQ2bRCZX0P2bm5uAAF+md6y1AZSUTSqLKxZShE2UnWhzEczL0EgsjbyvuI7gPQVro7C5xcIIki1WQCyKbHJ5JwGcRNgF7S7LkqqquLq6IkkS2rYNlt8DaB1xnAVFKkpW3ivPc7quo2naZ/FpVVVEUcRnn33G69evQ1gUxzHL1ZKuawO2IWFUFEUcDgdOp5MPaaKUOM04nkusMjRNy+lcUlUNJhoZxpGmbjkedqSJpR86PKdizThOniehFMM0Ehs7b+QnsE0saRRFz+SqKIqgQC/xhMt1XCwWQd4ugVoJTy9TxpfKVrxOwX2AAByKghSlIlb+0lit1+ug0AR/2263GGPCusk6iEyK5yiylec5WZYFg/dd471QCm6OTYEQy8mGEYtrrQ2aF55SixJuXGYFLl05D3CZZzl6SSPVdc1i4UMQuTcQlNP19TXH45HHx8cASEmuXjaKuOIiGLJhBfSR55mmkbZ9CjfG0dL3fXjX1WrFOI4hg1GWZXB1x9G77OJalmUZwgtJfWqtubq6wjkX4nVRLMAzjyJNUxaLBWVZhjkRDOJ4PM4Iuw7KVNxrUbzH45GXL1+yXC69YiIOm6Tve9brdVBacRyx2+2DMhS+hZ+DIcTc8m7jOIJK59x9C6rn7ds7jqcT57ICrajKmmEc6dqGrnUMQ8/kJoa+R2uH0YosibynYAwmMmjl51TkSTa7YDXiFcg6X252MRSXYaV4T6JgJEshnsM0TcHyH49H6rrmzZs3wbDI31x6GsKHkWcB76WJhyByKV6OyFqSJAHjUkqxWq0C2C3YmyiCSw/mu8Z7oRS0NuElgJDrFYsnGAMQNPE0TSF+FssvExVHEZExnM5nMknHtS191xHFMVZr+rbldD5Tl564xDSSpRl11WOtAjewe7zziG+W4CaNGyeWhU9ZNXWDsZphHBi6nsRGWKVxdJxP55C2mqaeqqyYxok4iVkUC4Q5KDiIWA5RVPI75xzWONyMWDP12CgmSyyLfI3SiqEfiAzYKA6urWQXZC6t9Qooz3PiyDL2DUPvSCKLURqmnjQ2MGnaqadrG9IkBZMxTVB2NZGNsCoiiTL65sT5UPrNrw3aTlhAaa+klB7phxrUQNuWFEXCMA5MfePfxSoiC1lmGcYJpQc2Vwv6wVFVLV0Lp1PD/nDCOXjz9g390FPVFWVVMjrPQG3agckpNI727cDjfk/X93z86iMWRYo1CUmcoI0mXWRMZlb4yxxnJsrziW6oWBQ51kazt+S9K1G24kWkaUqe5wETULNS66eRSUHdtZhxINMZSe6t8aQgjb0sn06nQFoSzEA8w8ViETy1uq4DUC1hp4S8wsURYFrSm4JZtG0bMhZt12HjGJskwTPrnaM+nWjmbN53jfdEKaiAhstCBCILPg4XpFVSeKKtgTCh4s51bUtZlmzWa7bbLUVR8MUXXwT3EPxmieaFzfP1U9wVRd56dW1we62NMPrJuiggjr0VFovv4/kOpSGKvIsoaHVVVVR9Rde29LOyE48hy7IgBLe3t8GrkXDHaI2a33GMInDe60jTOceuuzkmfQqzxOO5TAmKEE7TRN/5bE3ZnUmShKurK87nM+PoMwVRZzmfSrp2fApXMm/hszRDKz27ojnTNKKsnw9xn9u2IU0TtFagvLLI4pRIGbquJc1ilquC0U10fYcylslN9MNI0zb0bcRuv+dwOPLmzRu6vmEYR+rGs/XGoWcYemyU0Q8j4zRRNzVdV6OmCQVE1hBZPw/KKvLNgjiJ/UbKMvq+pe8i3ORp02nqler51IbQQt6nrp/4GiEtOY3oQVLMTx6hm2UrmUHh0+kULL1kx8S9b5omGMBLQplgLpfPcAk2ZlkWQhzJnAkeJEqkrCrKh4fAq1AzzqSNIZ7l77vGe6EUpskF4EqQbnHjtNY8PDw8Q4olLhMPYrFYhNis73sUcHV1FRhrct0XL14Ea3xJZ75kLkrsL26hTF7fNzP/309sFGmU1igsbavo+g5j/HeLogjutgiDkFBkk4q7LAoijmO2222gvEpuWZSYCJ6kliSPDd41bLsRhw44g4QFglFIPKqVo5ytndz/0pVer9ez0u2Joyyg9peuv4QJHj+JcfopE3PJ9hP8RbgRbphoWs8zcMz1B1pjTUTTdDTtyPlUsd93PD4+UlUlb9++JS/8BuvalvVmwzD4MCbNUtpuwE0T1mjc5MPJ29u3xJElT1OKYoGyiq7taNue87nky19/ibWazXpNXVXewPQ94zhR10OYM1Gm1trglQaindGBSyJZFfEIhJHrnCOy0bMUtYRuT9hNGxSKhGpiFAUYFH7CZcg6DEO4h6Q3F4tFABGTJAHzlBWSawIh1P6u8V4ohWEYuL29xVrL8XgMpKC3b9+GeF0EW8IKUQJiUYuiCOQM5tjZGMN2uw3km7quQ25+GAY2m00Ad47HI5vNJngfl6k/Y/ScKvTMvSe2mqXrelCeaef/RoV7y7UERMqyjPP5TFmWRBdEH1kwYSVK7hmgnkHEoiiekZSAYLX6vsdhAigqqS7ZlJc1CZdsyaurK6Io4nw+h+8K5nJ1dUWaFDw+PgagVGJfmZuQ2o004+TrJYyxxHFC348hNWstHhcBUJp+GGi7niT1QG/Xjzigqhoed0du3+6oqoY3b17PnpSPu682nuBV1SWME5GxpAufLZlG7z12TcN+fwDnWXNpkrLerhhmTCWOE47HE9vNGqV8UdfQt4zjAPifxfAI+3G5XIYMgXyeRDF56nGqrmkxStE7GPseDSjniIwFOwZGq8z/OI7ek91snhHuJFUqSkYUziWv5ZKkJ0pCMkMicwKCX2+3gS5t59BaFF3/x4QQ74VSgCeqs4BZMjkCRAkFWHLfQlCSTIBY+CiKSGdrdj6fgyJ4fHykbdtAQhKrKKMsy0BWEc/i008/RWvN27dvGIbOp7fGHufG2XrUF2yxKwAfE88ehqT3BBmOoojT6RRCo2EYQoGOKAeh2YrWn2ayjzA0BUi6zKFnWQbKUlZ1yMVfIugCWOZ5TpbGRFYHVPqyNuF4PNK2Lev1OmRbBOUWOrlwOQQYU1pRxAXGKMZxYhy7kOmQ9Twejx7onb04ZUCfz9g4JssLTucWo2PK6sjt7QP7/SlQojebDW1bM3Q9280GrRXHfce6WOCUIkpTtPL1Id3kQsVjWZb88suv0CbiN376Y1599pLBzrT1KEbh2O0Ovmiq7XDOez1iReUdRcbEc7TWst1uqZuGZvYucY62aXGxI008L6TvvJJiVrZCOxdFLt6opCWdc1xfXwd5FAUgKWwBhb/JstT6qUDrEoObpolpHHFzODWNI+0Muv9xFGd4T5SCCLekVwQYk7FcLomiiLquKcsyxFeSlpSJAu+6d20bGGuST5ZUobi+l4w2IRzJvfq+53Q68fbtW1ar1Uy1rgPNN4qiUNAirn+e57NrXwVQr21b9vsn5H2xWIRCK6cUh8MheEaXRUYy0jSlWCwoZqVSlmWwKKJEQtbFxD6fP6fDBLyUasTAaXC+UlDqGc7nc4hR5f/+GRQ4EwRNvBX5d1mWAb/out6XIGtF1/U+xNIaa2P6vmMYJk6nM3E8M+lGR9P2PO4OoA1ZvmAYFH0/cf+wZ5pgsVzyuHvwsqENRZajnGNoBxIbkSUpURwzTCNd37PIM4wCN83emjVUZc0Xv/wVTsPVyy3G2DlDNNC1LVV5whofvogMdd30jAkrALhYXMGt7PzuVVmyXCyelagLBtRfhKhCYBOFKRkdr/TaEGJK1argA5ebXHgo4glIxkOMqHiQPnzs6fsONw1M44DREctFQVmVRFaTptl37sf3Ril89NFHlGUZSqe/LfYSt0pcYSHsSFpHqt3i2ZuQ2FuYXSLMl6XZdV1TVZVH5udFkDSUEKfO5xNNU8+bvwjXjKKYOI6COyhZlOPxyP39fXD3tfaW7JLnoI0vt5baCEmZijUKYcWcTRDaqoQHomhCyDD5KsJLctIlaCsYgNYWowhkL1EsElKIgC6KBXnu3Vnh0EvV6WU1YNd1HoGfJsbRhazHYrEM+INSekbVE/qxm/kgI3QDZXUmjnuMzfijP/o1Xe/I0oR+6Fmt1r6oLFsTaYPGM0pXxYLNek3Xd7S9I84ylNYMfU+R+dT2qSxxDuq64Ve/+jXFKuPF9Q1FkZPEXglExqA19F1HEkdzaDiFGP1SEQoHQGRmmLMBsmlFviTe72euwSXwe8lfGYaB+/v7IMOSDpaQU2p+BDwWr3e5XIb1yrIspIXFaAo2BoosS1gul5RlOV+7J57xHSnj/7bxnigFFejKAgheVgPKRhItKyQX2VQS70lKcoBnfyOxFBCUziUB6nA4hPhMricx+TA3tUiSbI75YRhGrE1m5ZWjUDRNT9t6AE9AoUsOwSUTs2ka9OySyqa9pDmLFZmmiW4OGYSHIKlY8aaEyOIA58bwHt+ck4eHhxngLFBuDNeXyj8p+JEwzIdATSjgAcJmkZBFuCXHc8luv6NtfJwaJzF5VqC1Yr87UJYVWZqxXK1ou4Z+6Gm7jvJ4xJiEmxcf8Q9//kuStGCaHrl+8ZLj4ZHVekXfdmzWa/I05f7tG9I4YZHlpHHCerXgXHu3+lzWKAer5RIHtP1A1/UM40hZ1rx+/ZYi8+uyWa9IEzxIOo2M40RZ1rNRIIRJApqu12vSNA0g4jAMvLu9w2qNc9DblgZF17WMg5+fxEYweqWyvboKIe6lVyqZC5FVAQIvy+llvsWT+SavQTxCqcgVXKprG6ax57B7IMsyrjZrjscDE440tmRp/J378b1QCtOsfcHXsS8WixBniSadpokXL16QJAmn04lPP/0U5xxfffVVcJHF0vftE2tO6tovyRuXfIDNZhMq9oTqKtZXrOc4TsRRyjhAO3nUP1/nlGVJU/fBXTcmJkl8mvGyIAkIKHzo9zCnp4RNKMQTIdYI3TlJEnBP3H0RShHYpwYeNpBhgIBSSwwp3/Nx/RQqTzebDXEch3BMuPKPj7vgRYkChSewVhRPMdfwy30k/XZZlOYm/x5xmmAiizaK4+lEuz/SDwP7/Ylf/OEXZPmGNC2Ioph+6Nksl0TLFatFgRtHPn71MX3XkkYR282WbmxJxxjiGDd5L0WbiAnYrrfsTyemqsZY38jkcDiyXq+IosT3J1IaayOsjairCmOmADReepaPj4/PQF5jDGmSMI1TwLFwjnF4qsIVoHAcpyBP0i9DUouXGTSZXwlZFosF19fXz0hqsmYy1xLOSPGc3NPjV4a2LhnH4ZlHKAo9et+zD8453r59G9I/oqUFCRcBvyRniMYV5p7WOpBO1ut1oIrK9WRI3vmyLkAyGcId/yalN0kShn5imkAp3xcgjkeyLA+hQ9eV87VUsPbyvAIYiSu+2WxQM/gnRTJSBi2uudz7dDqhleJqtjYSy18qDa01KI2ZFYN4GhIXi3sr2YUi9wDoN+vwhQa7WCxYLla8fn0bnl3CBaGPC/BYVxVp5tmfTwzMMTz7OI4XhWEdw+i7EiltsMaQL9b8nz/7Geey5nd+53cxOgHd8fLlS7SDNI5ZLBYs0pS2rhi6nmlOISZJhCOdLawiihNG570EbSKiJKVpW6q6pCrPfPHFF/z4xz/mpz/5DYzWpElMnvneBicbkSQx0UwCE0p4URS8ffuW0+nE1ZUHkyW1eAnSitcpcisclKr1PTQE+7mkP4sREzxNiGfSD8G554VclzjDpQyLwWtnfg54nkYceYUjoYisi/zdd433QilY4+sRjscjfd/z7t27kGYU90hAFfmOpCulUlIQf1mYy1TNdrsNuXsZogjE8orLLJMdRVEoS66qGmMjpmnAGsvEyPHsF7ooCrLCcyymccLaBKMtSexjUGsNfd+htaFtK5zrAeMBMRdTns8M/UCRp6wWhU9tDr4yMoojmDGO7XbL8XgMHAapMRDLMIw9bhxQ2ruim+2KceqJZnAvjmPqqkYrAroOTz0DpclMqEvAkRUF1po5y2DoxwETWdL8KSYVJVre+c4/i2URrKNjomkbbm5ufNuwumFZLLFacz6cWGcL+rYnMREvrl9wPJ1xxqINLLOUoWl4eX3NDz9+xeuvvqRvGnAjJlakWUSW50zHCa19eJOnKX0/0LYdLS0qtrDMedjD211DW3VU54ZxND50UIaqaWjrM7F1aNexWl2R5xn39w+kaQSMZFlMHBus1bRtg3OeEyDzJ/iWKF1REJvNhmoGDq21rBZLwPHu3T2RjWByJFHM6XRkgqAwJIwVeQZCZbBwT8QwinEUT1AM6jhNNO3EhMaamGLhM1/9ONB0A+3j4bv345/Xxv6zDGM0n3zyCev1muPxGBqaCFBWFEUA6g6HQyghFvdYyB9iwaY53jLGhHBAylxlI0s14/l8DmQP0eSCXex2u4AKM82dlyLDOA2zq6pAOWxksINhUL5Rp5rd0rbzrp1S/h2H0a5uZAgAACAASURBVG8UbeyMdDd0XUtdNTNu4YVaa0MSp1RlNZOiTECcV6tVUGjC2S/L0mMU1mCsJp7bqEWxpW2bOS2pub65Ik0ShrYL4GogFs0kGAFrp8mBAmMtahhQWs3FRsZ3VZ2BrnGaaGdST1VVF/UEal6PBHD0fcc4Qdv2tNPANPpipZ//4R9SNgOr5Q1oTVbkRJHjdNjxkx/+iI9fXvPrX/yCsWtJ4pi2LbE2IslihnFgvd54l7yq6duWMRrI45jjNFLOhCM9DCzSguP5xPlcsd8fWK2WaANtfcCqiSw2VF1Lki+IY4u1vimt1orr66uA46TpinGcGNqn7lkSLklfD+E1iPf3zdL5yFqSOeVrtKZtWqqm9tmUeV2ltkIpFWpqJFQQb0K8OjEUAnIKjwdAKUOc+PoLlCbPFzinOM0Etm8b74VSEEKQuFJFUVAUBb/5m7/J8Xjk7du3Ie8ucbpMnFCRBQk/HA708yKIGwaEybvUtKIIhMwkE3uZ/YC5R8CczhTyStM0z/r7FUXBcrGkrVt2ux3n8sQw9Dg3EccRUWRJo5RxfCpD1lpzc33NMTpzPpdIlBPPDTratsUxhfcSF1LSmhJeaa3R1vKwe3yiwqYpH796xVdffx1AxM3MVjzMBVPidoogCa+i73varifLl8/CL+HpS/9CqcAUZSCUXkHlLzv/OOeoBkeeZ7hhoC4rXJrx8PjI7bs9/9hfekESxzzcvqNrT3z+g0/JspT//X/939gUGSqyNGWDjSKKRTFjL4qb6xfUdU0cRdRlxdD3TKPP0Q8zrhNFjkXkN9w0Dnz99Vc0zTXX1xu0sRRZjGGkH7whuCRpCZVYeAKBfj/qIEcif2KcZH6kL4a0oJMemEAoPAvl0oCem9qItyshhBi7SyaukKpkXYTkJyQ+8bYFJJZ0qHgyItvfNt4LpeDcU2NJiamttXz11Vd0XcfNzU1I9YkQi6CJovDcfV9lmCaJ78YzI++XsbdoU4mn5VpCRZVYUGrf+74nSX1sKlpasglCIpFqR+ccifXu3zD2WGvmEuPWK6u+A/WkEPwiLlBosizldDozDN4dFhpzkkR0fRfuIZ9L3z9J107OEVuPRfStL8rSWgcXtes6Xn/92j/j/K5AoO5KeCXvVJUlddOH1KXMTZqmITU6DEOYD0HXBVATBSrKa5omojhBOUeeF2RJyu3bW97dP+KU8V7i+cQnrz7iiy92/LV/6p/g9//e3+PHn33G490tQ+tDh812zWa7xc6bSzgA2fxcCl8v8jgDtOM40nQ9UaS5udqirOX2zVvquibPU662C5wb6YeBoR+py0PwCqQobblcstlsaJomNE5Jowxro5AalEyTbDaplxD5u6Q5eyD3MeBRWZZh44jJPTWKFY9WmKSCt0n68XQ6hUyDAJCX2IPQ3cWDk1IAqc78/4FScIHaK5tMOAZSHi3luDKpwmkQwZSX7vueaRiIZzBHYrNLltol2CMMNcElpmlivV4/IzdlWcZipkPL80j6RykVYjrgol/BicfdI4fDnjzPqKqSpq2x9qkRp3OOw/5InhfkuXQ+cvQztjFNE23XYO1T41lBqaVNunRpbtrWA3d5Htz5JI559eoVVVkSzy5llqa0F9x5UbJ5ngdFmaYp1zeWyXnlJaW2onyFRCbzKEVd2+02hCEyj8LB6PueEYjimDhOqM4VX379hn6cePXxpygFWZry5uuv+Mt/8S/wxT/8OR/dXLN/fIBposhzuq6m7zvO55KJCWsiSl3NGYCYZVFgtMFNvozaSirv7VuOVUU/jiRZxuF4pGlq1qsFi+JzEqtYLldMbqLuvFsdzwBnVVU8PDw8a8Xmra4O3hA8pTElpBCleNkNXDa8rKOkIdfrtS/qapvwXcHOBFi8TK9vt9vANhUsTTJsopCB0PNTDKF4GuLRfNd4P5QCBLdNhGy73bLb7cKkX2pFIeIAAeEWF26xWDAOAw/39wGoFJbeZessIDDLpEpN2o8LliDNLeI4ZpyRYVl0ASGl7wH4zMb+sCeOYtIsYzks0Vrx6tXLuR33kf1h9yz9p6O5S1HXMgwjbdvTm4Gq8gsZxZYoss/iTFF0cl9RoEopxjgmmj+Xis+6qkjimPVyyc3NDafTibu7u6AE5Xkui8PsnBYTZFxCAcloXHIc4KkvoXgzm80mrFnoZzGOFIsFp9OZx92B23cP5IsVcZKRJClJ4kle29WCX//yF+wfHtguVxBFdG1N2zSM48DpfGZyI3GUsCh8SnS5WJDGia950Bq2W6KZy7FZrTz6Po0wjsTWsjse+frrr1ktc642S4o8JY5T0nQI4ZIAz13XhbShGAOr4rDBZC2kFucytAWeVTXKMQRyD2lyM82HuAhT9nJdLolq0zSF4sCHh4egqKTkOs/zEDJfcn1k3URehCvxbeP9UApzbhaeDtSQw1UuhU0stUz+ZWNNwQv6vp+bbeiAzEpO9zIHLI1QRLOKGyoNT2QzrFYrtDGMs+aXOFNaXQnJJEkSutZvsp6efujmzePQ2vDixQuKRc44DYG04htuGpq6nd1PsLbDGAtu7pgcW7R+3r2nruvQqESwGBGyvusx1p961NQe+FoUBeMwsHvc8eWXXwbSkQifuLGXVNk0SUNRVnLhdUmsfJndAUL4IesitGo5i2C9XlOejxyOJ06nMz//h7/g9eu3fPTJZ7y+veOv/dN/nYf7e37yo8/ZP94ztC1XmzXV6UR1PFHkOcvVkn4+kcpEEeOMqfi43oeHisuTs3wG68XNDV3XUAwT6XJJP4ygFGM/UlcNVRzx9ddv0AqKZfEMqLu6unpWaJbnucdMep41KxHPDwjcAwntpLtTwH9mfsww+PNKjDEkWcrheAxhiMjkZRpROnULhiMH8UgXrEvjJPe6DHMvM3CisL5tvBdKAVRwNaVi8bI1mGAAkn8XxSANJyRXHPr4a008x11AEF6xhk8NR13gKch5C7JRhLhyd3eHA1azxyAhRVVVzyouBVzKYh+GPO4eUAoWi4Kq8qHO5MbgDoLEgJYoimfhG4giPwdaeXdRG0WWpcHbEcBRlIR4Kr7gpaU6l8+s13q9piqrUDdRVmUAxwTHkdp+qeMYx5Fo5iTIvEpc/cTydLx+/TqEdlJeLJyGaXqqwxAXOjKOIs948/Ydh8OROM/phomf/PSnKK04ziDx1Spmu1lweHikPB6ItJlLoydWyyWrqy1lXZFEccAx6rpGOcdquWLOUGKMP6shsgbcwP5w4lg3WKN9Lw03sd/tyfMUlURoa8Laixd5SSzSWocmK1lcBGN1SYiTWgmhrUsxlSgMmQv57M2bN3MKecvxfArhKhCqhS97Sgq3Bbz3fH19HfaFZI/E+Ikiu+S9SMj93vMUhsFzExaLRYiD2rYN/QFFqwmIYq3ldDqFsmCJ80UgrTGM84KkaUpVVaFtmnMuEICEtSYpPlEe9/f3obHm+XwmimMeHx+D+yyVigJ8CpFnGAbKo7e4282Wc+m77RwOR/yZiyNt98Su9GQUT2h6/fo16/V2VjJPrb/bqkFrFdKokh0R4PFwOPDJJ5+wWCyZxqcW8uL1yLNKvDnOZ2yIJYHnZyiKwi3LkrJqgzKVU6qko9R2u+Xm5ibgGjKPArZJ8ZkoEQCsQ2nLuSypm4a6bllvPAPx9evXNE3Di+srjvs77u++ZvfwSBYn5FlBlqZoK3005mMAshSj/WY4ugNMDqMNyax45Zms0awXBeMw8bA/kCYJVzc3PB72vHnzlixL+OEPPiVOIsCFNLUoAfm3EMCyLCNP8gCwCr4ia3ZJL5cNLCDfZU9RIDB3f/3VV+RFHkIUMXiirEVZXCpz+b2sm5w+JqG0zIGEyHJ/IUp91/gzKQWl1C+BEzACg3PuryilroD/DPgR8EvgX3LO7f7Y60ip5/ySl+lCYXlJquab2Qdx8yWmG4aBPE3Zz30IHh8fQ9oHnhBaidMEYxCFIhx3wTdkgzXzEW9SAy/AojxvVVUM/cBqsfJ1DlZD6bES58b52YcQY4t18acaSSeeGqX8eyRxNm9GbyUkuyJpJ1FCsvFxPstQa8M4jeRpRhontHXDXbDUflN1Qx/mGJ6ou0CwcsZYhpFnyPnd3R3As7ZkWvs28fJOApxZa8NZjcKoa+mZnA/bFssl0bEmzQs+/vgTxq6jWBTsdo+U+zse7++xxs6Zk5Zh6FlvrryljCJU21E3LcWcHUlm13qaxgCsBW8Qh9VemS2XC45Vg1aavvPzutvv+eEPPps5JuqZhyBovQDP0nGqa54YsxIiSer4EtQWxSuMQvnMWht6KSqlwpoIN0fwM1Gsssmrqgrhg4TN0udTPDPZN+JZSBgDhErdy2rcb44/D0/hn3XO3V/8/HvAf+ec+9tKqd+bf/53/rgLJHHMp5988pRNmGvJ4zim7zrMPIl1XYVNZY2maxvqqgzutDEGo5XvwTiXL8thGGLNxbXyTEnHND3lbqdpnN3GmKoqAUeaJnR9RzETSJI45mq7Zb/fh5ZuUiZb1zVZWtANI6fdbi4bHlAaHncnJjeRpl5rK6YZHc+JbDSHKvdBMD799DOurrZo7cgLn2F4eHhgHAeM0eR5htaKKLKAo+0aoiTCKU86SrIk5NclJx5FEcZaaKBrG86noz8ncowuwhqHVnEI3ZTyh550XRcO8BUMImRzGINSrduK4wEiGzH0PXmWE+W5J89oAMdXv/6SOF1RpAVXqw1j19M1NV1T0tYnhq7H5kvGvufY+HRjaiJu7+/Zn04+n59lLIsl2IxlumSzXBNZS1WWKOf7WsbaEMeWaepJigybJTR9Q91UnPf3JFaRJgl1M3D7cCJJY65XCdc3V3Njl5a6rnAu9sxQDEW+ROuIpj1RzR5nmiUkaUySRLStZBtqqrrC2pgkTgL5SLAzUaJinFarNZN7OudUPAj5jmTbxsHzL+JkPry360IadpEX86niUJUlk3PPWhxKilVSld81vo/w4W8A/8z87/8Y+O/5E5TCOIwc5xbf4vL3fY9WyjO/uo5xGKirMhTo+L/rw2b25aqOPEvDz8fjEeCZZRYvwbe6Hqiqcqb2+uvI8fD+qPGJuq58w9coJrKWoe9p6tqXNKep7ybkfHOPJElohwHqmlM5FxJF3tvIiqdDUrQxpNFcOBPJmZg5XTcEywyO0/mI0mr2IBR939F1Lff37wIbcb32dOOu80enaasZuoH9cU8/ehd1sVoE65XECZE1TFMWSqHbtmX3+BAKtJq6oh8nnPZH9HW9rzY087wJyOlJXDVDW9P3HuNZLXO0nsVqmhj6js3mimkYgYZ/8LOf87jbUSwjfvL5b2C1patrqvLI+fjAx6+u2O0GTJR45l8UE0WWsevYnU5UTUuaJKhJoTrF1eIGNWkebv3zx5FnIzLN4Gff0/YNIxGgSGNDFimG3ocWcRRxd//A6uYTlhgy2xEfK/IiJY5nVmjXkMQZRbHAmJjTsSLPE+LYBGss87jsiqdqUlswjSqEXOK5yDxLJe0wDKS5L/+W0FnK4y894SzL6FrfXUoo7qHWIYqIZ6/Dh2wGHT2dqyF9OKTHyB/XaOXPqhQc8N8opRzwHzh/kvRHzrk3fq+4N0qpl9/2h+riKPqbqw273S6g6hIHNU3DarUKWnO9Xj6bMHHFLnEBT99dhDhamI2ipSWW9u738y444nIK/iDx2jS54KZfX19TFEVIX3700UdkWcbPfvYzyrJCRwlJkgYN3fdP7cujOUV4PB5mprAKjEhpjSbsQpBzAZ6OOQ/KcMZQhANwWQq+Xq999ebsVobWamk69xlsydIsgLKCoEtZdiiYGSccPv11Pp+5uroKc+7Pe2g8e9A5lNIhZs2ynPV6w35/mMOsnjT1HtvkGn71qy/ph54otozTQFt2fPbpx+x3d1hjePvmLadzCcw9FCcoipyr7RUfvfqUcfC9FKMkYbXeUnUNQzWwWS15+ckrkijidDxSjWeUtURGM2mHtZq+70iSlJubF3RvbzlWDUkcE3cj+90jL1/cYIzjcDhQNyVX1+sAMspanseSum7AqSBfl99ZLpfPNl/dd9T1OXxXMgCHwyHInmRQ5LTv+/t79vt9CAfkO3meo5XCzfIv3ZnEi7gsv4/jmCTPQgczkd8kSQJl/rvGn1Up/HXn3Ot54/+3Sqmf/Wn/0F0cRf/TH//QycaU7IJ0bxavQeIviatEqIVdJ/GX/FtASGEyCmtRznwQd87TkONnlWPW2mfYgS9MycJJv5eHfV6m89brNTZOqeuGafKbxxrFNPbgNCaJyLIExZLq/EROkXy+HPB6f38f8stK+U7Jl8fAi7BI3ChIswja5bxdNvmA+SBXFKfTKbAi3717B/gsg5QNa2MZnO8OdT6dWK+WbNaeVuuzHnVQQtNQ8/Dgj5+LoucZHH/8nO+2/frtV9w/7Oj7kU8//YSf/cEX5NmCP/iDn8HU8vDuDbH1Z0IeDkcME1lReGWrDE5pUJaXn7wCYJwmdqcTKFhtN9RDD8aQrZaYNEbNstKNIwxeeeVZgXOKKHrkarMln6AdHyjShP3jA+uPtyHtezppsizh+vqavhup645p7CiKBXW9Dwbq8fExcFcEC5NUosT4EhpfnosqYLP3dt2zngvieYiHIPJ6Kcey9pf8GfE+bOSzQbKPhGsitTPfW/jgnHs9//9OKfV3gb8K3CqlPp69hI+Buz/pOpIiEwspZBwgpNyGYWC/3wdXKE1Tbm5uWK/X3N/fh7TgZa58tVoFNxeewogkSSiKgsNhz+GwD+kzsZSSx3/qYfgEwklKaTs3xZTFEAQ+z3PsbBEOxwO+IYsNKPzQ+yPJbm5eMAx9uIcc4bZYLJ49d9+3ARSSdwtFWhAIWeDz0wKKyTsK8nzZq6E8+bTVfr/n6uoqPLtgMzCfXRklc2r2zH6/49WrV0ExT+PIpGZMwyShXsXaiLr2523iFM4R8uhdP9F2A+vNds6c7Nis11T1maGrWS0XvLje4saBx67hsHukqRs22xtMFJOkBdpErK9ecC4r6vJIsVn7TMc0cihLlPFZgvXyGtyIOxh6NzA2HmCOE8/+LLKM/fEdzeiItOLd3S11VbGIJ9IsJs8TFARqs0IzjjrwR+q6DpmJPM/DHIpMyHx6JWsDLiBertCMBUSuW9/GXsKL0KcBgmHzhXk+VJWQRMhL0hNDfpYMloQJUk8hHsulofjm+H+sFJRSBaCdc6f53/8C8O8C/yXwrwF/e/7/f/EnXctNT/0LJe8shBzhbUs65ZJjLkIsn0layJfuesKQMYbj8RhoozIpsnDS3gp4xlsQdN27h0/Hjo3jGFrOf/7556E4SUBNay116Ss6rVYs1yuM0UEY7u7uAivucDiEqk8B9YRGLEfO53ka2INd1z3r7ychwmazCUIjnoEIisyh9KWIo4h+Ruol1bvdblkul9ze3oaejUYrtHKMfcsiz0hjS9dUWFMQGf+7pi6pziecG/joo48wxvDu3T3WemGW9nVuPg5+tz9xLlt+97f/En/4R7+i7zseHt9xvd3Qli3bm1eM/cDjwzs22w1FscTYmDhNQRt+46e/yYRmnODzlx+zXuUY47DGotzkW42lCUnsz8YozycWDn8IbVszjQNaQTeHklZrpqYhjSJMFDONvkXadrsmTX0pfVV7o7QoVsRxRmR9Cnl7dRU4GOIFyHxLuHo4HFB4HoqEAcIMffnyJUmScD6f/SG/ShElccBsxDOQDSzyPvQ9fdsFfogQmiQ7J3hB27UhWyZA+m6343A4hL/5rvFn8RQ+Av7uvBEt8J845/4rpdTfB/5zpdS/Afwa+Jt/0oUkJpbCjzRNQ3+Dp82RhwNGpIONcPUvmVziVYj1lRhY3C5hp/nFqYnjKNQPyMYULoB4FVmWU1XeWotyEXKTLKyUey+Xi/Bscl9JbSnlPR9ZTKkVkGcU/oBkTlar1RyGtKFAR7ABINQrXBJugGchkmAB0kVpvV6Tpb5iT7wMQbkv60QcT8w48XyEGpvnWajE83NgA47Rth3GDEyTozxXgC+53u12vLvf4TAkScrhsGeYPGbStTUvb26Io4g3X73lo49f4hxkRcGLlx9jowSUZbFckecLkjRjudoQWQ34/H95PnP3+g192/DyxQ3WapQCbS3jNMHknwOtiKKYRb7gxfU1++MvyRcrdqeSru94bAd/glVsGMYErfm/tdLruh6j+2CcZA1k/sS4VVWFwgaPQWRT1k/CCV/laoguKPnCtL26ugoGQMIQWV/BwKS/xmW3rzTNQKtAoLrkpVzyJL51P/5pNcA3h3Puj4C//C2fPwD/3D/StXg6YUespaS7pMtQlmVcXW1CM1VpiimLIg1CvDV3vHjxguPxGDaLdNERj0Nq4KVASYqxpAbjMmbbbrfEcfIMc1BKcXt7G4AerxQcdekr7IyC2BriOApCc319TWwtQ9eymgFKKamVTIlscGAWkCrU5wslVjwDgNvb22cbVipMpQWbhFHjOHJ9fc16vaGZPRo5ZFb6TYinIR2oA2BV5KFrcNfUrBYFm9WSpirRynsaURQHzoa3VgPT6Gjbhjj2hVf94Jic5vWbW05VSV5kKOM4Hvesi4w3X39NkRUMk+LHP/kp9w8PdMPED3/jh3z+45/ApLi7u+d0PPDu7h2TG6mq0qeltWa5XJAlMV3fo3WC0WpO8U0oB1pZxrGfOS744qlx5P7uFmVjuqahn1rivSXLEpLEkBS+DkdhiOOM8lyjlMZonrFZL5u9Sj0OCJnpyVWXZkGyXlJDMwwD5oL9uJzrVMRYCilpGAaaqg4hy93dHev1OoR1stmNtbQzl0bwCaFei3fzXeO9YDS2bcvr169Dv0RBVaULs3RBMsYTPuI45s2bN8HVkjhcKsLatp83chxcflmspmmCZyA4hngY0n1IuhyJFf/666+pqjrE6Je1BqKgBCx0zgVWmngAAqK+fPmScRy5vb0N3Z5lsa+urp4dgPpUtzE80/JSny91D/CEych9xfMSBqZsdoDDYU/bPPE1pDRXyn8lvJJCoMv7aP3UlVpiV/kcngS870fatkMrwXCyeb4MyljevntH33cYU9A2Dam13L55w6vrF8TGki02/PyLX/Nbv/Vb/PZv/Q43Ny/48ssvKU8VQ9fx+eefo6cRbRNeXF+TJP4ch6HvGXrPa3HjyDA4nPOdjcuyZho6sjQiSzPGYqBpalaLBWV9T2StL6Dq2rBpd7uB09lnXzabK/rOoZQhjhIiOyJHBwpBSAht8KTctX46nUvceDFykkU6Ho84RSi6uwSVT6fTjEHdkGUZ+8cdb9+8eZZFk9SyhBpt21I3Ddo+HRsge0HCS6lr+bbxXigF0V7SYWmz2QQOdxzHoUDp7u6WFy9esF6v+frrr5+l5ISY4Tfl00Emcl6fhANSjOKc43AgWDYJU9I05eOPPw4l1pdI+jiOHA6HkN6RgqinqsuOyPhY3hjDOB8z5wlHhi+//DWvXr1ivVqBNgzjGNJD0dxYRcIHYaklSRxCKllMOQpPctyi9QMte34eQbOlV6TWmiL3HtHpdHpWNyKH4XjWnz+gpjyfqErnQ5i2I4ojH6+PI0orrNHAU2+A9Xozl7GvKMuKaXT0vWdt3t3d0XY9yvhQxti5K1Qc+epE46tBjTKcyoa/+I//FX7nt3+bX37xR9zdP7BeLvn41UuU8wfjvvzRD0iyglPVkMwe4/l0ZP/44FmNlWcCerLZFamx3N++oa5rVkXGyxcvaNqG9XrF/W7P1Hekccykx2CQhqHFWL+ptDJMkyayKdZEMyj+VHEr1ly8vBCOokM4K1RywR3E/c/znGF6ophLeldCEkmTa62ZnPc4D4cDX375ZegQJsZTlEU5e4CCV4mcSNghiv7bxnuhFKZxIs8ypnEEYyjPZ6qqnC2VYb/bcXd3x+c/+mGwzMvlirIseXjY8fCwI7IeG3j58mNfYzCnwcRNkzSlpGYk4yBWvOt6fyZAkjLN3YeTuY3VarWm74fQj1BiQSBYV8kVZ8sCiaPHaSSOk1mT+wKZd+/uiSJLsVwRm5gkiWfqcj57KiX39w+M48iLFzfEcRSshYBI0hxG/pNF7zo5E6IPmZw4FhBWczyeaOqGOPYVhkLeMdbQtA1aG2wU+dLk0Z9DEEUR4zyfUTcfZdYP/rp4DMbqCKtjrLYc9wd2DztsFNH3oydBobh9ePBu9ORomwYNGBQGRWQsP/jB53RVw2ZzzW/97j/JT37nt/mf/sf/mZ/+5Df8WZFas1os+fxHPySLY6+kkpQfL9egNW1VkqcR29WCcRz8idIzpqOVosgyxqnnuH9gdI48if1BO7mnKPfDRJLn9KeBrm/o2p4kjbCRpzwPczGWcwrUiDYarZ6OJjgcDt5DmRykDhtplI0YJ3ATc/ctARpbjFbEmd+wRiv6cWR0T2dvSkgsYeD5fPZgYhxTZL7uwlPoXbjuJdDsgKZrgyG5VASCQ3zXeC+UAgrSJGYcevL1ipubG25vb9l1HW4cKeuacfBxr1i/NM04n6sAZt3cLCnLFjjz8HBHnDx5DkIwub6+RjoSezJT/OwQmK7zhUC73Z71ek3TtMjZg1Jr8emnn4Yjwi81+WKx4PHxkdOcv18ulwyTo247jueKpvMWIE7SOW3Yz5kT6dtvSNOVPzg1lVSTCkIRUOUZzJIQSATieDwxTX7zgwfTsmw+j7KueXj4yocYK8tp7l0YRRFt3/kWazPeIvHmOA50Q8/2+prPPvuM+/sHDocj3dDjsCRpAgrO55IiNdjI0pYNRZLQupbj6YhNUs5NQ1m3nPqOsXf0dU1qDG0PLzdX9F3LIl9R1z3r9Q2//Rd+l/Viyf/yP/xf1L1LrGVndt/32+/3Ofs87731Iotkky12s1vqjgJoYgTINEBGCZxRBgY8CZCpnVFGBjzKKCMPgiSDJHaQQQIEiARLHci2Iqsj5tLcAgAAIABJREFUWWr3k80qVtV9n/c5+/3O4NvfrltKM23IEsBsgCDrsliX9+y917fWf/0ff8TTszOKKMLzPMZBwHKx4Ob6lo8+/JC6LUgPO7788pdUZUneA87z+XwYb1zPoa4NDNMkSWKwdDpdxXQddMtE1XRcz2MymrCPEtROw9Fs0ihhv4sI5yGmZ6DbLp2mUHUVhqqS5QlKVw1bpDzNqIqSqgNT1+mqmqJuaOqasq4F3diaYOoqtAq1CroKqtpRVwW2qdNVUOZvRWxVVQ2ApWz/Jd4gR1tN04YxWeI5stswDIOWt8Smhy5SklvxVdfXoyj06LckdEiw7yHJQ8y+wolXhHfEpGlGXTeYpk0w8tBUnRcvXpAXKaE2HvAH6cokPxCJ0srTVNO0oQMZj8ccDgeCIGC/378z+0mc4GHrJW/QkydPhtZfblGkqtP3/aHDkO3cw59Nqu3kWCPHCYlPSNQa3jLgpPpTrppE+2gOAJf0EpCtsMyfFC3uW1GOoEqPB5xEFh3HEey6OE64ubmh68TsvN8fiKu4XzsqdHSUVUnT1NiGh6KpLJZLFprGercnrVri7Z7NdsfF5Fkv/YanT58SRydMow/7HY95/vxDxuPxYMO3Xq958uTJQCTb7/eClFXX7Pd7ri7fEEfHIatCEMr8fktjoevGcMqWZYGCgtlzL4q8QO8DcV3XIy1EhoVpm6RFximLhc6gFvfeDwQPoYXesaolk9uYXs6cZ7nodvvfYxgGUZpyPB3Z7LaDv+ZsMUfRVBFUk4l1seN61A+Ys9KlSa7PZbZGU9XEvWBPPhsSq5A4ma7r1L0XqBzNJVFKbqW+9s5L8gfruo7VajU82JJ0JLcDdVPRtDJuXmU2m1IUZX9a12i6sOSWAJDsFOSLKttuyVH4yy+g3P3ats3l5eU7phiKIlahaZoOrLC3vAgBHsq5/6HwShKSJGAnZ8m6LofiNGgO+g5ErCLbYZaUoiTDMLi/vx/IU/JlkHmUqqoN/400C3VddzhhZOCMYWjvqCwlBgIMhUnMn9UAXAr5txDbyP03CLBRRcHQVRRNFexDVQVNo64b8rwgihLG4yl39/c8efyY27trQCDzo0DwU1RNI0kER+Pzzz/H8z0++ugjPv74Y+7v75nNZizPz0XBuLzk8s0bVAWevfdebwdnslgsBKB8OglRWO+OHSe7noWqYFk2nm1hGTp13aKpW3TdYDKZEk4m5GVO03WUd1e0LUSniKouMU2DwPPQNZW2aTAME6/v1oIe6I6OR2Gjr+to/f0OgoCOjiQR44A4jGzSVFjLCV8Ol6ntDmxIyS2Q62xpZxdFEXQiq1LeV4lVyKIuV9tN2zDug4El2CxtAeQB91XX16IoKD3Y9RC0OxwOw8Mq1y/36xvyIus/BCjKAkMXxidXV5eEYciz956x2+0GbUDXCfrobrcbciLkyygNUGV7/pD9KFeXUgrreR7r9ZqLi4uh+3gYsmoYxtCJyLxKSU6Sc5982SWgKU9xYKjmMgVrt9ux2+3e0dbLrkRR3npUSmk5vC2iEpSSs6kkwYjvaw1kKgk+SUKUdLp6uDWxLCE5F4VaAeUtC880LWzL7k1nj1S1UHDe3N2iWw551Qhac90ync4pjtLNaEJVSU8AUZjp4OzsnB/84AdkRcZ0NmU6nbLZbBiNRpxdXPDLX/xCIO5Zhu/7PH/+PrZjDYYmVSNGtHAmNjmdquD4HhMFDjuF26sr1ne3zMIRyz59SY6QRiuKyHQ+paxrblZ3YvWsKVRlTZ4XxFGCqasYmk4QjAlGI0F+0zTyLMP1ROaFqigU/QpXM0w03cTzVDLJNaib3h1KxbZd4dHpeXiqNmzI5P2VLF3ZUQZBgKHpg1O0zJeQjMbdbidwFO1twZDPjAQ4Jdfhq66vR1GAoYWWdFE5/0i7KcuyyMqY6PpE18kYrZzzs4t+Fab1I4LHdrsFGDzx5LpI2oLd3t4OH5A83ZfL5VBVT6cTYRgOgTPyJZnNZnzrW9/iZz/72YDcL5dLTqcT0+mUxWJBnuccDod3KKcS5JQ3VqDLb910DMMY7L9lKyjtu+XoIr8ObzcFkgUqxp8MVdWGn/eh+YssaqLFVOm6duDYSxbeEGjbd1fA0AnJ+XU0GmNbDqqqYdsOWZZTNxVJKjZFWZnT9ThKuo/YHmPe3Nwxni0xTGcARqMoJk1OuI6Nqok153K+5J//838GCCbq8+fPGY/HTKdT8jznX//FX1BVFU+fPhWn83jM+v4e13MBQVXv2g5FVfA9n7qpByJRGFp0TcdoFLJdrWhbKKuauhaekR0aZb8puTh/TNvB6+tLyrYiS1J836WpWw6HI2HgMzufoWoah9ORum3QVU1I55OUIs9RUIbkaTcY9R2bxzic9KvA7p0IQFXT6TrQtbdJUXLElPoFubZ2XZc8zQaatRTmSQMcSY8uypKrq6thZJRxjJIA97V3XnpofyU/KJmAJDGGMAwZjcS8fzqeqKoWy7LZ7/do/YpoNltwPMTYtjPMydvtdhCNyJwG+cG1bTvgBlJsIouHVK1JjsPxeBwAUEkTlZsNOaNdXV2RJMngYyCFS5PJBOl8JMeI0+kwzIEy3v7hzyxXlNKcU44iFxcX5HnObrcbiockHmma/s7II01C5TpS1/VhqyOp4ZIfIYFUScQRRQ3SVJzKpmlydnaGqmq0TcdiseR0ithut2i6yqnM0QyDOIooipI0y4nTlJvbFV64ZLG44DDbYfS7c0lOK/Icx3I5HA7keYHr+Hz3u99lMpmgaRqvXr3CsiyRPuX7b233LYvHT57QdgKk7TSNspe0j8djQBw0aq88PTcMPMdGaRpoawxVwfcDmgZM0+V+vaVpWi4vL6nbhslkyik9oZkaRZFRlhamodN1ClEUo1fFO2g+bYeh64xCYX/XtS2GZYKqkmQ5umlRVzVtT0unKMnSjLIo8XyNu56EBm89MSUu9dCpXK6rJeYmDyzJkpTdr5qlNJ0YYWVhlc/qQ43Lr7q+FkVBzvayZbVte8hOlIy9oihABcv0GI2EZZmKhqZZRKeYTK+wzJMwLenZdXJNI9cvk8lkEAKJk2/Eq1evBnWiNG1dLpcDT0LeHGmAKV9cRRHJPVdXV8MHLf8uu4WHo4fcUNi2PQhjZOE6HA6DT4R86GXBeDhfSkKRLBJt27LZbPobLB4oKYWW30f6M0h5uSA4OQP2IIJXj4Mabz6f0zQNt7c3w55bWsRVVUXblGRZjuf5LBYLYUDaVdzfaRR9YlfbQd2qZLdrUDROUQqaRZqkZGlM01YDP0IWvzwTLfPH3/gmdVMP45V0zTIMg5ubG5bL5cBj8YIRiirDhAxUm8E3QNWFB0NDh6pptIpKkYtuj6bGMowe6O0oq4amE5qKU3zk9vYaXTfI8wI0ha5TqKqGSTih6+B0irC7twQjWqG/0E0DTdV6QxaxPWo6DcO02PQrWd/32Wy2BKMA1/MwTIvJJGS33VHV1fAMiA4nHO61fPE3640wHtK0ITNVHgLyUGvbFl3TB7BSYlryPZCA+VddX4uiIKW+IFhxco6SBSEMQ7bbLX4wwjBsuk6lrlK6TqMsGppGxLDf323xvIJw4qHp6tCCy9lbnvDSnGK32zEajbi/v39HRyDbbon+ytFB2m87jvNOLLlUasotg8Qx5Ikm20F5QorvFb/TFT0sjHIzIsFRKWmWN18KnKQMVxYS07QGcFG2nvDWH1B4Uow5O1sKSXQ/Kkn6tHywRJsvo87fKvQE7mIMBCpQcFwHx3NwXFeAYIrCuB2DllEUFUmagaJS1y2e53M6HsiLlLrKBQ25bftUp47ZbMZ0NkVVBO9C2obd3d2x2+14+vQpYRgOWx1V10mSlAzRPquagWE7dIYOKDQdoGqoXUdVVCJ4Z74gOR0xdR1N1Vmt1sRJJub8Dm5ubtF1g6YQdOZTFOH5NnmWE51OWL3oqqpr9Loe8jbEKOdDD2LLLYSmCFzm7PwCug7DNIfC4bhej32VtP39BwZRnnwOpEDKtm2hQ+nfG0k9lyCxJLzJsVCO3bIrkweX7ES+6vpaFAVJJHIcEVwqPRIlwm5ZFufn5xSl0DVoKjRNSpblKAjjjLpuRKpRVmHZGkWZDtUU3oJj8sSVYON8Puf29nZAY4/HI3meD2251A6EYTgoIbfbrWhfHz/m8vKSPM8Jw3Co5hILkdRqRVGGF1jGmpumObhWK4oy+EVMp9NBKdk0zTAHSuMZeAtKSkDRcRyCQESqSyOPOI45Ho/DHC8Bza5ryfNs4HtIN+KHnn3j8ZgwDMmylPE47E8ZweGvqpq6qodfHw4HGrWGtsPsTVsURWOz2bLb79FUHV03UTSdzXZDlmd0XdODxaLl1g2DFuF9oPV2+LK7+dGPfsTjx495/PjxsLMPw5C6afrNU9mvawVGIsVywq9RtNd5mlEkMbQNl19+iampjDxPbGhcF9NyOSU5N7d3qIrK/rjn9fUbbE9Etrdth+97g0gM+jQtTUXvHY/8UcD5mVB5RlFE2t/Duq5o2mY4sSWv5CH/QGooVFUZQHK5Ip9MJsDbsBlQhk3CQ8k88K6cHrAcEXknv5/seoGvf1GQKxXRwro94Oj1RByGtqvcRyTpiTiKBbHIMMnynLaDoihFm1c3rFYbmlaGetYYuo7an3RSsVaWFU1dk6cpjuvStSKFyLEtYTtmW1jWjK4TBKXVas18NsMyLY6n46ASVDVVjAFdh+XYb2WuqgpdRxTHuI7DbDZDUVW22w1JkmJbJl3bDUChoih0bUccxWR5NrR7+90ey7Z6q7NgKCwSTKz7bmQSTsSpU5YEgc9iPmcUBMRJTFGUA7+iLIsh81ESsB4KxSS2IJWRitLP5qoycB+qsuJ4PFHXQlDWdS2oQqJc1w1hGBL4I3TdZDQyqOuKqetS9eakdSMESpqu06EwnU55+cVLvv+930Y3NDo6Vut7Xr9+zXgc0iE+x9lsytXVFa9eveb84pw4zVgsz0XBAOqmge6t/0DXdjRaQ1c3qI3N6bjvx8YAo2eBFkVJ2yqEoxGbzQbPd3lz/RrHdYQeoevQ6SPdiwx0TYwFskXXDeggS3Pu7u7RVQ3LMvH9AM/3qWo4Hk+A0GE4joNpiAhE27Epi5wkqftOT2zefN9nNp/T9v4KVVWR96Otqek0qgAy5YkfRScURWc8Hg1biLrvDiQbVuqEgAGb+Krra1IUVMJwjnAGPhLHOWla4Dhe3xLVKEqOH7joBoShy/6wJ0oS1Lam6nJqrcV1QjRVZ7PboiktmqpBawyttudOANHaN3WH2rW4riXCR/Mc2zRI8oLpZITjubRtA+2IJC7QsFA7nXASomk6WZ6i6CqBP8IPA6qmIU1iwrGwWi/yjNl0gucK0PPi4oIoihgHPvv9ns1GzIaOPRqcc+I4FienqtE1LZZhoinqMFfXlWBc0nbYjjWMHfvtjrqsBv591cePSYcox3EIPDGSTXtRlms7Q/dgmRa14wo/RE0nS1Jm8xl+4A8gpqKAZQmVoWmpGCbUTUrbdnTolHlJXDdMRnNs0+G4OwmHaVNjEjo8eTLFsAzKQqNMRStsOT6jcM6rN28YzyaEsxFFnVApGT/+xY9QFJWZM8MJHAzDYrPb07XgOh51DU8eP8VxbU77HaZpMQqEaM4yHbqedNQUNV1Vk6cHmjrH8x0My0RVVOa+z367F+nU8QFXb4nLI51aEIQer65vaBUVO7A4pRltlWNbKkUV4+kTHM3BQIxTbdNSZBWtAZ5nE2WiYzH0hsVs1Lf1QFPQUGObCobaYto6eV7TtRpxkmD3gijDMPB7sNW2bX74wx+yWCzompquFS90XdfoBni+PTwjvu9zOBy4u1uRRNkgfJKdx2j09nn7qutrURR0Xeejjz4iiqIBwdc00UY+VB2WdTHM5Y7rkGQpKIq4IUWBoVd4Y591UQm3ZB3aU4Jl12wPJ2xbyGB1w6ZqBBpbodOoBvvDCd3QcF2bNC8pqprjcY9lmwSBh6V5zGYTgrGPYSqs1g2dIroDy7Bo6pSuAUUVbZkchS4vLwceuwRRsywbbow88SXIKjkJh8PhHcXk4XAYWmopfpnNZgMZS86WmqYN7j/S418yNmWCsjw9zs/P2e/3g0eEJL9IDGS+WGBZNpvNpldIxkP7KR7yflNiaqAwnE43N7fkRUFVViwu5rRtJ3wQLIv75HY44R5dXAyrWae31nddlx//6x/34JjB40ePiE4xh90BQ7d4+uQpF48eC3v2w57kIAxoFE2nyjMaVaOra7oWijIjihKieM/peE9d1XRtS+AFTMOQtm/Zsyyj6EHVal9C29JWNWWa0QCpqRHVBYFnkWcKrjXGcexhhJOjr+RLSCDZ8zwCz+ZwEDGE8rSWALB0whLrcZO8KIdQpIcMWMMwmM/nQjXsWGiKcG6SOQ/SYEV2wZZloWrqgJ8Bw3MgcYevfVEQe/KMqipQVYXxeNQjqQWK0pHnIpi1agQ6K3QFAuRR1Iy21Wg6he12g6romJZDUeRESUacviUlCYfdS0aBsDvTVJW6LnFdh/lsQjgKSIsc3VRoO2EdNhqNGY/GeLbH2dkUVdOo6gLbNKjbhjLLaaqKqq5Rmg5UWC6X7Ha7wSZObgl83x9WQ5KlttvtUHphjSwQco0pRwUp4ZZcdylflq2iBCglD15uKCRwKvkSco7d7/eDgYwEIGVrKYlcSZKiqG8BP8nHl27DcrbVDQPDtFFVnbpqUFSVLC9AUTg7P2N/OmEHI370ox89mItFzqVYr8V4jk3S07yvrq6wfZcsy3nyZM56tWI8GkML7z17j6qoOW63AjsALF0hrUqaLCdWFHTDZBxO0AwDVYNOrcmLVGwrHJfF2RnTcILSdcRpSlXXqP2Lg6KgtAigMy9oy5JOUfBNG82xqIqUIskpTJvETGmat/Fsvu8PUXCyNa+qiqY1B0wnz/PB+VkWE/nZO64viqdjo6mKGEdN4WRdVSW+57Ja3WObBnRviXfyOZLbMvmcj4IAzbCH7y0xNCnJl/jUr7q+FkVBWJyJ6AjLMgdnYenmLH+oqq4YjQJs28JyLFRN4+XLV7StcCNuGpU4jqiaDlQd1RAtVhwJso+iClrJ9e1KzFl+QJJldG1DOPL56IPnuLbO/hixnE+Zzc4Yh2M0pWN/2HCKD/0NLcmKgiAY9XOsuIn0LyKIdu14PA7AmKQjy3lXsislMiw3C5I1KV9Y6U0JDC/mw5dLbiikLd14PB7mUEnnlrTrqhJJXKfTacAsHm4dRqPRQODK86xfo4nxRWw0OgzD7Fe+GYeD+PksZ8RiviCcTImOMcejIJg5rsfV/RpF08jynNPpRBAEVGXJdDbj7u4O0zCgbXjv2TPBEahryAs++eYn3Fxf41g2nu2ymE3Jkxhd1cmTGNc2CQwdrRZy7MB3CcZjdMchLwqiJEZRVWxHZ7mc0VUZRZbj2uJEL/NcWO27ApA8no4opULXgK1b7A4HfMumU8CgQ1dV0ixHbQ00RaPtpc4SPJRqVcmBkYne6/UKTVWF+Wsvc5Y6H0mg0zQNTdcIw/EATIusEw3PFR1nmsTYlonveZRFNrg9S5BYCv3iOGY8HjMOQ6q6Y7lcslqtBgBcEub+Rjwa/zqvuq44nY6MRgFtW3M6HfsHW+QtPH78SMhEFZF9kOc5hmkMI8bNzZq8f0l32z2nKEHVDdIs5Xg4Dh/eZruhLEr8wBfdAirOeEaWxOyTguv7DRoNbV3wxrH45OMPAZUgcGi7lu1qJZx3ew59moosSNOwMHXRXWTpWwWijO+SnInlcjlsWuTJIU9/YKBjv3z5krOzs8Hb4HA4DFuEbf+iylFCkrLknys5DpIGK4lYD0lSkgwjTwypupSUWNHmWmi5AChPp4jFYonsDpoe+S/LClAZjcfopkmR5txv1qR5QVHVvHj5JYquYzsud+sNmqYzmYRkaSqcprpGgLuOjdWvgZMk4b35TPgv5AUqCtNwgmNZRIcjZdvhez6z0ZQ2SUijE7bj0JYWp32NltrotkXgOxiOQ5ZlJKcDm9UaXdPQNQ3TMGj601xVVfKyoG5FfmaWFixncyFuqhscT0ijHc9mPp2JXNCyRinE1kua7EqSm1DwirTy0+lEUzfolvjs5UEhX0jpBqbrOuvVPfPZHFMXRTrLMxTLJEsTLFPHNg0uzpaUVdnb0DEwGWUXKWMFT6eTIIL543d8NyTl/f8XNGcUBVVFyG11kQeQJgl5ITIKDEOEctiOx2azFgq6zRrTsnBch/Pzc95c3fTmIzmnOCZOhfZBrubkzOw4Dqv1hlMU80g3ifMtvucSBj7r7Z7AFYKZH/3kF8Rxyuf+S87PF3zjo6c8ee8D0VrHCXlRYhgQnY7YtjOkUMnq/5e1BVIoJV9QeUlZt2SqyVWalImLdaNgJq5Wq8HTz+jJN1VVMZ/Ph7Xmqi9ckj8vXX5kypPcU1dVRRiG73gHPrS567qOMJxQldXQFahKj+g3LWVR0jSCe+D6PtvtnizNSJKcJM3YbDfUTUvTNRyORzTdwPVcQefWdei6QYcyGi3ZrNfMplN83+fy8gq6ju9/73t8+PwDbq6uCFwP6oZHFxd0TcMvf/YTAsvCsww0VaXIMwzLZjSZYPk+6MLkRuuRerWDcTDCtizo52nDNNF0ndu7O7wg4Pb2liwvSJKMpqo4m0/plI74tENXFFRFpW07irKi6pmJsl2XFn5VVQ1WgFJsliTJYFzz7NmzYYyTStDRSPx/NU1N09TEcdYXb0+A0utyKOqaporYPd8niqJ3xgDJ+CyKgsPhSLxavePtKA8WEX33N2Pc+td2tW1LXuS9rFj4EmaDJbcBSoeiQN23xI7jUNYVh8OxNwtR+l2vOGm3uwPHU0RZCXTddWz0IEBRFbI049HFBRcXFxR1TVGV3N9es1/rYraNdMIgwPVGvLq8hbbl55+/4H615jvf+Y4gRHUaqmZxjBKKIifpR4bZfIamM8xugr22GTYLZVnieR7L5XLQRDw00RyPx8NeWc7+knQlx4KHL7CcZeXpfTgcBhm1LDaSHi1xCXmqPZxJZeGUnAXpExBFUlWqsLpfDyo+4e+YCTCvKLm7W6FpOnGcsj8cOZ5O7A8nkiRldn6BYVqMDCFcszSdxWJBVVUcD7vh5zN6z8iu6yibhvlsxvn5Oav7e9q6JktipuOQ1d0NdZ5jmZbwolBVyrZhMT3DGYfoqkpTNzSFwAPKvKDMhYu1bVkDMUpiPVkurNXrtuHy+pokL8jTBLoO0zIoywLXsamqEt0y0XSDrKzxbdGur9frQbgn3bylPZ4s6J7nvuP5Kb0WZfHebDYoCPampqroqoKhaxx2W7q2o2pqjH7kqfuuQHok2LY9yOjli6/rOn4QsNufhgQp6VwuwdGvPU9BPrCy1ZUfrjyxZJt7ipJe8edQ1wKI1A2LLEuHdny1WrHdHyj7D0fskTt812E2n5EmIqFpdXeLaVssJ2PGrsVuu0VTYOwHHA5HDN0gnCzZbXdc327YHn7ETz+/5FuffpPvfPYtzpZzmrpgZpmk8Ykg8FBVheVizul0YrVaDQIvyWyU3YIUNEnGZRRFnJ2dDcGx8rSfz+fDqOD7/iBi2u12Q0EBBtBKfgYSs5DdQ57nXF5eAjCfz9lsNkOradtCPyIxD00TaVVZmhPH7yLVx+Nbk5vJZIKqis+3qGtOUcL+cOT1mzeYpi28HbqOzXbL7/ytv8Uf/ot/QdO05LV4CcqypGvf+k/O5nNWd3ckScJiecann37KzfUNvuMQnU4sp1PS6EQaRziGgRv4ZEXGKJwwWS7RdPGslHVDlsbohkFRVMKrEEFFbiqxATBsa1CwRknMKY64vLri6uaaU5ISHQ+MfLffdFWomoKlG6Ao5FWNZZgDbVzO6A8LtizMk8kEQ1fo2mZwaJIyd9M0hyRv0xSmsaM+XSrLsuHEl4Q5UfjrATuSgUjy3jwcYSSZSb4/D42ApbZGFotfdX0tioKuadR1yf397VDFRYpvTlHo6LpB1zXkuWivyvJBSlIP0imKwna7FYVCU6nKBrXTsE1d2F13DS9/+UvathE8ebcDQ+Hu6kuapqWuGtqyINF1LMumaxVevb6irltaxSDOOtK7A9v9n/Ly1RXf+vRjPvzgGaORS1OVjI0xZZEPoI5ksElHaSlflgj+eDx+h9UmV0a6rjOdinTlPM8H4FLy37u+7X7y5AlxHLNer4eY+sPhMKy0ZACuPImkKYfMdpCz73a7fUCTFifYF198wXQ6xzDdHjsRcetXV9dDsTEMYVG/PxxI6obdds+rL1+T5wV1A4raayCqmrwoORyO7PY7zmYzoihiOp1y2G/R9X6F2rbstluWyyUfPP8A07DQVY276xvKNGU5Cdnt9hgKmLaNZ9uYwYjWtIiLkkpR0VqhhByFDl3bEYQ20W5PmWQsFwvOnjxB8zwaOvwgoKxriroSL3tZ4I9GVJ1Klqdi7DkdyJIINHA9B3RdaCl0A9N8a8MnW3IJPErw8XA4MJuMKEshaZcjpgSCPc8bXmLXsaHr+m6p7e9zQF2LMVRI/00M0x4KtewYsywbZAISjAYxKkumqjQckqawUmb/K9/Hv9nX/d/skixAcYqmg1WZZNCZpjBe9VxrGCtEocgYhyPyYj+0bLLK1nWNpii0dU1Ti927piqoqLRNRV1pGKrNe48vqOqGm9v73hhFx3Yc4ijj2599l/3hyGazI8lK6rrklOT89Be/5O7+li9eXPD++094dL4gzRNGgY+tCWttmQol50oJKsnIcMnalBuDyXTKYb/noR299P6XLaIcEy4uLtB1Y4h6l6Yn0pFpvV4P44qqqkO3IFtm2SWMRiPMHv+gbyeljPvNm9d4wQTTEDPxvke7pchLZBQIU5VXt/dcX133OEOHUTWkWQn96dk0DevNCtMw2e8POI7I77Ass7eQU1hFGIRQAAAgAElEQVSt19Q9cDYaj1mt7snTFLXrWC4X3NzcYABtz8No5jNaVaFRQDEN3CBgHE5Fgc8KNFUTa8pTRBLFHPd7LNvG1nXKpuby6orb+zvuVvd88fIleSEAOkXr2a9FynaXU5Uphm1StC1+OEXRFKIkpq1SPM/F78lBbdsyGgX4vs+TJ096fUsy8DCk2a7k2YzHY+JYxAFMJhPyNCGOTr3GwaGpKzTVJc4iVAXSJGYxfw/bcbm5ux/el4d0ZymdFl2pQV6+1dUsl0ug43A40vZd+Vddv7YoKIry3wD/AbDquu7b/demwD8G3gdeAf9x13X7/t/9F8DfARrgP++67nd/3fdQNY3z5SNevnyJawuUlk4V2n10PCdgf9gTjKa4ToBq6JziHMcNsCwP1y/Rj0ey8kBRHyjrlg6Noi6o4wY97ROhGoF2j3wf27LxbAfbMKnyCFNVUTSF9epGkH50k+32GlUzmExmuLZD05iY5rRH3wvevNlwfb3n+fPnPLq4YDQu+eDpGFXTiPMKXzWYLZZER9EyOraF3+dP3q92NC1Udc2bqyteX75B01Qs22S5XPDm6iU3t7dYhkfTdFiWYPUdDgdWq01vDlNjmjZxnHKKYrR+nrUsi+XZObv9nqwoBTAmjm90y2Z3OKGgEucV4XRBXlzjmibr1YpwPIau4+b2Gu2wIUsyDNNGU3WaBg5Riq5bqHpMWZlUlUKaFSSZcHq6ubrG8wLSLCcvCrSqZDEZkx+P6KqK4zl0XYViNET5Hse2iPOIKE0Zj6bo1ogXn/+CONoxXyx5/OQJ9+s1TV2RnFLm4wnjZUip2ow9B0wIRxaerdPkCXVekZ5O5KlYW1ptiaGVKK5DYxrUpkGZ1RRtS5znpFlB4I8wDJPD/kCR7KnrnE7VuD+dhITeNPFUkzrPOA8cNqt76s6lMTTM8YjAs/F9D8exCTwDTalQKRj5Jqrmcdgf8DxvkINLx+bVavVWaalqNKigqSR5QVW37E8xluWQRRGjyQzVsKj6EeFwOLwjfjMMY+gKZIRfs9sxm47QVJX720thLVjV0LWY+r+dHdt/C/zXwH//4Gt/H/j9ruv+oaIof7//9d9TFOVT4G8D3wIeAf9UUZSPu677ap0mQvS72+346JNPiI5Hrq+uBlRVsvZm0xmnKANFwdP9vuK2Q/vWNMKsUtM12q4ZWrCu7ejUFk1V+1gxG9MQNuVRFAFNT7MORYvetOR5QVGW1HXbi2BqTNPB90MBAB6Es+6TxWPKsuDy6pJTdOT8bElT+nz4/AN8L6CshN2ZdE42DJ8oOglfBcOk7Wp2u+1ge/bJJx8TxzE313ccT8J5qsgLXEeg0Gm/ypMKUsMQDtbb7ZambRmNR0PIqdozFne73XBKPXr0CEXVOOt32nmekds2bQdJFNN0ULcdmmmh6AbXN3dstztcxycMp9R1yylKWcw8Nrs9qAZar1QU6km/lxafKGuxx+8Ujbbtpd2KOrAvo36NmiQpt3e3BF7Ihx9+SBTFHDZXKNQE45Btz7g8Ho8sJnP2hwOe42DpJq1WY/sWaqNQJiW6anB9ec2rL1+SRCcuzhd88OH7zOcz7EZlsZijGyZVkbOYTzkedtxeXRH4Ll3b8OjinCQ7MRqNyIqSJM9pu7ZXctYkdcF8IlS8ujvCcQUd2XN9Li7OB6NdgRmJpG7XtIckMLnZkfiNNNy5vLxkv98PwUOSO6LrOqZl4fabLFlEZFYoMOSYSO+QIAgGklzXdbg9uUlyYGRX+W/l0dh13R8qivL+X/ryfwj8e/0//3fA/wn8vf7r/1PXdQXwpaIoXyBCZ/+v/6/v0fZt5pOLC/a2jdqr9+ReNcsyZrMZmi6whDSJUegwdI3NZs04DAkCn64RiUF1DQp9zoOhiXWmZWObJqZhYPU2Y6ap4/kOlmWLG9+05GWJqmo4rouq6my2W06nI57XYlo6H370vCelrLm8fDXIkfM85c/+7E+5P5tyeXnLx9/4CN9z6dqK5UJYf23amrIsaJpKMOUCj7OzBVUlqMNZlnM8njg7OycMJ9i2Q9e0FEXJfr9nsViw3+8HJx7P85hOp6IL6lq83nb+4aZDqB2zQXhVFAVd23DYrglGI/a7La4XsNsf6VSTY1pSFg2r7Ymr63viJEXXUk5xQVOLTI1woqBpBodT0m8wXGG2W9R4ns9+f4AOdN0c2tu2L86qrvWboxNZn9kQxxnvv/cRiqry4sUvaMqY87M5l9fX3K3Xg8PVfrfj+eP3CHwfRYE8SdGUjqg9kmoZpmGz3mw4nE7c3lyhOwb+bofjlVh2gOva0EFbFXR1RTjyUZUWTVEZ+Q7TMEC3HnO7WnFzt2K5WOC4LverW1RVZRKOSbMCTRfORh1v1bdFmfPs2ZN3nJWFSrNFpnFJxa3EfMIwHDAgiQlI9yuplJWZJ3kuQnvPzs6GdbeMLJRAtlzxHg4HJpMJ0+mUbc/+lKIo6WT2N+GncNZ13S1AJ9Kll/3XHwN//OD3XfVf+39diqL8XeDvAixmE2az2eAok2UZm81mIObIkzEYhWI91NSMRgHH04nz5RLX9/A8l8NhzxcvfkmRn0Qyr6pi9fO8ZZjYloWhiR85TROOh4LdXmQbarrQ4LeA7biEk2mfBRGwWIqEaNMSyVRRFLFcLnj6VMh5X71+JcggSsfV9T273YHjIeLZsyd88P5TqqqhbnLG4TnrzQrXsRkFHkWR94zGGl03OJ0iDMNiuz2gqRpxlOHYNtAN9GKpqz8/PxcjST8bKqqCbhjs9/uBmGIYBo8ePRq8/jabDXRCrHXYbXn06BHXt3egGmwOR4qyIclysqLkX//iBXmaYOgGbQeb3REVndnMI0kzxuMpmm6gamL12tRC2v3Ztz/jj//ln1CUNb4XYDoOnidWn20jKNNxbFPVDXXT0bU1Yejx/vsf8Bd//iNub1fMQ5/t4SAoyLrwDzgcDpzPF7z88gXH7QbfdlnMJiwWU7wnHrZtEcUJl5dXJHnKz774gs7USJsC3/VYhHMePzoTLNEy4+rNl8K9SulQ2pq2KomSE944wDINDF1jPB6RFyVJnKLgkN/eMZuOMXWdtmwGc5uqqjkeTlyp1ywWc9q2GeTbp1NMWVbvmPnKl1qSzuTGJ4qiAYyUmzhZJCaTCXVd8/r160EPBAwFQWJY0kej67pBvi95MZYlxk8ZT/9V11830Pirlp+/UnnRdd0/Av4RwG9844NuPJ/z4uc/J8/zAX13XXECSbDOsm00TSfZbAh8j4iOMBzTdhJE7IbU4a5T0XrJr64qKHS0dU1elZi62O8augaKgqYJq++uExyD6BSTFxWGbhJOQsIw5Ob2ktu7a8IwpGlKfv7zn9I0Dc+fP+fp08dUVcXjRxesbras1ndU9S1xHBNFR95//wnTcMSby8sejGvQe/n2k8dPyPOCqqpRFBVDN1mvdv3ab9qbqiTDTlvmGsgNh/RWnIQTjH4scByH3W6Hpmnc3NwMm42iKDgdD9RlQZzEVHVNVTf85Gc/4y9+/FP2pxg0g2A8IS0a6koQfEZjAeAZhkUQTtEMQQP+3ve+T11XRNdbHj9+QpKkaKZwZdL0kjCcYNo2juNi6CZpldPS0bQdddOgqgJAPjt7xP1qzdX1NYEfcIwiTsmJOE2Yz+e4jsNmuyU+HPEtizpLmX3yTSbjEUWSk0YJSVzwi89/yZ/9+b/is9/8LlGe8eLNK1bHDaEfMDYdPvnkIyHvrgq2m3t++tOfsVwu8X2PV69WpFmK6ZgEnks4HuEFI158+YqyrkhT8FyLqpYvtvBykPL+NM369e4ByzLJspzJZEIYTlivN8PW6e7ubqDwS/6JZJcKqn7zjveH1FNIjoNcU0omrLTSkw5ZD/0T5CpfHrRy4yRp1l91/VWLwr2iKBd9l3ABrPqvXwFPH/y+J8DNr/vD6rrmrvf6l+tFmdQsr4uLiyHkomlqNFXl0cU5ddtgOw6b7RpdV4Uufn2ibUVRUBCJRCXg2Da+K3bEbSNeiKrpMAwdpxeqBJbDtz/7DkmakSRCMPNnf/av2O1X7Ha7Yd8sKcFSzSiELg6OGfCNb3zM7d0N6+2WLBOzu+85LOYT5vMJo1FI2yjUVctmsxvszaqyIIpWg5nq6XQkDAWbMQiCYd0k15YSWJJil6z3SJAIt9x0bLdb5vN5jy/E7LZb1tsdv/f7P+DVm2t2x4gozSjqFtcb0akWumHTljW6bmEYNkHg9Kvdt/kK19fXTKcTDEME5nhewG63ZzwO0ZK0T1bqsExRzE3LJE4SOkDTLbq6xbIcnr33AT/8k39J3TQcT0fKMhdbINdlu9+z3W4IPI9DUfC9b3+b737nMxbTGafjkas3V/zi8y+wnIDXV1dsdwe+fPWaZ++/T5InvHj1im998jGuovDDP/ljPvzwQ968ecObN6+o6wLPszFNDccxKaucrqnoGoNJOCbJSo6HvejmWp0oTmjqirrxUVWDsqwG2ngYhjiOMHjtDFgslxiGRdqHwT404pW6FGBgqUregXy59/s98/lc4Eo9NXk+nw8chbIUI6VwpDYG79EgCAbCmiwu0ntTjg3Sou+rrr9qUfjfgP8U+If93//XB1//HxRF+a8QQOM3gD/5dX+Y0bPNHuY/yHh3RREmHIqioPfjgGUalFWFjjYQdwxNw/c8ZrMpX355I1BWBVR0EdFlGEzGI/HyWjZVWRIlGZ4lfAkXZ0vSJOfq9pY//MN/RhSnzOdzkjRju9sQTnyePX2Ppm0xdLGmO55O+J7HbrunqVuiU0yRX/Pes2eoqiIMY/KcFy9e8eTxI/b7I9vtkfff77g4P8N1Riho6Brstvs+c8ICWjRdzIDS4VcCRzIbU1KmpV4+joUASKZXR1HEfD7ncDjgui6vX7/mxYsXFGXFar3l5vaWNC/YHk50qFQt5GVFp+jopjhNRv5YcPdVHbcPMinLEs/1+gd3w8h3ORyOJEnK8+cXXN7cUhYVtusSxwnhdMrxeBIxc0rB8XTEsGx0TScuEt7/4COOp5gky1F0TXRFmk5alOS1yPkwNY2ma3n69DFn52fUdcWb1684bHa8fn2Jabn44wnHU8Q4nPDyy9fML+ZcXd9Q1jmff/4F7y+WuL7Pk2fP+PyXX6BqOrP5ghYoyopxOKHtOtI4EjmXecX19S1RHCNDfuuqomkE+9Tzgt4YR+np8y6+H/TW9R1NLUYL2RVIUZnRj3gPg4ju7+8Jw5AkSVitVgNNXmINQRAM4jjXdZnNZtzf31OW5RBVLx3DpM5BMmAFXT3szYJP71j5fdX1b7KS/B8RoOJcUZQr4L/si8E/URTl7wBvgP8IoOu6nyiK8k+AnwI18J/9us0DiLRdycmXQJqqqgMBZzIRrkJ1WVLkOYf9nqIscVyHtHeZsW0bx7aZhCG6ppLWIjPR7VeQI19QSLuuI01iurbD9zxGkzmj0YjTUVhpe67HfH5GBziOS1GULJdLrq5fU1cln3766eBhcDgceP36NefnjwdbeX+ksz9u0VTpXKSQFRVX1/cs5wuurjbsdim/8UkzsCAvHp1RFEIj8eTpI+L4RJ5nzOZjukaY1kq+OzC0f13XsdlsBLHFtvCDgOPxiKIo3N7eDj4Mkh0axzE//cUX3O9O1I3wJOwUXYTotC11B7qmYuoqqqIxsQOiKMLUNFQUqkJkQKq0hCMPlQbaqreBMwjHwuSmroWrcprlXDz2ePHihVBpNjWO65JnJY7tEYwMfvvf/R3+l//5H1OWNYoigmsbBaq2g7bBdiwWixmz0YjzsyW77QbygjQ60dQdfhiiKDooCpbj8lvf/z5ZVXJ184bn77/Pan3PxWLOdrNhtNvzk5/9HMt1Wa/XYmsFwu24qojSFF1pydKENC3YbNakadKHGBvkeUbTtlhNSxuJ8c0wTIq87P0lRPtvmkavZ+jjAa1uUL+eTiLF+uzsbMAYpE2aPBAly1NyQqbTaZ/WFQ9ahslkwmq1EsY5Pdi83+8HAFIWFenqJf+SwjlJivsrFYWu6/6Tr/hX//5X/P5/APyDX/fnPryqsuL+/h4ZlCrpmFI9KD+IrqlIkoqmrggCgTkcjwehHDM0bFN0A+ORcEui5yYIW6uWLBNfsy2b6XzCeLLAsAWBKIpjVFXHcl3CcMJoHKL0rke3d7fMFzNev37F8RjhODaqqvH+e8/54PmHNG3Lzc0Njx6d8+Xrn3F5eUWaxuiaiWs7TCYzVFRWqz3T6Yz16sDlqx/w+PEF47HP6RRxfrHo27uaKDrhuCZ1naGrzqC/l97+crTa7/dD8EwQCPsv6cvYdZ3gfbgup5NYg/7yl79kd4ioFIOyFfZgqqqjIJhwjmVimTq62mEZBo8uzok8j6qucG1zoMs2dUlV5hz2G+q6QFFEW3x9fYPaZ1mWZYWuGf3Du6brFOpa+E44juBY/MY3v83xGJHlFQodeZbRNAXBeEKnKOi6YE2ORmO6ruXNmzf4pkG82+FZFr/927/D+x9+TJLm3N2tiNMC23HYn46MRiMuHp1haBqzaUhb1syWZ9zcr3Fdh/PHT/mDP/gDPv7GNwhnKlXbYVo2h/srJprO/eqe/X6HYzvYnkdZV70Fm/j5ug7atusl6TVpkvWFusUwTBRFI4pioljcD+k3KqXopmkOeNl8Lqjx0tRXgogPx2ip+ZnNhIK0LEts2x7WtSBUl3ILIY2KpE+HdM2WgOfXXvugqspwmsmZWSKq0vw0yzJMTSFLUwF++T5F7wFgmCIZWUSFmYThiM16B11Lnqeoilhfjkcjurbl4vxcUHSPCVkpkOJxGGLbLkVVsd8fuLm9Z7vdMh6HXF5doesau92O+VzBMh081+PNm2vm8zmr1UroBlQNy9L59NNPsCyHtobdZsd+fyKLMzwn4P5+x3vvvUdlJ7x88QbL1lhv1nz7s2+iKA228xiUGkXRyYsYjQ4Rd2YN2nkpGQd4+fIlbdtye3/HZ599NpisSJDR8zxub2+5urrieDyS5hW1aaGbdt/CtpRFgaGp2P1Ma1smKipVnnO2mHN3d4uuKHSqWKM2TUN03EPbsNus0ayAtu344osXBOOx0PZnGZom4ti22xdDK6ugYJgmhq7x/e//O/ze7/6eUJGqHY7roKk2SVFgOQ6PHz9CU2G92TBybSw6sqxmMpvxrU8/xfVc3vvgA+q644uXr7m+vuP2bkWrtHzzm5/wT3//d1ksZ7z68jXjUcAf/8kPefL4CeNwwouXX5KkqSCXxSlJmpMXJVmW0u12xHEk1uBxCppO3bbohompa3QduJ7ba00KTFPYwe+2OzzfHajlXdeh6Qwg8Zs3b5hOp4PEHRgYrZom0qHCMHwnmAcQLM/RiMNBkKDG4/FwbyWzUeovJPW5rmtOp9NwsMruQvIcvvZFQdJmy7JkNB7j2DZ67wzcNg26YVA3DZbl4Y8F9uAGE4r9HsNwOD87p21bkTkYLlkuHvPjH79ENyzU1iQrDSaaT1kZhIHH2A0po4wii1Fcm8C3KeqEoqj4jU+/TZYVrNYb0jRht1uzmI55fDbn1StomgpHbWizE0ZbsBy7uNqcYhrw45/8mJvNLdDh+4HgrwcjPv74E8qy5Kc/+RmmbXC3fc352QWqq3PKYvZfHjmmMV98ueC3fvMzdF3j4tzlWfgY01R58+YVk+mUvMzwRwG77Q4/GLHfHxmHM/78z/9CxLu3grxVVhW3Nxu+fH1NC9ze39F2HUXdiWJgWui6hu8Iw9q4Asd2RG6hbuHbgkVZtjqdZlF2Co0qJN/HVOgmsjQnLxtAJdtvhRy5q6CtMQ2dotI5RhFuEJBXNUlZ0tYGXdNgaha2a1PkMTe3r9EMhboqqYqWMAyx24KPnn/IdrOiLnLm4Rhb1cjiI+EkRNU0rm6uyfKC7ybf4ac//Tlvvvw56+2W2fKMKM343/+PzymriuS6oCwKWuAYxwRxxPXNNVVV4Fomptqx2Wxpqoq2zDnEGUpSEU5C8rLENAS+Qa2SqdC2DUXZUfkdjaqAoaGaOsfkiGYCWoPj6uRFQ+AHLJbLIRpPcgikr4XMG5G42WQywbIsttstdV2zXC7J85z1es1utxvEa3EcD5sKOWpLqzfJbEyTlK5pyWIhn9c6BXM8Rmk6qqzAdv76gca/1ktWuKqquLi4wPd9Xr9+Pcxbjx496mdiIf7QVRGT5nk+pikQXuE8I0xPPvroI/7vP/0RZd3g+SPOzx9hGQZqJ5yDyrLCUDTOl2fUhoKua9R1y7NnT9is7lnMz1jO53zyjW9yOkWcjnvUrqbt2kG1Zts209kUP/Cpm4bbu1vOzs6olUYw+vrVY56Jmwr0UvAR0LLZbTAsA9dfEB2PrNcbDN3gD37wh7z37ClZWlBXHapWk2YxVdOSprloWZuOV6+vuLq6Yb1esT+c0FSd29WWuqnJsqxX/d0LN2LTIPA9DEuIlbpOyHerskRB4fzsXDxo4QRdVfFcj6Ks8UZjsrzg4uIRKA0tArwNRiNs22W93pGlKXmWYZgmXdv0XgVd/7NagiVa12iaToOKY1t0LT178UTT1CgKGKYxWM395m/+Jq9fvRJZnYpwy1IUaOqGw/4AtSCBLRbn/NEf/RE/+vGPOUYReVVwdX3J3XqLZpropompKpw9ekR83KEbBrbj0NFx2O95+vQJ+92OPM+4ubrGssXKcTobcXZ+ThTHZEWJnueDH6JsxauqQtN1LMdGUSFJUgxDRVE75rMQVVU4HPcoqorn+UNEgHTAkgQmXdexbWHWMpvNhjWlBAYl8eghoUkWAenJILNS5BpTang0U+t9NzNO0YnywTZisKD7FdfXoigAw7ggyUpy1/7BBx8M4ih419vQ9/130Ni2bQWAg0kQ+BxPMYoiaMqqahEGAY6hMxqNeXpxRlJlnPKEKDpxtrwgi1Nub+447SPmiyXb1Zrv/tb3MDSV9WbF6O5WoP6HA9EpEuq1QyRuomlTF0L9OJ/N/x/q3iTWtuy+z/t235/+3P6+tl5VkSw2kmCRFBwhsQcBEjhA5rENBIgzySyzjAJ4mkTDAA4CaKipJMOIHAmwTVFiI1Ji9c2r197u9Gef3fcZrL03iwnpRFQQVM7o1auHuq/u3Wedtf7r9/u+HpZ6c3uD67ocHR0JSe7dQkBNCyEnOT4+Zmfb3N3dEkYhsiTx6WdP+fTTz3jw4D7z4wmu57DaHoQVSxamo9e3S+IoJs8KJNVgH4RswogkTvoHWFINVODk5FRYhWSdsmrY+iIgMxxP8Pd7qqri8uKCi4sLPv3oY3GF5diMRiOCYE9dlwxHA3a7FUF4QFU1NFWns1YfggOmbZNmOXZ75RVFEd5wxGw6wtTVvri1226ZzWb87u/+Lr/3e/9Tey728TwRzf32t7/N6xcvBQLd0GnKggYIwhhZUQmTmMl4jKLoRGnK+x//kLvFgrKuKRvhsawlmYZGJFGbiuz6ClvXieOQ27s76rLA1A1qJK6urlFkCeSOTuVyfn6O43k0ksxoZvDq6ooa2uixhqLpYuDY1pWzvGmtW3UP6dV1rf11ymw27yVCkiT1PInb29t+YehuF7orxo7X2aVWy7Ls5T0di+OL2rhO7bdvf57DwQAJcYWt6TqSLJPlGYoqyodffnBrG2PtaqBfHIZ0qjCxSmZ9TLT7BnYk3S9alCzb4Oz8hDD5XESKG0EySqOQ0/kMrf1hDl2Psiw4ffgGZVlzd33H2B3guANcyyYME/7sT/6E8XSC5bn4QcjjR4+Js5wH8+M+FLLb7Xj05E3u7u5wUqtF1W+Fh9Hx8Pc+241ocnZgE0nRCKOY+Plzzs5Ouby4ZLFYtNHZEkPXePfd93CGLg8fPaRqB1qmYRJFCZcXl2y3B6JYPER5A2EsPtFub26F38D1MHQdVdHQLJ1CLciKEtcV5/vuAcyyrMeCXVxe8PSzp5yeX7T33gOSduHsuBdBECDL4kFWNY2yw8lLklCfqWIRUBUVRdYACalpGI3HVO21WufIjKKwZVg2fOtb3+Lm5obNbi8eZlXE0yVFJUoSDFVFMyySvEAvK55f3/Di5hpF1dhHEZphkJQlcZriDYdYrkNelcRJTCzJaKqGJCvohoplW/iHA1VZkAQheZ5xCAK+/o1vcHn/PlEUkW42SFVFFCXkhUDPZUVBBbie2894ylxCGw4wTJO6Kls/qSl2jmXT7y67uHnnL+16Kh2sV5Tdln14T3RDIobDYX/ccF23h6l0tesOjtPNIsTPKET5goqxt521arkvZoD+z68vxaLQDUk6PVsX8Oi+WV3/XlHC/n7+i469xWLRwyc8zyOIU+7dO+fFy5cUZUFR5DiWgyYLY5TtOIDEfrvD0FTkqmZxfcN8PME0HZBVmrLisPeRG9htdiimxdtfeYfVasV0JviJ8/mcIAj6aPEbb7zJ3/z1DwkCwTRMkpSbmxuqqm4TgSq+f2C93mA4IsyiKgovX73i7bfewjAN9rsd08mEIs9wvQFZWbE7iEzEwRcuAQmZqlHwffF1DlGIH6UYtsPQFLajPMuoGhnL8ihLGA4GFFlG3cRMp0KoaxsCH+7vxMP4zjvvYKgacSSuqwzDwPd3LflKgFWiWGxRm1rEa23bZrtZtVwIgyAMsB2PyXiM7Xo4touhGZR5IY4aaco3v/lNXr582Q9Moyji8eOHbLdbAXxpP5HrRmjWgjBiMJyw26wZuA61pBEkOVkQsY1iwb9QNVTLpkxTLNdpa9UNYRJDXZOVNcfzOYv1Gts0SdKE2USIf4umRlIU3nzrLTTD4Pr6hiCKyIqCyPdZLJcEYSyucSXQdIOmqdubHwVDE7avskg4Pz/r8XkinjztKVyyLPd0qe6mrTOh27b9BYuXyKPcu3ePq6ur/s91OEFJkvB9/xeAvt1NRfde6kQ/YRwJ6nhZ9CWopmn6K/Rf9vpSLApdJLO7S5/P5z1EJUkS0eff7SFXz7YAACAASURBVBgMRgJfPRj06OruzCXuh0X6y7R07t+/xPuZw2bjs9tv0VSNCkl0KAwTZToR9dG6Ynm7gKqmzApqrUKW1T52apomqmlycu+S29tbLMvi7OyM4+NjfN/nwYMHPH36VESOk4STk1N8X5wF67phNpv3gyMAw9CwLBvZsBhPxvi7HXKo8uLFS47mM6I4RjcMFAQYoypyXl7dtNFVWaDt0xzLjVA1g7yqkVWDsg64PDpGkiSyNGe5WGAaJq43IPAPuHZFXSPeQIp4MLzBgLIoiOK4f5A1XefJkyds9+KaS5CAQkzbpiizHhhTFDW6Jq5KVU0j3e+xXY+8qJAVBdcbMJ3OGQ6G1GWF0jYkPc/j9PSUjz/+SKDLZImLiwsePnzEj370w54epJsmaZLgByHjwYC8rJA1g1pSCJIMyzIparA8EdIZeWLXN5pOSdIU3TTY7nbCb9mAIskEcUxTVkLwaltIgOe6VA0cHx1zef8hSRITBKE4f0cx2/2esqpb4rJYqIDeNdoVoGRZAkv8OjW0lrdY4XkiptwFkLqt/xdrzp33Eeidpt2z3PV/OuFw98buFABdbLlbhLqjSFeW0nWd9XrNyckJhmmyb7MMo9HoV74fvxSLQtXWbAfjMVq75elwUZqm9fe2vr/n+PiEy8vLvuzx05/+FF3X+/RemqZ41gDHNTk9O2axXJEFQvAx9kZIgwGyIlNVNTIgNRWaqiBLitghtI1Nz7SwvSFHJ8ckaYbnOnz1H/4DhuMhZV6SJgnQ0NQ1vr8XRanDgSKPyTJxVWWaVjttFvTkIDi010getaqzXm/57ne/wycff0Tg+2y2O1GprmqKqkKKI9B0aCTyLMc0baqqxjItaGA2FWdTWWo4PT4lDiNm0ykPLi+JDwd0VXgOBwOPqhKK9jhLkHXxcDXtEW0w8Nhtt+LIE4RcXFzwxuM3KBoFRZE4HHYUZUoYHfr77yLPaWpxDj+EARUNaZ6haSZV565sGpqqpMiy1vOQCSXadMqHH4ruiGs7vP3223z/+9+jLMteAlMUJYos6MtJlmPqBpbjkaUZiq1jeyO2/o7BSOwsJVlwYppcLHb+wW///0TBzTFddrstcRjgOg5ZWZJXNYqqYVg25/fv0UgSg8EQVdNZbbcEYURdQ1nXxGlGXhTohik8F1L5c6ej2lKidZ2qpSRNp5N2oRW7ru7KfTAY4Pt+H2fuuInL5RLHcZhOp30u5fb29heKVNDW0vO8Xzy6I10H8ukQ82maErRN46ppaCSJ9WbTg2W7ReiXvb4Ui4KiCrPNfrNp7b1ObzPqVsn1WiDC5TbK252VHj9+zO3tbV8ssW0bSZPIypyzsyN+9MMUTROJNMsWjcLgEKBJCqYmo8pg2iam5VAh0ygqjawyOznhq9/6TbS22+4MXYo0I9qL867v+6SZUM7vtytm4yG6ImHZJ5yfX5DnOdfX1ziOw3a77Q3a2+2WMAyJigOSLPODH/xAtOaKnLoWK/0hDHvicCVnyIqCLMlEQYBumBRZAeMx+90W0zBRZAW97ebbqoZq1FycnIhh7XoLNHijMcPxkNWzNZ4u0FxZO4+wLbsviSmSmIcgydSyYADqhsHr188xDLU1Ghskyc/v2htZQtVUirKkIaduxGBQlTXKvCSJY46mMw6x31KJTKIoxLIsjo6OaJqm3/ElScL5+YzhcMh2u2W/2yM1InWZZjmOK8hMcVZSSyppXnByckKSxJRFjucOqOtSJAmrmtFoCJLM1dUteZaJnZIkYTkOaZbz/OVL3nj8CG8wwnIcZEmmCCOSJKMoKxRNoNdMU8w2GiBJU0xNaktFDZoiiyFjIm4gTF3rewemaaPrgglp23a/C06SpDeGd8j9LsvRDRU7bN4XhS9i9+H9wrHVNM1eAzCZTES6UtNwXJckTftFZ7ffo+vi2lr//4MMpit5dDj0bijX6dGur6+RJKVPdyVJ0jcA5/M5aZYxOzri7uYG2ZDQdZV33vkaH330lBfPX5OmMWki7D5iK47YpstC4lI3DZqpMz89497jN7DHE3TDREKCpuawXvPixQuyLOXTTz7tS0e2bTMdDhmPx5weH7Fcb3p562Qy6eux9+/fZ7FYcO/ePQ6HA89v78TZUpLZbLc0LS5OBHnaW5aqwtQFmSepaxQJDEVGNQ2oKlzLxLYc/MMBy3Kp84IyiSmyDEvV0CQJVZHI8gJFkymrnDSNUWK1V4p112PT6ZTVasXQG7RkH5+iUTAMrT3+VKRZRF1XPxfQ1FIfpsqaBkmW2kafiirryJKErEAURiKKqzY8fvyYq6sbPG+A6zp8+9vf5vd///fxvAFBIL5viqwQRzFpIkxUjQRFVSMrKoqmCzJRXnA4BFxenuF5Q/I0Z3Y8xTR0Xrx8hlzD0HWZT6a8eP1azGc0Eb82TJOgPdsXaYbrebieh6JquLbNs2fP0Ayd6XSKZposN1uSFmlv2jaW7aCS95Vk8SyUZGlJoipYhkgrNk2D6w76K8zNZtPr+jr4bpZlnJ6eYlliVxkEQU/8/iLjs7NLdUTusiz7W4yuTv/F9myWZSBLHB0fYdlihuTVIvosKwphFP7K9+OXYlHorl8G7ZS1c/IdDgeG4zE3V1ftGc7sZw+KovRFj/l8znq9Jm0HWa5pY5o6g4HH2dkpT58+R0IhCA5oksTQsglNC0VqODqecnxygqobFDXopgESWIZOI8vsAp9P3v+AsWPy6sVz4VqsBMnGtgwsU6csM9arBffu32c6nXPv3gOGw2EbOS745JNPuL29YzqZsVgsMQ2b4XCMf9jjuR6z2Yynn31CkWdtfFXv669NHbW2ZhlFljBNYZiWJFVUwdOE4cAjjUKGjs3pdMaHH30ottK1zPn5GcvVkjxPOYQ148mYnS+utahE7kKR5P5+3NQN0m4QlpXsdqJboesyRSrMyJIkiwx9VopbEanEsEzKvETXhLhW0cVwLTiE1KXQ6+maxte+9lX+8A//CE3TeOedd3j3Z+/iOA6Hg9/DbHf7HXleMp1M0DRNkKp0g7qsQFaQpPYGwcpxbRd/s2c8GjGfzVgsbimyHLklWVuGgaaqlAiYrKZpAhMnwd73mY7HZEXJIQx4eG/C3c0tWV5gmjab3ZYXV1dELcHasi1kVSXLM7yhg2HoZFlKmqUkcYRl6TityLcLE4lSU8HFxUXvcex2jWdnZ/1RIcsyNpsNcRz36cPBYPALMwjHcRgMBuJ7tBMFuo9b3MB0Ou0bxoqiiCtT2+rj0EBvIuuuQ3/V60uxKJRFQZZEnJwcYXWrXF2TFxl15ZJEIaOBi6pbKIrao7Ety8L3fZbLpZiCb7eiQrwXlBpbsXn84CEffvARkqwycIZQS6RNQ1KDV8qYjY5neMRlgW4ZeJMxpmvTyA0f/OwnPH36ObHvc1UKbJvtOBwNJ5iOg6xp2O6AyXSK63mCzaDCwT8wP5rjuBbPnz9nMHCx7AeiQ29oLJcLRo7F+fGMp5895Wgy4pvf+DrvvfeukLuqGiVQlyVhkGIbJkcnc7IsxzZsXMvl/OKC4HAgywosXcc2R6zXS8zQRbUtFFmhaWQ0xcC1hhwOAbPRBMcqMVyHumqI45S0bLi4/0jUcOuGpq6IqpzJ0GVoaqzXSxRFFv7KMqdpagzDRFUU0jpDlhUUNBRJpZYEkamuC/KyxLQt8jLF8Rycoctmv8O2PXbbA6qmMZnM+fGP/4qmES3DwUAcAcs8RwZGA2FQ1lUFVa5ZHzYocsO9e/e4vr7GG1ikech6vUFSL6hXGxbLLUlWkyQ5F/cmrLcb4iSlbGSKsqQqxNBQVmTquqKoSj7+7FP80Gc0HrfN0zYIlOVIDQwcD9cZUJQVcZZhGzbjwQhdV9lXNU2ei0Fq2SAjUZcVjmUzaGXBXXS/A+h2QaSOxj0cDlEVmcHARVNliiIjjoToRZElLi/OuLq+xtBVwiDAsj10zWK/O6DrFifHZ0RxLNK/io6EgiKDVMvURUMWZ0iNxHw8RzcMguDAeDD5le/HL8Wi0NQ1/n7Hq+dNTxIaj8e4rssnH7yPruvcv3fJYrWjbprehdiFZzoEeSdZHTtjFBSW+w1fefMtnr18zr/93veJ44TZ+AhZ02hkFdcbMZvMub1ZIJk6E9fBdWziJOFP/+RP2k6Aymw0oopS8rJAlmRR265qptMRF/cf0rTIc1VTWK+uefX6FZ9+9ok4x7V30iLfLjGbTdB1lTTN2fs+X337LbbbLYPhkG9+/Ru89+EHpFmGa1tiV6TqDAcjqCVmk5lA32c54SFAVVQ0R0ORJZIixxkOkDQNdzikLCpM3UZBRlMyBrZMFhVUSsVkNkGRNQ6HiIMfUjUS8+MTYeZKI2qpoawrzo8v2G7XIs1YFyT7EElqWiBNg6ZpRFGMrBtIyEiS0h//bNsRRwlFFsPZsmQ2O+LF81fkecHX3vkWz549JwxFVXrc+jZVpaRAtDU1VaHIMyRqLNMQnQy54fb2iuHQYzh0URS55WmWJEmGrGiUFZiWy9XNHWHo4w2GyIomZiVNzWa9xtQ1LMskjCJkRSErCj79/Cla2ZDlOXGSELRhIcNy2O99kfJ0HcqipChK5tMZ89mMjz76gCaq0QyDLEnRFZk4ijF0nfnxKbphsN1umc/nnJ2d9Z2ELqvhui6qImTHWm8DW6BrOuPJRBidTBPHsWkahbKk5V7K6JpBXcN0MmO1WhEEEVUlLOLT6VQMl8NYuDKRsS0Hzxn05bZf9vpSLApCeKmRJBmWJVqLUZRQ1yAhk2cFy8WKRlJ/ATfVGXKyLOsVWkmSUIQ5X/3qOxRyzeu7Ky7Ozrg4PyMKk1aBtkduVKLRiOvVEmvgMjs54v7jRyiayp/+2Z8RhyG2afHWkzdJogRfCzhus+qjyQTdtpkezSnygu1uj3/Y8erVS9arO3zfZzqd9np4gJcvX7JsNV4C/V6Qt5afpml4+eolpmVxfn7Oar1i13L2TFuhKEsmLfLdMA1msxlxHDMYDpAlsb3My4Ltfoum6miqjmXa1FVNg8RsNmW32eE4HofYZ+R6JEnOdDhm7I0oixpD1ahrmSDdUtcF/nbHyBaL0IsXPqoqwjO73RbX9drhV4Rl25TtgFQQs4VWLgwDwjCgKmvSNEGWFU6Oj1mtVoxGQx49esgf//Ef4XkCwmvbNkEoZCme/fNmaIemD4IAy7J68pTgT465unqNZdlMJzN03SSKIkzTRDc0iiJlPJ5gmCayIpwXVWvRNlSVshLR9cPhgGmanB6npJWYpyyWS7Z7nzBJqGUFSZF5/OZjXl9dochCDa8bOovFHZIk43oeErWwj0tiocqy1u3ZxvW7uHJX9GsasetRVZX9ditamS3eXzRNc4JDwMEXDUpdE96H7XbX3zh0bcu6rvsAX2/aapOOIkRV9h4RTdN67sYve30pFgVFVTm7uBDKK0Wlbn9vs9uhKErr2atQNaMvl3QR5y7L0J3BB4MBhmKyXC3IqrwlNJ0KItNigzG0sGyTqqmI8pTGnGGPhjx48gaSqvLxhx+xXW1QZJlHTx7gmjZRkDA4OsF1Pc5OTzBMA9MyOAQHbm5vuL6+Enz/vIC64eH9B4KiYxicn1/w6tVLdtutANIGQhleNRDFMev1Gtux2+q2TFrkYorf8hrOZkci1r0Xg6u75ZKoRWuhCBSYLMskWYpp2CwXK46PTynzlMvLS54/fY6maYzGI9arNWeXp5wcHfPi+SuiMMD1BqJEFSc0Tc3AdvH9DYal8/nnIhFq2zavr14gy01vNjo/v0TXxR161f4dDF14HJI4xbYdijzD1HWkpiFLYjRNYTIZcXF+xmeffoIiS2iacEDUVdnPAqr2Ae6m793C6jgORVEQxzGnp6e9N6Fq38iGkZNnJbblsNmuGI48xuMBSZqyXKwBCV3TaZr65+E4GsoyY7fbcXV1QxAGRHHMIQhEYlCWcMdD5DhhtduQlTlSKfPpZ5/1n96WZbNeH5CaGtPUqeqm/SSHpGUwjMdjfN8nDEOm0ym3t7d9lmA8HrP3fXF92AJVu/lA94Y/OzsTGY62f6Hrem/0sm27P5ooiiLanYrSm8o6K3tH7vr3pRnhS7IoaJrGZDKhKEvs1m3YzQ00XcexxfCmrBpBXq5E3bmLQruuK7ZJrV9x4AygkXANj0N0oKlKHj98QOiHXF3dURUNriO286Zn8uTr74jsfBQJKOtsThrFaIrK4uYObzLFO7tgdjRDVRRkSWKzW3P9+hVRdOCNNx5BI/4uUqPw6tUrmkYsDs+ePWOzWnNzdS3SaIDrOOiWjddy8va+GLKtNxsaGhFoKXUxH0kSpEaALsv2U043jN6rCbDZbNAMnbKsGI/GvHz5krff+ko7tFJa2pTB0fEcVVGYekM4v+STTz4n3O4ZjsYksRDoDEcuqaJiKCrWbMRicYvjuqLNJzcoiiBta6rKxcU5V1fXFFWJrhuUVUWRF1RlhSwJeIkkizq7rus0VcVhv+fi/Izr6ytGgwFFmbdodNFIHA5conaB7MA7HVtwNBoRhiIW/fTpUy4uzlBVjbLMcR2X3c7n/Pyc5XKJZdltkKegrn8eNTYNg7LMicuQRqqhqVE1lf1uz3uHgEZVkCQRNW8QXo74xXNUVSVJU1RNp6wrmixh4Lp4nktZSzjuAEVqUBUZRRX9GiS5F/Fut9uep9BRl3zf53A4iHxIFDEeTSiKgiCIeqJSFCXMZkcoitaGkcxfALceHR31IuUuxdhh9GVZ7mneAhAsFpwsyxgOh7/y/filWBSquibLxSe9bphoeYE3VEiThCwTyPXuqqu7Buw+Sbrwh9d6+IIgIIhDZEnh0flDqqYEGg5+wPnpKavlljiJMS2Hy0cPuP/kCYc0Qd7u2G02FFnJwB2iSSp3tws0ReX+eMr04hxZgv1uR1UUROGhjacalHmOqipEUQiNyte++lX+/Pvf57NPP2W5WqHIMm+88Qa3Nzc9DUlr3RJN06C1fXshdxXW6QIRMx4Px+SpgHUahkEYiXOu53lUtSjglFVFk5dYlkPTCGLUvk3z7fZbyqrg4f0HVFVBHIXc3d6y3fpkSYLjeJwcHaOrKq9fv8I25xjzI168fIU1EA9f2SbrtruV4FlaNmEUoSiCCSjLkmAEyjJ5VaJIMB4OmY5G5EnCZDRks9lwcnzEq9evOT055nv/7t9y794FRVlgmga3t9ccH81bUVUjehMtUKZrBna14w6VXlU1h0OAImuUZYWq6uR5SRwngIQia+R5yfXNNapqoKoab7/9NoeDz2a5RNNUFne3pGlC3Ma0y7psqVkykiyjKQqmJeY7pm2R5xllXVM0GlXdsA8CHj98iCI3XF+/hkb8Paq6QaoqirJEabs23Sd0dzVZVRXz+by/hu3iz106UZZlhsMhnTy4s0eD1AengP6olSRJz2LsSnHd97CDu4zHY66vr7/82jgAVdfZbXdohslmuxPXk4ZJWRTEqXDnubbR9w06tn5nWu6su47jIEkyum1ydXNFkaUcH82pq5owiFitdyRZxaM3HvPq+opagvlsxtgboiIxn0yRkZiOJ7x49pxvfuc3OLl/nyjPub655XDwmU4nFHmBqinM50fs91vhDhiOKLOKv/iLv2DbZsuHrR5+u91SFAXj0YiT42OyqsL3hdjFME2qJMaxbZSWP9np4uumxnJsirIkDcRQ1XVdiqqkiiPiKEKSZZpSFhzERuLo6ITNes2DBw/I0pSD79M0Na7r8PLVkuBTn4cPH5OlJaoiGnnz2ZymEY6C8/MT9oeAohEP5eb5CkVRBW26hYPWVUVViciz61gtpl4VR4iqxjQNojDgaevvnM9mfO2drxLFES9efM7xsfh6uqaxWNwSRSGyTCu/HbIPhAzHMAyCIKBpGi4uLliv1z3Q9PXrV7jugOFgTJFXLdpeYjgcURQihrzZrjg9OWO72+M4Q0F6ShJ0wySOQsIwRpIaZEmlLGtyZGS5RlFAQQCAaBpMTQy29TZDU5U1hzAkzTLRapQahp5LFB1YbcUHz3g8QlG1Hu7avXG7T/DO8CRmKg5pkqLrpthlICNJMuPxtJcSK4qKYVg0COjOfD5H/kLpqWtITiYTVFXtG5udkapbYLuw1K98L/5/8o7/v30J21OWCwaBZdstJ0EUgY6PjhmPxxx8vw8vdXTbu7u7/n/Y932qquLBo4eUZcHi7o6h53HwfVzH4rd+8zcwLZc//8sf8fr1K5zBkP0HH/Kdv/fbrG4WGIoGDxreePiIyXTKxYOH1JJ4UKsG9quWvHvwOT8/QzcMVuslhiEip7c3N6xu7sjzjP12S12LdNp0POHu7hZZ09lutyK9pqq4A2F0KtpPjjAM0aVe6yiGeWVJ1i6KXWBqu932+XYA2zTJs4qqrDg6PWW73VDkBVdXYosuSw1B4CMrYieSt32Hy3v32O32qJqG7+8ZTyYEoc/t3a2AjBQyi8UtnucSRX7/9QaDAbvtvrdVp6lA68uygqqoVGWJaejEccT19TVNXeONXHRV4cnjR/zBH/wBSRJzfHJMXZcc9nvKMmedxKIFm2e9/UrTNC4uLqjruh+OdR8Ag8GQ46MT8rykKgFkEbJKMyaTIdvdGs8dcHN7g+N6vPPO1/j8s6coskZWpiiyysATWYDcTMnbmxNoRGeCGqlpSKKIuiWIq4oigmaqhbBeSe2cYEyaF0iyQtPkSIpCmudo7eJgGEYvd3Vdt91hyT056fT0lCIv2O12vU9y4HlEcdTSsx3ubu/I8gW24/LkyRNc1xXp2Db/0D0fXXCqO1J3acmO4dCV+X7V60uxKDRNje+HjMdT6loiDBPqWhKDr8EYy3HJ8pLT83P2223v0Yui6Be64Z1Db7lasd1tuDg9JU9TbNNAkmRkSePoaM7JyQmfPn+BWbmcnZzR1DWL2zuePHxEeAgEsdmxkQyNcL8jDgLe/8lP+No775AFe2ZHxwS7PUmWMZnPMUyLn/zkT1ks7nh0fkocxyJ+3FJ2P/v0U4qiYDKZcNSm0BTLwg+C/jgUJTFI4oF3XJfBQJCTh4MR282GGsFNNGWLqhTb0qStyh7CgAeXj9E0gzAIGY3GjIZD9rsdk9FQ3Bps1yRJwsPHj1htNvhhyGR2zGg6IUoTRtMJ73/wHo5tEqchmqYTJzXz+ZwXL5+haRqz6RTDFBLf+dERWVq0Fq+05WEoPQvAcWwkSaZpKgxDZzab8r1/9z0R761KHNtmtVyg6xpNXSFLMqal49gWyXbP5b37AP1D38V/0zRlPp+3cpSKsqyIwpiiqLEs4W1UVJXFYoVhiG370fwI3TD54IMPOT89Ex2aoxN2uw0DT8Si97sd/uFALbcrcl1TVwVNXeGYlpg9KAoSDUWRt2/+RjQmkUjSjMuLMyxTx99vKYqcppFQVSF/6cC7tm33HQWgL0ONBhNMw+K1+prVakVV1qiqjqaW7Y2BKgjSctITnuM4btWHQq/YDWZt2/4FhHtZli0rwulr01/6K8m6btBNg8FoJAZMjZjWZlnGdrvl6lqwEMu2O9CdoY6OjlitVn3Ky3EccSYrUhRVJc0yRq5HkWVstzuyqhEMx8mY4zhhsVhzdnzBRx98zGGzZWC5DJ0hzmCI4Tg8e/Y5w+mEZy9ecHl8xHw6YbfbE/p7bHeAY9lopsWzZy9wnAH/0T98h+KwE+YhVeXu7g5Zlnsu3/n5OXmec3NzgypJqO3uoEurifqxCjT9vKRuaobjEZvNhhqh2JMUmTzLyFrFeSPBi1cv+cY736Isa7F9N4QlKs8z8rzh8vKSzWaNZZm8+fZbHPyInb/n4vwS/7Dg8RuP+euf/TVJloIEQRhwfHyfm5srjuZzoKRuirbaXveg0sPhgK6KAJrnesiKwqBdqMsypyxqphMbXVUpy4IwDPohomkaeJ6Drqvkedrv+mazGa7r8vr165/ftbdp1U6E8vnnnzObzkmSFFXRGQwmrNcbQXiqSh49eoysNKiqzPPnzzFNG8u2MS2L0WjI6m6BYZhMx2OSRGRcakBtoMgzqtZOpckShq6IgF2aUBU5IKHoFrohHBuyrFCVFTc3t2iqjHAMSTi2zWQy6ZOadesU7bR+3af3aDTC3wV9wU1YtEJ2u13PVOxizoZpkOV5D2+ta3Hks9q5Rzdv6W5qusp29z3P2uPOl36moCgyo4FLHAXYlkVdFsRhgO+LVV+VJfzdBtcwmE1n6LrGYrEgjmKitiTS1DWj0RhVVZBkiaPZnDA40LgeN3cLkCTKqkaW4OG9U26vX3M6n6BrCvsi5/TykqPzc37ru99BkiX+tz/6Q6azKaYq8+jynLnjsL65ZRscOL28xBt4oGkE/gFZkXnw8CEH32e7WFBVFS+vbjBME3c0QTFs6rrh85dXNECaVeRygm5YzE9OCcKQKIlQDNHTb+oGU9NRGiFlLcoCbzjCsW222w15Jlb7pq6ExbgQScePP36f05NT/MOGyWRM1ZSohs5oNKQoS1TT5Kd/8x7f/Z2/T56VNO3x5nDw+elP/6plV4SMRh7TicfrF8+QFZnDPkJXNCRZoy4bAW1RS1zXJokjaHKKIifNVDxvQFkVuLpCsDuQpQVpkbDcrahLuLm9QVEkHMfCtHR8fyfwb6nE6fE9EUWWdVZ3C2zDpi5otYAjirJku99zOPjMTy/YLJc0VY3jaiiGwaO33uLp558zcIas/R1SU6AqDW9/5U1uFiuOjo8Jg4D94cByvSZNE8q8oKlr7t0TiVM/iUjTBEWSsG2LIs8JA584ilAdDaO1cNUoWKaJoshUZUHe+il0y2DkOS0prKEsa6qyQTIUJGTR08hzirwiL3Ic26MsalbLJZvNGoB7l/cwLWHBrioFSW7QNIW6LsnzBMsyUeSGPIup6wZD18nzjOFwgCIr3N7ccnR81AqEZBzHoWlq1usVWZ4Rx9385Ze/fl0V/X8P/FfAqv1j7vZLiAAAIABJREFU/13TNP+q/Xd/axW9Isu4toWpi2GJpkhYhsbg/AxJkvpV8eWLFz1IRVVU6qpiNBxR1zW+72MctWCJQ4CqaSRRyvPgFaoqSlW+7wu3ngxff/sR7334lNvbK568+Rbz+SlPnrxJlOe8/9EH1FWFXBRUhz1H8zlyJSb9dV0TxBH+9SsuHzxksbhlPJny7PNnQrxi6DjugN/5+/8B251PWVXc3S1I84yjRuLFy1fIhk1NQy3JKIZJHgRoto1TV+Rxiq6ITyhLNyglFcPSWSwWRHGKqRtkqbirNnWLLE2xLQtJEjXhINoLyk8WCYBK6HF+71Lc7U+nBGHGX/34b1oOoNJ++ppUdYWiyNR1w+vX18ymU6SmIgkjcS3YWqMDXxzZFFmcrR3HIokLDENHlgWRKI5jdv5WhKl0kyzJUEuVgT2EpmqzJQFVrdNQcwgPTEcneO6YKMzYbK8YjT1cdyiu4qKEvIqYzKbEcUojKRSVCOtMh0P8KOFutSC5uaEG8ihgPh3iGCpVFpOVKbKqcHN326ZBD4wmY+LIIE9SwVo4xNR1hUqD2346V0VJFEaEYUIQRMK+pehkZYOlS+htu7cqc1zHYT6dirlLUyFLwqSlyBq+HwAyhm6hKjqGKzoJelmiKOLfV1XFZrNqQ1y+wLPbBpZloukKg8EAgDA8IMsCl+95NmUbv3dsE5CQPQ/bsgTu/3DoqVrT6ZjlckGShC3t6u92Jfn7/F9V9AC/1zTN//DF3/h1VfRd61FV1b533vXEO2pNN0TsGmPz+byXdQ4GA54/f85yuURVVVarFY7r9mCKbrtmmmaPt3rw4AGbfcTr6zXbzYbJZEYQHEgjcU6bjQZMj+asFrdEQUBRlCR5Dpq4Frp3eYm/27FeLHn/Z++Sxik0MHx8nySJcByb4cAljGKapub+5T10TQR/dvs9A2/AaDLm+auXyLJMTYWqqKRNjaIaJHFCmmSYgyFvP/kaRV6wXq8o8wzbFhIZRZIw2uqs43g9uCOKor780sFqumTbb/zGt/iLP/8BWZpQKAqLu7t2Gl3w8MEDPv3kU1JZXMeen56IRGFVUhQ5ZV21CDwxQ2hqEaAQ3AK5h950dWtD15EVhSAMkTKJYBOgKgrUFXVTopgmiioLRR01y+0KXbWQVGgokZUKVVMIgqXQ+AVLAn+PrMocmhC5ani9W4KqU0oqqDq6ZbeLW0VeNtwuFshLiTgpOD87w5tMuH95weJuIY48rc7NMAzqumLkekwmk95Q1lGMFEXpW7yj0Yi6EM+TWDB1Bu1/p65rdFXFtgUhaTgYohtab/Lq6tKTifCEdgj2OA4oy7ynktvt0aNzPnYzgKZpCKOIPCvaI0GNZYnejyTJ2JbL2dkZYRSx3W5JkhhFkYljg/FkRJYLDkiXc/hlr19XRf+rXr+Wir4bggiZatwvELqu98MTVVU5Ojrqk1qLxYL5fN7LT7pzU10LJfsbb74pGAyyzG/85m+y3WxYLpc9tSkMQ8ajIS9f3WKZOmF4IIkjPnt1xcgbiHP1wRfKessErWR52GOqDvPTE3x/z37vc9hvabKMSXdNV+YoikqaxBimBU3FaOBxdfWa2WzG3/ut32K9WaMbKreLOySEYOTV9TWKomCYpui61w1REFJFMc+fP+fNN99CkcVRwdBVlNEQ6pooDAW5V5F7ZVjnG+wI2ZqmCXS6aXJ5dsmkVZSpksRkOBTmYlUjPkS8/eRNXr++4vrmWmj1vAEgRClpFmMYeg+LifZbFFXFNkXfP04S4kgwBDRVQ9N0EXsuSlRdI4siBq5L1TRYLSA1STPOLi756OOnZHlBUVXYtommKSyXt4RhQFEISEsaBih1gVor1LEoY40HHnerDef3H1ErKqUkY1oOw+GAosg5PjsTjIS0II4jmroiT0XcfTgaMp/NOOx9PNdjs1lTVUrvzfC+8EbvgmRdt0OTjR6DZraBuqQsxdeoSgaDAcPhkDRLaRBAYdd1++p0F8nvas6ObTMcDvuFvZsjdNfv+/1epBazhCLPUFWtlcgE7XtI7UN9WSYSmh1Ve7NZc3NzxXAknn1V1Tpcxy99/V1mCv+NJEn/BPgr4L9tmmbH30JF/8VXXTd90KLLuNvtN6kDqmRZhuu5/Y1D0E7uj46OyPOc0WjEdDoVKu/tVhh1bBtNUVDaWrDYom1IkoTpdMrlvYecnd/nL//yR9QNbNZbLs4uGAw97t+/z83rlxxPpuwPB9KqRNY1jk5OMCyT1WpJkecYqozmuszH4tPFMg0GwyHXNzdkWc5qsyVOUrK8IEtj8rzgxcuXzOcCD//t3/5tNvs97sBlsVyyuFtSGAUD22U8NigQ5/zNZoNtWZSa1g4RBdXIbGG16/W6D/aoqtqeIwVV+fr6WmxXdZ3paMLpyTEH/8DzF8+xLYvBYMjrV68xTZPgEGBoOm88fkKUxey2O3RdUJOahtbuDXVZILVkJbkdotVV1SYjK2EIlyQkRUZTVTRVQzZNNEVGlXQs3aCpRH/l+uqavMiwXBvfP7BcrNFkSWjayhzb0qHMqctSpDtLSdS3ZYmkLjk/npDFe47OLgnTnLrMeP+9d3n05A1QVJq6QWoaZpMp282GQoKD7wtwTVukK6oSy7Gp66InJhstoh5EQe+LH1qG9nOLk9Fq3pQ2RhxEIsqu6zpRpDIYeD2Svfu5BIGQzRRFwWq1QtcV0dloBcFfvGYE+p+lYWjMz8/5/Onn7VxABhocxxbK+zzDqixkWULTVOI4bLmORt/7EAAj61e+H3/dReF/Bv45In37z4H/Efgv+Vuo6CVJ+mfAPwM4ORKWJdM0xX1tC4ugvV6ZTCasViuRMDMMtDZA0qUZO5CJpmmUZYlpmmxWK1zXZblYsFws+jv20Wgk7tl3O1zXY7lc0zQFn3z0AQ8ePeHi8oL5dMpiucQ/BBiqRlmXVDTM5nNUXaPIUjHciROyKGLsDrg4PUFTFV5u7virH/+QLM2om4bp7IgizwizmKa02G/X+NsNr19+ju2K+vX87ITvfve7ZHnObuvz3s/eZb/doasaqqLhDobc3i4w2uu7pqqwbQvHcdvvm4HjuGia2icfl8tlLwrpev3r9Zr33nuXJw/fYDQewoumnXBbWJYl5DLDEZqq4nlDji/OeS9+l+BwwLJ0TMvg9uaKqszYb1NkRabIchRFGL5F4KoiLRP8lvFomBZV22Z1FZWmqjEsE1XR2O8OZEXO1t9j2iZllZNlMXlaUkmiJOe1zkpNlXHcIU0NTVljmTa2rYNWY7sukqqT1wUD28CPEt566wlRmmG7LtvVGqOqudtvRQU8z5FkGZqGvEjF7szUQYZwH/Zat07E2m3zPc/ruxeqRM8myIui1xNK0CvaRqMRhiGq/oeDSMDWdd0Cg6Q2qCWkQVVZ9cG8ru/ReRzOz8/ZbrfCEyqDqim9a1JRtL4kJsviVsp1XepGHNHqukQ3xHF8MpmIlOx4jPx3OT78slfTNIsvvLn/F+Bftv/4/1hF3zTNvwD+BcDbTx413f1q1/TKc1GOMQwDpWXZ0cjYts1quRTXem1CqwNT/OxnP8NqZR+T6bQvlLiu2+PMuwDJaDRC03TG4wGnJ0dc39xhWwbvvf8uQ2/IaUtzilNxRTeaTpAkmaE3YHF3R9EOPseuyxtvPKJIYoJ9wmp5h9PWfKMoJokD8QA1NR9/+D41YBkaaSITRyFxnnG3XvLs5UsePnpCWZT843/6T/ng3ff56IOPCOIY1/VEajMS50FN1YjjBKkFsRZFQZomFIXSo8S72Uw3l+nup29ub7ANkzffeovpbIosK+z2OwbDEXlZs1ytuH//AftDQJCnfP0b3+SHP/hLkjRlMh7w4P59Nuslm/UCuWjQdI0kETJfXdOEih2o8hzNMFAVpb9CNi0T27RI0oyktYWrus54MCCMxZth5JpM3QkDb4ihiyCQaxuoskRVVEi1gqYYOJaHotc4A40GSYS8yhJ7MOLZqyuSIsfWDQ57H1MzCA8rDge/vdoTzcy8dSLUdcWLVy9wLBurRal1JPH+jZ/nvZdEURTKPOvnXY5tkqUpYTvY01W5b/Na9hhNE/Sqqqp68O+HH37Yh5K6r9NdW3Zyl+5nd3p62vshkyRGU7V+N23bHWo+JQgOuM4A0xSFwKLMsGwDkPrehW3Z5FnJwPx/mdEoSdJp0zQduuU/B95vf/1rqeibukaSZWRFYbVasVwumc+FQKNqz//73Q7TFKuvoij98HE4HPbHi/Pzc4EGa/v1WZYxaek9w+FQHC1Ms6cKh0HAwLM5Pzthu9sThQFxkjHyhvzVT3/C20+ekJUFnuOw32yxHBupQZzlg4CvfO1tpp7Hp+9/yGwsYqsP71+y2+1Is5zXccx6tRRbwbzANDRhjFqvkVVZLA5Z2jb9Kj7//HP2/oHrmzt+5zvf5T/+T/5TwjDiz//8e0wmU3RVFWfiLOVw8NlttmjtgykeOLN/oLtPug78Wbc9icHAY7lbYd06KKbGbrunrBqyuuHtt7+K9Plzbldrzi8uWG5XlFXNZDolTWLCIMJzdDzXJglN8ixBU2QqTUNCEjdCekNRVj3JKU4yVEXFdVwaqaHRFMqkwVA15KohiRImkyHnjx9jW5r4vpjiZ9xQUOQJcSyqwxVC6Go5Q8bzIxzPAKnAMA026zWSlJJHMSfTKS9vFsRpCFXD3t/iL8XnmKrIHA57ZEXGtCziJKRsqci6bWBpRr+gdjOqjqL8c1Cq6DOoqkoYhsRh0G7XxU61qsrWM5m2eDW7l+F0lXrPEwv9ZrNpE7kScSyQAL7vM5lMqOsaty2jzU5OuHrxAse1Remq7YbM50e8evWaohDimK7bIAakGrqutSGvks1mw2q5xnW9fhbxay0Kv0JF/x9KkvQtxNHgBfBfw6+voq/rmrvbW+Io6s9wWZZxe3uLpuu9xSjPCkEjCsWZrdsad3bdriVm2zaSLLZnZVmyXq9/oS/heZ7YFtKw3ayZTkacnZzw/R/8mOPTC4oyFw6G/R6amigImXhDNGSiQ4i/2zMaDQmDA9vFLbPjGXLTkKQxa38PsowMGLrKZDggjWPyNMWybWpdFQSdKCTOMqpWoGIicXQ6EyWbnc8f/8t/xVe/8jW+89vf5p/84/+Cf/Nvvsd77/4No+GQ87MzfvrTnwhEW7uQ6rrSQzt0XW8HSmo/IBPMCoUkTZA1iSCJGI3GnN2/4NXLa5IiR9Y0Lh48YLFYUtQ13mBIWZXohoVh6LzYLEljn+lkyGw64XDYkaUZtil2Z5IsUxRla/uuaeqaMi9Q21JOI9fUErgjQcR23QEXZ+ecHE05PpqgKDW77QrZqBlMXB4+epuHD84JwgNBFJFEJZ99+poP3vuc7bOA2eyY05Mj9EZn4I0JA5/JbMpivWbieexfXRPEKUkUYbU3T9SNcEs2AqYiKwqD4RBV11iulgSS2p/tu+eqc4p0zseiKGhKcYzYbrdQC2Cw2gmAZTEDEPYr0QPpmIvdTKELL3VXjYauEIbijer7fh9g6o59mq6LdqquYlkGpV8yHA7JspzhcEgYRq1KUZild/sYx7GwLLvnd1RVRRwlVJUQC/3ai8KvUNH/r/+eP/+3VtGrqtY7FjoRTBiGpGnKi1evKPOcOIpwbWFbUhSF/X7PyckJ7777rkg7tljx6XSKf/AZjUbcv3+/n8ROp1NevHjBarVis9kwGo04mk8FBstzGU9GDIdDFoslo+GYyWiMIsl8/PHHDB2XapJRFgJ6YQ9drl6/xvMcyiJns9ugSgKKUbXVVd0wcF0bx3F6uEVwECKYsqp676IkQZEXZKWPpOjcf/CINM0IDhFJkvKv//X/zvHxEf/oH/1nnJ4c896777Lf+6IaLNG35WRF6PG6XUHnFHRdgTTryMuj6QhZU7lbL1BNAwuJydGcPCu5ur3l7OyCew8fstvtePLkDX7y4x8RZxkD12I2n6NQ0pRiJyZLElVVIEkCwy9LErIkt9ekhvhUtywUTSxOURmhOxYDe0hd1BxNj3BNg4f3zinzmMBf85vf/Ab3v3bByfkUVZfI85hJpVLWE/JcZnw0QTI0nj27QXdMVN0lzSsc00EC0jihTHOSIGTkusRRiqFpSHXDeDwijCJIhO/SskzKpiZOItz/g7k3idUsvc/7fu+Zp2/+7lj31tRdxWZTlNWiLNoWiRgJEGeVrBJkGSD7bLKws+My2yBRgMhxYCcIkAC2EcSLWIgFqU2KUmJRpkj2UD1V1a2qO3zzcObhfbN4z3fUckgBliGjD9BAo3Cr6tZ3z3nPf3ie32P1iKKQbL3vtgpf7u01OWqKZVmMRyPyNNErx8EAoSRSNuQtD8Gx7M6ZCJDnOev1mg8++IDxeMxwOOy2Caenp22rLFsLedUlnWnXbMDt7W03cA9DH8Ogg/XojYnUGx/b0QPwqub27g2n96aUZcV+v2c0GmOZFpZls93u/txDwfze9773r/P8/qVc//1/999+7z/+D/8DiqIgz4vupg7DiKptBaqywrJsDddotfDr1apNe9K7W8/3KFuZ6GGqOxgMWCwWbFqS0QGjrZRitVqy3W6J+n3qWjGfL5gv5lxf3zAejSirErs1WiXbHYPhAMu2qGXNPt5hmkZ7EDRsd1tN7J2v9UlcVgyHY/r9AZJWc+HaKJQu7wwbxw9wvADPDzAsDSjRe3/o93qsV8vukPn+D74PAn7jN/4GeZZTlgVpkuL5HkoJdrsNo9GgzWSoaJqauqoZ9CKUbMizjKbWAbEaeGuTxCkCk+nRCQgDw7TwgoAgjMjyDKEadtstYRDgtZkGTaOBunmZY1o2tVJUlY5pN00L0Vp0bctujVGuRo2VJYarpd09v8fDy0eMegN6gcfi7g2jocff/Hd/na//1a/R6yksq8KyBZZnt4NlA8MEP/SYHA9wAsV6uWY9W+Magmy3o0xTlFSUTY1wLHZxguO5ZGmitQVKcXt3qw1X7ZQfwHEdXEeX/skuJs1S8pZRkLSkoqA1pzm2TaP0Gtl1XcbjEb6vq5CmrjFNo+NDFEWJlLqiEO1LY71ed6yQQ9TbbDYjS/UqUke8ed2soa4bDNPCEAZNoxiNR9q5KQTzxYI00Tkjq/W6NbwFrNcrpGxIkj1xnKCkDlY+Pj5pw5FdTk9P+c2/9z/ffO973/utf/V5/ErInJumpigqkiRlOtWsuabR9JokTjucddM0pHlGGIUcnxx32DPTNLm5uSEIw84oUtc60++Q9fjkyZNOPx5FkebZZTmL1YpdnGDbDvdOj/j02Ycg4ZNPPqTXHzIcDsnrEtNUYBkYtsHPfvoTGhru3TvX1GR0IGt/OGL2ZsN4NKA36JEXBR9/+hFSKNKi4IuXL3A9j3DYoyBA2trdOQhDjhxtNFovVzqheNBH9UPSquLV9RWDwYAPn33IfDnj23/11/nmr/wyf/wv/ojZbAZmwluTEU1TsNts8NvV3zpfEe82+I5DYeq3Xp1mrG4WuJ5PEPVQtSTe78nyksdvf42b21uiPMe2Bc8//4iLi/uEYQ/Hcnhh2Hz22acIt0eWVfiuRWPV2EJgOq6eCylB4IeAhLTBMQAkyoAKhW8IIssmECauVDw6P2f0yw948GSE2ysRxkuEYSNwaXKBYQYYIsC3wXclUZgT9huwe8hsxU/e/5TZ+jVv3XtMWQsaW7DJCxZJzCrbQVPjRz5FDdt9Rtgb4ssGw4CiyAkCHwtY3N6S5wWG0Ig/19eqxrKusBwb1YbQlk1N2dQ0bZhwUeZUTY3ruTSN9kfs4gQDRS/qUdUGhml0epuDaOmQ+6iUnpNYtkOvr4VMZVmy3SXkedVpTtaZdojmZcHx8ZSirBi2a/DFYsFoNMIPPObLO/IyQxiCLKk6MI9sFAI4PppqSvif09V/JQ6FAwjUcRwc1+Xi/n1WiwVCCM7OzrrYuEePHunQmDb44oCiOoictLIvRCrdNx7Wj+fn59R1zfn5Oa9fv9aDx+GQ9Voj0nTfqBHe9+7d482NHkodgLCu5XDvUrv2vvjiC+1TL9JOLur5LqZlslqtGEwmpEVBvqxZrJZ88fIlZVNRy4YkK7mZ6wg5r9XHH7QZh7Kx1+t1RJ7JZILf+u2rqiKJY4RSLBYL4t2eb33rWywXSz7+6CPWqzmBH1AVGhNvWwZ57rPbrKg8r9tEKCnb9GEL0YpbBr0ejqMBLEkcY5gmv/IrfwXqjF0SgzAZno8Jo4i33npMEu8IA4+7u9fYhpabQ/uWc6xWbGZTt/OhQ3y7EAaOsIh8F6Uyykpx+eg9Hnz9AcLKqIoleZ5h+ZYOay0lsi4wPRswkbWgqE0kA3rRW0yPDM4f5Fx/9hpMAyVpWzPJ/O6OyWRMGcdEQZ/h5FRTjtZLPv/8M5pGw3cWiwW2bVJWWq3oe/afiXs/fG6maXZyeiEEPd9rw1lqhFIkSYpsJHXdAAKJJmo1sgKiDpDitT+LA1NxPB6jlOLhw4eMRiPSNGW73XbiPL1xyLpQ5dV6yXCo0WuWZTEcDjsilVIafHx5ecnz589bcdOuy5c8vETLsmSxWPzC5/ErcSgcVjEPHjzg9vaWi/v3ES2jcLfb0W+5A/v9HsuyePTWW7x5pRWC6/Wabcu3O7gQszynbsU6Bzln2bIaNpsNy+WSR48e8fjRI8ajIZ4fcHX1CtlIHMfFsdsdda+vdeVeQNTvsdnvcAOfvhxixAZxvNcoNMeirip8P8QWEXlekBU5z69eMj2akq6WJEVFNBhheQEK6A2PMAzN00uSpCsvq6ri8ePHxHHMdrvFdmwePnjAdruld3FBU9fc3NyQ7PZ8+uwZf/2v/XW+853v8P3v/y55O73e7XYcTSf6MKwKPfBrGZaB72Pa2tgTRRH9KKIsSzabDRLBeDwiTvTWZLnboBoFhom/XYMhKIqS4WBAU+bMpcI0DHCtjklpmgYG+q2kS96mA5YGrmYqRKHLbnvLN7/5DtPLIXm6JMkT0jJjE+94+PgCOwgQjkQ4CmhQjURYDoaKoDFRjYPjx0TjW3bFp9ws5oThAMMJmU4mTNYrDAVJVqBcyatXr3Q2Y6D39JvNmjTVwSmWbYLQ0W4C0W2smqbptlhv3rzBcZwuj8FE8eb1GwaDnpblA3lZasx/69QU7UFykNh/eU18SJxerVaYpsnd3R3r9br7GqADpehZgp5Nua7d2QEOq/jNZkOv19MbuIsLitZB7DluZxc42KbfvHnT4Q5/0fWVOBTKSu+Ar6+vuby8hHZXaxhG9+Ed1kF1rbMJez0dorJq1YtCiO50/PIm4jDsGQwGvHjxolsjvX79mqdPn+D7Pot2h3x+75y72YzPv3hBmhVUtcS2HU6PT7i5uyMIfO7ubokibff1PZ8w0Fbc/X5HZZSs4iWz+ZzNbst6u+XV3UyTkQxBr9+nlIJdHCOsgMlkwvX1tYa3thxKjRnTFtd33nmHxWaN5dj0+xG9MOKzzz5jdnuDkpJd0/DDH/6Arz19ytuPH/PDP/j9js+wWCw4Pz/DMk2SPCfPMlxHQ0td26KpK+K9xroJ02TQ72kZ+GCIIQxW6zVP3/06q8Wak+kJf/KjH3MymfKNr79Lut/gGoL5m1eUVY7daj8E2vEqUAgUjusgm1o/CHWNqSyMBtbLGZf3J3z7O9/EjyRSCmwzZLmIef8HP+Xfc0554vWwzArTqrEsARStOtJHFjpW3YtGmKGHP+iRlDmSthU7OuLzF8+Z392R7fYUSUFlaVJRXZcd+k6TnRwaWbd0cAfLdLvtzUE/sF6vO1rSIaVpPl/Q6w9ACMqywvU8/RkIqMuiRQlq38hBbn5Yneuv0y+B3W6H7/vs9/sOxWbbNqPRiDAMCQK9PThEKAaB12kYDoPOw/frOA7RcEjy+jWnp6c4lg7S2e81bWqxWLThwNW/mffh38bl2BpSenF52W0gDv/Q+XxO3gpdDtCSYYub2u/3nYLx8KGLVvDktD16HOt4rKdf/zppUVBXFaPRqOMa+J6rh1BS0R+Mef78Bffu3ePTz77gzfVHPHr0iOfPn3P7+k2LMW/o93pMp2OGgz6mYXRTb0OYbOMMwzaRKKJ+H4nACwKKuiYrC27nC5I0Zbve8cEHH/D48ePOC5+mqY40b1OKb29v+fCTj8mLgn6vj1JS8x4fv0VZlOy3W7brNX/ww98nCHzqqtL4ulSbsNbrNUWhb0SjbVXyTEM6EDVpElOVpU6mSjN6UYBsKo5Pzgh6IbWS9AY9ZvMZ733rV7k4PuXZz37Gfr1kcXeDUApDAW3rZ5kmtm3iWDZZluA6DnWlKzbZNBRJRTgJqcqUX/v2X2E4DahJkZaLkg7C6fHZiyVHP11wNP0G06mDYcRIuUeYgNGAKmmEQokSP3SxAg/DsalyRWBbpHmGmSSau2BotoMQFrWnQa6OqzddNzdvGI1GVFVJmRZt6+PiOPrrDtyGA7bs8IAejHllXVPudwz7fbIsp9frU5Y5VVGihIHjulR1Q1OVXaV0kFQ7jtORpXa7HdOpzs48MDXm8zlCCIqi6F4Wh/8OLechIe0QNnuIi0vbFkEIQZrqcNt+v4/fApGzLOt4pr/o+kocCqZtcXl5yW63o2o/tKqqyLJMl2pt312WJScnJ/z4j/+YXq/HyclJJ/FcrVad7NmyLIIwxLJtysUCKSU3r18jpE6a9lv9d9qulWxbT/6Pjo64vLzk6tV1u++39bR4t9c6/1oR9ULc1h2nSTywXq113FqaURQZtZSEUUicpkgFu3iPEgZ1u/t/9Pht+kHA1dUVoHvuixZxP5vNUO3cIAgCAt9vo8MyHNvGECavrq50vHsra9VT6hIpG5pavwWUFO0NrG/qAyhUCMF6tdK+EMdlu1kzHI2YzRYEvT6uH+B7rj7slCJpQ2gPmP0sy/F8nyRJcVwXwxRY7feoszkhCAOEUIR+oLX3nodj26yrBNfzOL10KPoWAAAgAElEQVQ35vTyDGHpmHhhgGE7SCwmJxfsdhZVGZEm0B/0gBzDqFAUIBS2I+n1FWkpGU8nCNPAsg1sx6aoaq5vbrqXgRAChfZYTKdTZvNbgDaNquzK+zAMsEx9GBwwZ6vVqt0GuJyfn/P8+fOu9Hdcj91+x+3dnND3iJMM2zK056MyKEtBo7R79BA/cKhaD8DVA5b94LM4QGsO1XHWHuBpmraQ4ADDgPV63SWzB0HQxco1TUMcxzxq2R5lUXZbt4Nrttfr8fDhw45W9vOur8ShcHi7BYGm4zRtuXWg945Go84SDfD1d9/lpz/5CWdnZ5Rl2Q1ZhsMhq9WKKIo4Oj2FFg3+2WefdXvhg/Jxu90yn+mWYLPdMR6POjR7GIY8evSIz794zna7073/eMSgP+Ds9ISHD+4ziCINf9msyWL9xs3SlDAKqKqa2WLRotd90iwH00YJg7woeL7bM+z3OZpOu5IuTdMOVOr7fic8UkoxHg3ZbjaI9rMKXY9dK8gZDPosFgvSLG0fID0glU3VqfEcx6FpkfC2pfvcNEkoypIkTTEtGwyTpq5QsqYqC6ZHE9bxmtVsztnJGbJu+PGPf4xn2xjUjKYTVssKTLBbi3oURcjmT1O7BLSTde3S3G4yLM9iOB3R7/UQtsI2bJSyMQ2b45MjfuW9X2YavcPpqYeSiqausG0XZIEwJEI0WGaJ40h6oU1d6TxLUwmSNCWpKnKlkCiUgCTP6EUDGim5urrCMGg1MCmDQZ/pdMJg36csteHroPwsy5J+v/9ntlsHalGe5wyGE1xXt4/aCJaQ1BXHx0faZ5PE9PtDLAqNcrOsrqKVUhKGIWmadulhX2YqZlnWheAcqE0Ht6swIM3ibrB++PqDlLrf73eZlFWhX6JAV2lfXFxwcnbGp8+e/cLn8StxKBxw3kEQ8ObNm877EAS6lMsLbZ09lP1pkjAajbof4Pn5OVEUEUURoL3xWfuhHdyUoAGsUko+/fRT+v0+o/GYIs/avsxjudrqfIIWk1WWVadpEIaBME2ifo+Liwt8xyGL9yyrirRlJviuyzzZsFpvKIoKy4QyT5CNoshyvDBC1jW2rROZD4nPQggmk0mXiHRQbAZBgNeaoI6Pj/Bcl+dffMF+LwGF73lYpoHnOCRJzGq5IgrbN0ea4LoOptBDP6m0UxDAEFA3UlcZhslqteTpO++y3u4JfR9DKKqyJN3u2SxXHA0nvLq6wnUcfM9ju14wGI9oKJGyJonTjo+53Wi0vOu6VGWFaWoRkGwalCWJi4SkKDBcH6m0zdySJsqwGQwdnjx5wH5d8Nnz59y/OMJ1FRqQ6iCk/uZNYeAYAt912azXmMJA1g1xFmMFAbKqkIbACTyqImefpdhdqpOFaZmAxHUdlstF659JcF2PQb/XzWWGLR7w5cuXAN19cUiDBoGUSmdUSn2PrDdbyiLXsxvHxrK1NP0gSNpsNn/GgXkQl9m2zfHxcZvCte44CxpQ2+8Ok/F4SJ4nnbjJcRyGwyHr9bobis5ms272AfwZzLvneezbHMtfdBl/Cc/4v/YllQZI7HY7ja4+Pm5L4hq/bQOKsiRNU722iyKOj4+J45h79+4xPjri9OwMt+3Nnz9/zu3tLVnLrIuiiKdPn3YpOYethtEOai4vLzXoJc2I4wTHdVuenv5BGKZJWVcMR0OEYZAkKWEUUlYVqpFMj6YcTY8wDRNZl6imQskKWRfUZY5pKDzXpi4LJqMRliHY7XZdyCjoG+7gED1AZg7V0/3LS5SUzGYzHMvGNAyGg4EmAed6BalaX8Dt7a2OHW9bqT9NQqIT65imiWUaKCkpi5z57I7lYsFuq6lNUkoWd7cErsfXHr/N5fkF05HG2ud5ju26bOIdl48e8OjJ2x1SXFO2S/Jcr89k+4Y8SK9Nz2Sb7pDCQBo2UlrI2sQ0dbvi2HDvfExvmLNYfUQt50gVQ1OBskH5UHtQu4jaZbvcc/X8BbQORdu29Swpz9jGe3ZpQiUbavmn8e373b6rGJfLZcsdOMBPNGAnCALOz88xDINXr151P48wDDs7vx9GBGHI6zfXCMNkPJkQJymbjaZ7eZ5PVUsWSy2QO7gYTdMkTVPu7u7YtylUh2G5QgfoHJieh8SnL2dBHIJcptMprut2cwnHcTg+PkZKzW5o2llbkiTc3t52OauLxYLbN286eMvPu74alYJtMzk74+blyw5E4Xo682E4GJAkCcv5nMnJCfObmy6eOwhDZrMZaZ7jOjbLxVLjsVoM+t3dXbeFKMuyIxE9ffq0rQRKLMvgi88/p9frMxoPKe/m3L+8YLVcs95s9Qda5CzXBZ98qnCcr3Nze81idqtLaaH7+jzNkLKhLrUcuqlrXNvGtByEaZMVNUVVMJ/fEvX7uKaDaRqcn5/hOi677ZYiz/E9j32smRK2ZZPECZ/vdoRBQOgHJI2kyHOWywVJvEc2EsOA0Ui3Ttpl6rUhOhaWoUGwlhBYlqmt10riOBYKUG2vu1oumByf6hWipcNYl/MlUdRjtVziOT4P7t/n9u5Gcy2yHrajV5B+ELBaLrFbMM4uyyjzjMAPUAqKQuPKJIqiLAh7vdZNKXUV6EnyWlFLA9cLefLoiPjYodczUXUGlgMSlLJBAgiqPOPFZy/YrtY4tkPaJOz3a8rtBnw97ykA2/NwbY8wCgijgLu7W+qmIk0zyrJoUWgHSXiPXi/i+PiIm5sbtm1ehp5JWEjZsFgscD2X/W5LVVeMRgPqumK3K/A8VyPhs7SLdOv5Fp5jY1omlm0ShPrnGkUhQeATRSFVXWGaBovFjH6v38bZV+RFRhSFOpKwKhkOBziei2lpAjpKw2P1QbVttRRNC8X18Fyvc18eDiXf9/Xm5ku05//f8/hv57H/86+6qrh79arTcx+CU3zfb+PW9RonS2IMy+xko2EUtrkDGfO5pirZroPn+6yWS4Ig6Dj3B9vqZDJhPp/rjAXbwDbHCFnx8UcfEPV6TMYD1HLFaBiCKnEdgzQvUYZgtZ/z2QuLps7xLIdBGCHzkixJUXWDQJDvaozKpkpL+qMBp5cXDCYT1vGO+WrNNo7ZxXs8TJK91lgcQkXTRItmVFPgWD5lmWA0Nr7rka0TDFNgGyamZ5PlFQ05mIqiyDCw8EMb13NQjYmBgyVMLRGmxrEVliWo6gIpG1zHxrN1ZLztmjRVwfHxMTgBWWNSmyGGZ9OYDoPpMdvtGks1NEKRVxV+2KMoAFVjGja+H5LlGaahME2FZZua3ryXWGZAvKtItxmu5+vwVVVhuxD2XISQOI2gLkpMIWiEwyjqY5s2UqLpTbWuBGgadtsNH/70Z/zL3/8XBNIlyVK2RUwtFHkp8SyBbzv4owllVeP7LoFvkWYbhsMeSZKRxDlJnFGXNkEwwjQtHjy4ZHJs8+LFC03KFg2GqVCq6oJbhdFgWeCaFaaqSVvJspSSptZDw+GotbqnCVLVuNEEXIUdWvh9j8DzNMm675EV21bnUFLXGY3UyPc4kQSBzWJ50w0oZ/M31HVF1bbWvV4PQ9igasZtsvfaFLx5/ZKLi8uuMjw4M9frNefn58xms44v8vOur8ShIBvJYrHo2HUHroKUEgyDyekpm/kcYVuMplM++tnP6PV6ur3w/W5NtFwutWrMdZlMJgDd0O6gSDvg4H3fpypysrRkOj3i5m6BlGDZgpOTY8bjCbVseP/997Edk0rngzCfL6nSgnF/SNofku327c1stGUmFKXeBcdJwueff457e0ulJHGeg2G0O2ydF9jr9brNypfR293u2YSiNjBsC9d1SNI9UkkaqWhKbaJxbF8zHi0DJQ1kBbav+QaObWHQYBgNqIo0ragqHSdv+RYuUEv+1BPSNDx4cJ+7uzlNkbUK0jW2beF6DuPRmDTdI+uGi0eX3NzcoFDaHFYXrNcrvLbKqauGqqyp65IGE9O3UbbCDnu8ulny1pOHVKJpobMNOCY6l7XEtGyUTKmbEst2EaqhLApMDK7fXPGHf/j7XF3d4NgRSZax3e1xXM2q7I/G9AcjlpstgRBkacZ+l5DnJb2ew3ajy/ZHjx+ipMBxXE5OTlFK8uzTH7FarWhaJmKR59iOzX4fg1JEvR5VVbJYrHAcG9lIdts9ZVUSRfpw0OpGRb83wLIkthVhmSGqcSkyxWSotQXj4Sm2bTGbzYhCkywrqas11aAhz8t29uB3a/qyKHFsA9fWz8Z8piEt4/GYMNCpTxcXGmfSi/rMZvOOwnVoVTabDUBnkPt511fiUEDoh2Cz2bTZB/qBiPp91sslSUujafIcq20d/CBgeHTEeqZTmyxLf7hCCEzD/DOqsKLQEWK73Y7hcEjU67FcLMgTi+s315iGSxj2EUJLdUeTMVcvr3Bdi/FkwNWba/JKEXhtwk+vx2g8ZjVbUOUFrmlhuzbCMMjSTA+elCTLM8pUUq5W3H/0kLEX8OLVS4TQLRPo/fdhH36YNh/CPk5OTsjTgsViqclSroVMZJu8rduCummQdU0YuAgUQRRhGxZN3RD6AaYpqIoEqRoEBo3Ub1/DNDVEVRjIXJu6bm+uuffwbRazOybjMfEGvRI1BdevX/P4/rcxUHiuxajf79RyVVnSNBWmSburl21SlI6W01RjQVbnmKZNIQ3We8kmNgmjENtSSFIsq0GpCpoM2RRYlotsMhpVoyRYtsv11TW/+7u/y8efPIPGpSggSXPqWmLaYDsuvaiP7bjkWcFgNMI0HSxhsdluqCuptwZhq/w8mvK1p0+5enXFxx99yHa/aGGsBvv9XkN+DBvD1nmfVVmjlKCpIWk3Fp7n0u9NWsdrjs56dKlrhZAWWaKwTQhcEwOfIofAC5CNiTQslLSpS/B8C9N0qUpJnulKOQy0uW+11BXF+fkpVZmx3+87fkOW6WH5Adj7Zdv1IU3t4aNHrFcr/W9oq/BfdH0lDoWDNvuwfjl40bOWr7BcLnn7yRMQgsVywTtf/zqL+ZysVYMdcGw6mSgk3u27QM5DWEae54zHY+2pRzsFN1IQ+H1Wyy3RoMcu3lHLDM9PCUKPXj9gMIwQbyRKasZDP+q3LraI4NJHlpXGo3kBvSgibxruZnfMFnPyUguE/DBktVwRZzlRLyTNMgLf76bDB5PW6ammJx8Qc4vFgiTNsCwTz3JIsoSqqbSOo66o2u2I53kMoiGWJfA9H5T25Od5ShQFRFGIMAKqugByTENXGFYbZS+VQhk2u+2GCySvrl6SJommCx0fY1aC46Mpr65eYpgt7LUssWwLQ6gWOS5RChzHJt7vaIwKJaGpoapKpJBaOdgYfP7ZFdPpI27epJyd9whDk6YqETZ4jglCUhcxtRLaAyFNlncLnn30KT/453/Aiy9eYlkhjYQs0w+m7XgYpo1lOxRlhTJr3nn3GyAM1ssN/WBIGAxJ04S60kTw4bDP/QcXXL3+nJ/89E80Lo1eN28yDKNTCtq2zoQ0TY1bl5VBEiddv97U6O3GkUO/32c6PWIwGODaBoHvMxwNsAwDQygC3+PoaIpjW5iGwem9c5A1tm1q/YdtE13ozzhOElBwctJG0TeqzfDUocaGYZJlOS9evCSKQu0srvT3fHFx0aVrNa0g7rAKPQBif971lTgULNPqTEq0rrH5fE6apjx9+pR79+5RVxVJpkUch0j3w342jmP6/T5xHBNFEZ7vUZVVt9bRNJyG45aoexAI2ZbD2ek9rq/fAJoFcHQ0JcsTRqMhT56+zXI1424+p7qN8VwX27K5fnPDm6vXeLbLdDzm3tk50+MTDEMwDHzCfkQ46LNYrQmzHtskAaXXfOtlwWg8JvCDFpJRcHt721F4ylJDMw6KNcu1qeuKwPfxfZfdbs1uq98IQonO5LRqFJf3LnAMD8exGURD1qslGveiGQdhMMD39EqXduMj6wqEQaNM7CDARHF2PKVuJEfjCVkSMx6N9PYCRZ4kXG233Ds/oyxyDEOQZgm2bRInMXG8J89TUGAKE0PYukpRYNaS/W7D1tnw7E8+4dG9J6hE4Qc+6+2KQu6oA4UhSs3QSHfYts9HH3zCP/+93+fFi9dUhcS2POK0QcoGpcD1AgwpsR2PXm+IH/WI04yqapA0RFGfm9cz4niP77vkudaqvPX2I370o/+X6+tX9Achd7NronDA0dExWabfxofQlDwviCKtAhQYeG5AU+uN0enpKWdnZ1xcXJBlGV988QWr1Uo/uEaNYUK0DFFNjWxqTo6nLFc3TEZDRqMBQdTDMC2OT85oANFuiwBm8zlpkuB5Xgtm0YYrENgtJeog9hPC1PDWVgnZ6w86ifWB/dhIideaCn/h8/iX8Iz/a19SyQ57fZD5DgaD7s0ppdRtga0dea9fveqw74cU5Pl8znQ6bfurkP1ux3q97pRiZ2dnpFmG2a6mdEKyT5EmBIGP47ucnh2z2qwYjUd6pZll3H/wgC9evGa11i7L5WJJGidMxmN816OoauarFZ4fYNsWdlNzenrC9PiYL1685MXVFelsRi0lZV5yfHqCrGpme41pS9OU8XjcGbU8zyPLsq4sNG2BYRrkaUyeZaxXc1RLNXIsiygMCQMX1wrI9hmqkhBo843vBaA0LbssTExTo9fDUOgpdVVSKYkF1IWOkFdNRZHGPHj4iNPTc16+eMHs7pbpZELo+9y8XjIc9MlzDY1xHQvPd9ltN61/f09VFuRZiiEs+r0hZVnguz6eNNjvS/Z3a56tP+Tlh1qj/+//rX+HDz74Q7LkDt9XZEXK9e0tWVqw36fsdxlg47khruOS5xVVpVsN2wGp4Oj4lKg34PT8grA/5ONnnyKVIE5Skn2GbdoURYkQiocPHzE9GvHjH/9LkiShrisWC+14DfxhW6llDIfjzjEZhjZhGHF5ecl3v/td+sGIu7sZhmHw+eef80//6W935Xue53pmVVUI9riexenJCcNBhOvaSLknzXp43iV38+dEUcDZ6WMc2yUIQ9JE6xBs1+Xi8hKhFLP5vFOk9vtTRqNxd48c4EKvXr3Gti2iqMft7R273a7bRARB0A3yr5fLrr3+eddX41BoZLcuPFiobdvuYsc9T69WHM/t5Jy3t7e8++67Hd7qIIcejsdk+7hzhd3d3XUpU4ZhcN5yHMuyZDKasl6siHohJ+dnKCSDUZ8k1e3IdHqs+fqTY+paJ0vPZnOEVFRlzXg4xPc8Ni3J5vzeOSe9iLwsOL93D0wT07YxLIv1ZsN8sWIxm+P7HhKjS+85GFbOz885Pj4mSRLm87k2rtgO6W7ParVENjV5mjAeDuiHPY6mEwZ9PU+RtY1jhwShD0KRpCnpNiYvSjw3QvgOdS0Iwx5KGSTJnqZdR6qyRNYVVZGhmopkt2G9nLPb7ijynKoqqYqCN6sFVbsea+qqVUC2aPcsJd7vyPMMgdJ/rtSsBlkrelGfo/6UMm5I1lukD0YtefNizz/5RzNCH2yr4sVHL1lsd+RVxXAwwhQRtmEihI1sbPKspigaLNtpo9Ry+lGfh4/eoqwaVpstNSa//Cvv8eb6BhlnvPXWE15/ccV4POboeIJtG3z44Yc6TbwpOjVsHCegNDg4inrtvMDn9PSUp0+f8uTJE1zX5fvf/z6r2YbFYsl6vSJNM+q64gAzNwzRZXBImWu9ggVNkzEZ90kz8EODvNhRVjH7OGeUH9M0FevVAtMySXYalyelz3q15vTshGI8wLBMimTftsGCMDQxjIz1eotl6YNrtVp3z9bBYn19fc3Td96haVeThzb6511fiUNBKdXJcS1b50SeXVywXq87x2Oe58T7GIXi6OQEKWXn+BqPx2x3O1zH4fb6mqosCYOws8De3d3h+z5FUXD18mUHbNnvt9i2wLINHM/G9n2S7Zqw1+PRW19jt9+x3cacHJ/TyA2fPHvGdDIlS3QKcFFVNFIhm5rXtzesthviVLcypm0xmZ5wnBfsWhm2EBaNbHjx4gWipRR5ntcJVO7u7ro0qwOAI42lZjyWOYMo4O3LJ/qNYxtYQhL60O/79PsTbNenqkvysqA/DDk963Fzu2C12mPUOia+KEEYBxScnt/IpiEMfYRpIOsSYSpeXb3k/sO3eHD/Pq9fXfHy5QsC32M8HiEELOYzNqsVrutQVWWbqLSmKDXMVQCWqVuHvMiwTAtHmIxGY8p6SZyu8CILNwjZ7G7p9c6IwiELY07oCWy7QTUmCvDdgLJsUEL7KgyzII4TirrBD2yUEnhuwOWDM7b7mM++eMHN3YLVZsvx8Smj8QjXMHEcm6LI+NkHP2W9XrdhxTZRNCDLE8qyxrUlhmdyfDTm3sU93nvvPSzTYr1Z8w//4T9idjfTzlJJi2AvGY36NI1kPp91G6Q0jTEMUzs9DUjTAs8pqPsKKQVl2RDvEwxDW7VBcXt33b0YNXJwRVXpqmO9mneiKNOwNIl8GFHVFUnyGtt2QImWVG2097s2RB3gr2kcd/j5P+/6ShwK+mSOKIqC3XZLnmWsWqfYQXlVliVhLyIvS9I4ZjQada61oN9HCYGsa81juLikyDJevnxJr9djMpkwmUy4urrqYueEEGx2W5pKrwJ/8ic/4ujohOVqhWlp0ZFp2wz6Yx4+eMxq/SFJkmIYZlcaZoWOihsNhx2/fxfHmLbF9e0tn3z6BWEYsl6vdUS6abPZ7hgNhuStr6EsS6Io+jPAlUPST57nmFIy7EeMzs/xPZPj6ZC6TDiZRDx9+pivP32bk9Mj3J6PaZv6JklTGgWNstiuMz755IrPPr9mtdy3mnmt/DMEyKrAaYNNLMtis1rhRz12cYptebiWxWg0Yj674+OPP+Lxw4eMR0NtjXYcikIrTfMio6x0FSGU2fEabctCKY07T/OG09MT+sdDlldfsM4k0dEFMi959uIZnu1jCb0R8RwTqSRVCy2xHcjKjDTW8uLe0CUIRwhhcHp2jkLw8uUVwrLp94cUVU1VKyzbZh/vuTg7Zj6f8Ud/9C9QSieKDfpDpGrY7fYIAb4X8fDhIx48fMBbj99iNBrx27/9213mgm73MpbLFb0g5PT0hCgKu0rDtk12uz1NU2NZLpZlIisT0xAI5dHUNk1lI/Bw7R6WGeK6Fr43BAS7/YrhcMTJ+Tm2afLm9WsUNXkes1guOT4+RqAoi5okSajKujWr+fq+zgrivQ4DWi1XuJ7VQYoOPpiDMeor3z5UtU7lqZuG3W7HyckJtm0xbMMzNOyi6uYN2+2WKIro9fuEUcRqNuP08pLdcsnDhw8pywqn/UenaarZ/XXNxYP7yLph38pCsyzBNCCPM2oJd3e3vLm5JYr6jEZTHCUYj6Y4dshml1MWBYvlktGgz5/85KcotPCqqErGrqO1EapmuVq1U2ODTz75RB9kaUpdyQ5uIS2rg8ccNBSHVKCDxNl1XUaDIafHR9gWeK7B0XTMd3/jbzGIXKLAxvcsDFVgqAbX93FNEy90kZiYTsDF5SkXl/f49b8m+elPP+F3/tn7SNlgOA6ykC2/z2a3jxn6Abv9jkYpwOSTTz5mMOi1QhctYV6u5qhGC4KEENze3rDfb4j3sWZD1jUVkqZqsIyKIBC4jo+UDUVZsc0yBpOIMA5Iyz2rZI5tuShbEBc5vhthGwLH1kzC+kvIMqkKpNLsDcuxCSOP0fCYLC+oqprRaEJS5AwnQzbbHRKDfisJfvXqJe+//3skaULRYvWFENRlQ7835PLygr/xG7/B8fEJz5494wc/+EE35zk8THqjo3M0EZLtbgMoPM9nPBkxHA0Yj0fs9zFfPP9CVwxbnbcha0WeKcoC8qwhSxvWRkIQuPhehm2XmvYtNRhXYjOdTrAsk5cvX7ayZrur8KIoom7qrqI8tMuHLVy/36duNLT4QPMqioLA93X19VVfSSogznL6/R6O67JYakCI41iYQsdfVT2fRgq22x3ekfZGVHlBWRQgFfFqTS+MWK/X2Eoxv7nh4v4lru/TKIltGQjLZLackxcFjaoIBiPG42NW67UWTxUlFw8edzJQpRQISa/vcXE6RDQP+PjjnJ988DP6wx4PJo/Ii4rX1zfM45RMGUSRz3IX09RadnrQr1eGQVJnDE6mCMOgrCt6gz6ObWNbNrfXN+z3uy4tyPd9RoM+l0fnjMcD0mKN7dZ889feon9iYRoVjWiIc4ktLJRjI0oTZ3RC2VSkcUKvKbCMhOHIonfiYkwvsad/jR/+Xz8kT1LAQCibqkoxRU2WrijSingXY1oe41HIfvEKazqlSjcsZ29YL+8YjcdMplOkUqw3a6pkh6pqVA2yEuSl1lJUokGqnEbqTIS0TigXJbZ/SeiOaXKDamfhRz5lWRF6Lv1ehKANKmlqVBxTVTWl1OQlSzSEUcTF5SVV1WDYPr4ZIIXLbLED02Cxek0tK0zb5PHbl3zwJz9hdX1HkujUscl4ijYzNZwch3z3u9/lyZMn/N7v/R7v/873Wa1W9PsRsmqwDAGqRqia4cCjCjRZScqGOFniuh5NmvOTn/5Rh4Evy5LvfOc7fOMb3+CzT161mSUuu92GLI3JqxqFwXqb4Pkhm13GdDwhzyBLS3pRjW3D8fERq9UCzw3J85LZbKGDYsIQw/VY3FzTj3oIy2afbNgnGybTKU1Ts9lsuip4t9XkbcM08H1Ne9LAuJ9/fSUOBSkVwrBwbI8o6rHZ1BR5QZHlHB0fsW5XdQ2GRpm1KsC6rknTVIfFjkYdP89qWf5FUSIVLXzToaz1umaz3XLv3j32cUYURZRVxW6rNQ91XWO1vP9er8diPmc8HnN2ckoYhNR1w+vrW15f3/Dy6jVF1eAFIWmWtyTqPlWlV6DFl4AaYRThB4HeD7e06jiOkU1DXdW4rW3abEVFURThOS5e0CracPnWt99jOB6RZCmmIXENkzovMZXJrnDwc5uJYRCnBk3lYSsIPRshHIQy6UU+v/TN94hnFe//zg+pc4XrBuRFBu2gt8gLytrCMBq2hn6wlleeBT0AACAASURBVOsVy+Vaa/DrlH0cczefa9FVVdH3HZQAYRqoxkDWNUVVIRA0KG3LNAws26Gqaw238X2qsiYjx1CCqiyRdYNjOwShT1VXNEoxGE/Y7fas7mYcH5+AEBiWxf2Hj1CNotcbsN0lZK0Ja7dNsGwL13f4xi+9y831NT/+8Y9RmaZrHw788XjMo0cP+cYvfYOPPvyQ//Hv/V3WqxWe4yKEJn0LQ2CaRsv2SHFcq3tZxHGm3a4thLWu687v4DgO77//Pj/60Y/YblKevP2Us1Nd/f7yt3+d+/cvGI0HLOZ3VHlGnOwpywLHcfCDgOVywcnJMTc3N1iWyXgyatFrJpZlst/t8IJaG/yAJm/wfB8/yEmSuLPg07aFh/jA6XTahTn/G8mchRCX6Bj6U7Qd5beUUv+NEGIM/O/AQ3QgzH/ShswihPivgP8caID/Qin123/e32FbNrblEicp6/UOgUmR12zWK4QSLdLLwXUc8ra87jBVvV632guCQG8bgoijswviJEaZJmAgDRPbtTAcj6xs2OwSPC8gSxLS/V5HvHt9Qs9nNrsj8DxiqbBNC9U01HWJYQiCwOf+/QuSLEOJHZ5SWLZH1B8wmUwIA4+rq6tOiLXf71mv1220W94y+EfUsqEsS1zHxWit01WkBTOmYejhkO3QG/QpqhLbczk9Pyca9EEUxLs1RVZQpjmWsFheJ8Rlwjd+5RTbC3EMB1EUmMrAtD1MO8A1bcy+ybvvfZsPP77l9uUdyjCwgxBRSbJcD3KVrKgayWy5I8m1yCVOMoqypJE6RGWfJFi2dmzm6a493BvqpmlFNhIhoKkUluPgWwbHJydYls1ysejsvG6LWldKdXF3lmvTKEV/OEQYJsowwbJZLFecnJ5y//4D9mlKnuYI02a73XJ7N8N2DmrTEb/6a+/xT/7J/8nV6xeMBiOiaYhhanPQw0eXfOtb32K+uOPv//3/iRcvXtDIGsu0ePLWY/b7HYvlgjD025lWjUILvrrN1WTacQ9Ua9IyTZOmbsibgjRbo5SGEn/wwU949kzni8xmbzg6GvPg8oLpdMygDZ+djEacn53j+h7xbofj2jieS7zboBQcHU2o64r5fEYQRCAlKMV2t8MLQxzL4vz8HKWUzirp91DQia4OB9chku5AlPoLHQropKf/Uin1x0KIHvAjIcT/DfxnwO8opf5rIcTfAf4O8LeFEO8C/ynwDXR03D8TQjz985KilFLYjk+WxIRBr8sldCyHppaMj04o0pRGSQaDAXYYUrUrlXnLVzyoAEejEbIBYTnsU00JGk+n2uasFOvNhrN790nThHi34+7utgXCagPPaDTk3uWvMru7a7cTNtfXGwLfZ71ec3HvnO1uR5LmGOYN682OuqkJA5/1akkSay7e8fFx9z0dSLxfDnvtD7WwJIr07l3nWmjdwQG04jkuTV0xngyRoqCsK/ZJQqMy4n0MdYOJ9gvsU5Mff3jD8LTi6TvHCFkS7+8wkTiugRsG2JZL0whGpw94+933KIoPePnZp/R9F1klWjItG6qqoW6gklXrmrSom4a8LGgaqRWQKBACaQiS4kvqOKEXc0rnrWjPQiMRpt3Fu2ctJbuRkqquNR/BddvfpzSL0bToDYYYlkk0BGe7x4siBqMxludp+Kyn6dp5VhJGPcqqYTIa8fRrb/F3/4ffwjANHlzehwZmbxZYlsU7736Nt5884Td/8zd5/vxzGlmTJHu+9a33qOuG29trXaU0JVVlatl2VTEejekPok5xqpRAYGAIE8M2KZOEStbt4SiJwh6O7XapTsdHU6qqoCz12/z5889xXRPX0W//3W6LZRoIQzAeDUmSHZY10DL1qmK7XaPQ7VrTqI5mvtvtEOu1DkRqqz1A54W0JsBer9dVBoektAOq7S90KLSZkTft/++FEB+h4+X/I3ScHMA/AH4P+Nvtr/9vSqkCeC6E+Az4deAPftHfUVU1ZVXjhBGGYTIaDvXOXEpWyyUCzUDwIo+syLHzHLtN8DlAXo+Pj7vT0PN9StlQt5WEadnk+5jNdstwNGK1WiMElGVFluxxbJujY61isy2Toiq5d3GPLz7/nCSJqauKk6MjoijENG3Oz87w/BDLslG84vZuRrLfUzU1s9kdTdNwdXXVUXhHo1E3AT4o0w6xZGEYMej32bfti23bHQr85OSE0/EEyxIYTo1hmlRNQ5ZnpEWJa+rJc5VXOOGAXXaLsH0uH52S7zPWzRbfV3qfXxZIYSLMkEoZvPXONwm9CZ89+5yk0HqDRkoQ+o1f1RJhGdRNQ1FV1G2FIKU+DJSS1FKTmjENmqZuuQ0CYQgdG6cUUklM16GSjTbltL+eZRmmMDRl2tHbJ1oITJyk3H/0EMt1kVJxcnqMYbsMFZyd39MELsPAOoB3ghrX9Tk6PuHhw/v843/8f2CbFn7gUWU5VdnwS7/0TX7927/Gs2fP+F/+wf/K7e21Zh1aBvfvf00PBZMEA9HyE0ftz8igKDRBebPeMZ/PqJsa2/JxHBfDcPB9T681s5yiOPBEHTabmCBwsUzB+fkZcbynqQsMU7ShOls81+L09BShRMsXdRCGABTr9YqTE31fb7YrhBCcn50RBLp93mw2ncnvUCnnea7T005OUC2Kb7fbdRJty7JAiM578xc6FL58CSEeAu8B/w9wcgiZVUrdCCGO2y+7B/zhl37b6/bX/tU/q4uiv3d+RrL//5h7kx/L0vw87znzfO58b8w51NRVXVU9sEFSIgHbEkUCMg14Y+0MQfDSG6+9F+CV/gMvTcttSxApWTTFoSmaY7O72V1d1V2VlZmRkTHeuPOZ5+PFd+KyDbNpwA0TdYFEJaIiIzMy7/nOd37f+z5PhO25RJHAjBVZiiJJIr7cfVNpltK0NfFPUGOSJOHx48dojoPtupRVRVk1tK1Ekucs1yskWUY3TUaKiu37lB3tyDF05lXOeDSiaWp810FVZJIwoExibNPAsUyC7Q5JlpgeHLBZb7AMA4mGyWRElKREcUyRp6RZLtpsneH54ecPKreH9Fnbtqi6AIj2ej3aDuTywNoru8+RJIkiL7i5umMwdXH7Om3aIikKpmlT5SVF2SLLGoapYZgt6+0tr6+ukeuYtgloJRlJU5EMaCioGwPHcXjjzSdUcYNuWuRZApWIkTdVQ0Mjttqde7Kqa5pWBHOatkGSFGRVQe7yFQ0i99A2AhQiIVF0aPe6gbKqaWUZy3b2x2Hj8RilQ8DTMSIeFkOv32M8nqIbBnfze8IgJhcBCz7//Pl+9yK1LWkY8+jsKW+/8w62afG//7vfZjadkaaCfJxlMb/8j34ZWTL45je/yQ9+8AMcx6KuG+qqxrQN0iRHN0Twpy4rRqMhcZxwcXHBcDhiMp5xezcnjnNMU+joFVnddyjKou54nuJUTFWAVsYyTSxLQ1XEn9txbPo9F6mVsWyTphbFtjCMODk6Jk0EtHU6m+C5LqYpuhBhGFDXYnHXDQPTNPeReN/39x2f+XyOoiicnZ2haRr+oI/SPTo8cEWaRvxdP9Sxf6ZFQZIkF/hXwH/Xtm3w0NX+mz71b/jY/4MS+ZMq+g+//F5r2yavX3xOr+eTxqEgF5sGWZiSpoJvH2UhVWXu0W0P4IjVakWWZQymU+S2Rdc0oiTl0aMz8izj/n7OydkZWVWxuLpku93y6PFjiixhPBpC2yC1LeODGW1Z4jgivZinKXf3c3zP4/riFf3hkIuXL9G6OcCg3yfLS6Io5m4+J45CWlnZ5+VVVd137R9U5g+LhOu6jEYj8jxjtVyRdXdOs3t0eGjAUYsJ+N31DbNDH8MykCUF1TApGom2AV23QJN4990ZPb9hvX6J0qZMfQVFk0HSaFFoMIjjgCDKkGuVMs8xdJ3tMkKTxUIkqypK3VIVDUVZCIN3t12uG/HoIHcE66ZtRdxaV/enJlUtBLN0n/dQ3RU7pj5Flu+r7GUufs88SZEVBad7tIp2IfPbO8aTCY/PHhOEEWVeUtUN48mEqisEnRwfcv7iJZIs4boOv/Vv/h393oDTkxPOz1/w1Q8+5PjogD/41rf47vd/wO3tLaapsd1usG0Lx3XwPKcTwe7IsgpFarm+uhMls96IPK+IogxNNRkOTOqqJk4S+n1/D2TNc3EzeO+9o71sJcuEdq5uCnq+S9OIhaNtKiRJZTo9wHUdqrJBcXXKsgEU2lYmDGIsy8HRREM1z1csl0sePToTi1FV7U3qD92Hpmn2TeNev4/f86nyHFXX/29pYSGwqQWW4GdZFCRJ0roF4X9q2/Zfdx+ePyjpJUk6BO67j18Bpz/xy0+Am7/t67dti2mL7kESx9zNb7BMEyWWcG2bzFS5ubpCMXSSJNlLOS3L2vPw0zTFTVNs32e9WtE0LVmWoqsas/EQVQLqkr7vkicx8XZDnEQYpjgSHI6GOL6H1LZcfP555/vzmU0ngiEpyZR5xvtffo/b+T1lXaOmOWEUo6kiLTedTMjrZn8RPISyfrLg9YBHy7KMi4sLojASPoa6oejOnB8m2lEU0ZNVdGTu1huqrMCzhsiqqMO2CiiqimnYuLrGV798hOGpHB475HGBazSYpoQk1xRZyiKKuFmk3N9mvHp+ydWLS8LtGsvQaZqcusuEJFlFlteUtVgQaEFWVDRdE7kBoKHF0FSRB2laNFlC0iQ0RdtXqh+KbpbhoMpdGKujGwdBgO96+25L9hOtPdVoyeIMBlBmBWWa0/d6VHXNar4EJLZhgNQ2PH78mK989St86/f/iF/4+V9gs1pTFjn/xT/+xzx78Sn/82/8BpvdGsvRaClZrVf0+wO0TvyyWu4wzRxV1VBVhbpMGY2miFxGI/ibjcqjsxOGoyGe6+J6Hr2eS6/fo9/rd0PklN1uh6Kof234TlMkSVCbwmBHWeZE4Y4kDsW/eSNTFA1tI2PoNp6j7X/Pxf2aPBNNSN8bsl4FBEFCWTbourZ/BH0Iuj0gB84ePcKwbcIwJAlDWK0EaqAjLj28Nx+I0v+fFgVJbAn+R+DHbdv+i5/4X78F/FPgf+j++5s/8fHfkCTpXyAGjW8B3/5bfw9ZYrtdoUiQ5QmqKmOaGjc3VyQdvLUscwzHwjDM/YXzMLh6GDQGux3BbkcrtYKGXGbUbY3Vc1GkhrYuSaIUS1NQ2pqB7+H6nqgoh5HQrhUFmqIymEypspSjo2O26zWlIqM7Di1gmgJgqpsWd/N7yiKHtsW2HVzd2A928jzfs/ge/JayLLbM69UKRVX3Q8WyKCiyHK0LNQ36fQGaKSqaskSVZFb3Sx4/PcK2LAo1R5N18UMxMU2YHg5RLAfF1kllDVdr0eSWqiiIc0gS2Cy3PPv4U77/3U9Y3CyxDR3HkikQO4Gyrqm6xwC6bsR+hyBJSN2fX3ooqekaWg21XFN2XE2RmgOalrZuqIqCcLOlrWrU7o2pa9rejjQbTyiKglUH1tWKgjzNqPKCPMmIgpAgjHBdj57ria5JWuC7Pm+9/SZ/9d0fMJvOiJOEd959G0PV+eb/8k1enb/EtnRUQ+bu/hpFbXFci7atcVyHPCvp9z36vSGGYXJ1dcnJ0QmT6RTP8/ng/Q/RDTG999whq9WGH//4R9zdrrh8/RpZkYhC4YhUVJWXL14Sx9H+vZnnOU1b47libjSdjdFVlYPDCW88ecTBbEoYbCmrijBM8VwZx/bRVAPHsQXct6ixLRXP6wmug6Ts+aW6ru/DeQ8MxtVqxaFt4w9HglIVBHvA8cOOwjCMnxnx/kvAfw38UJKk73cf+++7xeCbkiT9N8Br4L8CaNv2E0mSvgn8CHFy8d/+bScPIHgKlm2ShCEHp0esbm8Jwi2OayO1LVGwxbZN0iRFVTXk7sjuwfak6/o+8lyWJYali8XAtpDblrYq2W02uI7DJokZ9H3hG+jOffWOoRdGIXVZUhQ5s+mE5TxneT9nuVxiGgZNpVFlObRgmRZydyTn93q0koSmGwwmAqkdBMF+wiu2p0HH/BOEI2QJ3TBwusegB22700lyLdsWZqmqpswKFCRefPY5b7x9hiwj4CRSTVW2SMioUklbxWiygUyFKrfdoEmmzGsWiy2fXqz55JPPefXjz4m3AVWWULY1im0hNcIjUSsSSDV190/2k4+JkiyhSgqKqiHLYsBYliVUHbmpaffDQiH4qZDF5JI8y3BcV5w0aRpVt2Ma9Pv7bsvD44Zruwx7fbI0Q5FVRv0hbdOyXCxBkkjSnLffeou/9/d+kT/7iz9HlYXI5YP3v8x3v/0d/u1v/VvyLCFPEyRqVEthdDTg6RuPePnigrqCpq7xvB6GbuH7fd555z1+9Vd/hXffeUqSZjz7/Bnz+Zy/+t4PefbsOZpmoHTP/7tgh6YXe5PXA/354URA2M0UVFUjCDKC3R2vzi9wXRtFltB1hcPZlLOzY3zP4Rs///PYlsugP8C2TMqiYL1ZUdcVpmlzfy92vpapi+PQyZCmaRiNRvtH0vV6vT8iNQyDNEk4Oznm/v5eoAYk4QEBmE6nP5s2rm3bP+ZvnhMA/MOf8mv+OfDP/9++9v7z65oy3GIpCm2aYOsanj9it92iyDLHh0fc3d2xWK/o+Q79vodjO9ze3jIaDUWwQ3EY9H3m8zneYIamyOSpiLMquoFqVURFTm82wbJtdtsthmZ2QNUWxzWJooS2aUiyCk23kWUd1TKJ02taWcKQZUzHIS1rLNUgCBM0zWIympKmJaZhUyUVDQ11XlPnFUEYkKSxmH8oMkUpZgpVUQINWZpgWw6qouI5PnGcc3R0hmXaYhretCiKjmH1ibYZn3z0jK9/430GfZemyfAcFeQI0zTQLdGYU+UGXWvJ05Yam7zUSYMdP/7Ll9xd3dImOVUSoqs1mq5SNCWoNranMrBMrm9uidMtLWKQWOUZmipTpCWmIcQuqqLSVA1tW6FZGlVVU9UFlmXQVOJoU5UkFEVClxrUtqIMQvzpBEWCNM8pJcjaFldR0U0H15XwLAdvMMDp9URvIY7ZLeasthsur69QdZ1Hjx/zi7/ySzx//opsW/LmW6ccHk/4oz/8Pb77ve8gGSVRsKORWlRNRdVssthm1TY4xoz+tMfTJ485mE754P33kXWZqij5zp/9BX/5p3/G1fWlqIWbGmG4o6py0jSjrApURWE8tkjyAg2wXZPtdkdLhu2YSCgE4QYtE6G1sNgiSS2yCVGxxTEN2qKlrCySaIkuF/zZH/0u/eGIs04ye/bojAN7InZSsoyqK/T7YgGQpRapkfG9PqqkItUStmFzeniKJEtcX1+zvFsyPTwkLWE6OyFOYqqywnYH6JpGmjfU7c/w+PB38ZJlibqsoGkwPR+pabm/m3esRnEX0TTBBxwORxiuS1kKeOXd3Zztdkscx+i6cE4urm8EJh6JPMvYbXfiotF0yrrGUVVGkwnBNsQ0LVQ1Jkkz0ZnQdUzT4vzFy87RoDEcjTEtwV+Mk5gwiugPx2wvb8g7FLdQc9mEYUIQBnsij2NbFEWOpokjP0mmG/KIO+qDXFfW5C7tKPH88xdMxhORcDMMJFE5xOsNuHh1haS0tHyJybRPVVUYpkpRVLStjCSpFEVN08og69xcL0Dq8fFHn3J9cU0Wi+2m77kkaUIUh+yiHbbrYrsOp6ePyPKSm5s7dNMCSe6OsjTapuk0eZJYGGRF5O+pO5WZ6BMgiUDag2S2bVqKLKfOa1pahkC/1yNdds0/2+ZgPCMJEwauhzscMJyMaVqBSM+6GUSaJJxNJ/yzf/ZP+ZM/+VP+4o++zT/5L/8Jigq/+a//DdtgzWI5RzOEEkBWVNq6RW9kDN3iq1/5Om8+fcKX3nkbXVN59vmn/Omf/J98/3vfI4oCgiAkKVvKMkeWJSSppaXCcSxkRceSNRRFJgwDvN6gmyUUFF1+A0lGkZWO16GRZaLFW9UFtmViGkJ4rMrCxVEUuaBhWxZFkbHbbWiaisVizpMnT5hMJmJXPOhj6Dqvz88ZDQekXYpX13WCMOTw8ADbdmjbh56QgNtut7s9tdmyLPxeD8M0+fijj/bD8L/p9YVYFJpaoL5NwyCPY0zTwO31cG0bv9djt92QlxWeaQijUbf9LLtAkq7rhGGEoohhlSQJmWsYhsRRLEJCjiOOK/McUzf2xzhxGrPb7faPIpIEk8l0r2urqwpJ9ZnMxkRBSBQlYoZRlhwdHnB1fYPrOuyub1gtFrSSgu06zOd3XeTVoK4F/aaqqv0w70E607aCIOVYYvgznk7F86JhMJtMub08x3PF86Xt+aC2fP75BdfX13z44bu8885TDmc98iKnSBUUSSXPU5brFc+fX/CX3/6Yq8sVaarQ1DquIzBmsqqhmzaurBLGEXGS0hsMqKoaVdFxHNFI/cn5jdQ5EQF0TcOxHVpaVrsVum6gaXq3cKioiiIeJ7qCjqIoNFXdqdjFiUQ/L1BUlWgXYisGmqpi2Tae79Ef9AnDgDgKWd7PqbKM04NDfvU/+Qf8+bf+iD/54z/G0m1+7/f/D/IyxzSE6XkyGbNYrrFMh+nBMe+992W+8XPf4PjwmLIsmd/e8r/9q/+V9WrJ5etXYo5RlaiKiGEXZYaqKiiKjK5r9Ps96qaiKHJWqwWGaeC4fdpGYTQc0ev3CHYhYRiz2WwpipJeb0QSx9R1w3AwIkliFAk0RaRye56D5/ndDUmnqmpMQxe9HU3b6+MvLi548uQJaZoymUyYTCYUuQgeVXWFIZukWcr9YoGqbrAsm6qqWXdfp+5mCg8nFLvOd+K6blfX/ptfX4hFQdFU3njvXcIgYH57S1lX2L6P2+sT7LYgK/SGAgmmqgIIqhoGSadce7jbmp3jsSgKrl6/3h/rbTYb2rZldnhIGkUsOopNXYoJeZZE2I6D59oC6CK1rJfCsiMBlu9Rpilt3eB5Pnle4roOcppxfHTIdrMVDsm6RNOFfWg2m7JcLonisAujIO74nVWobcWgqG3AMA2GoyFxmJCmCbPOvxDHMYZrU8ktdVnij3rIqoyqaoTBlu9/91NefHrBdDbtjqlULNsgLzIur6+4urqlbTXStMW2hriei6zI6JqL2dW2szynaGqyPOcBSfdwcpJ3sw5FkrtymCRCTt2ztCIraLqG43mYhkFVVkJuI8k0nYKtqWvUFmRZnLHnRUEcxfQGI05PTsizgiIvaWmZTmccHx1RUXN5ecF8Puf6+pr1YsGT01O+/rWv88lHH/HZZ58htS1JVlCVWfd9qch1Cy28/c6X+M/+03/EYDSm3xvwe7/7LX73P/wOd3d3qJLMeDwUOx1NxXFtmroCRCDLMLTOPSJ2bpvNFiRIkxRJ0tEUi7psidOE7TZGvZ6jKhqW7TCbHdPv9dF0ndl0xnA4QjUkoKEqSzFUzDPkVtCr5bbFMISt++jwCK8njq8ffJJJkohHCFUlryo0WabX6+O7nug/WBaWae8TirutWABsy+neDyKs9KARGA6H++tjvV7/1OvxC7EolEVJFibIDfhujyLPiXcRaZjgeS6D8UjYj25uoBEAirKqKIua0XDSnRVnGIZJ09S4rsf9/Vx4AGWZ2XSKJMvQNPT7/X2RSlNU8jQTYZrRUOw2dA2/16OuRP16sbhnvVnjei5FIaqqmqZxfHrK5cVr3nhyRs8XFurnL14yX65YLudkWY6sKNRNQ5alJGlCXYt4sBhIyR1iTgymqqpiNpth6CZvv/02sqyQZxl9f0hZ5Ww3G8I0Q5UUdMPDsWWyKKEudV58eito0G1N09aUVU5RFxSFwJc7toHvD9A0C8t1MJy/bvPleY6saeyCHbbt0DQtuqbjez5ZUXRBHRF0abtcgqzJ3Ta1wrJtHK8vPIlFAQgjstTZqOuqoshFmEtWW5F+bFvu53OGoxGu4+PanthRtS3b3Q7dNsiylCgK2axWuLZF3/P40//4H7m6vEKVZWzboZJbLEtFURoc16Dc5fznv/7ruN6AzSbgX/7L32S52OC6Fo4DtqUzHAxQFIXNZoOqqViOxWq5wnZs0rRAUiQ0Q7gvFUUlDEJx7KzbPH70mNFohOd5YkGxPfoDn16vj6ELT2SSheiG2Jo3tUSw3bHbbUizBEM1OJrMcGwTz7XxXBtNU6jKgoOjKVkhqMzvvvceq04wPB6PxQA9z8k7Z+VgOMTt96iKUtStEWW0B9DsZrNhMBqi6/peEDQej/f17wcw7U97fSEWBSQJSVWIwwDdEKTinu+LiWqWMZBlqjxHkWRsz2a1Wu17DpbrInXCzjzPyfOaKAxxbHsv3Oz3+9Rd+zHY7dhutyiKSl2W9P0ehi566qauodKyuL4mTRIW+RwA23YoczFv2O526LpJGocoMjiOzdHxMUVZkGYxaZGyWM2RJJm2FbHVh+2zosiUVdm168Q23HUc0XPoFrTlcsHV1RWKonJ8eAQamIZGT5IJNls0ScGzHIoioShlsdPJFWzHpUgiFEWibjWkOkNVa1TNYjAY07QKru9z+ugRRSOMxYZp4UsSsqJSFCVRGFNXLbquYVsutp10SjKDthFcSEUVd1LXcZCRsC2LOC9BVjA0A7/Xx7Zs8X2ZJrvtjnXn9MhLkY4cDAZi/rILyeIM07QxDw8JQlGscuSa168vqKuKo6MD0jDm+bPPKLIc33Voygq5bbogUItlGwLuIkl8/MMfcnV9z/XNkrKUUWTxWKOp4oSgKIo93zOqa7ZhhKRqGJbD9OAQz3PJ84LpZMrXv/51hsPOPylruJ6HaRrsNiEvz8/ZbXZstwHBNmY+v+f+fk4YCfR60whWhYRA4CuKRBpH1HWJoavYtoFtGVimwWg05IOvvoesSMznc8aTCePxWESYez16gwGL+Ryn3xczs/sFrudhm4LFqRsG569e0e/3sS2Lw8MjAPzhgLTjRcaJGKKbpslkMvnZcgp/Fy9N09gFEXle0iIzHIlz6yhOiZMMJPENREHEfL7ocgAWpmlTZkUHNU5PqQAAIABJREFUJmmwLJvBaMLd9WvSJKHMc+7jO2bjCbJhUpcVeZrx6uU5p6enqIpCURXYjkueJrie29VM4X4xpyxLnj59iuP3yLICu0sapmlGnIkhkaKqJEnEsO/x1htPiPOEINqxWCwpipL1dk3TCMy5LKvdkaqCqooKuK6J1XxRLdBVg/FozGazYdyd3a+3G4bjIb3+kKeP3+TFZ58TZznTw1OC7Za2apGSChSDuk0BlVaW0E0DVdeQFRVUg9OTM2zLIatKxrMpqGt0TSOOE1TdwHE9VsuVcEJILmdnj1BNgcYvikJIYzvBrKaJI0AJMC0LzxOadICTo2NMXUfXDXzP4/XFBY7j8+mnn6KZBkEYkiYJj04fUXcDzV5/IDBiskKaZ3iZSc93WdzfM7+9oypLVFlBViRxfGyJRSqMUrQy77bPKXXTkqYlluXz+PFjykJCUUx836LnSxSFwOI7nouqGbxjW+iGSMe++daXxN+RYVDVDYauomoaLS1ZmpFnJff3C16/vqGq8i7wNmIyG7LbhNiuyVvvPKUq62421aLrBjoSRZFR1xVZGlNWBcNBj9GoT5pEbLZryrLg9vYWx+0kSB2g9fr6mvv7e0zTZPoQ2PM8aKGqal5fXXN6eorfH3B8ckqe52RFyWYXMBoN2SwWYk6X5/jDIc+fPeP48JAsy1itVj/1evxCLAp1VYkEo6xQlAW649C0YNv2fstzcHgoNGLLJVVV0+/39mYoWVaIopDlcsXTN94QUdQu5fjh177GYrkUWQbLwrDE3aIsSw5nM6GXM0zyNGN1vxDZgLbB1HSqXHT8bcNERuXVixccHh0SRyH+cEDWpfpaWhQFNE1mMhlxfXPN/X3dmZNcirKmAfKsRPSJxPOrYPmlZGmGKqs4PZuiKNls1ui6kK5qtsH93RJLt6GVMEwLXbfIypK0LJlOZowPDkjSiLQWseT+eEoYRhhdQ7RpG9KyxBsYlEXGfCXMQpZhUtZiMZUVhTTLWC5XeK7L7GC6j2kXWS4ErqqK0fkJFVXBMkz6/T7e9JB+v8/hwaHIHagak9GYVxev2Gx3JFmG63rcLC6gFViwtq6FiVvXcW0H27JwOqxengSkcUSZCVFu0jViWwlquUVRZSzTpqc/ZCVqBoMh/f4Qw3TQDZfLyzmF2jAaTfi5r32FN58edVLgGt3QsT0TWpXFaokkK90zfEAc7ajLmjjOOT+/QJJbNpsNWZax2+24vHyNLMtMBgdsNmvyPCNNU6I4wDSFWdq2TXa7nRDRyhIyUNclvZ6H69k4js3h4RRJavF6Lo5jcXh4gNMh5B3H6dKRyv4Uq6prXl9ccHR8IohfVU3TtCyXK5TNltFoRBCGZGlKUQhXpiIJJ0hVVVy9eoXUCgHOQ1X9p72+EIuCqmkUVY3h+dS7HbKk4PT7mGGIoRu4nott20jI0NIx8wTRVkxZC0zTFsmtWJRKXNvCsWyuzl/tZTOe56GqKqfHJ4S7gHSY4NgW9/M7UbJRZIZDgfUeDgaCKxhHhNsti8WWN56+yefPn9FKsJrPsWyLOBZMxs16SV2VxElEWRVouka8DfB7JlXdYFs2VRXTVHUXAxYps7YRdxRNFTFg05AYj48EjHazZWJNOZjM0CSNu5s547EYKm43G0zPIchCPNdjHW1QTBXPtTg6PSVJMvKyZBvHgsbTNER5jud7uJ5LEidIisJwOKapGrTrW0bDMW3doioaYRiDxj6B+TDkdRwbQzdEldjzmM5mnLz9HqPRSOj6hiJo9MkPP2YxnyMhE0cJeVEiKQqWLVySu90OXdNYxjGpnZDlGVphUbY1miQhtw2WZaJVFcvlgqZt2Gy2OJ7Ll955h9nhAU0t3AdJmpDnGfP5PYvFisnsiPfe/Qr/8Fd+Dc/r4dqGMFNTk5cFd3drPv7kM25ubynrEmSJ8/NbXp2/YrtcA+IRKopCRqMBSRoCDU0r+IYffPBlJAl6PZ/lsuDrP/dVNE3l449/yO3dDZvtgiwTAB/fNGmrmjDKKIqUIMjJ85imzUQJLxTcg08+/YTRaMT7779Pv3tMcF2XXq9HUYjHvbqquLm+Js0ybNtmMBzsjdT3ywWj0Yhev08QCFlxkYravqIonJyc7LVxD/r6n3o9/h1d93/rqwVmh4eUTUPdWZt3y50411cVWkUhjGOSXYDnulxeXqLrwrZ7dXXFdDrFsiyxYkcirtw0dccrcDsnn9B2I0lYrkvQOSF0QyPLUjabDf1+nzzPGI1HDKdT5nd3bJdLer0euu6QxKJ3cXV1RV2VbDYptmMTroQEJU5Fecv3XbGd7baBQhiaCuqPZdPULWkWCsxcUXWVWQNFUviFX/gFsjRnuVjgOi5FVqD4CjfXN2S5qMXKikzVVDiOw2g8ZLvbgQrj4Zg0LdiEAYZh8d6773I3v+fs0SPuF/cEQcjN3ZxpI7yMTdMQ7nbcXt9gmCaHh4fUZcVyuUTRFHRT7U52aizTEvHrwQDHdjg6OMR1HPqDAbbtYlkOWZJwfn7Bi89foGsavf6Q5XK9P65TbY2mbdjttti6SZWVwo4tCaagrCpEcYqEwOev1mviOBKAE03lzS+9xcnZKZZtoxo6l+c3pFFOlqckSUx/0OfDD7/Cz//i3+fo6JgoWbPZrgi3MS8//4zLyyuKqmK12RFGCbppoRkGSAqGYXJ29pQ3H73ZlYtUkjRGVUHTFZarOVmWEMchz559ilzpXVZAI4p3ZFlKliV88OGX9xbrOI5IlmvyXNC/FRnqqkSyNGRZwvVdVE1BVmQGgxlxFO+J3rqu47ouQRBQFAVPnjzBcRyqqmE2PQTAdXyquqKuwbJMZEklCmOGgzHXV68BcQM9Pj7m9vaWw8ND0Q7u+g8/7fWFWBQkCVRTgzTFMjSW93dIsoSuKWiKRBJsuZ/PKcuGO2mB2+/jOgJtNplN8YcDTF1jMh0RBAGbzYLRaMh2s2F8cMCLFy/wgDjLsDp5rWZZbKKAod5DNnU022Kx3TAZTzFth6yo6I+mVGXNNgjRTBPdMUmSmMPTE9IsxXcdNE1jvdni9/rESQoN9Nw+Wz1AU3WCIEZRdMqiFNCUphV3CLtPXuTYhhgWaYpBU7c8e/acoiioqpqenzGdHbLe7pBllaOjEz7+5BNc38O2Lfp9kzQp6flDev6QxWKB53tIkoyu6ZiaGJxu5nPOP/+M0XCILcusb2+RJNjc3YmL3NRpuuacqkkimWhrDKc+ZRVTlQm6ouB7LuPBiPFgzGQ0ZdAfoOkiwbjb7pAQJy1NW5NlJY6tM59fc78Q7ALXdEUlWNXELqluMB0Tb+Di+g5JWaCbCkVScHk3J4wiyqpEN218v8dkOqHMa378o+8TRRGGLmYwk+mIOLWRZBXVMLm+m/Ps+asOt9dDUWWMvsUHR1/DsR0RvtJNhsMemqxxe3tPsAu6KLFgevg9D1luiaIdLRW2Y2JaGnEcEscR4S7h6uqSuhYN2O1my2Kx5JMfP2M4GHJ2dsZgeMD4A4cf/NX3CKNA5BVkGcv1kDUdRTVoaQlDISRSdZmqyQGT5fKessgEcbppuH59KfSCvgDNVHUl3lOmSdtIRGFMlhSMZlO2mx3D4ZSr69eMJ4c0rcJoPKVpRFFts1nT1F9wwWxd1ZRRSBSGnRAzR9M0JFlC6wxETV0yX4pTA82yMF2XVpLwfRdD1/F8lyLP8T2X2cGMIAwZTafIqsr04ID1es1gMEDTdZBlWknCsG0M3+d+taKVwO/30UyTXRihawWqpmM5HobdsgsDPM/jfrXAsiyOjo9JkoTDw0N0w+T6+powjBmPKm6ub6mrhqqsOkZCJJgOhoVpOfimSbAJ0FWRcDs5OcGyLK6vr7m9u6FpGg5mB8RpxIvzl5imJe7iNPSHQzRVRZFVfK9HGIbkFOyCENvxODo65OXz5yyjBUkYMJ1MmI0HvD5XSIMddVNT11WHejeZjUcM+719gef8pUDPFUWGLHvYpo5tmUitjOe6tC0EYUxV3JOlpRDd+hbD4QDf94Q30ffYbtZ8/PFH/OhHH+M4Jk+fPGE8HeHYNlmccPX6UlTIez6KphBEO1BkNEMlDSvuFss9pVjVDOI4Yf3ps45CJIhYjm2TZDFu4/LB+x/w6MlTbNsjSTMM02Q0GtEfjqkbic1uwW67pa4qbMvBtT00RSWNY/p9A1UxqYpGDBelkiRdkWcVRZFx/uoFQbBhMPRpabm5uaYqS3r9PrOp0MZZlk3TthiazXQ64/LyNZeX12TJjn/wa79GEsds1ktev37FajVH7waauiZyBbqhk2YJcRJzenJKkiZIQBSGDAcDVEUh7eZkdLIZVVVJ04TNZkuWFSiyiqKojEYj6qri3Q+/yuZ+zovnzzk5ORKnfF3W5GeuTv///2oJdjtWq5WoQLvuvtFV1DVSnmOaJoPhkLIU+nnhEWxIU9FQTO4EsNNzPXq9Hovlct9UtB2HvCurPMhXer0e8/ktV+fn2JZN0gie3m63o64q5G5LORpN9py7vGPcbTYbcYY8mbDZbPZDpQfOg2VZ9Ho9gjBCQjQNNd3YtznDMCTPM9q2wbYdXr9+BUgEwQ7DMPF9n7opaZoWRdOomxLD1ImisIt+G+i6RhgFRHHEaDRC0xXuF3fsdmvhfpRbEaNVZXa7LYOBcEtKkpCDbLfbvWvjwcD1ICMVAS6ZOAzZrDbUVcV4NCNKYuIkxzZden5DVpdUVc2p+5TNZs315WuKPKeuKjRV5vzlOVEY8uX33mM6mQB/XZpSVZWqKCiLgrIoRXlMkSkbcaT8cGTWti1hKHwVwJ4j4Ps+vX4PTdfo+33auuX1+QVJmtPrj3j7nS+JgBmSsFSlJRoyUiuxuV9wvn1OGISkScp2s+Hly3NxoUgi1KTpGmWRE0Y78jxD1zUkue1+rlNkGbp+y4/aHwt8RNN2WEGdg9khT5485p13vsRw+C7TgwlxGJImMacXR7Rtzac/+oSiSAVwR1Wpypbp5BDf90nTnNn0gLZpKIscVVNQVFAVmdV6Q5SEWKYgP1V1jWmYtFXOo7cfk8QJt9evadqWUSOi8tPphOVywdHBTNStq/KL731omobb29uuP2Bxe3vLbDYTtOA0FRPwosC0bYyqZjQacz+/FW4ETcX1fZIoZLVakoQRs4MDcWF1F2Cv1+Ps+FjESHXRf3h9eclwNiFeV+KO7Wk4rqA177YBYRiR5SVZnlNWAqZR5TlhGOK4AiUPcHt7C4iBnKaq9Ho9yqIijGNcxyFyUqo6omlqiqJCkkXf3nYt6qomzRNRZ9UN/J6PqqkMhn0RH16u0I0Ky7L55JMfiuOqpuHwULx5gjCg1/NZLOY0LWy3G1RVIU0irq4uqYqc8/PPcRwb0zQwDQNVUUkSEeIaj8c4jkOaijfnZrNBlmWOj49Fo0+rmU5gsVwxHk8Io4gsr9ClBnQZxdLRFZXNakXbtizmc8IgwPMcNFUliyM8x8Y2DXqeS1rkbNZr5je3lHmBaRhITYvnOOi6TtW2SKpYsFVJBIwelOsPSLs8z4UPYzDg7bfe4hvf+AaPH79BUZakWcE2CLBMh4PDIzRdQ1FlPMsg2GpEgQCMjLw+J4fHnTvEI88zPv3sM9IsozfooUiChZDlGZIMu01AHEd7AOpyuWK9XHN3e8N2t8W2LTRT8BjKsmA+v2K9nvPtb/8Jw9GYL739NuPxqHvk69PruZydHKFoKrdXnX3LcZlORE7CsU3Ozk55ffGKxf0di8Utu92GR48ecXw6Q1Y0ZEnm/n5BFMU4R8eYlsZ2c09dNaRJSl4WzJf3HB8dMhj2Wa8XbLdb0cuQZdHV+CmvL8SiQMs+rNE0De+88w5ZnlP9BFmp3++zurnf380d22Y4HDHo97i+uUaR4Pj4mDzNCKMQ3/f3dibXdXEGA5q2JYlj+sMhtmGQJjFVUdHqDePRmCRNmN/NSZIMVdNRNBUkGW805vZSnGI8OBJvb2/RdZ2joyN6vR5pmrLebLi4uWW1XKMqCqenp1Q1ZFlJlCQ0dUOaJpimJUJNikycxqIjYYqdked7eD0hzJVVGdMykBUJ3/b2O53BsN+9OZcoyim+7yNJ8p4DeP7yBY5jI7U1SZpgGBpxXFCXBYqiYRiWsAit1/u8vSRJ+11UmqbUVclut8AwTCzDIooigiAgKysWmzXnl69FkengiA/e+hJFnqNr4u56d71jMh5iWxaqLJElMRItx4dH1EXJQhLwHFVRcT0X0zTJixLNNNgEO5pCdEOGwyFBEBDHMWG3exiNRliWRV3XvHxxzt3NHElS0E2TLMuZ3y944823efr0TVpa7u7vWc3vKcKI3W5HmmVIioykSLQSHB4fcXRyjGHqxElM8uOY2XTGkydPGHsDVusVSRKx2WyI44S2Bc/1eP/LH/BLf/+XO4ZjShjuuJvfEuy2VHVJ09aEYUCeZ/zld76DoeuMx0NUBb783peoyhzDNDiYjnn3g1/n/m5BUzdomkoQxKzXG9qmwXEsjo9nLJc2SRKQZQ6eL+L/mi5zcnrQPQ6UzO9u8P0epqUzmU24WyzJ8pRqXXB0LLgg2+0Ws6uq/7TXF2JRUFSFwXRKsFphGGKbHXc25jxN997IJ0+eIEkyN9fXTKbTPf324OiIIo1pm4bZ4SG1IrO6FTsJTdO4vr7msa6TxLEgFVkW2zTl5upaMAdq8IdjgiBCVQ36fRtJVbEtG0VR2K1WBEHAo0eP6A9ES+34+HjPGsiyDNM0OTo+JqsbNFVH1XUuXl+SZmnXKwBVU2lagQLfbDciJmyZyLJCludYlomiimi0rCiYtoWm6ZiG1cVwU/G5aY6iqsiyyvzunqZpefL0DT766COKomA2m7FaLun7PoNBH0WWeP36gl25xXE8Dg6EZ7PuOIqr1WpPmn44qdE0lTIvqauG0WTCZDymbiBeLkSnpK6RFIksT7g4P0eSZILthnC3o8wzPEfIbMrcIIkjtstl59fYic6EqnUOBVivVuiWSVlXFHlOW7XUZbV/7nUcR2yxq2rPuozjGMdyWS7WeJ5PQ0uLRNvCH/7ht/id3/kPrLcbirKiLSrkvEJVFWRVRtYUDMvEtE2ub6/I/7zAdmws22Q6GXN7e80PP/4IWVZIkxTTtDg7PcP3Z7x8ec7t7Q1Kq3Zi3ZjZwZQ33njC2ekJ1ttPaduGi9fnhKGFLFs8++wZq9WKINgi0RBFOzzH4StfeZ84jnj57Bnvf+XrZGmOJMHrVy+61q+OaQ1RJDFbydIYTVOJoxBNU+j1exi6weuLC3TdZDIaoHSSWcMy0DQZXVdp6pb1asWw3ycKQzRN/+InGuu6ZrFc4naMPsfz6EsSqmmSpSnT42Pi7ZY0SdANE8dxhD1X0tBVDapqD/6kaXF6PqbrohkGuia8AGEQEHWi16auGU8mHB4ekex2XF9f05/M6A1GTA2roxnX6IaJrCisVgv6fTEFljpIiKIoGB1E07Is8TzZGYKm0ym33dHSZDwhDFOCMKQo6z0UQ5LVDrZq7wnPRVkRJzlpKtp4um7twZ5JknZ4L6EMOzk5YTQciWBNWvDq/IKyrEmSjPVqTRxFbFcbdruAD99/n35/yHKxQFXF38fDXGQ0GuG67h4VN+i6AcvFPaZhUZQFdVlh6CYnR0ecnpyw3KyRZAWrQ+Fdv74QOQVdQ1NksqokWK/B91BkCcexGfT75HVDkRdoXShqMhqDLJFmGZswAFUQmlEF/PVBIKxpGoZh0Ov16PV6e3DpoD8SVfUgIOtAuaqmI6kK2+WCsqmRVAlTs5DkCkVVQJbIyowmT9AsDVOVkBto24qyyNhs1l2zUOPs7BG+LyzOf/bnf4rnuYzHE778/juQi0iyJPfQdY1Pf/wjoijA9cTiYlsWX/vq11A1h9PTM3bbLYvFnJvr152yreUPfv8PGI+HnJ2dMp4ccHJyymq14unTJ5imTrBdY9k687sb2hZ8v4dt2ciyQhxFHTjIRZEVsiTBsRwODw5YrzZIqsbx6Qm6qpHEMcumom5qjo6OiIKQ3S74qdfjF2JRaFvRAWgeGo9ti6ooJNstareiaZqGoouGV9O2ZLmIag56ojGWZgmj0Qjf9SjKkiyK0F2XshY4rM1mg6qqewpNLUmMpjN0SUFTdeaX1/iTCYaaMjo4QAfqpqWVJZBk+oMBlmWhWhb319eir2CaRFHE+OCAtqq4u71FVVVePH9JXVU8OjvD8/rIis6Lly/ZbAMkWe6CPJ3EVtWp6hZJ1nAsF9vxkGWZfr8vjNuyQZqkGKZJWZQoiozjupRlyWw6E5p5WSLLcmhl2kairSUc2xOJNsPh1atLwjBiNJxRlQXz+bwzLptMp9N9jfzB8P3AlpTbRmQgWonl/YK6bvjwww85OTxC1QVZybZsfu+3f5/PP/sMq0v0GapCkWdkqbBdWaYJdU3bQpFlAh7TAk0r7namwUDts+jI247119mSByz5g1Tn/v4e27bRdR1J0iiqFt1xMD1v75E47fucPnlEEIXc3t5R5SW6pyJLwjAepxF5mVFUBVLSomkyjm2iGzrCkSLwZre3NwwGAwB0QyYI12x3Szabe84OHjMcerw8fymgOVWJZZkUecl2s0NWZC4vrxgMpzx58oQPP/wAw/g5ri5f8fz5M64vX4PEHv3/ne9+m8urC05OTrifX/LoyWN026aVIYkzFFWiquD1xRVVVXa1a42b3S225WDborD3+bPn6LrOxPcp8pQ8TdAta9+RGI/GzKW5CKf9lNcXYlGQAKmukRUF1RDps912u++Et7sdpm3jDIbEQSB493VNksTYpi622oZBWRSsVitM20I3DJHTl2W26/WeQrxarcTFbRg0WUERRqxXK16+PMdfrnj61ttEu4DBdEqVZRi2i2knOJbwMbRpyuzoiNX9PYqioGkabWfy7fV6ZE3L0dERw/GY65sbZEUny0uRQnM88cO28QdTHMdlNpvheR6+7wtzNaKlWFUVw+GAoT+m5/cpS7EbkmRJlGIWC3Y7IbN59Oix2DlMRpimQRQEAhqy3ZImKXEk0FuqpnJx/oIwEgOnB9WZruvc3d2h6zqDwaBT2gmrsa4ZwtVQNezWa3700Q8Z9H2ODg/xPI+zyZTRoMf89hpD0/b5kbapcG0bTVFom4bdZkvRmbVN3YAWFEkSx9FVgmaZ+J7PLgpIkwxDfzhyE4yMuq4ZDod701YURfTHMzzHxzRN4iTm+vaWvMixZIvpbMLho2M+/PpX2K53hKsYSWqFTiAJeH3xiijcURQplqnhOiZ13RAmOaqiUzQ5t7e3rNcrej2P6WxMmgWkeUKcKlxfvkBVNd58espms+PVq1coEpimhdzKtBVMJjN02yYvCv79v/9tyjLn+OiAD95/n69/9SuE4RZNVVguF5imxm63oihiHj96zP3dLYam8eTpU9597wMur67I4gVHh8ckcSjKf0kGrcR6ueHpkzcAMRSdPDmgSjMaQyKKQvqGwezwAFpZNG97fZrqCx5zlmSJ66srBuMxatPs2W+mbbNdr/dKejPPcH2fpq4p8xzHtsiSRKTDXHFBZXFCFIaMDw74v5h7s1jNsvM871l73v88/2c+p6q6q6qrupo9sNlsskVSo8PQsC0HAZILx0CCOBcJggC5iq8E6DKxBMNGjFDxhSTIEjRRpESZkkjJJEWKQ1cP7KHmOvP0z8Oex1ysXUekQjIIGAe9b6rq1Pnr1Dn/3mt96/ve93lFnqMUoSvTyUS6GaOIZgGYODs9RctgPl+gKgrLpUNvbZXl0pHJy0KQFEj2UbFDVSoVsigi8P0L5mK1WqVWr6OoKpV6neXSxbRtOt0es9mSF1+S1UEUp8zmS87OzgkTFV036HW7KAW1yPcjPM+VysOTE8IwhESgCvlwZFlGuVwiDGWpfHJygmHoJMlfUq6ULyy7lmGgGxqmrhOFIYKcZlNOGxSh0ul0aDZlPuG9e/fIskwmaxVefpBmrdiQx6E0jiDPsAyTyXCIkibkYUytWsVSNCqVCqsrq8UOZlGyLRazGVEQYlTKVGsVDENjuZTiHWEYJJHM0nRcl0qtRpQmBGlMmmbEcSKJTUX2hQT3yqZzq9VCURTOz8/Z3d2ju75FvV5ndW2VG8/dYndvj6OTQ7733ntMphOq1SpkAlOVFK+z0Tn9XpsXXn4RZzFjcHYqob5ZymLhSJzaYk65XGJ7e5tSyZLJ0CWDnBjLV4lCl1Q1UfKcg4M9trZ22Nx8jbt373N+NkQIae0OwxjNlvFu1WqV6TRiMhnz7e+M0VWVmzevc/PmTabTCePpgOOTA6pVm9FoQKvZxLZrDAdD0jihUq5RL9fQVEHJtphOZ6SpQ6fdZTQaE8cJjuOSZxB4UuXZ3GjT7rQYnJ2jaTq1ap0szijbZbq9/o9+Hn+cMeL/r+vWjev5b3/2X+L7Pv1eXyKotb9thAgE0+lUBq2mGVZBRVIFTEYjHNdhfW1VevoTOee2LFkO6pbFbDJheH7OxuUrzAbndLs9ZrMpgeszG04wLUuitAyD9Z1tMqDcbOAtlkRJgrtcEjgLatUqYRTR6/fZ3duViKtaDVXTSLMUIRSEoiGynNlyyXw2J0lzHj3a5eGjx7z3/l3G0wlnZ+fEmQ0IWV0EvsxwzGU2gCh2VNnD0IkjSY56Mv2QeWwU4zk5tej3uwSBR5rKRTVNEvJU6gJs06LT7dKo1fG8OXHkyKZdsfClaUoUJ9QbdYSiEMcJ1UoFo4CoKKoccyZxzGQ0JE9T6hXZLzA0ndySRzLf84gjmSURBQGu41Cv1bhcSHSnjothWlJX4riQ5xd4u2qjjmFZTGczojTBtGRkepqm0vqeycBez/MKjUKDTm+NN956h1K5TK1WvQDBqJqCaVmMxyPeu3OHMIiYT4t7QlepVcv0um1UVbC5voZlGrjOEj8IOR1Mmc9n1Os1up0WjUYdVREEgUcU+mQFzUhRJfEgAAAgAElEQVREEeSQ5jmu65OmOVev3kQoKrPZgnJFhrTkIiGJI1qtOqenR1iGjIpr1RtkWUqv0+Hq1avYFZuFu5RA1Rxcx2VtdQ1dl2rTPIfVlRVKZZvxaCBH5FGMqqioqmRmKorCbDqTFvEk5Hx+TppJ343r+HQ7PdbWN1GEim2VsFbWb+d5/uG/+zx+ICoFeZ6t0OyuYGkauRCUKzXGBUXZrFTIxlO8xUImOEWB5B/YNqau4RYg1AhBFMeQZbjLJabRlqusZSM6XQyg1+lKelCcUK83Kds1DNNkOB7RXV1huVhI3bWAIAwkSTHPEKj4foRm6DiOR73ewrQswjhGzVM0y2Q2nZH7EY6zJMsgSRIODo84OjhkNhrhzmcMjo9J4xg3iDAti8lY4r/SNEHTFPzEQ1FyOYXJYsp2W+6+Jf0ieER6/qVHw7QM5vM5ihpSLgsUxUDkCvPZHC/wscwSzWYVhZzpdIypCbIwJPA8XM/HLtmUalUsy5Z0nnZbuvCiBKWIkmt1WiBanJwcY9UqRL6PG/nYhoGlm7iRzBwwTB1NU6gVob/zxYL5ckma5dilMqh6AVPJLqYJqqGjaBqu55KlKaamYZfL2AX5OQgCVE2DTJBGIX4UEi9mzNwlo+mcV15+mclkwtHREUIInn32WVRVJQgCSprJCzc/xHy+4OzsnPF4zHB4TpIk0ohm2RwcnhRYv5R6o05vrUuzW8d3PIbjMcvlkuVsjipkAI5RBB2nqcT4hVGMouqUqw0G4wGbW5d49dZzhJGsevZ37zGfTzg738NQYRb5rPTaUDU5OzpGJAGz0YDrz95idXOTtZUNBoMBSZxJRF7dQC8mctPFnKXv0t/cYnJ2RugFWJaOocusT5KEJImYTn10S5eah3KZ4XAsHZgCgtAn8AKi6CcLmP2Pfgkh6K2toRRxYF7BX0SIC8GKYZrEaYxdLstzUbOJacmE3pWVFZaFRFrTNBrr64zPznAdh3KxwxqGwXg4pN3pFIKkhDRJMEwLx3WoVqs4nofIZEZivlyCIhiNRpRLErv+xEyycJaynM9zhKLgLlzstIznONRLJYKxj2VaTCYjBoMz/MAlTkKEkHPn4dBFUW0Qkl8YxQG2bRVMCBkEKhQwrRKGCeWyQRB46LpBt1dHCIU48UnSiGjpU6lIW7XrhigiJU1SnGWAqmokSYoQKuvr6/IGn0/QdZNqVUdoGkvHIRMKhpVimOaFQGexXFAqtBphGJErMvhV03XKtk0eJ6z3VySq3XVkAlEmjxiVSoVatcp4OGJwds7R0RHVapVqpVaE2OYoyMoiSVNM2yLJM2nuyXMMclzHwSikvEmaXOgW8jxn6cr3Nc/h61//Ot1Ol1qtxng85q233pKJ3aZJHMcMBgOeeeYZNje3cF2HNIm5e/8e+/u7lMtlsiyj1+0wnU0JfJ/FcoZlWWRJRKNaJksSbFMvqq+UNAkJspgo8EjSDN0wMa0SlWqF7e1L1BttqTFRNU5Pz6iUbMndUFTskoEgYTwZoxUcUdMwqdXqnJ6e0ux0ZO5HtUq5VKJer3P37l0ZVpznNOp1xuMR0/GYZquFJmRD1PU8At+XStwCg+e5HkZFBt5oispzzz3Hwd4BaRwXMvkP+kgySVnOZjS7XWajEeVSCfKcOAxlJHm9jm4YOFMFVdexymW5S/u+jDkTgmzpgKJi2Danh7JDq2k6dlnINOHBANO02N8/oNVu47guYRBT7/TIVJUkzwiDmMloxPUbz0g0vC7fIGn2kefsJ7LpJE0Jg4BWu4VhGpiWha4qmArU69JUo6g5V57aYdUPePjoMQeH+yhKRqVqEeU2k9mUbrdD5idsb29IV53nYtkSnyWVhgkQs7m5wvn5EM9bUqs3qNVqkoiUC2rVGmenI8rlNo1Gg9lkim3V6HY6dDsd1tZWKZdLTEdjxkOLxWyM47qomkGpLDMmXM8ljKOLc36z0SDyQqI45uT0FMMyqZTLlEtlDFUhi2IarRbe0iE3DUajEVEQFt6V+CIdKs1Szs8lGk/LFCzLliO0LJM7tABN1VFNnTQRiCwjy8HzPZaFW1B/QkHW5fRoUGglup0GaZwTBj7TidS41KpVdnd3i0i+kPl8zp3332elv8L29jbtTputjXXWVnqMxiNmqpBsS8vEMAxOTyaEzpIsS6mXbIyyjaXJnlTou+iajqprREmGUDTKlRr1RpN2p4dpSkbo+kafk9MzOp0Op0e7nJ2foyoZhibhNfPpqKCBpaSZTODSNY2jw0Oq1SpXr17FNA3G4wmXL+0QhhH9fo/pZEKlUsHSNI6PjnAXS7rdLq7noYAMR6pUqZRKLJw5iUgI/ZAojHhw5x5RFFGv1nFdlyj6CQxRQohN4DeAFSADPpvn+b8UQvwS8N8Cw+JT/3me539avOZ/Af4bIAX+xzzP/+zHfQ1FVQh8n7ODAyrNJoZlsSgAKmEYsr+3V3D/ZENMFQrL2YJypSwZC8WqKxC4jgcIhFAl6nqxpNFo0Gy2QZPkI8uyuXTpCq7jMh4O2Ll8mWVhUQWIwgi7XIYsgyzHcxwatTpZmkh3ZKtFs14nzVKWjoNpW0zHo0IcI7BtkygK2dzaIMty7ty9R71R4+bN67z73nsk5zGLhUe9XqFWK/P887cYjUbFGIaL7MkwDBBC0G532N3do1Ku0++vEQYJiqYxHk1pNdtYZoObN7e4+vR12u0WmqrQadeoVmQZP52OyMnZWF/H9xzcxVJOOUyDg4N97t67S6PZxCrb8j2ncK4aOr4boRsmlmWTAWkUE6YJFcsiThLscpk09C90G6Ui0UvXZIDudDxhPB5z7949ci+m0Whg2JJCnEQxqQIxObkqsMolHNdFURVazSae78usA00KrDIhewy9Xg/XdTk9OWFn+7LUXJSlPP58cEa73cbQVSaTJZ1Oi+PjEx4/fsRwOKTZqtNut1ldXWFne5sjTeHo6BBVVajXKqy0b/Ho8WMm4zFnx8cShV4E+Ahy4kg2bstV2X/pdrpsbe2ws3OZWqOJpuqcnQ2KRyVnfWMdXVdYW+syHp0ymYwIPJexEPS6vQuORsWy8H2PIPDRdWmSa/W6TAYDLMskB5lXslgQJTFHR0e0G00WiwU7OzuyGiuVaDaaJFFEf2OLk+N9fM+h1WyhazpxnHByckKj0WA6/cnArQnwP+d5/oYQogrcFkL8RfF3v5rn+f/2/Z8shLgB/BfATWRs3JeFEFd/XEpUnueUbJvhcIjr+yTdrhxRKspFV3w6nWKVylQ7Hdz5XLrMhEJURLH5fojne7iuy5UrV2RkVwGVEIrEpumqSrnd5vDwUI4lNZ1aEbX1pMPd6felJsAPCJKYyWCIyEHJIQpDbNPEnc+p12uU7SpxmqAbBicnx2xtbWJpMBoO8DwPu1Ri/+CQNE3lQhHHdDodFssll9vr3Hz2WaIo4vbt2wUO3qBeqyMUQRhGVKt1dM0mDBTq1VUMw8JZZLRbK9y4cYN2q82lS9eIo4QwXhAnKUdH54xHA8pli1rV5tLONtvbl6jVq5SrJc4H59x75332dh+zXC5pNptcefoqy+WSR48fFPFjdc7Pz2jWu3S7PYSmEEQBvu8h8lz+PFQd1/NkQngUX5B8arUapmnK8v8JE2A+x/M8Dvb2OdFPqNSqqIaOGwXkukq5UafRaKEZBtPFnNl0RrctzTyGYUgEveuCqjCbzSgVlvU8gUf379NqtTk62Jf6jSjm/OSEcrmCrmnkScLW+hpnZ+ekScR4MGRwesrRwR7dboePfORl+p02t2+/zsnREYkvj4YVWwrnnKWc+rSaTTTNlhMhJafV6VGpVqlWa1QbLQzbZmNjk8APMQyTlZWVooyfYxoae3sPcJ0ZgbdA12QjOU1TslzazfOF4MrVq5Ilquu4jsNysZBHD9PENgwqpRKKpjF3lrzw4Q/jLxZ4rsfhwQHt4ji9XCwgzwnjiPlsQafTIUkS6nUJorVMi+l0yvQnwbEVcfNPIueXQog7/JBo+e+7/iHwO3meh8CuEOIh8BHgb37UCxRFuTivA/jFzSqKzni906FSq3F2csrDu/fodruUbJ3A9YiiiEqlQprlpGlOGMXs7u1TqVSkek7XCKOYcOnS7/fJNZ1Gs0UUhngFwSaJM7zAp96os1wsCYOAII4xNI3pZIJpGChZhmEaRHFMd6WPs1xQ0xTiKKTeqLO20mc2nmAZCqVSiVKpxOPHewghsG2b1dY677z7PrZt81Ov/RRWrcdbb7/Nm2++habJsJV6vYGmKWiKjq4bVEpVTKNGuVyn0Why88ZzdNpd6rUmh4cn3L59m4f3zzk/H3Lt5mXWN1e5cfM6hnEdRWg8fvQAw7Dw/IB3332Xw8MDHMdBVVS6vQ6HJ6fcf/SQ2XSK4y6lLFbXCX0fXZd+hLKi4Hk+mSJlxEkqUeNRHKPmkMYu6ArVapXFTMaSJUmCs1ziuR5ZntNqtej3+1iZRpwkGKaBZplgaFiVMnatgmlZZELIsjqU+gnTNC96QqVSCT8KqdVqnJ6fSXza0kMT+sXP++zkBAoPx2Ih/THtdgvHcaVqNAxRVIVKpcFsPmG5nPP2W2/S63f5+Mdf5WBvn8PHD+l1pKBraTjMZnJBOx+OyKCwiNexq3Wevn6d9fV1NtY3pJYkirHtMpVKhXv37vONb3wD31/iew6GIYnjWZZTsss0m9ICr2s6uQrdbgeFHMO2SOOIJNY5OT5mdX2dyIw52NslSVPWtzYRWUZaTD8Amo0GQlFwlktMyybJMjRVpddfJYsTFrMlvW6fsl0mLBZ3Xf//qKcghNgBXgC+jcyY/B+EEP8V8DqympgiF4xvfd/Ljvghi4gQ4p8B/wxgbaWPXaQzCyEujDpPtO+KqlIql2XmIlK9p2v+xYIQxzFJlrK+vU11PiNJU1rtDvPxCNuWnMd6s0mpaCwpimyYCVVFUVU6rRanx0cEQUC1WuX05ESadHTJdZyNxyS2RJDFUci7b7+FVSrRC3xavS7ucoFlmjjLBcPBFLVw9TUaLU7PzjFNm8ODI1568WWWzpJ79+7x19/5MienZ1iWjL237SpRmKIqOc1Gk83NTZ69+SytVh9TrxLHktD053/+l4xHU6rVOs88c5PtrTW6vT5eNGbpuRwc7bOYzWi1JPTlP3zta8xnMy7v7JBm0On2OR8M+KMvfJFWq05QNEwNwyCJI3JVUpYM0yJJU2yrhF9oQmy7hK4qzMZjRuMJpCmmrlOqSju3aZoXOgff9wuLeEiv2+X69es0yzIARSgKiq4R5xmdfg/V0BhOJ5wNzrEMg/HZ8OK1SZJgWKZMCSt0GKVSScrhy2VECmenJ2xvb2PoGoeHhwS+R7lcxnUdBudnVKtV6rUq02mC4yyxTJ1GrY4qBIvFjMlkxHQypt1q8vwLL/L666/jeR5BkexcbTSI4gihKGxdusRTT19l49J1er0+tUoF27ZIklSmWXk+b7/1Fm+88SZhEGCYCqoqOYvVSpXRUHIshBBS7WnbmIaURRuGTrValU7cqkxBu3/3DleuXCmeVu0iAGk0GrHa61+E9ZRsG01VGQ/lxM5PEjRdGp/yLGM8GrG6tkY8i0mThH6v+5MvCkKICjKO/n/K83whhPg3wC8j16tfBv4F8F/zw3Mn/29iiDzPPwt8FuDm9av5+ckJ1WYTtTAZTSaTCzdcnueyS9zvkxRhpSCNSL7vE8XxD0SaVStVAsehWquDEOhQHDGCCyRamqYkaYKiKuTktDsdkijmYG9fGp6ee47j3X2SOKJcKjMenyMEmJbFzs424/GYO3fe51J4GUWVO2W9Xmc2npFmCacnA1RNo9tfI0tTGr1V/sNffJmj4xMODg7IMkGpVCWJE1rNLp1Ol0uXLnNp5xLPv/AipVKJ9969y5996cuoqlGIj9q88spLlMslylWL+/f2eOe9N9DvG6Cn9Fbb9Ho9cmIePr7P01ee5u996BdoNOvMx3OGoyHf+Oa3uP/wAe1uD8uUyskwkD+XPFNRFZUsS3E9B8tuEsYRhmmiaBqT4ZA0TSibpoSKxAmq8rdJ05omTUJxIUXXNI1Gvc7a2hq1Wo2tncus9Fdkoy6O8cMQq2Rj2RY5FDe0Qb/bxTItGs0m0+n0IrQ1yTOyPKPT6XB8fIxZNmjWZI5HqWSzXC7I86wwqJlF5ZkzHA4olcq0Wg0ZzlsuEccR5UqZ6XRCmiZ885vfoNfrsdpZYfvSFQ4OD4lmU5IcyAWVRotGo8HOlatcfvoq7d4auqazdOVot2zbVGs1FvNF4Z5d5ejoCNdZsL6+ymIxpt1p02k30FVoNhvkaXYxGSuXbAxNxXOWJFHI0d4uG2urTKdTRoNzLl++TBBF3L9zh97WNu1Wq7DWmximyXg8lhkdxbEkz3KmI5ltYag6znzJnfG7JKmMsavXqz/ZoiCE0IsF4bfyPP/D4qE+/76//zXgT4o/HgGb3/fyDeDkx/37T6y7nuNgFrtsvdmUfYECbGKYJnGWMx6N6K6sMCnCMoQQlBQFx3HY3d1ldW0Nw7ZZTqcoeY6CpNf4BZfhiblGN02UXEeoiixpy2WyZHGx8k7OzrEtk/FySRyFGJpUBx4fH2OXbPTCdfn2W2/hBwEUcXODszHP3rqFrks8epwL5rM5Dx+9SRxnJElOkmT4foyhW2xvrXLzxi1u3foQy6XDZDLlz7/0l/h+wNraGq989GW2tzaxLIvd/Yfce/A2d+7codVq0O/36XQ77Oxsc3x+QpZHHB7v8cy1azz19DaNahPTkF31YTxksZjjuj7Pv/ACL7/8IkeHR7x5+3XW1lZQFdh9/JCNtT55npLnAlWvECcpVslmNBkznc1YWenL8jWTVGby7OKYZ5fKeMUIWVNV+v0+5Dn9fp/V1VWq9TqVeo1KvUYYBCRpKpu7QmAoKhXTkkc6u8TR8QlWYTSLClWpomskcYJuSjm2ikKWpqiKynQyRREKrWYLz5WOWd/1MIoE5iSOaTUb2JbFyclxoWCdkaYJSRxjGgaT8YTxYM7lKzFPPX2dk7NTNF2n0+uyvrUpv4/1dTqdDppewjB00iRjMZ8TBT6e40rfTbFpXb92jdlsjB+4UtE4mbKzvU6jVqFkWtQqFcigWqnR7XWYL2YXzt6VdpujoyNKtRrj83OJb/d9tra20KtVkihCNQzMUok0Ti6ehflkSrleJ4lTTEOmQt258z65yDk9OaZUsqg3qqT5T8BTENIf/G+BO3me/8r3fXy16DcA/CLwbvH7LwD/TgjxK8hG49PAd/4fvgbtYgSn6TqqEGiGFIk8KUNVz8PzfVrtDt5ySbffZzaZ0G63oThzOs6Scq2KyHOaK33yJMUydMIoLHwKkqjjLJcy8rxaYTGfSZNUmuD5Lpvbm0zGY+aLGUkcgwKmbZJGguXSYWV1jdl8xnyx4O79B4RRiG6aHJ8cs1w4xLHgnTv36PVXGI0mOI6HphscHBxJ+lKWUa50eO6lG3S7PeI4YW9vnz/63OdRFI2tzS2uXbtGv7+CaejcfvO7fPXrX6Fer6MWFcn2pQ26vQ4bG+sMhwNOzw7pdDs8fe0as9kc2yyhqhr37j/ke2+/y6OHj8mSnFvP3uQX/7N/gGZofPc7r5OlCa+99nFyEt747ne5du0amgIPHz7AtktYJRN35NDudsiylK2tLYSAyXCIKJrDCuD6DnJDVUkyyIQKik613qRk21RqDdrdPuV6DdUyEJqsFAA81yWKIhbTOXmSIeKUarlCr9cHAZ7n4YchQhE0223q9QZREmPbJbyFi09IlqUyFanZlEQucgQCx3XQixDXKApIEhnKQp5KJmWSk8YS929oGoqhEqcqfhiydB0++rGPYdkWzVabza1N6s0mpiW1E0JRSBIQIqFWr5KUTPI8IzqV7ILNzU1ef/11zs6O6LSbXL58melkSLlcxnEcWo0mcSpVp37og6GR5jm91RU5iRuc43oeXuCDonByeiqT0fKcepwQBD5pksqMzc1NFEXBWSxQNZXpdIymGYRBgmbqVOs1HHdJb3WFVqvJ0pkz/Qlj4z4O/BPgHSHEW8XH/jnwXwohnkceDfaA/w4gz/P3hBC/C7yPnFz89z9u8gAgFAWrJLMHNF1HURQyRSGJIhqNBsvF4oLGpAiolku48xmtdgvPWWKWy4gso16tEjkOuaqQFicWVdhUa1WiIEDJwVBVSsVEI8tTTE1hXnAXBRmtVh3TUBlq4gIBFvohmRD4YcT88BChqghNxQlDTs/OUXSNs8GAOE4Zjj3eur9Lnsv5okAjy8A0ylzaucKrr36MlZVV7t55jzffeJfZbEatVuO5D73Ac7duMZ/PefT4IX/zzW/KwA49J8lSKvU6lmVjlSs8//yHuHLlKZIkuUDBlctlFHQiP+Vwb5fbt9/gvXfv0G53abd7fPrTn2Zra4Pbt7/NyeFjVlZWaDTq3L97h9lsxs2bN3nj9usMhwOEUJgvlgih0Wg1mc/GlGtVNjbWJMk6y6iWyiyWUsacCoM0yzg8G0lGg6LQanbxY7h24yq2bXNwOqSTxmRF6vbSWRJ4PrPJFFM3mI/GHD/ek2IlyyQIQrJcVlWKohLHkvxsGAZxlGCZNqKiEHoheQ7lag0/jNBMk5pl4HkudbuOoghKtkkcBiSJR71Wx1kYMh/BlyE3Wp6jC0WKt+pNmSVpyJzJq1evysq1ITMi86LvFYkEw9RIYqkxSHWBEE0s8wZ379zl/OycTr+Pks8JA4fjw8eUSja2YWAbBjmChbOkVLLJNcFkMsKqlPDCgG6vS0KO0CUIp1wu43ou9UqJIAyIz05IU5l4pVdKjMcD2aBNIxQNIi/ErpSIs5QgjVi9vM3j+/dor/ZQVJWZ76EZ1o9+Hj8I3ocXn7uV/+UXfg+zWiUprKRhHMvRVmGZ9cKQyzs71BoNnGLs8iQLMUkSmu02omiY+XEEQmZUzmczmaxjWWxu76AqKs50WgAwoVqRkVpe8XXr9TpxHDObzTg8PKRUKlG2y4gc3nv/fcIo4vDoGN2yODo9YbFcMp3Pmc7nBEFEkulomsHp6TnVag1Q2Nq4xE/91KdI4pQ33niLMIwQSs6tW89y7dp15vM5o9GQ+/cfFK68Booi8DyfVq/FredusbOzTbfboVyu0Gk3cAs7rRA6R0cHPH68y3g05fj4mDCMKJcrXL36FC+//DK2VZV9hgf73LhxBcvQ+dznPsed99/j5s0bdFpN7t+7x2g0ZLlYkKUprWaT1bVVytWKbABWyhf6ifl0iiZU3KVDrVIhTGJKts3p2Sm6qlEpy1i5ZqPB5Z1LlCtl8iyjXi1jGHqxAAvOTs84Oz1FEYKz01OGgyFxklDpdGiv9HnwUJKtK7UqlmUxGI9kA7JIw9ZVnciXE6YnbIs0i/E8F6WAm7ZaDRRgfH5GkiY89dRTPHz4ENeVxCvdNNBUjWazSa/fZ23nChsbGxdxg09+fcKxzPMcRVWJRYJeJEZHUYyzcIjCiN1Hu/zVX/0V9+/elyxNsaRSkirParXKpZ1tOgVRqt1pUS0a6CB7ZP31daq21Iucn5+zWCxks9UwcD2PerWGoetMp1Ns275wjfb7fUrVKqauFxV2QJKCalloyIzO3kpfKoZ9n9lsxnMf/7kPrvchzSRLUdXkOTwIAjl5yHOEqpJkGc0iD9J1HA4PD9nc2rqIIHsyzoyiiFarRa1WI0wSstSh0+kwGg6pVaqEnkcaJ1KOa5rkCheGoLBwPuaKUuRGZBfIssfTx9ILoGlYtpwVn52f43o+qm7y1NVr7O7t8/jxHktPpjG32m263T47O5col2q88dYbDM6HbG5ucfPWs9y8dYO79+7ypS//Gffv3yeOZFS9aZkMp2PWVtf4yCsv87M/9/P0+y08L+Tdd9+j2+3RbDY4OxvwrW99i+FwXFjCJ9h2iW63y8c+9irPPHOddrvBw4cP0Y2MSqXFR1/tcPv2d/nqX32VBw/u8/GPfYxms0MYBjiuR6UsG59ra2ukSUIQhKTktNptUFWCSO7efhCSxQm1coXzwQDPd6iUy9RrNZzFUqZmpTHOfMbRwR6dTgdDNxDF+X0wHKKoilzsPU9CU6Zj3DggjmJGB/sEacrKygqDweAiJewJS1LTNFzXxQs9LEN2/jVNUqSSNC7AuTWEECwWS0LPJfE8EALP8VCEQq+/QppnUqlZrdJsNqnW63S6XdY31ml3OtTrDWxb7qhPUpUUFBRVQS84iZom0FQNkQtiM76A9zabTTRNo1WtEfoudqlMr9dH03SGwyFbly5Rr1WICnDs+sYGiqIQ+z5qpUKUJCRpSrVWk81IXb6uUi4TBCkbGxscHh5Sq9UupOmNIlU6S9OCl1EiWMyIk4SV1RVUIVBVBcsyWFn5gLskn7vxTP653/g1jMLmfHx8TKVSoVk0G7v9Psv5/AK6Ojg7QwBbW1tMp9MLsCtC0Or1SJKYk+NjatUq1UYDspzED9CLVTL0fckTSBPiJKLaaJBEEWEQMBwOL27UeSG6sS2L2WzO48e7JFmGaZd4vL+PH4SEScp0NpPlaxCyt3vM1tY2L730YUajCfv7+/hexMrKKj/3c7/Ao0ePcZYO//4rf0aaZrRaTelsFFJG/fTTV/nUpz7B1atXUVWN0IsIgoDT0zMODg4Iw5DHjx+zv79fJDaV2dzc5PLlp/joK69w5coVFEUi7u7cfYcsTWh3ejx4cI+vfOUr7O8fInKF1177OK985CMcHR1x9/332H30iE67yUsvvcTbb70pfwa2iapp5AIqjTqu71Gv13l47z5pGNGsNzg6PMRzJqys9On3+ozHY3RVo1ouF5OVprQv5znddgdV1bh77x6aruF6Hm7g02q3SbIU13OJ0xRdM2m1u0xnU2kCK8Jj9w4PKJVKtNoy30NFxdBk30nXJdpcKDlnZ2fMZhNpFVcEkecRLhaYlkW91cQPAzT5+PYAACAASURBVPprq7R6HVbWJKPxiZem312jUuDfTEuSty6uwoWJgFzkZFkuuRCqShwm0jUZpyzmCylhTlPOju8zGQ2khN11pICuZGObOteuPs1wMJB/LpV57/33qVYrCCHodDqoukGt2SBLEpIwIoxCKvUGZ4eHmAXl6+joCMuSNDLP8wCwbVsKlSybs7MzXM9lvYgR6Pb70n+SZ/Se+tAHt1LQdI1Op8Pe3h5WkaTrOM7FN+46DtVGQ1YTQkgYSZYRRnJcZtl2MVO3cBcL4iSmt7KCu1gwPD6h1WrJJOpqFQG4jkMSxVTrVRk2oqpodgnXcQnDiLMzOduO44QwjLBLJaxSidWNDe7cvcfx+ZBMKAwnM/wgwgtCzoYzSuUyL3/0VTrtDt979z0mkwnb25e4ceMmg8GI3/yt32T/4ACBIM4TDMNkPBmxurrKq6++ymuvvUan02G5XDIcDahUqkwGc/7oc1/g7t27jMYjLFPi39rtNi+88Dwvffglnrt1izwX6LrO3t5D/tW/+jc0mjWef/45qrUKv/4bv8G7775NFEWoqsHHP/ZJPvOZz3D7jTf43B/8AbZlsLW5yTPXr3J4dMhgOLiIFTNMEy8MiFMZO6/pOlbJJlU1ZvNFYR4yqVYreJ5Lu9Vkf28Pd7mgUqmAaDCfT8nSDFXIXTQIApREZTSdkJFTFy2EoaHnFoaqYGk2o5E8SiyXS4JQOiV1XWc8meC4Lmtra4hMEPrhBbJ/OBwSxQH9fo9y2ZY2ZDLyNMXQLWy7RLvdpdFu0en3WNve5NLTT9Ff6WMUC4CWq4U9XV5RoVUAQJFOybzoVylCjrPzTB5lBaIIQT7HMi2azSaXLj3F5ctXiKKA5WyKqgh8d0m9UiZLU8hSojBA1w2uPv00e3t7UsW5WMoxuuMghKDb6xH4PrPh8ELMNSrSyzRNk8lhilIYxXJsyyLwPTrtJleffopcEURRyGwyIiPHtOwf/Tz+R3rO/19dWZZdkHWCIGB1dZWsMMzouo5VqaAUBGC1wHRNJxOiIifv6PDwgsqTJJLFtxiPyVLpFkuKXAHdNDk7OiL0A0zT5Px8gGFZOEuPPM/xXJ80yajXmkwmExkk2u0yGo8Ikoijk2NyRVCp1RjPFqS5YDRdoBkGrc4KL334w7z/3h0OD4/pdro899zzPHr0iN/5nd9hPl9IPmMsE4tLJZutrS1effWjPPvsrWJ3kwapweCMB/cf8PW//mseP9hHEfKB0FSNRrPOa6+9xic/8QmuP3OdRqPE0dGAr371a/zVX36Vvf1d1tZW+PhrH+XBwwf8yZ98gSyTltpypcw/+Mx/yvMvvMxn/8/P8sYbb6BrKq3WNs12g/3DfQ4P9tF0mbjsOA5oGl4Q0O73cD1PqgPtEk60wPWlq1Q3DYIwJAxDXNdhNp+jCIFlW7IacBwUVaVWbyKikEyROy2qgm1bLD1XgmQLvkIa5UXWpVKoVVOCKCLJJFpvsVwyHo+plWtcvnyZu3fvcnx8jKqpaJrKcunQbEp9hOe5xEHAWrdPo9nALNk8de0qK+vrmGWbaqNOqVJB0TTyPEfN1R8Q2hiGUShv5Ed/oK4WXMBg5Pujkqc5zWaTe3fv8e1vfxtdS7FNA8sy0RRBGgWEvkunWadkSxZGybJxl0uSLKPdbNJbX+f85ASyTGZWZBnNwuA1OD+nVC5fJEfX63XOzs7kwtHtFlWTjEIslWz5bCUxWhGwPJvPyQovx4+6PhCLAkAYx7R6PbzlEtMwcHyf0HFkh1VVmU8mlCsVtGLVbjQa0ikZhiQFlTiKoovzVbPZxvN9RA71eh3PdTk/PiaNEwQCUzfYunKFBw/uc/bgAUmSXOgY7t+XSURPJMqD4ZDpcsFkOiWIEvYOjplM58wdn83ty/RXVlFUja99/W+49ezNCyrS7/zu70qtQuEaVHKFy1cu8dRTT/HTn/pp6vUa33vnHfIsZXWlz59+8U/53//1vyaKI7lD+j62WUPXTZ566gr/6B/9IjduPMPKygqqCm9/73t87atf56tf/arE3ldK/OzP/CxxEvPbv/1bDAbnBGGAYWi8/PIr/NN/+k9QNYN/8Su/yuHhPqZp0mm3eeraZVqtBn/we3+BZZtsbW0SRB5hFBFPp1iVMnGSUK5USeIY3w8IoxhNN3AXC/I8ImOBrhscnZxAltNqNqi3OoRJytz1UBA8Otij3elglGxc36O72qdShP7mwMJxyLMcx5PVgV2kjjeLBf90cE4QBPR6Pa5cuUKtUuNg94BqVTIdoyjCD1wWi4VEqPV6rK+v0ajXqdfqlMsVgjCk3evQW1tFUVUUXUUoCmleBNUoP/4+/YHryXGiCPyJolhSmE2Dra0tKSTKQtI4wnOWCDLajRrVSglTFQhy1Bxmkwm6baMXLMrR2RmbW1vExXHWNE2yKGIyGlEul6Vj2HGKQKNz2STt9QAYjUYSwJIk+K50vObtFuE0wirZ9FdW8DyPSZFb8sOuD8SikOc5eSpnx3ZBVXLPzy8w1J4nd3JNVaVbsvDZR3GMoeusbWwQRxE4MuzD0I2LOXrJMIjCSMa6qxpW2SQsMiWXrkutWmNj5xLvvfUWDx48RNd1XNfj8FDGmp2fD6i3GoRJzOHxMa4f4AUxGbC+scn6xiZpmjMYTnjhxZc5Pz3i/fffv+hug0SUV6sVnn32WX76pz8loR8nJ6RhxFpvhYd37/H5z3+e6XRKGEaYpkmepKz2+jRbPV588SU+9alPsbW9wXQy41vf+ianp2f8/u//HsPREHKo16t85u9/Gs/1+PKXv1Sg4qDVavHzP/8LfPrT/wlxHPPLv/RLHBztoagKYajx0Y++xPalLf7tr/0fLGYz9KWG5y1QVQMyA0VT6Sgqx8enVKpyCgAKqqazstLiMIqZzBegamQiQdENGvU6jVqdWlPmW7a6fZIkJs5igjTBLtkoSVTAX1Nc15XgkzQlKzrtQRD9rRzY0Dk/P5fIc8uiXpdOx2atiaEanJ+fkWUZ7Xab6Wx8EdxSLpdZX19j59IlytUaWZ7JZrFlgRAX/QKRgyYEqCrihwpyf/R9K2sHcRES3Gq3ZMPYMKk15CKapgmh55AlERXbRBM5JCHuYkqqqiRpQrvTZTqb02rK13uOi6YImb1pWszmM7lJ2DaVSoX5XPpMrl6VZrZmp0Pk+3ieJyEzvk+lUadarUp7tm7Q7fZQhPwONfUDzlMgh3qrJf33hexWBpxIsrNtGORJcrF7J0UEnOe6mKYkPJuWRZqm8sihacWbIUNFDNtiWYwmQz/AMi2SMJKqRM+TVOhm80K3b9s23W6X+/fvc3R0hON7+HlMmuQsHJdMaPT6a9y89Tx37z2gv7LO9s4Vbr/xBrPREM/3ik54il0qcfnSDj/zsz9Nv99nd3eXlZUVhGFy+/XvMBwOef/99wnCAE3VQFexDI2Nyzu88sorXLv5LJcuXebevXv8u9/+TZpNiQj74z/+k2IsZaHrOq994lU8f84fff7zpGlGrVah0+nx8z//93jh+Rf57nfe4Itf/CJ7B/sITSYVr6522d7Z4Fd/9X9lOp0Q+h66plHxKiRRSqO2Sqla4eTsFEVV6a30MQ0TsowbN27wxndfZ+k4LFwfRTNQTQvdLiE0g/76BksvYDpfSn5jDqVaiSjPWE7HbK5vsL+3h6HpLBcLLNOiVq1iajqqarJELvBnZ2eouky/dlypDARZ1pdKJUzdvLAC27ZFs1UnSRJqtQrXrl2j1WpSrtXQCwL0k8AhVS3Qdk+e6yfXE9/4xb2Z86MKbVmB5yiKuBhXZpm0+0/GE+7cvVMsHBmB56KKjI2VHrqSUy9ZzKZTNAU67TZZmqIIQXtlhSyOyZOkgA/bBEGAQFqt4wIHt7a2VuRm5JRKJVTkMdyyJNOBPMNZLNANA7tkU6tVOdrfR9FUDNMkiqMf+Th+IBaFDJkvGPk+i8W8sBqX0FSVOE3wHefifBSGgSQjWzaaphIEvmyuZJJvGMeRfFgKX/9yuUAgEKqCqiicnJ5gmSae48rmS/Emdjpd7ty5c5Fd2F9ZwbJt/DCkpAj2Hz8kywVZLmh3mqytrfP222+zurbBYrHgG9/8FmEUoiF975ZlUrItnr0lNQaLpcyBHA6HvPveu6hxznKx5Oj4CAGoQiZP9Xo9PvTcc3zyU5+6+H//2q99lvfee48bN26gqPD5z38Oz/NRVTBNg8985jP4gcMXvvB54iSiVCpz48Yz/ON//J/z5ptv8cd//AXu3LnLwcGBnHkXMYKf/OQneP311zk9O0HXZCS6aZlMpiNKdhXHXeJHAaqhsbaxUfgKPNylwztBwOnZKUkkg3h1w6TRbDEYDHA9nyCMmM/mBHHCdC7pWI8OH8gbtFrF9T1m8znNWgPfDyDLSaNY9iLKVVbWVhlPJiBgPB6TZhmmbV30jUajEaPBmGatQa1exy6VqFWrNJp1ms0mlYqcUrTbTQzDRGhSMSiKCkEg/nYxEEj8QTFV+LurwA9bFgS5LDGKzxBCIBDkmRS7CSHY2twmSWMmkxHkKVXbknbuNMKyZWMziSMavR5xnOI4LsvRiGqtxtLzLs7+SRLTaDYlpzIMUXVdSsltm6PHjzEtaYd+6umnsQsEQRLH5HGEELBYRBiVCjngez7ng8EPMFD/7vWBWBQ0VcGyNOIow7Z0skylVCuRBAFJkkgkW+BgqIpsOFarxGlE4DmUKxWCYEkUR9RaLTIvRjMEnjtnNpujaSqe5xUyaIdUTYmVhEhNaJZrDE5OydOMO997G3cxR9F1ojTh9vfeZjAa4QUBCycg1epEYcilS5cplUocHZ9x5fIlBoMBb775JqVSCWIfzaxgaiq3btzg5ZdfJs8zlssFew8f85U//3Pywkp8fHYmQ0yCoGggNrh+/Tof+chHePbZZ3n06BFvv/02t7/7XZI45tVXXyWOY770pS/i+z6WZdFoNnj11Vc5Ot7na1/9ujQA5SovvfhhPv3pT/O5z/0+ruuSpinHJ7vkhBiGQsm02dnZIYtzbn/3TfJMIY6lFn7peqBoBHGEH8qQXiMxEXmXg8f35Fm+ajKfj1i4UiMhEgUdhWDpspzMaDabBH7AfD5nMpmgaRqP93ZJ/RiByXQxJq5UCOYBQ3dEEASEuiRBx3GMPxiRCXn0EYZOrir4vkeSS89FGEWcnJxgGjZJkv9tgnbhsXj66afZ3NhA0cv0Vsqoqo5Icml+KzT/QhGQZsWIUZCnGUITZLkUEj1J/xLFvOEHrjxHEBXmPQVSQZ4JhKJjmJrscQgV1/GZTwaQhJAEhH7CPPEJPIcsCdF0i9l8KbNLh2Pq5Sp5mnO2d4hmSWBrZ3WF8WRMnITYto1t6PiudIHGhUQ8yzLpbzk/l9BfRYE8LyzY0qxmaCOm05kkRHVqZNqPfvQ/EIuCAJzFDNdxaDabktSsq2gYZFlCuWTjuA4lo4LvenKkpWqy26yq5KpKLBSO9vexLQtn6VCySxe26cFgJDkCRVzbzs4OrVaHsmlDrjIcjUiY4PgB49Mz3CBgOpfQ0STLiJIMXbPptCV5986dO2xubnJ8fMydO3cu9OyGbtDv9/jEJz7J6uoKnudyeHjIm2++yWKxoNGU46NHjx7h+pLjWLJsrly5ws2bN3nhhRdwXZff/93f43vf+57MNqjX+NQnP8nbb7/N6emp5FUaBr1ej1u3brG7u8s777yDoqgkScLly5fp9/v8+q//Oscnx7z84Zf5ylekdyJJEjRdaht+5md+hj/8w9+XHXdFIUc+LHmeXbhSJffRvTCJPUmo2t3dZblcyinQdEYeSefitFCK2rbNm2++eaEziaJIull9lzSL5eSgVscLPaJFWJTzKoqjyMg8Q8P1fVzPKdLFIU5jsigDkZGkGnkO0+mMJJH/7+lszO7eI4RQqNdqVGs12q0Wm5sbPPeh5/jEaz/FyuoKpmEghIJqIEGYxfEhTTNIc1T7Bx+JnBzyv9tnyJGUSUX+G+L/au/NYjRLsvu+X8Tdvv3LzMqsvbp6me7mNGfImREpmqRAS4ZIjwiDtA3Y0BsfBPDFBuwHA6IhwJbfJAP2myGbhg0MDEND0SYpwZKoGVMcCiP2kBzOdPcsPV3d1V1dW1buX+a33iUi/BAR94vvVmarOequLngyConM+pYb98Zy4pz/Oed/BELY4kGHe4fcu/eA+SxHCMmNGzfodVu8d/s2o6MDBoN1JIa93T0uX75ElmW8d+c9OjLh5NiyiSEFG5cvc3iwx9HoiO76OlVpuRiN0iwmc45PxrSyFlmrzXyxoN1NKUpFkiboOOXg6JhuLCztfseS8g61JcLtDYZUT7v3QVWK44MDZrMZvXbblVWTrG9uIcEWKDWG48MRWdZCK4VSFZPxlNnMumZEZEupP/vss8xmC9599/2azWiRF5yMbdLOo+1dxuMpx8cn9Ls90IKj4xH7h0eMJ1MORiMm8znT+ZzZYgFSkqQtLmwMuXz5Mg8fPuT69evcuXOH3d1djDGWM+DiRa5evcpP/aWfsary7dt861vf4t79e9aU6LbpdDq8//5dlFJ0Ox3SNOOFF17gV37lV8jzBV/5yr/gO9/5Dru7u/XJ9zM/8zO899673Lt317qXdMVLz7/Ipz/9Y/zJn/wpu7u7dkGqiqjd5tatt/j+m9+j3Wrz2Z/4LK9+41UMmv2DPaSMaHda/PzP/zyHh4fsOQo4KSVa65Xz0NKPLd97+NAmut66dYtOp8O9e/fcpl+gFor5YsZkMmG+mDGfZxwcHpCkMTISjEZH5PmCLEvQUjCajJku5ghp09wRcOe9O7TaLbqdLlJX5Iu5TcF20ae6qlBViXb1JPOiQIgIKSzHAMbUeTOHhwccHOxz9/07fP/73+MHP/gBb735Fn/tr/1VfvInP8eFCxeQlQUIDZpKKaQUxHECgWZgjHFs+qtCwWDIc4WUhigSCGGFg0DQ6vS4+fzzYCSz6YJ8usdbb73F/Xt3iaUkloI0tutyf3+fWICMIMosk/bR6Ii01aLI52SdjmUByxccHh2RtTLKsmIwXOP45ITdvX22trZ45uZzHB0dkWYZi/mchw8ecOnSZQZZ7OjtIkrnXZvMZqiqZLD5EfApfLzNsJjNXPFRSeyqK4/2bBUmS2AyptOx7D6jkzEXNi+QRCnFvGRnZ4/R6Jis3ULKhEe7e8g4Yj5fcPjgATKKKJTi4OCARVmip1MUhlvv3eFkPLN8AAYOj444Oj4hSlLa/SFxu8dkOqPd6XPp0iV7mknJ66+/Tp5bktI0TVlbW+PmzZv83M/9HJPJjK/90b/k9ddfpywtjbZnBrI8ChqjDYPBgJ/92Z/l85/7HA+3H/K7v/M7HI1GNXnI5uYmn/nMZ3j9jde48957gI2N/6mf+ilu3LjBV7/6VUauilZRFvR7gxqPSdOUwXDA7u4uRZHXIdvdbpfPfvazXLhwgS9/+csW3JLS1lfQllNQCIGUtlCrqhSJ22h7e3usr6/XiWn9fp/d3V2kkMhIcHw8smZAnnMyjjBGs79vswKP5ragT6tKIRJoYTiejgHD/tEBN248Q6fftbyNU8saVJWVLWRblRht8+mqSjEtJxgDcRyhdQXGAsZSWJp8VYF0YKExmsV8xt333+f46ITj0Zh79x7y8ksvsba2TpLE9Ppd+oO+rU9a6ZXAJSsOxGMMIQJBnLSciSFQGrSyp/Du7j5loTg+PuH27XdJzJQkgn6vx/7eHlkiSYcDoiji8PCAQbdDp9Nimi8YxOvkuuLCxhqLqiRJU4gkw0Gf9c0LNqx/umA6nhMnKZevXKXX7zNb5MRpxt0HDxHA+sYF4jRhUeQIGZG1O3Q6XaI4Zv/wkL3dB2Tb25zVngqhUFYV45MJqqyYnEzo9rpovWAyntBqtZnNLMd+v69pZy0mk0ccjUZEcUxeFBwcHjEajai0Znd3n+ki53A0cryLBYtFTpZl7O3tgcDRWxv2j0Zs7x4wm88QImI6m4GMEAoWlUZGMe1u3yZSRREbGxu8+uqrtXrtNZHr16/zhS98ge9973u8+eb32D84II4i0jQmy1okSczu7i5laWsvbl67zi/8u3+FZ555hi9/+R/yzjvvUBSOZSjNWBsOePmlT/H9732XBw/uWXMqirh58wZXr17hG994ldlsSpYlLBY2gGs8tnECShniOKLTafHo0SNLJtK17E4XL25x8eJFfuu3fos8z5FSukrOFcZoa2dj7WkhBDKxJok3H/b390mShMPDw7pCtQB6va5jz5ZUlaSqrBuuKBZLG17AZF5QqJJSlRRVQRxHGAHv37tDu90ha7dsfoOq0JVCYgvSGmWFq5SSLEkwxqBUhTD2lFblAi1EPU5CSKpKUakSEMxnU4pc8Y1vfIPvfOc7bG5ucv36da5du0YURbz44ov89E//NIPhgHavRRTJegzq5tVt95IUsTUbcBYE0GrZIrhGgxCWT+KZywPefuv7zCZjiiKnKFp2HCNhvQ5VSa/f49q16xwcHSDimNH4hLSVoauSdnudk/GEqrIlD1pZxsmhjRYVQtRJgYeHhyRJUnsyxscjpCqsl85Vzh45bbzTyZDybNfrUyEUVKVsCnIUsSYiZJyQdGJMpdGLHBEldHsD3n33PYSI2H70yKrtZcHxyTHT+Yzj4xMqbUk70k6H4/GYnUc79Af9uty61tqGGJe2tmNRKUptKJWmqgqUAV1WKFM5uqyUXn9AmqTM5zPHuTdHShtpF0WWT//HfuzH+P3f/30ePnzIbH5sN2cFvd6ALEs4Pjm2aHEc8/LLL/PFL36R9+/c5n/5n/+BJRRVtjhJHMUkccTVK1d47933eLS9TVnmIATDwYBnnrnBq6/+a8aTMVJa8s92OyMvcpRSNr7BaDqdtqsHOXYl9+YMhwNefvkl/uiPvlbXZ9RaWc3F1a+we8CglKqxNa8dGYeE+0hTy3bUoSwKyjK3RKrGkCQxRbGoqfXyfF5zcEYiwmJgmiSJbP0HCcYIytIKt1YrRSqDcEVvkySqN6gAIimIkwStYpTSVJUK7hHSJEZrg5EKIwVK2ecrVM7xccV0NmE0OuK99961BXYvXeLNH3yfb3/7W9x89iZf+PxP8tLLL5EkKXHq6iMY7DWVRkSW2MUkgrJ0Fb0QVGXJ0dExQkjiyCZKSWnY2dnh4sWLPCwKOt2uFbzaUah1uwx7XZIk4tHuDieTsdvEMy7duM7e9jblfE6v16tjL5IoJXZMVCKOOXGRvZ6JPI4ikk7Hlj/QNnGs329xPLZCqZVaijalnvJiMAYotGQ6nnAyWdiKx86Wnc/nlGXFcDig019jMp2yvbsH0jIm7e7vWh77srTFYaZz8tGYw6MjZvM5J9M508mkjh0QwqqHWmsUhsr97eggMcaeOGVpg2guX7rEYj7nwYMHzGbWbk7TlHa7zec+9zmeffZZvvKVr3D//n3yfIGUoFRBlrVAaCbTMeOTKd1un1c+/eP84i/+Em+88R3+8F/+PvPZjHaWUJS2BFwrTdnc3GA46PHat7+JEJIkiUHA+sYaRZlzeHRQ11gUlahHMGulaK3IspRer8N4fEJZ5rTbliFofX3Iw4f3OT4eYRNQjbOjY6RM0MZqC1pXjgIPGzeBD9Kxzaf51qeoAJzbzNd71NomA9nMQoExVihQaYxKkfYoxRjlNn5i07IXC9LUpjJXVQUYWmlqNQMnZKSEWEqMExLGKATalVYz1gSIIpLYahECZat6C4M2FVVln1FIQVEu0KbiaLTPzs42t9+9xZvffZ0XXniBy1cuW8ykKFyy1SYXt7YYrq1jtOZoPMajElVVIUTkvCBtlKq4f/8+Wmn2DncZnxwxOTmh1+1w4colVFHQzpI6rmZvf4e8LJi5+Jwkjnnn+2+yvr7Owc4OrSQhi2I72EqxsTagXMwolSKfT7m0dYFWGttgOVWRRG06nRaHB4cYIZBRTK/bZXfvkauQXdn6oGe0p0IoCBHxaO+QxXzB2voak70jKlVxdHjEzu6OBbyiiMFgjW6vZynSqpKDw0PGkwlxkrDIF1THxyitSdKUSmvSVouyKJjnOZXSFJWqQ1OlEGgBlUPb/X1EUURVlrTSlGuXL5NEkkc7jzg4OKCqqlpte+6550iShN/7vd9jZ2eHLLNl2CtdWECvnTkQcs5g0OfFF1/mF3/xF/na177Gt7/9Gmgbku2jNbM0BQzP3nyWb3/rz+t6kIUq6PV7XL16lTfeeKPGDDyBp1eZ48hWcur1ei5Ix7Ihz+czhOhw9epV3n//fadh+M1ucQSldO1zF04N92xd/sT3QsBrDEpZO9/OzdIO99pEfboHKrgqSspoUQsMlLIhAlWFABIpidxmT+Ko7suTnBoXiuxNGhvlKt38CaSMkVLUsQhSSqQAUWkUXvhXaAVCC7SWjCcls3nEeHzE3t5Dtu/e4c57t+n3+zVHaKfTYX1tjY2NDfqDAUopZouC6XTmeC5skVfAUaoX7O3tU5YFxpR86oUXuH/3LpG0YchGKZ65fgXcoYeB9bV1LsQ2SCtzp3kUJ6A0oz2r9l9wldBHR4cs8gVXLl9hPj1mHMPU1aAsioLpu1Ou37jJ8cmYbrfLfGFZsMFFB+tqJT6r2Z4KoTCeTLhz94EtiAJcvny5RoRH4xmHBwd2ofMAISVjx4gkpGQ6nzGeTuxJ2+lYGm1lKPKcOIpRruJQlNgBNlqjjUEZrBtOOJsXgRSgioJWZv3lWRIRC5hPJpYB2mXqvfLKK3Q6Hf7YsSOlLlxXaUUUCeLYYhbz+RSwbqnPfvYn+NKXvmSBqLIkliVxFJGlKcZYlfza9Zvki4XliECgVcVw2GdtfY3Dw33GY7vRq6pESqvSWnCQ+rcQtvz4YjFHa0W326XX61KUBQ8fPiBJLIJtQ7CtQFCqROnKbSh7LQIh4FuNNTgtzguGSCiiKEY6D53Uy88K6YWDbp5JoQAAIABJREFUROUFlauYnaYpkRfOTp1OkqS+LxnFLnCnQgpnMrhoRDAYo1FVZYvnKG05DpLE3jvayn68NuSK8iqNwZtMWOEgFDKykY6z+YJqPifP5+y4Yr4eO/Fz33a8kd3OgKvXrnH/fcP3v/M6ZVkyGAy4fUtbz9hkQrvT5sqVq7z22mt02y2kgKpY0EoT3nnnHWIpWR8O2NhYo5WmFFXFIs9RLocn1oZWy3rjTg6PUIuCbrfF1auXmE8njA52SSUk0qDyOVmWMdwYcP3aZZKkxfXrN7h9+x3r8p+MmY7HJLEF8nnaMYU8z3ntje/Wtu53v/8Dur0e3U6HoixtKfjDY4zQTKYThJRojKNUMxgMldao2YxFnqNLjRRLNdZFpyNlDNIgjEEr7XzzPs7Vqpra2HDTJJL0ul3u33ufxdzmqQ/6fT79yis8++xN/tk/++eMx2PiyGXVOQkvI2UlvDCkScqVK9e4dOkiv/3bv83x6IRWy9KhC60oCkvwqbV2zEEph4f79WkuhD0lr127xhtvvFEnfQnnF7ensA2tlR4TEPa5nJeMNLO8lFEkSLMErY1D7u3G8hWuEcYJBVO74mCpGXhU3gfKxCvBL3YjKGW9FXESW4FRWxj2fv1YGWOQQthxAqIsBqdhSCdArEouXFyBcNl+tlK2dIQnQmA9Jdqu8cgJysqZEktwUPiHcXEYNnxRSgHC2IIrkcSUClWVzOZTx24djA82liGKJEopep0hd+/eccS4MWtra+w8ekia2gzYTqdDv9thsZiTOXq5fDFjfWhJUcpFxealLap8UbMwT0cjW3Qma9NpZYwODihzO9/SwMnomCSCwoGW+XzGoN+nWMzptluWoEgYRoeHXLn+DO1ux3lqYmbTmcubaLOYTDg+Hp25H58KoVBpxbRaMJ5PyAvr6hvNxy65KaHb7ZEXOfmidGqzPd3Deng2yASnz0q00LYuoQPObKRXBMJGs8koRmqJcUCUX2RGaaIoxmibyPTOO+8wmdgQ5auXtrh5/Qp/+P9+hdnJkVV1BeAWsy4N0qQYLWm1u1z71DXW1zf45p/9KZPRIe0sI58fuQ1lals6iiJ6vR7D4ZDbt2/Xp3Or1SJttzg5mThb2FmxxtQYiEWRJUJE7vQ0aAVJnKJiQxyl3Lj+DLfeehtVWb+6MqU9MY12SLm/Do5b0ssEBU4w2RPWqu9KC6I4chtVUQlbRyNOUlua3hikcIJKG5uIZCRVJKiMQSYRpRGOuSi2qr3TTrQGrUtkZNmGTGT7KbVBeVejECht6VmN0migFSfoKEZLA0LWtrOUgkjGiFIR2eBktLHPro2h0hWlsVhGEseIdsS8qlDFglhGJHGCdvRvwoCsbATkaHZEWqVECwuEHowPKfKCtbUh6xsbrA2HxO2MThkR6ZSD/SPW1wYUswqVV2Csxy1rpYynCxbqiHleMprtsrV1AYWgs7bB8fGRFZDtjFa7RYlGxBHVvEILyFVJFmVknTbd4YC93V1bZu/wgO7aZW4+exO0ZmfnEZWB4cZF+sMLtAYbZ+7Hp0IolGXJ4eFhbSt6ynCtNbOqQjmEPM9LqnLpIgttVqs12BgAre3RUaPeTtJ7lt8aQ8AuTCOX+eVpktb++clkYqtLOzBsa2uTV//4j9nd2bGL2Qkbf4pGUpImFhjb2tzixU+9yNe//nUmk4llAAbSNKlPweXClTX1m3+WOI5tQdALG/XYeAFiBYOn6LbP71X5oijqknhJollbW7NRiw5HsIxT5Yq9TjAmYVu+T/2MClW/Z5yWZoL/V0rV1aelCx/2z5vESxNASGntfocV4DQ649+TEm2MDVpSql4Pfu59oSDflNauorWu15EdL0ubhgSNRmqJlMbmOkjhBJGuWYtarVZNl17MF3WGrRTC5qc4k0cpG34vpbT8jZFkkS/Y3SuYLxbEcczVKLJxJK6s3u7uHmkiSJKI4bBn6eGmMypVsSj3aHU69Ltdkjhm+6HNR1kbDul1OyzmM/rdLlEsIYJ5URIlCbO8oD9cZ+viRaIsBWHp4opCsXAsY7bGZ5fj42Om02mdWHhWeyqEglK6DgYKF+vSj65doU9b0tuDbLAKhEUejDKqXqiwRMr9tf1rwhiEpl5gPv1Va0273a7zBtrtNs899xyHh4c8ePAAoObn99eO47jufzgc8sorr/D1r3+d0WhUZ7NNp1NSpw6XzizyG73VarGzs1Pb0V4opGnC9qPtuh/PGRFOqo0+FLbKU1XVgsZvot1dW9vSmh6gA85/P3anCQUvCPz7NQjpNlz4mp1HhURgHMFrHMfEQtbmhsbycSoXNOVdieFYWJMhqceyKRDCefSf96/5/0sp6z48rhHH1qMhpEQ49agsS5cEtQRF5/M5eW4TmiKC53WaZOTS91sB1lBVlY2Tqap6HLTW7O3t0Yn7bKxvWMLaVorWEYaYvb095vMp3U7bMjprxfUrl+sYg0hCEkskmkG/iy5z8vmcC5cuurT4mIlbg73hBq3uEOKIjc3LtNot5vMcpYRLChyzubnJ2potnJNlma3NeUZ7KoQCDh/wLUSujTH1oomjpPaH53m+BLo8z4L7fIRABTH8zeuBEyZOKIQnIrCy+Dw9nBCCe/fuAdS2s/9MKGjiOOall17i1q1bK4van0D+efznvbbhgTt7qkf1xrbOEiuslCueUrsk3Y/WmspUSKfxlGVZF2c9OTmpsQg7RoBeCgC/cfxYhnPgN3s4HpFT50NB6sdTa41xwK3W1k1YoetxN3KpdYT9KqXq090+u6rHwr/vPx+uj/AZ/FyHAtMfFFLIOjDL4wzeHVtWFUovhZR/jna7TRonlE4I24m3h9disUBIa/55lmfP9eAFhZTSFjPKrfYzGPSYTOwGlxPNiy++wPr6kKPDA7q9HpubG7SylMGgz+133iaJYy5tblDkCw52diyJTqfNbDpFmYgKiZEJcdpmMsuJkikyjplO50RpiyhtoXNLYuu5Jgy28NLR4aFN4DujfZhiMC3gXwGZ+/z/ZYz5b4UQG8BvAc9i6z78p8bWkkT8BUvR+0XkN4jfXKHLTSmFqkx96iz94KZeZP46hsdPErsezOomrnGoJaruS6D5iL9OxwKD+/v7terl+wyv59XWXq+HUoq33367xgwqxwXhr++R7NgF6Hh/dZZljMdjC0S5/y8WFnz1J6/XBvx91+NnNKq0ZsfcEdN2Oh2Oj49tYd2GZhVudOAxARB+tvkTfk4IsXJCxsJtdm0DoEQAVCqMK8qTrMy5D4bym9gH1oRz1Wz+ml4IhBqSfz+OY7tBkRjl5mnFBe3iNFjVQDyIapwWN5vNwBgih4GkaUJeWNeqdylHUVQLA0+7HscxETnaaI7HR2ysrxPF0G232X60w9HRId1Oh93dfXZ2HrF5YZ1r166SJgkvv/wi+XxBd22Ng71dsjTm6tUrTBcV/eEaRaXodAd0u5YiYPvRrtMODf3BGmVRoMqy1noWLgbCC9ezxhU+nKaQA/+eMWYibPm4rwsh/jnwHwN/YIz5e0KI3wB+A/jb4ocoRd8MLvfqtZ80v5DKQtUnlI/JDzUMf6qYAE8IF394gvjf0jT+775XlpbXcTgc1os3SZKVU8sLA399sODkzs5OvTH9tf3khGqzV4m9qry2tsbJyUmtWRRFUZsL/rP+RPULsH4+jUsNNvUpCzgXpk2GmU6nFEVe+/LD8fb/D8Oa/Xt1oV8nfP2mCbUbX7i31si0rkPKq6qyJdwjeaoQCjUkpRSxjIgiuSKAa7DYaYReYwxNGb8GmuOq0XVSU70XXN6TEMKmGbt78HNfFIVzmUoiYbk4/JxXlarH1T+313ayLFu5D+lg1E6nw6JYkOQRucOpBv0e0+mc559/jsFgwMXLlxiPLXfIYlEgpbCUeFozn875s29+k+HGRbprRR1Ap5RiMOiSJClHR0dUlS2aI4Dp1KYHXH/mGbIkIWq3UWXJwNETntU+TCl6A0zcfxP3Y7Al5/+qe/1LwNeAv80PUYq+Jqk441RaLkpRT2q4uEIcIooiFNol+DyOK6wALOb01/1G8NRW3m4EVja0F1rBWCGE4OTE1qScz+cW1XZagb/XUDX2bTabsba2xnA45Pj4eGWTxnFcq62eosw/l78/pTRVuap2LxaLOkAqdjRkcRLV4c1+4QK1ZtZUy5uagaVjs3MSmkE13gCOpdh7fZbzpFkKktD0C4Wxn5imwPWfaQpVLwCWIOxyLnwfUkikkcvnC7yVvq9mW5KwGDxxa9i3UlWtiXhz1sc0+OuVZYmkQkooqxhtUgyWvXzuuDs3Nze5d/8hvW7G8ckJSRLzzI0bPNo9wOiKssxRZUkry+gO1mxEpZB1IV+lNI+2t9m8fMUWgZnNGWxscPf2bU5GI6bTKQ/u3ePKlSu0jHXdLxy561ntwxaYjYA/Bz4F/E/GmD8RQlwyrpakMWZbCHHRffxDlaJvttBOdn3Wr/vFG8n4MdXHvxdKeiNtZtsHqZ/weEqs7883Dyb6ghve1vef8apruNGFEMxmMzz/gMcjmgvbf8cvqsViwXg8tpx6SjGfz2vVteV4+Tw5qe/XP3scxyRxspL3H6rm3tb2WpcVrqsofjju4VyEm9U/f3h9f1L6zeJP3aVpZlavcwro7W15cILIz08obBogY3iv/j78mDRNIz++xoTSYPV6TdzJGMuYsByXJUYRRRFCRiv32Ol0LIYQPIfXGiJpvUWVqlBGMegO6LbbqEqR5wXD4QDiBCUiIhETpS2yTpf337/DYjaj020joox+v0uvP7CBbdoeOoUrrRgbzfpgQD6b8Qf/9J8io4jFYsH169epHFW+cGtyuLbGA4ePndY+lFBwqv/nhBBrwO8KIT7zAR8/zdfx2M4UQvw68Ot20FbNgHCiQlzA/r1Ua0N10r9/amfBdR+/W3HqZ7wa6VmOkiSh49iFfQCRDzoJbVu/AYFaffXsOMaY2uzxZogXCsqldlsqsV6d4FIai2/4aDof4hwKIQDdwALCzaq1rslOCGjEmsBd+OzN9/zm9KevV8+b3gh/G/W81fieQUixZEBrgIUrm9MJztCl7FX10OvhNY7TsI7Q/EnihEQmtVmAi02hccCEwkcIgf+3XCqh4ND1QeHvy8+tn9d2u02eL+pnt9e0Hpjd3V26na7DoDSjkwn7o5Gt53B4zGDQA6MRRtPu9onSjOmi5N69B/TbVlvcvLCJHPQZDIdobTg5HtFKYp6/+Qy3332PVqvFcy+/zPz4mOPjY+6+/z55npOlqWXpOqP9hbwPxpiREOJrwBeBHeEqTwshrgC77mMfqhS9MeY3gd8ESOLY+E3SxACatq2X2H6x+Pe8TWfteBugFJ4qpwmE04RHc1EVRcHx8TGDwYDBYIAxxrmElsCdvwchbCprr9djb2+vJgr1p7LXGvwJHm4K688uODw85MqVK/XJg7bh02VZ1uqqByj9RjHGYLRa2bjh+ISAptbKkQWtbnp/P+Hzh8I2FDJNfKaJK0RRROFCqf01y6rEqOXzerMnHOt6DWiLAzTNmdM0AP98p5k/teBEEIu4DkUHi3VYD9UStPTfWV7bgd4ywpjlOAghiGJZr0kv7LtdW2+z1+vRbi+L0chIgLTga14UyOmUNEmZzm0ldaUMShjSdsZ0Nmc8sZ6EJInZ2tgg63R58GiHTqdLJ5as9zocHh4g0KRJCmg6vR5lWSAF9AZ9NjcvIOKEhasbkec+C7VVh+af1T6M92ELKJ1AaAN/Hfj72JLzvwb8Pff7H7uv/BCl6FlZkKctBKWUDV02CrABJDXo5Ww+gwAR1YFMNsjRrCyWpaAQCAlKrIoGIZ39665ZakU1n6GNTYyRkaDTbVGVNu6+qiw1faUUQktOxiOSJCVrJZRlhXTMPAZFUS5qTccm4rt8BQSRFCRpRJEX7Oxsk7Uyur02YlExnc2pSheY4+z4enFGiY3QjC3ZSVEUlNp9RjizSjnQTZq6f1WfuBIpQQqPvHlPjkBqN1Zag9YYYVxOhg0Vli4RS1WlA2ytei4cEOg9DsaHTQbNYxLekxRqhpUyxGKJGzSFnBdM/lQON2Y4NmDteq30MubFWADUBkopBIYIYxMhgMj4cCwf22RDv5EGLbUNdIvsOJVFiXZ5HK0kI44i1i+ssbG2zt7uHhQV7aTNbD4nToEIJicT8nle33un07FAqISimFvPizHs7j6k026zMewyGR+zvj60vCKF4nA2oJAx797f5vLlSxyc3KPTabG2tmYB7umE6WxC1u2ws/OATq9Ht9+lPxhgtA03H48nnNU+jKZwBfiSwxUk8I+MMf+PEOJV4B8JIf4WcBf4T9ym+wuXogexYnv7U0c0FpLSamnvSQcesRp1511CRjmBoJeqors/26MFnVcCeezrllY+jH0QGPJ8QVHkKypkHMXEMagAv/CuQ7uxjK2wvGL7qhXhV5tAUiCNJM2seVBOrDup219nc9NWJp46os4mUAcgKoGMRO3O8ye9rsfMuyJBysjlVixPOm9+BMqy5W40pv5tB9AKEG1stGKpijqDsTmO9XNKi977Fp70Idhaz782aL2KZ4RArRcU/jnDNRGuA/+6wVApKxB8mbf6cDDBGvFzsvIkLmrTaLS2p73QNsw6iWOyNLV5K5klWFkfDi2TstYkUcx0MWd9bZ0sy+pSiH1XAMfzWRZlwWwyI2slYGCxmFuzoZ3ZHId8jpT2YLx+/TpKGXb3D3ju5k0uX7nMvbt3SVttDo+OGI9PuPncc+zt75EkMQ8ePuDzP/3TFDMbym2pOEVtnp7WnooCs2kSm8ubG/VEhq688HfoevKvNW3eEIALkekm6CiEQCNQpyxmLxBCoWACVT0EDJsAVZqmbG1tobVmNBqtxAX4zVynDjeew6t3Wus6mlIT0e50a6+DEILJZMJsNqvHyS58ewI2x8KbGEtTwNr94T03x0VKSSwlSWN8/TXqtOnGM9Sb0Dzuqg1P+nBuwrYcU0MUL/GK04Ko/DyErkkfLRqaRN6tGX43NOn8/89aI02g1Zs97TRDYDkn+v0+F9Y3MMbyP8xnM1qZTVBKWhl5UdTxDJ1Oh36/byujBwF4SIjTGCkgSWKGgwHtVoskEpwcH9dJVutr6wghrQBaG3Jxa4tL169jqpI7b9+iKnIGa2t0Ox0m8xnT6ZQrN28SG8HhwQH93hBjDAcHh/ylX/oPnt4Cs8awYpd629Q3v+CaGzCcwPDUCTdtuEh9H8vvnS0QV66HQTrtwb8XajNh4EpR2JJvTT98KETCQKvw1PMpxakjFinLEqUFqixZGEOaJCRpSqfVctpLsfTLW6oRwJsCj29IAWhpw8r9WCw1iseBXgJh5QWk32T+mUM1PnymEOfxcxcKDd9PE0fSWiOkAcVj9wRLl3Dz+/6zYcBVuD78MwC1thXey2nfCQVheH+qqpgrTZamdT7HbDazwLQzqWTbjsmRowUM8aSisJXEvYBfX1+n1W0zGAxYX1tjNp9ysL/H7s4urTS2iWHGoCpF5LS8oihctq9iMZsxWF9jc3MTjOZkPOZoNKJ/YYPJZML06IhWq8PW1avk4xn9fp/W015gVojHN3UTVQ43um/haRN+rgmEhd9txtE3TRR/3ZVrWrRiZcH5TeJPfi8Uut0uaZoynU5rWnn/2TqYJrCTw368+RECerqskDJCq5JZmdMVXcffEFOVBVppBNpliS7VdePUYuGuH0kfGerThuWKRhU2b06EY+SFh4/G9DkiXmNpeiIeQ/Ibgv00TKDWxOwsrAiL8B484h/+3TxQwvgH30JMInRjhp8LBcVZ0X/GGCqtSF3yXb7IUWVFt9Ox4eztNrOpjQ25uLWFgbrMW6fTqTVBH3Xa7/fpDfsYA9vb20wmY+bzGUW+oEwTup02ZVGQpRnz+aIOpz52GkRRFJSLOdM8p9Nu2UNDStpZRrfbdaB1ST6ZOsZqW7DorPZUCAW/SCFwKwYqYvOEDRdQszWl/2pQzOknwmktXDCwBCybp1SoEns7LVy0YbBO+FlYqsveDPD3pbVesitpgxAatN3ki/kcKQRpklAlCUWe22xxIWzAljs9IikxDRdieGLX0Z/mcYTf/4T2frhBfS5FiG2EgVD++z5kvDkmTZMvjNtQymZZah43WZrj39RwQjPJX8u/HwY2hWspDIgSQliPD48fOOFcVsbQbXdQjhNUSlmf5t596rGldrtN5H77MfEAuY+Wnc1mFFXJeDqhKkrAOKbtiF63jxRgjKbd7pJlKUkSs7m5SbFYcPXqVbRSDNfWORkdMZvNyBcLPvv5z1vuESEoyoprN2+y/2iHtbU1W7Y+PXv9PxVCQQhqF0lo2zVtyLCdpvb6Fm4Av1Ca5kgNKJ0S1XiWsAmF02nfMcbU0Y/eZPAnV1PjaW4Qf40wDsKOhUJjEJ6b0FhyFk/KYkzbxUHYyD3loglxTEy+sLrQlqcwjBNoal3N5yUY3/B3qBWcNW5Njay5ycL5C+c3jmPHF7kad+E/611rYQCX/0yoYfn+Q4EbCi1v/nhin36/X2t5PtU9JLV5bMzM0mXp+5vNZsRRRLfbZTgcWhxIStrtNgcHB3WsidY24Gw6nVr2amNQsxlKWxMxTRPSJEGpknxR0G63yDIbxtzptLl4cYtLly6x++hRzfgkBDamJkvpdLs8evCApG2jTyfjMYe7u3Q6HWYL6wH7oI3/VAgFWLXTw5iFUDUMJxhOV/2BlcXu22lAUniNs67l34ujuF50YcBU87e3s5sLsHlChielz23w1wjHwNUhQjpaeq01plKUJidOEjpZy2bv6aq+T0SQOYg3IWykoEAEobqr2kIohIE6/bx5AjcFXRMI9M/gx+U0jS3ECPzn/RxZarfHg5GWsRZ6ReiEAiXEkcJ7C7GbJh5kjI141FqzsbFBlmWMRqM6rNyn9XtcII4ty3OW2BB2zwTlzb9e18YpeDNlNpuxsWGBdM8G7nGnbtd6lmbzhbsPW/dj4KpFp5Gl75+Mp6yvr9HpdJlOp7z77rsYN3/tVovj0cjyaESSIs+5v7sLkawLNe/u7tLv9Vnf2Kyxr7PaUyEUhMu59xu/qSnA45hDEwQKW7hpfTtNHVTGUAXuqbNMCruIVk/FEBn3myyKIkeWOq/fa6q3oboaXi9UdcOMPymF28xuE7lFXpYFZVm4hQpJHINYFaQYW7i2aT7Jxql5KuAHK7hCM5gp1JzC8QuvF5oHoYYU2vPAkm/BmWAGG6QWjk+YXenHp+nhOM10bGoOTezJP7cQ1k23vb3NxsYGW1tbTCYTJo6fE6h5MZIkIZER7Vab2JtFxs6BTZqratKWrNNGac3+vq3mZIypyXvW19drIXH12nWMsfk9Fy5sUJUlDx/cZ+fkmHa7zeXLl221s8WCKBIcHR3RSlO2t7fZuniRnZ0dkjji0tYmUWTrkfSGAy5dvsz2w4dMJlOqStFu20jGOPm3CF56Ek1rXcemh4s63KTNhQ2r6HrYfHx+6DL0n1vBKISsS3ivRAeeBiw5YDAEQL1t6Be+r8LkUfdQQwg3l1ddQyHh06ubaq6Uthq1/2wYFq3UMsU7jlOEjFYwjHBz+nE2xtKlN0/8praAsaZGE1wNhYe/x9PmzfcdzkFo5zdtef+5JLF08+F8hffl7yP0cnhh4+fRf64JTDc1m/AQ8mNbVZUtweYElcd2oiii3W7XKfBpmtb8kVXpSW+FEwoWSOx2u+R5Tu7wBaVUncPir2+Modfr0ev1OBodQ2ld2Yf7B8xmEyJp3Y9Z1mY8PqYoFly7doUsyxj0+xwcHHD71i20quj31knTlMPDQ65fv0ZnMGB8cuJiI4YYYz0vs9nMVvo+oz0VQgEcrz+NjS4E4ozT238mxA/q7/G42tkE2YzxBVCkjWqz3S1zCBzgYLSleHPcruCqElmhEoERaGVQQiOFpqwqojim1+87qvIYrVxdAqdtRBpMtfRYaKOJhMBIe6rFfiNJaXkFheUB8AvdGIN0TEZaW0ekMLouMtJKM5tFV1X2/v14CAtgabAl16UPVrIYxErUjrDQhJFiyYoayUawj43p90FBdWKhsHqNiOz3LKeiRlWlxTnipVaVJokTUrYCEsIQyegxgRBiB94tWq8RKam3vh9jKREGImOvUakKtCaKbe0PYyzLt3D36oVDK81sZfKiJJ8vljiCNhSL3N6isAQqVVnVQxZL55YWAqNNnWqddbp0uz0HLK451iMb2pwkKUmSkucFezuPbM3HouDRowd1XoQU1vd1fDKmKCv6vQFFqRDSFjTKkoTFYk4+n5FEkEWCVhIxnUxI++tESQs1W9DpdikXCxbTMaIqiNT8zH31lAgF23TjlHGBt0tBEfztW3gSnCYgQrcXrCL/gC1aWtuyy9DaFb+7i34UWCYkYwBblBlbgchFR2pDeXRUn2YYgypLm8EoBMYFF0VCUmqFLoraTtXKkb8aU3NH2kQee3oVZeF3nA3tjqK6cKgxzoWoFEL42gcRSqvaPHIjZJ9dYDezY53yG1pIavkAnkw1+NvoFRMuxCZ8SDmhtuGe2YZWGeIkqs0fO0eGoiweI645C4MI8QIPhNbCw2seLhIzdhGbkbR9VlVF5fJDtNHONWtqc6rWdpRyAtx6cozXmIwtGxBFUR02rVnGnyhjw4erqiKOIjqdTp2Zaty8nZyMKYoDFosFly9fRinFZDKh1+uR5wvyYoFWmqtXr5KmKd1uh8PDIyptKQE7vR7tdkbsohsPDw/Z2rzAdDYliyQnJ8ekkeBTLzyPkTFpd8BguMZstmA+nSKNIhKGKAIRP+XeB4/ihie/twUfs/c/wPa3by/Rbv/bZ7M1XVS+v1BdD1+rhYqwJ2bz2v7zXnVVSkFlVoQC2jIee9Zo6RaqEqY2M5pZleEpGcfuPhuUdX4x+k1pUzU8CUhVq8ZhOLD7iCWrxWDp4OvwBnfCm2VfgYALU8ydAAATOUlEQVStTY9GIFa4cZvejGa8R5baGoYeEwg9NOHcNXGB0GUZzv1Z9yCbcxuYNisgr1iGcitta4L4+wrXSjg3fs7iOCZ2Gg3GanJFWSKFIEuz2lygLImMqQWfd1MWRUG/30dKyWg0oj/o0+52aLXatsamMZSVYuviRYSwHB3T+ZxFvqDbTinLgjR2xLB5QWfQZ/vBXdaGA+IkozKGR9sPGQwH6Kqy5REXM1vlGlvj4qz2VAgFISANuAnABuD4yVwJTmEVNDwN5W7ayt4F5D/ftEc9o1IzF3+5gFbJRk5zg0opHXW8UzfddSIvNLxP39iYAhP58nQ2FNeHMftnMW4hRdgaEFmW2WzJ2gOz6trzi9NnYIaL+rRYDf96E3wLUfomoOuFtX+tOZbh/YSMykvsgMe+G4KupwGGTXC4FrgsTb3aWyOkLRAc3LMP3kLYNGgpZW3mWFevrJUjDZRFidLK1QUxdbKau1DNXq21RgVnUyRskZUsy4iTuE67j7OKOBD6WZbVyWIekN7a2rL1LCLJ5uZmjRVFjhPB4hgRi0XOrMxZG16h2+miVElRVhhVIqWg2+tTFhW33n6by1euUeWKH9y9Q5nnYBS9TkY7zcBUzOZPuflQq6L14gNPkmJfcPTcDVPBfzdsfjOHEYch+3O4YEJB4N9vBhjZ6z1+v7B6Mgq36OpgHqcVyCh2BU4CKnghqVg9Sb0/3IfE+nuwhKuqPv38hiqUBSZXkrdYemlCkNH/1KCas6Mty3kjsMsBm4ZVodMEfUOtrsk+5fsOT2cvAE+Lbwjnw3/XP7//bJhm7U0uGwa+1Pxi56FIksSlOxsLJktpTSkPFmuNNAbl6e6D9aRcPQjtSVicEFBmWXRHRhLM0mNkAca4LlWX5zm5wzYqV8AmSZKa3LXdbtNut+u4hbIsOZnYIkcPt7fZ3NwkdtW980VO2xUMTrOM555/jnw+ZTqf0+91WOQFaSSZL3IurA85Go04PjlmMpsTZV22rlxh995dVFUhhGQ8GdNttxkM1jirPRVCwWqyzq4Vnlff1n0U/kcbkGLF7j9rAYUnW4iKh0h38z3/veZGOA2w9C0UCv47vtApzhZVSqGMqU+sMAcvPGF9qHR4D1JKVOHcbw4BF5GkUoq8cKQpwfP4DZ6mac367DdTyBjltQqBrdHZRPGbtnxoQoSCqfnsXkMJ8xOaGlaovYSfCTED31eYD7Myxg18KIosbpAkCVnsGKaEN6v8vS/N0DiObYFZVxTXC4tQg6k1RWnH299n7A4Nm8ZvLI+jX4PuhC/yAoxNfirLklZsk6b6/T5Zlrm6HHauPa1/1u4wmcxcNGRFt9vl0qUrjEYjW2J+c9OCm1VFWVUgI6I4YT6bopOItUGPRV5Q5rlzTwtu3LjG/bt3kRIKVXGwv8/62hrtTof57CmneJeRLaihHLW3T5EWHmuQNuhGidXN21T1ffObLNzAoT0MPCYo/OIL1e6lgFj1uYfxBOFi9tcOTQ9/nUgECVoOVJRuw552mqcuJZfYlnrzlbOMM0UeM2GMVYVrBmO5DFAJXW+RtEVcjZBIbDai5YYQNdOQsaQSqAaeEwqMpqsxdBOGMRj++0qplcUWuiPDjdjEi5pz7e/Dtzi2ppVH+6WQtXCU0hGu4nkaHI4RNdyqWlvBLVYzcUOy1rpvhxMJjE2dD/JavJlggqJEcSutXc6erk0pS8zr6dpOTk5oaUO3PyCOY9bX1+uIyLULmwhsvdX9oyMsX4t1beZFRaU15WQBRtNpZxhVIRBMJxNOjg5J44hOt8+D6Riw6+rC5ha33z3mrPZUCAXPEGa9gKaO8/cqrD95pbSS235s9eSBVdOA4Lvhpm/aqk0V25sUIZBn3ZaPR1I2/eNCCES01HakXDIB+yAiYwxGaCoeB9dCoeLNnm6rbSP8HLvxoshXwLCo5m5Y3fyemzEUkNbMiK2l7IBTH+FYj1FgehlVPTa+zY3bxFiamyh8Ro2px8Xfb1MgN82UENRsvp64jNIkSRyRaYnSJQX2EInjmLjVIo5sTEipfCzKquovo6iODnSrDimd50Tg+BiXz2CMJsJVjXKmmy87p5VCCImMqLkzvbYW5ol4oleA4XBI2unS6fXY3Nyk3W5z8eJFLl26xK1bt7h//z5JktLr9ZmcHBMlEWVZITAcHBwxn425evEiulKoqiDdzJhMpty78x7PPvcce7u7XLlyhUhG9Ps9JtMJaZqdshFteyqEgjF6Jewy3LAQLDRHRgKPq7LhSdMEyPzGaC7esPn/hym24XUEqyShZwmX2p/XaDVAZsAITSS9a2w1UzEMEJrP56iiqkNmpZQgBYs8p7Qlk1ewkFC9Pm1zWTXbFlsBR5ZSqZU+jSujp7SmMqtj6vsJN3IYiBSe6qfdg29+7kJBEJo2p81jff8ON4idiqy1LeeuXNBSLKzbWArq4CMf+p2XRS0wveblBXjl57ERTAXUyXBAnXxmzYqq1ui8F8gmMjleyICP03MnRFFU17nY3Nzk4sWLSCnpDtfpDdcRMuLTr3yGnZ0dvv6vX6Xb7XLz2ed5//33OTocsb4x5OLmOocH+7z15ptICdcuXaTT6zIZn5ClNngqTVLGkxPefvstqkrRHQ7ptW1exN27dynK6tR1Ck+NUACfmGRcEE7sF7m0Qb4Yg4qwrgqWSPnyGqvuy9M2ffidEFdofm713uzJIE/pz0c3+gXkfdewVDN9AJSInB3tFpSJBMKsAnZNTwpQ06hHsSVg6ff7NhNPqzp6zy/0JhYSnrS1gJViZbOFgGQIsprq8XqDTS2gBucCt6f/TOjBqIWGXs21OA2bCHGFlY1pTH1w2FDfqNYavZCxVb+X3qfQU9LKWuQOzLVxBxpdFs6duMQPRCDcmiZNOEaYJbWd0Roi6ixVy2zlUrqVqmtceiGVpikbGxskScJoNOLGjRusb2wwWNug1Wpx+/ZtxuNxfRgcHBxgjOHGM88w6Hc4ONhle3uH/qDPcDDA6IqjoxGL2RSBod/rMRz0mS2mLOZzhJTs3L9H6+azNjy61WY8fsoxBWMMpaqI4sgWho0ju6mMRmi3MA0uEm91cYYqd/N0gseBrrDP5j2cph5bLQGUUfhglziOQEQYE1sAS1vOQqW1FWJ+kwvhouaWLi/vZamKZVqyt4EtiGVPbylsIlSU2pTcsiqRhbQs7kKQRDGFtDUcCGziMAAo1CL8IpdSkmVLItdw0/oFX1WWJzAWwgU5WcEofIASzsXnokE9uUtTiDTH146VOwSk32SxSw93cyls7ADCmgDezMEYGyxWKTvWasm16E97YwxVWVrTwVUYL8uy3ujz3FZ1irz72IGI9Vpy8wWPu679s2lt12UhIEsjKq3Jq5LI5aAY5+DU2lY0K/KcKI5Js3Sp7cQxeVHQ7nS5+dyzrK9vMFzbYDK1eRC9/oDxZEJRKRCSza1LXL16g4O9fe7d22axmJCkLTqdNYy2qdfz6ZR8PmV9bQhRxt7RGKEMZTUny1Im830GG+tEswlxnNg1fEZ7KoQCApSkXhhC2rLf6CV3IAYbvcfq4lsB85x6eZrdC5x6kp5lRqyYB8KaOO4DSOndnRprZer6HtHiMQNCSkmlrb0qzSoVm/QbDDBCItzJ7VOeK62pHKkoZUFeFvWGjqUFBG26sSFyIKMPDmpqTkmSuEg/q8L6qlU1UObLpRmrqaWxpCwtlpFXFUL7+JHl5hEiwu3lMwVybR5VNpTdCkZp4wrwlaxtFKbWGhUQrITENGEMRUSEkWCECyl2LsjSb3oEpXMHyijCCKi0sqzSDl+pY7Zg6aZ1AsqOm3/X/ljlzwonIw2mrDBIRCSR+YIkjjFV5Uh5NEYJxwthQMfIOKbTadPqdIiTlK3Ll+kNh1QGJpMp/d4ALWD/8IDuYMDoeMyFi5fBCN568xYoQ6fdo9fvkWUZj7Yfsre3jyoLyrIiTbtkvTUe7BzS7XZIpKHXH3DjxjUODnY4mY5pt9p0oojh+pCz2tMhFFzzoboSS8HtvXf+pBCI2r4LN23ongwLv8LjGX3+tVC9DX+H1zzt9fB3szW1Ed+aavKK+o5ffNTBMuHpbTUBq36Gfn6/yX2//uQLM0TDFHSr4cSWfVmtahXeDPEcAhYdbxNJT0EnrNYj7cZStbAWSAkmEHTNcV4ZO+91Ccyt08Y21GL8a+E8r4xn5MfSrRn7hRUTRmntAMJVbbI5xx5BOGtum1qnMobSjg66LEmiiFhK0iQGg823iGzSU5ZldHo94sRuOY8rLBYL0rQFMRwc7CPThHavR384RGkYjUbcu3ufYafLiy+/SKUKCr3gzp07vPfeu3S7lr9zbc2WrJdScHiwj8DQaSXEUY+LW1tIqSnyOVLa6Mhe5yOq+/DxNQdO+Xx3YZNKBNRJRGiDTORKsA0sN7i3VcMsRlgFxpqt6TP3iy+0wWG5qZsmy2NPcYrm0Xy9CajhBJ0fA6RY+U4cx4hoyX2wAn66+yrL0p5eZpntB6y4JmuvilhWY/KRnN5e99/VWtNpt2llsSMcBS1ACVvEdpUqrQHENcYgFOBeIHjhFdK7h2PjrxPOQ+gRquePsBS9dW3HcWxtfB14NDAQfLcpHGoh9gHC/rQ1pA1URoHRGCnRcYxIUuJWTJImoCKSVpt2p8PW1kXiNGU6dQSu3S7z+dxVIcsYTybIKCLDmouz+Yyj0Yid7Ud0Wh1+4id/kjRKOT45osgt98NLL71kK4uNjmi1MmazGePxCe1Wi+lsRpb00Mbw/TffJM+nbG1uOA1Sc3BwcOqzwtMiFNwa8pmSOPYAX7bL25a6tmVXw3tDwXCWmzLUCJqvNeMPfAtPh+ZC/yD7ufleeHo+Lhz8ACwFg9Ea7Z8ziohju3n95g4rNPvfVSAYQzPKP1udayAqjFmGd3t0vCiK2o0JkGYp3a5lCfIUZf7aSgOEwvf01OZwvDyQ3BSQobALvU2rLuHHsR4/eHFiOQwEkCU2HbksCjS23oXWNlw5vFaTrak2T9TjWl5zzptz780MY8xjQs8LfA+YK6UoygKV58goRghfWjCllbW5cvUq61sX2D84xAjB5sUtnrnxDD/+yo9TzBfcv3Of3qDH6MGBI1fJePDgAf1Om/F4glYVs9mUi1tbdNstVDnn0aNHPHP9Cp/+9KeZTsdMTk5Ik7Qeg1PX71mq8JNsQog9YArsf0K3sPkJ9v2j3v+P8rN/0v3fNMZsNV98KoQCgBDim+YUDvr/v/f9o97/j/KzPw39n9ZON47P23k7bz+y7VwonLfzdt5W2tMkFH7zR7TvH/X+f5Sf/Wno/7H21GAK5+28nbenoz1NmsJ5O2/n7Slon7hQEEJ8UQjxlhDiHSHEbzyhPu8IIb4jhHhNCPFN99qGEOKrQoi33e/1j7C//10IsSuE+G7w2pn9CSH+azcebwkh/v2Poe+/K4R44J7/NSHEL38cfbvr3RBC/KEQ4k0hxPeEEP+Fe/1jf/4P6PuJPL8QoiWE+FMhxOuu///uST37v1UL4+Of9A8QAbeB54EUeB145Qn0ewfYbLz23wO/4f7+DeDvf4T9/QLwBeC7/6b+gFfcOGTAc258oo+4778L/FenfPYj7dtd8wrwBfd3H7jl+vnYn/8D+n4iz4+NSuu5vxPgT4B/50nN/Q/780lrCn8ZeMcY864xpgC+DPzqJ3Qvvwp8yf39JeA//KgubIz5V8Dhh+zvV4EvG2NyY8x7wDvYcfoo+z6rfaR9u/63jTHfcn+PgTeBazyB5/+Avs9qH/XYG2PMxP03cT+GJzT3P2z7pIXCNeBe8P/7fPCkfVTNAF8RQvy5EOLX3WuXjDHbYBcTcPFjvoez+ntSY/KfCyHecOaFV18/1r6FEM8Cn8eemE/0+Rt9wxN6fiFEJIR4DdgFvmqMeeLP/hdtn7RQOC2B4Em4Q37eGPMF4G8A/5kQ4heeQJ8ftj2JMfkHwAvA54Bt4H/4uPsWQvSA/xv4L40xJx/00Y/6Hk7p+4k9vzFGGWM+B1wH/rIQ4jMfdKsfdf8/TPukhcJ94Ebw/+vAw4+7U2PMQ/d7F/hdrIq2I4S4AuB+737Mt3FWfx/7mBhjdtxi1cD/ylJF/Vj6FkIk2E35fxpjfse9/ESe/7S+n/Tzuz5HwNeAL/IJzv2HaZ+0UPgz4EUhxHNCiBT4m8A/+Tg7FEJ0hRB9/zfwS8B3Xb+/5j72a8A//jjv4wP6+yfA3xRCZEKI54AXgT/9KDv2C9K1/wj7/B9L38KmFP5vwJvGmP8xeOtjf/6z+n5Szy+E2BJCrLm/28BfB37AJzj3H6o9aWTzFIT2l7Go8G3g7zyB/p7HIryvA9/zfQIXgD8A3na/Nz7CPv8hVk0tsafB3/qg/oC/48bjLeBvfAx9/x/Ad4A3sAvxysfRt7veX8GqwG8Ar7mfX34Sz/8BfT+R5wd+Avi26+e7wH/zb1prH/X4/zA/5xGN5+28nbeV9kmbD+ftvJ23p6ydC4Xzdt7O20o7Fwrn7bydt5V2LhTO23k7byvtXCict/N23lbauVA4b+ftvK20c6Fw3s7beVtp50LhvJ2387bS/j+Er59CDmqSnwAAAABJRU5ErkJggg==\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "# Testing event\n", - "cat_image_url = 'https://s3.amazonaws.com/iguazio-sample-data/images/catanddog/cat.102.jpg'\n", - "response = requests.get(cat_image_url)\n", - "cat_image = response.content\n", - "img = Image.open(BytesIO(cat_image))\n", - "\n", - "print('Test image:')\n", - "plt.imshow(img)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Define Function specifications" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [], - "source": [ - "import os\n", - "from mlrun import mlconf\n", - "\n", - "# Specific model variables\n", - "function_envs = {\n", - " 'IMAGE_HEIGHT': 224,\n", - " 'IMAGE_WIDTH': 224,\n", - " 'classes_map': '/Userv3io/projects/cat-and-dog-servers/artifacts/categories_map.json',\n", - "}" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Deploy the serving function to the cluster" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [], - "source": [ - "from mlrun import code_to_function, mount_v3io" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "> 2021-01-29 23:47:54,881 [info] function spec saved to path: function.yaml\n" - ] - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Setup the model server function\n", - "\n", - "fn = code_to_function('tf2-serving-v2', kind=\"serving\")\n", - "fn.spec.description = \"tf2 image classification server v2\"\n", - "fn.metadata.categories = ['serving', 'dl']\n", - "fn.metadata.labels = {'author': 'yaronh'}\n", - "fn.export(\"function.yaml\")\n", - "fn.set_envs(function_envs)\n", - "fn.add_model(key=\"model\",\n", - " model_path=\"/User/mlrun_repos/demos/image-classification-with-distributed-training/pipe/52f2145e-7a54-4137-8c7b-b6c20cc8b1fd/tfmodels/model.h5\",\n", - " class_name=\"TFModel\")" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [], - "source": [ - "if \"V3IO_HOME\" in list(os.environ):\n", - " from mlrun import mount_v3io\n", - " fn.apply(mount_v3io())\n", - "else:\n", - " # is you set up mlrun using the instructions at\n", - " # https://github.com/mlrun/mlrun/blob/master/hack/local/README.md\n", - " from mlrun.platforms import mount_pvc\n", - " fn.apply(mount_pvc('nfsvol', 'nfsvol', '/home/joyan/data'))" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "> 2021-01-29 23:47:54,893 [info] Starting remote function deploy\n", - "2021-01-29 23:47:55 (info) Deploying function\n", - "2021-01-29 23:47:55 (info) Building\n", - "2021-01-29 23:47:55 (info) Staging files and preparing base images\n", - "2021-01-29 23:47:56 (info) Building processor image\n", - "2021-01-29 23:47:57 (info) Build complete\n", - "2021-01-29 23:48:07 (info) Function deploy complete\n", - "> 2021-01-29 23:48:08,029 [info] function deployed, address=default-tenant.app.us-sales30-demo.iguazio-cd2.com:31946\n" - ] - } - ], - "source": [ - "# Deploy the model server\n", - "addr = fn.deploy(project='cat-and-dog-servers')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Test the deployed function on the cluster" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Test the deployed function (with URL)" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [], - "source": [ - "payload = json.dumps({\"data_url\" : cat_image_url})" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'id': '38224902-a688-4985-9424-578ff9ccb4a5',\n", - " 'model_name': 'model',\n", - " 'outputs': [0.0]}" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "fn.invoke(path='/v2/models/model/predict', body=payload)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Test the deployed function (with Jpeg Image)" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'id': '246c00fc-225c-44ec-b221-4e6c99f7bc5d',\n", - " 'model_name': 'model',\n", - " 'outputs': [0.0]}" - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "fn.invoke(path='/v2/models/model/predict',\n", - " body=cat_image,\n", - " headers={'Content-type': 'image/jpeg'})" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "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.7.6" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/tf2_serving_v2/tf2_serving_v2.py b/tf2_serving_v2/tf2_serving_v2.py deleted file mode 100644 index 677280a86..000000000 --- a/tf2_serving_v2/tf2_serving_v2.py +++ /dev/null @@ -1,71 +0,0 @@ -# Copyright 2019 Iguazio -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# Generated by nuclio.export.NuclioExporter - -import warnings - -warnings.simplefilter(action="ignore", category=FutureWarning) - -import json -import numpy as np -import requests -from tensorflow import keras -from tensorflow.keras.models import load_model -from tensorflow.keras.preprocessing import image -from tensorflow.keras.preprocessing.image import load_img -from os import environ, path -from PIL import Image -from io import BytesIO -from urllib.request import urlopen -import mlrun - - -class TFModel(mlrun.serving.V2ModelServer): - def load(self): - self.IMAGE_WIDTH = int(environ.get("IMAGE_WIDTH", "128")) - self.IMAGE_HEIGHT = int(environ.get("IMAGE_HEIGHT", "128")) - - try: - with open(environ["classes_map"], "r") as f: - self.classes = json.load(f) - except: - self.classes = None - - model_file, extra_data = self.get_model(".h5") - self.model = load_model(model_file) - - def preprocess(self, body, operation): - try: - output = {"inputs": []} - inputs = body.get("inputs", []) - for byte_image in inputs: - img = Image.open(byte_image) - img = img.resize((self.IMAGE_WIDTH, self.IMAGE_HEIGHT)) - - x = image.img_to_array(img) - x = np.expand_dims(x, axis=0) - output["inputs"].append(x) - - output["inputs"] = [np.vstack(output["inputs"])] - return output - except: - raise Exception(f"received: {body}") - - def predict(self, data): - images = data.get("inputs", []) - - predicted_probability = self.model.predict(images) - - return predicted_probability.tolist()[0] \ No newline at end of file diff --git a/virtual_drift/README.md b/virtual_drift/README.md deleted file mode 100644 index cd7383904..000000000 --- a/virtual_drift/README.md +++ /dev/null @@ -1,56 +0,0 @@ -# Drift Magnitude - -Concept drift and shift are major issues that greatly affect the accuracy and reliability of many real-world applications of machine learning. We can use the following Drift Magnitude metrics to map and understand our concepts and how close the properties of the data we used to train the models on are to the current data we receive. - -## How to integrate - -The Virtual Drift function is built to receive two data batches of data (as `dataitem` or `Dataframe`), base batch *t* and current batch *u*. - -```markdown -:param context: MLRun context -:param t: Base dataset for the drift metrics -:param u: Test dataset for the drift metrics -:param label_col: Label colum in t and u -:param prediction_col: Predictions column in t and u -:param discritizers: Dictionary of dicsritizers for the features if available - (Created automatically if not provided) -:param n_bins: Number of bins to be used for histrogram creation from continuous variables -:param stream_name: Output stream to push metrics to -:param results_tsdb_container: TSDB table container to push metrics to -:param results_tsdb_table: TSDB table to push metrics to -``` - -The function will calculate the selected drift mangitude metrics that were selected and apply them to the **features**, **labels** and **predictions**. It will then save those metrics and export them via Parquet and TSDB. Alerting could be added on top of the metrics via Grafana or a function. - -## Metrics - -The drift magnitude metrics we calculate are: - -### TVD - Total Variation Distance - -Provides a symetric drift distance between two periods *t* and *u* -Z - vector of random variables -P*t* - Probability distribution over timespan *t* - -![\sigma_{t, u}(Z)=\frac{1}{2}\sum_{\hat{z}\in{dom(Z)}}{|P_t{(\hat{Z})-P_u{(\hat{Z})}}|}]() - -### Helinger Distance - -Hellinger distance is an *f* divergence measuer, similar to the Kullback-Leibler (KL) divergence. However, unlike KL Divergence the Hellinger divergence is symmetric and bounded over a probability space. - -P, Q - Discrete probability distributions (P*i*, ..., P*k*). - -![H(P,Q)=\frac{1}{\sqrt{2}}\sqrt{\sum_{i=1}^{k}{(\sqrt{p_i}-\sqrt{q_i})^2}}]() - - -### KL Divergence - -KL Divergence (or relative entropy) is a measure of how one probability distribution differs from another. It is an asymmetric measure (thus it's not a metric) and it doesn't satisfy the triangle inequality. KL Divergence of 0, indicates two identical distributrions. - -![D_{KL}(P||Q)=\sum_{x\in{X}}{(P(x)\log{\frac{P(x)}{Q(x)}})}]() - -## Additional Resources - -Webb, Geoffrey I. et al. “[Characterizing Concept Drift.](https://arxiv.org/abs/1511.03816)” Data Mining and Knowledge Discovery 30.4 (2016): 964–994. Crossref. Web. - -[MLOps Live #4 - How to Detect & Remediate Drift in Production with MLOps Automation](https://www.youtube.com/watch?v=66_Q7mJZOSc&t=1296s) diff --git a/virtual_drift/function.yaml b/virtual_drift/function.yaml deleted file mode 100644 index 55dcec11c..000000000 --- a/virtual_drift/function.yaml +++ /dev/null @@ -1,129 +0,0 @@ -kind: job -metadata: - name: virtual-drift - tag: '' - hash: 8990fdd72fc550189a0c8b488b69997428b786c9 - project: '' - labels: - author: orz - categories: - - data-analysis - - machine-learning -spec: - command: '' - args: [] - image: mlrun/ml-models - env: [] - default_handler: drift_magnitude - entry_points: - to_observations: - name: to_observations - doc: '' - parameters: - - name: context - default: '' - - name: t - default: '' - - name: u - default: '' - - name: key - default: '' - outputs: - - default: '' - lineno: 16 - tvd: - name: tvd - doc: '' - parameters: - - name: t - default: '' - - name: u - default: '' - outputs: - - default: '' - lineno: 42 - helinger: - name: helinger - doc: '' - parameters: - - name: t - default: '' - - name: u - default: '' - outputs: - - default: '' - lineno: 46 - kl_divergence: - name: kl_divergence - doc: '' - parameters: - - name: t - default: '' - - name: u - default: '' - outputs: - - default: '' - lineno: 50 - all_metrics: - name: all_metrics - doc: '' - parameters: - - name: t - default: '' - - name: u - default: '' - outputs: - - default: '' - lineno: 56 - drift_magnitude: - name: drift_magnitude - doc: "Drift magnitude metrics\n Computes drift magnitude metrics between base\ - \ dataset t and dataset u.\n Metrics:\n - TVD (Total Variation Distance)\n\ - \ - Helinger\n - KL Divergence" - parameters: - - name: context - doc: MLRun context - default: '' - - name: t - type: DataFrame - doc: Base dataset for the drift metrics - default: '' - - name: u - type: DataFrame - doc: Test dataset for the drift metrics - default: '' - - name: label_col - doc: Label colum in t and u - default: null - - name: prediction_col - doc: Predictions column in t and u - default: null - - name: discretizers - type: dict - default: null - - name: n_bins - doc: Number of bins to be used for histrogram creation from continuous variables - default: 5 - - name: stream_name - type: str - doc: Output stream to push metrics to - default: some_stream - - name: results_tsdb_container - type: str - doc: TSDB table container to push metrics to - default: bigdata - - name: results_tsdb_table - type: str - doc: TSDB table to push metrics to - default: concept_drift/drift_magnitude - outputs: - - default: '' - lineno: 60 - description: Compute drift magnitude between Time-Samples T and U - build: - functionSourceCode: IyBHZW5lcmF0ZWQgYnkgbnVjbGlvLmV4cG9ydC5OdWNsaW9FeHBvcnRlcgoKaW1wb3J0IG9zCmltcG9ydCBwYW5kYXMgYXMgcGQKaW1wb3J0IG51bXB5IGFzIG5wCmltcG9ydCBzY2lweSBhcyBzcAppbXBvcnQgcGlja2xlCmltcG9ydCBkYXRldGltZQoKaW1wb3J0IHYzaW9fZnJhbWVzIGFzIHYzZgoKaW1wb3J0IG1hdHBsb3RsaWIucHlwbG90IGFzIHBsdApmcm9tIHNrbGVhcm4ucHJlcHJvY2Vzc2luZyBpbXBvcnQgS0JpbnNEaXNjcmV0aXplcgoKCmRlZiB0b19vYnNlcnZhdGlvbnMoY29udGV4dCwgdCwgdSwga2V5KToKICAgIHQgPSAoCiAgICAgICAgdC5hcHBseShsYW1iZGEgcm93OiBmInsnXycuam9pbihbc3RyKHJvd1t2YWxdKSBmb3IgdmFsIGluIHQuY29sdW1uc10pfSIsIGF4aXM9MSkKICAgICAgICAudmFsdWVfY291bnRzKCkKICAgICAgICAuc29ydF9pbmRleCgpCiAgICApCiAgICB1ID0gKAogICAgICAgIHUuYXBwbHkobGFtYmRhIHJvdzogZiJ7J18nLmpvaW4oW3N0cihyb3dbdmFsXSkgZm9yIHZhbCBpbiB1LmNvbHVtbnNdKX0iLCBheGlzPTEpCiAgICAgICAgLnZhbHVlX2NvdW50cygpCiAgICAgICAgLnNvcnRfaW5kZXgoKQogICAgKQoKICAgIGpvaW5lZF91bmlxdWVzID0gcGQuRGF0YUZyYW1lKFt0LCB1XSkuVC5maWxsbmEoMCkuc29ydF9pbmRleCgpCiAgICBqb2luZWRfdW5pcXVlcy5jb2x1bW5zID0gWyJ0IiwgInUiXQoKICAgIHRfb2JzID0gam9pbmVkX3VuaXF1ZXMubG9jWzosICJ0Il0KICAgIHVfb2JzID0gam9pbmVkX3VuaXF1ZXMubG9jWzosICJ1Il0KCiAgICB0X3BkZiA9IHRfb2JzIC8gdF9vYnMuc3VtKCkKICAgIHVfcGRmID0gdV9vYnMgLyB1X29icy5zdW0oKQoKICAgIGNvbnRleHQubG9nX2RhdGFzZXQoZiJ7a2V5fV90X3BkZiIsIHBkLkRhdGFGcmFtZSh0X3BkZiksIGZvcm1hdD0icGFycXVldCIpCiAgICBjb250ZXh0LmxvZ19kYXRhc2V0KGYie2tleX1fdV9wZGYiLCBwZC5EYXRhRnJhbWUodV9wZGYpLCBmb3JtYXQ9InBhcnF1ZXQiKQogICAgcmV0dXJuIHRfcGRmLCB1X3BkZgoKCmRlZiB0dmQodCwgdSk6CiAgICByZXR1cm4gc3VtKGFicyh0IC0gdSkpIC8gMgoKCmRlZiBoZWxpbmdlcih0LCB1KToKICAgIHJldHVybiAobnAuc3FydChucC5zdW0obnAucG93ZXIobnAuc3FydCh0KSAtIG5wLnNxcnQodSksIDIpKSkpIC8gbnAuc3FydCgyKQoKCmRlZiBrbF9kaXZlcmdlbmNlKHQsIHUpOgogICAgdF91ID0gbnAuc3VtKG5wLndoZXJlKHQgIT0gMCwgdCAqIG5wLmxvZyh0IC8gdSksIDApKQogICAgdV90ID0gbnAuc3VtKG5wLndoZXJlKHUgIT0gMCwgdSAqIG5wLmxvZyh1IC8gdCksIDApKQogICAgcmV0dXJuIHRfdSArIHVfdAoKCmRlZiBhbGxfbWV0cmljcyh0LCB1KToKICAgIHJldHVybiB0dmQodCwgdSksIGhlbGluZ2VyKHQsIHUpLCBrbF9kaXZlcmdlbmNlKHQsIHUpCgoKZGVmIGRyaWZ0X21hZ25pdHVkZSgKICAgIGNvbnRleHQsCiAgICB0OiBwZC5EYXRhRnJhbWUsCiAgICB1OiBwZC5EYXRhRnJhbWUsCiAgICBsYWJlbF9jb2w9Tm9uZSwKICAgIHByZWRpY3Rpb25fY29sPU5vbmUsCiAgICBkaXNjcmV0aXplcnM6IGRpY3QgPSBOb25lLAogICAgbl9iaW5zPTUsCiAgICBzdHJlYW1fbmFtZTogc3RyID0gInNvbWVfc3RyZWFtIiwKICAgIHJlc3VsdHNfdHNkYl9jb250YWluZXI6IHN0ciA9ICJiaWdkYXRhIiwKICAgIHJlc3VsdHNfdHNkYl90YWJsZTogc3RyID0gImNvbmNlcHRfZHJpZnQvZHJpZnRfbWFnbml0dWRlIiwKKToKICAgICIiIkRyaWZ0IG1hZ25pdHVkZSBtZXRyaWNzCiAgICAgICBDb21wdXRlcyBkcmlmdCBtYWduaXR1ZGUgbWV0cmljcyBiZXR3ZWVuIGJhc2UgZGF0YXNldCB0IGFuZCBkYXRhc2V0IHUuCiAgICAgICBNZXRyaWNzOgogICAgICAgIC0gVFZEIChUb3RhbCBWYXJpYXRpb24gRGlzdGFuY2UpCiAgICAgICAgLSBIZWxpbmdlcgogICAgICAgIC0gS0wgRGl2ZXJnZW5jZQoKICAgIDpwYXJhbSBjb250ZXh0OiBNTFJ1biBjb250ZXh0CiAgICA6cGFyYW0gdDogQmFzZSBkYXRhc2V0IGZvciB0aGUgZHJpZnQgbWV0cmljcwogICAgOnBhcmFtIHU6IFRlc3QgZGF0YXNldCBmb3IgdGhlIGRyaWZ0IG1ldHJpY3MKICAgIDpwYXJhbSBsYWJlbF9jb2w6IExhYmVsIGNvbHVtIGluIHQgYW5kIHUKICAgIDpwYXJhbSBwcmVkaWN0aW9uX2NvbDogUHJlZGljdGlvbnMgY29sdW1uIGluIHQgYW5kIHUKICAgIDpwYXJhbSBkaXNjcml0aXplcnM6IERpY3Rpb25hcnkgb2YgZGljc3JpdGl6ZXJzIGZvciB0aGUgZmVhdHVyZXMgaWYgYXZhaWxhYmxlCiAgICAgICAgICAgICAgICAgICAgICAgICAoQ3JlYXRlZCBhdXRvbWF0aWNhbGx5IGlmIG5vdCBwcm92aWRlZCkKICAgIDpwYXJhbSBuX2JpbnM6IE51bWJlciBvZiBiaW5zIHRvIGJlIHVzZWQgZm9yIGhpc3Ryb2dyYW0gY3JlYXRpb24gZnJvbSBjb250aW51b3VzIHZhcmlhYmxlcwogICAgOnBhcmFtIHN0cmVhbV9uYW1lOiBPdXRwdXQgc3RyZWFtIHRvIHB1c2ggbWV0cmljcyB0bwogICAgOnBhcmFtIHJlc3VsdHNfdHNkYl9jb250YWluZXI6IFRTREIgdGFibGUgY29udGFpbmVyIHRvIHB1c2ggbWV0cmljcyB0bwogICAgOnBhcmFtIHJlc3VsdHNfdHNkYl90YWJsZTogVFNEQiB0YWJsZSB0byBwdXNoIG1ldHJpY3MgdG8KICAgICIiIgoKICAgIHYzaW9fY2xpZW50ID0gdjNmLkNsaWVudCgiZnJhbWVzZDo4MDgxIiwgY29udGFpbmVyPXJlc3VsdHNfdHNkYl9jb250YWluZXIpCiAgICB0cnk6CiAgICAgICAgdjNpb19jbGllbnQuY3JlYXRlKCJ0c2RiIiwgcmVzdWx0c190c2RiX3RhYmxlLCBpZl9leGlzdHM9MSwgcmF0ZT0iMS9zIikKICAgIGV4Y2VwdDoKICAgICAgICB2M2lvX2NsaWVudC5jcmVhdGUoCiAgICAgICAgICAgICJ0c2RiIiwgcmVzdWx0c190c2RiX3RhYmxlLCBpZl9leGlzdHM9MSwgYXR0cnM9eyJyYXRlIjogIjEvcyJ9CiAgICAgICAgKQoKICAgIGRmX3QgPSB0LmFzX2RmKCkKICAgIGRmX3UgPSB1LmFzX2RmKCkKCiAgICBkcm9wX2NvbHVtbnMgPSBbXQogICAgaWYgbGFiZWxfY29sIGlzIG5vdCBOb25lOgogICAgICAgIGRyb3BfY29sdW1ucy5hcHBlbmQobGFiZWxfY29sKQogICAgaWYgcHJlZGljdGlvbl9jb2wgaXMgbm90IE5vbmU6CiAgICAgICAgZHJvcF9jb2x1bW5zLmFwcGVuZChwcmVkaWN0aW9uX2NvbCkKCiAgICBjb250aW51b3VzX2ZlYXR1cmVzID0gZGZfdC5zZWxlY3RfZHR5cGVzKFsiZmxvYXQiXSkKICAgIGlmIGRpc2NyZXRpemVycyBpcyBOb25lOgogICAgICAgIGRpc2NyZXRpemVycyA9IHt9CiAgICAgICAgZm9yIGZlYXR1cmUgaW4gY29udGludW91c19mZWF0dXJlcy5jb2x1bW5zOgogICAgICAgICAgICBjb250ZXh0LmxvZ2dlci5pbmZvKGYiRml0dGluZyBkaXNjcmV0aXplciBmb3Ige2ZlYXR1cmV9IikKICAgICAgICAgICAgZGlzY3JldGl6ZXIgPSBLQmluc0Rpc2NyZXRpemVyKAogICAgICAgICAgICAgICAgbl9iaW5zPW5fYmlucywgZW5jb2RlPSJvcmRpbmFsIiwgc3RyYXRlZ3k9InVuaWZvcm0iCiAgICAgICAgICAgICkKCiAgICAgICAgICAgIGRpc2NyZXRpemVyLmZpdChjb250aW51b3VzX2ZlYXR1cmVzLmxvY1s6LCBmZWF0dXJlXS52YWx1ZXMucmVzaGFwZSgtMSwgMSkpCiAgICAgICAgICAgIGRpc2NyZXRpemVyc1tmZWF0dXJlXSA9IGRpc2NyZXRpemVyCiAgICBvcy5tYWtlZGlycyhjb250ZXh0LmFydGlmYWN0X3BhdGgsIGV4aXN0X29rPVRydWUpCiAgICBkaXNjcmV0aXplcnNfcGF0aCA9IG9zLnBhdGguYWJzcGF0aChmIntjb250ZXh0LmFydGlmYWN0X3BhdGh9L2Rpc2NyaXRpemVyLnBrbCIpCiAgICB3aXRoIG9wZW4oZGlzY3JldGl6ZXJzX3BhdGgsICJ3YiIpIGFzIGY6CiAgICAgICAgcGlja2xlLmR1bXAoZGlzY3JldGl6ZXJzLCBmKQogICAgY29udGV4dC5sb2dfYXJ0aWZhY3QoImRpc2NyaXRpemVycyIsIHRhcmdldF9wYXRoPWRpc2NyZXRpemVyc19wYXRoKQogICAgY29udGV4dC5sb2dnZXIuaW5mbygiRGlzY3JldGl6aW5nIGZlYXR1ZXJzIikKICAgIGZvciBmZWF0dXJlLCBkaXNjcmV0aXplciBpbiBkaXNjcmV0aXplcnMuaXRlbXMoKToKICAgICAgICBkZl90W2ZlYXR1cmVdID0gZGlzY3JldGl6ZXIudHJhbnNmb3JtKAogICAgICAgICAgICBkZl90LmxvY1s6LCBmZWF0dXJlXS52YWx1ZXMucmVzaGFwZSgtMSwgMSkKICAgICAgICApCiAgICAgICAgZGZfdVtmZWF0dXJlXSA9IGRpc2NyZXRpemVyLnRyYW5zZm9ybSgKICAgICAgICAgICAgZGZfdS5sb2NbOiwgZmVhdHVyZV0udmFsdWVzLnJlc2hhcGUoLTEsIDEpCiAgICAgICAgKQogICAgICAgIGRmX3RbZmVhdHVyZV0gPSBkZl90W2ZlYXR1cmVdLmFzdHlwZSgiaW50IikKICAgICAgICBkZl91W2ZlYXR1cmVdID0gZGZfdVtmZWF0dXJlXS5hc3R5cGUoImludCIpCiAgICBjb250ZXh0LmxvZ19kYXRhc2V0KCJ0X2Rpc2NyZXRlIiwgZGZfdCwgZm9ybWF0PSJwYXJxdWV0IikKICAgIGNvbnRleHQubG9nX2RhdGFzZXQoInVfZGlzY3JldGUiLCBkZl91LCBmb3JtYXQ9InBhcnF1ZXQiKQoKICAgIGNvbnRleHQubG9nZ2VyLmluZm8oIkNvbXB1dGUgcHJpb3IgbWV0cmljcyIpCgogICAgcmVzdWx0cyA9IHt9CiAgICB0X3ByaW9yLCB1X3ByaW9yID0gdG9fb2JzZXJ2YXRpb25zKAogICAgICAgIGNvbnRleHQsCiAgICAgICAgZGZfdC5kcm9wKGRyb3BfY29sdW1ucywgYXhpcz0xKSwKICAgICAgICBkZl91LmRyb3AoZHJvcF9jb2x1bW5zLCBheGlzPTEpLAogICAgICAgICJmZWF0dXJlcyIsCiAgICApCiAgICByZXN1bHRzWyJwcmlvcl90dmQiXSwgcmVzdWx0c1sicHJpb3JfaGVsaW5nZXIiXSwgcmVzdWx0c1sicHJpb3Jfa2xkIl0gPSBhbGxfbWV0cmljcygKICAgICAgICB0X3ByaW9yLCB1X3ByaW9yCiAgICApCgogICAgaWYgcHJlZGljdGlvbl9jb2wgaXMgbm90IE5vbmU6CiAgICAgICAgY29udGV4dC5sb2dnZXIuaW5mbygiQ29tcHV0ZSBwcmVkaWN0aW9uIG1ldHJpY3MiKQogICAgICAgIHRfcHJlZGljdGlvbnMgPSBwZC5EYXRhRnJhbWUoZGZfdC5sb2NbOiwgcHJlZGljdGlvbl9jb2xdKQogICAgICAgIHVfcHJlZGljdGlvbnMgPSBwZC5EYXRhRnJhbWUoZGZfdS5sb2NbOiwgcHJlZGljdGlvbl9jb2xdKQogICAgICAgIHRfY2xhc3MsIHVfY2xhc3MgPSB0b19vYnNlcnZhdGlvbnMoCiAgICAgICAgICAgIGNvbnRleHQsIHRfcHJlZGljdGlvbnMsIHVfcHJlZGljdGlvbnMsICJwcmVkaWN0aW9uIgogICAgICAgICkKICAgICAgICAoCiAgICAgICAgICAgIHJlc3VsdHNbInByZWRpY3Rpb25fc2hpZnRfdHZkIl0sCiAgICAgICAgICAgIHJlc3VsdHNbInByZWRpY3Rpb25fc2hpZnRfaGVsaW5nZXIiXSwKICAgICAgICAgICAgcmVzdWx0c1sicHJlZGljdGlvbl9zaGlmdF9rbGQiXSwKICAgICAgICApID0gYWxsX21ldHJpY3ModF9jbGFzcywgdV9jbGFzcykKCiAgICBpZiBsYWJlbF9jb2wgaXMgbm90IE5vbmU6CiAgICAgICAgY29udGV4dC5sb2dnZXIuaW5mbygiQ29tcHV0ZSBjbGFzcyBtZXRyaWNzIikKICAgICAgICB0X2xhYmVscyA9IHBkLkRhdGFGcmFtZShkZl90LmxvY1s6LCBsYWJlbF9jb2xdKQogICAgICAgIHVfbGFiZWxzID0gcGQuRGF0YUZyYW1lKGRmX3UubG9jWzosIGxhYmVsX2NvbF0pCiAgICAgICAgdF9jbGFzcywgdV9jbGFzcyA9IHRvX29ic2VydmF0aW9ucyhjb250ZXh0LCB0X2xhYmVscywgdV9sYWJlbHMsICJjbGFzcyIpCiAgICAgICAgKAogICAgICAgICAgICByZXN1bHRzWyJjbGFzc19zaGlmdF90dmQiXSwKICAgICAgICAgICAgcmVzdWx0c1siY2xhc3Nfc2hpZnRfaGVsaW5nZXIiXSwKICAgICAgICAgICAgcmVzdWx0c1siY2xhc3Nfc2hpZnRfa2xkIl0sCiAgICAgICAgKSA9IGFsbF9tZXRyaWNzKHRfY2xhc3MsIHVfY2xhc3MpCgogICAgZm9yIGtleSwgdmFsdWUgaW4gcmVzdWx0cy5pdGVtcygpOgogICAgICAgIGlmIHZhbHVlID09IGZsb2F0KCJpbmYiKToKICAgICAgICAgICAgY29udGV4dC5sb2dnZXIuaW5mbyhmInZhbHVlOiB7dmFsdWV9IikKICAgICAgICAgICAgcmVzdWx0c1trZXldID0gMTAKICAgIGZvciBrZXksIHJlc3VsdCBpbiByZXN1bHRzLml0ZW1zKCk6CiAgICAgICAgY29udGV4dC5sb2dfcmVzdWx0KGtleSwgcm91bmQocmVzdWx0LCAzKSkKCiAgICBub3cgPSBwZC50b19kYXRldGltZShzdHIoZGF0ZXRpbWUuZGF0ZXRpbWUubm93KCkpKQogICAgbm93CgogICAgcmVzdWx0c1sidGltZXN0YW1wIl0gPSBwZC50b19kYXRldGltZShzdHIoKGRhdGV0aW1lLmRhdGV0aW1lLm5vdygpKSkpCiAgICBjb250ZXh0LmxvZ2dlci5pbmZvKGYiVGltZXN0YW1wOiB7cmVzdWx0c1sndGltZXN0YW1wJ119IikKICAgIHJlc3VsdHNbInN0cmVhbSJdID0gc3RyZWFtX25hbWUKICAgIHJlc3VsdHNfZGYgPSBwZC5EYXRhRnJhbWUoCiAgICAgICAgZGF0YT1bbGlzdChyZXN1bHRzLnZhbHVlcygpKV0sIGNvbHVtbnM9bGlzdChyZXN1bHRzLmtleXMoKSkKICAgICkKICAgIHJlc3VsdHNfZGYgPSByZXN1bHRzX2RmLnNldF9pbmRleChbInRpbWVzdGFtcCIsICJzdHJlYW0iXSkKICAgIHYzaW9fY2xpZW50LndyaXRlKCJ0c2RiIiwgcmVzdWx0c190c2RiX3RhYmxlLCBkZnM9cmVzdWx0c19kZikK - commands: - - python -m pip install scikit-learn scipy v3io_frames - code_origin: https://github.com/daniels290813/functions.git#55a79c32be5d233cc11efcf40cd3edbe309bfdef:/home/kali/functions/virtual_drift/virtual_drift.py - affinity: null -verbose: false diff --git a/virtual_drift/item.yaml b/virtual_drift/item.yaml deleted file mode 100644 index d66f9e9c1..000000000 --- a/virtual_drift/item.yaml +++ /dev/null @@ -1,28 +0,0 @@ -apiVersion: v1 -categories: -- data-analysis -- machine-learning -description: Compute drift magnitude between Time-Samples T and U -doc: '' -example: virtual_drift.ipynb -generationDate: 2022-08-28:17-25 -hidden: false -icon: '' -labels: - author: orz -maintainers: [] -marketplaceType: '' -mlrunVersion: 1.1.0 -name: virtual-drift -platformVersion: 3.5.0 -spec: - filename: virtual_drift.py - handler: drift_magnitude - image: mlrun/ml-models - kind: job - requirements: - - scikit-learn - - scipy - - v3io_frames -url: '' -version: 1.1.0 diff --git a/virtual_drift/virtual_drift.ipynb b/virtual_drift/virtual_drift.ipynb deleted file mode 100644 index 23b9ef432..000000000 --- a/virtual_drift/virtual_drift.ipynb +++ /dev/null @@ -1,935 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Virtual Drift\n", - "\n", - "Drift magnitude metrics\n", - " Computes drift magnitude metrics between base dataset t and dataset u. \n", - "\n", - "Metrics:\n", - "- TVD (Total Variation Distance)\n", - "- Helinger\n", - "- KL Divergence" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### **Steps**\n", - "\n", - "1. [Data exploration](#Data-exploration)\n", - "2. [Importing the function](#Importing-the-function)\n", - "3. [Running the function locally](#Running-the-function-locally)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### **Data exploration**" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - ".. _wine_dataset:\n", - "\n", - "Wine recognition dataset\n", - "------------------------\n", - "\n", - "**Data Set Characteristics:**\n", - "\n", - " :Number of Instances: 178 (50 in each of three classes)\n", - " :Number of Attributes: 13 numeric, predictive attributes and the class\n", - " :Attribute Information:\n", - " \t\t- Alcohol\n", - " \t\t- Malic acid\n", - " \t\t- Ash\n", - "\t\t- Alcalinity of ash \n", - " \t\t- Magnesium\n", - "\t\t- Total phenols\n", - " \t\t- Flavanoids\n", - " \t\t- Nonflavanoid phenols\n", - " \t\t- Proanthocyanins\n", - "\t\t- Color intensity\n", - " \t\t- Hue\n", - " \t\t- OD280/OD315 of diluted wines\n", - " \t\t- Proline\n", - "\n", - " - class:\n", - " - class_0\n", - " - class_1\n", - " - class_2\n", - "\t\t\n", - " :Summary Statistics:\n", - " \n", - " ============================= ==== ===== ======= =====\n", - " Min Max Mean SD\n", - " ============================= ==== ===== ======= =====\n", - " Alcohol: 11.0 14.8 13.0 0.8\n", - " Malic Acid: 0.74 5.80 2.34 1.12\n", - " Ash: 1.36 3.23 2.36 0.27\n", - " Alcalinity of Ash: 10.6 30.0 19.5 3.3\n", - " Magnesium: 70.0 162.0 99.7 14.3\n", - " Total Phenols: 0.98 3.88 2.29 0.63\n", - " Flavanoids: 0.34 5.08 2.03 1.00\n", - " Nonflavanoid Phenols: 0.13 0.66 0.36 0.12\n", - " Proanthocyanins: 0.41 3.58 1.59 0.57\n", - " Colour Intensity: 1.3 13.0 5.1 2.3\n", - " Hue: 0.48 1.71 0.96 0.23\n", - " OD280/OD315 of diluted wines: 1.27 4.00 2.61 0.71\n", - " Proline: 278 1680 746 315\n", - " ============================= ==== ===== ======= =====\n", - "\n", - " :Missing Attribute Values: None\n", - " :Class Distribution: class_0 (59), class_1 (71), class_2 (48)\n", - " :Creator: R.A. Fisher\n", - " :Donor: Michael Marshall (MARSHALL%PLU@io.arc.nasa.gov)\n", - " :Date: July, 1988\n", - "\n", - "This is a copy of UCI ML Wine recognition datasets.\n", - "https://archive.ics.uci.edu/ml/machine-learning-databases/wine/wine.data\n", - "\n", - "The data is the results of a chemical analysis of wines grown in the same\n", - "region in Italy by three different cultivators. There are thirteen different\n", - "measurements taken for different constituents found in the three types of\n", - "wine.\n", - "\n", - "Original Owners: \n", - "\n", - "Forina, M. et al, PARVUS - \n", - "An Extendible Package for Data Exploration, Classification and Correlation. \n", - "Institute of Pharmaceutical and Food Analysis and Technologies,\n", - "Via Brigata Salerno, 16147 Genoa, Italy.\n", - "\n", - "Citation:\n", - "\n", - "Lichman, M. (2013). UCI Machine Learning Repository\n", - "[https://archive.ics.uci.edu/ml]. Irvine, CA: University of California,\n", - "School of Information and Computer Science. \n", - "\n", - ".. topic:: References\n", - "\n", - " (1) S. Aeberhard, D. Coomans and O. de Vel, \n", - " Comparison of Classifiers in High Dimensional Settings, \n", - " Tech. Rep. no. 92-02, (1992), Dept. of Computer Science and Dept. of \n", - " Mathematics and Statistics, James Cook University of North Queensland. \n", - " (Also submitted to Technometrics). \n", - "\n", - " The data was used with many others for comparing various \n", - " classifiers. The classes are separable, though only RDA \n", - " has achieved 100% correct classification. \n", - " (RDA : 100%, QDA 99.4%, LDA 98.9%, 1NN 96.1% (z-transformed data)) \n", - " (All results using the leave-one-out technique) \n", - "\n", - " (2) S. Aeberhard, D. Coomans and O. de Vel, \n", - " \"THE CLASSIFICATION PERFORMANCE OF RDA\" \n", - " Tech. Rep. no. 92-01, (1992), Dept. of Computer Science and Dept. of \n", - " Mathematics and Statistics, James Cook University of North Queensland. \n", - " (Also submitted to Journal of Chemometrics).\n", - "\n" - ] - } - ], - "source": [ - "# Scikit-learn's wine dataset\n", - "from sklearn.datasets import load_wine\n", - "\n", - "wine = load_wine()\n", - "print(wine[\"DESCR\"])" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "wine_t and wine_u are generated from the wine dataset, where wine_t is the entire dataset while wine_u is a sample (50%) of the entire dataset. \n", - "wine_t shape is 178 and wine_u shape is 89 \n", - "\n", - "\n" - ] - }, - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
alcoholmalic_acidashalcalinity_of_ashmagnesiumtotal_phenolsflavanoidsnonflavanoid_phenolsproanthocyaninscolor_intensityhueod280/od315_of_diluted_winesprolineyprediction
014.231.712.4315.6127.02.803.060.282.295.641.043.921065.000
113.201.782.1411.2100.02.652.760.261.284.381.053.401050.000
213.162.362.6718.6101.02.803.240.302.815.681.033.171185.000
314.371.952.5016.8113.03.853.490.242.187.800.863.451480.000
413.242.592.8721.0118.02.802.690.391.824.321.042.93735.000
\n", - "
" - ], - "text/plain": [ - " alcohol malic_acid ash alcalinity_of_ash magnesium total_phenols \\\n", - "0 14.23 1.71 2.43 15.6 127.0 2.80 \n", - "1 13.20 1.78 2.14 11.2 100.0 2.65 \n", - "2 13.16 2.36 2.67 18.6 101.0 2.80 \n", - "3 14.37 1.95 2.50 16.8 113.0 3.85 \n", - "4 13.24 2.59 2.87 21.0 118.0 2.80 \n", - "\n", - " flavanoids nonflavanoid_phenols proanthocyanins color_intensity hue \\\n", - "0 3.06 0.28 2.29 5.64 1.04 \n", - "1 2.76 0.26 1.28 4.38 1.05 \n", - "2 3.24 0.30 2.81 5.68 1.03 \n", - "3 3.49 0.24 2.18 7.80 0.86 \n", - "4 2.69 0.39 1.82 4.32 1.04 \n", - "\n", - " od280/od315_of_diluted_wines proline y prediction \n", - "0 3.92 1065.0 0 0 \n", - "1 3.40 1050.0 0 0 \n", - "2 3.17 1185.0 0 0 \n", - "3 3.45 1480.0 0 0 \n", - "4 2.93 735.0 0 0 " - ] - }, - "execution_count": 24, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "wine_t_path = 'https://s3.wasabisys.com/iguazio/data/function-marketplace-data/virtual_drift/wine_t.pq'\n", - "wine_u_path = 'https://s3.wasabisys.com/iguazio/data/function-marketplace-data/virtual_drift/wine_u.pq'\n", - "wine_t=pd.read_parquet(wine_t_path)\n", - "wine_u=pd.read_parquet(wine_u_path)\n", - "print(f'wine_t and wine_u are generated from the wine dataset, where wine_t is the entire dataset while wine_u is a sample (50%) of the entire dataset. \\n\\\n", - "wine_t shape is {wine_t.shape[0]} and wine_u shape is {wine_u.shape[0]} \\n\\n')\n", - "wine_t.head()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### **Importing the function**" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "> 2021-10-26 13:45:22,345 [info] created and saved project function-marketplace\n" - ] - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 25, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import mlrun\n", - "\n", - "# Importing the function\n", - "mlrun.set_environment(project='function-marketplace')\n", - "\n", - "fn = mlrun.import_function(\"hub://virtual_drift\")\n", - "fn.apply(mlrun.auto_mount())" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### **Running the function locally**" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "metadata": {}, - "outputs": [], - "source": [ - "import os \n", - "\n", - "container = os.path.join('/',os.environ['V3IO_HOME'].split('/')[0])\n", - "user = os.environ[\"V3IO_USERNAME\"]\n", - "rel_path = os.getcwd()[6:] + '/artifacts'\n", - "tsdb_path = os.path.join(user,rel_path) + \"/output_tsdb\"" - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "> 2021-10-26 14:00:41,020 [info] starting run virtual-drift-drift_magnitude uid=28ec7f08ce7c4c528114e2590ff49325 DB=http://mlrun-api:8080\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Warning - Server version '0.8.14' is different from client version '0.9.4'. Some operations may not work as expected.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "> 2021-10-26 14:00:43,469 [info] Fitting discretizer for alcohol\n", - "> 2021-10-26 14:00:43,471 [info] Fitting discretizer for malic_acid\n", - "> 2021-10-26 14:00:43,471 [info] Fitting discretizer for ash\n", - "> 2021-10-26 14:00:43,472 [info] Fitting discretizer for alcalinity_of_ash\n", - "> 2021-10-26 14:00:43,473 [info] Fitting discretizer for magnesium\n", - "> 2021-10-26 14:00:43,474 [info] Fitting discretizer for total_phenols\n", - "> 2021-10-26 14:00:43,475 [info] Fitting discretizer for flavanoids\n", - "> 2021-10-26 14:00:43,476 [info] Fitting discretizer for nonflavanoid_phenols\n", - "> 2021-10-26 14:00:43,477 [info] Fitting discretizer for proanthocyanins\n", - "> 2021-10-26 14:00:43,477 [info] Fitting discretizer for color_intensity\n", - "> 2021-10-26 14:00:43,478 [info] Fitting discretizer for hue\n", - "> 2021-10-26 14:00:43,479 [info] Fitting discretizer for od280/od315_of_diluted_wines\n", - "> 2021-10-26 14:00:43,480 [info] Fitting discretizer for proline\n", - "> 2021-10-26 14:00:43,531 [info] Discretizing featuers\n", - "> 2021-10-26 14:00:43,752 [info] Compute prior metrics\n", - "> 2021-10-26 14:00:43,889 [info] Compute class metrics\n", - "> 2021-10-26 14:00:44,000 [info] value: inf\n", - "> 2021-10-26 14:00:44,009 [info] Timestamp: 2021-10-26 14:00:44.008992\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "divide by zero encountered in log\n", - "casting datetime64[ns] values to int64 with .astype(...) is deprecated and will raise in a future version. Use .view(...) instead.\n" - ] - }, - { - "data": { - "text/html": [ - "\n", - "
\n", - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
projectuiditerstartstatenamelabelsinputsparametersresultsartifacts
function-marketplace0Oct 26 14:00:41completedvirtual-drift-drift_magnitude
v3io_user=dani
kind=
owner=dani
host=jupyter-dani-6bfbd76d96-zxx6f
t
u
label_col=y
results_tsdb_container=users
results_tsdb_table=dani/test/functions/virtual_drift/artifacts/output_tsdb
prior_tvd=0.5
prior_helinger=0.541
prior_kld=10
class_shift_tvd=0.017
class_shift_helinger=0.014
class_shift_kld=0.002
discritizers
t_discrete
u_discrete
features_t_pdf
features_u_pdf
class_t_pdf
class_u_pdf
\n", - "
\n", - "
\n", - "
\n", - " Title\n", - " ×\n", - "
\n", - " \n", - "
\n", - "
\n" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n" - ] - }, - { - "data": { - "text/html": [ - " > to track results use the .show() or .logs() methods or
click here to open in UI" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "> 2021-10-26 14:00:44,153 [info] run executed, status=completed\n" - ] - } - ], - "source": [ - "virtual_drift_run=fn.run(params={'label_col': 'y',\n", - " 'results_tsdb_container': container[1:],\n", - " 'results_tsdb_table': tsdb_path},\n", - " inputs={'t': wine_t_path,\n", - " 'u': wine_u_path},\n", - " artifact_path=os.getcwd(),\n", - " local=True)" - ] - }, - { - "cell_type": "code", - "execution_count": 38, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
u
00.348315
10.382022
20.269663
\n", - "
" - ], - "text/plain": [ - " u\n", - "0 0.348315\n", - "1 0.382022\n", - "2 0.269663" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
t
00.331461
10.398876
20.269663
\n", - "
" - ], - "text/plain": [ - " t\n", - "0 0.331461\n", - "1 0.398876\n", - "2 0.269663" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "virtual_drift_run.artifact('class_u_pdf').show()\n", - "virtual_drift_run.artifact('class_t_pdf').show()" - ] - }, - { - "cell_type": "code", - "execution_count": 69, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Warning - Server version '0.8.14' is different from client version '0.9.4'. Some operations may not work as expected.\n" - ] - }, - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
class_shift_helingerclass_shift_kldclass_shift_tvdprior_helingerprior_kldprior_tvdstream
time
2021-10-26 13:58:04.445000+00:000.013980.0015640.0168540.54119610.00.5some_stream
2021-10-26 14:00:44.008000+00:000.013980.0015640.0168540.54119610.00.5some_stream
\n", - "
" - ], - "text/plain": [ - " class_shift_helinger class_shift_kld \\\n", - "time \n", - "2021-10-26 13:58:04.445000+00:00 0.01398 0.001564 \n", - "2021-10-26 14:00:44.008000+00:00 0.01398 0.001564 \n", - "\n", - " class_shift_tvd prior_helinger prior_kld \\\n", - "time \n", - "2021-10-26 13:58:04.445000+00:00 0.016854 0.541196 10.0 \n", - "2021-10-26 14:00:44.008000+00:00 0.016854 0.541196 10.0 \n", - "\n", - " prior_tvd stream \n", - "time \n", - "2021-10-26 13:58:04.445000+00:00 0.5 some_stream \n", - "2021-10-26 14:00:44.008000+00:00 0.5 some_stream " - ] - }, - "execution_count": 69, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import v3io_frames as v3f\n", - "client = v3f.Client(os.environ[\"V3IO_FRAMESD\"],container=container[1:])\n", - "client.read(backend='tsdb',table=tsdb_path)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "[Back to the top](#Virtual-Drift)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "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.7.6" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/virtual_drift/virtual_drift.py b/virtual_drift/virtual_drift.py deleted file mode 100644 index 71dcf7129..000000000 --- a/virtual_drift/virtual_drift.py +++ /dev/null @@ -1,206 +0,0 @@ -# Copyright 2019 Iguazio -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# Generated by nuclio.export.NuclioExporter - -import os -import pandas as pd -import numpy as np -import scipy as sp -import pickle -import datetime - -import v3io_frames as v3f - -import matplotlib.pyplot as plt -from sklearn.preprocessing import KBinsDiscretizer - - -def to_observations(context, t, u, key): - t = ( - t.apply(lambda row: f"{'_'.join([str(row[val]) for val in t.columns])}", axis=1) - .value_counts() - .sort_index() - ) - u = ( - u.apply(lambda row: f"{'_'.join([str(row[val]) for val in u.columns])}", axis=1) - .value_counts() - .sort_index() - ) - - joined_uniques = pd.DataFrame([t, u]).T.fillna(0).sort_index() - joined_uniques.columns = ["t", "u"] - - t_obs = joined_uniques.loc[:, "t"] - u_obs = joined_uniques.loc[:, "u"] - - t_pdf = t_obs / t_obs.sum() - u_pdf = u_obs / u_obs.sum() - - context.log_dataset(f"{key}_t_pdf", pd.DataFrame(t_pdf), format="parquet") - context.log_dataset(f"{key}_u_pdf", pd.DataFrame(u_pdf), format="parquet") - return t_pdf, u_pdf - - -def tvd(t, u): - return sum(abs(t - u)) / 2 - - -def helinger(t, u): - return (np.sqrt(np.sum(np.power(np.sqrt(t) - np.sqrt(u), 2)))) / np.sqrt(2) - - -def kl_divergence(t, u): - t_u = np.sum(np.where(t != 0, t * np.log(t / u), 0)) - u_t = np.sum(np.where(u != 0, u * np.log(u / t), 0)) - return t_u + u_t - - -def all_metrics(t, u): - return tvd(t, u), helinger(t, u), kl_divergence(t, u) - - -def drift_magnitude( - context, - t: pd.DataFrame, - u: pd.DataFrame, - label_col=None, - prediction_col=None, - discretizers: dict = None, - n_bins=5, - stream_name: str = "some_stream", - results_tsdb_container: str = "bigdata", - results_tsdb_table: str = "concept_drift/drift_magnitude", -): - """Drift magnitude metrics - Computes drift magnitude metrics between base dataset t and dataset u. - Metrics: - - TVD (Total Variation Distance) - - Helinger - - KL Divergence - - :param context: MLRun context - :param t: Base dataset for the drift metrics - :param u: Test dataset for the drift metrics - :param label_col: Label colum in t and u - :param prediction_col: Predictions column in t and u - :param discritizers: Dictionary of dicsritizers for the features if available - (Created automatically if not provided) - :param n_bins: Number of bins to be used for histrogram creation from continuous variables - :param stream_name: Output stream to push metrics to - :param results_tsdb_container: TSDB table container to push metrics to - :param results_tsdb_table: TSDB table to push metrics to - """ - - v3io_client = v3f.Client("framesd:8081", container=results_tsdb_container) - try: - v3io_client.create("tsdb", results_tsdb_table, if_exists=1, rate="1/s") - except: - v3io_client.create( - "tsdb", results_tsdb_table, if_exists=1, attrs={"rate": "1/s"} - ) - - df_t = t.as_df() - df_u = u.as_df() - - drop_columns = [] - if label_col is not None: - drop_columns.append(label_col) - if prediction_col is not None: - drop_columns.append(prediction_col) - - continuous_features = df_t.select_dtypes(["float"]) - if discretizers is None: - discretizers = {} - for feature in continuous_features.columns: - context.logger.info(f"Fitting discretizer for {feature}") - discretizer = KBinsDiscretizer( - n_bins=n_bins, encode="ordinal", strategy="uniform" - ) - - discretizer.fit(continuous_features.loc[:, feature].values.reshape(-1, 1)) - discretizers[feature] = discretizer - os.makedirs(context.artifact_path, exist_ok=True) - discretizers_path = os.path.abspath(f"{context.artifact_path}/discritizer.pkl") - with open(discretizers_path, "wb") as f: - pickle.dump(discretizers, f) - context.log_artifact("discritizers", target_path=discretizers_path) - context.logger.info("Discretizing featuers") - for feature, discretizer in discretizers.items(): - df_t[feature] = discretizer.transform( - df_t.loc[:, feature].values.reshape(-1, 1) - ) - df_u[feature] = discretizer.transform( - df_u.loc[:, feature].values.reshape(-1, 1) - ) - df_t[feature] = df_t[feature].astype("int") - df_u[feature] = df_u[feature].astype("int") - context.log_dataset("t_discrete", df_t, format="parquet") - context.log_dataset("u_discrete", df_u, format="parquet") - - context.logger.info("Compute prior metrics") - - results = {} - t_prior, u_prior = to_observations( - context, - df_t.drop(drop_columns, axis=1), - df_u.drop(drop_columns, axis=1), - "features", - ) - results["prior_tvd"], results["prior_helinger"], results["prior_kld"] = all_metrics( - t_prior, u_prior - ) - - if prediction_col is not None: - context.logger.info("Compute prediction metrics") - t_predictions = pd.DataFrame(df_t.loc[:, prediction_col]) - u_predictions = pd.DataFrame(df_u.loc[:, prediction_col]) - t_class, u_class = to_observations( - context, t_predictions, u_predictions, "prediction" - ) - ( - results["prediction_shift_tvd"], - results["prediction_shift_helinger"], - results["prediction_shift_kld"], - ) = all_metrics(t_class, u_class) - - if label_col is not None: - context.logger.info("Compute class metrics") - t_labels = pd.DataFrame(df_t.loc[:, label_col]) - u_labels = pd.DataFrame(df_u.loc[:, label_col]) - t_class, u_class = to_observations(context, t_labels, u_labels, "class") - ( - results["class_shift_tvd"], - results["class_shift_helinger"], - results["class_shift_kld"], - ) = all_metrics(t_class, u_class) - - for key, value in results.items(): - if value == float("inf"): - context.logger.info(f"value: {value}") - results[key] = 10 - for key, result in results.items(): - context.log_result(key, round(result, 3)) - - now = pd.to_datetime(str(datetime.datetime.now())) - now - - results["timestamp"] = pd.to_datetime(str((datetime.datetime.now()))) - context.logger.info(f"Timestamp: {results['timestamp']}") - results["stream"] = stream_name - results_df = pd.DataFrame( - data=[list(results.values())], columns=list(results.keys()) - ) - results_df = results_df.set_index(["timestamp", "stream"]) - v3io_client.write("tsdb", results_tsdb_table, dfs=results_df) diff --git a/xgb_custom/function.yaml b/xgb_custom/function.yaml deleted file mode 100644 index 7c264c392..000000000 --- a/xgb_custom/function.yaml +++ /dev/null @@ -1,241 +0,0 @@ -kind: job -metadata: - name: xgb-custom - tag: '' - hash: 5a052481ac303bde0afeccef9d2c5257abc4b00e - project: '' - labels: - author: Daniel - categories: - - model-training - - machine-learning - - data-preparation -spec: - command: '' - args: [] - image: mlrun/mlrun - env: [] - default_handler: gen_outliers - entry_points: - gen_outliers: - name: gen_outliers - doc: simulate data with outliers - parameters: - - name: context - type: MLClientCtx - doc: the function's execution context - default: '' - - name: nrows - doc: (4096) number of data points - default: 4096 - - name: feats - doc: (16) number of features - default: 16 - - name: outs - doc: (64) number of outliers - default: 64 - - name: omax - doc: (10_100) max value of outliers - default: 10000 - - name: labels_col - doc: (labels) name of labels column - default: labels - - name: header - doc: () header for dataset, will default to `feat_` - default: [] - - name: label_type - doc: (int32) data type for the label column - default: int32 - - name: key - doc: key of datset in artifact store - default: xgb-outs - - name: local_path - doc: path in artifact store where data will be serialized - default: xgb_custom - outputs: - - default: '' - lineno: 22 - gradient: - name: gradient - doc: gradient of squared log error - parameters: - - name: predt - type: ndarray - default: '' - - name: dtrain - type: DMatrix - default: '' - outputs: - - default: '' - lineno: 59 - hessian: - name: hessian - doc: hessian of squared log error - parameters: - - name: predt - type: ndarray - default: '' - - name: dtrain - type: DMatrix - default: '' - outputs: - - default: '' - lineno: 65 - squared_log: - name: squared_log - doc: 'squared log error objective - - - simplified version for RMSLE used as objective function' - parameters: - - name: predt - type: ndarray - default: '' - - name: dtrain - type: DMatrix - default: '' - outputs: - - default: '' - lineno: 72 - rmsle: - name: rmsle - doc: Root mean squared log error metric. - parameters: - - name: predt - type: ndarray - default: '' - - name: dtrain - type: DMatrix - default: '' - outputs: - - default: '' - lineno: 83 - learning_curves: - name: learning_curves - doc: 'plot xgb learning curves - - - this will also log a model''s learning curves' - parameters: - - name: context - type: MLClientCtx - default: '' - - name: results - type: dict - default: '' - - name: figsz - type: Tuple[int, int] - default: - - 10 - - 10 - - name: plots_dest - type: str - default: plots - outputs: - - default: '' - lineno: 92 - fit: - name: fit - doc: "low level xgboost train api\n\nfor the xgboost `train` params see:\nhttps://xgboost.readthedocs.io/en/latest/python/python_api.html#xgboost.train\n\ - \nNote: the first parameter of xgboost's `train` method is a dict of parameters\n\ - \ supplied to the booster (engine). To modify one of those simply\n\ - \ add a task parameter (when running you supply an mlrun NewTask) with\ - \ the\n prefix \"XGB_\". So for example, to set the 'tree_method' parameter\ - \ to 'approx',\n add {\"XGB_tree_method\":\"approx\"} to the task params\ - \ key." - parameters: - - name: context - type: MLClientCtx - doc: the function context - default: '' - - name: dataset - type: DataItem - doc: the full data set, train, valid and test will be extracted and each converted - to a DMatrix for input to xgboost's `train` - default: '' - - name: num_boost_round - type: int - default: 10 - - name: evals - type: List[Tuple[DMatrix, str]] - default: [] - - name: obj - type: Union[Callable, str] - default: '' - - name: feval - type: Union[Callable, str] - default: null - - name: maximize - type: bool - default: false - - name: early_stopping_rounds - type: int - default: null - - name: evals_result - type: dict - default: {} - - name: verbose_eval - type: bool - default: true - - name: xgb_model - type: DataItem - default: null - - name: callbacks - type: List[Callable] - default: [] - - name: label_column - type: str - doc: ground-truth (y) labels - default: labels - - name: encode_cols - type: dict - doc: dictionary of names and prefixes for columns that are to hot be encoded. - default: {} - - name: sample - type: int - doc: Selects the first n rows, or select a sample starting from the first. - If negative <-1, select a random sample - default: <_ast.USub object at 0x7ff7bf99a7b8> - - name: test_size - type: float - doc: (0.05) test set size - default: 0.25 - - name: valid_size - type: float - doc: (0.75) Once the test set has been removed the training set gets this - proportion. - default: 0.75 - - name: random_state - type: int - doc: (1) sklearn rng seed - default: 1994 - - name: models_dest - type: str - doc: destination subfolder for model artifacts - default: models - - name: plots_dest - type: str - doc: destination subfolder for plot artifacts - default: plots - - name: file_ext - type: str - doc: format for test_set_key hold out data - default: csv - - name: test_set_key - type: str - doc: (test-set), key of held out data in artifact store - default: test-set - - name: gpus - type: bool - doc: (False), run on gpus - default: false - outputs: - - default: '' - lineno: 114 - description: simulate data with outliers. - build: - functionSourceCode: ZnJvbSBvcyBpbXBvcnQgcGF0aAppbXBvcnQgbnVtcHkgYXMgbnAKZnJvbSBudW1weS5yYW5kb20gaW1wb3J0IHJhbmRpbnQsIHJhbmRuLCBzZWVkCmltcG9ydCBwYW5kYXMgYXMgcGQKZnJvbSB4Z2Jvb3N0IGltcG9ydCBETWF0cml4LCB0cmFpbgppbXBvcnQgbWF0cGxvdGxpYi5weXBsb3QgYXMgcGx0CmZyb20gbWxydW4uZXhlY3V0aW9uIGltcG9ydCBNTENsaWVudEN0eApmcm9tIG1scnVuLmRhdGFzdG9yZSBpbXBvcnQgRGF0YUl0ZW0KZnJvbSBtbHJ1bi5hcnRpZmFjdHMgaW1wb3J0IFBsb3RBcnRpZmFjdApmcm9tIG1scnVuLm1sdXRpbHMuZGF0YSBpbXBvcnQgZ2V0X3NwbGl0cywgZ2V0X3NhbXBsZQoKZnJvbSBjbG91ZHBpY2tsZSBpbXBvcnQgZHVtcHMKCmZyb20gdHlwaW5nIGltcG9ydCAoVHVwbGUsIERpY3QsIExpc3QsIFVuaW9uLCBDYWxsYWJsZSkKCnNlZWQoc2VlZD0xOTk0KQoKIyMgVU5DT01NRU5UIFRISVMgTElORSBUTyBURVNUIENBTENVTEFURUQgVkFMVUVTCkRFQlVHX0VSUk9SID0gMCAjIHRoaXMgd2lsbCBiZSBhZGRlZCB0byB0aGUgY3VzdG9tIGV2YWwgZnVuY3Rpb24tLXNldCBpdCB0byBzb21lIHZhbHVlIGxpa2UgOTk5CgoKZGVmIGdlbl9vdXRsaWVycyhjb250ZXh0OiBNTENsaWVudEN0eCwgbnJvd3M9NDA5NiwgZmVhdHM9MTYsCiAgICAgICAgICAgICAgICAgb3V0cz02NCwgb21heD0xMF8wMDAsIGxhYmVsc19jb2w9ImxhYmVscyIsCiAgICAgICAgICAgICAgICAgaGVhZGVyPVtdLCBsYWJlbF90eXBlPSJpbnQzMiIsIGtleT0ieGdiLW91dHMiLAogICAgICAgICAgICAgICAgIGxvY2FsX3BhdGg9InhnYl9jdXN0b20iKToKICAgICIiInNpbXVsYXRlIGRhdGEgd2l0aCBvdXRsaWVycwoKICAgIDpwYXJhbSBjb250ZXh0OiAgICB0aGUgZnVuY3Rpb24ncyBleGVjdXRpb24gY29udGV4dAogICAgOnBhcmFtIG5yb3dzOiAgICAgICg0MDk2KSBudW1iZXIgb2YgZGF0YSBwb2ludHMKICAgIDpwYXJhbSBmZWF0czogICAgICAoMTYpIG51bWJlciBvZiBmZWF0dXJlcwogICAgOnBhcmFtIG91dHM6ICAgICAgICg2NCkgbnVtYmVyIG9mIG91dGxpZXJzCiAgICA6cGFyYW0gb21heDogICAgICAgKDEwXzEwMCkgbWF4IHZhbHVlIG9mIG91dGxpZXJzCiAgICA6cGFyYW0gbGFiZWxzX2NvbDogKGxhYmVscykgbmFtZSBvZiBsYWJlbHMgY29sdW1uCiAgICA6cGFyYW0gaGVhZGVyOiAgICAgKCkgaGVhZGVyIGZvciBkYXRhc2V0LCB3aWxsIGRlZmF1bHQgdG8KICAgICAgICAgICAgICAgICAgICAgICBgZmVhdF9gCiAgICA6cGFyYW0gbGFiZWxfdHlwZTogKGludDMyKSBkYXRhIHR5cGUgZm9yIHRoZSBsYWJlbCBjb2x1bW4KICAgIDpwYXJhbSBrZXk6ICAgICAgICBrZXkgb2YgZGF0c2V0IGluIGFydGlmYWN0IHN0b3JlCiAgICA6cGFyYW0gbG9jYWxfcGF0aDogcGF0aCBpbiBhcnRpZmFjdCBzdG9yZSB3aGVyZSBkYXRhIHdpbGwgYmUKICAgICAgICAgICAgICAgICAgICAgICBzZXJpYWxpemVkCiAgICAiIiIKICAgIHggPSByYW5kbihucm93cywgZmVhdHMpCiAgICB5ID0gcmFuZG4obnJvd3MpCiAgICB5ICs9IG5wLmFicyhucC5taW4oeSkpCgogICAgZm9yIGkgaW4gcmFuZ2UoMCwgb3V0cyk6CiAgICAgICAgaW5kID0gcmFuZGludCgwLCBsZW4oeSkgLSAxKQogICAgICAgIHlbaW5kXSArPSByYW5kaW50KDAsIG9tYXgpCgogICAgaWYgbm90IGhlYWRlcjoKICAgICAgICBoZWFkZXIgPSBbZiJmZWF0X3tqfSIgZm9yIGogaW4gcmFuZ2UoZmVhdHMpXQogICAgICAgIGhlYWRlci5hcHBlbmQobGFiZWxzX2NvbCkKCiAgICBkYXRhID0gcGQuRGF0YUZyYW1lKGRhdGE9bnAuY29uY2F0ZW5hdGUoKHgsIHkucmVzaGFwZSgtMSwgMSkpLCBheGlzPS0xKSwKICAgICAgICAgICAgICAgICAgICAgICAgY29sdW1ucz1oZWFkZXIpCiAgICBkYXRhID0gZGF0YS5hc3R5cGUoe2xhYmVsc19jb2w6IGxhYmVsX3R5cGV9KQoKICAgIGNvbnRleHQubG9nX2RhdGFzZXQoa2V5LCBkZj1kYXRhLCBsb2NhbF9wYXRoPWxvY2FsX3BhdGgpCgpkZWYgZ3JhZGllbnQocHJlZHQ6IG5wLm5kYXJyYXksIGR0cmFpbjogRE1hdHJpeCkgLT4gbnAubmRhcnJheToKICAgICIiImdyYWRpZW50IG9mIHNxdWFyZWQgbG9nIGVycm9yIiIiCiAgICB5ID0gZHRyYWluLmdldF9sYWJlbCgpCiAgICByZXR1cm4gKG5wLmxvZzFwKHByZWR0KSAtIG5wLmxvZzFwKHkpKSAvIChwcmVkdCArIDEpCgoKZGVmIGhlc3NpYW4ocHJlZHQ6IG5wLm5kYXJyYXksIGR0cmFpbjogRE1hdHJpeCkgLT4gbnAubmRhcnJheToKICAgICIiImhlc3NpYW4gb2Ygc3F1YXJlZCBsb2cgZXJyb3IiIiIKICAgIHkgPSBkdHJhaW4uZ2V0X2xhYmVsKCkKICAgIHJldHVybiAoKC1ucC5sb2cxcChwcmVkdCkgKyBucC5sb2cxcCh5KSArIDEpIC8KICAgICAgICAgICAgbnAucG93ZXIocHJlZHQgKyAxLCAyKSkKCgpkZWYgc3F1YXJlZF9sb2cocHJlZHQ6IG5wLm5kYXJyYXksIGR0cmFpbjogRE1hdHJpeCkgLT4gVHVwbGVbbnAubmRhcnJheSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5wLm5kYXJyYXldOgogICAgIiIic3F1YXJlZCBsb2cgZXJyb3Igb2JqZWN0aXZlCgogICAgc2ltcGxpZmllZCB2ZXJzaW9uIGZvciBSTVNMRSB1c2VkIGFzIG9iamVjdGl2ZSBmdW5jdGlvbgogICAgIiIiCiAgICBwcmVkdFtwcmVkdCA8IC0xXSA9IC0xICsgMWUtNgogICAgZ3JhZCA9IGdyYWRpZW50KHByZWR0LCBkdHJhaW4pCiAgICBoZXNzID0gaGVzc2lhbihwcmVkdCwgZHRyYWluKQogICAgcmV0dXJuIGdyYWQsIGhlc3MKCmRlZiBybXNsZShwcmVkdDogbnAubmRhcnJheSwgZHRyYWluOiBETWF0cml4KSAtPiBUdXBsZVtzdHIsIGZsb2F0XToKICAgICIiIiBSb290IG1lYW4gc3F1YXJlZCBsb2cgZXJyb3IgbWV0cmljLgogICAgIiIiCiAgICB5ID0gZHRyYWluLmdldF9sYWJlbCgpCiAgICBwcmVkdFtwcmVkdCA8IC0xXSA9IC0xICsgMWUtNgogICAgZWxlbWVudHMgPSBucC5wb3dlcihucC5sb2cxcCh5KSAtIG5wLmxvZzFwKHByZWR0KSwgMikKICAgIHJldHVybiAibXlfcm1zbGUiLCBmbG9hdChucC5zcXJ0KG5wLnN1bShlbGVtZW50cykgLyBsZW4oeSkpKSArIERFQlVHX0VSUk9SCgoKZGVmIGxlYXJuaW5nX2N1cnZlcygKICAgICAgICBjb250ZXh0OiBNTENsaWVudEN0eCwKICAgICAgICByZXN1bHRzOiBkaWN0LAogICAgICAgIGZpZ3N6OiBUdXBsZVtpbnQsIGludF0gPSAoMTAsIDEwKSwKICAgICAgICBwbG90c19kZXN0OiBzdHIgPSAicGxvdHMiCikgLT4gTm9uZToKICAgICIiInBsb3QgeGdiIGxlYXJuaW5nIGN1cnZlcwoKICAgIHRoaXMgd2lsbCBhbHNvIGxvZyBhIG1vZGVsJ3MgbGVhcm5pbmcgY3VydmVzCiAgICAiIiIKICAgIHBsdC5jbGYoKQogICAgcGx0LmZpZ3VyZShmaWdzaXplPWZpZ3N6KQogICAgcGx0LnBsb3QocmVzdWx0c1sidHJhaW4iXVsibXlfcm1zbGUiXSwgbGFiZWw9InRyYWluLW15LXJtc2xlIikKICAgIHBsdC5wbG90KHJlc3VsdHNbInZhbGlkIl1bIm15X3Jtc2xlIl0sIGxhYmVsPSJ2YWxpZC1teS1ybXNsZSIpCiAgICBwbHQudGl0bGUoZiJsZWFybmluZyBjdXJ2ZXMiKQogICAgcGx0LmxlZ2VuZCgpCgogICAgY29udGV4dC5sb2dfYXJ0aWZhY3QoCiAgICAgICAgUGxvdEFydGlmYWN0KGYibGVhcm5pbmctY3VydmVzIiwgYm9keT1wbHQuZ2NmKCkpLAogICAgICAgIGxvY2FsX3BhdGg9ZiJ7cGxvdHNfZGVzdH0vbGVhcm5pbmctY3VydmVzLmh0bWwiKQoKCmRlZiBmaXQoCiAgICAgICAgY29udGV4dDogTUxDbGllbnRDdHgsCiAgICAgICAgZGF0YXNldDogRGF0YUl0ZW0sCiAgICAgICAgbnVtX2Jvb3N0X3JvdW5kOiBpbnQgPSAxMCwKICAgICAgICBldmFsczogTGlzdFtUdXBsZVtETWF0cml4LCBzdHJdXSA9IFtdLAogICAgICAgIG9iajogVW5pb25bQ2FsbGFibGUsIHN0cl0gPSAiIiwKICAgICAgICBmZXZhbDogVW5pb25bQ2FsbGFibGUsIHN0cl0gPSBOb25lLAogICAgICAgIG1heGltaXplOiBib29sID0gRmFsc2UsCiAgICAgICAgZWFybHlfc3RvcHBpbmdfcm91bmRzOiBpbnQgPSBOb25lLAogICAgICAgIGV2YWxzX3Jlc3VsdDogZGljdCA9IHt9LAogICAgICAgIHZlcmJvc2VfZXZhbDogYm9vbCA9IFRydWUsCiAgICAgICAgeGdiX21vZGVsOiBEYXRhSXRlbSA9IE5vbmUsCiAgICAgICAgY2FsbGJhY2tzOiBMaXN0W0NhbGxhYmxlXSA9IFtdLAogICAgICAgIGxhYmVsX2NvbHVtbjogc3RyID0gImxhYmVscyIsCiAgICAgICAgZW5jb2RlX2NvbHM6IGRpY3QgPSB7fSwKICAgICAgICBzYW1wbGU6IGludCA9IC0xLAogICAgICAgIHRlc3Rfc2l6ZTogZmxvYXQgPSAwLjI1LAogICAgICAgIHZhbGlkX3NpemU6IGZsb2F0ID0gMC43NSwKICAgICAgICByYW5kb21fc3RhdGU6IGludCA9IDE5OTQsCiAgICAgICAgbW9kZWxzX2Rlc3Q6IHN0ciA9ICJtb2RlbHMiLAogICAgICAgIHBsb3RzX2Rlc3Q6IHN0ciA9ICJwbG90cyIsCiAgICAgICAgZmlsZV9leHQ6IHN0ciA9ICJjc3YiLAogICAgICAgIHRlc3Rfc2V0X2tleTogc3RyID0gInRlc3Qtc2V0IiwKICAgICAgICBncHVzOiBib29sID0gRmFsc2UKKSAtPiBOb25lOgogICAgIiIibG93IGxldmVsIHhnYm9vc3QgdHJhaW4gYXBpCgogICAgZm9yIHRoZSB4Z2Jvb3N0IGB0cmFpbmAgcGFyYW1zIHNlZToKICAgIGh0dHBzOi8veGdib29zdC5yZWFkdGhlZG9jcy5pby9lbi9sYXRlc3QvcHl0aG9uL3B5dGhvbl9hcGkuaHRtbCN4Z2Jvb3N0LnRyYWluCgogICAgTm90ZTogIHRoZSBmaXJzdCBwYXJhbWV0ZXIgb2YgeGdib29zdCdzIGB0cmFpbmAgbWV0aG9kIGlzIGEgZGljdCBvZiBwYXJhbWV0ZXJzCiAgICAgICAgICAgc3VwcGxpZWQgdG8gdGhlIGJvb3N0ZXIgKGVuZ2luZSkuICBUbyBtb2RpZnkgb25lIG9mIHRob3NlIHNpbXBseQogICAgICAgICAgIGFkZCBhIHRhc2sgcGFyYW1ldGVyICh3aGVuIHJ1bm5pbmcgeW91IHN1cHBseSBhbiBtbHJ1biBOZXdUYXNrKSB3aXRoIHRoZQogICAgICAgICAgIHByZWZpeCAiWEdCXyIuIFNvIGZvciBleGFtcGxlLCB0byBzZXQgdGhlICd0cmVlX21ldGhvZCcgcGFyYW1ldGVyIHRvICdhcHByb3gnLAogICAgICAgICAgIGFkZCB7IlhHQl90cmVlX21ldGhvZCI6ImFwcHJveCJ9IHRvIHRoZSB0YXNrIHBhcmFtcyBrZXkuCgogICAgOnBhcmFtIGNvbnRleHQ6ICAgICAgICAgICB0aGUgZnVuY3Rpb24gY29udGV4dAogICAgOnBhcmFtIGRhdGFzZXQ6ICAgICAgICAgICB0aGUgZnVsbCBkYXRhIHNldCwgdHJhaW4sIHZhbGlkIGFuZCB0ZXN0IHdpbGwgYmUgZXh0cmFjdGVkIGFuZAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlYWNoIGNvbnZlcnRlZCB0byBhIERNYXRyaXggZm9yIGlucHV0IHRvIHhnYm9vc3QncyBgdHJhaW5gCiAgICA6cGFyYW0gbGFiZWxfY29sdW1uOiAgICAgIGdyb3VuZC10cnV0aCAoeSkgbGFiZWxzCiAgICA6cGFyYW0gZW5jb2RlX2NvbHM6ICAgICAgIGRpY3Rpb25hcnkgb2YgbmFtZXMgYW5kIHByZWZpeGVzIGZvciBjb2x1bW5zIHRoYXQgYXJlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvIGhvdCBiZSBlbmNvZGVkLgogICAgOnBhcmFtIHNhbXBsZTogICAgICAgICAgICBTZWxlY3RzIHRoZSBmaXJzdCBuIHJvd3MsIG9yIHNlbGVjdCBhIHNhbXBsZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGFydGluZyBmcm9tIHRoZSBmaXJzdC4gSWYgbmVnYXRpdmUgPC0xLCBzZWxlY3QKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYSByYW5kb20gc2FtcGxlCiAgICA6cGFyYW0gdGVzdF9zaXplOiAgICAgICAgICgwLjA1KSB0ZXN0IHNldCBzaXplCiAgICA6cGFyYW0gdmFsaWRfc2l6ZTogICAgICAgICgwLjc1KSBPbmNlIHRoZSB0ZXN0IHNldCBoYXMgYmVlbiByZW1vdmVkIHRoZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cmFpbmluZyBzZXQgZ2V0cyB0aGlzIHByb3BvcnRpb24uCiAgICA6cGFyYW0gcmFuZG9tX3N0YXRlOiAgICAgICgxKSBza2xlYXJuIHJuZyBzZWVkCiAgICA6cGFyYW0gbW9kZWxzX2Rlc3Q6ICAgICAgIGRlc3RpbmF0aW9uIHN1YmZvbGRlciBmb3IgbW9kZWwgYXJ0aWZhY3RzCiAgICA6cGFyYW0gcGxvdHNfZGVzdDogICAgICAgIGRlc3RpbmF0aW9uIHN1YmZvbGRlciBmb3IgcGxvdCBhcnRpZmFjdHMKICAgIDpwYXJhbSBmaWxlX2V4dDogICAgICAgICAgZm9ybWF0IGZvciB0ZXN0X3NldF9rZXkgaG9sZCBvdXQgZGF0YQogICAgOnBhcmFtIHRlc3Rfc2V0X2tleTogICAgICAodGVzdC1zZXQpLCBrZXkgb2YgaGVsZCBvdXQgZGF0YSBpbiBhcnRpZmFjdCBzdG9yZQogICAgOnBhcmFtIGdwdXM6ICAgICAgICAgICAgICAoRmFsc2UpLCBydW4gb24gZ3B1cwogICAgIiIiCiAgICByYXcsIGxhYmVscywgaGVhZGVyID0gZ2V0X3NhbXBsZShkYXRhc2V0LCBzYW1wbGUsIGxhYmVsX2NvbHVtbikKCiAgICAjIGhvdC1lbmNvZGUKICAgIGlmIGVuY29kZV9jb2xzOgogICAgICAgIHJhdyA9IHBkLmdldF9kdW1taWVzKHJhdywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2x1bW5zPWxpc3QoZW5jb2RlX2NvbHMua2V5cygpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcmVmaXg9bGlzdChlbmNvZGVfY29scy52YWx1ZXMoKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHJvcF9maXJzdD1UcnVlKQoKICAgICMgc3BsaXQgdGhlIHNhbXBsZSBpbnRvIHRyYWluIHZhbGlkYXRlLCB0ZXN0IGFuZCBjYWxpYnJhdGlvbiBzZXRzOgogICAgKHh0cmFpbiwgeXRyYWluKSwgKHh2YWxpZCwgeXZhbGlkKSwgKHh0ZXN0LCB5dGVzdCkgPSBcCiAgICAgICAgZ2V0X3NwbGl0cyhyYXcsIGxhYmVscywgMywgdGVzdF9zaXplLCB2YWxpZF9zaXplLCByYW5kb21fc3RhdGUpCgogICAgIyBzYXZlIHRlc3QgZGF0YSBhcyByZWd1bGFyIGRhdGFmcmFtZSBhcyBpdCBtYXkgYmUgdXNlZCBieSBvdGhlciBwcm9jZXNzCiAgICBjb250ZXh0LmxvZ19kYXRhc2V0KHRlc3Rfc2V0X2tleSwgZGY9cGQuY29uY2F0KFt4dGVzdCwgeXRlc3RdLCBheGlzPTEpLAogICAgICAgICAgICAgICAgICAgICAgICBmb3JtYXQ9ZmlsZV9leHQsIGluZGV4PUZhbHNlKQoKICAgICMgY29udmVydCB0byB4Z2Jvb3N0IERNYXRyaXggKHRvZG8gLSBkYXNrLCBncHUpCiAgICBkdHJhaW4gPSBETWF0cml4KHh0cmFpbiwgbGFiZWw9eXRyYWluKQogICAgZHZhbGlkID0gRE1hdHJpeCh4dmFsaWQsIGxhYmVsPXl2YWxpZCkKCiAgICBib29zdF9wYXJhbXMgPSB7CiAgICAgICAgInRyZWVfbWV0aG9kIjogImdwdV9oaXN0IiBpZiBncHVzIGVsc2UgImhpc3QiLAogICAgICAgICJzZWVkIjogcmFuZG9tX3N0YXRlLAogICAgICAgICJkaXNhYmxlX2RlZmF1bHRfZXZhbF9tZXRyaWMiOiAxLAogICAgICAgICJvYmplY3RpdmUiOiAicmVnOnNxdWFyZWRsb2dlcnJvciIsCiAgICAgICAgImV2YWxfbWV0cmljIjogInJtc2xlIn0KCiAgICAjIGVuYWJsZSB1c2VyIHRvIGN1c3RvbWl6ZSBgYm9vc3RlciBwYXJhbWAgcGFyYW1ldGVycwogICAgZm9yIGssIHYgaW4gY29udGV4dC5wYXJhbWV0ZXJzLml0ZW1zKCk6CiAgICAgICAgaWYgay5zdGFydHN3aXRoKCdYR0JfJyk6CiAgICAgICAgICAgIGJvb3N0X3BhcmFtc1trWzQ6XV0gPSB2CgogICAgIyBjb2xsZWN0IGxlYXJuaW5nIGN1cnZlcyAvIHRyYWluaW5nIGhpc3RvcnkKICAgIHJlc3VsdHMgPSBkaWN0KCkKCiAgICBib29zdGVyID0gdHJhaW4oCiAgICAgICAgYm9vc3RfcGFyYW1zLAogICAgICAgIGR0cmFpbj1kdHJhaW4sCiAgICAgICAgbnVtX2Jvb3N0X3JvdW5kPW51bV9ib29zdF9yb3VuZCwKICAgICAgICBldmFscz1bKGR0cmFpbiwgInRyYWluIiksIChkdmFsaWQsICJ2YWxpZCIpXSwKICAgICAgICBldmFsc19yZXN1bHQ9cmVzdWx0cywKICAgICAgICBvYmo9c3F1YXJlZF9sb2csCiAgICAgICAgZmV2YWw9cm1zbGUsCiAgICAgICAgbWF4aW1pemU9bWF4aW1pemUsCiAgICAgICAgZWFybHlfc3RvcHBpbmdfcm91bmRzPWVhcmx5X3N0b3BwaW5nX3JvdW5kcywKICAgICAgICB2ZXJib3NlX2V2YWw9dmVyYm9zZV9ldmFsLAogICAgICAgICMgeGdiX21vZGVsPXhnYl9tb2RlbCwKICAgICAgICAjIGNhbGxiYWNrczogTGlzdFtDYWxsYWJsZV0gPSBbXQogICAgKQoKICAgIGNvbnRleHQubG9nX21vZGVsKCJtb2RlbCIsCiAgICAgICAgICAgICAgICAgICAgICBib2R5PWR1bXBzKGJvb3N0ZXIpLAogICAgICAgICAgICAgICAgICAgICAgbW9kZWxfZmlsZT0ibW9kZWwucGtsIiwKICAgICAgICAgICAgICAgICAgICAgIGFydGlmYWN0X3BhdGg9J2FydGlmYWN0cy8nKQoKICAgIGxlYXJuaW5nX2N1cnZlcyhjb250ZXh0LCByZXN1bHRzKQ== - commands: [] - code_origin: https://github.com/daniels290813/functions.git#55a79c32be5d233cc11efcf40cd3edbe309bfdef:/home/kali/functions/xgb_custom/xgb_custom.py - affinity: null -verbose: false diff --git a/xgb_custom/item.yaml b/xgb_custom/item.yaml deleted file mode 100644 index 3decf0708..000000000 --- a/xgb_custom/item.yaml +++ /dev/null @@ -1,26 +0,0 @@ -apiVersion: v1 -categories: -- model-training -- machine-learning -- data-preparation -description: simulate data with outliers. -doc: '' -example: xgb_custom.ipynb -generationDate: 2022-08-28:17-25 -hidden: true -icon: '' -labels: - author: Daniel -maintainers: [] -marketplaceType: '' -mlrunVersion: 1.1.0 -name: xgb_custom -platformVersion: 3.5.0 -spec: - filename: xgb_custom.py - handler: gen_outliers - image: mlrun/mlrun - kind: job - requirements: [] -url: '' -version: 1.1.0 diff --git a/xgb_custom/requirements.txt b/xgb_custom/requirements.txt deleted file mode 100644 index 4441bae23..000000000 --- a/xgb_custom/requirements.txt +++ /dev/null @@ -1,7 +0,0 @@ -pandas -typing -xgboost -matplotlib -scikit-learn -seaborn -scikit-plot \ No newline at end of file diff --git a/xgb_custom/test_xgb_custom.py b/xgb_custom/test_xgb_custom.py deleted file mode 100644 index 81b77a2e0..000000000 --- a/xgb_custom/test_xgb_custom.py +++ /dev/null @@ -1,50 +0,0 @@ -# Copyright 2019 Iguazio -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -from mlrun import import_function -import os - - -ARTIFACT_PATH = "artifacts" -FUNCTION_PATH = "functions" -PLOTS_PATH = "plots" -RUNS_PATH = "runs" -SCHEDULES_PATH = "schedules" - - -def test_local_xgb_custom(): - fn = import_function("function.yaml") - run = fn.run( - params={ - "nrows": 8192, - "label_type": "float", - "local_path": "./artifacts/inputs/xgb_custom", - }, - handler="gen_outliers", - local=True, - ) - - run = fn.run( - params={ - "num_boost_round": 40, - "verbose_eval": False, - "XGB_max_depth": 2, - "XGB_subsample": 0.9, - "test_set_key": "test-set", - }, - inputs={"dataset": run.artifact('xgb-outs').url}, - handler="fit", - local=True, - ) - assert run.artifact('learning-curves').get() diff --git a/xgb_custom/xgb_custom.ipynb b/xgb_custom/xgb_custom.ipynb deleted file mode 100644 index fe3882ab8..000000000 --- a/xgb_custom/xgb_custom.ipynb +++ /dev/null @@ -1,922 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Custom Objective and Evaluation Functions\n", - "\n", - "This demo was adapted from **[xgboost's custom metric tutorial](https://xgboost.readthedocs.io/en/latest/tutorials/custom_metric_obj.html)**. We demonstrate how to use a custom objective and a custom evaluation function using an xgboost trainer.\n", - "\n", - "This function differs from `xgb_trainer` by exposing the low-level xgboost python api, `train`. " - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [], - "source": [ - "# nuclio: ignore\n", - "import nuclio" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [], - "source": [ - "from os import path\n", - "import numpy as np\n", - "from numpy.random import randint, randn, seed\n", - "import pandas as pd\n", - "from xgboost import DMatrix, train\n", - "import matplotlib.pyplot as plt\n", - "from mlrun.execution import MLClientCtx\n", - "from mlrun.datastore import DataItem\n", - "from mlrun.artifacts import PlotArtifact\n", - "from mlrun.mlutils.data import get_splits, get_sample\n", - "\n", - "from cloudpickle import dumps\n", - "\n", - "from typing import (Tuple, Dict, List, Union, Callable)\n", - "\n", - "seed(seed=1994)\n", - "\n", - "## UNCOMMENT THIS LINE TO TEST CALCULATED VALUES\n", - "DEBUG_ERROR = 0 # this will be added to the custom eval function--set it to some value like 999 " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### generate data with outliers" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [], - "source": [ - "def gen_outliers(context: MLClientCtx, nrows=4096, feats=16, \n", - " outs=64, omax=10_000, labels_col=\"labels\",\n", - " header=[], label_type=\"int32\", key=\"xgb-outs\",\n", - " local_path=\"xgb_custom\"):\n", - " \"\"\"simulate data with outliers\n", - " \n", - " :param context: the function's execution context\n", - " :param nrows: (4096) number of data points\n", - " :param feats: (16) number of features\n", - " :param outs: (64) number of outliers\n", - " :param omax: (10_100) max value of outliers\n", - " :param labels_col: (labels) name of labels column\n", - " :param header: () header for dataset, will default to\n", - " `feat_`\n", - " :param label_type: (int32) data type for the label column\n", - " :param key: key of datset in artifact store\n", - " :param local_path: path in artifact store where data will be\n", - " serialized\n", - " \"\"\"\n", - " x = randn(nrows, feats)\n", - " y = randn(nrows)\n", - " y += np.abs(np.min(y))\n", - "\n", - " for i in range(0, outs):\n", - " ind = randint(0, len(y)-1)\n", - " y[ind] += randint(0, omax)\n", - " \n", - " if not header:\n", - " header = [f\"feat_{j}\" for j in range(feats)]\n", - " header.append(labels_col)\n", - "\n", - " data = pd.DataFrame(data=np.concatenate((x,y.reshape(-1,1)),axis=-1),\n", - " columns=header)\n", - " data = data.astype({labels_col: label_type})\n", - " \n", - " context.log_dataset(key, df=data, local_path=local_path)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## custom objective and eval" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "toc-hr-collapsed": true, - "toc-nb-collapsed": true - }, - "source": [ - "The following code was adapted from xgboost's documentation **[Custom Objective and Evaluation Metric](https://xgboost.readthedocs.io/en/latest/tutorials/custom_metric_obj.html?highlight=tree_method#custom-objective-and-evaluation-metric)**." - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [], - "source": [ - "def gradient(predt: np.ndarray, dtrain: DMatrix) -> np.ndarray:\n", - " \"\"\"gradient of squared log error\"\"\"\n", - " y = dtrain.get_label()\n", - " return (np.log1p(predt) - np.log1p(y)) / (predt + 1)\n", - "\n", - "\n", - "def hessian(predt: np.ndarray, dtrain: DMatrix) -> np.ndarray:\n", - " \"\"\"hessian of squared log error\"\"\"\n", - " y = dtrain.get_label()\n", - " return ((-np.log1p(predt) + np.log1p(y) + 1) /\n", - " np.power(predt + 1, 2))\n", - "\n", - "\n", - "def squared_log(predt: np.ndarray, dtrain: DMatrix) -> Tuple[np.ndarray,\n", - " np.ndarray]:\n", - " \"\"\"squared log error objective\n", - "\n", - " simplified version for RMSLE used as objective function\n", - " \"\"\"\n", - " predt[predt < -1] = -1 + 1e-6\n", - " grad = gradient(predt, dtrain)\n", - " hess = hessian(predt, dtrain)\n", - " return grad, hess\n", - "\n", - "def rmsle(predt: np.ndarray, dtrain: DMatrix) -> Tuple[str, float]:\n", - " \"\"\" Root mean squared log error metric.\n", - " \"\"\"\n", - " y = dtrain.get_label()\n", - " predt[predt < -1] = -1 + 1e-6\n", - " elements = np.power(np.log1p(y) - np.log1p(predt), 2)\n", - " return \"my_rmsle\", float(np.sqrt(np.sum(elements) / len(y))) + DEBUG_ERROR" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## learning curves" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [], - "source": [ - "def learning_curves(\n", - " context: MLClientCtx,\n", - " results: dict,\n", - " figsz: Tuple[int,int]=(10,10),\n", - " plots_dest: str = \"plots\"\n", - ") -> None:\n", - " \"\"\"plot xgb learning curves\n", - " \n", - " this will also log a model's learning curves\n", - " \"\"\"\n", - " plt.clf()\n", - " plt.figure(figsize=figsz)\n", - " plt.plot(results[\"train\"][\"my_rmsle\"], label=\"train-my-rmsle\")\n", - " plt.plot(results[\"valid\"][\"my_rmsle\"], label=\"valid-my-rmsle\")\n", - " plt.title(f\"learning curves\")\n", - " plt.legend()\n", - " \n", - " context.log_artifact(\n", - " PlotArtifact(f\"learning-curves\", body=plt.gcf()),\n", - " local_path=f\"{plots_dest}/learning-curves.html\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## fit" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [], - "source": [ - "def fit(\n", - " context: MLClientCtx,\n", - " dataset: DataItem,\n", - " num_boost_round: int = 10,\n", - " evals: List[Tuple[DMatrix, str]] = [],\n", - " obj: Union[Callable, str] = \"\",\n", - " feval: Union[Callable, str] = None,\n", - " maximize: bool = False,\n", - " early_stopping_rounds: int = None,\n", - " evals_result: dict = {},\n", - " verbose_eval: bool = True,\n", - " xgb_model: DataItem = None,\n", - " callbacks: List[Callable] = [],\n", - " label_column: str = \"labels\",\n", - " encode_cols: dict = {},\n", - " sample: int = -1,\n", - " test_size: float = 0.25,\n", - " valid_size: float = 0.75,\n", - " random_state: int = 1994,\n", - " models_dest: str = \"models\",\n", - " plots_dest: str = \"plots\",\n", - " file_ext: str = \"csv\",\n", - " test_set_key: str = \"test-set\",\n", - " gpus: bool = False\n", - ") -> None:\n", - " \"\"\"low level xgboost train api\n", - " \n", - " for the xgboost `train` params see:\n", - " https://xgboost.readthedocs.io/en/latest/python/python_api.html#xgboost.train\n", - "\n", - " Note: the first parameter of xgboost's `train` method is a dict of parameters\n", - " supplied to the booster (engine). To modify one of those simply\n", - " add a task parameter (when running you supply an mlrun NewTask) with the\n", - " prefix \"XGB_\". So for example, to set the 'tree_method' parameter to 'approx',\n", - " add {\"XGB_tree_method\":\"approx\"} to the task params key.\n", - " \n", - " :param context: the function context\n", - " :param dataset: the full data set, train, valid and test will be extracted and\n", - " each converted to a DMatrix for input to xgboost's `train`\n", - " :param label_column: ground-truth (y) labels\n", - " :param encode_cols: dictionary of names and prefixes for columns that are\n", - " to hot be encoded.\n", - " :param sample: Selects the first n rows, or select a sample\n", - " starting from the first. If negative <-1, select\n", - " a random sample\n", - " :param test_size: (0.05) test set size\n", - " :param valid_size: (0.75) Once the test set has been removed the\n", - " training set gets this proportion.\n", - " :param random_state: (1) sklearn rng seed\n", - " :param models_dest: destination subfolder for model artifacts\n", - " :param plots_dest: destination subfolder for plot artifacts\n", - " :param file_ext: format for test_set_key hold out data\n", - " :param test_set_key: (test-set), key of held out data in artifact store\n", - " :param gpus: (False), run on gpus\n", - " \"\"\"\n", - " raw, labels, header = get_sample(dataset, sample, label_column)\n", - " \n", - " # hot-encode\n", - " if encode_cols:\n", - " raw = pd.get_dummies(raw, \n", - " columns=list(encode_cols.keys()), \n", - " prefix=list(encode_cols.values()), \n", - " drop_first=True)\n", - " \n", - " # split the sample into train validate, test and calibration sets:\n", - " (xtrain, ytrain), (xvalid, yvalid), (xtest, ytest) = \\\n", - " get_splits(raw, labels, 3, test_size, valid_size, random_state)\n", - " \n", - " # save test data as regular dataframe as it may be used by other process\n", - " context.log_dataset(test_set_key, df=pd.concat([xtest, ytest], axis=1),\n", - " format=file_ext, index=False)\n", - " \n", - " # convert to xgboost DMatrix (todo - dask, gpu)\n", - " dtrain = DMatrix(xtrain, label=ytrain)\n", - " dvalid = DMatrix(xvalid, label=yvalid)\n", - " \n", - " boost_params = {\n", - " \"tree_method\": \"gpu_hist\" if gpus else \"hist\", \n", - " \"seed\": random_state,\n", - " \"disable_default_eval_metric\": 1,\n", - " \"objective\": \"reg:squaredlogerror\",\n", - " \"eval_metric\": \"rmsle\"}\n", - "\n", - " # enable user to customize `booster param` parameters\n", - " for k, v in context.parameters.items():\n", - " if k.startswith('XGB_'):\n", - " boost_params[k[4:]] = v\n", - " \n", - " # collect learning curves / training history\n", - " results = dict()\n", - " \n", - " booster = train(\n", - " boost_params,\n", - " dtrain=dtrain,\n", - " num_boost_round=num_boost_round,\n", - " evals=[(dtrain, \"train\"), (dvalid, \"valid\")],\n", - " evals_result=results,\n", - " obj=squared_log,\n", - " feval=rmsle,\n", - " maximize=maximize,\n", - " early_stopping_rounds=early_stopping_rounds,\n", - " verbose_eval=verbose_eval,\n", - " # xgb_model=xgb_model,\n", - " # callbacks: List[Callable] = []\n", - " )\n", - " \n", - " context.log_model(\"model\", \n", - " body=dumps(booster),\n", - " model_file = \"model.pkl\",\n", - " artifact_path='/User/artifacts/tttt')\n", - " \n", - " learning_curves(context, results)" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [], - "source": [ - "# nuclio: end-code" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### run locally" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [], - "source": [ - "from mlrun import NewTask, run_local" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[mlrun] 2020-06-14 13:30:21,675 starting run gen_outliers uid=29ae7c944a184de881acc81206a92a48 -> http://mlrun-api:8080\n", - "[mlrun] 2020-06-14 13:30:22,141 log artifact xgb-outs at /User/artifacts/xgb_custom.csv, size: 2762858, db: Y\n", - "\n" - ] - }, - { - "data": { - "text/html": [ - "\n", - "
\n", - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
projectuiditerstartstatenamelabelsinputsparametersresultsartifacts
default0Jun 14 13:30:21completedgen_outliers
v3io_user=admin
kind=handler
owner=admin
host=jupyter-7b44c8d958-kklf7
nrows=8192
label_type=float
xgb-outs
\n", - "
\n", - "
\n", - "
\n", - " Title\n", - " ×\n", - "
\n", - " \n", - "
\n", - "
\n" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "to track results use .show() or .logs() or in CLI: \n", - "!mlrun get run 29ae7c944a184de881acc81206a92a48 --project default , !mlrun logs 29ae7c944a184de881acc81206a92a48 --project default\n", - "[mlrun] 2020-06-14 13:30:22,218 run executed, status=completed\n" - ] - } - ], - "source": [ - "gen_outs_tsk = NewTask(name='gen_outliers',\n", - " handler=gen_outliers, \n", - " params={'nrows': 8192, 'label_type': 'float'})\n", - "\n", - "outliers_run = run_local(gen_outs_tsk)" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[mlrun] 2020-06-14 13:30:23,011 starting run fit model uid=489d2d26007e444cb81ffe7b6bc9d4a2 -> http://mlrun-api:8080\n", - "[mlrun] 2020-06-14 13:30:23,405 log artifact test-set at /User/artifacts/test-set.csv, size: 689366, db: Y\n", - "[mlrun] 2020-06-14 13:30:23,545 log artifact model at /User/artifacts/tttt/, size: 17052, db: Y\n", - "[mlrun] 2020-06-14 13:30:23,712 log artifact learning-curves at /User/artifacts/plots/learning-curves.html, size: 31641, db: Y\n", - "\n" - ] - }, - { - "data": { - "text/html": [ - "\n", - "
\n", - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
projectuiditerstartstatenamelabelsinputsparametersresultsartifacts
default0Jun 14 13:30:23completedfit model
v3io_user=admin
kind=handler
owner=admin
host=jupyter-7b44c8d958-kklf7
dataset
num_boost_round=40
verbose_eval=False
XGB_max_depth=2
XGB_subsample=0.9
test-set
model
learning-curves
\n", - "
\n", - "
\n", - "
\n", - " Title\n", - " ×\n", - "
\n", - " \n", - "
\n", - "
\n" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "to track results use .show() or .logs() or in CLI: \n", - "!mlrun get run 489d2d26007e444cb81ffe7b6bc9d4a2 --project default , !mlrun logs 489d2d26007e444cb81ffe7b6bc9d4a2 --project default\n", - "[mlrun] 2020-06-14 13:30:23,790 run executed, status=completed\n" - ] - }, - { - "data": { - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAlMAAAJOCAYAAACTCYKtAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjMsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+AADFEAAAgAElEQVR4nOzdeXyedZ3v/9f3TtKm2dqmSUrTLS1NW5pSCk0BrQKKsuiwOKLDNo4oruOZH8w5Hhk9x6PMuMyMx+NxVBQVPcyAqMygnCOjDiriAkorBdm60tIF2nTfkjbL9fvjTtosd5I7yb3lvl/Px6OPO/d1Xfd1fZIW+u73+l6fb4iiCEmSJI1OLNsFSJIkjWeGKUmSpDEwTEmSJI2BYUqSJGkMDFOSJEljYJiSJEkaA8OUpEGFELaEEN6QpWsfCSHMz8a1JWkkirNdgCQlEkVRRbZrkKRkODIlKeNCCEXZrmGsQgj+Y1QSYJiSlKQQQiyEcFsIYVMIYW8I4XshhOpe+78fQnglhHAwhPBoCKGp175vhxDuCCE8FEI4Cryue9uXQwg/CiEcDiH8LoRweq/PRCGEBb0+P9Sxl4QQ1nVf+yshhF+GEG4e5PsoCiF8tPv7OBxCWBNCmB1CaOi+ZnGvYx/pOU8I4Z0hhN+EEP5XCGEf8LchhAMhhKW9jq8NIbSGEOq63/9JCGFt93G/DSEs63XsR0IIO7prWBdCuHhsv0OSssUwJSlZfwVcDVwI1AP7gS/32v/vQCNQB/wBuKff568HPgVUAr/u3nYd8ElgKrCxe/9gEh4bQqgB7gf+BpgGrANePcR5/rr7XG8CqoB3AceGOL6384DNxL/H24F/6z5Xj7cDv4yiaHcI4RzgLuB93XV9DXgwhDAxhLAI+BCwMoqiSuBSYEuSNUjKMYYpScl6H/CxKIq2R1F0HPgEcE3PSE4URXdFUXS4176zQgiTe33+h1EU/SaKoq4oitq6t/1bFEW/j6Kog3j4Wj7E9Qc79k3As1EU/Vv3vi8CrwxxnpuB/xZF0boo7qkoivYm+TPYGUXRP0VR1BFFUStwL33D1PXd2wDeA3wtiqLfRVHUGUXR/wGOA+cDncBEYEkIoSSKoi1RFG1KsgZJOcYwJSlZc4EHum9ZHQCeJx4KpnffOvts962zQ5waZanp9fltCc7ZO/QcA4aadD7YsfW9zx3FV2/fPsR5ZgOjDS79v4efA5NCCOeFEOYSD3gPdO+bC/znnp9X989sNlAfRdFG4BbioXN3COG+EEL9KGuSlGWGKUnJ2gZcHkXRlF6/SqMo2kF8ROYq4A3AZKCh+zOh1+ejNNX1MjCr500IIfR+n8A24PQE2492v5b12nZav2P6fA9RFHUB3yM+OnU98P+iKDrc6zqf6vfzKoui6Dvdn703iqLXEA9dEfD3Q9QsKYcZpiQl66vAp7pHYHomW1/Vva+S+C2svcTDyKczWNePgDNDCFd333L8SwaGoN6+QXzyeGOIWxZCmBZFUQuwA7ixe6TtXSQOXf3dC/wZcAOnbvEBfB14f/eoVQghlIcQ3hxCqAwhLAohvD6EMBFoA1qJj/JJGocMU5KS9b+BB4GfhhAOA48Tn5ANcDewlXgYea57X0ZEUbQHeBvwD8TD3BJgNfFwl8jniY8m/RQ4BHwTmNS97z3Ah7vP0wT8Nonr/474qFY98Un4PdtXd5/vS8Qn628E3tm9eyLwWWAP8duXdcBHh/9uJeWiEJ9eIEn5IYQQIz5n6oYoin6R7Xok5T9HpiSNeyGES0MIU7pvm32U+FytjI2OSSpshilJ+eBVxJ/Q2wNcAVzd3bpAktLO23ySJElj4MiUJEnSGGRtoc6ampqooaEhW5eXJElK2po1a/ZEUVSbaF/WwlRDQwOrV6/O1uUlSZKSFkLYOtg+b/NJkiSNgWFKkiRpDAxTkiRJY5C1OVOSJOWz9vZ2tm/fTltbW7ZL0QiUlpYya9YsSkpKkv6MYUqSpDTYvn07lZWVNDQ0EELIdjlKQhRF7N27l+3btzNv3rykP+dtPkmS0qCtrY1p06YZpMaREALTpk0b8WiiYUqSpDQxSI0/o/k9M0xJkiSNgWFKkqQ8deDAAb7yla+M+HNvetObOHDgQBoqyryGhgb27NmT1msYpiRJylODhanOzs4hP/fQQw8xZcqUdJU1IsPVmgsMU5Ik5anbbruNTZs2sXz5clauXMnrXvc6rr/+es4880wArr76alasWEFTUxN33nnnyc/1jOZs2bKFM844g/e85z00NTVxySWX0NraOuA6W7ZsYfHixdx8880sXbqUG264gYcffphVq1bR2NjI73//e7q6umhsbKSlpQWArq4uFixYkHDUqKKigo9//OOcd955PPbYYzQ0NPDRj36UV73qVTQ3N/OHP/yBSy+9lNNPP52vfvWrALz88stccMEFLF++nKVLl/KrX/1qwHn/5V/+hXPPPZfly5fzvve9L2VBzdYIkiSl2Sf/77M8t/NQSs+5pL6K/3FF05DHfPazn+WZZ55h7dq1PPLII7z5zW/mmWeeOfnY/1133UV1dTWtra2sXLmSt771rUybNq3POTZs2MB3vvMdvv71r/P2t7+df/3Xf+XGG28ccK2NGzfy/e9/nzvvvJOVK1dy77338utf/5oHH3yQT3/60/zgBz/gxhtv5J577uGWW27h4Ycf5qyzzqKmpmbAuY4ePcrSpUu5/fbbT26bPXs2jz32GLfeeivvfOc7+c1vfkNbWxtNTU28//3v59577+XSSy/lYx/7GJ2dnRw7dqzPOZ9//nm++93v8pvf/IaSkhI++MEPcs899/COd7wj6Z/5YAxTkiQViHPPPbdP/6QvfvGLPPDAAwBs27aNDRs2DAhT8+bNY/ny5QCsWLGCLVu2JDz3vHnzTo54NTU1cfHFFxNC4Mwzzzz5mXe9611cddVV3HLLLdx1113cdNNNCc9VVFTEW9/61j7brrzySgDOPPNMjhw5QmVlJZWVlZSWlnLgwAFWrlzJu971Ltrb27n66qtP1tzjZz/7GWvWrGHlypUAtLa2UldXN9yPLCmGKUmS0my4EaRMKS8vP/n1I488wsMPP8xjjz1GWVkZF110UcL+ShMnTjz5dVFREa2trWzbto0rrrgCgPe///1cdtllfY6LxWIn38diMTo6OoD46NL06dP5+c9/zu9+9zvuueceOjs7WbFiBRAPTLfffjulpaUUFRUlrKP3uXuf/4ILLuDRRx/lRz/6EX/+53/Ohz/84T6jTlEU8Rd/8Rd85jOfGd0PbwiGKUmS8lRlZSWHDx9OuO/gwYNMnTqVsrIyXnjhBR5//PGkzzt79mzWrl178v1go1WJ3Hzzzdx44438+Z//+cnA1Ptco7V161ZmzpzJe97zHo4ePcof/vCHPmHq4osv5qqrruLWW2+lrq6Offv2cfjwYebOnTvmaxumJEnKU9OmTWPVqlUsXbqUSZMmMX369JP7LrvsMr761a+ybNkyFi1axPnnn5+Rmq688kpuuummQW/xjdYjjzzCP/7jP1JSUkJFRQV33313n/1Llizh7/7u77jkkkvo6uqipKSEL3/5yykJUyGKojGfZDSam5uj1atXZ+XakiSl2/PPP88ZZ5yR7TJyzurVq7n11lsTPm2XKxL93oUQ1kRR1JzoeEemJElSRnz2s5/ljjvu4J577sl2KSllnylJkpQRt912G1u3buU1r3lNtktJKcOUJEnSGBimJEmSxsAwJUmSNAb5G6ZeeQb+qRlezN2nBSRJ0viXv2Fq0lTYuwFaXsh2JZIkjQsVFRUA7Ny5k2uuuSbhMRdddBHjqbXRli1bWLp0aVqvkb9hqqoeSsph78ZsVyJJ0rhSX1/P/fffn+0yAOjs7Mx2CcPK3zAVAkw7HfZsyHYlkiRlxUc+8hG+8pWvnHz/iU98gk9+8pNcfPHFnHPOOZx55pn88Ic/HPC53qM5ra2tXHvttSxbtow/+7M/o7W1NeG1vv3tb3P11VdzxRVXMG/ePL70pS/x+c9/nrPPPpvzzz+fffv2sWnTJs4555yTn9mwYcPJdfl6e+SRR3jd617H9ddff3Kh5MWLF3PzzTezdOlSbrjhBh5++GFWrVpFY2Mjv//97wH45S9/yfLly1m+fDlnn332gKV0Ojs7+fCHP8zKlStZtmwZX/va10b+Q00gv5t21jTC9ieyXYUkqdD9+23wyh9Te87TzoTLPzvkIddeey233HILH/zgBwH43ve+x49//GNuvfVWqqqq2LNnD+effz5XXnklIYSE57jjjjsoKyvj6aef5umnn+4Thvp75plnePLJJ2lra2PBggX8/d//PU8++SS33nord999N7fccguTJ09m7dq1LF++nG9961u8853vTHiu3//+9zzzzDPMmzePLVu2sHHjRr7//e9z5513snLlSu69915+/etf8+CDD/LpT3+aH/zgB3zuc5/jy1/+MqtWreLIkSOUlpb2Oec3v/lNJk+ezBNPPMHx48dZtWoVl1xyCfPmzRvy5zic/B2ZApjWCAe2QXviFC1JUj47++yz2b17Nzt37uSpp55i6tSpzJgxg49+9KMsW7aMN7zhDezYsYNdu3YNeo5HH32UG2+8EYBly5axbNmyQY993eteR2VlJbW1tUyePJkrrrgC4OToEsQXOv7Wt75FZ2cn3/3ud7n++usTnuvcc8/tE3LmzZvHmWeeSSwWo6mpiYsvvpgQQp9zr1q1ir/+67/mi1/8IgcOHKC4uO+Y0U9/+lPuvvtuli9fznnnncfevXvZsGHsd7Dyf2SKCPZthulN2a5GklSohhlBSqdrrrmG+++/n1deeYVrr72We+65h5aWFtasWUNJSQkNDQ20tbUNeY5Eo1YPPPAAn/zkJwH4xje+AcDEiRNP7o/FYiffx2IxOjo6AHjrW9/KJz/5SV7/+tezYsUKpk2bxu9+9zve9773AXD77bdTVVVFeXl5n+slc+7bbruNN7/5zTz00EOcf/75PPzww31Gp6Io4p/+6Z+49NJLk/jJJS+/R6ZqGuOvzpuSJBWoa6+9lvvuu4/777+fa665hoMHD1JXV0dJSQm/+MUv2Lp165Cfv+CCC06upffMM8/w9NNPA/CWt7yFtWvXsnbtWpqbE67/m1BpaSmXXnopH/jAB7jpppsAOO+8806e68orrxzldwqbNm3izDPP5CMf+QjNzc288ELfJ/ovvfRS7rjjDtrb2wFYv349R48eHfX1euR3mJq2IP5qmJIkFaimpiYOHz7MzJkzmTFjBjfccAOrV6+mubmZe+65h8WLFw/5+Q984AMcOXKEZcuW8Q//8A+ce+65Y67phhtuIITAJZdcMuZz9faFL3yBpUuXctZZZzFp0iQuv/zyPvtvvvlmlixZwjnnnMPSpUt53/ved3JUayxCFEVjPsloNDc3RxnpU/H5JdDwGvjTO9N/LUmSuj3//POcccYZ2S4jJ33uc5/j4MGD/O3f/m22S0ko0e9dCGFNFEUJh+Dye84UxEenHJmSJCknvOUtb2HTpk38/Oc/z3YpKZP/YaqmEZ7+HkRRvPeUJEnKmgceeCDbJaRcfs+Zgnh7hOOH4MjubFciSSow2ZpKo9Ebze9Z/oepnif69nqrT5KUOaWlpezdu9dANY5EUcTevXsHNPscTmHc5oP4vKmG12S3FklSwZg1axbbt2+npaUl26VoBEpLS5k1a9aIPpP/YapqFhRPchK6JCmjSkpKxrxMicaH/L/NF4vFFzz2Np8kSUqD/A9TYHsESZKUNoURpmoa4cBW6Die7UokSVKeKZAwtRCiLtj3YrYrkSRJeaYwwlTPGn3Om5IkSSlWWGHKeVOSJCnFCiNMlVZBxWmGKUmSlHKFEaYgPgnd23ySJCnFCidM9bRHsK2/JElKocIJUzWN0HYAju3NdiWSJCmPFFCYWhh/dd6UJElKocIJU7ZHkCRJaVA4YWrKHCia6MiUJElKqcIJU7EiqJ5vmJIkSSlVOGEKoGaBt/kkSVJKFVaYmtYI+7dAZ3u2K5EkSXmisMJUzULo6ogHKkmSpBQosDDVGH913pQkSUqRwgpTtkeQJEkplrdhatu+Y3z0gT+y7pXDpzZOmgLltbBnffYKkyRJeSVvw1R7Zxf3/u4l/rjjYN8d0xphz8bsFCVJkvJO3oap2dVlFMUCL+450neH7REkSVIK5W2YKimKMae6jC17jvXdMa0xvtjxsX3ZKUySJOWVYcNUCOGuEMLuEMIzg+xfHEJ4LIRwPITwX1Jf4ujNqyln856jfTf2LHi811t9kiRp7JIZmfo2cNkQ+/cBfwV8LhUFpdK8mnK27DlKV1d0aqPtESRJUgoNG6aiKHqUeGAabP/uKIqeAHKurXhDTTmt7Z3sOtx2auOUuRArcd6UJElKiYzOmQohvDeEsDqEsLqlpSXt15tfUw7Aiy29bvUVFUP1PEemJElSSmQ0TEVRdGcURc1RFDXX1tam/XrzusPUgHlT0xoNU5IkKSXy9mk+gNOqSiktibFlwCT0BbBvM3R2ZKcwSZKUN/I6TMVigYZp5byY6Im+rnY4sDU7hUmSpLxRPNwBIYTvABcBNSGE7cD/AEoAoij6agjhNGA1UAV0hRBuAZZEUXQobVWPwPzacl54+XDfjdO6n+jbuxGmnZ75oiRJUt4YNkxFUXTdMPtfAWalrKIUa5hWzk+f3UV7ZxclRd0Dcb3bIyy8NHvFSZKkcS+vb/NBfBJ6R1fE9v2tpzaWVcOkatsjSJKkMcv7MDW/trs9woA1+nyiT5IkjV3eh6l5NRUAvJhojT7DlCRJGqO8D1NTy0qYPKkkwcjUAji6G9oOZqcwSZKUF/I+TIUQaKgZpD0CwB4XPJYkSaOX92EK4svK9FlSBnq1R/BWnyRJGr2CCFPzasrZebCN1hOdpzZObYBQ5LwpSZI0JgUTpgC27O01OlU8IR6oHJmSJEljUFhhasC8KZ/okyRJY1NQYWpz/zA1bQHs3QRdnQk+JUmSNLyCCFPlE4upq5yY+Im+zuNwcFt2CpMkSeNeQYQpiI9ODQxTPWv02R5BkiSNTsGEqfm1CcKU7REkSdIYFUyYmldTzr6jJzh4rP3UxvIaKJ3sJHRJkjRqBRSmutfo690eIYT46JQjU5IkaZQKKEzFn+gbuEaf7REkSdLoFUyYmlNdRiyQYFmZBXD4ZTh+ODuFSZKkca1gwtSE4hizppYN7DXVs+DxXp/okyRJI1cwYQpsjyBJklKv4MLUlj1HiaLo1Mbq+RBiTkKXJEmjUlBhan5tOUdPdNJy+PipjcUTYcocJ6FLkqRRKagw1TBtsDX6fKJPkiSNTkGFqVPtERLMm9q7Ebq6slCVJEkazwoqTNVPmcSE4ljiMNXRCod2ZKcwSZI0bhVUmCqKBRqmlbF5QK8p1+iTJEmjU1BhCrqf6NtrewRJkpQaBRimKti69yidXb3aI1RMhwmVjkxJkqQRK8AwVUZ7Z8SO/a2nNoYANQt8ok+SJI1YAYapCgA291/w2PYIkiRpFAowTA3RHuHQdjhxNMGnJEmSEiu4MFVTMYHKicWDr9G3d1Pmi5IkSeNWwYWpEALzahMseGx7BEmSNAoFF6YgvqzMwDB1OhBsjyBJkkakIMPUvJpydhxopa2989TGkkkwebYjU5IkaUQKMkzNry0niuClfcf67rA9giRJGqGCDFM9T/QlXFZm70aIogSfkiRJGqggw1RDd5hKuKzMiSNw+OUsVCVJksajggxTVaUl1FRM5MX+I1Mn1+jzVp8kSUpOQYYpiC8rM7DX1KL4a8u6zBckSZLGpQIOU+Vs7h+mKk+D0imw+7nsFCVJksadAg5TFew5cpxDbe2nNoYAdUtg9/PZK0ySJI0rBRymuieh9x+dqjsjHqZ8ok+SJCWhYMPU/NpBFjyuOwOOH4RDO7NQlSRJGm8KNkzNqS4jhERhakn81Vt9kiQpCQUbpkpLiqifPCnxyBQ4CV2SJCWlYMMUxG/1DQhTZdVQcZojU5IkKSkFHabm1ZTzYstRov6TzevOcGRKkiQlpeDD1OHjHew5cqLvjrol8cadXZ3ZKUySJI0bBR+mIMEafXVnQEcr7N+S+aIkSdK4YpiCgWv0+USfJElKUkGHqZlTJlFSFAYuK1PbvUafYUqSJA2joMNUcVGMOdVlvLjnSN8dEytgylwnoUuSpGEVdJiC+Bp9A9ojgGv0SZKkpBR8mJpfW86Wvcfo6krQHmHvBug4kfiDkiRJGKaYV1POiY4udh5s7bujbgl0dcDejdkpTJIkjQsFH6Yapg2x4DE4b0qSJA2p4MPU/NpBwlRNI4Qi501JkqQhFXyYqqucSNmEIjb37zVVPBGmLTBMSZKkIRV8mAohxNfoS/hEn2v0SZKkoRV8mIL4JPQBS8pAfBL6/i1wIsE+SZIkDFMAzK8pZ9u+Y5zo6Oq7o+4MIIoveixJkpSAYQpoqCmnK4KX9h3ru8M1+iRJ0jAMU/Ra8Lj/vKnqeVBc6rwpSZI0KMMUvcNUvzX6YkXxRY8dmZIkSYMYNkyFEO4KIewOITwzyP4QQvhiCGFjCOHpEMI5qS8zvaaUTaC6fIJr9EmSpBFLZmTq28BlQ+y/HGjs/vVe4I6xl5V5Q7ZHOLwTWvdnvihJkpTzhg1TURQ9Cuwb4pCrgLujuMeBKSGEGakqMFMapg0Wpnomob+Q2YIkSdK4kIo5UzOBbb3eb+/eNkAI4b0hhNUhhNUtLS0puHTqzK8tZ9eh4xw93tF3h2v0SZKkIaQiTIUE26JEB0ZRdGcURc1RFDXX1tam4NKpM+gTfVUzYWKV86YkSVJCqQhT24HZvd7PAnam4LwZNWiYCqF7WRnDlCRJGigVYepB4B3dT/WdDxyMoujlFJw3oxqmDRKm4NQafVHCATdJklTAkmmN8B3gMWBRCGF7COHdIYT3hxDe333IQ8BmYCPwdeCDaas2jSZNKKJ+cilbBpuE3roPjuzOfGGSJCmnFQ93QBRF1w2zPwL+MmUVZVFDTTmbBxuZgvjoVOX0zBYlSZJymh3Qe5lXU87mliNE/W/nuUafJEkahGGql3k15Rxq62D/sfa+O8proLwWdj+bncIkSVLOMkz1Mr92kDX6wCf6JElSQoapXubXVACwafdga/S9AF1dGa5KkiTlMsNUL7Ory5hQHGPD7sMDd9adAe1H4eBLmS9MkiTlLMNUL0WxwOm1FWzYneg2n5PQJUnSQIapfhrrKtiwK0GYql0cf3WNPkmS1Ithqp/Gugp2HGgduOBxaRVMnu3IlCRJ6sMw1U/j9EoANrX4RJ8kSRqeYaqfxunxJ/rWJ7rVV3cG7FkPne0D90mSpIJkmOpnbnUZJUVhkCf6lkDnCdi3OfOFSZKknGSY6qe4KMb8mgo2DjYyBU5ClyRJJxmmElgwfZD2CDULIcScNyVJkk4yTCWwsK6SbfuP0Xqis++OkklQPd+RKUmSdJJhKoHG6RVEkU/0SZKk4RmmEmisiz/RN+gk9H2bob01w1VJkqRcZJhKYO60copjIXEn9LozIOqKt0iQJEkFzzCVwITiGA015a7RJ0mShmWYGsTC6RVsTBSmqudD0QQnoUuSJMAwNagFdZVs3XuUtvZ+T/QVlcRbJDgyJUmSMEwNqrGugq4INrccHbjTJ/okSVI3w9QgetboS/xE3xlwcBu0HcpwVZIkKdcYpgYxr6acolhIPG+qZxJ6ywuZLUqSJOUcw9QgJhYXMXdaGet3DTIyBU5ClyRJhqmhNNYNskbf5DlQUu68KUmSZJgaSmNdJVv3HuN4R78n+mIxqFvsyJQkSTJMDaVxegWdXRFb9hwbuNMn+iRJEoapITXWVQJDrNF3tAWOtGS4KkmSlEsMU0OYX1tOLMD6wdboA2hxdEqSpEJmmBpCaUkRc6rL2DjYyBR4q0+SpAJnmBrGgrpKNiQamaqYDpOmOgldkqQCZ5gaRuP0Cl7cc5T2zq6+O0KIj045MiVJUkEzTA1j4fQKOroitu4dYo2+KMp8YZIkKScYpobR80TfoJPQjx+CQzsyXJUkScoVhqlhnF5bQQgknjflJHRJkgqeYWoYkyYUMWvqpMS9pmoXx1+dhC5JUsEyTCVhYV0lGxOt0VdWDZUzHJmSJKmAGaaSsGB6BZtbjtLR/4k+6J6E7siUJEmFyjCVhMa6Sk50drF1X6I1+pZAyzro6hy4T5Ik5T3DVBIa6yqAwSahnwEdbbB/S2aLkiRJOcEwlYQF3WEq8bIy3Wv07XomgxVJkqRcYZhKQvnEYmZOmcSGRJPQ65ZAKIKXn8p8YZIkKesMU0lqnF6R+DZfyaR4oNr5ZOaLkiRJWWeYSlJjXQWbWo7Q2ZVg6Zj65bBzrcvKSJJUgAxTSWqsq+R4RxfbEj3RV78cWvfBgZcyX5gkScoqw1SSFkzvfqIv0byp+rPjry+vzWBFkiQpFximknSyPULCJ/qaIFbsvClJkgqQYSpJlaUlzJhcysaEk9BLuyehOzIlSVKhMUyNwIK6CtYnGpmC7knoTzoJXZKkAmOYGoHG7gWPuxI+0Xc2tB2AA1szX5gkScoaw9QILJxeQVt7FzsOtA7cOWN5/NV5U5IkFRTD1Ag0Th9iEvr0JoiVOG9KkqQCY5gagQW1lQCsTzQJvXgiTLcTuiRJhcYwNQKTy0qoq5yYeFkZiM+betlO6JIkFRLD1Ag1Tq9g42BP9M1YDm0HYf+LmS1KkiRljWFqhBrrKtmw+whRotGnnk7ozpuSJKlgGKZGqHF6BcdOdLLzYNvAnXVLoGiC86YkSSoghqkRaqzrmYSe4FZf8YT4U32u0SdJUsEwTI1Qzxp9CZeVgfi8qZ1POQldkqQCYZgaoanlE6ipmJC41xTE500dPwj7Nme2MEmSlBWGqVHomYSeUL2d0CVJKiSGqVFonF7Bxl2DPNFXewYUTXTelCRJBcIwNQqNdRUcPt7BK4cSPNHXMwnd9giSJBUEw9QoLOh+om/oTuhPQVdXBquSJEnZkFSYCiFcFkJYF0LYGEK4LcH+uSGEn4UQng4hPBJCmJX6UnPHwpMLHg8xb+r4ISehS5JUAIYNUyGEIuDLwOXAEuC6EKinoRIAACAASURBVMKSfod9Drg7iqJlwO3AZ1JdaC6ZVjGR6vIJgy8r09MJ3XlTkiTlvWRGps4FNkZRtDmKohPAfcBV/Y5ZAvys++tfJNifdxbUVQx+m692cXwSuk/0SZKU95IJUzOBbb3eb+/e1ttTwFu7v34LUBlCmNb/RCGE94YQVocQVre0tIym3pzRWFfB+l2HEz/RV1QCp53pJHRJkgpAMmEqJNjWP0H8F+DCEMKTwIXADqBjwIei6M4oipqjKGqura0dcbG5pLGugkNtHbQcPp74gPrlTkKXJKkAJBOmtgOze72fBezsfUAURTujKPrTKIrOBj7Wve1gyqrMQQundz/RN+gk9LPhxGHYtymDVUmSpExLJkw9ATSGEOaFECYA1wIP9j4ghFATQug5198Ad6W2zNyzoOeJvkQLHkN8jT5w3pQkSXlu2DAVRVEH8CHgJ8DzwPeiKHo2hHB7COHK7sMuAtaFENYD04FPpanenFFbMZHJk0oGH5mqXQzFpc6bkiQpzxUnc1AURQ8BD/Xb9vFeX98P3J/a0nJbCIHGoZ7oKyrunoTuyJQkSfnMDuhj0Di9gvW7B3miD+Lzpl55Gro6M1uYJEnKGMPUGDTWVXLgWDt7j55IfMCM5XDiCOzdmNnCJElSxhimxqDx5CT0IZ7oA+dNSZKUxwxTY9DYveDxoMvK1CyE4knOm5IkKY8ZpsZgetVEKicWs36oSegzlrlGnyRJecwwNQYhBBqnV7BhsJEpiM+bevkpJ6FLkpSnDFNj1FhXycbBek1BfN5U+zHYsyFzRUmSpIwxTI1R4/QK9hw5wb7BnuirtxO6JEn5zDA1RgvqhllWpmYhlJQ5b0qSpDxlmBqjRafFn+h74ZVBwlSsCE5b5siUJEl5yjA1RqdVlVJdPoFndx4c/KD6s+GVP0JnR+YKkyRJGWGYGqMQAk31VTy789DgB9Uv756Evj5zhUmSpIwwTKXAkvoq1u86zImOrsQH9HRCd96UJEl5xzCVAk31k2nvjAbvNzVtAZSUO29KkqQ8ZJhKgab6KgCeG+xWX6wIZpzlGn2SJOUhw1QKzJtWTtmEouHnTTkJXZKkvGOYSoFYLHDGjKrBR6YgPm+qoxX2rMtcYZIkKe0MUynSVF/Fcy8foqsrSnzADDuhS5KUjwxTKbJkRhVHjnfw0r5jiQ+YtgAmVDhvSpKkPGOYSpGm+skAg8+bisW6J6E7MiVJUj4xTKXIwtMqKI6F4Tuh73oGOtszV5gkSUorw1SKTCwuYkFdxdBP9M1YDh1t0PJC5gqTJElpZZhKoab6ycO0R+juhO68KUmS8oZhKoWa6qvYc+Q4uw+1JT6gej5MqHTelCRJecQwlUI9ndCHnIRev9w1+iRJyiOGqRRacjJMDTUJfTm84iR0SZLyhWEqhSpLS5g7rWz4Seidx2H385krTJIkpY1hKsWa6quSnITuvClJkvKBYSrFmuon89K+YxxqG+Q2XvV8mDjZeVOSJOUJw1SK9cybGnTR4xCg3k7okiTlC8NUig37RB/E503tehY6TmSoKkmSlC6GqRSrqyyltnLi8MvKdJ6A3c9lrjBJkpQWhqk0aKqvGvw2H8DMc+Kv25/ITEGSJCltDFNp0FRfxcbdR2hr70x8wJS5UFkPW3+b2cIkSVLKGabSoKl+Mh1dERt2HUl8QAjQsAq2/gaiKLPFSZKklDJMpUFTMp3Q574ajuyCfZszVJUkSUoHw1QazJ5aRsXE4qGf6Jv7mvjrll9npihJkpQWhqk0iMUCS2ZUDT0yVdMI5bXOm5IkaZwzTKXJkvoqnn/5MJ1dg8yJCiF+q2/rbzJbmCRJSinDVJo01VfR2t7Ji3uODn7Q3FVwcBsceClzhUmSpJQyTKVJU/1kYLhJ6Kvir1scnZIkabwyTKVJ4/QKJhTFhm7eWbcESqd4q0+SpHHMMJUmJUUxFp5WMfQTfbGY86YkSRrnDFNp1DRjMs/uPEg0VGPOua+O95o69HLmCpMkSSljmEqjpplV7D/WzssH2wY/qGfelKNTkiSNS4apNDrVCX2IW32nLYMJlfabkiRpnDJMpdHi06oIYZgn+oqKYc55jkxJkjROGabSqHxiMfNqyocemYL4rb6WF+DonswUJkmSUsYwlWZN9ZOHbo8AveZNeatPkqTxxjCVZk31Vew40Mr+oycGP6j+bCieZJiSJGkcMkylWc8k9OdeHmJ0qngCzF4JW3+doaokSVKqGKbSLKllZQDmvgZeeQZaD2SgKkmSlCqGqTSrLp/AjMmlScybejUQwUuPZ6QuSZKUGoapDFgyo2r4J/pmNUPRBG/1SZI0zhimMqCpvopNLUdoPdE5+EElk2DmCiehS5I0zhimMmBJ/WS6InjhlSRaJOxcC8cPZ6YwSZI0ZoapDEhqWRmIz5uKOmHb7zNQlSRJSgXDVAbMmjqJyZNKhg9Ts8+DUOTSMpIkjSOGqQwIIbBkRhXPDdceYWIF1C933pQkSeOIYSpDmuqreOGVw3R0dg194NxVsGMNtLdmpjBJkjQmhqkMaZpZxfGOLja1HB36wLmroPMEbF+dmcIkSdKYGKYyJOlO6HPOB4LzpiRJGicMUxkyv6acicWx4SehT5oCpy01TEmSNE4YpjKkuCjG4hlVw49MQXydvm1PQMeJ9BcmSZLGJKkwFUK4LISwLoSwMYRwW4L9c0IIvwghPBlCeDqE8KbUlzr+NdVX8dzOQ0RRNPSBc18NHa2w88nMFCZJkkZt2DAVQigCvgxcDiwBrgshLOl32H8DvhdF0dnAtcBXUl1oPmiqr+JQWwfb9w/zpN7cV8dfXadPkqScl8zI1LnAxiiKNkdRdAK4D7iq3zERUNX99WRgZ+pKzB9JT0Ivr4HaxfabkiRpHEgmTM0EtvV6v717W2+fAG4MIWwHHgL+U6IThRDeG0JYHUJY3dLSMopyx7fFp1VSFAvDT0KHeIuElx6Hzo70FyZJkkYtmTAVEmzrP+nnOuDbURTNAt4E/HMIYcC5oyi6M4qi5iiKmmtra0de7ThXWlLE6bXlSYapV8OJI/DK0+kvTJIkjVoyYWo7MLvX+1kMvI33buB7AFEUPQaUAjWpKDDfNNVPTvKJvlXxV1skSJKU05IJU08AjSGEeSGECcQnmD/Y75iXgIsBQghnEA9ThXcfLwlN9VXsOnScPUeOD31g1Qyonu+8KUmSctywYSqKog7gQ8BPgOeJP7X3bAjh9hDCld2H/WfgPSGEp4DvAO+Mhn3+vzAtmRGfp/9csvOmtv4WuoZZz0+SJGVNcTIHRVH0EPGJ5b23fbzX188Bq1JbWn5aUh8PU8/uPMQFC4eZNzZ3FTz5z7D7uXhXdEmSlHPsgJ5hU8omMHPKpOTmTTU4b0qSpFxnmMqCnk7ow5oyBybPNkxJkpTDDFNZ0FQ/mRf3HuXo8SR6SPXMm3IKmiRJOckwlQVN9VVEETz/cpL9po62wJ4N6S9MkiSNmGEqC5bNii8rs3bbgeEPbnhN/NV1+iRJykmGqSyoqypl1tRJrNm6f/iDq+dDxXT7TUmSlKMMU1nSPHcqq7fuZ9h2XCHE501t+Y3zpiRJykGGqSxZ0VBNy+HjbNvXOvzBc18Nh3fC/i1pr0uSJI2MYSpLmudOBWD11n3DH3xy3pQtEiRJyjWGqSxZOL2SyonFyc2bqlkEk6qdNyVJUg4yTGVJUSywfM6U5MJULBa/1bfFJ/okSco1hqksap5bzbpdhznY2j78wXNXwYGtcHB7+guTJElJM0xlUXPDVKIInnwpidGpnnX6Xnw0vUVJkqQRMUxl0fLZU4gFkrvVN/1MqDgN1v84/YVJkqSkGaayqHxiMWfMqGL1liTnTS26DDb+DDqOp784SZKUFMNUljXPncrabQfo6Owa/uBFb4ITR2DLr9JfmCRJSophKstWNFTT2t7J8y8fHv7geRdA8SRY560+SZJyhWEqy0bUvLNkEpz+elj37y4tI0lSjjBMZVn9lEnUTy5ldTKT0AEWXQ6HtsMrf0xvYZIkKSmGqRxwztyprNmSxKLHAAsvBUJ8dEqSJGWdYSoHNM+dyiuH2th5sG34gyvqYNZKWG+YkiQpFximckBzQzUAq7ckMW8K4i0Sdj4Jh3amsSpJkpQMw1QOWHxaJWUTipJr3gnxFglgA09JknKAYSoHFBfFOHvOlOSadwLULoapDbZIkCQpBximcsSKOVN54ZVDHDneMfzBIcRHpzY/AieOpr02SZI0OMNUjljRUE1XBGtfOpDcBxZeBp3HYdMv0luYJEkakmEqR5w9ZwohJNm8E2Duq2HiZFskSJKUZYapHFFVWsKi6ZXJT0IvKoHGN8YnoXd1prc4SZI0KMNUDmlumMqTLx2gsyvJpWIWXQ7H9sCONektTJIkDcowlUNWzJ3KkeMdvPDKoeQ+sOANECuGdQ+ltzBJkjQow1QOaZ4bb96Z9K2+SVPic6ecNyVJUtYYpnLIrKmTqKucmHyYgniLhJYXYN/m9BUmSZIGZZjKISEEmhumJt+8E+ItEsAGnpIkZYlhKsesmFvNjgOtvJLMoscA1fOg9gznTUmSlCWGqRyzYu5UYAT9piD+VN/W30LrCEa0JElSShimckxTfRWlJbGR3epb9CaIOmHjz9JXmCRJSsgwlWNKimKcNWsKf3hpBGFq5goor/VWnyRJWWCYykHNDVN5duchjp1IYtFjgFgMFl4KGx6GjhPpLU6SJPVhmMpBzXOr6eyKWLstyUWPIX6r7/hBeOm36StMkiQNYJjKQWfPmQLAmpHMm5p/ERSX2iJBkqQMM0zloCllE2isq2D1SJp3TiiPB6p1D0GU5Np+kiRpzAxTOaq5YSp/eGk/XckuegzxBp4HtsLu59NXmCRJ6sMwlaNWzK3mcFsHG3YfSf5DPd3Q17tWnyRJmWKYylHNo2neWTUD6s9x4WNJkjLIMJWj5k4rY1r5hJFNQof4U33bV8PhXekpTJIk9WGYylEhBFbMnTqySegAiy4DItjwk7TUJUmS+jJM5bDmhqm8tO8Yuw8nuegxwPSlMHm2LRIkScoQw1QOWzG3GoA/jGR0KoT4wsebfg7trWmqTJIk9TBM5bClM6uYUDzCRY8hHqY6WmHzL9NTmCRJOskwlcMmFhexbObkkc+bmvsamFDpwseSJGWAYSrHrWiYyrM7D9LW3pn8h4onwIKLYf1PoKsrfcVJkiTDVK5rnltNe2fEUyNZ9BjiLRKOvAIvP5mewiRJEmCYynkrupt3rnlphLf6Gt8IocgGnpIkpZlhKsdVl09gfm35yJt3llXDnPMNU5IkpZlhahxYMWcqa0a66DHEn+rb9QwceCk9hUmSJMPUeNDcMJUDx9rZvGcEix5DfN4UwB/vT31RkiQJMEyNCz3NO0fcb2ra6dDwWljzLegawdOAkiQpaYapceD02nKmlpWwZqT9pgBWvjt+m2/jz1JfmCRJMkyNBz2LHo8qTC3+E6iYDk98I/WFSZIkw9R4cc7cqWzec5S9R46P7INFJXDOX8CGn8L+LWmpTZKkQmaYGieau+dNPTHSeVMAK94JIQZrvp3SmiRJkmFq3Dhr9mTKJhTx640tI//w5JnxNgl/uBs6RjiyJUmShmSYGicmFhfx6tNreGRdC1E0wn5TEJ+IfmwvPPfD1BcnSVIBM0yNIxcuqmX7/lY27zk68g/PuwiqT4cnvpnyuiRJKmRJhakQwmUhhHUhhI0hhNsS7P9fIYS13b/WhxBGuCqvknHRwloAHlk3ilt9sVh8dGrb4/DKH1NcmSRJhWvYMBVCKAK+DFwOLAGuCyEs6X1MFEW3RlG0PIqi5cA/Af+WjmIL3ezqMubXlvPL9aMIUwBnXQfFpY5OSZKUQsmMTJ0LbIyiaHMURSeA+4Crhjj+OuA7qShOA120sI7HN++l9cQoOpqXVcPSa+Dp70HbodQXJ0lSAUomTM0EtvV6v7172wAhhLnAPODng+x/bwhhdQhhdUvLKEdXCtyFi2o50dHF4y/uHd0JVr4b2o/C099NbWGSJBWoZMJUSLBtsMfJrgXuj6Io4bBJFEV3RlHUHEVRc21tbbI1qpfz5lVTWhLjl6OZNwUw8xyoPzveEX00TwVKkqQ+kglT24HZvd7PAnYOcuy1eIsvrUpLijh//rTRz5sCWHkztLwAW3+busIkSSpQyYSpJ4DGEMK8EMIE4oHpwf4HhRAWAVOBx1Jbovq7cGEtL+45yta9o2iRAND0p1A6xfX6JElKgWHDVBRFHcCHgJ8AzwPfi6Lo2RDC7SGEK3sdeh1wXzSqjpIaiYsW1QGMfnRqQhksvwGefxAO70phZZIkFZ6k+kxFUfRQFEULoyg6PYqiT3Vv+3gURQ/2OuYTURQN6EGl1GuYVsac6rLRz5sCaH4XdHXAk3enrjBJkgqQHdDHoRACFy2q5beb9tLWPooWCQA1C2D+62D1t6GzI6X1SZJUSAxT49SFC2tpbe9k9Zb9oz/JynfDoe2w4SepK0ySpAJjmBqnXnX6NCYUxXhk3e7Rn2Th5VBZb0d0SZLGwDA1TpVNKObcedVja5FQVAzNN8Gmn8HeTakrTpKkAmKYGscuWlTLht1H2HGgdfQnOecdECuG1XelrjBJkgqIYWocu3BhvIv8mJ7qqzwNFv8JrL0H2scQyiRJKlCGqXFsQV0FM6dMGtu8KYh3RG/dD88+kJrCJEkqIIapcSyEwAUL4y0STnR0jf5EDa+BmkV2RJckaRQMU+PcRYtqOXK8gzVbx9AiIYR4m4Qda2Dnk6krTpKkAmCYGudeffo0imNhbE/1AZx1LZSU2SZBkqQRMkyNc5WlJTQ3TB17mCqdDGe+Df54f3z+lCRJSophKg9cuLCO518+xK5DbWM70cqboaMVnrovNYVJklQADFN54KJF3S0Sxjo6NWMZzDo3PhE9ilJQmSRJ+c8wlQcWn1bJ9KqJY+s31WPlu2HvRtj4s7GfS5KkAmCYygMhBC5cWMuvNrTQ0TmGFgkAS66GyXPg4f8BXZ2pKVCSpDxmmMoTFy6s41BbB2u3HRjbiUpK4Y2fhF3PwJP/nJriJEnKY4apPPGaxhqKUtEiAaDpLTDnVfCzv4W2g2M/nyRJecwwlScmTyrh7NlTeCQV86ZCgMs+A8f2wqOfG/v5JEnKY4apPHLRolr+uOMge44cH/vJ6s+G5dfD43fA3k1jP58kSXnKMJVHLlxYB8CjqbjVB/D6/w5FE+A/Pp6a80mSlIcMU3mkqb6KmooJqZk3BVA1A1771/DC/4MXH03NOSVJyjOGqTwSiwUuaKzl0fUtdHalqOnmq/4y3irhx39jqwRJkhIwTOWZCxfVsv9YO3/ckaKn8Eom2SpBkqQhGKbyzGsbawmB1HRD72GrBEmSBmWYyjPV5RNYNmsKj6zfnbqT2ipBkqRBGaby0EULa3lq2wH2Hz2RupPaKkGSpIQMU3nowkW1dEXwq417UntiWyVIkjSAYSoPnTVrClPKSlI7bwq6WyXcaqsESZJ6MUzloaJY4LWNtfxyfQtdqWqR0ONVH7JVgiRJvRim8tRFC2vZc+Q4z718KLUntlWCJEl9GKby1AULawFS1w29N1slSJJ0kmEqT9VWTmTpzKrUz5sCWyVIktSLYSqPXbiwljUv7edQW3vqT26rBEmSAMNUXrtoUR2dXVF6RqfAVgmSJGGYymvnzJnKaVWlPPDkjvRcwFYJkiQZpvJZUSzwp+fM5JfrW9h9uC09FznZKuGjtkqQJBUkw1See+uKWXR2RfzwyZ3pucDJVgl/hF99Pj3XkCQphxmm8tzptRWcM2cK96/ZThSluIFnj6a3wJlvg1/8HTz7QHquIUlSjjJMFYBrVsxm3a7DPLMjxQ08e4QAV34JZp8HD7wftq9Jz3UkScpBhqkC8OZlM5hQHOP+NdvSd5GSUvize6CiDr5zLRxI47UkScohhqkCMHlSCZc2ncYPn9rJ8Y40ThKvqIXrvw8dbXDvn8Hxw+m7liRJOcIwVSCuWTGLA8fa+fnzu9N7obrF8LZvQ8sLcP+7fcJPkpT3DFMF4jULapheNZH712xP/8UWXAxv+gfY8BP4ycfSfz1JkrLIMFUg4j2nZvFIOntO9bbyZjjvA/C7O+CJb6T/epIkZYlhqoC89Zw095zq79JPQeOl8NB/hY0PZ+aakiRlmGGqgCyoq+DsdPec6i1WBNd8E+rOgO/fBLufT/81JUnKMMNUgblmxaz09pzqb2IlXHcfFJfCvW+HI2ladFmSpCwxTBWYP1lWn/6eU/1NmR0PVEd2w33XQ3sG5mxJkpQhhqkCk7GeU/3NWgFv+Rps/z388C8hE7cZJUnKAMNUAcpYz6n+mq6G1/93eOZ++OXfZ/bakiSliWGqAGW051R/r/3PcNb18Mhn4I/3Z/76kiSlmGGqAPXuOdVy+HhmLx4CXPEFmPNq+MEHYd2/Z/b6kiSlmGGqQJ3sObV2R+YvXjwRrr0HahfFF0X+yceg40Tm65AkKQUMUwVqQV0Fy2dP4furM9Rzqr+yanj3f8DK98BjX4JvXQb7t2S+DkmSxsgwVcB6ek49uzNDPaf6KymFN38O3n437NkIX70AnvthdmqRJGmUDFMF7IqTPaeyMBG9tyVXwfsfhZoF8L13wI/+i72oJEnjhmGqgE0uK+GSJdP5wdodme05lcjUBrjpx/CqD8ETX4dvvhH2bspuTZIkJcEwVeB6ek794oUM95xKpHhCfHHk674LB7fB1y6wfYIkKecZpgrcaxtrs9dzajCLLoP3/xqmL4V/fTc8+J/gxLFsVyVJUkKGqQJXFAu85exZ/GJdFnpODWXyLHjnj+JNPv/wz/D118PuF7JdlSRJAximxDUrZmav59RQiorh4o/Djf8KR1vg66+DJ+9xXT9JUk4xTIkFdZXZ7Tk1nAUXwwd+AzNXwA8/CN+6HDb8h6FKkpQTDFMCcqDn1HAqT4N3/BDe9Dk4uB3uuQa+9lp45t+gK8tPIkqSCpphSkAO9ZwaSqwIzn0P/NWTcPUd8V5U998EX1oZn1flkjSSpCxIKkyFEC4LIawLIWwMIdw2yDFvDyE8F0J4NoRwb2rLVLpNLivhjbnSc2o4RSWw/Hr4y9/Fu6dPrIAHPwRfXA6P3wEnjma7QklSARk2TIUQioAvA5cDS4DrQghL+h3TCPwNsCqKoibgljTUqjTLqZ5TyYgVxbunv/eX8UnqUxvgx7fBF86ER/8RWg9ku0JJUgFIZmTqXGBjFEWboyg6AdwHXNXvmPcAX46iaD9AFEXj5G9j9fbaBTXUVeZYz6lkhAAL3gA3PQTv+gnMbIaf/x38r6Xw8CfgiH8cJUnpk0yYmgls6/V+e/e23hYCC0MIvwkhPB5CuCzRiUII7w0hrA4hrG5paRldxUqb4qIYbzlnZu71nBqJOefDDd+D9/0KGt8Iv/5CfKTqvhtgzf+BQy9nu0JJUp5JJkyFBNv6P5NeDDQCFwHXAd8IIUwZ8KEoujOKouYoippra2tHWqsy4G0rZtHZFfHPj2/NdiljM2MZvO1b8KHVcM474OWn4P/+FXx+MXztQvjFp2HHGujqynalkqRxLpkwtR2Y3ev9LGBngmN+GEVRexRFLwLriIcrjTML6iq5tGk63/r1ixw4lgdPx9UsgDf9I9zyR/jAb+NNQItL43Oqvv56+J+L4Ad/Cc89CMcPZ7taSdI4FIZr0hhCKAbWAxcDO4AngOujKHq21zGXAddFUfQXIYQa4ElgeRRFewc7b3Nzc7R69eoUfAtKtRdeOcTl//tXfODC0/mvly3OdjnpcXQvbHwYNvwk/tp2EGIl0LAKGi+FhZdC9fz4fCxJUsELIayJoqg54b5kOl6HEN4EfAEoAu6KouhTIYTbgdVRFD0YQgjA/wQuAzqBT0VRdN9Q5zRM5bb/9J0n+dnzu3j0v76OmoqJ2S4nvTrbYdvvYP1P4r/2rItvnzgZahdCzaK+r1Pmxp8klCQVjDGHqXQwTOW2TS1HeOPnf8m7Vs3jv/3JkuE/kE/2vQibfga7n4eWdbBnPRzZdWp/cSlMaxwYtKadDsV5HjwlqUANFaaKM12MxofTayu4+uyZ/PPjW3nPBfOZXlWa7ZIyp3oeVN/cd1vrfmhZHx+16glY21fHl7PpeR4jxKC8DirqoGJ696+6Xq+9vp5Y5S1EScoThikN6v+7uJEfrt3JV36xkU9etTTb5WTXpKkw57z4r95OHIO9G+MBa+8GOPxyvK/VkV2w+7n4a1fHwPMVl54KV5OmQukUKJ0Mk7pfS6f0/bpn34RKiLkKVNp1dUFXe/wWcNQFUWd8Ye2oK/6rq/PU14l+ARC6A3P3a++vT26L9d3W42TQTrSt3/aEBrnjEEWn9vV83eeVBNu6X7s6ur/vzu6vu3p93bO989TXQ513qFoS/Tz7/Lyj7vN39dvW1X2Orvhp+7yP+n7du9aujr7fx4BtXfHXWBHEiqFoQnwVhlhx/LVoQr+vS6CoOP4Kvf78dHX/zHq/76TPn6+uzlN/LkIsfs0Qg1DU633o975nf8/nev+5ivX71WvbgD8DiX7vE2xL9nvp2ZbIgH9IhmH2J3FM/dnxdjhZYpjSoOZOK+dtK2bxnd9v470Xns7MKZOyXVLumVAWb8MwY1ni/V1d0HYgHqqO7DoVtPp/vWd9vGN720EG/YsQ4v8TnFgFJWVQUgrFk/q9lkLJpMSvseKB/0Pt+Z/qYP/T7eqI/+rsfu1qH+Z9x9D1D6bPX4b9/lKl91+w/Y4bEGo6+x7X/y/irvbuWruDUldH/LXzxKmvu9p7BSLljd7BNVYcDyCx4vg/Tk6+7/51cl/Rqf9uoq5Tfz46O7r/zPT/89Q+snoGBKVYrz+7/ULKaP67ygn9g1Gavo/mdxumlLs+9PoF/OsftvOln2/kM396ZrbLGX9iMSirjv+qO2P4oWGcYAAAFfxJREFU47u64MTheKjqCVdtBwa+bz8WX+i5ow3aW+Ovx/b1fd/z2tGWxu+v5NS/0nv+8ukJaMmKokH+RR36Br/e2wkD/5U+4F/z3V8XTzz1L/feowZFJf3eT+i3r3u0YcAoQOj7l2D/a/f/3nqPuCQc9ekZOTn5oV6f7bdtwPYhDHobOdBn5Kv/iNnJz4Z+P+tYr3DRO3QkCCB9gvpg501US68wH/v/27vzKLnKOo3jz+/W2mu6SUKC6XQIgRAWSQhhEwcCMg44CMqAgjLC4JFlWNTRcTtHnXFGHY/IoowLAopnlEVAYBgXEDB4gANkY0skkBBICGbv7vRW6zt/3Fvd1Z1OZ6nuut1V3885fe7aVT9e3lSevPe9twa3b2Tn44N/Z6f+42nX7TAKCiN4xcFql6NIe1lX8WjPkCNCxf1p0D8+Bo+aFkbA/AIH1jJsfxjiz9guR9D2se2H6t877Rt7wZIwhWG1NNfqgmNbdedzb+nKU2apdWJt2CVVNs8LLu1NkJpaR+Y183k/UA34QB18SWWoD13X/xdkcWDqW+eORmAAs+ByX2x0XrsQXivZUAFsHMwvJUxht6469WDdvXidvv/4a7ru/Llhl4O95Xn+5UgAwKhgJit2a+qEpC46fobuX7peazZ3hl0OAABjCmEKe+TKhbOUiEZ002OvhV0KAABjCmEKe2RyQ0KfeM8MPfTCBq3ayHfYAQBQQJjCHrvi5Fmqi0d14x9XhV0KAABjBmEKe6y5Lq5LTzpQv33pr3plQ3vY5QAAMCYQprBXPvk3B6kxGdUNjzI6BQCARJjCXppQE9On/uYg/XHlJi1f1xZ2OQAAhI4whb32T++dqebamK5ndAoAAMIU9l59IqrLT5mlJ1dt1uK128IuBwCAUBGmsE8+ceIMTaqP63uPMDoFAKhuhCnsk9p4VFcuPFjPrNmqp1dvCbscAABCQ5jCPvv48a2a0pjQ9Y+sktvTb7IHAKDCEKawz5KxiK4+9WAtfnO7nnyN0SkAQHUiTKEkHzl2uqY11ej6R15ldAoAUJUIUyhJIhrRte87WC+sb9fDL74TdjkAAJQdYQolO3d+i+a2TNBXfvOS1m3rDrscAADKijCFksUinn5w4XzJSdfetUyZXD7skgAAKBvCFEZE68Rafevcd2vZW208ewoAUFUIUxgxH5z7Ll143HT9eNFqPblqc9jlAABQFoQpjKivnXWEZk+p17/cs1ybdvSGXQ4AAKOOMIURVROP6OaPzVdnKqvP3r1c+TyPSwAAVDbCFEbc7CkN+voHj9BTr2/VjxatDrscAABGFWEKo+KCY6frrKMO0PWPrtLitdvCLgcAgFFDmMKoMDN969x3a1pTja69c5nautNhlwQAwKggTGHUNCZj+sGFR2tzZ0pfuPdFvm4GAFCRCFMYVXOnN+mLZ8zRIys26hfPvBl2OQAAjDjCFEbdpSfN1KmHTtY3/2+lXtnQHnY5AACMKMIURp3nma47f66a62K65lfL1JXKhl0SAAAjhjCFsphYn9CNHz1aa7d26asPvhx2OQAAjBjCFMrmxFkTdc1ph+j+pW/rviXrwy4HAIARQZhCWV1z2sE6buZ++uqDL2v15s6wywEAoGSEKZRVNOLppgvmKRH1dPWvlqk3kwu7JAAASkKYQtkdMKFG150/Vyvf6dDFtz+n7V080BMAMH4RphCK9x02RTddME/L3mrTuT96Wmu45AcAGKcIUwjNOfOm6c7LjldHT0Yf/uHTemb11rBLAgBgrxGmEKpjZuynB646Sfs3JPSPtz2re55fF3ZJAADsFcIUQjd9v1rd98/v0YmzJuoL972ob/9upfJ5vscPADA+EKYwJjQmY/rZJcfqohNa9ZNFa3TlL5eoO82T0gEAYx9hCmNGNOLpP845Ul8763A9umKjPvKTZ7SxozfssgAAGBZhCmOKmenS987UrRcv0Bubu3TOzU/p5bf5cmQAwNhFmMKYdNqcKbr3yvfIM+n8Hz+jR175a9glAQAwJMIUxqzDDmjUA1edpNlT6nX5/yzRLU+ulnNMTAcAjC2EKYxp+zcmdfflJ+oDRx6gb/32L/ry/S8pleUraAAAY0c07AKA3UnGIvrBhUdr5qQ63fzE63rujW362gcP18JD9w+7NAAAGJnC+OB5ps//3aG649LjJEmX/Ox5feoXi/XW1u6QKwMAVDvCFMaVU2ZP1u8/c7K+dOYcPfX6Fp1+wyJd/8ir6klz6Q8AEA7CFMadeNTTFafM0uOfW6gzj5yq7z/+uk6/fpF+99I7TFAHAJQdYQrj1tQJSd10wdG6+7IT1JCM6spfLtVFtz2r1zbuCLs0AEAVIUxh3Dv+oIl6+Jr36hvnHKGX1rfrzJv+rP98eIV29GbCLg0AUAUIU6gI0YinT5x4oJ74/EKdv6BFtz31hk69bpHuW7KeL00GAIwqwhQqysT6hL597lF68KqT1NJco8/9+gWd9+On9ccVG5XJ5cMuDwBQgSysCbsLFixwixcvDuW9UR3yead7l67Xd//wqjbvSGlSfVwfmjdN5y1o0ZypjWGXBwAYR8xsiXNuwZDHCFOodJlcXote3axfL1mnx1ZuUjbv9O5pE3TeMS06e+671FwXD7tEAMAYR5gCAls7U3rohQ26d8l6vbKhQ7GI6fTDpuj8BS06+ZDJika48g0A2BlhChjCig0dunfJej2w/G1t60prUn1C586fpvOOadHsKQ1hlwcAGEMIU8Aw0tm8/vTqJt27ZL0e/4t/GfColgk6ZfZkzW9t1tGtTWqq5VIgAFSz4cIUX3SMqhePenr/EVP1/iOmamtnSg8u36AHl7+tH/5ptXLBYxUO3r9e81ubdMyMZh0zo1kHTaqX51nIlQMAxgJGpoBd6E5n9cK6di19a7uWvLldS9/arrZu/0Ggjcmo5s9o1jGtfriaO71JdQn+bQIAlarkkSkzO0PSTZIikm51zv3XoOOXSPqupLeDXTc7527d54qBMaA2HtWJsybqxFkTJUnOOa3Z0qWlQbBa8uZ2LVq1Wc5JnkmHTm3UnKkNmjmpbsAPIQsAKttuR6bMLCJplaS/lbRe0vOSLnTOrSg65xJJC5xzV+/pGzMyhUrQ3pPR8nVtWvLmdi1f16bVmzq1ob1HxX+spjQmdNCkes2cXKeDikLW9P1qFePuQQAYF0odmTpO0uvOuTXBi90l6RxJK4b9LaAKTKiJ6ZTZk3XK7Ml9+3ozOa3d2qU3NndpzZYuvRH8/P7lv2pbV7rvvIhnmt5coymNSU1qSGhyfUKT6uOaVJ/wfxr6t5OxSBj/eQCAPbAnYWqapHVF2+slHT/Eef9gZifLH8X6rHNu3eATzOwySZdJUmtr695XC4wDyVhEc6Y2DvmU9bbutB+wNgcha2uXNnektGJDh7bsSGlHKjvkazYkogPCVVNtXE21MTXVxNRUG9OEmniwjAX740rGPJkxSR4ARtuehKmhPo0HXxv8X0l3OudSZnaFpDsknbbTLzl3i6RbJP8y317WCox7TbVxzW+Na35r85DHezM5belMaUtnWlt2pIJ1f3tzZ0pbdqS0auMOtfdk1NadUXaYL3GOR72isBVTU21czbUxNdfG+8JYc21hf7xvPR7l0iMA7I09CVPrJU0v2m6RtKH4BOfc1qLNn0r6TumlAdUnGYuopblWLc21uz3XOafudE5tPRm1dafV3p1RW0+mL2i19QT7gvV127r14vq0tndnlM7u+kuf6+IRP2DV+SNcE2piaqzpH/WaUFgftL8+EWUkDEBV2pMw9bykQ8xspvy79S6Q9LHiE8zsAOfcO8Hm2ZJWjmiVAHZiZqpLRFWXiGpaU80e/55zTj2ZnNq6M9rene5bbu/OqK0rWHantb07rfaejN5p71F7ENIyuV2PhEU8U2MyOiB8NSb99caaaN924fjgc5mMD2C82m2Ycs5lzexqSX+Q/2iE251zr5jZNyQtds49JOlaMztbUlbSNkmXjGLNAEpgZqqNR1Ubj+pd+xjCCuGqvSej9qLttp60Onqy6uj1tze09ai9J6uOnozSuV2PhklSfSLqz/cK5nxNKFyGHDAfrHA50g9mDckYc8MAhI6HdgIoi95MTh1B6CqErY6ebH8QC0bECpct24r2DTM1TLGIqSHpj3Q1JP1RsIZEsEwWQlc0+PHPqw/WG5JR1Sei3C0JYLf4OhkAoUvGIkrGItq/MblXv5fPO3Wms33zv7YHQaujJ6Mdvf4oWPH6jt6sNnV09m13p3O7fY94xAsCVrQvYDUkY2pIBNvJqOoTMf+chH+87/xgf30iyuR9oEoRpgCMaZ5n/tyrZEzT99v738/m8gOC1o7erDpTWe3ozQRL/1hncKywf9227r5zO1PZvu9pHE486qkhEVUi6ike9ZSIRhQP1uMRr3896ilRvF20Hov0b8f6lqbEgG1/WZ/on4vG5U4gPIQpABUtGvHUXBdXc118n1/DOafeTF47Uv2hqxDEOlNZdRaCWSqrzt6sejN5pXN5pbM5pbOF9by6u7NKFW0XjqUyeWVy+WEfdbE7sYj1BauGQRP8G5P9NwHUJ6Kqi0dVm4ioLh5VXSKiuoQ/h64uHlGUGwGAvUaYAoDdMDPVxCOqiUe0f8PovU8+75TO+cEqnc0rk3MDwlgm569nsnmlcnl19l3mzBbNQ8uoo9ef9P/29p6+/cPdiVksEfWCcBVRfbAsXKJNRL3gJ6JEzNtpXzLWfywR9ZQIjidjESUH/U5hyV2cqASEKQAYIzzPlPQiIz4h3jmnVDav9h5/BK07lVNXOquuVFZd6Zy6g0uZ3elcsM8/pzNYT2X8S6WpbE6pbF69GX+ZyuTVm82plPuYIp4NCFd9AW1AEPO3/aXXH8yiQdCL+8dq4hHVxPrDXzLmqSbmh+Bk1F8molwOxcgjTAFAhTOzvoAxZYRf2zmnbN4F4Sqn3iBspYNlbyavVLZ/WQhgqUxwfPC+otdJZXJq78loU2ZgiPNfNzfsXZ7D6Qtpsf5Rs2QsCGyDwlvhvMZk8NDa2njfQ2sLj/FoSEbleQS0akaYAgDsMzNTLGKKRfwJ8eWUyfnBqifjB7GeIGT1pHPBev/xvmW6P6j1BiGut+jcweGtcKwns+u7Qs3UF7Am1Mb9ZU1MiainiGfyPFPETJ6pb33Afs8/FjFTJNJ/POKZosF5Uc/kmSkaMUU8b8A5sYgNcdNC8Y0MNmAfwW/kEaYAAONSLOIHhIZkbNTfK5PL9z0Prb0nHTwDLfgKp+LnogXPSVu7tUvpbF65vFPeuWDpz4vL9W337y+nqBeEsqJAFvE8RTwp6nnyCkvzl4Vz4n3z4/rvVk0El1771ovnzA15vP8S7k7r0YhiERuXl2EJUwAA7EYs4mlSfUKT6hOj8vrFIStXWM8N2pf3L6nmBv1k8kU3KATLVNENDJlc8b58X8gb8FpF75cvHBtUQya487QrlfYv6wYjfIX1ws0SpTDz2zoR8RQbYlStsO7vjygejIouPHSyPnps6wj939h7hCkAAELmeSZPpvH+MP7CHamFeXDpbPGcuf55c4WbGQasF+bb5fLKZJ3SuZwy2SDEBXex9t/R6vyvqQr2zZnaGOp/N2EKAACMiOI7Uido9C+/jhU84AMAAKAEhCkAAIASEKYAAABKQJgCAAAoAWEKAACgBIQpAACAEhCmAAAASkCYAgAAKAFhCgAAoASEKQAAgBIQpgAAAEpAmAIAACgBYQoAAKAEhCkAAIASEKYAAABKQJgCAAAoAWEKAACgBIQpAACAEhCmAAAASkCYAgAAKAFhCgAAoASEKQAAgBIQpgAAAEpgzrlw3thss6Q3y/BWkyRtKcP7jGW0AW0g0QYSbSDRBhJtINEG0t63wQzn3OShDoQWpsrFzBY75xaEXUeYaAPaQKINJNpAog0k2kCiDaSRbQMu8wEAAJSAMAUAAFCCaghTt4RdwBhAG9AGEm0g0QYSbSDRBhJtII1gG1T8nCkAAIDRVA0jUwAAAKOGMAUAAFCCig1TZnaGmb1qZq+b2ZfCricMZrbWzF4ys+VmtjjsesrBzG43s01m9nLRvv3M7FEzey1YNodZ42jbRRv8m5m9HfSF5Wb2gTBrHG1mNt3MnjCzlWb2ipl9OthfNX1hmDaomr5gZkkze87MXgja4N+D/TPN7NmgH9xtZvGwax0tw7TBz83sjaJ+MC/sWkebmUXMbJmZPRxsj1g/qMgwZWYRSf8t6UxJh0u60MwOD7eq0JzqnJtXRc8T+bmkMwbt+5Kkx5xzh0h6LNiuZD/Xzm0gSTcEfWGec+63Za6p3LKSPuecO0zSCZKuCj4Dqqkv7KoNpOrpCylJpznn5kqaJ+kMMztB0nfkt8EhkrZL+mSINY62XbWBJP1rUT9YHl6JZfNpSSuLtkesH1RkmJJ0nKTXnXNrnHNpSXdJOifkmlAGzrknJW0btPscSXcE63dI+lBZiyqzXbRBVXHOveOcWxqs75D/ATpNVdQXhmmDquF8ncFmLPhxkk6TdG+wv9L7wa7aoKqYWYukv5d0a7BtGsF+UKlhapqkdUXb61VlHyIBJ+kRM1tiZpeFXUyIpjjn3pH8v2Ak7R9yPWG52sxeDC4DVuzlrcHM7EBJR0t6VlXaFwa1gVRFfSG4tLNc0iZJj0paLanNOZcNTqn4vx8Gt4FzrtAPvhn0gxvMLBFiieVwo6QvSMoH2xM1gv2gUsOUDbGv6pK4pJOcc/PlX+68ysxODrsghOZHkmbJH+Z/R9L3wi2nPMysXtJ9kj7jnOsIu54wDNEGVdUXnHM559w8SS3yr1ocNtRp5a2qvAa3gZkdKenLkuZIOlbSfpK+GGKJo8rMzpK0yTm3pHj3EKfucz+o1DC1XtL0ou0WSRtCqiU0zrkNwXKTpN/I/yCpRhvN7ABJCpabQq6n7JxzG4MP1Lykn6oK+oKZxeSHiF865+4PdldVXxiqDaqxL0iSc65N0p/kzx9rMrNocKhq/n4oaoMzgsvAzjmXkvQzVXY/OEnS2Wa2Vv60n9Pkj1SNWD+o1DD1vKRDgpn6cUkXSHoo5JrKyszqzKyhsC7p/ZJeHv63KtZDki4O1i+W9GCItYSiECACH1aF94VgPsRtklY6564vOlQ1fWFXbVBNfcHMJptZU7BeI+l0+XPHnpB0XnBapfeDodrgL0X/qDD5c4Uqth84577snGtxzh0oPw887pz7uEawH1TsE9CD231vlBSRdLtz7pshl1RWZnaQ/NEoSYpK+lU1tIGZ3SlpoaRJkjZK+rqkByTdI6lV0luSznfOVewE7V20wUL5l3WcpLWSLi/MHapEZvZeSX+W9JL650h8Rf6coaroC8O0wYWqkr5gZkfJn1gckT94cI9z7hvB5+Nd8i9vLZN0UTBCU3GGaYPHJU2Wf7lruaQriiaqVywzWyjp8865s0ayH1RsmAIAACiHSr3MBwAAUBaEKQAAgBIQpgAAAEpAmAIAACgBYQoAAKAEhCkAAIASEKYAAABK8P8zfrYNxNf0OAAAAABJRU5ErkJggg==\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "# THIS IS SETUP SO THAT YOU CAN COMPARE THE RESULTS AND SEE THAT THEY ARE EXACT. \n", - "# UNCOMMENT LINE `DEBUG_ERROR` AT TOP OF THIS NOTEBOOK TO TEST THAT THESE ARE \n", - "# TRULY CALCULATED VALUES\n", - "\n", - "fit_tsk = NewTask(\n", - " name='fit model', \n", - " handler=fit,\n", - " params={\"num_boost_round\" : 40, \n", - " \"verbose_eval\" : False,\n", - " \"XGB_max_depth\" : 2,\n", - " \"XGB_subsample\" : 0.9}\n", - ")\n", - "\n", - "fit_run = run_local(fit_tsk, inputs={\"dataset\":outliers_run.outputs[\"xgb-outs\"]})" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# export" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[mlrun] 2020-06-14 13:30:50,033 function spec saved to path: function.yaml\n" - ] - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 23, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from mlrun import code_to_function\n", - "from mlrun.platforms.other import auto_mount\n", - "\n", - "gpus = False\n", - "\n", - "# create job function object from notebook code\n", - "fn_params = {\n", - " \"name\" : \"xgb_custom\",\n", - " \"handler\" : \"fit\",\n", - " \"kind\" : \"job\",\n", - " \"image\" : \"mlrun/ml-models\" if not gpus else \"mlrun/ml-models-gpu\",\n", - " \"description\" : \"train an xgboost model using the low-level api\",\n", - " \"categories\" : [\"analysis\"],\n", - " \"labels\" : {\"author\": \"yjb\"}\n", - "}\n", - "\n", - "xgb_fn = code_to_function(**fn_params)\n", - "\n", - "xgb_fn.export(\"function.yaml\")\n", - "xgb_fn.apply(auto_mount())" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "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.6.8" - }, - "toc-autonumbering": false, - "toc-showcode": false, - "toc-showmarkdowntxt": false, - "toc-showtags": false - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/xgb_custom/xgb_custom.py b/xgb_custom/xgb_custom.py deleted file mode 100644 index f80868e7e..000000000 --- a/xgb_custom/xgb_custom.py +++ /dev/null @@ -1,239 +0,0 @@ -# Copyright 2019 Iguazio -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -from os import path -import numpy as np -from numpy.random import randint, randn, seed -import pandas as pd -from xgboost import DMatrix, train -import matplotlib.pyplot as plt -from mlrun.execution import MLClientCtx -from mlrun.datastore import DataItem -from mlrun.artifacts import PlotArtifact -from mlrun.mlutils.data import get_splits, get_sample - -from cloudpickle import dumps - -from typing import (Tuple, Dict, List, Union, Callable) - -seed(seed=1994) - -## UNCOMMENT THIS LINE TO TEST CALCULATED VALUES -DEBUG_ERROR = 0 # this will be added to the custom eval function--set it to some value like 999 - - -def gen_outliers(context: MLClientCtx, nrows=4096, feats=16, - outs=64, omax=10_000, labels_col="labels", - header=[], label_type="int32", key="xgb-outs", - local_path="xgb_custom"): - """simulate data with outliers - - :param context: the function's execution context - :param nrows: (4096) number of data points - :param feats: (16) number of features - :param outs: (64) number of outliers - :param omax: (10_100) max value of outliers - :param labels_col: (labels) name of labels column - :param header: () header for dataset, will default to - `feat_` - :param label_type: (int32) data type for the label column - :param key: key of datset in artifact store - :param local_path: path in artifact store where data will be - serialized - """ - x = randn(nrows, feats) - y = randn(nrows) - y += np.abs(np.min(y)) - - for i in range(0, outs): - ind = randint(0, len(y) - 1) - y[ind] += randint(0, omax) - - if not header: - header = [f"feat_{j}" for j in range(feats)] - header.append(labels_col) - - data = pd.DataFrame(data=np.concatenate((x, y.reshape(-1, 1)), axis=-1), - columns=header) - data = data.astype({labels_col: label_type}) - - context.log_dataset(key, df=data, local_path=local_path) - -def gradient(predt: np.ndarray, dtrain: DMatrix) -> np.ndarray: - """gradient of squared log error""" - y = dtrain.get_label() - return (np.log1p(predt) - np.log1p(y)) / (predt + 1) - - -def hessian(predt: np.ndarray, dtrain: DMatrix) -> np.ndarray: - """hessian of squared log error""" - y = dtrain.get_label() - return ((-np.log1p(predt) + np.log1p(y) + 1) / - np.power(predt + 1, 2)) - - -def squared_log(predt: np.ndarray, dtrain: DMatrix) -> Tuple[np.ndarray, - np.ndarray]: - """squared log error objective - - simplified version for RMSLE used as objective function - """ - predt[predt < -1] = -1 + 1e-6 - grad = gradient(predt, dtrain) - hess = hessian(predt, dtrain) - return grad, hess - -def rmsle(predt: np.ndarray, dtrain: DMatrix) -> Tuple[str, float]: - """ Root mean squared log error metric. - """ - y = dtrain.get_label() - predt[predt < -1] = -1 + 1e-6 - elements = np.power(np.log1p(y) - np.log1p(predt), 2) - return "my_rmsle", float(np.sqrt(np.sum(elements) / len(y))) + DEBUG_ERROR - - -def learning_curves( - context: MLClientCtx, - results: dict, - figsz: Tuple[int, int] = (10, 10), - plots_dest: str = "plots" -) -> None: - """plot xgb learning curves - - this will also log a model's learning curves - """ - plt.clf() - plt.figure(figsize=figsz) - plt.plot(results["train"]["my_rmsle"], label="train-my-rmsle") - plt.plot(results["valid"]["my_rmsle"], label="valid-my-rmsle") - plt.title(f"learning curves") - plt.legend() - - context.log_artifact( - PlotArtifact(f"learning-curves", body=plt.gcf()), - local_path=f"{plots_dest}/learning-curves.html") - - -def fit( - context: MLClientCtx, - dataset: DataItem, - num_boost_round: int = 10, - evals: List[Tuple[DMatrix, str]] = [], - obj: Union[Callable, str] = "", - feval: Union[Callable, str] = None, - maximize: bool = False, - early_stopping_rounds: int = None, - evals_result: dict = {}, - verbose_eval: bool = True, - xgb_model: DataItem = None, - callbacks: List[Callable] = [], - label_column: str = "labels", - encode_cols: dict = {}, - sample: int = -1, - test_size: float = 0.25, - valid_size: float = 0.75, - random_state: int = 1994, - models_dest: str = "models", - plots_dest: str = "plots", - file_ext: str = "csv", - test_set_key: str = "test-set", - gpus: bool = False -) -> None: - """low level xgboost train api - - for the xgboost `train` params see: - https://xgboost.readthedocs.io/en/latest/python/python_api.html#xgboost.train - - Note: the first parameter of xgboost's `train` method is a dict of parameters - supplied to the booster (engine). To modify one of those simply - add a task parameter (when running you supply an mlrun NewTask) with the - prefix "XGB_". So for example, to set the 'tree_method' parameter to 'approx', - add {"XGB_tree_method":"approx"} to the task params key. - - :param context: the function context - :param dataset: the full data set, train, valid and test will be extracted and - each converted to a DMatrix for input to xgboost's `train` - :param label_column: ground-truth (y) labels - :param encode_cols: dictionary of names and prefixes for columns that are - to hot be encoded. - :param sample: Selects the first n rows, or select a sample - starting from the first. If negative <-1, select - a random sample - :param test_size: (0.05) test set size - :param valid_size: (0.75) Once the test set has been removed the - training set gets this proportion. - :param random_state: (1) sklearn rng seed - :param models_dest: destination subfolder for model artifacts - :param plots_dest: destination subfolder for plot artifacts - :param file_ext: format for test_set_key hold out data - :param test_set_key: (test-set), key of held out data in artifact store - :param gpus: (False), run on gpus - """ - raw, labels, header = get_sample(dataset, sample, label_column) - - # hot-encode - if encode_cols: - raw = pd.get_dummies(raw, - columns=list(encode_cols.keys()), - prefix=list(encode_cols.values()), - drop_first=True) - - # split the sample into train validate, test and calibration sets: - (xtrain, ytrain), (xvalid, yvalid), (xtest, ytest) = \ - get_splits(raw, labels, 3, test_size, valid_size, random_state) - - # save test data as regular dataframe as it may be used by other process - context.log_dataset(test_set_key, df=pd.concat([xtest, ytest], axis=1), - format=file_ext, index=False) - - # convert to xgboost DMatrix (todo - dask, gpu) - dtrain = DMatrix(xtrain, label=ytrain) - dvalid = DMatrix(xvalid, label=yvalid) - - boost_params = { - "tree_method": "gpu_hist" if gpus else "hist", - "seed": random_state, - "disable_default_eval_metric": 1, - "objective": "reg:squaredlogerror", - "eval_metric": "rmsle"} - - # enable user to customize `booster param` parameters - for k, v in context.parameters.items(): - if k.startswith('XGB_'): - boost_params[k[4:]] = v - - # collect learning curves / training history - results = dict() - - booster = train( - boost_params, - dtrain=dtrain, - num_boost_round=num_boost_round, - evals=[(dtrain, "train"), (dvalid, "valid")], - evals_result=results, - obj=squared_log, - feval=rmsle, - maximize=maximize, - early_stopping_rounds=early_stopping_rounds, - verbose_eval=verbose_eval, - # xgb_model=xgb_model, - # callbacks: List[Callable] = [] - ) - - context.log_model("model", - body=dumps(booster), - model_file="model.pkl", - artifact_path='artifacts/') - - learning_curves(context, results) \ No newline at end of file diff --git a/xgb_serving/function.yaml b/xgb_serving/function.yaml deleted file mode 100644 index 7073d8ba6..000000000 --- a/xgb_serving/function.yaml +++ /dev/null @@ -1,40 +0,0 @@ -kind: serving -metadata: - name: xgb-serving - tag: '' - hash: 200148a9a4815d8b0394038d973b59eda1776d36 - project: '' - labels: - author: Daniel - categories: - - model-serving - - machine-learning -spec: - command: '' - args: [] - image: mlrun/mlrun - build: - functionSourceCode: IyBDb3B5cmlnaHQgMjAxOSBJZ3VhemlvCiMKIyBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgIkxpY2Vuc2UiKTsKIyB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiMgWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0CiMKIyAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wCiMKIyBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlCiMgZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gIkFTIElTIiBCQVNJUywKIyBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KIyBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kCiMgbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuCiMKaW1wb3J0IG9zCmltcG9ydCBqc29uCmltcG9ydCBudW1weSBhcyBucApmcm9tIGNsb3VkcGlja2xlIGltcG9ydCBsb2FkCmltcG9ydCBtbHJ1bgoKCmNsYXNzIFhHQm9vc3RNb2RlbChtbHJ1bi5zZXJ2aW5nLlYyTW9kZWxTZXJ2ZXIpOgogICAgZGVmIGxvYWQoc2VsZik6CiAgICAgICAgbW9kZWxfZmlsZSwgZXh0cmFfZGF0YSA9IHNlbGYuZ2V0X21vZGVsKCIucGtsIikKICAgICAgICBzZWxmLm1vZGVsID0gbG9hZChvcGVuKHN0cihtb2RlbF9maWxlKSwgInJiIikpCgogICAgZGVmIHByZWRpY3Qoc2VsZiwgYm9keSk6CiAgICAgICAgdHJ5OgogICAgICAgICAgICBmZWF0cyA9IG5wLmFzYXJyYXkoYm9keVsiaW5wdXRzIl0sIGR0eXBlPW5wLmZsb2F0MzIpLnJlc2hhcGUoLTEsIDUpCiAgICAgICAgICAgIHJlc3VsdCA9IHNlbGYubW9kZWwucHJlZGljdChmZWF0cywgdmFsaWRhdGVfZmVhdHVyZXM9RmFsc2UpCiAgICAgICAgICAgIHJldHVybiByZXN1bHQudG9saXN0KCkKICAgICAgICBleGNlcHQgRXhjZXB0aW9uIGFzIGU6CiAgICAgICAgICAgIHJhaXNlIEV4Y2VwdGlvbigiRmFpbGVkIHRvIHByZWRpY3QgJXMiICUgZSkKZnJvbSBtbHJ1bi5ydW50aW1lcyBpbXBvcnQgbnVjbGlvX2luaXRfaG9vawpkZWYgaW5pdF9jb250ZXh0KGNvbnRleHQpOgogICAgbnVjbGlvX2luaXRfaG9vayhjb250ZXh0LCBnbG9iYWxzKCksICdzZXJ2aW5nX3YyJykKCmRlZiBoYW5kbGVyKGNvbnRleHQsIGV2ZW50KToKICAgIHJldHVybiBjb250ZXh0Lm1scnVuX2hhbmRsZXIoY29udGV4dCwgZXZlbnQpCg== - commands: [] - code_origin: https://github.com/daniels290813/functions.git#2675b0d235d93571a696296c93cfb2103cbf261f:/Users/Daniel_Sabba/functions/xgb_serving/xgb_serving.py - origin_filename: /Users/Daniel_Sabba/functions/xgb_serving/xgb_serving.py - requirements: [] - description: deploy an XGBoost model server. - default_handler: '' - disable_auto_mount: false - clone_target_dir: '' - env: [] - priority_class_name: '' - preemption_mode: prevent - min_replicas: 1 - max_replicas: 4 - source: '' - function_kind: serving_v2 - function_handler: xgb_serving:handler - base_image_pull: false - default_class: ClassifierModel - secret_sources: [] - affinity: null - tolerations: null - security_context: {} -verbose: false diff --git a/xgb_serving/item.yaml b/xgb_serving/item.yaml deleted file mode 100644 index 413e26bfa..000000000 --- a/xgb_serving/item.yaml +++ /dev/null @@ -1,29 +0,0 @@ -apiVersion: v1 -categories: -- model-serving -- machine-learning -description: deploy an XGBoost model server. -doc: '' -example: xgb_serving.ipynb -generationDate: 2022-08-28:17-25 -hidden: false -icon: '' -labels: - author: Daniel -maintainers: [] -marketplaceType: '' -mlrunVersion: 1.4.1 -name: xgb_serving -platformVersion: 3.5.3 -spec: - customFields: - default_class: ClassifierModel - filename: xgb_serving.py - handler: handler - image: mlrun/mlrun - kind: serving - requirements: [] -url: '' -version: 1.1.2 - - diff --git a/xgb_serving/requirements.txt b/xgb_serving/requirements.txt deleted file mode 100644 index a5bbcdde3..000000000 --- a/xgb_serving/requirements.txt +++ /dev/null @@ -1,7 +0,0 @@ -pandas -xgboost -cloudpickle -pygit2 -scikit-learn==1.0.2 -scikit-plot -seaborn diff --git a/xgb_serving/test_xgb_serving.py b/xgb_serving/test_xgb_serving.py deleted file mode 100644 index 52f6ccb6d..000000000 --- a/xgb_serving/test_xgb_serving.py +++ /dev/null @@ -1,67 +0,0 @@ -# Copyright 2019 Iguazio -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -import mlrun -import os -import pandas as pd -from xgb_serving import XGBoostModel - - -def get_class_data(): - fn = mlrun.import_function('../gen_class_data/function.yaml') - run = fn.run(params={'key': 'classifier-data', - 'n_samples': 10_000, - 'm_features': 5, - 'k_classes': 2, - 'header': None, - 'weight': [0.5, 0.5], - 'sk_params': {'n_informative': 2}, - 'file_ext': 'csv'}, local=True, artifact_path="./artifacts") - return run - - -def xgb_trainer(): - # running data preparation function locally - gen_data_run = get_class_data() - - fn = mlrun.import_function('../xgb_trainer/function.yaml') - run = fn.run(params={'model_type': 'classifier', - 'CLASS_tree_method': 'hist', - 'CLASS_objective': 'binary:logistic', - 'CLASS_booster': 'gbtree', - 'FIT_verbose': 0, - 'label_column': 'labels'}, - local=True, inputs={'dataset': gen_data_run.status.artifacts[0]['spec']['target_path']}) - - for artifact in run.status.artifacts: - if artifact['kind'] == 'model': - assert os.path.exists(artifact['spec']['target_path']), "Failed locating model file" # validating model exists - return artifact['spec']['target_path'] + artifact['spec']['model_file'], gen_data_run.status.artifacts[0]['spec']['target_path'] - assert False, "Failed creating model" - - -def test_local_xgb_serving(): - model_path, dataset_path = xgb_trainer() - fn = mlrun.import_function('function.yaml') - - fn.add_model(key='my_model', model_path=model_path, class_name='XGBoostModel') - server = fn.to_mock_server() - - # Testing the model - df = pd.read_csv(dataset_path) - x = df.drop(['labels'], axis=1).iloc[0].tolist() - y_true = df['labels'][0] - - y_pred = server.test(path='/v2/models/my_model/predict', body={"inputs": x})['outputs'][0] - assert y_true == y_pred diff --git a/xgb_serving/xgb_serving.ipynb b/xgb_serving/xgb_serving.ipynb deleted file mode 100644 index 6c605367e..000000000 --- a/xgb_serving/xgb_serving.ipynb +++ /dev/null @@ -1,421 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Deploy a Serverless XGBoost Model Server\n", - " --------------------------------------------------------------------\n", - "\n", - "The following notebook demonstrates how to deploy an XGBoost model server (a.k.a Nuclio-serving)\n", - "\n", - "#### **notebook how-to's**\n", - "* Write and test model serving class in a notebook.\n", - "* Deploy the model server function.\n", - "* Invoke and test the serving function." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "#### **steps**\n", - "**[define a new function and its dependencies](#define-function)**
\n", - "**[test the model serving class locally](#test-locally)**
\n", - "**[deploy our serving class using as a serverless function](#deploy)**
\n", - "**[test our model server using HTTP request](#test-model-server)**
" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "# nuclio: ignore\n", - "import nuclio " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "### **define a new function and its dependencies**" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "%nuclio: setting kind to 'nuclio:serving'\n", - "%nuclio: setting 'MODEL_CLASS' environment variable\n", - "%nuclio: setting spec.build.baseImage to 'mlrun/ml-models'\n" - ] - } - ], - "source": [ - "%nuclio config kind=\"nuclio:serving\"\n", - "%nuclio env MODEL_CLASS=XGBoostModel\n", - "\n", - "%nuclio config spec.build.baseImage = \"mlrun/ml-models\"" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Function Code" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "# import kfserving\n", - "import os\n", - "import json\n", - "import numpy as np\n", - "import xgboost as xgb\n", - "from cloudpickle import load\n", - "\n", - "### Model Serving Class\n", - "\n", - "import mlrun\n", - "class XGBoostModel(mlrun.runtimes.MLModelServer):\n", - " def load(self):\n", - " model_file, extra_data = self.get_model(\".pkl\")\n", - " self.model = load(open(str(model_file), \"rb\"))\n", - " \n", - "\n", - " def predict(self, body):\n", - " try:\n", - " feats = np.asarray(body[\"instances\"], dtype=np.float32).reshape(-1, 5)\n", - " result = self.model.predict(feats, validate_features=False)\n", - " return result.tolist()\n", - " except Exception as e:\n", - " raise Exception(\"Failed to predict %s\" % e)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The following end-code annotation tells ```nuclio``` to stop parsing the notebook from this cell. _**Please do not remove this cell**_:" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [], - "source": [ - "# nuclio: end-code" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "## Test the function locally\n", - "\n", - "The class above can be tested locally. Just instantiate the class, `.load()` will load the model to a local dir.\n", - "\n", - "> **Verify there is a model file in the model_dir path (generated by the training notebook)**" - ] - }, - { - "cell_type": "code", - "execution_count": 36, - "metadata": {}, - "outputs": [], - "source": [ - "from mlrun import mlconf\n", - "\n", - "model_dir = os.path.join(mlconf.artifact_path, \"xgb/models\")\n", - "\n", - "my_server = XGBoostModel(\"my-model\", model_dir=model_dir)\n", - "my_server.load()" - ] - }, - { - "cell_type": "code", - "execution_count": 37, - "metadata": {}, - "outputs": [], - "source": [ - "DATA_PATH = mlconf.artifact_path + \"/xgb/classifier-data.csv\"\n", - "MODEL_PATH = mlconf.artifact_path + \"/xgb/models/xgb_test\"" - ] - }, - { - "cell_type": "code", - "execution_count": 38, - "metadata": {}, - "outputs": [], - "source": [ - "import pandas as pd\n", - "xtest = pd.read_csv(DATA_PATH)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can use the `.predict(body)` method to test the model." - ] - }, - { - "cell_type": "code", - "execution_count": 39, - "metadata": {}, - "outputs": [], - "source": [ - "import json, numpy as np\n", - "preds = my_server.predict({\"instances\":xtest.values[:10,:-1].tolist()})" - ] - }, - { - "cell_type": "code", - "execution_count": 40, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "predicted class: [1, 0, 0, 0, 0, 0, 1, 1, 0, 1]\n" - ] - } - ], - "source": [ - "print(\"predicted class:\", preds)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "### **deploy our serving class using as a serverless function**\n", - "in the following section we create a new model serving function which wraps our class , and specify model and other resources.\n", - "\n", - "the `models` dict store model names and the assosiated model **dir** URL (the URL can start with `S3://` and other blob store options), the faster way is to use a shared file volume, we use `.apply(mount_v3io())` to attach a v3io (iguazio data fabric) volume to our function. By default v3io will mount the current user home into the `\\User` function path.\n", - "\n", - "**verify the model dir does contain a valid `model.bst` file**" - ] - }, - { - "cell_type": "code", - "execution_count": 41, - "metadata": {}, - "outputs": [], - "source": [ - "from mlrun import new_model_server, mount_v3io\n", - "import requests" - ] - }, - { - "cell_type": "code", - "execution_count": 42, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[mlrun] 2020-06-14 12:49:05,013 function spec saved to path: function.yaml\n" - ] - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 42, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "fn = new_model_server(\"xgb-serving\",\n", - " model_class=\"XGBoostModel\",\n", - " models={\"xgb_serving_v2\": f\"{model_dir}\"})\n", - "fn.spec.description = \"xgboost test data classification server\"\n", - "fn.metadata.categories = [\"serving\", \"ml\"]\n", - "fn.metadata.labels = {\"author\": \"yaronh\", \"framework\": \"xgboost\"}\n", - "\n", - "fn.export(\"function.yaml\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## tests" - ] - }, - { - "cell_type": "code", - "execution_count": 43, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 43, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from mlrun.platforms.other import auto_mount\n", - "fn.apply(auto_mount())" - ] - }, - { - "cell_type": "code", - "execution_count": 44, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[mlrun] 2020-06-14 12:49:18,128 deploy started\n", - "[nuclio] 2020-06-14 12:49:19,213 (info) Build complete\n", - "[nuclio] 2020-06-14 12:49:27,347 (info) Function deploy complete\n", - "[nuclio] 2020-06-14 12:49:27,354 done updating default-xgb-test, function address: 3.23.82.202:30104\n" - ] - } - ], - "source": [ - "addr = fn.deploy()" - ] - }, - { - "cell_type": "code", - "execution_count": 45, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'http://3.23.82.202:30104'" - ] - }, - "execution_count": 45, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "addr" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "### **test our model server using HTTP request**\n", - "\n", - "\n", - "We invoke our model serving function using test data, the data vector is specified in the `instances` attribute." - ] - }, - { - "cell_type": "code", - "execution_count": 46, - "metadata": {}, - "outputs": [], - "source": [ - "# KFServing protocol event\n", - "event_data = {\"instances\": xtest.values[:10,:-1].tolist()}" - ] - }, - { - "cell_type": "code", - "execution_count": 47, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'[1, 0, 0, 0, 0, 0, 1, 1, 0, 1]'" - ] - }, - "execution_count": 47, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import json\n", - "resp = requests.put(addr + \"/xgb_serving_v2/predict\", json=json.dumps(event_data))\n", - "resp.text" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[1, 0, 0, 0, 0, 0, 1, 1, 0, 1]" - ] - }, - "execution_count": 26, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "preds" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**[back to top](#top)**" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "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.6.8" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/xgb_serving/xgb_serving.py b/xgb_serving/xgb_serving.py deleted file mode 100644 index a4d095e57..000000000 --- a/xgb_serving/xgb_serving.py +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright 2019 Iguazio -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -import os -import json -import numpy as np -from cloudpickle import load -import mlrun - - -class XGBoostModel(mlrun.serving.V2ModelServer): - def load(self): - model_file, extra_data = self.get_model(".pkl") - self.model = load(open(str(model_file), "rb")) - - def predict(self, body): - try: - feats = np.asarray(body["inputs"], dtype=np.float32).reshape(-1, 5) - result = self.model.predict(feats, validate_features=False) - return result.tolist() - except Exception as e: - raise Exception("Failed to predict %s" % e) \ No newline at end of file