From 6cdeb60ac4ee2c7dc8ad41ca536c76a5773a67d3 Mon Sep 17 00:00:00 2001 From: Donovan Date: Thu, 12 Dec 2024 11:11:17 -0600 Subject: [PATCH] implement shuffle benchmark --- .gitignore | 3 +- notebooks/evilkode.ipynb | 96 ++++++++++++++++++---------------------- src/benchmark.py | 95 +++++++++++++++++++++++++++++++++++---- src/evilkode.py | 1 - tests/test_benchmark.py | 15 +++++++ 5 files changed, 147 insertions(+), 63 deletions(-) create mode 100644 tests/test_benchmark.py diff --git a/.gitignore b/.gitignore index 1f1025f..7d76ca4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .idea -.DS_Store \ No newline at end of file +.DS_Store +output diff --git a/notebooks/evilkode.ipynb b/notebooks/evilkode.ipynb index 1cd7e95..3ecf5da 100644 --- a/notebooks/evilkode.ipynb +++ b/notebooks/evilkode.ipynb @@ -6,64 +6,69 @@ "metadata": { "collapsed": true, "ExecuteTime": { - "end_time": "2024-12-10T22:50:21.565075Z", - "start_time": "2024-12-10T22:50:21.562189Z" + "end_time": "2024-12-12T17:09:58.749289Z", + "start_time": "2024-12-12T17:09:58.747461Z" } }, "source": [ - "from src.benchmark import split_shuffle_benchmark, full_shuffle_benchmark\n", + "from src.benchmark import shuffle_benchmark, ShuffleTypes\n", "import matplotlib.pyplot as plt" ], "outputs": [], - "execution_count": 3 + "execution_count": 6 }, { "metadata": { "ExecuteTime": { - "end_time": "2024-12-10T23:03:49.651397Z", - "start_time": "2024-12-10T23:03:48.504246Z" + "end_time": "2024-12-12T17:09:58.765574Z", + "start_time": "2024-12-12T17:09:58.758204Z" } }, "cell_type": "code", "source": [ - "number_of_keys=6\n", - "properties_per_key=9\n", - "passcode_len=4\n", - "max_tries_before_lockout=5\n", - "run_count=1000\n", + "multiple = 3\n", + "number_of_keys=6 * multiple\n", + "properties_per_key=12 * multiple\n", + "passcode_len=1\n", + "max_tries_before_lockout= 5\n", + "complexity=1\n", + "disparity=1\n", + "run_count=10000\n", "\n", - "bench_split = split_shuffle_benchmark(\n", + "bench_split = shuffle_benchmark(\n", " number_of_keys=number_of_keys,\n", " properties_per_key=properties_per_key,\n", " passcode_len=passcode_len,\n", " max_tries_before_lockout=max_tries_before_lockout,\n", - " run_count=run_count\n", - ")\n", - "bench_full = full_shuffle_benchmark(\n", - " number_of_keys=number_of_keys,\n", - " properties_per_key=properties_per_key,\n", - " passcode_len=passcode_len,\n", - " max_tries_before_lockout=max_tries_before_lockout,\n", - " run_count=run_count\n", + " run_count=run_count,\n", + " complexity=complexity,\n", + " disparity=disparity,\n", + " shuffle_type=ShuffleTypes.SPLIT_SHUFFLE\n", ")" ], "id": "c86c6ed5014dac44", - "outputs": [], - "execution_count": 32 + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "file exists ../output\n" + ] + } + ], + "execution_count": 7 }, { "metadata": { "ExecuteTime": { - "end_time": "2024-12-10T23:03:50.331563Z", - "start_time": "2024-12-10T23:03:50.328850Z" + "end_time": "2024-12-12T17:09:58.835376Z", + "start_time": "2024-12-12T17:09:58.833451Z" } }, "cell_type": "code", "source": [ "print(f\"Bench Split Mean {bench_split.mean}\\n\"\n", - " f\"Bench Split Var: {bench_split.variance}\\n\"\n", - " f\"Bench Full Mean {bench_full.mean}\\n\"\n", - " f\"Bench Full Var: {bench_full.variance}\")" + " f\"Bench Split Var: {bench_split.variance}\")" ], "id": "6de455d5097d9c3d", "outputs": [ @@ -71,20 +76,18 @@ "name": "stdout", "output_type": "stream", "text": [ - "Bench Partial Mean 6.529\n", - "Bench Partial Var: 1.4486076076076075\n", - "Bench Full Mean 3.979\n", - "Bench Full Var: 0.1427017017017017\n" + "Bench Split Mean 5.571\n", + "Bench Split Var: 0.5252115211521152\n" ] } ], - "execution_count": 33 + "execution_count": 8 }, { "metadata": { "ExecuteTime": { - "end_time": "2024-12-10T23:04:13.237362Z", - "start_time": "2024-12-10T23:04:13.234728Z" + "end_time": "2024-12-12T17:09:58.908054Z", + "start_time": "2024-12-12T17:09:58.905569Z" } }, "cell_type": "code", @@ -110,20 +113,17 @@ ], "id": "99ddd0fbd421b058", "outputs": [], - "execution_count": 34 + "execution_count": 9 }, { "metadata": { "ExecuteTime": { - "end_time": "2024-12-10T23:04:15.054905Z", - "start_time": "2024-12-10T23:04:14.896389Z" + "end_time": "2024-12-12T17:09:58.989830Z", + "start_time": "2024-12-12T17:09:58.918011Z" } }, "cell_type": "code", - "source": [ - "bench_histogram(bench_full.runs, \"bench full\")\n", - "bench_histogram(bench_split.runs, \"bench split\")" - ], + "source": "bench_histogram(bench_split.runs, \"bench split\")", "id": "9cbf9282eba285e6", "outputs": [ { @@ -131,23 +131,13 @@ "text/plain": [ "
" ], - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjsAAAHHCAYAAABZbpmkAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/GU6VOAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAv/ElEQVR4nO3df3jN9f/H8cfZb2Mzpv2QmaUJWQmlhVJ8TCjiCkVNrfRjRFK4PiJJiyKRqD4ZLqR8i36i+Vmx/Bgh+TA/p9iQHzPazPb+/uFyro75tbOzne31ud+u61xX5/V+vd/v57PXZ58e1/v9PufYLMuyBAAAYCgPdxcAAABQmgg7AADAaIQdAABgNMIOAAAwGmEHAAAYjbADAACMRtgBAABGI+wAAACjEXYAAIDRCDsASuy1116TzWbT0aNH3V3KJe3bt082m03vvPOO08dIT09Xu3btVLVqVdlsNi1cuLBY+9epU0d9+vSxv1+5cqVsNptWrlzpdE0Aro2XuwsAgIogPj5ee/fu1ZgxYxQUFKRmzZq5uyQA14iwAwBX8ffffys1NVX//ve/1a9fP3eXA6CYuI0FAFdx5MgRSVJQUJB7CwHgFMIOAJc5evSounfvrsDAQAUHB2vAgAHKzc0tMm/27Nlq2rSpKlWqpOrVq6tnz546cOCAw5zWrVurUaNG+v3333XvvffK399f119/vcaNG1fkeLm5uXrttddUr149+fn5KTw8XF27dtXu3buLzP3oo49Ut25d+fr66vbbb9f69euv2NNrr72myMhISdLLL78sm82mOnXqSJL69Olj/+eL97HZbFc8LoCyw20sAC7TvXt31alTR0lJSfrll180adIkHT9+XLNmzbLPGTNmjF599VV1795dTz31lI4cOaLJkyfr7rvv1qZNmxyunhw/flzt27dX165d1b17d/3f//2fhgwZopiYGN1///2SpIKCAnXq1EnLli1Tz549NWDAAJ06dUopKSn67bffVLduXfvx5s6dq1OnTumZZ56RzWbTuHHj1LVrV+3Zs0fe3t6X7Klr164KCgrSiy++qEceeUQdOnRQlSpVSudfIIDSYQFACY0cOdKSZD344IMO488//7wlydq8ebNlWZa1b98+y9PT0xozZozDvK1bt1peXl4O4/fcc48lyZo1a5Z9LC8vzwoLC7O6detmH5s+fbolyZow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TtTw4cPVuXNnSdKsWbMUGhqqhQsXqmfPntq+fbsWL16s9evXq1mzZpKkyZMnq0OHDnrnnXdUs2bNsm0KAACUK269svP111+rWbNmevjhhxUSEqLbbrtNH3/8sX373r17lZmZqbZt29rHqlatqubNmys1NVWSlJqaqqCgIHvQkaS2bdvKw8NDa9euveR58/LylJ2d7fACAABmcmvY2bNnj6ZOnaro6GgtWbJEzz33nF544QXNnDlTkpSZmSlJCg0NddgvNDTUvi0zM1MhISEO2728vFS9enX7nIslJSWpatWq9ldERISrWwMAAOWEW8NOYWGhmjRpojfffFO33Xab+vbtq6efflrTpk0r1fMOGzZMJ0+etL8OHDhQqucDAADu49awEx4eroYNGzqMNWjQQBkZGZKksLAwSVJWVpbDnKysLPu2sLAwHT582GH7uXPndOzYMfuci/n6+iowMNDhBQAAzOTWsNOiRQvt2LHDYWznzp2KjIyUdP5h5bCwMC1btsy+PTs7W2vXrlVsbKwkKTY2VidOnFBaWpp9zvLly1VYWKjmzZuXQRcAAKA8c+unsV588UXdddddevPNN9W9e3etW7dOH330kT766CNJks1m08CBA/XGG28oOjpaUVFRevXVV1WzZk116dJF0vkrQe3bt7ff/srPz1e/fv3Us2dPPokFAADcG3Zuv/12LViwQMOGDdPrr7+uqKgoTZw4Ub169bLPeeWVV3T69Gn17dtXJ06cUMuWLbV48WL5+fnZ58yZM0f9+vVTmzZt5OHhoW7dumnSpEnuaAkAAJQzbg07ktSpUyd16tTpstttNptef/11vf7665edU716dc2dO7c0ygMAABWc238uAgAAoDQRdgAAgNEIOwAAwGiEHQAAYDTCDgAAMBphBwAAGI2wAwAAjEbYAQAARiPsAAAAoxF2AACA0Qg7AADAaIQdAABgNMIOAAAwGmEHAAAYjbADAACMRtgBAABGI+wAAACjEXYAAIDRCDsAAMBohB0AAGA0wg4AADCaU2Fnz549rq4DAACgVDgVdm688Ubde++9mj17tnJzc11dEwAAgMs4FXY2btyoW265RYMGDVJYWJieeeYZrVu3ztW1AQAAlJhTYadx48Z67733dPDgQU2fPl2HDh1Sy5Yt1ahRI02YMEFHjhxxdZ0AAABOKdEDyl5eXuratavm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uP1VtPUbMmSI1bJly2Lt88orr1g333yzw1iPHj2suLg4V5bmMs70uGLFCkuSdfz48dIpqhQNGDDAqlu3rlVYWHjJ7e76G+TKjgsUFBRo3rx5On36tGJjYy85JzU1VW3btnUYi4uLU2pqalmUWGLX0qMk5eTkKDIyUhEREVe9ClReJCYmqmPHjkXW51Iq4joWpz+p4q1henq6atasqRtuuEG9evVSRkbGZedWxPUrTn9SxVq/r7/+Ws2aNdPDDz+skJAQ3Xbbbfr444+vuE9FW0NnerygcePGCg8P17/+9S+tXr26lCstubNnz2r27Nl68sknL/uj2u5aP8JOCWzdulVVqlSRr6+vnn32WS1YsEANGza85NzMzMwiP18RGhpaLu/B/lNxerzppps0ffp0ffXVV5o9e7YKCwt111136Y8//ijjqq/dvHnztHHjRiUlJV3T/Iq2jsXtr6KtYfPmzTVjxgwtXrxYU6dO1d69e9WqVSudOnXqkvMr2voVt7+Ktn579uzR1KlTFR0drSVLlui5557TCy+8oJkzZ152n8utYXZ2tv7+++/SLrnYnOkxPDxc06ZN0xdffKEvvvhCERERat26tTZu3FiGlRffwoULdeLECfXp0+eyc9z2N1iq140Ml5eXZ6Wnp1sbNmywhg4datWoUcPatm3bJed6e3tbc+fOdRibMmWKFRISUhalOq04PV7s7NmzVt26da3hw4eXcpXOycjIsEJCQqzNmzfbx652m6ciraMz/V2svK/hxY4fP24FBgZe9lZrRVq/S7lafxcr7+vn7e1txcbGOoz179/fuvPOOy+7T3R0tPXmm286jH333XeWJOvMmTOlUmdJONPjpdx9991W7969XVmay7Vr187q1KnTFee462+QKzsl4OPjoxtvvFFNmzZVUlKSbr31Vr333nuXnBsWFqasrCyHsaysLIWFhZVFqU4rTo8X8/b21m233aZdu3aVcpXOSUtL0+HDh9WkSRN5eXnJy8tLq1at0qRJk+Tl5aWCgoIi+1SkdXSmv4uV9zW8WFBQkOrVq3fZeivS+l3K1fq7WHlfv/Dw8CJXihs0aHDFW3WXW8PAwEBVqlSpVOosCWd6vJQ77rij3K6jJO3fv19Lly7VU089dcV57vobJOy4UGFhofLy8i65LTY2VsuWLXMYS0lJueLzL+XRlXq8WEFBgbZu3arw8PBSrso5bdq00datW/Xrr7/aX82aNVOvXr3066+/ytPTs8g+FWkdnenvYuV9DS+Wk5Oj3bt3X7beirR+l3K1/i5W3tevRYsW2rFjh8PYzp07FRkZedl9KtoaOtPjpfz666/ldh0lKTk5WSEhIerYseMV57lt/Ur1upHBhg4daq1atcrau3evtWXLFmvo0KGWzWazfvjhB8uyLOuxxx6zhg4dap+/evVqy8vLy3rnnXes7du3WyNHjrS8vb2trVu3uquFqypuj6NGjbKWLFli7d6920pLS7N69uxp+fn5XfNtr/Lg4ts8JqzjP12tv4q2hi+99JK1cuVKa+/evdbq1auttm3bWjVq1LAOHz5sWVbFX7/i9lfR1m/dunWWl5eXNWbMGCs9Pd2aM2eO5e/vb82ePds+Z+jQodZjjz1mf79nzx7L39/fevnll63t27dbU6ZMsTw9Pa3Fixe7o4WrcqbHd99911q4cKGVnp5ubd261RowYIDl4eFhLV261B0tXFVBQYFVu3Zta8iQIUW2lZe/QcKOk5588kkrMjLS8vHxsa677jqrTZs29hBgWef/oxIfH++wz+eff27Vq1fP8vHxsW6++Wbru+++K+Oqi6e4PQ4cONCqXbu25ePjY4WGhlodOnSwNm7c6IbKnXdxGDBhHf/pav1VtDXs0aOHFR4ebvn4+FjXX3+91aNHD2vXrl327RV9/YrbX0VbP8uyrG+++cZq1KiR5evra9WvX9/66KOPHLbHx8db99xzj8PYihUrrMaNG1s+Pj7WDTfcYCUnJ5ddwU4obo9jx4616tata/n5+VnVq1e3WrdubS1fvryMq752S5YssSRZO3bsKLKtvPwN2izLskr32hEAAID78MwOAAAwGmEHAAAYjbADAACMRtgBAABGI+wAAACjEXYAAIDRCDsAAMBohB0AxmrdurUGDhzo7jIAuBlhB0C59MADD6h9+/aX3PbTTz/JZrNpy5YtZVwVgIqIsAOgXEpISFBKSor++OOPItuSk5PVrFkz3XLLLW6oDEBFQ9gBUC516tRJ1113nWbMmOEwnpOTo/nz56tLly565JFHdP3118vf318xMTH69NNPr3hMm82mhQsXOowFBQU5nOPAgQPq3r27goKCVL16dXXu3Fn79u1zTVMA3IKwA6Bc8vLy0uOPP64ZM2bonz/hN3/+fBUUFKh3795q2rSpvvvuO/3222/q27evHnvsMa1bt87pc+bn5ysuLk4BAQH66aeftHr1alWpUkXt27fX2bNnXdEWADcg7AAot5588knt3r1bq1atso8lJyerW7duioyM1ODBg9W4cWPdcMMN6t+/v9q3b6/PP//c6fN99tlnKiws1H/+8x/FxMSoQYMGSk5OVkZGhlauXOmCjgC4A2EHQLlVv3593XXXXZo+fbokadeuXfrpp5+UkJCggoICjR49WjExMapevbqqVKmiJUuWKCMjw+nzbd68Wbt27VJAQICqVKmiKlWqqHr16srNzdXu3btd1RaAMubl7gIA4EoSEhLUv39/TZkyRcnJyapbt67uuecejR07Vu+9954mTpyomJgYVa5cWQMHDrzi7SabzeZwS0w6f+vqgpycHDVt2lRz5swpsu91113nuqYAlCnCDoByrXv37howYIDmzp2rWbNm6bnnnpPNZtPq1avVuXNn9e7dW5JUWFionTt3qmHDhpc91nXXXadDhw7Z36enp+vMmTP2902aNNFnn32mkJAQBQYGll5TAMoUt7EAlGtVqlRRjx49NGzYMB06dEh9+vSRJEVHRyslJUVr1qzR9u3b9cwzzygrK+uKx7rvvvv0/vvva9OmTdqwYYOeffZZeXt727f36tVLNWrUUOfOnfXTTz9p7969WrlypV544YVLfgQeQMVA2AFQ7iUkJOj48eOKi4tTzZo1JUnDhw9XkyZNFBcXp9atWyssLExdunS54nHGjx+viIgItWrVSo8++qgGDx4sf39/+3Z/f3/9+OOPql27trp27aoGDRooISFBubm5XOkBKjCbdfENbAAAAINwZQcAABiNsAMAAIxG2AEAAEYj7AAAAKMRdgAAgNEIOwAAwGiEHQAAYDTCDgAAMBphBwAAGI2wAwAAjEbYAQAARiPsAAAAo/0/tkcEQUJtdb0AAAAASUVORK5CYII=" - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "
" - ], - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjsAAAHHCAYAAABZbpmkAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/GU6VOAAAACXBIWXMAAA9hAAAPYQGoP6dpAAA4TElEQVR4nO3deVxV5d7///eWSRkVDDYkqDnkhFpaRqmZmjhkmt63mbNxZ3nQVLRjdMwcMspO5pDi3X2b5p1kedI6eUpz1nKecgyVVDQBwwnRQIT1+6Of+3t2OG437M3q9Xw81uPButa11/qsJem7a11rbYthGIYAAABMqpyrCwAAAChJhB0AAGBqhB0AAGBqhB0AAGBqhB0AAGBqhB0AAGBqhB0AAGBqhB0AAGBqhB0AAGBqhB0ANuPGjZPFYlF2drarS7muY8eOyWKx6O9//7urS7kra9eulcVi0dq1a+/4s9f+jADcPsIOAJSQWbNmad68ea4uA/jT83R1AQBgVrNmzVLlypU1YMAAu/aWLVvqt99+k7e3t2sKA/5kGNkBACe7fPnyTbeXK1dO5cuXV7ly/BUMlAb+SwNQTHZ2tnr06KHAwECFhIRo2LBhysvLK9bvk08+UZMmTVShQgUFBwerZ8+eOnHihF2fVq1aqUGDBjpw4ICeeOIJ+fr66t5779XkyZOL7S8vL0/jxo1T7dq1Vb58eYWHh6tbt25KS0sr1vfDDz9UjRo15OPjo4ceekjbtm275XnNmzdPFotF69ev14svvqiQkBAFBgaqX79+OnfunF3fr776Sp06dVJERIR8fHxUo0YNTZw4UYWFhdc9vx07dqhly5by9fXVa6+9pmrVqmn//v1at26dLBaLLBaLWrVqJen6c3Y2bNig//zP/1RUVJR8fHwUGRmpESNG6LfffrvleQG4OW5jASimR48eqlatmpKSkrR582ZNnz5d586d0/z58219Jk2apNdff109evTQf/3Xf+nXX3/VjBkz1LJlS+3atUsVK1a09T137pzat2+vbt26qUePHvrHP/6h0aNHKzo6Wh06dJAkFRYW6qmnntKqVavUs2dPDRs2TBcvXtSKFSu0b98+1ahRw7a/lJQUXbx4US+++KIsFosmT56sbt266eeff5aXl9ctz2/IkCGqWLGixo0bp9TUVCUnJ+v48eO2ECL9Hoz8/f2VkJAgf39/rV69WmPHjlVOTo7effddu/2dOXNGHTp0UM+ePdWnTx+FhYWpVatWGjp0qPz9/fW3v/1NkhQWFnbDmhYtWqTLly9r8ODBCgkJ0datWzVjxgydPHlSixYtuvUfGoAbMwDg//fGG28Ykoynn37arv0vf/mLIcn48ccfDcMwjGPHjhkeHh7GpEmT7Prt3bvX8PT0tGt//PHHDUnG/PnzbW35+fmG1Wo1unfvbmv76KOPDEnGlClTitVVVFRkGIZhHD161JBkhISEGGfPnrVt/+qrrwxJxtdff33T85s7d64hyWjSpIlx5coVW/vkyZMNScZXX31la7t8+XKxz7/44ouGr6+vkZeXV+z8Zs+eXax//fr1jccff7xY+5o1awxJxpo1a256vKSkJMNisRjHjx+3tV37MwJw+7iNBaCY+Ph4u/WhQ4dKkr755htJ0uLFi1VUVKQePXooOzvbtlitVtWqVUtr1qyx+7y/v7/69OljW/f29tbDDz+sn3/+2db2xRdfqHLlyrZj/bs/Pmr97LPPqlKlSrb1Fi1aSJLd/m5m0KBBdiNAgwcPlqenp+38JKlChQq2ny9evKjs7Gy1aNFCly9f1k8//WS3Px8fHw0cOPC2jn0j/368S5cuKTs7W48++qgMw9CuXbvuat/Anx23sQAUU6tWLbv1GjVqqFy5cjp27Jgk6fDhwzIMo1i/a/54K6lKlSrFAkulSpW0Z88e23paWpruv/9+eXre+q+lqKioYvuSVGzezY38sW5/f3+Fh4fbzk+S9u/frzFjxmj16tXKycmx63/hwgW79Xvvvfeun6xKT0/X2LFj9c9//rPYefzxeADuDGEHwC39MagUFRXJYrHo22+/lYeHR7H+/v7+duvX6yNJhmE4VI+z9/dH58+f1+OPP67AwEBNmDBBNWrUUPny5bVz506NHj1aRUVFdv3/fVTGEYWFhXryySd19uxZjR49WnXq1JGfn59++eUXDRgwoNjxANwZwg6AYg4fPqzq1avb1o8cOaKioiJVq1ZN0u8jPYZhqHr16qpdu7ZTjlmjRg1t2bJFBQUFtzXJ+G4cPnxYTzzxhG09NzdXGRkZ6tixo6Tfn5Y6c+aMFi9erJYtW9r6HT169I6Oc7tvOt67d68OHTqkjz/+WP369bO1r1ix4o6OB+D6mLMDoJiZM2farc+YMUOSbE9OdevWTR4eHho/fnyx0RTDMHTmzJk7Pmb37t2VnZ2tDz74oNg2Z43YXPPhhx+qoKDAtp6cnKyrV6/azu/ayNG/H/fKlSuaNWvWHR3Hz89P58+fv2W/6x3PMAxNmzbtjo4H4PoY2QFQzNGjR/X000+rffv22rRpkz755BP16tVLjRo1kvT7KMybb76pxMREHTt2TF27dlVAQICOHj2qJUuWaNCgQRo1atQdHbNfv36aP3++EhIStHXrVrVo0UKXLl3SypUr9Ze//EVdunRx2vlduXJFbdq0UY8ePZSamqpZs2apefPmevrppyVJjz76qCpVqqT+/fvr5ZdflsVi0f/93//dcehq0qSJkpOT9eabb6pmzZoKDQ1V69ati/WrU6eOatSooVGjRumXX35RYGCgvvjii9uegwTg5gg7AIr57LPPNHbsWL366qvy9PTUkCFDir1b5tVXX1Xt2rX1/vvva/z48ZKkyMhItWvXzhYa7oSHh4e++eYbTZo0SSkpKfriiy8UEhKi5s2bKzo62inndc0HH3ygBQsWaOzYsSooKNBzzz2n6dOn2247hYSEaOnSpRo5cqTGjBmjSpUqqU+fPmrTpo1iY2Nv+zhjx47V8ePHNXnyZF28eFGPP/74dcOOl5eXvv76a7388stKSkpS+fLl9cwzz2jIkCG2gAnAcRbD2ePDAOCm5s2bp4EDB2rbtm1q2rSpq8sBUEqYswMAAEyNsAMAAEyNsAMAAEyNOTsAAMDUGNkBAACmRtgBAACmxnt29Pv3/Jw6dUoBAQG3/Xp3AADgWoZh6OLFi4qIiFC5cjcevyHsSDp16pQiIyNdXQYAAHDAiRMnVKVKlRtuJ+xICggIkPT7xQoMDHRxNQAA4Hbk5OQoMjLS9u/4jRB29P++mTgwMJCwAwBAGXOrKShMUAYAAKZG2AEAAKZG2AEAAKZG2AEAAKZG2AEAAKZG2AEAAKZG2AEAAKZG2AEAAKZG2AEAAKZG2AEAAKZG2AEAAKZG2AEAAKZG2AEAAKZG2AEAAKbm6eoCAGdIT09Xdna2q8u4I5UrV1ZUVJSrywAA03Np2ElOTlZycrKOHTsmSapfv77Gjh2rDh06SJJatWqldevW2X3mxRdf1OzZs23r6enpGjx4sNasWSN/f3/1799fSUlJ8vQkx/1ZpKen6/46dZX322VXl3JHylfwVepPBwk8AFDCXJoIqlSporffflu1atWSYRj6+OOP1aVLF+3atUv169eXJL3wwguaMGGC7TO+vr62nwsLC9WpUydZrVZt3LhRGRkZ6tevn7y8vPTWW2+V+vnANbKzs5X322WFPDVSXiGRri7nthScOaEzS99TdnY2YQcASphLw07nzp3t1idNmqTk5GRt3rzZFnZ8fX1ltVqv+/nvvvtOBw4c0MqVKxUWFqbGjRtr4sSJGj16tMaNGydvb+8SPwe4D6+QSPlYa7q6DACAm3GbCcqFhYVauHChLl26pJiYGFv7ggULVLlyZTVo0ECJiYm6fPn/3arYtGmToqOjFRYWZmuLjY1VTk6O9u/fX6r1AwAA9+TyiS179+5VTEyM8vLy5O/vryVLlqhevXqSpF69eqlq1aqKiIjQnj17NHr0aKWmpmrx4sWSpMzMTLugI8m2npmZecNj5ufnKz8/37aek5Pj7NMCAABuwuVh5/7779fu3bt14cIF/eMf/1D//v21bt061atXT4MGDbL1i46OVnh4uNq0aaO0tDTVqFHD4WMmJSVp/PjxzigfAAC4OZffxvL29lbNmjXVpEkTJSUlqVGjRpo2bdp1+zZr1kySdOTIEUmS1WpVVlaWXZ9r6zea5yNJiYmJunDhgm05ceKEM04FAAC4IZeHnT8qKiqyu8X073bv3i1JCg8PlyTFxMRo7969On36tK3PihUrFBgYaLsVdj0+Pj4KDAy0WwAAgDm59DZWYmKiOnTooKioKF28eFEpKSlau3atli9frrS0NKWkpKhjx44KCQnRnj17NGLECLVs2VINGzaUJLVr10716tVT3759NXnyZGVmZmrMmDGKj4+Xj4+PK08NAAC4CZeGndOnT6tfv37KyMhQUFCQGjZsqOXLl+vJJ5/UiRMntHLlSk2dOlWXLl1SZGSkunfvrjFjxtg+7+HhoaVLl2rw4MGKiYmRn5+f+vfvb/deHgAA8Ofm0rAzZ86cG26LjIws9vbk66lataq++eYbZ5YFAABMxO3m7AAAADgTYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJiaS8NOcnKyGjZsqMDAQAUGBiomJkbffvutbXteXp7i4+MVEhIif39/de/eXVlZWXb7SE9PV6dOneTr66vQ0FC98sorunr1ammfCgAAcFMuDTtVqlTR22+/rR07dmj79u1q3bq1unTpov3790uSRowYoa+//lqLFi3SunXrdOrUKXXr1s32+cLCQnXq1ElXrlzRxo0b9fHHH2vevHkaO3asq04JAAC4GU9XHrxz585265MmTVJycrI2b96sKlWqaM6cOUpJSVHr1q0lSXPnzlXdunW1efNmPfLII/ruu+904MABrVy5UmFhYWrcuLEmTpyo0aNHa9y4cfL29nbFaQEAADfiNnN2CgsLtXDhQl26dEkxMTHasWOHCgoK1LZtW1ufOnXqKCoqSps2bZIkbdq0SdHR0QoLC7P1iY2NVU5Ojm106Hry8/OVk5NjtwAAAHNyedjZu3ev/P395ePjo5deeklLlixRvXr1lJmZKW9vb1WsWNGuf1hYmDIzMyVJmZmZdkHn2vZr224kKSlJQUFBtiUyMtK5JwUAANyGy8PO/fffr927d2vLli0aPHiw+vfvrwMHDpToMRMTE3XhwgXbcuLEiRI9HgAAcB2XztmRJG9vb9WsWVOS1KRJE23btk3Tpk3Ts88+qytXruj8+fN2oztZWVmyWq2SJKvVqq1bt9rt79rTWtf6XI+Pj498fHycfCYAAMAduXxk54+KioqUn5+vJk2ayMvLS6tWrbJtS01NVXp6umJiYiRJMTEx2rt3r06fPm3rs2LFCgUGBqpevXqlXjsAAHA/Lh3ZSUxMVIcOHRQVFaWLFy8qJSVFa9eu1fLlyxUUFKS4uDglJCQoODhYgYGBGjp0qGJiYvTII49Iktq1a6d69eqpb9++mjx5sjIzMzVmzBjFx8czcgMAACS5OOycPn1a/fr1U0ZGhoKCgtSwYUMtX75cTz75pCTp/fffV7ly5dS9e3fl5+crNjZWs2bNsn3ew8NDS5cu1eDBgxUTEyM/Pz/1799fEyZMcNUpAQAAN+PSsDNnzpybbi9fvrxmzpypmTNn3rBP1apV9c033zi7NKBUHDx40NUl3LHKlSsrKirK1WUAwG1z+QRl4M+oMPecZLGoT58+ri7ljpWv4KvUnw4SeACUGYQdwAWK8nMlw1DIUyPlFVJ23vNUcOaEzix9T9nZ2YQdAGUGYQdwIa+QSPlYa7q6DAAwNbd79BwAAMCZCDsAAMDUCDsAAMDUCDsAAMDUCDsAAMDUCDsAAMDUCDsAAMDUCDsAAMDUCDsAAMDUCDsAAMDUCDsAAMDUCDsAAMDUCDsAAMDUCDsAAMDUCDsAAMDUCDsAAMDUCDsAAMDUCDsAAMDUCDsAAMDUCDsAAMDUCDsAAMDUCDsAAMDUCDsAAMDUCDsAAMDUCDsAAMDUCDsAAMDUCDsAAMDUCDsAAMDUCDsAAMDUCDsAAMDUCDsAAMDUCDsAAMDUCDsAAMDUCDsAAMDUCDsAAMDUCDsAAMDUXBp2kpKS9NBDDykgIEChoaHq2rWrUlNT7fq0atVKFovFbnnppZfs+qSnp6tTp07y9fVVaGioXnnlFV29erU0TwUAALgpT1cefN26dYqPj9dDDz2kq1ev6rXXXlO7du104MAB+fn52fq98MILmjBhgm3d19fX9nNhYaE6deokq9WqjRs3KiMjQ/369ZOXl5feeuutUj0fAADgflwadpYtW2a3Pm/ePIWGhmrHjh1q2bKlrd3X11dWq/W6+/juu+904MABrVy5UmFhYWrcuLEmTpyo0aNHa9y4cfL29i7RcwAAAO7NrebsXLhwQZIUHBxs175gwQJVrlxZDRo0UGJioi5fvmzbtmnTJkVHRyssLMzWFhsbq5ycHO3fv/+6x8nPz1dOTo7dAgAAzMmlIzv/rqioSMOHD9djjz2mBg0a2Np79eqlqlWrKiIiQnv27NHo0aOVmpqqxYsXS5IyMzPtgo4k23pmZuZ1j5WUlKTx48eX0JkAAAB34jZhJz4+Xvv27dP3339v1z5o0CDbz9HR0QoPD1ebNm2UlpamGjVqOHSsxMREJSQk2NZzcnIUGRnpWOEAAMCtucVtrCFDhmjp0qVas2aNqlSpctO+zZo1kyQdOXJEkmS1WpWVlWXX59r6jeb5+Pj4KDAw0G4BAADm5NKwYxiGhgwZoiVLlmj16tWqXr36LT+ze/duSVJ4eLgkKSYmRnv37tXp06dtfVasWKHAwEDVq1evROoGAABlh0tvY8XHxyslJUVfffWVAgICbHNsgoKCVKFCBaWlpSklJUUdO3ZUSEiI9uzZoxEjRqhly5Zq2LChJKldu3aqV6+e+vbtq8mTJyszM1NjxoxRfHy8fHx8XHl6AADADbh0ZCc5OVkXLlxQq1atFB4ebls+++wzSZK3t7dWrlypdu3aqU6dOho5cqS6d++ur7/+2rYPDw8PLV26VB4eHoqJiVGfPn3Ur18/u/fyAACAPy+XjuwYhnHT7ZGRkVq3bt0t91O1alV98803zioLAACYiFtMUAYAACgphB0AAGBqhB0AAGBqhB0AAGBqhB0AAGBqhB0AAGBqhB0AAGBqhB0AAGBqhB0AAGBqhB0AAGBqhB0AAGBqhB0AAGBqhB0AAGBqhB0AAGBqhB0AAGBqhB0AAGBqhB0AAGBqhB0AAGBqhB0AAGBqhB0AAGBqhB0AAGBqhB0AAGBqhB0AAGBqDoWdn3/+2dl1AAAAlAiHwk7NmjX1xBNP6JNPPlFeXp6zawIAAHAah8LOzp071bBhQyUkJMhqterFF1/U1q1bnV0bAADAXXMo7DRu3FjTpk3TqVOn9NFHHykjI0PNmzdXgwYNNGXKFP3666/OrhMAAMAhdzVB2dPTU926ddOiRYv0zjvv6MiRIxo1apQiIyPVr18/ZWRkOKtOAAAAh9xV2Nm+fbv+8pe/KDw8XFOmTNGoUaOUlpamFStW6NSpU+rSpYuz6gQAAHCIpyMfmjJliubOnavU1FR17NhR8+fPV8eOHVWu3O/ZqXr16po3b56qVavmzFoBAADumENhJzk5Wc8//7wGDBig8PDw6/YJDQ3VnDlz7qo4AACAu+VQ2Dl8+PAt+3h7e6t///6O7B4AAMBpHJqzM3fuXC1atKhY+6JFi/Txxx/fdVEAAADO4lDYSUpKUuXKlYu1h4aG6q233rrrogAAAJzFobCTnp6u6tWrF2uvWrWq0tPT77ooAAAAZ3Eo7ISGhmrPnj3F2n/88UeFhITcdVEAAADO4lDYee655/Tyyy9rzZo1KiwsVGFhoVavXq1hw4apZ8+ezq4RAADAYQ49jTVx4kQdO3ZMbdq0kafn77soKipSv379mLMDAADcikMjO97e3vrss8/0008/acGCBVq8eLHS0tL00Ucfydvb+7b3k5SUpIceekgBAQEKDQ1V165dlZqaatcnLy9P8fHxCgkJkb+/v7p3766srCy7Punp6erUqZN8fX0VGhqqV155RVevXnXk1AAAgMk4NLJzTe3atVW7dm2HP79u3TrFx8froYce0tWrV/Xaa6+pXbt2OnDggPz8/CRJI0aM0L/+9S8tWrRIQUFBGjJkiLp166YffvhBklRYWKhOnTrJarVq48aNysjIUL9+/eTl5cUoEwAAcCzsFBYWat68eVq1apVOnz6toqIiu+2rV6++rf0sW7bMbn3evHkKDQ3Vjh071LJlS124cEFz5sxRSkqKWrduLen3d/zUrVtXmzdv1iOPPKLvvvtOBw4c0MqVKxUWFqbGjRtr4sSJGj16tMaNG3dHI00AAMB8HLqNNWzYMA0bNkyFhYVq0KCBGjVqZLc46sKFC5Kk4OBgSdKOHTtUUFCgtm3b2vrUqVNHUVFR2rRpkyRp06ZNio6OVlhYmK1PbGyscnJytH///useJz8/Xzk5OXYLAAAwJ4dGdhYuXKjPP/9cHTt2dFohRUVFGj58uB577DE1aNBAkpSZmSlvb29VrFjRrm9YWJgyMzNtff496Fzbfm3b9SQlJWn8+PFOqx0AALgvhyco16xZ06mFxMfHa9++fVq4cKFT93s9iYmJunDhgm05ceJEiR8TAAC4hkNhZ+TIkZo2bZoMw3BKEUOGDNHSpUu1Zs0aValSxdZutVp15coVnT9/3q5/VlaWrFarrc8fn866tn6tzx/5+PgoMDDQbgEAAObk0G2s77//XmvWrNG3336r+vXry8vLy2774sWLb2s/hmFo6NChWrJkidauXVvsKyiaNGkiLy8vrVq1St27d5ckpaamKj09XTExMZKkmJgYTZo0SadPn1ZoaKgkacWKFQoMDFS9evUcOT0AAGAiDoWdihUr6plnnrnrg8fHxyslJUVfffWVAgICbHNsgoKCVKFCBQUFBSkuLk4JCQkKDg5WYGCghg4dqpiYGD3yyCOSpHbt2qlevXrq27evJk+erMzMTI0ZM0bx8fHy8fG56xoBAEDZ5lDYmTt3rlMOnpycLElq1apVsf0PGDBAkvT++++rXLly6t69u/Lz8xUbG6tZs2bZ+np4eGjp0qUaPHiwYmJi5Ofnp/79+2vChAlOqREAAJRtDr9U8OrVq1q7dq3S0tLUq1cvBQQE6NSpUwoMDJS/v/9t7eN25vyUL19eM2fO1MyZM2/Yp2rVqvrmm29uu3YAAPDn4VDYOX78uNq3b6/09HTl5+frySefVEBAgN555x3l5+dr9uzZzq4TAADAIQ6/VLBp06Y6d+6cKlSoYGt/5plntGrVKqcVBwAAcLccGtnZsGGDNm7cWOyrGKpVq6ZffvnFKYUBAAA4g0MjO0VFRSosLCzWfvLkSQUEBNx1UQAAAM7iUNhp166dpk6dalu3WCzKzc3VG2+84dSvkAAAALhbDt3Geu+99xQbG6t69eopLy9PvXr10uHDh1W5cmV9+umnzq4RAADAYQ6FnSpVqujHH3/UwoULtWfPHuXm5iouLk69e/e2m7AMAADgag6/Z8fT01N9+vRxZi0AAABO51DYmT9//k239+vXz6FiAAAAnM2hsDNs2DC79YKCAl2+fFne3t7y9fUl7AAAALfh0NNY586ds1tyc3OVmpqq5s2bM0EZAAC4FYfCzvXUqlVLb7/9drFRHwAAAFdyWtiRfp+0fOrUKWfuEgAA4K44NGfnn//8p926YRjKyMjQBx98oMcee8wphQEAADiDQ2Gna9eudusWi0X33HOPWrdurffee88ZdQEAADiFQ2GnqKjI2XXAjaSnpys7O9vVZdy2gwcPuroEAIAbc/ilgjCn9PR03V+nrvJ+u+zqUgAAcAqHwk5CQsJt950yZYojh4CLZGdnK++3ywp5aqS8QiJdXc5t+e3n7bqw4RNXlwEAcFMOhZ1du3Zp165dKigo0P333y9JOnTokDw8PPTggw/a+lksFudUiVLnFRIpH2tNV5dxWwrOnHB1CQAAN+ZQ2OncubMCAgL08ccfq1KlSpJ+f9HgwIED1aJFC40cOdKpRQIAADjKoffsvPfee0pKSrIFHUmqVKmS3nzzTZ7GAgAAbsWhsJOTk6Nff/21WPuvv/6qixcv3nVRAAAAzuJQ2HnmmWc0cOBALV68WCdPntTJkyf1xRdfKC4uTt26dXN2jQAAAA5zaM7O7NmzNWrUKPXq1UsFBQW/78jTU3FxcXr33XedWiAAAMDdcCjs+Pr6atasWXr33XeVlpYmSapRo4b8/PycWhwAAMDduqsvAs3IyFBGRoZq1aolPz8/GYbhrLoAAACcwqGwc+bMGbVp00a1a9dWx44dlZGRIUmKi4vjsXMAAOBWHAo7I0aMkJeXl9LT0+Xr62trf/bZZ7Vs2TKnFQcAAHC3HJqz891332n58uWqUqWKXXutWrV0/PhxpxQGAADgDA6N7Fy6dMluROeas2fPysfH566LAgAAcBaHwk6LFi00f/5827rFYlFRUZEmT56sJ554wmnFAQAA3C2HbmNNnjxZbdq00fbt23XlyhX99a9/1f79+3X27Fn98MMPzq4RAADAYQ6N7DRo0ECHDh1S8+bN1aVLF126dEndunXTrl27VKNGDWfXCAAA4LA7HtkpKChQ+/btNXv2bP3tb38riZoAAACc5o5Hdry8vLRnz56SqAUAAMDpHLqN1adPH82ZM8fZtQAAADidQxOUr169qo8++kgrV65UkyZNin0n1pQpU5xSHAAAwN26o7Dz888/q1q1atq3b58efPBBSdKhQ4fs+lgsFudVBwAAcJfuKOzUqlVLGRkZWrNmjaTfvx5i+vTpCgsLK5HiAAAA7tYdzdn547eaf/vtt7p06ZLDB1+/fr06d+6siIgIWSwWffnll3bbBwwYIIvFYre0b9/ers/Zs2fVu3dvBQYGqmLFioqLi1Nubq7DNQEAAHNxaILyNX8MP3fq0qVLatSokWbOnHnDPu3bt1dGRoZt+fTTT+229+7dW/v379eKFSu0dOlSrV+/XoMGDbqrugAAgHnc0W2sa6Mrf2xzVIcOHdShQ4eb9vHx8ZHVar3utoMHD2rZsmXatm2bmjZtKkmaMWOGOnbsqL///e+KiIhwuDYAAGAOdxR2DMPQgAEDbF/2mZeXp5deeqnY01iLFy92WoFr165VaGioKlWqpNatW+vNN99USEiIJGnTpk2qWLGiLehIUtu2bVWuXDlt2bJFzzzzzHX3mZ+fr/z8fNt6Tk6O0+oFAADu5Y7CTv/+/e3W+/Tp49Ri/qh9+/bq1q2bqlevrrS0NL322mvq0KGDNm3aJA8PD2VmZio0NNTuM56engoODlZmZuYN95uUlKTx48eXaO0AAMA93FHYmTt3bknVcV09e/a0/RwdHa2GDRuqRo0aWrt2rdq0aePwfhMTE5WQkGBbz8nJUWRk5F3VCgAA3NNdTVAubffdd58qV66sI0eOSJKsVqtOnz5t1+fq1as6e/bsDef5SL/PAwoMDLRbAACAOZWpsHPy5EmdOXNG4eHhkqSYmBidP39eO3bssPVZvXq1ioqK1KxZM1eVCQAA3IhDXxfhLLm5ubZRGkk6evSodu/ereDgYAUHB2v8+PHq3r27rFar0tLS9Ne//lU1a9ZUbGysJKlu3bpq3769XnjhBc2ePVsFBQUaMmSIevbsyZNYAABAkotHdrZv364HHnhADzzwgCQpISFBDzzwgMaOHSsPDw/t2bNHTz/9tGrXrq24uDg1adJEGzZssD0NJkkLFixQnTp11KZNG3Xs2FHNmzfXhx9+6KpTAgAAbsalIzutWrW66YsJly9ffst9BAcHKyUlxZllAQAAEylTc3YAAADuFGEHAACYGmEHAACYGmEHAACYGmEHAACYGmEHAACYGmEHAACYGmEHAACYGmEHAACYGmEHAACYGmEHAACYGmEHAACYGmEHAACYGmEHAACYGmEHAACYGmEHAACYGmEHAACYGmEHAACYGmEHAACYGmEHAACYGmEHAACYGmEHAACYGmEHAACYGmEHAACYGmEHAACYGmEHAACYGmEHAACYGmEHAACYGmEHAACYGmEHAACYGmEHAACYmqerCwBQ9hw8eNDVJdyRypUrKyoqytVlAHARwg6A21aYe06yWNSnTx9Xl3JHylfwVepPBwk8wJ8UYQfAbSvKz5UMQyFPjZRXSKSry7ktBWdO6MzS95SdnU3YAf6kCDsA7phXSKR8rDVdXQYA3BYmKAMAAFMj7AAAAFMj7AAAAFNzadhZv369OnfurIiICFksFn355Zd22w3D0NixYxUeHq4KFSqobdu2Onz4sF2fs2fPqnfv3goMDFTFihUVFxen3NzcUjwLAADgzlwadi5duqRGjRpp5syZ190+efJkTZ8+XbNnz9aWLVvk5+en2NhY5eXl2fr07t1b+/fv14oVK7R06VKtX79egwYNKq1TAAAAbs6lT2N16NBBHTp0uO42wzA0depUjRkzRl26dJEkzZ8/X2FhYfryyy/Vs2dPHTx4UMuWLdO2bdvUtGlTSdKMGTPUsWNH/f3vf1dERESpnQsAAHBPbjtn5+jRo8rMzFTbtm1tbUFBQWrWrJk2bdokSdq0aZMqVqxoCzqS1LZtW5UrV05btmwp9ZoBAID7cdv37GRmZkqSwsLC7NrDwsJs2zIzMxUaGmq33dPTU8HBwbY+15Ofn6/8/Hzbek5OjrPKBgAAbsZtR3ZKUlJSkoKCgmxLZGTZeBMsAAC4c24bdqxWqyQpKyvLrj0rK8u2zWq16vTp03bbr169qrNnz9r6XE9iYqIuXLhgW06cOOHk6gEAgLtw27BTvXp1Wa1WrVq1ytaWk5OjLVu2KCYmRpIUExOj8+fPa8eOHbY+q1evVlFRkZo1a3bDffv4+CgwMNBuAQAA5uTSOTu5ubk6cuSIbf3o0aPavXu3goODFRUVpeHDh+vNN99UrVq1VL16db3++uuKiIhQ165dJUl169ZV+/bt9cILL2j27NkqKCjQkCFD1LNnT57EAgAAklwcdrZv364nnnjCtp6QkCBJ6t+/v+bNm6e//vWvunTpkgYNGqTz58+refPmWrZsmcqXL2/7zIIFCzRkyBC1adNG5cqVU/fu3TV9+vRSPxcAAOCeXBp2WrVqJcMwbrjdYrFowoQJmjBhwg37BAcHKyUlpSTKAwAAJuC2c3YAAACcgbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMjbADAABMza3Dzrhx42SxWOyWOnXq2Lbn5eUpPj5eISEh8vf3V/fu3ZWVleXCigEAgLtx67AjSfXr11dGRoZt+f77723bRowYoa+//lqLFi3SunXrdOrUKXXr1s2F1QIAAHfj6eoCbsXT01NWq7VY+4ULFzRnzhylpKSodevWkqS5c+eqbt262rx5sx555JHSLhUAALghtx/ZOXz4sCIiInTfffepd+/eSk9PlyTt2LFDBQUFatu2ra1vnTp1FBUVpU2bNt10n/n5+crJybFbAACAObl12GnWrJnmzZunZcuWKTk5WUePHlWLFi108eJFZWZmytvbWxUrVrT7TFhYmDIzM2+636SkJAUFBdmWyMjIEjwLAADgSm59G6tDhw62nxs2bKhmzZqpatWq+vzzz1WhQgWH95uYmKiEhATbek5ODoEHAACTcuuRnT+qWLGiateurSNHjshqterKlSs6f/68XZ+srKzrzvH5dz4+PgoMDLRbAACAOZWpsJObm6u0tDSFh4erSZMm8vLy0qpVq2zb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3/72NyM/P9/VpZVpa9asMSQVW/r3728Yxu+Pn7/++utGWFiY4ePjY7Rp08ZITU11bdFl1M2u9dGjR6+7TZKxZs0aV5deptzqd/qPSvPRc4th8BpUAABgXkxQBgAApkbYAQAApkbYAQAApkbYAQAApkbYAQAApkbYAQAApkbYAQAApkbYAWBarVq10vDhw11dBgAXI+wAcEudO3dW+/btr7ttw4YNslgs2rNnTylXBaAsIuwAcEtxcXFasWKFTp48WWzb3Llz1bRpUzVs2NAFlQEoawg7ANzSU089pXvuuUfz5s2za8/NzdWiRYvUtWtXPffcc7r33nvl6+ur6Ohoffrppzfdp8Vi0ZdffmnXVrFiRbtjnDhxQj169FDFihUVHBysLl266NixY845KQAuQdgB4JY8PT3Vr18/zZs3T//+FX6LFi1SYWGh+vTpoyZNmuhf//qX9u3bp0GDBqlv377aunWrw8csKChQbGysAgICtGHDBv3www/y9/dX+/btdeXKFWecFgAXIOwAcFvPP/+80tLStG7dOlvb3Llz1b17d1WtWlWjRo1S48aNdd9992no0KFq3769Pv/8c4eP99lnn6moqEj/+7//q+joaNWtW1dz585Venq61q5d64QzAuAKhB0AbqtOnTp69NFH9dFHH0mSjhw5og0bNiguLk6FhYWaOHGioqOjFRwcLH9/fy1fvlzp6ekOH+/HH3/UkSNHFBAQIH9/f/n7+ys4OFh5eXlKS0tz1mkBKGWeri4AAG4mLi5OQ4cO1cyZMzV37lzVqFFDjz/+uN555x1NmzZNU6dOVXR0tPz8/DR8+PCb3m6yWCx2t8Sk329dXZObm6smTZpowYIFxT57zz33OO+kAJQqwg4At9ajRw8NGzZMKSkpmj9/vgYPHiyLxaIffvhBXbp0UZ8+fSRJRUVFOnTokOrVq3fDfd1zzz3KyMiwrR8+fFiXL1+2rT/44IP67LPPFBoaqsDAwJI7KQClittYANyav7+/nn32WSUmJiojI0MDBgyQJNWqVUsrVqzQxo0bdfDgQb344ovKysq66b5at26tDz74QLt27dL27dv10ksvycvLy7a9d+/eqly5srp06aINGzbo6NGjWrt2rV5++eXrPgIPoGwg7ABwe3FxcTp37pxiY2MVEREhSRozZowefPBBxcbGqlWrVrJareratetN9/Pee+8pMjJSLVq0UK9evTRq1Cj5+vratvv6+mr9+vWKiopSt27dVLduXcXFxSkvL4+RHqAMsxh/vIENAABgIozsAAAAUyPsAAAAUyPsAAAAUyPsAAAAUyPsAAAAUyPsAAAAUyPsAAAAUyPsAAAAUyPsAAAAUyPsAAAAUyPsAAAAUyPsAAAAU/v/APTORwUe+KCyAAAAAElFTkSuQmCC" + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAkQAAAHHCAYAAABeLEexAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/GU6VOAAAACXBIWXMAAA9hAAAPYQGoP6dpAAA2dklEQVR4nO3dfXzP9f7H8efXroxdMbZZtpmrXOeYEyvK1TFaDvE7lMuY09EZYYfKqRA5SgcRcTppyymFTnWKwgglk4tMklxOU7ZJLmZqF7bP7w8331vfSJrt+xnvx/12+9xufd6f1/fzfb2/XXj2+bw/36/DsixLAAAABqtkdwMAAAB2IxABAADjEYgAAIDxCEQAAMB4BCIAAGA8AhEAADAegQgAABiPQAQAAIxHIAIAAMYjEAEoc5MnT5bD4dCJEyfsbuWyjhw5IofDoX/+8592tyJJcjgcmjx5snM/JSVFDodDR44csa0nwDQEIgC4DrzwwgtKSUmxuw3ghkUgAoAKZtCgQfrxxx8VFRXlHCMQAeXL0+4GAACuPDw85OHhYXcbgFG4QgSg3Jw4cUJ9+/ZVQECAgoODNXr0aOXn519S9+qrryomJka+vr6qXr267r33Xh09etSlpkOHDmrWrJm+/PJLdezYUVWqVNFNN92kGTNmXHK+/Px8TZ48WQ0bNlTlypVVq1Yt9e7dW4cOHbqk9sUXX1S9evXk4+Oj3//+99q2bduvzquoqEhPPvmkGjRooMqVKys4OFjt2rVTamqqs+b++++Xn5+fDh8+rLi4OFWtWlXh4eGaMmWKLMu64vl/voaoTp062rNnjzZu3CiHwyGHw6EOHTr8ap8Arh5XiACUm759+6pOnTqaPn26tmzZorlz5+rUqVNavHixs2batGl64okn1LdvXw0fPlzfffednn/+ed1xxx3auXOngoKCnLWnTp1St27d1Lt3b/Xt21dvvvmmHnnkETVv3lzdu3eXJBUXF+vuu+/WunXrdO+992r06NE6e/asUlNT9cUXX6hevXrO8y1ZskRnz57VX/7yFzkcDs2YMUO9e/fW4cOH5eXl9Yvzmjx5sqZPn67hw4fr1ltvVW5urrZv367PPvtMf/jDH5x1xcXF6tatm9q2basZM2Zo1apVmjRpks6fP68pU6Zc9ef43HPPadSoUfLz89Njjz0mSQoNDb3q1wO4ChYAlLFJkyZZkqw//vGPLuN//etfLUnWrl27LMuyrCNHjlgeHh7WtGnTXOp2795teXp6uozfeeedliRr8eLFzrGCggIrLCzM6tOnj3Ps5ZdftiRZs2bNuqSvkpISy7IsKyMjw5JkBQcHWydPnnQe/9///mdJst57770rzu+WW26x4uPjr1gzZMgQS5I1atQol/ePj4+3vL29re+++845LsmaNGmScz85OdmSZGVkZDjHmjZtat15551XfE8ApcctMwDlJjEx0WV/1KhRkqT3339fkvTWW2+ppKREffv21YkTJ5xbWFiYGjRooPXr17u83s/PTwMHDnTue3t769Zbb9Xhw4edY//9739Vo0YN53v9lMPhcNnv16+fqlWr5txv3769JLmc73KCgoK0Z88eHThw4Ip1kjRy5EiX9x85cqQKCwu1du3aX30tAPfhlhmActOgQQOX/Xr16qlSpUrOtTEHDhyQZVmX1F3089tWtWvXviTUVKtWTZ9//rlz/9ChQ7r55pvl6fnr/3mLjIy85FzShVtzVzJlyhT17NlTDRs2VLNmzdStWzcNGjRILVq0cKmrVKmS6tat6zLWsGFDSeI7hoAKhkAEwG1+HmZKSkrkcDj0wQcfXPapKj8/P5f9X3ryyvqVRcq/pLTnu+OOO3To0CH973//05o1a/TSSy9p9uzZWrhwoYYPH16qXgDYi0AEoNwcOHBA0dHRzv2DBw+qpKREderUkXThipFlWYqOjnZeOblW9erV06effqqioqIrLoy+VtWrV9fQoUM1dOhQ5eXl6Y477tDkyZNdAlFJSYkOHz7sMrf9+/dLkvMzuFo/D5MAyhZriACUm/nz57vsP//885LkfCKsd+/e8vDw0JNPPnnJVRnLsvT999//5vfs06ePTpw4oXnz5l1yrLRXkn7u5335+fmpfv36KigouKT2p31YlqV58+bJy8tLnTt3/k3vWbVqVZ0+fbpU/QL4dVwhAlBuMjIy9Mc//lHdunVTWlqaXn31VfXv31+33HKLpAtXc5566ilNmDBBR44cUa9eveTv76+MjAy9/fbbeuCBBzRu3Ljf9J6DBw/W4sWLlZSUpK1bt6p9+/Y6d+6c1q5dq7/+9a/q2bPnNc+rSZMm6tChg2JiYlS9enVt375db775pssCakmqXLmyVq1apSFDhqhNmzb64IMPtHLlSv39739X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V1RUlE0d2Sc5OVkhISGKj4+3uxW3+uGHH1Spkut/gj08PFRSUmJTR/apWrWqatWqpVOnTmn16tXq2bOn3S25XXR0tMLCwrRu3TrnWG5urj799FPFxsba2Jk5uGVmA39/fzVr1sxlrGrVqgoODr5k/EY1btw49ejRQ1FRUTp27JgmTZokDw8P3XfffXa35hZjx47Vbbfdpn/84x/q27evtm7dqhdffFEvvvii3a25VUlJiZKTkzVkyBB5epr1n6MePXpo2rRpioyMVNOmTbVz507NmjVLw4YNs7s1t1m9erUsy9LNN9+sgwcPavz48WrUqJGGDh1qd2vlIi8vz+UqeEZGhtLT01W9enVFRkZqzJgxeuqpp9SgQQNFR0friSeeUHh4uHr16mVf02Xs1z6DkydPKjMzU8eOHZMk5/84hoWFlf+VMrc9z4YrMu2x+379+lm1atWyvL29rZtuusnq16+fdfDgQbvbcqv33nvPatasmeXj42M1atTIevHFF+1uye1Wr15tSbL27dtndytul5uba40ePdqKjIy0KleubNWtW9d67LHHrIKCArtbc5ulS5dadevWtby9va2wsDArMTHROn36tN1tlZv169dbki7ZhgwZYlnWhUfvn3jiCSs0NNTy8fGxOnfufMP9u/Frn0FycvJlj0+aNKnce3NYlkFfiwoAAHAZrCECAADGIxABAADjEYgAAIDxCEQAAMB4BCIAAGA8AhEAADAegQgAABiPQATAWB06dNCYMWPsbgNABUAgAnBd6tGjh7p163bZYx9//LEcDoc+//xzN3cF4HpFIAJwXUpISFBqaqq++eabS44lJyerdevWatGihQ2dAbgeEYgAXJfuvvtu1axZUykpKS7jeXl5Wr58uXr16qX77rtPN910k6pUqaLmzZvr9ddfv+I5HQ6H3nnnHZexoKAgl/c4evSo+vbtq6CgIFWvXl09e/bUkSNHymZSAGxDIAJwXfL09NTgwYOVkpKin/4k4/Lly1VcXKyBAwcqJiZGK1eu1BdffKEHHnhAgwYN0tatW0v9nkVFRYqLi5O/v78+/vhjffLJJ/Lz81O3bt1UWFhYFtMCYBMCEYDr1rBhw3To0CFt3LjROZacnKw+ffooKipK48aNU8uWLVW3bl2NGjVK3bp107Jly0r9fkuXLlVJSYleeuklNW/eXI0bN1ZycrIyMzO1YcOGMpgRALsQiABctxo1aqTbbrtNL7/8siTp4MGD+vjjj5WQkKDi4mJNnTpVzZs3V/Xq1eXn56fVq1crMzOz1O+3a9cuHTx4UP7+/vLz85Ofn5+qV6+u/Px8HTp0qKymBcAGnnY3AADXIiEhQaNGjdL8+fOVnJysevXq6c4779QzzzyjOXPm6LnnnlPz5s1VtWpVjRkz5oq3thwOh8vtN+nCbbKL8vLyFBMTo9dee+2S19asWbPsJgXA7QhEAK5rffv21ejRo7VkyRItXrxYDz74oBwOhz755BP17NlTAwcOlCSVlJRo//79atKkyS+eq2bNmsrKynLuHzhwQD/88INzv1WrVlq6dKlCQkIUEBBQfpMC4HbcMgNwXfPz81O/fv00YcIEZWVl6f7775ckNWjQQKmpqdq8ebP27t2rv/zlL8rJybniuTp16qR58+Zp586d2r59u0aMGCEvLy/n8QEDBqhGjRrq2bOnPv74Y2VkZGjDhg166KGHLvv4P4DrB4EIwHUvISFBp06dUlxcnMLDwyVJjz/+uFq1aqW4uDh16NBBYWFh6tWr1xXPM3PmTEVERKh9+/bq37+/xo0bpypVqjiPV6lSRR999JEiIyPVu3dvNW7cWAkJCcrPz+eKEXCdc1g/v2EOAABgGK4QAQAA4xGIAACA8QhEAADAeAQiAABgPAIRAAAwHoEIAAAYj0AEAACMRyACAADGIxABAADjEYgAAIDxCEQAAMB4BCIAAGC8/wc8sF2slnCLTgAAAABJRU5ErkJggg==" }, "metadata": {}, "output_type": "display_data" } ], - "execution_count": 35 + "execution_count": 10 } ], "metadata": { diff --git a/src/benchmark.py b/src/benchmark.py index ffb1917..8ac19ca 100644 --- a/src/benchmark.py +++ b/src/benchmark.py @@ -4,6 +4,7 @@ import random from dataclasses import dataclass from statistics import mean, variance from enum import Enum +from pathlib import Path @dataclass class Benchmark: @@ -15,18 +16,18 @@ class ShuffleTypes(Enum): FULL_SHUFFLE = "FULL_SHUFFLE" SPLIT_SHUFFLE = "SPLIT_SHUFFLE" -def observations(number_of_keys, properties_per_key, passcode_len, shuffle_type: ShuffleTypes = ShuffleTypes.SPLIT_SHUFFLE): +def observations(number_of_keys, properties_per_key, passcode_len, complexity: int, disparity: int, shuffle_type: ShuffleTypes): k = number_of_keys p = properties_per_key n = passcode_len - nkode = [random.randint(0, k*p-1) for _ in range(n)] + passcode = passcode_generator(k, p, n, complexity, disparity) keypad = Keypad.new_keypad(k, p) def obs_gen(): for _ in range(100): # finite number of yields yield Observation( keypad=keypad.keypad.copy(), - key_selection=keypad.key_entry(target_passcode=nkode) + key_selection=keypad.key_entry(target_passcode=passcode) ) match shuffle_type: case ShuffleTypes.FULL_SHUFFLE: @@ -38,25 +39,94 @@ def observations(number_of_keys, properties_per_key, passcode_len, shuffle_type: return obs_gen() -def split_shuffle_benchmark( +def passcode_generator(k: int, p: int, n: int, c: int, d: int) -> list[int]: + assert n >= c + assert p*k >= c + + assert n >= d + assert p >= d + passcode_prop = [] + passcode_set = [] + valid_choices = {i for i in range(k*p)} + repeat_set = n-d + repeat_prop = n-c + prop_added = set() + set_added = set() + + for _ in range(n): + prop = random.choice(list(valid_choices)) + prop_set = prop//p + passcode_prop.append(prop) + passcode_set.append(prop_set) + + if prop in prop_added: + repeat_prop -= 1 + if prop_set in set_added: + repeat_set -= 1 + + prop_added.add(prop) + set_added.add(prop_set) + + if repeat_prop <= 0: + valid_choices -= prop_added + + if repeat_set <= 0: + for el in valid_choices.copy(): + if el // p in set_added: + valid_choices.remove(el) + + return passcode_prop + + +def shuffle_benchmark( number_of_keys: int, properties_per_key: int, passcode_len: int, max_tries_before_lockout: int, run_count: int, + complexity: int, + disparity: int, + shuffle_type: ShuffleTypes, + file_path: str = '../output', + overwrite: bool = False ) -> Benchmark: + file_name = f"{shuffle_type.name.lower()}-{number_of_keys}-{properties_per_key}-{passcode_len}-{max_tries_before_lockout}-{complexity}-{disparity}-{run_count}.txt" + full_path = Path(file_path) / file_name + if not overwrite and full_path.exists(): + print(f"file exists {file_path}") + + with open(full_path, "r") as fp: + runs = fp.readline() + runs = runs.split(',') + runs = [int(i) for i in runs] + return Benchmark( + mean=mean(runs), + variance=variance(runs), + runs=runs + ) runs = [] for _ in range(run_count): evilkode = Evilkode( - observations=observations(number_of_keys, properties_per_key, passcode_len), + observations=observations( + number_of_keys=number_of_keys, + properties_per_key=properties_per_key, + passcode_len=passcode_len, + complexity=complexity, + disparity=disparity, + shuffle_type=shuffle_type, + ), number_of_keys=number_of_keys, properties_per_key=properties_per_key, passcode_len=passcode_len, - max_tries_before_lockout=max_tries_before_lockout + max_tries_before_lockout=max_tries_before_lockout, ) evilout = evilkode.run() runs.append(evilout.iterations) + full_path.parent.mkdir(parents=True, exist_ok=True) + with open(full_path, "w") as fp: + fp.write(",".join([str(i) for i in runs])), + return Benchmark( mean=mean(runs), variance=variance(runs), @@ -70,15 +140,24 @@ def full_shuffle_benchmark( passcode_len: int, max_tries_before_lockout: int, run_count: int, + complexity: int, + disparity: int, ) -> Benchmark: runs = [] for _ in range(run_count): evilkode = Evilkode( - observations=observations(number_of_keys, properties_per_key, passcode_len, shuffle_type=ShuffleTypes.FULL_SHUFFLE), + observations=observations( + number_of_keys=number_of_keys, + properties_per_key=properties_per_key, + passcode_len=passcode_len, + complexity=complexity, + disparity=disparity, + shuffle_type=ShuffleTypes.FULL_SHUFFLE, + ), number_of_keys=number_of_keys, properties_per_key=properties_per_key, passcode_len=passcode_len, - max_tries_before_lockout=max_tries_before_lockout + max_tries_before_lockout=max_tries_before_lockout, ) evilout = evilkode.run() runs.append(evilout.iterations) diff --git a/src/evilkode.py b/src/evilkode.py index f750acb..d202089 100644 --- a/src/evilkode.py +++ b/src/evilkode.py @@ -1,6 +1,5 @@ import math from dataclasses import dataclass -from itertools import chain from typing import Iterator diff --git a/tests/test_benchmark.py b/tests/test_benchmark.py new file mode 100644 index 0000000..eaee76f --- /dev/null +++ b/tests/test_benchmark.py @@ -0,0 +1,15 @@ +from src.benchmark import passcode_generator +import pytest + +@pytest.mark.parametrize( + "k, p, n, c, d, runs", + [ + (6, 9, 4, 4, 4, 100) + ] +) +def test_passcode_generator(k, p, n, c, d, runs): + for _ in range(runs): + passcode = passcode_generator(k=k, p=p, n=n, c=c, d=d) + passcode_sets = [el//p for el in passcode] + assert c <= len(set(passcode)) + assert d <= len(set(passcode_sets))