diff --git a/esp32/neural_network.ipynb b/esp32/neural_network.ipynb new file mode 100644 index 0000000..5b76b24 --- /dev/null +++ b/esp32/neural_network.ipynb @@ -0,0 +1,231 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 46, + "metadata": {}, + "outputs": [], + "source": [ + "import torch\n", + "import torch.nn as nn\n", + "import torch.onnx\n", + "import tensorflow as tf\n", + "import onnx\n", + "from onnx_tf.backend import prepare\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": {}, + "outputs": [], + "source": [ + "# Generate data\n", + "x = np.linspace(-2 * np.pi, 2 * np.pi, 1000)\n", + "y = np.sin(x)\n", + "\n", + "# Convert to tensors\n", + "x_train = torch.tensor(x, dtype=torch.float32).view(-1, 1)\n", + "y_train = torch.tensor(y, dtype=torch.float32).view(-1, 1)\n", + "\n", + "# Define the model\n", + "model = nn.Sequential(\n", + " nn.Linear(1, 50),\n", + " nn.ReLU(),\n", + " nn.Linear(50, 1)\n", + ")\n", + "\n", + "# Loss and optimizer\n", + "criterion = nn.MSELoss()\n", + "optimizer = torch.optim.Adam(model.parameters(), lr=0.01)" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": {}, + "outputs": [], + "source": [ + "# Training loop\n", + "for epoch in range(1000):\n", + " optimizer.zero_grad()\n", + " output = model(x_train)\n", + " loss = criterion(output, y_train)\n", + " loss.backward()\n", + " optimizer.step()" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAi8AAAGdCAYAAADaPpOnAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/P9b71AAAACXBIWXMAAA9hAAAPYQGoP6dpAAB0y0lEQVR4nO3deXyU5bn/8c8zM9n3hOx7whqWEAKEAAooilat1qVat2o9Wq22tdp6pOdXtZucLrY9tVatVqVVq7buoiiiCEjYAoGQhCV7yEYSsq+Tmef3xzMJiUDINvPMJNf79cqLZGaS+RIluea5r/u+FFVVVYQQQgghXIRB7wBCCCGEECMhxYsQQgghXIoUL0IIIYRwKVK8CCGEEMKlSPEihBBCCJcixYsQQgghXIoUL0IIIYRwKVK8CCGEEMKlmPQOMN6sVitVVVX4+fmhKIrecYQQQggxDKqq0traSlRUFAbD0NdWJlzxUlVVRWxsrN4xhBBCCDEKFRUVxMTEDPmYCVe8+Pn5Adpf3t/fX+c0QgghhBiOlpYWYmNj+3+PD2XCFS99S0X+/v5SvAghhBAuZjgtH9KwK4QQQgiXIsWLEEIIIVyKFC9CCCGEcCkTrudFCCHExKSqKr29vVgsFr2jiFFyc3PDaDSO+etI8SKEEMLp9fT0UF1dTUdHh95RxBgoikJMTAy+vr5j+jpSvAghhHBqVquVkpISjEYjUVFRuLu7yyGkLkhVVerq6jh+/DjTpk0b0xUYKV6EEEI4tZ6eHqxWK7GxsXh7e+sdR4xBaGgopaWlmM3mMRUv0rArhBDCJZzryHjh/Mbripn8nyCEEEIIlyLFixBCCCFcihQvQgghhHApUrwIIYQQ40xRlCHfHnvsMb0jujTZbSSGp7MR9jwPiSsgdrHeaYQQwqlVV1f3v//666/zyCOPcOTIkf7bBp5zoqoqFosFk0l+JQ+XXHkRw/Px/8Bnv4KXLofuVr3TCCEmOVVV6ejpdfibqqrDyhcREdH/FhAQgKIo/R8fPnwYPz8/PvroI9LT0/Hw8GD79u3cdtttXHXVVYO+zv3338/KlSv7P7Zaraxbt47ExES8vLxITU3lP//5zzh+Z12DlHni3Fpr4OAb2vuWbijdDjMu1TeTEGJS6zRbSHnkY4c/b/4v1uDtPj6/Oh9++GF+//vfk5SURFBQ0LA+Z926dbz88ss888wzTJs2ja1bt3LzzTcTGhrKihUrxiWXK5DiRZzb7r+B1Xzq46LPpXgRQogx+sUvfsFFF1007Md3d3fz+OOP8+mnn5KZmQlAUlIS27dv59lnn5XiRYh+Pe2w5+/a+/NugIOvQdFn+mYSQkx6Xm5G8n+xRpfnHS8LFy4c0eMLCwvp6Og4reDp6ekhLS1t3HK5AilexNByXoWuJghKhEvWQe6/oeEYNJVDYJze6YQQk5SiKOO2fKMXHx+fQR8bDIbTemrM5lNXvdva2gDYsGED0dHRgx7n4eFhp5TOybX/ywv7slog6ynt/cx7wTsYYhZCxS5t6Sj92/rmE0KICSQ0NJRDhw4Nui0nJwc3NzcAUlJS8PDwoLy8fFItEZ2J7DYSZ3d4AzSWgGcgzL9Ruy1plfanLB0JIcS4uuCCC9i7dy//+Mc/OHbsGI8++uigYsbPz48f//jH/OhHP2L9+vUUFRWxb98+nnzySdavX69jcseT4kWcXdZftD8X3QHutsubyRdofxZv0a7MCCGEGBdr1qzhZz/7GQ899BCLFi2itbWVW2+9ddBjfvnLX/Kzn/2MdevWMWvWLC655BI2bNhAYmKiTqn1oajD3bTuIlpaWggICKC5uRl/f3+947iuij3w99VgdIf7c8EvQrvd0gu/TYTuFrjzM4hO1zenEGLC6+rqoqSkhMTERDw9PfWOI8ZgqP+WI/n9LVdexJllPan9OfebpwoXAKMJEs/X3pelIyGEEDqQ4kWcrrEUCt7X3s+89/T7+5aOij53WCQhhBCijxQv4nQ7nwbVCskXQnjK6fcn25p2K3bJqAAhhBAOJ8WLGKyzEfb9U3t/6X1nfkxwEgQlgLVXGxUghBBCOJAUL2KwvS+CuR3C55zaFn0msnQkhBBCJ1K8iFN6e7Q5RgCZ94GinP2x/cWLNO0KIYRwLClexCmH3oTWavCLhDnXDP3YhPNAMZ4aFSCEEEI4iBQvQqOqpw6lW3wXmNyHfrxXoDYqAGTpSAghhENJ8SI0xVug9hC4+cDC24f3OTIqQAghnMJtt93GVVdd1f/xypUruf/++x2eY8uWLSiKQlNTk12fx67Fy9atW7niiiuIiopCURTeeeedc37Oli1bWLBgAR4eHkydOpWXXnrJnhFFnx22Q+nSbgavoOF9jowKEEKIId12220oioKiKLi7uzN16lR+8Ytf0Nvba9fnfeutt/jlL385rMc6quAYT3YtXtrb20lNTeWpp54a1uNLSkq47LLLWLVqFTk5Odx///3813/9Fx9//LE9Y4rafCjaDIoBltwz/M+LTgcPf+hqguoce6UTQgiXdskll1BdXc2xY8d48MEHeeyxx/jd73532uN6enrG7TmDg4Px8/Mbt6/nbOxavFx66aX86le/4hvf+MawHv/MM8+QmJjIE088waxZs7jvvvu49tpr+eMf/2jPmCJLKy57Z1xOk2c0Fuswx13JqAAhxlWvxUpzh5nOHrmSOZF4eHgQERFBfHw899xzD6tXr+a9997rX+r59a9/TVRUFDNmzACgoqKCb37zmwQGBhIcHMyVV15JaWlp/9ezWCw88MADBAYGEhISwkMPPcRXxxR+ddmou7ub//7v/yY2NrZ/ZePvf/87paWlrFqltQAEBQWhKAq33XYbAFarlXXr1pGYmIiXlxepqan85z//GfQ8H374IdOnT8fLy4tVq1YNymlPJoc8yzBlZWWxevXqQbetWbNmyHW77u5uuru7+z9uaWmxV7wJx2pV2bY/j6UHXscNuO5AOvtzNuFuNDA9wpcLZ4Zzw+JYIgO8zv5Fki+Awx9oTbvn/8Rh2YWYKCpOdvDvvRV8WnCCYydaMVu0X0IR/p4sTgzmqrQoVk4Pw2AY4uiCyUhVwdzh+Od18x76GIlh8PLyoqGhAYDNmzfj7+/Ppk2bADCbzaxZs4bMzEy2bduGyWTiV7/6FZdccgkHDx7E3d2dJ554gpdeeokXXniBWbNm8cQTT/D2229zwQUXnPU5b731VrKysvjzn/9MamoqJSUl1NfXExsby5tvvsk111zDkSNH8Pf3x8tL+5m/bt06Xn75ZZ555hmmTZvG1q1bufnmmwkNDWXFihVUVFRw9dVXc++993LXXXexd+9eHnzwwTF9b4bLqYqXmpoawsPDB90WHh5OS0sLnZ2d/d/QgdatW8fPf/5zR0WcMLYfq+eXH+RzecPfWWEys9c6nf3qNAB6LFYOVbZwqLKFv24p5MbFcfx4zQz8PN1O/0JfHRXgMXEvUwoxnlrqq8j/10/xqjvIlXSwHH8OK3EcNsZx2BrLkZZY3jvQxXsHqkiJ9OfRK1LISArRO7bzMHfA41GOf96fVoG7z6g+VVVVNm/ezMcff8z3v/996urq8PHx4fnnn8fdXdvh+fLLL2O1Wnn++edRbEXSiy++SGBgIFu2bOHiiy/mT3/6E2vXruXqq68GtFWLodorjh49yhtvvMGmTZv6LxAkJSX13x8cHAxAWFgYgYGBgHZh4PHHH+fTTz8lMzOz/3O2b9/Os88+y4oVK3j66adJTk7miSeeAGDGjBnk5ubym9/8ZlTfn5FwquJlNNauXcsDDzzQ/3FLSwuxsbE6JnJuZouVX32Qz/qsMrzo4hbPTwEIvPBHHMy4GE+TkdqWLnYWN/Dv7OPsLjnJ+qwyPsmv5ambFrAg7ivNvH2jAhpLtVEBMy51+N9JCFezt7AKr1euYIla2L94n0w1iw1HBj3upEc02V1R5NXF8sLzcWxbfAn3X5GBySgbRV3JBx98gK+vL2azGavVyo033shjjz3Gvffey9y5c/sLF4ADBw5QWFh4Wr9KV1cXRUVFNDc3U11dTUZGRv99JpOJhQsXnrZ01CcnJwej0ciKFSuGnbmwsJCOjg4uuuiiQbf39PSQlpYGQEFBwaAcQH+hY29OVbxERERQW1s76Lba2tpBl7G+ysPDAw8PD0fEc3ktXWa+9/I+thfWA/Db5EMEVrZBUCJTz7seDEYAYoO9iQ325rqFsWw/Vs//vJNLWUMHNzy7kye+mcoVqV95tZN8Aex9QVs6kuJFiCG9va8Ct3fu4nJDIS34cmLZY0ydlgItldpxBbV52ltrNcHdlVykVHKRaQ8ATfuf45HqJ/if71yHj4dT/fh2PDdv7SqIHs87QqtWreLpp5/G3d2dqKgoTKZT/+18fAZfxWlrayM9PZ1XXnnltK8TGho68rxw1t+fQ2lrawNgw4YNREdHD7rPGX7nOtX//ZmZmXz44YeDbtu0aZPDKrmJrLXLzE3P7SK3shlvdyN//uY8Vm/+H+3OJd/rL1y+avm0KWz4wXk8+EYOH+fV8sPX9mOxqlyVNuB/5v7iRZp2hRjKa7vLqXz35zzotgMLRtxveoWp01YOeMQ3T73bXn+qkKnNo/PIZgI7q7m++rd858VYXvzOErzdnepHuGMpyqiXbxzNx8eHqVOnDuuxCxYs4PXXXycsLAx/f/8zPiYyMpJdu3Zx/vnahone3l6ys7NZsGDBGR8/d+5crFYrX3zxxWl9pUD/lR+L5VSjeEpKCh4eHpSXl5/1is2sWbN47733Bt22c+fOc/8lx4Fdrz22tbWRk5NDTk4OoG2FzsnJobxcO05+7dq13Hrrrf2Pv/vuuykuLuahhx7i8OHD/PWvf+WNN97gRz/6kT1jTnhdZgt3/mMvuZXNhPi48/pdmaw2ZkNjCXgGQtpNQ36+r4eJp29K54ZFsVhVeOCNHD7Oqzn1ABkVIMQ5vXegii/e/TsPumm7NZTL/4DnoMLlK3ymQNIKyPweXPUUXt/bgsXdn1RDMbMqXue/1u+lp9fqmPDCYW666SamTJnClVdeybZt2ygpKWHLli384Ac/4Pjx4wD88Ic/5H//93955513OHz4MN/73veGPKMlISGBb3/723znO9/hnXfe6f+ab7zxBgDx8fEoisIHH3xAXV0dbW1t+Pn58eMf/5gf/ehHrF+/nqKiIvbt28eTTz7J+vXrAe139rFjx/jJT37CkSNHePXVVx12Nptdi5e9e/eSlpbWvz72wAMPkJaWxiOPPAJAdXV1fyEDkJiYyIYNG9i0aROpqak88cQTPP/886xZs8aeMSc0VVV56D8H2Vl8El8PE+u/s5i5MQGwwzYKYNEdw3r1YjAoPP6Nuf0FzI9ezyG/yrazS0YFCDGk/eWNvPDGO/zB9FcA1Iy7MSy8bWRfxC8C40WPAfAT0xuUFB3l5+/njW9QoTtvb2+2bt1KXFwcV199NbNmzeKOO+6gq6ur/0rMgw8+yC233MK3v/1tMjMz8fPzO+eRJE8//TTXXnst3/ve95g5cyZ33nkn7e3tAERHR/Pzn/+chx9+mPDwcO677z4AfvnLX/Kzn/2MdevWMWvWLC655BI2bNhAYmIiAHFxcbz55pu88847pKam8swzz/D444/b8btziqKercPHRbW0tBAQEEBzc/NZL7lNJut3lPLoe3mYDAr/+M5ilk6dAsf3wvMXgtEd7s8Fv4hhf71ei5XbXtzD9sJ6ogI82fCD8wjycYfP18EX/wspV8E319vvLySEi6lr7eamP3/Eiz0PEK00oCZfiHLjG9o5SSNltcKLl0DFLjZZ0rnT/AC/umouNy+JH//gTqSrq4uSkhISExPx9PTUO44Yg6H+W47k97e0rE9gORVN/GpDPgAPXzpTK1zg1CiAudeNqHABMBkNPHXjAhKn+FDV3MXat3K1Dve+UQElX8ioACFsrFaVH722nx93/ZlopQFrUBLKdS+OrnABMBjg8j+BwcRFxmzWGPbwiw/yOVLTOq65hXB2UrxMUF1mCw++kYPZonLpnAjuWK5d5qOxFApsDVaZ947qawd4u/Hkt9JwMypszKvh33uPnxoV0NkoowKEsHllVxkJpa9xsTEb1eCO4ZsvgWfA2L5oeAosux+A//X6Jx69bdz/eo70v4hJRYqXCepPnx6jqK6dUD8P1l09t/+wI3Y+DapVu1ISPnvUX39OdAAPXKQdZf3z9/OobjPLqAAhBihv6OA/H37Mz0wvA6Bc9HOITB2fL37+jyE4iSBLA//j+W8Kqlv48+Zj4/O1hXABUrxMQIcqm/nb1iIAHv/GXAK9bQcgdTbCvn9q7y/9/pif567zk1gQF0h7j4VfvJ9/aulImnbFJKeqKr94ew+/V/4PD8WMOm3NyIaenoubF1yuzXy7nk9IU47x7NYiCk+0jd9zCOHEpHiZYFRV5efv52FV4YrUKC5KGTBuIfslMLdD+BxIWjXm5zIaFH79jbkYDQofHaohi3naHX2jAoSYpDYXnOCC0j8yzVBJr3c4ylV/HfM8nNMkrYTUb6Gg8mffl1AtZh5599BZT1kVYiKR4mWC+eBgNXtKG/FyM/LTr808dUdvD+x6Vns/895x+0E6K9K/v5/m4S1tqIEJYO3VRgUIMQl1mS1sfec5bjR9joqC6brntTNb7OHiX4NXMLHmEu52+4gdRQ1syK22z3M5ASnMXN94/TeU4mUC6eyxsO7DAgDuXpE8eBp03lvQWg2+ETDn2nF93h9eOI0pvh6UNXRwxHeRdqMsHYlJ6o1Pv+TH3U8BYF76o1O9YPbgEwJrfg3AD93eIk6p5XcfH5lwzbtubtpQ2I4OHaZIi3HV09MDgNF45lPdh2sSny098bzwZQlVzV1EBXhy1/mnJoaiqqcOpcu4C0zuZ/4Co+TjYeJHF03jf94+xN8q4/kDSNOumJQa23uYtvOn+CsdNATNJ+TCn9r/SVO/BQf+hVvJVn7r+RI3NDzE63vKuSUzwf7P7SBGo5HAwEBOnDgBaAe5KeO9DCfszmq1UldXh7e396D5TqMhxcsE0dJl5tkvtCbdn1wyAy/3AVVt8RaozdUGiqXfbpfnv35hLC9sL+HTuhlYPY0Y+kYFBMbZ5fmEcEbvbPyY25VcejESdPNLYHSz/5Mqinb2y18zWWI5wJWGL/m/zZ5ckx4zoWYfRURoZ1L1FTDCNRkMBuLi4sZcfE6c/7MnuRe3l9LS1cvUMF++njp4AihZtqsuabeAd7Bdnt9kNPCTNTO5++V2DqrJzFeOaktH6d+2y/MJ4Wwa2rrxPvgSKFAfczERIYmOe/KQZFjxE/jsVzzm/gor2+bzwvYS7rtgmuMy2JmiKERGRhIWFobZbNY7jhgld3d3DIaxd6xI8TIBNHeaeX57MQA/uHAaRsOAivZEARR+CophfLdqnsHFKeHMjPBjS/0c5puOaktHUryISeKlzw5yN9sACL9wdAdAjsnSH0LumwTVFfBT06us2x7E7csS8fGYWD/mjUbjmPslhOuTht0J4MUvS2jt6mVamC+XzY0cfGffVZeZl0OwfV8JGgwK910wla0Wbcu0WiyjAsTkUN/WTefel/FRumkLmIaSsNzxIUzucMWfALjetIUZnQf5126Z8i4mJileXFxHTy8vflkKnOGqS2stHNRGno/HoXTDcemcSFpD5tGieqF0yagAMTn8c0cpN/AJAD7Lvjv+Z7oMV9yS/r62x92eZ/3Wo3T3ygsIMfFI8eLi/pN9nOZOM/Eh3nztq1dd9jwHlh6IWQyxix2Sx2hQuOeCGeywzgHAfHSzQ55XCL109lgoyPqAqYYqek3eKPOu1zfQ6sdQfcNJNlTz9Y43eWd/pb55hLADKV5cmMWq8vftJQB8Z1ni4KsuPe2w53nt/aX3OTTX11OjOOixAIDG3I8d+txCONp/9h3nqt6NABhSbwBPf30DeQWiXPRLAG43beSFLYexWuVwNzGxSPHiwjbl11LW0IG/p4lr02MG35nzqjbLKChB63dxIJPRQMzCrwEQfHI/aleLQ59fCEexWFXe+2I3Fxv2AmBYfKfOiWzmXIPVP5opSgtzmz7li2N1eicSYlxJ8eLCnt+m7TC6aUn84B0FVgvs/Kv2/pJ7weD4zvyvnb+UcjUcExYO7/zI4c8vhCNsLqhleeuHmBQrltilEJ6idySN0YRh8V0AfMe4kfVflugcSIjxJcWLizpU2czeskbcjAq3LU0YfOeRj+BkMXgGQtpNesQj0Nud6imZAFTtk+JFTEyvZhXyLaN2mrQxw0muuvRZcCtWkycphjI6j22jtL5d70RCjBspXlzUq7YtkGtmRxDu7zn4zr7t0Qu/A+4+Dk52StwibbkqoWknFSdlJomYWErq2/Ep/pgwpQmLd5jDl2fPyTsYQ+q3APi26WP+kVWmcyAhxo8ULy6orbuXd207CG7KiB985/G9UJ4FBjewXTbWS2TqRVgwkGyo5qPtu3XNIsR4e3VXGbeYNgFgXHT7uM8MGxe2nwEXG/aydW8O7d29OgcSYnxI8eKC3tlfSXuPhaRQH5YkfeW4/x1Pan/OvQ78I0//ZEfyCqQlWDuwru7ARsyWiTXpVkxeXWYL+/buYImhAKtihAVOepJ0eApq/DJMipWvWz7mg4NVeicSYlxI8eJiVFXllV3aktFNGfGDh1s1lkLBe9r7Dt4efTb+s9cAkNqzj88Oy0A1MTFsOFjNlWZte7Qy42sQEH2Oz9CPYrv68i3jZ7y5u1jnNEKMDyleXExORRMF1S14mAxcs+ArPzB3PgOqFZIvgPDZ+gT8CuO0CwFYZsjj9V2y40FMDO/tOszVRm2OkeIs26PPZuZlWHwjCFVaiKj8hMITrXonEmLMpHhxMf/JPg7AZXMjCfQesMbe2QT7/6m9n+kcV10AiE7H6u5HkNJGQ+EejjdK465wbWUN7cRWfoCv0kVv8DRIPF/vSEMzumFcdAcAt5o28fqeCp0DCTF2Ury4kC6zhfcPaGvW13z1ULrsl6CnDcJma1denIXRhCFpBQDLlVze2idHlQvX9mb2cW4xao26pow79ZtjNBILvo3V4MZCw1HysrfR0yv9Z8K1SfHiQjYXnKClq5fIAE+WJIWcuqO3B3Y9q72fea/z/TC1FVPnGw/y9v5KVFWOKheuyWpVyc/ewgzDcXqNnpB6g96RhscvHGZ9HYArez5kc0GtzoGEGBspXlzIW/u0JaNvpEUPnmOU9xa0VoFvOMy9Vqd0Q0heBcAC5Rgn6us5cLxZ50BCjM6ukpNktn+ufTDjMvAM0DfQCBgyvgvAlcYv2bi3QOc0QoyNFC8uoq61my1HtfkkVy8YsGSkqrDDdihdxnfB5KFDunMIToKgBNwUC0sM+bxtK8KEcDVvZZdxhTELAFPqN3VOM0Kxi+kKmY2nYiay+D80d5j1TiTEqEnx4iLezanEYlVJjQ1kapjvqTtKvoDaXHDzhvTb9Qt4Lralo+WGQ7x/sFrOfBEup727l4ZDmwlTmuj1CHSu3rLhUBQ8l90NwLeUTXyUKy8ihOuS4sVF9DW6XvvV7dF9V13SbgbvrxxY50xsP+hXmXI52d7DF0dkyq1wLZ/k17DGuh0A45xvOOeJuucy51q6TP7EG05QuvNdvdMIMWpSvLiAwhOt5Fe34GZUuHxe1Kk7ThyGwk2AAkvu0S3fsCScB4qRBKqIpo6398uuI+FaNu4v41KjNuZCmXudzmlGyd0b87wbAciof4uqpk6dAwkxOlK8uID3D1QDcN60UIJ8Brza6xvAOOtyra/EmXkFQnQ6AMuNh9hUUEtLl6y5C9fQ3GHGWPwp/koHZp9IiMvUO9Ko+S3TTtw933CQT3cf1DmNEKMjxYuTU1WVDbla8XLZ3AGzilpr4eDr2vuZ39ch2SjYlo4u9cqnp9cq2zWFy/g4v4bLFG3JyC31OjC48I/OkGTqA+dhVFQ69v9b7zRCjIoL/wucHI7UtlJ4og13o4GLZoefumPPc2DpgZjFEJehX8CRsBUvGeRiwMqGgzU6BxJieDbtP8Zqw37tA1ddMhrAe+G3AFjS/hnHamVcgHA9Urw4uQ9sS0bnTw/F39NNu7GnA/b8XXvfSQYwDkt0Onj449XbwhylhK3H6miVpSPh5Braugks+xgPxUxP0DSImKt3pDHzTr0GKwrzDUVs3ZujdxwhRkyKFyc2cMnoitQBS0YHXoXOkxCUADMv1yfcaBhN/XNgrvQ7bFs6kknTwrltzKvhCuVLANznX+98J1iPhl84DcFpAPQckl1HwvVI8eLE8qpaKKlvx8Nk4MJZtiUjqxWy/qq9v+R7YDDqF3A0bEtHazzzAfjgYLWeaYQ4p637ClhqyNM+mHuNvmHGke/8bwCwoH0bJfXtOqcRYmSkeHFifb/YV80Iw9fDpN149CM4WaQdSz7/Jh3TjZJtVEB0Wy4+dMrSkXBq9W3dhB3fiEmx0h0+3/l39Y2A1zyteFmkHGFLdq7OaYQYGSlenJSqqmw8ZNtlNG/AklHfoXQLvwMevmf4TCdnGxWgWHu5MqhElo6EU9tcUMtlxp0AeKQ64dywsQiMpT5gLgZFpfOgLB0J1yLFi5MqPNFGaUMH7kYDK2eEajcez4byHWBwg8Xf1TfgWNiWjq4NOArQ39cjhLPZfSCPxcph7YOUq3TNYg9eqVcBMK/lCypOdugbRogRkOLFSX2Sr52BsnRqCH59u4yyntT+nHsd+Eee5TNdgK14md2ZDcC2Y3V09lj0TCTEadq7ewks26hdmQhPh8BYvSONO5/5VwOwxFDA5/tk0rRwHVK8OKm+4uXilAjthsYyyLdd2s28V6dU48Q2KsCjuYgFAa10ma1sL6zXO5UQg3xxtI5LlB0AeM6fYEtGfYKTOOk3A5NipeWALB0J1yHFixOqbeniQEUTAKtnhWk37noGVCskrYKIOfqFGw8DRgXcFl4CwKZ8ObBOOJfdOQdZZDiKioIy+yq949iN+9yrAJjdtIUTrV36hhFimKR4cUKbbFdd0uICCfP3hM4m2PcP7U5XOpRuKLalo6Vos1U2F5zAYlX1TCREP7PFinfRBwC0hS8E/6hzfIbr8k3Ttn8vMxxie26hzmmEGB4pXpzQaUtG+9ZDTxuEpUDyhTomG0e24iWkLosATwMN7T3kVDTqHEoIza7ik1xk1ZaMfBZ8U+c0dhY6gwavRNwVCw05H+qdRohhkeLFybR0mckq0vo/LkoJh94e2PmMdmfmvRPjdE/oHxWgdDZyS1wTAJvyZcu0cA679u0nzVCIFQOGlCv1jmN36rSLAAioyaLLLM3zwvlJ8eJkthypw2xRSQr1YWqYL+S9Da1V4Bs+IQbC9RswKuByX22Xg/S9CGdgtaq4H30PgOawxeAXfo7PcH0hs7UroYvIY0eRNM8L5yfFi5PZNHDJSFVPbY9efBeYPHRMZge203antu7GzahQVNdOcV2bzqHEZHeoqpkV5m0A+KZP8CUjGyV+KVYMJBpq2X3gkN5xhDgnKV6ciNliZcsRbenkopRwKNkKNbng5q2dqDvR2PpeTJV7WJngBcCnBbV6JhKCffv3Mc9QggUDbnMm/pIRAJ4BtAXPBqDj6BeoqjTPC+cmxYsT2VfWSGtXL8E+7syPDYQs2yiA+TeBd7Cu2ezCNioAay83hJUDp648CaEXw+F3AKibkgE+U/QN40De01cAkNJ9gEOVLTqnEWJoUrw4kc+P1AGwYnooxvojcOwTQIEl9+gbzJ5sV18y1AMAZJc10tTRo2ciMYnVt3WzsHULAN5pE/RgurMwJWk9aEsMBXIFVDg9KV6cSN+S0coZoaeuusy8DEKSdUxlZ7bixbdiKzPC/bCqsPWYNAwKfezbt5sUQxm9GPFPu1rvOI4Vl4kVAwmGWg7kSd+LcG5SvDiJqqZODte0YlBgRZQKB1/X7lj6A32D2ZttVAANx/h6Qi9wqogTwtF6DrwJQHlgxsRcqh2Kpz+WiFQAAk/soaZZTtsVzkuKFyexxbZklBYXROCh9WDpgZhFEJehczI7GzAqYI2XtmV669E6rHLarnCwXouVmQ2fAmCY8w2d0+jDLek8ADIN+Ww9VqdzGiHOTooXJ/F53y6jqX6w53ntxswJMgrgXGxLR4nNu/FxN1Lf1kNelTQMCscqOLibqVTQg4nYpRPoTKWRSNCKlyWGfL44KsWLcF5SvDiB7l4LX9qmKl/BF9B5EgLjYdYVOidzEFvxYiz9guXJQYAsHQnHa9n7BgBHfBdj9A7SOY1O4pagKkbiDScoPFpAr8WqdyIhzkiKFyewp6SRjh4L4b5uRBW8oN245HtgMOobzFFsowLobOQbEQ0AbJFXfcKRVJW46o0A9Mz4us5hdOTpD5HzAUjpyeXA8WZ98whxFlK8OIG+JaN7oo6inCwCzwBIu1nnVA40YFTAUkXbMr2/XLZMC8epK8om1lpJt+pG0rLJcaru2SiJywFty7QsHQlnJcWLE+grXr7e8bZ2w8LvgIevjol0YBsV4F+5jenhvlhV2CZbpoWDnMh6DYD9nosICg7ROY3OEvqadvOkeBFOS4oXnVWc7KC4rp35xmKC6/eCwQ0Wf1fvWI5n63uhYhcXT/UBTu3AEsKuVJWw8g0AnEy4TOcwTsDW9xJnqKPh+DEa2rr1TiTEaaR40dl2W6PuT3w/0W6Yey34R+qYSCcDRgVc5lcMwBeyZVo4gKUyh1BzFZ2qO5GLrtI7jv48/FCi0gBYrBT0/4wSwplI8aKz7cfqiaaOzO4vtRsy79U3kJ5sV1+mt++xbZnuJr9atkwL+2rYpS0ZbVMWMDcxSuc0TiJhQN+LXAEVTkiKFx1ZrCrbC+u53bQRAxZIWgkRc/WOpZ++LdPFn5ORpPUdfCmv+oQ9qSqeR98DoCT8YkxG+ZEIDOh70Q6rkyugwtnIv1QdHapsRu1s4lumz7UbMr+vbyC9DRgVsCZa22kkl6yFXVVm499dRbvqgd886XfpZ+t7iTXU4dleKVdAhdOR4kVH2wvrucH4GT50QVgKTL1Q70j6GjAqYKVJGwy3u+QkXWaLjqHERGY+qM0y2mxdwLKZsTqncSIevijRCwDIkL4X4YSkeNHRl0equc30sfZB5r2gKPoGcga2paOw+izC/T3o7rWSXdaocygxIVmtWHLfAmCn1wriQ3x0DuRk+vte8mX5VjgdKV500t7dS+Txj4hSTtLrHQZzJ+ksla+yFS9K8Zb+UQHyqk/YxfHdeHbW0Kp6YZpxkd5pnI+teMk05ssVUOF0HFK8PPXUUyQkJODp6UlGRga7d+8+62NfeuklFEUZ9Obp6emImA61u7iB2w3a2RLGjLvA5KFzIicxYFTA5VO0w/u2y2F1wh7ytEMhN1nTyZwerXMYJxS7BNVgIkapJ9RSy75yuQIqnIfdi5fXX3+dBx54gEcffZR9+/aRmprKmjVrOHHi7IP3/P39qa6u7n8rKyuzd0yHq9j/CXMMpfQoHiiL7tA7jvMYMCpgkTUHgENVzTS2y6gAMY6sFiyHtOLlQ+sSliZP0TmQE/LwRYnS+l5k6Ug4G7sXL3/4wx+48847uf3220lJSeGZZ57B29ubF1544ayfoygKERER/W/h4eH2julwM4pfAqAq8RrwDtY3jLOxjQrwPb6NGeF+qCrsKGrQOZSYUMqzMLbX0qJ60xR5HgHebnonck4DznvZXij/BoXzsGvx0tPTQ3Z2NqtXrz71hAYDq1evJisr66yf19bWRnx8PLGxsVx55ZXk5eXZM6bD1RUfJKN3L1ZVIfjCH+odx/kMGBWwKtELgO2FclCWGEe2JaOPLQtZOn0Snmg9XAOadnOPN9LcYdY5kBAauxYv9fX1WCyW066chIeHU1NTc8bPmTFjBi+88ALvvvsuL7/8MlarlaVLl3L8+PEzPr67u5uWlpZBb86udcufANjlsQT/6Jn6hnFGA0YFfM2vCJCmXTG+1CMfAbDBuoTl00J1TuPE4paAre8lijqyiuXqi3AOTrfbKDMzk1tvvZX58+ezYsUK3nrrLUJDQ3n22WfP+Ph169YREBDQ/xYb6+RnNbSdILbifQBKpt2ucxgnZrv6MqtjL25GhYqTnZQ1tOscSkwIzcdRWirpVQ3kmmYzPzZQ70TOy92n/+ylTOl7EU7ErsXLlClTMBqN1NbWDrq9traWiIiIYX0NNzc30tLSKCwsPOP9a9eupbm5uf+toqJizLntSd39HG5qD/utU0mYf4HecZyXrXhxK91CWpxsmRbjqELb7VigxjE7IQp3k9O9hnMuA/peviySf4PCOdj1X627uzvp6els3ry5/zar1crmzZvJzMwc1tewWCzk5uYSGXnmdWkPDw/8/f0HvTktcyfW3c8D8KL1chYkSKPuWSWcB4oBGo7xtRhtnV22TItxYStesq3TWZoconMYF9B33oshn+K6NqqaOnUOJIQDlo0eeOABnnvuOdavX09BQQH33HMP7e3t3H67tmRy6623snbt2v7H/+IXv+CTTz6huLiYffv2cfPNN1NWVsZ//dd/2Tuq/R34F8auk1RYQ6mLuQhPN6PeiZyXVyBELwRgpbs2KmBncYMMiBNjptqKl33WaWQmSfFyTrEZYHAjSmkgVjkhS0fCKZjs/QTXX389dXV1PPLII9TU1DB//nw2btzY38RbXl6OwXCqhmpsbOTOO++kpqaGoKAg0tPT2bFjBykpKfaOal9WK2Q9BcDfLZeyZOrE2/497pIvgOO7iWvcjbd7Eo0dZo7UtjIr0omvrgnnZu5ErTmIAhx1m8XsKPl/6Zz6+l4qdmpLR4VpXLfQyXsLxYTnkMXe++67j7KyMrq7u9m1axcZGRn9923ZsoWXXnqp/+M//vGP/Y+tqalhw4YNpKWlOSKmfR3dCA2FtODDG5aVZMrl6nOz9b0YSrawKD4A0K6+CDFqVTkYrGZOqIHEJM7AZJR+l2EZOOeoqAFVlSugQl/yL9dRsv4CwCu9F2B18yY1NkDnQC5gwKiAK0K1c16y5LA6MRbHTy0ZLZFTdYevv++lgLrWLorrZeef0JcUL45QuQ/KvsSqmHipdw0L44PxMEm/yzkNGBWwlAMA7Co5KX0vYtSs5bsA2GedKiMBRmJA30ucckKugArdSfHiCLarLrt8VlFLsCwZjYRtVEBk/Q58PUw0d5rJr3b+gwiFE1JVLLbi5ah7CjMj/HQO5ELcvSFGa6BfYshnZ/FJnQOJyU6KF3trKoe8dwD4Y/vFAFK8jISt70U5vpvz4rTJ2/KqT4xKUxlunfX0qEZ8ExZhMCh6J3ItA8572VksfS9CX1K82NvOZ0C10Ba9nN2d0fi4G5kbLf0uwzZgVMDXA0sAKV7EKB3fC0C+Gs9imWc0cgPOe5G+F6E3KV7sqasZ9v0DgO2hNwCwKDEYN9nhMDK2qy+LLDmA1vdikb4XMUK9tvNdcqxT5XyX0YhZDAY3IpWTxCu18iJC6Ep+i9pT9nroaYXQWfynaQaA/NAcDVvxElL7JX4eJlq7esmvkr4XMTKdxVrxUug+i6lhvjqncUHu3hCzCOhbOpK+F6EfKV7sxWKGXc9o7y75HrtKGgHpdxkV26gApeEYl8ZqowKyiuWUTzECvd14NWgnNbvFL0JRpN9lVAac9yJ9L0JPUrzYS9470FIJPmHkhayhtbsXP08Ts6Ok32XEBowKuML3MCDnvYgRqjmESTVzUvVl2ox5eqdxXXLei3ASUrzYg6pC1pPa+4vvYkdZGwAZiSEYZYfD6NiWjub17AdgT2kjvRarnomEC+kp07ZI51inkjlVzncZtdjFYHQnQjlJglIjLyKEbqR4sYfSbVB9AExesOiO/sY2WTIaA1vx4l/9JUGeBtq6ezkkfS9imJqPZQFwzH0mCSHeOqdxYW5eX+l7keJF6EOKF3vYoR1KR9pNWDyD2Fuq9btkJAbrGMrF2UYFKJ2NXBul/cCUV31iuNxq9gFgiUyXfpexGtT3clL6XoQupHgZb3VH4NjHgAJLvkdBdQtt3b34eZhkGvJYDBgVcIlXPgBZ8qpPDEd7PYFdxwEImZGpc5gJYEDfS31bF0V10vciHE+Kl/GW9ZT258zLICSZXSXadsKFCUHS7zJWtlEBMzu0w8ayS09K34s4J3P5HgAKrVEsmJ6gb5iJIGYRGN0JVxpJVGpk6UjoQoqX8dRWBwde097PvA+A3SXaP+zFidLvMma2vhfv2n2Ee5pp77FQUN2qcyjh7OoPfwlAvnG6nO8yHty8tAPrOLVlWghHk+JlPO15HizdWn9G3BJUVWW37crLYul3GTvbqADFaubGsAoAdpXID04xtF7blZfWkPnS7zJeBs05kr4X4XhSvIwXcyfseU57f+n3QVEoPNFGY4cZTzeDzDMaL7arL6vctAPH9pTKKZ9iCFYrIU25APgkLdE5zAQyoHipb+uitKFD50BispHiZbwc+Bd0NEBgHMy8AoDdtl+sabFBuJvkWz0ubMXL9DbtqPc9pY3yqk+claXuKN5qO52qO1PnLtY7zsQRswiMHoQrjSQp1ewpkRcRwrHkN+p4sFpPNeou+Z62MwZkycgebKMCPJuLSXJr4GR7D0V1bXqnEk6qOn87AHkkMyta/h2OGzdP7cA6tKsvu6R4EQ4mxct4OPYxNBSCRwCk3QyAqqrssg0uk/NdxtGAUQE3BBcByA9OcVZthdrhdHUBc2S333gbcN6LLN8KR5PiZTz0HUq38Dbw8APgeGMnNS1dmAwKaXFB+mWbiGxLRytMtr4XKV7EWXjX5QCgxC7SN8hENKDvpfxkO7UtXToHEpOJFC9jVbkPyraDwQSLv9t/c9/VgHkxAXi5G/VKNzHZipek1r0YsPYvzwkxkNrdRlRPMQCRKct1TjMBRS8EowdhShPJSpX8OxQOJcXLWGXZrrrMuRYCovtvlvNd7Mg2KsCtp4lUYylVzV0cb5TdDmKwyoKdmLBSqwYxc8ZMveNMPF/pe5GlI+FIUryMRVMF5L2jvb/0vkF37bHNM1qcKEtG427AqIBrAo4CyKs+cZq6Au1wulKvFDxMcvXTLhLOA7S+F/k3KBxJipex2PUMqBZIXAERc/tvPtHSRUl9O4oC6fHSrGsXtlEB5xu1MzzkVZ/4KkOlNkaiO3yBzkkmsAF9L0dqW2juMOscSEwWUryMVlczZK/X3l/6/UF39Z3vMivCnwAvN0cnmxxsfS8x7YfwoVN2HIlBVFUlsk1r6A6avlTnNBNYdDqYPAlVmkmiir1l8u9QOIYUL6O17x/Q0wqhM2Hq6kF3yfkuDmAbFWCwmskwFFBc1059W7feqYSTqC4vIoyT9KoGklOX6R1n4nLz1A6sAzIN+f0v3ISwNyleRsNihp3PaO9n3gtfmZfSV7zI+S52Zrv6cqXvYUC2TItTyg5uBaDCLQFvXxnNYVe2/rMlhgL5NygcRoqX0ch/F1qOg08YzP3moLuaOno4XKNNOl4kxYt92YqXpcpBAHnVJ/p1l2njIxqDU3VOMgnY+l4yDPkcPN5EZ49F50BiMpDiZaRUFXb8WXt/8V3aZdMB9tp2GSWF+jDF18PR6SYX26iA0O5yoqmT3Q6iX9DJAwB4Jcg8I7uLTkc1eRKqtBCvVrK/olHvRGISkOJlpEq3Q/UBMHnBojtOu7vv1b8sGTnAgFEBy42HKKhuoaVLdjtMdnXN7UyzaKMjYuau0DnNJGDyQLGd95JpyGdPiRQvwv6keBmpvkPp5t8I3qcXKH2v/hclSPHiELalozWe+VhVyC6TH5yT3dHcXXgr3bThg1/0LL3jTA4JfX0vMudIOIYULyNRdxSObgQUrVH3K7rMFvKqmgEpXhzGVrxkkIsBqzQMCpqP7gCg2jcFDPIjziEGnPeyr/wkvRarzoHERCf/skdi51PanzO+BiHJp919oKIJs0UlzM+DmCAvB4ebpGyjAnwsLcxRSqTvReBRux8AS5QcTucw0QtQTV5MUVqIMpeTV9WidyIxwUnxMlxtdXDgNe39rxxK12evbcliYUIQyle2Tws7GTAq4DxDLgcrm+nuld0Ok1WX2UJCVz4AITPkfBeH+Urfi7yIEPYmxctwNRSCZ6D2Sj9uyRkf0tdvISMBHMw2KuACt0P09Fo5VNmscyChl0NF5SQrVQBMmSEn6zpU4oA5R9L3IuxMipfhis+E+3PhupdOO5QOwGpV+4uXhfEyjNGhbH0vqRzFh87+7epi8qnM04Yx1rlFoviG6pxmkukf0ljA3pIGVFXVOZCYyKR4GQmTOwTGnfGuoro2mjvNeLkZSYnyd3CwSc42KsBELxmGgv7lOzH5WCv2ANAcMl/fIJNRlNb3EqK0MqWrlOL6dr0TiQlMipdxssf2aj81NgA3o3xbHc529eU8Qy7ZZY3yqm8SslpVQpq005a9EjJ0TjMJmdxR4rTve6Yhj2y5AirsSH7LjpO+aaoLpd9FH7biZYUxl5PtPfKqbxIqOtHKHPUoAOEp0qyri4FLRzJhWtiRFC/jJHvATiOhA9uogCSliijq5VXfJHS4IJdgpQ0zbpiiZKaRLmzFS4ahgOzSBp3DiIlMipdxUNfaTVlDB4oCC6RZVx+DRgXkyqu+Sai5MAuAOt8ZYJK5YrqISkN18yZEacXYcJST7T16JxITlBQv4yDb9otyRrgf/p5uOqeZxGxLR+cbcqVpdxLyqt0HgCUqXeckk5jJHSW2r+8lX8Z1CLuR4mUc9G3NTZerLvqyFS/LDIcorWuloa1b50DCUepau0nuOQxAiJzvoq8B573IFVBhL1K8jIO90u/iHGyjAoKUNuYoJfKqbxLZX1xDilIKgHei7DTS1YC+l30l0vci7EOKlzEaOIxRdhrp7CujAqR4mTyqCrJwVyy0mQIhKEHvOJNbVBpWkxfBShudVXkyrkPYhRQvYyTDGJ2MbVTA+caD0vcyiRgqdgLQPGXhGU/AFg5kdEOJzwQgXc2TcR3CLqR4GSMZxuhkbH0vacoxio/X0GWWV30TXZfZQkzrAQC8py7XOY0AUBK0/w6ZhnwZ1yHsQoqXMZJhjE4mOAk1KAF3xUKamkeuvOqb8A5WNLJAOQJA4MzzdU4jAEjQ/jvIeS/CXqR4GQOrVWWvbXrqImnWdRrKgFEB8qpv4ivO30ug0k6X4okSKYfTOYWo+VhM3gQpbTSXHZBxHWLcSfEyBoV1bbR09eLlZmRWpAxjdBr9570c7D+DR0xcPcU7AGgInKc1bQv9Gd1Q4pYAMKv7ICUyrkOMMylexqDvVf382EAZxuhMEs5DVQwkG6qpLD2K1Sqv+iYqq1VlyslsAAwJMs/ImRhs571kGvKleV6MO/mNOwb9wxhlyci5eAWiRmunrM7t2U9xfZvOgYS9FNe3MU/VDqcLnb1C5zRikMRTfS9y3osYb1K8jMGpZl0pXpyNIflCwDYqQPpeJqz8gnxilHosGDDFLdY7jhgoMpVekw+BSjsNJfv1TiMmGCleRkmGMTq5AaMCskvrdQ4j7KX16DYATvjMBHcfndOIQYxuqLY5RzHN2TTKkEYxjqR4GSUZxujkotPpdfMlSGmjtSRb7zTCTnxr9wBgjlmicxJxJm7J2tKRDGkU402Kl1GSYYxOzmhCtZ01kdyym3oZ0jjh1Ld1M6MnD4CQWdLv4pRs/wYXGw6zV857EeNIipdR6uueX5Qgh9M5K7fptr4X40Hpe5mADh4rYaahAgCfaXKyrlOKTMVs9Nb6XorkCqgYP1K8jEJnz6lhjHLlxYkNGBWQW1yhcxgx3urzbf0uHnHgM0XnNOKMjCbM0dqSXuCJ3TKkUYwbKV5G4cBxbRhjuL8MY3RqwUm0ecfirljoKdqmdxoxzkyV2jDG9vBFOicRQ/Gari3pLSaPQ5UtOqcRE4UUL6PQ13i2MD5YhjE6OTVJmzIde3KnDGmcQLrMFuLbDgLgN/08ndOIoSi2w+oWGwrYV1qncxoxUUjxMgp984xkycj5+aZcBMAy5SAHKpr0DSPGTW5pLXOVIgBCUlbqG0YMLSKVHqMPAUoHNUel70WMDyleRshqVU9deZGTdZ2ekng+VrRRAYeP5OsdR4yT43nbcVcsNBlDUIIS9I4jhmI00RmpHSDoXZUlQxrFuJDiZYRkGKOL8QqkLmAOANbCz3UOI8aLWqoNYzwZkg6ydOv0fGZofS/zenMpbejQOY2YCKR4GSEZxuh61CRt11FUww4Z0jgBWK0qYU3acfNuSUt1TiOGw5SkFS8ZhsPsLZG+FzF28tt3hGQYo+uZknoJAIvVXIpqm3VOI8aq+EQz89QjAETMuUDnNGJYIubRZfTBX+mg+sgevdOICUCKlxE61e8ih9O5ClPsIjoUb4KUNopzd+gdR4xR4aHd+CuddCjeuEXN0TuOGA6jidYwbUu7W4X8GxRjJ8XLCAwcxpgWF6h3HDFcRhOVgdoPTsuxzTqHEWPVWbgdgBr/VDAYdU4jhstn+koApnbkyJBGMWYOKV6eeuopEhIS8PT0JCMjg927dw/5+H//+9/MnDkTT09P5s6dy4cffuiImOckwxhdl9V23ktUQ5bOScRYBdbvBUCNk2GMrsR7xkpA63vZJ5PexRjZvXh5/fXXeeCBB3j00UfZt28fqamprFmzhhMnTpzx8Tt27OBb3/oWd9xxB/v37+eqq67iqquu4tChQ/aOek57SmWLtKuKWnAZACmWw9Q3yIA4V1Xf2sUss7blPWzOSn3DiJGJmEenQet7qSjYpXca4eLsXrz84Q9/4M477+T2228nJSWFZ555Bm9vb1544YUzPv7//u//uOSSS/jJT37CrFmz+OUvf8mCBQv4y1/+Yu+o57R3wMm6wrX4RU+nyhCBu2KhLPsTveOIUcovyCVCacSMCb+kDL3jiJEwGGmcslB7t+xLncOIsXCGs3rsWrz09PSQnZ3N6tWrTz2hwcDq1avJyjrz5fusrKxBjwdYs2bNWR/f3d1NS0vLoDd76OyxkFcpwxhdWXmgtsxgLZS+F1fVdFibUVXtPQPcZK6Yq3Gfej4AMc3Z9PRadU4jRqO6uZO0X27izn/s1fXoCbsWL/X19VgsFsLDwwfdHh4eTk1NzRk/p6amZkSPX7duHQEBAf1vsbGx4xP+Kw4cb6LXKsMYXZmatBKASOl7cVkeVVq/XFeEDGN0RSGzLwRgoVLAoeOyfOuK9pU10dRhpqqpE4NBvwMiXX630dq1a2lubu5/q6iosMvzLIwP4oPvL+d/r5knwxhdVPSCNVhUhRjLcbrqy/SOI0aoy2whoVPrfQucIcMYXZESOY8Ogw/+Sidlh3bqHUeMQv9ZZzqvQNi1eJkyZQpGo5Ha2tpBt9fW1hIREXHGz4mIiBjR4z08PPD39x/0Zg8mo4E50QGsmhFml68v7C82MpJDynQAqvY5xw42MXz5xRVM4zgAoSlSvLgkg5ETQekAWEq26RxGjMY+W+/ngolcvLi7u5Oens7mzad6DKxWK5s3byYzM/OMn5OZmTno8QCbNm066+OFGC5FUagI0po8rXLei8upPrQVg6JS6xaN4hd+7k8QTsmYpBWe4Sf3OEXjpxi+zh4LeVVaX6neB7XafdnogQce4LnnnmP9+vUUFBRwzz330N7ezu233w7Arbfeytq1a/sf/8Mf/pCNGzfyxBNPcPjwYR577DH27t3LfffdZ++oYhLoO+8lomEnWC06pxEjoZZrvUrNIQt0TiLGImyutiFjvrWAsjr7bLAQ9tHX+xnh70lUgKeuWexevFx//fX8/ve/55FHHmH+/Pnk5OSwcePG/qbc8vJyqqur+x+/dOlSXn31Vf72t7+RmprKf/7zH9555x3mzJFjwMXYxc49jxbVC19rK9bKHL3jiGFSVZXw5gMAeCTLMEZX5hGTSpvii5/SSZGM63ApfeNx0hOCdO/9NDniSe67776zXjnZsmXLabddd911XHfddXZOJSaj2TEhfKHO4SJlD425GwmJTdc7khiGopom5qjHQIFIOZzOtRmMVAWkMb1pG93HvoALL9U7kRim/uIlTv/jQlx+t5EQI+FuMlAaqPW9WAo/0zmNGK6SQ1l4KT20Kb64h8/UO44YI2v8cgBC6mXCtKuwWtUBg4mleBHC4VRb30twYw50t+obRgxLR5F2ImtNQCoY5MeWq4uYp/W9pJjzaGrr0DmNGI7i+jaaO814uRmZFWmfXb0jIT8FxKQzdeZcyqxhmNReKJVjyl1BYN0+7Z1YGQkwEQQmLqAFre/lWM52veOIYdhrm+2XGhuAm1H/0kH/BEI42IK4ILZZ5wLQeXiTzmnEuTS0djGzVxvGGD5nhc5pxLgwGCj3mw9A29Ev9M0ihqVvtp+zjMeR4kVMOoHe7hT5acfLW2TOkdPLL8glXGmSYYwTjDlW2zUWUCMTpl1BX7/L4mhP+OfVsONJsPTqlkeKFzE5JZ2PRVXwbS2BJvuMlBDjo7F/GON0GcY4gYTM0eYczejOpae7W+c0Yij1bd2U1LejKLDQmgtFm2H3c2Aw6pZJihcxKc1OiidHnap9UPy5vmHEkNyrtR0pMoxxYomduYhmfPBRuijOld4zZ9Z31WV6mB8+5bafl9MuAh3PepHiRUxKC+NP9b1YZFSA0+oyW0jo6BvGeL7OacR4UgxGirznA9BSIC8gnNneUm0YY3p8IBTa+gSnXqRfIKR4EZNUfIg3Bz20Y+bV4i0yKsBJ5RdXMB1tWU+GMU48HVHazDrvqiydk4ih9DXrrgxpgqZyMLpDor7/HqV4EZOSoih4xC+mRfXC1N0E1Tl6RxJn0DeM8YQMY5yQAlO0M5cSO3NRe3t0TiPOpMts4VBlMwCLerO1G+OXgbuPjqmkeBGT2IKEULKss7UPiuS0XWfUN4yxaYoMY5yIps7JoFH1xYcuag7v1DuOOIODx5sxW1TC/DwIrLRta5+m75IRSPEiJrH0hFN9L2qRrLk7G6v11DBGzyQZxjgRebq7ccRzHgD1h6T3zBntsfW7LI3zRCmzNVbr3O8CUryISWxOVAA7lVTtg4rdMirAyRTXNmrDGIEIGcY4YbWEa2f3eByXCdPOqG+n0dd8i8DSA4FxMGWazqmkeBGTmLvJQHDMTMqsYShWs4wKcDLFuTtlGOMk4DNjJQCxbQfBYtY3jBhk4DDGBT22IZpT9d0i3UeKFzGpDVw6kr4X59JZrBWTtTKMcUKbMS+Dk6ovXnTRWrxb7zhigKK6vmGMBkKqt2o3OkG/C0jxIia5gee9SPHiXAL6hjHGLdE3iLCrKX5eHDJp/wZP5H6qcxoxUN8W6Usj21CaymxbpJ3jvCUpXsSklh4fRJZ1NhZVgYZjMirASdS3djGrbxjjbBnGONE1hC4GwFAmS7fOpK9Z9wrvPO2G+KW6b5HuI8WLmNQCvd0JCwuXUQFOJi//1DBG36TFescRduY5VXs1H9mSI30vTqSv3yW1a0C/i5OQ4kVMerJ05HyaZBjjpDJt7iIaVD881W7M5Xv1jiOAutZuyho68FK6CaqzFS9O0u8CUrwIQXp8EFst2lkTyKgAp+BRo/2w7JZhjJNCUqg/+5QUAOrkvBenkF2mLRldF1yCYumGgDiYMl3nVKdI8SImvYUJwRxQk2lVvaCzUUYF6EwbxpgLQOAMmWc0GRgMCieCtULVWrJN5zQCYE+p7XwXL20wKtNWO8UW6T5SvIhJLyHEm0AfL3bIqACnkFdcwXSOAzAlxTl2Ngj7MyZphWpoYw7InCPdaTuNVOZ2OF+/C0jxIgSKopA+qO9li655Jruq/mGMUTKMcRJJSllIg+qHh9qFWpmtd5xJrbPHQl5lM4lKDT4dFU61RbqPFC9CAAsTgthqtfW9VOySUQF6KtcG9DWFyDDGyWRebBC7Va3vpalAdv3p6cDxJnqtKld425aM4jLBw1ffUF8hxYsQQHp8MOVqOBWEg4wK0I02jDEHAK/kZfqGEQ7l6Wakwl8rWHsKt+qcZnLbazvf5RIPW/EydbWOac5MihchgDnR/ribDHzRO0e7QfpedFFU08gctRCAiDlyON1koyYsByCoYZ/0vehob1kjnnQzvUub6u5MW6T7SPEiBOBhMpIaEyDnveis+NBOvJVu2hRf3MJn6R1HOFjCzHTqVX/c1W6QvhddWK0q+8oaWWLIx2TtAf8YCHW+wahSvAhhkx4fTJZ1NlYMMipAJ51FMoxxMktPCGanVStau459oXOayenYiTZaunq5yO2gdoOTbZHuIz8dhLBZGB9ECz4UGKZpN8ioAIcLrJdhjJPZFF8PCr3nA9AhxYsu+uYZXWiyFS9OtkW6jxQvQtikxwcBsKlHznvRQ13LgGGM0u8yaZljtEZtv7ps6O3WOc3kk13WSIJSTYSlGgxukOSc/xaleBHCJsjHneRQHxkVoJP8ggHDGBNlGONkFTt9PnWqP27Wbqjcp3ecSWdv2UlWGmyNunFLwMNP30BnIcWLEAMsjNdGBXQZfWRUgIM1yjBGASxMDGaXVTvvxVIsW6Ydqbali4qTnaw0Ou8uoz5SvAgxQHpCEBaMHDDZrr7I0pHDeFRrx5D3RMowxsksaYovB0zakQUdR7foG2aS2VvaiAc9ZBoKtBuctN8FpHgRYpCFtr6XDzts23RlVIBDtHX3kmgbxhg8y7mOIReOZTAodEZmAuBVK30vjrS7pIFMQz4e9IB/NIQ573EFUrwIMUDiFB9CfNz5vNd23ouMCnCIA8fKmK5owxiDZ0rxMtlFT5tPnRqAySrnvTjSrpKTrOjrd5nqnFuk+0jxIsQAiqKwMCGIcjWcZs8YGRXgIDV52zAoKvVu0eAbpnccobPFSSH9572oJdL34gjNHWaO1Lay0pCj3eDE/S4gxYsQp1mcGAJAtmm+doP0vdhfhTaMsTUsXecgwhnMjQ5gr6IdWdB5VM57cYS9ZSeJo4ZEQy0YTJDonFuk+0jxIsRXZCQGA/Be6wztBile7Kq710JUi3Ygls80GcYowN1koD1CO6jQvSYbzF06J5r4dpcO3CKdCZ7++gY6BylehPiKWZH++HqY+Kx7JqoiowLsLbe8nlRFG8YYKs26wiZmWion1EDpe3GQ3SUnTy0ZOeEU6a+S4kWIrzAatL6XFnw44W+bMi2jAuym+NAuvJVuOgy+KE44AE7oY3Gi9L04SkdPL0eP15Fp0E64dvZ+F5DiRYgzWmxbOtpjmK/dIEtHdtNTvAOAhuD5MoxR9EuLC2K3qh1W110oxYs95ZQ3sZB8PBUzql8UhKXoHemc5CeFEGewOEErXt5snq7dIKMC7MJiVZnSuB8A94SlOqcRzsTL3UhTWAYAbtV7pe/FjnYNWDJSnHSK9FdJ8SLEGcyNCcDDZGBrRzwWdz8ZFWAnBVXNzOcIAFNSpN9FDBYzdR4n1ECM1h6o3Kt3nAlr96DzXZx/yQikeBHijDxMRtLiArFgpCrIdlx9kfS9jLf8gkNEKI30YsQYI9ukxWAZSSFk2eYcUbJN3zATVE+vlfqKApIMNagGEySt1DvSsEjxIsRZ9J33spNU7QYpXsZd27HtANT7zQJ3b53TCGezID6IXbam3Z4i6Xuxh9zKZjKt2tItsRlOv0W6jxQvQpxF33kvrzdO026QUQHjSlVV/OtsW2DjMvQNI5xSgJcbdSGLATBWSd+LPewZcL6L4gK7jPpI8SLEWaTFBWIyKOxtCaTXP15GBYyzorp2Zlu06bUhcr6LOIvo5DnU9vW9HN+jd5wJZ19Rzakt0i7S7wJSvAhxVt7uJubGBABQHqSd9ilbpsdPzrFSZtiGMbrJTiNxFhlJIezs63splb6X8WSxqijl2/FSejB7R0D4bL0jDZsUL0IMoe+8l+1W25RpKV7GzcnDX2JQVBo9Y2QYozirRYnB/U27vdL3Mq6O1LSS0bsPAOP0i1xii3QfKV6EGEJf38sbJxNBRgWMK/cqbQmgJ3KRzkmEM5vi60FloLYTzVC1F8ydOieaOHaXNPRvkTZMd50lI5DiRYghpccHoyhwqEHBHLFAu1FGBYxZZVMn03vyAAiccZ7OaYSzi0maTY0ahMFqlr6XcVR07BDJhmositFltkj3keJFiCEEeLkxM0LbOlgSYNsRI0tHY7a3qJb5hiIAPJKk30UMbXHSqTlHlG7XN8wEoaoqvuVbAGgPSwfPAH0DjZAUL0KcQ9/S0RcWW9+LjAoYs4qC3Xgr3XQa/WDKDL3jCCe3ODGELKvWTGoplr6X8VBS385Cs3ZUgVfKJTqnGTkpXoQ4h76m3bdPRICHv4wKGAdq+U4A2sMWyDBGcU7RgV6U+KQBoFTuhZ4OnRO5vt3Hqllq0JZu3WZcrHOakZOfGkKcwyLbkMaCEx30xC3XbpTTdketurmTxM5DAPhOW65zGuEqYpJSqFaDpe9lnDTkf46X0kObeyiEz9E7zohJ8SLEOYT6eZAU6oOqQqGfzDkaq51F9Sw2aMMYPaXfRQzTkuQp0vcyTlRVJajyCwA6Yle61BbpPlK8CDEMmUnanKNN3bZDnGRUwKiV5e0kTGmix+AJMbJNWgxPZvKpIY3S9zI2RXXtZFi0fpfA1K/pnGZ0pHgRYhgyk7Xi5aNKLwhKkFEBY+Bbru3Wao5cBiYPndMIVxEb7E1pX99LVbb0vYxB7qED2hZpDLhPu0DvOKMixYsQw7DEduXlcE0rXXG2OTyyZXrEKps6SevW+hX85l6mcxrhauKmzqaqv+9lt95xXFZ3wccA1PinglegvmFGSYoXIYZhiq8HM8L9AMjzWqjdKMXLiGXnF5KmFALgOcv1tmcKfWUmTxkw50j6XkZDVVWi6rTvnTp1tc5pRk+KFyGGqX/pqG2ajAoYpba8jRgUlVrvaRAQrXcc4WIG9r30St/LqByrrGehqu32C1twuc5pRk+KFyGGqa94+bysB6JtV19kVMCIhFZvAaAr0XVf8Qn9RAV6UeGvjekwVO2DnnadE7me0v2f4q1002gIxj06Ve84oybFixDDtCQxBEXROvXbY6TvZaQq6ltYbNEm2IYtuELnNMJVJU5NoVIN0fpeKqTvZaQMhZ8CUBO23CW3SPeR4kWIYQrwdiMlUptzlO2m7XqQUQHDd2zf5wQoHbQqfnglLtE7jnBRct7L6FmtKknNWQC4z1yjc5qxkeJFiBHoO+9lY2OUjAoYIfWItsOhImQpGIw6pxGuKjMppL9pt7f4C53TuJaiY/kkUUmvaiBukWvv9pPiRYgRWDpVK16+LGmGxL6lI+l7ORdVVYk/qb1KNk6XXUZi9ML8PakK1HrODFX7pe9lBE7s/wCAIs8U3HyCdE4zNlK8CDECixKCMRoUyho6aIqUOUfDVVl2lKlqGRZVIW6x9LuIsUmcOovj6hQMaq922rUYFp9y7WdVU9QKnZOMnRQvQoyAn6cbc6IDAMhSbJ36MirgnGr2vg/AMfdZeAWG6pxGuLrM5FB2Sd/LiFh6upjeoTXMB85zzZEAA9m1eDl58iQ33XQT/v7+BAYGcscdd9DW1jbk56xcuRJFUQa93X333faMKcSILLVtmf60xkdGBQyTZ4m2w6Eu0vVf8Qn9LUkK7j/vxVwkfS/DUZ7zKd50U6cGkjw3U+84Y2bX4uWmm24iLy+PTZs28cEHH7B161buuuuuc37enXfeSXV1df/bb3/7W3vGFGJE+pp2dxY3oCat0m6ULdNnZe3pZGq7bQjcPNc9FEs4jxBfD04Ea0M9jdU50D30i2IBLbkbATjil4HJ5PoN83YrXgoKCti4cSPPP/88GRkZLF++nCeffJLXXnuNqqqqIT/X29ubiIiI/jd/f397xRRixBYmBOFmVKhs6qQubJl2oxxWd1YV+z/Bkx6q1RBmpLr+Kz7hHJKmpUjfywiEVGsnEpsTXXMQ41fZrXjJysoiMDCQhQsX9t+2evVqDAYDu3YN/T/aK6+8wpQpU5gzZw5r166lo+Ps00O7u7tpaWkZ9CaEPXm7m5gfGwjAF+ZZ2qiA+qMyKuAsWnM3AHDEbwnubq7/ik84h+VTZc7RcHXVlxHTa2uYd/Et0n3sVrzU1NQQFhY26DaTyURwcDA1NTVn/bwbb7yRl19+mc8//5y1a9fyz3/+k5tvvvmsj1+3bh0BAQH9b7GxseP2dxDibJZP1ZpOPy/rllEBQ1FVwqq1ngRzkowEEONnSXIIu1WteOkulDlHQzm++10ADhlmkBQbo3Oa8THi4uXhhx8+raH2q2+HDx8edaC77rqLNWvWMHfuXG666Sb+8Y9/8Pbbb1NUVHTGx69du5bm5ub+t4oKefUr7O+86VMA+LKwAav0vZxVd00BYZYaulUT8Ytcf4eDcB6+HibaIrSTmt1qc6TvZQjWY5sAqJyyHMWFRwIMZBrpJzz44IPcdtttQz4mKSmJiIgITpw4Mej23t5eTp48SURExLCfLyMjA4DCwkKSk5NPu9/DwwMPD49hfz0hxsO86AD8PE00d5op9F/MdDg1KkBOj+1Xvfc9EoB9htksiQnXO46YYGbMnEPF1lBiDXVQsROmytW90/T2ENO4BwDPFNceCTDQiIuX0NBQQkPPfU5DZmYmTU1NZGdnk56eDsBnn32G1WrtL0iGIycnB4DIyMiRRhXCbkxGA8uSp7Axr4ZPmqKZPnBUQHS63vGchnLsEwCqw86fMK/4hPNYPm0KO7fMItZQh7VkOwYpXk7TcnQb/nRSpwYwJ3253nHGjd16XmbNmsUll1zCnXfeye7du/nyyy+57777uOGGG4iKigKgsrKSmTNnsnu3Nhm0qKiIX/7yl2RnZ1NaWsp7773Hrbfeyvnnn8+8efPsFVWIUVk+TVs62lrUJKMCzqSrmeiWHAC8Z1+qbxYxIaXGBJBjmgNA59Et+oZxUnW2kQD73dMJ8/fWOc34ses5L6+88gozZ87kwgsv5Gtf+xrLly/nb3/7W//9ZrOZI0eO9O8mcnd359NPP+Xiiy9m5syZPPjgg1xzzTW8//779owpxKicZyte9pc30hVvO3xNipd+7QWfYsJCkTWS+alyNUqMP5PRgCVWu5rgVXdQTro+g76RAK2xq3ROMr5GvGw0EsHBwbz66qtnvT8hIQFVVfs/jo2N5Ysv5LRE4RriQ3yIC/am/GQH+0xpLIVTowI8/PSOp7vGnPfxAfZ7LubaAE+944gJanbKbMrLQokz1EH5LpgmS0d91KYKIrpLsKgKYfMn1kBUmW0kxBj0LR19Uu0towIGsloJqNReiLTHXahzGDGRnTcttP+8lx4ZFTBIQ86HAOSo00ifmaRzmvElxYsQY3C+rXjZXlgPsmX6lOoc/HpP0qp6EZM6MU70FM4pPsSbo17akNTOY1K8DNSRr40EKPRfgre7XRdaHE6KFyHGIDN5CgYFCk+00Rhp6+SXw+poPqidqvulOpeM6bJTUNiPoiiYkrWGeb+GQ9L30qe3h7C6LO39aRfpm8UOpHgRYgwCvNyYFxMIwBYZFdDPXPARACVBy/D1mFiv+ITzmZsyhzJrGAYsUL5T7zhOwVKWhafaSZ3qz/T5y/SOM+6keBFijPqWjj4r7ZFRAQBtJ5jSkgeA1wQ6FEs4r2VTQ9hpGxXQdmSLvmGcxIl92hbpnUoa82KDdU4z/qR4EWKMlk/TDm3cfqxORgUA5sMfA5BrTWDR3BSd04jJINDbnepAbTt+d6H0vQCYijcD0BB1PkbDxDsgUooXIcYoLS4QP08TjR1mCv0Wazf2jQqYhJps/S67TAtJifTXOY2YLHxnrgQgsCkPulr0DaO35uOEdhZhURWmpE6sLdJ9pHgRYozcjAbOt1192dAYBQNHBUw2FjN+ldqE34741TISQDjMonnzKLWGY8SKuXSH3nF01ZKr9ZzlqFPJnD1N5zT2IcWLEONg1cwwAD47cnJyjwoo34mnpZ161Z/k+efrnUZMInOjA8gxaqMCThz8VOc0+uorXg77ZhDiOzEHF0vxIsQ4WDFdu/KSW9lMa/R52o2TsHhpzdWWjLZZU1k+PUznNGIyMRgU2iOXAKCUTeKDInt7CLFtkVamTrwt0n2keBFiHIT6eTAvJgCAbda52o19owImEcsRrVm3NHgZAV5uOqcRk03YPG00QHj7Yehq1jmNPnrLduJl7aBO9WdW+nl6x7EbKV6EGCcrZ2hXGjYc95qcowIaSwlsL6ZXNeA7Z2I2CQrntmjenP6+l/r8ybnr6MQ+bZDxLmX+hNwi3UeKFyHGyaoZ2tLR1qN1WBJXajdOoi3TZttVl2x1OpkpE2uOinANgd7uFPqkAZO378VUov3MaYhaMSG3SPeR4kWIcTIvJpBgH3dau3sHbJmePH0vrf1bpBcxO0q2SAt9qPHaabJeVZPwpN3mSsI6Cm1bpC/VO41dSfEixDgxGpT+xt0NbdMm16iAng78qrUmQXPShbJFWugmLl071Tmu+yjdbY06p3GsJtsuowNqMktmT9U5jX1J8SLEOFppWzr6uLBrUo0KUEu+wE3t4bg6hXlpmXrHEZPY9KnTKScSo6JydM8nesdxqOaDHwJw1G/JhN0i3UeKFyHG0YrpoRgUOFLbSnNU35bpid/30nRAWzLaqqb1j0sQQg+KolATrL1waM6f+C8c+lnMhNq2SLvNnPgzxaR4EWIcBXq7syhB6/DfZtUOzJrwowJUFWPRJgDqIlfg5W7UOZCY7HymrwQgpH43qqrqG8ZB2ou+xFvtoF71Z37GSr3j2J0UL0KMs4tnRwDwr8rQAaMCDuicyo5OFODfXUOX6kZ02sV6pxGC5MXaVv3p1mLyist1TuMYVXu0LdL73RaQHDbxG+aleBFinF2cEg5AVmkLPbHLtRsn8NJR36m6WdYUVsxO0DeMEIBncAy1bjFa38vuTXrHcQjvcm2JrDNupb5BHESKFyHGWWywN7Mi/bGqcMgrXbtxAo8K6Dr0AQBHA5YR6jexmwSF6+iI0hrH1ZJtOiexP3PjcaK7i7CqCnGLr9A7jkNI8SKEHfRdfXmzabp2w0QdFdB2gpAmbUnMc87lOocR4pTwudqogOldOZQ1tOucxr5Kd70HQL6SzNzpyTqncQwpXoSwg4tn24qXUjesgQkTdlRAd/6HGFA5aE1kado8veMI0c97xkoAZitlfHGgUN8wdmY+rJ1uXR26fEKfqjuQFC9C2EFKpD/RgV50ma1UBmdoN07Avpem/e8AsMdjCVPDfPUNI8RAfhE0eydgUFSqD27WO43dqL09xDXtBsB/3mU6p3EcKV6EsANFUfqvvmw2922ZnmB9Lz3tBNVoV5Ms074mp+oKp2NKPh+AKfW7aWjr1jmNfZQe2IIvHTSqfsxbtFLvOA4jxYsQdnJxirZl+u/HY1En4KiAnqOf4a72UGENZWHGcr3jCHEan+krAMgwFLC54ITOaeyjNlvbIn3UbzFenu46p3EcKV6EsJNFCUEEebtR0elOa0iqduMEuvpyYu9bAOxwW0xaXJDOaYQ4gwStqE5Ryvj8wFGdw4w/VVWZUrMVALcZk+uMJSlehLATk9HQf/Vlj3G+duNE6XuxWgio0P4u3cmXypKRcE5+EfQETcWgqKglX9LY3qN3onF1tPAoU62lWFWFGcuv0juOQ0nxIoQdXZ4aCcDLdbbtixNkVEB3yQ78LE00qT7MzrxE7zhCnJW7re9lkZLPx3k1OqcZX8U73wWgzHM6PkEROqdxLClehLCjzKQQQnzc2dYRR6+b74QZFVC3fT0A24xLSIufonMaIYZgWzpaYshnQ261zmHGj6qqeJVqy9A9iRfqnMbxpHgRwo5MRgOXzImgFxOHPdO0G1196cjcSUjZhwA0TL0GwyQ5V0K4qHiteJmllJNXVDZhdh3lV55kQW8OAHGLv65vGB1I8SKEnV0+LwqAd1pnaDe4+KgAc/77eFnbqbCGMidzjd5xhBiaXzhMmYFBUVlIPhsnyNLRgaxP8Fc6aDP445WwWO84DifFixB2tjgxmFA/Dz7pnq3d4OKjApqy/gnAJ6aVLIgP0TmNEMPQv3RUwAcHXH/pSFVVrEe1gZNNUeeBwahzIseT4kUIOzMaFL42J4JyNZx6tyjXHhXQWktIzXYAzHOukyUj4RoGFC+7Sho40dKlc6Cx2V/RRFr3XgBC50+eU3UHkuJFCAe4PFVbOvqsJ0W7wUX7Xjqz/4UBK9nWaaxcmql3HCGGx1a8zDSU46e28d6BKp0Djc2mXQeYbSgDwGPm5DrfpY8UL0I4QHpcEDFBXq49KkBV6dmj7TL60uciZkb46xxIiGHyDYPQmRhQWWIo4M19lXonGrWeXisd+dogxpbgueAbqnMifUjxIoQDGAwKVy+IIcs6GysuOirg+B4C2ovpVN3xW3i93mmEGBnb1ZelxgIKqlvIr2rROdDobDlygkW92QD4zp68ZyxJ8SKEg1yzIJoWfNhv7TuwzrWuvrRlvQDABusSLl04U+c0QoyQrXi50EsbE/D2/uN6phm1d/eVc54hFwDD9Mm5ZARSvAjhMPEhPixKCGKbda52gyv1vXS34n74HQDyI75ORICnvnmEGCnbeS8xPcUE0srb+6votVh1DjUyzR1mTh75kgClg16PQIhO1zuSbqR4EcKBrlkQwzaLVryoLjQqQD30Fu7WToqskcxaLGe7CBfkGwqhswC40LuQ+rZuthXW6xxqZDbkVrOM/QCYpl04KbdI95HiRQgH+tq8SA4bp9GieqG40KiAtqwXAXibVVxqO3RPCJdjWzr6ZkgJAG9mu9bS0Rt7K1hpsP3MmHqRvmF0JsWLEA7k7+nGhbO1xl0ACjfrG2g4ThTgV78fs2qkK+Wb+HqY9E4kxOjYipdUyyEAPsmv5aSLTJrOr2qhsqKUOYZS7Yapk2+e0UBSvAjhYNcviuUzqzbnyJL/rs5pzq1r90sAfGZN4/JlafqGEWIs4pcB4HnyMMsitW3HrnL15bU95aww2q66RM7Xtn9PYlK8COFgmUkhHA48n17VgLE2FxqK9I50dr3dcOB1AL4MuIzUmACdAwkxBgP6Xu5OrAXg1d3lqKqqZ6pz6ujp5e19laeWjKZN7iUjkOJFCIczGBSuWDKHHbalIzXvHX0DDUE9/CGe5kZq1CCmZX4dRZFxAMLFJZ4HwBIlD18PEyX17WQVNegcamgfHKymo7ubFUZti/Rk73cBKV6E0MU1C2LYRAYAnQfe0jnN2TXv0M52eVtdydcXxOucRohxYOt7cavYwTfSogF4ZVe5nonO6dVd5cxXCvGjHTwDIWah3pF0J8WLEDoI8nGHWVfQqxrwbjgEJ0v0jnS6hiL8q7YB0DbregK83HQOJMQ4sPW9cCKfW+b5APBxXo3TDmvcX95ITkUTF5oOajckXzCpt0j3keJFCJ1ctSyVnVZt/b1t/390TnO61q1PYUDlc0sqV16wXO84QowPnykQpg1Ind51kEUJQfRaVdZnleqb6yz+vl17YXOFT552g/S7AFK8CKGbBXGBHAxYBUBX9r/AmZoGu5pxz/0XALvCr2d6uJ/OgYQYRwla3wsl27hjeRKgLR119PTqGOp0VU2dfHSohlCaiO3SxhowdbW+oZyEFC9C6ERRFKauuoUO1YMpHUV0H9uid6R+3Xv+gYe1g6PWaBZfeI3ecYQYX7a+F0q3c1FKOPEh3jR1mJ1u2/T6rFIsVpXvRBRrN0SmTvot0n2keBFCRxemzWCjm3b15eTGx53j6ovVQs+XfwXgPa+rWDkjXOdAQoyzvr6XugKMHfV8Z1kioC3RWK1O8G8QaO/u5V+2RuJv+OVrN8ouo35SvAihI6NBQV3yfbpVE5End2M5/KHekTDnf4BfVxUnVV9iVnwbg0G2R4sJxicEwmynXJd9ybXpMfh7miht6OCT/Bp9s9m8vLOMlq5ekkM8Ca/bod0o/S79pHgRQmeXnr+El5XLAej84GHo1fe48pOb/w+A94xr+MbiqbpmEcJubOe9ULoNHw8Tt2YmAPDnzYW6H1rX2WPhuW3aUtH/pLajdDWBZwBEyxbpPlK8CKEzb3cTvUt/RJ0agG97OZZdz+qWxXx8P+GN2ZhVI17L7sLDJFsyxQQ1oO8F4I7lifh6mMivbuGT/Fodg2mn/ta39RAb7MWKvlN1ky8Ao8wV6yPFixBO4KYVc/iL4UYALJ//BtrrdclRufEPAHxqyOTr5y3SJYMQDtHf93IY2uoI8nHntqUJAPzfp8d0u/rSZbbwzBfayJB7V07FWPSpdof0uwwixYsQTsDXw0TE+XdwyJqAe28r1s9+5fAM3U1VRB/Xem46F9yFl7tcdRETmHcwhM/R3i87/erLx3n6XH15ZVc5da3dRAd6cfV0d6jO0e6QLdKDSPEihJO4dWkifzJ9R/sgez3UHHLo8+e9+0fc6OWgMoNL11zu0OcWQhcDznsBBl19+e3HhzFbrA6N09xh5snPjgHw/Qum4l76uXZHxDzwk11/A0nxIoST8PEwsfSCr7PBshgDVno3/Bisjvnh2dzSSkLJawC0pt0pV13E5PCVvheAu1YkEeLjTnFdO//MKnNonKe2FNLUYWZ6uC/XLYyFwk3aHbLL6DRSvAjhRG7JjOcV//+iQ/XAVJEF2S845Hm3vPlXgmnhhDKFjEu/7ZDnFEJ38UsBBeqPQNsJAPw93Xjw4hkA/OnTozS2O2b3X3lDBy99WQrA2ktnYcQKRZ9pd0q/y2mkeBHCibgZDXz3ygv4be/1AFg/eQSaKuz6nHnldaSUrAegLfUOTG7udn0+IZzGwL6XAVdfrl8Uy8wIP1q6evnDpqN2j6GqKv/v3UP0WKwsnzqFlTNCoTIbOhu1LdIx0jz/VVK8COFkVkwP5fjUm9lrnY7B3I76/v12O3nXalU59q+HmGaopNUYQNKae+zyPEI4rf7zXk4VL0aDwiNXaMMbX95VRnZZo10jfHCwmq1H63A3GvjFlbNRFAWO2ZaMklbJFukzkOJFCCf0s6/P4RH1brpVN5SiT+HAa3Z5ns/efp6rOt8CwPK1P4FXkF2eRwin1d/3sm3QzUuTp3D1gmhUFR76zwG6zBa7PP3J9h5+8YF2/P/3ViWTFOqr3SH9LkOS4kUIJxQf4sP1l17I//VeDYDlo4ehdXy3bhYdPkDGwZ8BkJ94K4HpV4/r1xfCJcRlovW9HD3t39gjl6cQ6udBUV07T3xyZNyfWlVVHvrPQepau5ka5ss9K5O1O9rqoGq/9r5skT4jKV6EcFK3LInnQNwtHLImYOxuwrLhwXH72h3tLShv3Iqf0slRjznMuumJcfvaQrgU72CIGHzeS59Ab3ce/8ZcAJ7bVsKmcT5595Vd5XxaUIu70cD/3TD/1InWRZu1PyPmgl/EuD7nRCHFixBOymBQ+P0NC/m16V7MqhHj4fdR894Z89dVrVYOPHMnSdZSGggg5LZXUUzSpCsmsYTztT9Lt59210Up4dy+LAGAB9/IoayhfVyeck/pSX7+fh4AD10yg9lRAafuLJRTdc9FihchnFhkgBffv/FqnrVcAUDnOw9Ax8kxfc1Nrz5BZutGLKpC3ZqnCYmMH4+oQriuvr6Xkm1nvHvtpbNIiwukpauXb7+wm/q27jE9XXlDB9/9ZzZmi8qlcyL4zrLEU3daLVBou/Ii/S5nJcWLEE5u6dQp+Fz8U45Zo/E2N1D08g9G94WqD3LouTtZcew3AOTN+D4zMy8bx6RCuKh4W99LwzForTntbneTgWduTicmyIvShg5uf3EPzR3mUT1VeUMH33puJyfbe5gbHcAfvjkfg0E59YCq/dB5EjwCIGbxKP9CE5/dipdf//rXLF26FG9vbwIDA4f1Oaqq8sgjjxAZGYmXlxerV6/m2LFj9ooohMu4/fwZ7J73c6yqQnLV+3z68m+HNziuqwX2/B312RXw7HnMqXwDD8VMUcgq5t3wc/sHF8IVeAVp/SUAxz6BnnYwd0JvN1jMYOkl3Nedf9y+iGAfd3Irm7n2mR1UNnWO6GmO1rZy/d+yqGzqJHGKD89/e+Hpp1n3bZFOXilbpIegqHYanfnoo48SGBjI8ePH+fvf/05TU9M5P+c3v/kN69atY/369SQmJvKzn/2M3Nxc8vPz8fT0HNbztrS0EBAQQHNzM/7+/mP8WwjhPFRVZfez3yOj5lUA9vucR+KtfyUwPO6rD4SKXbDvH5D3Npg7AOhRjXxiXYh53i1845qbwCAXXoXo9/nj8MVvzvkwFQULCqqqoCoKRqMRo8EIigFQtD+Vvj+191XFQFevSlOnBQsKJoOBUH/PU5838HPqDmtP9PW/wIJb7Pt3djIj+f1tt+Klz0svvcT9999/zuJFVVWioqJ48MEH+fGPfwxAc3Mz4eHhvPTSS9xwww3Dej4pXsSEZrVw8LVHmHXkadwUCy34sH/WT5h/xb0EqC1w4F9a0VJ/6lTQIqJ51bySDzifB65ayvWL4oZ4AiEmqaYK+NtK6KjXOwkExMJ3t2o7oSaRkfz+dpprUiUlJdTU1LB69ak97QEBAWRkZJCVlXXW4qW7u5vu7lPNUy0tLXbPKoRuDEbm3fhrjhy4HOXd+5huLWRFwWMczX8eH6UGE70AdCkevN+7hH/1rmKfOo1ZkQH8/dp5zIkOOMcTCDFJBcbCj4+CpQdUq3YFU7UOeFOBU7d19Zj56+fHeCu7Au16jJXYQE9mhPvg626kuaObozXNNLZ3Y0DF3ahw46IYrlkQhUlh0Nca/BxAVBp4+Or3vXABTlO81NRoTVLh4YPHfoeHh/ffdybr1q3j5z+XtXsxucxIzcSckkXOm+uYdfgvTFeOA3DAmsTrllW8Z8mkDW9mRvjx+/OSuHJ+FG5GWSYSYkgGIxi8hvVQT+CBa2O5/LxWnvyskI/zaqhotLKjceAjPPF2N3L1gmi+e34yscHedgo++YyoeHn44Yf5zW+GXhMsKChg5syZYwo1EmvXruWBBx7o/7ilpYXY2FiHPb8QenFzc2f+DY9Cw83U7/k3BzzSOUwiUarKL4O8SI0JPHXUuBDCLqaH+/Hkt9Jo6TKzv7yJY7WtdPRYCPByY2qYLwsTgk4dPifGzYiKlwcffJDbbrttyMckJSWNKkhEhHaKYG1tLZGRkf2319bWMn/+/LN+noeHBx4eHqN6TiEmhJBkplzyMBcCF+qdRYhJyt/TjRXTQ1kxPVTvKJPCiIqX0NBQQkPt8x8mMTGRiIgINm/e3F+stLS0sGvXLu65RybdCiGEEEJjt0Xw8vJycnJyKC8vx2KxkJOTQ05ODm1tbf2PmTlzJm+//TYAiqJw//3386tf/Yr33nuP3Nxcbr31VqKiorjqqqvsFVMIIYQQLsZuDbuPPPII69ev7/84LS0NgM8//5yVK1cCcOTIEZqbm/sf89BDD9He3s5dd91FU1MTy5cvZ+PGjcM+40UIIYQQE5/dz3lxNDnnRQghhHA9I/n9LXsnhRBCCOFSpHgRQgghhEuR4kUIIYQQLkWKFyGEEEK4FClehBBCCOFSpHgRQgghhEuR4kUIIYQQLkWKFyGEEEK4FClehBBCCOFS7DYeQC99Bwa3tLTonEQIIYQQw9X3e3s4B/9PuOKltbUVgNjYWJ2TCCGEEGKkWltbCQgIGPIxE262kdVqpaqqCj8/PxRF0SVDS0sLsbGxVFRUyHylM5Dvz9Dk+3N28r0Zmnx/hibfn6Hp/f1RVZXW1laioqIwGIbuaplwV14MBgMxMTF6xwDA399f/oEMQb4/Q5Pvz9nJ92Zo8v0Zmnx/hqbn9+dcV1z6SMOuEEIIIVyKFC9CCCGEcClSvNiBh4cHjz76KB4eHnpHcUry/RmafH/OTr43Q5Pvz9Dk+zM0V/r+TLiGXSGEEEJMbHLlRQghhBAuRYoXIYQQQrgUKV6EEEII4VKkeBFCCCGES5HixQE2bNhARkYGXl5eBAUFcdVVV+kdyel0d3czf/58FEUhJydH7zhOobS0lDvuuIPExES8vLxITk7m0UcfpaenR+9ounnqqadISEjA09OTjIwMdu/erXckp7Bu3ToWLVqEn58fYWFhXHXVVRw5ckTvWE7pf//3f1EUhfvvv1/vKE6jsrKSm2++mZCQELy8vJg7dy579+7VO9aQpHixszfffJNbbrmF22+/nQMHDvDll19y44036h3L6Tz00ENERUXpHcOpHD58GKvVyrPPPkteXh5//OMfeeaZZ/jpT3+qdzRdvP766zzwwAM8+uij7Nu3j9TUVNasWcOJEyf0jqa7L774gnvvvZedO3eyadMmzGYzF198Me3t7XpHcyp79uzh2WefZd68eXpHcRqNjY0sW7YMNzc3PvroI/Lz83niiScICgrSO9rQVGE3ZrNZjY6OVp9//nm9ozi1Dz/8UJ05c6aal5enAur+/fv1juS0fvvb36qJiYl6x9DF4sWL1Xvvvbf/Y4vFokZFRanr1q3TMZVzOnHihAqoX3zxhd5RnEZra6s6bdo0ddOmTeqKFSvUH/7wh3pHcgr//d//rS5fvlzvGCMmV17saN++fVRWVmIwGEhLSyMyMpJLL72UQ4cO6R3NadTW1nLnnXfyz3/+E29vb73jOL3m5maCg4P1juFwPT09ZGdns3r16v7bDAYDq1evJisrS8dkzqm5uRlgUv6/cjb33nsvl1122aD/hwS89957LFy4kOuuu46wsDDS0tJ47rnn9I51TlK82FFxcTEAjz32GP/v//0/PvjgA4KCgli5ciUnT57UOZ3+VFXltttu4+6772bhwoV6x3F6hYWFPPnkk3z3u9/VO4rD1dfXY7FYCA8PH3R7eHg4NTU1OqVyTlarlfvvv59ly5YxZ84cveM4hddee419+/axbt06vaM4neLiYp5++mmmTZvGxx9/zD333MMPfvAD1q9fr3e0IUnxMgoPP/wwiqIM+dbXrwDwP//zP1xzzTWkp6fz4osvoigK//73v3X+W9jPcL8/Tz75JK2traxdu1bvyA413O/PQJWVlVxyySVcd9113HnnnTolF67g3nvv5dChQ7z22mt6R3EKFRUV/PCHP+SVV17B09NT7zhOx2q1smDBAh5//HHS0tK46667uPPOO3nmmWf0jjYkk94BXNGDDz7IbbfdNuRjkpKSqK6uBiAlJaX/dg8PD5KSkigvL7dnRF0N9/vz2WefkZWVddocjYULF3LTTTc5feU/WsP9/vSpqqpi1apVLF26lL/97W92TuecpkyZgtFopLa2dtDttbW1RERE6JTK+dx333188MEHbN26lZiYGL3jOIXs7GxOnDjBggUL+m+zWCxs3bqVv/zlL3R3d2M0GnVMqK/IyMhBv6MAZs2axZtvvqlTouGR4mUUQkNDCQ0NPefj0tPT8fDw4MiRIyxfvhwAs9lMaWkp8fHx9o6pm+F+f/785z/zq1/9qv/jqqoq1qxZw+uvv05GRoY9I+pquN8f0K64rFq1qv+qncEwOS+Wuru7k56ezubNm/uPGrBarWzevJn77rtP33BOQFVVvv/97/P222+zZcsWEhMT9Y7kNC688EJyc3MH3Xb77bczc+ZM/vu//3tSFy4Ay5YtO21b/dGjR53+d5QUL3bk7+/P3XffzaOPPkpsbCzx8fH87ne/A+C6667TOZ3+4uLiBn3s6+sLQHJysrxqRCtcVq5cSXx8PL///e+pq6vrv28yXm144IEH+Pa3v83ChQtZvHgxf/rTn2hvb+f222/XO5ru7r33Xl599VXeffdd/Pz8+vuAAgIC8PLy0jmdvvz8/E7r/fHx8SEkJER6goAf/ehHLF26lMcff5xvfvOb7N69m7/97W9Of5VXihc7+93vfofJZOKWW26hs7OTjIwMPvvsM+ffQy90t2nTJgoLCyksLDytmFMn4TD466+/nrq6Oh555BFqamqYP38+GzduPK2JdzJ6+umnAVi5cuWg21988cVzLlGKyW3RokW8/fbbrF27ll/84hckJibypz/9iZtuuknvaENS1Mn4U1AIIYQQLmtyLqALIYQQwmVJ8SKEEEIIlyLFixBCCCFcihQvQgghhHApUrwIIYQQwqVI8SKEEEIIlyLFixBCCCFcihQvQgghhHApUrwIIYQQwqVI8SKEEEIIlyLFixBCCCFcihQvQgghhHAp/x+XTbP0Qaxo/gAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Predict\n", + "with torch.no_grad():\n", + " y_pred = model(x_train).numpy()\n", + "\n", + "# Plot\n", + "plt.plot(x, y, label='True')\n", + "plt.plot(x, y_pred, label='Predicted')\n", + "plt.legend()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Convert model to ONNX" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": {}, + "outputs": [], + "source": [ + "def convert_torch_to_onnx(model, onnx_model_path = 'model.onnx'):\n", + " data_size = (1, 1)\n", + " batch_size = 1\n", + " sample_input = torch.rand((batch_size, 3, *data_size))\n", + " torch.onnx.export(\n", + " model,\n", + " sample_input, \n", + " onnx_model_path,\n", + " verbose=False,\n", + " input_names=['input'],\n", + " output_names=['output'],\n", + " opset_version=12\n", + " )\n", + "\n", + "convert_torch_to_onnx(model)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Convert model to tensorflow" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "INFO:tensorflow:Assets written to: model_tf\\assets\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "INFO:tensorflow:Assets written to: model_tf\\assets\n" + ] + } + ], + "source": [ + "def convert_onnx_to_tensorflow(onnx_model_path = 'model.onnx', tf_model_path = 'model_tf'):\n", + " onnx_model = onnx.load(onnx_model_path)\n", + " tf_rep = prepare(onnx_model)\n", + " tf_rep.export_graph(tf_model_path)\n", + "\n", + "convert_onnx_to_tensorflow()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Convert model to tensorflow lite" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "metadata": {}, + "outputs": [], + "source": [ + "def convert_tensorflow_to_tensorflow_lite(tf_model_path = 'model_tf', tflite_model_path = 'model.tflite'):\n", + " converter = tf.lite.TFLiteConverter.from_saved_model(tf_model_path)\n", + " tflite_model = converter.convert()\n", + "\n", + " # Save the model\n", + " with open(tflite_model_path, 'wb') as f:\n", + " f.write(tflite_model)\n", + "\n", + "convert_tensorflow_to_tensorflow_lite()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Convert tensorflow lite to c++ file" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "metadata": {}, + "outputs": [], + "source": [ + "def save_tflite_model_as_c_header(tflite_model_path = 'model.tflite'):\n", + " with open(tflite_model_path, \"rb\") as f:\n", + " tflite_model_content = f.read()\n", + "\n", + " header_content = \"alignas(16) const unsigned char g_model[] = {\"\n", + " for i, byte in enumerate(tflite_model_content):\n", + " if i % 12 == 0:\n", + " header_content += \"\\n \"\n", + " header_content += f\"0x{byte:02x}, \"\n", + " header_content = header_content.rstrip(\", \")\n", + " header_content += \"\\n};\"\n", + "\n", + " with open(\"model.h\", \"w\") as f:\n", + " f.write(header_content)\n", + "\n", + "save_tflite_model_as_c_header()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "base", + "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.5" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +}