{ "cells": [ { "cell_type": "code", "execution_count": 1, "id": "4bcd49a4", "metadata": { "nbsphinx": "hidden" }, "outputs": [], "source": [ "%%capture\n", "# Install HermesPy and its dependencies in the current kernel\n", "# When running on Colabs, a restart of the runtime is required afterwards\n", "\n", "import sys\n", "!{sys.executable} -m pip install --quiet hermespy" ] }, { "cell_type": "markdown", "id": "199efcaa", "metadata": {}, "source": [ "Implementing FEC codings\n", "=============================\n", "\n", "This Jupyter notebook will outline the step-by-step process of implementing a new coding scheme for the forward error correction in communication modems.\n", "The selected algorithm is a repetition encoder, since it is arguably the most basic error correction coding.\n", "\n", "As an initial step, we will import all required modules from HermesPy:" ] }, { "cell_type": "code", "execution_count": 2, "id": "cee5a390", "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "from hermespy.fec import Encoder" ] }, { "cell_type": "markdown", "id": "32929b07", "metadata": {}, "source": [ "Error correcting coding steps are represented by the abstract [Encoder](../api/fec/coding.rst#hermespy.fec.coding.Encoder) interface.\n", "Each coding algorithm is represented by a class inheriting from the interface,\n", "which requires them to implement the abstract functions and properties\n", "\n", "* [encode](../api/fec/coding.rst#hermespy.fec.coding.Encoder.encode)\n", "* [decode](../api/fec/coding.rst#hermespy.fec.coding.Encoder.decode)\n", "* [bit_block_size](../api/fec/coding.rst#hermespy.fec.coding.Encoder.bit_block_size)\n", "* [code_block_size](../api/fec/coding.rst#hermespy.fec.coding.Encoder.code_block_size)\n", "\n", "Let's assume our repetition coding takes blocks of $K = 4$ data bits and repeats them $3$ times.\n", "The resulting code block size would be $N = 3K = 12$, which results in a rate of\n", "\\begin{equation}\n", "\\mathbf{R} = \\frac{K}{N} = \\frac{1}{3}\n", "\\end{equation}\n", "for the full encoding.\n", "During decoding, the repetition coding decides by majority voting which bit has been transmitted.\n", "So, our coding implementation is" ] }, { "cell_type": "code", "execution_count": null, "id": "53c0b665", "metadata": {}, "outputs": [], "source": [ "class RepetitionCoding(Encoder):\n", " \n", " @property\n", " def bit_block_size(self) -> int:\n", " return 4\n", " \n", " @property\n", " def code_block_size(self) -> int:\n", " return 12\n", " \n", " def encode(self, bits: np.ndarray) -> np.ndarray:\n", " return np.tile(bits, 3)\n", " \n", " def decode(self, encoded_bits: np.ndarray) -> np.ndarray:\n", " return (np.mean(np.reshape(encoded_bits, (3, self.bit_block_size)), axis=0, keepdims=False) > .5).astype(int)" ] }, { "cell_type": "markdown", "id": "7c6f60ca", "metadata": {}, "source": [ "Now we can inspect our coding implementation:" ] }, { "cell_type": "code", "execution_count": null, "id": "79ea6e6b", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Our coding rate is 0.3333333333333333 with an input block size of 4 and an output block size of 12\n", "Let's assume we transmit the following data block: [0 1 1 1]\n", "After encoding the respective code block is: [0 1 1 1 0 1 1 1 0 1 1 1]\n", "After channel propagation the first bit has flipped: [1 1 1 1 0 1 1 1 0 1 1 1]\n", "But the coding can correct a single bit flip to: [0 1 1 1]\n" ] } ], "source": [ "coding = RepetitionCoding()\n", "print(f\"Our coding rate is {coding.rate} with an input block size of {coding.bit_block_size} and an output block size of {coding.code_block_size}\")\n", "\n", "bits = np.random.randint(0, 2, coding.bit_block_size)\n", "print(f\"Let's assume we transmit the following data block: {bits}\")\n", "\n", "encoded_bits = coding.encode(bits)\n", "print(f\"After encoding the respective code block is: {encoded_bits}\")\n", "\n", "error_code = encoded_bits.copy()\n", "error_code[0] = not error_code[0]\n", "print(f\"After channel propagation the first bit has flipped: {error_code}\")\n", "\n", "corrected_data = coding.decode(error_code)\n", "print(f\"But the coding can correct a single bit flip to: {corrected_data}\")\n" ] }, { "cell_type": "markdown", "id": "e9e4d2a7", "metadata": {}, "source": [ "We may now investigate our newly created forward error correction coding within a full Hermes simulation capaign." ] }, { "cell_type": "code", "execution_count": null, "id": "2b59d719", "metadata": {}, "outputs": [], "source": [ "from hermespy.core import ConsoleMode, dB\n", "from hermespy.simulation import Simulation\n", "from hermespy.modem import BitErrorEvaluator, DuplexModem, RootRaisedCosineWaveform\n", "\n", "# Create a new simulation featuring a single device transmitting at 10GHz\n", "simulation = Simulation(console_mode=ConsoleMode.SILENT)\n", "device = simulation.scenario.new_device(carrier_frequency=10e9, bandwidth=1e6, oversampling_factor=2)\n", "\n", "# Configure a communication operation on the device, using our coding\n", "modem = DuplexModem()\n", "modem.waveform = RootRaisedCosineWaveform(modulation_order=4, num_preamble_symbols=0, num_data_symbols=10)\n", "modem.encoder_manager.add_encoder(coding)\n", "device.add_dsp(modem)\n", "\n", "# Run a very low-demanding simulation for demonstration purposes\n", "simulation.new_dimension('noise_level', dB(0, 4, 8, 16, 18, 20), device)\n", "simulation.add_evaluator(BitErrorEvaluator(modem, modem))\n", "simulation.num_samples = 1000\n", "\n", "result = simulation.run()" ] }, { "cell_type": "markdown", "id": "cb2ce415", "metadata": {}, "source": [ "This allows us to visualize the achieved bit error rates for given linear signal to noise ratios:" ] }, { "cell_type": "code", "execution_count": 6, "id": "f4a24f7e", "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAkIAAAHgCAYAAABJmwJ4AAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjEsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvc2/+5QAAAAlwSFlzAAAPYQAAD2EBqD+naQAAQnFJREFUeJzt3Qd4VFX6x/E3HQgJLXQQWToBQw0dRARUlN5FrKxucP1bUGxIsSCKqIugrKso6oLSi9JBpIXQpASkSQ0QOgkkpN7/c44km0ACCUxyZuZ+P89zntyZ3LnzziQ388u559zrISKWAAAA2JCn6QIAAABMIQgBAADbIggBAADbIggBAADbIggBAADbIggBAADbIggBAADbIggBAADbIggBAADbIggBhliWJcOHDzddBpxQpUqV9O/Ho48+auT51fOq51d1AO6OIAQ4+MMjY4uOjpYVK1bIfffdd9PHN2vWTAejIkWK5Oj5Jk+efN3zpbX4+HhxVgcPHsxU66VLl2TDhg3yyCOP3PI277///jwJlWqb2b3HqpUuXVpc2WuvvSZdunQxXQZglLfZpwfcz7Bhw/SHvYeHh/6gfOyxx2ThwoXy4IMPys8//5y+XoECBSQ5OTn9dvPmzWXEiBHyzTffyMWLF3P0XFeuXJGnnnrquvtTUlLEmW3dulU++ugjvVy2bFn9GqZMmSJ+fn7yn//8J9fbe+CBB+TZZ5+VkSNH5kG1Is8884wObNe6cOGCuLLXX39dZsyYIXPnzs10/3fffSfTpk2ThIQEY7UB+YUgBDiYCj2bN29Ov/3VV1/pnqF+/fplCkKO+JBRQeqHH37I9eMKFSokcXFxWX6vYMGCt9Wj5OXlJZ6enpKUlJTtOlFRUZnqVuHvzz//lBdeeOGWglBeU2Hh7NmzYhepqamEINgGh8aAPKZ6DVSwyNj7c+0YIfV17NixevnQoUPph14cMUYj7ZBd69atZcKECTqUHTt2TH9v5cqVsmPHDmnQoIGsWrVKLl++LO+9957+XsmSJXUoOXnypK7/999/l4EDB2Y5luWll16S//u//5P9+/frD9DatWvnqsYzZ87IH3/8IVWqVMl0f8uWLeWnn36Sw4cP696vI0eOyLhx43RvWsZDhKo3SMl42CqN6plTte3cuVO/DvV6vvjiCylatKg4QqlSpXToe+utt677XvXq1XUtgwcP1reLFSsmH374oWzfvl1iY2N1z98vv/wid911102fR/2sVLuWev2qBzIj9fNYu3atfl9V4N20aZP06NEj0zqqrsKFC+sey7T3TG3rRmOE/vGPf+j3Uf0sVJj97LPPrjuUm/Y7VatWLX1YWP1Oqd+3l19++aavETCBHiHAwdQHQ4kSJfQHsPqQ/Oc//6k/cL7//vtsHzNr1iz9odm/f395/vnn9QeYcvr06Zs+n3quayUmJuoP2owmTpyotzdq1Cjx9/fP9HjVi6UOhagaVVBSQePXX3+VqlWr6g879UHbq1cv+fbbb3WA+Ne//pVp248//rh+zL///W8dhM6dOye57UWqUKGCnD9/PtP96jlV79Xnn3+ue2RCQ0P1+6nW7d27t15n0qRJUq5cOenQoYMMGDDgum2r76sPe/Uhr+quXLmyDk7169eXFi1aXBdQs1K8ePHr7lOPU0Hm1KlTOkSqetR7m1GfPn30etOnT9e3//a3v0nXrl31bfWeqkOnTz/9tH68Co8nTpwQR1DBb968ebrXzdfXV/r27at7tTp16qSDl6LeKxV0IyIi9M9NOXDgQLbbVGFdHbpdunSp/nnUqFFDB6PGjRtf9z6qwLdo0SL9e62CbM+ePeWDDz7QAUndDzgb9a8TjUa7zfboo49aWYmPj7cGDhx43frK8OHD02+/9NJL+r5KlSrl6PkmT55sZWfhwoXX1fXbb79Znp6embaxcuVK/b2///3vme5/7rnn9P39+/dPv8/b29tau3atFRMTYxUuXFjfp2pVLly4YAUFBeWo7oMHD1qLFi2ySpQooVtwcLD17bff6u2MHz8+07oFChS47vFDhw61UlJSrIoVK6bfpx6nXLtuixYt9P39+vXLdH+HDh2yvP/apn4+2dm9e3f6eoMGDdL3qdeS8fE7d+60li1bln7b19fX8vDwyLSOeg/V78ibb76Z6T5F/ewy/qxUy+r3QL2nN3rf1M9u+/btmWpRLTY2Vj8+u9/ltN9F9bO9cuWK/rllrD8sLEyv99hjj133OzVgwID0+3x8fKzjx49b06dPN76f0mhyTaNHCHCwsLAw2bt3r15W//Gn/eetemhmz57t0OdSh3oeeuih6+5P61HK6Msvv9RjP66lDnOkHRLJOPhY9U5MnTo1/T71H7/qUVE9R23atMk03mnmzJlZPmd2OnbseN36X3/99XWHT1RtaVTPkBq/tG7dOj0GSfXoHD169IbPo3qU1KFJ1YuRsedMjeFSP4+2bdtmeo3Z6d69u8TExGS6Tx3ySaN6PtRhR9UDlHaILDg4WLdPP/00U09dGvUaVO+aGoS9Z88efXjSUTK+b+o5VI/b6tWr9Ti1W3HvvffqgeyffPJJpsOO6ndKHUpVPU1qnFca9d5m7AFVhw5Vz5PqEQOcDUEIcDD1Bz/jYGn1QatmSalDTAsWLLjhIOLcUrPDli9fnqN1rx1HkkaN9bi2JjU2ZN++fZk+9JTdu3enfz8n285OeHi4vPnmm/oDuk6dOnpZHU7JGBSUihUr6sNNnTt3vu7wVE5OM1CtWjUdBLI7xKgOXebEb7/9dsPB0up76uegDo+lBSEVitT7qkLSteOVVFhWh+i8vf/3J9iRg7FVMFHvab169TKNp8oqCOdE2s9bBbaM1OtTg9yv/X1IG4OWkTrsmZOxUEB+IwgBeUyFCTWAVI39UR/Mu3btMlJHdjPBHHHOodxuQ/UGpQW4JUuW6IHSqodJhYSPP/44vcdE9eSoADRmzBi9juqFKV++vB6rpL5/M2odNebp4YcfzvL7ORmDlVOqp0z1ioSEhMi2bdt0KFKvMWPAUdPV33nnHT2TUJ1mQY2lUuFE9bTc7PWo3yMVpK6lwuS1A8zV+CAV3lTgUj17KrCocVzZvQ+Olt3pG7KqHzCNIATkg7T//NWg6exc2/tikpqlpf57Vx9cGeuqWbNm+vcdSQ3gVYOzVVBQg5vVTKe6devqAblqppo6r03GwzQ5fe/U4F+1vppBlfFwUV6YM2eOHiiueoIUVfvo0aMzraMGDauZVNee+0n1Wt3s0KLqUcnq0NK1vTFqdph6rerwY8YeNhWEbvV3Lu3nrV5Txt4/Hx8f3bO1bNmyHG0HcEZMnwfyIQSpGU3qQzLt0FJW0sacOGpa9+0GE3Wiw7QP9bSeBzVjS43/ULOcHE31+gQFBcmgQYMy9Spc24ugeo2ye++uPVymZiyp91/1vlxLvZ6cnsU7J9QMssWLF+ueIDVLS/28VTjKSL2ma1+PCkdqFtzNqFCngqh6j9KosKpmbF37HCrgZOwpUmFJzVbL6n3Lye+bCjrq9Tz33HOZ7n/yySf14zOOFwNcDT1CgIOpyz2k9ZyoMShqSryaGq96B66d0p5R2riid999Vx9mUYcz5s+fn+2JDxX1IZ/d4Q41MPtGj70RNZ1aTetWh3oaNmyoz22kPrDVYRcVRLI6y/LtUtOq1fTqF198UQ88VofC1HmJ1PmV1OEwNVhZ9XaosUTZvXdqMLcKIyoM/Pjjj/rwkDpnkOppUuNl1GE49b6qQ5RqILV6LWqg982o157Va1aH7tT0+TTqOdWUdXVIStVx7RnC1RgxNQ1dDQxXg75Vr5f6+d1o2noa9Rj13qjtqkNr6ndLnfE6MjJSAgMD09dToUSdR0i9n//973/1euo8Ruq9VIftrn3fVI+ZOpHl8ePHdW+PGuN2LdVbpX5/1fR5tV116E31DqnXqda/0akhAFdgfOoajeau0+fj4uKsLVu2WE8//fRNp8+r9sYbb1hHjx61kpOTbzqV/kbT5zM+Nq2uhg0bXrcNNdV5x44dWW6/ZMmS1ldffWWdOnVKT53etm1bpuncGad5q6n/OX2f1FTv+fPnZ/k9dZqBjNPGa9asaS1ZskRP2Vd1TJo0yapbt+51U8vVaQE+/fRTKzo6Wk+tv3Yq/VNPPWVt3LjRunz5snXx4kX9Wt5//32rTJkytzx9XmnTpk2m9dVpBdRzXHvqgYzT5z/88EMrKipKr7d69WqrSZMm102Nz2r6vGpqm/v379c/D/V71b59+yynzz/++OPWnj179LT8Xbt26e2kvZaM61WvXt369ddf02tOm0p/7fT5jNPl1fYSEhKsEydOWBMmTLCKFCmSo9+prOqk0cQJmsfVBQAAANthjBAAALAtghAAALAtghAAALAtghAAALAtghAAALAtghAAALAtghAAALAtghAAALAtghAAALAtghAAALAtghAAALAtghAAALAtghAAALAtghAAALAtghAAALAtghAAALAtghAAALAtghAAALAtghAAALAtghAAALAtghAAALAtghAAALAtghAAALAtghAAALAtghAAALAtghAAALAtghAAALAtghAAALAtWwShWbNmyblz52T69OmmSwEAAE7EFkHo008/lYEDB5ouAwAAOBlbBKFVq1ZJbGys6TIAAICT8TZdQKtWreTll1+Whg0bSrly5aRr164yd+7cTOuEhYXpdcqUKSPbtm2Tf/7zn7Jx48Z8q1HVRZACAMC1BAQEyPHjx507CPn7++tw8/XXX8vs2bOv+37v3r1l3Lhx8swzz8iGDRvk+eefl8WLF0uNGjXk9OnTep2tW7eKt/f1L6VDhw5y4sSJXNXj6+srfn5+6bfLli0re/bsuaXXBgAAzCpfvvwNw5DxILRo0SLdsvPiiy/Kl19+Kd98842+rQJRp06d5IknnpAxY8bo++rXr++wel577TUZMWJElm8kvUIAALhOb1BUVNRNP7uNB6Eb8fHx0YfMRo8enX6fZVmybNkyadasWZ48p3ou1QOV1RtJEAIAwL04dRAKCgrSh7yio6Mz3a9u16xZM8fbWbp0qYSEhOjDcEePHpVevXpJeHh4lusmJibqBgAA3J9TByFHad++vekSAACAE3Lq6fNnzpyR5ORkKV26dKb71e2TJ08aqwsAALgHpw5CSUlJsnnzZmnXrl36fR4eHvr2+vXrjdYGAABcn/FDY2rcTtWqVdNvV65cWY/nUZfEUON51MDlb7/9VjZt2iQRERF6+rx6zOTJk43WDQAA3INlsrVp08bKyuTJk9PXGTx4sHXo0CHrypUrVnh4uBUaGprndYWFhVmRkZHW7t27dT0BAQFG3ycajUaj0WiS46Y+t3Py+e1xdQHZUNPnY2JiJDAwkOnzAAC42ee3U48RAgAAyEsEIQAAYFsEIQAAYFsEIQAAYFsEIQAAYFsEIUP8/AtJlUb1TZcBAICtEYSyERYWJpGRkfokjo4WWKqkvPDjN/LkhI+k9N/udPj2AQBAzhCEsjFx4kQJDg6W0NBQh2879sxZOX/ipPgVKiiPjH1HfAr4Ofw5AADAzRGEDLBSU+WHV4dLzJmzUrZaFen26oumSwIAwJYIQoZcOnte/vvqCElNTZUmPTpLg04dTJcEAIDtEIQM2rdhkyyb9NfFY3u+NVRK3nmH6ZIAALAVgpBhS774WvZHbBa/QoVk4Nh3xNuP8UIAAOQXgpATjBf6fuhwiT17TsrVqCZdhz5vuiQAAGyDIOQE1Cyy/77213ihZr26Sr377jVdEgAAtkAQchJ712+U5f/5Vi/3GvGqBN1RwXRJAAC4PYKQgRMqZmfJxK/kwOatUsDfXwaOfVe8fX3z7bkBALAjDzVMxXQRziwgIEBiYmIkMDBQYmNj8/z51FmnX5r+rRQuXkzWTpsps94dm+fPCQCAXT+/6RFyMjGnTst/Xx+ll1v07SF3tW9ruiQAANwWQcgJ7VkbLiu+mqKXe498XUpUKG+6JAAA3BJByEkt/OzfcnDLNikYUFge+egd8fLxMV0SAABuhyDkpFKTU+T7V96SyxcuSsXaNeWhl541XRIAAG6HIOTELkSfkqlXxwu1eri31G3XxnRJAAC4FYKQk9u9ep2snPyDXu4z6g0pXr6s6ZIAAHAbBCEX8Mu/PpdD23ZIwcAAeeTDd8TL29t0SQAAuAWCkKuMF3r5LYm7GCN31K0tnV4IM10SAABugSDkRGeWvpHzJ07KtGHv6OU2A/tJcNtWpksCAMDlcWZpJzuz9M10fvk5HYTiYmJkXM9HdUACAACZcWZpN/XzxxPl8PZIKRQYKAM+HCWe3l6mSwIAwGURhFxMSnKyfP/KMImPiZU7Q+rKA8/9w3RJAAC4LIKQCzoXdUKmDXtXL7d9/GGp1aq56ZIAAHBJBCEXtXPFKln9w096ud97b0nR0qVMlwQAgMshCLmw+R99Jkcjd4t/0SIy4APGCwEAkFsEIReWkpQk3w0ZJvGxl6RygxC5b/DfTZcEAIBLIQi5uLPHouSn4e/p5XZPDZSaLZuaLgkAAJdBEHID25eulLXTZurlfu++JYGlSpouCQAAl0AQchPzPvyXRO3eK4WLF5MBH4wUTy/GCwEAcDMEITeRnJgoU4a8IVcuX5YqDetLh7AnTZcEAIDTIwi5yLXGcuLMkWMyfcT7erndU49K9WaNTZcEAIBT41pjLnatsZzo+dZQadarq8SePScf9RwosWfOmi4JAIB8xbXGbGzOmE/k+J59ElCiuAwYM1I8PPkxAwCQFT4h3VByQoJMGfKmJMTFSdXQhtLhmSdMlwQAgFMiCLmp04eOyIxRY/TyvU8/LtWaNDJdEgAATocg5Ma2/LxENsycJ56entL//RH6UBkAAPgfgpCbm/3+ODmx74AEBpXQYYjxQgAA/A+fim4u6UqCTHnpDUmIi5fqTRtLu0GPmi4JAACnQRCygVMHD8usd8fq5Y7/eFL+1qi+6ZIAAHAKBCGb2DTvF4mYs0BfekNNqVeX4gAAwO4IQjYy+72P5OT+P6VIqZLS/723xMNDnU8TAAD7IgjZSGL8FX1+IfW1Roumcs+TA02XBACAUQQhm4k+cFD3DCn3PTtIKjcIMV0SAADGEIRsSI0V2jR/4V/jhT4YJf5Fi5guCQAAIwhCNjXz7Q/1bLKipUtJP8YLAQBsiiCUjbCwMImMjJSIiAhxR4nx8TJlyBv6PEO1WjWXux/rb7okAADyneoGsPL/aV1HQECAxMTESGBgoMTGxoq7adKjs/Qe8ZqkJCfLxMfC5NC2HaZLAgAg3z6/6RGyOXUtsi2/LBEvb295ZOzbUqhIoOmSAADINwQhyIyRY/TV6ouWKS193xlmuhwAAPINQQiSEBenzy+UlJAgwXe3lDYD+5kuCQCAfEEQgnZ8zz6Z+8GnernT82Fyx13BpksCACDPEYSQbv1Ps+X3xcvFy8dbHvngbSkYGGC6JAAA8hRBCJlMHzFazhw9JsXLl5W+b79huhwAAPIUQQiZXLl0Wb4b8qYkJyZKnXvaSKuHe5suCQCAPEMQwnWO7doj88aO18sPvvSsVAyuZbokAADyBEEIWVo7dYZsX7pSvH185JGx70iBgMKmSwIAwOEIQsjWj8Pfk7PHoqREhXLSZ+TrpssBAMDhCELI1pXYS/LdkGGSnJQkd7VvKy369TRdEgAADkUQwg0djdwtC8ZN0Mudh/xTyteqbrokAAAchiCEm1r9/Y+yc8Uq8fb1lYFj3xU//0KmSwIAwCEIQsiRacPek3NRJyTojgr6avUAALgDghByJD4mRr57+U1JSUqWevfdK816dzNdEgAAt40ghBw7smOX/PzJRL3c5ZX/k3I1qpkuCQCA20IQQq6smjJVIn9dIz5+fjJw7DviV4jxQgAA10UQykZYWJhERkZKRESE6VKczrQ335bzJ05KyTvvkJ7Dh5ouBwCAW+YhItatP9z9BQQESExMjAQGBkpsbKzpcpzGnSF1JeybieLl7S0/jRgtG2bOM10SAAC5/vymRwi35NC2HbJw/CS93O3VF6Vs9SqmSwIAINcIQrhlv07+QXavXic+BdR4oXfFt2BB0yUBAJArBCHcMsuyZOrro+RC9CkpVbmS9Bj2sumSAADIFYIQbsvlCxfl+1fekpTkZGn00P0S2vVB0yUBAJBjBCHctoNbtsniCf/Ry91ef0lKV6lsuiQAAHKEIASHWPHVFNmzNlx8CxaQgR+p8UIFTJcEAMBNEYTgsPFC/319lFw8dVrKVKmse4YAAHB2BCE4zKVz5+WHocMlNSVFjxVq+ND9pksCAOCGCEJwqAObtsriz7/Syz3efFnPJgMAwFkRhOBwy7/8VvaGbxS/QgX1eCF1niEAAJwRQQgOZ6Wmyg+vDpeYM2elbLUq+szTAAA4I4IQ8sSls+flv6+OkNTUVGnSo7M06NTBdEkAAFyHIIQ8s2/DJlk2abJe7vnWUH21egAAnAlBCHlqyRdfy/6IzeJXqJAMHPuOePsxXggA4DwIQsiH8UIjJPbsOSlXo5p0eeX/TJcEAEA6ghDyXMzpM/Lf10bq8ULNe3eTeh3bmS4JAACNIIR8sXd9hCz/z7d6udeI1yTojgqmSwIAgCCE/LNk4ldyYPNWKVDYXwaOfVe8fX1NlwQAsDmCEPKNuvTG968M15fiKF+runR++TnTJQEAbI4ghHwVc+q0vjir0qJvD7mrfVvTJQEAbIwghHy3Z224rPhqil7uPfJ1KVGhvOmSAAA2RRCCEQs/+7cc3LpdCgYUlkfGvi1ePj6mSwIA2BBBCEakJqfI9y8Pk8sXLkrF4Fry4IuDTZcEALAhghCMuRB9SqZeHS/UekAfqXNPG9MlAQBshiAEo3avXicrJ/+gl/u+/YYUL1/WdEkAABshCGUjLCxMIiMjJSIiwnQpbu+Xf30uh7btkIKBAfLIh++Il7e36ZIAADbhoS4HZboIZxYQECAxMTESGBgosbGxpstxW8XKlpEXp38rhYoEyqopU2Xeh/8yXRIAwAaf3/QIwSmcP3FSpg17Ry+3GdhPgu9uabokAIANEITgNCJXrpZV303Ty33fGaZ7iQAAyEsEITiVn8dNkCM7dulDZAM+HCWe3l6mSwIAuDGCEJxKSnKyfPfymxIfEyt3htSVB/75jOmSAABujCAEp3Mu6oRMG/auXm77xACp1aq56ZIAAG6KIASntHPFKln9w096ud97b0nR0qVMlwQAcEMEITit+R99Jkcjd4t/0SIy4APGCwEAHI8gBKeVkpQk3w0ZJvGxl6RygxC5b/DfTZcEAHAzBCE4tbPHouSnEaP1crunBkqNFk1NlwQAcCMEITi97UtWyNppM/Vy//feksBSJU2XBABwEwQhuAR1yY2o3XulcPFiMmDMSPH0YrwQAOD2EYTgEpITE2XKkDfkyuXLUqVRfekQ9qTpkgAAboAgBJdx5sgxmT7ifb3c7qlHpXqzxqZLAgC4OIIQXMrvi5bJ+ulzxNPTU/qPHiEBQSVMlwQAcGEEIbicOWM+keN79klAieLy8PsjxMOTX2MAwK3hEwQuJzkhQaYMeVMS4uKkWpNG0v7px02XBABwUQQhuKTTh47IjFFj9HL7Z56QqqENTZcEAHBBBCG4rC0/L5ENM+fp8UIPjxmpD5UBAJAbBCG4tNnvj5MT+w5IYFAJ6c94IQBALvGpAZeWdCVBprz0hiTExUv1po2l3aBHTZcEAHAhBCG4vFMHD8usd8fq5Y7/eFL+1qi+6ZIAAC6CIAS3sGneL7Jx7s/60hvqEhzqUhwAANwMQQhuQ/UKnTxwUIqUKqkvzurh4WG6JACAkyMIwW0kxl+R74a8qb/WaNFU2j7xiOmSAABOjiAEt3Jy/58y+72P9PJ9zw6Syg1CTJcEAHBiBCG4nYg5C2TT/IXi5e0tAz4YJf5Fi5guCQDgpAhCcEsz3/5QzyYrWrqU9GO8EAAgGwQhuKXE+HiZMuQNfZ6hWq2aS73725suCQDghAhCcFsn9h6QFV9N0cst+/c0XQ4AwAkRhODW1k+fI8lJSXJnSF0pX6u66XIAAE6GIAS3Fnv2nGxfulIvt+hLrxAAIDOCENze2qkz9dcGD3SQgoGBpssBADgRghDc3qHft0vU7r3iU8BPmnR70HQ5AAAnQhCCLaydNkN/bdanG1PpAQDpCEKwhS2/LJG4mBgJqlhBarRsarocAICTIAjBFtT5hDbO+Vkvt+jbw3Q5AAAnQRCCbaydNkt/rdmymZSoUN50OQAAJ0AQgm2cPXpMdq9ZL56entK8T3fT5QAAnABBCLacSh/a7UE9iwwAYG9uH4QqVKggK1eulMjISNm2bZv07MlJ9ezsjzXr5eyx41KoSKDUv7+D6XIAAIa5fRBKTk6W559/XoKDg6VDhw7yySefSKFChUyXBUOs1FRZ9+NfY4UYNA0AcPsgdPLkSd0TpERHR8uZM2ekePHipsuCQRGz5+tZZBVq15BKIXVMlwMAsHMQatWqlcybN0+ioqLEsizp0qXLdeuEhYXJwYMHJT4+XsLDw6Vx48a39FwNGjQQLy8vOXbsmAMqh6uKuxgjWxct1cv0CgGAvRkPQv7+/rrHZvDgwVl+v3fv3jJu3DgZOXKkDjJq3cWLF0vJkiXT19m6davs2LHjula2bNn0dYoVKyZTpkyRv//97zesx9fXVwICAjI1uJ+1U/8603RIx3ZSuEQx0+UAAAyynKUpXbp0yXRfeHi4NX78+PTbHh4e1rFjx6yhQ4fmeLu+vr7WqlWrrAEDBtx03eHDh1tZCQgIMP7+0Bzbnvv+S+ujHeutdoMeNV4LjUaj0cShTX1u5+Tz23iP0I34+PhIw4YNZdmyZen3qcNn6nazZs1yvJ1vvvlGVqxYId9///1N1x09erQEBgamt/LlOfGeu1o77a+p9M17dxNPLy/T5QAADHDqIBQUFCTe3t56kHNG6naZMmVytI0WLVpInz59pGvXrvoQmmp16mQ/QDYxMVFiY2MzNbinbUtWyKVz56VomdJSu01L0+UAAAzwFje3du1aPUAauFZyYqKEz5wn9w56VFr26yk7V6wyXRIAIJ85dY+QmuquzgNUunTpTPer22paPHC71v80W1JTUqRa00ZSqnIl0+UAAPKZUwehpKQk2bx5s7Rr1y79Pg8PD317/fr1RmuDe7hwMlp2rVqjl5lKDwD24xTT50NCQnRTKleurJcrVqyob6up84MGDZKBAwdKzZo15fPPP9ePmTx5suHK4W6Dpht1fkD8OOs4ANiO0eltbdq0yXK6+uTJk9PXGTx4sHXo0CHrypUrejp9aGhontcVFhZmRUZGWrt372b6vJs3dUqGofOm6an0zft0N14PjUaj0STfps97XF1ANtQJFWNiYvRUemaQua+W/XtJt9delJP7/5QPuz1suhwAQD59fhs/NAY4g03zfpGEuDgpU/VvUqVRfdPlAADyCUEIEJErly7L5gWL9XKLfj1NlwMAyCcEIeCaQdN17mktRUr/71p2AAD3RRACrjq574Ac2LRVvLy9pWnPrqbLAQDkA4IQkEWvUNOeXXQgAgC4N4IQkMGO5b/KxVOnJTCohNzVvq3pcgAAeYwglI2wsDCJjIyUiIgI06UgH6Ump0j49Dl6mTNNA4D74zxCN8F5hOwnIKiEDFsyR7x8vGVsj0fkxN79pksCAOQS5xECblHsmbP6EJnSoh+9QgDgzghCQBbWTJ2hvzbsdJ8UDAwwXQ4AII8QhIAsHNyyTY7v3S++BQtI4y6dTJcDAMgjBCHgJlPpm/fpLh4eajgdAMDdODwI9ejBmAq4hy0LFkt87CUpWamiVG/exHQ5AABnCEJeXl4SHBws1apVy3R/586d5ffff5cffvjBkfUBxiTGx8vGOT/rZabSA4B7ylUQUgFo//79sm3bNtm9e7fMnDlTSpUqJb/++qt8/fXXsnDhQqlSpUreVQvks7U//nV4rFbr5lK8fFnT5QAATAahMWPG6CDUpUsXmTZtmnTt2lWHoPnz50uFChXktddek6ioKHEHnFARypnDR2XPug3i6ekpzXp3M10OACAPWDlt0dHRVkhIiF4ODAy0UlJSrAEDBuT48a7YAgICLEV9NV0LzUwLvrul9dGO9dao1Yssbz8/4/XQaDQaTRz2+Z2rHqGgoCA5fvy4XlZna7x8+bKEh4fnRTgDnMau39bJuagT4l+0iNS/r53pcgAADpSrIGRZlj5ltWrqlNXqdsGCBdPvS2uAO7FSU2X99Nl6uTmDpgHAvkFInUtl7969cv78eTl37pwULlxYtm7dqm+rduHCBf0VcDcbZs2X5MREuaNObalYp7bpcgAADuKdm5Xbtm3rqOcFXMrl8xdk68Jl0rjLA9KyX0+Z+sYo0yUBAByAq8/fBFefRxrVE/T81K90z9Coe7vocAQAsNHV53v16iU+Pj7pt8uXL5/p0gNqvNDLL798qzUDTu3ozl1yZOcu8fb1lSbdHzJdDgDAAXIVhKZOnSpFixZNv71r1y658847M6Wv0aNHO6IuwCmtu3r9MXVOIQ9PLtUHALYbLH2j24C727pouT4kVrxcWandpoXpcgAAt4l/abPBmaWRleSEBNkwe75e5vpjAOD6CELZmDhxor62WmhoqOlS4GTW/zRbUlNTpUbzJlLyzjtMlwMAyK/p80rHjh3l4sWLelldf6ldu3YSHR2tb2ccPwS4K3WW6d2r1kpw21bSvE93mTvmE9MlAQDyY/p8SkrKTddRZ5v29s51vnJaTJ9HVlRv0N8nfSLxsZdkVLvOkhgfb7okAEBeT5/38vK6aXOnEARkZ+/6CDl9+KgUDCgsDR7saLocAEB+jhEqXrx4+nKFChVk5MiRMmbMGGnZsuWt1gG4FNXzue7HWXqZQdMAYJMgVKdOHTl48KCcOnVKdu/eLSEhIbJx40Z54YUX5Omnn5aVK1dKly5d8q5awIlsnPuzJMTFS7nqVeVvDeuZLgcAkNdB6IMPPpAdO3ZI69at5ddff5UFCxbIzz//LEWKFJFixYrJpEmT5NVXX72VOgCXEx8TK1t+WayX6RUCANdl5bSdPn3aqlu3rl729/e3UlJSrAYNGqR/v0aNGtb58+dzvD1XaAEBAZaivpquheZ8rWz1qtZHO9ZbH2xZbQWWDDJeD41Go9EkV5/fnrkdG3Ty5Em9fPnyZd3Onz+f/n21rEZpA3ZxYu9+Obhlm3j5eEvTnhwWBgC3HyytBone6DZgN2umztBfVRDy9PYyXQ4AIBdyPdf9m2++kYSEBL1coEAB+eKLL3TPkOLn55fbzQEub8eyXyXmzFkpUqqk1G13t2xbvNx0SQCAvOgR+vbbb/WMMXVmadW+//57OX78ePpt9b0pU6aIO+BaY8iplORkCZ8xVy8zaBoA3PjM0nbEmaWRE4GlSsqbi2eJl7e3fNh9gJzcd8B0SQBgawF5cWZpAFmLOXVadq74TS/TKwQAroMgBDjI2quDphs+2FEKFPY3XQ4AIAcIQoCDHNi0VU7sOyB+hQpJo84PmC4HAJADBCHAgdZOm5l+eMzDQw3BAwA4M4IQ4EBbFiyWK5cuS6nKlaRa00amywEA3ARBCHCghLg42TTvF73MoGkAcH4EISCPDo/VbtNSipUtY7ocAMANEIQABzt18LDsDd8onl5e0qx3N9PlAABugCAE5IG1U//qFWrS/SHx9vU1XQ4AIBsEISAP7Fq1Rs6fOCmFixeTkA73mC4HAJANghCQB1JTUmT99Dl6uUW/nqbLAQBkgyAE5JENM+dJcmKiVLorWCrUrmm6HABAFghCQB65dO68bFuyQi+36MdUegBwRgShbISFhUlkZKRERESYLgVuMJW+/v3tpVCRQNPlAACuQRDKxsSJEyU4OFhCQ0NNlwIXdnjbTjm66w/x8fPTM8gAAM6FIATksXVXp9I3691dPDzZ5QDAmfBXGchjWxctlbiLMVKiQjmp2bKZ6XIAABkQhIA8lnQlQSJmL9DLLZlKDwBOhSAE5IN1P86S1NRUqdmyqQTdUcF0OQCAqwhCQD44eyxK/lizXi8379PddDkAgKsIQkA+T6Vv3LWT+BYsYLocAABBCMg/e9aEy5mjx6RQYKDUf6CD6XIAAAQhIP9YliXrps3Syy36cqZpAHAGBCEgH0XM+VnPIitfs7rcWe8u0+UAgO0RhIB8FB8TI1t+WaKXuf4YAJhHEALy2dppM/TXu9q3lYASxU2XAwC2RhAC8lnU7r1y6Pcd4u3jI016djFdDgDYGkEIMNgr1KxXV/H09jJdDgDYFkEIMGDbkpUSe/acFC1dSuq0bW26HACwLYIQYEBKUpKEz5yrl5lKDwDmEIQAQ8J/miOpKSlSNbShlK5S2XQ5AGBLBCHAkAvRp2TnytV6mV4hADCDIJSNsLAwiYyMlIiICNOlwI2tu3r9sYYP3Sd+/oVMlwMAtkMQysbEiRMlODhYQkNDTZcCN7ZvwyaJ/vOQFPD3l0adHzBdDgDYDkEIcJKr0jfv0910KQBgOwQhwLBN836RK5cvS5kqlfXAaQBA/iEIAYYlXI6TzfMX6eUW/XqaLgcAbIUgBDjR4bE6bVvpkywCAPIHQQhwAtEHDsr+iM3i6eUlTXt3NV0OANgGQQhwsl6hpj26iJePj+lyAMAWCEKAk9i58jd9ksWAEsUlpENb0+UAgC0QhAAnkZqcIuunz9HLLfoyaBoA8gNBCHAiG2bMleSkJLmzXl0pX6u66XIAwO0RhAAnEnv2nOxYulIv0ysEAHmPIAQ4mTVT/xo03eCBDlIwMNB0OQDg1ghCgJM59Pt2ifpjr/gU8JPQrp1MlwMAbo0gBDjz9cf6dhcPDw/T5QCA2yIIAU5o6y9LJD4mVoIqVpAaLZuaLgcA3BZBCHBCifFXJGLOAr3com8P0+UAgNsiCAFOat2Ps/TXmi2bSYkK5U2XAwBuiSAEOKkzR47JH2vCxdPTU5r36W66HABwSwQhwImtmTpDfw3t9qCeRQYAcCyCEODE/lizXs4eOy6FigRK/fvamy4HANwOQQhwYlZqqqz/6a+xQi36caZpAHA0ghDg5CJmL5CkhASpULuGVAqpY7ocAHArBCHAyV2+cFG2Llyql5lKDwCORRACXMDaq9cfC+lwjxQuXsx0OQDgNghCgAs4tusPObw9Urx9faVJ986mywEAt0EQAlzt+mN9uomnl5fpcgDALRCEshEWFiaRkZESERFhuhRA27Z4uVw6d16Klikttdu0NF0OALgFglA2Jk6cKMHBwRIaGmq6FEBLTkyUDbPm6+UW/Rg0DQCOQBACXMj6n2ZLakqKVG/aWEpVrmS6HABweQQhwIWcP3FSdv22Vi8zlR4Abh9BCHAxa69ef6xR5wfEr1Ah0+UAgEsjCAEuZl/4Jjl18LAUKOwvDR7saLocAHBpBCHAxViWJet+/Ov6Yy25/hgA3BaCEOCCNs77RRLi4qRM1b9JlUb1TZcDAC6LIAS4oCuxl2TzgsV6mavSA8CtIwgBLn6m6Tr3tJbAUiVNlwMALokgBLiok/sOyIHNW8XL21ua9epquhwAcEkEIcANrkrftGcXHYgAALlDEAJc2I7lv8rFU6clMKiE1L33btPlAIDLIQgBLiw1OUXCZ8zVy0ylB4DcIwgBLk4FoZSkZKncIETKVq9quhwAcCkEIcDFxZw+ow+RKVyVHgByhyAEuNFU+gYPdJSCgQGmywEAl0EQAtzAn5t/lxP7DohfoYLSuEsn0+UAgMsgCAFuYs3Vq9I379NdPDw8TJcDAC6BIAS4iS0LFkt87CUpWamiVG8WarocAHAJBCHATSTGx8vGuT/r5RZ9GTQNADlBEALcyLofZ+mvtdq0kOLly5ouBwCcHkEIcCOnDx2RPes2iKenpzTr3c10OQDg9AhCgJtOpW/S7SHx9vMzXQ4AODWCEOBmdq1aK+eOnxD/YkWl/n3tTJcDAE6NIAS4GSs1Vdb/NEcvN2fQNADcEEEIcEMbZs2T5MREuaNObalYp7bpcgDAaRGEADd0+fwF+X3Rcr3MVHoAyB5BCHBTa6f9dabp+vffq8cLAQCuRxAC3NSRHbvkyM5d4u3rK026P2S6HABwSgQhwI2tuzqVvlmvbuLhye4OANfiLyPgxrYuWi6XL1zUZ5mu3bq56XIAwOkQhAA3lpyQIBGz5uvlFv16mi4HAJwOQQhwc+t+miWpqalSo3kTCapU0XQ5AOBUCEKAmzsXdUJ2/7ZOL7fow1R6AMiIIATY6Ppjjbt2Et+CBU2XAwBOgyAE2MDedRvk9OGjUjCgsDR4sKPpcgDAaRCEABuwLEvW/ThLL3OmaQD4H4IQYBMb5/4sifFXpFz1qlK5QYjpcgDAKRCEAJuIj4mVLT8v1sstmUoPABpBCLDhoOm67e6WgKASpssBAOPcPggVKVJENm7cKFu3bpUdO3bIU089ZbokwJjje/bJwS3bxMvHW5r17GK6HAAwzu2DUGxsrLRu3Vrq168vTZo0kddff12KFy9uuizAeK9Q015dxdPby3Q5AGCU2wchdUbd+Ph4vezn5yceHh66AXa1felKiTlzVoqUKqkPkQGAnRkPQq1atZJ58+ZJVFSUnuLbpcv13fVhYWFy8OBBHWjCw8OlcePGuT489vvvv8uxY8fkww8/lLNnzzrwFQCuJSU5WcJnzNXLTKUHYHfGg5C/v79s27ZNBg8enOX3e/fuLePGjZORI0dKgwYN9LqLFy+WkiVLpq+TNv7n2la2bFn9/YsXL0q9evWkcuXK0r9/fylVqlS29fj6+kpAQECmBrib9dPn6EBUpVF9KVOtiulyAMAoy1ma0qVLl0z3hYeHW+PHj0+/7eHhYR07dswaOnToLT3HhAkTrB49emT7/eHDh1tZCQgIMP7+0GiObAM/etf6aMd6q8ewV4zXQqPRaOLgpj63c/L5bbxH6EZ8fHykYcOGsmzZsvT71OEzdbtZs2Y52obq/SlcuLBeDgwM1AOn9+zZk+36o0eP1uultfLlyzvglQDOO2i64YMdpUBhf9PlAIARTh2EgoKCxNvbW6KjozPdr26XKVMmR9uoVKmSrF69Wo8RUl/Hjx8vO3fuzHb9xMREPdMsYwPc0YGNW+Tk/j/Fr1AhadT5AdPlAIAR3uLm1DmE1NR5AFn3CvV482U9aHrt1Bm6xxUA7MSpe4TOnDkjycnJUrp06Uz3q9snT540VhfgLjbPXyRXLl2WUpUrSbWmjUyXAwD5zqmDUFJSkmzevFnatWuXfp86B5C6vX79eqO1Ae4gIS5ONs1fqJeZSg/Ajpxi+nxISIhuiprirpYrVqyob6up84MGDZKBAwdKzZo15fPPP9ePmTx5suHKAfegDokptdu0lKJlMve+AoAdGJ3e1qZNmyynq0+ePDl9ncGDB1uHDh2yrly5oqfTh4aG5nldYWFhVmRkpLV7926mz9Pcvj3z5Xg9lf7+554xXguNRqNJPk6f97i6gGyoEyrGxMToqfTMIIO7qtuujTz2yfty6dx5ebt9V0lOTDRdEgDky+e38UNjAMyL/HWNXDgZLYWLF5OQDveYLgcA8g1BCICkpqTIup9m62UGTQOwE4IQAG3DrHmSnJQklULqSIXaNU2XAwD5giAEQLt09rxsX7JCL7foR68QAHsgCAFIt+bqVPr697WXQkUCTZcDAHmOIAQg3eFtO+XYrj3iU8BPQrs9ZLocAMhzBKFshIWFSWRkpERERJguBTByVfrmfbqLhyd/IgC4N/7KZWPixIkSHBwsoaGhpksB8tXWhUsk7mKMlKhQTmq2bGa6HADIUwQhAJkkXUmQiNkL9DKDpgG4O4IQgOus+3GWpKamSq2WzaRExQqmywGAPEMQAnCds8eiZM/acL3com930+UAQJ4hCAG44VT6xl076VlkAOCOCEIAsrRnTbicOXpMCgUGSoMHOpguBwDyBEEIQJYsy5L1P169/li/nqbLAYA8QRACkK0NsxfoWWTla1aXO+vdZbocAHA4glA2OKEiIBIfEyNbflmil5lKD8AdeagecNNFOLOAgACJiYmRwMBAiY2NNV0OkO/K16ouL/70rb4y/Tvtu0rs2XOmSwIAh31+0yME4Iaidu+VQ9t2iLePjzTp2cV0OQDgUAQhADm+/lizXl3F08vLdDkA4DAEIQA3tW3xCn1IrGjpUhLctpXpcgDAYQhCAG4qJSlJNsycp5db9GXQNAD3QRACkCPrp8+R1JQUqdakkZSuUtl0OQDgEAQhADly4WS0RP66Ri/TKwTAXRCEAOTY2qvXH2v40H3i51/IdDkAcNsIQgBybN+GTRL95yEp4O8vjTo/YLocALhtBKFscGZpIGvrfvxrKn3zPt1NlwIAt40glI2JEydKcHCwhIaGmi4FcCob5/4iVy5fljJVKkvV0IamywGA20IQApArCZfjZPP8RXqZQdMAXB1BCMAtn2m6zj2t9UkWAcBVEYQA5Fr0gYOyf+MWfbmNpr27mi4HAG4ZQQjAbU2lb9qji3j5+JguBwBuCUEIwC3ZufI3uRh9WgJKFJe72rc1XQ4A3BKCEIBbkpqcIutnzNHLLfv1NF0OANwSghCAWxY+Y66kJCXLnfXqSvma1U2XAwC5RhACcMtiz5yV7UtX6GWm0gNwRQQhAA6ZSl//gQ5SMDDQdDkAkCsEIQC35eDW7XJ8zz7xLVhAGj7YwXQ5AJArBKFscK0xIOf2hm/UX4twckUALoYglA2uNQbkgmW6AAC4NQQhAA7jIR6mSwCAXCEIAQAA2yIIAbhtlsWxMQCuiSAEwHE8ODQGwLUQhAAAgG0RhADcPg6NAXBRBCEADuPBoTEALoYgBAAAbIsgBAAAbIsgBOC2WWmnlubIGAAXQxACAAC2RRACAAC2RRAC4LDp88waA+BqCELZCAsLk8jISImIiDBdCgAAyCPeebVhVzdx4kTdAgICJCYmRn8FkLWCfgXE19NLChYowL4CwCnk9G+R6sfmlLA3UK5cOYmKijJdBgAAuAXly5eX48ePZ/t9glAO7NmzRxo1apTj9dXhtNDQ0JsmVRWw1A8oNjbWAVW6vpy8b3aqL6+ez1HbvZ3t3Mpjc/OYnK7LfpgZ+2D+PJ8d9kFn+SxU279RCFI4NJYDycnJufoBpaam5nh9tR5/gHP/vtmhvrx6Pkdt93a2cyuPzc1jcrt99sO/sA/mz/PZYR90ls/CnGyTwdI5MGHChDxdH67xvuV3fXn1fI7a7u1s51Yem5vHOPvvkrNy9veNfdB19kFX+H1Kw6ExQ9IGYQcGBjr1f2CAO2M/BMxyhn2QHiFDEhISZMSIEforADPYDwGznGEfpEcIAADYFj1CAADAtghCAADAtghCAADAtghChlmWJV26dDFdBoCrKlWqpPfLkJAQ06UAttWmTRu9HxYpUiTPn4sglAcXaz148KDEx8dLeHi4NG7cOFePVz/4tJaUlCSHDx+Wjz76SHx9ffOsZsBVtWrVSubNm6fPTJvdPxUjR47UZ5aNi4uTpUuXStWqVW8pGKU1Nbtl37598sYbbzjwlQCu6dVXX9VnkFZT4KOjo2X27NlSvXr1TOv4+fnJZ599JmfOnNFT5GfMmCGlSpW6pWCU1tT+vHPnThk0aNBtvwaCkAP17t1bxo0bp//wNmjQQLZt2yaLFy+WkiVL5mo7jz32mJQpU0YqV66sg9Ujjzwib775Zp7VDbgqf39/vZ8NHjw4y++/8sor8txzz8kzzzwjTZo0kcuXL+t9Uv1hzq127drp/bJatWoyfPhwHYSeeOIJB7wKwHW1adNGnzixadOm0r59e/Hx8ZElS5ZIoUKF0tf5+OOP5aGHHpJevXrp9dU1PGfNmnVLz6dCltoPa9euLZMmTZLPP/9c7rnnntt+HWr6PM0BLTw83Bo/fnz6bQ8PD+vYsWPW0KFD9e2qVataq1atsuLj463IyEjr3nvvtZQuXbqkP+ba26p9+eWX1oIFC4y/PhrNmVtW+87x48etl156Kf12YGCg3v/69OmTfl/jxo2tLVu26Ps3btxode3aVW8rJCREf79SpUqZbqe1pUuXWp999pnx102jOVMLCgrS+0urVq3S97mEhASrR48e6evUqFFDr9OkSZP0++6//35rz549VlxcnLVixQrr0Ucf1esUKVJEf79NmzaZbqe1ffv2WUOGDLmtmukRchCVghs2bCjLli1Lv09136nbzZo1Ew8PD52AExMT9X+m6j/UMWPG3HS76r9PlXY3bNiQx68AcC+qR7Vs2bKZ9knVfa/2JbVPpvUoLViwQHbt2qX3X3Vit7Fjx95022pd1dgvgczSxvScO3dOf1X7iRrakXE/VBcyV8M+0vbDChUq6M/H+fPnS7169eQ///mPvP/++3IzHTt2lDvuuOO290MuuuogQUFB4u3trY+RZqRu16xZU+699179Vf3gTpw4ob/3+uuvy6JFi67b1tSpUyUlJUVvr0CBAvqXY/To0fn2WgB3oLrPlaz2ybTv9e/fXzw9PeXJJ5/UY39UIFJ/lL/44ovrtrdu3Tp9EUn1R1011S3/3Xff5dOrAZyfh4eHfPLJJ7JmzRqJjIzU96l9Te1bFy9ezHY//Mc//iEHDhyQIUOG6Nt79+6VunXr6vFH1zp27Jj+qg5vq333rbfektWrV99W3QShfFKrVi05evRoeghS1q9fn+W6L7zwgk7PXl5eemCnGnek/uD269cvHysG7LFfbt++PdPp/bPbL/v06SO7d+/Wvb916tSR8ePHy/nz5+W1117Lx4oB5zVhwgS9b7Rs2TLX++G1vTrZ7YdqgoQacK2CUGhoqB6ErXqfsvrnJacIQg6iRsMnJydL6dKlM92vbp88eTJX21Lrq3SclozVRemmTZumB0yn3Q/gxtL2u2v3QXX7999/z/X21D8yafvfH3/8IVWqVJG3337b+HWSAGcwfvx4efDBB6V169Z6Fmcate+p0KIOmWXsFbqVz0ZFzcpO247qwVVDTdTEhdsJQowRchA11X3z5s16ZknGbkJ1WyVb9Z9kxYoV07sCFTXKPifUYTKlYMGCeVA54J7UH0zVA5txn1T/VKg/nGn/bar98q677so0iyw3+6XqHeLUFrC78ePHS7du3fR41kOHDmX6nvpcVGNjM+6HauaXOi1Fxv1Q9e5klJv90BGfjcZHmbtL6927t555MnDgQKtmzZrWF198YZ07d84qVaqUnkG2c+dOa/HixdZdd91ltWzZUs9QyWrWmBotX7p0aats2bJW69atre3bt1t//PGH5eXlZfw10mjO1Pz9/fVsLtWU559/Xi9XrFhRf/+VV17R++BDDz1k1alTx5o9e7Z14MABy8/PL/3xp06dsqZMmWLVqlVLz1zZu3dvlrPG7rnnHr1fli9f3rrvvvuso0ePWsuXLzf+HtBoJtuECROs8+fP688qtX+ktQIFCqSvM3HiROvQoUPW3XffbTVo0MBau3atbmnfV/vrlStXrA8++MCqXr261a9fPz3jM6tZY9WqVdPbv+OOO6yePXtaFy9etL766qvbfR3m30h3aoMHD9Y/cPVDVdPpQ0ND07+nfoC//fab/p4KNh06dMgyCKVJSUmxoqKirKlTp1qVK1c2/tpoNGdraX8crzV58uT0dUaOHGmdOHFC/5Oipryr/TDjNtQU3q1bt+r9Uk2j79atW5ZBKE1SUpJ15MgRa9KkSXqqsOn3gEYz2bKj/qFPW0f946FONXH27Fnr0qVL1syZM3WYybidTp066X9C1H6qTjPz2GOPZRmE0iQmJup/alR4KlSo0G29Bo+rCwAAALbDGCEAAGBbBCEAAGBbBCEAAGBbBCEAAGBbBCEAAGBbBCEAAGBbBCEAAGBbBCEAAGBbBCEAAGBbBCEAbiMoKEgmTpwohw8flitXruiLri5atEiaN2+efiFWy7L0hVcz+vjjj2XlypXpt4cPH67XUy05OVmOHDkikyZNkmLFiuX7awKQt7zzePsAkG9mzpyprwb/6KOPyp9//imlS5fWV70uUaJE+jrx8fEyZswYufvuu2+4rZ07d8q9994rXl5eUqtWLfn666+lSJEi0rdv33x4JQDyC0EIgFtQIaV169bSpk0b+e233/R9qidn48aNmdb797//Lc8884zcf//9snDhwmy3p3qCoqOj9fLx48dl+vTp8vjjj+fxqwCQ3zg0BsAtXLp0SWJjY6Vr1666Vyg76vDYF198IaNHjxYPD3Xd6ZurVKmSdOzYURITEx1YMQBnQBAC4BZSUlLkscce04fFLly4IGvWrJF3331X6tate92677zzjlSuXFkefvjhbLenHqeCVVxcnBw6dEjq1KmjD6kBcC8EIQBuY9asWVKuXDnp3LmzHiStxgFt2bJFh6OMzpw5I2PHjpVRo0aJj49Pltvas2eP1KtXTxo3bizvv/++3t748ePz6ZUAyC8EIQBuJSEhQZYtW6Z7fVq0aCHffPONjBw58rr1xo0bJwULFpSwsLAst6MOgx04cEAiIyPltdde0z1OajYZAPdCEALg1nbt2iX+/v7X3X/58mV5++235Y033pCAgICbbkcFqyFDhkjZsmXzqFIAJhCEALiF4sWLy/Lly/W4HzW+584775SePXvKK6+8InPnzs3yMWoG2cWLF6V///433X54eLhs375dXn/99TyoHoApBCEAbjNrbMOGDfLCCy/o6fPqPECqx+fLL7+UZ599Ntsp8sOGDdOHyHJCnXjxqaeekgoVKji4egCmqLmjlrFnBwAAMIgeIQAAYFsEIQAAYFsEIQAAYFsEIQAAYFsEIQAAYFsEIQAAYFsEIQAAYFsEIQAAYFsEIQAAYFsEIQAAYFsEIQAAIHb1/+RXjLf0SFoMAAAAAElFTkSuQmCC", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "_ = result.plot()" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3.9.12 ('hermes')", "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.11.8" }, "vscode": { "interpreter": { "hash": "15324ae639e283979e39f32b76ef84dde816ef5cb4e81fc04e688fd3d2128060" } } }, "nbformat": 4, "nbformat_minor": 5 }