{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "## Anomaly Exploration (understanding 'Odd')\n", "In this notebook we're going to be using the zat Python module for processing, transformation and anomaly detection on Zeek network data. We're going to look at 'normal' http traffic and demonstrate the use of Isolation Forests for anomaly detection. We'll then explore those anomalies with clustering and PCA.\n", "\n", "**Software**\n", "- zat: https://github.com/SuperCowPowers/zat\n", "- Pandas: https://github.com/pandas-dev/pandas\n", "- Scikit-Learn: http://scikit-learn.org/stable/index.html\n", "\n", "**Techniques**\n", "- One Hot Encoding: http://pandas.pydata.org/pandas-docs/stable/generated/pandas.get_dummies.html\n", "- Isolation Forest: http://scikit-learn.org/stable/modules/generated/sklearn.ensemble.IsolationForest.html\n", "- PCA: http://scikit-learn.org/stable/modules/generated/sklearn.decomposition.PCA.html\n", "\n", "**Related Notebooks**\n", "- Zeek to Scikit-Learn: https://nbviewer.jupyter.org/github/SuperCowPowers/zat/blob/main/notebooks/Zeek_to_Scikit_Learn.ipynb\n", "\n", "**Note:** A previous version of this notebook used a large http log (1 million rows) but we wanted people to be able to run the notebook themselves, so we've changed it to run on the local example http.log." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "zat: 0.4.4\n", "Pandas: 1.3.5\n", "Numpy: 1.22.1\n", "Scikit Learn Version: 1.0.2\n" ] } ], "source": [ "import zat\n", "from zat.log_to_dataframe import LogToDataFrame\n", "from zat.dataframe_to_matrix import DataFrameToMatrix\n", "print('zat: {:s}'.format(zat.__version__))\n", "import pandas as pd\n", "print('Pandas: {:s}'.format(pd.__version__))\n", "import numpy as np\n", "print('Numpy: {:s}'.format(np.__version__))\n", "import sklearn\n", "from sklearn.ensemble import IsolationForest\n", "from sklearn.decomposition import PCA\n", "from sklearn.cluster import KMeans\n", "print('Scikit Learn Version:', sklearn.__version__)" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Read in 150 Rows...\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", "
uidid.orig_hid.orig_pid.resp_hid.resp_ptrans_depthmethodhosturireferrer...info_msgfilenametagsusernamepasswordproxiedorig_fuidsorig_mime_typesresp_fuidsresp_mime_types
ts
2013-09-15 23:44:27.668081920CyIaMO7IheOh38Zsi192.168.33.10103154.245.228.191801GETguyspy.com/NaN...NaNNaN(empty)NaNNaNNaNNaNNaNFnjq3r4R0VGmHVWiN5text/html
2013-09-15 23:44:27.731702016CoyZrY2g74UvMMgp4a192.168.33.10103254.245.228.191801GETwww.guyspy.com/NaN...NaNNaN(empty)NaNNaNNaNNaNNaNFCQ5aX37YzsjAKpcv8text/html
2013-09-15 23:44:28.092921856CoyZrY2g74UvMMgp4a192.168.33.10103254.245.228.191802GETwww.guyspy.com/wp-content/plugins/slider-pro/css/advanced-sl...http://www.guyspy.com/...NaNNaN(empty)NaNNaNNaNNaNNaNFD9Xu815Hwui3sniSftext/html
2013-09-15 23:44:28.150300928CiCKTz4e0fkYYazBS3192.168.33.10104054.245.228.191801GETwww.guyspy.com/wp-content/plugins/contact-form-7/includes/cs...http://www.guyspy.com/...NaNNaN(empty)NaNNaNNaNNaNNaNFMZXWm1yCdsCAU3K9dtext/plain
2013-09-15 23:44:28.150601984C1YBkC1uuO9bzndRvh192.168.33.10104154.245.228.191801GETwww.guyspy.com/wp-content/plugins/slider-pro/css/slider/adva...http://www.guyspy.com/...NaNNaN(empty)NaNNaNNaNNaNNaNFA4NM039Rf9Y8Sn2Rhtext/plain
\n", "

5 rows × 26 columns

\n", "
" ], "text/plain": [ " uid id.orig_h id.orig_p \\\n", "ts \n", "2013-09-15 23:44:27.668081920 CyIaMO7IheOh38Zsi 192.168.33.10 1031 \n", "2013-09-15 23:44:27.731702016 CoyZrY2g74UvMMgp4a 192.168.33.10 1032 \n", "2013-09-15 23:44:28.092921856 CoyZrY2g74UvMMgp4a 192.168.33.10 1032 \n", "2013-09-15 23:44:28.150300928 CiCKTz4e0fkYYazBS3 192.168.33.10 1040 \n", "2013-09-15 23:44:28.150601984 C1YBkC1uuO9bzndRvh 192.168.33.10 1041 \n", "\n", " id.resp_h id.resp_p trans_depth method \\\n", "ts \n", "2013-09-15 23:44:27.668081920 54.245.228.191 80 1 GET \n", "2013-09-15 23:44:27.731702016 54.245.228.191 80 1 GET \n", "2013-09-15 23:44:28.092921856 54.245.228.191 80 2 GET \n", "2013-09-15 23:44:28.150300928 54.245.228.191 80 1 GET \n", "2013-09-15 23:44:28.150601984 54.245.228.191 80 1 GET \n", "\n", " host \\\n", "ts \n", "2013-09-15 23:44:27.668081920 guyspy.com \n", "2013-09-15 23:44:27.731702016 www.guyspy.com \n", "2013-09-15 23:44:28.092921856 www.guyspy.com \n", "2013-09-15 23:44:28.150300928 www.guyspy.com \n", "2013-09-15 23:44:28.150601984 www.guyspy.com \n", "\n", " uri \\\n", "ts \n", "2013-09-15 23:44:27.668081920 / \n", "2013-09-15 23:44:27.731702016 / \n", "2013-09-15 23:44:28.092921856 /wp-content/plugins/slider-pro/css/advanced-sl... \n", "2013-09-15 23:44:28.150300928 /wp-content/plugins/contact-form-7/includes/cs... \n", "2013-09-15 23:44:28.150601984 /wp-content/plugins/slider-pro/css/slider/adva... \n", "\n", " referrer ... info_msg filename \\\n", "ts ... \n", "2013-09-15 23:44:27.668081920 NaN ... NaN NaN \n", "2013-09-15 23:44:27.731702016 NaN ... NaN NaN \n", "2013-09-15 23:44:28.092921856 http://www.guyspy.com/ ... NaN NaN \n", "2013-09-15 23:44:28.150300928 http://www.guyspy.com/ ... NaN NaN \n", "2013-09-15 23:44:28.150601984 http://www.guyspy.com/ ... NaN NaN \n", "\n", " tags username password proxied orig_fuids \\\n", "ts \n", "2013-09-15 23:44:27.668081920 (empty) NaN NaN NaN NaN \n", "2013-09-15 23:44:27.731702016 (empty) NaN NaN NaN NaN \n", "2013-09-15 23:44:28.092921856 (empty) NaN NaN NaN NaN \n", "2013-09-15 23:44:28.150300928 (empty) NaN NaN NaN NaN \n", "2013-09-15 23:44:28.150601984 (empty) NaN NaN NaN NaN \n", "\n", " orig_mime_types resp_fuids \\\n", "ts \n", "2013-09-15 23:44:27.668081920 NaN Fnjq3r4R0VGmHVWiN5 \n", "2013-09-15 23:44:27.731702016 NaN FCQ5aX37YzsjAKpcv8 \n", "2013-09-15 23:44:28.092921856 NaN FD9Xu815Hwui3sniSf \n", "2013-09-15 23:44:28.150300928 NaN FMZXWm1yCdsCAU3K9d \n", "2013-09-15 23:44:28.150601984 NaN FA4NM039Rf9Y8Sn2Rh \n", "\n", " resp_mime_types \n", "ts \n", "2013-09-15 23:44:27.668081920 text/html \n", "2013-09-15 23:44:27.731702016 text/html \n", "2013-09-15 23:44:28.092921856 text/html \n", "2013-09-15 23:44:28.150300928 text/plain \n", "2013-09-15 23:44:28.150601984 text/plain \n", "\n", "[5 rows x 26 columns]" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Create a Pandas dataframe from the Zeek HTTP log\n", "log_to_df = LogToDataFrame()\n", "zeek_df = log_to_df.create_dataframe('../data/http.log')\n", "print('Read in {:d} Rows...'.format(len(zeek_df)))\n", "zeek_df.head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "
\n", "## So... what just happened?\n", "**Yep it was quick... the two little lines of code above turned a Zeek log (any log) into a Pandas DataFrame. The zat package also supports streaming data from dynamic/active logs, handles log rotations and in general tries to make your life a bit easier when doing data analysis and machine learning on Zeek data.**\n", "\n", "**Now that we have the data in a dataframe there are a million wonderful things we could do for data munging, processing and analysis but that will have to wait for another time/notebook.**" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "# We're going to pick some features that might be interesting\n", "# some of the features are numerical and some are categorical\n", "features = ['id.resp_p', 'method', 'resp_mime_types', 'request_body_len']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Our HTTP features are a mix of numeric and categorical data\n", "When we look at the http records some of the data is numerical and some of it is categorical so we'll need a way of handling both data types in a generalized way. zat has a DataFrameToMatrix class that handles a lot of the details and mechanics of combining numerical and categorical data, we'll use below." ] }, { "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", "
id.resp_pmethodresp_mime_typesrequest_body_len
ts
2013-09-15 23:44:27.66808192080GETtext/html0
2013-09-15 23:44:27.73170201680GETtext/html0
2013-09-15 23:44:28.09292185680GETtext/html0
2013-09-15 23:44:28.15030092880GETtext/plain0
2013-09-15 23:44:28.15060198480GETtext/plain0
\n", "
" ], "text/plain": [ " id.resp_p method resp_mime_types \\\n", "ts \n", "2013-09-15 23:44:27.668081920 80 GET text/html \n", "2013-09-15 23:44:27.731702016 80 GET text/html \n", "2013-09-15 23:44:28.092921856 80 GET text/html \n", "2013-09-15 23:44:28.150300928 80 GET text/plain \n", "2013-09-15 23:44:28.150601984 80 GET text/plain \n", "\n", " request_body_len \n", "ts \n", "2013-09-15 23:44:27.668081920 0 \n", "2013-09-15 23:44:27.731702016 0 \n", "2013-09-15 23:44:28.092921856 0 \n", "2013-09-15 23:44:28.150300928 0 \n", "2013-09-15 23:44:28.150601984 0 " ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Show the dataframe with mixed feature types\n", "zeek_df[features].head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "## Transformers\n", "**We'll now use a scikit-learn tranformer class to convert the Pandas DataFrame to a numpy ndarray (matrix). Yes it's awesome... I'm not sure it's Optimus Prime awesome.. but it's still pretty nice.**" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Normalizing column id.resp_p...\n", "Normalizing column request_body_len...\n", "(150, 12)\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "/Users/briford/.pyenv/versions/3.9.9/envs/py39/lib/python3.9/site-packages/pandas/core/arrays/categorical.py:2631: FutureWarning: The `inplace` parameter in pandas.Categorical.add_categories is deprecated and will be removed in a future version. Removing unused categories will always return a new Categorical object.\n", " res = method(*args, **kwargs)\n" ] }, { "data": { "text/plain": [ "array([[0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 1., 0.]], dtype=float32)" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Use the zat DataframeToMatrix class (handles categorical data)\n", "# You can see below it uses a heuristic to detect category data. When doing\n", "# this for real we should explicitly convert before sending to the transformer.\n", "to_matrix = DataFrameToMatrix()\n", "zeek_matrix = to_matrix.fit_transform(zeek_df[features], normalize=True)\n", "print(zeek_matrix.shape)\n", "zeek_matrix[:1]" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "IsolationForest(contamination=0.25)" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Train/fit and Predict anomalous instances using the Isolation Forest model\n", "odd_clf = IsolationForest(contamination=0.25) # Marking 25% odd\n", "odd_clf.fit(zeek_matrix)" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(32, 4)\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", "
id.resp_pmethodresp_mime_typesrequest_body_len
ts
2013-09-15 23:44:47.46416102480GETapplication/x-dosexec0
2013-09-15 23:44:47.46416102480GETapplication/x-dosexec0
2013-09-15 23:44:49.22197785680GETapplication/x-dosexec0
2013-09-15 23:44:50.80535014480GETapplication/x-dosexec0
2013-09-15 23:44:51.40461900880GETapplication/x-dosexec0
\n", "
" ], "text/plain": [ " id.resp_p method resp_mime_types \\\n", "ts \n", "2013-09-15 23:44:47.464161024 80 GET application/x-dosexec \n", "2013-09-15 23:44:47.464161024 80 GET application/x-dosexec \n", "2013-09-15 23:44:49.221977856 80 GET application/x-dosexec \n", "2013-09-15 23:44:50.805350144 80 GET application/x-dosexec \n", "2013-09-15 23:44:51.404619008 80 GET application/x-dosexec \n", "\n", " request_body_len \n", "ts \n", "2013-09-15 23:44:47.464161024 0 \n", "2013-09-15 23:44:47.464161024 0 \n", "2013-09-15 23:44:49.221977856 0 \n", "2013-09-15 23:44:50.805350144 0 \n", "2013-09-15 23:44:51.404619008 0 " ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Now we create a new dataframe using the prediction from our classifier\n", "odd_df = zeek_df[features][odd_clf.predict(zeek_matrix) == -1]\n", "print(odd_df.shape)\n", "odd_df.head()" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Normalizing column id.resp_p...\n", "Normalizing column request_body_len...\n" ] } ], "source": [ "# Now we're going to explore our odd dataframe with help from KMeans and PCA algorithms\n", "odd_matrix = to_matrix.fit_transform(odd_df)" ] }, { "cell_type": "code", "execution_count": 10, "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", "
id.resp_pmethodresp_mime_typesrequest_body_lenxycluster
ts
2013-09-15 23:44:47.46416102480GETapplication/x-dosexec01.112839-0.6157750
2013-09-15 23:44:47.46416102480GETapplication/x-dosexec01.112838-0.6157740
2013-09-15 23:44:49.22197785680GETapplication/x-dosexec01.112838-0.6157740
2013-09-15 23:44:50.80535014480GETapplication/x-dosexec01.112838-0.6157740
2013-09-15 23:44:51.40461900880GETapplication/x-dosexec01.112838-0.6157740
\n", "
" ], "text/plain": [ " id.resp_p method resp_mime_types \\\n", "ts \n", "2013-09-15 23:44:47.464161024 80 GET application/x-dosexec \n", "2013-09-15 23:44:47.464161024 80 GET application/x-dosexec \n", "2013-09-15 23:44:49.221977856 80 GET application/x-dosexec \n", "2013-09-15 23:44:50.805350144 80 GET application/x-dosexec \n", "2013-09-15 23:44:51.404619008 80 GET application/x-dosexec \n", "\n", " request_body_len x y cluster \n", "ts \n", "2013-09-15 23:44:47.464161024 0 1.112839 -0.615775 0 \n", "2013-09-15 23:44:47.464161024 0 1.112838 -0.615774 0 \n", "2013-09-15 23:44:49.221977856 0 1.112838 -0.615774 0 \n", "2013-09-15 23:44:50.805350144 0 1.112838 -0.615774 0 \n", "2013-09-15 23:44:51.404619008 0 1.112838 -0.615774 0 " ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Just some simple stuff for this example, KMeans and PCA\n", "kmeans = KMeans(n_clusters=4).fit_predict(odd_matrix) # Change this to 3/5 for fun\n", "pca = PCA(n_components=3).fit_transform(odd_matrix)\n", "\n", "# Now we can put our ML results back onto our dataframe!\n", "odd_df['x'] = pca[:, 0] # PCA X Column\n", "odd_df['y'] = pca[:, 1] # PCA Y Column\n", "odd_df['cluster'] = kmeans\n", "odd_df.head()" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [], "source": [ "# Plotting defaults\n", "%matplotlib inline\n", "import matplotlib.pyplot as plt\n", "plt.rcParams['font.size'] = 14.0\n", "plt.rcParams['figure.figsize'] = 15.0, 6.0\n", "\n", "# Helper method for scatter/beeswarm plot\n", "def jitter(arr):\n", " stdev = .02*(max(arr)-min(arr))\n", " return arr + np.random.randn(len(arr)) * stdev" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAA44AAAF7CAYAAACdN9UXAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/YYfK9AAAACXBIWXMAAAsTAAALEwEAmpwYAABWF0lEQVR4nO39fXiV1Z3v8b9XngMEkkBAxJKIKNJRQcx0qhVBBKm10870wXZOD5VeUzvWhzrTen6tOr9Tzjm1/KbH2nrUdnQ6l1o6Tjs61/TqoK1trQRte9oGfKg9iGIhtIgIhPCQBMjD+v2xEhJCsklCQjbwfvXaV7Lve617r427kE/WWt87xBiRJEmSJKkvOSM9AEmSJElSdjM4SpIkSZIyMjhKkiRJkjIyOEqSJEmSMjI4SpIkSZIyMjhKkiRJkjLKG+kBZIsJEybEqqqqkR6GJEmSJI2INWvW7IgxVvR2zuDYoaqqitra2pEehiRJkiSNiBBCXV/nXKoqSZIkScrI4ChJkiRJysjgKEmSJEnKyOAoSZIkScrI4jiSpL7FCI118FYN7FkPbc2QWwxjZ8DEeTC6EkIY6VFKkqRhZnCUJPVu7wbYuCIFx5x8yC+FnCJob4Htz8G2Z1JwPHMJlEwf6dFKkoZYe3s7O3bsoKGhgba2tpEejo5Rbm4upaWlTJgwgZycgS88NThK0sluMLOG9Wth/b2QVwKjep4vhLzR6boHdsHLd8KMm6F8znF9W5Kk4fXHP/6REAJVVVXk5+cTXGFywoox0tLSwrZt2/jjH//I1KlTB3wNg6MkncwGM2u4d0MKjYUVkDeq72uHAIXlkFsE6++D82535lGSTiKNjY3MmDFjULNTyi4hBAoKCpgyZQrr168f1DWy/lMQQrghhLAxhLA/hLAmhDD3KO3/SwjhhRBCUwjhzRDCd0IIpx2v8UpS1qhfm2YDD+xKs4bFU9JMYW7HjGHxlHS8c9awfm2aRdy4Is00ZgqN3eWNgrwxqV+Mw/ueJEnHlaHx5HIs/z2z+pMQQvgIcA/wZeBC4BfAD0MIvc6thhDeBawAHgH+BPgL4O3AvxyP8UpS1ug+a1hY3rXUNEY42AC7XoA3n4Y3fwy7nofmbfDycti2Ks1OFpQN7PUKylK/xrohfiOSJCkbZPtS1c8CD8cY/6nj+c0hhHcDnwZu66X9xcAfY4xf63i+MYRwL3Dv8A9VkrJEX7OGB+qh4UVo2Q0hJy1ZJRdiGxx4Exqb4TfXQ+msgVdKDSEthX2rBsZUDeW7kSSdgGKM1O2uo2ZTDet3rqe5tZnivGJmjJ/BvKp5VI6rdM/kCSZrg2MIoQC4CLirx6kfA5f00e3nwJdDCH8OrATGAx8FnhyucUpS1umc+RtV2XWsaSvU/xpyCiBv3JHBMKcAcsfAnt/BrhchvwxGTR7Y6+aXwp5Xj3n4kqQT24b6Dax4cQV1u+vIz8mntKiUotwiWtpaeG7zczyz6Rkqx1WyZNYSppeP3N74qqoqbrrpJm699dYRG8OJJJuXqk4AcoFtPY5vA3rdsxhj/CUpKP4LcBDYDgTg2t7ahxA+FUKoDSHUbt++fajGLUkj662aNPvXGQ4P1KfQmDsqVVPt6ze8IQdCLsSW1P5A/cBeN+Smiq2SpFPW2q1rufPZO9m1fxeV4yqZMnYKowtGU5hXyOiC0UwZO4XKcZXs2r+LO5+9k7Vb1w7LOLZt28Ytt9zCWWedRWFhIVOmTOGqq67iySeHbz5p6dKlvPe97x226/flG9/4BmeeeSZFRUVcdNFFPPvss8PyOtkcHAcshPB20rLU/0WarXw3KWQ+0Fv7GOODMcbqGGN1RUXF8RuoJA2nPevT7B+kZasNL6YZxZz8o/fNyYe2g6l9w4sDK3YT21IwlSSdkjbUb+DeX99LxagKyovL+1yKGkKgvLicilEV3Pfr+9hQv2FIx7Fp0ybmzJnDU089xfLly3nppZf46U9/ytVXX831118/pK81HFpbW4n9/Pf3e9/7Hrfccgu33347zz//PJdccglXXXUVmzdvHvJxZXNw3AG0AZN6HJ8EvNlHn9uAX8cY/3eM8aUY41PADcCSEMIZwzdUScoibc0QOnYitOxOj5yi/vXNHQXtB1P7zr791dIAY88Z8HAlSSe+GCMrXlxBSUEJo/L7V5V7VP4oxhSMYcWLK/odlPrjhhtuAKC2tpZrrrmGGTNmMHPmTG666SZeeumlPvuFEHj88ccPO1ZVVcVdd3XtnHvggQc455xzKCoqYsKECSxevJjW1laWLVvGI488whNPPEEIgRACq1atAmDLli189KMfpaysjLKyMq6++mpee+21Q9dctmwZ5513Hg8//PChGdLGxsZ+vde7776bpUuXct111zFz5kzuvfdeJk+ezDe/+c3+/nH1W9YGxxjjQWANsKjHqUWk6qq9GUUKm911Ps/a9ypJQJrd27cJfv8IvHA7rPm79PX3j6Tj/f1HNbcYYmv6vnFTxxLUfhYgyBub2gZSv8ZN/R97ewtMnNe/9pKkk0rd7jrqdtdRVjSwqtxlRWWH+g6F+vp6fvSjH3HjjTcyZsyYI86XlpYO+tq1tbXceOONfPGLX2T9+vU8/fTTvPvd7wbg1ltv5ZprrmHhwoVs3bqVrVu3cskll9DU1MTll19OUVERNTU1/PKXv2Ty5MksXLiQpqamQ9feuHEjjz76KI899hgvvvgiRUVFLF26lKqqqj7Hc/DgQdasWcOVV1552PErr7ySX/yir7g0eFlbHKfD3cCKEMKvSYVvrgdOB/4RIITwbYAY48c72v8n8E8hhE8DTwGTga8Da2OMQz9fK0lDZe+GVAm1sS4tF80vTbN+7S2w/TnY9gyMroQzl0DJUQoJjJ2R+uSNhgM7+z/bCEBMt9Zo25/6HdjZv24Hd6Xxja48eltJ0kmnZlMN+Tn5A66UGkIgPyefmk01VM2uOuZxbNiwgRgjM2fOPOZr9bR582ZGjx7N+973PkpKSqisrGTWrFkAjBkzhuLiYgoLCznttK5yLN/5zneIMfLQQw8d+rN54IEHmDhxIitXruSaa64BUghcsWIFkyZ1LbacPHkyZ511Vp/j2bFjB21tbYf1AZg0aRI//elPh+x9d8rq4Bhj/F4IYTzw96QQ+DLwnhhj568kpvZo/3AIoQS4CfgqsBv4GfD54zdqSRqg+rXpnot5JakS6mH/6BamABgjHNgFL98JM26G8jl9X2/ivBQ0Y+yYeczt50Ai0A7j3wkNL0AohJx+zHK2NkHrPjj3M0ef2YwxheO3atJezLbmNEM6dkYa9+ie71+SdCJYv3M9pUWlg+pbWlTKqzuHpir3UC557WnRokVUVlZy5plnsnjxYq688ko+8IEPUFJS0mefNWvWsHHjxiPaNDU18frrrx96fsYZZxwRAJcvXz60b+AYZXVwBIgxfgP4Rh/n5vdyzPs2Sjpx7N2QQmNhxeH3XOwpBCgsh9wiWH8fnHd73zOPnTN/B3alvY6x5wr+PrTth/xxMKYScgth+8+BohT2DgtzEQ7uhn0boXlLCn/j/yy1D3l9h7+hnFWVJGWV5tZminIHssKlS25OLs2tQ1OV++yzzyaEwLp16/jLv/zLAfUNIRwRPFtaWg59X1JSwtq1a1m9ejU/+clPWL58Obfffju/+c1vOP3003u9Znt7O7Nnz+a73/3uEefKy8sPfT969OgBjRVgwoQJ5Obmsm3b4Teh2LZt22GznkPFfX+SNFJiTEEqryRzaOwubxTkjUn9+vqtaggpfLXuTddu33/067a3pKI4ZbOAAMWTYdyfwKgzoKkuBcTWRmjeClt/DG88CXvWpeqrFXOhcHwKf79dlh57e1TIq1+bZksP7EqzqsVT0kxqbseMavGUdLxzVrV+eMqzS5KGR3FeMa3trYPq29beRnHe0FTlLi8vZ/Hixdx3333s27fviPMNDQ199q2oqGDr1q2Hnm/btu2w5wB5eXksWLDgULXWxsZGVq5cCUBBQQFtbYf/snbOnDls2LCBCRMmMH369MMe3YPjYBQUFHDRRRfxk5/85LDjP/nJT7jkkr5uez94BkdJGimNdelRMLBCAhSUdfXtS8n0tKQ1bxS0NkNs76NhTDOGbU0w/h1Q0PGPWIyQVwxzvgbnL4OKS+FgfQqH7S0w9u1w+nvgtEVQfFrm8Nd9VrWwPMN9JDtmVQsr0qxqz/ApScpaM8bPoGF/w6D6Nuxv4JzxQ1eV+/777yfGSHV1NY899hjr16/nlVde4Zvf/CYXXHBBn/0WLFjA/fffT21tLc8//zxLly6lqKhrFnXlypXcc889PP/889TV1fHoo4+yd+/eQ/spq6qqePnll1m/fj07duygpaWFj33sY0yaNIn3v//91NTUsHHjRlavXs3nPve5wyqr9ua2227jiiuuyNjms5/9LA8//DDf+ta3WLduHbfccgtvvPHGsNx2JOuXqkrSSeutmrRkc6B7+kJI/d6qgTFVfbcrnwOzl8P//WtofgNiS9rz2Ln0NORB7mgoqoAJf9YVGqGr2M2YqtQ2tsK2VXD61QNbUvsnt8Gm7wx8VrWtY1b1/GXueZSkE8C8qnk8s+kZYowDKpATY6SlvYV5VUNXlXvatGmsXbuWL3/5y3z+859ny5YtjB8/nlmzZvHggw/22e+rX/0qf/3Xf838+fOZNGkSX/nKV1i3bt2h86WlpXz/+9/nf/7P/0lTUxNnnXUW3/rWt5g7dy4A1113HatWraK6upp9+/bxzDPPMH/+fFavXs0XvvAFPvzhD7N7925OP/10Lr/8csrKMv/ieOvWrYftg+zNRz7yEXbu3MmXvvQltm7dynnnnceTTz5JZeXQF6sLw7mB9ERSXV0da2trR3oYkk4lL9yeZu/yBr6vgdbGtEx09p2Z2+3dAK/cA1v+M+11jB0FcMiBnLwU0gor0hLVzuDY2gQHdnTto4wxLT89sCuFwv46UJ9CX0sDjKoaWACMMS2RPX9Z5nAsSRo269at63d10hgjy1YtY9f+XZQX9//fivrmesqKylg2f9mAK7JqcDL9dw0hrIkxVvd2zqWqkjRS2prTrN9ghNzUP5POfYUEOO1KKJwAo6bAmLNTIBxdlUJj2354azU0vZHC3oEdaZlrZ4GaY1lSW78G2g4e26yqJCnrhRBYMmsJew/upaml6egdgKaWJvYd3MeSWUsMjScAg6MkjZTc4o7bZQxCbEv9+9JzX+Go01MRm9wiaN0NrXtSMZz2thRCYzu89QwQ00xj+YVd1zqWJbWt++Bgw2DeYaq6umdoyrNLkobf9PLp3PyOm9netJ365vo+b40RY6S+uZ4dTTu4+R03M73cStonAoOjJI2UsTPSMs7BaGmAsX0UEuirWmthOUycnx6jpqbASEdwHDMNJrwrzRKO6XGz4T3rU4gbjJA3+ODYn1lVSVJWmTN5DnfMvYOyojLqdtexZc8WGg82sr91P40HG9myZwt1u+soKyrj9rm3c+HkC49+UWUFi+NI0kiZOC/du/CI+yQeRYxpb+TEPgoJdC4tHdXLxvgQoKAUCmb3ft2mjr7d9xW2Naf7LQ5GTn4a62AcbVZVkpSVppdPZ9n8ZdTtrqNmUw2v7nyV5tZmivOKuXTqpcyvms/UcVNdnnqCMThK0kgZXZkeAy0601nxdHQfFdOGulprbnFH+Csc2PUgzVTuf3Pg/SDNqlZcOri+kqQRFUKgqrSKqtlVIz0UDRGXqkrSSAkBzlwCrXtTJdP+aG1K+wbPXNJ3MDyWpaW97Ss8liW1BeNS1diBVvA+2qyqJEk6rgyOkjSSSqanCqYHtqeKpn0FrBh7r3jam6Gu1jpxXgpxgwl/OYVQflGaJR2Io82qSpKk48rgKEkjrXwOnHcHFJalPYbNW9J9Gtv2p6/NW9LxwrIjK572ZqirtXYGuMGEvzFVcM5NQz+rKkmSjiv3OEpSNiiZnm5231iX9hjueTXN/OUWp31+k+Z3VELtR5AaOwO2P5eWiA5Ub/sKO5fUvnxnup1H90qtfekMf+d+pmtWdf290FaSKrf29j5iTGGzdd/RZ1UlSVktRqirg5oaWL8empuhuBhmzIB586Cy0t8NnmgMjpKULUJIM3TdC9MMxnBUaz3W8Nc5q7pxRQrHOflpP2XITbOcLQ3ptUdXdoVNSdIJacMGWLEiBcf8fCgthaIiaGmB556DZ55JwXHJEpg+gn/dV1VVcdNNN3HrrbeO3CBOIC5VlaSTzbEsLc20r/BYl9R2zqqevyzNauYUQPvB9LXiUrjgf6RzhkZJOmGtXQt33gm7dqVwOGUKjB4NhYXp65Qp6fiuXand2rXDM45t27Zxyy23cNZZZ1FYWMiUKVO46qqrePLJJ4fnBYGlS5fy3ve+d9iu35vVq1fzvve9jylTphBC4OGHHx6213LGUZJONse6tDTTLOWxLqkdqllVSVLW2bAB7r0XKipgVIZ/ekKA8vI0C3nffXD77UM787hp0ybe9a53UVJSwvLly5k1axbt7e08/fTTXH/99WzevHnoXmwYtLa2kpub26/7XO7bt4/zzjuPj3/843z84x8f1nE54yhJJ6PhqNbaqTP8TbsWZt8JF92dvk67Ns1WumlFyk4xwqZN8Mgj6Sf1v/u79PWRR9LxgVZOlrqJMS1PLSnJHBq7GzUKxoxJ/Yby43fDDTcAUFtbyzXXXMOMGTOYOXMmN910Ey+99FKf/UIIPP7444cdq6qq4q677jr0/IEHHuCcc86hqKiICRMmsHjxYlpbW1m2bBmPPPIITzzxBCEEQgisWrUKgC1btvDRj36UsrIyysrKuPrqq3nttdcOXXPZsmWcd955PPzww4dmSBsbG/v1Xt/znvfw5S9/mQ996EPk5AxvtHPGUZJOVu4rlNTpRNl0phNWXV16VA7wLkplZV19q6qOfRz19fX86Ec/4ktf+hJjxow54nxpaemgr11bW8uNN97II488wqWXXkpDQwM/+9nPALj11ltZt24d9fX1rFixAoDy8nKampq4/PLLueSSS6ipqaGgoIC77rqLhQsXsm7dOkZ1pOyNGzfy6KOP8thjj1FQUEBRURFLly5l1apVbNq0adBjHkoGR0k6mQ1ltVZJJ5bOspaPPAL//u+Qk5OmdyZMSJvNRo1KG89GjYKGBvjFL+A//gPOPz/99G/5Sw1ATU36ncRAPyohpH41NUMTHDds2ECMkZkzZx77xXrYvHkzo0eP5n3vex8lJSVUVlYya9YsAMaMGUNxcTGFhYWcdtpph/p85zvfIcbIQw89dGjp6QMPPMDEiRNZuXIl11xzDQAHDx5kxYoVTJo06VDfyZMnc9ZZZw35+xgsg6MknezcVyidejpnGH/7W3j5ZRg3LoXE9nbYvDktTR03LoXCujrYvTsFy6Ki1GfUKNi+3ZlI9dv69WkiezBKS+HVV4dmHHEYl1wvWrSIyspKzjzzTBYvXsyVV17JBz7wAUpKSvrss2bNGjZu3HhEm6amJl5//fVDz88444zDQiPA8uXLh/YNHCP3OEqSJJ1MOsta1tfDzp1pLeDo0ZCXBwUFMHZsCo07d8LKlbBjR3o+dmwKjMXF6af4008/PuUvdVJobk4fscHIzU39h8LZZ59NCIF169YNuG8I4Yjg2dLScuj7kpIS1q5dy7/9278xdepUli9fzrnnnssbb7zR5zXb29uZPXs2L7zwwmGPV199lb/5m7851G706EHce/k4MzhKkiSdLLqXtczNTTOJRUVHttu/PwXGoqIUIPfv7zpXVJT67d7dVf6yoiKVv9yw4fi9F51QiouhtXVwfdvaUv+hUF5ezuLFi7nvvvvYt2/fEecbGhr67FtRUcHWrVsPPd+2bdthzwHy8vJYsGABy5cv56WXXqKxsZGVK1cCUFBQQFtb22Ht58yZw4YNG5gwYQLTp08/7FFeXn4M7/T4MzhKkiSdDHqWtdy0KS0/7bnpLEZ4880ULPPz07HXX4ff/x5eey096urgX/4F/umf4MEH4fvfT2sR/8//SctdpR5mzEhbZQejoQHOOWfoxnL//fcTY6S6uprHHnuM9evX88orr/DNb36TCy64oM9+CxYs4P7776e2tpbnn3+epUuXUtTtFy8rV67knnvu4fnnn6euro5HH32UvXv3HtpPWVVVxcsvv8z69evZsWMHLS0tfOxjH2PSpEm8//3vp6amho0bN7J69Wo+97nPHVZZtTe33XYbV1xxRcY2+/btOzSL2d7ezubNm3nhhReG5ZYjBkdJkqSTQWdpyrKy9Hznzt5nGw8cSI8Y00/se/dCY2NaK7hnT9rbuGdPWuq6Zw8cPJiC5tq18MADcMEF8JWveAsPHWbevFSkd6AfiRhTv3nzhm4s06ZNY+3atSxatIjPf/7zXHDBBSxYsIAf/OAHPPjgg332++pXv8q0adOYP38+H/rQh/jkJz/JxIkTD50vLS3l+9//PgsXLuTcc8/lrrvu4lvf+hZz584F4LrrrmPmzJlUV1dTUVHBz3/+c0aNGsXq1auZNm0aH/7whzn33HO59tpr2bVrF2Wd/1/tw9atWw/bB9mb2tpaLrzwQi688EKam5v54he/yIUXXsh//+//fQB/Yv0ThnMD6Ymkuro61tbWjvQwJEmSBueRR9KtNaZMSc+feirNKvbcePbmm2mZ6v79aTYyJyeFw7a2rp/6c3K6vm9vT3sjc3PTWsScHBg/HmbNgjlzLJxzElu3bl2/q5PGCMuWpS2xA1mBWV+fftexbJnFe4+XTP9dQwhrYozVvZ1zxlGSJOlk0LOsZV5e78tK9+xJs4s5OSkMtrenKZ+WlsOPdW5Y6wyMkJa25uSk0LlhA2zcaOEcASn0LVmSJrCbmvrXp6kJ9u1L/QyN2c/gKEmSdDLoWdZy/PjDi95Amhbat69rpjHGNNvY3t61H7K9Pc0+5uQcvkfy4MH0tfPGe3v2pOWqEyZYOEdAmni++ea02rm+vu9lqzGm8zt2pPZOWJ8YDI6SJEkng55lLauqUgjs/tP7gQMpFHaGwRgPbxNjOg9pprFTCF1tQ0gBta0t/eTf0gJjxqTCPG6BOuXNmQN33JGWn9bVwZYtaQvt/v3p65YtXVtxb78dLrxwpEes/hrk3VYkSZKUVWbMSHscO+8HN25ceuzf33Wvg4aGrtAHKWjG2DUDCV3Pu+sMji0tqeBOCOnR2JhmHWfN6irOU1V1HN6sstn06WnPYl0d1NSk24I2N6eP4aWXwvz5MHWqy1NPNFkfHEMINwD/DZgM/A742xjjsxnaFwB/DywBTge2AXfFGP/PcRiuJEnSyJg3D555piv4hZAC3bPPprCYn582lY0alTaidc4udu6DzMk5fLaxt5/q29u7KrV2BtCdO7uWr9bUGBwFpI9EVZUfh5NJVi9VDSF8BLgH+DJwIfAL4IchhKkZun0XeDfwKWAG8GHgpWEeqiRJ0siqrEyPXbu6jpWXwzvekQJjc3MKenl5RxbO6b4UNTe3a/axp87iOd37dC6PLS1NU0uSTkpZHRyBzwIPxxj/Kca4LsZ4M7AV+HRvjUMIVwJXAO+JMf4kxrgpxvirGOOq4zdkSZKkEdBXWcvJk2Hu3DRT2NqaitwUF3ftbew+Q5mX13to7GyXn3/4/sjOPpACZXPz8L9PSSMia4Njx5LTi4Af9zj1Y+CSPrr9BfAb4LMhhD+GEF4LIfyfEMKY4RupJElSluirrGV5edpYNmtWCpD5+VBYmM4XFKRH597F7roXz8nL61qmCimE5uam6q2QZjM791JKOulk8x7HCUAuaY9id9uAhX30mQZcChwAPgiUAveS9jp+qGfjEMKnSEtamTo10+pXSZKkE0RnWcsVK1J1kvz8tIw0NzdtONu0Ke1zPPPMFPpWr0636Oi8BUdra9etOiB9n5+fnncGx84ZyNGjuzaxNTSkyicSpM9HZ3Wc9eu7quPMmJH241ZWWh3nBJPNwXEwcoAI/JcY426AEMJNwFMhhEkxxsNCaIzxQeBBgOrqautHS5Kkk0NfZS0nTIC3vz0FycrK1HbHjvSD/cGD6Qf5zj2LnXshO+/tmJvbtb+xc7ZxwoRUubWz4uq8eSPxbpVtNmw48hcXRUXpM/Lcc6mIU2VlWlo9gjdxrKqq4qabbuLWW28dsTGcSLJ2qSqwA2gDJvU4Pgl4s48+W4EtnaGxw7qOr04pSpKkU0dnWctrr4U774S774Yvfxnuuiuda25OX2fPTktZO3/AHzWqa/lq58xjjOlejSGkmcmWlhQYZ89Ox3bt6irOo1Pb2rXp89b5mZgyJc1MFxamr1OmdBVxuvPO1H4YbNu2jVtuuYWzzjqLwsJCpkyZwlVXXcWTTz45LK8HsHTpUt773vcO2/V7s3z5cv70T/+UsWPHUlFRwZ//+Z/z8ssvD8trZW1wjDEeBNYAi3qcWkSqrtqbnwOn99jTeE7H17qhHaEkSdIJqOc+yLIyuOyy9LW5Of2A396eHp236ygpSbOPBw+m+0KWlaWCO+XlqRDPvn1p9silh6e2DRvg3nuhoiJ9Nvr6PISQzldUwH33pX5DaNOmTcyZM4ennnqK5cuX89JLL/HTn/6Uq6++muuvv35IX2s4tLa2EmP/FkOuWrWKG264gV/84hf87Gc/Iy8vj4ULF1JfXz/k48ra4NjhbmBpCOGTIYSZIYR7SPsV/xEghPDtEMK3u7V/FNgJPBRC+JMQwrtIt/N4PMb41vEevCRJUlbq3AdZVpaWE7a3pyBYWdlVLXX//nR89Oj0dd++9PXMM2HxYjjttBQ8d+xIQXQElxwqC8SYlqeWlKRZ6/4YNSrNZK9Y0bWndgjccMMNANTW1nLNNdcwY8YMZs6cyU033cRLL/V9l74QAo8//vhhx6qqqrjrrrsOPX/ggQc455xzKCoqYsKECSxevJjW1laWLVvGI488whNPPEEIgRACq1atAmDLli189KMfpaysjLKyMq6++mpee+21Q9dctmwZ5513Hg8//PChGdLGxsZ+vdennnqKT3ziE5x33nmcf/75rFixgu3bt/Pzn/+8v39c/ZbVexxjjN8LIYwH/h6YDLxMutVG5+zh1B7t94UQFpIK4vwG2AV8H/jCcRu0JEnSiaC3fZCXXQYHDqRAuHlzOnfgQPoBf+ZMOPfc9IP+7t2wZ08Kmp/5jKFR6bNSVzfw5cqdv7yoq+sqtHQM6uvr+dGPfsSXvvQlxow58sYKpaWlg752bW0tN954I4888giXXnopDQ0N/OxnPwPg1ltvZd26ddTX17NixQoAysvLaWpq4vLLL+eSSy6hpqaGgoIC7rrrLhYuXMi6desY1RGyN27cyKOPPspjjz1GQUEBRUVFLF26lFWrVrFp06Z+j3Hv3r20t7dTVlY26PfZl6wOjgAxxm8A3+jj3Pxejq0HrhzmYUmSJJ34OvdB9vUDe/fKmJ0FdgoLU/XU+fNh6lSXpyqpqTn8Pp/9FULqV1MzJMFxw4YNxBiZOXPmMV+rp82bNzN69Gje9773UVJSQmVlJbNmzQJgzJgxFBcXU1hYyGmnnXaoz3e+8x1ijDz00EOEjj+bBx54gIkTJ7Jy5UquueYaAA4ePMiKFSuYNKmrvMvkyZM566yzBjTGW265hdmzZ3PxxRcf69s9QtYHR0mSJI2QowVLqdP69am40mCUlqZfTAyB/u4NHIxFixZRWVnJmWeeyeLFi7nyyiv5wAc+QElJSZ991qxZw8aNG49o09TUxOuvv37o+RlnnHFYaIRU+GYgPvvZz/Lcc8/x3HPPkdtZAXkIZfseR0mSJEnZrrk5FVAajNzc1H8InH322YQQWLdu3dEb9xBCOCJ4trS0HPq+pKSEtWvX8m//9m9MnTqV5cuXc+655/LGG2/0ec329nZmz57NCy+8cNjj1Vdf5W/+5m8OtRs9evSAx9vd3/3d3/Gv//qv/OxnP2PatGnHdK2+GBwlSZIkHZvi4q57gA5UW1vqPwTKy8tZvHgx9913H/v27TvifENDQ599Kyoq2Lp166Hn27ZtO+w5QF5eHgsWLDhUrbWxsZGVK1cCUFBQQFtb22Ht58yZw4YNG5gwYQLTp08/7FFeXn4M77TLLbfccig0nnvuuUNyzd4YHCVJkiQdmxkzIEMoy6ihAc4556jN+uv+++8nxkh1dTWPPfYY69ev55VXXuGb3/wmF1xwQZ/9FixYwP33309tbS3PP/88S5cupaio6ND5lStXcs899/D8889TV1fHo48+yt69ew/tp6yqquLll19m/fr17Nixg5aWFj72sY8xadIk3v/+91NTU8PGjRtZvXo1n/vc5w6rrNqb2267jSuuuCJjmxtvvJGHHnqIRx99lLKyMt58803efPPNXkPzsTI4SpIkSTo28+ZBS8vAb6sRY+o3b96QDWXatGmsXbuWRYsW8fnPf54LLriABQsW8IMf/IAHH3ywz35f/epXmTZtGvPnz+dDH/oQn/zkJ5k4ceKh86WlpXz/+99n4cKFnHvuudx1111861vfYu7cuQBcd911zJw5k+rqaioqKvj5z3/OqFGjWL16NdOmTePDH/4w5557Ltdeey27du06auXTrVu3HrYPsjff+MY32Lt3L1dccQWTJ08+9Oh+C5GhEoZzA+mJpLq6OtbW1o70MCRJkqSssG7duv5XJ40x3d5l1y4YyBLM+vp0S45ly6zQe5xk+u8aQlgTY6zu7ZwzjpIkSZKOTQiwZAns3QtNTf3r09QE+/alfobGrGdwlCRJknTspk+Hm2+G7dvTTGJfKxtjTOd37Ejtp08/vuPUoHgfR0mSJElDY84cuOMOWLEC6uogPz/dpzE3N1VPbWhIexorK+EznzE0nkAMjpIkSZKGzvTpac9iXR3U1MCrr6b7NBYXw6WXwvz5MHWqy1NPMAZHSZIkSUMrBKiqSg+dFNzjKEmSJEnKyOAoSZIkScrI4ChJkiRJysg9jpIkSZKGVozQWAdv1cCe9dDWDLnFMHYGTJwHoystjnOCMThKkiRJGjp7N8DGFSk45uRDfinkFEF7C2x/DrY9k4LjmUugZORux1FVVcVNN93ErbfeOmJjOJG4VFWSJEnS0KhfCy/fCQd2wahKKJ4CeaMhtzB9LZ6Sjh/YldrVrx2WYWzbto1bbrmFs846i8LCQqZMmcJVV13Fk08+OSyvB7B06VLe+973Dtv1e3P//fdzwQUXMHbsWMaOHcvFF1/ME088MSyv5YyjJEmSpGO3dwOsvxcKKyBvVN/tQoDCcsgtgvX3wXm3D+nM46ZNm3jXu95FSUkJy5cvZ9asWbS3t/P0009z/fXXs3nz5iF7reHQ2tpKbm4uoR9Lec844wz+4R/+gbPPPpv29nYeeeQR/uIv/oI1a9ZwwQUXDOm4nHGUJEmSdGxiTMtT80oyh8bu8kZB3pjUL8YhG8oNN9wAQG1tLddccw0zZsxg5syZ3HTTTbz00kt99gsh8Pjjjx92rKqqirvuuuvQ8wceeIBzzjmHoqIiJkyYwOLFi2ltbWXZsmU88sgjPPHEE4QQCCGwatUqALZs2cJHP/pRysrKKCsr4+qrr+a11147dM1ly5Zx3nnn8fDDDx+aIW1sbOzXe33/+9/PVVddxfTp0znnnHO48847KSkp4Ze//GV//7j6zeAoSZIk6dg01qVHQdnA+hWUdfUdAvX19fzoRz/ixhtvZMyYMUecLy0tHfS1a2trufHGG/niF7/I+vXrefrpp3n3u98NwK233so111zDwoUL2bp1K1u3buWSSy6hqamJyy+/nKKiImpqavjlL3/J5MmTWbhwIU1NTYeuvXHjRh599FEee+wxXnzxRYqKili6dClVVVX9Hl9bWxvf/e532bdvH5dccsmg32dfXKoqSZIk6di8VZMK4Qy0UmoIqd9bNTCm6piHsWHDBmKMzJw585iv1dPmzZsZPXo073vf+ygpKaGyspJZs2YBMGbMGIqLiyksLOS000471Oc73/kOMUYeeuihQ0tPH3jgASZOnMjKlSu55pprADh48CArVqxg0qRJh/pOnjyZs84666jj+u1vf8vFF1/M/v37GTNmDP/xH//B+eefP5RvHTA4SpIkSTpWe9an6qmDkV8Ke14dkmHEIVzy2tOiRYuorKzkzDPPZPHixVx55ZV84AMfoKSkpM8+a9asYePGjUe0aWpq4vXXXz/0/IwzzjgsNAIsX768X+OaMWMGL7zwArt37+bxxx/n2muvZdWqVZx33nkDeHdHZ3CUJEmSdGzamtMtNwYj5Kb+Q+Dss88mhMC6dev4y7/8y4ENI4QjgmdLS8uh70tKSli7di2rV6/mJz/5CcuXL+f222/nN7/5Daeffnqv12xvb2f27Nl897vfPeJceXn5oe9Hjx49oLF2V1BQwPTpqbjQRRddxG9+8xu+9rWv8c///M+DvmZv3OMoSZIk6djkFkNsHVzf2Jb6D4Hy8nIWL17Mfffdx759+44439DQ0GffiooKtm7deuj5tm3bDnsOkJeXx4IFC1i+fDkvvfQSjY2NrFy5EkgBrq2t7bD2c+bMYcOGDUyYMIHp06cf9ugeHIdSe3s7Bw4cGPLrGhwlSZIkHZuxM6ClYXB9Wxpg7DlDNpT777+fGCPV1dU89thjrF+/nldeeYVvfvObGW9RsWDBAu6//35qa2t5/vnnWbp0KUVFXbOoK1eu5J577uH555+nrq6ORx99lL179x7aT1lVVcXLL7/M+vXr2bFjBy0tLXzsYx9j0qRJvP/976empoaNGzeyevVqPve5zx1WWbU3t912G1dccUXGNl/4whd49tln2bRpE7/97W+57bbbWLVqFR/72McG8CfWPwZHSZIkScdm4jxobxn4bTViTP0mzhuyoUybNo21a9eyaNEiPv/5z3PBBRewYMECfvCDH/Dggw/22e+rX/0q06ZNY/78+XzoQx/ik5/8JBMnTjx0vrS0lO9///ssXLiQc889l7vuuotvfetbzJ07F4DrrruOmTNnUl1dTUVFBT//+c8ZNWoUq1evZtq0aXz4wx/m3HPP5dprr2XXrl2UlWWuQLt169bD9kH25s033+S//tf/yowZM7jiiiv4zW9+ww9/+EOuuuqqAfyJ9U8Yzg2kJ5Lq6upYW1s70sOQJEmSssK6dev6X500RvjtMjiwCwoHsATzQD0UlsH5ywZekVWDkum/awhhTYyxurdzzjhKkiRJOjYhwJlLoHUvtDYdvT2kdq37Uj9DY9YzOEqSJEk6diXTYcbNcGB7mknsa2VjjOn8gR2pfcn04ztODYq345AkSZI0NMrnwHl3wMYV0FgHOfnpPo0hN1VPbWlIexpHV8K5nzE0nkCyPjiGEG4A/hswGfgd8Lcxxmf70e9SYBXwSoxxaO9+KUmSJKl3JdPTnsXGOnirBva8mu7TmFsMFZfCpPkwaqrLU08wWR0cQwgfAe4BbgCe6/j6wxDC22OMmzP0KwO+DTwNTDkeY5UkSZJONjFGwmACXggwpio9lDWOpTBqtu9x/CzwcIzxn2KM62KMNwNbgU8fpd8/A48AvxzuAUqSJEkno/z8fJqbm0d6GBpCzc3N5OfnD6pv1gbHEEIBcBHw4x6nfgxckqHfDcAk4EvDNzpJkiTp5DZx4kS2bNlCU1PTMc1UaeTFGGlqamLLli2H3ZtyILJ5qeoEIBfY1uP4NmBhbx1CCOcDXwTeGWNsO9q0egjhU8CnAKZOnXqs45UkSZJOGmPHjgXgjTfeoKWlZYRHo2OVn5/PpEmTDv13HahsDo4DEkIoBL4H3Bpj3NifPjHGB4EHAaqrq/01iiRJktTN2LFjBx00dHLJ5uC4A2gjLTvtbhLwZi/tJwMzgYdCCA91HMsBQgihFXhPjLHnsldJkiRJ0lFk7R7HGONBYA2wqMepRcAveumyBTgfmN3t8Y/Aho7ve+sjSZIkSTqKbJ5xBLgbWBFC+DXwc+B64HRSICSE8G2AGOPHY4wtwMvdO4cQ3gIOxBgPOy5JkiRJ6r+sDo4xxu+FEMYDf09aivoyaclpXUcTK9pIkiRJ0jALltZNqqurY21t7UgPQ5IkSZJGRAhhTYyxurdzWbvHUZIkSZKUHQyOkiRJkqSMDI6SJEmSpIwMjpIkSZKkjAyOkiRJkqSMDI6SJEmSpIwMjpIkSZKkjAyOkiRJkqSMDI6SJEmSpIwMjpIkSZKkjAyOkiRJkqSMDI6SJEmSpIwMjpIkSZKkjAyOkiRJkqSMDI6SJEmSpIwMjpIkSZKkjAyOkiRJkqSMDI6SJEmSpIwMjpIkSZKkjAyOkiRJkqSMDI6SJEmSpIwMjpIkSZKkjAyOkiRJkqSMDI6SJEmSpIwMjpIkSZKkjAyOkiRJkqSMDI6SJEmSpIwMjpIkSZKkjAyOkiRJkqSMsj44hhBuCCFsDCHsDyGsCSHMzdD2AyGEH4cQtocQ9oYQfhVCeN/xHK8kSZIknWyyOjiGED4C3AN8GbgQ+AXwwxDC1D66zAN+Blzd0f5J4D8yhU1JkiRJUmYhxjjSY+hTCOFXwEsxxuu6HXsNeDzGeFs/r/Fr4NkY4+cytauuro61tbXHNF5JkiRJOlGFENbEGKt7O5e1M44hhALgIuDHPU79GLhkAJcqAXYN1bgkSZIk6VSTtcERmADkAtt6HN8GnNafC4QQbgTOAFb0cf5TIYTaEELt9u3bj2WskiRJknTSyubgeExCCB8E/jfwX2KMdb21iTE+GGOsjjFWV1RUHN8BSpIkSdIJIpuD4w6gDZjU4/gk4M1MHUMIHyLNMn48xvifwzM8SZIkSTo1ZG1wjDEeBNYAi3qcWkSqrtqrEMI1pNC4NMb4+PCNUJIkSZJODXkjPYCjuBtY0VEZ9efA9cDpwD8ChBC+DRBj/HjH84+SQuOtwOoQQudeyIMxxvrjPHZJkiRJOilkdXCMMX4vhDAe+HtgMvAy8J5uexZ73s/xetJ7+nrHo1MNMH84xypJkiRJJ6usDo4AMcZvAN/o49z8TM8lSZIkSccua/c4SpIkSZKyg8FRkiRJkpSRwVGSJEmSlJHBUZIkSZKUkcFRkiRJkpSRwVGSJEmSlJHBUZIkSZKUkcFRkiRJkpSRwVGSJEmSlJHBUZIkSZKUkcFRkiRJkpSRwVGSJEmSlJHBUZIkSZKUkcFRkiRJkpSRwVGSJEmSlJHBUZIkSZKUUb+CYwjh+yGE94YQDJqSJEmSdIrpbxBsBL4H/DGE8OUQwtnDOCZJkiRJUhbpV3CMMX4MmAz8L2AhsD6EsDqE8PEQQvFwDlCSJEmSNLL6vfQ0xrgnxvjNGOM7gPOBNcADwNYQwgMhhJnDNUhJkiRJ0sgZ8J7FEMLpwPuB9wKtwL8DbwNeCiHcOrTDkyRJkiSNtP4Wx8kPIXwohPAkUAf8BfAVYHKM8a9jjO8BPgj8/bCNVJIkSZI0IvL62W4rKWT+C/CFGONLvbRZDewaqoFJkiRJkrJDf4Pj3wH/FmM80FeDGGMDcOZQDEqSJEmSlD36DI4hhB8A/zXGuAe4BvhwCKGv5vuAl4H7Y4y7h3yUkiRJkqQRk2nGcScQO77fcZTrFALXAe8E3jcE45IkSZIkZYk+g2OM8RO9fd+XEMLbgd8M0bgkSZIkSVliwLfjyGA9cMkQXk+SJEmSlAX6WxznqGKMbcCLQ3U9SZIkSVJ2GMoZx2ERQrghhLAxhLA/hLAmhDD3KO3ndbTbH0L4fQjh+uM1VkmSJEk6GWV1cAwhfAS4B/gycCHwC+CHIYSpfbQ/E3iyo92FwHLg3hDCB4/PiCVJkiTp5JPVwRH4LPBwjPGfYozrYow3A1uBT/fR/nrgjRjjzR3t/wl4BLj1OI1XkiRJkk46WRscQwgFwEXAj3uc+jF9F+G5uJf2TwHVIYT8oR2hJEmSJJ0asjY4AhOAXGBbj+PbgNP66HNaH+3zOq53mBDCp0IItSGE2u3btx/jcCVJkiTp5JTNwXHYxRgfjDFWxxirKyoqRno4kiRJkpSVsjk47gDagEk9jk8C3uyjz5t9tG/tuJ4kSZIkaYCyNjjGGA8Ca4BFPU4tIlVN7c0v+2hfG2NsGdoRSpIkSdKpIWuDY4e7gaUhhE+GEGaGEO4BTgf+ESCE8O0Qwre7tf9HYEoI4esd7T8JLAXuOt4DlyRJkqSTRd5IDyCTGOP3Qgjjgb8HJgMvA++JMdZ1NJnao/3GEMJ7gK+RbtnxBvCZGOO/H8dhS5IkSdJJJauDI0CM8RvAN/o4N7+XYzXAnGEeliRJkiSdMrJ9qaokSZIkaYQZHCVJkiRJGRkcJUmSJEkZGRwlSZIkSRkZHCVJkiRJGRkcJUmSJEkZGRwlSZIkSRkZHCVJkiRJGRkcJUmSJEkZGRwlSZIkSRkZHCVJkiRJGRkcJUmSJEkZGRwlSZIkSRkZHCVJkiRJGRkcJUmSJEkZGRwlSZIkSRkZHCVJkiRJGRkcJUmSJEkZGRwlSZIkSRkZHCVJkiRJGRkcJUmSJEkZGRwlSZIkSRkZHCVJkiRJGRkcJUmSJEkZGRwlSZIkSRkZHCVJkiRJGRkcJUmSJEkZGRwlSZIkSRkZHCVJkiRJGWVtcAwhFIYQ7g0h7AghNIYQfhBCOOMofW4LIfwmhLAnhLA9hPCfIYTzjteYJUmSJOlklLXBEfg68EHgr4C5wFhgZQghN0Of+cA3gEuABUAr8NMQQvmwjlSSJEmSTmJ5Iz2A3oQQxgF/DXwixviTjmNLgDpgIfBUb/1ijIt7XGcJsBt4F/CfwzlmSZIkSTpZZeuM40VAPvDjzgMxxj8A60izif1VQnqPu4Z0dJIkSZJ0CsnW4Hga0Abs6HF8W8e5/roHeAH4ZW8nQwifCiHUhhBqt2/fPphxSpIkSdJJ77gGxxDCl0II8SiP+UP0WncDlwIfjDG29dYmxvhgjLE6xlhdUVExFC8rSZIkSSed473H8evAd47SZjPwTiAXmAB0nwqcBDx7tBcJIXwN+ChweYzx94MaqSRJkiQJOM7BMca4gyOXnx4hhLAGaAEWAY92HDsDmAn84ih97wE+QgqNrxzrmCVJkiTpVJeVexxjjLuBfwa+EkJYGEK4EFgBvAT8tLNdCOGVEMJN3Z7fD3wC+C/ArhDCaR2PMcf3HUiSJEnSySMrb8fR4W9J92H8HlAMPA18vMd+xRmk5aydbuj4+nSPa/0PYNmwjFKSJEmSTnJZGxxjjAeAmzsefbUJmZ5LkiRJko5dVi5VlSRJkiRlD4OjJEmSJCkjg6MkSZIkKSODoyRJkiQpI4OjJEmSJCkjg6MkSZIkKSODoyRJkiQpI4OjJEmSJCkjg6MkSZIkKSODoyRJkiQpI4OjJEmSJCkjg6MkSZIkKSODoyRJkiQpI4OjJEmSJCkjg6MkSZIkKSODoyRJkiQpI4OjJEmSJCkjg6MkSZIkKSODoyRJkiQpI4OjJEmSJCkjg6MkSZIkKSODoyRJkiQpI4OjJEmSJCkjg6MkSZIkKSODoyRJkiQpI4OjJEmSJCkjg6MkSZIkKSODoyRJkiQpo7yRHoCGV4xQVwc1NbB+PTQ3Q3ExzJgB8+ZBZSWEMNKjlCRJkpTNsjY4hhAKgbuAvwKKgaeBG2KMf+xn/9uALwP3xxhvGraBDrGhDHobNsCKFel6+flQWgpFRdDSAs89B888k663ZAlMnz6sb0uSJEnSCSzEGEd6DL0KIXwTeD9wLbATuBsoBS6KMbYdpe87gX8F9gDP9ic4VldXx9ra2mMd9jHpLejl5UFrKzQ0pMDX36C3di3cey+UlEBZWe9hM0bYtQv27oWbb4Y5c7qOO0spSZIknVpCCGtijNW9nsvG4BhCGAdsBz4RY/yXjmNvA+qAq2KMTx2l71rgk8AXgZdPhOB4LEGvpw0b4M47oaICRo06+ms3NcGOHXD77en5UIVXSZIkSSeOTMExW4vjXATkAz/uPBBj/AOwDrjkKH0fBB6PMT4zfMMbWhs2pNBYUQHl5X3P5oWQzldUwH33pX49xZiCX0lJ/0IjpHZjxsBXvgJf+lIKp5WVMGUKjB4NhYXp65Qp6fiuXSmYrl07+PcsSZIk6cSRrXscTwPagB09jm/rONerEMJ1wHTgv/bnRUIInwI+BTB16tRBDfRYDTbojR6dwuaFF8Krr3YtJy0vh9/9Dt7+9oGP45lnYMGCdI2+dIbXoqIUXm+/3ZlHSZIk6WR3XINjCOFLwB1HaXb5IK89g1QM59IYY0t/+sQYHyTNUFJdXT0ia3br6tKjsrL/fXbuhF/9KvX7yU9SYCwoSMtKd+2C+nrYvh1mzcocAjvFCC+9lK6xbRtMnnz0Pp2zlCtWwLJl7nmUJEmSTmbHe8bx68B3jtJmM/BOIBeYQNrr2GkS8Gwf/S7uaP+70JVicoHLQgjXA6NjjAcGN+zhU1OT9hL2N3i98gqsWpX2HMYIBw+mcNjenkLfH/+YAmBDA6xeDX/2Z0cPgrt3p8fYsSmU9ldZWVfwrarqfz9JkiRJJ5bjGhxjjDs4cvnpEUIIa4AWYBHwaMexM4CZwC/66PZ9oGd1m4eA10gzkQcHNehhtn59minsj1degR//uGvPYXt7KlaT1/FfsaAghdC2thQiJ02CX/8a5s7NPPO4aRPk5EBubgqk/RVCer2aGoOjJEmSdDLLyj2OMcbdIYR/Br4SQniLrttxvAT8tLNdCOEV4L4Y430xxgagoft1QgiNQH2M8eXjNfaBam5O+wWPZufONNNYWJgekIJbW48bk+TlpUAJKTyWlaWwWVGRQmZ+Powfn4LeuHHpGjt3pjG0t3eF0P4qLU17LCVJkiSdvLIyOHb4W6AV+B5QDDwNfLzHPRxnkJannrCKi1Og6wyDvYkxzRy2tqaZxu7Hc3OPvN7u3WkGsbEx3bqjqCj1Ky5OQXPz5jTLOG5c2gfZOWvZ1AQDrRGUm5vCryRJkqSTV9YGx479iDd3PPpqk3FnYIxx/hAPa8jNmAHPPXd4IOypoQH+8IcU8BoaUmDs3BM5YcLhz0tLU2Gc/ftTeIQU7hobU+VWSEtaY0xtVq9OfUNIM44DXXLa1pYCqSRJkqSTV7bex/GUMW9eCoSxj5qu9fXwox+laqltbV0hsb09FcbZsyfNHnbO+rW3w4EDqU1ubvra2ppmE7sLIQW+0aPTUtUdO9IM5LhxAxt/QwOcc85A37UkSZKkE4nBcYRVVqbHrl1Hntu6FZ59NoXD3Nz0yMnpml0sKEjhr7U1VTbdsyfta+ycvWxvT+1bW7v2PfaUn99VTfX88wd2W40YU+idN29g71mSJEnSicXgOMJCgCVL0l7E7rOC9fVpX+OoUV2BsXNWsr09PYqLU599+9LjlVdSv7y8dI/F9vbUpzNA9hRjmqnMy0tLXvftG9jYd+3qCr6SJEmSTl4GxywwfTrcfHPam1hfn4Leiy923V4jJ6erWmpbW5pBDCEFvf37u4rktLWl5w0N6evo0V2VV0NIS1tbW7uWuO7enQrnXHYZzJ4Nr79+5JLWvnQG1iVLBjZLKUmSJOnEk7XFcU41c+bAHXfAihXwu9+lZarjx6eg11nMpq2tq4pqCIcvW4WuGcmcnNS2sTH1HTMmFeFpbk7Xy8tL1VO735KjsDAVz9m+PX0tK+s9EMaYZhr37Uthd/r0Yf+jkSRJkjTCDI5ZZPp0WLYM7r47FavpnF0sK0uzhAUFaUlrXl7vS087g15bW2rb1pZmBt/2Nrj44swzg7m5KUTecEMKr3V1abaztLRrNrOhIe1prKyEz3zG0ChJkiSdKgyOWSaEVKjmT/+0q8hNjLBqVdrD2B9tbV39cnIy3yOye5/i4q7wWlcHNTXw6qtpprK4GC69FObPT7OVLk+VJEmSTh0GxyzU3Jz2HnYKAc48E37727SMtLGxKxR2D3C5uWlGsPMWHG1tMG1amq3cvTvNHnaKMR3btCkF1V270ms88kiqklpZCddee7zesSRJkqRsZnDMQsXFKQAWFHSFu//3/9K5fftSQIyxq0hOZ4DMyemqpJqfD2edlaqldt7rcfbsdI36+lR8Z/furhnJEGDyZHjuOXjmmRQclyxxOaokSZIkg2NWmjEDnnwS3nyzK9w1NaVAWViY9jm2tnZVW+285UZnddWiIjj33HQrD0jPd+5M32/dmm7zUVDQVRinuRnKy1NwDKGrAM6dd6YCOHPmjNyfhSRJkqSR5+04stD48bBmTQp048bB2LHpeG5uCo7jx6dHYWEKkEVFqYDOGWek/YdnnJFmHDvl5KR23e8NWVycQmJLS1rKOmtW17LXEFKQrKiA++6DDRuO/5+BJEmSpOxhcMwyGzbA44/DpEkpwHWGuZycrttthJCC4bhxKeDl5KTZwtJSmDIlFbFpbEzBs3M2Mjf38HtDxpjONzXBO96RrtPTqFHpVh4rVnS9tiRJkqRTj8Exi8SYQtrYsXDRRWkmsKUlnRs1Ks0a9pSbmx5btsCBA2nm8PTT4bLL0kzk7t1ppjE3N33NyUl7HnfvTufnzk2hsy9lZanCal3d8LxnSZIkSdnPPY5ZpDOgVVamWcV3vOPw/YgNDSlcdq+kGmPX7OHb3941c1henm6d0dCQlr3mdfyXzstLs5lVVV17HDPpnN2sqUl9JEmSJJ16DI5ZpKYmhbTOMDd5cpoR7KyAGkKaVSwo6KqqGmPa61hWlpaddtdZ6OaKK9LMZUtL170hB6K0NN3PUZIkSdKpyaWqWWT9+sPvtQhdM4fz58N553UFxpycNGNYVdU1e9hZObVTU1O6fceSJWlGMm+QvybIzU39JUmSJJ2anHHMIs3Nad9hTyGkQPmud8G0afCrX6VZxqKiw4vndO6B7Lydxr596XYa06d33RuysHDg42prS/0lSZIknZqcccwixcW9F8DpbvLkwwvf7NnTVUQnxlQkp64uLV29/Xa48MLUb8aMtN9xMBoa4JxzBtdXkiRJ0onPGccsMmMGPPfc0fchdi5f3b0bNm1KS1T37k1LVi+9NJ2bOvXwwjfz5sEzzxxZXOdoYkyhdN68gb8fSZIkSScHg2MWGUi461y+Ont2al9XB8uW9V35tLIyPXbt6v2ejX3ZtaurryRJkqRTk0tVs0j3cDcQ/Ql3IaQiOXv3Hll9tS/di+sMZJZSkiRJ0snF4JhFhjvcTZ+eiuVs3w719WmmsjcxpvM7dnQV15EkSZJ06jI4ZpnhDndz5sAdd6TiOXV1qZhOYyPs35++9lVcR5IkSdKpK8S+kskpprq6OtbW1o70MA7ZsAFWrEghLj8/7WfMzU23xmhoSAVrKivTTONgZgQ790XW1MCrr6ZbgRQXp+qpvRXXkSRJknRyCyGsiTFW93rO4JhkW3AEw50kSZKk4ydTcLSqahYLIVVJ7atSqiRJkqTsF2OkbncdNZtqWL9zPc2tzRTnFTNj/AzmVc2jclwlIctnhAyOkiRJkjRMNtRvYMWLK6jbXUd+Tj6lRaUU5RbR0tbCc5uf45lNz1A5rpIls5YwvTx7q1IaHCVJkiRpGKzdupZ7f30vJQUlR8wqFlLI6ILRxBjZtX8Xdz57Jze/42bmTJ4zgiPum1VVJUmSJGmIbajfwL2/vpeKURWUF5f3uRQ1hEB5cTkVoyq479f3saF+w3Eeaf844yhJkiRJA5Rp3+JllZfx7Re+TUlBCaPyR/XreqPyRzGmYAwrXlzBsvnLsm7PY9YGxxBCIXAX8FdAMfA0cEOM8Y9H6TcZ+P8B7wFKgN8Dn44x1gzviCVJkiSdCo62b/E/X/1PNtRvYO7UuQO6bllRGXW766jbXUdVadXwDH6QsjY4Al8H3k8KjjuBu4GVIYSLYoxtvXUIIZQCPweeA64GtgPTgLeOw3glSZIknUAGU+20P/sW32p861CIfMeUdzC5ZHK/xhNCID8nn5pNNVTNrhrKt3rMsjI4hhDGAX8NfCLG+JOOY0uAOmAh8FQfXf8/wNYY48e7Hds4nGOVJEmSdOIZTLXT7vsWMy1BrW+uZ1zROAKBX2/5NXMr51JeXN6vcZUWlfLqzleH5D0OpWwtjnMRkA/8uPNAjPEPwDrgkgz9/gL4VQjheyGEt0IIL4QQbgrZtkBYkiRJ0ohZu3Utdz57J7v276JyXCVTxk5hdMFoCvPSjOGUsVOoHFd5qNrp2q1riTGy4sUV/dq32NLeQk7IIT83n4LcAl5880VijP0aW25OLs2tzUPxNodUVs44AqcBbcCOHse3dZzryzTgBuBrpH2Os4F7O87d17NxCOFTwKcApk6dekwDliRJkpT9+jtr2FnttCiviPt+fR8fn/Vx6nbXUTmu8qivkRfyaGppSo+DTTS3NtPU0sSUsVOoKq1iXOG4PovftLW3UZxXPOj3N1yOa3AMIXwJuOMozS4/hpfIAWpjjLd1PH8+hHA2cCO9BMcY44PAgwDV1dX9+xWAJEmSpBPSQGYNO3VWO/36L7/OhFETjlrtdGfTTrbs3cK2fdtoi21EIjFGfrf9d7yx9w3W71hPxagKZk+e3evy1Yb9DVw69dJBvb/hdLxnHL8OfOcobTYD7wRygQmkAjedJgHPZui7Ffh/PY6tA24Z0CglSZIknXQ6K5b2Z9awu7KiMlY1rGLi6IkZ272y/RWe3vg0+1r2cbDtIIGQgiORttY23mp8ix1NO9jeuJ3tjdu5rOqywwrnxBhpaW9hXtW8Qb2/4XRcg2OMcQdHLj89QghhDdACLAIe7Th2BjAT+EWGrj8HZvQ4dg6pqI4kSZKkU1jNphryc/IHfI/EEFIAfGPvG5w+9vRe27yy4xV+uOGHhwIjQDvthI7/AQQCbe1tNBxoYN/BfezfsJ8/P/fPD808du65HGiwPR6ysjhOjHE38M/AV0IIC0MIFwIrgJeAn3a2CyG8EkK4qVvXrwHvDCHcEUKYHkL4MPAZ4P7jOHxJkiRJWWj9zvWUFpUOqu/ovNHsaO59Dmxn005++vufcrDtIDkhh9bYSk44Mmrl5OSQl5tHDqnNG/ve4OnXnybGSFNLE/sO7mPJrCUDDrbHQ1YGxw5/C/wH8D3STOI+4M973MNxBmk5KwAxxt+QKqteA7wM3An8f4FvHJcRS5IkScpaza3N5OUMbtHl+FHjaTzYeMTxGCO/3vJrmlqayAk5tLS3EAjk5uQeeq1IPCxI5uTkkBtyiTHy+q7XeWnbS+xo2sHN77j50K0/sk22VlUlxngAuLnj0VebI6J4jPEJ4IlhHJokSZKkE1BxXjEtbS0UUjjgvlPGTuEPe/5AjPGwGcHdB3bzhz1/oL29nUiqt9l5PifkQE6qlArQHtsPLVuNMdJOO7E98uKbL/LUkqc4e/zZx/oWh03WBkdJkiRJGkozxs/guc3PMbpg9ID6xRjZc2APeSGPJ157gvycfPJy8xhfPJ6mliYaDzYScgLt7V3BsLu8nDwKcgtoi22HQmQIgbyQR27IpaW9hfzc/CF5j8Mlm5eqSpIkSdKQmVc1j5b2FmLs/5346pvreWbjM9S+UcvpJaezv3U/7bGdtvY2Nu/ezAtvvkBTS9NhgbBT5+sU5BaQm5NLQW4BxfnFhx4FuQXkhBz2t+2nZlPN0L7ZIWZwlCRJknRK6KxYumv/rn6137p3K6vrVrP7wG6mlEzhotMv4l1vexcH2g7Q1t5GSUEJ+bn5RCKt7a2HgmKMkfaYlq52hsbeBAIxRvJCHq/ufHXI3udwMDhKkiRJOiWEEFgyawl7D+6lqaUpY9v65np+teVXFOSkWcFZp80ihMDkkslcVnkZRXlF7D6wm7a2tlTohnhoKWokEggU5hZmLMbTeY/H0fmjaW5tHuq3O6QMjpIkSZJOGdPLp3PzO25me9N26pvre122GmPkha0vEGOkpb2Fd0x5x6F7LQKUF5czv2o+86vmc/rY0ynILThsb2NhbiFFeUV9zjR2ao/tAJwx9gyK84qH6B0OD4OjJEmSpFPKnMlzuGPuHZQVlVG3u44te7bQeLCR/a37aTzYyKs7X+WNfW9QWlTK3Mq5TC6ZfMQ1QgiUFpVyWeVlnDH2DPJCHjkhhxDCoUcmnctZR+WP4rQxp3HO+HOG6+0OCauqSpIkSTrlTC+fzrL5y6jbXUfNphpe3fkqza3NFOcVM7pgNNWnVzNj/IyjBsBxheOYOHoibzW9RUNzAwCt7a0U5BZk7NfWcXv6qtIqCvMKmVc1b0je13AxOEqSJEk6JYUQqCqtomp21WHHb3/6dsqKyo4aGjuvMeu0WbzV+BaNBxppbW+ltb2V/Jz8XvvHGGlrb6M1tjJ5zGRmVsykqrSKynGVQ/W2hoVLVSVJkiSpm+bW5oxFbXoqLy7nssrLmFwymZyQQ3t7+6EA2R7bDy1LbWlr4WDbQdppZ/KYVGQnLyePJbOW9CukjiSDoyRJkiR1U5xXTGt764D6TC6ZzJ/P+HPOLD+T/Nx8cnNyCQTa29M9H9va2wghMKZgDH9S8SfMrZxLbk4uN7/jZqaXTx+mdzJ0XKoqSZIkSd3MGD+D5zY/x+iC0QPqV15czty3zWX8jPE8v/V51u1Yx/7W/eSFPEYVjuJtJW9j0phJFOUVUVVaxZJZS06I0AgGR0mSJEk6zLyqeTyz6RlijANaQhpjpDW28uk//TSV4yp7LbxzzvhzmF81n6njpmb98tTuDI6SJEmS1E3luEoqx1Wya/+uw+7feDS79u861LevwjsnKvc4SpIkSVI3IQSWzFrC3oN7aWpp6lefppYm9h3cd0IUuhkMg6MkSZIk9TC9fDo3v+Nmtjdtp765nhhjr+1ijNQ317OjaccJU+hmMFyqKkmSJEm9mDN5DnfMvYMVL66gbncd+Tn5lBaVkpuTS1t7Gw37G2hpb6FyXCWf+bPPnLShESD0lZxPNdXV1bG2tnakhyFJkiQpy8QYT6pCN30JIayJMVb3ds4ZR0mSJEnK4GQrdDMY7nGUJEmSJGVkcJQkSZIkZWRwlCRJkiRlZHCUJEmSJGVkcJQkSZIkZeTtODqEELYDdSM9jiw3Adgx0oOQMvAzqmznZ1QnAj+nynZ+RodPZYyxorcTBkf1Wwihtq/7ukjZwM+osp2fUZ0I/Jwq2/kZHRkuVZUkSZIkZWRwlCRJkiRlZHDUQDw40gOQjsLPqLKdn1GdCPycKtv5GR0B7nGUJEmSJGXkjKMkSZIkKSODoyRJkiQpI4Oj+hRC+FQI4ZkQQkMIIYYQqvrZ74MhhP8XQjjQ8fUvh3moOkWFEApDCPeGEHaEEBpDCD8IIZxxlD7LOj7P3R9vHq8x6+QWQrghhLAxhLA/hLAmhDD3KO3ndbTbH0L4fQjh+uM1Vp2aBvIZDSHM7+XvyxhCOPd4jlmnjhDCZR3/lm/p+Kwt7Uef80MINSGE5o5+/z2EEI7DcE85BkdlMgr4MbCsvx1CCBcD3wP+BZjd8fWxEMKfDcP4pK8DHwT+CpgLjAVWhhByj9JvPTC52+P8YRyjThEhhI8A9wBfBi4EfgH8MIQwtY/2ZwJPdrS7EFgO3BtC+ODxGbFONQP9jHbzJxz+d+ZrwzlOndLGAC8DtwDNR2scQhgL/ATYBvxpR7//Bnx2GMd4yrI4jo4qhFAN/AY4M8a46ShtvweUxxgXdTv2U2B7jPGvhnWgOqWEEMYB24FPxBj/pePY24A64KoY41N99FsGfCjGeN7xGqtODSGEXwEvxRiv63bsNeDxGONtvbT/B+ADMcazux37FvAnMcaLj8eYdWoZxGd0PvAMUBFj3HG8xikBhBD2ATfFGB/O0ObTwD8Ak2KMzR3H/h74NHBGNOgMKWccNdQuJs1SdvcUcMkIjEUnt4uAfLp93mKMfwDWcfTP27QQwhsdy7W+G0KYNozj1CkghFBA+kz2/Pvvx/T9eezr78vqEEL+0I5Qp7pBfkY71YYQtoYQng4hXD4sA5QG52Lg2c7Q2OEp4HSgakRGdBIzOGqonUZaLtDdto7j0lA6DWgDev4W/Gift18BS4F3A9d1tP1FCGH8MIxRp44JQC4D+/uvr78v8zquJw2lwXxGt5Jmbj4IfIC0zP/po+3dlY6jvv4e7TynIZQ30gPQ8RVC+BJwx1GaXR5jXHUchiMdob+f0cFeP8b4wx6v93+B3wPXAncP9rqSdLKJMa4nhcVOv+wolPffgGdHZFCSRozB8dTzdeA7R2mz+Riu/yYwqcexSR3Hpf74Ov37jL6T9NvzCaS9jp0mMYAfaGKM+0IIvwPOPmpjqW87SDPgA/n7r6+/L1s5ciZdOlaD+Yz25lfAR4dqUNIx6uvv0c5zGkIGx1NMx+b24fyB5JfAIuB/dzu2iFS5TTqq/n5GQwhrgBbS5+vRjmNnADMZwOcthFAEnEsqACENSozxYMdnchHwWLdTi4B/76PbL4GetytaBNTGGFuGfpQ6lQ3yM9qb2aQlrFI2+CXwDyGEohjj/o5ji4A3gE0jNqqTlHsc1acQwmkhhNnAOR2H3h5CmB1CKO/W5ukQwvJu3e4BFoQQvhBCODeEcBtpWeHXj9e4dWqIMe4G/hn4SghhYQjhQmAF8BLw0852IYRXQgg3dXt+V8e9887suE3M48Bo4JHj+w50ErobWBpC+GQIYWYI4R5SgYZ/BAghfDuE8O1u7f8RmBJC+HpH+0+S9t/edbwHrlPGgD6jIYS/DSH8RQjh7BDCn3T8e/8XwH0jMXid/EIIYzp+1pxNyilTO55P7Ti/PITwdLcujwJNwMMhhPNCCB8AvgDcbUXVoeeMozK5Hvhit+dPdHz9BPBwx/dnAX/obBBj/EUI4aPAl4D/CbwOfCTG+KthH61ORX9LWtb3PaAYeBr4eIyxrVubGRxeaOQM4F/pWuL6f4F3xhjrjseAdfKKMX6vo8jS35Pudfcy8J5un62pPdpvDCG8B/gaqQDJG8BnYowDmf2R+m2gn1GggLSC6AzSPfV+B1wdY3zyOA1Zp55qDl8B9D86Ho+QfrE2mfSzJ5B+iRxCWATcD9QCu4CvYs2CYeF9HCVJkiRJGblUVZIkSZKUkcFRkiRJkpSRwVGSJEmSlJHBUZIkSZKUkcFRkiRJkpSRwVGSJEmSlJHBUZKkERBCeDiEsHKkxyFJUn94H0dJkkZACGEc6d/hhpEeiyRJR2NwlCRJkiRl5FJVSZJGQOdS1RBCRQhhawjhi93OXRBC2B9C+PBIjlGSpE4GR0mSRlCMcTuwFLgjhHBxCKEY+FfgX2OMj43o4CRJ6pA30gOQJOlUF2N8KoTwDeBfgBqgELh5ZEclSVIXZxwlScoOnwcOAh8HPhZj3DfC45Ek6RCDoyRJ2aEKeBsQgWkjOxRJkg5ncJQkaYSFEPKBR4EfALcC3wghTB3ZUUmS1MU9jpIkjbz/BVQAVwC7gXcD3w4hLIgxto/oyCRJwhlHSZJGVAhhHvA54OMxxoaYbrC8FHg7ad+jJEkjzhlHSZJGRiGwL8ZYA+R3PxFjfBOYOCKjkiSpF844SpJ0HIUQ8kIIbwcuBl4e6fFIktQfBkdJko6v84Ba4HfA/SM8FkmS+iWkrRSSJEmSJPXOGUdJkiRJUkYGR0mSJElSRgZHSZIkSVJGBkdJkiRJUkYGR0mSJElSRgZHSZIkSVJG/3/Xbhry0pUkZgAAAABJRU5ErkJggg==\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "# Jitter so we can see instances that are projected coincident in 2D\n", "odd_df['jx'] = jitter(odd_df['x'])\n", "odd_df['jy'] = jitter(odd_df['y'])\n", "\n", "# Now use dataframe group by cluster\n", "cluster_groups = odd_df.groupby('cluster')\n", "\n", "# Plot the Machine Learning results\n", "colors = {0:'green', 1:'blue', 2:'red', 3:'orange', 4:'purple', 5:'brown'}\n", "fig, ax = plt.subplots()\n", "for key, group in cluster_groups:\n", " group.plot(ax=ax, kind='scatter', x='jx', y='jy', alpha=0.5, s=250,\n", " label='Cluster: {:d}'.format(key), color=colors[key])" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "Cluster 0: 8 observations\n", " id.resp_p method resp_mime_types request_body_len\n", "ts \n", "2013-09-15 23:44:47.464161024 80 GET application/x-dosexec 0\n", "2013-09-15 23:44:47.464161024 80 GET application/x-dosexec 0\n", "2013-09-15 23:44:49.221977856 80 GET application/x-dosexec 0\n", "2013-09-15 23:44:50.805350144 80 GET application/x-dosexec 0\n", "2013-09-15 23:44:51.404619008 80 GET application/x-dosexec 0\n", "\n", "Cluster 1: 10 observations\n", " id.resp_p method resp_mime_types request_body_len\n", "ts \n", "2013-09-15 23:48:10.495719936 80 POST text/plain 69823\n", "2013-09-15 23:48:11.495719936 80 POST text/plain 69993\n", "2013-09-15 23:48:12.495719936 80 POST text/plain 71993\n", "2013-09-15 23:48:13.495719936 80 POST text/plain 70993\n", "2013-09-15 23:48:14.495719936 80 POST text/plain 72993\n", "\n", "Cluster 2: 7 observations\n", " id.resp_p method resp_mime_types request_body_len\n", "ts \n", "2013-09-15 23:48:03.495719936 8080 GET text/plain 0\n", "2013-09-15 23:48:04.495719936 8080 GET text/plain 0\n", "2013-09-15 23:48:04.495719936 8080 GET text/plain 0\n", "2013-09-15 23:48:04.495719936 8080 GET text/plain 0\n", "2013-09-15 23:48:04.495719936 8080 GET text/plain 0\n", "\n", "Cluster 3: 7 observations\n", " id.resp_p method resp_mime_types request_body_len\n", "ts \n", "2013-09-15 23:48:06.495719936 80 OPTIONS text/plain 0\n", "2013-09-15 23:48:07.495719936 80 OPTIONS text/plain 0\n", "2013-09-15 23:48:08.495719936 80 OPTIONS text/plain 0\n", "2013-09-15 23:48:08.495719936 80 OPTIONS text/plain 0\n", "2013-09-15 23:48:08.495719936 80 OPTIONS text/plain 0\n" ] } ], "source": [ "# Now print out the details for each cluster\n", "pd.set_option('display.width', 1000)\n", "for key, group in cluster_groups:\n", " print('\\nCluster {:d}: {:d} observations'.format(key, len(group)))\n", " print(group[features].head())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "####
\n", "## Categorical variables that are anomalous\n", "- Cluster 0: application/x-dosexec mime_types\n", "- Cluster 1: http method of OPTIONS (instead of normal GET/POST)\n", "- Cluster 2: See Below\n", "- Cluster 3: response port of 8080 (instead of 80)\n", "\n", "## Numerical variable outliers\n", "- Cluster 2: The request_body_len values are outliers (for this demo dataset)\n", "\n", "**The important thing here is that both categorical and numerical variables were properly handled and the machine learning algorithm 'did the right thing' when marking outliers (for categorical and numerical fields)**" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "For this small demo dataset almost all request_body_len are 0\n", "Cluster 2 represents outliers\n" ] }, { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "# Distribution of the request body length\n", "zeek_df[['request_body_len']].hist()\n", "print('\\nFor this small demo dataset almost all request_body_len are 0\\nCluster 2 represents outliers')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "## The anomalies identified by the model might be fine/expected\n", "Looking at the anomalous clusters for this small demo http log reveals four clusters that may be perfectly fine. So\n", "here we're not equating anomalous with 'bad'. The use of an anomaly detection algorithm can bring latent issues to the attention of threat hunters and system administrations. The results might be expected or a misconfigured appliance or something more nefarious that needs attention from security.\n", "\n", "\n", "If you liked this notebook please visit the [zat](https://github.com/SuperCowPowers/zat) project for more notebooks and examples.\n" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.9" } }, "nbformat": 4, "nbformat_minor": 2 }