Skip to content

Instantly share code, notes, and snippets.

@ritakurban
Created November 25, 2019 19:01
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save ritakurban/c9ebcbfa0be45952c99ccd199b57af3d to your computer and use it in GitHub Desktop.
Save ritakurban/c9ebcbfa0be45952c99ccd199b57af3d to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "rZ9VsnQv4wPm"
},
"source": [
"# Convolutional Sentiment Analysis\n",
"The notebook is based on this [tutorial](https://github.com/bentrevett/pytorch-sentiment-analysis/blob/master/4%20-%20Convolutional%20Sentiment%20Analysis.ipynb)"
]
},
{
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "rf-Rkgdr4wPq"
},
"source": [
"### Preparing Data"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {},
"outputs": [],
"source": [
"# Install packages\n",
"import torch\n",
"from torchtext import data\n",
"from torchtext import datasets\n",
"import torch.nn as nn\n",
"import torch.nn.functional as F\n",
"import torch.optim as optim\n",
"import random\n",
"import numpy as np\n",
"import spacy\n",
"import time\n",
"import matplotlib.pyplot as plt\n",
"\n",
"#Load English language\n",
"nlp = spacy.load('en')"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"colab": {},
"colab_type": "code",
"id": "UmHvoEZS4wPr"
},
"outputs": [],
"source": [
"# Load data from torchtext (identical to what we have in Kaggle)\n",
"train_data, test_data = datasets.IMDB.splits(TEXT, LABEL)\n",
"train_data, valid_data = train_data.split()\n",
"\n",
"# Initiate class instances with tokenizers\n",
"TEXT = data.Field(tokenize = 'spacy', batch_first = True)\n",
"LABEL = data.LabelField(dtype = torch.float)"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"colab": {},
"colab_type": "code",
"id": "uiRr2TaX4wPz"
},
"outputs": [],
"source": [
"# Select only the most important 30000 words\n",
"MAX_VOCAB_SIZE = 30_000\n",
"\n",
"# Build vocabularies\n",
"TEXT.build_vocab(train_data, \n",
" max_size = MAX_VOCAB_SIZE, \n",
" # Load pretrained embeddings\n",
" vectors = \"glove.6B.100d\", \n",
" # Set unknown vectors\n",
" unk_init = torch.Tensor.normal_)\n",
"\n",
"LABEL.build_vocab(train_data)"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"colab": {},
"colab_type": "code",
"id": "prLYAyhI4wP4"
},
"outputs": [],
"source": [
"BATCH_SIZE = 64\n",
"\n",
"device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n",
"\n",
"# Create PyTorch iterators to use in training/evaluation/testing\n",
"train_iterator, valid_iterator, test_iterator = data.BucketIterator.splits(\n",
" (train_data, valid_data, test_data), \n",
" batch_size = BATCH_SIZE, \n",
" device = device)"
]
},
{
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "v_87VK9S4wP7"
},
"source": [
"### Build Model\n",
"\n",
"We visualize our words in 2 dimensions, each word along one axis and the elements of the word embedding that corresponds to this word aross the other dimension.\n",
"\n",
"In the model, we will have different sizes of filters, heights of 1, 2, 3, 4 and 5, with 100 of each of them. The intuition is that we will be looking for the occurence of different bi-grams, tri-grams, 4-grams and 5-grams that are relevant for analysing sentiment of movie reviews.\n",
"\n",
"The idea behind max-pooling is that the maximum value is the \"most important\" feature for determining the sentiment of the review, which corresponds to the \"most important\" n-gram within the review that is identified through backprop.\n",
"\n",
"After getting 400 different n-grams, we concatenate them together into a single vector and pass them through a linear layer to predict the sentiment. We can think of the weights of this linear layer as \"weighting up the evidence\" from each of the 500 n-grams and making a final decision. "
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"colab": {},
"colab_type": "code",
"id": "TLvnIV5s4wQC"
},
"outputs": [],
"source": [
"class CNN_Text(nn.Module):\n",
" ''' Define network architecture and forward path. '''\n",
" def __init__(self, vocab_size, \n",
" vector_size, n_filters, \n",
" filter_sizes, output_dim, \n",
" dropout, pad_idx):\n",
" \n",
" super().__init__()\n",
" # Create word embeddings from the input words \n",
" self.embedding = nn.Embedding(vocab_size, vector_size, \n",
" padding_idx = pad_idx)\n",
" \n",
" # Specify convolutions with filters of different sizes (fs)\n",
" self.convs = nn.ModuleList([nn.Conv2d(in_channels = 1, \n",
" out_channels = n_filters, \n",
" kernel_size = (fs, vector_size)) \n",
" for fs in filter_sizes])\n",
" \n",
" # Add a fully connected layer for final predicitons\n",
" self.linear = nn.Linear(len(filter_sizes) * n_filters, output_dim)\n",
" \n",
" # Drop some of the nodes to increase robustness in training\n",
" self.dropout = nn.Dropout(dropout)\n",
" \n",
" \n",
" \n",
" def forward(self, text):\n",
" '''Forward path of the network.''' \n",
" # Get word embeddings and formt them for convolutions\n",
" embedded = self.embedding(text).unsqueeze(1)\n",
" \n",
" # Perform convolutions and apply activation functions\n",
" conved = [F.relu(conv(embedded)).squeeze(3) for conv in self.convs]\n",
" \n",
" # Pooling layer to reduce dimensionality \n",
" pooled = [F.max_pool1d(conv, conv.shape[2]).squeeze(2) for conv in conved]\n",
" \n",
" # Dropout layer\n",
" cat = self.dropout(torch.cat(pooled, dim = 1))\n",
" return self.linear(cat)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Initialize Pre-Trained Model"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"colab": {},
"colab_type": "code",
"id": "SRJUKMJl4wQI"
},
"outputs": [],
"source": [
"# Vocabulary size\n",
"INPUT_DIM = len(TEXT.vocab)\n",
"\n",
"# Vector size (lower-dimensional repr. of each word)\n",
"EMBEDDING_DIM = 100\n",
"\n",
"# Number of filters\n",
"N_FILTERS = 100\n",
"\n",
"# N-grams that we want to analuze using filters\n",
"FILTER_SIZES = [1, 2, 3, 4, 5]\n",
"\n",
"# Output of the linear layer (prob of a negative review)\n",
"OUTPUT_DIM = 1\n",
"\n",
"# Proportion of units to drop\n",
"DROPOUT = 0.5"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [],
"source": [
"# Initialize model and load pre-trained embeddings\n",
"model = CNN_Text(INPUT_DIM, EMBEDDING_DIM, \n",
" N_FILTERS, FILTER_SIZES, \n",
" OUTPUT_DIM, DROPOUT, PAD_IDX)\n",
"\n",
"model.embedding.weight.data.copy_(TEXT.vocab.vectors)\n",
"\n",
"# Zero the initial weights of the UNKnown and padding tokens.\n",
"UNK_IDX = TEXT.vocab.stoi[TEXT.unk_token]\n",
"\n",
"# The string token used as padding. Default: “<pad>”.\n",
"PAD_IDX = TEXT.vocab.stoi[TEXT.pad_token]\n",
"\n",
"model.embedding.weight.data[UNK_IDX] = torch.zeros(EMBEDDING_DIM)\n",
"model.embedding.weight.data[PAD_IDX] = torch.zeros(EMBEDDING_DIM)\n",
"model = model.to(device)"
]
},
{
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "-qmSokzB4wQc"
},
"source": [
"## Train & Evaluate Model"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {
"colab": {},
"colab_type": "code",
"id": "1F6-f5aJ4wQh"
},
"outputs": [],
"source": [
"# Helper functions\n",
"def accuracy(preds, y):\n",
" \"\"\" Return accuracy per batch. \"\"\"\n",
" correct = (torch.round(torch.sigmoid(preds)) == y).float() \n",
" return correct.sum() / len(correct)\n",
"\n",
"def epoch_time(start_time, end_time):\n",
" '''Track training time. '''\n",
" elapsed_time = end_time - start_time\n",
" elapsed_mins = int(elapsed_time / 60)\n",
" elapsed_secs = int(elapsed_time - (elapsed_mins * 60))\n",
" return elapsed_mins, elapsed_secs"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {
"colab": {},
"colab_type": "code",
"id": "SobuEXbx4wQp"
},
"outputs": [],
"source": [
"def train(model, iterator, optimizer, criterion):\n",
" '''Train the model with specified data, optimizer, and loss function. '''\n",
" epoch_loss = 0\n",
" epoch_acc = 0\n",
" \n",
" model.train()\n",
" \n",
" for batch in iterator:\n",
" \n",
" # Reset the gradient to not use them in multiple passes \n",
" optimizer.zero_grad()\n",
" \n",
" predictions = model(batch.text).squeeze(1)\n",
" \n",
" loss = criterion(predictions, batch.label)\n",
" \n",
" acc = accuracy(predictions, batch.label)\n",
" \n",
" # Backprop\n",
" loss.backward()\n",
" \n",
" # Optimize the weights\n",
" optimizer.step()\n",
" \n",
" # Record accuracy and loss\n",
" epoch_loss += loss.item()\n",
" epoch_acc += acc.item()\n",
" \n",
" return epoch_loss / len(iterator), epoch_acc / len(iterator)\n",
"\n",
"\n",
"def evaluate(model, iterator, criterion):\n",
" '''Evaluate model performance. '''\n",
" epoch_loss = 0\n",
" epoch_acc = 0\n",
" \n",
" # Turm off dropout while evaluating\n",
" model.eval()\n",
" \n",
" # No need to backprop in eval\n",
" with torch.no_grad():\n",
" \n",
" for batch in iterator:\n",
"\n",
" predictions = model(batch.text).squeeze(1)\n",
" \n",
" loss = criterion(predictions, batch.label)\n",
" \n",
" acc = accuracy(predictions, batch.label)\n",
"\n",
" epoch_loss += loss.item()\n",
" epoch_acc += acc.item()\n",
" \n",
" return epoch_loss / len(iterator), epoch_acc / len(iterator)"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [],
"source": [
"# Network optimizer\n",
"optimizer = optim.Adam(model.parameters())\n",
"\n",
"# Loss function\n",
"criterion = nn.BCEWithLogitsLoss()\n",
"\n",
"model = model.to(device)\n",
"criterion = criterion.to(device)"
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch: 1 | Epoch Time: 17m 41s\n",
"\tTrain Loss: 0.432 | Train Acc: 80.36%\n",
"\t Val. Loss: 0.370 | Val. Acc: 83.82%\n",
"Epoch: 2 | Epoch Time: 17m 45s\n",
"\tTrain Loss: 0.313 | Train Acc: 86.76%\n",
"\t Val. Loss: 0.322 | Val. Acc: 86.13%\n",
"Epoch: 3 | Epoch Time: 18m 48s\n",
"\tTrain Loss: 0.227 | Train Acc: 90.81%\n",
"\t Val. Loss: 0.306 | Val. Acc: 87.00%\n",
"Epoch: 4 | Epoch Time: 19m 41s\n",
"\tTrain Loss: 0.161 | Train Acc: 93.89%\n",
"\t Val. Loss: 0.312 | Val. Acc: 87.49%\n",
"Epoch: 5 | Epoch Time: 18m 59s\n",
"\tTrain Loss: 0.117 | Train Acc: 95.79%\n",
"\t Val. Loss: 0.333 | Val. Acc: 87.10%\n",
"Epoch: 6 | Epoch Time: 78m 44s\n",
"\tTrain Loss: 0.081 | Train Acc: 97.20%\n",
"\t Val. Loss: 0.349 | Val. Acc: 87.66%\n",
"Epoch: 7 | Epoch Time: 46m 50s\n",
"\tTrain Loss: 0.052 | Train Acc: 98.36%\n",
"\t Val. Loss: 0.379 | Val. Acc: 87.49%\n",
"Epoch: 8 | Epoch Time: 55m 27s\n",
"\tTrain Loss: 0.039 | Train Acc: 98.76%\n",
"\t Val. Loss: 0.414 | Val. Acc: 87.31%\n",
"Epoch: 9 | Epoch Time: 21m 37s\n",
"\tTrain Loss: 0.030 | Train Acc: 99.18%\n",
"\t Val. Loss: 0.440 | Val. Acc: 87.17%\n",
"Epoch: 10 | Epoch Time: 18m 9s\n",
"\tTrain Loss: 0.023 | Train Acc: 99.27%\n",
"\t Val. Loss: 0.468 | Val. Acc: 87.30%\n"
]
}
],
"source": [
"# Training loop\n",
"N_EPOCHS = 10\n",
"\n",
"best_valid_loss = float('inf')\n",
"val_loss = []\n",
"val_acc = []\n",
"tr_loss = []\n",
"tr_acc = []\n",
"\n",
"for epoch in range(N_EPOCHS):\n",
" \n",
" # Calculate training time\n",
" start_time = time.time()\n",
" \n",
" # Get epoch losses and accuracies \n",
" train_loss, train_acc = train(model, train_iterator, optimizer, criterion)\n",
" valid_loss, valid_acc = evaluate(model, valid_iterator, criterion)\n",
" \n",
" end_time = time.time()\n",
" epoch_mins, epoch_secs = epoch_time(start_time, end_time)\n",
" \n",
" # Save training metrics\n",
" val_loss.append(valid_loss)\n",
" val_acc.append(valid_acc)\n",
" tr_loss.append(train_loss)\n",
" tr_acc.append(train_acc)\n",
" \n",
" if valid_loss < best_valid_loss:\n",
" best_valid_loss = valid_loss\n",
" torch.save(model.state_dict(), 'CNN-model.pt')\n",
" \n",
" print(f'Epoch: {epoch+1:2} | Epoch Time: {epoch_mins}m {epoch_secs}s')\n",
" print(f'\\tTrain Loss: {train_loss:.3f} | Train Acc: {train_acc*100:.2f}%')\n",
" print(f'\\t Val. Loss: {valid_loss:.3f} | Val. Acc: {valid_acc*100:.2f}%')"
]
},
{
"cell_type": "code",
"execution_count": 39,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAA3gAAAFNCAYAAABSRs15AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjEsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy8QZhcZAAAgAElEQVR4nOzdd3gVVf7H8fdJDyGdUBOS0BN6CEWQXkQQUECKIMWC+rPt2hbLWmDd1bWsZV3XBoKrIIgFCyAoip0kSBMUUAJJQFpCAEMg5fz+mEsMGHqSm/J5Pc99cu/MmTPfoWTud04z1lpERERERESk8vNwdwAiIiIiIiJSOpTgiYiIiIiIVBFK8ERERERERKoIJXgiIiIiIiJVhBI8ERERERGRKkIJnoiIiIiISBWhBE9EREREqiVjzCFjTCN3xyFSmpTgiZQRY0yqMaafu+MQEREpD8aYz4wxWcYYX3fHcqastTWttb+4Ow6R0qQET0RERETOizEmBugOWGBoOZ7Xq7zOJVJZKMETKWfGmGuNMVuMMZnGmIXGmPqu7cYY8y9jzG5jzAFjzDpjTCvXvkHGmA3GmIPGmAxjzB3F6rvEGLPaGLPfGPO1MaZNsX1/cZU/aIz5yRjTt/yvWEREqoEJwLfAq8DEYxuNMf7GmCeMMduMMdnGmC+NMf6ufRe67lv7jTFpxphJru2fGWOuKVbHJGPMl8U+W2PMjcaYzcBm17anXXUcMMakGGO6FyvvaYy5xxjzs+t+mGKMiSpWVxPXe19jzOPGmO3GmF3GmP8Wi7WWMeYDV6yZxpgvjDH6Hi0Vkv5hipQjY0wf4B/AKKAesA2Y69o9AOgBNAOCXWX2ufa9AlxnrQ0EWgGfuuprD8wArgPCgReAha6bVHPgJqCj67iLgNQyvkQREameJgCvu14XGWPquLY/DnQAugJhwF1AoTEmGlgEPAtEAO2A1WdxvkuBzkC863OSq44w4A1gvjHGz7XvNmAsMAgIAq4Cckqo8xGce3A7oAnQALjfte92IN0Vax3gHpzWSpEKRwmeSPkaB8yw1q6y1h4B7gYucHVtyQMCgRaAsdZutNbudB2XB8QbY4KstVnW2lWu7VOAF6y131lrC6y1s4AjQBegAPB1HedtrU211v5cXhcqIiLVgzHmQiAamGetTQF+Bq5wtXBdBdxqrc1w3ae+dt3/rgCWWWvnWGvzrLX7rLVnk+D9w1qbaa09DGCt/Z+rjnxr7RM497/mrrLXAPdZa3+yjjXW2n3FKzPGGJx76p9d9R4E/g6McRXJw3kwG+2K9wtrrRI8qZCU4ImUr/o4rXYAWGsP4bTSNbDWfgr8G3gO2G2MedEYE+QqOgLnyeM2Y8znxpgLXNujgdtdXUb2G2P2A1FAfWvtFuBPwIOu+uYe6w4qIiJSiiYCH1tr97o+v+HaVgvww0n4ThR1ku1nKq34B2PMHcaYja5uoPtxesLUOotzRQA1gJRi99PFru0AjwFbgI+NMb8YY6aeR+wiZUoJnkj52oGTlAFgjAnA6VqZAWCtfcZa2wGny0kz4E7X9iRr7TCgNvAuMM9VRRrwsLU2pNirhrV2juu4N6y1x56sWuDR8rhIERGpHlxj1EYBPY0xvxpjfgX+DLTFafHKBRqXcGjaSbYD/IaTbB1Tt4QyRa1nrvF2d7niCLXWhgDZgDmDcx2zFzgMtCx2Pw221tYEsNYetNbebq1thDOJzG0a1y4VlRI8kbLlbYzxO/YC5gCTjTHtXNNI/x34zlqbaozpaIzpbIzxxrm55eKMU/AxxowzxgRba/OAA0Chq/6XgOtdxxljTIAxZrAxJtAY09wY08d1nlycG1fhiQGKiIich0txhgTE44xdawfEAV/gjMubATxpjKnvmuzkAtd96XWgnzFmlDHGyxgTboxp56pzNTDcGFPDNQHK1aeJIRDIB/YAXsaY+3HG2h3zMjDdGNPUda9sY4wJL16BtbYQ5576L2NMbQBjTANjzEWu95cYY5q4unJmu65Z91SpkJTgiZStj3ASq2OvXsBfgQXATpwnisf69wfh3FyycLpx7sPpEgJwJZBqjDkAXI8zlg9rbTJwLU7Xziyc7iOTXMf44gwY3wv8itP6d3dZXKSIiFRbE4GZ1trt1tpfj71w7kvjgKnAOpxJUDJxepJ4WGu34ww9uN21fTVOqx/Av4CjwC5gFk4yeCpLcLpTbsK5f+ZyfBfOJ3F6vnyM85D0FcC/hHr+gnMf/dZ1v13G7+P4mro+HwK+Af5jrV1+mrhE3MJofKiIiIiIiEjVoBY8ERERERGRKkIJnoiIiIiISBWhBE9ERERERKSKUIInIiIiIiJSRSjBExEROQ/GmBnGmN3GmPUn2W+MMc8YY7YYY9YaYxKK7ZtojNnsek0str2DMWad65hnXFOzi4iInFalm0WzVq1aNiYmxt1hiIhIOUhJSdlrrY1wdxynYozpgTN1+mxrbasS9g8CbsaZEr4z8LS1trMxJgxIBhJxFm1OATpYa7OMMSuBW4DvcJZbecZau+h0segeKSJSPZzq/uhV3sGcr5iYGJKTk90dhoiIlANjzDZ3x3A61toVxpiYUxQZhpP8WZz1tUKMMfVw1sVcaq3NBDDGLAUGGmM+A4Kstd+6ts/GWUz6tAme7pEiItXDqe6P6qIpIiJSthpw/KLL6a5tp9qeXsJ2ERGR01KCJyIiUokZY6YYY5KNMcl79uxxdzgiIuJmSvBERETKVgYQVexzpGvbqbZHlrC9RNbaF621idbaxIiICj1cUUREykGlG4MnIiJSySwEbjLGzMWZZCXbWrvTGLME+LsxJtRVbgBwt7U20xhzwBjTBWeSlQnAs+d68ry8PNLT08nNzT3Py5Cqws/Pj8jISLy9vd0dioiUASV4IiIi58EYMwdnwpRaxph04AHAG8Ba+1+cWTAHAVuAHGCya1+mMWY6kOSqatqxCVeA/wNeBfxxJlc57QQrJ5Oenk5gYCAxMTFotQWx1rJv3z7S09OJjY11dzgiUgaU4ImIiJwHa+3Y0+y3wI0n2TcDmFHC9mTgD0sunIvc3Fwld1LEGEN4eDgarylSdWkMnoiISBWn5E6K078HkapNCZ6IiIiUmd69e7NkyZLjtj311FPccMMNpzyuZs2aAOzYsYORI0eWWKZXr16nXffvqaeeIicnp+jzoEGD2L9//5mELiJSKSnBExERkTIzduxY5s6de9y2uXPnMnbsKXu2Fqlfvz5vvfXWOZ//xATvo48+IiQk5JzrK2/WWgoLC90dhohUIkrwRESkVG3edZA3vtvu7jCkghg5ciQffvghR48eBSA1NZUdO3bQvXt3Dh06RN++fUlISKB169a89957fzg+NTWVVq2c4YiHDx9mzJgxxMXFcdlll3H48OGicjfccAOJiYm0bNmSBx54AIBnnnmGHTt20Lt3b3r37g1ATEwMe/fuBeDJJ5+kVatWtGrViqeeeqrofHFxcVx77bW0bNmSAQMGHHeeY95//306d+5M+/bt6devH7t27QLg0KFDTJ48mdatW9OmTRsWLFgAwOLFi0lISKBt27b07dsXgAcffJDHH3+8qM5WrVqRmppKamoqzZs3Z8KECbRq1Yq0tLQSrw8gKSmJrl270rZtWzp16sTBgwfp0aMHq1evLipz4YUXsmbNmrP6exORM1RYAEdzICcTDuyAzF9g90bY8T1s/xZ++Qw2LYEN78HaebBqNqSnlGlImmRFRETOW87RfD5Yu5M3k9JI2ZaFr5cHg9vUI9hf07BXd2FhYXTq1IlFixYxbNgw5s6dy6hRozDG4OfnxzvvvENQUBB79+6lS5cuDB069KRjxJ5//nlq1KjBxo0bWbt2LQkJCUX7Hn74YcLCwigoKKBv376sXbuWW265hSeffJLly5dTq1at4+pKSUlh5syZfPfdd1hr6dy5Mz179iQ0NJTNmzczZ84cXnrpJUaNGsWCBQsYP378ccdfeOGFfPvttxhjePnll/nnP//JE088wfTp0wkODmbdunUAZGVlsWfPHq699lpWrFhBbGwsmZmZnM7mzZuZNWsWXbp0Oen1tWjRgtGjR/Pmm2/SsWNHDhw4gL+/P1dffTWvvvoqTz31FJs2bSI3N5e2bdue1d+bSKWWkwkHMiAvF/JzIf+I6+ex94eLbTvNzz/UccLPwryzj6/brRDZofSv20UJnoiInLN16dnMSdrOwtU7OHQkn8YRAdw3OI7L2jdQclcBPfT+D2zYcaBU64yvH8QDQ1qessyxbprHErxXXnkFcLof3nPPPaxYsQIPDw8yMjLYtWsXdevWLbGeFStWcMsttwDQpk0b2rRpU7Rv3rx5vPjii+Tn57Nz5042bNhw3P4Tffnll1x22WUEBAQAMHz4cL744guGDh1KbGws7dq1A6BDhw6kpqb+4fj09HRGjx7Nzp07OXr0aNGSA8uWLTuuS2poaCjvv/8+PXr0KCoTFhZ2yj8vgOjo6KLk7mTXZ4yhXr16dOzYEYCgoCAALr/8cqZPn85jjz3GjBkzmDRp0mnPJ1KpWAs5+5zWssxfYN/Pv7/P/AVyz3KcrZcfePme5Kcf1Ag//vNJyxb76e1fcl1evuAXXDZ/Lscup0xrFxGRKudAbh7vfZ/B3KQ0fthxAD9vDwa3rs+YTlEkRodqhj75g2HDhvHnP/+ZVatWkZOTQ4cOzpPr119/nT179pCSkoK3tzcxMTHntCD71q1befzxx0lKSiI0NJRJkyad18Luvr6+Re89PT1L7KJ58803c9tttzF06FA+++wzHnzwwbM+j5eX13Hj64rHfCzxhLO/vho1atC/f3/ee+895s2bR0pK2XYHEykT1sJve0pO4DK3wpHs38saDwiOhLDG0GoEhDWCkCjwDvhjkuV9QpLm6QNV7L6lBE9ERE7LWkvytizmrkzjw3U7yM0rJL5eENOHtWRoO7XWVRana2krKzVr1qR3795cddVVx02ukp2dTe3atfH29mb58uVs27btlPX06NGDN954gz59+rB+/XrWrl0LwIEDBwgICCA4OJhdu3axaNEievXqBUBgYCAHDx78QxfN7t27M2nSJKZOnYq1lnfeeYfXXnvtjK8pOzubBg0aADBr1qyi7f379+e5554rGtOXlZVFly5d+L//+z+2bt1a1EUzLCyMmJgYPvjgAwBWrVrF1q1bSzzXya6vefPm7Ny5k6SkJDp27MjBgwfx9/fHy8uLa665hiFDhtC9e3dCQ0PP+LpEypW1cGhXCQncz04Sd/TQ72WNJ4Q0dJK3yI4Q3th5H9bI2e7le/LzVDNK8ERE5KT2HTrCO67Wui27D1HT14vhCZGM7diQ1pFl28VEqpaxY8dy2WWXHdd9cdy4cQwZMoTWrVuTmJhIixYtTlnHDTfcwOTJk4mLiyMuLq6oJbBt27a0b9+eFi1aEBUVRbdu3YqOmTJlCgMHDqR+/fosX768aHtCQgKTJk2iU6dOAFxzzTW0b9++xO6YJXnwwQe5/PLLCQ0NpU+fPkXJ2X333ceNN95Iq1at8PT05IEHHmD48OG8+OKLDB8+nMLCQmrXrs3SpUsZMWIEs2fPpmXLlnTu3JlmzZqVeK6TXZ+Pjw9vvvkmN998M4cPH8bf359ly5ZRs2ZNOnToQFBQEJMnTz6j6xEpM4WFcHBnyQlc5i+Q9/sst3h4QUi0k7xFd/s9gTuWxHnqYeKZMNZad8dwVhITE+3p1rwREZFzV1ho+frnfcxJ2s7HP/xKXoEloWEIYzo15JI29ajhU37PBo0xKdbaxHI7YSVX0j1y48aNxMXFuSkicZcdO3bQq1cvfvzxRzw8/jhpuv5dSKkqLHQmNSkpgcvc6kxqcoynD4TGHJ+8HXsFR4Gn2p/OxKnuj/oTFBERAHYdyGV+chpvJqeRlnmYkBreXNklhjGdomhWJ9Dd4YnIGZo9ezb33nsvTz75ZInJncg5yT8C+7c7CVtWKmRtdb13/Sw48ntZT18Ii3WStsZ9TkjiIsHD022XUR0owRMRqcbyCwr57Kc9zE3azqc/7qbQQtfG4dx5UQsualkHXy/dhEUqmwkTJjBhwgR3hyGV0eGsEhK4VOeVnQ4U6/nnXQNCYyG8CTQd8HsCF94YAuuDHi64jRI8EZFqKC0zhzeT0pifksauA0eICPTl+p6NGd0xiujwgNNXICIilc+xrpQntsBlpTrvT1xeIKC20xIX3c3VrTLWSerCYiEgosrNPllVKMETEakmjuQXsHTDLt5MSuOLzXvxMNCreW2mD4uid4vaeHvqaauISKWXd/j3VrfiXSizUmH/Nig4+ntZDy9n8pLQWGiVcHwCFxINvjXddBFyPpTgiYhUcVt2H2TuyjTe/j6DzN+O0iDEn9v6N+PyxEjqBfu7OzwRETkbxxb5LimBy9rqzFhZnG+Q0/pWOw5aDPo9gQuNgaBITWpSBelvVESkCjp8tIAP1+3kzaTtJKVm4eVhGNCyDqM7NuTCJrXw9FC3GhGRSmHnGvjhXdi3xZXMpcLRg8eXCazvJG2N+xyfwIXGQo0wdaWsZpTgiYhUIeszsnkzKY13V2dwMDefRrUCuGdQC4YnRFKrphaBlfK3b98++vbtC8Cvv/6Kp6cnERERAKxcuRIfH5/T1jF58mSmTp1K8+bNT1rmueeeIyQkhHHjxpVO4CLulHsA1r8FKbNg52rw8P59DFzDrr93pQyNgdBo8FZvDPmdEjwRkUruYG4eC9fsYO7KNNZlZOPr5cHg1vUY3TGKTrFhGD25FTcKDw9n9erVgLM4eM2aNbnjjjuOK2OtxVp70in9Z86cedrz3HjjjecfbDnLz8/Hy0tfxcTFWkhPhlWvwvq3nQXA67SCQY9D68vBP8TdEUoloRH1IiKVkLWWlG2Z3Dl/DZ0e/oR731lPXkEhDw1tycp7+vHk6HZ0bhSu5E4qrC1bthAfH8+4ceNo2bIlO3fuZMqUKSQmJtKyZUumTZtWVPbCCy9k9erV5OfnExISwtSpU2nbti0XXHABu3fvBuC+++7jqaeeKio/depUOnXqRPPmzfn6668B+O233xgxYgTx8fGMHDmSxMTEouSzuAceeICOHTvSqlUrrr/+eqx1pobftGkTffr0oW3btiQkJJCamgrA3//+d1q3bk3btm259957j4sZnJbLJk2aAPDyyy9z6aWX0rt3by666CIOHDhAnz59SEhIoE2bNnzwwQdFccycOZM2bdrQtm1bJk+eTHZ2No0aNSI/Px+ArKys4z5LJZWTCd/+F57vCq/0g/XvQOuRcM2ncP2X0OlaJXdyVvTYSESkEtl9MJd3VmUwLzmNn/f8RoCPJ5e2r8+Yjg1pExmshE4qlR9//JHZs2eTmJgIwCOPPEJYWBj5+fn07t2bkSNHEh8ff9wx2dnZ9OzZk0ceeYTbbruNGTNmMHXq1D/Uba1l5cqVLFy4kGnTprF48WKeffZZ6taty4IFC1izZg0JCQklxnXrrbfy0EMPYa3liiuuYPHixVx88cWMHTuWBx98kCFDhpCbm0thYSHvv/8+ixYtYuXKlfj7+5OZmXna6/7+++9ZvXo1oaGh5OXl8e677xIUFMTu3bvp1q0bl1xyCWvWrOHRRx/l66+/JiwsjMzMTIKDg+nWrRuLFy/mkksuYc6cOVx++eVqBayMrIVtXzldMDe85ywSXj8BhjwNrUaAb6C7I5RKTL8RREQquDzXYuTzktP49MfdFBRaOsaEcl3PxgxuXY8AX/0qlzO0aCr8uq5066zbGi5+5JwObdy4cVFyBzBnzhxeeeUV8vPz2bFjBxs2bPhDgufv78/FF18MQIcOHfjiiy9KrHv48OFFZY61tH355Zf85S9/AaBt27a0bNmyxGM/+eQTHnvsMXJzc9m7dy8dOnSgS5cu7N27lyFDhgDg5+cHwLJly7jqqqvw93fGQIWFhZ32ugcMGEBoaCjgJKJTp07lyy+/xMPDg7S0NPbu3cunn37K6NGji+o79vOaa67hmWee4ZJLLmHmzJm89tprpz2fVCC/7YXVb8Cq2bBvM/gGQ8IE6DDR+b8kUgr0rUBEpILasvsQ85PTWLAqg72HnMXIr+3eiMsTI2kcobWJpPILCAgoer9582aefvppVq5cSUhICOPHjyc3N/cPxxSflMXT0/Ok3RN9fX1PW6YkOTk53HTTTaxatYoGDRpw3333lRjH6Xh5eVFYWAjwh+OLX/fs2bPJzs5m1apVeHl5ERkZecrz9ezZk5tuuonly5fj7e1NixYtzjo2KWeFhbD1M6e17scPoTAPorpA99sg/lLwqeHuCKWKqZ4JXkEeeHq7OwoRkT84dCSfD9fuYF5yOinbnOUN+rSozeiOUfRsFoGXFiOX83GOLW3l4cCBAwQGBhIUFMTOnTtZsmQJAwcOLNVzdOvWjXnz5tG9e3fWrVvHhg0b/lDm8OHDeHh4UKtWLQ4ePMiCBQsYN24coaGhRERE8P777x/XRbN///48+uijjBkzpqiLZlhYGDExMaSkpJCQkMBbb7110piys7OpXbs2Xl5eLF26lIyMDAD69OnD6NGjufXWW4u6aB5rxRs/fjzjxo3joYceKtU/HyllB3bC6v/BqtecBcb9w6DTFKfFrrYScyk71S/BW/82fPxXuG4FBIS7OxoREay1JG/LYl5SGh+u20nO0QKa1K7JvYPiuLR9AyICtbyBVH0JCQnEx8fTokULoqOj6datW6mf4+abb2bChAnEx8cXvYKDg48rEx4ezsSJE4mPj6devXp07ty5aN/rr7/Oddddx7333ouPjw8LFiwoGi+XmJiIt7c3Q4YMYfr06dx5552MHj2a559/vqhLaUmuvPJKhgwZQuvWrenUqRNNmzYFnC6kd911Fz169MDLy4sOHTrwyiuvADBu3DimTZvG6NGjS/3PSM5TYQFsXgqrZsGmJWALILYH9L0f4oaAl36fS9kzx2aGqiwSExNtcnLyuVeweyM83w0SJ8PgJ0ovMBGRs7T7QC5vrUpnfnI6W/f+Rk1fL4a0rcfliVG0jwrRhCmAMSbFWpt4+pLuZYwZCDwNeAIvW2sfOWF/NDADiAAygfHW2nRjTG/gX8WKtgDGWGvfNca8CvQEsl37Jllr/zjlYzEl3SM3btxIXFzcOV9bVZKfn09+fj5+fn5s3ryZAQMGsHnz5ko3ScncuXNZsmTJGS0fcTL6d1HK9m+H7//nvA5kQEBtaD8O2l8J4Y3dHZ1UQae6P1au32iloXYcdLwGkl6CDpOhbit3RyQi1cjR/EI+/XE385PT+GzTHgoKLZ1iw7ipdxMubl2XGj7V79dyZWeM8QSeA/oD6UCSMWahtbZ4/7/HgdnW2lnGmD7AP4ArrbXLgXauesKALcDHxY6701p78v59clYOHTpE3759yc/Px1rLCy+8UOmSuxtuuIFly5axePFid4ciBXnw0yKntW7LJ862Jn1h4CPQ/GINBxK3qVy/1UpL77th3XxYPBUmvg96Si4iZWzTroPMT07j7VUZ7PvtKHWCfLm+ZyNGdogitlbA6SuQiqwTsMVa+wuAMWYuMAwonuDFA7e53i8H3i2hnpHAImttThnGWq2FhISQkpLi7jDOy/PPP+/uEGTfz84smKvfgN92Q1AD6HkXtB8PIQ3dHZ1INU3w/EOhz73w4e2wcSHED3N3RCJSBR3IzeODNTuZl5zG6rT9eHsa+sXVYVRiFN2b1tKEKVVHAyCt2Od0oPMJZdYAw3G6cV4GBBpjwq21+4qVGQM8ecJxDxtj7gc+AaZaa4+ceHJjzBRgCkDDhvpyKVIm8o/Axvch5VVI/QKMJzS7CDpMgib9wMPT3RGKFKmeCR5AwiRImgEf3wdNB4C3v7sjEpEqwFrLd1szmZecxkfrdpKbV0izOjW5b3Acl7VvQHhNDbCvpu4A/m2MmQSsADKAgmM7jTH1gNbAkmLH3A38CvgALwJ/AaadWLG19kXXfhITE0scWG+t1ZhOKVLZ5l9wqz0/OcsbrJkDhzOdFro+90G78RBUz93RiZSo+iZ4nl7OdNGzhsDX/4aed7o7IhGpxHZmH2ZBSjrzU9LZti+HQF8vhidEMjoxijaRwfpyXbVlAFHFPke6thWx1u7AacHDGFMTGGGt3V+syCjgHWttXrFjdrreHjHGzMRJEs+an58f+/btIzw8XP8OBWst+/btK1qoXUpwNAc2vOskdmnfgoc3tBjsLEYe2ws81PtCKrbqm+CBM21t3FD48klodwUEN3B3RCJSiRzJL+CTjbuZl5zGik17KLRwQaNw/tSvKQNb1sPfR112qokkoKkxJhYnsRsDXFG8gDGmFpBprS3EaZmbcUIdY13bix9Tz1q70zhZ2aXA+nMJLjIykvT0dPbs2XMuh0sV5OfnR2RkpLvDqHh2b4Skl2HtfDiSDeFNoP90aDsWaka4OzqRM1a9EzyAAX9z1ilZ9iCMeMnd0YhIJfDjrweYl5TOO9+nk5WTR71gP27s3YSRHSKJDteEKdWNtTbfGHMTTvdKT2CGtfYHY8w0INlauxDoBfzDGGNxumjeeOx4Y0wMTgvg5ydU/boxJgIwwGrg+nOJz9vbm9jY2HM5VKR6yEiBL56EHz8AT19nboYOEyG6mybik0pJCV5oNHS7BVY85iyf0PDEcfEiIpB9OI+Fa3YwPzmNtenZeHsaBsTXZVTHKC5sUgtPD30JqM6stR8BH52w7f5i798CSlzuwFqbijNRy4nb+5RulCJSxFrY9hWseBx+WQ5+IdBzKnS+DmqEuTs6kfOiBA/gwj/D96/Dorvg2uXqWy0iRdZnZPPyF7+waP2vHMkvpEXdQB4YEs+wdg0IC/Bxd3giInI2rIXNS+GLJ5zxdQG1od9D0PFq8A10d3QipUIJHoBPAPSfBm9fA6tfh4Qr3R2RiLjZ+oxsnlq2mWUbdxHo58WoxChGJUbRqkGQJqoQEalsCgucZQ6+eAJ+XQvBUTDocWftOs2kLlWMErxjWo+EpJfgk4ecvtd+Qe6OSETcYF16Nk9/sollG3cT5OfF7f2bMbFbDEF+3u4OTUREzlZBHqybD1/+C/ZuciZOGfYctB4FXuqFIVWTErxjjIGLH0I6vXMAACAASURBVIUXezvj8QZMd3dEIlKOiid2wf7eSuxERCqzvFz4/jX46hnI3g51WsPImc5DfC1KLlWcErzi6reH9uPg2+chYSLUauLuiESkjCmxExGpQo4chOSZ8M2/4dAuiOwIgx6DZhdpRkypNso0wTPGDASexpk2+mVr7SMnKTcCZ3axjtba5LKM6bT63A8/vAcf3wtXvOnWUESk7JyY2N0xoBkTu8YQqMRORKTyycmElS86D+lz90NsTxjxMsR0V2In1U6ZJXjGGE/gOaA/kA4kGWMWWms3nFAuELgV+K6sYjkrgXWg512w9K+weRk07efuiESkFK1N38/TyzbzyY9K7EREKr2Du+Db5yDpFTh6CJoPgu63Q2SiuyMTcZuybMHrBGyx1v4CYIyZCwwDNpxQbjrwKHBnGcZydjpfDymvwuKp0Ogb8NQXP5HKTomdiEgVsn+7M77u+9eg4Ci0HA7db4M6Ld0dmYjblWWC1wBIK/Y5HThuFXFjTAIQZa390BhTcRI8Lx8Y+A94Y5TT3H/Bje6OSETOkRI7EZEqZO9mZ0bMtW8CBtqOcdYzDm/s7shEKgy3TbJijPEAngQmnUHZKcAUgIYNG5ZtYMc0HQBN+sFnjzpT6daMKJ/zikipKJ7YhdTw5s6LmjPhgmgldiIildGv65w17H54F7z8oOM10PVmCI50d2QiFU5ZJngZQFSxz5GubccEAq2Az1yLBtcFFhpjhp440Yq19kXgRYDExERbhjH/zhi46B/w/AWw/G8w5OlyOa2InJ81aft5+pPNfKrETkSk8ktbCSseh81LwCcQLvwTdLlRD95FTqEsE7wkoKkxJhYnsRsDXHFsp7U2G6h17LMx5jPgDrfPollcRDPodB18+x9IvArqtXV3RCJyEkrsRESqCGvhl8+cFrvUL8A/DHrfB52uBf8Qd0cnUuGVWYJnrc03xtwELMFZJmGGtfYHY8w0INlau7Cszl2qet7l9PNeNBUmf6SpdkUqGCV2IiJVRGEhbFrkJHYZKRBYDy76u7M2sW9Nd0cnUmmU6Rg8a+1HwEcnbLv/JGV7lWUs58w/BPr+Fd6/FX54G1qNcHdEIgKsTtvP08s2sfynPUWJ3cSuMdT0ddvQYhEROReFBfDDO05it3sDhETDJf+CduPAy9fd0YlUOvomdCbaX+msr/Lx/dDsYvCp4e6IRKotJXYiIlVE/lFYMwe+egoyf4GIFnDZi87DdE/9Thc5V/rfcyY8POHiR2HmxfD1M9BrqrsjEql2lNiJiFQRR3Ng1WznO9WBDKjXDkb/D5oPBg8Pd0cnUunpm9GZiu7qLKL55VNOl4GQqNMfIyLnTYmdiEgVYa0z3GXRVPhtNzTsCkOfgcZ9NceBSCnSN6Sz0X8a/LQIlt4Pl890dzQiVdr327N4+pPNfPbTHkJreHPXwOZMuECJnYhIpZSdAR/e7kyiUj8BRs1yHp6LSKnTN6WzERLlrL/y2T+cBTZjurk7IpEqR4mdiEgVUlgIq2Y5D8cL8mDAw9DlBmf4i4iUCX1jOltdb4FVr8Hiv8CUz/ULSqQUWGtZtT2LZz/dosRORKSq2PczLLwFtn0JsT1gyNMQ1sjdUYlUefrmdLZ8asCA6fDWZGeAcOJkd0ckUmkdzS/ko3U7mfnVVtakZyuxExGpCgry4dvnYPnfwdMXhj7rzEiucXYi5ULfoM5Fy8tg5Uvw6XTnvX+IuyMSqVT2HjrCG99t53/fbmP3wSM0qhXAtGEtGZEQSYASOxGRyuvXdfDeTbBzNbS4BAY9DkH13B2VSLWib1Lnwhi4+BF4oSd8/k8Y+Hd3RyRSKazPyObVr1NZuHoHRwsK6dksgn+OjKFH0wg8PPRkV0Sk0srLhRWPOWva+YfC5bMgfpha7UTcQAneuarXFjpMhJUvOD8jmrs7IpEKKb+gkKUbdjHzq1RWpmZSw8eT0R2jmNg1hia1a7o7PJFSYYwZCDwNeAIvW2sfOWF/NDADiAAygfHW2nTXvgJgnavodmvtUNf2WGAuEA6kAFdaa4+Ww+WInJ3t38LCm2HvJmcpqQF/gxph7o5KpNqqdgmetZb9OXmEBvicf2V9/grr34HFd8P4BXpKJVJMdk4ec5O2M/ubbWTsP0xkqD/3DopjVMcogv293R2eSKkxxngCzwH9gXQgyRiz0Fq7oVixx4HZ1tpZxpg+wD+AK137Dltr25VQ9aPAv6y1c40x/wWuBp4vswsROVtHDsIn05xhK8FRMP5taNLX3VGJVHvVLsFbuGYHf313PdMvbcWwdg3Or7KAWtBrKiy5GzYtgeYDSydIkUpsy+6DzPwqlbdXZXA4r4AujcL46yXx9I+vg6e6YUrV1AnYYq39BcAYMxcYBhRP8OKB21zvlwPvnqpCY4wB+gBXuDbNAh5ECZ5UFJuXwQd/gux06Hyd89DbV70yRCqCapfgtYkMoXHtmtw6dzVLN+xi+rBW59ea1+laSJnpJHmN+4BXKbQMilQyhYWWzzbtZuZXqXyxeS8+Xh5c2q4+k7rGEl8/yN3hiZS1BkBasc/pQOcTyqwBhuN047wMCDTGhFtr9wF+xphkIB94xFr7Lk63zP3W2vxidZ7nU0mRUpCT6fRcWjsXajWHqz+GqE7ujkpEiql2CV5srQDmX3cB//38Z55atpmVWzN5dGQbejevfW4VenrDRf+A10fAd/+FbreUbsAiFdihI/m8lZzGrG+2sXXvb9QJ8uWOAc0Y26kh4TV93R2eSEVyB/BvY8wkYAWQARS49kVbazOMMY2AT40x64DsM63YGDMFmALQsGHDUg1apIi18MPb8NFdkLsfetwFPe4AL/2uF6loql2CB+Dl6cFNfZrSq3ltbpu3mskzk7iic0PuHRR3blO0N+0HzQY6M2q2GQ2BdUo/aJEKZNu+35j19TbmJ6dx8Eg+7aJCeHpMOwa1roe3p4e7wxMpbxlAVLHPka5tRay1O3Ba8DDG1ARGWGv3u/ZluH7+Yoz5DGgPLABCjDFerla8P9RZrO4XgRcBEhMTbeldlojLgR3w4e3w00dQvz0MfQ/qtnJ3VCJyEtUywTumVYNgFt50IU8u3cRLX/zCV1v28uSotnSIPoeZny76OzzXGT6dBsOeK/1gRdzMWsvXP+9j5ldb+eTH3Xgaw+A29ZjUNYb2DUPdHZ6IOyUBTV2zXmYAY/h97BwAxphaQKa1thC4G2dGTYwxoUCOtfaIq0w34J/WWmuMWQ6MxJlJcyLwXnldkAgAhYWwahYsvR8K8pzZMTvfAJ7V+uujSIVX7f+H+nl7cs+gOPq2qM3t89dw+X+/4bqejflTv6b4enmeeUXhjaHLDfD1s5B4NTRIKLugRcrR4aMFvLs6g1e/SuWnXQcJD/Dhpt5NGN8lmjpBfu4OT8TtrLX5xpibgCU4yyTMsNb+YIyZBiRbaxcCvYB/GGMsThfNG12HxwEvGGMKAQ+cMXjHJmf5CzDXGPM34HvglXK7KJF9P8P7t0LqFxDTHYY+A2GN3B2ViJwBY23l6s2RmJhok5OTy6Tug7l5/O2DjbyZnEaLuoH8a3Q74uqdxQQRuQfg2QQIjXUGHWvZBKnEduw/zGvfbmPOyu3sz8kjrl4Qk7vFMLRtffy8z+Lhh8h5MMakWGsT3R1HZVGW90ipJgry4dv/wPKHwdMXBkyHhAn6TiNSwZzq/ljtW/CKC/Tz5tGRbegfX4epb69l2L+/4rYBzbi2e6Mzm97dLwj6PgALb4J1b0Gby8s+aJFSZK0lZVsWM79OZfH6X7HWMiC+LpO7xdApNgyjG7yISNX16zp47ybYuRqaD4bBT0BQPXdHJSJnSQleCfrF12FJwx7c+856Hln0I8s27OKJUW2JDg84/cHtxkHSy05/9RaDwOcMjhFxsyP5BXy4diczv0plXUY2QX5eXH1hLFd2iSYqrIa7wxMRkbKUfwRWPAZf/gv8Q+HyVyH+UrXaiVRSSvBOIrymL8+PT+Cd7zN44L0fuPjpL7hvcDxjO0WduhXDwwMu/ifMGOD8ouxzX/kFLXKW9hw8wuvfbeN/325n76EjNI4IYPqlrRiR0IAaPvr1ICJS5W3/zul5tHcTtL0CLnoYapzDZHMiUmHoG9wpGGMYnhBJ50bh3Dl/Dfe8s46lG37l0RFtqH2qySUadobWo+CrZ6D9eAiNKbeYRc7E+oxsZny1lQ/W7ORoQSG9m0cwqVss3ZvUwuNMuiOLiEjlduQQfDINVr4IwZEwfgE06efuqESkFCjBOwMNQvz539WdmfVNKo8s+pEBT63g4UtbM7jNKfql93sQfvwAPv4rjH6tnCIVKVluXgGr0/aTnJrJ8p/2kLItixo+noztFMXErjE0iqjp7hBFRKS8bFkG7/8JstOh83XQ56/gq/uASFWhBO8MeXgYJneLpXvTCG6bt5ob31jF0g31eWhoK4JreP/xgOAGcOFtsPxvsHUFxPYo/6Cl2srOySN5WyZJqVkkpWayNn0/eQUWY6B5nUDuGxzHqI5RBPmV8G9XRESqppxMWHIPrJkDtZrBVUucXkciUqUowTtLTWrXZMENXfnP8p955tPNfPtLJo9d3obuTSP+WLjrTfD9bFg0Fa5boYVBpczszD7Myq2ZJLsSup92HcRa8PY0tG4QzFUXxtIpJozE6LCSH0iIiEjVZS1seBc+uhMOZ0GPu6DHHeDl6+7IRKQMKOM4B96eHtzarym9W0Tw5zdXc+UrK5lwQTR3XxyHv0+x9cG8/WHA32DeBFj1KnS8xm0xS9VhreXnPYec1rmtmaxMzSQ96zAAAT6eJESHMrh1PTrGhtEuKkRr1omIVGcHdsKHt8NPH0L99nDlu1C3lbujEpEypATvPLSJDOHDW7rzz8U/MeOrrXy5eS9PjGpL+4ahvxeKGwox3eHTv0HL4ZqZSs5aXkEhP+w4QHJqptNKty2LzN+OAlCrpg8dY8K4qlssnWLDaFE3EC9PDzdHLCIibmctrJrtzAVQcAT6T4cu/6feRCLVgP6Xnyc/b0/uHxJPv7ja3DF/DSOe/5obezfh5j5N8fHycNaQGfgIvNAdPnsEBv3T3SFLBZdzNJ/vt+8nKTWTpNRMvt++n5yjBQBEh9egT4vaTnfLmFBiawVo8XERETleYQG8ewOsfdN5yDzkaQhv7O6oRKScKMErJV2b1GLxn3vw0MINPPvpFpb/tJsnR7WjWZ1ApytEh8nOAugdJkGdeHeHKxVI5m9HSUrNdFroUrP4ISOb/EJnQpS4ukGMSowiMSaUjjFh1DnV8hwiIiLWwgd/cpK73vdCjzu1YLlINaMErxQF+XnzxKi29I+vwz3vrOOSZ7/krouac1W3WDz63AfrF8DiqTDhPf2yraastaRnHSZ5WyYrtzoTomzZfQgAHy8P2kWGMKVHIzrGhtEhOlSzXIqIyJmz1vmesWq2k9j1vMvdEYmIGyjBKwMDW9WlQ3Qod7+9jr99uJGlG3bx+OVtiep9Dyy6C376CFoMdneYUg4KCy2bdh8smhAlKTWTndm5AAT6etEhJpTL2jegU2wYrRsEa0IUERE5d59Mg+/+C11udFrvRKRaUoJXRiICfXlpQgfmp6Qz7f0NXPz0FzwweAAjI2ZiltwDjfuCt7rbVUXb9+WwbOMuvtqyl+RtWWQfzgOgdqAvHWPD6BQTRseYMJrXDcTTQy25IiJSClY8Bl8+6QwJuehh9RQSqcaU4JUhYwyjEqO4oFE4d8xfw51vb2B7zGRu33MXfPsf6H6bu0OUUlBYaFmTvp9lG3exbMNuftp1EIDYWgEMbFm3KKmLCvPXhCgiIlL6vvmPM1t3mzEw+EkldyLVnBK8chAVVoM513Zhxldb+ecSDxK8OtH9s8fwajsWguq5Ozw5B4ePFvDVlr1OUrdxN3sPHcHTw9AxJpT7BsfRL64OMbUC3B2miIhUdckzYcndzrJMw54DDy2VI1LdKcErJx4ehmu6N6JHswgefeMgXfffwPev3ErzG17XRBqVxJ6DR/j0x10s3bCbL7fsITevkJq+XvRsHkH/uDr0ah5BSA0fd4cpIiLVxZo34YM/Q9MBMOIVrXEnIoASvHLXrE4gz988ktUzv6RTxiyueeJlrhp9OV2b1HJ3aHICay1bdh9i6cZdLNuwi+/T9mMtNAjxZ3RiFP3i69A5NtxZ71BERKQ8bXgP3r0eYrvDqNngpQeMIuJQgucGPl4edJrwMHlPLeL2I68w6OVIJndrzF0Dm2sWRTfLLygkKTXL1fVyF9v25QDQukEwf+rbjP7xdYirF6ixdCIi4j6bPoa3robIjjBmDnj7uzsiEalAlOC5i28g3hdNI+7d63mi2Y/c9pUHn2/azf/1akJiTCgNw2ooiSgnB3Pz+HzTHpZt2MXyn/aQfTgPH08PujYJ59rujegbV5t6wbp5iohIBfDL5/DmeKgTD+Pmg29Nd0ckIhWMEjx3ajMakl5meOZL1J2whDve+4Xb568BoFZNXzpEh9AhOpQO0WG0ahCEr5da90pLxv7DfLJxF0s37OLbX/aRV2AJreFNv7g69I+vTfemEQT46r+HiIhUINu/gzljIawRjH8H/ILdHZGIVED6ButOHh5w8aPwcl+67pjFl395gM27D5G8LZOUbVmkbMtiyQ+7AKdbZ5sGwXSIDiUhOpQO0aHUqunr5guoPKy1rM84UDSebsPOAwA0qhXAVd1i6Rdfh4SGoVqXTkREKqYd38PrIyGwLkx4DwLC3R2RiFRQSvDcLTIR2o6Fb57Do/2VNK/bmOZ1AxnXORpwZm5M2ZbFqu1ZJKdmMvOrVF5Y8QsAMeE16BAdRofoUBJjQmkSURMPJShFcvMK+OaXfSzbsItPNu7m1wO5eBjoEB3K3Re3oF98HRpHqGuLiIhUcLs2wGuXgV8ITFwIgXXcHZGIVGBK8CqCfg/Cxvfh47/C2DeO2xUR6MvAVnUZ2Kou4CQt6zOyi1r4PvtpNwtWpQMQ6OdFQsNQEl0tfO0ahlDDp3r9FWf+dpRPf9zNsg27WLF5DzlHC6jh40mPphH0i69D7+YRhKvlU0REKou9W2D2MPDyg4nvQXCkuyMSkQquen37r6gC60L32+GTh2DLMmjS76RF/bw9SYwJIzEmDHC6Hm7bl0OyK+FL2ZbJE0v3AODpYYirF0hidBgJ0U7iVz+k6k0W8vOeQyzb4Mx6mbIti0ILdYJ8uax9A/rF1+GCRuGanVREypQxZiDwNOAJvGytfeSE/dHADCACyATGW2vTjTHtgOeBIKAAeNha+6brmFeBnkC2q5pJ1trV5XA5UlFkbYPZQ8EWwoQPnLF3IiKnYay17o7hrCQmJtrk5GR3h1H68o/A890gNxumfAbBDc65quycPFalZbFqWxbJqVmsTtvP4bwCAOoF+xUlex2iQ4mrF4S3Z8Vbxy03r4B9vx0l89BR9v12hMzfjh732uf6+Wt2Lhn7DwMQXy+IfvF16B9Xh1YNgjQLqUgVYIxJsdYmujuOUzHGeAKbgP5AOpAEjLXWbihWZj7wgbV2ljGmDzDZWnulMaYZYK21m40x9YEUIM5au9+V4H1grX3rTGOpsvfI6ujADph5MRzOgkkfQt3W7o5IRCqQU90f1YJXUXj5wpjX4aW+zvTHkxeBt985VRVcw5vezWvTu3ltwFnb7cdfD5KcmknK9v2kpGby4dqdAPh7e9I2KphE11i+hIahBNfwLrXLAqeV8UBuPlnFErPM344UJXCZOcUSt0POz2MJ6Ym8PAyhAT6EB/gQFuBDQnQoU3o4SxlEhtYo1bhFRM5QJ2CLtfYXAGPMXGAYsKFYmXjgNtf75cC7ANbaTccKWGt3GGN247Ty7S+HuKWiOrTH6Zb5215nQhUldyJyFpTgVSQRzWH4CzD3Cvjgz3Dpf6AUWqG8PD1o1SCYVg2CmdTN2bZj/+GicXyrtmfx/Oc/U1DotOY2rV3TtTyD84qtFXBca1hBoSUrp4QWtUO/J25ZOb8na1k5R8krKLml2M/bg/AAX8JcCVvjiJpF748lceE1fQit4UN4gC9B/l5qmRORiqYBkFbsczrQ+YQya4DhON04LwMCjTHh1tp9xwoYYzoBPsDPxY572BhzP/AJMNVae6QM4peKJCfTmVBlfxqMX+BMxiYichaU4FU0LQZDz6nw+SNQvx10vq5MTlM/xJ/6If4MaVsfgJyj+axJyybFtUTDR+t2MjfJ+b4SFuBDbK0A9ruSuv2H8zhZz95AP6+ixCwy1J82kcGEBfgWbQur6SRuoTWcxK26TQIjItXWHcC/jTGTgBVABs6YOwCMMfWA14CJ1tpC1+a7gV9xkr4Xgb8A006s2BgzBZgC0LBhw7K7Ail7uQecpRD2/gRj50JMN3dHJCKVUJl+uz6DQefXAzfi3OQOAVOKj1motnr+BX5dC4vvhtrxENu9zE9Zw8eLCxqHc0FjZ12dwkLLz3sOkbIti+RtWaRn5dCsTuBxLWthNX2PS9ZCa/jg41XxxvOJiJSxDCCq2OdI17Yi1todOC14GGNqAiOstftdn4OAD4F7rbXfFjtmp+vtEWPMTJwk8Q+stS/iJIAkJiZWroH18rujOfDGaNixGka/Bk36ujsiEamkyizBcw06f45ig86NMQtPSODesNb+11V+KPAkMLCsYqo0PDzgshfg5b4wfyJM+RxCok5/XKmGYGhaJ5CmdQIZ00lPhEVETiEJaGqMicVJ7MYAVxQvYIypBWS6WufuxplRE2OMD/AOMPvEyVSMMfWstTuN0y/9UmB9mV+JuEf+EXhzHGz/Bka87PTmERE5R2XZ3FI06NxaexQ4Nui8iLX2QLGPAYCePB7jFwRj5kBBnjMm72iOuyMSEZESWGvzgZuAJcBGYJ619gdjzDTXw0uAXsBPxphNQB3gYdf2UUAPYJIxZrXr1c6173VjzDpgHVAL+Fv5XJGUq4I8mD8Jfv4Uhv0bWo90d0QiUsmVZRfNMxl0jjHmRpyZxXyAPiVVVG3HF9Rq4jzJe2M0vH8rDH+xVCZdERGR0mWt/Qj46IRt9xd7/xbwh+UOrLX/A/53kjpLvCdKFVJYAG9PgZ8+gkGPQ/vx7o5IRKoAtw+YstY+Z61tjDN4/L6TlHnRWptorU2MiIgo3wDdrdlF0OdeWDcPvnnO3dGIiIhIaSgshIW3wA9vQ7+HoNO17o5IRKqIskzwTjvo/ARzccYYyIm63wFxQ2HpX+Hn5e6ORkRERM6HtbDoLlj9P2ditQv/5O6IRKQKKcsEr2jQuWsQ+RhgYfECxpimxT4OBjaXYTyVlzFw6fMQ0QLemgxZqe6OSERERM6FtbDsAUh6CS64CXrd7e6IRKSKKbME7wwHnd9kjPnBGLMaZxzexLKKp9LzrQljXgdbCHPHwdHf3B2RiIiInK3P/wlfPQ2JV8OAv2lsvYiUujJdB+8MBp3fWpbnr3LCGsHIGfD65fDejTBypm4MIiIilcXXz8Jnf4e2VziTqugeLiJlwO2TrMhZatIP+j4AP7wDXz3l7mhERETkTCS9DB/fB/GXwtBnnTVvRUTKgH67VEbdboWWw2HZQ7B5mbujERERkVNZ/QZ8eDs0GwjDXwLPMu1AJSLVnBK8ysgYZzHUOq1gwVWw72d3RyQiIiIlWf+2M6yiUS+4fBZ4+bg7IhGp4v6fvfuOj6rK+zj++aUnpFESkCaoIF1KFlBQpOiiKFhQaQI27FjWfZbdx3XVXXddH9cVFF1BRcHCoqiggtiwK1JEEFBAQKU3qQmkneePOwkBAiQhk5vMfN+v17xy586dm+8MmjO/OeeeowKvqoqp5k26YpHepCv7d/udSERERIr6YSa8dh006AQDXoLoOL8TiUgYUIFXlVU/ES6bAFuXw+s3eIumioiIiP9+nA1ThkKd1jBoivfFrIhIBVCBV9WddDac+1f4/i349F9+pxEREZGfvoTJg6BmExjyGsQl+51IRMKICrxQ0PkmaHMFzH4AfnjH7zQiIiLha918bzmj5How9A1IqOF3IhEJMyrwQoEZXDgaTmjjjfXfusLvRCIiIuFn43cw6RKvqBs6DRLT/U4kImFIBV6oiI6HK16EyBh4eSDs2+l3IhERkfCxZTlMugiiE2DYdEip53ciEQlTKvBCSWoDuHwi/LoaXrtek66IiIhUhF/XwMR+3vaw6VC9kZ9pRCTMqcALNY26wG//ActnwscP+p1GREQktO1cB89fCDmZcOUbUKuJ34lEJMypwAtFHa+DtkPg43/Csrf8TiMiIhKa9u/2hmVm/gpXvgZ1WvmdSEREBV5IMoM+/4J6HeD162Hz934nEhERCT0z/ge2rYQBL3ptrohIJaACL1RFx8EVL3gXe08eCFk7/E4kIiISOha9At++BGf9Hk7q5ncaEZFCKvBCWXJduGIS7PgFpl4L+Xl+JxIREan6tq+Gt+6ABp3hrP/xO42IyEFU4IW6hp3h/Idg5Xvw4d/8TiMiIlK15eXA1GvAIuDS8RAZ5XciEZGDlKjAM7OTzSw2sH22mY00s9TgRpNyk3E1dBgOnz0CS173O42ISKWl9k6OafbfYd186DsaUhv6nUZE5DAl7cGbCuSZ2SnAOKAB8FLQUkn5O+8haNAJ3rgJNn7ndxoRkcpK7Z0c2aqP4LN/Q/th0PJiv9OIiBSrpAVevnMuF7gYeMw593vghODFknIXFestgh6XApMHQeZ2vxOJiFRGau+keHu3wmvXe+vc9f6H32lERI6opAVejpkNBIYBBQurRQcnkgRNUh1vZs3dG+DVqyEv1+9EIiKVTZnaOzPrbWY/mNlKMxtVzOMnmtkHZrbIzD4ys/pFHhtmZisCt2FF9ncws8WBc44xMyuH1ydl4RxMuxmytkP/ZyGmmt+JRESOqKQF3lXA6cADzrnVZtYYmBS8WBI09TOgzyOwajZ8cK/faUREKptSt3dmFgmMBc4Dkp7FvQAAIABJREFUWgADzazFIYc9DEx0zrUB7gf+EXhuDeAvQCegI/AXM6seeM6TwHVAk8Ct9/G/PCmTr8fB8nfgnL9CndZ+pxEROaoSTf3knFsKjAQINDxJzrl/BjOYBFH7K2HDt/DFY3BCW2jd3+9EIiKVQhnbu47ASufcqsDzJgP9gKVFjmkB3BnYng28Edj+LfCec2574LnvAb3N7CMg2Tn3VWD/ROAiYOZxvUApvY2L4d27oclvodP1fqcRETmmks6i+ZGZJQe+aVwAjDezR4IbTYKq9z/gxC4w7Rav2BMRkbK2d/WAX4rcXxvYV9S3wCWB7YuBJDOreZTn1gtsH+2cBZlHmNk8M5u3ZcuWY0SVUsne613SEF8DLnoCNEpWRKqAkg7RTHHO7cJrnCY65zoBvYIXS4IuMhouex4SasDkwd7F4yIiEqz27i6gm5l9A3QD1gF55XBenHPjnHMZzrmMtLS08jilFHjnj7B1BVzyFFSr5XcaEZESKWmBF2VmJwCXc+Cic6nqEtO8SVf2bIZXhmvSFRGRsrV36/CWUyhQP7CvkHNuvXPuEudcO+B/A/t2HOW56wLbRzynBNmSN2DB89D1djjpbL/TiIiUWEkLvPuBWcCPzrm5ZnYSsCJ4saTC1GsPF46GNZ/Ce3/2O42IiN/K0t7NBZqYWWMziwEGANOLHmBmtcysoM39I/BsYHsWcK6ZVQ9c83cuMMs5twHYZWadA7NnDgWmlccLlBLY8TO8ORLqdYDu/+t3GhGRUinpJCuvAK8Uub8KuDRYoaSCtR0IGxfBV09AnTbefRGRMFSW9s45l2tmt+AVa5HAs865JWZ2PzDPOTcdOBv4h5k54BPg5sBzt5vZX/GKRID7CyZcAW4CngPi8SZX0QQrFSEvF6ZeB/n5cOkz3iUNIiJVSIkKvMB6PY8BXQK7PgVuc86tPfKzpEo556+w6Tt48zZIO9Xr2RMRCTNlbe+cczOAGYfsu6fI9qvAq0d47rMc6NErun8e0Ko0+aUcfPJ/8MtXcMnTUKOx32lEREqtpEM0J+ANN6kbuL0Z2CehIjIK+j8HibXhv0O86/JERMKP2rtwtuZz+OQhOG0gtLnM7zQiImVS0gIvzTk3wTmXG7g9B2iqrlBTrSYMeBEyt8OUYZCb7XciEZGKpvYuXGVuh9eug+qN4Pz/8zuNiEiZlbTA22ZmQ8wsMnAbAmwLZjDxyQltoN/j8PMXMOtPfqcREaloau/CkXPepCp7NkP/ZyE2ye9EIiJlVtIC72q8KaM3AhuA/sDwIGUSv7XuD2eMhLnjYcFEv9OIiFQktXfhaP4EWPYm9LwH6rbzO42IyHEpUYHnnPvJOdfXOZfmnEt3zl2EZtEMbb3uhZN7wNu/g1/mHutoEZGQoPYuDG1e5i1ofnIPOP0Wv9OIiBy3kvbgFefOckshlU9EpDc9dHJdb9KV3Rv9TiQi4he1d6EqJwtevcYbknnRfyDieD4WiYhUDsfzl8zKLYVUTgk1YMBLsH83TB7s/RQRCT9q70LVu3+GzUu84i6ptt9pRETKxfEUeK7cUkjlVbslXDIO1n8DE/tB1q9+JxIRqWhq70LR9zO8a81PvwWa9PI7jYhIuTlqgWdmu81sVzG33XjrA0k4aH4BXDEJNi6G5y6EPVv8TiQiUq7U3oWZXeth2k1Qp403sYqISAg5aoHnnEtyziUXc0tyzkVVVEipBJr1gYGTYdtKeO58r3EUEQkRau/CSH4evDbCW+u1/wSIivU7kYhIudLVxFJyp/SEIVO94m7CefDrT34nEhERKZ3P/g1rPvUWM691it9pRETKnQo8KZ1GXWDodO9avAnnw9aVficSEREpmV++htl/h1aXQttBfqcREQkKFXhSevU7wPC3IXef15O3aanfiURERI5u306Yeg2k1IML/g2myVFFJDSpwJOyqdMarprhrZf33PneLJsiIiKVkXPw5u2wcx1c+izEpfidSEQkaFTgSdmlnQpXzfQWiH2+L/z8ld+JREREDrfwRVjyGnT/EzT4jd9pRESCSgWeHJ8ajb0iLzEdJl0Mqz7yO5GIiMgBW1fAjP+BRmdC1zv8TiMiEnQq8OT4pdT3irzqjeDFy2H5LL8TiYiIQO5+ePVqbymES8Z5lxWIiIQ4FXhSPhLTvYlX0pvD5EGw5A2/E4mISLh7/z7YuAj6jYVkrVcvIuEhqAWemfU2sx/MbKWZjSrm8TvNbKmZLTKzD8zsxGDmkSBLqAHDpkO9DHj1Klj4st+JREQkXK14D74aCx1HQLPz/U4jIlJhglbgmVkkMBY4D2gBDDSzFocc9g2Q4ZxrA7wKPBSsPFJB4lLgyte8ax3euAHmPuN3IhERCTe7N8HrN0B6Szjnr36nERGpUMHswesIrHTOrXLOZQOTgX5FD3DOzXbOZQbufgXUD2IeqSgx1WDQFGjyW3j7Tvjicb8TiYhIuMjP975gzN4L/Z+F6Di/E4mIVKhgFnj1gF+K3F8b2Hck1wAzg5hHKlJ0HFzxArS4CN79X/j4IW8dIhERkWD68nH48UPo/XdIb+Z3GhGRChfldwAAMxsCZADdjvD4CGAEQMOGDSswmRyXqBi49BmIjofZD3jfpva6F8z8TiYiIqFo3QL44D5ofiF0uMrvNCIivghmD946oEGR+/UD+w5iZr2A/wX6Ouf2F3ci59w451yGcy4jLS0tKGElSCKjoN8TkHE1fP4ozPwfb/iMiEgIKcGkYg3NbLaZfROYWOz8wP7BZrawyC3fzNoGHvsocM6Cx9Ir+nVVKft3w9RrILEOXDhGXyaKSNgKZg/eXKCJmTXGK+wGAIOKHmBm7YCngN7Ouc1BzCJ+ioiAPo9AdII3dCYn02t8tR6RiISAIpOKnYN3OcJcM5vunFta5LC7gSnOuScDE47NABo5514EXgycpzXwhnNuYZHnDXbOzauQF1LVzfg9/LrGW7InoYbfaaSK2JmZw5L1O1myfhdL1u9kR1YOSXHRJMVFkRQXRXKR7aTYgu3owscS46KIjNCXCVK5BK3Ac87lmtktwCwgEnjWObfEzO4H5jnnpgP/ByQCr5j3TdvPzrm+wcokPjKDc/8GMYnw8YOQkwUXPwWR0X4nExE5XoWTigGYWcGkYkULPAckB7ZTgPXFnGcg3oRkUlqLpsC3L0O3UXDiGX6nkUrIOcemXfsPKua+W7eLdTuyCo+pkxxHraQY1mzdy+59uezel0t23rFHHVWLiTyoKDywHU1yMfsOLR4TY6OIitTS1FJ+gnoNnnNuBt63lEX33VNku1cwf79UMmbQ/Y8QkwDv3eMVef0naIYzEanqiptUrNMhx9wLvGtmtwLVgOLavys4ZLZpYIKZ5QFTgb85p9mqDrN9Fbx1JzQ8Hc76vd9pfJebl8+abZms3LybnVk51K+eQMMaCZyQEhc2RUR+vuOn7ZmFxdx363aydP0utu3NLjymca1qtG2YyuDODWlVN4UWdZOplRh72Ln25eQFir2cwqKvYHvXvhz27M897PEdmdn8sj2TXYH9+3OPXSQmxEQWFoCJsYf3HibHRZMcH01yfJHtuGhSAvvioyMxDUuWgEoxyYqEmS63ecM1Z9wFLw+AAS95RZ+ISOgaCDznnPuXmZ0OTDKzVs65fAAz6wRkOue+K/Kcwc65dWaWhFfgXQlMPPTEYT0RWV4OTL3WuxTgkvHedd9homght3zTHpZv2s3KzXtYtWVvsb1OkRFG3dQ4GtbwCr4GBT8DBWBqQnSVLBBy8vJZsWnPQT1zyzbsZs/+XACiIowmtZPo3iydVnWTaVkvheYnJJMYW7L/VuKiI4mLjiQt6fDir6Syc/MPKxB3HaFo3L2/oHjMZd2OrMLH9uUcvUiMirBA0Rd1WPF3oCA88FhyfDQpRR6LjYqokv/+Urzw+UsolUvH67wib/ot8MKlMOi/EJd87OeJiFQ+JZlU7BqgN4Bz7ksziwNqAQXXnw8AXi76BOfcusDP3Wb2Et5Q0MMKPOfcOGAcQEZGRnj18M1+ANbNh8ueh9QGxz6+CippIVe/ejxNayfRrWkaTWon0bR2IqnxMazdkckv2zP5eXsmv2zP4uftmby7ZNNBvVkASbFRhUVfw5oJNKgeX3i/XvV4YqP8v24+MzuXZRt2szQwvHLJhp0s37in8H2Ij46k+QlJXNK+Hi3rJtOybgpNaif6nj0mKoKaibHULKaHsKRy8vLZleUVht7PHHZleb2IO7NyDtu3KyuHjbv2FT52rF7EmMiIwmIwKT5QHB5UEEYVKQwPfiwpLkoFYik458jLd0HtUVeBJ/5pN9gbnvnaCJh0EQx+VRfGi0hVdMxJxYCfgZ7Ac2bWHIgDtgCYWQRwOXBmwcFmFgWkOue2mlk0cAHwfrBfSJXy42z47FFoPwxaXuR3muNWUMit2LSbFZu9Qm7Fpj2s3nqEQu7UNJqke4XcKemJJMQU/5GuYc0EOPnw/Xv25/LL9qLFn/dzxebdfPjDZrKLFARmcEJyHPULCsDCXkCvCExLjC33D/c7MrMLh1cW9Myt3rqX/MBXGKkJ0bSqm8JVXRrRIlDMNa5VLWQnPImOPL4isWCoaUHxt/MYxeLOrBzWbs8s3JeTd/TvjiIMqsVEkRAbSUJMFAkxkYX3qxXcjz3kZ0wU8TGRVAs856DjYyNJiI70dVhxfr4jKyePvdm5ZGXnsXd/Hlk5uezdn0dmdh6Z2bnszc4jKzs38Fgee/cHjs3ODRxz4NjM7Dwy9+eSmZPHTWefzO9/G7x1OlXgib9aXQpR8fDKMHj+QrjyDUjUUhgiUnWUcFKx3wHjzewOvAlXhhe5nu4s4JeCSVoCYoFZgeIuEq+4G19BL6ny27sVXr8eajWF3g/6naZUjlTIrdq656AP0QWF3NnNSlbIlVZibBTNT0im+QmHj57Jz3ds2bOfn7dn8vO2QAH4q1cEfrpiC5t2HbyqVXx0JA1qxNOwRkLhNX8HegITiI85cg+ac46Nu/Z5PXKBYZZL1x88+UndlDha1E3hgjZ1vZ65einUTYlTj1EpHM9QU+cc+3Pzi+0p3JnlXYeYuT9Q1OzPIzPHK2T2Zueyfa93PWJmtlf87M3OIy+/5AMNYqMiqBbrXWNYWAgWFoSRJMQGfhbZnxC4HxsVQVZOkWJsf6AYO7ToKiy+8sjMCbyGbK9gK4246Igiv/9AluoJMYHCNpL4aC9np8Y1S/vPUCpW1a7XzsjIcPPmacbokPPjh/DyIG+IzdBpkFzX70QiUgmY2XznXIbfOaqKsGgjnYOXroBVH8F1H0Cd1n4nKlZJC7kGNeJpkp5Ek9qJNA38LM9CLhj25eSx9tcDQz5/PqQXMDP74A/GtRJjaRgoABvWSKB2Shw/b89k6fpdLFm/i+2B4aJm3uQnLeumBIZYej1zNarF+PEyJQicc2Tn5R9SCBb5mV3QQxb4mXNw8VjQM7Z3/yHFWXbJijEzSIiOJD5QEHqF4+FF2UHbsVEkBArM+EBhGR9zoGcyIVCAVnTv8dHax8r710PCy8k94MrX4MXL4dneMGw6VG/kdyoREals5jwFK2bBeQ9ViuKutIXc2c3SqkwhdyRx0ZGckp7EKelJhz3mnGP73uyDir6CQnDuml+Z/u168h1ERxpNayfRq3k6Leum0KpeMs3qJFOthJOfSNVkZsRGRRIbFUn1cjxv0eGUBYVgdm5+YSFW8DMuOjyuFdT/RVJ5nHgGDJsGky6BCefD0OlQ6xS/U4mISGWxcTG892do2hs6jvAtxqZd+5j9/WY+/H4zn63celDvQYMa8TQtUsg1rZ3EyenVqmQhVxZmVnitWLuGh3+Ez87NZ8ue/aQlxhITFR7LNkjwRUQY1WKjvC8IDv/eIeyEx18bqTrqdYDhb3uTrkw4D4a+AbVb+p1KRET8lr0XXr0a4mtAvye8sVYVJD/fsWjdTj5ctokPf9jMd+t2Ad61YRe3q0f7htXDrpArq5ioCOqlxvsdQySk6a+QVD51WsHwGTCxHzzXB4a8BvXa+51KRET89M4o2LrC++KvWnAnKADYtS+Hz1Zs5YNlm/l4+Wa27skmwqB9w+r8/ren0rN5OqfWTgqL4V4iUrWowJPKKa0pXD3Tm1nz+b4w+BU48XS/U4mIiB+Wz4IFE6HrnXDS2UH5Fc45Vm3dy4fLvKGXc9dsJzffkRIfTbemafRolk63pmlU14QfIlLJqcCTyqt6I7jqHZjYF164BAa8BCd39zuViIhUJOfg44e8NqH7n8r11Ptz8/h69XY+WLaZ2T9s5qdtmQCcWjuJa888iR7N0mnfMNXXtbhEREpLBZ5Ubin14KqZMPEib1rsyyfCqb39TiUiIhXl5y9h3Tzo8y+IjD7u023etY/ZP2zmg2UHJkiJjYrgjJNrcm3XxnRvlk796gnlEFxExB8q8KTyS0yH4W95vXj/HQyXPg0tL/Y7lYiIVITPR0NCTWg7uExPP9YEKT2apXPGybWOuhi3iEhVogJPqoaEGt4C6C9d4c2ilpMFbQf5nUpERIJp8zJY/g6c/SeILvnMi8eaIKVHs3Sa1dEEKSISmlTgSdURlwJDpsLkQfDGjZCTCb+51u9UIiISLF88BtEJ0PG6ox5WMEHK7O+9oZeaIEVEwpkKPKlaYqrBwP/CK8Ph7d95PXln3Op3KhERKW+71sOiKZBxtTeK4xAFE6R8GFhwXBOkiIh4VOBJ1RMdB1dMgteug3fvhi3fw7l/g/jqficTEZHy8tWT4PLg9JsKdxWdIOXzlVvZqwlSREQOowJPqqbIaLj0Gaje2LsAf/m7cP7/QYt+oGsqRESqtn07Yd4Eb0Kt6o34ZPkW/m/WDyxetxPwJki5SBOkiIgUSwWeVF0RkdDrL9DyIph+K7wyDJpdAOc/DMkn+J1ORETKav5zkL2b/NNv5YkPV/Cv95bTuGY1TZAiIlICKvCk6jvhNLj2Q/jycfjoHzC2I5xzP7QfBhG69kJEpErJ3Q9fPUnuiWdxw/t5vL9sOX1Pq8uDl7YmIUYfW0REjkWffiU0REZB19vhxi+8gu+t2+H5C2Hbj34nExGR0lj8CuzewB839eCjHzZzzwUtGD2grYo7EZESUoEnoaXmyTDsTbhwDGxcDE+cDp8+Ank5ficTEZFjyc9n94ePsMydyOycVrx0XWeu7tpYwzFFREpBBZ6EHjPoMAxu+Rqangsf3Afju8P6hX4nExGRI8jJy2fyS0+TtPtHZqVcztu3nUnHxocvjyAiIkenAk9CV1IduOIFuHwS7NkC43vAu3+G7Ey/k4mISBFbdu9n8NNzaLz8GXbE1Oamm39P7eQ4v2OJiFRJKvAk9LXoCzfPgXZD4Isx8OQZsOpjv1OJiAgw/6ftXPDYp9jauXSK+J7UHncQExvrdywRkSpLBZ6Eh/hU6DvGuz7PDCb2hWm3QNavficTEQlLzjkmfrmGAeO+IjYqkvEnfwFxqdDuSr+jiYhUaSrwJLw0PsubabPL7bDwJRjbCZZO8zuViEhYycrO43dTvuWeaUvoekot3h5Uh+Q178BvroXYRL/jiYhUaSrwJPxEx8M598F1H0JibZgyFCYPhl0b/E4mIhLyft6WySVPfsHrC9dxe68mPDPsNyR98x+IjIFO1/sdT0SkylOBJ+Grblu4bjb0ug9Wvu/15s1/DvLz/U4mIhKSZv+wmQsf/4x1v2by7LDfcHuvpkRkboGFL0PbQZCY7ndEEZEqTwWehLeDFkhvA2/e5l2fpwXSRaQUzKy3mf1gZivNbFQxjzc0s9lm9o2ZLTKz8wP7G5lZlpktDNz+U+Q5HcxsceCcY6wKLwaXn+8Y/f4Krn5uLnVT43nz1q50bxYo5uY8BXnZcMat/oYUEQkRKvBE4OAF0jcs8mba/OzfWiBdRI7JzCKBscB5QAtgoJm1OOSwu4Epzrl2wADgiSKP/eicaxu43VBk/5PAdUCTwK13sF5DMO3MyuG6ifP49/vLuahtPV678QxOrFnNe3D/Hpj7NDS/wPs7LCIix00FnkiBggXSb54DTc6B9+/11s7TAukicnQdgZXOuVXOuWxgMtDvkGMckBzYTgHWH+2EZnYCkOyc+8o554CJwEXlGzv4lm3YRd/HP+Pj5Vu4r29LHrn8NOJjIg8c8M0k2LfDm/hKRETKhQo8kUMln1BkgfRNXpH33j1aIF1EjqQe8EuR+2sD+4q6FxhiZmuBGUDR8YiNA0M3PzazM4ucc+0xzlmpTVu4jouf+Jys7Dwmj+jMsDMacdAo07wc+HIsNDwD6mf4F1REJMSowBM5khZ94eavod1g+Hy0N2xz9Sd+pxKRqmkg8Jxzrj5wPjDJzCKADUDDwNDNO4GXzCz5KOc5jJmNMLN5ZjZvy5Yt5R68tHLy8rl3+hJum7yQNvVSeWtkVzIa1Tj8wCWvw85foMttFR9SRCSEqcATOZr4VOj7mHd9HsDzF8L0WyFrh7+5RKQyWQc0KHK/fmBfUdcAUwCcc18CcUAt59x+59y2wP75wI9A08Dz6x/jnASeN845l+Gcy0hLSyuHl1N2m3ftY9D4r3juizVc3aUxL17XifSkuMMPdM774iytGTQ5t+KDioiEMBV4IiXR+Cy46Uvvm+ZvXoSxHWHpdL9TiUjlMBdoYmaNzSwGbxKVQ/9A/Az0BDCz5ngF3hYzSwtM0oKZnYQ3mcoq59wGYJeZdQ7MnjkUmFYxL6ds5q3ZTp/HPuO7dbsYPaAt91zYgujII3zM+PFD2PSdN3NmhD6KiIiUJ/1VFSmp6Hg45/7AAunpMOVK+O8Q2L3R72Qi4iPnXC5wCzALWIY3W+YSM7vfzPoGDvsdcJ2ZfQu8DAwPTJ5yFrDIzBYCrwI3OOe2B55zE/A0sBKvZ29mhb2oUnDO8dznqxkw7iuqxUTy+s1n0K/tMS4X/Hw0JJ0ArS+rmJAiImEkyu8AIlVOwQLpXz4OHz0Ij3eEc/8K7Yd6M3GKSNhxzs3Amzyl6L57imwvBboU87ypwNQjnHMe0Kp8k5avrOw8/vjaIt5YuJ5ezdP51+VtSYmPPvqT1i+E1R97X5hFxVZMUBGRMKIePJGyiIyGrncUWSB9pHd9nhZIF5Ew8dO2vVz8xOdM+3Y9vzunKeOuzDh2cQfwxRiISYIOw4OeUUQkHKnAEzkeNU+GodOLWSA91+9kIiJB88GyTVzw2Gds2LmPCcN/w609mxARUYIRDL+u8WbPzLgK4lKCnlNEJBypwBM5XhERBxZIP6VXYIH07rD+G7+TiYiUq/x8xyPvLeea5+fRsEYCb93albNPTS/5Cb4cCxYJnW8MXkgRkTCnAk+kvCSfAANePLBA+riz4b9XwqalficTETluOzKzufr5uYz5YAX9O9Rn6o1n0KBGQslPsHcbLJgEba6A5LrBCyoiEuY0yYpIeWvR11tW4asn4MsnYNmb0OoS6DYK0pr6nU5EpNSWrN/JDS/MZ+POffztolYM7tQQK+2kUnOfhtwsb2kEEREJGvXgiQRDfCp0/xPcvsibjOWHd+CJTvDa9ZqIRUSqlNcWrOWSJ74gJ9fx3+tPZ0jnE0tf3GVnwtdPQdPekN4sOEFFRARQgScSXAk1oNdf4LZvofNNsPQNePw3MO1mb7IBEZFKKjs3n3umfcedU76lbYNU3ry1K+0bVi/byRa+CJnboMtt5RtSREQOowJPpCIkpsFvH/AKvY4jYNEr8FgHePN22LnW73QiIgfZtGsfA8d/xcQvf+Laro158dpOpCWVcc26/Dxv3dB6GdDw9PINKiIih1GBJ1KRkurAeQ/CyG+8NaC+eQHGtIMZv4ddG/xOJyLCnFXb6DPmM5Zt2MXjg9px9wUtiIo8jo8Ly6Z7Ixa63AalHdopIiKlFtQCz8x6m9kPZrbSzEYV8/hZZrbAzHLNrH8ws4hUKin1oM+/YOQCOG0gzHsWxrSFd/4Eezb7nU5EwpBzjmc+W82gp+eQHBfFGzd34YI2xznbpXPw+WiocTI061M+QUVE5KiCVuCZWSQwFjgPaAEMNLMWhxz2MzAceClYOUQqtdSG0HcM3DIPWl0Kc56E0afBe/d4U4qLiFSQ3HzHm9+up2ezdN64pQtNaycd/0nXfOatCXrGLRARefznExGRYwrmMgkdgZXOuVUAZjYZ6AcULgrmnFsTeCw/iDlEKr8ajeGiJ6DrnfDxP+HzMTD3Geh0A5x+szdZi4hIEEVHRvD81R1Jio0iIqKchlJ+PhqqpXkjFUREpEIEc4hmPeCXIvfXBvaJyJHUOgUuHQ83fQVNzoFPH/Z69D56EPbt9DudiIS4lPjo8ivuNi2Ble9Bp+shOr58zikiIsdUJSZZMbMRZjbPzOZt2bLF7zgiwZfeDC57Dm743Fs0/aN/wKNt4JOHYf9uv9OJiBzbF49BdDXIuMbvJCIiYSWYBd46oEGR+/UD+0rNOTfOOZfhnMtIS0srl3AiVUKdVjDgRRjxMTTsDB/+1Sv0PnsUsvf6nU5EpHg718LiV6D9UA0xFxGpYMEs8OYCTcyssZnFAAOA6UH8fSKhq25bGPRfuPYDqNsO3v+LN3TzyycgJ8vvdCIiB/vqSW8GzdNv8juJiEjYCVqB55zLBW4BZgHLgCnOuSVmdr+Z9QUws9+Y2VrgMuApM1sSrDwiIaF+Blz5Glz1DqQ3h1l/hNFtYc44yN3vdzoREcjaAfOf82YGTm3odxoRkbATzFk0cc7NAGYcsu+eIttz8YZuikhpnHg6DHsTVn8Ksx+Amb+Hzx+Fs+6CtkMgKsbvhCISruY9C9l7oMtIv5OIiISlKjHJiogcQeMz4aqZcOXrkHQCvHUHPN4BFkyCvFy/04lIuMnZB3P+Ayf3gDqt/U4jIhKWVOCJVHVm3oepa9+HQa9AfA2YfguM/Q18Oxny8/xOKCLhYtF/Yc8m6HKb30lERMKWCjyRUGEGTc+FER/BgJderVpjAAAayklEQVQgOgFevx6e6AyLX4X8fL8Tikgoy8/3lkao0wYad/M7jYhI2FKBJxJqzKBZH7j+U7jsebAImHoNPHkGLJ2mQk9EgmP5TNi2wuu9s3JaLF1EREpNBZ5IqIqIgJYXwY1fwKXPQH4OTBkK487yhm5q1k0RKU+fj/ZmzWxxkd9JRETCmgo8kVAXEQmt+8NNc+Ci/3jr5r1+Pfy7JXz4N9i13u+EIlLV/fwV/DIHTr8FIoM6QbeIiByDCjyRcBEZBW0Hws1zYchUqNsePnkYHm0NrwyHn770FiYWkVIzs95m9oOZrTSzUcU83tDMZpvZN2a2yMzOD+w/x8zmm9niwM8eRZ7zUeCcCwO39Ip8TaXy+RiIrw7thvidREQk7OlrNpFwExEBp/TybttXwdxnvGUVlrzuTWve8Xqvxy863u+kIlWCmUUCY4FzgLXAXDOb7pxbWuSwu4EpzrknzawF3hqxjYCtwIXOufVm1gqYBdQr8rzBzrl5FfE6ymzLcvjhbej2B4ip5ncaEZGwpx48kXBW4yT47QPwu2Vwwb+9tfOm3wKPtID3/gI7fvY7oUhV0BFY6Zxb5ZzLBiYD/Q45xgHJge0UYD2Ac+4b51zBOOklQLyZxVZA5vLzxRiIioOOI/xOIiIiqMATEfC+dc+4Gm76Eoa9CY26eB/aRp8GkwfDqo81fFPkyOoBvxS5v5aDe+EA7gWGmNlavN67W4s5z6XAAudc0RmQJgSGZ/7ZrPipKc1shJnNM7N5W7ZsKfOLKJPdG72179oOhmq1KvZ3i4hIsVTgicgBZtD4LLjiBbhtkTfd+U9fwMS+8MTp3nDO7L1+pxSpigYCzznn6gPnA5PMrLANNrOWwD+B64s8Z7BzrjVwZuB2ZXEnds6Nc85lOOcy0tLSgvYCijXnP5CfC6ffXLG/V0REjkgFnogUL7UB9LoX7lwK/cZCZDS8fSf8qzm88yfv+j0RAVgHNChyv35gX1HXAFMAnHNfAnFALQAzqw+8Dgx1zv1Y8ATn3LrAz93AS3hDQSuP/bth7rPQvC/UPNnvNCIiEhASk6zk5OSwdu1a9u3b53cUKYG4uDjq169PdHS031GkJKLjvZnx2g72pkH/ehx8/RR89QQ0ORc6jYCTeniTt4iEp7lAEzNrjFfYDQAGHXLMz0BP4Dkza45X4G0xs1TgbWCUc+7zgoPNLApIdc5tNbNo4ALg/eC/lFKY/zzs3wldRvqdREREigiJAm/t2rUkJSXRqFEjjnCJglQSzjm2bdvG2rVrady4sd9xpDTMoGFn77ZrA8yfAPMmwAuXQs1TvAkWThsIccnHPpdICHHO5ZrZLXgzYEYCzzrnlpjZ/cA859x04HfAeDO7A2/CleHOORd43inAPWZ2T+CU5wJ7gVmB4i4Sr7gbX7Gv7Chys70veRqdCfU6+J1GRESKMFfFJk7IyMhw8+YdPGP0smXLaNasmYq7KsI5x/fff0/z5s39jiLHK3c/LJ0Gc56CdfMgJtEr8jqOgLSmfqeTEGBm851zGX7nqCqKayODYuHL8MYNMPhVaHJO8H+fiIgc5GjtY0j04AEq7qoQ/VuFkKhYaHO5d1s3H+aMgwXPw9zxcFJ36HS9N4wzItLvpCJSXpzzZtlNb+GtpykiIpWKLpopB927d2fWrFkH7Xv00Ue58cYbj/q8xMREANavX0///v2LPebss8/mWN/GPvroo2RmZhbeP//889mxY0dJoh/Vvffey8MPP3zc55EwUa8DXPIU3LEUetwNW36AlwfAmHbwxWOQ9avfCUWkPKx8HzYvhTNGekO3RUSkUlGBVw4GDhzI5MmTD9o3efJkBg4cWKLn161bl1dffbXMv//QAm/GjBmkpqaW+XwixyUxDc76Pdy+CC57DpLrwbt3e7NvvnkbbFrid0IROR6fj/b+v251qd9JRESkGCrwykH//v15++23yc7OBmDNmjWsX7+eM888kz179tCzZ0/at29P69atmTZt2mHPX7NmDa1atQIgKyuLAQMG0Lx5cy6++GKysrIKj7vxxhvJyMigZcuW/OUvfwFgzJgxrF+/nu7du9O9e3cAGjVqxNatWwF45JFHaNWqFa1ateLRRx8t/H3Nmzfnuuuuo2XLlpx77rkH/Z7iLFy4kM6dO9OmTRsuvvhifv3118Lf36JFC9q0acOAAQMA+Pjjj2nbti1t27alXbt27N69u8zvrVRhkdHQ8mK4eibc8Bm07g/fToYnz4DnLvCu3cvL9TuliJTGuvmw5lPofCNExfidRkREihEy1+AVuO/NJSxdv6tcz9mibjJ/ubDlER+vUaMGHTt2ZObMmfTr14/Jkydz+eWXY2bExcXx+uuvk5yczNatW+ncuTN9+/Y94nVoTz75JAkJCSxbtoxFixbRvn37wsceeOABatSoQV5eHj179mTRokWMHDmSRx55hNmzZ1OrVq2DzjV//nwmTJjAnDlzcM7RqVMnunXrRvXq1VmxYgUvv/wy48eP5/LLL2fq1KkMGTLkiK9x6NChPPbYY3Tr1o177rmH++67j0cffZQHH3yQ1atXExsbWzgs9OGHH2bs2LF06dKFPXv2EBcXV5q3W0JRndbQ73E45374ZhJ8/TRMGQrJ9eE3V0P74VCtpt8pReRYPh8DsSnQfpjfSURE5AjUg1dOig7TLDo80znHn/70J9q0aUOvXr1Yt24dmzZtOuJ5Pvnkk8JCq02bNrRp06bwsSlTptC+fXvatWvHkiVLWLp06VEzffbZZ1x88cVUq1aNxMRELrnkEj799FMAGjduTNu2bQHo0KEDa9asOeJ5du7cyY4dO+jWrRsAw4YN45NPPinMOHjwYF544QWiorzvC7p06cKdd97JmDFj2LFjR+F+ERJqQJfb4LaFMOAlb3HkD+6HR5rDGzd51/bs2ex3ShEpzrYfYdl070sZLYciIlJphdwn76P1tAVTv379uOOOO1iwYAGZmZl06OCtC/Tiiy+yZcsW5s+fT3R0NI0aNSrTguyrV6/m4YcfZu7cuVSvXp3hw4cf18LusbGxhduRkZHHHKJ5JG+//TaffPIJb775Jg888ACLFy9m1KhR9OnThxkzZtClSxdmzZpFs2bNypxVQlBEJDTr4902f+8tnv7tZFj4ovd4Ym2v16/w1gZqnKTZOEX89OVYiIiCTjf4nURERI4i5Ao8vyQmJtK9e3euvvrqgyZX2blzJ+np6URHRzN79mx++umno57nrLPO4qWXXqJHjx589913LFq0CIBdu3ZRrVo1UlJS2LRpEzNnzuTss88GICkpid27dx82RPPMM89k+PDhjBo1Cuccr7/+OpMmTSr1a0tJSaF69ep8+umnnHnmmUyaNIlu3bqRn5/PL7/8Qvfu3enatSuTJ09mz549bNu2jdatW9O6dWvmzp3L999/rwJPjiy9GVzwCJxzH6z/BjZ+BxsXe7dVH0F+4Dq96ARvWvaiRV/tFhBTzdf4ImFh71bvC5g2V0BSHb/TiIjIUajAK0cDBw7k4osvPmhGzcGDB3PhhRfSunVrMjIyjlno3HjjjVx11VU0b96c5s2bF/YEnnbaabRr145mzZrRoEEDunTpUvicESNG0Lt3b+rWrcvs2bML97dv357hw4fTsWNHAK699lratWt31OGYR/L8889zww03kJmZyUknncSECRPIy8tjyJAh7Ny5E+ccI0eOJDU1lT//+c/Mnj2biIgIWrZsyXnnnVfq3ydhKDYJGp/l3Qrk7veWW9i4GDYFCr8lr8H8CYEDzBvmWbToq9Pa6wHU9O0i5efrcZC7z1saQUREKjVzzvmdoVQyMjLcoevCLVu2jObNm/uUSMpC/2ZSZs7Bzl8CvXzfwcZF3vaOIr3jCbUOL/pqngKR+k6rqjGz+c65DL9zVBXFtZHHLXsv/LslNDwDBr5UvucWEZEyOVr7qE87IlK1mEFqQ+/WrM+B/Vk7vDX2NhUp+ub8B/K85UuIioP05gcXfbVbej2HInJk37wIWb9CF/XeiYhUBSrwRCQ0xKdCoy7erUBeDmxdfnBP37K3YMHEA8dUb3xw0VenNSTX1RBPEfDWqvzyMWjQCRp29juNiIiUgAo8EQldkdFeL13tlnDaFd4+52DX+oN7+jYu9qZ/LxBf/fCevhonaUIXCT9L34AdP0PvB/1OIiIiJaQCT0TCixmk1PNuTX97YP/+3bBp6cFF39ynvYklClRLhxqNvV6/Q39Wq6VePwktzsHno6FmE2iqybJERKoKFXgiIuBdi9ewk3crkJcL23/0ru37dTVsXw2/roE1n8Gi/wJFJqmKSYLqjaBGo8MLwOT6muBFqp7VH3tfeFw4BiIi/E4jIiIlpE8cIiJHEhkFaad6t0Pl7POGrhUUfttXedubv4flsw5M7gLe4tCpDYvv+aveCGISKuwliZTY56O9JUfaXOF3EhERKQUVeOVg27Zt9OzZE4CNGzcSGRlJWloaAF9//TUxMTHHPMdVV13FqFGjOPXUYj5IBowdO5bU1FQGDx583Jm7du3K448/Ttu2bY/7XCJhKToO0pp6t0Pl53nX+f0a6PHbvvpAIbhuHuzbefDxiXWOPPQzoYaGfkrF27AIfvwQet7j/bcuIiJVhgq8clCzZk0WLlwIwL333ktiYiJ33XXXQcc453DOEXGEYS4TJkwodn9RN9988/GHFZHgi4iE1AberejC7QUytxcZ8rkatq/xegBXzYZvD1lnLDY5MPSzmAIwuZ73u0TK2xePQUwiZFztdxIRESklFXhBtHLlSvr27Uu7du345ptveO+997jvvvtYsGABWVlZXHHFFdxzzz3AgR61Vq1aUatWLW644QZmzpxJQkIC06ZNIz09nbvvvptatWpx++2307VrV7p27cqHH37Izp07mTBhAmeccQZ79+5l6NChLFu2jBYtWrBmzRqefvrpo/bUvfDCC/zzn//EOUffvn35+9//Tm5uLldddRULFy7EOceIESMYOXIk//73vxk/fjxRUVG0adOGF154oaLeTpHQkVDDu9XrcPhjOVler9+hPX+blsD3MyA/58CxkTGQVMcbRnfQLf3w7ahjjyQQAbyhx99Nhc43ejPKiohIlRJ6Bd7MUd7sd+WpTms4r2xTRH///fdMnDiRjAxvofkHH3yQGjVqkJubS/fu3enfvz8tWrQ46Dk7d+6kW7duPPjgg9x55508++yzjBo16rBzO+f4+uuvmT59Ovfffz/vvPMOjz32GHXq1GHq1Kl8++23tG/f/qj51q5dy9133828efNISUmhV69evPXWW6SlpbF161YWL/beyx07dgDw0EMP8dNPPxETE1O4T0TKUXS8tyB7evPDH8vPg13rDi78dm+EPRu9HsCfv4TMbcWfN756McVfMQVhfHVN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\n",
"text/plain": [
"<Figure size 1080x360 with 2 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"# Plot accuracy and loss\n",
"fig, ax = plt.subplots(1, 2, figsize=(15,5))\n",
"ax[0].plot(val_loss, label='Validation loss')\n",
"ax[0].plot(tr_loss, label='Training loss')\n",
"ax[0].set_title('Losses')\n",
"ax[0].set_xlabel('Epoch')\n",
"ax[0].set_ylabel('Loss')\n",
"ax[0].legend()\n",
"ax[1].plot(val_acc, label='Validation accuracy')\n",
"ax[1].plot(tr_acc, label='Training accuracy')\n",
"ax[1].set_title('Accuracies')\n",
"ax[1].set_xlabel('Epoch')\n",
"ax[1].set_ylabel('Loss')\n",
"plt.legend()\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": 33,
"metadata": {
"colab": {},
"colab_type": "code",
"id": "yPFKQRti4wRD",
"outputId": "01d1694f-a0a5-462c-a486-a9eb27934622"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Test Loss: 0.336 | Test Acc: 85.43%\n"
]
}
],
"source": [
"# Evaluate model on test data\n",
"model.load_state_dict(torch.load('CNN-model.pt'))\n",
"\n",
"test_loss, test_acc = evaluate(model, test_iterator, criterion)\n",
"\n",
"print(f'Test Loss: {test_loss:.3f} | Test Acc: {test_acc*100:.2f}%')"
]
},
{
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "GyU2AeeV4wRH"
},
"source": [
"### Check performance with arbitrary sentences"
]
},
{
"cell_type": "code",
"execution_count": 40,
"metadata": {
"colab": {},
"colab_type": "code",
"id": "sjP-gqt54wRI"
},
"outputs": [],
"source": [
"def sentiment(model, sentence, min_len = 5):\n",
" '''Predict user-defined review sentiment.'''\n",
" model.eval()\n",
" tokenized = [tok.text for tok in nlp.tokenizer(sentence)]\n",
" if len(tokenized) < min_len:\n",
" tokenized += ['<pad>'] * (min_len - len(tokenized))\n",
" # Map words to word embeddings\n",
" indexed = [TEXT.vocab.stoi[t] for t in tokenized]\n",
" tensor = torch.LongTensor(indexed).to(device)\n",
" tensor = tensor.unsqueeze(0)\n",
" # Get predicitons\n",
" prediction = torch.sigmoid(model(tensor))\n",
" return prediction.item()"
]
},
{
"cell_type": "code",
"execution_count": 48,
"metadata": {
"colab": {},
"colab_type": "code",
"id": "yG4QmntM4wRK",
"outputId": "11b1195b-9887-4de9-e16a-46293d566bdd"
},
"outputs": [
{
"data": {
"text/plain": [
"[0.0067734261974692345, 0.49260634183883667, 0.9711275100708008]"
]
},
"execution_count": 48,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"reviews = ['This is the best movie I have ever watched!', \n",
" 'This is an okay movie', \n",
" 'This was a waste of time! I hated this movie.']\n",
"scores = [sentiment(model, review) for review in reviews]\n",
"scores"
]
},
{
"cell_type": "code",
"execution_count": 50,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[0.0500052347779274, 0.47646334767341614, 0.9872849583625793]"
]
},
"execution_count": 50,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"tricky_reviews = ['This is not the best movie I have ever watched!', \n",
" 'Some would say it is an okay movie, but I found it terrific.', \n",
" 'This was a waste of time! I did not like this movie.']\n",
"scores = [sentiment(model, review) for review in tricky_reviews]\n",
"scores"
]
}
],
"metadata": {
"colab": {
"name": "4 - Convolutional Sentiment Analysis.ipynb",
"provenance": []
},
"kernelspec": {
"display_name": "evamodels",
"language": "python",
"name": "evamodels"
},
"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.6.8"
}
},
"nbformat": 4,
"nbformat_minor": 1
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment