{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Fast Fibonacci in Python\n",
    "============================\n",
    "The Fibonacci sequence is a classic example of a recursive relationship. It has the following definition\n",
    "$$\n",
    "\\begin{align*}\n",
    "F_n &= F_{n-1} + F_{n-2} \\\\\n",
    "F_0 &= 0 \\\\\n",
    "F_1 &= 1\n",
    "\\end{align*}\n",
    "$$\n",
    "There are a variety of ways to implement a function to calculate the n'th Fibonacci number.\n",
    "  - **Top-down recursive**: This is one of the worst possible ways to implement Fibonacci, at least in terms of speed. This is because for each call to `fib(n)`, we make a call to `fib(n-1)` and `fib(n-2)`. For the `n-1` call we then call `fib(n-2)` and `fib(n-3)`. We've already had to calculate `fib(n-2)` twice, and this problem just gets worse the further we go down the call tree until we reach the base cases. The time complexity of this approach is $O(2^n)$ which is obviously unacceptable. This problem can be alieviated by caching already-calculated results which will help tremendously, but is still not the ideal solution.\n",
    "  - **Bottom-up looping**: This is a much more reasonable solution. All we do here is start with the base cases and use the recursion rule to calculate the next 2nd Fibonacci number, then the 3rd and so on in a loop until we reach the one we are looking for. The time complexity of this solution is $O(n)$. Much better than the exponential time above, but we can still do better.\n",
    "  - **Binary Matrix Exponentiation(BME)**: We can write the recursive formula as a matrix operation. To see how we do this, first consider a 2-element column vector with the elements $F_{n-1}$ and $F_{n-2}$.\n",
    "  $$\n",
    "  \\begin{pmatrix}\n",
    "  F_{n-1} \\\\\n",
    "  F_{n-2}\n",
    "  \\end{pmatrix}\n",
    "  $$\n",
    "  We can advance this matrix to the next higher pair of Fibonacci numbers ($F_{n}$, and $F_{n-1}$) by multiplying this vector by the following matrix.\n",
    "  $$\n",
    "  \\begin{pmatrix}\n",
    "  1 & 1 \\\\\n",
    "  1 & 0 \n",
    "  \\end{pmatrix}\n",
    "  $$\n",
    "  Finally notice that if we multiply the result by this matrix again, it advances our set of number twice, and if we start with our base case and multiply $n-1$ times, we can get the n'th Fibonacci number. Therefore, we have\n",
    "  $$\n",
    "  \\begin{pmatrix}\n",
    "  F_{n} \\\\\n",
    "  F_{n-1}\n",
    "  \\end{pmatrix}\n",
    "  = \n",
    "  \\begin{pmatrix}\n",
    "  1 & 1 \\\\\n",
    "  1 & 0\n",
    "  \\end{pmatrix}^{n-1}\n",
    "  \\begin{pmatrix}\n",
    "  1 \\\\\n",
    "  0\n",
    "  \\end{pmatrix}\n",
    "  $$\n",
    "  Now if we can find a fast way to find the n'th power of a matrix, we would be golden. Turns out there is a fast way to do this. We just apply the [Binary Exponentiation](http://en.wikipedia.org/wiki/Exponentiation_by_squaring) algorithm which can find the n'th power of something in $O(\\log(n))$ time. Since the remaining operations after we have found the power of the matrix are constant in time, the overall time complexity of our algorithm is now $O(\\log(n))$. \n",
    "\n",
    "**NOTE:** While the BME algorithm has the best time complexity for calculating the n'th Fibonacci number, we shouldn't necessarily always use it. For small n, for example, it's likely that the simple loop algorithm will run a bit faster just because it lacks some of the extra machinery required to run BME(We'll actually see this later). Furthermore, if we are interested in calculating the Fibonacci *sequence*, meaning all of first n Fibonacci numbers, then BME has a problem because it necessarily leaps over some numbers in the sequence(hence it's speed). But this means that we would have to make a separate call to BME for each number. Turns out, this leads to $O(n\\log(n))$ time complexity which is *worse* than the simple loop algorithm.\n",
    "\n",
    "-------------------------------------------\n",
    "This is all fine and good, but I wanna see some code! Okay, well since we are so hung up on doing this fast, it's probably worthwhile to make our code as efficient as possible, but we also don't want to do something crazy like not use python for once, so we're going to implement some of thise algorithms in both raw python and also using cython to get some compilation goodness. Then we will compare the speeds of the various implementations.\n",
    "\n",
    "Ooohkay! Let's get booted up!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "27/03/2015 \n",
      "\n",
      "CPython 3.4.3\n",
      "IPython 3.0.0\n",
      "\n",
      "cython 0.22\n",
      "numpy 1.9.2\n",
      "matplotlib 1.4.0\n",
      "\n",
      "compiler   : GCC 4.9.2 20150304 (prerelease)\n",
      "system     : Linux\n",
      "release    : 3.19.2-1-ARCH\n",
      "machine    : x86_64\n",
      "processor  : \n",
      "CPU cores  : 4\n",
      "interpreter: 64bit\n"
     ]
    }
   ],
   "source": [
    "%reload_ext Cython\n",
    "%load_ext watermark\n",
    "%watermark -dvm -p cython,numpy,matplotlib"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The following cell contains python implementations of the bottom-up looping and BME algorithms described above. Note I've chosen to just use an ad-hoc 2x2 matrix multiplication function rather than involve numpy. Maybe it's a bit simpler? Eh. A matter of taste."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "def fib(n):\n",
    "    a,b = 0., 1.\n",
    "    for _ in range(n):\n",
    "        a,b = a+b,a\n",
    "    return a\n",
    "\n",
    "E00,E01,E10,E11=0,1,2,3\n",
    "\n",
    "tmp = [0,0,0,0]\n",
    "def mat_prod(m1, m2): #m1 *= m2\n",
    "    for i in range(4): tmp[i] = m1[i]\n",
    "    m1[E00] = tmp[E00]*m2[E00] + tmp[E01]*m2[E10]\n",
    "    m1[E01] = tmp[E00]*m2[E01] + tmp[E01]*m2[E11]\n",
    "    m1[E10] = tmp[E10]*m2[E00] + tmp[E11]*m2[E10]\n",
    "    m1[E11] = tmp[E10]*m2[E00] + tmp[E01]*m2[E10]\n",
    "\n",
    "def mat_square(m1): #m1 = m1**2\n",
    "    for i in range(4): tmp[i] = m1[i]\n",
    "    m1[E00] = tmp[E00]*tmp[E00] + tmp[E01]*tmp[E10]\n",
    "    m1[E01] = tmp[E00]*tmp[E01] + tmp[E01]*tmp[E11]\n",
    "    m1[E10] = tmp[E10]*tmp[E00] + tmp[E11]*tmp[E10]\n",
    "    m1[E11] = tmp[E10]*tmp[E00] + tmp[E01]*tmp[E10]\n",
    "\n",
    "def fib_bme(n):\n",
    "    x = [1.,0.,0.,1.]\n",
    "    p = [1.,1.,1.,0.]\n",
    "    N = 1\n",
    "    while N <= n:\n",
    "        if n & N:\n",
    "            mat_prod(x,p)\n",
    "        mat_square(p)\n",
    "        N <<= 1\n",
    "    return x[E10]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The cell below contains the cython implementation of the algorithms. I've tried to keep a close correspondence between the two implementations. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "%%cython --force\n",
    "\n",
    "cdef float fib(int n):\n",
    "    cdef int i\n",
    "    cdef float a=0.0, b=1.0\n",
    "    cdef float tmp\n",
    "    for i in range(n):\n",
    "        tmp = a\n",
    "        a += b\n",
    "        b = tmp\n",
    "    return a\n",
    "\n",
    "cdef unsigned int E00=0, E01=1, E10=2, E11=3\n",
    "\n",
    "cdef float tmp[4];\n",
    "cdef void mat_prod(float *m1, float *m2): # m1 *= m2\n",
    "    cdef unsigned int i\n",
    "    for i in range(4):\n",
    "        tmp[i] = m1[i]\n",
    "    m1[E00] = tmp[E00]*m2[E00] + tmp[E01]*m2[E10]\n",
    "    m1[E01] = tmp[E00]*m2[E01] + tmp[E01]*m2[E11]\n",
    "    m1[E10] = tmp[E10]*m2[E00] + tmp[E11]*m2[E10]\n",
    "    m1[E11] = tmp[E10]*m2[E01] + tmp[E11]*m2[E11]\n",
    "\n",
    "cdef void mat_square(float *m1): # m1*= m1\n",
    "    cdef unsigned int i\n",
    "    for i in range(4):\n",
    "        tmp[i] = m1[i]\n",
    "    m1[E00] = tmp[E00]*tmp[E00] + tmp[E01]*tmp[E10]\n",
    "    m1[E01] = tmp[E00]*tmp[E01] + tmp[E01]*tmp[E11]\n",
    "    m1[E10] = tmp[E10]*tmp[E00] + tmp[E11]*tmp[E10]\n",
    "    m1[E11] = tmp[E10]*tmp[E01] + tmp[E11]*tmp[E11]\n",
    "    \n",
    "cdef float fib_bme(unsigned int n):\n",
    "    cdef float *x = [1.,0.,0.,1.]\n",
    "    cdef float *p = [1.,1.,1.,0.]\n",
    "    cdef unsigned int N = 0x1\n",
    "    while N <= n:\n",
    "        if n & N:\n",
    "            mat_prod(x,p) #x *= p\n",
    "        mat_square(p)   #p *= p\n",
    "        N <<= 1\n",
    "    return x[E10]\n",
    "\n",
    "def cfib_bme(n):\n",
    "    return fib_bme(n)\n",
    "def cfib(n):\n",
    "    return fib(n)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now we just run the code for a wide range of n values and see how quickly each implementation runs."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "import time\n",
    "import numpy as np\n",
    "data = {fib  : [],\n",
    "        cfib : [],\n",
    "        fib_bme : [],\n",
    "        cfib_bme : []\n",
    "        }\n",
    "ns = np.logspace(1,6, num=10, dtype=np.int64)[::-1]\n",
    "N = 40\n",
    "for n in ns:\n",
    "    for func,times in data.items():\n",
    "        t_start = time.time()\n",
    "        for _ in range(N): \n",
    "            func(n)\n",
    "        t_end = time.time()\n",
    "        times.append(t_end-t_start)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "image/png": [
       "iVBORw0KGgoAAAANSUhEUgAAAsgAAAHmCAYAAABu5XitAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\n",
       "AAAT/gAAE/4BB5Q5hAAAIABJREFUeJzs3Xm8nHV59/HPlRAghiQnBAIoAglLtaWlCWCfVktVAmj7\n",
       "aGsTQOtWrUlQcAchbqdTITsgKEISSkutGwFculhMQq36PNUatkdxJQm4sMRATsK+5Xr+uH7DmcyZ\n",
       "OWfOmXvmnnvm+3695pXMb+bc9+9kTs5c87uv33WZuyMiIiIiImFc3hMQEREREekkCpBFRERERCoo\n",
       "QBYRERERqaAAWURERESkggJkEREREZEKCpBFRERERCooQBYRERERqaAAWURERESkggLkOsxstZnN\n",
       "znseIiIiItJeCpCrmNk8M1sGnA6ozaCIiIhIjzG1mq7NzO4C5rv77XnPRURERETaRyvIIiIiIiIV\n",
       "9sp7Alkzsz5gLbDE3W+r8fh8YCYwABwJrHf3je2dpYiIiIh0qq4JkNOGujOBB4F5wJU1njMXWOju\n",
       "p1aMbTKzBbWCaRERERHpPV2TYuHut7n7Be6+cpinLQeuqxpbncZFRERERLonQB5JSr2YDWypemgH\n",
       "MLfel7V0UiIiIiLScXomQAZmpT8fqhofADCzI9KfJ6cyb7OA5WZ2XrsmKCIiIiL565oc5AbsX2e8\n",
       "HDD3AaQNexuBC9oxKRERERHpLL0UINdTL3AeFTN7nPj33J7F8URERERkiAOAZ9x9YitP0kspFuWV\n",
       "4uqAuC/9OdDk8fcCxgMz6twmNXn8sWjFOZs55mi/ttHnj/S84R6v99hox/Oi13jkx0fzWnba6wt6\n",
       "jRt5XK9xtsdsxWvc7HP0Gmd7zDxe49G+vpOI+Okg9oyn9gL2aWA+TemlFeTy5ry+Wg+6+91NHn87\n",
       "MMPdxzd5nMyY2f3ufkinHHO0X9vo80d63nCP13tstON50Ws88uOjeS077fUFvcaNPK7XONtjtuI1\n",
       "bvY5eo2zPWYer/FYXt+Kxw6uuH8fESi3VM+sILv7ALABmF710CxgfftnJCIiIiKdqOsC5FTODWqX\n",
       "aFsOLKoaO4Ps6iCbmd1fcTs3o+OKiIiI9CQzO7ccWxGrxy0vw9s1KRZmNpMIfucADqw2s+upaCXt\n",
       "7hvNbGkq47aZSLdY4u43ZzQNr7wM0AFWddgxR/u1jT5/pOcN93i9x1rxb9cKeo1HflyvcbbH1Guc\n",
       "vV54jZt9jl7jbI+Zx2s8ltcXYJW7ryo/p10pFuburT5HTyi/YJ2UgyzZq86Fku6i17f76TXufnqN\n",
       "u1u74q2uS7HImVIsRERERDKkFIvie0SfWrteUS7nydjo9e1+eo27n17jLlMjxaLlpfyUYpGR9ILR\n",
       "aaVlRERERLpFu+ItpVhka5JSLERERESyUyPFQivIRdHoJxozu4M27L4UacA2dz8u70mIiIg0SivI\n",
       "3avcNlEkT+XWnSIiIlJFm/Ty8YBylSVP5U/gIiIiMpRWkLOlHGQRERGRDCkHucBGkYOsaheSO/0c\n",
       "iohIESkHWUREREQkBwqQRUREREQqKEAWEREREamgADlb2qQnIiIikiFt0iswbdKTItHPoYiIFJE2\n",
       "6UnPMrP5ZrbZzHab2YI0trDyfhrbbGa785upiIiIdCM1CpGOYmZ9wHXp7npgc9VTqi956BKIiIiI\n",
       "ZEoBsnSaWenPde5+ZsX4emAhsKH9UxIREZFeohSLbGmTXnZ2VN5x963ufrW7353TfERERCQHeWzS\n",
       "U4CcrUfd/eCK26q8J1QkZrYe2JTulnOOz02PDclBrvra5Wa2Iz1nk5md1655i4iISOu4+6pybAVs\n",
       "Ax5t9TmVYiGd5Coi53ghcAuRTlGdUlGdc2wpsD6ZWHXeDMwB5pjZKe5+amunLCIiIt1GK8jSMdz9\n",
       "BmB1urvJ3Re7++0NfOkrgfnuPt3djwaOBAaAufVWnEVERETq0QpywZhxB5F/k4dt7hzX4nPYGL5m\n",
       "jbvfWL7j7lvN7HRiY9/5wNqsJiciIiLdTyvIUnTO4Krz4KD7RmArMNPMprR9ViIiIlJYWkEumDas\n",
       "4BbOMGkYW4CZROm4RlI1REREpKONGwe7W94kTCvI0s0G8p6AiIiINM+MQ8y4BGa0Jc1UAXK2VAc5\n",
       "B8OkUMwiUjC2tHE6IiIikhEzXmB21rfh4Hvh4PdHlTfVQS4a1UFuPwNOGTIYLatnA7j7rnZPSkRE\n",
       "RMbOjMPMuALYAle9DO7/Ddx/PvgDtKEOsgJk6QbLhxlb0c6JiIiIyNiZcYQZq4G7gHcRPQ4+CMx0\n",
       "ZwV4dT+EltAmPSm6AWCWmW0iqlnsAM4E5hHpFUtznJuIiIg0wIwjgQ8DbyHi03uJxa617jze7vko\n",
       "QJaicIZ20XOic94yYB17lnvbARyv9AoREZHOZcYxwEeANwLjgV8Ri1vXuPNEbvPy9qxUdz0zuw/A\n",
       "3Q/J4nkyOmY2FTgDmArc6u435zyljqafQxERyZMZLyYC4zcQKb/3AEuAa915sv7Xtef9SyvI0hXc\n",
       "fSfqmCciItLRzDgW+CixqGVEpamLgM+683Sec6ukAFlEREREWsqM44CPEXuEIDbhXQh8vpMC4zIF\n",
       "yCIiIiLSEmYcTwTGf56GfkIExl9y55ncJjYCBcgiIiIikikzXgJ8HPizNHQn8AngeneezW1iDVId\n",
       "5Gypk56IiIj0LDP+0Iz/AL5HBMf/D5gP/J47XxpLcGxm55ZjK2AGbeikpyoWGVEVCykS/RyKiEiW\n",
       "zPhjYsV4bhq6Dfg74Gvu7M7uPKpiISIiIiIdygwDXk4Exi9Pw98nAuN/cx/Sv6AwFCCLiIiISMNS\n",
       "YDyXCIxfloa/C5SAm4ocGJcpQBYRERGREaXA+DQiMP7DNPwdIjDe2A2BcZkC5Cpm1gdcQLQwPhJY\n",
       "7e5b852ViIiISD5SYPxnRGB8Yhr+JpFK8c1uCozLFCAPtQ6Y5+67AMxsE3BCvlMSERERaS8zxgGv\n",
       "JQLj2Wl4A/AJd76V28TaQGXeKqTV4+PLwXHF+Mk5TUlERESkrcwYZ8Z8ohLFl4ng+D+Al7pzSrcH\n",
       "x6AAudoJwENVYw8Bs3KYi4iIiEjbmDHejNcTtYvXAb8H/CvwB+682p3/m+sE26jrAmQz6zOzdWY2\n",
       "u87j883sPDNbYGbLqlaH+2p8yQAwtSWTlaal13Ozme02swVpbGHl/TS22cwyq8MoIiLSLczYy4w3\n",
       "Ed3uvgD8DvBV4AR3XuPO/+Q6wRx0TQ5yCojPBB4E5gFX1njOXGChu59aMbbJzBa4+21EMFytr864\n",
       "5CylxFyX7q4nNlZWqt400HWbCERERMbKjL2ANwIfAY5OwzcAF7pze24T6wBdEyCnAPc2ADNbXudp\n",
       "yxkaOK9O46cCm4D9qx7fH9iS3UwlQ+XUl3XufmbF+HpgIbGRQERERCqYsTfwZuDDxHupA18iAuMf\n",
       "5jm3TtE1AfJI0mrjbIYGuztIbRHdfcDMvm9mU919Z/kJ7n5z+2YqY7Cj8k4qy3d1TnMRERHpSGbs\n",
       "A/w1sBg4HNgNfA64yJ0f5zi1jtN1OcjDKK82Vm/CGwAwsyPS/TOA5SlH+SrgHW2Znewh5RGvT7nE\n",
       "m83sKjObWfH4emLFH6Ccc3xuxdfukYNcdezlZrYjPWeTmZ3X+u9IREQkH2bsa8bZwF3AVcChwLXA\n",
       "i915k4LjoXpmBZmhqRNl5YC5DyCtHJ+Vxta2elIylJmtI/LIHbiF+HCzkAiEj0/pNFcROccL03M2\n",
       "MDSlojrn2FJgfTKx6rwZmAPMMbNTKnPTRUREis6MicAC4Hzg+cAzwDXAUnfuynNuna6XVpDrqRc4\n",
       "Sw7MbD4RHN8CTHP3E919OvGfG9KHFne/gcgfB9jk7ovdvZENBa8E5rv7dHc/muiWOADMrbfiLCIi\n",
       "UiRmTDLjA8BW4DLgQGANcIw7f6PgeGS9FCCXV4qrA+JyaTdVqugMy4mV39MrG7a4+0oif7yyfJ+N\n",
       "4fhr3P3GiuNuBU5Pd8+v/SUiIiKdz4z9zPgQERhfDEwDPgMc5c4id7bmOsEC6aUUi/LmvFq1jnH3\n",
       "uzM4xyQzu7/OY6vcfVWzJ7CS3QHMaPY4Y7TN+/24Vh08baScCdxS5/U4JT0+Vs7gqvPgoPtGM9sK\n",
       "zDSzKdWdFEVERDqZGVOAc4APANOBJ4DLgRXu/DrPuY1V2ld0bo2HDgQebfX5eyZAThUqNhA/OJVm\n",
       "EWXBsvCoux+S0bF6UXkjZc2yemm1t6lPv8OkYWwhgu9Z0Nu1H0VEpBjM6APeA7yPWC1+HLgEWOXO\n",
       "fXnOrVlpUXHIwqKZteX76roAOa1CQu3L78vTrXLz3RnAh1o9r6y0cgW3A5TTX6orjbSDUmxERKQQ\n",
       "zNgfeG+6TQUeA1YSgfG2POfWLbomQE4lwBYRVQkcWG1m1wPr3X0jPHcpfamZLSMqGPQBSzKsc1yd\n",
       "YpFJWkUPKXfCa9nGyWFSKMqF0tUURkREOpIZBwDvB94NTAYeAZYCl7rzmzzn1kpV6RZKsRiNdPn9\n",
       "ggaedwPRRrEVlGLRBHffamaQGrdUqyj/NmuMOeNG5DHv8fpXNJFx5R+LiEinMWMG8EHgbGASsAv4\n",
       "BPBJ91yuurZVZbpFu1IseqmKhRTD9cC06pJrKYidB+xockNlrTbk5bEVTRxXREQkU2YcasZlwN1E\n",
       "OujTQD9wuDsf74XgOC9ds4LcIZRi0bzzgflEisyRRPOPPgaD2KVNHHsAmGVmm4hqFjuAMxlsStLM\n",
       "sUVERDJhxlHE++FbgQnAg8BFwKfd2Znn3PKgFIviU4pFk1KaxfHARuLTcnkDpQOrG/zA4QztoudE\n",
       "jvMyYB17lnvbARyv9AoREcmTGccCi4HXE1f57yVSC9a4tz4o7FR5pFiYe3UcIWNRfsFGCpAbfZ6A\n",
       "mZ1M5AZvAW7NqFY1ZjaVqF4yNR03q02ahaGfQxGRzmHGicCHgb9IQ1uJK6f/6M6TuU2sA7Xr/UsB\n",
       "ckbSCzaJKLVSNiTFQoGJdAL9HIqI5MsMA04CPkJsIAf4MZHu9wV3nslrbp2mVoqFu09p6TkVIGdD\n",
       "K8hSJPo5FBHJRwqMX0UExi9Nw7cSOcZfcWd3XnMrgna9fykHWURERKTFzBgHvI5IpZiThr9DBMY3\n",
       "uQ/ZOyM5UoAsIiIi0iJmTADeQGy+e1EavglY4s63cpuYDEt1kLM1yczur7idO/KXiIiISLcxY18z\n",
       "zgJ+BlxLBMdfBk5051UKjhtnZueWYytgBrHnq7XnVA5yNpSDLEWin0MRkdYwYxKwiNhUdgiwG/gC\n",
       "sNSdO/OcWzdQDrKIiIhIQZjRB5wDvA+YTnS9Wwssd2dznnOT0VOALCIiIjJGZswA3g+cDUwGHgcu\n",
       "A1a586s85yZjpxzkbCkHWUREpAeYcagZlwF3AxcQHVuXAIe78z4Fx9lRDnKBKQdZikQ/hyIiY2PG\n",
       "UcD5wFuBCcCDwKXAFe4M5Dm3XqAcZBEREZEOYcaxRKm21xNX4O8FVgFr3Hk0z7lJ9hQgi4iIiNRh\n",
       "xolE17s/T0NbgWXAte48mdvEpKUUIIuIiIhUSO2gTyIC41PS8I+JHOMvuvNMXnOT9lCALCIiIsJz\n",
       "gfGriMD4pWn4VqId9Ffc2Z3X3KS9VMUiW6pikQEzm29mm81st5ktSGMLK++nsc1mltkvq6yPJyIi\n",
       "xWDGODPmA7cA/04Ex98BXg2c4M6NCo7zk0cVC60gZ+tRVQVojpn1Adelu+thSHH16rIrWZdhUVkX\n",
       "EZEeYcYE4A3E5rsXpeGbgIvc+XZuE5M9uPsqYkPkc1UsWk0BsnSaWenPde5+ZsX4emAhsKH9UxIR\n",
       "kW5ixr7AXxPl2o5Iw18GlrizKadpSQdRgCydakflHXffClyd01xERKQLmDEJWAScCxwC7AY+Byx1\n",
       "58485yadRTnI0jHMbD0898m9nHN8bnpsSA5y1dcuN7Md6TmbzOy8Jucy4vHM7EPp8ZlVedPPPd/M\n",
       "+sxsXdVjs+ucc256buV55zXzfYiICJjRZ8bHgHuAi4HpwBrgGHfepOBYqmkFWTrJVUTO8UJio8QG\n",
       "hqZUVOcIWwqsTyZWnTcDc4A5ZnaKu586yjmM5XgXAAuINJC7iJJAc8zsKGAu0Je+j93pWBvNbKa7\n",
       "76w46cL0/TuwBdienrvOzNa4+1mj/D5ERHqeGTOA9wNnA5OBx4FPAqvc+XWec5POphVk6RjufgOw\n",
       "Ot3d5O6L3f32Br70lcB8d5/u7kcDRwIDwNx6K84ZH+8dwBx3P83dTwNOT+MLgLvScc5Mx7qVCJjn\n",
       "lr/YzGYx+OHgSHc/Oj33eCJYXqiVZBGRxplxqBmXAXcTixhO1DA+3J33KziWkWgFOVuTUgmSslVp\n",
       "52V2zO4gSpzkYRvux7X4HDaGr1nj7jeW77j7VjM7nVjRPR9Y2+LjrakM5N39BjOD+IW8qOq5XyJW\n",
       "hqdVjC1Pf57u7ndXHOc2M1uUzrsIuGGU34eISE8x4yji9/RbgQnE1biLgCvcGchzbjJ2Kd2yXDr3\n",
       "QGh9a28FyNlSmbf2cwZXnQcH3Tea2VZgpplNcfddLTze+jrHGqgMeJNyWkVfxdhcYEet1fJ0XoiU\n",
       "DxERqcGMY4EPA2cSV8fvBVYCa91bH0xJa6nMm4ys9Su4hTNMGsYWYCZROq6RVI2WHK8BUwHUpERE\n",
       "ZHTMOJHoevfnaWgLcVXuWneezG1iUngKkKWbZX05LfPLc6kxSvnYX8r6+CIi3Sa1gz6JCIxPScM/\n",
       "ApYCX3TnmbzmJt1DAbIU3jApFLMYrAqR1fEY7fGG4+4DKYXiQXd/Z1bHFRHpNikwfjWRSvHSNHwr\n",
       "kWP8FbWCliypioUUnTG4gjA4GCuzswFGkX/cyPF8lMdrxFZglplNrXXeVBu5qbrOIiJFZcY4M+YT\n",
       "5T//jQiOvw28CjjBnRsVHEvWFCBLN1g+zNiKDjjeSK4iAvNa1TaWA/MYWv9ZRKSrmTHBjLcAdwLr\n",
       "iEWKm4CT3DnJnZvc9btRWkMpFlJ0A8Tq6yai+sQOYhdzOahcmvPxRuTuK81sMTDfzL6RzruTKO02\n",
       "j6iPvCbr84qIdCIzJgJvA84DjkjDNxLtoDfV+zqRLClAlqJwhq6iOhE8LiNWFyrLs+0Ajq9Mhxim\n",
       "SoS7+/jRHq/OnMbyfUBUx9hIlHybWzF+C1EfOeu0DhGRjmLGFOCdROe7g4Bngc8BS9z5UZ5zk95j\n",
       "7ro6kYVyXb6R6iA3+jwZnZS/ewZRMu1Wd7+5k443ivPOJjroAWxp1Xn1cyginSK1g34v0Q56KvAk\n",
       "cA2w0p2tec5NOk+73r8UIGckvWCTgMcqhod00lNgIp1AP4cikjczDiO6o70DmAg8DFwJXOrO/cN9\n",
       "rfSWWp303H1KS8+pADkbWkGWItHPoYjkxYwXE+2g30ikem4HPonaQUsD2vX+pRxkERERaTkzTgAW\n",
       "A68jKvf8kmgffLX7HldfRXKnAFlERERaIjX3eAURGJc3IP+U2Az9eXeeymtuIsNRgCwiIiKZMmMc\n",
       "8Bqi691L0vAtRKnMr7jzbF5zE2mEAmQRERHJhBkTgNcDFwC/nYb/kwiMN6ixhxSFOunVYWarU8kt\n",
       "ERERGYYZE814F/Az4J+I4PhrwB+680p31is4liLRCnIVM5sHnAicTpSbERERkRrMmMpgc48ZRHOP\n",
       "fwaWu/PDPOcm0gwFyFXc/QbgBjObn/dcREREOlGd5h5XouYe0iUUIIuIiEhDzDicweYe+xLNPZYD\n",
       "n1RzD+kmhQiQzawPWAsscffbajw+H5gJDABHAuvdfWN7ZykiItKd6jT3uBA195Au1dEBctokdybw\n",
       "IDCPGjnBZjYXWOjup1aMbTKzBeVgOuUVnzLMqTa7+8pMJy8iIlJwZpxI1DD+Cwabe6wE/l7NPaSb\n",
       "dXSAnALccpC7vM7TljM0cF6dxk9Nx7kBuKFF0xQREekaFc09PgycnIZ/QryvqrmH9ISODpBHklIv\n",
       "ZgNbqh7awWDHnqZOkcExREREOl5q7vFaYsW43NxjE4PNPXbnNTeRdit6HeRZ6c+HqsYHAMzsiNEe\n",
       "0MxONrNl6djLzey8ZiYorWVm881ss5ntNrMFaWxh5f00ttnMMvnlnuWxRETyZsYEM94M/AD4MhEc\n",
       "/ydxFfYl7tyo4Fh6TaFXkIH964yXA+a+0R4wbe7bSHQBkg6WriBcl+6uBzZXPaW6KH2WRepV8F5E\n",
       "Cs2MicDbgfOAw9PwV4Gl7nwvt4mJdICiB8j11AucpbuUryCsc/czK8bXAwuBDe2fkohIZ1NzD5GR\n",
       "FT1ALq8UVwfE5ZVjlZ7pDTsq77j7VuDqnOYiItKRUnOP9xHNPaYQzT0+A6xScw+RPRU9B7m8Oa9m\n",
       "KoW7392+qQAwyczur3M7t81zKbSUR7w+5RJvNrOrzGxmxePric0jAOWc43MrvnaPHOSqYy83sx3p\n",
       "OZuayTNv5Fhm9qH0+MyqnOnnnm9mfWa2ruqx2XXOOTc9t/K888b6PYhIdzPjcDM+DdxDbMAzoiLF\n",
       "Ee6creBYOpGZnVsrniKuekxq9fkLvYLs7gNmtgGYXvXQLOIye7s96u6H5HDermJm64i61w7cQrye\n",
       "C4lA+PhU/u8qIud4YXrOBoamVFTnCVsKrE8mVp03A3OAOWZ2SmUt7camOepjXQAsIH427yJqc88x\n",
       "s6OIqit96XvYnY610cxmuvvOipMuTN+7Ex8Qt6fnrjOzNe5+1ii+BxHpYmb8NtHc46+I9/vfAJ8A\n",
       "PqPmHtLp3H0VsKp63Mzua8f5C7GCnDZjQe2ya8uBRVVjZ6TxdqteQdaq8SilrojziKB3mruf6O7T\n",
       "iV/yEB0Vy7WtV6exTe6+2N1vb+AUrwTmu/t0dz+a6Lw4AMytt+Kc4bHeAcxx99Pc/TTg9DS+ALgr\n",
       "HefMdKxbiYD5uXKFZjaLwQ8GR7r70em5xxPB8kKtJIuIGS8x48vAncBbgHuBdxMrxksUHEvRVK4m\n",
       "oxVkSJfUFxErZA6sNrPrqWgl7e4bzWxpKs22mQgqlrj7zTlMueUryPbNb95B/HDkYZu//OXHtfgc\n",
       "y4nX+nR331UedPeVZraIqHtdNpY61Wvc/caK4241s9OJVd3zSQF4i461pjKId/cbzAzi+63+kPcl\n",
       "4ud+WsVY+UPf6ZXpQ+5+W/q3WZ+Oo6Y4Ij0mNfd4JZFCUdncYxnR3OPpvOYm0qzK1eR2rSB3dICc\n",
       "NluNWG5NnfK6Q7pSMBO4pU7++Cnp8bFyBledBwfjQ9ZWYKaZTakMzDM+Vr20n4Ea3285raIyv34u\n",
       "sKPWSnk6Lwy+MYpIDximuccS4KuqXywyNh0dIBfQpLT8X7YqferJTBtWcPNULttW3RkReO4DU1Ob\n",
       "SYZJw9hCBN+zgEZSNTI9VoOmAqhJiYiYMQF4A3G16rfT8M1E17uN7qrVLt0jpayW01YPBB5t9TkV\n",
       "IGdLm/SaUy7XV90ZsR2yzMnLPL+vIg9/gEi/EJEeVKe5x1eAZWruId1KKRbS68qd8FrW6GWYFIpZ\n",
       "DFaGyOJYjOZYI0kVWwAedPd3ZnVcESmG1NzjXUQd43Jzj88SzT3uzHNuIt2oEFUspDekFAqoqNxQ\n",
       "KdX+3W1mR4zxFEbkMVcft4+0+a/B/ONGjuWjOFajtgKzzGxqrfOmf58x13QWkc5jxkFmLAV+QeQV\n",
       "TyGaexzlzlsUHIu0hgLkbKnMW/OuB6ZVl0lLgec8YpPa3U0cv1b5v/LYihyP1YiriMC8VqWN5QzW\n",
       "jhaRgjPjiNTc424GN6svY7C5x915zU2k3VTmrfiUg9y884H5REm/I4nGGX0MBp5Lmzj2ALECu4mo\n",
       "QLEDOJPBwHI0x87yWA1Jpe4WA/PN7BvpvDuJ0m7ziBSVNVmfV0Tap6K5xxuB8ai5h4hykEVSLeHj\n",
       "gY3Ah9INUlm1BquCOENXUp0IIJcB69izRNsO4PjKlIgRKkVsHs2x6sxnLN8DRHWMjUQaSmUqyi1U\n",
       "1Y4WkeIw43jgI8Dr0tAvgJXANe48ltvERHqUueuKbBbSJ5pJsMcvsiFl3sqffLTSPDIzO5nI590C\n",
       "3NpkakXlcacS3RanpuOOualMlsca5XlnEx30ALaM9rz6ORTpDGa8jAiMX5WG1NxDpEqtMm/uPqWl\n",
       "51SAnI1GAw4FJtIJ9HMokp/U9W4u8FHgpDR8O3AR8GV3ns1rbiKdrl3vX0qxEBERaYPU9e41xIrx\n",
       "iWn4v4ELga+ruYdI51CALCIi0kJmjAdOJwLjY9PwRmLF+JsKjEVGxWhDxSYFyCIiIi1gxt7Am4gy\n",
       "bUen4X8FLnLnu7lNTKSArGTTgHOYxAwe5YFWn08BcrYmpRp9ZUM26YmISHeraAf9IeAwYrXrOmCJ\n",
       "O3fkOTeRorGSHczX+Dw/5eWApVIIqoNcMKqDLCLSo8yYDJwFfBA4iGgHfS2wzJ2f5Dk3kaKxkh0B\n",
       "nAf8Da9lH6Lu/6cosRAYrhRrNudXFYtsqIqFFIl+DkWyY8Y04N3A+4BpwJPANcAKdbwTGR0r2YuJ\n",
       "tKRys5xtwCXAld7vu1TFQkREpIOZMQP4APAuYDJRB/8S4GJ37s1zbiJFYyU7Hvgw0SzHiGY5K4Br\n",
       "vN8fb/d8FCCLiIiMghmHEpd+FwATiUu/FwKXubM9z7mJFImVzIA/Jiq8nJqGfwosBT7v/Z5bsxwF\n",
       "yCIiIg0w40ji0u9bgQnAdiIwvsKdnXnOTaRIUmD8amLF+KVp+Dai9OFXvN9zb5ajADlbqmIhItJl\n",
       "zPgdYDHwBmAccC+wEljrzqN5zk2kSKxk44F5RGB8XBr+NrAEuMn7a2+Mq9VqusVT1Sa9rIxyk95B\n",
       "0PoafiLDOAh4QJv0ROoz43ji0u/r0tBWYDnwj+48mdvERArGSlarJvjXgaXe798e1bG0Sa9rbct7\n",
       "AiLEBzT9LIrUYMbLiMD4VWnoJ8QK1xfceSa3iYkUjJXsecA7iJz9Q4ma4OuIwPi2POc2EgXIbebu\n",
       "x438LBERaSczDJgLfBQ4KQ3fTuRE3uje+rqrIt3CStZHVHd5P3AA8AzwD8By7/ef5jm3RilAFhGR\n",
       "nmXGOOA1xIrxiWn4v4nNd193R3mIIg2yks0g6oGfDUwBHgcuBy72fv9FnnMbLQXIIiLSc8wYD5xO\n",
       "BMbHpuEF+6sIAAAgAElEQVSNxIrxNxUYizTOSnYYsYluAbAvsItIS7rM+72Q6XwKkEVEpGeYUWuz\n",
       "0L8AS9z5bm4TEykgK9lvAecDbyZiyu3AJ4DPeL8P5Dm3ZilAzpbKvImIdCAzJgJvBz4EHEZsFrqO\n",
       "CIzvyHNuIkVjJZtNlD6cT3S9+xVR+vBq7/fHMj+fyrwVV7vKjoiISOPMmAycBXyQKG/4LPBZYJk7\n",
       "hdgsJNIprGQvI2oYvzoN/RxYBvyz9/tTbZmDyryJiIiMjRnTgHcTG4amAU8CVwIr3Lk7x6mJFErq\n",
       "encaERj/cRq+g8gxvqETut61ggJkERHpGmbMAD5AlJiaDDwGXAxc7M59ec5NpEhS17vXEYHx7DT8\n",
       "f4mNrF+v1/WuWyhAFhGRwjPjUKIZwQJgIrCTKNV2mTvb85ybSJFYySYAbyQ2sv5WGr6JWDH+drcH\n",
       "xmUKkEVEpLDMOJJ4I38rMIHYRX8hcIU7O/Ocm0iRWMkmAn9DfNAsb2S9geh6d0uec8uDAmQRESkc\n",
       "M36H2EX/BmAccC+xi36te+t3uIt0CyvZVOCdRNe7GcRG1muJrnc/znNueVKALCIihWHG8URzj9el\n",
       "oa3ELvpr3Xkyt4mJFIyV7EDgvcA5wFRiI+sVwCrv97tznFpHUIAsIiIdz4yXEYHxq9LQT4icyC+4\n",
       "80xuExMpGCvZoURN4YVEvv7DwHLgk97v9w/3tb1EAbKIiHQkMwyYC3wUOCkN307sor/Rnd15zU2k\n",
       "aKxkRxONcsr5+g8SHzKv8H7fkefcOpEC5Gypk56ISJPMGAe8hlgxPjEND5aXcnpiF71IFqxkxxH5\n",
       "+qcT+fq/BlYBa73fC5Gvr056BaZOeiIizTFjPPEm/hHg2DS8kahK8V8KjEUaZyX7I6KG8Z+loc1E\n",
       "vv5nvd8Lm6+vTnoiItITzNgbeBNRru3oNPwvwEXufC+3iYkUTOp6dwoRGP9JGv4BkUpxvfe78vUb\n",
       "pABZRERyYcZE4O1EXmS57up1wBJ37shzbiJFYiUbB/wFERgfn4a/S6Ql/VuvNPfIkgJkERFpKzOm\n",
       "AGcRLaEPIuqu/iOwzJ2f5jg1kUJJXe9eT+QYvzgNrydWjP9LgfHYKUAWEZG2MGM68J506yPqrn4G\n",
       "WOnO3TlOTaRQrGT7Am8jrr4ckYa/THS9+35e8+omCpCrmNkc4Ix0dw5wvrvfluOUREQKzYxDiNXi\n",
       "dwKTgEeIrneXunNfnnMTKRIr2WTi6ssHGbz68lmi692dec6t2yhAHmqRuy8CMLPZwC1m1ufuu3Ke\n",
       "l4hIoZhxBLHC9XZgH2AHUV7qcnceynFqIoViJat19eVKYKX3+9Y859atVOatgpnNAu5y93EVYw8B\n",
       "89395hG+VmXeREQAM15E5ES+ERgPPABcDFzlzsN5zk2kSKxkLyCuvixi8OrLlcCl3u89efVFZd5y\n",
       "4O5bUooFAGbWR3xS25LfrEREisGM2cQu+nmAAb8AVgDXuPN4nnMTKRIr2ZHE1Ze/BvYGHiLSkj7l\n",
       "/a6rL21QiAA5BaprgSW18oHNbD4wExgAjgTWu/vGsZzL3W+vuLsYWO3ud4/lWCIivcCMlxLNPV6d\n",
       "hn4GLAU+587TuU1MpGCsZL9L1AN/PdH17j4iLWmN9/sjec6t13R0gJxygM8k+oXPIy4rVD9nLrDQ\n",
       "3U+tGNtkZgvKwbSZzSMKZ9ez2d1XVh13PjDF3d/Z/HciItJdzCg3JPgIcFIavoOou3qjO8/mNTeR\n",
       "orGS/QFx9eW1aWgLsBz4J+/3J3KbWA8rTA6yme0G5lbnApvZLcCV7n51xdgC4PTKoHmU55oLnOzu\n",
       "i81sKrC/+/BJ8MpBFpFeYMY44k38I8AJafi/icD439UOWqQxqevdK4jA+OQ0fCdx9eVL6npXm3KQ\n",
       "G5BSL2YzNEd4BzB3jMecQ6yKXJU27c0nim6LiPQsM/YirugtBn4nDW8gAuP/UmAs0pjU9e5/E4Hx\n",
       "H6Th7xP/l/7F+313XnOTQYUOkIFZ6c/qhPUBADM7YjT5wyng3kBszDsvDbu7r2hyniIihWTGPsBb\n",
       "gfMZ/J37VaId9P/kNjGRgrGS7UX0WVgMHJuGbya63t2srnedpegB8v51xssBc99oDubuA8McU0Sk\n",
       "Z5gxCVgAnAu8ANgNfAFY6s4P8pybSJFYyWp9yPwa0fXuu7lNTIZV9AC5HgW5IiJjYEYfcDbwPuAA\n",
       "4GngamC5O3flOTeRIrGS7QcsJLrePZ/4kPl5YJn3uz5kdriiB8jlleLqgLi8cjzQxrkATDKz++s8\n",
       "tsrdV7V1NiIiDTLjQCIoPgeYAjwOXA6scueXec5NpEisZNOI/0fvBaYTHzLXAiu83/Uhs0Fmdi5x\n",
       "BavagcCjrT5/0QPk8ua8mqkUOdQvflRVLESkSMw4lHgTWghMBHYRu+g/6c62POcmUiRWsoOB9wPv\n",
       "AvYDHgMuBS72fv91nnMrorSoOGRhsVzFotUKHSC7+4CZbSA+oVWahSpPiIjUZcZRDHbqmkDUm18C\n",
       "fNq97VffRArLSnYEsbH/b4B9iKvXnwAu937fnt/MpBmZBMhmNoUoqzaLwWD1QWKFd4O772ry+OUV\n",
       "Yqvx8PJ0W1sxdgbxi7/dqlMslFYhIh3FjGOJXfTlTl33Uu7U5a2/bCnSLaxkLya63r0RGA88AFwC\n",
       "XOX9zcU9sqeqdIu2pFiMuVFIaqCxEFjE4K5MGMz7rUx72AysBtaMJlg2s5np+HOIItpbgeupaiWd\n",
       "OuWdmM7TR3TGu3G031Mz1ChERDqZGScSzT3+PA1tBZYB17rzZG4TEykYK9kJxIfM1xELd/cAK4B/\n",
       "8H5/PM+59YJ2xVujDpBTYLycCI5vBb4E3AZsSmXSKp/bR3RamkMUmJ8NLHf3xc1PvbMoQBaRTpPa\n",
       "Qf8J0ZDglDT8IyLH+IvuqFOXSANS17uTiP9L5S69PyX+L33e+/3pvObWazo5QH4IuI4IdIdtv1zj\n",
       "a2cRdQDnu3t13nChpRdsEpGUX6YUCxFpuxQYv5pYMf6jNHwL0anrq+6oU5dIA1Jg/GoiMH5pGr6V\n",
       "yNf/ivf7s3nNrZfUSrFw9yktPecYAuS+6pXiUZ80g2N0Gq0gi0jezBgP/CXxZv77afhbRGC8Xu2g\n",
       "RRpjJRsPzCP+Lx2Xhr9FBMbfUNe7/LQr3hr1Jr1GA1szOyI9/+6xHkNEREZmxgTgr4i8yN9Kw/8B\n",
       "XOTOd3KbmEjBWMn2Bt5EbL47Og3/O9H1Tv+XekhWVSzOA+a6+2np/lVEjjJmdgtwcrOVLApCVSxE\n",
       "pG3M2Bd4O1G153DAgRuAJe7cmufcRIrESvY84B1EubZDif9L1xFd727Lc25SsCoWzx0gguPlwK3u\n",
       "foKZzSZy3a4HNhG7pLtyY14lpViISLuYMZmo8PNB4GDgWeBzwDJ3fpzn3ESKxErWRzT2eD/RWv0Z\n",
       "4LPAcu/3n+Y5N6mtYzfpDTmA2V3AgLufkO4vAxa6+/7p/jrg99396GEOU3gKkEWk1czYH3g30cJ2\n",
       "GvAUcA2wwp1RbZoW6WVWshlEa/WzidbqTxD9FFZ5v/8iz7nJ8Do2B7mGWcQKctlcYEPF/e8Tie4i\n",
       "IjIGZhwMfAB4J9HC9lHgYuASd+7Nc24iRWIleyFxqX4B1a3V+12t1eU5WQTIW0mNQlKN5DlEU5Cy\n",
       "WdAzbUuVgywimTHjcCK/uLqF7WXuPJjn3ESKxEp2DFFm9i1E7LMduBD4jPercECnyyMHOYsAeQOw\n",
       "wMy2MFiI/jp4Lj95IZGP3AseVYqFiDTLjN8idtG/ifg9vY1oYXulO72w4VkkE1ay3yequ5xOdL37\n",
       "FbASuNr7/bHhvlY6R1psXAWDKRatlkWAfD6xSnx+ur/I3Xea2Rwi9WJLxWMiIlKHGb9P1F2dT7yZ\n",
       "/5J4M/97d/RmLtIgK9lLif9Lf5qG7iKKBnzW+/2p3CYmhdH0Jr3nDlTV/COlW5zo7huG+bKuoU16\n",
       "IjJWZvwh0fXuz9LQz4k38392R2/mIg1IXe9OJQLjk9Lw/yOae1yvrnfdoTBVLCSo1bSIjEZqB30y\n",
       "ERi/PA0Pvpk7ejMXaYCVbBzwOiIwnpOG/5voIPnv6npXfEVpNf0Q8Qt8zWibf5jZFKJ25+JyGbhu\n",
       "oRVkEWlECoz/FPg48JI0/D3izfxf1Q5apDFWsgnAG4gc4xel4W8QMcq3FBh3p04u8zaLqBW4wszW\n",
       "A+uADbVaSsNzLadPIRLk5xIb9maO4bwiIoWVAuO5RBWKP0jDNxOB8X8qMBZpjJVsIvA2BjtIAtxI\n",
       "tIPelNvEpKuMOkBOecanm1l5Y94KoM/MADYTZYgM6COVf0tj1wFHuruK2YtITzHjJCIwLudF3gx8\n",
       "3J3/k9+sRIrFSjYFOIuoCX4Q0UHys0Q76B/lOTfpPpnkIKeKFXOB6QwGxVuIgHmTu9/a9Ek6nFIs\n",
       "RKSaGf+LCIznpqHvAB9z55u5TUqkYKxkBwDvIbpI9gFPEh0kV3q/Ft16jTbpFYwCZBEpM2MO8HcM\n",
       "VqX4PvAx4BtKpRBpjJXsBcAHib1LzwMeAa4ELvV+b0stXOk8nZyDXFfahLd/vXzkHqBOeiI9zIxj\n",
       "gRLwl2noDiIw1uY7kQZZyY4i8ovfCuwNPET0Vfi09/tDec4tN2b7AuOAx+nBlc08OulllWJxMtFe\n",
       "ehbgxKa8aUQXvfPd/famT9LhtIIs0rvMOAb4W+D1xB6MHxNVKm50Z3eOUxMpDCvZcUQHyTOIYPA+\n",
       "4GJgtff7I3nOLRNm44GpwP5EjLR/1d+HG9s3HeVZYiX94UxuXrymKYVZQTaz2cB6Iud4JXBeemgr\n",
       "ESjPNbPjeyFIFpHeYsZMIhB+C/GGfhcRKH9RdYxFGpO63i1mMCVpM1EA4Frv9ydzm1gtUZFgIqML\n",
       "bst/n0p8gG7Us8Tq+S+AHcBuYHLF7SBgQpPfz9NkFWzDI7g/09R8OkjTK8hm9g3gBHff38z6iBdz\n",
       "rrvfnO7fAtzl7qc1P93OpRVkkd5hxguBjwJvJxYa7iFyjv/Jna55gxBplTpd734ALAXWeX+LAy2z\n",
       "vYgNf6MNcvcn0j5G42EiwH0o3XZU/Vlv7JER0ynM9mHPoHkysF+NsUZv40b5vVV7nOqgeewB96O4\n",
       "D7kCV5gVZGJ39opaD7j7gJmtJi6ZiIgUmhmHECtdi4g3yV8DFwLXqCW0yMisZOMZ7Ho3Ow3/N9Hc\n",
       "499G1dwjVnMnMbYgd7Rd2J4mgtctjC7IHcD96VGeq3HuTxJVPbY3fazB1fHRBtW1AvKDgCMzmNOQ\n",
       "AHsaTNsR/8YtlUWAvBOG3XzSVR3zRKT3mHEgsWnobOIN5AFipWu1O0/kOTeRIrCS7Q28ieifcEwa\n",
       "von4fxRd78z242/tYKDyNp3hA97RxjG7iMD1LhoPcncQq5ndvTkuvr/H0u2Bpo9nNo74ADPW1ezK\n",
       "22GkPOx9mp5Yg9PPIMViHfD77n50jRSLqUQu8iZ3P7X56XYupViIdB8zphE7p99L/KJ/kLhidoV7\n",
       "63dRixTdn77JJm9/Hu8155zpj3HQIY/gc+7jzj/9OXfOHGA8ewbD+zV42KcYfbrCDmI1VylQRRVp\n",
       "MZP3gp88C7s7vg5y6qh3F5FUv4YoxfIhIhF9MZHj0/Ud9FKAPIn45FWmMm8iBWTGFOB9RMeuqcSV\n",
       "slXA5e7synNuIrmLS/FTGQxsD2HPQPfgZ4znP7EXM5/3NJMaSGp9nKhYcX+N23aGBr49Weqsl9Uq\n",
       "8+buo02TGd05MyrzNoso83Zy1UO3Agvc/bamT9LhtIIsUnxmTALOIT7k709sMPkkcIl763PeRHIV\n",
       "G76qUxwqb5WB8LBXup812DYJHpiEA784bCf/s/8TbKZ2IPywAl5pVGE76aW20wBb3H0g04N3MAXI\n",
       "IsVlxkTgLGJD8QxiRevTwAr3DDa/iOQl8kCnM3ywW75Na+CIu9gzuL0PuP+HM3jmUy/hT77/Ak69\n",
       "dz/23j6Jnc+O4wrgMu/3bVl/W9K7ilTFYg/ufmvWxxQRaQUz9gbeAXwEeD6R23g5sNSd+4f7WpFc\n",
       "mU1i5ID3YKKawEjv9c8QwW69Fd5yIPwA7pVphFjJfpv4YPlXwHhgG3ApcKX3+85mv02RvGQSIJvZ\n",
       "AqLcW1+953R7HWQRKQ4zJhDNPT4GHE4ECKuBi9z5ZZ5z61pmewOHEv/eh1XdyitBzxLNEJ6tulWP\n",
       "dfr9Zo7hxIpvvYC3PN7IhraHgJ9SP+At/31HrXqzw7GSvYTYZ/QXaegeolnYNd7vj4/mWCKdKItO\n",
       "elcRLaUh6gPW6hKj3CIRyZ0Z44E3AP3AUURQ8g/AJ9zp6o3ELRWbtvandvBbvh1M/S5i5feI0XQZ\n",
       "61VPEMHtD6gf8N4PbEs1cjOTmnu8gqhhXN5z9GNgGfAF729hvV+RNstiBfkMYEO3l3ETkeIyYxww\n",
       "DygBLyYCss8DJXd+lufcCiE2bx1K/eD3MOB5wxxhO3Ab0TK31u0B3HenQHsccal+fNXfx3I/i2O0\n",
       "+n712DiinGC9VIdd7d7QZiUbB7yGCIxfkoY3Ec09vur9o1t9FimCrHKQr8voOCIimTHDgNcSbaB/\n",
       "Lw3fAPS7c2duE+skEZROZ/jgd7jV36eAX1I/+P0l7o3VjI7Ar5xyIDmzku0FvJ7IMf6dNPyfRGC8\n",
       "cVRd70QKJosAeSNwCnB1BscSEWlaCoxPAz4BnJCG/xX4uDtdX3ZyD8Ov/pZTIiYOc4ThVn/vIS7l\n",
       "awWxi1jJ9gXeRpQ7PCINfw1Y6v3+3bzmJdJOWTQK6SMutdxCbHJ5qNbz3P32pk7U4VTmTaQzmPEK\n",
       "4ELgj9LQeuBj7nwvv1m1yPCrv+Xg9+BhjjDc6u89xOrvY/W/XLqJlWwKUe7wA0T1i2eBLwLLvN9/\n",
       "mOfcRMoKUwfZzGYTq8h1K1gA7u7jmzpRh1MnPZF8mfFSYsX4FWnoW8BH3fl2frNqUu3V3+qNcCOt\n",
       "/tYKfMt/1+qvYCU7gGinfg7xXv4ksXl1pff7ljznJgIF7aRnZpuAOcD5UP/SpbtvaOpEHU4ryCL5\n",
       "MONEIsf4VWnou0T5to3uHVxBZ+jqb60KEKNZ/a0MfMu5v1r9lbqsZC8EPggsIDZZPgJcCVzq/X5f\n",
       "nnMTqadIjULmAOe7+8oMjiUi0hAzjiMC49emoVuJwPjrLQ+MzcYDk4EpNW5T64xX36Yz8urvrdQO\n",
       "frX6K2NmJTuGWNR6MzCBqJqxDPi097taqouQ3Sa9zl2lEZGuYsaLiXJtp6ehHwIfB74yYmBsNoE9\n",
       "A9tGg9nq505q4lt4BtgJ/JpYAa4V/Gr1VzJnJZtNNPeYT1Ql+TWwCljr/Q1WGhHpEVmkWMwBNgCv\n",
       "7PaNeMNRioVIC5nt/df8w3E/4Hc/7NhrJ/PwuIO5/9encdOX38q1Px7P7urV3HqB73ArtiN5EthV\n",
       "cdtZdb/WrdZznmx3HVvpbVayPyZqGJfTkO4iVoz/2fuzbSYi0mpF2qR3HZFmMYvo4z5Q/RRik96J\n",
       "TZ2owylAFqkj0hEOBGYQaQWjSktwmGKwTxMzeJzmA9uHs+5KJtJKqevdq4kV45el4TuIGsY3eL+r\n",
       "1rQUUpFykI8kguLyBr1xGRwzN2Y2F5iZ7p4CrHb3jTlOSaTzmO1NBLwHpVvl36tvBzCGFsK7scd2\n",
       "MYX7OXifnUzlCfZ9YgbbfnQ0P//BXjxbL8itFdiq/a30DCvZeCKFYjFwXBr+DhEY/4eae4g0pukV\n",
       "5G5jZncBC9395nIJO3ffv4Gv0wqyFJvZROoHudUB8LQGjrgb+A3wQMXtQYYGsXvcfzeX77OWBWc/\n",
       "yb5nESvH9wMXAWvd0SquSA1Wsn2ITXfnA0el4a8TzT2KW+pQpEqRVpC7zVx3vzv9fdSrXiIdI8qI\n",
       "TWb41d3K4HdyA0d9GtgGbGXPwLfyto1yMOyNX8Y1YzpwHvBuouTUduAjwJXuaMOaSA1WsknAQqJc\n",
       "2wuITfPXEc09eqtrpEiGRh0gm9k3gB3ufmbF/eGWocs5yKeNbYrtVREcAywiugOKdIYIeqfRWGrD\n",
       "QcC+DRz1cSKg/RFDg9zq20DWG8zM6CM6d72PCNJ3EJ3wPuXOI1meS6RbWMn2Jxp7vIfI7X8a+Htg\n",
       "hff7z/Kcm0g3GMsK8pHEG1jZdCJAHm61tak31NTOei2wxH3oJ2Izm0/kDQ+k+a1vJm/YzGYSwfER\n",
       "RC96kdaJTWzTGTmtoTw2oYGj7gJ+xcirvA8Aj+RRVcGMycSb+7lE966HifJtl7qzs93zESkCK9kh\n",
       "xAfKs4D9iO6tnwQu9n7/VZ5zE+kmHZ2DnHKAzyTyFpcT6Q83Vz1nLvAhdz+1YmwTsKAcTJvZPGLD\n",
       "XT2bazU6qWijPdPdh33DVg6yAOXNa/sRdXL3S7eRgt8DaWxz60PUD3L3HHd/PLPvKWNmPA94F5Er\n",
       "eQDxBn85sMqdB/Ocm0inspLNIhZs3gbsTSwIfQq43Pt9e55zE2mnIpV5uxJYXpWaUPn4bOAMd1/c\n",
       "5Hl2UztAvgW40t2vrhhbAJxeGTQ3eI45wCZ3H1cx9hARgF9d/ysVIBdONIwoB7GVwWzl38fyWCOr\n",
       "u2W7iTzbequ8lUHwb3B/aqzfbicwYx8iV/LDRAvlJ4HPAMvc2Zbn3EQ6lZXsd4ELgNcTH6QfAC4G\n",
       "Vnu/78pzbiJ5KNImvUXAOuDuOo+fSWy8aSpAriWlXswGtlQ9tAOYO4ZD7qAi5zgdvw/YNNY5SpMi\n",
       "/aBekNpMMNtMXd1KTwKPECkN96W/l2+Pplv1yu9gRYdRbGIrKjP2Bd5BvMm/gMiV/AywxJ1f5zk3\n",
       "kU5lJftfxPtmuZX63cSV1H/0fn8ir3mJ9IoxBchpNbfShtg7VNetYzlPA2alPx+qGh8AMLMj6q1s\n",
       "1+LuW83sejM7Lw2dCMzv5Q6Bo2I2jkgXmEx2wWwjm8wa8RQRrD5CBKflv1cGs7X+Ptxjj+L+TEbz\n",
       "6zpmTAQWEKkUzydaLF8NXOjOPXnOTaQTpeYec4nA+BVp+E5gKfAl79fvG5F2GesK8gUVf18GrGHo\n",
       "Km6ldWM8z0jq1ScuB8x9oz1g2tynxiD1xCeh6cAxVbej062ZVr4AzxKbtR4lcs9HE7DWe+zRoqcn\n",
       "FEkKjBcSgfEhxIrxGmCpe90rTSI9KzX3eB3x3np8Gv4fornHv3i/Vy9KiUiLjSlAdvcV5b+b2ZlE\n",
       "t7lOqrc4YmMPGYHZfkTAWx0IH0PtDx67idq4W4jGD2MNZp/Ko6KCNC9tvltEbCQ6mAiMryJyjLVi\n",
       "LFLFSrY30dzjQ8TvVoANxIrxf6rrnUh+ms5BdvfjR35Wy5RXiqsD4nIAN9DGuRSP2T5EmkqtQLhe\n",
       "8vu9wO3Az9Lt5+nPLVql7U1mTCJKTp1HVOV4CriSCIx/kefcRDqRlWw/4irLBxhs7nED0dxDe15E\n",
       "OkDRO+mV0zpqplKMJv84I5PM7P46j61y91VtnQ2UN7m9kD1TIcp/P4La5cUGgO8xGASXA+Gf467G\n",
       "DQI8Fxi/iwiMDyQC4yuIwFj1WEWqWMkOIDpFvpto+FNu7rHS+/2nec5NpNOY2blEnfxqBxJXnVuq\n",
       "0AGyuw+Y2QYiJ7bSLGB9DlN6NJcyb5EXPIOhOcHHAEdRu2LD48AP2TMILgfCDyrNQeoxYz/gbOIX\n",
       "1wFEJY9PActVlUJkKCvZC4lW0AuINuqPApcAl6q5h0htaVFxyMJiucxbqxUiQE7l1qB2t77l6ba2\n",
       "YuwM8umAV72CnO2qsdlUhqZDlO9PqfEVzxCr7OU0iMrbvbg2fkjjUue7cmA8HXgCuAxY4c69ec5N\n",
       "pBNZyV5EbFZ9E/F+W256dYX3u5riiDSoajW5LSvInd5Jr9zyeQ5wMrEJ7HqqWkmnTnknApuJdIvN\n",
       "7n5jm+eaTeFqs32Jdtm1NsfNqPNVv2RoTvDPgLtxf7qp+UjPM2MKcA6xArY/ERhfRQTGbfkkL1Ik\n",
       "VrITiVJtf0Es7PyKWAm72vu95W/sIt2sMJ30JIzqBTPbCzic2pvjDqP2Svl2aqdD3IX7Y81/ByJ7\n",
       "MmMqkSv5ASJf8nFi891Kd+rl2ov0pIoaxhcAr0zDPyFWjD/v/drELJKFInXSk0F7pFi8ANb8Cm5m\n",
       "aCB8JLVbEj/CnhUiBgNh9x0tnrsI8Fxg/F7g/cQVmceI1a9V7jyQ59xEOk2dGsbfJ0q1fVU1jEWa\n",
       "pxSLAjOz+ybDfrvg3xgMhCfVeOrTwF3Uzgu+X5vjJC9m9AHvS7epxC+gK4CL3dmW59xEOo2VbB8i\n",
       "t7iyhvF6onmWahiLtIhWkAtoUrRGPpOoaXkP8H8Ymhf8C7Unlk5ixjQiKH4vg4HxciIw/k2ecxPp\n",
       "NHVqGF8PLFcNY5HuoQA5QwOwA/hjYDPuT+Q9H5HhmLE/kUbxHqIKyiPEZeFL3Nme59xEOo1qGIv0\n",
       "FqVYZCQt+U8i8jXL8mkOIjIMM6YTq1/vBiYDDwOXA5e6o9JTIhWsZIcR/18qaxivBi7xflfdb5E2\n",
       "qJWD7O61yttmd04FyNloV06MyFiZcQBRqu0cIh1oF1HH+JPuz7VtFxHASvZiIr+4sobx5cCnvd/1\n",
       "/0UkJ8pBFpFMmHEgg4HxJGAnUAIuc0fVUUQqWMleQlSkUA1jkR6mAFmkS5kxg7gkdTZxaXgA+Fsi\n",
       "MB7IcWoiHUU1jEWkmgLkbLW21bRIA8w4CDgPeCcRGO8gSk9d7s7OPOcm0klUw1ikGFQHucCUgyx5\n",
       "M+NgImfyLGAi8BBwCfApd3blOTeRTqIaxiLFpRxkEWmIGYcA5wOLgH2JzUSfAD7tzsN5zk2kk6iG\n",
       "sYg0SgGySEGZ8XwiMF7IYGBcAq5QYCwySDWMRWS0FCBnSznI0nJmvIDImVwA7ANsB/qBz7jzSJ5z\n",
       "E+kkdWoYX4JqGIsUinKQC0w5yNJqZryQCIzfAewNbANWAle6t/6XhUhRqIaxSPdSDrKIAGDGYcBi\n",
       "4O1EYPwAsAK4yn2Pzo0iPa1GDeNfEjWM/141jEVkNBQgi3QoMw5nMDCeANxP1GVdo8BYJNSpYfxj\n",
       "4hHrHT0AACAASURBVP/KF1TDWETGQgGySIcx4wjgw8BfE4HxfQwGxo/nNzORzlGnhvH/EDWMv6Ya\n",
       "xiLSDAXIIh3CjFlEYPxW4v/mvURd1rXuPJHn3EQ6xTA1jJcC31QNYxHJggLkbKmKhYyaGUcCHwHe\n",
       "AowHfk282f+9AmORYCWbTFSjqK5hvMz7/ZY85yYiraUqFgWmKhYyWmYcRQTGbyYC418SgfE17jyZ\n",
       "59xEOkWqYfwe4BwGaxj/E7DC+/1nec5NRNpPVSxEupQZRwMfBd5IBMa/AJYA/6jAWCSkGsYfJFaN\n",
       "JxIrRhcDl6qGsYi0mgJkkTYx47eIwPivgHHAPQwGxtppL8JzNYzPJz5AlmsYLwWuUA1jEWkXBcgi\n",
       "LWbGi4CPAa8nAuO7gYuAf1JgLBJSDePFRA1jUA1jEcmRAmSRFjBjHPAKYBEwn2hasIUIjD/rztM5\n",
       "Tk+kI6QaxqcSK8avSMOqYSwiuVOALJIhMw4h6he/A5iVhjcDFwKfU2AsAlayvYkrKucCv5uGVcNY\n",
       "RDqGAuRsqcxbDzJjPPAqYjPR/yY23j0LfAVYC9zkzrP5zVCkM1jJpgALgfcRpdoA/h1YCfyXahiL\n",
       "SC0q81ZgKvPWe1Ir6L8hWkGX3+w3A1cD17pzX15zE+kkVrIXAO8lUo6mEKXaPges8n6/M8+5iUix\n",
       "qMybSAcyY2/gNcRq8alEbvFTwBeJ1eJvuqPLwyKAlexYYtXnr4i26buAFcDlKtUmIp1MAbJIA8w4\n",
       "hsgrfiswIw3/iAiKP+vOg3nNTaSTpI13LwfOA16dhn8FfBJY6/2+K6epiYg0TAGySB1mTATmEYHx\n",
       "n6Thx4B/IALj77qjHCURwEq2F/CXRGB8Qhr+AZFf/CVVpBCRIlGALFLFjN8lUijeDPSl4VuI3OIv\n",
       "uLMzr7mJdBor2STgbcAH+P/t3Wu0nFd93/HvX7Lki3w5+AYNYdWSEyDNDdlxCiZthW9AQkO6bKAN\n",
       "LbShsiFN25UGOyRvpvMmC8ckgbTUNnZKWmjrOLZDCiHgCygXIAEbErJCFxfZSgLYYGRLAutmSf++\n",
       "2M94njM652jOOTPzzDPn+1lrlmb2fs7Mtveac36zZ19gc1X8ACUY3+vCO0ltZECWgAhOp2w7tR34\n",
       "0ap4H3AzcFsmn2uqbdI0im6cD/wc8O+Asyk7t/wfysK7zzbZNklaLQOy1qwIAriEEor/OXB6VfUJ\n",
       "yhSKuzLHv5WM1CbRjedTRovfCJxC2W7pXcA7s5O7GmyaJI2MAVlrTgTPAl5PCcY/VBXvBt4D/FYm\n",
       "X2iqbdK0im5cSplf/GrK7i3foByAc3N28okm2yZJo2ZA1ppQjRb/I0oovoYy8gVlruRtwAcyOdRQ\n",
       "86SpFN1YB/wkJRhfWhV/Efg14H3ZyYNNtU2SxsmAPFqepDdlIjif8lXwvwWeXxU/StmJ4rcyebip\n",
       "tknTKrpxCvAG4Bfov2/+lLLw7kMeBS1pkjxJr8U8SW96RLAOuIIyWvxqygEFxyhH2t4GfDiTI821\n",
       "UJpO0Y2zgbcA/4Gy33cCvwfclJ38sybbJkngSXrSskXw3ZTtpt4E/P2q+G+A3wLem8lXm2qbNM2i\n",
       "GxcAP09572wCDgK3AL+enfxycy2TpGYYkNVqEZwE/ARlCsWPA+uAp4G7KKPF93v0s7Sw6MZFlPnF\n",
       "rwHWUxar/hrw7uzkN5tsmyQ1yYCsVopgC2W0698Ava9ZvkQJxf8zE/+4SwuojoJ+BWU+32VV8cPA\n",
       "rwO/nZ10a0NJa54BWa0RwcnAT1HmFl9eFR8E3k8Jxn/i0c/SwqIbG4F/QQnGP1AVPwj8KnBPdvJo\n",
       "U22TpGljQF5CRNwI3JGZnqLWoAi+jxKK3wCcUxV/nhKK/1cmTzbVNmnaRTfOAq4F/iPw3Kr4w5Qd\n",
       "Kf7Io6Al6XgG5EVExEWUUPbRptuyFkVwGmVe5HbgpVXxdyih+DbgQUeLpcVFN76bEoqvBc6kzM3/\n",
       "bcpR0H/dYNMkaeoZkBd3MeXrR01QBFspofj1lD/qAH8O3A78TibfbqptUhtEN36QMo3ipym/4/dR\n",
       "plH8Znbya022TZLawoC8gIi4PjNviojXNN2WtSCCMylzI7dTPpgA7AH+C3B7Jp9vqm1SG1QL77ZR\n",
       "dqR4ZVX8VeCdwG3ZyX0NNU2SWqkVATki5ihfq//KQvOBI+IaYDMlVF0I3JeZD6zwtS4H7ltFczWE\n",
       "6ujnF1NC8euA06qqP6L09T2ZHGioeVIrRDdOAq6mBOPeh8u/oswvviM7+XRTbZOkNpvqgBwRWynh\n",
       "aTflj8DNC1xzBXBtZl5VK3swIrb3wnREXA1cucRL7axGjOeALQPhOkbwn6JKBOcA/4qyb/H3V8Xf\n",
       "BP4r5ejnLzXVNqktohubgJ8B/hNwQVX8ACUY3+vCO0landYcNR0Rx4ArMvNjA+UPATdn5u21su3A\n",
       "a+qhecjXuBrYUiv6JeB3gLtONCLtUdOLq45+3kYJxVcDGylH2N5LGS3+YCaHG2ug1BLRjWcDPwf8\n",
       "LHA2cBS4k7Lw7rNNtk2SJsGjpodQjfhupWxyX/ckcMVyny8z7x54/usYIhxrYRE8B/jXlGB8YVX8\n",
       "VeC/U45+3tVMy6R2iW68APgFylaHJwNPAe8C3pmd3NVg0yRpJrU6INMf7X1ioHwPQERckLn8Px4R\n",
       "cRbwy9Xz3xARGJKHE8F64OWUucX/lHJ87VHgA5SdKD6SiQcSSEOIbryUMr/4JynTvb4B/CZwS3Zy\n",
       "8PeeJGlE2h6Qz16kvPeHY24lT5qZe4FfrG46gQhOp0yheDnwauB5VdXDlFD825k82kzrpHaJbqyj\n",
       "vI+uB15SFX8ReAfw/uzkwabaJklrRdsD8mIWC84agWoHih+mBOKXAz8GbKiqDwN3UOYW78jkWCON\n",
       "lFomunEKZQrFLwDPr4r/lLLw7kPZSd9LkjQhbQ/IvZHiwUDcGzneM8G2AGyKiMcWqXtHZr5joq0Z\n",
       "oQjOA66iBOKrgGfXqndSThz8KPBxD/OQhhfdOAd4C/DvgfMpC1jvAW7KTv5Zk22TpKZExFsphx4N\n",
       "Oo+yDmOs2h6Qe4vzFpxKsZL5x6v01KzsYhHBBsrXu71R4otr1d8B/i9VKM5k5+RbKLVbdGMz8PPA\n",
       "myj7gB8EbgF+PTv55SbbJklNqwYVjxtY7O1iMW6tDsiZuSci7gfOGajagod9LFsEW+gH4suAM2rV\n",
       "n6U/Svwpt2WTlq868e4yyjZtPwWso+zz/g7g3dnJbzbYPElSpRUBudrODRY+tOPG6nZbrey1wA3j\n",
       "btcCBqdYTPW0impx3cvoh+LvqVV/g7LzxEeB+zLxD7e0QtGNOeCNlKkUL6iKdwK/Abw3O7m/qbZJ\n",
       "0rQbmG4xkSkWU31QSERsBq4DLgIuBx4B7mLgKOnqgI9LKH9w5ign490z4bZO/UEh1YEd9cV1L6W/\n",
       "uO5p4BP0R4n/0gV20upEN7ZSRotfD5xKmV/8IeC/UU688z0mScswqbw11QG5TaY1IEdwPv3FdVcy\n",
       "f3HdV5i/uO47k2+hNFuq3SheQwnGL66KH6dsefgeD/aQpJXzJL12anyKRQQbKYvrXkEJxVtr1d8G\n",
       "fp/+4rrBEwglrVB0YwvlG6830V8X8aeU0eJ7spOHmmqbJLWZUyxarMkR5AguZP7iutNr1Q8xf3Hd\n",
       "05NunzSrohvrKR9GfxZ4JWWdxFPA+4Cbs5Ofb7B5kjRzHEHWoiI4g/mL6y6sVX+Dsodqb3Hd45Nv\n",
       "oTTbohvnAT8DvBm4oCr+AmW0+H3ZyX0NNU2SNAIG5NEayxSLanHdi+gH4kuZv7ju45RA/BHg85n4\n",
       "tYA0YtUWbS+hjBa/BtgIHAHupATjP86OX8lJ0qg5xaLFRj3kH8Gzmb+47vxa9ZfpT5vY4eI6aXyi\n",
       "G6cDP00Jxj9cFX8NuBW4PTs5kU3rJUlOsVhzqsV1L6U/SvyiWvW36e9J/NFMHpl8C6W1JbrxfZR9\n",
       "i98InFkV308ZLf5gdvJIU22TJI2XAblBEXwP/UD8MvqL6xJ4kP4o8Z+5uE4av+jGBuDVlNHil1XF\n",
       "e4F3ArdkJ7/YVNskSZNjQB6tJecgV4vrLqMfirfUrn0MuJsSiO93cZ00OdGN5wLbgWuB3td2nwXe\n",
       "DdzhSXeS1BznILfYQnNiqsV1W5m/uK73oeQwZY/U3iixi+ukCaoW3b2MMlr8U8B64BBwB2UaxWdc\n",
       "dCdJ08U5yC0VwXOYv7juvFr1l5i/uG7sn4AkzRfdmAPeQJlf/MKq+GHgZuC92cndTbVNkjQdDMgj\n",
       "de65QH1F+z7g9+gvrtvVRKskQXTjRZTR4tcDp1Hm+n+QMlp8b3byWIPNkyRNEQPySJ10EvAZ+qPE\n",
       "f+7iOqk50Y1TgGsowfglVfHjwLuA92QndzXUNEnSFHMO8oiUOTGxCeYt5hnJQSGSlie6sRm4DngT\n",
       "cG5V/AnKaPHd2clDTbVNkrQ8Cy3Sy8wzl/iR1b+mAXk0JjVpXNLCohvrgVdQ5hb/OBCUlc7vB27O\n",
       "Tv5lg82TJI2Ai/QkaQjRjfOAnwHeDFxQFX+BsujufdnJvQ01TZLUUgZkSa1TbdH2Ysrc4tcCG4Ej\n",
       "wJ2UaRR/7BZtkqSVMiBLao3oxibgpynBuHcc+9eAW4Hbs5OPLvazkiQNy4A8WkuepCdpZaIbL6TM\n",
       "LX4jcFZVfD9ltPiD2ckjTbVNkjRenqTXYi7Sk0YrurEB+EnKaPFlVfFe4L3ALdnJLzbVNklSM1yk\n",
       "J2lNim58F7AduBb4rqr4c8C7gTuyk55AKUkaKwOypMZVi+62UUaL/xmwHjgE/A/KbhSfdtGdJGlS\n",
       "DMiSGhPdOAt4AyUYv7AqfpgSit+bndzdVNskSWuXAVnSxEU3XkRZdPcvgdOABD5IWXR3b3byWIPN\n",
       "kyStcQZkSRMR3TgFuJoyWnxpVfw48C7gPdnJXQ01TZKkeQzIo+U2b1JNteDux4GfAK4ENlVVn6CM\n",
       "Ft+dnTzUUPMkSS3gNm8t5jZvEkQ31gEXA6+ihOKLa9WPAh8Abs1O/mUDzZMktZzbvElqhejGGZTR\n",
       "4VdRRoufXav+DPCh6vYXzi2WJLWBAVnSskU3LqQE4lcB/wTYUFV9B7iHEoj/MDv52MLPIEnS9DIg\n",
       "Szqh6lS7l9IPxS+oVe+kP0r8J84pliS1nQFZ0oKiG+cCr6QE4pcDZ1VVR4Ad9EPxlzzEQ5I0SwzI\n",
       "koBnTrP7QfqjxC8GoqreDbyPEojvzU7uaaSRkiRNgAFZWsOiG6cCl9HfdeJ5terP0x8l/nR28ujk\n",
       "WyhJ0uQZkKU1JrrxPEoYfhUlHJ9aVR0E/oASiD+cnfzbZlooSVKzDMjSjIturAd+lP7UiR+qVX+V\n",
       "/ijxx7OT+yffQkmSposBWZpB0Y054CpKIH4lcG5VlcCn6Ifiv3KBnSRJ8xmQR8ujptWIaoHd8+mP\n",
       "Ev8Y/ff3PuBOSiD+SHby8UYaKUnSCnjUdIt51LQmLbqxEfjH9EPxhbXqL9IfJf5EdvLpybdQkqTR\n",
       "8qhpSceJbjybcpzzqyhTKE6vqp4G7qcE4j/ITn6lmRZKktR+BmRpikU31gFb6e86cUmt+pvA71JC\n",
       "8f3ZyX2Tb6EkSbPHgCxNmejG6cAVlFD8E0D9a6TP0p868VB28tjkWyhJ0mwzIA+IiBuAt1cP9wA3\n",
       "ZObtDTZJa0B0YzP9UeKXARurqv3A79Pfm/jrzbRQkqS1w4B8vATmgLMzc1fDbdGMim6cBFxKPxT/\n",
       "g1r1LvqjxH+UnTw48QZKkrSE2LFjHbC+up1Uu79+heXDXXvyyady6NCBcf/3GZAXkJn7KFtjSSMT\n",
       "3TgHeAUlFL8CeFZVdQz4E6oFdsAX3JtYktopduwISr46ubptHNH9DawugK4umB5f3oxNmzAgNyQi\n",
       "rqdMr7gYuDUzP9dwk9RC1Ql2P0AJw6+ijBivq6qfBP43JRB/JDv5RCONlKSWqoLoqMLnKIPsRiDG\n",
       "+J8+SseAI8DRgVuv7PAi5ScqW2758Nfu3/+fx/J/YkAr9kGOiDngNuBXFgqrEXENsJkSai8E7svM\n",
       "B1b4Wpsz85Hq/lnAI5l59hA/5z7Ia1x040zgHwIvpYThFwNn1C75a/qjxJ/KTh6ZeCMlacRix471\n",
       "wKlD3E4b8rr67RSWHlFt0mHgUHWr3x98vNz7i9U9zWjD5rHctm36Q+AA90EGImIr8DpgN3A1cPMC\n",
       "11wBXJuZV9XKHoyI7b0wHRFXA1cu8VI7M/Om6v6TvcLM3BsRRMTlKw3cmk3VyXWbKUH4Ukoo/kHm\n",
       "jxo8BtwL7AA+lB3ntEsav9ix4yRWFkhXev04g2oyPzgeoAyGTSqULhpW2xguNbypDshVwO2F3BsX\n",
       "uexGjg/Ot1blV1XPczdw94lerxqpfoL+1+DPNGX4VmsWRTdOpuxH3BsdvhR4Tu2SY8DngU8Cn6j+\n",
       "3eVcYqn9anNKe7f1A48Xu63kug2UUdPVBNhx/m1/mhJSD1D+Xh4YuO1foGyp25LX57ZtngKqRkx1\n",
       "QD6RKtBuBR4eqHqSso/ssmTmnnoQj4gtwO7M/NiqGqrWiW6cD7yE/ujwj1C+0uv5NmV0uBeIP+1B\n",
       "HVJRrW4/hX7QO2WRx/X7yw2V4w6q9dvgoMk06Y2qHgAeZxVhdJjrc9u2oxP675Ia1eqADGyp/h1c\n",
       "4LQHICIuWMFWbXdWi/SgzGdeamqGZkB1Wt33MX90+HsHLnuY/sjwJ4G/zk76h0JTqwqpJ3PiYDps\n",
       "gF1OXW8f72nVm495ZOD+EeDgwOPFrlvsNorrDjJkiM1t2zwsSBqDtgfkxRbP9QLz3HKfsD6tQ7Op\n",
       "OqnuR+mPDr8EOKt2yWHgU/RHhz+VnXxs0u1Ue1RfwfdGHzcw/+vyxco2svpgutR19W88xukAJdAd\n",
       "pKwXqT+u3x98PFg3TKgcRQA96txRSSfS9oC8mBPuOqG1oVpM9zzmjw7/MPP3cHwc+AD90eGHPJxj\n",
       "9GLHjo3AJhYPj8MGy3FcP4rnalLva/aDlClmKw2py607bNiUNIua/qW+Wr2R4sFA3Bs53jPBtmgK\n",
       "RDc2AC+iPzp8KfDc2iVJ2W6tPl1ip4vpFleNjp4OnEkZae/dzlzm/UmNaI7SUcqipCMD/x5coOzI\n",
       "ImVL1fWC5mLBdNiQ6tfskjRCbQ/IvcV5C06laOCo6E0RsdhX8e/IzHdMtDVrQHU6XW8x3aWUqROn\n",
       "1i55CniA/nSJP89OrpkPTrFjxwaWH2QH75/Jyhcp7aecSrkL2Fs9fprhwuNyw+ZK6xa73q/iJakh\n",
       "EfFW4K0LVJ1H+ds+Vq0OyNWuE/cD5wxUbQHua6BJT3lQyPhU0yVewPzR4RcOXPY3zB8d/qs2HshR\n",
       "jdqexspDbe/+qYPPPaRjlGC7F/i76t+9tbKl7vce73OLJknSSlSDiscNLPYOChm3VgTkajs3WPjo\n",
       "xhur2221stcCN4y7XRqv6MZpwCX0R4cvZf50miPAp5m/mO5rk24nPBNo6zsG1BdNnc7KAu5Kz7o/\n",
       "SAmoX2X5obZ3/ylHTyVJa9VUHzUdEZuB64CLgMuBR4C7GDhKujop7xJgJ2W6xc7MvGfCbX2UsgBp\n",
       "f63YaRXLEN14LvNHh7cy/0Pcbvojw58EPpOdPPDMz5fTowYD6kIr/ZdTP+zPjmJ+bVL2Vx421C42\n",
       "antoBG2RJGkqDEy3OI/yjf2ZY33NaQ7IbTKps8Gn2RKjqMcHymOHT2Pf//teDn79hTy973s5enAL\n",
       "EXOs2wixEdZthA1n7GXjs55g49l72fCs/aw/7RgRSz3vSkdcl6u+Y8Bit179IeA7DDdq+x0XW0mS\n",
       "tLhJ5S0D8ohM6whytUhrqaNKl3q8nGt7t4WmwYzaMRZe/b9YSB1lvTsGSJI0QY4gt9iwn2hqR7Cu\n",
       "Jowu59pxzjNf+OjSzAMc3b+Ow0+ezuHdZ3H4iXM4sm+OY4d55pa5l/Wn7mTDGV/mlL/3Bc78/i+x\n",
       "/pSnGCKk5rZtrVt0J0mSVm9SI8itWKTXGmecMRc7dvwhSwfXce4Fe5h+UP0W88PrYJBd+PGxIwc5\n",
       "su8oh/cc4/C34PBuOPhNOPytdRx6fD2HvrWew99az9P7NkBuqv6berdNwPnAiymf8HqOAg/RX0z3\n",
       "yezk343x/4MkSdKKGZBHacOGU4BX1Ep6UwEOUBZffZPlhNXB+8cOH+LQ40c5+Fhy4OvB/r+FA19b\n",
       "x8Gvr+fgY+s5dqgXwuuBdaHH5y5RP4oAvwf4MP3FdJ/OTo59z0JJkqRRcIrFiETEo0ScQVAdUZzw\n",
       "bN7PdfweJw6swz4+ZQxN74Xw/ZSNt/ev8vFe4OHspPN0JUnSqjkHucUi4lFO5zkLnvmycvXwOqoA\n",
       "W398wCArSZLawjnIbXSUp4GPM5oAa3iVJElqgCPII+I+yJIkSeM1qby1bpxPvgZtiojHarfRTriQ\n",
       "JElaYyLirb1sRdkta9PYX9MR5NFwBFmSJGm8HEGWJEmSGmBAliRJkmoMyKPlHGRJkqQRcg5yizkH\n",
       "WZIkabycgyxJkiQ1wIAsSZIk1RiQJUmSpBoDsiRJklRjQB4td7GQJEkaIXexaDF3sZAkSRovd7GQ\n",
       "JEmSGmBAliRJkmoMyJIkSVKNAVmSJEmqMSBLkiRJNQbk0XKbN0mSpBFym7cWc5s3SZKk8XKbN0mS\n",
       "JKkBBmRJkiSpxoAsSZIk1RiQJUmSpBoDsiRJklRjQJYkSZJqDMiSJElSjQFZkiRJqjEgj5Yn6UmS\n",
       "JI2QJ+m1mCfpSZIkjZcn6UmSJEkNMCBLkiRJNQZkSZIkqcaALEmSJNWc1HQDplFEXAFsBfYAz8rM\n",
       "X224SZIkSZoQA/KAiLgGuCIz31w9fgIwIEuSJK0RBuTjvQe4oPcgM89urimSJEmaNANyTURsAeaA\n",
       "SyJiDrgEuC8zH2i2ZZIkSZqUVizSi4i5iPjdiNi6SP01EXF9RGyPiLdHxOUrfKkt1b+7M/PuzHwb\n",
       "cGtEnDXkz4/9ZBc1y9MRZ5v9O/vs49lnH68Ja/skvSoQvw7YDdxImRv8sYFrrgBuyMyramUPAtsz\n",
       "83PV46uBK5d4qZ2ZeVNEXAQ8mJnPfHConuvWzLztBG19FDg/M9cv6z9SrRIRj2Xmc5puh8bD/p19\n",
       "9vHss49n26Ty1lRPsagCbi/k3rjIZTcCNw+U3VqVX1U9z93A3UO85MOLlO8e4mclSZI0A1oxxWIx\n",
       "1TzhrRwfbJ8Erlju82XmHuCugSkac8D9K25kg8bxNdNqnnO5Pzvs9Se6bqn6xera8hWdfXzievt4\n",
       "tM9pH4/eWujj1V5jH4/2OZvo45X077CvPQ5TPcWiLiKOMTDFojclArgoM/+iVn4FcC+wJTN3LfN1\n",
       "zqKMPu8EzgHuqD/3Ej83dVMsxvE102qec7k/O+z1J7puqfrF6pZb3hT7+MT1y+nLaetfsI+HqbeP\n",
       "R/uc4+jj1V5jH4/2OZvo45X070J1TrEYzmJbsD1R/Tu33CfMzL3Am1fcIkmSJLVa2wPyYprYu/hc\n",
       "YF31yWZanDeG9qzmOZf7s8Nef6LrlqpfrG655U2xj09cv5y+nLb+Bft4mHr7eLTPOY4+Xu019vFo\n",
       "n7OJPl5J/y5Udz4TmCLc9oDcGykeDMS9keM9E2zLEWA9peMW8lR1m6RxvN5qnnO5Pzvs9Se6bqn6\n",
       "xeqWW94U+/jE9cvpy2nrX7CPh6m3j0f7nOPo49VeYx+P9jmb6OPl9u+m6hbMz1brgGNDtGdV2h6Q\n",
       "e4vzFpxKsdz5x6uRmadO6rUkSZI0Pq3exaLadeJ+ymK6ui3AfZNvkSRJktquFQE5ynZuUIbZB90I\n",
       "XDdQ9tqqXJIkSVqWqd7mLSI2U8LvRcDlwCPAXcB9mflA7bqrgUsoW7PNUU7Gu2fyLV5cRNwK3NI7\n",
       "3U+zo9pu8LXVw4uAX7SfZ0u1deTm6uGVlNM1H1jiR9RiUQ6musP38WyJiBuAt1cP91BO4b29wSZp\n",
       "DKrf11spffyszPzVFT3PNAfkWVAL79cClw2zp7LaJSJuzczrqvtbgYeAuczc12zLNCoR8RXg2sz8\n",
       "WNXHD2RmE7vlaMyqD7z3A9fU991X+0XE9ZSTds+e5BolTU5EXEM5M+PN1eMnVvq7uhVTLNosM+/O\n",
       "zLfR33FDMyQitgDbe4+rEac9wI801iiNQ/2QooWmeml2XEw5gEozKDP3GY5n2nuAG3oPVjOQ0fZd\n",
       "LKRGZebD1YgT8Mx8+TmOP/5cLTbwB/U6yiiUZkxEXJ+ZN0XEa5pui8ajGkXeQ/kgdKvTaGZHNWA1\n",
       "B1xS/S2+hIEpucthQD6B6n/ybcCvLPRGqobzN1PecBeyis5QM1bbxwPTZn6J8kt311gbrWUZxfu4\n",
       "tibiAmojFJoOq+3jiLgcdz+aaiN4H9+VmY9U195JWdfkVKkpsso+3lL9u7squzsivhIRF1enJC+L\n",
       "AXkR1TzD1wG7gauBmxe45grKvMSramUPRsR2P5VOv1H3cfXGPTMz3zLelmtYo+zj6g/r26rnfCQi\n",
       "Nq/kl65GaxR9XP1R3jIQppxKMyVG+D5+sleXmXsjgoi43EGt5o2oj5+A4wat9lAW0d+23DY5B3kR\n",
       "mfm5zHxbZt60xGU3AncOlN2KW8y1wij7uHrjXpyZb4mIs6rRRjVsFH0cERdFxDOnNtX+2Po1/BQY\n",
       "0fv4cmAuIq6vvoL/EeCaalRZDRvR+3iOhdcCuVPBFBjR+3ixqY27V9ImR5BXqHqzbeX4DnkSuGKx\n",
       "HxtrozRSw/ZxNQf5SuCWag7UNfhVbSsM2cdPUptzXJtn7kKuFhimjzPz7oGfuY7ydbwjiy0wZB/v\n",
       "qbbv6/3MFspX8e5U0gLL6OO7Br4VmKPsSrNsBuSV6811GfxEugcgIi7IzF3VCMSV1fU3RsR9J/iE\n",
       "pOlxwj6u7t9PeRNeX9XnSvdd1MQN8z5+pPql2+vfSyhbgLllYzsM9bu6un8W8MvVz9wQERiSW2HY\n",
       "Pr6z9j6+kPK3We0wbB9vp2StiyinLF+z0i1XDcgrt9jE/l7nzQG9X64PAG+bRKM0Uifs4+oNr3ie\n",
       "WAAAAn1JREFU6SKP9lru+1jtM1QfQ5mXCvxidVN7DPs+/hzg+qB2GraP9wJvHsULOgd59AxLs88+\n",
       "nn328eyzj2effTz7xtbHBuSV631qGeyc3mjEngm2ReNhH88++3j22cezzz6efRPvYwPyyvUmis8t\n",
       "VOk+uDPBPp599vHss49nn308+ybexwbkFcrM3uKscwaqtuAOBjPBPp599vHss49nn308+5roYwPy\n",
       "CVRbi8DCW7TdSDlZq+61uA9yq9jHs88+nn328eyzj2ffNPVxZLpH9kJqx8peRNlE/hHgLo4/nvRq\n",
       "yrZPOylD/zsz857Jt1jLZR/PPvt49tnHs88+nn3T2McGZEmSJKnGKRaSJElSjQFZkiRJqjEgS5Ik\n",
       "STUGZEmSJKnGgCxJkiTVGJAlSZKkGgOyJEmSVGNAliRJkmoMyJIkSVKNAVmSJEmqMSBLkiRJNQZk\n",
       "SZIkqcaALEmSJNUYkCVJkqQaA7IkSZJUY0CWJEmSagzIkrRGRMRDEXFnRGyp7h+LiCci4u1Nt02S\n",
       "pokBWZLWjgTmgHuBTwPXAg8CN0TE9U02TJKmSWRm022QJE1ARDwEbAWuycx7auVPAJ/JzJc31jhJ\n",
       "miKOIEvS2vJkPRxXHgLObqIxkjSNDMiStLY83HQDJGnaGZAlSZKkGgOyJEmSVGNAliRJkmoMyJK0\n",
       "tsQyyyVpzTEgS9LakdVt2HJJWpPcB1mSJEmqcQRZkiRJqjEgS5IkSTUGZEmSJKnGgCxJkiTVGJAl\n",
       "SZKkGgOyJEmSVGNAliRJkmoMyJIkSVKNAVmSJEmqMSBLkiRJNQZkSZIkqcaALEmSJNUYkCVJkqQa\n",
       "A7IkSZJUY0CWJEmSav4/UK3zbOg0ab8AAAAASUVORK5CYII=\n"
      ],
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7ff17ea77fd0>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "%matplotlib inline\n",
    "import matplotlib.pyplot as plt\n",
    "import matplotlib\n",
    "matplotlib.rcParams['savefig.dpi']=130\n",
    "plt.xscale('log')\n",
    "plt.yscale('log')\n",
    "plt.xlabel('n')\n",
    "plt.ylabel('time(s)')\n",
    "for func, times in data.items():\n",
    "    plt.plot(ns, times, label=func.__name__.replace('_',r'\\_'))\n",
    "plt.legend(loc='best')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Conclusion\n",
    "----------\n",
    "There are two things to see from the graph.\n",
    "  - First lets look at the pure python implementations(`fib` and `fib_bme`). For these guys, `fib` funs significantly faster for n less than a few hundred. However, for larger n, the `fib_bme` algorithm becomes much faster. \n",
    "  - Next, lets look at the cython implementations. For these there is much less drastic difference in run-times between `cfib` and `cfib_bme` than we saw with the pure python implementation. The asymptotic behaviour of the two algorithms in the cython implementation behaves the same as the python ones, as we should expect.\n",
    "  - Finally, it's worth pointing out that for n greater than ~50,000, the pure python BME implementation beats out the cython looping implementation."
   ]
  }
 ],
 "metadata": {
  "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.4.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
