├── README.md ├── LICENSE ├── localizer.py ├── helpers.py ├── simulate.py └── writeup.ipynb /README.md: -------------------------------------------------------------------------------- 1 | # Localization Problem in Robotics : 2D Histogram Filter 2 | [![Udacity Computer Vision Nanodegree](http://tugan0329.bitbucket.io/imgs/github/cvnd.svg)](https://www.udacity.com/course/computer-vision-nanodegree--nd891)
3 | 4 | - 2D Histogram Filter 5 | - Python 3 6 | - related to Monte Carlo Localisation concept 7 | - helpers.py, localizer.py and simulate.py are provided as an existing code base 8 | - a new feature for sensing the 2D environment is added in localizer.py 9 | - an existing bug in the function for move is detected in localizer.py 10 | - the bug is corrected after testing it thoroughly via a well-defined test case 11 | - user description of error is converted to bug testing and correction
12 | 13 | A similar histogram-filter based approach would look something like the following graph. 14 | ![Alt](https://salzis.files.wordpress.com/2015/02/figure_2.png) 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Anjishnu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /localizer.py: -------------------------------------------------------------------------------- 1 | import pdb 2 | from helpers import normalize, blur 3 | 4 | def initialize_beliefs(grid): 5 | height = len(grid) 6 | width = len(grid[0]) 7 | area = height * width 8 | belief_per_cell = 1.0 / area 9 | beliefs = [] 10 | for i in range(height): 11 | row = [] 12 | for j in range(width): 13 | row.append(belief_per_cell) 14 | beliefs.append(row) 15 | return beliefs 16 | 17 | def sense(color, grid, beliefs, p_hit, p_miss): 18 | new_beliefs = [] 19 | # 20 | # TODO - implement this in part 2 21 | # 22 | height = len(grid) 23 | width = len(grid[0]) 24 | 25 | # loop through all grid cells 26 | for i in range(height): 27 | row = [] 28 | for j in range(width): 29 | hit = (color == grid[i][j]) 30 | row.append(beliefs[i][j] * (hit * p_hit + (1-hit) * p_miss)) 31 | new_beliefs.append(row) 32 | 33 | s = sum(map(sum, new_beliefs)) 34 | 35 | for i in range(height): 36 | for j in range(width): 37 | new_beliefs[i][j] = new_beliefs[i][j] / s 38 | 39 | return new_beliefs 40 | 41 | def move(dy, dx, beliefs, blurring): 42 | height = len(beliefs) 43 | width = len(beliefs[0]) 44 | new_G = [[0.0 for i in range(width)] for j in range(height)] 45 | for i, row in enumerate(beliefs): 46 | for j, cell in enumerate(row): 47 | # debugging info : the "height" and "width" in the modulo part was interchanged. 48 | new_i = (i + dy ) % height 49 | new_j = (j + dx ) % width 50 | new_G[int(new_i)][int(new_j)] = cell 51 | return blur(new_G, blurring) -------------------------------------------------------------------------------- /helpers.py: -------------------------------------------------------------------------------- 1 | def normalize(grid): 2 | """ 3 | Given a grid of unnormalized probabilities, computes the 4 | correspond normalized version of that grid. 5 | """ 6 | total = 0.0 7 | for row in grid: 8 | for cell in row: 9 | total += cell 10 | for i,row in enumerate(grid): 11 | for j,cell in enumerate(row): 12 | grid[i][j] = float(cell) / total 13 | return grid 14 | 15 | 16 | def blur(grid, blurring): 17 | """ 18 | Spreads probability out on a grid using a 3x3 blurring window. 19 | The blurring parameter controls how much of a belief spills out 20 | into adjacent cells. If blurring is 0 this function will have 21 | no effect. 22 | """ 23 | height = len(grid) 24 | width = len(grid[0]) 25 | 26 | center_prob = 1.0-blurring 27 | corner_prob = blurring / 12.0 28 | adjacent_prob = blurring / 6.0 29 | 30 | window = [ 31 | [corner_prob, adjacent_prob, corner_prob], 32 | [adjacent_prob, center_prob, adjacent_prob], 33 | [corner_prob, adjacent_prob, corner_prob] 34 | ] 35 | new = [[0.0 for i in range(width)] for j in range(height)] 36 | for i in range(height): 37 | for j in range(width): 38 | grid_val = grid[i][j] 39 | for dx in range(-1,2): 40 | for dy in range(-1,2): 41 | mult = window[dx+1][dy+1] 42 | new_i = (i + dy) % height 43 | new_j = (j + dx) % width 44 | new[new_i][new_j] += mult * grid_val 45 | return normalize(new) 46 | 47 | def is_robot_localized(beliefs, true_pos): 48 | """ 49 | Returns None if the robot has no "strong opininon" about 50 | its belief. The robot has a strong opinion when the 51 | size of it's best belief is greater than twice the size of 52 | its second best belief. 53 | 54 | If it DOES have a strong opinion then this function returns 55 | True if that opinion is correct and False if it is not. 56 | """ 57 | best_belief = 0.0 58 | best_pos = None 59 | second_best = 0.0 60 | for y, row in enumerate(beliefs): 61 | for x, belief in enumerate(row): 62 | if belief > best_belief: 63 | second_best = best_belief 64 | best_belief = belief 65 | best_pos = (y,x) 66 | elif belief > second_best: 67 | second_best = belief 68 | if second_best <= 0.00001 or best_belief / second_best > 2.0: 69 | # robot thinks it knows where it is 70 | localized = best_pos == true_pos 71 | return localized, best_pos 72 | else: 73 | # No strong single best belief 74 | return None, best_pos 75 | 76 | def close_enough(g1, g2): 77 | if len(g1) != len(g2): 78 | return False 79 | if len(g1) == 0 or len(g1[0]) != len(g2[0]): 80 | return False 81 | for r1, r2 in zip(g1,g2): 82 | for v1, v2 in zip(r1, r2): 83 | if abs(v1 - v2) > 0.001: 84 | print(v1, v2) 85 | return False 86 | return True -------------------------------------------------------------------------------- /simulate.py: -------------------------------------------------------------------------------- 1 | import localizer 2 | import random 3 | from copy import deepcopy 4 | from matplotlib import pyplot as plt 5 | 6 | class Simulation(object): 7 | def __init__(self, grid, blur, p_hit,start_pos=None): 8 | """ 9 | 10 | """ 11 | self.grid = grid 12 | self.beliefs = localizer.initialize_beliefs(self.grid) 13 | self.height = len(grid) 14 | self.width = len(grid[0]) 15 | self.blur = blur 16 | self.p_hit = p_hit 17 | self.p_miss = 1.0 18 | self.incorrect_sense_probability = self.p_miss / (p_hit + self.p_miss) 19 | self.colors = self.get_colors() 20 | self.num_colors = len(self.colors) 21 | if not start_pos: 22 | self.true_pose = (self.height/2, self.width/2) 23 | else: 24 | self.true_pose = start_pos 25 | self.prev_pose = self.true_pose 26 | self.prepare_visualizer() 27 | 28 | def prepare_visualizer(self): 29 | self.X = [] 30 | self.Y = [] 31 | self.P = [] 32 | 33 | def get_colors(self): 34 | all_colors = [] 35 | for row in self.grid: 36 | for cell in row: 37 | if cell not in all_colors: 38 | all_colors.append(cell) 39 | return all_colors 40 | 41 | def sense(self): 42 | color = self.get_observed_color() 43 | beliefs = deepcopy(self.beliefs) 44 | new_beliefs = localizer.sense(color, self.grid, beliefs, self.p_hit, self.p_miss) 45 | if not new_beliefs or len(new_beliefs) == 0: 46 | print "NOTE! The robot doesn't have a working sense function at this point." 47 | self.beliefs = beliefs 48 | else: 49 | self.beliefs = new_beliefs 50 | 51 | def move(self, dy, dx): 52 | new_y = (self.true_pose[0] + dy) % self.height 53 | new_x = (self.true_pose[1] + dx) % self.width 54 | self.prev_pose = self.true_pose 55 | self.true_pose = (new_y, new_x) 56 | beliefs = deepcopy(self.beliefs) 57 | new_beliefs = localizer.move(dy, dx, beliefs, self.blur) 58 | self.beliefs = new_beliefs 59 | 60 | 61 | def get_observed_color(self): 62 | y,x = self.true_pose 63 | true_color = self.grid[y][x] 64 | if random.random() < self.incorrect_sense_probability: 65 | possible_colors = [] 66 | for color in self.colors: 67 | if color != true_color and color not in possible_colors: 68 | possible_colors.append(color) 69 | color = random.choice(possible_colors) 70 | else: 71 | color = true_color 72 | return color 73 | 74 | def show_beliefs(self,past_turn=False): 75 | if past_turn: 76 | X = deepcopy(self.X) 77 | Y = deepcopy(self.Y) 78 | P = deepcopy(self.P) 79 | 80 | del(self.X[:]) 81 | del(self.Y[:]) 82 | del(self.P[:]) 83 | for y, row in enumerate(self.beliefs): 84 | for x, belief in enumerate(row): 85 | self.X.append(x) 86 | self.Y.append(self.height-y-1) # puts large y ABOVE small y 87 | self.P.append(5000.0 * belief) 88 | plt.figure() 89 | if past_turn: 90 | plt.scatter(X, Y, s=P, alpha=0.3,color="blue") 91 | plt.scatter([self.prev_pose[1]], [self.height-self.true_pose[0]-1], color='red', marker="*", s=200, alpha=0.3) 92 | plt.scatter(self.X,self.Y,s=self.P,color="blue") 93 | plt.scatter([self.true_pose[1]], [self.height-self.true_pose[0]-1], color='red', marker="*", s=200) 94 | plt.show() 95 | 96 | def random_move(self): 97 | dy = random.choice([-1,0,1]) 98 | dx = random.choice([-1,0,1]) 99 | return dy,dx 100 | 101 | def run(self, num_steps=1): 102 | for i in range(num_steps): 103 | self.sense() 104 | dy, dx = self.random_move() 105 | self.move(dy,dx) -------------------------------------------------------------------------------- /writeup.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Two Dimensional Histogram Filter - Your First Feature (and your first bug).\n", 8 | "Writing code is important. But a big part of being on a self driving car team is working with a **large** existing codebase. On high stakes engineering projects like a self driving car, you will probably have to earn the trust of your managers and coworkers before they'll let you make substantial changes to the code base. \n", 9 | "\n", 10 | "A typical assignment for someone new to a team is to make progress on a backlog of bugs. So with that in mind, that's what you will be doing for your first project in the Nanodegree.\n", 11 | "\n", 12 | "You'll go through this project in a few parts:\n", 13 | "\n", 14 | "1. **Explore the Code** - don't worry about bugs at this point. The goal is to get a feel for how this code base is organized and what everything does.\n", 15 | "2. **Implement a Feature** - write code that gets the robot moving correctly.\n", 16 | "3. **Fix a Bug** - Implementing motion will reveal a bug which hadn't shown up before. Here you'll identify what the bug is and take steps to reproduce it. Then you'll identify the cause and fix it.\n" 17 | ] 18 | }, 19 | { 20 | "cell_type": "markdown", 21 | "metadata": {}, 22 | "source": [ 23 | "## Part 1: Exploring the code\n", 24 | "In this section you will just run some existing code to get a feel for what this localizer does.\n", 25 | "\n", 26 | "You can navigate through this notebook using the arrow keys on your keyboard. You can run the code in a cell by pressing **`Ctrl + Enter`**\n", 27 | "\n", 28 | "Navigate through the cells below. In each cell you should\n", 29 | "\n", 30 | "1. Read through the code. It's okay to not understand everything at this point. \n", 31 | "2. Make a guess about what will happen when you run the code. \n", 32 | "3. Run the code and compare what you see with what you expected. \n", 33 | "4. When you get to a **TODO** read the instructions carefully and complete the activity.\n", 34 | "\n" 35 | ] 36 | }, 37 | { 38 | "cell_type": "code", 39 | "execution_count": 1, 40 | "metadata": {}, 41 | "outputs": [], 42 | "source": [ 43 | "# This code \"imports\" code from some of the other files we've written\n", 44 | "# in this directory. Specifically simulate.py and helpers.py\n", 45 | "import simulate as sim\n", 46 | "import helpers\n", 47 | "import localizer\n", 48 | "\n", 49 | "# Don't worry too much about this code for now...\n", 50 | "from __future__ import division, print_function\n", 51 | "%load_ext autoreload\n", 52 | "%autoreload 2" 53 | ] 54 | }, 55 | { 56 | "cell_type": "code", 57 | "execution_count": 2, 58 | "metadata": {}, 59 | "outputs": [ 60 | { 61 | "data": { 62 | "image/png": "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\n", 63 | "text/plain": [ 64 | "" 65 | ] 66 | }, 67 | "metadata": { 68 | "needs_background": "light" 69 | }, 70 | "output_type": "display_data" 71 | } 72 | ], 73 | "source": [ 74 | "# This code defines a 5x5 robot world as well as some other parameters\n", 75 | "# which we will discuss later. It then creates a simulation and shows \n", 76 | "# the initial beliefs. \n", 77 | "R = 'r'\n", 78 | "G = 'g'\n", 79 | "grid = [\n", 80 | " [R,G,G,G,R],\n", 81 | " [G,G,R,G,R],\n", 82 | " [G,R,G,G,G],\n", 83 | " [R,R,G,R,G],\n", 84 | " [R,G,R,G,R],\n", 85 | "]\n", 86 | "blur = 0.05\n", 87 | "p_hit = 200.0\n", 88 | "simulation = sim.Simulation(grid, blur, p_hit)\n", 89 | "simulation.show_beliefs()" 90 | ] 91 | }, 92 | { 93 | "cell_type": "markdown", 94 | "metadata": {}, 95 | "source": [ 96 | "Run the code below multiple times by repeatedly pressing Ctrl + Enter.\n", 97 | "\n", 98 | "After each run observe how the state has changed. " 99 | ] 100 | }, 101 | { 102 | "cell_type": "code", 103 | "execution_count": 3, 104 | "metadata": {}, 105 | "outputs": [ 106 | { 107 | "data": { 108 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXcAAAD8CAYAAACMwORRAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMS4xLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvAOZPmwAAIABJREFUeJzt3XmYFNW5+PHvO2vPxj4sYRGuGDeiIiMhmlyJyxU3TNRr0EjUBIkmRuMSiCQ3Xk1uIrnGxO2qGH3A5Rc1RiMoBjW4RCPqgAgiaBAXdgaRGYYZZ31/f5weHYae6Zrumq7u6vfzPP3QPX369Oux6u1Tp06dElXFGGNMuOQEHYAxxhj/WXI3xpgQsuRujDEhZMndGGNCyJK7McaEkCV3Y4wJIUvuxhgTQpbcjTEmhCy5G2NMCOUF9cUDBgzQkSNHBvX1xhiTkZYuXbpdVcvjlQssuY8cOZLKysqgvt4YYzKSiHzopVxgyd30vKYmePppWLcOamqgtBSGDYOTToKioqCjSy9NTfDUU/Dee1BdDSUl8IUvwOTJUFYWdHQmU7W0wLPPwurVbrsqKoJBg+DUU6Ffv579bkvuIbRpE9x+O9x6q9u4Ghtd8srPh4ICUIXvfhcuvRT23TfoaIO1caNrq9tuc23V0ODaKy8PIhG48EI4+2y44go4+OCgozWZoqoK7roL/vAH+PTTvberiy6Cb3wDrroKxo3roSBUNZDHuHHj1Pjv9ttVIxHVwkJVl8ZjP/LzXbmf/1y1tTXoqIMxZ463tsrNVS0qUv3BD1RbWoKO2qS7Rx9VLS5220xX21VOjit31lmqDQ3e6wcq1UOOtdkyIfLLX8KVV37eU+hKU5Mrd+ONMG2a29yyya9/DT/+sbe2ammB+nqYOxdOPx1aW1MSoslAd98N3/421NW5baYrra2u3IIFcNxxrmfvJ0vuITFvHlx/vdtYuqOuDh56CH71q56JKx098AD8z/8k1lbPPAOXX94zcZnM9vTT8KMfxU/qHdXXQ2UlTJ3qbzyiAXXZKioq1GbL+KOhAcrLYdeuxOuIROCjj1w9YdbUBAMHws6didcRicDbb8OoUf7FZTKbKuyzD6xfn3gdxcXw/PNwxBFdlxORpapaEa8+67mHwCOPJD+sIgJz5vgTTzr761+huTm5Olpb3clqY9q88AJ88klydbQNk/rFc3IXkVwReUNEnojxXqGIPCQia0XkVREZ6V+IsbW0wJYtye+oYTB7NtTWJldHfb07s9/S4k9M6cqPtmpsdDMh4o3Vh93WrW6Yas2aoCMJ3g03wO7dydXR2uo6H8n+SLTpTs/9MmB1J+99D/hEVUcDvwdmJxtYV956y81BHjUKhgyB5ct78tvS2/r18K9/+VNXQwO8+qo/daWjLVvctuMHEfj73/2pKxO98AKMHg3/+Z9w+OFw7bVBRxSchgY33u7HCHduLjz+ePL1gMfkLiLDgJOBP3ZS5DRgXvT5I8CxIiLJhxfblCmwbZs7jNm+Hc46q6e+Kf1t2QKFhf7UJeJ6Y2G1dat/bdXSEu62iufcc90RUHW1O+qbPdtdAJaNduxw89f90NDg33bltef+B2AG0NkksKHAegBVbQaqgf4dC4nIdBGpFJHKqqqqBMJ1Nm7c8/WmTQlXlfG6e2a+K6r+1pdu6uvdD5gf2qZHZquOu29BAWzeHEwsQauvhxyfzl42N3d/Fldn4oYkIqcA21R1aVfFYvxtr4MUVZ2jqhWqWlGexLSM9pfPRyJwwgkJV5Xxevf2b456To6rL6x69/ZvjnpeXrjbKp6vftUl9PbGjAkmlqD17u3fub+CAujTx5+6vPzeHAVMFpEPgAeBY0Tk/g5lNgDDAUQkD+gN7PAnxL3dfbe7fPeII9zl4fd3jCaLjBzp38UPjY2w//7+1JWOhg93UyH9oAoHHuhPXZno4YfhmGPcujsHHACLF/uXlDJN376uk+mHwkL/tqu4yV1Vr1bVYao6EpgCLFbVczsUmw+cF31+ZrRMj02gj0TclKHXXoObb87uRbB693aLW/lxWHjIIe4kWViVlroTgLm5ydc1bJg7kZit+vVzC63V1LhFsbK5LXJyXGez45FMIiIROP745OuBJOa5i8h1IjI5+vJuoL+IrAWuAH7qR3DGm6uuSv4HrqwMZs70J550dsUVyZ9ULS2FGTP8iceEww9/mPz5nKIiuOwyfzofYFeohsaYMa4HleiYcnm5OzHt11n/dDZ2LKxYkXhblZW5WUrFxf7GZTLbpElueCrRob+iIvjgA3cFdVfsCtUs8/jjia87XlICCxdmR2IHePRR6NUrsc8WFbkLTSyxm47uvRf690+sB19U5D4fL7F3hyX3kNh3X3juOXdSqzvj7yUl8NhjUBG3HxAeo0a5turbt3uHwMXFcN997kSiMR0NHAj/+Ie7GUd+vvfPFRW5q8PPPNPfeCy5h8jYsfDGG/CVr7gTM51tYLm5LlEdcgi8/LJ/J3AyyWGHubaaMKHrtsrJcT+Ao0e7S+3POCO1cZrMMno0vPmm6wBEIp2fZBX5/M5ojz4K06f7H4sl95AZORJeeglWrnRn8EtK3AZWUuJOJBYWuqsL//lPtxEeemjQEQdnn31cW61YAd///udtVFrqelP5+fDNb7rbpL37Lhx5ZNARm0wwcCD87W/wzjvungG9eu29XU2aBPPnu5VYJ03qmTjshGrItba66Wpt91Dt3du/s/Fh09LiFm1qu4dqv37+TG8z2a2lxS0xvXOnO2Lu1y+5GVteT6hmySm07JWT48bhs/UCk+7IzYUBA9zDGL/k5roTrf33WpClZ9mwjDHGhJAld2OMCSFL7sYYE0KW3I0xJoQsuRtjTAhZcjfGmBCy5G6MMSFkyd0YY0LIkrsxxoSQl3uoRkTkNRF5U0RWici1McqcLyJVIrI8+pjWM+EaY4zxwsvyAw3AMapaKyL5wEsi8pSqLulQ7iFVvcT/EI0xxnRX3OQevRdqbfRlfvQRzGpjxhhjPPE05i4iuSKyHNgGPKOqr8YodoaIrBCRR0RkuK9RGmOM6RZPyV1VW1T1MGAYMF5ExnQosgAYqaqHAM8C82LVIyLTRaRSRCqrqqqSidsYY0wXujVbRlV3As8Dkzr8/WNVbYi+vAsY18nn56hqhapWlJeXJxCuMcYYL7zMlikXkT7R50XAccCaDmWGtHs5GVjtZ5DGGGO6x8tsmSHAPBHJxf0YPKyqT4jIdUClqs4HLhWRyUAzsAM4v6cCNsYYE5/dZs8YYzKI19vs2RWqxhgTQpbcjTEmhCy5G2NMCFlyN8aYELLkbowxIWTJ3RhjQsiSuzHGhJAld2OMCSEvV6imnaYm2LEDdu2CsjLo1w/y84OOKj2pwu7dUFMDpaWuvUSCjspkOlWoq4PqaigpcdtVjnUVY2ppgU8+cW1VVOTyVSTS89+bUf87Vq6ECy6AXr1g5EgYO9b9W1YGU6fC8uVBR5g+3n8frrwSeveGvn1h9GgYMACKi2HaNFi1KugITSbatAn+67+gf3/o08dtVwMHuqR1zjmwdGnQEaaPjz6CGTNcMh82DA47zLVXr14waRIsXux+JHuMqgbyGDdunHr11luqhx2mWlysmpur6ppkz0durnt/zBjV5cs9Vx06H36oOnGiamGhakFB521VVKR6+OGqK1cGHbHJBNu2qZ58stuuCgtjb1c5OW4fPPBA1VdeCTri4GzZonr88aqRSOf7IKiWlqoOG6a6cGH36set6RU3x6Z9cn/+edcIIp03UsdHSYnqs892r8HCYPly1b59O/8B7GwDW7w46MhNOlu7VnXIENX8/NjbkNCy19+Ki1X/8pegI0+9d99VHTRINS/P+z5YVKR6++3ev8Nrck/rYZnly+Hkk6G2tnuHL7t3w+TJkE3rkr3/Pkyc6Mb2Wlq8f662Fk45BZYt67HQTAbbtg2++lXYutWd6+qoHx+znuH0Zccef6+rc0OlixenKNA0sHUrfO1rrs2am71/rr4errgCHn7Y33jSNrm3trqks3t3Yp+vq3M/DN1p5Ex22mnupGki6urgxBOzp62Md9/+Nnz8sdsfY5nMfIayicnM3+u9ujr4xjcS34czTVtbdacj2qa+Hs4/H7Zs8S+etE3uixa5s8vJqK+HJ5/0J550VlkJ773X+Q7oRba0lfHugw/gpZdi99jbnM/cPf7tqLUVHnjA99DSzgcfwMsvJ9dBUoU5c3wLydOdmCIi8pqIvCkiq0Tk2hhlCkXkIRFZKyKvisjIZAP77W/dkEEydu2C2bOTjST93XgjfPppcnXs2gXXX+9PPCYcbr216w5DGTV8mSUATGAJZex96Lh7t9uXE+nNZpJ4beXFp5/CzTf7dwTtZZ57A3CMqtaKSD7wkog8papL2pX5HvCJqo4WkSnAbOBbiQa1fj0sWRK/nBdvvAHr1sG//Zs/9aWbmhp47LHkNyxw5zjeew/23Tf5ujKRKtx/PzzxhJtme+WV2Xv9RHOz60U2NrrXffiEEXy0R5lj+TuNFBKhkUYKmMYf+TvH7lHmI0awZUtfXnsNvvzlVEWfWh3bKhmNjfC3v7kh6WTFTe7Rs7Ntfej86KPj7/BpwH9Hnz8C3CoiEv1st737LhQWJt8bBVfPmjXhTe4ffAAFBf611TvvZG9yv/NOl9Dr6mDBArfdzJ0bdFTB2L59zx7kT7memfyWeiI0UvDZ33ux67N/r+FarsEd2BfQSBGfMpsZ/JLZrF4d3uT+8cddD111R309rF7tT3L3NOYuIrkishzYBjyjqq92KDIUWA+gqs1ANdA/0aCqq/07jGtthZ07/akrHVVX+3fFadjbKp777nOJHdxO9thjwcYTpOpqyGvX9bua33A1v0YRelPz2aO99n9XhKv5NVfzG5qawr1ddWyrZDQ3u6vv/eApuatqi6oeBgwDxovImA5FYqWXvdKziEwXkUoRqayqqur0+yIR/xKWiLt6Lqz8vIw57G0Vz+jRew7DDB0aXCxBi0T2HOpTcrieq5nI82xmMPXE3vDqKWQTQziaF7ieq1FyyM0N93YVifjXGRVxyzn4oVuzZVR1J/A8MKnDWxuA4QAikgf0Bvb6/VHVOapaoaoV5eXlnX7PoEHdm6vddczu8uiwGjTIn7E+CH9bxXPjjXDIIW4HGzoU/vznoCMKzoABsber1xnP/rzDZobE/NxmvsABrKGSIz77W15euLer/v392weLivxrKy+zZcpFpE/0eRFwHLCmQ7H5wHnR52cCixMdbwd3Mqu0NNFP76mwECZM8KeudDRihH/nE8LeVvH07++mlTY2woYNcPDBQUcUnJISd0FOLI0UMITNMd8bzBYaKNzjby0tcMIJfkeYPrpqq+5qbXXXBvjBS899CPCciKwAXseNuT8hIteJyORombuB/iKyFrgC+GlSQeW4K7aSPZSLRODSSyE3N7l60t3Mmcn/GEYicNll4W8rL/waP810M2bE3q6O55nPTqruppgGCthNMQBN5HM8z3xWNj8fzjvPLVgXZp21VXeIuB9B345yvKxR0BOPeGvLbN/uFt7xuj5DrEckorp1q/c1GzJVfb1qWZm1lfFXS4vq4MF7bysP8Z/aClpLsf6BH2kJu/QmLtFairQV9EHO2mPdlDVrgv4v6XmdtVV3HiUlqi+9FP+7yPS1Zfr3h1mzEv/FLy6Gq64K91hfm0gE/vCHxNuqpAR+8pPsaCvjXU6Om7/d/gg6n0ZO5klq6MXpPMqPuZndlHIZt3AGj1JDL07mSfJoorjYrS+z//7B/TekSk6Om0qb6GhDURF8/etw5JE+BuXlF6AnHl5WhWxtVb3gAveL1p1fwOJi1XPOcZ/PJj//uftv725bTZ2afW1lvLvlFtcDB9UIdXorF+tAtsTcngayRW/lYu1XVKeTJqk2NwcdfWrddNPnbdWdVSHHjXNH4F4QliV/W1tVZ81yDRBvGc22dcqvvNIdJmWjm292Qyydrbnd9sjPd+VmzrTEbuL705/cvhVvqLRtH/zud1WbmoKOOhj33uvaIN4+KOI6riefrFpX573+0CT3Nm+/rTp9umu09uu7tzVQ2wZlN59Q/egjl7R793Zj8W03DMjPd6+Li1Uvvjg7xkKNf7ZsUb3uOtX+/ffcrvLy3D4Ziaied1523yynzYYNqj/7mWqfPq6t2t9joS3xn3qq6osvdr9z5TW5iyubehUVFVqZwILrtbXuysEPP3RXcvXrB8OHw+mnu9vtmc81NsLChW6t97Z7qA4dCqee6t+FEib7tLS4VVvffffze6gOHuy2q969g44uvTQ1ubWK1qxxyxSUlrprU775TddmiRCRpapaEbdcpiV3Y4zJZl6Te9rOljHGGJM4S+7GGBNCltyNMSaELLkbY0wIWXI3xpgQsuRujDEhZMndGGNCyJK7McaEkCV3Y4wJIS93YhouIs+JyGoRWSUil8UoM1FEqkVkefTxi54J1xhjjBde7jnTDFypqstEpAxYKiLPqOrbHcr9Q1VP8T9EY4wx3RW3566qm1V1WfT5LmA1kMX3hTfGmPTXrTF3ERkJjAVejfH2V0TkTRF5SkSy+NbCxhgTPM+3AhaRUuAvwI9VtabD28uAfVS1VkROAv4K7BejjunAdIARI0YkHLQxxpiueeq5i0g+LrE/oKqPdnxfVWtUtTb6fCGQLyIDYpSbo6oVqlpRXl6eZOjGGGM642W2jAB3A6tV9cZOygyOlkNExkfr/djPQI0xxnjnZVjmKGAqsFJElkf/NgsYAaCqdwBnAheLSDNQD0zRoO4CYowxJn5yV9WXAIlT5lbgVr+CMsYYkxy7QtUYY0LIkrsxxoSQJXdjjAkhS+7GGBNCltyNMSaELLkbY0wIWXI3xpgQsuRujDEhZMndGGNCyPOqkOninXfgrrtgzRqorobevWG//eDCC+Ggg4KOzpjw27AB5syBN9+EHTugtBT22QcuuADGjwfp8np2kyoZkdxbW+Gvf4XZs2HFCmhudo82eXlw550uuc+cCWecATl2TGKMrxYvhuuvhxdfdK8bGj5/LycH7rsPhg2DGTPg3HOhsDCYOI0jQa3vVVFRoZWVlXHLNTTAlCnwzDOwe3f8ektK4Otfhz//GSIRHwI1Jsu1tsIVV7gj5rq6+OVLSmD//d0+269fz8eXbURkqapWxCuX1v3b5mY48URYtMhbYgdX7u9/h+OPh6amno3PmLBThWnTvCd2cPvgW2+5IZrq6p6Nz3QurZP7j34Er74K9fXd+1x9PSxbBtOn90xcxmSL3/8eHn7Ye2Jv09joxuZPPdX9QJjUS9vkvnUrzJ3b/Y2qTV0dPPig28CMMd3X0ADXXuv9qDnW55ctg9de8zcu442XOzENF5HnRGS1iKwSkctilBERuVlE1orIChE5PNnA5sxJtgbXY7j99uTrMSYbPfpo8r3u+nq44QZ/4jHd46Xn3gxcqaoHAhOAH4pIx0mHJ+JuiL0f7gbYSaXUlha46Sb49NNkanE9h//7Pxt7B3eYbLxpbLShBHCz03btSq6O1lZ44gnYvt2fmDLVypVw663w2GOuTVIhbnJX1c2quiz6fBewGhjaodhpwL3qLAH6iMiQRIN6++09p1klo6XFTZ/MVjU1cMQRbubQfvvBpk1BR5S+6urgq191bTVqFHzwQdARBae2Flat8qeu/Hx4/nl/6spEixbBhAnwk5/A1Klw9tmp6Tx0a8xdREYCY4FXO7w1FFjf7vUG9v4B8GzHDsjNTfTTe8rJcfVlq5tucj9uqi5ZXX110BGlrzlzYOlS11br17vpf9lqxw4oKPCnrpaW7N4Hr7rKdRw+/dSdv1iwAN57r+e/13NyF5FS4C/Aj1W1puPbMT6y12+TiEwXkUoRqayqqur0u/w+bEnVYVA6qqtzOxe4fxM9OZYN2rdVa2viJ/PDoLXVvytNVbN7H+w4CpGTk5phUk/JXUTycYn9AVV9NEaRDcDwdq+HAXsNAKjqHFWtUNWK8vLyTr+vb1//DltUXX3Z6pJLYMAAKCuDXr3gv/876IjS17RpMGiQa6uyMvjVr4KOKDh9+/qXgPLysnsf/MlPoLjYPY9E3JX0BxzQ898bd/kBERHgbmC1qt7YSbH5wCUi8iDwZaBaVTcnGtQBB/j3S9/cDAcf7E9dmWjoUFi3DtauhZEjXYI3sQ0cCP/6l3uMGOHWLcpWvXrBF74AH36YfF1NTW7MOVtdeKHrNMyf787lXH55apZH8bK2zFHAVGCliCyP/m0WMAJAVe8AFgInAWuBOuCCZIKKROC733XTGJOZ6ZKX505glJQkE03mKy6GQw4JOorMEInAl74UdBTBE3E9zpkzkx/K+8pX3MJi2WzyZPdIpbRdW+a992DMmOSmQxYVuYsoUnEIZEzY1NTA4MHdv0K8vdJSt87TpEn+xZXtMn5tmX33hWOOSXxlucJCOOooS+zGJKpXLzek0DZe3F25ue7H4T/+w9+4jDdpm9zBLR+wzz5unmx35Oe7seZHHumZuIzJFr/73efXSXRHTo47Z7F4sS2/HZS0bvayMnj5ZXd2uajI22ciEfjiF+GVV7L7hJgxfsjLg6eegqOP9t6DLyhwPfYlS2D48PjlTc9I6+QObhrfK6/Az372+ZS+WMrK3NrRV1/tVpIcODC1cRoTVkVF8OST8NvfullEpaWx58CXlrrHD37g7tK0336pj9V8Lm1PqMbS0gILF7qrLt9/353FLylxQzeXXgqnnOJ6GsaYnqHq7sT0+9+7ZUJqalzyHzIELroIzjrLbpLT07yeUM2o5G6MMdku42fLGGOMSZwld2OMCSFL7sYYE0KW3I0xJoQsuRtjTAhZcjfGmBCy5G6MMSFkyd0YY0LIkrsxxoSQJXdjjAmhuMldRO4RkW0i8lYn708UkWoRWR59/ML/MI0xxnSHl2W25gK3Avd2UeYfqnqKLxEZY4xJWtyeu6q+COxIQSzGGGN84teY+1dE5E0ReUpEDu6skIhMF5FKEamsqqry6auNMcZ05EdyXwbso6qHArcAf+2soKrOUdUKVa0oLy/34auNMcbEknRyV9UaVa2NPl8I5IvIgKQjM8YYk7Ckk7uIDBZxN90SkfHROj9Otl5jjDGJiztbRkT+BEwEBojIBuAaIB9AVe8AzgQuFpFmoB6YokHd3skYYwzgIbmr6tlx3r8VN1XSGGNMmrArVI0xJoQsuRtjTAhZcjfGmBCy5G6MMSFkyd0YY0LIkrsxxoSQJXdjjAkhS+7GGBNCXtZzNyYrrF8P69ZBdTWUlMDQoXDAAUFHZTLdhg3wzjtuuyoqgkGDYOxYcIu29BxL7iartbTAU0/B7NlQWQmFhZ+/19QEw4fDzJkwZYrbMY3xorUVFi2C3/4Wlixx25WqS+gtLdCrF1x5JVxwAfTt2zMxSFDLwFRUVGhlZWUg320MwOuvw6mnQl0d7NrVebnSUvfvnDlwdpeLcRgDK1bASSe5nnptbefliovdj8Avf+kSvdeevIgsVdWKeOVszN1kpUWLYOJE2Lq168QObgetrYXvfQ9uuCEl4ZkM9Y9/wJFHwsaNXSd2cJ2KTz+Fa66BSy91PXs/WXI3WWfpUjj9dLdzdUd9vdsR77+/Z+IymW31ajj5ZNi9u3ufq6uDe+6B66/3Nx5L7iarqMI553Q/sbepq4Pvfz9+b99kn/PPj99b70xdHVx3HXz0kX/xWHI3WeW119whczJE4L77/InHhMOaNbByZXJDK62tcNtt/sUUN7mLyD0isk1E3urkfRGRm0VkrYisEJHD/QvPGH/dcIMbXknG7t3wv//r/xhpJqqtdUkp2910k5tdlYzGRrjjDvevH7z03OcCk7p4/0Rgv+hjOnB78mHF9+yzMGOGOzFmuvbee3Dnna5nkc3q62HBAn+S0fbtsGxZ8vVkqo0b4aCD3DS+Pn3c/pitVGHePGhu9qeuv/0t+XrA252YXhSRkV0UOQ24N3prvSUi0kdEhqjqZn9C3NuLL8Jpp7lxqttug8cfh+OO66lvy2wbN7oLJpqb3XDCK6/AIYcEHVUwtm+H3Fx/6srJcRenjBvnT32ZZupUePddN2d71y745jdhyxZ38Ve22b07+V57m+Zmt135wY8x96HA+navN0T/thcRmS4ilSJSWVVVlfAX/vOf0NDgntfXu+lHJrZly1xSr693PdaXXgo6ouDU1vqX3Ftbs/uk6qpVLrG3l+y5jExVWwt5Pl0O2tTk33blR3KPNfU+5mikqs5R1QpVrSgvL0/4C487zl3xVVDgrho84YSEqwq9CRMgPx/KytwGmM1HOGVleyekROXmuqsMs9X48W67apOX567mzUZlZf4MyYBrU7+2Kz9+bzYA7f+3DgM2+VBvpyoqXG/9hRfga19zr01s5eXw9tvuaOfww2HEiKAjCk55uX8n/5qbYdQof+rKRHPnumsFXnkFhgyBRx7J3uUZiovdo6Ym+bry8vzbrvzouc8HvhOdNTMBqO7J8fY2hx8Ol19uid2LgQPhG9/I7sQO7mjvW9/yZ2hm+HD40peSrydT9e/vOleNjfDhh3DEEUFHFBwRuPBCN5KQrIIC/46uvUyF/BPwCrC/iGwQke+JyEUiclG0yEJgHbAWuAv4gT+hGeO/yy/fc3GwRJSWusXEjGlzySXuJHsyIhG3DIFf4/e2cJjJOmPHwptvJj5PvbQUtm3L3mEIE9vXv+6GixM9rxOJwPvvw+DBXZezhcOM6cSDD7qTYIkoKoKHH7bEbvY2b17iJ0OLi+GWW+In9u6w5G6yzv77u4vfevXq3g0Tiorg9tvhxBN7LjaTuUaMgOeecxd1dWeIprgYZs2CadP8jceSu8lKEya4dWYOOMBdeNPVzlhW5k5KP/44nHde6mI0mefQQ+GNN9zJ9uLirrer0lLXwbjjDvjZz/yPxZK7yVr77++miT73HJx5phvzLCuD3r3dv4WFcPTRbhhn0yY4/vigIzaZYORIWL7cjb9PmeK2q1693HbVq5d7feihcNddUFXlrvbtCXZC1ZioXbvcVZY1Na43P2gQDBgQdFQm0+3a5aaL7tzpevMDB8KwYYnX5/WEqt1D1ZiosjK7IbbxX1lJvvQbAAAMQUlEQVQZjBmT+u+1YRljjAkhS+7GGBNCltyNMSaELLkbY0wIWXI3xpgQsuRujDEhZMndGGNCyJK7McaEkCV3Y4wJIU/JXUQmicg7IrJWRH4a4/3zRaRKRJZHHz6vb2aMMaY74i4/ICK5wG3A8bj7pb4uIvNV9e0ORR9S1Ut6IEZjjDHd5KXnPh5Yq6rrVLUReBA4rWfDMsYYkwwvyX0osL7d6w3Rv3V0hoisEJFHRGS4L9EZY4xJiJfkHuteNR3XCV4AjFTVQ4BngXkxKxKZLiKVIlJZVVXVvUiNMcZ45iW5bwDa98SHAZvaF1DVj1W1IfryLmBcrIpUdY6qVqhqRXl5eSLxGmOM8cBLcn8d2E9ERolIATAFmN++gIgMafdyMrDavxCNMcZ0V9zZMqraLCKXAIuAXOAeVV0lItcBlao6H7hURCYDzcAO4PwejNkYY0wcdps9Y4zJIF5vs2dXqBpjTAhZcjfGmBCy5G6MMSFkyd0YY0LIkrsxxoSQJXdjjAkhS+7GGBNCltyNMSaELLkbYxLW2hp0BKYzltxN1quthTvvhAMPhJISyM2FoiIYNgyuuw62bg06wvTR1lb77w+RiGur/HwYOBBmzICPPgo6wvTR2AgPPQQVFdC7NxQUuO1r+HD4xS9g8+YeDkBVA3mMGzdOjQlSdbXqRRepFherlpSowt6PSMQ9Jk9WXbcu6IiDU1OjOn16121VUODa6thjVVetCjri4DQ0qM6apdq7t2pZWefbVWGh6kknqa5Z0736cWt6xc2xtraMyUobN8LRR8OGDdDQEL98Tg706gVPPw1HHNHz8aWTzZtdW330kbe2EnE91AULYOLEHg8vrezcCSecACtXQn19/PIiUFoKTzwB//7v3r7D1pYxphOffAJHHQUffugtWYEbW965E449Ft7uePfgENu507XV++97bytVN3xz8snw+us9G186+fRTOOYYePNNb4kdXFvt2gUnngh+93UtuZusc/bZrjfa3Nz9z9bWwnHHJfbZTDR1KmzalNh/b12d68XW1fkfVzq67DJYs8b7j2B7PdFWltxNVnn/fXjhBXeyKxFtvdIFC/yNKx2tXw/PPptYsmrT1OROKoZddTXce6/3HnssbSdg/eIpuYvIJBF5R0TWishPY7xfKCIPRd9/VURG+heiMf655Zbkp+/t2gWzZ/sTTzq77Tb3Y5aM2trsaKt589x5mWT43VZxwxGRXOA24ETgIOBsETmoQ7HvAZ+o6mjg90CP/+9saIB333XjXKZr27e7HtjGjUFHEqyGBvjjHxPvtbe3YoXb/sKqqQnuuCO5XnubDRvCPfauCjfc4M+Qip9t5eW3ZjywVlXXqWoj8CBwWocypwHzos8fAY4VEfEnxL1t3Qr77gvjxsGoUW5M0MS2di2MHg1nnunmJi9ZEnREwfnww+R7om3y8mDZMn/qSkcbN/p3XqG1FZYu9aeudFRX59+c9dZW/06seknuQ4H17V5viP4tZhlVbQaqgf5+BBjL/fdDVZU7jNm+He65p6e+KfPdeSfU1Lgxwd274frrg44oODt3uotu/NDc7GbdhJWfbdXYGP62ys/3p66GBv/ayktyj9UD79j/8VIGEZkuIpUiUllVVeUlvpjKy13PCVyjDhqUcFWhN3AgFBa659neVvn5/vXcRdwVh2HlZ1vl5FhbeeVnW3lJ7huA4e1eDwM6DoR8VkZE8oDewI6OFanqHFWtUNWK8vLyxCIGvv1tuOAC2GcfN1XrggsSrir0fvQjNze7qMhdBv2b3wQdUXD693djyX7Iy3P1hVX//v6cmwCXrPr186eudNS3r3/bVWGhf9tV3CtUo8n6XeBYYCPwOnCOqq5qV+aHwJdU9SIRmQKcrqpndVWvXaFqUk3VnX9Yty75uiIR2LLFrRkSVgce6OZtJ6uwED74AAYPTr6udDVxoptim6xIxE3X7aqtfLtCNTqGfgmwCFgNPKyqq0TkOhGZHC12N9BfRNYCVwB7TZc0JmgibnGrkpLk6snNhW99K9yJHWDmTHdpfDJE4Pjjw53YwW1XZWXJ1SHiLpDzq61sbRmTVWpr3XmHZKatFRfDP/8Jhx7qX1zpqL7end/avTvxOkpK4Mkn3do0YdbSAl/4AmzblngdpaWureKtMWNryxgTQ2kpzJqVeO+9qMitHxL2xA7uv/WaaxJvq8JCOOww7wtiZbLcXPjd79wPfyLa2uprX/MvJkvuJuvMmgWnn979HTESgS9+ER5+uGfiSkdXXQVnndX9tioocOuWL1zohhuywbnnwhVXdL+tCgthxAjXa/ezrSy5m6wjAnPnwrRpbkf0skOVlMCRR8LLL7sebbYQcVf1Xnxx99rq0EPhtdfcMsnZ5Je/hGuvdduIl+sESkth7NieaStL7iYr5eTATTfBokVw6qmuVx6J7FkmL8/9bfx4tyjU008nfzI2E+XkuMvrFy2CU05xPc2ObZWT45L/mDHuwrmXXnJTBLPRVVe5K8HPPde1U8eefF6eS/7jxrkLMF98Efr08T8OO6FqDG5Ji7lzYdUq2LHDzXwYNQq+8x044ICgo0svW7a4pLRihWur0lJ3zcl3vuN6oeZz1dXwwANujfeqKrddDR8O55wDB3VcocsjrydULbkbY0wGsdkyxhiTxQLruYtIFfChD1UNALb7UI+f0jEmSM+40jEmSM+40jEmSM+40jEm8CeufVQ17votgSV3v4hIpZdDlFRKx5ggPeNKx5ggPeNKx5ggPeNKx5ggtXHZsIwxxoSQJXdjjAmhMCT3OUEHEEM6xgTpGVc6xgTpGVc6xgTpGVc6xgQpjCvjx9yNMcbsLQw9d2OMMR1kRHIXkUki8o6IrBWRvdaKF5FCEXko+v6rIjIyTeI6X0SqRGR59DEtBTHdIyLbROStTt4XEbk5GvMKETk8DWKaKCLV7drpFymIabiIPCciq0VklYhcFqNMEG3lJa4g2isiIq+JyJvRuK6NUSal+6HHmFK+D0a/N1dE3hCRJ2K8l5p2UtW0fgC5wHvAvwEFwJvAQR3K/AC4I/p8CvBQmsR1PnBritvr34HDgbc6ef8k4CncfW8nAK+mQUwTgSdS3E5DgMOjz8twdxvr+P8viLbyElcQ7SVAafR5PvAqMKFDmZTuhx5jSvk+GP3eK4D/F+v/U6raKRN67uOBtaq6TlUbgQeB0zqUOQ2YF33+CHCsSI8vNOolrpRT1ReJcf/adk4D7lVnCdBHRIYEHFPKqepmVV0Wfb4Ld5exoR2KBdFWXuJKuWgb1EZf5kcfHU/YpXQ/9BhTyonIMOBk4I+dFElJO2VCch8KrG/3egN7b+yflVF3W8BqoKdvX+wlLoAzoof0j4jI8Bjvp5rXuFPtK9HD66dE5OBUfnH0sHgsrufXXqBt1UVcEEB7RYcalgPbgGdUtdP2StV+6CEmSP0++AdgBtDayfspaadMSO6xftE6/jp7KeM3L9+5ABipqocAz/L5r3WQgmireJbhLqk+FLgF+GuqvlhESoG/AD9W1ZqOb8f4SEraKk5cgbSXqrao6mHAMGC8iIzpUCTl7eUhppTugyJyCrBNVZd2VSzG33xvp0xI7huA9r+2w4BNnZURkTygNz0/DBA3LlX9WFUboi/vAsb1cExeeGnPlFLVmrbDa1VdCOSLyICe/l4Ryccl0AdU9dEYRQJpq3hxBdVe7b5/J/A8MKnDW0Hsh13GFMA+eBQwWUQ+wA3VHiMi93cok5J2yoTk/jqwn4iMEpEC3AmI+R3KzAfOiz4/E1is0bMVQcbVYXx2Mm78NGjzge9EZ4JMAKpVdXOQAYnI4LYxRxEZj9suP+7h7xTgbmC1qt7YSbGUt5WXuAJqr3IR6RN9XgQcB6zpUCyl+6GXmFK9D6rq1ao6TFVH4nLCYlU9t0OxlLRTnt8V+k1Vm0XkEmARbobKPaq6SkSuAypVdT5uZ7hPRNbifgGnpElcl4rIZKA5Gtf5PR2XiPwJN5tigIhsAK7BnWhCVe8AFuJmgawF6oAL0iCmM4GLRaQZqAempODH+ShgKrAyOmYLMAsY0S6ulLeVx7iCaK8hwDwRycX9mDysqk8EvB96iSnl+2AsQbSTXaFqjDEhlAnDMsYYY7rJkrsxxoSQJXdjjAkhS+7GGBNCltyNMSaELLkbY0wIWXI3xpgQsuRujDEh9P8Bfg7XM7XztCIAAAAASUVORK5CYII=\n", 109 | "text/plain": [ 110 | "" 111 | ] 112 | }, 113 | "metadata": { 114 | "needs_background": "light" 115 | }, 116 | "output_type": "display_data" 117 | } 118 | ], 119 | "source": [ 120 | "simulation.run(1)\n", 121 | "simulation.show_beliefs()" 122 | ] 123 | }, 124 | { 125 | "cell_type": "markdown", 126 | "metadata": {}, 127 | "source": [ 128 | "What do you think this call to `run` is doing? Look at the code in **`simulate.py`** to find out (remember - you can see other files in the current directory by clicking on the `jupyter` logo in the top left of this notebook).\n", 129 | "\n", 130 | "Spend a few minutes looking at the `run` method and the methods it calls to get a sense for what's going on." 131 | ] 132 | }, 133 | { 134 | "cell_type": "markdown", 135 | "metadata": {}, 136 | "source": [ 137 | "#### What am I looking at?\n", 138 | "\n", 139 | "The red star shows the robot's true position. The blue circles indicate the strength of the robot's belief that it is at any particular location.\n", 140 | "\n", 141 | "Ideally we want the biggest blue circle to be at the same position as the red star." 142 | ] 143 | }, 144 | { 145 | "cell_type": "code", 146 | "execution_count": 4, 147 | "metadata": {}, 148 | "outputs": [], 149 | "source": [ 150 | "# We will provide you with the function below to help you look\n", 151 | "# at the raw numbers.\n", 152 | "\n", 153 | "def show_rounded_beliefs(beliefs):\n", 154 | " for row in beliefs:\n", 155 | " for belief in row:\n", 156 | " print(\"{:0.3f}\".format(belief), end=\" \")\n", 157 | " print()\n", 158 | " \n", 159 | "# The {:0.3f} notation is an example of \"string \n", 160 | "# formatting\" in Python. You can learn more about string \n", 161 | "# formatting at https://pyformat.info/" 162 | ] 163 | }, 164 | { 165 | "cell_type": "code", 166 | "execution_count": 5, 167 | "metadata": {}, 168 | "outputs": [ 169 | { 170 | "name": "stdout", 171 | "output_type": "stream", 172 | "text": [ 173 | "0.003 0.069 0.070 0.004 0.070 \n", 174 | "0.070 0.069 0.003 0.069 0.070 \n", 175 | "0.069 0.002 0.002 0.069 0.003 \n", 176 | "0.002 0.002 0.069 0.003 0.069 \n", 177 | "0.002 0.002 0.070 0.070 0.069 \n" 178 | ] 179 | } 180 | ], 181 | "source": [ 182 | "show_rounded_beliefs(simulation.beliefs)" 183 | ] 184 | }, 185 | { 186 | "cell_type": "markdown", 187 | "metadata": {}, 188 | "source": [ 189 | "_____" 190 | ] 191 | }, 192 | { 193 | "cell_type": "markdown", 194 | "metadata": {}, 195 | "source": [ 196 | "## Part 2: Implement a 2D sense function.\n", 197 | "As you can see, the robot's beliefs aren't changing. No matter how many times we call the simulation's sense method, nothing happens. The beliefs remain uniform." 198 | ] 199 | }, 200 | { 201 | "cell_type": "markdown", 202 | "metadata": {}, 203 | "source": [ 204 | "### Instructions\n", 205 | "1. Open `localizer.py` and complete the `sense` function.\n", 206 | "3. Run the code in the cell below to import the localizer module (or reload it) and then test your sense function.\n", 207 | "4. If the test passes, you've successfully implemented your first feature! Keep going with the project. If your tests don't pass (they likely won't the first few times you test), keep making modifications to the `sense` function until they do!" 208 | ] 209 | }, 210 | { 211 | "cell_type": "code", 212 | "execution_count": 6, 213 | "metadata": {}, 214 | "outputs": [ 215 | { 216 | "name": "stdout", 217 | "output_type": "stream", 218 | "text": [ 219 | "Tests pass! Your sense function is working as expected\n" 220 | ] 221 | } 222 | ], 223 | "source": [ 224 | "reload(localizer)\n", 225 | "def test_sense():\n", 226 | " R = 'r'\n", 227 | " _ = 'g'\n", 228 | "\n", 229 | " simple_grid = [\n", 230 | " [_,_,_],\n", 231 | " [_,R,_],\n", 232 | " [_,_,_]\n", 233 | " ]\n", 234 | "\n", 235 | " p = 1.0 / 9\n", 236 | " initial_beliefs = [\n", 237 | " [p,p,p],\n", 238 | " [p,p,p],\n", 239 | " [p,p,p]\n", 240 | " ]\n", 241 | "\n", 242 | " observation = R\n", 243 | "\n", 244 | " expected_beliefs_after = [\n", 245 | " [1/11, 1/11, 1/11],\n", 246 | " [1/11, 3/11, 1/11],\n", 247 | " [1/11, 1/11, 1/11]\n", 248 | " ]\n", 249 | "\n", 250 | " p_hit = 3.0\n", 251 | " p_miss = 1.0\n", 252 | " beliefs_after_sensing = localizer.sense(\n", 253 | " observation, simple_grid, initial_beliefs, p_hit, p_miss)\n", 254 | "\n", 255 | " if helpers.close_enough(beliefs_after_sensing, expected_beliefs_after):\n", 256 | " print(\"Tests pass! Your sense function is working as expected\")\n", 257 | " return\n", 258 | " \n", 259 | " elif not isinstance(beliefs_after_sensing, list):\n", 260 | " print(\"Your sense function doesn't return a list!\")\n", 261 | " return\n", 262 | " \n", 263 | " elif len(beliefs_after_sensing) != len(expected_beliefs_after):\n", 264 | " print(\"Dimensionality error! Incorrect height\")\n", 265 | " return\n", 266 | " \n", 267 | " elif len(beliefs_after_sensing[0] ) != len(expected_beliefs_after[0]):\n", 268 | " print(\"Dimensionality Error! Incorrect width\")\n", 269 | " return\n", 270 | " \n", 271 | " elif beliefs_after_sensing == initial_beliefs:\n", 272 | " print(\"Your code returns the initial beliefs.\")\n", 273 | " return\n", 274 | " \n", 275 | " total_probability = 0.0\n", 276 | " for row in beliefs_after_sensing:\n", 277 | " for p in row:\n", 278 | " total_probability += p\n", 279 | "\n", 280 | " if abs(total_probability-1.0) > 0.001:\n", 281 | " \n", 282 | " print(\"Your beliefs appear to not be normalized\")\n", 283 | " return\n", 284 | " \n", 285 | " print(\"Something isn't quite right with your sense function\")\n", 286 | "\n", 287 | "test_sense()" 288 | ] 289 | }, 290 | { 291 | "cell_type": "markdown", 292 | "metadata": {}, 293 | "source": [ 294 | "## Integration Testing\n", 295 | "Before we call this \"complete\" we should perform an **integration test**. We've verified that the sense function works on it's own, but does the localizer work overall?\n", 296 | "\n", 297 | "Let's perform an integration test. First you you should execute the code in the cell below to prepare the simulation environment." 298 | ] 299 | }, 300 | { 301 | "cell_type": "code", 302 | "execution_count": 7, 303 | "metadata": {}, 304 | "outputs": [], 305 | "source": [ 306 | "from simulate import Simulation\n", 307 | "import simulate as sim\n", 308 | "import helpers\n", 309 | "reload(localizer)\n", 310 | "reload(sim)\n", 311 | "reload(helpers)\n", 312 | "\n", 313 | "R = 'r'\n", 314 | "G = 'g'\n", 315 | "grid = [\n", 316 | " [R,G,G,G,R,R,R],\n", 317 | " [G,G,R,G,R,G,R],\n", 318 | " [G,R,G,G,G,G,R],\n", 319 | " [R,R,G,R,G,G,G],\n", 320 | " [R,G,R,G,R,R,R],\n", 321 | " [G,R,R,R,G,R,G],\n", 322 | " [R,R,R,G,R,G,G],\n", 323 | "]\n", 324 | "\n", 325 | "# Use small value for blur. This parameter is used to represent\n", 326 | "# the uncertainty in MOTION, not in sensing. We want this test\n", 327 | "# to focus on sensing functionality\n", 328 | "blur = 0.1\n", 329 | "p_hit = 100.0\n", 330 | "simulation = sim.Simulation(grid, blur, p_hit)" 331 | ] 332 | }, 333 | { 334 | "cell_type": "code", 335 | "execution_count": 8, 336 | "metadata": {}, 337 | "outputs": [ 338 | { 339 | "data": { 340 | "image/png": "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\n", 341 | "text/plain": [ 342 | "" 343 | ] 344 | }, 345 | "metadata": { 346 | "needs_background": "light" 347 | }, 348 | "output_type": "display_data" 349 | } 350 | ], 351 | "source": [ 352 | "# Use control+Enter to run this cell many times and observe how \n", 353 | "# the robot's belief that it is in each cell (represented by the\n", 354 | "# size of the corresponding circle) changes as the robot moves.\n", 355 | "# The true position of the robot is given by the red star.\n", 356 | "\n", 357 | "# Run this cell about 15-25 times and observe the results\n", 358 | "simulation.run(1)\n", 359 | "simulation.show_beliefs()\n", 360 | "\n", 361 | "# If everything is working correctly you should see the beliefs\n", 362 | "# converge to a single large circle at the same position as the \n", 363 | "# red star. Though, if your sense function is implemented correctly\n", 364 | "# and this output is not converging as expected.. it may have to do\n", 365 | "# with the `move` function bug; your next task!\n", 366 | "#\n", 367 | "# When you are satisfied that everything is working, continue\n", 368 | "# to the next section" 369 | ] 370 | }, 371 | { 372 | "cell_type": "markdown", 373 | "metadata": {}, 374 | "source": [ 375 | "## Part 3: Identify and Reproduce a Bug\n", 376 | "Software has bugs. That's okay.\n", 377 | "\n", 378 | "A user of your robot called tech support with a complaint\n", 379 | "\n", 380 | "> \"So I was using your robot in a square room and everything was fine. Then I tried loading in a map for a rectangular room and it drove around for a couple seconds and then suddenly stopped working. Fix it!\"\n", 381 | "\n", 382 | "Now we have to debug. We are going to use a systematic approach.\n", 383 | "\n", 384 | "1. Reproduce the bug\n", 385 | "2. Read (and understand) the error message (when one exists)\n", 386 | "3. Write a test that triggers the bug.\n", 387 | "4. Generate a hypothesis for the cause of the bug.\n", 388 | "5. Try a solution. If it fixes the bug, great! If not, go back to step 4." 389 | ] 390 | }, 391 | { 392 | "cell_type": "markdown", 393 | "metadata": {}, 394 | "source": [ 395 | "### Step 1: Reproduce the bug\n", 396 | "The user said that **rectangular environments** seem to be causing the bug. \n", 397 | "\n", 398 | "The code below is the same as the code you were working with when you were doing integration testing of your new feature. See if you can modify it to reproduce the bug." 399 | ] 400 | }, 401 | { 402 | "cell_type": "code", 403 | "execution_count": 9, 404 | "metadata": {}, 405 | "outputs": [ 406 | { 407 | "data": { 408 | "image/png": "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\n", 409 | "text/plain": [ 410 | "" 411 | ] 412 | }, 413 | "metadata": { 414 | "needs_background": "light" 415 | }, 416 | "output_type": "display_data" 417 | } 418 | ], 419 | "source": [ 420 | "from simulate import Simulation\n", 421 | "import simulate as sim\n", 422 | "import helpers\n", 423 | "reload(localizer)\n", 424 | "reload(sim)\n", 425 | "reload(helpers)\n", 426 | "\n", 427 | "R = 'r'\n", 428 | "G = 'g'\n", 429 | "\n", 430 | "grid = [ \n", 431 | " [R,G,G,G,R,R,R],\n", 432 | " [G,G,R,G,R,G,R],\n", 433 | " [G,R,G,G,G,G,R],\n", 434 | " [R,R,G,R,G,G,G],\n", 435 | "]\n", 436 | "\n", 437 | "blur = 0.001\n", 438 | "p_hit = 100.0\n", 439 | "simulation = sim.Simulation(grid, blur, p_hit)\n", 440 | "\n", 441 | "# remember, the user said that the robot would sometimes drive around for a bit...\n", 442 | "# It may take several calls to \"simulation.run\" to actually trigger the bug.\n", 443 | "simulation.run(1)\n", 444 | "simulation.show_beliefs()" 445 | ] 446 | }, 447 | { 448 | "cell_type": "code", 449 | "execution_count": 10, 450 | "metadata": {}, 451 | "outputs": [], 452 | "source": [ 453 | "simulation.run(1)" 454 | ] 455 | }, 456 | { 457 | "cell_type": "markdown", 458 | "metadata": {}, 459 | "source": [ 460 | "### Step 2: Read and Understand the error message\n", 461 | "If you triggered the bug, you should see an error message directly above this cell. The end of that message should say:\n", 462 | "\n", 463 | "```\n", 464 | "IndexError: list index out of range\n", 465 | "```\n", 466 | "\n", 467 | "And just above that you should see something like\n", 468 | "\n", 469 | "```\n", 470 | "path/to/your/directory/localizer.pyc in move(dy, dx, beliefs, blurring)\n", 471 | " 38 new_i = (i + dy ) % width\n", 472 | " 39 new_j = (j + dx ) % height\n", 473 | "---> 40 new_G[int(new_i)][int(new_j)] = cell\n", 474 | " 41 return blur(new_G, blurring)\n", 475 | "```\n", 476 | "\n", 477 | "This tells us that line 40 (in the move function) is causing an `IndexError` because \"list index out of range\".\n", 478 | "\n", 479 | "If you aren't sure what this means, use Google! \n", 480 | "\n", 481 | "Copy and paste `IndexError: list index out of range` into Google! When I do that, I see something like this:\n", 482 | "\n", 483 | "![Search Results](http://i.imgur.com/gleBmBy.png)\n", 484 | "\n", 485 | "Browse through the top links (often these will come from stack overflow) and read what people have said about this error until you are satisfied you understand how it's caused." 486 | ] 487 | }, 488 | { 489 | "cell_type": "markdown", 490 | "metadata": {}, 491 | "source": [ 492 | "### Step 3: Write a test that reproduces the bug\n", 493 | "This will help you know when you've fixed it and help you make sure you never reintroduce it in the future. You might have to try many potential solutions, so it will be nice to have a single function to call to confirm whether or not the bug is fixed" 494 | ] 495 | }, 496 | { 497 | "cell_type": "code", 498 | "execution_count": 11, 499 | "metadata": {}, 500 | "outputs": [], 501 | "source": [ 502 | "# According to the user, sometimes the robot actually does run \"for a while\" \n", 503 | "# - How can you change the code so the robot runs \"for a while\"?\n", 504 | "# - How many times do you need to call simulation.run() to consistently\n", 505 | "# reproduce the bug?\n", 506 | "# Modify the code below so that when the function is called \n", 507 | "# it consistently reproduces the bug.\n", 508 | "def test_robot_works_in_rectangle_world():\n", 509 | " from simulate import Simulation\n", 510 | " import simulate as sim\n", 511 | " import helpers\n", 512 | " reload(localizer)\n", 513 | " reload(sim)\n", 514 | " reload(helpers)\n", 515 | "\n", 516 | " R = 'r'\n", 517 | " G = 'g'\n", 518 | "\n", 519 | " grid = [ \n", 520 | " [R,G,G,G,R,R,R],\n", 521 | " [G,G,R,G,R,G,R],\n", 522 | " [G,R,G,G,G,G,R],\n", 523 | " [R,R,G,R,G,G,G],\n", 524 | " ]\n", 525 | "\n", 526 | " blur = 0.001\n", 527 | " p_hit = 100.0\n", 528 | " for i in range(1000):\n", 529 | " simulation = sim.Simulation(grid, blur, p_hit)\n", 530 | " simulation.run(1)\n", 531 | " \n", 532 | " \n", 533 | "test_robot_works_in_rectangle_world()" 534 | ] 535 | }, 536 | { 537 | "cell_type": "markdown", 538 | "metadata": {}, 539 | "source": [ 540 | "### Step 4: Generate a Hypothesis\n", 541 | "In order to have a guess about what's causing the problem, it will be helpful to use some Python debuggin tools\n", 542 | "\n", 543 | "The `pdb` module (`p`ython `d`e`b`ugger) will be helpful here!\n", 544 | "\n", 545 | "#### Setting up the debugger \n", 546 | "1. Open `localizer.py` and uncomment the line to the top that says `import pdb`\n", 547 | "2. Just before the line of code that is causing the bug `new_G[int(new_i)][int(new_j)] = cell`, add a new line of code that says `pdb.set_trace()`\n", 548 | "3. Run your test by calling your test function (run the cell below this one)\n", 549 | "4. You should see a text entry box pop up! For now, type `c` into the box and hit enter to **c**ontinue program execution. Keep typing `c` and enter until the bug is triggered again" 550 | ] 551 | }, 552 | { 553 | "cell_type": "code", 554 | "execution_count": 12, 555 | "metadata": {}, 556 | "outputs": [], 557 | "source": [ 558 | "test_robot_works_in_rectangle_world()" 559 | ] 560 | }, 561 | { 562 | "cell_type": "markdown", 563 | "metadata": {}, 564 | "source": [ 565 | "#### Using the debugger\n", 566 | "The debugger works by pausing program execution wherever you write `pdb.set_trace()` in your code. You also have access to any variables which are accessible from that point in your code. \n", 567 | "\n", 568 | "Try running your test again. This time, when the text entry box shows up, type `new_i` and hit enter. You will see the value of the `new_i` variable show up in the debugger window. Play around with the debugger: find the values of `new_j`, `height`, and `width`. Do they seem reasonable / correct?\n", 569 | "\n", 570 | "When you are done playing around, type `c` to continue program execution. Was the bug triggered? Keep playing until you have a guess about what is causing the bug." 571 | ] 572 | }, 573 | { 574 | "cell_type": "markdown", 575 | "metadata": {}, 576 | "source": [ 577 | "### Step 5: Write a Fix\n", 578 | "You have a hypothesis about what's wrong. Now try to fix it. When you're done you should call your test function again. You may want to remove (or comment out) the line you added to `localizer.py` that says `pdb.set_trace()` so your test can run without you having to type `c` into the debugger box." 579 | ] 580 | }, 581 | { 582 | "cell_type": "code", 583 | "execution_count": 13, 584 | "metadata": {}, 585 | "outputs": [], 586 | "source": [ 587 | "test_robot_works_in_rectangle_world()" 588 | ] 589 | }, 590 | { 591 | "cell_type": "markdown", 592 | "metadata": {}, 593 | "source": [ 594 | "## Congratulations!\n", 595 | "You've implemented your first feature and successfully debugged a problem the robot was having with rectangular environments. Well done." 596 | ] 597 | } 598 | ], 599 | "metadata": { 600 | "kernelspec": { 601 | "display_name": "Python 2", 602 | "language": "python", 603 | "name": "python2" 604 | }, 605 | "language_info": { 606 | "codemirror_mode": { 607 | "name": "ipython", 608 | "version": 2 609 | }, 610 | "file_extension": ".py", 611 | "mimetype": "text/x-python", 612 | "name": "python", 613 | "nbconvert_exporter": "python", 614 | "pygments_lexer": "ipython2", 615 | "version": "2.7.14" 616 | } 617 | }, 618 | "nbformat": 4, 619 | "nbformat_minor": 2 620 | } 621 | --------------------------------------------------------------------------------