diff --git a/1_experiment_train.ipynb b/1_experiment_train.ipynb index 34ac4d8..7b0feda 100644 --- a/1_experiment_train.ipynb +++ b/1_experiment_train.ipynb @@ -20,45 +20,19 @@ }, { "cell_type": "code", + "execution_count": null, "metadata": { - "is_executing": true, "ExecuteTime": { "end_time": "2024-08-19T15:45:05.830869Z", "start_time": "2024-08-19T15:45:04.819700Z" - } + }, + "is_executing": true, + "scrolled": true }, + "outputs": [], "source": [ "!pip install onnx onnxruntime tf2onnx" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Requirement already satisfied: onnx in ./venv/lib/python3.9/site-packages (1.16.2)\r\n", - "Requirement already satisfied: onnxruntime in ./venv/lib/python3.9/site-packages (1.19.0)\r\n", - "Requirement already satisfied: tf2onnx in ./venv/lib/python3.9/site-packages (1.16.1)\r\n", - "Requirement already satisfied: numpy>=1.20 in ./venv/lib/python3.9/site-packages (from onnx) (1.26.4)\r\n", - "Requirement already satisfied: protobuf>=3.20.2 in ./venv/lib/python3.9/site-packages (from onnx) (3.20.3)\r\n", - "Requirement already satisfied: coloredlogs in ./venv/lib/python3.9/site-packages (from onnxruntime) (15.0.1)\r\n", - "Requirement already satisfied: flatbuffers in ./venv/lib/python3.9/site-packages (from onnxruntime) (24.3.25)\r\n", - "Requirement already satisfied: packaging in ./venv/lib/python3.9/site-packages (from onnxruntime) (24.1)\r\n", - "Requirement already satisfied: sympy in ./venv/lib/python3.9/site-packages (from onnxruntime) (1.13.2)\r\n", - "Requirement already satisfied: requests in ./venv/lib/python3.9/site-packages (from tf2onnx) (2.32.3)\r\n", - "Requirement already satisfied: six in ./venv/lib/python3.9/site-packages (from tf2onnx) (1.16.0)\r\n", - "Requirement already satisfied: humanfriendly>=9.1 in ./venv/lib/python3.9/site-packages (from coloredlogs->onnxruntime) (10.0)\r\n", - "Requirement already satisfied: charset-normalizer<4,>=2 in ./venv/lib/python3.9/site-packages (from requests->tf2onnx) (3.3.2)\r\n", - "Requirement already satisfied: idna<4,>=2.5 in ./venv/lib/python3.9/site-packages (from requests->tf2onnx) (3.7)\r\n", - "Requirement already satisfied: urllib3<3,>=1.21.1 in ./venv/lib/python3.9/site-packages (from requests->tf2onnx) (1.26.19)\r\n", - "Requirement already satisfied: certifi>=2017.4.17 in ./venv/lib/python3.9/site-packages (from requests->tf2onnx) (2024.7.4)\r\n", - "Requirement already satisfied: mpmath<1.4,>=1.1.0 in ./venv/lib/python3.9/site-packages (from sympy->onnxruntime) (1.3.0)\r\n", - "\r\n", - "\u001B[1m[\u001B[0m\u001B[34;49mnotice\u001B[0m\u001B[1;39;49m]\u001B[0m\u001B[39;49m A new release of pip is available: \u001B[0m\u001B[31;49m23.2.1\u001B[0m\u001B[39;49m -> \u001B[0m\u001B[32;49m24.2\u001B[0m\r\n", - "\u001B[1m[\u001B[0m\u001B[34;49mnotice\u001B[0m\u001B[1;39;49m]\u001B[0m\u001B[39;49m To update, run: \u001B[0m\u001B[32;49mpip install --upgrade pip\u001B[0m\r\n" - ] - } - ], - "execution_count": 1 + ] }, { "cell_type": "markdown", @@ -69,12 +43,14 @@ }, { "cell_type": "code", + "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2024-08-19T15:45:08.983925Z", "start_time": "2024-08-19T15:45:05.835311Z" } }, + "outputs": [], "source": [ "import numpy as np\n", "import pandas as pd\n", @@ -88,9 +64,7 @@ "import onnx\n", "import pickle\n", "from pathlib import Path" - ], - "outputs": [], - "execution_count": 2 + ] }, { "cell_type": "markdown", @@ -119,12 +93,14 @@ }, { "cell_type": "code", + "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2024-08-19T15:45:09.394745Z", "start_time": "2024-08-19T15:45:09.051361Z" } }, + "outputs": [], "source": [ "# Set the input (X) and output (Y) data. \n", "# The only output data is whether it's fraudulent. All other fields are inputs to the model.\n", @@ -141,17 +117,17 @@ " 7 # fraud\n", "]\n", "\n", - "X_train = pd.read_csv('data/train.csv')\n", - "y_train = X_train.iloc[:, label_indexes]\n", - "X_train = X_train.iloc[:, feature_indexes]\n", + "df = pd.read_csv('data/train.csv')\n", + "X_train = df.iloc[:, feature_indexes].values\n", + "y_train = df.iloc[:, label_indexes].values\n", "\n", - "X_val = pd.read_csv('data/validate.csv')\n", - "y_val = X_val.iloc[:, label_indexes]\n", - "X_val = X_val.iloc[:, feature_indexes]\n", + "df = pd.read_csv('data/validate.csv')\n", + "X_val = df.iloc[:, feature_indexes].values\n", + "y_val = df.iloc[:, label_indexes].values\n", "\n", - "X_test = pd.read_csv('data/test.csv')\n", - "y_test = X_test.iloc[:, label_indexes]\n", - "X_test = X_test.iloc[:, feature_indexes]\n", + "df = pd.read_csv('data/test.csv')\n", + "X_test = df.iloc[:, feature_indexes].values\n", + "y_test = df.iloc[:, label_indexes].values\n", "\n", "\n", "# Scale the data to remove mean and have unit variance. The data will be between -1 and 1, which makes it a lot easier for the model to learn than random (and potentially large) values.\n", @@ -159,7 +135,9 @@ "\n", "scaler = StandardScaler()\n", "\n", - "X_train = scaler.fit_transform(X_train.values)\n", + "X_train = scaler.fit_transform(X_train)\n", + "X_val = scaler.transform(X_val)\n", + "X_test = scaler.transform(X_test)\n", "\n", "Path(\"artifact\").mkdir(parents=True, exist_ok=True)\n", "with open(\"artifact/test_data.pkl\", \"wb\") as handle:\n", @@ -168,11 +146,9 @@ " pickle.dump(scaler, handle)\n", "\n", "# Since the dataset is unbalanced (it has many more non-fraud transactions than fraudulent ones), set a class weight to weight the few fraudulent transactions higher than the many non-fraud transactions.\n", - "class_weights = class_weight.compute_class_weight('balanced', classes=np.unique(y_train), y=y_train.values.ravel())\n", + "class_weights = class_weight.compute_class_weight('balanced', classes=np.unique(y_train), y=y_train.ravel())\n", "class_weights = {i : class_weights[i] for i in range(len(class_weights))}" - ], - "outputs": [], - "execution_count": 3 + ] }, { "cell_type": "markdown", @@ -185,15 +161,17 @@ }, { "cell_type": "code", + "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2024-08-19T15:45:09.489856Z", "start_time": "2024-08-19T15:45:09.419813Z" } }, + "outputs": [], "source": [ "model = Sequential()\n", - "model.add(Dense(32, activation = 'relu', input_dim = len(feature_indexes)))\n", + "model.add(Dense(32, activation='relu', input_dim=len(feature_indexes)))\n", "model.add(Dropout(0.2))\n", "model.add(Dense(32))\n", "model.add(BatchNormalization())\n", @@ -203,52 +181,16 @@ "model.add(BatchNormalization())\n", "model.add(Activation('relu'))\n", "model.add(Dropout(0.2))\n", - "model.add(Dense(1, activation = 'sigmoid'))\n", - "model.compile(optimizer='adam',loss='binary_crossentropy',metrics=['accuracy'])\n", + "model.add(Dense(1, activation='sigmoid'))\n", + "\n", + "model.compile(\n", + " optimizer='adam',\n", + " loss='binary_crossentropy',\n", + " metrics=['accuracy']\n", + ")\n", + "\n", "model.summary()" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Model: \"sequential\"\n", - "_________________________________________________________________\n", - " Layer (type) Output Shape Param # \n", - "=================================================================\n", - " dense (Dense) (None, 32) 192 \n", - " \n", - " dropout (Dropout) (None, 32) 0 \n", - " \n", - " dense_1 (Dense) (None, 32) 1056 \n", - " \n", - " batch_normalization (Batch (None, 32) 128 \n", - " Normalization) \n", - " \n", - " activation (Activation) (None, 32) 0 \n", - " \n", - " dropout_1 (Dropout) (None, 32) 0 \n", - " \n", - " dense_2 (Dense) (None, 32) 1056 \n", - " \n", - " batch_normalization_1 (Bat (None, 32) 128 \n", - " chNormalization) \n", - " \n", - " activation_1 (Activation) (None, 32) 0 \n", - " \n", - " dropout_2 (Dropout) (None, 32) 0 \n", - " \n", - " dense_3 (Dense) (None, 1) 33 \n", - " \n", - "=================================================================\n", - "Total params: 2593 (10.13 KB)\n", - "Trainable params: 2465 (9.63 KB)\n", - "Non-trainable params: 128 (512.00 Byte)\n", - "_________________________________________________________________\n" - ] - } - ], - "execution_count": 4 + ] }, { "cell_type": "markdown", @@ -261,12 +203,14 @@ }, { "cell_type": "code", + "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2024-08-19T15:45:29.664796Z", "start_time": "2024-08-19T15:45:09.496686Z" } }, + "outputs": [], "source": [ "# Train the model and get performance\n", "import os\n", @@ -274,26 +218,17 @@ "\n", "start = time.time()\n", "epochs = 2\n", - "history = model.fit(X_train, y_train, epochs=epochs, \\\n", - " validation_data=(scaler.transform(X_val.values),y_val), \\\n", - " verbose = True, class_weight = class_weights)\n", + "history = model.fit(\n", + " X_train,\n", + " y_train,\n", + " epochs=epochs,\n", + " validation_data=(X_val, y_val),\n", + " verbose=True,\n", + " class_weight=class_weights\n", + ")\n", "end = time.time()\n", "print(f\"Training of model is complete. Took {end-start} seconds\")" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Epoch 1/2\n", - "18750/18750 [==============================] - 10s 509us/step - loss: 0.2619 - accuracy: 0.9263 - val_loss: 0.2423 - val_accuracy: 0.9425\n", - "Epoch 2/2\n", - "18750/18750 [==============================] - 10s 537us/step - loss: 0.2371 - accuracy: 0.9474 - val_loss: 0.1983 - val_accuracy: 0.9564\n", - "Training of model is complete. Took 20.165951013565063 seconds\n" - ] - } - ], - "execution_count": 5 + ] }, { "cell_type": "markdown", @@ -304,20 +239,35 @@ }, { "cell_type": "code", + "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2024-08-19T15:45:29.845680Z", "start_time": "2024-08-19T15:45:29.674230Z" } }, + "outputs": [], "source": [ + "import tensorflow as tf\n", + "\n", + "# Normally we use tf2.onnx.convert.from_keras.\n", + "# workaround for tf2onnx bug https://github.com/onnx/tensorflow-onnx/issues/2348\n", + "\n", + "# Wrap the model in a `tf.function`\n", + "@tf.function(input_signature=[tf.TensorSpec([None, X_train.shape[1]], tf.float32, name='dense_input')])\n", + "def model_fn(x):\n", + " return model(x)\n", + "\n", + "# Convert the Keras model to ONNX\n", + "model_proto, _ = tf2onnx.convert.from_function(\n", + " model_fn,\n", + " input_signature=[tf.TensorSpec([None, X_train.shape[1]], tf.float32, name='dense_input')]\n", + ")\n", + "\n", "# Save the model as ONNX for easy use of ModelMesh\n", - "model_proto, _ = tf2onnx.convert.from_keras(model)\n", "os.makedirs(\"models/fraud/1\", exist_ok=True)\n", "onnx.save(model_proto, \"models/fraud/1/model.onnx\")" - ], - "outputs": [], - "execution_count": 6 + ] }, { "cell_type": "markdown", @@ -337,40 +287,17 @@ }, { "cell_type": "code", + "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2024-08-19T15:45:30.012353Z", "start_time": "2024-08-19T15:45:29.856416Z" } }, + "outputs": [], "source": [ "! ls -alRh ./models/" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "total 0\r\n", - "drwxr-xr-x@ 3 cchase staff 96B Aug 19 11:42 \u001B[34m.\u001B[m\u001B[m\r\n", - "drwxr-xr-x 30 cchase staff 960B Aug 19 11:45 \u001B[34m..\u001B[m\u001B[m\r\n", - "drwxr-xr-x@ 3 cchase staff 96B Aug 19 11:42 \u001B[34mfraud\u001B[m\u001B[m\r\n", - "\r\n", - "./models//fraud:\r\n", - "total 0\r\n", - "drwxr-xr-x@ 3 cchase staff 96B Aug 19 11:42 \u001B[34m.\u001B[m\u001B[m\r\n", - "drwxr-xr-x@ 3 cchase staff 96B Aug 19 11:42 \u001B[34m..\u001B[m\u001B[m\r\n", - "drwxr-xr-x@ 3 cchase staff 96B Aug 19 11:42 \u001B[34m1\u001B[m\u001B[m\r\n", - "\r\n", - "./models//fraud/1:\r\n", - "total 32\r\n", - "drwxr-xr-x@ 3 cchase staff 96B Aug 19 11:42 \u001B[34m.\u001B[m\u001B[m\r\n", - "drwxr-xr-x@ 3 cchase staff 96B Aug 19 11:42 \u001B[34m..\u001B[m\u001B[m\r\n", - "-rw-r--r--@ 1 cchase staff 13K Aug 19 11:45 model.onnx\r\n" - ] - } - ], - "execution_count": 7 + ] }, { "cell_type": "markdown", @@ -381,20 +308,20 @@ }, { "cell_type": "code", + "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2024-08-19T15:45:30.047040Z", "start_time": "2024-08-19T15:45:30.029773Z" } }, + "outputs": [], "source": [ "from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay\n", "import numpy as np\n", "import pickle\n", "import onnxruntime as rt" - ], - "outputs": [], - "execution_count": 8 + ] }, { "cell_type": "markdown", @@ -405,20 +332,20 @@ }, { "cell_type": "code", + "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2024-08-19T15:45:30.062713Z", "start_time": "2024-08-19T15:45:30.058023Z" } }, + "outputs": [], "source": [ "with open('artifact/scaler.pkl', 'rb') as handle:\n", " scaler = pickle.load(handle)\n", "with open('artifact/test_data.pkl', 'rb') as handle:\n", " (X_test, y_test) = pickle.load(handle)" - ], - "outputs": [], - "execution_count": 9 + ] }, { "cell_type": "markdown", @@ -429,23 +356,23 @@ }, { "cell_type": "code", + "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2024-08-19T15:45:30.210272Z", "start_time": "2024-08-19T15:45:30.073900Z" } }, + "outputs": [], "source": [ "sess = rt.InferenceSession(\"models/fraud/1/model.onnx\", providers=rt.get_available_providers())\n", "input_name = sess.get_inputs()[0].name\n", "output_name = sess.get_outputs()[0].name\n", - "y_pred_temp = sess.run([output_name], {input_name: scaler.transform(X_test.values).astype(np.float32)}) \n", + "y_pred_temp = sess.run([output_name], {input_name: X_test.astype(np.float32)}) \n", "y_pred_temp = np.asarray(np.squeeze(y_pred_temp[0]))\n", "threshold = 0.95\n", "y_pred = np.where(y_pred_temp > threshold, 1, 0)" - ], - "outputs": [], - "execution_count": 10 + ] }, { "cell_type": "markdown", @@ -456,18 +383,20 @@ }, { "cell_type": "code", + "execution_count": null, "metadata": { - "tags": [], "ExecuteTime": { "end_time": "2024-08-19T15:45:30.644142Z", "start_time": "2024-08-19T15:45:30.221686Z" - } + }, + "tags": [] }, + "outputs": [], "source": [ "from sklearn.metrics import precision_score, recall_score, confusion_matrix, ConfusionMatrixDisplay\n", "import numpy as np\n", "\n", - "y_test_arr = y_test.to_numpy().squeeze()\n", + "y_test_arr = y_test.squeeze()\n", "correct = np.equal(y_pred, y_test_arr).sum().item()\n", "acc = (correct / len(y_pred)) * 100\n", "precision = precision_score(y_test_arr, np.round(y_pred))\n", @@ -478,39 +407,7 @@ "\n", "c_matrix = confusion_matrix(y_test_arr, y_pred)\n", "ConfusionMatrixDisplay(c_matrix).plot()" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Eval Metrics: \n", - " Accuracy: 97.4%, Precision: 0.9938, Recall: 0.6999 \n", - "\n" - ] - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "text/plain": [ - "
" - ], - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAhUAAAGwCAYAAAAe3Ze+AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAABKl0lEQVR4nO3de1wU9f4/8NcC7nKRXUWDZRURL6kkglJx6KhFcVzNn8XJvuWt0FDTI6aQ11JErfTo8ZomlSl60qN2kUo9JmJqJtkBJdOURDExWbRQVlBuu/P7g5jcQGHdGRHn9Xw85qE7856Z9/Lgwb73cxuVIAgCiIiIiBzk1NAJEBER0b2BRQURERFJgkUFERERSYJFBREREUmCRQURERFJgkUFERERSYJFBREREUnCpaETcITVasWFCxfg6ekJlUrV0OkQEZGdBEHA1atXYTAY4OQk3/fc0tJSlJeXO3wdtVoNV1dXCTK6NzXqouLChQvw8/Nr6DSIiMhBeXl5aN26tSzXLi0tRYB/U5guWhy+ll6vR25uLguLm2jURYWnpycA4OfDbaFtyp4cujf9/f6ghk6BSDaVqMAB7BD/nsuhvLwcposW/JzZFlrP2/+sMF+1wj/0LMrLy1lU3ESjLiqquzy0TZ0c+kUhupu5qJo0dApE8vn9QRF3ogu7qacKTT1v/z5WsJu9Lo26qCAiIqovi2CFxYGnXVkEq3TJ3KNYVBARkSJYIcCK268qHDlXKdhnQERERJJgSwURESmCFVY40oHh2NnKwKKCiIgUwSIIsAi334XhyLlKwe4PIiIikgRbKoiISBE4UFN+LCqIiEgRrBBgYVEhK3Z/EBERkSRYVBARkSJUd384stlj//79GDBgAAwGA1QqFVJSUmyOq1SqWreFCxeKMW3btq1xfP78+TbXOXr0KHr16gVXV1f4+flhwYIFNXL56KOP0LlzZ7i6uiIoKAg7duywOS4IAhISEuDr6ws3NzdERkbi1KlTdr1fgEUFEREpRPXsD0c2e5SUlCA4OBgrV66s9Xh+fr7NtmbNGqhUKgwcONAmbs6cOTZx48ePF4+ZzWb06dMH/v7+yMzMxMKFC5GYmIj33ntPjDl48CAGDx6MmJgYHDlyBFFRUYiKisKxY8fEmAULFmD58uVISkrCoUOH4OHhAaPRiNLSUrveM8dUEBER2cFsNtu81mg00Gg0NeL69euHfv363fQ6er3e5vVnn32GiIgItGvXzma/p6dnjdhqGzZsQHl5OdasWQO1Wo0HHngAWVlZWLx4MUaPHg0AWLZsGfr27YvJkycDAObOnYvU1FSsWLECSUlJEAQBS5cuxYwZM/D0008DANavXw8fHx+kpKRg0KBBdfxE/sCWCiIiUgSrBBsA+Pn5QafTidu8efMczq2goADbt29HTExMjWPz589HixYt0L17dyxcuBCVlZXisfT0dPTu3RtqtVrcZzQakZ2djcuXL4sxkZGRNtc0Go1IT08HAOTm5sJkMtnE6HQ6hIWFiTH1xZYKIiJSBIuDsz+qz83Ly4NWqxX319ZKYa9169bB09MTzzzzjM3+V155BT169ICXlxcOHjyI6dOnIz8/H4sXLwYAmEwmBAQE2Jzj4+MjHmvevDlMJpO478YYk8kkxt14Xm0x9cWigoiIFMEiwMGnlFb9q9VqbYoKKaxZswZDhw6Fq6urzf74+Hjx/926dYNarcbLL7+MefPmSVLMSI3dH0RERA3o66+/RnZ2NkaOHFlnbFhYGCorK3H27FkAVeMyCgoKbGKqX1ePw7hZzI3Hbzyvtpj6YlFBRESKINWYCql98MEHCA0NRXBwcJ2xWVlZcHJygre3NwAgPDwc+/fvR0VFhRiTmpqKTp06oXnz5mJMWlqazXVSU1MRHh4OAAgICIBer7eJMZvNOHTokBhTX+z+ICIiRbBCBQtUDp1vj+LiYuTk5Iivc3NzkZWVBS8vL7Rp0wZA1Yf3Rx99hEWLFtU4Pz09HYcOHUJERAQ8PT2Rnp6OuLg4DBs2TCwYhgwZgtmzZyMmJgZTp07FsWPHsGzZMixZskS8zoQJE/Doo49i0aJF6N+/PzZt2oSMjAxx2qlKpcLEiRPxxhtvoGPHjggICMDMmTNhMBgQFRVl13tmUUFERCSDjIwMREREiK+rx0dER0cjOTkZALBp0yYIgoDBgwfXOF+j0WDTpk1ITExEWVkZAgICEBcXZzPOQqfTYdeuXRg3bhxCQ0PRsmVLJCQkiNNJAeCRRx7Bxo0bMWPGDLz22mvo2LEjUlJS0LVrVzFmypQpKCkpwejRo3HlyhX07NkTO3furDHGoy4qQWi8z3I1m83Q6XS4/FM7aD3Zk0P3JqMhpKFTIJJNpVCBvfgMRUVFkg9+rFb9WZFx3AdNHfisKL5qxYMPFMiaa2PHlgoiIlIEi4PdH46cqxT8ek9ERESSYEsFEREpAlsq5MeigoiIFMEqqGAVHJj94cC5SsHuDyIiIpIEWyqIiEgR2P0hPxYVRESkCBY4weJAA71FwlzuVSwqiIhIEQQHx1QIHFNRJ46pICIiIkmwpYKIiBSBYyrkx6KCiIgUwSI4wSI4MKai0T7U4s5h9wcRERFJgi0VRESkCFaoYHXgu7QVbKqoC4sKIiJSBI6pkB+7P4iIiEgSbKkgIiJFcHygJrs/6sKigoiIFKFqTIUDDxRj90ed2P1BREREkmBLBRERKYLVwWd/cPZH3VhUEBGRInBMhfxYVBARkSJY4cR1KmTGMRVEREQkCbZUEBGRIlgEFSwOPL7ckXOVgkUFEREpgsXBgZoWdn/Uid0fREREJAm2VBARkSJYBSdYHZj9YeXsjzqxqCAiIkVg94f82P1BREREkmBLBRERKYIVjs3gsEqXyj2LRQURESmC44tfsXG/LvwJERERkSTYUkFERIrg+LM/+D28LiwqiIhIEaxQwQpHxlRwRc26sKggIiJFYEuF/PgTIiIiIkmwpYKIiBTB8cWv+D28LiwqiIhIEayCClZH1qngU0rrxLKLiIiIJMGWCiIiUgSrg90fXPyqbvwJERGRIlQ/pdSRzR779+/HgAEDYDAYoFKpkJKSYnN8+PDhUKlUNlvfvn1tYgoLCzF06FBotVo0a9YMMTExKC4utok5evQoevXqBVdXV/j5+WHBggU1cvnoo4/QuXNnuLq6IigoCDt27LA5LggCEhIS4OvrCzc3N0RGRuLUqVN2vV+ARQUREZEsSkpKEBwcjJUrV940pm/fvsjPzxe3//znPzbHhw4diuPHjyM1NRXbtm3D/v37MXr0aPG42WxGnz594O/vj8zMTCxcuBCJiYl47733xJiDBw9i8ODBiImJwZEjRxAVFYWoqCgcO3ZMjFmwYAGWL1+OpKQkHDp0CB4eHjAajSgtLbXrPasEofE+IN5sNkOn0+HyT+2g9WR9RPcmoyGkoVMgkk2lUIG9+AxFRUXQarWy3KP6s2Lud4/Dtent9/qXFldi5sN7bitXlUqFrVu3IioqStw3fPhwXLlypUYLRrUTJ04gMDAQ//vf//Dggw8CAHbu3Iknn3wS58+fh8FgwKpVq/D666/DZDJBrVYDAKZNm4aUlBScPHkSAPD888+jpKQE27ZtE6/9l7/8BSEhIUhKSoIgCDAYDHj11VcxadIkAEBRURF8fHyQnJyMQYMG1ft98pOYiIgUQaruD7PZbLOVlZXddk579+6Ft7c3OnXqhLFjx+K3334Tj6Wnp6NZs2ZiQQEAkZGRcHJywqFDh8SY3r17iwUFABiNRmRnZ+Py5ctiTGRkpM19jUYj0tPTAQC5ubkwmUw2MTqdDmFhYWJMfbGoICIisoOfnx90Op24zZs377au07dvX6xfvx5paWn45z//iX379qFfv36wWCwAAJPJBG9vb5tzXFxc4OXlBZPJJMb4+PjYxFS/rivmxuM3nldbTH1x9gcRESmCBYDFged3WH7/Ny8vz6b7Q6PR3Nb1buxWCAoKQrdu3dC+fXvs3bsXTzzxxG3n2ZDYUkFERIogVfeHVqu12W63qPizdu3aoWXLlsjJyQEA6PV6XLx40SamsrIShYWF0Ov1YkxBQYFNTPXrumJuPH7jebXF1BeLCiIiUoTqB4o5ssnp/Pnz+O233+Dr6wsACA8Px5UrV5CZmSnG7NmzB1arFWFhYWLM/v37UVFRIcakpqaiU6dOaN68uRiTlpZmc6/U1FSEh4cDAAICAqDX621izGYzDh06JMbUF4sKIiIiGRQXFyMrKwtZWVkAqgZEZmVl4dy5cyguLsbkyZPx7bff4uzZs0hLS8PTTz+NDh06wGg0AgC6dOmCvn37YtSoUfjuu+/wzTffIDY2FoMGDYLBYAAADBkyBGq1GjExMTh+/Dg2b96MZcuWIT4+XsxjwoQJ2LlzJxYtWoSTJ08iMTERGRkZiI2NBVA1M2XixIl444038Pnnn+OHH37Aiy++CIPBYDNbpT44poKIiBRBgApWB8ZUCHaem5GRgYiICPF19Qd9dHQ0Vq1ahaNHj2LdunW4cuUKDAYD+vTpg7lz59p0p2zYsAGxsbF44okn4OTkhIEDB2L58uXicZ1Oh127dmHcuHEIDQ1Fy5YtkZCQYLOWxSOPPIKNGzdixowZeO2119CxY0ekpKSga9euYsyUKVNQUlKC0aNH48qVK+jZsyd27twJV1dXu94z16kgustxnQq6l93JdSomH+wPTdMmt32dsuIKLHxku6y5Nnb8JCYiIiJJsPuDiIgUgY8+lx+LCiIiUgSLg08pdeRcpeBPiIiIiCTBlgoiIlIEdn/Ij0UFEREpghVOsDrQQO/IuUrBnxARERFJgi0VRESkCBZBBYsDXRiOnKsULCqIiEgROKZCfiwqiIhIEYQbnjR6u+fTrfEnRERERJJgSwURESmCBSpYHHigmCPnKgWLCiIiUgSr4Ni4CGujffzmncPuDyIiIpIEWyruMT9864GP3vHGqR/cUVjQBLM+yMUj/YrE49dLnPDBm75I/1IH82UX6P3K8XTMJfy/F38DAJgvO+Pf/9Lj8D5PXLyghs6rEo/0LUL0lHx4aK3idWp7HPf0d87isagrNfYf/84DkwZ2QNtOpVi1O7veuRLJZd2hH6H3q6ix//PkFlj5WmsAQJfQEgyfakLnHtdgsQBnjrvhtSHtUF7K72KNldXBgZqOnKsULCruMaXXnNDugeswDi7EnJiAGsffTTQg6xtPTHn7HHz8ynF4nyfent4aLXwqEG40o7CgCX4raIJRCRfQ5v5SXDyvxvJprfFbQRPMfP+szbVeXXIOD0aYxddNtZYa9ysucsbCCW3QvedVXL7UxK5cieTySr/74eT8R1t2286lmL/5DL7+ohmAqoLizQ1nsGmFN96Z0QoWC9AusBSC9SYXpEbBChWsDoyLcORcpbgrioqVK1di4cKFMJlMCA4Oxttvv42HH364odNqlB56/CoeevzqTY//mOGBv/1fIYIfKQYAPDnsN2z/dwtkZ7kj3GhG286lSFh9Vow3tC3H8Kn5WDDeH5ZKwPmG35imWgu8vCtvmc/yqa0R8ffLcHICDu7U2ZUrkVyKCm3/9D0fexEXctU4mu4BAHg58QJSPmiJLSt8xJjzp13vaI5EjVGDt+Vs3rwZ8fHxmDVrFg4fPozg4GAYjUZcvHixoVO7JwU+WIJvd+nwa34TCAKQ9U1T/HJGg9BHb/7hXmJ2hntTq01BAQArXm+F/3ugK8Y/2RFf/scLwp8GMX25yQv559QYFm+S4Z0QScOliRWPD7yMLzd5AVBB16ICXUKv4cpvLljy+Sls+v44Fn6SgwceLm7oVMlB1StqOrLRrTV4S8XixYsxatQojBgxAgCQlJSE7du3Y82aNZg2bVoDZ3fv+ccbv2DZFD8MDX0Azi4CnJwETFiYh6C/lNQaX/SbMzYu1aPfsF9t9r84OR8hfy2Gxs2KzH2eePu11rhe4oSokVVxv5xRY81bvli0NadGMUJ0N3mkrxlNtRbs2uIFAPD1LwcAvBBfgPfnGnD6uCsin72M+ZvP4OXHO+FCrqYh0yUHcEyF/Br0z315eTkyMzMxffp0cZ+TkxMiIyORnp5eI76srAxlZWXia7PZXCOGbu2zNS1xMtMds5PPwLt1OX74tilWvlY1pqJHb9tvYiVXnTDzxXZoc38pXnjVtrVhaFyB+P8OQddRes0JH63yRtTIX2GxAPPHtcULk0xo3b4MRHcz4+Df8L+vtCgsqBrz4/T758aOD1tg1+aqQuP0MXeE9CyGcVAh1s7zbahUie56DVpU/Prrr7BYLPDx8bHZ7+Pjg5MnT9aInzdvHmbPnn2n0rvnlF1XIXm+LxI+OIuwyKqCrF1gKc4cd8PHSd42RcW1Yie8PqQ93DysmPVBLlya3OyqVTr3uIaNS/UoL1OhvNQJP33vjpxjblj5etVIesEKCIIK/fyCMe8/pxHSk03J1PC8W5Wje69izB3ZVtz3W0HVn8Wff7IdQ5GXo4F3q/I7mR5JzAoHn/3BgZp1alQN09OnT0d8fLz42mw2w8/PrwEzalwqK1WorHCCk5Pt4AcnZ8FmVHvJ1aqCoolawOzkM1C71r3iy+njbmjarBJqjQCXJha8u8e2KPxiXUtkHWiKme+fhb4N/zDT3aHPoEJc+dUFh3ZrxX0FeWr8mu+C1u1LbWJbtStDxh7tny9BjYjg4OwPgUVFnRq0qGjZsiWcnZ1RUFBgs7+goAB6vb5GvEajgUbD/sxbuV7iZNPna8pT4/QxN3g2q4R36wp0Cy/G+3MNULv+Ap/W5Tia3hS7P/bC6Fm/AKgqKF4b3B5l150w5e1cXCt2xrXfGxV0LSrh7Ax8u0uLy5dc0CX0GpporDi83xOblnvj2TGXAFQ1H7ftbPsHuVmLqoLjxv115UokJ5VKQJ/nC7H7o+awWm78sFDh41XeeGGSCWd+dMOZ426I/L9C+LUvwxujvBosX3Icn1IqvwYtKtRqNUJDQ5GWloaoqCgAgNVqRVpaGmJjYxsytUbrp+/dMeXZDuLrdxNbAQD+9lwhJi09h+mrzmLNW774Z2wbXL3iAu9WVVNGqxe/yvnBHScPV02rG/FIoM21qxYMKodzEwFfJLfEu4kaCELVtNOXEy+g39DfJM2VSE7dexfDp3UFvtzUosaxravvQxNXK8bMvgDPZhac+dEV0we3Q/7P/FJDdCsqQfjzRMA7a/PmzYiOjsa7776Lhx9+GEuXLsWWLVtw8uTJGmMt/sxsNkOn0+HyT+2g9eSoXLo31bZ6KdG9olKowF58hqKiImi18nQvVX9W/D11BJp4qG/7OhUl5dj6t7Wy5trYNfiYiueffx6XLl1CQkICTCYTQkJCsHPnzjoLCiIiInuw+0N+DV5UAEBsbCy7O4iIiBq5u6KoICIikhuf/SE/FhVERKQI7P6QH0c3EhERkSTYUkFERIrAlgr5saggIiJFYFEhP3Z/EBERkSTYUkFERIrAlgr5saggIiJFEODYtNAGXX66kWBRQUREisCWCvlxTAURERFJgi0VRESkCGypkB+LCiIiUgQWFfJj9wcRERFJgkUFEREpQnVLhSObPfbv348BAwbAYDBApVIhJSVFPFZRUYGpU6ciKCgIHh4eMBgMePHFF3HhwgWba7Rt2xYqlcpmmz9/vk3M0aNH0atXL7i6usLPzw8LFiyokctHH32Ezp07w9XVFUFBQdixY4fNcUEQkJCQAF9fX7i5uSEyMhKnTp2y6/0CLCqIiEghBEHl8GaPkpISBAcHY+XKlTWOXbt2DYcPH8bMmTNx+PBhfPrpp8jOzsZTTz1VI3bOnDnIz88Xt/Hjx4vHzGYz+vTpA39/f2RmZmLhwoVITEzEe++9J8YcPHgQgwcPRkxMDI4cOYKoqChERUXh2LFjYsyCBQuwfPlyJCUl4dChQ/Dw8IDRaERpaald75ljKoiIiGTQr18/9OvXr9ZjOp0OqampNvtWrFiBhx9+GOfOnUObNm3E/Z6entDr9bVeZ8OGDSgvL8eaNWugVqvxwAMPICsrC4sXL8bo0aMBAMuWLUPfvn0xefJkAMDcuXORmpqKFStWICkpCYIgYOnSpZgxYwaefvppAMD69evh4+ODlJQUDBo0qN7vmS0VRESkCFaoHN6AqtaBG7eysjJJ8isqKoJKpUKzZs1s9s+fPx8tWrRA9+7dsXDhQlRWVorH0tPT0bt3b6jVanGf0WhEdnY2Ll++LMZERkbaXNNoNCI9PR0AkJubC5PJZBOj0+kQFhYmxtQXWyqIiEgRpJr94efnZ7N/1qxZSExMdCQ1lJaWYurUqRg8eDC0Wq24/5VXXkGPHj3g5eWFgwcPYvr06cjPz8fixYsBACaTCQEBATbX8vHxEY81b94cJpNJ3HdjjMlkEuNuPK+2mPpiUUFERGSHvLw8mw9+jUbj0PUqKirw3HPPQRAErFq1yuZYfHy8+P9u3bpBrVbj5Zdfxrx58xy+rxzY/UFERIog1UBNrVZrszny4V5dUPz8889ITU21KVZqExYWhsrKSpw9exYAoNfrUVBQYBNT/bp6HMbNYm48fuN5tcXUF4sKIiJShDs9pbQu1QXFqVOnsHv3brRo0aLOc7KysuDk5ARvb28AQHh4OPbv34+KigoxJjU1FZ06dULz5s3FmLS0NJvrpKamIjw8HAAQEBAAvV5vE2M2m3Ho0CExpr7Y/UFERIpwO9NC/3y+PYqLi5GTkyO+zs3NRVZWFry8vODr64tnn30Whw8fxrZt22CxWMTxC15eXlCr1UhPT8ehQ4cQEREBT09PpKenIy4uDsOGDRMLhiFDhmD27NmIiYnB1KlTcezYMSxbtgxLliwR7zthwgQ8+uijWLRoEfr3749NmzYhIyNDnHaqUqkwceJEvPHGG+jYsSMCAgIwc+ZMGAwGREVF2fWeWVQQERHJICMjAxEREeLr6vER0dHRSExMxOeffw4ACAkJsTnvq6++wmOPPQaNRoNNmzYhMTERZWVlCAgIQFxcnM04C51Oh127dmHcuHEIDQ1Fy5YtkZCQIE4nBYBHHnkEGzduxIwZM/Daa6+hY8eOSElJQdeuXcWYKVOmoKSkBKNHj8aVK1fQs2dP7Ny5E66urna9Z5UgCI32EfFmsxk6nQ6Xf2oHrSd7cujeZDSENHQKRLKpFCqwF5+hqKiozvEEt6v6s6LHx/Fw9rj98Q+WkjIcfnaxrLk2dmypICIiRRAAOPI1utF+A7+D+PWeiIiIJMGWCiIiUgQrVFDBgcWvHDhXKVhUEBGRItzp2R9KxO4PIiIikgRbKoiISBGsggoqCZ79QTfHooKIiBRBEByc/cHpH3Vi9wcRERFJgi0VRESkCByoKT8WFUREpAgsKuTHooKIiBSBAzXlxzEVREREJAm2VBARkSJw9of8WFQQEZEiVBUVjoypkDCZexS7P4iIiEgSbKkgIiJF4OwP+bGoICIiRRB+3xw5n26N3R9EREQkCbZUEBGRIrD7Q34sKoiISBnY/yE7FhVERKQMDrZUgC0VdeKYCiIiIpIEWyqIiEgRuKKm/FhUEBGRInCgpvzY/UFERESSYEsFEREpg6BybLAlWyrqxKKCiIgUgWMq5MfuDyIiIpIEWyqIiEgZuPiV7FhUEBGRInD2h/zqVVR8/vnn9b7gU089ddvJEBERUeNVr6IiKiqqXhdTqVSwWCyO5ENERCQfdmHIql5FhdVqlTsPIiIiWbH7Q34Ozf4oLS2VKg8iIiJ5CRJsdEt2FxUWiwVz585Fq1at0LRpU5w5cwYAMHPmTHzwwQeSJ0hERESNg91FxZtvvonk5GQsWLAAarVa3N+1a1esXr1a0uSIiIiko5Jgo1uxu6hYv3493nvvPQwdOhTOzs7i/uDgYJw8eVLS5IiIiCTD7g/Z2V1U/PLLL+jQoUON/VarFRUVFZIkRURERI2P3UVFYGAgvv766xr7P/74Y3Tv3l2SpIiIiCTHlgrZ2b2iZkJCAqKjo/HLL7/AarXi008/RXZ2NtavX49t27bJkSMREZHj+JRS2dndUvH000/jiy++wO7du+Hh4YGEhAScOHECX3zxBf72t7/JkSMREVGjs3//fgwYMAAGgwEqlQopKSk2xwVBQEJCAnx9feHm5obIyEicOnXKJqawsBBDhw6FVqtFs2bNEBMTg+LiYpuYo0ePolevXnB1dYWfnx8WLFhQI5ePPvoInTt3hqurK4KCgrBjxw67c6mP21qnolevXkhNTcXFixdx7do1HDhwAH369LmdSxEREd0R1Y8+d2SzR0lJCYKDg7Fy5cpajy9YsADLly9HUlISDh06BA8PDxiNRps1oIYOHYrjx48jNTUV27Ztw/79+zF69GjxuNlsRp8+feDv74/MzEwsXLgQiYmJeO+998SYgwcPYvDgwYiJicGRI0cQFRWFqKgoHDt2zK5c6kMlCLf3hPiMjAycOHECQNU4i9DQ0Nu5jEPMZjN0Oh0u/9QOWk8+xZ3uTUZDSEOnQCSbSqECe/EZioqKoNVqZblH9WdF67dnw8nN9bavY71eivPjZyEvL88mV41GA41Gc8tzVSoVtm7dKj72QhAEGAwGvPrqq5g0aRIAoKioCD4+PkhOTsagQYNw4sQJBAYG4n//+x8efPBBAMDOnTvx5JNP4vz58zAYDFi1ahVef/11mEwmcZmHadOmISUlRZyR+fzzz6OkpMRmiMJf/vIXhISEICkpqV651Jfdn8Tnz59Hr1698PDDD2PChAmYMGECHnroIfTs2RPnz5+393JERESNip+fH3Q6nbjNmzfP7mvk5ubCZDIhMjJS3KfT6RAWFob09HQAQHp6Opo1ayYWFAAQGRkJJycnHDp0SIzp3bu3zbpRRqMR2dnZuHz5shhz432qY6rvU59c6svuomLkyJGoqKjAiRMnUFhYiMLCQpw4cQJWqxUjR46093JERER3RvVATUc2AHl5eSgqKhK36dOn252KyWQCAPj4+Njs9/HxEY+ZTCZ4e3vbHHdxcYGXl5dNTG3XuPEeN4u58XhdudSX3bM/9u3bh4MHD6JTp07ivk6dOuHtt99Gr1697L0cERHRHaESqjZHzgcArVYrW1dNY2d3S4Wfn1+ti1xZLBYYDAZJkiIiIpLcXbROhV6vBwAUFBTY7C8oKBCP6fV6XLx40eZ4ZWUlCgsLbWJqu8aN97hZzI3H68qlvuwuKhYuXIjx48cjIyND3JeRkYEJEybgX//6l72XIyIiUpyAgADo9XqkpaWJ+8xmMw4dOoTw8HAAQHh4OK5cuYLMzEwxZs+ePbBarQgLCxNj9u/fb/NlPzU1FZ06dULz5s3FmBvvUx1TfZ/65FJf9er+aN68OVSqPxb9KCkpQVhYGFxcqk6vrKyEi4sLXnrpJXFkKxER0V3lDi9+VVxcjJycHPF1bm4usrKy4OXlhTZt2mDixIl444030LFjRwQEBGDmzJkwGAzi52iXLl3Qt29fjBo1CklJSaioqEBsbCwGDRok9gwMGTIEs2fPRkxMDKZOnYpjx45h2bJlWLJkiXjfCRMm4NFHH8WiRYvQv39/bNq0CRkZGeK0U5VKVWcu9VWvomLp0qV2XZSIiOiu42gXhp3nZmRkICIiQnwdHx8PAIiOjkZycjKmTJmCkpISjB49GleuXEHPnj2xc+dOuLr+Me11w4YNiI2NxRNPPAEnJycMHDgQy5cvF4/rdDrs2rUL48aNQ2hoKFq2bImEhASbtSweeeQRbNy4ETNmzMBrr72Gjh07IiUlBV27dhVj6pNLfdz2OhV3A65TQUrAdSroXnYn16nwWzzX4XUq8uJnypprY2f37I8blZaWory83GYff9BERHRXusMtFUpk99f7kpISxMbGwtvbGx4eHmjevLnNRkREdFe6i2Z/3KvsLiqmTJmCPXv2YNWqVdBoNFi9ejVmz54Ng8GA9evXy5EjERERNQJ2d3988cUXWL9+PR577DGMGDECvXr1QocOHeDv748NGzZg6NChcuRJRETkGD76XHZ2t1QUFhaiXbt2AKrGTxQWFgIAevbsif3790ubHRERkUSqV9R0ZKNbs7uoaNeuHXJzcwEAnTt3xpYtWwBUtWA0a9ZM0uSIiIio8bC7qBgxYgS+//57AFWPV125ciVcXV0RFxeHyZMnS54gERGRJDhQU3Z2j6mIi4sT/x8ZGYmTJ08iMzMTHTp0QLdu3SRNjoiIiBoPh9apAAB/f3/4+/tLkQsREZFsVHDwKaWSZXLvqldRceOSoHV55ZVXbjsZIiIiarzqVVTc+GCSW1GpVA1SVAwMeRguKvUdvy/RneDs07ShUyCSjWAtBy7WHSfNzTilVG71KiqqZ3sQERE1WlymW3Z8ChcRERFJwuGBmkRERI0CWypkx6KCiIgUwdFVMbmiZt3Y/UFERESSYEsFEREpA7s/ZHdbLRVff/01hg0bhvDwcPzyyy8AgH//+984cOCApMkRERFJhst0y87uouKTTz6B0WiEm5sbjhw5grKyMgBAUVER3nrrLckTJCIiosbB7qLijTfeQFJSEt5//300adJE3P/Xv/4Vhw8fljQ5IiIiqfDR5/Kze0xFdnY2evfuXWO/TqfDlStXpMiJiIhIelxRU3Z2t1To9Xrk5OTU2H/gwAG0a9dOkqSIiIgkxzEVsrO7qBg1ahQmTJiAQ4cOQaVS4cKFC9iwYQMmTZqEsWPHypEjERERNQJ2d39MmzYNVqsVTzzxBK5du4bevXtDo9Fg0qRJGD9+vBw5EhEROYyLX8nP7qJCpVLh9ddfx+TJk5GTk4Pi4mIEBgaiaVM+SZGIiO5iXKdCdre9+JVarUZgYKCUuRAREVEjZndRERERAZXq5iNg9+zZ41BCREREsnB0WihbKupkd1EREhJi87qiogJZWVk4duwYoqOjpcqLiIhIWuz+kJ3dRcWSJUtq3Z+YmIji4mKHEyIiIqLGSbKnlA4bNgxr1qyR6nJERETS4joVspPsKaXp6elwdXWV6nJERESS4pRS+dldVDzzzDM2rwVBQH5+PjIyMjBz5kzJEiMiIqLGxe6iQqfT2bx2cnJCp06dMGfOHPTp00eyxIiIiKhxsauosFgsGDFiBIKCgtC8eXO5ciIiIpIeZ3/Izq6Bms7OzujTpw+fRkpERI0OH30uP7tnf3Tt2hVnzpyRIxciIiJqxOwuKt544w1MmjQJ27ZtQ35+Psxms81GRER01+J0UlnVe0zFnDlz8Oqrr+LJJ58EADz11FM2y3ULggCVSgWLxSJ9lkRERI7imArZ1buomD17NsaMGYOvvvpKznyIiIiokap394cgVJVojz766C03IiKiu9GdHqjZtm1bqFSqGtu4ceMAAI899liNY2PGjLG5xrlz59C/f3+4u7vD29sbkydPRmVlpU3M3r170aNHD2g0GnTo0AHJyck1clm5ciXatm0LV1dXhIWF4bvvvrPvzdSTXWMqbvV0UiIiorvaHV6m+3//+x/y8/PFLTU1FQDwf//3f2LMqFGjbGIWLFggHrNYLOjfvz/Ky8tx8OBBrFu3DsnJyUhISBBjcnNz0b9/f0RERCArKwsTJ07EyJEj8eWXX4oxmzdvRnx8PGbNmoXDhw8jODgYRqMRFy9etO8N1YNd61Tcf//9dRYWhYWFDiVERER0L7jvvvtsXs+fPx/t27e3adV3d3eHXq+v9fxdu3bhxx9/xO7du+Hj44OQkBDMnTsXU6dORWJiItRqNZKSkhAQEIBFixYBALp06YIDBw5gyZIlMBqNAIDFixdj1KhRGDFiBAAgKSkJ27dvx5o1azBt2jRJ37NdRcXs2bNrrKhJRETUGEj17I8/z3TUaDTQaDS3PLe8vBwffvgh4uPjbb6cb9iwAR9++CH0ej0GDBiAmTNnwt3dHUDVM7WCgoLg4+MjxhuNRowdOxbHjx9H9+7dkZ6ejsjISJt7GY1GTJw4UbxvZmYmpk+fLh53cnJCZGQk0tPT7f4Z1MWuomLQoEHw9vaWPAkiIiLZSTT7w8/Pz2b3rFmzkJiYeMtTU1JScOXKFQwfPlzcN2TIEPj7+8NgMODo0aOYOnUqsrOz8emnnwIATCaTTUEBQHxtMpluGWM2m3H9+nVcvnwZFoul1piTJ0/W623bo95FBcdTEBERAXl5edBqteLrulopAOCDDz5Av379YDAYxH2jR48W/x8UFARfX1888cQTOH36NNq3by9t0ndIvYuK6tkfREREjZJELRVardamqKjLzz//jN27d4stEDcTFhYGAMjJyUH79u2h1+trzNIoKCgAAHEchl6vF/fdGKPVauHm5gZnZ2c4OzvXGnOzsRyOqPfsD6vVyq4PIiJqtBrq2R9r166Ft7c3+vfvf8u4rKwsAICvry8AIDw8HD/88IPNLI3U1FRotVoEBgaKMWlpaTbXSU1NRXh4OABArVYjNDTUJsZqtSItLU2MkZLdy3QTERE1Snd4SilQ9QG+du1aREdHw8Xlj86B06dPY+7cucjMzMTZs2fx+eef48UXX0Tv3r3RrVs3AECfPn0QGBiIF154Ad9//z2+/PJLzJgxA+PGjRO7XMaMGYMzZ85gypQpOHnyJN555x1s2bIFcXFx4r3i4+Px/vvvY926dThx4gTGjh2LkpIScTaIlOwaqElERET1t3v3bpw7dw4vvfSSzX61Wo3du3dj6dKlKCkpgZ+fHwYOHIgZM2aIMc7Ozti2bRvGjh2L8PBweHh4IDo6GnPmzBFjAgICsH37dsTFxWHZsmVo3bo1Vq9eLU4nBYDnn38ely5dQkJCAkwmE0JCQrBz584agzeloBIa8WAJs9kMnU6Hx90HwUWlbuh0iGSh8mza0CkQyabSWo60i6tRVFRk1zgFe1R/VnSa8BacNa63fR1LWSmyl70ma66NHVsqiIhIEaRap4JujmMqiIiISBJsqSAiImXgo89lx6KCiIgUgd0f8mP3BxEREUmCLRVERKQM7P6QHYsKIiJSBhYVsmP3BxEREUmCLRVERKQIqt83R86nW2NRQUREysDuD9mxqCAiIkXglFL5cUwFERERSYItFUREpAzs/pAdiwoiIlIOFgayYvcHERERSYItFUREpAgcqCk/FhVERKQMHFMhO3Z/EBERkSTYUkFERIrA7g/5saggIiJlYPeH7Nj9QURERJJgSwURESkCuz/kx6KCiIiUgd0fsmNRQUREysCiQnYcU0FERESSYEsFEREpAsdUyI9FBRERKQO7P2TH7g8iIiKSBFsqiIhIEVSCAJVw+80NjpyrFCwqiIhIGdj9ITt2fxAREZEk2FJBRESKwNkf8mNRQUREysDuD9mx+4OIiIgkwZYKIiJSBHZ/yI9FBRERKQO7P2THooKIiBSBLRXy45gKIiIikgRbKoiISBnY/SE7FhVERKQY7MKQF7s/iIiIZJCYmAiVSmWzde7cWTxeWlqKcePGoUWLFmjatCkGDhyIgoICm2ucO3cO/fv3h7u7O7y9vTF58mRUVlbaxOzduxc9evSARqNBhw4dkJycXCOXlStXom3btnB1dUVYWBi+++47Wd4ziwoiIlIGQXB8s9MDDzyA/Px8cTtw4IB4LC4uDl988QU++ugj7Nu3DxcuXMAzzzwjHrdYLOjfvz/Ky8tx8OBBrFu3DsnJyUhISBBjcnNz0b9/f0RERCArKwsTJ07EyJEj8eWXX4oxmzdvRnx8PGbNmoXDhw8jODgYRqMRFy9evM0f5M2xqCAiIkWonv3hyGYvFxcX6PV6cWvZsiUAoKioCB988AEWL16Mxx9/HKGhoVi7di0OHjyIb7/9FgCwa9cu/Pjjj/jwww8REhKCfv36Ye7cuVi5ciXKy8sBAElJSQgICMCiRYvQpUsXxMbG4tlnn8WSJUvEHBYvXoxRo0ZhxIgRCAwMRFJSEtzd3bFmzRrHf6h/wqKCiIjIDmaz2WYrKyu7aeypU6dgMBjQrl07DB06FOfOnQMAZGZmoqKiApGRkWJs586d0aZNG6SnpwMA0tPTERQUBB8fHzHGaDTCbDbj+PHjYsyN16iOqb5GeXk5MjMzbWKcnJwQGRkpxkiJRQURESmDIMEGwM/PDzqdTtzmzZtX6+3CwsKQnJyMnTt3YtWqVcjNzUWvXr1w9epVmEwmqNVqNGvWzOYcHx8fmEwmAIDJZLIpKKqPVx+7VYzZbMb169fx66+/wmKx1BpTfQ0pcfYHEREpgspatTlyPgDk5eVBq9WK+zUaTa3x/fr1E//frVs3hIWFwd/fH1u2bIGbm9vtJ3IXY0sFERGRHbRarc12s6Liz5o1a4b7778fOTk50Ov1KC8vx5UrV2xiCgoKoNfrAQB6vb7GbJDq13XFaLVauLm5oWXLlnB2dq41pvoaUmJLhcIMfSUPw145b7Mv77QrRhu7o6muAi9MOI8ePa/gPkMZigqbID3VC+uX+OFa8R+/KmNm5iIw9Cra3n8N53LcEPtUcC13EjAwJh99BxXAp1UZigpdsH2DHptWtZb5HZLSdO1xGQNfPIsOgWa0uK8cc+OCkb7XGwDg7GLFi/84jYd6/gp962soKXZB1qEWWLu8AwovuYrXeD7mDB7q9Sva3X8VlZVOeK53RK33ihxwAX8f9jNa+V/DtRJnHEj1wTvzuwAAhr58GkPHnKlxTul1JzzzyBMyvHOyWwMvflVcXIzTp0/jhRdeQGhoKJo0aYK0tDQMHDgQAJCdnY1z584hPDwcABAeHo4333wTFy9ehLd31e90amoqtFotAgMDxZgdO3bY3Cc1NVW8hlqtRmhoKNLS0hAVFQUAsFqtSEtLQ2xsrGNvqBYsKhTo7E9ueO3FQPG1xaICALTwroCXdzlWz/fHuRx3eBvKEDv3DFr4lOPN2E4219j1sTc6BV9FQKdrtd5jzMyz6NHzClbP98fZbHd46irh2ayy1lgiR7i6WZD7kyd2fdYKMxd/b3NM42pBhy5m/Of9AJz5yRNNtRUYMzkbs5ZmYcLQv4hxLk0EHEj1wcmjOvSJulDrff4+7Gf8/YWfsWZJR5w8poOrmwU+huvi8U/W+2PHx7ZF81vvZuKn49o/X4oayJ1+9sekSZMwYMAA+Pv748KFC5g1axacnZ0xePBg6HQ6xMTEID4+Hl5eXtBqtRg/fjzCw8Pxl79U/W726dMHgYGBeOGFF7BgwQKYTCbMmDED48aNE1tHxowZgxUrVmDKlCl46aWXsGfPHmzZsgXbt28X84iPj0d0dDQefPBBPPzww1i6dClKSkowYsSI2/9h3ESDFhX79+/HwoULkZmZifz8fGzdulWspEg+lkoVLv+qrrH/51PuNsVD/jlXrFvcBlMWnYKTswDr78VH0twAAIDOq6LWosKv/TX0H1KAMU8G45fcqn7DgvM1wogkkfFNS2R807LWY9eKm+D1saE2+96Z3xnLNnyH+/TXcclU9fu5Iak9gKqWiNo09azAC//IweyJIfj+uxbi/rOnPMX/l153Qen1P/6kBtx/Ff7tS7DizS6398ZIere51oTN+XY4f/48Bg8ejN9++w333XcfevbsiW+//Rb33XcfAGDJkiVwcnLCwIEDUVZWBqPRiHfeeUc839nZGdu2bcPYsWMRHh4ODw8PREdHY86cOWJMQEAAtm/fjri4OCxbtgytW7fG6tWrYTQaxZjnn38ely5dQkJCAkwmE0JCQrBz584agzel0KBFRUlJCYKDg/HSSy/ZLPhB8mrVthQffpOB8jInnDziibX/aoNL+bX3CXp4VuJasbNYUNRH2OOXYcrTIOzxyxgw7ARUKuDIQR0++GcbFBc1keptEN0WD89KWK1A8dX6/y52/8tvcHICWniXIemTg3D3qMSJ75vh/cX349cC11rPMf79F5w/647jR5pLlTo1Mps2bbrlcVdXV6xcuRIrV668aYy/v3+N7o0/e+yxx3DkyJFbxsTGxsrS3fFnDVpU9OvXz2Z0bF3Kysps5gObzWY50rqnZWc1xaKpHXD+jCu8vCswdHweFm46hrFPhuB6ibNNrLZ5BQaPO4//brKvmtX7lcG7VRl69fsN/5rcAU7OAl5+/SxeX/ETpr/wgJRvh8guTdQWjHjlFPbt1ON6Sf3//OlbX4fKScDzL+Xi3YWdUFLsghfHncabqzIx7rlwVFbajnlvorYgol8+PlobIPVbIAfw0efya1SzP+bNm2czN9jPz6+hU2p0MvY3x4H/tsDZbA8c/roZEmK6oKnWgl5P/moT5960ErPfP4lzOe74cLl9gyudnASoNQL+NakDjmdo8cMhHZZMb4+QcDNaBVyv+wJEMnB2sWL6gqNQqYAVb9nXJaFSAU2aCEha0BmH01si+4dm+Of0IBjaXEO3hwprxD/y+EW4uVuw+wtfqdInKUi0TgXdXKMqKqZPn46ioiJxy8vLa+iUGr2Sqy74JdcVBv9ScZ+bhwVz15zA9RJnzB3bCZZK+35NCi+pUVmhwi9n/5iHnZdT9X9vw81XniOSi7OLFdP/eRTevqV4fWwPu1opAIhjkM6d8RD3mS+rYb6ixn360hrxxqgL+O7rlrhSWL+phkT3ikZVVGg0mhrzg8kxru4W+LYpReHFqj+a7k0r8Wbyj6iscMLslzuhotz+X5EfMz3h0kSAb5s//ti2Cqj6/8Vf+EeW7qzqgsLQ5hpeGxOKq0U1BynX5cesZgCA1m1LxH1NtRXQNivHxXzbRYx8DNfR7aFC7Epp5VDeJL2GePaH0nBKqcKMnHYWh/Y0R8EvGrTwrsCwCXmwWlXYt63l7wXFCWhcrVj4ake4N7XAvakFAFBU2ARWa9VgTV//63Bzt6J5ywpoXK1o16XqD+25HDdUVjjhyDc6nDrmgbj5OXj3jQCoVALGzc7F4QM6m9YLIim4ulXC4PdHt5pPq+tod/9VXDW7oPBXDV5beBQdOpuROKE7nJ0ENG9R1Vp2taiJOBbiPv11eGorcZ/vdTg5CWh3/1UAwIU8N5Red8Ev5zyQ/tV9eHlyNt5+IxDXil0wfPwpnD/rgaMZtgMx+0T9gsJfNTedkUIN6A7P/lAiFhUK01JfjqlLTkHbvBJFhU1wPMMTcc8GoaiwCYLCitA5pBgAsGaP7Uji6Ee74+IvVaPcJ751Bt3C/hgku/KLozYxgqBC4ujOGJuQiwUbj6H0ujMy9jXD+/P879C7JCXpGGjGP1dniq9HT/oJAJD6uS82JLVH+GOXAAArN39rc97UkaH4IdMLADBs7Gn87al88diK32NvjPnXzK4YPSkbicuPQLCq8ENmc8wc18Ome1ClEhA54AJ2f24Qi3AiJVEJQsOVXsXFxcjJyQEAdO/eHYsXL0ZERAS8vLzQpk2bOs83m83Q6XR43H0QXFT2N2kSNQYqz6YNnQKRbCqt5Ui7uBpFRUWydWlXf1aE95sDlya1TwGuj8qKUqT/N0HWXBu7Bm2pyMjIQETEH8vhxsfHAwCio6ORnJzcQFkREdE9qYGX6VaCBi0qHnvsMTRgQwkRERFJiGMqiIhIEbj4lfxYVBARkTJYharNkfPpllhUEBGRMnBMhewa1eJXREREdPdiSwURESmCCg6OqZAsk3sXiwoiIlIGrqgpO3Z/EBERkSTYUkFERIrAKaXyY1FBRETKwNkfsmP3BxEREUmCLRVERKQIKkGAyoHBlo6cqxQsKoiISBmsv2+OnE+3xO4PIiIikgRbKoiISBHY/SE/FhVERKQMnP0hOxYVRESkDFxRU3YcU0FERESSYEsFEREpAlfUlB+LCiIiUgZ2f8iO3R9EREQkCbZUEBGRIqisVZsj59OtsaggIiJlYPeH7Nj9QURERJJgSwURESkDF7+SHYsKIiJSBC7TLT92fxAREZEk2FJBRETKwIGasmNRQUREyiAAcGRaKGuKOrGoICIiReCYCvlxTAURERFJgi0VRESkDAIcHFMhWSb3LLZUEBGRMlQP1HRks8O8efPw0EMPwdPTE97e3oiKikJ2drZNzGOPPQaVSmWzjRkzxibm3Llz6N+/P9zd3eHt7Y3JkyejsrLSJmbv3r3o0aMHNBoNOnTogOTk5Br5rFy5Em3btoWrqyvCwsLw3Xff2fV+6oNFBRERkQz27duHcePG4dtvv0VqaioqKirQp08flJSU2MSNGjUK+fn54rZgwQLxmMViQf/+/VFeXo6DBw9i3bp1SE5ORkJCghiTm5uL/v37IyIiAllZWZg4cSJGjhyJL7/8UozZvHkz4uPjMWvWLBw+fBjBwcEwGo24ePGipO9ZJQiNd+SJ2WyGTqfD4+6D4KJSN3Q6RLJQeTZt6BSIZFNpLUfaxdUoKiqCVquV5R7iZ0XQVLg4a277OpWWMuz54Z/Iy8uzyVWj0UCjqfu6ly5dgre3N/bt24fevXsDqGqpCAkJwdKlS2s957///S/+3//7f7hw4QJ8fHwAAElJSZg6dSouXboEtVqNqVOnYvv27Th27Jh43qBBg3DlyhXs3LkTABAWFoaHHnoIK1asAABYrVb4+flh/PjxmDZt2m39PGrDlgoiIlKE6tkfjmwA4OfnB51OJ27z5s2r1/2LiooAAF5eXjb7N2zYgJYtW6Jr166YPn06rl27Jh5LT09HUFCQWFAAgNFohNlsxvHjx8WYyMhIm2sajUakp6cDAMrLy5GZmWkT4+TkhMjISDFGKhyoSUREZIfaWirqYrVaMXHiRPz1r39F165dxf1DhgyBv78/DAYDjh49iqlTpyI7OxuffvopAMBkMtkUFADE1yaT6ZYxZrMZ169fx+XLl2GxWGqNOXnypB3vvG4sKoiISBkkWlFTq9Xa3VUzbtw4HDt2DAcOHLDZP3r0aPH/QUFB8PX1xRNPPIHTp0+jffv2t59rA2H3BxERKcMdnv1RLTY2Ftu2bcNXX32F1q1b3zI2LCwMAJCTkwMA0Ov1KCgosImpfq3X628Zo9Vq4ebmhpYtW8LZ2bnWmOprSIVFBRERkQwEQUBsbCy2bt2KPXv2ICAgoM5zsrKyAAC+vr4AgPDwcPzwww82szRSU1Oh1WoRGBgoxqSlpdlcJzU1FeHh4QAAtVqN0NBQmxir1Yq0tDQxRirs/iAiImW4ww8UGzduHDZu3IjPPvsMnp6e4hgInU4HNzc3nD59Ghs3bsSTTz6JFi1a4OjRo4iLi0Pv3r3RrVs3AECfPn0QGBiIF154AQsWLIDJZMKMGTMwbtw4cSzHmDFjsGLFCkyZMgUvvfQS9uzZgy1btmD79u1iLvHx8YiOjsaDDz6Ihx9+GEuXLkVJSQlGjBhx+z+PWrCoICIiZbACUDl4vh1WrVoFoGra6I3Wrl2L4cOHQ61WY/fu3eIHvJ+fHwYOHIgZM2aIsc7Ozti2bRvGjh2L8PBweHh4IDo6GnPmzBFjAgICsH37dsTFxWHZsmVo3bo1Vq9eDaPRKMY8//zzuHTpEhISEmAymRASEoKdO3fWGLzpKK5TQXSX4zoVdC+7k+tURN4f7/A6Fbt/Wixrro0dx1QQERGRJNj9QUREynCHx1QoEYsKIiJSBqsAqBwoDKwsKurC7g8iIiKSBFsqiIhIGdj9ITsWFUREpBAOFhVgUVEXdn8QERGRJNhSQUREysDuD9mxqCAiImWwCnCoC4OzP+rE7g8iIiKSBFsqiIhIGQRr1ebI+XRLLCqIiEgZOKZCdiwqiIhIGTimQnYcU0FERESSYEsFEREpA7s/ZMeigoiIlEGAg0WFZJncs9j9QURERJJgSwURESkDuz9kx6KCiIiUwWoF4MBaE1auU1EXdn8QERGRJNhSQUREysDuD9mxqCAiImVgUSE7dn8QERGRJNhSQUREysBlumXHooKIiBRBEKwQHHjSqCPnKgWLCiIiUgZBcKy1gWMq6sQxFURERCQJtlQQEZEyCA6OqWBLRZ1YVBARkTJYrYDKgXERHFNRJ3Z/EBERkSTYUkFERMrA7g/ZsaggIiJFEKxWCA50f3BKad3Y/UFERESSYEsFEREpA7s/ZMeigoiIlMEqACoWFXJi9wcRERFJgi0VRESkDIIAwJF1KthSURcWFUREpAiCVYDgQPeHwKKiTiwqiIhIGQQrHGup4JTSunBMBREREUmCLRVERKQI7P6QH4sKIiJSBnZ/yK5RFxXVVWOlUNHAmRDJR2Utb+gUiGRT+fvv951oBahEhUNrX1WCnzV1adRFxdWrVwEA+69/0sCZEMnoWkMnQCS/q1evQqfTyXJttVoNvV6PA6YdDl9Lr9dDrVZLkNW9SSU04k4iq9WKCxcuwNPTEyqVqqHTUQSz2Qw/Pz/k5eVBq9U2dDpEkuLv950nCAKuXr0Kg8EAJyf55g6UlpaivNzxVj+1Wg1XV1cJMro3NeqWCicnJ7Ru3bqh01AkrVbLP7p0z+Lv950lVwvFjVxdXVkM3AGcUkpERESSYFFBREREkmBRQXbRaDSYNWsWNBpNQ6dCJDn+fhM5plEP1CQiIqK7B1sqiIiISBIsKoiIiEgSLCqIiIhIEiwqiIiISBIsKqjeVq5cibZt28LV1RVhYWH47rvvGjolIkns378fAwYMgMFggEqlQkpKSkOnRNQosaigetm8eTPi4+Mxa9YsHD58GMHBwTAajbh48WJDp0bksJKSEgQHB2PlypUNnQpRo8YppVQvYWFheOihh7BixQoAVc9d8fPzw/jx4zFt2rQGzo5IOiqVClu3bkVUVFRDp0LU6LClgupUXl6OzMxMREZGivucnJwQGRmJ9PT0BsyMiIjuJiwqqE6//vorLBYLfHx8bPb7+PjAZDI1UFZERHS3YVFBREREkmBRQXVq2bIlnJ2dUVBQYLO/oKAAer2+gbIiIqK7DYsKqpNarUZoaCjS0tLEfVarFWlpaQgPD2/AzIiI6G7i0tAJUOMQHx+P6OhoPPjgg3j44YexdOlSlJSUYMSIEQ2dGpHDiouLkZOTI77Ozc1FVlYWvLy80KZNmwbMjKhx4ZRSqrcVK1Zg4cKFMJlMCAkJwfLlyxEWFtbQaRE5bO/evYiIiKixPzo6GsnJyXc+IaJGikUFERERSYJjKoiIiEgSLCqIiIhIEiwqiIiISBIsKoiIiEgSLCqIiIhIEiwqiIiISBIsKoiIiEgSLCqIiIhIEiwqiBw0fPhwREVFia8fe+wxTJw48Y7nsXfvXqhUKly5cuWmMSqVCikpKfW+ZmJiIkJCQhzK6+zZs1CpVMjKynLoOkR092NRQfek4cOHQ6VSQaVSQa1Wo0OHDpgzZw4qKytlv/enn36KuXPn1iu2PoUAEVFjwQeK0T2rb9++WLt2LcrKyrBjxw6MGzcOTZo0wfTp02vElpeXQ61WS3JfLy8vSa5DRNTYsKWC7lkajQZ6vR7+/v4YO3YsIiMj8fnnnwP4o8vizTffhMFgQKdOnQAAeXl5eO6559CsWTN4eXnh6aefxtmzZ8VrWiwWxMfHo1mzZmjRogWmTJmCPz8+58/dH2VlZZg6dSr8/Pyg0WjQoUMHfPDBBzh79qz4EKvmzZtDpVJh+PDhAKoeLT9v3jwEBATAzc0NwcHB+Pjjj23us2PHDtx///1wc3NDRESETZ71NXXqVNx///1wd3dHu3btMHPmTFRUVNSIe/fdd+Hn5wd3d3c899xzKCoqsjm+evVqdOnSBa6urujcuTPeeecdu3MhosaPRQUphpubG8rLy8XXaWlpyM7ORmpqKrZt24aKigoYjUZ4enri66+/xjfffIOmTZuib9++4nmLFi1CcnIy1qxZgwMHDqCwsBBbt2695X1ffPFF/Oc//8Hy5ctx4sQJvPvuu2jatCn8/PzwySefAACys7ORn5+PZcuWAQDmzZuH9evXIykpCcePH0dcXByGDRuGffv2Aagqfp555hkMGDAAWVlZGDlyJKZNm2b3z8TT0xPJycn48ccfsWzZMrz//vtYsmSJTUxOTg62bNmCL774Ajt37sSRI0fwj3/8Qzy+YcMGJCQk4M0338SJEyfw1ltvYebMmVi3bp3d+RBRIycQ3YOio6OFp59+WhAEQbBarUJqaqqg0WiESZMmicd9fHyEsrIy8Zx///vfQqdOnQSr1SruKysrE9zc3IQvv/xSEARB8PX1FRYsWCAer6ioEFq3bi3eSxAE4dFHHxUmTJggCIIgZGdnCwCE1NTUWvP86quvBADC5cuXxX2lpaWCu7u7cPDgQZvYmJgYYfDgwYIgCML06dOFwMBAm+NTp06tca0/AyBs3br1pscXLlwohIaGiq9nzZolODs7C+fPnxf3/fe//xWcnJyE/Px8QRAEoX379sLGjRttrjN37lwhPDxcEARByM3NFQAIR44cuel9iejewDEVdM/atm0bmjZtioqKClitVgwZMgSJiYni8aCgIJtxFN9//z1ycnLg6elpc53S0lKcPn0aRUVFyM/PR1hYmHjMxcUFDz74YI0ukGpZWVlwdnbGo48+Wu+8c3JycO3aNfztb3+z2V9eXo7u3bsDAE6cOGGTBwCEh4fX+x7VNm/ejOXLl+P06dMoLi5GZWUltFqtTUybNm3QqlUrm/tYrVZkZ2fD09MTp0+fRkxMDEaNGiXGVFZWQqfT2Z0PETVuLCronhUREYFVq1ZBrVbDYDDAxcX2193Dw8PmdXFxMUJDQ7Fhw4Ya17rvvvtuKwc3Nze7zykuLgYAbN++3ebDHKgaJyKV9PR0DB06FLNnz4bRaIROp8OmTZuwaNEiu3N9//33axQ5zs7OkuVKRI0Diwq6Z3l4eKBDhw71ju/Rowc2b94Mb2/vGt/Wq/n6+uLQoUPo3bs3gKpv5JmZmejRo0et8UFBQbBardi3bx8iIyNrHK9uKbFYLOK+wMBAaDQanDt37qYtHF26dBEHnVb79ttv636TNzh48CD8/f3x+uuvi/t+/vnnGnHnzp3DhQsXYDAYxPs4OTmhU6dO8PHxgcFgwJkzZzB06FC77k9E9x4O1CT63dChQ9GyZUs8/fTT+Prrr5Gbm4u9e/filVdewfnz5wEAEyZMwPz585GSkoKTJ0/iH//4xy3XmGjbti2io6Px0ksvISUlRbzmli1bAAD+/v5QqVTYtm0bLl26hOLiYnh6emLSpEmIi4vDunXrcPr0aRw+fBhvv/22OPhxzJgxOHXqFCZPnozs7Gxs3LgRycnJdr3fjh074ty5c9i0aRNOnz6N5cuX1zro1NXVFdHR0fj+++/x9ddf45VXXsFzzz0HvV4PAJg9ezbmzZuH5cuX46effsIPP/yAtWvXYvHixXblQ0SNH4sKot+5u7tj//79aNOmDZ555hl06dIFMTExKC0tFVsuXn31VbzwwguIjo5GeHg4PD098fe///2W1121ahWeffZZ/OMf/0Dnzp0xatQolJSUAABatWqF2bNnY9q0afDx8UFsbCwAYO7cuZg5cybmzZuHLl26oG/fvti+fTsCAgIAVI1z+OSTT5CSkoLg4GAkJSXhrbfesuv9PvXUU4iLi0NsbCxCQkJw8OBBzJw5s0Zchw4d8Mwzz+DJJ59Enz590K1bN5spoyNHjsTq1auxdu1aBAUF4dFHH0VycrKYKxEph0q42QgzIiIiIjuwpYKIiIgkwaKCiIiIJMGigoiIiCTBooKIiIgkwaKCiIiIJMGigoiIiCTBooKIiIgkwaKCiIiIJMGigoiIiCTBooKIiIgkwaKCiIiIJPH/AYk9fQG6ale+AAAAAElFTkSuQmCC" - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "execution_count": 11 + ] }, { "cell_type": "markdown", @@ -528,19 +425,21 @@ }, { "cell_type": "code", + "execution_count": null, "metadata": { - "tags": [], "ExecuteTime": { "end_time": "2024-08-19T15:45:30.679688Z", "start_time": "2024-08-19T15:45:30.669086Z" - } + }, + "tags": [] }, + "outputs": [], "source": [ "sally_transaction_details = [\n", " [0.3111400080477545,\n", - " 1.9459399775518593, \n", - " 1.0, \n", - " 0.0, \n", + " 1.9459399775518593,\n", + " 1.0,\n", + " 0.0,\n", " 0.0]\n", " ]\n", "\n", @@ -550,50 +449,20 @@ "print(np.squeeze(prediction) > threshold)\n", "\n", "print(\"How likely was Sally's transaction to be fraudulent? \")\n", - "print(\"{:.5f}\".format(np.squeeze(prediction)) + \"%\")" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Is Sally's transaction predicted to be fraudulent? (true = YES, false = NO) \n", - "False\n", - "How likely was Sally's transaction to be fraudulent? \n", - "0.00002%\n" - ] - } - ], - "execution_count": 12 - }, - { - "cell_type": "code", - "metadata": { - "ExecuteTime": { - "end_time": "2024-08-19T15:45:30.722273Z", - "start_time": "2024-08-19T15:45:30.719926Z" - } - }, - "source": [], - "outputs": [], - "execution_count": null + "print(\"{:.5f}\".format(100 * np.squeeze(prediction)) + \"%\")" + ] }, { "cell_type": "code", - "metadata": { - "ExecuteTime": { - "end_time": "2024-08-19T15:45:30.756156Z", - "start_time": "2024-08-19T15:45:30.750131Z" - } - }, - "source": [], + "execution_count": null, + "metadata": {}, "outputs": [], - "execution_count": null + "source": [] } ], "metadata": { "kernelspec": { - "display_name": "Python 3.9", + "display_name": "Python 3.11", "language": "python", "name": "python3" }, @@ -607,7 +476,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.18" + "version": "3.11.7" }, "vscode": { "interpreter": {