search-4e.ipynb 89,4 ko
Newer Older
    "    assert f\n",
    "    assert f.pop().state == 2\n",
    "    assert f.pop().state == 3\n",
    "    assert not f\n",
    "    \n",
    "    #### Depth-first search with LIFO Q\n",
    "    f = FrontierQ(Node('a'), LIFO=True)\n",
    "    for s in 'bcdef': f.add(Node(s))\n",
    "    assert len(f) == 6 and 'a' in f and 'c' in f and 'f' in f\n",
    "    for s in 'fedcba': assert f.pop().state == s\n",
    "    assert not f\n",
    "\n",
    "    #### Best-first search with Priority Q\n",
    "    f = FrontierPQ(Node(''), lambda node: len(node.state))\n",
    "    assert '' in f and len(f) == 1 and f\n",
    "    for s in ['book', 'boo', 'bookie', 'bookies', 'cook', 'look', 'b']:\n",
    "        assert s not in f\n",
    "        f.add(Node(s))\n",
    "        assert s in f\n",
    "    assert f.pop().state == ''\n",
    "    assert f.pop().state == 'b'\n",
    "    assert f.pop().state == 'boo'\n",
    "    assert {f.pop().state for _ in '123'} == {'book', 'cook', 'look'}\n",
    "    assert f.pop().state == 'bookie'\n",
    "    \n",
    "    #### Romania: Two paths to Bucharest; cheapest one found first\n",
    "    S    = Node('S')\n",
    "    SF   = Node('F', S, 'S->F', 99)\n",
    "    SFB  = Node('B', SF, 'F->B', 211)\n",
    "    SR   = Node('R', S, 'S->R', 80)\n",
    "    SRP  = Node('P', SR, 'R->P', 97)\n",
    "    SRPB = Node('B', SRP, 'P->B', 101)\n",
    "    f = FrontierPQ(S)\n",
    "    f.add(SF); f.add(SR), f.add(SRP), f.add(SRPB); f.add(SFB)\n",
    "    def cs(n): return (n.path_cost, n.state) # cs: cost and state\n",
    "    assert cs(f.pop()) == (0, 'S')\n",
    "    assert cs(f.pop()) == (80, 'R')\n",
    "    assert cs(f.pop()) == (99, 'F')\n",
    "    assert cs(f.pop()) == (177, 'P')\n",
    "    assert cs(f.pop()) == (278, 'B')\n",
    "    return 'test_frontier ok'\n",
    "\n",
    "test_frontier()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {
    "button": false,
    "collapsed": false,
    "deletable": true,
    "new_sheet": false,
    "run_control": {
     "read_only": false
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXEAAAEACAYAAABF+UbAAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAGf5JREFUeJzt3XuQVPWd9/H3h4vGy8JiVjAqIRFXJG4lEl0vQWMb77gB\nk31C5ImumsdNJRo1bio6ums5qYpVasol5GbiRhHjJYouQlx9QBZboiZeAG8RWSMrXhmzXFzRCqvw\n3T/OGRzHhjk93T2nT/fnVdU1p5tzur814odf/87voojAzMyKaVDeBZiZWf85xM3MCswhbmZWYA5x\nM7MCc4ibmRWYQ9zMrMAyhbik8yQ9lT7OTV8bIWmBpBWS5ksa3thSzcystz5DXNJ+wP8DDgT2B/5G\n0ligA1gYEeOARcBFjSzUzMw+KEtLfDzwcERsjIhNwGLgi8BkYFZ6zizgpMaUaGZmW5MlxJ8GDk+7\nT3YEJgGjgVER0QUQEauBkY0r08zMKhnS1wkR8aykK4B7gQ3AMmBTpVPrXJuZmfWhzxAHiIiZwEwA\nSZcBLwFdkkZFRJek3YDXK10ryeFuZtYPEaG+zsk6OmXX9OdHgS8ANwPzgNPTU04D5m6jkKZ6XHrp\npbnXUISamrUu1+Sa2qGurDK1xIE7JO0CvAOcFRH/nXax3Cbpq8AqYGrmTzUzs7rI2p3y2QqvrQWO\nrntFZmaWWVvO2CyVSnmX8AHNWBM0Z12uKRvXlF2z1pWFqul76dcHSNHozzAzazWSiHrd2DQzs+bk\nEDczKzCHuJlZgTnEzcwKzCFuZlZgDnEzswJziJuZFZhD3MyswBziZmYF5hA3Myswh7iZWYE5xM3M\nCswhbmZWYA5xM7MCy7o92/mSnpb0pKSbJG0naYSkBZJWSJovaXijizUzs/frM8Ql7Q6cA3w6Ij5J\nshvQNKADWBgR44BFwEWNLNTMrF1cfnn2c7N2pwwGdpI0BNgBeAWYAsxK/3wWcFL2jzUzs0pmzIAb\nbsh+fp8hHhGvAlcBL5KE9xsRsRAYFRFd6TmrgZH9KdjMzBJ33AHf/z7cc0/2a/rcKFnSn5O0uscA\nbwCzJX0F6L3n2lb3YOvs7NxyXCqVCr2fnZlZI/zoR2U6OsqccgrMnJn9uj732JT0f4DjIuLv0+en\nAocAnwNKEdElaTfgvogYX+F677FpZrYNK1bAEUck3SjHHpu8Vs89Nl8EDpH0IUkCjgKeAeYBp6fn\nnAbM7UftZmZtbfVqOOGE5GZmd4BXI9Nu95IuBU4G3gGWAWcCfwbcBowGVgFTI2J9hWvdEjczq2DD\nBiiVYMoUuOSS9/9Z1pZ4phCvhUPczOyD3n0XJk+GPfaAa64B9YrrenanmJlZHUXAN76RHP/0px8M\n8Gr0OTrFzMzq63vfg6VL4f77YejQ2t7LIW5mNoCuvz4ZQvjQQ7DzzrW/n/vEzcwGyPz5cNppSQt8\n3Lhtn5u1T9wtcTOzAbBsGZx6KsyZ03eAV8M3Ns3MGmzVKvj85+Hqq2HixPq+t0PczKyB1q1LJvNc\ncAH87d/W//3dJ25m1iB/+hMcdxwceCBcdVV113qyj5lZjjZvhmnTkuNbboFBVfZ7+MammVmOLrgA\nXnsNFiyoPsCr4RA3M6uzGTPg7rvhgQfgQx9q7Gc5xM3M6qh7Y4cHH4Rddmn85znEzczq5MEHkzVR\n5s+HMWMG5jM9xNDMrA6efTYZQnjjjTBhwsB9rkPczKxGq1fDpEn939ihFg5xM7MabNgAJ54Ip5+e\nPAZalj029wFuJdkIWcBewCXAL9PXxwAvkOzs80aF6z1O3MxaUvfGDrvvDv/yL7WtC95bQyb7SBoE\nvAwcDHwTWBMRV0q6EBgRER0VrnGIm1nLiYCvfQ1eeQXmzq19XfDeGrWzz9HA8xHxEjAFmJW+Pgs4\nqcr3MjMrrO6NHW67rf4BXo1qhxh+Gbg5PR4VEV0AEbFa0si6VmZm1qTqvbFDLTKHuKShwGTgwvSl\n3n0kW+0z6ezs3HJcKpUolUqZCzQzaybz50NHR7Kxw2671e99y+Uy5XK56usy94lLmgycFRHHp8+X\nA6WI6JK0G3BfRIyvcJ37xM2sJSxblqxKOGdO/dcF760RfeLTgFt6PJ8HnJ4enwbMreK9zMwKpZEb\nO9QiU0tc0o7AKmCviHgzfW0X4DZgdPpnUyNifYVr3RI3s0JbuxYOOwy+/nU499yB+UyvJ25mVgd/\n+lMyC/Ov/7r6jR1q4RA3M6vR5s1w8snJJJ7+bOxQC28KYWZWo+98J1kXpdEbO9TCIW5mVsGMGXDP\nPQOzsUMtHOJmZr0M9MYOtXCIm5n1kMfGDrVo0l4eM7OBl9fGDrVwiJuZke/GDrVwiJtZ28t7Y4da\neJy4mbW1d95JNnbYY4/6b+xQi0atJ25m1jIikpuYUrImSrMEeDU8OsXM2lIEnHMOPP00LFyY78YO\ntXBL3MzaTneAP/ZYMpQw740dauEQN7O20jvAhw/Pu6LaOMTNrG20WoCDQ9zM2kQrBjg4xM2sDbRq\ngEPGEJc0XNJsScsl/V7SwZJGSFogaYWk+ZJa6NdiZq2ilQMcsrfEZwB3pxshfwp4FugAFkbEOGAR\ncFFjSjQz659WD3DIMGNT0jBgWUSM7fX6s8ARPXa7L0fEvhWu94xNMxtwRQ/wes7Y/DjwX5JmSloq\n6Zp04+RREdEFEBGrgZG1lWxmVh9FD/BqZJmxOQT4NHB2RDwmaTpJV0rv5vVWm9udnZ1bjkulEqVS\nqepCzcyyKGqAl8tlyuVy1ddl6U4ZBfw2IvZKnx9GEuJjgVKP7pT70j7z3te7O8XMBkRRA7ySunWn\npF0mL0naJ33pKOD3wDzg9PS104C5/SvVzKx2rRTg1ci0FK2kTwG/AIYCK4EzgMHAbcBoYBUwNSLW\nV7jWLXEza6hWDPCsLXGvJ25mhdaKAQ5eT9zM2kCrBng1HOJmVkgO8IRD3MwKxwH+Hoe4mRWKA/z9\nHOJmVhgO8A9yiJtZITjAK3OIm1nTc4BvnUPczJqaA3zbHOJm1rQc4H1ziJtZU3KAZ+MQN7Om4wDP\nziFuZk3FAV4dh7iZNQ0HePUc4mbWFBzg/eMQN7PcOcD7L8sem0h6AXgD2Ay8ExEHSRoB3AqMAV4g\n2RTijQbVaWYtygFem6wt8c0k+2lOiIiD0tc6gIURMQ5YBFzUiALNrHU5wGuXNcRV4dwpwKz0eBZw\nUr2KMrPW5wCvj6whHsC9kh6VdGb62qh0E2UiYjUwshEFmlnrcYDXT6Y+cWBiRLwmaVdggaQVJMHe\nkzfSNLM+OcDrK1OIR8Rr6c8/SroTOAjokjQqIrok7Qa8vrXrOzs7txyXSiVKpVItNZtZQTnAt65c\nLlMul6u+rs/d7iXtCAyKiA2SdgIWAN8FjgLWRsQVki4ERkRER4Xrvdu9mTnAq5R1t/ssIf5xYA5J\nd8kQ4KaIuFzSLsBtwGhgFckQw/UVrneIm7W5jRvhq1+FF16Au+92gGdRtxCvQyEOcbM2tmYNfOEL\nMGoU3HAD7LBD3hUVQ9YQ94xNM2uY55+Hz3wGDjkEbr3VAd4IDnEza4jf/Q4OOwy+9S248koY5LRp\niKxDDM3MMrvjDvj612HWLJg0Ke9qWptD3MzqJgL++Z9h+nRYsAAmTMi7otbnEDezunj3XTjvPPjN\nb+C3v4XRo/OuqD04xM2sZhs2wMknw//8DzzwAAwblndF7cO3GsysJq++Cp/9LHzkI/Bv/+YAH2gO\ncTPrt6eegkMPhS99Ca65BoYOzbui9uPuFDPrl3vvha98BWbMgGnT8q6mfbklbmZVu+46OPXUZCih\nAzxfbombWWYRcMkl8Ktfwf33w7hxeVdkDnEzy6R7EauVK5MhhLvumndFBu5OMbMM1q6FY45JhhAu\nWuQAbyYOcTPbJi9i1dwc4ma2Vd2LWJ13nhexalbuEzeziu64A77xDbj+ei9i1cwy/7sqaZCkpZLm\npc9HSFogaYWk+ZK8V4dZC4iAq65KlpCdP98B3uyq+XJ0HvBMj+cdwMKIGAcsAi6qZ2FmNvDefRe+\n+c1kCdmHHvIqhEWQKcQl7QlMAn7R4+UpwKz0eBZwUn1LM7OBtGEDnHQSPPdcsoiVVyEshqwt8enA\nd0g2S+42KiK6ACJiNTCyzrWZ2QDxIlbF1WeISzoR6IqIx4Ftbdrp3ZDNCsiLWBVbltEpE4HJkiYB\nOwB/JumXwGpJoyKiS9JuwOtbe4POzs4tx6VSiVKpVFPRZlYfXsSqeZTLZcrlctXXKSJ7A1rSEcC3\nI2KypCuBNRFxhaQLgRER0VHhmqjmM8xsYFx3HVx8McyeDYcfnnc11pskImJbvR9AbePELwduk/RV\nYBUwtYb3MrMB4kWsWktVLfF+fYBb4mZNo+ciVvPmeQ2UZpa1Je5JtGZtwotYtSaHuFkbWLnSi1i1\nKoe4WYvzIlatzQtgmbUwL2LV+hziZi0oAqZPTx7z53sNlFbmEDdrMRs2JItYLV2aLGLlNVBam3vH\nzFrIsmVwwAEweHCyD6YDvPU5xM1aQAT86Edw3HHQ2QnXXgs77ZR3VTYQ3J1iVnBr1iQTeF59NWl9\njx2bd0U2kNwSNyuwxYuTm5Z/+Zfw4IMO8HbklrhZAW3aBJddBldfnSxkdcIJeVdkeXGImxXMK68k\ny8cOHgxLlsDuu+ddkeXJ3SlmBXLXXcnok2OOgQULHODmlrhZIWzcCBdeCHPmJLMwJ07MuyJrFg5x\nsyb33HPw5S/Dxz6WjAPfZZe8K7Jm4u4UsyZ2443J6oNnnpm0wB3g1lufLXFJ2wOLge3S82+PiO9K\nGgHcCowBXgCmRsQbDazVrG1s2ABnnw2PPAL//u/wyU/mXZE1qz5b4hGxETgyIiYA+wMnSDoI6AAW\nRsQ4YBFwUUMrNWsT3VPnhwyBxx5zgNu2ZepOiYi308PtSVrjAUwBZqWvzwJOqnt1Zm3EU+etPzLd\n2JQ0CFgCjAV+EhGPShoVEV0AEbFa0sgG1mnW0jx13vorU4hHxGZggqRhwBxJ+5G0xt932tau7+zs\n3HJcKpUolUpVF2rWqhYvhlNOgalTYfZs2G67vCuyPJTLZcrlctXXVb3bvaRLgLeBM4FSRHRJ2g24\nLyLGVzjfu92bVbBpE3zve/Czn3nqvH1Q3Xa7l/QXkoanxzsAxwDLgXnA6elppwFz+12tWZt5+WU4\n6qikFb5kiQPc+i/Ljc2PAPdJehx4GJgfEXcDVwDHSFoBHAVc3rgyzVrHXXfBgQd66rzVR9XdKVV/\ngLtTzID3T52/+WZPnbdty9qd4mn3ZgPAU+etUTzt3qzBPHXeGsktcbMG6Z46//DDsHAhfOpTeVdk\nrcgtcbMG6Dl1fskSB7g1jkPcrI4i4Ic/hGOPhUsv9dR5azx3p5jVyZo1cMYZ702d33vvvCuyduCW\nuFkddO86v88+8NBDDnAbOG6Jm9XgrbeSXednzvTUecuHW+Jm/RCRTNr5xCfgP/8Tli51gFs+3BI3\nq9Jzz8E558CLL8L118ORR+ZdkbUzt8TNMnrrLfjHf4RDD4Wjj4YnnnCAW/7cEjfrQwTceSd861vJ\nzMsnnoA99si7KrOEQ9xsG9x1Ys3O3SlmFbz9NvzTPyVdJ8cc464Ta15uiZv10N11cv75SYC768Sa\nnUPcLNWz62TmTLe8rRiybM+2p6RFkn4v6SlJ56avj5C0QNIKSfO7t3AzKxp3nViRZekTfxf4h4jY\nDzgUOFvSvkAHsDAixgGLgIsaV6ZZ/fWcsPP880l4f/vbMHRo3pWZZdef3e7vBH6cPo7osdt9OSL2\nrXC+t2ezpvPcc3DuubBqFfzkJ255W/Op2273vd70Y8D+wO+AURHRBRARq4GR1ZdpNrB6dp14wo61\ngsw3NiXtDNwOnBcRGyT1bl5vtbnd2dm55bhUKlEqlaqr0qxGPUedeMKONaNyuUy5XK76ukzdKZKG\nAHcB90TEjPS15UCpR3fKfRExvsK17k6xXLnrxIqo3t0p1wHPdAd4ah5wenp8GjC3qgrNGsxdJ9YO\n+myJS5oILAaeIukyCeBi4BHgNmA0sAqYGhHrK1zvlrgNqN5dJ9//vrtOrHiytsSrHp3Sj0Ic4jZg\nurtOXnwRfvxjt7ytuBoyOsWsWfXuOnn8cQe4tQeHuBVazwk7K1d6wo61H6+dYoXVs+vEa51Yu3JL\n3ArHXSdm73GIW2Fs3gyzZ7vrxKwnd6dY09u4EW66Ca68EoYNc9eJWU8OcWtab74J11wD06fDX/0V\nXH01lEqgPgddmbUPh7g1nddfhx/+EH72s2R971//GiZMyLsqs+bkPnFrGitXwllnwb77wtq18PDD\ncMstDnCzbXGIW+4efxymTYODDoIRI2D5cvjpT2Hs2LwrM2t+DnHLRQSUy3D88XDiiXDAAUlL/LLL\nYNSovKszKw73iduA2rwZ5s6Fyy+H9evhgguS59tvn3dlZsXkELcB0XuYYEcHTJkCgwfnXZlZsTnE\nraHefBN+/nP4wQ88TNCsERzi1hBdXckwwZ//3MMEzRrJNzatrrqHCY4fD+vWeZigWaP1GeKSrpXU\nJenJHq+NkLRA0gpJ8yUNb2yZ1uw8TNAsH1la4jOB43q91gEsjIhxwCLgonoXZs3PwwTN8pd1t/sx\nwK8j4pPp82eBI3rsdF+OiH23cq23Z2sxlYYJnnKKhwma1VPW7dn6e2NzZER0AUTEakkj+/k+ViAb\nN8KNNyYbD3uYoFlzqNfolG02tTs7O7ccl0olSqVSnT7WBoKHCZo1XrlcplwuV31df7tTlgOlHt0p\n90XE+K1c6+6Uguo9TPCCCzzKxGyg1Hu3e6WPbvOA09Pj04C5VVVnTWv9erjhBvj852HcOK8maNbs\n+myJS7oZKAEfBrqAS4E7gdnAaGAVMDUi1m/lerfEm9z69TBvXrL12f33w+c+B1/6UhLkw4blXZ1Z\ne8raEs/UnVJjIQ7xJuTgNmtuDnH7AAe3WXE4xA1wcJsVlUO8jTm4zYrPId5mHNxmrcUh3gYc3Gat\nyyHeonoH95FHwtSpDm6zVuMQbyEObrP24xAvOAe3WXtziBeQg9vMujnEC2DdOliyJHn85jeweLGD\n28wSDvEm0zOwux+vvw777w8HHggHHwyTJjm4zSzhEM9RX4F9wAHJY599vKGCmVXmEB8g69bB0qXw\n2GPvD+wJE94Lawe2mVXLId4ADmwzGygO8Ro5sM0sTwMS4pKOB35AskPQtRFxRYVzmj7EuwN7yZL3\nQvuPf0z6sB3YZpaHem/PVukDBgE/Bo4D9gOmSdq3v+/XaJs2wZo18Ic/wFVXlbnyymQo39ixMGYM\nfPe78NprMHky3HVXEuyLF8P06XDKKTB+fGMDvD8bpA6EZqzLNWXjmrJr1rqyqGW3+4OA5yJiFYCk\nXwFTgGfrUVglmzYlE2LWrev7sXbt+59v2JAM3xsxAjZtKvPFL5aYPDkJ72ZoYZfLZUqlUr5FVNCM\ndbmmbFxTds1aVxa1hPgewEs9nr9MEuzbVGsQDx+eBHGlx4c/DHvvXfnPhg+HQen3js7O5GFmVnS1\nhHhmEya8F8RvvfVei7iWIDYzsxpubEo6BOiMiOPT5x1A9L65Kam572qamTWpho5OkTQYWAEcBbwG\nPAJMi4jl/XpDMzOrWr+7UyJik6RvAgt4b4ihA9zMbAA1fLKPmZk1TsNuE0o6XtKzkv5D0oWN+pxq\nSLpWUpekJ/OupZukPSUtkvR7SU9JOrcJatpe0sOSlqU1XZp3Td0kDZK0VNK8vGvpJukFSU+kv69H\n8q4HQNJwSbMlLU//bh2ccz37pL+fpenPN5rk7/r5kp6W9KSkmyRt1wQ1nZf+f5ctDyKi7g+Sfxz+\nAIwBhgKPA/s24rOqrOswYH/gybxr6VHTbsD+6fHOJPcZmuF3tWP6czDwO+CgvGtK6zkfuBGYl3ct\nPWpaCYzIu45eNV0PnJEeDwGG5V1Tj9oGAa8Co3OuY/f0v9126fNbgb/Luab9gCeB7dP/9xYAe23r\nmka1xLdMBIqId4DuiUC5iogHgHV519FTRKyOiMfT4w3AcpIx+LmKiLfTw+1JQiD3fjdJewKTgF/k\nXUsvooHfaqslaRhweETMBIiIdyPiv3Muq6ejgecj4qU+z2y8wcBOkoYAO5L845Kn8cDDEbExIjYB\ni4EvbuuCRv3FqzQRKPdganaSPkbyTeHhfCvZ0m2xDFgN3BsRj+ZdEzAd+A5N8A9KLwHcK+lRSX+f\ndzHAx4H/kjQz7b64RtIOeRfVw5eBW/IuIiJeBa4CXgReAdZHxMJ8q+Jp4HBJIyTtSNJoGb2tC5qm\n9dDuJO0M3A6cl7bIcxURmyNiArAncLCkT+RZj6QTga70W4vSR7OYGBGfJvkf7mxJh+VczxDg08BP\n0rreBjryLSkhaSgwGZjdBLX8OUkPwRiSrpWdJf3fPGuKiGeBK4B7gbuBZcCmbV3TqBB/Bfhoj+d7\npq9ZBelXuduBX0bE3Lzr6Sn9Gn4fcHzOpUwEJktaSdKKO1LSDTnXBEBEvJb+/CMwhwzLTzTYy8BL\nEfFY+vx2klBvBicAS9LfVd6OBlZGxNq06+Jfgc/kXBMRMTMiDoyIErAe+I9tnd+oEH8U2FvSmPRu\n78lAs4wmaLZWHMB1wDMRMSPvQgAk/YWk4enxDsAxNHBhsywi4uKI+GhE7EXy92lRRPxdnjUBSNox\n/RaFpJ2AY0m+EucmIrqAlyTtk750FPBMjiX1NI0m6EpJvQgcIulDkkTye8p9roukXdOfHwW+ANy8\nrfMbsnZKNOlEIEk3AyXgw5JeBC7tvvmTY00Tga8AT6V90AFcHBH/P8eyPgLMSpcbHgTcGhF351hP\nMxsFzEmXlxgC3BQRC3KuCeBc4Ka0+2IlcEbO9ZD28R4NfC3vWgAi4hFJt5N0WbyT/rwm36oAuEPS\nLiQ1ndXXTWlP9jEzKzDf2DQzKzCHuJlZgTnEzcwKzCFuZlZgDnEzswJziJuZFZhD3MyswBziZmYF\n9r8varwUoYrZVQAAAABJRU5ErkJggg==\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x106018c18>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "%matplotlib inline\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "p = plt.plot([i**2 for i in range(10)])\n",
    "plt.savefig('destination_path.eps', format='eps', dpi=1200)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {
    "button": false,
    "collapsed": false,
    "deletable": true,
    "new_sheet": false,
    "run_control": {
     "read_only": false
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAe8AAAHaCAYAAAApPsHTAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzt219MlPef/v/rnj+JHWnq1IEhICikmAHExSAhVj2AA8JB\ngRIgYhZ3s5LVE6MbEmP0G+VDmg+JJyRUT2zsQRNprXYaSWNCmygHdU882GpJ3ZCSgAQMQzBNyzib\nyHDP76C7k0yt/cwPGYb3zfNxds99v8Pr6nvu+5pBaiUSCQEAAHO4sj0AAAD4/4fyBgDAMJQ3AACG\nobwBADAM5Q0AgGE82R4gXX//+9/n4/F4MNtzZIrL5bJt23bsh6lEImFbluXIfG63215ZWXFkNsnZ\neydx75nOyfkSiUTkb3/7W/6fnTOmvOPxeLCvry/bY2RMf3+/q729PdtjZEw4HHZFIpFsj5ERwWDQ\n5fT3plP3Tvp9/7j3zBUMBh2bLxgMvvYLqyM/rQAA4GSUNwAAhqG8AQAwDOUNAIBhKG8AAAxDeQMA\nYBjKGwAAw1DeAAAYhvIGAMAwlDcAAIahvAEAMAzlDQCAYShvAAAMQ3kDAGAYyhsAAMNQ3gAAGIby\nBgDAMJQ3AACGobwBADAM5Q0AgGEobwAADEN5AwBgmE1X3qOjowqFQtq9e7cuX778yvmJiQm9//77\n2rJliwYHB5Ovz87OqqGhQZWVlaqqqtLHH3+8nmOn7cGDB2pubtYHH3ygTz/99JXzU1NT6u7uVk1N\njT777LPk6/Pz8+rp6dGHH36otrY2DQ8Pr+fYaZuZmdEXX3yhzz//XD/88MMr53/55Rd9/fXX+uST\nT/T48ePk69FoVCMjI7p586a+/PJL/fjjj+s5dtqc/P50+t5x75m9f6bl86zLT9kgbNvWqVOndO/e\nPRUUFKi2tlatra0KhULJa7Zv364rV67ozp07KWs9Ho8GBwdVXV2taDSqmpoaNTY2pqzNNtu2NTAw\noOvXrys3N1dHjx5VfX29SktLk9ds27ZN58+f1/3791PWejwenT17VqFQSLFYTEeOHNGBAwdS1mZb\nIpHQ999/r5aWFvl8PoXDYe3atUt+vz95zZYtW3T48GFNTU2lrHW5XDp48KACgYCWl5d1+/ZtFRUV\npazNNie/PzfD3nHvmbt/JubbVN+8Hz58qLKyMu3cuVNer1ddXV0aGRlJuSYQCKimpkYeT+rnmvz8\nfFVXV0uScnJyVF5errm5uXWbPR3j4+MqLi5WQUGBvF6vmpqaNDY2lnKN3+9XZWXlK/kCgUDyQe/z\n+VRSUqKFhYV1mz0dkUhE77zzjt5++2253W699957mp6eTrnmrbfeUm5urizLSnnd5/MpEAhIkrxe\nr/x+v168eLFeo6fFye9Pp+8d957Z+2divk1V3nNzcyoqKkoe79ixY1UPuOnpaT169Eh1dXVrOd4b\nW1hYUH5+fvI4GAyu6iEwNzeniYkJ7d27dy3He2MvXrxQTk5O8jgnJ2dVN8lvv/2m58+fKxgMruV4\nb8zJ70+n7x33Xno26v6ZmG9TlfdaiEaj6ujo0NDQUMpmO0UsFlNvb6/OnTsnn8+X7XHW3PLysr77\n7jsdPHhQXq832+OsOSe/P52+d9x7ZlvvfJuqvAsLCzUzM5M8np2dVWFhYdrr4/G4Ojo6dOzYMbW2\ntmZixDeSl5en+fn55HEkElFeXl7a6+PxuHp7e9Xc3KyGhoZMjPhGtm7dqmg0mjyORqPaunVr2utt\n29a3336r3bt3q6SkJBMjvhEnvz+dvnfce39to++fifk2VXnX1tZqcnJST58+1cuXL3Xz5k21tLS8\n9vpEIpFyfPz4cVVUVOjMmTOZHnVV9uzZo5mZGT179kzLy8saHR1VfX192usvXbqk0tJSdXd3Z3DK\n1cvLy9Ovv/6qpaUlraysaHJyUrt27Xrt9X/cv7GxMfn9/g33K8n/4+T3p9P3jnsvlWn7Z2K+TfXX\n5m63W1evXlVjY6Ns21ZPT4/Ky8t17do1WZalEydOKBKJaP/+/VpaWpLL5dLQ0JCePHmix48fa3h4\nWFVVVdq3b58sy9LAwICampqyHSvJ7XbrwoULOnnypGzbVltbm0pLS3Xr1i1ZlqXOzk4tLi6qq6tL\nsVhMlmXpxo0bGhkZ0cTEhO7evauysjJ1dnbKsiydPn1ahw4dynasJJfLpcOHD+ubb76RJIVCIfn9\nfv3000+yLEsVFRWKxWL66quvtLy8LMuyND4+rq6uLi0uLurnn3/Wu+++q9u3b0uS6urqVFxcnM1I\nKZz8/twMe8e9Z+7+mZjP+uMniI2qv78/0dfXl+0xMqa/v1/t7e3ZHiNjwuGwIpFItsfIiGAwKKe/\nN526d9Lv+8e9Z65gMOjYfP/7bLH+7Nym+rU5AABOQHkDAGAYyhsAAMNQ3gAAGIbyBgDAMJQ3AACG\n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\nI2Ocns/p9x77Zy6Xy2VfvHjR/WfnPOs9zGrF43FXX19ftsfImP7+frW3t2d7jIwJh8Ny6v719/cr\nEolke4yMCQaDjs/n9HuP/TNTOBx+7RdWx36TBQDAqShvAAAMQ3kDAGAYyhsAAMNQ3gAAGIbyBgDA\nMJQ3AACGobwBADAM5Q0AgGEobwAADEN5AwBgGMobAADDUN4AABiG8gYAwDCUNwAAhqG8AQAwDOUN\nAIBhKG8AAAxDeQMAYBjKGwAAw1DeAAAYhvIGAMAwm668R0dHFQqFtHv3bl2+fPmV8xMTE3r//fe1\nZcsWDQ4OJl+fnZ1VQ0ODKisrVVVVpY8//ng9x07bgwcP1NzcrA8++ECffvrpK+enpqbU3d2tmpoa\nffbZZ8nX5+fn1dPTow8//FBtbW0aHh5ez7HT5vT9m5mZ0RdffKHPP/9cP/zwwyvnf/nlF3399df6\n5JNP9Pjx4+Tr0WhUIyMjunnzpr788kv9+OOP6zl2WpycTXL+vcf+baz986zLT9kgbNvWqVOndO/e\nPRUUFKi2tlatra0KhULJa7Zv364rV67ozp07KWs9Ho8GBwdVXV2taDSqmpoaNTY2pqzNNtu2NTAw\noOvXrys3N1dHjx5VfX29SktLk9ds27ZN58+f1/3791PWejwenT17VqFQSLFYTEeOHNGBAwdS1mab\n0/cvkUjo+++/V0tLi3w+n8LhsHbt2iW/35+8ZsuWLTp8+LCmpqZS1rpcLh08eFCBQEDLy8u6ffu2\nioqKUtZmk5OzSc6/99i/jbd/m+qb98OHD1VWVqadO3fK6/Wqq6tLIyMjKdcEAgHV1NTI40n9XJOf\nn6/q6mpJUk5OjsrLyzU3N7dus6djfHxcxcXFKigokNfrVVNTk8bGxlKu8fv9qqysfCVfIBBIFpnP\n51NJSYkWFhbWbfZ0OH3/IpGI3nnnHb399ttyu9167733ND09nXLNW2+9pdzcXFmWlfK6z+dTIBCQ\nJHm9Xvn9fr148WK9Rv+HnJxNcv69x/5tvP3bVOU9NzenoqKi5PGOHTtW9QCfnp7Wo0ePVFdXt5bj\nvbGFhQXl5+cnj4PB4KreRHNzc5qYmNDevXvXcrw35vT9e/HihXJycpLHOTk5q3rI/fbbb3r+/LmC\nweBajvdGnJxNcv69x/6lZz33b1OV91qIRqPq6OjQ0NBQypvZKWKxmHp7e3Xu3Dn5fL5sj7PmnL5/\ny8vL+u6773Tw4EF5vd5sj7OmnJxNcv69x/6trU1V3oWFhZqZmUkez87OqrCwMO318XhcHR0dOnbs\nmFpbWzMx4hvJy8vT/Px88jgSiSgvLy/t9fF4XL29vWpublZDQ0MmRnwjTt+/rVu3KhqNJo+j0ai2\nbt2a9nrbtvXtt99q9+7dKikpycSIq+bkbJLz7z32769lY/82VXnX1tZqcnJST58+1cuXL3Xz5k21\ntLS89vpEIpFyfPz4cVVUVOjMmTOZHnVV9uzZo5mZGT179kzLy8saHR1VfX192usvXbqk0tJSdXd3\nZ3DK1XP6/uXl5enXX3/V0tKSVlZWNDk5qV27dr32+j/mGxsbk9/v33C/cpWcnU1y/r3H/v21bOzf\npvprc7fbratXr6qxsVG2baunp0fl5eW6du2aLMvSiRMnFIlEtH//fi0tLcnlcmloaEhPnjzR48eP\nNTw8rKqqKu3bt0+WZWlgYEBNTU3ZjpXkdrt14cIFnTx5UrZtq62tTaWlpbp165Ysy1JnZ6cWFxfV\n1dWlWCwmy7J048YNjYyMaGJiQnfv3lVZWZk6OztlWZZOnz6tQ4cOZTtWktP3z+Vy6fDhw/rmm28k\nSaFQSH6/Xz/99JMsy1JFRYVisZi++uorLS8vy7IsjY+Pq6urS4uLi/r555/17rvv6vbt25Kkuro6\nFRcXZzNSkpOzSc6/99i/jbd/1h8/IW1U/f39ib6+vmyPkTH9/f1qb2/P9hgZEw6H5dT96+/vVyQS\nyfYYGRMMBh2fz+n3Hvtnpv99blp/dm5T/docAAAnoLwBADAM5Q0AgGEobwAADEN5AwBgGMobAADD\nUN4AABiG8gYAwDCUNwAAhqG8AQAwDOUNAIBhKG8AAAxDeQMAYBjKGwAAw1DeAAAYhvIGAMAwlDcA\nAIahvAEAMAzlDQCAYShvAAAMQ3kDAGAYyhsAAMNQ3gAAGMZKJBLZniEtf/vb31Ysy3Lshw23262V\nlZVsj5ExLpdLtm1ne4yMcHI2SUokErIsK9tjZIzT98/j8Sgej2d7jIxx8v65XC774sWL7j8751nv\nYVbLsixXJBLJ9hgZEwwG1dfXl+0xMqa/v1/t7e3ZHiMjwuGwY7NJv+dz+r3n9P3j2WKmcDj82i+s\njv0mCwCAU1HeAAAYhvIGAMAwlDcAAIahvAEAMAzlDQCAYShvAAAMQ3kDAGAYyhsAAMNQ3gAAGIby\nBgDAMJQ3AACGobwBADAM5Q0AgGEobwAADEN5AwBgGMobAADDUN4AABiG8gYAwDCUNwAAhqG8AQAw\nzKYr75mZGX3xxRf6/PPP9cMPP7xy/pdfftHXX3+tTz75RI8fP06+Ho1GNTIyops3b+rLL7/Ujz/+\nuJ5jp210dFShUEi7d+/W5cuXXzk/MTGh999/X1u2bNHg4GDy9dnZWTU0NKiyslJVVVX6+OOP13Ps\ntD148EDNzc364IMP9Omnn75yfmpqSt3d3aqpqdFnn32WfH1+fl49PT368MMP1dbWpuHh4fUcO21O\nzuf0e8/JeyfxbNlo++dZl5+yQSQSCX3//fdqaWmRz+dTOBzWrl275Pf7k9ds2bJFhw8f1tTUVMpa\nl8ulgwcPKhAIaHl5Wbdv31ZRUVHK2myzbVunTp3SvXv3VFBQoNraWrW2tioUCiWv2b59u65cuaI7\nd+6krPV4PBocHFR1dbWi0ahqamrU2NiYsjbbbNvWwMCArl+/rtzcXB09elT19fUqLS1NXrNt2zad\nP39e9+/fT1nr8Xh09uxZhUIhxWIxHTlyRAcOHEhZm21OzrcZ7j2n7p3Es0XaePu3qb55RyIRvfPO\nO3r77bfldrv13nvvaXp6OuWat956S7m5ubIsK+V1n8+nQCAgSfJ6vfL7/Xrx4sV6jZ6Whw8fqqys\nTDt37pTX61VXV5dGRkZSrgkEAqqpqZHHk/q5LT8/X9XV1ZKknJwclZeXa25ubt1mT8f4+LiKi4tV\nUFAgr9erpqYmjY2NpVzj9/tVWVn5Sr5AIJB8WPh8PpWUlGhhYWHdZk+Hk/M5/d5z8t5JPFukjbd/\nm6q8X7x4oZycnORxTk7Oqh4Cv/32m54/f65gMLiW472xubk5FRUVJY937Nixqptkenpajx49Ul1d\n3VqO98YWFhaUn5+fPA4Gg6u6Sebm5jQxMaG9e/eu5XhvzMn5nH7vOXnvJJ4t6VrP/dtU5b0WlpeX\n9d133+ngwYPyer3ZHmfNRaNRdXR0aGhoKOVh6xSxWEy9vb06d+6cfD5ftsdZc07O5/R7z8l7J/Fs\nWWubqry3bt2qaDSaPI5Go9q6dWva623b1rfffqvdu3erpKQkEyO+kcLCQs3MzCSPZ2dnVVhYmPb6\neDyujo4OHTt2TK2trZkY8Y3k5eVpfn4+eRyJRJSXl5f2+ng8rt7eXjU3N6uhoSETI74RJ+dz+r3n\n5L2TeLb8I9nYv01V3nl5efr111+1tLSklZUVTU5OateuXa+9PpFIpByPjY3J7/dvuF9p/Z/a2lpN\nTk7q6dOnevnypW7evKmWlpbXXv/HfMePH1dFRYXOnDmT6VFXZc+ePZqZmdGzZ8+0vLys0dFR1dfX\np73+0qVLKi0tVXd3dwanXD0n53P6vefkvZN4tvwj2di/TfXX5i6XS4cPH9Y333wjSQqFQvL7/frp\np59kWZYqKioUi8X01VdfaXl5WZZlaXx8XF1dXVpcXNTPP/+sd999V7dv35Yk1dXVqbi4OJuRUrjd\nbl29elWNjY2ybVs9PT0qLy/XtWvXZFmWTpw4oUgkov3792tpaUkul0tDQ0N68uSJHj9+rOHhYVVV\nVWnfvn2yLEsDAwNqamrKdqwkt9utCxcu6OTJk7JtW21tbSotLdWtW7dkWZY6Ozu1uLiorq4uxWIx\nWZalGzduaGRkRBMTE7p7967KysrU2dkpy7J0+vRpHTp0KNuxkpycbzPce07dO4lny0bcP+uPn5A2\nqv7+/kQkEsn2GBkTDAbV19eX7TEypr+/X+3t7dkeIyPC4bBjs0m/53P6vef0/ePZYqb/3Tvrz85t\nql+bAwDgBJQ3AACGobwBADAM5Q0AgGEobwAADEN5AwBgGMobAADDUN4AABiG8gYAwDCUNwAAhqG8\nAQAwDOUNAIBhKG8AAAxDeQMAYBjKGwAAw1DeAAAYhvIGAMAwlDcAAIahvAEAMAzlDQCAYShvAAAM\nQ3kDAGAYyhsAAMNQ3gAAGMZKJBLZniEtH3300Ypt2479sOHxeBSPx7M9RsYkEglZlpXtMTLC7XZr\nZWUl22NkjJP3TpJcLpds2872GBlDPnO5XC774sWL7j8751nvYVbLtm1Xe3t7tsfImHA4rL6+vmyP\nkTH9/f2KRCLZHiMjgsEge2ewYDAopz9byGemcDj82i+sjv0mCwCAU1HeAAAYhvIGAMAwlDcAAIah\nvAEAMAzlDQCAYShvAAAMQ3kDAGAYyhsAAMNQ3gAAGIbyBgDAMJQ3AACGobwBADAM5Q0AgGEobwAA\nDEN5AwBgGMobAADDUN4AABiG8gYAwDCUNwAAhqG8AQAwzKYr7wcPHqi5uVkffPCBPv3001fOT01N\nqbu7WzU1Nfrss8+Sr8/Pz6unp0cffvih2traNDw8vJ5jp210dFShUEi7d+/W5cuXXzk/MTGh999/\nX1u2bNHg4GDy9dnZWTU0NKiyslJVVVX6+OOP13PstM3MzOiLL77Q559/rh9++OGV87/88ou+/vpr\nffLJJ3r8+HHy9Wg0qpGREd28eVNffvmlfvzxx/UcO21O3j+n753Tny3k21j5POvyUzYI27Y1MDCg\n69evKzc3V0ePHlV9fb1KS0uT12zbtk3nz5/X/fv3U9Z6PB6dPXtWoVBIsVhMR44c0YEDB1LWZptt\n2zp16pTu3bungoIC1dbWqrW1VaFQKHnN9u3bdeXKFd25cydlrcfj0eDgoKqrqxWNRlVTU6PGxsaU\ntdmWSCT0/fffq6WlRT6fT+FwWLt27ZLf709es2XLFh0+fFhTU1Mpa10ulw4ePKhAIKDl5WXdvn1b\nRUVFKWuzzcn7txn2zunPFvJtrHyb6pv3+Pi4iouLVVBQIK/Xq6amJo2NjaVc4/f7VVlZKY8n9XNN\nIBBIPgh9Pp9KSkq0sLCwbrOn4+HDhyorK9POnTvl9XrV1dWlkZGRlGsCgYBqampeyZefn6/q6mpJ\nUk5OjsrLyzU3N7dus6cjEononXfe0dtvvy2326333ntP09PTKde89dZbys3NlWVZKa/7fD4FAgFJ\nktfrld/v14sXL9Zr9LQ4ef+cvndOf7aQb+Pl21TlvbCwoPz8/ORxMBhc1X/kubk5TUxMaO/evWs5\n3hubm5tTUVFR8njHjh2reoBPT0/r0aNHqqurW8vx3tiLFy+Uk5OTPM7JyVnVQ/y3337T8+fPFQwG\n13K8N+bk/XP63jn92UK+9Kxnvk1V3mshFoupt7dX586dk8/ny/Y4ay4ajaqjo0NDQ0MpD1unWF5e\n1nfffaeDBw/K6/Vme5w15+T9c/reOf3ZQr61tanKOy8vT/Pz88njSCSivLy8tNfH43H19vaqublZ\nDQ0NmRjxjRQWFmpmZiZ5PDs7q8LCwrTXx+NxdXR06NixY2ptbc3EiG9k69atikajyeNoNKqtW7em\nvd62bX377bfavXu3SkpKMjHiG3Hy/jl975z+bCHfX8tGvk1V3nv27NHMzIyePXum5eVljY6Oqr6+\nPu31ly5dUmlpqbq7uzM45erV1tZqcnJST58+1cuXL3Xz5k21tLS89vpEIpFyfPz4cVVUVOjMmTOZ\nHnVV8vLy9Ouvv2ppaUkrKyuanJzUrl27Xnv9H/ONjY3J7/dvuF/Z/R8n75/T987pzxby/bVs5NtU\nf23udrt14cIFnTx5UrZtq62tTaWlpbp165Ysy1JnZ6cWFxfV1dWlWCwmy7J048YNjYyMaGJiQnfv\n3lVZWZl/FFNyAAAUQ0lEQVQ6OztlWZZOnz6tQ4cOZTtWktvt1tWrV9XY2CjbttXT06Py8nJdu3ZN\nlmXpxIkTikQi2r9/v5aWluRyuTQ0NKQnT57o8ePHGh4eVlVVlfbt2yfLsjQwMKCmpqZsx0pyuVw6\nfPiwvvnmG0lSKBSS3+/XTz/9JMuyVFFRoVgspq+++krLy8uyLEvj4+Pq6urS4uKifv75Z7377ru6\nffu2JKmurk7FxcXZjJTCyfu3GfbO6c8W8m2sfNYfP+FuVP39/Yn29vZsj5Ex4XBYfX192R4jY/r7\n+xWJRLI9RkYEg0H2zmDBYFBOf7aQz0z/2wvWn53bVL82BwDACShvAAAMQ3kDAGAYyhsAAMNQ3gAA\nGIbyBgDAMJQ3AACGobwBADAM5Q0AgGEobwAADEN5AwBgGMobAADDUN4AABiG8gYAwDCUNwAAhqG8\nAQAwDOUNAIBhKG8AAAxDeQMAYBjKGwAAw1DeAAAYhvIGAMAwlDcAAIaxEolEtmdIy0cffbRi27Zj\nP2x4PB7F4/Fsj5ExLpdLtm1ne4yMSCQSsiwr22NkDPnM5vR8Tn62uFwu++LFi+4/O+dZ72FWy7Zt\nV3t7e7bHyJhwOKy+vr5sj5Ex/f39cur+hcNhRSKRbI+RMcFgkHwG2wz5HPxsee0XVsd+kwUAwKko\nbwAADEN5AwBgGMobAADDUN4AABiG8gYAwDCUNwAAhqG8AQAwDOUNAIBhKG8AAAxDeQMAYBjKGwAA\nw1DeAAAYhvIGAMAwlDcAAIahvAEAMAzlDQCAYShvAAAMQ3kDAGAYyhsAAMNQ3gAAGIbyBgDAMJ5s\nD7DeHjx4oMuXLyuRSKitrU09PT0p56empnTx4kX993//t06fPq1//dd/lSTNz8/r//2//6fnz5/L\nsix1dHTon//5n7MR4S+Njo7qP/7jP2Tbtnp6enTu3LmU8xMTE/q3f/s3/dd//ZcGBgbU29srSZqd\nndW//Mu/KBKJyOVy6d///d91+vTpbET4S07fv5mZGf3nf/6nEomEysvLtW/fvpTzv/zyi8bGxrS4\nuKi6ujr90z/9kyQpGo3q3r17+p//+R9ZlqXy8nLt3bs3GxFey8nZJPKZns+0Z8umKm/btjUwMKDr\n168rNzdXR48eVX19vUpLS5PXbNu2TefPn9f9+/dT1no8Hp09e1ahUEixWExHjhzRgQMHUtZmm23b\nOnXqlO7du6eCggLV1taqtbVVoVAoec327dt15coV3blzJ2Wtx+PR4OCgqqurFY1GVVNTo8bGxpS1\n2eb0/UskEvr+++/V0tIin8+ncDisXbt2ye/3J6/ZsmWLDh8+rKmpqZS1LpdLBw8eVCAQ0PLysm7f\nvq2ioqKUtdnk5GwS+SSz85n4bNlUvzYfHx9XcXGxCgoK5PV61dTUpLGxsZRr/H6/Kisr5fGkfq4J\nBALJIvP5fCopKdHCwsK6zZ6Ohw8fqqysTDt37pTX61VXV5dGRkZSrgkEAqqpqXklX35+vqqrqyVJ\nOTk5Ki8v19zc3LrNng6n718kEtE777yjt99+W263W++9956mp6dTrnnrrbeUm5sry7JSXvf5fAoE\nApIkr9crv9+vFy9erNfo/5CTs0nkk8zOZ+KzZVOV98LCgvLz85PHwWBwVf+R5+bmNDExseF+9TM3\nN6eioqLk8Y4dO1ZVwNPT03r06JHq6urWcrw35vT9e/HihXJycpLHOTk5q3rI/fbbb3r+/LmCweBa\njvdGnJxNIl+6Nmo+E58tm6q810IsFlNvb6/OnTsnn8+X7XHWXDQaVUdHh4aGhlJuVqdw+v4tLy/r\nu+++08GDB+X1erM9zppycjaJfKZb72fLpirvvLw8zc/PJ48jkYjy8vLSXh+Px9Xb26vm5mY1NDRk\nYsQ3UlhYqJmZmeTx7OysCgsL014fj8fV0dGhY8eOqbW1NRMjvhGn79/WrVsVjUaTx9FoVFu3bk17\nvW3b+vbbb7V7926VlJRkYsRVc3I2iXz/yEbPZ+KzZVOV9549ezQzM6Nnz55peXlZo6Ojqq+vT3v9\npUuXVFpaqu7u7gxOuXq1tbWanJzU06dP9fLlS928eVMtLS2vvT6RSKQcHz9+XBUVFTpz5kymR10V\np+9fXl6efv31Vy0tLWllZUWTk5PatWvXa6//4/6NjY3J7/dvuH8OkJydTSLfH5mWz8Rny6b6a3O3\n260LFy7o5MmTsm1bbW1tKi0t1a1bt2RZljo7O7W4uKiuri7FYjFZlqUbN25oZGREExMTunv3rsrK\nytTZ2SnLsnT69GkdOnQo27GS3G63rl69qsbGxuT/KlZeXq5r167JsiydOHFCkUhE+/fv19LSklwu\nl4aGhvTkyRM9fvxYw8PDqqqq0r59+2RZlgYGBtTU1JTtWElO3z+Xy6XDhw/rm2++kSSFQiH5/X79\n9NNPsixLFRUVisVi+uqrr7S8vCzLsjQ+Pq6uri4tLi7q559/1rvvvqvbt29Lkurq6lRcXJzNSElO\nziaRz/R8Jj5brD9+Qtqo+vv7E+3t7dkeI2PC4bD6+vqyPUbG9Pf3y6n7Fw6HFYlEsj1GxgSDQfIZ\nbDPkc/Kzpa+vz/qzc5vq1+YAADgB5Q0AgGEobwAADEN5AwBgGMobAADDUN4AABiG8gYAwDCUNwAA\nhqG8AQAwDOUNAIBhKG8AAAxDeQMAYBjKGwAAw1DeAAAYhvIGAMAwlDcAAIahvAEAMAzlDQCAYShv\nAAAMQ3kDAGAYyhsAAMNQ3gAAGIbyBgDAMFYikcj2DGn5+9//vhKPxx37YcPlcsm27WyPkTFOzufk\nbJLz8yUSCVmWle0xMsbtdmtlZSXbY2SMk9+fLpfLvnjxovvPznnWe5jVisfjrr6+vmyPkTH9/f1q\nb2/P9hgZEw6HHZvPydmkzZEvEolke4yMCQaD4tlppnA4/NovrI79JgsAgFNR3gAAGIbyBgDAMJQ3\nAACGobwBADAM5Q0AgGEobwAADEN5AwBgGMobAADDUN4AABiG8gYAwDCUNwAAhqG8AQAwDOUNAIBh\nKG8AAAxDeQMAYBjKGwAAw1DeAAAYhvIGAMAwlDcAAIahvAEAMAzlDQCAYTZdeY+OjioUCmn37t26\nfPnyK+cnJib0/vvva8uWLRocHEy+Pjs7q4aGBlVWVqqqqkoff/zxeo6dtgcPHqi5uVkffPCBPv30\n01fOT01Nqbu7WzU1Nfrss8+Sr8/Pz6unp0cffvih2traNDw8vJ5jp4185uZzcjZJmpmZ0RdffKHP\nP/9cP/zwwyvnf/nlF3399df65JNP9Pjx4+Tr0WhUIyMjunnzpr788kv9+OOP6zl22nh2bqz3p2dd\nfsoGYdu2Tp06pXv37qmgoEC1tbVqbW1VKBRKXrN9+3ZduXJFd+7cSVnr8Xg0ODio6upqRaNR1dTU\nqLGxMWVtttm2rYGBAV2/fl25ubk6evSo6uvrVVpamrxm27ZtOn/+vO7fv5+y1uPx6OzZswqFQorF\nYjpy5IgOHDiQsjbbyGduPidnk6REIqHvv/9eLS0t8vl8CofD2rVrl/x+f/KaLVu26PDhw5qamkpZ\n63K5dPDgQQUCAS0vL+v27dsqKipKWZttPDs33vtzU33zfvjwocrKyrRz5055vV51dXVpZGQk5ZpA\nIKCamhp5PKmfa/Lz81VdXS1JysnJUXl5uebm5tZt9nSMj4+ruLhYBQUF8nq9ampq0tjYWMo1fr9f\nlZWVr+QLBALJm8nn86mkpEQLCwvrNns6yGduPidnk6RIJKJ33nlHb7/9ttxut9577z1NT0+nXPPW\nW28pNzdXlmWlvO7z+RQIBCRJXq9Xfr9fL168WK/R08Kzc+O9PzdVec/NzamoqCh5vGPHjlW9iaan\np/Xo0SPV1dWt5XhvbGFhQfn5+cnjYDC4qjfR3NycJiYmtHfv3rUc742RLz0bMZ+Ts0nSixcvlJOT\nkzzOyclZVQH/9ttvev78uYLB4FqO98Z4dqZnPd+fm6q810I0GlVHR4eGhoZSblaniMVi6u3t1blz\n5+Tz+bI9zpojn7mcnE2SlpeX9d133+ngwYPyer3ZHmfN8excW5uqvAsLCzUzM5M8np2dVWFhYdrr\n4/G4Ojo6dOzYMbW2tmZixDeSl5en+fn55HEkElFeXl7a6+PxuHp7e9Xc3KyGhoZMjPhGyPfXNnI+\nJ2eTpK1btyoajSaPo9Gotm7dmvZ627b17bffavfu3SopKcnEiG+EZ+dfy8b7c1OVd21trSYnJ/X0\n6VO9fPlSN2/eVEtLy2uvTyQSKcfHjx9XRUWFzpw5k+lRV2XPnj2amZnRs2fPtLy8rNHRUdXX16e9\n/tKlSyotLVV3d3cGp1w98v21jZzPydmk3x/+v/76q5aWlrSysqLJyUnt2rXrtdf/8dkyNjYmv9+/\n4f454P/w7Pxr2Xh/bqq/Nne73bp69aoaGxtl27Z6enpUXl6ua9euybIsnThxQpFIRPv379fS0pJc\nLpeGhob05MkTPX78WMPDw6qqqtK+fftkWZYGBgbU1NSU7VhJbrdbFy5c0MmTJ2Xbttra2lRaWqpb\nt27Jsix1dnZqcXFRXV1disVisixLN27c0MjIiCYmJnT37l2VlZWps7NTlmXp9OnTOnToULZjJZHP\n3HxOzib9/hfjhw8f1jfffCNJCoVC8vv9+umnn2RZlioqKhSLxfTVV19peXlZlmVpfHxcXV1dWlxc\n1M8//6x3331Xt2/fliTV1dWpuLg4m5FS8OzceO9P64+fkDaq/v7+RF9fX7bHyJj+/n61t7dne4yM\nCYfDjs3n5GzS5sgXiUSyPUbGBINB8ew0UzgcVl9fn/Vn5zbVr80BAHACyhsAAMNQ3gAAGIbyBgDA\nMJQ3AACGobwBADAM5Q0AgGEobwAADEN5AwBgGMobAADDUN4AABiG8gYAwDCUNwAAhqG8AQAwDOUN\nAIBhKG8AAAxDeQMAYBjKGwAAw1DeAAAYhvIGAMAwlDcAAIahvAEAMAzlDQCAYaxEIpHtGdLy0Ucf\nrdi27dgPGy6XS7ZtZ3uMjHFyPidnkySPx6N4PJ7tMTLG6ftHPnO5XC774sWL7j8751nvYVbLtm1X\ne3t7tsfImHA4LPKZycnZpN/z9fX1ZXuMjOnv73f8/pHPTOFw+LVfWB37TRYAAKeivAEAMAzlDQCA\nYShvAAAMQ3kDAGAYyhsAAMNQ3gAAGIbyBgDAMJQ3AACGobwBADAM5Q0AgGEobwAADEN5AwBgGMob\nAADDUN4AABiG8gYAwDCUNwAAhqG8AQAwDOUNAIBhKG8AAAxDeQMAYBjKGwAAw2y68n7w4IGam5v1\nwQcf6NNPP33l/NTUlLq7u1VTU6PPPvss+fr8/Lx6enr04Ycfqq2tTcPDw+s5dtrIR76Nmm90dFSh\nUEi7d+/W5cuXXzk/MTGh999/X1u2bNHg4GDy9dnZWTU0NKiyslJVVVX6+OOP13PstDl57yTybbR8\nnnX5KRuEbdsaGBjQ9evXlZubq6NHj6q+vl6lpaXJa7Zt26bz58/r/v37KWs9Ho/Onj2rUCikWCym\nI0eO6MCBAylrs4185Nuo+Wzb1qlTp3Tv3j0VFBSotrZWra2tCoVCyWu2b9+uK1eu6M6dOylrPR6P\nBgcHVV1drWg0qpqaGjU2NqaszTYn751EPmnj5dtU37zHx8dVXFysgoICeb1eNTU1aWxsLOUav9+v\nyspKeTypn2sCgUDyYeHz+VRSUqKFhYV1mz0d5COftDHzPXz4UGVlZdq5c6e8Xq+6uro0MjKSck0g\nEFBNTc0r2fLz81VdXS1JysnJUXl5uebm5tZt9nQ4ee8k8kkbL9+mKu+FhQXl5+cnj4PB4Kr+I8/N\nzWliYkJ79+5dy/HeGPnSQ771Nzc3p6KiouTxjh07VlXA09PTevTokerq6tZyvDfm5L2TyJeu9cy3\nqcp7LcRiMfX29urcuXPy+XzZHmfNkc9sTs4XjUbV0dGhoaEh5eTkZHucNefkvZPIt9Y2VXnn5eVp\nfn4+eRyJRJSXl5f2+ng8rt7eXjU3N6uhoSETI74R8v018mVPYWGhZmZmksezs7MqLCxMe308HldH\nR4eOHTum1tbWTIz4Rpy8dxL5/pFs5NtU5b1nzx7NzMzo2bNnWl5e1ujoqOrr69Nef+nSJZWWlqq7\nuzuDU64e+f4a+bKntrZWk5OTevr0qV6+fKmbN2+qpaXltdcnEomU4+PHj6uiokJnzpzJ9Kir4uS9\nk8j3j2Qj36b6a3O3260LFy7o5MmTsm1bbW1tKi0t1a1bt2RZljo7O7W4uKiuri7FYjFZlqUbN25o\nZGREExMTunv3rsrKytTZ2SnLsnT69GkdOnQo27GSyEe+jZrP7Xbr6tWramxslG3b6unpUXl5ua5d\nuybLsnTixAlFIhHt379fS0tLcrlcGhoa0pMnT/T48WMNDw+rqqpK+/btk2VZGhgYUFNTU7ZjJTl5\n7yTybcR81h8/4W5U/f39ifb29myPkTHhcFjkM5OTs0m/5+vr68v2GBnT39/v+P0jn5n+996z/uzc\npvq1OQAATkB5AwBgGMobAADDUN4AABiG8gYAwDCUNwAAhqG8AQAwDOUNAIBhKG8AAAxDeQMAYBjK\nGwAAw1DeAAAYhvIGAMAwlDcAAIahvAEAMAzlDQCAYShvAAAMQ3kDAGAYyhsAAMNQ3gAAGIbyBgDA\nMJQ3AACGobwBADCMlUgksj1DWj766KN527aD2Z4jU1wul23btmM/TDk5n5OzSZLH47Hj8bhj8zl9\n/8hnLpfLFbl48WL+n50zprwBAMDvHPlpBQAAJ6O8AQAwDOUNAIBhKG8AAAxDeQMAYBjKGwAAw1De\nAAAYhvIGAMAwlDcAAIahvAEAMAzlDQCAYShvAAAMQ3kDAGAYyhsAAMNQ3gAAGIbyBgDAMJQ3AACG\nobwBADAM5Q0AgGH+P3KmhkzzUJPZAAAAAElFTkSuQmCC\n",
       "<matplotlib.figure.Figure at 0x1060e7cc0>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import random\n",
    "# http://stackoverflow.com/questions/10194482/custom-matplotlib-plot-chess-board-like-table-with-colored-cells\n",
    "\n",
    "from matplotlib.table import Table\n",
    "\n",
    "def main():\n",
    "    grid_table(8, 8)\n",
    "    plt.axis('scaled')\n",
    "    plt.show()\n",
    "\n",
    "def grid_table(nrows, ncols):\n",
    "    fig, ax = plt.subplots()\n",
    "    ax.set_axis_off()\n",
    "    colors = ['white', 'lightgrey', 'dimgrey']\n",
    "    tb = Table(ax, bbox=[0,0,2,2])\n",
    "    for i,j in itertools.product(range(ncols), range(nrows)):\n",
    "        tb.add_cell(i, j, 2./ncols, 2./nrows, text='{:0.2f}'.format(0.1234), \n",
    "                    loc='center', facecolor=random.choice(colors), edgecolor='grey') # facecolors=\n",
    "    ax.add_table(tb)\n",
    "    #ax.plot([0, .3], [.2, .2])\n",
    "    #ax.add_line(plt.Line2D([0.3, 0.5], [0.7, 0.7], linewidth=2, color='blue'))\n",
    "    return fig\n",
    "\n",
    "main()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class defaultkeydict(collections.defaultdict):\n",
    "    \"\"\"Like defaultdict, but the default_factory is a function of the key.\n",
    "    >>> d = defaultkeydict(abs); d[-42]\n",
    "    42\n",
    "    \"\"\"\n",
    "    def __missing__(self, key):\n",
    "        self[key] = self.default_factory(key)\n",
    "        return self[key]"
   ]
  }
 ],
 "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.5.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}