\n",
"\n",
"# `xkcd` Name Dominoes\n",
"\n",
"![](https://norvig.com/xkcd-dominoes.png)\n",
"\n",
"The March 21, 2018 `xkcd` comic (#1970) was **[Name Dominoes](https://xkcd.com/1970/)**: tiles laid out as if in a game of dominoes, but the tiles contain names of famous people. \n",
"In regular [dominoes](https://en.wikipedia.org/wiki/Dominoes) a tile consists of two squares, each with a number of spots from 0 to 6. In xkcd name dominoes, the tiles can be one, two, or three squares in length, and each square contains a name (first, middle, or last). In both versions, a tile can be placed if it is adjacent to another tile on the board, and if no two adjacent squares contain different numbers/names.\n",
"I will write a function, `place_tiles`, to lay out name dominoes according to these rules. \n",
"\n",
"# Key Data Structures:\n",
"\n",
"- **`Tile`**: a tile is a tuple of names, like `('ISSAC', 'NEWTON')`\n",
"or `('FRANK', 'LLOYD', 'WRIGHT')` or `('DRAKE',)`.\n",
"- **`Name`**: a name (first, middle, or last) is a string, like `'FRANK'`.\n",
"- **`Box`**: a structure with a tile, the square that the tile's first name goes on, and the direction in which to move to place subsequent names.\n",
"- **`Point`**: an `(x, y)` pair denoting the coordinates of a square on the board. Can also be used for **directions**: `(0, 1)` is the direction that goes 0 in the x axis and 1 in the y axis; also known as \"up\" or \"90 degrees\".\n",
"- **`Board`**: a [width × height] grid of squares, where each square can be filled with a name. `Board` is implemented as a subclass of `dict` of the form `{(0, 0): 'ISSAC', (0, 1): 'NEWTON', ...}`, but with additional attributes to keep track of the width and height, and the boxes placed so far. If an `(x, y)` square is not in the dict, it is `empty` by default, unless the `(x, y)` coordinates are out of bounds; then it is `off` the board."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"%matplotlib inline\n",
"import matplotlib.pyplot as plt\n",
"import random\n",
"from collections import namedtuple"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"Tile = tuple # e.g., ('ISSAC', 'NEWTON')\n",
"Name = str # e.g., 'ISSAC'\n",
"Box = namedtuple('Box', 'start, dir, tile')\n",
"\n",
"Point = tuple\n",
"def X(point) -> int: \"The x coordinate of a point\"; return point[0]\n",
"def Y(point) -> int: \"The x coordinate of a point\"; return point[1]\n",
"\n",
"directions = {(1, 0): 0, (0, 1): 90, (-1, 0): 180, (0, -1): 270}\n",
"\n",
"off = '.' # A square that is off the edge of the board\n",
"empty = '' # An empty square (does not have a tile covering it)\n",
"\n",
"class Board(dict):\n",
" \"\"\"A mapping from (x, y) squares to names; for a width x height board.\"\"\"\n",
" def __init__(self, width, height): \n",
" \"\"\"Keep track of the width and height, and of boxes that have been placed.\"\"\"\n",
" self.width = width \n",
" self.height = height\n",
" self.boxes = []\n",
" \n",
" def __missing__(self, square: Point) -> str: \n",
" \"\"\"The contents of a filled square is a name; a missing square is empty or off.\"\"\"\n",
" return empty if (0 <= X(square) < self.width and 0 <= Y(square) < self.height) else off"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Algorithm to Fill the Board\n",
"\n",
"Now I need a strategy to fill the board with tiles. I will place tiles one at a time, and to make things easier I will *never* consider removing a tile from the board and backtracking. The major functions are:\n",
"\n",
"\n",
"- **`place_tiles(tiles)`**: The top-level strategy. Makes a board and places tiles on it, one at a time, until no more can be placed. Chooses a random tile for the first tile, then repeatedly calls `try_one_square` to legally place an additional tile on a square from the frontier, stopping when either there is no `frontier` left or no `tiles` left.\n",
"- **`frontier`**: I'll maintain a *frontier*, a set of `(x, y)` squares that are adjacent to tiles on the board, and thus are candidates for placing new tiles.\n",
"- **`try_one_square(tiles, board, frontier)`**: pop a square off the frontier, and try to find some tile that can legally put one of its names there; when found, `put_tile` the tile there, and remove it from `tiles`.\n",
"- **`can_put_tile(tile, board, start, dir)`**: Can we put this tile on the board at this start square, going in this direction?\n",
"- **`can_put_name(name, board, square)`**: Can this one name (first, middle, or last) be placed on this square?\n",
"- **`allowed(name, nbr_contents)`**: Is this name allowed to be placed next to this neighboring square's contents?\n",
"- **`neighbors(square, board)`**: returns the four neighbors of a square.\n",
"- **`put_tile(tile, board, start, dir, tiles, frontier)`**: places a tile on the board starting at `start` and going in direction `dir`; update the `frontier` to say that the just-covered squares are not in the frontier, but the empty neighbors of new tiles are. Remove the tile from `tiles`.\n",
"- **`move(start, steps, dir)`**: Returm the square that results from starting at `start` and going `steps` in \n",
"direction `dir`."
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"def place_tiles(tiles, width=16, height=35) -> Board:\n",
" \"\"\"Place as many tiles on board as possible.\"\"\"\n",
" tiles = list(tiles); random.shuffle(tiles)\n",
" board = Board(width, height)\n",
" frontier = set()\n",
" put_tile(tiles[0], board, (width//2, height//2), (0, 1), tiles, frontier)\n",
" while tiles and frontier:\n",
" try_one_square(tiles, board, frontier) \n",
" return board\n",
"\n",
"def try_one_square(tiles, board, frontier):\n",
" \"\"\"Pop a frontier square, and try to place a tile on that square.\"\"\"\n",
" square = frontier.pop()\n",
" for tile in tiles:\n",
" # The offset is used to shift the tile along `direction`\n",
" for offset in range(len(tile)):\n",
" for dir in directions:\n",
" start = move(square, -offset, dir)\n",
" if can_put_tile(tile, board, start, dir):\n",
" return put_tile(tile, board, start, dir, tiles, frontier)\n",
" \n",
"def can_put_tile(tile, board, start, dir) -> bool:\n",
" \"\"\"Is it legal to put this tile on this square/direction on board?\"\"\"\n",
" return all(can_put_name(name, board, move(start, i, dir))\n",
" for i, name in enumerate(tile))\n",
"\n",
"def can_put_name(name, board, square) -> bool:\n",
" return (board[square] is empty \n",
" and all(allowed(name, board[nbr])\n",
" for nbr in neighbors(square, board)))\n",
"\n",
"def allowed(name, nbr_contents) -> bool: return nbr_contents in (name, empty, off)\n",
"\n",
"def neighbors(square, board) -> list:\n",
" \"\"\"Neighbors of this square on the board.\"\"\"\n",
" x, y = square\n",
" return [(x+dx, y+dy) for (dx, dy) in directions]\n",
"\n",
"def put_tile(tile, board, start, dir, tiles, frontier): \n",
" \"\"\"Place the tile on the board at the start square, going in the given direction. \n",
" Update tiles and frontier.\"\"\"\n",
" board.boxes.append(Box(start, dir, tile))\n",
" tiles.remove(tile)\n",
" for i, name in enumerate(tile):\n",
" square = move(start, i, dir)\n",
" board[square] = name\n",
" frontier -= {square}\n",
" frontier |= {L for L in neighbors(square, board) if board[L] is empty}\n",
" \n",
"def move(start: Point, steps: int, dir: Point) -> Point: \n",
" \"\"\"Starting at `start` square, move a number of `steps` in direction `dir`.\"\"\"\n",
" return (X(start) + steps * X(dir),\n",
" Y(start) + steps * Y(dir))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Small Example\n",
"\n",
"Here I create a small example with 8 tiles, and try to fill a board. You can see the boxes that were placed, and the names that are in each square:"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"tiles8 = [('JAMES', 'EARL', 'JONES'), ('QUINCY', 'JONES'), ('QUINCY', 'ADAMS'), ('JOHN', 'ADAMS'), \n",
" ('JOHN', 'QUINCY', 'ADAMS'), ('HENRY', 'JAMES'), ('JOHN', 'HENRY'), ('EARL',)]\n",
"\n",
"board = place_tiles(tiles8, 7, 7)"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[Box(start=(3, 3), dir=(0, 1), tile=('QUINCY', 'ADAMS')),\n",
" Box(start=(3, 2), dir=(1, 0), tile=('QUINCY', 'JONES')),\n",
" Box(start=(5, 4), dir=(-1, 0), tile=('JOHN', 'ADAMS')),\n",
" Box(start=(5, 0), dir=(0, 1), tile=('JAMES', 'EARL', 'JONES')),\n",
" Box(start=(0, 4), dir=(1, 0), tile=('JOHN', 'QUINCY', 'ADAMS')),\n",
" Box(start=(3, 0), dir=(1, 0), tile=('HENRY', 'JAMES')),\n",
" Box(start=(6, 4), dir=(0, 1), tile=('JOHN', 'HENRY')),\n",
" Box(start=(6, 1), dir=(1, 0), tile=('EARL',))]"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"board.boxes"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{(3, 3): 'QUINCY',\n",
" (3, 4): 'ADAMS',\n",
" (3, 2): 'QUINCY',\n",
" (4, 2): 'JONES',\n",
" (5, 4): 'JOHN',\n",
" (4, 4): 'ADAMS',\n",
" (5, 0): 'JAMES',\n",
" (5, 1): 'EARL',\n",
" (5, 2): 'JONES',\n",
" (0, 4): 'JOHN',\n",
" (1, 4): 'QUINCY',\n",
" (2, 4): 'ADAMS',\n",
" (3, 0): 'HENRY',\n",
" (4, 0): 'JAMES',\n",
" (6, 4): 'JOHN',\n",
" (6, 5): 'HENRY',\n",
" (6, 1): 'EARL'}"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"board"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Plotting Pretty Output\n",
"\n",
"Technically, this is a solution. But it is not pretty to look at. \n",
"\n",
"I'll define `plot_board(board)` to plot each name in each tile and draw rectangles around them. I'll take care to make the font size appropriate for the length of each name, and I'll rotate the names according to the direction the tile is going in. The `fantasy` font is something like standard cartoon lettering.\n",
"\n",
"The `(x, y)` coordinates are taken to be the **center** of a square; names are centered on `(x, y)`. But the box is drawn a half-unit to each side of the center. Actually, we want it to be a biot less than a half-unit, becuase we want the outlines of the tiles to not-quite touch. In `plot_rectangle_around` we use 0.47 instead of 0.5 for this reason.\n",
"\n",
"One more trick: Randall has `\"Billy D. WIlliams\"` as a two-square name, not three, so I will write it as `\"Billy_D. Williams\"`, split that into two names, and only convert the `\"_\"` to a `\" \"` when plotting the text.\n"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"def plot_board(board):\n",
" \"\"\"Plot each tile box, plus a big box around the whole board.\"\"\"\n",
" plt.figure(figsize=(board.width, board.height))\n",
" plt.axis('off'); plt.axis('equal')\n",
" print(f'{len(board.boxes)} tiles placed on {len(board)} squares')\n",
" for box in board.boxes:\n",
" squares = [move(box.start, i, box.dir) for i in range(len(box.tile))]\n",
" plot_rectangle_around(squares)\n",
" for (x, y), name in zip(squares, box.tile):\n",
" plt.text(x, y, name.replace('_', ' '), va='center', ha='center', \n",
" fontsize=fontsizes[len(name)], fontdict={'family': 'fantasy'}, \n",
" rotation=directions[box.dir])\n",
"\n",
"def plot_rectangle_around(squares, half=0.47):\n",
" \"\"\"Plot a rectangle around this list of squares.\"\"\"\n",
" Xs, Ys = transpose(squares)\n",
" x0, y0 = min(Xs) - half, min(Ys) - half\n",
" x1, y1 = max(Xs) + half, max(Ys) + half\n",
" plt.plot([x0, x1, x1, x0, x0], \n",
" [y0, y0, y1, y1, y0], \n",
" 'k-')\n",
" \n",
"def transpose(matrix) -> list: return list(zip(*matrix))\n",
"\n",
"fontsizes = (0, 15, 15, 15, 13, 11, 10, 9, 7, 7, 6, 6, 6, 6, 6) # Indexed by len(name)"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"8 tiles placed on 17 squares\n"
]
},
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAZQAAAGKCAYAAAArGbdLAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjMsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+AADFEAAAgAElEQVR4nO3dd5gkZbn+8e/NkoMgOQdJEl2iKFFBAQNi4Kgo8FMERdQjIAgKBuAcUTEjIkmBA0cRFIQDAipBoqQlCZLTEnaXuGR2eX5/PG8ztb09sMzUdHXP3p/r6mu6UvdT09311BvqLUUEZmZmwzVL0wGYmdno4IRiZma1cEIxM7NaOKGYmVktnFDMzKwWTihmZlYLJxQzM6uFE4qZmdXCCcXMzGrhhGJmZrVwQjEzs1o4oZiZWS2cUMzMrBZOKGZmVgsnFDMzq4UTipmZ1cIJxczMauGEYmZmtXBCMTOzWjihmJlZLZxQzMysFk4oZmZWCycUMzOrhROKmZnVwgnFzMxq4YRiZma1cEIxM7NaOKGYmVktnFDMzKwWTihmZlYLJxQzM6uFE4qZmdXCCcXMzGrhhGJmZrVwQjEzs1o4oZiZWS2cUMzMrBZOKGZmVgsnFDMzq4UTipmZ1cIJxczMauGEYmZmtXBCMTOzWszadABmZv1A0u7Ajk3HMUynRMTRI/XiLqGYmc2YHYGxTQcxDGMZ4YToEoqZ2YwbFxFbNB3EUEi6aKTfwyUUMzOrhROKmZnVwgnFzMxq4YRiZma1cEIxM7NaOKGYmXWZpA9IWqzpOOrmhGJm1n2fAO6UdIyktzcdTF2cUMzMuiwiPg1sAEwGzpZ0s6Q9Jc3TcGjD4oRiZtaAiLgtIvYGlgLuAX4BPCjpG/2aWJxQzMwaIunDwBXA6sB7ge2ArYBxTcY1VB56xcysyyStCvwaeAvwXeDEiHi5LH63pLkbC24YnFDMzLrvdOBc4H0R8Vz7wk7z+oETiplZl0XEmq3nkt4cEU9UphcGdoqInzQS3DC4DcXMrAGSVpV0A/CApFslLS9pAeAiYJ1moxsaJxQzsy6T9CbgfOBkYD7gMuAosqfXE8Bnmotu6FzlZWbWfbsD90bEDwAk/RC4FXgRWC0ipjYZ3FC5hGJm1n1bAGdXpu8pf0+KiHu7Hk1NXEIxM+u+NwF7SNoVeBYYX+a/VdKJwISI+Fpj0Q2RE4qZWfd9AlgZeBSYA1gC+D0Dx+RJDcU1LE4oZmbdJ2BJYD1gLmBMZdlUcoyvvuOEYmbWfWcCU4C7ydLIi8BLZGL5InAv8MemghsqJxQzsy6LiPXb50maj7yCfjywbdeDqoF7eZmZNUzS4sDFwJzAJhEx/nU26UlOKGZmDSo32LoKuBbYKiIeazikIXNCMTNrgKQxkg4CzgO+ExG7RcRLTcc1HG5DMTPrMklrASeQJ/UbA7dKmgUgIl5pMrbhcEIxM+u+M4AVyvMbqwskAYyLiPW6HdRwOaGYmXXfWGB24In2Eomk2ZoJafjchmJm1n0/AtaJiFckLSVph8qyALZvKK5hcUIxM+u+7Rk4/q4DfLWybFng+K5HVAMnFDOz7lsQeKA8fxRYqLJM5HAsfccJxcys+wJYoDx/BFisbXlf9vRyo7yZWfeNB3aTtBo52vD8krYqyzYEHmwssmFwQjEz676zgPmBTcr0ecA3yJLJJGC3huIaFicUM7PuWw2Ymxxx+HngKWACOdrwAsBngb81Ft0QOaGYmXXffwBvJa9FmRX4E/ADctj6p4CHGotsGJxQzMy6LCIeBy5vTUt6BLg4Ii5pLqrhcy8vM7Pm/QtYvekghssJxcysedcC6zYdxHC5ysvMrMskvRmYrzJrPPBhSQtExJMNhTVsTihmZt33f8AybfNmByZKehG4OSI26n5Yw+OEYmbWZRHxzk7zlWPXv7nL4dTGCcXMrEdERACPNx3HULlR3szMauGEYmZmtXBCMTOzWjihmJlZLZxQzMysFiPey0vS7sCOI/0+NlM6JSKOHkXfsdG2P6PFKRFxdNNB9INulFB2BMZ24X1s5jKWgYPuaPiOjbb9GS2qn4u9jm5dhzIuIrbo0nvZTEDSRW2z+vo7Ntr2Z7To8LnYa3AbipmZ1cIJxczMauGEYmZmtXBCMTOzWjihmFVImk/S3JXpOSQdKuksSZ9qMjazXufRhs2mdRxwXvkL8D3gQ8CvgZ9Iei4i/tRUcNb/JH0U+DCwLDAvMAZQZZWXgX9GxB4NhDcsTihm09oE+FFl+mPAfhHxO0lPAl8DnFBsOL4MvARcBUwEJgMvAlOBpYDv0qdD2DuhmE1rArBwZXoJ4Kby/DLg8K5HZKPKYNcXSVoSuIi8v/xHuxhSbZxQzKb1X8BPJT0PrECeNd5bls1Lnkma1UrSysC5wIPAhyLi6YZDGhInFLOKiPiDpPmB3wJzAntFxLOSZgG+Rd4L3Kw2kjYBzgAuBD4dEX170uJeXmZtIuLYiFg2IhaNiF+V2XMAtwL7NBiajTKS9gL+BvwyInbo52QCLqGYzZCIeF7SAcBiTcdi/U/SIsDxwMbAxyPijIZDqoUTitkgJC0LrAa8nfzhbwzcD6zeZFzW3yRtDZxI1hB9Abhf0rqVVaYC90XEk03ENxxOKGYVkg4GtgdWJBvg/wXcDJwOHACMay46GyV+DSxSnv9ukHXuIb+DfcUJxWxaAmYnG+RvAs4GzoiI2xqNykaT9YA3AQ9HxAvtCyXNBbzS9ahq4EZ5s4qIOCgi3gosw0Ad9zWSbpd0uKTVmo3QRoFVyBLKapJWk7SYpDkgh/ohu6fP2WSAQ9V4QpH0S0nR9nhU0vJl+XySfiTpQUkvlb/HSVq88hr/M9g4S5LOk7SxpIUl3Sdp20HWu1jSDiOxj9Z/IuKhctvXvYCvA3MBe5MlFrPh+DbwD/ICxluAh4DnJE0FngMepU+rVhtPKMDPgB2Afcv0bsBngQfK9QCXAp8Ejizzfwm8C/i7pNnKNkuTVzR38i6yketN5Ng5J0rq1FPnJXJ8HSskfUrSkZXpGyWdLGnNGdj2AElf7zD/QkkfqkwfKumQDuvtIOkGSQ9LOq18F0acpA9K+pWkyyQ9BVxHDr/yG+A9uEHehikitomIOcgmh8XIatYvA+uT36+lyc4gfafxNpSIuB24XdJawA+BMyNiIoCknwPzA+tFxMOtbSSdDNwObAOcNdhrSxoDzEYOttbafhZy4L8PtK1+A7BRHfs0GkhaCPg5OdZQy1rA9cDVki4AvhwR93XYdhXgO+SFWt+vzF8a2IL87M4ss3cgP5+DKut9jmwA36u8/5rkSUE37FVihPxOnABcQt6Sty/rta03le/TREmTgSci4vqmYxquXiihtIwpf18GkLQSsBOwWzWZAETE/cAdvH4WX7D8fSEini/P9wQ2kbR327oTybrLIZG0m6SbJD0r6QFJ35I0i6QvSvqPtnX3lPRJSQdKekrSy5LGSfqbpFkl3SZpq7ZtPijpl5XpBSWdKunp8thY0rnliu7WOj+WtNMQd+nbwH3ASpKq9bm7Am8BxpNtC+t22PZwsijfXpJZv/xdu8S3FLAysGI17vLeX4iIP0fEFRFxTEQ8M8T9eEMi4t1k+8mHyZ5d25IJ5SlJl0s6rBtx2EzlVuCtTQdRh8ZLKBWzl7+tXg/bAXdGxAWDrN9+xrqCpN3Ig9ZYMtnMV5ZVR+68E/gM8HtJ10TEJWX+ZAaS2hsi6VfkF2IX8qx2KeAUMjnOwfSJexGAiDgUOFTSoxExtvJ6CwEnSdogIh4ss+8H3l2Wz0EOsf5nYEfgYLLu9SVgP+AwSSsAHycPzm90f1YCPgdsCJxPJoZrWstLgt9D0jXAqZJWi4jWicBmwObkZ3CHpIUjYlLZdK3y/1lTkshS4tXAqmR15L1lvbmA5SUpIuKNxj9cETGeTJhnApSq1Q2At1FOeGx0KKXmeSLi3w2GMQ7odGLWd3qphDIP8GKlG91KZPXKdCTNWpbf3ZoFfBH4b7L+8XxgD7JeEmCaC4TK/SwOA/4kadUy+0WmvSfBDJG0BbAO8J6IuC4ippYS1GeArwKdDohzMu0gg+2J/VkySfypdCGEHDRugfL8G8B1EXFIREyJiG+U4vJuwJfLj2Rv4OiImPxG94msrvoLsAaZ4NfptFJEHAc8BWxamf1fwMll3uS2bTclL+gS+fl9kDxo/4tpS5vfAo4AXi6lvZ9U/g9dFxEvR8Tl5PUDbpSvSWmrukDSmzosW0DSXcobnM0v6Z62knJrveUl3dE2b97ynRkv6flSc7BXWykYSW8lq19vlXSdpI7f8y64hjx563uNJRRJ87R9gAsDj1SmpzBQZdVuR/Ig/PcyPQ9wYEQsEhHvL10/TwYuL8un6+tNnrlfCJxbql6GWke/HXngnlKdGRF3kAfbV5g+YSzGtG0TnZLOSeRAhH8oJZJngNlKu9CuwP7tG0TEBDJRngB8AvhV+zqvR9J2ZdsPkx0gYJCEUtxHGe5d0p7k/UT2KHE829pW0uxkF9xLyN4tW5MlrjPI6z3eXtmPI8trrkP2sNqeShtLt5RqxS0lfU3SKWTvm3O7HUdbTB8uHQaeljRR0m8lLSRpaUn/ah00ld1R79JAd9TDJH1O0uKSru9wcD1VUqsEPEbSQZLukPSCpKmSJkhaX9J0+1+qAlcZwu5sSLZXna/pO10sR472PAtZe7EcnY8Hy1HpkKO82+bF5PDvPwU+Tx4nDgVOa9t2J+CvZMn5XuBvqvQeHSmlunvv1oMszS8saX9Jn5C0uUov137TZAllW+CccoCErLe+q7L878Bmkt5e3UjZQ+sQ4JiIaFVlLUJeWdruufJ3ujObUpXyafLM/yKymmoo5mTwZPQE+T9erm3+BmTVz2uKiO+QB+wzGaiOWxh4MiKeGGSzI8i2oBNLgnmjtiKr09Yg/6/7MEhxXNKiZPVWqyS5NdkbaqWIWJK8UVVr21b7yTgyqewPPBQR/yJ7Um1cXnNuSWMiYnJE3BQRpwBHkdVNI07SfpLOkXQ/mUBOBb4C/JO8c+N63YhjkNg+RZaSTgDeQVYZLkJ2YHiUrDZsVZ3uSh6QNynTm5EdVCaQpfiNKq+7HLlvrYs3jynTXyaT+sfI7929wJbK+3a0tt2ErLK8dwi7NBt5YrcgcGYr+RVjIMdQA54mT7rmm+4VMplMqkz/N7AQsEFE/DAiToyI/yR7e26rSg9DMqFdGBG3kAnoBcr3cIS9jyydtx5rkN2IP0qeiP0fMFhVf2+LiBF9kAfrizrMX4KsijqDrKM/C/heZbnIO+M9R/Y22oXsWvwAeVCat7Lus8C7OrzHUuQXcTFg7vJ8nbZ1FiAPFlOA64ewfx8Hzi/PFyfPeBYiG5ufIJPJfcCKZZ3tgEsr288NTGh7zfvJet3W/+HXZIKdSCaoe8gz+rnI0tp5lW1XJEt6iw5hX+Yg25s2b/sfTiEPXAF8hOzauA1Z0jihrLck2Ybzlsq2GwOPkSW0LwJXlvlbldf6SZler3zOc5BJ6BzygLcmsHvZ750H+14N9h0b4vd1f/LAck357HYGHuzm72Sw/Sm/kf3a5s0CzFWenwfsXp7fXn4rB5d1JgPvLMtOAb5ani8PHEv2roTscDGp+v0p279Snl8ObF+er1pi+tkQ9/lG8ne9JNm2+YfKsnVb71mmp9L22618XleX5/OX79HOg7zfedVYySrzj1WmxwJzd+N71sSjG/E3VkKJbNjdkvxC30T28T+psjzILqUHlfWOJtsF/gRsFtP2+nmEPGi3e5w8OL9EVj3d275e5ABs7yGLyVcPYVdOA2aV9BvywPkkefC/iPzx30cOAPcHSbeQP4BdACTtQf5455P0jKRWB4FHgedb/4eI+Dx5Pc4dkV0NdyLv1zGhPN+vEs9nyOq/oZROlgduj4iLWzMiG6j/Rp7tPkb2fBpHVoedRTbeQ7aB/Dki7q683pVkCXBRsjG7tX+Xkp/FsWV6HPk5LUaeoU0iz9KuLPuzR0ScOIT9ecMi4jCyF9r4EteGwBI9UgVxA/D5Ui2yhqR5IuKVGOjBeBmwbmkbWJL8X25KHijFwPf7OmBvSQ+StQKfJdsdIQ/kF7/G9+c64HBJE8i2r23Ik6ihGhMRD5E1Fu+S9N32FSoll3eU6qLvSjpL0qNkm92zZfm7ycRz8iDv9TjTVj8vTqV0ExHjIuK56bYaAaVa8f2lOvVrpSqzK9dajaimsyL5RV8NWLbpDD6MfZybLEVNIBPKZWSSe0/TsY3WB104cySriS4hT0aOBZZrcn/IEtyPyeT7MlmS2qOyfGsyWe9PJvuVyOqirzJtKXZL8uRgZ7KK9JLKsi0oZ/yVedUSyq5kEvoP8mTqf4axzze0xb8J2VlleyolFPJEY2r5HJ4iTzSOIk9mjiCrrQC+xmvUMpBVenuV57OX19yg29+zsj83kyeNN5JVxpPJ0tVPaSsljcR3bKQejffyinRrZM+ovhQRz0XEVyJvyLRARGxMlnr2kbR90/HZ0ETEJRGxGdmWsAh5Ae6pDcbzYkTsHXnzr9nIa6qqZ/S3ktWR2wNnRcSdZNXiLmQdfcv15MgRFwOfAg6sLPsHsICkzw4SxvVku+HNZOnkO8PYpalU2kUiopUMjyeTYcuC5InnYhExf0RsFBFfiIhjGejp2dKx63/pcLAyAxdCt9pVXxpG/EP1X+X9V4mItSNiHbLq/QvkZ/cPSUO+Jq5JjSeU0SqyQXmbGCU3zpmZRcQvI+JDZLXfUU3HU3EPlR6M5aRsDrLTR6t7881kh4abKus9To4ccTpZOrmksmwqWdX8PUlHlk4wwUBPxJvJ5HoicHxJWkP1DAPDuLfe/ydkCf+XAKWrcOvg/9jrvN6twMqSlqnOLJ1HjiVLU614W8M2dWsEhqqtyU5FD7RmRF5ucCLZNroI2fGo7/TShY1mPaX0QNyU7OF0XWT70EMNxjM3Oa7dzSWmn5KN7lV3AbNHtktAVqm8g8qFqcXNZJvDju3vExHjJG1AVuPeA/yeco1WRLwk6U6yve29w9yl++nce++zJT7IzjuzAS/H6w998xdy/y+UdAzZKWEZsoT5GHmNlsiSVat78HtLl+cbh5kc34hFS2zTiYhHJf2CrKbcq0vx1MYJxawDSWOBP5BtYvcDR0n6MzkUUBNntZDVOVuTZ68TgG9ExB/a1jmDaS/QPQdYNbJzRdVFZOnk9k5vVEo720tag+yWfHNl8YXA5THQbX+o/sTAxcfV954oaWeyd+PT5MH/wkFe42Gy4wcRMVXSlmSV0pfIA/cEMiF+OyKeUd6F83gGbuV8ePl7ZNmmGyaQiW4wjzL4NXg9TaWxZuTeQLoIICK2GNE3splK9XtV93esHHSuBg6IiOPLvEXJg/OZEVF7dcRI7o8N3Uh8LpJ+RF5usG506E0n6WfAuyNireG8T4fXvQhG9nvlNhSz6f0cOL2VTODVUQgOJHtGmQ3Ht8kquCtboxO0SNqQ7L12fKcNe52rvMwqShXPe8kG+Hb38dpVFWavq1S9bQr8ArhAORbZ9WQ112bk8D4/azDEIXMJxWxaB5B17hOUtx949UGOKD3ba29u9tpKlerkiNiFHG3g1+RFl7cBn4iIj8xAB4Se5BKK2bTWJod82ZnOo09P6jDP7I24iuzJdm7pWfaThuOpjROKWUVErD3YMkkLk91lzYZjMWBx5X2PXiZvANjEBZa1c0Ix60A53P6a5Gi765BDgaxPjmu2bYOh2ehwbHVC0ovkcE13kYPVnhQRt3XasJc5oZhVKG+z/C5y6I+J5JXoQY4T9c/KBYNmw7EvOSDnGHJcsXnIi1WXIb9/10laJQbu2NoXnFDMpnU5eY3AjWQ7yprAER5Cx2p2b0Tc3GmBpPPJe93M092Qhs+9vMwqIu/0uQqZWP5Jjqq7kAZuFW02XEeSJyzTKUPDHAKMi2bvcz8kTihmbSLi8Yj4CnkfkRfIYdMPL3cnNBuWiPhSp3HDynA/48lbCOza7bjq4IRiNoiIuDMiPk3epfJu8ja1lzcclo1et5Njm60eEde/3sq9yG0oZq8jIs4CzpK0L+42bCMk8m6Rpzcdx3A4oZjNoHKtQMfRec2sOwllcxgY6dKsJmPJe76PRv7N9I7q96zfP5cR/824DcX61TjglKaDsFFvNH3PRnxfRryEEhGdxkMys0H4N9Ob/Lm8PpdQzMysFk4oZmZWCycUMzOrhROKmZnVwgnFzMxq4YRiZma1cEIxM7NaOKGYdSDpU5L67n4UZk1yQjHrbF3gNkkHlXvJm9nrcEIx6yAi9gE2AxYBbpH0AycWs9fmhGI2iIi4B/g+cBOZXG6U9NlmozLrXU4oZoOQ9HXgSuBPEbERsCmwQrNRmfUu3w/FrANJ5wAvAutGxESAiLgLOKjRwMx6mBOKWWeHAs+2komZvT5XeZl1dg6wQ3WGpHMlrdVQPGY9zwnFrDMB32qbdxJwWAOxmPUFJxSzzv4C7N8274/AJg3EYtYXnFDMOvsCsL2kX0l6U5m3NjC+wZjMepob5c06iIgnJG0CfJO8sPFJYG5g52YjM+tdTihmg4iIl4BvS/ousBAwKSKi4bDMepYTilkHko4A3gUsAMxWZoek2yNi0+YiM+tdTihmnf0FOBp4EHgGGAOcDVzaZFBmvcwJxayDiDi79VzSbMDpwO0R8e3mojLrbe7lZfYaJM1Bdhe+OyL2aDoes17mhGI2CElLAv8AromILzUdj1mvc0Ix60DSlsDVwHHADyXNLWmuhsMy62lOKGadHUH27tofuBm4hbyD41WNRmXWw9wob9bZmhExtekgzPqJSyhmnf2l00xJF3U5DrO+4YRi1tlCg8xft6tRmPURV3mZdbampIfJ30hruJUgL3A0sw6cUMw6ey4ilqjOkDQ34Ds4mg3CVV5mnf2wfUZEPAfs00AsZn3BJRSzzu6StAfwIlkquSEi7o+IoxqOy6xnuYRi1tmCwKLAysCHgf+TdImkFZoNy6x3uYRi1kFEHNk+T9J25H3lfRtgsw5cQjGbQRHxZ2D+puMw61VOKGYzqFR3vdR0HGa9ylVeZh1I+hjZhgL5O1mebEv5QlMxmfU6l1DMOlukPBYC5gOeADaLiPPg1fYUM6twQjHr7Ciyy/CewM7A+4Fxkj5bhrZ3ScWsjau8zDr7JvBeYJOIuBNA0srAheSJ2HsajM2sJzmhmHW2G7BxRDxYmTepPCZHxC3NhGXWu1zlZdbZQsD4tnmnAncAa3Q/HLPe5xKKWWd3A2sDN1TmfZr8zVzXSERmPc4lFLPOfgH8WJJaMyLiUeBg4HeNRWXWw1xCMesgIo6RtC5wmaSjgalkCWUM8IFGgzPrUU4oZoOIiD0kbQ5sB8wJHAecFhGvNBuZWW9SRLz+WmY9TFLrS3xxo4EMz1hgXERs0XQgZkPlNhSz3jAOOKXpIMyGwyUUMzOrhdtQrO9J2h3Ysek4bBqnRMTRo+SzOSUijm46iH7gKi8bDXYk2yCsN4xlIIn0+2dT3Rd7HS6h2GjhBu0eIemitll9+9l02Bd7DS6hmJlZLZxQzMysFk4oZmZWCycUMzOrhROKmZnVwgnFzMxq4YRiZj1P0jKSFq1Mv1nS/0i6SdI3m4zNBjihmFk/OAp4f2X6R8DqwCHAZyV9rpGobBpOKGbWD9YHbqpMbwt8NyJOBQ4EvthIVDYNJxQz6wd3AysCSJoFWAT4d1k2DlilobiswkOvmFk/+AZwiqR5geWA54B7yrJFgKebCswGOKGYWc+LiAsl/T/gm8BcwE4R8aKkOYDDgVObjM+SE4qZ9YWIOA84r232K8CJwPHdj8jauQ3FzHqepLdLWrgyPQtARLwcEUdExHPNRWctTihm1g+OAd4NIOm9wBmtBZIWlXRdU4HZACcUM+sHKzHQCP8ysHRl2XzAGl2PyKbjhGJm/WBOsmcXwCPAom3L3R7cA5xQzPqEpLklPSUpKo+ryrJZJX1X0nhJkyVdJ2mHsuxNku6W9LYOr3ltGdZkaUkPSXqivO7zkm6W9I7Kuu+SdKWkCZLOlbRc9/aeJxm41uQRYOHKstmBZ7oYiw3CWd2sT0TEc5JWJ7vNjiOHIrmlLP4NsC6wGzAe2Aj4jaTJwDXACsAJkjaIiJcrLzsF2Ay4Cpgb+Bx5weDcZZu7ACRtDZwA7A3cCawFvDhiOzu9F4DjJf0MEDC7pEvLsmWB87sYiw3CCcVGNUm7AV8B3gI8TjbuHgp8AZhUhu5orbtnWWdFYF/yoHoL8BiwNXAz8KWI+Gtlmw8C20TEnmV6QXLcqW3KKtuSQ4O8PyJeKev8GLg+Ik56o/sTEePLa7wC3BURkyS9D/gAsHpEPFxWvUHSqsCOwAVl3izAAcDBlZe8G1iCTCzPRMRplWVXVZ4fCBwUEaeU6X++0diHaQOy2mtKmV68TL9Cfo63djke68AJxUYtSb8C3grsAtwALAWcQjbqzsH0Vb6LAETEocChkh6NiLGV11sIOKmc5T9YZt/PQO+jOcjrJP5MHsgPJuv9XwL2Aw6TtALwceDbw9y9MWU/IMexOrKSTFpuB9aKiKmSAD4FXCrpgoi4oqwziSzxtPZxQfJgvTgwW7n2g7LOcpLGRMTUYcY+VBuSyW8ucv9bpkr6V0T8qZmwrMUJxUYlSVsA6wCbRETrrPZ+SZ8BLgWO7LDZnExbjdP++3gW+D7wJ0mbRcTzwIPAAmX5N4DrIuKQynSrlHS9pP8hq4yOjojJw9m/Emur3eAd5NXi7dqHJLkV2Av4vaSNIuIhcn/HkAlkKbJ9YhIwAXhQ0t/K/+9Q4CTgAEkTgXOBfSLi8WHux4w6kyyd3F3ie5FM1GPIhHov4ITSMCcUG622Iw/cU6ozI+IOSU+RVSXt3//FgCuqq3d43ZPKen+Q9FHyoD6bpDHArmTbwjQiYoKkw8g2iLUZZhfXMp7VlIh4tsyaD5jYYdXNgL+3xXK8pHcC50jajDwoQyaoK4CNI2K6/Y6IM8r9SFYAViVLWEeQJbERFxHrt8+TNB9wOtlmtG034rDX5l5eNlrNCQxWNfME+d1v76W0AVk19poi4jvAfeRZc6vqZWHgyYh4YpDNjgDmBU6MiF0WFoMAABN5SURBVAmv9x7tJO0pab8yuSRZ1dZyG6XarbL++sCmwMkdXm5PMhGeXon/FYBOyUTS7JLmjIjnI6JVtfQ9YLpeY90iaXHgYvJz3qTVtmTNckKx0episs0ASYtL+qukhSStTHY//S3wEUmtIdG3IxPCvWV6bspBtmIWBkotXyKTytll3kRgnjJEyFySdpRUHXfqLWQC+/4Q9+d2YO9SqlifaRPfd4DvSdpH0lhJHyGT3SERcb+k2ct6raTxIrA9sAxZXTSVrEZaRtLqklYqj8XKdp8H/iFp87L8k2RC+f0Q92VYJL2d7DBwLbBVRDzWRBzWQUT44UdfP4CLgIva5o0hq3t+Q15VfRp5EB4P7FbW2Ra4juzJdTmwYpm/B9mY/jx5Jn9JmX81MEvb+xwMXF6eb0K2U0wm2xjeVlnvUOBzw9zP3cnrMaYCH2pbtiVwWXnve4H/rCybnexV1v56S5M91z5GdsU9rWwfZIP/uLLePMDPyfaV58guy58H9HqfR6fPZhj7PwY4qPwPPtPUd8uPwR8q/zSzviXpIoCI2KJt/tzAYcAnyIPqLWSX4J0i4gL6kKTZgIUi4pGmYxlM9fMY7LMZwmuuRbZBzUKWPF/tJhylO/ZIqCv+mYUb5W3UihyB9ivlAbx6YPqhpHki4oxBN+5RkRcl9mwyGUFnkB0CYNpbASMpyNLUel2PyqbhhGIzlYi4iYGLDq1/jCVLmU+0l0hKqc16gBOKmfW8iJhchq3fUdIS5PU1VwMnh3t49Qz38jKznifpY2Q358eAP5IdLLYC7pC0f5Ox2QCXUMysH+xPXpl/dHVmud7mDEnPRMQRzYRmLS6hmFk/WIVpRzEAICKuITtd7N31iGw6Tihm1g+eJkcI6OQuYKEuxmKDcEIxs35wHHB4GU+s3Za0dSW2ZrgNxcz6wcHk8DW3SjqSvMfLRDKZfAf4UHOhWYsTipn1vMh7sOxUbia2R3nMR14xv0tEXNhkfJacUMys50m6grzr5TnAOU3HY525DcXM+sHbgdUlLSlpEUlzve4W1nUuoZhZvziHHAl5DDCnpJfJ+8LcQN5n5uwmgzMnFDPrDwGMjYi7WzMkzUN2Jd6AvC3zUjGEm5dZfZxQzKwfTCbvT/OqyFsg31Hu3vgMOSyLNchtKGbWD5aIiIfbZ0ral7xz5L6lJ5g1yCUUM+t5EfH8IIueBXaOiL92Mx7rzAnFzPpWRBzZdAw2wAnFRoPNYeB2rda4seR9520m4zYUM6vbOOCUpoOw7nMJxfpeRKjpGMzMCcXMbIZI2h3Ysek4humU9puU1clVXmZmM2ZHsn2oX41lhBOiSyhmZjNuXERs0XQQQ9GNTisuoZiZWS2cUMzMrBZOKGZmVgsnFDMzq4UTipmZ1cIJxczMauGEYmZmtXBCMTOzWjihmJlZLZxQzKzvSfqKpDmajmNm54RiZn1N0jzAj4CPNR3LzM4Jxcz6WkQ8C1wHvLvpWGZ2TihmNhr8A3hb00HM7JxQzGw0uBdYoekgZnYevt7Mep6kPwNLA1OBKcALwLPlMRFYFpi3sQANcEIxs/5wIpk0xpTHXMA85bFgmXdYY9EZ4IRiZn0gIk57reWSZgdW6lI4rxXHGOAOQMAyZKKbDNwOfCsizpmB15gVWByYFBEvjGC4tXMbipn1DUk7Szpd0pGSFi/zZgVOB85oNjogE8kKZFLZH/gUsA9wBVldN+3K0v6Sjmib/V3gAeB5Sf+StEvbNjtIOmskgh8ul1DMrC9IOg74KPBrYDPgH5LGAocAW5RHoyJiiqSpwH9HxEWvta6k9YBDyeTxpcqiRYALgROALYHjJG0O7BoRQVb9LTMC4Q+bE4qZ9TxJOwM7AZtGxFWSFgDuBI4BdgB2i4hrm4zxjZA0C3AUmUyWlzR/RDxVFk8Elo2IE4ATJB0JnA9cAvyWrEabrrTTC5xQzKwffB04JSKuAoiIJyX9BdgRuDwifttkcB28pVTFLQksAcwBHBYRL5XlnwXWBN4JXAusA1xUlo0he7EBEBFXSjoK+BADCWXKyO/CG+eEYmY9rYzRtRrT9+J6EAjg+10PahCSliAP+MeVWc8DjwD3A0cAj0ual6zq+kFEXC/pDmB9BhLKIuS+tV5zAbKK74Yyay4qCaeXOKGYWa9buPzdRdInyYPpg2SSCWANSSsD4yPi9w3F2NIaoPLtwG0R8XSHdQ4AFgXWlnQX8BYyobQsCswl6fvktTfbAE+RjfWQXaWfHYHYh80Jxcx63SPAf5Nn7hPJEsAi5Nn/JcDWZb37gKYTSpS/d3dKJpLWB74BPAe8GfgD2UV4k8pq8wKbkw3ykPu0W0RMLtNOKGZmQxERU4EDm45jBrXaSGYbZPmmwNPAUhHxDICkTcnS18IRMYnsenwgcAvZdrQD8LCk/SLiZWB+MrG+qlSjPVt6gTXG16GYWV+TtKCkXSV9o+lYgEeBZ4AvS/pY5dEaCfmLwG9byaS4hixtfbgy76WIODMi3gnsVh5nlPak+YFlJH1Z0o8k/RN4EvjPEd631+USipn1DUnzkT2i1q88ViTbVY57jU27IiJekbQ/sF95jCFLLfdI2hCYE/hp2zbPSzoeWKzMuh8YX1l+vKQbgd8BK5MJ6ACymuwesrH+CLL6rFFquIRkZqOYpIsAImKLYb7OL4D3AcuXWXeQB9cTgOOBa0ZimJJq/HXtS1O6Eb+rvMysH4wnrxC/F1g3It5Knp0/EhGX9tuYV6OVE4qZ9byIOAzYCHgcuFzSt4AbyzzrEW5DMbO+EBHXlnaIXcnxuxYFnpM0V0Q832x0Bi6hmFkfiXQsOVT9YeQ1GQ9J+rGk5ZqNzpxQzKzvRMSzEfFNYAPgYOAD5EWO1iBXeZlZT5O0DTA1Ii4o07MC80bEk2WE4WuBn5QuxdYgl1DMrNcdQpZAWg4A/lhdQdK7gKu6GZRNzwnFzHrdKmSPrpYXyS7EVQuSd0q0BjmhmFmvm49pB0N8mBxQsd3s3QnHBuOEYma9bip5o6qWh8jh3eftsJ41yI3yZtbrHgDeK+lqciTeVnXXqpLuIUf2XZfK+FfWDCcUM+sH72Xg/iCQieVq8v4jIkf4/XoDcVmFE4qZ9bqVyIFsX63SkrQ4eXfEIEfzfbTpe4GYE4qZ9biIeKXDvEeaiMVemxvlzcysFk4oZmZWCycUMzOrhdtQzMxmzOYwcOfDPjQWGDeSb+ASipnZzGEccMpIvoFLKGZmMyAi1HQMvc4JxfqepN2BHZuOw6ZxSkQc3XQQ1l2u8rLRYEeyfth6w1ic4GdKLqHYaDEuIrZoOgjr60ZrGyaXUMzMrBZOKGZmVgsnFDMzq4UTipmZ1cIJxczMauGEYmZmtXBCMbOeJ2ltSStWppeRdJmkyZKOkTSmyfgsOaGYWT/4GfCOyvRPgOfJ2wKvB+zdRFA2LScUM+sHawD/qkxvAfwwIv4JfBf4TBNB2bScUMysH9xIlkSQNBvwZuDusuzfwPLNhGVVHnrFzPrBPsBfJS0LLAU8BtxTli0LTGgqMBvgEoqZ9byIuIFsL1kOmA/4YERMkTQ38EvgN03GZ8klFDPrCxFxI7Bz2+zngb2Ac7sfkbVzCcXMep6k7SStUJ5L0kIAkc4G3G24BzihmFk/+CGwTnn+fuB/WwskLQnc1URQNi0nFDPrB8sy0KvraWCxyrK52qatIU4oZtYP5gBeKc8fARZtW+4qrx7ghGKjnqQrWnXulXkLSfqbpCMk3SdpiqSpkiZKOlbSmyTdLeltHV7v2jL0x1KS/iHp/yTtK2n+yjq3SFqtbbuTJW03cns6qk0C1pCk8rz6ec5LllqsYU4oNjNYhuxqWvVWYG5gAeBC8srrtYGdgFOB2YEVgBPKhXRVU4DNgJWBpYFLgA8CN1eSyLnAUa0NJL0V2B64eqg7IWluSU9JisrjqrZ1FpE0TtI8bfO3kvTPyvTCJWEuXKZnlXR/Sagh6QVJd0javrLN20oSnijpYkljh7ovQ/ACcDL5v58EzCrpAUnjgSuAE7oYiw3C3YZtZjU7eXCaAlwaEZeW+bcAVAYbnAU4ADi4su3dwBLAdcDLEfF94PuS9gd+TyambwP/lvTRiDgd+Dzwu4h4eKgBR8RzklYn2wzGkY3Tt7St9kPgbcBawJWV+Z8ANpC0RInhPWTC3AI4rayzDJlQby77/RbgpvL/WBv4G3Ag8HVgdeDZoe7LEKwAEBFTSzyLAXOS1WCPR0Q3Y7FBOKHYzGpW8hoGgNnLFdiLk4274yLigaxd4VPApZIuiIgryvqTyIP6HEx7UP0BcJCkhSLiMUnfAQ6UdDZ5oB52dVdEjAeQ9ApwV0RMai2TtD7wcXLMqzWZNqGsX/6uDTwMvKtMr1xed0rZ399FxJSy7LrK9vsCv46IVqnrmuHuyxvRSiSV6UdLyXF9YBdJi0fEl7oZk03PCcVmFltJWoocD2p1soRxLplEfgl8D3iUHNLjp2RJA+BW8sK530vaKCIeAl4kG4GXAB6UNAd5Bv014EHg8bLticA3gdOBCRFxeY37MwZ4uW3eD4Cfk2ftr1ZHSZqVrOK7AVhb0vlk6eYCYNW215i/VIMtDrwJOKcczOcClpI0e0S8VON+zBBJC5KlqZXJmFcnS2JPkMntzG7HZNNzQrGZwezAl8n2i78APwY2B1YEFga2iYjzBts4Io6X9E7gHEmbAa0D6kLAB8j6fcgD9PsiIsp2L0naHTgf+M+a92lO4JnWhKStyOs0fkaWUparrLsh8ByZJMeSSXU+4BdkFRaSFi/rtpLqhPL8SmAicDhwFvCCpCeAi4C9IuL+mvdrMFczMADkBcAhwLUR8UiX3t9mgBOKjWqSZgEWBFaLiMcq85cFViHP5mMGXmpPsg3hdAaqgmYFLgNuI6u0JjJQOml5geyBVNtYU5LmBaa02g0kvQn4NdnB4A9klddKkmaJiFeAdwOXk8lhD+BOMrFeA7ytlLDmBB4ClinbTCMiriwlvBXItpV9gd8B76xrv17HhsB7yaq695EN9H+RdCZwXkS0/9+tAe7lZaPdm4GXqsmkeIo8AE8iG6tXKo8VJc0mafay3isAEfEi2UtrGeCLQKtO/96I+BywGlkquExS9RqJg4HDI2LycHZC0p6S9iuTSwLVksFKZBXVlsD8ETGW7GywSlm+GZn4riTbiHYF/lwa558g2yFeAdQpmUiaRdI8EfFSRPw7Is4lOypM16V6pETEYxHxvxGxe0QsTe7rbcD3gYcl/bZbsdjgnFBsZnBzh3kPkSWHY4DPkQen28n7bnykrDOueoAtDeBbAfeRbSuTKMOmR8Td5NnzdWRphdJ1d1myTWa4bgf2LlVu65PtIS2fA06NiL9HRKujwdXAtuX5WOD6suxqMqn8pSy7hjw4Pw68WdLYSnJdqqzzfuAGSVtLWk3Sh8gu0a12pq6QtJik90jaB/gqeVOtRYF/Atd3MxbrzFVeNqqVksmGHeZfDXyyTK4wyObrtM+IiAfJHlQtZ1eWvQx8ujL9LNlOM2wRcYGkbwF/Jts/PlJZvCqwX9smJwIblOdPMFBNdxpwd6V32JnAuhHxjKSjybaR+ckS2KPK+7ifSyaxo8lkdC/wW+BHdezbjCjX27R6qt1AJrNjgasi4oVBN7SuUmk/NOtbki4CiIgtmo1k5JWusgv1cmN09fOo67ORtCV5ArAe2WPtWbJd6DIyWV5f7UJdl5npu1UHl1DM+kgpBfVsMhkpEfE3slNE66LTDcnOBu8G9iar7FYb9AWsK5xQzKyvlOtiriiP/2o4HKtwQjGzviVpFbLzwQoR8dWm45nZOaGYWc+TNBc5PtmaZK+1dchuy1PJnmsnNhedtTihmFk/uJwch+xf5BX79wPzRMS6jUZl0/B1KGbWD94DnER2wxbZbXj1cpW/9QgnFDPreRExKSL+H3nV/4bkdTCzARs1GJa1cUIxs74REddExJbAf5AXWJ4t6ThJ012Eat3nhGJmfSci/ko2zm9ODsD5g2YjMnCjvJn1AUlXAO+vjipcBty8jmlvBGYNcgnFzPrB28lG+CUlLVK6EVuPcQnFzPrFOeS9a8YAc0p6mew+fANwUkSc1WRw5oRiZv0hgLHlNgHAq7cHWJIcVfmPkpaKiAlNBWhOKGbWHyYDz1dnlNsD3FFuX/wMeetia5DbUMysHyxR7jA5DUn7khc57lsGjbQGuYRiZj2vcifKds8CO5duxNYwJxQz61sRcWTTMdgAV3mZmVktXEKx0WBzGLhdqzVuLDCuPO/3z6a6L/Y6XEIxs7qNA05pOoiajKZ9GXGKiKZjMDOzUcAlFDMzq4UTipmZ1cIJxczMauGEYmZmtXBCMTOzWjihmJlZLZxQzMysFk4oZmZWCycUMzOrhROKmZnVwgnFzMxq4YRiZma1cEIxM7NaOKGYmVktnFDMzKwWTihmZlYLJxQzM6uFE4qZmdXCCcXMzGrhhGJmZrVwQjEzs1o4oZiZWS2cUMzMrBZOKGZmVgsnFDMzq4UTipmZ1cIJxczMauGEYmZmtXBCMTOzWjihmJlZLZxQzMysFk4oZmZWCycUMzOrhROKmZnVwgnFzMxq4YRiZma1cEIxM7NaOKGYmVktnFDMzKwWTihmZlYLJxQzM6uFE4qZmdXCCcXMzGrx/wEvTiQfKy60ggAAAABJRU5ErkJggg==\n",
"text/plain": [
"