├── .gitignore ├── .ipynb_checkpoints └── Wikipedia to Named Entity Recognition-checkpoint.ipynb ├── Export Categories.ipynb ├── Export Page Links.ipynb ├── MANIFEST.in ├── README.md ├── Simplify Graph.ipynb ├── Wikipedia to Named Entity Recognition.ipynb ├── resolve_redirections.py ├── setup.py └── wikipedia_ner ├── __init__.py └── parse ├── __init__.py ├── dump_result.py ├── pages ├── __init__.py ├── parsed_page.py ├── parsed_page_child.py └── parsed_page_parent.py ├── parse.py ├── parsed_page.py ├── sqlite_proto_buff ├── __init__.py └── corpus_pb2.py ├── sqlite_utils.py └── utils.py /.gitignore: -------------------------------------------------------------------------------- 1 | .ipynb_checkpoints 2 | 3 | # Compiled source # 4 | ################### 5 | *.com 6 | *.class 7 | *.dll 8 | *.exe 9 | *.o 10 | *.so 11 | 12 | # Packages # 13 | ############ 14 | # it's better to unpack these files and commit the raw source 15 | # git has its own built in compression methods 16 | *.7z 17 | *.dmg 18 | *.gz 19 | *.iso 20 | *.jar 21 | *.rar 22 | *.tar 23 | *.zip 24 | *.gem 25 | *.pem 26 | 27 | # Saves # 28 | ######### 29 | saves/* 30 | imported_saves/* 31 | pvdm_snapshots/* 32 | sentiment_data/* 33 | *.npy 34 | *.mat 35 | *.vocab 36 | *.svocab 37 | text8 38 | __pycache__/* 39 | *.pyc 40 | *.egg-info 41 | 42 | # Logs and databases # 43 | ###################### 44 | *.log 45 | *.sql 46 | *.sqlite 47 | 48 | # OS generated files # 49 | ###################### 50 | .DS_Store 51 | .DS_Store? 52 | ._* 53 | .Spotlight-V100 54 | .Trashes 55 | ehthumbs.db 56 | Thumbs.db 57 | ======= 58 | .DS_Store 59 | -------------------------------------------------------------------------------- /.ipynb_checkpoints/Wikipedia to Named Entity Recognition-checkpoint.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "name": "", 4 | "signature": "sha256:294f047f548a2291edaee643a39d0af6c12f0bc3f5015eb2bc473b52562c3282" 5 | }, 6 | "nbformat": 3, 7 | "nbformat_minor": 0, 8 | "worksheets": [ 9 | { 10 | "cells": [ 11 | { 12 | "cell_type": "code", 13 | "collapsed": false, 14 | "input": [ 15 | "%load_ext autoreload\n", 16 | "%autoreload 2\n", 17 | "from IPython.display import Image\n", 18 | "from graphviz import Digraph\n", 19 | "import wikipedia_ner.parse as wikipedia_ner" 20 | ], 21 | "language": "python", 22 | "metadata": {}, 23 | "outputs": [], 24 | "prompt_number": 1 25 | }, 26 | { 27 | "cell_type": "code", 28 | "collapsed": false, 29 | "input": [ 30 | "def update_graph(graph, dict_node, code = [], name = None):\n", 31 | " if name == None and len(dict_node.keys()) > 1:\n", 32 | " name = 'ROOT'\n", 33 | " elif name == None and len(dict_node.keys()) == 1:\n", 34 | " return update_graph(graph, dict_node[list(dict_node.keys())[0]], code, list(dict_node.keys())[0])\n", 35 | " \n", 36 | " graph.node(str(code), \"%s %r\" % (name, code))\n", 37 | " # connect to parents\n", 38 | " if len(code) > 0:\n", 39 | " graph.edge(str(code[:-1]), str(code))\n", 40 | " \n", 41 | " for i, subkey in enumerate(dict_node.keys()):\n", 42 | " update_graph(graph, dict_node[subkey], code + [i], subkey)\n", 43 | " return graph" 44 | ], 45 | "language": "python", 46 | "metadata": {}, 47 | "outputs": [], 48 | "prompt_number": 2 49 | }, 50 | { 51 | "cell_type": "markdown", 52 | "metadata": {}, 53 | "source": [ 54 | "Example tree structure visible in Wikipedia or in a taxonomy" 55 | ] 56 | }, 57 | { 58 | "cell_type": "code", 59 | "collapsed": false, 60 | "input": [ 61 | "graph = Digraph(comment='The Round Table', format='png')\n", 62 | "update_graph(graph, {\n", 63 | " \"World\": {\n", 64 | " \"News\": {\n", 65 | " \"World news\": {},\n", 66 | " \"Tech news\": {}\n", 67 | " },\n", 68 | " \"Science\" : {\n", 69 | " \"solar\": {},\n", 70 | " \"CS\":{}\n", 71 | " },\n", 72 | " \"Religion\" : {\n", 73 | " \"Temples\":{},\n", 74 | " \"Study\":{}\n", 75 | " },\n", 76 | " \"Politics\": {\n", 77 | " \"USA Politics\": {},\n", 78 | " \"French Politics\": {}\n", 79 | " }\n", 80 | " }})\n", 81 | "Image(graph.render('test-output/round-table', view=True))" 82 | ], 83 | "language": "python", 84 | "metadata": {}, 85 | "outputs": [ 86 | { 87 | "metadata": {}, 88 | "output_type": "pyout", 89 | "png": "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\nPK7OOussy8nJSc/GUGsIQAACEIAABCAAgSITQPApMip2hAAEIAABCEAAAhCAAAQgAIFIAnfccYed\nffbZdvXVV9u0adOsbt26kbvwPgkEypYta8qdNHPmTOd11b17d9u8eXMSasIpIQABCEAAAhCAAAQS\nRYAcPokizXkgAAEIQAACEIAABCAAAQhkGIE777zTiQqjR4+2iy++OMNalznN+fbbb+24446zVq1a\n2euvv24K/UaBAAQgAAEIQAACEMg8Agg+mdentAgCEIAABCAAAQhAAAIQgEDcCUyaNMkGDBhgDz30\nkA0ePDju5+MEpSMwf/58O+KII6xbt26mvqNAAAIQgAAEIAABCGQeAQSfzOtTWgQBCEAAAhCAAAQg\nAAEIQCCuBBYuXGgHHnigXXjhhTZq1Ki4nouDx47AnDlz7Nhjj7W77rrLLrvsstgdmCNBAAIQgAAE\nIAABCKQEAQSflOgGKgEBCEAAAhCAAAQgAAEIQCB9CBx11FEuH8wHH3xgFSpUSJ+KU1MbMWKE/ec/\n/7HvvvvOmjRpAhEIQAACEIAABCAAgQwigOCTQZ1JUyAAAQhAAAIQgAAEIAABCMSbwLRp0+ykk06y\njz76yDp16hTv03H8GBP4448/bL/99rODDz7Yxo0bF+OjczgIQAACEIAABCAAgWQSQPBJJn3ODQEI\nQAACEIAABCAAAQhAIM0IHH300ValShV75ZVX4lrzl156yXJycsLnkDfKvvvua6+++mp4m17UrFnT\nunfv7rYtX77cFLbML507d7YWLVr4b4u1/uWXX2z69Ok2b948e+yxx/L9rnLjaL927drZcccdl+9+\n4rV58+bw53379rVly5Y54czf2LZtWzvooIP8t3Fbjx8/3gYNGmRqY7169eJ2Hg4MAQhAAAIQgAAE\nIJBYAmUTezrOBgEIQAACEIAABCAAAQhAAALpSmDVqlX2zjvv2AUXXBD3JkiIGD58uJ1++uk2c+ZM\n69ixo9WoUcN5Fd10003h7d26dQvXpX79+k4A0ndWrFhhjRs3Dn9WnBcSZt577z279dZbbcaMGfl+\nddGiRTZmzBi79tprnXiT747eB1dddZU98sgj1qVLF1OdFQpvzz33tEMPPdQaNWpkAwcOtAkTJhR0\niJh9NmDAANt9993txRdfjNkxORAEIAABCEAAAhCAQPIJIPgkvw+oAQQgAAEIQAACEIAABCAAgbQg\nMHv2bCtbtqwde+yxca+vhJA77rjDnWfLli222267udctW7a0kSNHutc7duxwwoVfmTJlytg+++xj\n8uy5+uqrS5xfqGrVqnbaaac5ccY/drS1vIcuuugi91H58uWj7ZJrW/v27a158+bOq0Z11XnkuXTY\nYYdZgwYNcu0bzzcVK1Y0eWpJvKNAAAIQgAAEIAABCGQOAQSfzOlLWgIBCEAAAhCAAAQgAAEIQCCu\nBL7//nsXIq1y5cpxPY9/8BNPPNEaNmxoL7/8sq1bt87fbH369LE6derY5MmTbcOGDeHtejF16lQ7\n66yzcm0r6RuJOBJmCioSwFT8dUH7ptJn+++/vykcHQUCEIAABCAAAQhAIHMIIPhkTl/SEghAAAIQ\ngAAEIAABCEAAAnElIHGldu3acT1H8OASUc4991yXy+fpp58OfyRvn2bNmtm2bdvs2WefDW/XC71X\nyDK//P777zZx4kQXHu7xxx+3pUuX+h+59fr162306NHu9WuvvWa33367/fnnn7n2iXyjPEG33HKL\n21d5cFQKE4Yij5Hs9+rHjRs3JrsanB8CEIAABCAAAQhAIIYEEHxiCJNDQQACEIAABCAAAQhAAAIQ\nyGQClSpVciJLItuo3DYqEmv8Ik+jnJwc9za4/bvvvnOCVN26dd1nX375pXXt2tWFdvv73//uvIEU\n8m38+PHu83HjxjkPossvv9wefPBBu+GGG+z66683HSe/ovxByrWjkHGnnnqqE360b7oJPlu3bs0V\nDi+/9rIdAhCAAAQgAAEIQCB9CCD4pE9fUVMIQAACEIAABCAAAQhAAAJJJaB8Mz/99JOFQqGE1UN5\nciTaSLz57LPP3HmffPJJu/nmm015fubNm2dfffWV2y4h54wzznCvld9HgozCv5188skmEUgizUkn\nnWQXXHCBE3UkJulzefQoh84XX3zhwpwdcMABUdvnewDdfffdVqVKFZd/R8dKx7Jw4UJr2rRpOlad\nOkMAAhCAAAQgAAEI5EMAwScfMGyGAAQgAAEIQAACEIAABCAAgdwEunTpYgqR5gsvuT+N37uzzz7b\nHfyJJ56wnTt3upw+Em7OP/98t11ePrt27bIpU6ZY79693bYZM2aYPIEOPvjgXBU7/vjjTWKQ7xlU\nv35993mvXr3cum3btrn2D74ZOXKkdejQwapXrx7e3LlzZ/c63Tx8Zs+ebepPCgQgAAEIQAACEIBA\n5hBA8MmcvqQlEIAABCAAAQhAAAIQgAAE4kqgXbt2LndOMJ9OXE/4/w9+yimnWMWKFe2ZZ55xYo88\ne3bffXfT9qpVq5rq8+qrrzoBo3Llyu5bflg2fR4shx9+uHs7f/58t1aeIBV/7d7k80deRvvtt1+u\nT9NN6FHlP/jgA1u8eHFYHMvVIN5AAAIQgAAEIAABCKQtAQSftO06Kg4BCEAAAhCAAAQgAAEIQCDx\nBC655BLnHbNmzZqEnbxmzZp24okn2vr16+3iiy+2s846y51bYs6AAQNs7dq1bvuZZ54ZrlPt2rXd\na4kbwaKwdBUqVLBatWoFNxf6WmHflPfmo48+irpvOgk/t99+u3Xq1Mk6duwYtS1shAAEIAABCEAA\nAhBITwIIPunZb9QaAhCAAAQgAAEIQAACEIBAUggMHjzY5a+56aabEnr+0047zZ2vUqVKdsQRR4TP\n7Yd1U5i2o48+OrzdD1c2Z86c8Da9+Oabb+yPP/6wQw45JNf2wt6UL1/e9t57b/v2229t1apVhe2e\nsp+/+eabNnXqVBsxYkTK1pGKQQACEIAABCAAAQiUjACCT8m48S0IQAACEIAABCAAAQhAAAJZSaBK\nlSr2wAMP2KOPPmrTpk1LGIMePXpYtWrV7IwzzrCgN42Em1atWlmfPn2sXLly4foo/NzAgQNNgs8v\nv/wS3j537ly3/4UXXui2bdmyxa3lJRRZNm7caPo8FAq5j4YMGeLWl156qeXk5Li8QRMnTnTbdNxo\nx4g8ZjLfq37nnnuu84pSLiMKBCAAAQhAAAIQgEBmEUDwyaz+pDUQgAAEIAABCEAAAhCAAATiTqBv\n3752wQUXOPFFHjOJKMrZI1HHD+cWPOfpp59u/fv3D25yrx955BE7++yzTWLRuHHjXCg65fqZNWuW\n7bbbbu795MmT3b7yXPr444/d6+3bt9u9995r7777rgsjN3z4cFu9erVr75133mnTp083hZmTF5EE\nsDp16jhRKCgs5alMkjdIoFK/qd0PP/xwkmvD6SEAAQhAAAIQgAAE4kGgjGep9D9TpXgcnWNCAAIQ\ngAAEIAABCEAAAhCAQEYSUD4bhVD76aefnDDSpk2buLdTeYP22GOPPOfZsGGD8/4JevgEd5KnjkKx\nNW7c2Bo2bBj8qESvlc/n119/dcdSeDg9VktIKajIC+mEE06we+65J+puzZo1c4LWqFGjon5emo0K\ndyex5/3333ceT/vuu29pDsd3IQABCEAAAhCAAARSlED5FK0X1YIABCAAAQhAAAIQgAAEIACBFCCw\nadMm++GHH2z+/Pn2/fffh5eFCxe6XDiNGjWyww47zIV38/PmxKva0cQenUveNgWVGjVq2KGHHlrQ\nLsX6TPl8fOGoQoUKRf6uvGzyKzt37szvo1Jtl9glz6gvvvjCXn/9dUPsKRVOvgwBCEAAAhCAAARS\nmgCCT0p3D5WDAAQgAAEIQAACEIAABCCQGALLly/PJer4As+KFStcBSpWrOhy37Rt29b69etnWmtp\n0qSJnX/++XbkkUfa6NGj7bzzzktMhdPsLFWrVnWimMQp5SK68sorTaLZjBkzXI4hCWsKWxfLIq+m\n7t27m7yxlGuoU6dOsTw8x4IABCAAAQhAAAIQSDEChHRLsQ6hOhCAAAQgAAEIQAACEIAABOJFQKG9\nJDL4njq+qCMPnt9//92dtnbt2rb33nuHBR2JOnrftGlTyy9kmkKaDR061G677TY75ZRTnPBTq1at\neDWD4xZCQP3x0EMP2XXXXWd77rmnLVmyxH1Drzt06BBeOnbsGPZUKuSQfAwBCEAAAhCAAAQgkAYE\nEHzSoJOoIgQgAAEIQAACEIAABCAAgeIQUE6bSFFH75VvR/lnypYt6zxzfC+doMBTt27d4pwq175v\nvvmmnXvuuS7U27333munnnpqrs95E38C3333nV188cX24Ycf2s0332w33XST8/D57LPPbN68eeHl\nxx9/dLmHEIHi3yecAQIQgAAEIAABCCSKAIJPokhzHghAAAIQgAAEIAABCEAAAjEkIC+OpUuXOmHH\n99SRqKPXq1atcmeqVKmStW7d2nnrBEUdbdNn8SgKTTZkyBB79NFHrWvXrnbXXXdZ586d43Eqjhkg\n8Ntvv9mIESPs4Ycftvbt2zv+7dq1C+yR+6U8uhCBcjPhHQQgAAEIQAACEEh3Agg+6d6D1B8CEIAA\nBCAAAQhAAAIQyGgCOTk5Jm8M32PHF3UUhk25WVTklRMUdPwwbMqvU6ZMmaTwkTfJVVddZXPmzLHe\nvXvbDTfcgPATh56QuHf//fe7pXr16nbLLbe4PEol6XdEoDh0EIeEAAQgAAEIQAACCSSA4JNA2JwK\nAhCAAAQgAAEIQAACEIBAfgTWrl0bFnWCHjuLFy+2Xbt2ufw5zZo1y5NbR+KO8u6kapk+fboNHz7c\nPv30Uzv88MPtmmuusRNPPDFpQlSqcipuvfQbufvuu+2pp54yCT1XX321XXrppVa5cuXiHqrA/RGB\nCsTDhxCAAAQgAAEIQCClCCD4pFR3UBkIQAACEIAABCAAAQhAIJMJSLhZsmRJ1DBsa9ascU2vUqWK\ntWnTJizs+J47rVq1sooVK6Ytntdff90JFG+88Ya1aNHCzjnnHDv77LOtcePGadumRFdcHl0vvfSS\nPfnkk/bWW2+ZBMDLL7/cBg0aFHOhp6C2IQIVRIfPIAABCEAAAhCAQPIIIPgkjz1nhgAEIAABCEAA\nAhCAAAQylMC2bdtMIdciw7ApNNv27dtdq+vVq5cnt468dRo1apTR3i/fffedPf744zZhwgSTyHX0\n0UfbWWed5bx+UtlTKVk/1T///NNmz55tzz77rE2aNMn9fk444QQ7//zzrXv37la2bNlkVS3XeRGB\ncuHgDQQgAAEIQAACEEgKAQSfpGDnpBCAAAQgAAEIQAACEIBAJhBYvXp1HlFHIo+8eEKhkJUvX955\ns0jI8RffY6dGjRqZgKDEbfjjjz9s2rRpNnbsWJs5c6ZJ2FDIt169erlF3ivZWiSevPbaazZ16lR7\n9dVXbcOGDXbggQc6YUzimHI2pUNBBEqHXqKOEIAABCAAAQhkEgEEn0zqTdoCAQhAAAIQgAAEIAAB\nCMScwM6dO015dCTkBHPr6P26devc+apVqxYWdCTs+KJOy5YtrUKFCjGvU6Yd0Bc4Jk+e7ASOTZs2\nOaGsW7dudtRRR7mlQYMGmdbscHu2bNli7733nr3zzjtu+eSTT1zepq5du1qfPn2sd+/eLnxb+Atp\n/AIRKI07j6pDAAIQgAAEIJDyBBB8Ur6LqCAEIAABCEAAAhCAAAQgkAgCmnRXGLagqKPXCxcutJyc\nHFcFiQ6Rnjp6n8liRCLYB8+xY8cOmzt3rr399tsuT43ED3kDKe9Pp06drEOHDm5p3769paOXlNry\n7bff2rx588LL559/7toogVAh7iR0HXPMMWnjyRPsv5K8RgQqCTW+AwEIQAACEIAABPISQPDJy4Qt\nEIAABCAAAQhAAAIQgEAGE1i5cmXUMGzLli1zYdjkkaOJd99Lxxd4tJYnDyWxBCTESQB6//337dNP\nPzUJQL/99purhEQg9UubNm3CS+vWrU35kcqUKZPYikacTV5KEgslIgYX5TCSgFixYkWTaNWxY0fr\n3Lmz82Jq2LBhxFGy9y0iUPb2PS2HAAQgAAEIQKDkBBB8Ss6Ob0IAAhCAAAQgAAEIQAACKUpA+WAW\nLVoUNQzbxo0bXa1r1qwZ9taRaOALPM2bN3e5d1K0aVldrRUrVliPHj1M62HDhtnatWtziSmbN292\nfHbbbTerX7++87yS95WElL322stq1apl6nd/0ftKlSq5sHsS+vQ9rbUolJ+8ceRxpLUWCTX6/Sin\njpb169e79Zo1a0yC4fLly8OLBB8V5XHSb8oXpfQ7e+KJJ0xePZMmTbKePXu6/fhTOAFEoMIZsQcE\nIAABCEAAAtlNAMEnu/uf1kMAAhCAAAQgAAEIQCCtCWhSPTIMm3LryLNCE/Ty8mjUqFFY2PFFHQk8\n8gKhpA+Bb775xok9VatWdXl+mjZtmqfyElwWLFjgxBdfgPHXq1evduKMfjOhUCjPd0uyoXLlyk48\nqlOnjhOYJCz5ApPWEnrkhSQBKVgkSF500UU2btw4e/DBB+3iiy8OfszrYhBABCoGLHaFAAQgAAEI\nQCDjCSD4ZHwX00AIQAACEIAABCAAAQikPwFN5Efm1pGwI08PFYXHatWqVdhLR4KOH+qrSpUq6Q8g\ny1swa9Ys69u3r7Vr186mTJniPHVKimTXrl25vHS2b9+ey5NHHj0SZMqVKxf29vE9f7RW3iDfQ0jv\nS1NGjBhhQ4cOtSFDhtjIkSOTHoauNG1Jpe8iAqVSb1AXCEAAAhCAAAQSSQDBJ5G0ORcEIAABCEAA\nAhCAAAQgkC8BTbTLM0dCjhZf4JEHjyZwVWrXrp1L1PE9dpo1a2Zly5bN99h8kL4Exo8fb4MGDbJ+\n/frZ2LFjnbiXvq3JW/NMb1/eFidnCyJQcrhzVghAAAIQgAAEEksAwSexvDkbBCAAAQhAAAIQgAAE\nsp6Acp9Eijp6/9NPPznPCgk3TZo0iRqGrW7dulnPL5sAZIsHTCw9mLLp91HatiIClZYg34cABCAA\nAQhAINUIIPikWo9QHwhAAAIQgAAEIAABCGQAAeVIWbp0adhLJyjwrFq1yrWwUqVK1rp161weOwrD\npm36jJK9BLIxx01RchRl7y8icS1HBEoca84EAQhAAAIQgEDsCSD4xJ4pR4QABCAAAQhAAAIQgEDW\nEMjJybEff/wxj8eOwrBt3brVcZBXjh96zc+to/eNGzcmDFvW/FKK3lBNuPfv39/mzp1rEydOtJ49\nexb9y2m+p3JS9ejRwySKTps2zTp06JDmLcqM6iMCZUY/0goIQAACEIBANhBA8MmGXqaNEIAABCAA\nAQhAAAIQKCWBtWvX5hF15LWzePFi27Vrl0twrzw6vqCjtS/yKO8OBQJFIYDgYS5fVbYKXkX5jaTK\nPohAqdIT1AMCEIAABCAAgSABBJ8gDV5DAAIQgAAEIAABCEAgiwlIuFmyZIkTdubPn59L4FmzZo0j\nU6VKFWvTpo0TdnxBR+JOq1atrGLFillMj6aXlgAhzf6PYDaGtPu/1qfvK0Sg9O07ag4BCEAAAhDI\nFAIIPpnSk7QDAhCAAAQgAAEIQAACRSSwbds2U8g1P6+O1hJ4FJpt+/bt7ij16tXLI+pI2GnUqJGV\nKVOmiGdiNwgUjcCsWbOsb9++1q5dO5syZYrVqlWraF/M8L1GjBhhQ4cOtSFDhtjIkSP530vD/kYE\nSsNOo8oQgAAEIACBNCaA4JPGnUfVIQABCEAAAhCAAAQgUBCB1atXh0WdoMeOvHhCoZCVL1/eWrRo\nETUMW40aNQo6NJ9BIGYExo8fb4MGDbJ+/frZ2LFj8RSLIAufCCAZ8BYRKAM6kSZAAAIQgAAEUpQA\ngk+KdgzVggAEIAABCEAAAhCAQFEI7Ny50+XR8b10gl4769atc4eoVq1aVFGnZcuWVqFChaKchn0g\nEBcCeLAUDSseUEXjlM57IQKlc+9RdwhAAAIQgEDqEEDwSZ2+oCYQgAAEIAABCEAAAhDIl8CWLVtc\nGLagp45eL1y40HJyctz3GjRoEDUMm7ZTIJBKBMhRU/zeIMdR8Zml+zcQgdK9B6k/BCAAAQhAIPEE\nEHwSz5wzQgACEIAABCAAAQhAIF8CK1euDIdhC3rtLFu2zIVhk0eOPHP23nvvXF47yq8jTx4KBFKd\ngCax+/fvb3PnzrWJEydaz549U73KKVO/FStWWI8ePWzVqlU2bdo069ChQ8rUjYokhgAiUGI4cxYI\nQAACEIBAuhJA8EnXnqPeEIAABCAAAQhAAAJpS0DeDYsWLQoLO0GvnY0bN7p21axZM5eg4ws8zZs3\nd7l30rbxVDyrCSBYlL77EcxKzzDTjoAIlGk9SnsgAAEIQAACJSeA4FNydnwTAhCAAAQgAAEIQAAC\nBRLYtGmTC8MW9NTRa4Vh++OPP6xMmTLWqFGjsLDjizry1qlXr16Bx+ZDCKQbAUKSxa7HCIkXO5aZ\neiREoEztWdoFAQhAAAIQKJgAgk/BfPgUAhCAAAQgAAEIQAAChRJYvny5Bb10fIFH3gwqFStWtFat\nWuUJw9amTRurUqVKocdnBwikO4FZs2ZZ3759rV27djZlyhSrVatWujcpJeo/YsQIGzp0qA0ZMsRG\njhzpROSUqBiVSEkCiEAp2S1UCgIQgAAEIBBTAgg+McXJwSAAAQhAAAIQgAAEMpXAjh07nGeOxBxf\n0PFfb9682TW7du3aeUQdee00bdrUypUrl6loaBcECiQwfvx4GzRokPXr18/Gjh3rBNACv8CHxSIA\n32LhYucIAohAEUB4CwEIQAACEEhzAgg+ad6BVB8CEIAABCAAAQhAILYENmzYkEfQkbDz008/mcIo\nlS1b1po0aRI1DFvdunVjWxmOBoE0J4AHSmI6EA+qxHDOlrMgAmVLT9NOCEAAAhDIRAIIPpnYq7QJ\nAhCAAAQgAAEIQKBAAqFQyJYuXRo1DNuqVavcdytVqmStW7d2wk4wt4626TMKBCCQPwFyzOTPJl6f\nkCMpXmQ5rgggAvE7gAAEIAABCKQHAQSf9OgnagkBCEAAAhCAAAQgUAICOTk59uOPPzqPnWAYth9+\n+MG2bt3qjiivnLZt2+YKxSaBR148ZcqUKcFZ+QoEspuAJob79+9vc+fOtYkTJ1rPnj2zG0gCW6+8\nYT169DAJ19OmTbMOHTok8OycKtsIIAJlW4/TXghAAAIQSAcCCD7p0EvUEQIQgAAEIAABCECgQAJr\n167NI+pI4Fm8eLHt2rXL5c9p1qxZOAxbUOBR3h0KBCAQGwIIDrHhWJqjILiVhh7fLS0BRKDSEuT7\nEIAABCAAgdIRQPApHT++DQEIQAACEIAABCCQIAISbpYsWZInv878+fNtzZo1rhZVqlSxNm3a5PHY\nadWqFYniE9RPnCZ7CRBSLHX6npB6qdMX1IRwcPwGIAABCEAAAokkgOCTSNqcCwIQgAAEIAABCECg\nUALbtm0zhVyTh46/SNRRaLbt27e779erVy+PqKMwbA0bNiQMW6GE2QECsScwa9Ys69u3r7Vr186m\nTJlitWrViv1JOGKxCYwYMcKGDh1qQ4YMsZEjR3J9LDZBvhAvAngCxYssx4UABCAAgWwngOCT7b8A\n2g8BCEAAAhCAAASSRGD16tVhQSeYX0dePKFQyMqXL28tWrSIGoatRo0aSao1p4UABCIJjB8/3gYN\nGmT9+vWzsWPH4k0XCSjJ7+mfJHcApy8yAUSgIqNiRwhAAAIQgEC+BBB88kXDBxCAAAQgAAEIQAAC\npSWwc+dOl0cnKOj4Xjvr1q1zh69WrVpUUadly5ZWoUKF0laB70MAAnEkgAdJHOHG8NB4YMUQJodK\nKAFEoITi5mQQgAAEIJABBBB8MqATaQIEIAABCEAAAhBINoEtW7a4MGwKveYLOlovWLDAcnJyXPUa\nNGiQJwxb27ZtTdspEIBAehEgR0x69ZdqS46l9OszahydACJQdC5shQAEIAABCIgAgg+/AwhAAAIQ\ngAAEIACBIhP49ddfLSjq+K+XLVvmwrDJI0eeOcqnIzEnuMiThwIBCKQ/AU229u/f3+bOnWsTJ060\nnj17pn+jsqQFK1assB49etiqVats2rRp1qFDhyxpOc3MdAKIQJnew7QPAhCAAASKSgDBp6ik2A8C\nEIAABCAAAQhkCQFZ7i9atCjsqeOLOvLY2bhxo6NQs2bNXGKOL/A0b97c5d7JElQ0EwJZRwDBIP27\nHMEu/fuQFhSNACJQ0TixFwQgAAEIZBYBBJ/M6k9aAwEIQAACEIAABIpMYNOmTVHDsC1cuND++OMP\nK1OmjDVq1Cgs7Piijrx26tWrV+TzsCMEIJAZBAgJlhn9qFYQki9z+pKWFI8AIlDxeLE3BCAAAQik\nHwEEn/TrM2oMAQhAAAIQgAAEikVg+fLlUcOwyVJfpWLFitaqVSsn7ARFnTZt2liVKlWKdS52hgAE\nMpPArFmzrG/fvtauXTubMmWK1apVKzMbmmWtGjFihA0dOtSGDBliI0eOdEJ/liGguRAwRCB+BBCA\nAAQgkEkEEHwyqTdpCwQgAAEIQAACWUtgx44dJs8chV3T4odh++GHH9xEhsDUrl07T24dCTxNmza1\ncuXKZS07Gg4BCBRMYPz48TZo0CDr16+fjR071onEBX+DT9OJAP2bTr1FXRNFABEoUaQ5DwQgAAEI\nxJoAgk+siXI8CEAAAhCAAAQgEEcCGzZsyCPqSOBRzp2dO3da2bJlrUmTJlHDsNWtWzeONePQEIBA\nJhLAAyQTezVvm/DgysuELRCIJIAIFEmE9xCAAAQgkIoEEHxSsVeoEwQgAAEIQAACWU0gFArZ0qVL\nw146Qa+dVatWOTaVKlWy1q1b5wnDpm36jAIBCECgNATI8VIaeun5XXI0pWe/UevkEkAESi5/zg4B\nCEAAAnkJIPjkZcIWCEAAAhCAAAQgkBACOTk59uOPP+bx2FEYtq1bt7o6yCsnmFenbdu27r28eMqU\nKZOQenISCEAguwhoArN///42d+5cmzhxovXs2TO7AGRxa5XbrUePHibjgmnTplmHDh2ymAZNh0DJ\nCCAClYwb34IABCAAgdgQQPCJDUeOAgEIQAACEIAABPIlsHbt2jyijrx2Fi9ebLt27XL5c5o1axY1\nDJvy7lAgAAEIJIoAE/6JIp2650HwS92+oWbpSwARKH37jppDAAIQSDcCCD7p1mPUFwIQgAAEIACB\nlCQg4WbJkiVO2Jk/f34ugWfNmjWuzlWqVLE2bdrkCcPWqlUrkqCnZK9SKQhkFwFCemVXfxfUWkL6\nFUSHzyAQGwKIQLHhyFEgAAEIQCA3AQSf3Dx4BwEIQAACEIAABAoksG3bNlPINT+vjtYSeBSabfv2\n7e679erVyyPqKBRbo0aNCMNWIF0+hAAEkkVg1qxZ1rdvX2vXrp1NmTLFatWqlayqcN4UIjBixAgb\nOnSoDRkyxEaOHBn1Hqb7oAwXypUrl0I1pyoQSE8CiEDp2W/UGgIQgEAqEUDwSaXeoC4QgAAEIAAB\nCKQMgdWrV4dFnaDHjrx4QqGQlS9f3po3b54rv46fa6dGjRop0w4qAgEIQEAElIunevXq1r179zxA\nxo8fb4MGDbJ+/frZ2LFj8TjMQyi7NxT0+5g8ebITCm+77Ta7/vrrsxsUrYdAnAggAsUJLIeFAAQg\nkKEEEHwytGNpFgQgAAEIQAAChRPYuXOny6Pje+kEvXbWrVvnDlCtWrVwbh156fiiTsuWLa1ChQqF\nn4Q9IAABCCSZwNKlS03XLIWefPvtt+2www4L16goHhzhnXmRtQSieYB9+OGHduSRR9qOHTusUqVK\n7n661157ZS0jGg6BRBJABEokbc4FAQhAIL0IIPikV39RWwhAAAIQgAAESkBgy5YtLgxb0FNH4s6C\nBQssJyfHHbFBgwZRw7BpOwUCEIBAOhM47bTT7MUXXzSJ3Mol9sknn1iLFi3soosusnHjxtmDDz5o\nF198cTo3kbongEAwx9Po0aOtd+/epklnCYnyeh04cKA99thjCagJp4AABKIRQASKRoVtEIAABLKP\nAIJP9vU5LYYABCAAAQhkLIGVK1eGw7AFvXaWLVvmwrDJI0dW7r6Xjjx2/EWePBQIQAACmUbg448/\nti5duoSbpYn5v/zlLy5Xj7x9FOqtZ8+e4c95AYGCCKxYscJ69Ohhut/KE/bPP/8M716mTBn74osv\n7IADDghv4wUEIJBcAohAyeXP2SEAAQgkgwCCTzKoc04IQAACEIAABEpMQJNLixYtCgs7Qa+djRs3\nuuPWrFkzLOQEw7Ap544mOykQgAAEsoVA586d7bPPPnPePX6bdR1s0qSJ8+7p2rWrv5k1BAolsH37\ndjv88MOdsBMUe/RF/a70e3rnnXcKPQ47QAACySOACJQ89pwZAhCAQCIIIPgkgjLngAAEIAABCECg\n2AQ2bdoUNQzbwoUL7Y8//jBZEjdq1Cgs7AS9durVq1fs8/EFCEAAAplGQN47p556atRmaXL++OOP\nt5dfftnKli0bdR82QiBIQKHb+vbta6+88kouATG4j17rN3XiiSdGbuY9BCCQwgQQgVK4c6gaBCAA\ngWISQPApJjB2hwAEIAABCEAgtgSWL19uQS8d/7XCxqhUrFjRWrVqlSe/Tps2bVwuitjWhqNBAAIQ\nyAwC8sRQnh6F3gqFQlEbJaFHuXseeuihqJ+zEQJBAldccYU98MADLmdPcHvwtX5T8h774YcfTGFU\nKRCAQPoSQARK376j5hCAQHYTQPDJ7v6n9RCAAAQgAIGEENixY4fJM0d5dYK5dTQhpIdJldq1a+fJ\nrSOvnaZNm1q5cuUSUk9OAgEIQCBTCIwcOdL++c9/FuiJ4bf1vvvus8suu8x/yxoCeQj89ttvttde\nezlvsJ07d+b5PLhBos+oUaPs8ssvD27mNQQgkAEEEIEyoBNpAgQgkPEEEHwyvotpIAQgAAEIQCBx\nBDZs2JBH1JHA89NPP7nEzr7lr/LqBHPr6HXdunUTV1HOBAEIQCCDCaxatcqaNWtm27ZtK7CVEtN1\nXb7lllvs+uuvL3BfPoSAjDTGjBljjz/+uDPWUGhVhXmLVqpVq2Y///yzM+aI9jnbIACBzCGACJQ5\nfUlLIACBzCCA4JMZ/UgrIAABCEAAAgkjoNBAS5cuzRWGzffa0SSjSqVKlax169Z5RB1t02cUCEAA\nAhCIH4Hzzz/fJkyY4PKdRZ5FuXv+/PNPa968uf3jH/+wgQMHMikfCYn3BRLIycmxF154wR588EH7\n8MMPXeg25dYLFv3OLrnkErv//vuDm3kNAQhkCQFEoCzpaJoJAQikJAEEn5TsFioFAQhAAAIQSD4B\nTej8+OOPeTx2ZOG7detWV0F55UR66igMm+L3y/KXAgEIQAACiSXw5Zdf2kEHHZQnb4+8eXRd7tev\nn5uIP+KIIxJbMc6WkQSUd8/3+tmyZYv7jfleP/rNffvtt6acexQIQAACiED8BiAAAQgkhgCCT2I4\ncxYIQAACRSKgB+XVq1ebvCS09heFydIAWcumTZvCr/Ve4VpkqatF1pXB13rgloWlvyh5bvB1lSpV\nrHr16qawG5FLnTp1XKz2Pffc0/xFk/sk4C1SV6bVTmvXrs0j6shjZ/HixS5UiyZsFBrID8MWFHiU\nd4cCAQhAIBsIKBfZr7/+aitWrLCVK1e6te7Xukdv3LjRLf5r3aslmuu+HLmIle6lkUvFihXdPblG\njRpWs2ZN09p/rdwp9evXt7/85S9uXa9ePdttt92iYj/yyCPtvffec7l7dM/XuKCplwtN3jznnHOO\n6f5OgUCsCWzfvt0mTZrkvH4++eQTN97Ub6979+726quvutNpXKoxx5o1a0w5gfy1Xvvj282bN5u/\naJyr1xofB8e4/ljXX0eOd/2xrr/W/0rVqlXdovGu/1prva9Vq5YLK7vHHnu4tca7eq0xMgUCEIgv\nAf2ff/bZZzZv3rzwIoMzRRTQM2iHDh3CS8eOHa1hw4bxrVAWH13X0nXr1rk5CF2X/bmI4DXavy5r\n7S/+eMe/JmvtX7OjXZ+DcxKVK1fOMw/hX6f9a7M/F6G1rs/6nAIBCBRMAMGnYD58CgEIQCBmBDRo\nXb58uZtEX7JkiYtrrtjm/mtNIPleE/5J9SCqgY0m1TWwiVz0IKrwWMFBU/C1Jur9gZc/6PIHYHqv\nh2h/oBZc66FbAzst2s8vsgzWwKtRo0bOg0MTSFrkzaG1wsNokoqSegQ02NZvzQ+9prW/qJ9VJADK\nCtcXduSpo9etWrUyTURSIAABCGQ6gfXr1zvPxoULF5qWBQsWuLXykGlyWvdyv0g4kfCi+6IvzgTX\nu+++e1jU0cSz7s++SCPxyL8va61FE+a+cBRcq04SmjRR7hfdjzUhrftuy5Yt3XVaa40lrrvuOreb\nxgB9+vSxwYMHW7du3fyvsoZAXAhonLFs2TL75Zdf7P3337epU6faxx9/7MahGlvo96uJRO0XLPqf\n0W9Z/0e+ABMUZPzXwfGtL+T46+B41x/3BteajNQ41xeS/LW/TXXTWEj/g8Gi/1eJrRr3amncuHGu\ntca/CKhBYryGQGwI6H8TESg2LINHEVcZ9OmZMHLRtVvXwZ07d4a/orGG5iEksugZ3xdiIuckNN7x\nr8eR1+rI67M/9vHnJCTo+9dirYOLLz5pn2DR+WQAo2twtEXzEqoPBQLZTADBJ5t7n7ZDAAJxIaAH\nWU0Mfffdd+FF4S60+IMVDYSCookGKnqvh8qgBUsq5DrRRJNv3aO1Jp2CA0SJVtruT4Jp8mufffYx\niQVa+4vaRYk/AXl8ySpOvzdf0NFrbfMnMtRHQS8dX+DRb1ADewoEIACBbCCgSY8vvvgi16IJDxXd\npzVhIBHFX2RV7HvZ6DqaaCFck9a6B/veRZpc94UprXU/1kSKiiZmunTp4pYDDzzQtMhTkwKB0hKQ\nF5tCu0Yu+g364wxN8Ol/RYtEE1nl6/9J41zfe8Zf638tVYqEIN/ryF/r/015C3Vt0FpLUHzVZKgE\nrchF1w1f4E2V9lEPCKQzAQkBiEBF60F5H/vzD8G1jE/9IrFaIrYvmOi1rtm6NvueNBLjU0E40fOt\n5hskSPnzEhoDaU5C12Z/rf1UdF/RNVjzEb4Bo7+WgSMFAtlAAMEnG3qZNkIAAnElIHFHoSv8RQNR\nPTCqaHLIH2j4IoiscTWYKlu2bFzrlciD6wFfgy1faAgOLGWlrNKgQQPr1KlTeJF7PuHASt5LGuz6\ngo7WYq61BrwS3zQ4b9GiRdhbJyjwyJqWAgEIQCCbCMhi9fPPP7e5c+fau+++69a6jkrk1qRAu3bt\nwsu+++7rJkA0aZ1ORW3UPUA5U5THx180Ea/7giZwDjvsMDv88MPdWnl+0q2N6dQfmVBX/Z78MEtf\nffWV+01J8FCRmKFxRuvWrZ3YobUWCTsa52byb0se+ZpsXLRokRO+NP7VIhFME6r6f9OEo8ZeBxxw\ngLu2SPRq37698wbMhN8GbYBAKhBItgj09NNPuwgJvXv3ThoOXXPkTam5CI1ztEjwUVE0EN+wzxc8\ndJ2WyJOJwocEIRnz6FrsPxtrrWu1DGI0/6LIFRr/6HrcuXNnFy5QnqQUCGQaAQSfTOtR2gMBCMSV\ngFyPP/30U5szZ45bPvjgAxeeQg+1EnQkYuiBTovey90524vCy2iSQNz8xbcu0iSbJp+UOFqLJg4o\n/0dAk3catAYFHV/kkYu7in5j/kA+KOqIbSpZzf5fq3gFAQhAIDEENFmt3CHTp0+32bNnO2MMGRoc\neuih1rVrV3f/kedLpj/oywhFnkwSu5TbR+G2dA9Ru5Xvp2fPntajRw83AZSYnuEsqUhAltEfffSR\n+31ofPvhhx86bxeJopog0//K/vvv7wQMiaISdjJZ1ClpH0kMkvjz9ddfu/GvxsCagNVEpM/ykEMO\nMS26Dokl3tUlpc33IJCXQCJFIHnDyBtQYVNHjx7tnsny1ih2WyQm65oiwxUtuqf7z9W6JkvE8HMe\n6Xot8Z1iLrSojF80FvKNGHRdlseq7mO6DvsGMZqTgBu/mkwggOCTCb1IGyAAgbgSkAePJozeeOMN\ne+edd1xSWd9KVgMDhUzRQ7ASDlKKRkBWRxJ/NOmkCShZJclLSAPVY4891o4//nj761//mjXJchXq\nL2iJ5As8GpgqhI+KPKSCgo4v8mg7BQIQgAAE/kdAk9STJ092Io88XWTBevTRR7vE8RI3ZOGa7ZOr\nmjCSxatEsNdee83eeustF3JWEx4Sf5T35+CDD+YnleEEZO2sycI333zT/RY0FlNuKU10qf8lSMgz\nW5bQshKnlI6APKM00ShRTYKaxsEa/ymskiYYjzrqKDf21fiOAgEIxJZAPEQghVhVHhkVRVbQvfXK\nK6+0oUOHxtToU9cO3as1F/H222+7kJKK1qDrtD8XIaGHfGLF+82ovzTPo+uy5iR0P5QgJANfXYeP\nOeYYd03WOhO9oYpHi73TkQCCTzr2GnWGAATiTkAu0S+++KK9/PLLblJEXhSaMNINX4u8dyixIyBR\nQw+/s2bNchMPmnSQtY3Czmji6eSTT46rpY36etiwYXbLLbe4c8WuZbmPpDjwvoeOL+porbAgGnQG\n4w37go6/xlssN0veQQACEPAJ6Do6btw4e/bZZ11IM4VOVXiV7t27u4lU8mj4pKKvdQ+WpbAmlKZM\nmeImQBTu5bTTTrOBAwfG3WI5eq3YGg8C8rqeNm2avfLKK86ISd5fMrbRGFeCqIQHvafEn4AmFWVh\nrqgBEl+1bNq0yeX0/Nvf/mYnnniiM4JKhXye8afBGSCQeAKlFYHkPXzCCSfkqriEH+XQu+eee+zM\nM8/M9Vlx3mguQsYrulZ/8803puuARGFdq+VNJCE+k8LDF4dNPPfVPVHGqDKEkTGEBCA9n+v+2KtX\nLze2xNgynj3AsWNJAMEnljQ5FgQgkNYENJhSHF5/wkgPvBIbNJCT8EB4rMR1r1zjX3/9dSe4aQJK\ngy+F4NHAuX///jGzYJKV1NVXX+0euGXx/fe//90eeOCBUjVUD/CKE+wLO378YL338xnpQcAXcrT2\nYyprkjIVEmOWCgBfhgAEIJAAAvIKnTRpkj388MMu9JSsbAcMGOBECsVkp5ScgIwuNBaaOHGiyVBB\nVsSXXHKJnXLKKbb77ruX/MB8MykEfv75Z3v++efdIq8STRzKeElh/I477jjC6SalV/KeVONH/e/N\nnDnTeSjK6lz/bxJ/NPaVAJTp4SfzUmELBBJLoDgikLxC7rvvPucZGa2WGos88sgjTpyJ9nnkNgnA\nuvc+99xzJq8eGV5IZJDnrcR47r+RxOL/XlFJNCch4W3GjBnOK1NjotNPP92NiRT1hQKBVCWA4JOq\nPUO9IACBhBDQoE4Dq//+978utIIGVqeeeqpbFKaNknwCsjzWw6/6SR5XCkGiwe8FF1zgLB9LEppH\n1jrXXnuts9yRJ5Fy5ajIckoiUFGKrDAjw7BJ1FEYNtVR9WrUqFFY2PFFHQk89erVK8op2AcCEIAA\nBCIIKA/GQw895BZdh+XJc+GFFzqLV6xdI2CV8u2uXbuclavGSPL8UVgvGUZoUd4CSuoSUF4CCXbj\nx493oWoU6kdjp759+zoLcSYOU7fv/JopXJQmGeWFLmtzGQTpenf22Wc7oY78ST4p1hCIL4H8RKA2\nbdq4Z0FFaYhW9D+rZ8yLLrrI/v3vf5tyCEaWtWvX2oQJE+zxxx93njzKZyvjFYm8zEVE0krue81J\nKKyejI00JlLeO3mSn3/++U6Uw2gzuf3D2fMSQPDJy4QtEIBAFhBQvNb777/fxo4d6+K0alB13nnn\nOU+ekggIWYAsJZqoWOcvvPCCPfHEEy4ERuvWre2yyy6zc845p0ixdRcvXmw33XSTE480KJM1ZbBo\nAmv16tXBTS4RZtBLR6KO3issikrFihVdMuOgoCNRRw8BxPvNhZI3EIAABEpMQNfmO+64w3n06No6\nePBg53Wy1157lfiYfLHoBGTlKm8qJaXWvVgeP9ddd51h3Vp0honYU/lh1E+akJIAKk/1M844A4Eg\nEfDjeI7169c7Dy1FIlD4xYYNGzrDp0GDBoVziMTx9BwaAhCIICARSJEZFJWisKJnTuX61RhGBou6\nNsubR3MR8ubRs6QMTvU8K+8RSuoTkJe5RJ8nn3zSiUDKfXfxxRc7cW+PPfZI/QZQw6wggOCTFd1M\nIyEAAZ/Ad999Z7fddpsbXClkm6xUzz33XBdr19+HdXoQUF/Kylt5GxSe5IorrrBLL700amJhWYSP\nGDHCTVRJ0IsUeoItVqJNCYISduTBowG9iqyyIkUdvW/WrBkxlIMAeQ0BCEAghgRkQXn33Xe7iRLl\nMpPIII8e8lrEEHIxDqX+ePTRR11/6P6o/lBoVPqjGBBjvKs8sZTrQf8nyofYqVMnN6moHEyEAIsx\n7BQ4nMIGyxtAxk8SgtTP+h/cf//9U6B2VAEC2UFAHngKJVvcoudGGap8+OGHLtSb5iL0PyxBiJKe\nBJYsWWJjxoxxEWO2bt3qPH4USUSRPigQSCYBBJ9k0ufcEIBAwggoDq4m8hXa4oADDrAbbrjB+vXr\nx0R9wnogfidat26dE37uvfdeF0btxhtvtH/84x+mJN3K/TNq1Cj7z3/+48KsFST0+DWUhU67du1c\nKLagwEP4Gp8QawhAAAKJIfDqq6+667lCnui+ffnllyMsJAZ9oWeR8KPcBSNHjnR59WSAodAmlMQR\nUBghhW2TQYsMVOStrv8RLMQT1wfJPNOOHTtc/ys5vEIVy5tr2LBh7jknmfXi3BDIBgLTp093eX4L\na6ufA1jhvv0i0eexxx5z4TX9bazTn4DGRfL4ueuuu1yEEHn8KLIIcwjp37fp2gIEn3TtOeoNAQgU\niYAehu68807n1SMrC8XPPfnkk50wUKQDsFPaEFAuB4k7GmTJ4uqvf/2rC92m7X6OnsIaI+8fiYJn\nnnlmYbvyOQQgAAEIxImAPEc0ca2wq7oe6z5O7rM4wS7lYWXlLEvWp556ynlMSwSSJxYlvgRmz57t\nvDq+/PJLFwbo+uuvN+V+oGQngddee81uueUW+/jjj23gwIF26623mgyYKBCAQHwI6P9t+PDhJuFd\nRobytPQNCxWyTf9/Cu+t+YdvvvnG5QqWGH/77bfbEUccEZ9KcdSUIKDfgSKQ/Otf/3KRQvQ7kTEq\neddSonuyqhIIPlnV3TQWAtlF4LPPPnMPPXKz1aBMLtO+lU12kciu1iq3jsL0zZw50zXcT5iZX0LN\nIB0N2K+55honDAa38xoCEIAABBJD4Ouvv3aJ5SX6KGxRjx49EnNizlIqAvLGUuJiiT1KMk94qVLh\nzPfLyhdx1VVXuSTfMmCSh5XyGVIgIAJTp061IUOG2MqVK53oo2cfTT5TIACB2BKQgaFy2vl5W1u2\nbOlEd60VNl7Pn5r0v/LKK005XeSJ14EDaDwAAEAASURBVLNnz9hWgqOlNAE/JLHSCeyzzz7OiImx\nUUp3WcZVDsEn47qUBkEAAiKgJIiyOD3mmGNcrHklN6VkF4EJEya4Qba8exSiTTHPly1b5iDIwiZa\nLh9t69Wrl4uFn120aC0EIACB5BOQlfopp5xiXbp0sWeeecb23HPP5FeKGhSZwOrVq+3000+3jz76\nyCZNmkSItyKTK9qOEtXOO+88J6ppovG4444r2hfZK6sIKLqBPN5lXa5rqcbD5JLIqp8AjU0yAUWX\nGDRokL300ksm78ubb77Zdt999yTXitMni4ByAyv35Ny5c921efDgwcmqCufNMgKYe2RZh9NcCGQ6\nAbnQ6mFYyUvlMq2HY8SeTO/16O0766yzbMGCBXbkkUe6ySclM5bF+Pvvv28PPvigG4h36NAhzwBc\nbvcUCEAAAhBILIEXXnjBTjrpJDvjjDNsxowZiD2JxR+Ts0mgU9+pD9WX6lNK6QnIQ/mf//ynyxfR\nt29fUxg3xJ7Sc83UI8hbXZPMn3/+uctledBBB9lbb72Vqc2lXRBIKQKa3JfQKsOHOXPmOE87xJ6U\n6qKEV6Z58+b2xhtvuAgiClesuapgTqeEV4gTZg0BPHyypqtpKAQyn4BunHoQfvfdd51FTbdu3TK/\n0bSwUAKaKJFllcKePProo07oCX5Jn2twrgkULdWrV3eCYXAfXkMAAhCAQPwIKASnQp1cccUVLl9P\n/M7EkRNFQF7W9957rymxtXLqUUpGQGNbGbC88sorLhyMPOAoECgqgZycHLv00kvdb8fPiVbU77If\nBCBQPALffvutHX300S7Mprx76tatW7wDsHfGE3j77betX79+ThScPHmyVaxYMePbTAOTRwDBJ3ns\nOTMEIBBjAqeeeqqznnjzzTdN1mwUCAQJKNay4po/99xz1r9//+BHvIYABCAAgSQRkOCue7YegJWz\nh5I5BJTTR14+8jSQhSuleASUBFwCjyaI5LEuq3EKBEpCQDkk5CU2fvx454FXkmPwHQhAIH8CP//8\ns7tGazyjifxKlSrlvzOfZDUB5ao89thj7eCDD3a/FfKsZfXPIa6NR/CJK14ODgEIJIqAwrcNGzbM\nZs2aZV27dk3UaTlPmhGQ4KNwbh9//LHtu+++aVZ7qgsBCEAgswjIw1L3bHkxvPfee6ZQRJTMIaBc\nIoceeqjrV/Wv8uRRik7gmmuusTFjxrhwXJ06dSr6F9kTAlEIjBgxwrQovNthhx0WZQ82QQACJSGw\nfft20zW6atWq7v8LsackFLPrO/PmzXNh5y+77DKTIE+BQDwIIPjEgyrHhAAEEkrgu+++c9bBd955\np+mmSYFAfgRkLatQf1u2bHGiDxY1+ZFiOwQgAIH4E5C1ubxA5AGy3377xf+EnCHhBJQXTxbP8t46\n++yzE37+dD2h4v0ff/zxNmnSJOf9lq7toN6pRWDAgAH24Ycfmv4vq1WrllqVozYQSFMCCmGqkIkK\nDd6gQYM0bQXVTjSBCRMm2DnnnOMMnuTtQ4FArAkg+MSaKMeDAAQSTqBPnz62dOlS++STTxJqPapE\njMuXL8/VXiVlbNiwoYvdW6NGjVyfFfbml19+cbHuZfHx2GOPhXdXuJtbb73VbrnlFnfs8AcRL4q6\nX8TXiv1WceQ3b94c/p7yJvlW2YoVPnv2bPviiy+c9aAGL76oovopgaVf2rZtm5TQez/88IObWBw3\nbpydfvrpfnVYQwACEIBAAgnIu2efffZxHj7Be168qrBy5Up755133OHlaaJ7V4UKFXKdTjkAly1b\nFt6miZsjjjgi/D7ZLwq6//p1mzp1qhMKgkmik33/HTRokJvQkIEOXj5+T+W/3rlzp+2///524IEH\n2jPPPJP/jnH4JPh/Ejx8vXr1rE2bNla/fv3g5iK/zm+MO2rUKNNvdfDgwUU+lnZM1Jg3WKmC/v9+\n//1311eLFy+2li1buvFl5cqV3deT/f8XbMP69evdM8qFF17oEogHP+M1BCBQfAIK5aZr4+jRo50B\nS/GPUPpvyJtW4oFChTVq1Mg9g9eqVcvWrl1rhxxySJFPUNLrcZFPEOMdC7omb9iwwRma6N6jHJHH\nHHOMlStXztUgla7JMuyQIercuXNjTIfDQcAj4D1sUSAAAQikLQHvJh7yJg9CU6ZMSXgbvEFU6Lrr\nrgvpUvqXv/wl5FmvhoYPHx7ykhOHvIe80N///veQ5+JdpHp5D4oh76E+5D1Ih7wJplzfef755905\nvPjtubZHvinqfpHfK+5770E25E2AhRYtWhTyJgZCnteMO8SqVatCzZo1C/33v/8N/fbbbyHP2ink\nDbBC3sSF+1xt9AbFIW9CLeRNsoWuvPLK4p46Zvt7Qk/IGwDH7HgcCAIQgAAEikfAszJ39zbPQKB4\nXyzh3rpXeda3IS+XjDvvxRdfnOdI69atC91xxx3u86FDh4Z0X0ulkt/9V3WcNm1aqEOHDq7uakew\nJPv+qz7WWEl9TimcgCfahTxjmZA3KVX4zjHeQ2M2L/xeqHr16q7PPA+80COPPBK66qqrQvr9aZz6\n+uuvF+usBY1xvfC6IS83UbGOp50TNeYNViy//7/vv/8+5AlioVatWoU8AyjHrUWLFm6MrO8n+/8v\n2Aa91jWuZs2aoa1bt0Z+xHsIQKCYBLxw4aEmTZqEn3eL+fVS7+6JBaF27dqFPOEg5OUxDnmeRiEv\nmoW7Dt19993FOn5Jr8fFOkkMd87vmqw5Gl2DzzrrrNDRRx/t7qedO3cOnzmVrsnvv/++66tPP/00\nXD9eQCBWBBB8YkWS40AAAkkh4OVjCXmeNCEv/n9Szj9//nx3k5YAEiyeN47b7oUvCW4u9LXnrZRH\n8NGXJKBEFs9DJXJT1P3y7FTKDRpcXXHFFbmOogkCLx546KSTTgpv//PPP90AWAPhyNK0adOkCj7T\np093/ZNqk3mRnHgPAQhAIFMJeLkk3D0i0e3797//7a7/EiA8z6I8p5cwJKMN31ghzw5J3BDt/qvq\nLFmyxC2nnXaaa1uk4BOscrLuv40bNw6pzymFEzjzzDPdJFXhe8ZvD88a2v2WvJyH4ZN4FtMhzyvP\nGVp5YRjD24v6ItoY1/MYL7HwEG1sXNS6lGS//P7/unfv7sRkHXP16tUhz6PNsTvvvPPynCZZ/3/B\niqiOMpZ7+eWXg5t5DQEIlIBA69atQzfccEMJvhmbr3j5X5yg4UU7yXXACy64IHT11Vfn2lbYm9Jc\njws7djw+z++a/PDDD4ck+vjFn5fxvGj8TeF1KlyTJU7dfPPN4TrxAgKxIlDWe9ihQAACEEhbAor7\n37FjRytfvnxS2uBZQEY9r+fd40KZKfa63KyLWtSOaOFO9thjj1yHePvtt+3GG2/MtU1vIvfLs0Oc\nNii8nVyRvcFl+Axymx44cKB5opxzVQ5/kAIv/Di5Cj1HgQAEIACBxBP49ttvXciqRJ9Z91iFM9L9\nVvfqYKhR1UWfN23aNByONNH1K8n5PDHFtKjeqVqUx0d9TimcgEIUe0Y0he8Yxz2i5XdRqOLevXvL\nYNQ8j7Jinz3aGLdKlSpW0gTnyRrzBhuuMMxnnHGGHXDAAW5z3bp1XQhmhTP2LLeDu6bMa9VRYZX1\nO6NAAAIlJ6AQ5z/++GOxwqaV/GzRv6lnWeWo3bRpU64d/vOf/7iQbrk2FvKmNNfjQg6dsI8176Iw\nabVr1w6f088fmN+8TXjHJL049NBDTfcSCgRiTSA5M6SxbgXHgwAEspaAYtPuueeeKdd+xSPXw54G\nYH7x3IfNC8tmnleQi6/rhX5za//z/NY6hvLiVK1a1Tp16mQSe3r16uUmpcaMGePiqZ944onuXMH9\ngsfz3IRNoowXYs569OiRa5LNs/RzuYO09ixMrH379uaFvAl+vdDXkydPdvso5nywKAm34tKq3f37\n9w9+lNTXGgRq4mHNmjVJrQcnhwAEIJCtBJRLIlnJjb0QH+aFLrHLL7/cTj75ZPegrRwlftH9IbKs\nWLHCZsyY4XL8dO3a1cWD1z7KC+SLRl5YFTvyyCPNC21q27Ztc4dQ/HzlAVJuoIkTJ5ryelxyySXu\ns1jcf92B0uBPnTp18uQ9TINqJ6WKGpsEf49JqUQ+J1VeBBXPizvPHvn9j+TZMbBB/wMSjzxvmMBW\nc7kilZNC+Re8UGnmheOxvffeO5yDIXJsHPzyZ599ZsrH5YUsc2Najbd9YyrVW+NojdH1v6kcEMrt\neOqpp7rcNsHjFOW1RFaNm4PFC/NsXnjFpBmjBeuS32v9vjwPqfw+ZjsEIFAEApqHUNlrr72KsHd8\ndtH1TQamMrLU87hyCavoWdcLxZnrpBKovDD47pqnZ3YJI8Gcw/ldj71QcW6co7xAAwYMMN3P/aI8\nyi+99JJdeumlpjx9yiMoAxQJ4brOBktB8xHar6DzBI9T0GvlFfZCzOfa5auvvrITTjjB5cbL9UGK\nvNFclu5DFAjEmkDu/8BYH53jQQACEIgzAU2cSFBIteLFN3cPw7LQ1MDDyxvgElMrQbQsivXArGTV\n48ePL7DqGjhpYKXJKd/yQ4MtWRJWrFjRJYlUcsZo+/kH/uc//+kEHU0wKWmhRCMvf477WPWQACQx\n5pprrnEDNj0oF7csWLDAfUUPucHii3GyfkqlkpOT4/pHlkwUCEAAAhBIPAFZ9fuiSOLPbnbZZZe5\nCRJNUvfr18+80LD5VkMTxMOHDzd5qWjSWV4OuperSMx56qmn3OfHHXec81bQBIwXnsO8nDXuc+2n\nSRgv14fpHq4Sq/uvO1ga/NHke0k9OdKgeTGtosYmmphLtaKE4C+++KKpfl74wFzVK+h/JNeO//+N\nFzLRnnzySfNC8uTxWJcYLMFERkP6P5IgpMlJCTQavxY05tUE5+23324yhPrb3/5mXq5NN4bWxKyO\n6+V0MP1/enkunFf6Bx984JKtH3XUUeaFQoxW1QK3aeLTF5OCO2oS1Av1FtyUUq9lhCZDMgoEIFBy\nAv5zZDKv17oWS2CRmCLxWUK5X4KGmBp/aE5BcwjDhg1zwo8MPb1ccZbf9VjeMoreISMECSa6zss7\nUNdgFQnmulZ7od7t/vvvt1GjRrlxjzxqdB0OloLmIwo7T/A4xXktb1SJYddff715Yd6K89WE7qu5\nLM1pUSAQawIIPrEmyvEgAIGEEtCgQ1YbyS6ayPj555+dJ85dd91lXvx1k6Xv008/7UK6yXLQi13u\nLIkVSsGLqWtevhs3iPIHTdHaIFHISxyd66MDDzzQdAx5EekBVe+j7acvyeJGD7Ua2GmiRXXSeRV+\nTUWTVHrg06IQbF5ugwInvdyXovzxcuG470vcChZ/8LJy5crg5qS/1qSFSps2bZJeFyoAAQhAIBsJ\nyJNUExDJLPKSleeAl6TeCUDR6qKJHC8nh91zzz1O8JGBhCZNRo8e7SY2ZMEqy1Z50PrjEY1NNDmi\nsLOacPCLvHx8b9dY3X/9Y6f6WtarxfUeTvU2xat+GtPpt5MK5fnnn3chyk455RTnXX7OOec4I6bg\n+Kmw/5Fo7dCYU8eSSBpZ7rzzTpNhzuGHH+7EJYk+Kqeffrr7P8xvzCsjqscff9weffRR91uTQKv6\nv+N54WlCUmKrxsQqEnq9XJh27733Oo88jVNjFYJNHvXyEvSNq9wJU+iPJlf17CHxmgIBCJScgMJK\navHv/SU/Usm/qWdthWeUwC2vPYktErU13vCLBB0JQzJWkeCj65MMPSX86lqQ3/X4gQcecJ7YmsfQ\nHILGQRJ/fM8hCevnn3++O43EpSeeeMKJQBKeZBzgl8LmIwo7j3+c4qwlolx00UV27rnnujaqfqka\nxlKGwRo3UiAQawIIPrEmyvEgAIGEEvCSyjqhJZkDLTV4+fLlNnLkSPdgqXAR06dPN8XUVcgEhYDR\npJafN8YHJDdqPXTp4bSgIk+eaCXSojDafhJw5NUTLC+88ILJolFFgwuFgZNApUGiXKAV3qa4JT8r\nQQ0wVVItNInczWVtHZywKG6b2R8CEIAABEpOQGHRdO9OZlgh3Tc1EaF71COPPBL1fvzss886TyR5\nCsirR8uvv/7qQqAuXLjQAdBEtHKeSMTxi8KkLFmyxN566y23Sd4+Xbp0CYekitX91z9fKq/Vx+pr\n9TmlcAKauFMo3FTwYFfYRU0cSjiRt7nyQsgqPFiK8j8S3D/4OtrYddGiRe66oDGyiiYaZUkvrxm/\nRPuexBv9XwVDFHkJ1d3YVv+bynEhYymNn9UGP3SjBCQVhY8rbdG4V4ZaL7/8csp60Oi3JYFak8IU\nCECgdASOPfZYF0qtdEcp3bcVUeO1114zXYtlFPrGG284AxU/V63+5/U6OCcgUUaCj4xT/BJ5XZXH\njowP/LGP5jr07Bz0hvQ9d4OCha6pwetpYfMRRTmPX8eirnXPkPivNkqo0nrw4MFF/XrC9pPxwccf\nfxzV+CFhleBEGUugfMa2jIZBAAJZQUBJ7mShphu5b7WXjIYrvrgshaMV34MnUhSR5aKKcvqUpEQK\nPpHH0EOnEiQrVE2w6Hv+Q64e3mXhc/fdd7uH0/vuu89ZwgT3L8prhZXT+WSRGRwsanCl4j9MF+VY\n8d5HlqjKr6Ck3YUxjHddOD4EIACBbCWgSW09kMvKXvehZBVNaMsStVu3bm5SQ2GkgkX3UYUrfeih\nh4Kbc73W/V2GE/Iw0ISIBA5N1mtSWRavMk7Rfedf//pX+Huxuv+GD5jCL9TH6mv1OaVwAgo7pvA3\n8iK79tprC/9CHPfQOFuTZBrLykBJXuX/+Mc/cp2xKP8jub5QyBv9LyoMj7zR9X+iUGwSf6J5A/mH\nkiedxtOqb2TReHvx4sXO+EoefZFF1u0qQW+8yH2K+l7XMlm/y7soFYvaqGuULPP9XB+pWE/qBIF0\nISAPYIk+8h5R2PRkFnniqC7y5lE+HN0/JP7Ig0T3YIlBwRIZmSP4mcLOSoxQ+3S9KE7RNdW/nhY2\nH1Ga8xSlTvLCloenPDhl4BM5V1GUY8RzHxkqqF+Cwls8z8exs4sAHj7Z1d+0FgIZSUATKJpkkXVE\nKhYlTVTxvWr8OjZp0sSU08eP5+9vL+q6MLFCAy0ltVV83fyKBkEKnaGcQ5rQUtLcyJi7+X03uN0P\nCxG0vtTncvtWSSXBZ8SIEW7iIFVDbThg/IEABCCQ4QQUhkThNmRw4BsHJKvJmiRWSBFNBMjLNehZ\noYkLhSMrKMeP6n3xxRe7e54mFPQAr4lfxb7Xe8XI1zGDE6yxuv8mi1lRz6u+VR+rr/0wr0X9brbu\np3Gjcg5ovKLfTrKLxqoSYGRFrrGT8jgES1H/R4LfKei1JhgV+li5J+VZJI8ZiRQFCYYaE2s8rUlX\nTTAGi4yyVEo63g4eq6DXsiaX0KPQyalalMdCFvu33XZbqlaRekEgrQjIoEMitUK7KspHIouEbEWt\nCBaFmJOhia7LCmcpQUXzARqDRF67g9+LfK0xioofBj3y86K+L2w+IlbnKaw+EsJ0Dwgaphb2nXh/\nLiMF5T7SPa4g8S3e9eD4mUsAwSdz+5aWQSBrCCgefo8ePeyMM85wVoCJbLhvvVLQORXCRUUxvYPl\nm2++cRNISkJb3KIH28gH2shjyItHQozCyEROGCi3kJJly1pTg0BZTeoBUINWTXoVtyh+rwZQyoMQ\nLPPmzXPWoAqpkQpFVk7KsaTJuHg/+KdCe6kDBCAAgVQmcMMNN7gJEk1uJ6pIuJGwE1nk9SnRRhat\nGzduDH+scFKaKFHIt2DRJIo8MPyiuPi6nys0yY8//ujCt8mIQvdY5fAbOHCgv6tbx+r+m+ugKfhG\nfatJMPU1pegEFEJQxjJ9+/ZNiiAaOb6tX7++Pffcc85qW/l8fv7553Bjivo/Ev5CIS80fpURkiYt\n9X8lL34JQIUVjbclMEbmP/rss8+cWBXPHFKTJ092bJQ/I1gUNjlVigzP5H0kITGVDLFShQ/1gEBJ\nCUjs1XP9TTfdVNJDlOh7EnckwkeOaRR5ww9brudz5a9ReeaZZ3KdZ+3atfmGo6tevboLhymRWHMG\nwaIQmcGQbcHPIl8XNh8hgwKFlC/teSLPG/lenqjF9VSKPEYs3yviiPJB6r4lgxgKBOJBAMEnHlQ5\nJgQgkHACTz75pJtUUTLCrVu3Juz8mvBRCT74Rp5cD8Ka6JHgExwcKVSFrA41yeQXTTJpYin4oO0P\n4nxvGe2rB2HlEJCQo1jn+k60/YYNG+aOJcsjeUEpvu8555zjtinm7oIFC5yrt44py1vx0+CxuEX5\nDxTiQ95Cft0VH1zeRZrU8q13invcWO6v2MUSBzUBF/lAHsvzcCwIQAACECgaAQnvCocq4UQeBIko\nykeS3z1blpaHHXZYrmrogVyTJ/LY0T1OFpmqq+7dCr0VLHpol4eBH/JKYTok9ih3iPL2BUus7r/B\nYyr0lYruv6lQxEl9qz7GyKJ4PaJJMnmHKVeCPEY0OZTIEm18q7GkcjFoPNqrV6+wEFXU/5H8xrja\nHrSM18Sf8k1KnFUoN42dI70Ao415lV9Ik5sTJkwIo5LgKqFDn8niXRw1TvXzA2lHf3wdOakZPkgh\nLxQ6Sd7xqu+DDz7oFoVI1vUg2TlG/apL9FL+DgmIEhMpEIBA7Ai0bNnSNBehMUJJDCdLWhPlDtS8\nh641/jVRx5JXjsJwaoyi533dQ+R9qPCqMmyZNWuWE9L1TCyjWb/oGMHrsULCacyk0JryFpKYrrkF\n7dO4cWP3NY1vVCKvqTqWPydQ2HxEUc7jTlKEP7qO6z4lAc4vErZUdxkPpELRGE3e5BqzyZAiFeZJ\nUoELdYgDAe+fkAIBCEAgIwh4FrUhTwgJHXHEESHvQTXubZoxY0bI84wJeZdmt3iTPyEvrFzU83qD\nj5CX8DC07777hrwBYeixxx4LeQ9eIe8h1u2vz71BSMgblLljea69oVWrVoU875yQl4PHbfPyCoSm\nTZvm9vdcskPeZECoZs2aIW+CKt/9tLOXN8Dtp3p61johz0rZHUN/dB4vyWLIG5yGPKuf0GWXXRby\nHgrDn0d74Q1qQ14s3DwfeQ/VoSFDhoS8GLSuTp41b8gTmfLspw1NmzYNeRZJUT+Lx0bvYT/kTTaF\nvAFvyBuQxuMUHBMCEIAABEpIwBNTQl4y9ZDubfEq3qRF6MYbbwx5xg2hOnXqhHSP0r03snjGFCEv\nT0muzd7EScjzVA3f73U/jnav9CZe3Lgg+GW1yQufFNzkXsfy/qs6awzhhdxydfSMGkIzZ87Mc05t\nSNT9V+32Jt9D6ltKyQlobOtNrIU6duwY8rzPSn6gIn5z+fLlIS9/UMgLL+N+S56HTcgT7cLf1ljP\nMw4Kf+aFE3KfFfQ/Em2M64mubqyo/0WNTz0Rwo17dTDPWybk5Ztw2/0xttZeSJ7QypUrCxzzvvvu\nu+43rnGq6qb/BS//lqujJ/a4ca6O5RkqhTyjpJDa64my7lyegVbo008/dftG+xNt/Ot5sketq86h\na5o30ZjrUIn6/wueVM8r3sSwe55gDBwkw2sIxJaArjVeFI6QF4Iytgcu4GhedI6QJ+SGunbtGvLC\nyoW8ULJujOPlXgt5BqHhb2oMpHkL1U/LUUcdFdI2FY1dNJ8QeT3W9V5jJc056Jqmtee1G/KijLjv\neSJQyPOcdJ95oTjd9fnZZ5918w3af/jw4SFPCHf7FjQfUdh53AGi/Il2TdZ13hO3XBu9nErufuYJ\n8CHPaCDKERI3JvJPrjkqT0Bz4zVPlPI3s4ZAXAiU0VG9f0YKBCAAgYwgoDAq3bt3d3FQFdM2VUKJ\n+XBlESOXYlnFBGP5+58XZ61jySJE1j2FFW8g5Sx0dM6gFYksKmVFunr1amcVWaNGjcIO5bySlFgw\nPysZhZqTteRee+2V77Hkui2rZ4W+iXeR27nyKMgaVV5OxMiNN3GODwEIQKB4BHSPkvfpiy++6Lwa\nIr1hine00u+te6LylUSWJUuWmEKq+patkZ/rvTe57Sxqg5/JmtOb/A1uch4Nsb7/5jpBPm8Scf9V\nXkBZr8qbQBbFYkYpOQHlR9QYxhM7XEgeedqkainK/0hhdVf4XU+Icd528maXBbs82eX1o9BEhYWA\n1PSGngfkFaT95fUTiyKv/ILGv0U5RyL+//x6aDyuXD3epKt5k78unLG8nCgQgED8CIwdO9Z53Jx2\n2mkuTFm8c9fpvqDIHyq6V+gZXNeqqlWrRm2kvDc15vJzDEfdKWKjxjWKKqLrV2nak998hH+64p6n\noGuy2qln/sLqm8hr8vfff+/mP+T99Oqrr5pndOs3nTUE4kKAkG5xwcpBIQCBZBGQwKPQDRIb2rdv\nbxp0pVKRoKLk0KUVe9QmHasoYo/2lcijCaqg2KPtmmxS0cRWUcQet7P3J+g27m/z13qYLEjs0X6F\n5R/yj1WatR705aqucHoKX+FZHCH2lAYo34UABCAQJwK6NykcinLxaULVs5KN05mKdthoYo++2aRJ\nkwLFHu2j8CmRJVLs0efxuP9Gnjfa+3jff9V36kP1pfoUsSdaLxRvm0IKKgywDJqUa9HzXnECSPGO\nkpi9i/I/UlBNlPtR4q9CESlMkkIs/vWvf3WTZPptFWWSUr855a/wvKJiJvb4dS5o/OvvU9A63v9/\n/rkVelLs7rjjDpcLSWGmEHt8OqwhED8C5557rnketibDhw4dOpiuafEsvtijc+heodBt+Yk92seL\nDlKk66j29YvGNV6UkkLFE3///Nb5zUf4+5fkPPldk9XOwsQenTcR12QZISgPpH4Pyof30UcfIfb4\nnc46rgT+N9MX11NwcAhAAAKJJaCJGsWmveWWW1yM/YkTJ7oY8vFM1prYFib3bBpEeqHl3IBRgpOS\nRUabzIqspWLpemElXCx2xfstyncij1HU98od5IXQc4M45S3SZAEFAhCAAARSl4AmApT4WJO8l19+\nuXmhmdwDsh7aKf8jkMr3X1nTKjeAvDDkVUCekNj+ajVx9cQTT7g8LMoRJW+4u+66y0455ZSMEtWU\n80YW617oY/NCuDmRVTm3vJDJLh+OF14otmCLcbRU/v/zm6HxtfJXyAv/kEMOcXkrdE2lQAACiSNw\n1FFH2ZdffukMD7t06eLGNPK0K6qhZuJqmt5nSodrsnIpXXLJJeaF6TcvlK/pHhZpgJvevUDtU5kA\nId1SuXeoGwQgUGoCsqpROC/dbCVMKAxEcTxZSl0BDpBQAhKVlFhbllXy7tFkCJOFCe0CTgYBCECg\n1ASUHFgW/gr/oQTuSjhMSV0CL7/8spvQ0CTGhAkTTJNdlPgRkLh2880325gxY8zLN+Um+DPFsEWW\n0BIrZLgjj315wiksm6zm5flDWN7ovyuFQtK10ssd4phJdBUvPOyi82IrBBJFQKHF9Wyq8q9//cvO\nP//8sIdvourAeRJPwMvF7PpbhkwHH3ywu1/LS4oCgUQSQPBJJG3OBQEIJIWAJox0sx02bJh5iQPd\noEveHwg/SemOuJxUgt6tt95q8ubq3Lmzi1MuiyoKBCAAAQikJwFNastQQ2HBevbs6XK+pVpevvQk\nG7ta//DDD3b11Vfb9OnT3eSyJuoxsogd38KOpHwAN910k02ePNmFL5NRk3L9ZEroLo3ZK1SoUBiG\nrP58/fr1zhPy3nvvNeUKU7i/a6+9tsCQTlkNjMZDIAkE5Hmn51SFVlQINl23ZdSCgJ2EzojzKVes\nWGF33323E+AV4l4el6effnqcz8rhIRCdADl8onNhKwQgkEEEZHGqMCOLFi2yq666yt2Elc9G4UaU\nXJaSvgRmz57tJjf2228/58WlECeyCEXsSd8+peYQgAAEREDCgfLw6TqvBO6yjLzooou4b6fAz0Nj\nJ/WF7r3qmzlz5ri+QuxJbOco4bPGPV988YVLpq3wbgrfdeedd9pvv/2W2MrE4WyIPflD/fzzz93/\noHKCanJRzzkKfScPAoU5okAAAqlDoHr16i6f1sKFC+1vf/ubKSxn06ZNnUdeJlyrU4d08mqia7I8\nUZs1a2bPP/+8uw/LKAaxJ3l9wpnN8PDhVwABCGQdgc2bNztrOFnZaKJCyYUV9k0DsEyxiszkTpU1\n49NPP+1coxXC7cgjj3ReW+pHCgQgAAEIZB4BeeoqLIomM5cuXWpnnnmmM+CQ4EBJHAHdc0eNGuX6\nQsmh5TmtviAefeL6oKAzSYjT2FZC6e+//+4MYs4++2w3vkU8KYhcenymiWF5ssvrUSGrFepu8ODB\nNnDgQFOycwoEIJAeBH799Ve7//77XQQSzUv069fPhSLv1q0bYRjTowtdLXWflbjz3//+1+Xoadeu\nnfNMl8jDPTeNOjKDq4rgk8GdS9MgAIGCCezcudOFwXjkkUfsrbfeci7WukGfdtpp1r59+4K/zKcJ\nJZCTk2OvvfaaPfPMM6ZcARpEqZ/0oKv49RQIQAACEMh8An/++acTG+TBoFCeSuouy3bl+OHhOj79\nr7Bauu9qrPTmm2/aPvvs40JGSehRfhVK6hFQaK8XXnjBCQNvv/2285br27evaTn66KP5X0m9Lsu3\nRmvWrLGpU6e6/tT/X+XKld3ksPKAHHroofl+jw8gAIHUJ6Br9bPPPusEA0WoUAQSzUUMGDCA59sU\n7b4dO3bY66+/bs8995xNmTLF5Zo8+eST3Vj08MMPT9FaU61sJYDgk609T7shAIFcBH766ScbN26c\n8xxR6DeFxOjTp49bFB4M69VcuBLyRhZPM2bMcKKc8gPIikbePJpkUtgSQlYkpBs4CQQgAIGUI6DE\n7ro/jB492l599VXbY4893H1BhgCHHHIIFrKl7DHx1eSTJqImTZpkmnTu0aOHM7KQNzSJ4EsJOIFf\nl0ecJqZkhfzJJ5848ef444933u3qS/3vUFKLwLfffuuua9OmTbP33nvPCXTdu3d31zjlaMKbJ7X6\ni9pAIBYE5s+fbxMmTHD3XYVnbNWqlfPS7N27tx188MFEIYkF5BIeQzmYNOaU+K45Cb0/7LDDnDh3\n6qmnkruwhFz5WvwJIPjEnzFngAAE0ozAxx9/7CzpNNGxbNkyq127tpvo0IPxMcccY/Xq1UuzFqVH\ndTXB9PXXXzsLYk3gvfvuuyZrbg2ofMvUBg0apEdjqCUEIAABCCSEgMJYKSmuJrVlGNCkSRPTA7gm\nSTp37ozBRhF7QWHzNP6RxapYimuLFi1cuCiFBRNXSnoT0CSiJqxeeeUVl3dJYyx5SR933HHO80ce\nI9WqVUvvRqZh7X/55ReXq2zWrFluDKxw03Xq1HHPHieeeKJJ7MHIKQ07lipDoAQE9Dz80Ucf2Usv\nveSMHpX3R3MRuk5LrJeXJvfjEoAtxlcUBeazzz4zXZMl9Lz//vvOk0dzEjIIlkePwtpSIJDqBBB8\nUr2HqB8EIJBQAhJ4JPQoV8BXX31l9evXNz1sKXTMhx9+aAptosTRRx11lBMi5LqLCFGyLtLkkgQe\nCTtaFHZE8ck1qFWYnp49e7qH3Lp165bsBHwLAhCAAAQyloAsLP18bl9++aUpdrq8P9euXesmSjS5\nrUlTTZBowlRr7ie5fw665yo0iUKmai12SiStyQyFlJFgRslMAhJHFc545syZTmT48ccfnQX5QQcd\nZF27dnWecrIqZ2Ixtv0vkU3PF3qmkBfd3LlzTdeq3Xbbzf2/+ZO6HTt2xKI/tug5GgTSkoA8f3SP\nljGkPP4UBq558+Yu6oUECF2v27Rpk5ZtS5VKK3T8p59+6vjqmjxnzhzbuHGj7bnnnk5ok4ezxpAa\nU1IgkE4EEHzSqbeoKwQgEBcCmjRSrHOJPLNnz7YaNWq4SaMzzjjDiTp+6BKFGNPnsvbQQOCLL74w\nWYBI8OnQoYPp4cxfmFTK3VWyVlqwYIEbTGlApeXzzz83Ma1evbqLQ65wbRJ6lD+JEHq5+fEOAhCA\nAAT+R0D3D+WTkReK7i0SJi688EIX8iTISIYamiBR+A09wOt+vffee7v7uiZINFGiSZNsKgpfKxaa\nNNJaE0nlypVzLGRkoUkN5eihZB+BlStXujGuxrcSImSQo/8ZjWc1xtUib6ADDjjAhT1mnFb4b2Tr\n1q2m8GzynJPII2FaiyZs5UklQVVeVRr/KhSl8vNQIAABCORHQNcO3b8l1stYUmE6ta1mzZru+dm/\nVmstD11/DiO/42Xjdok7uh7PmzcvvHzzzTfOqFcCj8aHuibLk2q//faDYTb+SDKozQg+GdSZNAUC\nECg6AXnqyFpGIo9CW2jS6IQTTnD5YTThIUu7woqsI/UQp8GWFk1CKSyDitx85QmkiRNNMPmLvFcy\nuYijwsBoEim4aOJAwpoSPItLp06dwosmDzThRIEABCAAAQhEIyDjAN+bR8YCegi/6KKL3D1bEx2F\nFVlqaiJbIocmSfSgr8S7CtGqiRF5B2nRhLZy+KX7ZLY8aBUGRoYp/iSz2vzrr7+68Y3aLA9liV5H\nHHGEM3QpjCGfZxcB/c/5BjpaK7yNclzqt6UcMhrXtm7d2i2yLvdfy4gn28qKFSvshx9+MHlJadFr\nLRJYxUtjXxWNfZWHUv93Ggsz9s22XwrthUBsCUi80LVZIeC0aD5C1x09j8uAVWOltm3bukXXbL1u\n1qxZ2o9xikJRgruux5qP+P777534rnuZQmbK07JixYrOgEHCuxZ5tOo+RoFAJhFA8Mmk3qQtEIBA\noQQUg1Uij5IQr1u3zk106OGrX79+MUm4t3r1ajfY0gSLrIu16KFPgw4VWY7I4kYhMrQodIr/unHj\nxikfo1sDSCVvlqijRWEogq81wRRsqwaXEr30YCvPHU2mkWy20J8pO0AAAhCAgEdAExljxoyxZ555\nxj2gK2SbvHlkgVmasm3bNmewobBKEkW0aGJAk7Oyste9S8JPcNG9WwJRqljM6n4sAUeT8Lr3BhdN\ncOherAllJX7WvVeLJjQ0scF9uDS/nuz97pYtW0yW0LKO1gSaL3JoglHeQCr6H9HYVoZP/qLxrf9a\nHkPpJHTIel6CztKlS8OLjLv892q7xDEV5dnR/5sEMC0a/8qoSSLYPffcYw8//LC7vlxzzTU2ePDg\nlB/zu0bxBwIQSCsCMrDUPITGNUHjy1WrVrl2SOgIzkUE5yH+H3tnATdHdfX/S/HilDaF4u7uwTVQ\nPEjQBAgWggTnBZJCoaEEC+6hQHBI8AZ3gktwC1CsQLGW0lLK/M/3vP+z7zyT9d3Zndk95/OZZ/aZ\nnZ2585t77j33KJ8Zw81IneUHZz7CeGN6CMZl+4x+gv+Rk5hviOaeZZZZVO5jXB4+fLhGNOfhObP8\nDrxt2UfADT7Zf0feQkfAEWgQARakeAZj6Jk4caJ6u5CujY0FaNqEsIHgYcYfPrOZwQTBzAglDEah\n5EbOWNI/FNtQTiGwTDnllLqPf8ZLGS+W+EZ0E/+zZ5FKpFJywxsaww4GrPhGvn9b1KP0Qig0wxUL\nfLyGzMjjeW7trfreEXAEHAFHoFoEWMRTS++iiy5SBwrmFKJ5dtttN12wV3udWs/DQEI0KooSjD+k\nIcWIgkIXpS/E/Mq8N/vss2uNP/ZsKBLwpk1uKFaYm5Mb12IOTm546zL/JrevvvoqkHKLDeUze4w9\nzOXQNNNMowoNDFQonPFSJWJpqaWW8jRRipD/SRMB+jGGR+RteAZFmxlF2CM7GiE7Eu0+22yzabq4\n+B4+wmhiGzKvfWYfl3PhxfiGvIt8Gpd345/hYWRe25B745+pX4XcS1vje84x4n6kcTYDFntkYPgN\nA0+lmp5c97TTTgvnnHOOepcfcsgh4YADDlDZ3u7he0fAEXAE0kAAOQJDPUYg5BozjrDHcBJf3zMW\nY5w3fYR9RsZJ6iIYmzmGHJIco+1/G5+ZK+Ljsv2P3Ge6CMZc+8yesZlxGX1EfM9vjNCFMBbbmIxO\nAnkI+ZHx2TK3kK50//33V8eFgw8+OAwdOtQN7wai7zsSATf4dORr9YdyBBwBvFjI74+Rh/DdOeaY\nI+y0006aSgElSJYIAcyErbhxxT7zLF9//XVB+EE4SoswOCG04Y2IwcYEPfa9evUq/I+hDMEKZZaT\nI+AIOAKOgCPQKAIYWojmwUEDwweRtxh6SD3WTsJpA29+FCQYW8zgYnsML8zRGGnMMNSs9qJAQcFC\n2rqkoQm5hg3PVebkrEQeNevZ/TqdgwB8AQ+hVERhZ5sZVvifz/CQGWEYA9Ik+AUloRmUTMGJYtOM\nUHw2RSc8hnG3GekeyTBw+umnh7PPPlu9z4cMGRIOPPBA5fU0n9mv7Qg4Ao5AMQQwwjA+Y6BH72CG\nFdNF2JiNk6oZy81AVOx6jR7DQGOGJeQf00fYeGz/MyZj5OF4tUQkN3Ugjz32WJ0DTj311NCvX79q\nf+7nOQK5QsANPrl6Xd5YR8ARKIcAnh5jx45VI88999yjk3jfvn3VyLPuuus2ZZFW7v6t+o5FMMKW\nCV0spM1DBoHNPpO+Di/CK6+8sqjHDV430003XUGgQrDKU5qNVuHt93EEHAFHwBFIBwGiaq677jo1\n9JB/Hi95Urb1799fnQ7SuWt6V6UuUDw6h/+Zk+MbqZ0glLzMw/ENJUc8Ssi8UtNrsV/ZEcgmAvCM\nGX/YI+PDT3HvcPuMvHvuueeqvBuP+ol/xkHJjDvskX+bYbxpBD0MxWeeeWYYOXKkph466KCDAl7n\nGJ+cHAFHwBHIMgLIb/FIHPQTNiabLoL/4/oIxmSL+rHxmf/N+G5GnlbIPjgZHHXUUeGyyy4L66yz\njupMSPfm5Ah0EgJu8Omkt+nP4gh0IQJ4l9x7771q5BkzZowuBjfeeGM18myxxRZdnaf+hhtuCNQ7\nwDvZyRFwBBwBR8ARyAoC1AEhmgeHBOrpbLPNNhrNw6K704l5GaKWoJMj4Ag0jkDe5V2MxGeddZYa\nf1CQDh48OJDuzVMjN943/AqOgCPQXgSyPj7jbESaN6LMMboPGzZMnWHbi5rf3RFoDgI/a85l/CqO\ngCPgCLQWAdK04QVHvuw+ffpo7vBTTjlFU63cdtttYYcdduhqY09r34bfzRFwBBwBR8ARKI8A0ahX\nXHFF6N27t9aW+fOf/xyOOeaY8OGHH2rNnm4w9pRHyL91BByBbkSAqL7jjjsuvCf1PfE4p34ZNSj4\nTColJ0fAEXAEHIF0EFhllVXCU089pSk2R40apZHmV199dTo386s6Ai1GwA0+LQbcb+cIOAL1IzBx\n4sRw4oknhkUXXTSstNJK4c477wyDBg3SArGEC/OZvNtOjoAj4Ag4Ao6AI5ANBCgQjIMG9WYGDhyo\njhpE5r755pvh8MMPryn3ejaeyFvhCDgCjkDzESCd0dFHH62GH4qJo3zE8HPYYYdpXY3m39Gv6Ag4\nAo6AI0B6z3333Vfl0s022yzsuuuuASckotGdHIE8I+AGnzy/PW+7I9AFCFDYlMJ6a6yxhhYmpsDp\nRhttFAi/RVnEgmiBBRboAiT8ER0BR8ARcAQcgXwgQC730aNHh7XWWiuQE53I2yOOOEILt5PKbP31\n1w8UTXdyBBwBR8AR6IkA9YUwhpujG2PpfPPNp3W/Pvnkk54n+3+OgCPgCDgCTUGANJpEWI4fPz5Q\no2i55ZbT9JrUTXZyBPKIgBt88vjWvM2OQIcjQNoX8r1utdVW4de//nU49NBDw9xzzx3uuOOO8NFH\nH2me65VXXrnDUfDHcwQcAUfAEXAE8oXAG2+8oXM26VYHDBig0Tvjxo3TSFzSE/Xq1StfD+StdQQc\nAUegTQhQyHzIkCFq+Dn55JO17tf8888fDjjgAE2F2aZm+W0dAUfAEehoBMgkg9HnvPPO01TEiyyy\niNaL7uiH9ofrSATc4NORr9UfyhHIHwI//fRTeOCBB8Kee+6pRp4dd9xRCzlfeumlmsaAXKqbbrpp\nmGKKKfL3cN5iR8ARcAQcAUegQxH44YcfwrXXXhvWXXddTbl60003qZLygw8+CHwmKtejeTr05ftj\nOQKOQOoITDPNNOHAAw8M7777bjjttNPCLbfcotkN9ttvv8A46+QIOAKOgCPQXARI87bXXntpRpkt\nt9wy9O/fX6PWJ0yY0Nwb+dUcgRQRcINPiuD6pR0BR6AyAkyaRx55ZJhnnnnCeuutF1544YUwbNgw\n9VzDK5gcqtNPP33lC/kZjoAj4Ag4Ao6AI9AyBN5++21N0zbnnHOGXXbZJVB4nNp6KCWPOeaYMPvs\ns7esLX4jR8ARcAQ6HYGpp566ULv0rLPOCnfddVdYcMEFw957761RQJ3+/P58joAj4Ai0GoFZZ51V\nyws89dRTAQcn0rxRl/Kbb75pdVP8fo5AzQi4wadmyPwHjoAj0CgCH374YRgxYkRYZpllwtJLL60p\nCnbbbbfw6quvhmeffVY9g0nl5uQIOAKOgCPgCDgC2UHgP//5j6Zc3WCDDcLCCy+skT2DBw8O77//\nfhg7dmzYZJNNAl6RTo6AI+AIOALpIDDVVFOFffbZJ7z11lvh/PPPD/fdd5+Ox3vssUd455130rmp\nX9URcAQcgS5GYIUVVghPPPFEuPDCC7VGJWnerrjiihBFURej4o+edQR8RZb1N+TtcwQ6BAGK3V12\n2WVaqJlonuHDh4fVVlstPPzww+oNfNJJJ4XFFlusQ57WH8MRcAQcAUfAEegcBIjaOfroo8Ncc80V\n+vXrF6addtpw6623qlf50KFDAzV7nBwBR8ARcARah8CUU06pqbCpnXbJJZeERx99NKCEJPXQm2++\n2bqG+J0cAUfAEegCBEhPTPkBxtdtttkm7L777mHNNdcML774Yhc8vT9iHhFwg08e35q32RHICQJ4\nAqMQ2n777bVQ86BBg8Iss8yiOf0//fRTDY9lkvTc/jl5od5MR8ARcAQcga5B4Mcffww333xz2Hjj\njTVt0JVXXqle5e+991647bbbwmabbRYmn3zyrsHDH9QRcAQcgSwiQH1TjDyvvfZauPzyywOph3Ci\n23nnnfVYFtvsbXIEHAFHIK8IoM8677zzwtNPPx2oQ030zwEHHBC+/vrrvD6St7tDEXCDT4e+WH8s\nR6CdCDz++OOaY5r8/VtttVX47LPPwtlnnx0w8tx44416jHQETo6AI+AIOAKOgCOQLQRIz3bssceG\nueeeO2y33XZq1BkzZoymbTv++OM1yidbLfbWOAKOgCPgCGCAp57aK6+8oimHqIu65JJLhh122CG8\n/PLLDpAj4Ag4Ao5AExFYfvnlw2OPPRYuvvjicN1112mEJUZ3T/PWRJD9Ug0h4AafhuDzHzsCjoAh\nQDoB0rrMP//8oXfv3uGRRx4Jhx12mCqIHnzwwTBw4MAw88wz2+m+dwQcAUfAEXAEHIGMIPDf//43\n3HLLLWHTTTfVeZwUrNSDIJXbnXfeGbbcckuP5snIu/JmOAKOgCNQDgHqqJF6EyPPtddeG15//XWt\nmbrtttt66qFywPl3joAj4AjUiACZakjtRpo3stqg80IX9vzzz9d4JT/dEWg+Am7waT6mfkVHoGsQ\n+Otf/xpGjhwZVlpppbDooouGSy+9NPTt2zfgUTZhwoRw1FFHuSdw1/QGf1BHwBFwBByBvCHwl7/8\nJQwbNixQW2/rrbcOGH5uuOGG8MEHH4QTTzxRj+ftmby9joAj4Ag4AkFTZhOlybrspptuUgP+csst\np5kWnnvuOYfIEXAEHAFHoEkI4NhMRptnnnlGx94VV1wx7L///uGrr75q0h38Mo5A7Qi4wad2zPwX\njkBXI/Ddd99pmoBNNtlEizQfd9xxmi7g3nvvDSiORowYEZZZZpmuxsgf3hFwBBwBR8ARyCoCGHVu\nv/32sPnmm4f55psvXHjhhWHXXXcNb7/9dhg3bpwWoqUmhJMj4Ag4Ao5A/hHAAx2DPkYeIjk/+ugj\nrTlBHTbq/Tg5Ao6AI+AINAeBZZddNjz66KOBSHkM7Ysssoh+9jRvzcHXr1IbAm7wqQ0vP9sR6EoE\nUA6hBEIh1KtXLw1bRRk0evToQJTPqFGjwvrrrx9IIeDkCDgCjoAj4Ag4AtlDACXfCSecoEaeLbbY\nInz//ffhmmuuUWeN4cOHayq37LXaW+QIOAKOgCPQLAQw9FNo/I477ghffPFFWGWVVQJOfE888USz\nbuHXcQQcAUegqxHAyN6/f/9AyYMdd9wx7L333mG11VYLzz77bFfj4g/fegRcO9t6zP2OjkBuECAk\n9eCDD9ZInj59+oR33nknnHLKKeHjjz8Ot912mxYBnXbaaXPzPN5QR8ARcAQcAUegmxD46aefwl13\n3aUpfEjbds4552htB3KNE5lLup8pp5yymyDxZ3UEHAFHoOsRoF7b+PHj1aHv73//e1h99dXDhhtu\nqDVYux4cB8ARcAQcgSYgMNNMM2n5A6IrkbVXXnnlsN9++4Uvv/yyCVf3SzgClRFwg09ljPwMR6Cr\nEJg4caLm7acmD7V5KNY8aNAgTfXy+OOP6+fZZputqzDxh3UEHAFHwBFwBPKEwCeffBJOOukkjdpB\nsffNN9+Eq666Knz44YfquLHgggvm6XG8rY6AI+AIOAIpILDRRhtp+iEcAH744Yew1lprhfXWWy88\n+OCDKdzNL+kIOAKOQPchsPTSS6sx/fLLLw9jx44NCy+8cLj44ouDp3nrvr7Q6id2g0+rEff7OQIZ\nRAAvgwsuuCCsscYaqhyi4BwLgCeffDLgBTx06NCwwAILZLDl3iRHwBFwBBwBR8ARAAEWjnfffXfo\n27dvmHvuucMZZ5yhn19//fXwwAMPaGTPVFNN5WA5Ao6AI+AIOAI9ECA190MPPaSGHtIRrbvuumr8\nwRDk5Ag4Ao6AI9A4ApRHIM0bexyqSalJRh0nRyAtBNzgkxayfl1HIOMI/Otf/wo33HCDpnn59a9/\nHQ499FBVEJHTmTz/Z511loadZvwxvHmOgCPgCDgCjkBXI0AtvZNPPjkQtbPxxhuHzz//POBFyFx+\n2mmnacHYrgbIH94RcAQcAUegKgTWXnvtcN9992nUzzTTTKNp3nr37q2p36q6gJ/kCDgCjoAjUBKB\nGWecUR2ynn/++UBpBIw+++yzT/jb3/5W8jf+hSNQLwJu8KkXOf+dI5BDBMjlj5fvnnvuGTDyUESO\nos2XXnppQGF09dVXB1K/TDHFFDl8Om+yI+AIOAKOgCPQHQgQzYNSbvvttw9zzTWXpmmjGPerr74a\nHn744bDzzjuHqaeeujvA8Kd0BBwBR8ARaCoCGHmIGH3iiScCdSio5YpiEsdAJ0fAEXAEHIHGEFhy\nySU1qvKKK67Q2tikebvwwgsD+jonR6BZCLjBp1lI+nUcgQwjMGHChHDkkUcGCjaTl/mFF14Iw4YN\n01z+48aN07DS6aefPsNP4E1zBBwBR8ARcAQcAaJ3RowYofm/N9hgA43iueSSS8LHH38czjzzzLDY\nYos5SI6AI+AIOAKOQFMQWHXVVbWe61NPPRV69eoVNttss7DiiiuGW265xetPNAVhv4gj4Ah0MwI4\naJHmbcCAAWHw4MFqWGe8dXIEmoGAG3yagaJfwxHIIAIUZkYptMwyywQKxV1//fVht912U+/fZ599\nNgwZMkSjfDLYdG+SI+AIOAKOgCPgCMQQoIA2UblzzjlnOOmkk9TbGmeOxx57TOd2Uu84OQKOgCPg\nCDgCaSCw0korhVtvvTU899xzGlW69dZbh+WXXz7cfPPNbvhJA3C/piPgCHQNAjPMMIOmYMYpGyds\nDO177bVX+OKLL7oGA3/QdBBwg086uPpVHYG2IPDtt9+Gyy67TKN4iOYZPny4Thikd3n33XdVSeTe\nv215NX5TR8ARcAQcAUegJgTI53366aeHRRddVAtoT5w4MVxwwQUazXP22WcH0kE4OQKOgCPgCDgC\nrUJgueWWC2PGjNFsEdSN23bbbdW5EMdCT0XUqrfg93EEHIFORGCJJZbQ8guUWbjzzjs1mv/888/3\nsbWFB1p0AABAAElEQVQTX3aLnskNPi0C2m/jCKSFwH/+8x/1uCKPP6H2gwYNCrPOOmu46aabwqef\nfqq5QNdcc80w2WSTpdUEv64j4Ag4Ao6AI+AINAmBRx55JOyyyy7hN7/5TTj++OMLqVjHjx8fdt99\n9/Dzn/+8SXfyyzgCjoAj4Ag4ArUjQPaIG264IRBpuvjii2sE6lJLLRWuueYaV07WDqf/whFwBByB\nAgL9+vXTNG/U3T7ooIMCEZasAZwcgVoRcINPrYj5+Y5ARhB4/PHH1bgz++yzh6222ip89tlnAY9f\njDw33nijHptqqqky0lpvhiPgCDgCjoAj4AiUQuCrr74KI0eOVMXZWmutpQu9c845R6N5zjvvPPWg\nLvVbP+4IOAKOgCPgCLQDATzSr7322vDKK68Eon923XVXnceuvPLK8N///rcdTfJ7OgKOgCOQewRI\n7UZ5hhdffDHMPPPMYfXVVw8YgKjl6eQIVIuAG3yqRcrPcwQygAAF3YYOHRrmn3/+0Lt374AX8GGH\nHRbef//9QH7/gQMH6oSQgaZ6ExwBR8ARcAQcAUegAgI4b/Tv3z/MMccc4dhjjw1E5FJn7+mnn9Y5\nfbrppqtwBf/aEXAEHAFHwBFoLwKkHr3qqqvCa6+9punE99hjD01HOmrUqPDjjz+2t3F+d0fAEXAE\ncooA5Rjuu+8+Nazffffdmubt3HPPdYN6Tt9nq5vtBp9WI+73cwRqROCvf/2rev0Syokwfemll4a+\nfftq7mTC6I866igtnlnjZf10R8ARcAQcAUfAEWgDAl9//XUgeof0NzhvMJefeeaZ4ZNPPtE0rBTC\ndnIEHAFHwBFwBPKGwEILLRQuv/zy8PrrrweiVffZZx9VUF5yySWBNOROjoAj4Ag4ArUjQPkGxlXG\n1CFDhoQVV1wx4DTm5AiUQ8ANPuXQ8e8cgTYh8N1334XRo0eHTTbZRHP4H3fccVqc+d577w1/+ctf\nNLxzmWWWaVPr/LaOgCPgCDgCjoAjUCsCTz75ZMDrmdo8OGusssoq4amnngrPPfecLuBI3+DkCDgC\njoAj4AjkHYEFFlhAnRTffPPNsOGGG4b9998/YAy64IILwg8//JD3x/P2OwKOgCPQcgSI+j/55JPD\nSy+9FGabbbawxhprhAEDBmhph5Y3xm+YCwTc4JOL1+SN7AYEyHM8btw4zX3cq1cvLcw8xRRTqOGH\nKB9C4tdff/3ws58523ZDf/BndAQcAUfAEcg/At9++22gBs+yyy6raW4w7pCT++OPPw54PBO96+QI\nOAKOgCPgCHQiAvPOO69Grr711lth0003DQcffHDAGERKon//+9+d+Mj+TI6AI+AIpIoAWX/uueee\ncP3114f7779foyip5e1101KFPZcXd81xLl+bN7qTEHjmmWdU+MXjt0+fPuGdd94Jp5xyiiqDbrvt\ntrDDDjuEaaedtpMe2Z/FEXAEHAFHwBHoaASowbPXXntpbZ7DDz9ci1mPHz9e07EOGjQozDjjjB39\n/P5wjoAj4Ag4Ao6AITD33HOr8wPr3K233lpr0FKTduTIkeH777+303zvCDgCjoAjUCUC2267rdZN\nY11BXW9SQj/66KNV/tpP6wYE3ODTDW/ZnzFzCEycODGceOKJWpMH794777wzMFC//fbbmouTz4Rp\nOjkCjoAj4Ag4Ao5APhD4xz/+ES666KKwwgorhJVXXjlg4Bk+fHj46KOPNEqXFG5OjoAj4Ag4Ao5A\ntyKAg+NZZ50V3n33XXVqPProo8N8880XTjvttPDPf/6zW2Hx53YEHAFHoC4ESPP2hz/8QeuBzj77\n7GHNNdcMu+22W/j000/rup7/qLMQcINPZ71Pf5oMI/Dll19q3mJybeLRRNjlRhttFMjpT37joUOH\naoh7hh/Bm+YIOAKOgCPgCDgCCQRI07bvvvsGFloHHXRQWGKJJcJjjz2mi68DDjggzDzzzIlf+L+O\ngCPgCDgCjkD3IsB8efrpp4f33ntP05kPGzYskP6NLBc4Tzg5Ao6AI+AIVI/AwgsvHP785z+Hm266\nKTz00ENhkUUWCWeeeWb48ccfq7+In9lxCEwWCXXcU/kDOQIZQeBf//pXIC3b6NGjNYpnyimnDFtu\nuWXYZZdd1NhDjR4nR6BZCFxxxRWaCtCuN2HChHD11Verh7kdY08tKK8bEUfEPzsCjoAjUBsC3333\nXbjmmmu0NgGpWRdbbLGwzz77qFfdLLPMUtvF/OyOReCrr77SWk3xvOrMy9BOO+1UeO7JJ588DBw4\nMHjfKUDiHxyBkgi4vFsSmtx+8cUXX2iUzznnnBOmnnrqcMghhwQcJmaYYYbcPpM33BHoRgR8fG7/\nWydakqifU089Vev7MK6utdZa7W+Yt6DlCLjBp+WQ+w07HYGffvpJrepXXXWVWtjxUkLBjpGHnMXT\nTz99p0Pgz9cmBEgDiHIpbkjEpj/ZZJMVWvTDDz/oAop0Ck6OgCPgCDgCtSHw4osvqpEHRw4KTpM/\nG0MPKRScHIEkAo888oguspmXf/az/02sYL52NjcjN+KB+fDDD3s/SgLo/zsCRRBwebcIKB1yiIwY\nRP6QCQND+JAhQ8KBBx4YZppppg55Qn8MR6CzEfDxOTvvl3IRjJ933XVX2HnnncOIESM0G0F2Wugt\nSRsBT+mWNsJ+/a5BgGiKI488MswzzzxhvfXW08LMhKd/+OGHYdy4cRqu7saerukObXnQfv366eII\no45t//nPfwqfOQb17du3Le3zmzoCjoAjkEcE8JQbNWpUWHXVVcOyyy4b7r///sD8Tm0enDvc2JPH\nt9qaNvfu3Tv84he/UINOfF6Oz80YeziHc50cAUegMgIu71bGKK9nzDrrrFrn9v3331dFJcYf1tbM\nuTi1OTkCjkC2EfDxOTvvZ8EFF9QsQ2PGjNFU06R5Y0z1NG/ZeUdpt8QjfNJG2K/f0QhgzCGlCwqf\nl156SXMPk6KDaB7Suzg5Aq1EgJoR1IgqR7/85S/DX//61x5RP+XO9+8cAUfAEehWBF5++WWN5rny\nyivD999/H7bZZhuN5llnnXW6FRJ/7joQOPjgg8N5550XMPIUI9L9Dho0SHOtF/vejzkCjkBPBFze\n7YlHJ//3zTffaLTPGWecoUrKwYMHa7o3jOROjoAjkD0EfHzO3juhRaxjhg8frnXSMASR5s3XM9l8\nV81slUf4NBNNv1ZXIPDtt9+Gyy67TKN48Dhi4FxttdU0Fce7774bTjrpJDf2dEVPyN5Drr766mXD\ndFEq7bbbbm7syd6r8xY5Ao5ARhCg9h75x4m2WGqppbQA6jHHHKPRujh4+OIoIy8qR83AEaiUsYfH\n4Lt4PZ8cPZo31RFoCwIu77YF9rbclFRuxx57bHjvvffCUUcdFS666CJ1sOTz559/3pY2+U0dAUeg\nNAI+PpfGpp3fTDvttOGEE04Ir7zyio6h6667rsqeH3/8cTub5fdOGQE3+KQMsF++MxBgMX7rrbeG\n7bffPvTq1Us9MQk5v+mmm8Knn34aLrjgAk3pYvnYO+Op/SnyhgD9D4MOhp1i5EqlYqj4MUfAEXAE\nQnjttdcCkRhzzDFHGDhwYPjNb34T7r333vDmm2+Gww8/PBAd6eQI1IPAyiuvHOaaa66SP+U7znFy\nBByB6hBwebc6nDrprBlmmCEcffTRavgZOnSoplmdd955w2GHHaaZCzrpWf1ZHIE8I+Djc7bf3gIL\nLBBuv/121W2OHz8+kObt1FNPLeuYlO0n8taVQ8ANPuXQ8e+6HoHHH39cjTuzzz572GqrrcJnn32m\nYeUYeW688UY9NtVUU3U9Tg5AdhAo50nMwmj55ZfPTmO9JY6AI+AItBGBf//732H06NFhrbXWCosv\nvni47bbbwhFHHBH+8pe/hOuvvz6sv/76HhHZxvfTSbfu379/UWcMHDT4zskRcARqQ8Dl3drw6pSz\np5tuOnXCmDhxYvj973+vc/h8880XhgwZEj755JNOeUx/Dkcg1wj4+Jz917f55puHV199NRx66KHh\nuOOOC8sss4zWKC3X8rvuuis8+uij5U7x7zKGgBt8MvZCvDntR+CNN94IeA7NP//8mtLlkUceUe8h\nikc++OCD6vk788wzt7+h3gJHoAgCSy+9dCAva5KmmGKKMGDAgORh/98RcAQcgdwj8NRTT2mtnWof\nhHmeBQ5RPIyLRO+MGzcuvP3225oyhkheJ0egmQjsuOOORb0nibzlOydHwBGoDQGXd2vDq9PO/vnP\nf661fDD8nHzyyeqkwdr9gAMO0BSs5Z6X1K1kRKBOn5Mj4Ag0HwEfn5uPaRpXnGaaacLvfvc7Nfyg\nP8LRrV+/fuGjjz6a5HakfqOW6UYbbeRj5yToZPeAG3yy+268ZXUiwOIZYY8BqVqiiP3IkSPDSiut\nFBZddNFw6aWXhr59+4YXXnghTJgwQRVA5dJxVHsfP88RaAUCKDAx8MTpxx9/dKVSHBD/7Ag4Ah2B\nwJgxYzSl6n777VdWyfPDDz+Ea6+9NpCzmnmelKx4BH/wwQf6mQWMp2XtiC6RyYcggmyxxRabpG0c\n4zsnR8ARqB0Bl3drx6zTfoHC8sADDwzU0T3ttNPCLbfcEkhZhEzA/F6MqAN05ZVXanQv6VydHAFH\noPkI+PjcfEzTuiJRkpSvINXbM888o+ukU045pYejEmsm9Emsp/r06eM11NJ6GU2+7mSRUJOv6Zdz\nBNqGAMUbt95660AqNro2wh8DWDH67rvvwtixY8NVV10V7rnnnoCnEEaeXXbZRRVCP/uZ20OL4ebH\nso8A/Z7FTpwoPv7SSy/FD/lnR8ARcARyjQCOGixAmO8xclPYediwYT2eiagdlDuXX355+PLLL8Nm\nm20W9tlnn7DxxhsHn+d7QOX/pIzAH//4R+2jLJgh+uyJJ54YjjzyyJTv7Jd3BDoTAZd3O/O9NvJU\nKCNHjRoVhg8fHvBIR+lM7R/TB5DKde6559Y07YzBM800U3jssce0jkUj9/XfOgKOQE8EfHzuiUde\n/iMCEmMPkZPzzDOPlrNgrMRhzoj/V1xxxfDQQw8FL29hqGRz7xrtbL4Xb1UdCBCNs+yyy4Ynn3yy\noPwhN3+c/vvf/2rall133TWQsmX33XfXBTfnEeWDgEgooyuB4qj557whQEoDavWYtzqTMgseJ0fA\nEXAEOgGBn376SQ09Bx98sM73PBNK9PPOOy8wzxPpe8MNN4QNNtggLLzwwhrZM3jw4EBqVhw9Ntlk\nE5/nO6Ej5OwZSN1mxh7rs57OLWcv0ZubKQRc3s3U68hEY1A+4tTx1ltvhfPPPz/cd999Kgfsscce\n4Z133tEsHl988YW2lfH4m2++0ShhnEOcHAFHoHkI+PjcPCxbeSWiJilvQX2fRRZZJGy44Yaa5m3y\nyScvNIOx8+mnnw5777134Zh/yCYCHuGTzffiraoRgeuuu06L3jL4oOwxYqJBuCM0kUge0rlg2Flt\ntdU0kmf77bcPs802m53ue0egYxA466yzNLc1/IDhhyLk1KtwcgQcAUcgzwjgeYaSnNQDGH6SRF5+\n6vGg0MGwg+KHfXyhkvyN/+8ItAqBVVddNVBzClp55ZXD+PHjW3Vrv48j0JEIuLzbka+1aQ+FbgDH\nzpNOOkl1AtThJdo3TjjG/eIXv9AMIegOnBwBR6A5CPj43Bwc23kVjDqUuyi25qJdI0aM0Hrn7Wyj\n37s0Am7wKY2Nf5MDBBh4jjnmGA05LNVcwg0x+Cy00EJq5Nl5550nSXdV6rd+3BHIKwKffvppmGOO\nOdT7vXfv3uHRRx/N66N4ux0BR8ARUAT+9re/qfHm+eef7xEpYfBg1EFZg0Fo4MCBwWvvGTK+zwoC\nRKFRbwJCETJo0KCsNM3b4QjkEgGXd3P52lreaBzgGG8vueSSoopLjD6/+tWv1OhDGiMnR8ARaBwB\nH58bx7CdV/jkk09Ub/r999+XbAaOxTjhkTLbKXsIeEq37L0Tb1GVCBCCjdcuOSZL0ZRTThlmn312\nTfP25ptvanhisrZJqd/6cUcgzwj8+te/DmuvvbY+Ah7vTo6AI+AI5BkBonVx4Chl7OHZUOiQlmXP\nPfd0Y0+eX3YHt3277bZTRwzqTvHZyRFwBBpDwOXdxvDrll/jJEpB8lJe6kQCffbZZ2GNNdbQrAjd\ngos/pyOQJgI+PqeJbvrXPvTQQ4s62CXvTNakl19+OXnY/88AAh7hk8JLoFjg119/rTlh2X/77bfh\nH//4R/j73/+uG5/ZsJSykZ6ELf45+T/56BFQUGbYVup/juPlSh0a9raV+p9ct9NOO20gXyNbuc98\nN8MMM+g2/fTTFz5T8JCNMOkZZ5wx9dz4b7zxRth0003DBx98UHEQmnXWWVWAAwcnR6AVCFAQFL6P\nb999953yfXzPZxsHknvGETauFf8M/xvvV9pzLkqlOO/b53J7vNymnnpqLcLH+GCf2TMGFNumm266\nwJgQ3zNWMB7Yxv/Oh63ogX6PrCCAAgHnhK+++qogF5gswPjAZ5MHbN43WSA+Jth3jAUmA8T3NhbE\nj4GBzf+2N763/20flwPi/G0yAcfss8398LXJAzb/zzLLLCoLMIY0k6jN16dPH8UKTMsR96ZA8wkn\nnFDuNP/OESggAN8gr5Pmx3g1Pn/Dw//85z91M77k/2KfkdfjfJj8TP+1PkxfZTM+LLbHccl48uc/\n/3nJz8y9NtfaHpkcnkQO5jPXd3IE2oEAsiz8VWyD95CH4Sn28c92jDkQvoGfiu3hO+Rd+jg8Y7xk\n/GV7voOP2OAZ28c/M8cZ38A78c35qB29pzn3JCXRXnvtpf2k3BXpK2RIePzxx5uaChv5jVSzn3/+\neY+NYyYXmr4ovre+b3MHe/q78QFyHW2Ob/Rz/mdvMluxPf2cqKZf/vKXPTbOdepuBJBvMIDaRkkE\nPiMjWX+1dYz9z3ht/dT6KP8z/jM+W59M7umnjMGmN7C1hf1PukVqb9NX2fhMSQaXadLto2SHWXPN\nNau6Ce8C4x5OeYwnjRDZHD7++ONAdBF7NmQHZHHTsfPZZHP6WnJDVqBfFdvoV3HdtX2mbxEowPjP\nxmf6Zd7JDT4V3iADlA1wTNA26PGZjkeHjO8ZBJmYixGDm022dDRbwFVjaKGzmvCaVNgk/yesLqn8\nKfc/z8igTrtti/8f/4wAYkIIAjmDd5K4P89nwjKDNMIyezYTLGzQZs+gzXNUQ3fccUfYYYcddPJg\nEqmG/vznP4eNN964mlP9HEeggAB9HZ6HzxHI2ewzfA+/m3LIPiP8wFOlCL5nHGACsQWmjQXsTanK\nHiVs3ODCZ8YRxgLj+3J7vmNiZIHKxGfjQKU9k2YxY1N8fGBcsA0BD6wYE9jz+1LEMzOxMj4kN8YJ\nxgLbGC/4jODAszs5Au1GgD6OAMq4YLIBe2QCGx/iYwT8UIyY05knbYsrcm0MsHEh/j9GV+N5kwmS\ne75nnICYI43fk4pn+5/vTQ6w+d54O/k/vG4LO/aleJ0xzvjZ5n7jZVu0sWdjgVBOoB47dqzO+fYs\nxfBMHmPMYIFgOCS/9/87HwEWgvAqGylFbEsq2+BX5u1i8izzDvMncxa8anxqe3g0+ZnfJHky+T/z\nK8S5xoel9pwL3xlPFvtsfGmLYbt+/C0jm2MIgh+Tyj140DYWuGw8s5MjUAkB5r2PPvqooJiJK2iM\n/+A5+m+SmNuYJ5AFk3Kxyce2h89M/i22Z96j/9NvmSvgp2J75iz4pZhRyY4zHpiMz3XiBB9xD9au\nphAqtqdmZrl5LX5N/5w+AvSF+eabL3z44YdV3Yw+RkrYxx57TMfDSj+in+CEWmqDR+ifcWJesPHY\nHGjgAzbmG9szz9CeUhsyHM9H32Yf35gLkNWQRdnss8lxzH/wZ1J3BW8yJ8w999xFt3nnndf7d/xl\n5vAz65iJEyeG9957r8f2/vvvK5/QR+LEGMy4R5+1tQt767smI7G+ifdV02EyrnJuvJ/aZ/bWJ5N7\n+MbWWPRtI8Z82kIfpT/aRjpGPpPe2cdgQ6u+/S233KJGcvCHkFmLyZd2dd47mRgeeuihsnobxst3\n3303vPXWW5qVgb19puZ0/B6MRcikyK3MvbaZbM47po8lN8ZX+lVyszHR5GX29tnW9fF5nz7L3EFp\nkAUXXLCwX3jhhXWMtGfP8r6rDT4MdHQqJv/4xqLQhFQEvjjRkW2hhPLCDBm2R2i1Dmh7OiaDIB22\nk4jFMQIzA7gxSnwfN4QhUPA/AwYbyvH44hpcmURsocl+zjnnLGwIXfx/zjnnaM0ecIz/vhyuMDwG\nIgo2OjkCCMbwuHkMxBenNtCzZ0suUOlLxusIGUmDBTzPxuQQ3xgDbDGLgNLpxORqCwvGBxsj7DNG\nKDOQmcHMxguUB5yXJLCOK4pZiMQX2Xxm4zwnR6AeBJi/bLGObMBn9jZWsE/2TfiauYu+yZiAXMDe\nNpMJbGyw8QHDTScQhiIwgafjG3zNvG+bGcNsjE0awhgvjYfZM+eziHvhhRfChRdeWBYqFHCMzTa2\nmvLj7rvvDhtuuGHZ3/qX+USAxRi8aYoKFBR8jsvy8T5G34A3mTfg17gcz+c4fzJf2/8o2vJIyC7G\njyaX2/+mODF5nLUQMhE8Cu8YMbaZHA4/okQxRQrKFI7Bd06djQCKYNJpkirT9nG+w0hiZIoZ1nCM\n47amY35Edo5vzI1Z5y/WmcxvzGfIqLYxr9k6wvQF7OGluKKIMQdegW9QPpJSHIURG/xjc5bh5/v0\nEGBuQEFn6zrkBhSEJi8UuzO6Cd4fXu70YYjx9PXXXw9kGonv4Q9TUqIUxeAXN5YwlnIN5hv6BXv4\ngXZkgZgv43MDfRkjlcnCJg+bDEy7eaZFFlkkLLroorrZZ447ZQcB+v6rr746yca4BjGPM17T122O\np+/SX5GXbEMmaCcxHjMG0zfZWE8wDjMfmQzInvEZoo/yHIsvvvgkG2sOp+oRYH57+umndRs/frzu\nGQttHLWxjysyr+2yyy7hT3/6k94AGeHFF1/U9RxrOrYJEyYUxmLGQpsX2WNcicsPrdbrMIfTv1jz\n89yMgyb7mBxkcg9tX2655cKyyy5b2BgHsza3d7TBh0nJXgwvCit2fECIezPA+EzOTFLxTsbiEIHV\nBjsWgVmZnKtn0+ydiYWexSUMxWDNBlPZHuZigoLZ4oNIvU/C+2NicOp8BDBCMvmb1wo8T19CaDXl\nbdxDBI8VW5SyNwEnvjclLpOO83/6fQiDEQIbYwQLEBPsbA8vM16w8Tn+PvH0YBxnMW0bQqxtHGMR\n59R9CLBYYG6hnhueRCYX4GXEeGGLH5ChH1n/icsFyAdsNj4wfjjVjgDCsvGzGdTgZz7beI2CwYRq\nuwO8i7GM94PcZkp89jjWsCBl47uddtpJ9/Zb3+cLAfiVPmBKNfP+Q65njrdxH6UdvIqigsU9/Gry\nPHvkePjVjRPl3z94mkxuMrjteQ/IUshQzM8QuIO5LdTxfjSFH+/BZaXyeGftW2TnV155RRUxKAdf\ne+015T3euxkCUW5gtGDj3dsG/zEvskbuZoorioxnTO+AvMFmcxrGLgwQpixfcsklw1JLLaX85GNV\nOr2IfoycwfzBe7HN3g3yRzxDA0o7foMDz2qrrab1KfgthFGHsY8xL76x1mDO6dTxDyUvuDEfY/SK\nbzgVQIwDyyyzjCpAl19++bDSSispRllTgmpjO+wPc7gp5m3POhpCTl5sscXU+GF7+nCnrYsxXsKn\n9E2by5jP+B+DL7yJvLLyyitr36R/orDPugNC1roqGNPHnnnmGU1/+dxzzxXmN9q6/vrrq8OE1V1l\nXbb00ksXDCN8Zg7EySpPxNqEuYI+FTdksVZBjuZ5evfuranwSIdHxFO7nTxzb/ABWBZ/tiCEmfnM\nRISy0AhFLt41TMQmoLK3xSGKAqfsIQBTMVGxyISxHnjgAf3flMAYiEx4ZgBnUc87ZeP98r557wjS\nHHPqDAQwBqC0hffjG4rbON/D13E+R6gxYwCKIMaFvE00nfEGm/cULMYYD0xRbMpi27PojiupWEjT\nB+KelnGFVadFYjYP6fxcCYVkUtBn/kAuMO9OBHv6APMD3kRszBdszBWt9ijKD7qtbSmLV+NlFhcY\n5tgY61HSxN8nCzgWsbbh1YciBsW0U7YR4B2/9NJLqlCj6CsbPGzyHfM075Kx2hTO7OFXFM2uSGrN\n+2W+Za6FF01Jyh45jPeFMhDCEM77QvY2RTbKbOZep/YjgAyNkgYFDcoY9oyprLlQTGCEYBxlb8ps\neM/Xyo2/OwwOprcw3QVKSXgK/JFBl1hiiYCi3DaU5+1WGDX+5Nm+AsY6eGHcuHHhwQcfVJ4gmgDC\niQTlJe8DJSVjGXOPG+Z6vlPkNfoySlDmc/PkRyZn7ECxjiJ09dVX1w0FsFNjCDCGkD7r4Ycf1kg0\n1rwQaxoUzWzgTp/F4NPNhPzCOAufM/+xPfvss+rshzMZGK211lq6rb322mro7Wa8qn12dPFEQd5+\n++2BFHDMbxBraeqtr7HGGmowp092qiGc58VZgMgl0oCCB3vme+Z0xrzf/va3uiFTtZpyZfDB04zJ\ng4mExSCeSAx0FgGC8hYQsRayt4UhHcy9cFvdtVp3PxT8tvA0jxOMAWyWfxTlHQK0LT6x5CO0+eKl\nde+pnjuhBDLljy2M2JtRhwkag05cARRX3BIu7+QIIOQxfyQ9LW3csOg/lIb0J1NyoDBm3GBzw2A2\n+xELcpRVbCwwEbZMLoi/T1NeWQ5eDL6dLHhm8201t1Uox+BrFhfM/bx3DHvs4XX4Hi9c+JmFHHO+\nKdB8bmjuu6jlarybp556ShfbLLzZbE7HaQc5zcZdG4s57pR9BJhLzfGONRobMpzNsSicSH/BhiIK\nD1vmXKf0EGAcZG585JFHAqlYnnzySV0zcUeMpfY+MCrAe8yRrshO732UujJe6cYvNi7y3jjOPMa6\ndZVVVlHFGV7DbjwthWT1x8EbAw/OpCjMyQxDdMqqq66qCjrwXmGFFVzxWz2kk5yJEpR+TCTA448/\nHp544gk1LjPGgO26666rqXdRCrtRcxL4JjlAJgL6LNu9996rDlFEvNNnGReIRGNudRl3EuhKHkAX\nQP9EQc88yTqS9QVzI2mhN9lkEzVUenaQ/4MQ/SrGnVtvvTWQPhtnH2QHDDxghmG32yN+QYu+xdxC\nLXlwIgoSneVmm20Wtt56a+XZVjisZdbgg4XaQhGxvmLosQUhihoW7qaMs9yMrrz/P0b0T/+LAMog\nvE0Q6mzPQM5AhbIPprOFJx4QCB/ucdL63oOXNu+FRQ68jnDIOzNvUdJImLc2xlwz7GLc8Qm49e+r\n0+7IgtqMxCirTGGF4tgiCIgOQxliaQoYN3AqaMVE3Wl41/s8ePvjkYXCig3ZAG8tiLSdKERQ7LPx\nrhgzPERf4em6P/Atcz7KZuYWNuYWPFAhvHOZ71HosLFAdseg5ncTUicjy+PthrIHQw/vgHETYw4G\nOPjWxtVu90Bt/hvIxhVZv5nDHnsM9MyvGCMYuzH84AGJ0g9Z3CNt639vYArG9913nyqyUWKhyGZt\nY+OdpbIh9ZRTdhHgXSKPMm6yYbDD6ZVoFOYwvNGJPFlvvfXcAFTFa2Q+QkmOkvKuu+5SZTkOoRgd\n1llnnYBXP/KjOwNVAWYDp+D1TlQKkVT333+/OuxgtOA9bL755rrhxO30vwiQpeLmm28OY8aMUaME\nxggMOyjW4X/GddeFNK+3YFSjbzJWoKTHqQzjBYafvn376r4b1wtE6t15553hiiuu0D2RPcw9RK5g\n6EEn4lQaAeZtDN5giLGMNSrjXL9+/UL//v11HVT61419kwmDDxMwShwWg2b9twUhil0W4iwKWRBi\n6CGXqpMjUC8CTJSkhEFoZkNpSP8jPRxCHkoIJlILO6YPuvBXL9qT/o6IPHA3gy6LGBY0DISEzSNs\nw+vszaiLwcfJEWg1Aiy2GSswPrJhiKTvYhyiv7JAwfCDgooNJQpGZKfmIIBXOIpiPK7YwB7c8fY3\nhRWyAe8AT2UnR6ASAqSjwrEAhTNzEPMP/QxvU+YdPCTZUDx7VEklNCf9HnmeBQ0e0yhywJg5n0UN\nCn1kK8ZK+Jb53ql7EcDRwviQPsP6D0Ug0Qz0ERQJKADpM24AKt9PSGuLBymKBBRURL5iPEWJzcZ4\nhkztDirlcczDt/ANDi/IRIyzfCaKgrUrCkkUbxiC4COnoE5b8MV1112n/IHjEM4eeFj36dNHdUwe\n0dbenoLjFuPWHXfcoUp2HHaIWNl+++3DdtttpzX52tvC1t8dJwn67OjRo9XQi1M7fXaLLbYIG220\nkaedbuErIYMAfdMMbkSiYZjcZZddwsYbb9zxaaPhzwsvvDBcdtllmkIfWX7HHXdU/nT9XP0dEZ3G\nNddcoxuBLqyL9ttvP60/22yDYlsMPggmtiDEgmrCCgobBHsGeazVKHF8QVh/R/Jf1oYAiiCUE3hQ\nsfGZIqYMZnj92MKJVCNO1SPAQpSFPF6GbBjYGAPwqkLoxqDLHi9flOVuXKseWz+zPQig1MQAhLLK\ncgATQYBiEyULwhAbRmMUV56moLr3ROQlCgw8k9nAGK81FPFgyYZ84PXYqsPTz6oOAQRt5nyboxDC\n8Vxjrsd7kg3Fs0eRF8cTAzjKZjym8dpFWYOnn8lNKJvxRndyBCohgGIBIz9rQ/oSnrVEadKXUGaj\noCVtt1NQZxQUUHh+s6amVhnGajBCIUiUq8vTnd9TGG+Zu0jxxDhMVCtzFYYfUsbgfd2NuhTGkcsv\nvzzccMMNupZnDNl2223DVlttpQ4Ind8z8vmE9GciK2688UaNxCI6EeM/HvBEV3Ry1D4OyTz7RRdd\npBEArB3pryjXN9hgAzfiZqBLo9Nizr366qvV6I6OcMCAAWGvvfbquAgX1kUjRowIY8eO1TFz4MCB\nYffdd/c0vE3uh/A98xV8z7jHGLfvvvuGAw88MDQrCrtlBh88+BFEEEgQ4vGwIHLCimOxdyVOk3uQ\nX64hBPAkJy0CuRfZ8Kai0CmGSSz6bO5lMSnE5KdEaWsbSlu8p4jOM4Mue4+EmBQ7P5JfBDD2MF6g\neEFIYk+tCivWh8KYzUPve75jZAMKPeKByRhLVBUGYMMLI083Kit6ouT/tRIBPKhRoNkchpMCnvEo\nU1Gi4WWJ/NrNhKMWi0A2UnNh6EYhgUxEmhGvL9HNvaN5z04dx3vuuUe9v1GE4fVMJANKMDbm024i\nsl/g9Y2yCTkDvmM82nLLLZX3mu0V2k3YdsqzwjOkLCNlDHMYTjN4o++00046f2EY7FTCaehPf/pT\nOP/88zVdDrLkrrvuqgpzUkc65QsB1lWsDa688kpdJzC+oVwfNGiQ1gvJ19OUbi06UYyTI0eO1AwS\nGCf32GMPNVD6mF4at3Z/g7MY723UqFG63scpZciQISoLt7ttjdwfJ+1hw4ap8REny0MOOSRss802\nXtuvEVCr/C165gsuuCCcc845Wu9nn332CUcddVTDhp/UDD5Yq+gwCBxseABipWIhyKKQzVOwVPn2\n/bRMIECfRqHLopMNIxBewCiBCLHFk6obi8+CCwoxvHsx6qIIQjnGJGEGXaIdXGmbiW7sjWghAiy8\nGSdwcmDDuDHTTDNpxAAGYzwvqUnXbUQEBV4seEmRwxZZAK9kNmQDov+cHIGsIEA+b+Z85jc2ooFJ\nN8oCCI9hItC6gUhpiaIZhTORGGCA7IMykfne00V1Qy9o3zPiDICR47bbblOFNnMHkWM77LCDKrNx\nKupE4rlxlrzkkkv02ZGl8XTnuXGM8HRUnfjWm/NMOOARBcaYzRxGIffddttNvdE7yWmBVJBnnnmm\nph2CX0i1tPfee2vmiOYg6VdpNwIY+1Guk1qKQujIHkceeaQ6kra7bfXeHwMlit0zzjhDHeGJYho8\neHBYbLHF6r2k/64NCDDmkPLt7LPPVgcVMtcce+yx6ojRhubUfUsiqo844gidM8hqNHToUJUx6r6g\n/7BuBMiEdOmll4bhw4cH1qCHH364bnUbgEVZ21SSfOiRWAIj8e6L5CkjyUcX/e53v4skPVYkDNHU\ne/nFHIF2IiDp3iLxoopEqIwkP732d1F6RDJxR6IQamfTUr+3FG6LJN9uJLkmI1FY67OLgBIdfPDB\nkUx6kXhIp94Gv4EjkDcEpPBmJDlwI/G0jKQWXSTpViIRDKMTTzwxEuVV3h6npvaKJ1T0hz/8IZI0\nWYXx4n/+538iZAaXDWqC0k9uIwL0VfosfZc5DzmXPk3fpo93GonCMDr33HMj8ZTWZxUjT3T88cd3\n/HjVae+xE5+HOZO+SJ+ED+mj9FX6bCeQKAMjUWJHkh4xEmNqJN7D0fXXXx9JStlOeDx/hhYjwLr0\nlFNOiSRCTmVPicbU9VqLm9HU20n9vUg86iNJgRPNNddc0amnntox/N9UoDroYshg6F4kCkbHffqx\nOALk6gklcimSaJ5I0oFF4uCmelIxaOXqGbyxxRGQGqGROGPonC21ZiNJT1v8xAwdRaaQiJ5IUghG\n4jgTiYNJhlrX3U2RFJc6b4uzcCQOTpFkRKkLkFDXrxI/khBznWRNkUMHZ9KdOHFi4kz/1xHoTAQk\n/Vsk+RfV4CHe6pF43EXivR/ddNNNEcaRTiGeUUKpVUiRNAGReOOr0CLeNp3yiP4cjkBLEJDoQB0z\nJFRXF+AorCRSIBJvjkhSwbWkDWnfhHGRhZmknNExUSIgVVEuET5p39qv7wi0BAH6MsYf+jbzPn2d\nPk/fzzNJmjad6yWaIBKv8EhySUdSryzPj+Rt72AE6Jv0UfoqfRY5lT6cRxJvTlUA8iwoA8XjNnr3\n3Xfz+Cje5owiIDUSI8lKoUpJ5E6JAMqV4414P0d//OMfoxlnnDGScgCRRH1EHHPqLgQkDXQkNRbV\n8NOvX79crJ3uv/9+dRYST/1IokDcQNmhXVYi4iOJfte+iQHoo48+yuSTSuaiaKmlloqk7lt01lln\nRegmnLKHAM4Nkp5U+5OktYyktllNjWzI4CNpnCIJP1SLIBE9DFySsqamBvjJjkCnIYCih+gXCSmP\npH6HRsDgwY9hNI/EIINXmBTK1cUBRp6LL744cm+UPL5Nb3NWEZgwYYJ62BifScq3SIrNRniC5Y2I\nfpQ0BeqZLPniIxZiUochVwqFvGHu7W0vAnid0sfp6/R5vPLhAXghT4R3oqSp07meiAlJoRLhYebk\nCOQBAfoqfZa+S1QMfZk+nQfCy1YKJKuRh6wBp59+ekSUj5MjkBYCkm4/kmLjOmctt9xyunZN617N\nui6Oh0TXoqBkberzU7OQze91JNVutOSSS0bTTTedZlnJosMNY7nU41CF7fbbb9+REeH57UHptZx1\nAVGVM888cyT1xdK7UR1XljSxqqdcb731cmEsreMRO+4nZFGSEjmqk0VvVC3VZfDBoo4yinQ07KVG\nj1sEq0Xcz+sqBL788ktdtC2wwAIR3hykPMuqlT/5YhhIpGigGnRRXhF5QEoqJ0fAEUgXAal/pwsD\nPJVJmXjyySdHjCVZJxbepLTs1atXJMWk1UtZcqtnvdnePkegqQjQ50llDA/AC/BE1pVSRBDsuOOO\nhVQ/eKE6OQJ5RoA+TLof1qr07SxHyeAkttBCC6mxB6OPFPHOM/Te9pwhAG9IbR/lFalNl8m1Htky\niKY1Q25e1tI56wq5bS79AwMg6f1I95YlfQX6FKmZpYpaIsCdugsBnDkYu8gCsPPOO7e97AEOapRf\nQTZirZJFA2l39ZDanvbTTz+NpH6jOj1g7K6GajL4vPLKK9Gmm26qky0d1tOyVAOxn+MIRDqY4q1P\nTSuEEQb+WsPxWoUjYaiE+jMRwO933XWXe+a3Cny/jyMQQ4AxQopAqiIIb0aiaEn3kkVifCOtFQpu\nPJPzFtmQRUy9TflGAB6AF+AJeAMeyRqRBueEE05Qx47evXtHDz/8cNaa6O1xBBpCgD5N3yY/PX09\nS6mfqHdJHVDkbSItPv/884ae1X/sCDSCwJNPPql1JUmVdsUVVzRyqab+lowSUkRcU7iNHj26qdf2\ni3UWAq+99lpEtBr1cXBQbzfdeeedmmZ0ww03jMiY4tS9CFDPh+hd+me7an1j7Nl99901sufGG2/s\n3peR8yfHwD1w4ECNzh0zZkzFp6nK4IOn0eGHH66Wya222irC8OPkCDgCtSPAQIvSh7RNhORR4ycr\nhCDCJID31HbbbReR19PJEXAE2o8A3jfXXnutpiwgpz+porKSZxcvS4pJk74Sg5SnoGl/f/EWZAsB\neALegEfglax4JiPLk7sbg9RVV12VLdC8NY5AkxGgj9PX6fNZWMe+9dZbmpqKGiTUVHFyBLKAALLl\nSSedpIok1oTtNpASqcGamQiJvNblysJ77aY2EFFNxNpUU00V3XzzzW179Ouvv151p4MHD87Mmq1t\nYPiNFQHGM+qmzTfffG1J63fQQQfpWoRUc075R4D3SRrxSlkZKhp88PZnop1//vmjasOG8g+fP4Ej\nkC4CCNDU9UEBtNNOO7U9vBNPrplmmilaY401oqeeeirdh/erOwKOQF0IYPgh5y7GYjyE2q20IvoP\nA9Raa63l9fvqeqP+o25CgBqX8Ao8A++0k3A8Ic0s6Xs8qqCdb8Lv3UoE6Ov0efp+OyPukLNnnXXW\nCK9vr4fZyh7g96oWAWrlIGsyZ7XLkQdHRFKir7TSSs4n1b44P6+AwJFHHhlNMcUU0W233VY41qoP\npOnk3kcffXSrbun3yQkCZOpgTEO/3sp07ZdddplGE7fTCJqTV5SbZhJIQM141pXvv/9+yXaXNfjQ\nIRCKsZK3a7Iv2XL/whHoAAQwqC6++OLREkss0RZLP3lFSc9IrZDzzz/fU7d1QJ/yR+h8BBAQmZdJ\nDzlq1Ki2PDBRRixmjjvuOM//25Y34DfNIwIYbeEZeAceagede+656nVKbTAnR6AbEaDvk08fXmg1\nPf/88+pgxSKdtBxOjkBWEaC2DwYXUiK2ug4dvLHaaqvp+riVStGsvgtvV30IHHjggdF0000X1VLg\nvL47/d+vULyigN1zzz3/76B/cgRiCOB8QjBFnz59YkfT+zhx4kTlA0pKOHUWAszNSy+9tNb1KfVk\nk/FFKELXXXdd2HXXXcMf/vCHcNhhhxU5ww85Ao5AMxAQY2oQj8Mg6R2C5BoPkt6hGZeteA3uKzV6\ngnhQhVtuuSUstthiFX/jJzgCjkB2ELj88svDvvvuGyRdlG6tatkFF1wQDjjggCDGpiBKq1bd1u/j\nCHQMApJeKki6nCA1upSHW/Vg11xzjcr2F198sd6/Vff1+zgCWUOA+Uvq5gR4sV+/fi1pnkTzBKnl\nGVZYYYUgKZ2DpFBuyX39Jo5AvQiI8jqsuuqqYeONNw7InK0iKSYepAZeeO6558KCCy7Yqtv6fToM\nAfGADxtssEH429/+Fp599tkgzjapP6Eo8cMnn3wSJJIzSO241O/nN8gnAvRHMWoHcbgOYhxM9SG2\n33778PLLL4cXX3wxSAqwVO/lF289AvSllVdeOUj6/yBlOSZpQFGDz9NPPx3WXHNNNfYccsghk/wo\nCwckV50qquNtWXTRRYOkudFD33zzTZBCafGvw2abbRak8LUek/okquSWgpkqeK+//vph3LhxFZVX\nko8zbLvttlUJ6SjvJVd7jzZICq8w55xzBgnjC5JCq8d3lf754IMPwh133KETlqT1KZwuHjhB0oMF\nKUaq1y58UeQDwhNtGDRoUJFvm3NIQmcDuBr17ds3SB5V/VdSmYWHHnoogL+kD1Mhst4Fj1irg6QZ\nDOLlroaLX/3qV3bLACZSfLLwf7xvFA5m6MMPP/wQJLVDwAjz2GOP6TOl2TzJ0RyklkCQonH6Pmab\nbbY0b9fwtRGcpNhdxetgLBNPtIrnpXmC1DwLko89PPHEEzqGVnuvVo0X1Y4BtYwr1T5jsfPKjRfl\neLzYtao5hnGThSvjoNGtt94apMC6/atjfF4EIkkbELbYYgtdGKc5rhs4kuYjrLvuugGjT9oCqt2z\n2j1G82eeeabH6b/97W+DRFIGyZvc4zgyDnMxxDwiIfb6WaKaw5Zbbqmf6/lTap5OXksKy+p8Lrmc\ndexPfp/H/8vxsj1PMf6z76rdlxsX8sTLyHH77bdfeOCBB1Qeqvb56z0P/kBGlhQj4Zhjjqn3Mk39\nHbIi/aYaWnHFFcNCCy1Uzaklz5EaEOH2229Xpft6661X8ry8f9EqXjScivF1HniRtZNE+wSJumm4\nbxkW5fYSmRsef/xxVbqI13m5U1P9Dvn0vffeq3gPlJU4pLWTqp1TG21jOZ5hbXb11VcH5h6MD5KK\nOyAr1EPl5q+srl1ZtyP3weebb755PY9d028+/PBD5ccRI0YEqX9S02+bdTLr8iuvvDJIZEiYa665\ndI6WqA01HKCkbTYxFyILIGP/8Y9/bPjy5fozYxBrB9Y56B5QFDZCn376aWBuXWeddXpcJitzAEZL\n9EBnnHFG6g42rP8xMIFxGv2kB8BN/kei6tTxGBmJfoFTcBpUrm+i30V/O/vss6sjxm9+85u6mlBJ\n35iVvomenSCLd955p4deoq6HLvEjZH+pgaZOJltvvXWJs9I7zPobwz1rcXS+yPGS0i5MNtlkgbEe\nfbBRvfr5cn3q66+/DpdeemlAlkAngM5fIrztlnXti8m87Z6/kUsYh8F6EkqG/lCsj4KWYglMfpWp\n/8VSHw0bNozoJN3GjBkTiaK10EZy2pF/dskll9Qwp0ceeaSQrupPf/pTJIaf6KyzzopEyRoNGTIk\nEoW3HitcoMgHUQhqiCb3qoZo4xFHHKHtk4Erks4WicdKtNFGG2mqvP333z8ipVY1JMJmJMJmNMcc\nc0Qy+PX4CXmowUEGyB7Hi/1D6rBVVlml2FdNOybCsOb8lcErEkV9AXdy8VKkTDxLNWf84YcfHgnj\n1ZUOiHQMIlho3QjerUSn6Lu0hwAvWcxEfEcxK95x1ok83vRD+nXaBH7U7JHBL+1bNeX6pMGRBWr0\ni1/8Qvu6RDVEIojrJh5n0WmnnRaJwBqJcbEp92vkIqTCnGeeeSJRJtd0mVaNF9WOAbWMKzU9aOLk\nUuNFJR5PXKbivyLARuJVq/0nmR5CBI7o7bff1jyojKXiMFDxelk6gbmF4qRiREi1WcgH9B/qjmWR\nZMEcHXXUUfqOSdfz6quvajMJd6ZmGu+WVFri5VSYlzjh22+/1VBoEUJ13qj32crN0/Fr0tcotEh7\nyKncKVSKl3m+cvxXy/NXGhfyxsvwEjwFb6VNW221lcp/yMdZIeqQwQdiZFUeRS4X5ZoeO+WUUyK2\nffbZR1NRnHnmmQ01m74hBja9NrXQOplawYvgV46v88CL8AJrIngjbWI+EgWHYpb2vSpdXzxAdT0p\nGTwicQJSHoMPWVeNHDlS1yHUGJh55pkrXSrV76udU5vRiFI8IwoUrWWDfICcBU6kOWN9WytVmr+y\nvHYljTD6oVYQaYdYQ7Ur5SH6Hgqri3NYdO+990ajJHWyGLz03bPeTINYc80777yROC425fKl+jMp\nzlj/cx/6MmOSGJjquudnn30WHXrooZpemusmKUtzgGQliODhtIm5RAw+ad8mletLlEC09957a79A\nV5cWleqbjI/obWkD9cPEOFDXfFmNvjErfZO2oqccPXp0WnBrGmnG01bL/tQrR8agXjk6X+RFMehF\nw4cPV306Y098PK1XPw9wpfoUujXma8laFomTl/Yp9IX1UjmZt93ztwQMKO8WS185SQ0fjBkoSsQa\nVy8WLfsdbWSyShpA4g34/e9/rx3LjmFgwdgjYfx2SPcI4kyAvKxSdOGFF+r9KGBYLaGAo43J30g0\njh5HgKqFxDJb9HmLFd2FcZKEQixuGEt+34z/YbqDDz64x6VQ2IsFNxJP9MJxFBwoximqVwtR7JhJ\nQCyYhZ8xMWEMKNZvEaDyYPDhYVho0T/TzJVMH+Ae3CtvJFF6yjdMGEmiCF4WDD60i4mlVoMPv2vF\neFFqDCg2XhQbV2hnM6nYeFErj1dqD/mU2XbccUftP0mDj/0e4yHjdd4MPrSf8XWHHXawR0llLx5R\nOvZm3VC87LLL6ntEmRwn8fDT42+++Wb8sH4eMGBAVU4Tk/ywyIFS83T8VGQO+toVV1wRP5zrz8V4\nmQeqlv8qPXwt40JeeBleQp6Bt9Ik7kN/q8YxKM12JK8tEXmRpNPqcVgiebSt4pVXOH7RRRdFKAMa\nJRyRwKEbDD5JORzsmsWLtVwr67womRO0T6Q9r+EASJHmLBBrMXOIoD0oMeCLeJ9hvUyN0SxQNXNq\no+0sNX9JNoRI0uDo5VFwDxw4ULHaY489arplLfMXF87a2lU8r/W5JQtMTc9dz8nijV6zbqCe+5T6\njZQz0Hk5qVNAd4SBI070Cd5tMwhna+p6NIOK9WdJI6k8jv4F5S/GrFlnnVUdoZgbayVJWaa8wdhR\nzOBj18vCHIAxg3ZSOzktQsEtUZG5duRirAOntA0+8bmG90H/k3RUhVeDPha9bK3Gs1r1jVnom9Tx\nSXP9Ti00nJ1aSegxJX2tvkOc75OE4yPOXejpoUb08/y+2HjHceqTY/QxMv07QSG1Ui3yczvmb8Z0\nAgdw4knSJMmDCYkS40Qh1YkwfWZpxhln1LbZvlhDxTspsBkRbiWDSCC8K07ULxGLsqa4ih+Pfya0\nl9Q5pF4i/L8aKtU2ie7RsDZSxBE2XC2Re5QQuCQlU3IRFiweMsnTAikESIHWagIzwpTJl21EOF3/\n/v2DFC7ukU7Jvi+1l0W/piWx9H2cRx0JUWRryF6p3+XhOOF49E/C59MiwrhJOyYKzrRukdp1xVBV\n8trwuRTDLvl9K7+oN1S0FeNFsTGg1HiRHFdahWGzeZxUf2wyAbfqEVp+H9KrEWIsC7nU7i2LWk3D\nSXqLLJOlthOvzB7NFEWN/i9RNT2Ogxn5byX6tsfxev8pNU/Hr0dYO2T7+Hed9rlZ/NfscSELOMNL\n1EeAt9Ik0oyQgog0HVki5spqUkPKYjiQTqdRqndubvS+Wfl9s3iR52nmtdqJDzwBb8AjaZIoPZo2\nxzTaTlKoVKrbSTo36oxlgaqZU9NoJ3LBzjvvHKQgsl7+l7/8paZPZ94mZVMtlPf5i/SzvXr10rV8\nLc9d67msgd94440eaX5qvUaj55NWSJRnQaK/e1yKdyjKw8IxUS5rer9q0iMWflTmA/0qTZmQVI6n\nnnqqpjNCl0RqI+ZWZGDKOdRKpGUiVVoeSBzBdJxPpn1uZttJ1UwqMWS6vBJjLVRM15jmM5FOjr5o\nNP300wfSj5XSi9h5yX0z9Y3Ja6f1P/2lWr1yPW0Q58dA/28lkS6X1GIS2VN0LJeoG9XZWTr9RvTz\npZ4L/Top/MWoXTiFtLpQrf2K32Rd5oVnec+87yRNUrlMPJw6qjhecvIkh6FElQSJZFJDQzw3rESB\nlCxkhQIeEMVDPJD3UVJLBPGIT+JZ9f/Uj6BtCBRxgjlYFKCQp7AnCqhKgy7XoH0Mjky+KG+pQcDv\nJCopSBq4Qs5d8UTR/OXimRS/rdY9YJAUC6vm7IwPDGIlLNTdYbHM5F6r0gC8IQkH73FfCd1UYw/5\nOosVmepxsvxDwVPwMYa178GTwQMDmqREs8O526NgF48GzTOZVuMnSg5qCZWta7BLq02NXlciNrQ4\nIoUSIRZiDPQsaOHTdSSvsOUopm4RNTsknFfr/SDwGok3V5CUbFqQXrwfVYHOAM+CLymEIzSW4hm7\nHrxD0Ubqg9E/MehV4mf7bXxfbLxgUQTfIGCiNGSsqEYRnxwDSo0XyXHF2oNhdezYsbogg5+ZTOmz\nRlyfWmPseWbGMfFYs68r7judxysCUOcJzG2M3+TSluiyOq9S/mfwjuC77gAAO9RJREFUTC3vsvzV\n0vuWAtziPab51yV0vFCk1RamElWjde9M+ct4QH56+5+WVZqLqflzzTXXaD08lPXkJhbPz8K9ij0d\n4wW1yFCkwRdQufGARTj8ydhDLnAcclCE8HzUAYxTqXGN+1k9OxQ2a6+9dhDPvSDeV/pzrouTD++W\nPNIoPqkrAzXKy3qRJv3p5HEBngL/NIl6kuRCt8V8mveq5dpxWbPc71ic4ZQFlerr9vtKc5Sdh9wA\nT4E98meSp+w89rXwonhNK89hoEKBIdHneqlO4cU4Lp3wmToW8Eay5mqzny3NubnWtqKEqYYkHYue\nVonnkEN5PuYX5kPmKXgKmRRZktqkKJuZa+LKUHiPNTVzDutYZGXeBUbgapwTS/EajW7G2hUnIZur\nDS9qS0h64JrG0k6Zv3g3vOc0yQwqGJfaRayn0CfglIr+wmRqFIdW2xrFPmtD+iA1hJHlJD2k9nWU\n1+hJJF2rynAUSoeoh8Wa0og56MYbbwwYjKhRR581mRAcmJ8gjmF0xNEVBSlrMO6B3IpOq1qSKMMe\nci6/o741ReOb4VBRbTvacR5yNO8JXkyLrO/Ga0qnda9S160kt1da25S6rmRGCOPHj9e1DrWSMcbE\nqZzeJX5eqc+sYePEvCFRP4E1XC3ULH1jLfds9FzGOus7jV4r+XtwxHBtcmjy+zT+Z46QdMy6npTI\nv5K3YHxl/ofq1c+XvLh8Qf14KSXS4xTW6ox5SX10j5Ny/A/vORnUwuP8r4tp7MHwkk+r08Vu07aP\nDPgIsCzeJJ9nkBRQBSEfIa6URztRKHgNr7766jrhSthhQ0IPQi1twMuKDgkhRFCoj4KIKK6ZmCkq\nW+59oJRmQcl5eCJBTNoIBiiVYCAEbrxQJGxRjXnJyB+iIlDQInBTzAqjEcYvo2OPPTZI6J0q0FAO\n8X+tRMEwCIzjZJMiE0k1hAWYwSt5HX7LtWgnAlNeCQEOZUU8Kq3Zz4LAipCZZ5ySmNC3WXBKuKX2\nYYQRJn3J/R+OP/54LcrLb1CeSh0t5WGMQZJrNxBtByFYs4hDUSx1BIKERKpwg3ExWUCzEs9wPXiO\nMQblKgIWUWiSJoCvaqbkeMHigWdEUUH7Gdwl9UZAkV2KSo0BxcaLYuMK16UYHOMN4wuGVRYdGHXg\nS4h2UOSRhT7jLMYznr0W6nQerwWLWs61RUyaizYMexg6sk5EAjK3S25kdXCw9l511VUq5KG8ikdU\nwDfwp1GluRgjMgoAqcOjjiNHH310kNpBAb4pRcccc4waoDAKYbCRsHI91Rb3yd+Bs6SGVEMukUpE\nx6IwO++888I666yjY7j9pty4hoKN52bcQwGBEg1lBvM4ize+h3ge+Nv6TzN42drXjH0njwu867jR\nvBl4Ja+BwaTYIiB5Xtb/L9fXaXulOcqeDyMoc5nU81Iehg9KydrV8iJOJvApYzELStqKkdnGhU7h\nRcOwk/bwRto8yLwk6WJzB1s5nsPxCFkP+ZN1MjIvxh1kQxQtOCUxtxJ9fPbZZ4c111yz4IAgNQtU\nluT3rK/JooEyhmswx7EeKkWVeI3fNWPtivKk2ByNc5ikeivVvEmOd8r8heKwXKaFSR68jgNkIYBY\nC7eLcO7FMINjHwY/+qaRKQpxsDInQwxh6FswEKKLQIeCfAVhlAE3jjE/GWEU5fdcD3mQeQO+sf5G\n30NnRZQd0YeW1QR80INgII0bj+y65fZEqCWJvozcFzfEJs/plP8Zr6x/pfFMOExBFrWQxj3KXbOS\n3F5pbVPq2ji5o09hTYKjPNfBSAhV0ruUuma54zhfcC90jug6aqFm6RtruWej5zLWWd9p9FrJ3zOG\noGcmkKBVRLQS8zfObOXmC9q17bbbarPq1c9X+0zoPDHis1a3vlvtb/N0Hu+5qLOMANCDqOshA7/m\n0uvxRQb/oc6CvIRIFLclW3fuuedG1N5JEnnzRbjX30tnLJurkrzOoigpXIIC2dxXlL6FY6U+yKCl\n55KTXCIrogcffDAaMWJEJIytBQGt6CP1M2RBHslgXbiUCAP6WxGWC8dEkTpJbRDykdIe8hQaUTRO\nDD32b2Ev3iWRWJIL/5PPVQSVwv984BzaC4lQofkAReDX//lD8etyVCyPoghMWhsq+Tvyv9J2UVon\nvyr6P3nuOZ8cjEkSRbN+l6w7IgJYbmr4kEdbBr2IfpMWiSeRFmkUr/a0bpHada0Giwi+WnxNDJ3K\n//QJy1kpk732A/qcGFUj8XaJ6BMi6GluZJlYC+0TL0I9VxSpeswKvpPX2IjriCHI/o0q8QwnSro8\nzeMLDxtxjfh17Hh8X814QY5gUSJFQ4cOjf80ovi3TJ5RvG5JsfEiOQZwkWLjRXJcAUvxxo6opWBE\nTmTuKcYyPSQL+kg8PO3rSBa50dVXX134v9iH5HhRD48Xu26xY6KY1/ctBs9iX0diONTv81jDh3zy\nFJ9Ok8TYoPNUmjXGmtX+e+65R9+lOFDoJUVpGzFuiPFUj1MTAOK4GDD1M3+qnYvFs1OvI0ZN/a0Y\nnAvXSPIddVMkeqhHbSjuw7hVjj/AmXMoFizCs17f+MN4rppxzeoPivG10EZ4XjxDexTxFOWDjpmc\n1AxeLtzs/3+oxH/J8+P/23NXO/fnhZd5x8h+8FaaJAYO7Uvx+SHN+zVy7WI1fLhepb5ezRyF/ANP\niRKt0ER4iWPGU4UvYh+q4UVJlaPF7u1n1H/guhT+NuoEXrRnsX0lvs46L4rRT98TPJImUbOVsTyL\nVKyGD+2sxHP2LKynxVmwUCNWFNxaiBqZRBQQepooQVVejK8hWd+KgjviHRixtoZvLrjgAjsUJefU\nSrzWrLVroQGxD6Jo13U42FRLtc5fXDdra1eKi/Ou6CtpkzjfFtZ0ad+r1PV5XmQi+iIbeiDG9DhZ\nXSP0QkY2nsTrxNn7R/40gjcoZG5EnxUF6SR1vliDIquZDMj51OOwulL2++Q+ubZKfm//MyaJQt/+\nrXnPmhR8sl7DR6IJtZ3FagDX/NAlfiBOIy3jkWJNKCe3V7u2QUbkfcb7L30prqdj/YDOzaiU3sW+\nT+7L9U3WbmI81TbQDtZatVCt+sYsyCfIBrXWKqoFE3RG4nRYy08aOleie/T92fq7lovVop+PX7dc\nn0LvR/01dO/0KXGqj9A/10uVZF6u2675mzqRSf0g7fmZPHgPIuUQngN44nQyYTnG00KESK2Zglce\n6SIEk0keW4TOQioJvsTzgygJjuPhUQ1hrSYs8YYbbtDIHiJqyBFLai0I6zmegHEPM9JL4CGFdy7e\nIaWISJ5iZF4i8e+S55500kkaERE/h/BiPIkhroHXCp6QeGhBeGPVSqSbK0ZEHUCGQ7Fz4sfsOsWe\njWvxfOahHP9dHj7T98h5SZ0o0vClRSI4qvc7kV5EmeWRTjvtNPV4wusJ71kp+lZ4DMOOaDVSNOHR\nROQe6ZdEaaORc0TFsBF2SoQKkWGQWcXhRSM8F0l1aVSJZ+w8rhVPEUP6QsKTq6Fy4wXppxi7kt5Y\npFbD61EWHmVvkRwD7OQkTyXPw1OTMQtcjUSw0vETb2YI3PA6w6NTjGw6fpHCoBbqZB6vBYdazsUr\nlnmC6JE0SQrK6uXz4B1D1Ctel0TyiGNFICqX+V6Eak2BIUoLTVlGGjOigYyqnYttnCF9KhQfM+xa\ntmfuJ3qQKAsjSzGZ5Dv7nj2pHPmeMcpScTEeQTYmVTOuIdfhZUUfMULWwDNPFr96CG9U0pFYWrtm\n8LLdqxn7Th0XiNiCjLeagVWxa1iuffp3XqlSX69mjrJnJ72hEXMzVG5+roYXiQrGs9HkC/ge+ZmI\naqNO4EV7lk7Zi6Ojjt/wSJqEJytpPU3eTPNezbp2JZ6z+zC3MU+ZDM18wxy50EILFY7hwUzGCXF+\ntJ+ptz1zG6mvjPDA5RhYlaJKvMa82Yy1a/L+rDNFmaJpaGxOSp5T7H87t9h8n5e1K5HGZJ8gYiVt\nIgpZnOvSvk3Z6xOpg/wID7COFEW0RtmwDkpSsfeaPCf+P3IXUaZxLLkGY1DyWmR7QVZDNwPhOc8Y\nQqaFRgm9DhlTiFbvdAI/xqnk2rmZz41ukEgs05c189rVXKuc3F7t2qbYfcRZXfVTfIfOhagwi6Th\nmK2HknoXvquVWKOh42CeIOUvkaDoTKslG2uT59eqb0z+Pq3/4WfGmXh5gWbfiygpUk+2imy9apjX\nct9a9PPVXpeoPnFWVn3VGWecoXur9VvtNfJwHnoBMmaRjSxJkxh8UIyidCZdj6UIS/4oK/+TzoiJ\nsVyHQgFKyFgxwshAeBeKIBZzpF5KFmEkRysKVDqIeK7rRgguShEUmgxE1RBCL/V0CHlHmCVc3QhF\nP+moig1ShL9D8TBg+12lfVJoSJ4PbhR2mldCkOPE74xZOU6bmSTFoq/KsnrSglhaOfCMk3hI6b+m\nxIp/V+wz14GKhctyLRTsprAq9vssH8NowfugoGLaxAKX3NnxGlZp3zPN6xNqDI9BhIVCyX4Atgi2\nEvVX2FD6IjhjoChFXMcMwdXyTLFrwVPlxqr4b8qNF5YeJjle2FjBWFIPVRovSCPHpJlMCRAfX1Gy\nYxCWqAVd/LNATBqOKrWtk3m80rPX8z35mlEWI2hj0EiTSDGBsgP5AH7KMjEOwNcYtUnZJt5thVpc\npMhAyOY4qTqM/2uZi22csX05LOAdUyrbeZX4zc5L7m1cszGpmnGNsYJn5HmRiTAoM4eioLvsssv0\nFsg/AwcOLNyuGbxcuFgTPnTiuMC7g5fgKXgrTaK/kVKU911OkZpmGxq9dqW+Xs0cVawNJu9WOz/b\nNeK8iFxMqkh4KC5jILtTx8+oE3jRnqUT9vACPIFxrt4xuVoccIxhrVNt/Zxqr5vmeZV4rty9i8l+\nrNuLrd/i18EwRIpR1tjFqFpea8baNXl/5FvSGVl6reT3pf7P+/xFelzJTqIpr3k/aRNrOlIDPvro\no2nfquL1ScHLugtFNGnXivFvrWMHcxVUjVyIoZjUSDg6Qjg24BjaKKGwZ+wzGbDR62X59+ie0HuQ\not2M0mm1l/UFa2DWZq2mUnJ7LWubYm3GeQ45hnos6BhYOxAcYGTrIJOJ7Hgje3STpmO19IjVXI+x\nFlmuUX1jNfdqxjk8I3OarUObcc3kNdARYGA2/VHy+2b/bw4ccaNgLfeoRj9fy/XsXPopZRtwRMY5\nK9lH7Ly87iVaTR3cGQeSNInBhxNQAjPBoEDCczirxKCNYhTPh1KRCnjWxRWURC4lF3VEr2BRhKzY\nlz0zxiBq2yB44Llum3nFNsNbEkGBqJSnn356kraZErueqJVKAggTAAO2pLGwxy26x8JOHQ6soVj5\n8eqPeywW/VHiIPVSILwC4mR1J2ox+KB0Tl6Ha3Ktaq8Tb0MWPtMvyeGL8pGJNG3CGwNjB0IJgjXK\nzzwTPG5RJqWeA0GEnMmNPGu1PFOqDc04jgcRZFF4dk0it1hM1zNWcI1K4wVjBQt18rmXIiZTFoXU\nHMK4JmnGJql/VOq3dhxhrRN53J6vmXtJT6ReQbzzePRGM++RvBbKDrwS4Tfun2WyeR1vYJw6LN85\nCzL6Ko4cEItpKI25GNmEnLoI28WoEt8V+038WLXj2r777qtzJHW1kFtQXBHZzP/UF4C3rTAx128G\nL8fb2ejnThsX4B14CMEcnmoFUWR3wIABGrFd70KsFe0sdY9Kfb2aOarUtRs9Dr9AEyZMqHipvPNi\nxQfMyQnwAIoQeAKHtrSJsR4vU2TvPETJgkclniuHWam5rdRxuxZKGKLvbV6247avlteasXa1e7Ln\n3WHoqUfZnuf5CxkGWYqIlyOPPDIOSWqfqXdGPVCiJVutlCOyIBmhgTM0hhH4AT1I0vG1Up9OAmVZ\nW4rJhclrcU+i96knhIGaTDFkmmmEaP/vpK4jTkDFDLONXDuLv8WRHR0RtTTTJpw+WKfj3N1qKiW3\n06ca0TNStxgMqWdMRgT6ZCsInR76qmqzANGmZukbW/F88CG15liLxddfzb439VsxwlDTuhVERguc\nm1hbloucj7elVv18/Le1fsZ4Dz900tiHXp7648yZ6AKTVNTgw0lMbITU4jVeySCQvGgr/ycFCcIA\nIUzFiMk0HqaPcahYyiOYAUIpFCc8AlBaJgmvDJReFHwtFyZnXrjJ3yf/5zmIUMHiGCcMLQhZpQTf\n+LnxzwzuScNW/Hs+49XIwIjlHKaMExZn0l+BLUYIwvPxWiSskvQ4KIlqIamVooyF4SxORJEhlMdT\nX8W/T36GObkWbY57FyA82eIt+Zss/4/xAWUPwhxh45YeqBVthi8eeeQRfaeEkmZdedsoJqRwQalJ\nKsY4MeFaWp348WKfq+GZYr+r9lg14wVjBZT00mYsoj9R5LBWqma8sEKlGAnjRKFrM5QztsKXjKeM\nZfSrWtODdhqPx7Fq5meURvAwaT+Zg1rhdUn76SukQWPMXmONNXQR2sznaua1EHDpt3jamfGH62P4\nQeDDIz+ZSqvZc7GNGXhK4yXbbKp2XCP9B2MDxi/kJZ4T2QZ+xRDQv3//Hk1rBi/3uGCD/3TSuIDi\nBt6Bh+AleKpVhKIZpSXya1YdukrNg5X6ejVzVFo4EwXPWAy+yM5xwhhvKRg5nndejD9bXj/T9+EB\nHNhaaXwhnRCOBgcccEAhRVMWMKyX59JoO85MpEsv5cRVDa81a+1qz4eMC0ZECMQJJ9BqKK/zF3oE\n5AQcUsGA52gVkRUF585WZ6LAuDNkyJBJDE0Y7UgTCBkONnfH9S0WMVou5b/NVeY8XAlTnJRwbMRI\nwz0biQjGAYk0cei34mUE0O2U0qVVal+WvyddFtHNKENrMRzU+0zoEdEzkOEC+a6VVE5ur3dtgwEU\nYw8RKBYdFde/pfl8RHmio0EfXS01S99Y7f3qPY/5BEMPRP9MkxgzcMYlqxX8kDYxPmFcYlxkrClH\nliKzVv18uWtW+o71uNQXqnRarr7HiZOMO6VS+5c0+GC9JQWKFCbS0CcmXEu/lSUEYGwGICxayUUW\nlmiMCRhMjKSoU6B2SdLwQCQPCjMpDmanqqELKxmTfDEiFzfEfUoRAxVUSZl+8sknqwCBccWIARXB\nl+/Mmi7FxFVpHRfOzfvFomX4Pd71eEiZddVC6DmXa1hEFOlEuBYLHzw9GAgGiLcbx8CVPROX3Y9B\nF2GIrRZikqUPMeDYtRCGMCYyQZnHFteklhKePaWUYxhIpNB2j/y+TKp46NVaL6SWZ2j2uQw45NWk\n7URNpJ2OqVj7UaCgmCcvMwIoAmAjETDF7tHMY9Xwk/X1OD/QBiL54GUGRfohYclMfvQ3Uwab1xVp\nj4y4Dnxj/bYSz/A7jCBSJK7HggHrO4J2uUVANc/HO0M5i8EnrkQi9QERgTyPUanxIj4GcG6x8SI5\nruDViKKQeQEPZeonobhgMQi/QhhdyXMNMZ7Ck7WOFfy2Fh6vNF5wPSPGDajcO7Bzs7pnUUZ/xcuK\n1BJjx47ViKhWtpcFDWM37x3FNeNGqxYAtT4n6TiYy4hajhM8hBAcr9/D99XOxTbOwOtJSvKdecWi\n5IOvwMoWgvBtsWtwTcYQxp3keMR3Ju9UM65xPkQ0J4obU6CgQMDYw7hHDbA4NYuX49esxH+VeLmW\ncSF+36x85r3DK/AMvAMPJZ2M0m4rMi2KOzyoyfOM7Js1snkQPopTpb5ezRxlvGZ7rm8R67aP39M+\nV8OLjMekyiVqCy9wZCvkBZ7DogvtennnRXsO9pX4On5uFj7T5+n78AC8UMwbMs12Mv6iDGFuaqWx\nqdwz1ctzXJM5ivnQZEa7DzyT5CnOS8pfrEfjqYip3UIK9bjBJzmnVuI12tSMtSvPgkMN63zWRqSJ\nY2Mch4fjRvNOm794V8hNzFNE7Zuxw95v2ns83olmYc2B3qZVhIMrazXeb7xPE71JSiTkb1N8s3aC\n0NXQ5+gPOHLMK+moGGdQYpLWk+eAmBOQA5irqLeCzsec93BAwoDIHMJ1TE/D77gf4wa6gkaie+jD\nvFPWZbTP+jMZRngunBaMKvVnOy/L4z/yNboVMtSg22oVId8R4cM9W5mWsJzcXu3axuQuxm/I9vQX\n1go4CtNnee98h27Y1kNJvUsteFOfGD0kvGeEfpCx17Id2fFyfbMWfaNdrx17+gdjK2ND3PCaVls2\n2WQT1R2x9i2WJanZ9yX9Hw6VBAhg2LI1q92HsZH3aLaFWvTzdo1Ke+5J3W0coo2Q/RmHLcOHHS/X\np+wc22dtzGMewcBManbmr6IkE1RFEuNIJBNTJDkcI4n8iGSyqvibVp4gA4+2T5g8EotdJB0sEkV6\nJDVRJmnG3XffHYlXdCSRS5FMApGE0kVi9Y5kgo5EgVk4X4CLxEIZySQbyYRYOG4fpNZPJBN2JKDq\nJoanSDqAfa17Gbwi8XQvnCOdKZIcmD3Oif8jg2gkQkIk+QUjCSeOxJMokqgaPUU6bSSdU9vDPSXn\neyQGkUgiXSKZvPUeEnUUide3ni9CQSReJpEo8iPxaohkANU9z8TvxeKqv+dk6SB6HsfFcyoSIVmv\nwR/uKwJNJAuTSAalSBTleu/CCUU+CNPqMyS/ot+I4isSIV7bIsbESAb35GmRpDTTNkq+2km+swPC\nvJEsCPR64rGs9xNFqH3dYw+m4q3T41g7/6GfyGIlkkVmJAqMSLzP29mcwr3FC1XfNbzAuxbLfOG7\ndn+QmhPa7+BH+qlEpkWSlmiSZknKNuUbzhFDr54jytLCeSKsK6/zPRs8I1F0+r0oaCKJpNPjEpId\n0Z8k6kp5gnPFsyoSYVnPLccz/EbCufU6YmmPREDScdN4TwxOkSwiCm2yD7WMF/ClGLkjiWCILr/8\n8uiSSy6JJAVnJAYgvVyx8UKMziXHgOR4UWpckYWIjmmiKI/Y1llnnYhjRoxLzBUS1RNJJFAkE34B\nXzsnuS81XlTL49WMF2L81vGTPsG7ZGxlLkgSWPK9CLzJr9r+P+OGKA8jSXenY58sPtveJhrAGM48\nI9EjkXjqZKJN8UZIOLmOs/FjfJaFivbl5HH+LzcX8z38hjxEX0HekEhiDut8WWye5jvmTjGCRqLg\nj1ZcccVIarWpjAEf2xjEeUa0D/7hHsg2sjCIGAfFQKPHxPAbSaSInl5uXLPrsUcOQCaJE7wv3mXx\nQ/q5mbxcLf9Vw8vVjgtZ42VZYCiPwCvF5J5JXkDKB5DHTjnlFJVDkO+QJ9tN8JEUj9b+Tb8XpYnO\nwfF2Verr5eYovkPu59rMU8j8zJnwMMdEoRmJ4i5+O/1cLS+CKXItsjfXYy+L+qKyVCfwYrV8nRVe\npI/T15G96fvtXsuy1qItohSMROkxSb9rxQHkY+Q1SZ2jfVYUT5F4c0fMm0bleA75lrU2/V0cCCJR\nCuqzMH9wTJQPen36uygc9RhjoCjx9fKiVI/EoTESZbaui3g/rOO5LlRMluU9VuK1Zq1dJQuFylw8\nS3JjLhflkbaTP82cv7heO9euyJf0Cdogxgea0za68cYblU8kvX5hDZZ2YyQ7QSTOQKpLEkedSBSW\nKq+J4SAS5XaP23MufUMcZyNRYup3yIj0c0lrFImBJhJDTiQGLNVVsE6FJk6cqPoofsvaU5yIte+L\nQ0gkhmDt+3ri///DeIs+RgxB8cMlPxdbW8FfyX5s/6MXilM1/VnqCal8zTVYX7E2LqaLacccgB4N\nnYEouIvOwfFnTeMzOhQxoun4IUbjNG4xyTUrye2V1jbIYOL8pX1EHDwj3i8kjp0qz9CnmLfgSYkm\niMS5Rdc/rKmtD6CbietdJmmkHCjWNyVlpvILekj0peIUoXxT7PeV+ibzQzX6Rq7d6r5J29ADIR+C\nYysJWZb3ytguxrmW3FqMEZE4PEW9evVSvTl9CT0jcrcYwwttqFY/X/hB4kOxPmXPi74K3b+kJozE\nWaOovFWpT3G7amVezm3V/C1O1sqLkq6S25YkPBKqIvHIUaGOyQtFAwNpu4XlZMMRmBmsxEsi+VXh\nfyZq8WTS/xFAUbSgCM3Ks9AOGEC8cCMwb4R4ThOaK12HiQlBpZiSHyU3CmoTZCpdqxjTxX+DsALT\nlCKeW7yftY+VOseOS7hnxYmlVUxnbSq1R4mMYk3yRqrBQtLjlTq1bcfpLwgMTLgYVTB8NtoP2/Yw\nZW4Mz1fbn0tdphzPlPpNs4/D4xjkxVuj4UvXMl5gfIgvdO3mZhBjQW7jrH1Xal9pvKjE47WMF6Xa\nYMdbLfjZfcvtUVKiNIQnEdIwxmaN6H8IbxKpqYsrFrJZIvpQMSon8DZzLrZ7wx/GqyyIihl+7dx6\n9tWMa8g9SUI5lqQ0eDl5j+T/tfBypXEhK7wML6BwgDfgEXv/yWdv1/8YDSUSPkLRy0K92X0yreeq\n1NdLzVFptSd+XXgMw2RSMRg/h8+dwovJ50r+325epE/Tt+nj9HUzlCfb2Y7/xfs7mmeeeVQ5UMwJ\npR1tKnXPSjxX6nfljmPwwegFYXyt1dmmHK81e+1a7jn4rpnzF9drx9oVXhGPaFUgYXgrJTvRvlYS\nDnHwL05mxQwKzW5LXI9Ev0RXVMooi6wYd3yztiBXmQ4Gea+YfoVzcfpEMQmVugffodjDoaBaqrS2\nqnSdWvpzpWu1cg5Ax4QeAyUvivV26vdoC8ZCxjiMeGlTNXJ7vWsb68v2DPSPeqlU34RH0A9WemfV\n9s1K+kba38q+CX9jSMZZQCJf6oWvod8xtknElDo8x8e5hi5axY8l2jciQAOnqmL6o0b186X6FE1j\nPVBJHq+2T1XxqHpKK+Zv9Mj0JYxolXimaoOPPSCMiNcpVnMUwngxFFu02Pm+7z4EYDo8ceolBH6i\nnGziqvc69jtJ49XWCB8MC3jOIKwyAEhe4qY9mz1js/cMxghMeOxJ6LcqnN9+++1m38av5wiop09W\nxgsJH1cvpVqVDs1+jUzceIQRvYkXkBRA1IipUgvGZt+/3uvhxSipcrTNKLlRejp1DwJZmvvbzcv0\nfXgA/oUn4I2sEotiFOJEoaJ8xks3L4afrGLa7nY5L0bah+nLeJfSt+nj9PWsEfIGSkEUlJKWOuom\nWTtu8Gn3e8kSz4BFq9euRBHjeU2GAnQ7WSNJ+xdJ6nHlZZxCu42ITrUsDtU8e5b6c6vkMaKnyDaA\nczqRBVkhIkqJZCSrC8rnbqdu7Js48mNoITtEsUjyVvYJDNRkuGGOKZZhopVtada9stSneKa052+y\ndzGmSImFks4EcWxrNvjYjzH84HWMEE3YKmkY2h32a23zfXsRwIOOjo4nChEtxbyHy7UQL5ZGjYiE\no5NCh1BsDC21eMWUa1u132GsuvXWWzV9HZ69RMWNkmiZZhmxqm1Ho+fx7hD8SUFEuC6pEjFYlfOM\nb/Se/vvuQiAL4wV9mnQjGFaIpEl6MrXqjaAkllzlqqAiXJ6IgCwrikvhIrXgNO0cYwYh/3gyVQrx\nL3UtP54fBLqdl+nj9HX6PH1/bUk7Cy/khYjKJC0AY+Acc8wRSe70op54eXmebm5nN/MiDkv0Xfow\nfZk+XW3EcTv7DKnCSTGOkRgDENGBnU6kPMLQVS6yoVUYZIFn2rF2Zc2NkhzlEf0uK2nGi7131qSk\naGddLTUpojfffLPYaR1zDAdrqYUakWa8Vse4LPTnVq2t8N6nRAPrJvQUUssmc32AtRwONaRozmKm\nhlYC1m19E6dvxldKWmRlfEUm6tOnTzT11FMXyoe0sg80+15Z6FOtmL95bxiO6U/ouaulug0+dgMU\n8yiEEVJZ4KLYpgGNpkuy6/veEcgLAnjls2AjFzWRMQyiMGUeFbbFMKc+B8IneThZkFILAmGulSGh\nxdrlxxyBPCOAdw15ZYmYZQ5dfvnlI+qSZSWVRiPYkjoHhQ4hx+T3PuSQQyJqmTg5Ap2EAH2avk0f\np6/T57OUNqpWrFlQUMcDhTnPQ352cr87OQJZRoA+Sl+lz9J36cN5MPQkMSWvP963yNnU/8AzuBOJ\nuqGsJ5B7qI3iskHr3jLOCdQbRd7EeEI0ObWa8kLUQ6YmA6myqIPYqetQdAgYRKmr0u7MA1nsG/Rj\naspQ2wgHdD5XSm3UzufAmRDDHTyHY5CPee18G+nem4wcRJkR0UOmHFLHZY1oIzX4TKf37rvvZq2J\n3p4YAkTh0p+oB/eA1N+thRo2+MRv9sorr2jRRcLnEeCYjPGa5riTI9CJCCBskHoJIw9MiGCGp9S5\n554bka+yE4mUGHiE4XGEgotnJjJi2P9r795dbCu2NYDXTRVBI1M3PvABYiQGKopioKiY+cIrivgX\nmBuLYCIKBnIRFfGBCioo6BUjDQzMRJArPvCBmSZG+9avDp/WWae73e5e3XutuUZBUXOu7l4956jx\nqvGNUdUPlAd4beKWGUuch3qn7aSAANSbb745DqUUlGIrr7zyynFAZQ5z3c432/+p6ULb6Tgs0vs6\nHN2WkUDkakWBbaQA3sXDeBlP4208viS7n6CgSiV23sHS7LytdaoVBTaBAngRT+JNPIpXBbLx7jY3\nQUt+gu0g6Zerr7765PPPP78RlTDroitfyPZG6Yfd2WFdz7Xk7xHQUwmhykBS4oMPPrhVQM88N2Tk\nhRdeOHnixIkB8lqH/98Cq+IOc1bKTK8lXavoefrpp8duCI6YcFbPNm2VJiHo2muvHTbLTg61/fVy\nuBOIkqSNANJ7nVmzSW+MH8UhyNLjjz/+t+fdbNKz78KzqFi84447hi/4332r8NPRdWsFfEJ0RthB\n4rZ5c2YJZ9UoC8M2V2dqu5w8X41FgcNQgENpX3B7bZ9zzjkjUwPIs4uVbQybQ2cfe+yxkZFI1m2h\nd+edd560v6SgmN+pVhTYVQpYmACFLbKvueaaUYZroX3zzTeffOqppxa5QD1oriWA2GIngXJbHKgc\ndCjvP93+86D/Uz8rCqyTAngTj+JVPMvW4WG8vAtJTc4VocME1r27CgQLw6Xs/71OXqnvOloK4Dm8\nhwfxIp7Em0s9+0YwRmD+rLPOOnn22WeftOB///33t26L6KPlivr2/SggCcFOLAHu2S9Z3T///PN+\nf7JVnwN3n3vuuXEeqG1uHIr+0UcfbdU71MOeGgXEXxwn4Zwp5/Q47/nHH388tT/ewN8SE5UsJFnh\n9ttvP/m//zBrfwNfaWcfScICPWRdQA/de++9G7m14H4T5MiJJ598csTwVMw988wzJwts3o9ax/P5\nd999NyoCAYfOrzuMfvgvj9wd5iNt/Wyf1pVa63uZt88++6x1xdZ6tlLr5YytOyCtB8tbd2KP9Bnq\ny4sCp0uBH374oX3yySetb83WPvzww9YXla2DGu2mm25qt912W+t7crZe6XK6X7+ov0OrvhBtvQKo\nffzxx62f9dXOO++81jNZWt9Xt/WAd+uVf60vXBf13vUyRYFQoC8+2qefftr6oYytbzHTPv/889ar\n3loPTrUbb7yx9a0Z2g033FAy0AnWA+Wtn3nS3nnnndaDWq3vvz18gg6GDVr1hVDrWx+EtDUWBY6N\nAj1xqfXtNlp3sFsHbIf974Gl1s+zGza/J3y0K6644tieZ5P+Ud9iqvVDs1uvQGg9Y7z16uZBk1tu\nuWX4RfyjakWBdVGgb2U0fO8PPvhg2Ap+Zgd52l133dX6lkfDp1zX/9rk7+nJku2VV15pfZuY1pMq\nW9/CqNFD/YyPsZ7uiSSb/Pj1bMdIgQ7mDFnhX1mP8a16Il7rwGHjX4nDLK2x2WxSTzYca/ZLLrmk\nPfTQQ+2+++5rfQucpb3uzrxPT7Zpb7/9dutbYjU2oJ8R3fpB5aOLLyyhvffee+2JJ54Yfqa1ovfr\ngMGInyzh/Zb8Dr3KuHVAvfVzulsHSNr999/f+pk97aKLLtrK1+7VSK1vh9v69ojDx+jbVbe+o0/r\n5yFu5fts40P33V5a39p/6LwOvrW+m8Sw3YeJhxwL4DMTO467BbSAMEHpewe2vo9s66XrIyAsKNwz\nUOY/q+uiwLFQQGC2H7o1grWCthZVAhoWUv2cqhGE7GfXDD7tCP6xPNM2/5Mvv/xyBMx6FdCgZT/b\na8h7R6rHIl3wrG8H19x3BHubX7WefQcp0MtqW882HmAFYKfvK97C4/08uwFyXn/99QPE6Hv47iCF\nTv2V+5lFrVdQjAUdYB1wdu6557brrrtu0BFoTF9UUOvUaVq/eeoU+OOPP4Ycx1YBa/uWQ42zLbkD\nmNEPOG39fL5T/9Id+E3+UhK6+EyahC6gti7RoxK6doAR1viKvSp2+IvWiDq7qlkb9oPaW9/aYviM\na/yXW/dV33777QBd33jjjUEfMhYdJamkb62+de9UD3z6FAB28EH5UEmu7dvzDJvVz+cZMrNLiXaS\niXq2fXv55Zdbr3AaPnjfOmsApJWgefp8dlx/KbkGuPPaa6+1t956q/XqiXbrrbe2hx9+eCTaLjX+\n0ndFaf1IgAHsi0cBaQE/fE+gbbXNoMAvv/zSXn311fbSSy+NBE8JKI888sjoEjGW0KzBe8VP6zsa\njQSBXlncHn300Z1NdDvqOe27ITXA77PPPjvs+MUXX9z6VpUD6FlHfPTYAZ9VgslCUTkhsN7P/2iU\nHSXX95cdgeAEhAFCsgirFQXWRQF8BkXlJOsyzPEfx0KGqsUlEFLAURVaPwh2Xf96Z7+nH6w55Fyl\nnyxhdP/999+HIyNbWpBc73uJjgV9Bdd2llU26sUtpvtWAk216hdffPFn95kme1Dlmk5vCHhWkPNw\nU9gPEB5gsepKwXfOpwXPVVddNeiLxjqn6DBZL4d7yvrrbaQAee57Io9AqWCyzvYLMvRztUZFKqBW\nRd7ll1++ja94Rp4ZQCaZq2+nMzr/SkKXSj0+FH/KWMHoMzI9G/tPgRcqYq0BjSrr+Od9a5RRuWI3\nCFUJEgCq/ScF+NVAV8ECyRLWMGhHf2UnjQpy/yfdtvkTm7NImFWBqgNGZWbzRYGidp8AAAJ9drn1\nbYrau+++OwLoKsll4LNDffusUZV62WWX7TJ5Nurd8S+wsh9MPgKev/322/AXVHHefffdO7WTindX\nRf3iiy+OajW2D8+qaiXXuwTebgqTfv/996PSTNWkuDXdqsL2gQceGHZ2iVWTaK9QQwWTih87HEl+\nv+eee0Z1tVh9tcNRQBy0nzs5bBRfjq/bz6Mb9mmdsY0zDviskomjKvBuAW4UFFZhoUFNEwwWEBYg\nZqz7OSqrX1P3RYF/owAhEkDsB+P9GbSVASSrVxAxFScCtoKIgjzrFLR/e5i6+ZMCAm+qgFRJCLil\nc/w0gA85Nx/6pZdeOhaywN+lGtc/iVMXx04BAd+vv/56AMH4ko7QXdtWAM/J5AE66AKZKtTK6Tn6\nqTIvgoHAYpUEgDeL+b6P9wCIJYWYE7qczijA7ejnZBv+g2oBMqwShX1hawC3Eg1kTfEpgbQWMcCI\nCy+8cBteayuekd8FrE3VFLrLYhN85mtJ6IrcFgi0FVN66IcE7kQOs8aTLStj27pORZhqTolWwNdq\n/4wC1jRkDvCjCybwsyVGoK1ujcNGLjVL/p9RbDt+m70iL/wf+hQ4qnJF/ENygipUgSL+T7W9KSC+\npALK9mBAIOtM24MJoKOditTy5fem3VF8ak3Fp6enVPPwzegkRz2o4rRVpfnZ9dbP8Wivv/766Ohl\nlwO8Cti140yBlkfDIeIB6O2YAskU1pzWmyrNVE0C1XcJeJNkQFb/p2+tCPRCH3wIjEULuyFU+3sK\noCMfmB0C9Hz11VdDzwEOH+xbrh7VVoAbB/jsRSrb5iQQbCR0AnAcW81CUTBYRpM9WzPKdKmg8F4U\nXeZn+EFQkPDILDXiE0CPzFOtH/Q3HGJBngRtLXyqVHazeEKgCDiXnqC7Pcw1RpasW8RSjoJ06cCg\nAus2az436Wlk+KnMoSvSZa3QF998880ISHpefMSRtp+yTk/olWCwGbNJ3wsgWySm0xMB5k6cODHm\nDUhsHo16ZYlvxvyt+ynYePZel/lsZD/IOgdbNh75BTCkCzDXFoHrnon9v0/QUgA6VVWuUyVpL35+\nWQBbOpdfv5Q9+venyjJ/Yt1GH6cDXK3dfK7Rz5IlUqnpWjCl2nopIDsXOBDgFWjARkqIiB6UuKKz\nk+vYOmS9b7B732bOyIpKN92csWmAO4CExISAouZNFWW1f0YBiQfsULYRRuNUFQKbU40qnlRxpH9G\n2/1+27bNAuj0kV190F/QWBIdwM22ZYDLOitkPwq2cS4y8EG1mkpqukJihGpOfKvT48Wz+9Nwv5+I\nDeBJttLOEoB1IDH+BK45rxvAUbv9tJEwB7CwrZ0z4tBOTBWdAGKS6Cqh5C9OI6fopIJRt2MJuQVq\nA8zY86OW2a0AfP4i2V9XjLUgXRYTWegL2llUaoTSokIgmMAanQ2kX3DBBRX4+YucW3HF2SUkzsjQ\nBQpUfyVo6yBXv6NxilMNwvgJ9AggVPbOVkz1vg9p/sk6QE+nA8w/PggAbMEKBI6ck3X3AGBdxtAu\nZWXsS8yF/uDXX39tSq91mVF0BSAno21EBYA1wcQAhsBDi7vojQo+bR+DxC8QXNSB/QIltu+ysNSc\npRSgOHNPR/AVZCgdtdO1fVTdjCcms/Q/u0+e6X36Xze/5F6TvGF+2X2AAQBB91klAmzGXM5PAaiT\nyCWwCcAF0pFbC21NNVD0siSPyCx/vuz4TMnjvzZH8b/JYZKs+GaqdjRzRA753wBWAWqBgQLej3++\n/EdBbbZRpYggt2QJ62j2ke/M/zFXOh1K9shcJcWtf77oPrJiTZMdKOg/VXAaGSEvwFAVkapQ63zj\n9c+Db7SFlkBvjhggG9aUtndH/1Sj0mHsUAUzD54HvhrQkm1HS90aTKNTVBqqTBNAL54+mJb7/TSg\npW108S0wjU2mN8Kz+Fa3xqn2FwXsDkHX2kUq/One5wLx4U0VVOLH1fangAQS24qqmtTJucTYJCYA\nM9iuXfLX6T+AYTpdaA0rwUk1lM62H2fbWsDnICIJ/Ft4ZCGSwIAgQbLL/L0sggSCZXMnIEzYAQOC\nPxabZdgPovZ6fkZh/PTTTyOgQ1BUeCRom1HwljLWBG7MT4C8BAGMnLHKEFnPvGzLtwD68Angh5wn\nKOia8cFP4R3vJNBP5sk6PsoYmT///POH7Fd28WZwgCCFgC6wRiDJaE7piugLIx6QaZIGtAHwcXbn\nnkQAFX/Vlk8B/MMP4BcAB9IFKfGMhZOm2sPiE8/wDYx6dAU9ATAqUGi9PMMRJt9kWufDsfe64FeA\n24D6fDL+GnsPyEln+wEBlfG83vk57m9jz9lwQdAERAVFyW2ABM/ET6fLyaxOx5PX+PJLOTz3uOmf\n/2fLo9n/jj/FpzI/fPY0ayVyCDBI0gSgx/wU0BoqbeYI7AH6JFHC6N7ca/RtfKastay9InMF3u09\nr3OSItmZYxJ0GT9WA6ahK5AtCQqABTSvdmYowNeQhCAgnKAw/5GvKJk4YCjwYu67tJUwWrADcxIm\ne81uJwHHmlolIcAyoGXZ5aPhaTEOPKtKJXxrPughNKdb2OQkQxnNz5Jb1n4S//BlRvaNjAMhBN5n\n/rSGqHb6FEDnnL0LRLd+syZj07Kzkmp+HaC+7c0aNeA2gFsSDXvP7/WOqbyzVeWZPJd8kYDPQcxj\nSyiLFZNh5NBixixqBBvmgKEJM0ECwEaLmowCPwKGOmWa613PDOcEKF+zv7Bu0ZiRE2DBrrQ3o0Wj\n35+bBUQW7Rkt5C3oLTIE42rrgZlidX0QBTg8+IysR94DFAQ4MK7yIR4j82Q9nay7NgKEdPyaawZs\nl5z+g+i++jPzIJMO8C670Th3+oG+MOaarvBZqnJ8Z/SyAHzAulwnSG+sQMTqDNT9KgUsCDhsFq46\nv4COCNDAN5h9AjpBoJlPEGA4Y/RCRjpC8sGuBTzJOV+L3EaeMwawzSjoRTfPgLyACrtPhgO8sfsC\nYLrPCtRZ5eTduGc/ksSVBI/Zp3dmUxo+AtaS17nHnyen/HkjW7H05C6+ObvLtrKrGSOD5DAd6Drr\nPT5NAvzxwwX9AwDUVqfhuuWMdssI4AqgSEUl+cM7aWwcXb2aPDXfk7mlrI3ZN36rNcTcs5bI2oLv\nkMriOUmBzOgSFICj5KjsWbhpc0eJqaoAVKIKHAfo4DfSrRp7Qz/yUdJnP8Y6cVsShlSLsAN84fjD\nuTZ67/A3+QZ8BfAHXgrusq/VzhwF+Eu2zgUEATkCevADNH4PXRTbPo/4d9PX0HQx/2X2ARPfNbJV\n4VHvE7ALf6p8svvP0v2+M8d9//rP5kalS/gQOMJ+anQlOxibaJQ45HP++6Y0z4uXZj+IP8QOzO+S\nCnaVPLYF3aTig50DfE6FeWZHLosfwYkAFBkFMCjT1UZ5CPrqlKXRYoizO4+QZfvKY2p9vl69lwEk\naOS70/e79znngyI0pu91L9hFGXJkLO70g64tpr2zhUBGgR2BcgbEuBdNPBNHJwvsGThzbWGQbmGO\nFtWKAsdNARkfnIc5GJnASAAIo05P4HkytNrIKEU/d/KvC5zM46wH8H26agOd7Ke7tzCM7J/K6Hci\n+6c6Cr6iBd2g5zr6gY6InjDSCzq9MI90w9yz3eYqveg7+kGAPIAaXZFOR+gWFbrPvVe1osBxUEDC\ngmBOuoDOXnrC763qA4t7egB/8wd093yBudMDsfvRAXvd0wHxAVbH6IN8jjax/3v5BPPPyPh+8j3L\nuyAAGz93Mk4X6vSi+xmg9Rz0lqQYAYDIcWQ6gcGAtn6vWlHgdCiAB5PAZSSz8ePJrWs2nZ1abeQx\nPntkdb73c7IZm51x/sw1e00G8Xxkca/R/59lcPWaLvFZfHRySP4ij7nOSCa9f/zxyGTu9/LN+SOz\nHAYYI4tJtjKiQ7WiQCjAl5uDbALDATqMOj95tgOSJZIYyR7m2ug+fjG5wperI9kiU5GrvUY2MHKz\n38i/Jf/kZr+RzLBlbHp67snV6nuRm9ixjORG4EoQVdDf81ZbHgXoZ4FA4KggILmYgRH8koYHEgfh\nC6X7TKwo60S2xnXGmfd9h06ejGyLtR1+nzs+d+/55pjNfM0miGWxiaudfKTxOwNcCZzjack3AXnK\nPoRS2zHSzwF/AHffdHBEx7v4Ic28Z/09j0lmw59zt7aht2f+nK/pZz5NeBN/5nrm06wvrCVcG/Fn\nYrGJ0XhWvK/57gCu9K6uWidVTeSp2mZQAJ+phgGg05n0p25e0/gEc0Ivu0pfJr4+j/wF+nC1043h\nMXyWjtfwFDs/d7raGiE+TJI4+Nya78NXAaaAVSqXVPJsug4swCecdZoj5uEMUjrG1QUWRorCorRm\nQ4uBZpAFA25SE6gScErQyUiRxwmJI2IkePPC2D1hZRQ48362LVktmzQH9SybTwFybSGok//IfIxJ\n5J/sz2BI7hO8iT7gDG16Y1QtQNKzMF8Fs+iKGfRyHSNNP6RzKqsVBbadAoJA5J8/MPsE0Q2zfsiC\nJmPkP+Om6AEO7kE+APsfuWbndXJtZPsD4pL78gG2ncOX8/zkTEBaECEJHHz4BHVjxzOy4+y3v9MF\nwywkz2QTSGF7Y4fZ39hb8ha5TEA9YwKORn9brShwFBSwPhY8ETQhYwFOZjnLZ2wjnzggzHGvh9km\nshBflu9KXubOrs33EhcEochR2baj4KBlfCcfDwAEFF0FVXJPPvweGdATxD4qCsyxHHwd4Gl1BGQC\neAT7i8ePajY263vxH/BHwkwAliS4BWjhJ2XtcpS6Gp9mjUHPBnSie+drPAqQFJuotr0UwFOAH7ts\nBGwx5tq6mk/u9+aki8O+MV+az2zdSgcm+TDJG+4BPUDubeWxAnwOyyVr/HvMmwzbGQhyzXFOdr5A\n0Hy9eu975kzfg64xuWzEVWDHfQVh1zi59VVFgVOkAFkXUEpVDWdKzz15n2U+umC/cdYH0QV/N0Yv\n0AFzdZF7ukEQuFpRoChwdBSIHkiAOb4BXTDLf/TB6kgfaJF1MrtXz8/JuYBXwJ0EkbfVuT26malv\nLgr8iwIAHwHqyGiuye6qPO5171v2ksnVz5JgMYM7rtnpakWBJVKAvKxW35AzMudn+43sHvkhG5Gj\nXGckT+RnriJi7yqgvURO2s53YksCABmt//A822Jc7eF5PL7a+XYAzCTrGvl91YoC66AA3sSj6fT0\nzKfzNd0d/qSH52v3dHIAHnyKr6sVBVYpwM7jtyRR0pf4bLX7PTyGt+YenQjgAfTwB5beCvBZ+gzX\n+xUFigJFgaJAUaAoUBQoChQFigJFgaJAUaAoUBQoChQFigJFgaJAUaAosHgKFMS/+CmuFywKFAWK\nAkWBokBRoChQFCgKFAWKAkWBokBRoChQFCgKFAWKAkWBokBRYOkUKMBn6TNc71cUKAoUBYoCRYGi\nQFGgKFAUKAoUBYoCRYGiQFGgKFAUKAoUBYoCRYGiwOIpUIDP4qe4XrAoUBQoChQFigJFgaJAUaAo\nUBQoChQFigJFgaJAUaAoUBQoChQFigJFgaVT4P8B9mlhJTpY/8wAAAAASUVORK5CYII=\n", 90 | "prompt_number": 3, 91 | "text": [ 92 | "" 93 | ] 94 | } 95 | ], 96 | "prompt_number": 3 97 | }, 98 | { 99 | "cell_type": "markdown", 100 | "metadata": {}, 101 | "source": [ 102 | "Here we extract wikipedia articles that are not special pages,\n", 103 | "redirection, or disambiguations.\n", 104 | "Among those pages we now take out strings of text with references to other articles\n", 105 | "to learn named entity recognition over a hierarchical softmax tree" 106 | ] 107 | }, 108 | { 109 | "cell_type": "code", 110 | "collapsed": false, 111 | "input": [ 112 | "parseresult = wikipedia_ner.parse_dump(\"/Users/jonathanraiman/Desktop/Coding/enwiki.bz2\",\n", 113 | " max_articles = 200)" 114 | ], 115 | "language": "python", 116 | "metadata": {}, 117 | "outputs": [ 118 | { 119 | "output_type": "stream", 120 | "stream": "stdout", 121 | "text": [ 122 | "200 articles seen so far. Processing 35.408 articles / s : position 9851453\n" 123 | ] 124 | } 125 | ], 126 | "prompt_number": 2 127 | }, 128 | { 129 | "cell_type": "code", 130 | "collapsed": false, 131 | "input": [ 132 | "most_common_category = wikipedia_ner.ParsedPage.categories_counter.most_common(1)[0][0]\n", 133 | "print(\"In '%s' the children are %r\" % (most_common_category, \", \".join([parseresult.index2target[child] for child in list(wikipedia_ner.ParsedPage.categories[most_common_category].children)])))" 134 | ], 135 | "language": "python", 136 | "metadata": {}, 137 | "outputs": [ 138 | { 139 | "output_type": "stream", 140 | "stream": "stdout", 141 | "text": [ 142 | "In 'Category : Member states of the United Nations' the children are 'Afghanistan, Algeria, Andorra, Antigua and Barbuda, Azerbaijan, Angola, Albania'\n" 143 | ] 144 | } 145 | ], 146 | "prompt_number": 9 147 | }, 148 | { 149 | "cell_type": "code", 150 | "collapsed": false, 151 | "input": [], 152 | "language": "python", 153 | "metadata": {}, 154 | "outputs": [] 155 | } 156 | ], 157 | "metadata": {} 158 | } 159 | ] 160 | } -------------------------------------------------------------------------------- /Export Categories.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 5, 6 | "metadata": { 7 | "collapsed": true 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "import json\n", 12 | "from collections import defaultdict\n", 13 | "from epub_conversion import convert_wiki_to_lines\n", 14 | "import gzip\n", 15 | "from epub_conversion.wiki_decoder import almost_smart_open\n", 16 | "from multiprocessing import Process, Lock\n", 17 | "from multiprocessing import Pool" 18 | ] 19 | }, 20 | { 21 | "cell_type": "markdown", 22 | "metadata": {}, 23 | "source": [ 24 | "### Extract Wikipedia category graph\n", 25 | "\n", 26 | "\n", 27 | "Find all the category connections in Wikipedia and save them to a JSON" 28 | ] 29 | }, 30 | { 31 | "cell_type": "code", 32 | "execution_count": 6, 33 | "metadata": { 34 | "collapsed": false 35 | }, 36 | "outputs": [], 37 | "source": [ 38 | "import re\n", 39 | "link_pattern = re.compile(r'\\[\\[ *(.*?)\\]\\]')\n", 40 | "\n", 41 | "def save_progress(work_so_far, path):\n", 42 | " with open(path, \"w+\") as fout:\n", 43 | " json.dump(work_so_far, fout)\n", 44 | " \n", 45 | "def lines_extractor(lines, article_name):\n", 46 | " yield (article_name, lines)\n", 47 | " \n", 48 | "def category_job(args):\n", 49 | " article_name, lines = args\n", 50 | " categories = []\n", 51 | " for link in link_pattern.findall(lines):\n", 52 | " if link.lower().startswith(\"category:\"):\n", 53 | " if '|' in link:\n", 54 | " link, anchor = link.split(\"|\", 1)\n", 55 | " link = link.strip().split(\"#\")[0]\n", 56 | " anchor = anchor.strip()\n", 57 | " if len(link) > 0 and len(anchor) > 0:\n", 58 | " categories.append((link, anchor))\n", 59 | " else:\n", 60 | " categories.append((link, None))\n", 61 | " return (article_name, categories)\n", 62 | "\n", 63 | "def run_jobs(worker_pool, pool_jobs, output_dictionary):\n", 64 | " results = worker_pool.map(category_job, pool_jobs)\n", 65 | " for article_name, categories in results:\n", 66 | " for category, anchor in categories:\n", 67 | " output_dictionary[category].append(article_name)\n", 68 | "\n", 69 | "def parse_wiki(path, outpath, num_articles = 9999999999999, threads = 1, max_jobs = 10):\n", 70 | " num_articles_processed = 0\n", 71 | " num_articles_with_categories = 0\n", 72 | " processed_categories = defaultdict(lambda : [])\n", 73 | " \n", 74 | " jobs = []\n", 75 | " pool = Pool(processes=threads)\n", 76 | " \n", 77 | " with almost_smart_open(path, \"rb\") as wiki:\n", 78 | " for article_name, lines in convert_wiki_to_lines(\n", 79 | " wiki,\n", 80 | " max_articles = num_articles,\n", 81 | " clear_output = True,\n", 82 | " report_every = 100,\n", 83 | " parse_special_pages = True,\n", 84 | " skip_templated_lines = False,\n", 85 | " line_converter = lines_extractor):\n", 86 | " \n", 87 | " jobs.append((article_name, lines))\n", 88 | " \n", 89 | " num_articles_processed += 1\n", 90 | " \n", 91 | " if len(jobs) >= max_jobs:\n", 92 | " run_jobs(pool, jobs, processed_categories)\n", 93 | " jobs = []\n", 94 | "\n", 95 | " if num_articles_processed % 100000 == 0:\n", 96 | " save_progress(processed_categories, outpath)\n", 97 | " \n", 98 | " if len(jobs) > 0:\n", 99 | " run_jobs(pool, jobs, processed_categories)\n", 100 | " jobs = []\n", 101 | " \n", 102 | " save_progress(processed_categories, outpath)\n", 103 | " \n", 104 | " return processed_categories" 105 | ] 106 | }, 107 | { 108 | "cell_type": "code", 109 | "execution_count": 7, 110 | "metadata": { 111 | "collapsed": false, 112 | "scrolled": false 113 | }, 114 | "outputs": [ 115 | { 116 | "name": "stdout", 117 | "output_type": "stream", 118 | "text": [ 119 | "15706200 articles seen so far. Processing 1675.302 articles / s : position 53557320927\n" 120 | ] 121 | } 122 | ], 123 | "source": [ 124 | "x = parse_wiki(\"/Users/jonathanraiman/Desktop/Coding/enwiki2015.xml.bz2\",\n", 125 | " \"/Users/jonathanraiman/Desktop/datasets/category_graph2.json\",\n", 126 | " threads=9,\n", 127 | " max_jobs=100)" 128 | ] 129 | }, 130 | { 131 | "cell_type": "code", 132 | "execution_count": null, 133 | "metadata": { 134 | "collapsed": true 135 | }, 136 | "outputs": [], 137 | "source": [] 138 | } 139 | ], 140 | "metadata": { 141 | "kernelspec": { 142 | "display_name": "Python 3", 143 | "language": "python", 144 | "name": "python3" 145 | }, 146 | "language_info": { 147 | "codemirror_mode": { 148 | "name": "ipython", 149 | "version": 3 150 | }, 151 | "file_extension": ".py", 152 | "mimetype": "text/x-python", 153 | "name": "python", 154 | "nbconvert_exporter": "python", 155 | "pygments_lexer": "ipython3", 156 | "version": "3.4.3" 157 | } 158 | }, 159 | "nbformat": 4, 160 | "nbformat_minor": 0 161 | } 162 | -------------------------------------------------------------------------------- /Export Page Links.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": { 7 | "collapsed": true 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "import json\n", 12 | "import os\n", 13 | "from collections import defaultdict\n", 14 | "from epub_conversion import convert_wiki_to_lines\n", 15 | "import gzip\n", 16 | "from epub_conversion.wiki_decoder import almost_smart_open\n", 17 | "from multiprocessing import Process, Lock\n", 18 | "from multiprocessing import Pool" 19 | ] 20 | }, 21 | { 22 | "cell_type": "markdown", 23 | "metadata": {}, 24 | "source": [ 25 | "### Extract Wikipedia category graph\n", 26 | "\n", 27 | "\n", 28 | "Find all the category connections in Wikipedia and save them to a JSON" 29 | ] 30 | }, 31 | { 32 | "cell_type": "code", 33 | "execution_count": 2, 34 | "metadata": { 35 | "collapsed": false 36 | }, 37 | "outputs": [], 38 | "source": [ 39 | "import re\n", 40 | "link_pattern = re.compile(r'\\[\\[ *(.*?)\\]\\]')\n", 41 | "\n", 42 | "def save_progress(work_so_far, path, num_saved, mode):\n", 43 | " with open(path, mode) as fout:\n", 44 | " for ex in work_so_far:\n", 45 | " json.dump(ex, fout)\n", 46 | " fout.write(\"\\n\")\n", 47 | " num_saved = num_saved + len(work_so_far)\n", 48 | " return num_saved\n", 49 | " \n", 50 | "def lines_extractor(lines, article_name):\n", 51 | " yield (article_name, lines)\n", 52 | " \n", 53 | "def category_job(args):\n", 54 | " article_name, lines = args\n", 55 | " out = []\n", 56 | " text_block = True\n", 57 | " for block in re.split(link_pattern, lines):\n", 58 | " block = block.strip()\n", 59 | " if text_block:\n", 60 | " text_block = False\n", 61 | " out.append({\"type\":\"text\", \"text\": block})\n", 62 | " else:\n", 63 | " link = block\n", 64 | " if '|' in link:\n", 65 | " link, anchor = link.split(\"|\", 1)\n", 66 | " link = link.strip().split(\"#\")[0]\n", 67 | " anchor = anchor.strip()\n", 68 | " \n", 69 | " if link.startswith(\"File:\") or link.startswith(\"Image:\"):\n", 70 | " if len(anchor) > 0:\n", 71 | " out.append({\"type\":\"text\", \"text\": anchor})\n", 72 | " elif len(link) > 0 and len(anchor) > 0:\n", 73 | " anchor_words = anchor.split(\" \")\n", 74 | " out.append({\"type\":\"label\", \"text\": anchor, \"label\": link})\n", 75 | " elif len(anchor) > 0:\n", 76 | " out.append({\"type\":\"text\", \"text\": anchor})\n", 77 | " else:\n", 78 | " if len(link) > 0:\n", 79 | " out.append({\"type\":\"label\", \"text\": link, \"label\": link})\n", 80 | " text_block = True\n", 81 | " return (article_name, out)\n", 82 | "\n", 83 | "def run_jobs(worker_pool, pool_jobs, output):\n", 84 | " results = worker_pool.map(category_job, pool_jobs)\n", 85 | " for article_name, out in results:\n", 86 | " output.append(\n", 87 | " {\n", 88 | " \"content\": out,\n", 89 | " \"title\": article_name\n", 90 | " }\n", 91 | " )\n", 92 | "\n", 93 | "def parse_wiki(path, outpath, num_articles=9999999999999, threads=1, max_jobs=10, save_every=10000):\n", 94 | " num_articles_processed = 0\n", 95 | " num_articles_with_categories = 0\n", 96 | " processed_categories = []\n", 97 | " \n", 98 | " jobs = []\n", 99 | " pool = Pool(processes=threads)\n", 100 | " try:\n", 101 | " num_saved = 0\n", 102 | " write_mode = \"wt+\"\n", 103 | "\n", 104 | " with almost_smart_open(path, \"rb\") as wiki:\n", 105 | " for article_name, lines in convert_wiki_to_lines(\n", 106 | " wiki,\n", 107 | " max_articles = num_articles,\n", 108 | " clear_output = True,\n", 109 | " report_every = 100,\n", 110 | " parse_special_pages = True,\n", 111 | " skip_templated_lines = False,\n", 112 | " line_converter = lines_extractor):\n", 113 | "\n", 114 | " jobs.append((article_name, lines))\n", 115 | "\n", 116 | " num_articles_processed += 1\n", 117 | "\n", 118 | " if len(jobs) >= max_jobs:\n", 119 | " run_jobs(pool, jobs, processed_categories)\n", 120 | " jobs = []\n", 121 | "\n", 122 | " if num_articles_processed % save_every == 0:\n", 123 | " num_saved = save_progress(processed_categories, outpath, num_saved, mode=write_mode)\n", 124 | " processed_categories = []\n", 125 | " write_mode = \"at+\"\n", 126 | "\n", 127 | " if len(jobs) > 0:\n", 128 | " run_jobs(pool, jobs, processed_categories)\n", 129 | " jobs = []\n", 130 | " num_saved = save_progress(processed_categories, outpath, num_saved, mode=write_mode)\n", 131 | " processed_categories = []\n", 132 | " write_mode = \"at+\"\n", 133 | " finally:\n", 134 | " pool.close()\n", 135 | " pool.join()\n", 136 | " return processed_categories" 137 | ] 138 | }, 139 | { 140 | "cell_type": "code", 141 | "execution_count": 3, 142 | "metadata": { 143 | "collapsed": false, 144 | "scrolled": false 145 | }, 146 | "outputs": [ 147 | { 148 | "name": "stdout", 149 | "output_type": "stream", 150 | "text": [ 151 | "15706200 articles seen so far. Processing 1053.715 articles / s : position 53557320927\n" 152 | ] 153 | } 154 | ], 155 | "source": [ 156 | "x = parse_wiki(\n", 157 | " \"/Users/jonathanraiman/Desktop/Coding/enwiki2015.xml.bz2\",\n", 158 | " \"/Users/jonathanraiman/Desktop/datasets/triggers_and_documents.json\",\n", 159 | " threads=9,\n", 160 | " max_jobs=100,\n", 161 | " save_every=100000\n", 162 | ")" 163 | ] 164 | }, 165 | { 166 | "cell_type": "code", 167 | "execution_count": null, 168 | "metadata": { 169 | "collapsed": true 170 | }, 171 | "outputs": [], 172 | "source": [] 173 | } 174 | ], 175 | "metadata": { 176 | "kernelspec": { 177 | "display_name": "Python 3", 178 | "language": "python", 179 | "name": "python3" 180 | }, 181 | "language_info": { 182 | "codemirror_mode": { 183 | "name": "ipython", 184 | "version": 3 185 | }, 186 | "file_extension": ".py", 187 | "mimetype": "text/x-python", 188 | "name": "python", 189 | "nbconvert_exporter": "python", 190 | "pygments_lexer": "ipython3", 191 | "version": "3.4.3" 192 | } 193 | }, 194 | "nbformat": 4, 195 | "nbformat_minor": 0 196 | } 197 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.md 2 | include *.ipynb -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Wikipedia NER 2 | ------------- 3 | 4 | Tool to train and obtain named entity recognition labeled examples 5 | from Wikipedia dumps. 6 | 7 | Usage in [IPython notebook](http://nbviewer.ipython.org/github/JonathanRaiman/wikipedia_ner/blob/master/Wikipedia%20to%20Named%20Entity%20Recognition.ipynb) (*nbviewer* link). 8 | 9 | ## Usage 10 | 11 | Here is an example usage with the first 200 articles from the english wikipedia dump (dated lated 2013): 12 | 13 | parseresult = wikipedia_ner.parse_dump("enwiki.bz2", 14 | max_articles = 200) 15 | most_common_category = wikipedia_ner.ParsedPage.categories_counter.most_common(1)[0][0] 16 | 17 | most_common_category_children = [ 18 | parseresult.index2target[child] for child in list(wikipedia_ner.ParsedPage.categories[most_common_category].children) 19 | ] 20 | 21 | "In '%s' the children are %r" % ( 22 | most_common_category, 23 | ", ".join(most_common_category_children) 24 | ) 25 | 26 | #=> "In 'Category : Member states of the United Nations' the children are 'Afghanistan, Algeria, Andorra, Antigua and Barbuda, Azerbaijan, Angola, Albania'" -------------------------------------------------------------------------------- /Simplify Graph.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": { 7 | "collapsed": false 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "import json\n", 12 | "from collections import Counter\n", 13 | "import matplotlib.pyplot as plt\n", 14 | "% matplotlib inline" 15 | ] 16 | }, 17 | { 18 | "cell_type": "code", 19 | "execution_count": 2, 20 | "metadata": { 21 | "collapsed": true 22 | }, 23 | "outputs": [], 24 | "source": [ 25 | "fname = \"/Users/jonathanraiman/Desktop/datasets/category_graph.json\"" 26 | ] 27 | }, 28 | { 29 | "cell_type": "code", 30 | "execution_count": 3, 31 | "metadata": { 32 | "collapsed": true 33 | }, 34 | "outputs": [], 35 | "source": [ 36 | "with open(fname, \"rt\") as f:\n", 37 | " graph = json.load(f)" 38 | ] 39 | }, 40 | { 41 | "cell_type": "markdown", 42 | "metadata": {}, 43 | "source": [ 44 | "### Clean broken, disconnected elements, from graph:" 45 | ] 46 | }, 47 | { 48 | "cell_type": "code", 49 | "execution_count": 4, 50 | "metadata": { 51 | "collapsed": true 52 | }, 53 | "outputs": [], 54 | "source": [ 55 | "bad_keys = []\n", 56 | "for key in graph.keys():\n", 57 | " if \"[[\" in key or \"]]\" in key:\n", 58 | " bad_keys.append(key)\n", 59 | "for key in bad_keys:\n", 60 | " del graph[key]\n", 61 | "\n", 62 | "for el in graph.keys():\n", 63 | " kids = []\n", 64 | " for child in graph[el]:\n", 65 | " if \"[[\" in child or \"]]\" in child:\n", 66 | " continue\n", 67 | " if child.lower().startswith(\"category:\"):\n", 68 | " if \"Category:\" + child.split(\":\",1)[1] in graph:\n", 69 | " kids.append(\"Category:\" + child.split(\":\",1)[1])\n", 70 | " else:\n", 71 | " kids.append(child)\n", 72 | " graph[el] = kids" 73 | ] 74 | }, 75 | { 76 | "cell_type": "markdown", 77 | "metadata": {}, 78 | "source": [ 79 | "### Special Nodes" 80 | ] 81 | }, 82 | { 83 | "cell_type": "code", 84 | "execution_count": 173, 85 | "metadata": { 86 | "collapsed": true 87 | }, 88 | "outputs": [], 89 | "source": [ 90 | "cats = set()\n", 91 | "articles = set()\n", 92 | "for key, value in graph.items():\n", 93 | " if key.startswith(\"Category:\"):\n", 94 | " cats.add(key.replace(\"Category:\", \"\"))\n", 95 | " for child in value:\n", 96 | " if not child.startswith(\"Category:\"):\n", 97 | " articles.add(child)" 98 | ] 99 | }, 100 | { 101 | "cell_type": "code", 102 | "execution_count": 174, 103 | "metadata": { 104 | "collapsed": false 105 | }, 106 | "outputs": [], 107 | "source": [ 108 | "fixed_points = cats & articles\n", 109 | "blacklist = [\" in \", \" District\", \" County\"]\n", 110 | "def in_blacklist(art, bl):\n", 111 | " for el in bl:\n", 112 | " if el in art:\n", 113 | " return True\n", 114 | " return False\n", 115 | "non_date_fixed_points = set([art for art in fixed_points if not in_blacklist(art, blacklist)])" 116 | ] 117 | }, 118 | { 119 | "cell_type": "code", 120 | "execution_count": 8, 121 | "metadata": { 122 | "collapsed": true 123 | }, 124 | "outputs": [], 125 | "source": [ 126 | "inverse_graph = {}\n", 127 | "for key in graph.keys():\n", 128 | " for child in graph[key]:\n", 129 | " if child in inverse_graph:\n", 130 | " inverse_graph[child].append(key)\n", 131 | " else:\n", 132 | " inverse_graph[child] = [key]" 133 | ] 134 | }, 135 | { 136 | "cell_type": "markdown", 137 | "metadata": {}, 138 | "source": [ 139 | "Can find the root of wikipedia by looking at [Category:Main topic classifications](https://en.wikipedia.org/wiki/Category:Main_topic_classifications) online and finding the parent for this category. Going up this leads to **Category:Articles**, which has **Category:Contents** as parent. **Category:Contents** has no parent, and is the most meta of all articles." 140 | ] 141 | }, 142 | { 143 | "cell_type": "code", 144 | "execution_count": 49, 145 | "metadata": { 146 | "collapsed": false 147 | }, 148 | "outputs": [], 149 | "source": [ 150 | "root = \"Category:Contents\"" 151 | ] 152 | }, 153 | { 154 | "cell_type": "code", 155 | "execution_count": 7, 156 | "metadata": { 157 | "collapsed": true 158 | }, 159 | "outputs": [], 160 | "source": [ 161 | "fname_inverted = \"/Users/jonathanraiman/Desktop/datasets/category_graph.inverted.json\"" 162 | ] 163 | }, 164 | { 165 | "cell_type": "code", 166 | "execution_count": 10, 167 | "metadata": { 168 | "collapsed": true 169 | }, 170 | "outputs": [], 171 | "source": [ 172 | "with open(fname_inverted, \"wt\") as f:\n", 173 | " json.dump(inverse_graph, f)" 174 | ] 175 | }, 176 | { 177 | "cell_type": "code", 178 | "execution_count": 8, 179 | "metadata": { 180 | "collapsed": true 181 | }, 182 | "outputs": [], 183 | "source": [ 184 | "with open(fname_inverted, \"rt\") as f:\n", 185 | " inverse_graph = json.load(f)" 186 | ] 187 | }, 188 | { 189 | "cell_type": "markdown", 190 | "metadata": {}, 191 | "source": [ 192 | "### Upward edges" 193 | ] 194 | }, 195 | { 196 | "cell_type": "code", 197 | "execution_count": 51, 198 | "metadata": { 199 | "collapsed": false 200 | }, 201 | "outputs": [], 202 | "source": [ 203 | "from collections import deque\n", 204 | "def get_node_depth(root, graph):\n", 205 | " visited_nodes = set()\n", 206 | " node_queue = deque()\n", 207 | " depth = {root: 0}\n", 208 | " node_queue.appendleft(root)\n", 209 | " visited_nodes.add(root)\n", 210 | " \n", 211 | " while len(node_queue) > 0:\n", 212 | " node = node_queue.pop()\n", 213 | " if node in graph:\n", 214 | " for child in graph[node]:\n", 215 | " if child not in visited_nodes:\n", 216 | " node_queue.appendleft(child)\n", 217 | " visited_nodes.add(child)\n", 218 | " depth[child] = depth[node] + 1\n", 219 | " return depth" 220 | ] 221 | }, 222 | { 223 | "cell_type": "code", 224 | "execution_count": 50, 225 | "metadata": { 226 | "collapsed": false 227 | }, 228 | "outputs": [], 229 | "source": [ 230 | "depth = get_node_depth(root, graph)" 231 | ] 232 | }, 233 | { 234 | "cell_type": "markdown", 235 | "metadata": {}, 236 | "source": [ 237 | "Export ontology to format of the form:\n", 238 | "```\n", 239 | "root -> child\n", 240 | "child -> subchild\n", 241 | " grandchild\n", 242 | "```\n", 243 | "for easy serialization" 244 | ] 245 | }, 246 | { 247 | "cell_type": "code", 248 | "execution_count": 6, 249 | "metadata": { 250 | "collapsed": false 251 | }, 252 | "outputs": [], 253 | "source": [ 254 | "from collections import deque\n", 255 | "import gzip\n", 256 | "import numpy as np\n", 257 | "def save_graph_from_root(root, graph, outpath, connector=\"->\", max_log1p_degree=7, max_depth = 99999):\n", 258 | " global inverse_graph\n", 259 | " save_nodes = set()\n", 260 | " node_queue = deque()\n", 261 | " node_queue.appendleft(root)\n", 262 | " save_nodes.add(root)\n", 263 | " depth = {root: 0}\n", 264 | " \n", 265 | " def acceptable_node(node):\n", 266 | " if depth[node] > max_depth:\n", 267 | " return False\n", 268 | " return (\n", 269 | " not node.startswith(\"Category:\")\n", 270 | " or node in graph) and not node.lower().startswith(\"wikipedia:\") and \\\n", 271 | " not node.lower().startswith(\"file:\") and \\\n", 272 | " not node.lower().startswith(\"template:\")\n", 273 | " \n", 274 | " with gzip.open(outpath, \"wt\") as fout:\n", 275 | " while len(node_queue) > 0:\n", 276 | " node = node_queue.pop()\n", 277 | " first = True\n", 278 | " if node in graph:\n", 279 | " if np.log1p(len(graph[node])) <= max_log1p_degree:\n", 280 | " for child in graph[node]:\n", 281 | " if child not in depth:\n", 282 | " depth[child] = depth[node] + 1\n", 283 | " if acceptable_node(child):\n", 284 | " if first:\n", 285 | " fout.write(\"%s%s%s\\n\" % (node, connector, child))\n", 286 | " else:\n", 287 | " fout.write(\"%s\\n\" % (child,))\n", 288 | " first = False\n", 289 | " if child not in save_nodes:\n", 290 | " node_queue.appendleft(child)\n", 291 | " save_nodes.add(child)\n", 292 | " return save_nodes" 293 | ] 294 | }, 295 | { 296 | "cell_type": "markdown", 297 | "metadata": {}, 298 | "source": [ 299 | "### Save a subgraph starting from a specific point\n", 300 | "\n", 301 | "Starting with **Category:Sports** or **Category::Animals** we can find all descendants for this particular domain.\n", 302 | "We can also do the same with all of wikipedia by starting at **Category:Contents**:" 303 | ] 304 | }, 305 | { 306 | "cell_type": "code", 307 | "execution_count": 95, 308 | "metadata": { 309 | "collapsed": true 310 | }, 311 | "outputs": [], 312 | "source": [ 313 | "visited = save_graph_from_root(\"Category:Sports\", graph,\n", 314 | " \"/Users/jonathanraiman/Desktop/datasets/sports_ontology.txt.gz\",\n", 315 | " max_log1p_degree = 7, max_depth = 7)" 316 | ] 317 | }, 318 | { 319 | "cell_type": "code", 320 | "execution_count": 7, 321 | "metadata": { 322 | "collapsed": false 323 | }, 324 | "outputs": [], 325 | "source": [ 326 | "visited = save_graph_from_root(\"Category:Animals\", graph,\n", 327 | " \"/Users/jonathanraiman/Desktop/datasets/animal_ontology.txt.gz\",\n", 328 | " max_log1p_degree = 7, max_depth = 7)" 329 | ] 330 | }, 331 | { 332 | "cell_type": "code", 333 | "execution_count": 96, 334 | "metadata": { 335 | "collapsed": true 336 | }, 337 | "outputs": [], 338 | "source": [ 339 | "art_visited = [vis for vis in visited if not vis.startswith(\"Category:\")]" 340 | ] 341 | }, 342 | { 343 | "cell_type": "code", 344 | "execution_count": 132, 345 | "metadata": { 346 | "collapsed": false 347 | }, 348 | "outputs": [], 349 | "source": [ 350 | "visited = save_graph_from_root(root, graph,\n", 351 | " \"/Users/jonathanraiman/Desktop/datasets/ontology.txt.gz\",\n", 352 | " max_log1p_degree = 7)" 353 | ] 354 | }, 355 | { 356 | "cell_type": "code", 357 | "execution_count": 119, 358 | "metadata": { 359 | "collapsed": false 360 | }, 361 | "outputs": [], 362 | "source": [ 363 | "degrees = [(len(graph[node]), node) for node in graph.keys()]" 364 | ] 365 | }, 366 | { 367 | "cell_type": "code", 368 | "execution_count": 127, 369 | "metadata": { 370 | "collapsed": false, 371 | "scrolled": false 372 | }, 373 | "outputs": [ 374 | { 375 | "data": { 376 | "text/plain": [ 377 | "1095.6331584284585" 378 | ] 379 | }, 380 | "execution_count": 127, 381 | "metadata": {}, 382 | "output_type": "execute_result" 383 | } 384 | ], 385 | "source": [ 386 | "np.expm1(7)" 387 | ] 388 | }, 389 | { 390 | "cell_type": "markdown", 391 | "metadata": {}, 392 | "source": [ 393 | "Visualize distributions of degrees. Most categories have between 3 and 55 children, however there exits outliers. If we perform a cutoff $D_{\\mathrm{max}}$ with $\\mathrm{log}( 1 + D_{\\mathrm{max}}) = 7$" 394 | ] 395 | }, 396 | { 397 | "cell_type": "code", 398 | "execution_count": 118, 399 | "metadata": { 400 | "collapsed": false 401 | }, 402 | "outputs": [ 403 | { 404 | "data": { 405 | "image/png": [ 406 | "iVBORw0KGgoAAAANSUhEUgAAAYsAAAEACAYAAABCl1qQAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\n", 407 | "AAALEgAACxIB0t1+/AAAFHZJREFUeJzt3X+s3fV93/Hna3GCyEBQp5v5ZQJqTRVnbAFWiBZN9UJD\n", 408 | "3GkCKlXB2VLc1aqiug1ZNG2DTAqOIkVhU0LJJpC2OGBooSBoKaiU2oRYylSBgQFx4jCbLd7sC5jK\n", 409 | "BNJs2oaV9/44nzufOJf7OcfXvuce83xIR/58P+f7/d73F+49r/P5fr7fc1JVSJI0n7826QIkSUuf\n", 410 | "YSFJ6jIsJEldhoUkqcuwkCR1GRaSpK55wyLJyiTfTPLdJN9Jcl3r35Rkf5Jn2+NXhra5IcmeJC8k\n", 411 | "uWKo/5IkO9tztwz1n5Tk3tb/RJL3Dj23Psnu9rj22B66JGlUme8+iyRnAGdU1XNJTgGeAa4GPgb8\n", 412 | "VVV95Yj1VwN3A78InA08BqyqqkqyA/jdqtqR5BHgq1X1aJKNwN+qqo1JrgF+tarWJVkOPAVc0nb/\n", 413 | "DHBJVb1+DI9fkjSCeUcWVfVKVT3X2j8CvscgBAAyxyZXAfdU1ZtVtRd4EbgsyZnAqVW1o613J4PQ\n", 414 | "AbgS2NLaDwCXt/ZHga1V9XoLiG3A2jGPT5J0DIw8Z5HkPOAi4InW9akkzyfZnOT01ncWsH9os/0M\n", 415 | "wuXI/hkOh87ZwD6AqjoEvJHkPfPsS5K0yEYKi3YK6n7g022EcRtwPvAB4GXgy8etQknSxC3rrZDk\n", 416 | "nQxOD/1+VT0IUFWvDj3/NeDhtjgDrBza/BwGI4KZ1j6yf3abc4GXkiwDTquqg0lmgDVD26wEHp+j\n", 417 | "Pj/cSpKOQlXNNZ3wliu/5YPBvMSdwM1H9J851P4McHdrrwaeA97FYOTxXzk8if4kcFnb5yPA2ta/\n", 418 | "EbittdcBf9jay4H/BpwO/Mxse44aa75jWOoPYNOka3i71j/NtVv/5B8nQP01zvq9kcWHgE8A307y\n", 419 | "bOv7LPDxJB8ACvg+8Mn2k3cluQ/YBRwCNlarqoXCHcDJwCNV9Wjr3wzclWQPcLAFBlX1WpIvMLgi\n", 420 | "CuDz5ZVQkjQR84ZFVf0n5p7X+LN5tvki8MU5+p8BLpyj//8wuBR3rn3dDtw+X42SpOPPO7gnb/uk\n", 421 | "C1ig7ZMuYAG2T7qABdo+6QIWaPukC1ig7ZMuYDHNe1PeNEhSNc4kjSRp7NdORxaSpC7DQpLUZVhI\n", 422 | "kroMC0lSl2EhSerqftyH5jfux4145ZakaWRYHBOj5oU5IWk6eRpKktRlWEiSugwLSVKXYSFJ6jIs\n", 423 | "JEldhoUkqcuwkCR1GRaSpC7DQpLUZVhIkroMC0lSl2EhSeoyLCRJXYaFJKnLsJAkdRkWkqQuw0KS\n", 424 | "1GVYSJK63lZfqzrO92X7XdmSdNjbKiwGRskLc0KShnkaSpLUZVhIkroMC0lSl2EhSeoyLCRJXYaF\n", 425 | "JKnLsJAkdc0bFklWJvlmku8m+U6S61r/8iTbkuxOsjXJ6UPb3JBkT5IXklwx1H9Jkp3tuVuG+k9K\n", 426 | "cm/rfyLJe4eeW99+xu4k1x7bQ5ckjao3sngT+ExVvR/4IPA7Sd4HXA9sq6oLgG+0ZZKsBq4BVgNr\n", 427 | "gVuTzN7hdhuwoapWAauSrG39G4CDrf9m4Ka2r+XA54BL2+PG4VCSJC2eecOiql6pquda+0fA94Cz\n", 428 | "gSuBLW21LcDVrX0VcE9VvVlVe4EXgcuSnAmcWlU72np3Dm0zvK8HgMtb+6PA1qp6vapeB7YxCCBJ\n", 429 | "0iIbec4iyXnARcCTwIqqOtCeOgCsaO2zgP1Dm+1nEC5H9s+0ftq/+wCq6hDwRpL3zLMvSdIiG+mz\n", 430 | "oZKcwuBd/6er6q8On1mCqqpxPqDveEiyaWhxe1Vtn1ApkrQkJVkDrDna7bthkeSdDILirqp6sHUf\n", 431 | "SHJGVb3STjG92vpngJVDm5/DYEQw09pH9s9ucy7wUpJlwGlVdTDJDD95YCuBx+eqsao29Y5Dkt7O\n", 432 | "2pvo7bPLSW4cZ/ve1VABNgO7qur3hp56CFjf2uuBB4f61yV5V5LzgVXAjqp6BfhhksvaPn8d+JM5\n", 433 | "9vVrDCbMAbYCVyQ5PcnPAB8B/nycg5MkHRu9kcWHgE8A307ybOu7AfgScF+SDcBe4GMAVbUryX3A\n", 434 | "LuAQsLGqZk9RbQTuAE4GHqmqR1v/ZuCuJHuAg8C6tq/XknwBeKqt9/k20S1JWmQ5/Fo+nZLUqF9U\n", 435 | "NJhbGe37LI79PsfbryQdT+O8doJ3cEuSRmBYSJK6DAtJUpdhIUnqMiwkSV2GhSSpy7CQJHUZFpKk\n", 436 | "LsNCktRlWEiSugwLSVKXYSFJ6jIsJEldhoUkqcuwkCR1GRaSpC7DQpLUZVhIkroMC0lSl2EhSeoy\n", 437 | "LCRJXYaFJKnLsJAkdRkWkqQuw0KS1GVYSJK6DAtJUpdhIUnqMiwkSV2GhSSpy7CQJHUZFpKkLsNC\n", 438 | "ktRlWEiSugwLSVJXNyySfD3JgSQ7h/o2Jdmf5Nn2+JWh525IsifJC0muGOq/JMnO9twtQ/0nJbm3\n", 439 | "9T+R5L1Dz61Psrs9rj02hyxJGtcoI4vbgbVH9BXwlaq6qD3+DCDJauAaYHXb5tYkadvcBmyoqlXA\n", 440 | "qiSz+9wAHGz9NwM3tX0tBz4HXNoeNyY5/SiPU5K0AN2wqKpvAT+Y46nM0XcVcE9VvVlVe4EXgcuS\n", 441 | "nAmcWlU72np3Ale39pXAltZ+ALi8tT8KbK2q16vqdWAbPx1akqRFsJA5i08leT7J5qF3/GcB+4fW\n", 442 | "2Q+cPUf/TOun/bsPoKoOAW8kec88+5IkLbKjDYvbgPOBDwAvA18+ZhVJkpacZUezUVW9OttO8jXg\n", 443 | "4bY4A6wcWvUcBiOCmdY+sn92m3OBl5IsA06rqoNJZoA1Q9usBB6fq54km4YWt1fV9vGOSJJObEnW\n", 444 | "8JOvqeNtX1Wj/JDzgIer6sK2fGZVvdzanwF+sar+cZvgvpvBhPTZwGPAz1dVJXkSuA7YAfwp8NWq\n", 445 | "ejTJRuDCqvrtJOuAq6tqXZvgfhq4mMH8yDPAxW3+Yri2qqq55k/mOo4azM131+TY73O8/UrS8TTO\n", 446 | "ayeMMLJIcg/wS8DPJtkH3AisSfIBBq+S3wc+CVBVu5LcB+wCDgEb63AabQTuAE4GHqmqR1v/ZuCu\n", 447 | "JHuAg8C6tq/XknwBeKqt9/kjg0KStDhGGlksZY4sJGl8444svINbktRlWEiSugwLSVKXYSFJ6jIs\n", 448 | "JEldhoUkqcuwkCR1GRaSpC7DQpLUZVhIkroMC0lSl2EhSeo6qu+zeDsYfECgJAkMi3mM/kmyknSi\n", 449 | "MywW2TgjFj/OXNJSYVgsOkcskqaPE9ySpC7DQpLUZVhIkrqcs1jCRp0MdyJc0vFmWCxpo2SFOSHp\n", 450 | "+PM0lCSpy7CQJHUZFpKkLsNCktRlWEiSugwLSVKXYSFJ6jIsJEldhoUkqcuwkCR1GRaSpC7DQpLU\n", 451 | "ZVhIkrr81NkTgN/rLel4MyxOCH6vt6Tjq3saKsnXkxxIsnOob3mSbUl2J9ma5PSh525IsifJC0mu\n", 452 | "GOq/JMnO9twtQ/0nJbm39T+R5L1Dz61vP2N3kmuPzSFLksY1ypzF7cDaI/quB7ZV1QXAN9oySVYD\n", 453 | "1wCr2za3Jpl9O3sbsKGqVgGrkszucwNwsPXfDNzU9rUc+BxwaXvcOBxKkqTF0w2LqvoW8IMjuq8E\n", 454 | "trT2FuDq1r4KuKeq3qyqvcCLwGVJzgROraodbb07h7YZ3tcDwOWt/VFga1W9XlWvA9v46dCSJC2C\n", 455 | "o70aakVVHWjtA8CK1j4L2D+03n7g7Dn6Z1o/7d99AFV1CHgjyXvm2ZckaZEt+NLZqipGn2GVJE2h\n", 456 | "o70a6kCSM6rqlXaK6dXWPwOsHFrvHAYjgpnWPrJ/dptzgZeSLANOq6qDSWaANUPbrAQen6uYJJuG\n", 457 | "FrdX1fajOShJOlElWcNPvqaOt/1gYND9IecBD1fVhW353zCYlL4pyfXA6VV1fZvgvpvBhPTZwGPA\n", 458 | "z1dVJXkSuA7YAfwp8NWqejTJRuDCqvrtJOuAq6tqXZvgfhq4mME1n88AF7f5i+HaatR7Bwb3I4wy\n", 459 | "CArjXY46yXXH26f3WUiC8V47YYSRRZJ7gF8CfjbJPgZXKH0JuC/JBmAv8DGAqtqV5D5gF3AI2FiH\n", 460 | "02gjcAdwMvBIVT3a+jcDdyXZAxwE1rV9vZbkC8BTbb3PHxkUkqTFMdLIYilzZOHIQtL4xh1Z+NlQ\n", 461 | "kqQuw0KS1GVYSJK6DAtJUpdhIUnqMiwkSV2GhSSpy7CQJHUZFpKkLsNCktRlWEiSugwLSVKXYSFJ\n", 462 | "6jIsJEldhoUkqcuwkCR1GRaSpC7DQpLUZVhIkroMC0lSl2EhSeoyLCRJXYaFJKlr2aQL0OJKUqOu\n", 463 | "W1U5nrVImh6GxdvOqFlhTkg6zNNQkqQuw0KS1GVYSJK6DAtJUpdhIUnqMiwkSV2GhSSpy7CQJHUZ\n", 464 | "FpKkLsNCktRlWEiSuhYUFkn2Jvl2kmeT7Gh9y5NsS7I7ydYkpw+tf0OSPUleSHLFUP8lSXa2524Z\n", 465 | "6j8pyb2t/4kk711IvZKko7PQkUUBa6rqoqq6tPVdD2yrqguAb7RlkqwGrgFWA2uBW5PMflrdbcCG\n", 466 | "qloFrEqytvVvAA62/puBmxZYryTpKByL01BHfjzplcCW1t4CXN3aVwH3VNWbVbUXeBG4LMmZwKlV\n", 467 | "taOtd+fQNsP7egC4/BjUK0ka07EYWTyW5Okkv9X6VlTVgdY+AKxo7bOA/UPb7gfOnqN/pvXT/t0H\n", 468 | "UFWHgDeSLF9gzZKkMS30+yw+VFUvJ/kbwLYkLww/WVU1zpftHK0km4YWt1fV9uP9MyVpmiRZA6w5\n", 469 | "2u0XFBZV9XL79y+T/DFwKXAgyRlV9Uo7xfRqW30GWDm0+TkMRhQzrX1k/+w25wIvJVkGnFZVr81R\n", 470 | "x6aFHIcknejam+jts8tJbhxn+6M+DZXk3UlObe2/DlwB7AQeAta31dYDD7b2Q8C6JO9Kcj6wCthR\n", 471 | "Va8AP0xyWZvw/nXgT4a2md3XrzGYMJckLbKFjCxWAH/cLmhaBvxBVW1N8jRwX5INwF7gYwBVtSvJ\n", 472 | "fcAu4BCwsapmT1FtBO4ATgYeqapHW/9m4K4ke4CDwLoF1Ksx+X3dkmbl8Ov1dEpSo75QDV78Rjne\n", 473 | "MN53VU9y3Un//MG6hoU0XcZ57QTv4JYkjcCwkCR1GRaSpC7DQpLUZVhIkroMC0lSl2EhSeoyLCRJ\n", 474 | "XYaFJKnLsJAkdRkWkqQuw0KS1GVYSJK6DAtJUtdCv1ZVAkb/7gs/ylyaToaFjpFRv3tD0jTyNJQk\n", 475 | "qcuwkCR1GRaSpC7DQpLUZVhIkroMC0lSl2EhSeoyLCRJXd6Up0U16p3e4N3e0lJiWGiRjZoV5oS0\n", 476 | "lHgaSpLUdUKMLJJ8ctI1SNKJLFUjn0JekgbnwH/jf/XXvP8d8KOTRv/Au3FOl0xy3Un//HHWHW+f\n", 477 | "zllIx0+SGudv7AQJi1GO4YI3YM9pb/cX4Gmq1bCQjp9xw8I5C0lS1wkxZ6ETk5fZSkuHYaElzMts\n", 478 | "paXC01CSpC7DQpLUteTDIsnaJC8k2ZPkX026Hi1NSWrUx6RrlabRkg6LJO8A/j2wFlgNfDzJ+yZb\n", 479 | "1bG2fdIFLND2SRfQ1IiPw5KsWdQSjzHrn6xpr39cSzosgEuBF6tqb1W9CfwhcNWEazrGtk+6gAXa\n", 480 | "PukCxjY0wvjmlI9A1ky6gAVaM+kCFmjNpAtYTEs9LM4G9g0t72990gLMjjJuZL4RiKe2pMOW+qWz\n", 481 | "I/4RfviN/jr7Tl5YKXr7Gf3S3eMVGN4/oqViSX/cR5IPApuqam1bvgH4cVXdNLTO0j0ASVrCTpjP\n", 482 | "hkqyDPgvwOXAS8AO4ONV9b2JFiZJbzNL+jRUVR1K8rvAnwPvADYbFJK0+Jb0yEKStDQs9auh3tI0\n", 483 | "36yXZGWSbyb5bpLvJLlu0jUdjSTvSPJskocnXcu4kpye5P4k30uyq82PTY0kN7Tfn51J7k5y0qRr\n", 484 | "mk+Sryc5kGTnUN/yJNuS7E6yNcnpk6xxPm9R/79tvz/PJ/mjJKdNssa3MlftQ8/98yQ/TrK8t5+p\n", 485 | "DIsT4Ga9N4HPVNX7gQ8CvzNl9c/6NLCL0S8bWkpuAR6pqvcBfxuYmtObSc4Dfgu4uKouZHCKdt0k\n", 486 | "axrB7Qz+XoddD2yrqguAb7TlpWqu+rcC76+qvwPsBm5Y9KpGM1ftJFkJfAT476PsZCrDgim/Wa+q\n", 487 | "Xqmq51r7RwxeqM6abFXjSXIO8A+BrzFlH/va3gH+/ar6OgzmxqpqhMuvl4wfMnjD8e52Eci7gZnJ\n", 488 | "ljS/qvoW8IMjuq8EtrT2FuDqRS1qDHPVX1XbqurHbfFJ4JxFL2wEb/HfHuArwL8cdT/TGhYnzM16\n", 489 | "7V3iRQx+2abJzcC/AH7cW3EJOh/4yyS3J/nPSf5jkndPuqhRVdVrwJeB/8HgKsHXq+qxyVZ1VFZU\n", 490 | "1YHWPgCsmGQxC/SbwCOTLmJUSa4C9lfVt0fdZlrDYhpPe/yUJKcA9wOfbiOMqZDkHwGvVtWzTNmo\n", 491 | "olkGXAzcWlUXA/+TpX0K5Cck+TngnwHnMRiRnpLkn0y0qAWqwZU2U/l3neRfA/+3qu6edC2jaG+M\n", 492 | "PsvgIwz+f3dvu2kNixlg5dDySgaji6mR5J3AA8DvV9WDk65nTH8PuDLJ94F7gA8nuXPCNY1jP4N3\n", 493 | "VU+15fsZhMe0+LvAX1TVwao6BPwRg/8n0+ZAkjMAkpwJvDrhesaW5DcYnI6dprD+OQZvNJ5vf8Pn\n", 494 | "AM8k+ZvzbTStYfE0sCrJeUneBVwDPDThmkaWJMBmYFdV/d6k6xlXVX22qlZW1fkMJlYfr6prJ13X\n", 495 | "qKrqFWBfkgta1y8D351gSeN6AfhgkpPb79IvM7jQYNo8BKxv7fXAVL1pSrKWwanYq6rqf0+6nlFV\n", 496 | "1c6qWlFV57e/4f0MLpaYN6ynMizau6nZm/V2AfdO2c16HwI+AfyDdunps+0Xb1pN4+mDTwF/kOR5\n", 497 | "BldDfXHC9Yysqp4H7mTwpmn2nPN/mFxFfUnuAf4C+IUk+5L8U+BLwEeS7AY+3JaXpDnq/03g3wGn\n", 498 | "ANva3/CtEy3yLQzVfsHQf/thI/39elOeJKlrKkcWkqTFZVhIkroMC0lSl2EhSeoyLCRJXYaFJKnL\n", 499 | "sJAkdRkWkqSu/we225Y0XFjemQAAAABJRU5ErkJggg==\n" 500 | ], 501 | "text/plain": [ 502 | "" 503 | ] 504 | }, 505 | "metadata": {}, 506 | "output_type": "display_data" 507 | } 508 | ], 509 | "source": [ 510 | "plt.hist(np.log1p(degrees), bins = 30);" 511 | ] 512 | }, 513 | { 514 | "cell_type": "markdown", 515 | "metadata": {}, 516 | "source": [ 517 | "Edges going up are parts of cycles. Let's detect them:" 518 | ] 519 | }, 520 | { 521 | "cell_type": "code", 522 | "execution_count": 67, 523 | "metadata": { 524 | "collapsed": true 525 | }, 526 | "outputs": [], 527 | "source": [ 528 | "def get_upward_edges(depthmap, linking):\n", 529 | " upward_connections = set()\n", 530 | " total = 0\n", 531 | " for key in linking.keys():\n", 532 | " for child in linking[key]:\n", 533 | " # if child is higher up in the tree\n", 534 | " # then this is an upward connection\n", 535 | " if key in depthmap:\n", 536 | " if child.startswith(\"Category:\"):\n", 537 | " if depthmap[key] < depthmap[child]:\n", 538 | " upward_connections.add((key, child))\n", 539 | " total += 1\n", 540 | " return (upward_connections, total)" 541 | ] 542 | }, 543 | { 544 | "cell_type": "code", 545 | "execution_count": 164, 546 | "metadata": { 547 | "collapsed": false 548 | }, 549 | "outputs": [], 550 | "source": [ 551 | "def get_connected_articles(roots, linking):\n", 552 | " connected_articles = set()\n", 553 | " visited = set()\n", 554 | " to_visit = list(roots)\n", 555 | " while len(to_visit) > 0:\n", 556 | " root = to_visit.pop()\n", 557 | " visited.add(root)\n", 558 | " for child in linking.get(\"Category:\"+root,[]):\n", 559 | " if child.startswith(\"Category:\"):\n", 560 | " if child[9:] not in visited:\n", 561 | " to_visit.append(child[9:])\n", 562 | " else:\n", 563 | " connected_articles.add(child)\n", 564 | " return connected_articles" 565 | ] 566 | }, 567 | { 568 | "cell_type": "code", 569 | "execution_count": 165, 570 | "metadata": { 571 | "collapsed": false 572 | }, 573 | "outputs": [], 574 | "source": [ 575 | "connected_arts = get_connected_articles(non_date_fixed_points, graph)" 576 | ] 577 | }, 578 | { 579 | "cell_type": "code", 580 | "execution_count": 166, 581 | "metadata": { 582 | "collapsed": false 583 | }, 584 | "outputs": [ 585 | { 586 | "data": { 587 | "text/plain": [ 588 | "4946350" 589 | ] 590 | }, 591 | "execution_count": 166, 592 | "metadata": {}, 593 | "output_type": "execute_result" 594 | } 595 | ], 596 | "source": [ 597 | "len(connected_arts)" 598 | ] 599 | }, 600 | { 601 | "cell_type": "code", 602 | "execution_count": 16, 603 | "metadata": { 604 | "collapsed": false 605 | }, 606 | "outputs": [], 607 | "source": [ 608 | "targets = {}\n", 609 | "with gzip.open(\"/Users/jonathanraiman/Desktop/datasets/index2target.clean.gz\", \"rb\") as f:\n", 610 | " for k, l in enumerate(f):\n", 611 | " l2 = uber_decode(l)\n", 612 | " targets[l2.strip()] = k" 613 | ] 614 | }, 615 | { 616 | "cell_type": "code", 617 | "execution_count": 17, 618 | "metadata": { 619 | "collapsed": false 620 | }, 621 | "outputs": [], 622 | "source": [ 623 | "detected = set()\n", 624 | "missing = set()\n", 625 | "iffy_detected = set()\n", 626 | "for title in art_visited:\n", 627 | " if title in targets:\n", 628 | " detected.add((title, targets[title]))\n", 629 | " elif preprocess_title(title) in targets:\n", 630 | " detected.add((preprocess_title(title), targets[preprocess_title(title)]))\n", 631 | " else:\n", 632 | " if \"(\" in title:\n", 633 | " if title.split(\"(\", 1)[0].strip() in targets:\n", 634 | " iffy_detected.add((title.split(\"(\", 1)[0].strip(), targets[title.split(\"(\", 1)[0].strip()]))\n", 635 | " else:\n", 636 | " missing.add(title)\n", 637 | " else:\n", 638 | " missing.add(title)" 639 | ] 640 | }, 641 | { 642 | "cell_type": "code", 643 | "execution_count": 23, 644 | "metadata": { 645 | "collapsed": false 646 | }, 647 | "outputs": [], 648 | "source": [ 649 | "import sqlite3\n", 650 | "import xml_cleaner\n", 651 | "import wikipedia_ner.parse\n", 652 | "import gzip\n", 653 | "from os.path import join, isdir, exists\n", 654 | "\n", 655 | "def uber_decode(s):\n", 656 | " try:\n", 657 | " return s.decode(\"utf-8\")\n", 658 | " except:\n", 659 | " return s.decode(\"unicode-escape\")\n", 660 | "\n", 661 | "def preprocess_title(s):\n", 662 | " return \" \".join([word\n", 663 | " for sentence in xml_cleaner.tokenize(s)\n", 664 | " for word in sentence])\n", 665 | "\n", 666 | "\n", 667 | "inpath = \"/Users/jonathanraiman/Desktop/datasets/enwiki.db\"\n", 668 | "outpath = \"/Users/jonathanraiman/Desktop/datasets/wiki_animals_onto/\"\n", 669 | "sqlite_conn = sqlite3.connect(\n", 670 | " inpath,\n", 671 | " detect_types=sqlite3.PARSE_DECLTYPES)\n", 672 | "insert_into_db, update_in_db, update_lines_in_db, get_obj_from_db, get_lines_from_db = wikipedia_ner.parse.sqlite_utils.create_schema(sqlite_conn, [\n", 673 | " (\"lines\", \"pickle\"),\n", 674 | " (\"parents\", \"pickle\")\n", 675 | " ],\n", 676 | " \"articles\")" 677 | ] 678 | }, 679 | { 680 | "cell_type": "code", 681 | "execution_count": 24, 682 | "metadata": { 683 | "collapsed": false 684 | }, 685 | "outputs": [], 686 | "source": [ 687 | "missing = 0\n", 688 | "found = 0\n", 689 | "corpuses = []\n", 690 | "total = 100000\n", 691 | "\n", 692 | "max_labels = 1\n", 693 | "\n", 694 | "\n", 695 | "for title, num in list(detected | iffy_detected)[:total]:\n", 696 | " objs = get_lines_from_db(num)\n", 697 | " if objs is not None and type(objs[0]) is not list:\n", 698 | " corpuses.append(objs[0])\n", 699 | " found += 1\n", 700 | " else:\n", 701 | " missing += 1\n", 702 | " \n", 703 | "fix_succeeded = 0\n", 704 | "fix_failed = 0\n", 705 | "failed = []\n", 706 | "sqlite_conn.close()" 707 | ] 708 | }, 709 | { 710 | "cell_type": "code", 711 | "execution_count": 25, 712 | "metadata": { 713 | "collapsed": false 714 | }, 715 | "outputs": [], 716 | "source": [ 717 | "tsv = True\n", 718 | "if tsv:\n", 719 | " outpath_fname = outpath\n", 720 | " if isdir(outpath_fname):\n", 721 | " outpath_fname = join(outpath_fname, \"train.tsv.gz\")\n", 722 | " with gzip.open(outpath_fname, \"wt\") as fout:\n", 723 | " for k, corpus in enumerate(corpuses):\n", 724 | " for example in corpus.example:\n", 725 | " kept_triggers = []\n", 726 | " for trigger in example.trigger:\n", 727 | " if trigger.trigger.lower().startswith(\"category:\") or trigger.trigger.lower().startswith(\"category :\"):\n", 728 | " continue\n", 729 | " elif len(trigger.trigger.strip()) > 0:\n", 730 | " if trigger.trigger.strip() in visited:\n", 731 | " if trigger.trigger.startswith(\"Category:\"):\n", 732 | " print(\"hello\")\n", 733 | " kept_triggers.append(trigger.trigger)\n", 734 | " else:\n", 735 | " new_trigger = (trigger.trigger\n", 736 | " .replace(\"( \", \"(\") \\\n", 737 | " .replace(\" )\", \")\") \\\n", 738 | " .replace(\" , \", \", \") \\\n", 739 | " .replace(\" : \", \":\") \\\n", 740 | " .replace(\" 's \", \"'s\") \\\n", 741 | " .replace(\"s ' \", \"s' \") \\\n", 742 | " .replace(\" - \", \"-\") \\\n", 743 | " .replace(\" l' \", \" l'\") \\\n", 744 | " .replace(\"l ' \", \"l' \") \\\n", 745 | " .replace(\" d' \", \" d'\"))\n", 746 | " new_trigger = new_trigger[0].upper() + new_trigger[1:]\n", 747 | " if new_trigger in visited:\n", 748 | " kept_triggers.append(new_trigger)\n", 749 | " fix_succeeded += 1\n", 750 | " else:\n", 751 | " failed.append(trigger.trigger)\n", 752 | " fix_failed += 1\n", 753 | "\n", 754 | " if len(kept_triggers) > 0 and len(kept_triggers) <= max_labels:\n", 755 | " fout.write(\" \".join(example.words))\n", 756 | " for trig in kept_triggers:\n", 757 | " if \"Category:\" in trig:\n", 758 | " pass\n", 759 | " fout.write(\"\\t\")\n", 760 | " fout.write(trig)\n", 761 | " fout.write(\"\\n\")\n", 762 | "sqlite_conn.close()" 763 | ] 764 | }, 765 | { 766 | "cell_type": "code", 767 | "execution_count": null, 768 | "metadata": { 769 | "collapsed": true 770 | }, 771 | "outputs": [], 772 | "source": [] 773 | } 774 | ], 775 | "metadata": { 776 | "kernelspec": { 777 | "display_name": "Python 3", 778 | "language": "python", 779 | "name": "python3" 780 | }, 781 | "language_info": { 782 | "codemirror_mode": { 783 | "name": "ipython", 784 | "version": 3 785 | }, 786 | "file_extension": ".py", 787 | "mimetype": "text/x-python", 788 | "name": "python", 789 | "nbconvert_exporter": "python", 790 | "pygments_lexer": "ipython3", 791 | "version": "3.4.3" 792 | } 793 | }, 794 | "nbformat": 4, 795 | "nbformat_minor": 0 796 | } 797 | -------------------------------------------------------------------------------- /resolve_redirections.py: -------------------------------------------------------------------------------- 1 | import sys, gzip 2 | from epub_conversion.wiki_decoder import almost_smart_open, get_redirection_list 3 | import time 4 | 5 | def main(path, outpath): 6 | wiki = almost_smart_open(path) 7 | redirects_to = {} 8 | print("Getting redirections") 9 | redirects = 0 10 | t0 = time.time() 11 | speed = 0.0 12 | increment = 100 13 | for page_title, destination in get_redirection_list(wiki): 14 | # can we skip a step? 15 | redirects += 1 16 | if destination in redirects_to: 17 | # if yes we can shortcut destination and 18 | # immediately connect to redirects_ot 19 | redirects_to[page_title] = redirects_to[destination] 20 | else: 21 | # if not wire up page_title to destination 22 | redirects_to[page_title] = destination 23 | if redirects % increment == 0: 24 | speed = 0.8 * speed + 0.2 * (float(increment) / (time.time() - t0)) 25 | t0 = time.time() 26 | print("%d so far, %.3f redirects/s \r" % (redirects, speed), end="", flush=True) 27 | 28 | print("Got all the redirections, now following redirections") 29 | total_rewires = 0 30 | rewires = 0 31 | epoch = 0 32 | changed = None 33 | while True: 34 | new_changed = set() 35 | rewires = 0 36 | to_remove = set() 37 | print("Epoch %d, total_rewires %d" % (epoch, total_rewires)) 38 | if epoch == 0: 39 | for link, value in redirects_to.items(): 40 | if value in redirects_to: 41 | redirects_to[link] = redirects_to[value] 42 | new_changed.add(link) 43 | rewires += 1 44 | else: 45 | for link in changed: 46 | value = redirects_to[link] 47 | if value in redirects_to: 48 | if value == link: 49 | to_remove.add(value) 50 | else: 51 | redirects_to[link] = redirects_to[value] 52 | new_changed.add(link) 53 | rewires += 1 54 | 55 | for link in to_remove: 56 | del redirects_to[link] 57 | 58 | total_rewires += rewires 59 | if rewires is 0: 60 | break 61 | changed = new_changed 62 | epoch += 1 63 | 64 | with open(outpath, "wt") as f: 65 | for source, target in redirects_to.items(): 66 | f.write("%s;%s\n" % (source, target)) 67 | 68 | if __name__ == "__main__": 69 | if len(sys.argv) != 3: 70 | print("resolve_redirections [wiki_dump_path.bz2] [outpath]") 71 | sys.exit(1) 72 | dump_path = sys.argv[1] 73 | outpath = sys.argv[2] 74 | main(dump_path, outpath) 75 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | from setuptools import setup, find_packages 3 | 4 | def readfile(fname): 5 | return open(os.path.join(os.path.dirname(__file__), fname)).read() 6 | 7 | setup( 8 | name='wikipedia-ner', 9 | version='0.0.24', 10 | description='Python package for creating labeled examples from wiki dumps', 11 | long_description=readfile('README.md'), 12 | ext_modules=[], 13 | packages=find_packages(), 14 | author='Jonathan Raiman', 15 | author_email='jraiman at mit dot edu', 16 | url='https://github.com/JonathanRaiman/wikipedia_ner', 17 | download_url='https://github.com/JonathanRaiman/wikipedia_ner', 18 | keywords='XML, epub, tokenization, NLP', 19 | license='MIT', 20 | platforms='any', 21 | zip_safe=False, 22 | classifiers=[ 23 | 'Intended Audience :: Science/Research', 24 | 'Operating System :: OS Independent', 25 | 'Programming Language :: Python :: 3.3', 26 | 'Topic :: Text Processing :: Linguistic', 27 | ], 28 | # test_suite="something.test", 29 | setup_requires = [], 30 | install_requires=[ 31 | 'xml_cleaner', 32 | 'epub_conversion' 33 | ], 34 | include_package_data=True, 35 | ) 36 | -------------------------------------------------------------------------------- /wikipedia_ner/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Wikipedia NER module for creating labeled examples 3 | from wiki dumps for Named Entity Recognition training 4 | """ -------------------------------------------------------------------------------- /wikipedia_ner/parse/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Parsing sub module for converting wiki xml dump pages to labeled examples 3 | """ 4 | 5 | from .parse import parse_dump 6 | from .dump_result import DumpResult 7 | from .pages import ParsedPage, ParsedPageChild, ParsedPageParent 8 | 9 | __all__ = ["parse_dump","DumpResult","ParsedPage","ParsedPageChild","ParsedPageParent"] -------------------------------------------------------------------------------- /wikipedia_ner/parse/dump_result.py: -------------------------------------------------------------------------------- 1 | from collections import Counter 2 | from .pages import ParsedPageChild 3 | 4 | class DumpResult: 5 | """ 6 | Stores the result of a dump parse. 7 | Contains the lines observed with their intra wiki links, 8 | the counters for each article seen, 9 | and the targets along with a mapping to a unique integer id. 10 | """ 11 | 12 | def __init__(self): 13 | """ 14 | Stores the result of a dump parse. 15 | Contains the lines observed with their intra wiki links, 16 | the counters for each article seen, 17 | and the targets along with a mapping to a unique integer id. 18 | """ 19 | self.stored_lines = {} 20 | self.target_counters = Counter() 21 | self.targets = {} 22 | self.index2target = [] 23 | 24 | def observe_line(self, line, article_name, links): 25 | """ 26 | Adds a set of line to the result by integrating the 27 | article name, the links, and converting the links to their 28 | unique ids as stored previously. 29 | 30 | Inputs 31 | ------ 32 | 33 | line list : a list of strings with double bracket 34 | wiki syntax inter wiki links 35 | article_name str : the name of the article these links come 36 | from. 37 | links list> : a pairing of target and anchor text 38 | 39 | """ 40 | 41 | if article_name in self.stored_lines: 42 | page = self.stored_lines[article_name] 43 | else: 44 | # get the id of this article: 45 | if article_name in self.targets: 46 | article_id = self.targets[article_name] 47 | else: 48 | article_id = len(self.targets) 49 | self.targets[article_name] = article_id 50 | self.index2target.append(article_name) 51 | 52 | page = ParsedPageChild(article_name, article_id) 53 | self.stored_lines[article_name] = page 54 | 55 | page.lines.append( 56 | (line, list(self.replace_links_with_index(links))) 57 | ) 58 | 59 | page.add_parents([(link[0], self.targets[link[0]]) for link in links if link[0].startswith("Category")]) 60 | self.target_counters.update((link[0] for link in links)) 61 | 62 | def replace_links_with_index(self, links): 63 | """ 64 | Takes a set of tuples of targets and anchor text and replaces the 65 | targets by their integer id from the dump result. 66 | 67 | Inputs 68 | ------ 69 | 70 | links list> : a pairing of target and anchor text 71 | 72 | """ 73 | for target, anchor in links: 74 | if target in self.targets: 75 | yield((self.targets[target], anchor)) 76 | else: 77 | self.targets[target] = len(self.targets) 78 | self.index2target.append(target) 79 | yield((self.targets[target], anchor)) 80 | 81 | import sqlite3 82 | from .sqlite_utils import create_schema, serialize_protobuf, deserialize_protobuf, convert_examples_to_protobuff 83 | import pickle 84 | from .sqlite_proto_buff import corpus_pb2 85 | 86 | sqlite3.register_converter("protobuf", deserialize_protobuf) 87 | sqlite3.register_converter("pickle", pickle.loads) 88 | sqlite3.register_adapter(corpus_pb2.Corpus, serialize_protobuf) 89 | sqlite3.register_adapter(list, pickle.dumps) 90 | sqlite3.register_adapter(set, pickle.dumps) 91 | 92 | class DumpResultSqlite(DumpResult): 93 | def __init__(self, sqlite_path, commit_frequency = 50): 94 | self.sqlite_path = sqlite_path 95 | self.sqlite_conn = sqlite3.connect( 96 | sqlite_path, 97 | detect_types=sqlite3.PARSE_DECLTYPES) 98 | 99 | insert_into_db, update_in_db, update_lines_in_db, get_obj_from_db, get_lines_from_db = create_schema( 100 | self.sqlite_conn, 101 | [ 102 | ("lines", "protobuf"), 103 | ("parents", "pickle") 104 | ], 105 | "articles") 106 | 107 | self.insert_into_db = insert_into_db 108 | self.update_in_db = update_in_db 109 | self.update_lines_in_db = update_lines_in_db 110 | self.get_obj_from_db = get_obj_from_db 111 | self.get_lines_from_db = get_lines_from_db 112 | 113 | self.commit_frequency = commit_frequency 114 | self.to_insert = {} 115 | self.to_insert_parents = {} 116 | self.to_update = {} 117 | self.to_update_parents = {} 118 | DumpResult.__init__(self) 119 | 120 | def should_save_to_db(self): 121 | return ( 122 | (len(self.to_insert) > self.commit_frequency) or \ 123 | (len(self.to_insert_parents) > self.commit_frequency) or \ 124 | (len(self.to_update) > self.commit_frequency) or \ 125 | (len(self.to_update_parents) > self.commit_frequency)) 126 | 127 | def update_db(self): 128 | insert_keys = list(self.to_insert.keys()) 129 | 130 | for key in insert_keys: 131 | # create a new saved copy in the db: 132 | self.insert_into_db( 133 | ( 134 | self.targets[key], 135 | self.to_insert[key], 136 | self.to_insert_parents[key] 137 | ) 138 | ) 139 | self.stored_lines[key] = True 140 | del self.to_insert[key] 141 | del self.to_insert_parents[key] 142 | 143 | update_keys = list(self.to_update.keys()) 144 | 145 | for key in update_keys: 146 | object_id = self.targets[key] 147 | # get previous saved copy: 148 | old_key, corpus, parents = self.get_obj_from_db(object_id) 149 | 150 | for example in self.to_update[key]: 151 | ex = corpus.example.add() 152 | ex.words.extend(example[0]) 153 | for trigger_id, trigger_text in example[1]: 154 | trig = ex.trigger.add() 155 | trig.id = trigger_id 156 | trig.trigger = trigger_text 157 | 158 | # update that copy 159 | self.update_in_db( 160 | ( 161 | corpus, 162 | parents.update( self.to_update_parents[key] ), 163 | object_id 164 | ) 165 | ) 166 | del self.to_update[key] 167 | del self.to_update_parents[key] 168 | 169 | def close(self): 170 | self.sqlite_conn.close() 171 | 172 | def observe_line(self, line, article_name, links): 173 | """ 174 | Adds a set of line to the result by integrating the 175 | article name, the links, and converting the links to their 176 | unique ids as stored previously. 177 | 178 | Inputs 179 | ------ 180 | 181 | line list : a list of strings with double bracket 182 | wiki syntax inter wiki links 183 | article_name str : the name of the article these links come 184 | from. 185 | links list> : a pairing of target and anchor text 186 | 187 | """ 188 | 189 | if article_name in self.stored_lines: 190 | # remember whether the page exists in the db: 191 | 192 | if article_name not in self.to_update: 193 | self.to_update[article_name] = [] 194 | self.to_update_parents[article_name] = set() 195 | 196 | self.to_update[article_name].append( 197 | (line, list(self.replace_links_with_index(links))) 198 | ) 199 | cat_links = [self.targets[link[0]] for link in links if link[0].startswith("Category")] 200 | 201 | if len(cat_links) > 0: 202 | self.to_update_parents[article_name].update( 203 | cat_links 204 | ) 205 | 206 | else: 207 | # get the id of this article: 208 | if article_name in self.targets: 209 | article_id = self.targets[article_name] 210 | else: 211 | article_id = len(self.targets) 212 | self.targets[article_name] = article_id 213 | self.index2target.append(article_name) 214 | 215 | if article_name not in self.to_insert: 216 | self.to_insert[article_name] = corpus_pb2.Corpus() 217 | self.to_insert_parents[article_name] = set() 218 | 219 | ex = self.to_insert[article_name].example.add() 220 | ex.words.extend(line) 221 | for trigger_id, trigger_text in self.replace_links_with_index(links): 222 | trig = ex.trigger.add() 223 | trig.id = trigger_id 224 | trig.trigger = trigger_text 225 | 226 | cat_links = [self.targets[link[0]] for link in links if link[0].startswith("Category")] 227 | if len(cat_links) > 0: 228 | self.to_insert_parents[article_name].update( 229 | cat_links 230 | ) 231 | 232 | self.target_counters.update((link[0] for link in links)) 233 | 234 | if self.should_save_to_db(): 235 | self.update_db() 236 | -------------------------------------------------------------------------------- /wikipedia_ner/parse/pages/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Module for Container classes useful for storing metadata 3 | and graph relations within the wiki stored in a wiki dump. 4 | 5 | """ 6 | 7 | from .parsed_page import ParsedPage 8 | from .parsed_page_child import ParsedPageChild 9 | from .parsed_page_parent import ParsedPageParent 10 | 11 | __all__ = ["ParsedPage", "ParsedPageChild", "ParsedPageParent"] -------------------------------------------------------------------------------- /wikipedia_ner/parse/pages/parsed_page.py: -------------------------------------------------------------------------------- 1 | from collections import Counter 2 | 3 | class ParsedPage: 4 | """ 5 | Stores the content of a parsed page 6 | """ 7 | 8 | categories = {} 9 | categories_counter = Counter() 10 | 11 | def __init__(self, name, id): 12 | """ 13 | Add a name and an id to a parsed page 14 | for referencing. 15 | """ 16 | self.id = id 17 | self.name = name -------------------------------------------------------------------------------- /wikipedia_ner/parse/pages/parsed_page_child.py: -------------------------------------------------------------------------------- 1 | from .parsed_page import ParsedPage 2 | from .parsed_page_parent import ParsedPageParent 3 | 4 | class ParsedPageChild(ParsedPage): 5 | """ 6 | Stores the content of a parsed page. Specialized for 7 | child pages (that can have parent pages, e.g. categories) 8 | 9 | """ 10 | def __init__(self, *args): 11 | super().__init__(*args) 12 | self.lines = [] 13 | self.parents = set() 14 | 15 | def add_parents(self, parents): 16 | """ 17 | Add parents to a parsed page 18 | 19 | Inputs 20 | ------ 21 | 22 | parents list : a list of parent ids that correspond to this page 23 | 24 | """ 25 | for parent, parent_id in parents: 26 | if parent in ParsedPage.categories: 27 | parent_page = ParsedPage.categories[parent] 28 | else: 29 | parent_page = ParsedPageParent(parent, parent_id) 30 | ParsedPage.categories[parent] = parent_page 31 | 32 | parent_page.add_child(self.id) 33 | 34 | self.parents.update([link[1] for link in parents]) -------------------------------------------------------------------------------- /wikipedia_ner/parse/pages/parsed_page_parent.py: -------------------------------------------------------------------------------- 1 | from .parsed_page import ParsedPage 2 | 3 | class ParsedPageParent(ParsedPage): 4 | """ 5 | Stores the content of a parsed page. Specialized for 6 | parent pages (that can have children pages, e.g. leaves 7 | / articles) 8 | 9 | """ 10 | 11 | def __init__(self, *args): 12 | super().__init__(*args) 13 | self.children = set() 14 | 15 | def add_child(self, child): 16 | """ 17 | Register a new child for a category 18 | """ 19 | self.children.add(child) 20 | ParsedPage.categories_counter.update([self.name]) -------------------------------------------------------------------------------- /wikipedia_ner/parse/parse.py: -------------------------------------------------------------------------------- 1 | from epub_conversion import convert_wiki_to_lines 2 | from epub_conversion.wiki_decoder import almost_smart_open 3 | from .utils import line_converter 4 | from .dump_result import DumpResult, DumpResultSqlite 5 | 6 | def parse_dump(path, sqlite= False, commit_frequency = 300, sqlite_path="out.db", max_articles = 1000, report_every = 100, clear_output = False): 7 | """ 8 | Convert a dump to a set of articles with their 9 | text tokenized and the intrawiki links separated and 10 | matched with the corresponding sentences. 11 | Also creates a unique id over the articles for better 12 | memory footprint (though overall this script is probably 13 | notoriously bad at its memory management) 14 | 15 | 16 | Inputs 17 | ------ 18 | path str : the location of the wiki 19 | dump (bz2 or xml file). 20 | max_articles int : the number of [valid] articles 21 | to be read before stopping 22 | 23 | 24 | Output 25 | ------ 26 | result DumpResult : the result of the parse. 27 | 28 | """ 29 | if sqlite: 30 | result = DumpResultSqlite(sqlite_path) 31 | else: 32 | result = DumpResult() 33 | wiki = almost_smart_open(path) 34 | 35 | for line, article_name, links in convert_wiki_to_lines( 36 | wiki, 37 | max_articles = max_articles, 38 | clear_output = clear_output, 39 | report_every = report_every, 40 | line_converter = line_converter): 41 | result.observe_line(line, article_name, links) 42 | 43 | if sqlite: 44 | # flush out any remaining pieces to put in the db. 45 | result.update_db() 46 | result.close() 47 | return result -------------------------------------------------------------------------------- /wikipedia_ner/parse/parsed_page.py: -------------------------------------------------------------------------------- 1 | class ParsedPage: 2 | """ 3 | Stores the content of a parsed page 4 | """ 5 | 6 | categories = {} 7 | 8 | def __init__(self, name, id): 9 | """ 10 | Add a name and an id to a parsed page 11 | for referencing. 12 | """ 13 | self.id = id 14 | self.name = name 15 | self.lines = [] 16 | self.parents = set() 17 | 18 | def add_parents(self, parents): 19 | """ 20 | Add parents to a parsed page 21 | 22 | Inputs 23 | ------ 24 | 25 | parents list : a list of parent ids that correspond to this page 26 | 27 | """ 28 | for parent, parent_id in parents: 29 | if ParsedPageParent.categories.get(parent, None): 30 | parent_page = ParsedPageParent.categories[parent] 31 | else: 32 | parent_page = ParsedPageParent(parent, parent_id) 33 | ParsedPageParent.categories[parent] = parent_page 34 | 35 | parent_page.add_child(self.id) 36 | 37 | 38 | self.parents.update(parents) -------------------------------------------------------------------------------- /wikipedia_ner/parse/sqlite_proto_buff/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonathanRaiman/wikipedia_ner/b6215c38a58e019a566411445ff440c2a2ea9d2b/wikipedia_ner/parse/sqlite_proto_buff/__init__.py -------------------------------------------------------------------------------- /wikipedia_ner/parse/sqlite_proto_buff/corpus_pb2.py: -------------------------------------------------------------------------------- 1 | # Generated by the protocol buffer compiler. DO NOT EDIT! 2 | # source: corpus.proto 3 | 4 | import sys 5 | _b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) 6 | from google.protobuf import descriptor as _descriptor 7 | from google.protobuf import message as _message 8 | from google.protobuf import reflection as _reflection 9 | from google.protobuf import symbol_database as _symbol_database 10 | from google.protobuf import descriptor_pb2 11 | # @@protoc_insertion_point(imports) 12 | 13 | _sym_db = _symbol_database.Default() 14 | 15 | 16 | 17 | 18 | DESCRIPTOR = _descriptor.FileDescriptor( 19 | name='corpus.proto', 20 | package='', 21 | serialized_pb=_b('\n\x0c\x63orpus.proto\"c\n\x07\x45xample\x12\r\n\x05words\x18\x01 \x03(\t\x12!\n\x07trigger\x18\x02 \x03(\x0b\x32\x10.Example.Trigger\x1a&\n\x07Trigger\x12\n\n\x02id\x18\x01 \x02(\x05\x12\x0f\n\x07trigger\x18\x02 \x02(\t\"#\n\x06\x43orpus\x12\x19\n\x07\x65xample\x18\x01 \x03(\x0b\x32\x08.Example') 22 | ) 23 | _sym_db.RegisterFileDescriptor(DESCRIPTOR) 24 | 25 | 26 | 27 | 28 | _EXAMPLE_TRIGGER = _descriptor.Descriptor( 29 | name='Trigger', 30 | full_name='Example.Trigger', 31 | filename=None, 32 | file=DESCRIPTOR, 33 | containing_type=None, 34 | fields=[ 35 | _descriptor.FieldDescriptor( 36 | name='id', full_name='Example.Trigger.id', index=0, 37 | number=1, type=5, cpp_type=1, label=2, 38 | has_default_value=False, default_value=0, 39 | message_type=None, enum_type=None, containing_type=None, 40 | is_extension=False, extension_scope=None, 41 | options=None), 42 | _descriptor.FieldDescriptor( 43 | name='trigger', full_name='Example.Trigger.trigger', index=1, 44 | number=2, type=9, cpp_type=9, label=2, 45 | has_default_value=False, default_value=_b("").decode('utf-8'), 46 | message_type=None, enum_type=None, containing_type=None, 47 | is_extension=False, extension_scope=None, 48 | options=None), 49 | ], 50 | extensions=[ 51 | ], 52 | nested_types=[], 53 | enum_types=[ 54 | ], 55 | options=None, 56 | is_extendable=False, 57 | extension_ranges=[], 58 | oneofs=[ 59 | ], 60 | serialized_start=77, 61 | serialized_end=115, 62 | ) 63 | 64 | _EXAMPLE = _descriptor.Descriptor( 65 | name='Example', 66 | full_name='Example', 67 | filename=None, 68 | file=DESCRIPTOR, 69 | containing_type=None, 70 | fields=[ 71 | _descriptor.FieldDescriptor( 72 | name='words', full_name='Example.words', index=0, 73 | number=1, type=9, cpp_type=9, label=3, 74 | has_default_value=False, default_value=[], 75 | message_type=None, enum_type=None, containing_type=None, 76 | is_extension=False, extension_scope=None, 77 | options=None), 78 | _descriptor.FieldDescriptor( 79 | name='trigger', full_name='Example.trigger', index=1, 80 | number=2, type=11, cpp_type=10, label=3, 81 | has_default_value=False, default_value=[], 82 | message_type=None, enum_type=None, containing_type=None, 83 | is_extension=False, extension_scope=None, 84 | options=None), 85 | ], 86 | extensions=[ 87 | ], 88 | nested_types=[_EXAMPLE_TRIGGER, ], 89 | enum_types=[ 90 | ], 91 | options=None, 92 | is_extendable=False, 93 | extension_ranges=[], 94 | oneofs=[ 95 | ], 96 | serialized_start=16, 97 | serialized_end=115, 98 | ) 99 | 100 | 101 | _CORPUS = _descriptor.Descriptor( 102 | name='Corpus', 103 | full_name='Corpus', 104 | filename=None, 105 | file=DESCRIPTOR, 106 | containing_type=None, 107 | fields=[ 108 | _descriptor.FieldDescriptor( 109 | name='example', full_name='Corpus.example', index=0, 110 | number=1, type=11, cpp_type=10, label=3, 111 | has_default_value=False, default_value=[], 112 | message_type=None, enum_type=None, containing_type=None, 113 | is_extension=False, extension_scope=None, 114 | options=None), 115 | ], 116 | extensions=[ 117 | ], 118 | nested_types=[], 119 | enum_types=[ 120 | ], 121 | options=None, 122 | is_extendable=False, 123 | extension_ranges=[], 124 | oneofs=[ 125 | ], 126 | serialized_start=117, 127 | serialized_end=152, 128 | ) 129 | 130 | _EXAMPLE_TRIGGER.containing_type = _EXAMPLE 131 | _EXAMPLE.fields_by_name['trigger'].message_type = _EXAMPLE_TRIGGER 132 | _CORPUS.fields_by_name['example'].message_type = _EXAMPLE 133 | DESCRIPTOR.message_types_by_name['Example'] = _EXAMPLE 134 | DESCRIPTOR.message_types_by_name['Corpus'] = _CORPUS 135 | 136 | Example = _reflection.GeneratedProtocolMessageType('Example', (_message.Message,), dict( 137 | 138 | Trigger = _reflection.GeneratedProtocolMessageType('Trigger', (_message.Message,), dict( 139 | DESCRIPTOR = _EXAMPLE_TRIGGER, 140 | __module__ = 'corpus_pb2' 141 | # @@protoc_insertion_point(class_scope:Example.Trigger) 142 | )) 143 | , 144 | DESCRIPTOR = _EXAMPLE, 145 | __module__ = 'corpus_pb2' 146 | # @@protoc_insertion_point(class_scope:Example) 147 | )) 148 | _sym_db.RegisterMessage(Example) 149 | _sym_db.RegisterMessage(Example.Trigger) 150 | 151 | Corpus = _reflection.GeneratedProtocolMessageType('Corpus', (_message.Message,), dict( 152 | DESCRIPTOR = _CORPUS, 153 | __module__ = 'corpus_pb2' 154 | # @@protoc_insertion_point(class_scope:Corpus) 155 | )) 156 | _sym_db.RegisterMessage(Corpus) 157 | 158 | 159 | # @@protoc_insertion_point(module_scope) 160 | -------------------------------------------------------------------------------- /wikipedia_ner/parse/sqlite_utils.py: -------------------------------------------------------------------------------- 1 | import sqlite3 2 | 3 | def create_schema(conn, schema, table_name): 4 | symbolic_assignment = ", ".join([name + "=?" for name, row_type in schema]) 5 | symbolic_values = "(" + ", ".join(["?"] * (1 + len(schema))) + ")" 6 | 7 | insert_string = "INSERT into %s values %s" % (table_name, symbolic_values) 8 | update_string = "UPDATE %s SET %s WHERE id=?" % (table_name, symbolic_assignment) 9 | update_string_lines = "UPDATE %s SET lines=? WHERE id=?" % (table_name,) 10 | select_string = "SELECT * FROM %s WHERE id=?" % (table_name,) 11 | select_string_lines = "SELECT lines FROM %s WHERE id=?" % (table_name,) 12 | #lines pickle, parents pickle 13 | 14 | cursor = conn.cursor() 15 | schema_definition = ", \n".join([name + " " + row_type for name, row_type in schema]) 16 | 17 | try: 18 | cursor.execute(""" 19 | CREATE TABLE %s ( 20 | id integer primary key not null, 21 | %s 22 | )""" % (table_name, schema_definition)) 23 | except sqlite3.OperationalError: 24 | pass 25 | 26 | def insert_into_db(obj): 27 | try: 28 | cursor.execute( 29 | insert_string, 30 | obj 31 | ) 32 | conn.commit() 33 | except sqlite3.IntegrityError: 34 | print("Error: sqlite3.IntegrityError => %r" % (obj)) 35 | 36 | def update_in_db(obj): 37 | cursor.execute(update_string, 38 | obj 39 | ) 40 | conn.commit() 41 | 42 | def update_lines_in_db(obj): 43 | cursor.execute(update_string_lines, 44 | obj 45 | ) 46 | conn.commit() 47 | 48 | def get_obj_from_db(key): 49 | cursor.execute(select_string, (key,)) 50 | data = cursor.fetchone() 51 | return data 52 | 53 | def get_lines_from_db(key): 54 | cursor.execute(select_string_lines, (key,)) 55 | data = cursor.fetchone() 56 | return data 57 | 58 | return (insert_into_db, update_in_db, update_lines_in_db, get_obj_from_db, get_lines_from_db) 59 | 60 | from .sqlite_proto_buff import corpus_pb2 61 | 62 | def convert_examples_to_protobuff(legacy): 63 | corpus = corpus_pb2.Corpus() 64 | for example in legacy: 65 | ex = corpus.example.add() 66 | ex.words.extend(example[0]) 67 | triggers = example[1] 68 | for trigger_id, trigger_text in triggers: 69 | trig = ex.trigger.add() 70 | trig.id = trigger_id 71 | trig.trigger = trigger_text 72 | return corpus 73 | 74 | def deserialize_protobuf(blob): 75 | corpus = corpus_pb2.Corpus() 76 | corpus.ParseFromString(blob) 77 | return corpus 78 | 79 | def serialize_protobuf(corpus): 80 | return corpus.SerializeToString() 81 | -------------------------------------------------------------------------------- /wikipedia_ner/parse/utils.py: -------------------------------------------------------------------------------- 1 | import xml_cleaner.wiki_markup_processing as wiki_processing 2 | double_bracket_no_other_ref = wiki_processing.re.compile("\[\[([^\|\]]+)\]\]") 3 | 4 | def get_article_links(sentence): 5 | """ 6 | Uses regular expressions to extract 7 | links from text by looking for double brackets 8 | and optionally pipe characters to symbolic 9 | target and anchor text in wiki markup syntax 10 | 11 | Inputs 12 | ------ 13 | 14 | sentence str: text to parse 15 | 16 | Output 17 | ------ 18 | 19 | list> : list of tuples of target and anchor texts 20 | 21 | """ 22 | pairs_of_anchor_tags = [(target.strip(), anchor.strip()) for target, anchor in wiki_processing.anchortag_internal_link.findall(sentence)] 23 | other_links = [(match.strip(), match.strip()) for match in double_bracket_no_other_ref.findall(sentence)] 24 | return pairs_of_anchor_tags + other_links 25 | 26 | import re 27 | letters = re.compile("$[^a-zA-Z0-9]+") 28 | 29 | def test_okay_sentence(s): 30 | return (\ 31 | ".jpg" not in s and \ 32 | s.count("Category") < 2 and \ 33 | "http" not in s and \ 34 | "ISBN" not in s and \ 35 | "File : | thumb" not in s and \ 36 | ".htm" not in s and \ 37 | ".png" not in s) 38 | 39 | def line_converter(lines, article_name): 40 | """ 41 | Creates generator that takes the valid text from wiki xml dumps 42 | and uses regular expressions to select only the lines 43 | in the wiki that uses intra wiki links and returns the triplets 44 | of valid tokenized sentence, article name, and tuples of targets 45 | and anchor text from intra wiki links. 46 | 47 | Inputs 48 | ------ 49 | 50 | lines str: a block of text from a wiki 51 | article_name str: the name of the current article 52 | 53 | 54 | Outputs 55 | ------- 56 | 57 | tuple>> : triplets 58 | of valid tokenized sentence, article name, and tuples of targets 59 | and anchor text from intra wiki links. 60 | 61 | """ 62 | for sentence in wiki_processing.to_raw_text_pairings(lines): 63 | sentence_cleaned = sentence 64 | sentence = " ".join(sentence).strip() 65 | if test_okay_sentence(sentence): 66 | sentence.replace("<", " < ").replace("< ;", " < ").replace(">", " > ").replace("> ;", " > ") 67 | links = get_article_links(sentence) 68 | if len(links) > 0: 69 | yield((wiki_processing.remove_brackets(sentence).split(" "), article_name, links)) --------------------------------------------------------------------------------