diff --git a/week1_intro/crossentropy_method.ipynb b/week1_intro/crossentropy_method.ipynb new file mode 100644 index 000000000..691c1f912 --- /dev/null +++ b/week1_intro/crossentropy_method.ipynb @@ -0,0 +1,484 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "language_info": { + "name": "python", + "pygments_lexer": "ipython3" + }, + "colab": { + "name": "crossentropy_method.ipynb", + "provenance": [], + "collapsed_sections": [] + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "Tgw0BZflWFHi" + }, + "source": [ + "# Crossentropy method\n", + "\n", + "This notebook will teach you to solve reinforcement learning problems with crossentropy method. After that we'll scale everything up using neural network policy." + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "58SAV2yrWFHp" + }, + "source": [ + "import sys, os\n", + "if 'google.colab' in sys.modules and not os.path.exists('.setup_complete'):\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/setup_colab.sh -O- | bash\n", + "\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/coursera/grading.py -O ../grading.py\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/coursera/week1_intro/submit.py\n", + "\n", + " !touch .setup_complete\n", + "\n", + "# This code creates a virtual display for drawing game images on.\n", + "# It won't have any effect if your machine has a monitor.\n", + "if type(os.environ.get(\"DISPLAY\")) is not str or len(os.environ.get(\"DISPLAY\")) == 0:\n", + " !bash ../xvfb start\n", + " os.environ['DISPLAY'] = ':1'" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "metadata": { + "id": "yjWWG4ojWFHr" + }, + "source": [ + "import gym\n", + "import numpy as np\n", + "\n", + "env = gym.make(\"Taxi-v3\")\n", + "env.reset()\n", + "env.render()" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "metadata": { + "id": "6bkcCW0DWFHs" + }, + "source": [ + "n_states = env.observation_space.n\n", + "n_actions = env.action_space.n\n", + "\n", + "print(\"n_states=%i, n_actions=%i\" % (n_states, n_actions))" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "dWUbRVMwWFHt" + }, + "source": [ + "# Create stochastic policy\n", + "\n", + "This time our policy should be a probability distribution.\n", + "\n", + "```policy[s,a] = P(take action a | in state s)```\n", + "\n", + "Since we still use integer state and action representations, you can use a 2-dimensional array to represent the policy.\n", + "\n", + "Please initialize the policy __uniformly__, that is, the probabililities of all actions should be equal." + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "ABbdevILWFHt" + }, + "source": [ + "def initialize_policy(n_states, n_actions):\n", + " \n", + " \n", + " return policy\n", + "\n", + "policy = initialize_policy(n_states, n_actions)" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "metadata": { + "id": "l_petDW6WFHu" + }, + "source": [ + "assert type(policy) in (np.ndarray, np.matrix)\n", + "assert np.allclose(policy, 1./n_actions)\n", + "assert np.allclose(np.sum(policy, axis=1), 1)" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Y2y9sadSWFHv" + }, + "source": [ + "# Play the game\n", + "\n", + "Just like before, but we also record all states and actions we took." + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "lkEYeB3MWFHv" + }, + "source": [ + "def generate_session(env, policy, t_max=10**4):\n", + " \"\"\"\n", + " Play the game until the end or for t_max ticks.\n", + " :param policy: an array of shape [n_states,n_actions] with the action probabilities\n", + " :returns: list of states, list of actions and the sum of rewards\n", + " \"\"\"\n", + " states, actions = [], []\n", + " total_reward = 0.\n", + "\n", + " s = env.reset()\n", + "\n", + " for t in range(t_max):\n", + " # Hint: you can use np.random.choice for sampling action\n", + " # https://numpy.org/doc/stable/reference/random/generated/numpy.random.choice.html\n", + " a = \n", + "\n", + " new_s, r, done, info = env.step(a)\n", + "\n", + " # Record information we just got from the environment.\n", + " states.append(s)\n", + " actions.append(a)\n", + " total_reward += r\n", + "\n", + " s = new_s\n", + " if done:\n", + " break\n", + "\n", + " return states, actions, total_reward" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "metadata": { + "id": "SV5ykl0DWFHw" + }, + "source": [ + "s, a, r = generate_session(env, policy)\n", + "assert type(s) == type(a) == list\n", + "assert len(s) == len(a)\n", + "assert type(r) in [float, np.float]" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "metadata": { + "id": "8_lQnXmZWFHw" + }, + "source": [ + "# let's see the initial reward distribution\n", + "import matplotlib.pyplot as plt\n", + "%matplotlib inline\n", + "\n", + "sample_rewards = [generate_session(env, policy, t_max=1000)[-1] for _ in range(200)]\n", + "\n", + "plt.hist(sample_rewards, bins=20)\n", + "plt.vlines([np.percentile(sample_rewards, 50)], [0], [100], label=\"50'th percentile\", color='green')\n", + "plt.vlines([np.percentile(sample_rewards, 90)], [0], [100], label=\"90'th percentile\", color='red')\n", + "plt.legend()" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "z7WRpzqCWFHw" + }, + "source": [ + "### Crossentropy method steps" + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "IytipjvLWFHx" + }, + "source": [ + "def select_elites(states_batch, actions_batch, rewards_batch, percentile):\n", + " \"\"\"\n", + " Select states and actions from games that have rewards >= percentile\n", + " :param states_batch: list of lists of states, states_batch[session_i][t]\n", + " :param actions_batch: list of lists of actions, actions_batch[session_i][t]\n", + " :param rewards_batch: list of rewards, rewards_batch[session_i]\n", + "\n", + " :returns: elite_states,elite_actions, both 1D lists of states and respective actions from elite sessions\n", + "\n", + " Please return elite states and actions in their original order \n", + " [i.e. sorted by session number and timestep within session]\n", + "\n", + " If you are confused, see examples below. Please don't assume that states are integers\n", + " (their type will change later).\n", + " \"\"\"\n", + "\n", + " reward_threshold = \n", + "\n", + " elite_states = \n", + " elite_actions = \n", + "\n", + " return elite_states, elite_actions" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "metadata": { + "id": "J4W9Ptu3WFHx" + }, + "source": [ + "states_batch = [\n", + " [1, 2, 3], # game1\n", + " [4, 2, 0, 2], # game2\n", + " [3, 1], # game3\n", + "]\n", + "\n", + "actions_batch = [\n", + " [0, 2, 4], # game1\n", + " [3, 2, 0, 1], # game2\n", + " [3, 3], # game3\n", + "]\n", + "rewards_batch = [\n", + " 3, # game1\n", + " 4, # game2\n", + " 5, # game3\n", + "]\n", + "\n", + "test_result_0 = select_elites(states_batch, actions_batch, rewards_batch, percentile=0)\n", + "test_result_30 = select_elites(states_batch, actions_batch, rewards_batch, percentile=30)\n", + "test_result_90 = select_elites(states_batch, actions_batch, rewards_batch, percentile=90)\n", + "test_result_100 = select_elites(states_batch, actions_batch, rewards_batch, percentile=100)\n", + "\n", + "assert np.all(test_result_0[0] == [1, 2, 3, 4, 2, 0, 2, 3, 1]) \\\n", + " and np.all(test_result_0[1] == [0, 2, 4, 3, 2, 0, 1, 3, 3]), \\\n", + " \"For percentile 0 you should return all states and actions in chronological order\"\n", + "assert np.all(test_result_30[0] == [4, 2, 0, 2, 3, 1]) and \\\n", + " np.all(test_result_30[1] == [3, 2, 0, 1, 3, 3]), \\\n", + " \"For percentile 30 you should only select states/actions from two first\"\n", + "assert np.all(test_result_90[0] == [3, 1]) and \\\n", + " np.all(test_result_90[1] == [3, 3]), \\\n", + " \"For percentile 90 you should only select states/actions from one game\"\n", + "assert np.all(test_result_100[0] == [3, 1]) and\\\n", + " np.all(test_result_100[1] == [3, 3]), \\\n", + " \"Please make sure you use >=, not >. Also double-check how you compute percentile.\"\n", + "\n", + "print(\"Ok!\")" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "metadata": { + "id": "uzl8MCioWFHy" + }, + "source": [ + "def get_new_policy(elite_states, elite_actions):\n", + " \"\"\"\n", + " Given a list of elite states/actions from select_elites,\n", + " return a new policy where each action probability is proportional to\n", + "\n", + " policy[s_i,a_i] ~ #[occurrences of s_i and a_i in elite states/actions]\n", + "\n", + " Don't forget to normalize the policy to get valid probabilities and handle the 0/0 case.\n", + " For states, that you never visited, use a uniform distribution (1/n_actions for all states).\n", + "\n", + " :param elite_states: 1D list of states from elite sessions\n", + " :param elite_actions: 1D list of actions from elite sessions\n", + "\n", + " \"\"\"\n", + "\n", + " new_policy = np.zeros([n_states, n_actions])\n", + "\n", + " \n", + " # Don't forget to set 1/n_actions for all actions in unvisited states.\n", + "\n", + " return new_policy" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "metadata": { + "id": "Kbd9S0-kWFH0" + }, + "source": [ + "elite_states = [1, 2, 3, 4, 2, 0, 2, 3, 1]\n", + "elite_actions = [0, 2, 4, 3, 2, 0, 1, 3, 3]\n", + "\n", + "new_policy = get_new_policy(elite_states, elite_actions)\n", + "\n", + "assert np.isfinite(new_policy).all(), \\\n", + " \"Your new policy contains NaNs or +-inf. Make sure you don't divide by zero.\"\n", + "assert np.all(new_policy >= 0), \\\n", + " \"Your new policy can't have negative action probabilities\"\n", + "assert np.allclose(new_policy.sum(axis=-1), 1), \\\n", + " \"Your new policy should be a valid probability distribution over actions\"\n", + "\n", + "reference_answer = np.array([\n", + " [1., 0., 0., 0., 0.],\n", + " [0.5, 0., 0., 0.5, 0.],\n", + " [0., 0.33333333, 0.66666667, 0., 0.],\n", + " [0., 0., 0., 0.5, 0.5]])\n", + "assert np.allclose(new_policy[:4, :5], reference_answer)\n", + "\n", + "print(\"Ok!\")" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "c1OuPogqWFH0" + }, + "source": [ + "# Training loop\n", + "Generate sessions, select N best and fit to those." + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "EnUX8LZuWFH1" + }, + "source": [ + "from IPython.display import clear_output\n", + "\n", + "def show_progress(rewards_batch, log, percentile, reward_range=[-990, +10]):\n", + " \"\"\"\n", + " A convenience function that displays training progress. \n", + " No cool math here, just charts.\n", + " \"\"\"\n", + "\n", + " mean_reward = np.mean(rewards_batch)\n", + " threshold = np.percentile(rewards_batch, percentile)\n", + " log.append([mean_reward, threshold])\n", + " \n", + " plt.figure(figsize=[8, 4])\n", + " plt.subplot(1, 2, 1)\n", + " plt.plot(list(zip(*log))[0], label='Mean rewards')\n", + " plt.plot(list(zip(*log))[1], label='Reward thresholds')\n", + " plt.legend()\n", + " plt.grid()\n", + "\n", + " plt.subplot(1, 2, 2)\n", + " plt.hist(rewards_batch, range=reward_range)\n", + " plt.vlines([np.percentile(rewards_batch, percentile)],\n", + " [0], [100], label=\"percentile\", color='red')\n", + " plt.legend()\n", + " plt.grid()\n", + " clear_output(True)\n", + " print(\"mean reward = %.3f, threshold=%.3f\" % (mean_reward, threshold))\n", + " plt.show()" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "metadata": { + "id": "rjWzwcnkWFH1" + }, + "source": [ + "# reset policy just in case\n", + "policy = initialize_policy(n_states, n_actions)" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "metadata": { + "id": "rO4I4c_RWFH1" + }, + "source": [ + "n_sessions = 250 # sample this many sessions\n", + "percentile = 50 # take this percent of session with highest rewards\n", + "learning_rate = 0.5 # how quickly the policy is updated, on a scale from 0 to 1\n", + "\n", + "log = []\n", + "\n", + "for i in range(100):\n", + " %time sessions = [ ]\n", + "\n", + " states_batch, actions_batch, rewards_batch = zip(*sessions)\n", + "\n", + " elite_states, elite_actions = \n", + "\n", + " new_policy = \n", + "\n", + " policy = learning_rate * new_policy + (1 - learning_rate) * policy\n", + "\n", + " # display results on the chart\n", + " show_progress(rewards_batch, log, percentile)" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "DFbElLtLWFH2" + }, + "source": [ + "### Reflecting on the results\n", + "\n", + "You may have noticed that the taxi problem quickly converges from less than -1000 to a near-optimal score and then descends back to -50/-100. This is in part because the environment has some innate randomness. Namely, the starting points of passenger/driver change from episode to episode.\n", + "\n", + "In case CEM failed to learn, how to win from one distinct starting point, it will simply discard it because no sessions from that starting point will make it into the \"elites\".\n", + "\n", + "To mitigate that problem, you can either reduce the threshold for elite sessions (duct tape way) or change the way you evaluate the strategy (theoretically correct way). For each starting state, you can sample an action randomly, and then evaluate this action by running _several_ games starting from it and averaging the total reward. Choosing elite sessions with this kind of sampling (where each session reward is counted as the average of the rewards of all sessions with the same starting state and action) should improve the performance of your policy." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "M1yaM2oyWFH3" + }, + "source": [ + "### Submit to coursera" + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "8-gzJQyzWFH3" + }, + "source": [ + "from submit import submit_taxi\n", + "submit_taxi(generate_session, policy, 'your.email@example.com', 'YourAssignmentToken')" + ], + "execution_count": null, + "outputs": [] + } + ] +} \ No newline at end of file diff --git a/week1_intro/deep_crossentropy_method.ipynb b/week1_intro/deep_crossentropy_method.ipynb new file mode 100644 index 000000000..e41dccc69 --- /dev/null +++ b/week1_intro/deep_crossentropy_method.ipynb @@ -0,0 +1,468 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "language_info": { + "name": "python", + "pygments_lexer": "ipython3" + }, + "colab": { + "name": "deep_crossentropy_method.ipynb", + "provenance": [], + "collapsed_sections": [] + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "3DQr095WiWhN" + }, + "source": [ + "# Deep Crossentropy method\n", + "\n", + "In this section we'll extend your CEM implementation with neural networks! You will train a multi-layer neural network to solve simple continuous state space games. __Please make sure you're done with tabular crossentropy method from the previous notebook.__\n", + "\n", + "![img](https://tip.duke.edu/independent_learning/greek/lesson/digging_deeper_final.jpg)\n", + "\n" + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "4OMgbRtniWhV" + }, + "source": [ + "import sys, os\n", + "if 'google.colab' in sys.modules and not os.path.exists('.setup_complete'):\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/setup_colab.sh -O- | bash\n", + "\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/coursera/grading.py -O ../grading.py\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/coursera/week1_intro/submit.py\n", + "\n", + " !touch .setup_complete\n", + "\n", + "# This code creates a virtual display for drawing game images on.\n", + "# It won't have any effect if your machine has a monitor.\n", + "if type(os.environ.get(\"DISPLAY\")) is not str or len(os.environ.get(\"DISPLAY\")) == 0:\n", + " !bash ../xvfb start\n", + " os.environ['DISPLAY'] = ':1'" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "metadata": { + "id": "3JfSCwrdiWhW" + }, + "source": [ + "import gym\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "%matplotlib inline\n", + "\n", + "# if you see \" has no attribute .env\", remove .env or update gym\n", + "env = gym.make(\"CartPole-v0\").env\n", + "\n", + "env.reset()\n", + "n_actions = env.action_space.n\n", + "state_dim = env.observation_space.shape[0]\n", + "\n", + "plt.imshow(env.render(\"rgb_array\"))\n", + "print(\"state vector dim =\", state_dim)\n", + "print(\"n_actions =\", n_actions)" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "AVH_vr6NiWhW" + }, + "source": [ + "# Neural Network Policy\n", + "\n", + "For this assignment we'll utilize the simplified neural network implementation from __[Scikit-learn](https://scikit-learn.org/stable/modules/generated/sklearn.neural_network.MLPClassifier.html)__. Here's what you'll need:\n", + "\n", + "* `agent.partial_fit(states, actions)` - makes a single training pass over the data. Maximize the probabilitity of :actions: from :states:\n", + "* `agent.predict_proba(states)` - predicts probabilities of all actions, a matrix of shape __[len(states), n_actions]__\n" + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "klwcW0L8iWhX" + }, + "source": [ + "from sklearn.neural_network import MLPClassifier\n", + "\n", + "agent = MLPClassifier(\n", + " hidden_layer_sizes=(20, 20),\n", + " activation='tanh',\n", + ")\n", + "\n", + "# initialize agent to the dimension of state space and a number of actions\n", + "agent.partial_fit([env.reset()] * n_actions, range(n_actions), range(n_actions))" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "metadata": { + "id": "tHl1Z4XhiWhX" + }, + "source": [ + "def generate_session(env, agent, t_max=1000):\n", + " \"\"\"\n", + " Play a single game using agent neural network.\n", + " Terminate when game finishes or after :t_max: steps\n", + " \"\"\"\n", + " states, actions = [], []\n", + " total_reward = 0\n", + "\n", + " s = env.reset()\n", + "\n", + " for t in range(t_max):\n", + " \n", + " # use agent to predict a vector of action probabilities for state :s:\n", + " probs = \n", + "\n", + " assert probs.shape == (env.action_space.n,), \"make sure that the probabilities are a vector (hint: np.reshape)\"\n", + " \n", + " # use the probabilities you predicted to pick an action\n", + " # sample proportionally to the probabilities, don't just take the most likely action\n", + " a = \n", + " # ^-- hint: try np.random.choice\n", + "\n", + " new_s, r, done, info = env.step(a)\n", + "\n", + " # record sessions like you did before\n", + " states.append(s)\n", + " actions.append(a)\n", + " total_reward += r\n", + "\n", + " s = new_s\n", + " if done:\n", + " break\n", + " return states, actions, total_reward" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "metadata": { + "id": "mBhJn6GuiWhZ" + }, + "source": [ + "dummy_states, dummy_actions, dummy_reward = generate_session(env, agent, t_max=5)\n", + "print(\"states:\", np.stack(dummy_states))\n", + "print(\"actions:\", dummy_actions)\n", + "print(\"reward:\", dummy_reward)" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "4nY61ynwiWhZ" + }, + "source": [ + "### CEM steps\n", + "Deep CEM uses exactly the same strategy as the regular CEM, so you can copy your function code from previous notebook.\n", + "\n", + "The only difference is that now each observation is not a number but a `float32` vector." + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "irzlLE8-iWha" + }, + "source": [ + "def select_elites(states_batch, actions_batch, rewards_batch, percentile=50):\n", + " \"\"\"\n", + " Select states and actions from games that have rewards >= percentile\n", + " :param states_batch: list of lists of states, states_batch[session_i][t]\n", + " :param actions_batch: list of lists of actions, actions_batch[session_i][t]\n", + " :param rewards_batch: list of rewards, rewards_batch[session_i]\n", + "\n", + " :returns: elite_states,elite_actions, both 1D lists of states and respective actions from elite sessions\n", + "\n", + " Please return elite states and actions in their original order \n", + " [i.e. sorted by session number and timestep within session]\n", + "\n", + " If you are confused, see examples below. Please don't assume that states are integers\n", + " (their type will change later).\n", + " \"\"\"\n", + "\n", + " \n", + " \n", + " return elite_states, elite_actions" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "xRxVyyv8iWha" + }, + "source": [ + "# Training loop\n", + "Generate sessions, select N best and fit to those." + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "BKII0ncFiWhb" + }, + "source": [ + "from IPython.display import clear_output\n", + "\n", + "def show_progress(rewards_batch, log, percentile, reward_range=[-990, +10]):\n", + " \"\"\"\n", + " A convenience function that displays training progress. \n", + " No cool math here, just charts.\n", + " \"\"\"\n", + "\n", + " mean_reward = np.mean(rewards_batch)\n", + " threshold = np.percentile(rewards_batch, percentile)\n", + " log.append([mean_reward, threshold])\n", + "\n", + " clear_output(True)\n", + " print(\"mean reward = %.3f, threshold=%.3f\" % (mean_reward, threshold))\n", + " plt.figure(figsize=[8, 4])\n", + " plt.subplot(1, 2, 1)\n", + " plt.plot(list(zip(*log))[0], label='Mean rewards')\n", + " plt.plot(list(zip(*log))[1], label='Reward thresholds')\n", + " plt.legend()\n", + " plt.grid()\n", + "\n", + " plt.subplot(1, 2, 2)\n", + " plt.hist(rewards_batch, range=reward_range)\n", + " plt.vlines([np.percentile(rewards_batch, percentile)],\n", + " [0], [100], label=\"percentile\", color='red')\n", + " plt.legend()\n", + " plt.grid()\n", + "\n", + " plt.show()" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "metadata": { + "id": "jejOIXVliWhb" + }, + "source": [ + "n_sessions = 100\n", + "percentile = 70\n", + "log = []\n", + "\n", + "for i in range(100):\n", + " # generate new sessions\n", + " sessions = [ ]\n", + "\n", + " states_batch, actions_batch, rewards_batch = map(np.array, zip(*sessions))\n", + "\n", + " elite_states, elite_actions = \n", + "\n", + " \n", + "\n", + " show_progress(rewards_batch, log, percentile, reward_range=[0, np.max(rewards_batch)])\n", + "\n", + " if np.mean(rewards_batch) > 190:\n", + " print(\"You Win! You may stop training now via KeyboardInterrupt.\")" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "svMc8z9viWhc" + }, + "source": [ + "# Results" + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "YkjWv7qKiWhc" + }, + "source": [ + "# Record sessions\n", + "\n", + "import gym.wrappers\n", + "\n", + "with gym.wrappers.Monitor(gym.make(\"CartPole-v0\"), directory=\"videos\", force=True) as env_monitor:\n", + " sessions = [generate_session(env_monitor, agent) for _ in range(100)]" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "metadata": { + "id": "mStHKVLqiWhd" + }, + "source": [ + "# Show video. In some setups this may not work. If it doesn't\n", + "# work for you, you can download the videos and view them locally.\n", + "\n", + "from pathlib import Path\n", + "from IPython.display import HTML\n", + "\n", + "video_names = sorted([s for s in Path('videos').iterdir() if s.suffix == '.mp4'])\n", + "\n", + "HTML(\"\"\"\n", + "\n", + "\"\"\".format(video_names[-1])) # You can also try other indices" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "GnY7Pd1oiWhd" + }, + "source": [ + "## Assignment: MountainCar\n", + "\n", + "By this moment you should have got enough score on [CartPole-v0](https://gym.openai.com/envs/CartPole-v0) to consider it solved (see the link). It's time to try something harder.\n", + "\n", + "_if you have any trouble with CartPole-v0 and feel stuck, take a look on forums_\n", + "\n", + "Your assignment is to obtain an average reward of __at least -150__ on `MountainCar-v0`.\n", + "\n", + "See the tips section below, it's kinda important.\n", + " \n", + "* Bonus quest: Devise a way to speed up training against the default version\n", + " * Obvious improvement: use [joblib](https://www.google.com/search?client=ubuntu&channel=fs&q=joblib&ie=utf-8&oe=utf-8)\n", + " * Try re-using samples from 3-5 last iterations when computing threshold and during training\n", + " * Experiment with an amount of training iterations and the learning rate of the neural network (see params)\n", + " \n", + " \n", + "### Tips\n", + "* Gym page: [MountainCar](https://gym.openai.com/envs/MountainCar-v0)\n", + "* Sessions for MountainCar may last for 10k+ ticks. Make sure ```t_max``` param is at least 10k.\n", + " * Also it may be a good idea to cut rewards via \">\" and not \">=\". If 90% of your sessions get reward of -10k and 10% are better, than if you use percentile 20% as the threshold, R >= threshold __fails cut off bad sessions__ whule R > threshold works alright.\n", + "* _issue with gym_: Some versions of gym limit game time by 200 ticks. This will prevent the training in most cases. Make sure your agent is able to play for the specified __t_max__, and if it isn't, try `env = gym.make(\"MountainCar-v0\").env` or otherwise get rid of TimeLimit wrapper.\n", + "* If it won't train it's a good idea to plot reward distribution and record sessions: they may give you some clue. If they don't, call course staff :)\n", + "* 20-neuron network is probably not enough, feel free to experiment.\n", + "\n", + "You may find the following snippet useful:" + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "H9A0Z1_aiWhe", + "outputId": "e7d5cc4f-2191-422e-b884-06babeb6b9a4" + }, + "source": [ + "def visualize_mountain_car(env, agent):\n", + " # Compute policy for all possible x and v (with discretization)\n", + " xs = np.linspace(env.min_position, env.max_position, 100)\n", + " vs = np.linspace(-env.max_speed, env.max_speed, 100)\n", + " \n", + " grid = np.dstack(np.meshgrid(xs, vs[::-1])).transpose(1, 0, 2)\n", + " grid_flat = grid.reshape(len(xs) * len(vs), 2)\n", + " probs = agent.predict_proba(grid_flat).reshape(len(xs), len(vs), 3).transpose(1, 0, 2)\n", + "\n", + " # # The above code is equivalent to the following:\n", + " # probs = np.empty((len(vs), len(xs), 3))\n", + " # for i, v in enumerate(vs[::-1]):\n", + " # for j, x in enumerate(xs):\n", + " # probs[i, j, :] = agent.predict_proba([[x, v]])[0]\n", + "\n", + " # Draw policy\n", + " f, ax = plt.subplots(figsize=(7, 7))\n", + " ax.imshow(probs, extent=(env.min_position, env.max_position, -env.max_speed, env.max_speed), aspect='auto')\n", + " ax.set_title('Learned policy: red=left, green=nothing, blue=right')\n", + " ax.set_xlabel('position (x)')\n", + " ax.set_ylabel('velocity (v)')\n", + " \n", + " # Sample the trajectory and draw it\n", + " states, actions, _ = generate_session(env, agent)\n", + " states = np.array(states)\n", + " ax.plot(states[:, 0], states[:, 1], color='white')\n", + " \n", + " # Draw every 3rd action from the trajectory\n", + " for (x, v), a in zip(states[::3], actions[::3]):\n", + " if a == 0:\n", + " plt.arrow(x, v, -0.1, 0, color='white', head_length=0.02)\n", + " elif a == 2:\n", + " plt.arrow(x, v, 0.1, 0, color='white', head_length=0.02)\n", + "\n", + "with gym.make('MountainCar-v0').env as env:\n", + " visualize_mountain_car(env, agent_mountain_car)" + ], + "execution_count": null, + "outputs": [ + { + "output_type": "display_data", + "data": { + "image/png": "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331W7W8/Ju5UfXz7e5+7j3LPdSIily9flt69e8s999wjwcHB8thjj8mPP/4oAOS9994zt3Pk+LD3PKIVu4hIcnKy1K5dW4oVKybx8fHywQcfaJ5bRez7LNytO50jtN7z3377TR599FEJCgqSUqVKSd++fWXBggUCQPbu3WtuZ+97K6JW9VerVk2MRqPTIwcUNYrIHW7GIaICxcbGokaNGpqD8XqLffv24f7778esWbMwaNAgvcMpNJKTk9G+fXvs3bsXNWvWdPj527dvR+PGjbFo0SLNCmzyHYsXL8bTTz+Nbdu2mUcucPb4KKr69euHJUuW4NKlS3e8JYlcj5ePiQqxo0eP4uTJkxg3bhyioqLuejJ60rZ582Z069bNri/8lJQUpKamIjExEcWKFcPevXvx5ptvonLlyjYLQsg7LVmyBH/++Sdq1qwJg8GAH3/8EdOnT8fDDz9sMZSVI8dHUTVp0iSUK1cO8fHxuHbtGr755ht88sknGD9+PBNCHTApJCrEJk+ebJ5e7IsvvrjjfUnkuOnTp9vdtkSJEtiwYQPeffddXL16FaVLl0abNm0wderUO441Sd4nNDQUS5cuxeuvv47r16+b/+B6/fXXLdo5cnwUVUajEdOnT8eZM2eQnZ2NypUr4+2338awYcP0Dq1I4uVjIiIiIgJnNCEiIiIiJoVERERExKSQiIiIiMBCE5cwmUw4e/YsQkNDnZqajYiIiKggIoKrV6+iXLlydzXIty1MCl3g7NmzqFChgt5hEBERURFy+vRplC9f3mXrY1LoAnlzfZ4CUELPUIiIiKjQywBQ8a7mGr8TJoUukHfJuASYFBIREZEnuPqWNRaaEBERERGTQiIiIiJiUkhEREREYFJIRERERGBSSERERERgUkhEREREYFJIRERERGBSSERERERgUkhEREREYFJIRERERGBSSERERERgUkhEREREYFJIRERERGBSSERERERgUkhEREREYFJIRERERGBSSERERERgUkhEREREYFJIRERERGBSSERERERgUkhEREREYFJIRERERGBSSERERERgUkhEREREYFJIRERERGBSSERERERgUkhEREREYFJIRERERGBSSERERERgUkhEREREYFJIRERERPDBpHD27NmIi4tDUFAQEhMTsXXr1ju2/+6775CYmIigoCDEx8dj7ty5Vm2uXLmCwYMHIyoqCkFBQUhISEBycrK7XgIRERGR1/GppHDZsmUYPnw4XnnlFezevRtNmjRBmzZtcOrUKc32x48fR9u2bdGkSRPs3r0b48aNw9ChQ/Hll1+a29y6dQuPPfYYTpw4gRUrVuCPP/7Axx9/jOjoaE+9LCIiIiLdKSIiegdhr/r166Nu3bqYM2eOeVlCQgI6deqEqVOnWrUfO3YsVq9ejYMHD5qXDRgwAHv37kVqaioAYO7cuZg+fTp+//13GI3Gu4orIyMDYWFhAK4AKHFX6yAiIiKyTwaAe5Ceno4SJVyXd/hMT+GtW7ewa9cutGzZ0mJ5y5YtsX37ds3npKamWrVv1aoVdu7ciaysLADA6tWr0bBhQwwePBiRkZGoUaMG3njjDeTk5NiM5ebNm8jIyLB4EBEREfkyn0kKL168iJycHERGRlosj4yMRFpamuZz0tLSNNtnZ2fj4sWLAIBjx45hxYoVyMnJQXJyMsaPH48ZM2ZgypQpNmOZOnUqwsLCzI8KFSo4+eqIiIiI9OUzSWEuRVEs/i8iVssKap9/uclkQpkyZfDRRx8hMTER3bp1wyuvvGJxifp2L7/8MtLT082P06dP3+3LISIiIvIK/noHYK/SpUvDz8/Pqlfw/PnzVr2BucqWLavZ3t/fH+Hh4QCAqKgoGI1G+Pn5mdskJCQgLS0Nt27dQkBAgNV6AwMDERgY6OxLIiIiIvIaPtNTGBAQgMTERKSkpFgsT0lJQaNGjTSf07BhQ6v2GzZsQL169cxFJY0bN8aRI0dgMpnMbQ4dOoSoqCjNhJCIiIioMPKZpBAARo4ciU8++QRJSUk4ePAgRowYgVOnTmHAgAEA1Mu6PXv2NLcfMGAATp48iZEjR+LgwYNISkrCvHnzMHr0aHObgQMH4tKlSxg2bBgOHTqEtWvX4o033sDgwYM9/vqIiIiI9OIzl48BoGvXrrh06RImTZqEc+fOoUaNGkhOTkZMTAwA4Ny5cxZjFsbFxSE5ORkjRozArFmzUK5cObz//vvo3LmzuU2FChWwYcMGjBgxArVq1UJ0dDSGDRuGsWPHevz1EREREenFp8Yp9FYcp5CIiIg8p4iPU0hERERE7sOkkIiIiIiYFBIRERERk0IiIiIiApNCIiIiIgKTQiIiIiICk0IiIiIiApNCIiIiIgKTQiIiIiICk0IiIiIiApNCIiIiIgKTQiIiIiICk0IiIiIiApNCIiIiIgKTQiIiIiICk0IiIiIiApNCIiIiIgKTQiIiIiICk0IiIiIiApNCIiIiIgKTQiIiIiICk0IiIiIiApNCIiIiIgKTQiIiIiICk0IiIiIiApNCIiKv16MHsGYNULKk3pEQUWHGpJCIyMt17Qq0b69g61YgIkLvaIiosGJSSETkI6pWBbZtA8qV0zsSIiqM/PUOgIjIV4SEqImZp91zj/qvv7+C2FjB9u1A06bAyZOej4WICi8mhUREdlq5EnjsMUXXGIxGBeXKCVJT1cTw8GFdwyGiQoRJIREVaYqi9gCGhQElSlg+bl/24IN6R6syGhWULp3XY3jggN4RWVIU4D//AdLSgLff1jsaIrIXk0IiKrQCA4FKlYAqVfIelSurxRqhobnJnr49f3dLTQyBrl0Fr72mdzSW/P2BMWPU/RoW5n3xEZE2JoVE5NMMBqBiRcvEL/cREwMYDPYlfVlZgvR0ICNDfeT/OffRty9QurR3JJHZ2YI//gA++EDvSO7s1VcVFC8uGD1a70iIqCBMConIZ4SGAg89pD4SEtTE7957gcBA24laerqaPB06pD7atgUaNFBw86agXz/gv/9VE76bNwveflQU0LOnC1/QXTKZBBcuANOmqZe+L1yw3TY8PK9QxVMCAiz/P2qUmhgOGgSIeDYWIrKfIsKPqLMyMjIQFhYG4AqAEnqHQ1RolCypJoBNm6qPOnUAPz/rBDAzU3DkSF7il/9xe8K0fDnQubOanJhMwBNPAN98Y188iqJeknanUqWAChXUR/ny6r/dugHlytlOfK9cEezeDYvH77+rCeGhQ0BYmP69myKCzz4D+vQBcnL0jobI12UAuAfp6ekoUcJ1eQeTQhdgUkjkuBo1gE6dLJcVL65e8o2NBeLigDJlrC//XrokOHECOHcOuHgRuHRJvdRr75msWze1l9FgUGAyCUwmdcaQL75wyctyi1WrgI4dFeTkCHbtAhYvBu67T02Sa9bU7in95x/B4cNArVr6J4S5TCbBl18CTz8NZGXpHQ2RL2NS6LWYFBI57pdfgFq11GROUdR7AxXFOoERURO33J49VwgIyNuOyaSeAnv3BhYudM36XS03KfzmG0GXLpaXuo1GNcmtW1dNEuvUAWrXBkJDvScZvF2tWoJff9U7CiJf5p6kkPcUEpFHVamS11undSn4doqiwM/PffHk9kQuWKBehl6+3H3bulvTpwO//aZW8WZnW/4uKwvYt099zJ+vLlMU4N57Be3bA2+/7T3JoYhg4UJg/369IyEiLUwKicjtcu+L69YNqFvXe5KU28XG6h2Bth9+UB/2ElEHtf7sM2DcOPGaium5c4HBg1lsQuStmBQSkVuUKQM8+STQvTvQuHFeUpKVJUhJUS8dly/vHcmKiGD+fOCtt/SOxLUuXlTvzQwJsc7CoqPVIp4mTdR/IyMt34v0dMH33wNr1wLffgtcu2b/dgMCgJMnLdf31luCMWPu6mUQkYfwnjbUYhMAACAASURBVEIX4D2FRKp77gEef1xNBFu0yLs8bDIJvvsOWLoU+PJLtTikZ0/g3//2fIwJCWqFb/4CllmzBC+8ULR7sBISgEceUR/NmgH33JO3f27eFGzYoL53a9YAly/feV1GI3DrVt7zJ04UTJjgnriJiiYWmngtJoVUlAUHAx07qpeG27SxLOL46SfBkiVqZe/ZszoGmU/ukDS5SeG0aYKxY3UOysv4+QGJicC//qXuq6pV897T7GzB5s1qgvj118Bff1k/P39S+OKLgunTPRU5UVHBpNBrMSmkoighARg5Uu0VLF48L2nYt0+wdKnaK3j8uI4B2rB8OdCli1rA8tprgkmT9I7I+1WvriaHTzwB1K5tWbm9bRuwcqX6OHVKXa4owPjxwPnzwIcf6hQ0UaHGpNBrMSmkoqRFC2DUKKBt27zk4MgRNRFcsgQ4cEDH4OywdCnQtauC0aMFM2boHY3vqVRJvUWgc2d1Zpj8du5UxyH84gvg6FGdAnRQ2bLqIOkHD+odCZEjmBR6LSaFVNgZjUDXrmrPYJ06efcJfvUV8M47wLZtOgfogOBgdUw/R6p5SVv58uoA5J07qwUr+YcY+uEHtXjniy/UaQS91aVLamFMq1bA9u16R0NkLyaFXotJIRVWYWFA//7A0KFAdLT6hX/9uiApCXj3XeDYMZ0DJK8REaHeg9ilC/Doo3kJ4o0b6h8P8+cDmza5bgByV7lyBShRAsjMBNq3V2Mk8n5MCr0Wk0IqbGJjgeHDgb59gZAQ9cv93DnBzJnqWHN//61vfOTdoqLUqex69waqV8/rPTx9Wh28esECdRxFb3Dlijo3dE6OICdHvTSenKx3VEQFYVLotZgUUmFRv756v+ATT+T19Pz6q3rv3ZIlwK1bOgdIPqdePaBXL7UgqVSpvARx2zbBggXAsmXA1avAf/6jXtb3tKZNAX//vFsiTCage3fBihWejwXwjnE7yRcwKfRaTArJ17VtC7z8MvDQQ3lfSuvXq8lgSoqOgVGhERgIdOgAPPecOnRR7h8d//wjWLsW6NLFOxKi3Lmwe/USfPaZp7fuHfuAfAGTQq/FpJB8Ve3awIwZQIsW6pfRrVuCxYuBt98Gfv1V5+Co0CpbVr283KsXUKOG9yVCIgJFUfDAAybs3OnJLXvfviBv5Z6k0OCyNRGRzyhfXr3xf9cuNSHMzBRMny6IjVXvA7ubhNBgAPw5cSbZIS1N/WOkZk2gXj3BRx95V99ETg5w7ZogPV3vSIg8iz2FLsCeQvIVISHA2LHqfYPFiqm9EosWCV55BTh58u7XW6IEsH+/+ujUSa3kJLJXiRJAerpa7KEollMQ5t7n586q5fyz8GRnC65eBR55RLB7t/u2qY09hWQv9/QU8u96oiLAz0+tJJ40CYiMVL94vv9eMGoUXHJ5LDAQKF9eQfnywLp1gnbtgOvXnV8vFUbW/RAZGcATT4h5tpRy5QT16gE1aqhFIAaDeu/hnj3q8erK6vf8UxxmZwuuXAGaNRPs3++6bdivMPTRMLH1ZewpdAH2FJI3a9sWmD49b2iQQ4cEL74IrFrlum1ERADnz6vrz84W7NqlDgbMy29kzf6vnPBwoE8fYOBABXFxecnGunWCWbMEycnO9yBeuaIgLExBVpbgwgWgaVPBkSPOrbNoY1LoGSw08VpMCsmbPPOMes9gVJSaEN57b96g099+C/z8s3rPlCuFhACvvGJ5Ce7AAXVKvEuXXLst8nWOf+UYDEDr1sDgwQpat867vHzihGD2bMFHH939HyC5SeHJk4KHHxbz/M10t5gUegaTQq/FpJC8Rd26wK5dCkwm9d4sRVEg4v57sgBAxPrerCNHgObN1cICIpVzXznx8cCAAQr69AHCw9Xj7epVwbx5wHvvCU6ccGx9+/YpCAxULxmfO+dUaASASaGnMCn0WkwKyRsYDMB77wFDhnjPSTk7W3D6NFCrFnDtmt7RkHdwzVdOUJA6IPaIEQpq1lSP+ZwcwcqVwIwZgp9+sm89igIUKwbcuOGSsIhJoYdwSBoisqFaNWDbNu9KCAE1UY2OVr90qbAQJx+ukZkJfPopUKuWoGVLE9avF/j5KXjySQU//mjAtm0KnnhCPQbv+GqECaFrOXt8eMfxVVQxKSTyYQYDMGYMsHs30KCBgqtXveekmJMjuHULaNcOuHBB72ioMEtJAVq3FtSoYUJSkuDmTUGjRgq+/NKAQ4cUDBkCFC+ud5RE3o+Xj12Al49JD1WrqgNQN2ig9g4mJwuGDQPeeAOoUMGzsRiNQGKi5f2EN2+qxQE//ODZWMjdvP8rIzJS7TUfODDvvsO//xZ8+CEwc6bg7FmdAyQ38q6rJe7Dewq9FpNC8iSDARg5Epg8GQgKUpCeLhg+XE0Q9XL7kDQ3bgCPPgrs2KFfTOQuvvOVUayYOtfyiBEKqlRRj8+sLMGiRcC0aYKDB3UO8A4CA4F69dTbQsgRTAqdwcvHRD6kalX1S2L6dAVBQQr++1/BfffpmxDmJyLIyACaNGFCSPr75x9g7lygWjVBx44mfPedwGhU0KuXggMHDPjqKwX16+sdpbZZsxT88IMB48bpHQkVJUwKiXyAwQCMHg3s2aNeLk5PF/TpI2jbFvjzT72jU2/WB4Dz54HGjYF9+/SNhyg/EWDNGnXYmQcfNOHLLwUmk6BTJ7UoZfNmBa1a6R2lJT8/9Y+sKVMMmDKlqPR+kd6YFBJ5Oa3ewRo11MpLb3HxIlCzpqBBA+D33/WOhhxXdKo7d+wAunQRVK8umDdPcOuWoFkzBevWGbB7t4KuXdWEzBtkZ6v/jhun4N13mRjah5XOzuA9hS7AewrJHbTuHRwxwruSQSosiu7XQHS0es9h//5ASIiaeB09Kpg+XTB/vlo9P3iw5xOy6tWB0qXVuZ9zffKJoH9/cftA9GQvPRN1Fpp4LSaF5GoREcDSpUCLFupJZ906wfPPA2fO6BwYFVL8GihZEhg8GBg2TEHp0urnLi1NHVapYkXv6KUzmQRLlwI9e4rLp6qku1H4kkKfu3w8e/ZsxMXFISgoCImJidi6desd23/33XdITExEUFAQ4uPjMXfuXJttly5dCkVR0KlTJ1eHTWS3Bx8Edu1SE8Jr1wR9+wratGFCSOROf/8NvP46EBMjeOEFE06eFJQtq3hNQgiocz537w68+qr3xESFi08lhcuWLcPw4cPxyiuvYPfu3WjSpAnatGmDUzZmMD9+/Djatm2LJk2aYPfu3Rg3bhyGDh2KL7/80qrtyZMnMXr0aDRp0sTdL4PIpv79ga1bgQoVFPz+u+DBB4GkJL2jIio6btwAPvgAuPdewbPPmnDjhnf1oiqKghMnvCsmKjx86vJx/fr1UbduXcyZM8e8LCEhAZ06dcLUqVOt2o8dOxarV6/GwXyDUQ0YMAB79+5FamqqeVlOTg6aNm2K3r17Y+vWrbhy5Qq+/vpru+Pi5WNyVlAQMGcO0KuX2gPw5ZeC3r2Bq1d1Dox8hM+cxj3LBR1q33+voHEj9WeDQV2hiHpfn7sv4fr7520z15AhJsya5d7tkt7sOXDdc/nY32VrcrNbt25h165deOmllyyWt2zZEtu3b9d8TmpqKlq2bGmxrFWrVpg3bx6ysrJgNBoBAJMmTUJERAT69u1b4OVoALh58yZu3rxp/n9GRoajL4fILDYWWLkSqFNHQU6O4OWXgenT9Y6KiACgf39B167ql3RcnKBJEyAuVoGfH6Aogv0H1Fl7zp+3sYK7zNc7dVKLTQwG9V5CAPj3v4WFZuRWPpMUXrx4ETk5OYiMjLRYHhkZibS0NM3npKWlabbPzs7GxYsXERUVhW3btmHevHnYs2eP3bFMnToVEydOdPxFEN2mVStg8WKgVCkFFy4IunYFNm/WOyoiynXwIDBhgmVm17Ch4OWXFHTooKBmDaBmDWD1asEbUwU//XTbCu4yKYyJUXDffWpCKAI884xaZELkTj51TyGg3k+Rn4hYLSuofe7yq1ev4plnnsHHH3+M0qVL2x3Dyy+/jPT0dPPj9OnTDrwCIkBRgPHjgeRkNSH86SdB3bpMCIl8QWoq0PFfgvtrm7B0qToQdseOCn5MNWBjioIWLVyzHX9/BTk5QOfOTAjJM3wmKSxdujT8/PysegXPnz9v1RuYq2zZsprt/f39ER4ejqNHj+LEiRPo0KED/P394e/vj4ULF2L16tXw9/fH0aNHNdcbGBiIEiVKWDyI7BUWBqxaBUyerMBgUDB3ruDhh1ldTORr9u0DuvcQVEsQzEsSZGUJHnlEwbcbDfgxVUHHjuofgHfj+HHBP/8I2rcXrFrl2riJbPGZpDAgIACJiYlISUmxWJ6SkoJGjRppPqdhw4ZW7Tds2IB69erBaDSiWrVq+PXXX7Fnzx7zo2PHjmjevDn27NmDChUquO31UNFUsyawcyfQoYOCzExB796CgQOBW7f0joyI7tbhw+r9fpXuFbw/U3DjhqB+fQWrvjZg3z4FPXo4PkvKpElARIRgwwb3xEykSXzI0qVLxWg0yrx58+TAgQMyfPhwKV68uJw4cUJERF566SV59tlnze2PHTsmwcHBMmLECDlw4IDMmzdPjEajrFixwuY2nnvuOfnXv/7lUFzp6en/m/PmigAmPvjQfHTvbpLr103/OzZNUqeO/jHx4c2PHN9/KEXzEVEmR16fYpIrV0zm74mjR03Sf0COBAbpH59LHnofW0X+8bcAkPT0dIfylYL4TE8hAHTt2hXvvvsuJk2ahNq1a+P7779HcnIyYmJiAADnzp2zGLMwLi4OycnJ2LJlC2rXro3Jkyfj/fffR+fOnfV6CVREvfQSsHixguBgBevWCerVA3bv1jsqInKHCxeA8eMFFWMEL48z4fx5QXy8grlzDDh+TMGoUUBIiN5RElnzqXEKvRXHKSRbFAV45x116iwAmDZNHXKGc5dSwQrBqZkTbwAAihUD+vYFxozOmyHl8mXBzA+A998XXL6sc4AFCA5WB/W2UAgOT9+WAaAkp7kj8hVGI7BoUV5COHy4YOxYJoRERc0///xvlpTKgt59TPjjD0GpUgpee1XBqZMK3nlHQcWKekeprXZt4K80BR/OVe66aIZ8B5NCIjcICQHWrgW6d1eQlSXo0UPw3nt6R0VEesrKAubPB6rfJ3jyKRN27xYUL65g+DAFR48oWLhAQc2aekdpqVQpICREQb9+ChYuVBwumCHfwqSQyMUiIoBNm4DHHlNw7ZqgXTtgyRLXbiMg4O6HuiBvIzYeOlNc8LD52nz94RyTCVixAqibKGjZyoRvvxX4+yt49lkF+/YakLxWQdOmTm/G5Xp0B5YvU2A0wjXHhzse5BTeU+gCvKeQcsXGAuvXA1WqqDOUtG2rDkHjSnFxwI4dwH//C/TqBbfPv0ru5qWnYJd8wXrpa3Oa67OPxET1nsMuXQA/P3X9P/8smDZd8NVX6pA2w4cDxYt7NvOJjwOefTZvmzk5gvXrgSc6C/LN9uo9CushZ8U99xQyKXQBJoUEALVqAevWAVFRCk6cELRsqY5f5mp16gC//KKepFeuFHTrpl6WIl/lpadgJoV34L7ErFIlYORIBb17AcWKqds5fFiwPVXwXE8Dbt3SZ58GBFgmhlu3Au07CK5f1yUc2wrrIWeFSaHXYlJIDz8MrF4NhIUp2LdP0Lo1cO6ce7aVPyk0/9X+BLzzr3ayg5eegpkU3oH7e+siIoAhQxQMGaxOhQkUPK2rJ2VnC7ZvB5o287L32MvCcR8mhV6LSWHRpCjAoEFAo0bAk08CRqOC48cFixYBmZnu2265csCgQZZ/tX//PdC+vcawEeQDvPQUzKTwDjyXmBUvrg5n8+r/KQgP946EEFCTwnPngIoxXvYee1k47sOk0GsxKSyaOnUCvvpKMf/1bjIJsrM9t/38l3OyswU7dgCtWwMZGZ6Lge7ES0+tGnmF4q2xeinP7i31DRvQH5gzxztqQ7OyBOfPq72ER4/qHY0X8sgB4p6k0N9layIqYrp0Uf/NvZxjMCgICNAnFn9/BQ88INi8Wb1hnYgKl69XAW3bCoqHACVKABXKq5eYDQb1/PPPP4LTZ9TbVlxZfFaqJFC7dt5fEllZgj//VBPCfBOIUSHBnkIXYE9h0TNsGPDuu95zKQdQewtv3ADuuQfgp9obeOmbwJ5Cp+nRU6glOhoYPFhBv+dhvrR89aog6VNg5kzX9OK1aAF8u1HtoczKEhw7BjRrLkhLc37dhZYP9xR6R180kQ/p1887E8KMDLXghQkhUdHw55/AuHGCChUF/fqbcOCAIDRUwbChCo4cNiBlgzrEjdHo/LZMJsHvvwMPNWFCWJixp9AF2FNYdDz7rDojgcGg4L33BPfeC5Qs6dkYQkKAWrUsL+f8/TfQrBlw8KBnY6E78dJTK3sKneYtPYVaHnsMGDZUQZs2eZeWz58XfDof+Phjx3sPmzYFtmw2YMdOQcuWgitXHHt+keTDPYVMCl2ASWHR0KULsHSpOrDs++8Lhg3TJ478Q9KYb/huCt7w7XW89NTKpNBp3pwU5oqJAfr2VdC3D1CuXN46Nm4UfPSx4Ouv7R/f9IEH1D84r127q1DuWkgI8PbbCrZuFXz2mWe37RQmhUUbk8LCr317YOVKddiZjz8W9O+v32Xa3KTQZFJv9G7aFLzhW1f6n0IVRf8Y9Ke1D7zrNo9cnny3/PzU81e/5w1o3dq69/CTTwRHjngwIAfcey9w+JB6l9uAgSZ8+KHOAXkT4T2FRLp49FF1nlKjUcGiRYIBA/S9b89kUv89ckQdI5EJIRHZkpMDrFoFtGtvQnwlEya/bsLZs4IyZRSMfVHB4UMGbPtBweDBajWzt5o7x4ARI/SOovBjT6ELsKew8GrSRJ26LjhYwZdfCrp29Y65hh94ADh+HLh4Ue9IiD2F3oI9hfZSew8V9O+noFWrvN7D7GzBxo3A4iXq5eWrV/OeExUFhIZ6Ns7YWGD9Osu+q/H/Z8KUKZ6Nwyu5qaeQSaELMCksnB58ENi4EQgNVbB2reDxxznHMGnR/xTKpBBgUugodd9ERQFPPQX06K7gwQfz9tc//wjWrAEWLVZvU/npR8ViwHxPMZnEnLTmmvqmYNw479iLumFS6L2YFBY+tWsDmzYBJUsq+PZbQfv27p26jnyZ/qdQJoUAk0JHWe+be+8FuncHnu6hoGrVvN9fvaoOdeNN3p8pGDbMO/akLpgUei8mhYVL9erAli1ARISCH34QtG4NXL+ud1TkWfqfFj2b6On/en2L/gmSu9+xOnWAHj0UdO+mIDpa/9erJewek1um9bznHsDf33O35yQkAO+8rWDy64Jt2+x8EgtNiNwvPl69ZBwRoWDHDkG7dkwIiajo2b0bGDNGUDHGhBdf9IIbqW8zYaK4JSEMCgLOnVXw048Kypd3/fq1PPgg0KqVgpQNClq08Mw2bWFSSPQ/99wDrF0LREUp2LdP0KoV3HLSISLyFSYTsGo1cOOGPr3JWhczXxxrwsSJ7olHUYCgIAVxcUDqdgXx8W7ZjKaAAOC/yQratvXcNm/nr9+mibyHvz+wfDlQrZqC06fVhPDvv/WOiohIf4cOAWWjTAgKyr9UQViYOpPSY4+qPVylS1teZr5xQ7BnD7BjJ7Bjh2DnTuDyZfu3Gx8P/Jhq2Xc15AUTZs2665dSoJo11X8VRUHZsoKff1LQr5/gxEmgVCmgWjX1cm+JEgreecc1iWlsrLrf/PwUKIpg1dcKunUXfPmlS1bvEN5T6AK8p9D3zZoFDBqk4No1wUMPAXv36h0R6Uv/0yLvKfRm+t9jp/87ZrkPDAZ1qKxHHgEaNlDQqBFQqpT1fvrjD0FqKrDrF8Eff6gJ56lT1mO/Kgrw3nsKXhiimHsLU38EjrpxoO177wUaNtTnvc3KEhiN6rZNJvX1PtdL8PnnNp7AQhPvxaTQtw0eDHzwgTpDyOOPA6tX6x0R6U//0yKTQm/GpLCgfaAoQJUq6gD7jRopaNQQqF5d+zmZmYLDh6EmiYeBQ4cE2dnA55+pvYQiApPJfZMGKP8Ly2DI/b8XvL8iEAEGDBR8/LFWAyaFXotJoe9q2RJITla77V98UTB9ut4Rkfvof6rTnGPYJd8/9r825zen/350nv17wRfmOS6It7xjJUsC9eurSeJ91RVUrar2zgUG6p+EeSOTSU2WqyVovINMCr0Xk0LflJAApKYCYWEKkpIEffvqHRG5l/6nOiaF3oJJobcwGICYGLVXsWpVBVWqKKhaBbjvPrXor6jKyRHcugV06Cj49luNBkwKvReTQt8THg789BNQqZKC778XPPooZysp/PQ/1TEp9BZMCr2Xug9q1AB+3WdAdrZ6GTX/FV1bP+e6U1YjYvv3iqJOAajH5eOcHIGfX950gzdvAq1a32HcQjclhaw+piInIABYuVJNCI8dEzzxBBNCIiJv8ttvwEsvmxAf79kELTAQeK5n3v+zsgR//w20biP4/Xf3bPPZZ4EP56o3NGZnC65fBx59TK3W9jQmhVTkzJ0LPPywgvR0dfq6S5f0joiIiG73n/8Anu7nLFYMeK6nmohmZQnOnweaNhMcPeq+bd68qf6bna0OyN2sueDXX923vTthUkhFyujRQO/eCnJyBF27AgcP6h0RuYf+F8ycrx62fr5jfSbObd/2tjy4b53sJBKxtQJ3XW63bu3Y3nJ232pH62xfm2c/TZ7c2h2OchGcOaMmaKdOeSaaS5fUBPSPPzyzPS2c0YSKjA4dcv/yBIYPB9av1zceIiLyLiYTcO2a4NAhoFFjzySEKSnAjBmCho30TQgBFpq4BAtNvF+NGmqlcUiIgtmzBYMH6x0RuZf+pzX2FLqA23oK3cXZnkLXb98V9P80uYv2/goJAYxGL5/VioUmRHcnOFidwi4kREFKimDYML0jIiIib3Xtmt4R6IeXj6nQe+89ICFBwZ9/Cnr0ALKz9Y6IiIjI+7CnkAq1bt2Af/9bncLu6aeBixf1jojunv4XsdwxzqDmOm1ypEDC2cvHtgZzc2q1bqMVrSuGm9PeC/YXsGi2tLFrRfeSkMJQqOIId0XmpR8SO7CnkAqt+Hjgww/Vn19/HfjuO33jISIi8mZMCqlQMhqBpUuBEiUUbN0qmDRJ74iIiIi8G5NCKpSmTAEeeEDB5cvqfYQ5OXpHRERE5N2YFFKh07o1MGaMek9H797AmTPu29ZLLwH/93/uWz8REZGnsNCECpWyZYEFC9SfZ84UrF7t3u2NGweEhiqIiFCHuuGon0RE5KuYFFKhYTAAn38OlCmjYM8ewZgxntv2kCHqeIj9+qkj4pOzPJdda9YJOj3wNGD/4NOO1Le6oPpYY8XOVio7xhXbsre609a27B9k2i2VtzbKop19H5wfrNs97403ROVZvlvVzKSQCoXQUGD8eOCRRxTcuCEYMQKIjHT/dg3/uwFDURT07i3qZOrPcSxEIiLyPUwKyecFBQHHjgGlS6t/RQUHK9i82fNxGAwKunUTBAcDXbsCt255PgYiIqK7xUIT8nlRUXkJod4MBgUdOgCrV6vJKhERka9gUkg+7/XX9Y7Akp+fglatFDRurHckRERE9uPlY/JpLVoAPXp4Ry9hrpwcwYYNwLZtekfibfS9Xdw107bZWzziyPOdLzRRHCiM0d6es6/LFaxjsD3tm1a89hePuIvmVHtuWKetNTtyHGjuW5fsMNdPteeKY9H3ilW0iI2fXYc9heSzihXLm8bu2jXv+MibTOowOP/6F5CZqXc0RERE9mNPIfms114D7r1XwZkzgvr1AT8/zyeGBw8CxYurf8eaTIIlS9TqY86gQkREvoZJIfmk2rWBUaPUnwcNAs6e1SeO/GMSzpsHDBjAcQqJiMg38fIx+Rw/P+DjjwF/fwVffCFYs0bviIB33xUOXE1ERD6NPYXkc4YOBerVU/D334IXXtA3ltdfB4xGwZQp+sbhXTx7Gd/uggwH7lZ3bGYJ5wpFbBaaaBQN2I7L9QUsLpnlxMkKAduFJva1tVV3odnWoRhs7Vvnil20C1XsL7ZxqCjFgc+II0eSAytwRWO72d6P9vGOu9bdj0kh+ZTYWGDyZPXnMWOAv/7SNRxMm6bv9omIiFyFl4/Jp8yZoxZ2bNkimDdP72iIiIgKDyaF5DN69ABat1aQmanev0dERESuw6SQfEJ4OPDuu+rPkycDhw/rGw8REVFhw6SQfMLbbwMREQr27RNMn653NERERIUPC03I67VoAfTsqcBkEjz/PJCVpXdERZXn6u8cmeLN/qJCF0wn51Bb+yp6bU1NZu/zHW2rWWmsGYMjU+c5TzsCW2vWqvLVWGbj6dpVwtqNtfajI9PvaQdha9/a39aRCmrt59tPu3LXgSn1bAbmwckUxbnzl62jw+7NO7V1z2FPIXk1g0HtJQSAWbOAn3/WNx4iIqLCikkhebVnngHuv18dk/C11/SOhoiIqPBiUkheKyhIHRwaAN54A/j7b33jISIiKsyYFJLXGjoUqFBBwcmTgpkz9Y6GiIiocGOhCXml8HBg3Dj15/HjgZs39Y2naPFkQYkD2/LgNHXOThEH2D9NnQHaE2YrGssNNrdl3dY1RSla3HN8aBaK2Nzj9rZ15Pm2OBeX1nHgyPR9nq1QcNeUerY4sl77tuWKpvazOY+iA5v3rmIV9hSSVxo/HggLU7B7t2DRIr2jISIiKvyYFJLXiY8HBg1Sfx4zxumRBIiIiMgOTArJ60yZAgQEKFi3TvDtt3pHQ0REVDQwKSSv8sADQLdu6kDVY8fqHQ0REVHR4XNJ4ezZsxEXF4egoCAkJiZi69atd2z/3XffITExEUFBQYiPj8fcuXMtfv/xxx+jSZMmKFmyJEqWLIlHH30UP3OEZN1Mm6b+u3AhsG+fvrEQEREVJT5Vfbxs2TIMHz4cs2fPRuPGQJSsVwAAIABJREFUjfHhhx+iTZs2OHDgACpWrGjV/vjx42jbti2ef/55fP7559i2bRsGDRqEiIgIdO7cGQCwZcsWdO/eHY0aNUJQUBCmTZuGli1bYv/+/YiOjvb0SyzS2rUDmjVT8M8/gv/7P72jKWz0nqLORgwOVQQ6VxHsSFwOVe46NE2dVkWxdvWx1nKDRpWxrbZa27Idl5PHhwsqOx2pPjZp9GeIxlxqjlQJO1Jb7q6qaM3p9xT9p9/Tf0o9+9fstuplt63Wgekk8zUVN53TFRHfuY2/fv36qFu3LubMmWNelpCQgE6dOmHq1KlW7ceOHYvVq1fj4MGD5mUDBgzA3r17kZqaqrmNnJwclCxZEh988AF69uxpV1wZGRkICwsDcAVACYdeE6n8/NSewerVFUydKubhaMhVmBQyKbxTXEwKPZkUOjunsy0OtbU9IbFT69V+DY5w7mDyiqTQXfInhZIBIBzp6ekoUcJ1eYfPXD6+desWdu3ahZYtW1osb9myJbZv3675nNTUVKv2rVq1ws6dO5GVlaX5nBs3biArKwulSpWyGcvNmzeRkZFh8SDnPPecmhBevCh48029oyEiIip6fCYpvHjxInJychAZGWmxPDIyEmlpaZrPSUtL02yfnZ2Nixcvaj7npZdeQnR0NB599FGbsUydOhVhYWHmR4UKFRx8NZSfwQBzUckbbwDMsYmIiDzPZ5LCXMpt91eIiNWygtprLQeAadOmYcmSJVi5ciWCgoJsrvPll19Genq6+XH69GlHXgLdplMnoEoVBZcvCz76SO9oiIiIiiafKTQpXbo0/Pz8rHoFz58/b9UbmKts2bKa7f39/REeHm6x/K233sIbb7yBjRs3olatWneMJTAwEIGBgXfxKkhLbi/hrFnA9ev6xuJb9L8d2Plp6hy5T9CRGJycus7mvXuOrNe++wdt3Sfohxy7ltlar617CrW25/Q9hTY4dj+exn2CNu8p1CrIsP/5Wsu11mmrrVasgP33NTo0TZ5D90Xaeh812rrpdjqtKgV3FaVocaRQxV3FGh4rYHFD+D7TUxgQEIDExESkpKRYLE9JSUGjRo00n9OwYUOr9hs2bEC9evVgNBrNy6ZPn47Jkydj3bp1qFevnuuDJ5uaNgUefFCtOJ45U+9oiIiIii6fSQoBYOTIkfjkk0+QlJSEgwcPYsSIETh16hQGDBgAQL2sm79ieMCAATh58iRGjhyJgwcPIikpCfPmzcPo0aPNbaZNm4bx48cjKSkJsbGxSEtLQ1paGq5du+bx11cUvfii+u+nnwIXLugbCxERUVHmM5ePAaBr1664dOkSJk2ahHPnzqFGjRpITk5GTEwMAODcuXM4deqUuX1cXBySk5MxYsQIzJo1C+XKlcP7779vHqMQUAfDvnXrFrp06WKxrddeew0TJkzwyOsqqmrWBNq2VZCTI5gxQ+9oiIiIijafGqfQW3GcwruzcCHw7LMKli0TdOvm/u0VK6ZWOhee+xb1/+jynkLeU3gnHr2n0IHn+9I9hbbHT3RkPEDvHP/Q2W1pc+R1uYv7xz8UyQDE9eMU+lRPIRUeFSsC3burP+dObedOJUoAp04Bhw8Djz0GXLni/m26lu8PPu1Y4mH/4NNOJ4Uag0/bTKg01mF78GnrBE4rIbOV6Pkh2/62isa2bCaQ9u0vWxz5utNO3uwfkFprma11aA5obeP5WnEZHEhWTTbec3uLXWzuA9GK1/mk0P5k04EZUWy11RzM3YGjxoHThGPFNtYcmz3FkS05Xy6jF5+6p5AKj5EjAX9/BRs3Cn75xf3bMxqBsDAF9eop+P57oHRp92+TiIjIlzApJI8rVQr497/Vn//zH89vv1o1YNs2ICrK89smIiLyVrx8TB63aBFQvLiC8+cF7doB7dq5f5vFiuX9bDQqiIsTbN+uDomTrzaJiIioyGKhiQuw0MR+jRsDP/yg3i+RnS0wad+a4xaKoiaEubKyBBcuAA8/DBw96rk47g7vKeQ9hbyn8E7rcPaeQkcKYGwXpfjOPYWOFbVocb6t5vMdKFTxZFGK9vbdpeC4WGhChUKHDnk/+/vrdzMtoCaIERGC1FSgShVfLD4hIiJyHSaF5FGdOukdgSVFAYoXB/z89Ni6l/b+ObQS+3v0nG9rqw9Co61m759zQ8fYWu7skDJaPYIA4K9YLzciy+5t2e4p1BiSRrNi1H6u6P3T6n0zQfuDqb1e+4eO0eqRsx2X9XKDzbbW+9aRnkat98GR4WtstnVyqBytKl3bU8Q5NySM4mxfgc1D2ZHXYB9nq5fVGOxf6ngbxzEpJI+pXRuoWlX9EImI5hyZ7qQogJLvjJOdLbhxA3j0UeDSJc/GQkRE5G2YFJLH9O6t/nvokOC33zy77cBAoF07y4QwIwNo3hzYt8+zsRAREXkjJoXkEQEBwNNPqz8PHQqsX+/Z7YeHAxcvqj9nZQkuXwaaNQN+/92zcRAREXkrJoXkER07AuHhCs6cEaSk6BeHiOCvv9ShaI4d0y8OIiIib8OkkDwi99LxggXw6DA0uXJy1EvGp0+rCeHp056OwJNFJc4Wjzi3XtvtXD/MDGD/XL62h5mxv9BEa+gXR4aU8ddapmgXj2gVlQTglmZbrfUaNGIF7B+SxrGhZ7QLL3IcKjSxLirRer6tto4UteRoTEfnWFGL/UUpWkUtzhaqqG0dKDRxcvo9reW2apPcU8Di0InKRlxOrdXGUDnOn9dt7Rl7uONbhUkhuV25ckCrVurPn36qTwxXrqjzLefkAOfP6xMDERGRN2NSSG7Xsyfg56fg++9F10Giz53Tb9tERETejnMfk9v16aP+q1cvIRERERWMSSG5VePGQOXKCq5dE3zxhd7REBERkS1MCsmtcnsJly8Hrl/XNxYiIiKyjfcUktsULw489ZT6c1KSvrG4h97T1DlfZexQpbKdFaqOVR/bmHpOc5o6W9XD9rV1TUWx/dPUGTWqirUqio02Koq1Ko0DlZuabf011mvrNdhbfWyLViWprcpdrerhHJtttaqPbVUE21epbPv5zsXlSKWyVqWz7Ypi+yudFY2qZtvVw/ZNn2dr+j3NimIb89FpVxTbv15oVvna4khNsf1t3TH9nq19oP3R02+aO/YUktt06QKEhCg49P/snXd4FNX3xt+Zremhht6RDiIdVIo06SICCigWEBVQUVH8KujPgmBXVGyAgCgKooCIFAGpUpTeOwIh1CSSsmXm98eQsuy5ZCZbk5zP8/BEb+7cubPZnTl773nPe1DF+vWhng3DMAzDMDeCg0ImYGStEs6cGdp5MAzDMAyTNxwUMgEhMhLo0EH77wULQjsXhmEYhmHyhoNCJiB06gTY7RKOHlWxd2+oZ8MwDMMwTF6w0IQJCD17aj8XLQrtPPxDYBJ6xXnLOs8nHMCIZZmvfQ2IR6i+Aq8sqq9IKELb1BGCEIHtmxHxCGUnRwlKAJFNnbdQxEa0AbSoxI4Mwbm8RSkioYlucZHgjWBEpOEyIB5xE48jX8cVCUJcBs7lVo1cg3e7yZB9nwFLPV8FLIRQhRKJaONS4hH6XL7a51ECFqFIgxSqiN7fPipFCMSfJMIWUNSbugS94wbg0cQrhYzfkSSge3ftvwtHUMgwDMMwhR8OChm/06wZUKaMhORkFX/+GerZMAzDMAyjBw4KGb+TtXX8+++Ak95ZYxiGYRgmzOCgkPE7hSufkGFuTJ/7YvD7jkqoUcca6qkwDMP4BAtNGL9SqRLQqJEEt1vFkiWhnk1eFGxHEiNuJMZcRkT4JjSRJW9BiNilxIAjCSGokAlRiVkgvKDEI5RDCECLSlrdFoOb6towb015PNjpKPbv0MQgpKhEIB6RZaBt39I4eywD+7elAAAikO7Vt2JF4MKpNK92KzFfSmwDiMU91yNK7qdFHvSjxFhf73bqeNEYVF9qTFG7cF6SAVGKTgGMEVGLUGhCCmsMCE0IoYrY0YQStdCfR0rAYkhoQp7Ld6cVQ+4npKuKEfcUfUeLEAl+PEehfGp8h1cKGb/So4f2c8MG4NKl0M6FYZq1smD63Dis2Fgc5SoE7nbncqmIijFh5h/V0bB5hOHjS5S14ZU5DfHBiiZo2Cae7DPg+Rr48khP9BhZ09fpMgzDkPBKIeNXsoJC3jpmgk1snIQ2bS0AgKbNZPToa8dNtXNucW99FI85071X2cjyNbCQ5zATK5DlK1uhKiosVhkRkTKmL6+OR3scw861OauCFarZ0LFvMcyfchKOTPH3e3uEjHd/uwXj7tqOPStPe/wuJt4CVVXx8Hu3wBppxk+T9wnHYRiGyQ8cFDJ+Iyoqx8WEg0Im2Ez5Kho9+9qEv+/Sy44uvewBObfLpQV6JrMEqwR8uaQqnurrwsbl2lbwoNEJuPeJBLTpFINn7tqLzHR6602SJZgtwKSFN+P1AS5sWnzO8zxOBRarCUNebwh7lAlzJuwOyPUwDFM0kVRVWOmR0UlKSgri4uIAXAEQG+rphIw+fYAFCyQcPqyiZoHY4eKcwsKSUxgXL+Gv3fFIKEvnagWbrNuq26VCUbRgUZazfge4nJ6vkSQBFqvscbyqAjvWXEDiUW11s3bzYqhQKwoWa841LvzwAKY/t51zCgV9/ZJTaKTQdUHKKSTbjOQU0n1DnlNo6G4r6EvmFOo7v2hcY0+bvM+vqilQlNJITk5GbKz/4g5eKWT8Rpcu2s/Fi0M7D6Zo0bGrBR9+ER02ASEASNeS3c0WwtlAAqy2G9/0teNV3NyuJJTb1GyTBvm6S+z1ZC3YIk2YPnKT2MiBYRhGJxwUMn6jdWvt5+rVoZxFAVr9E42rcyXH4HdfQV//29SJVvSoVUFjimLPvlYrMPH9aDz4qCbsSE9TEBFZeLRzWYGlyXzjALLzw9WhXr6CBS9t9GinVmYB/SvMYos5/St6dF8jK4W+9XUKckPp44309W1lVLhSKPlmqSdaKdS7Aik6nlq9E/WViPed2H6PWlHzfn+KVu58ttQT9JUMWe1RJ/NNqSwc9gb/5y8MBYWqqmLNmjVYu3Ytjh8/jrS0NJQqVQqNGzdGx44dUbFixYBMkgl/YmKA+vW1/960KbRzYQo/CWVkzJwXi2YttQf51A//w8UkBaOfjxYeY7dLsFj9738aDsjmwhMMMwwTOnQFhenp6Xj//ffx6aef4uLFi2jUqBHKly+PiIgIHD58GD///DOGDRuGzp07Y/z48WjZsmWg582EGc2aAbIs4dgxFefO5d2fYfJL46ZmzJofi3LlTbh8ScGjgy5j9XIHAODDSVcBACai9mDT5iYs2lAuqHM1gqqqHisUqqoCKqAoOSsCkixBlj37rJ99ED+9uCGoc2UYpnCiKyi86aab0KJFC0ydOhVdunSBxeK9zH7ixAnMmTMHAwYMwEsvvYRhw4b5fbJM+NKqlfZz48Yb92OY/NKrrxUdOlsxcIgdVpuEpHNuzJ2dgYa3WNDwFs97kkiocvG8CyVKhUfWjKpoG2Un96Yg86oLtVqUyPmdquLiqTTsW58E9VpQWO2W4ihTPQZyLqHJqs/3YvaT62DhhEKGYfyALvXx7t27UT9rbzAPHA4HTpw4gZoFQ37qF1h9rIlLuneXMHq0io8/DuVMOKewMOYUVq4iY8eRYtmraYqiwk2La2+IyQSPlbZg4nIqMFu0bV63W4XbqWB8323Yu+IUSpSPwPRj3QBoweKa70/h84f/hOLOeX0HTbwF3UbVhvlaUPjbuzvwwzgtV8MKB8xWGS5HzuvJOYUFMKfQiFI5THMK6TxB3/oGO6eQVg8bOJ74iBnKSdRxF9fUxwmhUR/rDQgBwGq1FqmAkNHIyhgI3kphYIK/QAV6gSkpYyTQE41LlYkRjKszABQFelSJFGFQKHlu/7a/I+LaHLQrkeWcEi+hwO1ScDXFjcUzEnHfmIpIvezEm0N3Qsl1iblt7rqPqIomnROyj3U5FLzeYzUOrzuPeFxFbK6+q6ftx4wn1iNO9Sy0bUcGTNeCyt9fW4sVr61D8Wu/6/DkLej0SnvMvmcuDq04CsDY+4t6YBkJfIwEb8YCNXpcagynRLQJzkW1GzmXS/UtWBWdS2+pHa0vFegZEbBQgR59PBlAEqVnhH1FohSy/AwhNBFY11HjCoNCIrA0EkBSd1GRHR09X9HnkegrXKvL3TcMhCYAULVqVQwePBiDBg1C7dq1AzEnpoBRsyZQooSE9HQVO3YE77x16gAuF3DoUPDOyQSfRreY8eb74bUCL5skRMebseLH8xj4VAXEFLPg4LYUXE5yZPex5/IubnZnGciyFhA60tz4vztX4dCWi9m/T09x4uD6RBzdch5zxv5FnjPjPyckScLicX9g1buefUrWLAFrlBUP/HIfvh3wA/YtPujnK2YYpihg+Lv2qFGjsHTpUtStWxdNmjTBBx98gLNnzwZibkwBISufcNs2wOldQzcgREYCe/fK2LRJQsOGwTknE3wqVTFhzsJiiIwKH9WwoqhQ3MDL9+3D/q3/4eiuVABAw9uK3fA4k1lGeqoLL9+xwiMgBICMVCdeb79YGBACwJI3NmNi3aleAWEWbqcbsknG4B8GoME99QxeFcMwTD5WCseMGYMxY8bg4MGD+Pbbb/HZZ5/hueeeQ/v27TF48GDcf//9gZgnE8aEUmRSrBiwdq2Ejh1VbNkS/PMzgSMyUsKcX+KRUMaE3TucOLTPgcrVvLfy9OZFypJK7spkbaGbLVK204icdbwE1G+WU+ZGcatwu1WMu2cvNiy5BADYseYyajSKRaPbi+PAthS061dGGy+Xy0h0vAUXz6Rjww/HcXOnsri5U9ns31mQs7qYGwvhUmIV9C13cxlA1dTJAHDvrLsxz27CP7ODuHTPMEyBxy82d5s2bcJjjz2GnTt3wp2f7O8CTlEXmvzzD3DzzRL69lWxYEFwzhkZqeLqVW2h2+VSkZkJdO2qYt0638blnMLwySn8+Os43PtABBLPuNGx5UVcOEMvQ5uJ4Ml8XUmaqGgJ3ywuizIVzOhS97DHirYVDjw7uRwGjyyFZ+49jpW/JGfnA0oSsM3RAoAmDnE5VTzbaze2rbqSfXzHPjH4vx8b4/y/GTh/OgO1m8V5CETywtgaqHhcSZYgmzw3f34ZtRh/fbFVx6icU1iocwpJAUvocwrpnEADlnpBzCnUm2coPl4ElVNI98w9rqqmwK2UCS+bu82bN2POnDmYO3cukpOT0a9fP3/NiykglCiB7O3b//0PGDs2OOc1mXI+HGazBElSsXy5hJ49VaxYEZw5MIFjwBA77n0gAm63imGDriDxjJLvm1VsnIxZS8uhUTM7AC0fENd5D5dMMMNskfDe3CoYN/QEVnzvWWxTVVU4MhQ83X0Xdq5P8fjdP6sv4eLZTJSqYEepCtfOESKF8/X0/rgHXA43ts34J9RTYRimAGD4Ppu1bTxnzhwcP34c7du3x1tvvYW+ffsiJiYmEHNkwpg+fXIegE2ahO5BqAWJKpYskXD33SoWLcr7mECsCuovJxPslUK6L1W2RNiXXBU0svrn3ff6FT1AyyN8e4qmq33n1WRsW3sVVtDbqQBgkbzbs7Zki5U0YcayaqhWx5b9u0ikwZTrGm3IgAkuuF0qZBMw6ZvKmByRhiUzziBLRJiW4saYrn/j+LZziLnujWNOTscLty5Hv+froNMj1cImIAS0YLZSnVgcVS/nNBLTo1aS/FE6xunjSiG1+icag2pzwOrT8cK+wnnpK3Xjj9eWKjMjXoHUV+pGvNJIrP4RimZhXx9XIEUlbaidDmH5G9K6TlSCh+hrYKXRkFKZut8K1NbXHxkIDG8fy7KMpk2b4r777sPAgQNRpkyZgEysIFGUt48/+AB48snweQgqigpFAapVU3Hq1I37clAYfkFh42YWfPl9MVSsbMbZf11YsiA9Ow+QOhdAX4MMBRGREjr3jUNMnMkjUNu56T8PlxAZKirWtCOuuEVbRbzG+sXnsWdTMuJKWCDJwJXzTnKrOnew2nV4dZSqFEXOM9ioioKjv+3FLwOnw52Z63XmoND3oFDYtwgFhX7o62tQGIiaiFq7b0Ghsa1mirzHVdUUuNxlQ799vH//ftx0001+mwBTsKlWLdQz8MTtBs6dA/77L9QzYfLDZ7O1gFBVVZQobcKQR8VexjnQOZRmi3YDvd46rkELOmiTrvt23qZHKbS8s2S2o4geJAk5/SVtzKyC2yd3XYI7wzuoFOdgerdfX9Q7i/gqxWGLj4DJoj18VUXFwZ92YPH9M6G46PEZhmGux3BQqCcgvN7Dkym8VKyo/XS7tRW6YKKqgNWa8z5zOrXVwbZtVVy+fIMDmbAkOkZChUpaUCNJEqz0Ig+B/nuN0fuSySQBJt/uZVnnXPTuLmyfs8fr95G4Sh4XRbRTbQDQfUofNBiqCWJUVcWeb7dg6bA5hgJahmEYXUFhnTp18PLLL6Nfv36w3uBOfejQIbz33nuoXLkyXnjhBb9NkglfypfXfn7yCeB7uUr9DzCrFXj11Zylf5dLxZEjQLt2Ks6du8GBTNgy/MkoWCyF98tko84VyKDQX8jXVgm3f7Eey0fPh8R+yAzDGERXUPjJJ5/g+eefxxNPPIHOnTujadOmKFeuHOx2Oy5fvoy9e/di3bp12Lt3L0aOHInHH3880PNmwoC4OKBUKe0h/uKLwFV6EUOAbw+syEjg1Ve1/3a5VOzeDXTsqOLSRdq10heM5AkG04/YiEex2AfXiB+xvpxCKncQoEUlWTl68cVlPD5G2ypWVbqeoFGyFgXDZdeiZGkziuOSV7to9Y9qj0Qa0ROwqpmQJAk73/sNW1/4Hjcqo03lRpG5bJKRkjS+5diJ+opy9xxknp/3goUop1Dv8eK+vuUfGnu9BH8HIt9SXL5GX6kbqh9A5y+KPJllMleRvqdQOYVuSX9JG9lAqRzaUo+eF+n1TApVRHd2/f7NlACFFJ9c651rRoI+vqErKOzQoQO2bNmCDRs2YO7cudnK4/T0dJQsWRKNGzfG/fffj8GDByM+Pj4gE2XCjxo1tJ9nz6oGA0L/sm0b0KWLiuRkozXfmHDhsefiEBMr48RRJ/Zsd5CBqVgAQwSmUFC8tAUNW8UAkppd1BkAUi45PUaSoCIiygSzVfYIIC+eScf5U+nIDZXTl1dOYGQxGxJuKg57nI3s5w82jf0Ox3/ZhtMrdgfsHAzDFH4M5RS2bt0arVu3DtRcmAJGzZraz1B4D7vdwIkTKo4fB7p3D21QyvhGdIyE+0do6rkJT1/Eyl/TyfIzVOkZANmFpnNju9bW+NYYfPxrHVisMkxmLeDrU3kDHBk5gZxdysALMxqiff9yMF27I86asAc/TDzgNS61UifOCdT6Vm6agOc23Ie4MoFTJbvTHRwQMgzjM4a9jxkmi6yVwsOHg3/uzEygalUVnTpxQFjQueeBGETHyDi414GVv6bnfYAB/lmXikc77UVGmoKs6lsms4RnptyE+56p5NFXvrbr9dlz+8iAML9cOa1J4WPLRnmsWDIMw4QbHBQy+SaUK4WApj520otHTAFBkoAHHtOK3n/zaUoevfPHns3/YViH3Ui9ouU02iJk3PVoeTz+VnU88kpVAIAjQ4EkSfhw5B7M//C4X8+fci4NbpcCk1lGdEJ41DBkGIah8MnmjinaeK8UBqjCuqHeoS4+rV9oYkQoQnoUC+ZK5+P5Jh4B9DuSUG1au3cE37aDBdVrWZGa7MbiWRdgv3btVsnh1ddGbBNr7Rlebfbr2s7uSMUzt56HJEuwZeb8buj/qqBEVAamP7Eey6fE4uTuZMRBLOiIItrzFIoowH9nUxFXMQ6VygNnz16i+10HNYcIwbxE9QtzU+yW6rj89xGykDApHhH5+xJOFgETmqgCoYmkT1RCiUREfY0ITXwtii06l7Fi39S4vhXFFglNqL+5sK+RotiEgIUWqhgofk0IVYR9RYWuCaUbLQgRFb/2Pp4Sqmh9jbif5Kq5GkqhCcNQhHqlkCn49BuqCdP+/P0qylfJeVBaiBu7VXADptqtxK3NLGnBYKU6nnacPZ+qDWukCV+O2qp/4gZJOZOCuIpxiC4fBwTuNEJqPXMXGk18AIc+WYxtY2bAL/JuhmEKHRwUMvkidzmaI0dCPBmmQFKhihk9BmoCk+79Y9G9f/AsIq8vsN95WA3YIs34ZNhfUNz+D5hSTmtb4zHl4vw+th5kq+YSU+Px7jBFRWLLiM+gBrvaPMMwYY/hnMJ27dph5syZSE/3b0I4U7DIXY6GLeWY/NDhzsiQ1RC8/rySJKHtfVUwZnbrbJWyP7lyXLPYqdSuht/H1ovqckOSJFS9vz1afvMkJDO9JccwTNHF8EphkyZNMHbsWIwaNQr9+/fHww8/jJYtWwZibkwYk7V1HArlMVM4aNE2ItRT8ECSJbS6uxK+Hb8TyYf8K2n/Z9Y/aPVUa9S6qyEGLnsMjtSc/EiTIAeTyhMU5Q6K8lOziLmpfE5fWUKle1rDFGnFhnvfheKgz88wTNHDcFD47rvvYvLkyVi8eDGmT5+O22+/HTVq1MBDDz2EIUOGICEhIRDzZMKMChW0n8ePh3QaTAGmYRN7qKfgxa9TDiDxcCr8Ha4m7UnC3p/2on6/+qjUtkbIXVYkWUb5bk1x24JxWNdvElzpeQtVGIYp/OQrp9BkMqF3797o3bs3zp8/j88//xwvv/wyXnzxRXTr1g2jR49Ghw4d/D1XJowods1H69IlwF+qY/FjMrQ2daJ5GVMf67epI9XDxDXk5aTh2SZQFPvJpi43VOFpwFNRXDLBjIpVLV65faFkyeS/seClTYgHrTIGaKWwXpu6vVOWoX6/+j7P019IJhllOjREq88ewbah73r9XmiZRqiShapXwipPZNtGjSFU+aqE0piwfRPb3PlmiSdWH+tTQIvt+yhVtH5LPfFrq6+vWOms/+99t1hMAAAgAElEQVRo1mmpBwBu4v1B2eeJLPWodpHNHa0+FqiadVrtiRTA1BzEimJq3AKqPt68eTOmT5+O7777DqVLl8bQoUNx9uxZ9OzZE4899hjeeecdf82TCTOy3AyvXAntPJiCSbPbtXp9B3em4+GO3oWiqfIzopI0EVRJGsk75zkSWltErAUfHe7n8bsF4//Cr29ty3viPnBmwxFkJqfBFhcZ0PMYQpLgOM8fYoZhNAwHhUlJSZg1axamT5+OQ4cOoWfPnvj+++/RpUuX7G/8/fv3R58+fTgoLMRkrRRevsylLRjj1G+qbdD+s/4/pF7xXpl0ECuYTkHunZtYmXQTlngqtJXK69XFc59dh+Uf7cx70n4g9fgF2BpVguJWoLpv/E0/rzxBo0iy7CUuOfn1Euwd+wUgWDFhGKZoYTgorFChAqpXr46HHnoIQ4cORalSpbz6NG/eHM2aNfPLBJnwhFcKCzeSFNhSdjXqavmEh3bT27SBouU9VWCPzrntff3ERmz8MjgBIQAcmbsJJRtVQuqxJBxf+A8AwGKg2LfZgNAkd0uxlnUR16y2x6bU0Q/mY+/Yz3XPnWGYwo/hoHDlypW47bbbbtgnNjYWq1atyvekmPAnZ6UwtPNg/M/QRyPx3PhoDO13GVs2BsZHsEZdGwDgyF7vrd9A8uiXbWCLNGPb4pPYNO8E1s85imBu5jr/07bAL+44hb9emAtAnL9IuZfYVXoLncojVXNFgNXHDUJcs9rZ/3/wzW9x8JVvdM+bYZiigeGgcMKECfjpp58Qn7VUdI2UlBT06dMHf/zxh98mxwQb/UtD8fHaE0dPUKhfRmDEYk70C//b1BmzozPQ14BNnc/iEUFfs+S5SvXo09F45W2twHK1Kip2bswJQigBiQXednSURR2QkxMYGS2jXCUtoT5xzwVEEytlVJ5ghCQKnqj8QUoQkpb9d2jSoxJObTyJYrjsk3jkRn0pm7oos/YamF3pKAZtmT1CpWu+UtdlJV5vAJApW61cye5W1QnZot3uj/5vKs5MnoXoXH3dpI0ZvaVMiw4EfQlRCiU+AWiRg8imjhR0EJZ4lB2eaFxj4hHfxhXNi34NfLPUM9LXH6IW8v0hskzUbb+nX2hCvZcBWlTiNiAUMWKTJxFCFZElnkJ9oRPZ56mBF5oYLl69Zs0aOBzeN6aMjAysXbvWL5O6EZ9++imqVq0Ku92OJk2a5HnONWvWoEmTJrDb7ahWrRqmTp3q1Wf+/PmoW7cubDYb6tatiwULFgRq+oWGrJVC3j4uPDz9vxi88nZ83h19pHQF7SGXctmF1Cuhq5HX541b0eOVVkE9p3wtp09xBrcEjDPpElS3giNj3sfJybOCem6GYQoOulcKd+7U8m5UVcXevXuRmJiY/Tu3242lS5eifPnyosP9wty5c/HUU0/h008/RZs2bfD555/jzjvvxN69e1GpUiWv/seOHUO3bt0wbNgwzJ49G+vXr8fjjz+OUqVK4e677wYAbNy4EQMGDMBrr72Gu+66CwsWLED//v2xbt06tGjRIqDXU5DJWijm7ePCwYtvxmLUWE+buTbt7YiMyvlmqncF8vrVx+z2ayuCVWtrIpOYeBPWOdp69RPlMvqjcI0ke45y54stEBUJLB67wg+j6zi/RQsKVVdwg8LErxfiwoLVcF1KQT7WAhiGKSJIqqovnVyW5Wx1MXVIREQEPv74Yzz00EP+nWEuWrRogVtuuQWfffZZdludOnXQp08fTJw40av/888/j4ULF2Lfvn3ZbSNGjMCOHTuwceNGAMCAAQOQkpKC3377LbtP165dUaxYMXz33Xe65pWSkoK4uDgAVwAEz7/V/+jbeo2IANLStAdLTIySp80dbx+H7/axRXbhtffj8PDIGI92h0OFhd5J8gvhUpswi41fbMPPo5ZmB6SB2j5uMq476r86CEe/WoZtj38KIIDbx4Lgz020B2z7mOobqO1j6njePjbUt1BsH4tqDxrp6+P2MV3TUNTX+16oa/tYTcVVV1UkJycjNtZ/cYfur4zHjh3DkSNHoKoqNm/ejGPHjmX/O336NFJSUgIaEDocDmzbtg2dO3f2aO/cuTM2bNhAHrNx40av/l26dMHWrVvhdDpv2Ec0JgBkZmYiJSXF419RImuV0OVi3+OCzhsfxuOhJ6K92q1WCZIUuH/hRqvhTVClTcWAnydrpVBxsrUcwzDhh+7t48qVKwMAFCUwyY15ceHCBbjdbi8bvYSEBI+t7NwkJiaS/V0uFy5cuICyZcsK+4jGBICJEyfi1VdfzeeVhAO+1RoR5ROGgyOJMZcRfccbWykUuIxIhEuJoK9J56qgaPWPciShypsAQJu2xaEogKkIl6lTXAqSdp1Bxq4DKH5N4GJkpZBaEQToFcAIkxYMWlzpiFOTAQB2QlSjtXsrjSlXGYB+L4pXCokVE2JlRLg6Q6wqCh0rDKwaUY4mTsKlBNDvEuIgnE9E4/rD0USvU4oRRxMj86JWNY30Fc9L/6qii+orWB2m+hpxT3Gr1Oqf6FzefU0G3uPU58nXlUYAkMkVSPrZoOYSsKiC+7+v6AoKFy5ciDvvvBMWiwULFy68Yd9evXr5ZWIirl9lyMsmi+p/fbvRMceNG4cxY8Zk/39KSgoqVgz8KkO4wPmEhYcR9yRi7h/lUKyECWZL+K3gBRrFpeDMlpP4seeXyEwJfHmcrOLRKq8UMgwThugKCvv06YPExESULl0affr0EfaTJAlud2Ci15IlS8JkMnmt4CUlJXmt9GVRpkwZsr/ZbEaJEiVu2Ec0JgDYbDbYbLb8XEahIE6rWIIitmteKDl60Im7bj2NH/4oh9JlzR6B4cUkF66m5v7Gqm8VNa+V1eh4M+JKWJF+1YW0KzkrmPYoE6LirTi49TJmPf+31/HUyhkA2Ijcuwiirx0ZeGDJ/TDbtNueoig4vvY4Ftz1JZxpdK6evzFFaUW7lYzgnI9hGMYIuoLC3FvGodo+tlqtaNKkCZYvX4677roru3358uXo3bs3eUyrVq2waNEij7Zly5ahadOmsFzLom/VqhWWL1+Op59+2qNP69atA3AVhYOsZPxAOl4wwePf4y70ve005v5RHuUr5QSGbz5zDgu/y4n8qfqDVjL4ooO3rG3SQc9XwSOv18TqH8/ho2E5fsODx9fCoJdr4eDWK9i79rzX8aJtWlFNwuuJltI81McXDlzArF6zYcsMXoBmK1cSAJB59mLQzskwDKOXAlWbYMyYMfjqq68wbdo07Nu3D08//TROnjyJESNGANC2de+///7s/iNGjMCJEycwZswY7Nu3D9OmTcPXX3+NZ599NrvPk08+iWXLlmHSpEnYv38/Jk2ahBUrVuCpp54K+vUVFLIWg4tyHlphI/G0G3ffdhrHDjnhdgU22r+aom2dRsV6fieNL62tvqdc8H+QJskSen3WC6askjCKir+n/w1XZnC3ce3ltaAw4/SFoJ6XYRhGD4YdTUaPHo0aNWpg9OjRHu1TpkzB4cOH8cEHH/htctczYMAAXLx4Ef/3f/+Hs2fPon79+liyZEm2CObs2bM4efJkdv+qVatiyZIlePrpp/HJJ5+gXLly+Oijj7JrFAJA69at8f333+Oll17Cyy+/jOrVq2Pu3Llco/AGuK49R82G3z1MOHMhyY172p3Gt7+XQb3GEQE7T+pl7Q0UXcwzybxs9SgAQOJx//ohy2YZ903rjsb96+Q0SkCDgQ1RomYJUrxBubcAtNBDJP6g2qPrVgUAZJ7xXgllGIYJNbrrFGZRvnx5LFy4EE2aNPFo//vvv9GrVy/8+++/fp1gQSC86xT6qPwl2m6/HVi9RsbevSrq18s9vo8qYaHOgcpbMzCuj3UGqRpwACARimKqnqCo3dc6g+Ii0ZQdHR3kUHXvise50KZLHP745Qqcjpxrtwny9Lzbblx375YuZTBh8a04uv0y/tc8J71jypG7UaJiFMbftgSn/zrhdbzII/hGtQNNVhP6fjsIN/Ws67F1nHXbU1wKmQfhH8kNMa7FDEmSsLVCFzjPaVvIou12q+r9t6GU6fSZAIWw2gL011szVhuOPpeLVCrrV6JSimSAVg8bqbtHqmkNKZ2NqI8NqJeJ+oX+UR/7Ni+9dSG1vr7WP9T/PqBrGhrpK3iPk6pm32oiGqlpKOybS9Wsqqm47Kzt9zqFhtd6Ll68eC0A8iQ2NhYXLvCWSFGAVwoLJ9Xr2NC6UzQWfn0Ov/8YOGn5lSQtkCxeLmc10h5tRomK2krhmQP+UzD1+KIfavao4+VkklVdIGs7OZiobgXOpEtBPy/DMExeGH6s16hRA0uXLsXIkSM92n/77TdUq1bNbxNjwpesnEIOCgsPtRvZMWNFVcQVM+PQP6n4e13gqpKfPayNHV/ajjc2dofiVmGL0t5MLoeCFxZ3JFdRRauwN6rrWKx6Ca+AMNS4r6axSothmLDE8GN9zJgxGDlyJM6fP48OHToAAFauXIl33303oPmETPiQtVIYCqGJLAN16gB79wT/3IWVhs0j8PXSqoiMCo7uLD3VhatXHIiKt6JakxIevzNbZdRoXjIo88giaytZVdTABmuSBNkkw53MNkAMw4QnhoPChx56CJmZmXjjjTfw2muvAQCqVKmCzz77zEP5yxReQrlS+PEUGSNGmDBqpBuffRqa8kiFiWa3R+HzxVVgtUqQTcFbUbuUmIGoeDp/KdhIkgRVUaG6FRydtwWAWDxiItpFzjLm69qjG9VEVL1qSPnTuwYjwzBMOJCvx/pjjz2Gxx57DOfPn0dERASio729U5lAEpjVDDok8D6X50ph3nPRKyoRFT3OfY4Iu7ay8/EUEyIjVbz3jmdgaMR6TrfQhBCUAEbFI959qQADAEyEgMRCql5F4hHvdqqeYOvOMfj4pyowWSSYcgWEX/5eE3Q5Un3vOz2hpckSXtWwVEVB8o5j2P7AZABAhMi6jhTW0E4o1wtzqn33NqLqVYPz752IVnPEMdTfC6D/viLREyk0Iay2tL6UqIRIdhcIVci+goR7F5WwT4hPAMBFXK9QYEBY5ZGiBYG9Gm2JZ0A4IRSl+Cro8L+lnpG+mQaOtxqw6jNi60f1tYgERzpt8kTtQvs84n1D2eSJRC2UAEUhPgtaX/2fp9yfSUXw/PCVfK/1nD9/HgcOHIAkSahVqxZKlgzulg8TOkKdU+h2a+eeNNmMyEgXXv8/XjE0SvuecXjvh6qQZXitEJqtoQnYVFXV1MB+QKhON0mQZM/rU90KLm7cj3W9XvfLuUXYa2hWmI7D3spqhmGYcMDwY/3q1asYNWoUZs6cme1uYjKZcP/99+Pjjz9GZGSk3yfJhBdZQWFsLDD3h7wDCPEKoHGaNZc80r4mvGJGVJQb454PjL1iYWXSt1VgMnv7foeStCuZWP7OVgD6VzsButwOVWrHCgeiKpRA7cc6Z7epbgXn/tiJDXdPhDs9sM4mthqVAHBQyDBM+JIvocmaNWuwaNEitGnTBgCwbt06jB49Gs888ww+++wzv0+SCS+yto8tFiBXHfAb4N/AQ75OTfrscyZERgJPjXYHame90LFo9iX0Hx5eq/tH1p3Gsre1oJCqSRgFWqBB96VrF5ZoUi07KFQVBaeW/I0tAydBcQTW2cScUAKm6Eiobjccx4peLVeGYQoGhoPC+fPnY968eWjXrl12W7du3RAREYH+/ftzUFgEyFoplCQJ4bLQ9PgTJpw5rWLyW7xiqIfXHj+FzHQFQ54s7dHuciowhyjfb98fJ/Pu5EeO/7gJax/8DBHOwFvd2a+tEjpPnoXqoHMIGYZhQo3hoDAtLQ0JCQle7aVLl0Zamn/tqZjwJMV/tYX9SrjOK1yZ/MxpONKceHhc+ew2s0XGlLFHcGS390obtSVLuZxQbQBgkzzbK99cAve80RwAcOXMf1jzyQ5D888PjitXkXExFacWbsXGx77SytAEgayt40zeOmYYJowxHBS2atUKEyZMwMyZM2G32wEA6enpePXVV9GqVSu/T5Dxv02dr+e6fBlQFBWyLMHhCP5+rdnsvYU8/iUnPv/UTaozjaiPKaWxMUWxqC+hHhbY1FE5cnQbnQN3ffAFiAO1WeP3QrmahmGv18xuO7ElEfvXeTtuUIrcSGrrVvIOKLW+nu1nV8no8WwDRBSLwK7vtqM4cs5Jb/8KbO5U777UvCKRBhy+gmUVB0F1uRF3LTnViKKYarcRdnSAZxAdW7sCAMB96Ei23V8WlLIcoN9LovxclfikU20AoBDtpNWWQL1MWuIJlMpmSrEpUGFSSlCLUKlMqUMJ9TKhUgZoVbJITUspoJ0ipTKhSjakxiXGpazvROOKrOccsOk63mpEvWxoXnRf6oumkdfLiKUe9Z4R/R2pvmbyPUd/dilVskh1b8Q+L/dnRxFULfAVw0Hhhx9+iK5du6JChQpo1KgRJEnC9u3bYbfb8fvvvwdijkwYcj4JSCgDLPhJRVLStUYD3sUU4gA25/iOHWVUryEht4D02aed+PhD3jbOL99OOo7MdAUj360V1PMqLgXr3l+P5sOaYeu0bUE7rxqE7eLriWhxMwAgc9uuoJ+bYRhGL4aDwvr16+PQoUOYPXs29u/fD1VVMXDgQAwaNAgRERF5D8AUCk6e0oLCOd+qWLz4WtAmiOr0qo9F/XK3fzVNQo2aElRVhaoCox534asvOCD0lXkfnURGmhtdh5RD0sn0vA/wE2ve+hNr3vozaOcLCWYz7E3qAwAyNnHhaoZhwpd8VZqLiIjAsGHD/D0XpgCRdE4FIKFMmeCf22yWoCgqHh7qxJzZXKPQXyz+6jQWf3Wa3E5l8o+9UW3IkRFwX7oC58GjoZ4OwzCMEF1B4cKFC3UP2KtXr3xPhik4JCZqP0t7a44CyvnzKlwuFYPvdWLBfA4ImfAnomVjAED6XzsC663MMAzjI7qCwj59+ugaTJIkuN28lZc3obWpMzYmfXziOe1sZcpKgKTesC81B70Wc9e3v/i8gg/edeJ8Ep1GT1rPGbKpC4x4hPLSpcQjWjul8iWKMUv6xRCi1b/rRQ8ALdLQ2gnxByEqoUQionZR30iVqj0osp6jRCXe12Un2rR2QpijChTUxN9BJPjJ+vtGt2wAAHBu2kKey6zS7y+RQEovQqEJUUeKsr6jBCVaOyFUEYhSqOR6URI99RkxIkqhziWyR6Nt8ujPIyVKEdnvUcIFSkwhsskzYr9Hiz9Efb3fd5T4xCYQhFD2d8G03xMJaJy+ilIM/B2M2OSRfQWiJ0qUQlnqAYCc670YUps7hTZCZYow585pgVqZIK8UAkBSkr/LYTNM4LC1vAUAkLEpeGIahmGY/OBTldqMDM49Kqqcy94+5vCMYUSYEkrBUrUSVEVB5ubtoZ4OwzDMDTEcFLrdbrz22msoX748oqOjcfSoljj98ssv4+uvv/b7BJnwJHulMARCE4YpKNhaaKuEzj0HoabSNn0MwzDhguGg8I033sCMGTMwefJkWK05+/kNGjTAV1995dfJMeFLltCEg0KGEWNr3QQAbx0zDFMwMFySZubMmfjiiy9wxx13YMSIEdntDRs2xP79+/06uYKP74KSQDiS6CkSndOZHjNr+zgmRkJUpIq0NH1CkRu3GXAeEfSlHUnovpSAhG4TiEcIUYkR8QiVgA4IrOMIUYlIPEIJKsTiEUrQYUAoQriJiI+nBCEi9xN94hGAvl5KbGMXiEeov4Pob2Ml/r6UQAIAzKoLUV3aAQDca9bBpjrIvpQzjoZv9w+R0ERV9bmfKAKXEr2OKABgIkQ0IqEJdT5fRSmUSEQ0rkVwLkogIBqXEqC4KIGDQHRACR+E7iekKEUg6CDcRxw63UQA2unE2Ll8E7CIjqeEJmJXF/87pRg53iQQtbiIZ44sFEjl3CsUwT3KVwyvFJ4+fRo1atTwalcUBU4nG70XFVJTgfR07aFFWGEzTJHHVLUyLA3qQHW5kPHbylBPh2EYJk8MB4X16tXD2rVrvdp//PFHNG7c2C+TYgoGp09rPytXZrEJE4ZIEmCiV3+Cgb1nFwCA489NUK8kh2weDMMwejG8fTxhwgQMGTIEp0+fhqIo+Omnn3DgwAHMnDkTixcvDsQcmTBl314VNWpIqFtPwurVXJSXCSNMJtT84n8o1rkFdrR+CJmnzgV9CllBYcYi9oRnGKZgYHilsGfPnpg7dy6WLFkCSZIwfvx47Nu3D4sWLUKnTp0CMUcmTNmzRwsE69UP8UQYJheS2YTas/8PCfd3h7VMSZjiY4I/h/g4WG9vCQDIWMxBIcMwBYN8eR936dIFXbp08fdcmALG7t1aUFi/Hm8fM+GBbLOiwdz/Q4k7W4R0HhFd20Mym+HcvR/uoydCOheGYRi9GA4KH3zwQQwePBgdOnSARNglFW1U5FcxaEgRbGhcSlFsoO8NFMV7d2sD1a0nQYJiSH0sG1Af+6oolgU2dZSCkWwTWNcZURRT7XYDNnW0ophW49LKXd+t5/T2FSmdKfUxZVGntXtfm0htnWVJJ0fYcdPPbyO2XVNIcs4mSIUhneA8c7PQrtBs4D1jUvW9F239ewMAnIuWeCiW6fdnYByjhOpjop1UHxPXKuwrVCp7t4vU1pRVnlvwd9CrVBZZCLqJeYmVyt6ff5fAfo+y1XNJ3gJMkT0apUoWWbFZKfWx4P7jJJTClCWeSOVL2d9RymGAViVTimQj4wbTUs9IX7EFqne7U9BXJv6OeqpruAOkPjYcFF68eBHdu3dHiRIlMHDgQAwePJgFJkWUAwdUuFwqihWTUK4ccPZMqGfEFFVMMVGo9etHiG7RAJIp54GvOJwoNWpw0OcjmbVbq2PR0qCfm2EYJr8YzilcuHAhEhMTMWHCBGzbtg1NmzZF3bp18eabb+L48eMBmCITrjgcwKFDWXmFvGrMhAhZRu0VUxHdvAGk69TGstUCyWwO+j8AUK4kw7WZi1YzDFNwyJf3cXx8PIYPH47Vq1fjxIkTePDBBzFr1iyyfiFTuNmzOyso9MlGm2HyjSTLiKhTzWil94Dj2vI3oLIqn2GYgoNPT3Kn04mtW7fir7/+wvHjx5HAVYyLHNkKZBabMCFCdbmwv8tjUNIzobrovJ1Q4Pzjz1BPgWEYxhD5Uh+vWrUKc+bMwfz58+F2u9G3b18sWrQIHTp08Pf8CiWi9G/fjheMQdjUiY7Xa0eXu33vbi3xtV49iRSPaH31JedTghLAqHhEv02dhUgANxM2ZpS1mdZO2NERbQAtKqEEJQAtvqDFIyJBh//FI1q7PgGLSABDXZfQqk/1bhe9tlY4oG7ciGPtB6Pq8hmQoyOzt3ABwLH/CJT0DIM2jCJu3FcqWRymihWg/ncVrmkzvN5PpMDKH6uJBr6T6RWayIJBKZs7WSBKoYQmikCgSPWVBesWlCiFuk+4JYGlHjFuMEUpouNJoYpK338oSz2rQJRCCVCsqn6hCSVKoazvRGMYscQjLfUMnCsTNrIv1S4SEdJ2lPpsUYXHC95f+RWlhI3QpEKFCrh48SK6dOmCzz//HD179oTdbg/E3JgCwN5r28d160mQJN4tY0JHxj97cbTtIFRdOROm+JjswPDMvaPg2HVA7EtNPHSpLxdA3g+G2L9WARUrIG38G1AvXMjPZTAMw4QMw0Hh+PHjcc8996BYsWKBmA9TwDhyREVmpoqoKAlVqkg4doyjQiZ0ZO45hKO33Ytqf8yEKaGkR2maQGO6uSHMTRtDzcyEY/b34ZbiyDAMkyeG75jDhw/ngJDJxu0G9u/TAsE6nFfIhAGOQ8dx8tZ+cJ06G9Tz2h7SSt84fl4M9eKloJ6bYRjGH7BklPGZLAVyo5v57cSEB64Tp3Hqtntwsm1/OHYdCPwJ7XZYBw0AAGR+PTPw52MYhgkA/BRnfGbTRi3J/Nbb+O3EhA+uM+eQsT44dQKtd/eCHB8H97ETcLHqmGGYAkq+1MeMGH0bqEaUxgb6EkrjvNSSeZ1LaD2Xq+/a1SoAC1q1kWGzuOF0Xt9Xn9JYbBmkz45O1E6pjAGQwgPKjo5SGQMCOzqBdR1t26bfDo5S+fpHUeyrTR11XbT6mFIU24WKYu92kYUg9Xe0qEbeM/pVhSKbOvvD9wMAnNO+gfmacIVS5BpTOhuA+OiL7hyk+piYhMgmTyLVy/QXQkptrVAnA6AS9wRKJSxqp1TRIsWnm7DJMxE2eQCtPhaPS1jtEeO6ifcnALiIvkaUyk6BUtlCqIedhL2aqNKCg1AqOyX680hbxAlU0YQq2Sp5q4TFimLfng1G+hp5DpGWeFL+xGuidpegcoOv8NIO4zP796lISlIRGSmhSTN+SzFFC7lZE5jb3grV5YLzm9mhng7DMEy+4Sc44xfWrta+wdzejv62zTCFFduLzwEAnN9+D/U0G4AzDFNw4aCQ8Qt/rtG2fm5ry0EhU3SQG9SDpVcPqIoCx1vvhno6DMMwPsFBIeMX/ry2UtiqjQlWuvg8wxQ67OOeBQC45i2AcvBQiGfDMAzjGyw08Ssq9IhIDNncEZ2N2XUZt67zbBMJTTzbD+4DzicpKFVaRvPmwMb17lx99SXSilwkKOs5SjxSrISMGjUkbP/LMwHXIhAoULZpVJsx8QgtsqBt6nwTihgTmtDiEWM2dd7ttHiEfr2o11YkHqES3innEUCUQO67eIQit3hEqlkDlnvuAgC43pzkJT4w8tkLBCIBCykgIcQfKilcE9nk6e9LCVUAQCXmILLOVEhRivfxIqGKTNjkKYK/uYkQpSiC95KbGNdNCU0E9nuUKMUlFKV4P77NgnEp4ZWT+IyJRC1WQihCiU8A+t5sEdjUkZ9dSiRmwI7OiKDMV1GK2PlIn1BF3Jd+vTyFJrRIz1d4pZDxG2vXaG/uW9uG5rvGt7+Xxdw/K6HHgJiQnJ8pWtheeAaSLMO1cDGUnbtCPR2GYRif4UBUk5oAACAASURBVKCQ8RtZYpPbQhQUyiZAloH3ZpVFv6GxIZkDUzSQKlWEefC9AADnm5NDPBuGYRj/wEEh4zeyVgpbtA5dXqEkSZBlCW99VRZDnogPzSSYQo917NOQLBa4VqyCsnlLqKfDMAzjFzinkPEbB/YpSDqnoHSCjD83RyE1VWvXm0dlJNeRyjWqUt0zx2XChwmIiJQx/e1EXednGD1IFcrD8tADAAAHrxIyDFOI4KAwgPjuRmJsXL1CEdHxpPOIKOFe4Eiybo0TffvbUK9BeLy1xk4shfjITHzx6r9ev6MEERGSfvEI5UhiRNDhqyOJ+HjKeUQ0L33iEUDg4GJIPOLdTrmRAIJkcx8dSfSIR/LsCwXWSa9DstvhXrMWWL1KKIYImHuJTkR3FGoOlFBEEjmPEH1VSdTXgNDEgICFmptMCU2EYhkD7inEuUR9KVGKm3gvKqp+9xSReMRFfB7cKn3fdRFCDdoRhT6eEnoIP4+E24uvQhGRg4yheZHjCsQfxLhGxCO+CmD0OZrQzyVf4e1jxq+sX0M/5EPJ8JcroGO/4qGeBlMIkG9tA/O9/bW6hE8/G+rpMAzD+BUOChm/svL38AoKFbcKp0NB0ml69YopGFga1UOpQ1sQMXRg6CYhy7B+8A4AwPXVNKjbd4RuLgzDMAEgPPb4mELDiWMKXC4VZrMEl0sFsTNnHJ17bhIAsyWns9ulwuVU8VTv/di58T8/TIQJBdbmjVHq9+8hx8bA0qIp0md8H5J5mB+8H/ItjaFeuQLnS6+EZA4MwzCBhINCxu/MnpaJocPtOHFMwXffZJJ5jXT+oiCPQpC/eD1DRhZHyQTtLe12qcjMUPBotyPYtyHF6CUwYYLtthYouWQOJKsFqovOyQkKcXGwvvEKAMD56uvAhQuhmwvDMEyA4KCQ8TsfvZOOocPtqFxVxrTPM5BySW91eHrrmaqQT4kWuvWPRckEM1wuFelXFTzS+RD2bkuHLR/XwIQeW6e2KPXzDMBihmQyQXU4Ya5eBfYBfTz6mXR+6RAKtFRK3e55vHxbG8ilS0PZtx+uT6YauAqGYZiCAweFfkSCqktxTCmNfbWuE/c1pqz0aiNW6QBadZWlovr3CLDrHycaNLagVx8TfpjmrXylAkCrJFKt6rOjy5r/1WQXnrhjJ07uTkM0xLZrlNKYtqMLnqJY3NfIvAj1sVBR7P0aUK+t1u799zGiKKZs6kSKvMhenRH3wzRAliGZrqkvZQm2O26H7Y7byWMCiapo7y3X089Cdnleh5HPYzAR29xR9wn9yl9qZCqw1sag7POMqI9FM6D6EopkwbwoSzzRvY5SGoss8RTC5k6mjhfeVwn1skB5ayJUyZTSGQBMhNqZ2m0xSaLj9e3WiMYQqnx1zkFogUqMSymHtXP5qh72zSZPfC5KfZz3uE5WHzMFiUXztSCkVz970M55/EAGLiY6MPy2HTiymw6YmPDH3vtOxM2bAZhMOQEhAMkcuu+wkizDvehXKMuWh2wODMMwgYaDQiYgLJynBYW3dbAivlhwqrONHXgEd9fYgpMHA/MNigkOto5ttRVCOXxuT6qiwPnM2FBPg2EYJqCEz12XKVQcPeTGnh1OWCwSuvSOCNp5MzP8IXdmQknKyxPh+ntHaIUl16EeOw718JFQT4NhGCagcE4hEzAWzstAvUYW9OgXgbkzeDuX0Yd6JRlX7uiDuMVzYWnVNHsLWXU6AbcbakqqX88nXMeOj4NktUJ1OOH66BO/npNhGCYc4aDQj3gJTQRPm0CIRwD9NnUioQmZICy026FskzwT8H+b58a412Jw2x12lIp3IOVKznkpUQklKAFE9mq0cCJSoize6O1kWihCCTr0C0KiDfQVj6vvGiJUkf0eYV0nFI/ot6mzUKISItHbIkiSvpE4yatvagaudu2N6J+/g7n97VpgqAKOmXOQMeJJj7563+Nie0fvdvNTo2B+7x2o//0Hx81NgaNHIQvHEH12Cye0TZ6Bvn4RpRBWe0Zs8qi+Als/SoAisrnTa59HWecBgELY5Mmgbe4M2TMS10B+bgSFZenj9YtSZJGAhRJZEMIaI+IRSnwCAGZSwCKy6iPG9dFSzz+ilJx2BwtNmILG0YMu7N/lgNUqoVPvqFBPhylopKfjv5794VyyTFP/mumHo7+R6taB6c3XAQCuZ54Djh4NynkZhmFCDQeFTEBZPE9b9erWLzrEM2EKJA4HrvYbDOe8n4MjPLFYYJk5HZLdDvevS6B8+XXgz8kwDBMmcFDIBJTF87Qt0ls7RqJmXWuIZ8MUSFwuXB30MNKGj0Lma5MCeirzS+M0K7uLF+EaNiKg52IYhgk3OChkAsrh/S78tSYdVquE7/4oj9oNODBk8oGiwPnVDKinzwTsFFLLFjCNex4A4HpsJJCYGLBzMQzDhCMcFDIB59G7z2LXtgyUKGXCtyvKo04jDgyZMKNsWVjnfQ/JbIZ79hwo8+aHekYMwzBBh9XHfkSCep2FnX5FMaWA1PpSqi+RitJbXUWpxowoikWKKcrKTGRT57jiwLAuR/DFb1XRsFkkvltRDiO6HMT+fzxVtpTlGiBQ3hIWdYA/7OQCY11nxD6PUhXTimJagU0piimLOkBgU0fY0QH6FXVCRTH1/hSpJY0oK3Uq9IUKf5sVlvlzIZUrB2X3brgef8Iv1nVkX+rwAMmUKTWu+HShteQD6NdLpAgmr42wDxW9BrRSWdCXmIPofUCppen3Ir0eQ9kFCt+LpFJZ8GwgFcEGPmM6jwcEXuRCqz7q+US0CY6nFcUiVTTRV6BqJi3tdCqSteMDpFTOdT6z4P7vK7xSyASFlCsKHulyDNs3pSGuuBmfL7sJdZtEhnpaDAPzp59AbtkC6qVLcPa5G/jvv1BPiWEYJiQUmKDw8uXLGDJkCOLi4hAXF4chQ4bgypUrNzxGVVW88sorKFeuHCIiItCuXTvs2bMn+/eXLl3CqFGjUKtWLURGRqJSpUoYPXo0kpOTA305YY3FArz/RSxGj/VvGZn/UhQMu/MY/t5wFbHFzJj6+01o1IpL1TChwzTqCZgefACq2w3ngHu5/AzDMEWaAhMU3nfffdi+fTuWLl2KpUuXYvv27RgyZMgNj5k8eTLee+89TJkyBVu2bEGZMmXQqVMnpKZqjghnzpzBmTNn8M4772DXrl2YMWMGli5diocffjgYlxSW2GzANz/FY/DDkXjgUf/b011NVTC823H8vTYVMfFmTF1WC+17x/v9PAyTF3KH9jC/+zYAwP3c81BX/hHiGTEMw4QWSRWVlw8j9u3bh7p162LTpk1o0aIFAGDTpk1o1aoV9u/fj1q1ankdo6oqypUrh6eeegrPP68pCjMzM5GQkIBJkybh0UcfJc/1448/YvDgwbh69SrMZn0plykpKYiLi4MJ5yFJsblnQfYP15zCmEg3Zv8Sj9ZtrTCZJJw87kKL6rQC00hOIZW3FhfpxFtzqqFtj3goiorJT53EL5+eJI/nnELOKbxh33zkFEpVq8K6eQOkEiXg/mYWXA8+dF1fmsKQU6j/eBFUPp4/+lJzMJJT6NvxRvoqor5ETiHVV+SIQrqfCPq6iZxCReB+4ibGcEvefV2C412E/MAl0c9Hqq9TIF9wShair3ebg2gTHe8ALWTMJNodkqivTdfxmZJ3PyPHi/sKxs11PoeagRlp/0NycjJiY2PJ/vmhQAhNNm7ciLi4uOyAEABatmyJuLg4bNiwgQwKjx07hsTERHTu3Dm7zWazoW3bttiwYYMwKMx6gW8UEGZmZiIzM+fBm5KSAsDb5k6crG4k0NNvL0RZCVEPaEpQEh0jYe6S4mjcXAsIAcBqBRo3pB/EZiLYtAiuwUa0W+HCN68ehJJRBe37lcYLH1XGLU1kLPjoOJJOZSD1Uk5gQlnXiYKvaHjng0URbVpf34JCyqZOFOhF6gz0AJGtHxXo0dZ1RgI9ypLOmB2T/kCPSvT2x5chvbaR2W1RUTD/PB9SiRJQNm+BMmKE99iCyMVIUKibAH0tF86VDJ6obqKg0rcJGxlV3FefKEUixCfa8b4FhaLXhrKvo/oK3PuMWaAS6zmK4HopYQspahEcT332hJZ41GdXZHNHjGHEbtVMWuLp/1IqssSjxiC/AAst9QJviRcooUmBCAoTExNRunRpr/bSpUsjUVBLLKs9ISHBoz0hIQEnTpwgj7l48SJee+01YcCYxcSJE/Hqq6/qmXqBIL6YhHnLS6BOAwtM5py7VZlyZiz5p1LQ5tH5gYro/EBFJJ1Mx+Bqq4J2XqYIYbXCPO8HyA3qQz17Fq6+/SBl0sE1wzBMUSOkOYWvvPIKJEm64b+tW7cCACTiq5WqqmR7bq7/veiYlJQUdO/eHXXr1sWECRNuOOa4ceOQnJyc/e/UqVN5XWrYUrKUjIVrSqJOAwvM5hu/lsGiVEU77JHB8bllAotUojjsLz8PqVzZUE8FMJth/n4O5C6doV69Clffe4AzgSuGzTAMU9AI6UrhyJEjMXDgwBv2qVKlCnbu3Ilz5855/e78+fNeK4FZlClTBoC2Yli2bM4DKSkpyeuY1NRUdO3aFdHR0ViwYAEsFjp/IQubzQabjd7zL2jc3tGGWvVufL3BRpIk3P10VXz7xuFQT4XxAalMAmJWLoap9k1QU/+D6/2PQjcZWYZp+jTIfXpDzciAq/ddUP/6K3TzYRiGCUNCGhSWLFkSJUuWzLNfq1atkJycjM2bN6N58+YAgL/++gvJyclo3bo1eUzVqlVRpkwZLF++HI0bNwYAOBwOrFmzBpMm5finpqSkoEuXLrDZbFi4cCHsdrsfrqzgsPSXDPy5MhNt2uXkEoYDdz1ZBQs+Oo60VDq3gglvpArlEbNqCeRKFaAqdO5RMDFP/QSmQfdCdTrhumcA1D84PYFhGOZ6CkROYZ06ddC1a1cMGzYMn3/+OQBg+PDh6NGjh4fIpHbt2pg4cSLuuusuSJKEp556Cm+++SZq1qyJmjVr4s0330RkZCTuu+8+ANoKYefOnZGWlobZs2cjJSUlWzRSqlQpmEzGtjBlKB4J8qIEYVo8IkraNZJIqy9hNbdy2J0GPNzzLKb+UArtu0VClkMfGDoy3IgtbsU9jyfg58l7BeIRkdAklWjzTWgiFo94txsTj/imHhaLR7zbKUEJIHrPCIRM1HuRShSvVhmRq3+HlJAAyWyG6nJBhkI6FVCCEu1cBhLu8+grv/8uTI88DNXthnvQEGDxrx6p/76KR8SfmFAXdhA5dOjsKRAdGDlXMF8DagaGamsIRRr6RSm02poQmggmRrmUGHrfC8fVV/HCmHhEf1+TSj9LKUcTyv1E6MJFPAvF7in6RJeAfvcT0fGUAMYv7ie5hC1mNTC50AUiKASAb7/9FqNHj85WE/fq1QtTpkzx6HPgwAGPwtNjx45Feno6Hn/8cVy+fBktWrTAsmXLEBMTAwDYtm0b/rq2hVSjRg2PsY4dO4YqVaoE8IrCh8xMFcPuTsKU2SXR9e7o7MDwzEknejU6SB5DqWGtAjUsWVKGaMtSGTfvXQEjp7dCz6drY+knByGI/5gwRK5dC5GrlkAqXhyS5drtRVVhe/tNYNLrwZ2MqkJdtAhy374AAPdDj0D9cV5w58AwDFOAKBB1CsOdrDqFViR61CksCCuFubHJTkz6OgF3DYmFJEn497gTnWrsJ/vSJVLolS8yAKTq9l0LCmWThPd3dkO5m2Ix6/l/8Md7W7368kph+K0Uyg3rI+qPXyHFxkLSWeMzkKhuN6Rrq/3uJ0ZC+XQq2a/IrRT6drhgTN93GETrYb70FV0rWZJGeAn6VwqpmoRGyt8oZO1B0bn01zSkxyVqF4pqIhL1C6k6hwBd65A6HqBrHVI1Danah4CoTqGRmoZ0X6rWIVXTUFR70EHVHvSxJuL1fTPVTLyd/oHf6xQWGEcTJvAoCjD2oXOYMzW0Nn+KW8VPb+0FAPR6pg6sEaxELghEfPIepPj4sAgIAeQEhGOfh/IZHRAyDMMwOXBQyHigqsD4kUl4+8XzeOd/50M2j3XfHUfikVTElbaj3fA6IZsHox/HtFkAtLJP4YKyaROUd94N9TQYhmEKBBwUMiRTJ13Gou/pbddg4HapWDBJWy2885lGsNh5tTDccU6fhfQHhgOK4qE4Vh20xV4wUJf8FrJzMwzDFDTCY5+nkOCtPhbYfen0KNb66s/5MpO5ZIRHscAH1yYZyRP0bhfl01F2cFFS3vl8O2f/gwsv1kHJKrG485FKWDvl7+zfifMEvdtFfcn8QSJPUOhR7HOeIC3MoXIFrcTfkfp7a+36LJoAwXvRiALxujbl2zlwpF+F9btZUAFIsgzIMpxTv4Dy43yv48X5fJSimEYCgGLFYJr4BqSaNaGmp0N59f+AvzZD/fNPoSLzRgTEzi7oGMnSo8wBBMOStsP6Xy9RPp2PGZA+IxJbi3MNvaFWWahhhVdFfPZEBg3Uay6yglSIP6abuGAjSmdZ8AahnmUuocc5MS5xPFW5QDveiKWeb5Z4Ro4n7WX9YomXM65J8Bz3FQ4KmbDF7VSwdPLfGPxpO3R4tgU2frkDrkz6Q8iED+6ffkZmn36w/TQXqtkMSBLUQ0egrFrt1dfIQ0jITTVh/uoLSFWrQk1KgrtHL2DLlnzOnmEYpujC28dMWLPhm/24fCoFceVj0PzBBqGeDqMT5bffkdmtN+BwZAs+AoHUsiXM6/7UAsJDh+BqfSvUrd5qdYZhGCZvOChkwhqXQ8HKyZsAAHeMbQmTlXMLCwrKqjXI7NgN7r+2QNm02e/jyw/cD/PKZZBKloSyeQtct94OHD3q9/MwDMMUFTgoZMKezdN3Ifl0KopVjEW/TzrBFkPXcGLCD2XjJmS2uh3Kxk3+GzQyEqbp02Ce/jWkiAgoixbD3eEO4Hzo1PIMwzCFAc4p9CMy3JA8EkGN2O2IElb1F5+2EImnVsm7TSRwoEQSIvFIBCG+EBWUpkQlRgQh0Zn/Yc34pej19T1oMbQh6nSsjNWjvsfRxbt0jRGl0vMiC2gT1ysWj3i3U0WmAcCqEn8bQV+q0DT1PhBaLBkQj1AJ3KJC6pRwyp92dHm2qwDq1YP5h+8g1a0L1e2G8vIEqG+9pUtMEmzxSCAMIwN3BfqFPfSfRtA7iKIU1ag4yet44SR0Q9nJGSleTQt+RK+Bd7ti4I9GfWYU0eeRuC5hX5Ww6hOoePRa7Rmz1BPc6ygBi8gST6dpBGVnBxi1xCP6CgUsOX3lAAlNeKWQKRDsnLkNszt/iUuHLyC2Qhx6LXgU3b57CJFl/FfJnQlvpKEPwLx5oxYQnj4Nd/uOUCa+ZdDglmEYhhHBQSETNOp3Ko/iFaPyffzxVUfwReMPsH7yaiguN27qdwse2PUS6j/cGhCUbWAKAZGRME37WtsujoyE8vsyuBo3hbp2bahnxjAMU6jgoJAJCh2fqItnl9yJUT929GkcV4YLq/63FN+1nIzErSdgi49Ex6n3od+K0Shep4yfZlv0sD73FMwD7wn1NLypXx/mzZsgD30AqtsN94svwX1nd84fZBiGCQAcFDIBp9uzDTH4g9YAxIVYjXJ+x2nMbfMO1jw7H86rmahwe00M/nscWn88BPZSMX45R5FAkmD78G3YJ70G+1uvhno2OdjtkN94HeZtW7Tt4jNneLuYYRgmwHBQyASUAa80QP+JzQMytqqo+OfDVZjV6A0c/nkHZLMJdUfcgf77J6PR2O4w2S0BOW+hQZZh/2IKrCMfDfVMPJA6d4J51w6Yxr0AyWKB8vMvcDVuwtvFDMMwAUZSw8m9voCSkpKCuLg4xOIYJClH+KBHQZTTJlIU67epo5TGlHJWpKalFMUiizdKaXx92z1vt0Lnp2/2aHNlunDpeIpAyZp/ezUAMEVYEVE6Fia7VrJGcbqQeSEF7pSrOPfLBhx48WuP/nqVxiK1tjFFMWVTp189TPUVK4oJ9fH1r5fZDPs3X8I8oJ9mRQdAOfUv0us2Ftoz6lUaG1YUZ2QAbjeQkADT++9Cvneg9qtTp6CMehLqL7+Q4+WMS+Hbba2oZagG8yFgRKksHsO3AYwc72tfldgdEb0GtCWeqC81Lr3OoxBzUIwcTyqd6b5uYgwFdH1Zqq9b8u7rEh5P9JXooirUGKK+TngvKDiJYi0OiV54oI53SHQpNQe826k2AMjMNUa66sSo9PlITk5GbKz/BJdckobxO5IE3DfldrR7tJ7X78w2M0rXKh6UecgWMyLKFgfKFof98V5eQWGRxWqFfe4smHt2yw4IAUCuWAFRqcHP1VO274A69XPIb70JKT4eqtsN9aOPoYyfAPxHlyliGIZh/A9vHzN+p9WQWmRAGErM0RFouepdlOzcJNRTCS0REYhY+CPMPe70CAhDiXxzI5imfgopPh7K1q1wNWsJZcwzHBAyDMMEmfB4KjCFijP7LsOR7oLiprchQ4Gqqih+WwM0XzIRbTZNQUKfNkWyjI25V3eYO3cMqB9xflBTU+Ee9STcLVoD//wT6ukwDMMUSTgoZPzO8S1JeK/zQjjS3XC7PANDRVGv/VO8/qmB+qeqyEy6gmMf/gR3Wgbimt6EJvMmoNmOmUgY3AWSObwCpEDiXrka7j37oLrofMZQ4apTH8qUTwAlfL5IMAzDFDVYaOIHsoQmxaVDkKWccihiIQElHqGFJlZC5GCT9NvU2QkxhUg8QrWLrOv02NSVv6UMhi0bBFu0BfK1wCv51BWsn7wGNpW4LqGdnH5BB9VugRMp63cgbdcRmEvGo9yo/ij3RD+Y47W/Veax00h8byYuzv4VlpRLus9FiUcoizrAmE0dZdOkSzxyg3YPkUixYrAt/xVywwaQzKFPK1b/PQ13xUoebeErHilIt8vArIQH7hUghA8+XoJ4rsETpZCCEAO7FEaEJpQgxMgcxMdT4hH9ohZKUCIagxKPuIWiFqKvQJRCiUpEAhYXIbdwksfTQhMH0ZcSnwACoYlAwJK7b5rqxCMZv/ldaMJBoR/goFDcllCvFEasHAR7vB2y2YSzf5/GVy2mIFrV732sR+kMACXbN0Tle1rj8PhpcF5Izm6n/JtNsVGoOKIXEp4aDEtpTfjivpqO5O9/xaUvf0T6lhxf5UIXFAJATAxsS36B3LJ59layejYRmd173cCVVae3bO5bSpXKMD3yMKQ7u+aonJevgPL5F8CRI1qfU6eAixfzHpeDQoNwUMhBobE5cFCY1V50g8LQLxMwhZpze85j+u1Tcf/K4YgpG7ii0qXvbIoW81+CbLUg8fuVuPznzhv2d6dcReLk6Uj6+DuUeLA3So/oj4i61VD84X4o/nA/pP+zD5e++gFX5vwKEKuHwUIqXgzWHl3g+vEnIN07uM03qanI7NIDtv9v787jo6ru/oF/bmaykwxgSMIS2Qoh4MKihMQlacumIhSpQLFBqER4YQq4oFh9SuxTEXgUKCLaokL1h5QHCjwUEYkFIkjCjmEHIawSwpJMWEISMuf3R8qYYc4J986WDPm8X6+8XubMuXfOmYlzD3fu537/bwkCUlOgmUwQFeUQu7+H+lCqbzmgBQVBG/grBDyfjoCfp9rbbctXwJb5FpBX83tDRES1g9cUktddOnIB8x+Zi+Ljl/DjjtMe33/TgclIXP5Hl64NtJVex/m5i7HvvkE4mDISRf9vJWzXyxDaJQHNP5iMhNMbEDPvHYT06OLxcd+OFhONyI1focGCDxH45GOef4Jr11De71ewffW1Z/YXHw/Tu9NhPn0C5kULEfDzVIjKSthW/B8quj4I21ODuCAkIqrDeKaQfMJ6ohhz4t+FsHn2y6cWw36OrgteAgD715OBTRohuHmUvU+Q4lrFwFu+mi87/iMK/jAThdM+hmVQbzQa1g/B7Vuh4e+eRsPfPY2KM+dw9etvcfWrbFzflgeT7aftRVk5bBc8d0YxoEVzRG5YhYC7W3hsn1JlZSh/6mkEzn0f4vgJ49sHByNg0FMISB+FgJRH7c3i1CnYPv4Utk/nA6c9/w8BIiLyPF5T6AE3rymM1fY5XFMou+asqt35GjVV1QzZ9YOya+RU7bLrBMPcvE7QE331XidY1e48h1BcQ9NRTyJ+7kRA+6mmsqi0QTP5/gS4uHEDF385CJWbNksfl10TaBKKijet70Z49hpoMTHQAqv+3XZ96HDc+N9/OvRzt/KIql3Z9+ZHRWQktN69ENDvCWhP9oPWuOqaTFFZCbHqS4i/zYNYs8YpSeyN6wTV+/XOc9253Lt4z9evrJFr8nTv0yN/SbIqIfr6qfqq5iqvaCIn76u/0oqseomyr/T6Q/37lVdEUVxTKKl+orqmULZfQ9VPJOfQ1BVRZNckGqh+orj+sPo+rokbGHZ9Pa8pJAKAFr//NdrNHO/UXhsLQgDQzGaEjRiCa2fOoDLfhTNu/xEQ3w7hG1ZDa9zYviAUQiB47l8Q9N5UfWNx+dlvUVGBG08PgdixA2jXDgFPPA6t3xPQHnkYWuBPH07ixAnYPv4UYv4C4MwZcPFFROSfuCgkv9RmypjaHoKTsJHDEDZyGCrPnEXFplyUb8xFxaZc3Nh7QNc6yXTfPWiwbhW0yAiHW8VomgY0bgQNjbw4emeishKmWTOgNYmC1r6942MHD8K2ajXw5WqIb7/l/QWJiO4AXBSSX8r/4zz87H8yansYDm4cPQ5TXDOYmjeFachAhAwZCACwFRXjRu42VORuQ+X+w7hx6Ahsx08CNxwvIwj/5+fQLJF1ptqIZjJBeygZACDKyyGyv4VY9SVsX662306m/tWEISK6c3FRSH7p1MzFqCwtQ/yclx3aRWVlrS2qzG1bSdsDGjVE0GO9EPRYL98OyE1CCIhdu1D59jsQWd9Au3y5todERERexEUh+a0fP1oB27UydPh4EoCq9LFmMuHIsD/gytZ99n6qEE+gkN182vHsikxqjQAAIABJREFUXWCrFoj5YjZMjRvZr/GrLzRNQ+WCzyCWr6jtoRARkQ/Ur6OclwWjDAHVUkOqShiyRLGsGgkgTxSHKiqSyFK64TqTv4A8JRxhKFGs6uv8fLIEtKrSivw1qHq9rn62BMdKrWjz+RQI2KAFBMB09jTM+UfsfU2K98Esab+18kjDzHEwRUfZ083+TJSUAEVFEEVFwKUiiHPngPx8iBMngWuS176iAmLJUnvqWJVKvpXefjXvwwgGW9xn5DV0fneMvF+eeLc0nTfNMJJSVv3dylo15Yy98Leo2KWmOT+grn7ielvVA87XDKtfW9kdDeQBQNn7KJuX7XZ3RKgmQFPdlcH5G6QAxd+RbB+ySlGy6lNV28vuNiHvK70zhWR7ADBXu2OFTXinfj0XheT3ipasxQ+lZWi75F37vQo95eonXyBs0BMQQcEu3RzbG2ynz8D21Rrgxg35T2UlUFICceZHiDNnIM78CO3sj0C58yJY78GViIjufFwU0h3BuiobPzyZgajBvXD9wDGP7bd84xZc6jkIjdb8LxAWak8Fi4oKh9uy+FLl6q9QMSZDej9CQHXGg4s/IiKqGReFdMco+WYLyrK+9fh+K7bswKWfD0Djb5YBEQ2qFoZC4PqSFSj9n/cd+gYobkhtknz1oL75dLXtBvSD+bkRqHjtDxAHDgIAbHv2ujQPIiKimnBRSKTDjd17cfGRfmi8bgUCGjUEAgIgCi/gxo7dDv1UVUoguW5Edo1KlZ/O6tl27ETFH/+kXEASERF5CheFHhSCUpiqXcwaosnDI7JQiSo8IgtfqMvBObfXduk6QFVqzzk8EqIo3xcinIM5qkSxLNwTpCg3eGuoRNVmX+jt34eSh3ojcsOXMDVvigDYnBLMqoWerF399a/srKKR0nWSNsW1g0ZCIe6WqXM/quO7r8C9FSu6M77E904oxRuvjerv3lgARboH3a2yUIpQ/r8rezbFKyN/MgP07yBANgch7ysL5an+SSubr97wSdX2zu2VBj7rlPuVhEJkn+E3VKEW4by0MikDMPpLoFYPoFRKtvOE2qkJRuSnbEfzUfJQH5SvXYeKVWtqezhEREQewzOFRAbZTp7C5b6DpLcSICIi8lc8U0hEREREXBQSEREREb8+9qhw7RpM1S6ylVXiAFTBC/fCI6p2b4VHZNVTjFQkkYVtZIESAAiShEpU4ZFASbssPAIAZskd4WVfCavCI8ZuM2MkKKKvrzo8IuN+X/3bG+Gd6EVdrT9T/wIs+sMMvqyKIv1/RzEAVZUQ6X6l28v+f/ZE3EayDwM3o5dlbVRbG7nzqXQIipCF/LWVhU/kz2UkPCKriqL6DA3QnM+XST/DldvL+spfA9l4lYHFavu4obzThXt4ppCIiIiIuCgkIiIiIi4KiYiIiAhcFBIRERERuCgkIiIiIjB97FENcBnmaqkhVRpXlugN90DpuQidfVXPJR+XKlHs3B4qSRQDQIhwbpeVqZOVqAPkieJAVaK4pjJ1t7bLygtJy9EpUmOGStcZSB/rTBAaK1Hnfj5VfwazfiWK6wJfJnfd52bCVtHq9rwMJFxru0xeVV83U82yMnWqmK/eff5nFLcKUJTEk6WPjZTJkyeVFZ+rskSwYg6yUnlGtg+QlclTlsSTHUfkS7PqqeZylrkjIiIiIm/hopCIiIiIuCgkIiIiIi4KiYiIiAgMmnhUBEocAhCqEnHuh0cuG9iv8xhUJfXk5ffkpfr0hkeq2p0DJLJQiSxQAsjDI2YD4ZEAxQW5esvUeSs8YqTMnbyfirfK1Hk+osDwiO/pfc1rP5ACGAkz1HqZPMUgvFEmr6qvc291X9l+Jf30v9xKRkJAsnabpFEV0pC9BjZ1vULn7RUTln0G6w2fVG3vfL7NSABGdcypHkoJUpTNcxfPFBIRERERF4VERERExEUhEREREYGLQiIiIiICF4VEREREBKaPPcoCq0OqVpUolrXLUsaqvqr9ysrXycrUqcrvhQrnpHGIMlHsbpk65zazkJeuk5ejkyeKZSXpZCljQH/S2BOJYvnz608Kei9R7N5zeef5qS6o26Xz9D6jD8vkKXYiS5e6m0iu2oeRMnfyPeh+NllyVlnqz71XUvYZLFRl8qRj0P+e2xT7le9C8nqrEsWyvoqkcoChVPNPx6zAGor/uYNnComIiIiIi0IiIiIi4qKQiIiIiMBFIRERERGBQROPagirQwBDVY5OXrpOf9BEVT5PFiAJlZSpkwVKAHmoJEgRNDFSpi5QUqbOJClTZ1aGR2Sl6+QX2cra3S1TZ+hiYo8EQtwtc+f6Po1iqISAmsIQtc39Mnluz8FAeTUj0TMjgTR5pMS9MnmGXhhvfVBIS+KpusqOGYrXVhoilJSuM1AmT3UcqZTsQ9U3oNoYzCxzR0RERETewkUhEREREXFRSERERER+tCgsKipCWloaLBYLLBYL0tLSUFxcXOM2QghkZmaiWbNmCA0NRWpqKvbt26fs+9hjj0HTNKxYscIbUyAiIiKqs/wmaDJs2DCcPn0aa9asAQA8//zzSEtLw7/+9S/lNtOnT8eMGTOwYMECtG/fHn/+85/Rq1cvHDp0CBEREQ59Z82aBU15h3Z9LLAiBNftv0cogibGqpQ4h0qMVSS57tQmq0ZS1S4Lj6iqlDiHR1QVScyyoIk0EKK/SokqPCLr625FEiOBEHfDIzXvw/V9GsHwCHmK1yqHuM3I/49e+D9S0VF+CFKFR9yrimKkIoo8qKJ/XKrghOzpjPzNyNqF4rmkr5fimC+dg6SfpqiIItutkeOQTRlgMdn/2+yliiZ+sSg8cOAA1qxZg9zcXCQmJgIA5s2bh6SkJBw6dAjx8fFO2wghMGvWLLzxxht46qmnAAB///vfERMTgy+++AKjR4+29/3+++8xY8YMbNu2DU2bNvXNpIiIiIjqEL/4+jgnJwcWi8W+IASAHj16wGKxYPPmzdJt8vPzUVBQgN69e9vbgoODkZKS4rDNtWvX8Jvf/AZz5sxBbGysrvGUlZWhpKTE4YeIiIjIn/nForCgoADR0dFO7dHR0SgoKFBuAwAxMTEO7TExMQ7bvPjii0hOTsaAAQN0j+edd96xX9tosVgQFxene1siIiKiuqhWF4WZmZnQNK3Gn+3btwOA9Ho/IcRtrwO89fHq26xcuRLr1q3DrFmzDI379ddfh9Vqtf+cOnXK0PZEREREdU2tXlOYkZGBoUOH1tinVatWyMvLw7lz55weO3/+vNOZwJtufhVcUFDgcJ1gYWGhfZt169bh6NGjaNiwocO2gwYNwiOPPIINGzZI9x0cHIzg4OAax01ERETkT2p1URgVFYWoqKjb9ktKSoLVasXWrVvRvXt3AMCWLVtgtVqRnJws3aZ169aIjY1FVlYWunTpAgAoLy9HdnY2pk2bBgCYNGkSRo0a5bDdvffei5kzZ+LJJ580PJ+GsCIEQfbfPVK6TugrXQfIy9TJksayEnWAvExdoJCXrpOVpDNJUsZV7fqSxr5MFKva3S9TZ6RQlRHuZTaZKKa6wsjfYt1NKusvPWdoDgY6y0qsqTfXl6Y1VObOUGFAVe05yRx0JpI9IUDxgsnG4HaZPE3+xaw81ax4H6q95/U6fZyQkIC+ffsiPT0df/3rXwFU3ZKmX79+DsnjDh064J133sHAgQOhaRomTJiAKVOmoF27dmjXrh2mTJmCsLAwDBs2DEDV2URZuOTuu+9G69atfTM5IiIiojrALxaFALBw4UKMGzfOnibu378/5syZ49Dn0KFDsFqt9t9fffVVlJaWYuzYsSgqKkJiYiLWrl3rdI9CIiIiovpOE6o7PZJuJSUlsFgsmBYwCiEavz52bufXx/z6mMi4untwqu1bzMuHYOTrYxljY3X/E1B682lpV/03mVbf6FrWV7FfWbBV0tdmYFw2xdfHNkneV7Xf6vu4LGyIv1EEq9WKyMhIaX9X+MUtaYiIiIjIu/zm62N/EIkShCLQ/rvq7J+0dJ3kjCAAhErK1MlK1wFAkM6zgkGSM4KAvEydrEQdAJikZwrlF77Ky9TpP/sn7au6ENfQmT69Zeq8UaLO2H6N4FlBulMYiTL4lmoEegMd3hmC6g5t8gCJvrGqn171GSw7y2bg/KE0aeL+K2aofJ40ACONhMi3l51vE/LjoywwpCnO11U/7pm89CUvzxQSEREREReFRERERMRFIRERERGBi0IiIiIiAheFRERERASmjz0qAiUIq5Y+ViWKwyC796A8URwsaQ9W3GdQljSW3XtQljIGVPcedG4D5PcZVKWPNWn6WJK4MpAoVt97UMa9vp5J8/I+g0Seovf/B9+nlPU9oyyh694ea+4sTyXLyuTpH5c6GS77DHWvuKGQ37xQmtz1WmZdsnmAMu2tvySedG6K/VZ/HU1e+uvmmUIiIiIi4qKQiIiIiLgoJCIiIiJwUUhEREREYNDEoxqIKwiv9pKGolTaT1amLkRSog5Qla6Tl6kLFJJQiaRMnSxQAhgLj+gtXQcogiKSUIk6POKdoIn+7VUYHiGqy+7UMnk17UF3Z2m+Qb5XI5+28nJyRj6DDRSkM/IieOMD18DzByhK9clK4mmKkni2apNQBTPdxTOFRERERMRFIRERERFxUUhERERE4KKQiIiIiMCgiUeF4xrCYbL/LguUAECwJDyiqlIiq0giC5QA8lCJrCKJukqJ/vCIrCKJMmgiDZXIGAmaqHgjVOL+Bb0MlRDVHQaiDD7mXiDDG+ETdbMqOKE/LCPfXn9FFPkUFOOSVA6RV0Sp2oueZzNS1UVVlUVozsdNdWWZn9plx2BP4JlCIiIiIuKikIiIiIi4KCQiIiIicFFIREREROCikIiIiIjA9LFHhaIUYdXSx7KUMQAESZLGqkSxLH2sKlNnkqaPjSSKDZSuc7tMnQxL1xFR7TCWkK0L9Kd09W2talRQJpUlyVsDOzFSJk9/oT3FKBSJYChTyXq5WapPMawAh/9m+piIiIiIvISLQiIiIiLiopCIiIiIuCgkIiIiIjBo4lGhuI7QautsWUgEAIIkoRKzoq8sVKIuU+fcLg+PyC9QlfWVBUoAVXjEvaCIkdJ1ngl06LtQl+ERIqrOQJTBx/SXbXO71J+BCnFGysHpHauKOpQiKwuo6Csdlu+KI6pyLqLaAwyaEBEREZHXcFFIRERERFwUEhEREREXhUREREQELgqJiIiICEwfe1SQKEOwQ/rYuewcAJil5ejkfWVJY1npOkB/mTrPJIq9kR42kl42wlsl8YiIfuK7fKpReu+04G5RUUVnZUk8fTtwt0xe1T70H7OEbL+S46aQJpJVx00PZNardVUdx93FM4VERERExEUhEREREXFRSERERETgopCIiIiIwKCJRwWhAkHV1tmyQAkgD5WowyP6StdVtUsupJVcjGosPKK/r4r7Ze70bW8UQyVE5G11N3wio79EnKE9GCiJZ6Sb3jJ5qlb1sHTu10jYw8MHHCPHYCN4ppCIiIiIuCgkIiIiIi4KiYiIiAhcFBIRERERGDTxqEDcQGC1q0ll1UhU7erwiKQiieIC0wCdoRL1BapGgib6tlfxZaiEgRIiqkuMfCbVjVCKkc9259kptzZS+ENnV3n4RN7b2PsgOz7qPxIqK5BIq6Lcfg7eOq7xTCERERERcVFIRERERFwUEhERERG4KCQiIiIicFFIRERERGD62KMCcAMmh/Sx/kSxKn0sSywp++ouHWekzJ2KN5LGLF1HRFSdusRbXeVeStcbiWTVjtWvob6ksirpLO+rKL8nOcYLxSQ0h/9mmTsiIiIi8hIuComIiIiIi0IiIiIi4qKQiIiIiMCgiUeZUOkQNAlQlaOTBU2EkfCIu0ER/ypdx/AIEZEjI8XRap/qmKPv011VIU6xU7e7ygMk+svkybfWX35P3fWnBxg0ISIiIiKv4aKQiIiIiLgoJCIiIiIuComIiIgIDJp4lAk2h6CJ6kJQWajEWHjEvaCIkTu+eybkoe+CWAZKiIhcZ+QztG6EUvQeG9ysiFK1E92MVC+Rb2+kjpf+466oXurES28gzxQSEREREReFRERERMRFIRERERGBi0IiIiIiAheFRERERAQ/WhQWFRUhLS0NFosFFosFaWlpKC4urnEbIQQyMzPRrFkzhIaGIjU1Ffv27XPql5OTg1/84hcIDw9Hw4YNkZqaitLSUsNjDIDN8UfIfzQIN38g/amKIzn+6O2n7muEfL8y7j8XERG5yr8+gz1wzNJ3aFJSHXf1H2P171fd13Et4A1+sygcNmwYdu/ejTVr1mDNmjXYvXs30tLSatxm+vTpmDFjBubMmYNt27YhNjYWvXr1wuXLl+19cnJy0LdvX/Tu3Rtbt27Ftm3bkJGRgYAAv3lpiIiIiNymCWGo1HStOHDgADp27Ijc3FwkJiYCAHJzc5GUlISDBw8iPj7eaRshBJo1a4YJEybgtddeAwCUlZUhJiYG06ZNw+jRowEAPXr0QK9evfDf//3fLo+vpKQEFosFBQhCpFbtPoWKl9bYvQe9cZ9BI/c5NMLIfZyIiKguqfOLASfORxJDc/DSgcjdI6yeOZQIgSgIWK1WREZG6t737fjF6bCcnBxYLBb7ghCoWsxZLBZs3rxZuk1+fj4KCgrQu3dve1twcDBSUlLs2xQWFmLLli2Ijo5GcnIyYmJikJKSgk2bNtU4nrKyMpSUlDj8EBEREfkzv1gUFhQUIDo62qk9OjoaBQUFym0AICYmxqE9JibG/tixY8cAAJmZmUhPT8eaNWvQtWtX/PKXv8SRI0eU43nnnXfs1zZaLBbExcW5NC8iIiKiuqJWF4WZmZnQNK3Gn+3btwMANE1ymlgIaXt1tz5efRubrarc3OjRozFy5Eh06dIFM2fORHx8PD799FPlPl9//XVYrVb7z6lTp6qeCwKaqPbjdqDEE0ERff08EyqR868LmomI6ifPHBt8Sf/xTTov/dlIQ4wct/Vu76v3oVZrH2dkZGDo0KE19mnVqhXy8vJw7tw5p8fOnz/vdCbwptjYWABVZwybNm1qby8sLLRvc7O9Y8eODtsmJCTg5MmTyjEFBwcjODi4xnETERER+ZNaXRRGRUUhKirqtv2SkpJgtVqxdetWdO/eHQCwZcsWWK1WJCcnS7dp3bo1YmNjkZWVhS5dugAAysvLkZ2djWnTpgGoWnA2a9YMhw4dctj28OHDeOyxx9yZGhEREZFf8YtrChMSEtC3b1+kp6cjNzcXubm5SE9PR79+/RySxx06dMDy5csBVH1tPGHCBEyZMgXLly/H3r17MWLECISFhWHYsGH2PhMnTsTs2bOxdOlS/PDDD/iv//ovHDx4EM8991ytzJWIiIioNtTqmUIjFi5ciHHjxtnTxP3798ecOXMc+hw6dAhWq9X++6uvvorS0lKMHTsWRUVFSExMxNq1axEREWHvM2HCBFy/fh0vvvgiLl26hPvvvx9ZWVlo27atbyZGREREVAf4xX0K67qb9yk8h0BEVrsc1Ni9B43c2ci9vp65YJX3JCQiqg/8a5HggfsBeuGgVXMU0/g+vHWfQr85U+gPbqaFq/+u6ufcpuKtvnpx8UdEVJ/JPtvr7kLRyDFLcSpFtgs3D3CqzYWL4/XW8dYvrikkIiIiIu/iopCIiIiIuCgkIiIiIi4KiYiIiAgMmniUO0ET9T5ljKSP9W9vBEMlRET1l5FjgL+FUmQBFG+ET1S7UL9eQlcvd/BMIRERERFxUUhEREREXBQSEREREbgoJCIiIiIwaOJR+oMmMt6qHMKKJEREVHvU1TzqKn3VwYQwcNT0cFdWNCEiIiIir+GikIiIiIi4KCQiIiIiLgqJiIiICFwUEhERERGYPvYo5/SxSu0mjZkyJiKi2masxFvdoy5Zq7NMnrxrreKZQiIiIiLiopCIiIiIuCgkIiIiInBRSERERERg0MSjNNx6zaiRMndGsHQdERHdefw9fFJFViZPUeBWNrlaPHDzTCERERERcVFIRERERFwUEhERERG4KCQiIiIicFFIRERERGD62MMcY0SeCRAxaUxERPWXkWNb3U0q678biRCKGfvgIM8zhURERETERSERERERcVFIREREROA1hR4h/nNL8pKq3+ztvr7Gj9cUEhFRfVZ3rynUT6hmUa255GaTtCSK67go9ICLFy8CAFrV7jCIiIioHrl48SIsFovH9sdFoQc0btwYAHDy5EmPvjl1VUlJCeLi4nDq1ClERkbW9nC8rr7NF6h/c+Z873z1bc6c753NarXi7rvvtq8/PIWLQg8ICKi6NNNisdSLP8abIiMjOd87XH2bM+d756tvc+Z872w31x8e259H90ZEREREfomLQiIiIiKCKTMzM7O2B3EnMJlMSE1NhdlcP76R53zvfPVtzpzvna++zZnzvbN5Y76a8HSemYiIiIj8Dr8+JiIiIiIuComIiIiIi0IiIiIiAheFRERERAQuCl329ttvIzk5GWFhYWjYsOFt+1dUVOC1117Dvffei/DwcDRr1gzDhw/Hjz/+6IPRus/ofIGqmoyZmZlo1qwZQkNDkZqain379nl5pJ5RVFSEtLQ0WCwWWCwWpKWlobi4uMZtrly5goyMDLRo0QKhoaFISEjAhx9+6KMRu8eV+QLAgQMH0L9/f1gsFkRERKBHjx44efKkD0bsPlfnfNPo0aOhaRpmzZrlxVF6jtH5+ttn1ty5c9G6dWuEhISgW7du2LhxY439s7Oz0a1bN4SEhKBNmzb46KOPfDRSzzEy52XLlqFXr15o0qQJIiMjkZSUhK+//tqHo3Wf0ff4pu+++w5msxmdO3f28gg9y+h8y8rK8MYbb6Bly5YIDg5G27Zt8emnnxp7UkEu+eMf/yhmzJghXnrpJWGxWG7bv7i4WPTs2VMsXrxYHDx4UOTk5IjExETRrVs3H4zWfUbnK4QQU6dOFREREeKf//yn2LNnjxgyZIho2rSpKCkp8fJo3de3b19xzz33iM2bN4vNmzeLe+65R/Tr16/GbUaNGiXatm0r1q9fL/Lz88Vf//pXYTKZxIoVK3w0ate5Mt8ffvhBNG7cWEycOFHs3LlTHD16VKxatUqcO3fOR6N2jytzvmn58uXi/vvvF82aNRMzZ8708kg9w+h8/ekz6x//+IcIDAwU8+bNE/v37xfjx48X4eHh4sSJE9L+x44dE2FhYWL8+PFi//79Yt68eSIwMFAsXbrUxyN3ndE5jx8/XkybNk1s3bpVHD58WLz++usiMDBQ7Ny508cjd43R+d5UXFws2rRpI3r37i3uv/9+H43Wfa7Mt3///iIxMVFkZWWJ/Px8sWXLFvHdd98Zel4uCt00f/583YukW23dulUAuO0fdV2id742m03ExsaKqVOn2tuuX78uLBaL+Oijj7w5RLft379fABC5ubn2tpycHAFAHDx4ULldp06dxJ/+9CeHtq5du4o333zTa2P1BFfnO2TIEPHb3/7WF0P0OFfnLIQQp0+fFs2bNxd79+4VLVu29ItFoTvzra6ufmZ1795djBkzxqGtQ4cOYtKkSdL+r776qujQoYND2+jRo0WPHj28NkZPMzpnmY4dO4q33nrL00PzClfnO2TIEPHmm2+KyZMn+9Wi0Oh8v/rqK2GxWMTFixfdel5+fVyLrFYrNE3T/XWsP8nPz0dBQQF69+5tbwsODkZKSgo2b95ciyO7vZycHFgsFiQmJtrbevToAYvFUuPYH374YaxcuRJnzpyBEALr16/H4cOH0adPH18M22WuzNdms+HLL79E+/bt0adPH0RHRyMxMRErVqzw1bDd4up7bLPZkJaWhokTJ6JTp06+GKpHuDrfW9XFz6zy8nLs2LHD4bMGAHr37q2cW05OjlP/Pn36YPv27aioqPDaWD3FlTnfymaz4fLly2jcuLE3huhRrs53/vz5OHr0KCZPnuztIXqUK/NduXIlHnjgAUyfPh3NmzdH+/bt8corr6C0tNTQc3NRWEuuX7+OSZMmYdiwYXdk8e6CggIAQExMjEN7TEyM/bG6qqCgANHR0U7t0dHRNY599uzZ6NixI1q0aIGgoCD07dsXc+fOxcMPP+zN4brNlfkWFhbiypUrmDp1Kvr27Yu1a9di4MCBeOqpp5Cdne3tIbvN1fd42rRpMJvNGDdunDeH53Guzre6uvqZdeHCBVRWVhr6rCkoKJD2v3HjBi5cuOC1sXqKK3O+1XvvvYerV69i8ODB3hiiR7ky3yNHjmDSpElYuHCh31U4cWW+x44dw6ZNm7B3714sX74cs2bNwtKlS/HCCy8Yem4uCqvJzMyEpmk1/mzfvt3t56moqMDQoUNhs9kwd+5cD4zcNb6Yr6ZpDr8LIZzafMXIfGVjvN3YZ8+ejdzcXKxcuRI7duzAe++9h7Fjx+Kbb77x2pxq4s352mw2AMCAAQPw4osvonPnzpg0aRL69etXqxfse3POO3bswF/+8hcsWLCg1v6Gb+Xtv+mb6spnVk2MftbI+sva6zJXP18XLVqEzMxMLF68WPqPhbpK73wrKysxbNgwvPXWW2jfvr2vhudxRt5fm80GTdOwcOFCdO/eHY8//jhmzJiBBQsWGDpb6F/LZy/LyMjA0KFDa+zTqlUrt56joqICgwcPRn5+PtatW1er/+L25nxjY2MBVP2LvGnTpvb2wsJCp3/9+Ire+ebl5eHcuXNOj50/f1459tLSUvzhD3/A8uXL8cQTTwAA7rvvPuzevRvvvvsuevbs6f4EDPLmfKOiomA2m9GxY0eH9oSEBGzatMn1QbvJm3PeuHEjCgsLcffdd9vbKisr8fLLL2PWrFk4fvy4W2N3hTfne1Nd+sySiYqKgslkcjqDUtNnTWxsrLS/2WzGXXfd5bWxeoorc75p8eLFeO6557BkyZJa+VxyhdH5Xr58Gdu3b8euXbuQkZEBoGrRJISA2WwhW+RkAAAKnUlEQVTG2rVr8Ytf/MInY3eFK+9v06ZN0bx5c1gsFntbQkIChBA4ffo02rVrp+u5uSisJioqClFRUV7b/80P1yNHjmD9+vW1/uHjzfm2bt0asbGxyMrKQpcuXQBUXSeRnZ2NadOmeeU5b0fvfJOSkmC1WrF161Z0794dALBlyxZYrVYkJydLt6moqEBFRQUCAhxPvptMJvtZNV/z5nyDgoLw4IMP4tChQw7thw8fRsuWLd0fvIu8Oee0tDSng2ifPn2QlpaGkSNHuj94F3hzvkDd+8ySCQoKQrdu3ZCVlYWBAwfa27OysjBgwADpNklJSfjXv/7l0LZ27Vo88MADCAwM9Op4PcGVOQNVZwh/97vfYdGiRfZ/vPoDo/ONjIzEnj17HNrmzp2LdevWYenSpWjdurXXx+wOV97fhx56CEuWLMGVK1fQoEEDAFWfxwEBAWjRooX+J3crplKPnThxQuzatUu89dZbokGDBmLXrl1i165d4vLly/Y+8fHxYtmyZUIIISoqKkT//v1FixYtxO7du8XZs2ftP2VlZbU1Dd2MzleIqlvSWCwWsWzZMrFnzx7xm9/8xq9uSXPfffeJnJwckZOTI+69916n23fcOt+UlBTRqVMnsX79enHs2DExf/58ERISIubOnevr4RvmynyXLVsmAgMDxd/+9jdx5MgR8f777wuTySQ2btzo6+G7xJU538pf0sdCGJ+vP31m3bx9xyeffCL2798vJkyYIMLDw8Xx48eFEEJMmjRJpKWl2fvfvCXNiy++KPbv3y8++eQTv70ljd45f/HFF8JsNosPPvjA4b0sLi6urSkYYnS+t/K39LHR+V6+fFm0aNFC/PrXvxb79u0T2dnZol27dmLUqFGGnpeLQhc9++yzAoDTz/r16+19AIj58+cLIYTIz8+X9r91m7rK6HyFqLotzeTJk0VsbKwIDg4Wjz76qNizZ4/vB++CixcvimeeeUZERESIiIgI8cwzz4iioiKHPrfO9+zZs2LEiBGiWbNmIiQkRMTHx4v33ntP2Gw2H4/eOFfmK4QQn3zyifjZz34mQkJCxP333+8X92S8ydU5V+dPi0Kj8/W3z6wPPvhAtGzZUgQFBYmuXbuK7Oxs+2PPPvusSElJcei/YcMG0aVLFxEUFCRatWolPvzwQx+P2H1G5pySkiJ9L5999lnfD9xFRt/j6vxtUSiE8fkeOHBA9OzZU4SGhooWLVqIl156SVy7ds3Qc2pC/OfqWiIiIiKqt5g+JiIiIiIuComIiIiIi0IiIiIiAheFRERERAQuComIiIgIXBQSEREREbgoJCIiIiJwUUhERERE4KKQiMgjNmzYAE3TUFxcXGO/Vq1aYdasWT4ZU1paGqZMmaK7/yuvvIJx48Z5cUREVJexogkRkQeUl5fj0qVLiImJgaZpWLBgASZMmOC0SDx//jzCw8MRFhbm1fHk5eUhNTUVJ06cQEREhK5tCgsL0bZtW+Tl5aF169ZeHR8R1T08U0hE5AFBQUGIjY2Fpmk19mvSpInXF4QAMGfOHDz99NO6F4QAEB0djd69e+Ojjz7y4siIqK7iopCI6oXU1FRkZGQgIyMDDRs2xF133YU333wT1b8sKSoqwvDhw9GoUSOEhYXhsccew5EjR+yPnzhxAk8++SQaNWqE8PBwdOrUCatXrwbg+PXxhg0bMHLkSFitVmiaBk3TkJmZCcD56+OTJ09iwIABaNCgASIjIzF48GCcO3fO/nhmZiY6d+6Mzz//HK1atYLFYsHQoUNx+fJl5VxtNhuWLFmC/v3729sOHjyIsLAwfPHFF/a2ZcuWISQkBHv27LG39e/fH4sWLXLhFSYif8dFIRHVG3//+99hNpuxZcsWzJ49GzNnzsTHH39sf3zEiBHYvn07Vq5ciZycHAgh8Pjjj6OiogIA8MILL6CsrAzffvst9uzZg2nTpqFBgwZOz5OcnIxZs2YhMjISZ8+exdmzZ/HKK6849RNC4Fe/+hUuXbqE7OxsZGVl4ejRoxgyZIhDv6NHj2LFihVYtWoVVq1ahezsbEydOlU5z7y8PBQXF+OBBx6wt3Xo0AHvvvsuxo4dixMnTuDHH39Eeno6pk6dinvvvdfer3v37jh16hROnDih/4UlojuCubYHQETkK3FxcZg5cyY0TUN8fDz27NmDmTNnIj09HUeOHMHKlSvx3XffITk5GQCwcOFCxMXFYcWKFXj66adx8uRJDBo0yL6IatOmjfR5goKCYLFYoGkaYmNjleP55ptvkJeXh/z8fMTFxQEAPv/8c3Tq1Anbtm3Dgw8+CKDqzN+CBQvsXwWnpaXh3//+N95++23pfo8fPw6TyYTo6GiH9rFjx2L16tVIS0tDUFAQunXrhvHjxzv0ad68uX0fLVu2rPH1JKI7C88UElG90aNHD4dr/pKSknDkyBFUVlbiwIEDMJvNSExMtD9+1113IT4+HgcOHAAAjBs3Dn/+85/x0EMPYfLkycjLy3NrPAcOHEBcXJx9QQgAHTt2RMOGDe3PCVR95Vz92sCmTZuisLBQud/S0lIEBwdLr2/89NNPkZeXh507d2LBggVOfUJDQwEA165dc3leROSfuCgkIgKguhGDEMK+cBo1ahSOHTuGtLQ07NmzBw888ADef/99t55TtnC7tT0wMNDhcU3TYLPZlPuNiorCtWvXUF5e7vTY999/j6tXr+Lq1asoKChwevzSpUsAqgIxRFS/cFFIRPVGbm6u0+/t2rWDyWRCx44dcePGDWzZssX++MWLF3H48GEkJCTY2+Li4jBmzBgsW7YML7/8MubNmyd9rqCgIFRWVtY4no4dO+LkyZM4deqUvW3//v2wWq0Oz2lU586d7fuq7tKlSxgxYgTeeOMNjBw5Es888wxKS0sd+uzduxeBgYHo1KmTy89PRP6Ji0IiqjdOnTqFl156CYcOHcKiRYvw/vvv26+pa9euHQYMGID09HRs2rQJ33//PX7729+iefPmGDBgAABgwoQJ+Prrr5Gfn4+dO3di3bp1ysVbq1atcOXKFfz73//GhQsXpF/H9uzZE/fddx+eeeYZ7Ny5E1u3bsXw4cORkpLiEBIxqkmTJujatSs2bdrk0D5mzBjExcXhzTffxIwZMyCEcArAbNy4EY888oj9a2Qiqj+4KCSiemP48OEoLS1F9+7d8cILL+D3v/89nn/+efvj8+fPR7du3dCvXz8kJSVBCIHVq1fbv76trKzECy+8gISEBPTt2xfx8fGYO3eu9LmSk5MxZswYDBkyBE2aNMH06dOd+miahhUrVqBRo0Z49NFH0bNnT7Rp0waLFy92e67PP/88Fi5caP/9s88+w+rVq/H555/DbDYjLCwMCxcuxMcff2y/rQ4ALFq0COnp6W4/PxH5H1Y0IaJ6ITU1FZ07d/ZZibnadv36dcTHx+Mf//gHkpKSdG3z5ZdfYuLEicjLy4PZzJtTENU3PFNIRHQHCgkJwWeffYYLFy7o3ubq1auYP38+F4RE9RT/zyciukOlpKQY6j948GAvjYSI/AG/PiYiIiIifn1MRERERFwUEhERERG4KCQiIiIicFFIREREROCikIiIiIjARSERERERgYtCIiIiIgIXhUREREQE4P8DvpEed2HU6nkAAAAASUVORK5CYII=\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "tags": [] + } + } + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "BLbFIhgyiWhg" + }, + "source": [ + "# Implement generate_session_mountain_car(), training loop, etc.\n", + "\n", + "def generate_session_mountain_car(env, agent, t_max=10000):\n", + " \n", + " \n", + " return states, actions, total_reward\n", + "\n", + "" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "T6MnwXZ5iWhg" + }, + "source": [ + "### Submit to Coursera" + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "ZAmKPGLOiWhg" + }, + "source": [ + "from submit import submit_mountain_car\n", + "submit_mountain_car(generate_session_mountain_car, agent, 'your.email@example.com', 'YourAssignmentToken')" + ], + "execution_count": null, + "outputs": [] + } + ] +} \ No newline at end of file diff --git a/week1_intro/gym_interface.ipynb b/week1_intro/gym_interface.ipynb new file mode 100644 index 000000000..4656f3ca8 --- /dev/null +++ b/week1_intro/gym_interface.ipynb @@ -0,0 +1,249 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "language_info": { + "name": "python", + "pygments_lexer": "ipython3" + }, + "colab": { + "name": "gym_interface.ipynb", + "provenance": [], + "collapsed_sections": [] + } + }, + "cells": [ + { + "cell_type": "code", + "metadata": { + "id": "XCiI86ScJcep" + }, + "source": [ + "import sys, os\n", + "if 'google.colab' in sys.modules and not os.path.exists('.setup_complete'):\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/master/setup_colab.sh -O- | bash\n", + "\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/coursera/grading.py -O ../grading.py\n", + " !wget -q https://raw.githubusercontent.com/yandexdataschool/Practical_RL/coursera/week1_intro/submit.py\n", + "\n", + " !touch .setup_complete\n", + "\n", + "# This code creates a virtual display for drawing game images.\n", + "# It has no effect if your machine has a monitor.\n", + "if type(os.environ.get(\"DISPLAY\")) is not str or len(os.environ.get(\"DISPLAY\")) == 0:\n", + " !bash ../xvfb start\n", + " os.environ['DISPLAY'] = ':1'" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "metadata": { + "id": "ggYvjt2RJcey" + }, + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "%matplotlib inline" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "TY5b59AkJcez" + }, + "source": [ + "### OpenAI Gym\n", + "\n", + "We're gonna spend several next weeks learning algorithms that solve decision processes. So we need a few interesting decision problems to test our algorithms.\n", + "\n", + "That's where OpenAI Gym comes into play. It's a Python library that wraps many classical decision problems, including robot control, videogames and board games.\n", + "\n", + "So here's how it works:" + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "-DnbE2wYJcez" + }, + "source": [ + "import gym\n", + "\n", + "env = gym.make(\"MountainCar-v0\")\n", + "env.reset()\n", + "\n", + "plt.imshow(env.render('rgb_array'))\n", + "print(\"Observation space:\", env.observation_space)\n", + "print(\"Action space:\", env.action_space)" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "rbq7DyYYJce0" + }, + "source": [ + "Note: if you're running this on your local machine, you'll see a window popping up with the image above. Don't close it, just alt-tab away." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "2EShsU_PJce0" + }, + "source": [ + "### Gym interface\n", + "\n", + "The three main methods of this environment are:\n", + "* `reset()`: resets an environment to the initial state, _return first observation_\n", + "* `render()`: shows the current environment state (a more colorful version :) )\n", + "* `step(a)`: commits an action `a` and returns `(new_observation, reward, is_done, info)`\n", + " * `new_observation`: an observation right after committing the action `a`\n", + " * `reward`: a number which represents your reward for committing action `a`\n", + " * `is_done`: True if the MDP has just finished, False if it is still in progress\n", + " * `info`: some auxiliary stuff about what just happened. For now, ignore it." + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "CzeQku6LJce0" + }, + "source": [ + "obs0 = env.reset()\n", + "print(\"initial observation code:\", obs0)\n", + "\n", + "# Note: in MountainCar, an observation is just two numbers: car position and velocity" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "metadata": { + "id": "1IZVB7MQJce1" + }, + "source": [ + "print(\"taking action 2 (right)\")\n", + "new_obs, reward, is_done, _ = env.step(2)\n", + "\n", + "print(\"new observation code:\", new_obs)\n", + "print(\"reward:\", reward)\n", + "print(\"is game over?:\", is_done)\n", + "\n", + "# Note: as you can see, the car has moved slightly to the right (around 0.0005)" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "BxHtJWTlJce1" + }, + "source": [ + "### Play with it\n", + "\n", + "Below is the code that drives the car to the right. However, if you simply use the default policy, the car won't reach the flag at the far right due to the gravity.\n", + "\n", + "__Your task__ is to fix it. Find a strategy that reaches the flag. \n", + "\n", + "You are not required to build any sophisticated algorithms for now, and you definitely don't need to know any reinforcement learning for this. Feel free to hard-code :)" + ] + }, + { + "cell_type": "code", + "metadata": { + "id": "NKG5uQ4lJce1" + }, + "source": [ + "from IPython import display\n", + "\n", + "# Create env manually to set time limit. Please don't change this.\n", + "TIME_LIMIT = 250\n", + "env = gym.wrappers.TimeLimit(\n", + " gym.envs.classic_control.MountainCarEnv(),\n", + " max_episode_steps=TIME_LIMIT + 1,\n", + ")\n", + "actions = {'left': 0, 'stop': 1, 'right': 2}" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "metadata": { + "id": "deNJs8IeJce2" + }, + "source": [ + "def policy(obs, t):\n", + " # Write the code for your policy here. You can use the observation\n", + " # (a tuple of the position and the velocity), the current time step, or both,\n", + " # if you want.\n", + " position, velocity = obs\n", + " \n", + " # This is an example policy. You can try running it, but it won't work.\n", + " # Your goal is to fix that. You don't need anything sophisticated here,\n", + " # and you can hard-code any policy that seems to work.\n", + " # Hint: think how you would make a swing go faster and faster.\n", + " return actions['right']" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "metadata": { + "id": "bomTLtJIJce2" + }, + "source": [ + "plt.figure(figsize=(4, 3))\n", + "display.clear_output(wait=True)\n", + "\n", + "obs = env.reset()\n", + "for t in range(TIME_LIMIT):\n", + " plt.gca().clear()\n", + " \n", + " action = policy(obs, t) # Call your policy\n", + " obs, reward, done, _ = env.step(action) # Pass the action chosen by the policy to the environment\n", + " \n", + " # We won't do anything with reward here because MountainCar is a very simple environment,\n", + " # and reward is a constant -1. Therefore, your goal is to end the episode as quickly as possible.\n", + "\n", + " # Draw game image on display.\n", + " plt.imshow(env.render('rgb_array'))\n", + " \n", + " display.display(plt.gcf())\n", + " display.clear_output(wait=True)\n", + "\n", + " if done:\n", + " print(\"Well done!\")\n", + " break\n", + "else:\n", + " print(\"Time limit exceeded. Try again.\")\n", + "\n", + "display.clear_output(wait=True)" + ], + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "metadata": { + "id": "o6sDccFIJce3" + }, + "source": [ + "from submit import submit_interface\n", + "submit_interface(policy, 'your.email@example.com', 'YourAssignmentToken')" + ], + "execution_count": null, + "outputs": [] + } + ] +} \ No newline at end of file