{ "cells": [ { "cell_type": "markdown", "metadata": { "id": "nwaAZRu1NTiI" }, "source": [ "# Q-learning \n", "\n", "#### This version implements q-learning using a custom enviroment \n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "DDf1gLC2NTiK" }, "outputs": [], "source": [ "# !pip install -r ./requirements.txt\n", "!pip install stable_baselines3[extra]\n", "!pip install yfinance\n", "!pip install talib-binary\n", "!pip install huggingface_sb3\n" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "id": "LNXxxKojNTiL" }, "outputs": [], "source": [ "import gym\n", "from gym import spaces\n", "from gym.utils import seeding\n", "\n", "import talib as ta\n", "from tqdm.notebook import tqdm\n", "\n", "import yfinance as yf\n", "import pandas as pd\n", "import numpy as np\n", "from matplotlib import pyplot as plt\n" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "id": "dmAuEhZZNTiL" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "3015\n", "1866\n" ] }, { "data": { "text/plain": [ "1664" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Get data\n", "eth_usd = yf.Ticker(\"ETH-USD\")\n", "eth = eth_usd.history(period=\"max\")\n", "\n", "btc_usd = yf.Ticker(\"BTC-USD\")\n", "btc = btc_usd.history(period=\"max\")\n", "print(len(btc))\n", "print(len(eth))\n", "\n", "btc_train = eth[-3015:-200]\n", "# btc_test = eth[-200:]\n", "eth_train = eth[-1864:-200]\n", "eth_test = eth[-200:]\n", "# len(eth_train)" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "def initialize_q_table(state_space, action_space):\n", " Qtable = np.zeros((state_space, action_space))\n", " return Qtable" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [], "source": [ "# Policy\n", "\n", "def greedy_policy(Qtable, state):\n", " # Exploitation: take the action with the highest state, action value\n", " # if we dont have a state with values return DO_NOTHING \n", " if abs(np.max(Qtable[state])) > 0:\n", " action = np.argmax(Qtable[state])\n", " else:\n", " action = 2\n", " # action = np.argmax(Qtable[state])\n", " return action\n", "\n", "\n", "def epsilon_greedy_policy(Qtable, state, epsilon, env):\n", " # Randomly generate a number between 0 and 1\n", " random_num = np.random.uniform(size=1)\n", " # if random_num > greater than epsilon --> exploitation\n", " if random_num > epsilon:\n", " # Take the action with the highest value given a state\n", " # np.argmax can be useful here\n", " action = greedy_policy(Qtable, state)\n", " # else --> exploration\n", " else:\n", " # action = np.random.random_integers(4,size=1)[0]\n", " action = env.action_space.sample()\n", " \n", " return action" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "id": "wlC-EdLENTiN" }, "outputs": [], "source": [ "def train(n_training_episodes, min_epsilon, max_epsilon, decay_rate, env, max_steps, Qtable, learning_rate, gamma):\n", " state_history = []\n", " \n", " for episode in range(n_training_episodes):\n", " # Reduce epsilon (because we need less and less exploration)\n", " epsilon = min_epsilon + (max_epsilon - min_epsilon)*np.exp(-decay_rate*episode)\n", " # Reset the environment\n", " state = env.reset()\n", " step = 0\n", " done = False\n", "\n", " # repeat\n", " for step in range(max_steps):\n", " # Choose the action At using epsilon greedy policy\n", " action = epsilon_greedy_policy(Qtable, state, epsilon, env)\n", "\n", " # Take action At and observe Rt+1 and St+1\n", " # Take the action (a) and observe the outcome state(s') and reward (r)\n", " new_state, reward, done, info = env.step(action)\n", "\n", " # Update Q(s,a):= Q(s,a) + lr [R(s,a) + gamma * max Q(s',a') - Q(s,a)]\n", " Qtable[state][action] = Qtable[state][action] + learning_rate * (reward + gamma * ( np.max(Qtable[new_state]) ) - Qtable[state][action] )\n", "\n", " # If done, finish the episode\n", " if done:\n", " break\n", " \n", " # Our next state is the new state\n", " state = new_state\n", "\n", " state_history.append(state) \n", "\n", " return Qtable, state_history" ] }, { "cell_type": "code", "execution_count": 66, "metadata": {}, "outputs": [], "source": [ "from enum import Enum\n", "class Actions(Enum):\n", " Sell = 0\n", " Buy = 1\n", " Do_nothing = 2\n", "\n", "class CustTradingEnv(gym.Env):\n", "\n", " def __init__(self, df, max_steps=0):\n", " self.seed()\n", " self.df = df\n", " self.prices, self.signal_features = self._process_data()\n", "\n", " # spaces\n", " self.action_space = spaces.Discrete(3)\n", " self.observation_space = spaces.Box(low=0, high=1999, shape=(1,) , dtype=np.float64)\n", "\n", " # episode\n", " self._start_tick = 0\n", " self._end_tick = 0\n", " self._done = None\n", " self._current_tick = None\n", " self._last_trade_tick = None\n", " self._position = None\n", " self._position_history = None\n", " self._total_reward = None\n", " self._total_profit = None\n", " self._first_rendering = None\n", " self.history = None\n", " self._max_steps = max_steps\n", " self._start_episode_tick = None\n", " self._trade_history = None\n", "\n", " def reset(self):\n", " self._done = False\n", " self._start_episode_tick = np.random.randint(1,len(self.df)- self._max_steps )\n", " self._end_tick = self._start_episode_tick + self._max_steps\n", " self._current_tick = self._start_episode_tick\n", " self._last_trade_tick = self._current_tick - 1\n", " self._position = 0\n", " self._position_history = []\n", " # self._position_history = (self.window_size * [None]) + [self._position]\n", " self._total_reward = 0.\n", " self._total_profit = 0.\n", " self._trade_history = []\n", " self.history = {}\n", " return self._get_observation()\n", "\n", "\n", " def step(self, action):\n", " self._done = False\n", " self._current_tick += 1\n", "\n", " if self._current_tick == self._end_tick:\n", " self._done = True\n", "\n", " step_reward = self._calculate_reward(action)\n", " self._total_reward += step_reward\n", "\n", " observation = self._get_observation()\n", " info = dict(\n", " total_reward = self._total_reward,\n", " total_profit = self._total_profit,\n", " position = self._position,\n", " action = action\n", " )\n", " self._update_history(info)\n", "\n", " return observation, step_reward, self._done, info\n", "\n", " def seed(self, seed=None):\n", " self.np_random, seed = seeding.np_random(seed)\n", " return [seed]\n", " \n", " def _get_observation(self):\n", " return self.signal_features[self._current_tick]\n", "\n", " def _update_history(self, info):\n", " if not self.history:\n", " self.history = {key: [] for key in info.keys()}\n", "\n", " for key, value in info.items():\n", " self.history[key].append(value)\n", "\n", "\n", " def render(self, mode='human'):\n", " window_ticks = np.arange(len(self._position_history))\n", " prices = self.prices[self._start_episode_tick:self._end_tick+1]\n", " plt.plot(prices)\n", "\n", " open_buy = []\n", " close_buy = []\n", " open_sell = []\n", " close_sell = []\n", " do_nothing = []\n", "\n", " for i, tick in enumerate(window_ticks):\n", " if self._position_history[i] == 1:\n", " open_buy.append(tick)\n", " elif self._position_history[i] == 2 :\n", " close_buy.append(tick)\n", " elif self._position_history[i] == 3 :\n", " open_sell.append(tick)\n", " elif self._position_history[i] == 4 :\n", " close_sell.append(tick)\n", " elif self._position_history[i] == 0 :\n", " do_nothing.append(tick)\n", "\n", " plt.plot(open_buy, prices[open_buy], 'go', marker=\"^\")\n", " plt.plot(close_buy, prices[close_buy], 'go', marker=\"v\")\n", " plt.plot(open_sell, prices[open_sell], 'ro', marker=\"v\")\n", " plt.plot(close_sell, prices[close_sell], 'ro', marker=\"^\")\n", " \n", " plt.plot(do_nothing, prices[do_nothing], 'yo')\n", "\n", " plt.suptitle(\n", " \"Total Reward: %.6f\" % self._total_reward + ' ~ ' +\n", " \"Total Profit: %.6f\" % self._total_profit\n", " )\n", "\n", " def _calculate_reward(self, action):\n", " step_reward = 0\n", "\n", " current_price = self.prices[self._current_tick]\n", " last_price = self.prices[self._current_tick - 1]\n", " price_diff = current_price - last_price\n", "\n", " penalty = -1 * last_price * 0.01\n", " # OPEN BUY - 1\n", " if action == Actions.Buy.value and self._position == 0:\n", " self._position = 1\n", " step_reward += price_diff\n", " self._last_trade_tick = self._current_tick - 1\n", " self._position_history.append(1)\n", "\n", " elif action == Actions.Buy.value and self._position > 0:\n", " step_reward += penalty\n", " self._position_history.append(-1)\n", " # CLOSE SELL - 4\n", " elif action == Actions.Buy.value and self._position < 0:\n", " self._position = 0\n", " step_reward += -1 * (self.prices[self._current_tick -1] - self.prices[self._last_trade_tick]) \n", " self._total_profit += step_reward\n", " self._position_history.append(4)\n", " self._trade_history.append(step_reward)\n", "\n", " # OPEN SELL - 3\n", " elif action == Actions.Sell.value and self._position == 0:\n", " self._position = -1\n", " step_reward += -1 * price_diff\n", " self._last_trade_tick = self._current_tick - 1\n", " self._position_history.append(3)\n", " # CLOSE BUY - 2\n", " elif action == Actions.Sell.value and self._position > 0:\n", " self._position = 0\n", " step_reward += self.prices[self._current_tick -1] - self.prices[self._last_trade_tick] \n", " self._total_profit += step_reward\n", " self._position_history.append(2)\n", " self._trade_history.append(step_reward)\n", " elif action == Actions.Sell.value and self._position < 0:\n", " step_reward += penalty\n", " self._position_history.append(-1)\n", "\n", " # DO NOTHING - 0\n", " elif action == Actions.Do_nothing.value and self._position > 0:\n", " step_reward += price_diff\n", " self._position_history.append(0)\n", " elif action == Actions.Do_nothing.value and self._position < 0:\n", " step_reward += -1 * price_diff\n", " self._position_history.append(0)\n", " elif action == Actions.Do_nothing.value and self._position == 0:\n", " step_reward += -1 * abs(price_diff)\n", " self._position_history.append(0)\n", "\n", " return step_reward\n", "\n", " def _do_bin(self,df):\n", " df = pd.cut(df,bins=[0,10,20,30,40,50,60,70,80,90,100],labels=False, include_lowest=True)\n", " return df\n", " # Our state will be encode with 4 features MFI and Stochastic(only D line), ADX and DI+DI-\n", " # the values of each feature will be binned in 10 bins, ex:\n", " # MFI goes from 0-100, if we get 25 will put on the second bin \n", " # DI+DI- if DI+ is over DI- set (1 otherwise 0) \n", " # \n", " # that will give a state space of 10(MFI) * 10(STOCH) * 10(ADX) * 2(DI) = 2000 states\n", " # encoded as bins of DI MFI STOCH ADX = 1 45.2 25.4 90.1 , binned = 1 4 2 9 state = 1429 \n", " def _process_data(self):\n", " timeperiod = 14\n", " self.df = self.df.copy()\n", " \n", " self.df['mfi_r'] = ta.MFI(self.df['High'], self.df['Low'], self.df['Close'],self.df['Volume'], timeperiod=timeperiod)\n", " _, self.df['stock_d_r'] = ta.STOCH(self.df['High'], self.df['Low'], self.df['Close'], fastk_period=5, slowk_period=3, slowk_matype=0, slowd_period=3, slowd_matype=0)\n", " self.df['adx_r'] = ta.ADX(self.df['High'], self.df['Low'], self.df['Close'], timeperiod=timeperiod)\n", " self.df['p_di'] = ta.PLUS_DI(self.df['High'], self.df['Low'], self.df['Close'], timeperiod=timeperiod)\n", " self.df['m_di'] = ta.MINUS_DI(self.df['High'], self.df['Low'], self.df['Close'], timeperiod=timeperiod)\n", " self.df['di'] = np.where( self.df['p_di'] > self.df['m_di'], 1, 0)\n", "\n", " self.df = self.df.dropna()\n", " self.df['mfi'] = self._do_bin(self.df['mfi_r'])\n", " self.df['stock_d'] = self._do_bin(self.df['stock_d_r'])\n", " self.df['adx'] = self._do_bin(self.df['adx_r'])\n", " self.df['state'] = self.df['di']*1000+ self.df['mfi']*100 + self.df['stock_d']*10 + self.df['adx']\n", "\n", " prices = self.df.loc[:, 'Close'].to_numpy()\n", " # print(self.df.head(30))\n", "\n", " signal_features = self.df.loc[:, 'state'].to_numpy()\n", "\n", " return prices, signal_features" ] }, { "cell_type": "code", "execution_count": 67, "metadata": {}, "outputs": [], "source": [ "# Training parameters\n", "n_training_episodes = 20000 # Total training episodes\n", "learning_rate = 0.2 # Learning rate\n", "\n", "# Environment parameters\n", "max_steps = 20 # Max steps per episode\n", "gamma = 0.95 # Discounting rate\n", "\n", "# Exploration parameters\n", "max_epsilon = 1.0 # Exploration probability at start\n", "# max_epsilon = 1.0 # Exploration probability at start\n", "min_epsilon = 0.05 # Minimum exploration probability \n", "# min_epsilon = 0.05 # Minimum exploration probability \n", "decay_rate = 0.0005 # Exponential decay rate for exploration prob" ] }, { "cell_type": "code", "execution_count": 68, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "REhmfLkYNTiN", "outputId": "cf676f6d-83df-43f5-89fe-3258e0041d9d" }, "outputs": [], "source": [ "# create env\n", "env = CustTradingEnv(df=eth_train, max_steps=max_steps)" ] }, { "cell_type": "code", "execution_count": 69, "metadata": {}, "outputs": [], "source": [ "# create q-table\n", "\n", "action_space = env.action_space.n # buy sell do_nothing\n", "state_space = 2000\n", "\n", "Qtable_trading = initialize_q_table(state_space, action_space)" ] }, { "cell_type": "code", "execution_count": 70, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "997" ] }, "execution_count": 70, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# train with ETH\n", "Qtable_trading, state_history = train(n_training_episodes, min_epsilon, max_epsilon, \n", " decay_rate, env, max_steps, Qtable_trading, learning_rate, gamma )\n", "len(np.where( Qtable_trading > 0 )[0])\n", "\n", "# #train with BTC\n", "# env = CustTradingEnv(df=btc_train, max_steps=max_steps)\n", "# Qtable_trading, state_history = train(n_training_episodes, min_epsilon, max_epsilon, \n", "# decay_rate, env, max_steps, Qtable_trading, learning_rate, gamma )\n", "# len(np.where( Qtable_trading > 0 )[0])" ] }, { "cell_type": "code", "execution_count": 71, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 417 }, "id": "FIQ0OqtsO3jo", "outputId": "f98374ad-c7de-4dc4-80b1-25f018ad96eb" }, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAA20AAAGQCAYAAAA9YYgkAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4yLjIsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+WH4yJAAAgAElEQVR4nOzdd3xW5f3/8fcnGwJhhrCSQNigzDAcDAFX1boRBWsdX+uoo7v9dtj+rG2/HbZV66oDLYhgtY7WOtiiyAgosjdJGAkQIISQeV+/P85BYwwQQsK5k7yejwcPk3Pu8b6TA97v+7rOdcw5JwAAAABAeIoIOgAAAAAA4NgobQAAAAAQxihtAAAAABDGKG0AAAAAEMYobQAAAAAQxihtAAAAABDGKG0AGgwzc2bWPegcNWVmY8wsO+gcqHun83dtZleaWZaZFZjZIDNbbWZjTsdzAwBqB6UNQJ3z3ywe/RMysyMVvp90jPvU6ptaM5tnZkX+c+41s9fMrENtPX44MLP/VvpZl5jZZxX2n21mS8zskJmtNLNzT/B4g81sgf9YOWZ2X4V92yr9Ht+rsO88M/vMzA6Y2T4z+5eZdaqwf4KZfWRmhWY2r4rnHWhmGf7+DDMbWGHfTf62fDPLNrPfm1nUKfzYKj/3yAqv6bD/QUDFn2nKMe73SzObWos5nP/8BWa2w8weNrPIGj7cHyV92znXzDm3wjnXzzk3r7Zym9lEM1tvZgfNLNfMXjCzhAr7Cyr9KTezR4/xWGZmv/Zf80H/722/Cvv7mNkcf98mM7uy0v3Hmdk6/9iZa2apFfbdb2Zb/GNnp5n9ueKxY2Zd/PsU+o8xvsK+Mf6/XRVfx02n8nMDgJNBaQNQ5/w3i82cc80kZUq6rMK2aacxyrf9DN0lNZP3ZjYQtVk0jnLOXVzpZ/2RpFf852st6U1Jf5DUUtLvJb1lZq2Oka+tpHckPSWpjbyf2XuVblbx93hBhe1rJF3onGspqaOkjZKeqLA/T9JfJP2uiueNkfSGpKmSWkl6QdIb/nZJairpfkltJQ2XNE7S90/0s6ku59wHFX5+R8tCywqvM7O2nqsaBvg5xkm6QdL/VL5BNY+jVEmrazlbRR9KOsc510JSmqQoSb8+urPSMZkk6Yj847IK10q6RdJISa0lLZL0D+nz1/qGpH/7+26XNNXMevr720p6TdLP/f3LJM2o8NhvSRrsnEuQdIakAZLurbB/uqQV8o73n0r6p5klVti/s+Jrcc69UP0fEQCcGkobgMCYWayZ/cX/1Hun/3WsmcVL+q+kjhU+1e5oZsPMbJE/grPLzB6r8Ga+2pxzByS9LqniCE5vM3vfzPL8UYMJ/vau/vNF+N8/Y2a5Fe431czu97++2czWmjeStcXMvlXhdmP8kaEfmdluSc+bWRMzm2Jm+81sjaShNftJfpWZdZH3xvcf/qazJeU4515xzpU756ZK2iPpqmM8xHclveucm+acK3bOHXLOra3OczvncpxzOytsKpdX+o7un+Wcmylp51fuLI2R96b/L/7zPiLJJI317/uEX6xKnHM7JE2TdE51cp0q/xh80z9GNpnZ//jbL5L0v5Ku84/VT/3txzweToZzbp2kDySd4Y8GOTO71cwyJc0xswgz+5mZbfdHul40sxb+36UCSZGSPjWzzX6ubWY2/li5a5Avyzm3t8KmL/2+K7lGUq7/eqrSVdJC59wW51y5vPLe19/XW96HAH/2j+E58grjjf7+qySt9o/xIkm/lDTAzHr7OTf7f/cl75gKHc3pF7/Bkh5wzh1xzr0q6TNJV1f35wAAdYnSBiBIP5U0Ql55GiBpmKSfOecOS7pYX/5ke6e8N4PfkTfKcpa8EYi7TvZJzayNvDd4m/zv4yW9L+klSe0kXS/pcTPr55zbKilf0iD/7iMlFZhZH//7UZLm+1/nSrpUUoKkmyX92cwGV3jq9vJGAFLljRI8IKmb/+dCSV+abmVmj5vZ4yf7+nzfkPSBn1/y3qRapduYvBGHqoyQlGfeNMZcM3vLvjo1cJqZ7TGz98xsQKXsKWZ2QN6oyvfljexVRz9JK51zrsK2lfpi1KuyUarhKJKZVf55nMh0SdnyisM1kn5jZuOcc+9I+o2kGf6xevRncaLjobo5+8o77lZU2DxaUh95x803/T/nyRvpaibpMb/0NvNvP8A5163i4x4rt5n92Mz+fZIZzzWzg5IOySs6fznGTW+S9GKl329FL0vqbmY9zSzav/07R5+mqqfWF8dwP0mfF0//35HNqnDsmNkNZpYvaa+8f3OeqnDfLc65QxUe+1N9+bhrZ9404a3mTa2MP8ZrAIBaR2kDEKRJkv6fcy7XObdH0q/0xafmX+Gcy3DOfeycK3PObZP3hmv0STzfI/4by73yit89/vZLJW1zzj3vP/ZySa/Ke2MueaVstJm197//p/99V3lvyD/18/3H/zTfOefmy5tOOLLC84fkfZJf7Jw7ImmCpIecc3nOuSxJj1R6vXc55066lPq+IWlKhe8/kjdyeb2ZRZt3Pk43edMNq9JZ3hvm+ySlSNoqr7QcNUlSF3kFdK6kd82sZYXsmf70yLaSfiZpXTVzN5N0sNK2g5KaV76hmd0sKV3HmeZqZpea2WK/XL5uZl8zs7ZmdpWkB6uZSWaWLOlcST9yzhU55z6R9IyOf7ye6Hg4keVmtl/etL5nJD1fYd8vnXOH/eNokqSH/dGpAkk/kTTRajgF1zn3O+fcpSd5n4X+9MjO8qbgbqt8G7/0j5Y35fVYdskbhVsvr/BfK++DGsk7hnIl/cA/hi/wH+/oMXzCY8c595I/PbKnpCcl5VTzvuvkfbjUQd6o7xBJDx/ndQBAraK0AQhSR0nbK3y/3d9WJf/T93+b2W7/0/LfyCsF1XWv/8ayv7zzpTr721MlDfenQR7wR4gmyRsZk7zSNkbeqM4CSfPkvVkcLW80K+Tnu9jMPvanzx2Q9LVK+fb407Yqvv6sSq+/Wszsf+2LqaNPVtp3rp/9n0e3Oef2Sbpc3rTHHEkXSZolb+SoKkck/cs5t9TP/CtJZ5tZC//xPvSnkRU6534r6YCqKCTOuTx9cV5adUpEgbwiXFGCvBGciq/xCnnnxF1caWpeZdfK+12mSJopbzrgWnll69lq5Dmqo6S8SiMx2yV1Osbtq3M8nMhg51wr51w359zPjh5nvorHTVV/j6LknT9Wq8xsUoXj7r+V9/tTVt+RN2JW2TfkTX3cWsW+ox6QN004WVKcvONujpk1dc6VSrpC0iWSdkv6nrzf6dFjuFrHjp9zo7wR2qMj2ce9r3Nut3NujXMu5Of/ob74UAcA6hylDUCQdsorTEel6IvznKqaPvWEvE+8e/iflv+vqp4ydVzOuc/kLZTwN3+KXJak+c65lhX+NHPO3enfZb68QjLG/3qhvPOoRvvfy8xi5Y3O/VFSkj/K9HalfJVf0y55b06PqnJlwmO8ht9UmDp6R6XdN0l6zR91qXif+c65oc651vJKSy9JS47xFCsr5T369bF+3u44+6LkTTut/Ka4Kqsl9a80dbG/KkyB9M/F+ru8hVA+0/Hd7Jzb5BfMl5xz5zrnEp1zV56gPFS2U1JrM6s44pciaYf/9Zd+t9U8Hk5Fxeer6u9Rmb4YRaru45z4xt45jkePu4uPcbMoeaO4lX1Dxx9lk7wpizOcc9n+qPcUeR+w9PWff6VzbrRzro1z7kJ500GPHsOr/ftL+nzaczcde/psxZyrJaVV+v0OOM59j3e8A0Cto7QBCNJ0ST8zs0TzVn77hbyFByTvDWeboyM7vubyzi8r8BcXuFM194K8IvF1eavR9TSzG/1pV9FmNvToeWv+p/JHJE2WtMA5l+/nu1pfnM8WIylW3uIeZWZ2saQLdHwzJf3EzFqZWWd9MV2zxsysibzRpSlV7Bvkv7YEeWUi2zn37jEe6nlJV5q3/H60vBX5FjrnDvjnq51jZjFmFmdmP5A3gvSh/zxXmVkv8xbISJQ3jWyFP+omM4s0szh5b5oj/MeI9p93nrxzF+81byGNb/vb5/j3HStv8ZGrnXPHKpyfqzQ6VWP+9NWPJP3Wz9tf0q1+Fsk7HrqYv2CNanY81NR0Sd8xb9GcZvriPLWyaty3cu6T5o++pZgnVdJDkmZXus3Z8kYlj7Vq5FFLJV1rZkn+8XOjpGh9cf5pf//n39TMvi9vuuIU/77/krdYy9X+8fULeedHrvPve5uZtfO/7itvGulsSXLObZD0iaQH/Me/Ut6HBa/6tx9T4TUmyxvlfaOGPzIAOGmUNgBB+rW8ZblXylupbbm/7eiKedMlbfGnLHaUt6DFDfKmLP1dX17O+6Q450rknUP2c3/K2wWSJsobtdgt6f/kvek+ar6kfe6LJd/ny/ukfYX/eIfkLR8+U9J+P+ebJ4jxK3lT2bbKO9/pHxV3mtmTlac+VsMV8s7FmVvFvh/KO58vS96b3c+vcWX+9cmOfu+8lfn+V9J/5J1H1F3ea5K88vyEvNe5Q95Uy4v9KZiS9+b8HXm/p8/knctX8XpaN8orwU/IG8E8Iu/3efT3coW8UZkD8pZ/v8LfLnnlsYWkt483Ta+OXC/vPL6d8grCA8659/19R8vIPjNbXsPjoaaek3fsLJB3LBWp+h8AfCm39PnU25P5mfaVV2gL5BX39frq5QmOjv5WnuaaYl++/t3/yTtH9BN5v//vyCvoR1d9vFHeCHWuvIWIznfOFUuS886LvVpeadwv75IQEys83TmSPjOzw/JGPd+Wd4wfNVHeOZL75ZWya/zHlLyVJRdJOuy/1lX68uUCAKBOmTvmAk4AAAAAgKAx0gYAAAAAYYzSBgAAAABhjNIGAAAAAGGM0gYAAAAAYYzSBgAAAABhjNIGAAAAAGGM0gYAAAAAYYzSBgAAAABhjNIGAAAAAGGM0gYAAAAAYYzSBgAAAABhjNIGAAAAAGGM0gYAAAAAYYzSBgAAAABhjNIGAAAAAGGM0gYAAAAAYYzSBgAAAABhjNIGAAAAAGGM0gYAAAAAYYzSBgAAAABhjNIGAAAAAGGM0gYAAAAAYYzSBgAAAABhjNIGAAAAAGGM0gYAAAAAYYzSBgAAAABhjNIGAAAAAGGM0gYAAAAAYYzSBgAAAABhjNIGAAAAAGGM0gYAAAAAYYzSBgAAAABhLOpENzCz5yRdKinXOXeGv22ApCclNZO0TdIk51y+v+8nkm6VVC7pXufcuyd6jrZt27ouXbrU8CUAAAAAQP2WkZGx1zmXWNU+c84d985mNkpSgaQXK5S2pZK+75ybb2a3SOrqnPu5mfWVNF3SMEkdJc2S1NM5V36850hPT3fLli072dcFAAAAAA2CmWU459Kr2nfC6ZHOuQWS8ipt7iVpgf/1+5Ku9r++XNLLzrli59xWSZvkFTgAAAAAQA3U9Jy2VZK+7n99raRk/+tOkrIq3C7b3/YVZna7mS0zs2V79uypYQwAAAAAaNhqWtpukXS3mWVIai6pxN9uVdy2yvmXzrmnnXPpzrn0xMQqp24CAAAAQKN3woVIquKcWyfpAkkys56SLvF3ZeuLUTdJ6ixp56kEBAAAAIDGrEYjbWbWzv9vhKSfyVtJUpLelDTRzGLNrKukHpKW1EZQAAAAAGiMqrPk/3RJYyS1NbNsSQ9IamZmd/s3eU3S85LknFttZjMlrZFUJunuE60cCQAAAAA4thMu+X86sOQ/AAAAgMbslJb8BwAAAAAEh9IGAAAAAGGM0gYAAAAAYYzSBgAAAABhjNJWz+w5VKyM7ftVWh4KOgoAAACA06BGF9fG6bPzwBEt2ZqnxVvztHjrPm3Zc1iS1LZZrK4e0knXpScrLbFZwCkBAAAA1BVKWxhxzmnbvkIt2bpPi7fmacnWPGXvPyJJah4XpWFdWuu69GS1bxGntz7dpWc+2Kqn5m/RsC6tNWFosr52Zns1jeFXCgAAADQkXKctQKGQ08bcgi+VtNxDxZKkNvExGta19ed/erdPUGSEfen+uflFenX5Ds1clqWtew+rWWyULhvQUdcNTdaAzi1kZlU9LQAAAIAwc7zrtFHaTqOy8pDW7jqkxX5JW7otTwcKSyVJ7RPiNDyttYZ3baNhXVurW2J8tUuXc05LtuZpxrIsvf3ZLhWVhtS7fXNNSE/WlYM6qVV8TF2+LAAAAACniNIWkJKykFZmH/h8FC1j+34VFJdJkrq0aeqPorXR8K6t1blVk1oZGcsvKtVbn+7UjKVZWpl9UDGRETq/X5ImDk3WOd3aKiKC0TcAAAAg3FDaTpMjJeVakbn/85K2PHO/isu8VR57JjX7vKQN69Ja7VvE1XmetbvyNWNpll7/ZIcOFJaqU8smuja9s65NT1anlk3q/PkBAAAAVA+lrY7kF5UqY/t+Ld6SpyVb9+mzHQdVWu4UYVLfjgka1qWNhqe11tAurdU6wCmKRaXlem9NjmYuzdLCTXtlJo3skajr0pM1vm87xUZFBpYNAAAAAKWtRnYd2qWJr07UjGtmqH2z9pKkvMMlWuKPoi3Ztk9rduYr5KToSFP/zi0/XzRkSGorJcRFB/wKqpaVV6hXMrL1z2VZ2nmwSK2aRuvKQZ113dBk9WrfPOh4AAAAQKNEaauBu/5zl55c9pQu6nKjBrf4npZszdOGnAJJUmxUhAantNKwrq01vGtrDUpppSYx9Wu0qjzk9MHGPZq5LEvvr8lRabnTwOSWum5osi4b0FHNYrl0AAAAAHC6UNpO0q5Du5T6l64qDRXLXIx6uCkakdpNw7q21oi01jqjU4sGNaVwX0Gx/rVih2YszdLG3AI1iY7UJf07aOLQZA1JbcWlAwAAAIA6drzSxnBKFR5c8KAkr8xGRUpjB32gJy69PthQdahNs1jdNjJNt57bVSuyDmjm0iy99elO/TMjW2mJ8bouPVlXDe6sxOaxQUcFAAAAGh1G2irZdWiX0h5JU1FZ0efbmkQ10Zb7tnx+bltjcLi4TP9ZuUszlmUpY/t+RUWYxvVpp+uGJmtUj0RFRUYEHREAAABoMBhpOwkPLnhQIRf60rZyV64H5z+ov13yt4BSnX7xsVGaMDRZE4Yma1PuIc1clq1XM7L17uocJSXE6pohnTUhPVmpbeKDjgoAAAA0aIy0VTLoqUH6ZPcnX9k+sP1ArfjWigAShY+SspDmrMvRjKVZmr9hj0JOOiutja4bmqyLzmivuOiGc54fAAAAcDqxEAlq3a6DR/RqRrZmLMtSVt4RJcRF6arBnfW9C3qqeZhe7gAAAAAIV5Q21JlQyOnjLfs0Y1mW/r1yl/p1TNALNw9TqwAvJg4AAADUN8crbawmgVMSEWE6u3tb/XXiID01eYjW7T6kCU8tUk5+0YnvDAAAAOCEKG2oNeP7JmnKzUO188ARXfPkR8rcVxh0JAAAAKDeo7ShVp3dra2m3jZc+UfKdO1TH2ljzqGgIwEAAAD1GqUNtW5QSivN/NZZCjlpwlOLtDL7QNCRAAAAgHqL0oY60at9c73yrbPUNCZKN/x9sRZv2Rd0JByHc06rdhzUX2dt1C1Tlmr22pygIwEAAMDH6pGoU7sOHtHkZxYre/8RPTl5iM7r3S7oSPAVl5Xr4y15mrUmR7PX5mjnwSKZSW3iY7S3oET3ju2u+8b3VGSEBR0VAACgwWPJfwRqX0GxvvHcEq3ffUh/mThQl/bvGHSkRivvcInmrsvVrLU5WrBhjw6XlKtJdKRG9WyrcX2SNLZ3OzWLjdLPX1+lVzKyNbpnov46caBaNuUSDgAAAHWJ0obA5ReV6tYpS7Vs+3799sozNXFYStCRGo3Newr80bRcLduep5CTkhJiNa5Pks7vk6SzurVRXHTkl+7jnNP0JVn65Zur1S4hVk9OHqIzOrUI6BUAAAA0fJQ2hIUjJeW6Y2qG5m/Yo59d0ke3jUwLOlKDVFYe0vLMA5q1Nkez1uRoy97DkqS+HRI0vq9X1M7olCCzE097/CTrgO6cmqG8wyV68IozNCE9ua7jAwAANEqUNoSNkrKQ7p+xQm9/tlv3juuh74zvUa3ygOMrKC7Tgg17NGtNjuasz9WBwlJFR5rO6tZW5/dpp7F9ktSpZZMaPfa+gmLdM32FPtq8T9cPS9Evv95XsVGRJ74jAAAAqu14pS3qdIdB4xYTFaFHJg5SfMxnemT2RuUfKdUvLu2rCBa7OGk7DhzR7LU5en9NjhZvyVNJeUgtm0ZrbK92Gt83SSN7tFXzuOhTfp42zWL14i3D9Kf3N+iJeZu1ZudBPTF5iDrWsAQCAADg5FDacNpFRUbo/67ur+Zx0Xruw60qKC7T7646U1GRXIHieEIhp1U7D2rW2lzNWpOjNbvyJUlpbeP1zXO6aHyfJA1OaVknP8eoyAj96KLeGtC5pb7/yqe69NGFevT6QTqne9tafy4AAAB8GaUNgYiIMP380j5qHhelv87eqMPFZfrLxIFMu6ukqLRcizbv0/trvWX5c/KLFWFSempr/e/XemtcnyR1S2x22vJcdEZ79Uhqpjv+kaEbn12sH1zYW3eMTmOKKwAAQB3inDYE7pkPtujX/1mrkT3a6qkbh6hpTOP+LGFvQbHmrPNG0z7YuFdHSssVHxOpUT0TNb5Pks7r3U6t44Ndgv9wcZl++OpK/WflLl3YL0l/vHZArUzFBAAAaKxYiARhb+bSLP34tZUanNJKz908VAmNqAA457Qpt8AfTcvV8sz9ck7q0CJO4/skaXzfJI1Iax12o5DOOT27cKt++991Sm3dVE/eOEQ9k5oHHQsAAKBeorShXvjPyl26f8YK9UxqrhdvGaY2zWKDjlRnnHNavDVP76/J0ay1Odq+r1CSdGanFhrfJ0nj+rRTv47VW5Y/aIu37NPdL61QYUmZ/u/q/rpsABdPBwAAOFmUNtQbc9fn6s6pGerUsomm3jZcHVo0rBUKQyGn99bs1qNzNmn1znzFREXonG5tNM4vavX19ebkF+muacuVsX2/bj23q358cW9Fs7AMAABAtVHaUK8s2ZqnW6YsVYsm0Zp223B1aRsfdKRTVlYe0n8+26XH5mzSxtwCdW0brztHd9Ml/TsoPrZhnMNXUhbSb95eqykfbdOwLq312KRBatc8LuhYAAAA9QKlDfXOZ9kH9Y3nFisqMkL/uHWYerdPCDpSjZSWh/Sv5Tv0+LxN2ravUD2TmunbY3vokjM7KLKBXpvu9RU79OPXViohLlqPTxqs9C6tg44EAAAQ9ihtqJc25hzS5GcXq6g0pCk3D9WglFZBR6q2otJyvZKRrSfnbdaOA0d0RqcEffu8Hrqgb1KjuJD42l35umNqhnbsP6KfXdJHN53dpV6cnwcAABAUShvqray8Qk16ZrH2FhTrmZvSdXa38L6Yc2FJmV5anKmnF2xR7qFiDU5pqXvG9dCYnomNrrQcPFKq7838RLPW5uqKgR31m6vObPSXcwAAADgWShvqtZz8It347GJt21eox28YrPF9k4KO9BWHikr14qLtenbhVuUdLtFZaW10z9juOqtbm0ZX1ioKhZwen7dJf3p/g3olNdeTk4c0iHMUAQAAahulDfXe/sMl+ubzS7RqZ74enjBAlw/sFHQkSdKBwhI9/+E2Pf/hVuUXlWlMr0R9+7zunMdVyfwNe3TfyytUHnL684SBYVm8AQAAgkRpQ4NQUFymW6cs1ZJteXrw8jM0eURqYFn2FhTrmQ+26h+LtulwSbku6Juke8b20JmdWwSWKdxl5RXqzmkZWrUjX98+r7u+c37PBrsYCwAAwMmitKHBKCot193Tlmv2ulz96KLeunNMt9P6/LsPFumpBZs1fUmmistCurR/R919Xrd6u7rl6VZUWq5fvLFKM5dla2SPtnpk4iC1io8JOhYAAEDgKG1oUErLQ/ruzE/11qc7ddeYbvrBhb3q/LyxrLxCPTl/s15Zlq1y53TloE66c0w3dUtsVqfP21BNX5KpB95YrcTmsXpy8hBGKAEAQKN3vNLGUm6od6IjI/SX6waqWWyUHp+3WYeKyvSrr/erk6X0t+wp0OPzNuv1FTsUYaZr0jvrztHdlNy6aa0/V2Ny/bAU9e2QoDunZujqJz/Sg5f303VDU4KOBQAAEJYobaiXIiNMv7nyDCXERempBVtUUFymP1zTX1GREbXy+Ot3H9Lf5m7Sv1fuVHRkhG48K1W3j0pThxZNauXxIQ1Ibql/3ztS905foR+9+pk+yTqgBy7rp7joyKCjAQAAhBVKG+otM9OPL+6thCbR+sO761VQXKZHrx90Sm/6P8s+qMfmbtS7q3MUHxOp20d1063ndlVi89haTI6jWsfH6IVbhulP763X4/M2a/XOfD0+abA6t2IkEwAA4CjOaUOD8MJH2/TAm6t1Tvc2evrGdMXHntznERnb8/TonE2at36PEuKi9M1zuuqWc7qoZVMWyThd3l29W9+f+amiIk2PXD9II3skBh0JAADgtGEhEjQKr2Zk64evrlT/zi005ZvD1KJp9HFv75zToi379NicTfpo8z61jo/Rred21Y1npSoh7vj3Rd3YsqdAd0zN0KbcAn3vgl66c3S3OjlXEQAAINxQ2tBovLNqt+6dvkJpifF68dZhatc87iu3cc5p3oY9emzOJmVs36/E5rH61qg03TA8RU1jmDEctMPFZfrxa5/prU936vy+SfrThAGUaAAA0OBR2tCofLBxj25/MUNJCbGaetvwz8+PCoWc3luTo8fmbtSqHfnq1LKJ7hidpmvTk1n8Isw45/T8h9v0m7fXqnOrJnrqxnT1at886FgAAAB1htKGRidje55ufn6pmsVG6cVbh2nNrkP625xNWp9zSKltmuruMd11xaBOiomqndUmUTeWbM3T3S8tV0FRmX539Zm6fGCnoCMBAADUCUobGqU1O/P1jecWa9/hEjkndW/XTN8+r7su7d+h1i4NgLqXm1+ku6Yt17Lt+3VRv/b6/oW91L0dFzUHAAANyymVNjN7TtKlknKdc2f42wZKelJSnKQySXc555b4+34i6VZJ5ZLudc69e6KAlDbUlS17CvTX2Rt1Ub/2urBfexa1qKdKy0N6fO5mPb1gs46UluvaIcm6b3wPdd90aKUAACAASURBVGzJdfMAAEDDcKqlbZSkAkkvViht70n6s3Puv2b2NUk/dM6NMbO+kqZLGiapo6RZkno658qP9xyUNgDVsa+gWH+bu1lTP94umfTNs7voztHd1CqeSzMAAID67Xil7YRzxJxzCyTlVd4sKcH/uoWknf7Xl0t62TlX7JzbKmmTvAIHAKesTbNY/eKyvpr9vdG6rH9H/f2DLRr1+7l6bM5GFZaUBR0PAACgTtT0xJ77Jf3BzLIk/VHST/ztnSRlVbhdtr/tK8zsdjNbZmbL9uzZU8MYABqj5NZN9acJA/TOfaM0PK2N/vjeBo36/Tz9Y9E2lZaHgo4HAABQq2pa2u6U9B3nXLKk70h61t9e1QlDVc6/dM497ZxLd86lJyYm1jAGgMasV/vmeuamdL1651lKaxuvn7+xWuMfnq83PtmhUCj4RZYAAABqQ01L202SXvO/fkVfTIHMlpRc4Xad9cXUSQCoE0NSW2vGt0bo+W8OVZPoSN338ie69NGFmrc+V+GwQi4AAMCpqGlp2ylptP/1WEkb/a/flDTRzGLNrKukHpKWnFpEADgxM9N5vdvp7XtH6q8TB+pQcam++fxSTXz6Yy3P3B90PAAAgBqLOtENzGy6pDGS2ppZtqQHJP2PpL+aWZSkIkm3S5JzbrWZzZS0Rt6lAO4+0cqRAFCbIiJMlw/spIvP6KCXl2bqkdkbddXjH+mCvkn6wYW91COpedARAQAATgoX1wbQoB0uLtNzC7fq6QVbdLikTFcN7qzvnN9TnbjGGwAACCOndJ2204HSBqCu5R0u0RPzNumFRdslJ914VqruPq+7WnONNwAAEAYobQDg23HgiP46a4P+mZGtpjFRun1Umm49t6viY084WxwAAKDOUNoAoJJNuYf0h3fX693VOWrbLEb3jO2h64elKCaqpuszAQAA1NzxShvvTgA0St3bNddTN6brX3edre7tmumBN1dr3MPz9K8V2VzjDQAAhBVKG4BGbVBKK03/nxF64ZZhSoiL1ndmfKqvPfKB5qzL4RpvAAAgLFDaADR6ZqbRPRP11rfP1aPXD1JRablumbJME55apGXb8oKOBwAAGjlKGwD4IiJMlw3oqPe/O1q/vuIMbdtXqGueXKTbXliqdbvzg44HAAAaKRYiAYBjKCwp05SPtumJeZtVUFymKwd10nfG91Ry66ZBRwMAAA0Mq0cCwCk4UFiiJ+Zv1pQPt8k5adKIFN19Xne1bRYbdDQAANBAUNoAoBbsOnhEj8zeqJnLshUXFaHbRqbptpFd1TwuOuhoAACgnqO0AUAt2rynQA+/t0H/+WyXWsfH6MpBnTSuTzsN7dJa0ZGcKgwAAE4epQ0A6sCnWQf06JxNWrBxj0rKQkqIi9LoXu00vk87jenZTi2aMgIHAACqh9IGAHXocHGZFm7aq1lrcjR3fa72FpQoMsI0tEsrje+TpHF9ktS1bXzQMQEAQBijtAHAaRIKOX2SfUCz1+Zo9tpcrdt9SJKUlhiv8/0CNzilpaKYRgkAACqgtAFAQLLyCr0Cty5XH2/Zp9Jyp5ZNo3Ver3Ya16edRvVMVAILmQAA0OhR2gAgDBwqKtUHG7+YRrm/sFTRkabhXdtoXJ92Gt8niWvAAQDQSFHaACDMlIeclmfu1yx/GuWm3AJJUs+kZp+fBzcwuaUiIyzgpAAA4HSgtAFAmNu29/DnBW7JtjyVh5zaxMfovN7eapQjeyQqPjYq6JgAAKCOUNoAoB45eKRU8zfs0ey1OZq7Llf5RWWKiYzQWd3aaHyfdhrbJ0mdWjYJOiYAAKhFlDYAqKdKy0Natm3/54uZbN17WJLUp0OCxvdpp3F9ktS/UwtFVJhGmZMzTVu2/FTFxZmKjU1RWtpDSkqaFNRLAAAA1UBpA4AGYvOeAs1a402jXLY9TyEnJTaP1bjeXoHr3eI9bd18h0Khws/vExHRVL16PU1xAwAgjFHaAKAB2n+4RPM25GrW2lwtWL9Hh4rL9KfRt6hNk9yv3DY2NlVnnbXt9IcEAADVcrzSxlntAFBPtYqP0ZWDOuvKQZ1VUhbS0m15KsnaU+Vti4szT3M6AABQWyKCDgAAOHUxURE6p3tbxcWlVLk/Nrbq7QAAIPxR2gCgAUlLe0gREV++QHdERFOlpT0UUCIAAHCqKG0A0IAkJU1Sr15PKzY2Rc6Z8kuSWIQEAIB6jtIGAA1MUtIknXXWdmXGbtG9c55VTuklQUcCAACngNIGAA3UlYM7qUl0pKZ9zCIkAADUZ5Q2AGigEuKidfnAjnrj0x06eKQ06DgAAKCGKG0A0IBNHpGqotKQXlueHXQUAABQQ5Q2AGjAzujUQgOSW2ra4kw554KOAwAAaoDSBgAN3OThKdqUW6CPt+QFHQUAANQApQ0AGrhL+3dUQlyUpi3eHnQUAABQA5Q2AGjgmsRE6pohyXp39W7tOVQcdBwAAHCSKG0A0AhMGpGi0nKnmcuygo4CAABOEqUNABqBbonNdHa3NnppcabKQyxIAgBAfUJpA4BGYvKIVO04cETz1ucGHQUAAJwEShsANBLn901SYvNYTVucGXQUAABwEihtANBIREdGaOLQZM1dn6usvMKg4wAAgGqitAFAI3L9sBSZpOlLGG0DAKC+oLQBQCPSsWUTje2dpJnLslRSFgo6DgAAqAZKGwA0MpNHpGhvQYneWb076CgAAKAaKG0A0MiM6pGo5NZNNPXj7UFHAQAA1UBpA4BGJiLCdMOwVC3ZmqeNOYeCjgMAAE6A0gYAjdCE9M6KiYxg+X8AAOoBShsANEJtmsXq4jPb69WMbBWWlAUdBwAAHAelDQAaqckjUnWouExvfrIz6CgAAOA4KG0A0Eilp7ZSr6Tmmrp4u5xzQccBAADHQGkDgEbKzDRpRIpW7cjXyuyDQccBAADHQGkDgEbsykGd1DQmkuX/AQAIY5Q2AGjEmsdF6/KBnfTWyp06WFgadBwAAFAFShsANHKTR6SoqDSkfy7PDjoKAACoAqUNABq5fh1baFBKS01jQRIAAMISpQ0AoMnDU7Vlz2Et2rIv6CgAAKASShsAQJf076AWTaI17ePMoKMAAIBKKG0AAMVFR+raIZ317urdys0vCjoOAACo4ISlzcyeM7NcM1tVYdsMM/vE/7PNzD6psO8nZrbJzNab2YV1FRwAULsmjUhVWchpxtKsoKMAAIAKqjPSNkXSRRU3OOeuc84NdM4NlPSqpNckycz6SpooqZ9/n8fNLLJWEwMA6kTXtvE6t3tbTV+SqfIQC5IAABAuTljanHMLJOVVtc/MTNIESdP9TZdLetk5V+yc2yppk6RhtZQVAFDHJo9I0c6DRZqzLjfoKAAAwHeq57SNlJTjnNvof99JUsV5Ndn+NgBAPTCuT5LaNY/VtMXbg44CAAB8p1rartcXo2ySZFXcpso5NmZ2u5ktM7Nle/bsOcUYAIDaEB0ZoYnDUjR/wx5l5RUGHQcAAOgUSpuZRUm6StKMCpuzJSVX+L6zpJ1V3d8597RzLt05l56YmFjTGACAWnb9sGRFmGnaYpb/BwAgHJzKSNt4Seucc9kVtr0paaKZxZpZV0k9JC05lYAAgNOrQ4smGte7nWYuy1JxWXnQcQAAaPSqs+T/dEmLJPUys2wzu9XfNVFfnhop59xqSTMlrZH0jqS7nXP8Hx8A6pnJI1KVd7hE76zaHXQUAAAavagT3cA5d/0xtn/zGNsfkvTQqcUCAATp3O5tldqmqaZ9nKnLB7KeFAAAQTrVhUgAAA1QRITphmEpWrItT+t3Hwo6DgAAjRqlDQBQpWvTkxUTFcHy/wAABIzSBgCoUuv4GF1yZge9tnyHDheXBR0HAIBGi9IGADimySNSVFBcpjc+qfLqLQAA4DSgtAEAjmlwSiv1bt9c0xZvl3Mu6DgAADRKlDYAwDGZmSaNSNXqnfn6JOtA0HEAAGiUKG0AgOO6clAnxcdEaurHmUFHAQCgUaK0AQCOq1lslK4Y1En/XrlTBwpLgo4DAECjQ2kDAJzQ5BGpKi4L6Z8Z2UFHAQCg0aG0AQBOqE+HBA1JbaVpizNZkAQAgNOM0gYAqJZJw1O0de9hfbR5X9BRAABoVChtAIBq+dqZHdSqabSmfrw96CgAADQqlDYAQLXERUfq2vRkvbcmRzn5RUHHAQCg0aC0AQCq7YZhKSoPOb28JCvoKAAANBqUNgBAtXVpG6+RPdpq+pJMlZWHgo4DAECjQGkDAJyUScNTtTu/SHPW5QYdBQCARoHSBgA4KeP7tFP7hDhNXZwZdBQAABoFShsA4KRERUZo4rBkLdiwR9v3HQ46DgAADR6lDQBw0iYOTVFkhOklRtsAAKhzlDYAwElr3yJO5/dJ0sxlWSoqLQ86DgAADRqlDQBQI5NHpGp/YaneWbU76CgAADRolDYAQI2c3a2NurRpqqkfbw86CgAADRqlDQBQIxERpknDU7Vs+36t250fdBwAABosShsAoMauGdJZMVERjLYBAFCHKG0AgBprFR+jS/t30L+W71BBcVnQcQAAaJAobQCAUzJ5RKoOl5TrjU92BB0FAIAGidIGADglg5Jbqk+HBE39OFPOuaDjAADQ4FDaAACnxMw0eUSK1u7K1/LMA0HHAQCgwaG0AQBO2RUDO6lZbJSmsSAJAAC1jtIGADhl8bFRunJQJ/37s13af7gk6DgAADQolDYAQK2YNCJFJWUhvZKRFXQUAAAaFEobAKBW9G6foPTUVnppcaZCIRYkAQCgtlDaAAC1ZvKIVG3bV6gPN+8NOgoAAA0GpQ0AUGsuPrO9WsfHaCoLkgAAUGsobQCAWhMbFalr0ztr1tpc7T5YFHQcAAAaBEobAKBWTRqWqpBzmr4kM+goAAA0CJQ2AECtSmnTVKN6JOrlpZkqKw8FHQcAgHqP0gYAqHWThqcoJ79Ys9bmBh0FAIB6j9IGAKh1Y3u3U4cWcZq2mAVJAAA4VZQ2AECti4qM0PXDUvTBxr3auvdw0HEAAKjXKG0AgDoxcWiyoiJMLzHaBgDAKaG0AQDqRLuEOF3QL0mvZGSrqLQ86DgAANRblDYAQJ2ZNDxVBwpL9fZnu4KOAgBAvUVpAwDUmbO7tVFa23hN/ZgpkgAA1BSlDQBQZ8xMNwxP0fLMA1qzMz/oOAAA1EuUNgBAnbpmSGfFRkVoKguSAABQI5Q2AECdatk0RpcN6KjXV+zQoaLSoOMAAFDvUNoAAHVu0vAU9W8zS4s/7qp58yK0aFEX5eRMCzoWAAD1QlTQAQAADV+HmLd165mPKUrFkqTi4u1av/52SVJS0qQgowEAEPYYaQMA1LmtW3+q6IjiL20LhQq1ZctPA0oEAED9QWkDANS54uLMk9oOAAC+QGkDANS52NiUk9oOAAC+QGkDANS5tLSHFBHR9EvbIiKaKi3toYASAQBQf1DaAAB1Lilpknr1elqxsalyMu09kihr+TCLkAAAUA2sHgkAOC2SkiYpKWmSikrLNfoPc9V5W1Ode6aTmQUdDQCAsMZIGwDgtIqLjtQ9Y3soY/t+zV2fG3QcAADCHqUNAHDaTUhPVkrrpvrjuxsUCrmg4wAAENZOWNrM7DkzyzWzVZW232Nm681stZn9vsL2n5jZJn/fhXURGgBQv8VERej+8T20Zle+/rtqd9BxAAAIa9UZaZsi6aKKG8zsPEmXS+rvnOsn6Y/+9r6SJkrq59/ncTOLrM3AAICG4fKBndSjXTM9/P56lZWHgo4DAEDYOmFpc84tkJRXafOdkn7nnCv2b3P0pITLJb3snCt2zm2VtEnSsFrMCwBoICIjTN+7oKc27zmsf63YEXQcAADCVk3PaespaaSZLTaz+WY21N/eSVJWhdtl+9u+wsxuN7NlZrZsz549NYwBAKjPLuzXXmd2aqG/zt6okjJG2wAAqEpNS1uUpFaSRkj6gaSZ5q3ZXNW6zVWeYe6ce9o5l+6cS09MTKxhDABAfWbmjbZl7z+iGUszg44DAEBYqmlpy5b0mvMskRSS1Nbfnlzhdp0l7Ty1iACAhmx0z0QN69Jaj8zZpCMl5UHHAQAg7NS0tL0uaawkmVlPSTGS9kp6U9JEM4s1s66SekhaUhtBAQANk5np+xf20p5DxXpx0bag4wAAEHaqs+T/dEmLJPUys2wzu1XSc5LS/MsAvCzpJn/UbbWkmZLWSHpH0t3OOT42BQAc17CurTWqZ6KemL9Zh4pKg44DAEBYMeeCv6hpenq6W7ZsWdAxAAABWpl9QF9/7EPdP76H7h/fM+g4AACcVmaW4ZxLr2pfTadHAgBQq/p3bqmL+rXXMx9s1f7DJUHHAQAgbFDaAABh47sX9NThkjI9OX9z0FEAAAgblDYAQNjomdRcVwzspBcWbVNuflHQcQAACAuUNgBAWLl/fA+VlTs9NndT0FEAAAgLlDYAQFhJbROvCUOTNX1JprLyCoOOAwBA4ChtAICwc8/Y7jIz/XX2xqCjAAAQOEobACDsdGjRRDeOSNVry7O1Kbcg6DgAAASK0gYACEt3jemmJtGR+vP7G4KOAgBAoChtAICw1KZZrG45t6v+89kurdpxMOg4AAAEhtIGAAhbt41MU0JclB5mtA0A0IhR2gAAYatFk2jdMaab5qzLVcb2vKDjAAAQCEobACCsffPsLmrbLFZ/eHe9nHNBxwEA4LSjtAEAwlrTmCjdfV43fbwlTx9u2hd0HAAATjtKGwAg7N0wPEUdW8TpD+8x2gYAaHwobQCAsBcbFan7xvfQp1kH9P6anKDjAABwWlHaAAD1wtWDO6tr23g9/P4GhUKMtgEAGg9KGwCgXoiKjND943to3e5DemvlzqDjAABw2lDaAAD1xmX9O6p3++b68/sbVFoeCjoOAACnBaUNAFBvRESYvndBL23bV6hXM7KDjgMAwGlBaQMA1Cvj+7TTgOSWemT2RhWXlQcdBwCAOkdpAwDUK2amH17YSzsPFumlxZlBxwEAoM5R2gAA9c453dvqrLQ2+tvcTSosKQs6DgAAdYrSBgCol75/YS/tLSjR8x9uCzoKgEZg16FdGj1ltHYX7A46ChohShsAoF4aktpK43q301PzN+vgkdKg4wBo4H41//9p4faFenD+g0FHQSNEaQMA1FvfvaCn8ovK9MwHW4KOAqABe2XFSv094zmFFNLTGc9qyXb+zcHpRWkDANRb/Tq20CX9O+jZhVu1t6A46DgAGpidB47oW/9Yplte+7GcvGtDloXKNf6Ze3T3S8u1eufBgBOisaC0AQDqte+M76mi0nI9MW9z0FEANBCl5SH9fcEWjX94vmZvWK/imDly8hc9sjIVRc/W7PXrdckjC/XN55doyda8YAOjwaO0AQDqte7tmunqwZ31j4+3a9fBI0HHAVDPZWzfr8seXaiH3l6rs9La6KyB82TmvnQbi3A6d8h8/eDCXvos+6AmPLVI1z75keauy5Vz7hiPDNQcpQ0AUO/dO66HnHN6dM6moKMAqKcOFJboJ6+t1NVPfKSDR0r11I1D9MxN6Vq1d5lKyku+dNuS8hJl7Fqsu8/rroU/Gqtffb2fdh4o0s1TluprjyzUW5/uVHmI8obaY+HwaUB6erpbtmxZ0DEAAPXYL95YpZcWZ2r290YrtU180HEA1BPOOb26fId+8/ZaHTxSqlvP7ar7xvVQfGzUST1OaXlIb3yyU0/M26TNew6rS5umumN0N105uJNioyLrKD0aEjPLcM6lV7mP0gYAaAhy84s06g9zdfEZHfTn6wYGHQdAPbAx55B+9voqLd6ap8EpLfXQlWeqT4eEU3rMUMjpvTW79fi8zVqZfVDtE+J028iuun5YykkXQTQulDYAQKPw2/+u1dMLtujd+0epZ1LzoOMACFNHSsr16JyNenrBFsXHRuknF/fWhPRkRURYrT2Hc04LN+3V43M3a9GWfWrZNFo3n91VN52dqpZNY2rtedBwUNoAAI3C/sMlGvX7uTq7exs9dWOV/98D0MjNWZejX7yxWtn7j+iaIZ31k4t7q02z2Dp9zuWZ+/X43M2atTZH8TGRumF4im4bmaakhLg6fV7UL8crbYzRAgAajFbxMbp1ZFf9ZdZGrcw+oP6dWwYdCUCY2HngiH711mq9uzpHPdo104zbR2h4WpvT8tyDU1rpmZvStX73IT0xb5Oe+3CbXvhou64e0ll3jE7jPFycECNtAIAG5VBRqUb9fq7O7NxSL94yLOg4AAJWWh7SlA+36c+zNijknO4d10O3nZummKjgFlHP3FeopxZs1isZ2SorD+nS/h1155hup3w+Heo3pkcCABqVpxds1m/eXndaP0kHEH4ytu/XT//1mdbtPqRxvdvpl1/vp+TWTYOO9bnc/CI9++FWTV20XYdLyjWudzvddV43DUltHXQ0BIDSBgBoVIpKyzXq93OV2qapZn7rLJnV3uICp0vG9v16dM5Gje3dTt84q0vQcYB65UBhif7vnXWaviRLHVrE6Zdf76cL+iaF7b8FBwtL9cKibXr+w63aX1iq4V1b667zumtUj7Zhmxm1j9IGAGh0/vHxdv389VWacvNQjenVLug41bYpt0B/eHed3l2dIzMpNipC875/ntq3YMEC4ERq65prQSksKdPLS7L09w+2aNfBIp3RKUF3jemuC/u1V2QtrmyJ8ERpAwA0OiVlIY390zy1ahqjN799Tth/Wp2TX6S/zNqomcuy1CQ6Ut8alaYL+rXXZY8u1BWDOur31wwIOiIamMKSMh08Uqr2CXFh//ejOjbmHNJPX1+lJbV4zbWglJSF9PqKHXpi/mZt3XtYaYnxumN0N10xsFOg5+KhblHaAACN0j8zsvX9Vz7Vk5MH66IzOgQdp0r5RaV6av5mPbtwq8pDTpOGp+qesd0/X4L81/9eo2c/3Kr/3jdSvdvXzzegCD9z1uXoh//8THsLitWueawGp7TS4NSWGpzSSmd0aqG46MigI1bbkZJyPTJno/5eh9dcC0p5yOmdVbv1t7mbtGZXvjq2iNP/jErTxKEpahJTf35HqB5KGwCgUSoPOV34lwWSpHfvHxVW04uKy8o19eNMPTZno/YXlurygR31vfN7KaXNlxdJOFDoXXtuUEorvcBqmDhFh4vL9Ov/rNX0JZnq3b65rhnSWat2HNTyzAPKzCuUJEVHmvp2SNCglFYanNpKg5JbqnOrJmE5Gjd7bY4eePP0XnMtCM45zd+wR4/P26wlW/PUOj5GuU3u047Da79y24HtB2rFt1YEkBKniuu0AQAapcgI03fP76m7pi3XG5/s0FWDOwcdSaGQ0xuf7tAf392gHQeOaGSPtvrRRb11RqcWVd6+ZdMY3TO2hx56e60Wbtyrc3u0Pc2J0VBkbN+v7878RJl5hfrWqDR994Keio36YrRmz6FircjcrxVZB7R8+37NWJqlKR9tkyQlNo/V4BRvJG5QSiv17xzsaFyQ11wLgplpTK92GtOrnZZty9Pj8zbrlc1dpMiNkpV9fruYyBid3fns4IKizjDSBgBo0EIhp8seW6hDRWWa9d3RgZ0P4pzTgo179bv/rtPaXfnq1zFBP764t0b2SDzhfYvLyjXuT/OVEBetf99zboOY9oXTp7Q8pEdmb9Tf5m5ShxZN9KcJAzSiGgWnrDykdbsPaUXmfi3PPKDlmfu1fZ83GhcVYerbMcEvcV6ZOx2jceF4zbWgzN+04f+3d9/hVVXpHse/KxUIEBJqCkkI0qQlwFBUJChKsYLgZcYZFSuDOjoOFpjxjtdRx8Y46tVrGVEZC+gIVooFEZWAlITeQxoJBBICoSQhOev+kSPGkISSsk9yfp/n8SHZe59z3izX2We/Z639Li5+tw+ltujENj8TyIsX/cAl3bsT07qZR46OStU0PVJERLzaN1tymPTmSh69uhe/HRxd76+/LjOfJxZsYdnOXDqGNmXqpd24ok/4GSVfHyfv5u7ZycyY0Jdr+js/YigNw46cAu6Zk8yG3YcY3z+Sv15xLi2a+J/18+0/XERSer47kTvA2oyDHDteCkCb5u7ROPeUyj6RrWr1vqvVaXn8ed4Gj11zzQlTPp/Cv9a8znFXMT74E8JImh+bDECb5gH0jw5hQHQoA2JC6Bke7JXJbUOipE1ERLyatZYJLyeSceAo3943vN6mdaXuP8IzX2zls3XZhAYFcNdF5/CbQVG/mJJ2ulwuy9Uv/cD+giIWT01oUIUipP65XJa3ElN5YsEWggL9eHxsb0b16lDrr3NiNC4jn6S0skQutdxoXI+wlvSLalV2f1xUCB1Dz3w07sCRsjXXZq9sGGuu1afsgmxin4+lsKSQpn5N2XHXTo4ca86qtAOsTM1jddrPo6OBfj7EdWzFgJgQBsSE0i8qhOCmZ5/AS+1T0iYiIl5veUouE19dzl8u68EtQ2Pr9LX2Hy7i+a+38+6KdPx9fbh1aCduvTC2RiMc8PPfcP+obkxJOKeWopXGJvvgMaZ+sJYfduRyUfd2PHFNb9q1qL91/nJ/Go3LOMCatHzWZuZztPin0bgA4stNqewTGUyzgLISC/GvxJO8J/mk52tKZ8KKnm9wa67VlymfT+GV1a8wuf9kXrzsxZP25xQUsjr1ACtTD7A6LY8NWYcodVmMga7tWriTuLIROU8tOOMtlLSJiIgAv3t9BRuzDrH0/uE0r4MLvyNFJbz2XQqvLU2hsMTFxF915O6Lu9CuZe1dMN/y1kpWpOSx5L6ERlklT2rm4+TdPPTRBo6XWh66/Fx+PbCj4xfhJaUutu4tYI17WmVSej679h8ByooF9QhrQb+oEH7Mf4rF6XM47ir++cHWj05Nr+Dz699ssGuu1bXsgmwmfjiROePn0KH5qUdTjxaXkJyRz6rUA6xKO0BS2gEKisqKmbRvGciAmFAGRIfwq5hQundogZ+vplTWFyVtIiIiwNqMfK568QfuvaQrf7i4S609Tha8IQAAGG1JREFU7/FSF7N/TOe5r7ez/3Axo3t14L6R3Yht27zWXuMnO3IKuPTZpVw/JIaHr+xZ688vDVP+0WL+8tEGPluXTXxUK569No6YNkFOh1WlvCPFJ+6LS0rPZ21GPgeL95HV5Bas+TlpC/Bpwq67Uwhv6ZnrLDYGpS7L1j0FrE7LY2XqAVal5pF1sBCAZgG+xEe1OnFfXHxUSJ184SVllLSJiIi43TZrFYk7c/nugeG0ahZQo+ey1jJ//R6eXrSF1NyjDOwUyoOju9MvKqSWoq3ctLnr+WBVBl/dO8yjL8ylfny3fR9TP1hL7uFi7hnRhcnDOje40ZGfEoe7Ft7BtxlzKOU4Ab4B3BJ/S6VT/qRu7c4/xir3PXGrUg+wec8hrAUfAz3CWvKrmNCyIicxIYQFN/3lg+PjIfnkaa7ExUGS1o+rjpI2ERERt617Chj13FImD+vMA6O6n/XzLNu5nycXbGFt5kG6tW/BA6O7Mbxbu3qZipZTUEjC00tI6NaWl67rX+evJ57pWHEpTy7cwpvLUjmnXXOevTaO3pGVr/fXUFQsrJFyd8ppTfmTulVQeJyk9HxWpeaVTalMzz9RNTSiVdMTxU0GRIfQ7ZEH8Jk5E4rLTXMNCIBbboEXlYBXR4tri4iIuHXr0IKr+obzxg+7mHR+zBkXaNiUdYgnF27h2237CA9uwjMT+jI2PgLfelw7rV2LJtx2YSz//Go7q9MO0D+6bkf2xPOsy8znnjnJpOw7wqTzY3hgVPdGUVE0rEUYk+Im8crqV5gUN0kJm4do0cSfC7u25cKuZetKHi91sTn70IniJst25vJxchYAnZoNZZF9g1/MY/D1hYceqv/AGxGNtImIiNdJ3X+Ei//xLb8bHH3a94Vl5B3l2S+3MS95Ny2b+HPH8M5cPyTGsQvlI0UlJDyzhKjQZvxn8hDHi01I/SgpdfHiNzt5YfF22rYI5OnxfbmgSxunw6pVZ1pYQ5xnrSUj7xgr3SNxQ2b8hZEr5hNYWkKxrx+bRk+g5cxX6+Q+38ZE0yNFREQqmDZ3HR+u3s039yUQ0applccdOFLMi9/sYFZiGhiYdH4MU4adQ3Az59c3eu/HdKbNXc/Lv+3HqF4q1NDYpew7zL3vryU5I5+r4sJ55MpeHtEPRU6SnY2NjcUUFlLkH8jQ2/9FTlAIcR1bMa5fBJf3CSc0qGb3FDdGStpEREQqyMo/RsLTSxgbH8GT4/uctP9YcSkzf9jFy0t2cqS4hPH9I7lnRFfCq0nw6ltJqYvRz31HicvyxR8vxL+BFZ+Q02Ot5e0V6Tz++Wb8fQ2Pje3NFX3DnQ5LpHpTpsArr8Dkyez9+ww+Tt7N3DW72bKnAD8fw/Du7RgXH8FFPdoR6Nfwp/bWBiVtIiIilXjk001s2fUGv+8/h9LjmQQGRhEd8yhLMy7k2a+2sfdQESN6tOO+kd3p1qGF0+FWavGWvdz05ir+58qe3HBejNPhSC3LOVTI/R+uY8nWfQzt0oanx/elQ3D9LZQtctays2HiRJgzBzr8PM11U9Yh5iVl8lFyFvsKighu6s9lfcK4pl8E/aJCvHqqt5I2ERGRSuxIe4udO24n0LfoxLbi0kBmbriTIv+xTBvdg4GdQh2M8NSstfzmtRVs3VvAkvsSaNlE0+UaiwXrs5k2bz3HikuZPqYHvxscjU89FrwRqUslpS5+2JnLvDWZLNy4h8LjLqJbN+PquAjG9YsgurX3LWdSo6TNGDMTuBzIsdb2cm97GLgV2Oc+bLq1dr573zTgZqAU+IO1dtGpAlTSJiIiTkhMjKGoKO2k7S6fSIYPTW8w3/iuzzzIFf/7PVMSOnN/DZYxEM9wqPA4D3+8kblJu+kTGcw/ro3jnHYq4CCN1+GiEhZu2MPcNZkkpuRiLfSPDmFsfASX9wmr8ZqaDUVNk7YLgcPArApJ22Fr7TMVjj0XeA8YCIQDXwFdrbWl1b2GkjYREXHCkiU+QGWfg4aEBFd9h1Mj98xOYsGGPXwzNcGj7ruTM5O4M5epH6xlz6FC7hh+DndddI7uVRSvkpV/jI+Ts5i7JpPtOYcJ8PXhou7tGNcvgoRu7Qjwa7zvhxqt02atXWqMiTnN17oKmG2tLQJ2GWN2UJbAJZ7m40VEROpNYGBUpSNtgYFRDkRTM1NHdmP+hj3M+GIbM67t63Q4coYKj5fyzKKtvP7DLmJaB/GfyUOIj9L6e+J9wls15fcJnZk8LJaNWYf4cE0mn67NYuHGPYQ08+fyPuGM6xdBXMdWDWY2RG2oyeLadxpjrgdWAX+y1h4AIoDl5Y7JdG87iTHmNuA2gKiohvfhKCIiDV9s7GNs3XobLtfRE9t8fJoRG/uYg1GdnciQZkw6L4ZXv0vh5gs6cW54S6dDktO0Mesgf5yTzLa9h/nt4Cimj+lBs4CaXKKJNHzGGHpFBNMrIpjpY3rw/fb9fLgmk/dXZfDv5WnEtglibHwEV8dH0DG0mdPh1rnTKkTiHmn7rNz0yPbAfsrmlPwNCLPW3mSMeRFItNa+7T7udWC+tfbD6p5f0yNFRMQpe/e+Q0rKnykqSicwMIrY2Mdo3/46p8M6KwePHWfY09/QOyKYf988yOlw5BRKXZZXlu7k2S+30apZAE+N78Pwbu2cDkvEox0qPM6C9dnMXbObFbvyABgYE8q4fhGM7h1GcNOGW4ypxtUjKyZtVe1zFyHBWvt3975FwMPW2mqnRyppExERqR2vf7+Lv322ibduGsiwrm2dDkeqkJ57lHvfT2ZV2gFG9+rAY2N7a7FhkTOUkXe0bP23pN2k7DtCgJ8Pl5zbnnHxEVzYtW2Dux+01pM2Y0yYtTbb/fMfgUHW2onGmJ7Au/xciORroIsKkYiIiNSP4hIXI/7xLc0CfPn8D0PxVYl4j2Kt5f1VGTzy6SZ8jOF/rurJ2PgIr7o3R6S2WWtZl3mQuWsy+XRdNnlHimkdFMAVfcvuf+sdEdwg3mM1rR75HpAAtAH2An91/x5H2fTIVOD2ckncn4GbgBLgHmvtglMFqKRNRESk9ny2Los7303iqfF9uHZAR6fDEbf9h4t48MP1fLV5L4NjQ5lxbRwRqvQpUquKS1x8u20f85Iy+WpTDsWlLjq3DWJcv0iujo/w6PecFtcWERHxItZaxr60jOyDx1gydThNA3ydDsnrfblpLw9+uI6CohLuH9mNm87vpIWyRerYwaPH+Xx9NvOSMlmZegBjYHCn1oztF8GVfcNp4u9Z50YlbSIiIl5mZWoeE15OZOqlXbnzoi5Oh+OVrLUkZeTz+ne7+Hx9Nj3CWvLP/4qjW4cWTocm4nXSc48yL2k385IyyT5YyMq/jKBlE88qWqKkTURExAvdNmsVy3bmsuS+BNo0D3Q6HK9RVFLKZ2uzeSsxlXWZB2kR6Mek82O486IujXphYJGGwFpLau5ROrUJcjqUk9RocW0RERFpmB4Y3Z1Ln13Kc19t529Xn1QAWmrZnoOFvLMijXdXpJN7pJjObYN45KqejOsXSfNAXXKJeAJjjEcmbKeiM4iIiEgj1bltc34zMIp3f0znxvNj6Ny2udMhNTrWWlanHeCNZaks2rCHUmu5uHs7bjgvhgvOadMgKtaJiOdT0iYiItKI3T2iC/OSdvPkgi28en2ls27kLBQeL+WTtVm8tSyVjVmHaNHEjxvPi+H6ITFEtW7mdHgi0sgoaRMREWnE2jQPZPKwWJ75Yhs/7spjYKdQp0Nq0LLyj/H28jRmr8wg70gxXdo159GrezE2PoIgTYEUkTqis4uIiEgjd/MFsby9PJ3H529m3pTzNGXvDFlr+XFXHm8lprJo416stYzo0Z4bz4thSOfWak8RqXNK2kRERBq5pgG+3HtpV+7/zzo+X5/N5X3CnQ6pQSg8XsrHybt5c1kam7MPEdzUn1su6MRvB0fTMVRTIEWk/ihpExER8QLX9Itk5ve7eGrhVi45tz2Bfp61qKwnyTxwlH8vT2POygzyjx6ne4cW/H1cb66Oi9BC5SLiCCVtIiIiXsDXxzBtTA9umPkjby9P5+YLOjkdkkex1pKYkstby1L5ctNeAEb27MAN58UwqFOopkCKiKOUtImIiHiJYV3bMrRLG15YvJ3x/SMJburvdEiOO1pcwkdJZVUgt+4tIKSZP7cP68xvB0cT0aqp0+GJiABK2kRERLzKtNE9uOyF73jpmx1MG9PD6XAck5F3lFmJqcxZmcGhwhLODWvJU9f04cq4cJr4awqkiHgWJW0iIiJe5NzwloyLj+SNZan8bkg0kSHeU1DDWsuynbm88UMqX2/Zi48xjOrVgRvPi2FAdIimQIqIx1LSJiIi4mWmjuzKZ+uyeGbRVv45Md7pcOrckaIS5ibtZtayVLbnHKZ1UAB3JJzDdYOjCAvWFEgR8XxK2kRERLxMWHBTbr6gEy8t2cnNF8TSOzLY6ZDqRFruEWYlpvH+qgwKCkvoHRHMMxP6cnmfME2BFJEGRUmbiIiIF5qc0JnZKzN4fP5m3r11UKOZGuhyWb7fsZ83l6XyzdYcfI1hTO8wbjgvhn5RrRrN3yki3kVJm4iIiBdq2cSfuy/uwl8/2cg3W3O4qHt7p0OqEZfL8p/Vmby8dCcp+47Qpnkgd13UhesGRdG+ZROnwxMRqRElbSIiIl7qN4OieHNZKn+fv4ULu7TFz9fH6ZDOytY9BUyft57VaQfoExnMs//VlzG9w7SAuIg0GkraREREvJS/rw8PjOrG5LfX8MHqTH49MMrpkM7IseJSXli8nVeXptCiiR8zJvRlXL8ITYEUkUZHSZuIiIgXG9mzAwOiQ/jHl9u4sm84QYEN49Lg2237eOijDaTnHWV8/0imj+lBaFCA02GJiNSJhjkPQkRERGqFMYZpY3qwr6CI175LcTqcU8opKOQP7yVxw8wf8fM1vHfrYJ6Z0FcJm4g0ag3j6zQRERGpM/2jQxjTuwOvLk3hN4OiaNfC8wp3uFyW2SszeGLBZgqPu/jjiK5MTojVfWsi4hU00iYiIiLcP7I7x0tdPPvldqdDOcnWPQVMeCWR6fPW0zM8mAX3DOXuEV2UsImI19BIm4iIiBDTJojrBkUzKzGVm86PoUv7Fk6HpEIjIiJuGmkTERERAP5wcReCAvx4YsEWp0Ph2237GPnPpby0ZCdj4yP4+k8JXNM/UgmbiHgljbSJiIgIAKFBAUwZfg5PLtxC4s5chnRuXe8x5BQU8uhnm/lkbRaxbYN479bBjsQhIuJJNNImIiIiJ0w6P4bw4CY8Pn8zLpett9d1uSzvrkhnxIxvWbhhD38c0ZUFdw9VwiYigpI2ERERKaeJvy9/urQb63cf5NN1WfXymio0IiJSPU2PFBERkV8YGx/B69/v4qmFWxnZswNN/OsmeTpWXMrzi7fzmgqNiIhUSyNtIiIi8gs+PobpY3qwO/8YsxJT6+Q1fio08n8qNCIickoaaRMREZGTXNClDcO6tuV/F+/g2gEdadUsoFaeN6egkL99tplPVWhEROS0aaRNREREKjVtTHcOF5XwwuIdNX4ul8vyzoo0Lp7xLYtUaERE5IxopE1EREQq1b1DS8b3j2RWYio3DIkhqnWzs3qerXsKmDZ3HWvS8xkS25rHxvYitm3z2g1WRKQR00ibiIiIVOneS7rh62N4atGZL7h9rLiUJxdu4bLnv2PX/iPMmNCXd28dpIRNROQMaaRNREREqtQhuAm3Do3lhcU7uGVoPnEdW53W45ZszeGhjzeQkXeMCf0jmTamB6FBtXNfnIiIt9FIm4iIiFTr9mGdadM8gMc/34y11S+4nVNQyF3vJXHjGyvx9/Vh9m2DeXpCXyVsIiI1oKRNREREqtU80I+7R3Tlx9Q8vty0t9Jjqio0MjhWhUZERGpK0yNFRETklCb+qiNv/LCLJxZuYXj3dvj7/vy975Y9h5g+dz1r0vM5r3NrHr1ahUZERGqTRtpERETklPx9fXhwVHdS9h1h9soM4OdCI5c///2JQiPv3KJCIyIitU0jbSIiInJaLjm3PQNjQnnuq220CQrg8QWbVWhERKQeaKRNRERETosxhumX9WD/4WJ+/84aAlRoRESkXmikTURERE5bXMdWPDi6Oy5rufmCTgT6+TodkohIo6ekTURERM7I5GGdnQ5BRMSraHqkiIiIiIiIB1PSJiIiIiIi4sGUtImIiIiIiHgwJW0iIiIiIiIeTEmbiIiIiIiIB1PSJiIiIiIi4sGUtImIiIiIiHgwJW0iIiIiIiIeTEmbiIiIiIiIB1PSJiIiIiIi4sGUtImIiIiIiHgwJW0iIiIiIiIeTEmbiIiIiIiIBzPWWqdjwBizD0hzOo5KtAH2Ox2El1LbO0vt7xy1vXPU9s5R2ztHbe8ctb1zPLXto621bSvb4RFJm6cyxqyy1g5wOg5vpLZ3ltrfOWp756jtnaO2d47a3jlqe+c0xLbX9EgREREREREPpqRNRERERETEgylpq96rTgfgxdT2zlL7O0dt7xy1vXPU9s5R2ztHbe+cBtf2uqdNRERERETEg2mkTURERERExIMpaRMREREREfFgStoAY8woY8xWY8wOY8yDlew3xpjn3fvXGWP6ORFnY2OM6WiM+cYYs9kYs9EYc3clxyQYYw4aY5Ld//23E7E2RsaYVGPMene7rqpkv/p9HTHGdCvXp5ONMYeMMfdUOEZ9v5YYY2YaY3KMMRvKbQs1xnxpjNnu/jekisdW+/kg1aui7Z82xmxxn1fmGWNaVfHYas9RUr0q2v5hY8zucueVMVU8Vv2+Bqpo+znl2j3VGJNcxWPV72ugqmvLxnDO9/p72owxvsA24BIgE1gJ/Npau6ncMWOAu4AxwCDgOWvtIAfCbVSMMWFAmLV2jTGmBbAauLpC2ycAU621lzsUZqNljEkFBlhrK11cUv2+frjPQbuBQdbatHLbE1DfrxXGmAuBw8Asa20v97angDxr7RPuD+YQa+0DFR53ys8HqV4VbX8psNhaW2KMeRKgYtu7j0ulmnOUVK+Ktn8YOGytfaaax6nf11BlbV9h/wzgoLX2kUr2paJ+f9aqurYEbqSBn/M10gYDgR3W2hRrbTEwG7iqwjFXUfbGs9ba5UArd6eQGrDWZltr17h/LgA2AxHORiXlqN/Xj4uBneUTNqld1tqlQF6FzVcBb7l/fouyD/WKTufzQapRWdtba7+w1pa4f10ORNZ7YF6gin5/OtTva6i6tjfGGOBa4L16DcpLVHNt2eDP+Urayv5HZpT7PZOTE4fTOUZqwBgTA8QDKyrZPcQYs9YYs8AY07NeA2vcLPCFMWa1Mea2Svar39ePiVT94a2+X3faW2uzoexDHmhXyTF6D9S9m4AFVew71TlKzs6d7qmpM6uYIqZ+X7eGAnuttdur2K9+X0sqXFs2+HO+kjYwlWyrOGf0dI6Rs2SMaQ58CNxjrT1UYfcaINpa2xd4AfiovuNrxM631vYDRgN3uKdzlKd+X8eMMQHAlcAHlexW33ee3gN1yBjzZ6AEeKeKQ051jpIz939AZyAOyAZmVHKM+n3d+jXVj7Kp39eCU1xbVvmwSrZ5TN9X0laWRXcs93skkHUWx8hZMMb4U/amesdaO7fifmvtIWvtYffP8wF/Y0ybeg6zUbLWZrn/zQHmUTYtoDz1+7o3Glhjrd1bcYf6fp3b+9N0X/e/OZUco/dAHTHG3ABcDlxnq7i5/jTOUXKGrLV7rbWl1loX8BqVt6n6fR0xxvgB44A5VR2jfl9zVVxbNvhzvpK2spsMuxhjOrm/9Z4IfFLhmE+A602ZwZTdPJpd34E2Nu553a8Dm621/6jimA7u4zDGDKSsz+bWX5SNkzEmyH2DLsaYIOBSYEOFw9Tv616V37iq79e5T4Ab3D/fAHxcyTGn8/kgZ8gYMwp4ALjSWnu0imNO5xwlZ6jCfcljqbxN1e/rzghgi7U2s7Kd6vc1V821ZYM/5/s5HYDT3NWr7gQWAb7ATGvtRmPMZPf+l4H5lFXQ2wEcBSY5FW8jcz7wO2C9+bn07XQgCk60/Xjg98aYEuAYMLGqb2XljLQH5rlzAj/gXWvtQvX7+mOMaUZZharby20r3/7q+7XEGPMekAC0McZkAn8FngDeN8bcDKQDE9zHhgP/staOqerzwYm/oaGqou2nAYHAl+5z0HJr7eTybU8V5ygH/oQGq4q2TzDGxFE25SsV9/lH/b52Vdb21trXqeQeZvX7WlfVtWWDP+d7fcl/ERERERERT6bpkSIiIiIiIh5MSZuIiIiIiIgHU9ImIiIiIiLiwZS0iYiIiIiIeDAlbSIiIiIiIh5MSZuIiIiIiIgHU9ImIiIiIiLiwf4f3eGfb62uPugAAAAASUVORK5CYII=", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "plt.figure(figsize=(15,6))\n", "plt.cla()\n", "env.render()\n", "plt.show()" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[919.390869140625,\n", " 488.588623046875,\n", " 626.90869140625,\n", " 29.600830078125,\n", " -8.8203125,\n", " 166.931396484375]" ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ "env._trade_history" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "351" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "len(np.unique(state_history, return_counts=True)[1])\n", "# count = 0\n", "# for i in range(len(state_history)):\n", "# if state_history[i] == 1987:\n", "# count +=1\n", "# count" ] }, { "cell_type": "code", "execution_count": 438, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "352" ] }, "execution_count": 438, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Qtable_trading[1987]\n", "len(np.unique(env.signal_features))" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [], "source": [ "def evaluate_agent(env, max_steps, n_eval_episodes, Q):\n", " \"\"\"\n", " Evaluate the agent for ``n_eval_episodes`` episodes and returns average reward and std of reward.\n", " :param env: The evaluation environment\n", " :param n_eval_episodes: Number of episode to evaluate the agent\n", " :param Q: The Q-table\n", " :param seed: The evaluation seed array (for taxi-v3)\n", " \"\"\"\n", " episode_rewards = []\n", " episode_profits = []\n", " for episode in tqdm(range(n_eval_episodes)):\n", " state = env.reset()\n", " step = 0\n", " done = False\n", " total_rewards_ep = 0\n", " total_profit_ep = 0\n", " \n", " for step in range(max_steps):\n", " # Take the action (index) that have the maximum expected future reward given that state\n", " action = greedy_policy(Q, state)\n", " new_state, reward, done, info = env.step(action)\n", " total_rewards_ep += reward\n", " \n", " if done:\n", " break\n", " state = new_state\n", "\n", " episode_rewards.append(total_rewards_ep)\n", " episode_profits.append(env.history['total_profit'][-1])\n", " # print(env.history)\n", " # env.render()\n", " # assert 0\n", "\n", " mean_reward = np.mean(episode_rewards)\n", " std_reward = np.std(episode_rewards)\n", " mean_profit = np.mean(episode_profits)\n", " std_profit = np.std(episode_profits)\n", "\n", " return mean_reward, std_reward, mean_profit, std_profit" ] }, { "cell_type": "code", "execution_count": 75, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "746362c4808b4d068d499fd7b96419b0", "version_major": 2, "version_minor": 0 }, "text/plain": [ " 0%| | 0/1000 [00:00" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "plt.figure(figsize=(15,6))\n", "plt.cla()\n", "env_test.render()" ] }, { "cell_type": "code", "execution_count": 77, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "173 151 0.8728323699421965\n" ] } ], "source": [ "def count_equal(env, Qtable):\n", " count=0\n", " for i in env.signal_features:\n", " if abs(np.max(Qtable[i])) > 0:\n", " count+=1\n", " # else:\n", " # print(i)\n", " # assert 0\n", " \n", " print(len(env.signal_features), count, count / len(env.signal_features))\n", "\n", "count_equal(env_test, Qtable_trading)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "colab": { "provenance": [] }, "kernelspec": { "display_name": "Python 3.8.13 ('rl2')", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.13" }, "orig_nbformat": 4, "vscode": { "interpreter": { "hash": "cd60ab8388a66026f336166410d6a8a46ddf65ece2e85ad2d46c8b98d87580d1" } }, "widgets": { "application/vnd.jupyter.widget-state+json": { "01a2dbcb714e40148b41c761fcf43147": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": { "_model_module": "@jupyter-widgets/base", "_model_module_version": "1.2.0", "_model_name": "LayoutModel", "_view_count": null, "_view_module": "@jupyter-widgets/base", "_view_module_version": "1.2.0", "_view_name": "LayoutView", "align_content": null, "align_items": null, "align_self": null, "border": null, "bottom": null, "display": null, "flex": null, "flex_flow": null, "grid_area": null, "grid_auto_columns": null, "grid_auto_flow": null, "grid_auto_rows": null, "grid_column": null, "grid_gap": null, "grid_row": null, "grid_template_areas": null, "grid_template_columns": null, "grid_template_rows": null, "height": null, "justify_content": null, "justify_items": null, "left": null, "margin": null, "max_height": null, "max_width": null, "min_height": null, "min_width": null, "object_fit": null, "object_position": null, "order": null, "overflow": null, "overflow_x": null, "overflow_y": null, "padding": null, "right": null, "top": null, "visibility": null, "width": null } }, "20b0f38ec3234ff28a62a286cd57b933": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "PasswordModel", "state": { "_dom_classes": [], "_model_module": "@jupyter-widgets/controls", "_model_module_version": "1.5.0", "_model_name": "PasswordModel", "_view_count": null, "_view_module": "@jupyter-widgets/controls", "_view_module_version": "1.5.0", "_view_name": "PasswordView", "continuous_update": true, "description": "Token:", "description_tooltip": null, "disabled": false, "layout": "IPY_MODEL_01a2dbcb714e40148b41c761fcf43147", "placeholder": "​", "style": "IPY_MODEL_90c874e91b304ee1a7ef147767ac00ce", "value": "" } }, "270cbb5d6e9c4b1e9e2f39c8b3b0c15f": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "VBoxModel", "state": { "_dom_classes": [], "_model_module": "@jupyter-widgets/controls", "_model_module_version": "1.5.0", "_model_name": "VBoxModel", "_view_count": null, "_view_module": "@jupyter-widgets/controls", "_view_module_version": "1.5.0", "_view_name": "VBoxView", "box_style": "", "children": [ "IPY_MODEL_a02224a43d8d4af3bd31d326540d25da", "IPY_MODEL_20b0f38ec3234ff28a62a286cd57b933", "IPY_MODEL_f6c845330d6743c0b35c2c7ad834de77", "IPY_MODEL_f1675c09d16a4251b403f9c56255f168", "IPY_MODEL_c1a82965ae26479a98e4fdbde1e64ec2" ], "layout": "IPY_MODEL_3fa248114ac24656ba74923936a94d2d" } }, "2dc5fa9aa3334dfcbdee9c238f2ef60b": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "DescriptionStyleModel", "state": { "_model_module": "@jupyter-widgets/controls", "_model_module_version": "1.5.0", "_model_name": "DescriptionStyleModel", "_view_count": null, "_view_module": "@jupyter-widgets/base", "_view_module_version": "1.2.0", "_view_name": "StyleView", "description_width": "" } }, "3e753b0212644990b558c68853ff2041": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": { "_model_module": "@jupyter-widgets/base", "_model_module_version": "1.2.0", "_model_name": "LayoutModel", "_view_count": null, "_view_module": "@jupyter-widgets/base", "_view_module_version": "1.2.0", "_view_name": "LayoutView", "align_content": null, "align_items": null, "align_self": null, "border": null, "bottom": null, "display": null, "flex": null, "flex_flow": null, "grid_area": null, "grid_auto_columns": null, "grid_auto_flow": null, "grid_auto_rows": null, "grid_column": null, "grid_gap": null, "grid_row": null, "grid_template_areas": null, "grid_template_columns": null, "grid_template_rows": null, "height": null, "justify_content": null, "justify_items": null, "left": null, "margin": null, "max_height": null, "max_width": null, "min_height": null, "min_width": null, "object_fit": null, "object_position": null, "order": null, "overflow": null, "overflow_x": null, "overflow_y": null, "padding": null, "right": null, "top": null, "visibility": null, "width": null } }, "3fa248114ac24656ba74923936a94d2d": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": { "_model_module": "@jupyter-widgets/base", "_model_module_version": "1.2.0", "_model_name": "LayoutModel", "_view_count": null, "_view_module": "@jupyter-widgets/base", "_view_module_version": "1.2.0", "_view_name": "LayoutView", "align_content": null, "align_items": "center", "align_self": null, "border": null, "bottom": null, "display": "flex", "flex": null, "flex_flow": "column", "grid_area": null, "grid_auto_columns": null, "grid_auto_flow": null, "grid_auto_rows": null, "grid_column": null, "grid_gap": null, "grid_row": null, "grid_template_areas": null, "grid_template_columns": null, "grid_template_rows": null, "height": null, "justify_content": null, "justify_items": null, "left": null, "margin": null, "max_height": null, "max_width": null, "min_height": null, "min_width": null, "object_fit": null, "object_position": null, "order": null, "overflow": null, "overflow_x": null, "overflow_y": null, "padding": null, "right": null, "top": null, "visibility": null, "width": "50%" } }, "42d140b838b844819bc127afc1b7bc84": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "DescriptionStyleModel", "state": { "_model_module": "@jupyter-widgets/controls", "_model_module_version": "1.5.0", "_model_name": "DescriptionStyleModel", "_view_count": null, "_view_module": "@jupyter-widgets/base", "_view_module_version": "1.2.0", "_view_name": "StyleView", "description_width": "" } }, "90c874e91b304ee1a7ef147767ac00ce": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "DescriptionStyleModel", "state": { "_model_module": "@jupyter-widgets/controls", "_model_module_version": "1.5.0", "_model_name": "DescriptionStyleModel", "_view_count": null, "_view_module": "@jupyter-widgets/base", "_view_module_version": "1.2.0", "_view_name": "StyleView", "description_width": "" } }, "9d847f9a7d47458d8cd57d9b599e47c6": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": { "_model_module": "@jupyter-widgets/base", "_model_module_version": "1.2.0", "_model_name": "LayoutModel", "_view_count": null, "_view_module": "@jupyter-widgets/base", "_view_module_version": "1.2.0", "_view_name": "LayoutView", "align_content": null, "align_items": null, "align_self": null, "border": null, "bottom": null, "display": null, "flex": null, "flex_flow": null, "grid_area": null, "grid_auto_columns": null, "grid_auto_flow": null, "grid_auto_rows": null, "grid_column": null, "grid_gap": null, "grid_row": null, "grid_template_areas": null, "grid_template_columns": null, "grid_template_rows": null, "height": null, "justify_content": null, "justify_items": null, "left": null, "margin": null, "max_height": null, "max_width": null, "min_height": null, "min_width": null, "object_fit": null, "object_position": null, "order": null, "overflow": null, "overflow_x": null, "overflow_y": null, "padding": null, "right": null, "top": null, "visibility": null, "width": null } }, "a02224a43d8d4af3bd31d326540d25da": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "HTMLModel", "state": { "_dom_classes": [], "_model_module": "@jupyter-widgets/controls", "_model_module_version": "1.5.0", "_model_name": "HTMLModel", "_view_count": null, "_view_module": "@jupyter-widgets/controls", "_view_module_version": "1.5.0", "_view_name": "HTMLView", "description": "", "description_tooltip": null, "layout": "IPY_MODEL_caef095934ec47bbb8b64eab22049284", "placeholder": "​", "style": "IPY_MODEL_2dc5fa9aa3334dfcbdee9c238f2ef60b", "value": "

Copy a token from your Hugging Face\ntokens page and paste it below.
Immediately click login after copying\nyour token or it might be stored in plain text in this notebook file.
" } }, "a2cfb91cf66447d7899292854bd64a07": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": { "_model_module": "@jupyter-widgets/base", "_model_module_version": "1.2.0", "_model_name": "LayoutModel", "_view_count": null, "_view_module": "@jupyter-widgets/base", "_view_module_version": "1.2.0", "_view_name": "LayoutView", "align_content": null, "align_items": null, "align_self": null, "border": null, "bottom": null, "display": null, "flex": null, "flex_flow": null, "grid_area": null, "grid_auto_columns": null, "grid_auto_flow": null, "grid_auto_rows": null, "grid_column": null, "grid_gap": null, "grid_row": null, "grid_template_areas": null, "grid_template_columns": null, "grid_template_rows": null, "height": null, "justify_content": null, "justify_items": null, "left": null, "margin": null, "max_height": null, "max_width": null, "min_height": null, "min_width": null, "object_fit": null, "object_position": null, "order": null, "overflow": null, "overflow_x": null, "overflow_y": null, "padding": null, "right": null, "top": null, "visibility": null, "width": null } }, "c1a82965ae26479a98e4fdbde1e64ec2": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "HTMLModel", "state": { "_dom_classes": [], "_model_module": "@jupyter-widgets/controls", "_model_module_version": "1.5.0", "_model_name": "HTMLModel", "_view_count": null, "_view_module": "@jupyter-widgets/controls", "_view_module_version": "1.5.0", "_view_name": "HTMLView", "description": "", "description_tooltip": null, "layout": "IPY_MODEL_9d847f9a7d47458d8cd57d9b599e47c6", "placeholder": "​", "style": "IPY_MODEL_42d140b838b844819bc127afc1b7bc84", "value": "\nPro Tip: If you don't already have one, you can create a dedicated\n'notebooks' token with 'write' access, that you can then easily reuse for all\nnotebooks. " } }, "caef095934ec47bbb8b64eab22049284": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": { "_model_module": "@jupyter-widgets/base", "_model_module_version": "1.2.0", "_model_name": "LayoutModel", "_view_count": null, "_view_module": "@jupyter-widgets/base", "_view_module_version": "1.2.0", "_view_name": "LayoutView", "align_content": null, "align_items": null, "align_self": null, "border": null, "bottom": null, "display": null, "flex": null, "flex_flow": null, "grid_area": null, "grid_auto_columns": null, "grid_auto_flow": null, "grid_auto_rows": null, "grid_column": null, "grid_gap": null, "grid_row": null, "grid_template_areas": null, "grid_template_columns": null, "grid_template_rows": null, "height": null, "justify_content": null, "justify_items": null, "left": null, "margin": null, "max_height": null, "max_width": null, "min_height": null, "min_width": null, "object_fit": null, "object_position": null, "order": null, "overflow": null, "overflow_x": null, "overflow_y": null, "padding": null, "right": null, "top": null, "visibility": null, "width": null } }, "eaba3f1de4444aabadfea2a3dadb1d80": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "DescriptionStyleModel", "state": { "_model_module": "@jupyter-widgets/controls", "_model_module_version": "1.5.0", "_model_name": "DescriptionStyleModel", "_view_count": null, "_view_module": "@jupyter-widgets/base", "_view_module_version": "1.2.0", "_view_name": "StyleView", "description_width": "" } }, "ee4a21bedc504171ad09d205d634b528": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "ButtonStyleModel", "state": { "_model_module": "@jupyter-widgets/controls", "_model_module_version": "1.5.0", "_model_name": "ButtonStyleModel", "_view_count": null, "_view_module": "@jupyter-widgets/base", "_view_module_version": "1.2.0", "_view_name": "StyleView", "button_color": null, "font_weight": "" } }, "f1675c09d16a4251b403f9c56255f168": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "ButtonModel", "state": { "_dom_classes": [], "_model_module": "@jupyter-widgets/controls", "_model_module_version": "1.5.0", "_model_name": "ButtonModel", "_view_count": null, "_view_module": "@jupyter-widgets/controls", "_view_module_version": "1.5.0", "_view_name": "ButtonView", "button_style": "", "description": "Login", "disabled": false, "icon": "", "layout": "IPY_MODEL_a2cfb91cf66447d7899292854bd64a07", "style": "IPY_MODEL_ee4a21bedc504171ad09d205d634b528", "tooltip": "" } }, "f6c845330d6743c0b35c2c7ad834de77": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "CheckboxModel", "state": { "_dom_classes": [], "_model_module": "@jupyter-widgets/controls", "_model_module_version": "1.5.0", "_model_name": "CheckboxModel", "_view_count": null, "_view_module": "@jupyter-widgets/controls", "_view_module_version": "1.5.0", "_view_name": "CheckboxView", "description": "Add token as git credential?", "description_tooltip": null, "disabled": false, "indent": true, "layout": "IPY_MODEL_3e753b0212644990b558c68853ff2041", "style": "IPY_MODEL_eaba3f1de4444aabadfea2a3dadb1d80", "value": true } } } } }, "nbformat": 4, "nbformat_minor": 0 }