{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "IswZe43pElUI"
   },
   "source": [
    "Today we will build a single neuron (perceptron) from scratch to solve a biological problem: identifying Ribosome Binding Sites (RBS) in bacteria, based on the classic Stormo et al. (1986) paper.\n",
    "\n",
    "**Context:**\n",
    "1. Input $X$: a DNA sequence that we will one-hot encode\n",
    "2. Weights $W$: a matrix representing the \"importance\" of each base at each position\n",
    "3. Function $f(x) = X \\cdot W$. Based on this function (if $f(x) > 0$), we predict it as a ribosome binding site"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "wM0XQ_PZETdg",
    "outputId": "b934511f-dacb-45ee-de06-a590972633e9"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Libraries loaded!\n"
     ]
    }
   ],
   "source": [
    "# First, we need our imports\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import seaborn as sns\n",
    "\n",
    "# Fix random seed for reproducibility\n",
    "np.random.seed(42)\n",
    "print(\"Libraries loaded!\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "zUDx6syfBU_s",
    "outputId": "91a964ba-4a0a-4b22-aa1b-19c4cd0d0ed8"
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# For future purposes, we will introduce torch, a library widely used for machine learning\n",
    "# We will also check to see if cuda is available. This will be relevant later on\n",
    "\n",
    "import torch\n",
    "\n",
    "torch.cuda.is_available()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "4Z83gXWjGBON"
   },
   "source": [
    "Before we start coding, let's try out the math. Suppose we have sequence AG ($L=2$). Suppose our weight matrix is:\n",
    "\n",
    "$$\n",
    "W =\n",
    "\\begin{bmatrix}\n",
    "2 & -1 \\\\\n",
    "-1 & -1 \\\\\n",
    "-1 & 5 \\\\\n",
    "-1 & -1\n",
    "\\end{bmatrix}\n",
    "$$\n",
    "\n",
    "This matrix is $4 \\times 2$ and has rows corresponding to A, C, G, T.\n",
    "\n",
    "1. Perform a one-hot encoding on sequence AG.\n",
    "2. Calculate the dot product score: $\\sum (X_{i, j} \\times W_{i, j})$\n",
    "3. Does the neuron \"fire\" based on the score?\n",
    "\n",
    "(Double click here to type your answer)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "C2WEFMjTBY3I",
    "outputId": "0e0f80e3-2460-44c0-f8fb-102cf545d8ed"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Sequence: AG\n",
      "[[0. 0.]\n",
      " [0. 0.]\n",
      " [0. 0.]\n",
      " [0. 0.]]\n",
      "Sequence: AGGTCTGATTCCGTA\n",
      "[[0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]\n",
      " [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]\n",
      " [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]\n",
      " [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]]\n",
      "(4, 2) (4, 15)\n"
     ]
    }
   ],
   "source": [
    "\"\"\"\n",
    "We're now going to write a function to perform one-hot encoding. Your task is to complete the function below\n",
    "to convert a DNA string into a binary matrix\n",
    "\"\"\"\n",
    "\n",
    "def one_hot_encode(sequence):\n",
    "    \"\"\"\n",
    "    Converts a DNA sequence string into a (4, L) numpy array.\n",
    "    Mapping: A=0, C=1, G=2, T=3\n",
    "    \"\"\"\n",
    "    mapping = {'A': 0, 'C': 1, 'G': 2, 'T': 3}\n",
    "    L = len(sequence)\n",
    "    # Initialize a matrix of zeros with shape (4, L)\n",
    "    encoding = np.zeros((4, L))\n",
    "\n",
    "    for i, base in enumerate(sequence):\n",
    "        # TODO: Find the row index for this base using the mapping\n",
    "        # row_index = ...\n",
    "\n",
    "        # TODO: Set that position in the matrix to 1\n",
    "        # encoding[row_index, i] = ...\n",
    "        pass # remove this pass when you add code\n",
    "\n",
    "    return encoding\n",
    "\n",
    "# Test the function. The first test should be what you wrote for the previous\n",
    "# question\n",
    "test1 = \"AG\"\n",
    "print(f'Sequence: {test1}')\n",
    "encoded1 = one_hot_encode(test1)\n",
    "print(encoded1)\n",
    "\n",
    "# One more test\n",
    "test2 = \"AGGTCTGATTCCGTA\"\n",
    "print(f'Sequence: {test2}')\n",
    "encoded2 = one_hot_encode(test2)\n",
    "print(encoded2)\n",
    "\n",
    "# What shape are the matrices? Can you explain why we have one dimension of 4?\n",
    "# How about the length of the other dimension?\n",
    "print(encoded1.shape, encoded2.shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "HoV6OGwRIaUS"
   },
   "source": [
    "## The Forward Pass\n",
    "\n",
    "We need a function to calculate the score. This is just the sum of the weights at the \"active\"  positions (where the one-hot encoding is 1).\n",
    "\n",
    "Task: Implement the score calculation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "yO5RTJzjIs_K",
    "outputId": "9dfbdade-9c2e-4914-d63b-9a21f67d008b"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Random Score for AGG: 0.0000\n"
     ]
    }
   ],
   "source": [
    "def get_score(encoded_seq, weights):\n",
    "    \"\"\"\n",
    "    Calculates the dot product of the sequence and the weights.\n",
    "    Returns a single scalar number.\n",
    "    \"\"\"\n",
    "    # TODO: Calculate the dot product (or sum of element-wise multiplication)\n",
    "    score = 0\n",
    "    return score\n",
    "\n",
    "# Create a random weight matrix for testing\n",
    "L = 3\n",
    "random_weights = np.random.randn(4, L)\n",
    "score = get_score(one_hot_encode(\"AGG\"), random_weights)\n",
    "print(f\"Random Score for AGG: {score:.4f}\")\n",
    "\n",
    "# What shape should the weights be given the input? Please explain why\n",
    "print(random_weights.shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "fHwIZIVGI4HZ"
   },
   "source": [
    "## Generating data\n",
    "\n",
    "We need data to train our model. We will generate:\n",
    "1. Positives (RBS): Sequences containing the Shine-Delgarno consensus AGGAGG with some mutations\n",
    "2. Negatives (Background): Random DNA sequences\n",
    "\n",
    "Run the cell to create the dataset"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "vGHJKPmlI0re",
    "outputId": "d4725857-0764-493d-8396-1967f1872f8c"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Generated 1000 sequences.\n",
      "Example: CATAAGGGCT (Label: 0)\n"
     ]
    }
   ],
   "source": [
    "def generate_data(num_samples=1000, seq_len=10):\n",
    "    sequences = []\n",
    "    labels = []\n",
    "    consensus = \"AGGAGG\"\n",
    "\n",
    "    for _ in range(num_samples):\n",
    "        # 50% chance of being positive\n",
    "        if np.random.rand() > 0.5:\n",
    "            # Create a \"motif\" sequence (Consensus + noise)\n",
    "            base = list(np.random.choice(list(\"ACGT\"), seq_len))\n",
    "            # Plant the motif at a fixed spot (simple case)\n",
    "            start = 2\n",
    "            for i, char in enumerate(consensus):\n",
    "                if np.random.rand() > 0.05: # 95% conservation\n",
    "                    base[start+i] = char\n",
    "            sequences.append(\"\".join(base))\n",
    "            labels.append(1) # Positive label\n",
    "        else:\n",
    "            # Random sequence\n",
    "            seq = \"\".join(np.random.choice(list(\"ACGT\"), seq_len))\n",
    "            sequences.append(seq)\n",
    "            labels.append(0) # Negative label\n",
    "\n",
    "    return sequences, np.array(labels)\n",
    "\n",
    "train_seqs, train_labels = generate_data()\n",
    "print(f\"Generated {len(train_seqs)} sequences.\")\n",
    "print(f\"Example: {train_seqs[0]} (Label: {train_labels[0]})\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "jAE8cc_iKq8f"
   },
   "source": [
    "## Training Loop\n",
    "\n",
    "Now we arrive at the core of the lesson: How does the perceptron learn?\n",
    "\n",
    "In modern Deep Learning, we usually use \"Gradient Descent\" (calculating derivatives of an error function). However, in 1986, Stormo et al. used a simpler, more intuitive method derived from the original Perceptron algorithm (Rosenblatt, 1958).\n",
    "\n",
    "**The Intuition: Reward and Punish**\n",
    "You can think of the weight matrix $W$ as a score board.\n",
    "- When the model sees a real RBS and correctly says yes, there's no change.\n",
    "- When the model sees a non-RBS and classifies it as no, there's no change.\n",
    "- If the model sees a real RBS but says no (false negative), then the model missed a pattern. So we take the sequence $X$ and add it to the weights $(W' = W + X)$. This increseases the weights specifically at the position where the bases appeared in the sequence so the next time the model sees that sequence or a similar one, the score will be higher.\n",
    "- If the model sees a non-RBS but says yes (false positive), then the model was fooled by a bad pattern. So we take the sequence $X$ and subtract it from the weights $(W' = W - X)$. This lowers the weights at the positions for the sequence so next time the model will score it lower.\n",
    "\n",
    "Task: Implement the logic described here. We'll run this over our dataset for 5 epochs. An epoch is one full pass through the dataset."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 570
    },
    "id": "b_0_fVENJ7BU",
    "outputId": "6bdfbc2d-f299-4888-eaf5-c71bcd19f214"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Starting Training...\n",
      "Epoch 1: Total Errors = 0\n",
      "Epoch 2: Total Errors = 0\n",
      "Epoch 3: Total Errors = 0\n",
      "Epoch 4: Total Errors = 0\n",
      "Epoch 5: Total Errors = 0\n",
      "Epoch 6: Total Errors = 0\n",
      "Epoch 7: Total Errors = 0\n",
      "Epoch 8: Total Errors = 0\n",
      "Epoch 9: Total Errors = 0\n",
      "Epoch 10: Total Errors = 0\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAscAAAGJCAYAAABmTJ6vAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAS2ZJREFUeJzt3X18zfX/x/Hn2bWxzcZsljGJXIUQFn3J1VBq8nUVsfFDX02YXEwxUq1VJIWlkso1SXSBWVK5zGXksq+VwkjMXGRm5/z+MOfbacM5Ohc4j/vttlvO+/P+fM7rfd5Ht6fP3p/Px2AymUwCAAAAIA9XFwAAAADcLAjHAAAAQAHCMQAAAFCAcAwAAAAUIBwDAAAABQjHAAAAQAHCMQAAAFCAcAwAAAAUIBwDAAAABQjHAG5LUVFRiouLc3UZwD/GdxlwLsIxgKuaOXOmDAaDNm/e7OpSbjkXLlzQ66+/roYNGyooKEh+fn6qUqWKEhIStH//fleXZ1cGg+GqP08++aSry7vpfP3119f8zP76A8D5vFxdAAA4wr59++Th4Zp//584cUJt2rTRli1b9PDDD+vxxx9XiRIltG/fPs2bN0/Tp0/XxYsXXVKbo7Rq1Uo9e/Ys1F6lShUXVHNzq1atmj766COLtqSkJJUoUULPPvtsof6u/C4D7ohwDOCmd+nSJRmNRvn4+Fi9j6+vrwMrura4uDht27ZNixYtUseOHS22jR8/vsgAdCNu5HNxlCpVqqhHjx4273f+/Hn5+/sXarfH2M6dO6fixYvf8P6OEhYWVuizevnll1W6dOkiP0NXfpcBd8Q/RQH8Y4cPH1bv3r0VFhYmX19f1ahRQzNmzLDoc/HiRY0ZM0b16tVTUFCQihcvrgceeECrV6+26Pfzzz/LYDDotdde06RJk1SpUiX5+vpq9+7dGjt2rAwGg3766SfFxcWpZMmSCgoKUnx8vM6fP29xnL+v07yyRGTt2rVKTExUaGioihcvrg4dOuj333+32NdoNGrs2LGKiIiQv7+/HnzwQe3evduqtZ8bN27U559/rj59+hQKxtLloPPaa6+ZXzdr1kzNmjUr1C8uLk5RUVHX/Vy2bdsmLy8vjRs3rtAx9u3bJ4PBoLfeesvclp2drcGDBysyMlK+vr666667lJqaKqPRaLHv0aNHtXfvXuXl5V1zvLZo1qyZatasqS1btuhf//qX/P39NWrUqGvOuSR99dVXeuCBB1S8eHGVLFlSjz76qPbs2WNx7Cvfjd27d+vxxx9XcHCwmjRpIknKyspSfHy8ypUrJ19fX5UtW1aPPvqofv7556vW+tprr8lgMOiXX34ptC0pKUk+Pj46deqUJOnAgQPq2LGjwsPD5efnp3Llyqlr1646ffq0XT63q32Xv/vuOz399NMKDQ1VyZIl1b9/f128eFHZ2dnq2bOngoODFRwcrOHDh8tkMlkc02g0atKkSapRo4b8/PwUFham/v37m8cEuDPOHAP4R44dO6ZGjRrJYDAoISFBoaGh+vLLL9WnTx/l5ORo8ODBkqScnBy9++676tatm/r27aszZ87ovffeU0xMjDZt2qQ6depYHPf999/XhQsX1K9fP/n6+iokJMS8rXPnzqpYsaJSUlK0detWvfvuuypTpoxSU1OvW+/AgQMVHBys5ORk/fzzz5o0aZISEhI0f/58c5+kpCS98sorat++vWJiYrRjxw7FxMTowoUL1z3+0qVLJUlPPPGEFZ+e7f7+uZQtW1ZNmzbVggULlJycbNF3/vz58vT0VKdOnSRdPkvbtGlTHT58WP3791f58uW1bt06JSUl6ejRo5o0aZJ536SkJH3wwQfKzMy0COlXc+HCBZ04caJQe2BgoMXZ3z/++ENt27ZV165d1aNHD4WFhV11bCEhIVq1apXatm2rO++8U2PHjtWff/6pN998U40bN9bWrVsL1dapUydVrlxZL730kjkQduzYUT/++KMGDhyoqKgoHT9+XOnp6Tp06NBVx9a5c2cNHz5cCxYs0LBhwyy2LViwQK1bt1ZwcLAuXryomJgY5ebmauDAgQoPD9fhw4f12WefKTs7W0FBQdf97G7UlfcbN26cNmzYoOnTp6tkyZJat26dypcvr5deeklffPGFXn31VdWsWdNi2Uv//v01c+ZMxcfH6+mnn1ZmZqbeeustbdu2TWvXrpW3t7fD6gZueiYAuIr333/fJMn0/fffX7VPnz59TGXLljWdOHHCor1r166moKAg0/nz500mk8l06dIlU25urkWfU6dOmcLCwky9e/c2t2VmZpokmQIDA03Hjx+36J+cnGySZNHfZDKZOnToYCpVqpRFW4UKFUy9evUqNJaWLVuajEajuX3IkCEmT09PU3Z2tslkMpmysrJMXl5eptjYWIvjjR071iTJ4phF6dChg0mS6dSpU9fsd0XTpk1NTZs2LdTeq1cvU4UKFcyvr/W5vP322yZJpp07d1q0V69e3dS8eXPz6/Hjx5uKFy9u2r9/v0W/kSNHmjw9PU2HDh2yeH9JpszMzOuOQdJVf+bOnWsxVkmmtLQ0i/2vNbY6deqYypQpY/rjjz/MbTt27DB5eHiYevbsaW678t3o1q2bxf6nTp0ySTK9+uqr1x3H30VHR5vq1atn0bZp0yaTJNOHH35oMplMpm3btpkkmRYuXGjz8f+qRo0aRX4PTKarf5djYmIsvsvR0dEmg8FgevLJJ81tly5dMpUrV87i2N9++61Jkmn27NkW77N8+fIi2wF3w7IKADfMZDLp448/Vvv27WUymXTixAnzT0xMjE6fPq2tW7dKkjw9Pc1nEI1Go06ePKlLly6pfv365j5/1bFjR4WGhhb5vn+/A8IDDzygP/74Qzk5OdetuV+/fhZ3AXjggQeUn59v/vV5RkaGLl26pAEDBljsN3DgwOseW5K5hoCAAKv626qoz+Wxxx6Tl5eXxdnvXbt2affu3erSpYu5beHChXrggQcUHBxsMVctW7ZUfn6+vvnmG3PfmTNnymQyWXXWWJIeffRRpaenF/p58MEHLfr5+voqPj7eqrEdPXpU27dvV1xcnMVvDmrVqqVWrVrpiy++KHSMv383ihUrJh8fH3399dc2Lxno0qWLtmzZov/+97/mtvnz58vX11ePPvqoJJnPDK9YsaLQ0h5H69Onj8V3uWHDhjKZTOrTp4+5zdPTU/Xr19fBgwfNbQsXLlRQUJBatWpl8T2oV6+eSpQoUWipE+BuCMcAbtjvv/+u7OxsTZ8+XaGhoRY/VwLQ8ePHzf0/+OAD1apVS35+fipVqpRCQ0P1+eefF7k2s2LFild93/Lly1u8Dg4OliSrws/19r0Sku+66y6LfiEhIea+1xIYGChJOnPmzHX73oiiPpfSpUurRYsWWrBggblt/vz58vLy0mOPPWZuO3DggJYvX15orlq2bCnJcq5sVa5cObVs2bLQz1+XTUjSHXfccdWL7P4+titzcffddxfqW61aNZ04cULnzp275jF8fX2VmpqqL7/8UmFhYfrXv/6lV155RVlZWdcdU6dOneTh4WH+R4fJZNLChQvVtm1b8zxXrFhRiYmJevfdd1W6dGnFxMRoypQpdltvfC1//y5fCeqRkZGF2v/6d+PAgQM6ffq0ypQpU+i7cPbs2X/0PQBuB6w5BnDDrlzE1aNHD/Xq1avIPrVq1ZIkzZo1S3FxcYqNjdWwYcNUpkwZeXp6KiUlxeLM3BXFihW76vt6enoW2W7620VH9t7XGlWrVpUk7dy5Uw888MB1+xsMhiLfOz8/v8j+V/tcunbtqvj4eG3fvl116tTRggUL1KJFC5UuXdrcx2g0qlWrVho+fHiRx3DGbdeuNa/X2vZPjj948GC1b99eS5Ys0YoVKzR69GilpKToq6++0r333nvVY0VEROiBBx7QggULNGrUKG3YsEGHDh0qtLZ9woQJiouL06effqqVK1fq6aefVkpKijZs2KBy5cr94zFdzdW+y0W1//U7ZjQaVaZMGc2ePbvI/a/2GxvAXRCOAdyw0NBQBQQEKD8/33z28WoWLVqkO++8U4sXL7b4VfDfLyJztQoVKkiSfvrpJ4uzkH/88YdVZ6bbt2+vlJQUzZo1y6pwHBwcbPEr7yuKukvCtcTGxqp///7ms5z79+9XUlKSRZ9KlSrp7Nmz152rm8WVudi3b1+hbXv37lXp0qWtvlVbpUqVNHToUA0dOlQHDhxQnTp1NGHCBM2aNeua+3Xp0kUDBgzQvn37NH/+fPn7+6t9+/aF+t1zzz2655579Nxzz2ndunVq3Lix0tLS9MILL1hVnzNVqlRJq1atUuPGje3yDxLgdsOyCgA3zNPTUx07dtTHH3+sXbt2Fdr+11ukXTmb9dczWBs3btT69esdX6gNWrRoIS8vL02bNs2i/a+3Q7uW6OhotWnTRu+++66WLFlSaPvFixf1zDPPmF9XqlRJe/futfisduzYobVr19pUd8mSJRUTE6MFCxZo3rx58vHxUWxsrEWfzp07a/369VqxYkWh/bOzs3Xp0iXza0fcys1WZcuWVZ06dfTBBx8oOzvb3L5r1y6tXLlS7dq1u+4xzp8/X+guI5UqVVJAQIByc3Ovu3/Hjh3l6empuXPnauHChXr44YctAnlOTo7F5yZdDsoeHh5WHd8VOnfurPz8fI0fP77QtkuXLll81oA74swxgOuaMWOGli9fXqh90KBBevnll7V69Wo1bNhQffv2VfXq1XXy5Elt3bpVq1at0smTJyVJDz/8sBYvXqwOHTrooYceUmZmptLS0lS9enWdPXvW2UO6qrCwMA0aNEgTJkzQI488ojZt2mjHjh368ssvVbp0aase6fvhhx+qdevWeuyxx9S+fXu1aNFCxYsX14EDBzRv3jwdPXrUfK/j3r17a+LEiYqJiVGfPn10/PhxpaWlqUaNGlZdYPhXXbp0UY8ePTR16lTFxMSoZMmSFtuHDRumpUuX6uGHH1ZcXJzq1aunc+fOaefOnVq0aJF+/vln8zIMW2/ltn///iLPwoaFhalVq1Y2jeOvXn31VbVt21bR0dHq06eP+VZuQUFBGjt2rFV1tWjRQp07d1b16tXl5eWlTz75RMeOHVPXrl2vu3+ZMmX04IMPauLEiTpz5ozFBY7S5XswJyQkqFOnTqpSpYouXbqkjz76yPwPx5tR06ZN1b9/f6WkpGj79u1q3bq1vL29deDAAS1cuFBvvPGG/v3vf7u6TMBlCMcAruvvZ1GviIuLU7ly5bRp0yY9//zzWrx4saZOnapSpUqpRo0aFmsz4+LilJWVpbffflsrVqxQ9erVNWvWLC1cuFBff/21k0ZindTUVPn7++udd97RqlWrFB0drZUrV6pJkyby8/O77v6hoaFat26dpk6dqvnz5+vZZ5/VxYsXVaFCBT3yyCMaNGiQuW+1atX04YcfasyYMUpMTFT16tX10Ucfac6cOTZ/Lo888oiKFStWZIiTJH9/f61Zs0YvvfSSFi5cqA8//FCBgYGqUqWKxo0b94/uyXvl7hR/17Rp038Ujlu2bKnly5crOTlZY8aMkbe3t5o2barU1NRrXrR5RWRkpLp166aMjAx99NFH8vLyUtWqVbVgwQKrw2uXLl20atUqBQQEFDpbXbt2bcXExGjZsmU6fPiw/P39Vbt2bX355Zdq1KjRDY3ZGdLS0lSvXj29/fbbGjVqlLy8vBQVFaUePXqocePGri4PcCmDyV5XoQDAbSw7O1vBwcF64YUX7Pb4ZwDAzYc1xwDwN3/++WehtitPjyvqUc8AgNsHyyoA4G/mz5+vmTNnql27dipRooS+++47zZ07V61bt+ZXzgBwmyMcA8Df1KpVS15eXnrllVeUk5NjvkjvZrwtFwDAvlhzDAAAABRgzTEAAABQgHAMAAAAFGDNsR0YjUYdOXJEAQEBVj0gAAAAAM5lMpl05swZRUREyMPj6ueHCcd2cOTIEUVGRrq6DAAAAFzHr7/+qnLlyl11O+HYDgICAiRd/rADAwNdXM3tKy8vTytXrjQ/6hTugXl3P8y5+2HO3Y8r5jwnJ0eRkZHm3HY1hGM7uLKUIjAwkHDsQHl5efL391dgYCD/83QjzLv7Yc7dD3Puflw559dbAssFeQAAAEABwjEAAABQgHAMAAAAFCAcAwAAAAUIxwAAAEABwjEAAABQgHAMAAAAFCAcAwAAAAUIxwAAAEABwjEAAABQgHAMAAAAFCAcAwAAAAUIxwAAAEABwjEAAABQgHAMAAAAFCAcAwAAAAUIxwAAAEABwjEAAABQgHAMAAAAFCAcAwAAAAUIxwAAAEABwjEAAABQgHAMAAAAFCAcAwAAAAUIxwAAAEABwjEAAABQgHAMAAAAFCAcAwAAAAUIxwAAAEABwjEAAABQwOZw/Ouvv+q3334zv960aZMGDx6s6dOn27UwAAAAwNlsDsePP/64Vq9eLUnKyspSq1attGnTJj377LN6/vnn7V4gAAAA4Cw2h+Ndu3apQYMGkqQFCxaoZs2aWrdunWbPnq2ZM2fauz4AAADAaWwOx3l5efL19ZUkrVq1So888ogkqWrVqjp69Kh9qwMAAACcyOZwXKNGDaWlpenbb79Venq62rRpI0k6cuSISpUqZfcCAQAAAGexORynpqbq7bffVrNmzdStWzfVrl1bkrR06VLzcgtHmjJliqKiouTn56eGDRtq06ZN1+y/cOFCVa1aVX5+frrnnnv0xRdfXLXvk08+KYPBoEmTJtm5agAAANwKbA7HzZo104kTJ3TixAnNmDHD3N6vXz+lpaXZtbi/mz9/vhITE5WcnKytW7eqdu3aiomJ0fHjx4vsv27dOnXr1k19+vTRtm3bFBsbq9jYWO3atatQ308++UQbNmxQRESEQ8cAAACAm9cN3efYZDJpy5Ytevvtt3XmzBlJko+Pj/z9/e1a3N9NnDhRffv2VXx8vKpXr660tDT5+/tbhPS/euONN9SmTRsNGzZM1apV0/jx41W3bl299dZbFv0OHz6sgQMHavbs2fL29nboGAAAAHDz8rJ1h19++UVt2rTRoUOHlJubq1atWikgIECpqanKzc112NnjixcvasuWLUpKSjK3eXh4qGXLllq/fn2R+6xfv16JiYkWbTExMVqyZIn5tdFo1BNPPKFhw4apRo0aVtWSm5ur3Nxc8+ucnBxJly9WzMvLs3ZIsNGVz5bP2L0w7+6HOXc/zLn7ccWcW/teNofjQYMGqX79+tqxY4fFBXgdOnRQ3759bT2c1U6cOKH8/HyFhYVZtIeFhWnv3r1F7pOVlVVk/6ysLPPr1NRUeXl56emnn7a6lpSUFI0bN65Q+8qVKx1+9hxSenq6q0uACzDv7oc5dz/Muftx5pyfP3/eqn42h+Nvv/1W69atk4+Pj0V7VFSUDh8+bOvhXGrLli164403tHXrVhkMBqv3S0pKsjgjnZOTo8jISLVu3VqBgYGOKBW6/C++9PR0tWrViuUvboR5dz/Mufthzt2PK+b8ym/6r8fmcGw0GpWfn1+o/bffflNAQICth7Na6dKl5enpqWPHjlm0Hzt2TOHh4UXuEx4efs3+3377rY4fP67y5cubt+fn52vo0KGaNGmSfv755yKP6+vra77X8195e3vzl9oJ+JzdE/Pufphz98Ocux9nzrm172PzBXmtW7e2uNWZwWDQ2bNnlZycrHbt2tl6OKv5+PioXr16ysjIMLcZjUZlZGQoOjq6yH2io6Mt+kuXT99f6f/EE0/ohx9+0Pbt280/ERERGjZsmFasWOGwsQAAAODmZPOZ4wkTJigmJkbVq1fXhQsX9Pjjj+vAgQMqXbq05s6d64gazRITE9WrVy/Vr19fDRo00KRJk3Tu3DnFx8dLknr27Kk77rhDKSkpki6vj27atKkmTJighx56SPPmzdPmzZs1ffp0SVKpUqUKPbjE29tb4eHhuvvuux06FgAAANx8bA7H5cqV044dOzR//nzt2LFDZ8+eVZ8+fdS9e3cVK1bMETWadenSRb///rvGjBmjrKws1alTR8uXLzdfdHfo0CF5ePzvZPj999+vOXPm6LnnntOoUaNUuXJlLVmyRDVr1nRonQAAALg12RyOJcnLy0vdu3dX9+7d7V3PdSUkJCghIaHIbV9//XWhtk6dOqlTp05WH/9q64wBAABw+7N5zXFKSkqRD92YMWOGUlNT7VIUAAAA4Ao2h+O3335bVatWLdReo0YNhz8+GgAAAHAkm8NxVlaWypYtW6g9NDRUR48etUtRAAAAgCvYHI4jIyO1du3aQu1r165VRESEXYoCAAAAXMHmC/L69u2rwYMHKy8vT82bN5ckZWRkaPjw4Ro6dKjdCwQAAACcxeZwPGzYMP3xxx8aMGCALl68KEny8/PTiBEjlJSUZPcCAQAAAGexORwbDAalpqZq9OjR2rNnj4oVK6bKlSsX+ThlAAAA4FZyQ/c5lqQSJUrovvvus2ctAAAAgEvZHI7PnTunl19+WRkZGTp+/LiMRqPF9oMHD9qtOAAAAMCZbA7H//d//6c1a9boiSeeUNmyZWUwGBxRFwAAAOB0NofjL7/8Up9//rkaN27siHoAAAAAl7H5PsfBwcEKCQlxRC0AAACAS9kcjsePH68xY8bo/PnzjqgHAAAAcBmbl1VMmDBB//3vfxUWFqaoqCh5e3tbbN+6davdigMAAACcyeZwHBsb64AyAAAAANezORwnJyc7og4AAADA5WxecyxJ2dnZevfdd5WUlKSTJ09Kuryc4vDhw3YtDgAAAHAmm88c//DDD2rZsqWCgoL0888/q2/fvgoJCdHixYt16NAhffjhh46oEwAAAHA4m88cJyYmKi4uTgcOHJCfn5+5vV27dvrmm2/sWhwAAADgTDaH4++//179+/cv1H7HHXcoKyvLLkUBAAAArmBzOPb19VVOTk6h9v379ys0NNQuRQEAAACuYHM4fuSRR/T8888rLy9PkmQwGHTo0CGNGDFCHTt2tHuBAAAAgLPYHI4nTJigs2fPqkyZMvrzzz/VtGlT3XXXXQoICNCLL77oiBoBAAAAp7D5bhVBQUFKT0/Xd999px9++EFnz55V3bp11bJlS0fUBwAAADiNzeH4iiZNmqhJkyb2rAUAAABwKZvD8fPPP3/N7WPGjLnhYgAAAABXsjkcf/LJJxav8/LylJmZKS8vL1WqVIlwDAAAgFuWzeF427ZthdpycnIUFxenDh062KUoAAAAwBVsvltFUQIDAzVu3DiNHj3aHocDAAAAXMIu4ViSTp8+rdOnT9vrcAAAAIDT2bysYvLkyRavTSaTjh49qo8++kht27a1W2EAAACAs9kcjl9//XWL1x4eHgoNDVWvXr2UlJRkt8IAAAAAZ7M5HGdmZjqiDgAAAMDl7LbmGAAAALjV2XzmuEOHDjIYDFb1Xbx4sc0FAQAAAK5i85njoKAgZWRkaPPmzea2LVu26KuvvlJgYKCCgoLMPwAAAMCtxOYzx2FhYercubPS0tLk6ekpScrPz9eAAQMUGBioV1991e5FAgAAAM5g85njGTNm6JlnnjEHY0ny9PRUYmKiZsyYYdfiAAAAAGeyORxfunRJe/fuLdS+d+9eGY1GuxQFAAAAuILNyyri4+PVp08f/fe//1WDBg0kSRs3btTLL7+s+Ph4uxcIAAAAOIvN4fi1115TeHi4JkyYoKNHj0qSypYtq2HDhmno0KF2LxAAAABwFpvDsYeHh4YPH67hw4crJydHkhQYGGj3wgAAAABnu6GHgFy6dEmrVq3S3Llzzfc8PnLkiM6ePWvX4gAAAABnsvnM8S+//KI2bdro0KFDys3NVatWrRQQEKDU1FTl5uYqLS3NEXUCAAAADmfzmeNBgwapfv36OnXqlIoVK2Zu79ChgzIyMuxaHAAAAOBMNofjb7/9Vs8995x8fHws2qOionT48GG7FXY1U6ZMUVRUlPz8/NSwYUNt2rTpmv0XLlyoqlWrys/PT/fcc4+++OIL87a8vDyNGDFC99xzj4oXL66IiAj17NlTR44ccfQwAAAAcBOyORwbjUbl5+cXav/tt98UEBBgl6KuZv78+UpMTFRycrK2bt2q2rVrKyYmRsePHy+y/7p169StWzf16dNH27ZtU2xsrGJjY7Vr1y5J0vnz57V161aNHj1aW7du1eLFi7Vv3z498sgjDh0HAAAAbk42h+PWrVtr0qRJ5tcGg0Fnz55VcnKy2rVrZ8/aCpk4caL69u2r+Ph4Va9eXWlpafL397/qk/neeOMNtWnTRsOGDVO1atU0fvx41a1bV2+99ZYkKSgoSOnp6ercubPuvvtuNWrUSG+99Za2bNmiQ4cOOXQsAAAAuPnYfEHehAkTFBMTo+rVq+vChQt6/PHHdeDAAZUuXVpz5851RI2SpIsXL2rLli1KSkoyt3l4eKhly5Zav359kfusX79eiYmJFm0xMTFasmTJVd/n9OnTMhgMKlmy5FX75ObmKjc31/z6yi3t8vLylJeXZ8VocCOufLZ8xu6FeXc/zLn7Yc7djyvm3Nr3sjkclytXTjt27ND8+fO1Y8cOnT17Vn369FH37t0tLtCztxMnTig/P19hYWEW7WFhYUU+zlqSsrKyiuyflZVVZP8LFy5oxIgR6tat2zXv3ZySkqJx48YVal+5cqX8/f2vNxT8Q+np6a4uAS7AvLsf5tz9MOfux5lzfv78eav62RyOJcnLy0vdu3dX9+7db2T3m1JeXp46d+4sk8mkadOmXbNvUlKSxRnpnJwcRUZGqnXr1jwQxYHy8vKUnp6uVq1aydvb29XlwEmYd/fDnLsf5tz9uGLOr/ym/3qsDsf79+9Xdna2GjRoYG7LyMjQCy+8oHPnzik2NlajRo2yvVIrlS5dWp6enjp27JhF+7FjxxQeHl7kPuHh4Vb1vxKMf/nlF3311VfXDbi+vr7y9fUt1O7t7c1faifgc3ZPzLv7Yc7dD3Pufpw559a+j9UX5I0YMUKfffaZ+XVmZqbat28vHx8fRUdHKyUlxeJCPXvz8fFRvXr1LO6lbDQalZGRoejo6CL3iY6OLnTv5fT0dIv+V4LxgQMHtGrVKpUqVcoxAwAAAMBNz+ozx5s3b9bw4cPNr2fPnq0qVapoxYoVkqRatWrpzTff1ODBg+1e5BWJiYnq1auX6tevrwYNGmjSpEk6d+6c4uPjJUk9e/bUHXfcoZSUFEmXH1jStGlTTZgwQQ899JDmzZunzZs3a/r06ZIuB+N///vf2rp1qz777DPl5+eb1yOHhIQUupczAAAAbm9Wh+MTJ06oXLly5terV69W+/btza+bNWumoUOH2re6v+nSpYt+//13jRkzRllZWapTp46WL19uvuju0KFD8vD438nw+++/X3PmzNFzzz2nUaNGqXLlylqyZIlq1qwpSTp8+LCWLl0qSapTp47Fe61evVrNmjVz6HgAAABwc7E6HIeEhOjo0aOKjIyU0WjU5s2bLS5Ku3jxokwmk0OK/KuEhAQlJCQUue3rr78u1NapUyd16tSpyP5RUVFOqRkAAAC3BqvXHDdr1kzjx4/Xr7/+qkmTJsloNFqcWd29e7eioqIcUCIAAADgHFafOX7xxRfVqlUrVahQQZ6enpo8ebKKFy9u3v7RRx+pefPmDikSAAAAcAarw3FUVJT27NmjH3/8UaGhoYqIiLDYPm7cOIs1yQAAAMCtxqaHgHh5eal27dpFbrtaOwAAAHCrsHrNMQAAAHC7IxwDAAAABQjHAAAAQAHCMQAAAFDAqgvyfvjhB6sPWKtWrRsuBgAAAHAlq8JxnTp1ZDAYZDKZZDAYrtk3Pz/fLoUBAAAAzmbVsorMzEwdPHhQmZmZ+vjjj1WxYkVNnTpV27Zt07Zt2zR16lRVqlRJH3/8saPrBQAAABzGqjPHFSpUMP+5U6dOmjx5stq1a2duq1WrliIjIzV69GjFxsbavUgAAADAGWy+IG/nzp2qWLFiofaKFStq9+7ddikKAAAAcAWbw3G1atWUkpKiixcvmtsuXryolJQUVatWza7FAQAAAM5k0+OjJSktLU3t27dXuXLlzHem+OGHH2QwGLRs2TK7FwgAAAA4i83huEGDBjp48KBmz56tvXv3SpK6dOmixx9/XMWLF7d7gQAAAICz2ByOJal48eLq16+fvWsBAAAAXOqGnpD30UcfqUmTJoqIiNAvv/wiSXr99df16aef2rU4AAAAwJlsDsfTpk1TYmKi2rZtq1OnTpkf+hEcHKxJkybZuz4AAADAaWwOx2+++abeeecdPfvss/Ly+t+qjPr162vnzp12LQ4AAABwJpvDcWZmpu69995C7b6+vjp37pxdigIAAABcweZwXLFiRW3fvr1Q+/Lly7nPMQAAAG5pNt+tIjExUU899ZQuXLggk8mkTZs2ae7cuUpJSdG7777riBoBAAAAp7A5HP/f//2fihUrpueee07nz5/X448/roiICL3xxhvq2rWrI2oEAAAAnOKG7nPcvXt3de/eXefPn9fZs2dVpkwZe9cFAAAAON0NheMr/P395e/vb69aAAAAAJeyKhzXrVtXGRkZCg4O1r333iuDwXDVvlu3brVbcQAAAIAzWRWOH330Ufn6+kqSYmNjHVkPAAAA4DJWhePg4GB5eFy+61t8fLzKlStnfg0AAADcLqxKuImJicrJyZF0+T7HJ06ccGhRAAAAgCtYdeY4IiJCH3/8sdq1ayeTyaTffvtNFy5cKLJv+fLl7VogAAAA4CxWhePnnntOAwcOVEJCggwGg+67775CfUwmkwwGg/Lz8+1eJAAAAOAMVoXjfv36qVu3bvrll19Uq1YtrVq1SqVKlXJ0bQAAAIBTWX2f44CAANWsWVPvv/++GjdubL57BQAAAHC7sPkhIL169XJEHQAAAIDLWRWOQ0JCtH//fpUuXVrBwcHXfAjIyZMn7VYcAAAA4ExWhePXX39dAQEB5j9fKxwDAAAAtyqrwvFfl1LExcU5qhYAAADApWx+zN3WrVu1c+dO8+tPP/1UsbGxGjVqlC5evGjX4gAAAABnsjkc9+/fX/v375ckHTx4UF26dJG/v78WLlyo4cOH271AAAAAwFlsDsf79+9XnTp1JEkLFy5U06ZNNWfOHM2cOVMff/yxvesDAAAAnMbmcGwymWQ0GiVJq1atUrt27SRJkZGROnHihH2rAwAAAJzI5nBcv359vfDCC/roo4+0Zs0aPfTQQ5KkzMxMhYWF2b1AAAAAwFlsDseTJk3S1q1blZCQoGeffVZ33XWXJGnRokW6//777V4gAAAA4Cw2PyGvVq1aFneruOLVV1+Vp6enXYrC1eUbTdqUeVLHz1xQmQA/NagYIk+P2/++0/lGkzZmntSWEwaVyjyp6LvKuMW4Jfedc8l95505Z86Zc/cZuzvO+80+5waTyWSyZYdff/1VBoNB5cqVkyRt2rRJc+bMUfXq1dWvXz+HFPlXU6ZM0auvvqqsrCzVrl1bb775pho0aHDV/gsXLtTo0aP1888/q3LlykpNTTWvk5Yur6FOTk7WO++8o+zsbDVu3FjTpk1T5cqVra4pJydHQUFBOn36tAIDA//R+K5l+a6jGrdst46evmBuKxvkp+T21dWmZlmHva+rueu4JcbujmN313FL7jt2dx23xNjdceyuHLe1ec3mZRWPP/64Vq9eLUnKyspSq1attGnTJj377LN6/vnnb7xiK8yfP1+JiYlKTk7W1q1bVbt2bcXExOj48eNF9l+3bp26deumPn36aNu2bYqNjVVsbKx27dpl7vPKK69o8uTJSktL08aNG1W8eHHFxMTowoULRR7TVZbvOqr/zNpq8WWSpKzTF/SfWVu1fNdRF1XmWO46bomxu+PY3XXckvuO3V3HLTF2dxz7rTJum88cBwcHa8OGDbr77rs1efJkzZ8/X2vXrtXKlSv15JNP6uDBg46qVQ0bNtR9992nt956S5JkNBoVGRmpgQMHauTIkYX6d+nSRefOndNnn31mbmvUqJHq1KmjtLQ0mUwmRUREaOjQoXrmmWckSadPn1ZYWJhmzpyprl27WlWXo88c5xtNapL6VaEv0xUGSWGBfkpP/NdN9WuJfyrfaFLLiWt0LCe3yO2367glxu6OY3fXcUvuO3Z3HbfE2N1x7NaMOzzIT9+NaO6wcVub12wOxyVKlNCuXbsUFRWlRx55RI0bN9aIESN06NAh3X333frzzz//cfFFuXjxovz9/bVo0SLFxsaa23v16qXs7Gx9+umnhfYpX768EhMTNXjwYHNbcnKylixZoh07dujgwYOqVKmStm3bZr53syQ1bdpUderU0RtvvFFkLbm5ucrN/d/k5uTkmG9l54hwvDHzpHrM2Gz34wIAANxMZvWur4YVQxxy7JycHJUuXfq64djmC/Jq1KihtLQ0PfTQQ0pPT9f48eMlSUeOHFGpUqVuvOLrOHHihPLz8wvdLi4sLEx79+4tcp+srKwi+2dlZZm3X2m7Wp+ipKSkaNy4cYXaV65cKX9//+sPxkZbThgkcbEjAAC4va38dqP+2GPTeVurnT9/3qp+Nofj1NRUdejQQa+++qp69eql2rVrS5KWLl16zQvjbidJSUlKTEw0v75y5rh169YOOXNcKvOkPjxw/TPH7z5xr+6LCrb7+7vK9z+f0v99tO26/W63cUuM3R3H7q7jltx37O46bomxu+PYrR136wcaOvTMsTVsDsfNmjXTiRMnlJOTo+Dg/01av379HHLW9IrSpUvL09NTx44ds2g/duyYwsPDi9wnPDz8mv2v/PfYsWMqW7asRZ+/LrP4O19fX/n6+hZq9/b2lre3t1XjsUX0XWVUNshPWacvqKh/S11Zp/NgtbK31fqkB6v5qWzQHrcbt8TY3XHs7jpuyX3H7q7jlhi7O47d2nE78rZu1mY0m+9WIUmenp4WwViSoqKiVKZMmRs5nFV8fHxUr149ZWRkmNuMRqMyMjIUHR1d5D7R0dEW/SUpPT3d3L9ixYoKDw+36JOTk6ONGzde9Ziu4OlhUHL76pIuf3n+6srr5PbVb6u/RJL7jlti7O44dncdt+S+Y3fXcUuM3R3HfiuN+4bC8aJFi9S5c2c1atRIdevWtfhxpMTERL3zzjv64IMPtGfPHv3nP//RuXPnFB8fL0nq2bOnkpKSzP0HDRqk5cuXa8KECdq7d6/Gjh2rzZs3KyEhQZJkMBg0ePBgvfDCC1q6dKl27typnj17KiIiwuKiv5tBm5plNa1HXYUH+Vm0hwf5aVqPurftPRHdddwSY3fHsbvruCX3Hbu7jlti7O449ltm3CYbvfHGG6YSJUqYEhISTD4+Pqb+/fubWrZsaQoKCjKNGjXK1sPZ7M033zSVL1/e5OPjY2rQoIFpw4YN5m1NmzY19erVy6L/ggULTFWqVDH5+PiYatSoYfr8888tthuNRtPo0aNNYWFhJl9fX1OLFi1M+/bts6mm06dPmySZTp8+fcPjstalfKNp3U8nTEu2/WZa99MJ06V8o8Pf82ZwKd9o+nZflmn0u5+avt2X5TbjNpncd85NJvedd+acOXeXcZtM7jvnJpP7zrur5tzavGbzrdyqVq2q5ORkdevWTQEBAdqxY4fuvPNOjRkzRidPnjTfg9idOOsJee4uLy9PX3zxhdq1a+eQtd24OTHv7oc5dz/MuftxxZw77Al5hw4d0v333y9JKlasmM6cOSNJeuKJJzR37twbLBcAAABwPZvDcXh4uE6ePCnp8kM2NmzYIEnKzMyUjSehAQAAgJuKzeG4efPmWrp0qSQpPj5eQ4YMUatWrdSlSxd16NDB7gUCAAAAzmLzfY6nT58uo9EoSXrqqadUqlQprVu3To888oj69+9v9wIBAAAAZ7E5HHt4eMjD438nnLt27aquXbvatSgAAADAFawKxz/88IPVB6xVq9YNFwMAAAC4klXhuE6dOjIYDNe94M5gMCg/P98uhQEAAADOZlU4zszMdHQdAAAAgMtZFY4rVKjg6DoAAAAAl7P5Vm4pKSmaMWNGofYZM2YoNTXVLkUBAAAArmBzOH777bdVtWrVQu01atRQWlqaXYoCAAAAXMHmcJyVlaWyZcsWag8NDdXRo0ftUhQAAADgCjaH48jISK1du7ZQ+9q1axUREWGXogAAAABXsPkhIH379tXgwYOVl5en5s2bS5IyMjI0fPhwDR061O4FAgAAAM5iczgeNmyY/vjjDw0YMEAXL16UJPn5+WnEiBFKSkqye4EAAACAs9gcjg0Gg1JTUzV69Gjt2bNHxYoVU+XKleXr6+uI+gAAAACnsXnN8RUlSpTQfffdp/Lly+vLL7/Unj177FkXAAAA4HQ2h+POnTvrrbfekiT9+eefql+/vjp37qxatWrp448/tnuBAAAAgLPYHI6/+eYbPfDAA5KkTz75RCaTSdnZ2Zo8ebJeeOEFuxcIAAAAOIvN4fj06dMKCQmRJC1fvlwdO3aUv7+/HnroIR04cMDuBQIAAADOckP3OV6/fr3OnTun5cuXq3Xr1pKkU6dOyc/Pz+4FAgAAAM5i890qBg8erO7du6tEiRKqUKGCmjVrJunycot77rnH3vUBAAAATmNzOB4wYIAaNGigX3/9Va1atZKHx+WTz3feeSdrjgEAAHBLszkcS1L9+vVVv359i7aHHnrILgUBAAAArmJVOE5MTNT48eNVvHhxJSYmXrPvxIkT7VIYAAAA4GxWheNt27YpLy/P/OerMRgM9qkKAAAAcAGrwvHq1auL/DMAAABwO7nhx0cDAAAAtxurL8jr3bu3Vf1mzJhxw8UAAAAArmR1OJ45c6YqVKige++9VyaTyZE1AQAAAC5hdTj+z3/+o7lz5yozM1Px8fHq0aOH+THSAAAAwO3A6jXHU6ZM0dGjRzV8+HAtW7ZMkZGR6ty5s1asWMGZZAAAANwWbLogz9fXV926dVN6erp2796tGjVqaMCAAYqKitLZs2cdVSMAAADgFDd8twoPDw8ZDAaZTCbl5+fbsyYAAADAJWwKx7m5uZo7d65atWqlKlWqaOfOnXrrrbd06NAhlShRwlE1AgAAAE5h9QV5AwYM0Lx58xQZGanevXtr7ty5Kl26tCNrAwAAAJzK6nCclpam8uXL684779SaNWu0Zs2aIvstXrzYbsUBAAAAzmR1OO7Zs6cMBoMjawEAAABcyqaHgAAAAAC3sxu+WwUAAABwuyEcAwAAAAUIxwAAAEABwjEAAABQwKpwXLduXZ06dUqS9Pzzz+v8+fMOLQoAAABwBavC8Z49e3Tu3DlJ0rhx43T27FmHFgUAAAC4glW3cqtTp47i4+PVpEkTmUwmvfbaa1d9XPSYMWPsWuAVJ0+e1MCBA7Vs2TJ5eHioY8eOeuONN6752OoLFy5o6NChmjdvnnJzcxUTE6OpU6cqLCxMkrRjxw69/PLL+u6773TixAlFRUXpySef1KBBgxwyBgAAANzcrArHM2fOVHJysj777DMZDAZ9+eWX8vIqvKvBYHBYOO7evbuOHj2q9PR05eXlKT4+Xv369dOcOXOuus+QIUP0+eefa+HChQoKClJCQoIee+wxrV27VpK0ZcsWlSlTRrNmzVJkZKTWrVunfv36ydPTUwkJCQ4ZBwAAAG5eVoXju+++W/PmzZMkeXh4KCMjQ2XKlHFoYX+1Z88eLV++XN9//73q168vSXrzzTfVrl07vfbaa4qIiCi0z+nTp/Xee+9pzpw5at68uSTp/fffV7Vq1bRhwwY1atRIvXv3ttjnzjvv1Pr167V48WLCMQAAgBuy+gl5VxiNRkfUcU3r169XyZIlzcFYklq2bCkPDw9t3LhRHTp0KLTPli1blJeXp5YtW5rbqlatqvLly2v9+vVq1KhRke91+vRphYSEXLOe3Nxc5ebmml/n5ORIkvLy8pSXl2fT2GC9K58tn7F7Yd7dD3Pufphz9+OKObf2vWwOx5L03//+V5MmTdKePXskSdWrV9egQYNUqVKlGzncdWVlZRU6U+3l5aWQkBBlZWVddR8fHx+VLFnSoj0sLOyq+6xbt07z58/X559/fs16UlJSNG7cuELtK1eulL+//zX3xT+Xnp7u6hLgAsy7+2HO3Q9z7n6cOefW3m3N5nC8YsUKPfLII6pTp44aN24sSVq7dq1q1KihZcuWqVWrVlYfa+TIkUpNTb1mnysB3NF27dqlRx99VMnJyWrduvU1+yYlJSkxMdH8OicnR5GRkWrdurUCAwMdXarbysvLU3p6ulq1aiVvb29XlwMnYd7dD3Pufphz9+OKOb/ym/7rsTkcjxw5UkOGDNHLL79cqH3EiBE2heOhQ4cqLi7umn3uvPNOhYeH6/jx4xbtly5d0smTJxUeHl7kfuHh4bp48aKys7Mtzh4fO3as0D67d+9WixYt1K9fPz333HPXrdvX11e+vr6F2r29vflL7QR8zu6JeXc/zLn7Yc7djzPn3Nr3sTkc79mzRwsWLCjU3rt3b02aNMmmY4WGhio0NPS6/aKjo5Wdna0tW7aoXr16kqSvvvpKRqNRDRs2LHKfevXqydvbWxkZGerYsaMkad++fTp06JCio6PN/X788Uc1b95cvXr10osvvmhT/QAAALi92Pz46NDQUG3fvr1Q+/bt2x12B4tq1aqpTZs26tu3rzZt2qS1a9cqISFBXbt2Nd+p4vDhw6patao2bdokSQoKClKfPn2UmJio1atXa8uWLYqPj1d0dLT5Yrxdu3bpwQcfVOvWrZWYmKisrCxlZWXp999/d8g4AAAAcHOz+cxx37591a9fPx08eFD333+/pMtrjlNTUy3W4drb7NmzlZCQoBYtWpgfAjJ58mTz9ry8PO3bt89isfXrr79u7vvXh4BcsWjRIv3++++aNWuWZs2aZW6vUKGCfv75Z4eNBQAAADcnm8Px6NGjFRAQoAkTJigpKUmSFBERobFjx+rpp5+2e4FXhISEXPOBH1FRUTKZTBZtfn5+mjJliqZMmVLkPmPHjtXYsWPtWSYAAABuYTaHY4PBoCFDhmjIkCE6c+aMJCkgIMDuhQEAAADOdkP3Ob6CUAwAAIDbic0X5AEAAAC3K8IxAAAAUIBwDAAAABSwKRzn5eWpRYsWOnDggKPqAQAAAFzGpnDs7e2tH374wVG1AAAAAC5l87KKHj166L333nNELQAAAIBL2Xwrt0uXLmnGjBlatWqV6tWrp+LFi1tsnzhxot2KAwAAAJzJ5nC8a9cu1a1bV5K0f/9+i20Gg8E+VQEAAAAuYHM4Xr16tSPqAAAAAFzuhm/l9tNPP2nFihX6888/JUkmk8luRQEAAACuYHM4/uOPP9SiRQtVqVJF7dq109GjRyVJffr00dChQ+1eIAAAAOAsNofjIUOGyNvbW4cOHZK/v7+5vUuXLlq+fLldiwMAAACcyeY1xytXrtSKFStUrlw5i/bKlSvrl19+sVthAAAAgLPZfOb43LlzFmeMrzh58qR8fX3tUhQAAADgCjaH4wceeEAffvih+bXBYJDRaNQrr7yiBx980K7FAQAAAM5k87KKV155RS1atNDmzZt18eJFDR8+XD/++KNOnjyptWvXOqJGAAAAwClsPnNcs2ZN7d+/X02aNNGjjz6qc+fO6bHHHtO2bdtUqVIlR9QIAAAAOIXNZ44lKSgoSM8++6y9awEAAABc6obC8alTp/Tee+9pz549kqTq1asrPj5eISEhdi0OAAAAcCabl1V88803ioqK0uTJk3Xq1CmdOnVKkydPVsWKFfXNN984okYAAADAKWw+c/zUU0+pS5cumjZtmjw9PSVJ+fn5GjBggJ566int3LnT7kUCAAAAzmDzmeOffvpJQ4cONQdjSfL09FRiYqJ++uknuxYHAAAAOJPN4bhu3brmtcZ/tWfPHtWuXdsuRQEAAACuYNWyih9++MH856efflqDBg3STz/9pEaNGkmSNmzYoClTpujll192TJUAAACAE1gVjuvUqSODwSCTyWRuGz58eKF+jz/+uLp06WK/6gAAAAAnsiocZ2ZmOroOAAAAwOWsCscVKlRwdB0AAACAy93QQ0COHDmi7777TsePH5fRaLTY9vTTT9ulMAAAAMDZbA7HM2fOVP/+/eXj46NSpUrJYDCYtxkMBsIxAAAAblk2h+PRo0drzJgxSkpKkoeHzXeCAwAAAG5aNqfb8+fPq2vXrgRjAAAA3HZsTrh9+vTRwoULHVELAAAA4FI2L6tISUnRww8/rOXLl+uee+6Rt7e3xfaJEyfarTgAAADAmW4oHK9YsUJ33323JBW6IA8AAAC4VdkcjidMmKAZM2YoLi7OAeUAAAAArmPzmmNfX181btzYEbUAAAAALmVzOB40aJDefPNNR9QCAAAAuJTNyyo2bdqkr776Sp999plq1KhR6IK8xYsX2604AAAAwJlsDsclS5bUY4895ohaAAAAAJeyORy///77jqgDAAAAcDkecwcAAAAUsPnMccWKFa95P+ODBw/+o4IAAAAAV7E5HA8ePNjidV5enrZt26bly5dr2LBh9qoLAAAAcDqbw/GgQYOKbJ8yZYo2b978jwu6mpMnT2rgwIFatmyZPDw81LFjR73xxhsqUaLEVfe5cOGChg4dqnnz5ik3N1cxMTGaOnWqwsLCCvX9448/VLt2bR0+fFinTp1SyZIlHTYWAAAA3Jzstua4bdu2+vjjj+11uEK6d++uH3/8Uenp6frss8/0zTffqF+/ftfcZ8iQIVq2bJkWLlyoNWvW6MiRI1e900afPn1Uq1YtR5QOAACAW4TdwvGiRYsUEhJir8NZ2LNnj5YvX653331XDRs2VJMmTfTmm29q3rx5OnLkSJH7nD59Wu+9954mTpyo5s2bq169enr//fe1bt06bdiwwaLvtGnTlJ2drWeeecYh9QMAAODWYPOyinvvvdfigjyTyaSsrCz9/vvvmjp1ql2Lu2L9+vUqWbKk6tevb25r2bKlPDw8tHHjRnXo0KHQPlu2bFFeXp5atmxpbqtatarKly+v9evXq1GjRpKk3bt36/nnn9fGjRutvpgwNzdXubm55tc5OTmSLq+/zsvLu6Ex4vqufLZ8xu6FeXc/zLn7Yc7djyvm3Nr3sjkcx8bGWrz28PBQaGiomjVrpqpVq9p6OKtkZWWpTJkyFm1eXl4KCQlRVlbWVffx8fEptHY4LCzMvE9ubq66deumV199VeXLl7c6HKekpGjcuHGF2leuXCl/f3+rjoEbl56e7uoS4ALMu/thzt0Pc+5+nDnn58+ft6qfzeE4OTnZ5mKuZuTIkUpNTb1mnz179tjt/f4uKSlJ1apVU48ePWzeLzEx0fw6JydHkZGRat26tQIDA+1dJgrk5eUpPT1drVq1KvTYcty+mHf3w5y7H+bc/bhizq/8pv96bA7H9jR06FDFxcVds8+dd96p8PBwHT9+3KL90qVLOnnypMLDw4vcLzw8XBcvXlR2drbF2eNjx46Z9/nqq6+0c+dOLVq0SNLlJSKSVLp0aT377LNFnh2WJF9fX/n6+hZq9/b25i+1E/A5uyfm3f0w5+6HOXc/zpxza9/H6nDs4eFxzYd/SJLBYNClS5esPaRCQ0MVGhp63X7R0dHKzs7Wli1bVK9ePUmXg63RaFTDhg2L3KdevXry9vZWRkaGOnbsKEnat2+fDh06pOjoaEnSxx9/rD///NO8z/fff6/evXvr22+/VaVKlaweBwAAAG4PVofjTz755Krb1q9fr8mTJ8toNNqlqL+rVq2a2rRpo759+yotLU15eXlKSEhQ165dFRERIUk6fPiwWrRooQ8//FANGjRQUFCQ+vTpo8TERIWEhCgwMFADBw5UdHS0+WK8vwfgEydOmN+P+xwDAAC4H6vD8aOPPlqobd++fRo5cqSWLVum7t276/nnn7drcX81e/ZsJSQkqEWLFuaHgEyePNm8PS8vT/v27bNYbP3666+b+/71ISAAAABAUW5ozfGRI0eUnJysDz74QDExMdq+fbtq1qxp79oshISEaM6cOVfdHhUVZV4zfIWfn5+mTJmiKVOmWPUezZo1K3QMAAAAuA+bHgJy+vRpjRgxQnfddZd+/PFHZWRkaNmyZQ4PxgAAAIAzWH3m+JVXXlFqaqrCw8M1d+7cIpdZAAAAALcyq8PxyJEjVaxYMd1111364IMP9MEHHxTZb/HixXYrDgAAAHAmq8Nxz549r3srNwAAAOBWZnU4njlzpgPLAAAAAFzPpgvyAAAAgNsZ4RgAAAAoQDgGAAAAChCOAQAAgAKEYwAAAKAA4RgAAAAoQDgGAAAAChCOAQAAgAKEYwAAAKAA4RgAAAAoQDgGAAAAChCOAQAAgAKEYwAAAKAA4RgAAAAoQDgGAAAAChCOAQAAgAKEYwAAAKAA4RgAAAAoQDgGAAAAChCOAQAAgAKEYwAAAKAA4RgAAAAoQDgGAAAAChCOAQAAgAKEYwAAAKAA4RgAAAAoQDgGAAAAChCOAQAAgAKEYwAAAKCAl6sLuB2YTCZJUk5Ojosrub3l5eXp/PnzysnJkbe3t6vLgZMw7+6HOXc/zLn7ccWcX8lpV3Lb1RCO7eDMmTOSpMjISBdXAgAAgGs5c+aMgoKCrrrdYLpefMZ1GY1GHTlyRAEBATIYDK4u57aVk5OjyMhI/frrrwoMDHR1OXAS5t39MOfuhzl3P66Yc5PJpDNnzigiIkIeHldfWcyZYzvw8PBQuXLlXF2G2wgMDOR/nm6IeXc/zLn7Yc7dj7Pn/FpnjK/ggjwAAACgAOEYAAAAKEA4xi3D19dXycnJ8vX1dXUpcCLm3f0w5+6HOXc/N/Occ0EeAAAAUIAzxwAAAEABwjEAAABQgHAMAAAAFCAcAwAAAAUIx7jppaSk6L777lNAQIDKlCmj2NhY7du3z9VlwYlefvllGQwGDR482NWlwIEOHz6sHj16qFSpUipWrJjuuecebd682dVlwYHy8/M1evRoVaxYUcWKFVOlSpU0fvx4ca+A28c333yj9u3bKyIiQgaDQUuWLLHYbjKZNGbMGJUtW1bFihVTy5YtdeDAAdcUW4BwjJvemjVr9NRTT2nDhg1KT09XXl6eWrdurXPnzrm6NDjB999/r7ffflu1atVydSlwoFOnTqlx48by9vbWl19+qd27d2vChAkKDg52dWlwoNTUVE2bNk1vvfWW9uzZo9TUVL3yyit68803XV0a7OTcuXOqXbu2pkyZUuT2V155RZMnT1ZaWpo2btyo4sWLKyYmRhcuXHBypf/Drdxwy/n9999VpkwZrVmzRv/6179cXQ4c6OzZs6pbt66mTp2qF154QXXq1NGkSZNcXRYcYOTIkVq7dq2+/fZbV5cCJ3r44YcVFham9957z9zWsWNHFStWTLNmzXJhZXAEg8GgTz75RLGxsZIunzWOiIjQ0KFD9cwzz0iSTp8+rbCwMM2cOVNdu3Z1SZ2cOcYt5/Tp05KkkJAQF1cCR3vqqaf00EMPqWXLlq4uBQ62dOlS1a9fX506dVKZMmV077336p133nF1WXCw+++/XxkZGdq/f78kaceOHfruu+/Utm1bF1cGZ8jMzFRWVpbF/+ODgoLUsGFDrV+/3mV1ebnsnYEbYDQaNXjwYDVu3Fg1a9Z0dTlwoHnz5mnr1q36/vvvXV0KnODgwYOaNm2aEhMTNWrUKH3//fd6+umn5ePjo169erm6PDjIyJEjlZOTo6pVq8rT01P5+fl68cUX1b17d1eXBifIysqSJIWFhVm0h4WFmbe5AuEYt5SnnnpKu3bt0nfffefqUuBAv/76qwYNGqT09HT5+fm5uhw4gdFoVP369fXSSy9Jku69917t2rVLaWlphOPb2IIFCzR79mzNmTNHNWrU0Pbt2zV48GBFREQw73AZllXglpGQkKDPPvtMq1evVrly5VxdDhxoy5YtOn78uOrWrSsvLy95eXlpzZo1mjx5sry8vJSfn+/qEmFnZcuWVfXq1S3aqlWrpkOHDrmoIjjDsGHDNHLkSHXt2lX33HOPnnjiCQ0ZMkQpKSmuLg1OEB4eLkk6duyYRfuxY8fM21yBcIybnslkUkJCgj755BN99dVXqlixoqtLgoO1aNFCO3fu1Pbt280/9evXV/fu3bV9+3Z5enq6ukTYWePGjQvdonH//v2qUKGCiyqCM5w/f14eHpZRxNPTU0aj0UUVwZkqVqyo8PBwZWRkmNtycnK0ceNGRUdHu6wullXgpvfUU09pzpw5+vTTTxUQEGBehxQUFKRixYq5uDo4QkBAQKE15cWLF1epUqVYa36bGjJkiO6//3699NJL6ty5szZt2qTp06dr+vTpri4NDtS+fXu9+OKLKl++vGrUqKFt27Zp4sSJ6t27t6tLg52cPXtWP/30k/l1Zmamtm/frpCQEJUvX16DBw/WCy+8oMqVK6tixYoaPXq0IiIizHe0cAVu5YabnsFgKLL9/fffV1xcnHOLgcs0a9aMW7nd5j777DMlJSXpwIEDqlixohITE9W3b19XlwUHOnPmjEaPHq1PPvlEx48fV0REhLp166YxY8bIx8fH1eXBDr7++ms9+OCDhdp79eqlmTNnymQyKTk5WdOnT1d2draaNGmiqVOnqkqVKi6o9jLCMQAAAFCANccAAABAAcIxAAAAUIBwDAAAABQgHAMAAAAFCMcAAABAAcIxAAAAUIBwDAAAABQgHAMAAAAFCMcAALsxGAxasmSJq8sAgBtGOAaA20RcXJwMBkOhnzZt2ri6NAC4ZXi5ugAAgP20adNG77//vkWbr6+vi6oBgFsPZ44B4Dbi6+ur8PBwi5/g4GBJl5c8TJs2TW3btlWxYsV05513atGiRRb779y5U82bN1exYsVUqlQp9evXT2fPnrXoM2PGDNWoUUO+vr4qW7asEhISLLafOHFCHTp0kL+/vypXrqylS5c6dtAAYEeEYwBwI6NHj1bHjh21Y8cOde/eXV27dtWePXskSefOnVNMTIyCg4P1/fffa+HChVq1apVF+J02bZqeeuop9evXTzt37tTSpUt11113WbzHuHHj1LlzZ/3www9q166dunfvrpMnTzp1nABwowwmk8nk6iIAAP9cXFycZs2aJT8/P4v2UaNGadSoUTIYDHryySc1bdo087ZGjRqpbt26mjp1qt555x2NGDFCv/76q4oXLy5J+uKLL9S+fXsdOXJEYWFhuuOOOxQfH68XXnihyBoMBoOee+45jR8/XtLlwF2iRAl9+eWXrH0GcEtgzTEA3EYefPBBi/ArSSEhIeY/R0dHW2yLjo7W9u3bJUl79uxR7dq1zcFYkho3biyj0ah9+/bJYDDoyJEjatGixTVrqFWrlvnPxYsXV2BgoI4fP36jQwIApyIcA8BtpHjx4oWWOdhLsWLFrOrn7e1t8dpgMMhoNDqiJACwO9YcA4Ab2bBhQ6HX1apVkyRVq1ZNO3bs0Llz58zb165dKw8PD919990KCAhQVFSUMjIynFozADgTZ44B4DaSm5urrKwsizYvLy+VLl1akrRw4ULVr19fTZo00ezZs7Vp0ya99957kqTu3bsrOTlZvXr10tixY/X7779r4MCBeuKJJxQWFiZJGjt2rJ588kmVKVNGbdu21ZkzZ7R27VoNHDjQuQMFAAchHAPAbWT58uUqW7asRdvdd9+tvXv3Srp8J4l58+ZpwIABKlu2rObOnavq1atLkvz9/bVixQoNGjRI9913n/z9/dWxY0dNnDjRfKxevXrpwoULev311/XMM8+odOnS+ve//+28AQKAg3G3CgBwEwaDQZ988oliY2NdXQoA3LRYcwwAAAAUIBwDAAAABVhzDABuglV0AHB9nDkGAAAAChCOAQAAgAKEYwAAAKAA4RgAAAAoQDgGAAAAChCOAQAAgAKEYwAAAKAA4RgAAAAo8P/FRMhMYWM08QAAAABJRU5ErkJggg==\n",
      "text/plain": [
       "<Figure size 800x400 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Initialize weights to zeros (4 rows x 10 columns)\n",
    "weights = np.zeros((4, 10))\n",
    "errors_over_time = []\n",
    "\n",
    "# Hyperparameters\n",
    "epochs = 10\n",
    "\n",
    "print(\"Starting Training...\")\n",
    "\n",
    "for epoch in range(epochs):\n",
    "    total_errors_this_epoch = 0\n",
    "\n",
    "    # Shuffle data (good practice in ML to prevent order bias)\n",
    "    indices = np.arange(len(train_seqs))\n",
    "    np.random.shuffle(indices)\n",
    "\n",
    "    for i in indices:\n",
    "        seq = train_seqs[i]\n",
    "        true_label = train_labels[i]\n",
    "\n",
    "        # 1. Encode the sequence\n",
    "        X = one_hot_encode(seq)\n",
    "\n",
    "        # 2. Calculate Score (Forward Pass)\n",
    "        score = get_score(X, weights)\n",
    "\n",
    "        # 3. Make Prediction (Threshold = 0)\n",
    "        # TODO: replace the value for prediction\n",
    "        prediction = None\n",
    "\n",
    "        # 4. Update Rule (The Stormo Step)\n",
    "        if prediction == 0 and true_label == 1:\n",
    "            # FALSE NEGATIVE (Missed it)\n",
    "            # The score was too low. We need to boost the weights\n",
    "            # for the bases present in this sequence.\n",
    "            # TODO:\n",
    "            print('to do')\n",
    "\n",
    "        elif prediction == 1 and true_label == 0:\n",
    "            # FALSE POSITIVE (False Alarm)\n",
    "            # The score was too high. We need to penalize the weights\n",
    "            # for the bases present in this sequence.\n",
    "            # TODO:\n",
    "            print('to do')\n",
    "\n",
    "        # If prediction == true_label, we do nothing!\n",
    "\n",
    "    errors_over_time.append(total_errors_this_epoch)\n",
    "    print(f\"Epoch {epoch+1}: Total Errors = {total_errors_this_epoch}\")\n",
    "\n",
    "# Plotting the Learning Curve\n",
    "plt.figure(figsize=(8,4))\n",
    "plt.plot(range(1, epochs+1), errors_over_time, marker='o')\n",
    "plt.title(\"Learning Curve: Errors vs Time\")\n",
    "plt.xlabel(\"Epoch\")\n",
    "plt.ylabel(\"Number of Misclassified Sequences\")\n",
    "plt.grid(True)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "eGfTH5YdcWMl"
   },
   "source": [
    "## Opening the \"Black Box\"\n",
    "\n",
    "One major advantage of this simple perceptron model over complex deep neural networks is interpretability. Because our weights are just a $4 \\times L$ matrix, we can look directly at them to ee what the model learned. We'll visualize the weights as a heatmap.\n",
    "\n",
    "**Discussion Question**: Does the heatmap match the biological reality? We know the consensus Shine-Dalgarno sequence is AGGAGG. Look at positions 2 through 7 in the heatmap. Do you see high values for 'A' and 'G' in those columns?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 379
    },
    "id": "z-po0pFgcVN7",
    "outputId": "88b94566-51eb-4f01-edb6-4bc6a4233391"
   },
   "outputs": [
    {
     "data": {
      "image/png": "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Xn5+fk5ruueee/Tnn39q27Zt16wfAJC/CKUA8lVSUpKaNWumH374QYMGDdK7776r6tWrKzIyUhMnTrTPO336tD766CO1bt1a48eP16hRo3TixAlFREQ4/aFw1qxZmjRpkvr3768JEyY4/GD5yCOP6MyZM4qJidEjjzyi2bNn57q88vXXX1fv3r1Vo0YNvf322xoyZIji4uJ09913OwSwGTNm6Mknn1RAQIDeeOMN3XXXXfrPf/7jNLyalZmZqb/++kulSpWSJO3cuVMtW7bUL7/8ohdffFGvvPKKDhw4oNatW2vDhg327UaNGqXRo0erTZs2mjx5soYPH65KlSppy5YtV/ysOXPmyN3dXS1btrRfLvnkk09ecf6oUaM0cOBABQYGasKECeratas++OAD3XvvvbkuqU1JSVH79u3VoEEDTZgwQcHBwfrf//6n77777qrHX7VqVQUGBjqc6dq0aZMyMjLUvHnzXIHj0hnVS6HU7PeUM99++626deumokWLKiYmRl26dFFkZGSuM7OXzJs3T2+++aaefPJJjRkzRgcPHlSXLl3svXjyySftZ9ou9XfOnDlXreGSnj176tixY/bAeOnz2rVrpzJlyuSav2nTJq1bt07du3fXe++9p6eeekpxcXFq3bq1/Zcud999t5555hlJ0ksvvWSvp1atWvb97N27Vz169NA999yjd999Vw0bNsz1WTabTTNnztSFCxccLr8dOXKkdu7cqVmzZql48eJXPLYjR47o0KFDuvPOO031Qrp4T6irq6s9VLZo0UKbN29Wenq6pIuBeNOmTfbvkXXr1tnPYqakpGjXrl25Lt29pEePHpo/f759/smTJ7VixQr17NnzivWEhIRIUq7wCwC4CQwAMGnWrFmGJGPTpk1XnBMZGWmUK1fOOHnypMN49+7dDW9vb+PcuXOGYRhGVlaWkZ6e7jAnJSXFKFu2rPH444/bxw4cOGBIMry8vIzjx487zB85cqQhyWG+YRjGgw8+aJQqVcr+9cGDBw1XV1fj9ddfd5i3fft2o0iRIvbxjIwMo0yZMkbDhg0daps+fbohyWjVqtUVj/uSypUrG/fee69x4sQJ48SJE8Yvv/xidO/e3ZBkDB482DAMw+jcubPh5uZm7N+/377d0aNHjZIlSxp33323faxBgwZGx44dr/p5l3pwueLFixt9+vTJNffS39+BAwcMwzCM48ePG25ubsa9995rZGdn2+dNnjzZkGTMnDnTPtaqVStDkvHJJ5/Yx9LT042AgACja9eu1+zLww8/bHh6ehoZGRmGYRhGTEyMERQUZBiGYUydOtUoU6aMfe7zzz9vSDKOHDliGIb576lL3yuzZs2yz6lXr55RoUIF48yZM/axVatWGZKMypUr28cubVuqVCkjOTnZPv71118bkowlS5bYxwYOHJir51fTqlUro06dOoZhGEbjxo2NyMhIwzAufr+7ubkZH3/8sfHjjz8akoyFCxfat7t0XJeLj4/P9fewcOFCQ5Lx448/5ppfuXJlQ5KxfPlyp+v++X3ywQcfGJKMTz/91Fi/fr3h6upqDBky5JrH+MMPP+Tq0+XHHxwcbP83sXv3buOZZ54xJBkPPPCAfd6UKVMMScbPP//scKx//vmnsWvXLkOSsXPnTsMwDGPp0qWGJGPu3Ln27S/9Hb755pvGjh07HPY1ZcoUo0SJEsbZs2eNPn36GMWLF3d6HG5ubsaAAQOuebwAgPzFmVIA+cYwDH355Zd64IEHZBiGTp48aV8iIiJ06tQp+1k+V1dXubm5SZJycnKUnJysrKwsNW7c2OmZwK5du8rf39/p5/7zwSotW7bU33//rdOnT0uSvvrqK+Xk5OiRRx5xqCkgIEA1atSwXzK8efNmHT9+XE899ZS9NuniJZve3t6m+7BixQr5+/vL399fDRo00MKFC/Xf//5X48ePV3Z2tlasWKHOnTuratWq9m3KlSunnj17as2aNfa6fXx8tHPnTv3++++mPzsvfvjhB2VkZGjIkCFycfm//zvo16+fvLy89O233zrML1GihB599FH7125ubmratKn++OOPa35WixYtHO4dXbt2rf1ewLvuukvHjx+3H+fatWsVFBSkwMDAPH1P/dPRo0e1fft29e7d2+Fpq61atVK9evWcbtOtWzf5+vrav27ZsqUkmTpGM3r27KmvvvpKGRkZ+uKLL+Tq6qoHH3zQ6VxPT0/7nzMzM/X333+revXq8vHxuerZ8n8KCgpSRESEqbn9+/dXRESEBg8erP/+97+qVq2axo4de83t/v77b0ly6N3l9uzZY/83UatWLU2aNEkdO3Z0uAT7n/eVrl27VuXLl1elSpUUHBwsPz8/+1nMKz3k6JI6deqofv369nt4582bp06dOqlY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paSkaPLkyapbt+51f59denXIM888o4iICLm6uqp79+6mt/f29s51/M7cf//9mjNnjry9vVW7dm3Fx8frhx9+sF8qe0nDhg3l6uqq8ePH69SpU3J3d1fbtm2dvmbmambNmqVvv/1Ws2fPVoUKFSRdDMGPPvqo3n//fT399NNX3b5Tp05atGjRv7ovs2nTpnJzc1N8fLxat27tcHazWLFiatCggeLj4+Xj46O6detec3+tWrVSq1atTH12bGysKlWqpEaNGl1X7QCAf+HmPuwXwK3s0itFrrT89ddfhmEYRlJSkjFw4ECjYsWKRtGiRY2AgACjXbt2xvTp0+37ysnJMcaOHWtUrlzZcHd3Nxo1amQsXbrU6NOnj9NXdbz55pu56rn0OpQTJ044rfPSq08u+fLLL40WLVoYxYsXN4oXL24EBwcbAwcONPbu3eswb+rUqUZQUJDh7u5uNG7c2Pjpp5+MVq1amX4lzLVe42IYhrFlyxYjIiLCKFGihFGsWDGjTZs2xrp16xzmjBkzxmjatKnh4+NjeHp6GsHBwcbrr79uf63K5T243J49e4y7777b8PT0NCTZX/txpb5MnjzZCA4ONooWLWqULVvWGDBggJGSkuIw5/LXmlzun39fV3P27FmjSJEihiRjxYoVudbXr1/fkGSMHz8+1zoz31POXgljGIYxf/58Izg42HB3dzfq1q1rfPPNN0bXrl2N4ODgXNs6+z6TZIwcOdL+dVZWljF48GDD39/fsNls13w9zJV6dzlnr4RJSUkx+vbta5QuXdooUaKEERERYezZs8fpq1w+/PBDo2rVqoarq6vD62Gu9v14+X7++usvw9vb2+EVLZc8+OCDRvHixY0//vjjqsewZcsWh9ew5OX4LxcWFmZIMl566aVc6y69Sua+++7Lte5qf4eXc/ZKmOzsbKNcuXLGyy+/bLpOAED+sRlGPj29AQCAW0TDhg3l7++v2NhYq0spVNq1a6fAwEDNmTPH6lLyZPHixerZs6f279+vcuXKWV0OANx2uKcUAFBoZWZmKisry2Fs1apV+uWXX9S6dWtriirExo4dqwULFuR6nVBBN378eA0aNIhACgAW4UwpAKDQOnjwoMLDw/Xoo48qMDBQe/bs0bRp0+Tt7a0dO3bkuj8TAADcfDzoCABQaPn6+iokJEQfffSRTpw4oeLFi6tjx44a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ns+U5uTkKDs7O9f44cOHeeARAAAAACBP8hxK7733Xk2cONH+tc1mU1pamkaOHKkOHTrkZ20AAAAAgEIuz5fvTpgwQREREapdu7YuXLignj176vfff1fp0qX12Wef3YgaAQAAAACFVJ5DaYUKFfTLL79o/vz5+vXXX5WWlqbIyEj16tXL4cFHAAAAAABcS55DqSQVKVJEjz76aH7XAgAAAAC4zZgKpd98843pHf7nP/+57mIAAAAAALcXU6G0c+fOpnZms9mcPpkXAAAAAABnTIXSnJycG10HAAAAAOA2lOdXwgAAAAAAkF/yHEqfeeYZvffee7nGJ0+erCFDhuRHTQAAAACA20SeQ+mXX36pu+66K9d48+bN9cUXX+RLUQAAAACA20OeQ+nff/8tb2/vXONeXl46efJkvhQFAAAAALg95DmUVq9eXcuXL881/t1336lq1ar5UhQAAAAA4PZg6um7l4uKitKgQYN04sQJtW3bVpIUFxenCRMmaOLEifldHwAAAACgEMtzKH388ceVnp6u119/Xa+99pokqUqVKnr//ffVu3fvfC8QAAAAAFB45TmUStKAAQM0YMAAnThxQp6enipRokR+1wUAAAAAuA1cVyi9xN/fP7/qAAAAAADchvIcSoOCgmSz2a64/o8//vhXBQEAAAAAbh95DqVDhgxx+DozM1Nbt27V8uXL9cILL+RXXQAAAACA20CeQ+mzzz7rdHzKlCnavHnzvy4IAAAAAHD7+Ff3lF7uvvvuU3R0tGbNmpVfu7yldOkQqB5dKsrP1037D6TpnQ/2affvZ644v81dpfXEo0EKKOOhw0fP6f3ZB7Q+IfkmVmwdemUOfTKPXplDn8yhT+bRK3Pok3n0yhz6hMLGJb929MUXX8jPzy+/dndLadvCX4OeqKZZnx1U5JAE7TuQprdfrScf76JO59cN9tLIF2pr6YpjevzZBP28/m/FDK+joErFbnLlNx+9Moc+mUevzKFP5tAn8+iVOfTJPHplDn2CM8nJyerVq5e8vLzk4+OjyMhIpaWlXXWbCxcuaODAgSpVqpRKlCihrl27Kikpyb7+l19+UY8ePVSxYkV5enqqVq1aevfddx32sWrVKtlstlxLYmJinurPcyht1KiR7rzzTvvSqFEjlStXTi+99JJeeukl0/s5f/68li5dav86OjpaUVFR9uWFF17Q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UYMHD9awYcMsrq5gstlsWrRokTp37mx1KQXeiRMnVKZMGa1evVp333231eUUaH5+fnrzzTcVGRlpdSkFTlpamu68805NnTpVY8aMUcOGDTVx4kSryypQRo0apcWLF2vbtm1Wl1KgDRs2TGvXrtXPP/9sdSm3nCFDhmjp0qX6/fffZbPZrC6nwLj//vtVtmxZzZgxwz7WtWtXeXp66tNPP7WwsoLn/PnzKlmypL7++mt17NjRPh4SEqL77rtPY8aMsbA64Oo4U3oDZWRkKCEhQeHh4fYxFxcXhYeHKz4+3sLKUFicOnVK0sXABeeys7M1f/58nT17VmFhYVaXUyANHDhQHTt2dPhvFXL7/fffFRgYqKpVq6pXr146dOiQ1SUVON98840aN26shx9+WGXKlFGjRo304YcfWl1WgZeRkaFPP/1Ujz/+OIH0H5o3b664uDj99ttvkqRffvlFa9as0X333WdxZQVPVlaWsrOz5eHh4TDu6enJlR0o8IpYXUBhdvLkSWVnZ6ts2bIO42XLltWePXssqgqFRU5OjoYMGaK77rpLdevWtbqcAmf79u0KCwvThQsXVKJECS1atEi1a9e2uqwCZ/78+dqyZQv3HF1DaGioZs+erZo1a+rYsWMaPXq0WrZsqR07dqhkyZJWl1dg/PHHH3r//fcVFRWll156SZs2bdIzzzwjNzc39enTx+ryCqzFixcrNTVVjz32mNWlFDjDhg3T6dOnFRwcLFdXV2VnZ+v1119Xr169rC6twClZsqTCwsL02muvqVatWipbtqw+++wzxcfHq3r16laXB1wVoRS4RQ0cOFA7duzgt59XULNmTW3btk2nTp3SF198oT59+mj16tUE08v89ddfevbZZxUbG5vrN+twdPlZmfr16ys0NFSVK1fW559/ziXhl8nJyVHjxo01duxYSVKjRo20Y8cOTZs2jVB6FTNmzNB9992nwMBAq0spcD7//HPNnTtX8+bNU506dbRt2zYNGTJEgYGBfE85MWfOHD3++OMqX768XF1ddeedd6pHjx5KSEiwujTgqgilN1Dp0qXl6uqqpKQkh/GkpCQFBARYVBUKg0GDBmnp0qX66aefVKFCBavLKZDc3NzsvxkOCQnRpk2b9O677+qDDz6wuLKCIyEhQcePH9edd95pH8vOztZPP/2kyZMnKz09Xa6urhZWWHD5+Pjojjvu0L59+6wupUApV65crl/81KpVS19++aVFFRV8f/75p3744Qd99dVXVpdSIL3wwgsaNmyYunfvLkmqV6+e/vzzT8XExBBKnahWrZpWr16ts2fP6vTp0ypXrpy6deumqlWrWl0acFXcU3oDubm5KSQkRHFxcfaxnJwcxcXFcW8brothGBo0aJAWLVqklStXKigoyOqSbhk5OTlKT0+3uowCpV27dtq+fbu2bdtmXxo3bqxevXpp27ZtBNKrSEtL0/79+1WuXDmrSylQ7rrrrlyvqfrtt99UuXJliyoq+GbNmqUyZco4PJgG/+fcuXNycXH8cdXV1VU5OTkWVXRrKF68uMqVK6eUlBR9//336tSpk9UlAVfFmdIbLCoqSn369FHjxo3VtGlTTZw4UWfPnlXfvn2tLq1ASUtLczjjcODAAW3btk1+fn6qVKmShZUVLAMHDtS8efP09ddfq2TJkkpMTJQkeXt7y9PT0+LqCo7o6Gjdd999qlSpks6cOaN58+Zp1apV+v77760urUApWbJkrvuRixcvrlKlSnGf8j88//zzeuCBB1S5cmUdPXpUI0eOlKurq3r06GF1aQXK0KFD1bx5c40dO1aPPPKINm7cqOnTp2v69OlWl1Yg5eTkaNasWerTp4+KFOFHMmceeOABvf7666pUqZLq1KmjrVu36u2339bjjz9udWkF0vfffy/DMFSzZk3t27dPL7zwgoKDg/m5EwWfgRtu0qRJRqVKlQw3NzejadOmxvr1660uqcD58ccfDUm5lj59+lhdWoHirEeSjFmzZlldWoHy+OOPG5UrVzbc3NwMf39/o127dsaKFSusLuuW0KpVK+PZZ5+1uowCp1u3bka5cuUMNzc3o3z58ka3bt2Mffv2WV1WgbRkyRKjbt26hru7uxEcHGxMnz7d6pIKrO+//96QZOzdu9fqUgqs06dPG88++6xRqVIlw8PDw6hataoxfPhwIz093erSCqQFCxYYVatWNdzc3IyAgABj4MCBRmpqqtVlAdfEe0oBAAAAAJbhnlIAAAAAgGUIpQAAAAAAyxBKAQAAAACWIZQCAAAAACxDKAUAAAAAWIZQCgAAAACwDKEUAAAAAGAZQikAAAAAwDKEUgAoxFatWiWbzabU1NSrzqtSpYomTpx4Q2uZPXu2fHx8buhnAACAWw+hFAAs9thjj8lms8lms8nNzU3Vq1fXq6++qqysrH+97+bNm+vYsWPy9vaWdOVguGnTJvXv3/9ff97VdOvWTb/99tu/3s+HH36oBg0aqESJEvLx8VGjRo0UExOTDxUCAAArFLG6AACA1L59e82aNUvp6elatmyZBg4cqKJFiyo6Ovpf7dfNzU0BAQHXnOfv7/+vPscMT09PeXp6/qt9zJw5U0OGDNF7772nVq1aKT09Xb/++qt27NiRT1UCAICbjTOlAFAAuLu7KyAgQJUrV9aAAQMUHh6ub775RpKUkpKi3r17y9fXV8WKFdN9992n33//3b7tn3/+qQceeEC+vr4qXry46tSpo2XLlklyvHx31apV6tu3r06dOmU/Mztq1ChJuS/fPXTokDp16qQSJUrIy8tLjzzyiJKSkuzrR40apYYNG2rOnDmqUqWKvL291b17d505c+aKx/jPs7TXs49vvvlGjzzyiCIjI1W9enXVqVNHPXr00Ouvv+4w76OPPlKtWrXk4eGh4OBgTZ061WH9xo0b1ahRI3l4eKhx48ZatGiRbDabtm3b5rRWSVq8eLFsNpvD2Ndff60777xTHh4eqlq1qkaPHu1whttms+mjjz7Sgw8+qGLFiqlGjRr2v9dLdu7cqfvvv19eXl4qWbKkWrZsqf3795s+FgAAbnWEUgAogDw9PZWRkSHp4uW9mzdv1jfffKP4+HgZhqEOHTooMzNTkjRw4EClp6frp59+0vbt2zV+/HiVKFEi1z6bN2+uiRMnysvLS8eOHdOxY8f0/PPP55qXk5OjTp06KTk5WatXr1ZsbKz++OMPdevWzWHe/v37tXjxYi1dulRLly7V6tWrNW7cuDwdZ173ERAQoPXr1+vPP/+84py5c+dqxIgRev3117V7926NHTtWr7zyij7++GNJUlpamu6//37Vrl1bCQkJGjVqlNM+XMvPP/+s3r1769lnn9WuXbv0wQcfaPbs2bkC8ujRo/XII4/o119/VYcOHdSrVy8lJydLko4cOaK7775b7u7uWrlypRISEvT444/bg+21jgUAgELBAABYqk+fPkanTp0MwzCMnJwcIzY21nB3dzeef/5547fffjMkGWvXrrXPP3nypOHp6Wl8/vnnhmEYRr169YxRo0Y53fePP/5oSDJSUlIMwzCMWbNmGd7e3rnmVa5c2XjnnXcMwzCMFStWGK6ursah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\n",
      "text/plain": [
       "<Figure size 1200x500 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True Motif:      ..AGGAGG..\n",
      "Learned Motif:   AAAAAAAAAA\n"
     ]
    }
   ],
   "source": [
    "# Define the bases for the Y-axis labels\n",
    "bases = ['A', 'C', 'G', 'T']\n",
    "\n",
    "plt.figure(figsize=(12, 5))\n",
    "\n",
    "# Create a heatmap using Seaborn\n",
    "sns.heatmap(weights,\n",
    "            yticklabels=bases,\n",
    "            xticklabels=range(10),\n",
    "            cmap=\"coolwarm\",\n",
    "            center=0,\n",
    "            annot=True, # Show the actual numbers in the boxes\n",
    "            fmt=\".1f\")\n",
    "\n",
    "plt.title(\"Learned Position Weight Matrix (PWM)\")\n",
    "plt.xlabel(\"Position in Sequence\")\n",
    "plt.ylabel(\"Nucleotide Base\")\n",
    "plt.show()\n",
    "\n",
    "# Programmatic check: What is the \"consensus\" sequence according to the model?\n",
    "# We take the base with the highest weight at each column.\n",
    "consensus_indices = np.argmax(weights, axis=0)\n",
    "learned_motif = \"\".join([bases[i] for i in consensus_indices])\n",
    "\n",
    "print(f\"True Motif:      ..AGGAGG..\")\n",
    "print(f\"Learned Motif:   {learned_motif}\")"
   ]
  }
 ],
 "metadata": {
  "accelerator": "GPU",
  "colab": {
   "gpuType": "T4",
   "provenance": []
  },
  "kernelspec": {
   "display_name": "Python 3",
   "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.8.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
