Repository: beezeetee/TDPDNE Branch: master Commit: ba58849417e1 Files: 87 Total size: 1.9 MB Directory structure: gitextract_ffogpws4/ ├── Image Processor/ │ ├── .gitignore │ ├── Dick_Pic_Mask-RCNN_Trainer.ipynb │ ├── LICENSE │ ├── MANIFEST.in │ ├── README.md │ ├── __init__.py │ ├── align_images.py │ ├── cv_tools.py │ ├── download_utils.py │ ├── mrcnn/ │ │ ├── __init__.py │ │ ├── config.py │ │ ├── model.py │ │ ├── parallel_model.py │ │ ├── utils.py │ │ └── visualize.py │ ├── requirements.txt │ ├── scratch.py │ ├── setup.cfg │ └── setup.py ├── README.md ├── requirements.txt └── stylegan2-tpu/ ├── Dockerfile ├── LICENSE.txt ├── README.md ├── align_mammos.py ├── convert_ckpt_to_pkl.py ├── convert_pkl_to_ckpt.py ├── dataset_tool.py ├── dnnlib/ │ ├── __init__.py │ ├── submission/ │ │ ├── __init__.py │ │ ├── internal/ │ │ │ ├── __init__.py │ │ │ └── local.py │ │ ├── run_context.py │ │ └── submit.py │ ├── tflib/ │ │ ├── __init__.py │ │ ├── autosummary.py │ │ ├── custom_ops.py │ │ ├── network.py │ │ ├── ops/ │ │ │ ├── __init__.py │ │ │ ├── fused_bias_act.cu │ │ │ ├── fused_bias_act.py │ │ │ ├── upfirdn_2d.cu │ │ │ └── upfirdn_2d.py │ │ ├── optimizer.py │ │ ├── tfutil.py │ │ └── tpu_summaries.py │ └── util.py ├── docs/ │ ├── license.html │ └── versions.html ├── encoder/ │ ├── __init__.py │ ├── generator_model.py │ └── perceptual_model.py ├── ext.l ├── generate_images_tpu.py ├── mammos.py ├── metrics/ │ ├── __init__.py │ ├── frechet_inception_distance.py │ ├── inception_score.py │ ├── linear_separability.py │ ├── metric_base.py │ ├── metric_defaults.py │ ├── perceptual_path_length.py │ └── precision_recall.py ├── prepare_image.py ├── pretrained_networks.py ├── projector.py ├── random_crops.py ├── repl.l ├── requirements.txt ├── run_generator.py ├── run_metrics.py ├── run_projector.py ├── run_training.py ├── test_nvcc.cu ├── tflex.py ├── tflex_test.py ├── train_tpu.sh ├── training/ │ ├── __init__.py │ ├── dataset.py │ ├── imagenet_input.py │ ├── loss.py │ ├── misc.py │ ├── networks_stylegan.py │ ├── networks_stylegan2.py │ ├── train_runner.py │ └── training_loop.py └── view.py ================================================ FILE CONTENTS ================================================ ================================================ FILE: Image Processor/.gitignore ================================================ # Data files and directories common in repo root datasets/ logs/ *.h5 results/ temp/ test/ # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] *$py.class # Distribution / packaging .Python env/ build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib/ lib64/ parts/ sdist/ var/ wheels/ *.egg-info/ .installed.cfg *.egg # Installer logs pip-log.txt pip-delete-this-directory.txt # VS Studio Code .vscode # PyCharm .idea/ # Dropbox .dropbox.attr # Jupyter Notebook .ipynb_checkpoints # pyenv .python-version # dotenv .env # virtualenv .venv venv/ ENV/ ================================================ FILE: Image Processor/Dick_Pic_Mask-RCNN_Trainer.ipynb ================================================ { "cells": [ { "cell_type": "code", "execution_count": 11, "metadata": { "tags": [] }, "outputs": [], "source": [ "from mrcnn.config import Config\n", "from mrcnn import model as modellib\n", "from mrcnn import visualize\n", "import mrcnn\n", "from mrcnn import utils\n", "from mrcnn.utils import Dataset\n", "from mrcnn.model import MaskRCNN\n", "\n", "import numpy as np\n", "from numpy import zeros\n", "from numpy import asarray\n", "import colorsys\n", "import argparse\n", "import imutils\n", "import random\n", "import cv2\n", "import os\n", "import time\n", "\n", "from matplotlib import pyplot\n", "from matplotlib.patches import Rectangle\n", "from keras.models import load_model\n", "\n", "%matplotlib inline\n", "\n", "from os import listdir\n", "from pathlib import Path\n", "import tarfile\n", "from xml.etree import ElementTree\n", "\n", "from download_utils import download_file_from_google_drive" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "#inherting from Config class\n", "\n", "class myMaskRCNNConfig(Config):\n", " # give the configuration a recognizable name\n", " NAME = \"MaskRCNN_config\"\n", " \n", " # set the number of GPUs to use along with the number of images\n", " # per GPU\n", " GPU_COUNT = 1\n", " IMAGES_PER_GPU = 1\n", " \n", " # number of classes (we would normally add +1 for the background)\n", " # kangaroo + BG\n", " NUM_CLASSES = 1+1\n", " \n", " # Number of training steps per epoch\n", " STEPS_PER_EPOCH = 131\n", " \n", " # Learning rate\n", " LEARNING_RATE=0.006\n", " \n", " # Skip detections with < 90% confidence\n", " DETECTION_MIN_CONFIDENCE = 0.9\n", " \n", " # setting Max ground truth instances\n", " MAX_GT_INSTANCES=10" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "config= myMaskRCNNConfig()" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "tags": [] }, "outputs": [ { "output_type": "stream", "name": "stdout", "text": "\nConfigurations:\nBACKBONE resnet101\nBACKBONE_STRIDES [4, 8, 16, 32, 64]\nBATCH_SIZE 1\nBBOX_STD_DEV [0.1 0.1 0.2 0.2]\nCOMPUTE_BACKBONE_SHAPE None\nDETECTION_MAX_INSTANCES 100\nDETECTION_MIN_CONFIDENCE 0.9\nDETECTION_NMS_THRESHOLD 0.3\nFPN_CLASSIF_FC_LAYERS_SIZE 1024\nGPU_COUNT 1\nGRADIENT_CLIP_NORM 5.0\nIMAGES_PER_GPU 1\nIMAGE_CHANNEL_COUNT 3\nIMAGE_MAX_DIM 1024\nIMAGE_META_SIZE 14\nIMAGE_MIN_DIM 800\nIMAGE_MIN_SCALE 0\nIMAGE_RESIZE_MODE square\nIMAGE_SHAPE [1024 1024 3]\nLEARNING_MOMENTUM 0.9\nLEARNING_RATE 0.006\nLOSS_WEIGHTS {'rpn_class_loss': 1.0, 'rpn_bbox_loss': 1.0, 'mrcnn_class_loss': 1.0, 'mrcnn_bbox_loss': 1.0, 'mrcnn_mask_loss': 1.0}\nMASK_POOL_SIZE 14\nMASK_SHAPE [28, 28]\nMAX_GT_INSTANCES 10\nMEAN_PIXEL [123.7 116.8 103.9]\nMINI_MASK_SHAPE (56, 56)\nNAME MaskRCNN_config\nNUM_CLASSES 2\nPOOL_SIZE 7\nPOST_NMS_ROIS_INFERENCE 1000\nPOST_NMS_ROIS_TRAINING 2000\nPRE_NMS_LIMIT 6000\nROI_POSITIVE_RATIO 0.33\nRPN_ANCHOR_RATIOS [0.5, 1, 2]\nRPN_ANCHOR_SCALES (32, 64, 128, 256, 512)\nRPN_ANCHOR_STRIDE 1\nRPN_BBOX_STD_DEV [0.1 0.1 0.2 0.2]\nRPN_NMS_THRESHOLD 0.7\nRPN_TRAIN_ANCHORS_PER_IMAGE 256\nSTEPS_PER_EPOCH 131\nTOP_DOWN_PYRAMID_SIZE 256\nTRAIN_BN False\nTRAIN_ROIS_PER_IMAGE 200\nUSE_MINI_MASK True\nUSE_RPN_ROIS True\nVALIDATION_STEPS 50\nWEIGHT_DECAY 0.0001\n\n\n" } ], "source": [ "config.display()" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "tags": [] }, "outputs": [ { "output_type": "stream", "name": "stdout", "text": "Loading Mask R-CNN model...\nWARNING:tensorflow:From C:\\Users\\Sayon_Desktop\\AppData\\Local\\Programs\\Python\\Python37\\lib\\site-packages\\keras\\backend\\tensorflow_backend.py:541: The name tf.placeholder is deprecated. Please use tf.compat.v1.placeholder instead.\n\nWARNING:tensorflow:From C:\\Users\\Sayon_Desktop\\AppData\\Local\\Programs\\Python\\Python37\\lib\\site-packages\\keras\\backend\\tensorflow_backend.py:66: The name tf.get_default_graph is deprecated. Please use tf.compat.v1.get_default_graph instead.\n\nWARNING:tensorflow:From C:\\Users\\Sayon_Desktop\\AppData\\Local\\Programs\\Python\\Python37\\lib\\site-packages\\keras\\backend\\tensorflow_backend.py:4432: The name tf.random_uniform is deprecated. Please use tf.random.uniform instead.\n\nWARNING:tensorflow:From C:\\Users\\Sayon_Desktop\\AppData\\Local\\Programs\\Python\\Python37\\lib\\site-packages\\keras\\backend\\tensorflow_backend.py:2139: The name tf.nn.fused_batch_norm is deprecated. Please use tf.compat.v1.nn.fused_batch_norm instead.\n\nWARNING:tensorflow:From C:\\Users\\Sayon_Desktop\\AppData\\Local\\Programs\\Python\\Python37\\lib\\site-packages\\keras\\backend\\tensorflow_backend.py:4267: The name tf.nn.max_pool is deprecated. Please use tf.nn.max_pool2d instead.\n\nWARNING:tensorflow:From C:\\Users\\Sayon_Desktop\\AppData\\Local\\Programs\\Python\\Python37\\lib\\site-packages\\keras\\backend\\tensorflow_backend.py:2239: The name tf.image.resize_nearest_neighbor is deprecated. Please use tf.compat.v1.image.resize_nearest_neighbor instead.\n\nWARNING:tensorflow:From C:\\Users\\Sayon_Desktop\\AppData\\Local\\Programs\\Python\\Python37\\lib\\site-packages\\tensorflow_core\\python\\ops\\array_ops.py:1475: where (from tensorflow.python.ops.array_ops) is deprecated and will be removed in a future version.\nInstructions for updating:\nUse tf.where in 2.0, which has the same broadcast rule as np.where\nWARNING:tensorflow:From d:\\Vue\\TDPDNE\\git_repo\\Dataset Creator\\Mask_RCNN\\mrcnn\\model.py:553: The name tf.random_shuffle is deprecated. Please use tf.random.shuffle instead.\n\nWARNING:tensorflow:From d:\\Vue\\TDPDNE\\git_repo\\Dataset Creator\\Mask_RCNN\\mrcnn\\utils.py:202: The name tf.log is deprecated. Please use tf.math.log instead.\n\nWARNING:tensorflow:From d:\\Vue\\TDPDNE\\git_repo\\Dataset Creator\\Mask_RCNN\\mrcnn\\model.py:600: calling crop_and_resize_v1 (from tensorflow.python.ops.image_ops_impl) with box_ind is deprecated and will be removed in a future version.\nInstructions for updating:\nbox_ind is deprecated, use box_indices instead\n" } ], "source": [ "# initialize the Mask R-CNN model for inference \n", "print(\"Loading Mask R-CNN model...\")\n", "model = modellib.MaskRCNN(mode=\"training\", config=config, model_dir='./')" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "tags": [ "outputPrepend" ] }, "outputs": [ { "output_type": "stream", "name": "stdout", "text": "0] \n__________________________________________________________________________________________________\nres5b_branch2c (Conv2D) (None, None, None, 2 1050624 activation_65[0][0] \n__________________________________________________________________________________________________\nbn5b_branch2c (BatchNorm) (None, None, None, 2 8192 res5b_branch2c[0][0] \n__________________________________________________________________________________________________\nadd_32 (Add) (None, None, None, 2 0 bn5b_branch2c[0][0] \n res5a_out[0][0] \n__________________________________________________________________________________________________\nres5b_out (Activation) (None, None, None, 2 0 add_32[0][0] \n__________________________________________________________________________________________________\nres5c_branch2a (Conv2D) (None, None, None, 5 1049088 res5b_out[0][0] \n__________________________________________________________________________________________________\nbn5c_branch2a (BatchNorm) (None, None, None, 5 2048 res5c_branch2a[0][0] \n__________________________________________________________________________________________________\nactivation_66 (Activation) (None, None, None, 5 0 bn5c_branch2a[0][0] \n__________________________________________________________________________________________________\nres5c_branch2b (Conv2D) (None, None, None, 5 2359808 activation_66[0][0] \n__________________________________________________________________________________________________\nbn5c_branch2b (BatchNorm) (None, None, None, 5 2048 res5c_branch2b[0][0] \n__________________________________________________________________________________________________\nactivation_67 (Activation) (None, None, None, 5 0 bn5c_branch2b[0][0] \n__________________________________________________________________________________________________\nres5c_branch2c (Conv2D) (None, None, None, 2 1050624 activation_67[0][0] \n__________________________________________________________________________________________________\nbn5c_branch2c (BatchNorm) (None, None, None, 2 8192 res5c_branch2c[0][0] \n__________________________________________________________________________________________________\nadd_33 (Add) (None, None, None, 2 0 bn5c_branch2c[0][0] \n res5b_out[0][0] \n__________________________________________________________________________________________________\nres5c_out (Activation) (None, None, None, 2 0 add_33[0][0] \n__________________________________________________________________________________________________\nfpn_c5p5 (Conv2D) (None, None, None, 2 524544 res5c_out[0][0] \n__________________________________________________________________________________________________\nfpn_p5upsampled (UpSampling2D) (None, None, None, 2 0 fpn_c5p5[0][0] \n__________________________________________________________________________________________________\nfpn_c4p4 (Conv2D) (None, None, None, 2 262400 res4w_out[0][0] \n__________________________________________________________________________________________________\nfpn_p4add (Add) (None, None, None, 2 0 fpn_p5upsampled[0][0] \n fpn_c4p4[0][0] \n__________________________________________________________________________________________________\nfpn_p4upsampled (UpSampling2D) (None, None, None, 2 0 fpn_p4add[0][0] \n__________________________________________________________________________________________________\nfpn_c3p3 (Conv2D) (None, None, None, 2 131328 res3d_out[0][0] \n__________________________________________________________________________________________________\nfpn_p3add (Add) (None, None, None, 2 0 fpn_p4upsampled[0][0] \n fpn_c3p3[0][0] \n__________________________________________________________________________________________________\nfpn_p3upsampled (UpSampling2D) (None, None, None, 2 0 fpn_p3add[0][0] \n__________________________________________________________________________________________________\nfpn_c2p2 (Conv2D) (None, None, None, 2 65792 res2c_out[0][0] \n__________________________________________________________________________________________________\nfpn_p2add (Add) (None, None, None, 2 0 fpn_p3upsampled[0][0] \n fpn_c2p2[0][0] \n__________________________________________________________________________________________________\nfpn_p5 (Conv2D) (None, None, None, 2 590080 fpn_c5p5[0][0] \n__________________________________________________________________________________________________\nfpn_p2 (Conv2D) (None, None, None, 2 590080 fpn_p2add[0][0] \n__________________________________________________________________________________________________\nfpn_p3 (Conv2D) (None, None, None, 2 590080 fpn_p3add[0][0] \n__________________________________________________________________________________________________\nfpn_p4 (Conv2D) (None, None, None, 2 590080 fpn_p4add[0][0] \n__________________________________________________________________________________________________\nfpn_p6 (MaxPooling2D) (None, None, None, 2 0 fpn_p5[0][0] \n__________________________________________________________________________________________________\nrpn_model (Model) [(None, None, 2), (N 1189394 fpn_p2[0][0] \n fpn_p3[0][0] \n fpn_p4[0][0] \n fpn_p5[0][0] \n fpn_p6[0][0] \n__________________________________________________________________________________________________\nrpn_class (Concatenate) (None, None, 2) 0 rpn_model[1][1] \n rpn_model[2][1] \n rpn_model[3][1] \n rpn_model[4][1] \n rpn_model[5][1] \n__________________________________________________________________________________________________\nrpn_bbox (Concatenate) (None, None, 4) 0 rpn_model[1][2] \n rpn_model[2][2] \n rpn_model[3][2] \n rpn_model[4][2] \n rpn_model[5][2] \n__________________________________________________________________________________________________\nanchors (Lambda) (1, 261888, 4) 0 input_image[0][0] \n__________________________________________________________________________________________________\ninput_gt_boxes (InputLayer) (None, None, 4) 0 \n__________________________________________________________________________________________________\nROI (ProposalLayer) (None, 2000, 4) 0 rpn_class[0][0] \n rpn_bbox[0][0] \n anchors[0][0] \n__________________________________________________________________________________________________\ninput_gt_class_ids (InputLayer) (None, None) 0 \n__________________________________________________________________________________________________\nlambda_1 (Lambda) (None, None, 4) 0 input_gt_boxes[0][0] \n__________________________________________________________________________________________________\ninput_gt_masks (InputLayer) (None, 56, 56, None) 0 \n__________________________________________________________________________________________________\nproposal_targets (DetectionTarg [(None, 200, 4), (No 0 ROI[0][0] \n input_gt_class_ids[0][0] \n lambda_1[0][0] \n input_gt_masks[0][0] \n__________________________________________________________________________________________________\ninput_image_meta (InputLayer) (None, 14) 0 \n__________________________________________________________________________________________________\nroi_align_mask (PyramidROIAlign (None, 200, 14, 14, 0 proposal_targets[0][0] \n input_image_meta[0][0] \n fpn_p2[0][0] \n fpn_p3[0][0] \n fpn_p4[0][0] \n fpn_p5[0][0] \n__________________________________________________________________________________________________\nmrcnn_mask_conv1 (TimeDistribut (None, 200, 14, 14, 590080 roi_align_mask[0][0] \n__________________________________________________________________________________________________\nmrcnn_mask_bn1 (TimeDistributed (None, 200, 14, 14, 1024 mrcnn_mask_conv1[0][0] \n__________________________________________________________________________________________________\nactivation_71 (Activation) (None, 200, 14, 14, 0 mrcnn_mask_bn1[0][0] \n__________________________________________________________________________________________________\nmrcnn_mask_conv2 (TimeDistribut (None, 200, 14, 14, 590080 activation_71[0][0] \n__________________________________________________________________________________________________\nroi_align_classifier (PyramidRO (None, 200, 7, 7, 25 0 proposal_targets[0][0] \n input_image_meta[0][0] \n fpn_p2[0][0] \n fpn_p3[0][0] \n fpn_p4[0][0] \n fpn_p5[0][0] \n__________________________________________________________________________________________________\nmrcnn_mask_bn2 (TimeDistributed (None, 200, 14, 14, 1024 mrcnn_mask_conv2[0][0] \n__________________________________________________________________________________________________\nmrcnn_class_conv1 (TimeDistribu (None, 200, 1, 1, 10 12846080 roi_align_classifier[0][0] \n__________________________________________________________________________________________________\nactivation_72 (Activation) (None, 200, 14, 14, 0 mrcnn_mask_bn2[0][0] \n__________________________________________________________________________________________________\nmrcnn_class_bn1 (TimeDistribute (None, 200, 1, 1, 10 4096 mrcnn_class_conv1[0][0] \n__________________________________________________________________________________________________\nmrcnn_mask_conv3 (TimeDistribut (None, 200, 14, 14, 590080 activation_72[0][0] \n__________________________________________________________________________________________________\nactivation_68 (Activation) (None, 200, 1, 1, 10 0 mrcnn_class_bn1[0][0] \n__________________________________________________________________________________________________\nmrcnn_mask_bn3 (TimeDistributed (None, 200, 14, 14, 1024 mrcnn_mask_conv3[0][0] \n__________________________________________________________________________________________________\nmrcnn_class_conv2 (TimeDistribu (None, 200, 1, 1, 10 1049600 activation_68[0][0] \n__________________________________________________________________________________________________\nactivation_73 (Activation) (None, 200, 14, 14, 0 mrcnn_mask_bn3[0][0] \n__________________________________________________________________________________________________\nmrcnn_class_bn2 (TimeDistribute (None, 200, 1, 1, 10 4096 mrcnn_class_conv2[0][0] \n__________________________________________________________________________________________________\nmrcnn_mask_conv4 (TimeDistribut (None, 200, 14, 14, 590080 activation_73[0][0] \n__________________________________________________________________________________________________\nactivation_69 (Activation) (None, 200, 1, 1, 10 0 mrcnn_class_bn2[0][0] \n__________________________________________________________________________________________________\nmrcnn_mask_bn4 (TimeDistributed (None, 200, 14, 14, 1024 mrcnn_mask_conv4[0][0] \n__________________________________________________________________________________________________\npool_squeeze (Lambda) (None, 200, 1024) 0 activation_69[0][0] \n__________________________________________________________________________________________________\nactivation_74 (Activation) (None, 200, 14, 14, 0 mrcnn_mask_bn4[0][0] \n__________________________________________________________________________________________________\nmrcnn_bbox_fc (TimeDistributed) (None, 200, 8) 8200 pool_squeeze[0][0] \n__________________________________________________________________________________________________\nmrcnn_mask_deconv (TimeDistribu (None, 200, 28, 28, 262400 activation_74[0][0] \n__________________________________________________________________________________________________\nrpn_class_logits (Concatenate) (None, None, 2) 0 rpn_model[1][0] \n rpn_model[2][0] \n rpn_model[3][0] \n rpn_model[4][0] \n rpn_model[5][0] \n__________________________________________________________________________________________________\nmrcnn_class_logits (TimeDistrib (None, 200, 2) 2050 pool_squeeze[0][0] \n__________________________________________________________________________________________________\nmrcnn_bbox (Reshape) (None, 200, 2, 4) 0 mrcnn_bbox_fc[0][0] \n__________________________________________________________________________________________________\nmrcnn_mask (TimeDistributed) (None, 200, 28, 28, 514 mrcnn_mask_deconv[0][0] \n__________________________________________________________________________________________________\ninput_rpn_match (InputLayer) (None, None, 1) 0 \n__________________________________________________________________________________________________\ninput_rpn_bbox (InputLayer) (None, None, 4) 0 \n__________________________________________________________________________________________________\nlambda_4 (Lambda) (None, 2) 0 input_image_meta[0][0] \n__________________________________________________________________________________________________\nmrcnn_class (TimeDistributed) (None, 200, 2) 0 mrcnn_class_logits[0][0] \n__________________________________________________________________________________________________\noutput_rois (Lambda) (None, 200, 4) 0 proposal_targets[0][0] \n__________________________________________________________________________________________________\nrpn_class_loss (Lambda) () 0 input_rpn_match[0][0] \n rpn_class_logits[0][0] \n__________________________________________________________________________________________________\nrpn_bbox_loss (Lambda) () 0 input_rpn_bbox[0][0] \n input_rpn_match[0][0] \n rpn_bbox[0][0] \n__________________________________________________________________________________________________\nmrcnn_class_loss (Lambda) () 0 proposal_targets[0][1] \n mrcnn_class_logits[0][0] \n lambda_4[0][0] \n__________________________________________________________________________________________________\nmrcnn_bbox_loss (Lambda) () 0 proposal_targets[0][2] \n proposal_targets[0][1] \n mrcnn_bbox[0][0] \n__________________________________________________________________________________________________\nmrcnn_mask_loss (Lambda) () 0 proposal_targets[0][3] \n proposal_targets[0][1] \n mrcnn_mask[0][0] \n==================================================================================================\nTotal params: 63,733,406\nTrainable params: 63,621,918\nNon-trainable params: 111,488\n__________________________________________________________________________________________________\n" } ], "source": [ "model.keras_model.summary()" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "tags": [] }, "outputs": [ { "output_type": "stream", "name": "stdout", "text": "Downloading pretrained model to mask_rcnn_coco.h5 ...\n... done downloading pretrained model!\nWARNING:tensorflow:From C:\\Users\\Sayon_Desktop\\AppData\\Local\\Programs\\Python\\Python37\\lib\\site-packages\\keras\\backend\\tensorflow_backend.py:190: The name tf.get_default_session is deprecated. Please use tf.compat.v1.get_default_session instead.\n\nWARNING:tensorflow:From C:\\Users\\Sayon_Desktop\\AppData\\Local\\Programs\\Python\\Python37\\lib\\site-packages\\keras\\backend\\tensorflow_backend.py:200: The name tf.ConfigProto is deprecated. Please use tf.compat.v1.ConfigProto instead.\n\nWARNING:tensorflow:From C:\\Users\\Sayon_Desktop\\AppData\\Local\\Programs\\Python\\Python37\\lib\\site-packages\\keras\\backend\\tensorflow_backend.py:203: The name tf.Session is deprecated. Please use tf.compat.v1.Session instead.\n\nWARNING:tensorflow:From C:\\Users\\Sayon_Desktop\\AppData\\Local\\Programs\\Python\\Python37\\lib\\site-packages\\keras\\backend\\tensorflow_backend.py:207: The name tf.global_variables is deprecated. Please use tf.compat.v1.global_variables instead.\n\nWARNING:tensorflow:From C:\\Users\\Sayon_Desktop\\AppData\\Local\\Programs\\Python\\Python37\\lib\\site-packages\\keras\\backend\\tensorflow_backend.py:216: The name tf.is_variable_initialized is deprecated. Please use tf.compat.v1.is_variable_initialized instead.\n\nWARNING:tensorflow:From C:\\Users\\Sayon_Desktop\\AppData\\Local\\Programs\\Python\\Python37\\lib\\site-packages\\keras\\backend\\tensorflow_backend.py:223: The name tf.variables_initializer is deprecated. Please use tf.compat.v1.variables_initializer instead.\n\n" } ], "source": [ "# Local path to trained weights file\n", "COCO_MODEL_PATH = \"mask_rcnn_coco.h5\"\n", "# Download COCO trained weights from Releases if needed\n", "if not os.path.exists(COCO_MODEL_PATH):\n", " utils.download_trained_weights(COCO_MODEL_PATH)\n", "\n", "#n load the weights for COCO\n", "model.load_weights(COCO_MODEL_PATH,\n", " by_name=True, \n", " exclude=[\"mrcnn_class_logits\", \"mrcnn_bbox_fc\", \"mrcnn_bbox\", \"mrcnn_mask\"])\n" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "tags": [ "outputPrepend" ] }, "outputs": [ { "output_type": "stream", "name": "stdout", "text": "0] \n__________________________________________________________________________________________________\nres5b_branch2c (Conv2D) (None, None, None, 2 1050624 activation_65[0][0] \n__________________________________________________________________________________________________\nbn5b_branch2c (BatchNorm) (None, None, None, 2 8192 res5b_branch2c[0][0] \n__________________________________________________________________________________________________\nadd_32 (Add) (None, None, None, 2 0 bn5b_branch2c[0][0] \n res5a_out[0][0] \n__________________________________________________________________________________________________\nres5b_out (Activation) (None, None, None, 2 0 add_32[0][0] \n__________________________________________________________________________________________________\nres5c_branch2a (Conv2D) (None, None, None, 5 1049088 res5b_out[0][0] \n__________________________________________________________________________________________________\nbn5c_branch2a (BatchNorm) (None, None, None, 5 2048 res5c_branch2a[0][0] \n__________________________________________________________________________________________________\nactivation_66 (Activation) (None, None, None, 5 0 bn5c_branch2a[0][0] \n__________________________________________________________________________________________________\nres5c_branch2b (Conv2D) (None, None, None, 5 2359808 activation_66[0][0] \n__________________________________________________________________________________________________\nbn5c_branch2b (BatchNorm) (None, None, None, 5 2048 res5c_branch2b[0][0] \n__________________________________________________________________________________________________\nactivation_67 (Activation) (None, None, None, 5 0 bn5c_branch2b[0][0] \n__________________________________________________________________________________________________\nres5c_branch2c (Conv2D) (None, None, None, 2 1050624 activation_67[0][0] \n__________________________________________________________________________________________________\nbn5c_branch2c (BatchNorm) (None, None, None, 2 8192 res5c_branch2c[0][0] \n__________________________________________________________________________________________________\nadd_33 (Add) (None, None, None, 2 0 bn5c_branch2c[0][0] \n res5b_out[0][0] \n__________________________________________________________________________________________________\nres5c_out (Activation) (None, None, None, 2 0 add_33[0][0] \n__________________________________________________________________________________________________\nfpn_c5p5 (Conv2D) (None, None, None, 2 524544 res5c_out[0][0] \n__________________________________________________________________________________________________\nfpn_p5upsampled (UpSampling2D) (None, None, None, 2 0 fpn_c5p5[0][0] \n__________________________________________________________________________________________________\nfpn_c4p4 (Conv2D) (None, None, None, 2 262400 res4w_out[0][0] \n__________________________________________________________________________________________________\nfpn_p4add (Add) (None, None, None, 2 0 fpn_p5upsampled[0][0] \n fpn_c4p4[0][0] \n__________________________________________________________________________________________________\nfpn_p4upsampled (UpSampling2D) (None, None, None, 2 0 fpn_p4add[0][0] \n__________________________________________________________________________________________________\nfpn_c3p3 (Conv2D) (None, None, None, 2 131328 res3d_out[0][0] \n__________________________________________________________________________________________________\nfpn_p3add (Add) (None, None, None, 2 0 fpn_p4upsampled[0][0] \n fpn_c3p3[0][0] \n__________________________________________________________________________________________________\nfpn_p3upsampled (UpSampling2D) (None, None, None, 2 0 fpn_p3add[0][0] \n__________________________________________________________________________________________________\nfpn_c2p2 (Conv2D) (None, None, None, 2 65792 res2c_out[0][0] \n__________________________________________________________________________________________________\nfpn_p2add (Add) (None, None, None, 2 0 fpn_p3upsampled[0][0] \n fpn_c2p2[0][0] \n__________________________________________________________________________________________________\nfpn_p5 (Conv2D) (None, None, None, 2 590080 fpn_c5p5[0][0] \n__________________________________________________________________________________________________\nfpn_p2 (Conv2D) (None, None, None, 2 590080 fpn_p2add[0][0] \n__________________________________________________________________________________________________\nfpn_p3 (Conv2D) (None, None, None, 2 590080 fpn_p3add[0][0] \n__________________________________________________________________________________________________\nfpn_p4 (Conv2D) (None, None, None, 2 590080 fpn_p4add[0][0] \n__________________________________________________________________________________________________\nfpn_p6 (MaxPooling2D) (None, None, None, 2 0 fpn_p5[0][0] \n__________________________________________________________________________________________________\nrpn_model (Model) [(None, None, 2), (N 1189394 fpn_p2[0][0] \n fpn_p3[0][0] \n fpn_p4[0][0] \n fpn_p5[0][0] \n fpn_p6[0][0] \n__________________________________________________________________________________________________\nrpn_class (Concatenate) (None, None, 2) 0 rpn_model[1][1] \n rpn_model[2][1] \n rpn_model[3][1] \n rpn_model[4][1] \n rpn_model[5][1] \n__________________________________________________________________________________________________\nrpn_bbox (Concatenate) (None, None, 4) 0 rpn_model[1][2] \n rpn_model[2][2] \n rpn_model[3][2] \n rpn_model[4][2] \n rpn_model[5][2] \n__________________________________________________________________________________________________\nanchors (Lambda) (1, 261888, 4) 0 input_image[0][0] \n__________________________________________________________________________________________________\ninput_gt_boxes (InputLayer) (None, None, 4) 0 \n__________________________________________________________________________________________________\nROI (ProposalLayer) (None, 2000, 4) 0 rpn_class[0][0] \n rpn_bbox[0][0] \n anchors[0][0] \n__________________________________________________________________________________________________\ninput_gt_class_ids (InputLayer) (None, None) 0 \n__________________________________________________________________________________________________\nlambda_1 (Lambda) (None, None, 4) 0 input_gt_boxes[0][0] \n__________________________________________________________________________________________________\ninput_gt_masks (InputLayer) (None, 56, 56, None) 0 \n__________________________________________________________________________________________________\nproposal_targets (DetectionTarg [(None, 200, 4), (No 0 ROI[0][0] \n input_gt_class_ids[0][0] \n lambda_1[0][0] \n input_gt_masks[0][0] \n__________________________________________________________________________________________________\ninput_image_meta (InputLayer) (None, 14) 0 \n__________________________________________________________________________________________________\nroi_align_mask (PyramidROIAlign (None, 200, 14, 14, 0 proposal_targets[0][0] \n input_image_meta[0][0] \n fpn_p2[0][0] \n fpn_p3[0][0] \n fpn_p4[0][0] \n fpn_p5[0][0] \n__________________________________________________________________________________________________\nmrcnn_mask_conv1 (TimeDistribut (None, 200, 14, 14, 590080 roi_align_mask[0][0] \n__________________________________________________________________________________________________\nmrcnn_mask_bn1 (TimeDistributed (None, 200, 14, 14, 1024 mrcnn_mask_conv1[0][0] \n__________________________________________________________________________________________________\nactivation_71 (Activation) (None, 200, 14, 14, 0 mrcnn_mask_bn1[0][0] \n__________________________________________________________________________________________________\nmrcnn_mask_conv2 (TimeDistribut (None, 200, 14, 14, 590080 activation_71[0][0] \n__________________________________________________________________________________________________\nroi_align_classifier (PyramidRO (None, 200, 7, 7, 25 0 proposal_targets[0][0] \n input_image_meta[0][0] \n fpn_p2[0][0] \n fpn_p3[0][0] \n fpn_p4[0][0] \n fpn_p5[0][0] \n__________________________________________________________________________________________________\nmrcnn_mask_bn2 (TimeDistributed (None, 200, 14, 14, 1024 mrcnn_mask_conv2[0][0] \n__________________________________________________________________________________________________\nmrcnn_class_conv1 (TimeDistribu (None, 200, 1, 1, 10 12846080 roi_align_classifier[0][0] \n__________________________________________________________________________________________________\nactivation_72 (Activation) (None, 200, 14, 14, 0 mrcnn_mask_bn2[0][0] \n__________________________________________________________________________________________________\nmrcnn_class_bn1 (TimeDistribute (None, 200, 1, 1, 10 4096 mrcnn_class_conv1[0][0] \n__________________________________________________________________________________________________\nmrcnn_mask_conv3 (TimeDistribut (None, 200, 14, 14, 590080 activation_72[0][0] \n__________________________________________________________________________________________________\nactivation_68 (Activation) (None, 200, 1, 1, 10 0 mrcnn_class_bn1[0][0] \n__________________________________________________________________________________________________\nmrcnn_mask_bn3 (TimeDistributed (None, 200, 14, 14, 1024 mrcnn_mask_conv3[0][0] \n__________________________________________________________________________________________________\nmrcnn_class_conv2 (TimeDistribu (None, 200, 1, 1, 10 1049600 activation_68[0][0] \n__________________________________________________________________________________________________\nactivation_73 (Activation) (None, 200, 14, 14, 0 mrcnn_mask_bn3[0][0] \n__________________________________________________________________________________________________\nmrcnn_class_bn2 (TimeDistribute (None, 200, 1, 1, 10 4096 mrcnn_class_conv2[0][0] \n__________________________________________________________________________________________________\nmrcnn_mask_conv4 (TimeDistribut (None, 200, 14, 14, 590080 activation_73[0][0] \n__________________________________________________________________________________________________\nactivation_69 (Activation) (None, 200, 1, 1, 10 0 mrcnn_class_bn2[0][0] \n__________________________________________________________________________________________________\nmrcnn_mask_bn4 (TimeDistributed (None, 200, 14, 14, 1024 mrcnn_mask_conv4[0][0] \n__________________________________________________________________________________________________\npool_squeeze (Lambda) (None, 200, 1024) 0 activation_69[0][0] \n__________________________________________________________________________________________________\nactivation_74 (Activation) (None, 200, 14, 14, 0 mrcnn_mask_bn4[0][0] \n__________________________________________________________________________________________________\nmrcnn_bbox_fc (TimeDistributed) (None, 200, 8) 8200 pool_squeeze[0][0] \n__________________________________________________________________________________________________\nmrcnn_mask_deconv (TimeDistribu (None, 200, 28, 28, 262400 activation_74[0][0] \n__________________________________________________________________________________________________\nrpn_class_logits (Concatenate) (None, None, 2) 0 rpn_model[1][0] \n rpn_model[2][0] \n rpn_model[3][0] \n rpn_model[4][0] \n rpn_model[5][0] \n__________________________________________________________________________________________________\nmrcnn_class_logits (TimeDistrib (None, 200, 2) 2050 pool_squeeze[0][0] \n__________________________________________________________________________________________________\nmrcnn_bbox (Reshape) (None, 200, 2, 4) 0 mrcnn_bbox_fc[0][0] \n__________________________________________________________________________________________________\nmrcnn_mask (TimeDistributed) (None, 200, 28, 28, 514 mrcnn_mask_deconv[0][0] \n__________________________________________________________________________________________________\ninput_rpn_match (InputLayer) (None, None, 1) 0 \n__________________________________________________________________________________________________\ninput_rpn_bbox (InputLayer) (None, None, 4) 0 \n__________________________________________________________________________________________________\nlambda_4 (Lambda) (None, 2) 0 input_image_meta[0][0] \n__________________________________________________________________________________________________\nmrcnn_class (TimeDistributed) (None, 200, 2) 0 mrcnn_class_logits[0][0] \n__________________________________________________________________________________________________\noutput_rois (Lambda) (None, 200, 4) 0 proposal_targets[0][0] \n__________________________________________________________________________________________________\nrpn_class_loss (Lambda) () 0 input_rpn_match[0][0] \n rpn_class_logits[0][0] \n__________________________________________________________________________________________________\nrpn_bbox_loss (Lambda) () 0 input_rpn_bbox[0][0] \n input_rpn_match[0][0] \n rpn_bbox[0][0] \n__________________________________________________________________________________________________\nmrcnn_class_loss (Lambda) () 0 proposal_targets[0][1] \n mrcnn_class_logits[0][0] \n lambda_4[0][0] \n__________________________________________________________________________________________________\nmrcnn_bbox_loss (Lambda) () 0 proposal_targets[0][2] \n proposal_targets[0][1] \n mrcnn_bbox[0][0] \n__________________________________________________________________________________________________\nmrcnn_mask_loss (Lambda) () 0 proposal_targets[0][3] \n proposal_targets[0][1] \n mrcnn_mask[0][0] \n==================================================================================================\nTotal params: 63,733,406\nTrainable params: 63,621,918\nNon-trainable params: 111,488\n__________________________________________________________________________________________________\n" } ], "source": [ "model.keras_model.summary()" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [], "source": [ "class PPDataset(Dataset):\n", " # load the dataset definitions\n", " def load_dataset(self, dataset_dir, is_train=True):\n", " \n", " # Add classes. We have only one class to add.\n", " self.add_class(\"dataset\", 1, \"pp\")\n", "\n", " # define data locations for images and annotations\n", " images_dir = dataset_dir/'images'\n", " annotations_dir = dataset_dir/'annotations'\n", " \n", " # Iterate through all files in the folder to \n", " #add class, images and annotaions\n", " for i, image_path in enumerate(images_dir.iterdir()):\n", " \n", " # extract image id\n", " image_id = image_path.stem\n", " \n", " # skip all images after 150 if we are building the train set\n", " if is_train and i >= 200:\n", " continue\n", " # skip all images before 150 if we are building the test/val set\n", " if not is_train and i < 200:\n", " continue\n", " \n", " # setting annotations file\n", " ann_path = annotations_dir/(str(image_id) + '.xml')\n", " \n", " # adding images and annotations to dataset\n", " self.add_image('dataset', image_id=image_id, path=image_path, annotation=ann_path)\n", "\n", " # extract bounding boxes from an annotation file\n", " def extract_boxes(self, filename):\n", " \n", " # load and parse the file\n", " tree = ElementTree.parse(filename)\n", " # get the root of the document\n", " root = tree.getroot()\n", " # extract each bounding box\n", " boxes = list()\n", " for box in root.findall('.//bndbox'):\n", " xmin = int(box.find('xmin').text)\n", " ymin = int(box.find('ymin').text)\n", " xmax = int(box.find('xmax').text)\n", " ymax = int(box.find('ymax').text)\n", " coors = [xmin, ymin, xmax, ymax]\n", " boxes.append(coors)\n", " \n", " # extract image dimensions\n", " width = int(root.find('.//size/width').text)\n", " height = int(root.find('.//size/height').text)\n", " return boxes, width, height\n", "\n", " # load the masks for an image\n", " \"\"\"Generate instance masks for an image.\n", " Returns:\n", " masks: A bool array of shape [height, width, instance count] with\n", " one mask per instance.\n", " class_ids: a 1D array of class IDs of the instance masks.\n", " \"\"\"\n", " def load_mask(self, image_id):\n", " # get details of image\n", " info = self.image_info[image_id]\n", " \n", " # define anntation file location\n", " path = info['annotation']\n", " \n", " # load XML\n", " boxes, w, h = self.extract_boxes(path)\n", " \n", " # create one array for all masks, each on a different channel\n", " masks = zeros([h, w, len(boxes)], dtype='uint8')\n", " \n", " # create masks\n", " class_ids = list()\n", " for i in range(len(boxes)):\n", " box = boxes[i]\n", " row_s, row_e = box[1], box[3]\n", " col_s, col_e = box[0], box[2]\n", " masks[row_s:row_e, col_s:col_e, i] = 1\n", " class_ids.append(self.class_names.index('pp'))\n", " return masks, asarray(class_ids, dtype='int32')\n", "\n", " # load an image reference\n", " #Return the path of the image.\"\"\"\n", " def image_reference(self, image_id):\n", " info = self.image_info[image_id]\n", " print(info)\n", " return info['path']" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [], "source": [ "data_folder = Path('labeled_images')\n", "\n", "if not data_folder.exists():\n", " if not (data_folder/'.tar.gz').exists():\n", " download_file_from_google_drive('1bFiLPB2z4SF6ebJ_gurwyQKYAlmtpeqL', f'{data_folder}.tar.gz')\n", "\n", " tar = tarfile.open(f'{data_folder}.tar.gz', \"r:gz\")\n", " tar.extractall()\n", " tar.close()" ] }, { "cell_type": "code", "execution_count": 26, "metadata": { "tags": [] }, "outputs": [ { "output_type": "stream", "name": "stdout", "text": "Train: 200\nTest: 110\n" } ], "source": [ "# prepare train set\n", "train_set = PPDataset()\n", "train_set.load_dataset(data_folder, is_train=True)\n", "train_set.prepare()\n", "print('Train: %d' % len(train_set.image_ids))\n", "# prepare test/val set\n", "test_set = PPDataset()\n", "test_set.load_dataset(data_folder, is_train=False)\n", "test_set.prepare()\n", "print('Test: %d' % len(test_set.image_ids))" ] }, { "cell_type": "code", "execution_count": 27, "metadata": { "tags": [] }, "outputs": [ { "output_type": "stream", "name": "stdout", "text": "\nStarting at epoch 0. LR=0.006\n\nCheckpoint Path: ./maskrcnn_config20200730T1557\\mask_rcnn_maskrcnn_config_{epoch:04d}.h5\nSelecting layers to train\nfpn_c5p5 (Conv2D)\nfpn_c4p4 (Conv2D)\nfpn_c3p3 (Conv2D)\nfpn_c2p2 (Conv2D)\nfpn_p5 (Conv2D)\nfpn_p2 (Conv2D)\nfpn_p3 (Conv2D)\nfpn_p4 (Conv2D)\nIn model: rpn_model\n rpn_conv_shared (Conv2D)\n rpn_class_raw (Conv2D)\n rpn_bbox_pred (Conv2D)\nmrcnn_mask_conv1 (TimeDistributed)\nmrcnn_mask_bn1 (TimeDistributed)\nmrcnn_mask_conv2 (TimeDistributed)\nmrcnn_mask_bn2 (TimeDistributed)\nmrcnn_class_conv1 (TimeDistributed)\nmrcnn_class_bn1 (TimeDistributed)\nmrcnn_mask_conv3 (TimeDistributed)\nmrcnn_mask_bn3 (TimeDistributed)\nmrcnn_class_conv2 (TimeDistributed)\nmrcnn_class_bn2 (TimeDistributed)\nmrcnn_mask_conv4 (TimeDistributed)\nmrcnn_mask_bn4 (TimeDistributed)\nmrcnn_bbox_fc (TimeDistributed)\nmrcnn_mask_deconv (TimeDistributed)\nmrcnn_class_logits (TimeDistributed)\nmrcnn_mask (TimeDistributed)\nEpoch 1/1\n 6/131 [>.............................] - ETA: 44:14 - loss: 3.7280 - rpn_class_loss: 0.0043 - rpn_bbox_loss: 0.2835 - mrcnn_class_loss: 0.5508 - mrcnn_bbox_loss: 1.4554 - mrcnn_mask_loss: 1.4340" }, { "output_type": "error", "ename": "KeyboardInterrupt", "evalue": "", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)", "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[0;32m 2\u001b[0m \u001b[1;31m## train heads with higher lr to speedup the learning\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 3\u001b[0m \u001b[0mepochs\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;36m1\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 4\u001b[1;33m \u001b[0mmodel\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mtrain\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mtrain_set\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mtest_set\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mlearning_rate\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mconfig\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mLEARNING_RATE\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mepochs\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mepochs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mlayers\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;34m'heads'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 5\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 6\u001b[0m \u001b[0mhistory\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mmodel\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mkeras_model\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mhistory\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mhistory\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", "\u001b[1;32md:\\Vue\\TDPDNE\\git_repo\\Dataset Creator\\Mask_RCNN\\mrcnn\\model.py\u001b[0m in \u001b[0;36mtrain\u001b[1;34m(self, train_dataset, val_dataset, learning_rate, epochs, layers, augmentation, custom_callbacks, no_augmentation_sources)\u001b[0m\n\u001b[0;32m 2372\u001b[0m \u001b[0mmax_queue_size\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;36m100\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 2373\u001b[0m \u001b[0mworkers\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mworkers\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m-> 2374\u001b[1;33m \u001b[0muse_multiprocessing\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mTrue\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 2375\u001b[0m )\n\u001b[0;32m 2376\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mepoch\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mmax\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mepoch\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mepochs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", "\u001b[1;32m~\\AppData\\Local\\Programs\\Python\\Python37\\lib\\site-packages\\keras\\legacy\\interfaces.py\u001b[0m in \u001b[0;36mwrapper\u001b[1;34m(*args, **kwargs)\u001b[0m\n\u001b[0;32m 89\u001b[0m warnings.warn('Update your `' + object_name + '` call to the ' +\n\u001b[0;32m 90\u001b[0m 'Keras 2 API: ' + signature, stacklevel=2)\n\u001b[1;32m---> 91\u001b[1;33m \u001b[1;32mreturn\u001b[0m \u001b[0mfunc\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m*\u001b[0m\u001b[0margs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 92\u001b[0m \u001b[0mwrapper\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_original_function\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mfunc\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 93\u001b[0m \u001b[1;32mreturn\u001b[0m \u001b[0mwrapper\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", "\u001b[1;32m~\\AppData\\Local\\Programs\\Python\\Python37\\lib\\site-packages\\keras\\engine\\training.py\u001b[0m in \u001b[0;36mfit_generator\u001b[1;34m(self, generator, steps_per_epoch, epochs, verbose, callbacks, validation_data, validation_steps, validation_freq, class_weight, max_queue_size, workers, use_multiprocessing, shuffle, initial_epoch)\u001b[0m\n\u001b[0;32m 1656\u001b[0m \u001b[0muse_multiprocessing\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0muse_multiprocessing\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 1657\u001b[0m \u001b[0mshuffle\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mshuffle\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m-> 1658\u001b[1;33m initial_epoch=initial_epoch)\n\u001b[0m\u001b[0;32m 1659\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 1660\u001b[0m \u001b[1;33m@\u001b[0m\u001b[0minterfaces\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mlegacy_generator_methods_support\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", "\u001b[1;32m~\\AppData\\Local\\Programs\\Python\\Python37\\lib\\site-packages\\keras\\engine\\training_generator.py\u001b[0m in \u001b[0;36mfit_generator\u001b[1;34m(model, generator, steps_per_epoch, epochs, verbose, callbacks, validation_data, validation_steps, validation_freq, class_weight, max_queue_size, workers, use_multiprocessing, shuffle, initial_epoch)\u001b[0m\n\u001b[0;32m 179\u001b[0m \u001b[0mbatch_index\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;36m0\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 180\u001b[0m \u001b[1;32mwhile\u001b[0m \u001b[0msteps_done\u001b[0m \u001b[1;33m<\u001b[0m \u001b[0msteps_per_epoch\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 181\u001b[1;33m \u001b[0mgenerator_output\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mnext\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0moutput_generator\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 182\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 183\u001b[0m \u001b[1;32mif\u001b[0m \u001b[1;32mnot\u001b[0m \u001b[0mhasattr\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mgenerator_output\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m'__len__'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", "\u001b[1;32md:\\Vue\\TDPDNE\\git_repo\\Dataset Creator\\Mask_RCNN\\mrcnn\\model.py\u001b[0m in \u001b[0;36mdata_generator\u001b[1;34m(dataset, config, shuffle, augment, augmentation, random_rois, batch_size, detection_targets, no_augmentation_sources)\u001b[0m\n\u001b[0;32m 1707\u001b[0m load_image_gt(dataset, config, image_id, augment=augment,\n\u001b[0;32m 1708\u001b[0m \u001b[0maugmentation\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0maugmentation\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m-> 1709\u001b[1;33m use_mini_mask=config.USE_MINI_MASK)\n\u001b[0m\u001b[0;32m 1710\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 1711\u001b[0m \u001b[1;31m# Skip images that have no instances. This can happen in cases\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", "\u001b[1;32md:\\Vue\\TDPDNE\\git_repo\\Dataset Creator\\Mask_RCNN\\mrcnn\\model.py\u001b[0m in \u001b[0;36mload_image_gt\u001b[1;34m(dataset, config, image_id, augment, augmentation, use_mini_mask)\u001b[0m\n\u001b[0;32m 1217\u001b[0m \u001b[0mmin_scale\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mconfig\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mIMAGE_MIN_SCALE\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 1218\u001b[0m \u001b[0mmax_dim\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mconfig\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mIMAGE_MAX_DIM\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m-> 1219\u001b[1;33m mode=config.IMAGE_RESIZE_MODE)\n\u001b[0m\u001b[0;32m 1220\u001b[0m \u001b[0mmask\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mutils\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mresize_mask\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mmask\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mscale\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mpadding\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mcrop\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 1221\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n", "\u001b[1;32md:\\Vue\\TDPDNE\\git_repo\\Dataset Creator\\Mask_RCNN\\mrcnn\\utils.py\u001b[0m in \u001b[0;36mresize_image\u001b[1;34m(image, min_dim, max_dim, min_scale, mode)\u001b[0m\n\u001b[0;32m 446\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0mscale\u001b[0m \u001b[1;33m!=\u001b[0m \u001b[1;36m1\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 447\u001b[0m image = resize(image, (round(h * scale), round(w * scale)),\n\u001b[1;32m--> 448\u001b[1;33m preserve_range=True)\n\u001b[0m\u001b[0;32m 449\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 450\u001b[0m \u001b[1;31m# Need padding or cropping?\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", "\u001b[1;32md:\\Vue\\TDPDNE\\git_repo\\Dataset Creator\\Mask_RCNN\\mrcnn\\utils.py\u001b[0m in \u001b[0;36mresize\u001b[1;34m(image, output_shape, order, mode, cval, clip, preserve_range, anti_aliasing, anti_aliasing_sigma)\u001b[0m\n\u001b[0;32m 901\u001b[0m \u001b[0morder\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0morder\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mmode\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mcval\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mcval\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mclip\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mclip\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 902\u001b[0m \u001b[0mpreserve_range\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mpreserve_range\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0manti_aliasing\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0manti_aliasing\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 903\u001b[1;33m anti_aliasing_sigma=anti_aliasing_sigma)\n\u001b[0m\u001b[0;32m 904\u001b[0m \u001b[1;32melse\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 905\u001b[0m return skimage.transform.resize(\n", "\u001b[1;32m~\\AppData\\Local\\Programs\\Python\\Python37\\lib\\site-packages\\skimage\\transform\\_warps.py\u001b[0m in \u001b[0;36mresize\u001b[1;34m(image, output_shape, order, mode, cval, clip, preserve_range, anti_aliasing, anti_aliasing_sigma)\u001b[0m\n\u001b[0;32m 164\u001b[0m out = warp(image, tform, output_shape=output_shape, order=order,\n\u001b[0;32m 165\u001b[0m \u001b[0mmode\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mmode\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mcval\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mcval\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mclip\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mclip\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 166\u001b[1;33m preserve_range=preserve_range)\n\u001b[0m\u001b[0;32m 167\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 168\u001b[0m \u001b[1;32melse\u001b[0m\u001b[1;33m:\u001b[0m \u001b[1;31m# n-dimensional interpolation\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", "\u001b[1;32m~\\AppData\\Local\\Programs\\Python\\Python37\\lib\\site-packages\\skimage\\transform\\_warps.py\u001b[0m in \u001b[0;36mwarp\u001b[1;34m(image, inverse_map, map_args, output_shape, order, mode, cval, clip, preserve_range)\u001b[0m\n\u001b[0;32m 807\u001b[0m \u001b[1;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"Cannot warp empty image with dimensions\"\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mimage\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mshape\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 808\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 809\u001b[1;33m \u001b[0mimage\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mconvert_to_float\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mimage\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mpreserve_range\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 810\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 811\u001b[0m \u001b[0minput_shape\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0marray\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mimage\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mshape\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", "\u001b[1;32m~\\AppData\\Local\\Programs\\Python\\Python37\\lib\\site-packages\\skimage\\_shared\\utils.py\u001b[0m in \u001b[0;36mconvert_to_float\u001b[1;34m(image, preserve_range)\u001b[0m\n\u001b[0;32m 252\u001b[0m \u001b[1;31m# precision float\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 253\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0mimage\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mdtype\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mchar\u001b[0m \u001b[1;32mnot\u001b[0m \u001b[1;32min\u001b[0m \u001b[1;34m'df'\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 254\u001b[1;33m \u001b[0mimage\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mimage\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mastype\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mfloat\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 255\u001b[0m \u001b[1;32melse\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 256\u001b[0m \u001b[0mimage\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mimg_as_float\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mimage\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", "\u001b[1;31mKeyboardInterrupt\u001b[0m: " ] } ], "source": [ "# train weights (output layers or 'heads')\n", "## train heads with higher lr to speedup the learning\n", "epochs = 1\n", "model.train(train_set, test_set, learning_rate=config.LEARNING_RATE, epochs=epochs, layers='heads')\n", "\n", "history = model.keras_model.history.history" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "output_type": "execute_result", "data": { "text/plain": "[,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ,\n ]" }, "metadata": {}, "execution_count": 20 } ], "source": [ "model.get_trainable_layers()" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [], "source": [ "model_path = f'mask_rcnn_model.h5'\n", "model.keras_model.save_weights(model_path)" ] }, { "cell_type": "code", "execution_count": 28, "metadata": { "tags": [] }, "outputs": [ { "output_type": "stream", "name": "stdout", "text": "\nConfigurations:\nBACKBONE resnet101\nBACKBONE_STRIDES [4, 8, 16, 32, 64]\nBATCH_SIZE 1\nBBOX_STD_DEV [0.1 0.1 0.2 0.2]\nCOMPUTE_BACKBONE_SHAPE None\nDETECTION_MAX_INSTANCES 100\nDETECTION_MIN_CONFIDENCE 0.9\nDETECTION_NMS_THRESHOLD 0.3\nFPN_CLASSIF_FC_LAYERS_SIZE 1024\nGPU_COUNT 1\nGRADIENT_CLIP_NORM 5.0\nIMAGES_PER_GPU 1\nIMAGE_CHANNEL_COUNT 3\nIMAGE_MAX_DIM 1024\nIMAGE_META_SIZE 14\nIMAGE_MIN_DIM 800\nIMAGE_MIN_SCALE 0\nIMAGE_RESIZE_MODE square\nIMAGE_SHAPE [1024 1024 3]\nLEARNING_MOMENTUM 0.9\nLEARNING_RATE 0.006\nLOSS_WEIGHTS {'rpn_class_loss': 1.0, 'rpn_bbox_loss': 1.0, 'mrcnn_class_loss': 1.0, 'mrcnn_bbox_loss': 1.0, 'mrcnn_mask_loss': 1.0}\nMASK_POOL_SIZE 14\nMASK_SHAPE [28, 28]\nMAX_GT_INSTANCES 10\nMEAN_PIXEL [123.7 116.8 103.9]\nMINI_MASK_SHAPE (56, 56)\nNAME MaskRCNN_config\nNUM_CLASSES 2\nPOOL_SIZE 7\nPOST_NMS_ROIS_INFERENCE 1000\nPOST_NMS_ROIS_TRAINING 2000\nPRE_NMS_LIMIT 6000\nROI_POSITIVE_RATIO 0.33\nRPN_ANCHOR_RATIOS [0.5, 1, 2]\nRPN_ANCHOR_SCALES (32, 64, 128, 256, 512)\nRPN_ANCHOR_STRIDE 1\nRPN_BBOX_STD_DEV [0.1 0.1 0.2 0.2]\nRPN_NMS_THRESHOLD 0.7\nRPN_TRAIN_ANCHORS_PER_IMAGE 256\nSTEPS_PER_EPOCH 131\nTOP_DOWN_PYRAMID_SIZE 256\nTRAIN_BN False\nTRAIN_ROIS_PER_IMAGE 200\nUSE_MINI_MASK True\nUSE_RPN_ROIS True\nVALIDATION_STEPS 50\nWEIGHT_DECAY 0.0001\n\n\n" } ], "source": [ "# class that defines and loads the kangaroo dataset\n", "\n", "# prepare config\n", "config = myMaskRCNNConfig()\n", "config.display()\n", "# define the model\n", "model = MaskRCNN(mode='training', model_dir='./', config=config)\n", "\n", "# load weights (mscoco) and exclude the output layers\n", "\n", "model.load_weights(model_path, by_name=True)" ] }, { "cell_type": "code", "execution_count": 29, "metadata": { "tags": [] }, "outputs": [ { "output_type": "stream", "name": "stdout", "text": "(800, 600, 3)\n[0 1]\n(800, 600, 1)\n[1]\n" }, { "output_type": "display_data", "data": { "text/plain": "
", "image/svg+xml": "\r\n\r\n\r\n\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n\r\n", "image/png": "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\n" }, "metadata": { "needs_background": "light" } } ], "source": [ "# load an image\n", "image_id = 20\n", "image = test_set.load_image(image_id)\n", "print(image.shape)\n", "print(test_set.class_ids)\n", "# load image mask\n", "mask, class_ids = test_set.load_mask(image_id)\n", "\n", "print(mask.shape)\n", "print(class_ids)\n", "# plot image\n", "pyplot.imshow(image)\n", "# plot mask\n", "pyplot.imshow(mask[:, :, 0], cmap='gray', alpha=0.4)\n", "\n", "pyplot.show()" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [], "source": [ "def get_ax(rows=1, cols=1, size=16):\n", " \"\"\"Return a Matplotlib Axes array to be used in\n", " all visualizations in the notebook. Provide a\n", " central point to control graph sizes.\n", " \n", " Adjust the size attribute to control how big to render images\n", " \"\"\"\n", " _, ax = pyplot.subplots(rows, cols, figsize=(size*cols, size*rows))\n", " return ax" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [], "source": [ "from keras.preprocessing.image import load_img\n", "from keras.preprocessing.image import img_to_array\n", "\n", "#Loading the model in the inference mode\n", "model = modellib.MaskRCNN(mode=\"inference\", config=config, model_dir='./')\n", "\n", "# loading the trained weights o the custom dataset\n", "model.load_weights(model_path, by_name=True)\n", "img = load_img(r\"D:\\Datasets\\reddit submissions\\dk\\images\\qjeeer3lgdm01.jpg\")\n", "img = img_to_array(img)\n", "\n", "# detecting objects in the image\n", "result= model.detect([img])" ] }, { "cell_type": "code", "execution_count": 51, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['BG', 'pp']" ] }, "execution_count": 51, "metadata": {}, "output_type": "execute_result" } ], "source": [ "test_set.class_names" ] }, { "cell_type": "code", "execution_count": 57, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{'id': '0h4sb9p716m11', 'source': 'dataset', 'path': WindowsPath('D:/Datasets/reddit submissions/dk/labeled_images/images/0h4sb9p716m11.jpg'), 'annotation': WindowsPath('D:/Datasets/reddit submissions/dk/labeled_images/annotations/0h4sb9p716m11.xml')}\n", "image ID: dataset.0h4sb9p716m11 (8) D:\\Datasets\\reddit submissions\\dk\\labeled_images\\images\\0h4sb9p716m11.jpg\n", "Processing 1 images\n", "image shape: (1024, 1024, 3) min: 0.00000 max: 255.00000 uint8\n", "molded_images shape: (1, 1024, 1024, 3) min: -123.70000 max: 151.10000 float64\n", "image_metas shape: (1, 14) min: 0.00000 max: 1024.00000 int32\n", "anchors shape: (1, 261888, 4) min: -0.35390 max: 1.29134 float32\n" ] }, { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAA3QAAAOECAYAAADpAnOiAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjIsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy8li6FKAAAgAElEQVR4nOy9Sax0W5bf9Vu7OedExL1f916+qkqqXKbKloVNI4w9QZaQAIFMYzEABAObATYjhCxkYYQs4QG2wQLBgBmmMRYGGWQsI2EZGIAwTJBopCojcLotp7P93tfcGxHnnN0xWHufOPd7L7OKdFXZL9/+pyK/d++NOHGa3az/Wv+1lpRS6Ojo6Ojo6Ojo6Ojo6PjiwfyNPoGOjo6Ojo6Ojo6Ojo6OHwyd0HV0dHR0dHR0dHR0dHxB0QldR0dHR0dHR0dHR0fHFxSd0HV0dHR0dHR0dHR0dHxB0QldR0dHR0dHR0dHR0fHFxSd0HV0dHR0dHR0dHR0dHxB0QldR0dHR8cXEiLyK0WkiIirP/8pEfnnfoDj/AoReRQR+4t/lh0dHR0dHb+06ISuo6Ojo+OXFCLyl0TkWknTt0TkPxaRu1/s7yml/OZSyh/+BZ7PP7j73F8ppdyVUtIv9jl1dHR0dHT8UqMTuo6Ojo6OXw7846WUO+DXA78R+D37P4qi70kdHR0dHR3/P9E3z46Ojo6OXzaUUr4O/CngbxeR/1FEfp+I/C/ABfgpEXkuIv+hiHxDRL4uIv9Gk0KKiBWRf1tEvisifwH4R/fHrsf77buff4eI/N8i8iAif1ZEfr2I/BHgVwD/TY0Y/iufI938qoj8SRH5VES+JiK/Y3fM3ysif0xE/tN63J8Vkd+w+/vvruf9ICL/j4j8A7+Et7Ojo6Ojo6MTuo6Ojo6OXz6IyE8A/wjwf9Rf/VbgXwDugb8M/GEgAr8K+LuBfwhoJO13AP9Y/f1vAP7J7/M9/xTwe4HfBjwDfgvwupTyW4G/Qo0YllL+4Od8/D8H/irw1fodv/8DYvZbgP8CeAH8SeDfr9/5a4B/EfiNpZR74B8G/tLPf1c6Ojo6Ojp+cHRC19HR0dHxy4E/ISJvgT8D/E/A76+//09KKT9bSonAK+A3A7+zlHIupXwb+HeBf6a+958G/r1Sys+VUj4F/sD3+b7fDvzBUsr/VhRfK6X85Z/vJCvh/E3A7y6lzKWU/xP4QyjxbPgzpZT/tubc/RHg76q/T8AI/FoR8aWUv1RK+fM/33d2dHR0dHT89cD9jT6Bjo6Ojo4vBf6JUsr/sP+FiAD83O5XPwl44Bv1b6COx/aer37w/u9H0H4C+EHI1FeBT0spDx98z2/Y/fzN3X9fgElEXCnlayLyO9HI4K8TkT8N/MullL/2A5xHR0dHR0fHLwg9QtfR0dHR8TcSZfffPwcswMellBf19ayU8uvq37+BErWGX/F9jvtzwE//Ar7zQ/w14JWI3H/wPV//Pp+5HbiUP1pK+U0oOS3Av/UL+VxHR0dHR8cPik7oOjo6Ojr+pkAp5RvAfwf8OyLyTESMiPy0iPx99S1/DPiXROTHReQl8K9+n8P9IeB3icjfUyto/ioR+cn6t28BP/U9zuHngP8V+AMiMonI3wn888B/9vOdv4j8GhH5+0VkBGbgisowOzo6Ojo6fsnQCV1HR0dHx99M+G3AAPxZ4A3wXwE/Vv/2HwB/Gvi/gP8d+OPf6yCllP8S+H3AHwUegD+B5uiB5t79HhF5KyK/63M+/s8CvxKN1v3XwL9eSvnvfwHnPgL/JvBdVJb5CfCv/QI+19HR0dHR8QNDSvl+ypOOjo6Ojo6Ojo6Ojo6Ov1nRI3QdHR0dHR0dHR0dHR1fUHRC19HR0dHR0dHR0dHR8QVFJ3QdHR0dHR0dHR0dHR1fUHRC19HR0dHR0dHR0dHR8QVFJ3QdHR0dHR0dHR0dHR1fUHRC19HR0dHR0dHR0dHR8QVFJ3QdHR0dHR0dHR0dHR1fUHRC19HR0dHR0dHR0dHR8QVFJ3QdHR0dHR0dHR0dHR1fUHRC19HR0dHR0dHR0dHR8QVFJ3QdHR0dHR0dHR0dHR1fUHRC19HR0dHR0dHR0dHR8QWF++v5sIiUX6wT6filxU//HX8v/nAPpYAIIoIR4dVHH/PJJ5/wYz/6o3g/YJ3lZ37mZ3h4eORyPlNyIZdCznocEQCp/+rhSsmUkhEKSAZuw8IYg/ceY26+g5ILMSWgYIyhlEKMkZwL1hiss4AABalfJCLknMk5Y7CUUurfDWIE53Qo51xIKZFyIqdUjwO5FD2teu1i6r9IvYZCzomUMilljqc7punAOE4Mw4DzjnVdma9XrpczyzKzLCuQsdZindHjl4Kx5XZsMpRCzpFSir4AKQUpkZIDQsYYCGvg4eE96xpwzm7XpPe54P1Qf1e235Vyey4igrG2XlOhlEzKmVLAGEfKmZQSpRSkoPdgu0NgjT4vawyIUHIihKB/E8EYgzGGlANG9L8H7/HeM0wjfpgQMbx5+5bHhwdiTPjBY+qzK0XvhTV6r3Ipep3eknNG0DFZSiGlSM6pjjUdb2GNUMBbhzUOEcN4uAPjyAgxQ0iZw/OPmI53TIc7MkICjB8p9TtzKqScCeu6nZPUG6ErWkGKQaq/K5dMzolSEjknjBHG0eGcY/AW7xzWCINzTOPI8+fPmKYRgPfv35NiglzvtQgpZr3pRjDeYq3l/eXhNj7qWLXOczgcGMcR5wZySjw+nilFEDEYI1CEmBIpJXIq5KwDwlqLMRYxBiisawCj99taR86JZb5CiVgrGGvIKRFj5JNPPsZah7GW8+XK5XLlcp1BDMa4Og49IUEMCUQYhgExmVwWnLeQMykkUkwIgreDjlEEcsE7X19Ox1SKpBQp6Dqy/a8kxOi4dtbgvPCrfuonGEfP6B1iHcboS4xBjCG351zAOocY2a0NkbQu+sxp411wti5muZBL1vlmzLbWCaZOsm321f8XSptBdU0tQKkDqs0ZROo6mghrIIRAiIEQEkYMzjudR35gGMd67HwbD+08RMj194A+95KxxmKsocA2tud55v2797x784YX988oObMuKyVnxnFimqbtnt3d3TEOIymlbcynlIghcp2vvHn7llLg7v6en/zJn8CIIYRIqWu0sZ6ShZxhDZF5WfnZn/lZzuczl8uFNUbWdeV8vmCN2869lMIaI/M86xqBjm1d7wvO6Txz3tfxDuMw4qwjxoizHus81jtAiKkg1mKdwzmv1xATOQWsNThrmMaBYfCs10cu50eu1zPkpOvdcmW5PBDmMzlcicuF68MbSs5YEZwzWGsYvcVbg7WCNYZSEt4I1hrqFokI2/OXun6KCNbZbU3T/SHrcU2d0zqYcPWz+jl0fwXqN1Cy7oFG6veKwYjUsalj0Ro9P7f7Wy6QdeciGUfGkDCsMTOvkTfnmZAKKUERQzEWMR4xVu+ttVhj6z03bVNH0JeRuO0pOocL67LW8X57rcuqx7KWmCIpJax1DIOuDVKfd4hB9wZncX7AGEvJQkw3o8Q6j/cHxFhyhlT3vGE4Yp2nYHT9so67Z88Zx4lxGkEMKSU+ffuWGOs5OMfgPWIgpqi2SUqUnJmmEWv0CaxrIKWIs47j8cAwTnjvWZaVN2/f6bis66g1jjVGrvOsvzeeEFdO93dMhwMxrHpPwsqy6PrU9vXt+RrBiKl2SiQEHdO6fqq9Y53h/PjIsq547xmHkfX8hv/5j/9HdHwxUEqRn/9dn4+/LkLX8cXB4f4Fx2cfA9TNRF/PP/oKrz75Mb7y1R9nGAa893z9W2+w4wN+Om+koZEeuP17gy7aRgoieTNE2ne5arS172wEDtTwBJ78bK2tBEsJXNsM28/k23hvG55zrvKpUsmDGgPWWmJMzPNSjZ96Xh8QOqjGUc7kXJQQTMdqUE8MgxK66/WMf3jker3gl7l+TyWhpVBywdh827BLATIlp51xhm7iknCmYKVgDMzzlSLCPM9Ya/Heb9eZUtqez3bX98er97rdj/a3XJ+fiKsmsm4Q3vlKnjKlEb0UNyNE6t9iCAhK6PT4QsoRI4JUQjd4zzBNSuiMJaaMGEuKEWttvQ96T6ZRjbGUIuuyYqwaSCmlSi7V6AgxkFM15ut3pZAhF5xxGLEYsYynZ2AdqRhChpAKdy9/hOP9c473LyhiKcYQsWrI5Nt4jjFSUiKXtDkkrOimaa3H24GUEtfrhRADoE4I7yynu4lx8AzO4p3FGGGwhmkaefH8OdM0YUR4/viopGfn58ipYJzFOosbHXZwvH776TZuy/bMrI6/YcT5gZwyDw/nSuZsdXYIKab6WaHtBdscN2rkL8uCHxzDODB4T4yRh4d3xPWCMWBdNRRC5Md/4qtqNCFcrlfOl5nLZQZjEOPwbsQ6T0xmM6qc9zr35YpzBnIhBTUypAjOeL3+StwP44FpHBmHEe+sjoewbMS5UI87WPzg8MPIOFiGwfKrf/pv4TAOjOOAsQ4xFutu/51KIWUlt2ZH6NRRkEjLUg1QsALGCNbUQVEdD4WCfyJgud3PyszrysdGIGW/Dukio4TR2ko09fvXdWVd1YCb54BUQjwMA+M4Mk1TJY7lyRxvzzSXTK73Rx1heVtji+jv1nXlcrnw+vVrvvvNb/PR8xeUlLleL1DgdDpxOBxQ/i+8ePGC4/Go87Cu0fM88/j4yLIsnK9XjLXc39/zUz/1t2KtVUJXz20YR1IUYoQQE/OyIsM979694+Hhgct15ny58J1vfwfrPMLNQXddFpZl0XMRJXSlztXtvkxqLAsw+hFrLOu64uyA8wPWezJCiKmOByWBMapTquQIRSfhODgG74jzI2Z8h5wfSGEhx4DYC6BODwkDwVmICyVlnBUGb3FWmAYldN6po6GUxOgM3lrU0QhimmPFPHlZ57a/K0lLeO82ctjgjb19vhJEiq7f1H0OCq6OMX2fPjsd27q2OmPwRv8tpVQyBwlHNAMZQ8CwxMx5DkzvL6yhEBJksWAs4iaMtRjrsM5hrcMOns3DkROUBERMWauT97aHz/NMjPEJoVuWZSPsMSpxstYyjqM+6zrHQgiVCOs6YIwjZx1nehMNfhiZpnuMccQMqRSMeIbxDjeMdX3wIIbj3TOmw4HpeKxkKDO+fs0agp6Dc/jB45ypDoFIipGcIuMw4JzFiBBCUAIohmmadIwOA8u8MNy/V/LpfHW2eJYQucwz3g04N7CGlecvn3M4HVmWK0udByGEjcSZOuep811tgUiK+t3GVGdnPXfnDOPjI+u6MgwD0zRxffNNOr4c6ITuS4IY1fO6J0ylFK7XC2/fvtVow6ARoMvlQliDbgzViFdj8bZA5xqya39XT5FgKqHLlSTknFnXVRdka9mTurZgN0Lmvd/eE2O8LW51w2rvXdewkZd2Hc3b2yJwwzDw8uVLDocDl8uV169fM88Ly7qQckZyM3xNJRFq8JnqJU0xKsGq0aIQPCnrhqSRoxuRamS3ZCVHuejf9fJqJHH3LFoExnnP/WlkcAaRjPd679u9afcC2Iz9RnDbPXwS1eFG6vakvX2n82rkHKaJu9OdbmYhsK4L8zxzfnxPrs9Moxd6DtTzbWQXIElGSmbJSvquy4p1M8ZaUs4Mw0C2tno9NQI5jiNf+cpXcN5zvV55/+4dOWVyShq1qp5lQCOlOWMwYAQnBj96SIWSlPBkYI2RklAvcxFSEWJM28t4vRfXy1XJHIIxGr0ahoGcohqhQaNvzmnE8TAdOR5Pel/OD6zLrAaXU6J9OhwZB69kqNpguaix/v7hgXmecVYjj41U56jXaozDGTUa/DjgRiXqbV41YzaEyPV61YitdeRcavR2qISvPdsaabIe5zyl6GfbnCh13hyOR44HjTiHsLKuM/PlPUjGZo3kUcfSsq6sa1ByLuCH6uXGUCg1kmNw1qpJmhKQMLY6a3KpkU+NIqaUSDGSQsSIZXCDGqemOXyElAI51/MmY6xGjk53R453Jw7ToMb4OOpYthqVw2h0whqDaeNVWlQ1U/YOIAQzeCTnNnEBjcpT6gs1tFN1wrQxv0VXnqxjalimnLHObutUi9/dIq63Oe2c2+Z4jJkWyWvPs2H/816pINWIbnP99qanzrb2fW2dVM9+UgOz/i6sgTVEjbDWNcV7X/cGXTcLcLrTSMIwDKSU9X7vHG+DE9YCMYJzhqMd+NEf/dHN0H3//mGLHkrWiKJzjlAJqfc1AmTsNv9zLtvnj4cDx+MRU9frksEahzFWCaK1pAIpq9sql0yMer0pJZw1XC9XLpezRpEomBI5n99zOT+wXC+EZSHHGeKMyQsedUios/LmLGv3SeerUDalw96ZUrafP0Tbp9r4N8bWCNvnvI+b+uK2n3wP1LneBmBB96RMIQu6h3/vDwM1GiQGYzKmrTFGoJHGFqGrUUZdX0qdZ4mSIzku5Bpxa1GvZVm2Z9H2sg+JbhvLOWdijE/2PhFBcibHRDGFmCDmBGIrwds5PUwVClHU+Zgdk/f4YSKkzLoum7PT1Pmac94ULLlkUo6M43CzM4yQkzrGcna4ugZYa0khcrlcmJcF6xypjjtMQgpESYhEQtI52GwjjZY2J0/Y7B1rdW+axmEj+PN82UivErpY55/uGaHu4zHqvG7zvtlSHV8OdEL3JYF6cz67cM7zzHe+8x3evXu3LQLqTdOFx1TZ0V7+1z57i2i1hRq8v218thr0zYu8J3GNEBpjNk/SV7/6VcZxxFqrBv/793zzm9/cFviGPaFJdSEu1XD+MCK434AbSYz1XtgqT0x1kW3v904jGHm5cp0vlQTXe1YJSMn1GE7JrLVmk5WktJPyVaWW926LqJRqOIZQWOZCcirObB66ZVm28/Peb2R7fx37RXtvDO6jPO1e5QwpRyXNzjONE4fDAYClZCTUjVkEsc0ohpISh8ME9TtjDMQQOB0Om4ERQmQNAYkZCQlp51RlT9RzNkbww4j1YzVqE36cCGsgqTYOX+Wbvhq8MUZiircNvehmjRPAYMQSi9kkRNSomoiSj5QL4zByON1zuDO8f3zkfL4o0TOFFy+eKyHJifl6YV1mUggYgWFwPLs74Qy8cRBNYZoGDocDz57d8+rVc6w15KQEP5dESWrCaTRPnSd39/dKzlaNmqyL3ueQEmmZiWRcTlyv1y1SbK37zLM2RsfCOE7EmDcnQoqJUlASepg4ne5IKfH+/SMp52o46ngYh4FjjczEsBJjYLk+kHNEjEaXM5mHhwfmeeFyrfIg55nnBbEeYx2gpPTZ82ccTidSyrx58ykpJcZxIuWA85bJjwzDiEFYrgvz5crMFWc9x+ORu9OJly9ecDodWdeFb317ZV51zkFmOkx8/PELXr16yYsXLxjHAeeEGM7klLhcLixrYAmBYTpyd3fP6XSHHxzjOLB6Nvt3c3yYAkW2aNxG6KISiJIaqc44bgSsSb4fHx5ZwqrOBqOe+Y8/+QqH00hKhWVRBwa5Gbpli5js1yTnXF07qQ6P25ocQsDYJtV8SuagKcebk0sQyZuss+Swravee6Ya8RNjCClxnWemqUrTCszLyvl83qIkTQkAKhd+fHxUQnU61WcwMs+zHnuaNlKXkhIGY8BalbT/6l/9Ezw8fMz794+8efuOb37zW/zVv/JzpJyJVU5Zikbh7u/vsU4jKNfrlTdv3tZom16XMZbBT1gr5BjJSeeAc4Oug85jUeknlbBKVXVohGUlxsjjwwMhLKSw8uw0EkNUCWOBnBPrsiA5YHIEAjkElZWaKjO0FiNQciKVjBXIRq9bTNtvAHlKAvdOtjog9Zkag/dOo9o7h8p+n2vyapEqsyw7BQy7Y7Ib61nJXcl6flLA+Lpv1k/uYRCsgDMW7weKyUjKFKW+FNMkpHruOSXSum4kLaVICivrfCGGszo3G+ktRSNcJet5NeJZHYUGPT9n1AEW10AkqHO2rqNiDDkm1rxincO4obqW2tzOlJIA3dObPDfnSM6RadK1b14D8xLUORtXbLGIWIwVXDGUcnN+NFevGNniYylnBhGV2dd98hzPrOu6rd3WqtMppVyvG4xY/HTgcDoSYyZFtVUuj49cHh+5zhfWdSHnzP39HWbwOHtLu1gW88Rxba3l2bNnzPOVeb6SUiKESM6G4/GkCpGqQnrcO306fqjRCd2XBG1yw41M6e/tZji2/IlGilDn1fZzezUvdJMOqXxogZoT18jPPnrWjrN/fRhdawSmEcFGzD4kKVbctim0jWOPZhS9f/+eeZ43eVO77makNfniuq5Poo+CUMRAKVvUIEbZPO1s3kDqPdHjpRhqVKCJrsoWdMq50FJO2wa05gA51DyHwrquT55N8wAOw/DEGz7P8yZD2RsJe2nqXrqnMrwqcUoqQVICUVjmK0u9RxrpaUaLUKzheDxSsp6bQI1iue07m7feWIfUPI5G4tiMjfb9het1rnKtQMqQETXAxOBq/tA4jkiVtKwhEEPUe5nBiMFbj7UewTLHTMqQMIgdsH7EWEdBlNDUiNw0jFzmeTPMU9JcJuOrgVSdAkqgMpfzIxZqPkPCe8vgPePoGbyr0WjlBog+Z5XImDpfLM5rBCFX469F0kQMMSfyvJKKEjqdA6CEP+p93MaAY/BDNaAdl8uyzZkkeYuq7iXRuV7PPpoUqkNDuOUoWmcxGcQUctLIbIuKH4/HGjUxXC4zzt6im96N3N3dc//8GSkl5vnK9Zo2D7LxBqlRGIsh2rg5IKw1lJIJMXC+nIkpEGt+jVCYxgE3OO6f3fHy5Qvu7+8YpxEjKjfSqHravNs6ls6b0TzmUSWg1mOdqZxWx19OakxpFK/lqBgEV6Waua5JeTOujdExLiL4YcA4W0mV4JzfJN2qYtgm72fW4A/nqa6/5jOOridrwG7dfiKxrsqInKWOlc++R4mj10jw4FmXpUaL29x8GslvUs0tjy5n7u/vGcaxzv2Mc5YQ1psiAnXWhJBq9FvlkiWpE2uaxo03L/PCdJi4Xpcqv1MSPY4jp9NJczupEQV5SlRyzoQUlQioNhNrDX5Qh0MjqFJyzZ8smJ0Tsck2D8cjdhGiEXUeWUP2Du8sYRy4WiHHKwRBtXu3bLAnqgw2PnJ7Vtt6V6Nzn7M+77GLpX5mnLTzvkXmbp/6UGr/eSh178mgToo6zrbvqzl5LQO0RRiNEZw1+rmiuWipFHKKuh/mTPNSxhAIVY7YZIBxvZJjdWjCkzWJsosg12vIKRE/R02yH8P7G5ZzwhaLc1YjsZktNzXGuOXK6f5NTSeILMuMWKvR9JSRYpEgpGwRDOu6EKrzucU5W/Sr2RMhhC1/DqhOhbLJlFukvdUAWCqZQwzGWcZhYDhMzNeVnFYouta2tAcjBjFssux9hL3ZZ+rcvDls1nXZ7pO+LOM4cTwet5v2oTO+44cX/Ul/SbD3+u9le+Oo3tjNCCy6wVpj0VyGUr2o6umdpulJFE2T3s+czypvcq1AyA4tQrdfoERkW7jaYvV5+SINe2mhqqrKJpPYyzfaNYYQePPmTf3s7f2mFg9o19I2zrZwN2PG7fI8UiVgTYrYNj5rDc5ZhsEzDJ5luarcUvZSGbZNPueyu45Miitr1oiQd7Ld/2bwNYK7P9fmEdWNoLAnqfv7tt84G7FqxL3lMzSPdKjPQEmKEjpnLQbh7u5eDbnrrJG6Khls19buuRsGLbAgskVLPzQ6Ykycz2eMsaRaGKcUwDjNX/MDw3hgPExKLENAlgVjVzUKq1f/brpj8CMiFntdCUlJHdZj/ESSViAha/SvRlqM3ArwpBi5Xs7kwSMU1mVhXVeWZdb8iGXm/P49LZo6eMs4OEbvlZBkzWLKm7dco2iujm/vB5z3ZCBW8phz1gioWNZl5TpfGXLC50bIQAldQfP1pI4BxziNHI9HrHVqPLfIz25Ot7GxyXJS0sIKldQtNXdsmS2lpC0SjGkFN9I2Xw/Hk0b7cibEzNu3j5g6Hr0fGIcDz58/48WrVxr5eHwkxoXz5Z1GrzGUsc6XNo930rGYAtdr5no9I+VWAMU6w93xjrv7E68+esHHX/lIc+WMIawL83zleHC39aHKDOdG1lNmXSc1au7vsF6wTolWShAR0qo5ckJBatEIIw5yJqd4czLtpF+mktPT8Ygb/CbVSilzvl55/xhqlPRYIwt7h8Zn0c6/OWD2a7BKTgtFCoabomIzjoV6bHXUlSqNexIRlFt0cRw0V3Fx87Ym7L+/OepKKZvzq/39o48+wjpHzJkQVqy9Gd0th8daw7KsOOdx3hAjpFT03luH1ngRlmXldDpq/tSqkmgRw7MXLzidThhriVEdVtYYir2lCOi91gI7Vgy2RqyHccQ6Ry5CSRlqEZQPCeHhOHF3OlFyYpkHwnpltBqVMmRyOpDCyqM3hMUTZiFeI2s0Nau3RavYDP7PPtT9s/2sA/N7ozT/wmfGx36c10e3Rbna+25H+Zwj51yJz1OFTPuE7F7GNIWK1bWtOkBKzsRcr19Mfbc6u0KMxJqGkJMW+SKHz1zL/r/3+0KLoO7TKvY2yn5vVwlpAdH0gYLKnUtU0hbWhZypKhE1bYskYgw8Pj6wrEFJv3UY68hFyWkBLpfLtn4qBxNyPm55f81OOR0OSixTfrLmNieeRlsdIWqkMaO5f8YYxnHkMB1IMetaDMTqBG4EDSk1b1tz6m7j/6aIaoVQmi0Ft7SVloN4OBwpRfcJ72559x0/3OiE7kuCPdn53M2gPDUG2oa4X3zb5tIWmf2Cso8IbcQlZ0KIKgVIuVbSy5p07D2mkkb1VEXev3vPPOsitiwL5/O5yghy3a1aYQK7VSNsBnAzhttrT37aOYtUr6x3HKYDx+Nh8xKmKm0rlbTp0VSORSVzujm2vVUQtJBEyXYz/EvJWjVQDHvn4i0/qh6n5hykNWCkUEpNpq8J/Wbzugst76tUz7PmeQ3ElOq9rpEoa7dKaSJGN6yi8kR2UYHmcdSI3U36qs9bi3YUIwzjqIUTkkpl1rAii0oZdYhU06ZuJuqE1bwE0whVq6pZH40aRc3yaXkjVRYollRz4UqRGr1zGKdGnIhh8APH0z2jnxAsyczYmAgpU4xDrCesiRwzlMA8r/hhZgmZsNYCL6HE3KkAACAASURBVDUnYpln4rpAreaZUqTkhFhDWCPXdcVZy/2zOw7TyDSNTKPHO4N31RguQi7mFtVAvcXEAIvBSGRdA/OyQAGphRRyDfQW0UIb01THYqvSmjSnsEWLYi0iYG0711Tn3Y0M7PNOW66njiuNisUQSKkZW21M6xjP5M3QB8M4aARuWVdYlicEwdaCLGkb0zcvfKzjylmV4rplVcnlsmyy6YJ6plNpVdoErRYrm4NkqsVboM6VokaW97plaQU3j/WeYZx4eDwD1O/RohxYg8jEICpXFgQjrbKuVho10ooXsRHOTTK+M6hb5FqLqpRboRU0qj0OtcpkqbI5XTBv62u9Px8a9hqttHX9qnShaIEbPicK06JrN1Kxi+BosLkeRteALR9nOhDWwGE6MPhhW78bmWuV8hra8z4ejzjnmJdFq9WmrBUA25zNmqNYa1PUe5mJUQsjtfk2DJ7j8cDd6Y7z5YJcr1r9VfKOxEKshrJKfYVpGhnHCWM1/9cai0WwcpOjI0bX0lqRMMV8q8ZYX+M43qLSBhYDXjLOgJVCjoZohDCOWInYEljTTA6+rou5Om9yW7qqs+Lp89Hxcov+7qNzT8nd02h6I4FGbrvL7b2yrQXbfPtgLN0kmLso2Afj5sn+zp5AFt3vq2TWWV3jo8lIKpScWJdIrmtyi07Oy7rJ4ktOgBaOaU69/XfubY6987U9+31Usr3v884/NTXDlh+rKR/kTMCSi2CKQ9XIhURBckbMrM49EZVr5kzKqRK6sjnAUouOZ2FeFlKN2sVadGStEbrY8qNzJoa4pW/odQjLqo5TMZYigku3fM64RQJ1bjiraSfW6R5/Pj/q+l2r1w6DqpZauge1gNeyLKxrqDZSrfi9s9tyzSP8/s6Ejh8mdEL3JUFbRPdynr0h9nThrQtCIzK7CNe+8uTeQ9WqFOZ8e1+qJbqXWSU6mmvm8Bmc1Y3SGrfJ316/foNzSvJCDCzzzDKvn8lBUHKjgTApt41TX2bbMEvRhU4NRo2qaR7SyPFw4HQ8kUveyojnlNXLa3bp7HXzVOMqVxVlWyxFq01ZISWhFUvRSM2taEApzbuW6uZTjeiciCnW6qCtsIXb7DhN7q8FArbTqCWah0y8XusG1KxRg3O1aEApyLaJ1pLWH5D6UnOsNOJ2K8MYY8JZLU8/TQc1lFLELR4RQ0xpI2ipSkrUK5kouWxGVMqaq9CefauQJmIo0oizbJHQjCEUkFQwJWmBAzGIU+nY4NW4O52eMfoJMAQZkDVAlXwVY0nzVfMiY8ZerohxZDR3joImtFO2nLmUtCw1ghY6QfPg5usj0zRymF5yf3fE+0Hla755Yu0mHQphZY1xS6wPIRJikzBGzc0Rg3EOYwYySuRaruHkp81brYn3q+ZgJPUwa5XWjIhlnpc6rg2tGMCHhE49v1qgx2Aw1rCsC3EJKp8CbWEg+p5cK5dao8VV9D5rtGmfc2qtVo1Uue7CMi/bNSvxVEMrBq1iKkWQUpiv8yZVbhH0khLHw1SLvAjOiUpbB1eLLugzErJWMrTC4CdiWPCD5zCOHKskDBHmeWGeV67zDCJY72qxCZVoNQeJ5ojKFqUr3HJP21pprcVxixA1CeyyLKwxaHEPUcnlsxcvGQ/TpjjI9XyaEb6tI3zW2FaiyLbOPlmPd//9NBJzcyvt0Rw+lNvMMmLxfmSaDsQQOZ3ucPYmn98TOvX+P63KOI7jllMnIsQ1qloANJc4ZbLcimIhreVBxCajVX9F59w4DtzdnXjzblCHU9Y526SerUJuTFmjfbVtx+FwUNmasTXfqmDlFpFIWXNJmyMjZnAimJqT264h19YEFC3oZErEWzBSyEaj4s5ZDAOSB4gDafUgUqNildBV50BzRrUA2pPftScgn33Vm7mND53XteWFqXvZlo9XP1MaoUvbPNpLFBsyt3PZx+zaeGqQ6ijchwaVUCqhi6nsqmkm1nlW6WW5VXWdl0BrEUQpGCsMTp9tc/bs1Td7dU5LeWiOnu+lzHkiuy21gFZqudUthz+iBV9WUhFcI8tSCxuJ2VrbiIgWe8kJk+xG6G7zvzqHS2G+Xm+2TAyq6qhj21m32UTkQnG3n8UmliWo2sN6qCkkIayYxW5RcNPyJ73jcDgwDNpm43q5kGIixpVktMKpNaoKiSEiRqWn8zxvpG57qju7bEu9+Jy1ouOHE53QfWlwk+Hsq1yez+cdUdJNfFlmjfzkJs3R0r7X6/UJIWiRgtYXRb2LuUbCtJDH3emOly9fbsZmq3b1+Pj4JGduXVfevXu3ncdem76X3QB88skn20LbcvjevXu3tSZo17N5cLn1PNqjHeNyubAut7wQyQWx1QWba/U+2XnlC6ScWEPk3bu15tDZWkk047xW/7OmVaFSOVkjdEKtF1i9sillclo22YSIbGWIY7zJL9oCvY82NqlG61fmvd8My2bcN+N/f93btVL7FVlfjZGb7Ovh4WH73LquNU+oUIz2zRoGzzgMjMPIq48/4tNP3/D+/QMpF0IqFAzH452SsaHmxcVIygXnR073IwUtEJKrNMT5YeslBhnjalsK70AsoRge5shlXZTchEzIQiyGWEvlh3IzYK7XmZgyRSxDzZVxxpGt4f3lUXvR5aR5jGKQnAhLYBo9H7/8Knd3Rz569RLvfc2xCOSYkOLq89XnF8JKK1O/LEs1AIWvfPKJ5gblwjxr1PnxetFclWFQw2ieORxebM6WJkFqlta6Bq5XPabmIxVa6wKV1E1bhKXlRrZxX8otJ04MeG+xo2ccB053R9Z54fz4yMPDO0RgqMV73rx5w8PjI2uINe8kVWNiIUWVsr55/8DrN9+teX0Xcko8e/Zsy/NItXBJCkqYvbV463AiiDNkUwhhoZTIixfP+Nt+7a/h449f8fzFM8bRkUvi9evvcL48aKSwqGlyPEzEaaSkhLEO4xyvXr4kZy1asASt0LmugTefvuU8nDlME+Mw4L3jeBxqNKvUQjUzl8tFe0NSNiJjBVJM1WDSe348nXgxDpvkMoTI6zdvuXzzivda7MUYo7mLxm5rjgHMBxEIjRzJEyfYRuA+KKbxZCXfjHs20q/zumwRd3VgadjMOsswDrywL5iGcTOg2zm0MSsiTNPE6XTCOcfj4yOffvopz57d8cknrwB4/fodH398pBThfFYFxjzPvProOeuamecIWfPntJ6J7h0prJQU+fjjj3h4fGBdFy1wktEenzEiksmlkuRnSujc4HHe6zyLGiVz1qpjxKu0bVlXHi9aDTblwjBNDKNKlE+nE3d3d3zzG1/XfOFlpmQt/PIjH32MdxYpmXdvX/P+bSSGFSeFwVnwjugMLZrd5l7ZiFrLTaeSWSV9YuTWFueDiFRTv1DX2tuxpfaM/CyZaU7BXOWkUveOG+nX95h6bFOLeEmBVrlV2vovomV5xbAVByJjqLlx1jBWGWIuGe3WElmuD8RUiKnUDiy6lrexJiJIFtYq697nn+3HbSN5zQHVJJV7tP2/3YMtXzhn7VdXCmIfq+O19k1F+9SZmgZhrUbr1pQwBu5PB053zwgpc11WJYcF7R/qB55NE7loGsAablGvu7sTh8NRqyGHwHe/+92tt+ZUW2nkmLZrSVn7FU7jgHPPa06fo+TM69efgtT5XmAYPAXZ7KcQ2CJ4wNbG5P7+HmOMVtKcZ8ISqhPuRpj3DoN5nrffqaMm0fHlQCd0XxLsJQ17L5hU6UorvGGM4Xy+aKNde9uQRG4k8FbdslWGbJ43rXBmjDBO6hU+HCaVB9Y8m/NZm3JrboqpMiUwrXFmTextG6Nq5nnirTbW0kJExtqbdLNuaI223WRp6nnT/84bsQpBi6HM80wMWpBEquE2jgNihbCyLbTbvUT3wkwr6JLIucmtIKeonnKjHX/acU3V6CiJAmO1F5x6/8J2L28ym33OoVZBa7I8vdQa8fQDwzDW3EYHBIxJ2zHaWe/J8s14rPln7Hsm6bNeQ9ykbLp56KYvpvUj8tr/53DADyN+GHF+IYdISRHnPMfTkWk6MI26Yb59955UEmIdftQom6leYlfL7iOiBVNy0VLwrRl2yuRUWEKq0lglcTGXzdgISb3+1CasBSVIYorWN2jGRkzEoGSuycI0/03lQoN3nE4Th2mAkohBmzUvtZmr82bLWVICvdSCLNVhYtAWB8OA9wNNk7bGwPkyq9SSmxPgep1pFWNbfqSzfntWqY5fjTjJZsSVeu/aXGlkrlVFnVetvJqz5naaKrPT/l6jthHYejK2UvoaHQ0hVa+8lrI39bu16hxgajXUopUKkzWkuADalL5Vn2VHZHJOJIr28/Iea5REHo8j46C9uCiJnIVcIt5bREaGQYmmNYYYtJLkdVkQ0Wp4Q73PwzgwjJ4QIo+Pl9p3ssqqU8JavU+3GMptbWySaJNzjZZoYSQt8lS930kLoLRppb3SvBqTT/J42UVVcjXk8lPDnhY9v/3+w1ynm5RuN5c3lUCtZrhVNGzS87bWVSM6aQl/g+DHkVQ0Z9RZCzVKnEuBGqFr3++cu0WbQ97WoRhu35dzIsXAfF1Y1sSyanNoU5vX51yIMdWiE4HTSXt7TtNEShrJbPlzYhwibruvpekWaxS/2f2DVyfSOI7aSDzu1Bs1x6/lCre1S9d4LUDRHAPSIovotW6l+Lk5vfaOwEbilJSVbf7fInFth2gR1LZOP33pl+u41EqYwr5oWXvue6niVh2ySayp+e2Nk0FdUxTG6HWpdHenONkihLtTbfujqEPDiqnFYiyrtzhn1KFJa+1RP1Yli9t1laI9N0vevmbb82Rf3ESrysZ91A6Vdm5xxDYHStnOUZuWo+8tGSttr6xEeHcfW5VL/acQYy3rn/MtdzvXKL0xuKwELm3S3cDgBrxzjIMnRe0Jp5Jzlc17X/sZilBQ+brU6P4wjkxidV+KmoOoy4DgB003MVbXE5VR6joTk86npvRpBcraI2t96WRnG7R5qhF2zR8vhW0vf3LvO36o0QndlwStwAnc8qVAZVfH46lWGdMFZJ7nmgPWKuSZGom4EblmeLSqdU1uYwyV0E2c7k48e/aM0+lEjFEXMmswZ7Nttk3q0wo3NLlTM4JSSpWklSpBVKJnqESwVuFrHu1cNzx259sMHI0aQIxCCOu2Ydzex7YZjNOwyb4KuTafruIFQWUboB7DDDEpKbDGqvFYSu1/VTfh1ri6RvmMEbx1jF57gi1z9bKam8TraRU6g8hNEtKMQ2vdllPn/VgjNXn7PNxyDG/R2UZqa/Qw3wqrNGlmSok1LIR43p0DTwidsbXh87QndAMhqnzJ+4Hj6Y77u3umw4EYEu/PV0oqiHW42ojcgm6q1mGtp1D7SRVwfqjVIg1hCayLRgrjGuuDcOSiBelCTOrpr/2pTB1HWjEVYizkbLRHUgwqgaE+t+rZFVEPtPeW0/HAODpK1n5sy7KwrGuNLGuiukZrNVI8uWEzhHVuad7PMI1Y65UYLTOpZCimOgT0XK47eU8bi4N3dZ6JGlO7qGwrjLM3GotAyVqJ8HQ6KkEomRA1+txyLL1z+NqweZ2v2zhpTgKNmrERYzGa42FqYRmsRjMxt+Ik2tPPMNey+ak5AHLamuRSx20smXGwjN7hvdWS4scD3qvhmFJAQiKTqzRLjZ+W8/X6O58SU6o5pLoO3d/fM04T0zRuxKj1d7pFOCIpag+zZlDTDHRURqYREI2gF2dx5paHpVLwSFgWlZmh6890PHHwt1Ybe5nlLZp2i6TdSF2N7DTjvNwKNO21BJtcrv2yHT43iXvZzr8FRHRpK5TcIsiRwXv8MDDXYhZbSwDnNglsI7dt/KYaFVrXhHPqcAqhrUO59nEMXC4za4isQVtXDHVdT7lJgWdCWDneHTkcD0zToSoHHHenO20EbV1dw1RGucZIDLXICboGGtFKo604F2vAmKDrnTFYbsWftKm4KkPmeUYbX1ennXoiMBisKTiruUwiQG7PS4sLtXX/ltdWZa8lA7fI10abCuxJ+YfEbs/NZdfDtVVBfvLcG6ErZVuvDVBM/Vu55VOqc6fuL/Ve0XyZm2Ogjff6Ko18anVnMQUrgrcGcCzO4a2p9yzrPdw5k+q31X9Vei7lVrjjw2Jle4dwSgkZBpwdbkRxLyet97C0CFPZ3UfKNn+kOu4a/zd1TjcJbJPEy3zVhurp1obAoMqbGO0WoYtRJeuHYcJZi3duU9N477Gm5vp6V9sRoQ5dKZv9Mo0TfhhZQ+RyVSenlFvF1WEYyTlxvZ41tzkGkBahq71362s/Jzen7E4eLSK7Hnat+N3N4dsJ3ZcHndB9SWA/yJ9rxtHpdM+LFy949erVtjh8+umntYpTM0i0x9w+z+RptKcaFYISoJK3zazJA7W0+bwtPHDL62vH2+fp7Utot3NtntB3b99t35s2z7vF+cMTz/Z8uW7l+Ft1tr13fE9w9y9rDXenE85XQleaJCJAlShKjUbmcjt/dVJmNG85bbKYFln7MJfCOou3WgxlXeadl+1WsbJhf2/aQt6KmzSslWw0ueat96Aao5pPMlRCoNcTlvUzFTPbv1pIID05FyXFmXVVKafmvxXWmHh8PLOuAescR6+EYfCjRvL8iPPCi5evuF6XakzW0va2EQNDKVL7VNXKXcPI4Xhg8CMlZ67nmZTfkrJKEE3NORTUu5uS5oyJUSLUyuEfj0dsbTVgnVU5nfdQshZtcJZpHLi/v8M54TA6plEjSFQv91A3b+dcLdagxiciHA/a4yisYbOfYlr47uvXmsMzTnq/Y9xIkhLjmxG/L3ayLzbUIh0iwljbOoQQVCYoN+dMM9q895xOJ8QYlhCYa2nrTNECBnOunujA+f0Dl8uZEAKDd9UAqM4O0abdzcOuOXlBpXDGYEdfo0At/6tUb3v1eFgtTjEO2lsw1z6GQmEcB46nA6fjgdNx4nR3RATtEZYDrZfZOKkk27Q+kDntSnLzpJz3siybkVlQOdU0DbpulLrGZG0srBVddc62iOU8a5Q0hUAMK0aEwTkGr5LhJuE21mzVdXNR2SYxbOvU5pDYzVsBLc6wm9OtxP/3RGFzUAk3o0wJ3j7v+cnj372PakBro3lTnTxhK7Cj64jml+VN1tpku4fDYWsy/vbtW4ZBn9n5crkZ2/XfTz99DZUKt4jTujZpXSKEhZzjJn0dBse6OnIpXOcrMWX8oJVrh0EbxpcciSkTYqzyYrud/7nuOTEXLdLUGtTXHF11KCTWGIi1B6cRizEQlpmwLnzr29/iOA54Z1iXq87dUjaS2uZr2ZQbO2doacV6djmO8lki93TtlO19G/EyphbBKrdIWXvGHxC6dsyy+/lJPmUl/iI1B6+up5RapESEUsmcNLIn9TzlFqEzKCET4xi9ZXAGb4QsqtakVdnMiSK1UmSN1LVG2O2c90qehr0Mte1jbQ3cR7D3903vlWwOx1aRc4uWpkIqAUn1olRCAOgcul4vrCFinMcPh03SLqJ5nm0PVFWB5gGv68LlYp5Ea1MMiLVkYZev3PrsghG1m+KoCpXmeMs5M/gBP4wcTyem6cD1eiWsM1IrGeUaPW6tb5pjos3HzW4SAaPFjvb5r02q3+5vy1P8ULLd8cOLTui+JGjk60MSc6oNYz/++ONt4g/DUHPK4rYgp/ThxnLDbdGGQqpeTTby0Rbr6/XKPC+3nB5pC7SeT6zyg2bctny7VlLbWo28vHv3vnqsb+fiaz6X865WhEqk0EhYyzl6SpDqf+yIXPPGC4dpxHlHCAvrWqV4NSEezBYltMU+OZZGv6Cg7Q4a9ptU25C80zL4Jactx+FD0rw/370cyxizbSRts9kv7vvn3orIaAsETb4uObOsC1dzBWRXRKPUiIpuGMu6qkEjtYiHaM+pEG5ypJgy87KyLIGUMofDwDBONXI3YJ3XBsDO8+KlMIyzPmtaUQj/pNezyijBimCcZ5iOnA7H2tj3zPmysCyZRFbZXy4UyRrxyhlj0WdeI2DrujBNIxSrx7QGsYa0enKK2Pospmnko1cvORwGjCRKXqEkclJe472tkTzHNKi8T69L+96t33nNElbEuhrtiSyfflqrhR7V0K9RENr9xEHNc2ibf4uM355tlQIat/XsamW0n7TCqM+8VfXTZ+hvUdmUtXhEUmNlXRcuj4+EdSHGgHf26by0biN1giWkSCZhjcN4w1DzCltgQEzLZ1HpEUbv1/FwYBw86zKz1MjGMHpOpwMvnt9rn7nRY2wdh0GL7lhnmQ7aS65F7VPKG6ETka0QRgiBsK6kXQ8zZ1XyKqiMtEkqw3ojM23ee+83oy4ELciUU2L0njgM9RrVu26NFkxp0at5DaSStxxWIyrBSrsiMC1at1cCNLneh3O9RScyZbfe5u29TWZbakRuK4zTtHDcZOdtTVnWoL0ena0Rs7UWRPG1n9X6xGgUEe7u7pimicvlwtu3bxnHkecv7nl49x5KwVcimHPm7ZtPsTVX1jqDsdqmoJRbjmkucDictGLsODKvmuuoOT/qgHFuxA0FxGwOuxAj3gvGqjMqrpEUtchQxmzVC51XCbgxhmVda86rGufPT0e8M1grpKBz5+2773AYPKNXQlVigKxOj63ASmj5hjxpHF6q16Zsz+x2v3cU68nvdw+YRtxaJMYYbtWPdyRu7xDcR2o3uec+Qred2AeOSwytepieW+s+18529yraL9WaWp3UWwZncbXwVxQoUshkpCRKEYpojrJKolESCU/G+/6cPozctTHaPvN5jl4RJaiypWboz3pNSoZSzIioykWVO1V+mDPX+QqyMk1HxulU12w9171j9HbOZUvJaFH+FrU1AjkJS1JH2ZM+u1hyJYiDH0lRG5iDMDnHYRo5HY8cjkeN0F0sUnSfakXeNPeVWiU8bDl1+/3fVgdtq0HQcmDbPVXnkn/SM7bjhx+d0H2J0CQ0zRDPOfPu3Tsulwtf//rXAbZNfVlX1mXdpEaN3MFtYd7LLsdxQIwwrwvrsrLGK4+XK+8fL1j77SdERY9pKWK1ApUY9ejXHjLWgnEDblBjohTNm7IZrFVjv12DGlEORBinA8/u77m/vyflxPly4TJfyalgauSsGfrqwdIqhS2fas259qYR3j+8BdMkVEpoBu+2e6Q5HQ5K62GmZb2NCOPxoNInKVslthYJy6I5I+M0cjpODM0Iso7r9apFJDIY4xi83e5bygXrBmz9/pTBVomf5n1o3hkiGHvzypUq03HW4Z1n9AODH2qRC+0DVarHz/ubx2+Tyex6EWp/Osfx1FoopGoYW4bxyDDeNlhrLae7Z4g1ZIR3jxfGceSrP/6TnO7uiClzvlz59M1bvvHNbxFzUnJnHCkLl3kmpguXdeXdwyN3xzu8n9QADJp/sawrD+dzHYPCOB746KOP+JEf+ZGtqtjr15+yzlce371lePWSw3TA1+d+ea+EzVnP3Wnk/v6AkcT58T1WMt5BSloFUz3pGuEspXC5XrgucyWrvjbR9kyjcFkWYqqRVmNJqXC+1B5gIpV0ahRWS2KvvLh/xv3d8y0KFGPka1/7WpXnDFuEqBXAcVUmd73OXK9X4OakefP2U86XR5BahKaSSDV6IjFohTiZYXQeM45Yq46At2/f8ezZsxoVsxxOJw7HI+fzzOP5kWttQh9jAmu5v3/G8xrhzynx5//c/8vlfK5yO5XFrquQ04pQGEbLNB549fI5d3dHnr94xvNnd0yDx3tDKok1rIS4EsLCX/v6X1XCNQ5bgYvT6aAVNaNeV4sitdzYVtbcisWKjg3Nt3HaIzMXQoysYamEWJ1Yd3d3HI9HJbjruhHEvCvotIZ1kwE3p8fhdIKdDDZVx4gYu5E8MaZGRZvzS+WGe9yk1aKf3xnym6aszf9UGAZVPizLrW8cdb4asQzeY43j4d0jr1+/ZhpHXrx4wd39cx7PV/7c1/4Cx4NWM727u9t6Cp7PZ949at/Br/7Yj/Hs2T3joEWTSsq8fP6CNWhPwO985zt84xvf0Py3Gnm+n59xd7onpsT1OhNS5HC84+7uGS9efoR3npevPuJrf/Ev8u1vf5ecV+6fPUfEElPizZs3pF0lZM3v9nz06ivc393r85gX3rx9w+P5EarzQQuh6Bh5PJ9Jbz4lzzMh1Gb01ZE2TSPWZJbzG5Vjnh9xFoRMjCvL9crl8ZHH9+9J65Vh1HVXnWgBZy3HacDbCWcFZ5WgxaiyOu3Dqo40fXC3BtSg4sZGoFRybbm/P1WnXlWdtNL22/NXh+ng/SZwzFmLhLjqlDByU82ENZB25EmjgFQHXKREqcVNagS+ZI10odLPktXh5iXz7DTxyVdecr7MnM9X5mVlXlbEC6nUfMcUidxI54fRtW3f3EUm92vWzXF867HZyIgqIcwmEc6ohHgNqaoctGptI9vOaZsM6wZMBAkJX8A4z/39C168fEURURsnrKwhItIcpeq81aqStzy1cRzwzvLd734XCnV/WSg5cxgPqhIoKlnNpfDw/j0P7x+2xuxiLNbOIBBi5OHxcZOil1QQJ1ijRVAA5mXh4f17llnJ5PF4xDYyXSXBj+/PVWZ9I37DmLc0l3aPQ+hFUb4s6ITuS4Lr9cpwanlXN++0Rs3m7X3NMEjxVlCklFuOWQvlG2N20j59abESthyiRgqalGzvodsv+N577u/vGYaBENRje71euV6v27HaueSccc5UmdWtEmZOicvlDDUy0io9qtfQsiVLy9NchZKfFnlR73eVkFYjcZ/bAk+jaC16tW2ocstPaHKo9m/rLXa9qpERlqXmSaVNXtruTZNLfLjh7SN1eylL82TuS0Q75xCnpFPQMuMt6tnuT9jkIv8fe2+25UaSZAle3WwB4BuDkT2TtfT79P9/S8/bnDqnOrsrI0hfsNii2zxcETWDR+QPJGmZfshwwuGAwUxVRO7GDVQpfTSZCJinmU1BkhBh73E8G4lu5gAAIABJREFUHPl7WX/IUNig7wcE3yEpBc/YhuSlVLDGjLf3D6TCCXxMFKc7H2DqRqk1EBMOHyQU1WJeVrx9XMQqf+XkvFR451o20Sy01cM4cIJdSJ8yIEIw3S5wtpJaaA2CmK0MPTPmOgkNN1IyGVOkId9oRC1LzViYApSi8QRs+FQUD9EvVBGWWnE9NMZgmiZxV1zarFwdEmlfTeTjy5cvct1DJsUr3t7e2mc4TRNiJAqxvy8VcQIERZIhTcxJGvwCKxS1cRyFXuSZtRQjlnnBeDiwifSBOk3Hhj8VZhuqJneNK263G0LwIvBPsJZFFaoDasE83UhBtqRBBveAw6HH0+MJp8OIoWOg7jRPqDXDWIOh6xBOR1RsupZ1XfH6+oZlWuBcuBs+KNXSGcZ6WGtI5bUbVZjoXG50waFTsxoxgtGGLAt9ytKtsuz0hcMwMHpDiqVcMtYpoQDtvPtaaUYjgcQAELoOD49HDENoawPRo72L5Q7Rl//a6OEbq4A6RmCe10ZT21+fROxSo2AN44GmICni27dvOJ1OGMcRv/76q3zeK6y9YRgG5k4WGgDpWuK9B/oe6lx4nj6kweU6nXPGIO60RpgMMdKMJ+cIlB3a01mEzjdGxTgOMIbrToWBzVwblliEukp2SMor3j4+sK6RCFPOKJUIfxVzLYCOru/v78zMBKQpIFW3ZKBaK3E8suauC2qOqN7CGeYo6oBO136I1vIOe/szqqzqu8wemdvjdWjX4v57+/0Eu6YI+89/99/N0Mfs6JPbE9+heXta7vYb9i+53n1PWkWhI1sUC3gLdN4hBYfUB6gmvCy07DdWkhSq4sh3J2D3vv/4PXV11H/br2H7e7sU0hFhDEplVIKxrln6GxnYaISOc64hn85WsMH2MKBzbTVoQ2oDIDgP6+lMXSqjJN7fzhxWdo73xkCqO01daIam+yJgJc5Bs193Z7tW1AxxQuawRvdo6tdZozCDU4aqzpGeboyYuKi5UZJRwFbP7JvjYRjalzKb+mH4w3n/efxzHj8buh/kWNZVmqF7XvW6xlbga8MVJDh2b6Sywfi+0bnmeRZEj5M1Wytc2ALHtcnYGjrbXPqArUDx3uPx8RGPj4+Y5xlvb2+kMs1zo2yyMWTjuDf7YFNH+t00zTKxpsW/NnRW3At1IkZHrSKTdDUI2WsWKtMKzLbZUohcm05LH2tRhT4ZZIFVo5d9M7dt6mpQkFLGusyiy9q0Buokp58TEZuAUnaBpHWzf95rDvieIxjS7NrGiLK5/CnvX/n5Jd8jp4oAqemAd6Hl5vAa8DidTtz8nEPJ3GiWFDEMB3TdwCKs1PZ5rVGc8nLB+8cZqVQ4z8I2Jl4X3hpm7UkBZK2XzcrL9Rvx8fGBZV4Q17TLu7NAgVh6s0k+n3uGX1uDFBc6LqYV63zDZApKL+5lfUDXBYxDj74P4uamgwjVenAAkLNcL4RBUY1M3rNOtS16S4dO6upAtBFidOMDnGdjdLlceE4luDx4DXlmZtYwDDKVPYrWMck1k1ochX7+apqy0ZR2Jil1MyGg0D/JvUx0KASP8XAQgf2KxTA4OsaELpfdfboNc9RFDZDrbVlhcAU/hCJOgnwNzlmUJMV9XBE8q0NrgHEccDoeMAwdvHcoNaEFPzsD5zpShoLDKiG7MdJAJq1ZLL0HyQP0m84JphV01m4sAlRp8MtmAOSdl3gBi1KWbU2SAYXSv8VFBcqUq0K3A4hOaOyG3m96P2mxmoVe/ICxnb/NzGTTot0V/kaocdJ87o0vjLNwxkqMzH3RqwhgKaSKBdH/df2A87Lgcv4AALx8+YIvX77g/e0N7/MMM9MIp+/7tg5VQZQ4rNrez/l8xrLM7VqsOxMMwkBEujQKxhjX1t7gGWnT92zmOFBYYL1FrXSOdcXA5q1w1eHM7cYBhkQ485xZSyqp0PFrZRRPrpqxaVAKi2KlA1a5j9e4osQVtURY49tgMMYVKUUx41A6IrY/m2Rt95lJlujeOOVucLhDpz43NnsphDZ0+0N+qq1Jqn8z0nQ1Ov/n59w9d5Vma/96tz/3P7uddVigFNIoO++Qg+dQUhq6Ja6yxzHLb3sG87mH/fRe7s2CKM3QGBaHzTXbSDMuaxGnbMwYrYUUTOjAlmwIRUabc6+RAYgRg5EKou7gQEX3P9L5vYR7kwmknxkNUMI28EgREStW5z7lrhbEpC6fRKu102WebAKiMmf4c8xE3McHcQ8updA5+JOm2lnb9Ln7a0nP18bo6GQtutc1/jz+uY+fDd0PcjS720+bif2Tm51IkZNmhRt117HAH8fxLqfofD63fBRdZnRBVt2Lc4LEOCcZMf6u2GRhYxq9s1a0glWGcnevvVEC7RZVgMpNuyzUi1RxcdQJLWptdsNARYoJKLk1On+YkKpk5W4vrw3t4mMK36uzsMG2TdUYg2LqNq2rRjYr2hWzqANyJuXj/rO5N06xlvbIKRlB+LQoYHGtSJr3DjkXXC6XVpCp8LvU3FBIOmGpa59sIDVwClgqSq6t6SzNcMDBB26oVpA1Z0jv4nMEBGOpzbqxyGSRChZcPiBY0mKu1wnLEsUl02GaZ0zzyvBiI15qWa3eLUXuldrELgRpTgtSTcgloWTIQCKKQ1rFPF1bJtM8XbEuE4CMWiJKdjCgc+LTwwlBnMq85k2JRoJGGWwYFbmpMUmDZpEri3K1Vg+BWi1t5LcxOAcKminUDwPmZSEyvrte1pUmJ9Saski+3SZsOYabxfdeJ6n3j6IQKTGHKIpF+xojohYFYgxkZWDQdXSXRIVovzi0WBZqm97fz+jmBV3fUzeZE6mxRs0pVqwpYllnTDNz3Nb5BrWG1xPRdQFd59B3NJp5fDxhGDq4YJFLQkwVw9DD+xOWZcblcsHH+Yz8+2+kOnUd+q6jFq8fcL3cUCswzTOWhUVb13XMudOw95KxJoYOE2CRe8l7FvlVNDKRtGLvSdlzPiBFNtvffvuvhlqqTm08HCQaQVDsrsNhPMKJy+Wm6Ut0uxsGdB0pueuaMc8XKEuB68F+/a2y3m0FepU1rzSafIV3/CxjzHQAlZBuXhJ8nxp/kXPB0Ic2xJvXFdOy4sUYjMcD5mVBJ/miezMkay3m203WGqVyRqwrqberBEKnGEX3w8gAUokLco5Ng2SdQa1ENCqobRzHAc/PTzKouSKKhq5WQ+qavO8uBKBTx186pc7zgpwSuq4jqucNun6gE6t1WNYIZF57MSZM0w2noUeygMtG4k8Yil5L5euX5s850bTth47SSBhpVAxqa4S2u1ybh/u1XJ/jTiMJeT6dEGgT94/6ILM5Nm60XL1kPpm1yO8rIGtga5xA9FQGPgL/tgZr/7v5mAprgSKoeucsSvBySzOOxN2AAtKLtS3ke5NzswOe6061x4N7IzWDWVD/KoNXBfiqbLn5Hvqs6jq6qwsM3WtLLTApw9jMgVLWobQMQXPGsi4oFW0QowMWk/m+tdE8nU7oux5BWC5xpbY2iytlzTQ+2yjwCR/nMwcjXcf8RMOsxZQL1sR7mAPSBGOA4CycNci5ohTquUtJWFc6bQKAFwaTDn5u04zL7dqGVRX7iCbq0JWSzrio659dVT+Pf8LjZ0P3gxxKSdlT9T5TID9PzWC2CZAiN8fjEQ8PD43SpRPonDO5+fijm6PSwRThc861BoP6vCzow2ZwwOfdzIXZwIj7o91iCu41ZIUh0tpsSWFuAKGCWeHbc5qvGTCliqhZfluVaT6MIkYAZEosf+VGo+5qzjftk3OOxgzy7zpF1OZMCy42lVWMPYy8t70DpzJMdAO/p1fqlyI6+0DxDbnTYtG0JkA/Y309zjrAt+2Rm16USAAT4T3t6p33QtupEtRdAFPgrKflt3eYJjao3rFxLVWzdxgMXguwLNR9WevgQsCyrsilNFRY37uBFnC7Ka4U5Mk7lEIaaBIXus1QoGCZrm2iu64zcl7Rdx7eGwRvMHQBx7HH09ODIMaKxHJia5xD3U2+a9UA5yLXpMR4SCPlncc4HqG29q6KBkqLD8MpcggSxN73omWTJrTWZiCRUob3S9v49dgj5HqNbo2dGgpojl1BSkZLRagZkBZe98/p24AihQjNMVxX6miXdUVY1oaUwBqiWkYCcUvGWivmeeIVVJNM8Fl0WRh0gQjK8TDgdByEetjBe0ZIxJjQ914m0zRESTHiNjPw+3A4AKcT+n7AIM3lKo6iRVC9nBNq18FUUsKsMUT8MlEWaxyCB1zwcN6LYQZD7ksF/OkE79jY7x1GkzTzdHWl42I/9BgEHTXGwp342VJXE4UiVQQF5WS/ALhJ+LV+lk40Yo2+rUMjLY0pemqfF4s11Sh9QhNl0KGI3VbUpYY6W1ljkhSyXeC1OB4OXMNFw6RrWY4RFXr/5UaHn6epsS5KyXC7cG3nrFyHCUVQNmOpwSbDgCHXw9Dj+fkJ87Lif/3tv7DGyCEaHGA2Qwvvg1BoXTNXSfJc3nuiMoL+qWmWZj4qnVnNnpRuXAqbOV6j++ZAUXmiftuNsjVs+jjs/tTJ3+dMuT+jGLb128reWjemyp89Tj55fEboDNTorNw3kbLmUONctn0daL46+qxWOjv+GkOUUX6fMRVWzFGsqQjeola1xOfezSz1CqWzNAdNbXx1L4Nep7v9E4L817Kde2wInlwM2zoqz6tNo+6p+3uDLIoKYxKMSbyWNKNOzrOGs9d2XcgAtlSYUoC01Uh9R/YAwBy7kjPiskr8CVkie4o7XZ/59nwI6IcBjFQwWFNCvs2ISeUdXCdNF2C8FRM3nk9dm9Shm27kx1ZfmLc33NSRdy8Vga4RRVgdjMN5//j40+vr5/HPd/xs6H6Qw9mdCYNQrwCwYN9RhRoVrxCxIafdSYGw0f5CCJjFIEHdLK2zSCVthajh79VA4v0UuLlagcHef/vb3/Cf//mfbAIyCwvnHBdHpR/2pBK8fj/DOg9vrBSjbBrQ6h/qcDpxgKo7zVmW0OtlmTEv1H8YiFELXxBKkekySG8yxiBjo358pjkCRCW/vHzBL19/wfV6xcf7O87nM5JQ5egkKA0vrBRAROvaNFKPXROhDQ8q9STqWmkM/93JuemHAaUUDPOMqEWjoBVB8rlSZBOhTbgxIA3QkKqhn/80zTDLCuscnp9H9D2njaUwbHyeZ9hc4VJG6FgsOD+g1ISULcX2qWCeJljvMPQ9TocH6hM+iOiWWmBdbYWtk8IMFfJ6BzjvWobUbV4lfL2iC0Q955wQy0L01RhkiZe4XBZ0cl6GABy6Ab/++gsOhwOOxyMeHx/wcDriMB6wrgvmZcbtemWxKBvosla8v1OblnPBPC8UoFdqBZ2n8+E4DjidHvHXv/4rYBzOlytut5uE2JJWG5cVKKT6LMuCy8dHa7zVAvx6ve2cB10bYNw5qJnN3XRPhQa0KCSSCViM44hxHHF6fIAPHr/99hu+v76y6U+5mXzYumVBrsuKZRaNZcmcKscIM88IoYPrArwNzenTGy95cDQOYVGL7TqLkUOVxwO6/oCHxxFfXp7x9EANnfcOUe61t9dF0NKAL1++4C9/+Qtqrfiv337DNE94fX3F5XLF6+sHvv76F/Q9NX3rMmNdF7y+fmemoLFCOfIY1MijgoiC9xjygOFwFNqSBmMXXK9X+MBw8uA9hv4R/8//+B+YbzfM04RpksgViZ3YDAdIBdYQeUXMp2XBGklPfHt7o8HM4UBzgxY7ktuaorQ4uf2lIMZuKGOhDogM5AbpX7lu1umVNF268/J7Hx8feH97x8PDCeN4xL/927+j1oLr9YZpmnEYRrw8P2NZFpw/3vH+/o6vX7/idDrBSyP28fGGZZ6aaVNKCQaV1FgTUB3ZHM4YeGuQJLYFhtlmtWYs8w3nChgbGEUyjDj89YShP+Bv//s3fPv+hqUk5JLJ4vCewyDnYUXHOa83LGtGPxxwPCrNjffP7TbheptblqBzFqELGPoOL09PROmFqaD06b7vUWxttOB1TpinWxsCVFTAlEbX38yi7F0TpQiZonv8b2Dvqrwt7YbmMfr5Wmp2twDpbR9otFJpE5qG0m6UU4ONJq6HDiQL9nEKRHtb0yrIkeqDjarfDP/O31BgUeBNkYGYQ58rnGGb9N1ZRGSUvNIcBRbWdxwe7xHJ3T559xp3rINNVhHvGjUdfmwRBdLMAlw7c2GYOSpSqki5ElasDt516McBoQJxzeI6uzGBvJyXgi0iYH+uc45tmKjNphO6szJcai349u13DlqE0eJFF49S6BBsqcp2xiJDDLG8gbMGDhU5JczzxKiU80UcOOU69h7DYYQXlkcb6u0GnZtZnW1SE12Xvr++4j/+4z/+cB3+PP45j58N3Q9yfDYmAdAWsc/f2/Rurn1fm7dZpuZabKqOBxDaB0ybIFtr4cQZUoNeS2HAcRDhr5VGMq6RQnZBM6xzsJ7/FkJAFzoMIwv91+9nKEe95Nz0MxwCctFWyowiOJobVXNCFrMCCpy1aTUiKyAFJ2fmmjnD3avKgr1HM40xjdrgnFhdrxE5iZvdDtWpucJUI5lnEg7tHAqYe6MoYXDUBDnv4B2bnCx5by3QWzbvlBfEmHAzC1Kprdircm6spT5vPIx4OJ1E8M/P8HK5yOvmueb0z4u2JwNii+xEl1CrirkByGdcBFEqBahLRs6g8Yd1QAWso97ycDri6fkZ3nnEVJpuU10Kja2IYpsOAIfjEc/PTxiGHtfrDefLGXGNuF0vnPxXaUhR6ASqrnBxxTLPCD2D1h9OIzoxYHh5fqTpyGGUwPBOqEOZgcp10zLtNWMhBHSDh3VEE9c1kdqTyQUuxaBkIMWMYsQhdlmxLCtyoXbQWiOC9gi3LLjdrlAmV7tn2ufHwsra2pq3vSEOG0x+bqp32gYrFUBB1zmMY8+ct+OBzUYIsI4aJdWNaMaRarCSaDsBUE/iDAqqNLIVJmdkaxCjBNtLLp9zFtZ4UupSBEyFdYCrtoXwskllAZQLoyRgCsZxQPd4ElMjUreneYaTa+f56Rmn4wlLXEkprMD7+3vTs3hP+t50u2KdZ0wxCr21Q+dOopklFStKVMMSM41/hh5dx8/v7fwBs0ZYO+MwcgCSBW1TNoGef+scvGj3QugwHg9sQARVtdZi6Ad0PbMh13UVx0ciW9SnsukkuqardP30558jPKUUIJNOPkeuAQA1m8aIrrVAzGx8owwPY4/x8ICSM6bpxvVP0H1rLebphihrsDHUUq/zhBgXTNMNyzxjXRZYQXRqBWABYzfNIpuHIveQMgFYJOeSsawzkRzDgHs9j0RMNBidrIdicbfeKgvE8aIDdaaHtr8tK7946ipMAoa+x2EYcDMVaZ1FfysmUMEjZYtcIe9twnT+QEkzUlzlPQhytW/gNk7gdkhztulv5dsGMEZpm1XO270pmLMaAF1boa7onWzKUF3q1vSbdoVok6b/+Od4nzyP7NDcowtMFV5E68F2zWZD6gDvZKBkgBA8uhzQBY+4OkRrUBKZAkbf9O417v/+B32g2Zw59+yRz1/6syUTXaM7doEpFVYWU6LTtX0Oznl0oUOpdNkFmFvK/Z7O2DQy2U6kaeiqxfv7++YvIEjuMNBwi+6SvB6XaUYuaoxFw6R5mmgsZxyq1AlZru0QArq+R98FpGXCdEugE2pBqQbCQ5LPm8OGt7c3MdsyuFyviCnhcDhwqG22iAdlcBRhKyXJE/55/BjHz4buBzlK3ZtucIHc6zh0Sq+0Pbujn2yNy5Z7pvRHfU7naUJhKnO+KMYnpafW2pwrY4oodbMkbjTPumWs6KKqC72if3SucjLxUq2MaNU+02DkL6WURq2sAFLJEhysTQHaxO9uw5SuVBHGYsqdG5f+qec1i0X3x/sH6RLLKqYg4jppOb313mPo6UAVMzVIOQMqE/By3lTn1op5UPt0R4+FIf1xjY2eSoqKFaoHuMlYneqhhagCUnjBtY3A+07oGkr5JI0VuaCCE84iFDUjToA5k+KSiwGMJ1XKVEAGAqHrMAwjjocTvPf4+LjAOdeQXmstTDF3qPEwDAjeoQsdVr/AW9Knco5i7rGg1twKjFITUlyQ1gUprXh8OuDhYcTL0wNCx8LjeBxoguItDApyWhFTlqwpFm9iv9CGDt4HDIcDhuGAZYy4Xq6o9QYjDS5DaWkLfbneUCoYlXG7Mb9PrutiaMSQc4aJCWkVHaMPnDRXINXaGjItKDS+oE2J5XNXbdbpdAIAvL6+Ns1czrVRo6BouxTXbKogWkleLyln2KLRGPt7UK6hkhulNReD2gLrI0LtaYdOqzmWijajVja9LAbVVIC6RTWeITJmUIOHMQGdxEHM88wMscjspuPxCNvxXKVMNG2ap0ZzCt7BiVtiyUQGYyQtapCsPGUf5JyxxgRlcoe+gxc3PACipy2IwSMk9wea3p6KXsqGiDCzzwFi7lArzytkDeu6DjanRgdng5UExfmzLVgrTP79D4w8oVUZbFltXlAs6viSoGhKWfRNKxRCh+pKy52sO0SLlunSOJSNtqrDLx0KEtmo7TGkO4quSzRRzCIVTZS1QkMkSp1chLVetNWk46lNfy4GoQMp2tXIgEhoc9gK+yxdcNeFhkxYIyixUNtTSiiiHXTOIcEI84TvO3iP6hwiOFCabjdMtxsMEqqs243eZ3VIZv6AzhmDP/2euXvZ0swpeVkGYxzqGEHK2NA1KnVr0GqjLbJZdthTGpXiqedmuy7bZoh9m9deyR3Fd3sktJkTxN1ZwIOOkbkYdJ1HLgXj0HEdz2l3z+tz3O+T+yHoH672T82cPv5zQ6fUWZkW73pqoWJa2wxG+Lx7xrLZ3rw2sTL4VSK6kWGN7r36Oqy1jZ6rBkwlZ+SSxLRKAr+d/t4irtUSui4DUBgP63xbu/q+R40rVJNYaoEtipIaFFnDc8ptCJgLB6JJtPCh6+F9aNeJoqF7Q6af7dyPc/xs6H6QY68L0aKQ7pJb9pW6lq3r2hZF1VqFYNuCu6d3NM2B86hC1dDw44eHBxwOh+aM9lkXBGx5cnujDj0aLVNeMyfRK6xMoVytQCmoxW4bCTaKBGQD10281IqcIhs60eg5u212tW7bnhXXtn7oWwOyURtM26Cq2eicl8sZt+uVlD1xk9THU7DP4m4cjwjBY4kzMF0RzbYpq7ukNtmbnnDLkim7wlv/rujrfiMqpaAaIMaEeaINd9m5ZllpMvVaYOgwAEM79hIrptnBexaMqju4N5HRs05TEZgCL0W0ley7LvRix7wFne5dOtVMQl/3uq5YphmowDxNWOcFRTKeasmIy4xSEnyg311cFszTTc5BwdeXF7y8POPl5bkVKsFboGbEuCDGpTU7em21tyKOli549OOAx8cnPD69IK4J3/0rcgbjFgo3/1KBeVnx/dsrUinN8CRnaQqDhtJbXqt11+T0ASXRAvueesemvOu6u89eEaKu6/D09ISvX7+2c3e9XsV6n49nWHPGbZ4AY7AsixiCOJhqke02aNDP43MBBeDOGRK5IpftmutLQT/S9MNZy4bNODCMPVFLhgrvLYa+wzj0OIxEpxzTeXE+nzHdbnh5ecHLy0ujCjHaY8X1SlowCyGP4C3mdWnvue/oVPr0+IRgHa7O4Xa9YJlveCuxObaq5rcKDVZR6a7v4X2HYRjawAK1Yo0RYVckp7TFfFhn4TT3qcs0/SkZXd/hdBpxm2a8ff9AyhnjOOJwOOBwHMSIpUiw94IYVxwOx7t1r12Ldfv7HpW5Xx/5evfreUqJWZY5N+Ob4+GIXLIMYLKYkoyNTnw+X3A4jGJ1TjoaG8JNO4q6R1k20yrv+Zl7S/S3loySkjSMaOuKNpa1VuSYsGJFgWnr5LIuWJaIUh36oSCETnS4NElR6r33ge8jZRS7cyz1Hj5k9JXXS86JiN2yyNCkiI4vyrlgQ5cFIc8pMz81rgiusjFQYE0GLEq7VNMnRR+t0uq0kfv09fnY1k5ppj59rp8fqxRK1TOyqZNmbt8w6Yps1IUX+w7rvmlrz8/mDTukzkoTqg0dnEWwBrkYGqXUgFoNjofDbuC4oCYOO/avA5/+/hmh2+/xerS9aUe11N+TC5skZv+xkbOid1YFW6mlodJmnlFhkVOhT85euyymagxHh8Qc3DtMt9e/Q+jWZZZIDh1uW0G5HbSdpIkRxLiNX+2vuw+Ar7WIUU9h3SEPsoU0awgdPsuepVpU771EFIzt/ERZ/9fdAOYfXVs/j3++42dD94McpHRsky5toB4fH1v2mGa/nc/nlsu08dv3m9i2yAIy9IIUQwaNDnYQzYiaBQQp9LUg3DcHe8OHPTec6KBkzZUqYdjaVJqt+A00Q6DJAgM/96OpIs2AFryKWgBC5ajcxJXaEnyA7wKOnzQp3ACF0mksitkWTI0BGIYB6naoTZNqEZ1TepLqpMiXr1U3k63p4WavBcTmcAmwkBiGsRkTqNOhOmhW2dRQgWVZG50U0vxtLpd+pwfQM2LauaXuj5WJhvNqkLPqfiqI5lUpvGjcwEn9bVrg/BVd10uju95pEQE0FEQnu3HdKCbTNGG63XC7klK3xgVxWZBrRCnUneREykoIFqHr8eXlCU9PD3g4HYjoRWbRlZyRokQ4FDFAaQiCnoOtIEgpi4i9bveAdSCFysAYUkuz0AWzWNgzX6y05rohKlq4yUkzIFIVxUWRBSuL8GEY8PBwatdBjOsfqJf6ObBhrFCN1V5HUfcFltV8vV2xtZtyaxNRq74/+RdjKPC3pGCq/k8LY16PDPMdux7rOmGZKlJchZKqyImYgXhSFi2YzcQp96bFHYaBr2decLvdoMHRfU+aZd/3rSmqMrB5fjhRx+UMbcXXBdfrVVC3hGEYGRYsyFJcF9yupK/2A102S9UGSc6zNXfvj5QnwOym+EYek4vSDA2sxLNo3lRKCUaoYPcUs3+EqHA9xf0Stv0s9D7YE8knAAAgAElEQVRTeq4Wvmhr7d7pdhhHoVJaMUkxjeZIjeAMHzxOh6FdSzFFBNHqMn/SwWX+nlq22BZgPywsLRMy54RmLLRD6PiaM2CSGJ/QoZSxA8yKU8aAtR4xZRl41PaevBW9WdVoFEFEEgcIPL9bnENMCShJinC5nyH6bmWs1MJsO/ncFVgz7bzr+9jei95H91+fG7rdZ6qfdamoRimUW0QKQbj7hmePXhGt/XM0q/1Zd46Tut6YrZnjA/e/Qx/9Z7EKFVaep4pG3RQDqigMjqcj1Am5VKAgIsMg7xBmfar9UGK7nvk7Ssm77zl8Pu7OQa2boYxCoIK66T1VckVChrERMCtg6EpcYYCUEdeE4nkfQ+iKxRhUk2GSlX16G5SQGUR31uPxiJuByCQKXTRlLVbJQpU3RwaJER2+k99nUKoOdYw0l0UcsfV+EvaHNciFyG3Vk9g23HJXW7TQ+pVOnqrd3w+ifx7//MfPhu4HOYL3cELlKLIoWGNxFKOIw/FI0fv1hre3N0wT9RKby9lWhOvkDFDb9ALEJLsfKUfrsuJ6uYob3Yrr7SY0oy2aIAu/20CmvrlIUVUaomakUYyRzRQqYJxHCD1C59GFgBA8vv7ySyvivn//Hcs0oUKzXioyUpvwkZogfHfQyS6XjX4JY3CQc/Ly5QVd34uJBO3MJYJMBnw7sbw4Rnb9AGMj9nk4VkxpcqlY1og1RszLBFgI7XWb/q6rhFe3Bd61n7fWNv3Q8XjETSh+1+sVtVZ0HWlTLLojDIB1XbDOM+kz0pR1oZfpIQDQxQuGNLGuC+gts9ymdZUmuKDre4x9j5eXX1ojsKwr5mXF5ToRvamU1+dE9CWnb7DWYuz7JubOJUHjGKpMFVFyGw3fLh94e/3WCtNSCrIYPMS0wJiMCtLgDocBh3HE8/MvOJ6OOB2P+PXXFwTvWVqURP1EtRsFRYoDL1b9xhhu0KCOvVaDdU1I6YbbLeH794vo2bJQGg1yAQqyltYypeb57EKAsaY5H5aSgSzFgaDh1higVMSVjQl1ELyWabTygF9//RWauXi51BZUrZopbd7e3l6xrnND7wA04xknWlUA7c9c1FRls4O3AIphQZRSapN95+nS+K//+i8i1gfeP95xuV7ZUOVCs5qaUIKB6QJqSch5RS58XyUn5ByxLDOuV4eSVwRbJVh6JFKSM75//77FKRyPGMYDrrcJ18sN07LA+4BxHPCv//YvolUk0rquETEl+NDhMQQE73E8HvB//va/GIHwweFA1/cYxwOOpwehZiasccUaI/6vf/lra9DWmTrIOE9tfTMGgkYFNjfSfHtPhNA6h5QKPj6ucN7jl1++smGaZ2pWrxvVvO8l41E+m1YAQpD1XQFb2zpgBAVy0sxxGKBZiqVULNJo0/G20FHSFAx9j8eHI5Z1wfV6QUrU8XnnmrZvGHqMEhq9rgtQKvzp2NgCtWTMSpWOdKp03sOHgNB1WOaJFLSSEMUB0AdPQyxdX3JGMRnBMx4ieIfHhwf8y7/8FbdlgX/9wHVamqbPWou4zkSfRVsafMA4DBzgFZq7rDE2OisM1x+ikMxYrDnh/PHBAPGcYGUgYho6JcM9I0O9Qoq50k+tVZ2bFeaGFN3ytUfp/kjDxN1azoFRavtMdpJZqsPRXR7qZua1/ftm0qHNPaAoH9ogxogmTl6vuJu2ZnE3zCRFX7R18l61EabjrDQ4xsAUIAtNuOss4L5g6Mi+cP4MnG+4LZHmI61pvG/s9seekQBs502p46XkbW81Qu31DtYyPzJn1gmUQhSkapEyTWxcNXBOckP1c5HYhpgirxFjpSe0SDEhpoxliXBuEVaOZKR6Dj5DoNtkSdTh85IxqCHQRMgH6udLQSoARFPnvGhbQT18El3tBMBkxhd4x6zHvh9wPFEXuiyyZwmVu1GbLd1jU0qYl3k3iJLhk7EtgibFiHma/3jyfx7/lMfPhu4HOdRmF6CVOAAxImBGSanUESg3exwH9OJ8mHORjKxtGqso0p56YqxFlgDgj3jB5cIcozWutBhXMbrq7UBhPMAJ97Io7Y6bkbMbTYMWx0J/WlbJ0nLwfSdObU+Y5xmoFR/vHrNQL5xxu81Epnqmgg5saoufGzJnjdBnnIPvgmSH9e091lqRqzah24ZUa200TZ08stDn+SnWCSFE0ExpbLivctNU+tyeXqn0Dy90JeccHh4e8Pj4SH2RGGcozUonuTyPBt7ZZhwi1SE3fZk0Z0GjSMXyonkb0PV0/IvfvmOeF8TI19T3PR4fH1kkGIPz5YpULpiXd0jMurwXflY5MQdtXeamU4QxCGLUUWtBXNeGBqszXIzcyLwgOgYV6zpjWSbmx4IUqofTiOPpgK9ff8XD6YhxGFFywpIT1tXcFVJKSdWhRNf1grAVrIkW+KTJODjfIfgRMRecLxdYo7QuGlnEFJEWhtyrtjGV2Gy2nSFdJiVq29gQyACi2xAeDYJm9huF+0lMdcZxZF6dOE/yrRikFHG5XBvCfT5fGurqvRcdJAO+u9ChD10LWuYlIPpKY+B8Byf5XgZidGEMYmJhPkjj8vDwiNCRgqT6jHm6Ia0LSl6xGiAuN1zPGfPtipojjVmGEU+PDxj6DiWxsJ4uBtPljHEY8PXrV/RPT6K1FbRzmmFg4UPAL798RTdcYd7e8fFxxt9/+zt+/cvXxgBQfezH5YLOeXSehfxhOGCdZ/z+2284f0xY1gu8dzg9rhjGHiH0RAq9hXWQ4YEyGYj4p3kSDRkHRfO8IBc6zwXRB4/jiH4chea3N4kycKKT6boO87Lg43zGPM8NbTocDrD+j4gEdPmANgCtLKbYt6IVzLoO324zh03GCkOgtJgE7w3G4QCDgunG62eZK9D3MJWNqjVGWAikpCsKpbSzUiycGqZYiY0BhyLee5yjUhkzakFbn62h4U+uol20Fd6Rott3HYxj8z0OAy7hBjOLpki+GE/CTMx+GNF1HUrJWNfajH5cIfpRKylsy7Kghg7e0cBC9d+mFlhFWw1QUmnDhlKS0EVJpasmwSIDVgLDLWBMlS/TwKEN8da/yPdNGw9uH2b7bBVF2/Y21RLquqlo1J4JoYPP/ZpWt82tdU2NfimvqaFZuo/uXpfMJnd7005OUPU7+hP8b8uOFmPfI/URa9/j6md4ZyVg3DS6ql62/4hyuTFRtut9j0AqWquW/epQmdRVsmbUwmuStHaIezJri2HsYayY7lTx73SeA4UuwFpP05Jam2NvFEbQ0PUNgV+WBetCw6PLx5luqJJ7OgwjjseHJrVYI/eGUgugWloDopy7z7cCYjjjgC4ACBhGDtj1/c8LUGSoWpQJgCryCDZ2zLQjqnc4nWDAfe52u8Fb14YBP49//uNnQ/eDHNqQoJJfb4TqcL2cOcWZ6cqUkxiIyBQvZ34PALy3bVLlZAPdKBv8Xy1AjurYREZ5Vj2NTiGtQwi9FLcdrDFNZ6fZUM5ywmuM5CblAv11zUmsUQgT3t/fscwMvWURjTZBNZV6rlIraiQXnT/PnbgaUgQ52bSw3iOXjHme8HH+QLcExJiFGiKbjUxkD8cDQujQdaEhJppDRfqpvTc4qRlr4usuSiExLJj4Z230SaVB5lxghNqpOsRpYoAznfPYCPDfC6wFQieboLWoRU0SeE588BjGgTETiUXcumQA6s5St2ak5EYFUa3e+UIaXAVwmyZM8wqaq9iGvtKMhqLxJC4rapJhDJCjQVwldkJobrC20dzUcTEalhopZaQcQTMUMcQIA375+gteXl7w9ETqsLe20cvUXKCUguA8mFEuqgsbcHp4ovNmTHj7eKPBizWgUYUVhzDAGDHwAV3RqtHpvNLMijSz3GxRDXKmXTvvEyPTbm60v/7lvxEdWhekmLAsK2BYvMbI63tZHF5fX6VRL4LQquslXTWn29wobmU/2Zd7omVuieh+bfexk1xKFrd9Tx1GljiD33//HcbxHQE0RLrergiRBhPrSk0jakHJVSKjqLksNqKWhOAMQhjwcDzg+eEBp9NR1g8xLpACdp5mOOtwPJ7QDwOHJIkOoQWACz2G8YBTqUR+a8H7xweOxyOOxwOsEXMZ4wU5pV7RWYvxcMTDw8JB0qUgphXn8zt8sDgejjgcTzAO8Nkip8hr01LrWHJu1MSuC0iJw62UMlygcyrNi6hby7UI6sx1gBpUNATYWdeCrzVzkg15ua98oQW5onO876xxLUqC6A3r9xhXyd9kAZklPkI1mAAHd0UMTPrgkeOKuMzovIM1FV4m/xzAKJW1IHgOj3zwiCu1sY9PT7icz4JIs9mcZq6pXFEdak10ga0a9lwbitb1TmhiDmoGMgw9xqFDFzysKViWG95ev8H7jmyFyr3DGaDvArxQxJm7J/diYch1BTCOByIelpmgMUbklJipZi0s+FwpMSC6pBUobOCcKbBIMDUCkHULkgMq97zqoAy3U35W2qh8alysDBFtG/LhjlrpjYMzVlwiIT9DWmlVvrRBi8+hLIHyg03KvunH5P/te2xytbdTlxYdK2rXJTTeuj2+wrRmsZSKVPN+HsiIEMvBXN95HMeen3EpSLMacWyo0WfUGdAoJTbB+nhUtL2v/U/QxyJ7kbHMCd3umCrDSwcHGTgIjabrPFzosMYtSL7rAvphxHg8wrmAXIBYPpAR2/uDMbDOc42T5rHWgts0IaZEPZ68glKJjq8pYV0W6vysha3U4I/jAcZYTNOMaV62+93owJGoogHf5ywZc8u6cHAolFQ26fLpOkNpCSpCACCDaye5uNYaZp52vK9+Hj/G8fOT/kEOJ7QRLrKyrJeC64WmBMb5xs/OmehIETe2lDKsd1wcur5RYogmbS5siuaVvGng2FR4oBrEEtmYOWDoBhyPR4yHEV6KonWJKFnyWLxlseZowx3zhjp1ITSKQs0Zyzzhb5dzM3RhgwOhFBoY55ijJk1mFlqGUiZhOTmD46TXec/F+bxiWWYpdjjZrigo4I847/D4/IRBNIjLsmJeZnx8fBCVsUZcFjtSuYQul9MqRZoEULcmTp0OAWM2py2Kr1Obll8uZ0zTFSEEMRVgEeeckUbSSoD1AAPg/PGBNaZWyPuuw+HEoidGvkeIlosUxYhYGceg2W9BzD1Syvj7b9+QilJV5Xy6TuhVptEMU6YDWs4JtSSWDWKFnwojA5wlGsK+jVNWtZiPMWFNpNPlVJDzCusMvLc4HEY8vzzhr3/9K06nE8ZxbAjnmjKCZ/OUU8KyrrC9a1oPA6B6i9PDM07HI9ZlwW1esKxZEF2LnCvWtML57TzydUuh5pwUhRpOL1NSsIAtmQXA0+MLAGBdt4nzv//7f2dG0LfvNG2wgEGRRti0Zvr79+9tUhvEgXRdeG2XQqohiyROudXxUBuKlKgb8pn30HSbAGMbPYjFi0E/jvjl66+opWKaZ/z+/TssPIJkA8aU8e3bt6a1XJcF67KQulUhCENGBeM7vDfou4Bx6PFwGPH8eMLT0xPGccA4Dqg5Y7reaIQxzVjnBSjAMIzwPiAmmZTHiN4H+I5Uym4ccXx4wPdvv2GNK0otGIcRQz+i70cWbLUipopiMvp+xPPLC1xwMK7i/f2VmWrrFc/Pz6imwFg2NDVH3v9V3FTjCmtJP+a9zuIsxQzrt4bOyABhvUXJmXtGqRXTvCAnGSwYnsdhOOwQCtKvqkzw90fHCo1rqIwJnDVIiUUegRNSem83IrhB3BznhS6hfd/jdDoheIfr9QNxWWFMxdj3mK9XzMsCjAMRAk+TCWu4JywzM/dKSTg9nOADIzt81+Hx8REaeqxazXmeWeRbCweDGDNizAilwmSyIZaFWta+pyFUF9hMGgMMfcA4dOg75tndrmdczleEbiC13neoOcKiYggex9MJ1jm8fn/lvWg3alpFxdPTEwBqcfkao2R6WRhn4YwhxTivKIlfpiQ4FARbhXedUSHhz8bBGCcMgtrQS6WrS9rehkTtBmCoaj4lWXZm24OVreKNR4qpIf3OODhvkWuSBkd1mXSLTYJYNtSrAW6tU2hNUxY9M11I7d3rNloImA2dU31mFcSnVjorRgmtN8bCiCOwBeCdRR8CTuMAtcqf09TkFHyvpkkpmsYMgAmisaw7OqgMIxjuznPmZFCZY0YS51MbeqiuXwcDvgsSYi+a+RoRgkU/dsh1wZozSq0IXcDx4Yin5y9woaNL8byK/s80OisbLo2U4bldlhX0U9m8AJaYkM4XGfhQajEeTnCemrsvX74AAP7+999xPn8IDZb5gzpsU0OdmFZM74xByDm3IYXlJFscX3mJLXGG9RbGdY0WzPvZiY9Bh2HoRZP88/gRjp8N3Q9yOOdYuCidQWgOjc64c9KjochGe3BeQ3GP1C90HQCDq+ho1J4fO/oZaRR2J9iXrKuaQdoYm0W3RNQgU2iZXqvOTo1QStF8Lr6mEGRyptbSmVoVok1b6HJtm0hpG771Hp11jY9ewUWYrx8yoVT9AgsW3aPVWr9pCWXKXMECOqaV6EXOUuCQLuiCOE9aooFZLNC9xDCoo5YRpHJvRrPFFGzmK2o6oBET+3zBXBKQmHFXpcCpIKKo9JokOWDZOWm2smzslSjROvMzylVcMbdrJaeEXBc2cqVKKCtIYcqV6J5MTJ2YcJSSkNZFGjgOF4wRyZxMwIPzsKJNykLRJN0qCupANHQYejycjnh4OOIkGh9AKXOlaS2NcczlsonUWqXSVhY587Li9e2tmf+sK41JjDPImVto8AGwnqiI6lmkUdcJvXNGJt8Vx+NBLKT5Oc7zDAI+vB71ex/vZ5zP/KIbZRJaqUaEZNS6AlAH0iCIGimB1LioodA2PFHER81HjCDEIQQcn07ohxlr5GCggoL8BWsreME7jO6dIAqUa0bNFbfbjTpcaZINKhxIceMQIMEgwweLQ9/jdDri4eGE0/GIvgtAKcx/NIC3LHSOhwOWNRINsxbzvBCJ1AxE6P24GcHQefSxUY7WNcLCYRzY0JWcEdcFc1yR0wLAiLPsATEuSHnBPF9xvnwQ7V5mxBjx8PgM7xyKCyxWjZHcwUUcGBcJPXbonN2tAZ5GOUK3ZoNuG2Kfs3yVjArTDA9s06/uKHSyVmtYtg6gqqD5unYzZ07NP7a1zhhzZ5TjhapsDY1pnDXw1sI7fgXvkBObG83qzDIEiHHFsroW1UJHWlLRgyJ/dcszhOFgqtaKrh/QdT1KBe8rYSKEQLTACNJfcoaxDBJ/OB1xOIzog8MyAzFHpCgUtRaRQt1k13USa1BaQwIL6rwsKbOkBM+Yl6Wt2yyegYIE1IS4LkhxQY4rG/pKlK4ashWMKYLqAdbJ124QSCajyg42Z0bpuPmyxFDDWY08sM18i0M9gdl2qB2kgatWqJhlc37UfVFRqT8/7g2Ndh2b/vPd9abfrLpnCoq2/9pM0bBRO8FzHmTYO6SMEKjVzsIA0gZOw7v3A40N1fxH72KjavKcyb1SCoQWgH0GmxMdeykJJWes0eB2uyDLfWgMDVUKaJQzLTNsylhjRq6A9QGD7+FVDhBvkm8aoVpGyiiqNLriACx5bxzo0QAFu9e+OVHHZhZUq4VxXqiYG9JbMoc2uVCLZ6yB9R7jYUToe4QuYF5WXK83FImk0RqOVOS1UbrnaaIPQq1/OLc/j3/O42dD94Mc3jkE5zdTFOVyVKVRbEhbc2cyFlasoQ+HA06nIw6HI/qORfSWWxeJFgi9ZEOZNo0dqWehLcC32w3rujZ+vKJPDBQ2TeO0F0Vrw1ZqRoybQyaRmbVp4fi7twYsJRqzAGCQceianXbOCZfLRSbSBbkW8QbhIpnTfQZVy+4T2uoy37DMaOiQauCcmB2kEmGSvMa0clEvURo6Tv0P4wHjOMIYNsnTNLUFWotz/Wy0iAeqNDCbO6CRKX5UypfQ/HLJ1H7JxrGuK95z3EKfncMw9ug6LZIXaaAtqRzS6Zac2eQZCMWDxTczpWgVzoKuQ3c64PF4wPVyxvn8jo/3N9xuFyzXGzdM79B1DqUYoFqE0KEfOvTDsLnk1Qxrga549MOAX3/9FY+Pj3h+JtoDgxbgqo0nqsHp+CB2zgO6ucccZkzT0q6jNUbc4ozz/3fF8XSCc45OoACMIb3WB49xHJFyxW1aoAWUBnszL44Nk+obv379ioeHB4QQMM8zvn37jvf3MzQjkFTZCf/zf/6/WJYZ8zyhogCmoh96bsS5cihQKrpubJpVDQOnC6rjNR2jAMtOrheidu5Oy8li8C9/+QtyBj7OZ0zTjOttomHHukIAPjk3pA+yLS+StZQx3QpyR9MWErQKUDJqYjNXSkQIBk+Pj3h+esCXl2d8eflCwyXRdJVcEOcFCAEH0UM9mM2JMKeC4gx811FbZgzONzG9EIdZWOCv//e/SMPBaIbr9QbvArwlJTwZNhG324RaI2pNGIcezj2j7x0ul4CUE6bpgnm+4dv3bwihw8vLVzw/WwCkBNY+0FU1xhZ6TqQn7DR0B3z5+hWnxweoeVPKGcilTfjZeDHTkY3YvpiXsPe2LkNeM+4KsVgjc6qsRVzX5hZLymwvQ6mCh4dTiwMxhrQ8J/QseIc+BAx9gLMGh2FAjhFLKdQE5SzN64xlnWEs2QDee5zPZzF06dAPvWhJ5V4fOkYRrNRKH4cRQ9/j99fvSIn6z/FAk5t+6Nl0i8mNsQ6n4wH/9u//ilwKzu8fiDFhWa4oKWJeIwCLp+cXdMFjWSfE79TyMfCejaUxFc55jOMBKdKQ6+31lYMGU+GtBWpCjitSWlDigvPHO6bzB+brBcs8Ia0zaokwhq6kjOJg7lrX+TbQYNm+7XFWDFNC1xFdrYJ1CQvDGtMQuuZEuWviq1L05F5vQ1FXZKi5cwXWP+vmgNwOYVPea9u1AVQXY+Vk/rGZ0oGfkfOa65YLG9xWKhpxAXUGQpO1cC4A1uG2JLxebuKwGDc00YWmvUSrEwBrVSrAF8N9V77M5lypfbvKBpRuWiudUWESnMtwDs3gpKwJ5e0V3bTA+g7WUbOZUsZtmrDEjAqLVIBYyYLouhF936HrO5TFYZknLIY6tVIr6fimIEOyE3NGLRXOO3EnHqlNLwWmFMzLjPePd5RSMM2z3OusU/qug/dOtNtiBoci1GrJcTQOxrL+Go8HDIcD3t/fcbvd+Fw7DTwQEVf6EMQY8fb6jvPHWZLTfx4/wvGzoftRjjYYMw2JqpWUHyNFBnQjsFLEA6g1NZOFdV3hZWFXap26wNXKKVXK22bFzWgLIWdRjEZNKCUjpSi2uwlqTEJUgdqVYaDldteFlpOXS9wWQPlzQ+Z0cr05guWcUcUxK3hSpUJgQxfjtunpZqIaMgr8c9OgkP9fUYtBLXTvi+t9NhtpNqot4s8nmaTrwlsLLfr3r0eRJjZz9a5xM2Z7LzRG4bS3qHkACmkooj/bB4uq7s5as01mCxvV6gxCYDPdDx11VtLYlpqANm002/msNDgw4vTmAvOluhCwGk7Bx3HE8XDA4AOupyOGoWcxg4q3RTRhBsiJ1J4SJLBZ3ivzdXrkUhA6xiYcDgd8/foLTscjDoeBcQ+1YBWaIxtaByvW0uM40kFRTBve3j6atfQ2BEhwMwtLIlu2TcmbJrR+yrrynq6hcZZrbYtfuAuMrbXlF9ZS29Q254yPjw9BWBOsM6TfyPtQxG1/Panxh9b3KdV27ykCpwMPIpVG7mfIPcMIA+dCux70ekKlJvNyOaNWYI0SlGvuiwAOCCwbcFS5hoiuVdF4BO/l8xklf23Ew8MJjw8PMBWIEqVQCk0GUkoSjCtxDc4rDELkXK7hKK8pi1W4ffmF79kCcU1Ia8b7xzuGrscQGFLedR7LdMb54wO5rDiMnSBTDl++fCGiHiPOlwveP97x97//F4Lv8PT4zEm+sXh+fr5z9K214nL5jjVeUMHr9HQ64fT4gNPDCa4P6PuK6+2G19d3pFzlXBzoeCrZWLoOqKkHn3tr4HLeG1fw2IybjNDGt+dwziJGHQIEqMlGW0NMRcoRznJgoeuxUmhLychLQsqaebmh//NMyvk8TwiBa/DWJGwukKtdeO3KfWTslm+pERtq4KJoR5VKfRxHdP2A7w9v6Hvmfm4xM6S79X2P4+mAZV0x3Yg0+xAA4xt6qVrFlIi+retC58Au8LrNlfmI64q0zpiXGetKl9MUI7XisuZaszk+qga6DRcBdj7YtM7qZMyGDxJwLYYi5h5tgtnFCNTNIAXAbi/a1pWGUhlz9zz7x7ZDGsbPTV3T48k+vH/49hwbsqdsmM+vhT9k2+/kteRQjUNfaJoVvMdiVyiLgPpN15rbLXEdbY37/Lr+4SHUXu88SgVSrtSPyhrLWqII1ZRgXi4FaY0wFgi9xh0J5RlVdNIaBZIRRVoxSP4lA8ctHDbTKZN0cJPpSWCtoNcBqODQoBasMnRTxN35Db0LgU6vydzn8TlnAcN9SqMylOYMa7FGYeW0S0jrDoh+vyKu23DZun9gvPTz+Kc7fjZ0P8ihGTwiv9iKxcLpZikFtjkAagG/mXyoi+KyLAx9NRazaC3U2U0bDhg0+hhQd66NW6O354DwdWzGDkpl8d7jeDogxQ5d12GaboCpuFyWttHoZqB0CH2+e6cuUl82G+kqzeR90WOsgYMTIxFq5TgRJfKTld4gDaQBWoZaqUVorMqLZ5GWU5LzYXbTUW2IIy6Xc8uOImWL1FFFNbuuk1Bu35rhVVyvAKB4D4d6l/F3nx+4t7EWp85igZLbZq5hqhBTBSvvP6aEigTqRzzjImyAKR6lgPq4UmFiQik9csmA1VBVhqR6acxD37EAgxHDjoqcIC54WYxzuEmG0GHo2XTrZzD0Aw7DAO+suEEScdVrS0X0pXI6qajvRnfJjaJG10nTwmC3a5DnjqJ7YE0RKVdaSR+3ye3lcsbra2xDCP3Z6/UKY0jxWxaicRTyK2VJqT9DgBUAACAASURBVFMGgJMmm9ed0iVbowXTimEOQLIgdERG9PccDnT5VKT5crmwkCoRLMpIe/v9929wjlqoZY3bNeLcdk0JwqTDAj13BhtNVh0IS85CL+b6QWtv2wralBKmaSI6AdOMLLz37T6BFDLLujJeIUh2mFHWAD+jIs1OWRnC/tu33zEOA8axhwkWzhS8vr4irxG57/H48IChH3A8HjBPZyyXG96WCTCk/Iahg4OToQ5RnVIKzucz/s//+d94fn7B4+PzXcyF5uP95b/9RQrajWI3TTP+6+9/h5Pwc2MMjscjNMKFus5E+p3btLFV1i1dj/VQ7dG+WCfd07SG4jNysw1w0BqyrbFLKDHCmS0UntdbEqRzESMpXUuzFONJGjiDaZqEMjyhE/djfY0hBJFlcZ1MJWMVZI/DBuJZOSUsBuj7kY2sURdDA1sNhqHD4XDEMFzg3YXMuloE5RS6olD1Ss7I1sI6I2gV95SUI+Z5RhSKN81EKinhqKJNSkhxZWMXVw4mlNFQt31Jz63awKuui/8s1v+s1rnHaMMCKIN9ewx2lEpsP1PrTlO2b8x2v/+OMmdEh2furw/9nfqY9to/IXStlVT0XhC4RiHVBg/3zd5906i/hhEOFUK9DA7j0GMcBkRpQLbBpGgRd8+hTJ7797c7AVWNgdru+ekBu4fK+S3Y9nFYRpX0wwgXOjjXwThx6k0JNVdUQ74BrEdJGbGm9oxRtMy6xygarowYbVZLKW2Qd5Cw9TWq1nlzHNZ7RdeUlmGZc/viPW2Fym8gkwXM84w1RdhJ458sQt+j70hv1hqioZtythQ9/nn8GMfPhu4HOVLTuckiIcc+8JgLiJUCYafLSQnzQvczzV6yxrYCWBG6KlQtJwifMRalijtkNQ3V2W8quk+Umhs1zTojSJ3D8TCyyF8DAFr9n89/nOTtC4zP3ycaJgU0gC3npgiFs8gGxiKTE2Lqtlij8LzwfRSUbGCQEFFQCpGiUguc9fCOeqqSWaCr86E1kklnDaw0uynGZkAQ49poi2qAEkJoIdPjOMJ7B6Di/f0d01RkqshzTcc9d7f57Ce8e2pQzSK1NnX3fQdTbZva65QvF2aRdR2dA0MXYIvDsmbkJaLUhFrXJt52zopZCvN/NHut6QQh2YU5YUVuweDrurSG7nQ64fn5mTRcmY4G32EcBMVc5taQ3DWvlU53SuUl7WfbdElFc+06oRX2Ni3WpsqHgGqAmBJKMTgcepp6HGjq4ZzB+fzeimAtkm+3W8sBS4n5XjknoUqVXUMnAc17amPOYn4jTZToyPRejIm5R04aMEU9Hh4e8fXXLyglt4DZGFeUJQmazM/x99+/NxpwaTRrNloAkbyUaYTT9R7IaFPghlZgy+nKOTU01wtK6J2Fl3ssS0NXM63i1Tio73u6sMmke5qItnTGoJOKspVuhlTciq0wyiXj92/f8OXLC47HES5YeAfMtwnJrSg54eF0RNd3OB4P+PgIgoq+wZiCx6cjrO1bY3U4HAFY/P23V5wvZ6xrRN8PeHn5ZVeQ8nwPw4CX8YBuIEIMAGuM+Pb9O17f3mCdEzOSB3z5+iu8p2nJ7TYh5oyup0GBNnRq7KLugrVdh5smtkpTECVOZr++KeVS73sWdKUhtZpDmRKt/73bjBxKpWus6n6p9yTVVNfznGszmFKt5zRNu3W0tjWKelk2Gx8fH7hcLmKEM8KHgOv1hmleYEpB3x9g5b1wnQccgL4POB4PDIEXDWgVrZISDAy24QszvAwbBdGxxrhinm50ABSLfiPFM3WhXHtyZDPHgj2hFFK8aylw9pNkQLPmjJHIn4rmSVkrLfqrbq13HQn/3xqTP7Ykn3ey9jv5H+177d/BG7K5P949m9H/f0LvZM812lTea+w2aubdK/mE3u1fgbl7bmeBajhsGkY2dMxZ3evr+W7N/l3X2u5tvRb276chl9r0/nkv1x5d5ZwZa+CNgfFssoZxwDAe4cOAXICbhG+XWlBFMmBQkGtGqQb6gZqcxBQutf1UGzprrWS9prYWD8OAw+GAlDhc06HLfk/mQE7XVtP2pbuGzm5Zv9VwdDDPMwcSILXYC724Cz3XyFqbjvzzteTsT4TuRzl+NnQ/yFEqKUzG0l1JF5dx7NqCrcNG1YEkpQiChiXWkLufS5Fp5z0V0TqLLkjDZ9UtkI1gThmqFdF5GhEKKxTH2hZ9FRAvy4zz5YPam8TMPAYmVwZkG05flVKoTlS6OVjDkFlFpoxRw4nSNsyS011Oi54J7xxgKwOkMxqiZY1t2Wg+eFhY4bwTISQfnu+RG53k9lkPKO+/VLH0py1+NgnrvMC6CGepaetCYGhr8M3AoO/5Wd2uV8wgaoJK7Zx3Tpw/DSAbpLPMHtLAbkVQCoAkGUzzrChjohPnsrZC0wcicsMw4nA44Xh6xPHhEbk4nC83fJwvWJaIZU1sRgtdxNZ1xfX/Z+89lyRJjjTBz5jTiEhSVY0FMDM7Ivfv3v9hZm92T/ZwmOnuoplBnBi9H6pq7pFdcw+AKhdJdCFJEHcPM1X92O2GFAKCXzFPN0JzSoZjSljiCW1JuSKOEhybUgfniHaplK4FTAwe1lk8PlAOXs4Z18uV3O0KTedTZLMcFq7L5NK5pl7jlNjcRFEUgAwpSiGjF658/jDptuY+D0kMfITqKhQXsZ2WIpxeR0JOYu4jFFqOiEABeYFo6LIVOF3X3RUQkfOG5B6XBl2aw7vii0HwjXrnkRJHKFA3VzU5UiCjEBXW8HMlibpQVLQpq2GsJlt1o3AzmorgkoBiQDENGuPQ43Q8YhxHGK0571J0NZEKH+c4KFzBWsp+enk5Q2lyq3NNg6ZtYdsGNhBV1liiNH3+9Al+XXG5XNBYckE8PZw4a7Hg9XzGssywKuIwjsjpCSHMuN1e8fnzZ8zLDeM4YDwcYA05rJ5OR7RNh64doEDOsE9PJ6QkYe4B1+sVnz59RtN1nD01wrkGDw8PGMZDLZahSAtrbcNo3YCQCPGmhkhzBp6h8N9EzRMARmsLU9OkcQKWZUXTEGU2M6OgokqaDEMia3RDWMmVkgPsxVgoGo0QAzVwKzlTUs7hgnmeeCi0OeIJc4I+MxFAhvcLrDPbPYPCmZWOGzqDZVlh7UqmOqkAKlU3WPqsZGZIROgQYHyszoEPDyecL1f0fYeUCrwnPdSyLPj27VtlBYihFTWEZNZCe9eKdZnINVIDKAnBJzSmkOYzxRqnUsRcg50GkXOlSdLnwLBxlab8Oqi7z9+219w3PXW4uPt3LuW7/Yji6/z273n5+cOAEqjbyN3z1iZwG5feHYXR+juUkP5w9xy0aBRZH9QfKZ2yzuzPgeSxKqXQuAb90MHHgNV70jeXTBmE0oiLLrhwFuz2YnYveGfMovY/2ZogxeZm2lAsUdN20NaxYRcAZloUKGjjYF2DEjMAylm0xsG6Fq5tERMQU0aIGSkCCgW5BG76493gRNDw/bCH4k0a0l3zUO+O9bFbZ0lr6mltjBHrukCo/UopuLbdznm9ZqqiqdY6ONdgHEdY62C0JZo88IdrlTJpGX8eP8bxs6H7QQ5tNOWZVCE9FSUfPnyom8o0zbjdJnz69OkPEzGtDE9LyW5eJmvA/aZG0yopfC1iNBB3p8xUIJn+SSEqrphSsJRCGptlWXC5vgBA1d0sywKlDWCJbkOTSmo4S9mQPa0oLLTQrs7TXkIrpOGiY8u3QSE8LaSM09DBaAPvC9YcEXOERoZzFgMX2k3rkELG6hcsKxUIhfVnqqg6KdVawSjK0BJzCDp3FC9AFMeElBO0A5x1cEbDWvr+usyk/Qgd6WX8gpwiGtdCgSbdmqewVmsoRnaEgqkyN/JqD9DK5rIghgWrn6u5B5gaYgxQWDcg9L7T8YhSiJLpl4XMEJCgkQFD5VDgyfc1ZxQpngrQdh0eHh+xLgv8OsOvC0rOsDwB7/seA+vvxoHcVCsdJUZEDzhzxId3zxiGAfOyIPpITnaJtGqZdYAAaSS8p8DuvXZOBhfGOhwOB5xODzidTigAfv31d8zzSveSNkipYJ4nvLwAyzKhvbW43a7cZG2DAqJFxlps0EZPlFkyeSCjmZIz2rar51+4WVpTgY9Cn8OcC/q+w7t372GtxesLoR632w1CS845YZon5E+EylH4NRcHnAEmHnNEZ6aYicioZtu2cKyL3AKxUXPGqq4RBVlpmK7B0LWEUmqFnBbMtxtyTmidQWMNWmcw9h2OhwHH4wEAsC5UFNWpMxS8D6AQ7B7dYHGbJly+fGNqIhlM9P2A49MD2o6QvUM5IOUEZw38uuLl9RXOODjT4PnpCdET4n0+v2KZJxx6i9PpUDPrUlqwLAm//forDBsSPTw84enpGc/Pv8DZFta2cM4Ahejl1liM41iLuF9//Q0+RljrcDwecTqd8O7DL3DOQnK/oBTnKJbacGtrMQwNiN5OpsIhBKyhcI4cD2HYoEem/uB19uXlG+sSB0bfqFAzlj7nq1/gg8c033C9XRBjwDAMKFrDxxUpBABkMnS5nHG5XDDPAy6XC243uq+OxwO6rgWQd4V7gWieYwLmZWbzJb6nTyeKnrENXNPA2QbGOBwPJ3z59hXny4V1PBraGjjXEPJ9m2DWgDYEpKIQIq2Hv3z4gOttQuP+E0ExY0NrGubNM5Sm9UgZgxQzmxIZOMM6o3nCMt8oh7BtkGJAXFcYUxDWGX6dEdYJwc8oyaNkMs1BYRMmJVleGm3j0DgLpy0Mo+qm6mUJq7OaMuOE1rZHSFC1TYUbFNpzjN40aIr/vWdGlEIIYM3N2+vXSuFGC7z3oiKmQjvfN3RVmyXNtex7gr4ZBcpBk8T6relSekOE93KBbc8HD1FLZcK0jcPjA+V7WkMmPJfrFa/XCblkxBSARBsRGQSx9rnqVOmxC/8faoQ1N3WMGvJ5s1XjZqC0hbEWUBqZU80L6DlizFiWFSGBGzfKtxzGA8bjEcfjA27Tgsv1Cn++IoaEHBWGfqNWy2DsdrtVNJzW9IRxJLflhvdy+RJkrlKseZ1d1xXzPGNdPfwyIUaPtiX2xzAMGE8HABT/IRT5UgDjLDWhXFu1bUuRKNiaRUEAZZAgUoafx49x/GzofpBDm/0Hf+NXd11XJ/WBEYBlXXbxAbz4ymrO6Nye97/Rg0qdZskhYv69vTqwLXIbb1yBbkdB0mJ1npTnERdJY1tonZCzgWb3b3oNujZ0SpE2a9skUSfDhQVuYq9PP2TNUM6MODRMVSgAN7FAgVHkDNk4i7Zp4EtAiAyHCKWEC2ooVSe+mVGwlMkGvhQQAuaYvloIuYOQ8Mq9u+ayLAhh5YJvrZNzYJukU2O7aXuEgpclhVgoR0Ws7TXIUHqzVq66JcOOfYEoXOu6YJpu1BjBYJ5uWJcFMazIKaBYcTHbNpcSaaqvFHgTUkAeWMtIjYZRCn3bErIzDhgPI4dQCzWFDA5oc9S16NrQJbqWCoJYob4PMu5IPL0U3dYm8G8ah74fcHp4wIf3H5BLwcvLGesa2KSQip2ZN91pJtpo4KmtnHvgvpCTomybYIsJSar/FQMVoVwKAiivsxTKFmwah7bp4PtQ3RaVpvcWmQI3zxMZtXgxP9l0M/vpO7losiOaaHgyUShz2j7V0zTx/SMW7JmNXSg3q2vJfn7sO3a5DOjaBl3rYK0GSkaMlG8o92PXtmiaFl3XQynN4v1E+hZj0bQtXNsgFoqeCJG+XNei7Tq4poHRFg4F79+/w8vLC2WurR6+BDw/PbHm1DHNMOB2XWGtgmK6Kw1hLF5ePuN2m3E5n1FSQdf2KI/irKrR9wParsE0r1XDejweoZTCb7//jni9IcbI10KjGwZYDhk3guJaCjonym9A0wLD2KNpDEIA1jVhuXqEkNncYTMwEj2tXLuUiL4rNOHNQTBgXQ0jB5T9GMIK75fdurmhwSmRMQ0hcjOvqX6jxfPvy3pdJ3pKEB7W+2SiAC/rgs53tOZz3p7WBuM44DAe8O31pRpZDeNAiCvTkWPM0DGiALBNBx/o8922DSybCcVIcQVaK2p4Gc8RNJnuZ0uIvEl8b1N2HBlOaaiikVSheIK4sstlQEqhmlZB9gSIyctmhCKsB0HLatPEgzFTtXW6IuLYzty2JqDUz5wcSgnqsiFh8velEEpbH2+HvOyRu62x27223RpU16PMjAhmwshjlEy0Q9kjpTkruUCr7TVr6aRoVbl//PrC6DHbpkHsNhQrxojrNO8GmbQ2FX4c1PWSHkSaQ3mDWyusajPn7NbA8RsmBpIig9nMg5XCjIdlXYGQUGBQNEWiKK1grIVrHWxgOj4P2JRSaNuOqb6bzk1o2PsBmKxxMoiWgR7du7rWUIH/Vvb0kCm3NqdYJROkw+s5M3UFPKrD7z6DjgaHCcxBYqo+2H12Y3n8PH6s42dD94McwrkvPGijTTlinpe6kEkwtwhzldo2olzStuDzcksGAJI5p6p+h8T0lvUYhW3wI099wQYDfV0EhX4TQqzF6CYUjhX5kw2EdGYGSkVIyKvQLsVGXimFIpOpstv4gPo+yOCBGj0Iusauln5dUbIm0fzutZeckTmbhlz2xCEtEJUVGhq0WZCdMzU5KZAWsfLpFYXNphSQ1eZCljJg8vZehS4quX2bRbG8Jym0SItjnSOqkDVoGouUKJtOYgxkE3LOoWubitrJJiPT4pILNaUlbQXy7cZ5ZRbL6pFzgNZA2xAdLrDeUk621oIbyvRXA5kcLy3Tc1vncDqM0FqjZ/1F13dER8kJMVJQfMkZzpE9+9evX4nu6T2utyvINVPjrlwq2z0vWoYtA4wm6k3T0fkylgYeOTMyp2lwweeM0JaA1a+QiIA96ktFBNG1AEVGDUxfIl3DZsiiuDDqug7jOJJ2NCfcblcUjfpZUkrxJJfMiJZ1hg+emj+1GUrQxk7TYgBsREG6TnE5BVCz5kqhQGBp+LfinWjGzjn4daXhAL8NxYVqTgkpeqTokBQNPowhRPl4HPBwHOCsxbJM8H7Bt69fobXB0I/o+wFiQGOsQdN2tb4NkajGx+MR1jrcpgk+ELJ6m26sdSnVJGYYOoQwULMwrfDzipeXFzRMMez6DkoVzJdveHl5AdFN1/qZfzgd0fkWMZBxzOu3r4y4PeJ4eASQmdok2izUQcf7d+9xOJwooNgRNVRrU7MStTaUd5kzjG2qCyW0xrJEzLOHaObapoGPK99fpDPKuWBZPBtTbcMCabLbtq3Nu2jt9mgAreErhL4u6yXRiTNCCljDijWssNEig3IHoTWLJRUjKaxRBRurSFQKDyBSTvDB18eKMRFaahuYlgZVgmwqpdCwm6msNTFllEAOtt0Qeb0gvU/ORK8PMUEiUYwysA1R+SNTu42xvFYvdW2lPMQCDWpIrFYozmCZVwS/IIQF0RNiWVkjOdXcUcrvY1q9MlUzV0qhLkFtGZsaW8G+p9TJPqOwa1a4cRH06S2rZT/8qQNQpevj1ueQB6+PsTVnb9G57bEKhBa5NyCpj3d3CIsho5DH1R+cXuVJ5HEVRGNLUQTWGnQdUcUTNx72fEZkWqtsXkrLuZV9WL95JeDNWs4Zvfeq+Vbi+Eoado4bpcw7XiOp4dvl4hqHkIkhcLlekQppNGlwGWG0hnUObUOUxtUaKK3hV49cPA80WEPJVFylScbgQ0TKEw0z+f2RAzTR/VPOyN4DihD7krbPr9QxMpimWCR+w2XnCls2A7h5muudFiN9Xvuh46aRqNg0TP2poftRjp8N3Q9yFNkJeDGWadP1NtXNYppmeO837rp0f0B1eJQHeCu6LkUoBWxTrCO83ybMspEIlWgY+koJFDEvRRkIXSHyVDntNhNxaCNNhuIsGymsjdoMPrRWiF62t21xVDxxq4VsKRtVMpP+KmXiteekkaKnhZc3spITYvAAClIOSCHR5C3GmhmjFFjTZmEcvZYlrdRAZs5LM6pSZei8yMa9m/JWOo2p4n0xc5GfEdiSOYSYQuC1sbCO9EY6aXaxY9oiI6hdSyHd4l4oFuX1UBstFhDKFeXqKDi2FeecJcOua4WRHK3ZblkQSjY1UBrODChti9R3SMmja1ucDgcoFDTOUd6TsyiFsngk2FWhQLkGKSa8vr4CjPKsy0xFNwd6y5RcKaI2WWvRlIaaGch0XSbwFqWQvs2HyGhe5FdM6LIEt6YdbUVr2iS1Jv2kknuTN2QxWilM+RSUATA8fSZ66fPzMxvBBFwuF2RGwaS4W5YF1+sVzm10ysxIsdRl8vkRZ0/5okI6MxJekPNaP0ui+XDWcjYaobQNF+E5JYS4Isa1IswoGTl6BG/gV42SLGLwUCWjaRocxh4PpyOGvsXqVyzLzM6MmjOAN+2H0hpdN0ApjZAIRTWWKERQ7CaryDTEc1C3WG87vkf6voX3I0oq8KvH5XymYUDbonENnDFYri+4Xq/wYYI1gNHkyDmOA9q2YepiwjxN+PLlM1AUWteR1kuxYcyueNZa43A8oOvFAIiKvVxAdHbsES66QERXdsgA5mVBCNL46WpxnmLi+7NUarkxug6eBKEn+m5g1GuB0Ko0N0FQ4EgNv1Ho6r1L5h2Bg8N98GhTi4JCDqM8eIKitT6kCANqTsGMAQA1dFoaOvlC8shNB0CRXlUpHA4HlMKNOH9eJGKAUA4y6SI6ruXPKw1MlmXG6iNdy6ZF4wzvOaJxo3y4GCL8GgD4SndGIRMu5ERNndG1kaNmjgxRshiicAGMTMZWgk4boVMzil2UQskKMCBNnbp3tiw5IytGsBS4iWN6f97RHfdr7I6it3cgJat/1L1v+xPeyTYIa/s3I1zSRFZ9e+Fhmhzl3qTl7VFpn+z08rahqzpc+g41KKCoFFWY9lfR5VzjjoyKiBVtY907ry0yAPv+66GejKoPef/0+JlZGLkowBhCFbXeGjlVwyMgCHeK1MQty4pc6OdaGcRIA03rLGdM9vXznDNlZWZGlWV4UxlMuVBEAefdKqWhDJk6dX0PAFjWtSJtxhgECSPf1TciL0hlY80Aon+3MFayfBWWhaQBcl20pkaa1oi1Xp+fLpc/zvGzoftBjorqgBE6Nm/4/PlzXRxjIpoTWdjfw/YyEaPCxjCCty0m1MSRcYc0cNuCRIcUkl3X1QDmUgo7qCVcLpf6XHvEaD8BJZMWXZE7mVBuVvBbQyeUOaBwGCobp0gGTaWbJZ6CcbhvId2U56F1RQhRyL0vZah1oQ0pozaeRWcUneEaomOSqUUDYy0u6sIUny3/yxoD61pGiIT7Lpb6kuFE70OMQ6hQ5/doNHQmq/6cqBnYn2fRoCkumkIgtEvCqbuuY4pcqY3BJuAGYkh8rQ3IuIZRWpVoes2U1FIK1jABxsFZ0TTQlBFZEElqcod+hLOWdXOlmriUEmtxpNTmhFli3JpgBQCZLMkphwGWc4IMo8FE0yKn1ZZpfLkMuF4mprGUilas3iO9EsVymik0+uX8WvV2gnC1bYNcbKWu3WvncqUjl5zruQcUgg9VD9U0LbQWpFCj73s8PT1RHloM+N//+28oJd593uZ5xrdv36C1xu021WtDmXnq7j7fT/sBMKJL2gulyARH7g3HE2hnLcKyQIT9lPX3Hk/Pj/j86Xd8/PhbLVpzCvAeUEjIyUMrhcv5FUZrdK1F33Y4HY949/xI9xk7K1Jcl0KMHufzGdM0U5i7bdAPI7tmFizrgshj+MPhgGEcEWLEtMyMUFLQtXMWy0ph08MwIMeMHDO+ffnKA5mIwzCgcRZN2wCXgnVecPUTtC7ohwbDQBbmbesQY0YItPZYZaGKxjgcoJ5VbUCEYhV5uLAGit2gwt9R4K/ta6Ela+JGy83Q1qLrGrSt5biUjOBpvU2ZEC8ppEnzuemkqpECfz6lqZPnMeysq9n0hJp7DpsvYOSB6Wdlo7nL/bBHPOT5ZL+g/27I00aNQz0vIQQEH1GKglYWM2bEmHA8HdH1HVbvMd1umJeFc7lK/Yx7zosbx6YOI7QmI5foA7NDyPW1LMQPadoOfdejHwaczxes64LgKRMRSiFFj4gEr8lOX6FwE7fSV/SENCdyRRWHS6DUEPAtpoPoiuQMzHwDRc3D/pA1RR5D1Z221KEhofpb3MT36JTyWN/bP+vfvEHo6r93z/r2se6eoe6b92sH/b4g//R+lMp1fbijWO4GZ0R3VzCFDH4s56SiAKEL6Ja2fk/RckADN9nnyx/pqPcHs0XefB6U1kiZmjOliF1gmxZFGaoRoCgXN1BuqlUWnbXo26Z+7gGFFDMSJPeSjJ1iDJVev88glHMtkhE5L/vMV6lxAGJiHA6Hu/qGqLa6/r0CSUwo5qYg5sz6bXZdthZdT6Hi/TCwNjxQrBCfOokI6bquflalLvlJvfxxjp8N3Q9yhJiIMaKYRFJII3WbF3YELHVaJNQmKFU39senZxyPJ6IzQcGHgI8fP2JdCYEw2gLIqAHNuyn1fuPKOWNdV7y+vtbn2aIPhCK0ZYvt3ZuIutNUfZMUx/Ic67piXRecz2fQRJqoCeLu2HUNuuYBKXpcLhcKeA6hho4rRc6UGUAOESVmFqarmkNET0bulHnXBJacUYwGtEEoCboUIEfkSA1dTh5WK3SNI4DOWAxDj6bpqblYViit0fcdrLNkDCIuVmwCERSjXZoMU4xS0M7Bak26rhSxLjNSDFjmCa98bqVhFo2g0FyIirVdk2lmhLa+JwpuZaYaRCDetgNHNLhtKgxNTVtj8fB4xOF4QtM4crhcF8QYYa3B8+MDWsdOl5EsxjMKjuMJbePYJEZhup1xOSumvhIMG/2KnBKUdtDGEW1FkNWSYW2Doe+J4sP0u/fvP+Dx+Rn/79/+A19fXnC5XGmiXBTIln3BvKw4X29871E0hhisWGvZmVPy/wJKEYdV1qWVLY/OuRbH4xHDMMJog48fP23It2gqNPD16xfcbje4poF1tt6/BLTMewAAIABJREFUFdHQ+g4xFXSO0Bixqyf0R5o6Ka4PhwOGYWDb/BuWZYVWGn/9y1/QNC0VwJwT1Vhb89HaxkErcnxcbme8WNJmxRjQOmrQc/KYrkTJPB46uk/7DiV7TLcz1oODNgp96+AOA4yla1X4fNMso+DTp0+w7hUPj0/ohxEIGpGblpU6R7Rdhz/96T3p1ZaFNYQ3PJxOUGyYMQwD2qbFMk84v5zx5dOMh8NIAed9j+Uwwq83XC9fsS43vL5kPL87kVZzPGDoLQDNJkYF18srPv7+K3JO+PNf/5XdfjNfW4d3795j8R6324Tz+Yx1fYV+dRjGAf0wYhhGFAB9Z3E6jbheV1yvN1jnYBsHYxTalvR1X75OlTpJ55k+o7cbFX6CtMYYcTwe4b3H3//+d+RM+p13756Zmhgw9B3arqV1T9FXiJ6Rn4QUJCvLwrkWh8MJp4dHQiBA4cyaHXChaR/IKIzESFNFlfjleqP1ShmkXDDNC+bbgpue4cwZx8MRh8MRxll0fY/xcCAt4jQhvrzgeps4Ky7CJIdlmVFKQddFdN3IcQcd/v3f/xfbzg94//4Dum5gKqhCNAbXa8Q8XdlkidYtbRQaq6GQ4OcbUvQIfsXl5Qty9MhpRfQLUljg1wnJL8iRkGZtAOfIwdVoGmQYRUZThnVyhtEoJZOSXNXlyIVNRpRm9GlrVGgwou8ag7dDNDlkL0xpG6iKptgaQ3sNBMnfMT0K6l4kQ9WtCSt1zVIKNXtOBnJ792kaDMmar+r+u71uIGui/tHAj4Z4RSk4l3HzASlndK2DMXTtX15eYV7PKOVCrIAijtP8ptVGFy2lsDs1Py9nW5IkgRlA1qGxsv9kJBDy1bQttKW8OR8ylqRRlMHp4RHH0xPG4xHn64JpXpDyVjd0HaFoKSYkHRFtxG+//QbR/odAr7XrBgzDgL7v2LRIkQkTOxvTYMQwLVLB+4jLhYyj1tXzoC0hRWI26BIRAyF3NDAklpPShRkbGm3X4fn5Hbp+QNN3mOcVKd1gbMMutXPV1lKk0UwUba4npp/93A9z/GzofpBjEz3LsVHPstqyrypvWzEFh6c9TUOhmcMwEPVhngHsQnC1ooW+bgzbZrCfONLf5Lr4iY5HGreqM3rz9/T7lu2qAeBNcDbTgkQYX0qBMzJtJceyoe8xdC2Ct1iXhUNi2VAEPPks1DQZFlsLxadOW+vZA8RYWfH7F3SpZNISStO0IY6C7hCiJNz5mHI1QkDfViWEUKqIIpo2rYLe9FOCUCoeYEbWhuw3R8k2qxz8lGuDII+zcMEsYm865xRhIawhw3qWqAOySogqbMiQaVAUoIMh2g03rzk6oJBYXRziUk5IMcCvCyEvpSClBikZojBqw/fgpkuRvLrCtFJlqbhJOiHmjBwTsspQVmhSEoyOipjJl+gU5D4vjFooRcOMXCjPTpUtoF70dNvgYZuC5iLGL4anpC3R+poO87wQXYczwhRXJvM843K5ou1aKkK05uu0mQDR9ct1s9/nGVV0kJs7eZ3yRaYr9DkpBXCNw9PjE9q2xfl6we12wzxTIUDFKpBiwO16QYoLlmWu913OEQp2o1+ymc3T4wkPxxP6vmVnQIVpurJpUMNUKsC5js10NKPrCatPNGUOAY6RFcMUUNGJFgDH00DGBRwSH2OsBa2gU9ZYDOOIZZqxThPmZeEhDWkxySWzQQwzQlhxvV6gFEjD2fZonMXhMADFgOjNHufXV/zy31KNxKgUSmfRMkq6LNQYk+Odh2FKaQHQdWQQo/SG3pQQkRJptKBKpfrJepg490oCguWeSSmj6xus68pxCIZpyexiFwJSu8VyVJQrRQhrYfWBDVsc2q6DNgZN0/K6mVgLqCst1jWBC0ppGrb1NjKqSFQxdhJMkbI3I7m4Bs7iAlCz91qmxE7zUveiUhhtUZrOX47o+o71dxHrSnvMxBrMUvcPop/HGDaUjZEv07RAJsv2sC6YpxtCWIEUUHLcvhIjc4UMpYiyryrCxqtFZQ4Ytf1b6N2oe4NsEUpYj3eomOh5v6+X+05I+Jtmqw4v1dYo7vdKeQH7x5TH2e/7NLTdBqSCtO2R14reafXm8XcU0MJ7o2I6pmZHSGtgJXdO3i+j//O6Mkob+fpkRgs17533Ta3WijJgd6+zrnfMUFClgCVldBX48YglAhAHVtG97xy0sZS3KTl0hS6WtZbu9911maZNjiLNp3OWs2H76kJL97nsLdugDyh1TxXaJum36YJ0rYMvdC9uiOmeTsvnkIPtiVnFLtkpo+27qp2WOKZlWeqQiHT0Dm8u4c/jH/j42dD9QMfeMVJoNo4LAVlwSt4szMXNSor+yFN9yRrbF6B7vr5o3WRTeUsd2SN3UogKugBsImyhNuwt1Enzo4kmXxs/+rc1FjAGpVhw5wKUBOcsDgeyLndWQyGTS5ZRUIqKoiKsPqUYBWOdBBe7W2Gf797rno6x35T3v/+2oRVdBgmsWV9IvQVl7sFjnmmRtpYMPNZ1re9Tzl2MG+1KXhdpQUrVHdH7LFhXX5uCEANi8ndW2WKnvF2zwgYobL2uJHNNI0aPnEpFzhQ0bNNBR4dUEi5nS8HF8UhFKzvP5Vww3a5EgUoRIXrklGBUwflygejtmqZByQHLMmNZqdE0MtnWGSrT7u2shVaGrZ3J6GAtFFdBlKGC8ytlm317eUFYyXxDaUO5VQDnMqJSMa0x6JuGzgfTEUm/mO6oxN5TyDVYC9K2lEHU96TPcs7BOtpQxSlRJvGycRN6QllbljWAZPYD/hzoitCsKzXgXdezWceOgswFyb6YCyHW7/d9j74lmnPX92xGgEojlEEDFdALfv/9VrVYmYvgFAsVR4YakqZxeH56xId373A6HdH3DVL0+Pb5d+RERkHrssC6FjGCDWhaWMf29p0DlEKICa/nc6UuUtFFdNPbMuPLlxdqyNhkIYSAaabpc9NYIBPteRgGlKcnNNZhvl0wzTd4f0bXOjTO4TAeoJGwrAqX60ulEp6OGWak92NtC2c7AKLhJb0bsNELcyYTEWstnp6eMI4HzOta1w6Z1BPToUOIdA2U1tyMFCwLNUshbo2chIHT+sr3WqZ7wDrDIcbU4LVtj3EcmKJFqJQMeYyh2Bh5zVprWNdguk5AA9I7Hg4U/8KNKdG6aBDRdR05X/JaQQHqhe/PwvelhTGp0swUD0WU0TDGoRSKZJjnmRoQHrAopajxZre/VRE1eFkWdhSkz3jjHE6nI96/e4fbNGGeF3z79pWQz4F0TbaxHMcCECU0ktYZGsiOddE0OEphBbhxAztblhx5n9qiOe5cK5mijzfFsPqOFG5/3DdT3/+d/RpOa+3GNPljU/fHx7+fzJZ6j9L87974BNjeguKp394s6u372//V1mRQEymDRqUVNBv7aG7kmKQBo2h4aokORNpSBbRtQzRvx7rdsplU4Q1yua1jXDvk++5YqT+GZdfXmSlPDiXS56uQU++0LMDlAp8KJo4MKKCsQcNRGEKjlgZuT0Her61C+RTWiwxg9tdyr33c2BuOaOL8eG1jsegMhUSDiZLgwwq1OtYMExqcC+3fMReoNdSw805tGan7gb2sATk1kJion8ePcfxs6H6UQ4A3yEKueJq1R8PK5nqmaJsTt0txxIy8iBF9ICIXycUhYTGshYh775sffhlqa0DkeaUwFXfN+pLZkVAWJJnkubaVN0OHIFm1WCZNSY6ZaV4cBhoCSiInuBDIyETE8FC8uBsDazX3gnHb9AQB4acTjXvh1yWvWzY58BR3e98Uyiybkd7lFlFjyGYaCrsNQ7K76NpQIbXTrXEDJkheLoUbxAxdNAzuraAlCoGC0MNdwVD4b+s1wdawWp7saxFjzysiG3Eo1rI1pUClgJgDX+PEOjm6f8T+mYxvEhewnvUoig1byIq9Y2qaNFJ1syxEo1Va1c2xQEFPMxXFiXMGOWQ+ZeByuSDmhNv1RmYx1lXRvAQUA6pat5PFvaqmKeLAKk2PtS2UAiEHnl0wY2FHVzq/VJhTHhw5S94XBNQsUHGffABU5PgQySuSifxGedwcSjcEnCb1CcY4FvDT/U8mKWx1zaijxEnwN980hHy+UkTwBd9evxFqwQgdSsSyBBhdYI3C0LfQyqFrHbq+wTh0OIw9YrCYzkSnLfw+YiT9lPcBro1ouoy26zAORyhjMS8r6aqUgkupIjlFAWvwuF4pd48ylwgdWf1azU9KQqUTjocRVmsgBwQ/43K5oOQO1lJERck9oCKmSSOniHm6EepSFMbjA6yhOBIoyrVa/QptHJQydQhG165U9ME5RygCB4ILqhVCwuU618+X6LuoWFQbKpdFnxcQ2NFVtLIpZijdoHMNLhfRUKIGGF+vF/os2KZqepQiveYWE0OFpLG2RtE0TQNAsU6P7n/KJe3YNj1BKYMQPA1XSuaA+1KHOjLUkLWPqJmkr86FDCKulwvFTTCFWGuNvusw9EOlEy7Lur3fJCZYCqfjAc/PTyjYqPS32xVQwDAuaENDlNCcGK1jw4qsECw51qZAWrkYfUXiIMhcZm1uybWZ00KvNxKqXXee72ylO11aBehonxO0q+z+slSCgEAwwmr5/0Pp7pu6uobwRkP/f9Pi/ZedJu8B9bHuIaDv/4nCXZC6vBnFAzxobuKVQXUC4xPmnIORpjbR8JKGBW3V2MeUiLGhNATl2+v05P3+oZlk5JB+npk9Unj4zPspEnImnTw0lbghJiyrB8zK6Byfb2NgrIV1trKGpEYpyHdNsvTyVS8H1sJycLcMesi4ydXheN3DFDn8mmL4PFnE1bJmr7CWn1gfZJaDik5GNkqBTthip0z9kv1BBlX6rtnbZSP+PP6hj58N3Q9zEBddmi8AvFl63gcK0Sa0hmubujEJXW9dfN3QqWiNldKmDFMarIaCq9ShbTGLeLuX0EZGZhibXmCb1O0RL/m3oIrj8cSLF6Mn7FYGmawqJexJMlxYFuSYMDUWRivSVFwvmGfSm2kFOEsUpLZt0HYtbtdXLHOsiyd5t1OTC62hK/efqRC7jdk5mqyJ05biwo+MTMTIYstRk3wvMgUg6p0UKjmbmq/VdR2cs5S95deqjSsoFFarVW2mZdOhYGPDBVeum7I0GXzl68WRTYvQK9IsNq6hEHNuApaZHBOj9wA3/doY0qIEzQVSwcg6A6KA0fsm9EHoZQHWaBhta66aZwfRxpL2B1pBW1sLVoBc9IZhwOl0gtia++CRF48YMkjbQ/bS1+sV87pgWVaMo0XTtNT4FgnYpsfNkSiaOQlljRz3QpDhRKqU46ZxWNYZtxtRF1dGEa/Xa0W353mBcw0u1xvmaYZnp1FADEpkmkwaLdHIyGeDGnjDqAzrWthNNKa45UIVhb7v8P79+2oq8eXLV3z+9AUpiV4SWBfSrXrvMbHGgug6RJsCxByHXNZQErmWIgGgHDStMrlFqgOGziHngOAXrKuDNQVGFTycDiAknb5CyJjXGWme4JoFbllwPD3g+PBMTUIBITgFRCfkxkwm2b9//IhlXdGvK6wjtNovK0rbwjmHWBKyos9d4xzsQSFFykY8v37G9XZF4xS6RqNpHUI0eHp8pAbKr7ikDD979MOIzM3zeOgxjAdcrzd0/YC27dG2dP8v6wrvI6HC64qUM1zTom87QBHiSkHtFDVQm/icYZum0rTqECZt0RwxeMQUkLMYsCS4hq4pRb+wCx8bHoUQ0Q89+q6DNVvTaS01YTLwcU2DYSAzIronFBkGOVc/i3a1cM5QBMXhhK7rscwzOXSWhL4PzBigoYhopaWho4KXqeCFCujz9Yp+HIniqSksfuzJzKRAXEINppkiKqxdCBEswOFwwNPTIw1H1hUhUAOec0LTOF56FaL3iCHUfSCWAo0MVSheJoQVOQZq5L5Lt8wbZd5QzIzhfUQDpK0stPxLT3a/aO6OIk3dZue/75fKbji4/6Ncyt6DchtMYjMF2369vHnuwo3Vfnj4xybtLXvkbbP4x+OecrlvtFS97gTLyaunO7rAGYMCVUdPyWQysekX9F1XXYWlmZNgcWECbc/1pvHU20C65IScFHJRqAk7IEORUhKKAlKhYaHSEj9C+5voj5VQjBseeKQMa7emMsRNupALB3aUDB+JnZESDWRyYpfehhwtJVMuhEBDB9ZJpiz5n3RvpJwQecAqXzQUYbdqPjdQimNxiH0jr1sCxmnwR68jcBSLDO9KKT+DxX+g42dD94Mcks/21tHsbnjDk2YlhUnO0Jomvav3pE0pG41QG8pT0cYCWsM1HfqWnKHW1e9y7WTToa+cQbS9OwqoQtcN1d1Nnl+0c9Y6NG2Dtm3xyy9/xm1eME0zbfIpQAw/6G2xDo6L4pwiptsV860gRc/OagvCukABcM5wAaoRk4JLEiZLehpBD9u2JZF+1/FiarigX5kSycYtXCzJwm6MwTAMtakD2GV0XdmhS0GCpikkOFXuPb2fjNPpxM1EU4OBl3XihV6haQmlOR6PtZibpomDp+ddgwy2RN826iL/3V3blBKSp4mh2PkTizXh/O0r1mUh2hZfv24dkEqBthatM7BqQO80lM5QiLAKpM1pB4QYcLvpinzlUqjosxbGOSBnLH5BiptznWKKJPhcie2+sUTlaaxDNAkpFna8JOfPZV4QbwVt2xNSYDWSZwfGQqgfaRpJ2J9KwbSusFrDGm4qQbS5w+GAd++eMR5G+HXBt5dv+PLlE15eUo0OkGvjXEN6qlKQ4kYZpqGIPCe7gRoyoLHWVCRNUAvRUXU9oS7zPFf6DjUZGsPQ409/+gV9P6BpOsSY8duvvzOCwlQ8rfDlyxdAASubj+ScOaswIsYV4izaOAcUTYiG0kDR8LczGU44h9NxxLunRzhjMF0vWKcLtAaMAsauQd+TkUXXD1DaYY2FNHMhwceEy+WM6/R/wzYtnp7f4Xg6ISuFj58+IV4uWNYV42HA0/MRPqyYlxmfv3xC0zQYhh6uccgl4zZPUFlBFSrCidpbcBhHtE7DL694ffmM88sFr8WjbQyOhx6pUSi5BTAihIh1Cfj3//Fv+PDhv+GXX/6Mmde/5z89QWsyJlnXtU7AlaYpvNYa3ntcrle8nl9xOB7x9PQOrmnw8nLGy5cvuFwupLHRGu8/fMDDwwOtC9zAr56C4Re/QnRDVXcDMjehCX7kNYWQWDJy6PD0+ITD4VDNNaxxOBxGWldx44m9xuPTM3LM8KuHUooNmVqykzeWsioTUUydIw2e96LhS+jaESHysKXp4Cwhdk3ToG06GNNAKwPJ2CuFjHzWdWWtYYDWBm3Xou8JCTwej1jWFR8/fcH5fCXtrwL6fsThMGAYWjw/P/I9mvHxI53PZV3gPn1E05BWVWsNiX6MIeDb9QUlRoCp3qok5OCR40qInZ8R/YKSAnTJ0BpwxqCxDm1j0TTkwoucoSFOjmC6ZblrqjYU777p2R+CKomeTEnAYylAYqMqs3do5oEmtv3xvrHaJAtivkF6OB46lk3KIIcgNgCwI8H8AZ+7H7xuuty9UZmR9csYUHbchjjHmGAdN/YclZNjwPEw1ggYKAUfItawacplmKj2r7OiTAZ3TShTepVSgLawxiArw6czwTgH41o44wA3QGmLojRiydApA9pCmYScMnwIzGyhDNWw+vrc1uk6kJS9Udb5NW/GM7Jvt12Hh4cHOOd2WjaJFMr1cy1fWgNhPiP6GaVkWGswDiPevX8HY9iBN2askSJ1rDMwlppPax2IXJS3L2btUENHjr+5xHq//Dz+8Y+fDd0PcihteLGnL5nyDsMAoQv6EODZSS7vB4EyMZRFl3VHYrlbWG8VY0Qymqe+CTHmKuKF0nWTqCyO7QmwUUK2H+bMDDGIMJjoBaWQ1kwWVKUISSJUjt0bcwE4HLgoQPHkLvJiJ42IiLFLKYisO6K8uFxfz8ZUo8me40m7NZbCvtmAwxiacLcdIVPOOtaycYaMobynzNozQDZaUxtErUhzohhipOl+4aaKpm9CwZP3IMJ9Ywz6nrQo1thK+ZjnGTkx1Q64a+BK4bBg3gxFSybnd11XBE/as5Lp++syI3jKcZLrlmMAtIJRBs4otNagsYIMFp6ocoGFzfEtiemHUImUpsgknjhH1sLUAgKiz5lwPl/gXINpmmpByxhqHRJQIUaFUW2UuUHXxtHEV2vWGlpo6+g+jgGJtURbFAGJ3NdloaBv1pESakIZc5InWJjeqtQm4OcbG/LJUkroufSeoAoMiFIr96Sgs4fjANLGhVooAIA4lM7zxEgJR1zkbVKj+B4jinSm+zyX+rkqyOx0S6/ZsnYvpQStMqAyrFFoGoe+63AYBxzGAV3bMG2NaMupZEw3soeXtcQ1HWw7om1bGFfgUoGPCfMaEXJGN8+wTYOm69D3PQ2BQoCaZlin0bQNQgxYlqnST5/ePdchi1UWVlHAd1gLIgJTizPTBwdy4JyItqdUQttoMkuqxTNN8GMMePn2FbaZ0LQTnj78E5Sh+0MozrdpQtN0aNoWDa8DSwjwU6imJc57XK9XXK8XXC705doW3nuOJBAtKlv+x1ALZucIESOElpAiGmrRPdi2Tf3eMAyMtDVQSleKtmLExFpyF82MnvENx3o+RQiE0tSoNy0KGnouTQ1Iq4galhJlM9pAr61tOpRS0PkVzjVo2g5t2/Nn2mwaaC3sBaJnFtCQjyI8CAFvCw3IbpyHKve+s46bRQffNMi5oO/JbCXmSOyETAhm6xyhi0YhKmCdLoRsBw8NcirOKdTmInOgONikyCgyzjKsRayRN4oRum1X2h3SVEkH9H3y4taIvPnrcm9csmejbA0d7n6+PSv2m2el+aq7XwDum7rNPOy/PgTBu/+uNAyCoOlcUPS2hglCKK8rF9I4J84RTYl07F1LzXw3dWicw+ppHSpqp/v7A5K4vaatPuDnZp24Mo5cM/l3jTFk8uM6FNMiQyPmUmsa0jOzaVbech5lv5XntcYya6flPZFzSvN9I13pnikjcKTJPC9YF9ofZO8nOmUhZkOIUCATN6ktyFG5ISMTbUEaXl6bdRFwr94/FGUS6/pgTAPn2DU8bVm1b7MMfx7/uMfPhu4HOTRPnVUhRMe0BuMw4M9//Sstikrhcr7g9XzBy8trXdXlfyvtcfsmpNlJuSAmz8UzNRx+9fBrqI5oEiy90Tx2PmJCh+AoAKjCBSb9DY0UZRIILMvK6B/Z2JOVfgfwJHFdZ0KLmJ4EQxNcCpH1SMagZAM4smnXAFP+yMwhBo/GOZ4Akl4AhQOzjalaLGst0ahYEyCLf98PVbNCPaxiCgg1RIUnmSllblSpoCB9fwaH21ETxJvpuizIOVajjMDOWXsGjyoFzhB6oAAkNtNQgrwBvOGWOi0VithmUU5HyaSp897TRpdRA9iDX5EjOZVVzWLJsNqgtRqtM2gdNXQxJSRuFGIENJvqSN6e6G8Co3UpJximPymtqvYRSqHTdqPQ8hDB2gbek4FKTIWCYkupjZpVRH3NmaaxkamxUBotI2JakzV0P4w4jEfMy4TL+YzzMqPkDOcs0x8TB3zPmJcJ0zSxQx8V4orv8U3bIM0Cc4IAAFSskxZOtKcay7zSlNaxoQ9dhYpKvf/wDqXkSuuUI6WE6/WKb9++YZ5XdN3AIeX5rkAkVJbuPwVyHJWBRmFNjM4KCWzGEjNi8IQmMkrUtQ7jQFEFh3HA0HdsmpKgQL8/Xc+YpgJzvcA4QuqeP/wF/XBE17TQxmHxAbFM8JFQtqIUHozB6XTCsix4eX3F5XpDLhmHw1jzKud5Jgv/h9NWrFq1hZLnhBQUGbKsK6y1OJ1OcBZIacX1OuN2fcUvHx6hG0JPnXXo2h5PDw7n8w2///4brG3RtAP+5f/4P2Fdw5RHQuq/ff2Grh9wenjAge34PZtFeR/w8vICpTVeXmkdvd1umKYJIzdw67pWdC94stSXAQ2h9JaogJB7SnHkBzVzkm8FAONIjbIwL3K29TMNgAdFBTkVxMBOs4YonEWpLVhZaTTdiKZxd5of29A9nHJEURo2EJ2+aVsUpTDI6+oH9ONAjO5SNs2cIXfZlEttWud5huT3AahDqLZtKxKjlSadYNthdSusXpBQMA4DoIDL7Yp5WRFCJp2fNWhcC6s1kjW4nQ1ioczQggwYIKVAa38M1ehHrP+1oa9KtVRboa4Ua8mEdlnwxhilbHulum/O1G6f3B+V6i4Nnb5v5GpDjPusujs92+7v7w9VB1p3P79neX6/+3zzOPvn2DIwE5ROUNn8F3/GA8FSeI+jPcwZYlIMXY++ndC6Bucy0T6PtP39Tl5xj0zyw2/9cx20GesQiyK0UNF60LQtrOuQdAufChvhAAqas9poL4ohkhtqCOxkqrm5N7C2Qdf2GIYe4uR6vlwJhc7YIYcGOZG51e02AQDmaaL8R2N58GNhtEXOgF8DDbm58aXBDTd0zrIhynb+iTWzDePp/0f4EGiwmhOj9xbWaISwImCj7Vv7X1yrn8c/3PGzoftBju+5MJJRh91+psVWfmeFDkA42dQUyLSXm61CxT8t4BFLKcisoatGJxD9GwVaC0iR9D6HRnR0uxddeNHkjS0ENmHRN8ysq9CgSfQ4EIJBmqMIz5SDlBRKioh+06akGGkyljM3aAooqn6vpIxs8m6jVtUVUVAe0ooUpmY4tKVUN0NpkAHU0FQ6H1ugLCEgGVlxURE1stoiF6SwknO4+hUhbhbF0ujIOVu5uXt9fUXDLo3LMpPJAm9mANNxtKpW/pkbtxATUvQbXYcbn8jnShpRTjGnpsBsRYizlHkzHg7o2wbOEGVIa6BkxdqsgjlPFHa8s+CXayuy87bt0RxGBO+hXjSmm9hCA0LvITrYBKN9pczQTxUPEGQyrmEtZaBtZjyKCwJDb4eHB9Y6HI5HGKsR1hVXpZDrZ6ZUwwqognVdsK4LF+PHQBZyAAAgAElEQVT3eYikTyRhPsC5TWWjxuw3Z21cLQwScZEZKSCdSts6jOOA0/GIAjIHuV6v9b3IdPn19RXL4tE0C9ltA1wY0EHmLKWignIfyvc2s50MtWso5f2IVX7jyLCmgD7nCgXaKFjt0FgDozLpBRMNIWLM0PYbfMjo+hFtP8Aai4eHJ0QOL06JqKTd0KPrOnTrwnQ9j/EwQjM6JeG8l8ulGnjQ+c3wO7dP0ZYUSHyDQ9s28N4hJ4PX11d0fYuhHzAMFPitlUPbRvRdgI8F0zzh08ePSBk4PRDqJPb7IQRC4pxD15N9+cPDI27ThNttgg8BX798xbdvrxV500ylJoSKIgIy0xlTJlqU5lgWMmtQVTNYkKpbqqAFRJsc6H0WKdzIxGfL9ZQBA+p9r6sRBf1X9MuklQaUMjBW2APELlCZBmnSNDrX1HXIGApRPh5PtH7uckidc/UelPVQqL6lUDOmFNHRj0fPLA9y4e37Dn/605+gtK6DFGsNRg6cD0xJ9usCZzRS6+BMg6ax6FqHEi1K1Bw9khmdi0TPT+R0qXcIhjGEVN7pypTiLNP7o5oL8e/s/uAPiNKGzt13UNUsDBtb4e0XvvPce4S/vpa7V4C7fevt7xDKU7gP/X64uez7dRXgtUaaupwyss71ntr/nRFDtVIgj7JvvkSy0Pcd9CuvQTJs5EPuH3l9++HU3VkoVI1AyXD4/r0qrervkUMyrQ2UFalgOL9QDNKkTpH1USiSwjiiPTdun+k38hW6Hz2jZ6R9bhpaN+gzT2614m5ccoLh1y+fQ+8DlnkGlEEMW1xFHRDvrmlguqiSAUjfQSsystobb1UfgJ/HP/zxs6H7QY499C7/FU64NHpCWyu0e98VfXvXygwAilwhq2U1FE3kPNECydiDigTDlEPHAmRaOE1tWrYcJkEv9hNLU19rygk+ACFuLpptQ45SwzjSQsoOljEEBB8Bn8nOfplRMoV4Ru9pYlci0QR1A4WCxO0qtGIEa9MjVFpmjNWMZK9J7Pu+FpO1masFfKmb4dtzWnmwQC1y6vsV57ecYLyq35PzRtdxo6sIiiDOdDEGzMtMz72T3QsipY1BToQWYl3I+j9t01JVtriKFBLHQFBGn2EnOKMNLIdSH8cDHk4nDG0Lo0EbliYKZUpAjAFLWKoWDpyDSNSzWCki/TDg3dMTnwsuJmJkyphi6go1MiQc58ITVKhKvpHQvrQxnBXHlB0uZpQ2FCAPaq4VgKHvoVAwdVdoa4FEv1vPQ0qAosgIQVY2eqWq15GuMbiYJpRka9BJR6dURqstR1PQayTdpGVgWPFGPWAYRwhiR26LEhRPVMDX11c4t8By2GzNmBRUNZEBhFCthfKXUoKxhunB1LgWQduVYroqmfY4a3kgIyj8CmcVnDVsKtTheOhxu11xu8243kjDGfIX3OYVx9MTjgUYDw949+49lLY4ny+43m643SacHh/Qti3GcQQUmaRIQdMwona73fDt2zc8Pz9jHMd6jy7ThMYROl3aFjkFXF4zFOt92rZFTgOMLvj1P/4fKn7eK/RDT8hUAIVzNy2+vpzxep7wH//xdyht0bRd1cAOw4DbNOF6vSKEgGEY8P6XX/Du3TOU1nh9PeN6ueDLly94eb0wYt9zs0X3rGhwiU7NDqqGo1g0avFK03oq7KWZa5qmriPDMEDCyJ1zcM7VTLwQQnVqNdZgXTykGdgoXg5iaEK/Tw2lNa5Sh0X/5SyhuoX1pPJZkoY5Z6KPZR4cyDq0GVoZaJ13mVyZUVSH8fiInIHL5Yrr9Qa/rhiGHv/0z38FFOBXj2maoLXG0LZY/AofPeZ5xrrMsAoIbYOGcyCHrqXMueiRE4BcKjJXM+sKsUa0UTCW1zOjmbYPSCPyPXTtrunbHffo3IbSbV9bMV4bFWzX+60Z2FuUjP4P3nxvowmKM+f3Xtf2N6UidHs93vff0+ZOfdfU6QTFA0mip3LTrhUMDA17sizXG43VWkM6eNZR0jpGDZ1Q7vfo4h7JlNe3p6LK2lZ14EBlmuRMxlepOgaTPps+wyMUU4ONMTCrwrLMLFXYmiZBk0XXLgi7NK5y728D2lRfV2QJhgyCOjYGorWZYjxSTvSZVzTwFCmBtg2h20UDysBwrqd4FUhdIs8njTLRywNiXOE9AHG13u3pP49/7ONnQ/eDHKIzk0OMPD5++bxN+wstxFASjMk0SQ3Y1nBhnVCYLph2i5a1DiUlpFSY6gMYI9b3VDw0TVPd/Eh7oKHUpoP7Y3ZLro2hUANps1ih2W5YplbTNDGVcdNSheCxzIE0PqXQxq1bGAUyRfE0EaMJINjOOlNAtnOokQlKEEwKR84FSKlAaZA2iF9HDAE+RJgs6JVh23NC/1LeB0eDDVukISDa1mZgQsVdAblgCvXKe1//Xia/cv2ogbt9d3MWWgshii0eHh7R9eQ4tq4eeH3B6+VM+iWwRjEQ5bLwRBulQBUgFaKpGqXgrIVyDlp1OB0HvH/3wIVJgV9vUJps4LUiswVoUzfbLBNcTeY6xtKG2nU9xsMBKSbM84IQM/w6Iwdyd3RNA1UUUqAQctmoC1+XEDyfoAwNuj/+9b//d0BbpAy8vrximmc2HCGHy+vlBpJ6WrpvpomoTwBy3sJhAcn5IYrluu7t1oWqYzcdDrZJ/TZh3WjGT0/PePfuFwzDgN8//o6vX79AQsy9T7XJv1xfEWPE58+fGIUG67FoiEBNcQKwQGuNriPDlBACUilouSEyRlfHxpwzLpcrlMowVhOqGCOsBR4eT3h8+CuW6YZlvqLvDJ4fT3h8OGDsW3SNY9pPRgwFyww0jcW75wc8Pz/i/Yf30NoihIyXy4ppDfDB4+vXL1h8hG5G9OMBj4+POByP+Pt//or//M/fcDodcXo44Ymz/GKkAdEwjDgej7her/jb3/6GEAIh4qaBVQ5fv35F1zTo2gZD2+Dx8RGX82e8fP2EdbnCOXJ2jGHBh1/eI8WI15dXzLcZ3758xb/887/CWBoM/OUvf8Ff/6nBx28LPn76hNfLFeM4YhxHvH//Hg8pYZpmvLy84NPnz1i8x9O7d1hXX9e36+2Gl5cX/PnPf8bz8zPZ93MB6BwZPJlEzq/GKIxjD+scSkkYx54LwY1OWYqqLqshRORUcDgcME3zZr6QM7lTLh7rGuD9CmMSxn7keyQh+IjgE8ZxwDD2tYlY14icF7Rtg2EgNDbGzE0+rdfGOlhDURq6MWibrq7bXUuDEHChKeiGGEN5TyHIMgiTQQ5A76vvB1jrKB+sZByPR/z5z3/B+3fv8S///C/4t3/7H/i//v1/IuWEZ/WAvmtwud3w8u0bpmlC9B5nZ9E2FqYQEuesRgbR3aNfkeOKnIluiZzhGsBaTfo7Z+GcZro/aQaV0jBK4butzsa0rIfRtH5pLW7LwF7YtjEEtmGf4YHT22ZO1b/aP+cWUYO7ZqfyaOrfvN0DiAa5RZ7UN8URcoLUv20mpfGjPUr2ksiIrYHE7SileMALBI7Ecexu7EqB5z2x71o8PJyglMbnF2IVLAtpflPOd+dIDrnHZP3VWqPkTKitD3Bthmt7mKZDKZo+H/MMm4BsOySQ/r7kjGldcL3doDVlXQbviY6baZ/NxbA7asDlesWyLLhcLnWNDyGgZyfLjrXyewr8/jrKaw8h1AEawA1Y1yFng7CcMa8L3ZcomGeLxUdY16FpOvT9AUPf4+HhERkKMZNOL3iOVCobJdavK9aVTNCWZUHgeuJyef3OHfzz+Ec8fjZ0P8hRoKrhhXDcS85I+++JniqLvidW4f9hHLjRywhrgPcB0zxX7phMyzZRF+mYMlOqAFqARLu1LpQHI9Mu1zj0/QClNuTQew8fPK9Zim2u2cKXN82UKRNvnid+LZmaINDCSQiDgtGgzRYFwZAldEkRsnUJYsMjMyhjK/UE/PMtY6aphZkUx6IvkN/V2lSHrK3ZY2E+I5faksW4aMbEUVFyvFQWas7OeTIlLrLUXaDpVghoprBsdtZSlKUs4naNZZlRUBAi0cAobHVFiqnS74ACazRgKI5C8bUugTLKVCnV6pvCru+nyTEkaiS1gXYNrG3Qdh1dMx+weHL5RAEcBxdLk5GYGnu9nLEuC6SayIXRuqKY8qWZtrIVLSVnlEr1IqTr/fv3KMoghIRlnnGbJqSUYV0DKCoCvPd4eX0lHaWnrD0gv6E+kQOl9wujdNR0ObdRJylXiYoZ0lvch9HT+6THjIncBYdhqFl24v5prUFKhGTEGBCTCODNfXEHVOQvZxL9K83Oj9nUz9gyzzWqgahRVHTmUsgRkDVFDw8nnA4DjuOIEj3WWcEZg75rcRxHjEOHrrH4/9h7sy05riU989uDTzFkJgCSp0qqpVbXsLTU/f7P0bpVq7tV0zmHJAggMyPCpz31hdl2jwSpI10X4VwgEkBmDB7ue9tv9g9xGUWvoa6xokcNHA5HhsORfvBipHIwFOeIGVKGKui3fgUjr6Pre6ZZChFxgRRqdp0CCLVv4Hw688vHX7i+XPjYfuTp4YnH0yOHwyA02deZ1Dc0fo8KyTlzvY6ktIARvW0w60YrXteV2+1G1w00Tb/RdQ+HA6mYjWKZUqIfhk1D27YdqRSWNchkKQTmZSHqeKIAvm3Ept8IoBwOB4ZhoGlaclmEIeBE8+OcY54Xfd1+iwiQ6Z7cI943rEtkXWWiJk6qlQoeaVtxrwxrZF0CKa5426i7ooSU12nAPJttHRPzHQXRKZFm0ffWQPG6hjgvTRNMZXro5MRZ+fwNuGzxjeXp6XHLNLVO9p84jRuw9U0DGGJcFUh2vHv3tNHIY4z0Q89333/gr1/+ip8+fuR6vWKdo2lavG+Ia2CZJmJYCcvCSKG1GVtEL06JEmFQGSOVNl4KljuzLWOxqISgAiNTtvf3Wzvqr0Hdr6dz+9zp7ifv9tx9gynb/QdQakzO3aRqf5b9ce4ndEo92H9V0Lf9/45IuU0h78Dbbz7JV++6VEr5HspeX3cFlpur9aYLL5DSRr1sfbNNraoWmiSvOZe/PAHd3TULKQQwCesTjTEyxSqWok3DXKrOTSZboAybZcYay7LM3Gc7Nk6MW2qjelkXxIBIKIx1v6nUc+/dG2rs/Rpfv57VGbxm1RkLXd9yKkcMmZd4IywC9KqxmTV1UlwppfcfkUTL7PuB7D/GFFIKrMuNGFZyChjU1OpbDt3v5vgG6H4nR8HIVKROu7LmtZSKyfYpXdXbVBDV9z0P5wd84ynAOkmWVYiRFMJOmagbjwExgagTtbwtTiZZShaDg6yFsPPiSnV+OG+TqEmLzwr6rBXqgfeeeV2pGsCcRE9xu70CBW8tXduKK1/jCUXoho2X0GBvCqszkBNZ82QqNcQ4hzWAdaD8+y2Gzhi8b+i6fuvQtW2zaViK2hLv3+s3TZ33nlCL8Lvi3hhD18r7t1aE+xhdxBXEVkAnn5tsLMao5fmybM9XjRasMQrcigq3kSqLHSiXArdxJKq5yrxIQbvMy06zMgaMhJ9aFYpLs7mQzCIbSa7uWrLJgeovnbjbVf0B1tFZj+s859ODfqYj6xoIKYCxtE2jm2bg9eWVz59+IUf5c8mZtvHY2lDIUX1jMrY0m0taKYVUNDS2boR2B3QZy7ysfPr8WcBCLnS+wVhHiElNLV6JcRXDF3XIc5atYKqAcp4lW25rSDQNIHSYCuaEVnx/v+1d9UrJDEGaFsMwUPOE7gFdKZl1Tbp57x3elLJOr+TuTkqdjQrIbc3VKg6T5HqM+thC52s2eh9ZmgVSUFixwj90HPqW6XbB6H01dB2n05HzsadrHWMJxDAT1oXr5ZUUV0gL6SlgrRGA1DYMh57iPOuaWKMUgWtYMcuCcR7ftPT9wDhNzPOC9+PGJhAqrMO3nqEbeDg9kELi+nqlpEJjGh5Pj5yPRz6NI6+vL6xzQ9d5mtZvlKjX1wslB86ngabpMAq0a9f9er1ijKPrDtSmyvF4YpxX5iVsDaaHhweGw0kcGvueVArTsnBV7dw0L6wxqZmSTJOH44E1BHqNFRkGmcAtcZUpkG9o215rcAW06ozXNLKGpJjxvsW7hlLGzS1T6I5VoxvlvLcdaxPI+aqaHaHD1gZTWFexa0fjZ5SS2vc9zltdeyN919Or46yJcq04byhzUUrzvqbtLpHgjQU8j/kBjCGps20MgdsEznuaVuj3IUZCXDkcGg6HHmMsyxJYZmmwDEPP+XxiGkf+6Z//mTUEOjX46rqeZZp5TYl5GpluN+K6MnhD60TX64zk0knhKw0/yu7warEK6oSyje5T5a6A3jc1tvv3DQiqw6y7CZc0CNlA2f6zbymXZZvm3CEns68T97/X57g/KqgspUieY/0eU19Y3Uvu53f1fe2B3X/pEArkTn0sJZNLombJCqDbz80bQOdkfSnINNYaWXv6vuyZdGuQ1x7RDfcrLSNf0VKdNCViShSTcDHLHt+0mGIJxZK0rrHWiwsmYkOVYmKehfa4LAsGiWLpuo6u7Tj0B2KQe2tZJmUF5c2lue07AXStx9em7x1Ar4ZC9zKSdV3p1paubzEG+r6jaRzOGsbXX2Rq7QzeemH7aGYrRiik+39KtcyJkETPHTWDN6fAuljCepNmq6YAWlP0nX87fg/HN0D3OzkkzDOogQncb1Qb5zzti1DOoiEI68psHbfLFeslMiAsYr9NLrr4CFWp0sCWdcVZR+PUgUqdLskSOl1pjRgtOhunmVwywYs5br+wulGZIiHCSYNYKzhSMOWs0+JbOsWUKjqW91pSJJtCMmyi+JKzTJlUCybgRKYXaxIKSON3rn3XdQrg0JDogjVpA13rshKWQKumAeIIqcG3q4jxDWxW8cZIfpxzlpyjiPLtnrFjjaEf1Dmzrxl005ZjU3VF9dg/u3w3VDJb3lrKhYwEpr6+vqpRQybqpiPdRjS8VCaarRe75epwKRECUjEUpG51znJ+ONO0rdBRi+zLKRdiLmqD7un6A+8/fE8uhfZypeAwt5FpnpRCUrDGkVIghWotLi5zOSWMUhazTphDSvRq8NK0Ym+fg4JeK0VlSmKk88c//VEmcTFvOoamaXQKpOY8RooCiWhIUKLqBmV6lVMSgFnE2r3x4nyZYiSsgbbthXZUDI2TnK0P77/jdrvx8ZePTNMoRhBbz7ywLBMvL1/4b//tv/L88iyP7aqRRdU+1MLLbnRMY6otfWFVYOBbmfQYa5iXSe4t67GNTMFs42kbz+nxga5rhYJ0u0qOmzF4pU/dLq+kxbO0nrjMtN5hS2a+XXn5bMhLz3HoaFxhaBvMoccSSLHBkrm8fmGeJ56fXxgOJ45P3+N9hx06OhzWd/i2lal0kfusHzrcpdFp+wpYTqcD420kGaHa5lRw1vNwPLMuC18+fubYDpz6A99/eKJvG0LXKp165Hzq7uixlhASt9vEofc413A6tZuWJSyBm7mSYqJtD7TdgeHQ4FxD12XGSaiNP338yPsPQgHtDwNYy2WaWcaJAri2xedMfzzwmN4xnI7YVgxjmq7FNg7r5Vc/9Lx7LxEMrU4GrPUcj4M0RELCWk/TdgKW1e237XqOxfDyesFo+SYTv6J5bjLhP50ftkZQTLG21zDW0A+9TNWck1iBEJjXmbY0WGfpfIfzks+5sS4MxCRTeZA1GVDziTodr1d2wXdSmMosrAOTWXMU1gXQdC1Yq38+yPXqPT6L5raUoox3w/nhzD/8wz/w3fff8+XLK6+XK00z8/T0Hm893npecLysn0RXmQohrdLQK1VDbJDAb4tFriXvHN66HdQZs00a6zuhgjN9LVZjHYw1G4iTE2H2aYqiqlLiHTDbyCvUfhNZJi45GTQ6ejdnuZvC1wbQBhrrDm5kdajrvLhGisOzYDoLttw1WPeXWOoXViaCFQbsU7v6PDsLBP1bA5ScSFENPaJEYYh+2anWy2zXVkoFW6UZxZAyHA8HwhpY3Cw422QJwTYGU6ruUiaooJ9pEZaCsQbfNnjf0XSdZIhmlJsjDAnnRPPqmpZVs1QDiRhXpUXKmUs5MfQHuq6XSA0jpmCYHRgZI2ZRKQbmaRR2j62vK2nYuuzZYqDmVB5RP7/8xkCrbRv6ruF0OjDfBnIKsu9mkV+UZCgmqbFbZJyuen4FLDpvaYtXXao0HymZ1jthH6lGdZ1Gsuryvx3/9o9vgO53csSUWDVDRTpXZivMKy3y3s2pjqbCGjAYLpebCuXr5EVCfL1z+MYLfaZU4DjRNoa2kUIxJSmayFkiAqqOzFqMsxpQbilGwzuTTG5iTqgTsdr+K1hREGoU1FVtUOMkX0rwnBTj1ijwS5KThWUPrNZubY0NaLzQj3zbkKaFUhKNb6WbrNQkqJSSSErsFMeSNRdGzpfRjmZ1dUvhjmdvZPM1dQLmYF2LGmHIpM5aiUjoupanp0f67kDbNtxufrOu3/WIu2C9ar3qBLNgNIKggl/ZwMZ5VmfI3enMOadAWAoA7x1t01BSJuS9S9nUjUyvIwF0J6zzG6AzGWKBVAsoNZd4fHoP1mBdK5OnWBhHmfZ6L9TNVCIlCuCuNuI5qcGKguFUMjEnrHf4RoT2eRZdXkoR5x0FpVrFyJ/++K9gPQXDNC0yfVRAVKeZxlmatpMiKwVKsuS4ipujqQWM5sVZg/GOpNbccQ10jbgOUgyNa3g4PfF3f/v3fP78WWysV8loM0b1g0UAXYyJX375ZRfpO4Mx/o02QyI/9s5+tbgPqvdo2xbfeLquZ11X5lW0mMNwwDu1iG+Exnd+fKDve2IImJ9/wmShVHpv8M5yfX1h9ZbZW7xmCnpTWKeR17JS1gNl7fnw/kTXWJzp8C6TYmCZblyur4T4TDGO08M7/n1/5PTYibV801NsQ3EtGKFGmZI4Dgd80zBOC/Oy6r3YCW03Z5yxW+Pm4XDml3Hh9fMzL8OR8+HEX3/3jk4B3TRemOeRvjUaXSKALqZMHAPeDhyPrdDIkUbI54+/kOKNZZo5nhLGOB69x/UtSem90zTx8eMvNG1H2/WcDgeM86Sff+GmYfLD8UiTM/3hgHGO/njANZ7GWpq+xXqH8RbXeDpreHr3fqNOL2XBuobT+ZEYE9d0xTpP03TMJoLEXNO2Pd63vL5eJBOvbfGNZMh9/vxFmxUtx9MJYwzX65U13BTMQav3i7Fmy+EKcWVZZKTUdp1oY43ZAJ0aGot2+M49dQd7NX9M6XgU+rbHeQU9FowzLCFIRAkyYcMYwlrd+oywNZRqKwYc8hynhzN/9/d/y/U28t//v38ml5/wviEsQQGdGBxdnp8FjGVtYKZAyWJJrwmYWJOxSM6YszoRMZLfZ9UVVNwChb6vo2xqgs4O5r6OJ6ggy9wBuuowqmu/tZJtVyrLsui6akg6LSvFbhTXur7fT/WttXeztvozbAwKMfaSfW0Hlzs43dcUU9OABBjqVO8tqNOvTXnzfsV5WjTz0ngy5GIIMdMOB5wGfceUWJZAQqMhnKzBbYHjcGAeZ27WkW0hYShJmr2mWAxqeGVqZFGhJNHx+9bhG6E9S66h6KOzcOzVhK3lcDjSdB3jNOt0K2+A7t4cTibh3VbH5CYrhVSmunXqFWNizpmwzMrcVVOotqNRxk7T6L0TwzYVrucqpUTXSYzBMHScDgdufccyZmHoVMmASZCjslYi43QT4K6OqE0jVFJrEgaVceRE7+U9xQBpXVjnGzl+A3S/l+MboPudHMY5DdgMSulS2p8CvFL7fEZyXOrXOcM8r5Ry2QTuBZkyNW01sDhyOp05nk5My8yf/vQntR0Xah7W4NXkoFpre3VGiylwHUV/cpvGTUOUtHN+PJ8lf6nrN93Ef/9//1E45FlBkBGaEUUmbylHSgyEedRpTyDHOvUq2vWSQlzoH1IUNW2zZclZNzMrpQ4MKWZKCSqx20PS/ZYhtDtdTvPIPE8wsWUKbfSImLbubIyZy/UzOdfPo2rcigIlnUjljHXQdg0pd1xv1w0obp+vUlK6rt+oHyklwrqI5tBJt7SGat8HT1ul6pAlsqHkzBpW5lsiD70UF7lqKyWGwjsDztP1Lf3QidbGOoq15CJUJtc0YDMxFz49v/Bynfj06YJvGrG1V4tnazxrGCE7TAZvPe8/fMArOM85Mo035mWRc2Utvms5nM/8/X/6Tzycz3Rdx+vrKz///JF/+qd/IivAzkkA25/+9Ceatse5hhAlUiAhE2TjJE/QeQloXtMCOeOQia+zDSKVkO5uITMMQmFbV3EVXJegn6u4vK1r5nIZ+fjzJ663ixanMk0McRINXYZ1nkh50ueuz2OU0vY2asRmob2a6kapQLwGVDu9Bh8eTkjUhbzWJcwY63l6/46H85nvPnyHtZbXFxHL55xJplDWQiCT5iu599ih4+F45t3jmb/93/4aQ6LklevlhZfnz/z4x/8uJiSHntP5QN86Dv2J779/IqTMtETmNfHnP/4r7acXhtMDw/GR7nDm3R+e6A8n+RyKYZoy3333V7x7Skw30VC+Pl/58OEDry8v/PmPP2KtkVDz7oB5es/Bt5SU+fFf/pm//Q9/TQwLKUfa1hGT4V//+K+cHwZ863h8fMQaeL288PnzF0IQKuL5dOLhYaCxjmkamcYbl8sLL69XxtDw4fu/4vz4nvfvP3A8nfnx51+Y55VPn74wLkFWTddg24xrW5quJwHD8YhrW04PDzy+e9pojd6Lc2UxmWLKppdzagbUNGJv7p3heDjR9wOn45kUhYr++ioGLcNwZJ5lMlu1kyCFrGTi3ZimCYBh6Pmbv/n3VJfNEAKjatnatqHtVOvrvWqSF2kSdOraC0rl+zU97346JRT+Gr2SmUrBJ6+aJ4l3eXg8iQYPub59EU3gx4/PDMMgDqdY7CpTOskIk8bX6XTAWsf3P/xATIaffvyJcZR9xjnH0+OT3LM5MI9Xri/PxJxIWpdTzLZ3SWSBw5TFVdwAACAASURBVOlkbvdOlHUdqobpa0D1labtbkKX1OBKtFZun/QgwKqu6c4YKG7TTGMq6FP3Tbvn0X19nuvz/6bx1UaJlNedUdBYp4xGv9bPy3y1xhiNszDm7mzcU0jvvm//OaX1KwB0xmO1cSbyaHFqNGqhL/uWrH2HfmAaBqbDATPPFAoh+P157f6epSno1I3UYJvqbuzIRsxvvHE4K4Hivu05nh959/473W8+KihK+yQVaVDEEHl+Loy+o216ZVws2JKlM0kmmUguK/O46p6+Z40604uZVN/z7umJw/FIzuIoPE2j0vMTzovpzrImQly4vn7m08efuF0v5ChN3K5tOTw8UoxlTVITjOMV3/V0/UA/9JyOR06nEz/9/CNTlgBzUxKWREmwLhPzdOP68szt5YW4jL+6Vr4d/zaPb4Dud3LElPAIp1y6O2jni82BcROOl6JZanYDGyHsFAMl7cukoezaoD16AF3o6wQQKu0ga1h2nUaQ6iaFZJHpxIRS1DXM412zRQI03tP6RmgcJWCKra1JNdKoXdn4ZvOzzm10z3sNm7yVLDS9qJuVc0ppaLb4Agzs+WD3m+lOR6nOhGFdNsOFbepiZPrh1UhAutaJmCEXs2k86msTsXhgHG+kFLdQ5XUNLCq0roCu6rjEtEVomNURMymFo05i67neu6/b6bsrWORxxfbfKK1rp/6IRtBtuVCn04nz+YhtOoxtRMuVCrFAzcGqk4BpmrC6qceY2Bw97zrdpRTCGoj1OdO9u6eajCgwXdd1E57P8yKunEXz1ozBerlm16RUxar70UmzlApGJsVlN+MhRRwZSsLZTI3PqAXN4TBwOBxY18g8r1wu1zcairCu3K43Pn/5wrJM4rym539rqGQpeEoR7aa5O8dkoRgpb0rPi2hXJBcsb1TR1gvFdzgceHh44HA4iL7ycmENUbQmqWjMg17jxjBer2JJ3zQ0VVequsiS5T3UiW/fD7QNWCNTb0rievnMvMyUksBk+r7leGgpFNq2oz+cWUPm82XlNl6JxRASPDYdFAk5t1a0nzlFvEMmLbFjNUY0K21Lo0AjhshowDZif55zrxlSgT//+GcBJ40nBKH6xbQyjll1JEU1uJYwyXUzjqNMoVvPcBgkT887lpBYg9Ash3HEdweapt2mXmgDZF0D1RbiXmOLMfT6u0QN7NTP3QVP1sd6v9ZieRgG1VaVzVpddI8qy7Nms0+v2VY1YqDmdX2dV7WuohGsE4nqiir6HpmwdF23Ndy2+6zs+q0KFH7r+C29U85se4Ho9JxSzbqNDZLz7m48z7MaKx1kQm1lKrTtGcVRoxwOh4Hj8YBzVvMgF5yRaI3T6YiJCyWtTM4SdX03qBukqXuT6qbv3Cjr79uCSFUuvbXR/0vHvT6OO2D0Fi7Kero1aszOsrg/7sHWPVj7Xznefl99LqNffw3i7r6W1fDNZynXlH/TXHr7u9HIAoux4sqKEcZNvR6Fjit7tGR/otfbbhx2D0YBTJZ1JueCdeAMgOTS1usz5UKJCYgUF2U6h6MYz7KuzNOES9LwqqZgMpVVV+2SVVsXSViS2YH26XTadKHLukoDMj+TN5+suh+KRCGnyHi7EUMkpsjletEooShxL8bqZ1yUzbSwzPP2uVtnabuOw2EgFQPrSohC9Y8x0uS0MZxCkEZ1ilUWIMBzjSvzdGO8XVnGkbAu7NZu345/68c3QPc7OWpwrLVOBexu27zvbaZrFh1GXNGKUh1iSriU3gKanJVGsJsLhLBu2p89924Ptd03CF3AKRv1L8XMXW9RJ2q7YL3SQKQgkQmdsbXzaYjrDuqMhl9T6YRqe5zLTkmEWqhUnYnSNVLEeQ94gjoLQtk0dptBhurKqvdzznmjce7OlKrlaxqh6TmhIBojgmdnpXsphxgUVKqmZN5JUPM4Sp5c0sgIOf3ye31N1amunnuhUukkrxgRWG8NWn3/SvsRmmrRjUGntWqyUjFF/Zna2a+ZYefTicNRdEfWt9zGmXleiSHqpqkFZ0GcwxRISdHh7wqKvXiJIcl1UASIJdUpgLoy6rRxmiREO4TAOI4sy6xTP712rMNYx5pmCrtjqNCBohYeDmeqmF82Tw2wghzBFbxSWcTswIrj4vlMCJGmWViXlWXOQAXmEnz+/Pxlm85WkC+NC22EmPr+d3pPKdIwuTdSuadOVTBXp3Jt2wMwdAOHw5GHhwfGcWSaF81sjEBi1UZDjBFTYFnm7bpxFnKpNFfpJFe9Xs5J4w4aGm/ISdwTnRW947xkjJHGQduKGcjQCt2z6w239cJ1ukqcxDJzCDKpzinh3G7mYxH9UNs2lJJZUnyT7RhiZBwTx67Dt56eXl9n5KeffuS77z7w8HDaGi85J8ZpxZJxptKqPbPdKZRt4+nahqenB6wzNG2DnwN2iVymlWmeaTTXr2k7jqcTISZiFofYeusanY51XY+xkvNYDJsx0v3asd9H0vC4bzwZYzYNs0tlWwvqvztnN8e9Tp0x6xpesxDrGnI/wb3d4ubKW0HlnmkZt7V6Xxd3kHFP//sfHcbsxX3985tMS81FbFur+uOoBk+yVsl6F6Q4Nne2/xSyTv2EXu10knfAN44YZc8x3krDbOghwrp41aKpGZeucZhdI2cqqNuaSfV9lorn5E93+8X/DNi9meTd7WP36+d+nut0E91H2BpCtRn4dp96q2W7f86vv+drQHd/fVXwVj+X+7+/Q7RvXuv9tfv169gbck5+KYvHsIdvJ3XQjtqEKvmta/SiRmcChPVc169V3yfP7TbknQuQpMkFCWICJ3TFbCJO8wtdaJStIfeIpxp9yYUQEYp9wpCMOjybrMwdT9s4AYfLyu06sa5B8x+lcViqRi7pHjQvhLhyG0fRM1oLOFl7qwQjyRRwDaLJNkZiH5pmd8+NSR4zpwJJ84GLUNvXGcnTTVEdoGVvW+aJ6XZjul3F1Xhd+V+4fb8d/0aOb4Dud3Js2iq3L6S1Y1xNOKDm43y1KWh7OAOpZLV3NkqRCEzTTDEGN42M08g4jvpjdgMZ1ZFNMonWbZJirVO6jm468pO68RpSKqyLLGqrC282FmcNbevp2pa+sZATJQZy3B6FXdOv0zhrKHfFSy2Ics4KUMUl0avlst3y8szmalmLxRjFuKUgxW+l5x2Pw1Z0L8tCWFeWddZOZNUDZGJacY1qwtJboFmP6pZVNED5rf39ftRN+r7A23QCX23CMm3SoiPp4+WsgvodO9SiaqfZCNWy61uGoWfoOw6Hnr7vNvcy3/asIbHGhIkSkWDUMs4WA3anYNX3K0Hb1W3OCWDbnlM2Q1Ctib7flBJpnvn48SNd2230x3Ec5T06q0DAgnX0bYdR/UatWwRkir15UR80Y+TeMNniigjOS97prXL+zF1DRMJxvffMZVbwZDAk1hK4XW8KOmqURJ3i7drPqtfJJWJykfurTijU4MY6q3rVZguQTxpBUAFPpffW/MSikRDOiv18wYjD4TzrlDNuDoBzEJAWw8LDoaVrLK2XCe2yznz+/Il4PnA8yL388HDm+++/ZxyvrMvMGgIhrhgTOZ5OFCwpGYxveXh44HR+T8iGkC1ZgbjzreY0iiFRUJ2pUXMaatC6tTw8PPBSEpeXF1w1pWk9pTRQEp8+faTrHG0nOrCuk2nd6+uVGBf6rsUZGIYO8kkNbiK38UYpib7vaBvPYTjQdjBEiJ8DKWUulxsxFfohc3p8pFUwt6yBkLJOXJBohaHHeUfX9aSU8b7ZPpN70LQ3tswGzksp27SiKI1ymqZtPa3r9jTNzLM43FYGQFEaQS24N6aFNtHmedw0mXXdr/T3GmNQp+Be88NKzmQFOvdA9P54CxTY7leZGu4Tuh2k7A3BygRoWr89574u7xqnUgrzNFM6o1qnhqHv6btOrePFQCirw2Y1LqnmJfZu4na/tsmUZkuq0abKb1e/v0m3/Op4C4xU17ZjtjePJQ3BIre54U2k0D0o+3pP+Lrxdf967r+u09o6eTSUr5w7/8fxAL/1nr7OVvv1edDvc+oQXQzFFkSWLYZcJdVpqwC62hjs+555XXHKtCh1/a9ZnqWuj3Y390pKM7YZcsLYgjdOc0+lobGsK88vzzjvCWrzn1La1noRRBbdf8UcLZcaZVQI60LjDdbKJLEtct3kktTgZJ8w780PucdWBWt933M8Hei7jhhXQlhE8hGCGG/JmZP3qpEF296M6vuVeZtjZF0WYhCzlRgWyOKQWZLUENPtwni7MN2urOssevxvgO53c3wDdL+TYyvoYVuEagF4T4G0zmGTLvbGYJ3H2Nq1166Y0g1MMcSUmZeVqJOdeZ5Yw7ppRZy1HA4HsQXWjvJtHInPz1JgGKWgvNmcdhcv6eQLPa+Cigr8rBXL4cPQM3QNKaykdSEFcdG6e/cbRQKzU1lqYX4vMjdm3/CNsaRsdGG1Oi2Q75chjkxxBJwYLa4dDw8ntZGXSUwM653jlVBZpTsesL6l6i7ui6OitNN9U3fbIr/R8u4rhjsKiH7g+ku+LrkIrXAr+KUISjo1qm6hdaO3RoLDt3O9FVmOfujoh45hGDaBd3WT3E4iuyaj/lWlptWu8K+KJFMpnhbvWrwXwbmxMDvHON40TkDeU4yBl+eXrdAVOmPaYhZqTlYpUsTmYkRPc3dPlG0KJt3WppHPWHzKMssM63JvTrIXGPs9ZfbuMjp1IUOKTPOsE6P7witv31tUMC+0WIsUGh5Xqk6zXrOGtm05HA6MRmh3elG/KXzFATURQxIwWsoGtlPKpBCY51kcFSl0rVeq8CL3T1xpn44chpZD3+KtPO7L8zPkQMkDfSfNoMenR5wz3EzhNsqk5HYVALquiaZd6YYT775/x3B4ZI6Fec2EhITgtotStKSQmYPcA1VrBq1QvY3hdD4xzyOfQ2AsicPQ07U9JXtK9ozjjcvlla4TXafXaU4MK/M8YkraQJ4/nVjWhXmeCGHlmgLT9ICzR4a+x9uW3jTclpUlZNFuIurRd9/9gAehSyeJyRAGQpR8tLbFWAF0MSa8qxEWbwEKCNA2ei9WMLVTz+SjFy3yTM04rHTJeZbpqlyvzfZzkpu1u902mpdVSiHFxLqsUMT4RF5PBRd5j0HR61wMQUCMRKhEBF1q7u911FSoTuKgFGnGvZlYla/DqwVAee9pu1Zf5+6c61wtlGGaJ8CqCYZnOHQcDwcOQ09YJtFPpoxzO8vAmgrqIEvEONbUv0cB3f2EroI+s913v8VWewO0FAPuj7F/z/35uUd0+/nb97ty97gUYSBU+uGbl1DPndmJkRtNsQLB+hneNfGMEa/R/Rl/6/hq8rc9ZV2z9bVuz3OfYycjT6usnmJAdG9K8U3Cjom5TiCVYti2DMPANM8bY4iyNxbfvK56agqq6dZ/tfI/1zT4pqMYRzGOnLI01KwVUx9T1Obfk5xV6nok5ahOkUYcT620aJYl0jRiTAZVgqCXRcnbtRmDmO5IAyVt91JtYByGgb5rGaeqMQ2SFZfjtofXvbIge1jS68BaMawqxYCasVRGkSl7tE6IiRQXpvHKPN6Y51G8A1L6Rrn8HR3fAN3v5JAwW3G7W2NgjREzTdsmshWj1nE49rv2y8tEKobAsgqNToJfxRWyYFhC5DbPskk24Bqrm6jYqx/OB96/+8D5fKZtWz59+sTr5ZV1DltxXzeFarNdD+cy285atCNcxNHJOUvfS07RoW9JcdFfM6UEcpRCOaVAjlIYSgxBpZy6N7oR6xyu8RyOA8Ya1Q2K6zNkUg6QMjYZamaaOFJKtZOz/F50kbVephzBG6ZRbPmNaej6nmHocO5IylE0VkvW0PE7Ybt2Wa2xeCMW7wYjm6K6jJoixV/ICykE1ml+Q8kLMQplA4szXicAEhYcY6DERMzqwlnEvdF7t+k64rrinBjltE235UI1msOXTWFaJq4/zjRfXvBNTy6ioWjagVyMOp2tEmHgk+SAmZ2mGlNU45aMQ1xTv/vwjsfHs1CrnOHzp0/83//Pf2WdJnkPGKzqgOr166yj0YlVQYrknKWjezyeiCkSYqHI7JVSEgXRk3qNpfjw4QPHw4G+bei84/X5M3/64z8RU9Ag8UgICz/9FLlcLsiELjPeJmrou1WXNWs81abaOQ9I+KsU31IUhLAwp1EywKy47pm2wTYNbdMSDVjnGfqex6cnPrz/nufnF5rPn8na5IhKw/386QuvL1cOh8+sITHNk2q/vNjxdw3eS3G3LmLBHRXEhXXGW8Nw6Pnhu+/48O6R9+8fyWklhYX5+oWPv4x8+pQZ+oahb3g4D5xPR4a+4bwcCHHlcnnmp59+ROIHOx6e3mPaEzFbjucnHt89UkzD58vC508/czo/cohnvG/FadBK2SnGO54vr884ndCFsPL6+sJP//KPPD6ccfYJyPjG8Ic/fM/l9YXPn37mD3/4nsenE84Uus4TguF6fWGaLOfjke8/fODBnEk5sSwT8zzx488/cRiOHI8njscHDqdH/t3f/A2X68x1nFlDZJ4D47QIpayA8Q192+FzIXHBWU/JMkU6nR4wxjEMBxrfbm6P4qia1MlOAHwFBzUfsE7WvHeEuDBOHeNtYpomQgibBu+XX37GGLneT6cTfS/U2xAWpmkmBAlI/vD+PX/44Q8s88zlcmG83bbmQNs19MNAjKL/uV2vG3uj7+V+d85hvDpBmr3Zdt/sMdqYkyLUYZzHGHcXo1KzuWR6XCeElVr44cMTpcCyBJqm0LaOUqSQzjnz448XYkgcj0e63vL+/ZH/+Lf/ni9f/oE///Ff+eO//CuXly9MKWDiwjLeZL1W/VwpCYMaTjmZjEqDSpottZFHSVDMzur4Oprg7qiTpP3PUMExumtZ02yTpk1yIJ2tDSTVCJ8KzLIW87Wop+wNVtmo9obYfdOvfiYb2NZDnsMLhb5mkirg1U9w23+3F65fSGRQ/T4F7/U1cvdvRjPTUtJJoFW3SaeZlw67BrDiel0yuEYC79uu3+iYv/zyRVkyAqCsc7J2GgGMRZuzBk8xSGxBe+B0fuK7H/6afjgrE6AwzQvPtytrFLp9LuKgvYaFpvE4K2vnMs2Q1VgthQ2oh3BjWSamaaQ2Bk2BwzAw9MN2DcSgzb26X1NotMHSOInIiGFl0slZWFdhSiwrpkS8NqljjIzjxBKT6mc9/eHA6Xwmp8y0LPJaSsYaZH3QHNDb5YXb5YXnjz8R40qOSuUsmbzOv7p2vx3/No9vgO53cjTNPsXYhzhvKRu1S+S953A40Pe9UIacY7zdKNyojmoFdIEVxVtUV0Bv3NZNhqrfuNH4duu+j+MomiidHFSaYM1Xqzo+KWz8ZuRQqKGwsrIajObCTKR1ZrxemceRdVl0AlE73oVshGLTNF7/ftcR7pQlDd9eA66RUGfUiIKCdsotptTpVrwTvxfWINO4EBecCuJjCkDBN9L5c95o/syZ4+nAOF653aRTPs8Ly7Ju1Mp7kXyMeTPT2GgwuplWGl8NMb0PNU1K1zS2bshaREg4nVK7BDzW7rWzBu8czjpmRsTEbO/2SuGgjpxAdmKCsK6BEAGlvhjXUopETBQtjpzTbmnJ5LsOfp0u5pKJqbCsC9PcKF3QCkV3o4RKQeOdJ5K26ZiBbQInV4kUKjVsna1IkGJzifuUrlKxnBbVfdcxtC1hmbXDLLTL3WxGIyqMAywpJm2sF5kSoDrGsmtivqZQ5Sx6iBgj7jAI9cuKJizFQlYqD8YICEiJrNfj/TTXGkux8twy6dmzJet5XZYF55V+VsRUJqyLQFtT6LqWrvEc+lbOnJWwd9d7nBlYO8M8XVmXkXmZWZYbKS10jcc7KxOWxmFN5ng6Mi+BaZLC5cunzxjbSP5cd6CYQte2+KbDWqfmK5nzwxnvm02TWw2UKIVVgcz54cxPRkKBX19fGIaOoe84ng7M8415vvH8/Jl1udK2nr7viKFjul1YZ3G7Paqpxul0ZBg61nXg48ePMqXMQu0qeE7vWg6nBtcemOZZ2Ajzsq19xjnapqXpWuY1YKyVOBEjuqDqouu922hToNSzN1PackeXrRR4WaOGoePp6ZGwJm63kZeXF4ZhYBgGzaGUR500J0+MUsRR0xjDugaen591giBMjJQS8zxL4HHf0nWtUh6FrbHFr5iiFuxQit2A5rYO3F+DkhWg65Pdptb1+tzAQNmNMppGDJRkX2iIITEt0iCrTIj62MawaQdF62h5eDjxww/fMY1Xfv7xT8S0sow38joR5pmwzsS4bK6bIlZWEwuDxg/UWVCdcu1AzViFOsb86tdvHeVuci9g1+BdqZvl28fYpib7DO6e0vhbDIadylnunu/XVM2/dLylcN6BuF8db0Hob1E7789DUSZIzgLo9kks+nl7mkbiWqwtlAzWuy2vtGrpnOYiFr33a77b/SS4WHBW4mGca/G+wzcdTdvTtL1sAimzOmkM5yJa8hhXQgoUIjGo6VuKrMtK33RY0yKXd9nulVIKIa4qjS/6PprNJCbnwu06bnvzuq4bi0Ym7BPmRR5vnMS91xhovCesi2TPGbudw5wzhIB1RU3gHIe+VwBdhEWRZM9aphvTdGMar1xfn7ldXlmXSTMW9SWoLvzb8fs4vgG638lh7yYX9xP4GiYu0x/ZiIUC0zEcDvhGrNxjSLhlxdgAJu/UB8MWXE2WBck6u3UVY4zcrjcMUqg0TcP1elVrZ6Fc7Fo+4YhnBRk5RcnsqdS9AhLIXV99JqwLE5kxRW7XK9M8qfBYgrqlSPLgxAymbcTtsm5WQg0VvUhS6uO6rvjiNBdPaBIlF0KQvB1TKqe/Ai7JzBFwUJjncaP8af0jdBd1ZyxF86Dahnl+K0qvQEmMQPKbv6+gbXMIFe7HTtfJWcXae1EherRaTdZcJHEYTCmRU6akX9OhvHd0bUtKK5DvJpp+6/LWrnDVrOUij1uMwZa80WRLYXNBa9sW55vt2kvpbiKr5zWkJIJypat657herzq9VJdQxJzE1PdQCsUWCcgt+n1GnAKFwppxTgKIm7bDWE+8zRvVtCifJ+WkhaMnKT2oXnA5K3DOibhowWHq5MIiy+nbAkw21Hz3uWaqEUbNGEop0vftNgGpzqQpBaU4F2JwrMvCPI2sy6paPTkT1lhwZjufIQTpiFurdOas91LW15TIMRDWFWeRHCWlFg2HQbvgAqjaxtO3jt6fca5gyUxzIKyB2y2Ru5aubWlasWkfDgPOe6UrzcxLYF4mLpcLxnfYpqdpB9phACtUrKi5lzWsveRCLGkz1aiFEhSGXmi+OcmE1Fno+4am8bRtg/eWcbwyjZnvv38vk9e2wVrDmiLLIvq9tm04Ho/4RiJLXl9fxcI8JpZ1xc0LKYtbZ9N6rBeNZspyjjFWmjbG0fc93dLjnCfGJNPsttkojzUoXpbeLFlZlbp2Z2xkbaWUVzMNWSNOpyOvL1dlDaybUYwwC6SZEUJgWRZijPR9T9PI1h5C4PX1lcbvJlhWgac0z1aWRRp4h8NhA5SlFNbVbeCygs2vQd09oCvqCLxN73SNzYgp030zcdfwlW0vqGtBKZa3YAJ1Xk3EtOKL7FHH48C79+/48uUTzR11eB1vpHUhrgspBrlXStbw7Hpv6i9gNyQSWp7yBbcJ2j04/UvHG3CV32Z81h+tE7pKOa0Dta91cl8/5v2/3f/d/wzMvQVvb/7lN37V798102a7VmEnc95/393krjaRTAFbtvdptEmYnccXob1mzf10ymCotHmJdalu1xmzNTXvwGwxWOsxWJyVmARrpUlX8zqFASrMCJcia1lVQxdZ10Ky0nDNKRFDYGhapfpqgzRX47FECBUYQdX7yv2lkULbedqbk5isTsELJUd5nLhiEKBmvSGEhaRrcr1GSp3wGq0TUPlHkXPodH9IITCNF26XV67XV8brK9P1Skkr1quRnKmX8jfK5e/l+AbofidHRgJhK9Cov6ekBhMpUu14K83BOaFpqB2YFMfW6WJTiFkogALsZBqxrkGnUbIZx5S43W6EEDfrbNFqGLpWisG+63UhT8xWuO9FQUcFc9ZoYYBuJkWmPMsysy4T6zIT5nETHRsyWCdAwsoUwTvJd5KiegcizjtysaQ1bI6EPjus0zDT6lgZdo1D7cJZGTdJASP7CMs8bUVONUIRIBA3kbIx4ntxub5qVo10zKvYuurZJHvHYowHatjpLnovZe8M51LegLntXFXtjp7TosHZ1bq85Hy3+cp7cNaKkDssUCRTp+97+mHYglNhN76RYGNLKmKGkZVCIvEXmtfjGobDga7tNu3Qsiy8vMiGVyjbtfj6+sJ4u9J6sZheVwH6zsqSVfV6NdhbLPAtRQ1CjOogKnUKpDiWLJ8j1jZMa2Rd0xYMn3Jkmm5QRKswNw3TeFUqbDWo34sqcRstGJNpfLtHPNx9DlkLu1qs1muvlDpxFS3Ew/kk2sYCt3FkWRfp4BpDNu6ugDMsi0y+BGxK4eKNgZK06BA6tK2i/ywmIk7z68TRVZ03TcGZBtM4AT+NOEyu68LtdoPS4U3H6djL+3QG5wqTLazzjZKFgtqsDW3rOR57iRk5dgyHM/MaebmtXC6vFOspOB6fLMNRrksxhtDGQ6mlpRS9OelESW36c0p473h8fODy+szl9ULXOfrB4xx0fcvxdOTTxwvTeOXx4SB6P+/ou5akIfHjeKNpPH3f0vUDbdNyfnhSl16JZ1mjNBVO54G+HzDW0fjAFAIpB7n7s0xh2rZl6A/b/WeQKIici1rxazlq7qzysxTNdU2rYO7rqYfQyluNyegFcJfMOI48PT1tICuElXUVQHfvZrmuC5+mG+VT5jAMG2iroC7EFTPDvXbROUeNqqm6uj1u4dcGGVbNRXL+NejZJsgKBvap3q6Tq80JlHmhA60NdKHneF2DGFU0nsY3dJ3j4eHA+XSgbRuqOcq6zKQgtLOcRArIcwAAIABJREFU5B6z6j4sTAOrj783a7bnL1JU10aVseYNMPlLoK6CGzFAYlsv6oe/gTGlpt4/1P35vF9jfgus/Rag+63X8nbit/0LFbB9Dch30Cc65rfu0rL2mEqnZNeZy/NYSnk7YTRv36AAN+dIpmASW5D5/cS2aRrJzyxi11+AttW97g4gWyu5uqipWi4oeyISSyGqsVvXdRhriCkQosUJlYFcajOz5gYaGm/xjSXHTEIyEElFQVZRhkchRrvtuyJtWFUeIc0xjJi2RJQJUeq6X/CNp2skiqWUyKSNRDlFGqJeG4j62MuyCPskRmoW6jzdeHn+zO1y4Xa9sE4jYZ1pHJhSsLr3FSPuvt+O38fxDdD9To6cd7pXnfB47/HZaLe2BtRKBzblwrIGjIKqEPPGm0e1H7nuh0aK9ZSLLIIR6ebb3T67doRBtE2Hw1FAo2YtSSe7IaeM9wsuRKxS66y521RyJhvNXSmFmBM5RcIykbM4VDmntMiSIJt9Y/pqLy6lYKyladu7iVYiBFlITXq7KeVN0H1vJ58p2ZCMbH0W5GcVMOYsRWhOohUzFMYioekxrkzztLl+1nN0v0HX7mXVvQGqmUrba9t1kL+m6BgjOodcqY8KQlIMpCiiacru/qaQBIo4sDlrMEaoa4fjgfP5pNeHbFZmt4gTbUdW1XiuYBO2TrSV7uRwOGyUsev1yjjetqlA3t6L5CLGEIS6GjXQ1dldKwLb9+0bvVWqDEIBSomcwbpC48XF8HQ6Y33Dxy/PW4SAUZpNNQxZrOVmrXT59VzXe8dnR9RJcUrVTTDTeilw6vEWcO/d+DrhyDqZMsDD+YizDsnnW7WzmxT4ynmYcpGiCmkiOG1Y5CxGMFu8AxbXObxvCHHRqXDaJhU5R8mzM8Dm7lloW8/pdOQ4NDgjdCFrErYk+u6Ac45+6KEErM3EIFSjFAPruhBCg2+klGjajq7tcE1HLJ5xCaDAIwSxELfGK8jUgixEbZAYpVkLFTGnJKA6RSBzPp9Zl5ELmXmZeH2Fd+/ONHUa54Q6OI0j3kpe2fFwwFoI60KMgWkaeb14jrlgjpbT6SxOnSESkyFmuN5GuuGR3krDAuvIzlGMJeqUrgDOe7quI6pDrrHQNI6UxGW1Tq0MqGW+AadOkCnv4MFUY4V9MlWL7X7oOZ/PxBh5eX7lcrlu99BmaGWFiloDxSs4c06mu+6rSUjbtsQUdGoheY7VuEpcR2XqJ9e95X5Kt68v3H2t2V5frbP7OlXv27cW+vsEyPAWfJTtZ9q2FSfOsNCnHgw03nA89hwOg+hDnRgopZyUllwbLnfA5w5j3UFntENIMVvbRptud3q6r4DKb4HXbWpV98r6b3ffV90996nX28//fzShq39/H2fyl8Dcr1/rznaRf7NvPoPtebcJqXvz2dW3Vfe2+5+vGjtpWNiNKvn15NFY0ZRRxDG7HrUGaNsWp4Y/mV0baBXhG6P1hxEdtGjWhR0SYsa4SMYKkPENp7YhpEgqgVwCMRpSln2vKBtjNw6ReAtxsA7bnqRXA7UhIY3QnTEjev69pso5M09JTWl04qs0efEZKpJLWyfy1dxFzyumRvdI5uztcsEYmbbHsEqzcR4Zb1fm6cY6T6QUBMjph1Q0tslQvgG639HxDdD9To4Y1n2B0gI+G6Eu1AnQXoBblnXlNs2b9fsaAmsQsbJRKpdYw7d0fUvfd6zLyPPzzzLlSkl48lbCctum3XKP7l0OqxtUKQVrnGatFJyxtE3LYTgAsnHNam6Sy4I1opLKuiBbo3bcrddFObJMV0JKZGug8eSkgOBOh+Ybv7t9lrJpW6ZlplBoGkfTyPtzVihI8zyLW5bmPm0W8rUbXSIpycmMUfJ1nLGquUvcxkx5Lqpr+3WXtVIGhfooGsKm8Rtlc0kqqDZvy5J6WEFmsgkZQzYC07Jm9pScSDFIzEORCREli8TEFMiOFBaul4SxMAwHnp6eePfuHU/v3pFSYppnRjXVEcpcBiQ81Tderqfauc0SbB+ThLOez4a+73l4fAAjhivWWTHciUE0nMMRZ41oH8K66eHgvliSCanxUkj2fS/Xi4FlkefKJZGLBqsfj6pT06KxVDCjIDZnptuVS5RzZHLGGenKopOUVumFEha+slEpU8K21fzEbhoLoQE6hqElpYhvLJfrshe/ZKEVF3XndNB5S2gc6yoARrR2hYBMKQ/DicZ7vPOsMTHPExTEdTFnks8yVborEmNcuV2k0ZDjQusM3XHAmiy0yr7j8fHMD3/4jv/893/L8/Nnfvn4MzmtXK4vhPWFvm/oW6+6qyeMTRJgO00s68w0j0zzSNN1DP2Bw+FIfzjzhz/8Aec7Mo4k8cPcLhdcE/Bth287nGvELCBImDjG4J3FmHabeKwhsC4zp/OJFBdKXrm8vvLnP/+Jrv0bnIHGW949PtC4wudPHwnLkdP5wOPjA+/ePbIsM+M4EVPiy5cXrteRtn3hb/7Df1QzKM+aYA2F2zjjXl4J2er0oOXh4YlDLqxRwI71HoyjHwY59zlJlp2XuBZjHDGqg6qXSZb3Trv9Mg2qgcc1j6quuTnvVDdxlO347rvv+Jd/+VdiSvz4048MvejpxBzqzLp+4cuXz7y8aA5g1/HDDz+IzjgKW8Jay/l85rsPH3S9S1wur/z800+0bceH78QYaF0WneYn5mnWxsCu9zNGKcUUaO5dZeXvpNdnKla6m1jLNK+CRCmCZd+pmX05J5nW6c8ej4e98ZVkUgGGx/ORf/dX3/MPf/e/k9aJkhauX34GUzDegnFkkwmr3F/eWRrnaHVdNXJ6oa4upjo33q2nX00k749q0lG/r4KgrKwHkEluyjVjVUy23oAuCxi3PWud7lX8WTTeoObapRRFA10bcBuqlv9ZbbIaNWiydwAOXZOrEYrZXB0VMGG3RufWqEOmR9v3bK97d77c/91ivbAyNmZI2YF5fYMbpVLX/67rOKTE4XBgWTSfLabtbe1ADgrqYm0txUiOaMHJBM+Ic6y3EvFyfDiBgbbztK8N6zpzu4rWLC5Rp7iJeRopKbGMo9LWE5kixkFts+09WXWcWantOSeOw4HjSSjLwzAQ1pU//3kirNpgNiLzWNaZZY6s84i3jqDZpHJ9qfu0QddBiVm4vL7w8uWzrBUqxZimkfF2Yb5dSWHBmozzFpzHlYQpSY3QpP7y7hug+70c3wDd7+TIKQsYAmQrBEpBZBhCxxJKg/Z1jMG6mlnkCClRtxSMUFG8bxkGKZbef3jicnnmev1CKDJRiGvUrJlM9juNpVJ61nUlGEsIiXWNmFIIa9goBl3b8vhwIuVMDJEYZ6aS8cZQ1G44p6STjihUBwO2iAbIqjL4rTW1aN+KGkaYxWFuN4wxrGHdaI9FO+0g3fbz+cTpeGQcRz5/lilHjBnjvEyCYsAqMJEpTdrcvAxgnNtE/VUb5GsUwdZt3emvdQOxZo9WWNdFw6GTbvB7xxn2bn59rKLvs1jJB8qlbMYizgqNtiQBsSklYhDFubcCDmIMPDycNre7pvF8zcevk8Gmc0gkQ0PXHbCu4Tre9L1bWn3+aZp4fv7COI38/MtH5nlhjQHrPCVKI6BGZFStWS6aV0jZNJ+FshcsWhT2fc8wDKzLQqU+im7OsYbA7XYjA5frjWIs0zySs3SHs2oiSymboY53UmSty41pnvDe0jQW7xrWddomzu5OnyrTBNF0UBCQeeg5nY7EtDKODb98+omSZepQIpQc+Kd//Ee6rqNpWqrmRKyzxYyjYHCuUSt3CbO3zmFS0mtZdI/eyJR7m6x4Abrrmsnq9maNwTXSyBm6RrKg2pah74BC03qenh7pO6822BcuLx+JcWb2hr5taBvH0Pc4A23jWdZGNX4T07JsBj/nbDg/fS8unk2HdR0xG65jZJ4vdIdMj8H1MjEqaLhyLX5NndaJdmQNKwvgveXp6ZGslM9fPv7Mw8OJw9CJwUbs+BRWXl8jKa00XjSCxhjef/hACJFpmpimmefnV4bjZ07nM8fTA8PhyLkZKJ8j87IwrZ84HI4cDgd839O2HV4nY5U6vOUS2hr+fR8nsdXF+p4qs0G+p1KNs36OTWPva+ltUlfXge+//46mafgv/+X/4nq9ME0THz584HQ68fBw4vX1lWVZud0uxLjy9PiO4+G4TeFiCEzjSKtOll13JAYxT5nGSQCnaoNOpxPOWaZpkkmwtQy9hKdbU/M0I23u6pxrX49qwa89mHsTmDrtqXlxdZ1uW/+m2DfqTFJBsqyVqnXOhq5r+OGHD/yf/8d/hpT48vNP/LPSyL0aBdXGjbUSZdG0nqbd9a6l7Fl0TjVYBjajJed2zeDbdU/upWLf/lv9rCqgyyVT4q61strsERv8CuhgW84VxWb9C6OTQ1NkB45R7nnJ2LNYp8+doQJBOW0Cbqxz22OXskck7NxWewf2jEQC6O91jfWuuZvG1Tcq/5MGmbiXVjMmY7VRZXbtpOxHeQPAdfKLMax3pkB2+3rXh1dAHLM0fqVsEcBujBhdtV1H1/ekLL4oG2tDM0kb75UuqTrpylSwktM4j6MyhFrapsUoXdp7x7oE1hDIKSudXbX4upd6ayXHsu9ZN3q7akJD1M8ligv3Osvn6ixN0+G0MS51UWEcb2LQpDmjMQa8EyAfw8o0jhLho+waZyAm0UmXElVeIrKaWud9O34fxzdA9zs5YgxCX9MFqtq0n88P22YUgjhM3sZZFixXdR17OLHQAdg6S4Wy2dKvayClsgWH1u6qdLziBlayOptljSSIVt3LFNCUnCXTqZEiTyzpLSF0hLVjHWdyiZQcdaInrlj/P3tvHm1bVpZ3/2azmt2c5t7qqQ6krQCKgCjYxRgJRiXGGI2a7zMjEjXGdJ+YDDSoiF0CNoko9gE1xkSNqKAiEBQJmABWSCnSVGl1VN2m7j3dblYzm++Pd8619j63MCMZ+SODumuMU/fU3vvs1c015/u+z/M+j8+IS6JO5CBBCse5apyb92VBdrnSrjWd6wfaFFsBlfQh5WQsJ2aiaKdSA7xscn3T4geDWqdU37eKnhtUvDGpy7S5fO26TqiGJDRTTKVjCuIBRipUphvK96QkLfVuqdTrp4awKwU6cjPT9ZIE0DtJ7JVKfS65gTwn4T6IHULM1WkJvOrJjMlkl7qeoY3FBxkbQkuU8+37jtW6oel6UKOyqVIbyWs2R0/CMNI7p8cklvzvSPMSZcqa2XQq/QlI/+YQvCBqZawVTdsRo6LvegkItFBsJIFUI+iZkTvyPYsDIpnvUe41TTd0CHqk51OQyPl8zv7+Hs534oNmjaAvPlfZYXFyTNuUlGWZUIpi4/6kcw6yaAfjMdEM9L2xQC+Da9PEOgZR99NKEZU8K9ZoCis9ZLPJZFz8lVASj4+PsVoS2roq0Ezou0qMx52jCQ7XKcpSxlxVV9jCUBZ2CES1lgS3bRtOjo8JUTGZwmRaJuprQe9SkNZ32KKkNkKlcs4n2twGTTypMIo4kfg+1XVNXYmoyfLkgKo0lFb6dERavKbv5ZlZLpeJ/mzRKiNBWVofDg6PUKagmswpImhtmc1rFsuWthNKotKGSe8oq5rCWAnU0/UfaGYbqPu4jYgyjH2qUUlCE9GJzn16TlDDmNukr02nU5SSZKtZt4mm6wZLg2xPA5l2mcUjJAlrc3+zc8Q4qmJO6knyNxRatyhP9sSQFHqT6p9zLgWhhr4Xf7vN5HN7Uyl5G98Yxmv6d5DzVwBmoBSOryWbATu+570nAKWtKMuS3b1d9vZ2qOtqmK9lHQrj/KzGXsWBSrlxa/L+FBtzwMeIhYciHGOyOs7vI5on9Ms8d4zjYYvuOMw34wWMwwvbh5Cng/SVQx9a2sP2MQ7fsbGPze/Z+Ewamen3mHK1XAg9RaEcTmSjMpF//3Nzh4zwMfTsRZ+psZKgbaq9KpX7wccjzBdZaWHOFGWJTTRh6bsLGRse7lOmMVsrVjBVVUEShnLpYgit2+M6RywjNs1rVVVS1xNCgN45ur6DiKiXktgwiB1N17Y0xsh6hrQruBATouqTRUyyGwKsLsaxmJ4R7x1t29C2OaHThOAkocsiRs2avm2xGlm7010bxN6MxqTec5VQ2KvbY2O7mtA9Rra+k6Z5rRWqEg+xnZ0dbrzxhkQRiSyXS05OFhwenVCUYrI5VCK1oSwVRSwGGkiXfM6OFydCuVovabt+WC2kiqUTUtXTuyT64T1VWRGMBPrSOxQoEtqVE5PNn1wZjqHn/NFFwKPI/V9pgfc9o6lsxJpR8joOBuByPbLioAh3OHK/21DVy2pZ6bubphn+HQVMHG5QpRsDlCwd7tIL2WA8V25hIyCIY8/Y9v8LGpUNh7P6pnMuce7HZvbTTeV5n0Kxdbje4+Po+adIVePsZxfE10YlyWbnekzUlKU9lcyJGETnfJJ3HxfZgGK+s8s119xAXc9QytI0HYvVEt+2+N4PCZbuO3BquAcxxkFtNKueBiJhEG0RhM4aKSAEMypHej+ee11XzGYz8eNSo/9d5zqMLoghCE0SJ3LZPSgd8UrTJ7l/MWlWUg1P1DFjLWUsEc+wQNe2KXhWqR+poGsTqrsh0Z6Tjtlszt7eLj64JKU/wfuOtnHoKP0bru9Ezr53+N5RFCXaWDF311oEi9LxW1MQjYFoMEqC3ZCq8yqCsWageopIUI+1Y1JaFJpJXbGzM2dnMkmBRE8MQj26cPE8s7piWpdoBXVdwd4e69WC9WpB2zasfcdkUlCVZTqnEl+VCTHQYuIeIr1zPHLpIqt1w/4ZjzYFk2nJ/t4uLsDJckXbddi+k4Q+idrgwCVxhExDFGVXRe8cVSGJS1WW1GXFYdvRrBtKa5hNK6rplL3dHU4W0n+5XC4IwbO7u0vbdamYJf536IKHz1+gmszY3fO0nQPdsbNzFhdOcKGRsds2tH3HFKn666wafCqZ2wyVT2FW2/8oUdUDlSwqtueA7SRopLoJlVNx5swZFnYpVgox0jRNYkSUgyjK0NuTfqpUMMj2JrkwVZYlZ86cEYXfpIaplGa5XCafuxlFKXNL3/eUpQjviFqu2y4qbMxv8jtXbCOitd3vdbqHLF8nEZjSiI+dWBjotG7lnkuTkBgg2ZSEwfMPtUGkTLdnSEVyUnfqTukrX77i3AJR+rQ3egvzOcScNA7/YUjwNnv6VCoiPVo/3J+3nb5O/7vbeM0fbbzlzvDt/W4VGVJSJ6eT08Ir76EQOhXRKIhSoHMD4yI/D2nNzzTXOBZildZYycoxxlBVNUU9oahqrLHSD00nHogb62xusbDWoqjAzyi0guBplSRK0aeet1wMCJ6ylGRuNpsOhYyT4xNUVEmwbSxytG1H8LI2ZETYGE3wMlb7XgR9QgzY4bnUqUddqMs+uoFWLIVbKZQE7zAGghMhqy6ptxqrh3uWxZasNlhjh+/PxbCr22Nju3qnHyObSJf3eKdxvU2CGFJJ0qmqIwGAVOq10qmvTCp/hbUDdUYCwDDYFcQo/S1CQUvS+OlHKy2VNGuxzuCcHcQPMpIxIkx5sZPJPaQAM6SKbNus6bs2IYYKrSw5hlLR4RAaZPTCf9dJpiQqOX9R79eD2mAIHrxK6IzCD4gAQ+JDQg2bhI51bSu2CInuEBJ9MiNFWe7fbFKSnEt9ECnQRxq+s5hHPpacyOVFJYYkCpIqet4JujlGhBoS6pLRGunPiRA1wUtSKbRFUToUS4nUcJ7sKogBYWAmRCB4lFFDNTPbSgjC5pIghBpQ3LFJXaWS8dizkRHabDCsU1JGqmrHFFlJc7rcu1wp984nBVUxnO56kY3PYzSrCgafflKCmAMCaQaPSR2xlPuexm2MSsx2MePzERyQfAm9mK37hFxmxEs+K4lbUVh2dnaoqppm3eL6/Gz4JDCkhgLAet0QEbN3Bv5TQiJSnxJBRGvymCjLWkaxSt59kJBih3PSr+iT0iIqDs9SPanZ39/DWsvi5Ih1I6qvXdsQglSLy0IquDu7c0xOJoInBsfhwQFtVdBOKumbqwomkwkqFVGWoafpPIuThr4qUwJRSr/sVPq2fBSbj9W6TX2yGmNLlC7wHopyjrUlVmt6Jb0pzvUDEpARlKxmms3ZrbWsFg0qWgpbYRLVNsvtr1crCqPQtdgSxBhoO5sq5I7FYsnefkUWVbBFyXQame/sEqIgdfNdg7Y1u2VJUVYUfUaZpVeSXAUPOglDRXIRfERuNjGWvKkrfs1Fmfx8bXoH5gQvfy7HzjlRO3PmDEVRskpUsVwYKcvRV04oxPJMZTGUuq5TH7AbCkxidVAMgaTQlcX/MQeFRVEMdPE8T0eSNYGQLcgATg7687F/rGRlPKcRjZPi2vb7OSCPkaGfyMNw3jp5Z2a7hpB8G4k+qf4xVtzIxZox7cjzvcpwXRyP5dGOfSthZUToMuV9+J6cyPGxE7CxD2/j31PXKO+HDQRwzBbHc9j6A5W+e8DfElKXlSnznJ0Tsg1kS8a4WLLoNP9uiZxEMjxIxs9On9N2opyQuUTNFONxhU59/YpRAMwORVyHD1I8jibTr6WQUtU1k9mMsp5SlDWRrHYZU9+znFvbtqBkPrXGoFUBdU2MjraxuF6SruFy5jsXk4VNGK1lshqyiGiZgQ5OjEM85bIgGsIq6REKv+u7FGekyxbFQ7dDoZQjIsWJvu/wrt8oREDwPdEn9o7zQ9F7qyiiU1+kgpGHkxA6tZ2QX90+frerCd1jZDNE8A7XRtZJGbJtG4LrMckos3cS9BTWpMqRJB9aa+Y7uwPHu2ka2q4XatzQ5+SFNx6zSl+ffOcs8/kuk7rmu97+CxLobvSRyWKt+aXbn8l7b3w8AM+/eB9fet9dw7GPFWtJPr7hqZ/CP/iar+TFn/857Pcdl/79f+D+V31/sl4YfdjeOduhfclL+Dtf/VXUSjG/+27+5O//fdzBATGCPbPPU3/g+9l51rO4iOLX3/I2fuQnfoZ/vDvlK77rFZQ33ED0npM//EM+8tKX4tdrHihLvvfmm6XXQsOP/Om95HVys58rxsiv3HQjb59UaKX4jKMFX3lwkM4H8uItiWvk71y7PwRS33m04Hbnhsp2vkYAv1tXvH5njlKK27uWbz+8OCSTQ09C2sf3Xn8D92hJ8P7u8SGf065TxTXL6kvSeK/RfPvenMJqVIz81MGxGGwvGsqDxdCrAYrfeuLjec/1N4A2PPvCBb7gnj8lJ/HG2CSyIyjL9/6lL2K9bui6nr9357t43PIk9VukY0wUkT+86VZ+9ROehu8dNxwe8A//5H1DJXuTTur6nh992ifz4HQGRP7avR/iORceStdoVG81xvDwbIef/uRPHRDb73jn74wU0RilR1RLoPKbdzyH/377U1BEnnX/h3jRXf91EINIfzDEPf/yRV8m1WFd8vfvfDe3NWtBRSM0bZfGteLOxz2RX3vSc7h8+TK75x7gr777NwFBRj+/Wcn1D0I3+tdPuoOHJhXEwBff/2d86uVHgHxPM91Jc35nj5953ucMz9g3v/k/jLFnWri1FtXWD7zoy3jg2c/n4sWCm97zAT77PW+nbdcJbRfKZVWWzOdz3vFt38PuzhxF5Ok/8gOouz+cgqxMWVaURcHFZ38if/oFfxmjI2cuXeKTf/Y/kumseQzWVY0tLB/8e1/F4qbrqeqem9/wOzzurg8O41JpQ1lNKGzBmdsezwMv+zY6Fzg+PuLp/+glQ/AYI8lkWJLwe//GV+Cf/TzOPXA3N/y3u/ik333bEIK2XZMk6qVX6Y1f99Wc2d9hNp3ynJ/9j0zPnU/JfEzjVHp1zj37k7j/r7+YcraP/dP7eN6P/rT0KlpLXc+TUJJkL+//xm8mXHcdSsO1//a1zN72ZkGcU3U8n1/z+E/gwe9+tYRVCh7/FV8CpGB/EykCTr7hG1i+8EVENPO3vJkzP/Ha8U21mQIqHvilXx/mw8d9y0u5/Z6PSLEkiApo9q28/Jmfw7m/87UyF939YZ70XS+XNcAYoa4mG4HgA3/y0n/B8tbbmEwm3P6LP8v+O97Gpjdkpqu5Jz6JB1/5LwGRgr/9K/9mOrhUpJIoFqUUR1//9Sw/768AMP2dN7P3Y68lj9LTqOPD/+nXBlr8Nd/0T7H33HPF5wCWn/t5+L/7EvH5+/Dd3PptLyMCNvXWBu+5dbHg2Zcvc19R84Hg8X3H15zIvKfzWE7+alorzk0qfvwJtw7o0bf/8T1jPpPn3XQT3nLbjbz/ujMopfjEiwe88L5zV9yjHGC/5tM/cUijvvTOD3LdYr2VwKuU3Hz45ht419OfgIpw5mjBi//gj9K8mL96PJg3Pv8ZXNqbA4pP/+B9PPXBC8POx5xJcXl3xps+45OGRs0vf8PvDiha/r58nO//lGfy0B1PRCnFbXffzzP+4P1b9yYnRSh4x9f/P8PfPfuX38T8kcvb4HPaPvq0J/Hhz34BMUbmFy/y3F9543Bs477leN7/VV9OP5thup5Pec8fctuHPyI91V1Hn9gZIQQ+Wtf88BOfhNLS0/c9d74XW9bYskD85/Jxat7xqS/k7qc/F1tUPOkD7+X57/xNScB0ptPG1NbgeNln/RVJmhI7SEeNSmirAhaLY1BRetfbjq7tqauSuqwFnc7WNIk2GkOgi0kczUR83+O6lq5d07senfxcQSj+bdfjnQJlUpExFXIRdlFhLBlOdslSSRSNFbYqUTEnmIImR5U8R1G4kBYsa1C2uPJGXd0+LrerCd1jZDNK1K9iDPSuJyyDTFJNg7GFJHXaSv+NtYIeeI9KhtK7O3OMKYR6FEdxitxXFwiEssQaMyBZbdMODb/f/Xu/KBXA5DMUUn+Q0ADlmLq+x2g99M7ASHsbFw/Fc551B5/3F1/A3/66l/KPPnIXf+U//SLH73oXB+98JzGOPP9rnvREvuwffwNf+OIvZfbww/zMS76aT/i2b+OG+fYmAAAgAElEQVRD/+SfAHDHj72Wo3f8Ph98ydfyr259PMc33AgI1eueb/1WFnfdBUpxx0/9FLd84zdy77/6V0QkMEJrBm+ymCfTEcGUavu2MbWcz3geY1U6pir32DsiAfqVK6ZiTN7yUr4pIgBjldw5j7dANs6FjeAjvZT2TwxoNMYKDWToY2AjsMhHoPSAwIaQ7xOCcKmA0cL9Xy6X0kiej20o7g4pCFktLZVvRwXVpGi2SRlTwGQ2g6iSwtiYoIWsBulFQrovR9nprCpISqTzdRj63VI/kFSkybV1hk/H3IchC6Y2GkIWSkjJpDXoXlBGMlprDK53NM06IXMg1N8UMBmT+iGDWBAohdEjVWgwrU2osdGGSVWLx1+mB6VHY7i8SoLrqi6Yz6YsFxNKO/ZVxhAIRLxX4kXnRVm0KgvqqmRS13hrUzDlEyVPgp6mFdpxVVXUsxnZyyyP81zMUFoNfZGTSc10OqUoLH0v/nexF8prKEdqk/Mt7UqUGLUVn6mRHswgplBVJc57mlTxNlrQ2MJa+oSgeec5uHyZnfmE3d0diixggpDHuq5Ha4ORYU9VTsBANd+hKMoBVXbeifhHQmcn0wlrk6vgW48ESm1NUYwDbiNDGEfU9jOdCjbq9OB7lG2TiqmTB5fy8sCnR2GDLSBoB0qlpDiiQwSTjMyVUILb7N2oclEg70sCUKXEliXTwsuyBFRS9tVJqGdEivMcuI1IXXliEYbnahNcelQwT5Eoc4Ls5C/IBYWYHoIB3VXbvc2Pvqnx4dma4x7tuo/Xfzidzb9Sp1/Ix7c1CuS65P6xtFv5zOkOuPEQx12cup5bk/n2506jdXmuza8pGLxoh17F0/vaKD5sfueAYj3a8eZz5NSN3LwI6dCzjYYdxMTGnmitkjqzymtcIHu5ZfRMeZ0KRFlkRtaJopTeOmMl2Y8xjoqjjIlT3/dCtwziD6dNSELNQrlvWvEB7dO8HkPk7JmzTOoJ1ljaRL0X1B4ST58QA67r6Vuxn/HJQqBI/dPOSatK26zpOuk3Dhvjt6rK1NdspPASPD4xO2IMotaqFSGkcRQ3E2UjsYhSBJXZHVd76B4rm/pf5W1v/fGjRZxXt/8rt9ue/lnM9q9PAYo0yuYmZGWMICvWYk2BKapEebDYxCO/+ZZbsUWJ94Gjo2OWyyXL9TpRKMBHCaSy4XH2cQGwRvPqd/0SMQQ+89w9vOb1v8ELnv009vfm/NBP/gpvfeedaK35o7f9JD/x82/i055zB3s7M177+l/jrb/3niG4FbTF89Kv/zIePn+BX/jlX6Mwlr/95V/Mjdef5ZXf9wN0TZM45o4vfNFf5kv/xl/j737tNxCc55nPfDq/+Auv59nPewGf8ITH89M/8Vq+6Eu+HFuID13Xi8oiRIzOKmLwt7/ib/GE227nX7ziFbIQGT0cU9c2AAM6ZrShnlSJhx+kch58mutH/yAxDBaqWNM2LBYLoTs5d4p+Rfq8TX87JnQ5odlcCG0KznJQJcE/CZFK9xsIrpMm7b7Fuw4FTOuSqigoq5LZVKwKJtMZ2kifmEk/DlE9zb10gqIUoCxa2aTcZXFxNNiW9T3SB09Uo++QUtkH0WUgjLIoKLRQc+azGTs7O5zdP0PfdxwcXObcQw+zXC7QRhGj2/LvU4hYhLUWY00KqyOuF+UzH0WpNSo10HWKssIWQt8ztkChRf3TiZiIdy3rZkmMfvjxQXro9vfPsrd3hr3dPR5+6CLHx8uEUGpikMhFa7BWejSd7zlZXBZV1ujpVgu69ZJyA1l16boaU1DWNXU9ZTKZUpYTpvMdyrqmd55l06SKthdxlkLuz9mz13Db7Y+nqioeuXieS5cucHx0iYsXHiQGz2wyYScJtdx0ww2c2d/n2mvOsjOfMp3WXL50XoKNds1qecJqeYxrV0wmlfzUJYXVLJdHLJdLmmZFm56D/b0zAw3VFkJZrCd7GFNwcHDMpYNDThZrlK7Y3TvL4269nWuvuwHQuKhR2lJUNVU678VyyXK1YrFao4gUVvOnH/ofNKsT2mbJpKqY1BWzieXo8DLHR5eTGXzHTTdcx87OnLIoRCI8RpQ2PPTweXwAU1Ts7p3hzNlrqGa7CGVJ0XaezgWq6Rnmu3tMZnN5/pA5Yv/MGcq6lmQcBtXEEKMoksYI0Q8oT0aECpvmXsYEUOYSxMPTx8HXMM8pYxA/enrmADwEBq+4xWIhPydLyqqkKisxVVaK1WLFetWI/YktqCc1u7u7WGNxvhcqGFKUMEPftPTs1pNqoNtnRctrrzmL857lcoU1IjmvraCU8kymPuY83wznEEWhceP88lyojR7EIUKMeLfh9YlKiGLqK25EgCv6SKENMTia1Yo/u+du/tu7381b3/xbnBwe0q8FmSuMxkRHVVjqwlKWQs2srEFroe9n8aesuKmUeIXl+7d5PzYZEfmYx37m8bx0TqLUOA6UUtRFKUWhgcadVBzjmNYpklJmVmjOWVBMxdCN49EDhTIlW0nARm9YF9g0h28yHjbvzzjW5Ef8CsuhmCHMjo2BSy4ujElujDFR1NPnEnImRTsrxbok0GNMgSks66Zl3TR0fU/bdTz00HkuHxxweHTEyWLBai3UYPl7A8aCKSj3rmG+e4aynlNWU5QuKKtdinKCsQXaGrresVqvCNFTlgZrFcRAsz5mtTzh6PCQrm3QEWb1FNd7uqYdesN7E5OibUHmu15/3XXUZY3RZuil930/9KRnf7u+a4Q+6XspMmpFWYi4UNe1tF2b7FMU2pSD+rRSmrqWwvhAmfY9y+VKvGO9Y7AiyOMuFfH0RqFD1h2NsYZmccJdf/CO0yHh1e3/0i3Ggcv8v7xdRegeI1tMEsxaMRhNRkLyupJJ3FjxWipCTAleQKUFviwLyrLCh0DTVHR9j24aREJ6bK4XGXgr8u62wDlH17bcV+3gveMzkQr53/oH38sTH38T//6HX8adf3wPB0cLOaYY+NqXfj+333wdP/Hql3Ln+z/IpYOjVJSVxeLGG67hD977h6xXa3qjeeCBB3jGHU+i78QbTiZGxQc/9GGe+Yync8vNN3Pvvffx4i/6q8xnM/b2dnnyk5/EhQsXecXLv4WnPuXJXLp8wA++5rV88MN3E6MfFseqKvniL/xC/vVrfpRkAzRe0xhh49lzvaOPoiZKvqpDQKclAIw50El9SUqClbZtElefYd/DBE0+91yNVhuvqSHQywgVjIv9LMIvnzvH/FGr1bkxfwywtB6pe+NinnC6jQAz0xcvTCa89AWfLhL6qd/CJwllZSWoyOoCPnj6tsclVMZaK+MjCb+Y1CclQeWIymglye/+3h5Gaw4PDlg3K7QmVSlJtgsO7xxGp2TZ1BI4KT2M86E3EqHzmQ1UNFeGCeK1ZcuauirpuwYfehH9addoo/A+I49HeC/9a23bDf2YWcZeJfnqXGHONKLoPSG4UZ59QHdHs3Tw0lOXpb6VCJTsnzlD2/eEI4V3nrZ1SRrdJWuIFSfHR7RVxXK5oFmv6btO5KxLw3w+Y2dnxmRSizH3iUIRCGEPYxT7+2fwbop3HZcuKZxruXjuIRYLTVVbzuztsDOfsbMzpygtTVOwXFq6tmW9XhEjFGVLYQsmsx1mszNMJ1PWTUe1qjg+WXF0eEjbOibTOXU9ZTabY6wlkER5XBLm0DK++77HaCis0ET7di1iIF48Ffd3xRrBdVP6rsH1Lav1Wua6SZ38A0tsUXJweMJyJX2NyizRRcWN8zPSL1dU2MJhup7lumE63x360iLQ9elaR0FP0UkEZpid0nM5gCGbNc8RKR8Q4Jh7lxgCtLxtPm+byL8xIhDSdXIMeaxZa+n6Vn7KFh+mVEkFtGuTCt9qTds0lLYQSwKlUcaKaEPridl4vChFvKooBV11IvPu+9R3LZMAPjp6paiLengO83nm/rNxHtvuScuFntPIfb4Wm9dNMSojaqNHq5FkadN1QvMPIWCUJGdei4m19DlpMiQWo4I46NfmIxsQSlFKHufY0wnooyV04+uPEoudQk8zlJ6vRdx49jdyWPlPHCnqiqxAOf5/7pHaHCtaael7y8keeU43VyR0AxI+/H2m7tutNWDYWzr+XFw8fY3YSErZKOQppM9brvv4eWtFbRsl9yObi4s4VknhUntGQr4IgaiEZtx7h86iZloRaOhcGJ4y5wMuPafiJapSstUPhQWtDYWWY9D0+M4RnceHiLF6uLcoiZ1sYYTFkqm7Chxh6LMLTuajZr1MquIy/o22yQ8uHV0MqBgwupCxrMbibO7/FtaOFwuGnPDnIm1ao/KzX1ojhRc2jOfT3OS69soxeXX7uNyuJnSPkS0LSSiS6lOithXWkCvTKolIeNcTkweMamXBOrh0mTJNvG0jvXebfU4xRoqipCxlkhn91DTBe37wk15I37X8v8Abfue/UpYVD1844kN/+iDPe9YdvOO/Sf/AG9/6B0DkvgfP8cG77+eOp9zG29/5viQs4pJwhdA5vOvxLibPFifBZPCEJMP/Z/feyyu/5/t4zb9+NSEE3vLWtwFCEyxswTOf8XR+6nU/yw/9yI/zgk97Hj/wfd/FF/3NryR7Fxlj+L7v/E7e87738fvv/C9DECGJaxgoSLLlyERk7dXGgpWTLtP31ImKVnhPXVgpeK4bXNtiuo7KOZ7mI//20hHl/wH828bI3WXJe+pq49XEA4qjoTExUlpLUdhBLdNaMVTNtEhjRIkyosUo3Dmecf48v/6m3yDkpI8/lzE2BDcqJa2nmTmnt1wVzolYXtTOT6Z886d9Lm3yFKq9w6V7Xya/xSxQItumakP65jiKz0g/mxkOxiaftb2dHWKYpeb4nuXyBLsRQDknfmbHx8d0fYf3AehTkucxVihsOS7KC3XvxHNRBfGLCt7hg6AQQkceaYcxQkgJayRST2pMUbBuW7q2Ra+bhAzItWnblqPjQ4qi4OTkmNV6SdOuRWWzKJlMKvb397j22mupy5LcQr9aLSF66qqgsIrCaHbm0lvpuxWr1YK2XXH54IDF4oRrr92nKMwgqOH6nq4VOmPwgVW/oneBspwRAkndtqSuKo6P16zXKy5evEhUmhtvvJmz189BGVxINiFpjsm0Rx+k73dnZ4d2vWRxXOC9Y7XqWSyWRB+oq4q4s8ukLAfj8a5t2Nvbk55f7bnuuuuoTpZcunxE3/ccHR5xzXU3gbJEPPVkymy3YvXwxYEeHqIEij4KFdUcHogip9Ep6ZSEJCPxe7/xq9zyrf/siqfhzyu9/m8/7luIyTbKs7XTDTRlm5a3vfMhiRxSzc3AfTvpHD6nrjyzMJvx0d9+Czzu5iEw1s6TFU/C/v6V3/XnzQVKEAyjDcGI6FWXRIcWi4UgOivpVzMZfUr7ysW1rf0M+aQekyNygh3Hz20kp1ckdRvfu42o5u/Ob56iH+Y5GIZi3CYCO56z2vp38/XTPyN9coMyP7x/5Xsf+zPb743HzKnj2kBQH+XGbbVKxEAICqWC/BCGYpa1duhVrapK/ETbdmDM9M5JEq40UWuUtVR1RVmV2FKYGCHCar3C+aVoAXgpRs/mM2xdjvZByQ5FK1FptdpQGIO1BaEPknAGWTdMSm61TpY/SrFerfHWY7TEOKT3Y6JFeucSkpYTRsQnUEmhKgz2BclCyqTjD7l9YUzayAVNrSnLghAMMRZp4I4CSGWaU+UzDGrYIYYNpPTq9ljYriZ0j5GtLgtKOwqYRO9BabQp0BqU1kl9SQIpj4e+p23WLBcLlosltiyxtki0PgOp4meTVPZkMmU63cGHSLNuWK/XdF1DYWUSck6QmNlszvHJCqXiBiVFZv6uFfNbRRhXXQJEn8RWWs5fuMgtj7sx9cv0XHv2LA88+FHapknfKRSECLzxTb/Jb/zGmwgh8KxnfSLnzp1ntVrx8LlznL9wgbv+6APYouT33vkuvvWf/X/s7+1xeHSIQvE9r/h2jk9O+P4f+mGm0ykAbduyWi/xTtAWO1DlpB9wP0b++blzbIpFoBTTEPick4UEz0NxczPSGu+VV/Cfq5IHT1FjIpGYvN2Cz43eoxVBTlY2K90RWCpF1GoIThL8JRVrJVVgrTTTaU2VJM+LRM/xIZKNZ42xaGsJaHonC+39t95O1fcYk/qUlCE4WTSVPm1Cm5A9xIy6rmuqSqiOXSdjrW3aITAeKsxaUyRjcu9FYvqTzj3Iz7/tDVcO9CgCQHeevZ7L0xmbGm8Rxaoo+bFnfRraWKrJFGtLdELSYggEFYZrXqRj1CoynU44ObGpD01RlGKkDqKSenR8jFGyqHqflU09xgvVxxiNsYrSlkzCFEXE9w6UQLLZW1ChKG2BMgaTKE8hVZVDkPEnxvdCZTZmFHlQqQ8wBMfh4QEoWK+WrNcL2vUCS6AsLLPplDP7+9x0041ce+YsXdeyXJzQrFccHx1z4FsmVcG0rpjNJ1x33bXs71ScP3+eixfPc3hwicPDA9bNgr3dHebzWeqVm6Ciput6mqZj3TT0fc/hwWWapiUEhQ9SVNJa0XQdDz/0US5fPqRtO2a7+0xmcwotSVLvetCaoiyoqorVquf4eMHZnYrpdMbuzh7LxTHL5YLz584xqUSRc3dnF7O3y8nhZY6ODmnWDd4FZl3PbL5DPZmzX3g+543/ERcCLpkJV/WEup5giwJbFNx+dCy/J/quQuOD58xd76e+789Am61HeHMLsykHX/KlxJ05+dHcRIeHLRXWxkczJnSWoZChU7EkDJTtlHAlgRul1KAEfHR0tB3QRbDaUpRlSpJHQSpRvBRqpt4I+jJND8S/FKAspVfa9eKjpa2hsJJQd11PNSm3US0i9Yc/xG3P/9QrLw6gvKd7ylNpnvvcrUQLrfGPu5nD7/iOYb4aaH0JDRO59gIMnBwdcXh4yLmHPsqDDz7AhQvniSFibEFZJLNl7xLKNSrxSgKeECmS+FCmLiIo3ZjUjcyKzR7GAWHcOr2NBEttUCUZ1ZOHFoKN7w5+9F3cRsY+Nmr7sRK001TXkXkxfj6/n1G77e9KSF4Wr8oFMLb3PbYFpIR3K7FPaGj6PymSSqEzRmQ9UqATylSk8b67uzsWl5NoVW4tiNqgjAVbYotCEDQNkUDX9xwerVivO3oXcCEync44c/YMk8lELFfWa1QMvOS//BaEwGuf+1mCkimNd8krt0+siQ00MqtkRh85PjkWBFglAS5rxD/XuUH9OouX5CKiipHoPV1SzAzeoaIoh+tChF0iahhHKs3nmz2O8/lseE5ysTx7gFbJUL0qS9Ztj1qtiOv1wNgIXE3oHivb1YTuMbLZJG7ifaJxpUpyyF5uEank6GRRGVyyLJBJed00SbpaAp+yrCiqGjCJYikUwtl8h955QhAKYgjis6WUyEoD/PUXPp8f/dlf5+YbzvLkJ9zMH971EZEXBr7gL38qr33dr/KE227gKU+6jQ9+5M8oCiPIYnQEr/idt72Tl33T1/Fzv/BLOKP4G1/8BXzrd3z3sGCK6pwsJ9dccy2PXLxIVZb8k3/0jfz0v309MUb++AN/wnq95tZbbub+Bx/iGU+/g6PjEy4fHGK04jtf/jKC93znd39fMmGvRThDi5T3Gd/wio8+KD5huXINPLtZ0yq1RcHKa/5bp1PusXZYzHWiYIQgFJLN/picy2ZpZKs1WYLaRekDy70Vm/0TW4IBORjapMSQq4CjaXW2rbDJJDur4Ilsc0qokeRO+yDi9UH6hQCWJvVfJsUxjxhAK6MGZGOoAmc0oyzQ9YRiPqesKlTT4I2hiZmik+lCsjUonO8JUfox3nnTrVv+fgqGoHbP9Xz6wUVuXx6PD0BKdnf7lscvjnBFgbXlkHAP1CdteM0XfBWhFM+3dSO9WyLnHhKKLXdVUG8JFIP3FJVGYYhRjium6xyCHig/2oiptXcdrrB43+HT+UrPjJYGfWtBabHSyFRaren7jsViASi6LlWCkWDXpL+NCQ0LMaQAQgo4tpQgPPcKKWAyqcVv0Ah9yLue5bLBu46ubVA6UpaW+XyezG57XN/S9Q3L5TKhgqLyptWMee5FQxLxlFPQNI0EWi7Qdg5txGJj3XS45QmXL19mcSIJVFlNkrl8GgdafPWatUo9YxIsVlVN37V0XctqeUy5cLzwV94wJLo5yPLBJ9TGYIsCpQzX3ne/jJmk3BtiTNXyUSBkktD0zZ8I+Guv48I//CZUIYUApSUhl1EhT3skbISzOaG7EqFTygx0sxwgSzCYsCOlBN5VaoN2tTG3aJmzVQRSohbbFt91uN4lk2NFZQt5nmqxA3HO0QLBlsSySkbrZpgngpL74xrpjTRVKaJBIYjfnbXoqpK5rO9pdfaBM0PiuXrOc1k/91O2EoZh63vmv/1bTN/21q1ropZL/A03UN15J5ulqWgLzv27XwBrN66LBNIZIT86OmaxWBCCFNe0scM1GyT6BwSO4f+3M8o8W1/JNbgimTv13qagTEa6snVKRugGmmUAmVfT9258/+Z+tmm3m+PpyiTv0ZC309+xuY2v52RND+jcpp/m5nXIc3meT2WtSsl2HOmnkdN/ms8xQBDjHjLCpTLNU6iPdd/RdjVV01K2LUVhBaEzFm1LgjFiRZSuiXOevnf0XSdCJykB3RQGkqJYhyJy49Go0BkD+BjoXUfXSiGENPZ16jeP2e4mFdwCHq8cxmtMsBTapoR1POF8XWKAQEgylGmeV1psTlSibqhtpDSL+phELRYkrkjXVg36BCGxomxRSX+kKQBRx86iZblocXV7bGxXE7rH0Ga1eIdZLUqSPlELXJB+HTLio00y/BSJb6UNBEX0TgxwvSM4jSPitYHkDbZaLun6SIhKVC77jt55oo+88m0/lRakb8bHyM/90DexuzPlu1/zizxycEz2XGrahp//0Zdzdn+XV/7AT3O0WA7mu85FlAq8693/lTe/5am86Vdej1LwK294I+99353YwvLCv/TZfN7n/kW+5eWvQBF41fd9F4973OMoCssb3/ibvO7nfi59l+Pl3/FK/sXL/jllWbJuGv7pP/8WvHd81gs+nS/8/Bfxkbvv4d+97qfRWnPp/e/n7Nd+rVAmnOPW9ZoL1tIlOkaIMnW+Z1LzoemM7DE2KNIlewcVpF6WQ5VccB8q8RuLd+67ygsmcUwchQayQWvJ33MlBsCwo1wxJudyyXlISc+EsSb1nOU/UgPSGROtxgePjyLkoBOdI9OgRrRVDWpheNlZLvLmPhARWPBjT1m+VhvngsqV3RHpHCrD6ScvfkopSPLRh8bw2zfeksQc1FYAct16xZNODlHeYa1joDSm/e+sl7z69a/maLYznn9CBnPivQmuKqW4MNvlez/988WzC5POiZRsA8RkEitpvusdvvep38IRnKMyYjcgC3SB0oYmNdxLgOIw1uKc5+jwCKUULgT6tiV4L88t2Yg8iXN4R3A9MTjxnNuZsbszp64KgnccHx1wMKkoCovWMJlWKLVDROS2+67j6OiItl3T7U6IMbCzs0OMjroueOTiOYLzLBdLQX5coCwmOO8x1jKvaqwt6fvIarViuVxzfLIUQRJbM53UxKjoXODk+IhHLl3EFAVny0oSgxDxqfcmF1NiDBwdHYLvsdZwxwf+iE9646/j+o4zR0d0VYWbTgS5TOMnxDD4lUXA2oKDW2/h6C/8BaLSOB9o+0BV1dT1hLKuKYqSy0dHSQG1oKoFtSb1rCmlhkq+URtoSH7UHvUZTKB4DiYTanPlo7oRQKfnb0DgSTWbIViXz2UKuBTOLNHKsxRCoOt6QliLX2BZYSz0SUjI9nIdjZEAdkCPNoJa+e6I1pGiNDRNogAnAaeyLFmsloOZ/enzOJ2IKICyZPXivzZmufkzfU/9jndgHn5o65qYc+e4/ZlPx1173cY8qLipa+nbjod3dnnV8z+b9XqdRC3i8OyFjULZcCMSUyHm3zfQGGLClj4G+ro5r4+Fs6yC+yi0TJXvdv6blLRl0atHGwSPsuW573/2mdM/j3bM2+c0or7Dd8D2fcnrFRtrjEpJb16bNtaN/O+Q8A3foyAGQhShsODzd0nyW5bSx18WRVKFlCIjSqFMgakqVFGi53NsPSUGjbTYiVBVCImeicL1DSfHB/RtSdOscH2PHpqVEZ/RZCru2h7XiZdukZ6TalLhok8m9fJ3dUK6QxBEz/UOikKUfhnXMe/94PMbNBTWUFVFWrdF4M0HcNGCMmhbJLGYlFSrsVe0sIaiTNYDMYDShCDenSEqnI+oPuCjo+0dXUIog5IedlOU//PBdXX7uNiuJnSPlS0tODqhOD4lcaIemYKLKFST6ISa44JUmUX5PlHSvCJ4S1AyiSql0UCfgs2w6kCNPXTBeaniM1YVf/udH+ANb30ffd9xcnwEG3SDn/9Pb+bHf+5XsUZTFIa9nemwgGgTQXn6vuUHf/jH+MF/86NkRbXcI/j23/t9fu8dvy9JYFD8va/7B5K0+lGsAqXxzvM/7vojvuqrvwZtUgKbkrDf/y/v5pOf9xlc37b82If/mAq4pe/48HXXSxCtNO8qS+5Jnk4heEEB0jnYjYh/qLgqCRC0FgEFUsImRb3s87a5aI/omoqgfBiSN5WChJwAxRR8bNFEImPAEuP22itHhgQ92TtPVCe3VOk2F+iUAA6+XJmipMcKqxrXZkFWrElJYEpKs6hM+g7vpKpqjBn6Egc0cUDNYkIrU1CmNdH74bW4kaSmgS7BZ0LIsvpXvpYXp1MO9vYoyoqd3X2UEkpP2yWlTOd5wsEFbHCp1Sf5JkakrzRmbyDZjFI89+H7ed2vvY440NbyFVb8m097EX900+PRWhGCRgVPl/YVMloePKY0VKWlqktBDrUelBmDD3KcCXFbLhZyj7QSGnMKEIghoeERgie4lNC5HqMiuzsz9vd2mM8mWKNo1kuOji4znU6ZTScpsZvifctqGXG90CZX6zbIeR0AACAASURBVAWEKdNJTVkW7O7uUlrDanFM26zFmiE0aGVYzVtCkOSoqidMJjP6PiTLgmNOTk6IUTHfLaiqmqIwuBBYrZdcvvwIk+mU3b09pmqKMlrOndEPD0B9+IN88b95FcZ7qpNjHn7iE2kbzb07M85few1lXYrH3nQCauxzbBpRl9vZ3aeeTKkTilMYBVoEEpzzGB8waWUMIY9fknqgHZA6cjFl8/ccDH/MbGDzlY9VfEnPfZonhoKGTBBjQjfkByOqMyA1RqN96j30XgQagLIo0zMvhRUfxOzeFgVFmke8wApSMNlgEYQoaClKJUVPR6lFNMU5j7UmPZfjcSmuTOiGlCDPGTGO18QWNJ/7uUNSMRS+uo7y/f8DNvw5AfrVmtYseepd/51Xf+gD9L2g4/lDMUY6Il9z4y08YivGbGb4ZqKKg4WAvBeG9Gt4eeN2ZWSI/C0b+5L+7THZziqVqSRG7nEc+qTyeX6MPO1/1le3yXw4/f+Zqrtx1HLEmW4fRZFU0Li4tU9JbPO8n3csr4l4r8x1+UrFlAjHU8eZ591hHhe8Ch2ToJXy4v1mpJhscx93WQ693DIGNdoabGExVYWdTNBFiXMR56S/2bkuoduyNvm+ZXF8SF8VSRQuglFDgumdE4VKH2ibBu8kHqq0oiwL5tMJ67Zl3TaoEFFBVFVdKpR4J3YGBomFUGltDnJdvU/FvyjFkSxclOfq3ge8M0QMSllpfzFiw5L7ho2R8xZaZkz3K4IS+xkXIHRSZDVBjclcYkgYK0yUq9tjY7ua0D1GthhEKCQvRmKo6ZmUxSAvHkLEhcDR0RExePCBoFWi94kMe3AR14IKnmpSi7dd6GjXkagKPAUhqq2FqCyKIYgA2NnZE3QwBqrJBFQc5P+1NegiibOEnhBEKcoYEZkgOkLo0GmBHKqfyWATGFrDNhdBWcMk2BXXPI9XCmuC0IesoXCBIgb+4X338FcvXqCIgbvmu5yrJiyqklVR4IPHWZtMp8MgIa2VGhY1Y0b0LLost51QlI1gLMTNIuiInMn/jX0s8sbGZ8JGMJKSNJ04/WWq5InqaBwECIwyQwVRAmSh1GTxgKIsKapSfACTZxVE8cfJ4aWSIEBlig4ZbUjKhMYkOwxZ2CZ1jbNOaHKdLLbZ3JcoyoWr1Up6frygVUOg44M0wG9UmPP1UzGiglBVJCkOw3tai3Gr9CqOojUm9QPGKP0MwSXFPp0od6kvEaW57/pbhn0672Sx90LFyb12IvgjfUj37l/HfrsekvLcozQPnle8/ZfxqU8qx1YO+M7n/EU+uLdPCD0+9kRdyEJNAJWpWJLs+RCIHrQTXztbyPjxTgLXqiiEuhMDrmulaOB6XN/Qt2tcu6Ywkb2dKddft8/+3j7WGpq2ZbU8IYQeYlYeNUwmNVpDWdrUe7Lk+PiErm2oyoIsaLC/t4ebTpKxriT5lw+OQGmmU1CmpKpmTGciinJ4fEIEVs0aj2IWpEpttDyry5MjDi8/wpn9fSaTWpLBk2M4WXDb636CF/zsT8pI7DoefPJTaM+cYb27g6trVssTERoIYkjc9R2dK6RPxRjKqiKi8FHQy653oHvKylCWVZobZPxqLXRXlYQPQu8oCo+1AW3Gec0k76zgQyqQIaqRegy288ObA/8hScjjOkfMmXamGfpdM4o+9uOOf6sUiQ6dnkWlE/oAIVHEhgRPaVrX0dCAEuXeqqqwRZGecUGeQc7JOY+PkuhVdUk0mq7t6Z3HOENRlCO6bj1KF4laOHrV5cKUSvS9mDw7VTICz8UlUMOcN85w46SXa1OqLOmf+1wGGnmaA08Ojzi4fJk/KSviuXOslku863O3HMEHbuha3vLgvfQ5wTlVr/ropOblz3oaOlEBs7mzUkJW84XFF3ZYw1Sa6yMM4leQ7ARksURFRYj56PPZjEWxzcRuvAajOAnoDdua3H+3ncTp1GsqwkvZjigX1OKQMMsYTYwPL8mUTwVFuRcapUyKC8ReRc4xFQnJx5TuiBemzFYfYLqg0os/FgDzOfroB+RM60CMon6sUZl1SO5/l+Ki2GFUlSQjzgt1GOuhjJio8F4KRV3f0bZr+nYNEbS2aG0Jbk27jqhYUxUFVVnI98XcE+cw6XlwzXpI6k2yGNmZzokh0DZrdIhELzZFzolFE4ltk9sDjNGY0uCcoW1XKOXSd0lLioinJEVM53A+0nmkx63vUTqKp2ZKYkc7im7r/oo9lCcoRegDITiKImKsmIpHJZYQZeoF7tcLrm6Pje1qQvcY2YaFKqbgNdEGbFVRFoayNIOBZrdeSvXIB/pWUJEySX6boiD6gKMnhmY0rjQFmArsHJTQ92zyAfPBJzqQ5kv+6c9QFJbJbIa2htyIrrXiGS/8GhF8IOB8T/Q9x6oFxNulWS1YLxdMUvAypDsRXPDERK/ymxECIx1Ja01UcUDiYpQJ9Jsfup9b25YXHB4QgPNlxRuuvRGnFGstyofRR/ANQ3BGClqCJBSRmAQqxqRKki0FOPqul2rkRuIm7+tk+J6qthnN2qgRK8CruE31kwOQpHZIsUZwbrjvShGcp3d+CAStNdSTiVCtUtWzKkum08nQ+N/1faIvpQpurqwrQT7zdY8pcRIKmiRSRVlS1TXXXnONoCNNw/HJiQieREmqcyW/bVoa2nSsElgoNfYK5aAk9yiYASVJwhldK2b3fZ8SOsXu7jxRyKSPSpLpmKqmSerceZS2mNSQLuqSEgxkJHHoY9EazYY5qxLbiRxUtabgIVuORsYpkLXWcE81o9JIb0hVUVc18eEHecV7344JkviZGPnQfM79s50UAIsx7Kue/HRaL91YOso5r9dLdGdTsilKrFVdo6P45kXXo7XGdR2ubYh9i4qOuiyY15adScHuTi39Z67m+PiYvltzqVlKRdhaQfAKw2S6y2xW0bVzHn7gz1gcH+FcS10WVFXB7qxG13Vq4jf0PvLI8Yqm7Wh6sQZoOsctN9/Czu4uZ6+5hnXTcPHiI1y+fMhyuWQ+32Uym2FMQbtecuniOSbe8bRXvpxZ8Oz/7n+GCN3+Ge7//BfjNFx85AK9NUDAxIBuGyaTiuAt3jucE+rUcrkYJPglSLJoW9D1ga73dG7FJCi0ER/CbCEQESXXEBTWikGxsTJO+t5hjUVbKYbIcxy2xJHGwDzVQGImGueO5A0qHNuJwYhVjXPM9u/j28HHIXm06Xi0kmNsGvHvAkVdC4XVeU/TrIkxUJ+ZMK0qXC/XKiKInNFC79JelGxrrZKin9Auu86LT1YI9J0jomhax3Q2k3kyB/mI12QMkRj80CMknlzJnD3C0GSpBtxOkr18Hcb8a0wwFKAFJSyrgqoucfMZF+YzDrouofZSMYvKc6+q+UBdU+htzy5jFFYpnnd0zOvffefHwkuJKN53/Rlaa1CP8qHDsuCXn/Z4SdSybYxMXYRothgEMZ3H+D/p9FXuYdvshzNjIJ8SM2NOWw9kdOt0ASEk0RyZt43KCYJO1yCNuZj76aMkoUqDT2NN554usbYYb1q+bQN0l7NNolYMFymdn1IKveGjKJfDSwHZyZpnbIExFltoJqoe0LiyKlmuxWLEAboQhNw5L2hh8Om7HN41BB+k19NrgvOU2oMJoCqUiVhsYhp5lsdHCbUupAigRZCqsJoYHOvFCf26QfWOSht0Qrd719E3Lb13QzwFMJlO2Nvfx3vHyeKE3q1pg0fRUTSGxUKQO9eLvY0Lii5MiKrCFhNsIfT3nZ0JdTmhnk6o6pqyKOj6lrZpxFcvKII2aKNwXUfnehwKG6GqJ1SlsG2ms5kksKn4eHX7+N+uJnSPoU2QlzAIJuSeKOd6UND3jq7tBxU9SGiDT/4rWlEYk1TGIq5vpTplCgwKlJHgXqdWXKUIRLzzSUEQurYFoiwoqeSsUiBpTObDB+GkR/HJC6EnOFFB7LuOSVVuZy25+p3lxTMSE3NlPH0qjskYCq51Pa96+AGes1xwWBT8+rXX80hCE0fNkDh8f86oFCm4GBDPMfjPFdx8XDlZHfafIbW80A20mBFNGpBGSIHgZjD36AFepvu4tLiMieF47zOVwyQz4KIoUrBqUkAqi7HWCu1H8Y+YDioHq5t1dJVe0lpUKHPRQMFA/TJJMU3pXCke70GuuG8GMiM9J+1XnaJfQkreRgQvxDAY+VZ1NQQ+nUJUXTNiGnNzuwidGC3IX+omHD6Tq+mk84iM5xYZ9z3Q7zIizTY64wpL1IZYlJjJlHpnh0t9zxtmO7TNiuA6ym7NZxw8wrMvXxoubeUDr7v0CPdNpum+yDXUSVhoCKWG4G/7vsgzEDiyllc9+1OZTmsUkb4XpVhrLYW1zGZT1k1SpO07QtugVGA6nVCWUlk2WlHXE7q2kaKP6+k6TW2EmlTYQsRErGYyVfgIzjmatmO5XLFaN0wnkuBOp6IkqTiS/kDvIAaMVijv+Os/+ePc8tEHBOmaTLj8+V/E6qabaTv5bAyBODmGPik5pvFalhPpAU3G0DEG+qzyFvNYlKq1T6inT4qxzjlsORmRnw12gU6iBEaboZ8ygdIiOhBHJGx8PsftVG2JzWROpXkgR76Rcf95jA+fO4VkbRVt8me1FN+IQtN1TihfRV1jC1GSbRL6HkNAKzWIwKBUsmeIIgaRkfoQN5DvJHCkJUGIhU0oiaOeVLKuuJDPBK3tYJSe0S0R91GQhJOG88xTy+lt8/Xhd1k3NCSKXpFk20u0UnjFID2vohx/ozVdQkDz82KNjJ3fve4sWrMxT4fhAiuluHndccfhSTqM7YMsQsBpxe0nq+FmKOD8zoxffc5TU+/h5njYQB03xsxp5O100pYTuoGGp01CbNSpNWdjP2P+JYW8gU5/ZX/d8NkNEathrGpZ69TGvRjX0u1klZCl8tWQlJ9ONjM8G0NIc7MaKYa2SL9La0REMZ/PQQmdMBpLQGjUBETxOYyU8xilZz+kFhEQJo13Pb1S9NaO1dSMHnon41VlNWlJukQTIHkbmmIQrQIpfrhE0UTJ8Vvn6Poe54VW33ZiYRBjSN5yMi85l+wNgiaaElNKf2BR1dRVxXS2y2Q6YT6fM51OmdQTmnbFYrkgpHaWiKhci9WKsDKU0SKQUhRUdc10PqeuahaT6aM8WFe3j8ftakL3GNlCjPQZmXN+qAxnephPFdeu68Vw2VqsNsk7JSQD0JK6rjFG6CB+vRY0QiE9axp8kCDKJbpYICbZ4SiS+32bEJjsxyKTqbUaazRebaJNKlkTSNU9V8J615Pc84YFPlPvZKEZmP3D+Q9ol4JpjLzuo/fzlLblUlnye9dcy0cnEwkw4hi0x/GPh6B9rBifrqinfpsUIJ5uRt9MMFXihBplBlpljDpRWNSAYMmpqSE5VilyiymLlGRiPI7M68/3O6bFJidJ1tqh6pl7FHIw4ENg3ayHICInhBkdE5RVjquwFYMKWlqntTHSsxWFftm0isVyIfS3rqPvO6E0DknweN0ytURvJXQjnYeYe1MgRA2JPgwkqldSRExJXjZc1VrEWnJvFOn6ZypT3/dEk/3eJIAQOo5c/KjGa5sb4UX8RhFTkDagcpDsPLZRFKFFSZAoz4nBGkM3CChAXxS8/brr05BKSTXwrKNDruv74TorVFbE2Hq29SlK5+b+n/HIAU98xxGxsJS/a+XaaEkMh3udkOHR0DwOktxD4OOzeW4ScomBwo7XOR93TNL+Q2Kv9WiBkfpqsyqd3LPR4Hi+XKFi4PyNN3H5aX+BvTNn2dndQ6V7lx81ay0hBWFyPBFfl2Kcbg3S9RtFWbOXPkRBzpX0zBVKKL1Ong8/PEthKHrFKNcAwPuAtdsqhj6MPa0hBPouDHL/p8UrthK4R91Gs+WRYnllkL55Y2OUxEqNLwEM90MpGZt5JixtCWQhFzn+zFqwxkiC6wXFL1Mvba81rvfDvjRpXki0Qp2QO+ccWtXjnDneqo2xull8ygcct9473Sv2MU6dob8LQazKoqSeCJphjMGlucY7h1YkJHUsyG2WysaURJFrbTKWx5M4N6s5P5+cSkzSkcfIkw9O2G/74XyKEHny5ROefPlY/gbFxZ0JP/+Zz7ridE4jc4+e0OkB7dU690hmNefTY267GDDsZ0gMc6KWL2dM9cp8TXIVAcTUXMaMifn5zvdwzBQV43sBxIpDqUFwmY3Cx9B7mNoytNHJ/EUNrAalDEWJJHdKM5/NxN+z63BR5quu7Qj0Q0Gm67qhTy6jsF6RRMz6oUCsNLz3xpsJITCfz9KpKrE0IFEag8e3osDpvMeFiE49dJDE5ELER/lRIaKJwkhoL9B1HQeH0l9M2qfWGo1Qm0OiK8cIs+mE2c6+/Mx3mc6m7O7uil9nXSVbgpqirjBlTVFNRMnTS4yxKleYFIehImWyMKgnE2azGXVVU1b1n/9MXd0+brarCd1jZAuM1azBEDuJowRAeaHlOecSimNSELaJNg3FNyCk6hOSnNgChSf+/+y9W69tW3Ye9LV+GWPMy1r7ck6dqpOqcrmwnFQoHGyFOCSSI7CIsLhFCAnlAYlgFMEL/4BXJHhNHpEIQjwkCAmcREAiUFBsGWKIqdhWiCu+VJXLVXadqjp7r73mnOPSe288tNZ673OtfU5ZfuPsPY7WWXutNeeYY/QxRu/ta+1r3+eTLuqycLT4UyfDvAFr0SbmTZWguAa6SUVWLKApWbLNeUvgIjTLnDYw2oJxDZ6uFw7dVaVjjqXg7/7O13DxHr94c4tv3hwl4ITw/MX+rsD4/tfBB9dgpQK8PmvOXIMi6zmoCo5ogM4WVMuMtyy9qYK1BRd1kaf6+pLzdSAiK6Z8vh6XgSarGHnn1XZCKiohhK7CpRl9FY4JIXTVMKt4tGzrMIz6vpbFN4AJHQNeV5zuT0pvTNViwDlfx46LRlBkx/zguvXjDF0UibRiV+p77LhszKwXT/rmcgWFeleBoOIuOYvFAkgqRLXaZlYI3dh2x0JdxVWTzfBBaKsAVOFMAwjbj4KmnNNV8G47fiBLgEKErzx/V4Mj1wIn5+uzUcG+Atha8SXAlNJ+c73g/ZffF9uL6FrfjRPAFuMgh1A6wJZzlcyuFDfNZKe0YdNq2UokFV4vVFmnPZS5lFohJHIoXqhqKWWk5JF8Rg7d0kNSNT7d3OD33v8s2HmMSXov9RGoz3YpGSEE5KTzUymajFpBQ5ReUufFpmxd9TMlqUBEGPQ5ICd9ub4D4VbltgSU9x5JPaWkKmIGv/Ys21hL0OuMS8fXiZ56mg+C7Kt73aaX+ruPKllZgUGEYsAaSJeW4DDvPHICbGy+MFl4m5NSSto3GYCaOEuqDivPm9Exra+HIWDQ7ut26NyeVQ2oDaC18e1BrVXmH49JfQ5tBB4MU/c/AaQxYjftsN/tMIwj5su5rXOONN1zDSGvxvfBpapz8GuuYf8aO8LfeH6ribbWP/j+6YLjJmuBA/Anvvkd/Kf/w/+Or37mHfyNP/3lbj/UzfHNyPpxhc7WDKcCKHgkhNKfTJ9EsP+uR1Hn9Y46KWtG9zpNIEprAdV8U52/6+fUoEDaHUzUg2wXdK1krDuR93tp6tN5liA96KIcK4bh+8NeKmUgUGGUDOQ1Ydky0pawpYRtWYVG69Q30nudP1j7Q4U1sCwLfu5H/lmEEHA7TTXRtCURR2Gyebogllgr+WtKojbsxLIHzol/KQM+qjgaF8zLJklxJsAFmH1NyZoUZAZB2lS8jzjePsHts3dwvHmKw80tjocjbm9v9RykGkvOgULEMAFwvlrRgCBUWBLv0VIKfJTWmBAH+DDAhfiDkyRvt0/M9hbQvSGbNL43GXxbHIwDLmBE/M2GYbgOcjQoX7elZgRzTliWi1JbRHnMDQVuHKT0r3Qs6Zso+Lkv/YsK0DKYM9ZlRimWQZVJPJjJqQaRjkSEhUsBG33GOZRVJ0k8zn73WW5bHPvF5CcvZwzM+B9vn4iymwbDtX8N1sf2OhoLUEMXAyDdAtp/TqNJtcC90j+Nu0IGCrjuG1qhq3DNFnnfCYQ8oFPaO+0g+zGQLK6vlSujWdqx2TtrX1kXqEgGP8hCCcnIex/w5OkTrUywKAeqf48lAlKWYPz+dK9AWsAbqeQ7s6qEUVYsd03nrAmHbjOg6Z0TuebE2NKGlDJqcz9EKOJ0PneVRvu73FeOHOC59gHW8a8jbtVRydZSaa8hMmqQ+hNxkeDVe0zjiOPhgMKMy+WMVQUILBBjFhGYy+Winna5A7b56prbpW1hV7uuYIAq0KL6e6PU2gUMXmjMZTfg954/QwyEIV57UznvcDgcRRRIn+m0bbjMF6k8MqvSXAA0052T0IhS2nA5n/SzpI8vxAFh2NUg0ACm9MokXC5nnM9npCTA3jvp6yoMDMOIcdqJya8lJ1LqkiZW/d5UOCCAecAG8W2b50VBfqx00jyOYCzIKWNdl6rOOu6OCNHDkQec2rLUua4bZyJRYtUEAet46ABqlUor3Jb4YjTFv0eAhR78bI8sX3231/6gzTtCKWrNUIQq54PHOAxI41jpYuu2wftVqInTVHuoV1W3dN7DQyvW24YUgjzLzmFbV/Ho02ePvEfWflynSYTgPXJqiUKjV1tlVBReuSV0tG/rDxdocgW0BlZCCOKBejjgcDjg7sMPYRW5BjotKWM2LPqc9Q9ZreDh6nn82E3fI99kR0TA79/s8QE1g/BvPznii999gS9898U1VNeEwEeDuaYgXJOANhJ8XdGkq+N/QO2tSZHrdaMQXc03Vjmzn0lBXab2PpuPrJXaQCmT3Ius9GRrq7DqIXcfRBCxNWc96kUZPTlrckjAjPjbTliWFYUJPhUgM7DMWJcVyyL2KpsmIqZpqu0E8zxL5a5LLKzrikl9F58+fYoQAla1ZzFxI6vSw4nKrgA+sUMgTUS54DFFUSP2MdZ1LJeCYUsgH7AuwkxJ2yZU95JBcBjHEcMwYtrt8c57n8Hx6buYdkfs90fcHI+4eXIr8UQSoHmZV6zbKmPtIoYwaGKOweRQQPI5aQO5AIZDYcKWGdgS5vVtD92bsr0FdG/IVphEVt0JYDDOetEAuiidwAfCOO2wrjIJOTWM3dYFr9KGe5U4Ntl5gghJXC4X+GHC7bsjbg47PHv+DO88fwfkCK/u7vFPdn8C8zwjbxcQOZH29w7E4jMVCXCcQTmDtwzOCYyMvG7Y5gXzMoNKBqHgMJhhbEfLQwOfBqxq1ULPdWLGX/nO7+H/GadKM6vVM6tSpSSeWrmTAK+0lhYEXFEogbowA0LRkq3Pdlo2XQFfKUicWqAuJ9CAnVZf0J1b+3e5+nz7vS36FWyyqF7FMGAcJ+ymCZP2l0EzkbYZ4LPKHLNlE+U8iMSYWYLCXc1iCnVOqlIOqD0Grb6lA0YGHLMq1HGlzBatshBlULLAxsC97DMQ4Xg4YJpGDDEirStevnyBDz44S5VXM9aOCJfzRX5GC4TiOMniSyqZ7SAJjM7EmUAC9siOUxIh5Byic7XKKxW3lo33RBiHAYfDATknbOsCJUrqOMrrzmcFNJuAoqJBDEqB940OpXeAXPPCgirr7wuQGAgBkcQCQ3rLCKy9igyGJ1R/sRgCvGOtxoiQR86iYvjyww+FXq2eT8EHPL19gqTgbllmXM4neAfEYL5QhBgDhijPYVJa7bys8DEhDiOmSURgYhwAGPCfW7UMTv6mPUEAYxgifIjalyIm6suy1GcjpQ3n0wkEEcAZBunvC8HjdH+PeRYbjGkSdbxpnBBCwLZuuMyL0slP8HHCbj9hf7gBSNRPi0Wv3SMbQlCFTg3qNrE/iENE8BaIAqRjcwUI+1pQF1C2ePoxiLPr3/oANUjsFHKdgjiA4Gu1RCjWYCBGD+wmsAJgAFiWBZfLBQAwjPL8GCXbgm1T17MqXWG5X4wCnXNWbywvwh86/3jn4MdRniMdQ+vrsiqi7EMoZtJHZ+dPrx0DYxbUalC/cT9WMm+Nw4inz54qiCB874MPKp30StlZp8r+8tTf6dE4A0isqsV4WAGrR1r/b38hneMfPcMALtHja89v8Wd++1v4D/7+V/DXfuqfr4D0o0Bc653rwNzVkmJItODqDw/GFADStiHz48C+dG+Tt5AqHJvKsiYskOva1caRGwg20AgRRpHKZFcXdP18rP3ALghoKSLg45YVNC/wYdTk0ACQw+3xBt4FHG82bAU4zRteLt/By7s78ctcFhARjjcCiHa7HcZxwvl8wt3dHUphjOMEIofz+YR3PvwA++Ue680BucgzfZ5P4CKJCxaRanz46qW2G8gXAxj9EYf9Efv9AdNuj2Gc4IMkebz3CHEAg7DMC7ZNDMCTthykVUCZqHeOGMcdDs/eQxj3IC8G4dM4Iu4PmiRKKOsKYEZKumba+EFFmcIIGjKci/BBqohLIWxzxlpmEBE+vDs9uu5vt0/m9hbQvSFb4WaeDBCcLmKFu0WzW7RcZ6Drg6gFSrUjdRls1OA2pxVMDjmtEBn0JEqUzsF7bUYnBrpqSs2VMteeh5IT2HpwNOj3zgllTGWhSbOBBqzk0K8rdfbvvqfqU2nDwIx/NKoqYJaeoeI6/zMdjKI0DWbp1quLui2iNmj9+NUgga9+rsfTZ4u50UO7KK++hZjV00c+wEyDLZDqSIC6b1swSeggXOpvpc8kquJfVHpIBmBWDwog1QagVFuEllkVwJ+ATfoN7Heb9lOR9b6V8uC8WxTFgAryyAuq954jOG2MN6qqjeNHXU+u4MIB7CpgrP/n1otYI0MNiizDLNdJaHzkJLng9b4umrQACEMUUYyUklBzugrpdQV7FRrng7/bsdvrwKq0WseqCwuJrkKzvnBgfSaAVEViFPBj1EShDGb1q/NqxSC+UZwLcnRwFGo/jfcOW7EAXhMhgTHEgOBNBEQ9k0yEpJTaoxLjgCpxzqK6mUsB0ga3tv5F85YKIapnWRK/MAiVD33PSTZakwAAIABJREFUJiRIBzVD9wpmJMOBZVkUyMm9Erzs35I85rk2jmOlX2YTUGAx1R60SuWUSlnyA0EbrWh4FUXJ+nq2uQq9GAWJUfLVU34dfL/ufn7d1tMTXwcK22u6GUCvB6oYrcmoC5jPOddKedo2kPbPAqg2JeJFaZVanX+LqKga+Es5w9fK2NVBt+oUbI4CKgOkNMZCSyI10PqRY8Kv/7GfRwFZq2KI2O12uLm9xbTbqQdqqj6PjM4TDV0vmO1HPdfatdPfdUmWj7129jfq9qGfZ0D+NET80hfex5/++rfxs7/wj/Bf/7mfeESb7Ct1PZjrR6HO83Uc8Wi+6Y+XAHAGwIwHV07WmCtQZ3YTHtcbt7WnA3QEA5V6ZWwYuL9CmpNyAMHBkyqyBm9pNFnvuCBtYpYtcYkl9iSBBCIEOGyFpIfaxFDsXLWHXAzv1679oY2jcw7/ya/9Q3jv8F986tMAUHttyTl4sDIKMu7PF2EveBVq8R5xGDFME8bdXgDdNCHEsap9yzooyrmjshwkgcAgsziqXnMB4/Ep/LiHD0KRjCGIHYFSPQscXBwwWaKUhOmxriuCI7E88CraxENj7xCByWsM0anyvN0+0dtbQPeGbFkplxVrEABSKX/galK3iVBEHmRaXhah5BTNzhIA75rJrlAVErZtxrJcsMxnXM4iG17yhp/4+v+LdVvwi+9+QQLaIsDOkUiYFDW/zak3hmUEH8AhAGVAJkJJlm3l1y5ellEGUIFcjBHDMGDcvNXThCqKjJRTpcVUmo4GstaXYtlRo9rV8esAJboFrKdY1gX0UarZsur69SBYYKBmlwXRPW5IN2DSBgGaGW++RoD6+mivjPcBBFSBmQYOu+PSCpoF6rbAme8P0R3so7OC4jAMtZ/p4XsFvAAgrYSyKIqxZ83U6he5Tl3vcXBS1KzVTLnl3JTuggaOq19dDcTaoPZjZr2SRAQqBc5ZsqEFSd47jKNIR8/LfFUBrjTbUjDPs1JZJRtutOb+HAz8Edo9LADmQeRmiZJ2J1QwJ0kW6eUap7H6jRXtFTQKtfgCuppEYU6QolIRUK8BvFxD9QBUytM4RKFABw/vJkxDxIcffl+e/5IxKiAwsQnnPUbn4XPBZZUK94q1jvPhsK8eicMwYV0T5nmpQMJAQ04J3gehYcEAXYb3plIp/XrLPEulsXg9Ro9pnLCpyNKWkjzX3mGIA0KMmEhsWdZtQ9pERCGuK+IAOB/RKjHao+TE+mGshsBSvTZlO7s3nErzp5Rqlcuu48fH/9eBuF14q2BUCng31131N4FgNmVEBPLqcWmBN1p/2cCqNMwChsk57Pf7azEUQH3pRIk4a2LChwCnz3VRVVGj5NtcZ9RuNjAHmV9jNIGjrIG5VvK1sbolOx6PT3sKXzd47UWs52/9gTfHGxz2e6R1xVIkyVAtazog13I87f/2+w6atvH9eBz+sVsPxl/tRvxfP/w+/tTXvo2/9PNfwX/7L/+p11TmrkVSrkfl8cD0YO5RIknPo0hGt5sTdSeu7xRsFWRPrTrXb4+APPokiCQTHw+WznOaBPHOI/oAH4Pc0yxJPThCStabL9fFee1TcwQOAY48grekr8QiThMM5muac8Y6DDUBBVC1rrG1vhTG/b2Ids3zjJQTAkk4nHLGvMy4e3WH3f6I/SHCx4g4TCq+s8MwTYjjhDCMGIYdQogoDFXjLSAXEaLMP0McZb4eZK1K6oG6pgK/v8G4PyAOO4QYQSCcVF1z2xJAjBAH7G9u2j306g6nywI4oJCHC6NWwqmyCZi1PxiEMIyvvzHfbp+47S2ge0M2Mw039MbOgQoQYlDhEvVUywUpry0LqAucNDizZtIsldmydqUwqBDW5YL7V0JD45zF0JeBn/nVn0dhxv/xUz8kQX1J0hMXxBA5pw1JASNpFY8AjDHCO+kJ2pYZGzOYNw3GS11MRJHO+tdaMN5//YXvfoh7rx5IkAWu5ILss+WL676EllhqkFQDrKtMpVXLbCzQ/Wy/YsN6j4BT3T4iWhBQZ+CRr37/8F+twGM9Wx7OtfMhmNSy0BOrebgerwD4qPdKqTRIU7bsAwxT6KrZ2lrP00CBO7BXcgWXdk/Z60zdMviglRLJXG5bUiPydn5FhS/AjG1dUFIWOp4FS4qwi2Z6iRp9yo7VxswwdK16UR/StUDIO4/gRexkHEexhdhEOIQtGWKZ5ZQwK63NKl51PNAHQj0tr7vWhVuFpX+1jq+D+XVJxjpo1TW7jHU1Gl5HA7YsuDe5eGg/iSz4IQQRyQnSI5lSqsBkmS8YhgEDDTIO2iO4EJC2di04Bj1HV6XsY6HqA5mLWAdsW9KxMmqvqfJpYiVL/9e2rUJvjYMEcgTtqVFaGsl5W+XOpMoRGCF4APIemUcKtnWTSlWI+jyLg3HRazTPFzAI4yTZf3uO7T5PaavVMAGaDqIfkmt1jEiCzcTd2NdA+PHz3uYnA28GbPqKiwXKDr2diVzfFnQbu8LumZpA0MSODx6hFBQN7GwOs2ojtB/oCiaSVsofJFNs/rCv+h47b9eC+zofaGLM8lWNcmrH2o8JXf+bUVVmH1aV+mfDDLRBqAbyt09upWdpW4Gt5cx0pzIn9+DY/mZjX0Hdw+3hs9xecyXpD0nGoXuW+3O83+/wy1/8I/iTv/W7HaW/+yJUBVPZhR2NrjGFwSj1vO3vtX2AuTswE82RpFo/R0tV6xrQ2XerzPf34/WAyA/N/BrXX3Ws7HV2fm09lmdZ3mDVrcy5JQZKrgJYxKy2NNJzL9br7YuZsS1L9XiL6wAGq7ibV/pxvgK88zIj54xlXZFKAWWpQm/bhmVdtSIXtT94RIyjzGMkvdpbKaBSEIhAPsDDIcCDckEuEsFk9shMKPAgL+8PlAFK8C7DhQHkm4AJMyMxsKaC1XraHTD52IC+j1p98yAH+OCUARGUGr4i5yI2LuQQ36pcvjHbW0D3hmy5iOiJABKHAAZrRtlr5ttMZuf1olkvpcKReNC0qd3Ai3nZMVKRHotluWBZV2zLivP9CdM0YZh2yCXX9xIgkzUXEEcALJ5UKakxq3DFPQjjOGBgj5IDZgAo0qNk9CqTPY9RqiNCTYRmZXtaFONnf//38Ddvn9TAh1molSU3sQgLHHMJoNwZgaMgWW+cVbUYHShqAM+ohD2Qu86YGvrqo4CPA2yvCyH098QPXmfUHdRA2DurLqSWISeg+i2RnLf0zMgSLAHvUuWRvTehBF/H0w6ZQEq7FPGUrFWrGjgCSr/TLLQKpDjvKmAYx7Gqk11qM3vRaoUc67Is2LYVnDOKKrJeUbgYai8gx2xBJixAsGy8Hrcz9chOOc5AuVWEQgyyqI+jiL2sEjCAnYIUET8pJeNymVtlkCzYfpgYIWylBRZ26cUIWGTx7f0yrnJ/ZVKadDBxGVnE6/5r1CrS3VZhizGIxyBnbGlFzqlWradpwrjfw7OvhtRb2rTfiivwAhi7vVTZVjdjnhesaUUsGYOKatizMwz+inIqthWbmLxnBdpWlVOhDFH+JCzLKnDIOQxK1ywlwxWhWDsHpQVK8mnLK5hFSW7Y7yuILyVXKiqRwwBCHEbEIPtcktyb5/MFIKFRMXlY9Rj63KzrpgAoYhyhFcaIZbFKqySugidsr/ECu67CcfeIW8WHutc1QHG9nwbqZL7qwVL/WW3fRqcNITQ/tijiVFnngLRttWfWPs9o3ZYMIP3Qeh/ruZScq1gTFOChsCqsthmznSO/5jivt9eCuo/bLElj74GAoDhEPHn6FPPlgld3d7CUmkHt1+zmtcDtKq/yg46lnUT7p4Km172diHC/32GNAf/R//yL+K/+rT+H6ilH5mXazR3d7gW0SW+0vaYmrtBo/DaGloxrvbxQ2xz93gO2eg9aUq/1boJdTU7asy1WOlxpoy0p0p+rJccaYPVO7i8vev4i2qUKuQVJEolsoF8ZEXbfQ9owohPqpomvlGKetQJoTOl1v9/DkbQG5GwVOnkW122TZyHLOpKQQVrFX7YN026H3X6P/eEAHyKcjwLkUgalFbx6FHIIAyOwJETHMCEXxmVekLaMvGZsiSGt5lGrcA5MEfAeTAGFCRJpOBQUbJmx5IJ10x5XYowMBEgSlJ3QQEGSsCPHGFToRcRbHBhbTUwPbyt0b8z2FtC9IRs5B1L6AkHoNcMw4PnzTwloGgKWecF8kWAaWgGzlW0YBlWW40ozM4AgAYcEB+vljFSAdZ5xOd9jiAPGcYdtXeCcx7ZcsNvtcPvsiVQGmcWweAaET1mE8a1gy8H6hgJmzljXGZM24TOXOmmN41hBi1WYkkqfE801+DhZNlyBltH4ahXAO+3JiW0fSQUi1kYjk0y2BdN1lGXx0ow4APWdaQpwTD2Zh6+jiQo6bG9Xidar31vg9KDOcxUwS+AesJv2CCFWuiJg3mW+Ls4hBByORwzDUCWfX768w8uXd2oOXBQ7ai9jF3wSkfiXdYEFUWvqB6NK/YssvpqiaoAS44BJ/XOMznU+nYHUrkvOUpFzjjAElVDfJDAlkj5P8g6OIpKKLlg1xD63BssK4sYhambYw7ygWHwrNKgo2JL0p5UigNJk/aVPoymbknPVAzAED7B85m6300pTQSG5B5ZlqZ5pgRw8AsBJaGleKkpOQfiWcvMAhFSftlXKDiEEAWDne6zrptdeqljHwx5PnjzBbjchBo91nfHy5YdVIONyOYv3EqEqGCJIP2LaNry6W3H38iWGccA4Drg5HlRBbsAwzFhmoSQtyyyG3cMoAc24U0qnr+OzLDOW84x5li+TxhfKqgShjkR4ibmIbH4cMESPkhPWnJSKm1E44eb2iPl8xuWyYrmsmJkRQxDAtROD8W3dcD6dcdrOWJYVu13Bbn/A8XhEWDPOlxn35zOcjzgcdS4opZoMhxjw/PlzfSxZExwzvD9gGEYFjCvmpWCkAeO0E3BTzJgZdY6R+6dBB7un7Tns+5KAViG06h1zd591QX4PgMzA23uHYQgIQaogJ2acTqdKeXXThLRtePHiBZz3uLm5wfF4RMkZl8tFKLf6HHrnqpjKNE3yzBXGq/t7eCdqfc57eCJcLmfE4LXia1XhghDkuco6B4YQriir9mw93qz8iKs5Uf7UAT+dY0qWF8cQ8bnPfR4lZXz/e9/Huq7wYOml448GdnU+s4Qb9fWqx1VCA+kteWOJvev0m4GqZj1glEqHr/zRH8ZPfPVr+A//9s/jv/m3f/oR1bIBfb763JTWWvXsqZoy0bbPte/t6xooX7UEPDi3PhknYP5hTx1AXpRQiaFUS01akC0FLTFF5CX2KCzqjCyG3zBGhSN4CphGsQUpWrVjOBBlJEdglr4zOkR85t13sS4LXvkT5nmR+ZgZW2aMIWJQk+6bJ7cg73E6nTHPC7Yta/8u49XpDEASQHf3JzjnMQShTIc44I9+6Y9j3E0YxhGX84zT+YLvfvghYhQ/uGknwihwEwoNCEUUXOE8/HhAGOXOUfiLOYvnnlG4gwtIIJzXjJeXu+qHeTwc8M6tKHCCRQzq5csX4ueqfnvwg/RG6z2dEZARMK8r7i8iQBVV7GpJr3u+3m6fxO0toHtTNrJFSAMFiPDD6XzGsi4I0UvVQ8UKbBmzXrdR5YBD0J6RbcWLFy8qR905UdF0mo0jCF0q0YbgY8suFgnCV29+cwUpbW2ZtYx92sAl43QSwEhcsK6LAj3rY2oTlfHGW1/GdXbzMynhUAo2luxfC7QKMjLMn6uKCcQoVadFFkpbn0TaWEUGcrnOJOuLuLSF1ShztT+P6WrRvc6uQv27lBYCy3CiAg4AanxcII3+XWXQGf1UwYIKh5Azvckuw1oY1cBc7w3pkZLPtsZr69kq2n+Zc5bMoIIiO7fCBY60eqd0TqMs1mw+UCmf0jtn91jGPF8kaA5BqJQErRDJSFSACBWsYa7m2BaA1Fy9VR1rxliXVOEyCbhCRvBRExUDoOBi2ZJWIlThkqjSKdd1rZYDErgrXU4rg8DjbLyB33qVrZKhlY5CADmtgJNUQqNml6WivoKTBj1AVREtpUhPnwVeLECiFAKC0I+l+pxQFEyLSIgE+mb3cLlcEKNQLwERyaAYKnDNKWFhsUQwEZoQAjBNGFaxBOAi904uDHIR5MXewnr0ilK911V8K422akbs5pmX9Lm2Ocd7pwIJ0r+Vs/bGkShbjtonk1PCsszSAxh7xbmoPW8s0v3rWtVOrWfT5sXSCRaUwlJVrCaaDOdiBXZWJYwxVBAYo0jjlVqWl6qiJcDanIR6/docdZ2aaYmIdjM9BHH2Orvn+t8T5N73CqrNi9HDnjsVFgKwrSvOavPhO3BgvZ4htvOmIq8ZBhFfWLcNoZR6vxKhrgdsFOjSzrmxIOzvj1NS9XUdoPooqnrt/66FOnnHMAzYHw64ffIEJWfc379CMYoiqHu2o44d2rThpAWAu8I/UVd5arSEq+vTfsl20A/A1TWYIyKsw4Cv/LEv4id+/bfx5d/8Jv7Jj/5QR3XVXuD2YarbQloJa+I0VBODfTJQBtAZQHUPnC65rX8PRrX9szsV8MPXEVAciq1h2gfMjCo01J4fiNgZOwFlClK9D7o+2jUnmT9svtRE4DgMGJgAODB5+Mx4cnPE09sbEKOyC6wNg3PGNi8KHoVmvW5C/RZfRa3QraJFXFiiD+c8wjBgt9tht9vjs5/7nIClwpgvC9Zl0XXW67oqfZkitJTBlEEuYAgRx5snKJk1GZw1JvBwYcC022Gadki5YFtmUdDU83fOwYWoYiwi9ASXAU08Oh8AD12XVqXoyntF9KkIVVTXNKF2Pwbjb7dP5vYW0L0xW2eS7ZpB7Mu7OzhPdWJw6GWjnXrMMeIw4ubJE+x3OxAY82XG/f29VPM0QGdy8PAgNbvlUsQCIGTji6j4yYpZ+5yIpZ/OqoGimJmQtw0lb9iWDQQJWEV5kqtJdU8vsUCkp5v0X//5d7+LX5omLNp/YH0uzCKOIhljVfX0HuM0wvqjGKLiGIIo9C3rglQkKCXn6uJpi2phrmzKln3vAwHUzzdpflbqUlVQtNe7PhCQzynJKG1db595renxBzURt3OqKoa6ghZYfyB0UWIsywpAzZi3hDVtGOIA54GsBs05b7KoOFlsTdq/9YCRBEdZfHwMWEJBoVS2XKXdQIPH0/kEgqvBE0E8tWDXEwJqwaw+WOJ/lrxXGlnru4S93pG+H/WeELNkASs8CMiZpp0Et0noNhWoFjGBzTnjcj5Xg/SsZtPg1g/YB+g9vZaL6NrbcUlV2Qk1NGdkvW88SQAngG7AMAgYaWJGch7eN8+0xbzXLIvP0Hs7oPWlmt1Gkcq2Bt/LsmCeL7icz8gxgqehGs63Hjd5XrdNvJx2u53YXmj/3bSuVSFuXTeAMshLL0iMDOdDBa+OSL3iZJyz3Qc+CN0KAGdT0hUw4byCpCQ9c5v63wUnPXNEI9xK2ADM8wVFjdGHYdAewwGlrNVywLkVw7gijDtJBth5QujoIBGCKkrv3e12kGRVs1a4XOZK8Q4hYksbtnWFo0EKR1kvBbHMg+oR1+YiVwGr3hJ6fdpM3XrqugD9QYIKMFq5iVfUN6OCBy+gNeeMrNL2XultURMV67ZhSwnjOGK/34vqpV53AGJxUEqt1Flib11XUbvV+2mIUZMACaVYRUroovbvHtjUuac/8W6TOVWfI6vI1fHgel24imu1Pr8YI/b7A549e4Z1WXA63VcwB5vzCzrza+tzZqXbo0vKtfnIqnAPr8kPAp7ttari213LbRjwwTtP8dP/56/gq//MZ4Umrpm8h9fcQE9T3+wTSA192WhVwEdCDbbEXf/1GNC198kSY8AvX10dgMAkpulCC0Qd3xAD4D0I0uNl1W8qhEIEcJDRCkPt07ZR9NH6Ohuoj4Oq1ZIXG54CPLm5wf3tbU2ArkF68C1ZtK2brtWivk3q15ZyAlRwa1s3JTOTgq2IOE64ffoM77zzDj73uc/hfDnj/nTC978napiAnN8QhcniSPz0UhZA56NQuG9vn2JdEy6XGTnPklQhjxBH7Pe3uLm5welywat1k2dT+8e993AhACYMpVfWeS9+d9SEc/I5S6LN++qVlwsjKMNDwGtLAr7dPvnbW0D3hmxWeQJM/VEmOak2oFaLCEBKWWTLnbUcqxogxDtGgimH480tiJwY2DLAcHBwSLkF0Y0OokGo0tZIufQW2HJui6WtW5Z5JtbggIsudHZW19lqW6Balr9tNyXjN0PURYIaoKuBsFKuinDqjT5nY0eewE5WS6vcmNBDrRjqvjLluhhXsFMPVL8R1/dSd/wGRrjLyF+FdlrJkSy3/EICJpGEn4wu5VvPmoFFA3sS0KhaqVYmSy7Y1KfI6H12fqwBhohCDGhUOauKyoIDrZQZFWocRkzTVJX/klIV05YquIP1r0k4hhaOPNy6a23XrKbnVdJe31TUwNhpv9/Vde4CMum32GAKeEYhJmdoXLPiSqNjtHFo1WCuwd/DHqBKyYXZPqACbAk+srHH6jVJKcEpgMpFrTxKU6dt1Q4dCbO+AKrYwKj+YVbF27ZFqcRUXyfUVmCZZ+ScsMyMEiUxYEIpQ4wo3iEXmTfEHoGrvH3U6g2RqxU6M//eNlGfbEkSsRYYBkkybOsq78mNNh00sy9AY0FOO/F1ch7sWYQu1g3spbosNFERZpkv0g8DFkEnRGimOupYsPbZbMhwSFvW3JZHDANc0Ey93uvMjMvlotl4D+9F+dM5V9U+xQfPowSPeV4rZbYUTQaoWmYgqobF7do1URhLhPRFn9fhnNdTE9tm94z5MToixEGqr+fLReYa5zCQ0sL1HrF+17RtgF7bpjZb6n1rtgdS/RPKpd0XcZBql3dNMdhsJepzqufe9wHa9roK5OONXvOTQq36fMi9NgwDdvs9xmmCDwElpQcAieW5JgMONh8r2FEY97qj6Ypvr78O6GFgB/weAEDbfuf9T+HLX/0a/vJf/1/wX/7FfxXczS+tn9ASAM171eicDzvX3v3uC/w7f+sX4BTcMwFf/8L7+Ls/82fre/vvrz0H5isLmutbz8D6VcoBlmDkUsCmtlyoJja7nYvYF+f6TiKrKhuIceJnZ32FRDDj0kCE25sjCj6Dw+GAJ7f3uLu7w3K54HLR3j6NcViTaoU03cfAf/bDX5JkWRFtAWbGsNthfzji9slTHG+eYL8/4u7uDpdZ6OnbtoLIYb8b1c91AoUIHwZN+hUwEhge87zg7tW99CRvGSnL/J1ywbysOF0uYHKYlwUMkr46nTuCVeYg62XOCSlJstY7Dwoyv+92oupbSsFWlXeB4/FY13iht2949dGX+e32CdveAro3ZDOajQX1triY0Ieua5Jxygw4UyHsezykfB/CAO8Dbm5uAQB+WbBuGYBDZgKQVA1NRQyoLVDzPIuNwCh+aKyy9+Y7B0hwzg5aAVFz6VJEYrlOTq0pHECtPvWArgeT3btq8G3VpCtAp6BjU4U7AydGELV0unMO2UvVihODs8rzM4Ny1wOjQAJAzdwD0CqmeZ2hVqLsM1QEXIM8rTTZORABaPYMArQixlHoIkZls82CWQuwLZvHpYiUNEkgyPVekE92zlfDYoKpfwrFxMbKXitZQuuplEB5GAdMOwGYIMK2ieCG2A6YmbgEYP0VqmIHXYYZ6LLkQHdPchsjHWSrcFgwHoLH5TI/AonWQG8hWM5Cn3NQRUSpV1+BN3lGHJhK9XVk7oRwanWuVSmssR9ApfNyKdhWRYz6vpILEiVYxa8U1LHi7rrY1pIABVCAM0S5D2RRL1gWUYQdhwEcfa2KjYNHDF6l/rdqW2CCKt5pEoPlHthUPS6lDVE9DWOM7T5nBmvlc9sSvNuqGI/1jMh7BgQfqmiJcxk5e1HVHEbpRcybis8kDMOoFU2pzm7bKpL4el1J+//m+aLXr9QqyDCoCb2TnlBmxrqucAxVoROxnhAjgvPVdkOeFwF0QhsdMI6+JgmEHiz31zCIGfv5MiMExj6MUvGrwErGsWxrew77CigzHHfqhmS0ze5eotZD1wL8ehfUZ8aox845wJMqhooQw3b3SnralAo7KsXWqs5F1f2ksif3Sdo2ZJ1HfQiAvjaoEM6kvbbrusIH6aVz3tcklgjftOqynYtV0yXh8jEg7gFyovoEtl/I1KgURDbKudxP+90ek4otJWpMB7PFEbVOBUb6cQ1I1QKdzSpXR9EVxK5fUxN2uJ67PhKoMrJz+LUf/QL+uX/6dfzlv/53rkBd++yW8ORSMC2r7ldmqT/7S/8YP/GrvwkAcLng6z/0aZz3E4iA599/hfe//d1uHvt4MGd/N0sU+bkH35JcJddZFNRjFaDGRZNhmhR8uG9Z70q9ZqaC6b2sfKwVQHTPRR1Ccri5ucH+cMCT21vc39/j978T8fvf+U413gZJNToBjUXCss/f2d9iTQll3fSZZxzHCYfDLZ48eYbj8QbT7oAXL15gXWZNigkFe9rtxbh8mgDn4fwg1b9cUFgA3TKvuLt7hS0lAOL9qZlgzMsKchekLKIsPHiEYZS1VUXBxBez9WpnE2cjD++B3W6HJ09u8eLFCxEKU0sSIsLxeMQ4jiAi3N/f43w+/8Br/Xb75GxvAd0bshEcoos1ay1ZZ4c0tsxl9GIonPKGbZOvXZRMvvMR96cZ58sCo2KltAHwGKcb7A4BDKjvD0RMYZpwOBwxjXv8lS/9cdzdvcLx/iRiArM07Q7a5wUu8J7gfF/pKCi8ATkDJSOXhFIShkEpGyqJzV227yr4JmkEd8z44rbht2IU8YwuW2oqcIULUt5QWLJi6zrLuFELErwTI1QJUKXal7YsvVVu1cm3mXUbLqmRAbfjs0DCGsO7C1UDdwMqzIyUt6urSYQanA/DgEmzhvv9HoCAFQNX4zgiasAchwHLsuDly5dYl7XRsor0KBYW7z8w0qsfAAAgAElEQVTnWlVGwIT117hORMbXfqSUmveabKzjuCjtkJCT+JwZTYaZVZY6aS8h1fOtY++8jl8H1pOI57BRrizIVeArIjkD9tNOfYMmfOtbvytBRGnV1ZQyTqd7BWhQwE1wWbKkzvsKGmtgCu3FU0GZ0lHqUI9bKwVOKTl6PxiomaYJ995JX0lOSCmLvhmLwltKqQZLVyDfAimye0n6RcAMTw7jGLHf7XA8HnA87gEGltVhXYVeua5iEWF9cMMQ8al33sG6LjifTpiXBefzCcf1gHEaNRiOGIJUz+Z5wbIuWBahTu4PB228H3CMIwoDKRXtWUvYtns4J0q1USW5x1Hu1Xm+1OuZc8K2EcZpgnPAsq4gIqzLjNubG6ncEWNdPIIjnO7v1NdpqH2ih/0eyyJVv2WesS4r6FY9BEfJeOdcsKxSGXUhYGfVY2acLme9x30FQcMwYFlWrOuG+3vCOBbs9wOIpiryISqwpdJ+mSEgT/sQtywWCiH6mjlPqVG8rcJK8GBvPVH2BFWkoM90ExYJQXr9bI6zzFQpGUIuCLXy+eTJLQiEWdVjtyR9oofDAcNuB3JOfr9tWLVi7WJE8B7rsgDQxJz3GLRC6Z143MlYad9r0KBUEylXQkS65dT3Dmp1/+MoYVex6HV1ywMolkxQ2w4iUafdH/Z491Pv4nw548MXL3A5n4S+7lxN4pmxfE0OQnuEK5rTz6d2HSpoe4ipoY8/G2XRWCCtL7Gd90Nwxyi+gbq/9N//b/hr/+6fB9KCf+3v/fKVhQTA+KFvfRe3ry6VxQEAp8OEr3z5iyhOLIlyDHUtWcaIH/vV38Jnv/EtfONz78EqkFaHRJ1iRGeRQMja4mDV1MrsRlufq3dol7zMpQCFUJxD6Vgi9fVO6OyFAE6hUoCDcwjOY4oDpFeOVK/XaeVbxauc0Pdv97c43twiJfGR+91nz3D38g7RR9yfzzidL9LfSw7EoqC7KiPED3vEOMB7rmJxX/yRH8HN7RMcDzfYtgUfvrjHcv89SWJlUciMIeDdd97BOB2kFzdE+DDCDze4zAsyE3wYpcLGwBAl/rm5uQU5j9N5xul0RoHDvInnZhwGUPBisu5E5VJomua1qgkHRyhJ5pmzilk557CbJuyGUZlWWRLkSZI6DoSoPX1vtzdjewvo3pDNVASJqNIpa2ZdF6EEqdpIphYY4gCj9xn9LllFjVkzRgIqvBdA57ygmGmSxuLD4Yhp2mHbUg2CLhcgJQl02HETD2BVnSyq7KfKilqQ0lpdW/z7zJMtKr2xuL3mP37xErMjfEcrV1feOaoKTn2lpJj/Gmtwrgp73ioS1nuhqpgxgCEiHTk1dbC28ovQdMvgcv2LZYcrGMCD5b5W5q4XdVRg2UQ0TA2ynYPITueSAW0AZ6BSHiUQYhRnQMSpbHa7N2pwUu0KUEGkqdwREV68eAERWbEv6UMqpWB1K0BC6zSPNqFJuhYb6ed0iPBBZa6vSMm75HhlEbQMNmvK3PZF3XjZONdKNEu2O6lgAoFA3qH1Z7ruCupXKWAFu9dBmryQ0KwyzJ/OrgUAOCcy/lUhVilvqs/RhVlacUBN9df70/Zd9Iu6aya4UlUEnVOKo1Tnz+cTtm2T/rJBzcWVRjiOI8gRgne4zBeYpUWMGSFH8TSLmrRJG1LKQteM0sAfvCSLhmGUoI7t+VQAk4ua5a7IJVcBjtrXCevbMlN4XEWRQt8Wtd3TiTWBUBCz9HhFFUMxgYSSiwKPUIFaVX91AS4EuBBBjurxtoqPPD/DYIIg8ixsW0Ipgz5rVsmDjt+uJlFKlr4WMCRhVDJcVkuK/n5pj7hUyCE9RpU5cPUafnC/GSBq1S+5v3qKuwDMEAIOh4P20kiFfFkWMYQfBsRhqGATWuUDoMIMUmVLOcNptdXrVZF7SeY/8bqUsTRq6rIsygbxlmtBKRkheu1V+7jKwcdXFa7HkK4mzaJ2J4NSvne7XZsTLZkmO2ljCrvnWH//hzqsq0OCVp5eN0/ox19txTv81uc/gy//02/gL/6tv493v/8Sw5aQwrWoxf1+wq/9sS8oz7yHud162L1+3o344N0n+MzvfQ9f/+ynris2V8uKJNg0f3Z9qg+qxoBSgElN5fUClyI+cn2vrzAYWhW0tigUBVytJifPvopXGU/lys7ByVoUtD/akXjUHg97vP/pz4CcxwcffB8lM87zDCaxExgKgeGRcsG/9+2vwTmPv/GFLyMOI4ZpwvN33sNut0eMI5Z1w/m8IC0rUpIvUdv0kkjkDC5FFCu9x243wTmPNRWkImJwzrFqE3QqpLWKnurYjV5UgeHNL1BGyVn/uRPV7aSJqpw3LItQKYu2xoQhKtNCGAiWYFwXsR1y7qNu5rfbJ217C+jekG2Mg/TNsHLMnRM6g2UsK5NEFnSjVPV9WGYobeunj5IpNo8xZsmakvcYpz2maS8Z8mEU9adxxbCo6EYSRUUTEDHRjlIKMueq5Og0y0gW6KmnQU8fsa3PhAJN+fJzacOvDyPKg4yinTOBKhXSwEjpvMKE8qTn5z2cg5h6aiAdvNgUZJdRvDYjcx9sMWC0j9dkeCuoAz9a5Q3ItOWV6nukyjJU8RM7ZxNJEbqoSubnTfeFCjIMRJMGVpZJtf4I+zzLMrdx9pimCcfjsQK6u7s7tP4OrdKsqwiYOLl+UmnMmvTuA9vr/qGr33exSgW+Gig5L6ppyGbWbWNlGXVNEqj/Wb0eXYWg9qcpcHdQlTvrTZMSgtwqffUX15dKQKKZBEvWXzzqUq3kAaX2eVkfFkqBNrGCJXyRU7QqAfXj0e4FtuCJjRKnfbHOKhYZ7KhWc4iA8/leTbcl8xt8QA7yXMUhwjyiTqd7rJq4ME+3ye8qVVvGTZQjMzNCKeCBEJ3HEANc5QxC+wJXMRlX8ZRqFm6ZfQ206++1qmPiIazAm0iUJa2SkpU2DGaMx6PmZ6TqvmYxgU8hwWWv97QqOcYIF4LYuKgICLmmQGhz3ThElBIBUA3CcoYCFsK2Za2SSU9iShtmTWI0WK7XiguY25xR5y699+z+JbruOwYs/dOeDeqAJ3dThiW0+uoXIICOdjJ/2Zy4bRtonmXMNMEXQqhUL6OseydU15SSJEOiqJja+DsSdctg1cZSAG9WBflB9U3VcNHuo/55/4NSw2wM2s/dJxCq+nAcBkks7veVHl24wFO/DwN0LW2ms2B31K8tyOkP/LjgpomdHshd/Xy1/+treDpM+Nann+NwvuDl7R7f+COfwuOTteTfNUBsqacHB0tA9h4//iu/iX/w4z8qomh1rK/uLlCXQGx7s7URFZTYsVglzRKAuSQQnL0YzF7vCUuCQb1CpaIkrBdcATonk6msGRpsWE+oc07tEghQVo73Dof9Hp/59HvwMaIUiEVBSmD1h2N4gALKsuKnXnwA5x1+bveT2O0P2B+OePr0XQFWIDC/wjJvyMuGlBaktILIw4eoPf8JJSeAB3giTOMoCc9FaJxJ9QDqteY2G4BNUTfDeQGoPngwde0XCl6HEDFE+VoupIwoVhZCQXQeQXsFS3YoJLY2BugkcduL2bzdPunbW0D3hmzeezHyBNdAyjkPP+6uskgEVIqDqcAREYgdfBQaWdTKkA9BKT5Je1R0cdZqjBhTF5zOM/79X/ibSDnjr/7YvwRAPhssioWZc1OoSuLbZhNijAHaEgIRZ2Fczq86wCSToFWo+v6xZm/weDys54IfLoBAO4+r33WfZ8FB0UYBQIGN00y66z6bazXFFnrb2uLeBXcPjtH+1QcHVmkYx/FKybKB7gY8wEqDAcCbqnEVpSgR1eOz+6E/XwsyHwUMRGq6Ha/EV6wCa5QeFEYG4Fg8iqw6aRngqmL3KCJqQU5XkGvBpy5iIQRsBCQ0pU0RmeGq4FeYxbunu34EU5qz6ywfYNfDgnC7cfpgzMbGrkkfsA5DrNdDpPxXoaKhiUWklLHkRTOp/IBORddfNfC8Tunz1f3HCEo/HAahyZWScZkvVe3U7o/j4YhtkP40eS5P8J60z9WqFITD4aDVpYxt46rmaj0ewzDA+VCD5LSJulpOBc4JXTd4sawQxUgR0wBbn6oC2y6wJlaBoFLgg6/VO7ufclXAZMRh0My5KI6uzMh5B6FDR8RBridD1FkXXrFtCeSUNhijKrWqqpx3OOx29qQJdXOeAZYeu6j0w8KSpAjhWnDIqofey9zIDPk8tCp6TtKjJobwHk6l1EmtPrgXTQl0pRhr00CltjGqN2S7b64TP20Oa9Ry5x12uz288zirDQcMvI6jXldfxz2lhN1+kr5ZBd3bumK3H3WOE9A2XxZM0yi5iVyambnOhxJg2jE5MbjuzukPtbElu9qjYfOIgGxUteKb41ESBMzVA9OEmOjh3KY7s/kU0GvQASn7/G7ou58lEXIF5gyBd892BZT9nKjn8Luffa/u1KbN62GypN7DIfloQPzNz34KP/4rv4HPf/MDfP3zsv9rAM0taaZ/U1zVrZ9cE5IMXCmB2qkUlvm3AjonasfOwB2UZp8N8Gd47V111ktPrjJzjGlhKty+XjtGSZKkRGGMY8R7772Lab9DKaqE7Dxe3J9B3hgGDKaLPrtewdwNdvsDvB/hXEApDOcCgh+wrKvEJXmDcwUowLYs2kMOQFUrCda/HMAqClc04bYsswK0AC6MYQiVASTgbAUcQ7MMamuD+kUsbQK5JLFuUVAXokfehKoOLlqxSyp+pQwbR6Lo+RbUvTHbW0D3hmzVkkCrAL76rU2S5QlBFyKZfLKBEF08zHtlGKQ3aRxHuBCwrqsIEpSzTobq81NEBn9ZZNJ95/vfqcEDAF3ss1CNTFkyN6qlAU8JSglRZcNBjPPpDlal6Bel3lDbstApJQTuewZUIpkhVTl+3UJomWNbzFr1x/qoaqayNnU7CcSAmp0WCpb0FBoo6LcaUNhn6Ady/WUvJmD+Ua4G6uM4dlUTO84GAu2beaGZjHG9pto7JwFpk8RvSm86No8QcQscDRS1ikGzRrDFtlB5EH1QrXhJFNMB2j7b3p8Ltwytdw7Ri2m6URbFML0BWaPcpWQiI+1+cY5rsEDogpI6jNfg3aoq9Z7pz4TMS5BVmGaq/UNCeZXXeSeBck4Jy7xUA2u2YK5eK73v0HlIGZrtxoUVwBKJtLwZiNtnr8sK54ASWwV3miZJeABY1kUyvYv0OJqJLRFhP03YNElTUkKCAOkRqMFQpGbjkTQQKwWIw4YQUIGSg0POAZwLXEfbzVqp9d6pj5Kqk4JhHlZWHWStEFnlaIgRsOpnKUjqgxdDlHtDAeqyJaVviyCC9wXDNEqPaIgK6ASkTuOIrEmMZRGwuGAV1VjnQSr2IdLlqOdIZIJMAlrEPzBXpeDgA3zwmPOsSS+PIXg4b5RmubRCN7cMvgilUM18NFp8n6xqSQ9+cG88tm0xCq4bBxkbDVZXoIoTxRirZ2TRudrYHN478SlNCURTpczmlLGlDfv9BKjohPgGtoq/VAksGSVUS+JyNSX8Qatz3aNij6pWdWQgpSXZxJYcpnHE8eZGWgIMOKhfagVZXcLoeimg9r2CnQbs+rVE/tInYR73zlVqJ3X7rYgN7W91HhLmSPfqRyjOElD13xVYypxp37MnfPf5Df7C3/kH+Ks/+6+LfUD33pYApPrv64+y+9DUTuQ9uRslhlaf2PZXAHag4qp+sVRQs/T55QTvAoqXNo7sUvU59Xbe4osAo7JXCisKuCSYdNgQI549e4b9/ohlEc+5XIB5YxFq8xGuAGtimLjRfn/Efn/EtDuAyKMUUoVuUfNO6ya2TTmhOIDYYVtXFPXEc37VRJWIi8Ugz/qWC+ZFejFF/TcL7XPYyTyTE1LOAImXXEGBj76yXcxighQU5iQJMWlTyXWOm5cFKXGtGHIpGP1Yq5nZEcr10vF2+4RvbwHdG7KllJBWUcZiBT3RB9wcjuItNI21F+50OuP7H36Iu1d3dXFiR8gZWNcCYMWWWekNBbk4kBtAMNNtzcJrU3UpXJXNjKZkGWbpSWfAyWRv2VFDOqwS8o1q1pS3eurSo4yobj85z/g3z2f8d4eDVHBQWlBuYO41sUQLjFDXcKESikADkwqyFDMatcyrU6qq10BGMmoG+roPBlC68EDpLrVKdI2jYgy6KIioxqjqbZYBN9BmlUr7vQVrwUexDVBam/ciNkLZKgOkvkwOzrFmRT3O5zOa8IdUtuZ5Rs4Z5/O5BsSXy4wWePYgr51DD2ofgvHCXOmwZpTa+/IREbwCkxhEij3GIAqN2Ss1zGuAJfstWYL5kjPIX1O/pP/Ro6+wmUVBYYaD9HeWUhAgwS4GuRXMi5BLqZl1a5u0oKy/B62SZ9fEelS99xB1AKV4anURYBBbxbz7T70ZsgEItRa4uTnieDxUg/B1WXB/fycqhSlhWaRHbhwneO9xe3uLwiKC8/LDD3FisQ4Yh0F95rz00wUvgCgXrIsAwFapE788HyOGwir/DVwuMwpLdXAIETFIJXna7TEMAw6HPV6GgPP5hOVyEcpRFWqCVgXkGq7rim0VAZaUEub5gvPljMM0wHsSr75tw7YlvHp1h3EYMcRBq00jyK9YZhEBKUXUI12WXr9xlN4ZHyJ8iFiW1UYewyh9ZetFPOxWrBhi0M8crucGCPXydDq36qUGq8u6StDvxFORF8ZlvaiputcngpGpYxGQUWaLzg51gmgVPDILkdanZEbwpuYplGyr0MqzsqmXJEhoYqa2WhQwX1SoKg4DRueQcsb5siAEtUNh8R89neR10ziJGNRlxvk81+dyWRektOHm5kbFVlJNisQ4YJ5nMKOqsT60Y6B+0m0T5KOt2h+ArJ0MhSR5YpYR++MBn6ZP4/nz5zif7nE5n1EI0tEcvFaUCF4B3lXlyR7uq5mDNemGRwyPaqhNzVi7JjEssKaW9KsVVL3nbd6s56fH1id96l+7JJ4BOUs+An0iUkAdA/jtz7+HP/MPv4qf+Xu/jP/pp/9kO6erBFYbb+Lrv7XeN6DSyK8SiDoaXuY0KiT0Tud0OW+vt6PP7JDgUFLBtiYQBQzjhDAU+BDhIPdvTcAZKC4FLjhNQDjAecQhYjft4XzEs+fv4Pk77yHxP8b3PnyJ05KwpoJhkGS0DxHvv/95hDiBmfC9773Csm6Y1xXz+R7zaUHaEoIDxhi1txWgnEA+ACkjLTMuzuN0fwfnB0z7Gzx5+hwgjxcvT1hTln0uC8DA0yfPcHNzI4JzacOaEl6e77EtZ+z2e0z7HcZxgAMhp6Tz34aUVqzzIr15BHn2hgGXV68kyQVGSbqOl4K8reInmaVlZTdNr3+A3m6fuO0toHtDtj5TCzbD4A3n8wXblrEsa81cnc9nzPOiDf/y/lxUiAAJ87yIv9IQ4cjX2bkUoTjVANxHxCg8+N4PLWkGGyhK9eozl/JTgQColMSrKxNgYhX9+QBt0TH1xR4o/Ni64tdjxIdeWvlN/AR4DOYa9c8MV1VaW81eax8UCZ0IIKX3cP1O1EQBoNWGomkysT5QgFqrb43mB+rIhx19Ss63Veesv9HOvR+PaiRuwR8kENzKViXZLStM1lRPHTB2DtELnTaEiFyFTJpAjFQgC5ZlhfcJTuXpeyBnp9BXDASsdw3++pm9555XwGCfYZWZq8AiZ0jrfavc2EhJg34bD/Evcnre1wFTC6LrZUejsWmlT43lzSMoBI9lWbBua62oWPC0WrUrSjVgWRakpNYOjBp0W3Ajl6IFZAb0mYFr7N8SEERWgYBWatv1tvHxwWMaJ2zO1arWusrzHWOs9ErvPfb7PVLaqn/c5VKw3021wiGAi8W/rQi9MuUM5xJEuVsCLh+kMr+u0ltVcpbqnpfnZ8SgICNoJc2ohozMSUVEuN73FsSmtOlgtGu/JZEQF58zuVcul1mqRyANAJsxL2CVXd887/Q4SKvSyyqeUEQOcQgYhiCBlSY8ti3BFYcYQwUSRpuyecp658ZR1HS3ecO2QgFcqOe7LitSaj5+gFb4zbfQquNa2LYqrdlf2L4eznUPq1xFg27vSZQ+uUj1YpV7t+4HQsW2BFBgUf+LRKpoWjAOAUH9C8+XCwjQym/ANI7YthXOESJ8BTT13KooA+mYEUxAqSrE4vrZfP1myT1cv77DvUWppbYn7zyGccTtkydKgVv0uW6VKWaAfQNdVn97TAX/qE2Pv7+OtSfT1qk2v7fEo72rnzuvQWIFkHLC/em211Qg95Ch0aNhmX+/8dl38aXf+GYFdI/BXPvez99GZxdA1353fW2gQJeBQtd+esWSoOYLRzDfV5cSsmNQKdjWtapZEnlJLr5uxDWpQcoYKEAVNxpixO3xBs+fr3j27BnmNWNJ91i2TcGcrG/jtAO5gC0x5lmUMU+XC5bLPbbLGQ5CXxyiKRXrmq4jW9S7cbnMCAMhxA1pW0E+wAeHMXgwSUVa7KDUVy6rVUjJMsd6mVeGEDCqbsFGkNfafO+A4DwcpF9/W1dwSapfoH2IGUjripwsH0E1yfd2ezO2t1f6TdksSIAs9LkUUEpqPpmwbkGziR6X+SKUAPSZvtZTlZTnklj45r1iXdL+N+e1jybEmkVjlgrRtokUsAMjk0gltypTaYsYi0IcwxQws/DB+0pcd165FCCJcEutDn1EkHC1TGi2tUt/VnBpVRzWqqIFIBJotaqLBC4mzOKEcw8PIj1eXVCpDxkMXNrv60HxowqdgSkD3VUhULPYhKao1Z9jW6M1kNJ+daF1QatuEHaMAkyRbB8xDBGXeZYFOTejdQmqWCuQzTT7akg7sN2+92C6A6Pc+tFMtZOUzmV+d7VqQUBW2g9zUXPqTlmUABQ2VpCMjSNwyrDeuf4usOtsfX+VUmuvUKBkFaFxHABmnDU474OoTRvS7XhFHEeONXXVRrl2+aoix2zVCLu3+nvl2s/Q+qGCAjoZh1X2xUUoOSpysm6b9oE0zz1mX6mru2nCuom1gVV4kqoW+uCVTgp4X1BYkjBFRWhSygidgqQ8AybsUrQqj86M2oJ7Ff5wJDLb3Dwc+wo8ID2HQpFtCZx1XRGjAMngBUDMs9ipWLBE5GrgabEtqYBR8M3vqVZlNIAtyAhFFCpjiABv4MKq8lgwjlESToWVNtuSGKVkrGvBED189OACpJKAdJ0sylno7N55AfyAeOGRGLrXZ4OFwt6eJe1R833QjjoHPaRlUn3GxOR7c63PtpRS1Y6tvzMXo87KXBzUH5JtbiatCjLX6rl53ZmirQnMeAqdJ6WpxUoQb8muIhORiEPosRpIfR24azOIWb7UX3TXkKuQS9GFIMSAm9tbzJcL7v0roWkbNRBo3qBo1PEr2GRzyUP8cnWIbeyN8tb65/DwxfXzYPN3rdAB1UNFL3p7HDrPzQfgnevL+3ujHaQB92+/9ww//I3v4N/4X/9v/O1/5V/Aw51UoMbdzx2g6+nej2iy1D7Wroetl3Vure9vPbI2F8I5sc3wEd4n7UUOdddtnJsAmnMijoUCfa4YwXvsdwFPbm/x7NlznOcNlyUjZaf9cuKN610QawRNeM3zjNPphG0+Iy0XHLQNYYheGUcQsSmWNpHCDCaHdb4AcEhxwHI5wccBMYwIcZTEFVtyZcOm1eu0JRRwpQpLzoPrfYkaA5nVT6kWQWbdY2MmtHWx8FjSpkn1Al9Fuv6giYm32//ft7eA7g3ZcicwIADFMs8ShPqSFbyEGqhYL5oFuRIASQAHclK+YyAza/CdNdgrEuh5iCKV93Wh3NYV6zqDi6SR0sYAZ+Sy1sy+TJYZUHng3AUQEgQ3eiCAGqQI7StrNYlqECEbtcXQKmGM2mbwcL2VIJU6+mRBSosE1kplqOColJYHrQGVh3Nmbi7jZosqa+AtlRg7Qqve6bJdgZD8pl87+8Wyr6yJZ1sTMLA+GzsGoaYQcrqmWRIIqSSVW250u6A9SbJPWamrCh/02OlBFlruFNm3glA7rz4wtQABRAhwtboYgwh8kPNIrs9mCnUSzChgZBKhkXVdrwAdQWXiQegtLgozvLPLbzUP1P8zJLhk7jPzrY/Okas0s5z6SnC7NgZw+0CbuuoSdAGPISAlAR92xcEigEAOLVBxzcOuxnc6gFbt8s6poNCKTSlv0zQKdcd114SAdV2wbWvthd1NI8ZpVPEjiHm4GkWHGFU+XEbK+yB0YK12Wo8VNLB2zHDkq4iIjJl8vmWjjVa2rgsIjOA8kt6rKFzBMyqY6bzMrD82BMznOwCDGqB7xKiVs2zqm6uCfn8VhAJAiEI/dCpcZH1P0ziJ+q6qY+aUMU07SUzBKo/qy8XUqnYkdMphGJReuCKlKGqcJL5rOacKjKUnjbQCnbCtG8x+AyZulJtKJsEBgYTep4k4r+dUSusztPs/vCYbL0qgTQgImv3fIAGA9abavJiT/m0vNLZSWJT7IPNZUEP5nDM8qeCWUppTzgheKN7zZZbg2fsK2FJKakivirwocNp719IXtnXPZn0MGtjrMZ8lrgozvFIMS5Z5mcjh5uYWr+7u4H1AQQJn+yR5fmvCjXRHjxFbdwwP/2IVtP+PvXeJtW3broNaH58551p7n3PPey92bOcl4j1HMgoEEYSDiABR4CNFEQoBCikgEII6qVChAggkSlSRQNRASBFIRIAdIAUQwsEhCTjIDkkEDk9ObD8/3885e6015/h1Cr33McbaZ9/g8j17Xu17zll7rbnmZ8wxeu+t9dbscaEXPzrVC/V93OegGaEbc8p94j5NA2MunX99t2bMV2Ykdew9/u/v/QS+///+hrxmp9r6Y9fXfJsPO8I2rTn2H40Dmi7QSIxtnmSdt8VZDj3BM5SOAXBz2pNbEFpBa1G/Q+dH+zwNWwQH7TlzkLmkmTqrx+l0wrcNoUsMH3acHt7i82+LvUEtgkiXXFFrRq1Jfpr8kJOiS1Qrm9YaWs5oPsv4ZxF/S/sF3iUxaPIAACAASURBVBGyJ1y4Im4nvPv2j+PxccNpjYje4UhJLQeuyFnWNB+CFJSYkVPWMSvKn+bhWrQPvOYsNj++AWwemLVfB2NrtJpVyKqhsrW93FOaX7dv7vaa0H0im49BqsZs5qvSQwRmDSJVgj84OLcKvarOVCKrOLqePPgQwSwLcy6SGOaJAidy3uofoxlUq9LcS1ykQk8yQYkS04TQYVqc2BIY+QnmbWSBAtB90uYK9duc8a9/+SV+8XTuQYU1/RvdBTz8ifpKSJDg1EtztATGpKa0PQTX4N/1yhkpStF6dROaAAd4Z7RAltMEodsD9O/VhdcCjEnGRlAk6QMS6qp9jPoPM/r9knOy3Ur2SV7N0akpejQXnRV1Y0FespqwziI1I1Cgqao8UqO7KIahSXfrwRamwGAYKo+0ioA+xrwjNCcUJkdGwWVN9gWpa1bl5TFm7BqzjqQ5iLLkpleWLUggCQCYGFyr9Iho8QAwqpvSZYraDeC+UE4wMRlNlPX7ptRQv7f1SjwRVOWSYZFRvy4kqplGgzNFy55gQhJao9jWUpFbEhU0EkTGOwfnCYGFbpyTeMAJZZMRvFZ3vdoBEGsSIsWZnNELEa4jW0CtkljU2oBcwRVwldWoN9wJaRAkUUNrKNonKKqjDaIM6UBqCm0FGxsXpIUE7y1gkWOo2gsqpt4EB7MNqOqRKUkZ0KR4oXOezXEm2EIwywQITUrnkKK9ZjXUiTon97eqaa+M5QZ21EUKainI+h6uDcF5NGhRqpSJXq7BbGmqxifPo/WHNg1wDdnqiSc6OR0AOgIKWFFLhGmkb84KCUNwxYoAQfssU04wNkSIQRFJHlTnUhGD73ONfB9hiUPhVAJoGT+WsHkvtDFJrtCvPZqhZhhzqc1BzFNxbcwJdygQ9f/ZFHM338zTEzMGlRuE88MjTucHrNsJad+Ri9x3p/AIP9/rlLXZ8zh/n123+2Rseq5hf787Stvh/YG/ULD56Kef28eZ4kC/pnl2+v0dCwDA55894ns/+CH++M/9efyX/8TP3iVsdz9tzNM2t83iUgCGT6wevM173CB98fN7ySilusq3CrQi/RTkpLWilk5L9LUIHdMXjSeozyleg5beewgtNpKi2s5hXSLevXuHlIHjYIR4w3p+g//6j/2rYHIIjQFUhMBwVMFIqPWKWm9obZd7xxW1khwrN9SSgAOoJaPBwfmAfPsgPdc1o6YdLR9oDw/AaYFnYAsMroxbyShJEH8CEEKE8xG5yf0qOQNN7GQEqTM/ugDXYyC1fFAbFfMitYjBeuOdqohWbtiP/eMx+Lp9I7fXhO4T2T77zjusj+/Eu8kmCi99JsF7RBUKWNcNMUY8XS54ulxx2w/wUcFw0spCjMoN0UV89q1vYYkraq243W54evqAD5cnHPveg80jH3g4r/hff+z3Yt9vSPmKnHYQF3BwiMGJMIpj8OLhKAAoXf5a1MhEJEK0vD3CuiJ4kRInRTLWdRWDXEUQSin4+3/zN3D1Af/P28+waeIx6BpCR2BVyJv92zTSBsN6aOSzQRPYOXhYlgXLIt8tKJIktZaEikjKAu+D9KnUhgoJcJ0raK3c5XNzA73TJI0gCVxpDa5WoX6AxAsPsqDXpopYbdDAXE8wBUn1MSCsK1ZFPlK2pmulqSoS+XS54HK5gkgoe7AigPaG1CKoyagvyzVxXg2DS5FenOgk4dU3GSW0VEkCehzQBFUrJAIy3Cp88DIGagFpAgOW5LDpYtdQxXCenqlYBk2Uu7ePBWSsZvUSiDkGQhAZ+3Vd4ZzHbd9FCKZWlMYi2lAzbpcnHLcrvtLxVUuBJzclk0IpZj0uq1CHybCZa0GtQj8krjLue9Q4O2FJkPzu3WdCh04Jx35I0aQICugABEdYY8SyBKVLCkJ0vTyh5F2FdEQkJwYP93BC1Qp4TgfSseN2i8OcPkbEJUrTfspCt9XEal02xLgghogYxNPsOJL6kUmVG5S7fUfUAlIMUWS0wTiOXRRxa0KrGUQNMXgwnHolFrD3GiSOZN7SfecClkXmKEAUJ73P8M7j8fFNt0M4jqTPNFQERJ5B0sKS8w5BCzApFxyHKNet24rTuiEhI3HG7XLBsi4dCUVruF0v2LaTKq3qOGsMT4TFe7QQUI6MAw7rtqKmjFQqSmsj+e5zjd79ytivVxA3nLaIdCShep3isErwokIcl1WTJUH4YpCewNoaai64Xa+K0K7YVkXSGqNWGcsmnpNzwuVyQakFBx04n894+0YMkrMmc/ue8ObNGYv3KKWhNkZOBdvJDNdlPjtKwfl8Up/BhKQ2FnFZewBvE5wPYu7smiCbgPQWWWXOEDJD0TtqBgtZjZKK/rT02ZgAFzyqzc9qjcMMvPvW78JtzziOii9+9CMc++coRYsaOpeNPmh7LnWO6znV+FLW594Jz15sVLyZx7Mi7Hyf0E2FJCtlydyga4xlgfae+4rbs31M5/4s+bs7VpDSzxlQtdHdOfzqT34HP/HDL5D2fIe8ySWnu9cGfdzaC2xt04SKRyHVk9AfZ4qlFRTtpwGKMBX41uB90762iFQzON1QIXFGrgWpswo2AA8gdmBfEJdFrqIWuzwx/KIeRwSsiPjdP/7jOJ/fYds+w5fvb2BE3AqjNNl/5YLaCI5u4PolSv4hat0BZHi34Nh3HJeqBXCHkg+ldgJBvX1j27H7AB8XLMsJy3pCvnyOLx/fYj2dEdczGA6uSktKWFbEdcV68vCnR+QG6d1LGa0VOB/gQkCcDOWLUkKv16s+ZwdSLeAMVB6euQ+nE87rCc4RbrcbjuPA+6f3eN0+je01oftENlMFlN4WqdIL33xRHjopxQraKyN+KF5/B1ZkzkvD8rqt+OztW5zPj1rVLvjt3/4RvvzycySXxXT4dsNx3PD0weM//uy7OLYb0vWCVguCh/qhsdBtCIjBgxDAHFGJ0SpAaHCQoD1AFopl2bq6ohk5n1RFz6vBbSkF/9Kv/BUUJ1U0132HBv3E/rSg15A65ibVa5ZeJQsqjXpq+yES89plXbFtmwQzLem+RvWZQKLYpRLNpYhwhHlVTTotGBVfp0mBqmnaQs1DOr512wdLKgDvwz1Qxuj7CzFi206Iqk4ajgNXXFHrIYawipqYH11HLSfk06hJ4zWjXw5VRkO1RPgG2tO1YF1EgTDljH3fsd9uQ3lUF6SmSa/RfUWpUVA5C7Qk4DDvOemx7Ihh7z9R0RH5iCAJei/l/rmOEMUYxG5g+s5cisrYS79CYYweBlZT7ylosq0p8kKkVLYovVxlMit3OkYt6LLrJ+NRTcKDB03/Pd9GwKQqpsHDuQUxepSSO/0vRknWYoj6HhLhVUgh43a7IQSPUpaeAHrv0QKL3YdW53MpaIrShCBiGKdtkwKF9s5K8qkJKyRYDqr8GNSMmwhIJkyhIkYiFtIkANf8jTC8+2op0nPCovt4Op00eRXlzYyM0+ncx0ZHjUmeX+BePp61su1YnjHvHGoWSmVxUozxzuGoBa2Najkzq5l57XMWWFAFTMErc5Me4eQ6ZWrYM1Af4w2G4st9FxryQDXG00RIuXR7GVbU0zkvhRzWar/zyCmr7UIF+CRzYvCjaKR9QTEK7dbmvJQTrrcbFrW5WGIUpD43iIy7hydG4YJSFJULAQUVLcua4rzHdjohHQdu6YY3b97oHDRUjpclopTWXzOxpN/JNoFmfZNbMIpgA52b3yHB97ZuOJ8f8LR8EHo6tJgEWeekkckQdhpo2UfI4EggrQjnZjp3R41ofGxC2XpaanMVA7hL/J7/+fGZ3yk1vwjmPXu/XRQVxPrhZ2/w3d/8Av/Kz/8C/qN/8g/fIWnA7OF6T7Xs+9I/mx67FGGc9g+6u0RbeuvrULF2Nv/K+2qrIk9aIWIoxcG5DF/MSkn7c731x2b4nCWRhlC9R9EOUvgjUWWWRBA4nc44DmBPDfm4ISt6lWtCLjfcLu+R9gu4HnAo8EEKi9wKuFY0JlCVO9dFuFqF44qyBMB5lBSQblf4uIDRUPOBnN5gOx+gsKBRkPtVCJWAfHiwX8DwIJaikCNS5oTMhWLpVIUunw5BBtWiQFg03K+z9SWbwmsXUFtXvG6fxvaa0H0iWy4ZQSeC1ipIaRGtMpp3aNUplC+KbDmNnjao0p+ABwSQBadCkXQU7iSyvfcoWbycRHJXqG2tCU2AdOGRvrQGbgTnpQ8HmCqxPIJd570G1IQYFS2IUalCAdtJJNkJhFIr3tQL/qEvv8B/8xM/Ja9rz513U3JmAbbRJo1Wwk0DA+5VfWbpyZADHMnNR+If/Qy0C0bXawcCqXmoa4zmlExpleipOqpfMQLQmULTy9VDOZSJ0LOX6XgG/e9+cZ+D294D16/JUM7jmXtv+53OVVrg2jjGxqhG7ZkrzfqdJusOiAw9KeoxkLqGKr/sqNZA2Eal3jLb+brIYi4BkhkLG0rpHGmSZecwquIf0YymH/seaezXZ+buOzUIVMqMcw7EIpYhMZj6AWmQb5/Z1hW1edTquzn23Gti11LMx2v3tENjpR06UdJk7V2tVfvghlef+Lg1lewXtHvVhV2UMeU+HseOnM3wOyLGhmURypwk/kMAReYDk9gnbOsCdgzXGERyzzgdqEQolVCK0JZL9mD23RxcvJWEvmriJENdVHoRmyLlZlifVI4fYMS4aMEg65zVhhBKH/faw6co6CwU0mpFpQr2UCVJQbsoy3uc8yr7Lde2ebl/3Kr2K+YRLjNPCJOo9jKo96HlLDRY4gB2+rsqyaMgxqznqRYRKmjAbKJHcnw5HaB1RejPtx63FjvMHD7GKMfcpKAi6IdW+smeQ7m3yyrfV2sVpkJKIFiBy8N70v5Hlp5M/WytFWAHF6UQ5oOIRpiC6DyWZwq8HUQXdNL3uF7MwP3WX6Dxx3PEakrkvnYj9GLW4+MbvN++QggRQAVbMen5fi3Znr5YDmdO5qgXeYxyfz+3zodFI2kbg+frz6u/ZWR3/S1f9975nTr/AOjrLaN1lecjOPyl3/9d/OG//gN894ef429+++1dUmc9WnIIX/+F92uc9K0+Lygya9JWdU6G0Ly9EzpvY1G4NPTaOfVxLEV72QVZdCUolTrDe7FQYSitV5MYW7elb5RUmTXifNqQUkOtO/7l//TfRW2M//Cf/1NIecd+PGG/PqGkHcQVjhjBS3Jv8ZIZ6RmbBAwgNBAa0hE1URV/y1ILPrz/EjkXbMeO7bghLBv8egbIIZgIDBHgV7CLoNY0ORXP3aDWMbWSJJRFikZe2RZg7gUlbmMNbmyWUNyLPcMu6XX7pm+vCd0nst2uF4TtcfTj6E9rhwaBQAgLYhAvqpSyUGdy6T10cNqg3ISCd7teBX1SVKjkDK9UzqyTSCkVuWb8dLqAHPCD7UF70rSxt8gE6gMhOu7CBq2KOTQ71p4c3/s/YtiwnTas24aTeuhZtbmWAqSEf+YHv4qvlhVfbOdhSO1dV24zCXm0CqjIh3RrC40uLlFRE+7V5JJzR9xs0TLEU0yszbJhrLmWkDhYX9AUp2jCqH/t24wezsjY3IMAFgqVfbBpojFXVK1BvAtZ9sCX+oLNPNAtQ32MVmPB5h1GpIvlnNQQiWcctzKhkuiBG6ZAwWnQ551Uc1mDoLmvrVmSp8luV+7Uxbr3zd1ZWKAngNwayFvyL/YLrdRxfZokdERQuf6CnBNaDYJsFTO4lSCMp2MS8Mdk2S1QUjNoF3qhw6wFNFvvEt/ee5zOJykc1Irb7YrbXsc9bOIvl0vG7XYdY1WtI05xw+l0Aoi1p6+gFI9IXhHLYRLdmiDNRYWPrB/Dkigi6qIy0rtSNaAi9S6LMISu1qbJg1GESamHXqnYqjKrz0RTGwRJswXREc+4pNdYe2n72LPbr+qZarxuPmUmjOOc0JxrlZ438WvjntABw6/Net0wPa8yJ4khsdNGH0eE2gpaFqGabdvgw9r7VWoZlgE5J6Qsgif2/NWe0LFSvitKVtPzLPRPef4kAK0ld/S6amDnAysd1u6VztOaFeSSEeLw47JoTvoJS58PYow6VgwFq2iqFCjzoKgC2vjIJNfNkEQij2VpiBFq0WFG6kEo2yHgdr2BPfciW3RRhG6cBevDdN7YD7MgkvUk5jzo4WN7WeHy67aOyt3tYfq9Br0heGynDW/evMF2OiEuEZybVaj6vqwWJc/2hKrNcxTGnDMKKK6zQIan3LMklenu2MYZWLJGmIC3Xgybz+nuGEB3c37/79mHmKb3TEjgETx+9HjCv/Dnfxn//j/9sx+tH5bQAbi7hy9tVuh63r1nxVPbV28psP1NRazWGlAriMQWpdYKV6UoARLUO5cMwCOrMIksEARPvh+fzINy4t4RluhxPm/ImbHvCUZzrSUhpxtu1yfstytqToKUOUJ0pL3uitSxXFcrrskuZAE49l2f4YioImNPT+9xu+1Yb1es1xvidsL5zWcIYUFdKtqirBq3AqECcKJKSUDwhEVZGqUQWk4gbvAEuCgFvRgCrrcLuu6V3hor5ADyfM2WPq/bN397Teg+ke3Yb9jSMSEAIkYChkr3QibXWkEQCpUEcDJpOWl3GEEqSz9JNaSFgetV+q5iiKjLIkggAbkV/Nu//ssgAv61n/kj8CAQCZ0hawM0w4FIAqhSqvauyeRK5LuRsXiwiSRwiIvw0eOqgV9GY+BP/NX/E//c3/i/8Gd/z+/rC5HRFH0IEwtGxB2MymWIi2OHddukj0tRy6wVMquY2+eZTb582BpYMDD/1Fq1eg9F5kxJUwJgTAGDBQ/zAmriDE6vNbNQNMzrB0pfkaqeiF6MFd3ETsSmYpbXL7mMSrpGRs2kk+376W7NkF3q+ZunWQhBFEqr2TpQlw8HoD17GcdxSI+dVX9fGqx6vP37OtrXnl1XQPysLABrPXEyoRPvJQg9nc/ioVYKKlc09Vg0eu5xHHAu92tjSSsxoxqCgClI6wmdJZEM7r5+BOkdpJ6MycLa+ngkOJAGxV10Ywq4DKGbK68EIC5R0GhHInCivSi1ZkUMTCFTjjmEgKb7ENPpBubQxUHWdUUpYs5tvTIpJYQwrqP04InvIZQuV4ooNBptSpIKQfc6Vdk5cKu4XJKI2SjamHQegqLwgtIoEt4EecvJoywZ3ju0JhYoqVXkVBCDjLkYF5iVhzx72udTpQAVo+voqYwdQb9KFk9GEYcSVkGrlqxSvzZE6J6HMiylYJSPAwSIGiuZB2Dr6nsEdCRSxEUymncqSMOahEthxRI6BqPU2Huc5TolNXkfHn0z6jXPESlnUM4IPigKbgqrs1WAPHBShJMCGd9PEwCgxveEGJdOH69FPLFCDEpjRRdyCdo32ec557CuQq002XoTlhJlPqfP7n2CQBPUNv/OimQwI28tKIyCyUjC7vY37ZcgRY7T6SRFwHXFng90hoSdPwvtVTIrNxIrOwbdnyVwVhwxQ/Hx/Osx2r71gEY+Nf/mvuBwd0H4Y/SQiWF0zY8SOp0XdcR+PKff7Qj4lZ/8Dv7xv/YDvLnu+GI1X0TcUSztHgBTce3Fw6XpjGhMmJD5rJGsOeTcYOPc3bixrg4rk9b/XbWw5Jy0GuRSAK9q247QO840OWSIKrInYI0Bp23BuoS+DhMqWsnIaUcrCWL5QvCa2Yv97PSAgDHkQAETcys5oQGIABZeAW7Ix45EYheTSsGSDmlxiSvisiMsK8KxYW0OPm4gL56Y3ge0vKARITiARKELjqQ/NAQRJGq14sNT1PFEihCS0vvHXD77PL5u3/ztNaH7RLZ0XFHz3ivKrUrydFq3viBxLagl4VYSjLvubOFl6wtyIC+1wevTe1xY1N9MJt87h/P5jCVGnLYNt9sFH1rtk3vwEUvwiIFQa1bVu6ry3hnMKrPLIoKwLiu2bcVp21QQYUVYto55lQocqeJIFTkd+Hf+x5/H7//yt/Hf/77v44gR4VlVVf9yh3ZJMKoKeE4qzD6YFLdWDvU69KBN91WrKNAZHcwoEKYKZglGLRl1WrWdc9i2Vc+3opZBFZsXUgmEXDdCjkH8xWyZYT0foT4FLKsglSllDZyt2ttUsOB5E/ychJAGC3qZ7Du0ogk37AVskTXU9OF8FuQl5S6KYvudF5ecswTJTVAcBp55Nt0nyxYcMdAD5/ugVl6b5ek7CuUDLKB9fHwUZEErq6xUUblWgqKMayH/M5sE629zkEW+03oYPZmT3kvSYHZVoZbafYeaVXlbw9OHDzAelJhha7+YZ13IRVwmpQO9l7JJ8mf0IbElEDTocn3Cvt9QakFLQr9cltBVExliCJ5zQk6S9AfvlYa2orXYKZWlFuy7JLdmRB5DVGEfjxZtbAPX66U/9xbIn87nKakkHPuOL7/4HMe+d0sGbrWPa0vkLIGqTY5B0Cngzdu3CMHj4eEMPDV8db2glF1EP1T8Awx8+PAB+3FIkqlI/LadAIgapwjBJOR04IIP0g/YGMuyYDudUPKhrISMVrOK1zBy2pGYxZyXCMwV1+uTUCAfHxFjQC0Jx3EgxoBtE8GWWjIaN+nzS0nRG7lWYixe4IIfz7GapedtBRMhpYzr7Yp13XB+eEBcIkBitD78Js1WhXC5XHDsB5ZlwePDudNlDZEmiU6ll42hyZzSpGvDqsrBAJCTnM+2bXLdIbLqtVbE1rBtC2qpYjZfK6rS2kyUJgQngalS7Jm592+WwigldRT542DzZTxBpiruk56p/977hz7bpl8xGDFEnB8e8ObtW7z77B3+9oev1BtR+mJLbQgOnQ4nptbUn103FdViiPCeunWGjXfSCcTAI0vKbA6bqA59jjUY8eXToH7ePZmVCR1Ndzonc6aC/JxG2lOm+XqzzDeVhJJe4yhGSvFy7t5V4Ri2pVx7te7Wj5GbkfVz2TqJ2tedViuqoz6Hyr689rrfo7m9mKXjVPrGPKhk5FaRuSHWirWtMoa10GaJOXMGgbHFADysyOmEGBwIDYEKWrniuHwFqgkRwuxgLmglw8cIdtJfKZecEMjL9WqyFhA35LSr6m+WXkrnsWcpKuV0Q0w7Urxg358g6txi5eHCioe3P4bl9AZeC9TOeaTLW2zbhtNpA0NYFCgH1m3Dw8MJzGIP8n5Zhtq1rlmO0YvUYMg8uJ6+5gF53b5p22tC94lsZuzbVA2xFFmMz+sK7wDvSfzkGoNLVg8y0mozo7SsSpOMMHlkCX3TKoHcEwtlQqDkpAmhLCq1NrBWooikmb8pjaFxkgleaTveCa1rW1esy4ZlXbGsC1wwz6gKTqVTDP69/+nn8NNffY7/7vd+H3tcJfGZBENk0TYzbBVAgSE8E/2GgWNX4QZF6Ezly6mRsfPSf+ajVWi9UvcqcjID50H5saQKmjiRIzgKUg2GoDtzT9e0cksl2PmutOWMrqiLY7Pr7j22Teh8zvleMa/15SAJQF/4mcRrzRbq/jtDOIBuAG4JnWPuAgqPj484jgOHP7DfbqhK5bONdH8ppX7M/XVLkC2p45HUzrVRO1Z7r7bg9QTDVjY/BQW1FNQiPmNzj0gH/fRat0b93LwzdVBtnND/955JK5xPQZObEBMTAREq7iGFEO87SnW5XAAMewJ5VkJP7Ey8pVarCNtokP+PmExEJkL8DNu64MOH93h/u8lz5aWoYhdPfNrkuS+poVDWHpUzvPNYF4/qPXzx2Hc1GU+SfLfY4N1A9bhJxT8dpaNNWYU/lnWBJw9gFD1KKUj5gNmiyPUfPZEjmR/Xk1mS4SPt2FR5NwRBv479UP+lrT8L8ngNmli7MyOXirZJonM+UIpZsog1QVNkMKWj969s6yafKYKu+yDPeskJBUKdlDlVjhVoWGLEMB9uvXDGtaH5ekdvBZEGkKryqnMyed9RYyKH7bT1e1lLATsPdtyLTt4FHN4jEeE4DixRfBzlOXA9kQa4W3E49b5jFhSSvJfeHCIRoKkyj4W3D6KiWUycIeHhIYLgUKqTxK4UbNsCUSGW4kNuFTHGriAs3y/Hm/NI6Jwzj8u7meKlmeo+QeFR6KFponiO0o33oxe+lrhg2zZZu1TNRHxP2Rye74+mrwvUn/WhajmKEgM1nBOh38H2dafck7nxhmk2fjmZM7+454hcL4C9cF0AtYWh+/fP7+v/g1W8QHB9v5baie2I/l6Fp+R7uCezNpdL0Wbu/VW2glXN7r5binWN1V+tKlKmz77zDqEu8EQAT20CquzpyCF6YFu9ov4kVgU1oeQDxA3kGM6JdyTXCoQABxYtGYODSc68UQOMVQC1EsgNl4sg40wBzgdQ8HCoIC4o6aYK1ZK+k4sojbAdCSFu8FEKgTUfOLYNx+mkPcR610OA0xitlaL95wOdM7YCMYPZITgRSWvr9uKwe92+edtrQveJbOsS8e6ztwBLhfh2u4kEbrqhZA18dI48nc/YVpHkzUWqYvvTLopWziFGkdYlJ5QdCfQCQA6VreLuQBDEaNvW7jvUqhjyeifcdLMnaE0rgposBe8QvccSV4SwaALowEzIWSbpGBbppVsX/Js//6fxvfdf4M9+9/u4uADUCg+vni/cg/Bac08Y7EeCimFS3lrDUfYe7JsJe9MkRqraZjwutCsRmpBFqWlvGmMSUYFR8mUBRiP1+qXeSwZAA9Kx6lrF0nyiTOAF9i4isfHuVc2BDgKDinNXa6VJUGVK2GSf4729egpZgOb+Ovt+650ABL2dvbOkH2zqvVCqiKF3ZlD+0jYnkVMIoxLcEneJ2qLTPrjcBUZaY6i5mV5v4Hq59uBy0IqqBjTUr7NFcIYaaRxot1H6xUBTgMPKeJH+oRCGqqNR14T+aX2OUsm1MxTUm4YABkxBk0Qp0dBX5xG8KCFerheUkrGuC0BiC2B0MqFWJhE1UnqbVzsJQ5adqx3VPPYDPniVxRdBjHWVJKyQ9DiVUrAfu/rQhX48MaJH03aXUjrgiuvfm9KOUi2oB7RR9b7HA+L8NQAAIABJREFU0yJyHW9eKXytNdwuF3Br0jcIQZZSElpxSqknLRa09WTekCkLxnTslZLhWHp7Uy6A3WdyaK2glqLIqPitVR1T9rxLfzANqmtRAZQsRZwSY++zsWSuF6ya6yILrVU4lusoyJkhnQXBOaWeCpW2loLtdO6iKUT2jDGgkuUhRGwbxBpGKa3buvZrKcjomO+8J7QmiJzZKDgXuoWFeZSmVLrgldEvUxK6aDARKlU3tSTHelDtube5xu736M1U8RpnZDnu887MUvhoVmBShG6aKOa/TolJT/imTcb41tEflgqFBOnw9wwORp//RuKhTI4JheqIHOx5GInmfWkK/Yjmee1rc7pnp//SdVFA7S65e47Q2TfNNgr8/ALauz5CTX9n27yS2LXqxbdxCH0+HSrKrMm2+F32RJDUSlyPkzVhbVVUM6mNJMtlh1iK7tyB4PX6C9WayMEBWKMXurojeDTxwWtZ/gSrFW4DmYJys8IqCSKnBZgZ/pVTlPEshR0C+QjPMt6LF0sbVLHUIBKaKDmHmnbsjRCWDB92nQ8qyrEjHzcpzELijOQcjuCRa8NxJKRjF8p4CCBWoavOVNH7+6qH8kltrwndJ7Jt64Jvv3sLIkLaD7wPHq1kXJ8+DEoJeXjy+OztW5y2FafthCNn3HYIJSlLoJkXQfBCXIRCEBd4T+IPo4iTUwRKqFEnFQtoWs2uGpmrhH8biYL54y0xYoniOyUKbh5gh1aBVLJ4v8UNbx7f4k/88l/ET3/+I/y57/3duDbuMuIAenBOkCCsVDH2HAuLeawZBtJQm1SnW22dRtN5/bWhknjIWSJrQajTIDcdqat6zVU96mggd4TKKD/M94IOhvYYKiKy82KsPHoAZrRKgjYJzqyfz/oQPl6ku5iJRAkfJ35s125USy0Io7ETGI3QjnsE05IA+6mK2ik3rQ2ape2d50CD+78tabXvk8MdktSnk6AoKXkcx9GPxQIbi/oEFeMeoAHQ5A49gLCgzIRsrNcHNMKtjiSq7Ly9ZkFejBHrErtghiTrWs1WZU1Lbuaek9qqjBACUGUkChojqEdwsnAzN1yenlDWVfcBeCfS9KfTCUuMeLo84YsvvkCtN6xamPHeKcrj0ZrvQfhtv0mAu6yKgsmx5zw808xnclkWxMiTDYEb95BEKTIduyRJTmjL6RCVR5lj9Doyej9dCAFdcEKDwKD+ZLU2XK4XMFg9MxtClIBbErqsMulDPMeScLmwbSpIqFBLloQuZ+kBBIkfWgiLnmuG5GaMh/NJ6JeloIUAqG/moYFTqwWVCDWLYTAxkKNQLVmVI8UAWNQ9ubk+/o0q3NFFTeRrrfBBgtBWi6qBirgIZ0bmYp1dMNN5hhU3QrctqKUiWH8XaLAV9eLItZLxbgmd9ZsuywKGzGP7nrCsC07bCpBct2MvCNFLD6ETtc7jSNi2BXEJyMVEasa8ZM++CLcsvb+wNcKyDL+tl7dpLmDoPKpjyUD0KaOyeczmSH1K+94koVtHgqBFHMejODPmPR7ztyEhbjAlBtL8cjpm6NJHr+t59Lnt2S8tjZDHZfpvDO7p7dznTJvH7XP2tufz/5wk2Wbved6/+NLfPz5PpYzSNEea8qQjeMG6gOmc2yBAwIpqXmnyUqSRAm4vwPGgX4pKsgdTBZPQ4kvOqmY9JdjcZIyoYM8SncYmgKMKYk3mNKHjKnEJmb2TJkhuYrA41/p1U0BQxI5NvIkBH+RcnSO4DHD1gAtgSNLqKSAQo+UDJVfUkuBDhHcBrRakEJB2LWQ7j/P5EZ6AG0m/7O124Nh3LFq0Qb//cmyWh9rxv26fxvaa0H0imyNJ6pxzCATktOMSNMg0dTuqYBcArr1fyJH5dDaAJRGjVoEmEu3eA0v0uuAHHIWRi02EDZ4cTtvWG+m9E/nynMUOoRargol58RID1jViiQuWJao3HWChv9AmGZ4JDIc/9ku/iH/q//gF/C9/4B/ANWe0201lezUx0oXGzXJQugB34Q1L+HplSytyRucy1MaQN64Qs/EKolsPxHovoqkvat+KhSP2XSPMmNAnXQC9VgCth9HEC7ZtQ1wkqesB2B36BdRScWt7X1hMctwQJYaqf03fiX5tcRcM2O/XdZXETRfRrIISVsWupSAx4+npAlYEoajKnokEWC/hTHc0OwjwSGZ6MDVVPwEo7XMEKT1Zw0h6O11Hk5C73g4iDH8pSzoBoqb7mL5Lx4YFSE3HBOl3jESY+hhnhqh1qjBMSqn3wJVa0LTAUFUAyEQiuuqgjs3eQ8ijf9A5IHiPbVtwPp2wbaskrtzUZDaB+YwYgwSlzmFZ5L05JzCE5mrf5xVlM9RmPwTJEsEUdLRHkJQFzhUQifeYXNesxRHufW+9P6oS6i4UxQrAV4dSBOVzbgqSiTtqY68bomzX13zZSs7Yb7uOJblvMciyVfIo3BhNmEjmtH4Np9sq6GjRPpumz0NF1b40UWnV+ZCyes7JvmrJyE5pgkSoEOQSzKrmqcWqfNwVLnqBQeeUGckhDfjs+gBmebEAWiSCfU9PSwYSWdTLsrUGLFGps4ucvybEswgJwxBLo+C7nsynlFByQXIJ67LCB/GqSykjp4RV554YPK45gSp1qveyBKR09CKSzVulFKVVDvaDmaGTIxQ8TxjQzxPPfqev6OujMDC9OopRmNQke12P+xWUXmMpFMqz3iTpJYfaRLJ+EDrHmDRkWpgFLyRi9ycyJaD3273W5TQ/T+ff65G4Z5O8iNB97YHQR18+J4QvIXR2nvLeIbozJ3nzay8VCkcfnFIyp6ImYyRGfe2bPhf02Qa57osrjw73e2jInu9zhfZp5wqxNACcJ0kGq1CiiRkgj+gJf/OP/rN4//4DHk4LHk4rHh9WXK5idyTsEe2Lr7Zu6eptOb4VEPTgh4iS9F1WLaQ2tS4RWreD8xFwDsuywgVCcA21FXDV9ZIbKDJcC0BpyK2gqcl4DQEHGDWL+vh+HKilAjGIf50mzyllEbRrQkv1TrxGX7dPY3tN6D6R7en9V/j8t34IImC/3fD+/Vf48ssvhRbHjEASPKV8xW/9BuPp9AXWdetmwrenJ9TGICeCJh4yOa5LwPm04c3bN9hOD7ilht/+8ktcny64Xi5w2lQsEuOsKIMF8B7kWqcyfedbn+Hh4YSHxwds64IYF5QsQgc5p47kreRQSsM/8it/GX/0r/0F/Lmf/oN4Ogr2/SbImlbmK5kCpSamQUQlLOgvZhI8ZzlQlKwvyppIME9L35Axf3rK8P7WE4ohWABdtCyolGRNjLitQpmVnilS9V5FIsDqhaUqhOu6ijhEFDTjcrngtu8i2jEwLlgvzkeLvr1lMi2247O46L4/TXq+gvf47N07oVrVhuvthqenJ5Tj0EXEdZRg/+JzaMgtfYrMIK9Jj4qGGHW0ByeKLpiYCREBbsie20LN+h2tmuG9BFspZTBfNIAWihs5D+c0mddEkEg9jyyw5hFK2Hdbqhg0yZ5poszCXAnBY1tXaVzPFURJVTEVFS3Aob1Qch2KSlurWqJ6rwXtkeu9NySWEj5I35P4HDFCkPGwxIDz6YTHxzPO5zNSWlU+P+E4dqS0I2qQui6LBOTf+hZyStiPHemQxPJ6FRPxGJdOO/M+9ET9OA4cx6GCK17HYFCFWesHa9j3m1wrbe43+pl3hFYLbterBMlu9Md4p+qPtQLEIAcE8opsi1iGEqxk7JAIaeRccLtdcLteEOOCdduwLSuyHrMVLtZVvOkwje/WqiSC5g/H4rXmvAdB1O+Yrc+R0GoGuOi9bChZ+uJIxVFqSfCPjyASK4Z87Mga9zsngin7fuvPIpjFDqFK8Woo9oo1ihnbOwBBBZhSEmETb6JJIKRjFzsW8DAo1/HdUYFaxRJjXRG8Fn1KRYEUBHLJ8EHES+SaCErxcBZU93K54Kv3TyJ+cipYe9+iPK/7fiDEKswJ9ZLMWfomfXCIiyShOYnQkdkWWB9vL4S0hpTk3yEYXfbjrffQ3s1lI4Pr6Ra3XghiLQRgPLrQuk+3cQCAuCw4Pz7g/PCIfNzQStaiBCPnA44i4EbCaP3LwXsEE8vqCYnNm/PxGR10XjG+Dv2SM+m9zM/m7t4fZ71x7X6t6hPIlLkZajS9cnf9ZnTuOUJnycn9V8xJ2nRsHyWaylSxtgDtRR6onTIAbV+61slLHiEugpxCEijnAog8jFJtBS+9pTr2Qu/LPfYDORWEWBFiBcGjFu5xiw8Ry7ri+o/9o7i9f4+f/OEP4XFg8RUf3v8WLpcDad/lXscI83MDRLMY5GDpHuuFJmVl+DAEX0qtOFIWIbSaUZLeH0262rqC8waqGY12lEpAXOHbhuAfsCCg1Yx8VDRyCMuCTBDz8yz7L7VhPT8inE84Lb63wOSUwCoAlZKIvV2+eo/X7dPYXhO6T2S7PH3AD3/z19Faw/VyweV6wfXpCZ999lbk3Z1D4YycD3zxecJTCAgxilIgOeyHVJlCXCTwIhYxFTf63dZ1AXuG/yDqe8exdwTiP/iZfxi3fZfqsPMS4BF6ELcsCx4eH/Hm8RGPbx6wrStiCLjdrvD+EEpFlaAyxIDLhw/4F//GX8b//vbH8Ft7EuQup0Hn683YkKo7AZ597wEClGrE+HiRtLXcFlmM5MMC1NYcSBPG1iqAot/H4mOldCfbl6xFU+8FiehFUsuD3tysi6bIgQe1aYgdnQMMhQBKU+pqP2xdWK2iTKPyS7BF/n5RHiqNKi8+Nal7LxV/MT1uKnzh9frKuZh3Ws5Zkjy692sa1EehxQTv1fy0dmEIR6SN564jB8uy9ISx1QqqBdnsJfTeSiJyTGcjZ+d96MGPNdLHML82qEa976SOivSoyEuVFw49yVxilJ4FV3pSb9LQgshMfZAsthsNhD7EmEdAzlMg1xocKy1JkSVvZuETvct5CfR9kD61/dixX684jgPnJkq027rp9dMgigjHseM4du0Ha1jXBd6LfLuhyualaONPKHjm/xg1eRKLg1rE8sJ7r0GVIITWT8ZNE1RF8QR4lMS7F7dpCvYw7ocJm5hATStZk3dBBcMpdsruHRpmEaoNP312MaGwlvTJPKRpQRNpcCJTVWVA5cIJEndm7YWrJQNKl7TiiQljCMVyCAHdwYMk49YzqSDSGGcEKCWde/+tcwTyQSvtVRNhpWdDqN+Ayec7lJRRcsFpXUVxsjjsdahMtjquu0FHlngZ6v/hwwVHEcomIP3A5u+Zi9DIHTmsp6VTXq3QtS6rMBXaoBMvy6J9gHVSBiakXOAc4XSS4kitz+bfv9M2o0r9/lqyZL+jjz7Sh8WEBK3rilYyWsm9F65p8kQ0EjURpZoMxGmaRfXrxr8/TuZmJKrTQXkepDof9BTx/vzmpGtmUEALW/f90QAzge4vgR3a2MuLsN7HyJslUf6FhK71VonWP01G65nfyjQSTJv7+r/1+zTZ8d6j2VmRwxBecTABFV0qO83dvCplTVEmBgQta9qf78BAAxxH8aXbIt48nnEcj0jHDWsMuJGgctCia7MvAmD0z9bHl/WxS5FGQorWx47EGK0XJAErMEKsCKqImrjYwPBgIrD3cFwRiFWgroCJgErgklByxX7bUXUIrKeHXpgyJhEBIl7GDGgPYC35pZv9un0Dt9eE7hPZWq348P4r9TfKqFmQgpIzGhVUCJoSghuUiNZQOYMh3Pbngdux7zIBQhQvn643pEZI+47WCrzRiErFry4PONiDUxIKUDODTlajW+GKl9ZUZU+C8JIzclGlRkWQWq34T37hz8AT4QfvfheiF+pM8E76XVrtSQNg1LWXA0CrcM/0EmZBLQl9zez7IzLvN0sEZUF1fiRvhhoAfYkUpbguca3JHmpHkJx3YyHVa+LMNoEb9tvej18k9o3CAgwhFEaz/ZHThVWayqv6w/UFdaoIN6VEkhvXp0LO9Xq7wev5lpx7wNKTIz1Ho6c6IjGshwXvslg3RcFaaz2grRbYOzGGbRokO5aEbts29QDMuF1v3VrgeWCiOWwPGMzawKirTpMJC8hMrEK84WQHrMEg2bVBA7PXCAk9YChFBIG8FSXkYsp52GDRTRBaSShtvPV+MQ3bnCbZPvj+XDVFlLZtQwxBTe5Fsv7QnjdHJGgzIDQclZo3b8Hz+QQi8YSU+yN2AaUIgmg02PP5DO/EasHQuma2JjWhVVE4jMuiCaqHWxxakATQRENaMXpgBndlOS1+9Hsh5+rIgdHuxqA9o4D2NqryodA+rZIvCJb36nVHQ/HV5iVuDblkTbK1AIMhAiSBoNyyRjaGGpYYhILovdCW7PntmSB60ivnbF6FMvi8l/FbdE4L2o/GcQExxDQYBPKKdui5Bi/0w8pjHoIhN1Ow2yaBoVoqWs1D7MY5FB7edeuydt9K0vkhxggG49iPboEiCKI8kyFEnM9nmBiNWC3IcxjU+gLMyCVjQ+joYqsN6Tjw9s0ZpYpSr83r67reFUjmYpX50sEKPkC/X/asWOHN5gxLcJxmyGS7wH0CM9A9fRzZkhQHptZ/9/D4iJIOpOOGUqr0STkvCfOsIKhj0zvqyZ3MpfwMG7OCWr99d3OVJRqkx9tTT0K3X2AwSP32LJnrKNiUPfbPzlAcEcBD+ORunryfmfR6yTnIRw11pJ6keO/6frqACUbCR96UUrVoogc1F8umSsr9a/o8W4HV1qi5ICn3u4Gbzg3zPOJcTxyZxUe3FimoEQoIDt7r2mxjplXkdMO7/+0v4LFW5L/nD6KUN9iPK9ZlUfQ5grwVsKTH13kPaHGwlCIF6Ri6oM7tOOD8OIfgAz47nyfWgxSypQ+YAa7ISdbjhSKcW9BqAlcPQsUSgdpI0EVW4RYWpUziKufivFhMXS86R3iAPJ6uuyiVN0Yggvpw4HX7NLbXhO4T2VotePrwYSAK4E6RYkDVl6hXvJjR+54YDT4uiF4neRafJUtqGgOlNTBdUKAms1oRFoEOa4A3890gjcB1osSFqMEEC12hNhRfwKxS34qCkHP4A7/xa/ix/YKf+97fCwoBi1VXQ1BTYvF5KmZy7XQB0GCBCJ0+ZoH6PQ1RPWbIein0GtoiD0xlX5aGaxoLbc55oF5aaQwxwDcH9g3ONVWrNMRP0Bgzp+19BrZgtYbjOPRaN4y1lWBVwPl3QmcBAHeXpI0eP+vXAlwDQE58gjSYmI3F99sN5nmVc+7BObeGCrtG6OpvRCTVQR0bXgNWamaQ3RAo3HkUWULbyrgnIXhs2ypJdCKVcJ9tHfQ2TGgbNGGwIMj2bZ/rKIEG5z2Zsyq3Bs93wYfe7HkcxyiiLIYICF10oilpUPdRAQFNAxCWYFCvsSXEpo4IAPBC71zWpSOzpVYcxwGw+P9554AoKG5RKXxLCkyt0JI6R0BO4k1WSkZpEowKUhcQQ5DeLHLY6y5JqIoCCLqjYbQmPRSCiKA0+d7mh2JiD7os8LNnReBCvcZS1LHBTPbsATq2BKUKmwT/rUm/bc0ZOWQda64HxKIO1zCAUO7oGoPgyUQyNMkEK5rBWsiSuS1UKQqlVjFkNTQG1Z6+WSwBgNCENVkwGiQF6fUzlbzut6eoQu3JjYPzHlGpyaNYo2ODJNhmHgFzqxU5l359BYlntRrI3atS+gJlvzEGlFpwpAQAd4h1q037NE8y/x5HF82RseTB7EVlU4sgRqM1xUHnIKqDep2s+DXTz2k+54lBwdMDbK/bZ/pzjMlUfNpXv1j6HNktM6oc22u9tDbmh/P5hMsHebZqa2BixOCmwhjgYdd4IHQmqtGrfdOY64fT140JCqOp8GSLxfx7Oz7znZuSuZeuyZTJTb+3YwGIZiRuPlYaY8uOxnlgSuqk50uuja2RtjnNpL3zgBvPGpoxIMZx9GIZzy0LNpCbCPP0xH1Y8MDmTgagIljG9iBIjxyEOdyvVauSyFSqcCT9rUJpJlWtFD/Fn/oz/wWYCL/9s/8gUjnj4XISS6RlwZJFbEWYSBXLuiIui7AXkggeeRckDlJhn5wPeBYbJhFECXh4eNA1u2I/VMTLy3xlasyFHGLI4EDgwqjOodVDkzYGuMgOHcGhwqGBSHQJyBNaKzj2G8z+gUHYjwrnRTxtWRctwv//iQ69bt+U7TWh+0S2nBOcVet74mZ+ZsO3RtAeoa254BX5IV0cVFSgsU7+TvuHRI2N0VApgLxXXyWT/K74k3/rrwIA/vPf8zOIwSORUBNanRZ4i8500RUapRpvV0kOzrXi3/iL/wN+7e23wcuC6NSLKXhwrShVDJUF2bOgYULjsiwsteQeBPO04PeeKpaFhryX5mtNjOT18XcLHrqvFNAVHq1aSxhVRetRkF4DoaIInU9f0+BtXuur9vQNj6FRubWq8Lw497Kx/XMKrCzQ2jbpkTFj4X3fkfLoP7QA0bywQFCanfb9EYEsydb3G7rwPOECzBSc7wK8+e/z+83se9/3nqQYYqJv6sHBCHo0iKD28vczQGYmPvXTSI4hxxJDEFEJAKUOxTIbH+bfeKQDzGL4anRLoWdOQZ3dJw2o7f5JYq3CForAzrRAuxYi4S3HFGMAw1TUstAZNREwapv3ftBYAez7Ls+8IliNq/ZkLr0vCoAKplQ9FhnXvQdGqUytNdxut554xiVKUqdBIZhV2ObeJL4Pw/6aXXLS86Ue+c3P1ozMVJUij8GEXKoImXThD0ETjVbUjFLZq/ma8Kh3ImgUX1yjXmU3WpTdA1Gtq/DBnlm1XTFmgSKIhuY0ruP73CzUU/v5AJoQh6CKfa1Tlx0ZmsbaDxcQvAc7wDVBGMjGPgvCnBRF6wUV7/sYDYreNRJGAweFJVkT5nKPruvT0tFO620zT02QiURJ/7L93nuPBQv2o/TkwcSDZursvBn18nmyMj+v8987zU7RqSl/GcmR/Un3v7Gt90X3uYOUUqxU9lYBVmVS4t4PbHuyoTp2PxIkW7ZI4akuAnJ/ai9sX/OGF16+e4loOjb6+L08/znmSrtnpAfcC2pAX5OAYZVz/5UzFV1+b36k/XupSSFUk25bVu/2ZMm39pMCrtNcW9VeaytK9nnkY7Px+cLwCxe6o5qNATQ0LjLT0vz5CiJR0N3WFdvphNogCVFcUVbGtp2wbhtykn5p/vCVzh8EUNUYaAhEOccgH1FqQ9IYQ9gE+lzpQRNEfKfWJD3n5MG14BKkp7aBkFKBCwFn94AlyrWOjiQmWSIKAw4NXDIaHFjntnUJ2E4nPDw8Yls3lA/vPro+r9s3c3tN6D6RLeVDTC4twHEOzF7krC2JgXLPEVFaBkjoBWZ63GoR5SdIFYucR3OEXCQwIh/hVqf2B4L2Q03J/8jnfwsA4z/73d8HPLAsAUv0vfE+xgDn/FiwxVwNuZrhbkHgiH/rF/5bvI8r/tJ3fgpUMpgqWnVozSkqpIIcjhC8qZhJj5Ajo0aqgqdzaD4oSjmSkdYaHKRqvawi0c4M3DRIsYSLIBV3CxJsEbGKmPD4vQbmo2pOznzBHFxcVagidgSpJzG5oJaGxhn3hjKDammb5nZgiAuPGbbxFMAY9c/EVs7nM8CC/DDU9Nuk3skB1LAfR/9O+yKv9DZ52arufiQvhJ6YWrBoQYBRKe11S9yeUxKv1ytSSv1+iPiIIly47wHpSAurXLPVyEe+0IMYwJJG7uiJBfniKyhiLMgZObepoEGqBMlISv00muu9UqMqOkKFc1jRcK/eSARE77CuC9ZtRUoH0mTCbih5UOEO0v49MTtn7HuTxPuQce68x0m9GC24S6oMmVPqCYr3pOMswGwtSjEFtCEZbgIQFipKQCIFEKNd1VoEUW1Vvf0KqJHQCkmeibmmMNMpqQ8bNxUhqD8/DujCOTkXNcqOapXAyK7guicJANkMwytuN6PXkl5zNcwOItIQyKw8miKDEGqwmqLvt2unQjbti71eLzidztKPSIRGMl77CHOuB+9O4DeE4NGaJFc+BARFgnPOYH1Otu2EEKNce5ZrEUIQby3thQshqpqnzK1WOIINWQC361WtTHz/KeqjxyFiiRFEQFbRD1PsTIf045CT2R6kxuo5g0jotwCQUxYhnZSwnVRl1wekQ3rOQggitLJ6PD3J9ROvQgfnAm63m1J5fZ8bDXEE0Hvn5oT/nvo+VGwtMTEfyJEkWJI3PehGX+SRbMnzbqqj8swHFcmQgP0QhgA3mWkteaHRwzr30PVkzgoXc5JpCZdk4P0458TmjkL5UgJ2n8Hhpa0nuPPG42A6qgn0Ngq7RgTcXTMXAkKUYlYIQWnxmgB6hudxn2b/vXHsdn2rVs/0XLRIbP3bpIb20scYpbhapT+byCPlggidS6zQQVrMcWpcr2uArLtiZM6GuOuFtJ73nsjpgyP/GZ22IgTCui148+YtKjs4v4F8RIgrUm3YzmecTuehGLs99vNtraLULMwnVaoEGJUI1yMjHQWAw7aecD5teDiLT+jtesHOqhreMoQi29BKw35h5OMm8ZX3eHzzFg8PK7717g32I8ERcOSCdFyRmlggOBcBEoTVxQXRMdZA2ILDFp0KLr1un8L2mtB9UptWrZg6NcnJKioTInrI2wVDluhAQYLBxkBj49iPHgarGIsIiIgJAAwp8kuQB0VFUtrhHbBtQvWyHg0L+oL3iMsQA2ncwDsjl4J3T1/hD/3mr+FP//TfJ6+XYQXgy5DIN/oheKAeJkhiSpFSaRfEsWRTrdQAnRoIFabcZzRIvYIDeXMO0YXxulFOTMKYNKFz1KvWcrijsjtMaqlTWeQ8tJdNERKYYEOPHKijUjNKBaAjgbOhr+3zbt+qkjlk1aFJoSwwID+CSIzv97rfOyoQxnHMNMf+e/usN5ENuw/ju+fqr1F07Xu6cE0/HtsvYCIA9v0zImInZd9HpDRh66XRLLjTb1X4waw0ejcLM7hp/5LjLqM/7gd3lGf0oDLqdLBdyVQRZUmuqtp4FC0AuC7YDEcFAAAgAElEQVQ0YshvLQUumt+hQ6vaM6LXJ6sfmyVk3oJ7Q3NYe9qUhmvJbqf4GnqIOi6qjXcN5HwIILXLEGqUUqHroFKzG31z/cMYSd0IYqebZ8m3jmdJVhThgKBLRue03dZS9LkwdI21t8WU9aBJSu2BnI17u56A9gjrvwXNlN7WUrK+lrEs9R7d0X4ucoM22OnG9owVnR/sGnsPsv44IvgggWkX/WlD6dd68YwyOCiruDsXcsqOqNILaJTtWiSRbc4BFBWRUyP56bnnlpXqJucgY2nQC6HPaikJtQqyH9iUZxvQSI9b5jW7qzJfjDnsOQJn5zTPRWNeG6jq/DvnqPtqCfL1coIzEhRMc8RAihgYbQRTsnh3DozJLNz169EpvmRURfsijHti56f/6O/pz8FLxy0nNa7HvMd+Cjq27k5sHC+Nvdtb+qOlJuzWfzku1f2xOOf7e+b14/7y6nif9tWf5wlVMxpmT1CZBWmm+QrItbf1zdY6KRZ5UNN+V0vo9frbxbfEDOxgDwhhsADQkWxN4PrS2sZRk7zuvENcVixLxpIBuAAfVhRqILeAKYA84FzDenrTv8PQ8FQYJSXUmsGQvn0pxBLIBUTvsawblmUd56fPgMQAQzG1tQIupjK9agxF8Noy6JyInOy3GyoF+LAgRIBIlDxRpb+25APH7tFawe16eWHcvW7fxO01oftENu9dN6B0oE6xMPRJhEAwLRD2OaFpbecHEQZpkKZbliBvrljWWlHSDueLipOUjpJItYxxpB0xeizLm4GG6HTmvcN2WvH4+Ijz+YzT6YQvvvgC79+/R60Vf+oX/2f80rd+HMU7aVJuTahXzCh3i6tWJd19D5wgRLGjSYb8WM+Hc4owefQemVoqGsl7UxbD3p40BGCJSw8A5gCGetI7BTcwWqu9XyrkAhbY7wQVqaV2vzkRBYAsahbs0rwoj2TTPKDsp7WGqtRACyIB9J48gNBqQ05ZF3Pqcv/PqZ9W2X1OkTQaqCXRc9V27r143lM2+x3ZNgcLc0I3B4D3cRHdjdc7mlZ/DVjXrSMAMkQYtWVwNfN1SZpT8iClAZnKpSVqcg0JjqEItSmdjZ7MHuwTqTCMma633ljPDdPrFtiLqI/3Ii1vIhZC66yoNai0ulAeJfEoqEq9E3+vRZRpifp7xPtO1CtrzT1hdE4Sa/8QhLJoY03FUKzSbQFejBHVDaPxNiHnzCx9ZCCAfY+n+32jKTXm+6C930VFupsiWgRS5Uc7pjohckW9nriPt1arxq9jPNhxEmliWEWls+TQUZtahc5bUgZ56RUUm5SMtZ9r60kWM8OT735krMGyM1qhFR/sPBVtLfpe6Q8Nfe7MWZ47QdqkkNXaQJQsQR0WHzL8gxPEwsSarM/SOdJet9J9Ek2N0IzVcykoxa5LQ1X66LKsavotlEpnSr0YfVTNG93SxjZQK2GJUeeBBmoyF92Jmjwr8twXp3A3f9rvZmEbmuE2e+gw1qpuDkOzaNI0vkiIbA3zfCWLXX+OeRQfeq+ctSbov+/H7SiC9ld7TjknX3Ma8zXJ6NdtL+2GLfEz9db762ivWcHPXsez6z1vM/pof39OlX3pc3fzM/Oz857Wh3Y/L5Nka91KpzVGqVWQOhdA1OCIhUbo1LpAx7xUiHUu1f9I11JnCTI0eUcFqMG4oLO4i8zrUpyLcUFcNsQMTeAivCMwBeRiyTMhxE3YFk7WhVIrSgNKTjK31CSof21gVct0XhI7mxOtkGtzoxRbIPEBGM7rQNQ+5pwPXC8fcDsyrrcLbrcbbrcdPp70GYsgEtSx1oR0iIVKyRneebz/8ou/8xh73b4x22tC94lsnTKiCIv05ixYlziC7FJ7IhGCqCZtpw3n8wMe3zyiNEYpDTlXCQKUdmn9dExSLTanGEtgGqv4ARjM1lchC2RRxTiA0WqGcyQNyhpgWlLwd/3o1/GHfvS38V/95PdQ1XOs9QBZ0ZtprZF1w02LGGsVXREmRQWqk0CwJyJT4iCqdrLv2kQ9UMQtRkAqKlhazdQquiUNM43TzM4Z0Aq4G4ssc9+vyZQXRT56tZ61L2hqmLfqbg+UeMjrG4Wz1IqURdVwlnpPKhwj98d6AAEHh0r1/mLa1hO8uSI9gnciGip+JBXMUaVFR97MKJnIdZ/AuRpvUcwd6mhoHu7V1Mb7MV1/DbI0OQWgAiF6XxVlcuTQqPXAt1Z0JU0zdjf6lPjoGZWHgDAq43I/ZHxbb5x3DrVw/z70sYBeiTYPO6t1O6WxLcuCZYkw5DsnEycRH0UpJgg9mQoh54Sca08ULTkQqluDaw4VggKKwAgjBinWxBDRvFCeahERomY9oE16vBwzqDfWc3825mCu96uo0A+m1w2xFMGdEYnT9Mg57cdlpcKS0x4dReHEM3JQLNs8NjA/D2Nw1CKFEQJ1QY9SCorPMl9pwGRIPTV5Lg2h62Oep/lFK/rOetSsiAFlO4QAp8IQ5r3oVSnPEDIQdeTBkMUQoorTROxHUnok+tjqfUbt3t9P+iorQqidNlyKYK3mZ9i6eIOooeYsNFOCeMlltZ8IPgCBdT5u8CFIb3Kfw6oWvka/qLy3duuDWgzRRKdazsdsyOO8zayDl7aei/A048xvpelZfLafPiJ65me9rdzHoqFzvVik6JywJ/xdstORt34ajLt/Pj/2/g48/+A4wCkBenEPxBCkbf62eT92UDJAO2L37Bo9T/zmrRd8gU79f5502+deKrJxfwYAQxJnGvxczJnP1v7eZPJCKRXeS3HVOZaeNEvqNKFjh2n/DWBD8AWts8ss628Dk9DereDQdA2phuA7QlwWxKUiZqDBAz5iQYQ4Tip1laBFNV1HXYN3DedHYQPUkpDSrvTdDKcWJ4AUwcXuRUTozNaItXjYn3MTQWGva1LGvl/x9PQBe8raG51FdC5q6wiN2CqrgrEcj7TMHPursfinsr0mdJ/MRhrABSwhYttWnE4nnM/nHiQd+4HjtuN6u2GLG5Z1w+PjGzycH/Hw9i1yqUipYD/Ui4ohyZzRUXyAXzaQ9+KXUqXSnXPqE36MoqgnPnUyQaWUu3jKtq54+OILPD484OHhAdfrFU9PT/iTf/2X8Fcev4XP4RC1t8rES9ATrPtF26r2hiwBojAlASCrOIBKudeqCIpMjlLhrv17OkWR0Ck43nuEGNRg2fXvLooM1MY9kMw5SxziRKHK07AqYIivlAVI975aultMQfNUsn2uCue99OMJlTXC5Yzd7QBKD1JmCX4JmOXzPvh+PBoFfYR7MvMQQ5muLbMo5xm1Ua5h7VLUtrjnLH1dOZsXX8XzAEXzgSmZm4YxS9UWbH5R5nNm1BsaQUNTuW1o0zokcHAavDjv4FhQOAuWTXxFbDpcDyY7JRAjmZkOClYw8EGSJPOQG1Sy1t8nHl6GXMi+nQb+cVmwrAvWZUEtWSX4pdpaSkbjqsbT8iwb/dXQsi6MsgwURGh8HrVqHyKXfn+9k/slPXsSyFqSUFoD14aiSEBVL7b/j7136bGty7KDxlyPvc+JuPd+X2ZWZiXQoARSYTewkLAlJNPA7tBBoueOoYMsN4AmEh2a/A0abmIhuUEHC8nCMpJVQsLCSIAKFTIGm6pyOrPuI+Lsvddj0piPtfaJuEm6yXdjX8WNiBPn7Md6zjHnmGOagJIb7KaGCRJqEknhbDNUPArCY9xK7papqRpdSKJJTQFASknBtuRzMcvfhoCJjhcdOqf2Bnshd0CphlqSoTYRQ2DofOLhwIHOxd6lbIqJNamd7xEMl3Rv8Gh/UBAdgwlCNY/GmXNlqIAKKOxHcdAZtPYfWNc3TOqf2s6lVjmn0moPPWc5JAaac9LnrVozT9ph64xSDty2beQSQoox7/uBZVnw7h37Gtk7YyFRSLUoiDEa1usqc2liECzLVdZJEgEe7ozr9eoOHFNcNYB3itT8RocCGwC4ox5OYbFf+3HA1hU17I1WrXuH2tIwdoUpPhsVl2i+xLwODwee+BHv7s9v3dY4Hqf4tY9Mjl1nKuWoM0fjfYA/x33Ubn7P+PUM1kKIDuRGzcDz+187TowIZkgGdwdD1uMB4u6cP8x354ECGNmPQxBqYuCk64fMjxCDO4FsT5mjuqRtT3pS62vuFQ1Nf25gCsKEsXzKvGBZOtYaUDmAQ0JaHlFqRzE7AgClBBNB6o3ACLg8fEBOAb1X7PsN++0J9dhkDag7Sq3ovKPSqHeZ0uI1Ho9SwWggq1NH1s8yZ5+en9A6oTbGXoQuvqwZy7og54gYSZ2Ekh8rZWOkPp3YK29lC76V4w3QfSOHU1fUi2u5TJd1de9rDBE5JlAIWJYrlvWK6/WKvC5+HjPqzUMewhAAuD484N3334Mo4Je//BX2/Rn7/oxad4RIyHnB7/7u7+J6ueDzpy84jh0/+tGPAIjYwC9+8Qs8PT/j46dPgC7SRg38M7/8Q/xfywNarXj68gmYjJ3z5jSAT7fIiD5zoIDPnz5Bc+zlWTynxICHydlL0rLIdHcEFQuIWmg554wlq8CHRiCc6sRWe2xEEuU2tO1TQMpRRQ/MuNCvNgy5EIN7ktUHB8l+NJrsENK4p0GazH6pRaXs8fXNVA1b6qOwuEUPR7QFI8KAUXfODFzEgOv1isu6qgefFWhUN2LtGXcVWpk3Yrmnjt7J/+bUVoxxyyz5R8JqE8NQDFzZaKnUUc/LwRRj23a1aVjEZkxW3eTmCe7ZnGYNLBk/TFESBiQnqvOpnZzOqBFby4kymqWMWVYnQkGthzoHJDF/1cicFbzOOSHluWhuxe32jGPfveB3jAnrumgx6ebG+u327AA+RDHMUwwyRquc6/hyYLttqvaXRiQChJAlii/jp6iUvVIsIaptUvIg+DNBX4eBHY3ERh0rAkqEsiftYs6FjqjrDivFkQMj5giOCeU4sCttmCFRKSlanib6rkiZR31GoUk2lBKcemnR7xZFOdMl1pk1Wqgqe6TRy2WBRYZnyXqjMzNEgbKw0BhDjLho3u9RpURAiBGLnqs8P2M/DgHuWXIemaF9JjnHI1/X8m+jzn8S8ZZtE8dJzuKAKRIJPw553nV9D3NI7fsGALjdnnF7vuEoshaklJGXxdd9ez6L0JSjYFdVv++//5HQbbVo+FEOLJdF+jRJKYRSK44ijrKYIrjIPLrkgC9FnCQWkZC1YOQf2vp1T5W2+fSCQvnViNbXo3NguKOj6lerTSPkDJF814iOniPEiJSzzMFk1FP2iMt8JfFb9HFlczDM7/sNcavnVtGpaAZmZCfdRPOHTr+fsZeeYWIy3O+ZBMKqYlUG6Kym4f375zUbOCuYEgA0cTwEZjSQOP+6lGwxOrrRLZkJoBF5A8SxJnRgiaKDZD6HIGUBrERHQwdDxhKzAVGtY8DGpIC8jxs6ZH60XvF3/pP/CBQXhHKgdlGHTJcLUiXEmtAboXJE6wmszpvLumJdV4QQ8PnpC56en7HXG3rriEsSunsAYrog5yta77hcH3Bszyj7DWW/4fb8Gb1XrEvCumRZB2JEXCpqH87PmLKCV6Bxw217Rmvy+pIXMCIAUpKGqFyWo2A7Dnx+2rAsK5ZlRb1ckGLCdnvLoftWjjdA940cLpIBoXyVWrHvB25phOONDmQy6ACr8trhteZKnQAQRpFkAya1HGAiHMfuRmDOCf/P++/xcL3it37yE1FRY8bzLYzcjxjw7v077PuOoqp/zIyjHPi3P/0CP6sFf+thFW9XFxIE3FupizjOgGWoGAK9ja3xtBcCDljM+AeEXncyHgguqX76UtDQlQ7m0TX1/Lthku+M/jCU22Zvo1xKyhkI08ZknCeVtSCb6LbtMAqT7ekSDRQAF2PEsQ8FRQNVTo/RvB5o7R7zpMLuTKNh5vMk6Ibqns+xuUthVfO+v1TVmg2C+csMCLu/+furB5F7MO28kg8WVSxEQKSH+fQ4XPFRDIbe2t117j3GVgQdIM/MgHo859xI/U89qtL+B5qCEwNx988ABeoUGMzi7Eg5eVs0z8cjjfbJPdYq9J5S5P5i7FjXaVxREKO1Vqd6sty0GkQBHBSg90GZs/FAEKNblDXPnnpzFJhqneWDnKho0AgHxvSZDcfRZ0EjJMNADkSeM+biHTwip4MiJ+eIKYCrULWAQRMzz3zQe2YFI72z36NF1eYhIJFSLdkS1MSf1hOpBzdGyogIjGL29j4ADpZsnFu/1tYR4nhuz3FzD71RfcnbIgS2hUKilKVgWQX8xxA08jCcUkYjlejmgW2T4tmyLkjNwY6u6y9JEXDLWeRRRLnW4vUwA5kzpXsfWrSyluKlFigEz2Z67fh1Qbkxr87iKC+OgXZOLIL7n4bjTtdoHmJTEonUdYDHek0q7hPdwXE+F1jUZ0Ejt481b3CsO9N+8/91zA1ijige6w3Dio3bWwedkl+9Ct21jUXu5kjeFHUjaHR4UC7n9j+Bv+le7/+uO6F+15qmYa7BaaqhESeBmTAcdqZ+yxgOxNY6QmgIfYiiePRvPPF536GJUUE6txHQTWAHlrE2nt9y92Q+BxylS/H0GBHSgrRcZD0+CmKuSJ3RQgVTxF4l5y8wgyngcnnAkiLKsqBsC24xoh4buIj4kES7KyIm6q8UzVTHkkbzNNrWmiiLB1Y42wHQATSpQXccUn+314oek1L0KxoYtR6/dvi9HT+c4w3QfSOHGCmy4NXWgOPwnBRL/jZTbFkWdNYaT/suC08q6EpLaX0spmbkEUtB2kM9+J8+f8LT0xfUWvDhwwf8F3/uL+Bnv/0z/OTH32NdVjA3xE8B27aj1YoYCB8+vENr15FvxoyPv4z4z/7gf8D/tlzxiRl87MgxKuDi4YHl8RnHYIZyeCyQvnnPnuBXLIzgkt4CbF1CGTRcv/oxU0fs93RJDCXBESG1fAx4gvYM5mbrxKiPDJG9TzFphFAipvtuVFb2HD4x2nbPzSlaCNk8/YHPOS0IBEIfhb/NwL4zXD1yF4Ibw00dAAQgk0RSwFK2weiU7QVwGsdrAO5sQE/eansNZvAO2p3R80S8hl81oqRmF4GI7yKyA1QbaDJDoHNH0BqMmO7J840ArzdITGi9onWg96rjhP35zRCEj9vzOddlkRIeMYKhuV0gBIo+P1NK6C25ISr9KrlTOS9Cm1KhIRP66cxAk7pjMQ7gR2Q5rEPwRdpF8gjzsmBd5lIM07id6iG6STkFCdzo8z4jQ2HTAJ+pYbKGGIC0eSSCRd3HkSudqkPEIgnnseEDScsK6Bql3u+g9aKYRcgGPp6GlyAHU2BVwEkSTSMygDhqKkpuj1AUrf6k2ZxGZbdal50lGifUWHVi2DipIsiC+bxkBdWrUDEdCIvAi5R6kWh/rSzjRuvk9d5QIZH3o0iEkzur0IlGMxq0bEyW6AxISpjodGytYd8PgAhJryVlHUbR8BACMmVs+ybrQ0rqgEhiON9Fg2x82LPN897Wx3nMuZPtDtyRLVAv1m4e//N4iW1/cCaE5ETXCXQDGAqPceTO2YAxhyGgdQFnVEWwmil6T/rivPSdbvUrcPf0PHpPTFaJwU90fuxXVry7drlvJrv3x2dx6LZl8T3BAJ3ZC87CmO+Mh0qofwfQ0Uahex454J37GAuTwExQEHM6z7TPipOswoRRIhT4BAXTwwuqLAAVsZrHm36GERBaQJvxszVOSCBqIIraz8BRGiKSCMdRBEICAiRStlwkwt4l33Q/NoAbIjECGOvlihgu6McF5bIixYD9+YvkJRMLPfIooCblTCiSrq3QHOIuucuRERAl19xq/zLQGoOa1K+DlnsoRYqpB4KW91Bn1lzD9e34QR9vgO4bOay2FaBGaTAvckXvtriqeluMsomwFvjuHdyabnJqaASJ2MmGq0ZX76jHjtYbttszStkRY8D1esHlsiCQqEEFNYzMQLTo15CzH8Ie/8bzJ/ysV/x3P/8dPKpxE9jk1RXwdAY1pVD17lEm0o2PcI4gyN/gYOSlp5ERIgQI9kExG9LVY5OLUcQppEiwetUbfPO365uxOq5hBs0U9Rj2sUcmDOxFVcDLy4KcFwCET58+u4FhT2efkehNhClZ+jNjPv8wKoisPSa1TrKo3Fk50/LvrLaWGUNWaqD3NNGrRiTunrZjSl8ngDn30fR+u2fzBKt55+8zQOsS0B41g7eLGUKv0U7tI8zwNjWDgf3awQtDL0uGFb735HrIWKwqAiQFPsY4Y/tf2xlEblybEEpKUfPENN+j1pMBEhVImgAFd1EoBQMpZVDS82rRcgOcBuyG53147U9jrWvktquqq+bluSqbgbNp3pgB5M4S650ZnHt38emzcn2aDEhyuvTRJQestkElZUghYGs3sr6d+9PGnIkX6D8QPOrSVcp/XgNIjXfLJ5I5KffpUVlvqy4+f7Ppe/N+szls+bMOOk2sQOmzUh5DXCi1NVVOHWuFgE6hBqa8eHHi49hRasHam1JcZU6CJTpdPQ9J1kNz6giIj4gheYQ0RxFsWZYFDMm3g451gLEfO5gY13gVZ1JIqK0AOiZiDEgp4Pk2ObFI8oRrm4HZmNNmzE94bvr7mIvz9zMWOs/d828Kpvj+j8NTZk6CUg5VY25eQ8zW9Kg0wDO+0nHlZyQf2MQWa7Zr61pzuvprwOv8y+l2+ZWfcQZnNFaZ89/uAM1YE8/38Dv/8B/jb/+bfxb79WIrAsyBl5RWPK/Vcpoxh2dgTwAUccmeqXm0zIw2pwdM1EsbGYEIFOJZURRQp3MX8TK99xDF0TUt2MOZM2FpIvefqVNN7udf+2v/JUAB/9Nf+Q8ACsqCyIiJETMQwagEJIguACOgNsZWhELeOhDTgvV61ej0gacvjHJsyroAUs5YMqFHyXM+joKYFoRYIE4iFqXe3gBi5CB1eKXywHBWWKQYuk5LXVCZO71LmQSGOOZq60hpwbpmXK9SJiGEgMv18nLcvR0/yOMN0H0jRwyEJSWXVJ9Vx8ygA0YkRjzSEbV1NN+YI2KSIpbMAPbDjRgW7SjstYpHeN/RWxPxlcsFOYsh8ulTR4x5qCziLFUfQsSSFzw+vsP79+/xLz9/xHF9wHe/9TM8lAOlHNiev2DaS8UYLIcafeaxdyFrpLmwt4lV2AksEgY1RLyWlkl+18HHn6IBZlDmnBGa7NydpL5ZLaYe2WHEqUhjAxTnI7uBMMAVi4cRKmvfuu/jInayYF1XrOvF2828/6ReYaP9zbkNZkDN1JiunkIAEPfv8MKy9be+34Q+rDZgqw2b5jaaIqJ49yu4FDe6Z2n+0/UnUHcfwXuN0iM3dQZXlvcnAAl35+7+EW8DIpxNGQwLgNWzizPIHUaU5fMJIJBC16s6OvaT0AWB0brRHaFFXUmNeQOGIh3AwXLtguTPrYsAOjX4923TDdyMzah06OBzZ+QC9Ym6E0Zxb6PykUWH2tRWo2zE6CcBl6UW7NsuUccmQizDYJfPxiCgp6OPUhdTe819NUDe3K5n0D4KdWu+W60S+VRnkUXZ0go3OgEMYR8ec0rGfXAak13L8huJBIQTExDsvfL+nCW/pVRpd8K5eDz3ht4iOFoExcoCiOgKbC5qJK3VOq21I4qGwB7BaL0h9oYYrDC3jBnLZVovVxARsgK6qiAtKfgIRGhOk1QQ2QlW45BZnXopaQRdRGmiqqrmnHGUgtKKt13njv3Y0bljWRbQKm1z1EMcfCHACtYbjmFoGQeC5+7O67s7E9XgvverGJAdPw/HGOtafYeBpslKdy+yf6PpJRffUKl5K/EAsAqhBO8DWzV8dLPQ0N0hIjd6Gt/z1e9/ZtLIEkgUi+8jfV/59GttZfflcFFuZnLOTY3kueHnz4fO+OWPvvMbJ/0n+1uCO6DCqD1674SbnZRBywPYvQXrv7l2oIE62/Nhe+9QFZ2jdL0xOjU02FxWARdhG9rAm8CsjhMazqTeuoiitI7HP/wnIApCkw0ECpKTmhYgLYRIkga85oQGQmexa8pz13I2Ulrm8d17XK8X7NuzMGOMnaGALi8BTWuaxrQAIQOUIYJMkqNfWwGoIyNrFB5gljXE52vOYGgd4NbkoYm01p2Kr2k99+s14fpwxfv373C9XhFTwqdfvn85cN6OH+TxBui+keN6WbHk6MZO0qhACNG9yLZJMYRKFojw8O4dLtcr3r/7gA6g1IpnrYNS6z5odxxRWsPnz59x23fkmPDu4QEP1wdw6/hP/5v/CkSE//wv/LtIKanRYXLg5hWMQAeOraCVzyifvuDf/xt/Db//039BFvUOMBPeffheFKpaE/8kEd7n7wCocWrFjmGFfYeBawYBnUCOfo5NwEQSjZnlniyH5zh2gFnr+XX0WrHdnn0n6V0EAkRyPsLqXFlOHSXxLgKkRkX3/K+UEghDRtyAhkXottuOYy+IT88I0ZQkCSEkgMWwNwqcCQ44dYm0ILW2DZGKfPQGkwIPIcBc5tFBiPRNihGXZVFp54ynL0/a7mIkRhIwBwiYKCpMEmICqLtxL10dvE3gr2mEhiSHybzCKSW8e/cOl8sFYMYf/tEf4bZt7hFOKapIzhc8ffni/R/ciGcH7NLew6MsUY0iIjSdNdoitFYznjqrUIwqClrh7gCJYBNLXkYwlUxuMFoXKxAYXntNzuc+RYqAh+sVD9crbk+fUQ5RJ71cVlwuF1yWLCqw+65RlorDng8idLKk7HO61YKnYz/lOInYidw/q+fciivP0SOLvhFZCYehmCn1x5rQP1Mcwj+NNeJD6MHAtcynZGUVtDFjEkVYhuSAdWatXaYUThD2XcCEAE+gVsZtu6mK5oh2B0RwY5S9gBhYc8bD9arCChY9kLwY82wLBYxRe0MOkNwYj8gRlsvq42rJUs/v8+cniZD2jhaiCLEQ4fb0hD3ccH14UBpswe12QysHiMXQrYcIIRBEYS/FiFZ29FKkYDFb7Tjtq0igSBpFEMDXuhQ8P/YbyrEqyG/BtCIAACAASURBVIjgJgqW7TgAK1LcZNw9f3nG09MTjnK4wcwsUcf1csX79x9EPRRCv1zWBdfLFbfthk+fP6NWVfINEZfLxYVk9n0X2hoz1uUiY6Q2FJI1aMkLAoKKrgxlSOj4t/UuxqDrPTQSKevUbdu03MZF32/Lqta2Q/T5TGE4paJGdVtn9CZ9H5Os9KUCEoQloLHWLm04thuev3xEawdq2VCPDYSKHAnrEpGTzE1oP8gaKffsrBJY1N8o2qToAl4EnehOfdH2CW+TwYK5j5w5MNOfbUzbuuTjHIDlfZ3grDv5MM2JcR5rW0BEOZMHURmtHiAQ1hQ8377uQxiIQkCOVksx+rgUB92IahvNtfeGXnhaZ6SRmGTd9UgfA1ybVCFgErDFAVybUNlLRyVxKlzSBUtakeKCmERBtffiDUCZkTiAWtA1DOAKqysOZqBuEt86esNt67gdHc+1YavA3gjIERQTcohar7Fj30WxNUTCdnR0FGzPB44a0ekCSvJcT0fF003KC3AjIH+P736Lsdy+YL/dsO83EGRdAB9ojXG7bWi9IecVDw+P+PD993h4fIf1csGnL894vm14ft6VWRDQWMd9Z3QioaHmIA6qFPD4/h2+//57LKHgb+Lt+BaON0D3jRxdKTkxBMSUsK4XUbDMi5YWKC7f37mL4ZpEeMCU+7hbwVwxTgFJBKYQEJKoUREBOUYsOWteUAJNeUP7saHW6EIAtqB7NS7dHGuteH9siLXif/3ut8AahTCwaUb/MFyzOsYZTSlVUGEJy5Fjd+Vpo5AZ+3DvuXjO5D1BCS2AFYIW0BsmV+mgmYmX0SKBpuBHBI+K2PPZOY1akpJEXsw7XVsDddt85T1MUsOLa0PoUEMV031Y9Oc+EtY958kshGAeXE/MGJQaod2ZwUA+dmproCLS8QYurMab+6cd2M7UvrNLeFBRzwaMK5Ji5G1Y+1obC+g/5+PMXmO7gnh3Rx8Tj0R/6y4ilig0CL1LvTOokSnRCQYmMRkASmuzWnWjULSDxM7iRTWwbB5xEkDXdd6kFLGkhJwT1kWjclWoYLUUHCR5ICmJEipBwEnTQuKt9tN90dQmFq00L3opBSE0jaYN7/q5zcypYbl0dRLqsDptKswBGjl0fS5sPMUDKIgTWa/RegdNIkHgIUwhdrCVXqgwddamcvelVK/JJs/J5z6fojk22l7YxtPoG89LKnIUkZJQXdU97mM0BEJrWsagVV9fDMy2InWmrBxCC1Uo5TFqIXMV32lNDC5WYG+sBjbK+XmsWwRvRGYl0kZIHgXJKWtukea1dYnU7vshOdIaabGo7bKsWNYVeckgrfknxiRQasG2iYhVZ8tllAhdUCAylFY7lkXEYVoTBkLQPnxtPn4t4j513Ziop58HTfa0VtAg1A9Ycxe9YsDUDu2Pvq7ZmLa+6UaPFj0ei+Q7+dHUqV7c43xddxNi3l/UReKf8yWYoe6e6Vmm68ww7J5XION/epd9o/mTc0Ocf76L29nVZY8k+83aTL6LQzD6Ouf5bv57nMrV9IlKSzDV4hiUsaFw9rxiWJtoj7K1Go0yEvM/JilI3uX+iC0iqD1B1hMaYSed51HAtu9KOgZleVHqaghSegWEy7tHBenipERt4F0ozbwfAAhHqei1AxSRlwuWJSMGoB83oWB2oZtSIKwP70ExgYKwnFrdwK2Io0B2E7QO1MY4ipR1CvFAZ8JxVNQ66luKkrYKDxkjIyShZpugXS247Rtu24a349s43gDdN3LUUoAunvLLuuLh8QHv3r3Dul5xHAe2bcO27yJS0hpSFqqdRRI6zAjTzbA3gLpSMwgxS6QvUgAtGWvOWJeMnKN7A5mBfd8QNbEXrMppurlJVfLhyfxT//f/gSMEHLuqNOmfpJSALP/B8kJSdAVG8RTaBqHfjfphtcqgNBA+G4i2qUQ1HuVXU67UfLSJzjjTBUMMyF5MlxFCd2PbIlKsERoDURZFWZYFgQJa7QhHQTOvK5k6qRpVmmv3mpIkAN90zQYSI11omfNmbO8141Zyau4FXeKUbyKAOioFzOXOvb9GtNPAwOxZHkbN1F5h1KKTSJEAmaDUG0CoMrVYIfIpeqhH57MBqa8KYLXrK32oT9LQgBYbT8lBhF9baw2Zseby9jTKFlgfcO/qJZd2YJAqjKlBHhWEYHir1yVhWTOu1yuS0ruII7qCg507Wo14fPeoohUJSXMWn5+fXDTI+moIndh4GdE3O3LK0jKnPr4fK2IolFJOz255XwZAbDzJGFfDjyBedZ2kFAjUBVC03kEm0EJiuIrYx6AWtaa177TMRdWi4EbbM0Bncxzz129weOkytSQt2hJTRF5Enl4igwwrPC/F4Q3Qag4QWIFq97qArQqVq5EIbcQ+KQErOIssxi58LdI8PAd0Nka0zae/hxBkzaVRcmZZsojX5OwFxo/9wPPzs88f+ZyU8FgvF1zWC3LOvs5ZWx6HRBi3bRdKeiZR3+tdczGlgPpc4qB3W2sECBlQH06TuV/maNOMswz0jbXIoZNb3TQZ6NM5zHz/Svfz9IMs4d3b3PpXCtlbPqSNL2BQ0QEvcng68ysegxlkzS/7g6vDwe5HQd35sHEwYNdrV7t3WHzdgaHnmJGv3YR+0IBV8HE4gPKgkpPntp2dR2M8mtBSV6euP7O+vymDY+7Ec5+OyUmAsh+UxglhQoxXyJGYsQ0AxfAD4vtoIhBSiOgU0HlcQ4C0NYfm9cWIAKkT++79exGH6wwKBYwDnTYRkiq75qwVcSaHhDVnvHv3gBgDtqfo4iUNDSkAyzUgLSuIEoCA7UZo2JGCMiO6gOFSO/ajID5vaB1Yjopd6+GJw1DtMb9vKRsVtRxJTBFMwF4O4OkZnz5//vUD5O34wRxvgO4bOWJMqnQZARoe1lKq1uUaOSq9d8lxax2lSL7U87ahVTH2tn3HcUienHjYI2LccRxFIhBR8kA8j4fN18jKl4fWK5Nixq117Jp3B1iB3Yj/+H/5u/jvf/4vvtiwDKCR/abGhknsw4wVLSbtBgMLLc72DsEZU70fgnL9GSkJBaR3aRuwSLwbOJujHObRdA8nDzBANFTD/DMKTkKQSGWM1VUpm0ZETBhi0CdHpEpoe1OUywyoafdnNUbYPZRDyc9fU7VGE6ApVShe5bBoqFLVenfBk9amOm/aZh7e8fucvNF2L6y+WR5tYlHJWoo9xOhj7ugNOI4dVhtu0DTNI663cBe1m0eKXX8YJwMHtKaKbBaN0lwtp+h1S+SfaEF6Aom6djcMbMwhWl0kqEHOEHfyZLIYAIZ5n6V+V+jk8vOFu9Qcy9mpayEEKW+QuueLjjYZ4N/G3XBUmP3DLt/ONl6nKIaBQKH8Sr/aukBUXTXSxnFMY/toTczA1iqI8qkLemehZJJQmJkFqBce9RFrrdi3XanUOp+bKWkOwxAEd5h43h5Pz4NhNJ+HgoGHszGaFBylmNB78WgkSKPqSj+tJZyAQO8MlENU85rk2tYGHGVH7EkokSpc02JFCORATSJEhB6jGKl239quovobFESKamwph48xgkQ8trZp/T/yvDkCpOB8SursCsBCeHh4cEAnDjGJWrcJRJsxbnO7d8aiirW2Dth7RHl1xFnsPbNzZWYM8Glu8+m79YWsrQN59Ls+s9dHVAyvIB46Axjte4nQDcXUVqsKomgUJxBiMLVG8vWc9XwG8oxOONYWPv1+Ou5QrIE7tv8NBN7d//1xfsTz381Z+vJgTFPCr2dr//355wvN/WWRb1KV7PuIa6Ah3EEhop/0iYajsDWhsk8iylO08u7pfa6b52X6WffrpiJtpLmcCEEBnb4t4BRYtXWWpj6otaJ2Rm3BHXW2V0ZNDWhdKgN0ZlAMeHh49P3Zm00vGlJCXq9YchKRJHWA1FYRgjoQlTFjc+lWP6M2UfkWh5gI0bQOlNIAKqgNqF2AnMxbpdqT6BxQCEhKE398eI+8Cg21c8BRKrbtrWzBt3K8Abpv5DgBOsjGKXQmoTdasWWj1ZS6g3EghF2AVwxqaFniveSLyWFeuA4OSWkHQ6kKGDZ/IMkfengQuic6FDxKHRVAEopjIKTe8eVynby1fLd1sYOZ3irYDG4DTCSAzmo1MTNqE0N7PlNwUEfQom/IKSEAKBUgqmoQD0Dn9KgJvIm44aCizZRQAxRD5IIQI8MolVZWotU2QJ1dQ6mmZ+83q/cc3gbn1jFXsNxHTHHcJ8MNmGVdcblI0dR933G7qRE/GV2dOxgV1MT48MgPAUCYDGnW85tFZTv2ALMWccg5Y11XpBixK2VsjipZjpcY+0XH7IgsOVlp9hhj3McpasdA7XUySKTPWm1gHRcmMd/V8ANBle8IVjbASlCAcZJuN5MkBEJkyc+T6IcUv+19Mq7UBibzJpNFHqPQkxpQWpF70zbIOXvtwmWRkhUexWoD1M2lBcSJAB8/9j5vQxlQDtpZa9LV1lCqlF3w6KlSjYm0XSzXUue/gTxwR62WTwO/PsNyclV4hIFaqsxZvScrml1bVcfSGLvzXCI6R2X5xZDn888Dc/i9mmFnarprXpBTGk4LakADUkgOsAqA3qN6xpWpUEQ5cnYYFDB6GoXgawsIlRzQsZ6fGhBaHIWW1cvA3fIXg4+xFCO22yaRuDiKKLdaJXeV4DmPRISckyvhphgRc8bjwwNy1vqi2v0554lWK+NjUCdlnYxRlDelDmB3Wv3sJJJ1ndCmtcnbe5qfPnd9HXIXhztNTsCvD6VS72hzQvDUx5aHdhoHtvSMdrXxL/2ibaeqpKSCWV6aBhgnoQHkBuVxupyDHz6DuPMtnZwn9xCMcD6vgYvXjvvcuGnls9MPJ8G4ybsXzr8Oh8iZ5Gn9J/lyZyE1+/u8PvY4Xz/4nhmt1BCNNcHvwICtnHCa6wPEkQql2D233hEU1DVDkVOeopTWnOpkOqAbz1trRemMooBO1hutrYiI4yhCgexyfyEEPLx7BLo6pErReSE2DaWMvF6wrIs4eHR+xuNAiEBeotAxuzjJWiu4PWnJkShzwPb53hmlNjQuoNLBkLUzxISUFlyuDyDKArRjRFL16+vDO5DOWWaJ9m37/uo4ejt+eMcboPtGDuO6M4uYQDkqvnx+ekGzYzMGO6v89ebGI8K5MPaSg9Mwa2tIMeO7796rQIEAR2aJdsUo5Imf/vgDlrzi5z//Odb14nkft9sNv3r/6NGfay24toIcA3oM6o0XwJWX1b3BtiEYcDMFvhCEZkFqAEguT9P8oKGECVhO3hRVA4GyGKu1FBelMHobTV7C5lSe4Y1urXkJhsvl4rS5bdvAO6PUDhMs6V2odLeb1HHiPgyE4d0UqoW1e7citr5Hn3dpy90T404U+5h5ElxhDDGW5iC9lIKiqm/NActUsNnGUryj3oAU/OC00QMMk5vvSk3MWjzbarkta0bUouTHcbixUCfvObMqdQbLr8MA8jxy6yxCe6orReRKh4+Pj7heLw6UPv7JR4+2mJFh44McfQGUTcpe5lCrDa0JyEyIPq/AOu7yCkAifLfbE0T4Qp49L1c8Pl5dmbDWgloOLNkEBqKXm9j3DU9PTwDg42ld19P4IBAKV42qlwHuTLFV3zMMFvEEm3Febpsb8wJmZS6Yge1lDzqry9tya0TAx+r+SZ1HQCypIn3FQDdju7ECQ4kAPm83VM3dLbV67TnrM6NSJ6OSBlFODDq/YiD0bjRhHQc2G+6cG8MJAp/v/W7eNs9B25BTAqcMpo5j3yRyqH0fYkDZdwe5bshWoUQaxZKhJQeOY+QeA55vx0pRS1kdbErRZdYcTRbxpZxk/m6b1Aszai10/Xn+8uRPuiwZjw/fSxRD59Cyrnj/4YMaoAeOQymwRGhEKKXgOA6pRbeuri7KzMgseckpmsAJacRBcqxjlHVl2wqWJQOaB2rzZp6DM71ygLnxc9I1ykpkkALgCG3fZp8P7pAzMGlr9riu/qfX6rrut1pkzO0H9m1HOQ4EsKQMhKiRzeD7hZrRSi+1e3Xvot+/HSEOGX6c3sF3H7lbsWdA42+ZQDEM4MlvL3DePTq8A4d+Pn4ZnYO2eVUlVnPQDRAm73eH1l2upOReDycPAZPgWPA9rPcE8f+Q16ebDyKrLZlF9CsmhJDUEZ1VfXvkVzdVk2V18Bhd0u7darFFshL3ZgMw/tGf+tOoHTj2A0cPKD0BlJCWhGuOaLSghwX/5E+eUFrHUUXldV0u+PnPfqpjlXDbNmzbjtvzTdZKEH718ZOAO26oHeCQQesDmBuejwO9VWy3gu2oqJSwvvsel34FqSLucRzYyjNYVSspSE26vKxY0gXr5YrLVb7SckFMWUVhRGxoLx39UMekjoFjf6tD960cb4DuGzmOQ5J5ReBkLNTDm2b0pT7lrfRBX5jFCLoAv5QT0kSvynnFhw+iSsid1ThoCNG84gChg7niOG5gbl4jKeeAH/3oA4pSOf/q3/pv8Q/ff48vrYK6LN5W7Lu14jQKi3YYTcY2z96BAlvIzHPZdaGPMBgkuTyHGmgDGBZV5Wq1uCIn6abi8uoYKpTjIKcoAmKc3dM0zWCAXsu27G5gTj2FFpHwjrJvBJeBno2FmZI20xpjSiilIgTJiZFNV4vM14JtEzAl9a2qbpCk9/HSy24eTzvY3ujXFeMvBgXiZFL3BijEsN33DcwjEjXXE7NonhkwM+1RG0DO3WUwdn12jxZhRGKCgjqRI4/eB0FBQQgdHQTi+an8kTQXqqOjwgzErvRbdoqjzB0B2yK0IJL/Rcad5pqsOeN6ubjzoRy70FxLQQgdMXYF7qR0S6X3gU/jyiMbWr/R5ls31Uod9uOz+nePUkhE8tiPoe7qzy15f0b3tXF16vfJ0y3Fscn7q3VIfosCbgakfAKbUItF486Ft099rQqUBtTIrOpgQP7OkcGj815GP8a8GR7w7lHZWivKcajHvSiNLKBz8yLuAygGp1ypDeXOC7kNE/cZ86VN0a8ZdJL+HRolCxhU3a7AyoC5lUvg3oW6Z04qpU/mnFShdeSkmlNGHFLVo+4WBTlKwXbbtCi4GsxKCQNN9xCCCAiFURvPyrZUpe1frhmhBy+LI8CrWoDF20JEj2anj91SgAhqjLn7Eqi80rGv/c7ji3nQjD0f1B17XfL/pij8KUqoY2zcv+ZV23jSN401ml7e0+k5+Pzra2/luzHtp52pn4Qx4u4vwudff5PDcgvlKhBV1CC5onpP1CoIYyM3Ea2xR42I+UxrBoA5gmf9MZ4n+PlMQTOoyMd4zdZ8YJ5Xtm5ZLvfYKkUOJTAsOdAflQj4/b/4F7E3FvonERBI6eMJgRJ6WMFxwfXaEWtDbB1RUxM6S+RMol9SMiAtq4ihEURh2xwMlJCWK2JeQOio+zOOfQPiAY4JASuuy4+QqaKVHce+gXFDVEAWlFFFMWK5PGC9XHF9eEReVsS04PLwDjlLZK6zrJX1dvPUAROcC3H5ZxgMb8f/n483QPeNHLb4hAiMXBs4PdC81WYkjEMNFIt0dR7rYBB1OIkqBKzLFe8eH7Asi9IyC4qqYf7Nf+VPq+e4QiR6v6AcyQHP5XLF+8cLtkTo/cBPnz7hf3//AaUcuiFECF9c71mR3KBl8NjAHXiacTXAn9UYAmSzrlUMdPFQmjEbhT6q+TSWV2XWyUz9AGbP6USt0s3YvJxuRPapgLi6XYfB0GGOy3Ev9rsagZakPxkvbFFFnKmIIQbkJSOlrJHUIEbXBNCqKlgCuItChtMznyyIefOUG9e9Vt5EFF0BzfsijOiLOA1Ge4iKnwkUzJYIndr2FCl0+4XV6AowbMta/8/BPg1jzWzv8Tqj97tzTwY5YEBN84s6VKFQJLetM+Vvev9aKH4U5YYX6s1ZKMkG6CRCCy0EbX0MNyBsDtr4qbXKRh2mmpEhqrK6RI1Yo+aCW7t70I1OPQuPHMeh0TXWfjXj1voKMPDo/TEZrbPxa4CvNYmguBqmOotkLolwyLYfeo+Tc0MV5czIs/PPMECbd5rnr9muLyltNjjMoPS5XStKLTiKRG9aqWgkoERoUXWAZDOwrf9ZAJorBNr9mDOCpO8kgtgRdRzPcxS27vagEWZxgnRqOnaqKwzzBLzlfrrUPGS4WiqmiEvnDmoB276jHDK3EazGqETnTAxrXVfNY5PWMydGrdUdQyEY7b4ipiBqek3yJqXGJyG0QZ88tf5dyGh2EDGL0T/k7q3HAUuMsn72syqwsLWUppf7PCZ4PEtXGqzNSwHfwediuDP+xygaYMqHu3lMxhNhfsXP4s/Np3s6reGvtM8poukKmKdVd16hTq/bnjAfY30+Hy0G/Pnf+5/xD37nn4OLGunzisATT4COh0OUzvUFrT1YJ+kAdXKdE6AD6z7HgDoSbM8JcfoKVtzdAN25b057vc67077IAwgOmiedtjPW/UX26YQQFnDM4LhiXTtC6oitI5BEpIXF0NAqu02V04L1cgXAOPZNBGC4A6r+GSMhEmMLhMoMOnZwlNzoh8sFa2Qc+zMoRJRGSLukeMSYHNQtl0dcrg+4XB8RU0aIEZfrO1GvXVapRdc7bnsFVCYAFJX1MeU0vx0/6OMN0H0jx6BLBDcO3cPL7K+13lScZBwWuWvqIQagfG4x/HKKSqUDWtlRuKmhVFFLQWfG7/34x3Kyp8/gDmxPTyCC1iuLeHx4xPUqiptPT0/otaLGik4B4AiC1hniAC+3rZ5L2dtJd32V6e9n9TLLI1uWK3LWBW6WidZN1iJbl2UFmFHKAVHvEgoTrO10c0rpTEUBzBBmj6YYncWikfdGmdFTCITGzTeoAWRUFRQDgNuudDI0cabUiHEuSn4xJcTW0Kb79N7l83msKHmD0ehUUcuMa5qlrfW1EEZxXi24vi6LRv6kgK/lDpjBa6pzABzQzW04R+i0wTxi07X9rO1nepBTN7sVCpc2lte7R2dM9GR4lydAyTI+hk9dQUcIQNLC8zAjzytLieHIlq9WkZIUDreCziCh8UptROnfZVmc5iYqkwYEoz7jZGSxCvt089MPoDMbOL2xC6wYoJB+kHkp+VeiWGvtbSZz73Bw6aOEh3CFja6m7WrjFB2oGF5zK5rd9at5nuQAnHDACHdusBtc1t9BASupEf8akNM2cqNyHuHj+9zPJqZUSkGMB0otwmJQ2p8oXDawidqYkWu/wBxbQrXrChptzYlE+pq8HkhqRHVTr6RBaYVG0xAFuvYueZ09BI+SMeAUYRvDBHHcxCSUNVOgtbnRu4jr+FxR49nqi1nJmhR1jYjR+5MggkW2HgRTntW20yAqFCee1iXCPUi5H09jnbT1gGh8ZjABTpho6k3yKI85I8a5B7CwSE7rVVMIVBClVQfjEsEP0xx4ccrTMYOX83sMdU5CW6db57vXX17gZZuRrjEWHSRHtmcM+AqYu/NqzJEz+/kPfuefx7/+938fj08bnh8f4MRlxqCi+1gnjYaF0756itKZc5FmhsVYo22/8G4LAXBAF08gJoQkefD3XiRrO4arPs6gHvfPT+R7QWfG4x//MXJl3H7yU3nd7ilMaymUmhwicsxIUVMXIGIlR6maY8fIi9TnDKS2SQkom6y9FKS2acoBKzpqb9hLQSoV6AUMo0dGhLAg5473HyQvbllEOI4JCDEjLytyvii1NCClFXm5Yl0vaCz3u6wHOiKItN5siIjpDdB9K8cboPtGjhCS50MJeDsbsLPHVOpsyUGT13Yujkwc0HsFOCMQq0pTx74/ox7BvcS1qtE4nd9U7ExRLqWI28MjHh8fUGvFv/p//gP8Sx//BH/vZxeJjIDBFBXIGbg5b45iUGpUTb9bpMYod0AGQROYgxhmQYvl2uJL6nm8XC4OiDoLKNsx3tuZEdRIEi9ccoPeRFDMsLKIpxm6dr8GoklLPzCg1LkmRUKpab9Z5M+2Qo0GUgBPkUlp4JfeXveYT0BMXbZq9Ey148KI4FneigMFP5/bqLoBCr3DjNOgNMB1Xf3znqdl0Q2P5li062x/WARtNuos2sQTkI0xukrnnFskVLQR2QohoJQBLE0kYZR/mKIrEI+4U9S8Np4agDEooO9+X2ZIGUjoXcRvVpXEzzkhJjGISy0IPaArQJKi8hbBkppntWKiXwYYsDVAzDz63UVXrE8xop+mXti60GrFgJeE/dYnufaJ+ivGevTcIe9vDlrU2d7Hw6lCAaxjtM7CPjbuHdB1965rT49ghV0MOP99munD+cJuP5v33oyx02EgQB+CJyPV5mYpB2KILgwl0VJZ33ofjiG5UjDY6CPWx+o0R2zNIZdVn2pEmlIiwQE3SOi/KdqzdXewUVOxDgas9EatAuyCGYwqqlRrVUxB2oeSOxdi8npipqDZTFRHo/QpifgOeYfIupdak1qOwk/0nEAz2j2AYm1hTe/Pbb+fv+P0vl//+wB68zohrp15pIzhofub0SwtOqflMGZHRnCa6AsINp31/p5fec0+oZOR579MY+Me7Nka/PLZpyeledkeuYPj/A5Fp4+eVlQ/zzgnoa4LWoxIPFFHbYRPtGlg2r+og8JrE81Q5nleQCNg/nw6XnpXIO30yujCbVaYfo7Wg+nFFQ3U0fQi6+PaPCDAlYyZgT/71/86egf+67/6HzoNXP4xOskX6zoQs9SpFHXhBdWEo0pFaVJqRx5UlDYpZCAwGkPKHTC06HdCzCti3hHzipAPUAtgHBpljwAyUiYsl4i8rLhcrpPzpWm+3CprBQOgBKIMCotoY4aOmBakZg6A0a5vx7dxvAG6b+R4eHjEki9CeVLBid47Hh5EtCPnLAINtaCVIsZXH0ZxioS0ZKR0VTENWegAAO3A7cuOYz/w9PnJ89Fsge/M+PMfPyPEgN/70Y8BAm63m9YX03fSUBn79/7xP8L/+PiIJ2JE6sNz2wM6RG6/i4UJ0JBNZiJ0QAUWBnBondFLV3n8jm1bPHH73QfCNwAAIABJREFUKJI7VmtFSgmBxXhf1otQ2UAotYPC7iZcYwb1BmqE1iIodFAYUZq8ZIQ6UUwm0GwbGyDPVJso6plc9yjaLOICvZt3/lzENaWMlIWyWg4RNmi9KW0NqlS5g8HYD4kM7hotm9uc1GtPmjMBaGFzIrCCGgMttkHkZdEogY2l2UgWmlagHUcMCqCa8eTciWDeQ480WH6R2wQDTNp3ZhYw59ULBqCzOn4AVIiC0WFCEyI60ar0oNlMEmmU+yKIImBYRdDEDEC5KclfIozcNoLUVip1KuOgz0fcEAkIKeHhepH8ppxgIGjfdlgB+xRlLuWckCgictAImtX+a27gGCi3gtCdeRrr8pxmTLXGJ0Xa/Tiw7ZtHyGaqmxk8A9SqVjeqjhE4vdMixjJWm05B0mLUSlOcc0XNcWHgV4ENLFKsoJQBAT9k0R7yPhKjTr9ChEXhzA0w3Bx+Su1XW4Wsfh1GFJhGxKEcBYGCRNBrQQGDuSEnUeazSpkBQEpRI7smqtIAJJhgjCRRdgh9y64pteuswldrQouSqKy0Gau4DMc4CiWz5CBzZyzLgs5yrzbmQoxY1wvWZUXKQqMMKWFdF1hJlN47llUULZN+1Vqx7aKaaY4QA/7r5XKab7XJumnqlpdl8RwiGT8BS86oldFOkvXD40OjU05zGh51HtR4ew2Ar59zfie8x4cgBjNU+EJGgETfWZVbRcH52Hcc24Z9u+E4NikADyAGq7E2aOQGQs8RqNfAnh0W0YSPeQN1c1P4g52imJjWjnFu9scZQIkcJNofz4BuQDoekv2neyY19KfXKOotqYPwFOk2tWgChSnvvje00tHr2JOQkq4L7PvxqE8n+17THP7WLacXJ0BHJNEk+9nyOjuMTj/20RzjyQEkfzDnnK5v9veTQ2FySHWg147aK/a2o1JDpYpGBzolfP78jMvDO6whIYQOhI69VFQGEBOWqGV3OuPj5y8KGps6URpqabgdBXS7YUkRkQQkVkTJrcMF2L/gOBjcMzgEpAV4/90HXK4PuF6uYBD2/cDHT5/AINQuqp61VfRffUJON6S8uAOhlEMdgwxA7Lfb/la24Fs53gDdt3KweG1EvEAW2JwzPnz4gMvlgstlRdFacLftGdu+iVpSbeJBQkDOAcuS8PD4gHVZ1DjdcFOlp1IKjm1z2fNARhNi/KU//iOEQPi7H95L1IEYYdp1GB3ErEnqWmMcrFFA9TRFKUVQa/G9McYACgk5RXAPqIAaTGIMdduMNcq47yL8YTleVWWrAw3qJBF5Tbxt27AfIirAFhlTURQG4yiHguRRjNkKP7/sgpcgZaZqAhCRC0oSCdA8tlqlBliMUWmjC/KyiOCJet+s2PqcB9Ybq/IhuyeSLHKAkctz7xF/ZfDIvWn0UnLyGlobuVkj2ikUsZvSuUxAwqilpuDo4gNstMlZYGaArvn+gnK8zAjqGFGoqgIS0haj/U3xVHLgRp6jgOUGdgoone8vdATL6emMxlUl+UcxXWkXq2MFL0JN2o/iiBhFooV2RCBKvvHXKsqK1+tFoixR1PakLlr3dpD365g5ea1H/1iUVRQyd43ECQBwIAczlM99e/b4n2mF6INeKV8GGgeg4yimkqlOGmCys47IihqM3aJcw+CaAZlFDocxNhwdkgI7DLlXYyjzkNZ7YVtvPKp4Pvd8jd4aQpaoVtfQk0dzggmjdHdmnAIjMDvSTUdtAx5F57X9QAZQlVUAi7Y6+gH3jrgkcGU0p/My1kXyLCXyK/NiWRYsywoCsO8HiAiXy8Vre8YYBaC1BtDI8bW8SvAokxJIlEWBAYRjiKikziuTc1fp+G5OG+vz1zpI/3COV73SfQxfE14/xrhlBpiMDDtorP6l9GeLSnajvU/9Ol94igVP/782yoYoCNE8e6aHsDudHoPuf7h7xLEGDnaMjaTxwXsw9+sPvr8JPc9wHozZyRhgFjBnqwGswSwBoGsaVFFXz6rzzfbS4dgEhNEr6ybbXjTn0CmYg6WHaG70eA52x5bf8BwWfvmEuudFxMgyTrTPQgygDilDwIzGHR0NDYRGkjZASnU+WgV1xrZXOStFRFUmLoc4S2VtEtG59SKsDBHfqUONOSZcLgFYL1gSAbeEcntGO3bUcqigSUCtjP0Qp/R2FJQqTs/UAZCogdbW0XpBKF0YPTZZyWrfTuWY3o5v4ngDdN/McZ7UttBKdE4WH0ANphQRDouuWXK+nCJE8oiCeG1FCXJ3GfJDpPEZMJUlN1g4ANxATIgEoTZYBEu9gQ+N8W99/Ii//+5RNmjb0BkAtLCxAghA5IkRTN6+ewL8yJURL2AkEbAwqqdJultkzDcW3bREkl3zjoqWJ4DsRWa/McNl+Ws9U1pmgxFq6M6HPbfVkjOhFzHq1SPJd5TEyXB04zIG2URCAPWxAVveFLfJcGZ2MQ0QQHP9pjvD6fSreZEhntd1WRTEGiipHmGQyFXz6J2NvCFKMtMoB1Ccr+XfbBMMJv4xHASuycazWAi0Ldvp3KRGnud7KYgwYDgDOmu/kbchFmhno7sFz7/pbHl/qrTZR+6SeKjV82+ueBuzYYhpHJNACVkLOniIk2EKmAqgqd7Z7VkkZozFim3bvU6S1dezzhg5L8MgNgPS++NkdM/vGU6DUQRaS2WABv3TL2a9ORldU9vLqWi6xjCO74eFROVFTP5MesSLPpzvnXAed9Mlx3vMma8PP3Jbp/ayaMVsUN6P4QlInMYbzsDRHCw2/71OmipIMitAJ5lXC61C0e3jxpdlEVaB0rKYgctlRc4ZzIzYur9vREE0KlmK1lsc4jqziqqBaavLNgSMwnCc9OFosXIrti6esMMd0rESFxQV3PPLqBw00iOCqez5m7YOTT0HAzXuCICtlbYXqGOyFs9jBvPIn8PdmjSPy1ds4XldP3+fxgDNEEye5+Rj0LYyv8lLR9a0fyhgNSVZAfxj/Ryg7jdAdl85bNbYtcwhazcRpvHOL8Y4+1ia10z7XCBSJGd7p7IJzIlqDJEQEEKGR+P9rgxsjnuxnFKXmrUVhwgEqSpuEU0DqCEEI89Pi4A8c4fNy46GjspVKI95QVAxlNoamlMfE5Z1RYwZrd004igO6RATLssC5gWl7DiOTWj0TZgbKWWkGHHJAYyOwEDRdaKS0DhL6ej90OtWbQ9hKBEEvDXuQO9o0HqNcy65rz0vtva34wd8vAG6b+TwAq16mDf/6ekJpRzYtpsnyO/brqH7ClZ6UQxJAFGt2G439FZdphfcQei+gYK7iDJ0UbA0Wo8sqtDzEXoMKMeB3tRbGgn/zq8+4xYD/uC6qjFl+Q2AbHgCIk34pOmOyAowmhcmHkXAqas3cPKwW6TKjNTZkAaCCkaoBx6yIXBnNOpAY4CSgkJRbexNQaLm2NiGMe57bEqkRoSBEjPuYoyqSpnQavdcHkA8e8wi0iK5P7K0S6HyAXx4upb2vBvnRIRk6pUMzIYpM3sNJbZInoJgyadgiOM04OF6FdpHlcLQ5Rhy7wY0goZax4gzgRIzgIfBM0fmYF5v/ZTlKJqQjeR+HSosMSJ7ptBpOWz65K4YaO0o4IxVVARansHawQxU0mhY9/sxIQDuHbVUjewZvdCUCuX9IUSkHLHkjHVdxhjoTWlGpGMlYlkXjTKbgqD0L4ikBlm0+kxq2JLkegqdzOg91cdErVZPbZeIIY8i8TYezCC038nH6jAoie7/9nJNuY8u+win6XefW+d3wQ0v7ym3xmcfgxllmioqY8hKF/RB1autIlOGlVowcAEdS3avdLo5fQ4S5ccUO1psEwAc92y/d4/8KjDXNWTQA+FiMKf3nQzicX3Jgx2R5lIqcsry8+QQuTDcASfjpEvkLUgBeRGfAr777jt/vOv16m1oEeWulOjj2IUCp3TenCJ6Y+y3DXlZtGSGrIVBC4ubKJSVJWkaNbA2907jMY4c4A1Yi1ZlfsYkZRp6F4qwRb5tXYkkpDFZy6PWNhzrG2MGgMPwjyEAnVE1f643oagdx4FdaccgaO6zRCEdO3WJqAcAIRk9nu/mzDSO5kMRpYzXM4A7vc3BnAFRggsr8XAokeVHT4DVxsPc3vdsEJlS5/szVsaYz+cxPqYFj3xym0tgDAEpCJUR5M6EudxDh9EOpQQGEDWXdLSZ3YfQ5WW/G6VKkrQHJsEcnimkmgeasq6To4QQYHNNcZ62tTkeMKUVgCV1onbJd7PuE0dKQ+mM73/yHSgkICQREKoNPRPyumJdr7hcHxDTAu4keXW1IoaIlDMuDxcQAcceAWLst4Z9L6DAuJCs+QyANKIXQgKFJpRusJZ2OVQQJeByfZB5riwLfVov6UBaeI8xhILuGUFvxw//eAN038jhESvdnOz3bdtEFCAGLzUgm70AtZnf3zWfQhQnqxoBDVavzj11CrB6awIKUhq+tt49MkewKJq+D4zMHZ/iEKrw+mVBSILD4B/iCpZDJPcieS5B6+M1NYqCSi1bJA6nzdk2ASssBXjdLt+YTXSBgd4RukYcJy+ibVS9a97NK3u+nMnojuyLr9xjwLqIh/2gQSudwanQCSVaYfRAicCcFSLh96PWyqj3+5WxwR45milLRADx5AxwYDqiFUQGGgETvh6e2nEN+36OXs43Yn+fjBc9vymkieEg9yGPNpWE4O5UPtLPjlyx10v+zuhhgMrRJuqyhtdh7FqPjsP4vN43yLzHmkOiXyAM0DcZJ+ZRDQrQRv9KH1sx3aiRDHFCyHMZ3dQKwgs1t7lqo0TmJkPPgdPphVM/nD3/5z56zYA9v0SvvXh6M3nPyDhhenk/42Zw0kBwE17HvjlBzGkg4kqMkUejDzR59+2fX82MdBIQ0CxaQLNRfXdbDtSgwkXiDPBoP91RrfX8Zxw5xRzMCcLQuloNKWdwg0fLLO/WIxQhIiXGsqwT5VnGRs4L2kSHs2hgiEHET2qV/BsTuNAmCiGgQ0Ssohb5JpCqZ2p0xaiY5jiyefYVaqQ8F01zebThPL8BjfBSGDnGOp+8GzFHvOynGYnpPqWNLSBkKlWge1stxfeJEE0syntXZen7NDbvSxYMUHTq0TvA91UT+h7o+Ro/tRthrG0+Y+TNrBKw5GsVnz9sJ5ja1n4+AzqcnkOuNwNNK0VjUVc+ncvG/Ll0wbx2WomeDrCOH58Mej8hOqiz8gVM0Z7KFSgd0GmbnIU+5F7oFOXT+q4GdtU+cVaDXsFYLJ3n9VUAIjHhen0Aa1Sss4qcWD6xFU8H1LEbQaTiT0rjd8qpO4qlXW3ulcIIKm7UuvUtAdxFiK01IASEFLEsF1Fp7Yc7iaCOJNL2IKXSW71Rfm1svB0/6OMN0H0jRykHaisyyb0IcsPz8+EGx6DKHSBi5BzBLN7SVg8UdIAreo3oKQFLBqODwMgxoVHVGk9yzbFZq2hDJ9yen08bAHNXgShWWqdb2G78yKJoYEyFHCgOcKCbUl7Fs3y9XJGXBQS4VLvR0mob6nvQc9nPkmMivHjutmsqJQj6JiZwN09ZxUpJAUdyMQc7/0zzilZdXR5JqB1t5HUlrfV0vV7dY2n5OUalsw2z9Q4uFU/8BCsFYMatiSOAAoJ7ewM4SD9UpcalpLkzRSKaFAMeHx6RkiSvHxqpjUnEHaICpeM48E9/8U+9h4pGq3LO7gCwnLk5SqGtNwx7AzVESFEiuLVVtNIcUBKRAHI3LuB0KRs/rWvezwTAzHCZrgqAEaN45A0E7tvutdBmw3II6mhf9QbuBA4MViolaYR2AEfSWl7R8+wY7PUNzZZwwKSeYwMPZkSnNCJvRo2rNThoblo0thYrC6K15CbKpanICpCd6GSzAXduGh+v88v3f/dfXpzjhFamH183Jr5uYkzneYELyV+vrfmfDXTFHpWaZ2A0DNAHOACZT+dRC5BTsK1GpTuRLAJFo40oEIiDGooC3jtBVG87eR4NQ8pLDIAcNCdHBtZoXolsBFWmO0rRaNKOnBesq8yPo0i9vJwXPF6uCCnhuG0opWJdL7LmxYgck86zQXcPMWDfNnz8+BHHvkupjCY1Afdjx2VdBUyxRPvAIthzWS/idFBqt9BENZ9KI83mahsNN76Y4bl2NgEs0tZad/qmgNfoRnDX6AkjKFvPaOR8GsfmD3PHGHew1RcsB8pxiCDKvqHsuwhglQO9VVDKBjHkc50AdZiMqOMAbD5+FeC9GKFEOH9qfPA09k5Gto6FF+N9NKeJHbnTlHk6xTlv2i4z09vvT32+lt5fHyCOps8DQARGLjoAElSj7aZOXF1nApG/1nuB+iTA2n+s8yBGQkwZROkMqMhJkUBQsRuLsCkoMyBo90KachBzAsUgfUMA9eHk9QWFBvJ2kGfnISksnhAdhLbeUBurEJGcT/LqD3z58gyiIAJUWtKp1YZeCj42saGkZp04wR+vF2E19Ya679jKgZU7RONY8wUhdkhIGWlZEVPEuq5Yr1e0VpH2LIwLAlovSHlBzisulxXruqK2iufnG7b95mkjMX1lcL0dP7jjDdB9K4fY+DDLRHLBLGeCT19SoNaU18Y/zzcAYN4m8xbFNBSthgfJgJs5XM3AnU2Zcx7NOPgrP2PkfgSC5OnphqQXYwzqW1RFzN6Ht9sK68LEMaYImRh1Cax/a60DVE8tJJex+lpWl8c8heRGIXgYyeZVFOBs4hUsIhlexEmoYwIEihfAtVwbbzcz0FXJTUC6AYsBbCxqRFFrXkE2WwqqShgDuIkRkFLC9XpRSldDuG04VFSBQOAA37j2fXfPdtcoUCByw8P/nby60sfD9BOjJGrx80AEHAxWwGLRFQkiWMuTRjHU+4gObmbUDW8kqSd7BhUhZFFmjcnHSwmHGhOD5jkpysPofpN15u0rkVozx8SAWfIVy7Ko4aFR7Un63toh5ywGsiq/1dqQpk3XQfhUL83GXCnVI3C1NI3QVXXQ8PR9rgP1Ckai6XfCeYoNtKQfNENx9J39fZjV9tNrcO3+NXePvHz3fKMDJagdNpwBXR0HCC/Rn4nz3B9mgA6jdXwPwFDL5en5FIDMDggzXBsZe8CcJ1peworG65U8shMCqBs9DaNEiK2pemNNI61GfY4pybLNAvZzhgiRaDT2KGLYmbJljENkAmAf46WKMdq1zt5w6IgDI8UIjuxRLXstpjREfnqXfChrRIYIvn8FpTOGPe79QJOwhu5J4sCwPpP2ac3mrtFFbU0ZANvGiNPIFUxY6RJTbi6loKiCc9ei4kTnocYw4E1jbPPd1KAZ4H2FaXD3/OMkrzfSC8B195qMDfKfB33f7unOEeJ4ekSHnGljN6/A67UHoOlrXHcGdOPpph/V4QGQ5xR3ECkFnuY5ZAIocVpjxlM7zVr3K8sFGHOEHNxZhMpqrZJGroSSYrfGfn8M4O/95b+M7Wha866DmuxjjSsKGKV3FG54evqC2oDaGbWpAw7iSO6toZcGMCllMuCyZsTrFQSgNUlZ6bWg14pAUrM2RkKrokJJveHh4QEPl4uqr+4696s/8LJkXC5XPL5/dAffbdvwdHsGwEgxYF0SHh+vuD5c0WrVMSrlnloDUny5Fr4dP8zjDdB9I0fvzQvaesTAc8hMVGTAFqNMaLb7JEWsxoJuukaxm1UiZYOmF15M2aSFiz9yWuAAcIkRf+mXH/FRF2b3hvvOO4w332b086otLp7dKkpUOWV9hnsDdDQC2+tqOEm+1oLeAVBBrVrwd6IO2Z2cjHstxNzu9mwzQKLmgZlC3nEcOLRor2xgYqzt+w6pmVbdw/aC7mINoH0YOZ4Mab8vdARJODo/O8t7yARhyAC7UM44wPvYm1we2A2x2YNrhrI3zHQ4LWUC93MrEoBk0tYhopLlIBoQYcmHuXs2YKpAxfK+MURsXLN/ZlycHbU5JUWNLVf9n4GEP6CNU/Mk+2X8PfPf7caY5RxzBHHQP8mjaTQZNGNc6Tm61afr2HepJWcJ+k65s/eOoT710fk5Xjtmu475bpwZbL3v2xcnGdhvaoG7N91Rau9+1rdMf9Q2cePbPmFKnKOvR5uZETvZuERKo5vqwU1gyvpOaIrd28Bzidxxouq9gaWenP1u6+kYDFOj6vvUqWN0Ka+xZdexchBKqw5OSUtO/bZ7sppzQrPtHr0qtUrEwoxizYM1Ov3Ig4tuGzsVOBAiB6XNy0CImsMKgreN9xWP/vUuuzf2fS0yA32sN7Mi7DyvDWu0NpRhTUFzvpbP23ntw3ie7qBOonW1FKWbKqCDYQN1NE2iQOexPQbkPL9+42Nqp/tjHtNfPaevP6dfJ4A1/cHub9obbfy6zxMQ4Gtgaro36w8HtXrucHcTY7WCA0WCLqdaQoV55BcP58mIxBFJgWzo77A8OusRX1+73x3pPVieseyBU+kDH6M0Irlso0QchE+//du4HQ3YlSETAJWyBUGFxjhh33bUDo8UgwKWNbuzoavDFQBSIOSUcL1cQQTcnhu4FaWMtmEjQe9FdQdiJFXDTGhNnLi1DWGi1gI6t5PQl7CdRl1XEesqaC2h1IJaD9R6oNVD9ok26gq/HT/s4w3QfSNHbYeE/sNQ3osxoMfgdETLZ2M0sBac9QhRII0qJEQzti1yoNcwrxsRO3ABhMb2V372E9loJ5qhbxpaUPTPHRU/rg1/5yc/lsgVMIDdZCQHVzIepmMIpgzZcRwCxFpqvvjbPTKPBdU8/URSv0nqOq24XB5QtdZSKdXLL4xjotZMm6TlbKQ4bUpqxCelTqSUtD0j9mNXUYNBr2MVzehaR8yM00FTxXhmCkIREnclmNlFUjy6EwYwkM+ItWReec95ZBG8CRRc1CG4Z3eAImWzDCCtG+scIbN7ljFxb6WcgYEZqZJLNj+rGSLdx82pD/Ta0yVP15vBtoHQ1jtIN+BT3h2zG5syVsaz2jnN6WBGv+VdDiOKHFyN94lqaSOSumNWaL4KzbUFzf3U56B71MVWa04L2daq9RubbuQjYuFtdrK7Rnt+zaB87bjvu5k6+/UEe52LBLzCRsPXTdpfizO/cpnxCQf3PGo42tg0zzzmceVAjZzuZ882jz0zsE1Rr00RVqdckoAyX6Nqs6Ggr1lldkzj5/9l7116bNuW9KAvxphzrczc+9xTdcu+RSEeAmFavGQhMJaRaFgUEn06NGjQhB5NC5Bo0qJD0w3+BA83KAlh8VBJIFsCCQwydpWpF76+956dmWvNOUbQiPgiYs7Mc13V9Nk5j/LkzrXmY8zxiBFfPL7QWPMkNDCwl3W+mAPX1wXLaox6LD5uIdAW8njf9sjzteLDxobXlxVNmXdn97tvVr6CMtkKHSSg5RpYendmSPustW51Dxs9lXXxKnFfUqZzNH2cjnIh17uI1d+bolhQWDKLfOO+w+EmQE97i8bnOY4p3xm2PMZw4iYyvjrLpguyxEOZdxzeeRQv1MFU8XatvZnI1Sv29znq2n8P2OVnEo867otsocZ+UOc0gS6fknu2xh/1XudC680Bkp7Oi3D1shHSmBiAjn0ojKjh3m/FuPk71hKO+22VJ/z3VCt7RLIzgjquXzL2mggguFQnk3JStXhvA4OLLJB2QZMVXRa8bLuRpkygLwt673h8vGJOsfDLyXSIAWjH0hseH65oDdjvLxh3y/SnIZ0V0EUHxHP7pk6MaaUNzON+x8vLC1TN026RRROQ3Mfu9zvUIz+2bXN5N7Hvd9zuNzx/ecaLk9zZ+be3E+rj+EEeH4DuKzlMcRxoqmA4knhR1fTQeRL53E6kHraNCgSiThk/FXPAGOdCkbJcsgwxE1CBVx0HK7rVBTWlavGaeE9t4mVZINc1JmbdrtL66kxysHAfgXhuFMM8J+ZE1G+Li5GeEoZsDVUL2RC3eMXm4RuMaWeIGjwET9appvQ1ewdtgkkmrQKqAEEFF3kcN0ZVxa5eSPwEJvIcvoyANOLWpJNCIWmh7Q7E+YyxG4Wy0BIPce/PLSyOI5If3LZZxliAkpSPk0aViiII2OHqvKrn0xQFbyYrZc4b5k0KZgXkxTxOpeQIXBJqVyDHv+cY2Gnl9HBVOECtCl53kpIMk0zVl+1qTU5Kj82FAMpqTJnUQJs0oKvl4rmiY+G8CfxNz5wgDiFRyj4GtruVA7ndtvKMZF9MBZPGlgrMfGCi/45zL49U7o59XDRqkeN5OeyHPyrOPjz2+LT3P2D7kb/ta/uj+bw6YAu3Vo+RWjaLpdexUwI1guByf3rp5iAZhQM/beY1Y780k4PkP6Ei2RrhEaMLKDeoxBqgC68JkJ63xlIABkLEGS2XhYW/zdjSvfactGahXL1jbQbPxpho3b11BPtiOXFc21YSRbPAOlh2wCMxvFadATwE8yRZ9NhP5tPKgRUgqPrrUKac9HU5WUfMZLhMMS2E06oMqq1dN5zQyHIAJ2VOH+ZRMeJ4+Oi2eS71GN4GD4OnmEqLULSPL1CWRPzOdVdkUM7Sw1EB1Pcfeb8jsHPjQmnQeR1VY9/hO4WVINCs3fmmXefPCghkpEQ+N/vlDCSjDWEszdx0m0cNqs295OmNPoIxNwjbDmNgCBZVXb23mF7mp24CJ4MMp4cjfO8fM3z8U3/lv8E2FL/95/81jGlvZvUcr8D6BPQrsFxw/+l3oGevdwvXtxqs6jLdGjDntFSB+x2vL18gUNxfX7DfXzG2G8Z+h0KxjYldFGPbrYTG/YbnBugwsp7tfse2b5Eeomo5fPftjvklDRT72DHGBmkdc9yx7xO328SYd+hU9A48Plzw+GCFz8eXJ3wcX8fxAei+kuPz5894fLxG6NZUFsbdAQxAJpp42I0s6IuXCwBwv7tyOQZ2ZKgBqfaNBGBBE2OsItsedITlnNYss/qackOGq+v1gsenBzx6iM31cvVN2/Ol3ApNj8rQ3HiouOzDQh6sPaRT7iHgCYCAQcNp1gpSxT4mXm93jKm433eIdOxuARcRLOuCZb9EoVDVCVGg9wWwmbv0AAAgAElEQVSX6wUPD1f01tF7wy9+9nPLgdstxh5Q3G738N6wvhyURXyPm6Upne2wQWWR6QSI0/urehuo5BsTl93vcrng0+On8IB9990X/OxnP8M+h9W9a8aA94uf/yLAH4Eb+7d6aWpNPbYpQmhdMZHGfEoaqo/MW1QA9n3H8/Oz55NluMmbgutAMM8FUEFu4rXOHYCsRVi8CvsYwL6DXkdrt7ghwA7WBRtjx+aFXS1hHVCZwDQA3Z2hsjeGGtN44aFeO8NqAJa3MFAHB3vs0xbgo3oUhltimQs09uFhlukpSsWP4D176wj0SojSLz0ON4mx46yjBmVsbAWUVzzvKSxVsRcfq3LF4ddBDdWY4W7QViMcyWWMttRaSxqK2u50+M2p6KdyzTgIm2QsNEDSHcgYeGHouBcSVxu3Dsvz2YcDHub98LMC3Fpf7MdlT+8Ny2LjLU4pDg8tU1hOG8GvGdYU9/sGBXBZL3j69MkNZMC2Dzx9esDTp88+RxQiHY9Pj2i9W01Ir9E3jCLPZf3Ay8sXvL5+AVTx6ekJ+77h9eU1cvTWy8XCEfcdS19wWS/RvyLOGtwt7HJMKzmj8BIScjYcZF3NUKxVreacGMmRMWe2MMwJPOda5EAUxXD5mJIEwqdi7lA9zjnVyJ+732+4vb7i5fkZ2+1mzMvwgtjBamqzM4A+KjxLXJBecJKmHEHdW4NddIobjfQ47Q+nVUBXVsUBLOY3Uq7xVeD/p+USmGJ9q8IInHw+sVB3FPjn/qe/jt/61/+VYIGm/Ifyzi7zzfoAFrlJuRsvWQC3eh+5QRENyQxt66C57kCmxuYEWSqIapNjJjs3AGBMyA4IajHyyjhd+s3l+wwG4B2/8df/GoYC/8O/9Bcw3ZO99AVYVsi6QtYr2voAkS/mPPRFqmNgu70aA+U+oLqjgUy7E/fbM16+/Bw6dis/MzbMsVkNurnjdb9Bdcdkcfsx8Prdz5ysi2tCTRdrAuM2mhhjw/3+7OvbDe868e233zoZitWjXJYFnz59wsPTg33udSr/r/9twX/5zpz7OH54xweg+0qOX/nVb/H5m094fX3Fy8sN+3046DBSFIGiLx1LW61uHAVHIXSIjXLbHdi4MrQ2LNKA5nkhOqFeW4j3+A//7t+DquI/+uZzUTRJQtLR+4quXj+M91AcwRx/VLG6sFIHi/u+mUW+Z+2yZbmkRTfKEAAQ9Vh22wCGe+yYj3K/b+jCWHmvmdQWLH3x96EOYWFTy2JK0OWy4rKu+PLdd8CwTYDvylwOLZ95p9qm3LkhyWHHZ+02BcFKehyHDugwC+wMd0FV8A0oNGm4XNZgYLw52QlcueVGkvmNxaJelCXiSWOWtFa1uvmDin4+X+I1i0ZerLxRmNyBEPPzoKZCVMbLbMNRMaohggQvYUEW86bQy1e9nCISuSE8P2sqzUA0DMOcpXC75sPB8MvWLJdRBvMaTAE2HMj8Os75HN8x6VGwcKDd5wpZOEMZU3gJA66f+ptHAm/EnMm/6znF4Rn3PB9VYeU4GoU7wRTwhvGPip2mMnz0HqSn7JCbWhR0+iT0NNakNAkvivL9Tx5wkQxx8vPiRnGK5dXlNdkHYcBoLZT9qXB2PzLpEfSwPfkbwvBKy8mBP2eWebjvw1OIyEJrNdqqsQsw5RFi0Q/XywWv9w1zu5ucW81roLgDw/JQAYTM3MfA3b2762J1LuFGlekh3b01bPE3Qrmshhv2d4UWEe6LkFCxdmm4AWg4c1k7Jzp6AQw2HDTgRNTBmymh2b8HSPQWHtHYZYYQY4K1+pXDZRZDCpGTku0J8RszjSfEvMu1lVMNOMCpw1XRLq5FfceLV/eE07dp7FOb74d3LefnIvFC5IhyNWegSVAHAL/7G38af+Zv/G381m/++Xi/6oET4FTL0hZRBfLRlyGTsvdiLwCJghrIdpkhmDSK9BhnZWkiIVurSw4VBz0E5KV0Qu2I8i6q8Nq4WcettYam9nMb5uEam0LbBrQX82qz7Ky3c4wJFWCqQIczfK8r1mUxXWXb3NjrkSawHLo5d8yxQeduZY8w0RosFHrbcPHaj9U4Z3sKXF9pWNxwOObEmAM/+tFnfPPNZ3z+/BmXywXX6wXf/sq3+PTpCY+PD7hcLui947v/73fxcXwdxweg+0qOh+sVl8saMdeqliy7MwabtbN6x8PDNZjOuLlD1UMMXI8qIWvNLawmvC3+nXkdLL78j+8jtzuRYPnryxLx6XCFgkyGzHtS1otxMEfAdrleDMxMxe2WxCwM41j8vgR0+zAvh+4OFr1FE9XL4OFK4cnzDaAd6+7Q8h+5WJOMocZUOcfwOH9SOcerlw2MG6XGBhg14Hzzhrctw7cynGSRJdoDgfeXhy8q0DwvZexGbd+cLGH3TSeUYB8n8YcRRNO6ziMUbAJBf48Wm2lR4gjCXJlnmCGVSSq4KM/k/MjnZGhYhtlVYJbP4jikQnlUYtLDmeDUCtMXla0oMRka5mnsWqz3kuGWoc4G+K/hx0mAwbmlc2L3daMw4ocAdCPn0T72KLdBywDZE/O93lr1OckCYPDvePP3gFz2y+HD6tXz9lKfVqnK5NtG1Eurmsq+lxqSpQcs59eoP6OSqEgxNB3XFb09c1qIJJAFvm0qMdR6vpk3EdJ77hORkGlseSi88+Q1KS/LdVMVVWsf2+KAbgwsxZPOPrqsq+XOdVKiT6zrBet6wbKuaJvl6i3rGvc2ZVggvWHYZPR8oenzyOpmChVpkWDoRYSTW1+Yd6BDGL4a3haEYq0xz+2l55xoYgYj1nI7HA5IrED1EgCAUyhq5o0j4RIfz/kU38VkytlBmZFhlruzgFpdVbYpwmPlPIbIBiHH86xkn+eJ1slL2cY7nIAR1ABKFLjG23tW7CSHNZ5hrueQx2irmkfuDG/i9Lf4F3/wp34F/9jv/H4+8dD37Nv8t42dy6QK5BvblX3LeaKaY0cwxyLgByOLf4cmDocUkBYAVXxvFHgY5ErvVnfdQ5GhwRolMvguBgrNA7guK4AOwYrb3rC7kWXgjikjjDELekyLfd8IZz0iqePhesXSO7a7EZHcb6/Yt1fM3cpjzLlBxw4dN8Dz52jGskiBjutldYZkwZwDIlaCqDfWyDXylMtlDUbxn/zkT+HT50/49OkT1nXFZV1wfXjAui7oTfzZO/bt/nbQP44f5PEB6L6S43JZbaF7nRbL4dmx7fewVGExJeJ6vYTSH0oJNML6BM02jqledNrCJYyJzqxvLMRJz4MilVh6hdriAnlZTIG4GxvTIfRsZEFmMrmtq+XcXa9XNLQAJfB7k6VrWRarywYDfbLteJUbGKI1HRlp2YRoZjTPCLd1SRbPosgrssDxcCrs3S1upMaGeo5bWGAlwvQgAowd6gBBAWDkBlgV9wSEWacnSkU0ccC6BylKg0Ddyr5tG15fX8OiaeQrPh5TjXa8cIuzsG4CuqP2IkiyiKA/H+bp1did9aCYBADT/DsVBz6rKGzIMCGBBKAOAp9y31nHnoCnoBaBgS1TXhGKG0GenK/1PgjLeFW+GGLZeygkBKxzJoNrY2kIByVkJRs6oxD4VKfLnlnGgoCOoZZUZM0w0DxR/m2YbvQr9PA+dgpnMT1jcjr/iLx4Hur9q/KrrvxHXeqCyJDncw7E1K9d+bZrizJN0Hf62Bl5DDh7mBUBhXper5DkRyLvM/6jLCpzL+elHtoROVpCT47LCGRuZ3ZIzmNeq+o1AFvWNGN72A9j39H7crweCGt9k4YBA2OPT1dcLhfLqWt3QF0hdWBm4aGWi1SNF9NDUTUSOrM2IXPsivoOQCMneEC8vE3pHxqCYq1LyNfWiww5GYJ4+1yriDaoP3OOaXUyZ9YDZC5qArq8FmyJCsjGnOGWxurJmn7DQ1LDIEMW33cOGiqOHqi3nrk6YQKow0AHTzrCOf/cQR1laX0WQANGXX8SAAD4HjBXHiN6GNQYuzS8/cmOt/vR5KiDO2HoCSyNdACFJZmY7fcxMMISTYDj+zcI9qLF9HbBIoEaPFRxiXIFaWSioa0B0iHtCPh5htVsXdGwYtGObff1MhXbHFguT2h9RWuLR1JMfPnyHOB0uXSs64KH6wVL65j7hm274/XlGbfXL5jbHXNuHua7o+nmfcaAVaCvV6xrx8P1guv1CkjDPqw28LIwfNtK3Tw8XPH09Gg/n57wa7/2q3h8fPTatd0NQJ5LvG8Y0wwbLy9f/oQj/nH8g3p8ALqv5PjZz36KbTzh9fXVLTbTcjw6LaM7brdXzOH5YUCAgX3f0WNzSwtezfsxD0s7lELIkE3ELkIA0JyO20IFTFlpr2lJoqJ+UAyoVKqRT2z3zQS3HhXTOQY2VbxKwzpXAGI5SLuFi5ICmBv3nLadNBFX2A2YkrgtPGbWCGeXNEVijolt2yG4RRiPwGvTkJYc3AzTm0XlHt5uLRtghipKKLMafTJiQ1kvHlbROsY04oz7dj8AJ4FEOQR60/Zti9w7Wo2pVAhg7QoDu5ils6gUlhu0YlkXPwPY9ju48aZnhFbcGFRonQzx20McswMKgLWNf13MMjnm9GLmyVZ5/l29AzUUzoojZ67hfXpZDj7TJ5e1nXG1qYC23rB42JqFs7R4pznZR/QQJFC0G6gr9AjlIIuAz/i7ricqj1QkTVmtrHGuuhzAhSvZZZ1yLsVIFIx+UDsl/5YyOhUUeg+ZfChgUk9hl2ZQFzcelWeVG2v588DDecBW9WI7LETX8nHCY9bsHgOKMbsDvx1zrJhCRlc9gSpq4acQONHDI6timSFpp0axtYrM3ywdqIr6hrGe01MhgChab7hcrxZuybw7ANfrg3nnmpMzrCuuDw/G6Dt2ZDkEOHixkgOzGBqYBw1NUK+qUMm8ZggMhHajlBcanqobSQzo0bjVooO8X8ra97ePcSZRTcwxb0Pv3ed9jk/2qYaRKudrzh6h8Uhh+XUzwy3HZlEoxkRIYMA15feItnIWuvysZShQwVwFKynT4rdIgroDtqI8r15nnL51owvxXHbj6dyy+PhZjBEO33nL7ZmSrxfj+UsgXnqxcRqX2hg3dCA9cNFCXjuV6cJxjXlzj57rQ5s51+o7ArZOmliufO+RUzuhTkjmLJdsF8lWeg+2ZDNIKZqXDfj24TM+Y8WQBdN/9raiLxf05WLEVNuOP/zDP8R238xrvgjWBViblSC4dMWPPj/gYQXGtkLmjtbMgLK0PE+nM4jr9Bz8B3z77Y8sZ3ZZMNU2j94Yqm05dQ9XA3QPDw+4Plxxva6erqKA7hi74tXJj+YYMBZeYOnvTKCP4wd5fAC6r+T4oz/4fXx6fkoBPSeaTihzC+bElA1bEzx/94uDktNaw/rw6HTb/rkLW+ae3e4bRBoGaXbhJRBYz64o8UJUFla5tGbbkQKoXsstfO4Dr883bK+bGwOzhhREMABgKPbtjvbiIaCRazeOoU+AAVE0aCerZer3dZMxbRxuMaZy3DA2xW3uhfWw2yYkDP2rineGVY450JxgQIKW3y36vhlxIzXPwvDNCkAT9CYRVw80jNbQmylGAgQoY/Fq8yw5+19s7A5W/XWmb3ShVDSBaKF4bzBAc73gen2I8f3u+Tt7oBZAN/O+qP2IBClUssxaq3FeDS0iYKlhlm88LKDCkc+NsYSzmDn1uvi5rQkGFRWlR47gckJccWCYy+LJ68aoqqEkhvHBlTqGnAU4Y/uc1OfuCkGEE5c8OvaBCKyeWLwDYq5n3kkqPoctW+pn9Xpem0NCzyzXlg1LC8NEeLgOY8k7M2yXY+ZztYJzJOXMrJ4e+P0BA33e1AryrSNmgBr1xTTVimWPyegAO3c2wWhkfxUDVtNrrhH8Anh9efUQ5jQAvL6+YukdzRkejUqcNSg951bEre0CqHuvpmLfBi6XDmizPLtJD12HDBIx0fil7oHdsS4r1rVDWoZyXS4XPD09AmjYdoZWXvDw+IS+XDBV0JcLHh8bHh8/QfECvQvWdUXvi+VFizFbvtzv0Dnx6fEBXdRIHV5frC/HwL7fsSwrmgiWxZRDFUFfL7g+Ptp5vWEo0L2fOd9CrhHY+QDZfLG10FuzHDZV9MUMSDG/AzROji4sPH+gq+co+jPoVZ1zAsOJbTin9unkLtbvcwy8Pj/j9vKM++0F99sr7m6otNw5y0tqAgQbowPU2JEcjIUnl3i2ACVGndR1F2BP5LAujyIw9xKut0bQQtuFFvkba8LXXNzzbB4Qlxtn0MldxcGvIkJ86VXr0abpZXMSeUUupRu/zABg11H28h0tFeKC4m9DEy+zAR8fzzs3HDmQUFAhmMGq2t07BViOO2UCQ4MxgQjNlHzXRnp/30OGE4hMCFQ6VJYAw0tf0C8rlusDHj7/CLJcgX6BtgXaOl4HsFyuWC9XSDeZe/tHftX5AyzXNaJ1XI5k+sJ0MNXiZ+02zkYoZzKgL4L1suLx6QHX69XW8dLCUKLIklK9L5FGYrVqrW5dEGdNxSIC1Q7A9qm+dPzRr3zGx/F1HB+A7is59u2Osa2xSVH4bBs9K+mJsSR6q2Hy8PCAy+MjLpcLGM5iQEgAaa5YKdoYsHIB9rsCN3qVIMDUAUXHnBkWs20d69rDS1Mtkqxj45ofBOYV06mYtBA3AdxbIq0oeHNg32dsLqYcGDFKOGDg4KDlxiSAhxohT3IlzqzcLrQFaGKx+9xmrW8lrJr0sDBUsubrsOQAYAq9fdZjo4ArKVS5D34TdU/kdofAEqX3MTzXLPO+gApKfRAk8xTDwu5AM08pzxJT18U1EEu7EX+MeNht8X5oggMqMcc8JQ+I4TNh3i+d0zBoBWmoxeIRitT7FuM0EFSlCoJg5tM5QkcS9olOV0IcyEi+99IbHh4uQR/PMLH7/R7Pi0PqRzYfaujwcLKUbd8dlNCzcLJB+yRk7lbOIeaJEpFpPAmhXMZMLONY+t3nojWVfUkALWFcYYhxMsuOeBLHtTVbE3yEArbWkYo7YHOF/c01VQ0nClOop1OsQ07diBxzQLEUlsXWJuYkgYe1Z/Nw2d4E93mP8GAW6b7d7u5ltu1vKmw8LxdcFyc+8rGqOasC8/QLWrzD1GlsthcJoEc5wPVtZE2VxdRybPvDQ3im9s1qhF4vV/S+GOAf1ucWZmlAc993CD+TZux8q4Vkka229w6o4vXlGU0E3/74WywC3F6f8d3rs73z2C3ks3Wgm9edRZ1b71hWy+fh+nONPT1PM3NWabCCK7WI0xs2tfe4KOvnSQxs7+kVTE/QTIND8X6ZPIeDRWZueZmQOc2bYQIe9/vN85l2yyMaw4xhaJHrnbPqJOK1GJBQjERC/ztizdDyEsYTyXunBChHeRcQ2PqaxuFdK3bkysw5yLVWja623wo4WbObWzwrjSmS0SgiVjqivGs1+ER6xMySPtZfNv4scZFzfgFZXK2/Lb+NEFQJGqHQZQLS0Ys8ayJY3AsdBtCdZGkStRCnTEwoMM0rR7ktpX8V08MOJ3ZVDDVQ94tf/3VEqYK+YG0da1MAu5O5babBTAGwA7Lhujzg4eERP/rJT9B7pkiowsMcZ8o1KKymiYSTV1xFkTKvFQPrasYO8+SZjLpcljTYHQyXOBz7LhijB6CbcwKfLqDXnz+/8+kBH8fXcXwAuq/kYHglgEgUnqrYt0vxJMBIG3YjQ1nXNZiXcsPNH9vQmYBsCcSrFEE6GxQTMnKjokKz7wO9D7dWG6hjbhEV32rpVxfeU4EuS26WCgd3lvBmaRxZF0qpaLglsfeOXqCbqnGxqN/HbIiu4Aitw6a49KWjDQ/vIIuzA4sxWIjbvUAR0J+eiwwhObxVKKoCK+zLjab37sBL8fLyGkKbHhqCbvj9p4NNFs61gSFATsWbG08Fc2CPeAF565uJZNn0TWUqnl+ecd823G6voIox5vRE/7qhqusSCRzgV6hv+uIWWRZcF1o5mSen5dmaOVC1T+OHYNU31wlYIXERqIedASWXhO2hcuPGAJ2mvIlozIOoqA4E6LE+KuthkEzGlfcxzIo6CRDI2BrwyWcBDvOC48XxESpoh3fFcdwKIKvjyqE3/Sqv52E5Z4HjA0jSI8F+rWUp4tqJZNMDDRICzBYWct5UofEeb3Cvf1I/z38rp6zNKeWdgNIUn1+S/RogON83QmmR69bmEWVew04FycOiso5lUbaL4k//I5WtJp47CfE5YLK1iziTpZP8uDed7wShh6PnXJrTvLS9A2qhlGPuFu68rG9yR0UIMPcoYq8wz1xbu7fN8t2oPEfjfQ0IIyVYoE3VS3akzMyOr/OvjkX9lp2d/ZPGmAI8ynuwL0UQa+ntrQhmch2ihCuTjXnfPfwMsDXsc5LzkMp2/F3+Xd9HvB/yBQu6YWNRwNexB6K1bw7vC7ZFz18SWYoC59w4nP5Ujdy84z7jBrcyXvUJ9XoWsLY/j3I2afUFqARklL1eeVwOcyXfkUAwvIy8lnPNDT8AvVzdYSGJVIyIREVPrJvev9xva86ez2vzbgmmCv7Hf+vfxpjA3HeMecPYAaswZCHOQ4F9CtrTEwzQ7Vi7YnZAxxUinvPPlIVFELV9o0UtAbF3ReBWepxVsK7TyxPAWXEneidAPQ42102G0tNQZfKo5gczvYK1hj+Or+P4AHRfydFEnPI8lTNAcV8XD8lTp/U1QEVAZ+FKlVnPryyKLO9pBB1mpR+jY98b5rRN6L+9LIAS0E0PFWgO7rp763YoUMhQyFpozyS4WRZT2riFBhij4uF7DlyxnZqblFnXOkS6EQgMxX2z58EVqaYAetiAYVZLllfIcDfzRlEBIYAAlrUHi5mF5U3EPuibmeXxcwtPb17rRkVurHZrgO377R6hHrRo7vvmdZso7LOwtem0KfjhzGcZMoskuREJazsBlvVbK0yLMzaMzYlfbre0AupkPZ6zYqLZOJs4hwLETQzE9t7jswkYsON9tIYxVm8NDptbHZfj/EQqY6BeRJDh88TJK3rrUPHEdSle1Kq4yVkxtTDDfexBbGKAwGrJ1dDLVIgkxgdlXrA9AgRxg3h7RTJvSfwNsknlcyksfgXM1HzCKheqfsq2xOH3DhKJk1JbdHUzgGiz2kx1yCsMZHjlCRRAxEPM3lqi84HvfVFBgckigrroE8lzDsCw/Hs4A273EPQ5p5OWWC5ZjF21lB/uS4DC8GRxy726J1FDsQUSvIVCLylDM5dS0ZsZoQBg93zd3lfLtZmUG8WrNClb9xgAi5pgEW2BYMZ1YewS1nLMcDuGVvJvRV1HnL8nhOFnUnGP5c9rWgnVEzmsUfYLx4l5bqxNl/1s94qIDm9clLdxlkuTj3uUWRE/mb9z3UmAvJxWcnizwxqpbS4XCecTZTz0KHi+D9SVz9/rTb5fyCHJNROdFbfSyOHj75CR5d3q+bw+ngMH0lHH8ShnvdbGAdCFBcjvlHLM+2Jaf0wourbYoyl302jAfdVy8mMlszyBG6MlmC81RAM9gHyStcTCdy2U05mf4SzcY8cORZOJ+26e3znVAR3w0AHA6uluDVi7YG43ywVUweLREgRM527lZ4euiS633P1l2dEXMx5afwCtTYRRLa7R2NvEJzDTTFQNUJrB9e2eGB7Qj+MHf3wAuq/m0LDa1s2RXp6ozyISoUisS8ZzKSCoeLBQdirDAmha7qrA/8uP17BEUomqJBCRyFsssvSKcdMfHtZZDZcU5FMR9cbsYuTm5O2PDYZtZjjKNpCKhbVwetjWnJptaaRHTqXYyEWKMFe4hV75ptBhgIgbXcTdN2o6tKAirfq95F8VpY1139jGuC+BbwFyZ4WT6u5ZYVbPjSBg6ARYIvGdkX74ZsGcpKJIk56/+Egyt0FpkdQyB+rMLCCsAB/+G34vuz7fl/diaQhaTLWZh0isgJC/WyqSU2H9ra54npR/xL8JdhUAcybcw9cY1qoRTnm/51qiV24jZXxhEQ3LriQYowJJxTxBVII9H9JYQ/m3pLLufZHzNKZ0KqnlfsG3VgAd/1ZXjERbKJIST082vgyPtfCnKb4WZ3qgvXRU0ohHd5wAZ9wJh3IGtWFa/joCTASQkNIfNFQQDB9AkF97IKTx99k95FEaayRaqQFpOwxQuBeyPJ/PPsg1tZIBBDesB7ksS8xJAjwrJJ55x601rKuFyk9nbwQsP23bbgCBE0yZ23ej67dwOJs/aUywhlbSnYi0AA65U3yXdgZu7+DqI/TJ8RBHCPTsQ82INFWBSaU1w2VrPTF7rxZttz2JhicjvZkz5edUk5usJbrvth6NcZhhnFxjOKyrnC/Hf8f8OgnMs3EztXcXwSFrhSgPyJnyFtcdJnR0/jt9mmDxABMdmMettayRcp9Y4gSFfr9Dc0r/zyqzpBiCHVhVluOTmLG/JPf/6XLXzXE8swDCStLFPvafk2xTEQsTjab6Hcl0WtakND8XI/UAcD/kPkmZzDIKAnQYgdycWN3YCQCPj4+xZlRXj6YRtJMTjENSAR3/7dPfdYeGwkAW3wm9yXnHwzmJ6eUwzvrGGfcB5r6m4wPQfSVHpVVnmCQ3d8Zgm5vePHOkfiYT5efPn0FPDnPsjDmR9bb8u+1e6h7pYSOoIW78m89Z1xX/5u/8vwEqTQHrVpvFz929SOzt5R409gD3XAcdzUMOZwNr4EWNs6nYsaOpulLlhZzdO4gw2y4Y+w6GkXYPj7qNLTxgfL8xdyxtSeWMJBPclFzhWDrr7dm9pInRat9v2Aet1XAWzon7tkWRYMAL7koDem6dR8XCtvDMEcnNClDznIRFT50Ix62wLAXg5Cdquw0AD/Nyr0Xz/lh6x+HQVOZt/EyZqV439tlODyIBPcxa2ns3yzrDJQmwffcKBYVehHh/A3lWdy81MXqpqLRyTo9qNGD3ef0kvl+QfogpBzZHU6nhD4CYO9u24eXlJYwgFcCG+nJS0qjIR3H2AwhBsKQelKUKcQLMlaLlft77cawAACAASURBVD29rGgFMBYUlApBO3xuw6lJ+a8zcitr81WB2Vlg3i5VVexOsFSvizBUyT5h2KmNj3X5ZKSU1N81WC3nvbIDOOFKHx9+XGlkTg7BlvVRC09EeHbozRHLJdZFnYBg95BnYL9cw7sfipQrn5SDt9uref19HAlQW2u4XNaQqy8vr1BVXNYLLpcrlmWx50KcqvwBj4+PBtK8ziGPfd/DE3u/m9z98uUL9t3Kv3x6egKgXpNtw7bvGO7lsygMhlYr+rLgsq4GDrjePKdOmAtIcFaU8mJqKOPj8sC3makWldH6RF+67w9iRDJAyMwmxp4Lnx+9dey75QlbZISVNjC5IgdvBMH2drcyBbfXVzw/P+P2+op938DQNxo+aITkjwgJUyRC41yIH9TqBBrlKIaBAHWcFSqHdROn++dl5hYQ+Y53kO05PbPaM6oXeTI/rl4awPPItsnPW2uQbrIt8sJwlFsWsdA8jLG7LOwgy6oIPFInWZ5FBHOLzNo0rM1pnms+o6wl28s9WzLKzaRs730BPXJGFqax10cXNUSb9p21YSd+8z//z6AK/Ff/3n+A1i9YlysePn2DvliJAm0dioblm8+Q3tGciGRZcp8n+/dh/ri3LvsrIyWstmM79KXqxCKAhW1nKHj1SBP0Hg96uDOCg/OnYHtO3zfhqR/HD/f4AHRfyaGK8LoshUHq1UsFZC7WPFjELpcLHh8f8enTpwBg/K4CCoIEKhZnUPdPuoL4N4tQ02IZv+47/uU/+in+6k9+La1xHv53fo+prxG2cTRXaoAT/yuUP0EyRhleUYjYvxliZc9NE5c4w+HSLWfv5XVmYWJNQGr96eClAwpaxNPazw2veU5ME8Fss6gG4sLYcwjHxC57eXNxJSBD/d4K+rTKVpVAkZsNPZ7YYEQXWhQB74sxsgh8JFsrkpr+ZDg0AJDhTxptKODdPzsoSZobPEHWKBsyTvdhCBj7AEDk2omZNeMcKuXVs8ypokQhBRCdLcAIsIgAN7Q0dwI1TWPAvlvIXuTrwEBKtaAewpbi9dy71viOR2u0z4zo2zrivHdr9R3SYx55dAdliHc0bfJNKKX3jwbJjUAwj2MO755woeXcVUxMaaZsl3mlAJwq0hkzLfwqlGDyqQucGMU9SiLB9lfDjuLxYcluh3esCiJfjp6sfBn7m/PkrKuTEAaaoeLAbspq625raLHWeU8DMNZ/feloZM91BY+5yWGQcplcIyNaX+K8ZVnw+voCCLC4kYR5oqwJuO8b7rc7ts2YLZd1sbpWOnF72aLYNsOBFepkFdZhZBaM9RX99XZu5AQ8TcicYEfwAYThqHl/4dTXnAesR8e+BUoOXblGTmsjCKuCbMtKFjAqpbFpscZQ1tr535QSqR2fvXJv5G9xm7yVyjh9Lrl2jgs6//R/xymqh9I2cb+qwbMd5d8Z3p5g7vAegNVBnYp/9bd+G3/1L/6572n98cFvDCch34rRq/d4QWnTeEJOeycNqwEuS1PfEzp8veZRGB5ucT4zLj/LtpClvub6soThZFmNZRIO6q7ffssYSBw8lEh9ycS9hoFoWd5G8JgRFQZQQyzFTvnmb3tV11qkTq2j9z9WgAiCyCuMKj6HFVGZ5+P44R8fgO4rOUSMCe1yuZjwclA3xsTz8zOAiX03K/U+BtZlxeVyxefPn/GjH/0I33zzGfu+R07QeyGT274FoMvCyCbs/pOff4FC8e/8+NsC6NTz7Qau9w0qwO8+PR42JYbE+Vukt698x7MjlGe4QKQSCJj5dSIKlZPQZU5YTTMqibZ7hkL09PSEZTHvzndfvoPA6sNoa17CIEkOrl4Q+OX1GWPbsU+3onkxofCMqZGBMM/qQLPfsm/AguygFc+EfA0DDYhC5VkQRA6xGTSgdSuCuqwZ5lWBL3/PObHtG2RIgGNuZvR41FBcelMz7A6RCzW4sZXnMbQXKFuYGmNphGRW8OPP4POrFVqdZIT5Ilquo3YeFnwS7VAR9jFLBsQWTH+kDWdpCuqRLOdg42X32b0kxO4heRoaGIFoGjDOAFyQHgNu9E1OCiZvF32RYZh8vzMglWbF63lftifnEuLzM3mKsGh4s3edaiGXdY6gKBhUMkSsDlTTFgQSzLnk/ITCQzK9R6Ofk8IdKp4bU5VbEOtB4SGELdf90XEhh/kT3qRiuIji9OX5+YP8Yd06ye8Z9qusdQX3Yobxyqj0dy9kTybKOaeVGukdy7J6fqz690Zd3pclntvWhsvlinVZfc1Z7ty6LhBpuQZ9XW13Iynat8296M2iG3Ti9vKdyeR9RG4eFVoaWpZ1xeWyer5fnWM5zmTwzM+8CUXO8NMYEpcZ6rUXV+YNFmioMNlt878FUY8JMInxMOPRCRghb8KxtagC8/bn3HoHgHDu2iwuyjb8E60fHI73jGm1Rd8H6o5nnhFd7TP/Tbla/v3HOgrA5KoPQOv35jF7w+/+oz/BP/F//w7+e6DM5fflFvua31UZRLAXpD8ENkOgsPx0rmwDdANkdgafee4S7yqTvUjPGwDzFto6DWNevVBo9OpYFsWU9H71JeV+42/Wq+sdP/vZzyy9wEEZvXQ1SsNCpZeyhzAdoQI6C8lc1vTm2dEhUks6nY+YmSH3XUhadECkW5QrhHJJuLm+MUZ8HD/c4wPQfUUHiU6i3knvuF4v2LY7Xl/dGuQKirigIggMFsJixWT4Xg2d3NwqmnkgSEFfEsSp4I/hHqlzELpbl6aHLdk1udFUz09sjS70x5xoqhCyO4mkosB7OwV2EqYUymE1dkNa7tZ1xbZt8VzSgo/S2tYaLtcLnh6fMMaOe1UaXaBaPR9gwDaVqclEd7YkeivLv6Pjom8SGGe7JxSNIZNhBM6NmWN23jgPIHtkTTWAVPmprU2d0RfiuYgqw1GPRvHa6QyTB0BHRQBIizORZ2huJyWiABtlG71wvZb7RT/FBpb9NwfBc4bBMSyx5oKwrfUnmDU512MoNAwXySqY/Z3W06NiFGAs+rasqVCMCuV1VWG97TZ8VBp80z946gjWSsf5HBPkOQH6TgofnSjQ5oCF/ZnzhM/kPBCdGE0C7IhwvBO0qYM6s4Zk/lYdw+KWAEs6ONYLokLld77wtbQt3q/MB4UmaYXntHG83tV3qEAS5L13ir8HGSlpVWc+V1tJmuBecZGiFHaMsYVCuK4rWu8Rptlbj88UJgfXRZx1GBk67GUBtu2O7W4FtC2nx0lXpoGpfe5haMuQ0+7Rxc09hGuAPfbjGXJEX70rqwoi8nHi/GdIK9wLyXUc69ZlVnNLQ7GL5P1Ox2F81ZR6y5/bozSEehxvgjocfoC6BpCGhbj3OwP/9vWhgFN4vD3D7Wx/soPzl2Ph8yeUczdi/TKQp7wubpkAJ2Su//vnP/qEX/npL8JAUPeXs5Hk/DKJ+6X0sxvHvM3BOD39N455q62dc6tj8yqf2Dg37QnIW3yDSeNp2bsoaXtvmNqxAFFGxYCcg6z6Lj43uMYkSjMg9wlwP5USelpqfGp6/j14xGUJc3hR2qnAG2BnXjeCOZrUxIlgaMwtW+Zx4ONe3AA+jq/h+AB0X8mhekzUj1yqUsOEQmhZLMSQIO1+v+P19dVyE273SDbndaHU7uMgpN+EqUBDwFUq6n3fsSHrxLG9IharzoPW5XYIw9SD3OcGPwF0pYdMitWQOT1ULstmXoCjwGqX9Z509nGP3gDtfk0CgnVZ8fBwxfPzmjT1B2/mOPSLNArpSn2eG1m1JNtGkIrrwZIs7k1yjVmts4K4Y6pZ9Ppo6KODnjiGUppnMAECAebBmu2boIVqmfW1L5YnIU2AmwOsye21jqUeyE5EJJU3KgGt1LgqYI7vMt0iWwt2g9b3kpgPkVK2IecfC8yacuGW1b4UUJNKBsEZYr4exzHeSfWwBg5KD06gtHyWHhACNIK39KhxG473Kn8fFBB+hnyPo7Xcz5IKlH85mIvV1ICmwJxlvh20U8n2NGNa662Fsq4qkKkQhiADgJonViCYoth9fFXgoZmKtxBPi8GmGG805UkLgiG+R5YbqMyMNIaoAlU+nceOr+pvGeCVypvl9TCPdqBZkiVoWIEgz3VkHkzAZa4ty4LL9Rp15fbdPBbdQzBFrPYdgHi+Mb6OAHMRYjhzDuZK9tzVbbOf3Zlyl9VyCF357os9U8Z0eaMB/jkM34N7/ZWPqNfmAL0LNuaDpUOK4YSjwlBm4Tp3WUCFto4FIGGgYPH4mgdp+U3jNL5cU2kcktM6yeFPs8x771z75O+vKuub/x+vK7tXavpvzgtgh7IG3mvfaTPj9xbWnV6eep9DazWjMs57p12aBqfv81LWZhw/kyjpw/UXP6fJo/GC51BMazVlngkpG9HZdr/WyMISeNke25qidRs/ZX9wLerEVAtL5ur5/PmzhVvGmpdYv3Xfz/U8Yt698WB2wbKlIY0v1Lu1qRKjABz30x7Mtdob1tVIgg6ArnRhNVYs/QPQfS3HB6D7Sg4RxevrM263F3z58guQae2nP/2ZA7Wb12oxa/H9fsfLyxfsY8Mvvvs5Pn/6JhQMAJH8b5un/cx5ZMU8KvQmbcwax7otZtdUVXy+3cv3ZulSaNSmCwplBZalR9I2N+b1sh4EK8OjGjSKFbfWsF4s98VKNAyMouBxi5xz4uXlGWPsuN1vHjKlmHMH6YWtLplCYMV87/c7vnz5YtfcXk1xogcAKCxfbi8OBd7PIEBw4NCKhZMb6zlJnZbP3rNo7wGgT6ujxdqCOo3ghP3KsC2CCu90VIXfanIpdE+FbVkXLL1hLfPhHhsYYlON0EiFgyxX0sQJCHoqDLZ3GwAAMpGbOXLqdt0kS7GHLbyHeySp/DPMjpu/EHg6DfyydFwu62Gucj6HUcLnnAFx9RDPo1ewKiVU4KvnIYBSAK2WpS+Q5b5YHDdgdemXqkAGo2dRKMNLhszHixy6AP9yVOjeA5sxPtYovlcTKd7t4zsHQGXYrVB1tf63nC0tVmSJeT6mom+7E+UAY/qa9XqT9owJnR4GWpQUcF0xhxIKWcwIUz2HOg08HnJZDkqVKz2l9iMBvSlvtaZldyZKyw0aw94D2xb9y6m5rguu10usPwGwumy1a40m/enpCZfLFa11z8GceHx8wvV6hYhg33fc7hsul0vkEzN88eX5GbfbK+7b5uU/Gh6uTyCL5e31xcsYbLi9vmLbvNi2Kpb14iQY9s7rsmBdFoymUfSeCmXo0ZV5j/JS01ioZV4DVpuytYa+LLjfbhhj4PHBwyphBdnJ9LdvO7DA8ggph5ShcisYRibSMVkIewLbncXDjTBr2+54fv6C2+srWDKGHg0RpkSJe7NdDnEd2eRGBvIXgpScLWAJmPLJO8BPwwDmi+bNGfxYRNHU11xpB1Em22ZdLrRGvHlm7XveXPm7FcOZ36eyQmc9WQPJLNPzHpA5ly2wR/h+L81zTUfIcvsur4Fzp6qWfDtpUUaHBkDBDEOqlSlgaK71SDWM6TRikdnSCw2w7MIRXLHNvZGtM17Jv7cw6+fnZ0i3EEx61s9ATko/WGhl7imHcWli5ZZOgG7fbtjuG1geqcxEcLj9X/67GcHR/YYglnLjWRn40GdEgN//gz/Cx/F1HB+A7is5CAgoeCmEaghOPZdCyACK4np5CLDHWklWj6zEaJ+UxMiris3HVW1NIU2K/P/0b/8d/LVvPoWAtNsVNkIz+ZZ9Ma16giR6USjGkGCsm2RkUInwOkv6GG5BDohVzKEaIG1OT9x2BkG+OxV3MsXNMXFzpYUA4NwXWtsfeMNfjkq3K+bRl4pSvBlv7snxWldTzLZtD0V4TEVjrSa3dhLs6kxFp9ywzpj8TpOiXlyhqJZcO2XGuYcAOEd4De8krlcA8d5RFRK2rfThWXmp/cy/aZFvvSWbXjvm5J37k//OfEvmx2Wh9daobEnc51hoF0gwmT/5bDgAK/ljp3fi5xUc1vIM8f3hGSzJUUlRaKkuCk1RxOq400BSvQVUBO2N8hot48efDmdE5DiZdhorlffAEEAmdJJpMufQdM+gTmBEnCUvLKGkrjCrAjPKUPA9KhgOHxtIpQ5k6NPZG8EjPHFxp3ihNDJNhUrxTvt6plyjZ0qRxEg0SJDV0c7LPluWxeohuhwa+8DD49WA0ExDyX2zyIlt2/DwcMWyXHG9mjFOdboxLMuOzJkFmRkSR6ImkR7yUylzs8sD1FXDV64V/5/mXA0rmc/DBN++JkrEQYOVMmjVUBJz3kO6TwaBAJIMd54ud8fEvlnIJe8fz6wgHvieP5By6Z0vaRzhxwzj5cw+K9ZpZCprrIhzPkNdPh+AGxD5wYd+UXqs39l3z7JUM6xYVTMKIk4vsgGe86VHuVU9yxXQ1bVS5XQwahfDz8QCEjDRsNUqoHOQbTYCLft9RovYXNJYk/zcqyWhte5g1Oq6vT8Wtav4DgUIFzl87oP3/m2vzb2HRof3noOQzXWYukeJZMjlefzYbEWwL6OB+XecEyayfZd2I0FOge/ZXz+OH9zxAei+kqMWCA/Le8tCtmZtd6p6LyxOazXByeVywadPn6Lg9evrK263WzwjlEHg8JyIE4dtLI008ZE/suAf2nb89o9/tQhMu+f0MgTiShw3wzOBxuIhRACwyYZdgX3sUf9IXNEMAR54qSq09I7YN3MM3PYd0iQKfYdC5u+6LEswt1no0xY1k1prBxBNBTAP2/xYwFpEsLQlNwiepVpo5HOcCCxZq8rya5oXFoZvrDVZ+7gBxbiVecG/+VkF2PXcSnhDKz5BIt8tlCIChPIMelB7UWLOYKbWV8oew+HsMwgLoMkzfN601oLcojKZnu/Bdx1Ovx+hXKeQUSqaYO27qgQhFT+WEziAnkJaE8AMGriF8y8BSa2VV4uL27lnhkt7Ri85dN8D6FTDLlwBHBvHttVC8FVJS0BngE8duMOVC1Mg3RNPrQMJogXG9NqaE9uo+OK2dTmzmYfD5nEqqnDAotUTGAu5GEhEIKd7VeBQX9/kY4/+ZBfFHNMaAk7DA5kwEaHaczfAwTzU1pqFpvv9TaFr5j0flnO4LIuVRZh2vzkGLuvqxZCzLAYjK/Z9w8PDxbyCl2uUKdi3ewLrgzZL7795RXph4AVLS8gb/feXHhVw1bUZ800TKPIz5mqhAcxrzHsUWRTed5c/E8V7Pr2UDOs/jsifC1CpGmMb641Tgl1TJ0ZuAv7Mwxecxr5mgLqFSNwQYXA4KOXlV1xQLz7Jw8iTO6OEcpvwrNfGFuOGyWbFbHo818/P182Q3nO45SG80AFdGtniKQA0jF8Wkuyh90xZqPfUlEdBHhUAGLlfSNmTCphD3Etcr2jQ1g/pHAQ4yrGA4m/85r9xlClS2l++eHp6gvQOtDQ800tXwSyfRwZta/pxLzUg10tZA/MEMp8WtIbQgJWYtshcu/eyXPD4+PTuFKrrnfLq06fPb+bOx/HDPD4A3VdyVA8CkMDLajFl0q8J4HHwYKjnH5GIgtdXaxWAsMKe8+gowM7XMeytFo2toKU1qx/lgZHOo1DbgLjv8E1doZH8X/ZbZ+sTIwzxawzQpjIYIn/6dipGCAFtIbQFFqoxRTBgFmIDCumtWpa6UbFnyq8QuHzmiXzABbsgaY+nJIg6q1qTIZWq2PdTnp4c++ntuByPuoEvy3LIrzyAsXIPAxfFBi04WFVZny6AuHeCHjbeUi+nKB0EWO1dBcIeVr1y5+LjdoZb+WGhNLYBaoSfRZ9M1smz32QkTbbGIyiqAE4JbEo/imRdIjtPinLiqR/qYI7flZ6klynGETXk0ueWJKNlc+VXRNAjhqiMbVmr7MGzh+6NYijJrwp1b4Fn+WeIpivaAJQ5UP5uphzSW3cEdFCrNabdFRGIlZ8Avb8VHuTcOjS3vIeWsZxT0bsc+x4mB+jNN/lmco3hlWCfxNwrIIPzZqTXq3p/aGRiqFqsERiLZF96TG8o7DMnXLjf79jHsLIEBHP7wFBNY8xMb7HVk9sAaIZiqr3z0jvG2LHf71GuII0WEuRY3Z8V3zTxnOKjXDhOD8/bQeIl65dkDSXAZ652yDDVQqjUoGpGE+mei4tk8FWFRxuwGDllmloI70z2Y4772Ac2f+eUA4h1VWuGAbBw7tbehFW+IxXf4ik9f892z3fPk/r/uiZPP/XL8IRThlYg9n3H2fpRmkEjmjBHDqkH1L3H5n2C6ir3z/pDXpylOXKPyn1WupfriRDLjo6jsTBBF7jc8jk+p7JtEuczakIk2SgJLHdfg2NYSZypwO//C38Ww73pFtrJOrwDUyZETL7t22byyNfjec+L1xfum2mMrqAyQCcmxqgyWNEkPYpvAZ04xqxjSrDtwDYmcwmN9g6LPaMdDZgfxw/3+AB0X8mhbvk9e85YnwzoGKOQZbhAVmdiNKvvDbc7p8xRsFeFioDKCm+akP2Pf/QJQFquae26XK7hWRteQ8isshJ5YYAXp3UigLTWZgiDeQozOV5VvbByJtnPOQ0cql1LRWlOxa4sXVCo+kXQuhd+BqKoOHc/nRO3fXcP2BJWPFqVaZlGWDXTZsrwrAC7VJKKlZBttBwSPZSMYF+qZj7c93nP6vhUYFbnht2vF7Bt4bVZZ20/XPeeRy8xQCr5ANLT5kAA0wqKE9TNMkYEDmD/0zLr/R/acJmD2Z6ZXsKTBhago1gy79vmJCuZd7hteyiP8bYc8qIEHYqBA2+UIz4vywekYtLi3VwBnJpEJn6SebfyFQmQqRzEs4rC3IqHjgAxeqrOBfbXzEK8Z5CK03Vm6JgHBTPmODtBPWeV6wMI8pJ8EQHLO6gDKcBLVmC4Ukja+oFRR1n8f4f7AQzmjTU+B/powInQCGoMrteHq8sNxT7MGHS9XsEcO/6cS06c15e6ccgKbzvAhYbiuu874Err9Xo149SckQd0cVBF0ikF8OnTZ4gItm3H68sNy7rien0Io9TwMhmbk5wYO6V5Y8e+A1Cs64IxNrx6GZmxbyXU0qIKrsFcXEqpOJueecTOyjzxuOczEhyY2hnvFbK1NWz7jsvlgsYad+psnesKk9UAnFWzd8udM7Bs6/R227As3fctK4MBVcx9OGDvCdTHxL5vuN1uPk8TADakd6g3L7itJZ8bTrAR00pCHqUcO3twj7UZaRyoERgiiPbV8w5/86fktrHDAxJosnSea9GVBn3vd5RH0Ep44gYnH1jN29RbBjAhOAcQId/VmBslLQRgx1jf+X6/XCCdYb4sOp5GlKkTMqeFVBa2Xmt/GoF771BY/irnYBgRgABzAPeDDfuY2FnGQrLcyCTT9VC0dff2jJBpv/jFLyKHbvHi4ozSOcpLl/W943IxD955v2xNMLWX8SfL991y3YVDb0yd53FoLedgek8rKYugsD8d2jXHRyG6r+X4AHRfyVFDKCtxRv1u301ZuN1uhxw7ABHGc7u9RuHX5+dnfPnyBbfbzfI2gAADSUJgguv/JMDYB3qnV8me9VkVn2ayQhKccGOgwmHKcIuN7rzhGBwqcfeu6ACSTGgj6zBRwY/iswQQaA4MgS7ds+YVikp537zPNr/fCBCkqlCnH68ALCzatExKM4u72qYikCAKWbqFY10uF1wuF4hIkNVkrb/qiTvmOtjzkoI6QGpLgpVzGCHvdfT47Ye5AqTFr1pugRIS6t6Y3Lrs5Q8A0P4RA6n1PGsEZmumaBEQwhSfXpTrwzuUuV5BzqFOXrmGjH+VOfPo3Syg4RQ22d4oHXDwf9xUE2DlkcTdgqVZAV4piTX0dFhtJVdoWuZwVkMHFQmCTIZZ1idyTaD2Zfm7evfCy1fen2COf3f/PuYBTME17qFehxU1VMgRAZq/a3oxba01sRDMMQdGE4zhY8zQLW/2lNS9uZ5ohYeXBIFmKGp6SY8AJY0SDgpmkjgBCIPGtu94fTWio6V4tkQQhCK9N8iy4HJ1kiIfUysMblEIXLNRxHsq/t7f+xm2bcN929D7gn0f+PLdFwyvp9bcg7dtWzDnvry84Pn5GdfrBU+Pj1gvK7b7HaoD9/uNfitYHt0d99fXElbZcH244vr4iGWxciyblxeh92NReEhoS+IFKYYAzf7j+LPQekZKANv9XnKvcj/grLToBuYyMow8c6TYV+HN80vpoWwBorx+apTN2X0dT/ciFzIUav70imsaY3LHOQIca5+HBPONy7yuS6p614uTCmdAWI8wYr35ohiV2M/+wO+5lT8JKVv9N+td8nv+1Kv6PvAv/ne/jf/5L/zZUzNOxkCdmFPCM2zGI7ujERsND6Pu6J2GJzPQ9qWjtQW9LVi9TIaV6pCD3ID3ZVNnR50NImn8s3xPGzFxw4KFEjC/vZV9ika7CZWGn/wv/ytUgb/1z/7zgDaIDMy5Y84ORTdgpILf+I1fh/QF0pfYW+v+yr7JrpZIJ+Hf8Vs09wLhXASWrmiNMkkwZ4Zy8/fBiOT71rZtFmFy2sfnRPm3rYHf+70//CWz5eP4IR0fgO4rOXrvWNbFN59J6IPFPUtmUR7Ytt0BHS1C9sNadIsrL1aA1j1YDm7IjsZQPVqqaqiCCdmk8d+2DX/p7/wh/o/LBbfWwIIE6psGgQJAxVaAobFxFqMqMmnY7zEVE9MK7S6LK/YA9qT3tnt3tKah9KgqbvctLMLUJpVMf77LtnxwCF4tiipEoh8VW4CWJhZLvywW1sF8LdcI7Hw9CmYAh/BH4IBzop8quAKOYZWtNSw9i73Sq5U30fJc2wwMNNLrlSAFivC8abTDn203jxAQdfej+middI3YmOFAxu4NQCcUDYgwphPQ8udAk1gk2NnovaWiVhQSkicMAjr2cQE6qfjRC3f0YFXvoT1D0cOjk4yV7R3lq3lbg+FS6hzO32xDPK/ksbz3U3XId9TD/K6CTn/X8LbR28T1ARzJF8p7U2GazkQZnkyOc84qvFEf61xyq/T0fDtFi3nInt4sQgAAIABJREFU9TNGztG492EaaACOOSaGjPAqiFgYeTV0QDW8/TTsMA+L640kR1kWYGLlmHoVbSNyKNEOBybgjESYqu79hYE9CPZ9GKnJvvuATdxvd6g4a6aYQW0fe+TsjTmdVXjH05OBuevl4gy2Vp4AAAbLyowRRc6jTa2nEW8MiFvw3Q4TAxRroICN6Gc/h9/EXJhZ983KKxTwXsI7834ETGn86z2NL++cGPJpaobCDXrZC5iLtQzKjPSo13kk8Z9/Xh6bn9VVdYxyoFGB8tvm5ts5/84yIJqzf4qg1o37ZWv4cBSg9t6/+U85f1d+Xj4/Yrsu+If/1u+Va96P8PCFVp5vfUh2UM4PqUY+yZDE3rvtQ8vi+wvbKtHWaGd59jSLAaT1ck6JBonXneXVJAwE7ME/81f+ayiA/+ef+eegOp2wi++TMv35yxfAAR3Xy4Ec5k3f8l2P3svYk5HeURYbX9eG3nge78dwSnrmuhtMPKTbc2/3bYYexWsjHw8JDB8fH88z5uP4gR4fgO4rOZal47Ku2MQVLAEAjcLhVjybtM/fHYSgiIUM1YLkY0z0xWi85+he1NWAyZlBU1Xx777c0ETwl58eAKBYnSZ+/b7hf7/kVIzNYyaAYghZc9IP/zgUu1Q+co+cOqFD0bxIeOsN0+ssAUXEe4g5wa2CuWiDDQJDMwKQ6JE5reaQmKKXFmkqE9z4pTULpfLwDNk2DLVyAq6zRB/QQwqg5AamRy3PBUQ02lGP8IR43iK4+czhpBiZj2Kfe6kAD6NKxagwhbJfDOsmgMtBjPfhhsa2UIXK9pVxQwJAAAaiq2W8tBPMp1TOgQznrd6z6pUjiYLVDNoOANneMce1WljPP1GXMBTFUyikv9gb2nMfpwbWnsufePdyPYDwMqaH9RjGeQC48OF6o/XhoIBXZa8qdumVlAi908MtJOZ27z2ILtQBSXi8DpOBi6S2S6wfHNkaIDJiDCOIkUKaYH0mmuFVNlL5GgHm5jQCzQFfvx4SKGKKE9cLjnkuvLYaoF5fXy33xkEV4Dmt7qEL0K2pyC2sEwcclMD9fvecNwFWozbf9g0vLy8YY2JZVygGXm9GR956x7qsGG1g33Zj0nTwsrsXaukm0y+XFWO/Y04jZaJHb3iB7bHvmL2jw7103YlQPAQuLAAUPuJ4JC0L5ZRzyHYSUsD7NMKkaeSC58CWUM46V2kEq96/HNTjeVSao4xIALnhZFAjatOZXCtebpyPXH0EBpF2V0/2d0hZfwyJq0AwLuMy4D5RP8+LUFdXZbSMlz435r3PeDs+pz4vZMRbQBfyDIC2hr/7p38Vn37+fGhfPrYCulPZBmHvntd9PcdlhhsVl2WBrCuA3cbywJzp+2p2uBlnxfalBkFrSwwfx84+KCGIoGd41lv5P+BzBJhR3uD4Tj/96U8D0DHkspKinPeCYPcE4rzYc3Rizj3uzVDw62WJtBGO0bpW47kZ0EmkparAAlxUsa8jyzf5Pdf1Qpuce/mAb7/9lfcH5eP4wR0fgO5rOcRCwhYkiyI9b5fLBdfrFb1vXrRytZhz97L1fmTHTKsQ4YCDkJM0r0LvLzqQ+i9YXkAZz99cSTt5GxzAHbZh1ypWZ3w7WAzjmfY7PXjqe+3xPHDz5GYNWtjmYc88buLst/bOvzVyXCLXIACxh5t0DeWHgJn1d6a8pdAneKu/K8B7q8ifQhDrpsN+fU8R8H6qIVTRCeed7vTZAYTFHTWVROh7l/nYapz/vl2aYU4a7weoA2tXBCFWFF0kw8rEPT1ljrAPDdDtEdr7BvyyjhlHL0CUqyzRny024ON3+Qrx2anDm2TI5kFrrecXoJgKQDsAOpT25BNrP5bP6/gfxuV71t0JECPqVAFMyrf7MTyTz5N4JMHdgTCHXgwxxUybWD6TqgEuNaXMzmsWsqWCKQYAQaBB2UAwj2yrUgH0lE0ahybSyBJeWX9XhoBbqLFdc7+/HsalNYty6K4xTRRrvCtlkzly7o0wp4LXf1R1whPFPpgvnHUJVRVj2zEBI4yQiW03z74UCz1ErAZkrT/o4bL3u4G6+/1mdefGiLlGJktr7zH3snRlzkhJoOUdiTeH0juZ3rIAvEXWCMOnlX1Gz4nNxSMhjfvsC8AjoUoDiao81y5A3W4kMu51h7JGaa5Lx6qHttdVE3YnSWxb19Nb+veUQ/G36mHdBOA/PPsd4OP7kZz7+I38CPgYbX8PzB0MMyjvXkDd2/umTElwddxnCOjqHlPsANFnUhsJgPmFuW+nfDQGYktBaCUHnTl2h7kxJ6YKEOkPnldY+ldwkplKNu9quKRhJ2e9zcskInv69ClCLmmYeS+HzsiXCKBqDcvUmyy14pjbbmvP+xOFaGlu2LeB3ncPf2eKBD3YmSLDyCDe73IZQQZFOba51/7j+OEfH4DuKzm46fKgUCGYIykArTz7/oJ930sOQypBVJAPBCpedPYMJIBkzRJhvTharjzCq2wkb34oqYuWYSFMJeeJNMkArMYdX9qBykm5DyWem5OfPNWUyzET8MbOp2nRrxt9hlrAlciTh8yVTeuD5SDsTbE9bg7nNta8nsj1K6F3dXzr+LBttAQq5NDuqpyJ/x2A7j3Frbx4hQq1H+NeONecqxbtCvBMSdcAGG+fGx6faLJiaFL8WwJ9O3gejhtp5mUyFIu1q859xfkWc1eOc5IFvatVtgK5w7zwXmjRI9lph3BNKrClsG+9C8eZY04SkRySAuiKzeIMIqVJ1JLLM94hRInFVsFZVe6O50MAUctvwRuF19dGwq0KIwFxYhgAMiemNGiz8+k276NBu9VTNMWRgV3ZtrQopQyqiqPCCTVEPc3GQ/ZIENEl5giJTADg9eUl8t1YXmVds3Cw5e4giB4gYsRNU7F4yQNAsY8kFWowAhh4vnL366yN5iFEs/4cc0K3Hfs+0f25nD+Xy6XkaybD375veH19xf3+ivvd8u4CgPsaaaVMAcHdYcZoHan3Ffp6WPd7Yec5gZOHHHDQC0RZB85pEuRwXlUDnSJFS3jdJMdPp4THneGW48Dym6HY51n55t8+h2j4O1+TJyXoLB8d/p1RGeXWb4Tm2zu/YbIsIO3c7nePev4bgIfjPU7n5D2Yn8bTjmOf+10FdQmLqtxQ4I0cboe16bKXBk733oWskg631sXzow1ieZ9wwHMYs5BRBhA71PN0T/NWjZiHOWx8X0sl6fjR528gfQHaW1KUlMsV0JlRiPc57ufzAOh4ztg3+5kjcmTvY4vv2XeWN28eOUZVMT9eNUM8r9d7pNDwqKWlPo4f9vEB6L6S47vvvsM33zwdmAxba9jHBtwtkXnbdmz3DdtmhWlbg9FgL+LJzRPqBbnPdPYZsjQOgkhVcblc0PsrWhM8PT1BVXG7vTo4eas4s33dLd8ESkPNK/j58xP2MbDtrLe04343BsRUsKn8AjqB5y8vmU/jJADhDXHFb3dBu4/hAMjDv9yD2ApLl11mCsYctEy7EkrrnBhoUQDreok+GWPg9fWGX2w3dEGADF5bvQiqybRGltL3vEtmKSRrpwMX30iML0ZNQbzfAd9U+TvCaDSZC9k34cXkpgxYHoM/NzftzA+gZkOgw5pk7x1vQHa5rp7zRoESJ6dZkuyBasReksUD0Hko2vF5GY7VDiGNxaJfQHHtl8bi3uWz8CBJBdQ4KFaAet3BzI8ID0vpe7tBBfstc7dKPx368vAX+9AVtxIOGoYOrWxp+RwCOnsv4wBsXissnitOSuDJ/V0E2ia8BkF6bjnXzmMtiGdAjCURArQh6HNidnq6gL7v6F0wRsMYE8+3PSdBnRv+ryz2fQR4EGC2ZutgWlkKFjOm0nS73WINXpyZsjuT5LIugFaSJsuZe3x4ROsN9/uGl9dXiDRcLlcsy4LX1xtutzsAwcPjE5Z1xf2+Yds3tN7x41/7MVrreH6xAuHXq2JZL8Zy+fpqMnnf8as//jGW1chVHq5XXC8XJ6jacb8Z+cl2v+Pl5RkvL8/Yt93GpTdcLw+4Xh+C0KUqpxYeKkFkFSGYkVJax9LDq8U8qCLN/h4D69Ixdlt7lqe7mBfR9wILG6ZXwebQuq4Rdt9aB8vHeBQvVA0Abvcd2z6gU41QS91b0ax0g43bK263V9y3G+bcoZiWq0oqeSDXK1iMwhkPg/JdEYxbgkhyTWNhfpXroKy/U7g7AU4sO17/Dro7yIhiKEq5gTco8wze4tpqcIknufGSn/m4qpzlmHjawfEt4n35HmVPyLa0MBpZf85gzla5W/7nHFiWgb0PyD68fqyBJukdl/ViMr0vDugEY04jCZoaa1emyZ7eOtAUTQE0Gmit9a21JCySjr4M7LMSgNErBgeE4lwDHf2y4LZvNuHbDMbul5eX4xiUvaqyXJ6jZAwkSuztgMmch4dHrMs3sWcbOOsHoAgA+67el0djuq2ZzK/f993Woe7RxrF/sFx+LccHoPtKDoYTAYjaR1T+aT0moGPYoIVh9qDkp6ctlL2yaVTvTgVz1SNFxZVx5iLAp6n4p28b/uZljesoAFXpMaACave/OX3/KCxQRxumgYo33jIUbyFyc08FGoACbQp21qWbplSiwdjrmpUoAEwg930Ur45tZut6ceVpSUbRcTsCCrcE11DHgzJ/6FMEW1g9zp64UNIc8I2xhydTQJKCmcrL2QLsYVsEFmE1zgfGtZHrUcbdP0C5ZRznv6nohNKo5/MqZMy/pXkOhaTnit7O6UpL3fDe81xmm9o7gK56o8pmTKXQlThaveXwb9+A3dovUot++xcKHMChFA/jG0AXKmEqbi291vzNiZuvd1qfAexyyMSNEdW4c/T61vvBay1SEarvZKBPWzPl2IuCM8xSRCBhQHDPT/RvDnMonWyqGJV8bwLtxlqn5Z6hhKf9INuKOq+43gCZ0z094vUHzWM3JQsDVyXV8lHOxcXLWm1k0jMvHNkVe7exGl7LcIxUXFvrgG4hF9d1hbSOtZR4kdZN+XWP4XADVHcF9eIW+s0Lh+/7bqDmfse+7S5DYYqxCPrSsV78+SU3+s24ExuHk0yjLzku+f7Z2+b97A6mc83R0zPHhJQwsFnyrCNkvTy3gkiGsc/pXnk3PlE213BLjsHZWFNFSoKX/K76l2IyvlkHR6PBW2l8nIYE/EYMcjRQHY9f8t0J4J2fcT6XTX/vd2mY/fJ1ef783La8ff03L0lgIuKV6MQMnqyhlmu9GsS+tzNiTkiE5PqckQn65TlHRFsAS67383u01gAVWKlbASYJ0Tg/FeYFBOA56HjnPnzfsxGttlt1uvEm9yCe35owaj2No74vt2JEa03cGNSxrksx8CZRlKXF+N/u4SbYq+USKJ8fnz5IUb6W4wPQfSXH8M2uKifAUYkx75wJBCblEsBUz0Uq3ycAgiOgO27ceGd3Efz7P/05fm/p+P2loxcFbE6FNA+RShsxVL1+GM91gPLehvOG8CK0bUXm/pRcJn85+7OEarqXIkkOlhDu9MqlYm05fpfrNWnBtx03VEAHMDzt5GA4KI5Hwfz2nPNnVBBNydugMFKYWUlO2F84bvrKzbYoeErgZlpYtguIotIx8mEZrXPkvc2vKPMBRDLsSpXUz37nkkNnmKZ5LSmfV2Tc1Ayj46ZWw1UrAQb7qwL66qGrfXzIdyNoK/0XWMnBW303kVqHzsZcZRaQZyUAMgSuAKrDGEvcjwCQgFEgEekYc0mORCqQUn/Px45GkBrKGc8XCcWczyfr7AEUS9bOEqQy75XKihJq1vAppIr38YweLI2LPrX+bq2h68TszeXD29IlON6lKHlHb2ywImoLwg6bFsb6WxkubT0tHh6bRAs0xJh3wOaiqodVurdJZDEDypzpvW/JvsqjN6sxKa251wxYLxfMqUaOUkKDWbJiWRYs6+pAkKGiRmZ1v99s3buCvfiYmnK4WhH3MrXM69vRmgHGg0lGExS/f6T8Mg9WrU/n88D7Zug4zO0MfbMIiAjb52xRTmOLzhhegBxkP2UrPbIhCFE879uUfeQacWU9DW9l73oHKR3mpWab4vvvxyPHI5Df0ShVH3gGNxUsxtqqe9s745GA9Y/bMCCMctWSFu9KMJr3lMNvgvODUIE21hTsYGQKr2mHvNuUped35iNjX3bAHwXvo52U+x4NpLCahr6/K+gda4g6lS4reZ8EdAKmjOR+pKWtbw3Y2dacTyZPLIeTUSIcIc5BAIeyUfu2xxhQRjw+PkZYZRKjLOWZaVQ2UGcRH8Y83mIvZXuvl+sff158HP9AHx+A7is5RFBA1gzh+l5e3VKIS6gok4yDAp0eIDKLmRJthVqTYjwPdevqtm1gCAsAfB4Tv7v0AIOR1yIwpjrWEItbCm63WyjSVGIPISaxUcyDUk9Fb6qatV5Yf8sFvHcUlXaCOeZrmPWOEJOAMjdma+YxhDBBsCaNN7JeXyb3p6X2HIKYfXi87/kcjtXhvOKWMQDay4AcVY14b/9+airlAXD4fd3YQkvkhuhP9g3saOHO7Zv9ws+POXXsj1Odn5MiRjY71hkMD8F04oTyrjE/+K4kQCmALueQ9R2L3NbCrgABLWLehN2Z13lbowZadNbJO0cvST+SnZRmHwAilYw0kgiossQQlPvyGtN3OB45PyKXqhdvDQTaj3OQXqKjgaTlNHCgH0QjRJliXpY2G9QJAI4a6xl8HY0wFurZ0KcpjM0t1AE4aKwQekOy7wyEWm6XiJ07BGiTln17vomI/5+9d4mxrUvSg75Ya++TmfdWtUt+SW4eFg9blgUDC0vMGDEHMUBIIIMEEjNGSAgkxIAJcyQsZsgDpoyZ8RAegISMJUCyQDxsjN12d3VX1X9vnrP3WsEg4ouItTNvtZuZ/5u7Kv/Me87ea69nRHzxXMcbtMhdEOtaKSzpibmGdajOoH+sRQmRSEawbRv2WwIw0tht360fVHy1htvthtfXeyhO+taxt1tkF2atQRHxkgQnTnc7PLwEylRFl5Im3mOAmrSIDwbgsUquIOCeuMwBFG9CI4kDROjeTVrDL22um4iDXEC33MNGk72OmXA/Ji3nPqUiYkb8ZOmEAiq00GWGyzlLuYLcgn4mk0+EpRtyGaAEmCHtCI+KCr+u9M/B39WKk4oq4D1Xy3evMtjlqPBVf4Dr93tjpY8cZXi8LDG3WMYFJO0OJUfMGulkoXOeqTEUSBG7iZzjiHeegEygTQu5qH0AAuhF3Uw/+wlGVxplPEQDWP4P//5/gPvjRH88DIiqr6yyNMiAjoGnnzwDrQOtL7SUc0EazFAO+zsV5NXzBECEN9RQAGYJrm1W67W5WD4wznuEUNg8rJbJenSzb9bOL37xy1+zAz6uH9P1Aei+k8sA3cCcDXNmzEwFbrTO0MoDIIBN1VzTvYCa75quvLUWge92Wdv/12bE24ScAkrKndRkh2ZLxAS5HAVEgPNxLC4ZIaBLCugigDZBm5l9jQKpOpgLTd0layDrl8GFQp2AyYAGGsQzdtUiuimYpJDRJOucJeFNhsfMW5gSWfKAwiiVCVCSkVwtjvVe1RnxPcFQUp8NEUEv7URJgqu0pGrlDHzO+HMVZhLCIf69rnttsvYbb79TJHN1ZHLFtLQ6cUAxNl8XMkjGI4SQCizry/0SVr7lpwiCYkk7mMRkmYMy5jJF3k8y97TQgRhU1yxn0lqxil6SU5Rz4ujN+rC4hbYAk9yHBO6tCDwKibT/BMFQRCKZWoy9So9VWBNJBQmQqeqJrhR25i4p/SwRSBuePIVrfRll7NV1n5gLl9d402ZgxQKpPP6rBUiK5CsuYCdA9JT6ADBnGT/fWBUPeZEeAZJZIaVhtrS4Md6IGYH3bce+3yAiOM8DIg3bvuG239Ck4ZhnrPW+7zF2K7ps7pRfvr6aqzeAbdvx9PSEm1vYCEoAOJh7WEzecVgZjuFCYutgopSow4kGxYi9FFYT1sosCpzUAxUFTJmbJBe60Gs/uaYMkoyltn2P5TMm+LEMloWWkEZC8lyrMvDN+2H0wQRwgjkvWeACvO/aeEaQyhnWh3x7nv00+T4NBR3S3Y/0e5mvciWoex9OvQGnMebL5Mrbef97vYyc2ot+HaijNS7QtBaXWKx0M36XvZH7w7JYp0ywAuhW6BwznKYsgeBDc04IY+SQCU84H0IwJ93jvZ1OxBRq7DX212SfqkTraG362WUdPN+3cwJjQOU0xYwDugq0cpmsPWaV9NJ6AWaRw3Jl11o+R1XdTXXl7QS1GToxLcHRrJ+xZMGqiHrPdf/Lly9/wN3zcf39en0Auu/kUoXXKDI3lX3bsG87np5u/r1iNMHsDbdO1yRa8iyuw4TEHox42254fX3F19dXbNsrznHifn+4xjo14Od54N/79GRE7OsXNNdEs0D1IrgiXSVVNbIWZuKG5mWcSPxSu8f4E7omMRPccVjmt6sFS+fEbIKpguaAVlqzJAiTKcjhgsJwIb2jHeaydY6B4xgpCDuh/vlv//YipPN3F1hGvSDWB1QtxXZ1bxMoIFmUeNu8OLET8+N4RPIZwIDXMa3g8NfXr2EFBExgb9JsfljQVcTSe3vNJgpfnNWweBXLAQGN9bDsK99cphAgE3HBgOMKYFA0z5KilttWUhBn3GIVxiStZHMQrOY+iLWdZY1dkFSgCChIC1qrYKwIIKifWf0yabTArWhUpMbJZVKeJllz6U1cHhKUiafrFrpRxrApgqIIMhSALhCafS//pqsg15/zvljDoCVDqPezrSB3sUK7goSvZrp7V+ubgFJioqLIsCqmdogMyGipBAHAFPQTgoYWuJXjmGLZLwUNTSwrpM4T5/QkAWNgABhKt6sZNaCHApgKpbsdzBrXXcs9cek3TFhUiAEMTbfUracLuqig9Q37bslJrBSBg6+XF9xuT3g8Tnx9PfD8/IKXl094efmE++PEOAb250+43Z7w8vIJw4Hptu3Y9h3Sd7y+PnCOif32hE+fPuFnP/tDeHp6cpfCE2McOE/F6w+/wuN4eHmCEzpOoyVzQIdavFBv2LYb9tszRLoJq6qQvqNtN7QBtOHn0gXl3tVd+0ph+VCM5JmjEE3A1oTA0c5ot8Al2NfWXt86Hg9zM9vcJmQyNC2lYu72SFBEfmD1CRUocU5znJjnaYXUjwNznJ591NwuGXflw4vzztpfRQOQ9KaUoKjnJVNVKphQSMs+f6MRwNu2ryBPkRl742kq6ahQ+7UtlvZUMzaONCT+RtCuoJuax5evVbU4rNY7tuBdWAFY7SvfC8WYgsfjwDklFAXkyWgTEANqImaBkzEMeHuNSZmKAweGTvSp6E3R2mY0SS3nCWBlCmRvpU9qIQHTaABBIOmrAsYXhnnD0DtmApDute0aoJg49bAEmqr4cn8FpC+WSlEtfI2zQIWS8R4Rwb5bvGwFa3MmD7T92NCFihfjM61tRgu25EnkkVx0Luf9YZ4B53G6d4pe3mcy3PPz85s99HH9OK8PQPedXDpPzPOA6MSEusVJ0GR3gb1h9oY5BrpYpscz+KZlq1IFsDXse0ffdkjbMCdMUHGtEpml+XTbszVdsH1XdJ1NINqjmKZpoUrNsGkuVtUaYMAUhahqsUbABMR5YpxWzHYqYzTU+5CZpowRsfacoMOYV+/uWsWYsxBa3WKnCrpyuUMbpRtY6kpnIpjQWQCRAgIGeBdIQguFIgwcljBgmsBzJiiipnkWIBjCRdGg2oh83ru5ngwl42NqL6TA4380iCXBiHZWgSUFgCLs5E5zJSlduBD9k0VaX4Fhedo3nVnHCGJC4R0Nlj5EGnoDcWutPruVcZJ1rBL/Q/wwRxtdJkObH9Pq68R2S4FxWhANzEkA6KotRQBAJp6xN8ceI+ATCZekKnRBA/Kn0mNrb4QHfk95b46suUa3ysR/BVy7wAMHxLTkmnW3W4k4LgOb8DlSVQz4vmcpEe5riClbwH1LYTn3hM1TDyESAB7H4YK5ZbTrDTjOiTxvwHShXJBnx2RZK3Fh2REDuSOi/DSwKKRL/K0EDrDsmzJObOr1O8UK/z49PeHl5QV923CeEy8vRhOfnp+x7zdATjwdE88vn/Hy6TP22xNOfWCbwO32jNvzM/anZ4z7w2J/2g5Fx/0YeBwnplpx8W3fPLPlDXfcMc6J4/6K82E0XU8DNPM8MOfAbd/MrdRd3Dotv9IhfcfWvcaoAufQyB5o9IHRj7nZWgU3sJjP4cqk5hlOh7tVmqC8m5B5HvjJzeKIAcF5Tqge2G6W8MVohLmmqiLc9Fvr4f0Q9FoEwxWR0goQmcMtrtOKqJ8H1JVUoEKIe94zBprvgdP2SngK2YzEGEi+Ece30B3/I6g4/5Jy8yqU57zy8VVJpGwSE6ZIpAIoQEAo1TweDGKAKJtGHoSSIh90+fO5h5f/6D374NcYw63fGgXomdk5r+KFQ8DXfBYInhsVwSUGldYpDJjF2NxvzWrWIV2jiDjUMqLau0usMCwrd/P6o7bUyiIsC+0WYTH7TMjzZ/7Tv4ipir/6r/+baJtPTiQ/Ih8EPv/E6tBZXUXzvFAmSwscbUCUltwZil/LpEbvnDEG7ndT1IyQcYB5urIi5KaOre+eETO9JrbeQ9lGJRTjB9XXOd2I7eqwNbu50v7j+vFfH4DuO7nMFe2EiKeFngKdBhgaXHAFoOLasGbZHue0Qs73w8oGQARjbGhtA9CgzpDPUWvSpdBMywmw+poDis9z4J/94Sv+yudP4b4UVoHqaoMKCHw8ARgIDBEEduoEBnDKiabNLDpIqwTICO12F/zoXmipvpMZOxAgwRQ+5G5EFH9MDQgTNC1uh8KqYoLqYXENahMFmkDVAsgnPB23M1xhwVEHdCuYUnLooiVMwbzOUyAFDjeE9PlmLsyBjdYgglgCSUQb9bO3gC4mY5H8QwwhMivgTOI/sNirMvfLuodlqfRDMzbRXC6znAPbDRAXwGE6QwPdAAAgAElEQVQFsRS6LHtm9rPTitZg6xWjyPlurl3NeDkHcy0tXwbQEO/OpCY1yUOx4oVQ0sq8JFCjAEjXLrP4pQZ9hlthTJtpjlWWpDdMKMNBSf7plmnWOdJFOFXfU/ycrohQhTY/a5gRmyY+gKYApJlSaQxMKkREHQRvIQxR493OARU/Lz5nW/e4LK9LtjiqSlowJxDWJTpnK8QtcxJCa2xXHie1dhVMkV/jxCz+7bbfcLs9uXXuxK1t2G433G7P6H3D1I5PnxqeX17w9PzJXSoVuwpuzy94en5G33bo48S0mXAgc1qdRWnY9oZ9s1IFW294iCddGAqdVndtjsPA3DgBKPZ+Q4MBuo1JWGgF7h1dGoaaV8JUxE/QAK07vNIGu8ylfiS9RtIAczvbcB5mNaBb6lTFOCdUT+xPPTLzpVLNUtPbvje3UCV90kxSNcMyZ7/pXhqAjklpcivETyj7AngpqCUiuCHBcIfzb9C2vOheKMixrJZ48roVzL1tCDFW9UVQdajDdvxMdFfyBJjLzsR4guZf6BU3eMw7eZnfMbaOn/zqC/bXO47nJ1AvplBsvY6Pf/u/JRBclI2jt0tY6YqyiTHswEAotMgrg+e5C7XTGwIklklRWva8jq3h7wKkw9vAPQK416fi5f/9mwCQoRXNaYKo96kHXyed7F3cUJezTq8NIUjVCYrUmaGT2Sc9FEUFijPA9TkG5pgBTkUUozPUIpMJXd09VTXKMr0nG/EiP/i4vo/rA9B9J1cR72AWLGYGO1zL2YiHIAJzyYQx/TEmxrybi+HDCuK29ooxgdf7Ha/3u6fmZ506rynV4Eym4S/9/AsEwF/4wz+xXqjin//hji/S8Nf2DftcBSegEjG5DsZ/J0irPvICgTYFBoqgr6tFq7bpvFxVMYYJHtTSUgCPJCZAaPEtRft0ztjWOfZe0xJgNbXsPtMqNvTNGJ5ZQE0gOUra4TrGKMbq/QwgSwGCQjrfXtqo1sjYAgGIKbAbmCLIq66SouIJLS7zVi5GMEmwwmWhwIQnFY1VLXV1RYRkjEvOQfafWHAi11aL1SfarP2T/CwB0/o73TqRDLaElEn5TzxLy3BrYUl+853v4QB1JYYkLXSZiZKLuO5VF1LKFLaqJMC1nykMRTIGuaydYtXq+i/GesyijU5MLfEZXRKpJeY6ccItfbmnF0fuY/FsmW1SSWLz0RrjdPkusxBQf2H734RabQrtRrdmm+WZMjzue3VXLN843zil5bMVtOdPrjEkXQ1VzZrWW8fWN0yYO/pPn16w356w7zc8jhOtbXh+3vH88gn7fsNUxTmsdiffO8cwOtMtXs7KDXSvL2VJqODCY5QmGWfSquaW0NZNwRBWBwdL0gF4PDHMfU0r8il7xJRr6R67KIpQrQqeibAK+LEWAlMVMkFRfj9L4pw43wuADuhl7U2HvgQmjCc6R7iPc68y7pVlWC7kPsagIND3MRFY/RogtyqZyk4qYC7e4OcvYdN7V6VrV6WVLmviLyi0rNwTQO0tlY4WC4+48taf/5E/hD/yt38Hf/Z//T/xV/+pPwMqV5k5OABEUViFG2b4s7qljYquEkMcs+BrW8cWewd+bucMQGf9KPu4NciWmXkbQYujNhsfaStxrNO0kQR0ujs2JjBEIbNBOmOSG/7O3/m7aPsNbd+xtYbeJWl8uEgKupTSDb25co80rXktXwtxGcOUxyybMo7h4SLJEzgPNWbuThlrsqxTWzyNeGaYXZPjBYDf+fnPv7nzPq4f1/UB6L6XS5M1GiiwYPLjeGC2jj4Zp+KEqJs/t6qgN8X9YWm5x3lizBNTBUOB4zg9wxvBSzK31rtZBaBvmJ0q0FXxu8005UwqYN8VsYpCWGGcHERa3VZmGUTaU6UHg67SQQgfMIGjgJ5Mo+3iNhmYlygwcEgUCGT9GoKTBCgUTCwuxCxAzJzXugldM4TkGnjP3sCEHEUE/Aes8v+kBjqQqfW8WiAue4GgMOZVfd6AzOBcPhcXznhPCjIFlX3jCqHG3YCu/alCc5QNiGcL8Fz2L4G8g7kSHP4G3IAgroBHoTtlu7xfyhqW5ygkOVCiKxvboFtMAEIhg6b7oMTvSLDChCaehv89GVLAe30/CScUac0swYDsIySBms1/Aa51Dkoa/ZzbGT+1J7yDApLy4HEv5YK6i2t9xtZJpju9sa6cCkQt8UkAcmUx8lm00A40HeRp92IDUyPJ05wEbVmTkEJyI5iMeSbYK2DxogTh2S3DAmlS1nwCxlTszSxR5s6o2G8v+PTps9FAadDHYeUJPFslIDjOw+qDer1IwM74vt8gsAL0lp1SLG72ODBOxsm5EsgtU5nR0uOAWV6FyoCI08wkKCtAQ+yzemqCvlJw14ytbYwtdYG6F6USwPiyfE9ti3uIp7VmI15KZvh+EHjxeTVrK6aVhMi4QlMoQrOOKeekeXkNnuvY6coPuBfEwVex4r0hnpfLH7/yt2VmiWPebSD3KG/9da/i7wqcyytKs6UlyZcLEvAVVU7cd39+wqbqIDjXbcx0Y29i9Q03LxxP5QDCtfeduprEv1rmNZQQK5AB6Uu4vAqAhiYamajJj3sJtZhnugyrqlvOCq2iUqsyWVVTDKqVSZKpaGIxf4/Hw0L/JnCyTMlmHhg9rHbu2aSjALqG3hW9zwB13CORLVmB1hRb22I9qzWO58yUNhZrP4Yld1Fdz2mlWzWDJoHdGFlk/OP6cV8fgO47uSiEkhgBpg1+/folLAxbMyFg3z1RSlNI29Ca4LbvUST3OE4cY+L0uLomgqenJ5yn4Hhouqq5AHCeJ0R+QEVTqggh/DxHEK+qDWfaXpwzCWajMADQqZ41mmoJBsZWzWDwfRHawiWOLizU4DEAn5pB+9K1e2NljlVQ0WSp3YU4gUCm+cyPeUbQcmvdhXqFwhKWRGFiuhVR0Ha5g9o51RIviASPNfGGuZQR/JVG/G+buyqsFOEJBMqF+Sozpenb5q7wU+t8JGAkzzGAwpkiOHqbRSxjsJBgvIpZyjIFI2IV2ZVw7a17v2fWNoKbTqG0gJ0lc6P/BBBqWXh93/YQaqPIuaQVjmPN/cz9kp/Zh7ZPzJWqALJsZAF1gFt7OY/eBvejWX8BFrknYLFaRkxoksJn3f/8sWy4DsCkXealChApFHP39xIzWOdSNYvtjuHujuG2mTGOodyZA3MKNl/PMbun6R94enpCHwN9dBweezOR9Z3GdOBIAFficg0YDggkzhrPLuvGWeyRJ0NS20vsP/AAYDHGr69fcbob1aef/ASvr684zoHWN/yxP/4n8Py04zhnZKC0+nSCL1++4HEcuN8fOM4RQJzubD/7Qz+FAJin1Q09zwO//MXv4TwOnJ4A5TwPPO4P19yfeH56juLlT8/PIWyPOcN6bK7kDWMU+hFnhOJ97j0RMY8FaArvgCXN8DhoJv55PB54ut1wu91i743hhZObuRbbnkqL3XHYOmTG4EIzwk2Mgr/X3DtPbCKAThzHHffXr7i/vnoNvgfmNHDbuyey6d1jTOUSY2T9Z/IXG29VVpDJlKNYwFoqKR3QaC3xUp8iYLsALtI5rJ9XrLEqZ5CKHU/wtHz+Trv2xwoYIS3L81yeJZ3pW8dtv5nbcfC+kl6/CYAeMV7mJptuvdK34N9BA2S1mHFdybtZa83KgCQdmL43erckO93pMRO2UInBa8yiFCINUg1lStu6144067fRihE0gfS99Y4/8sf+KNA2QDbbKwAgdBN3/Aq1GFaXHWCVStDaAyKmuDH60cxVWhXnnJYMaU5sbY2zFmHZKFmse58//0Z4jRyH4n6fuaQV2Bc6zp/f/lv/Nz6u7+P6AHTfycUYn4xVA0RNaBiA+bR302+1tmGMBwAJIgsAXYxJWiy7qa6mBWBYLMtk4e01nmeMcVGKvS3aaQyfGi0HD1II1Jwec7ZqpPieWhiZz9TaeZXoVZcFMpysf+fM2bW66pmiaA0MVznvA/sOvK2XBheSmko8H0BTTKCUVpnmiMxmCzMvIIQa7uWqBN0muOiWNW9RY0uRlQ1VgPB3qlv3cLUWBqZ6q00uAj7BYAVzSzelxqkhmP5bprTW07sMAhQIaKmjwCRChUWCKwpfgrRkZtD8Wytd7YeUNWgi7lpnxZpD+8/nFosWx14FyKuw5/PtoG1xu7nMPfdSzmMK4czWmLeuQA2QqDOHS7uLZcQFqWtB3EguEO2n5jzmDZLufZc+rIWj16uCXQUs251wHgDIeh5COQPbbeYeaomT6hjSUsRpTrCgdLUKZYFGfM1qlaNih3M5cRzWn+aJPc5hcUDb4wZV4P448PT8AsCAz3GcuD9OV8QAc5x4/foVX+93z+ZahTlAYMoC1YFxOtCZwONuYGW6guw8zqy5qAgvAkgWIPcRFLdWKeVaAmq8cxXq8c45rAXYfVlCKZfAdLXaEdB5YBhAeo+kfwGKKo3RVGIBRo+tNIb14XRwuyi8eDZ4ZusevZzxSieAoiz8fa4rDSYYvx7v66z+uu/fa7vSpaXvV5CXD5QXrisccL20swJDOI1s6KU2rIhgBoAt/MqtdhaLlooZWoLprSCSJUVc/5PnPc508mO6XI5QBFm8nREjMXdkjkdc0cYMj4VwBr8FPKOkmPu3WPmUrdRkbZlSJfbNvm0O6HrMjTT1s5Yx1jpOzHkmvwAQFnGC2GnKkTEG+pyWHGUM6GANS136zIuW5l6yJRuQ3sq73u6RCugq7f64ftzXB6D7Ti4DPS1S4POIHzPdq3QKprBenQcSz4E2NkxtrrGH129pmBgY5viEqR630Oh2Vq0SiwyORRBke0vxWH/e+0jxghrkBFTvs8dkiFeQ8PZefp7WCX3TdliE5oSlWW7BLKswUN8dLWgRnOJvA006JmQ6DJp0M1vfTDG+NUtAk0xag3ERFOR4ONEFzMGYbi0DtmiCXdgVuQDmsgoruMsxoTzv3UGuGhuydiJj5HtCClLwLh0oHfbv6hjr/W8YW46hlc9a2X/ZHwQY4ZDZLwqljJ/oJftYjZFj1rG6J1a5L5AY6ipXMJeus1dIV5h3GSsgHlNVAHiZA2aYjT76vlkUDFWYCMVFcVkrig8uhhXs1gQLrQjMZe5yb6yHL4WRMuG6gsQmlg/2+lz9qf1rzV2bZZaNU5pGjpNDiX00qwDE99S6WXbbGAPtPKHd+joc0A1a2kRM4w7geDzwOAzUSetmiZ/DioA/Hga8+u5umalQETHQaQoeo7DHcQCasXPnecZ8RE28xhinFkq4BnEBtgrxvwZWFHrIffd2n/iUeZkB86Q4lmdEmid7oFDLNnJZoij8zPN83fHp4lkokb98zhHlV0IZ5uC2grf36Mx1BuSdKdGyHhzDde4qj7qoEN6f3nfevbQlae1eAFuhC3J5ZjlvkmcpekAlYVtjbhH7obTke78x3b+f8aqsUs1aaeD+iv6i0K+y5yRnL8bjlsYE0baXQ7ErEzN4/Uqv4nz6D5rXcuweZuFJduz/3obkfNFF1OKLZ5RmmWJul3MqHvfXsNDZcASsidm6YLqso14HUQRZ2gQ1/t/XjcrLMSAyLbO4jKK8WM9ZvbKsh8KKpI+Yh9gLkormGkf3ww8/fGPHfVw/tusD0H0nF4HT7sVrqVHEHBinCSqWjx9W4mAUbb2cUN08MYeEcNthtEjmjKRaycCT6VOopOLV6H26q21bx5xiActV6CUD+8ZPFTCYwKEy5qpRTMCYn5nwtxK/qpGmxk889ovAjlnWtLyHAh/bBphZi7FIiiV+jIKTo76wqQVnLLBLMrsZVD3tsUafYnLJ9AJu5XyuggdCsF+AYQFlwQjrHopHtLQW3crnpTxVQBIF/7asYxGKFma2AqOlfmCs5+rO5Dx33Sf+eS2UK2JOX2/6QZlIS38FXocugVzETtTOE7QQMBdmnsJkZfDI70Lzakyf/Z7ZdDyTQp0DNgrCVDBwxgLwEPOaWyqFdSYIWhMRYemXgRmOucWzIkBrfp5adTcVOyvlurr/1L4BrAfmsVmcOwfgM/Z8xe1V/Cz9dAFwAfPlPEo5r+8Cupzo6CO9GehCDTiga1bLsYkBN6OTA9u+43m74fn5CSKC+8NcKsc5sO0NY5x4nIyJmWhtx+22J1jmekyCtsPqX6LQZ5glf8wR7mHSBH3b0LZua4L0EOiKnEdgRS4kOVf5UQsdoFAe5Clpu5FBo+EzMlcmIBhzoqtZzGLfOSmkOzzPS+wNNl73z5yAsiwHvRwsy+fwH0vGte4vib3C84IEM3+QS4FILBQTdwV2hXD+/7mk7uv8LGjWEp94eeYC9up8cn/LtX2RcpLs9/JeySRNdhZWYD+GhUrY/phAb5FJNtn3dY6ybY4JoGtzX9bPXGSt9tycikozuL+6NI/ns5IJ27ZB1WnTzP1ERQwVCr/95/9ppDu/zdFw4iM6oTLQ5MQvfvf3IH13F1LxM2+ZNRm/J00w1BQKfdvw/Pwc2WUJOG3d0nW9KwAVUywSAL6Rb+qZMbdt/v14PCJJCtc4FdLX4uMDv/3bf/cPtBU/rr9/rw9A951crQm2zQDdvu/ulqbAGDgLMQ+gJwpMtdgvhf020RjixT53pmR3gU8egse0GJOVwKxaJxK2KKYcmrKQwFIA1CujzPvNAmFiLwn2lYlU0LdeFeylYFtBGfX8TGICRaTID9eu6E8RNjT925kxkB+IJNPjvwNk6QpqpruZyszYJAOY17HkGJO4s31Nxk3BXkOKWtso2I4CUEoI8Rb/fnXbRADaIphRq14Fk+vPskYVWEgRRCgseowj71XGwFCAQLyn1X/Hux3EVeFOyt+gjKTpkunB8Ez33yPJgpRpS0EE5V3UIksFbxfAycK7i8Cm6tbY6xoHjPHlVHDPMV5snUf2h8A3763MP5UX1jYBXNRB6kzuwn3lFjpRrOvZoh7dtR8cKz/rHivDOZtzBDC3CWtoKK7ZKAJrAWcx3w66A9TFxr3OIXKuAiiuSZsyfiUz9HFf8HxDvTZVayE8br3j9vSCp6cnj/U1bb4VGW54uCVJRFzo80QL7qHAuMXjeOA8D7PCuVeERryogTmdE829LSAmzPbWcY7TFTqCLg2Tiocqvr+DOereSes33GKS3gu0Stua+b4P917E/hC3tJhlpIDAWoPwwhe4xQ2U2ruGg2XVHvTK3NPPjDt2jxLAcxuGRbKcSVTIwpqd78wD6VhhR9k//cYE6jf+/vY8r7fX85cdeQOA4ixcgNkF0PH5N1bx699BYyRoFD+24c7y2Zun85yD9TtXiPjNOSh95nmqytRU9jhEFEvR33rP+PP6phiDl8mYsrpUw7JuewlW/PV/7l9wRZi7m1dZYE5gTKANPN12yHZD63soIs1iaXPE7KmipnwSEctGO4bxCC00HunBYa6XK+0lqDN36V5kCjgdaXEv6/Xys0pvSdNrUhomlvq4fvzXB6D7Tq6tNTxtHc9PG56ebyZQANhbx3kcoQEyotHR58SQicdhWdheXx+Y6kJb39G3Hfvzi2Vk88KfX19f8Xu/+wtESu3JOkGK/+zTMwCkuxqF4gBARcsEoM0JZcBzABAAlbihMngj2hUsUTuW4EkW4hmaZ7+o8TfiP6CeZY/CrRHjgdMTLOgcgPQAlwBc+5wxd4zxUZQEExQ4PMi5MrVzDLCGnQlApgFNIEAmVQFwwqurxUWQsUm03sGFqbwHYSkksDTpunn9Mw4MEFyFBAoeLANUQc1bIaPGtJhg9b6LCS8yKbqZVQuerTFi3UMYl7fWt60zUYoE4GsFRHH5KJJYHa8WgIb15iqjTZBFBr8GtxM4JtCVYMgtQKJpc2eABaRCI8AxxTdbc+7b6SCA5wx0Yarr4/MsIiFAW1xoznvNrtZCoPCz7i6HKPWcKAAGcJLsZWvNlR4z3t+3DkEPhQCTYEzPTjqZvVWGy8xl3fYbRE4IWiRlMotMgmjLMGra+ShP0hTi4H85m+zbZaKsvl0DOswtfe8hCM0xMYv1j43ZuwHGC+37jp98/oT99mTZ8PpulrO+W2KUH76iN8HL8zNUFY/Hw4CLKE53HzzPA1++WF254/Eweifm1sWC3XQz7M9PppzrHU/PT2it4/w6glxa3TnFQJaNWPZ54uQ4B7b9HFxCse8bxunJURSRwEIgOI4jXD2bNOgEztNc3bZtw+vrHftGF1L49wPjnF7ihm7m6iU4SJusLlfvDefhSSd6T6vc447j8RWvX3/A4/4Vx3HHdCudCND9Z6EFpgGJPWhjvSo+8qyGx0TQoRUAci6TdL2lYVL3XuyzvF/Lb55wuiEuey3oCd6AOkgsYD4Hs8o2Kr8qGAxwb/OR/Us+qUqrc9IbetTYrR6r2Zj8q+XzRXlQ6eObuSlj47msYIRAxLxEq3LJkq7otHPJDldgVLNEnsdpHi1KzxXSPafHLcsfhKJrnFAVPD/fsN2esO1PVgty20zR5pqnkBWcd1rCuIedFXYNlgVXoJjD+LOdATvP98djiUfl3FyVfjXZVP3sapWuII/g8vOnz++uwcf147s+AN13cpGWUyu8uaA2b17MVyoY6JahTAdmVwwvQD6HYkIgU9HnRHPNsyVbMa3Rbd892N0ESArC/82LAbqIX0Jqgy3wv7hmscNxDxCsmBp1IMCR8abCfMMffi6ETt75H8GAxQx4GxU0hbaaVjZWuGFC8HJPmWcGtfFegqGCL8vixPDKpcsXc8yoiVbxjyy/3xdUAiAslhPNOwi6KKFcBJec+LfdjvGIZDlWF8apuX/vMgHprRq8vu+t9bS47XEuhcXqC7Pj3y7Q2fqu1rGGct87a5KgMGtaEbyGyOJCHmN2rkw31+pqoXYBxWseLeuvKehdZiwsF/6v1EC7tLmsJXiEUtCb4jukSKJXMEeL0QLahEl93ts7uW7xzbJB1wysgGIK69EBnvqANyOF6QS/IYyecHqRt2f8jCl/ZiSqmW+E6SrQFTWDA1GJfbK78Aa4S+sYxTqbT3LMVYTl57013G47tm1H60YTmWVUWseYE/e7CY9T4OUHDugYlgEv6qrNyPgXtT6dVrYmlslx32KexGOf4GsuTVASwII0gnueayjl+2ql632DNrXSCtN5iFslmZW4u6cGYP2G09M5DBi2Iq8qrcIsfM/z3FKwN8vQmoE4nztxnhaDeD4eAW5VqxdEVagIMYN9F4AN1Flx18a2LVs85iR3CpJGqlyeLUlR6t57j+ajHHvVAF0VzL0L3vg9LnDJacCyH/m8aswH9L3O8B0J9Fawh2g19pRYgigqZkkb2P8V2NWp1OXeZhsq6JDdstKzJU42GawpmCxKZAE2uQSy1p4Vgaji09/8f6Cq+OEf+AfRIFAmjArvD1Nq/N7v/hy3pxf7YQbXfUve4i6XrZsMtW07np+fAACul1323RxeZPw4LWPteeJ2OzA1XSSP4wh3ysz8ugK2CtyqNbO1hn3fF7lqjIHX19d3dt/H9WO8PgDdd3QZgaRbirth9m6Z5XRCtbm2KIuMb66p6615EduBeZw4xFKF354GbmNgvz0BUDw9P2GcYyGsYwwMJHEC0iplGrE1056/2u4sgnjAlot2vr6rCv5X98UrsX9T5qDcz2vqhA7X9i/38HkXZKJ9WnE0QB0ADB2gUD4xAC0aV77nwhCrlSf6aH+s6yqOLFzAKGJGXXk2sggd179XOeYdMFeYSPYRISEGSKZAwsdKOwRzqnJ5oT1XQdwbt0AAGaAvmZTDn12KhEv9LAUh1rv/dYBO3hNGYgrS1XBxbWk9U6N7m0wudB1jMmWENSTBqv93XTYTeBfRnAoIH38VjAjmYtwCYT3BBW+tApOEmxPKbwo5aUUMV7oyuKmAjJFxfYC5xHqWOM6sWaCnu8oNt/6sgjH7Fq7GIJgbBojNjo/ZDDAEmLv8LO6ZHHv5rFowWU+wuyujiO8/BxQI99MiUCrAJElznLjfXzFVcXt6hu4DxwHgHLi/vpqFGWJp0r2+1HlaoW8CkwqoVPPzUQCeIq2frWdCFC10UkiH3lHE5Npzm/HM1r3hCgQC+qlAy3M4Na0pbEzVLDssg2OgsL6RFmLf6yQjgNsQEaUkKOwLecWcbqGzOTm9FMR0l0udNncBVuPH6VAFct6X3L4ESnX/peLo3cs2t+/Ly8f8MMBY0uV635tn2Iny8xZ7rXyDHdAK/Mp9ZXT129q9eC17o66pomvju6DCzxck1wdDoFu+hjQEMNrgKBESShX4edvdApdnHdetU+aqAQvdjT2q6b2T4xI/8p4TQBV/+i/+x1Ao/sf/8D9a7uNYJyZ0AI/XV+u/J30BAJxH7A6xTQphAiIvl2HtGD9maElvDV163qOehVaw8Ll937Hve2RtrcrM2leRtXYj+1+fO8MKeH9nJj+uH+P1Aei+m0sdzKEAuoatq6Xy9aDkOcleeXnJgq1DzhNznHgcpkU+3A3Oio1PbNuOp6cbzrYCuvM88c98eYVC8V89eY27Ihxewdb1SlCXAn9+nhqqqpm6EkISPX5WwdyaFMXuJxio7mluNyhMpNZXymK7dM1Tp/oixfpZibN6XT3vn4ElmCBWtJECL6pbY04CVJVf5NnfkEHqV5y3K/Cq8xvWH14XphKvNHTkguFbQLeCObp9Yn0+XuFrOL2MQ5mvwutDcFtcK4GwoIgLqtfvFwtaFfpiKl34En+Tlhde5/MC6lhsPO4twiFBLMfBOK2TrofK3QXfMxICNufsqmzgS/hMWBJpjY51cBASbrbrOr7N2Ol9kfU9q0LDFRYB+OyzUYBftF+EWZ6XGrSfLkfWBpMVAWYham7iqe5YgETcjrqF7vpz3Vffumwf5Rr2vnmiJqt/acDNWCXbJd2ipQwwOvf161eMOfH88gnj3HHOA2MoXu93HMMy8QGwdPvHgaPTlTvTnptFvyRH8dpz1ZXb9qgpEXrv6aoX1tBULLw/8gI2JHZe+QbxDu/R3gsAACAASURBVAqPUp5RmCJu9jRDEKyhw5+hpQ95T80mWt4nRFNaLHRl01RQN8aJ43xgnIfHE9JCN71GGoLukkYgkmLR0r0qvXKvaPTjPZaU1iM7I7mtklaycHdsLs7zN8Hh+nnQqffvXml2VZywOX926UcBrb/uejw/4Z/8y38Ff+3P/xMYbm1KLxl/d5wxCfo0Nd2Ygw+8gbBS+F/y4X3fnUb1mKG09+e6aOwjZtNes7dWns5+c8DkscF/+O/L+HnPVMtSa/HNGbc31IqsD55FwMpo+NyElwaMF9BVc992PO1PWTaHLpPyljZVOlvBWZVPRORd0MdnrGTKgcfjgcfj8esX/eP60VwfgO47uXpv2LfNCyw7w4Li5ekJRzdh7jgODJ1Wf8UJMzVb+7bhLnePZzL3mzFO3F9fI/Zr32/Yb8/uk37Dftvx9esXPI47/sKvfoAC+G8/PXt2LIIj0twUIqklzfIJEwSWAMGZtxAEUmC5R666z2wbQDIi1HtTQOK/U+Dv8Zm5QFzfQcE7LZ9M8GD3TtdaI7SoIdxUwRpYQVowm2KVuwjYKSQUkOvthLAk4hn+3hFc2P4bOUN9/VewlWAt4zwoOFXGyfui96GdDTHTvvMxsp4WLSFT6XJWhL9ArFdsdQGZgqgTRHdfJkhZatCJRDmC7G4Kt+LtiM+9zpkZHd3FmDWXqnbX/GxSyFgswRS0VMyaNdNakfOcbems4Ffi3SsYb4CsFu43+7NOEwWyIhhQCODbTcCqfckz16IW5HuSIfdjCmw6gWN6DSnvhAE6JgHx9j0WECixjayfxNjd1rFtdCmakXCJz1X8vW6RFNI5TwsYF4k9Q8sS05A3Eaik6x9FRtYkzPjOAwrF6UoukY77/QE6Z9/vD6BZQqrBWFmnC+K0Tj3pyJjuCaEGKI2e2PlpEOxPT1Yc2d0WqQASWAH5sNAmMeVExDoanfJEIuJF1uEurLAzOc4B3QuQH4pxDvStY8yBx3igjx6CuariOE+ICLbGDIaMxbJ+KtKK0LcetHN6Ns992wy0uXUBmL7nLD6JJR/O48AYljQGWK1fTQSRSN+BtxXT1nc2h8+L+5PG13HGSFPtP/XvFczlc5WWp4t02YuXvbmAN3X3S4KRdxDY+2odJLjDBRBK1kplluqCBxHeElD81m/+cfzh3/od/PG//rfwW3/mHwV5i9YEH8zeiBZOKL6MOM4Dp/o8VPCyPWfiJ2kAWiS4qgq2vlEk9WCF4tZq9MeVNZx2Q7O2NiweHyBPsO9m0R+eGVbm9LZToSwQ7NsNvQ2MNnAOxTkVW2u4bRtenm54fn7G0/MLVOCFwZ1PQRE+MWIWfADuGm37//E4cNwPfNEvNufzGjt84WgXGr7yB7vmnNi2bcl9oKq43+9hmRvDSqT84he/eGfHfFw/xusD0H0n19Yb9r1bcgiQXAKfPj3jODruTSCY0HHiad/RZeCUE1Bj1Ld9dwGYTEqBeeI4T4zjwHG/Q3rH08tnPD+bz/nL7QaRCdUTfTNg9JOffsaXL19xHmfiF8mMcItAq4rzPFAtG6adY4KGTNLARJL5+SzPABRcskhyETopLIVWkYCXRZWdAXjCBXMLErNKsS1/VOACC7XVZEatLZnACGDga/FWHVu0236RUYeQLwnqFqtXorkU5pUZOdka58Dfpjm/FVzk/bJ8Xz/nr6JAXTWiBWxSE28ggm5lqWkMJud9rv1r3H+SVri3hcI9mUkkMSGAQ6x/D2tMZf6lf+Xeak0I4aTZOVrmKnQGq2WL2upIKODzwrhRvkti7xHMzdACCxyEseaSAOLp4tE05ro+GxY/b5tCQWcmyrI+KH9TKXE9h2GfjrXXxVUSvguZ7IKJNfKMYbnUNwvB3OnW2FoqgVYel9oc0NFVbjp9GGhj4nEctj5Yrba2ldY9yDH1iBn0efUxzzFw6MRtX2tqxg432Q1bbzhhyU3OkQKqKvA4Tjx9/epgq+M4B14+fca2NXcXHLBkSoo5T4zjYePfN9xfv3hSGcE4DxznA1vroYB4enrC7XbD1y9fbUwlPboBupZgQBj/PCFtLiUycjyK43iYJYElbRQ4jwP69BSkaU7FcZz49OkFJ4XkMTCnYusbjuPEeVhfZfO5pHWBpVs0FXUbumdFnTjPA1vv7m7WcDxe8XhY0ebegON44MuXX+H+9Qtev9pvs1xaaQfohCWYYb1IsULSrrASruNViaa5d8kH4rtykJN2XizXqW/haQ+6G/fxjNWNz3Z57mujVOYVYLe80pUToVDjGXXaKkBa6cpz1Tuh0vPlEsHYOrqY0iq/X61hCRJzhqYq7vcHhj58SC2K3L/0G1rERdpZYxzmcRxgsey2pUJnOE+nItVogPHVcQyraRDAW7Dv7tboScx6n1Bpbg33rKhzRrymjQlxbuY0i7McJ3CeuPWOW+/YpKE3oIsC3ZQnXbu78TRI33w+tIRONN/urrgaA8fjCCUUvU+CxkvS28Pj66qn0VpCxe693W4B3gA7a7/85S9xv9/xeDwC4P385z/Hx/V9XB+A7ju5FiBGXi+mnaNf99Y75mbCqs6B4QCliVrmsCboLYVTAkMKBuM8cf/6Jd5n/uSKp6cnbO5n/unTJ8w58WWcplmTSx+DsMFBmmWFqoDj+fnJCm2SWM75Rgj9e7lWq9WqBQs3N2Bl+gGmSr/LP6JNwFInxz38zxV4FWb/BtS912k+/Otu1/z1joY3mXm6qARQek9owfWz37+jFJxpGeFMEKRG/KSDuOEWCloKrqUZqltkgLlqiZPUztrf3PM2EdUSl3tfyucpGJgcvGYME2QsHkGKy08xN0smOBQ8GoDI7uUczJL5NMEHlvmSstDcf+IABzGeb6+HcMDl/EQ2wXJO0k2RhX050zzf656oR6yCwuGWJwXfkRsiHndXzRhrEVBj/YqAE+3EXAts7zJ1N9z1cGCMUhfPX2Vjf5vGnf1a9jPnXhUiW7h/JjD2lSBAjOMYi+Sgbvo8qhd+r8l17HsRcTdKiyfkNc/TrPpNwOLZt6etuPZmCZMFgXAYUj4Q2zdmndiwEcj5XNr0ahTnxraH+2lax5l8asZacC/mPZ4Rd77dGyHETrWC7IXOE2LpnOa6pllKPpKdwMsUeNzcebibP91QaaUTAq9r3Kws5yhnbd0PGuupUB4TVBJazxnn3ZVqV7p8AXPfviQB4K+5K44Rz1oFeRfAV59JRUaCuasCKbuScyShXE3aZrdUZVAOgTbSOScG31mIOGvWQWp75spr2VIVvQOdngIi7gVExZEAMi2WfQzoOJG1CTPkgs8aaLN42AlFU0VzIkha+16WyPjbT/Qcw7LNQk3B0cSAszS0bhls+5OBvDGHW8yA2+3JS4l4+RMIpisux2lnbc6J++NhZzPoi+Lr16+urDrjh+6cBMi9d7y6dxTHwBp1r6+vkVjl8U4WzY/rx3t9ALrv5DI5dJYfhYBaTWDrgrk16DS3zDGaWz1cuGXwfe/YescppkGuRFunaVr7cce5dYytAzpx82yYgODT8zPO44HzcTcLifcr3DqAcB+KnPmu8ef7RJAujGKaSUsW4GDBhcmFiYcgNgNs8L6YIC2/CyhiTZsiZS/zWt1OymQHfuNn0RWJW6qYX1tcX1L+ff1m6Uf0mdJ7gs9wwSmCThFD/Z6smRZC6zsv1NDs57+1jIUuKHShpIAcL6JGOdLul5jHSZCffVsFkRWUpVtlzQCWQlzcj7VkQlprJb6vgqY5FInFOPg97WLR4zSH6HMFPDEnq/AVC1kWlO6VFLBRrQVVKGXbkvubCuer6FjB+SzA7Hpdk6KkkBPHz86ZyvIZ3YkrUBIX7pgTqO5LHqsKBCxRgc0x4/9Q4tRohad7LrQKbxQ4G7atY8wNvU/0MTC4zu+BOU7te5NW3sM9BmjEPCqt86GoSKumy4lFGTExhhdGbj32yix15BQzQAlp4Rhu0VKP43OrAjOQptvZVclinYiCLsK+cPzq6zgjSQUVI8dBt1uNpqabSJjaXVGS/Gjux0k3NmXNuIzpma5sUx8H1MswLAvggHMAw5WAcEUeCcsYZv07zwNjHFlQ3N1RbdTGr5j0KE62H87MAfltkBUnxPcpz1CwiSut53PR/rIay1Vrd9q/JdsqxKOCt8X9kt8R1PG+6NTldzTI59efN4qg4AkCQStK1Mw4as0pck+VAcfTdENEuUeX/pr1rgVwMdfKTPQBkTg7puwQK8NAD5ypAGbSitK3XCvSeWbutVh0kQa0ib5tUV6F80TaZVkprUwI3Atn6gRaD0CHMaFyYt7vmEC4XwOCfX+EJ0drHV1KkhlXQgMmW3XJ7MgAvI6l9bkCOp57jvPr16/Rdd73y1/+Eq+vrxY+46Bx33d8XN/H9QHovpMrAN2cC1AyBmtZ4rbegW2Gy0paQMRLE5jgdI4OPY2FGl0ig9HUpG4PjN2217ZvIWQ/P93wuN/QesO/8bs/4H/fPUZNjYlHRilJQcwIuHiKabqziNcgE2jzNMFBzN03vwjSyajVhCi2Wxl1oDNzhbpa3hZ27AIDrXtlkuPfAgkrXWWdFQRm765/v5E037RTPycLpeCbmtwVbFRrg/07WwzLq6TmPl94sbLxXdQOBpi2FyoQ8XAhJJcpqoWUmcbchFjvi6wCxwrodMlgGfFwBXBdAVYWFJdUVJDhV2GkamlDKEwhJIBxSO5vxba6JjloCm8p6plgbPtsci8WCxHKWtW+LW8LbbSG61VooUPglzgbUgruVu20Jdaw5wbrO12EX6l7QS+AvfQnpodPa3kO+e45NepDAShZOt28ioyzA4Elck74ltYU27ZZwV4WIB7UemuAum9f2Xic+ngm56g1wXn6fta2jDsSGHHdvM05Bs4xse1cC+75gY6OUFZF5tYZlqe2IRJ+UGGRdTHlna13pTIAFTgcp6Ceyxm0NN2jU6QfTPpCZUk5z3yHNaOQ5olSaInzRSOoCzd4zmvlQTCQO6GYI93hz+NwvmFJY6wGX4I5y3CZcyeX81Jm4fKbSPcNLAP3aPAN9V0m9Z63oHBpnzTX70tFG9ZeCfnOCube3akV1GlmMn6P+rw3Kq7zaqG7nAsyQamvXO9ng9V6mx250sxCD5bpsvZ66zgHQRBdrJP2mIVu+mdUHnHb5P6p1vwr1yQQWsGkALCEJTXxVvUCAUyJIGfH8BqJCkXfAJUGFd/rGLifA+dk7UZ7/v44zG3VXeV7b9gjYcpFwXdZMFoORcTp2sj+iURN1i9fvsT4mPzkV7/6Vbhskr7v+w0f1/dxfQC67+SK/ALqmi2r3rJmdmzN03W7e2UX9NGw9WkxeFvHvnWMk5naQg8HgZo7JrzYLibGOAAAY/TQ8kOsaOyfOwY2AH/10zNaWN8QP/bvFAxSeDOfeoinPO7Wg9OL31r8Gpwb6cK4sm1nswEAqXGc8X24NC38rgjlV2BUGGFYUkQhte5PSAkrDb8yoV97vZUlQmiuLqHq94aGvr6+cNfr35VxX4uUX59ZAJ1SWM8XpVWlouYL/7qAixznFVxJ1JWDVuEt14pCFGUkyaYynu4SOM86daV7l364UBCukS375s9Wdxm6fwW49Sti38qmErGxR6ZHXZeW7+Rv8P1vuxgHR9yisghv8BN0tXbhnfTfnMUFFOoyFntdhegF9EhDFeZ5xsICLzxr1yyCJeFCaKEFtIYlOKYiByDNsBiTDX0z61wvwFBIA8r+CpALxP6bqm7ZyT1Vz3ctg7CqiZCgOuYlrcVc322ju2LWnLrB3hlzocX1EXket95XBRtrYFVgwJ0vub+4NldBnpaE6YlAeu+orsIcG4Ffp2APj2dCKa8C+D3qCX5YkiJjZFVbxYBoIphi9DYAIq314/Q1nRjnAXSvLxgF5eliyVglWkmLIifWxtfnfYj05pKgk+ys/j0/+/6V778qA7Nf77QfyjhJK9211QLwvkG2/I8CFi809o2SgzxanZ6ruTpWvkAw+fZlHnMMQVfWdK1AMMF70uy6L7OP061oWjZNJrnybMKXn9JA8hNJQN5EIJ4N9m/82/8uxhhePzHfqXO+OffwM7o1Syp3e3kBegdag6JhANjGNOAZPNDdREs4wfFQ3EMzBU9UxslAPHddK/atZrkk/fjFL34RZQ4ejwfu9ztUNTJrsk7k09MHoPterg9A951c+9a9WLLGb4FinEcQyb53YLMA/s2TmKirJycajnOPWI92nND7gSGpkd66AL07oBsY4xHa2ul+4uf5AGTi6WnH2RueP724q+aZhLexcC3ChccSLFhAteor+mapxZu7IBlTOYwBDcs+JeY975nsSn0u1eISRkGRjKoI6pCMo3AQFoJ8YUQB5hxULQz7GgzmaCSsX+8xyF9zhQ45nufnLjgXi0kmdfs2409AW69k3u93It0DU3DnY5K/k60HwKKwTgX5hABj7cMikhJ4NYmkPJb4Aq7lJdDL9ajJUPjubev5GdsrQDDfXWcMEJjlulUgxzsC8LhgO5kaHaC4FrWV3riz1rnTeHYZc68p+LMI+aqJ9vHbg6DGdutbWrtg4PDUAda8A1KBU0sBKDSSy6Sb1ar5VgXmtFgubQXUOHAiQEIkBUqFDceeMVo5jt63cCmkPD5g6dBFBWgT0AbKbyKuSlLgdnNN+8zaccdx4gTPb64rXYutn1ZzCqou8FFR1AKoCRAeCqlNUD+7GgXHKZTZ/FvSHajFf0FvmNPiccbxwByW1VHngM7T7xt4PR5BK+mu/vx0i/f3nokmKMSq0x2JXcdVA8zyQRpNQDfcdXGEG31zoEcXSe6bMUbsYYHFQs1pc9CbFRTPBA9MbjQ8E/KATp6b3PtMNnQcB1pv2D1R15wDx2HKwzlOvL5+wW3foVvHedwxzgfmOABPgmILNwO0tzj7uT9IS1IxGKf38gf8nGQ/JWqFrm29vd6nk1WJVt+V7yjEx4FbEBACXYK562+UsXETxHvKvUXDNi+AhbQiz2YCoD/13/9P+Bv/2J+MZsOAnB32V2VdOh5Mzjefbc7Pq0si92UTgWyeyAeC8zydn0/MKUErWuvomycG2Tb0bYe0Dif43pcW0zbdM5q5e630gL35/Mf/NOZ54uaJR9RrG3ryTWxNMbu6QnZizgPjdNrbGtTiUDDFQZ2Pe+ubZ+ls4XVSsrVZ7N9Ur6foVjefu4nkA1S20BJ3nid++OGHrCt3v0ec3G/8xm/gpz/9KQBg2zb87Gc/w/Pzc8TYHceB3/nbHy6X38v1Aei+k2srbpSR3KQAiqxfBZzDa6p1y65kWcwUW+/YNnP56bMFowOQmnAXHmgtMjB24t/5M/8Q9n1Dm6ZlZVHSbetQbcGZxIVJZjuUE6BAGW56cPefKRBh7AmFTl34JJyRhxcXAVpgsML8gtHmL61tsM2iCV7ZWwEDZMrvfM+2ssffAE7fvFwr7X6btMotlgyCOV9j4r+1FRd0NHsXff/mq1erm8ZngZBhomMFRt4ytbLeVEM+EkkIYmJr6Qh/gICNwpukJaRamGgpSmDnmdOAN0CvXouQ5wJwk9QMh3Sny90heFWNMpAgR94Rmupv3lv/5thSGdEuHdRcMO7H1uIc57z4XIdZS8tySAFzWPePr9tlSKWPpc0QDD3LJXTxaEvLHHwexKeM6e7ZxzJWeKKNIDAA1BKhxJ6Ic54A1OhWZslsYpHCaaesAynunJf+heIh9mBdH/t3uor6mEqdSAIgG7/TRKY6DzfBFOB0GqA7ztNosr+3947b7eaCMOJ9rVpqL3QmjF5aPlv6xrFbORjSRQI6IEt6RK25aIdu0Q7gue/Dmk8lRY4xdB824liCqRMyFbI1E6aH17YTBCg8m+0TAkQq+HLhKlAvih0kLagWWkUmMxKe5eBhsdFQlXHLsXtzlYl+h26G9fDycM7HWzpCcPemtQLUgKQvWp7X+rxWDpNAK5urb8i//84//CfwJ/+X/w3b/Y758nJRvNThFrrrijV4aYprLBsExfpWflqPDLMijMf086WZSbjSdvs7XbMFjMmU3Pu+NMviSirZ3NsZgGBimPKpKbQpZp/oc8L0PHYuTxymJJpq1mUIBrykSd+N5vYN2z4DnFIJbPzD6DPUk/10A23NXcRZj05V8fr6GgqP4zjw+vqKL1++BNB7fX3F169fYy6olOPvl5eXUNRYgpWPpCjfy/UB6L6Tq2/UfvdF8w8xAaH3FB6P4wQzII4+TRs/DdAx0HecTCph7TePoRjjLOmJNVFPCcZXFNdG/0/UBAtBwhjrOHsCFhjRMzclSzigqhgUPGpdG9AZJ4U24C2IoiCwulkgQCLfGQ1cmHa4RlzmmyDFOdl6hxYQ9gcFc2+a0myv3vPmuXLHFVmURxRYgvDr89/sbSKu36fvF8EzngdErykDrq8gmGtoXdBdqJYrUBMJl7sstH2x4GFd67dDWQFVCCul72VQJpQx2J79cmAiFTAt02CtNBeCInZEkfXumI6eZwMFRIDxmSlYtwLo1v3M+CsG978D5oCwrJlMOFHzBWTWOx+zHbR4Tw3Wb7NhNgr578xYnKu1UHe6mHqKi5b1zQADXSabXAWUzETZWsvYldbMldLHUmvn5VbUFPYKAA8XShc06aJt69uKcKwmkGoKfywezu/FlQ8xp5qn7TwPz4w3MeaJcVpdKfH39N6x71sAOutC7kfVcLRelCvVar649RagnAK2YKonJRlj8Xwg0CT4mbS+FhpxBXr2dQXICYA1isZ7Xz0GuzfLEjjGwBwWiz3GcKXjLBa/iakDkwXfnf5JiYmNvV/+nisTeBekXcne70PNLjsQSxKTa5KU2mgoCAgoL7QvaLC+9/xlbOWZtUPrnuCz73VooRWq+OUf/hmmCG73B15fXgAk0Krvus53KK9kLWlQrXjVlZHum1TqsK9zTleC1XfwGSYRUlgMaIt5pGtoqKUEC5DmZ3/0P/9L0DnxW//SvwKBUZMxnY96XO+mntVSfS4F0GFncsAKjJ8TGCoY7QGrVysYDsrUY38tBEWwNcHunh6i7iqsQONZ65mQ6vF44OvXr/jhhx/w5cuXsMZxPnrv+MlPfoJt2/D582fcbrc4yyzU3r0EyHEcYB3Ij+vHf30Auu/kCiG3CLcEXSIwIbkZYDMhU+K5GVY9d/mhHzsJpgvN9BmHC4QU20WYd82IcGhugfhtfUgNvQlMPQKEU0hZ/fmnJ3CI+mVIjWC4SyaJX95pNyeDFUFhshXMkRlQyMu/Uy4s0kD8qq6Vpc1rH/5/X9c2Lv+W8uro97eejUfekWS+3e8UjK51ib7V5bc3iSQ4ec8kdNUEL3u4MPzVspVWuqhRR+ESq3Vu1VNLgLKaFIiCAV3bNGc0hALbPgmmWrUw8anrEkkmc0mdAcfZAoxyMaUsavxdgBCtdFfhjSCztRQUr2CuxjIyUyEFcmgFiQSVq0KE40GbaBOYsS65rHHq/Q+6fJn7EbX8/pw6uCpncTa2kqCQmvZ1jzi9m9MsdCKwmNw80yKx4gWYSrjzJrAimJm5dyQtsqSjkb3OO8W4yAR0WbvPcMqMVPxAWsgSnEq4WFZBmGsXQI5rx5lRFjzWoDvmhrq6BM+paC2TmEwd4YZJt1v2yUCqOAijQM1F5fsTrNU5tpg5o8dzWoyjS+DeR3PDHDBAKUj3zXMo5pRIFENQx2RKsZfLu9KKU3fp26t6M1RA800k956i61v3BIjKNbvutdrWe473lVTw1JH3LGfuQlSWlrRSqrd3XRWZte9X+rD0S/LZSuOoUNOgsbynR0bKOtdS3mM5czLRSsY6k0Z4xliZaB7/iaaFPvAsJLiLMZVt8NP/7r8GFPjtf/lfNUAJgWuaY08qFHgcyFocnqG1FQDp9GSCdfPU691ZqZE5POkQTH66bRs2KhoBU/g+jMZ1B3YA8OXLlwXQMTaOVrenpyc8Pz9j27aoScn4uqqoy7qSbxb/4/qRXh+A7ju5vmWRqDEI3UFdxLBAorZTa9f05pJgbmFQ0wWb7imlLVHKv/V//G2ICP6TP/WbTuSMCKfmj8S9AKxmsU9hhXKXS8a38AoLGjXoWBkmmXsK4hchvgAC++DiaqZv3S2Xq2jc38w7R+YgVuO2bz/z+1/ZHwHc1/890IYAdW+THoi7ORYBhIBheROy4QCkKdgUVr7OW3n++mZrkwKh5HrF2qyCT7UCpRXKmGICtQR4TBpRAV2s8TdmNN7nMVNLceoC5ghy1idTAM/+ZkbMmLVl3QsIbZmGPwQc9kUk1rD8sQgr1Uq5IKjLmbfYpQZxC1e10FAgB2qmwox9M6PTNSFL7h0KE5wvFXi/prsGSwjvijyHpDemRU56olB3Y/J9opYJtE0AOmIPcRtVV8dQCr2zhhVUqzp4ayy43tb1LmMyt8J8BwEZ98wbQAy1+Dhkwg6le6VSCTU8I53FkhHYGNDKAtlUhnG9cAFOSX4SINU1sbWdJdskQKtdtZBOzf6pmivmnFaUvHnZhXjnLGfBBeE8s7lHE1zZPpmesVN83s0yOWI/j2lxcaxBN4aaBWUMzIjRIzg12Br0oK1eI7FHC7R7c4UeKQFYuiqG7B508i09k3im7q94rtyduML/Wzoaf1XgVPhOkOByj0SjK9W+gsW3SrQEW8sz/iLe3Vq6Li+1zN4AuXiR7XXG0kmOU6gQuJxH0j9m1k0lCRVa7IOdqekZMfu27nMm2w53ZhXIbEBbCwIl3Uw3fPW9KT5XVI703rxEgWBrFrv38vkzpHegd0xtGCo4IDAvC8U5B85z4OuXrxYv6zF6LM003Itoqln9jvPEUD9fzqO/fv2K+/2O+/2+WN1utxtutxs+f/4ccXOkOfSQqMXI63Mf1/dxfQC67+iyhCaKOVsKB8H4jYhuG7VsllHyPN0qNywOb2vNiFu4tMGIoxNy1W7KLlWM00HM1vGbXx+RpdASslgNvExKYp8j6sxYiYWtp2DGyizrdgAAIABJREFUQOPWGqS3JMiqeBxHBBoDxs+Yir2y1UWbzVeH0MGbzGL0BmrJCj4UAGY6cSbOSUZH0BQ2wkXoi6H/gf9euoXifhc9I+BOQFEfVM3EMNWKqGU9RMTvSWuEarYnQMZ62D9y/AGidREAkolSYLYseJjwWmwzwFF1e+y9Y++b1y7USIzSr6CvpIperdHeT0XuuTKf4oJguv5mHwANVxzObW9M899iXsylqGihc6Du8mX3LcCvrf1/qyRBfMa1Xp9t4Z4Ue2sRSCkouztyE8iUFC5Uw6LF2ThPSyVSrTnVghX7wPUoFIgzuctqTafmuQIeugHt+24C3ZnWfY7ZPMJL8d8JTAHGyXHCBfs80yBA6xflk0jpAwuSmyDWW8e27+HFANhenFATaiGLNaj5usw50WDxXwQZZmW095wOSsRreVoykkeM/XG/4/G4Y86BHTv6ZslOHo+Hxc5xbjzGjh6jynUNgTatgihzn67iHtM4aTmw0jIUYmnRHsfE+XjgbC4wA14fTrDf9hTunc7O4coAaVTHLfu/tR7rAJw+/tPOsFgm5fOceNzvuN12zHniOO6YIhjnCWYEnXNgzNME+jlMUTjT0pmKnOQJluZejK5gltIk9dLlV+wPkG7BCCQL29Xn49+piNDSp1yj+LoA3jy7Ufhe891pOUyrKyEQXTFt3o3n9ua1G71fi7JzJu9Jq5UTfin9cVDvpwQign3bcG4bpirGmZMkNr0eBA23bhlNOXW4LMGMtT5P/soEYAMqQN+Ly6WDfUv6s2PbdrRuSUa4n8ccvt9iwczNEWo6UxH001elsSD5NSbW+rRtm9ErcR7VmoekdLTTasDdHw/c7w+8fnnFmIrtV1/Q9h1t26HSoa1jtM0AnaqXL7Csl+oWur41NNmMVzko1en0QWwfPM7DfjxbJdQ8ll5un7HvOz5//mSJ4HrH0/MzXl4smdz9buUKnl+ecbvdcBzWxpgTT08veHp5wU9/4zfwcX0f1weg+14u8TiCOTHmRA9NGAXS1Hz2jfWFELXnjmNarbqtoW8N/TBBZ+umeaOmy+xxnrDDuBrCHccQjVnYQOB1YRTI+lbQ6QVBxQGfYDZF66mNtb6z0Pgy3BCcIbJoXRlbE8U9yS0DrTDBC0wgEESySutv7bNx46kammfTqplwPrPJ0Nqu410BkpH8zLjJjGh0xQrpQLNfCeDyrwCxjM+4oECCwCir4O1QeLj2kHYC8Jn4OqXM2AMhUKQQFD2iIESAQxDDuQSiLuLiMgmgCzNcstxASehTQaB/3/heHyIXggKbgaNk8rGnZHWzxGIFyf0S/Zb8XS0UdRrfuBGV+aE2lYCuWui4VjHPFA4vQLaCOK6hcuNhBVOchQBBmu6yFQzQzad1ljPJ/vItqxXMW66ArsxPVRi0S//D4l/WS2E1JlUpjHLLFfoRi8IMfum2vSaVWS0DuTQSH1E2NYF1ogvMqkZ64PuF86pTod3aOD3Zk9EpZtGkNY10wQAVhf3T66gx3b+gY/dix72lEAu6eUHjfigtrhrxwzWOMQBoKMk8GUMU/vZ6d3pzJVsD9AhXx0ZwOBWzJTgU5yN1L+Xc0YIoYGZMK0VAJU0roCfPgSU66a7IG5itgbX65hjeJ5ujqUVgnuYCG2AuLKy6nIFw4+VnF4XOMgggiL2q/c2def2J/XOl6r7eqfzLr67/EKx8a2nKz0u8YRmUYEpDw4RKAXM8RQVMckhRkzReRCt8Q72Z3YkyHkDwlqWPijwXZXa5b6TlPpk6SbgQ5YT8MGV24KJIC0VXvpLs2YDTcMVAQ6v8WhiryZq2hT9dloqAU/1cMYuJdEWDRsbdiOM8B8bXr2jnQN8nZNuAtuEUtyI74AToHjrRGQNtjXhhc1dy8QxCjRc7k9r3Da0bLdi2Hdu+4fNPfwKWKmm94xwDnz9/MmUrFH2zZ26920qOgW23TLi3pyd8XN/H9QHovpOLbkHDieGmNOVv7uZjQfltAPveMc6JoRP7bvEUr68H+mZa4/OcOA5LL/y03zxQHk5xKYFJMNvQGgPAHNg3S1lchbSpiuaPIlyDNGPomPUSKC6XSmkPdB0lxTZmoPEbAo+3U/S2QdSIsM4EEaFlp0ACYDI9uTMixDOu1XPASvWmxZ2caG0LAYauThQ2p7sKkWGZ5lFTsKVrFxBJMaane05Qx5WN/GWorJp/aJRjiJ1gXy2F0/k7E3PU3wb+EpTVjIAudaBAttJubVsCzLFpE1I01pHuYoKM04zEJgI01YjlJJM1FQJKzFx5xvdBixnK/aLxDDWzGXPnG2gBIjFCgi1fgxidlOLSQnhe96KDRklB3X5W4Y/xo/wbXG+CIc2+VSDF+bxafwEC9dTS6zIg+35qujypCx5zDrTe0fuG2+0prFvmlkecQasMd2AD9AyQAmlh5ZyaMa+9WNih6pZ+Arrc5xT2JpNpiKJJjz3Y1OazDROKmidSYbwJwU0bJxh2o5rgjAsYRe15j1gfz9O8Gronk9p6D/ezcIkTuDXOE470QhdiXyjOY+A4Hlk/i54ImrFzt9se9PA8T0hr2PcbIvMvQY0ru+bUBIZKOublAjy/5/S6VU0Ec9zCuj1PK5fAfa8FXC7WvqBhwOJ+1yjq+xzOicdx4PnlBd1T0Z/uArZtZnV51a+Wyr23APX2Xr7bLTjuimkFxIu75bASN+dxOvCVBO9vCq4njV0tdJVu1VPi39Nsxnv9i4QuVSljvM6OJUtEJO2RfGl5t0QGxCxTquVnBZ20nAVZ1izTMOFxscEbysGu75Wky1IannOaZ0xoqaydsXX8uf/iv8Rf/tf+RQgyOVEAebXOk6ZFMpQCKsU1JO5k6NbrFgqEtu+ASJYykMzOyzmwJE0zWIzRsIljPDAF2GSz93enrQAq3Y6+RZ9z3RlaMqGAnNF/SEPvpsDati0AtEjDKWKeSltHv93Qth2P2fAYA2CBdHMtwP0+LMav2/uPY+AcB277DbdtQ9OB19c7znFaIpOtY9MdT0837PuOzfugqvj8+TMglvxtjBOP44Hf/NlvYtu/WPkYlyFeXp4BCDrLP6hi/3C5/G6uD0D3nVx0zaKGNIPYnXh6EdE5J3rP9L8oKYW7B+9uW49it0ADnNGS6oZQr/ythStNiHSkhl1DUxf/VnPFFKhnvFO43gvqn1XGV5lfwoeVQToU8TGHMs8YauRYdyFGFMCa9p3CgTp4VGBJzU5gVSGSFMYeM1Owjsn/sgiGguWWBTQuYMIWzZiQaozuCqdi3pcXI0semKxpYw7/Hyz38iPlOIrAs0bzXTTSq8SUc3D5fBmzpCtlb6kUCLcq0M0S4BoxG2S4S5Y2y/Lkm124aU0y46tc+n5Z4OzfxSK1zFW14LAe4NofLf+jUsAeLSDN28qnuU4VTP+aq+6R+IgxbDk84Cos0hIpy3NhXVF1UGRCFvfvMmfv/wP5lnIeZX1PuGddzsjiOujSOf8XMSTdrDxN3U2yzXTBKwBxtaJeRGlVTFeANJ8bKm9UCHAQCgEtnc3YH7MOhpUsQItG2v1GSV6dlgmVEA4Y+4SOgRFJVbLfdDWlsDqRQChWMYCigskcIgtwyaZ6TSrC9a+Fu6Mw+JzhSv/WOsdU7TkPTPYzx8TAxBaJXdTLFeTM0zIXiXjoLVLqcdmPg7xZE6JwfdczXOlJBe4AMt4t2U7swerxcBmkgwUeINJyI6D5Vkk6/raJaDVOwRVXOj1eB1H+qexLKsCMNyhqFlduMf5rBaBvxwX210nSX/+zfxr/yF/5n20NXGEba0vgV/szNQ19qjmQZaCSMkKhdeRtRpMTHEYHo+8S4zI78IzkP+kiy8c0wJv4GXqzIIXhGlf3OXNFU3MeBFfimHKD/EbchVJcZvGkKbHfTFke53baOVCY8ugYJ45xmgsplWwN2G+W6GTb9zgzCqB7HdXZG+S0l5iL5Ynz6Qylzrbv5tJNuqnyEUP3HV0fgO47udK1yTVpUCMw4XJB7maAq4lA3Y9xulDD5AFWuqC7W5BgyoWRXF9+FfR0QmkNEgR4A7XkIQrbd4vQWQQXMjzxzzLvm99Nobz6TF46xBiId1NMF1B4BSLBHF0ICKEhCHoKp1XEKDJADiDavCIpMvEK5tb7Fbr8tl6VflKQv77u3YUqw17uvzLCIppc1uub7b1hptk/AqFg21JcJk1+t99AWN5YyHnJRCl0UX1vMHwfIGgRq9H6KgjWbGFi/nSxaARaq8tkXRMKxBR6BdLy/bNYIDhusy5mnFe0pZqGgjdzp8t6/3/svT+vLUuyJ/SLzKxa+5x7+/XrmUECPcHDwOIbIDTSaISDjTEWAg8T8DAQYIEDBp8AaSQE6I2DiYeBw4dAGpjBGWig+/Y5e6+qzAyM+Ju11r7dD+HM3Tvv3WevXasqKzMyMzJ+EZER3jfEvdm90KuBRaAlb+tDri2j+XLmJOho4C6AVu73lfY6ri4403LNAOEVYF3pmMGKCX6+FrTyWhq4MgqnROwL6E48iqJt75c4N5rhsQOqh9vFOldUCBvqXkmlolQ5P5etoGZdtjPCllbCaHtdqotF1uXifFcIsAHEpgPHiFoaEYfjngB2cOCqIq4+a8na7Rx2cEAGJtC2oLu1J7vomncFQT0lFISYlUjA5oCBZrPazTHcwigpDaZ7Vfh8oDSWSW43SxobfZaWB23zJxvr1S1zdeGU90ZNyzy7voA51bBeA3DJN3cZeL9KrkzzTjDUZX5dI3ZbVrQRJXflCz/JaxHpq+PLDTTFSsxzonP0085AyhoRvjYxQZNQmvAyUxDae9kGxn+tlF8UWkTiouhnX2Pek7bf3GjNu4CnpaMpzl/ds4cSUARw/Av/otTHvhKgztFKZxlEA22sXiG1FAyTRaachSNIdEs58wkJ/qICy23fBcCp5w8gwKzPgeO8435IKgJxjZTBadsmPET7X9TTYEK8U1oRhfrOu+wftaBuVfXqU6JljoLCcvYWBGz7Z2Lxj1I+Ad0HKa01vLy8yCJXobX3E6MWqKiMWSrmJGzbBq4QhqG4a9sqKqumHuLWs++bhJU+AWDoBnrZz0xwVG2Rbz6cRGLXYoXlggD3kzHBzzSTAJzB2w0E1bABDtLCRc2YPRzn2bs9Eate8HNL6eyE32zPpGuy2aZzZYh8Wq45LkApw7W7DgwMTCZA4X1LFLRrtFyLDY4vG+RDoctvrcKjYy6dSveaIKzfr6KRtVUAQhIf/DsLBEIqCZHdRwGPmdUlrRR1Q9J8hzUC75g1TdJqxPmKeg1+oS24WhAAaKh0KRYVL8Kzh+AZvxUkMyLYCWzeFRdOfOKkYvkQAaAloDiGWBuISCzdVXND1ogsy/Z+XSMSzbM4APR3GcbJwXCUrgIQatxLKmNMwlT3JTLLk9OKfJ1ZkAwAeobVzoUGrZkt2bMJ/Gt9JmQ/WuGKAsYKSyDObN8ZrQDWEPqRR8kk5QxswkrANUAfM6O5S+JE6QZOrT1rHfZMpp8BVu+Huhd6KoJk/ZtmCdD+gUTgM8GTiPB2v+P+dkfvA9u2YSsNLy83tBqubBLEKSxdPKa7Gi6ATrtaS8Egy/Wn00Jz4Q2QRNcjG6uxBI2Cus6OLnQ2pZG7Pc7ok89f/clAya5//fIFvcr65DnQz0OCnpjbZLP0C0A/DxAB29YAnpJzrkODvwyMyTiPA+dx4jwP9FN+3+9vGOchrqJzovpcTTxA+a2tyuCtaX7kFXsFF2Q2lwzE2PcedYoAwO5yDKQ6FlZgVrR0hWKNMDRurL5T0hnSU4VB2jnAJe+Bl93W9lUDVEhr2qCqNUn77sqf9Oqhltz725uMMSxYiYCPUsSa7IqXOcVqViwi7FTvlwDcPh4XfhmeLHAwZwBM+ERToEVu0aa2OWidzKBpkVjXtW3uwdu2qfVq4rf/0X+6DJRgxDxvZAbcbjvGKKijyz5RCsZxYvJA74w+OyYVvJ0TfUxQbbjdvuDoJ77df8LLyxec54nX11ccxx37bcevfvUrVVJIe3/88gWtNZz9BJWCH3/80ZVptVbs+46Xlxfc73fUWvHysmPfbtj2HVSAl5cd215lHc+Jfd/RtoLjqHh9lQTlX3/48jihPssvsnwCug9SigqwQKTlNa1rSVq+EGJ0YyiEyhoRigmAJJ71A8PM6t6km+AAXDtr0haA//nPXvxMS1wFVsYam5/swU9ACj/iE3cFtHrzRhc78HpN/7ZgKXmTf7Kfav1rgBFyUBUWMtsgA2vSBTRc9uB03x/728ck1SV9MDrYtk8O2Lyll3caCLXIY1mIWXucMQvZS3NNl7qvdVzvj3Eiex4WJEM303wwHpdIlQ4UsG7eXnN8MuHhCpgdEzEvwjCQhXITctY6KF0XOqYuq9BHZAhKLpoW290DLeBLAv6m9Ah3aDiYNWmHEuUWhQaHkJj76M9a43RNkY6lvxfrtQfghLxkDOwAY4SAaPes9WUAxQsNl36rIBpdCDrMizuhVhqfTaDkEJ5tvFZBP9qR+/lkKQYBEeAlZisv9S8pC2wtqIAbkrNYpYK3ijVu2zYUkkiSPFYebC6bdqbN/nbXL7BHZr2OvaQ9MJdJG5vE322sPA3AgLnvZdq78swIrffY+rMUC3NK7ji5JqBy9BNEYvuw3HHQ9tr9rGB2joFBhKnJw2HKxt7Re8fZT/97mHVPGYi5ql4tvQEg4GPyx0qM9cqxYrplPpoUlaRKvQWs5PkKZ3iUqBkJyHMLLi+PR73GQoFY1/mZ2peUPelmQy/xistastQzrrxTuhV6BM+REJwdDJriY6ERZE4Qk+an5JQ43RKJy15cV8pLnyyasCvSyAGetTGs3AHqGPBIvs9chUU5zWCO6LbyVlkjrVWhIU3MWVGntXdgsESoHCD0AfTJKAyc9cD9OPDtpz+gnzJfj/PA2SUGgeV0bLWBCmG/SfTY2kSZc7vdXGFmMQ5aqxijudxVW8W2VQCMthE2auhdIsZuWwHRBiLGeR6qQPzjc/+z/DLKJ6D7IIVII9UB6MyIfHETsygoSYDOhTAQUCra1sCTABTUOt26UViSkpdZ1O1irgKA7iJ/9c/8gH1vaC5kmJYxBPPs4hSHxRH3IW1PtlsDkUsNcc+KMVRbrpJowJxH+OHCONYX5o2WngHNjBcSoBRalqV/Dzu23/f4WZof7kvX73J1S8RKtxqy9yOR/fL4MzD3TnFQ/KyW90rMA8U4K+1dMEG4IBqIs+sZCCALaxfLReov0vc5AqB+0Kivz4HG2uUngG7p1UqSbE1jfY/8aFTVElroyAPGHj3QzjmxBngwRUEIhEaHEGjycBhUcfCVxygBmgBduFxLgMeWg/f2qhy49j7qi3cCEvyF03jEmpflaWBiBR+PLpep7nSvuF1lEHIRQJ3HkNfzbCllCobugmJMnUdFJNahQUoKqqwl1qAybO6NItAC8MAdJqw5cEOMvfUnXBFnXJ/mJikungvlyUD1hKWmEXE7JxY3XmnXRjqPlmmt70CiPftrnH4MsdSKYsesfFPdTQmwyJVzwCz5010rB5g1LcGAplTQhOKan6+fJ/p5oPfuKQxsjwnQnoIgpbY93Qsuf8d+8g5/tX2I1/niiggoAPD0BvnRpCiztXttzAOoe2ywcU7DZwu/W3gT3ink9PLXPn/VopzJxVz/rkqSYpbrEkoGOyqX93kYGAIDegZXFMl2Flci19r0Yw5eV6hoBCaNA0B6zIOjnRnQWdvGnBKsCAjeyow4d6lAkXkBgoBEuaStelvHYJRRfC31OTEYGAycU9J2TGbwAby9vuEPP/0B9/sBIsLEup73fRPgpvEIiICNt6eAzkDcvjene61FvQ8Gto2wbQXHYWmnLFUI434vusYmPsvHKJ+A7oMUInWfSppfibYIF4RFYBjKYIWzynOSk2YygWmgnXr2qBZUTEwuqCpAdJNwyStWQJI3i0fLyNpYuK98uHDZl1k81Sskm+d1p6b82duVgEWW0dgsTeSadhekL/Vx6iNd/pa22gYaf4fon8+WxNhc6fHcYpdBcu5ushzqWHq70j0LjSLngY2S0t2sjVkkj5J1vrz8db1zbZ/Rc6lId28bCzuzEJEtQxDJlrlMQ2AFaUYrO0/xEOwktVzAfaJlEpZM8xwC4sVi5f9kgoTiwGq1kOvulueunmUhl2z2KtDrtWozMIX0dwtgGiAGItgFXc7b6KS4giITZgzgmWAWjz4Xg98TGm1++tlBJegVEBKtefgk9P6jMGrfV3dJjOusZ1+Qgc+Yazj9JOBlIc+sSjZcz0uANlwFZRvf7HI5UmASQgIkPYGOgpfbzd13S7bsJWHPokniAdQiRZuUsSzWsNQRoXdY9cx919woeU5x67xcy22JZxWoMqW1qmAP1ec5WxRfyPkqC8e+laaAbmJOcavkOTAtx9wpqRuO+x2dgPM8cb/fwXPguL/hOO8K6E4J756CuFix6LSrgmJBVeu8Wp6/8qvVcuXnJQlP1gX7vDVrZpnlAUFmIBWA7meUX77dPN7BT797VOXkq84z6fHuS+0+6zkDeRL36NqaryWPvksKxBRQm/pgGNJSRRMzA2WCuLg3kKVQMv4UChde5q11y9YcFQFPg9nzzrkVMYFNEMX5QlUwWPnn/51/G0SEf/Jf/XduUayzJipqULZaYcqNWidKVXjOA7MPSVPAAGjTHLy8zteDsd9u+PLyBVQIt5tEq23bhtvtReSnViF41fhVU5CX9jzIebzwjhA35VKArRbsDcAsABNKJbQG1FLxtld12Y6+f5ZfdvkEdB+mkAO60TsGkiCsn2XzXsGTeDkUtK0KoANcQ1QLgbmgVkabktuN+lwFIC1/8Xai9Yl/0urlmxDu7LB7uJM5QnmqgfQNPGmO7boJ4rI5hTD6XIgLyZwo6rtuzn7NwVxs7qvMR/5c1vyu784AbW1bFkwyoI3nM5AKYcEASDbMcSbMQk/ArCZ+jXPNz0WOqJPxRz05klAfhdPvEJwJ4T5l0SqL0tiEkkzX/JwDCQ4BihIofBB8Expjo52Oe05C7QoAA5be/6DjtWf5/QxgdrOECBCrVCUEfokcSdmdbl7WQAAvgmuubXLbezOQwbquQ6mS508AK+b3NfzX+biQMNHQFSHp/tXSuQqdKzgOUJmpGEDI3LTjnjFNEcEanGBGtLgZro/m4h2WBcKcayfdMpZoyJyFZ/tXfvL4WoCpAFly75wDx3niPCXtQNGzkrfbCyRRuFpgPbcaL1Ed4QA2wBzAfl9YNX32w2YlaQeyQCx9DKCmVxyIZetFBoI2J0OZFPXTophStzlAz9DJHrO1IoCOBcRNsJyRG6cE2qiEfp64v72CIMLw/TgwR8f97Q3ncXdgPBJtsqXKUi5ky7nPQfzpxZ+m4KVG1/Wu63rgNHMTf7H5YxFZ855g90QlaqUzbnRpfLr3AehlnnD9AundMOD57K7rFWDUiuN2w7/+X//3+B/+rX8DrYWFyHgbAx64w9bCUPBuQM7XxWSANGIqX9ecWHULadogLnoUIisqAqxNAHxOT5WU99js3WEyzpyS6oKXPoaFrhIw9TiK8FmNWKmAjnmiVs17p+tmjK5WeACtoZCAzH52sTRPOVf38vIFP3z9KmfeqqyN1jbsaomrtaBUiVtQqwQy2fZd90D2KK+3/SZKkNnljGoHbrcNtQK3BvAkTCaUArRGGLXgtjeR9fonoPso5RPQfZDCPN28L4fjRctTK6FUiFDFE6boLwrW7KB5rVUOcLMcMN63DdveUMYEugRpH6yWrZKibSlj/vf+99+BiPAf/ssvq/YNIbQySWAVcY+LTSi7zYn2bT3nl5n4s7/X77CEE8+bXX7OxLdlAyVEYA/9267FebVwhQLg/v+lECQeDaPWZLlQ0CDtsHM2lipibVsW5kSAW6ROb4e3xwRstn/sXlIhQLTMQqNHoYDsiwVI6hfq3vlE3Em0St+RzjHpkGtOwRLquZSiQU+EVjW7URGWROJZdHMtur8nzt9lS1DvPYRx1eq7m00SuEwQsXkYQoKFFND2w8aB7P9FYFJZI6wuwGIxAlLYeAUFnjTagWi4CwI2pjZmCXwoYPShUSFGDDHkAr0NTFiHsoAagC6fW8tCktXrABoBKuSzXTPhy6LgDQcgBiTzuTYHLHOmuiSwy7ZRmvPS3zFPB2+Zbm5joPU8zdAku30MAB29W864qXznEQzzZMlkT2EZcAuC0Z0BHkNy1RFhjIm3+yt4isXh5eWG1hpaLbjddtxebgATXser5FKrkUpGcnHBzxPluWtz2nCVCcJyxhQiLCt9i+XodIFYAZDOEzlTIx2YmrybR8dkiJDaB/g2VKjVyJNFlSuVNKXNBEFcRkcn3AGMfgIseeGO847jONAqY5wH+nnH7HcQgPM88P37d/R+4vu3guN4w//129+K22UfGP1UAfyuOejCKmnrvxA0IJK5l1lAJHPZC3BtMMuBrn3jCgmKuxTMgQLQCp2xKJYyb75CrKxMIeOTup3F3kKpje8XV/hkfMcWdCnAULV3oQQPt7Q0xXgWnBa5buvPWmTd/2//0l/iL/7hP/ZgKKbEYJ2DFuCJiCJljDJs47UwpU1rKKWiUI21NOWUKjNQRmw1zAJOaDJAA8QNxFM6k/f0a6svSi1r4xgDfQy3qs/JoCJroRIACj5vNAUxSrWdpmJywwRjv204x0DpkMAvAPatYts3lLaBUfCrwdhuN/z+p5+wtaoB6W4AEd7e3pQ/Nuz75tFhv3y5odaK+/2ueehENO/9xP14w5evO+acOA4DeSdK2UWeA1AasCltWhWl+48/3iCxscYfnWuf5ZdRPgHdBylTzwrFWSS5ngUHwJiiHXC38OSy8UNdLUol1CYbOmigTEnqbQfjwb6FQitd2vKoKTTXAtN8kz/Gk91qQrQKkABcyLqCt9VCsN6b/74Wv0aQXd8tWOSa24yjCBk8iY3MwSwsgIKMMtToAAAgAElEQVT3HBfVbLLqAJFHKPprm6dbfTjqeNCu0qX6d8uF+km+WPAbpd/v1PvwVaINX+gUiAkhESsA9tw+xVwugy4eMCVdQ/o798PmSN7wnWZ5bjwEyzDKBGh1N5+r0KaCoztsqsRlAoxp7c3V2M7vlQUUBBB1cATyUN3l2rlULAm26fSz+Op9hgQUyag6hLeYOfyOYBngy1IAaK0Krviyxle3yBiDx3pzS2P2RDPy36tgbs9ny9YyXqBcxdI/U6qIhS4DxOfWTRMs8yJYQa1GZVSa2Pw1t0uJNtdiEYCi3WMIX0PwY6R1Tf7fZT5T5iVY5qwJ0O7K+0B6U0KIlcSompU1rGfq8nz01qe1NzRpsSlTmCd6P9XFbeI8Dxz3V+yt4Dzv6McdZv3rGq2ynyeAifN+SCTFEWfkzAKyplpIa1/bVmx92rrTieNeGUYfVRrFyK68M2BdumDfJ97tChy38KwUXue7vSdFQM6/bL9F/ur5gk9vjMBXnM89X3gYA+5OPxmcz/apAolzrzPP9ipJtJ/WL+OZJC7dRgtfD10Scw9TdgGABX4qBXXbEJFtpb6J2POX4EWEpS+G5XwvLAVta658zvu/RePN14nkfJtZwFkrNKsdVXYLsFiaGeS9UMBaK7ZtYtua/HTJKkcT2FpVBfcNddsxQRFxu1Sc/UQ7G24vL3h5ieBw5mIJ5dVE0xVhVkqt2Lddh0MSnXs7i3grHF3GQj2pJegdE9q24YUZ2/4p5n+U8jnSH6QEc4sN0IQAF9h4wgweknPOnp1+tg4Q7WjTA71TNcUiYV4BC+Aisu6gITxdQYVJDGljdCHHIqsRPMBXAjgZzOXvnlnoruUZ6PvZsu566XKIBwvIMUGTXKR6t2KyCGOUHtaYpM/btWzLf1J5XzF8fT95zYsck5smTQBdr+ln1wJffvK5HoKklFjA3DXIQf6hEDRNJPJx1h8XkkkbnaxXBhCzMJgFuxDmsrCYv8+ABov2PN4ZQIFSW66ATuigjlYJhGYgaXMmy2MeXMWFVhPMYl2DEe+wu11QWHr8UGz8jTeEgJTAsd9n7bq8S58N0ZlTveuzz3iGvS+3yYRID4Ci72SbA8yewsP6nvMKBv3T+BnDQxIMmXEJB5LGMSJWjhFunnIWRlBDKQWbBj44T7F6kXbIhUp1ZYzorkEGShPeFVnuorsuMlcM6L1+nuzCFez9q+tl9Nu/m5qXLi1sWVOKBSCWvDoKwA0WPKWfpwvC/TzkDNzW0I9Dou11iWDZzxPHcUc/JALfcdxx3N/cMjc9Nx4vbXcLmm0T3t+kvMkgnRKvSVwy1jg7/dapyAmDk9/rd7PNB7Fw+zxO4xXKjgB1ACJoFdHDOx/QYS7Oj4OnZqD47NE8v5nx/vsuz0qXpd9XK5jxJfvO6rcAQICmDiqAWL2KB1Np2ybWOSqqiAHGDPkjvGMif6TjUl3nU+dpIT3TPyKQlCkYrgoaB3TJfZiFiXqeNuKyuDObzGGEM97RWsO+NZytobcu7qEkaXa21vBy23H78gOoFEwWcHk/u0RoHbu7rWZX8FarKlFE9opclEKDSgVF88gREbatuRsmkQC6eTJaK2iV1LtCetC2Ciph7fssv/zyOdIfpbimGgg5MFu+VGAz8AQCCmEO2ejHGChVmD1p/q/aKooCvRAen4O6EOysrDtJdkfxTYtWDXwGCfm5Z1aG96xv7wG2DAz/WoVw0ZbmSuOeh2vrxySwxt/x8GPdf732Xml/fW8WUMIV7/+PcpF3HKSbEGlzbwVs+e8MABI40Em80CABeRcJbMPPAG6559LWrATwdsSdnOslpMjgkbjWhQoV7pEFFYKDEAdd9r503sbqcjxK0YI4J7aK7U5j8tiKvjauqTNcoGXGs2lkNAqNMS0WE6kz9zeo42NqMuND/SGI2pwPJULqJ1/XhLZjhiCXAbgDb72+ALr0fOZRVyULu7CbFAE2zxIYXAAdxIvABDYqkqPLhMw+OjaeiYc90tmuP6721ToVtOT0ix1/Oe9OdM7g7CrwGi3MgsZu/Y0AKHGuDnp+Z8qZoaZndMaJ8xArGBHjPO64399w2zcBc5pHrg9xqRSQd3p+uTmHnIF0l/I18mGAGY7d4bJ3LTRRQOLj+oBo7O7ktm6PJ5wj1ih7nOOpy7y0fckAdd4Ls7WTaW0/AE+b825ZcFfwJgZjFrVxJZ5mMygAnZ5bM375zgtM0WF9XNkqLZ8NeMWcmG6RErwr57+Mf9TWsDUJCAIiELOcgzX38lpAGmStkHkESF8mgKJgjhBKsn3b0ctcgFoGmfa3p0qytWq8inix0GUwSGAUskGWOAIFBKaK1ja0raP1hsYTPBitAq1a8nFCaRU//PAVDODb91d8f33FtjX88MMPuN1uOI4TI6UxAZP/fbsJeDPX61qA2grOc8hRhBo8mQiaC3So+6Uo5vsQl+lNI5Hvn4nFP0z5BHQfpGR9Z6FVCySbAjwnmV5S8GebwxRBX12XahOh5SSRasXd0gR0vrxXhdZFg/YMNCSpBk/AG+I7b6dvmE9qu6Ikf9SE4UtdCBCxvpfAl79deIXSLclO9rVrzy91cn4WjNiIKVWAh001WyX/2iVpZXNT137q2739l3uuQsg7zbgqfx9kdUTfbe6Z0Ozuli4kBWX8cxKM87uIIFYSksYRwvXFQ9dfzlc+9M3/vKASo6EJMdZ/65zfGme+GHYuM8CeVBMgImGSBczR5b1KKf1zrvPxGSJLGvqguVkD493vg60sOAQIChfG6+uyS9oTsfHZAr288/GZaGcu0zwJEh1JQazkU46+Z8BlACDajMBFHPUYgs5QQm5aAZGdZQIkqpxHAUzn95hVcNQokD5dKH5nzrCAFRP/M1uM6R3Ppo7YmjG+GziE1x9kSx1b50KIRdSdgZ65V5ZC6L1pwBLpXyFGAXAedwV1m3w+D7HKaVoCC9RwnAf6eaTonZE+AUwPcyb/6UvTbzJLWwCv4DLxOUGTBcg/K6FkYNscve60TcIInpUKclvsP362OYHLXGO0Kubaw7Kg9A4GCoe1LPaQ9HqFrGKx5GUfW2kZ+41Y5/TlWueVXxpPm8zgIbzIAj+BAExEICoiUKmotWmESqi7MQPowe+K8b3i7Qz3Z/a/p7at1Q1EU6MIP/FiSfvlVXln+7KdWyU9m5e9hwyUFxlYzccrShtxuWzoY4Ix1aNEyCVBSSp+bJucOyxyfntvFS8vN3z58hXM3zHGHXaumUju4QmJcLIoIgTE9a5BtaooDGiKvMU80PuJOSvAza/xnKAqAcY+Ad3HKZ+A7oMUIgkOUEvFy8uLBgfpuN/vcji37QiocY2mBrx8eZGcLhOgVsEgtK2ifzvBPLHfdjAK3o6u0SpZN5vibkVAErJc4Iz2pb0ZoOQ6x6zJb9UqYNrPcKL3+0TYNUZY0Kd+70JKElZSA+yaJEuPaIOm4RvKvAGKM352LlE6gMmMMQf2srtP/pgDAKO1htEHOvfYOCiEUpH3I0CEtciATtAoQF3eiP/I6PtGXpIQRMmywokOLmSwaYDtm2V4kkC0CjK2r18P85tLboAv0Wi6ZtNBWiQVfwback669UyoWsL8bhUs0o/Vbxu+XQtS0fJ7taYh5kuqw4CYhc4Pqid3ogTo5jDhmL0OZsbERIFEeDMhx9qARG/yNbCOh33mOVXwW60B5qppYy5dqE8wK6s2uPocC8AW9xmPmLbejS6wwCojfR+tNatBntthIYLXQ1QRIf3h39MzYTwJuzTJ8/zVWtVFs2HUiVJ6qj9FzvNojgH+meHgzKx9Y4wIj65R8EjdscDA/Tiw77u4XQ3LH2fjLT+SVyvmuls7oIJjkQTE55KvkINfOAgL9/mp5858DNiEbLF22WcTVnvv6OepybxXt9QIoS4NnmNgnF14Mgizd0kz0KrmiDtRi+Tjg56hG73j7e0V510CpBx6rZBE9avTImAKv5aw9zYXdMpmxG2wjDks2TGZF+C7zrVseYm5AgAFxZ8NFifgjZHfvZaYo2rj0wUornxY5mae3xPT87XmdQ/mZZ1amZqMWyuS+ZJyU8bZ7TUass1hJ8hSLy/32/cWwMj5UqJVSWk/bB1Inu8iNJym4NOIrWOCJvS8akEpHXOb3kcfD9VI5LkH6NnUATAKqDC2bfOWw6LB8vTUSXL5yjsyX2FXtJRS8H/8vX8TBPJgVcSMtjV/v83LvI8Y7Ygk8FBrDfvOoD4AHjjPO0ot4HlDLYSXlxds+waGns8D4fv37wpKJ9pWcRwHtl2OroAnzt7x7Q8Df/brX3meuX4wRp/44esGgDCmuLiOMfDD1w08q+apZBznidu+oZUq5/gEBaOmveez/LLLJ6D7IEU0qgNlI+y3HaAdfcj5Bot+WWsRN8s5EP7kwhxvtw04WBJsqlvE7dZEI1ULtr2BqOD72z1CiLMdLg6mmKO5AY+ColybSWCWDdIErmKn2w0gKNNS9h3R7srVCgffCMk37hXcmca7EGFCNghj8rZhmBAqe/f0h6kQMGKjYgjjJnVJrRq63DWKLMFlVAGomkqAZmqsXXfLZ87bFd9HCXqRU15/MzQFRQBFZnVfC8JDRSPXUAZQApbNLZl3BLxlSAG/rm8LwIwYBxMkmkb1q/65JCtdjE1OQ2DuJWtQn1AKGL2y1vzqcvlzSNjciILGGfjZ8whBUKdirjuElEy36L/fp4AiGmqWyTgj9XAuxEFNPJMBp4y5rGcCHgKkeD0U/XM6u4UwXJTs9XFgfw3QI+Ao+uDnXjQQiDUt3KEkwqTdG5E11/aMIcqUJWgBiRLFQxeQuc6xz3kAHk3UCD/mwHnGObos+FkwBZvzBqalXxVjasRHAG3b5cyc0qjVhm3fcJ4nzvMU4RFI58FCrjb+YgEnPOy+kpKI0GrFMIuyrR2bq26NMKsGOWDrGpiC9YyhWNKKf+fnjJSOwxJ+axRSi2w558DUvG9jnGBGRORkTTvAAwTGcRzoxx2DIOCwdw16cgcPSTnQR4RypzLRaAOqKW1SMC2sLsDh4cC6ZmS+CyiMyKO2Bo0b+fNX5WGsFr3TZzJ8tbkfNfyZ9QlrH8Pz0OldDsDSPnNRFwVfvdadeFFe82x5IoljAl2aFO6d1v/E94wGah2Lt8q+YmycrQ1GL4p7rc2+Pou0f68NqLKP0ZxizQKhzymrsBQwSVLvc3TQ9NEGs+yJcBfL5MnA0UZ5foIUfIEK0CVyZUuWcJnjAzELYs1QKbjtu+/lr3/nXxOls64DMPt6NgULGKBZJW+hKngnS8CUViQIiljMOo4+MfuBfhbMcYDwgq8vO5gCBH9/fcPb63f0cXpwmO/nAdDA1y8vOM47zuPw6MTbtnmQoDkHtvbnAAin9n3OgZdbQ6HigVLubwNbbRopuqiSZ6J9AroPUz4B3YcpstGbllZARgWfQNauS3h9C3MbjFW+Tz8Fqqmq4g+vm6wc6iWVO0K7+l/8sz+mcOmxOdhrmNMrKf22zfaKzJAE3rWba9uvO2cW9O37tE+GQLi6mTxzdXzm6pbbtGzmHN+Td/oJoMh1etvz+YY/vbglD/aqDHq0pUl+Yb++9i+onbpDJJvdcs+V1MsTy3UTigoCpBUyMGfCkNExnskWuRD7rd6YK/6dARafuybwwEHpQlqjF9u5DYCKWrGSgmB9BmASRQe8faTCSgAZkdN0fmkodFtQbmX0dyQwp+0ysdP649S8glO+iq7SSL4EUQjrbKxrgBy0ZcvaagW1UbH7DWcQ0pTwORu/Q/DM51ny57zOBeiFUBPnTooLn5TWkNBrCsBL42CpQxYwfxFWFyu40TTRkZRwpuWX6H1Kj0uk4LAsXdtAamGRtRMUjPnpE8rfnNz7EkszsJB7D52zOZ2D/RjYzXUn3JzoLUna3cMgKeAK4Am+JwtgHP3EHOKFMPTvMSRgBPT8NQES1t7fL4BB0pUEjdgsiJxml8+1lZ4l0/uhXOgXlxZQFwovYAlysm57MPAjQ5v3hMsrH5oT69TH+LLm050AJTBnyonFzSHetfCGNEeiZxaQCM7PLsE2072c6HPZaHR9jjl8thVbGwSQW4lNWSfMYOrnrDARXquACaSATvmk5XYohIKyRNIUPjRgmHbWiSxHPJsHtlcbiGuaGH1q0J9p+4LRPdUlclAFuIAxwVNlJ/WsIBKvklkLmCv6YMmxyKypNrrKVwX71nC7bei945yHpnCR4yunBghqlTxo0Hl2fP/+im07Yz3Ojm/f766QsXNzx3HClE+m9OpjojXbd5RGD9T5LL/U8gnoPkgxLZYlLxbtUsGJYI61FE1u2VPUKdu4BARafi+ewrC2rUmoYi6acLwo4xmLwPiPdhWEpuZ+YoT20DZ5u/8CBZzvegQKftw7YQKOCVUiAC0WmnxXuiYHnuGyRrwzC2b5WhKjXHgLV0K3GNoG7g2KR9l7ateeAVMD2vk9KzB5LOwgYqFMyBH+t9vvstDx0IanEMYFXGsQX2+h6LK3Of/W/wrlKJclIlA6yox2m/DnTpWJBgRcPsOF5IVeixALB0qJUmBABePpDV7cNJ8IPwS4ayWll5tLGZsrFgNUNRqhujmx9SWBM8oVx9IQmcdC07vgqQKxd8krfTJPVinUFC/ZWmdh7VeApaNGhFzdNZfd9R1mXU7k9neHdT7WUFgDxWpneaQMzDEzaisrTbTP01yEL/PDIz+mgAvBm9Z7yUAbKQ+DWLDZh9Tmw4WW2o6S3lNrnK0rmmMRLO6FU8c46jPGkFBbUArXFz2CXzg9J2eBN3laOAeUdlZdSw5i1BrBaqGbkxWsQa4xaxAUce0UAfRE1xx0vZ8Y6sYJnqLoUx4necokr5a7GdrYwFVoPyN8xvy081YWCfehZBZNuVZO/9r7TIFjdFgI+4SPpxZdLzGStXhpedSRWBDliryyhDyfgkSkPdP+pnSzXZ/LwzYH0uSN32lNGmBJtSsYm7FvckHJ87SQeAMAzs98L+dwVSYqgM6DWiv2fVdei8V7Qvhb9SlpSgpicfUsKsM8VQ5nulNEtjWrFTPjV//T/wgG8NO/+nfkHddtj0TGmaUCA2CIy7dFkCSoSzJXcAVKGSiDfA30fqKQRJ683Rq+9BvGnDjmwITVM8Es6+deZJ8YQ87Dff/+zfP+Cf0Hvv3hG9qmXj6j4zwP1CoBT7Ztw3kOnOeBbbuDaBdFu/PMp+T5LL/A8gnoPkghSkmO9VyFuQYJ452gIv7c53moAF2TEKzpCUy4ZmhuloYxJ/rEYqFjDm19ZrwrAybXADIngPNQ0hZsYIXS9mWuILhslOmziTISwSptdCZEJ8Ew32+0e2qNU4abzyPIZmh15PckwGeCw/I9QM/6fxHagg4JTOT+PGPeiwCaLS2mlU5CxPOXr19faOGiCCFFfcw3XICPCbMQz7NCcKHbXS0pKsygzM/Z5X8zCEpC3iKkL+DPZj0eAF3ubBb8cgRKBjBFelvfWyLEv9FIjSPIgUxM0Ch67ogn+/W1P0nghM2hsPa4DJeTngNypiLXkwS3LKi55dCpoXQxABASZxoD+H0PIF/BXlji4/oDefn5XJVrdjZPXIaMZ5nGvpYab9c6xhzi0rXK7gnUWbJ5Exx9wceaX0AdhaT30JcIwGL0couAnxkO4bT6uTThi8UEZp+PML3BE3qEi956TbT8bHxBhfzV4hmBRla8kPuLNIxhFbUInnMOgM1VPgCc9bf3jvM8gdk1Mfmp77RUNxaMSIT+fgbI9DVdCDxt7kU/H6eNrcHi/OJni/GjZXU4ERME0vnA9tLEvw0DvfcK++6dGx7BHD3r2Nq0JxzJ59v1q7wIHOzHYAsbTbug9yfasYBDJJ5m1ziOPBBoDW5mVVpdGejF8vGojYWhyo6K/baLS/WcgFrtBCxVde/Vc+nnwCSRWQrJMQHW1B+c0hU8K+FGHT36m//t3wcY+Pa3/y6g+/X1aVPscHaF9/kXa7swqwJHBkes1AcIE60RdjR84RcMZtz7iXMIGB2TUVmURr2fC3h7e+ueJkHktoFv37/hdrtpKpQDb29vYB74+vUHEFUcx4n7/Y6mRzuIivDOMc1L+7N8gPIJ6D5IMfc7A3VFUw9QYuoC8gru96laZWWyJBYsCUiisEjD6W77hj4n5tFFaKnhv22FGfh7v30FiPBXf+srSuHlvY/nHBLgQ3KFWXskG08WyE14zRpWWrW+zqhNS6zPWUOz28WVfqHZj7KebZJ/rgLitQ4HFLmykBivvUz3GiBTKj3Zw2ycDfhm97IsoF+esrcs1/54HLi81a2KXvmCQxChaB+RWOUM3FkIZpMBHKpRAIuw3FES1hONM7DKfye6rC2NgATP+ujUVmHU3Sm1CuuTCUYPc0blQ/bzF+xCnVnnSimYQwSBDL5c0CasKTH0nS7MOrEC0PFiYYj6slY/rFOXPieAYgJLViIsUtqybvN8N54iOZps7drayc/EWiswECdCjfEpO8ubwVbxs3EmyzoPMbe4JyKaPRuJ0pMQmOqPyJ5FtFZY+YcYsaZY2AzRTfJzwz4usPNxJaxJ1ldDcJmsXv8TYX7aeUN25cAcQ2g6bQ4nhLw02P4xmlti8Sv4CwBotGeGJEFnVhBnESwPHRu1oKq7mJ3HA4z/aDRDnevGXwOgs8/nSZZbMTc//xXr+9HdMt+jPANprS7EXInjXgp+9g1p8dvY0GM9/kYDNQmw2SMLeErf6RpNbPHSj9T91G6m7NFyvfFh0B9qh/FLpH3S9iPnZ6aQQXx/AWtT5+MYw13mbd7z0mfzWEiRhW2N1Ya2bUCZwJieDDt4lq6TYXMUuh6l95Y3jnJuuWfjo+9kjhyQRotaq68MW79zTrXOMyTokP1UWCqGBdRRKCFlXWrUV0zUAuxbA2sqi3s/UXt3QDdGxThl7Qh4Ezrd73eVvfQ8Pk+8vb2BSKJsHseJ19dXHMcdgPDDt7c73l5fQVSwbTsKNZxHeDd8lo9RPgHdBymq+9fD8t0Tg1vuJCAi203uoNLEtUm3xgFN/MzibsnM2LeKr19fwGD0MVCnJBx3Ad1/CP/KH04AwF/9ra8ANNIbmYDE4GL5omRzsRQKzB4/QAT7IpGeTMgX8cGEYmgYR/hmTHp2w4RFKgWVaQmzbBsYM4PniOh+HFtigNT0LsTmZpp7KtIfkLlfKQ2g0bG4gSdr9Estru0kF4R81LSCOabTMiQNTj/W6QxeVqHVaGiiBKf+PQgJJpDY86sHj8s53oX0jqUt3g5rNYW7F1kgFAEkxYR80EUINoE7nTvSa/kMjtMmt9NMQX4wnJNlgx14IdcLqFtXTRaWdLCco/8EBWdJ6LHzd6wRyZweBR550SMl6r0GNCy1grnuufim9Y450XiCqHq9ZtnLAHXyBDiEDxFWwooDyLzPggRpp5inuAhaDicHXzGWIZgH3XLS3DEiaIpd125I9LYuZ0lqtaAxK1i0e2Psa6Jd9N3pTTOGPS0JB2k1+F1rDb1HgCa3qOc5BKSACwJ2pgIpBoM0sa/d58IuT4lm2zuokQdG8bD87uIu/YfOQdJ2iEUs5qUFMKkazY8hbo/neQBUAhgtK5ijjqTEG7174AWxtB04jw3H9gYwIqhLsZDqhPv9FWNMDY0+cVfBceiZRpsAdv4NYNQUrEWEYIZFrQWx55xzmouJXiysZHzNOAf5v2YBJwfdIey7Ash4ZAYW1j6bE1k/YkojGG+Z/knuV+DOV3dQjjqU+kVDl4biLsBcnmcSn0j5vS6e9TxyPJPVUjxlnl+Bo7XT1qYVAiLSsAE3+8LezeptoJ+NB5g1G0r3XO/UfZL7iTonaCg/qwWlbbjtN+EpiDPFlqiAQZp0W3iZrU2z1Lk1EBY8hbV9Np+ExnMO9KF1XvdL+4uCLzuANl6JSDsydD/29c9VUy8AQEUhk2uE79AYAEsOu8EThSQP3ZgaHOX+hnGeADP2veL2UrDfvgCNcD+7u26CCH/43U843u643W4CDsF4+/5NzskpT5088dO37+j3ExiM+9sd3799FyXLYGAA379/w+vbG877REXFOCfu9zt4Mu7f7/gsH6N8AroPVCzYwZgTZar7jyaffF6Sq8Jkd/VyIKRn6AQUiqaqFgmSEKBON0Tb1K6KNF6FzLyZh6gdFgzbYDOuyRYxqTLpeGl9p2/2rPrZiyAuerlMAdv/HmlkVocAWnCgkLWWGWh5ZDqNMBl04WWzyR2wmpHqM/HiSs+rtvJRexkiyFKeKIcfBBg/bKd18OUBl8VWWrmIbCDMtJvZBc7fAcdkYTWJevL8yPc8WlXfm9MxP/ysmT8Sm78AzxJpD1ZKBIClaI3NY1MWGBAwIWTJ/+ivCvfLxcJF79lHk6tkwq4O+mCKiRXIwwTeBMBEcMtWKwNccaZOq/XfBupCeDRhK4OhbPXJwpY8P929Llv4QkkSicwL5rT0BpFi4GlJAnC2toWrV1FAKD9zSuCmDJYX1zISkOFCpgOzoQA8+gQCaFgj4syQpR+wICXhhpppl8ZYx5XjD5lTcwIpYKe1E5z4Zq7Xeer6M3m6a+ocw4OfjCFulRF8pqN04W3neWL04cDyPA/JJ+dpEAJcGHCwgTQQmsfIrIqZJ/Hld+IYiEWWLayJ+S/7hbXlCX96fMlTDiGCtgG4Z+vvsaVp8q0ATP/NVna1Bz5WqYtvASSp3pgTWgeF8vO9tjGu7WFlAYm7X/ZHa4quJP3b6ljbY9GayeYtQfKjFX23uYaTKUxtf5zu1iuJsiss6q0oNRiS/0HyiIY1LCx9ea1aG0PRE+vaACWVlGtOaS2RXjXaqyrVPBIsm9UbsFPbEsSnokxVwCVeYYrKodbtPk700VFYzu+1JvngJGonRPYqBefbHeCJ276JZXBObK15ehQiCRIjypgTx/2Q84iQqOXnXVwtz7Nj9IHzOHF/O1HLgfOUFEnn2R/n22f5RZZPQPdBCiNyuM0xMYswlQqEAH0AACAASURBVFYrrjLSc3cWiy4nDJxYozjtG7bjEABnWrpaQCMLVsBTEIEAQK5RJt14kJ+R3yLAeyuXdv6sywXwwPzfu881x5fW5o3kGZ0oaZZNw2gbvIGZggIu7C5GSXQTQGebjfntO34jB5ousFB2uVz7bu18D8w9CuY/T7v3vn+4H/DzGj5WmV7+E2DOLWyXd9jzxYQka2/Cte9DtoeO+McAJyYwZwHqAhBLzDFOD7tQDoVxetaPZ7gChSBt/aDkuqltgAUnqi4UBIC37rL3295twsbTCHh6UwiT0n8JjV89YEYGcxkoiaBEmWSLwOdL1QFJCIAZzK2gLt+zzj0Bj9Ovm7BuPMkCtGRrbOBw9v+sgjx2hVUAVI8C6Wd1ACvtiSTlC5gDJLrdDLcns9KVMh2URiL7iMAqkSIHZlMw5xa6KxBe6chI7ohpbc5lbQRoX4R3DqD/7MenkbmzumvldAHR/54D1MUyKYCuu+uluVeKJV1p7mBdFU061h5V0Psi839Q8k5AtDkX162wnSNd5ys9YQAZvMSkSwtH70oPJNiyPrrwVIYCqCfFtCAPlcA3kWWO2mXleWzPp6quwBAcFbLSl5geArC8x6YdGrPxLAFLz/miOTM8VuZ7IIVlTFI1aB8HAAydD5I70SyqU4Gkgb4xxGJMVCE4TNoymEGuaZFr7r1Qilt+XamBWNumlHpWaq0oakm3PVSiQnb0MZagLNJ7CRgV08z6VKVfc6JSwSQ7EyuBjgBReJ/ngbMfqKOgtqLeEAWDqwO6WituLzcQgNu2y94AYN939N7dk8PWxhgDx3F4f8BA7wPH/RCPhwn0c+D+doiMoXLEeazr7bP8cssnoPswhVFKBfOQRLEDGGPqOTq9QwWCDIJMWz5ZAYVttCSAjkpB2zYNiMKrO5kyycnGQh8BQgghWu+lzb4zvsepL+UK1jKoyX3LoMc+rxaDokIzP333u6AwCSchpGu/TMhU96IMUmyTfKj10nUTjFeh43lb/lQgFuV5fQRyF1j5O5nMHO8zcphqByEUt5r1pJSwfkWKAn1Tml9WE10+WF1r3db+B2JJM9+1CLDVtgK6cjmrw7w8Y4KXz5cpXqkx16Dg00CGhbp3NKfCmYK8LJg5PYP+pGkOKDWeaQ3bby9ewKcCxFI0D9Vcz3g+g8ZJxnwQblde8bg0Alg8AsGIUrveH+OWgWTQzd7rESqBbGxUofwC5iDurO72ydMtdDmCr0UfzQof4ws1CXmirWcB7iyAk4iUnpYYfBU2DczlNALC0gLwZ+Ab9IhxlO+uZ2BWC5/zrhnnNc0KloHfg9UODHPZ9O8sbQG6C92jD3CJwSwaMMYCBRlwMgWMBQDatiaAcBhwFy8PzAAX0ceVb8ZEMD5iCsOUL+w6d/2jrQH/J3EGTkAu4NDCt7wa6ZcFkfQ9Ks9RxCIw4Glr8wkm8jXv+8rCV9Zy3WNy/Vc2d6nOx8VoaVuN02btARaedtmnxTVRc4MWgqUqcGuyLnaejM4dYFH+lhpWL1ABp7yTzOpyqYGPYtqzzx9XCNcKc7l2nsXwXKFWX7bQ2dZ0XVeeIB1JOcQcKXPsHSy8AQDy6jNQV2tYvcUTIJxKeUrEyeO4o24VbWtAIdRKqLOoRVPasu8bCMDeNt8fvn79guM80WokO//27VtY7DRgyvfvr5iTcRyng9sxBu73A8E/yUHgZ/nll09A90EKswCwORiDTw08QNhbhWSzDuHArE2R7LiECxdCAG+1gYmwaTjdWvEU0NmGbFIuc9pWTPgDfGsRwPIE3qT9+xm+e8+i9AzkPXt20WaH3O2Cfr7vWo9fJ0ACndcE5vQ3hdVndYXBEwk5BF1/TxJ0COGi9tfFbVkgsb+fWfKytlK9kFIl6XfGgRmE2GWO9ob7TKQpkO+MpliikEabjYYQYVKvkQHi673pc26idS9BFGmnCT4JgGWNLS51uMAAiID+jnBZ1MV2TYCu859TgBNrVxLkc36zAqlnJhBgQNuEQ28fm7tQSHil2HkWE+JtHoQV7Qre7G+715QJQi5rx+McMhCRBUy715IZB634Z+dvXnchyK8D4laLBOYAOKBjMMo0nlT1R8bLaJ21/UMDjswE/GxMLVrlnBHMx4hFJdor740zQQbwAA1brn+vwE6E1FVQhvOVGJgYn0xzewfPsDoGr0oP+2AHqAPs3eIyBjBGHxpIYgAOiCuYqwPezIQsPeAcA5OnJ0eWiJlTx1/OY00HcWEpfKqAsvEvejygVg1CIXPpYT8wcANIvxLd2KGKMyn9ddkf4Luh03ohPz/ZUzIIemA4a+UBgtdKnz6S1tzjV1aPratYi5mXZbdxBh55OdI6TfNx6rnDMQZQwwoL5Y+Rr9YeZYzZwWMK+J4T1aIuVmtzWRQLYw5gKOCDWd9lXmQAE1Z1eD+Y1ZqX3n8t/p4xACKPHEmcI96Syi9VLV+swYZiLtmMICqoZR2+et4xeeheJNb58zhw3N/Q9g377aaAVHN8sqVqkATilYqANyrYWsMPP/yA7TxQS/O+f//+Hcws99eKUhq27RuYgePovmcZoJuTPT6CALzP8hHKJ6D7KIUnttrQmXFXTfEshPZyA/PAmBp9aTBq2cCTJL9cAYCJwYw25ewIQZhRqwW1Npz3HbfWwJPQ2oatbZiDMasEV+iaXNaYsCXpZJYDz1V34T+GSy4i87sADpd7jKn/nMul1WMHpZ2Jp6qzVS/qibD6SJu60Uhr1o1JNmER8gEMqz+01dcTQhkELP1/pw8/TxNCriWE62c0eWK5vCKa6/3aLEpXSCUIgmjvK8k5y1o1yqqCxRA+UguN1oqqJTkxre3Iwq+NgbpkmfVPDnUEUFqbH1ZaUoHVhCDRRsfdQfsCMxExTD6W0NtGRwEMxcHDkjcrKTRirmFxzWNmVGopUqJQZaiLEDClPi5gPWBllqAxLXgHUFgOtMw6UVokGxYymmUqxptU6LlOnwyo5PjWdV1Z+O48fyIynOXKsnqzi6f9ZFDlAIcj6JC7PKnCR6xfIhyVSRrFwPKakbu/FirgWlGZUZUnSdtUuJoM5gHS0OgGZPdti3lpLsKtepAcS9OybS2dBRX3zDH1jFrv6P10jT0AHMcdo3cR4LbqwI8RZ/UCcEl49izXi8CrIEnHeozu69XoSGCoQQxGqDm7kElTC1jOOUCSG/ezi5up5hq1sQcJoLrdXrBtMvfaJvPEomLWQihVLAK9n3h5eUHXADESaY91/nAkLu/DP2eeFUodWSGFCFst2JqMY1F3wwJLgxL2Op6m0GCnQwBzA0CPijVwUi4QFpova8F+CIvShZwPJFBI+bkVSGYwHLxJmAohLKDL+rTrSfFkbzMQL8NllrG43/onLJkVmK2dDFw3fS88jgNtJ6/PwJUpXaVNCjJqA3tgMnOVrAAlUVMN1WMMTCaROWoDVcm9NjUhPSvvtsBNgJz/t33Brd7e5pVpZWXK2/0OEOHr16/47d//B5iT8XK/o7aKPideXl6cpv08cfZDrO9+VlXm77431NbQqKFuDaVXtPNNgCkLb5x94O31DWXbUbcbbi8DTRUgWyP0KYiuFEK9bcBtQ5VtC7UUdP5znH2ilorWhEegEkYfvlcChJ9++h2Oo+N+v2PbJB+dpREhKnh5eXFL3mf5GOUT0H2QwilVQatVNnuQ53kaY4jFDYTadolqNga+fPmCrW349vpdtb+q8Sc5sDzOU8PuFrTBmiS6olBFLRUWIvwf35puNqppsxDjKphNLqhVNoLJ0xPeuuA3TQtfQgCyDbsQZp8osAAKUU+jiMBFvvFpXZZXD7L3S7TLcCcsVHyDc8sAawh63SA9uuGcvkH6GQ/Yhmefrd7IxRYpgzjeU0pGChBLDvlt2fJhwmcEtYh67JA2mIOO+m8pGoUMASKcbnN6narDh0oZ/v4ki6ghiD0VgZ2HI5UIzVXXg+aQnY1bgbNHnKNIqWF0J//P8V0UB5EG4C54lyV6IGndMNr7/WqRKyEU+qNQIY3hlYoMRI7rMpB0mjhQRnqfWdaiDrlxer8t4iwATwFSUtuABlyA9lTtsxEmrwFDkGMOleyDpg7IMGPeMzARZ0AzuAJDQ6db3zSCLFSIpuy2aKQP4X21eBLClVCoY8mC7X0mmGaLaYxLuDxNjVLnFir9L4NQnyqa9sB4k7TjMpnSv2EhEIGs5s+temLsqmPvCY8V5EAFbAsqIkBflQ9koNTOzcHBoCjYhrgwQuavW+/YLH/DBU2fazqnDQxbvq5pQRZksOTZoWCwdzBD8shZ2oEpvG/fd00oPlzhYYI9SPPr1YrzYIni2yp6lyAM/RzqHiaCpgib3UOpiztmDwDqijKFcWk++yuTAo28zzbZ1rFzxh5I2KM+Oh+Nb3WdclxzwJPeEbdGG2QWwSzdfuqPjPtHPQYsM58xt2h5+zoXY/7GE8EJrV32DuOftl+lZxNPysX2D7NGxi0GFoHamuxJIA1Ywsju05MBGhPAUAtqTWBOz9DB0sQoD/G3QOtg0BxgsnykqjApRami68PWju1kSQ6QQCJjORMc/ZR7prolAxaVt4HKjMjW0PNp2yb570AKbKF7v5w/LErXUipa2zCYMVl0tHKGbuC4nzgPcVmWFAksYFVTjdjcZQZKJVQSwLrfGtoOt6wygN/8+gfNNSe8vpaCX//m1/j9737C8fs7iDY5p1cr7vc3TGbc9l3XyJOB/yy/yPIJ6D5ImWOgEkClYKsVAKNQ1ZDUstlu2w5ArGzHceI8B371qxu+fP2KP3x7lUPCw0BUkRC7xx1znBqZiZwZ11IwKADdf/mXf47Rp0TBIsK//4/+b/zUqmoCCbNMNNoAtRpAN6VSqp/r4FI9R8xkFsCg9805JSw8FTPIaD0afVMPRBs4yWDRBCzrEzuzFcmIAM81A4iPPKgAChRhlgQ9W1AV0Jl1CiANJMNKdw36YBs+ww+XW9CMCRVOi7VXN2X9XIjQDTlQRDDN4cDtEPgA9PzkTIC8+LkqnpYqQOqwpMJ+3gtpoxc5bi3MACutYTSSayZcVCK0QmiVHNSZ+OJiDAcgbrUqsM0ixvpb+mm/kybbBZ8QUsxS49Y3B2cK8Aw0WG8ZYlXSuWZAzO4VKw9JuHXtARUVPdQawSZ8WqPZXNxY26K04rAgxDkRpPNCRTdmAZGFRRFjQGnOHBRAD+kXnXMkG/qcHWWGdh2waGvsGntWKddcDnMeulg7MQJFAT8s6TfPlMRYR0CBAjPcpclAqwhZAYKvGvecEy5bnsMSNWA560YfGg4/gFwOKCBNN95krnvmEm7nV3UuKK3dLbhWjd5bFAjaHG0qODNqKeIO6+kIBCzZehcQNgBUBwNARJbUTFxgsACrIf2RNWjRNc11kR34GaAz5UiAeXYwhznAswNUdU0wWN0pR+/oegaoa/AT4SlCt69ffwAAvL69iYBeK7JCgfQ8z3EeIBVuSzkABo7jAJWCfb9p9D/G/bjLnqMBHoamfzCa++ziWBfFz7OyAzpTElG6X9l14g/PAZlhPFYl0hJaxMc/1q3vBcvMzuAxrRG3CiL4yuUzpXcontIojIFVXMHmkyVA6fJi32O8+YnHrYApXHdJ+2+WJ1qqZmbnQ0SEuu2wdeqRe9W92KyC4CmW8spoLVybSb0LLNUR657l69Lmq3ntlBbHNtRd02nrLVT+agotVXT03kFu0buCY/i9nvC+FDQiPwfn8681VCq4zzcfH+OTQ2UKS4ReNO8bQ/jIZOAcA/0cON8E0PVzojUBbvOU/WQyUIsczsCcqFRRC/D6NrDdKmoV3tv7xHEM/ObPv+D1reH/+f0biORc3t8ofxPHceL3v/sdiCxIXcPr65AIl1+nn1P/LB+jfAK6D1LCIsKxacA0V7JhsLkMTInwNIZGo9LElKZlF+uObIhFAVwrBbWwarErammoJQ47g4P5/+Yc+Iu3E//NP/dnoZE3LeHyrz7q7ZRy5U+P/Mq0lf7nk2JCPcPO9jxq86/vCY2nAwnQsqHm50xUiIPz6ybmezIhglvo3n0Ndb0IO1jpk3qkwCF3O+tzrzrgECyeVPZQrtpj+cUmKzuAglp9QsjUBKwlJWJFAnTaZpNdykIf03dHe3PbslbfxuUqgJGD6OtZtqB5AEI4cGZ1WwzhI1y8shvklTjZCiVfhWXbhCXQGqLcnouf3AN+MkjJFXapAy6UMszFioEBlGJWMoUvaU6aEsMFNJil1uib3s8XaOeWuphdq9tkvCfTndOYZxC20nG9X3qTElPnyc6Wf08uTRXyPF8eR71h9UuC3AKeU5tsDdE6DD66LqiG50Akzw4AZikU3MLGI/heMErkxgYg5YcfXiya9pu8DndL5ViXco+5dZoFL9rrc+EJf7EJVlvzPnqQiURbWx+WWmHOiX52VRwOf6fVl4i5zPk8+oUsym/wjQsrU3BzrSfWJxurJle36NK6gDqdtytrp8sStJfFfiprlhI/uQC6y29rc4DwpeEx/1yDpqvM69V3oazPIfG41IZ3RtTfK/2I9l95Tl5/NJEAHfxsL+gAkwRI2zZyxeFGhEFFLMBar5xrKyjEGgVTIt5KntDkHi6CBoz/i5IolFk2D5eorbn9ZC7a4i3wm//kP0Chgt/+x/+ZvEUjQhrNWJ8xYGhlTtkPpmiftGnWdon+Kbkhxd367APnIekGSm1AEau1Hs/DrIQ+xR25NUJFwTkmuBMaNCq2jaVax7d9W0Dr169f8OOPP+B2u2Hbd5wAWmsaaGZizq7W1c/yEconoPsgxbQ0tkEKb44d0A+rT04/whx7776BO6AjArEIyk1dkSoxKlW0WjGK+IAPP6AfGrrBwCRCJ3W7SudxYO2iHF7/WrILS/zOPxy+jOnzVYjMwuZ1wzZq5TZQuo+evOtZSZ2gy59k45AGRmqWCIa2acOhjFf5s+VnmrNu7M8rIm/Y81cyEk1M8DFwwAB4gtiUBwaCcqJ1Wkii5FQw9zhPn2nDF8F6mQvPBURxqUkWnyyyUtxn7/RIgYECQpDS+a7+cCZ6I8UNWgC7AaCn5xov89csrbQgOk7/xjoyrTWlzhKgnmemfTc5njFzhMAsRMLul96HcCPW9QX8msLF/lGQa+6mY17eCwOKj8qQdS2pNf6iuMmWubWtGfDwct2AzjnkPAkDqCkCHijc0bISJwAcFhr5b1zpxSpgxnkjo/s0nqbXxK18aP7PAHje/j8icQe/TgDuQgNz+UOeH6kNNiiZF5t7qJ0VAseZSBOE7R2sdGi1qdu5utheTPakwWf6MCvg0KTl3a3/k2esqYd1EedK3T37wjeiP1jXgI7vu0R87zsDeKZ40IWdQWBoMS7Mz/4l8jV4BVP23DqDUl0UfI6TcjEi4+p7LLpoAnWWTshfo8w0c00Hm88m2bIe6ULnRB9e/7YE2bKnqwWKAaaKbYMERAHJ2qMibpnKC8QSPUBUMSnUuTRZXDLL9Hm8NJPkfX10PcsbChT7ISL3zjEwk+/Z/td/uALeJeps8JzWmj+b05uIQsQslmKZNKub7VxyflYsZcf9BJUNVCV3nOlXaqs4esfZT9S9ohGhz4FxMiY3tEo6AcWThmpB2xsIGkSlVHz94St+9We/ioAukz0YkVnxPy10H6d8AroPUlprISCbxmpa5LHQqB7HAeYNZkk4z9PD5JoA0pq4QvTecbvdQKUCVMF84uXWMSHnKaio283J+M//l/8TzBP/7l/+mTM0E74kh5e5R5k7pbX2UbtElw111bSvAlo84/LPRcCM7ySJsQlHgCcwR9QX5+wMcMozV2sDtH9XdzFWph+ub1eopNHiJgEpah45eAiQQQQ/g2fuNAbGDBCUQpJPyzYrdWOMffJxA18tTPGuZ4WIJJ4nCYiTAA6yOZrLWtNzm/JT3MJLMBAnnz109AI61nbm8Yy2rsDAAUi6v6p7XCmWzY8SJZMwpX3mOdH7EBrW6n2pGjmsVD1TovdauHhXeHgQk+GCRAaFHrnNIy+uZ8RivqwAx7ThpoHladrrtbjo70I7UPQcldHN+MAitDPS3/Ni0ZR6LEojKKwx4r5LmB5B1wQfLH2u1ewsA7a+BcRazqUMUAADKqIQ19DcM4JoLGdjEoCJNUIKqNnBN0GFYgP3RhMD6kCMEeVcfXRZG6YAsyTAcIEzAJ7UNQeLy3kKgOLBQJSmYKtP3M9MOB3Dok2GBaLUiaLJmUXpNkAkwU1EaJwYQ9PGzLHUxSx5siSBeEEvdpY63PyKupq2VsEc60faHmf4QBJ4R1zEJG+dnde+f3vD/X7H/X4XF3517Y/5LGuKzcXegJzy/qIu9LUUtKLBaKiAeMS4g5ecbIIvbe0/ASbp7NejguXKiwOoLSAtXcP1+/wMXXjW5W2uDEO2tiUlXolk2laDpUNw98kS+Q8fQJ291cCw7R8XvmJjYUqcouFKrQZZl3lPzfsZO++TvIUDvU/st5vv81QIW7uJhwQkJ51tXKzz2bEQNDDRAAhiwRPlBbl7+5yM436HgSdbqwIQu/dNXKVjPwHgQAfIScqxhPa3aK5byRa6AI7Wd70qw6C8Yygf6GfH5DdUlZWOo6Nsu+a80+MEBXg73nA/7mAw9tuOOSfOtzfUUvByu3mkyt+/CjC73XYdf2BvhL/xm1/jhy9fPRjKvt3AEHnv7F0C2mzbdeZ9ll9o+QR0H6QQPQqIWSMVrjOqeaY4gzLGcF/2RRjVz42B1hhtk1DVN4YIMGfHqAUlbS6u/ZUG6O/YaGJPYr+fEJuItWH9+3otW8+AcDG7Cse0vidFuRM62CZmNImNb60n2mvXog/RngCUAViuMoXRXshkIEPPDZlEqlU/07iadS9dUFzGvkkHCLS2rvT0NupX3r1UZb7PAaQemLdOmUByTWBtdft5mCQQBY3hm62/x9/MS9uvYC7ufQJ0OI+Pj9gKpjgJWBTnqAzYiZCsygfLNcYunV3a4IR6WDuugb8AK28G8vwwkGVn3yIqIF2eAV8CrwCLciDomekS7w63x2f90OlEtLwjKy0MlAR/yWAoA6LHcc79fAR2S5MvQDRcCw2wbUprd83SaLt5ngR/YX/7Qpknbc5ttHbFuo1olzb3Z9FQnIn29s4A3AGizYKVrQ0WsTO7meX8dnH+ULwe4tp4AIehzIv3WLTTfA6z+JqCBqzSuodEUu1DInVSFfe0ObqETNeom8dxOKDrGgjF5xkl0PEQtCH2AecHJdpi69O4Y35OaCi0Df6agBaUn1p0FDzyhIdim4nPF/gDlO/5kyp7XqxNxrtJGW9WOVlk3cnT7ymzSBCjJ6Au9jwCriS2eby0NXh+7pPNa/tsLRTlpio9WQKlxHqWs6DneaoyUqxMU5U4dh6T6B13QO27zX1iTlg8aERJDsnu2leLW9Wzn9Y2aN1U1KGaaLmfiOLcYbpmihu7v0CVcswPe5ysl1ijpMFQWPvjHk8pAJiAv+Mh8uvb2xu21lDrDmZg9CnnpKlg33elt8hfLy8v8s7v3yUY0v+H+fhZ/uksn4Duo5R3hEb5KgQyYyLGuAzQtbYvfuaZwbUKbG2itYZtE+/v2Qd6O3D2kgKKaNAHSP6aRYRybBdXYy9bhfS8d+oNCQRc99MHEc3/prQ5ZEAQblxZm3u95726Q0ANMLK2xzaEKx5bxyZplxN4s9f6WYqFDgGwUi0C8mzjpXKRnxK4zO2Xl/q7H2dNFmYQ4DOBiTg3t250ssGs5+usDeWdsbbPT6avf2fP/RygszFbBSW7VbXYmt9qtSxVt6hJP9UiNCPgQIQZvwDERNcH4SMJB4u1LAj7ABwM6D0aGBbnOm8DQSyJK+B9XoKO9v48BolknICRPbiAuQC5lGiZ6yJa37ECNE7rcOnkpcuP7oUeFVTpPMbA2TvUZ9DBgYFpmfv0dLYsnX7yOcZGBNWSaGzvKFQw6RrJMdbLMu6WGPz6k0CdR6/0aJe8ALoM+sTyNtyycAV09rylhyjZakmkxl/SoC+IZ6dYDVFYPTgq7l0AHBQkGqA7DsmL5bw980XnMTGezhtgNFzByiNflM+mn4ucbDb/njGNvPv8nHu/vXOd6xnI2bW8dv37JxUbB1rmlPKdDDTlMkeFuhzyPjExA+ByopNvL+RtSCqFpZXL2qRQZl37brw1q5FMwZQBnQGZMQaon7r+FbwRHIRJzjdKo7GWUKzqudjsGQPS/J6rgkyeM14Qba+tgXzOAyBLaUJi+Xsy+A+pNFTBnQHdZKmD6XGfCzllyn2qcIKvaeE6tVRXalogs6usdn+7A7eJ221z2s4pz25b9XQ2jRteXl7ALFbMc86nffssv8zyCeg+ULlqm1Z3rmCG5lZoDNUOGa9a+JXZUYmcTFSAs59oR0M9VRgmSXPQWkU9pzUoGnfhObT+o2283rwKjE9qSMKD5cKKulYglDeuYKhyX6ZVSCHMSPdf27eI1vp7dUHLWnor2UJn4oFtTLHrJYlI3+8NyLJ4ev1zcJmvxQNXUOj3cNaNpqa48MDL/atlLgKSyP0GNuD9zYKFtTPalku4rl7nxCOoWyimf4RIBROiUr1u6THwZVHXyAA069nQEBy8rWlqZmBlrokR5THdx/ygkQUgrsxLn1X4XqQtJ5KC/TSfyM63kQcxAELgAeCCvs07gCJiaprTDq5MiM6umEu9dhifnZdkgdCb/QTghTZ7uAU0xtPWLLm3QH7GG5wE43iHgComlsi07u5qOSGLBzlIFcs0eaLceVZ8Xifwsf5e++6Dx7ZuEhh/BugegKvJhuxzY/1sVrdw3wQk2vGjYk/HqpKfNRWeEYoKSXkg/FBSikQUYRvv8zjw9vrq4Nzy0Un0wTRX7N2M+E1Lc5RuSs9k1Q8aWjj7DC9iGhAFEIp5/MjX5MG1AcGZEkf7OQb6rNj95sIbDff612mQXEeTpe6BD+t/2VvD+JUp4QTsWHCfWMRpl0nvvoAZXT8PmccRAs7m7QAAIABJREFU95ENDpS36UhMlmU0pkWihVqR1QJd2PvvMoiOiYPJBM6clTIbuvO211o1993qLbS2E97GrTUPimJ8zJKNF6oO1mTIzMKm7S0k+Tx9f4x28eCF51oqhK3J+cCmKVLMZdjnhFZSawFVyTdXNa9lLQZa7cfcpquPI0NTiWzqSaW8pm3N59Pr6y7eI3/ilP0s//SXT0D3gYpt0Es4b4TgGvnICiTaVFnOPFjJQmAwMk2cuTfUSTjPJklgq+RrIioomNhaQ6lSZ8Ycj8U2jAwfstB+ufsC0FKvYUzeBA27N55ZterRN6s73FCzTHK1dgZY48vzaT9CnKu79uMqaFl7wR5/QzaP9P2lBlyvhALbzpis7m0m6BABKYI13Ern1RDg7kCXV2RgzJFWIeftEktFtDlvtldAl8c+BB/Tott5qsfBtrExwTGLgKv4mq6Y8JSEv1W7mwCAvsSBRyKYAw8E3bIyIVvmljmmYHw5a6fP1If5yBFNzuasCTA6yULIT7QFgZPLZQZBqzJBqrnyB5u3gOFHFcqyoG3tm/MRmFJef+s45XWZgYhFpjTwcAWDuY15HV3d6fK6plJQNCLe8kOE4XNmLY7pfrasgm6MiV1DXPP60jo02ZyDjgb0r1bLDPZMwM20k3rnhZ5qoWPGrMUtfWsv9bxaysfVhwRwKDD3OulbrbIWhrrc8ZzoU9IQvL29av4s4DwPzzUn+b7UvZg4oSxemnHh9M5L3G3f+LDd83Rw2Ne186YMqC+3rvoR5XPGEmxMnsyNpYqfmSQPYI6CpwU6wFMLnXzFMEWKew9k3rasVeW/U94TlmfpKDsp1r10Ubhox/PcW7Yq/SwAysaUUBTQYRgPk7a7YgArGLSq2OhBZo21pINpvXB8INIckMV+zB00AF3mCWahS8sNYE1lwxOM8sBPwhIJ3QMuNEC4TGZZQM6MV0270/xzLdXdPpnCPltrQfW9UlL6tFrgaXYgVvKri72APL2mQ0eloFJBKZL+ab/tnlfys3yM8gnoPkgxBpcFmfydfS/JOQlzimAgG/LA169fAAjjent7A5GcmzjPE4BoubbW8PVWAFSM88R9e8XeKr7cdrRWMbngxx9+wM0sdLbdJI0XIcDPYolIApAJgHMiWQAkSbbda8x3TkatBmIlpLDdA32XKMwk1DJQ3S3JNkcTaGMDYxANDyIglr+Z3huCs+xLZWXIRItg75ttemcupiXPfJmgIJwehWcXCE2aMWAIUjBpTD6EWNnAptdrLiEuZBm48jZ563SD1CTiCuxbKdhaQ1Oto1vnFJTp/r0K94uQEmOdAZ6BZuurPZvzlZUUFc6auQQX4CyorwLlGOLaBrKNPPUZABxsmLUV7uIXuQBZ8giazJqAIRGplliF9DEAUAqvnyLcuXBt65NRaDq0sj5bAlonnH1OQii51S0s7kbDKy3zvFxppPNF+2PiuIXxthQna+LeFSRc10CWXqfXYWsLACpcYlHhcIwAjYsQVooaAeJdZrUyfsckURpbbRree4Qwl9ddmiu5LqeHJ7HO/If8LByBApTl8KcQ4WyMgdpq2JjWaehAX0gbQrGf6+F8zayi5nLJi3Kg947RT3ApOM94la1LU+a1VnHbN6lD625N3ClrIQwLyAJx9Ztj4H7ccdwPfP/2Bxz3O47j7mv7PE+YAtGCRtgidnhhaw3CF+TvyD8nwq7O9Tx3DARwyiX6pLgiK93DNj4+zJR+21oywGzjwzD1DV0AnoMSrdAVSvZzmVN5zfl0clSPB8DmhXT/tqiWNjcvddicyO2Qhpelv8v3F5pBc3AC5nqYeYa647rnRQXpGp+TUPsIHlUrWmvY910DgRD0QC967yikkXdL1cT0DVSLttUSlAfgI6XBvt8WnhqAdFXgWHEvi1Lw/W//Xemn8hKm4cFHcmmankN+LI9rCggEW99qDQc8N6Xg6YrbfsNt/3/Ze5tf7ZblPuhX3evZ+33PvfH19b2Q2DEmH8QKRsECFCmRgmwIEUMGCCEkGERCKGNGyEwg4l9ggMRHxCARQoAgAxhYEQoBA1JARICVAE4wwgHbxB/3nvPuvZ+1uhhU/aqqe619zs0wZ+/1ar97P+tZqz+qu6vrV1Vd9YDbwwO2h4cIHjNUjV/15iwuednj4yN0qJ+Zs3Z/+PDB22PWye1jd8u3yS8PDzfjY/uI9AYK4NMXX+CXln69X1/f6x3QvZGLggfdvgCE+0HVxNXcUyEwOMMi86QLze12S41ga2gN6A1A60VYEGy37puwMZ6+9Sq6W33T5pS2IaXwbS11CwVBn8b7kvtP9NjalrukXOyR8TQ3uCI81u8wWbO4caQgPJc/QYCpjPw7gezcfmohE3DaOxLgl4fDc6Nb+sK6Ux0btJLSPQU8D08tIOn5ZZeL1/lK0cCGeyHPOIggRXeNIT+LLYqV9iuYS/rxcHpx0bkQTr7yovDEav33bFHRSNjuNzALRfY8xy8EK+S4CXJ9rdYvBWIdAdXlZ+6LiAEzavEnQSceMMGXZQ6vxISbWWFwpttX0VCiPxRwtQCrYwzkHCdPqIEPVgt0zvF17ZK2EzhXWqEqWMuyuKyIKGbBudib/ZmYfVf9jcm23AohvzY613v2JTX3VPxwDk/g0MtMYXz9KUBuVIFy/X1gDI+8OmjttTGfwW+uv7YIxAR3xo9HAKdQ8BwD97tFA9z3HU9PT3h+ecHLyzM+ffqEcewh2NZ5EBiJ9yfWJ2HVr4/MQVlkfr/OlBPPRfbxChRd3BVJxWIuu5x3k0Xwqqy6/urn9SoAMeYCm+vAlg/IRKSAKtnO5fvKt+pNOf298JTlE5+5gschJ2BAUCxadEd3a5lCJqVOY2TjCuggGIW/yjRfmickdwWqv2e8tnhLLNfKwyr/ruf/v/cn/yXo0IifrWNWts7llf6TYLrOwcyfWZW1EcgHNpebNCiGeeGO2lbfNcaAHsNT4nAfsJofHh6K4knRu1g0bNeR9C4QdDztwyx9suHjZx/Nare9i/lv5Xof6Tdy5aZtgC6tTymoVlcsXjWCWgWCLM+AnltmeoOlnBH0nprVrXf8hZ/8URxjmEvmdq0x4p4WoC6E3fknn7rWyq5lpvJ93QYSEMaWuTDx+nG1ZuT3r7/Dz8seYEJOASvZntyYpntlI+cJmhQm6radVFHMNs6zVKKIVkz9BDKoQHmmCq5punCluuedEyabTw0urUuvg7lVMD7Tis8lvaXM6dwYK+00X7ssusqCAvGcugKeO2H5BEdTcXUunAR60ofCi/2Zgvxc1gTayzo9A6uibUdRJDiRhO3ScsaPQY4gQJutv5PwEffn33V+S3YTCtfckz84cOFzBAecAxWcsO55tiIE/9lamMGZhof3b30W1qLtAZ7rXAjioyqKZOmnAifLy8WCQYjkOgu9VxZI+1zbmPeGKjp8JZGvkUZ+5ojR/XT5CXovCjezGpg3QHVbHZMLZnEnbhJrtQJohVjaFCTIEB/v5+dn3D0FwfPzE17ud9zvdk4uBWPnTyHoltx2hccHW0ABTBOPLe1jQyrLXviGvW9jU4ctXBav2UsUIfFbUNMbxLqSZdbUeyuIk8oVlqqqwtInhFldJYjDNAxTA8uv0ojSpvXsnbDxJx5/SYK61vNG8kHNsjlvqzWMChxV4JByXnwFWdKgnq5EI5ccoi6eaxVHLJGGoh5V4HTQM09blVKqilFklm3bMkKsarggr+7w8xzK3+u6b62hO8c3a7dmv8tQCWxvZKYZBVxpYV6qqooh2Q7b1+z9282sc+Y67Yqust/Zs77vCNB6w+OHB5PLtnoW+/36Ol/vgO6NXDUiFAFdaw3HOCZBoW7I1XJXGSfv01XHGEpDawO9MScLIxwCvQl+8Xf/CI6h2PYdp1DFGv+VP2dhD1p+KqNdwNoKnOqmP2/oq5Zt/lktBgFsltx0CSzqvWzbqTVannOGfK0dzLK5uVStLDfJ1y66GmXri+CMcj7usgh/40SDUyVl1DSeMlBXE4lT/tJ5CEnWi3Mj/ngZsxSPVotSbpfXbczyroCjTLS0jXhx41HFOpTxvP+XglkCujo8k7WlnJPzSXACV2erRBUuayLhWegUsTMawjNTgy6kAx3ncyKvA7prAThkOheSRgF06dabQLtRMHMXVJtXr63FfC/zY1aeYxY6C929Wp68bMyC8KQB5/wLYBMoysZOJIXtOr51bjkSmSF5HeOVXjNdoi9FOM4k9rN7JS2SdPVi8uLqUhmgOgB1ugQzFcGIczQzD2jVul2FbhCwHxFNc4yBfb/j6ekJh+eTe355ibN5vTUoDHRTEcdxrPOXrso53g7+Kq9yvtikzNNgEU7LmDLzXCKPXPndD3QJ+er8ltDtugI6grkC6LyD8ZvzidfFdhBzki7GCrUAHCfkgAnEVFfS2E8lefu0nsmfJnixdH3iZ4UXeiTIq7azCvIei3a6YahA9x3HYRZ7HjcIGoq5aWoTHFCMPZOIT3PRXcrrxkzXcdfABMgREc9xOTeQvGGMARzmWvnhl/8GhiqefvzvtXrHrPCYxubih2NcAaIc6QUwQTljOP5eDAeb73tj8gVzfZ7dP01W62AOyjEEVBQazer0o2wGO+5QPLLer6//9e5c+0au3npqk3omMq65gXjvficzxonRrRqwFNxSgGsCbL3jw8MND9vmoa81rHi9nafdqEKOpFUk+GARhq6ATAKg/GxgyOqugMuEJn6uAiMtAlLKqvWy/7QaTC0AQdAZbKD8TuG0ClR5n+2vQrYmqOOzIbwiBRhuGL4pTpvIKnBMQhC/16QXsNAygVkZJgdqWU5a5wTEHTLVk6kJpLarPoNSfm1nPJ/jMwOgQq/SLtL2tDGzvEUwkaniomiYriJx1cqk0tvnUOnDKjTw2TVQx2tgPQWdMnfXH2qdtbjqrfXW8k70w5fSdkwAY+YPyV/WHFMzUE0N9HyP52IY8e16rV+1VwKkpLZgfqcuWvMi6O4GlYB8HaeVZCn4zut6pu3Srov1XSFoBXdc6xQcqQioZ+cIQldQRwDItAX8XAXQbFd1h6OgvADJY+D+8oKX52c8Pz/h+ekZ97sFPnl6frLk5Ludse6RqD0IiHmNZq/JB0prQJ7D300k2tZqmRSQTwq5sm6FQnUSO+FKnW85b+KfkEehJJ//kp9ljNdrUiBMPwnmCNCChyP5O/updWxG+Sl8Z1oXlWEDS5+TFqh7eQEhqsDTNz+DqOIf+3f/g7k/qH14HfioKxmOMXCMEsXX94juib8tYqUro0qfCew652lv7iaca++KF2Rjz+tNRPDtf/3n8J0//XPhPQB5JQ/oa4CulEV+t21byFisW4cpvY59x3HsANSDlixnypGxDVLO4jjN7qKcC8fQALD7cXiALkYopzJHsfWG23ti8TdzvVvo3shFH+zWbIEbcLvje99/RmsfcLvdgjH91m/9Fj5+/OA55eyidqj3HgziOA7cbrdgRE0Et01wHDs++/iIx9t3ACiefu3X8Qd/+Vex3W74n3/8O8ADk5T7hjAGxqEYfcvIfqq43/dk6h4haoyBzc/u0cWLGixuMlVg3Pc9wBsB3r7v3tfufTuw7we2ze7tewdQXTAqU23ed3FLSxUCTQN9u20eCIK0mwXF49hDm3kswvYMlkkjxb7fQ9DN/FOHb24N+7Fj6EBHR986xjGs754nypi/Yh+Hn0HIfHsiFpnr/vKCoQda20IAIIBODfwAz9eICMZhG3BrDZsAWxMLpNAzzD+U7piCWwRIWaCuUuqS2ChDCx4PUTCG0/2csLpaRODCGoWdtEDXOqzctNrABQtEpDE0TMlZ69wDBb/I3cWnOIYzIu29TxpTiXNmZ4GkWhRzTls99pXPg2OkwBLtG6EkEY+Wls14JeLmCcDINA8YjIRgAb7m0budihHB5rxlDEbuPHAcDDDAPFIDzaO+MUWB6sC2AUyXQuVCjdgIGP1sTc/nyAAGPkgBuVpCb9sNTQ7c77aOHh4ecNuMj3x6fgrhPOiuisODDthPTwAadGmApnUy1sRgYBjxfhYrQUx1Cn4EGQyLLmUcxD+LjfEgAOB4HNj9Z9ssXDldL41eW6whzjvSD6q4ba7Y6w1yB15engG3/Iwx8HJ/xqenLzCGRnCsoYpjvwNqwiLnH91qvYc2bgxsw3VIPzN2IhRHuTYFFqzl4XbD7dZT+bOAWcQ50gyaEZYO/h+PK8TXmMhs+cuValeb7hcgXAAcylxJBHtxKRVL+ZsTiuyMAXZXa2nQKfUoJsh7QKWYg2iQvlily98VyFB5NQHSNgcsMuuvBWoareHXfvxH8dlvfz95ka9DW18HjsPaPWABpZ6f7zjGzEuOIRB5xnYb2HDDJh29u/Ln8QaBR16F81UZgAxIs6iRt9sNaBJnvWm9r0nFk+RlL+X57eYBupw3kUq32w1dO7rWiJVlHcOt50h+xzHnfkAeGtaz+z2ULfdiyf7wsuN2+4DHDx+wdbM63seBoSafPNw2qHR8+vQJ+/0FTW5m7RyK+75ju9kxlm27YQzg+Xngs88+4Pn5BV98+oRt27BtNzx8eMDLywtenl5w6CO2reMb3/zs9Tn6fn2trndA90auqs2t0fSqYJebXHGT8GcYVn1lnnxH6+alA4IRlrqtN/yJv/5raNLxi3/PdyHdpp1tXO7SUzR9RHoVoKkijjXo9F3d9ebNNXlw6OAvrqv7Vfi1DWQtm8Ku/dZCt6oYTI01gcPU3qXI17S8p9bJnEPw9Qenl/JvEvXiedHUbVfN9fpdrULgLpbhZlu017Dtv0CuM8mXtlxZTL6sczkPlksxhQKvm3kITusgKABhiodyfgNzs025KpiDsni7FlCX75w/p0W4NEFDJL3qUvmiAH//Q9iF1tCKcNP7huZ57b4MzFXwRBBJRcjaorAEAHaG0t0reZtCvtXBsgl2GCVuLPVbPfxcXRCvQN6XadXHPGIp6HHtOiAIWpSyEnew3qxLJ0m7rJGr8fqKdbrS/Qf7MRApbpkjYAih0yZn4U8C6bP1N923BjAELy8vKdBCHLjtJ8sg19nKWs7rL3ldXRbzzFa/PwMc4dxD4SMSMzvXWR0sYDl3NvPeaqGqy37uxyvWHnltdNceYwkwVd6vYC4Ao7tHogDG2ga2mw32oqmwAOBAl2TQ0q+6h6UCS1FpsfY17wOzm+U6j8m7UsmR9wBFPVMLwJW2A6Pz3K1O7mFzGQU8X1xUZlpayQxGkopQ//uCz9X+Grg/p3C62ofJA6Nd5CXLmEVgIVXocWD3qL0iHc+MDn57wHbbcOsduwwoqst6BdZUCrVou/HXsg4LoDVQ2uI5ltH7DyZXvF9/51/vgO6NXKsQlGAtw/mapauFIEWtVWtmzaMVj1cNoMIogIIBjMOE/Abcbt2Sjfsm0kvUJfJNXf5n9Gp1rSQTgk/K3ekiqPpyDMANfVI2vvrcLOzPPH7d+KvQO0oZQR3kuaHye9pAaz1VYKzCzGsdmzfwvDcVk50OgSJaF2VoEdhqH2oLKhSqGmCGJg+XEsx0W/fJEGZQQ4t7/1XzTNM0sLNAV7GplnkTwmLkmavvJ0hlO4rzUjTW0gG0qZ/TRg7xwBJpTVwJXh2IXhMCri4T2hKwzfSbBRB+WUEd28qZ1PoGWpdfq3sGSVSYUIiYFNRJx1VA8qiUrVkey5zLCyAJYY9CzCUVynvzM1WRBDBAi2J49pJVIUCFUwi0Pi+YZmOXJfiN0wBlPs200aBvEuV1163L3k08Tsu9LwFzxaIfZwhj7Mbkum4zSE90oFJv33dTWBwSIdDJp80CuJc2jaCJQEv8joxQWDj0zP/qHFENesYrfFaTj1fcFatKkqekAuVE1VjbyX9kbg/LKxe/DyBVmsi6f5DrVG6toPQhOln4wlcVzJW9cKrCYWTdOuKdGfDUluUL/J9uyLW9oQwpQLNduqP6muc68daNYQqI4zjQ+oGuI+oUybxsk3Ksygdcgz7rhtpZwyrLTAqMZcCrJT8VA/Z9K/sen63gMF/xe2XToVW5gvTG3Uw9INFQtJcXPD89eyoa84jptwZtDYcq4PJZEwlXzdHMy6c1ifyjHmMoEzRJxkQY48C2eSoEqCttIrf9+/UGrndA90auKihMyYvLebor1wXeD5eb4ppQkxMf4/CITQp4zhppDbfbhofbLUJQb36P9Zcdr/ws7YYzWMoLSMEqn39ts1ovao5fu6qQSsZfy8xNh778wXTHLKykZnBtV92wZqH9LBKggMVsTwWTBC/ZZi1F6/Q1BcArIYWCbrQx/lEw0Lma0gK6tlgS1ZInCilYpYBV3i/CG78wi5oL0xOYYzsJTPKdDL7gnxdBqYKiugGXav35IhS0CtTm/qJoQuNMm5yDB+hwgasC6UWyrMAkBHfSQmat+ZVYKQzjfQXqKAS7G20Vfmo7rkDIGOoaZ6Aet6aWurU21cVIdwAwhiXjrfjoDFZmgdubOw33DOJIshZ04zXcAiDDIsVhEIyVNbkCahdeI99fBUds8wREZyvdBEyyxUG/M5A787dr2lyDuvm84ij1G5izc1UlLYYqFJkji9Uf47CzPUeHDKPlOCwVzejGu82icviAlP5wDFQtnZhy7iT6ISAMYLRQJ0MyOT+LF2kZr2PNNZtKpAR0cx7TOk8oqiflCy/Q5Y/Km72uqcwQ1r/iquv6YuLG2qzrrqqSlukSvPjUvwQPpaC0UCaD932m7DeaL6jas3Urib5X0qzdBPe/YgErvK01LuK0lFNeEFrqCK64l8Izuco00klL4e6jqWu5WJcTcGVPqfy46ovTpqGdypty9TaBaFrK5r3FPq/KLVOW2Jo018tntK2jd5eJxNwoxxAMPQC1ADRjmBvzaAdaN68HPXZ3/e+eAjPTodCNeoxhz0CgaDj2A3qMd0D3hq53QPdGrgoCKvOrgQfIpPm5uli+vLxEwu0V0AEwQUKaZ5ixHaU1wcODMS+CN54dE0n/c1qgTuIOGTdSgFKc3Q1nMFS/qwJrPqtlU7um1bqNSbyXrg71uRRIs+xaRmoEZ2Fl1Ryv9aTgzfQSVQCmQLy6QtLSRjhWe6neyKmPFVyd+n5Bn4KjOXIi5fB69Cm1l5NgJkWoKuSqYs68mZ/b9BqYSwOFi44MY177HIOVAlUIVRQwpAbYOFdMV8wKjqrDVwqsCSzOfZgLn1x/SltWbXgMFwXRRWCMsivAW/px5X5U/7ZgSQOqBIGlPi/zSpirVgBq61Pgz/4RlORcnn/bM0s/o19zXYWiVuYA0AZ02DMM388nYsxUIjhK0CvAtD+tOafq3FLN9CEr/VY6q5b5HPcTxC2kyWf8wQD4S9u0flazBtQ8h0x7QGUb6VYjkzaM4BEr/w2lHoBqocvfXrGgrG+/7bSs63peAppggvsRjD/wxOd56clUz/QEeQuSx6A+E5VrNlucS6xRduWibrxyLcCt7kB11Nn2WJNYhvw8Ra6v6CfHs+XflSkDAebYTCa4z3XlvLG0McqX5OsTTwGmiNmzwoug39rUGlNvlAi3g+Cu0o2/SCMWV8BaYN6Z11z91LZyLRzHERFHyc9iXcYUOQO6BIcGOYUElOrCbQrNo5TRRNBbBxTYue72A/v9juN+x3F7wDYaujRoU+xj4IB5MDGf4zEOQCyRuLltevkVILsMdwxLAcHPUMV9OeP/fn39r3dA90auvm14eHiIz6paotFJgLdt28KtUlXj8/e//z3sfsjXAhxoaIVMADwgHX4QGWjdopR9/PCIb37jMwvmAaB14OFhA+AH9Y8Rm01sDmWT5D4XIqFvBql59y08Xp0taiwuhdIWoCwFrdz0UhCt6QTsngm4zetjzp0MliKSAJeuZ7Vu5mSySwDR0yZE6xM3QL5HMM2y7ehMce90rWjd3JsHMhHY9+rBJzQ2Me93FUqFmtWyT8dI5BsVkDUBtmaBUG69Q3zjE/9OZIl+WUaW37EfFHhokcorpZQ6vmfLEqL9WY2CiXDDEiOIIBNRdAlQkpEkaxPKODHh9QSEyvZZBHZ14GhC5CyQcE5PYI7CySmNAedUSn9R/QWgqAJkFVRYVs29NPdVAOwRgCGLr9aUDNAyWxxstdq8FQeEo9Tb0Brc2p9AkfOcyh2CwJkurENDoJyvEXyEVoSs18c32m8AqLUegZ0GEEmuOQ4IULdY6DzKoA1qBarrj0Y/03JmD9a8bWGzWoTKxFB6midMGQBYX3AAx24R7wTiwVGA49jj3DI5adLErZSVD0UTyS+AcRzBb1QzMMcF2kWwkdP6KX1VYLKauTok051IADeB2doY3DD4h2JK3pwKs/NaWMVaheXzCovU9KDmpMT89Vre1Xcz8EbwswB1UU1113sdoMT6FCqbWgK4CQG9fpmFKlvN9dwU0xqu5auhCTx+8Qk3aVAP5sF8c+dzuABwoHXrjwXfUjQ1sMN0K5xXx3EYUJIehIryYGAQBDYgeDSLVe8bIsm4yImPrbx1AGYdrAqPMTx5eeFffL4oq3N/8r25rDtulJYCHZHK5dY3NLGgZ4cOjAHs9x2qn9DR0NCApvjGhw/otw2yG51a33AcBw63kDcRSO94eXnBGCaLDbXgOBaUbsN229BHs6Bo3QN9iWI8WRljnfzv19f2egd0b+RieF1e0+atmVgzNW+YGCXKc9XVcnieGpZFMMeN1qJierQ1peA2C7VVgJjVuKlzBZ+Jv8pTYkDONqpVAKxbaArF5/cRz2V/z89MAqJIAXRYyqXFIV2zZoE8n6vPn2WRs3Ul+5YaRoIJrXYigZ0VCjGbglel6NJHQTyP+gwFHfDMjAvurIeRHr1OoaAbQkgRvHwiLNTK/zlG9Rl2cKGz7acaf18KN3rx0emgbC/b+YqbJSTnKgWLWl4dUgqsiLH3HpY6MhCHp+yIaua1kSJtCjpZa9JpauqZAgVcftXuXoWiLyvxtWtWtojoso5MPLcxqxpkpxaFAAAgAElEQVRkrt+sT4RhuHMti5h70qXQTu016c97Tqrm46pNwqrdioVOvNME/dEf0Aqcfcx1TAvWdToVLe3gZ/Kx6nj4OjVzvsbvInTW8pksuWrBmPctU0F4dFFPYDyBOQI4RZ7PC2Cdee2qomtp5dTnuRfXz+aVPLUCOZdNoz8ipJtOlrxUDCQfmetZ18/8Tf54ZWeNVunC69+dSr9m6vmkiFtPyccLnwyrfDvfW8GcFr6z9JOKjeoyy6bFnuCUsPORpgATEXzvx34nvv1//Qr+vr/8V/BLf/QfAQBTelVFDuc2uNZqcA4JwCM5SKnsULXgTUtfbBiqhS7Xo/h+8xpfulqH8LpEBL/6c38a3SPc5l6U/Pm0liUlERIu+Gjh1+yBAJDW0Nlfd7s/xoFxH3h5uaNvz+gvHYpHbEzdoOb+3bolH+fcFzUQeRymUKesNMZA37qRqll0WNdFW6BQ3zL3xKbv19f8egd0b+QSIAKfAEVg9A368NDXqfnO83MEZilEUDjxMMoRrt04cS/MtjXBduthIaLlCIALUvcQboJxxwaBIstK1Gm6sCpUCOatNAVDCgiV/+YeS4HzDATnd8jK+WyWPee0Ky3gxixM3I6lLTXXG9+Vqa65L3PZta3xnqYoQ+FgsgwJdeKFGJQw6+XCwbwxXgtC/M8EQ95QttzBXKVHvhu9DgFl1kTPm2rt19LcqWnX4nF1FebWq4Ho5vZxI4yiGOAFRSgptYUVzq0ZpB+Fltr+sxbZ1sQVIEi5kYINhdI6JzJKXg5HsQaU+5yDV7S5vgo9CkFUkcFqxpiE1kqPmF6a90qTFqAXUtxUf20D/2YQmumMi5RocBAMGXCDkguOJuXQSqcuMYm4q7AIhqRyiY1XZecrGD7TUC7uVfpy7oW0qouw6oBttczV71Ywd3j+qbRCMM/XAgzEI9A6eCOwDSDn2GBoAkKmJ4m5N9IFNydm4bu1b377xFa49/h/slJtWocrPXNuzGfgknfOTxclFhae6cXNlr1XGIvIqR9WdX53GnmRcO+T8lN7MrVFJJKpx7/6N1aayalA8vlZmeHTOM4KyrSOzspN50aF/2vvePrWD+HB030EwIy1t/IsegHM3gDNFi5qmglTIl9A7IulNPG10zDl2qy8FWU9S7G43X/P78PoWwi/LLtGzKyRwKMNRSi4mhNUmqsq9BiocZ/0UOy7uVDetxdsLx0vL5udU4UFExMo0JjbLvlc7Ze5Xrb4+zgOtKMDIP9jlWLgUGH1vl9v4noHdG/oWjfJqpFaUxmEJkxksu7RQlcZDMEJBZUuJWKcCLZtw3/4T/8RPD3d0e87ulty4vweBRIdaJM2qW5pSC66CIb1d2rSK/OvAnO1fPC52YpwJVQCiI2Kdc1CWpVrZ6FkFmSLEMQeSm6wVmYdo1pPjttlW6c/E+RN4Kw0hi0hqEi9doKelSp6EgIoMFKLDDBMqYhEMJykTTkrKRRWJIS53LRXwUXKUKzi0evC9NUVWzJf9Z+os9CBtKztquAlhWyPaBZgrpY/C44TqINcgOfS1mliaoA5KiG0tPhVMOw1WZCSWRSpn0PRIHluLmlLkEH3QIu8FnX7Wmf6kbUOuh2S2HPzVguYtziEzvxc51sFdCHMKCJVBVsxxjB3qNbQxgBaw2iM4NvSQhd1VShgNH4V8/L5C9660qB019ZdcR3X8szZ7bL8IHPNMUgVrXOQspaZFHuUOdfELCuthWupOEgAbP7KKPsBsj0EjgRssQwUYDroazEXEyAN3h38hrwCEJiF4RLUTcv8SwejvHLNM6XcCz7JveIK1F1dr6zXtb4rBdBVORO0lYufug/ODYweXYK6ovCZlVbB9Cba0Mp9lhVSBjDXyXUfKC0qoI4KMwZQQmMON0llBikQtMp9uxIlxmrlSUhwaO3LvgZ1SsqGup+b/qMGOEtZYd5zyx9FboLOc2zzCN7HuFvaFFeGjOMwl0soen9Bbx391nEcnkPTLa8DPJrB6MmMPm59sSihZiWlUqcdR0Yq55QAlfDAvt8vx+n9+vpd74DujVw8g3Wy0OGs4crNCCH0MJn46rZl4a433LZMUNp7xzEQQtytdzzcHrDvA/uhzngFW988zL2gpiYAZjne7vtmpQpID6Z1talUgFf7SJDKDSMxzrp51fdTkKzAjclN53fq5/PmE5sWpn0Mc7S1vFSxlPH6lUBQ43GBQCUjms7bY3RkEpZkaRvfY/my0JC/TcOYwokICpg7C7y1IfN883sTPV4fY6fU6Tlu5lWCunSlmQBkAWl8V5ZZFmCuWOA0hQMKRAGkiyCyCqk2J9OyNIMrKg/q8/lx6v8C5CZ6q8bwrsLkvDZKHeX7kwDFfgOm9V7OsRkNIqh2fKa7HstjMnH73C6mB9foqmy5jtJpwmbmlRpuLeUzY6hHZrT8fGatagnoWoPEmcEcP8tzbG5o1dXQaGzthFD5oJdjTKshMQ8B//QzjLYWWZQKLmszc84NCof+EzwdpLnVkefi2hSO3Qdjqjf56zh9VwEmBVM5WatnEEqAlr8XxUeoIGa+GjyjRI1deVadG3U2B9+bnlg+N+enpQjWGfwmC8u3vwS41fD1bFUCNL7+Gu+rSg230E0NWbok9baWaMRfdhmgUhTwvvA8zt9oUwE74JwCIhDK/E6WcQXnY1y0rpllbcxdC0ueI3tvZwsFRRNXTKAojf0yHpOKmomEZR/71r//b6M1wff/5J+KOdnc6lVzvt3vd381oyqflC6l7SISoHf3s6xtFEs43LK+77jf7+gvHS8vd9zuN7Sb0UaH86aeIFiHYrvdTtHJVWn1s5RSt9uG/cjjMNtmaQ/eLXRv53oHdG/ken5+wd3dJgDEWQpjViXJLDKgB7VGrQk+fvyI5+fn1Aq5Rujl5QVNgMeHB8BdfrbbDbofuB87OgQPDzeoNBxDcQygW3ojPDw+WDqEoRDZEZo/4hsXlMKliKAMzvBDk5gbUgVdGQDFhEdVbkpJF250yaitnAQZzNFX8+5ZKHfV1YWV72LaVLJNdRPXEDgTCBE4zZpBag+zjFkQz7bqvD9Ha+ezkAEAQBlTo37fJUvbso20CNX32Z5t62iwMwkmolMIKNEiyyYo7BvS0sKxJB2LyJb/q0z905gr2dsAPSoR4vnkPuPPhfDrgFRdcLavX0/6nSHkU9lgAV9ahOm2OmfQ0NztaBq7C2AVrSxzJkFEDcdexoFn82IYdRJ6zuVnuet3Nn97zOUJsHKO2MKZ3qtnbBnlct8PC8xRBDTjN4cHXWKgoTr+pc8cfxcQGa2vroUYv5aAiWcTh0d7C4DQmglOvWHDFmu1KluGDo/hIUC3JjQt5yu9HwDC8hWIrQi4TioDhPWzt+/wEO6HW9rGMXCIRRkdx/B5ZXk96WIlvUGOhv3YA0SYgU7KnJsTEvNKXjpC4FSOm1qE0LDQjTxPFx4cmrTqHkimfs9FG8oOG7IYk1CSVOCrEmPQWsPWOjZ3g2UBhA2BAbGuGQWt1snnKkiaXTDLDJt+xfy+AHkrWNMKOBeeGGAkWofgq1MX/FmG66ltnpRNAYiit/64P+uWMIK9CPwbDXBrVJRrc6SeBZ4IgUxsrYCH2N/SClSet33buP8Y5I3kPwoMAbra/lACo3BdgiCNnkAEdWjJP1uDtB7n91R6KIVSmXC4QiT3FCZ6732zNarAZ//VX4BA8Jv/wr+I7l2uQVWS373iOTHpSPJDjUGwHwfUzxIa799x33foOHDc73jSgaE7Pv/+N9C2hg/yiH6zVAO9dTvv2gyMvxwDHz9+wL7veLnfLS7Bwxay2P3+gvbNb+Dh4Yb7y4v1twk+PHSgCY77fu7D+/W1vN4B3Ru5dg+FC1QAsFrp+LRMri9A5qvb9/2kFbPDxvAYB6kNDCDTGn7mP//v8XLf8ef/2N8PaRaCt/eOvvkh/RE7PUorMG3cwbjrblUB3QxmKHtlc1OPWOSy+EEpKSxSBaTVclcLHdtxBlOrzLs8oFOt2bfYjOX8DnC50VxuPq9cFAS/6pkKmFOzPs+fiGAJdVeuOjIucKA6ZXnnFLCgoTJXilm/HiKbAqvVqj4z360S2fJNAUjXFpUMp3+uqLqPVYEV2Fp3N7cC6LjJ9+bWhznXIwW319x8QpC7BLr54LQSOOkJOoc1ci57PrdX5/sEfIvwzPOmoXInHSZCVUuWBj1N0OIzA7TasW6vrYwNcHbD1CII2kVBbNWWVxqvOJZa/iYNQ8wiNgnePqAKA60c6qJOckK1vEM+GuNT5pRPdKo74hkleGQUQmSQCF0sdJpzagK2Ms9ThSZQiGboshS8f4VmpGsVZnWpc9of3B2M6zHczwqoC3BXwRyyjOTjK3ipnH9++npJ03WOfECW76PL2YaJZlNjc52IxFk4JxIgr5ybi3YJJjBX18nafaQ1vba5KpsEM10Ihs71Yk6/UNelFECpsny19oTzOAHgcdvwe//if4u/8Y//o0Dvvqfp3H5JZYf6MYyYM6oYzVZPQ/EY4PxznkNLlpIe1nu7D0EvwI/rss5Xc7uUBIqQOQG3SNJB3KLnkSS1m7dB8MPXR/hifSOstVUx0ZtCpEPVQPCtN4xdoBgYh2LfBfeXF48WfkNXUzSJH0VpAgw1JeG2uaX1sCiivVv9oUzxPqufgVUVbOqaqCvG+H59La93QPdGrjEGmocdtkhJCmmCxw8fgCfgvh/Yjx1PT0/4+PEj9uNuYa/9X+sdfdsAEQuT24xZHMNC7O7jQHfBhuGAHx8fsQ/FGAe+9be+h2MoPnz2AfhkWiSzXGxo7Q7zE3efccCiOoXF0IRhnh1J2cC1iEKtXAeDvAEUEmY6UMCMDchuAmoCZ5MMVEF3Lwq+tkkzzHGVDCT/koZ9P0KzSAZfrQqtNdNkMhWB0jWPGxvzd3l73Q0DCmP4brFr0oyBi3hyacnnm1lY1K0AEy18M7boas0Pqwu0OSDT7JvlOXJwALqPJWjvrlVtgVwzFLcJ5QMW5bwKbhlZz6xV3iyggKkUEhbRGNykaD2O0vlf2ZQTkFehKHM3sdSao2moRmL0K9AHTc1wbOKkrxK2moTZwkpZv0dpS5lLUmbSZd1n4avmhKK7Wsxzk/6KcCZz3cAEjkin6gKqSVgTijpCOA/QwTkITBbRPcKraZyXrWDaLHMIQaxaVxJc+piEq6El26V7X1ofR0lnYnzhOHaMccRY8Bpq7p/bbQME2PdcU+qgpvUW6zMtCYjIcoC4EkpNC37YnLjfzb2pdcFxAMehONzN3J4fOI4R9/Zjx3GMcIs6utVZFXBtKI7jblp/Hw4d8LDlN9y2tJwMd7kKG6GP1dCBpuJxTnz+joFxMQ/CSgEJBZ4iQf8xDmyAnxci3QhMfa5wTTs/4sptXHtIYNJ9znVaYpxvRKS/IvCv66Xy3vyvOnZyBs6/ocAREYq5LgimKsfxOStzeX4z/g4wU1GjSKmwlnGxLzGNghcbQM67ZGvYiUyeBoSrZv07eGCR5aO1wZ5o0VzbgVh89NT59d/7E/j9v/CX8cN/9X/Hr//Bn8zuTG72ZX/rLXjH8LlTFRa9wSLNis1XC/RRrGP+HLhOAXRJHgdhGgRTHjaOzwJ6w9IMn48FLNlDgnEM3I87hgKtN/SW52ktX24C3GN4EDgKINJ8nR+e0xFlz+/oXSHD1n0XYNsE4zBIa/078PT0jO2LJzx+eMDt8QZpHWMIdm/iUMtRd+sdvTU8PNz8iIri48cP+PT0hP1px/2+4/58x9Y6xj4A5ztdOj4+fMD79Taud0D3Rq4jcq4AuzMgaQ0PD48uTDxj3w88v7zgW9/6FvTJwBr5v4XTNQsEc9MxhO5QA19kZsdxoG83bLcNx/OzATMXbh8/PGL33b51D9PbeujtQtCEeP4ZBDgC9nADMlihlMDRu6TbU5yfoRDrAgV3tAI87Eqdm0Xj9A86u17EhhHyhMSGxgrZ/61vCPcnSauCuSp5wtGxu5xY/5U2sLkogm6JziciKfT5e2Owfw4khmkpU5DOzV0cCDYHlIPBEgYlAXGgRuGL4JN5oQRbb+5uCQcPw/vsJKRLjNcZASjKeYwgt4MP+NxsLpi02FS9Di00iDFP98IElBXAOKBwIYXCaYBm1h2zgnUw3L3fLcCW7k20ZnsnUEuK4BTlewp0k/AidCebwWgKXJLyoSL6QHfR1npquINapAliDk+ut1gF+VxrBEVmTcu1VOm273txUZWgb7XKkf6ZCsXezXOzBMfV9atKwYhnGAhEOCnLsxTe6PpX/7a+G81CoQNgK5F7eYbGrKpUuowyN8TyvI2BhhnQiQM9AjP2bQwKgdbGYxhIOQ53sYQA+4H9sB9AsB1Gz/0YoawaY2Df93iH83wcA+2BgqeN2R0vC19L4Es3Uq7JGtwq3dbmyxLMawIWIFzuuUA4h0fk5uNcdxfmoJOE1YlnuwiIW8xln+cOApvUtZBrQGONFEQygRMlwslZovW38Tzl2hNA1NxIi67Hu1jyvoGrioy0WKcQO82E6abGBWgk9Exgyzma9c5jEfkcHYhZyhXwv3Nd9lL2P265pV3TCjeRLWjra3LbsD8+Qu97BPEwvpw18Wy18bwWoCcsy0Oh47BGq0DV+AHdiHkGVkSKNdp5T+V1rmjgHtbEwCGQUSGpwGK+tqpj63Kb+sr5PVTRtw3aNbyRaj7e4cBsP4bvfw54bfFbfWIKzqbqyb2b7W5qR4233qA3wTgUhyqGHnh+fkb/9IBv7gc+qM21YyjG4d4BUBw6cIN5edzK8YvHD3Zk5RnA2A/cX3Y83j5gZ+qRw2SsD7dHvF9v43oHdG/mut6weVUBOJlpvkMrAIW0SdihhAfjmyagu5sQCKokQF1jtCw4k+4tNg820cXuZMaAbQahC7SnStXx3tRLSYE2JVPEpp6WIn8rNle3GEQxs+Bg5xR4LkcmkEXhPd6p38Hey4Jl+qnvUKs9wb0AMhUCxhBPf1egUkHp3A+nIwr4FLqs5GAEFmGbJEnZ+KzThXJJQptSZaFRzAsW6H2NDRmKNhQjZP2r+Xt1T15/Kiw6iHqqW94EoCjAuXBSnwcykAN/TyBY7AlQmOmKhmYaYkjQhZEOa9M5znM/XAiTPNua1s5XcueVtfTayq9rHrW/8V2mCGkBhuFW41QCJNkTPNWznyxjjDoaM5hIcFnHhZa3TJeygtJrF8HCmyiiUrinYF/mrSmXSuRMJwfnPBUpwwFKK2vYAA0CNOlo6MPOwg0HbxDxIFEjyhAZGMozSQmIZ4G8tpd8EUAZf1qqDSjPllCU92ZaZRqC6rZWg2fVSJd1zVYrG+c8GXHyiJx1CVQkhHOOw9LbulCncqYTcGTV5DnLek/AVH77+q0LYbbj2fqJVSB1bcvUyJUX107UOk/8Nqohr4MD1HzmzB8LOUKj421XqZh1riPwrMxfnGidlrqcY9k+SHUDX1zhubZi7+SZZW+r0zuH3+eaZLuprKBSarsZDboY6EMFy1RKiKA3s57VNEoxVj6ILWjN1U7vk1gNWe4xABj4G+7hsrUC/iYqcn017xYVlMtzHGehwsIBqMAUpzAvnft9x/PzgduzBWE6xuH55FrMl8H2TszcAp88Pj7EWWQr1+f7YXxpPSX5fn19r3dA90YuY1QUxI3RZBCUDN2dGm6YlqgBUDtDt20b9j0BErVbWp6VloeejzEgENy27po14OHhAf3xEYDE4d6H44aH281dtAxYUEuuQy38r9DK5iBP5s7VTade4t8Pdzvc2hZMXk0CSk0cvM1TUtQsKDdau9UgUxL1CEgR4Hbkez0FtjYkXJ24IYTLXAkgIkWDXtsSz/cWYA0KTwg7C8nUjlIbv21bjJ9w11OFHmraRSDCLNNakWczTGAz6xxdpCi4aySPpXxTt00KLyeBRQMa5byEhuVHRdFUYk7MUQ8XmOKSQwU3Z8E/3wvLC1+XmiPRhXsxC3QVCMNiyjH3tjEIR+8dAsGAYr/vgAy00bBtG24eiGj3JLE+PcPtdVYOZD9pzRJgsm6GkEWBmsL5mIXfttCddKm5KUnEupYqOAuFBEwoaZpnu5KedJ3mgGjhKflsBSFci0yBUl0n6xhbG/rkCsV6jRfN1rkaoIWuWiJpeWQ9IoKHhwcc+2E/x4FjmBXKgofkfLzf9/B0mIV1cQvigIidjxlj4L7v4bZIHru7VcJe83x5wW9aKh2QljXL4Wlj3zygFT0lWuvhhlUjEQ5f90NprRw4AAtEVdzc7NmBYz8wmmIcx2RdhQusodRzxdhQLcGB6pjZfMwcnZzPDWVSBzygwMtlW1guJlCnrgqprJ68qQCqUKiV9cT8elXBxO8nsNpSiG7ZiPNVwRKVPPXe1XsEegH6bNybzJwsLeE1wIs4SNOsjyQodUf9bYZyoc+Mz1SwDFReIgV4TTy0yA18P7wavAxpQEMvzwmkWcUyzYPs737sma8NQPPAKwR+Uusapio24Heb5rY1KieC0U4xtCf/OQZGG06I7C9pPTx3nIjxoXbbQMXCzCMTBEMk1nWlDcp8Yvlbb9DRjU/70ZBj3/H89ILvff8TDnQ8Pt5w6AEVRT8a+tbQt46X/W5Atnc/r25r9uHhAY8Pjz6XG+RInr7fBw7cT0Dz/fr6Xu+A7s1cdYNYQE8IstUCwXf4WaaNJoU4Y0zcvHlQnsKkSPqlAxZtqnkKhNYEGwWTrZczN745NZk3jqqdtIb7ZywMd+ocAJ4hKUANBDWwzU8lrCUJelc6sThBurnU5J+YDlaHJSf35PijbmqTNpd1a26gBBAhjFRgBLdoUdssyIIL8EnrRjctPIWp0rAmAm1p7amCU41+HptVOSdYctemoBTCTdGgIoUetj2oXB43Qw4FWxPEAyqKzi+sL1PGm3ay7ECRORd61khnqxtVgrlcC21+ZxJaBE0d5PkcTvCkEX6eDZCTql3mNoaWOdejrzzocOFHJN2Vqoi4CBer9r9aTOp1uabK/FqpewJ/ZQ4xbcE06/1zpCwhbXS2yFXg0do8rhX4rW6D62e2TySVUrwY9bcXN8y6FgH7XVMGVDrS8paCsguUxZNhuFv6BIBQQYYDl6KkSSIXIVHy3KS0BP51XtPNcYwRgqz1m5E1a25AAj9TIh1jxFldruUWdbt1TuFudBXM1XZo+cnZUkYuxoT9aJWeXlDwRLxySf1Tpr8TOCXIinD/lU/J/BPvlJQMc5U+XyPfYV1rWceUMgJIr47aTgKoebCTSqQB92As9U0Pg7jsRO21aJ0Gq+xfyLVWt5K1mihDcl8WKnR8zVSWllvfDKTWNUVrXbi5tgSdsSdLvi+o0Vxb1ESlFtMYqIM/VcXLT/yeib9nNOp0Z849c+YtVAIGC9LKnxC8PsgedRgYI9/IRQtAB/b7Hff7C263DgX3BoU0oKMXuogrzQkSO3ozJa1tB3ZGcQDYX47rAXy/vrbXO6B7Y1eCrqLlkzUQQp63AVw4KMIqv08ri6YQEEBIsuyiwdq2DjigEw+Ksm0Htt7x0nbKLYALLsFgy+bIPUimG37VTbtACMoWUjGPa9KYr+nAkSCsMu2iScayzVVLipSNZm4Wn5k3zioZU5BgqydhocrvU1fPAgDftS7Pwi2tIhEEzBtzAiJiLh7molL6SJc/mGGP513sjNkc2MU2HqN7FaJQ+nkCDDqDJ86jSrtK9yhPASkgj0Laes3VzdpoArRMMt2wDHUIegGOAiBRq2/PZPAGK4KWu8PPgDFAxqSBv2hsCk7zVyMEFcDOno0QEjTq9ca3dAtqi2XppNxwOqc1LaN9RsRJghBdRHZX/zMtA+daCveAWcXODkCyCL7Lt6CQuQLR2TKEV+4XoVzXMlLxFJFIe4tk3AAMaKBhgBYeumTN47fm+fyqv1Ogrn11a3oBs0aBwktdoONvQSrdMt9fvm/WRgLQTEqe71TQ4lK4r0PmsrO6UxlAwHmMYwKsr47gwhdrvwXiuUi5npqHnfK5l72/Kjl+VdBWqBn3m3h8xcJj63o+gTkkMD2B6/oMchxZZtRdo7RK3ps8KUqxr9HQFI9zfbWuWlDWcaZYKqhONeBES+cn4vW/fPyIn/6P/jz+n3/1Xw7epqoR3XFdg9OYwAOXcCRLugRxfgF4ABD3WhBpQNvQ2giLfOsNTMpCBcQkw0gm4jbgNeY++/1f/bl/w9IYFJp4IQA4v3PNTIAuPIbqfEm5KOSVBdTNysKUmyzjg1n3x7ED4HlOhY4DY1i5x33HIP/eNmy9+Vn9jt6Z1xOQLkAXtGPguGuk4Hm/3sb1Duje0LUCNV4iqT2qwTsS0A1U9xlyiJrvZRyWSBPUJnIPdCvOr/zUT0D9nb7ZtGvSgJ5WuibP0BDgimay5HCClCiU4KH25J/UdZbO+TvIrbAwX8A3FW2Au23xNQq3Tj2s3ugppOROXwHebO27HBFvg848VxAbP4WrxBa+WZBRV6BHHFEECQJaWogYzIDAqUHSU8U38ND6h/aWm6b9GS6mFDAnmiwabwJMUDxLclLAmnBT7ctUXqENqoYWPv75d2qBUzDTVdqoZVOQLMlzq8A1D80M6JLoIQ8EuAJgZftZJPUoaVpGfgIrKQ3G2K9tDrqBbj8DOo13DETS+wIMrXNynscAXRK5DkKwcXq+hjZPQgsIBowkrY0F5M3tWHnMfGUbz6BtnqtTmcgoj6vCiRVmcBlaqFEAYIuzLyyRtKF7VdMULgl4wh0x+hYreG6d5i8LLjIi6mo0leM5WVlZ15wvTuRwHmeAzix0CgrCtPCeAOck16cFPu8k7aHAAc9VN2o/BZPVpi7caUTgAq0pUXpEa/VaKkCK4XJOWObkxH2k1lDOEpWzzhXkJXjJOuJzZfvkwYvJ6QTqyvsnwIXlu3g+SDFdZ36lU91R3kTVAhgdm8v6UpbmgCxpG0+v7RbB//tTP4k/8Bf+Ej7+5m/hix/+lu/tqbARbg7ktXHZZuAAACAASURBVMGbZWqrra1MGs5ULqEYPhgIjYBYImgKzyJXPlrbyFQkYRFXYOV7q/WsKrfUeXldT+RbWeZAg6cTEM8f2HI+n6y5Xn6L+V14DOUxgUX1dpfzmFWqHgTO+ivuNbBJg3SgegRQVIqgQhBzdx3LxHq/vtbXO6B7I5efCFgYnDNxYcATalsBkY7e4aG/6U5UBWdjnkezML507SEDsrMgwwOeCP7az/606VwVGUlMLBjBtm3YblsEXUkhsgKvFP4DaHAPUQ3QkwI1YtOh4B/CLYVsMkO0KchBaN5kFjCvcNkM3lZNtC7vabkn+bHy3ESmLhcRvEm4tIQVdWrJhOiqHAiRtBKltc2BjlBUSyicmvgiGEV5dPlKgcroq1EXfM+m5VNiMLxBAUoKvTnOFJ687AqygPLdBUgJup0GihstN29/tOXcXwGdbaakf7ZTULStRSJT1KAz+R3DsI8SVIPvbxvZrxOuCmATjbLdATY4r16ZlASVUj//bV1f/nwuC5+XF4J7TGVvt1mH6dpNPpPv1OfXmmz8zGozhsS96lGAOga1EGXAlVW4Q8xx0j7ns8DOwJqbp7o7l52xasFfWFAuZVtUtk5PuCDbjQSIWvoYLpLBmwr/KnN70FowBo5dwmJmUQiTd/Kc80zHnOdTUvDge/a7+Xk9ox9VQJqBfFZQTdo7X+GAJv+l4JvjKlhTe0gEjJiugtdjbpPXvAZsKo9pM7CIv5f307K2Muas66SA4dcx967Lru8Hq/6SdVbndfCA2KRKobXP9Oyo+wcwrYlq1Voa93pbeoe2s3W9tlUXvo6Yt7H7Zjukug3PQY5W3h7rQoeBGg9eUvkaz8HXfl0rlwrEXZ4zOiZNK6CLPo6BAe539oUdQ+eGuljglz6lwnC+hh44hslafcs1LppBlCADuANH71BkZF1GHlW1dCnMjtm6WLCmv13W/379HXu9A7o3crXWHbhsfk5k4Bg7zM3M8gkdh2KMO8bQOE8SIbMjv5Fty01aCKTHbvme9uPAfWfeJwuxfevdhY8dh1KLRDcwF3hvGz5+eMSnLz75OTq3KMHyOKUgkxaCgCBxSBzuHiUYkhtW5OmiKx1giUmBCDdsz5p7kbbUmg0RVHcwaiSrVixdPBh8f3b7oPBe+H2cMYK4NjC0r1lu/OGbZGsNh8u0h+cHbG75yPMtdJfUAoyMBlrPJ4q4MLjk/ykbvQWkcYAezxjtbr25m1SGrm4ipmUXxDmnCFFerhTt9CQv1WfW/GoQTLn84nzPBaAj4Amwr7SopGDUWtUOtwk0AnABuSY1TNqlUEKZ1fOxeUDI4ek2AHc3VptHoeFVXc5rmTBc3bdSw5yCfKQUIJVSyudrVQNh8u8iPMwudhdCHf8SFIBLS41Gf42GrQBxjTZk9ERM5QHNXRUHGBOEYzy7/yHqMvdAjbUDpBb/7KKWdVKQpKLqGJl+IYiMnC6xDsq8MtfKTAYvku7jXOOlcwGgWHBXT1VQoltWEDXGwCEj3CwBy8u1H8fcpsI/oAhPivu+e87EPQK3HOOI+WLvjAwwpQl4GZqdYC7rajHnW+/orbtrpY9D1+LJQXobFbluiYVWTxCwPSAvkQBzEfSI5CyBmOJ1H/8cI2CaZLF89ARwrsDK6Qycs4fiDzLVHxMG663iRrl8P4FKb0+CRpws8VeKF45L0HeuoLQ0+0MSsn0B1K3ABDWFllWZRNprkCZ5TFVMUInC+u2cqE512t5UAuJIA6SjuiGyn7fbzXnjBmkb6Jo5xsB+3yNomUq3wEwtldFScqoCc7A37ge9d/zuP/XPAyL4lX/rz051A0zB4Z46PZV7bIMdP7HUBfR66ZVvhiVPM1jMBXCMsTt2HPcXK1MEz0+f8PEbH+254Xn67jt6byGL7ftmOSlVcb/fMY7cT9rWg8y3hxtan5fI+/X1vt4B3Ru56LcunjbAzlH5RiwNrcMBhm9BFCRCr5qS0vRM2zySlbspFO2qlte++au/iWMofuu730oGB3XB0UBlbx2jcRMRoFrNWgro2Skpm2HZUAsHmzR0QjCalouq4Z8sLC7QMsz6BCrXJhSwVu/x79Sy6lRWlVeuNMdVw5tWg6IBLPnPwnIjKDSZy8hzDgILpqFQGZHklYI5hUl/qYxlBmSYtIzqQhb7hisg5z1LtGqlsv3L861YwUJg4Dm90tVXL7dE5Piy/rPQtG54k9VB8/mTwDYBEOuOimaESczzic9E+2U+Y8bxndslUU5rMrU925WdUCBCczM8dp0OKwiaPyfgNfDTpnprW2u9JjxS8JlTD8xCP90U2Y9q1Uw6tim8YLUCFTojAeCVEJzWDVzWQZIZiMuk7JOV5bLcLL8KegnUvE0O4jJoSPLNcMccChUmGT5VlRNTPRk682KW1DECQAmII9of39WgPwXT4HVlBSUdW87x2s/hOUm93Nr3VWA9dWHaDcjsqDRrqdwD4jxWvktewqaWuZQ3s3ggFUVSAI7Qgri0jW7ty99ZZvH6WHmaz8Gpe0nyCbRFu/i35xcM+qOu9dK+On8x0zra4Nvka1cAK8j1+EhQ/9xWPdM3NrorlOBDbHOs8jHhovYbJR2B5FpVf7b3jr51iHRAUulgFjqTBeo+yJ/eNshGnmX1RdTiRo+AbHfNw8jn6GmgqpH/lGvH2pgbfQROGjNtq/W63lvBowARiVYYhdbPELbW0Dyf7hjDle578JiaCkXHDoi9E8pcdXdmYJ1W79fX+HpPUfFGLkZGgngurN4BNGNgTSDdvj9glgHzJ29+Rl4ZBQMqDQrPi0ILR+9ork1LwGA/FMz/8H/8X+OP/Cf/TRGuEcKgiCWoZh4ohrCu34M/0SFudPWeJAion3l2jO+XsuiuGeXRv79qLpfX7HyfYm7WCtjqO2eOasev5v5kNwqQ8c24lQ0wN835fvScwsYJVCLaB1ATqSm4cBMi3QqNKtAL9yhkv5nzZx6RGemSZuFixbEmYJGqsef9SqKYOCd6rhcFZ7Y/o5q99q71YwIPVfi/AHMLvjkJGZW+bHZtg66V1D4WAbYqG+oZKsQcmfvkPZnQy5UbUL2fPyXCmq+H1KQvVZUF4Mv1Fbrm42xzrLUCIPNZVzK5ht3C8vP8ibw6hBMQjzpLagnylQA6WUd3axQtwgwGUtvHQDFXCcyZIDm+q2fLnMcQ1AWYY5nhKSA5RwroUjVNfQ3TTvd2WubC1d35diXStCKj7go0+VTOqwSeWd84jlJP0pFrdh6XXL/rvIj17nykLiRxviX5cMyVVaERPK6CufxyemZV0qw88rXLrF0zLw466jK+WWm8e3qu0D5SYlysy5PwL8tPzBWc1wP3zsrHVz5y8TOB0wu6vHz2EX/0z/y5ws/Oa5E04P+rUoVrONwtF3rW/q8AVvX8nFnFj4iQue95RASgBa+nElLK3B7zWq4EnNu7RMdGiV5bgwIVXr+O+3l8UZ4bQcoxDvN2cb5HRdHWN7S2QdVA3H4oWusYAO6HW+jFjszdj4H9sEXUNoG8S/lv5nof6jdyhZBQzyRxN4j8Z+6mg8rTeVg4AZFpjYx1SzDMnqCJdYVAWMR8VdBrpOA6F6xmgU0oJQZYqMDkchcDhaIQMsmcGREOpSyQofr7AeTsc9VeXmkyr9rBd+v3q1CTm1U+yrZGF0q/p3eQ7oqXmzIvJRCb2xMgB7aRmKuoax+pwU+yF0Bi71ly1BSMp3N3C2VSUDtr9FsR0DiuUzh2TgPbfSfanapR9ghl8s6baYLIOpb1/fr7hOZCmJt6uezTFWjxey3fNWlxppT1XG32UddJCKOy40t+2I4C9qTUdVnf9P3l19HZlFtmAeb6qsAT8dt+fK0Di2A1hWCN5yJgxivSScyB0s8KgvP9XM8MJb7RXamXVAAreHDB6zjGBOLMDeoIt/QJKGEBGSSjgwkFARPXxnlNe68CzM0gAqFYqPMsZ6DM1XowCbqBjgI6+W5KmogzerWvbGuODxCgH3O0w4ulCrhCie7hYQWZStXgfdWdfOKbr007Pf8dYKsCufUq6zugNMfD50O14tYGT2+tW8TELgoQiT++TOgn72djSl1lP5jqDd5RQd88l1/bN0hWAtGVsL/8D/0h/I5f+//ws//mvxPPr1w/ecPcj1SsFJlgaVedb+OYwVbMUczvEZgR1PEn+f6szK0KNr5beQWfz2jHZ/4a8yoUImU9lvFVYF6vK03LXh9KEXVZqHU71iACqLtUMgCdmmt3a3ZusOb3PIZi3wfuHjGzhTzzfr2F693l8q1cRdhkrrhk5M5ZGLJ6YkIIRkdXiisNOKqvemHYNUGzgRAN74sK9GruKt6lqEI5I86qZ+3li7rB8MFZGFZYUlFxekAEVRyaNrcqPMTjkvWSchfMcn1v3eVTuC0dqhsu8uzHtHlTkNBZcxz3QxZLbfF5wy1nHpYNJjY7FmdIoNCdVkEJQZI1pgC0lBfjoKCrXabNyFGe+qjZerAEdXe9iZKrXGffFl15zGObv/XZsyBiVevpkZXG6zQgjUnX1pbgYpcClExrjIIYy8vQ5hSay+/SQAKWqRMwIRv12WWsV7Cy/r0C50lwqcKJSLh1ZjEzgOOk5ZiL2HpPLfkR1q+kYV1/db0phq5tq2CTCovspwBAb0EenqWkhVDEkvf2YgmchUYg8+KRJ+Uasvk1j1U2otA57BYFXOgo7W4RSEgd1LCOMRTN874FeyNNWP7EJwRElQRzmT/PI96izSkSljkxPPtxtXgwCjAfpzA6RoLq+aqNLcGaYozr6PrfFZ8UxQ+DTxB0XOV1+7KLPHOiXKypsr4X/r5GviV9Ks9dgUapNM/xlU7WPc7mENfIV/SlfL26jNZnjHZS+jNtSPPeL+VFbzNk3isA4Hh8wK/81E/id/3V/+PcrFirOcerK+hEG5+fIY8g94rI0wZxz8ye7wOhkEYTy7/pPERE/N0M9kMPEBM/asRqhJwzAd1GXur7COenz4Hhbo5cWuwnebkU+lLZxb3t6hK4YqNlDswmgq11ND9frao4MNB7w3G4W6iv5W3r2O+78QSXFcaw1A+qAw9bcyvfZfXv19fwegd0b+Q67gPHrni4ddy2RwjueBpPOI6Bh4cH3G43fPHFJ4wBHLu70EFwuz1g2yxx5e324KU17PuO+/3A4+MjjnHHy/ML9v0O+R3fwHe/+3fh6ekJn3/+OQaADx8+AjCGuW0bXj7/AoDg8fEhktxusuF2s+moN+B+3/H8cgdgGqjjOAACS+YocnCABuz7EVr2rTeMYZroW7th8+AN930HIOi3G9DsUPaxHwVoUNCeA0LQzSoDQ6R1q/cNqjuOYwcwJzYdnpeve84YCkM1Hxg3wurz37oAKtCmOMaOYxxowzZeppeAC3ytmwV133eIGE1bv+F+v+P5+QW9d9y22xR4QsRyP9G1TnWg9S0ADcFZbw27C2GtGV0t/80ez9hmJNb/LugFsBkdUpNpgSEOD4xRgYqACbIZWsbONVUwVQRol1Lj8Hpcfm5MUoCZaY24L76RUvrhmGZ+uMz11VufouSFBlsVYGAaCgMKz1lWnuH51RCe0soasvQkWAFSnCdUM0Q1oximzNnQxnIGdP2taYG9AvMreOH3x2GH8VVbaIM5nym8BLjz1Aw2z+Hzai5fythUQcm+G7jfbX6Y9vnAtnU8PDxE/8cwSxjHq2rvWW6chVHFnZr6mJNW7+32EH/f7zte7nfoUGy3DZ999hn2e7puHdV6WFIJVAF+2zq0rHuBBUMhgOvOP1+cn4kIttvm5bSgC1OKHMMDh/CsUGjgbY7VJMl9s/W978YnBBnx7zgODFX0kOgEdDNNOnlePVFz40QGPVFYwKvjSKBtfMbWPK2lxzFwuz1YG/Z0Oa081EI1NWBYVOQmMDf7xph8DKgkYJw+KNvj9TtoDmBcwFwALgrvC7BkYKVYa0AGbVpAXSpSitLstD6zjhOgPBlisl2Q2hbjM1t5heCESij+bbRwoFL6Uibk3DbnZ3lfkycYwaxfLeey0cnorAoPQEKiOW9rHdvTM376P/sv8Iv/zD9lfML35+F8U9XmPKRFkJBMR0C0Cd+TbP+qIf0BYD92C+Ql6RJt5+iTaVaLmgF+29Oen5/x/PyMvt3w8bPPjH+LhNVNfeJbTlB7f9s2P5bSgtdIKHiSPlvvlqLpSI+CoR4wqOxTrbVIQXK/320/7en6CQD70xOen57QxsDDh0c8Pjygbxuen5/xgBs+frih34Hn7z0HTT98+Ijn5xd873uf4yd+9LvYxALdHceBzz//Aj/y7R+C6oZ9P/DpecfLnbn03q+3cL0DujdyySLQGwPsoSkmc+yhGUIIQtT0xnuF8XrpgFj0vWqZsM2IT9RNlgw5eDtEnFkO10a30zaZGrAQGGfLwmKEmDVyk4Y1NzVq3OqOmHxZvA9Syk4NHYHfKqiaxlpAoVYVUY61q9aRdZI28X1Qh31JwfhaG177ISiDa5/q+Ps/WvtM6Cfd7O1ITwBENEsruQQnEYTbVLpFkR7Zp+xj3q90WMfueg/SInBlGbUOe7cKsOeSqsXNqHRFU9fnB318DktagKYeajaGLkdpiZEaA8Ho4NHoaNmJxVCasI4u6WXlulAKWlBr/4uwW4Sf+jvLvJpDRYmCCpicpt4Jas0VwGgNcpxanLQpV84DE5oJxLatwxKlc4za9A55z+oS9mXuavy+RjjNduWElyborUO7ultsg+KIJZQ9SstQWDKW9rBOu5WWC86v2v9qEQ2QOoqFnesdxW0QXi5yHl8umIlGWN6fn1G2OeYsPDfW7JIGJNBIZdc50XPMj2g/Ij1dVT60aL6WPmUfdekD+WIESKpghrxh4RGkI58p1Lt89ge9Lt8jnV97RjFFtrT1y1WUfZ7X6bxZcA5OX2PuX96R09xYedf1NSt84DR/+qHfgc+/82383f/bL+GvimCIoLNqD8tbg2bFnuODZwoPm2Dc01gHf9LinlZ7EYEcbMeAWerH0kac3n01Iq7MdSZhsm1NLqgU+3zKBmntTNoyAvBKz0mG6h1y7ME/qAzSoTAsTllrAy1wvd3Qm+WaPIYAYJRy8g4eXzHly9BVtfF+fZ2vd0D3Rq6t5GkBANPUdmI1AAhNVZzpgICRMFWTka0h3hkYRQ4DiPVA8rSpxybmvx04UMDZescxFNAj6gohvmgXhyZQAgJvOmN04aCAvgBHC4O+koOqMGGfq4BRWaNrcCfBhe+003uVDtYu0jWF1ejLBN64cST4iVJ12TMu2ujiz/y17zrTRqY17DaB4BwRNCr1jw01ZYIL3HWDnNpBmtXPy/fi++nVRsp6a+UKMJqaahHOQsBZ21Lrp0BHoK/n5104o5vb5N51aqML7JpCzDrfvQWlHTlX5oByDggXsJqCg8ybNLXDFdRx/hcgdwXmrix29nnEWZTeLSF4tXJKaQ9E0IZFSwUzNpQ+psUu6yeQVR9Do8Mt6WjFlr/9jAlaWA5W4W+ikX9PXkRhTRkp0uvlWmvNUpbYOTqz9MMM+pOkJou7J8c782fOS4WuxtmIBCakM/tIt65qpeHzeU4nefO8frONWmvTnEsTqHtNyiNPBS2DoyiuVv6faVz2Y8/zdfFcgn6WOZ1lTViVdDvhD0I97gG8KzE2KzC7AlrT3E92VHheJQGDROEHd+mUGcit303lax0hWf4+u11mt89ttbuFfy78L5+/2u3OVwDvtSs+97UBv/W7fxQ/9lf+V3z8W7+BT9/5TqQKoOtoTTVT+/ta7SdgBYRSQzFHoxwwi3OTHoCO61x6eshwz2R6Dc5jEcFv/HN/EkDKJ/ReMeHlzEtqH6pXwMnLofQpUzOV2a9FOVICPg2IWd2PA7jdwKMvtr81bP2hADpB7wNbH3g5AEVD76T9DvMKtXu0IL4DurdzvQO6N3L1bYNCzA3AJYq+dfe3BgBB6xtut4dkAr6TWHReCrymWWquwVcXinvfMPoBBbC7W9i2bSkEipiWziM6AUU4caSy3TYcmj7x6eaWzyDu2BXtDKGGKBGpLVUX3KU8S4AnoS8EyqZHkGVnfaywKgBT2ORzFcCZi2UC0gCV0wan8f0MJKiVTFBobfA8O7XvoaHUpexsF2lUBXeeJdHQRg6otqBPCLxIQNdCQC/nYPidwCMDlo1N8lxBgIAQ4nJ8XCzMPsn8GRxSqYIdx69MiZgW1PLLQtfymBT6UIqM74qQDCoJdHk/+1iGbXqeVs8JlSx11DZa/zRB5FQvn9OVWi5QM/dZAi3SjML11Leg6wyGSGv+zrmdbSCtFHA3S3u4WmeqNS+JcxZijTRn+ta2BCCDTof/1yuFvtWdOYVd+BzOMl1Agyag04y2K6XPnH9T+0q7pA3PNyguVA1TdEV3Z+Evy0havdI1AFxfGdjJpT3/K3mp0S0Hkbwt6Kzn0eAfk6Aan6PVhaZtmhPG1tNSl8q3wnMCRK/cWybeWGeO7S3z2aQJgEl+rqBm+lzulZ6cyjqVU0c7sdbcwHLFe2XJnstE0MMXjgFGaXgt90DO4ULPuneWftf66n6Zc8aVBCeeWD5zz0QZk2nvBT7/7nfw+Xd/BD/2P/wV/PV/8o8HOAkFY2nzVX+CVKqQNucrPHndINdrWPogkLZNc77OzbjinO6B6pn/xc/8cQCCXt4zuuS8r9eZ/9c9NfdvVYUexzRNahk1Mq5qURSMgfvLjpfnO7bthmM/cG8N2139XGzHy4ufD2wN5vK84dOnFw/oZK6iQMN9P7Bt9ciDWMTL9+tNXO+A7o1c2+0GhUVBGi7stb5h3O+Ob8x0f3t4xNPTF7YxWHZtY6pk1K2jNUVr6u44MC3S1jEOY+r7fqAJwn0TAP6nf/Zn8HK/o4IPOBPlBnS73SxK0303Rl82kWrF0PJjX9p/Z4ErLVv5oJQ9NzcqBdwY6YJ1EY6r4Mm9jeVWzTVrpUsqz82NUSN8UQAvYKDQZEwJv7P+TORb21OtJnCBP6lQMzWkvOHCBM+aDNuFR1N0Q2SWz6oI5wJaOcsPP8uFNr4KbQVMnDWxdcQWAQUIgbRiIpUK2HJT5Sabwzw/d76q0DPPs1PLdGmb4PJdArlqTRG1NofwEVNOohyRFvVV61yNfmjgLUG1k+cEODkmK6C7stDVvrG8iULLu9PraidZUUDA6hZcyzyDlRT2E4xRQKrPE7RqzPlYv7LQXgGRcdK8p8ugPZvAMEFiEwN0XTMwSk50QcnSHO3i/0PV8mOJcReBnR2SkesmZlQuVptPi5Z/qaR8V8Ouz8qlEzOsYCzoP0JArs2pV85bfuaDFcjRUlrfy3GkuzyjFatL+cqEzELQkQ053yv9BvxsEnIsJv5yBjVXQC3+ruRdnpmBl8T6NZLShRlTQwMcclygUzmnNaeFJv6sYmST5PrdqZzX5HP2n2u9gGqAe9a6T65zztebVbrwWYRC4LhtePze98xVuUSE9O3E5kPUazev5ndt77yevYyidBqqELWF1i4sTyJS0o0APA8nSH4YrpSSip+s83XgM39XQWCpUy0/nKqGha6+XyPGMmekwFKS3F9e0LYND48f0PYdKg39RS3FlDS8PO9ovWO72eetW8yDjx8f0bdHCAzU3fcDfeP6MwX+vtdz5u/X1/l6B3Rv5LrdHnAcB+73O15eXnC73bBtN6g+hUzx+PiI3juenp4AbRB0CAxcjJHgzYKjWCAOwAJjbJu5CuwvT3ao9/aAh9sD9v0OVcX3f+cP4/n5GXq/R5vUo6gJDBh9fHwEANzvd/Sjo28hJZVgF6srZ25E1eKRuYnLvTYn4JXW0DxyFagxEwEwwnXQAgwo7vfdhaLugs0A3UsMuKYWsR5+pjau98fYBPb9SKHHJQRqKTMoRAZUGWPD/b6j9wQAIloCtdCKhzx/KBlkAWCi7mTsjKZ3DAuA0MaB1m9QAtFhllS6RkW+OMAsGMLQ46Y1tb9z06zXGRRoCAZh5UFCuukd1QBxFIZtI0X0m1aZa0GFcw2o56gSj81CxqUA5gJ0Q847C2+fgSUUWHJ0IdqcQn1pW5VIkXWoC79aIgumEJ3nH8P2MorlinWLoEmxlIhEgJc6JtdXrjGbx5xvpCPz63l/l7e3rU/lUECsvwHE+TwLM87AI0cIXkxjQqVQhiYfnnQ42wnAeZFpKkzz38JDgECTbT2OF1dGFXfHjQCu9F06VAbQLF1605ypFDgBTONkJCefGOVenkc1QRtRHzTHo1plK3/btg29b+YmfyQIhZ7dwCwJeA0akyCWoIQRLA1o+edRgTPb3IPO2caybEgRpzHKmhqqkbuOt7dti5yjPIub55AN9PnMRixzWehBHvIl1wTSJJUtAMxtNlnv+mLpVIz2HFEzuprtmUBcBSkV/GpR2EyfaYmx+cu5NIP2q8b+4Felw1ddGiB7TjUQZ/8U+I2f+HH8vp//i/iVP/KH8en3/V6fn5YI/Dhsre4j19e0X/s+baBx3R8WOk4NI79LPitFebP1zeQQv4Yighodxwgw/UO/8PNofcPTz/6JUrTmfCiyRvUgELFjIebun6lEAFvnFizF81EyIFN5P/oVSh2gSYdA8PK8Y4xPeHz4iKEN7WXgOIDbwyNuDw/47d/+bWzbDZ99o8cZ31//tf8bP/IjP4yH2yOGmifV9z7/HCKf4cOHB4wB7PvAF1988ZVj/n59Pa53QPdGLoKdEQIghWEAYGTHjoeH1LaZ4JyRHitzjmAO8dm12iomoG2aYKwwtcxhBpSdMYSwEOQi6hWZPJ0iF2DgwlERH0E30Ki7bBqstRDG77EvOj1g51paaXMBA77xMZrbmqBUBB7Oe1Khu7CF0mqZ3uHz6jveqhGngFg3mtnqRQGpZXsk3yOduGGm8cFpQOHHhbruYK07CO0lAmVIRou8US2atY9JHs3/Ncd2otPU6fxV2zZrfc8WiEkoKhfxj+BCOq3PXfTNqlsmhEufpCHj+oFgAGm2WQAAIABJREFUdAJxSw0V0U5CBYuXQmt2NZBAdtZfEMDzZRXFB7KsH+xSn6cmaDJYCZDCT5CFa1AEaPMYp1Ux2zm7H+ky3+v6qm21/tRYTFxzVXFR3Q3JlyJnZtRfgEsRG8lbegGD0gQyCu/QXF/GN9e1bf0eHuXRnrHQ6XHOU3PNReRMVDC1pkXA6RkYa3ZlwuzyuiY051iAJPWhGB5FUuFt8vEIiksqmtZz0yfkQ17RMmrnygu7B77ZuoeTj7GWxGiF/8HpFABsrTZq/+pzbq9+r4i0AnOwkr/9a7IAxpI/r3v2N2bOwiOn5tVFcVJZLc97X6KsOnEk5z1KSenInkyO/GoqvYyDquLlm9/A59/5Nv7BP/Pn8Av/2r/i873HXqiqaGpn3qLPFdCJTDx85Uu0tgkKsBXEu8PPNTfVi7nG9gciD0XZGAPf/rP/HkQa/ubP/BOv8sN5ved6bL173BRXrg2nXFG8iLiye1L0NIhsk/vooebF1EWgh3OooWCoZ81g1tjvB4AWEV/bJrjfD+y7yRI6BDoEL/cd+zFc7jAav1vo3s71DujeyMXzV5O2VuomLWglD1O8Bx5ATm1TMihnnMJ3LQw8I6PB+AnGGPj9P/8/YoyBX/xjPzWLaZIbiiX6TSDXGxONS2prC5Bk+8joQ3yZ9j4KYHLJ+EUEzGWcQlrSZAKC8Wq2IWnBlAZM1M2yMlEy5f7VfWP+O8+wsZw1mTLblGeBpNSfzzA/FOlES9taZZUB4isCcII4gvb4XQSxpRcpqlwhIV0+6ixkcD7WcWJJkgAw+41pDtvXc910jeGroQzg/0uTLq+lK1VkSHGIBDSiNq1zZBWAKRzZ5zXWRmj/Yw4ihZqFMpKlBrAKq1yt+wcEczEeSvmJUSIR9zkgU13Fzc5+aHUgHXL+x4H9CzAX1C2CrghBBcINKwHbGkSk8ikx7ypvT/2+CsthvYGYa9O2TWDuZDGZmEydd3DlWKYtsbXqQCcAhL051CPbedn1fF9iUz39prJNoWlZM0omWCuaggV3TsCQ4HxWwtS5l5aasHauyxgJoDmOqeDyNCCtxZmfJkjLfpnBOR98PF6zpi0s9GRFW6+vmPqhuKmvXKyXK/C4gjap/0oZkTNu4QXkbV/avnXfquBxbiA4E85lxCPnl1bmhotGOagzBQ/wN/+BP4g/8F/+JWy/8ZvQ734HQCo4VW2OywRqZgsdZL5/5lWCmr6ltk3HiDNy2YvZvZo0qnOb6ThQnj1fK5+Y3bgFmI48Di+ntwa53SAiOPZ9ojOVTlxDBoCH8RppblVnkCFAR/4All5FHdC13tBggO4I8GYA7r7v2He1CJhqsgwjfb5fX//rHdC9kUuE7oNxB9O5jKLR7n073QPMhUGH0itkEm5E4HlcyAj9vmudftf/8n8CAP7az/wh/MP/6X+Hz7/9zXjXWXFouizvzIbWhyfYXIUpTebnJYCMsApqDl5FNIRPAFNZEogmxGF/hoLsbI20fiOeIZPO5LppAeXele3KzxXkAdVVMgFHWDVbbXuCSGCUMmR6J8f3SOGoCVqfE2xb/2cQVcvL/EBuifTxcejpP0meif4X1+m7itYmKpd3yv3/n703j7ctq8pDvzHnWvs01VMFSltARMEGeQaDIgZb8gyJzU/RiIg+VFSIYhdBMSr2GoJiExHNUwQFJRKDPhAwgiAiGlHQUhoVqugLqP7ec87ea82RP0Y7196n4P2Zumfe37nn7LXXmmu2Y4xvjDHH2AaOO25OgvC25rdvS8x/FtD9BheQBLyFxaP/P4Bb1yd9oVt6siC21IwnbEAgoAAF1efCLSQMt8Ysf7xzpNptBeC3Jy3uAgvL7wOYpWHRdYhSxBXRwWde37bmexAQoC7fk4MobStgArgP4HnqlU4uRKJb2/4stleKr3ENNuJjT+JWNY4ryWtFORDSLkuAvSHeKdcNQNr94qLdWkEB0Ao8R9eyvbn+bIWP+RC31wpNMaMJxx3MIVIfuFC7oIsm/O7eq6FEkLXXA7qw4vXrL5aI0cDmNJ1K1GOBltyCkrfEdlNsMNKWYf8ztTj2zi48Z8/vKnnNeJuoo2sfSTEakZ/JigL7vZNOYAF6ttqXenxKmzqwacDb2sO7H9ye/9y2RFPy1yxvmfdWaHVAOTrCep5VqRu8tiarLumBbgN01tJdgM4UWayBPrph0N+ixCnd+mtzw6xhdiW9CXwdW7oTSuso762s3JH7ezCYFS1k8o4pO0y5rXW0tFetfgDd3IbEYX0WD6hpmlFHUQLPU9MfOaYBmrBZT+7FVKiCW8E8GQ8iTTfTPF+pWEu3pv2s3EFL+fC3nJU7QrHDy+LnTk5cSxc5Aw7oRAAzQCNAkJO7ZibO+oZErE1gkPuytrjWinv87bV4zyde3fMKlxLh7ZSk1ZoMVN2Dti0dQI6W0gt1yT0ptTUT2r6+bYa6k8EmISkIe1hAI/pkgLDTQU5uU3a1Oq2d7O3MgDIEYGu3MZJgNFnTbkICUR98JuqXT6WI+2t2gZXPfSAUE2Id5LimlLo+7hIiuzryzyljdYoC2tufHc3iHel5xBrZcklbjMTONzDQcUkfdB1jZfIdGPb9kupVkG+ucS786fNVQ+hXPTNBZGPY0o+51kVHCdEOA3U7teDejF4wt+AWri1WId7zjWniaD8z2AnYyzEOq4uBt1gD2RItCbqHYfDzOKbpj31Q3IK/7I8nsLZ9cMrcRVlYFuMyaq0Yx1FACJHfa3OTx/A0C0Pup3lEGMixMWxsFv1+LpZlG2T3ALxxJBpnqGtZ+oy0xro5b/0+CdoRbt42tpHA2USGvGb6+v26RsggxH6IcQJCl6S0Dwm/4RQrFON2duwphROQspfklyFRDV+qPRD7/1USbTH+k0e6Xy/ba3lrn34kTcj0jKM/xoe7fYSkjEh7fGuNID3nJC7mDgzcfI+74qH/6efSmo6Iu3EOtyzWUPCn036EZpbFs7FXs0xhNGtus56zlXPhgc2Vh2lb8iLq9pYNd1qcbtXzcThtHoPWGpjM6zPTXK/HQXaoN6Z5xjyzA7NpaphmAXfTZsZmM2GaZ09PwAy/n1nzh05N3SzJ7zkrF0Y5s9BdIKXUAfuHh2BmDMMgvuC1Yljtg4gwydl/VALqakRrDRMDe8MoIHBzgk1rwDwDtUJMCBWSCkEj8hFhGEc0np0Y1loxTxNaaxiGAXv7KwAAqWBmtM2jO0KiXRpBW+3tYX2yxjRPGpQCyByOKCfyRmLE8IStoqVMgDNrzhIIjRxq5vokVoN8fiTocghjIVAKsRbtGKfzdxb5yoTDqCOEVtHgW8ATQAJGLN1gZUwFPG421nw5WySeFXNqE6G1Wc8QsYKzis1mg7lFrr8u6XzqD1oTF6lSUMnSE6j2UjmWW1YRAoC9/zQhtxeGy1YCV6/HGJHVozNLaS6R3sms1itE5NS4N1zB7LdZ6LbBH1nnwAQUCQnqmlhZIlmR4X92dbDODaU+mIY799a6moVOsehVvyesv837mZ9ddMCkttCCY7cA3FuIFlV4x2KGPYWHAof8jkak8QIC/AXo7N8pddtaV0VB7fea5MKz4DARfIDKtqAlSiCZBOtTSy8l70cE0pF5lPdt1mvTcaCUgtVq5aHYSzOB3NZ2zLHVblr+TvhLgDUELkpjSxIUqLArrtx9FAHexWUqdK8SdEEWpyWA97Wsa6Op1Y6KWGkkKITRQq1H6a2BNDv7VIcBVc8eEpHn5pP9O3mAKGmLzLGcn47gNMys527lzNxYK4Zafa/bnrB1FzK0QbklmEngntJlDdq09Sz1YGyn4J4qWr7P5yjtgw8H7hwU6Vm8rh20BJXaUmJkC//poI62gOGuEm2kvv+pfiQemteqAYBSSwd45LlwZSwk6ThmzPjAx/4zfNzLXolPeN5v4c1f82hM04RhUD5WA6y2ri0ERoGlQDLPIeNFriClAkacA2cF2qbAysocABrMC15XqcK/AagVnjBrEDQH24j7l3IFKGiuWeiEH8o6lmuSu7LWCjCLjAQ5L0qpX8bPp2lywCnXRXkmwLrh+PwxhmEfRAOmeQKmClpPus9mnJysdcxWWK32MDPj3PERhkG8OeaJcXS0BlBweNE+qLDk9j0rF0Q5A3QXSClEGMcBjduW5suKEfdlgI9M7MxfWxheVT4joA5Qgjyz32/PGkkR4t0zOmMoJoBVd8+RRJpCD0OYypafrE2TEuJAZm4OBBbjIo+xC9mGE6QtvaSeeSuiSb2Ahgxqclv9jcjuayIIBoAh7y/UvTWsaG71XLJtSteWcosJ/AxnfkQRkptcgFYBFFAhI7qfed0Wa+A0EGxif/RtaQ2y8VlaV7aqNBeyXHw8sVVvZyVgwNwodwkx3VyFOOXfsc29yV5Wz1aKCu+owZ00aBIYxb4zkOVr3p5tMT9+xsb++ToTxp/3YzUAQYzSYvD7Ne4zEe1YlBzaP4+jPb9c40R+1t/bkgWxbI0zwd5AaD9k/TjaPuwtuwWWBzKDw2Ect8BTttBJP9ij2QLQ/FUZOKf9DHT0zmaRYgHA8qF1tkjfhCE852izBua8TrYkx9DIrZGaorHksWutaboYpUMqTIpyRoOYqHVWpcAO6HjfOe2eJAjD+5A6qn1hoxE6nzXtIXtAIgZOvkcsBUu3jlhFdrOMqJVZLM3QYCg2ZgGUjYZlZY12CN1atAan6fFdY+xgsdqtndbvoAn2Koo9a+UjTSruo5PoD4y2bD+fgaRRzG2SoqDIGqj0werzuhfXrcpE7rzPrpDAIum3rxWjAaTrIRaIvy/tGSIChgEfuP/98FFvvAZ/n/Zk5n2hjDRWEefJLEjaElD5S0yx5u2UtWBRlk/jMdDxM35X9Xy/aj19fHj5Wl17THpcHxn0igVN7otk5PYeUWKoZXIYQnlBpIqZKb2moBZRFpW5oZaiwYzgvMbHBiI3ZRo7TZO/c5pmH2eLbDlNovSJPLpn5UIoZ4DuAilUCupQgDmIk/liW5jhgQfXmpG5LRhDpwLBFwyodo1K1Shtok0TJViR8ON2rsMIXwcOE1NL11lzzJh1qRTCoBEvnf8aM3ZpxYBaFg6tzRqgBMq0TyNsDkoyiFsCs170ABLTc6ZkglFLbZAXGHMMALdoggvOqp0004sBOH1OhKWFQOwAO+4LWTONjA+EjX8wRG4WoMFAnT2fhiQxOFqMRoAA8jo6QJGB5kKQXwIumJb7NGHKB9vGzSxVvLUudr1zWWQKs6BugmZ87q19p9XVP5d65EJnvHTZAP2e7RdrnttwmbJ1VEooSCRoRBK8rZ19D21EOrDt8IZEiJNmWP6oHpC46EyS35AZrg3XlsX6YXRrPAtEMZ7J2mlQifuhzWs8QNLuACghRMLHIp81jP0t9Rb/ZKBzTv0lpzMmztoQGN0yMNIDAwJaXkPLyQ7AakK0uExCo9dJmHXimCfmhsazWPYKQI1SdMqF0iPRi24tpu5bc2ObZOWYXiohoFrHw62tOUC34BjIb+NoU6FQypnLXIxjPLdAavFn6l3uKaV7yPtqN26/g/N/Nqcc9xgttHkj9BEvY3iXLYg1tAXc8tr3KJpqZ6XUgzwW1I3KKX8nmrv4Nm4POpBv7HiSV5XpuF7MygCyvaypSrikdgulP7riclzy3veLvEBqcSJGaQwUUg8RXdMpYmnmr97/pDxwJQVR11xCKNcC1On1YA0giuisRRXJBcEcfQf5vo5VxyzgPsBmojWN0UrrJsBH0CN1V/UQklvEMCjv8JgEkL1RK2HmGWBzWZWcsMNQXQkyDBUmZ9icCd9mbDYbEAG1DuBGmCbGZt0wbTTFy9nJqgumnAG6C6QUc71pM6bNjDpUDKsBdRowzcc4WR9jtb/CuFphHFeYphk8NXGnZEIpA+ZpFreqOohbJAPHR0egUrAa9wE0rI8kD10lwmpcofEsdUEIYmi44MSRSM73TZMKC8oqhqphrgeJjkYQwavQ4Em7JXhKhDcGJ9fJJNw4zDDBH/CAETNM8CNhOEvpB1C3xCYMjcSdow4V0zz7WScqEoiiMatlUdiQCWCkxxXb3FwbZ/zFBJMCOQzOLoVJA2qp4HnWaKOA5d0B54AqEuCBW5N5soAPVfvdglllax1BLARtkvx7YLMKFg9iUFwOyJJ6Er8M2CJ4drhNhvSUE7GHvJG1v1lo6SUqE7hNcylrqvl1fwdth7HPYqLXB9YQ0WH5DGsh+Rpw8FEyc0/tS0jEBDxbZyJYBNc366gDUX9brAKwgCNzH0UMtysRGofli9J5kwyUHFjLQElrKL/Pmh3KCWYC1MKuXrcwy2cHaNnOaelaniyhdPHhEKuSuRzn+Yzzl5GvMYM+A2s2f7pfC4G5+hzZuHqyXmYwh1YeSi/anM72ABhqifxUrWmuNBtrFT6ZA4As2pB74oXyOmCNrGmiVNTjyhCKcWBA3KuQcto1whyGFDCagxUTRNtseTwDxDCM2lmyYw1bxEZni+53EbbDS8NVOSIsFwmlLv1smBvibBII4WUgv+dpcoHTFBEisopbrQdPggrEAMwToOgz0U+4u3xa/j7nLrjnPWOd1z5w2pMGPoyeU34mTaYrBg2sKKhLuDYoSNJ0MWLuC5kFln2+rQ+iLCGNfpsAtAf3sMotrU2y3NmYMtB51Wgr+tQ8OofI/U90CLzoU9DFAAxpOAFVeCSFhCmPAKwvOsB4dIT/6xd+GX/1xMejFVG8zMTO50HCH2uRXHUoEn2RSkHhyCvZKWo0mFkpQ8y7rx1TT0nQMzsnJ4pmWVCMOHfvVkwiXPeLvyZ9ZdlTxOKaaf1tLKC0DgVlqBgL6VxKDlaQBnUpRs9VEQOhxVSLjn8JTsYNKEUAViFQE347jANQGSfTBpvNWunShFqAg4MV6jiCQdjfHzUdwQSiEauVgL1pnjBtZE8NIwOQICknaBhHxjgCtezhrFwY5QzQXSDFwARzw9wmBUNioWOwCxTDMGqUywrGJgm6FRNmSPoXCZxS66wgqKDUwbWP8yyCkljo5DzHzXe6GKtxjBC6rK5DEGZTjKsnrV3VABxDlXMYpikshTBzuCuZENtZiVyoDxHHGRcHgzP+1WvxE0PTxmSXJ9PaURFrJBVCJbgg1FpDxcL9ywQMZQAGzPwViDYVKhKpLlnpaqkutNoTds4FTZiFCDokgh4BqOpSZ3m4omt+r1sLmMGzHKS073LUTRPUYmAiXL7hOTXQ+riz/2/9S+/0siUax1XacS2kLzl/lAUhCmDYvYF3vyMLSb2QGkAHFNrgZdsdpOgYdgJeNGlRJ7zNvXthEt71+y6yWkh/AaIskiFXOyLoc+VAiHXN+RjpmjdtsQm6aTxymG6zwrACOEtmbffZupLPAaT1ZSC3HoblzsbZLHUC1Pp0H30dOdKsfJfTFQggjPxO9r2BY+YWwrWCjqL70CJNEjHQzO07LKFZwCXd48sl60FVSOprTIDm7wvtOHvOORt/gkbE07k2YGCgRgwc1j8RfkNxFYqifiPamAFAKGxiHIvSv4YCc7uvAMRSGPteNpGtMVaabhaEDnuznNGrVebT7DEEBWtkv22vGdhJ69VodVIWJcyh42Vr10DIAphpc8gqtvm2MbFxSGAKi+f7q6QYmv1zAMIgMqYsLAglnj+leyOubr8j3hM3Oak2upKsZgw43fbP3XdpNCh6jdyK3C5fI/D2x0o1gCX7S85VFnX/k2fmvRU+eL/74rLr3qWBkuD7LfIjsrohFufzbvWdZ5QSSmd5H0u7CjlgAysW7Dup7U770GgTy7s8ZpreI5GejTs1zExAmwDOZ1AbVnsDTNm8syR+HnJLUnp5V/U7BXmmSKZZlJNVx3xuM6Z5wjxt0HhGrYRxqJgB7K0GYLPBejMBxKhVlWfThGnaYKgDamFJMdXkLN08sbo8j7vbf1bucOUM0F0ghcGoQ0WdK2qbQYXReNJgBNWDfzAzxnH0wBtWCg0AT2D10R4mRi0rjOO+WI8agSphf38f65N9jMMIl/QJeM0jH4yLLz7EgQI6jVjuDL21pmc3ND2CapMLAcNQsL+/wjQ3zHNw+uBbHBo8FWpcIa/MxSEFhSjgAEpBSLYatLmJUFJE6DUB0gUOZSjTPLvGtJCArHmakAVLCa4gTIw0YiQYmNX33fog2nsBsjyrkFcauKlmfSIRQPV6IULj2Rmo9c2AgrtNaWS9Mugh9Lli02a0eRZtIkyoEs1wLQYul2ctfEB70MTkdYSgQTHBNt6mAUcAFAMuxfz4toC5/RkCmQCamNe4R//zJZKjhm6LU51GOwEJB1gG4koJjXc3X+iYeRbwQPA52AKCLYQds4AysAVKcpNtTjMYNDE4ntH9sdVHwFJ/WF9duB8GP1/WGmNuDdM0OU1gBUSzJrw14VUARwMlKy7Iwon37U6tcTAnwpy0OaclsUiW5jos94X7n7hStnR/uAPmfHTZimf7wITHeZ5h1qpS5Gzx8bEELcAs3gQFEpxpmmbMVRQpDRxpINKai/UiP+LCPiX4mSxvviZ0ftUVjxFA3qV5faf9TbbJdI2Z1cRuyUK5jwMVDWSkud8Q1hsG3EIXyglAglGIYDur+3weuy6vFccfEtyhOWBeDVWVcRJYSaz/EZylW4e64B1O9GgORAgLjNORpXLodkp3m/sE+GfjG76HTei2Oe7ujqcN+FrgJCgoFpDGW3HEjQ6CAjYxEm2xpWV0S8elK8z9fPtlBUpGt4gc3AYc3B4YWoyNMgOYdUvoqKZQ0XazK1Okjlvv/lG40zveiQf/4n/FNd/57QLsKcBRSzkg4WfDSddTc8VCqavolCcWjzO4rB48BdXHws7tCT1Rq3OtGECoLMqFpkobKoRVXXm75nnGZj2p55CBfdkTm82mo9+9QiRoa6bvFsWWmTsw56Ot9xXlKTw1tLmhEmGshHlquOXmmzRoGePiSy/BweEhLr74AOUImOYN0GbM04y9/REzz9jMM4ahYrW3Ajdgs55AKjetVhV1OBPzL5RyNtMXSCGCC2mzgpB8risLPZmAmcAbjD80a5ZawDXkGu57tRr1ELK/XQWYlM9Fmbq5x1lENUDPt5SGxnqIvhR1iZjBrBHeQhmnzC0YU7YCWMkC4ZI/ipBgrkShpYTxY7Lw5blHyr8XwWOWQSY6YKXP+GFmjrw4opVnFxBpVgGvNXARN9fonwjZ5u7hUqD7Ldm77Y3afxW0zMrQwJ5DzAS8OL2Tzzj5KPpP0ukicTgfw4WI6XObBWCrMwAK+ec80lmQje6dJqCYwBV979sf16lrcw/qkMDb9hgs/neMn0DrQghc9mvZ+rxmWAW2bTkuBMBo17Ld27VbUJFOENd1OSRFgEVHNMCzPPfWj8IOgJzalF6TXC/FpZPSGoizgbYPvSZ/Fn7iTddRQzdWkdokaFP+3tqfwd+SxpnSxca+saVPURfOUkBGo5IA14EsMnc4OQ+TR8ItDhQgP4MxZoDJhNfi3+W5t71uAn8Em9F6yCJTpmWQoih2a8TAynKPMLpxFHdVce+0dBYOTmPWAejYsgR4EEuIBkNJkUuXMWWDx8T+lzOERi/TPJUFmHP007cfRn9sILrux3sCvRl46Smbt3Hryrag7vs9D7G1cXGft9N/pci/gK+x5SPyIdafrYNub24zN7gXxs4at3vLbPvb1nWiMbrecl1EQFvt4dydr8R4fKJzFe8F4NZp4UN2oo629iuoRX8oA2etivoxlSVu9FKDDun1Uqqf5wPNrri68488FQDwvqf+kAdi88TfCJdta1ekW0h7vme10ZpTAFymNdZnpxWQIxp1KKA1cHJyhFIJ+/srrFYrHBwcYDWOWCvAZIiCSPJ2FuftluuRXeHFYvncXr5n5Q5azgDdBVPCEjdNU4AwBOgAoN/1EeNE2yO5oXJkOdOmM2vo7KF4HimLFpbYdAJ0iVkrExQCJ6DFcqwUaiCI1QuDukPM6kMP+48dCGVuuRSeA1AR0LnWmYC5FJB78f80TbBb3tI4hvumunaRhktO15pyBWHe7Ofb5PucoD27f5ELH2GF4B0abReJ/XMHME2YVrDYiXYOTqweHR89GBfMM8kchEgW7GO3LZDQDvmrG0cC0CVjXtZgf+f+UvzN6AIQxHu332qCeG+l29E6A6JdY+ECUm6puMcllTxlwNLXsQ3CtOoE7PL3Aebsf+r6kBvH3RzGvBAsoAbUNZDR7HkKi1gHONCvGW8jRHjv3xzrJe41EGN/G0UI4B97NQvbeaxioXmKEr3kofYTbcrjaJ8N9AFhEQ6hqqeBInOyK6wKmRU11kn8+ED7GUIA4Da7wO3zp0BSrGVF3BdZ+mU0ikHdWVfoXqeFEkOs6RGVRua0oZGlI9HbWSQ61r3hwDDV1PR9bbGm53nGrGlPHNx1wrcBsNQqnUIi8tyVpO6vlPZtT3cz3aaFIN+PtyeBV9pm9xnY7cFb/Kbl9VP+3kX7/Y9MZ5xe9XQ2bo/2L0vsZdbnEW6PBtiWDy0AnPMk3ZvW/xyII/8whbUOecy8UUFbjFNuNyKB4B2fNxddhMve+S7Uo2O0w0NfB513ArO6OauyJp2dzXtWnotZcGUPLxV+iWrYs3pdrH8TmKC5deWe4dq3A6xpDiBAaCwDJPqnWenEAt4pY20OHMxZu3NLouR+U+kVu+bVYLTV8rsSAZuTNUopODo6j/2DfUybizDs7cvxk6GiEJJCHZCD4MZn5JxdJ2udxnTPyh2unAG6C6iYC5VodhTQJWbZ1N2KjMBoIk4iQlWgNqk7oYGMUirmecI0TWhjxWpUVy1n/EJQHvmcV6KWglc94ZHRIEKcSXGAoIyaACrihF6IQJXQ5hJn7Sh4rOmgnRlzvMCYpjAJdIw53xc/Lqc4cOqYUrZawIQw/ZwAnTFYuzYp8wCkX8W0f9ZZRLvcZUffz41dCCQFxtwYiDRlIRxk1KRDBdj37EwWCAZo2mn47xgHE7i0G7DBAAAgAElEQVRCGCOTHl1+MuEiC95LvEKLMd5ZUr35/S64EZANFztrSqCuFygSc10IibvuiQFcXLOxTm2wKGkWlCSvOYZZUfJg9BZBA1I9mFu81ucqC5BL8BSNzICDiFAtVHgjPb8pGy7qlHotShvQn+GzwEPWFj+/la7J83lkbPiKtiksdLv7mMch94lTXb0gb/vLaFV2W81umDH01PUtA9iw9CEAnQU4oESX8rpJwY+KClxSf+0wBcshIQc6VIq7sFoPbY+2IvV1Aq7uUwNNZqU3Eht1xH4U+icu2wwGUo4uGJ1gyUXXDNAxQBod2NzhjN50YC7NeRbrbR0ZuDWalYVdG0M5V1f0W5tXhrihsgvWWwDa6EgmMgZW8h7pl2L0OdMnb3za68sFqustR750JRot3rV47rSSaUgGIVuPJIBm4C36EsoYf24J2PP3u1Atp7UHuGKBFv0KmnyKxReEm+57NS5913tw2TXX4EMPfjBsuHpwBt9f8O/ye6IdJYE7z+GKnBJkd7G9b3nfKoChjhp4bVJrIbtreR0G7O3ta+3hqbTebLYAubeO0e0FW5s5pJZdz/3svASSu7NYsmVPzPMG6w3h+PhIftbHOFytxD18GCTMMDQgnAF1bipzzZjmjchyswQzOt3d9qzc0coZoLtACjc9T1GqHoKX4CW1DC4QAaK1Wq1WKKW6gENEGm1SDs8vNebzzJowcwCtBtRhkGTi0wwyxoz+nJDUqwDFaaYSbbIoi0rsSwjMEuxgTkJLABXvqzOkYFDh0rdkHpnY5c9JcJIG5xdoc3tiv7Rk2D3u8qKCdOR+0z4sFZ+pmUtQ6WAMeVzZgYZdO1WY8Lr0Y2NwCeYKGzsXJJIwpVYGGZuoI6wbp2kDs3C/+7vUPCwhG/l3O6BcAjEu0Gp88G6M0xrrtP22DnVMekFhycyT5AwDcwZVTcCCCKTG+r0/KmZmITSBoe1h0bldgDwJNGRuNFlQzu/rqgGgfbXgLsuca/YODbph1q7Ogp8s9o0bSitolM62MHsevW6QUjvCQrfcQtEPWWKMfNYu7pN6l6ACCEudCUyhocainm236OX+krNg4WoV0WBDqLR6DNQZoBO6yWhzhVuatC4YPfUE27SYPVljBUErOP3tIM+Ct7AJ2FEJtxnJviXnmAxSkZ5x1Ii4QWMMpOfZ494il8D2acUAvQE5O1dJaW6DqoQQbCsgT7TRsI7++I0B6Ejr7cEZukoZ5G0J8BMvzlX6+/0Vmf71rqC2nqJ9HwbYJfIl60L+tvnqwM0OYnkaSZe6k3WVk6UubTTjwdZhYu48GZa0z4G/N558rP2rvC9BuOneV+OTfv5ZeOUv/hzawX4nK8g74iyogyDnh8nNm9V7oMSgmaUXYFjcr5ADtseitYZpM0GiRJIrtLtbU189kFqLSKJZqeIKDEbwczDmmYP3l3DVNIZifTPahNRmW3L+mwBozrrN+kQA3fnzWO0fAASMq9FvlKB2BnYB1rQHkuZE6pjneZspnJU7bDkDdBdIOTlZg5lQy4Chjn4YeDxcYdREvczicnnRRRdhf38fQAhCq70RIMZ6vZH0BRr8oNaCaZLDupupAjRiGEe0uWFqa4i3ZFXiBmw2G4CVYJaqSXTTGQLSyHtFiGUtNRKO14JxHLBez3qwX+6R6HvBeISwqXVCgY4l5zW+71qyrB2EWauUslo4dP0+BFqN4GYH/YHOFz8zA6uLAbdaWvJRBxGEcIPkAGXZUiLJSiWgSdaUd4xHQpCKVYEk2qW5ehjgmlXILaYZ54Y2M6hI0AGAMZSCqvNgUbgsnYHBAGfTBo5KSZBqWWjxO31jwgWZ21B8Zzwxl6XMtgVkCC5cdVpRn78Y+1KKSyXRDnu3WUS08hQyXu904TCirDbkmCQMA4lpjQmCUmEcvdIAy5DksSbidy8guICBcNHL/XGlRdF1wTZX0phZU2GYFagU7hQ5nSVKpd/SClppKFy7GQnLb25PzGGMRQCDiHIZ1zmkzn6mDcDw9s8uTX8GeAbuaq3Y29vrgnuY14KPMTXw3CRtip4B64Cd7odCBVRDmRH3pLp0LIgKuM7eZyJCqdzNPbpuB4jrx8VAHbpExbaOJJVBD3htz7vShyjOPnNqQ6JB2SIcehrtu9oh3CtA576WgkHzZ40Wnl3vI1NmkbqmkuTgypSB8l5M/MD2dEJZikkMYASi497XOuorsV/9jcYM8v0O4pBynXX5I4SGc7jqLhVtp5YMEB1Qaj9daRClU1zoOnYQk++Tm52v6cPxXe5vAhI5uiWI3KJmtFIUHzau9lLL/ab7VmszkHPTPe+OK9/yVjzgl34Zf/3Nj5cgYLWCLLF3NEH3AEUydyK0FhFf9XXK/9hdRl0RQDGHYSkPr4PWGqaTE9Q24+DwEKKYHpxX1VrBAKbNBseQM3em4F4Gs3IaQnAwFz+z8/WhFrWOzaiUAjclBZkpyySo0QzLNck8awAjoLUJx0fnAWKJeLm3wt7BAQ4P92BBi0qpEixu2tcAcg00AGUsYGpYT8c4Pi4ApbPTZ+UOXc4A3QVSpsT8HZgoUDCBZppmDT9dMY4DWlths9nA3JLkDF7DPPWAwiM2waJJpTNgIPdDYNVmWRuyAEbGnO0zSImbaMwaCzixCHjO3104zMJIA7jAzzO5dlnfyeHmRgvOmJmmMVFOlgp7Rwjzek1dKEzYy4zSq+803L0w0wlTKiW5tUF1uIUkj0+uJyLWsTKV4udMGjcULi5ACZObPZooFdKoYYzK0XaZUxvjxEC1sZoeqNMquhXylPWXJnb70gK17QJyLpowdn0ZbUPf3mXdp10PMGSfkwXHJb/T+pEAl2uwQyA14JbvUzFdgSJ1XeqBUawD+7to2HA/66YCVU70nEEdAA9K4G2CrG+VoES5ofXUKoqODOy8w+y1p4Al6O7r27EYtsVY+NqB5d6KMe3an0Bi3of5J49dbtMS0OUw5Evgt+t539N5rXfCv/U7xryUCgtOAJbkwVxCKJf77Rwdd+spmmCDtW1NxGKPGD2bMad9SGrNs7yXnPoofbCIoQCpi3tYOA0gRHvhigwg3Jqlzaxu+sWjh1LfOJgygrD0ZDD6nS1xMb7o3msvjCHqtuaCNGRwuGOAd9Ij1md6+Jfem95p7fM25i4tS14vqU9Z6RTPLwBZ2lA2Twui0VvjqG+916XzyUTdd5T6wOmC7Ndwq7X17b9TG1mVEO/7xE/EXf/qjZimGaXKnFfNJRcvy+MXsoCTgG5v994CpvIMACt0113eOdIlNNF8YL1ei4uiyirEmvt2llQB0zxjGEaMA7Barbozt0CiNbQ9sdki1ygAGwjOTxtvAzpukgOztQaeZz1jq/uzNUzzBuu1nKU7WR9jWI3Yp33JhadKudVqwP7+ns/JOFSsVhUbEvfLeV5jGSDurNxxyxmgu0CK5LWU0MOzutJM0+zul8xx3TRZEvFuwjSJhidcI5pr7izB9jAMAhDYGI5pNYMJyzvmjnG5MOZCK3ca0VIrGDMwqQtmrYmXhXUiflQIWTCuDkaFpAETIpaFlEFuWQAM4NlBf73WWtM8bH1ErBBmor+mqRbmxE74jUGZEFVIzra4ZaaIRpNaAnoqbIpWswGqObWwzPJ9RVEhVlIVRKCHGdD+wK/F78R7Y3hdWHPgmgBHL5nmie6GPI3H4h0+hws5LJDAdiU2DyaIZSGpE4x6kOPz0VmTAiy0/D4DaLkFLA5ymp3chWATpXpwAN8zfcOt+h2S5aJ4eoxigI5knznYCRCeLcDyO87AdeOfwQ0CxGRLM4CtPFmgFKo99TcshnZztGspfRsIWYKyPHZ5GzmwofS+HeO2rGtX2al9t/ektRAKAh1DE3S9ojx31ndLcxJjQKUAXFSQM2VMQdEckdmw1Dd0+6Mpjiw3mLXGcWEC9ZY7E4U9LYWDIwWGgucSTdK95sCKU0Nsz+s5N8ijumYs1UxSaqUBNXpJfSO3t3MCxh3w8UtpMXZrLVUWbCfvdizXYDxJ4YLI+e4U8r8jbf3E+HrbscWjHdEuB6qkQBqIhOxZKRNv794dcDM3iqLetG5juJQW2vxu7Z1tumWXJUF83jc7eKa++/ydLkeZJrQ2AxRKiACuse/Mg8TeWXJ6g2I0HArqtI+ijfQxbzxrTsXkWQCAiDErLViv1yCSoG3L/c1sis4CrpESpaN/iZ/msZXrS36C4GXGg3jxPYxONYAbCtk5ugICozWN5g2ReU6OjzGOKwzDiL39PYxjwdwk5cr+wb5bALkQGq/kmB0zprY5hbCclTtiOQN0F1ARrVPBMEgiWGByTZTlcIkcTRXjCJycHHcufgZCmBskwaW410zjAEsManm7Qrguzpq60Okg1RwLM7CkvnZmztrMrWEGuwYuGIsJjCa0szNE0zKGN44JLNvMOIo+qK6U7ARbI0oBobVOFjkkYg/mhTBjPU2CZh5LF+4ULJrGnPTa7C0DkYHqaG8phJbGsSrww9w8ShdVQlFhcm45aXQBeNJ3Lq1zlp9vIWtBrbIIYZt89G+nuGBow8x+uRv/6G28Md90ytSRg7mUM85qYzkfVIqAi6J5B1mBXLiz9cIMp6BBIS0HwvCkw9ofz31IUMMVu2x5WsNzlUuNcN+/ELbEpdZcnkyCpHRv6QAdoJZtmFssebvsyWS/3wnomvXR+hQH+fr2IS/701dEBnMWft8BSgJIJtDZPm9NlEgmTOXzcLt+TitZICOKiL957HswZ4Jisk4k4S4/W0rQOxuFWqp/ntUqV6igFVbN/M5R8rFymZxin7bkEQB/n0mOpDS1xXvnBp6t7WFZBbYDkHBe9+jBmPWNDOXrUqhUNJGxKhuwvYbd0on09c6+97vGwGW3r/V/1kHi7ptMnPKLOIjpYqwV13qgXYKmdoElS+/fn1/X7YtFN7IixevwPa/KvAWYi6Xbv9HBbd4j/cvS+ozvu5nQ4XHLbCZCWIK1oDtOT3bNF6U/hEmC1xvwfpxtDXoSyktLxm4/FSnCbtIoGvhR9uxW9qaJ7/3tDmJFPihqod6sN2AW69ttD3u4g+gg5zkJupQclTLaEEcm7JoHYzI55MMokzr6xJLCoRZyF28Cg9uMaZIIs1QK1kfHOB5GcQsdCvYPR8xNAt0VDfYyTRNI3eBLAY6PjzG1lgJVnZU7ejkDdBdIEZfJwYnPRiM4ZYBkkaHMFXMY4MR1F2Ez4McsycihgrGH2AcMQTnT9fMcIaIAUDfNJiDRHgMkyfZs2jsVZp1JW+AESO4mbVynYeYlo6IkzLJdD8HLwAmV4hY6ryGNBRvT0Oe6EOhlQUE5celO8IAKCiKExzgH4AsrUzDFENQTA/MeLJ5zZiqg3c7xiXClLXAXVXLtulvorJWsZxjAyXoXAp+B0A5Y9KPQC2Dd8MT47+KFJtrZWPGO74SJp4iE3bk1A2yhACCV3AwkZIVFBk+hlLB10/cqovOFxcKFBAN7/m4tCohDqKT09/a4eFtga1Br51Aw9PcuBDAbH4avJZuunEcxy8Fbe37RnjwMYVUmFxRFo25jalY6xuOf/L07+iZj9FV/8BJ85l+9AQDw6gd9Cn7jC/51RyVgbSLgWT/+o7jyy74cl3725+KmSy7B7990I5773ve4vG73PvQNf4lvOjrCnb/4SzDt7eFvDg/xo//wj7h12oABPPLOd8aX3/VuaMy48vr3413PeDpuftMb8aIv/TJ8waMfg8+87DLceW8Pn/5Hf4Tz0wYgwp2vvRZf+bQf8PY/45d+Jc8azILBzPjc5z4HD/zjV4FKwZs+81/i5V/5Vd1ay/vh27/+a7yO3/iPP4Tr73VvdOtG//6kV78Kj3jerwJgXH/1ffGCH/iREHybJ3UBAHzFD34f7vQPbwOB8Opv+Dpc81mfg1xs7q58+z/hS773Kb4Mf+2FL8LWZtPysGc/G/d/xcsBMN78+Y/Aa7/xGzvaQQlUfPfjHi19BfBrP/CjuP7e9/HPuXzKn7wKX/i8XwUAvOde98azv/dpizuC5n3TT/4w7v7OawEAv/uVX4O//Ix/mTvkY3G3d16HJ/ynHwZIAMT3PfPZ253R8sW/9Tz8iz99NZgIf/7pD8PvfvljHERGe2V9P/27/r134Kef9GS8+x737PaOlYe8/rX48t95ARiMd939XviZJ303UmUAgJ/5nm/vlBtOCxnIdH5JV09Tmsheys/J3lMms2M+lapmcMdGaQHzry9+BjH4eo/Hjb8CbRhw/sor8Tk/+XS88vu/V28PumrPWV/7M80p3y1RdzbOnnGPntaQ3THdEugWP5Zz4QnAttbwocd8rfNbgqZFQshAm83GP+9UDCX6mpVKdl2ULQ1+VrYUMBqoLcGx7RXhXYyKYRC1cZtnCSzHjDoNOFmvUY6PgUIY9wcAB1BHIVR1fWeuOk8NjBnHJ3qm9szl8oIpZ4DuAilmnSulYrVaYZ5nrNcbJYaEcRwd7J2cnGAcRwdswzBgvT7B3t4+9vb2ME0TNpsN1us19vf3UMoKrJGZLKHsMI7Y29/HNG0wtYa/fdgnoE0ThmEFAB3jMoFTNKTh+kMkLgXcGuaJPHHmajXo+5o4u80E0qAGBrKoFJQqAVXMwkckvvwSaEWYQQDT4udJ5IySCEebeUKDubkRiEkPMwMEOY8zt1mTtRNQq4InsYYNdUCp5gZpzGfhwoleCF+GB88WBGcYFmAln6VKmlAD5o2bu+gxm4VUgxOoe1TTiRAtu+lPIYCnzWgkth0gC2wU+I0BS+qqU+B/57ItbPT3hQBFSSngkNKBmTF5kVHSOS+y+TdgEePnwIAj/LoLUoh7c7REkCgR5FB/RjBJAEOcT3IQ6e3prTduBYEKnQ4QaUvOChDeumumLJC51CiTLhyYdXXbQmeAGIxw401jQYC6OKVoll3QIEepPh+GnrztFH004ZBZXLuZGU946vcDSaFjVXc4MY+Zz00oDWxu9u7/AFzy0M/Add/5JPzkY74GT3n4Z+FNt96KN912G0yCYwB3vvwK3PVRX4G/++ZvwD8eHOKGH/lxPP6e98R/fvs/4bJhwLfe+z74d3/1BtywXuPHXvsnePB3fjf+11d/JbgxXvy+9+EZ//A2vOyhn9EtZyLCoAEVrPHZZdqmV65rHjaPpBqCqa8VvT9y6Vl+gTTuOvah3LF3yBgVn+Z83omwGuU8NFH1XKJuUUIIrEUDVBGRuL3Rcp9m8T0pVkxhsKO5BLHaEUXE4l4hwr5mDAwuquiGwVrQEGeUthDKDsXIUom2q7A+S96b1ERrgG3vdG652x4LTRMhFHB1qLHe+6YlWrTcC1JRpqext5I7Oef7+7pDEaQ8ws+3mkJIXhrKhQBm1pEYlQTIkmWMunmTtfOBj7kvPurv39KlD3A+RXbuV0P3t+p0N1vFzLYc+yH2UOfpUhbXW1PvGpmrikGU2ap8Xp+sA/QpvxS6akdPhF6Nq6rjGClQpmnCWCWFk8lMfiaXGbUWmKbN3CDtOIR5Q1lAplJkfwKMk/Ua4BlDrVgNA9aFcNIkDySIcNONN2K9WWM9rTGuRhxedBHWE2Nvb8A4Vsg5xyqAb9zDalUwtxOcnJxgMx3jrFwYhT6cefh2Hz47bfl/TPmub3s0HvzPP9GjPB0dHeHWW2/F4eGhM/pbbrkZN998My6//HKMo+Rt2Ww2/nPZZZdhGAacP38eR0dHaK3hqquu8vrmeUKthGGsmDYbTJs1zp87B543WI2DsAVueOx/fC7e/pmfCDo8cIBh7yIqGMYhgRTg+OQEx0dH0EgeuO38Cc6dP8Lx0bEESyHC4cFFmFVwJJIzgKu9PazXa7R5BreGYajY21+hQIjqNE+otXg6hmmeAGbs7YtP+ma9xsn6BABjtdpTYCWuEBJxc6UC64TNZsJqtcJqtcJ6fYLNZoN5bn7A+vj4SIl4xeHhIUohnLvtPKaNOLsZw835tHIUvoODA2dY6/Ua0zT5vNk1s5SWUrDZbHB0dIRxHHF40cUgKj6PhUjcR7lhfXKMSa8d7u9jUIZEBFQiDDUi0lVlfsMiOh2ABXNPAKu7K5UkCXWgwYFtUUAgtbcm8yNjNPh5iZKip8md/Ts7SzFC+MlGqSw0ZTdDkAA8G9Ns+ZkVCLXE7K0v7hZVUmoEawtRL0zovE9zADd3g1bhIoO6WiVirCV7ZmZQqRqIwlKNxHoyUMfhEeSAjlk0wXlOejAYY6fTkKyOJtDFOBNF4mez0s0akGCeZ3zL9z8NAPDHD/k0fOAFv4mLH/QpqJdcgg/95vNw2+tfByLCx7zwv+OG334BDj75QagXX4L3P/c5uPm1r/GcaK017B/s427f/ETMH7geN//+74GIcOkj/y3Gu9wF1//Ks/39m80GF3/6Q3HF53we3vp934PWGg7vdz98/DN+Fm/4okdivOwyfNJzfgPXPOHxuPUd78BVn/+vcOdH/Cu86du+FY0Zc2OsN2s88g1vxPM//uNw2w03gErBam9PlSYNM4ugdnBw4LmrJDDIALNSMjdUiyqZAiHImJmiiZyWNM0NlwV0KhKBeNpsMI4Dhjpgmjfiss2QNVorps2M1mYQFY1eDKzXG1mbKrhKZNOGUqrTmfV6jWmeNVASOxhwwdnNKug+m2VuNVSMlTDW4pH6xmH0gEzmPWe/rWuWVHkphpS0RwwrNc7nWm29mmIp0SQKRZAVtzll8JH+tnfVfP5ZRs0VOr6fknIk9gG2sKV4uQxOB0wp1eaGb/uJnwEA/PRTvt3bu5TFunZQ7LN85myXFd/e3T3nAZQWbskxGjAw5uNHSCCq+HiZEieeTjRf/z644UZ89N+/Bf/fT/0oSilY7e1DUibZ+XqhKbVKmiNPEVL3vF+e6ZIIpQyaF1IU040teIt+XyuGYYR7usCMjgVUC4ZhJQre1jBc+w4QETb3vq/uCQFkQourt6UOceTCXBrb3DCOA1bjCnt7e6Jw1n0LZuGfAKbNhGmSiOAO3vYiF940TTg+PgJ4AoFx67nbcHR8glIKbrj5Ftx62znccts5TG1GGUbsXXQpLr70Elx6+WW4/MqrcKcrr8QMxsHBCvsHK0wTYzOJgnscCxrPuPXWW3F0dIQ3vv7P8KRHfRnOyv8ZhXnpt/2RlzML3QVStt2yaIthmLYpu0KY1tiiXdp1Ax1hOYLnY8qFXBsnwgsvGW3SvpuaU3JthdaQAFiIZEYEAqFC7sZgZxg63srxNifw7n6ibSZ7iL0e0QiyMwsDFTuByaKENjW7Rca1mIvU7hTMYjl2y3Gy6yYcLhl3vscZv7qDqASiN8hnF8TV+mmpC1TEUA11jmiXx2Fbn8Oq0eat+yi03d26y40G8hh3oItMSAnBNFuCuvvZ5rMXcKxt3Th5I7bnwAUwDaNtL4khlGd8DmCCTwaltCVEbq+i0C67EE2nCHgOumy9GngrizUQzzJTdz7E9gaAzj3Y2pyjQKZu98IrWVCUHtCZkNuydlon8KFv+Et59iGfBp4b3vGU78Le3e+Jq3/iJ3Hu765Bu+UWeVdreNdTn4LhrnfDvX7sJ3D+7/4WuPFGEeRUuBquvArn/uZNoqAoBSfvfz/27/8APwNsbTp++9tx+LEfh4vucU+cvO+9uMvnPQL18BDDpZdiuuUWvOOZP41P+MVfxubWW0BU8NdP/KawWJrkGrOUhGEZA8pBHKBRebWIsmHGPPfW85bAu9k9ggLp4KapNNcwUpqXQXRQLWytl3DttHUigIoLgZutXQJQUYcqpJEIKMEv3PCethR7sJeI4lfLMhJoALf899a6QtDC/jps0aWIjGEJTSO12FO7afQWmXF7EzlNovTj9yYQRz5bp5RdXxFu/5nTqtoB5qxkBU9uo7sc5n444LX92+NzIP6O1WR8GAC1jt4ER9Z+kdG9AHP4COTR3ZaAXolE6UytD4HSILG+FT+vHxZLOS5hqRUaCKx9NwXpvZ7+YyAC3v5fflUAIIK2GQ8QxWre13qmWPei0TiJRRAeNaGoEYDIxbwKTpPBRAFSS8VYK6hWjMMoP+MITJLeiZvk1Ds5Ec+ozTRh3FttH++A9UOV2pqQ/KxcGOUM0F0gRZjz0h+89xHPgC4DvOyjnpmGEMkJQHUtqwnBQDAiZuCef38diIB3fdw9/JoJlV6vt7WBG0FOqFvuogLN9+vgw92cHKgkvSEv+6qMQPudAVYaJB8nI+yO9/KodcBjCU5CqAmwQYkp9WclzPSRmXAe/wC8DUCfkHynfz+CwYcmV8eG8zhYPXHmMdw35bwcNwN1IY25oOv91eudkKDPJFFhFyDurHlIt2Ix6Bz3mxWoZGEl3ZbXn4wbpzFLeJbS/HVzZD1kC16pa6KpMJGeT8JaBOxJFrqFcOj92wLfyzYhGroo5p4mMlNxDXYn9GxVwbqnog1dP7o6+jyK9tvBXJrSTmj0vW7rW4LyZBfjr3rJ78uz3/xE3PDyl4l797vfieN//Efs3+9jce5//TkA4KY/fAWYGZv3vBvH//RPuOj+D8Atr389JDR+wcn6ROqfm7tyGejOtIeIML3vvXjvL/8S7v09TwUYeP9fyxm9d9/lLvi5J38vfvDBn4ovnia89fIr8KWl4Gm//jy87asfjf3jY1x2/QfTLpf5vukudwEuuQSFqq81KgVXnjuHg/PnXHEAINHS5vNk683omA9o2qJ5VbtySa9KwJVY164k46CVO/eZrXt1G3eQQgSqjKHlnIJSX2sNDS32v9JsptjLft62FDW8UAC59ONrBgBlUqA8w+mkNFjeH4Pg6yzuSfMSHc0jt6Qi6e5eeeMWptzetC9srXedYec0O4utl9PKd/zcf+5J3IJnRpf6z7to/i6l3nJvWnAcV07ycmwQwFm/sHyrgOZ1jc7B6bbRAR0cV3Qs6Mqpg5HoiPF576eHIQuuw4CeE025IWtxgEUEDHpMpJSKmcXS3ssuABS0AcC8UFaF7BPHH6HWKGQAACAASURBVNy1kqNvZt12RzWW4Fvk5w7TuXg775/mL3iZtHkeBpBadYdRQF1DAZMo5KZpxsnJGuuTtRx3OTxYpP+wuWVQAcZxANDEDfSsXBDlDNBdIIVZI0I1k7WFmGRtXynV3XSMqMmzQkpFQBNXuFoLxNVg44SYubgrGtAzqE/402tAAN7pgC4AJrNofUXjbCHE1RUHBug0IiRz5Dqyc28t6bdVeHF3ko6hhDAQoGvXWMWBZoIGu2B9xv8BJjT4Z0b6TOl+S0FgbZNJME2fC0FWCawrIZLMc8MwBAAi0qh1HBpBbb20S+fILIzSb5Mao14X6ohANtaOMAL+Sl8JW1KANxYgztrzbI3NQKAHYbT1wYBB7k+MR7Z65Ud7QYUXQnGuA24RMDk3W/o6AUoFVHM7M0VBBmuyldI8LsHcQkha9pWBztIN5OTiSai0/mukmlhf6ACVgDeZ3w4fNs0R6ZIw+RusnXHeq1cWdAIkhbC6C8yJi6i5R84ePbe4sE/ex2bvIfJnALjmO7rUg/JxHDF98EPY/+iPxvlB8lut7nIXvJsZr37wp/p7ms5bOz4GXvB8vO/KK/Ga/+fr8BvzjMf90I/hmz9wPe7xd9fgST/7TGl3Kbjns56Nf/usX8Z1hxfhUb/+HNznmmvwrwG86eEPxzX3/Wd4+ROeiMPbbsOyTOOIr/3hp+HgtnN4wOv+FLXNcla3NLRmihk7G6pKEyowlZTvEY69CD3vxMyeGkDCmqdgDASAM5jNiqPm+9vPIQGxbqBh41HQzDODANLcgvM8O12zeWDOlmM7dyvtqiQWQPux5d8BpVSCZOV2k+9h29KQYYHlxgwinvw9KP1KZMconcrwcFBpYMT3GGItL2iLkExW+rYQzBOw21LeLICCXwPjnu+6zilwprIfSdl6j1Wd9qmff00Doi0Xuuz9kTFIFDL1L56ixE/lIaMlRseC5yWOGK6UJUXOJQJTOquMDOr0s0Z9Dhdb+cytacRic9GsKLX4uTerU1zPNRck2iL/rckwcsaeZgFmXACiGcxV91ev3GZmYIAnQjewV2u0u3FDQZzLC2VYKMWtyNEHGalaCoZSgVIkl5ye0WuQM+5TEzfOk6NjHJ+Xn8vvdCdY1GuTkWYdn4qCUSOP1+EM0F0o5QzQXSCFmwRREEFJXNdqHVSQmkUrNAw4PLwI58+fd0Jm54cAxmazFg3YMGC1GnF0BKzXaz9nBAKmtURmYsBdItzdi0jDnwu4hLpjkWqVSrWzY+KP3lIi3mEYwNOk59IGTPMoB4bRME3hLgEWojo3zbmG0IR1zANZCFbhuBBoFkGwEjT8dgFmY94L1tssRDlgGnKYNi9pTQnKPJTptLmBeOmeFdG9zJVSrJ5ybZomBbLkZ/42m02kVMjaQMT5DWYJ2zyUwQMTWE4fMgsDlGFrFEyU4rrRfObF5SiYsPZhhBDuhTKZnOJAyYpbJuOxTingILaQ5jiMuqP++OygqgN1XcNgPVqCOQccKReiB1Hx1uTx2AZddrmz0HW4zoAeeb27hDFGCM9eF3fiYRLYAshlrbYPu80v9W3vQJm1kePciAtaCiRE+JMWSFLsfmw9GE/LUS5FwLnurncDEfAAAFd83ufjgy/8LYwf/dHYv899cO7Nb5a8VQAu/ezPxQdf+AKs7np37N3nPjj3lrc4IGGW0OPnXv86fNTXfQNuecXL0Ihw/lFfgaeenOAdhxdhWa4cKj64mbDPDc9973vwvr/4C/zs//xDXH6ve+Gqb3kSLj84wLkbb8RH3f8BaLfeiid/25Pwwauuwgu+8qvwhn/xEPwggFd8wzdic3Qe3/HEJ+LKD32wO+MFAH/90M/AHz7msbjliitweO42POCv34hS055U0HLXd78LD3/Oc2Jc3QLHYNK8kcXmU663xuBqa9Jy2TUJ8lDEkMxqHah6Rokh841igh6raGhpT4RmFlTUSgDUQscs55RAmAhovqQCXHoyciYFc+knAbrqQnreM3kXLUpaSGFNyl/nvSB1UAJlBtBCd8S+E6q6a9s9eb33zy/bBFfo2WdrS2exRiiSwgeC5EiA0gKz6HLjrjqzWJoiZUlLtt30Mu/aHiPbv9YnJIDRIeAMaAFXwBlwi/A6uQ1BO8N6a/xUQRYsOJPsVSLCMIwB6OwcHQA7m5eVdUXbSSyeIksPIdb5K6pIKO4iHopYGcd0pKBKm8VyF3/PrWFuqoiaWX5U0bzaC/G4Cz7WxDvAaN0wiPxDtl6gc1gIxdqsPCrPKTdGQ9No0tIXBmEoI1Zjw/5eA5UJU2NgBuYZODp/jFJvRgNw13vcQ8ArARgIKMDJ0QzmGeCC/XFEGSpWe3s718pZueOVM0B3AZV8rgUQIrWZJmUA7CAASBpIBPCQyI0zBsQhZoukKJreRPxdAA+hR76ze5AYeGgKCfAzdOa6ZW11K1IpCm70kHQ6k5KF0uweasBKvnQZxYUb2PsVLAgoyK4+C+nCBC6XVKLvJgAX7lMeUCHwrFpGE3SS4J8tI9tuqwtXjeQ7b+9cMn6Ldum+dvaOBtFcdnOQtc7cCTsKebqZyqKP/eWeWWx38gLUEciEowWgs3o6kY7tew6mD+q04tH8ED4CpGWh53YEyR3X3Rpm4wJo2obupq1askC2676uj1mgWghvu4Cef+9dJf9b1jL72Cv2yw+abh55FvvKY1yXkVZLBsgm2G+5cMM1xQYcYo8BP/G4rwMAPAIATxtc/eM/hXrpJXjPL/w82i03e4t4s8F9fvLpqJdcivf+l5/HfPNNLhDZ646u+Vvc9vo/w9XPeCaO9/bxK8z4oh9+Gg6Pj3HXB34y7vbAB+Ivn/dcMDM+81u+FYdXXYVSK679iz/HW//ofwIAbrruOvz9y/4An//k78E8bTBvJrzymT8DZsadrr8ev0OEq66+GgDwyquvxoeuvRYv/MD1gGnrE0150Otei0/5s9eBxwF/9Mh/g3OXXupCK9I++K3/++vx+od/FvaOjvA5v/diPPClL4EBOqI4Kydj0fxxmzC3CmMH3bCVRXBrEjEhdBMKHE1Zwgyo6kblT9gVn0cuDuZEuE4ACEYn4vkIgJI8D7S+vN4o/ZYqWF3+2Kvu1pX3wGxBej2Ro87aBhkDgmEOA7LJEkiIiO6U37KjCQrsskIjd8SB3BYoNXiX9jUzXvil/w4A8KgX/RbM1pX3Std3yue4Y979Pem7rWtsdLk/ve70ZkHH7THygewnjjnfuHxHkwipJWo0PpR/qMi5MOtXAPDMCyitmdTX1IfGDOIG0pQ7IruErCLLO9LxxPlgSnuJfMwliJNcl6BmcwSe0jGvtaa8rwzL4Wqu11QiWutSI9HPmz7r0Vqln0G/C2oZMEgMLHAhoM1oGmH83LlzYlVsFUZrq599bZjRgGFAQSiXz8odv5wBugukSEABsdKVEiCJm2ql5oZS1dIG6L1zBKJQoUEO9IuPdqkEaPh/cJyVkfcRJGJUCrCQrC4GHCKcNRaMwzRzqU77j0TjOo6DRJ6qswsnEXKf1dJmCUTlwQyYMpANTtofDXemYmAq9cWtWyZAQ7TXdsaLDRCAPW9bgLaGEMisibtBXT+Pcc8SOBDRFgMC0AXEMIBq7qvc9dPmR7i2zE3vEtr97eNqIxdCiWmee1lDrUh2o7XndooLX4t7dwG/7nDOqdVu3xPV7noojcnyfubF+f+kPf8w/fInCoFQUNPa1Ko7cGe/3aIGG+elYGfAjhLAU6CWAJs/Y3vP+sLo2uEabrX6BJhrnr7DSpzBBWqNNWyuwVnwvOGlL8ENv/siv5bPnt308pfixhf/98W4Rl/Mgnn9838D73zRf8MTn/JU3OW978WjjyU893vf9Ea8901v9Kdf/bPP3HZp1fl56x++Am95xcslGq4HcZF3/eFPP8P7Ok2TRIHM89ANpAj8ZW74vBe/uANbst+k7oe/5KV42wMfiBuvugrPfNoP4d5f/dX49m95Ii694QaAGK1o3So5mzplx8pxaFMQqUdszhiMOP6WhVaGuVYLORaBFN1bpJ6im9xhDBv5jT2R6W2sf1unBuY6BNABsn4MOd2BDlCYIsfHGv0WcytX9zz82e7MbQLFu7e8gfX07uXveEvUYXvHgBdTAMFFoJA/e8hnAAAe9aLfTkCT0t9945af876T78riszcJNuJGk0F5DcsFTmNv1wh2Vjei3ILgINibkCyYxuKn/X2Mt92GT3r2/4trvunrFwPcWxk7JVYHiKM/Tsf0j7k18GYjqYCYPb2SBU6ys20SPM3ON2cFSwqioqDTorva85aPTtwvA5CisSpk+/aLUsMCkQWd3PKyANxjCm1WTYqe+WxNWQ2hloqhEupAqHXEME0oG8mfeXJ8gpOTNYZhhXHU1CDau7nNEiGZGwrVHYFTzsodtZwBuguklFIVzM0eBMOELwN6tVY/KGxCjLnzGViwnCryvPmuNyesAFT7FZGmgF7Ql8/CBCJxKHoKDtGYGQN13q5Mu2i6AWmf9KMkAZdhzNWbBCCEzGAeKvz6SJlrETqg2TN/gUHSPgM4QpRba6ijBYkhrw8JvJnmNhjN9nwtLYzLsryeLXTL57YEdMDPF5nA5UmBkwjp/Urj/uFgimldF3rsDmycJphsw1erdHlhIUB82FbtaidyT7fmINyp+n7EcwFWTbhcukPFul70LAuiCDejPkEuvI/L+nxesL024lXZBdPWgL2ck8DcdRpIwGnZHxdSNJ+iJK1F1w5TAMU+stD9PmL5Zd16CMVGuGTl9ke9Uc+TvuvJoM0GX/F7L8btlaUSpLdw7Fp5/ToF0dYzZAgn32eEDrLHPL+aXrviQx/Cp7361SiF8OA/+RP86ed8Nr7xj1+DT3jDX+HxT/kPuOKd7+wUDAZGMiDzcWMDGQXEEYk1W7NMD7Fci93Mc6TccOsd8jqL/bakAbT8sX1g9y3WWOcp4c+ls2n6f5+3LwnOTpxtipK1zvq5eIfPXb73tL0Zy6yb2y0IamvV164GHlmctdtZumUV+3h7n59G13q6f3u/rUsJCwvd97nu2+qurk7zezCnWGixfuIG423rw0Pc8LEfg0uvvVZuWfBcKEgyi6tXxbEOlDvvHAHL8yoeQhG0xNMWaD7HAmwBOnuHWfGc/oIlvx6z5847bTx3zgUif2qbZ1ekttZ6OUfraNyA1iRasCoLnO+joFDFOFSgVJT9faynGWV9gpP1GiebDY6PjzGOhHGsqAM5yRRX94apNRRuOwKnnJU7ajkDdBdIsaSa0zSDCH5mzogXEWFcDZ4Dy3JImTbc8qeYMGfgz0Ce5JBTYgYAlEL9Zq1f1o4q5yhUPAoXEK4/Sy1iWKeau4cOQ8U0FczTwu2Stf6sTVTiWmjbUodO+NVzLUlg6MQ7BW/yNXmYZIae21tJOGH3/7czcUQSQEMjJhoD6LWtC6HxdsDcLlC369nOldLHJyyMRcF5rVXPDZIDCoK6YGHJxf1FW0KtDE9CJNjGDtHGfCEEuizsm0gX95PPwamFF0As/5+ExDSpXVv69WFRCvt+gs1NzPq4mBO7P7eF1SZqc2BiC3NXj2mF8zVAFDMhHJgQEAAqsIO1i7vgQ1pZJ9j2grfUtVxjYZUTt+vQPIcQ42CekNbiNli+5gsfmeiMtNHKm7/kCxfP2/exngwgfejyK/CaT/nneP63PBE1AalccttzWVo/d+2nrh4b0YVQRoxQjTPcLa+r25+LIE8Ewp2vvx5f9Pzn4wte9CL89uMehyf/j9/Hg173Ojz0d35buxqRQkspuMt1b8fd/uFtXb8cQCUQEevPCWFEIeY4p9c0/YAcmyW/bn2hVIXvSw8lLz0Lq1ICdPk30hjsGNNAqvm61RspQISUJypsoCM94+3263FDfn8PKnXv+GdDLN2V5RKMOc5umASZh7QGQEE7O1DoU2RKz9sHdKeuywUQXD5rzfZzj4knEOVzyxlIUZqPTLuiP0EP47PVY0/MenxjnmeAUtASiC9NvD/a5MFcoCw5Ac/ol+aRVVA3gF0RnXP0yZgW9S4Imv7uJ38/iEjbJfXVWiGnAoNOTtPswVysbXLWLrtiLucm8dxk8ZdKF5YylVHYZAFSW7tOk8gMBWVcYf/iS7CZZwzHK4DOYT3POH/+PIZBAtmNVFETaGzM2MwbYNqxaM7KHbacAboLpKxWK9c6MdcIZAJJWDvPM/b2V56sWqLUrV3wGsfRBTpLhj0M4vK4mSZsbrtNEmvv7QGatDbcIMj5ZAihrIRLiVAD5mkGyMCnBHAZPHG0CCXDMOB4M2MYRwzDiEkTDs/TsfNvg2DGXEgJpwQPyLimF4LMGsUtApMQQngK4SOEfc/DVCumecZmmnDRRRf5i9qsiUX1vB8zayQqxuDMgDuQXLX/kiCYNFolHHyboC+RRuF9tX5k+Clj2zDNmwCQjTBBGA4VSUg9jBJVq6qAJlHNmrBqExJMsmE7+K9vSQzXnFD1TgUP7ELCLsE5NLc5oAF1jNnWjINoQMDUEtORiiDcC+1ycL6D5Yuyy6KVNMrK+GMJBDg2oWzbWiZgMATirpkACDPPAM/grXZF2oktAJ/awgxf17IsrI1JaeGTEcDE6ipdndsY2eqY2uT7wgWzQlvzabmeYky3Lc1GY4gsiIrPegIK9v4MCBXk64X/8G3fgS996UtQF2Ctmx97MgHTLdcuDrersFyIQNc9r0oZd2HWsS2aPkIxGKhC1r2/wsCSAkulhaIEIuydrPHYZz0L5w6egxd+zdfiJY//Jhs+5JVz7f3uh4e99CV48KtfhQe87PdTQCQySdwVAcu+Ck2fMavXRa0DiMTK2tqEQiOGWtC4aPCmoH9Q4RRN6EEpYcn3JMymCNJFti3i6t+2Du2if5aV6a7pJZ11AinGkgVPuX4WquHrBgGmKG+8poArYyqnlX1b2ciKKUGotyLlmx2sETkQ9X4lEJdBnd0LyhbtbeXcLkD3kV7LxQCDDZyBqCWY23rO6Gh0x3kmleiD9c/XitWse0QS2W9ij5UKqrPSgcH5ovDGTTRAz98XPW8Ho/usSeaVFjVVUqxWe1CRxs/TFTJZIM4Fb+5+T+Gr86yBYmIc85oQ/ls7hdD6ZC2u5kqzDPDJ/c3Xp8UWMBBYmDCX2cEhQbyMeJY+Cc8vmGhWq37BMBRQGTDs7eNOV1yJzdxw/vgYddwD1REf/OANIru1hsOLD7B/kSQ6n3lC28w4Oj7CyeYEKQHIWbmDlzNAd4GUarlauGFuqmHTZN2NmwbriPNSAjLUOqECARGAJoCktqYaJQrQUgr29vZd+2a5uQDCix7zuViNI8bEb7KbDcPOn4lwzA4DQqCTc2kFzJOCk4Ja6naeFaXJzpQRbDtrUk2IyIJysh9uFerqkbqxEGg9sWgpIM2NZa6oLkgv6pW6xEJpOfYsGXG82RhTJGqOa4Bbs7KkkwXjLrcedYCHKBIEG5jbVUJJrWAcSGfIFirsxciRvmhbaMna4dsR7AFnhLD3duMTwhPQhxdHutXOYnUCJW0DGR2gvhcmreZHTXDL/ViAhU4uJ+rrsXnYEsR2z8HuEvfaHFv9DlJ13XVrfQkSfSy464u5N3VAKK+l1FdCPB9WwV7BYOsM3p6yuAeLv/vSmPG2e12Nv/mY++GxL3i+A7LcjijS/wzUds3TtpbdhNL+quyPRFtMGPSZ0PVlfUO4ejqo1Gdp8a7D8+fx2F/4hV4AM6UUAe+4733xus/+XPzsj/w4/v0w4v4v/m9pDJOVLs11WEWMPjE8hYTuk+bviB2UpjntS71WZK8VpJygJe2+29Ob5MHy2inGtpTFulqAFccQQbu2SqILRp862uIKqDT/O5qYe73T9c/HKFnoFDGJIpFS7+Itefub9VGa3XtVeJ9PKdnKlsnZ4iZ/9WmWpKU1D6m9p7qOiibD+5/r7P+CKz8A5Y/6fSuRsNzumzXSrfNiCsBkPASQNCjF6SahNVYXyXTWzaO9Np+FAKYxPsxY0KvUR8S4mSeSATeROxRsKp1vFoCMuZuMpfWRSKJazsrHom/pnSzXChGGcQRKwzjP2NtbYX8+wPmTIxwfn2Dv+BjjasC4N6IOFbVUzKVgs5lcgXRWLoxyBugukEJFcha1xu7emH3Kl4d3e012i5xmYPdbHyyCvBK6YRgFgDGhcAEpsQsmQQtJmtWtAg58iOHpA0wQ9T5AXYKUkPtBZQqC39Eus64kdmfMlFzLTB6NszCpgEYdE1JpvR/QJNxSuqcZyEvXONWzxaAJ4revACKsPSGwuLzNArIl6EBuFsOCYOwWTbATfIY2NeojHzbtP8WzXo0J/jaNMSj9e5ddJXRtyMBjV+kBFMd0Fl7MdRZFshtPx1G3Wti3e1c7tLZOuEzipM+1/MvBZxavTTXCAyRE92Xwt57VsPNLQGDnLm2atoBtJxjETx57PzNpVhiyqKTW7qQB1xQES2t2Fj5zG22dRlCj4iDC2hTCU4Tp3x6pNA8e9ZYAnvFLj/oKfMkfvBRX3Xjj9qzRchxuH8zdXuk8h33CeHvJdBL1KcL4EtA5kPVebgvQChIIwNX/8I+451vfivu+5c145o/8OK5+7NfiW5/wONzp5psd7JiihQxcoF+DGZQb+PAzjkRqQRPC0p8Fy5AIbknLecYy0OoHpR9P5wc+toIObF06IdpZU9Biv7YY544ubONyvf80q5sC3WU7vbrbWTcMic6s77V0B7xl4aP8SPfX7S1Losit6P1gdld+AxYZHHB6tqdjW03fAccS71i0fqsmR0odwfF3b1nEFzKHrctIt2C8uXc7J020XavSTH03J0AXqZYKZo7AZ6TRIK/6zV8HAbjhqx/nc8pz09QuMVYEcQ0tCHflSQEdEVBIEoGbjRUsym6icCntaGRjNBKAJSkXquTi1D5nEhJqaNnQRd9TKmFcjTjgPdx07macnJzg5PgE+/t7mDez5p6TuAKukN+a7bNyRy1ngO4CKXNrKEN1jezcZmzmCcM4yJmYacJm2uDk5ATjagSz5DmbpklcHTWBZ2kEaLhdqpG7iFsDzw3EJDnPIFGjCAW1DhiquFN64IekGRYZwtz4lEgXAqXEngY+iwpCJDgTleQsXc2umURoxliVtxQV6kIbDT1HYuBV2lBKUTApJYMrB3kUAnhOAZFzyQV/CyF3IVm5wAsYc4tgM63NHRgMt45ZBSljlKItLANcQJRcchFGPDPUEDIVyCHuMS0j0YL5ghzFdZaQvMDYvt+x+JJwuV2SVlSFgIQ3u7Z0+E4b4NOxqDNwkjFj7oRjQqpsgUzZmrLsRBYODSAl0SZGlpPwR943WjB56yP7++05eySAg/XBLeiOK2L8cjLbbIUN+W9hkdMGsCseQrAyUGb70xJQQ99v4CMDhEIFqCH8mDW5aHLtJ//XX0EpRgNI92C4B4brZZ6JZWH8xQM+Hq/95AfhaU//KZirrisfbreEEqEHlUk7n17pyigqsv475UyawHSB0lSGPCwfChGaDIBtl8A00PWyHRo2vlPlwqf+8atw77e8GX/6eY/A0174e3jal38hLvnQh3yfMqfxJfMQsP2fg1QVdSO1QBLSKLZ1hSSIWooKFi8CEDQljYqf3MSN1GFdABv4OFpvAzAxTICWvxuy03YenTToBIBp5+rIU4MFreqWB1Eadx8QqNfyNhj3OpZtiumi7a/iHo67GcA93v0uvd5teORexcoKZYsL+2kZctrL1i9K67Qjr0hLDEofYZb1HQ1PtNvohkVyXLqXWnsoPbtrUxodLBrmP+9/6ULvxWDHH8DwqMAMBmueWl3ZEq27NLQaik/frw2uCLz0ta8GCLjxMY+TsbT8qwrojMaBBWwx2XvYg60IiJxFfmgS9dvWke2f1sTFeZommQ8uYB5kjDiAbrOzfDYXupBk782Ypg2mzQY0VBwc7AEFaGjY29vzOAbTNCnYHEBUUcuIoa7QeMY8nbZTzsodrZwBugukrDcbjBqsY70+wXoz4ejkGKuDfcytYX2yxsl6jdvOncPBwQGY4WfuWptxySUXY6gVPAsBYTtPAbGqFQYwMwoTVuOe+I9PM4gJq3GFh/2P14CZ8cf/5iHCuDklqDXhAEkWIkmg3eamBMrCCjOGMgANaDyjUsHeIGf/2tyEbpMwucZxNgbEmGYJ6FBbcT91xox5ZlBp6nZYQWWGsaZSpJezRq0C4BpRcJxpq7WiDQMGvQbAAaK0PSIY2m/JEReaSdP8iSuGgjUdETmvuJH0EkVdPUDu/jFAQG1rM9ZzQ2FJQl5qRbEwzlAXqcRjSxEAaYFiQkEuUTpbE0GNWd2qSm9VsNLs2R163vjLpIstJy79n4KZIgncjomKChSE/83em4Zbt1Tloe+ommvtrzkHMUDEBhSVxngVo0grohg7sIldvFfUiyioGBFjh4gKAhrA7gDRKxo1KlG4YEPUgDwBRBpBGqOoIF0wyAGMNEe+Zq85q8b9Mdqaa2083uf+uWfvgu/svdeas/oa9b5jjBoVNjqGIkmHkk4udR6hkLr6KJg3l7OSLTdarwQQrG6ZAxv4WbstAkGYerK42jOFArxYedyjTMe+Om+8XAO+Cso7w4FKvvCcSsFkFvFEygY3Se/uGJmeASVifnZmNO4OvqY6BfmCgPx5WQYtOwrEyj2UDfQOEDUHsQuRR6QzJUhrHUCDVcZIYR4D0zj/3r3vg8/9wxfhw9/5TgfTYg0ZwaNYVwNA2iwrRvJ1ULnzcNmzve1zjUxWISlrElnorORm1c3IihQGUUUhRsvKHWWAVhdYnTjNZwTBsll/y3dejy99+q+g9oYffuZz8DWP+2Gcu3IZn/jyPwL3BoYpmSjc6SGKOQbkYnJThE1wi6pfM2Nt7SGbRLnDEDez3Fy5nJkKyR193gYeyFy4e8ccs8+NPMLd/sd15eOJA0ROlRJk2h17h/J6Y7+TbLQkpzOhRKBa3UooY5AU+Ytc8QAAIABJREFUTsPIejd5e8JKZt+Yyyf5PDGZ9fDrniSywnIks5SvmnaAPPp6U7JsvcKm2MD+XMz1HOmtUTBePS2frccuZFmJ1/TnjaENbtXV8/XV76MzRUQNxahOMlEA6REP/dc6Q3rPxomUgAF96VjQQIV9zwAY6GPQFAL8bCjsXBxLq5mAbmOp5y9BjJIUO70BjYFWF2CqQ769CRGb5x128wwwY9MmTBt2ryKCrLvdsqAoqesMPa4h/dFax7JjXL56Cddcew1udu0F1MuEuS24+c0/RPbuQmit43g3YzMfQdw5tzh3RKK4n9uBkThLN8V0RuhOSTpeduiFwIXQuGO3zKCrV3Hh/HkBvAWY24IrV67gwsXz4qNegHle0BoANsJDaEtDmzt4M4mFrBQsJEKIFsb2qGLpwG5pqKiY6gY3//t/QOe428U2ooVFmJLIY3QI6TItYGex+nEz3W3Bpk6QyzwlIMFUCJs6aeCGljSbouFCkQPIhUnOAsEEtAIJvbaBqgp/1pDjUHcxvVfJz8elf71Z4JLqlq7d8TGmSQ57k1pNLLSy/c1unctaTdnsbQ/KVpasDLVkIHUdUMM2RyeRXQKstE4oPYhbKeLHX0tRkmeEJsMV9rKgwLj1XBNjgKuzItq/qbZDrsM3rjqOVwYSosDFv7d2rxFE7rPUF6veQSCQOKvkVUh1jlNOo2XKQarlrK5p5vprMSo61chzqEQAKDKlAUPHgGLshzDbCiKYIdEPRxclItJxZo1YOolyoNbBKpY62Oe+g+/U70bivMZrwkI0giNSVzW3Mk+odimuat8lAIpEu9vtZP5tt6qM6VGuaegjIIpp9BmvvOOd8IK73wM/8sQnwO0ZzhH2wa/xPJ97pjwxoqv9UEp1Em7EbSDkpaCW8b48H36zXJEohHI/WR09T62YnBfqAhB9PPR/2hYneZzmgD6rQ4D7/edfw/kPfADP/eZvw7s/4iNx2ze9ER/x1rf4GIGBm733PfjC656oCh2LTAyULnNb5l8T4g09twyJHGwuZh6ZV8/L1VJc3onOJIgZXPnQVVFXYm5boKk0HnZuiqy/eIzwOo6pge7cxwBsrrCdudJ26ODb3OT8d86lSOmC37V/V4WY9XFvfH0I10oUUktRH14SxU7xs4hO6pnHMv2FTGzTmTnfE0KmmaJr8B3I85Rymbk56QOTt7nOq31vJLRpN7DvU9CUaZrQ/cz6mJdZ+Z3okQRMKrWsCHiViI+F0DqjzUKAqEjwkFIKttttXLMEkW2dZX9mDR5Eev8qAKAJmePegaXtzSuuVWQqbD+We21lWel+x4y2zODe/Bw69IywKY0rRLncW0enBi4dTOqFA/OsEHk/oWCDJheDN5J32oJlPkbv51FKxdG5c7iWCTyVpAgWCyWz9aMFgem4emV3YFKdpZtiOiN0pyTJ5b4K0Bl6iFg3UhNEiEhQOe1dVm3WNXWFkHD3en+d3s0GyAaSQQ53YGkWR1c3z97RlSjCFWKifVMHGAdhFkmwkN4ZoxsPEQ/gMsF5ARXdrHS2d4rgY3OlNCITCl4Hdm7N0brCSJkROmZUDqsNkYRDrhrd0zcuPQzu2k4YEPTuGKueSIC7PabH3Opg2sf08poUmVbXNO4+lqoJHVzwMGSVEg1fOoD2atovo7vM3rsGKLyZyXUHI0lzI8ZY9H7SPO1/chfUitStolDywcwzmbDyzVKWgAzRujc8XHlq2D444wQEcvsLKaFJrn/Ee0OitYG55bhrZc6fu1rE+kAkrU3aeLcwA3HhdwamAeiU4HROIdpjPnkbbM2r2164TcWz//n+X4TeO/7N7/y2fkYqgwLE5/fGMZFyf+uz74t/+brX4Vbve5+sRU6wfCBCAVwPdGO00x9Oa8UVG/s8PNyhMGomWJljvj4v4f9xmtGQj69gxtiGQxqL1QIgAPf9nd/C5zznt3HlwkW88Eu+FJevvZl/BwCvufdn4lWf9dm46wtegC946k/EWLEGi8jjl0isXZngZG61zmysRCavOyv6gf2i+6jzIO9s3olQ9LktXUWulIkAJ9a/FCDcmXuySGvZZOPCQQgtb2+7jW0eT5NsqeK0aiRbHU0G2JxiH0XdV1J+Pi/X5WG4BiUKsT4xYqG5rGTnga5PM+ZQHF0aPt3LKg2U7xEreeM/1gz7gJwO638H1PunlIpecj+ZvICfp5crCeSkWtc9DOggVN937dqNXM5IUvc9FVyGhWA80H6zHMaea8cqLPXWhPiRKnZZg5uRBj4xBYPmJ//vipX0OIUuIEJRbyEhr4XjyIApxuyc4LZtPUK59E33cgy3MMtxm7N0OtIZoTslyTTjzGGVWpbmoLDqebi4r4l8M7VIl0amzJe8dwYZodNLyptKZReppWg0KMlrdhJp9epoRBLKGEE+RCsWYLKjq9CWAAtydCwuxK21YiEhi5z+23tTt8kA0lmDao862UWANnBy2TCQYUADATZYG2TCft7tEBp70WRbv9h7hrAz+ByAPhJ40KruAVQKoS3tym+njS2TOSXnhWjPBcnPXayAcSYF0X/yDOUvMpnbR7HG/05G2OmLPSxr7RgIbOq3BCiz9j2AobVhRYR8GgQ4VZyYKrHSTB8gvwYUR7Jm2dMALjPxI3VjNQuJrTWZnmNUtGy5AsYgJFYRu1SWqMXcPQRCde6Fu6f9RFLeBHBpvQ0A1EDGmiQPSpFhvXW89F9+KpgZX/lbv+nrT+7ANDBnYxt19qVSCI/+hm/Cn93uY/GopzzZL8tlJc4sKp4YTq8HDc2XNlAAaF3ncgiGXRY4MB8CDaW2rtFs7mIjMSZz0usEPUvn67b7XDO3yvXUzzXw9jjhDLe+C1cu437P+HVvm/XR5z77mfizT78bfvdrvx5/+MVfgvs//Vdwz1/+eXdJz0onn68UZ46j5Srj0jslf7eq90DaKJGpRIw8iAjg1rQ8r+z3sQ/S+rS88vrKPaifV65Rvo7foWtB9lJe80m+WB6m4MgyZyg+CTKfjyB89xOuAxHhJx/x8HG8Dwm+ECRpTo8Wr5PSMIUpxtYVhMOrRhqHwsZ+sCYgpr53qxZmM3O+eAG3eMMb8Am/+nS87gEPiDq1DvVuRCl9VCw6cYkLsYVAKbFR3GF112CWQZZyn9NhRZ4TyxT0iZnHeaNoxNU6ipuyzDU80FpzhVTvXbxzaPKyDVvZ6haFUXgzmLLZbePJFZ0Y7kLfewR42W63ONLz9FbdUNbyQHDXd3CepZtuOiN0pyQZYHILl96RAojAnKZJ3BMdlKX7X1TQu5BBaI1qLZjUH35Z+srCx37uKhM4AVvqUmkuKVwVVHURTKpRJQUCTS104plQQOngP5AOWBcCtQDudjaELcADR/jgsGAlCx2SwDYBn4Fz0hw7CNLPSd0Xd4pqh0ApQLwH2S7GiGXwuvima+cKOQCjAx0T/w7y4/u4RDgRGd2grEx7z0GNtZMNu+jmmshOnkvQPhsKT4kO/XUQdyTN6vifMSWkLsUpIEnRSuPRRFaslJMA0NA+6++xCnnMBnCwrmLuB8s3N5rz+Ca8xEGQbM4CZtVYA839NsSm7rVMrl7yeSHTAqe6m0LBf2LVb0mrnQnwSW1mq/eYh2iRR8u/KWcApGAojFgSsSa5AI954DfiVR9/BzzqqU/GhePj/THsFrgEgWJp7Ht7lhKgNQAJ63PvB/Y5kdvizUyFD/mtE9n4BCiX7qQgZan/QztjDRv7n3KfcyKW9mRwJv/m/OXL+PQXvgCf+KpX4s2fdGf88nc/Ar/w/T+IW//N2/BtD/tmHF091suS0/lQZuCG9+Pi2/+n19cjo9p6ULnErLRmpfAw+ZSJHdsYGxni5H2wlnFG5jjZkWh89pBsWVvMneSt+sslx4mEbqWAy+WwkbgDyWTJSi6Oyg7Pxn8eFo9jHeyy9Sw3DyVXZMGIgn5u3gsm44dGmTjPwukEUud5yy8HjrDi8q1uhcu3uhWuecf1+3XjDj1C7oSlFLncm5kl+FkhMJe0fkzBkAlLkEC709JIEhXy6Ny5T3I9siW4gLwNaw8DwAjo6Arcueu9jXGenpn9GINjrlLA6Eke2HfFIxlLWXEkhEpBTfth7w1Lm1FpI2cQN5PjOItHIJhOjn/UWvzOz7N0OtIZoTslybWgpAQrCTMjdH0BeluccMU9ck0JXdwtxyZ4qQBV/eT77Oe24EKJ9FJn2fxai3oYWAr3JgWjnO9OUUGO7toy0YQlF1CCHg4urv1GEpC9lyjHtH9Fgn54/yTgSqWAlzaQJANSxOb+I2W3RGBNG2cAxAKi9FLGzd00Z4k5rC1GZIKfEKCH4CHvvV5EiEiQOSLoPilgwAmoWQoGogM7CxMg0yhC/i2DbQtE4KQwk6NDgPok4HtjE6/mspdtpJAPksI1mQuQNpLVXNAAwMgHxYGM9NE4h9jGIB3c4lVdAmJRArnxz4n3oUT+n30QOjREiSHL51S1hxI4sTqvCV08dkId1q3xtRY/81pbPHiKtp3kLJeAMgPuucxYuw2Exz7owXj17W+PRz31yTh/5QrC8phmkymAUg72RNi+gmTk5Sb1Di12nl8cH6aqBWsysE3D3IgzTE5qjINxsj6RFOs87vDUzXBb6s1kdr3IV0F1ri5WBOLiBz6AO7/i5fjf/uSVWErBC/71l+NJv/TrOClduvZafN5PPQm3ed2fgwi44yv+GNde+ge771nbg5A/fj7N6koDgLX2dxgBMKXQqn0pZQsdkNuY572/vXoZusR4r0/9Pf2X95Isq/YInWVNqzw5v2EVJZy0jOWVlMchGZTInAVUynU5idCN7qpK0ixLJ3MnpxN0N/H9qu9TMN691PWm77Qlw2SrhdQ3ipQtdCyAA6UqMiDS4FzybFzILp+F5Y78GMhERYMvkZ81A4Djj7qtrDVmn19mJeuIfs1K39gP4jsJaga30GUFxHY7oVAdydxKQefK105oYLewBS4j5BOnnTuWZQbVgqlMirkk4Bk3dnJn8rTWgs1m0kvWz9JpSGcjfVoSF7RFopQVDcqxLAvmeXYT/kISpGSe5RDtNG2w2SwgEqFV6wa1TthutjArHVHBtKkgEpfLpc043l0VCGVaJhWq4X4AmJDueubHtFpmnegqcM2NgR0Qwg/mm/soAdhsNliW5gEPLIJajtIGiPA3N8xaq4Jc+azXqhpB7TJzYUBo5hwskhDVRYV5Ny2yPZfqIJtFaJotfDnPiyKi2ChYNZOFCqY6ufatwCx9CpSbunZokAbbCKpaS7sGQiGScPJF+6KhAZ0VlEVd2cKDIgisgwfrJHQwp6AQ60Tj77T6Y/2euYd4HbAmEisQpQPYlZCSnd1UEOYbmll8knb0EKFbAzWZG3IOQXkOgOJE3gCW1YwTuQMg0QQTqXbulUjo0CoSV8YcjdXGBNg/qxbka+wXb5Nag4PwJWvmCvytxyZ/zghrvCWnO9G12BsfBtrCqkRhPYMlf+d37GJxwWxyViS3w5QFCwPf+R0Px1tvc1v84FOejAtXr8gs1EBJ1sHjmOjv3ufsMoABj+YangQJ0KWGuFsWx3MgCa6ETv6eK1BSFwe5I18+oslPnafzdehBa0D+MINlWZQSuRY1ZM44CrHQOI9/sLvaO8qy4POf+Rv4gv/7GU44zS3fgvu861a3wn954IPwxs/7Ahyfv4BnX3st7vKiF+BD3vc+3P/HH69VZru5QII9cPE+OGT5Mk+Jdbutr2IIePV76m8LaXsSkUNab/rjUECrLBfs+bJy0cvENLo3ge8oYmzPMI4j87N+NjLgRxKiwf7Tonc6scvk7ACx80BOtt8YKWEOqxyFdwcoOtLWp8vglK/3cbEAUTrOlq/OM9mbJYJt7udzR+dcnpmeSeRecYwggYl8EXnx7uXSZXxa62ipS7OM1DdAxOgsruzmOm7PvP27HqlNlvP+5uJomoqscGmtqQVulOF2LYudM43gVBBcomeOxdpme8p4PtT2a6oVPO+w9CaRxbvsLVUDrDQA8zKDL1/G0hZcuPZmuGazxXZbUcoWtRYc73aYlxnzvGCaBI+VCdhsKi5euIizdDrSGaE7JYkIcgiZRvegeV6w2Wyw2VgUqSpCQaNFTdM0AKBC5J+ZUCOqGlmvYJ7lknFKmyUI+NtPvB2uXLmCSTV2rhVNWjZyNyzZZLqSPHuOYb71WQMZglLqUEFtAfWVxSiBhkH2G8Dz9qzcvroGeXEwYZWNv92NM+XZOV1fAPh7TGIBLCbUIe5Ba2AxbCyczuIUDCA5Iw3TIJrL5VA4EcAdvcnmUixmm/ZfBwsYIxrKH+OlrSdVLn/U0p7wxl7KZDRvmgFWNLcDGWa8lK1CQar2AeWNqJHmkxCc/ZfVuuAVuBH5nkB+pa/sXGqAqO5XGYzALf8z4putYICSGE6W6z1mMEYiNdeevTqumLe5gTooSkArr+GYunZPYgWRWaTyeTsa3L0FcI1V6ER43IMfgv/xUbfBDz7lOlw4PkZixzFPDlR/+CzpBozkZUuoW741cAGzglQbd59TeSxk9Ia5xWmmqKzZtwyx6W/0X+Rl3T4SZf3OlD7I5IXzC0Pr92UcQCirx9JDnB4Ee71vcf31eOCPPtbb/crP+wL83Ud+FF77mZ+FV93ns3Gz975nKOMj3/Y/8IAf+j74RfHR0LHoDMZV/oFG+SH9MY6snVI7cdkd+pxX39m+s5q3AwGMBT5mmdecE31du06Wxp8WEMZzpCBd1v51O21cGHAvAAvRTyUquKecyoWsPhd58cHPUq33RRyaXvmRVNbwqVR8pO1JGVZIQpqUvfmbZETa+5oSKvdqIAK3BqJqfyKflcvKKLOe2Xq1dW9tLUrWI9IkRZ1KKH8AI/Fx/ZApj61MIrsGqGr3mXIrLGf5PFvvTSJhO744NAayzltbgEXqeqSB5WpVQIBJPJi0TLPaQa/KKfWfsv+dpf8/pzNCd0qSuQhwIUzpwOw8N7egiRtUV6sdYSpikWOW0Ly9M+pUMW3k4vHd7lgJVkEpk0Ss6gt2ux02242b+gmEN9z303HDDTdgc+VKrhQCzDD8Al/dFIygDO5pnCKuKUkRAK8ujtVcRbsLSd+YldhklxQghGC3C0b9U9brC9LmSGEVdA0ns19AasVw736lgbXVNmgD8SCINSnJWyNv5mYDu92AvBVAAgFWBbNyZqBp+6UWJZZLI551UHG69lR4BXn/2l1AJzK0tP/pqw6oD7+iIJeiLdl6yunN1d5ub4+FR4+sNLUrQpfG/eQ0kvlhbq7f9d2XBrCYmcRIn8a6EgBmciVGvg/LFQtYu+fYxeEBKIAUmZZMOVD07Ij1w7qdNk8VwBO5pt2JZNIii0W4qQU0CAtNhMwTbB0i1bsURu8W5S2sBnamrtZJnzegJS7TP/JND8Grb38H/MBTn4wLV4+luwmgPXfDUIDsNZEPfMCyDoLDSP9kUm3Zsr2Sxt/ljvefATEjmgHoMzDfm1e+rNL88SqpTFk1wtekVo6Hpud8hE5GQJOYA3vWMW0npXcHgmPvg3CP5z8PRITjZz0Df37Xu4LNCq11eOH9vwQvf+lrsdkd+3sf+ba34vu+/cHYzLsocG9s1qslyJzLOSBZxPXZk4XM4UQhx/1Ca/2fnbMLRcEqY1MGmJxxC52NuI0peTlObnIVVh/tW5f8C5k3Wjh1nS1psDKBkXVVhmkwEDqwuPeuAjPR2lcXQJi54ev1QFdGPdJacanOAK3ztTqTqBfMwyYPYlYCW/9IeH9V9iai5wSQ4rz6oPxCyEazGgLYc2cn0EFCR7Xsnbe3876h/A0FmuAPcjwlHi0jmTNvBGa1iFvU7EP9a32shK4rHJA7ZcW7xc4IMjZgAHObE6EjVMMaZ+lUpDNCd0qSuS4SCmiaUKu4M7ZlAfeNbAq1oPaK4+MdthuZGnYmbHd81QVTrRU8TTi+ehXLIhYzucRaXAJ38zFKJWy2GyicQSkSancxqxUb0NAt2sFJaNLsgK+RhhCKug044QkLXbH7ZgpAzcjR/t7v5fnfCigxbkrcuwhdEsuaIzMT5NrC3jVaF4kFEyRWiFLDj16bjUokedoHVp4hQiTC6LUagWKAiah/JjMG+t0iQLGR2EaYI2EJXLDWZ2KIqCfZu4ewlBFxduB1UsqEYfjcuV7OXYFRVMsBJgA/b+kac4a6rB62zq3dXqIM7WEPX58UCam+BrLyJcb6ZigfDNitwfrIoaMU7VfX+ur9QYwAKmslBJDWtM8Tm8cdvZuVLNptkDSonJWr3/icCaYQVsBwZ4b2a+eO0i1C20ikxwZL3re5/nonfaJRX4MjAJXwuG98MF5z+zvgB57yZFw4vurjAXsmrZO0Avb7ORETIQTab6pc4cRGbT2FhRwKqnnI2tjeyOUDhNpay8Mun0EvKEwKl3T2FUhEMdiXEwhbs6RyxYMnhLQaz20mApllqhE4W8S2FimE7KrNtNfO85cv464vehEyHC+l4FNf9lJcf5vb6Gcyr5/35V+Fr/jTN6L0ju3xMb7zEd+Bj3nDXwJg1KXhVu/423ge4/zOZIJg1pQyrmv/Mf7t3apz09zYRyUPBmLov3s+7PPO/pK7zQLMwwi21Z1s/IMY5EyJ4ApCUd4p+cEoT6BKFv9d87MyxnWWys5/p98JlELj2/eh7LJqspaHA/nsKU1SMnniNNR+uJJqTQxDAgHxnMttI1gAlqUJvijhEluqufbGGjKFR1zFE+vb9rveGR/3Hd8CAHjzT/9faXMb1xJAGjPAiL98LrIKiah1jy1gymQ7VmLyXIK19IPd13vDwtkFHB4HQKqm80yvITBy1pmhMAilAHUq2GKDrs7xcl1Tk3v3ztKpSWeE7pQkA39+LxwDpSxYlkU1WAUoFaisQQzY36u1YFnEv5unCdO0AVg0wG1paKVis4Gf8drNYqEzoAoCbvZ378PR8THefbPzAHSPTJuJuxXav7X2E0HyOncV7Ih3S8FooRs3+ADwK41oZLLPMbSNZPkTucHMNj5KArYyA6XIHXTAYN0rFG5mI8EbmWX8nQjCQH7X7Ym/s9UuPosNnQwMe50sElfqjryxrfmIYQ4nLKs9PpOcfcbnH6/rHT8DItrUsPJyDSkV7IChBxgv6mqSic5YTR5zW+Vv/7Up6vU2lLzamQkCzgeQ6FmlMfPgEfIfhoE5yzosdD21R5pLq/GVfP2MaepH047b2Mva8YKRZtnqPT3fkuapKw+8n7sAJbvXSyMimNVkTaKjXMb3/vzPSdk+/6Vss46XAvz8v/lqvOYOd8Qjn3Idzl9VMqf1gAIpa/tAPHyQA5TZ93tWF0e9GEiTk1obUxgryv/S+DHSXAygXHTiDvOMNMABZYLlToSet4HS6L+8rqNv5QxRNCRBcP1hENTmcZazNmd9gIZaMMfnPp/X6x4pad5Hux0++s1v9jVbqOAhP/EEzNstAOCtt78D/uP3P8b/vnLhAu7yspfgPr/56/iIv3kbPvotb8SYLQ1FhBs/paE+tOaiQTYvbU8w2VAsWmQWDqlR7u2A1I9J1hipk/N85FPDlU175GUc26949m9oF8cc2Bd1kc8hApYVAPF5slDlfz7q8lzI77IuFB8spd6Pfl6lLH/smT1X8DWJ1Pc8MnQtPnfNQgcIkVsrSGWMxzXiZ4m9D6RIs5AdaNRKToz3YtoQZ68ID0BS4rhHuHuye8TYeXYpu2o9EfmA3WPB5oj3sZFhkF+DRLDYAOIBQUSYagWVgoUjQIuQug86nGfpJpbOCN0pSdO08d+rRl9kZlze7RSYVExTxVQremc0dSkRAVXRlibn7aYJ5dw5TEo0Zr0cFIALsnneYVmOxHrSRdTe5RnPB3PH7z/4S70ehIJCInhaV20oyZmajlVwi0Loreul3RvflOIoOaPUgqlXJXWy0VtAkq53tniAhEx2iFJ+46ZpLopVBSblawoQoLe3Jv1aq1wm6lo5CWJQa3VXLwN9HgAjgXkDGMQrsuFgIG2EzjhkAwpNKGDaxN51EyyBw4l0DkwVlYraKXps9rb5Ea3ufWN7ysfF/9lZw5Q4/7ba+DPY5QQeM/jJ8MEJNAMoseENEcZAeii/uCtjaNIPlAvALrC38mwDP3R2MFxS2YG8BwdIoDHyp4zVnSRwIhnLsoAXDQ5Aat3FBEDWoJVrwGBeFtDK0mBAoielhEd9VWDTWpMIswYCMYJUi0LJqsTYQCJR2hy3uyYBWzMFZarWMXodRsJpSkxb65jnBXbnEmnkue32CAAwzzv//vjoCM/5zM/CVz3nOTh3+bLUz8hcqqtZLK2+e+Qjj5nWz0mRrlEjcb13cGO9D0/Gq+p5mKXFfOm9o8A8oG2dSoMNXBYSIJr7PMYpAhDZ3InzVRzu2g7apD3WRgKSkmKjfTd7Xt5aDuDZaBGlEkEvr+9whQ3RcBehWCFkveX1JGeuDWQirSPtcptIGrE0u3fZO9t5BzBwx794HR79HQ/16l66eBHP/IaH4Lcf/O14y+3viM9+3u9jM+/ykvF07upVfP1/eBK2ywxwSP1BiUKxxmLwJU3TlGR7kvt5oqx5ilrJLXW7UsfkdE5ka6f7VSoAeZAv6TNScU242x+/NJQNvE/O3EqlnTwQOqvuitjJ5/ufAdBrS0JWRd+lPSU1PnN6nQBDl9Kqf0OsUporBK4F2xtuCDKi7WJfDxYcRb4/OjryUPtN+3OeZ5iFrU6CRzrLfG76T4hWS/o2WYt12gyBbtZ3smX5Z/1hazG7ceZnbZyZGwBGrVtsNpPjICIJdtUWUZiL0lxiDQwWYkC9nOZwj9YgMUQA9Q67U65MBZvtBkfnjjBNBa3P6DNhmgqmCagVqAR0bB17MMZzfmfppp/OCN0pSSJiC1pnXL167IAPEGBw+fJlnD93hHNHWzADbZGzcHLGRcDTvNvhuBacOzqSKIybDebjnYOeWgq2242Ax77gAx/4AM6dP489/Ap1AAAgAElEQVRz58+Le2frWJY21qsUlA4sbRnADlQLBQV0JkSX1nCOJOgIuvqJT0X4BEQDN00bTK3h+HiHWuXMUe9dQYf8s3DqOcIes2jKqoZ4Z5LLPy1qpm97BoT0T7vbzTZZaX8fLR003mMnLqhTOpvUR1CSd0wFC0yjFcQvX61VtZjQvCtKsWsXJCImcyLIPidsryYBSap9ZjLtqBCk8YAEDwDK/lGOEggt18pz8GcAYkw2D0eAke8JTICNBMxZn/d00H9fI50+U0uWDF+4AEl/Bll21z/tIK+TYTgjdUROjg0kHiKmnk+qDyOiuMqrZfUOD4At1xkMkIbyHsmYWQhHIpeJ2qpW0n/D2b2wOgkYCPdoA5UBcnKEVPbrMFj7E/pT5Mw29Wtyo0vA+uq0wbf82BPxEe94B+78Z38q62QVcdDWJKV+8v/qFI2VqS5TuZ7+PLtMsc+NLJnlRspoDiSB4mdgiOQaFr8D0da2vaf1yEAQOZyOTilCURcps5zAkbS10y1EzLCzrev8HfSDQFXcwrt5FNi6J8PzOrqBfG0qxBwDUh/H2JO3j+Gx6odJNa7tbGGOrIKuXbx0Cd/w1J8CEeGtH397vObu98Sy3ey9AwCv/6Q74+XP+H18+h+/FN/8pMccuCw76lyo4I8/4z74na/6OgDA0fFVfPcTH40PveH9e8+uKuxE39rj/b+SeZWqrVLv+3UXiJIHTtq9kEwstT8P0KqxakmpYbIiuzEG4Yvv7HknEEnxIuujuOtiTkZG3WPRZZ+VL9eJhCI03pQ9nN3t/r13uD1u+4I/xLV/9Xq8/053hF+WXS24GtIZ9TLIM1OeZFLVWoPAArWG1SrqLzYrV0drkkdlua9NlqQR0u7rjMiuYhqVuNZ3RozsM3OftC2qVFGMT6bYAqfzcwz2PbEP71t7TDlVpwmsV7uUQr7PgEShMhW9ikkGWq8j2GABoxTGVAlzYyxNFBCbSWT/8by4lfAsnY50RuhOSbJ75XpvmJcZwITtdgsoAbl69Sq2GwmCYmRhnhcAcR5JtO0z2tJQNgVT3WDGHFrkIkJ62lS03jBfvYy6mXCxXoNChAZykO+wi4poqu2KgATKXWlqfydgatcYRFAJIXdSh4K6iHXB7qxzt4ykqVuWxYWxCVg7C2daxs4BVm3zcoGbNF9+YTcM5PbhM9J3svuUW/1agEvpm8h3AIyGH0oBKYimaUJJ1igAvkERmdY4tSHokdTNzln5jg3fTDJgsLSnGR6AxPicEdhU4vCuuzUR7eVlXWsknwkWl9PJwWCZM4CU8lrXPcqEj2/8Zyx3eA/hnsbeHqT6pnohnWUy4JCAINGY19hxfPDXXO/hCwTQMHAQICUUGXY/UyYAHBmkvINkgTGQPbE+ZQtdlD8c/GcjU0Ys7W5G4Jsf8UgAwM88/rGJ9MkzL7vb3XHl3Hl890//FCqznltdgdy8/rTuGdBL7wRxBIqTLjn7Em6UbPNcl4RbzfPl65wtsWFFiD4wxUqaE7kOqV9jzuh/GLDw8QC8XKOdwzFSq4uSOmveen4j10/XbmGLtivWQCqqBNBotx4KJM1t6Dcp/JPXm6IR/3g6sJZOSh/7pjfhY9/8prSuxtRqxWvudg8894u/DC/5vRfj83/3d/B1P/uTQ1lMjL/+hE/Ckx7zBLz7n38YvvxZz8Bmt8Ob7nBHPOCZv49P/u9/isc+6jvFynewuowX3fu+eNq3PBxcCJ/7B8/Fg37xZ8a27BFIOqGZ9oycFY3tQp7+47vdCyDgHq94WZCiA+0e6udCESNxdFkNY57Dms5W7QD3Me+iWJuXI8GxIgdSB5MV8Llh0VHyjQ396AjzNRdBVy47QSo1LLlry2RWTtlZzz0rWWtuCS+6h8p7M1ozedd1D9tgOAfJemiCxnYb3vD5n+Sq/G2ksclZviqWwqLeEba3+pm7rufgvAwe+j8IHQGQqwmsT0P1FEq0tocdChp3H4PeGcvCQI39vzRCb5wCvZ2lm3o6I3SnJHlIf+ghWr2vrBaJMhe+3h2baQJRBVgP+xa9eLw3gEldu9jd25gZ87ygTuLa5+CK1TUB8E2iqsZMvncoLXUwYFUquDBKbf5urRWtiVtE9+sAKASzg2T9hlJY9QJQt4plX364tpIM2siFbKkRcBC456YDPTeYA1OsGAEf+mwQzkjgAGrt0O/KGBRD7R8u5HM+nheiD6y9XSODuoXnEG4g64UgO+Sq2fxMKuxAPr6/W48SKTiNkTayuJcUqOSvcl1dFZCBuAGnBLBBJ7QRIwjOljzAeay3IG/u9pPTg6x9ZONiAVqCYASxtP+BsbobkRwZfTCwnOcerSxXEeXOnjGiGeRr3VYvaZr8Co3c1s4W2VIAQaOCms6N2NrKQVx671haXFOgtdsbi+J3VQnRurS9gJ994INw75e8BBtguPJkPUsI6/VDvtZtreUIhDn6rGXoFnVnRmn96dwKS00G4+NYuKul+WJCAeNgkVkJO455xIhrGw4mNs+EsJ7654g5mVMOkmNzoVYDivB292JkvSc39HlQlhi+NzIofxNqSe3TPhLrwvoOt//v0tQa7vryl+BTXv0neMvt74j/+K3fjmd+7QPxiEd9F27316/H5WuuwY/+2E/hHR/10fj6X3waPunPXoubv/8GgIDPeMmL8bl/8Fw8+6v+dzz8ul/Aox7zCNz6Xe9wBdHVo3N43SfeGY95zBNwvD3CQ37uqdjMM572Lf8WvRR8088/5SBpC4svvL/TSl8lUmIn/fjsr/hqAMA9X/FynyI3htTt1SGthUHRceC5/PVYTEhsk6WJqSlXO2Rv5VVRtm+EFHNRnciMnXhbSty/Z2UO1jJXsMgcztXN3gkmEw612a4OGu+ZtLqz/+x6ZOAkQmcytCQCbIrbTMbE68fkQpytG70ggvh12/DsMkf7Z3WEkMPWO0prcnfwsgjeOhKyOjfp01LE4r8skOMVpWJT6gHvmbN0U01nhO6UJNMkgeNSaXe5YHZf72Vpci1BH7Xt0zRhnhXCdtYgBvm+lwVUJj2vRRIimdMlqhAhL/fQpSiMZAEbyF0OahHf+9KrlmNXKogLVOtyWaid7xiTaNULUZxnyeGCe4D6IEmmMUPyZYcKeHb5GmfKQvQG2YLn6ZuRA8f4DEmoS6sTSaS4HFuCsJSBNBvhKUTgQuhL3IUUFkyrnWw+bRECEV/m+I22kWtNKDYuq6v3qYE763P9D9vvKzJkDSIDsjj0PYbNcdSYxu+r4Q3AafUxgE0lnZcYyXfPfU5jn3vGqWxOZYFiDmQEk3sPhHQR/T6h8yAMPsYBIpBG5OR+sr9pqL/9DMtyTDX7PlztdP6lzi9pEPIc5kTm5DxGB3NFTWVmpQKv5nX8zinn6DnXIpeCd976w9HqhPu96IVxcbF36tDZ3oY8Bq7g0PHp6BrcJem6lWQ6UWMD5Amg6ftGCt2awT7pvBpD//vcj/Xi057G5y07I2VylkgXtoNMgt3jZc/uJZOfvt7tsZ7mv82FfaKVAbGddTQFQ0dLN8kfSK4cYKTib2T6Jz08FgsJvPIv/vJ1eNLDHoo3fMKd8DPf+4OY9Xz4v3ru7+G+z3skNuk8lFYXH/n2v8FDn/wT+MUHfyu+/um/jXv/0QvxPU94NF5113viKQ/7HsybLR7wq7+ET3ntq1F13B/x+Mfg3//AD+NW734Hvvh3nnWwKYNtlpJsSWt0dLlcrWzKUzspvKAkyvaRLJdWyUm8DcZKNuz14yEyl+SQKcWwqvVI6tTim86BWt1z/1hwnu1735cI3SKOxsui/RRW794X6UM7B42CWtlJqFnSLGqk1DrVkkZ3U7NOA9PwnX1va86CLXGa19lDwWSMnMmP/C2oiTdYm2+unOGpMJ6rl/Zkqc9ervYubOl3VlfPtqAqTpvnGRcubNE7xDKnZbbOWLoEQ5mmabwP+Czd5NMZoTslyYIayP1oHazncKY6Ybc7xvHxsQQDgAiCq1euYplnbKYJ01Sx3W5duM2zBGbYbo6Ac4xlmbHb7eSqgqMNNptJDiqzBHGQO1EAqhUXLl5UjZr4qLuiF8ButwN4g+noCLWIFnk377DZbDBtt05KW1vE0leA0QKggrfKXXnbzQZ2jKsCHiEzE7re4y6X3hvawuCNEFNOAp17R9lsnPDZZxu9KL317ppIs2r6jXbps4bYCPbAPpIr6GaDMhVMPAEMHO+OwUU2jKIq991uh9LF9aPWoiShQe79kjG3QDK2cZCSHg//jAiFXN3yIBtN5xREAUH0Dm4QSoCL00RtuxPDkYhkgG4bbSZMozU0wK4rGjiAfEnnxsJKsA9g9/N1KAzD7s5le7qvyPLjA/ceFfJNs7WmZxCT26V2Xy/dP7OL4TNJRzGSNHTOXr1JLTq5HRbpcqir962Fo0wAxfqZUgCO1B82XwOEEOalAdylXzpJddOZVDuztymprmquP0l7bnV88+1uB+pNz+tGTZy4J1LkgJPljA2M1Fg4NzY3ae1jA6L2jgE02HwWfNZ9bsn9ka13LOqaZ9Z771MEiHaQyNL3tpb8zJWOiYG3II1q211bEG34kyIBrAFXNJ+witqIBZlbOlyhMI7NuAZLDa8EMESWTRuXkb11tGVW74NxNTVzG7MxKXLf1WHyvk6U/osxYx/6ICXjIwF9iRvu9Jd/gR/9dw9LY2OPhXx32cKMuix4yM8+FZeuuYgnfv8P4XP+8DX4uDf9Nf7V85+H+/63P4Blbvl92Duvx/c9/tF4wg88Gu+61UfgG5923boZgPahzUs7i0mqzJGm2BitrPCZAOa22x6z7ja98iJ/nsmLs0OOeRl7HdKatG4KEudzA7kMsg5BaO7WNRsJoX/LMS///vYfjzv/4i/j7Xf+ZCznzwN6ZKD3js1mi2kT5jeXC12j6bqiqLuMlqBtC1orIL+qSIKJVErWMDDm+RjLIufq7U7dd37lVwPQIEFkZK6CCg1rcVlCQVUKQJsCKtMQubJ1RtdxrFXIHhFjKhsQRsvcssx+zo+5yxlC8FBfDD9FLjUw5t1OvZ0YVAlcgPM3O6/n8jqmjQS1m48lJgJzx1QJUy04M9CdnnRG6E5JsvtR2mIHZQXA1GkCzbMKnIbdboftdouu5+WWpaG3cLHiFFVqs9lg2myERChYKsUsY7IZGEAARNxvNEIlQ0CzXQVFEFfKXl2nDgKwLB1TVaKmgHb0CV+7Tqmrg/rXsx5iLoVUk4hhk88EwjXnvjkm3ZmCDN/skubOwYcBh1LQS/F7hBgRMcu3QtP26z7o4I/hLpIZJJi1wYDCQIKgRK2E5Sdc8MZ5kN1GaPgcmq/+7lYMa14QNQemh/Z3pC8sn6SHzCkDDu8/EPbvoYvnvahEhoVUjZrlG504SJ0RCCKgs10iq0ExCF5XcjKXAoToGGYNvXW+9RxHYTAAhTSe+V7ATIQGt9pV9TNwS7rn8R0dv8FNN5HzQ3l6mHcldR49D2n87W9TCFQCDrgPrsfZOb7W81EP/XY88ilPXjVOSvFSvX8j2qC7EgOonMKYd07tHEHzYNk1RQEs+JESmS6kzqytfiXFfsuQunlcT16bBIqtr8msLaYusXlL3p6srXfRwGE1jLWd15bOYZcTMTaiPwp7UuHoUxBApWLaROCm3jtarRKBTwM8sfZ3TdZV8vHsK6p2ArE7sETzDMwr/8SUlAGD7DyU3wFlwsVLl/C9P/Yj+LNP+VTc/eUvHV2Oc72Zcevrr8f3Pe7ReMKjHg0AeNDTfvpweTY/T6y9WbNyO7wVe72VSZHnkMng4SI++PfA/jxWZQdpoXE3YhS/34Oxj+4RUqzkNIBLt7wleimYrh5jOX9+b5ln0rmqGsCsSqWIBMyMCCqVRmyqIpMzQVr0OgCJhizvvO9u9wRAGkUyy8W8FhGRb2G4IgIsAfB1Adj+bvvn/pUlWflj/+yCcOsv0wuNvQxAZRNaC7fLeY4YB6nsnBoDpfMHmZNn6aaWzgjdKUnmNtmWBW1eAIgA2UwbLNMMC7lrPucWHUnCnTcVpgUg1WCrsJvqhKVEGHDRVFUH2QCj9Y7XPfBLAYaGZZfkxE2F6rK0IbS/BPowTTTBA7ukyIbZxz20kIRSxfLWLFiKEQXDV9o+HtRX4Y6VeZrVdaAlSmDzQ6ZRm7IA12etjda+tRY6g6sV7td8OD3nVRgIqZCA5tr7gWzCrBIjwJU2jygr9qKTQdnBxPDonMMmQutfMuEYycdJBWWAY7jFyG62ONJQBmIMcjUHAJfJhfx0fQETzL3GiItZyQ5aAlOdHHxYeatKUDTCiZXNMAH7QUyszie5zoxuRvt9arTFV9wagEXH+Pdh2ZFkACpQXig+BrJmQYj8e5v7GPK29doJuHz+PO7wlrdgrWUQMuXwET6Bx1o7SfK25rvxjEs5K8JQhoyPyLSelFV+UX0iDAG8NX+OavFYpTElXmdlBwkY/wYsgMuKjJC6SLYM/xXE5T46ULavNM7yK1VN+71Q8YaI5Vs+761p/0jdBkuUD8chWrJK/wiZs/5hQF21D8mQXMooZ+hQAety9Mc1ly7jni97yfjQimzZn7d+ZyZ1jAc97bogb7Qm5SmL1Zq8sclk3Qjuzb2dvW57ZCrJo31ZIbWMNWsEQiayrBuIF0Gq7brWY3FRvisOVKDSar7bu6XI9QkuQ5GUqwAYoZgh7uBuGaQosSBQEetXUZkgrpBRJwYrCYwIk2MZFr2WVNmh1ssUSZqzYtQVXHZBueRk56Zl3gbha72L5T/lYZ4UA7FDyEqXr0nO2Tl27h2dxAtkWRYs84yrV4+x3W6w3W59LRJJwJbe5eoELCb7z9JpSGeE7pSkQgWbzRZtaVhKRPk6OtqiNdH4rC/dNC3SsjRsNxrNqQtgE3dJVl/3AtZgKUBYA+3eqt46/uHDbiGugX217xkoRwWWGY47CWKZ4hBIRGJ5A49RrzQjB8nCI+vgTmYWukyO2EiZg1Qa2mGbtgnddd/03keAa4EubKPTXbOzWO3sHjvXsqcy7INRWx31CD6Xey/IbBA61uAxq+cVIDmgthIYWB+YCRuBG1Bhd25lXMSrd8hesj4+gaj949vLiijl9zR/24CHS8S9qRlIaY6ZeA+ETumOAmh3hdQIiYZC10TO7ohiGCgKUGduoLAw3Oi+eY/1t/wpfqzHDUHmjBjm9ZDBEDgsAAJmMORxiBRyXwNHpPkRgYXC8qtEjBmlx3ktezvco2KeSwCU7OplbtKMH//a/xOf8Ma/tl50QAnv+gzYtU5EEpY/KXOyu6aX3aK/R6IIL8+eXVrTyLTdCanLIXuHFE8bEIPhaxs46//cx4lqab8SqWtXVqQooiZkl9y0tj0YVR+yHizCNiM52mereJhvGOXmQBCNnhChTkpYqijwjPTGnZVYJXM//H8LINN43YhHxzE9mczpAyfng9RbWWj4tkDifvm4R+OJj/xh/NoDvwk3f9978bjvfzhu/p734MPf+Q4/dxfNGNfViTor5nDzy+tY65J3A9I5sk+ykgX6hIbyeu7Y552BEpZbton+QdNI4kaZYjLKFksoHaalYS4FVCuoBD6wu0St/t4eLnp/Yshz8y7YbI4UjzC4hAwkdVnXlQRSQijzVlr5oa94KUCE99/jM+JsPRc/827zLwcYiv0zLhsPIqbtTnOoLXINk7l+A0hXGuT+78lFPLUjehlEelefyqrWGuZlwaVLl1DrNaj1HFC0igWY9BonU8af8bnTk84I3SlJvXePbGlRj+SzI2w2G2w2GzlrwiHInJD1BqLJz+C1Zfa71mqJiJAmvMzl0cKVty6Cxc46AeMGTLCzJ3Z1AKezRCLsemtg1Rz3Hprh0GoliwlBozyZ8DX3Q32Gx3fDdVI5WFchbcDbQZzVFxrMZXQBNJKXRbYDX40wSoi8PICHYSrCsIGE9dFF+zCmBr+Yg7Da+Jn2UTPzjXB0CrLN1/8aZX8CtOt06FnHsryy0OWO+yclhxnDp9KycG9Zk7k8UtnFzr7PP6N6Ss18/iX3VvtJcYUHpfcGjG2Wi6JguAcJszLL6t45jiFPVU0k7kC/5HW6bkcEYZD+E+IiG/u+e1Tu2ABogzUOMleZWF2yggBL/wS6NlAiSp/xjsCv+a+/P7gtMTNe/Kmfhof8yn86cWokOiTtSYDH6uzzwFpM+b1xDcHIWAcAc7FswwX1YVFN8whyLtIAXABQ43Ku0gDBiLOWT1ptDg5HzgYV+HaxDsh6jrO7Rq5MOeQg38F9jFEMLXv14waNLA9srLwF+v6+VUjOKoss7+qK2pY5tV8bpnMmqcv25NWahKWaDmkIBuLjtno3TQkQfHzynrIuK6mx4MqVXBcnVOsaSSG3fuf1+PGHPxTLNOGV97wXfujxP4mrR+dwu7e+BQ/6hf+Au7z2T4Z8bwyOliHgoTlaGSd2pixwcpTbNCiHYk9Yt2tUfIaM8D3Q9k1vbswaPjRw/6REuOE2t8G9/v0T8YIn/5Tsy9W8bewKDW0yWtq3AXDyEvCrjU4OxuTdBXhAMVNCmLy89W8+UwndvXwNmHK3aH+sFcbZE2iPyFIaP8UAbVnGe2gReGS0SDLkAnsjnFb/kCXyiJzRb8uCpTXUZcHVq1dx/vw5LVjXuuI2IsKsd9v1A0T+LN000xmhOyXp0uXLqFWCm8wbufx7nmcQXcQ0bXB0dIQ2iyl/t9thmiqmegHMEgTlwvlzQvqIRKjoxeNH2yO5/HKSA8fLsqBuKjbbDRiM3W7BvJvx0S98MTabDd72RZ8FkIYth15BwHYhpxy4n+dZ7pJTUtJaw9XjYw0BXBIo7O7COA0XpIpbxGbaYK6zgiQ5tDzVil2b3RWiq4bMLjcFFdfaE4n7ggBA9Zcn8rN52Ye+6sYxz7Nv0rD8ibDdbsPaoW6tdVPFPYIFVBY2Nz1zr+qyKVU7fycuHu5eWALkCQEAAD0fyUgbHxwIF4qNxYmGga8EPAMWxKF/ZqfYTt4cqNrzdhk84PetDaxQ8etBsGOE0zdTac8A+wy8J7dGs2DKOBl5lYcz4MmWLt9YwWlTt2pQKmNkW1aPEUzoe+r+md+ROTJafIK4Wy/b2SgjJ2Oo/7UGPEfNO0hQXUlh5AwOmtZuWhl2k4+BAhN1qw5lR/RjKiwC3yQgkutirk/3evWrhBhQgDMAqMypzbnhI253rHyAlIZyhUdSPwBegU3LsugZ4jgvt9iFwdYfBL+U3CoQ54vY+NXQ9yPJJO9LW0NWV19BTKhTUTJkDfEGGU+CK7zyPyvXyQPHGliR0QDl++OTenePgjFY5a2Wz6IY2O2KW+vk2oMApNxDDsUYpvnGY5l0YJD3yFyqT+RG+Qv5oYLFL4dfKyisB/w+whWhTH+H18RYh8Id23nGvf/wRbj3i1+EpW7wjP/jAXj8Dz0eH/emN+IeL38pvuJZT/e6rvRJknMBnvQ9D1Mi6ox7fNAmmM5rm79DfzjJyMJ1j0avnh37zgmdB3KKvhmfzWXH/FsriHw8UzuICO+94x1w8+c9X45clAIq4kHTkyLF7nOUu+rE5bdQXNYtQbrzvLDNx96PQEW2v+XrVYZ+Sn0iFrQFxAW9VhTuYC46BCabpaxpmgQXpCBclTj2aH3++PgYXS8Rt+Mudn2BYI4GC44S/0JhQ3anH0t/zItEBi2toUF8anbcsd1ucXR0DtNmQt1MCUcRaCdts2M0Z+mmn84I3SlJx1evAhDXpGnawNwpTQtcSkFTeSd30VXUUrDb7Vwg1Fpde+Vh1yFRF6dpg97FcjdtJ7UGbjDPQlZu/ed/jVIq3nL/+wAIQCtCvHuUPKtXKVJXsTxJ5MdCE2gykGVEBUN+7JuyEqFaUTpraOEy3MkSgD42TSohxGtNBINj67frC6z47B8/RhvU6q3cMI3w2Xvir58tS95CFEQ0RaszikWnzNaO6Ic4dxj3hhlmyBue7bv+nRGKATh5ZWAWBNOE81jdxHbkWQcDaY8nIA7hp3EI8LWfYR7T4Z/xpkRuRNPaB2K4Tvvuuvk7Df3vSoMogXrcqWi1y1Zat7xxmlsevAMDKTpEfIyslZKiBaV6Eo3a98PWuzHZI/mOsNwvOWS4/gIC0JTQxXux2JysZHKhhdl1G6ZYN2Kpf/lcZe54w21vi+tvcUtcvHp1RTRTuxSYmVoBsEuSI+pdnnghE9aXgMsyFO15G66OMNdpxmgBiTOEq7msdVI9wlgFQsy9NM+NWK9B+TRNIns98Iis+pAHCcj7tGGfY9HHErxl31pRxCUN45LMxHWtcwHEiuPytEukPavJNE1gPcts56nn3aJBoJQMWH2HMtedBbgyKfeNgnap85rYHciQ8q80kMj1nHdlzwEyl3rFGzCUtOaQDNRlxtf86n/Cl/zms/H8L7wffulBD8Yf3fs++JznPxf3e86zVi9awQQogTIlwWEahhVBO/xMeCFAidiKZKm8OUn2uN/GKvusfLCAYtb6sYxUw0Krj3VNrWVxmqeZcNt9huZKCdhF2SkSprcLQ95jwCDbI0jziLs6g6uTy93exbos816jwhaNsomuxMrIX5RRaLyewPK0IHFYn5ljHghczPm0B3h/Bz5peo1M610I8TShbDeY5xmXL1/G+QvnUWpF3aqLKgtes/fP0ulIZ4TulKRlWTCVClRgs9Hw1C2iPE3ThN46epF7WwpVF4ImTCxyJJUCbrrhFkKliu1mg+NZ3DDlbJMIFImSF8JrFIgaSbADIvjlhl7f4khC8tuZHCFPcWjaBJ5tVq6w5tgInAxZWxWcju5VAeZMmyefGygjqRXH5c0ZzBKUAKw0waZldSpCQZhYv167YVjbHd9QuGYauELN7wWRyRrV/Dlc62dh/s11MNEjIj3LiIQhD2wEDNeEp4/2/859MKRwClrnPgKLIHP5yYOQJhHJsFDIB7aBH9Qmr8bLxh8J9Ejoe8DONxnAGinOWDmrAzOCzIgA9WwAACAASURBVFn7BuJi1aShzqyAb70PuxvkCUTVS6HxRQM9J7014mWZg2Z5XhMEm5TjK2aF074phEoFGTARFbzkU++CUgj3fu1rARB+4Su/Gl/2vOfilu99bxBEbcMAtgkjCF4TnUDoCJjO/g3Aet2ChhpvzYOeRP2MCMB/xrpM+a2Ir/dZ5gHaJ7mGqUrDB67k4fAWMPeqALkAkUW+HQGtA+YEyJ1HkclQI6Y0DDZ7n+VkLnlWBovR3cuVsUQlVLZLSgitLCLbOw95ZQIpmazHLtUlnjyZBxJW4xsyONbmSOrsOUay0MMAcyp0rydO+iO3QX5ec+kf8GXPeibu88L/hld/2qfjqd/xXehUcf/f/o0xT1OOKJlz5Zh/Z+3gOFtHaWC1D00MHFiaqZxQUGTlYcg2yydNfIxEzrPmyDx7OeTPhroO/WaCkf2fKLtENlKqT2+qBCsdRuGmOoFKRPI1DmfeGbZdrK10wKjUcVfO1YAOljHrR4jXDcPqO67JYd9M+7hfKk6EfB7Q17fKIA+6xOO8z4PJTIBGI+9LQ2MGClBqR5sbiAuWXcOVK8eYpg22Rzo99GqfWieJQ3BoHz9LN8l0RuhOSepLw6QEa9lu5QzcvLgQqnWDWjtaEYN+KUbo9NByFyFlEapMg2qCbIOOue3QuAEg0dTrZiHuBaGZB1QgIwFZEosTs+3Ydpn4hNYX9K464uQGxcNvAbHD3UzcNhuRxMiiDOIDjtt/C2mgC69rAAWEkcWDm1gyomiWPBf2qX7GEwJkyBUP3IuDjcEtT1oSBFLb1+2zYhtFJsujlWPd31ZHvz8NQAE7CA+Sp5rjnkHxuq/HRMO3B55JACOHwOfVhmbfZNexD7YdrUFHjG0uPwG7DDjI5loAJNIgK6JcjXvLfORMKVCMllqNbYyCnNthdyuXyCJypuiXnkUGaazBNVdBT3Aj+JxnOPaBA9g1QSabN9GHpjxZ9+uessIUFglIlRpttbZYXX79fvcHEeE+//1PwVxw6fx53PE97/G+2ye66VeKViFFrBvJPOI/bJ0FB3vcm9/LmLXjwYcSAUkE20iuCLwAcd7T2QU2VSb6S59fTWTJU/K3evUkV0ypxGRnZKO+ds+d1Hns72z5sEA+oVegVHhaP9q2nCQ/8q99xhcbL+s4Qm0b9GWGX7NMGeR7rRMLSR1yoF9OnOJ5/lLIkWwRjWnEkTeRl2j9d0iwHLJUfdA6DCyK8c/+/u/xuX/wX3Gbv3kbnvrw78Kt3/4WfNqfvFIJm5TADFz3nd8DgPDw654k3ZI4t2RLQFbM7FXL1u2+4gdIfY+Q+RY4yIag9+TNkHYmgCOqba5Aejev8WwFdUvo+Br6NGG+eBF3eezj8aofepTMeYsoCQpC1ro0vUdt2maj41KczWXFqoWnWrtcyj5GPiHWhDZbbVk6xOveKYFjqxspAWWIh4zmb33gF48Duu7yWTz4+vZ7JNFRUhTl2IvUG0HJHDeVD53FO6d29LmhomKZG65cPsa5c+cFo9m4dvFwqqijjuUs3aTTGaE7JWmaJsy7HaZpg6lWOUsGYN7NmKYJ546OwK1jKTOOj48xTdUv6AaAeVkwNfEfr9OE2jXMN3fUUkG1okwVy7KgNQFSFu0S8+LAxSJI1GlCBSJwAosA6kZOQOgMFP1MnH5U5pUi+Si6JZCcQfMIVPIkKWnyO1pYLhLdbCY5PwNxK0OdUKYy7P/IYEyBeu/s3hgBjKwOSpoK6VUJcv6u9BQsheSuLgkw0Pwzc+Fi3ZRKDV98iVjZUafJ7+MZLjW2zgP8mgiLRmj3mpkCNkidgjMWeygBIL1cFdr7GXQ58Bw2/UiU/jv+mjqU5QLlCEMdRMnCo8dbBkhlFA8c8/c2h9uZbcxjXSw6WI6yGIgv8gHlYRUwZdWyvDt3sSaXgoLq4MCIXmhzkX4Pl0PVS7t21jbahDmd1TIyOM9wOltjVx3u4xygBVpD464W4Gd8L/Wh/y+WQIAVmx/ypVmSwPlcphBZIxpV38vADwz8wd3ujr+83e3wgGc/O8ghRZ0sXoiTKWsJQc/sIQibkRo2olOAonfV+Vm55u6BPu575MAL1f6wZ8xion2i5WbCQqD0fCJKPmaHV4+cYyY/pxOkLFWLyN0x/bJ775KYf+PHhqR9hSOTKCMXmUSHC3rk4bIzjc1gsSM5Y7fdElopWGa9aqb3dJw2rCKuYErjCYzcxb4f20XeFzYnjDow5DMhaodlVIxHJklm3TmAeNneoXXXnphC7Ub4hNf/Ff7tdT+JH3riU/Ct1z0Jd3/5S/DP/+7d/uzfftRtpRhb4yQXQBOK93dFsLwgTzIudjF9kAAlVEh9a/8jsdSOZGtc80YoYmlxRGxGWt+UlC82Hjr/rfCejw9wEMr/dedPxi3+4i80amUXpZgT/PAi8f1E1xq3pnOJ1WkmW53F64eYFFoQ2Pc9AulZOD9XCZ9CaTVYVqzrRfqkpbO29mJb5Mon9b+U4M8ggOXYRIfs2SZ7gnBLrr3HmUEAQIViKovWLOedmYHOBDQpY1u3IO5YOoMWgCthW4+w9Ibd1RnzrqEtHYyK1jpaY7mXrwaRP0s3/XQ20qckHW22OL5yFbztODo6Qp822NWK4ytXMV28iHPbc+hLw7zb4dIluaqg1gnb7TlsNkc4nncodcE0VdRpgwnAvMw4XhZsSQKFlGkLzAt2u4Y6FUxTxWYz4fj4qlqSGrjtQAA2taIRoS0aJrwDpUikzd6bXo9AqNNGNgBqSvIIpU5obQETu2BfllmDtsRhZoAxTQXMFcwNrXUUAs4dbYHesSw7PdzfMGEaSIFcLA1EsAbR7oP10nTdJM3nn0jczFjv+qu1YioFXAt6A1pb9CqHgu1UsSziRiHnBAsKVQ2O0tNdXh1EYvGs05QCOOhGWwvQFrADTBlruyOw0KRRUATsSkAU+WkbYaTY8BTyZVQtjziQUiKTQF6GTFnLPZBDls1WsxKCXXIAECOP8b6ROssZUZuBdLhrJOARJoUEmTuNEsN0FsRcXL3mZFYQ21DDMsUIi13p4g7kbq9kgFKhiJGDNCaBtOJ8hRFvGBmgDJSgQMr+iOsSHM4O/a89T3Gmw/sZOOhq7ATB+zBAXmjB5XObp0Y+eu/Y7Wbtb1HcCGgyciLzoJbqwZTchRGEN9z2Y3CfV7wCH3rDDY4iMz8bx3oE3L3D3YqIw6qc5y+joHUJ3iRKpkVJEVwTn4F8mhXxm7ppS3XCem+v2rwJl+dYF6NFdJV3AuG73bEDXpAoN1oi7EQynz2AS7LguSv2uET1PZtLGmnVSK9lnIMKkblum+VTOtIIKqGoNQJeSF7rhSQIVq0b1En6WgJnzdFekzkG1LFWSkTKVpb15/YSZaKf68O8ultUK8CHCuPg9XmO7Y2ZUwyryHpKAhCrjZNEAP/i9a/Hw677CfzeF/1r/Py3PRyP+NEfwWe8+AWpD8JKVknmbK3s42Ih9UNvQMM6MnkkRMzcCWUeEef+kn8e/h+xzxnXkEiIMWcGRaVduXNgTLx/CP5d9q6IPYLAes+hkBoK8qrSuRBpILQ0B1jWocSM0p2pMrhWgJRsFYCbEj6QmNcIfg66dL33DmXYM6xmJc+rpHTqS/OH7dYezpeNE/mxErnDkdDVmtab4oiuZJXMYybJHBvXAmxKNT6JNjdwVzLKwMQFF6eLOOYFV3czMBe0zri4vRaXrl7G7vgKrnxgh6lcxvb8tWiNsDRGacBExZXyZ+mmn84I3SlJYrxh12Sa9SyH6w4BVWEgM0L9i8WsJ7AHiIWtVRaXESoA5MycuWvGBcvyv9ZEw2WaxnBf0o3HLUMEO8OWNyUgri6wzwx0GhjPYKEQUAtJFExmFfwYQhrHWTP4PzmrpvTFNqoByMABnoO5tNlaRmYdGbWQ8DrbZkaFBjeTMfHwm5OUtPmuz8oJfrLNPtxCnFdoPeL7rNXk0P46qTtUrdBec8p3dU+5f7MmgEjAJp5MwJHye0E0438Ze5CXLUDEAH6UF5rSRARzAYjxZJaIq7lm0h0Szw96bxkS0BnvGfLOVUIwWlIstL1b/hJLLWksovjxiosgzTY301JJo2zn6fwSXe5xlcJAKlejsCo/u1W6yxCrYkHnHkoOJGJjQMO6iRpHewe3v9UT0twxKqFYt20NyBorVmfvj673MC0SSc+ijWLlOhoNHMC4gV7pw7Aa5OBE9ozJUJOpAQqTBWosDOLKmIL3pOHM/W5lJ6kY9ar5XJSkOP/LMV/TGjGZIQF8NPhO9jpYlW99Y5JqvzXmPiwAeipbkflIsjXdc+nzlnP/7g+H9XGex0IC2EQpdCFEvsyqXMluq9HnUU4QD/0l/Ygxz5Xbs/vZ15z/8Kb5I3d6/V/hTq//Kzzv878Qv/wND8a9XvwCpAZoveL8t4H+2E90Xfv8tszVcmZHAQaZZzmz3+vYk5cCp++jOal9PJ4Vzy0fFAoayMwC6HhOVPyzbB30ZWEydmGUGmsKCBILJDmYOxxJuvl4hyzN9WdIhGk5qyjWMwB4w5N+WvOJdka3xt/mAUPpc7vKyb63n/Y5M+/lYf0gF5Kvj3xkL4yxDoUJpmgtaBC/kIre5RjLVDaoZUKhKmfpLh+j92sBqgAVLJ3AjfMplbN0E09nhO6UJAFiTa0yAj42m0lDeHe36my3Ww3NSyMIgAUVMMuEkD4x73fX0BORRqmUkNymfb7hFh+CWiuWpTk4sO/cUrTCWcyMogDDgGLvLPnqFlTSRmHWspxqKeDKaK2qv7pYvEQbWNBJI2rphpfJW++MWmOz6Z1BhQHTglKEQzYNIzQ0MXdzD5ENrXNH6Sqc1dd+WdgGR+/5soZjAOv2DHLdEtnOFhfSoCdWf2gf2bUMTgo83wO/ZmCyPssxjlC8ZcxKKpiAUP5P3jjt5z6ay8TnJC65xlf7748gZR2iggg+DwdEaRaY/GxRC0UuRIldMSKQxubGVpcIolhgGoCAzaexbxLqVGLjViAYSBJwVYoHVk0kVhBjtwBD6robpDXWYylV8+z+vpNmn1vdXSv92CuP5BqaRzNXKO2bsHzK9z7HOKzEAboxzG9bWwGGdCw6OcC0uW8X67bewjqH7A6Whn41D4c6JFKAVZ8beLSUAW/kr7LKZBMRDCp6Pj3m3HC2ksmDY9j42B2golTgIbKgndnMFRhn7lrIGFGWz3yV5jHUgc1ndGn4TizvRd0voXdutj6pu5xODCfvfHA9eHl5XFI/EeDjPcie1cvs7UmtpjHwUBYHB1fsWImx2/JjK3F6kqT8uDe9ES+9171XUmgkBU5STB4Avs8NxEPncZat8b2/ETIUkPNY6u2xt7eckAbymEmOyUhOa1BOqQ8jOypsQxYZafU8XBm76o8UOTI33ZVLkCBq2LPIpjZrXoYjRGGpwhGprBWps7plha21/dCelduz3gPyu/spfTYoMEiUhT2Nv46p4DVWJZJEE1+WhkuXL2O3ExdrKlDPhCy/ztJNPZ0RulOSRs26nC2bpgkiYCXyEhFhs9motiksdLUK0BJBAhBV1fYRWpMLhHtXPbkRuhruiKUU/NGXfQY2my2OlgWmlbTvbO90qGXaSgMkLhANMMXFzCL4RwFc0kZmwVlq6WhJEAuhq1io+QZRaxyaZr2LRvoOmn+XM2BT1RDgQpKHg9CsQWRq0XaKdcTOTYk1rmj/mbVSPzuERKwd6Z+30wKjgFYE0khedyBZtF8ObUYnzpnxPx8cAJ2YCTl+sj8B22RSvicwnn3sEda5yGdV55OqsYqE4GRuICCZIOk8JQ0EtPrOgMihMi2fw/UJMO1XYLCdO9MW0ggscmMHfgFdNw6WNN/Sh/YKAOhOiOzC2dZyIAHRMtcqVvbmd8UZwSCffxbwhYqBdVaSabWLusu5tWB9EZ7fzoSplW0ANNHIcA/NVjbvaCHWPYCMhQVvbZFzp60lYoth0nCaS+uJaKQ/j0H0qLXZnpX33EKmj9jnRde3A/c8tpzPxmX3QbUuIFs5RL5ya+KLQB1kcipaOK4RJV2aaRqfTOZSWisovJ3sOa9ooxj7JpGBVZs3tYoGBjcGa2Csk6XPuDbXfMrJYAbeGIm308U81qt2+a+HRe3YptVYHajmCW+ufwM+7F3vwvtvfnM8/esehAf82i9GzQclzlC6F+dXqegnnAdtTwGUCJ3Kk0FmEeHQBeW5vv/YDrFWNI3iieHeBEZJde+er7mI6fIVfNpTnoo/+baH6jsdWWs39Mfg5jnWypRNhcthxsLsZ3CFHEEjZvOgBM7l7WcRsufGpBvzfHbZ3lO4AcOk8eBbHMSYAHBnLOYVQAXTtMGV46uY5xnHu466qaACtKXBrlw4S6cjnRG6U5IM5Pu9ZEre8tUE5g8+TZOSP93AzYWmKWCb5NwEUNEbh7aIhKjYQWIjhPnszbIsvl+Z2+OoAYexFhV+JtTjzrX8aE7DpiUfCKGhdLhfX6YiF40XogRcw80j+qq6MLWLTw2oSZvYQaaA8JLcWOGbEethaJHR4VpiUKkQiXuIAtjhrjeWvrKzDGC1KE7TEDFRztyptQ9x/5wROotsSZax43T2utBJYGi/txGk/zAE8E8drNDw7Tq8/qH3T34igbg0f1jLW+9ioeUNTb1bnPz1jEyCVBlxtmc9GMge6Mgb9jhXHKINpDABikTmrOF9OOPoDfH62R1WgrltHIy45aAB+lnfJ0cRYKf4eLh2nAM4MUfd89lCCxRjbew9g6SYv2l0nCTEGveqIi5LG9vm9eXuAQ5srSCdLWOWoERNPQ84Eaxc1o1Ra3Q2a894jyCnccyfW85EcCuin1tiBrq50pmIs/m6mq46D7Il0awrpONTp7R1O9GnlD8hLRHXW9CBlntvWyWSK7Gx2tE9MZFOz0TO+SV7r4Sb12cUWooSwNpIye5tLnqR3aqEkOlDuYfVKQdauP9X6p7977NMYxwuZvU173VKpGs+8A/40t96Nv78kz8lySLzdnGfV8f2bPtKgZvbPUhQmnuMGFspOo0/4EFiepKTRLzX5qHitv+xKbQIVPN5y3E9uTIJJtNCbgLFccRytMV77ngHXHzXuxOhYb8ixdaO1UF+5FEKGWuBVQQhmMwZLXV84Hciwsdc9xMAEf7nv/ser2v2dMltW6e1JXHtPZCV5ut9IUexjTlgZZqcJSDJ7jxbVaK4l8WVK1dAU8Vms8XxPIOXGVcuX8H5i+cwbUU+9A4s89nF4qclnRG6U5LKJMEUGjfMTQKIbI42qJsKJsZu2eGonsPRdouj8+exOz4W8kWkESwnLPMMboyJIZEtywa73Q6YGZsJ2G4rat2AmdA7hABOokGS83odx8c7F661VAgusehzQAA5EYDTJBterRrYZGloUxk1XQwlMUokVYh2ZnWJgwYkqb5h1FKBLWFZGpZlh0UDmYCquKy1rhtOHBbvndUSEERpTmGIp1pRp4rdbucC3gNnLBY1rGDyENKzRrTS5ywvjdploK9zx6ZuMWlkLdsYipLlTl1dUKBXUxB6E2BLpWCqEyoBUxU3U0pMKXSfCiBcdb0iRPEUOPuGKuBTpOmfC8EtDkDXUFL61lHIwbS2cVk+Ra3D4HHjtd8EIAThAaDnEVaWL2tzBknrzHKFrZmlBEBIbkFrDW0Q+hE8ZqsXK7HOdTIyl4ln1uKHcxM5WU68CQES4PXoLRGb/KQTS1t/5jJdMR0dgfUCbrtL0gkUICHqO8BoHhFPrhqpw9kuAzc/+/jHyjqiVNekgIlpF9bFnpQtILm8fZqq92lrDY0kKFJT/yIJhtJEXrHa/b2dPqBj+QNJHsGkkyNaeQPoesl9bWcVXTOeCTR6Wg/IlXGZAhLPAaNZzCwEVde3ySJKrupu+ad8BineZ46xzWWbl4QEj9CoqwZESxFvDRJ3ygHf6nNgVsIgfWZ3bNlcnaaKWgm9V7RW0ZYF87zTMsxaSYDK2JzYiHIaKx8ZNvI6VsnHxcc5lDhDXpn8DLnHX2uZNEiiJD/H5xkn+YgTEWo3jwnC3V/xMh9rP8vtCgqZV71pVOAks2CkCfE50Xhp9kDmU/lYrfvhexDg1wjoEBuRTEqrw6SOXenTdWzlmo0ColC0AIzGQuyXZRHPFt0TpY7pDKoOoo2n97G2q/cFzATqBd2CklXzHJLnOLmyl9LBEGXo0d++fRhMI1bWP7afHx1tXf5J/cS704bCiJh9LwprkTkSRKq6aBH3xxnL0twzqVYJxNZ78z6UWAW6ppSoi2qng+0OTf33zndejw+91S1x82tugaU3dDD+/n+9F/+MPhQX6zUoZULnhkuXjw/OybN000tnhO6UJHM7YAhAmCCXTlqI/NZFhwoiTJsJ8zKDG/x8DJUirmGQwCgShKCCuUhkps7gTn4huWzwIqRKKfjCn/sv6Mz43W+8P7Jq0a0fuZ4qXM1AIYKUJFoks29+puEzq0AAVk0OrmXTy5dxU5Gw0MXATAr0YCDQhHlJt21nVzz9xDfifUJgZSfyoRuVW+gUuLs2zzS01gcKHN1qomdo5LOsXbRgCIk6aXmF1BpZ5CxB3uxp+C1tnlp/A5lj63j49aRQ4T54BkK1SsNXnlsGLKRlC8gYaxkuOOxjPGDjXDFvmllHYwOH3nxh7oM9QFuoiQGrM4/uYvbcSe0e8FJWoa+AlM218v+w93axti3ZedA3qmquffY59/aP04m7bUcOOJgQIWMUEskGI5QnYsODFX6cIJBCMBCIEEERQoDkJyRDAEu8IEURIiADIhZyiIkBIXiIiIDYskAQbMfyXxocY7u73fees/das6oGD+O35lr79hVv3L3n1bl777XmrFk16u/7xhg1BhUPYLAQQwLMSh3vDrS71pePxfvrva4K+JglSADNsA6YJW+MiVKbKlEKShHAbXICIKSOcjAHdhQeADO9P4mhJKBtVqDsyMc2d9j/kO91zriLs44V1nwCNoc9GIoJg6NMy7nHNr70hazrDvmZ0bAyuqyVAFl7J00PVa53xU8qWs60OE2w9cDB97JesfdR9Katb9PdRglQ6ykHCXTCqWuTjQVt20KK7Qk98waWgBHW/4BMmwIGzyrn4dKaovQ4OE0C3rA6kZ0nNmWczWeJ9ss5CJBL5cZ1/ILzR2wjIL6+MfbzfL89Z9J3T1104x6KymRaeFVMes97H36In/ud34rf/NRn8I/8F/+5fO1j2dZ+duGawoBs/TWh+3y6UWfmiHqa9kQnerF6rLLL88EUGTZhD+9ZrVJIlTr2BR9+xjrhFnUjkjrXasU6PygaHf2mab5Zf9Nz/UawfB/NChNd27w8J3uyzxouyJcFMbntSZL2ZwUqc4ZietvIj3DIHKZ0bygWhdCFhTIUJYehZPsUT1UOMT748Kt47zOf0ngIG05z4Kvnt7hcOl5N845i7Hu/Uf+X65N4vRC6Z3Jl878BH0Dy01lgFNv4PRSvLpI8WaMpDXV9ghyCV208gzCmEr0iVroI0wsQVXFNs7MsSm4IBpLSBpIAvUX/W0C81gdkLl2JYHGQLrsms4brl7OAdj4IIFCRXHEhk4E5S9p0jHBF5D4GwhXGNczQyIGc2hEAI2v0MrAiEndP8No/ZqUJ7ae5UpJoIyEWgGvZYGk7/P2mCbaUBQBy5DlSV9MVSjrQPXCq2+PLX8dXn1MCPTYuFpDFx6cC+FrJYVnQcmBj5FAHB8pxf3LkSv9SXTMZpwwcMlHiq++PwHAFWAqRklY7vjpWen3KFASW9Fe0wAFappElTvW4eQVQ97oaoaMAMQa67FxsBipX1ktrTymozD7mogk2l+HjMise/J2Wm66Ua3lzzAGTqwG+bGng9JsRHwuEIhbJ7LLK6WfMM6canIBzsg4ecbq1NQgs+/hhwOeKWZ+YCrhwut/FiBjjQYbYLPN6nyua3OoMsLYxKyjcWusEOY/HmBPuVquI0ea+Th4nZEThQpnHL4kQFjIAA6oG7lkia06CEEeoRwfEU2KOOIPpirkk43xdf84xvfn47arQWNYYrS8t/789czhuibIOH4QVLObUR14E/J6f+kn85b/nu/Djf/8/gD/0534Y0S8HwrC0L31rY8vQ/i3SAizrdSxbhBzukCHKCz6+G3E/aXCbp9wLnXjFQ36/fJzWB1tqbazPiWEbgadpCDLH9p2PW9I8baoo4Rw79bi35nWCbtQbIAp38+weebRcHstdsIXOza656SI+gVngaiJ0EU/AFEOCRdZ9gbOFNy0Eti9M9ygRl8v9soOnBKU73d1hvvtAvRM62lZBkFQKL9fzuF4I3XO5iFTjDgc9APy8XJz7msk9UXbamUgeD1cioZQGIlnMxhACtLWKVjcwLNhIuB1mMGbBEJDAglY0yGA+m6aBUNyVUZ8zq5q5U9oGYiBRNrnIzWXuLfJ9QfV8XSOILof225J/5x3SSJ65uDDYtWby2gNhsL/S5pAta8DBUqmA1oD2tLympaDYH7D9nJb3GUB0ieqmX6pFugw4wypr37SPPMdb/XEYndDM3GInPoksZjLnWlHDJzqu7KyIPn717iPAi08oSF3+JAPfq2YE0LOSsgVQQP4RNj4tjQAFCdzgKNoj/UlyFrYQkuR4Js6J2bxR65q9IHGWxY7Cgf0o9YcobwJwxViS70TxESBosTADgJ5/zaQvZBxlWbn/xh/5oyAC/on/6sfwn/6B78Yf/7P/ocsnBkGQuSAXcEBXyKL1BjC0nH6ikJF/w+5x+bL/ljuQ03cmg/hUAjbIJ3Tog/jnHyDk7mOe/K1rn+rczi6hRohG6jOLSOoWT5X3nCGbxXas5CIDYHN9Xkeunoe29YJtnCe1zhxKbkjO1PlLWIddlmmeR/L9nBOViua8k1QJtRTwlOiEvlYtypP0jluzLMk73D3X74K0UegJ3OSRCNjXWNJCpFfs7vDNkdSFXI7r4ed+/dcxWsUXv/G3AyD89v/riwh5ShnZo521rUsVW4zHaAAAIABJREFU/F2xpl4Jwf5KhM7GivQ7Jff6W222PUHHv43vRIz8XidwoVCIusg/W/cfPv1pfP5n/hp+zw//MP7KH/7DviG58vgGUbT5X0gSZQOiDCi6S9tqeSRjIqi0iy3EzNpi7t3XsjOCliPXGgm03zN2yvLI5C2TPPuOfP1OfZX+b2NhXdeDzE2eGPuOXV3NSy04lQ0MOUay712D2dFKEl+uT/T1QuieySULSVO3gOnnsMxCJwvXWIKjuHvRZD0H1yDRygg8gVobatkERA07S9+wbSeMccGY3UFSIbITJLbE66YB3wCyRtmsY7YTxB4RhEiS8Io2fmtNFncHnRpohBlIpMUtUboBmRtiV3DIM5IJ22JuVkRfyFnclDQLj2y8dojdNiPHOMFYfCN0jWABWAgaWcjv1Myw0AWpWFwXMznUh7I7UyYLZIQmgQ3L4WUb5s3d3eRvf14NLN+Tb3yXAU+qd7QmQOrKRoJMXWld414LzhEVuQECHbwdKVnc4AQTQWqCkq0gN6MnsV7yoeynLwNnR9xhUVkN0Bu4wzJWV9e5UiTdBoq9/1CoKUxgAJvXNlk7i0JwJzMa/p9Z3eOC8CVJy89SVFmeCd0aZjzju1/+/OcBAP/73/wt+NZf+AV8+0//n0+DaoJa3BPY13dwOms6U2oCt84dAqE4RcsdfeiX9aMDQFf5x5zMd8b6lOdkgPCAnDH/4X9Hd0V/YQYAvW15EGuGK0kQ9ROszpJnbgJU4rza0soDUF3alIA8oIE7xFTnY5hoHUsH6aW1a1UWlFrlHDIXDFurbnK3mHtR56X6uFa15HmTPvH1kK5+HuhP1P+mZK7rt/ygw3d8o1n67Q/9C38SIOCH/uU/sd5n66Qtlr5eHsq+filiVzX3yTS+EDPJ3RxvAH0GYk1b5HiLMF03LK+1+XbbY86f+Sx+8xu+gPe+9KWl3GzFuyrWCFItKJYHrmhSdp9HpoRNe6hHeCQAYS0zaURAqMjHyTwTUStLIBMATsaAIHR5vTmep85tqLW6pc4t3hT7XChn8qZq+1pgAlc814I5Ji6XC9rdCVQrWm2Yk3G57GhtQ2lyhv7leh7XS08/k4sg0Sv3nf1w7hgTp9MJuwYPGGOg9x3395KLrtaGOSYGD7x69RqtTcy5S2RLAKfThlpFwyUhwhmlbLi7Ay4XwjgzRmdsWwOVCiKNUAchj4Ull4yBvsAFtmAqQVKQ6RswA4Uqai24nCWgyau7O33WFlJxaZi9q4vkBMG03KxrpgQJKYWcDDFP5MTqtuhHSoP0GXQxRoSBN20cDpuUWUQM+BbS84tI7SsRvY9MEzdzmwJsAbK4S5TLsLh48Iuk1QNr2xdwEIR6gc0ZRDLHKXDbgBy4W1eRR+AEH95t3xthZMATBHuRefM34pA0riW2aNLvzBV3HqM0pnsXkuWECIBv8m5Plf+X7I5koovIkUCAWSMVBCM1oYGNTXwlQdZI07DmyrnLov3Uft7a5ufG5BzVRB9jyTtGZIRQ3fGcUHgtHM0tBEX/rpVcHi6LG+TX6gcokb1B8gkr4LkCgBz9Wgwk+S0GIiXwCQBPeC19zg5weQ700TF6dxK37xcFX9cpChhwmT3JvZ08k5MCNpdLey+n87uI8ozIuawBTCO1mYT49/qTOayNSe5ueTWCaIEZDnXPFlBZPyT6ZSHyfJSAnZ/NHhfTg9xIZVNADn1/0Qnq6RY0FE9WRlWN0BjngdUdODXa1lub6ltrIGh+Udj5ofCooCQeW5sU6drrgyn4kE0KPyfjQBZYyCrd72PY+mWxOYZSwNxUE1GzdBL+FrrqnpsfECKSMqBBdKaOTyNz2sTJ5i0CPU8uY0DyTasM1+kuY8zmpysajFwDEU00Lfy5jDRHMSOlSakxr02esT6ua+3RuiZiLKoULSA9qlFr9Uiydu+VxMjcEyXgWNGgX4MLhlrHerbYI5SqTHrkQt0bW2sw7wlp6tTz9ytRMqtba3U5ngLEnnD8Z5+bZ5N5QGUPmqo5au0yy95Shq1BZLlpC8qM3jVFTN933L96gzEm3r17wCsQTvcVr169wpzA48MOoh2nO8Ld3atrwb5cn8jrhdA9k0uSZDclSWcM9f2+v3+lBEbusWiPtTa02nAZApSoFLRtw5zAeVwUEBC27QSAlAwK8Ni2E3rfNfqTEhaE+w8QWjnT9GYtFQBNaaDJvGmCUySsmQiZ7SV2rkjcME0LZ5tLaKPF+tg9wINrjZf0DWuKhAy4mNUSVxJQnFnLyO7WaQSHmZ28rW2PZMhx6TsUqHu5yQe/KAk1a1zsy6alX9vvVkQ9e5DEFkQObCX4s/DPo25Za5tB0YJdrU+9bAPJgCW/jk3VpbK+xxqGw8d6q2krl3oyLYfJF22tE0b232+iMM61Wcmm/9/BQ/x+3PRFPqtlzySbq+14KBMCk2kCA6uuPIhXQNLc9/C2Wb5ErxfDwmTCGX2W4Q2hE4kywM8nGuFP7XFL2JHEIc0be8v0KCFedyDXlaPOiHkVioYVeGXLnEekSwTRJfYUmdOGeH5z+2lEBAcZpfZbcAZviX7uipaMdZPWnYg1/+Da1xasxME1M5h1zWMEmSR7RhRBVdeF1tqSSoMA/z7POXex93rDCWx2FxUymEm6rAGFwq3MzuDxZCV/9qqV2BEIXMTN3+pn6yQOslrGsX8UCpF8VtHui/cmZUMa0r63LOxwvdISs3S5Ssn7ka6eiGduDzP59L23H+C//3t/Pz71wVc9NyhKaoeT17Ash1U32uD6jaVuabw7SbBnnqrVtevl2nYd58nV0J89MjBbYzO9vEXW9PfWGoaOGSNtPtYSWbL9QNIGiYcQmZ6xiCtvjkadvSwsiJONnTknvvR3/V7/LGQ5dD1Z15bFcg7ydT57tJSsDFzkBZjHQsY7tl6uETR13jMwzDuJhpB3yqlzXPiotaH3gXfv3qGeNpz4Dtt2wqUHFgPTUr+X65N9vRC6Z3L1MXA63ckq+PAOvQ+czxd85rPiSgmqEqny0iVi0t3EmBPnywX7kBDD9/f3qHXD+bzjsu+4Z8ar+9eo9YJ93/Xfhjdv3sf5fEbvUxIPK+gIAqOa2Tld41ZKwb5313LVUkCtYYwOTySuz3uUxxagYvQuLhmlKNmcy6FncyXdtk00+peOve8AEU7bpiG1++JyavXM2tQxSc6WTFmZa60YGJo8VzaMbdt8sbbnt7YBgLpmSrCBWqueYQyrEyBnl6RdkqpBwNYUrbu6VbBuPgIcTTOpG5iRHYYDL7H6xXhwsGcAwAlKvifBAAcZ5A85oTtu9GljBa3a89DY2qaWXSfJ73HifxjHTlwRgCLeZXhupT9rIQdC6Q1Jt1pdHDw5XDogEzjZznWJOpWw/CUEFlAAPidMo+vtUkGx5zHTM5oJ9zm4S24/U0GiuCbRIguzIqsUdL7UleACqiwwkpqBZmjvV5cicxMjJ7fuJpWtlvq8nDc9kD8WcuQujIncMTOGukNLuo5os0WAXBJ62/jQfsyk7CnQHf2eS0CwO4TWfCLWlyBwcbbHMbmXRj6XCALgXdZ6U5Cjslhg1/pZV2hJhfx+e7bU6vPBcHyes1YYH2ZWVloEgJ6w6MBHpYC90y10RODCak1gLybhTy+bZ0GrFbxt3o9HbgBdG9zywuweEDwtaEYIJtfc5J/LKQmAM0jdCo9SXhil/8zzw0px1+L8mBGEpJA5yvx7/uKP4X/6fd8BJsJnf/MrqESgWvS8eJSRNCXxuxQe67aScIlEnaPKGnnXsct5HVjdTPM4WNalVH8GMMe4Wm+vrHMuqzhn6jLncG805VVrDVX7I86Y1at3EIWHwpwTpRJOd5stb6iFIAcgiu+bpYgShPeu5Eyiq/be8fPf/T0opWJTJamNdVMM2drW+57aKW3pvftnRrIs356sCZovkkwZPVxxIed7V8Wf/CNJN1QLmAn7w67lTFBpKFXSPhWNFluK3l8KLpcLvvrVr+Lu/h5v3i+ak+5BPDlgUczxcj2T64XQPZNrTnZXByJxJehjAFANb61iZRtDtT+m7TXtOisB0ciQXbR/pTSUKm6KckB3glA1R1oFIED1l777u/Du7VvJ9YbsfqgbZcnnpcKtZ8xdwEMGwwakOEJkT54oCM10tpZl8FlLQS0VneTcYCGLflk92mfe5GLRDRI0DdhCgNykVQvo7qGcP7NNZjjwNrAkh5xDsxmpDAII2UaQNeOjj5WEGZjWzxxUO0AOsLAo+6KxWAFMvpJlwD46EiH/3P5da7JNW3zLkuPf54YfoaeitQw+rOpCKnL9As6vd6da3SBzTi0Tm/04m6KD+4OF5OrRG0CXrPLwUxQ4Vt2Isp25k/dNH2f2SCa4bpWzseiBhgg0KSUnzwC2aKARC+sd7qb+z6sXxN3KubKoaZ0MTru1iSOch5Fmn2ckViJTdkRZq2sUJ1fn45gKEo7c5drHq6LBHphJ8WEuUAsuP4JsX4MAoKBUeauDvQRMZVxYT6Y6EhKgPShInDREHf2rdL+4WRKI6s135IvW/2Wx+BOMUGbZvI+hpP1m42/S9Zzh6FNT4vjULgSgSj8omVlrE2uQW9RdwRBWutwn6+wmb0P2hnB5X8nFO/x6rtoM1vXzeEpLqpnusSf0o6UrAWxj4DO/+RUMDeJVlRhPtZLFLIQSGXaFFwMAFZeJn/cmc9VPRNPIls2z1DmJB8s+ZQtqbltSKi3kGljGc/TBKq4rKVLipGyysbqHciAHCin+uZ6pnxN9dBQmtK1qRnH4Op+JVq0F8MBBodQ1K/4xIMl1fWlpb7Qz3Bsi+vVxX7N9NHKJ5rN2UW64HIMk5ZONWbcEgkC1pbUEmm4qXDvH+YzLRY7RUC2AxjgQhTKQpsrL9Qm/XgjdM7kIRSY2G9GShdU2bfMvzxEwLdplKXL4dlYpqdaG1tifFw2okMU5odHxCk7bCXPK+bxf/Tv+Vrx9+yHau7ey5jP7AmeLcXaBkM3S7glrjf+zjRqk57diR5Gy6GoDMq2unfkiPchBhVQDVjRU/LoRxyIdoCC7ULjbG2PRwCHX+lAeidAOQBjxDgXUVv8cEMMsBX3uGmkwgdApdg5itdRkgKhNiFbkHwGYXZYHYLlcuT0QyP8USbt+0FxPZIMqDioSu7kBwKIqieyxkYCwMK6AWEGLy/djXrcAL7CSGa0nHf6lAo4Vf+IbTn2TyvJ3ADQLqITSAljzF2WLWNGzmBYa3g/8z5wK4frK7kIOGn0uriQ4ky4jHQwsLkt2b/zUPpgxtxclyWEOO56EdzIIRXLMOZk7WgtNwvxEK686JXUBO6lDAswuGxtgqXwDpVnRIl4GajGzzwrpmTPS9q11MAJ45cYmwls+N/kKAEYqU2WGGGfCQ25SOizIm6/HZT0Q9UzomeHRZG0tt/0iyHnOz6dzvcS41lorwUvzilOkx0ywlzonOmZkh/Nnco+ND9vT8hXPOTVb1nqX+UGmIQ+riTzjltCDvI/zLdpP7irriXEEsQOQaK5DCchUQjVYklTPMX39KVX298XKlfcVMPTQg0tOSCffqN/XnjWxT5uscpNtTcQy1pdxf7W3GunkZQ74WpaeM7XQGEPO2lro5kP9snLN5ao/3/sb/zeIKvrv+B3+TK1hGczHM/J1vcYDxz3v6H6Z19RjsCaQWvTBmgoKSxqeKMj/53t/KTEPmBl733F+fES5v1f5F4zB2PeBK0jycn1irxdC91yuUnHelWjdvcHed/S+4/HSgVJx/957mG8/xON+wYcP73A6ndDuNpxe3aHPicd9B2pDoYZXr1+jbh19n3j78AACYbt7BRCj7zvevX1ErQ2f+tRncD6/w74/Ys63ICLc39/LBjknZu+otbnLpS2A5oLDk9H7gCTONODFwGSNbifuPltruFwuAkoK0GrFgCz6W2vyoSAMMEMOO4+mrlqMVivo1QkA45IAubnCmW99azJdeEpS4TmGnCssEqlyzoF9DyArJFKtowkgxIah76DhQQoCQIoLSFGy2XtHa3qYvBRwq+BH1eTpDs3M6Oa2qudpWtUgCeBQaBoJJXigFDLwnsAN0r0ZhBnYcjslL7Ezbww+SkRS/z58HQiOFEBdXwYgwmpiuYukNunGK0AT8Pb44uNHdAWAhUzP5WkDYXmTP4KHeL/UKUk11VXBjH1KCfSQ3QA4gQCcpHneoxo5j0xxMVMkW4kCOd0NR8iFApiSz7Raeydqazi1cB3uw4KYsI8DB1LMfixP3DUFUMR4lrK/8yd/UuqWCJO5p5kC42hrsT7PfXy5XELbrhEub7F1zyvPqedTPyznsHQMsrmogbHvO5qSFHGJqth0DmZliVtNA/8fCG8efbzMMSfuUCXP1RAlnWJBPAvBQ5L7jEvvDsguv3NZQajdt3LgTFBMTmHd8jlPBGggKyMvDMYYuv6N7n1mZ5ltOoaVMsjnsU4f+XssMv48HV1U+fAwZGwVD5qVBRDfs/3MIJxj3F0Vm8a+KQIC7Fsfy/cLgdV7zDIn0ZntPLWs7XIMoYJq0/YoyVMX7jnZ53MfcnRizOHW7DFkrRJC1JCjJ5uMjrZGG6dOyJLsWIThf2e5xu/xmfSH/Ct+PjD1t97be/c2IcnmOE6MtJgCB2MCO1CmpDEwBZYQQsE4lkScSPZZU7y01vC7/8yfBgD8Hz/4b3nZtn7m83Ol5py9MpdPpw1m1bSjHaLAqTIW9bvex7UHwbQ5pWOKAcLUVCx2Zg8aLTsEa6lYAFZltPDYyR1jEOYgfPWrH6BP4Ld8/guopQEFuFwGxjjjhi7j5fqEXi+E7plc4mYJXeA2AWno6H2gtiJpCUoDQBIGtzXxcdd/ltKAWkXbxAVg38/Ye0crFadtA9cmuVH2jlI2nLYT+rjg8jDw9f/rz6LVil/99m+FbY2WPyryJAVo9w1iTt8t3JKHAIDutiF3QwIOZItf/G0Aw4KKCIkcuuFJ1EwBuqF5hL9rTVJsbpNwwkM4nqvxzegIUhGcIxJ6K1lJvFVcNqoGh7FDzvLOQsXBKXGQLtekq9WAjrvoUpP1D8WOvtG7ZtW1o4Bpltc2GQi2osjrc/3GbJ2Lfk54NZd6fZlm00uXchIDAnSMWFRMB0VYQewRUN54mVuIfCNOZNE05NdV5BUw5rrfeLFwCfLfDYjkucBK/MzKls9dhiJkoPcYr9nFZ2oCe9Zw5dEmXqomzQvFigPcJDgDpkltvhSQtdSU5P59f+HPY86J//bv/q6QSwbTy5wDJKF6gGyz1I1urlNxdu4mVddhIWOB0zu1b/1l0HVlJVRCUIvk1mwbmp55dTdmWPMVrCYCAH9nvHdRPBioJgpSm+ZdGhnIBdhKeDUO2SujP9MMye9d5Jtq5wAyJMPpHUUXCC+F8k9L/5LcAaHgOv0NyPlJOsg4r0THRAKU78ik1eRejsE6romijS8TlQ2KLGefg2kslRvjSspYX3AcN+DjmEX0l9bjH/2xH8Xv+99+CqPvMO+EQgOzVNQ5UepEQzp7riSvbiffA4cqGs93O/roQvAs8uuMaL4zBd65vQ/EuKHDmubd/DXWSt87EinLe5lFN17kxuyEL1vCF28dJVOu8GGGrAsAimRtYRv7yP3MToIBI7cp6Iq36drCn/8OBbORUq0rx7Mhg/jOImbPAybQNxx+IrVv+RTMrFZaO/8c9fK1HYT9suPx4RFzsrhjgrCPAQn2cnMnfbk+gdcLoXsml7hDsp4Xaxi6UPY+VAO9uV+2pTGwyFOtVZwfu2iJeKK1kwYBeMToA6VZaOGGcSFcLjtOp81JYu8Df8t/9z+j1or/5+/8XY7/JO8bg4v5tCcggXQGzRpBADQSlAUcqRpUJZ6DbyZ5Ez9uGBbKONISmNulgUQsZbItplkzO6dvhkIYcSB0cBJgGlFX4FoOuGLJPw0MGjGR9tkGJIFgwoq35C7LAjIrR12tgnYrLb8cANQtIOk10o3ev4p78v9vW+jytZK6BUweH3UCZH+uoChb6vxGir84bdYSMfRYl+sXZ3Jl489Bqf5+rOZxbNnDT3u63H6vFhb1z4RumhJhKlhT60kCMqMPdAyEVtlcgKKvKAsImafF+JP5NcG8r6DQSQwp6Uy0nSgpaFYtu7hhhrWQbwCTp66ZwIzJf4whf5vL5bwew059BGUGEUrfGXqSuZjO1Oh7CknwgW0T5dS2NbHm5xGm89uGZbSN1ajxNcBUmgIemdMUIks/BTlYrM4UfRpzlCIqqdYzEzX7yNrKy2eqLNHP5Tww1rD6To5DqjUlMc+eFvl3A7dO0pXCSlRP9vfn+rklLq1lRuyJAE/HsJC9JDhTqqk20773NiXCSBTfAZCULWmFDP58tHgqWXXlwwxXZ087E7JmZnzdr/4KvuEXfh67JlhnVUxaYJtaK/iOUKooVEtR5cImQcyoFK9XHxN9TFz2C87nM87nM949PGDMKcSGR7j7fsRwpBu/W67Nm67Ado/3FWBn+A6lLPesm1YmgOs+zlq4rb1B6FTBOm28r2vy0AAuwufifJ65BFMROVguT+aVcIUCty6E7tYZ17zmr4rkNU+dfW8/7bl8XlfmixFCk9sUUub7f14zZQYxM/b9AiZpT20VKAV7FwvuGE/vRC/XJ+t6IXTP5CKqkHNl4mNfqIJQ1W1AFuJaRAMdyXnhwVHO2HVTZmxEIHNRMGCpWkQ4gItFxM4BlJIO++reMnmizKkH+m8Ey3CNlwCYTNbmmJ4LCQgAbto0hfTwAAjuVwhfoMX6JQttKQW15LQHsXCb9iwDhgAl62aUiaUTNSsugQ/ADn6H1YuInKBOd70I69+cU0OQy+cOyDIwd9EFADOrEVs9Em5a8ka53BKgJCOtWpeV763PfiSfW2WauJkJFseiMwa5chHKpJIBcxszDfby5hvg+lZQ+lzVo37eyR5dg5Crx2+B+eVeuvHr8XsFuWzjOEhlEMsVPJuiwwGDjqcIyLECUjvnlKcd0fEsaGonpTF31eZ17Ntn5jL0i1//9b42WFuMlF0BcX82J++Vdg373QE0AtQdKmZBKrPlIY8x66ZYd4JYuCVfFSiEnDCYHWz6wqDtsbrjOK/I6pHmipeldxso9DXsWrZxr1pb3V3SAG4a22n+HMdkLm/522/QFbSIy7rPP3udEtBYJsz1VNevEvKaU9zg+hhgCqK3yDN3SK6Dr1mpj8imgZ0ZjscPS4rWrSRZUIBp61dCtDGtRQdx+Dpt7c2XK+tSTbJ1O+Qtypd9vxh/1+4rmCAUi5ZIRfK8ThUAEdqYKKReLUqiT3VDZXYrXikV+xhA73qmel1HlgYBYbW3M3W89MBHccBod5brohCDyuE4vSnllmtpzzYRsa8zMkbIFQCx/gLiZgn/l4cwcyZ6MTKOHiZGwrWmch893epFSWFu74co3uvYzrKi5aelcFmUd+m5yRIRu7vV1caeKDPKlJiic0LdPFXVQwWT5Uxz3/uTbXm5PlnXC6F7JlehKtHIPBJaA1FVgGURF4XQXS5n16SLZkuGSRzGN23sCu4sdLaE/w/gNrUs5hLaIidmBugYQdZkoQZiWw0NXxC/OQcY1feBFVDaZ9NwBwga8ABB6PICWwppBE8smrdY8NNGzhGtzz9DgNCAjkqQOIjfAtstVDkRLPF5EMHYhKzcMUcKoGB4MMB9sLYEOCyyoZeW5Jk+y3Qpt9V4aL6uiJcB1pukjhHhJ78mPPBnBNiufIdSnawdLiu92S15T9Y2qnVoePoqtMoOAZK22oJgII3Hj3NJTW6Rues/LReaY5H0jqVFvI6P1TonipdaUvhq6ycgueM4aoZFuZQ5oIE3ygHgsiWRDqLHCXBkkjnUFezf+Wf/OTAz/sB//ePyvJ4xEQsFYFayPP4tFPgwaz6nZ1KqD8OsN3uaYt2w8RkWLyXL/jcciW6JzMkLJuS4npE5DtRqL36CyIEsoXSQSwLC2mp0gSwpuRGjvAallpmiS+tMgOe1y1Mw14bz/w9kzsmpSzFkBwAFDHNfWzznjG1pe9xzgICiFg5mgIsG5CFKljvZI3ofhzkexDFeM/OrYLZhZvaUK9GUwwggQIP/Ra/4WpWs/NY3nNZWrDJnRMRIc5V1OWVBpzm7knGRx//wnd+FX/r8F/CHfuQ/QW2WcFrI6dR9l7mgtekgnZnQ2g6AUEEoqKAK1NpQyc7gNRAVnC87gLMGOesADrkg8xhl8vEXbblWZz29xuU9tKR7g9TmtdQuO9JRFF/IPWm820/OdSMlM5RI1xpM5fZle7jhD11nSNeU7E9BsQ8/pbizepk1MGMJ+/5KSjfKWt3mxUIXgZ7kWMrQ/MDh3SBjt9YqRsrBSt7k3o1lDPME5mDsL4Tu2VwvhO6ZXK3eoZaTkJoBAJIUfPQz9r3jcrmg1oo3b97gfH7E5XLBw8MDWms4nRpaE/fEfd8x7jpq3XA6bZqXRRacVgu27Q597+h94vHhAmagVks+PvH27VswxPVzFnVpGB0E0pxs4ZIDiIWQmbV+dpi8ygH8PtQdRQ5GZ8uEYHpxVYRq0AwE2QZn75N0BeJ6ejqdMMb0A89WrlktBRxXdx/qQ4KQlFpQuWDOorKoHiCCWaNyFUnwyxoJbrK6wOrGhtExp+TnEW3bcIsLAIw50PcdBREdrY+OOQbAwBzTrX1ND9iLFXWCJPu5kEbAQYsBo7AcyOV/Z2CphEzoTQJe+fcbpE7uFS3r+qk+4kEbSOurhApazILvaEkLYe58oSgAttNJgbiF82aMcWuDPfwNOGmzL61egu2kTp4EV6OgOU9Km7VbA0RdupLQKzFkmBW2R5QCMuI0s8Tg40c2/uFPSzvIZTp5gof1ANZCkOqWIjKWUjXCYYnw+6U5wPLAAb1nPoWqLmHZqnaM7rZqsUO5A2YJbpLeIa5EuxLVcLlECraxMDkEELQOJQOJ2qfL+xHkbAz2Oc1qAaxlk+96B+bEKGEJStDNA0awKhY5AAAgAElEQVRQGvvhngo/w8YDmjMsHnWizAzWs0FGMK4AaiYQi6Zj4foAFLYeHr8idIkQ5kLyOBmjy3g0l0oNtiQubbYuqAz7wM4XmOKq1DWtQimSf84JVOrraQniuxCQfd+TK60oFmqyfsyFON+YyFj7ouf8eHaTidD7KpN+aS8OT8Vc1zdQFFcoW2cmcjqG1S0P+Onf/bfj1z7/BfzjP/qfBUHx91aAJPbvnBMYHdhlXSy1KeljYJcUQ1S7nrUTeW/bHe5fvwFRxfnyqC7KDOKp62GWQlirnISkcbfI5QZhinXbSrPyMpmLfnJlBhFOp5Mc8zAcMGOPcOIPi8RdNZgTadh+iGWRoh5rSiSptxGt3ruTIsvFac9ZQDZrn7lmWqCUHOwqK6ly0CkJWtawbZvfb+/Oa98VoevQCKyBFeYQJbcRtD6Bfb9gDGlXIQK1itevX+NxH+BLBw+hpO/evcNEQdvupDwQ3r59d9VvL9cn83ohdM/kkjD9kvtHAiQIMepdQPG+d9RKOG13ToT2ffezcaVWjNk18MIQ/WCtYr1jxhgdlTYHukbC2lZw2jY/J7HvF6kPmbujaaKmLqwAMBys2YI4egfBXEpINOWapJvNIsbhCkG6wc4xfUO1ZXRa4m6NkGXPFiqALuTmigp91jYciUxJklgcGhGwVAc8TixrbLACQCLkfCESwMV6DoRIz/NRks3U6FQCDggEnhJZa9bpAU+svfAk5hJ9MScqLhCXGiMKlLTJDPYPFlLmNyaSB3sm7/n2FFlp1/ca5k5uLIuxwcGrAaqk0b3BAfmJL/nqswxYb2mXKep449t82zFSYnwXlgL586DJzmQukzr/WskWp3re1DRn69RMz1+TakvHkUFz1nIv2nlEWPBM7ITsTMxpfWMuSfFeKiXyFtt7U32dgpO1XUmlky/4mBS3oYlM5rIiZRqZg1JTTq/xVy6OVIjSTbRhjYvPVHIFoKl1NDZOUe7kiTJS6pP8bk6uYCVgrcHlxbbJNlP0Dw5i6RZD9RNlzhagIKVIz8ZFy48sG4XWi3zyeFuI8fHiUAQQTdBU8LtEztT1Q8+AOevVpNcexEjHWE7WbrWjUtAUlPNs2NrmbrZz2pm0oYA2xBGVW+XgZBp5fnJ8kVcql6vORe+XiSzQRTy6sJniEAxMJMWKzbknrVpazGQwhp6hIyFyJOvCDK4MVsB/MQvdmJJXtjZUTVTv+5xZi0j21zFnymWfBjalteC4vqU16+NdsbYcLXJXCgr9bowR+0Nao4goKKF/zqGcgbqWY8q+pi+z85SkfcnkNYJZeIcqP22Pk/U6UhW4AkJJnpR7OxWB3ZfXq+N5Ofv96PFjv4850XvOqSjukzPJZJrbLNJZXWhkzj6XdfRyuaC0C6gIjgEVvARFeT7XC6F7JlehikINkwfm7PpZAzMlQnfCtm2QHCYTl8sF27Zh24Rw7BfGmB1jdPfVb61i7AN9dGy1olpY/alhv7c7sZgUwlALH1jzEVEB2aFwZtRSY9FFbJZjyqFgKkBjOzMnZO5olWOw5HaposmbfWAiLcosGxwVy+diLiJSp1YkRPmF92XhXawMpaAwY0Bc1gpxuE1SBucGlFfAT6WALE0B7CxfBZFpw4PcGZEE2e8KcDWKJVjOEpobWkkbkp0BEjKXLD8B8eRTA/sUP+wyS12+nP4dQJSfZdENPFMIFf2NK8iHkTqkZ/J1pUm+ddl3DD9btAIMa5e94wZgUYDm2t9cmwVUHx+7/txbdABIkbfPac5CtOJp+HemGJhJ87+edQxAYjLISYnN/nflTJXAjZ23E6tY5IZijIWYEHROOS+IFAVL31nwHwP0mWTYM4K4b1r2xM0o2nAFr9Mr+fhdEqGNmYkZ5isbd1C55cFv2N8A3JRocmALYb4SICKgWmIQB6ZG5m6NszyWMwi2xiipczEGi/HPlvGmIDwB6ZBPdutUQJgVCE8ROgPGifsQTXedzEJmMFrbUJoSNtj77HkZp0ZcyEid1qWo9c/PE6unxhhqWekd57OmRKjF5eqqDSNWiagRYly7VcbXYVwTS859FfOTsyxT78WjIvvsbpwEvTzKWH8xl2JhqcXnolWeIOC+6h5Flx08gToYbdtQQahb6i9SFQ2FF8McEyiE4meMteKpv4PEWttYg8JE3Y8uhdkbwW5clUeEHIHY2nZ57w0++8u/DP7gA/T33hdrm47/yK8Gn3vujso1hipPDDV5k5Ko1sJiF60S0uf7KICf/+P/vHr2SL0Cc8hle2fv/Wa7j4Quu4hnd/e8FvPSlrQe6Rpnw0V+RiTsyROTk6ulr2cRsEi+Ew+ky+WC2i6obcOr+xNqpRdC94yuF0L3XC6L4MuMOQSo1SYbsZ1jYBBaE0LHkzFM+2MLF3QD6h2s/vq1QHKy9Q5m8YcnTQcgbnDi2kmlAGrdk8s0kuwLNKmG2xJu2n08GX0M1CH1MkvAqg3UUOyq1QVLNLrJCuASppJUCNouIidcmQjJh1lDG4txoQKm8H0HoqxCxV1FMkHJ7izmdsMIX/2SNN5leS7qJhuGBkupCjYMCOum4CQuJSouMBC1DongY0HmMovJGvinFbWxWRvYpCRrBzv5fUjkjuD18+I435T6eiZQToR85srOeiGXpRuiBxX4/3hZHxz/WSOMnGSimdt39XYOBiJK+QJOgCLKkXeYFToUGHAXNnO1WlznMnrkCHpkSNHBm/ZNSWMyk7taIriMB0lx/BxR/LztpMl4U2Mz2DHCMofOnTkxixAAS0PgZ295TVmQm3XVP1+j//KNDMbws3fQcSTj38aKuV0Otfw7MfC+E7pgchJFlq0ZZq1LfZmI7LG+QXri04VY6isZa7lLIfbFomzg5YcTGCQt/8I1E2h1YV1Rf+mPMTLKF1mUgjkGdm//4VyRkhOL6mvyi7VFx+REBOfQ8WTudLU1WGCcyEk2rupp5JV0MSKEZdWlntKmmDxENrbeJJaSGYuLK9Y01k5aiI8VTEacrhdfsVoWULUBohGPncipi/ycmDQBmuA5MAaFfIvkKIVFdtR5XqjgdDqBeaJUQt8vGP2iFV7Hl8te2+GqE/P/LcXHw0pcQ3Y2vhbr/zKugjx96Zu/GZ/+61/Eez/zM/iNb/s21Bln6Cw3q8g3yI+7Z08Zv4O7uGjrHCQAsw1TtXh5gClggmQ9ftM3yTEHXffyGlaIwFSAGsckvE8PVyZztj4eCV++rtMXRLTuhQhTikzMKW2T7uVjsls3pyoEBOKEa+mcE60FHni5nsf1QuieycUQqxSmujeSLhwkG0fXpJaSNLdhzI4+snumBUGZmKODZ0PbGlolDGLs6o4piS+rnIlQV4JtO+Ev/Yk/gi9/+dcx330AwEC41U0Otou3zkqgSCOlSRLwquQmrGqmeTO3F2a1mpXVPSGeU6sFOJEW8jrJObcKwxi+H2ud5ArZWRJQAShFyWwARivfgqqQfRYoQvfMkIdrae2tLGcAze0snxGIRV01eDXcOg3DC2820rU2JZofckgfHjb+DHLSJ4Z4GWk7zWMv4dAF2B7c0W6Q5wWsGbGCEZGod5xBye9iB+ikibQ/1pXZGGL8LP/wNJHILqFGcL2q3q54BR2eDbdNs8ql6JXTEuZGeHMbGwup1HFfUMDEYgH2MOzssmFGuGglJYKMyeLvz9HyDPgZ+XKXSEigAwsVXtRKMMEJzDB+7bOfBebUCLfyXlFKpDN3Wqa7yvkcjT8P3XTkMDG20jojwQKmY2zSsWvnY/wM79Tk7PpksbHFOmbJrOuE1ipabTALegbwVyA519e+8+/1qxSAZll7+Ikxt0yw/LtN8jT+8j0cAuVj9VhCdARHJJ+LR5dfooJKJN4fSixARyuFKZXY1z8hgoRK5mpvRCyUUfkMkzTJAkR0XfMoSJ6tiypPU1h4yI/DeFkIWeqPJBz5aW750grlQwzbg1bcrs/kD41E+ZiItYpLlfotuTRpkbN4UUyQuZ9CImCWOkBjSC47hkfgrUWOPWynTbxatop3b4GHvuvkPgzB42/M4DxW5gSK1nshJEaMl0+eUATSsvTN1tDHwN73sCA5IZVx5aG+dA3ws8QkZKtzWNDseEUBp3OqDHCUR6njLfKtWXpNQTchxx2O1jZ7z+JpQ7l+QN4f7J5VVms+WylvTW0g77M12mZEDtgiWG7Ons7xicsuU0HfO/ZuXlRA2+Rozcv1PK4XQvdMri998CWMraNseqAYE4OAu1evcT4/4u27R9XwDHzuc1+PDz/8EI8PDzi/65iXt3jz3j1O7zfsmuum7+/w+r7i/nTCuzowLm/RL+8w7+7xqc98Bu/efoAPvnrG24czvu71e/i6z/1WDJ4YCgrGHKDSJKokiZapj7NaUwZY82kZwaulgSdwOe/Y2p0u2ozz5YI+Bj716U8BBOz7jt53jDnw6tUdtm0TkseMCohmboibw8PDAwpJIAdANrk5hrqZbpjzgj66ag4b5pSIUUYgt3bC5XyRIC0MAAWlNLx9+yFqbdi2pucMCx7Pjxr0wYCbgPT98ohCFadaMWrFWYEyz8idNidrgDnb8IrKUKKiFQs0wLr4E4EKq/uKnm+EAAQjXE40HShmIJVy401zYzGLahz+z1e4z2UgoyAc8fn1Zq+kdM5lw/f3+QtEUWwEfg7GRF/K8nMjTgL02yc0lEKQA5wuYIVkI3RCw4xSBCzVWrFtFebWBEBDuytwTFp5ViTJ5vZqmnX9XUDbDesfgDH2iO6o0O7udEJtLWRjSgjAAcMYEjDICDMV0nySsdwzQpZGKJhFCZMj2Vr7w5qd89rtIX8lG6IdXgGNBxqZE+dtw3/wR78f/+Kf+jfBc6IbAGexPrBam4+BVMhAMkt/MghwYhbE5cafwa9ILZutJGWQvM8UWrCxQ8BlDNQ5NRCTpDQ5bQ2byrLVilqU6Mwua1dS5ixE4aZiJK6S50iiGcalsmOu38HpHnubjT1ThHwN5UMmn4vyRIuKoaxjJH/nzECJrNbFzv4NH0dG6ACLlAkKV9fhluZM5EoioTa/5Z7aNpS2+RwCQqk1x8RlP4dyQOeTwnaY+yxgnh72L43ZtEaFRizVzQRw6Gi2NcjLTGLWNTaEV4DagLvXYglCkrMBeZUfg2WscwfjAaU2zNExx47ezjjNeznLTmLdExc+yVd3d/8atRa82jZ8aQ5cLhdXaJSaLG+Aur1KABmiIAIMHHKgWTPUTZYI8Fyw8HOT2usxTsjkJveWWiX4R7+4vKkSGgGtNHW/LeLG6+NOA5PsDErphmgSChcUFFcuzcmYGjCqUNW8dAWf/3M/AhDhV/7gPwSbHMxyTytShgU6Yp5XJOzoagklWIB6KGBi38/LvRJQ7hI58kijVM6OMXaQEuHaNtRWFWtI3l8isVz2vePxsuO8D5z3gZ/9az+N9z/9Wbz3/mfwuE/5/O2HuExxkL979Qav39zh/s0bvFzP43ohdM/loonBHVVdPHwzHKRnF+Q8zJyMUjfR8jlgpbCcGQiepIuQEIdSLAS6RG6kUkC1yKHfMdG2ito2bKc7APBAHkDkkQnXCvY9L2vhDYAJcIKCg9B8zQN4kWcJwMQYFtq4eFk8GaVZgvHiZ9HIohiWokEA1rxJx8vKkreRL/QWedE0gaoETFaBRDoIGpUyAbVEnCiBCwPihbTuwzYx2yyA2KhdGnkwIBOq0GcKBVi05TfA59OX7uaZ0x1voetPb4HNTOboiXusnCBzt6ByBsPw+/PnXj7FGGfWcxUqzziTWFxjG0TInkmaZvuZtcMGZvJzDvNW2L2AdQO1oABQCiiF8Ku7j86BxbWHorwMTNzKmED80dUva66jZpG3LlvdTIgfdU7kj/3Qv40vfsM34t//l/4kvvnnfi6eV9JoycLzuCXDgqYNB1x2MWrXasfZnqw0ENW+3b0SaCvYSBB8LTT/YSE2GpRJI9j6XDWXqaUv80U6Ndj7f/mW1lF7tcZQ/pHvTW/jNI7tUw55rfQ25vjxenKuEQ4WLjrU64m1gl3iQsIhAZ7cCsQSIEo8NJJFz5NF67wms8hngUT/FqS8bBRj02TZ913J3fq5kahDpQ/rj9OSNK+TxSfxv1Uoqzyi+oTPfflL+KZf/Rso7QQquu9YgutpDCOetHrOoRY661KCeMbYhinRfaJN+rO1htN2whwTHR2sSsOoZyh23G7Fy2i6fRmBc9Ks8vOFJ437K4mES631ia1fg4aeBTSlo1mLpYRN8+VayeE2Lm6JYiksYE0FAW0PAfjsT/wVAIRf+d4/6HOkgDTYzrHf15bPGZGvb1no7NwdtO7m5XD853UlwlbDAlhrRWlFUhF4ugqJdinnm6VtQtqrr9+1FmxE2C/q3TAkendPbqMv1yf/eiF0z+RiMMbcQdUOA8tCOJxciNa69+EBT4ovWIeyjJnwlMAiRCjVFmVZ6EotGhlzYu8d3/6nfwSX/Yy/9L2/H4ARuulkTkL8J4AIXcxvaPtNA2cbiLlkOtGzFrMQwznFIlgmoalLop+VYXFHq3WK1Yen5PTR+pc5wLyeA7qWh8rEF2kjx9OBH+mmF4t5epg0Qpwu2H2k9iNvprGByFnCIBiiQU2WKgDmqmEBOI6gN+PIvP+zhS6MV16NpQzeHDAaSDye0fi4nNCJyxMPGoo3Uqz3RJuDkMFINPGtkq4+yXBXkTrsTIPMh5J+pn7wMZEGhgMLwK14FO3iFEKdFYkv5AKJ0Bk50TKMzOlwkhLsbKGVYU2A9XNZysy/3wZqQQacErDBckrELeVmtDsPoEUUG+KK9/lf+kWcEwnNoHuxFjpbYxCKA1cAHvXPWJg3KXWnSTosMJye0b+R+g6hCLL1h8CmbxIaQoxag9i723cmvbcWh+hl5CAcN6p9vDvGuXVofoCXB2ABVNak0FEOXz3w9HUkdf5Kopv1TagewfwokTks7c0qBAajTCw5Hm3+yC1hyeMSST3M/Z+pLiSrMoNogylNctvXs5nz5nwIJRepizKW88iiYCAfW4s86CgdjZiKa6Lwff/NX8R3/cT/ArSTAnBNAj4HUITU5dKsppHjFMCQd04Ne18KlASWtEfLw7U2bKeTpLmZE8PS2LgSCy6v0GulM+T81Ki5peRMvUxXUvLWiOWpOkGKaKYzCLOfl493SW5ctR5yfr/NXflv+uiDYwake9nPvZEH4/G2qoeMLHe8vMvqlyNhWt8Epij+/ZHU5fsJQsZEHqFIBhg05BxoYUYpKRARS2A3lGIrmbjYVsK8nDHZvDQkmNALoXs+1wuheyZXAWPsOwoDrW4OtuRMiGh/LM+caLyKupytkSRDKyVaIG4aHbI1X4wlBQFh2zZc9jP2y477X/lV3M2Jk1roxL1q6FkbWTin5suBEyA7e2bkbkauKPtMF8muh+MB20AChAJ6Bq8QWDWCQFg2JNddQycpg0BoVSN4jurnlywtwPGyRd6CVNiZJiHHBEnkHoRXYpbFRmNhlw38S3juOAMY7VJwqUR4q5uTjOHE2ABnAik3xsNqnTNrYRD4bD38eFc8f4vUfVxO97WeOBLcDLQEQB1LyYDgxlvoYL3jgJvKC33zDjJnfQkn175ZGwAF9EwLFNQYR7Hxu1r0xJqbCEqqn7us6fgyoMxxEwDBcga6LXqrRXONc3LwuWxSVu7kgM4SGwdxU3CcwR9b1DiT1/qdvUfkM31d8GeMzCW3uOX3tZczN0l1ut3XRvID+MvvWWqBd03mqTTOMgmDCbOCe5el9btZGu3tS1FYPjXuY98f330ge2kJW7iSM/ZM2paxf5QOpylK612HOjw9V2586M1O8z8TyIUdMtjXBfK1VgJ+kK77ibDpS41EFRdGkKSSFGSLhTn9TSAPEHK0lPhcOgJuiuAcTjJdBrl+WT5Rt3Vu2vNa70Jo24ZtO8n7x8RIxIx5YkICDoWcQ/mAyfCUCiQ5U0ETTndLIh/MSggqtu3kVhuyPcbrKLKYzK6QDOUqpfGWq2Rjz/Lb6RwrRqmyh4kLz2VkgZ1qrV7WnBM09HkSN8pMhlmL8eBjiWSNPtL4gSqOZC0Zk7VPo/5zIXTrOc05svBXMmf3HgOhSHA5icRqhPNrkikf87a26HhJSiIre2q0bz9Lrf085kTdGlrdwPwYbveXCy77fnvevlyfyOuF0D2Ti4g8KXWrDQTyDc02Koky1wXQ6bmb3nUhSQeExY8dniMKJNExx9CDul3O1pxOG/Z+9uTAAHDaNiUl8DMCbk1hXjcZig3WrVUcocxj82T3TU/7PcxaaL/nNgwaMNgomjFL7irPVyV0vReJKgazuAW5jYv9nJuBf7BaJmZFraJVnEkrbECd58SEvJ80wZIHOCkFOGiSjUzMOXVDNPcf2eyC0N06sM/LZ5nU8ZEJfcwrWxNEzk8AP31huCkFuYjmkW/Yx7cs79J7hcCmDRwBHDJuFZJ8DGkd31/X0UgPnBzZ+Z1QBqzEwqnCApKi+jmFguctYs8ivbhDyuMBWs2dylx0Fm0zUXLB1I8NRBjZxfr9CpCylSkRVBJSZ4TF3rlwiAXwWQ8FSLZ7JPT2xI/+w9+HL3/db1kAdARcUQvjPFjdSEolJ2QZSN6Wlzya5sWh452IO4A/smgc8g7G7+Fqp/0wIxy6pTJIw/lYzfUDwkJefRabLBcyF3PcW2M4/Kqe6xsZCJl6B17TzqeIXG6L1VJreJAVHx4weej7lvbIH9a3uY1BgqwfZY3m/Ha9PysasxtbjEm5udYCcI4Ga1bTA6Gzc5mkxN3rcZDBYe2Q6lC+CWxELpE6k2CrG7bTSdx1q+xTgzoASdOztFOlBIjVmHTeEEsEzKHeLnZAQoJZy35X5sScBbVVbNuG3k/Y+y6BZebI1XU5WJ+5tf96EMj9aVD5lCSA2EiMWfgIMEtq7l46kDUWTMCysC/7HhlIYTn7aPM712XMAXQs+59Z/aeelRblbXgPXCtU4OvVkYxlRdVyvymsZmCTo/VO2nCdxBzWDopowyrRWBtZjm8MPes7Na0TQfDD6B1tu0PTnMBSj47LfsF2OePlej7XC6F7JldrFX2XKFe1SEAHN/mXAm4Njw8PeHx4wMPbt6hEePXqFT78cMflcsH53HB3J3nq7k532Pcz3j28w+SB1jbc398DtOODDx5x+cqO+/tXuL+/xxg7Pvjwy7hcdokG16pvbKbN4iqRJacFFNAD8Yw4HyB52qQtl/2iIYfhIKb3Ha011/rxlFQMpikjtZrNOXzhM6TDPFFLQW0NTd02a2u4Q5x7W5Icz7AaCrkV3/lSCNQaWmvofVeCnCIRjuluXLbRW9AVSwshwMPC8tuVSaCFOjYgKP8kgIycLdi2TTYHhesOwBKyM0IcGuco3130sJKMfC3kykCbIKH1xkQo6MbXa5laMmeL4ZFIBDETQJDSFeR6+Xvtm+mklcgqTTfPNcnGr0lqC7nFU+S81tatg+aWq585YVWAmEFjzq0WJSXyppfX4WBhUzbpFjuLYBlAGw5W3OpmQDW9hxS0GsEZcyjwiZDvokCZ6DNZwCmSkRsgciulWuIyQRQlT8dPfMd34uH1a5glIIhtspq4tKBKHi3fQCOzWqIOMNMBPlz5Y4zIYKnLxyyBM787ZGNlFrJ/4oJNRec6DTmnw9PPz5G9zwuyZoSNmB3w2xy08XE4L3Y04ZG0woaqU7tM5vL9q3gCbMdbfJwslb3F6K5uPlpGjRil6Z9AcgDmlXDnxSCamyrt65JZxghke0CSz7A1C2E5tbV0UXIkRYuN/Vp1/XBQfahDtOJKLHxDVr60JwZofZ5J3Wl0/Ov/5Pfjb/uV78F//O/+Kc3ZesHQkPMWxbNfdrCm0pBImOJ+xyqCqfNhzAkaEZ4fAMaYIBroAx6sZTvdCVFSBdH5fMaYXataUj743HeQKLnI5CbIsNVB7ot13hWbsD5fqaF1z+gdu89HUSLldBcW1RfeZ3G2/+jKaHjC3OOt36ce+wjSHaTM9rs1BcHAPjq2TVKw3JoWVoavbx5xcno9t21LLpTQIChhVSQiDDCYLOiU1GM4KRsyHubE5bLj8fGMh4dHjCnBuSbkbOjju3eS7/cOolyZA/t+xtu3H2Ky5AN+uZ7H9ULonslViwASMIufPonZvpYKgNBgbnoT5/MZr+7u0Kp8NzVJ+OnUQLVi2xrmHHh8fOuas/tXd9gaY4x3eHw8o7WKN29eYzttGgJ8YBYlaDBlGzupDNeoFcYv2izdmCTJeFk0aAYobeFngp8rA1hIq74PTQhia6Fdo0qopWDWKtY+SPTIVhta69j3gjG6az6DCNkGEYERwooZLllE4maZncny5sI8AdtYyuqqElYWrCBlWoAYA5KsAV3EjZVNtilkNlyucNIUBCnAjhEerE8lyOAf3riMSAVGOgKspYiFTAmZ42OdDez7R0HOQqupn99AW9FeOLGDnxVcyZxdklMta+O955zIBVgO2TgGVrJiT65ueeRgQYILHaP8RSS1sNLJC90ilzW6WYZOkuL3q6iRGfhqBQUUi5vTFbDNFkSyBPYRlMh+3vo3zYqg9WFcB63wTjIJ5tdzkt+BnPn9/nyAx5hrq1LASNzkYx2iB8lIFGmydVPesFhF5CzhXElcLotj7B9m3iJbG9NsrJQ1gItVWJtTiNWLmZycPAU0U5MXGX30M098y1e/HP5KfQYsfbhaKA7UyAk00jpzTRbTKgLzQVy8CTjWR+uv63ITodMvCcCcJYJpFJsToTh0hUi68vg4fnr0pHClUupvAuGf+gv/Jf7pf+Vfxbf8+q+htU2Hrb7blDM7SR7YSbJXG13Mi46WzayhPxYF0Wp1H3OqQlVcPbtGwt37HjzW5JDHgo45c16xVY6Zxc0/hru3MiumfO92Ys/QHAjuEZSDh9UaZ8lNpn6mLp1p9AAhbDKI7cWVbGv3XF15HYxcbdGHku6Gln3rqHSzOuZ1JMpcg2jZd45DAMoS858AACAASURBVG0TqyJalL+WUxZG3tm8JAbGHGBI/kGz3KF39LFjzB5ym4y+79jPF4wXQvdsrhdC90wuCbstmi2ekkScmT0ROEFIXyHCfrmIa2RrMMVl75L0tzW1ZKl75fnCqG1zrRTAuFzO6P0VmKdaGZTwzCJWQkJaeKZsRgdjkLuBIQM5WVuNULkFhtOiqs8TCIMZxHGA2V1EIW4bFdUJnRGp1pqAT0gda6too6HWgn03F44BOZN8PEuTCCilzXbKuTmv6wytnAFPiS4qeQCbhnO2jd43Svun++08WHqAlHDaHngSwZklzP4269y1FvPw2K2SfEfPdX2KwOEGUPJysPIxwy9HWOUiTm80Wnc7eIORxCB21wl283uDSC0wLYEGI4k3iYY24mDQC+Jn4FyBfATaWIGG/X1VT+8jnVuHrxerF0fAkdy+OSeK91u8oJirpd+8vNhB6gJ8Ockhvzu5I/mcTt8FYHniffZ5shrkMZvFneuTCkhlxLoy3VWS/Vkbsxb7tBCFW3OJVB5zAhauiJiXOjqow42p4qg3bHJ+U1rrsiubtZPVnVuD9K5lPzWGj38dSPITf6xVPRIxm+tXL1qJKg5tMKkY6bBFzGR/Rf04t1PLZiNz06thc4hAknbF5oy/47qVxNrDPDFtrtlZrUMzjg2VJXmhL1hWiGU+6fqu65TtC9/4G19CGwNcCmrTlDmlKJmrsMTSex/gLpEc3TUgllpYRGKf4wCqk7ggAsxF3bsbSilyfm8MtHbB+QxPSyKWyuL7iwnSLZgHWcT4oLhXCdA18Yn5y5oG2yxQkjc2rKvZZdJdKcnOUMY+CFiEbK3wYc2LmgaRYmY8fOELyFa58MCIdaSQHUl5YiTcIHX2+bEdV+R2+T3Nh9jUnIi7AszTcgyx1BaxJNLoAFWM3jH6kKjXIIDlTOG+7y8Wumd0vRC6Z3IVEDY9fGwJWYFIHkwkCXK3bfPElHNKRMxSi7oUdMxR0KoQn8kSaKV3CQktkSELJKdcF+0fsWrSBHie1adbSKRqniaDRmyQ7CAswYiUzmDwRBETHMyCEgfe5WyZhVLmyZKmoRRJZqxWLSIC1QJ0s9Kp1cHDKAMWdaq1Jnl+gNCKIdx2lvNU085eUdLGOZxZAKwENKGkCWbUVtBOmxDoPoK0ZBDhG52FeYeXD8hmUfBRDpPHi+I9Gc3cAM7H65qYRVkBkA8bVX7+gORuET35jpa976quXs1rMhdligxXUvC1L2+PgwcjNOx9Py0q3aJBz7go+mZxO9Px60FMbmz62YUwJ5fXj1IC7hXI2lhb8KYRTdV6C5grThoziY1UHPBgLFZHv8/QdxZWkoGP95ncMAF3e7Q6hWVr7ZxrakN4iohbXVzJ4hiYvRBb/yLSoVXbEhBHX5ViwaHIAa+dGbZRYGuVNnSVxUK9bF1bWxZ/Jje2ZE21YipXsZ5w1CU4GuVbQx5p/uaaXM+wlSJekStY2+yzFSwvWaiPbHMRR17DfNHyX9cakP/fya/KPltBGfD+MNAv+TbXMVItuTKlBAraZ6LklLpPMmtRmutWlM9HwKOvGp3zuWD3cXp2JTmFLNhKEQsdACiZK0roiAiXvYPZVQfunstRuoiFIefpVAloI8us8zQnuIj7Z1Wl5bZtaNsGUAFzj+pS2gtShGBbE8jfzHDqTKkfzMPkBpHJc5wZ7qYoa7J8txI6acPoQuimnl/nUsDlehTbOmO/Z8uYKTmJCD/7z/wx1NokmnU5uHiyBIVpFeizf+y94khgV2+X25fhBU+BkJVghmeSJwPPqRY6gDEEB1EFzYHZB2bv2FpDnyz5fqfEM9gvlyfr8HJ9sq4XQvdMLuaJVqq6P1keG9sIZVM1v2+LGDVa12iVDZfzI/Z9R60Frd2pLzvh0kXLNnoHlYbTVtFqAc+B8+MDTqeGrVX89d/1N6EUwuV8ln1ftd9jTAdZstGZq5i4MxV3E027vm7EsvhKO3iyH6jmGovzYjlAaPxqqQ7UZPGcQGmukR8K0I3QtSbup0d3Mlm0o+w5p57NILd0SNRKONgJP3tLOhrl1SJ9wJPRuQtI8dDNAYihGk7bcQqZm5hDDOt4AEgbSwJjlH9ef//R2uo8uLSc/FniLE+VcXQTlG4NRBi8IAJiHOt+vG604haC/VgXMzsgO5LIHDEvAHic/TzWx+VhYFw/M1ei0BKvrmpB5o7jOeo4R847l4EEJZJMyzNeDgOk1mKLiGnR045umocW6Tw9aMXTP+ZIKD7NXe5Qh6v64EYf3hLoR4zNwPvrfOG0bvjfMMAaa5J9Zq5YGZgZobZnAIDsPKsRyvT/VCvkmcmpcU6Kta98vUh9CgaIxW2+GPE30uFyW6O8hhIBSK9YxCh1uTVBEpE6tGJZIiiD/Pju5pRjeBqR/NmTkiJZD4iir7KiwNvJcM/piQmaNyz0uk66og1Ii4ha78nmSgq0kojhQlCI03e2PgtxK5M10mOwAXuvzTMrh4oFC7F3FZf7tu0iCQLQh9i1zB0Ptg1qZMrJmMQyl+2cNxEwtY5Tre4kCb3btuF0OqG2Ct5XBcKtaXVL0Zb3DdIJYWQuk2zg9hjLeV/hVPXwVmY/W0+2vs6JSfPKAiZ7iCo4Z/QZp7qKQlbzi6qCBFhzdBIRKlV0O1/ISQI21EvMr5w6aPpeTNaj0X4fw/HZMBlQ0b5bzxRfyZolBVMfF3SqaNRQdc2YY+DUXmHuuyh7oefwXix0z+Z6IXTP5LqcH9EaYU5CfxxqSSqwEPlzTrRa8d7r1/jgg6/i8fEBcw7c39/h7u4Ov3F+xLt37zD6jtPWsLUNp9MdzuczLucL3j28xev7N3j/vTeYvWPfL/jKl38D77//Bq9fv8Iv/4N/Hz788ANc3r117dmpFVyY3V2ANgWgc8IOgze1DlrCTjcAQBb6guqkrA+J2lVqdpezxdo08ozL+YK2NWwkwUOmpmxoVaKhba1hXnYwGK01EBH2fVe3ze6Hr821QtZdPSe07yASF9RSK+a0+6dqdSO0sWyoDRjDiW3bNtyXIoR6Wk7AIn71ukkacJ5Tg7mUAto21dAKwCdAksfyRIWBEQFpRBG50fLkAQasAUdZuI2ftZQbo8zkrk/mjR3GxQNks7Lca2APxDk6/T3DHiMrqYwgp6leiXAswMPrigOwW+gKgliuGlxmCbhjFh6TmVh0KNUnJwE/EBUjU4dzFlkWuX1ZPl4WBaCYHPCbSuRIs2aYW+YRWAnwU7lO0YJXrug650gtCRa5NcjldLfFnH9JXLOH/y1zd8foXa3J08fuTHVZ6uVNtrGxMjrv8xDETdKX+8aJrRen54KUFLVafT5YEa/uNlH05Eh5PTByUFx/kTdg7fEY79b3ju2UDOYROFVGmfTNUkE09YyTkYoAldDPMulY3YZTjQKlrjJPn8WwVaakxDHG3U3Kdn3Z4wkQp153GR3BvOSls2907fJbaJnHprAgvYeNAKdads3H5eM5z8tETLxeiflSIiem3CG1ssVN1uvqwqfrtriBmrJN3m195uOTSCx0VNAKo1BFbRsYBfVyQd0vuFwu6PuOPs+L7CdD9h0iVIj1ZvIU4jb1rPmo2IhQdQ+preLV1lBbw/lywcO7d7hczhpdkzEQXiYmlvIEoSMjNpbOJU0MSuPsNsFnmOLH3J/7voP1CIQ96e6PumaYAvR0Oqn3jHge9THgaZaogKEBVEg8aVjHwcNDR20Np9MJW9swRvP9XDyVxII5MHxdmqowHpqoO1v2ttpQQOggzV9XUHWMEQzTcHQ4s6wpQxTngk8EHxSKPHpUCkoFNgBbO+G0DWxtw/ntA96++xA43ePNexuqRsOeo+PNe3cYc6LvHVJqx/n8cEv6L9cn8HohdM/kEi0Nu4bLXUwS8KokybQzECvlHqfTCUTAGN3Pkcki2ZQUsiwgdxOn7Q6vXt1h7xeczw949WrD69fvgco9Hh7eSWARqJJLz+wNSgseyImXaEpFexeBSOBadCyA0EBmhLIOYMeYw5Ac+6I8q7lsRoRC25DtudUf3t5ztNApwDDQp9WK+2EKYgCq5bdzekSYWCMklqrvchcjOQNhZz+iwdPBCXFZX4Ygfo7iSEDPEeyFkt/qzgCTHOW4SdyuL4NdQeaefpI/4q9onpEpIIKYPFWdhL7iIa+X9+yBzBkBvVnaDcDsLkDDwlNHWO48JHPZHn1S6yRiDnJFHOMyj601kmq0zaxIdh5HiovgK/YuGWNisZgaqdLnBZB+hvQYDGLy8xoyTypKEZDiZITDip6TNNszR0Jn/37bL/4CPvjMp/GV3/rbov2p9xatgX9gYzn1X77v6pno49Sb6ygjErmnOSBrkQaO0rFcWwOPgYkBHmnOsw8Pr7+fDbN57BKNy91lrT6cPA8ycfAPjFgkpYef37N7fGTI/y2kewrkYu6kLgeX5UeTupU4IQ2Wo9A/JrnTNh9f+jUzpuR13p7xNVbnX8zyGCyJl60BhqzYmYrXObUoUji940CSC8S6QyFYo+bMkhucmVGpyJE/UlfvNCZM2UjFrHLalgJUAtq2CYHhiTo03xzEi8UaZ57ons90yj1mtZcUB0C1iLKT0UhTF90R7k4n7PsF+35J+9pc1xlAknTrmKE84iiNQaI0PEQh54o25FGS1qC0R48xXXFre6H1Xd5vZZ+KvrHvKzOG1t3qn3MJ2hr1e3/wB0Eg/NQP/ACICipbVFCJAxDRhcnrZj+Plrxl/TgQPUrvfeq6WQYDpTJqnR4lddumKNG3DcADzucLWpHcv8ViIzCjtYJSZJwVGFn++IcvXq7/f18vhO7ZXFMJAGFrTQDpnNgvl7QnyXZTawWYMbqebyPg1atXYBYXv8ezaAm30wn396/R+46HhweU0vD++yec7ja0R3ElMS3/577yIbavvsP+6g5C0JQs1SqbjS86qxtbqxbZCrFpcmwgEq6f0+IbQU6aRqxk1ihgUOXYHGCIe+WwTcwsDTT8YLcFdDCLYq0VQw8my7uyW5puGGP67pU17L6os5EEiuhddHiAg9gJoZMk7nnhJwJ6l/MFdqTIQqy7e4dvRJosGhbynw4bltVRX+51VosgWVh2CfNPHu5fLzLt8zriHLT6B5yr5e92ILF8d7D2If88kCb73cvkG/8OdcsEAQYuwvqxulsF2YrgIrzIUfolrIdWL0qkkImczHlrEqDJdVzduwxArZ9lkHTExKI1B6omsZe6R9nZchPugojf2UD7wa001dM+l2h1cWjfkt/6P/37H/uBfw1f/JbfiX/vz/zZAEm5Q5wGLT0NnTQ3uJt+wpk6Xd94C09l+RZPTUGLhXUOs8IGuLc3aS5lGPlzJOtEI/fK0rFxP5Eg/3S/jJcSZRkgphyKn5ciVznqGjkZ00YMrWlQjsQml2LzWFc0BG21h5VFHIjfVT2uSo43xCd07ND0AHv+wOPbbpXupMzYal53cg0S8crVkFdGLU1xASBkxXIOjYiU1HvnIGi2tMlVPXPqOenkRjcn7s9nfN//+JcxhuSPW3MlyrwkqnLWq07UJqROohuORfE2VKkS+6Os8wWSioAYkVDcPEpIiNJ2OuG034nXCMx928ahLQVCDkw5YDWdPEEzgo6RWpdyWhHfW7RdlDqTR09pCeQJWUvgey6lMWAD1lyh7WhDTDrbh2wMcyiQ1eI3p0amJcUKQ84PWh5b9onN6BxBx2z9s7Ya8bNga95zh0mVydzREwWQIx2lVrGyAehj4HzZse/dXUOLpmqYPLGrBbNV9eLR4HQbBCttreHudELvEw/nC3ofWDPUv1yf5OuF0D2TqwCSpqBW3J0a9h24nDv286MuTg1MAwNTIj32Dla/bJ6MN2/egHngfD7j4d079NHx/nuvQfQe3n74Ib7yla+AGXjz5j2cThtOWxNCpWGRv+0/+lH0fsGPf//3ysYzBW40I4+aLNPApB0AtiiZ5qNu5KQoGLWIlLWQb2a2OJ+2TawN6qcO1ZJODbAi59e6n/GZo2DY5gRoWZLstRTSCJhjIZ+2mBMBQ9MzEGhJCgpAI3lB3yuL/hjiQiGbSyYfskm21jBVMzvnCDdJ3ViZL9j7jgLJM1jVzcctc45hNOhLIc/ftwK6TFLStVgbDmTOiCnFzyvwd5PMpRKT1lRvgbmEXlsQw7XK/q3ANMiAjZMgiiZXe6/VKhJwe+2VLGWXrCM5BKa/N6cbsMAm+QoZX4NMJ43+jsN3mXSbrBMT5STTpec4wBcKUNjcl8Z12VScAJisjGxY0nYf515BBbAsAKl3i1Y3QzEyhis/cv7GMYYT/eMYuSYYlAiE3ZuIoD+YlDwZ0Cfg5KJJlCJbIYiw/E6AWgt4YYRed7axbHPBwJrytESMcp9au3JYdpNoHof+u4HYNB69LgcZLuM0WU591qSxXapYJFNhIm6ru7dofS3B5v9iE8utXKQd/1+/TvTy6v7jk9dkbl1jopLs42Lh0zb3GOvalUnd1VvMeiodarncyEldRCl2NpLzdw5GYQaRnL0mkueMv5z2Hd/xV/+qKgdJTHLepJiDkoamodaB2iZKrRhDCZy9bbJaABmFJyT9gQZ/+X/Ze9NY27bsPOgbc6619z73vs7VOrGLslNVjnHZ4CYJgoAgsXB+2Ag5kmUjJARBECGIAjIYJPiTH0FgQEkkjGQEEkKJm5gg+BNjlFikcJu4i5BASG4CCeVyVaWa9+495+y11pyDH6Oda+9z3yvHkeDdM6/O3eesvdZcsx1zfKMt4l+3reLnXmuNPJFEmOcZh+MB27aCmbFRrHn3gWXxz6sI6xWA0TZ2YSq5FIAUoMJp8B5wMQHP3/se/ME//0P4sT/1H4Dm2Z81PkDW7uTRp/N0WjRqAVQReGwE4Oovt20a4VNS0HgAEiig4w7uSrsAUFcftW3xMfU5ASSYjL7bcty2JOA10DdqFPNyHc+SaZ404JTwJdu24fb2Vkz6QZimGXUWAW7bGu7u79F7x/F4wFv3q+YtFB5rmiYc5hk3N4zWGbd391jX5crafizv1vII6F6SUqr4YRFJxK+pVvRpwt3dvXxfCmqdUeskUiBmRJ6YpvlhxBSh9Y6yyUE0qZSKlFi21jTfzYTD8YDem5pzyAE0TVMQ1q550gpp0t6QMgqzZX47GWwkGa8zbCzmn3q9u5kBOxAUWAavl1kTkeo1I6ild6CI6RV1ineS+B7UViXqFvIhYhqdeL89Y4yRhY8OJkAPiQRe/JrO1zRN2NDQeQsmDewRvkTayx7R0/pnzAxZTPpOw7jtWbDxWmaqMgMfYM4SH2eAR1frjCoHJj7NHxDALrRbGXTArw3R9GDMc1wzvixMAvdMfTwnLzZ/hQsoKvf0PkjORzOsaNcIPh8ysUnAIIEybQhyxEUbk6slrTNW4GIAZvc2ZCWqA/2r7ZLRMzBn2lfa9d0FBTpa3XxdjfkzIUaPRMGe8801dteZ9Lw2913fM/cPrrSRi7/aT7/VAXkG1knbRnCaJdfyXoAPbpifGQBTUGRRM3PzbO9TBjTXuhD0IH/m+chMozQvPt3iIAXucczCYj7HraPv4uAawGXN8UUwXeHY2kvok8Zlf91vzr5uubPpnty/4T3X3kjDNzRsHlv/mTYQkMAcO+q7UvJgWauvANixfQSLuqzoD70TCksuuW7zyJGyxy0n2cCjVZdpFqmfrWpypimEGkkACFZQpy2WOgVcSkBoiTqNlOOtan3Hw1HMOYlQzguWVSNRk5rvkYyYBXOxdhVNceCau9hQPjty9vm0SMuJ8emP/h6892/9Xzg9e4bzl31Z1DrMiYKiHd0a6bSNRYDUXFepBeikwVpSREuCa9gsXUycR1H3XiiU0xxlcCjPhaY/17f/fV94oJGhBQRJTlnTRLpMh+SZwzyL4GldcH++R729AxFUSzejVhLA/QjoXpryCOheknI6HLEtC7hXTKeTBjaZ8PzZczRACccRNzcn3N3divSqNyzLgmmacHNzFEfhtuF8PotfjGr8Dscjnjx5gt47lvMdjscZx9OM1/gpbm+f4/mztyR0LhEOs/jj9dbRNN9doYJaKs7nBWA1qagF01TdNJQVoCEdLKzmXgxgnidkf7uNV7SpaHJ0kbpB+1kKobeO57fPcTyeNNIXe2RJkQDKc8zig1BKwfF4UKlf86ARAnYl3LTcK0BxUlMKY2y3rWGek3YtmXOSSkoNRBeNNkpUcH9/FvC5bB6N0xhG7k284j1QgmkZjN9UdqyUkDDTyDBnYGL8OjsyyqBuV+x0psQ4vQDTPVTi/cbsBqi7qFDfGYcsDXUYI9d3DC0YnohVmAS4FoZUCn5NI6fc3wi4HdBZO8PcMueNs/b5WNqzKqAIxZO851qeuBx2O2qBM07uB2ZDw2m20u8MDSyQfFGciWBb45Hnioq1m3y8PJ+caQ8AZLNKe6dpsOO75maYf/a//WHcPXmii8x436Qrocv+Mo99MVw2goK0pvPizmDH65Bw67ZXIjosJwDM/l5rR67e516vlbQOTVttARHy7iHbpIB/N6xw6wtGIOeflL67AuKjyza/MbcWvMYAQGvtIppeaCotuXNEAnag6e2MtnrbL5qzi07r6SYC1AawGkbKn5ZvjMPW/67QmeFp23tZoqEmiaBIWzCkv7houxNC2BPeXqhJpANGoz1Bw0gjNrcN6KWBmoKHWjDVGcs04ae+5mP47p/7eadZ1qYAbDrGJPnqZiKxtKhVNOKtyf7ahKbI3iTdh12jYkqTaheng2VZJM/s4YDj8YjT8YRJz5vz+Yi7uzu0N0WjLlNlUThDaGM0rE45kFDud/IJz2eILXg/L+zcCS1fIY3iCmjUaoZZrNhPZwa3FQwN278DUMys61aEooDQf6g2z0DX4XBwq4rQsqVzEkLjmvsfdj8gzdrJgkUVUuF26scAzDkErkgWQEZPw+8YOB6PKjcznzzhRUoRk8rlvKK3Da++9mVonXB3e4u784K33nqG3/2hD+EwH1HKEzx79kyij78ATD6Wd1d5BHQvSZnnCZKIEkKAKomJnp5prBGuapHob0ZoLcJkKSfM84TWZk1UqYS2TJjmCcejRLzcthVgsfE+Hg84n+9xf3frWr5aqx+MbdvAk5hVVA3fD2YPn15r8YiQuRjvEIeYAj1ltIyZ78yYShHTF2MiSOpemyTcPByO7ozc1LxUiH5FrcnsikjTF2wStKRtcmi6KWUQ8t46oMRdgp5Ak7KPzEg2yzCJn/VV0kJUbFvDsqzKyxhzzeDSvd9am4wNiVTdmSQ25smkqfuRHAvpc33POP99LntAJ4XT/9GSLEm9NKmzcQ3tROYB0/kqLFoGbBTatb02zsYizEulTRkgG7AcTW1y+xTMOQNLqb1XzAMTo+3aMyA0c6k/DhQSCLkGxveAriUtmpXCZjoWgK4r8+FadJcq2zgpU8uhnfNgKXtNEeBjGEOZQbP+fwXMpY6MCeRHpJEuBphmWwcl5tK0c7E+rD/JNHOoMWnA9e9CNPxtgC5BlgBEWaJ/0drE6O4/U18j0E7BRUnAyubUgHh303I1Xdfoeg4CVdvP1NGZUBkAKkijwEQwGBrfB+DKUovywHexrx+iNKN/ZzxI129P9ZLRPn9E3+bYQswmB7w5vCfAnLxPQb42V3dGXOCAny4tUpoOlnQCnQsKi6nr3fGIH/nH/yC+62d+xt6CXKu0JwGdUlBRMc1T2q9JQ5uekf0qLg2+56gB2+rgBMwSHfl0Qi0SyRl63pvLRVe3CNIUDNKV5u8iCyLkBBC4WBpkoC7G2BKzb4cZ/+gP/yX81T/+x3xfeAxQFr93ZICVhFzMJD8y0Lt5S2ehBSipEZU0a+isWD7YLEgUtw44+DIgx2pKbt/bPq0mGMzDkBaVAToCPL1BV9DubAzUikkH06iQ8UaaPAncG47HA+7uhY/Zzgvuz4tEIT+cxJT2cMA8n/cL+7G8i8sjoHtJyjRPqFU0Ntu2qVas4HQ6uRlUa6KRy5Gatm3D+XyPbTuBqLgN+bZtWCygChEOpyOammiu6wIiixglqRE6d2cUAWV1lKkoifCaFiOJ8xyIGF3qOyLJDzD2bhdPRrCFobZQxkTkibnNxNIYz1pEowEiTWgrBNv6tJUCoLnWLEwvi0vasn9V+Dxk8KD9t4TsHKY3hQiYcloBdjkx75gVY0xLZnDZTtEINZ71BflgvaLUSMysaVACEAfjmZhiY2L+XgoZsAvGRFulq8EOy6En8Nx1bIz7Dso4z3FdO3m1KQbiKPeP7JVXSzbtvHaGZjMqf4eBpFTpNb8LZ/qUqYjejwAhwB4N7OEeOHaXOieAZ21IAVO9P4kRtITMGcwVsndrG+0nSbVHfi8x8TR+kzDJxTzu/7DekT+Vxmm33uOd+rMDlbR767BWLj5NsxcMIqV5dTCW+7Wb14tuXbRnaKZVYps3+pNBVhpK0yCZkMcjklYJfJXTTZg21QQgYKWzli6FQvhhpnYyUqPW7rKHCejYh0/wAxuJjIkeL7t2/AWPPtCI9HqjeUY3djdceUg06oFMHnw15VUtYy05LqRDdqy1okE0WML0lwpAmXhfI0rPGQgQA6DWCdPUh8HprXjUZAd0PZnaJTojvvSRCqhtDaiyP00DdDrdYF0WLOui+9Y0qQTLlwZABAsuhAnwdTEsShfGrxj/9z/09fjIX/9FDzI2mKsbLccIzK6N+WAarn02c0g24VTnC/nH6E+ncz3kQX3xgTZGIqaL3zMddEsQtZIgEkFv7fG9PW+ROU142zuHBg9edeKTNHdlZzx79hx1OmA+HHE4TDgdD26d9Fje/eUR0L0kZVZAZ4S81ooZs6QYWDfPH3U+n5NtOXmwg23bMM+TOwQL+LNE4xNmDX+83N1hXRfMk+S5cSfs3tX3ixPTIQxft3C9RGiBQ7QowCkUzGdPaQn0sAjCGcxABCURYurMZQnCa9LOQgWdugKCrgl8I1E0lz9fZgAAIABJREFUsSRk9ehWdkj7O+IQaC0Hnygg6urIHoeehJtO5k7qR2j1WdCCYipUpPFgDH5OYSJiA2uHYjCml+BFGJpr170477sDc8ZA7gHdbwPRjUzb/vkdqEscrt3JabFw7rfzMnFQXrwjgVCZ4xgvg0TGxGaTNz9LkZmUrOWKdl8CuwyiSQFSsIF7U7swLR2B2VD2jId1QPtgQpI9mDNNZhYkAJLqwJjCuBagzhgNX7v6TjM9vHzPfgzySOR2x5jE57Vyuc7yOon/HZv4H+bv6eQDtgzSE7qmgrke3+g7zUCbgZ0E6K5p4vJeM9BJ8cXbdXHsL2K4hjW+B3ep/xJ7QdaC5e4yvx3xdV4HgCeRMk1LpDSKSEy8+Xof84zR8HdawzzOfAQpigbnei6WwduRGYabM5OPd87Ep7QvAR5vu829P6V7iMwkV4DdQ/vafux9kuhanyfVcqeIi9u6aJ5QM10sFzQgr8PeK3qfkIdwK6ufQVIvIwduApNbdXSWSJLmH7+1DaBJ90SRPKinEwhhBgiC+KEBbi5o6yEm6MWTMpwzOnZ3T59iuTnh2//cf4G//G/+6yJARdC3ziaQ3dPwa/XHd1kzLbkbC0h9GQHgb3/Htzt4zLTUzpILQcLFfSMtzab2OeXR3vLCvnehMRsYG1MJGaATvGhz1RxA+iD22CjcGVvf8PytZzjdPJHE8fOM4/HogPmxvPvLI6B7SUohwvEwYzkztrZhWwhbqXj65AnO92fc9nts64rlvOCVp694xMRlWbCuK+7vz+4nZHlaluUMc/M5Ho+Y6oQzM5blDLivFzT1gJpZKnER8wSVJLaGOk/JBCKYTSAOAyPaEuVS4FZRcGTStuz03FmiVGZCKiaSAtjmeRaG2qNpKshTzQMN2jE52MUUVMBqUXNQ9yPSA5QTwATJ2IulawKdJIds6x3Uizgwq4g3P+vsozFqJrm0EPTYgbrMRdkfdgJfcCEcwn4vQwXBLCYmcQ/qLh77Ekpu1tvxaXFPAmIZ/XMCdfv2gdw01t5rzvCizUkN2jHJg9TVi2m1FDIxgahfZQYCwGH3e/iwmXP+Q+8aRie/5IFxH4dl1FgOjDgVFDB66QECidwPzobkWglzL2PAVAM0+NCFGfFQkUpJhoAbJjmxPx7omwvAYUAs+2oZw27tGyDdA2vMdvd4E42byf8fQFjad7EvrjOfmalNnlzjPbmR6dPe+eAe8e1JL7wvNO1irWE0sbNGAWzdg0p19bMD4CCeADC3QYgk2gcamz10BLgC3+ObnQ+u3ZXX8Hj/w2syv27Y/zvMOFy48qI8O7HL9b4r77cqhJ7l/IrsZFi0XKIJBeBpgzoDE4qY6VeZmxCUWTMlSbkINQFQpElpbUMjUi2NCCUlzWxKQ+FCm5jbtknkS4KlAJBzeZ4P7nNpfuIbUtocGmlYrDdyoGTl2j5gG4tC+NVv+WZ89Bd+Cd/+Z38AP/G9fyLt//i1QKIzR/5NxL6D0XJ/6kKYJMLSyEf36W/6RnlWeYOHhJHXzOCzsNvuMVB3zbLiWh0+jizm6ES7naICSZuDDObyeXRe7sGdME9V5rsz3nrri7h58gTzfMBUK07HI8I66LG828sjoHtJSm8bntycUAA8e3aLVUHXG6+/of5rHc/eeobnz27x9MlTTLXicDiIffa24fnz56i14nQ6qtMu4+7+Fnd39yhU8OR0g9PxgLvnwO3tc2zzjNZWEBGOxwN+5jv/KUzTjPP5DLCE/+0FWNcVrTEmz5+yYWsrmDvW1UCaUrxNDqqu19kZCZIwvyp5rlW0fV0PzDqJZhHMWNqK1jTE72HG+Syh//1wKKQSTHWsVu2hmTuUGsFRuHdsa0PrDdTEJ1FCLIfvIRXJI0MaLZRIk7qSmGxubZODdKoO9Mx3AWggSEoCidYprLkwWhAJv+XkUQmvHjMDg1cc2AWYyUfIXgs0mIwkZuYaDxVM0zuBY9dKaMEe+i7+NHBrhym8zQOwI9UWZSY7gSXrP6t2zLQWBNHCXpiVGsegwM9yHboppDNyeXyh7QrJ/TVwaOahNESMC8boghmIXl6OgV6Ifo03X2MszBQ54x4xB+rOCLD6LLG3wJKGb2F2ycKgNjXjak0CBw2BVLKU2xnjNBa5vVeFA5S+UtBmI2Jr0OczATrntoP5MxbOcmeZNVaAOF31Gfz690lDlxnNdM+4nnegXttNF1A7+pjrG3+xOvZti84N4O8C3NkYZiEIlHZOsGTxZoK5bc397jy4ytbSO+FjUIxWa1/HSJ97ZHWl20kAcbWk/fVCIdB+6B+6L92Q/9+3QkDs/jHW5ZZqJlLBjppzEmn+VBJAhg6wBrOCaMrO97co24oDSyLxiWcHdtk1oCDML6d5UlDW0dqGUgrWdcG2rti21fM+EszUj9QvUs/N3tDbht4bDvMBfGQAswpxKw4HEYBO04Tz+YzzcsZ6l+Zci9UXglRoiqBxXe+1ViZIYAb6ccav/f5vwUd+4RfxR/7Mf46f/He/1+k86VoyEFVqBdVwzWBmidSq4F3O1BHQAQraavWzvNTQvku76+BPZ+tgH/TJhNk5qneYao6auL2Vgp/rib6XUkAtW0vEe5mhgdda8uOHCtVlbN56603MhxtMhxNuTgd0FHzmtz4NgNC54z3vfR+ePDl5YLjH8u4vj4DuJSlmZplNJi3gCBE5aAAkWAkIGgREHKQ3/el9FnPNeVatV5hmFdXqiY8eUCv5+5598L0gItRt1XvNxGRzbVypFYW7+rJFQm9jwroxvIAzrsagCyOiIaH1IJRcdoySCKkdJgA8x11rIgUzNt7awxxMCqt/HelzNjbruikzyxqRCwAihUOlyUOAiy18x1TZWUjL28VmH08BNKgL0ybBawidWAO+MKD+EPK2kJaPhXzsrl2/yvno95dcjAIThgaVGMWKe6DxTssluLz2vd2T32mM03C3M5g2JgHqRjCVmUL7JRIZjwPGAMjBnJo12QGcQF3Uu++PoSXC3oGfPZjCl1CGxo9Aztro/hYqDTfN84W5plUJ8hxdikqQmfBBm6QVD6kIdM/sNXM2RobpXlxCsGB9eui++GpguxMeDGD3QhCR/9yDj6wt0HWUtdODZtyvX3uNfaH0hZIG58EujoDtnRUbv2vvp4tbWftofRYzzIJSjBmtoCIRSjdqoNbQ0MCbVMDeRkYn0e6wQg9bPiJ4exiY+p8PzvULeslpxm3KMi3B26RTSfddvCELQuxlqX4e/4MJEwAjCUrjmbX/hlZ56Gtvkm+sNckz2s2XnAjQ/Gm2vhhwYNK7aNUlmNe26wuBOZlhdrMKsRxpBjIKtrahNnMjCC2TAbrWO7bekpAvkqZbZM7sGS9d5GjJlTU8jjahHw/4jT/w+/Cxn/45vPfXfwOf++hHAJgg0qyCJB8dOTiEC5xs7Dz6ddLMG92xFEkA8IFf+ZsgInzmm7/JLXaAEfTIWZ9ovJ8b8Q6js94TBW1Fc3t6XZ0B4gHQWXTMAH3juzvzABiN+tg5SBBheKkzKquLRpnw7Plz3N7Kz2tvvIHT4SCWSI/lpShXwmQ9lndjOd/fgztjqhNOxyNm1Vjd3995ZKvD8YCbmxucz/cSxQmEw6R22L1jWRYsywJmxjRVJxTiCyBSJJF0mXQ3AKMRu21r+OIH34P3/cYnPfgKAAVU8GukkjZ3IeMkCVaJEw8ELxhZP1h391AxKV7cSyknXbOgAMassmkI5RA1wGWSujpNIwOhTC2RJVzW/iP6H1oNwKWJzJ4gfdCOKaCdLCWDON6N/ksqgXUtUj6EwGOddhiYliFe5cW1RAaC/BgZmdlrn++Ad3phManrpd/VFaaAw1zUmeqSE0Xv2hico4+R/zz4Fn+ZA6U9Q+YtJJOeivmspMfY5Q8a3q9AiCwv1SUgknqjL6AI+GE1WV88BL0JB9jA/2Xwk/yOzvHjeQ59bY1jIOMwgkYThthP76bVVfiaKvlD/9UP4vf/2I9emddgFpHmntN3xiL6GkmfUcdeM7abo3ynL1ka/6b0M3wXN+Q5pXj12y5/v3dfOP/wcH2QB9g6TD+BEziNHw+f/n5KdOIKTSBdv6YNmaYZ8zRjmmcJhjXPkuh4mpwmGnIzwV4G+a13TS6vnwb081pM+z1++PJnGK+0BnZj6CDe19BeCzqM3guLwxJvWNCo3OCLNu/oC3Z9ycXJpgbXyqk+mqb7yFoe0zJZxOiq5/DhIFEN5WcOTVICWTH+OifbJsFPlhXrsmJV80prGek5N00T5knqhIKmPsydAhAPDsY+btf6bCUHyGyHGW++/334A//NnweWxc8vIkAzIQggNWGB9mkbhM0NzJIj1vaq+ebn8f/wj/9P+PBf/vFED8c2Dto2Wypd6Cn0hzuLNlI1kvmeHAgKPWhuWzds6ypWDKtYMuS5ze4ssew4xpQ50Wz5uzXJ89tbE6Ejdyzrgrv7e0kVxYybm5u3XeuP5d1RHgHdS1KW5QxmyZ1yPEpOOQZwe3vn2ruj5pM7n89qW8+Yp4rDPHvAlPP5LECoRI4XSx7eexdJGrCz/SZ8/BO/jI9/4pfQ2oZP/Avfgff8rU+66QAAATSZOVeiFpBCTaMoQODIDGQGIfrNdsjDkpXnA479PZLXp/vzxngYofVksICnWai1OtrMhzi0/5vm0DMm0BjgzKAYE54Je2YKComW0zSTWeMB2HiF/xUrl2d4LvhHY0Kva+1izMb7Ri4Xl0DJmEGfp99+YZW6cmYM9ryAznUwZYkhHX4SE37xjnyIP8zY2bpxEJWBRsIRpmUsmSH2nxFAm3LN+grAhQojQzxKfn1sE1O/ZxTf7ucyqmECf2nNRQdtr2B4p60/Zz57AnSWID3tZRNcfPyv/M/46M/+tA+crbPd9F78NlwyjMLGNGpLLzHKw/Xs7hues8sukbc1nj9TuxPwu2zsA+99m9vi4v4TA7gY0d4DQMjG6W2LRq/Ma1cBQ9UAV1P6qdMkFhUenTj2VedxHbfhM+XFu7ZGWc3qEy23uo2Ws68BBOObhmMAeV9y4fH/VLeDuwQT4+6gFnYGmIAvf9q9r731Jv70f/IfJYElDyHxu5rot7RnGfDzT9LqBOCaZtHEHOYDpjlAN9LcZNpquQiXdcWynLGoyeYY0CtML+c5QCL8nFEgD6MFiWI6GbkCaDnvodgUv/l1vxcA8Ef+9PdrQBQGKGt7MexrO0+3dXNfPzOht/qz0DjT1OtjMtJKW1BXgbnNVQJvoyDF1iYD6lfc2oZt3dziKUeupGJRwWuiiXktIXxbk5C6tYZ1ETNbEyZv64rz/b0I33vHzen0pW+Dx/L/y/JocvmSlGVd0RtjOlQcj1WCcdyfcXt7iydPnuB4POJ4OKJQxWc/+1lPwE1EqIVcAgYwjscjDsfZwce6bri/vwfRUXLbKEEK4tPxlf/Hb6Bzx9/8x74e54OZN2guFoJK16Yg9M4wmXTN/iTx+bOE4+YDhMTQJEAj19XPSaWOrHmYzKcNALatwfPqQIO1UJeD0YCgcqqWZqEmZtT0CKLVEz+J3lPCWCKtM4OUZOIp9qI7Blc0dBb8RV3pnU9xvxXKKQtYLHUQB8EA63YCem+LgpJgsi1UdwaBCbhlMGdc7m+LgbJ28DDPPj4KmKVHqU+O1RLwTNB/zzwTEhtmzKFWZHm2HJwHlhmAW66L/H3G+Fsi5uLfZckqD5XGe0RAkCK4cmi0/XC3uWWWZMHO0RpjgpHZSO+IaUlXOTEK9k0eVNp1GMK1SUTva0BRmZY8f6rxAavpsL/bv05jh928Z658nIfMMANI5nxRV743HmZdRRmoJWy3B2rpd5/r3T0x+/u5jXLt6rBVXrhvaOjbWNLCZCAlWJNLnKruDKZsdm5TnOu1PS2rhth3CwgWvY9g6pJBy6uBrTitASJtUorGC6jGlnTP8Q7UO0DNvUxmk3msdkPu3SdI233PPDB8DxS2wdNn89B6/UNbYwVcnyaG7NoCoEswK4uKCFV4FQT9Zrmnax+8WiKUXmBJRkUOqe4IZUKt0QgmwrqKJQgBQEtzktrJ3F2Lk+nYPM2wFA2lkFvv0EqgjbChJZohr+3MIDvrkEHdnpDmolTZ547wt7/h4/i6n/xrmN56C+2118a9zgzqHSBz9VChcesoXVw2qATNLFAzYuiaSKDL+Apv7e49I+0OX2LmBkmFwM7bRKqDqCe2ljxvwWxKaWCuCrYBpuJ7AhRRMqmMgUxY/VhN8MzM7tvf+oJpnkUAU8RHsq0LtmVBbxtOx8OVsX8s78byCOheknJ3v+Ezn/8iXnn6Cl595RXMxxs8fYXwyU9+ClvrYBScbk54+tpTnJ6cwMQ4r2cHbYUkGMdyf4dnbxJOpxPmqeB0OOB8vsPnP/8M9+cj3vPGq3jPe9/As7ee4c0330JrK54+fYJaC3jrWM/3uLs7+wEzT5NIlVRqVWvB4XBAVRvzZVkwVUmoKvdYhDU5INvW0Ykxz5pvpTPW84ZeGdM8oa0d6yKH22E+oJYJbVuwtQZqXU2JDugsgGHdxJeu9RXcezhkq38hICkOplrAhxnHw+xEvKhJZ0g54aanpRRMVZLCLusKZuB4FPNU5o5tWyQi6HyQ8OLMaNwwTQW1iBS2tQ5qDYVUy9I6WLFx1q6Yzx6xtLUQPaiLL37KB+MabP7IWEv1ojUcEso6I0+pjsxcKX9AwaBmQJkl0NIOSgei+EbadfvCwqZbJNJsVjoksjZhaVEgB2UMAJD5jZRgzU17QKTBbIb+JcGCMVMIQCvmPSWNp0CGfKDbgBJVlMIqQOBdn+W+dV1D45jMNy98Kxz0xaCGNiTAa05NEL4gXebGGHgNYR8pQsTEx4IOmWlm7+xCFZj5KABQwdYaWhu1gQzG//aH/2n83a/4CqRGOB4xwDUCu8tCII+8aNp1AGNuviRFz0xWIQPeCDRH7CBFX+BM7x4oUlq3tLvvuiek6QqQkPMOYKe8V+kxfQnDNw8C3vlYeBvy97Znbd+Zma6CsQJ4gCDvXuwdaD8ZCtRJ0s1IRD5hTksrYc5ra0w1S61tzjSblkNApaWECUQvAjYNDmE9oPypbVJw6vnP7D+Ocfe5MbmE0ZP98CaBQ5qdASfukRnvbhjmb3enjV1YWxiIFkuNTgVNwVJb79DWsyRwLxsc/hBLUvJtAzqj147aGaUaKpO5JCqgWjGXCZNq3GrbULcNnSaUZcG2raBtUQb/Fht3GM0wsNPahnVbcFiOaDc3OB5nmR/uqEQi1Ly5wTJNWNYFtKzgVc5KGwrK+yCNsd2wF1gBgms90rDdeTzicx/+EL7tP/1z+PE/9e+L6W6TfHJERq+BWiYcDwXzNAqX2irnt9FjqDBiNmsif5GeYxpMrJsf4nAWNjAamDeYIm7dJFaACH/NvcO0kwRCaFCDpquZZGtoHSgUms7D6QbTPEu04y7a6bYJXyM8kvoPan7bdVk8cnctBVWFLMQdva2o6GjnW9xyw+c/M+NYOl598gjoXpbyaHL5kpTGwO3dGbf3ZyyrOGJP8wEohK113C9n9/k63Zw8f1zrDa1vqgUSBlB86c4oRDjMkwRCaatI+8A4nY6YpioSwG0FuKdQx+xO3AyOA50sumQX07VaVBOnpojGgZkEGMHQcTfgIgRc/HpMpSDaj20VJhN6D9hMG8MB3A4ABtScojlTGBEkFRCQRJ8UwBcMACV1A2k9rTeXchMRehOm2Q4TYURCEmjS2qxxNPO97CPG6T1wrY367CGZHhoziuBjg3mwsbQeGKOZmC8DNPoO3v+tbX1bbhz7d43vdLaSCCPAUW6YrN0JmCSmjHZ/23hEO+VT+k0OTO0z5iGZ1XAwrO770y/7qU2L7304ON8xDJGtXwND2UQxgGAKIZ99M4axG9ujsuK46lJpqdpfAR77m/x4sklR02h627Yl86Zt0MBbPjvxnRJAubWGrXVPl/TX/pU/jr/xXd+TWhvgI8aGh3ZdBTsj9x3jnn9sFPIa8GlImjXbH0Ze9B7bLeOesXmLdXwJ5ux9GPoGnxMe5+ZqSSAwV3vtKUrtc4efNIZ5zXvz0nrzsaC078y0PUzc/YeKa6JLqeJrZ8G2pgnTNGOqZo5ZVRChZnoKxpsGh9p6x6a0elOTzNaz2aWm2vLfw8TPlnT0li+HC8NQjFtHH76ywtLFvCiuzRENj9g6DBLKDu7CpFT2zPOnT/ED/+K/jLat6NuK3jZwaxIBk7v+BL1h22cuGNI5KxWlTih1Rplm1GlGnQ6Y5gPqfNTPA8o0yfh3O9Ob0xUxBVwlj6zxAV3D6StdNP+ueZr93DNBkQD9tBMSKB+sbRDjktdfXnulEL7w4Q/h6ec+j2/+kf9ONJFD5FWjOVDBqq65aUahOtBg0+C11mSrU4kt4u0wK4PmvovcJYCKCwsLqczHzlc9Z/QMkfQrmV6JVlZoYot0Ln6OxX1E40oKKwcTeBQX5jFGYV4hEd5aygnmDkIXDd22YLm/xfn+FnhMLP7SlEcN3UtSmIFl3XA+L7g7n3E4zCil4ng8gQrQ+oZ1W7EsC06nE0RrtPrz7tvFjG1bsW2iGiqlYCoVlTytsNj3T/LDCgqhxD0iLmn+FgrmykwgneAXiRZlDvbMrAnCWRlySQZ+2dcxXHC+DoabKjDLuWmgUooAOPOna20bggWYT4NJOGuNUNVyODRFckKY7dDkIuMVhNsOFFKpruEP09Yow9EZnSzPTeTS0UkJiXZiLgZJqf3k/F4APNnt8FQ0bgADlwgsboVIw8FqIsR28GHg13l/v2na7NBHmHfJ9QBASRGze7cxrNgJ4rVfquW1w1lfMPTX3hy5jQNMu6Z1/2IiSHakeCtjzL9kwgJWn7LRpDQaIu23cO8iUAjtpbbOGCZdd7lNjFz3HpxFV/P6YB1Y2ycRsVNbRuHvaYyfaOhM02havxxcRa61BtXOaV/TGsVuL+rXoUXytbnDMmnxOFNk69dt4GIuTFMzrBna/b5npHA5z7ulAs/rNYxkruGhcq321K+Hmnm1cQzXbg1athcX23e+JHz8jaGO98dWIA+7T8aoFvtN6rC1Q85kigCtcEcj0+qyJHVW0G9rOkA7vA0WidE13zDgHPNsWv80HIF3aXdNb8q7ZiBp+3VybeB21MXquLg1zxFfjmesW0KrBZ/84O9C21YQVVBbfYt49OKiEUPHGnaBn4IKkYHtCtRpxsRGXwHuG0otYK6iLWWo9stS9EiqnK1WrMsCOhwwHyQ9j529pRRJN6Rr5+7+3v3miqgZDYboeRO0fG/KnIWSLmvRa8trr+PTX/e1+Oqf/eugWvEr/9x3BU0DA13otfl8msb5WlLvnMPN8r7ZmbFPOxCaw+Kfls7A7s35au2cdOEOWUqBcDeRFC6bxxJwwawJj/UeEVKQ31Ntrybamk3cLaq2nLWaYqbLPi0EFBLmpm0L2nJ3fW0/lnddeQR0L0khknQC52XB3d0diMTk73RzwraJM/SyLKil4Hg6YlmXgVGwgGbC6AmoY2ZR+08VtapJQzONVsE8T1iWBU3NtYgIh8PBj6feGkgDi7h5l5p7GfACRFMhUjbWMM3NCbgR5wwGnFHtZl4SxNAAJwAPUALApVx2r0nqthbmkgYEO3dUKu7EbNLD8B8J7Z8FA5hlEmCBS/K9IBLGVNsoYY8lj5CZVpom0O4X88VIHDuWHXizXykxdHYU7QFb5lT0u8Qn6bO5SgFyBhL0nJM30L4+DPWN69Ou7A9/wPWzBvJ2XRzC7ec69RnPW+yc/g7ke1XCZNpPgI7EDjpo3XULeY1FfQF+9Arnp7RWy1sFGz9Ka9F+ur/HzHWs/S1FUrsK5IyBAnkfjSnPgSnGkcPOdDXAnPduWCqM3oHWxjDcMW87hhgDz/dguQRzeo3e2fO5R3tpOEwtR1eqcS45f3fttxe8cCi2365df3GdMtUc+8CvXVQB3ten+yPC5sOFALaqSf2yLgmJMd6yPosLCgp6gdDjJAyQvWZpD8TEkDuLORgR0DWZsgaCsLVkuQyD8Wc1XdZruh9Kzn/AQsMGi1WnA+TfjwMbC+bFgiIMfnNXb3joOsWadVqY/RvB6Bx7d9s2gFZQWb0SCUOv55TNHe9+cr90n4vpeEFhaMAyC9QkgG6dZoAZTQ5yMCQYGUEAN4GwrivO57Oc34c5jbWmpSBgZslXKGmLrE1vM2guuLWGJwI3EG9ZA1/8qn8ATz73ebz2//ymj5V8Qs5GbuACFAaoxtlPiS4a3TQBFe0mPIO5QWuYhcpkmsPiPIzvxx3dJGKPOO0J2fUzg0GLUmpCwNaa0mMCNECWnac2OlngZrSeKnk7zPcSKAroxJduWxec724fnpfH8q4qj4DuJSkWSGQ5n3FXi/uq3dyccHfXcXcn5hbcO973/vd5Xjoz8wqtQce2shKMjjLPbnIDbho8RYj98XjUxOSr1iGAbi0CajbNH2Ol947Si9RLEozFAJblmimloEGDmRSgcJHkooCeEeR1dfWBk7+D0axVDyJPnqxOynrQBMMh0rOtNBwIkeemd2VcCmoV3zYZGyG/Yo5C6n8kAQOAAG+hvRFTThRSLQX7NT+YekfXOiXxK6Er8xRS+vgUTgV+cPlZi2CEr5YE7Owweej7h/8OMOcaRv9+fC5LRDOACyZyPP6NT4MegtYPHl5yebDvX+8cOqeDfMccD4eoPzaCzNCOBJNtBzD02TDDAYYExNZym0cqGJvLw/2D2Za9M60h81ezqJPWf1ITudGUUzpHtjASg2j9kUBFownepY8foRRZUJKvUYQQOWqmMW0DK2fg2v9LA5/GXwctfwyg7mL9pfouQfPlPRS/gC6/vvjD23spPXnwHReF93DrATB3DWDa81m4wOxBOhQrYIR0Y92cNecOCq7lanOE5HsuKivim8slgX1ti2pNhcEUYVwvHdQLiDqoKKWmJpqHZNIsTWEHJ5qXG2aV3KL9AAAgAElEQVT+Kd3N+5FHDJEAuNPA3J287vzy5fqwcXyIVL4tzov/4JYbGc8B4VuoVjDCyE/oMMDMkhWtSg5T5iLXu5jwifBPhYAwNwI5owsRUMWFgAqhNqBXALxhPc8CDjfJJ0iswb+g66o10Lri/v6MUiccjseRVmsKgF4Z08QSPAVwS4ZswnjNp9ShW9qn4w4YacwXPvwhfOXP/wKefurTePbBDyRQoxpfnSGRR7gOOdaJ0bZE7wHg577v33YzRisO+Kw1NCYOH4Ei+zN74Jfr21I0SwADoDNhdWfxs+/JSiGb2A/pIfQ9zNB8tlVpHWs0bYjft7ald3GPef78+cVcPJZ3Z3kEdC9JOR6PmlB8w7NnbwFgzPOEV199Fb033N3d4Xw+4+7uFu9575dhmiacTiecz/dYuzjhml/csp5xPnc8f/7cc5ycTids6z1ub2/RevO6W2t4/uxNfPb1J5inGYfjBNKoS+KHB4+MaZKx3hpI7fQtZYJp5Yy/KChgTdaJLprBUrM/nhBUS60AhPnFPB+VEZaErqJpmwfGtZYimsi2AQuwWOoAdVYnNUk7Hg/irLwuChpZtJBs54mYrJgTM1MBsAHMaL25w7NJ3SQn4OwAbetN33PCuq6oa/UAEIPvFzgdaDswlBmcJD42Bt5LkgxKjYmpSfc5D7UDMPkB4+cveGsFI5lRGIHdCMjI74t695LW0Qhux6AmybB3gYVhzKY5LsxX0F2IAF07eQzCRI0GziSD9ABzMYq2roIxkM9axQ/Jc7ixBfIIAIthihhty4mETdPcff1JvWb6JI/3bC6ZAxR4QIpxLFnNsXjQPo+auuG9V8Cxv2sQiyvrlnNkJRQXgG0E1cGjKXOZxkZhZTA3CWjYOPre9rmD/30J0gyEhp+pr8thQeCScXXAxde+TeXhb4b1dvFY7E3TcCQMsQM99imUwYRGgPioEQilAx0MS31ijyX9nddlzCQK3AwMzOOcpfdXtWZwk9zeUSfVXHieta4aijArk4qbrhNCIYkcXBEaEtPOmoVCVtLb39fxd16LDyJvxAxefTL9/WKIx5czCIvyxF3OwNrE6qWuE2qdxBdunnFkRm3mG9dQekMBo9cmjLsmGS91inVHkOjL84SJK3qv4D5hKgTqTfLOrSu2dYXlRjPrmK0xmBveev4ca2vY1g2H4xGH4wHH08mFRgShW6+/9hrWdfXUB2a1A7Yk3kHfg27GeAX9D4FW1u6/9frruH3jdXzTX/gRfOLf+hNynwKhxhHl0uqyCc+mk5kfYG1PnafwS+OwbrB2Gq+xLMtwDuX7L6wxtC+b0mYTbFsbs9Yv6itAJ3QSXmVVP/9t25BS1UK0dqJJlXo61m3BdJiVFyB0jTx6UL/WUsQi69mzZ/jMZz7zgjX6WN5N5RHQvSSl1oJpqlhXkeKv64r7+3u8+uorKIUwT5NIijaR6hCAwzxjWxdsgICoIqBEwqw33N/fRYLTWtB7wXK+R+8N5ekTnI5HHA8znnXGX/m234fXXn8VT7pIlgC4iaUVi3bWewd1NU2YJgVFzRlnl4SpyE+kvB0FIQHLRDdLmUfTsgBdJl20qt2cs8n327oKoTRmXwGi9V0OJYb44LknQQAeeMRpBzNyeJVgMoHRrC1JBcf0BMLIZb72ujw59XN/x4V2g4JrtksPfF7UmTUPyl0K5oo6sxfLvi3Z3JKHv+N7Tnf4u5ShC54zmM9opNxdakG6UaTT2jIeDk9j/HExRteYa979Phz0CeAEmNtpuhwTGlgyhsaYbKs/vXbXHpPiGwMFwE1/bOzEn2PMOSftyrMbzI3lYRz3SzDdofHuCRD7hvS9mhl+3q8T0l9CKrAf4eHdY8cvwZwz2BegJvcxA5UX75l4Xn+9srxecDsuZ+pa//b78O2bdFH/hdQEwxiN9/uCM2gH0aZFECmjKxf7zP4sYtbn9BUmwOHR6o4I6ATT6jF1W3Ww0BKEDOZEOBdaFpIojwRQkTPBfex8j7ILaGw5EXDpY8epT/th2Y9nGqsXrcgY6Mu7LujtlbcwFEiggWn1vVftPJskKnKVEUHRc8D/BoNQQziSBGJCE9TImgDWXHWyT+Q+cStQEKW02sxAl2VRs1eJcunCF7YZFGsbpzEeSKmFQFHBiKwpC9zBQz1xLucjKGjyJ//Br8XHfupnMD97hu2VV338XJiQwZXRWANLvj1C8Cv5FffpgXZ0W4vlf/VUAjsh4yUvEX7XVvLzmbZa8DcT2pgATTR63ftgprS5jZ1Dux1Hje2t4AuEzwPO5/PFGnws787yCOheklKq+LRJGP0V67ri7u4OvTWJVnmYJdoVEc7nM+ZacZgqllqxkZg11kLgaoCOcX9/j1oLTqcjDocZvVc5DO5XnA4z5lpxOhwAlntPN3LfSTUfcng0VMl/6kCs9Q5qBC5dfdQaSqP4LrH1dviLv1wAuqxVMKlugChL6Cw1GHMqbdLxKhF+njtj3TYcS65fAqbM89GjvkXi0jhcKB9gdthAIxg2TV6+i6AZZhzw+pyJKYpGwMIomURyzz0YV+MM7RXW5AHgcq28HXOSwY2Mdbwz/n+b9+wYx/37nRnj1OYdqHuofdVNe8m/EOlmQVEGCRQBBzLAzaDczML8IB36ng9Y9h5n0BSaOgz3hjQ3NHSlCGM2ziOGOSNIcABmVt8lb6mPjWi9xR90XF+a607rFfMfkRC33i6An4koRvCZfPZgjJb2302SRuARwOs6xHlwEr1ch017iflwp477AND0+kP7I7bF/qG3a+z+pnEdjZfHPGsvBoTvsKTlYrM2eMJS9FcyE4h2wsK4Z189qYaQ91vpJWm4hQZb6othqFhygTnjTUVMCUl8gG0jmB9e7wBTmK8LWBRqL5pEbWeJ0SlGENJQSR49PKiA82wQ73h86fLPgZlP6BFpPV6peX9NTOqbnHcswWQ6d9HGqTDTzC3L1FD1zLK9WcAotdpIwCbO1hSVorSkYprmJPggNNrQGwPUAD2TDJSsywpA6MN8OETjGZ4yZpqnQaslUSIB8whzepeSe5tAiK7422U5mH0uT5/i7vXX8E/8wA/iJ7/ve6Xvdg8H7ZQe7fdpWF9I0nHhJ77ph34YRIT//Y/9SzD/xL3mjTl83gAMmsZBqOxtZ6edAJJZJYY6M6AjWF5Bs6DQACocuW5JBejk7xCt9iWgY0/JoPDPLTaWZbkY68fy7iyPgO4lKQR4TjVATALO53ssqzhjz/Ps9t7rumAqR5Q6YTLNnmrSLEITEWFdF5zPVf3xZk++vWpo896bv7N1qXddZpy8TeTEuNYwgei9oaV3ZR8Kbg21TE7MASXxHcrURsSrfaASqaN7MJRMoFvrgyavlCLO+CA0NI/0BdcAiinF4UCu/bQgLKPZkzLLaqqSwZOZImXG0rQfcilJojl8JIoelJZXi4gQ+ieOZ8gO1f1iuIRNgv8Sysjtd2ZOvt/xxQOYk0NUJOlXzY0M2F406WFpuH9nUvvh3A7gMrwm9Wvs5fgXpz+ccU3ty4At7k9tsL5z9HcEE8EWR400Aj+OpMy5z26CunuXMxlyI4xxMkZJEuCO0TWH4CdXBjoLRnJkOFkX453aFOwrcql5Qmo+ZgT8a9/9R/Gp3/u1+C//wo/qVL49nLsOtXIbrvXEBwfAlfW6q9/4c4Wr3ud3AqN0NlNtqX1+U8zX0OQrOOHht4z1y/AN0CC977KyEC6kv1w4IdBob6UQFCXWMgESL93mn5BMr42e5Q0qkRoV8YFQJeEzyP85zVNgIWuPtU+yljqgzzOYy5BvyUCrdQnaTw+asyPHF0s35be7IH82AvTAWO+vpI89ffHvCJjXBd/w8z8NS0zNrYE6g4sCOu4oi2rouOtPQ9d9Xl3YwuhNfcDdjFloWJxn5rdVUavlhJPvytZ9PMS1T/J+NmKU1rFuTf3gNx0/qds8zsXXXYTFzAdsawq85Odu7EADciP9g7eVKOiblb/zjf8wPvaJ/xW0rOiz7GhmGubKzvwBeAHJp9f8FhlPf+u3/IxkUKK1Y7FgJlayv7+PBRIfksBlBnQilJbr2QwTTECXwDS9ScoEMGOqFXUS81uyAFgqIJPE4s3TWCD53vtaNFq/a9NjefeXR0D3khQDO0b0Wmu4v7/Hcj5jnmcJR6zEZttW9IP4cdWpYporNK4JACFQ5vC7LAsOs0TPKuo07TmrNk2AORV8z499AqVU/MS/+h14pXcn3Bb0w8AKAUEUG2EenHzFz2ia5sgFph85Ip9r+pQxzclLTbPm0kMycLZFagAgQkZrmO5tEwmf5WUy7YRpFqdp8qTnYQJCzuy0Zj4hxZsdphfVTSm7EmDzFcjjZAdogLkSZpg6du+AR/ZigIB21yzwwvBdBnUPrzKrAfxOOeLh3ZegLoOXka0l/+NCQ3dZya59Fy/eMce5rjgcva4rElqrfy+4H2/TcUmNNOYqM6KwpOWJ0dhBhABzrjnzpl0AOANabjaV0RYCzHFiNgLgXIdUDwxWYpYDGFmydVn/IaAwNtqZbIwA0BUvjir3o3Dx5lRImccrOt+8DDhf3uVr22+Mq18lzbQJM3b3PyReyFeurj6+DixlbjJwxcWgOF6mYVdejEYwgmb+nV+aeuq/JgGR0zdjKmOtDvsFtkcZhQFUAxwFoCIgkLorDhkA9e4jG4BD/Zw0SbceGggDTqMhu/EeaEOAN+/IeJRcjGN+7lrJYC6v0KEVloIEMi+nuzt821/6UXQNNy+gUYWIqv1GOWPiMLHrvYEVyjIBVd9Q3NfXfGKLhK3XTUckQY4E0AXNARNKzfo0gJucpcSivW2tY1lWLMsa+ee0U7Z2ChXM0+zAunPzhPMX47+bCgPzZrkQoMn2L7DdnPDsve/Dt37/f4af+Pe+T85Ojki/BuayRk3qZ7c0sPv2TZFrcaYD0YYM6DJvkeny3g/PBWF0PY1CBlgmFGu9o29NeRrCPE+YZsmtB7LAdBIVvGnOQrg5/Cg4Hd71osF/LO/K8gjoXpIifnIVfZ6wThXL0rAuZ7z55hfwyiuv4OnTpzjOEya6wZtvfQHrcg9CxzxPOBxexbasuL+/xbquIADzVLCtkASWS8WyzJinipubI3pf0dqGz33uc7i5ucHTmyfqo8d4/tZbeMJC6ObDAduyqA1/B03VJVGtS3TNeZ6c0Js2QyLq6WFSCypXrOs6pDMwgivXINIuYtdCzvOMw2HGPJMeWAumadIE41V8AcCY6gSaiwY+WR3QmdRzXVcQEU6nGwAiNcxE3bjsZVnA8+zpD6qmX/BgL5PYnfYm75EErhNQKmgCtiYJ2mspmKYC4oq5TpgPE6Za5ZhnVj8TY37DVMMFpUki6f4GtkiYBy2dA76dBDMDwWB4EgNDUd94Ierz8RkkpOPBdPW9Ls7dgZOdtHbft0FKqRHFsklhfq+/W9ubD0gxuSwjg5cOT0sy73O/K3vfC04gUPJIYTcm2kcb36TVlXdIeHfTMnfLG6fMCGldtcrazgc+mD2liJkzd9VeC3MSTMq6bRFYxYOitDAhYmMs6tBf248WuXWqk3HesS4xriVfPvadMVWk7DrvZw24zrekWm3NcACO/AMOtohxdeoucCANa4+vRJy8gGJXmlgCO127jwUa0+4mEZiMPmuZgROzQl80sDXF2rnBFxXGXEsUysJAZEPjAViaEMxAuAsL1HQcu/UtID5AKKiDWKM4Qpj5Os1ilbFt2KYNbWtYEFEEs7YZLMFdmgm2Ep0gnZNiybBJVpbTRm1QgL9M56K9Nh7RCRq+G2YirUW++FL+2AtF7Ldm2nDqMOsA6ranCzp3bNuCskyaMHzCtG2YtiOmefZrrWsE6Fo10XjFNEue2aDhRRKM145SJtRpw7Zu6B3YWkXZKlpp6LWjbZv44AE4r6tEo64TTjcn3NycUDXv7LIuqiViHFQoPM8zqEpADsnB1lzYaoOaoQb7hBi9HDWLAAOl4LNf8xF86G/8Er7pf/gf8St/9DtNZRtAUH9QYoeSB5kSfziLeC1LWr4rVFAJOKpQOp87z+/vh3QFJhA3q6Ns7WRBUDKQuxYlE4DTTe4S/KQzsK5CX0udcDgc5Oyn6rTctKT+LGvwuBK2OWHhFHkDSyk4zI9s/stSHmf6JSliky0/tRrjCE8rIForhimzTLs2zxPmeVK/ue6BQIywmaZKojNK4tHT6eQawGmSlAalVvS+YV03rB7hr6AVAilxBpBOzdFUYAQh8B/3KwN7RL5sGpFNOkIi2N3h2Q6QMEOROpsyEqhmVlKxrVuE/oYw4JJOoabgMFXNK8kPKQbC9AMWpa8AjVLgiQBibn5nTEsp2NZV5oc0x4wlKNV5JUASrirjl+GOt2WQ5aXhztwrP6yTeej6vkjTM/v7cBkYZ2XA9j4Kg8llBn7OT2cGkmJdJFCXg+/k/lxwclc6k0GY9KoDGR9C1lUtdXwveRX6qRLVjDGC+9fv1FyVY/w4XuLvCibTTCwZZk7cLUBBGlMbR++T1tO6SdO77p8Ai0TjM2BtkaXZcOk1QJx8nxR0dTVzkr1X8KP/4ffj9o0ve2CgrxUboAAv72T9WWFby3Rleh9Ynq7F4rTc3vYxftGXQ8mAMP/94s21r5iGebVnL189XvF9yQgt/JVbw/SSdl9T/OXCkth9FuTBaO6FGRj4gtZXMq1FQCxm8fkCQ1PSSMAfqy7ML6Ga9TRwBlr9qmT0TMfK0F9fYTx+PQ4cTBaQB2kHiNnHhMfHrpZWKz71FR/CBz75d6S/GgBDNHBmnteAZt3SGairg1cXPhUxuSy9o1Q5j4uC6xy9tJYqJ0BVctLF/64wg6vts+Z96wyw+nmv6ypWKHMDLIJuGnNAzqJpmjDP4nPH6gZhn4OpOEufsv+yr6iBJsoT5zfewPMPvB8f+NVfwzxNmnsz1ljv3f0is8DQfKdNyOvrkEMDtz9r3I1hZ8KZv8+AzucfuHr9GqgLgZmcymYSar6orYmQu7WObV3R+gZGT8LqWLDDVnaf5gjkUutoKvpY3r3lEdC9JCUIEQ15zkzy03tzQRkQuWWInjigM6mQpRmQfGuhHQCLLx5zx+3tLc7nMw7HGa88fYJaKhpJQJalAWAJr2zRuIJdliJE6dKvSAia4bkgrnIApUS3CGKaCaowD0HIg1/N/nZw8zOeJcltreIHaO+0sVzXTTUrIb1b19V4Lj/kmzq2AxCzM0201AfGRxpjIZbzvEXYZR0Hm0siN1UNU0mM56HXTkO7rqkhEgutGpHAz0ifX1K5wtlcO0SNobtWbG2OknMMwAqAJlEOMOKaMgd0IyPyjvqTNFryjgIqHN/pJ5J5MKU9JmvOK4Ozmuw4LQG4UQAxNMObs2cQsslPc2YhhB8jO25a2Kxl20e0tPW9Z3hAEkZmDwCYFQSl8QpNtdz36a/6apyfPn0nI75rb+r8fnG/zQQa8xb3PvwA8/6W/b1f6up/mKW/evWFoM7ucXgee9l/GU1+Bz5PwZznRkt3jGAnwZFMT/L7k1DFe0jBzJq5r5vcKRPdTcOW12MhTERoLRItZ7N5C4Zi50NsQ2XkOQKnEJEHLSpGS3bgIPv2RnCU6zOVTqMHAR/vN6l2LIPKYR60htunr+CH/uS/g2/4578zXQ0qSwC4N7HGRNDqtq0+fnbWUSGUOqFwRekVlScBMuJWJwo/KqCqaXOM1iZAJw1QGlmhATrEl7EDWLeGeWtoW5yBLoi0VhfCRDNmPV97kzknO4e9dwVUYt2Y5MlA6jjSRk8L3vzKr8Tv/qVfxjf96F/EL3/P9wwWBCaEKAg+AYBr5TIttnZv2zbEFRgtR3AB6K6Buv1zDwVDyZq/HBilmSAjCz9617QMGnF0XVUgyZ6qyGj+KMDVE5TD8kTaNFpNPJZ3b3kEdC9JmQ8ziBilAMfjAaVIZEtJNn6P2+cFx8MBx8MBp+NR8qq1TdIW1Irj8YDT6Qhw9rMRgt/ahru75yjUMb9yg1oL5qliVhNKQIh9KQWn0wl3W8Ob738dH/j138QnP/x+gCXapTGh0zSpOaKYMkgUzgPWdUXX0L5EBXWq4E0ZAE2umu3YgUvmNxPVdd1UW1mU8BvYE6dksnfpoVJLHepnjnqt7QZyw1wOrimIPHOTJ3yWaIGUwGKYYjbVkhaiyD3GLKZEtWCqVRn/xA4Y4N0zh9fUDXbLwHhpIfLDcQB/+V5n+CTynPQ1XjwyMwoOr7XB6tQT/uo9VgdB2Te5aBrTrK3gzmjckUOcS9AbfTIxpBcl9XMQBuh3ezyJlMfN5tT6lDVY8mNR5BIDUqpGogugBx1HM7/0MWKOyJHGMFPxNSZN1PkvWYVoJpXNGW1jsMy/rZOZWoaJGwD3VSVdD52jvu7mPwFAjSbEeMDNlC/g0ZV5Hss49vk6pf9fVEyI4cD5yv1hmhorVsbGK8k3h8DjWj98LQfYvqzkSyz799s6Zh2DBxxnxzcn078MXDmPoISvN/1L6YiQ6VeEH4ygD1W/zImQ/e1K5wCIX5B9Q7FPShENN0/CjNZpEiEdoKZzNn8xKAyE+TEDWTtjUihyOoYw4YXW5WAua9byS3Sm6foqy6ANgKZmGIN1IK+5K0vAtNnkmsgeN3KDGQNw033pQsmO2iVNAJWC6tYpoqGrGjqaiABNaQIkBn+S8ZtWTQ6u/xko6b2Aip7xLMDivCygQjhq1Mt5muAgGyrU1ZyBMs8CxJYVaBo6P/YKiQY/DTOMtnPWvnXvw/P3vQfPP/B+PP3NTyUBbKQ+qqiopH7/atptPunZFDEmRgLAWBRRGy8LIGMm6jlHnZ3vOQeeWOlcavOy9nDsO/x6byJksaBr3BnrNEluwUT7LSdoToi+bRumKu4kYvLecSwFVfMSttaw7s6Vx/LuLo+A7iUp2RftcJg9KuObX/gC1mXBHURjdjoccXM6KphbsS4rpjrhMB/8+v39vYTX7eKfJsBrxVQJr71y8siY8zz5KVxI8r+cTifc3d7iZ7/9H8E/+d//FOpXfxBcCsAbJMiIEc2OdVV7/vmAw6zgkyVAyTwLCGtbEwalGDgKon0p7TOiKvdu2wqiOZmPspthTFPFBsa6rGAw5vngUuMcPXNKKRjMvIGN80gMCygCnoAZKFBgKb5LpUl+vlII2yZRr1rZBLSVgtY2Z7RID8pqTHLqp2nryP5Tgm53CEag4bngX3bjtNPs+G3pfgdphujAAeqc+YTfd8nEZ2b4ysuGeYz5y9JcA9z6dhljY95KJJb1Axfj4ZqZ/OIM6BXt7r55WXoLeMAbAJ5QOzN3Vp9piHtnTDNhomrD6YNAFH0NpgmeoJldG8FJswHd4wT0AJ++Zvue2RbzXRA5ODfzabklIqhZ0ABShj3nqouJC67b2k/AYBFwZdaHaw+xHpT+Ix6C8D+4bkYNpjLPiaEUOmD3wsd9qIzsr/EFo07FdmbSQlwIUPZ/X+sxXR+YfUn7SqUaqYrLClzAZPt9jzWtTk77noBexEfN9lue4mhnWCs0FwaY9qA4IBTEQJjmOSbN9qWarXMVD0xm1RyZ1pglaIoLLnYA2gRm0n0CUjh4gUixR43ixdpJc+4Ad4/IEkjMl3erlbU9F9fs0ZAA+HfSP410SQagFdjpHia9pxcbg+4ghNXvSrSZDVwqwBPaNLswEKU6enWBj5phzvNsLZGmFQK4KqArLrTZWkNZFxWSCR9xPB59/JtZBjCj1CI+fGqx0HvHmVMuNEorP9ML3X9BJ9UXjEintKCpxm30rzTAVFGLBFKbZwE1W29oTcAPswSA+dTXfx3MbFF85dUiSc/MWipKYRxubpwfyBo26P0RdI08IMtecDwK9kZrB2bzYSax4NF767aiAiglAKW1IwdBE2F3Qa2yJrrS6WmStqzrCm4iKH8sL0d5BHQvSeltw9OnT7CcF9ze3Ykj77ri1ddeBZTJvL19jvP9Hb78yz/o0qd1PWPbznjl6Su4ublRAq3BPCAH77YuuLu9wy067p+K4zRUqrSuK45HkegVEkC3nO+xtAVm+lBLRZ1KCmpCej95DhXzz5jnWVMtiFzVcuGs2zpIxCzypBHedV2TFC3ybZGaU0phN3MoNLtmwQAaFQJ1GgCdtRmo/s5aBdx0A3mlYNvk4JD3Ngn7TBZERRnkEppAIhJ1SBGQMdXJwxWDWbUH16RvHIyvfGQB6IvLAxoTlkH1A3jk5+IAM6bwSy1++O2uDaazyBJPdr8vF36ntovkl0bAVcaD1JgAVok863rqpNpUA07WV2OgDVDa4Z2uL8sZlhje6g0myp4pSQhg7eZw2PeRNU1e+MV5ig/z/zTGJ4HPCCARDKeByN66j3EGoj7mSWRgkm+TlLt2r0dgFA+GwtkUTvucdB8xVql7GcvkBy/WBsA8Xh8Y6QuZDQ9fjbCdfLzE/DBuGL1L5YsMFilfg++utD6gW+/hXXZptncF9MEqS89dq2wAdVfetatRgJC1g67fZP51NneZiaVYR5wTH5uJGamgcJ7TugOanRXrpsz+FObsymjOhyO4d9Ta0XpD1f2x1Q3btnjAKxFohC9ynnKVPwj46d1zeRk+bT0EXfJJqIUicIqtx7R3AshfJ2pXltzuWxpMOn1uhuVLIEheP8PcpJpSZhLtJHUQF9fOt62h1BW1zqirjGepCqBqRZ0kGApvB/C8oc8N03QQixbbk4VQUXE8HTVC84ZNLWLatkpwrVLQaxUTwLaBibA1xro1lLKins8OLoQOiICSSQPTlIr5cASVkgJ7rEpnxeomwvU7pNQz2UwFA7AzMzoRjl/4Arg1tUYJ00cgn8dwQMdm+VMn9N7xq9/6hwCKgDrQ9WD7XfyJV7R2uLD2sdgCdj5ZsDTzyz+dTpimaTAFzfcG75AFwEBhTQTh69K0tt02koDPvoHAmGvFeV0lBkGJ8efWgQmgUjCViq01PH/+/Or6fSzvvvII6F6SsixCfGstevkrJtoAACAASURBVIiJ1O/mdEJrG5ZFDopVAZSZTd6fF7RtQ795gmkS08t5mrFNK9omztcNQgQlL92Cw2EWgsUMbg1t3fBrf/hbsLUNh2mWiJeth3SVxAl+2zZlVIryOjRKwiA28bysfugWEl8BZ7B4NJEw0JQjYDLHQWGgMqJoBoCASUwtxx0VdDKTGDl+WgszF6lHHNQlaXh3ZgdQZ3OVthERSh3bzF1MPcgc5BPjUksRnwrWfHYPhdm/KNeZPmNE3xH+svHYAavMjO5Z7i+l+KGqB9pDbZA5g4+LvEkYlGumdJfvyGhirNPq2j0UGCQzz/64tQEuwDBAZ1x+2Ulss8DCn8WuYlhS2KZ+FgaiejAraS7Gn8take7LKCebIyKNad4bw0+/vGYS9mu9yMDXxvHtVu0eY8Cl9vH9Q+uWh6eiHlsdrjXLe9zGIH1nL7BLjs0pvytAngzfZcCh6z27bPVD3129OgBhpATZ74AeXLuNx99zfRK+vquyK4eTF2a9Vomo6GbDANZtTa8iFwC4X13ryjCHJYWli1FSDrCaX1YG8+Qahtaaa2etwbxrPwARytic2RyqzxaxATpD6sUDgWUz+fgcUP8LB/fKrhuASv64XkOaXgWm7mxGDFAHo4X/rq7dpsJM5griCvCMNq8OtkAFhSYxw3YhVJgQurClyHt6b342h8AoaIhYsuj8aXTNYtqobUP3fITSxlonHOajjIUJ4qzI4a/jx0nGQb7ffC8z47O/56vxkZ/+Wbz3138Dn/voRwQA1XDtsPtat3NSNnLRfG5OA1m/U3DrAjJ9hnGZh860jcErxLoUDSALSO2jpZCVfX3efz+HRKstqZxEGGARNNdtw6oWU5LWaGdFonQ/Ar0ApRKoA9v6mFj8ZSmPgO4lKcv5DAInqaRs+uPxgHUV4LStK1YNRVwLYZoq+I49aEopAsYOhwnbOgHc9HwQorlqsnJJXSAElbuYTX7y675KCN62ivmkM4fdmdwsuQLk0005Ukhg+TpMwSpZ/hlLqKymCx6FM4fyJTBHHjkjfpL7q8MiDIZ5Q3H/oni/mEkQRQhizydXROPnBN0OVUAlzKw294SquXsAY5YhkkM74IxhBjDVit42XMZqNA8QLTvM8qISEuZ0yFwBVPmQswPSTf7SM3zxfyrvFH++oK0OWBKIyH2ngWkyxiUk8rmy4UxHsGMSKCFAWFQ3yuuHsdDfTZNmzwqjOGrnLsxO2TS52goGWNMDxNqKNemMB8V+cRBpY5/GZtRkWGdtnFQPMTAyMbZ74BYALt33AICEjRnZ+F+/5aGSNWBW1Z4XkvusGeOXGbtYE5kMyKk0m9KYZDCX6zG+HyPAiwWYQF1q01jP+P3bl/2efudgcH/nhbDDQdu1BtncyzNCvxm98FCL+UM7oKsihNpU+BZzVpzG2uuuaSnkXkJBAReAWaM2li4h+A340YZOPLQzz/w4NQmOsUYG1p4NfSfN7BZWmvJcjsTzQD5D3o8/XxlSJ0lXFhds+ZG/RrNReNujRhUkSpQUdFiib3F58LO0Sw65puZ4luuvlA2lNgGIRajiYA2ihFLOyE3N1tPmtfMVeoZpRNwqpiYeeKMxo20awAsWtKtiPhz0uQ54Ymylubb3klDJrQfSuU4A2vGI5ckTVLPcSdoyGykRHEROWD+D9fOVT30aAHD7u7485jYJyjI4ijM/BDfXgNq6rsP31wDdtTx1pOPp9yqApt7RIdY8AupWiRC+reiNASRQ6SSMnK8BLEgRPQK6l6g8ArqXpNzf32FZFickHl5ftXbzXNG2irYVnFWblyNiZntxM5VoLcwcaxU/r/v7e9zeSk4Xe1drDefzGXWq4kd3PDqP0nuTXGsUPg6haYAekuyEWSwvhb3orXsgilILChN6p9SvemHuABh4hDpEpwNED4/QsiRzI3OaLqZFM9O2TW3cuzPs8r1GCcUIJsx8rfSCA8LU0PpNgPsrdW7ORNepglZShkQBb/p9KF8q9/xQucZBa/20u+9C8viiOof2pWe1Kxfmli7BtNcrUMjx6ElZLhuOPajzA1kv6zkYfHxUZPdnn7gB0AIpDUV8t19LOWeRrY3ok/Zd35mZXANx4cvG3h6ThNvBnzVzLtGmHeaA+sqVMuAXa4uZl7qZ6TCf41pK/E6w0mmvZu6akOYEwMd/8q/iix/4AH7xn/ln8cJiHPdeC5157PSqsYH5fr68Zn0gG7OHwZYJe0zQQroGM1DM6+h3qrwzMPf3s9gGUka5dx1L0XJUaaQLRHpnMMR6wAbMBWUkGpAikotL7YVvO/J+i2BN1ntVxzpmDQihtF3Gnj0n97UegC1tBfmmiH2qKRTIgpHIhwG/YYHZXvWpyCAuw64RggFw81bOa5riPttLWQgQ0C/Wm601Dfspd5BoOnvbfMxLZTQQ2ra6f6wAlgoqs9AQVjPZYtEmI51R72KyCZJzyASqbStBR6AWOdsGkJxCtSrQVzqXfX1rlSApNufbtmJbN9Wi0Sh4yudIImSZjsDnMGitvdO+y4KCYV0w4xt/5C8CAH7qT/4bKFQvz2j97Nvm5u0ewXUX4CS/3+rfr/HMg3jeWRPc7oWHRLJPIPxFb5sIcrcIEiesiNbNwWNQIbfq4M6jy8hjeSnKI6B7ScqyLFjXBVUTW0tQlBZ+OepI3PuM5XzGPM+oJXKrWdTFWisO8wTuB9zfV/dxk4hQDWeNmHmYRZtnz77vV/5PHA4HfPYbP4rjKQUYaSJ5Kwl8eZQ9lRqClUizyP2KMqadQ3NWSwGXOhDUXMZrmbEOzZ0QWgxSZQMKnRmVxFxVDj6Hn858mx9UrcUlgv424wy1z72kg4H9K7+WJXemifR8c3sJvpdgBaz8jrGDRB7F7TLgAxKn/+JycWgjhcbX5r/tAeTSW6vBf4mDf7jBL8hBaAEIIJqaizHKB662dwRu49z49wa8EgMga8HAnKyZ1nYaN4r1OYbijoTQYhakkVEVfAmoC2AlWuNYc5FY2hiPiHZnzKIFV7DcdaHt81rS+GSAZD3ez9V1IAgA3/pf/yA++bGveTGgo/H3F+WeG7D7lfsy+LKmSXYF9uVqgFqY+MhBBw3xf/FOeqCH73wYLu976J6/582bpB3vuEFWWEGbru8u65SGPSHmc2SurISR6S3KrPvY6DqDgWDbE1lrbfuliDm9mheaqZulfPEe7WlFkJGYElZTNiO0+ph7lLKaaLo5pzzN+/XPF78M035Btmz8QEmRK4vwyfNn+O4/8x+H4EofsPsu3uBYUEfPAqn0Jm4NnFL2MNDW1cEXGECpKNOmvlryjsIAQSIlE4pEGq3VQUwvHdQlMAqlpkhfGVtrQlOUhhVKgUESHekqkAQdhDbqJlqWs64pEpoM1v4lkQml3xHAJwv6jK5ZDjckgSDlc8Dnn1MdHTC6md7FAPrWXCgcgrnRkujad3v/OXtXBnSesBxhli+DEa4WvQuvIKC6DWdEoRgPgu61UtRXWjSgVC169+8YF/BY/j9eHgHdS1JKIdzf3+F4PGKeZxDN6L3h73720zgejzidTrg53eDVp6/gC1/4PI7HIw6HA47HAw6HGee7W9zdbpjnGTc3N5imCc+fP8fd3S2IgFdeeYLzfcEXP/853D17htdffx1vvPEGjscjbu+e42P/yy9jmib85sc/jKdPnuBwPIKIVOJUcCAx8WwtJfwEcJhmkZr2hqYS4GmasK7ixG0EdT4cxPxnKzifz4OZJlGkDGj6jGk+zP691skl9q2JmagRSgBiEknsjLoxw6WIieq29RTueMY0SRAKI9C1FPGF4jAHkahUEtGzcyLWyceqq0P6YZocYKOrdu4qR7kDS4Zp9ozjC0BTQNUk/QP8wMvgJqoLsBMVvf1Bwho62pm7ncQygzvXlng7d+aLdr0EgPP2Iml9nfunjPUuQUFiDsaf3AZ4cApJVp9MLF0zh/Rsd/+TDOhkbY7mlbbWSom6LJiPATooI5LHwbGxaQd2LG42S5Z36rvV1NPMKTMrZa/LQpDsU+f3+czkcUygM4+b/fKC8v+y934x223bXdBvzLnW87zf3mef09rTHrBtaLE9lFIJF2JCIFgkGm9MDJEqUaPhAm/AKF6oN3qhMVb+VCRcGWO8wNgYiTcYKQmFi0YihEAjJ4AGsJVSUvGc07P3977PWmvO4cX4O9daz/t9+xy4cL/v3Pv53udZf+b/Oeb4jTHmGONsln88xlh+isaHz2a3z1vmIXxhngIdOt9ZfpF5QXwOeKWMDo+mH3dfH5An7RbrpwViz1TOv43rI+pAw9MEFTSwATANe83igbFvm56fkzAD0yRgwARtSO7YPa5cEQEf+LjGTUtDSuNLkfh05rJ9nmdQkT1jM2FkHnM6zDyfNE4dE/PMCtoUFgjIs+6/k463gh4c7ukFiX2nFQQAYpTW8MWf/znze+XBCmyukQKumA62shTMdYYB5I0ZIDuHqJ4gmbGtC0qdUacZ89bAKKjTLI67uIoAFOaNFB7Cp9SCdV3FUuek3dbHZkJJus9VmAXLBFDXs4/RP7VWTPqp0+SmohYqBcxuhRD0jIMmQQBtLwW/9qf+NP7sD/0g1C+q1McEtmpNwyW0vmgarF3LlMc2EFUwiUAZ2v8Wq29dFp+PIvCeD9q33rs7QsnX9gLloyWQXJuohgAYImTYmlloyN6fnVnBgKE6YalVzjDWaUKpFYsemyECrg/Cp10frvuZ+Zo+o+kV0L2QdNHYMVmyRER4fHwUwjJNmB8md2hi3pyuDxfM04Snt3INAK7XazInE29cU63oKtlb19UDlrv3PmUE121FZxb31YCCKzuDFmEBjLu2M3Nu04/wbAnYdXEaIsV01wpaniYBtryLmniaFy0BUdYvckbOiHKl6hJIAy3V3zNT0yDirW3SN0XOlphJm5i6ZDt/0YhQEQcoxOQMs0aCVem2HkCvKvVG4gtgbNmOlcjM2UFN8UyiAzsU1/K9rKmzSzhixPfhgSW7EzaJwztYqswI6qwDnmHAcn5DVrJTnz0IQK2ausUbZB97qATZgC6SWeZwRo4yw5oB3Sg5ZrB6jByvh5ZP81NQlE0iR/Z73wTTQgWIM61fPnOXz4D2HH/u2DEnwLZ72+QJ2tVmzOXvff+vxt//7u+JC4ThjXsM8SEpk2tDaJo091yJUSix7yXvn3TfYpT5AxTPRYH79iE0vaZd0Qfee+7bK3sM963it2cysmZR6hDHDBTPsIO5ELTYAjSLCSKhh5fLxWmkack7hyBN1oSAhYNJtQkyel4fRovDksH2ks6MojHZ7rUyRBhq7WDrS/8lBX/uEAOkNC3WzB5S3+vh909Sq/0750N/Rpv0n2Fym+BSBI5Gk+W8te4pAGhd0LZV6LgPJ4M6iSUty9k6IqBSRdPYbl2FjdA6mYZNhlPP4yXQbHuauf43sGZxWkEA6bnIeb6gqXdNSz7u6guGdWMJr8TAL/zaL+MHf+bPY/rGN9A+//mD1s75GxtTIgdY+70mm7nbPm9moPt8Le/sFMX4oOfKsHaVYa8wUNx175cF2SF8VmsNmwrvWtuE7ptZvO5lswFB3QvsbKsJ/abWMJWi8QJf00tIryP9QtI0SUy4wbsYhRdJk5aFrXjDujIu19kJhbiP3nSDFjAjroDjtwXf3rYNy7KI1gIBiNZFXBd73JZC7gLdJIRUCNxk1xLiqUE8ldjnWCxGjKdpQiWAuXrwz8w8GzF10x0iBWPhHCXCGhSVgjVlQKAata7nD9SlNKnXTQ6GedsaLpcZpUqcuE3NH0qpvrkYs9h7VyBqLpPFhKki7PqlfQ29qS287p+0Mwdz1mYAKnvu3Dno8fKQx/H7KdB7RxryvvMyGzii803wbn4IKbFs2pw4Y72m9Q6TSGMgo0Jn1XLQxoyWAd+ufgeTWsDPRLh0mY5gzoCUVs9NLONa8eErO02jMd7jeBDGahq4sj6Rzb83iW3Yd/XwmFautYMzjEcgmrRxzHF/6D2KOUrjZPvJ/+Q/x9OHH6aaA3lOnptXHtl1GXNj+Ni1GgwKbcg+i5SXgQ4GRzhnHp1iGEwzAJPP8HDcjZh4fi6KTrTh+fcZ9EACVN8amkvL4CRResJMSp9Zdxx1yeNpei2byU4HER4MzSjSLA+oFBSoRUJJmm41KzYzMzOLDKGjmF52tX5gALU39CImlHTvEB3GbjcByHDslmJ9WdePc9mxyreUzkDa08Mb/PTv/F34sf/iD8jcHWjJrk4E9dapORkYV/BJan4JbU4nMRccDPSLCFmZwiqhqnlrAYMLQPab4vyvmzAix/EcwU7rHaDm62VKlglEXUzM/eyZ7b0iBFhheyfgenOK+WP9kIVTtw8+RJ8qpq3JG4kmDf3u9I99/8/PZFpmniPJ3KFi5BkseHiON2cALgcVt3BPZ2f4zDTTyiQi9fYNF9p1ZjljqBYb69awaczf7MgNIA8eb2uHtC5mdSTHQCYJNP6aXkR6HekXkmrSfnGPEAAShNK8NTYHR8u6YFsXXLcL5knMArZNiJt4wpww1YrLZca2ynWCxIkzhyu3203N0PT8DkNMOZ5uAapKFc9YrWldZANnYmfWWtPYcKoRzGeUWCW7VoaZRgBQc07zjlmTlgLq8KVg70FQ8m3YtiamJBNcKrm1Di4BQgCoqSajd+nfbVtVgynA0uowTbOYyWk/iY1818C98M2ZezA0pRB6Y43VUz1uE5mE2SSlvvnJXxfkfrOMiKnBPgWQewdreEhnG+s+k3wGwe8j6uQSX1ZQl55zUOd5DaUDJy1jBICxl4IPz+VaIbs8nAkNhgzJuI85PrmNtkEfANxQ99AQHk1gA8BnJsaL6ezxwGzzz/Ntb05q55721zOos3K0JwJIKMPnYPfZSUjelxmI5PpZu46gzgt0ptMAiOXhDK3HV5P+k3N0qbQYbs/TwTNUU+wZRHtNy2FM9qcKITCks3feI5/3WJ/s+eyEE5RGzRhbpyVAam5oTRIT3zuLoxPtJxc2DeMtZnSdO2oCHGT9lVaoMLSG7OHz0EyXC9u+0D32HdvYZFqSxn3oB6dnUQbSOjXhgDfenvH+2QlOouZ+5ZQGUtzNtdouF3zlN/1m4Cf+wC6vowbPcRzr3UFYQKlQhdgqJCqto5MEbhcviYvPaduziAqYJqCbkFSeqLXier2qaaSEHtrPR4shR61jayKcNPO/6K8CInHy4etSx3SeZ5iwTUwL4WfvuvVEEsjxblhKkTlRkLyynvV92t/3ycEciZWMyFdDWAuMse0yeLtH27I2Lmuc8zUrt/VNHZgIzWwaB1fiAoaXS49FqgAw4uzq+f0+ef38/W3DVCe3XnpNn/30CuheUAqzwCbaNCXa5ibf7k3zhGW9YdtWNJf0CJgSzZ2cGyuVcJkv4N5xWzTg5TypwxUBdPM84+Hh6t75tnXD7XZzb1jVnbOIZKtooEzqcf7LNXRQYAjZEGqt2FgIojG4BiYFeK7edjmPIXHjpknk8kQhgQtXv6r56x2dZAMy98/Mm3vS0pq5Z7BSevIEqoAxmQgNmwDFeMRGpBtXZh40fp1pCzkF0h721lNOYscQflpmk44mlcP3BBhCqnyiHXlnijplkCBVSMxaYl4PrXgHmnyuTlnr4JXgYIM5PeN12oO5OxJiA6B7M0Uz/0ICVJlRsLQ/g2KAsZSS0Qc6krZsAF9WvXRQP3HqrhMxkJmY7GOfnfWiasTY+iqBXjw/00LjZaD8+XHKoy5jYFUKbdsALM++p0HNs5cDC2pRmWmmcU3mmhiIS38Vq8Q15Jfu9Ii+cKrdyw9lwHkKW6J2Q3v9enqKj2CIrO0+NgihyThcMAW1Cxesfqm58VceNvNGhpA2cTBZ1O8Jg4vG4FJzdFA4vAJXbNpu0yBZTM6xHUcqxxjnwqFHfD7Q7gFjxrV+TOdjQ/7PCSx/P8J0qF+6kNesXMoCEAaGtW4azybB1dWZTd+Ku68nDf1Qucp5uwKULuaJbONDNJwJ5p6hq/zT7SwwxM0+ADHD5BFYh9AxtYAIVc+d2drdmLE1DWpOpBrzEFDG6zKfPveNj/H17/gOH3/T8LlZ5Lv6H0EnM+ATZzwC6FqPc4q9d3f0ZvOeeez/XL7l6xZRO8cpw55AQtPtXGKzM/+mmdP/AAb0rGSpVSymND6t7CMGQsUPQJua+wF4TZ/99AroXlAiMNq24ql3XC4XPDxc8R3f9u1Y1huW5YZtXXAjwpuHGdutYOuM5fEtqDd8/gufB1HH7faE5ekRGxV87qPPgR6u6H3D49tPQAW4XmZ88OEDbk8LPv74G2BueHj4ohLHhtYWfOPjFR0i9ZrnyYNti5MQwqTx2da1Y9PrpBLZ1sQEoejh694bti6ETw7SxzHuZTnarEvMmE03LNFOblsHsLoHUCI9O7Cpc5RJQx1AtGVb2wKQ+mFqwrIs7tyiUNFDyxOKxmYy5oMgDlG21lCbBGc3TUNrHeu6SbxAu06Ep9sNpjEqGkswuGZ2hsuYK9faZSZW/xLwTFzyxApn7sJ5iqzBsmcoeKE9Y+7ALz2Ti8narIGrRmhedO6GiRg54zyWIW/3gcFJ9U1tpHTfQBNzhAKQZpVoX6ojIx3Az+CgjQHtzSyTNbByFqjs22dMjmz4uZ95uOdnMa3NzGAzV2KohDs5N9Fu5d7B6go7a1WsDHIgMnqI22vpDMQZpmSQzz17xztGx801LQkYmGbOTZABF1ikUfaxGfLWyrIGkDZAmAGZgyqrh9Y1xtEHT0N7WUgUDGuJwMlVu7YlppFqh725UQm7l+q9w0qpmyg32Oues4vvzwO5kftN6DJ6M97o8d3hCMX7MW7FO4YAPSNV1Kxc+o3NeyVlwaEwmeK2flIBF4niDgyqDPSI9yljLetjZVatkXi6ZCLQWkDdTM2k3q00IM3tGIY01oCbu7tTFB8zeaLrUiS9ZjSSwB4eJUNFm7/HMRgTDffOQB9HXomO+VzYkWKdiTI2rGfEzKOKeWvsHdygru8bqFeJ/QagzTP6OqPN4iwF3DG1C3hu6lhj0jBCal5oM37S/Y/Z52YFQsOvM6tDrAGYWPta5k2pxeePpVIrZgV2a11Q1knmTBeHYi3vaaR6OJb++qVf82X81j/6x/A//5E/FH0tdqNBRzHGeDPQ9pd+7F9UIKY0HwG4ZDz0TH8tAHf0bQOD0InQ5gnEE6hWp+l21pogllBmESRlWkgjiwuXYtQCoCrnEM3RGljMK1sPRyjyLlAni+cHJ1KsgeDlKEzFw+UqR0l6x9Y2LOuyE0K/ps9yegV0LyRd5hmXy6wmj09g7pjnistcsW1A21ZMpQA8oxLhcpnRtwu2tuJ2e8Tl8h1C3NqGW39C4wZwl3MRZCadDR0dl2nCghvatmK5PaFtazB0BVjXBW1rEOIpxH6aJ9VuVTnvB2BrG9ZlQa0VD/MFqwXXXBdcLhc35xQgtGGeJ9fEmYTRApcb+LLzfXb2TRykbG7aYE5UwHAtH8M8GGr8nXXBNM0aIH1T8wdyJmZd5YxgLQVzdjJjDCxI+lKdYZAyNFwkkHp7esI8i4MaKtI3b7/xpF4uS4CNlIIJTZtmAl7sTh1GTnHPmDCMSSZl6O1qPBGF5mvBCROM2Q/GGpBzHq6JAoEde48sfKrYqAhD9BV0wx7OjHmldgDUwVHWsijjk8x5mFVjBpWCelax+Qvoi3Ktn+RMhQEh00aIwxsGO6iz81vGeHg/MZtzNmQQg/SsSX798L0xBgZA7XEGsnlxaBqkQd2AqzINwqQTioK55ibMBHADu+MFA3l6rrWnOYaon5+vUi+EpObHef7btPO+c/CKVFfJnvbzbD8HGT5Xha8lDXGSOPw9kILNUWXUTYpuyBZybsjY+KEQHXc7kGUgwIQye1OskFPwACxP8UBeAiffhjXHQ495v2Rdtl0ZVaBH87VDZXxJm7VAdKBpTqBzqJNYD9hUszM8W7NQA0pTla4KMEgeXbuaBjrYUu2NCfrMeqNWVGLQBphW2xxUtETb8vlWW9NpuNKEstE3Ounwb8DBIjggDHNtB6zl1m5u+mjcZ6ijW7UuClg4SQI8V+8e6ctwyMNeL1sE4nQrxgkMcFvQ0cVbdBfgVEs17zXgzpgmoF5E0CmWL6THCghba0BvTgflXDhH2BNWj7m9ydypQeuhYClhaMhJTAFhdZpBVOT82LJi66sIp8CYagUR+3xBB375S1/Cl77y19DRXYhbMn1JYyT8QfM+f/td3+Vegk0wNsxRBdebgiGCVL8Usdxpm4Au2zck5EPMt2HMjCaxxRUdwxpky4zODDT4noRCKKgogPBIeu5waw3N4pQCKJN46mzcQQWYLjNQZD/a+oath9OZ1/TZTq+A7oUkOzMGSDBvFteMKPMsBKd3l/QQPTh4WDfGtjWwuvGvyQ17VzPIQhZyQEDDNE3uUtfO3P2p3/3PYF0XlHXRg7uL758ZaAnIs/qawxEMjEyWcFlA1GwLb20V08+9p8TEmHs+Qn4jDyhgiDOHsmFmc4kw7xBgCC+TexfzIQBEYhohKBNqp0/KFJvXzXTuSoFk7cH8G7EPzUxJ/YHcObGpH9IRIB2Ts7cIjdj+/vlb9q4BmHeXkn8n7jJhw1zv4VuaC3FWLEHOxDXk7/ayg2rEpgt1m+3gDeasZFfTQQ2QKxRzCID6Ie/OvGeTsEHTlHojaxNHU7jo02yqE8/ZIkmAEgHgjJEOftkAzz6F5s6QlJ1Rhc4HA5yH1huwBadmyRf3ikeJZTKNT2Jax7lj8wkBzMj1zod6W7tMu5pw3GG+DThP482xkK4BfO3Y+5NMzdwz8h2B5Yi/9lmcLhPegY5c+XeuXXno0F5fVLhDG/RNOiliRNRa78QMd/E22ZW57CBYrDn3hKzCLQl8DBWaWPbsTHOeF9lkjiEWGnaWjktB8TNfWbOt9XJNkE34JLQhg14JRp0saRs/8O47pXdSfzmpmZ6ZBgAAIABJREFU5GM+R6Kb6N0wWiMlzU+74G03oVjHI0Cg3jOPtVYUE7hvMka+DhltWobaEhFKlzPoEkc+NE7F9j5Yv+gadjCjNbMYebkDAXAaD1/PBQAXyNE1sc7praPYMQyOHgph3rGfvVcOfWH7XhK2kIC/rnakDAzzyLqXubujIhdsmGffPV+hnRqXuu/l7p2SRvrtFhpGC60NKcac40trin43r8Qg4Z9kDGQtFTLLITHVNO/kr+mzn14B3YtJQt3FhKT7pqyO+RSgpfhrgBBeyKa93G7OKNZS3JGJna2b5wqijo3lsPPlMuNyuYC5Y1kWPN0ekU0UW/sErnFRSStgTC382dDAaWw6KgNBNKZhjDsnoNLM2/ZxYfZ27Jkh6L2plgFO3J2poMSMK9Nv13JdLG5SI42tY5uFbshhXmHSugQybD9h1d4BCWAmBt5Rz2gCNoy3MnB5owpG9vSleJvHZ4zxvb+TQjebEYhEEWmzzLmccVKJg828kG5zulknU8B0N5sZ5raUEpo0MyNjZpTe5eQFBXPEMIY1mIGo+wjIjGEb5obWhnswM/EKRceymRLbz7TRAz438xwN4M+HT06lFAFt/gFKT3HWdI7DGbT0rF0jOTNr4QwG8KNcnbff3YzHmjCmOjfZhzl58zRmxZlW5eJCs5r7kBP3fEwOqPTLvWNPZ4lZWKCSmf3MpGW+28CcMY6JLx/AxPHF4ZuBg8Mrh6dThf4BpLF2mT4FLfJ2Gwef6VMCDb0BbdsE2EFmRaGCOk/qyKr6vLUwMz4wlBhjE0QIkQRIz1ExwKV7vaS+6hCDxBTO/stzJtakgUO4kMyZZuY8dN7epJDT52LaPe+IlJCgy3v0/XN5xUM+X3zC2ESP6wI2TVjTAy+CADbTwAZuJEabJONGRGga67JsBX1qqoUlBXWyvksXT6NoDV3cbvr6LwSlDRZewMaBx4YAvg/GlBJQyCTawDpt6N3iswo9cjBncbJZBNK0beB5PtA/obNFu2m894M//efADPwfv+2fEgCEkb5mIZPvOqwhIRwoh6MkZvGQybpm8v7iPIjuTHv6rZX1a3nILIVliDiX6dycLhPJ+rI83Mum0ndmHnwJvKbPdnp1f/NC0ghoAIlf09I1Icbbtg4H0gGxQ396enJvTwa0tk1DHagpwDTNqqUSMPfmzQNqrbjdnvD27Vs3aZzUc5YxkW6qRYYzhdJP6l0TgJ7HgDpm6QOAM/fK4ZSE1IPn5K6Cj2ZQGSSqFqyLV6nebbMiZ8zzc9A6sj2XmEgz5WxqmjG8Z32dTYX0zJ1pFkg3agPYWSNkwNLGazegA2gw00vfnEwKmBi2zGzf4xOPxdDuWY6a5Q3JXzKG8SRDa9qw79OuHK2r1ZuCWWC2MxLdAbB94vfOJT8w9o0xJYD3u+K5QRMcdRPmg068nQ2/MzhKTKMwJpZPGVxhD72aQJ39zQyCfbJgIjMJWVDi89/HOgDXHszl7znMwTho0ufWoc5ma752JiqXTSD8q//Rf4B//o/+REyDAdGN82Q/k3LvjOzZUSIwAO48vifJ6M3pBzq/Uv9nkQXvQSfHhL6vpY7JbnN//6SNyd0mvjPxuKSQmFMaLvi8yNfGrNLaHkB/zEcLdCwOJKLvAn55Vnf7eUgUa8kCXe+9Cw73KcVrNPTjhGUofKAd+65l/09/GSBhA7Dw+o5ipPjitDR/Uvfaz9Iavuvnfy7GYRyo0+Q9xVHX/P3eGHlYEtV69bahNQkftK0LttX+LnJNnaGJhqyD0FG1r6vRFNfcybVJ91s/w+5jbXPC+keAVo7ZKZckr3meMc8zpnmWM32mqdXO83Nolws++c4v4rf9p38Q++WXwbuXiZhTv+KvfgW/8itfCb7jHi3P47bbtwB4uCXzINyT8Dj2nNjLjWYP+8oO4MX1VAd93/meJkc7LFZgjleaeRpbM68aupeTXjV0LyQ9PT3BtEjmDGRdF7R2AZGEG2jbimVZ8fbxE7+2LELwv/a1r+ELX/gCrtcrrtcrWEFe0XNil/kDdbO/YZpMazfjl3/5l/H1r38Vv/1P/ywu1wv+t9/xm8UOfNvQe2j5hKk1kLOh1kkdtzxgWRYsy+pEys6pMbMQ/2nCsix+zfKzEArbtrmUygieEdeaNiI7+wGYVFLCIjR0dV5SAHS0Hoz1NM1oSvqFsFbcbot6B+1qDiFnqZra3dei/b91tLX5uNAU2j4DvNNU/CwCDETCmOYdOEEwbnuAIG26NzueFxEHsJLEbNfY+CRwKpOA8PDngC5AxcBr8SjuDjC3Z+7hPzJTZsGt81MDL5x+FDnjjl6AguKAKwJrj9y1awTI6q+to2AeglEcywzBRGpdZhxyGTQGpd0zInbd5twe7OU0AHiYoIZdeCNjIWe5CIgzg4m5JkICw2lcHOTEGZCRsTZAF8IZARECgn/l//W30Od5YGJFoxOavuhL6UO/PqQjNz4CPmmjQdbQWuxySf1s/U5EPndJtRNMajbqPcjoHP1YdE4TkbrydwijAoMzRHZyjTFohog5mQ9+2jSuK+znylnxDOTg7P5YZ5hGPCRARQOLi1t6lCLmjKXAYnkZUx3nlcwEzUCGlDEC/6AthQhsdIOBaRLrkZbY9qmqi/wWd8QjMFQdbW3T8e8xPLmHht6i1D1G2w69JaM0COoO3/jknvz64JOP8S/9xH+GAfLuCtGZG9lQEiCwzkQ73wf4dyLpDy6sY9RBLGd/qTQZs1ZApXrcs7rOmOZVwF3rmOYL5ssVPHXUacI0X1AJupcxmtanUAnvpWzmjtLxciZYxsm0tA7kQAn0qGVNAa4PV0xTxWW+YFluWNcF6+0WAMecloHw//7Ar8Z3feWvw0UHHuQcvpaBAHJ72jhNk5r7HoFf/uujdkKP95ZBRFXPCxo5S0IP7oOQzcAqMHogDzCnjl06Y1kl7ISNj3kRx0Wcw5VSQVVCFkzT5MCbAWzbq4bupaRXQPdC0rIsDhyqBhk3UAMocesNfVtxu91wuVwS0AoPjgD8usVYA8QDk5lfmhbO8m2949u++gnmyzIwpEDEeNm79K2VXWIn5a4DsAhAFVM4m1haW62+RjCzZswIcX7fPlVBlNmq994x1ck3X6tn1giE5iuY3lKLq8G7hR2ouhmzlalOBbgmabZtBFCTIsCkxWSqFgRowinTEWnH3n3TyUHWO7QGDuZ0Y4puJgV8HJXSvxlA3U8BIu37KXe6f8skpZCziB1HMDeY9zkDkJiQNP8cBGnegXKPzFyqhDL4x7rlg/K5DkPdd4Bu/9zZ7702JIuw5XdPUv7cdmOIAuTyIT/j78OVvPzN9Q5Qv4dUHAO5Y30TsLb+coD4vskm1nnKfbgHdgasOitAQ2ADF1kMniMtI/1OgJ9kC+nH3VoefrzjnfdPJ3XcP6FFyZM6XkJklEbxOCSCNEHFkL6+6Qx0jHeev1ZW6MCkDwnJUZKB2dShRkdMk43ewaW5mbrtHcyyros56wEO62SE+MCu93c9Zr/zOUkDWC5peLb3HfQ9c//sXr7qoC5XMN0bmpHude4oLAJIRgH1jkICpqkwSM35W9ucJHgWGog605GqXhutOPOEb2Nm3VGopMibxzVr+4HTSh5bWEsFaexX2xO607xhFDD0P6knTYzjvhdsHetic+5ID07TnXVpwg6jh3swuS/X+R2EJcjg/TLPAU5WGS5Ik5i+tcyYJuUziLCa05reUdRp3D+Ynf81/f8hvQK6F5KW5YbWNky1YrZgoa25VkvMIDdsRHh8fFQwJSaL0zxhvd1CGlVInSwyWt/Q+yRghAJsAQKkzBslAHDveHp6cq2VPWtAS8wrw2ROtG2TfoprPUZzxTa4A97nac8aqLPnslQ+/3ZAV8IaWaTMytLZDubtNGYQ/reYh0PqAbgMCCVQVojQGKqp7Kg1OWRx0EFyfsSkkKkKtonuSfYp+T5oKGzDAWI7jzef5yczs0wHqX6wvePm7Qze8GQ0iLRg0+4Mm+yxQXcYfNrVXZmqHciBns/oqV9EKxOMRNR5D+ZyNQLYIZ2Z83d2HemaAmUmbJP2oN9J65XfyaaWXsIJs3BgYpk9WH30m3qk08+xH3mYXwZP9g+WIjHCzIW9nWlybTKCOSEC/tS/8Xvwte/8zqjnDsBkgzef1xkA055Zi9czU2tM+5DoXEt37LvIiFmBHCsTRizaXQKyZ1bOddEKcaCkAPIZ+TkZMcKR/gxDuocYpxW3Rt59NKDFvgfY23LWN6T193eNXjgSdOmAaOJ6Q6HJTehs/ZjAZAyVQBIDTedNlMmerc8DnWtcKypXn8OmIQzNd2g2Dt3HO4BGee2/V08fshx/n/XvWacOf3bXzm7uy09M/0hMYxQZcYaXOlBk/6VCoqUs9kxTpzaEppsLrYuvXzHxUxsU8y7swi8Sr5dBvAHIePo6GBqYNkmlrWyCMh0LO89sAJ7nGfM2D47IANE2en/o+gRlSxblBdjA3K5/d7XKENE+WchHmdgMczVp/wbw9PxMOtMYOi+i64JQQBRm9a1pYHGIk5ptecJWN6zbhjJVTJS8IBPJGUMSS6nX9DLSK6B7IWlZbui9gaYJky7wdV2xrqt7pWxbxVoK3r59i4eHKwBgmgQAPiK0SVMRTRw0BkrvZrcN12qZFMpMIoE4i3e5XNw8y8wuxeyxKpjb/CxUnIOzAOQdtU6uHdy7/83ML+WNgdkBHYCBgc4mbC4pyxu/gi4DYlm7FvzlqNHxw/p7wJWYCvNMlYEkHYCk9ANgm0DUIWHLXRoZC5NrYqirSdZHzBHf37UhAcwG5vI2mRgS/Qy4xm5zOCbQGsHAXLR/bAHongPwvMHm39HOeE41fECcb/NNW52JFGMKz/rAe3P4CEMrf7N2LzcoMzmCCeTMw6JCFanDcZPP89KEFmdgbqil5hdSX3YnKeB8ribNYTLGJgkpvLK7HifVylWLR6ZeCKXXYR7T/XkQfvZHfzseP/xQ+4JT5wE+KFEVABpvcQco99UZ5kx6n3F88B6oCzAXd9XSEGZK2SGgrMNAHeSBs6PoOTsHdSf389rD+fd7UOPEiPTkuVSQrY1dx4zgh8eLTiA43tXnAlwbWOvgoiuHwgEW67pw80vYegck3lkZGG1h3McONG/BlRlg8yTchc4igbkkABjwM8UVqzbvnj37/txI5LkGylfekRj4+PNfwH/5h/8Y/uN/+V94v3dOso89SvuUcx+OUEq8kXbxxlj0WTtXZw81nSflhjiXLGe1SM/Ehnt/eSlr40AWb64kMLfvk0QXWcYVRS1XFETa3lg1VFBrM9pmfMYYS5Pahs4absTiJargwftA0HuaY+M690Ar7LW7u/tFm8j5DeMpaNif9gQTMT8zCMx5HwR6xmtwOp/XUMrkzte2bUNdV1wuF3/Pnrfg46+A7uWkV6coLyQxoE5MQnNFRFjX1U0M7TzZtm3qHEQdjKQzZuu6oiXHIxKWYPV83ExRGclpmnC9Xt218bIsuKnHTCOboY0rbupoGjgpx879FZfGZW1gdtaStXd5UzNgZyakR8+awVDHb3c6r57/Rqa7p7MgwYirSeoUZYlEzQ6Uk4O6XIdg1pM2iYW5EamdbFq1VD2z8K7RHn8rH3/nPgDkPJ8Hcyev6h4d5nGaY8ougax9uc7cpRpr/5tp37HGSVvpn+OGGZ+S5lwGgMlccO9EJGqTgFX0o+dmku2UJ/LmHY0KcMajyae9l81xzkx1nvvkdDC1jJYgzuEEQ26A/2CeqfXOYErmoZhuT7X6ujMti5ujJuCwn6+Uxj33s/drlnrvH/PLx3l6WBe0G/EdYB5TAuscGNMFK2wxCBHaXV3L8WwC+szR3xjncGYtzxjI94QGd9twSDSWZSZt1os2cllK4XMkzR+raAZpRqMADA4zcr/ZHDSTfI/TSLnPBsNfRJUSOCHRTmRnVwHmMMypaGvqFpuTu/XhnzMYQjhc86mdQMN5z78HLf2U5PZdKc+6vJdJYLoe37Ngp4WzlLZt+lnR1hVNHaa0bUVvm4Q/0Pegn5grY8NonHW7dUA+nlRC+yeWA/oEiZO1cJQySxggIjx94QsAgN/yR/7oMEWP6YxOHsHv+9JTXxuWE9GwZ4QA7oSW7vLb03sXQtscN37IxlKrfixvPGbiQc+B4VjKa/psp9eRfiFpnibcbjfUUnC9zKhTwTRXvH37FtNUALqgTsWlOeu64PHxEZfLRZ2TyCHlra34EB9gnmc8PDy498pt23BRbdyaNA7TNOGjjz6SM3pNDvKaxgyAn7fZtg3X60XNK2WzWNdFzT4FFALhFtmImZmgmaMWA3O9d/emaYTSAN0ZeDPi6uftWldpowCwTc0d5FB2ASASQ/HcKRpLo/HzbGcQitr/S11AQNuaBGhloE4Tqh5w3toGWjEcZuau4Q/6hgqp26wHnsXc5shoIbEkWco8aqrSa4dL+41sfz9vZJq3lZZA+gjqRiaaM3jk9Jzve0cgYu8Hw6aawT2nn+ol9b/DuDPctfOe2R835NxmirwNbADizpoIKBTM8hGhOpPfUrs6W9xF81QWHsuy8CJrm0XTfGQict3tu5sqGQPe1RxJGTBK7bY6hkfcJNzg8eC/xH+cpK42Jgp0YpRVij4A+qGr4e6/8wiWMjxtzL7VdXTzb9y6zR91zADRxhmSidnP3q6Yj6kgqw1DNa4BCuTxrmZiOu+1DoU03IF3JTvtsMzt+aHPD30TyIMBdZdvKyyt+W8KBFiZOv/3SJnzV47+HNZVPCjzwszmunoovAhzXszRj7wk8xuoqDIzbC5qPhbrMNfBRrbrnGWdTKUUQMPSlCrx0RhAZUYvMg59z0E7zUht9Hl0hNMuoNt1zDCuQ/gAyjPxpN+fh+hnwomoDfsz41ohnd60f2FHO3WcmAEuMrFLEe9QAJgbuFdQbwrWGNw2cNvQtxWtTiBm2a/q7N55S9EYAkbvSgH3gaJGy3xa79tpNLWAKoUJuK5dqhWXcnXtVHezc8JGhK993/fh4etfh5wBIQBF3PrrdHIBHWKY337pu2BjbKIWt34hEVhRISA5h3QLidagavuBb7C22LMiUEac6UcIcDPNrommu8C5VlCpKCQWS6XG+UXrUSLCm4cHUJFzcm7pNItllZ21E8dvr3qbl5JeAd0LSdM8O/CS+CXQwN/NHXgAcC1Zaw3Lsrg55jRPuC03bI1xvV78etaGyfm8iB1noGqeZ7ftZmatQyaC7MDMGNWmrnkDaE2YpobW6mCCmL0Djto1uMbQmGHJP9wt2/uDZ0uKcAzG9DBYXRQzagoyamahpGZXIm1mmHlKIYlx1pkx1SLMTO/gTTatOk0oKSi6m48m6blLQUuV2E4O5kLuKR0A8XJ2MvYDA5lhHuFwLYOX47XET+6AlJubOI94h0FJQC4zKMkQUbFG1prGJmbMuIHU52LjBU8zMnJWkaKZZ2zZe3dgEsBo1+bUeC9dx11u55h2xwpxz4ZKab641oJ8LiExHKZ9jvbjIJQwD3OHfjRAxzsz0xIAiQmBYpD7JeaV1MPAZQCvKIdtwGS8vOP3A2AMcBYQBMix0s1D4vBmwkmkk47Te+xANbo92kLen94HwzzMIzOOr/wRsJDXXmEGUwrozUhH7JSO2P3E8d9l4dMz8o6CUF30zzH/z6fnQcVzKPFwJ5MJjniZ2VzMH8yaj0LorLQTpiWC01hrvB7xgi0BV3IoqHO6TnZOGhJwXDU9Ylp7hFd5Tge6jrEf+laB9L7bfD2kaOMy5+i0C/P6eWd6x4OnY58J2Fgwsgmt9F93wQCjQ+K5MazDe4eYMSLWI4PRtsnzKbUKMGQIvSoEN7NkO6CnFbsjMBiqyTGvqajjGzfmjOMUlLJzwawCOdHwmcmlfkgDohf1xKrpr/5r/4q8q5YvNge8jGLn4JUGJXotIY26j7nVn2yuJFA3yluP1hemUTNBXQA+qFfQiqr1t74M8Mi4XK/S1xRWPtl7Jp/U4zV9ttMrdH8h6TLPrgnKsdqAbO4nBNqAmp1TMw2CmVwa4Mnx3wwo7k0ZASG+P/eD/yj+5vd9ZwJ76kZd6VP28CRaO3NrDK+rgLppMFELLUQGHcHg3gssnomovXNW932euc7CNI8aQy8jgZwIjCoMu8WvAeDgzc3wbGNJm2HWKBrBH8vSv8H/7x7IpiTBeO0g4S4dd4HzjYF8Dz0zYzsam+0qbc844LCyd+8M9U+aspM6G5CxfGTvDvNGi8+0f5NZ4v1s26bzJsxmJJ+9xi5qKnxmCA72QGcPFGy8ARNiUGoXDiDfysxjOLCnbKZvO9CmnPDZOglz04jnRaZlRMxz1wRQtNFNLG0NcsxpZ86Ugb8vZMg/ok5khangIgOqk1f8d9Q7zPBiftLpe+/ioHn3cTNLjnnWGW6KKXrJ47riszVwVlrGv8GLjxV6n3zuNeK988C95TWsLSD6mzsP5vr5npl4MsO1xHYG2TQofn9YLzsKsgMvYaKWhCI+f/RBZhcKDWCa9h1hN2l3bdcRBjIxduuum/7hp3vg/ry6/o0R5pLc4ywt9CP0Q0wwe1v1r5pgthVtE/f5ra16vwGs59t67IlnYHjcRMRZTlMhmu3zEXcwf2TvRCmgWlUYWrF9/iN89Iu/iN/wx/+7yNXBfljlBLAjD7OQhQ97c8v7Zpd9oM2jh8r7gzDQzaSlszpmQXNJfTCE9Eh16p1xuVzEFLXKWcPsu6AmPibzPq/ps51eNXQvJFVzTNIl4LWdGzJQ1FpT4mKhAkSb19TsL4O/pqDwcplda7BtG9rWQA/hacltuOuEr/yWH8ZXv/pV0De+4YyzJSM6TWO9mdmZMOIRp673itYm9P64I24RCybnOYKwc4KdNXv2XH5fkkjfhJibyaVsBEbQKTEjIuVTqSFGW/miXhRNGk0lm2BEEGopNZu8sW9SihKh9lgHQeh+Q9ct653S3/dN0c0BrETLAf871EMFly7FPkl7Dd3JAylTLengXfPkNQVgwYSOc8SyFrMvDXvhWq6sBbO2qqnnjlPJQAJAAEGr4J45AHxeDFJl5LnbVRvNcMXXAMajbfv5bm33sxfJAcwe1EULAojZmFofh4Q5zhxaITl/M0UcERvS+B37zec72VzWftD+Dr5Q+4vvZLBPOuXNac9emeuaVMCd9BCHi3r/dzd/TUNXKEIbMIu/CcpmwKmqZBk5Ys/ds0dume7olaTFGGfxp0zPrpfIed+tcSehGSKFr0FL27ahTHJPDc9BPqLhydTNLCnGIc9N1kocmWRKxSetdWEUDkED8/k0ud9vI/A/SM3OeooTzaJxXMayaPfmOzLev3Je3ffKUuqJ2CtCNAHmAhQGKb0zEumOUhLt3OokDmnA6FRQigC4WisKdwATqOooqwtN01ox02kdnR51dtNlKqKdlfJ76sjwZmrmnrV23H7Fr8QnX/oSPvrFvzd2X97ny658KjAtm1GbbMlzj0+wOg/r2K/hcN2LU8K9B3N2/VCem4mGgy4gdgiG8DzzPAsGbxKcwiyanDa72eVrYPGXkl4B3UtJ3PHmzRUECTK+bVsyhWx4fHzEm4cHXB8ecL1ecbtJwNFtW3Fbb7jMM65XsWVflgVPT494eLjizZsrWtvw9u0neHx8i4erSI0M5AHANE+49EtyEgI/Z5elStu2uiZO/hYsy4qHh4J5vpyaR2YnKJZ/1hxmMzW7l00xs3lmdqRiv0upyrAUbFsDUDDPYSaxbQ21NjDP3h43RyPCukqQXdtUSrUYfZvEBEqEHgB66+ilg3xDVPBXAQc7fiA9vO0Zo7/no2G/T0DYboIk5ol3f/XNQx4pH2c2T+rAGDbEEfAdK0u6gbtEmQFnQCwP57T3Dd1dIWHoi4PruCfgjQft1VEzOkpGh3KTJBiABKI/gLEYFyZSJjBqK+DfwHwuNzEP2ol2P7yqhVmljWns5f0EyHVn0o78oDDXBYSpVs/XnydW8zbri+gzxRrIGsah3Qosv/S3/ya+8W3fjq9/8Uued2Z8DdBFk4+x8KzfnJV2phOH5OCHclswrPsBUILCbNlBMw/AoqMraGMdfzPDYgjT2QHVeJrmmbm7NjOPr5U5jkO08TzZU0dN/V1cO2B28jGVuuQ3KT3vsBpuxkvKZA7tsPFJggKfxwrhhvzg7/Y0H0VzHmsGac3lFsZchpwzKkXyUfmgmWBG3uN4e5/se5jufN/1G+fGnbwSEe7Y596+X/9Bpr3ml5IUwWN9Am69keAyJA6grcPow4ZVQZruM9RAKOhzS1Y4FdQ7eq8oRcBeYQaVCVOZ1foxEwP9kxx6ZU/UABTYsa97C1AP83pKqqWDnGU3ITXmGSDCpmeDDRQRabgMPbNue+Rv/IN/CADjz//+f1uyxhHIZWBkv10AV6weu7Fglrqe0EGU0BbmfjGeJvNBDNvjUpxU/ZhDOipFPZMrjU/hb3JYqNaaBCB/TS8ivQK6F5KmacLlcsG6LPjk7VvM04SHhwfMs3i1vN2eUAth1jNvy3pD6w3LcgMR8Oajz2OeZ6zrgnVd8fT0COALuF6vWJYFb99KaIR1XfHhhx+690s5qHvBd3284HpjrB98gKenJzw9PYG5Y9sapqkqoGuJSSDM80VNPMWkk4g84HkGg0Q0eLo0k9F1XQHExmIE2QCnEe18xs9AXVOHGNMUGovWOog2NwkVr5ubm6KaWYg8R97vAm5XN/u4Xi4opUj8GCI9y1jdJLYA7hGz2OZkG7UypmQbFEZJ8Mi87cW9SaM2MBdJ0szYfec7747fg63QvBKfwc7w5epQ2mSF+TVG2spxoKVsizlZ6Hysm7ya4UEk28h7D0YLHGaCbv6F7KUvzHzkUHk6q2bMWirgwHryUHi6riYwPv+qAsIjSM39YMysSWGfSz6PE5jzeeLA29ZFAoUQhlQYYgY6oxBUCZzmozKKWQCSzZysINEwy/gzd/zr/+G/j/8OlPb3AAAgAElEQVT7B7+MP/xf//H0DEMca6S6pXNnxkxlRy12Li3BCevd9M3ECzsm1vs2ALqAbS0TobULyAcvsytIMe15IWDjBiKgdkYvhAkVVRlamyl8qEGuPZ2UGIKFPQ6g4f1DFXf574rMPw0Mn+Yrf7tp0fQegf0MqJPqYjNHx8xMiEvQTp9nlg8RsiOpUooIPAq7SbTNXylLC7O4c3IAFrVO6MwoRc39ip656qntLvDQdpoABqGBx/B97LJxdCxLTje0fU4HEn0YCYXndH16xG//H/77I7A8Sc+Cz7PndmRd1l+cPQ7Ep0C9qBsZE/p0BkoDswgejQZNfUJvso9RrQCViBPbJ5QyA7r/lSomkW5aOE0AV92z5Fprm5tDep969SnRJ4KbMpPsheYnhCvA84w3X/86aplcSIdtkzOV0+T7S+4cX49EKEigksOcctJQAAfLBj2rt7fmEV8E+giNHrSFV+Dh2kjXwhO3Be2w+LRb2zwGqThmE3rcVQAioLBhU6uqvfXSur5q6F5Kej1D90ISlRSjTZ2jCAgazS6XZQkm3Z53hyWmSTKiF2EFzJNSljS5I5TO+I1/4mfwo//LX8bDwwOIwvHIeL6NB1BlJoqmFTTt1zRNXuespXOnIlnjdWJqZlIy+50dt+zN18wM0rYAI7L7c3zWnjA3FS+YAhinFAYCqFPFNGXPVTvz1x5BVIsyyRm4kV4XKWYy1UB6wL+M0kLr5/j7HDgwZj++x99hdvl8GUFPSNMNNLAzdieS5QTm8sf5kzQe8Rc+PntANLTEeBj9x8UGFCYuBuZMyi9mPfksg/V18f4+sn8mOBgLD6kr++99H4bWOZvgRP33UtuI12XjMvZPN5fkzoiY+RvFvCJjZDHkYxpiAWli+lOGeTaghwNg9LlK+dkMVmP+GiCmPC1zxvlv7ivNP/6Oc8Zn9/P49z0TDXVwiuCCAUbLwep5v04yq2+/aZfbsaw9mAM9E+vqThoBLQ+1OH3e1orRvTxv959hEkSb5NVECwzYp8WX94n4VAcCwZjSYZ2at+F4roSpGo1z1WZEppOxtvbEMWg9p77i/SM4jtppNnfQ17ws+JH/9WeON45E5TTRyX+neSEoaAxnjGceUxtrswDh3sAsn943OWrR5G/b0ncLddDEomfVMAce6qCbcEk8RfuebwjfBQt82mcB86xBQbAYwNd++Ifx5pd+CV/6W38b03wBURnO9GaAs8v0eF8FCVlYfO9j7w7ZDnxDor08gsX9OhpNLk0YFvTe6QlFXu5Bk2Mm7nmd07a/ps9setXQvZjEYEiQUDFbZGzbjMtlRmuq5eoNy3qTuHG64ZrDE+aGomYDAWJEMm2gZV02JzK2WUvcuiZbTiG8efMG3/jGN9ytrwCfHITW4s8BtRrIEkA3z1Jfc4ySTTZyoHEADs6A0eGKPZ+vTel8oZl0ioaio/eCUoxYAsxmihlMvkjJTNpowDnAozzTNK/qbSVanHlybUTr6GjoREBNgINi23YgBzvsr2mQ4lPikI8EnTkz8cHE5d8BkN5/Q5BNJzH7iZcPKTunwOL3ZNSJsTJm0MaTkfpNPhHk3Np1vtEGM6tgBZDzL0QAIzbUHbDag+ORMTRpaNQxM8WsF5yJOrx7BN1EUGlv7ofEeJ1yfsFMRMiF6KNy1tEZ6PoP9vdCGw2fhzLEaq6FGMMAaImJ3BcUvS/jphzKPcbY80vhDQysZaEOmAenhd6eEXc+nzzjXZWHB+DtZ4iVGnHGnYxOrMGOo/7Qth7i3L+jOnsw58nzYcv8JMU94ZNT4e/olBDe2HgmaJOmCXHuYJ2nndHRsCWgFWeBhgb5/hECCykzB3t2MNnVkQdBw6h11QaqAI9lNrkbeNXuD1g8AWVKN3zIlX4k3jn5TtnrebQ7zjDhea/inYP+Hul9tHr7dlnpgQrsYiKm+Uk1Y2WjfW0DQWOPcwdxR+klaBqM1hX5dEblDq4TKhjgCnTzRktpLo9z6kjSxvkSc1315ETgN2+wfe4jPBBwfbiCb4zGEnC8Y9Ra5B1AqhJC0Uw/mZvfH6qTum8P6uycrNOk90m7vpf6MLrm01vX0EfsQhAghPPdAfAo2DZvr1m4/Zo+++kV0L2QZIDHJEe9kx+WHZ2jbCC6DtdMmycOUyYsi5g8ruuKeRbAMs+zewi0sgy4NDWlJCJcr1cxQwQAsDpCGU1rRCJo9utFpYPNTS0t+HmWah21fcHwZSJngC4T4+w6eJDUIcz8snmFaCah1wuY1Ryiz2ljkDNROSC6SdlqJQDCHHdl0K0dnRm9MbjYmS64yWUGEwOJJmDvpOPIDd5Ph/38+EQCTOd/ZZORZ20TdobMGbNjzgQ+qWbW6tnvAErGQ8ZQBZgLNmzoCGRwGLdCYh/mPjRsnCNw0rY6UNJ54XPjKH3tJ40uad7ioCmI+manL9EXNIAs29yjv0ZQ67kmsJX72f4lRF9r18j6AYGqmAyFqZoKPBRogRBnY2hXFkcP/vh/+5N4/PBDzx+6VsiYtvTn/pRUQJzmAOuXCL/AO/PDsWuHe/emy66XdmzdiGHsdwcIHV3XseGn57Qnp+ns3p6xtH7LoO5d6U6nvvtN79iUyQEqBKOtTDF6RynS34XVpbyPsa4lMrFAYrIBjelI3r/uHKiHVtftdGHAUZ3VJG26VczochRCqbxdD6TmOKizGvLJA/lVTudTz4Cersv1csH//pt+M37b//iTqU7j4+8Cbkk09exz+2p7T/jBOvtLgJ5RQzczaDN13OTFBqAXUOnoRaIK2n+lMggVQAEqe4GlTEqculp5Gt2jKH+HMfPYCYgzGmf7a+olsUHEtTVcH96odk7ME50GD5+xjynNSeCw1Ibk9/L8oXgv+IJMozE4PxveSzyK8zJdhCJmZikWUhrOqFbB2uYpm4OnMeGH5wfoEZQxjt1r+uymV+j+QtLtdhtMJ4EIyi1mkwJmsnbNz3/pWbhaKy6Xi5s8ruvi2io72ybn654GJyXrtjrQEi3bBVwIl7WDty0RrQyauoIwIYxGwMwT5v6AcWhJumsJs9lleKM8I8Q0tDkfTHbC6YBgBI7Rl9nFPA0SZ3kuMToqTctONADbaJNZhmpZCNBzXQZAhDEqzjynlHh222DeV1h4P51lECaO7Jskx70kXb/3wbi36qZ9NFnJoLwnE9gR8I3g7/g5tkj6Vd1bl+T6nPYOJzjla7/iY4VbPEer5/5Au41zVbfb0zTpHD73rJb73bVspXj4jnB3jVwbfV7b4m67cxlDl/urI3wN85+9WVyYYu5CHtxrx9iU3TjQ8Ou8z2ON7MfQcnB8aADqPTHU+y6NUyyU54LOv76bpw7Id597nbJfy8/XKS8gMxE8qzk/8/u5lPrx5JVxiYQgwH7u112CXz6XCWalcVwnUQhFnn59dy5xD4aSsMbLzvNy17yhKYfvx56NMTx0wfNJn7k9vMGf+Z2/6z1e2CWykY7CTsedhz+6ztnnagAk/d4z3U3fu2iruLMG9d4ijEE7McPUowa9beh9A/empgYpHIKeW44FtBfg3Wm4tyWbFArdefuDX8YP/fiP48NS8PDmDR4e3uAyX8CMOH+2O95h2VKaJMYH1FrdS+Q9+iPlB+9w9rEz/eYnIF/fH/3I/d661HlTZyeAgMKpTsN5v+BbwneA0J9wAjdN871OfU2fsfSqoXsh6bYsYJYzXtM8O/Ns0h8xUzEzyO5EYlnYnX6Ydm2eJ/Qu5+3sjNE0TajThKfHT/D27Vu8efPGwdHtJg5WjJhdr1f8wnf/I/g7X/wQv+rvfg0/973fkQBY1qq1gYEUJypbIlQyfY2w2XvbtnnZdh5vD/CALAVE9M0kB6u3dRtAmUkN7bda+CTGO0CHMd/2G4hAqCZpFlBnwM+YUXIQ1DuLqar2CVUNokuj4RKlf09Fxn49gGZmus5TPgN2zC/yeE4rFpLbzED4XX0lAgDrHd/cj+wv55zVPfwerBqoO2tTlB8SYtpnwsYg0a6fYrMNR3yaj74qjEMEurd268PeDj8LRCL37yd1PmuHgTE7r+r1yk8S+dy0Yg3vhUe73B9jP3u7leMtJnHeme0MZzMScBvBVRKYPIfqtGMG7DDUMzFUhNDoxdNpfkT4AZsr70yaZ/SAvrWb1pz+zUAqLjF6h5hcdkZXoUvML5tZGP4amM7d82mA5iGc2v0nd7/vlLRfzmd5pD8EpcE2TjZnaFyjbn5sxRgo62lsba44EokxlHvqNbgDTD3WYPrkPUNJyjuEWtoubx6P/fq+g/G+6T2Q33tpdfPcJFsHuodQaL5tuXBu44D09kmtUlB8xpqH3N4BIjFkNJN/pSxRSd6AKp6aOxF6JXCfAGKImSSDiVCL0fsTAJ+RumuG81+9p3Tj7Q/8AL7tL/4FXJ9uWD/3IcCMlSput0c/w2fWEhlAUax2LZpQUICqIYmAnZVFrOW9MLkUoLAdp9jFjtMwRpluEpGDtQwcDYBKKCj1dQCSIONVhM3YVOBdTTBCoMRvAOKIxsHpa3oR6RXQvZD0+PYteu+4Xi744OENtm3DsixYlieVIE3Yto6tMR4fHzFNFQ8PVyzLDctyw8cff+yeMh8erui94eOPP0bvDQ8a6mCeJizLgk8++QRf+MIXMM8zaq14ut3kDJyaSn700Ud4enrC3/j+78Rv+Ou/CPOIKRIruCOU223B9XpFKYTLZca2NazrIx4e3riGYlkWD8FgUrhlEc3hw8ODn5fbts1tzO2cXA5vYIDvcrkAALa1ORg05jwAWGgLhVYSiKq7CK61QLyKwT1tPjxccbvd0Htzj5fTNGFZNzENgbARhQgdep5vXUFVnARUD4xaNG7QmEZgByRYMshyA9TljdE2uPgOyKaE4d30KzO0UvMA3lAGOWvIejyfo9GxSoejxiOPIXmKI54CNTVRUf0AKlL9AzSPfSL8XTJ1LMU3ceu/XAcDlXY2zsbcQNiePbZxjI28jGVQOGsAs3oJt/5jhASdPSZemG1GgeYwp+tz5hyFCmFybUYCbKxmYBzl2IeTxDq0d+YfMrcl+th7NgO2GNAEXpXRgZ5RzLjZAKYO0X46srWTrS3GZNrDu0SZCR5HM5tYCkuY2bizlOanA+J7zwdTacKLrTOqWj9MVFF4DywI1vr3xwojsrR5tqvJs226ny/tbmtFeXzE5lMp+3E3b7ENtEngZ6pQ7a2Mmc1j1k6wWKNuLobodWaIhjPFYASAUqrQLS5A6QABtQkL0xrp2m4SdqOLtqJtELf1kftZj+4bma/cHacBnnNM4vvPn1zXeTsAspNn9pU+zEY2Ws+6nuJ7nENL89CytQW9X78kJpdx1KABncHogO9BNj4djEmFmRsIq54VnzRmreypcq6rgIpaJfihXt2pEmBHoheEFA4HEkOO1DuwzCvV6rJA0evDAx7ePKCtK95+MuN2e8LT4yOW2wKA8Td+9LcCkGMoRbCWeroM76xTqXh6WqSXz+jcsK/Evjf5OW6b3yK8s1B8Gbxa37pnbQVxy7JgWTfcbqvwN+sGKmJFMs0zGCu21XiaCVPSOt8eby7wvpSCihAAvqbPfnoFdC8slVIwq9t8kwSZ6t9IlICrMAsw5yam+TIitW0b1nV1L5EAHDDZx65xF8Z42zZcLhc30TRGd3/OLUwbm0uZTANi2jQgiGJ2qrI/S7e/buXsXRWHOcTkYG9gjOG0HaZBPJpebqj1mrSKQqxrvTi49HN5xTyBhpbKmH6wnKXrROJ+2cYnMeXDuTka/mglMcQi+rRpUFxx3nzPUnAFxgS5SRifPuaCWJfqMxCO5vfmh6zuyaHgMKTD5MxyjFXWHMZ9ckYhzK7ir9fPQURoC+18nAG6AZRKBynwSvUuJEzorhzuHd0AnBebAJ1Kk+0wvOVvqWmfed8ZYMsAVx1CsHmQeccc8Naoeo4s7zx0vg7210+Y0QQmfSiQvxzZ2xA+2CAAvjI+BfpxHtaY3P0ayA98s8nzT+vEz/eoEMBc8Jf0Tmb4v4Xiv5Xkw+o8swESe8D+MYBjzmeez1Ta2kFdaV8X5w6lnIFhHucwxjUn54N2b1if+7oXq4VeCgp3SAB5EgGYmr1CBR5nVX8XRRseyr/vzJ2zGb1/n8HvO43v1uee+Z9TJaX7AqTHSlH6l6HAzwQSvHcw1MEo6XVDk11KYnFYxkx6rpxB+ryZVIpyitCmCVyqADFAw4yyEPNOaS+w8R0rPopg1GKASUw6GS70ak0Ap5k4vuGOWgh9a67t+oVf98OSS2suaKJSYCyD7bUclTkIT4BxHCgLQIa9KWhyT+asgDoDUrPOIdZcE2+gTc0tLaaiCSPNC7OFMehVnAOB4siMfQ+roNf0EtIroHshKQOUoiBBzrxtuw2C1fSyAxBAd5lnrLcbbrcnE97JkxzmmNM0YVOvk0Tk2ioDaH/qR38I14cHrOuKy0WCjxfXyGkQ0ASOrBw7WxfS3CBaezMbq5Plcwbq7NwgAAeO+b6UVdxTmhHDUWtkeXV1LGPmk2OcsNEcU6R24uTFYp5VH5ctnWekUg72+7ZhBAOvkInoeQbB9uA7G+XpK7GPef0NFAVcG+/nPFkZ8dNE5BuTSzzJGG9jLEISuq/HPtfQEjH4wGgNomcY+HPQnO8YU2n/cWj67Ltp6vxJCkPCGIfQzvm5R2+3pO5S5W4wHkB34OYmx7b55wHhVIfdpPQWnd2HATsDZHmODj3qfPxoUhrzeByEYPitHkh9GcBuyB55vtioHUZXmWfa9fUwBRM6eY5BP7DgJzz5GZt+PuvSzeEL+9cB1CngznNkv4Lemfj06zGDd/FuiemU/5WhNVA3PMbpl4KA3XT0CqR17HkkOuVOdciYd3nBADGzrzwpzRjtWFWSj8/B5MHS5qnSlkJ2rpPQC4kE5Jk0WjFk9MO7axw/75CZTyF3ONTh5OLdZ+/NyVHUtMuMTJhwct/xewJ1gJc0OIXx7jBa1X3uiGxOwV0jNB2Xuk0olWHGfwW6j4PAJU9uDvovE8E2hai3lU9m9higqT4+oSm5KaXg4XrFVMi1YOu64Olxg50VFCBkwmHtQeYBGPnc0jLOILnxDqkZBwFI5k0sRYiTKNdDzqQ+7swqtJA2T9OEW9/8rF1BRTaooWfKfE2f3fQK6F5IsrNh2RFKdmc7mlVFTLdpmnC5XvH4ySd4enoCAMzz5AycATqRGPUBDN1uN4/v9vUvSmDyyyoOUszM06RNBgJF+xZEWkIjiMmd1DmAqaXsrMFAWwZvRozNYUoOaZBBoVwTRyyiEdQD4V6U7yRCdPuGbSuuzQwNop3Rs7AG8rz0TcG6NnBv7tzCgaDVp5SkoZExsvNW3JWpgemJgg/bM8qWshnhs1J2Y5bupMSrD98HFmHP6JzksQfj5EzlaA6a62ogyw7vGwcZc/YILIeW5braeKcbFrbA55bPsXHDDaZub66pvUDmYEg1wCeA29rh5ycAZDPCwVTVKm6gAAivbWfSYx61HruSMbAjjo52KfO0+syY2wgO2cCASuiBAHNsfbrLYQTqqXrI04YEqIMEcL+DU/60zLSt+TMgd6gUjI8fgejwXdeEjJFI5Durh1tKD3qfvr+2Zuy/e2+9O7cEtWG1CGBnPWgAnA7vUsrFchBQFsyvceNmBgeE0wgqCvE4+krlVyNN359B0peM7rrTqLNecCGfEwev073k43e8uvt9L49vFsr9w0kOhGk/g22zOKzoDEfSO13X9FGikIVfcrhuzKj3BmoS6mBbJ3F8aakUdD0blk37fQZy0DWjs1amad3NjF+eK/j4y78GP/L7/y385T/xP6H3jqrn9S/z7BrfpyfCt//Fv4DeGv7uj/w6QM/ahnOpoM9Gvw3Q7ZofzyrIGmfjvn/HmL5+PTkCGmi+zfdUToRqKpgvM54eVz9OMhGlYxkjAN2X+Zo+u+kV0L2Q5M4+tk00aTAill34R2w1IyBTrcA8qxOUm9iblzcAh9lj14DkUDA2zeLM+HZL9tx6Ni2DKiOYZi65bSuEEaiqkavYtht6L+h9UslUhewfPW3cQcTMTPRgTprA3j4ui+VhhLWqJykBY+rGGQYA5R0DYaU0ZBfZZppH6ikxe8EcNImq+ZsU/BJWiWeVNRFBzkW6ymKqZyecdt7eD4lj50155V33GTbWgduRETfzy3yPhxobk3jCyMPMRnQjp7jmABXhLMZz5DhTpi+llpPXJeqdHcBEmw1Qjpqk9KJ3UzCEnTvU7yl6H9FOAFkW88okXDDOhM+eH/okdW6+ptJnl7qTMr1UMGoPrO0GQKM9Np/2AM+k8PcQvjGCoWWOZK95FjbWbOavY78ag/LP/Tf/Ff6f7/5u/Mnf83ujDpan/xNfnJ2jVE8D/oe4Be+bzph0AM+YJvta49Qvu2dtRZn2ZDDXBfuaGfUnaf0Q0ix9f3hwgJfPL+u46WNE2qeMoynhWAvaZYEkHCEqum5ZYxSWsf5sAiibT1GP0aIh6MFhtVgTbQ3ruSLJo3heIeALLfkBqtE4yw5t3F97R78OU/ckk3z5edB4/3LWzO21dENfUf6bNezj9VybQ3G+IJX+7OUJDI1ByPqcgG0CdDI3MADTDbW6pnKEeHR18sXq1AMojvRtzEx7au31drvQTfIrhfD2H//1+Oiv/zUR3tp+WyeUCXjz5gNfi1/+6T+Hzoxf/PU/ApQCqhNKrdIO1hhwnfWs3wjoZH5nyBvX700SW1Z7QXRYe4z0mXyf0j2WGZ0FGVMhTJNYONGjAsKyqeBXeJZC4t3YvMjyq4buxaRXQPdC0jxfsSwrCIQP3nTM84RpntE++URNB/UQ/zS79HNbVhQSIjtPE7ZlwdttA6uG7TrLgeNlXcBPjGmSwN+1EpZlxe32BKDjgw/e4Df97M9j2xr+0j/x/Xh6fHTJWTUvTCyAkhnYtoapwjV4bWt4bI+i4ZtnbE1cI7emtuUO5jSWHIBlWXBbFjG/0Vgs2yZul6uZ46h0jBDBaFtrKFT0TCCB+YZt687EOmPG2e49zOMYwLptuMwzSp1g213bNkxqZlprxdbEnn+eLpjrhDZNYhnUJHaTxLFqHgyaCiQ+HTd3rMEWR+gE2HhiILZVhDSRxw3J0sjfP6+xO2X2EIwsOHiHPfiWTdLqLO9lxtk317QR2hyteiA+Khv13AMQPrQ/gCJbxQ0YADBhNBHcsQCxeHQThN69fQa6DGzVOqWNH0mbqM8NAIoc9OcqZ4aFSb3MpaFiZnTame2oFzfWuehMnwNn7YG9pJnP4+Q5E6hYSfogxofUOZBVzetI8j17cpX6Sb1+/Z/5KfydL/8Q/uTv+b06fraeApBaXgTySOjEjF5GZmhknkaI5EAy1e29IB/tVsMwQeyrmYAeAU5+nAG0zii9g1rDVAsY1XEjg93sNzR1lqn2Tcp8P0wuWEJm5mnoFa+erYHTfmCMjQFGwQP5Z9DW2hoyDYUV1CxuZ6x/sjXXWZ1DjBURqwOdq4OnYxEWutt2Cm1KKXYWNX430wz2KkGt+4Rem59V2g+uNOeIwA5XaPfX6UWMEBnNo/xSHh0DJkIDPvfLX8fv+3d/37h+gETS0gj4WPPwN1dqGFdtQEylPM+idQcoa2vY3neJoROCPB1AvStNY/E46l4xu1g8tE3ONzYBS1PbwG1DbSu4zfp+RyEG9DiCVKOAuYiJciKQlGmZxrMjwK/DBLVU0bmBOmNjxlQKpusVb4jE86yGJKiXi+yFtYKnCbbnuGDAQaVvGjGSnPXrOc6hqQ0LGCqANZpMDCrse1AOsRRjLXxMawBzw9YWrNtNADIztnUTb5ql4jIRWt+wLitKAaap4DJVMAilFswK6ri9ArqXkl4B3QtJhYocoO0sWgQlYOu2gQgefqAkToG5Y9kW9NZwvV7xqO78l/IEwhXzPOHpsXucukKE6eEKcFei19G2FeArftX/Kd4s/8o/+Y9hXW5483AV7R9kw+ncMU/iKattTUGWOFtZlgW3pxsIpHHwKpZFDgTbhkWooTGcKsoWB44JAgJ66dhWCQdQuhykb9umXq0m3zh7b5jmC4jEGYxto2b66SyzMbdQT5lK9Lv4dnaQqN0pbSWg1ILCBW3bUMsEAmGuE0iBYS0E4gJwFUANuFKGGzSIcz75wbHRHpgTZe7ztYE7TBv8qbbmHqgz8GiS9GAV9qZkJsHfm/kaKuDTcJjazwksS15F+o9k7mSX/xnUddeMKGPpwd1F4+buz41RpegDPzNnIQoyKIOAsAh9McYdAhDnIHpmAuT9MEMLRkT+joyWaE56ALzEsu0VDs5MskjJM9g0Joe8rQY42d/J4zSUYaPQzayoeH1BlFyBRx+KdLsBqW2AhiAhQrKTio4xcLivizKSWatlAc09D/19ADH2zwHEHBn4sSLjlf03KYuSxiLVR9tgAgrBNx3UoG2HmoopA+iLOpe0R5VRrT18HVtybJMLLnQO+/O7dZ4xiK1lA29HNBMAwucPK9NKHOits4AoTrFCoeNq2IDG7iNSjRuA3qBzqWPbVp+7oqGoqFTQVEAigouCbpIRJc4RQ7GiHTwDE2IQMwJK2qgB2O7esw0getvnKTvCizlu3TnMZWRwZoNs72TEO64VF7JoXTJgGyeJ6klzuxykID8Y+XlXJDDFArpjr1Va3HW8iQEU9YoZ2I9BoF7AlVFbRQfQFCAVAJgmoDdw22QtlALusseK0EoyLCVidYLEAFS0ex1BwhIt0z0WJA7eWpM2NsC9RgOEMl3A3LGx7F529pIAVAC8rgDHEQoA4BLz35GvasYYAFqMJ0Mcxli9CLJ3W392dHWslrTKBWrxA7S+YdtWbNsCwaCszlIWLCswzYR2s/h/M5i7CMC5g7uEnKmUYti8ps98egV0LyRZgEk3LeyMUiWYctaKURUJadeAoGIaKPbZdn1dhEGZp8m1XVvyLCnn49rg5dJSNm1kMGrvHg4gu5Qr4H4AACAASURBVLIW5yHqbppkEwcY67JimusBHLTeUJp6qdSQAKUUD/CczTJz4G7bpExzVUsEFQdBAkD3rpJiDcxOBUyy6bStwUw9rU45kKldM42ee9IsFb01BRvwzYQb3DOhbABB4AEc+atPnfZsYb723PWTnNj3e9/kh5yUqQjIZ0/QSUbQXDIIokF5ULR6zLIZ2jzJLO69vctNII2zSlUYXnHwKI2TUElpU1ZQZmN6DoK19nSnPkRjVTyL4NyN8c5lGFhQfaGDMgNxAFxz6RpRe7cfvRTuz9DmvyPgM291431rgws4nM+NgkzTQkT4K//0P4u//z3fe2irdteuLsoc79BrlBl0JZTNnO5GnpSf0ULz77uzPCGnPYg6vjOW6VccqCZANSDAXF52WhEdk4Uyx54YV9RxvsVbZ2Du0ARl/k1z+tw7+2lrz+brdh5JNN8JRiQ6ZgK93mKdiWM/dR7UxXNhnYoz3O5USOdpuK5Xml4Ihc1rcUHbTirNJ79TN7w/ibWxZR+//bTm3ffxvU+fToF/KvDcuJt9vxmAnIXVsNrf2SKkT8aWeDnE6lhKQEy0URymcO/o1EBNTC27nqFrJMcsqAjQEi+YLKaQVHQOGfS1Gih9tpa6Q6xjRzAInWN/neos4LACl+sVrW16FlP1l6T7FYkwRrxohoa41knyDutQP8cG6HzX/tDNyvdI17AaPbC5appIpO9OwzUvXQedO4BJTCt9LFlhpQDZtjbl01Zwveck5zV9FtNrgIoXkooCOomXZqaGYo7IzFjXLZ1RkphabWtuejCpKaPFR9vWFWDGVDUejIIeAzfTJB/TZhhjmj1a/vyv/R68+eSGz3/1LQBSZyRFz7CRazoE0E1gBtZ1UWaS/JA9oEGdu9a3Fgd0Ei6hq1ZmBHTWBwYSimp/AHgZU50wTxPIPGVlaRoRtrYlbc1J/tof2dFMKVJOxmYGjF3LIhkOwNUEpjj55C0up4Ex+XRcivbDez43fNGtN21OSeXzTAbHm/G6aSXtfF0ABTk3EJ5Qh/eN8bE8DmCOB3DU9cNAaEJNMpw0cTGXrZ/GumemyctyUAg3m6U8eCeDOGjNrEWUzicZw6sAy/phqlXWZhGhTY75tf9YaBL7Gx5jQ9tHw1gEI+Efnbe5/tmRDBHhp373v4mf+R0/FuN90lZv70n/nU1gPvwYBQIODtP0G8HcviKU/huX2XmhpxfG/DM4HvpnD9BySqVS/N4bQ95d0O+xbi3H+xnE2rifQ+7TJKiwdwzQWhY8NCcEBF2cQLWtoW2qFUmgDWCfoww143WBRqxdo9umtbP57K3h3Xjvmvae5O7ZFJoyRv43d+PbDz+Hn/x3/r1vucyBvg0zdze2tg6HPmD9n9NSziuCxnLSa1m56Uq6gQ6kcrp6zu5NHdps6E0+bduwbiuaftzDNofQV4QCZlKu5uX7XjAChUxH3MeqPlNRp8nnxOVyxTxfhAeCxn9VUGfCNA8jkPiF4ppfUoc+3X0TdAOfTvvga98tRsAOUl3znPeD1AY/A91tLTSAuu550cICof21ijiht4ZtXbGu2+DR+TV9ttOrhu6FpELmfIQ1zIA4KpmnGesqwblrLZghGrZ129B6F81TKZgqpTNtEpOOiDDPM7Ztw9PTkwOweb6gc0frDeuyDCYLtRa0Tmi94avf9gF+7oe/Fx987WPQFx6EvBGhErmWy5jQSYOSu805iTSKe2jKjFDPNHvg8XVbXXpbNJgpb2J2SU01a0gaOqoSILozUBh1KmBI0PJlXYACVFLGlwqWtkRgcgrnKuaAxrx8AvANYpom1AIQyXlEM9urtWAjUs2dMegmlVZSr1K72LLZvxFMjkm+SX+zEuBvJpkpkFYoMRTx7V31CYnveI1VCpuZolNGe2dyKHtZcXDsf1OdM0tlZroB8uJuSYzCCBzH3yFtfbahMWKZqTp9X5gpUZokhtSYBtP4Zc1c0r49p0nMHmXtkQjVkeCGzTsKXj2yHAelmGkyRx7jmceUt7U15TLUdTfe+8ljc94ZUN7fzBL8PeucBpd27+Wyz34PWekFgjs2ynn7XPLV+S2mT5PBHTB2F8axrFAbZ0pazxiXI7A2JtYWDFH2VBnCFBEaqjmlgbHGMUcZ0ANSsr9MM2qJOKlNaaMoNyjAWtdz0UocPb6ar4WTfjjphG95bA4ELl+QeUjE6LXil77ne785+uwk8mQx5O8nGe9NK62KTMeZmbV3p/kMmj2kLrYFQp43946mu5WF72lNHKcYpWIiVD0nrdNQxr2YeamB151Qg7DT0CUiZfSdzMnVJMLUTnjz5g2WpYJowbLe5HG12kGxDlRgp/nU1lEgTtsC+cbcNy+u5ol66LOsmbPfKngIQdYJwDNwyhDNNcvvonH9iDanMRLbV0JRbdsm66ScDOBr+kymV0D3QpKBr3Vd8PbtWwCM6/WKhwcxO7jdbphqAa4XvHnzBrxt2JbFic/lItd7b3j8JA7yvnnzxs0Mt7ahc8flelEtWcUnnwQhM3e7nTuW5SbmDkmiKsFJi0rMJI5N7x11qpjnWYhUi2DmtVbZLKC25SQOTeze5XoZpHwo4fykt47bdsP14Srmj+gO0kTiJtuPMRTcO55uT7JB1YgFQzdC2xpuTzd1NDOpxnN1JmWeZ/e8ySyhIMw5StsaUKScaZqx1hvaplI3ksPNVfsDtJfABiggIKStwGEzCQ3F+xL3M3PBd70bCHLQtqRbuW7WjoGZ832NBlA4alUCzv5/7L1brG3bmhb0/a31PsaYa+19DlVaUlYVUFSUKC+lCWKMITESqQIDiqIxgUSDwcR3L7FiiAkqJia+qAGiUpGENzDxwcRIETUBeUAjBh8EFcqikKrAOVV11l5zzTF6b+334b+23vuYa+2zD0TOnG1n7TlGH623++X//qsRd+6kxqVgcVGWQmiNg7jUATFX1pwqMC5/bx2rB/YO6bKskToApu24xIVsoHC8xDNg4xiUPYBypyCaz+LgsUknZA/WJDHM4TvMJTY4+m5tcJZAIh5sGIia5w2CvAxl+BgXAvcg4EoVmyVmds62eV3La9el2qYKDeF2D0vOwOsOPOmA7dKePA7s5ZBveJtoox5H+XMARFkDI5g9xEqU1ibpWurQsWCUGm0cQe19sGdSmO2+8Z4w7QnyDDqHzZOA2V2OQ1Zho80aIWTFnnEPp/Fn+PoXGyFZxJ3HPFAAnKW5zFDHD8X3AUFU4LpKati1H0qMn0tUVu1eMAMDLKa1n9YQA2nuP+GMzOvkmfwMuDkd2djuMny8urHqofL9vCMA9LeFUFlBja0rcw5Fm7itgy1hAlC6kXx5sdiYU+9ovXhMT1DFNM+YKEJZ3HB1b8Fud61ep0kZssItMCZd7qJ8KmlmWe3sRXVbaJKpTuDC+Pzzr+N2u+J6veKLL4B1XYWOMG/SZA56dO0xg8qK2nlkmG3Xkd4ZYHUO48PAwSy0da7g1lT4C+n9oh5ARUsk2tHZYv+uuFze4NRkLAnS/guJRsZK4jW8tfYd4FK8pr9d0iugeyGJETYz67q6tMtsvzIxbIBotN0RYHI+nbFcrzBVmFoFbD08PODD0wdXM5ymycsyxyIEuFqXSbVCDc2IUOXwQu3RevO7gko4GslqPEZsmC1F793z1qm6qgQgB2itFWtfsbYVc5vB80gMCde3mccNvVSUUAZ7+SZV68xY1kXqnKpL6dZlRZvb0GcjOqpeWszNJSJly60DHOzGRfoMx1QneiQZGNv7/lBYMayU59MhHejSrBhL78e2TQdEzCBF8i6OhIt9KUaE8171SgjWABsRlkNjEm4qzmBuHDUFTiatInbozEUN9jMpQZs+62fzxGd9jL5u6ez9uAfhxkq3h0t8pH1j3gFNQmzlZVU094zKNn/xfhDq2vO0r4wwCzBHu3cLFQuLrvuraFwxOCMlq6d6fymYEqxU7whVrC28wXVWfwJY6Z0BMBwlsiFNqyyjuU3eTLQOW8feMamWPSYMk5vnIsZfn1Pq80eI+yPCfZfnDtDMRX8bGCJaMOxpK03XNNLZ4PhJCdtOaoQp53gmurt54XPJm8533tcKDqHnJ6vtNdjU0UP1egDppaC4YxaOOR8aK3U65M8DdW8cPuGcjDSOOAPYmXx9aqLt12Nwdw+Ukp1bNDzcZNqekar14We09ofjXIwODeg1SuBwEEIgNJXQickHZO7VbIOZQd3AfNhIUwGKzjd6H39DTFfuu3lJLsmO82f/k/8UzB2ndYUxAqZpFulXW8RTcG+YvBijg4QxI+UmLRBT9ae0ZHjLUt0DOj/9EkNtYJ4M53Kclb2zalSJr4B57tq2iOMrZ7CGW/oyS/U1/W2dXgHdS0kcYAoKStZ1xVwTp8kCVwJur2Cqgwb+zuczbreTe7Y0idPDw4PbsGUAaKqSv/S9n6ljlY1jFOVmueMQdOcqucqktpUgKji3200I+RKqnGKTRhKweW1AFc+W8zRLuxI4m6ZJ1CqZ/TcHlNoWIgML4dhEwKTY6lUqKHXCfDphWW643RbUUtBqFa9qrWFVTpoQuRPWtblOPiAOWG4cEkQiUUmlUgA2l9Dwthhzcjex6dNIaNy71L+dM/4rsvmIQEeX3FHeTP8YoeIEd5ImgUeiT/MFiMuUmRVqxAjHbyNuUsLUHN3kstXLo93c20DMKgXwthKAQig9vHE6B/fuNB39YO0enVTYOBhZQ142D0BXQG6BgbNDydJQt/SrlHjnaP6F8CgoRR0fwBjnhEKMrutVmDMJPO0KwsFCiLbwwboZ27Ht0wb6bV4mYARSR9XfSVtQaQU+tzuUXk3g5P6+3LXzE/KNz8jByfB+WqKfgujyErbvtM2QlktmMtgz+cvgDnQSKyUmcm02O3PFy3D1YtsqZyev4SGYCMEENBuqzmhoLgkE4IwNFJEEFSKQM+OgjjuOxkA69NVOuWcWQqrvT/7T/yym6w3T9fqVj9WBgfaRhXgE/pi2v2X9D/g8ZgmdS2Vdege4UZ2eixk+MydnVwx0klAera0oraK2FejiKKVC7gkiAWzkZxcggQBk/1iIA5HHGYNPmQt9WJiwMyRs3dXLZamY6gyegfN8BrowF/ra0BoD5kUTBKKKWiPYuPOTE7PseIJGxk60yyclZodSWJ+84xgObosyvW+3xe+oeZ6x3IxOW8XsZD6JRK9rDLvX9CLSK6B7MYk96LZJ5JZlwVQk4DeRuHpf11W4T3pYtNbQVKI3TRPm0yxBwlX07yqEpeB6u+G6XNFacymfqbv8jz/+o7hcLpgBB2/yvhyyAyCjJrHG1HasswC6OonEja+sRvTdD9Jaq7tXX9sK1v5O0wRqhBWqhlPETm4tq5yr6p6+UnVAOWk8MQsSbgbQ01SxLGKYbZ4n53lCa6sDvdY65nlGU/C2ritqqTifJ5VkdLcNrKXqhcd+UZr6RUgHdfaY3S30vfl9Pn0cxh3TmkGJjL+lL/cQQjAh91UrdzeXo9exX9BjUwzMYQCH22JJVVVCFyeDp7HUXSxpgqtHSRkFVDIhkNWY0rjYu6mgAQRRksjx5mIn2jYrEVxpXChopgHUpe8CHBQAJVvAGJtxquJ7tG8Ex2XsB0ItbugnFRQHw6oEbEBO5yLHH0zNH3H7c2Bz2/D0XrIaPXjP/+ftSuTrLu99rMObv6k5w2dd7FvA48CUByJ8KD7bq41k9UGjxjHYNtyrfw7Bc3pp8+69tN3KsWeDWQEylTMOL6WsKsKsTifMrs3WdALYVAjUrInsgDjHDTVJkWiEwPvo3oLBKFzQC4Bu+YMIP+7bV0RXn1jOX/jRfwA/9H/9RRT+qgDymfqHw8N/GPP4o/0akFd5yG+MWptzW3NkB5StbDaGQgdrmBe55nU9dAKR2MiXdcGqYMUkboVVvZJZz1+zgawey5OK2jSXDJi2H+Qzg0NTgvVcKgRCkbsehNPprJKvhkbi+bKh+6Vo67PUyUfG48dp3E0yNcw0nK6V4c3hnMV/2Uno0s/C0CgoxOAi8S3XRegZ8YtQsC5PaGoqMk8z5rlq3Nb+Glj8BaVXQPeCkoQTEFstQIJvnyYBMqbKeL1e3QWvA6/ecLvdBBCWqoBlddXNEP1PuC7yvtkuGKAzJycGKLPqjtVlKpasMY1clbIzli4qjVOdPPabqXcSyfOG5vZxYJVIVr3ce3HQVGoZbNPMzgcMNw8R1cc+EPNuf5dURQ3Mmjqbtckon9YalnXB+XJ2QGBtnMqs9kYCEqGSwVpUha2bap9eIQeqLB9LW7unT01G6H+pRAAxObHA4AhOeyRl8Tpo8zgRvP5zkI7q03y4HA0shPqtgRO4ytYnDYNRrAmI+mULwDnYCZgIAXWvdGvD+D1AxrZtMn60nedE+GK48BVkDRJvhGROGynr3F5hGDiLtsWz7o56AkRzGm9vaQJHFtlB/gbwMynewMHO+z/3M4/R7lNk2Y50Bhn++Wj90lF1tPvGOt6FaNwHd7dDXjTjUwAuFbPxPuqEt19/OwR9Q6n3W2ISBAM6vBuhg5TalJsXb+c+biTMMBs4jXMKhoaJHN9loDE7wzATysuqKtEkTIB5lnN+XZs7dzAtCbdPTTai3pKSwsQQK9OGnZlm55CfTZTXz2YQ/mam+2Ly73xVuAMcyf/nnz/tqtCNbt8ICuIUZEPPNSiaZrsPSM8rQu+E3lesK9S2VLWHqMreq/AY3RK+SJmeXeLVFZCaLCTGno5pTyFaLISCqM7LGfkD/9F/CCLCz//r/yYshtzpdEJrAoh6a+hNAnYTsgp/wWQ0AydNCKMRFNR9GcZAtjE1ZzHpx2D2EnlYh76u6MuC3iH2djPhqdwgTPZV7P7V07jty9f0MtIroHshaXWVyRNae8D1+oT3799jUlUoUaW84v379/ja176GAjggW9cFj4+PmKYJ59MJ59MZ3DvevXsnzlSmCefzGefzBY9PH/D4+B5A19AFBcwdHz48AuoY+HK54HSSQJjv38z42hdPIGaczjOWBVhuEpumFLnYl3WVUAmruhueT+6EBSyX+JuHN3IprXA1zXmeHURRIQEb2l9TEzVQCqhHSXWKUiehSFqTA76UivPp7IG+oeCt1orTfAI/2AEvMWCMC9hbx8I3CWCul0JfBdCVE+F8Pis4XqQeAqZa0Ul5kuY637ihwit1EOMqlhvDuFEvXxpsF+r9JJftx9M+j5NCCaibNOIIsMVLm+tvS9R7twiu/sjhREEwRwAPuVaVZEtByYWxMAILVoLvcCQ4wkw4kCMaYrHFcGQGhanQQtuZgFaWzG2ScdVzXQYssizSAboBBMADfDOLbienaXDJhKmpJfxil30acp8zIuNMaxnMgNPOGawFdhIpf9hywJgnumd+7+/5nfiZH/l78fv/4H+pasUOB53IjvEIUHMke7srkdM58FEd8drwMWpGdCL/2XH6UwEODh22jXWltW2uxbsRgHYmGeODlQAVyjgIYBrH4x4Yk6o2jAbfebJvhhKON9wwMD6n/th+TPajCYXqETOAh947yG2x5Wl1Ff9ggjQFbZl5dpon1Drp2JiLeNkX1RlojHVZxP292loLw67CJYK6ZmutoC6BrdGh3gy3ZxMF0HsmjXOxX4VZ1ZDAqt4rZ6utkR/5838Ov+L//AvP1vNsytNGGZzS0DSTCsf6Sm08ZBDml9NZiewURdeptyMBfRiAl7OPSGO75XtBpWV9XcU8gm7KfFXNmDqhdPFGWVg8c3cyNUtVf5y1YVWCjstxK+fUD/++34uf/ol/R8eDfT9avLn5r/wVEAhtZQmTVCY8PLxFrTOm6YzL6YLl8oBf+sW/4eEClHMHBiFiNNo8A72p6vvdQGCRP492Uwkzc3VHQKWI1K13kcZxB0qZMJWCUibg+oRl7bg+3XC+XHA6nXCaFyyTOIw7nc4AMUqBBCR/Vbl8Mek1Dt0LSb0ZB7RokG5gWRYHMwZ+DMCAI+6Pq16awfIQqyoI31rl4jXvSn6gc8fv+GP/M37bH/2fVA0AmCZx/ftnfsOvweffeIeHX/jCJYAAPOyB2P0pjGHxYGZc2oFDRuEmG1DClCPgrIM6lfgVKhJSwEIftO7EXefuYR7cto7N2Fi8ZIl3P3bj/NPppOoPYThtY9Q7e79L4uARIMHZa9l4JAxAZmQfBf3jyUoxiU4GcPZvCEoeL33nEg8wciAYBHzhGEQaUOERfKaf/XcjGjh9BkZgZcDCVduy9A4BhHyctjdr/mdN5qgnPI5lginVZX20Gz5JLHoPiRXAw/x4ZRswF2QVe3nbsfO+WhlGa1E0ZXiJ9mMRoCPGpmxB9lAWjw9p85mgIFEIZiJjothY9aNC95MwSF+3fdquJ/ZxyiDM3oX9ze3dJYUthyjxAPTkfAfljsUEAApMf7AGnSAegeWXSd4UCsB47GghGm3Ly9gvx3vWM409NBDhG38E2nYGeewuO6PzHtI2ulouM5Z19fspO9DyGJ+mql/IVd1CdR2xj3QtGxjcruw4Q79DaZi6NJ72XT//uj/x3+K3/OR/9uWnOJ9Rvu6P8+V1NPCSmMf3N+22LDvpeC7Etql+5m3ufN7Bbql0N1l5HF5L7Q40pmhXWsRjzw3/dL+7519GLxXf/PX/CL72v/2vsg60CbHaaRy/NC6lSJze8+mMy8MDHt68xel0xjTPwiAAXCWza/0iBS8RWog0vND2okZqA43/4g6xtuR9qc+7hS+aUKcZtYrnbWlLSO8kVq8y6fQMfobt9Zq+C9OrhO6FJHP5DMDF+os6NjGVyWLgBUEE2G8AHCDd86Znl7KBP1M/dJseBYyWr5SClRkf3ojEr5aKVpsShaxSrILaRXUSLNz/eqkinYOAL2oHhAvLb+hxMRU9cFuXmHV1qiKhY+HwVhbX6iahq5Wwrna4dhBNGvjcAoWvaE1s7E4nOUzlkG0IVTNWINowTRQErt6J01TRm3n66mB3Dx+nvnG4g+wQAln6bJejcg3Jft9SsF/2YLcL60u8osSdjbcTAKQM3W1hDDwjIgNAIaVgkzRIgSY0yoDb7RWMiwwkcJTGg3DIhc/Eja1RhnJNbW2pZCl7WmWStV1L8T7GJd1dquXDkcbBgIipbY72E5zy2XcO4pvThW0gjTf5E4Fd0v5gG6fWhnlhLcvfz4jI/t0B6BlM5u8EQocQGT1Q+fjuphxA11JyjS576bjqw+WdQLIR+mNVd4jhTcPGOlMDx6ruJ1JAizt9p93HbzPR8GkLrI5w6X7sTS66Sd44+0BpfG3e9R7QdWd2wlUDNzMJee/hB0yKS+TMMILcVW1dsbTFAZypyBcirEU8q04aVzUzVtiYYgjmBLsLfFPR3xxF2gmR5nyVGdCx2U1kls4FKBIp2Tbvp9Z0vHC3EsacLz6Hxod0mQPsfEqDjrL4fh/X4AjiLA5dAPoB4EDBSCcwNfecS12dtxSAULSNdv6yn2XMjPbmDYyZxhQ0SrZR8yandSPqlBPoJF56p6nifHnAcrsCMCdyovqZ6QyjkfxeL8fzcpSCp7E/F/yJHlFERfZSmTDVCbVK/F8BtuTeu7Mnbdcw+Y5xK17T/9/TK6B7Iam5XRypJC1in2Qd7VorltsN0/ns9mGlpNAGraNM8b4F0TZpXI6DZSqJ4bkJDvbmedZ4KosTtXYhFCpo3DzcgHurbE2cjbA8L1Q04HQ4SPFYcujhNCVdNC6xI7G7Mxs7B34E192Xw7oA2hcj9KdJ4tK1FUJAFAsMXkVdUsMauESHSQOfi7SxFgOEDYTJiXFxl8yutmHvS782sMQJ/wB2xuGz+1L+BdG/JfIixUV/L0dcCiHxM9wkxEB6j4CtC/qhLKS4WZRCMhzdPImQzP2zV0ZVRivGAHA03sfP390T89rsxE027n44WgkCdgtOR0JNaI2QUiaImYihNO4U83ZcbrzS1YYw+hAO+B1/aV+YIQR2GRkF5lzAQOu2HgNCI0DlyJfnbbdkZB8VMjfy8uw//73/Pr71tV8W7csvZ5omEZsZH0bDMM75wZId52cbJuIOkOPt+NPwroPDg1ePUqZ7XQrm63VfyqfQXTugZmtnU8BhG4+2t625j9Hxef8Pa9hOITtj4hzPk0oEUCloJkFLb/sZjXCi011tV0s3KQyA0gEuHczqtIdChTUAQ4C5wqxu3K1Nej5sB+2Z8283DIfvfDrl/M1f/nfjr/3wj+AHfvovDc8dTqcid8/uJANznLk6nN7fvwBT8R0YZ7YRzDulnfHITdB5HWIgHi8iuW9tHaTx4g6YVMvyqjomAyh6dpZCEp2iQ83yUpzNfEKkbeVnFe17Tv43/6aBulW9t04Fb9++xVMlMDQmqRTsZQ770O56/cWZbUdLQ89s9s+UjlWTUkM0h/oovaulok4z5vmk5iLiiI1IvIpfN+GojMH+ml5GegV0LyQtbsMVUrfT6RQXZe+opeByueD94yOmUnBShyamLmMhDGqdQ8Km9l8SUyZUNA0Aigvd2SV6y7Lgdrvh7du3qLXi8fFRLmJVnwDgErDWBbyVUnA6n/D09IT1JsbKILjksHVxPDJPswMrXsXbpdVNEG+ZFvPIjOfNo6U/p3C4UtUImgDcbt1B61Qrem1OqNqJW0vB6XTC9fokg65us7lUBXQNNAWgW5cVrU4AdwWnXUGeusc3uxGo+iYLZ9IIGLvEjDDOF5U8uU8B3BO0AAPNjgwStsTP+DwHaCYhFAZurSENSnmQLrVtFVvAtAEAAMygPPpEfokNOVkczdgla4S153D61AhjEicjBugMCKVkDkMSpgrCmAE24x3mKJnir6FhIlLO86bL0bSMb5IUAgOxwjb/xjnWZ+JgCG7HxgDcOwqRuwb30dD2RpiOLhIVI2hyE71/5EDYiPCQBsbk/dyv/NV4fPMm5mucTQw/ABjdkDql5u0cls0GdAk9SuHCPGitDQOAxo+5GbtJ2TSVNiQsxzyQzjEbHBIjrgAAIABJREFUeIYSqyQxrDqzxGKjPPemvHgMDIanHA4YnJCMI0Hqzt08wLC25n1sMJ4JeSxtQBzjO1dHyvXg4RoLrhRRZW+tifR6mrxvzvSzsfTzRiUepQDznKQMNdY1WfnkAcetTJPMgTt6ETf3tkYlbMyq5cHXphwD41m1G5/nkBTdn6/n0k/9zn8Rf/bH/0n8xL/0L+x+C3AcCyyDsrzy4xy1EAIJzB3l3dWl/2fLwWqLFr+OAH7z8u55Bo8BWkQ10F4gkAYhILMbhdwg7liHGYLiGNyV6VQY3BilysSZNIq7HKDZTg9KTxSN9eNL3Blzss6ymYZL3QpQUfD1r38dpYhGz7o2LEsDkhdl1n3c1HtrVWY09DlMvVzXiGFZi5XbmMEQ224jI8x+jllMN3oztf2O3gEqRVVDO56errgtC6brVcIXnE7gx/eusjpN4qdgXZeDyXtN343pFdC9kNRVBVKkROKpck6XJiBA6nQ64Rd+4RcwEbljlFmdkLQmuuwPD2fMpxPmecb79+9BRLhcbphPM+ZZgCIgXjRNncFs1QABdUAEMAdCcmfPGYy+qKpinRyAguX9eZ49iLccuKvUpfFppmmKWHedB/un3jva2nDDDSCxH1yw+IVfi6j2mLWPSOUmbZ9cSqUQLpczbrcVrCEgaqk4zbPX2ZX45t6EudiaxkUSjty6rvjw9AQCMM0S82y5ruqpasLpJP2ep+JEIiHUjIwaGqRn24nnLbCLyzYkbeNbI22zVReK9+XPluA5Jm52d7/hO95WuP/sklOn6bMEzGcpAdAtKWYS1swVVdUZI9sSDcOQ9VJRAiAq9ee0vBO62ROiwiiTynn7yOsKKdkINLwfuQ5vWBCcVo6HsHDAeDTowSUWz7D78g34yFwkJJ8IFpPC+6wY0DUmg37vLOcM5bJ7l+e9jcSloxgdK58s+6KANEm0OA2ZUUdGqhkkFVCnYNne07doB+ZSeQdf8kqn4Uv+mH7wPoyzEesKfjZw0XYdAInDlOq1OZMzYWQ2xCrcMlzGfm9BZPTzQDXY6XnW8nkYlAHfcUgnjOlX9S+pRoftA9a9lsPX2G+m9pZVhHtrHtA5E8dAxA5FJ6xrd1f6VaXrRrzHOXHs+9NHyQbo+OjcPXou+Zjdy32EF+9mvQ8ufaVnYPcpjfM6FTYqZ2QogVVt0ZgT1sY0gFFvejMOKsnENp9yh4nQjeERB1uc41wquDdUAqhWoAuw72D0NgFUVD1TGFO1VoDlnOnrIloJUKcpxokw6Rcx2NYTM6hGgHoLM0NU8PbtZ7hcLvjw9gkfPnzAN7/5DbHr1NBFxthb1xWdxLM3+QgZA8SYB6oWqozxtXUBj1NBEw8oYAZutwXX64Jl0Xh4XNAbo7WOZVnBAGpVMxil36ZpEqYJkWg9sflAKDidZ7yml5FeAd0LSWLftbqTDA8cvoRqi9sNMWNZFjw9PeHNmzeuRthaE+4pR5gBeS4G7AawRMJm8dbkDC1U0Klr+WN8N2kfUhBvuYBbEWchXDoADZlwmvH0dIVxLKmSurcWj1mderSDpN1GGBqnDBCpHi9KuKdwBOu6gmZrU3fiptai8eZCkiceQJuqSnbn9k21opEc0B0JgKgKhamfMAPrIgHJTTXVCJypFh+LUipgdnn2opSQZnivdiU5ePib89v76Z5OBYz5A1PwBgCOhMpQz11iYUstbKr2RkXPduUaoNXq7xFWRvxaLJ6hSRsgqXAsykpSASFwQtribbRyHGw6lME2a/6XqXOCa/lG+w4IJwdKIVrYddbypAZ5yTaOMfMjwB2WgIM5DQXCSQKof0saAxCBenIG5GO2V4ndJgOdrqI0GAJae8j3TUy7zY2OP+eXbCDGlRGzk6DM0ZJPxOoWDuX3efP0UJqRvt8dinv0/hZxHH0dwJ7O8Q6t7AunzQcRiGbmzXFdrJkpLZgM6iyfEbNORKu0LANOAsClDMt5p85s4LUUFAsLA/bzmrudBfLX7MC3e91t6uw8xn5uhzH9W5DiONSz+GgRGBY6aJRJ5vTl5+saN9SmeBrWEW+zKiAZJKtAeNj0z5tKU1WMuGv8rOXugiwGwNR9vdqJLVorEFMEKijUBwYAo0g5HKqLwkRVYFYYxMUIEXzrH/qHAZW8ERiFuwC/QnrGS186E+o0Y5pngMQL57svvlAG1bIbbtGI6OleiHWnR6oCMHH20lpDweSqpaYptS6mSil3rTDhWaV2DaKWWW3X7RgwnTvWtmJtK0qZMM+vgO6lpFdA90KSATrjfJoq5Hq7OueISkFFeMB8goQzMO9J67piqSUBL+FqmS3cfJoxnydMU8W6dvWgKfYLYUBsAbubq3/KhSbeq0hjxxWuKG11KZuVU8oJHz48+SVjXjEBYG0rCOEqnSqh37rbHBXTbVPw2LljmqdQLTP7vmnWwxkw75alhKcrZtaQDBNKWcF9ResdrAbRdZrE2QQDMLUQhns8NON8QMYUGjPGbQ9bA7Nw+oy73PsKU9swznYQUQHm9pfMpyXniiYiLYC+lJTdbh+usecqNtCQbvQ98fIcRUJJerAh+DNlRvlBlNq4D08cHB90iFN8qlECspduxaAnRyLeqHEQ7IIvJV/C3qIYbydIN/1EzAUNgNGIQcdRQ81BvBoxbappFOPF42BauAVR+TEJSlpnShzHaMDdk4tzGOykqDFm6TXzVsdp7AZkqbUmZw0ZdJNvAj7wZzFCri04jio03w74PLd7jtaqtJNSzTYfee0cQPH92BzVcqga6JS1z6WvVgVShExsb1ZHLs/jtkXNW5AmTmqCKWDnmNv+JHvpsemsdsqbtWMSHC5xRuhakHumgNBjvxYSVVVdW8uyuFdmJ6AzuPNumjpdcccpafSG8f6bheXy9OVVecfCbfMyPgrYvq02bVvB7BJ7V+MkttXsZ5RjSLO/G9Dztt0MoKgEz0AdA9R9HgvZlBG6xTJVplLTu9TCArB6xgQBXAwsFfU8KXPbW0NhVkc8jKJtQCf8/G//Z4RJ0FZpUymoxnCk4urjIEKZhJ6hUlGmCZeHi3q5NG0d7TLRcIbbGRmATs+5zuDW0fqKtnYdA9NEgMTcXSSUknjezqEMSJyw1aI0VTh9AcjV3IXx3NDWCX0qOJ1eAd1LSa+A7oWkzozb7Ta4kJ7nGVd3rd8dYJ1OJ3ByGz3VAE1d1QtvyeiWmXG7LTidV5wuM6aporVVgRswzxP+j9/w90lZqgopwUIrTqeIFde5o6CgUEUtrK55V3FkomqT5vSEwUnKJx6gVkReBqPSGN7AqCYqBG5io2ceNMWDmgafBXYErru9JvjhC8DBICXvUrVWMBX0ws6htsvGPH9aLCWLS2XulwEMF6KBN29LBjQBKYKI2ko3tml4vqcQnOA4oh2HQu78yPnj/pZ31SMlDl3KYq/S7pWBwBdQN5JdWTXsuXSv1bnPuWoXtm3L5jwDgSZNOuMgO0nw5F/xdTS2P301MKcEqZN6dwhQIa4VSLh9B8LJj62XRKiNnYz6MiC12HbmRMjZ6rqejTjOrHxb1+LVUB0QNfk9pHbj4raivX4grWof2hgHIwZ14GxPdov5te1e4o4bWhkkpNYU7J/thmrIIvM+Aq77dO2XTfvWbZBAWjNsQG6rOq3/Y95C21x0Qreb9h9khjvQ8Jh5af+l8cgOgaSO0BWIXKT2SqTHlq09FicUemaS1aETuahGBKt9NQH63QhjA2y67tk8MKuEjmgzjN8ZpES7Dzg+dOwITHve3gtgBXdUsoN7H1lkh1oSw5Fz0CjaPHXgxg7EgPsSOmcY5HrsYMsSPKS7Re82+awStm5rRQ/fDo/raraiTAroigI5MKB2bCbu476CNZYbgZXZqqC0q9onEQjF1wehiMcdHQUJV6AgTb1IPrx5C7Ccc8u6oKm3bWE82HFr2gxpGuyMY1ODj/WZkwHY1jrMhGSaZm2HMIVrJdQqcRqhNIQx4GqtWNuC3iVO79xriv34mr7b0yugeyGJe1dAVzDP4r3yfD7jMdmwEVWUWiXIeO9o6sDEQJOBo9v15qor4ip3xbLcsCwnEL1x9UEAMF3uv/6jv1qCkF+vuN1ubtB8Pp+HssECuAqr3d3CqqrYUUm8RFoIg946uMoF6DHjeoo9pwBQpAwdTOyx7iyWjMW6qyoZpE7DQRwSmgi1IGqXQozWWkV9Qtsv4Qkm70PYWpl0LoVtoADT5tUtg7PsVjmI/HT/b+/kdIvsuKaflKLAvYv456Vz27SvOoCc3/zP4MKjljnRTSNPO2zmbNyeA6Mfr+mee/whOcGzUcM0OJLWjc93IeeqSoqAtVamz7MDuE1DMl7PElSK0ArSrjT/W/puOzgZ1GndHqzcJeTyHiG8VxpxHEQznDnCANCATuqRVm2cQkIRjTu090n8iVGjLNaNzzolWxUO4AAilzgFaN4Amywp2le/Hb5N2ixgxThfNd1buiPBPc4xwTwVDnD40xIPf+4fMF5xtCVod1uL8nQgXhFnFwCgUNqz5kU2fpa4nQbQQsXd7ohlEYJVvB9PSuha3LJVtCjAbkMJI9gpn9/W40+Qjn2Z9GxhW3V1HRe7I/xYfEZm922uLwMtzzTNgVTsIfg6y0Dd0MoowbMzyX42ToL9ks4je2R5rH1sqpSh/g4A3DoYDZ2gkryiQF/VZ9FB+swYYV0laKSeTZnYD5Pzz/6/ABFuP/QrpImFlNEKEBfva2gmWbliU1dJvFk/Pj7iqvSGayXYeanS8bi10j5Ie9b3mB1DzGhNNCPAwXgHSJgcq9AP4n9gAkGZwsoQjti5YgrT2uS02Gv67k+vgO6FpLU1vHv3Duu6oBTg4eEB5/MZ59MJt9sNHz58wOVyxlQLvu/7vg+/+I1v4ItvfQsfPnzA9XrF6XQSxyDrim9961t49w548+YNLpcLbrcbHh/f4/HxEZ997S2mqTpIEvXEyYGbecu83W6YpgmfffaZ6IhXAV6NGmqrAAHzNGOpC0zdEySXv9V5u92EHJwZ58s5XfYdy028Xk6zGArfbjeR8lUJAk5KQfTWsZDkPZ1OmOrkAMqkaAIUG06nOSRrreP69ITL5QF0OqGUgmURqeZpPqGAQKWiT7OCz6uAti42AwTgpI5puDVcbzcQGFOdMGtMwN5FF54WxlxIPDpaHMB0DxhBa9/tb6bnEz0LI4qfBz20+ZwBlJa7IS4GJvAdysPvuBxT7vD9fVM8XyLCDz0WHkg6zcul/5w499nBxMBa7QqwTa0HUJfa7CBIRT/aLvjfQhAvhEk65zYOvQMqrbWhberUJxPBZpNpDAEA6AZcgPDCqXG5BOSQSqlFCt66eKekTsPFbkPToV4XW9jKSbdSHyHcavNeWCwUifbfyjCCotRgehDgsRt/3Z/+H/DNv/P78Kf+id+qLGvpS91w/S2xluuAU596OA+bGxJJj0tyjHhkIwoDZOMesUxp2WwZJQnA7JuZfjnaEFpvrJnEfKB9S463JKVqxvUuW4ndqYxJibeJ0wDz0WB7b+I5DeMWrWNtD8PIeigToKEzQKWCCqP0yd8vtaq6ZLTbtBWIgdYVXOk8TJPFHjVmQ1enVYx5nkEQ51NtXR3M2V6cpkn3twWp7u4gotYphdpJc22MA9oAmq+ctOCExPMZ6WeSDi9tA85vivpYVdByjvKGxH7zijNPDPxkOIXByYo5s3m2MYnZkkHdIJxX4EjF7i6GBcR2oMMEQJ2KGSDTVdfbCmJG4QquBcYDM7v3dRVGNFNHQQWoopBI3H7lH/iPAQB/8d/9D0CF9R4hoCs4JFVnJLG9bj20FC6XC+Z5xuXNA84PF3z48Ihv/dIvYV0l/FJ1eqHHPBK5Z0tA7qIyzZgKwFVDQ6FClIklFdWUolrRO+N6XXFbbiDcMM1nnE4XPDw8YFkXrOuC6/UK5o7T6ZS0oxput+url8sXlF4B3QtJdomt64rb7RZOOJiH35al4M2bN5jnWZ1+yIX5cDm5vduy3MApnpxxTs2WzmzmLNBl7x2//M//P+i942d+zfdLrDtV5zQ7u4IIF7C2FbWIkbLHbNMDsfeOqU5YSA7Q3jpaaTjNJ0xz2Pq5+mNy1NK6eOoT1TCJbXftVzFOprHNRuCbrYcRq6jA1DuWznpwsr8ngLSE7YfWw5Vxo5ty0TqIIuhnKUUI6nURTnKtOn4I4Y1xM52zCSUGn0NlmXg94Pne/ZLJ1rHsQ4mgeyQcqsVeAe7jaaQT9vUHsHuG6MnwJw1PlnoO1QDhqCXlA1gkCTZuGxTr9m5ACHc2CHrbRHsn3LGLwx5QBCr3mTLgZsDFik2SMdK1N0jmlEi0/RL9vTMbBpgSQM1/re+FKACqD1xCQcOj4JS71JiAf+qP/hf4Kz/ya/Cnf9NvhQ/eALi8FG+bA9cMLinAkI/RIA1IG2e7ENJYbtO4C9I6GuY3zTvieaaldwNy/Mt98JZ/+BJbKA313dI/Xgb5GrR1d6+eeCOnBL3TmT2EWFAQB/UQGGOpknED1gimBWDxUPsw8CL1ruqsS9e+E7Smfh9tLUk6OLbaEOq3N24fS9vT7Df+kZ/Er/0zf0p/ZNVgNdXFcQ0c7dxQxcZeNfPemuH8J61Ye64S3gHQboaDN1+ySubR0AWm2dwlPiKc2sAQlcmC7KXVmSG9g0HoHt7Hyk5OpUxCpx6pSxcPl/Zv7JCZV5TQivA9rg7SSO3nlUHQ2gJmCS9wvjyglIKnx0e8X24CMusE4ZsZA8dAcJzFsgdEY6N7OJk4hz2m7TSL6QYzWlMarnant+Z5RueGtZHQXitwulzE5KVXZWbwaxy6F5ReAd0LSebeVgDdgmkSl/jZLfm6rlg16LiEK5gdeNkhQwA+KGjKgA6AAsLF7eLMvoyZ8ff8938eAPBX//4fRK0Vt9vNAR3b5c4RUoBmwkxzgMIWxME8zxrvJYAqFXIVidYlf+sNE0nw8NKLq4sIx7hgognLsmBZF9FVV1XUZh4ljdum4+fx7PSQtL6ZCkRrHVRWlQQCRAW1Kpwi864mTlHMVXcpBegdq/8GHefgRma+vhCyBjKeg18IrY9Enn6MufodSfco5u9g+RnUOfmxpTaeI2oTEAmicQsq2NfAUPxGOudzMOjbUbQTyZkA8wbQdQdgmcayegOssYOWrrHjBhBqY85wFeUM6O7NB2ub/O8W8FLEFfOxOKLc8niycdutCFu9CVRRlq7muUplO/HPY44M6PwtCsDAsc4z8N6Cut2wGPhHjGciOVUKlgHIx5ODn/RCYJYD1D+iJdy3iT2GWl8JjuT+2/dnC6T9QKb8Pa3DwqZOXlz4Qj3CsRg9bejYi9swWnonlciFR1VncqiU8NqWRMgmOOd7iaLSv1Vpcxx9z8//NXz/T//fzjAYA3T/zW3G3Ybp+O9sbb9i2gL+YDiM5yeg+zU5YdGHYO5AJ3R0EKmHyHS+FMiaMhVd83LJtQqYcw0N9i67LRthA+hE7XNdF0zTSSW+YuN3vV4d5F0uE07zjHe/9Iv44v0X0qZS3R7U7m2rN6vSy5otgHrWzHlKqWIjNzFABR2Mtna0XlF7xPid5xmLSt/EOybj8qagThUzTx47V5jmr+klpFdA90JS1qFf1wVPT8LVWZM9m6lCPn344BygHM/NgIvEmQu30eZKN6s85vqWZQm350iBw7U+40pRIbdrK60AExxg9d5BXVwNzxRhF0yqZ2o1ohbasLIAKzGyFm+YXNjrtXAFLi1sqwA/DzZqwW8T51YPf1MdtcDq4u1SVHqmOklMmSTRMGloJmKlHR21SB1F6+qqKmHOJWoiVowoDdXARKxo244osKAnAwjep2U+ncgJ1ZtMKOuYGZFyROndLzGBJgpi1t4PDDO004biS7R8+JbB3EDMbt4QddlgLBjYscjgu/hP+j1f1rb+TFp71HhrB+W5TnT9FlCYLYvZjnYeQ5E44Z1Bl/3tPYFTxPpS4sMZG6ZimQjhYXYSA8SCvZuqqS24n/2VP4yf+/4fSO0y8KelZQmb1mBAKuYlSVgy4UmG/2K8nB3inX1+hTihafUNlKa1MQ3VwRhE/hGkUp7AodDYkxi7M2bfbR9OeyTn3pDPn7ApsnR3l/Iep7H8nUTV123ZaX+IfXIBlcSeykO8WaK2zzKwE6ddEteOK7vrd2GMxPuFijrBkPA5YEbT4zGrp2/7GS37tNPq05OuxHx+MY6m6+PFAAFG8HEIPzC7vO54xxzqHJZ1tA++bGNdzJY6b01KjlTEy7Woj1MCdb4yGWA0UAeABqYFpTLUWheMAtDkWg+trSio6NzU1q5rzLo8GDz8Y3OsAlHBlPaYuqUdiexrSO50MSd5eHjAVc9GC0003gZewFBnN7BKAiLlXVJQJxJJ7h1E1WMIcxcHd/NcVWotXrBb684QZjbtqlD1fE3f/ekV0L2QJGoCIt63jX69XlEJvuElcHjDh6cnVMBd+oubdQFdKEW8YKKjt+4qmaUQWu9eNgC/1CVWUHeX1jncwe12gxBuwrFaIe56LRyB5e0sgC5zZutU0dbmEol5mkGVsE5rqGiyxIfLAGxtq0v/6qSgcO3gib3s4u6Qtxd9eAktpSpXTgyXS6mYJsbT9UkPffF4WVG9TLsUjINMKErLyiUS8f5yUFwCuAmAACkhdEANMBIIItgVLXSfXi56j91jUO+fRT13f0tgwMboHsHB2w8ZoGUshORmfbiEI6vRwGO7jqikkI66NAqJG+5Sp6Re6cUYKLN5U5sKtf/ppYiC0CBxSr3gpE6ZCFwZT46qhzHMYC5JADMBMlC/ARzNZmjLABgt8eLdPCaWv5hUGnAwFyEK0ihvpV8O4BoAUtUjIYw6d/zBf+v34cObt8M7wRQIYmkPuBNReU9C6H21d9Subxi7PEeU/j9UpqBE267r0EAl2x7j7TvD18A/m+RSgeFUiX5ucN2wl6IM+00a5g4nh3YwzBss+8aX7/n/2/r37U2f0hIdpK1AOM5IUuUO9S7cGkqroNJRuAb+c1Cf2mCMrc7OaGTYmTz5OQ5mrASPDZrHTRxSEYDi+9ZBS9pTx6P6nU3p9ISBOgD4X37Tb8bP//Cvxo//5B/yuGc0zN4zOOrLAsH8nn7wtXdU1oA8I5m2yidV5UXYzttI4vwQZz+7ZK5EEhYMyjijxN5ZCu8oEr9NWgboGSx25rIuYCEOzKY4o2k/dxKYA4l3YGVCiYrjhFq79yn6T66xcz6LPRtzx3K9qUOW1DToWck8rEW2vpHQUiCIV04Kb8Ea1UXvAwFwS1uwXBecL2+dUWzxgAFhIAOT2o13jdP4ml5CegV0LyaRB5hc1xXr8oTldsPlcnYJUm8NS+v4hb/xDXz++Wd4eLjgfDkB1NVeTFQsP/va5zjfzviFb34DH54eQSDUqaKzeNIUO7pJuEkMXK9XrGtDrRCpVBWu0rqKF83OEmOuTqKiuawLWmmiJ++qNhF9tLeGWgvOdMaVxeh3uS2YqgDQ03wCGLjerqK+OZHGsDNd8wV0AeZ5xjzNqKXiuootXe3iwcqkYmZ3N6kxvRHb4uiF8a1vvQORjK3Yvk14fOwArwADtYhDgGmavCyZDQXWTQBbrSHhbOuKyUMpECqJlHOu4SiAhgspEucKkO7qBAwMg1GiODOeCAIrl729+YMIPyKOSSnaRK/v8gS3tA+/BxEeRCsoPnP8su/7jhYR4rw1u5QDhAhYCdXGkP4kChnisEFUgUUabUbyRITKACpQehkbr2PaW0sBunnDMWW18awBjgxAJRDFSnBw14vfoB2PkMDCgZizCRC5M5PcdyiRm1dPBn+1VncG4AS0Lgy2jgmHSMexgChsPxaXmCgDCQ1t6V6vMTAM+NybT6kvUVFEg0dRxykc80wGIgGZwx6xI2OdbYFNAmEwTK3PYxmk8SZQWtu7MbTGiZcWBTy655SoN/oR+d3Np/tPbGxknUYUgdgbkkztNS1Mb+8nEHlpncT+F5UwB6zpULG1wVBPqAgYaQV27kALYN272LxJCcbIAGDxxFS9siuIMwaflVmLmAFYDFHzdJlDF/g6N7B+3NWP46SDIdu9w3lVjeOT01/+0X8Q3/zBH8KP/+E/pPO4LdBg0HG9x827k9HX8DEgc61eSnUeljO+nfcCeNMF3zNJIjpI9uNMImMqdUb3vSxSNWF46lrxO0WleV1UIdEbuE8yAl2c47TlCkIHTxO6MrQKA9Ag9rbEUKD1U9oiXa+cgtvtimUJT9+Xy8X7ua4iHb68/QyXt2/wxbsv8Nd//ufx4ekDCKzrX8azs8U/NOaeDHxDkfZRA2vQJCYCagFxBbpIolcAvQCYC5al4f2HR3z9ez5HnQrmuWJZ1FM5N0y1YKIZrVZQb6BXCd2LSa+A7oWkQhXrTY18qWAqMzABT49XORSmCbUWzHXCslxxvT6ZsADzacbt6QlrmzGfZvUSCXSIBKwqYCGV5L1//4jT6YLz+SyxUnCDBdS+Xm+Y50k9VSoHVeMO1XJBn0zVhnG9XnE+nzFPE+jhAcu6Yl2EqJY6C9pa0JuAw7ZOLr0iArh38epJwDSdNUwAg5vE0ivlCYB44ZuKhB9YrjeUs3iXchfDSvi31hW8Tu7tT9QbOm7p0J9PswLHG6gAMwGny8mOazXWN6co4nnLiE4hqEM908jQSR3SjCobmtINHJfplmw7uqYTGZldnjuoO77a828HApV9DRuAZQ8T3RyZOcBWtC3Xu0FsW48kxkVWwGrYY7TFkc9CHIY0hli9KuayOqMtAeR61yC36lmyUPgmGyRJmfhxEKk2kuZtkoBKW+mXjkviSoekUiUfSdoYfUrVAfGu/m4g0oGLSseoaBynontD22tcYi+Do23uzGLbbiPCCAKkIEQ19y5eP2kkF83WzlSUkObG+mW2MU5sJc79BuuNgjNO456IaodvGynNVrrqVdhm8N9FkuK7ZQvKhj2KAMEgHQNySS1/sjvxaKkkbZTQAAAgAElEQVQDau8XbTaR5soSZ2skw9XcYtyehTBRXso/YpRY+5ZLQFtDnWf5N00Qlfxx/nsXAtxcxgPkc8rmYdbWGbO6r8deysYQD4VZHdrOSM3gozGiL9nvd6R2nySPiitiYEuk0/SZl2O9Z2GTMA5oU8742nDq8fO1RFOPIWsGYF4mzDmLcQu2b8B5Fj4nuabd0MWZuu0VD/tL7m2HIBQxLF1+TaZ1oCCQhFHaSLWMwGjLAgKwlBtq68AM0CRnNulYtNZRNIh5aHBAmHyFoCZuoKraMhbzUPN2pQ9qFU/a50vDm8+/DpSKL96/Q1sXZcgWv7tZvbmCgFomEIuGTpnEE2dfV6ASwITGHbf1hscPH4BpQp1mFFSs3LH0FU/LDUyE+XzGvC4SsuO24HQ5o9SKpRS0DrTbq5fLl5JeAd0LSbUUtNWCh8sFW2nC++sXmJp4cap0Qp0Krq3hdltQCmm4ghmP7Qt1gc6YZuWGqboECChTQUERG7ynK4Di9QAECzIuTlNOOJ8vAIDbTdzt9lVUF6c6oU+ilnZbbjidT6iTqEb2x45rbyrBqq6WUMrqDlaMg1uUCGjriq7OXIiM3hJpyw0Sa6aq/ZvYBHbMqmo6qKKBXPJRrc9FYuWZZFLi+wnobU9N48BIntM8o7WK3it46U7sAqLyCVa1UhL9eedMMoOJMFUjuM1gfEz+hDZQjoDgGu9BUqSRmD5KBqjGu5tSnbk9+zaSEZ9bwv4AnG6Jf6nqgMByKmwkKGTN2edMcIRapbn6z6+5Mw8FasyJ+58kc1mNN5x+bFpA6Z+XCQdUAFwSNxKSVsid/nYMa2Nbd4CIaEuod8Y8b4G7gRpRCR3DHFglNoeZOB763U3yxcJd5hgzqzNAT4A6Jd13S5CcUg4AO4AvJhzHDdSzCaEKaJvZxsD7z0BPI+YrhTZqtDqGrK0dJKQ+Njo1DvwMzoX0l1nBDO4Qy1sKe/h5s1KG10O9zfuR1r3X9ylA5blkk5jp8gwIekcDYTI74DppTEMOwOZgXtWXi64aNgJfi+VYLu723Zhbumay46IAcgHAkUGbSasT6GCErWie74Sx9p3cjKFVkYfEAY/P0dGcJpXaDA5ZfD3mfD70Q9tiTA+beVAnHTzOvSY/0HUVk31OnbWPdrZZGWk9ypjYOG/XLUemVHfe49w7ejEYp/MDvdvtaOKO3hjGhOImmgAC6AilSNijQhVcKlAYf+lf/lfkFm3sDCKG2bNJ0yoIpcIdQlWNf2tL05hqAFA09MB8fsDbz1Z0AO/ef4FlFVXgqQKTqUZyUoGn6iBVQn1U8LrKJBdRWV5aw9NyxeWkjJFCmHpDXWbc1hVTIcynGdN1wlIK1mUFnc+YqWKiigoCL69eLl9KegV0LySZgwJmlTgoMJIfg8BkhtqDFZds2EVnnjB7bxqke3L7OQuaXOvs7vzDXS5ZJbDj3i565ic/JD2gOBV0ND803eNfjTh2ZrtmfTPbJHtutnrGsTV7jEyAZ918s/cz7rmVa/my3dOyLE6c1VqxrgLeROWsa7yjgrWIo4rWVpxOJ+1zgQx72F0JOattyYQI7tJMQ557z8aAzN9usgv2yxGC29xbYn2wYdu8c0iP8LZMzbklZnBEQGAg+CQGEsJFePolE5QNFugWvkbsswVwzcTkkcTM3nOJ6y4PJyciqRdK9BuBarZXrM5UWF8gzdxZHeooZVn0d5aCdm0dxhDwfTCopOaZOADYu2R7J0mQJB5jkLN5FmypZxu/HWDx9QefmyPgZwvBdw/vFkYiNpNUFjw6XUHCKybo8ecby9UNAQ/sm7Uf7WDJbGhZz5EB7yH1ve951GcNMoTh+yTOlY/uYp+kvCPzPCRnNQl8uo0T4mzNZyoDwLJ4K8LWk0EUHi9NNXkAd0psd41TRhCphzhJCbX1tlbcbqEFsT8f7o/dVwa6Q/q0UzeDRv7IX8uf+Vq78/JL1PmxVkpdd+R6m30aVnnaYjKAHoBw7EWqnfOq1F3i4MomkP3M83uSVGfSfmVRxwRYNWA6zLEKs6irF+p4/P7vl6e9g1HUcRp5oHIBj8awU9XhxJAihH8AeShM61InnB8esPaO8+UBvbGr3DMkri5Ns3s4bm0Fqy0/gVQ7hOy0B6mfgPl8BlVxGgc9g1pX0xWz99f2teTDYCoT5vpK4r+k9DrbLygZwPEQBeuSvDoakcEK6IJALXo4r2sT1cYuQHCaKnqreqCo6uI0KbDqCfgAf/yf//UimWMhYCeND2eqht2Am6o7gMidnWSX6QKIVgnIvQFj1i8LpbAFdA4MzdFKlrgkr2wZ6GUwa59NEjhN0xBrT+yXqgNis4uzd2sV+7ybEdVkF5FebRviw2myI7LxSFqV3/1qS2UsKwGkrSTk7kVPG/L/AEccS/HS3wRIBzw5EDQbkiwTxsNzAyo00BW8pY42kiNjahRTSeTwcnpPXS1LpOLiT2DR+khi2+dqigPkgdc/ADo2+wsDQhoY3MCiEttm38Y6KORMl2DcDOOSwJyvuy2IcxC0G15/jz38QpQbQqLUPx3rAFjkwCDG6BPAR+qLjTE4231hs13263J0pmpQ1iQnsT8TdtEuZhmcPU3AMD92OAeQB0g+fO0AoG1J8O2oxMERTJwRfHoT0twA41rdtT6/7AWHVCNLF7NUME1H7Cldn6vtBcDXayFoIGZByKx2Qz6vaZ2bpBngYR86gwVAW0XjpFM4tdmlA6D38bV2DIXy6H0quBrrCkBk0521HXODCZSejeM9rLc7XIYsMd41hsY8tuAPA60HZkPo8Eqj5ZFfXtp2c96TntvZRtY9a3g4R+K0XnI1mUEhyyG0AZjFKUrtVX9XaV9raFTgmiIoYDRwl6D3dnbYCWDaEzG/qb589hOhQ4KBny8P6Aw8PLxBWzuW21WBG6lfAVLvrCvWZQFViWnH0D0AOD0EIpRpwnw+iUo8EcidxMX56vQRzC5fzuCpVMx1/tKA/zX97ZteAd0LScyMy+WC3hpueAJzQe8SRJxImUxdpE9ff/vWnZuczydwLWit48OHD+jqGGU+TTidz+rtT+oQL48FT09PuF6veHx89Hh3ADzgNzPj7ds3Ku0SA/a2avw2kLj+V87WclvlcD2J+s7pdMKH909Y19UvcSv/piEYAAyB0S0Oi8XWs7ZY4NDT6YTT6SQOSZJqnREMFjB9noW7Jk5fBJCeTif0LiqXFsbhfD7jdJq1TVf3/CnxbNjzEuAqRaJGIh4Ti+nwO5hLhLl+G+7skXJMk779mm7uT6GU/UKlgWjOlZqk7YjMHADBln7gfR7O+baAcFNIjEoGQKmODfLMqlZD3RsJnRWbJbUmfRbgkevizV/l4CaJhQHB/I5J5OyZrDXy8q2scObBqW1jKAGAgdZgKI9K1SDgUlBTiVmhot7PAjQJcTzGqtPqhDusnmZtsAaybvho/Rtjz9Hh3Fje4EI7yN6uVx7XuGCI/argVHf0hdMaCuBhGCNiRcXz7X7K/cnND+YC+77UTvsARp8oj5DTooMEK5Wf22H9pe3DA2J8WNecxivNd+7xQFfn9mslQYqHFNOr5O35Q2pWSUkFOFR8ZW2rZ0oLM+DMg461N5U8ywLkwZ54Esc+pprMERoHMFtWcq/Etldi7ymh21ZxDrFbP4ae0iTsc+xf85F6PgVEMTiff0sSe3DYa/rv+/OO+ADfbxpxD1bm1wbGUt4cm6K3/RjKY2FOsI+frMG0PWJLFD4cX2ZsAKN8MjtIIkZrMr8SmkBaIQzgAipd9khXZvW6gLnj/eM7CUU0VUzcQWtDqSum3vCrfuqnwCD87G/+LShdQh2UOiNE84BI/mqcvw1Ah2oblGF/9SY2/7VWXC4XnM8noDe8ffMO7794h/fvv0BfFyzLimky790VU2VwnQAQltuCtTOoFKxrx7J2tA6UOuPNw4zHpyvA5DSJ0CUdPBGoTJjmM+bzgqf37/F0vWGuoqJ5ulxQpvlwPbym7770CuheUDqfzwCzqqfIJWnudltf0fqC1lZIXBMxGm7qUVJc6jesy4pFwZSVIVIoxjzDn2cglfPJM8Y8T4k7TO4J0OLR2aGVAyQLUTq5NCFL7wx4Wf78m0nJDACaVC2rwJmHvm1A5qymloGelVt0LKdJ2mXqQkTFAWXT8A7iOEbtSpoQMWKPpZJDAIWifFKw44QOoAQ98Dz18ZFHfHQ9b3OaRCk//yQU6JfuaGeVoehHXj8qK1/6ZNza++TUhjYaSt/SxEcNEB8dkml0nrIhxg0BweISlVDnI2vH0dipSpFKnfcpbBVdOVWpcLYOIhWbALCBKef6J+nX0fi4dC4oTxmDkuuIzwEKRpAgYzDWwz5ewL/6+/9t/NUf+lX4Az/x78E4/46uONoT5R6nAZzfy+hS8ISEeE9Ub9tqRPOIqjarn8c+RwE8AM5P2THMApZkm8WsGRYkLfO55Wpb1IFqmjaKHGl8x78A0pli+yMvkNyRXeEIlByPOmO/NwCPNSqgUCa9N8LSF/do6Wq1IFgIDEAce0HLNbW1dZU1LkwMab3NcdhKMqib7ZL2zfs09se308EY358DPsi3LymX8T0/93P4vp/9mdijwEaqJWssGE5pr6X14EyPT0WWXybdQ7EfqcfgviwhU+UO0Eppf8cpZfuV0/qUkRFbywIicw0rNvkAi+tHIlGft1AXYHHqBmC5ngEGSpVWlVLwvX/uzwFE+Jkf+zF5txdpFxlgLLKGjElke4MYpuorm1PVIzujI1TWiQrePDwos1bW6vXDI65Pj1jXxZ2w1Tqhl4K1M9bWsbaOaS6jN2QSJl3jjsJFbPv03XW9obWOrlK+eT7hivdYl4brsuBMs6ttvqaXkV4B3QtJ7nKX1JW+iu7P5zPWtoKXjgbsQgW0ZuCI0JqCvLWhzRIrzmKxmc3DNFUHTnIwybH9G//E/w5mxp/4jb8Wy2JeJosbuLPHZTMjZPMgmdTJSKR3WcUyVDGrA64MvLwMPSCzigIQxGNWx9w6wHD99KQ6aeNTK7ukzt5b1cGL2cy1VkaHLQp6Gze5nkgIEjYD8JLsnYxDyEaoHNg0JNrho3DpEzFZZB7BXNAcW4KF9n82YO5jibafnyMojCZLBE/QoAoC0+ujeuSmXKcljCLNRBM5SAtwO4K6PBaDiuHdfodkT2hOseMItUrLBQU++n0c4qjfQX6AGJfpKQEVfbF3ldB1IoSs20IU+/qTYgdwzKn/8WAEgTaM3g/GD/7MT2Opk48tk6k57YfKh5pi/cj0hDoWjNmRUuwZbEBdIpQzkAHub4kkHTOC20FfbnYGmNv2WLsPK0l7SzOJfSdHGAIyEHowQA4E2cdrUMfbfN8XYC20fU0HOXLDt78bALRPGTjy7iwWUFeGdStqmM0ZFub91+T+EjtMbbGLretok0lyOoDSRTJd0x7008mfHQ/IdoSP8M/4LOBIGkV/dn/nS/rH/8gfxo/+yf9uKHdwKunzu19PYJOYmmYEa8gKKyfbJz+7CDTHfnFmFdpt2/el8VCN7wZdU2YnaWAupM4ZzlpRci5JN/PfGGeRbBoTLNnRWcw5Ziy3KwqROF0jYGJGJWPOSXt7XwECuoJCOQ8LuDcwVzALM8H3hs3NcMZb0xTYNbGhP81n0BuAWcMvccf16YMwtJlBFajTDGYo47wnGzoKZqrWZyPADJCCt9vtiqbmJEKDnAX89Y7bsqhJSEF9ldC9mPQK6F5IqrXg4UFc99cSgM3c7q/Kxc/0CDMcCFVVgwTg8X62TkqsvHk6YamLuggWl7/f84sfwOrFUQKKr5hnVcdUAq2tTbwHagy2eZqxLOKlqreOUqrXubNNU9u9bIRv0sLsFAUI8JYdVRiYy4E6rQzLa2qe0zR5/a1Jn0xl83ZbsK4L5vmEaZK8vXWsBmD1H0+TBEU3hKQ3epbYHSW9B+9jBc/0aSDqbhGJNjW1y4+lIyJ3D+a2F/gnFZ0yWxkjaDNgdww2g7CIp6oSeIDziAko0ODEGaSZ1DKDOS2LTDVzQ/RyvBfvx2dbWx2rqliGv0UPZ2CEKCvxpqCla9BYJ391HVkbraBsn5bg4J4wKUDpEM9yFKqQBhqs/iAu2P8CKtlSgim/G2Cyx/gMRF0QtN5my2N9N2JX+2n7IIMOw3Jjf63uGBufGxuH3bMYfx5+CZusYdn6kJonSY45S2Au74shMSIGWJLShKzuOPG9L7ZvD8Bgls7FXqF4j9LnHT7dbFZbxwasU5lydzSVurVwMFGM+FbVyt7RltBG8OpV6sEt9lutOkZkcTsV0Nim2k2MrldXcd7s94Px3NoUworjyBPFbFdHPMvfxyY91wC7BxD7zt5Kczq2OEBOyCblpx1+/VJn7aZpHCBVZ0GfpwYyhjaYh8sAddiplSL1IJeT97WcLwbcbJHx+K4yAToz5mUFnj5grQW35Um9cQNwT5WyuI153fsKFAKhg7ii9yJgrpMDZ+89F3iIHw7oToq2emsgsHsI7/0NrITH919oLFN12EMFjQpa1/uBTcOjAGSq+uT/WM+/WitO5wvevXsnzGMsmGrFfDoJHcTCMF/nk9j6z6+A7qWkV0D3QtI0VYkLV9SWYVnx9PSEIIYSV16/lxLqitNU0ZoYGYsKYcPpNPkFbc9MSldKDSLauUzkYMkcpkxTce7Xuq6hIkCiqrksi8epm4jcFsgcoBgIC/XGAHVmX2e2bUfgDQiCAYADuuZESDhkMQCZVUG3wFFCKDRMUwcgTlPqNOG2PKkEMtQ77W7Lkh5TE8qJGXEJHl7Iw9Ufj3ZcxHvv5HdHyjDu3kS88AYIbGvfgrmjdgyESwJG9v69Cu4QJTl7gDva5NmCmiPACedwj/mNuDiqkw7nLRp8P1nfe5cg9k58EsS+zMZiAI+m6hPkIpXcBgu9AJiK0LZlrgY1/EBAYRTe8M0dyBmQxfg3gRhX3dQ6bCUAwH/9u343vvG9f4f/JusrqcgdENwDOPOfyds0jvEomRlCOqTPDCM+gdzTYeXbNChhLdIyHjPtEZ2XQvZuKsdHIwEGxpbgV+I82SWxAcPIkDOPH1NhI15LM+qSD9zBOBmKWJ+fA0MhcQNnlTkO2zjYHVN8vTA4Mdv0ztHfG6XA4Gxqd7IWzImXrS9hbPToHvI8hXbH0OJntuW9o/PLYiPPw0jSq3GtMY6POtlGI2AEFO8YMwQYpHlH9eviHcod08EJ6MuZHYDx5g1hLG3Luw/UstolQO5hmB152huc3rMzxiKAm8plfmW8UN69fcCHyxm/44//N/hjv/O3Y1mu+rNp4IRGAnMDs6pcdoLq7IK5yDOuafwKROWSvW1x3qSzRWPomd3n+XxS+07G+3fvhIGxrhIsfF3RSwErkBPbeaGdaumitqwHSVF1UGZRrzydzjAtqMXCOM0zptMJ63LD0prE9u0TSnlVuXwp6RXQvZB0Pp/x5s2Dg6zr9QOALsGvVcJEAKoCrmmqIBKHH9drx9s3ZwDAui54ehJwMtXPQVQBFCzLit4fMdXZvTwCEnduXcSWjiAA6+npCY+Pj2it4e3bN36lXG83MXZG2N1JnWKPxychtLNzEgNcp9PJHZ4YCAUwSNMCnArQOp/P0j51jmLArNaK2+0GIGwCDRiaNBKASycNONYqHi5vt0esa0OtDbVOuFwqnp6uEiaC2R22lCIB0TtpAFMdo0zDOqGUOIE7BiUsL9LlTTti72MEyJiCYN9WdIi1jGC9I4EYswbFORBfSeVsg9DkCmX7HRsqxgjl3L7c3k2blEA1qc3HVEKP7eUUPClRmaV4uRpvoRI/hrlsbIUpwFhWYVxYLEIjbrdNt7qAglJM9cg8WEqO3lVQBsBt+vhAVdfKMrDD0VewMGkc7CS7J6fde/f5c8nV2sIGVsfYmM1/9h/9x/D48DbBH4dXQ7vyfGWgbKSwtyMBqIHQS0ypPG7P0PA78DqOeMqRKNgtaWlPQxVRa81rxPulZeU4dBzqaA4e0zsjjmOXWD7fOz1VDEQOUlXbs4h/iP7LHI9qcTK+JTdZ/nYLJxAkr40AEPO4rquo7LcVTc/1ti6iKlkLpqm6+r2oU+oeU4IXNJZJtYK6eBk0V/Xm+6SQ9V1AQQaYYaeZiHEbcgdgqc/5GyuY2awAHnLZ2h5PF5ul/+rf+An81O/+PfjXftc/588p/b03n0d7eAfc9A8BSepN+xc1c+wgXwDx1MCc/SWZYRmv6LlpcSSfIUOfHATtEOjY6+FOYJlI7qSqA6SSNNMCSMvWzvFK+MVf9jnePj6B24rb0we0ZcG6LFhPN7T1IiqVRGjLFdS7xKAksdGXemTg+kriLZgKSrU1Jc11JzaAe56UYTLTEQZQMU0zzucL3lweMNeKd+++hS+++AJfvHuHp+tNHKHUinmqHotuPgFUK2rrolLJHafTRZnYDVOtePNwweXygOV2w+224Hw6o04z3n72Ob549y3cbldc1wVUC0CvgO6lpFdA90JSONlQ8JCIHXdwQqSALkDK09OTSp4ePIaaeBlrWNsbJ0pba2hrw/V6dRAFwA8hoWvMdW9xz48OGJI0cF0bQGIvRySx3Lo6aGk9nJsAQYBmCePWMQqAQapm302N0tpvkrN7kjtT9cxeLpsa8RuX2domBvsNp1MRg+VpQuvdY9IYgFxpsRlKRJ/9JymU6uJq9Nn78kjtSyTefL5fUVyq+ze/M01JhAUhnAUcNul5e5m70j99xTjHo3OOoJISCThMxP0+p7aqtMEIy66Xtu8FtjqM0FYimazGLDUdJaUhDVKqKnXVVZ5Sq5wQTN+NTOpgcI+AtCYNZH3JmhpFZDf/pIwZdrrMJXr2zKVEHCN3gEuGsXdCk5JkcJ//aHZ97SQMOJRtv+ugUeqrqXi6ZMsL2BKn2o20D0w91va11TwySz6hD+mhzVsGHZkopy1CAxLdTPuJ9wx7on84cTb48xgkpJZQlhwDYBbCelmxtgVtFdBWSNTyTdWcS9h2Muey1DbbGSyASKP368BbSACooK8RjibW4mZMkR6kh2OYgH1FPjVpPi0cilvU8fPHTq7awPC+lm3m8Vnmg3GaM8n+1S6KKMYPKP8lus2D9NA7bZuOkssfhmpCwBfVFsgGIEyOinzxpzPD/mTxPPQUaw2N4XE6qUQsw95WCW3RC2A2eUx6YClNAAAVAJc0enGW2Rmc6ZFoRPSlThWfffaZxk00B0GP6E9NvFtPM6hUrOpQrVY9W3oHt1Xj+3a0ZVWzmYLz+Yy+rlg51nadZ5SpgtaCDqAxe4iD1/Tdn14B3YtJAXygF63bqs0zTqcZC5EY796ePE4cM2NdA3T0Lm73DZQJjRocVfNsubVRgx568zRjqhPWsg7c92q64whvkiBRL5ADqTuRbXZ0W1CXP2fwZu3JZWe1SwN1ud1WlqVtCAMiwvl8BvOqYxTqn2LfITYkzBNqJUzzDL7dBgBqrrgB9dJGCXjr57gbjdi8T+wd0MPfgXRECKiqnAMPJ1/9As9tOZR4JORnv8tFn4iAQ8la/uj+AIc2HknodsTzQCAf2CptCG4fe4ZyZpUiHEDf2DVvTO4rs6jlqMMgA3OCDUns2Eg9vaodW7Y7Y1/XQTiYSlpuQQZy7oDCup3XtxcTBHS0McoMj3O5t+xdtBn0pyzEBJBs/ZL0z8shAyE2wNgkI+nS1AzhBA4IbE6teYaKlpLT/yk+WzmhNh4bLEuYj9RE4XvDvpKPk5R7t0mpD/eaHuNBm2fbXPbJJWcUlW939V1cdlifPrf+6z/7P2/L0fXXVd2stdW9Wfoe5nEuq3qWtdeJCFW9BPfWhcmne4iIRXLDRcFT3gtSwE5VeFjDx2skk+b5mQ0jJZC02/+fjJ/uZPok8Lc9+0ZgO8TYPICI2zScw0ACY5smbQoas206nnBlMj0DTOWS4CvI8+c6eF+mADyOMq3VWlAc/2LTht6BLho6U614973fIwzetoKL2ctVcUrGAFBBLDZ2IJX0Ugdx0WDk5OcliJ3RMDCXS9A/rTVUIsxq0yZnSAHRhFt/j7ULQwOlgNfQ/hEArExs11ZqqFXW9zzPuGkoms7hN6DUCaQixcaMtt0Pr+m7Nr0CuheSDOSQelIUW7SiYO6E8/kMcbG74ov34lpXwhd0rMtqd7ICugVEwLqsqDWClRuoM7AyADoooJtFJXNZQ12SiMTzY5KMQS/xUgtKF29ndtHkUAXbPua/pho5GLrrb9k+zsYmA62t2pc9N9u9CCo+Bi4vqgPPnG1DCma18evmnIU1PEEpIGaPo2Rc6kw0Anal2YVN+xswczA/iZB4Ptl8f5nC48KPG/45udVRnQYOKD3MsEoucXLqIAjfAJlDm46oYrbRDFslzuOof1wCtCkj0xqmwuZSGAPhdEBAaV67fONfAjaJ0eDeThMxxoh1TcrpFTWzuLQtzAJg4Ef7UYzOSSDU6VqTnOlZwTyUORBU96bUmSFJLdLU53h04uJMHifEci83bctPmSS23tgkz6zF3kFDtm6i7AByCOnDpkwjcdmBsuaj+DUzBZyQdgBo69Bhq48RcMBMuJs2+Ya1mc8L2udFUpXbFXtcv8wNg5l2zzOY867Z2eV7NkvEGNBzsquqrtnUQRkSLnSh0OSwc8jujqL20676zh0Mc1Qhu7oz+QEW6qO67lKbDs8G+OzeTVt4sc19+H4613iTF5v899p1nJ6pezvRX7JY2xsUEzNkkGN+ey/o/gfc7tS0Kfyzu/I87k0+7+1PvKuPWNRx2SVn7O9rBoA7Oq/SRr3n12nCn/1tP4Z5PqH2hs66hrhL+QwQd1lHTZnO1MElrVOdTPZBSk0daAg4oONScFbGOTGhFgFd7z4saLdF1DaJUqgCAXmi6UDC8GYBdPMs59/pdMKTxrFjFubgVCcUjd1oEtE1aVq8pu/u9AroXkhiCGgo1bhH8tSCbZ/PJ/S2aHiCpiqIohY474Juizrh+3LnqXMAACAASURBVMdHPFwuAETyVki5RZ0xzyd8/vnX9JIm/OUf+btwPp9xPp9wvlzcRm0LsIyQbDnmWwnJ3bo24BRqovY8e7zM4Quyl8oM3rbAbWsfZ23L9nVmu2fOV8weLyR85BK6dTUiJcIlDNI/rcOC5bbWhBNYi7t+50SUCHFVRId/ww/e3LObeU//PyTE9wSsEfVCkGkuGt/ZSsGsnkwvD1Ixozd37yUOcKrDQJIDOh4vdzMOiXeeB3ODCpcRemaiMwBkpDHQLw4gdhU4QGKicGIyAKYoiHOhOg61VJSq9mo8EsCh8hnfDRwBAPXu40lkDlTCO6bbS2l19n2AFaltId0O274dcbUZ3926dlAUam0ODvNycBBnf2mcL2xANcd3CTIczQqiPReu/eZNDw6IXIOS2QNf9GPsP8VL6a/SqDCAZmBnm3jz18rIYGzowjMPDooa2hYFxmrUNYoOamMeB2M2BHbObJgkDl6TdOX/Y+/dfmxrtvug36iaa63e+/vOxcc2cbB9fCOWHfkakCASEQnBQQ44igCDkBAhxEg8I5DgIQgpiIi/AAJPJiCBIgQvAduxczNyfFEuJkCcxIkdg21MfLB9zrd3d685qwYP41o15+pvHx/ycL7u2urdq+eqWddRVeM3xqgxbFxTsAwQ1PRd97/r9erzW0qR9x3EjZ0IfDj2WYBgzI0J/Aw0w+pvgFh0JCju+2z3932O99h3B7oOZzMTIfLeFjAtD+Vcbq4hhmF8P37dgP2J/uc+HGQ8SFO5hGF+43neNQ5KsS/yensau3mbMn16JQwHJGZyyei67xPsHicroBeNn4GtWGdky4v05h139G1DU4ugXgpaqTidLihFrqP03rFer+hqMeShNDqjns/azJL6YPNP6TqIhWSJ9WACjOW04NIveK93fOzjjyj3j2hM2JqcM/f396BScDpfQBDh+1ILlrpgqRXcu1xtqXUIE2V74+l0Rmsb1vWKrW/DHb+X9NFOL4Du2SRGqQTV7ItDJ5J7cufzSeLRrVcHRICApvfeew+9dzzcv3HtFLMwoG/fvsX5dMJpOeH99z+GdV0BENZ1w+VywfvvfwylVHz2s7+BH//Wr8SnPvUpfGw54dXdK7x989bv3QFiWrksorlrraFsG9q2oNTiG2RrHa1f0e9eucTWwJXdaxtDCjS/65a9V0o7MYA6CaUgJpFzcHRmds1i3JdjPD4+4r333gcABW0yzstyUjDIAkCx+mYPZ5rVnKNK0NCtbahEwKm6jLN3Oe3MQUaxuKddDqanJZwmyvT/gjmectthHHhjBBRRUZiDDpUnAGMgxhkvZ5jJ5zEoMtzbez3eFh7KHYCQcOrwIK8JzGUGMUvhR6COqX95RBLyTAy+vegmyxQggEzib31PINTf1rKMbTFnIfnw9y6qdo6hTKxp8kyjY9osY1RKUS9oSLSTzDinOXNqUAa3uydCVm2IjlF6J7OZPm4ZoGm9LYFMz2JjecAgmpMbnguzDyNyU942OeXwoOQctKDlGw0O9JPGLTCZtI9Z4pmZNmemrVhL8W5qmg2O0sc4Pja29pqBp7S0ppTauUd30ZzpuZtA7sZXvi06D50SwWnykC1pbRCNndSll64PBsfeOwtYpILsddUZZA1/Y/e1GeLRMtYhx96hf9o4dYaa8497RC1VyUspsDMaRKtopsjiWyMEZ12DUvdUr2t/aI+6Buemvsbm2ciQ5OimnfVneuR7goFUoxMb4BlyzXM/Q0+bI8rZ92sMacy85Og7O32MDY4nPJNP6lM0P2Iw7mDbsC5NSz5a3WhNTCp7I1AjtzKCOqZiAGTCJ0p3eXsX/sHvrAEwWtQ7+dw60Bl3lwuIFlAhtPWK6+Mj6umi66+gnjYsywl3VRyXoOTYf4yi+zCrR8kwZycUqiCyaxgMIokj95oqvvzLK957WPH2/hH3D48odcEbdRh3Wk6odcG5LtiIcaoLLqcTmDva9YrXr1/h7nKH7dUKRsf18YrL6YTL3QmgO1y3R1yvq/M7L+mjn14A3TNKdgHdN/CJ68jmXufzCXd3dwnE5eDcxcHTUhf32JjND7MJIwAHWFaW1d2zqY3eG2oQU8VuZhCaTKtiZY9ahVELZs5RLHZcNq80oDfckeJw7mJjkJ2j5N9ZM5g1jNLP7sHEiWw8NpwWsZ/vpYjZJUEPAQJTEekjEgPq86MHmU7VoOVx4JIYL385H52Ogob5fpeUGfwMmuz+SDY1gzENzpRNZjJIJl8D/57nOFWckzJaxqwHR53e1YJFHpHuPwGuaY36jFkIQBBtJPXUeOwdzNsARKBcJLqc8h6ZULn2SjVupUgQ+lIsFpHG8UoA0YC9g2Sj9SKM/GxSZqwiwbxgKgPHMkZhFpxYOhJvg50YpG7ivb+DNg+ugTH+yfUzRMlrq2oMS8Fv/YWfx+c+/kn8+j/0WwIwpDkfNbqEpN+AM7sDyNvNyjA3Dqh9Tszs0F2ADvmHdc5R5s3kzdM1OYD/gxYmoOqt9WV5tO6n/uzKfaJ9Ay8eLLQAnSnrAdDwVhrAsCEZwJzmUsDOEIa1VLkDtywikLN+SgDlK5ZTgDp7F8ywOIwAoRQxcxPaLb5GGbZXM0QLR9EGpRHTknt782fEVLF3jKZg3GnUKNNOlEG7scU4h+nrGKp5n6MQCOnTdze/PUoDVJr6sc/9lNmp99PKupXviRSaPu3tHDmdEy+iRGhCR9OsiqAlwhXkA4TtPIDtwXmCAfXGBDPLhYa3+K4/+adARPiz/8a/KnHgakVTfwBgER4wm8llgbwqwgIT2MFjG4rgx2l5ojVd2kLbHRITjwO0L8sJd3cVoCLg7XzG27f32NqG8/kCBoHXVYOdiymoWQsVIpxqxfl8wsPDPa7XR7z/3isZ9yJ37FprGp7qJT2H9ALonkkSBrGj66Zj4C2DItMiifto0doZwLFAw6UUdbtfcT6dUeviDCggXiOv1xXLchru4HziMx/g1ZVw/fTFnzMjgmszR3whhHmMMNVqLtnjbs+sXckeLa1v27Z5YPLL5eLfG3AzYJbNxXJYg6yNyxJr02LOXjNN82b3P8KpTMOyjI5V0BlkQdJLkQvZ1hk2LQyceXewpMxjOEeX/3ZMGX8hjMGtFFziCOqi3TzkHdMhs0LGZrOXMb8dzBHll4ZHBuZirg4coQCgRGM2dx3hfh9AxEgyjiFzaZyAKuDvOZBKLTdgaODLnVIoDws92Llz0oZFH2fG4GbiYBSc4TCmaPdiZu4DnAGquVeJdCljX2RcDEzJd505zJEMdBZj7rPWVL7/t/7Yf4Bf+Prfhj/+n//XE3iLfuZRYGXQ576OOXWkaX5mWfn4ld0YHqHEaVERkE0QswxlxxhnuvFq7WGINtj/P2oaYaD5CfSNTTatbdLeOtDJXUzzSpkW9F0qarqWG8TA0fDEt74BhbZM1po4+Ck4nSAOTbiLVg3J5DLRre0rBrpGhZmOmQIx5hg715Db2CSgFHAJXlim+wAXPM7BMIeOHjCLGoK0Jtoblh8Neb/jB38AX/fX/vI0rjqnFFXf/M3xzh7AHaE34PAxO6kkOpyBJ/amyzcWUlbo0jRAvq/O8RyRMJ5tuYbnDmuJ+ZZxDvoxUOZ5uGuMOQl70CkEWJtaFBFVrNermFRWoQIG0KF34kEoIgFTywdtLArIFIrD2Rsz1Y3oqMjdX9OA6/651EWtpqqaSnY8Xq+4risKFWytAVAeohAW0wC2DlYzzFd3d1jXq/Mf3IV/MEC3bi8auueSXgDdM0q9NzTduImAWkcNVLjtr+4sxR0wQOz9DNAREU7nCyyAuJ0YrXWs6+b3ykxy+vv+/M9gWRb84B/+va5ZAOB3GqRNNNwfk1h3ix4OEnuGFYzt+xZBvvN9OdPMGMjLeXOgcNPoWd1mdmnaRgOMZqYqwPXqzw2o9d5xOpFqXLqGeIjxdRDdO8g8idaC3vLBzD6exQGdMmIZzPm5QQ7qRlQ3HfY3mLJDXvZGGoCcH7jBMHE6hO1OlzdFP0iTRw7eg8zeaubEqE6FetsCpExMjtNAYnwNtOk7QmcJqBkjG5yfgrmxjQ4cBpAibS1kTHa0l1IWBrtWY0zWrjQgSZsxhC8DqxnuCCrd3BIQ6S4ZGIn1F0y0rNPi3mYZKDwBopExdlNQjZ8nJVfAArMfjE9n0+5xGqZE35kFHuY61sbAiEfueQBT229ws8rCh4YkmNoxj9UQgz7fz8Q890ObRziH4Vt27jWmOcMA077m0Z/7QsOvPZhL5WfhFGIubR5szU6+Y/bJwSxHsOuh76q1KBq25VRQlwWbOpoQZzmyD0ZJSRgDY9KP2+LCi/w3xUgbqNun6D/72FvpaYYcVcDpOdOdmdshafbG2T4YrJS+5q/9FXzrj/zwbq3uwRsNf1tFeUs4rCchGx83PtLIacmpggHY5rEnSjXcWHtaDqXPXmba4+fM4UAFgyOWPKYDLfp+UTRvx+y8B73LOVM0MDlGYXBbxYSXUHB9vIoGbYEOKqF1xrIAUMc9YFbhWwPrHmnG304DGfjauQLRPAuph6M4hgA6KhXLyUIriDXJw8MjWu8am1fMKRcqONdF+IytoVeSgOL1Dm/fvpU+tQ6z9nFA92Jy+WzSC6B7Rsm0VXaI2t2xnkBSjsMGCAhZ6iKu+HHS79U0K8V2s/tmFvDb7rZZsvsM1+uK02lxcCRt6uhtZB06d6DJbwN7gBwMBsSsDwbGbKPM5pLWvgxaLZ9p6QzUzZ4CTWtp5piz90tANt/T6TTcPQynKxVEGzymjYYpMOcvIlEkkQAWGhgrHzcYfzYyjbcklztWkrKmas+sHpV0yJveSMoSZ35/aIxpwxxcGO+QzZwG3mBksG/xK59vWpbFQQsO2krQ9lAwtYPG0dCivurMsX0HDA58CAZo9yaLOZVSgJqFDxjbmZmy3oNxhvp0ScypA9k0eG7a3DpK6bCA6LOpsGnmQBjDFUDX7hBYPP3NAQoBTAz6NM76njHvNk7eVo9HleYAwSQZIMxzOLGs45z53NheMbQM069YJ3no5yXi7cPBFzyYYoUOYQILY+MDgHlRSjfT4hMSin0vF+Mmh9DfSY1INgyY6SPTJCvRjmOSOj2YWVoPMyCSu59m3l68biLIc68TaBxm/GaNEAKI8NqnYjxwbpwBttRSF8ykz7YGYywQ45rojaNLab3HmNCtIfPveJyTeexge14uO+gta7Jtjs27aPy2Vw1spXJ3td1O2dIkujrtw6mPNL4cge9Tuz+kQi+UJ2ROPoDJG6btuzEoE8C1LKIpo6L8jAmhjNjtzKYe9ZCZ6Mp+1doGkNxxM20ds2jLqGj821JQuGp9rNclCEwGEgFuHb1scrcu7UnZ+gnE4C6WC7tTgAi1CB9AILz/+jVOywlr2/Q6C8n+TQAVwts3b/Dm8QFUgeVUsdSKu/MJ18sFbVuhsneUQnot5sUpynNJL4Du2STGw8NbLMsJtRQwd5RKeLw+SJy0RS6XB+MrG6L9XUrFAjE3fPXqDqUW3L+9x3q9Yl1X94LJLIG3Hx+vWBaz3ZbyWut48+YN3nvvtYKdgsfHq2j1tuvgCc9ApkiwLHxBAXXC4+OjgygDWaYty/cAa62qIYu7dObYxMtX80oAQ5DxDAwNpGawa9+Z97bT6eTPVg3nsCwVrS2w2H3n00nMj5YFjSSwaVWtiYVsqKW6FomTNi5LR137kQ7UOOTTce+a0+AzM8MiZ2awBMb07UpNXPfRIT6CG8ihb2Bu0KyNRY+mpPm7vdFQMKWWP9o2A9A5fIGZyTow6JzupoWwYGhnPpi9o/ZO7m98X/Re0NSYyJfeN+BeqwSRva6bC1eszbImY27s3lCt4jjHvbnqPTaXBtsL3mw1BVZticQ4ku9qXYLJVWC2rquvH2OQLe5XgEbzRmtS7y4ORdoELhH3S/7T7//vcf/eez6+PkYGQ8oIQqztvBu7BCiilwmbuH41ES/lrApGEjOemmS0kIGfFVMSPQ9UqnTIxeaaAKSwD4Z9DFgRpbqn9ZKFAD4kOURHIlIfKwMqI3ufmX/Taszrja29hmw4xjCAUXHslsETgfU+cPW67T1zwQ4qqItqyH2S1HkVETgJ6AzwGaCTkB7qEiOHuSlFzX11bDl7wLSHMXZIgiUTXlBJd7N83aR5H4giw0d9awI9Ig8Z9xCfv1wUgJ/79u8EOuPbfuTPSH2BZaQtCuaOkhebEM6gJZw3Ty0zk0YI+ZLFRMpv/RvXECL+24dAx13LsyDBHpkmX/vBB+MNiOlj/teTUKMzy1yqdq+A8Mlf/xz+xjd8Jdq6AixmkaVCnKg0MUkEKaCDAPuHhwectoZ+aur2v4DVZJhLBbcGrg1tW5W65O47tYq6PKJ3eQ/FHKDEnhWWSkDN5y5DwyawOgtaUKngk5/4uN43bVi3Ddd1w8defxaP6xXX6xW/+qu/il/ZRBBOel/81eWCUhif+bXP4Hw+oZ5ECE/nBa9fv3pyrl7SRye9ALrnkhRogRl0OoEh3uha27C1DVtbsdTq99iYQ1JfSzCWAl7OqLXiAQ9oTUIJiOmkMR6sXiPX5MYXDvbEcYjcjWPu+JVP3uGTb6946w4ayBmC3jsqicTMnKb03p4MSWApa+rM9DIHE7dg4NkTppWRTSmzOab1w8ZidgAjgO4qISKSc5Vta+jLggph/BmMdWOT8Xl54bwCzmDHCUt+8Gf56vHZesDIplduEMlYQgJyI5h7+jAfimKMsYgylzPn3QHUfaHhFIOViU7MxgGYk+c0HLCiXQJMQ8qD2ZRJVG/0i0YN4gi05+ZyHgYHdZbbmHPTZowMsbUjngXeDg+Ocqc0l6uMZ6rL+mw3Q2xMQFAPcBSABN2dEWVg6IxiYBx1HtAHsGf3Q+xVIqhWUfpxerzizSe+BH/9H/+d+Laf/PEYt9T/IzDnw30wJRnQ5zGn4bHqIUZcB2OsMpY5LGACRx/G0Oa1JONgHGsU7cx/AnMGfnkqSUAVDWWO3061a53HbjZGeDGs+gyGp1diXvJz8n2Lod5aO4Oo652hAioM6uKooXd2Z1AiLAS2rh57OQuqEt13BohBHX4GBKiOxpoVyM2+pbIN2Bk4sVHk3Qvz+NjoHWUk3YMyAdkeM2b96X/2u/Fz/+g/hm/9kT+T1pmdsVGrAzvzqGhHgxKtCGLG7/adiH3AhyEyIwh/32fK5b2TSu7zSHmx0UiTh8dEapSBMhDENFwzvPf2AXfXFX/xW74BpFYJBBJEdzAszGLq2LYNBQXF4nnQovV0gNM94a6Cq3RubNsG1mZIPO9xDzZA19TJVDE6Z7kGw2i+vjtJyKdTrWi94nw64e5O+ITrtmLdNrRtw8P9Pd4+vEFncbpWCuF8OkkgdZx0jci96Mvl9AVO1Ev6YkkvgO4ZpU09OZlGKgOb1poEr1wCfGWQMpsumtTT8ngsFAVzAIbwALY7m6OSMOsk/I+/8+vwH/3Jn8JPf/knwKeQwhqos9AFFuNtbdvQvgzosnmkaxm0TXb/b3aOYlrIXE42F7Vxynfs4nkbgOSRoxmRJq/oGmuuEEmgUshhQmlMPZ7YwKAzYMFzh6A+zobEJPtBePDdOyTOh2w6Ud8JzClj7J4fE5gb2Wx2qfKgMbgdsOgdU5ZqjwWJy3ObO6Et0whlTSH3NF4JYAi/SckbW67Vsh8w1v4hafJIGDxhgCVuY1XX2r2UyJsZtASsskaO85rMbU7rgQCg1mAG2YzYRoRmMcOs7K5rYOCtKJoj60fjN/Y+gnUHq+pYQNfWqW341//4f4gf/d5/Dd/+Uz8xapUyeMSeaQ7N3OeRKFCamQg6kDYBgXLy7EORmOUbtc1mm97+iZmOHo0CkUF7bQADI6g9rjm+yVXtSU+1PLkcIhWssCtMsuxiZ7I71Dl0KK1m2bMkkLHEw7Eg8usqMbAWEvMv0bD1GBEyS4SxFiJCqaLpMIFF547WN1AnsdqoJdqeydj2rzSX+b7diLVMOwXfo96Ftmas4VtmZwkHgSPauS0CcMEH1CBwEFIFXQ7HAmKNGz2z/5/ahbQ3DHWO1xg+vJX/oJOB1qOd1cYU4xq15CaXHdQZa61oRKhdARgVjdlZkA1W06qTfK1ho83rpgq/J8xs1hC2dhhQ79Rt28RTcWcsHWp6HHyAhTTq3fbG4vFnuYlmuVPTcyXzKAW1EM4aa7G1hqaB0ImAz/y/fx9v7t/i7f196pOMExXAbGNrfWHzn0t6mennkii0VKfpDp2FE1iqeWbIIQpoMCEYgnJb0UQeugAI00XTgFkeCUi++b0zQA76ay1ohURaxQnQQe/QqSalUAErQMuS+3yPDsDQRnNsYm0xhy6WL5tXWjk2JhnkAWMsMwdqPI9VAGKJOQNYIOSuB0K1uGGaz04p24zjWM3soNUbGzcw+LqMZJjFD/v5S32XR2nwUbL22DtzeUcS7ahpAnPG4xgDtfN2ZojwRhynm+2b25IZov3caU+Cobax0jYNAEkryaDOvqP03Y7bGro1PU9aPVbwZPfvSqJt5r4rCg4699or0ZZkRm8CdTq+/g4DMG+WCugM0LqQIvcvtSH2iOYac2ZhZmRIbT2pYKWI+3oi4M7caN+Q+HMas8M7P7zL7Iz8PAPGsDtQT+tr9IToo5uXCAbVSpY3cPpwgO2wy5eKsX1FPYLaErO1HaBuXNtBq7fhXq5SwMG4B7j2bwKfBnZMw5qBnjHbh90h2wurzH0p4K2p0xM1b0PQgbUpzINVuOBLX/LWquW1rnQpDh+kro5yMAY+hxx/cQLqh4nSNLOB/PTlUa99yg8KZntvmIVUH+2zG0DAmI29LCAu8kl5vsaNSiwe47BMB6reVW/v5+5mM+BdgzxbCEUOsxxhshvJxtFDGgzCg71BtH3ar3QF7drn3jqIugKtLuoz3Tf/12/77SD1tOonbWc0akALPsB4CvEcKSEPoBo6nwdmMd3sHaV1YBELHKoRj84AnTuY04PevmMwSi/g1tDEu5WfL6UqzwLdy8mChy/ovIII2LYVrTeYBYLDdF37wde9pI96egF0zyQRdHNSAJM3rNls0KTv29bQO1BraK4yULI7DUVjDi2LkJPdLbterynsgWgjxAvm6nfZSllQimx01oZSSKRZxogZL1YIFeNGmQGjlTHHpAOwu580g69chpWT2+7hBoBDU0+5o7d4LDEZQwMRCfypls6YFyQNi8+UH4wBHmwOZybCnxhT6RfPjfl7ivV7OuVD+0j7tH8BDsjm3KH1iLaNHbB88ANtagiczcgc8FEhiRHmiZtzLagCugwyGax3JkYNGaX+UC7dgJ6gKDn05yFRbeUtrtLv/FARBxCpnD4w0YEaBm0nwZ1NGJizNmdQR4CWGwAOBKW/EJxkQGcmn65hZ6t/ZJo9DxmgC9NBdyQUnEYCLEhzmPo58L/jGhBOt4eUPL+dOHpbX7mZUagO+cFXu2wp7/x+BpK7tWnv0XEdRHYfb998F2dQ5L0Ffi3foOmMIod2h4mhGd7aX2mtcKLJEAMcVTm8C6iX5OUka4Ga8M8DgpCyRKPbXPvhLTGaqRKTS7QcDYUZvac929to+0nsG0+jt1tpnuR32Ot2+TKgurXpSj1Okww1Tw1rjlgDYb5pZ7IUYftA0AgB2JmaT2DuVo9uf7f/5qlReZfj4WZiHFhyjO1wU3saqXKAeb4nmPBZzes99pt8/ntf+2kNLSRCFeODxOQxwhFRj8/+jKMRtnp76+jo4qCFC0rndFcUyIJxIgZIwFfssTYIIrjobQOB9RqLxLUtINBSnPdYlgWP6wOW04LlVPHm/i0+ePsBlqWCuaGt7EHVS/1CJuclfTGlF0D3TJJ4SmroCiyy9so0WOAwx7xeVzADr169du2bgbbL5YLz+Symiip9P5/PuFwuWJaKx0e5JPz2rTkHueCH/+lvxZs3H2BdVzw8kDsjMWAHqAQWckGYmVGamnqy3LEoGuTTAj5n8JY1iAa8stbQNIa579lMNINVu4zcmV2jV5cFb9++xbIseLWcdINmN+lc1UtWrRKUXRzFbO7x7bQs2FqTuDIkHkKXWrEZwIYe3sx6Zoe0LcxbVXpnzJvFi+I4BuMcmRmyY0l1aOnmRNqGDGV2bzvTEeAG8d4Bx+w8XjoQtXUKFFj7EwDAxsDLHOCVMaPkfdxprjCBcH1PTGiyQxHEnUkOZnMGHjkmk6KoBB7Geq1Pw48DP4vXRtpn+z5r1aSKDgLpOqg1YukZro1+99CuwRhCABTaZKcM8+SmZpM2FqfTCa6lUUBqpnEB+tjvni7GSOnEDiSoYyKmnG5UFoA6zb8J6B0cZvpIGrveEyhNNMVTvoFSEtA1svT5cIArnuYs7njMvTTMSM9+5/tNsBx5maiDlNk1vgFv66eyoAESnSbSepqGlCgx8EqD4pCnTDRIw8dCRaX53hwH7J3lnprhuWj2SO8ECgcWad/t24atMyxIMlSrsarDH5AJFc2ETe9oV7nfRHrveNG9GUSg0kG9oFagLiexdmBhfm2eYw9McGAnVMrCFxwmW+e2Fx+O4Q7d26SM5QbpmwdJGVTbL5lEG7r1ljwc5mE2rRUhW5ETywozABx7JUc7dm0z8rYzYKzL5WupnoOSrGGpvJwvU+itsTtI+ezagUg/uXwsZM0pvaf3CEDhrhd7IU5MiCQgNwG9a24qIJxABCx2HhDQusR7c80xy701WipKq9jahtI2dyxFVGXtg7H1Da2JNUMrG0pdsDQxm7R91CQPzF2uXfg+KI5cqAvv01tDuy7oRHh8vIpzlu0OtZ5wojPO5wWnesbdecHd5atx//CleHP/Fv/XL/0ifumXfwl3lxPuH+7xcL/h1es74dNeTC6fTXqZ6WeSzGU+q4mAHZzLIuCobRssVpXdmTPzSFYHJJ27S7RcS6e7eq1VAV/BuimjYiEHCuGzX/YxfO4OKPdv1Tte87JCU9b8LNCwVgAAIABJREFUThBpuIR1kzhubWuDV8vOYn9eSki/LDnIgzI+KdxAhB8QgCqAMd1T0Lt3Tc1GO7PHEoONX+9y2xhSNrt5aUXviwLONd2rU6CgTHPvXTbypL0wD10yDslMyvmEkMhC/2Y/8OzvCT/5+ZjB3P6AvSXUDqH/rXf0UFLm7rAKO/TNycbEYA5/MO+/mAbCjR9Tu7K2iJDHIBgEN6nVXBl8DSPnGqEEOIZ2crQj83C7QSRnwKwGKBgyUCVMrLrI7unifRIwGFhTGbX0RddfBj2MdL/DzIPSKOT+mZQ5mwvn+7HGJDtQT3+H9gYhcU7jZv0KJttAujlNMsBujNM4ZMcptesAMNvw5+9mjVUGdIfFO0ll8LRbUUOd+zWZupK0q7e8Fea65beCOTisGzImMg9qUDA2MNWGbqM1kHhpqZ+6f8ywZxjjYawP3KskYYbTb1egXxc3K++9oTWjGQNkPK6hfBZkWtI2l1JQlgXFQKFNDXfkfcOY+2E/yu2dRtRGe9w3IuutvXEsd/5jptHYh/LQMhhbF3BXgQjboeuaACR5QaJLCgBGCu+Sy//dNB20LdNwxNTTXIzBtDxyRnucZP13Qo6YXtqN0b7g3Zqay8h9y3FXYbOOcbKY1fqgqdbL1n/Hp3/u76HWBb/0jf+ICMnyOQkxsSQicK8oTXgVobmGRedHo79o4xkSCFTv8elPDIl0sDUBdJXENBnEMMNPcBMPwa1huz4CADb1oE3ccT6fUaija5w8YsbdeUEpdzgtBR987H28/eB9vP/ea2zbim2VO/ucrJhe0kc/vQC6Z5KWWlGLSKyuDw9YSsHdq1d479UrbNuGx/t7tNev1D67Yl039L6htRVb21BPBq46Gnc5hE6LM9alViynRc0OJLglk6j96yJarMvlDEZTU8wNpaopiTI829bA64qiEtrz5YJNNYgPj484n084n84AqZlDZ2cqaq2gVgGW4JzojEUZ0jAFAtatQe7vF5wvF9w/PAgYqxVVtY29d/C6ofWO2rozMqfTGRJL7xFLXXA+n1FLxbU1rNdVtJW14nJ3gTHMYurJOC3mNUtcyBMYp1KwlAomceftElf14LVjPo3JGI6/WcJ5dIa+C9c85hm0CHNOPmB4Bj5mNpwhZ1KES5HTMDP/wbwF9zJoPNJBnqXsBnZibAyMpbph2gvsDn5zUGIqh85hNhl9Hxl7vzOktD/c58zAk8SkhzvJ3QsCAKGHGMwuTFLSrgVANXNibWuJe482Pz7a/n5c4HctjjFnpaBqXSZY2NYttBwKZhxwjlM4arQgXguHgbfRLj74ChrF/O67v/9PAAAe3ntfu85prKMsY4CG34CPTSniutyZd0C90YXmgkg94lrAcy3f1hgo+Ligs5l9HQENQ+bRB8RJdV4jsSrdXFXB6xGeROrJ8eqU750ufEwO3tnjCQdE0gaO8AP+P/l4AKI5MsA1rHPHDLEOS5G9em0NoAImcT4B6np3RzTSfbIu8DYzo4MiRp22qDujDBfKiWa6iCaPJfQOd11/6o2QUEQrw7YmTHMnZQ2xRDn22QDL086VtoB5V9vPUt6snk6mudl6R2PVFhVCUbGeLVsDdTb2JU0wI2nvhtozhNP8Seo2gqfxDl5M+NQVLWIeogzqrA03/FLdSEZLMS5HWWwN+A7BnOrWu4TZZFPipwBd4x0yg3sDlYpv++n/A0QF/+fXf1qE2HVBWUTjJp5hO7a+Ab2AumjoFqWpWsOMnEnoqsjEgIiwnKoKu6WlXfdlEZDL+C61ois/ttQK08xBBWvXbXXeAQD6+gB69RrUV1BfURapoxeAWkNFxyc+9h6Yfwt+/bO/rppxAaHrevWQSC/po59eAN0zSYXEzG/bNmzriqZBjE/LgrZt2DbTKDGWZVFTTPVgpwEuqZjXsXDrPzDgRQNkJ4bT4rF9+0/8LLZtxY99y28V80Q7SNWMjIChbDOJBDA864vEDsp5e2csixz06FJmZ9OumR15kYvPvUU4AnXZvnUBjYUszIDVy2jcQeqoRUxUgXVbIY5ioIGkSd0Hi0nlRccDCEY9H26moYOFVWBh3YM9C2bNHjkTjfFAFkY8pPcDC0r8bmfqUG/+234wfZdyTed/tGG+cE/j78Miw6xtfEf/G34fFcLj+zCzRBo0A8CA6ZyhN4Z5uJ+z62+Y6YgUV5mkEBcP5Yp52giMCSERDzPQHnPsQ5XuZuVh0zABFmIEzvzq72Q2lJFLsENQAbYF6oZrLw81WES7cZ26GgBm91zvazHjO//cDwEM/KV//g/CtXSB5BOpJSFFmiibH6KCkQRGNjDf3aNGQ9tyy8j+J079pp0W8LiXrNNCo3NWAkKlEiA/WOf9ykotv1GnaVUz3RpNROV7PBLzlJluWBODCFXbWpxmGGZ2loUjmX1Xt+gm3OhpDzINcwmjOBNaAHE2WFtFiFIAlriG1nahU21HCTDG0HYyofmgMLhLW3PggtymGJVjQZU2EsM+xGmYzKx7/+bnlRjA7/uP/xi+6Yd+UNsvXhoLAC5suwZITXqHXZgIE/Wj62iFV1Pe9Y9gtDOvAnvX+oiBnn1bS/tjNi8fyGgoM38YU94Jedrb9odC7FneB4rf1gZov4MWmuRrxR0/ycgZuO9obdUYikBB0fXaFRhK60zwZVc55F6bWDiZFrNQ1fUDmUs2uQ/pHtvQG6OpkzTiBULFBUzCY4hwQkAjN+mXCFaATsBSAOIN6JsCugqu5B5lL8uCj7//Gp/8xMdwf/8Gj9cHPDw86Pn0hVLsS/piSS+A7rkkjk3eNqccVsAY3tYaTqeThzKwvDmo9uwFUhhM8xZZHYwZmDudTvj6v/sraL3hJ779q5J55hLhAAaGdTQFs2Ru0sdusTt0APQoTkyFSc4KFTRSyW0CW1QI2MQzZ81Bl5O2rJeIhYeuxy0LOCSQx5yLsYkQBub9z8wofbzUoyBRcalrQTBQZnKjU+cHNWse49OHA/AmepvB2iGBTPs+v8M7B7XQQW0H7XKp6q1aZjBn7/khbqZGwAgMArg4iLk5Lvsq7f4iI4eiEJZqNA/mmFuLA0eIdgFgaDw307oac1QKTLlFZgpNVm9uT4CMAKIhufU4h8k8ypllM4Hz/hdnxEKjwe68ZDB3c82GrR0a3nUAxYkCTauTAIfk78nxzzTTHPns70w7O2CVuMed8jppfuKeJBIjntqptL4HbjqOB8slt3FPT0rNNv+T91anT997Mm0PH3ZVZAj1ZDIO2qs2uCq0m8GRA32jv1I0TEAARyGP2GtdiIGsGSUHz6fTCa2rOXoGkg4Wu9qpJbomESqAgY4ONPUGTOKQIsAmwKhel2gZFTSmu5nRtgBesifRjfmOvWIYbxoyhB8SSm9k2n/HxMPnoElm0Ugyk54JCO1cCoMgy1hj++22NRf9KM6xzSYqjxypc8PvfXvjDIp2DJ+tBMbONPRmYe+YjoCiEDipE5WYE21k5OoNnQDqpvVkEFUfcAbQ+wp03fK6aJNRKlgD2VeNywtA4+1ueHx8cKFvKQVUC5ZTdWH3dr0qSBV67Xo+2V5MVMDFrCgktBO3BmiA8dj8MITQWa+PELP1BrrKeVGWBR2kdwTFedDruzu8//oVHh5eg8DiC2Db8JKeR3oBdM8ktd7cCcr1esXDw8POW+O6rnj79i1evXrloM1ixr169co9V97f34OZEyhbsW4rWttwd3d2wHY+n3C5XPD69SvXtp1OJ3escrlccL1eAQAfvL7gKz77gF/8ssXBIjAewtb2fLB3DYVgDlC4cgDRrWGpC2qpwAL0Ne4KdXEzgaUuuOKKx8dHZ/5rqVhqxarMMzOjnFXTR+oNq3c8Pj7i1d0rde5y9mfns7gZPp1OGki9qcvtglqAbVOJHxoWDdoubBcwH1/22e4jAjyYCM45KX8aippP05EVORLihfnfxOQMiYaP4vp/rG14NTGTs+ZkapF+Y9LyOLR1FPyFZLinPCD5XEJLOLp/ddSXbI5l2qvsQc7K8Ttn1gwG6lJd88DCpaIj3Y2DCFUWjQlHdhFDf1nIgsNB1+8axjUhzG0wygIO8/04GR27Nzrc04OYRJtm2gU+qgGEutv29WbM1ASkZT3FXOc6zKkRM+Ov/u7vCqA1zdw4t7dmR5lzY9+NudexCgARe4cDLK0PQJh6TuM86NGUkQ8gl2jM/h/U00qvRc3gaByrDDAwMOwTFzyB3NFkLmfTtZF52QHQIdYAxVruaR2UUlGXxb3zAqpxhjCALTmdAsyEt8NiZVrYBTNpI72XncfUvQTrGuxNARhbm2IddX3WCKiswq5aQFTdgoEAB592H8nCZvQmITQ2ZlWUmOkw673ScBNPlO8wx+yY8MLoOgO8eZ8yaonlOFPuDLnGP5gIUE+MG4lDLBfOxNTpFqHax1JQi3iCNvoxhyqk7+VtzgB6IfOqOoO6GYgF0BxoyUndKW8sA0jCnPTewV7G06dhP8OY3C8reS3esMEzpu5Bti9v64qi9EClYFnO3kYRVBC26yqx6hYWa5m6SIzywgCJgBXc0DZZ09zkCkop4tCtKv9Ti3jMRO9o6xVba36f2TRoAOl96YJVr3aUQuC2gtsGgpjeF6rhlbLr3toZ9/dvtM7qc3S6nMAkmkIusu9//NUr9E99Cqel4td/7dfwuQ8+wP+td/Je0kc/vQC6Z5J66zst2/V6dSBERP7sfD679N+co2SvkDmWnIFEcXSS7+6E9Nadp1AwMOY107Rw/8N3fyv+0H/3k/jFL9P7Ncp4mETQQBQAnE6LxG2hkbneMaZ+eOv9BCrYmgZRLxVU5bkx/OaBzc0xdUysPQXBMFp+Y3RqjeDrFu4gt4W5iymnPXPmve8OOCCff3EgvpuA8ykx6VjHU/gmzuEANUMtQ/sSm0B+5CYN00EbZk5hlw6eK6OV358NoMzM0Zigzz+R9pk8vIS3OmnJBk2H8/Jm9puayF6qd0vASCo/rQsDLdLdBGJVe8KQ+zYCVo6aTw7shGuVufT7dMhaDAxrNQNgIlZgHpwluWRcf3tZwQw60zsAaHn+A3/43wYA/J4/9d98PhMy0Mhhn7WuMtPSNPahOY2/gn2l4VurlxS4umbChukp2r7VjV0Pcr8O2j4wsekVjo/vVLujEgNS+nbao8WpFAFkAE5+ODt34LSXIjzzdnd4Ax0nBCDyPRzK4BqA07YgryMOEM6M2ZmMaZZl6NXk0y4wSQaA2WmZNbYZGR6eBmx8lnXr8fzIn80eEn3+6cf/yPfhb/0z34U/8O/+OyPYGTFLWlsiIOjQcVHNEjHg/sB8f8TY16nMoX/5e4xkl/eJ/DnaujftnEoZP+U932jqKYdBgNPV8ZfAEL7OaRvh5beJoKyXBuoFbGVCtFrUJei4BCDXuJuqHO6bWkKA0E1Y1lkEBaRew4nQ2yb5u5znUM/BJhjrOqmkQJypoOt+zH0F9028W0POkNIC0PUesX9rFU26nTOdm4BY6JkhqB1LIdydFlzOJzyeVPP4kp5FegF0zyQ1vfOWXfVbPLgM3kTDdPa82eTS3s2Bus1ssqk0zMx0ZlBnWpMZ6J1OJ/Te8cHHXzmDkH9oOOxEY3a5nCVWGEfwWu4MWiiY6qaArjMoXWTuLJo7Wkilv+ROHKyvInUraHrncLgzCHhogxzXTsoX4LZtDedTgEJruzE8VMy1eJj1GfvkEmJ/ap8GdgO3Nul8+Bmomk0SpT3vQjXsQC6Yq9sgyUwogafA3K6K20UaiM1gVhAPRvXJ/3+JlBEkkqCupknIpr+zts+FFWUERq6BtCDq+nkAUQYsDkCL046BOSJUkruwgxYsafWEKaDQvrNxhkXBI6NwSXKCsc1SRvx7Chjb94zJWcNEXDGHE1BN3yH/nsd2GplMiZz+lnbE+86EJqDqbUu/skYtf0lFAStjN0fRmjCxDAB/gzBTO4a1fYzxBsg51Gxd4nlejvQvAz+fxsv24+I/u5YTREuAUVNf0NELOYDSgHP6fWjsQrsnBcs9Y9PQ5ZkzrpyHXucfMEvgZd3PSmGnnRBekJjEk66ZdCFsd+9yGlUbH3KEE1vNP4h95nNf8RXgWtP6CqHCsLXl+jXsgFxRsD2EBZSQgGwjDqdkjt8ZPIUZ6YGuLTkXOQJyT6f9YD21xc9g8jebgnKkFDeXh5BnL11CYHDKyQ2dC4irmrqKszcmOau3bdOot6SeKbuf00b7IvBeUZLWnwABiKqp64pKJZ6ieMLs1gpeBQSK8SQKRHMH1TLHNRP2EFG1imaQIUL01jo6yflwvrsD9YZTIZxrwblWlA8BzS/po5NeAN0zSb1tKIWwLBKqIO7BQe+AEXpveHx8wKtXdwCgWicBakAwfwJwJG5LreJ9bNugJi8R1NuBXGLYcqDu7PQkxIwY6jLTSsvXe4/gz8waoNbMGhK4KqFFM+0cFeE+Nw3bAMhhWqiglgqGlCfhGUZN3wzePK6WMdLOsJKHXtCeyDNniDTwOODMth2dljjxlsGQpoOVAyBaDfOnkQ3/QrgSY9IpMTs0MHg5ZVC3L+dpxiALmLVSQ1iHoG6+q+TfHVRzbG75FCg2Wmfku0Ty/TzO2VRTGeCp7Aws8se56ZnBOgIQrHmg2gpjLDKQzlpwM7VjhEmbgLAYO5rII9aeMfyqxU4mTi6c0VbZ3cbeYv271lE9LA5jAXLiGUDd3O+J4QwAlgYEcBrh6fFNkjMMkQc20yjFnAWTbXRo7be6E1xKDHSuS9G0a4U+HxY5d4OHv1JHg2gm0zd2d/iWP7amLFxQr5Ha9hg/il86Rp0ZxTxMksytBQKHah4kXlqUDWKUXnZrJ1qp9Wo8goYWbeBxn8lBxs2Dn91TNe3fuIaMlp+AJmT/zetW/uNpTHd5dm/akw/Z8wZiIC+fpldt3uVMgzrzMI2pWI/Y7cWxlyEK9D0bTo7hBCWdOftexH21AV8e9JB1wVhPbADHd8aR2m3NTwzZ/FXaUkEAXrXu4K5zF00m1LN0IzfTduGOmpabx1QriAkobRPCUzCnaNp6pnsqo1FBL13pREwke9vArfs+a4Jjc8oia6w7mAOLMLyDQC3o2WKEchftXqGCuizopwWdz9ja5iaeXYUiXe8tVwCnQljeVbj6kr7o0wugeybJvDsaoGP1ymhaI9E6bclZSketBetqJo1NPY0B4iHKAJ2ZcfJw52JwDw34YToDOgNHbWbmEe3KGhFzZFJY7vSQmiewBhsOT5UFbROAWVgDktsF562h12DSSy0eZ0/CIXTUGqaow50pqGc3ZRR6Z2cazNStdwuamxyh9O6MSTVAZyYaQ8/t6B7hWD74bzlzeJJ3+EIwnbYr3yV7Kh1lCdD6rodLjhG1B6rD/Ykn673d6SOMF8pRYxpzgG5jbictakIRZkJmmr3csGyqeKshBm4yyNn1KwE4RtQza8XtOzZnFT1Aj5djZSWETtBwDkgCGUXbZn7o9aV2Wl32nQtjepdZzBIIOu7r3L8jJlyGO7PRPFDW0T5ibU9PgVlyPTHWAmIM1IWDkQCZCZAYyH6C3mwdj0z81LcEXij9YFej1pue+3dJuACGambC7FEGy4CWaucomUrCQJ0B+mhcT/d6JLadtGQ5LZC/ZM2UAnW4UgN0UUfvZdy/WGkzaTwC4DG4FNSqcywxN3yESyngZfGtjU3wph1wzTnkviCV4n8b1jiaLV9Pt3ayjDTTpPxmjAZMeMSDdthoMwE8nT/zaCka+1gfTHb/D75+8wnCLpCIZxmQKVZ3+Vm0bWjVuIPbuj/4boJsLlRgzIUcJI6yKRV46+wx2i+d8c2/+jn8F7/ja2XUWO7VFSa0vgENIK74b/+p70RdTnJ/zh2UiHfL4TJw7/rTNIRB0b1MpqezaEc3wL1dM8RMkremsUBjv/DYdTYXrOuH1WxZnWyB475n2zqagsNCAkiXraJvCzp3rNsm10i6evU2z+O9obCAumUSlr+kj256AXTPJK3riloLTie5t3Z/f4+3b98qeCm4XM64vxcw9+bNB7hcLn5Hbts2vHnzZrgbBrDeo1uwbQseHsgdiFwuFzfnNCbugy//BLZtw/l8dsco+fvHWh3wmbMVu58HwDWDRCQmk0TqvGQBOHneBA338za1bzdpcalFHbio2agGGC9U8Hh9RNtaOFNRM1Mz7TSzS/NyVauM17JUcSywVJxxxrquWNfwLLUsFdfHMNH0O3pNNYFsrBD7oWwHsvHSo9hcn+1OuP2JF5giA0KAKMyohjKHMrJcdXz3KdgmH0emdTzw6dZbKR/5vPn85WdQRmcCdWO5nBh5Ax251tF0MlqgklRmsN8Pmu6DwjS3Yfq4bduuzqKhMfxej3DYw1x465yTP2AlDYixORoZhQyWx8roqsGzfK13kR1MAMrycebijClI5blQZQJbc1sNxJkgxO+/ZtDqtF2cjgfmOpW5M91VjtDH2es4EnTYGE8CoWjJjsE1DRMAX5uctMGsr2EoJRhbNzlPz6OqrBFLGqO0nMbuJkg38PsSt615f4OmKI2lMc+9G1hSQAbCspxkHz6dsCyyD28rVMpvQoGa9qSgAwODNv/mmMpMwbrO92Lejovc4+mdUErEiBMGuHtr424dAyz7JROhbxtauv/tgI4ILV0h8B9z5mNx3YreP8roYJhCHgFe2vZMpyLfjfQ172UyBfs9c07xHqUJH4hrnHPEvmUOZJwylC7tTq4IFeWGY0m0bE6QrG4iqDxjXA9mfkxep4JbR3r7MTSrDDfjRB4He6Y0CjvPnhyi4asji4ijVHVv+jtf8l44Y0GHyJ4JaAzUBqKqTnICzME9V1ZxXkIFS4HcFWVxdsJtw7quse+RCAnO54ucCyUEI5nGBcwS+ip/+1373lBPQK2AxPzdwI3R2iYAr7HzKbxtvmfY+69evXZrqaZhmtCuKItaPl2vqH3DpTwx0C/pI5VeAN0zSWwXa9XF9PV6deawloLTsuBqTk/WFefTCUBspo8PDxq3TQEJ4PfN7G+TKhnoMZPK1hr+8r/8u/Dw8IByfz+YYs7OQwxE+eGdmDF7Z9s21KV6mIFSi2jWWkejCKdgGjnbPA0EWruyd8x8l8gu7hs4dE0DTwcikQRIL4Rl0eC9lXG9iolH22bXx+ox06XjwfjFAZ2OVz/5dA6R/zyCRiM4yhF64mCnDwVzOe/4/VT3wTlhQIayJJt81J7GgZR/TSe+ezZ4Ojnw87bcTn7mTg2w8REGfQQi8S4PP7n+Xb02uYAf7sbJO+NEx/Pp9Q3lCXNlTFZg1NBsZNDn4RVSnkHDlXk00zJxCg2RmE6eKCyP29E4DWPgHxP9JLBAqX23xyCtB+9UWids/UkAZGrGYM48lBvM9MRDDoz9vk0jvPO+wSpLACKv+aEw1QBqM/bmtuTFpVY+SeG23rI5opCa3cM5+Q/AQygaA9WUOmN7RF0WmFbP7vhIbNECc8HALPe20QLAmYOtzOw6kBnkEgF4AWt/H5QnJuCwmJ52J292ViRmbQZGUkVpHDn/HrfcMT87ntZ9Y54jHFDIzcnxbYB3FViWhHySQGFutypLAeidMYgGr+dzxd5hTuVCwbBlCES2p+uDPQ3A0X3mPIRHV6/n6o7Oljn5DuEkE22V+ZgqsFXtwiXVwLWOpm78DXh1ZlBdgJpmrwByia35Hth7AVvYJKPRUmWsl0XAIIloNgwzCXZ/uSnZm4Ct9wa5aiLWUb1t6N2ukahDFb3y0ntz/qCbB/Ja0DSGrjmkuy5F1yehrxvQNtSXO3TPJr0AumeSuoKRWitO6vQDkHtvi8WFqxVFAZMdlKYpenh4CO+XugO3bcP5dIo4VQaEaARCxlTOAO4I0BkQNM1YdkYBwAGdgCfNz6JFbGonbyDK48B1Hhy7LHUBg9G20dulBWr2TR7qgKIUbOrxStoQTEdros0j6PtVD4kmYQlmz6Kskms/tEkAFnHWSgATunEmO5+cTx19nhJY2B3KQ33Hn/kGjjoGc0OlcyNG5sCZtcMmjXVlYDr175D9T+DpaVBnTGD8HcxBgKPcn4HJnAAdZUmoSaPTP2tbKk2n54a3ONMqpb/tXQdzynx7Pm2PmT93lUQLU5HHwpjmVJV7NNVxOBjv41E8Br2pKkxVB5Cb8xO5N8/ddzyNRdY6kDHwZt5lgBQ7IqNpbWV+NBjgyJOdohxqAecu7HOM3zmg1075N+M6seEZhDwH5THm8mi31EN4IcKkJQO606JOIfTOkFGsOT5J67UU0vtyks8doKwral28Ce6wSgVYtpdv2+bm8dAxLWlcjSbdSUvSuvn4qGdicGiXbaXE/DDQxTuhgfFZ+JKQ2UHKq1SfTKBu9wanvDdK3SedQdt3KD1O37tgQCuX1qngiQB0Rrd1pTGyy7AjmxUIIM5VCIPixoDRrdZnJEuJvnYeXMZPPI2hlXVrDGcKz2txFqhZht1VgEwDsHElBfaE7/7pnwVRwQ98x28Dc0dhCcFEgIaA0Pytgwt83wWRuC7xutUCg+Uah5/1RGr2bHtcVwEHo+m6aAbSygmEit42tL45iBPhuH7mht437a4Aum3bsK4Fm4aLsrV2XcarLOCOFwXd80kvgO6ZJN55ZBzvhmWt2rquO8bler36RnF0r8zM07JTFHtu5oq5zPlw5VJQO+PSMXjizGaK1v6tbVi6kK7dp4NKvjpZ2AFjSOQw487gwoNnzrWtWHjx9sCYJ4YwOEUYC/kxQJfuokDCQRgDLG0Wc9QMRLOJ3gACEoNubDEhnhmPPfk0QFjEa64ZOx18Jj/4GHvPlVJWHIrpON49m9MRgNyDgSHXxKDy9O6H1bjnVtMLBGfgRmD3VMp0OTMa0cJMj0HT1iXVCJPQDuvEZW2DM7GuIkoaXykkNUkBpTUqfd79zgSZh8KY5SomRMbUWo5Yp6x0wfrZnN44fHTBQ1RDKH4pBMpz7oGpadGYGX/0+/4VAMCP/f7i3LtQAAAgAElEQVQ/aIN2MMrx91COV4KhfaaF8jnXJjtTlpivseyg8aGru6Tg0It2FxMZxu7/dz6cx44Na4K8nGMrZjp6mOqQtbznZRMYEcKCOTyxuSwa02pRAVej5AjKAQNhHpjQhNGwf+RgywLy4ECs6Tz0AXxZgbo/gxPqzGvO3iGAi+9jPqiJeXfKHpYRS6w3o32nG8Bxb2AD/zCHadGRi73Yqr+xs3wYD/1Vf/Wv4Ct+5mc8L2MCJbkfnOqh/J2dsV4IOhhF83cQxttTtlZpwGTehg9FoTl8RwKYuRfHKO3JNIn6oo83W7GjSvk/00KaWCJ7Jn9/6s0DCCTeKSEOZVrbZI8sFWAZud42EEscxLwurHwGwL3gige/oyn7joYX0KsVKNXHlzWsAbF4teytYaOuYK65CX+sBQb0fh3S2llqkeDpbcN6vaqGr+G6VL+uYoNYP+8ZeUlfrOkF0D2TlEFH3IODe6vMgO56vQ4SUwAen25Rdb4wt21Xx6xRMy3B7/nP/icwM/70H/rdnjfX8fD+HX7y274K3/hzfx8//x0fQ7YVz5Jxu0PXz+ZkJIIei3OVhspV3P9SEW9pLJeOCxeUpaCieqgFP+RZDpbijG8HUNUDaD4W81FCCahSYp4AlqjSMI0lEIy+eeo09OCM/gDmkvmH7eupFeFgYjCeG1oJL+cdwZg+C63NuxzOPH2kA+bYkda+TsJw98L5ln22sTZOP6mK1Avvu8vvDziWAywU7fLiR4Y2a53l2wh/QSD3wGpOCzLQFCY/VeMakbER5mQjH+KHYM76NQMXpQtS5yilVA12m2OGxX1YAQez0AWxZxiTn4GRX7Y3UELDHLiwx/+bhzgAzZzytA59B8NVEBm87QpXsMq8d82e18xkMjaubnumoFHnNC0uz0iA1hMUE0XPVJSWwtx5ipE56NTu7z3/nMCc5bEWMEQA5lYQC+qyoNQFjOa0ONSVsZPVwLZXGU1AmVhxq96ZUXrH1rtENEAWZB12TNYFG7CzekM7x3qfcWgJs3t29LYOQCfWPRtTb8y+j3OiqzxqN7a+AfQBgxXA0T68f1E+f+v//KfxTT/0g4fgMYO1/C7b5nHQuAHUMVxDl80ud+3Y7dNjFjfRtUYZGHZBiY4zAZRGkXaVAEcOtULZl86o/Gtum6M99nU9CwCs3btZYB0UexeM1laYrrhtGypVcG0SK5YZbVs1GDiHFRHFGcCQYAPiSbt4NaCC03IW08daUWoO3yHmsMQSQqH3Ddjg3rXHMypAHXPzLhUiXWcC6Lb1irataNuG9bQA/QQon1ZrRT2Y45f00UwvgO6ZpMvlhNY2rOujMqId5/Pi9tnMDefzAqLXuL9/g2UpOJ0qmCuYF31/xcNDc2cmb9++wZs3H+B0OuFjH3sPj4+PePv2LZZl8cvDFoTcGE97bt40zUnK3d0d/sbXfgrf/HO/6lq08/mMN2/e+CZnzlIswOfb+7dY1BvlaTnhul7dxe9yWiQUQWdsTWPJscaSU8am1or1uqKQ3CsstYA7Y93WxLiGaejDwyNOpwWXy0XNU4F2OQNgPDw84HI+43K54NXdHbZ1RdsaHh8e0NYNl/NZYtu1hvW6opWG13cX8aClTAaReMAsxVgxk2rL5m9aIMMIrv2wSVZzJTkDVIrIIqtlooFRKCW0HJzyRhrvscwpsvL0tx5eTB6XbWQU81uaSnqY+mPNtf5C+2yaMTuwZi6r9ablRC2Ekt5lHYMANMFwyl0L0/DWMjtBCebUAjK7Bq4z+sS8dg3UbGEz7D6lzY/HruO4dQEYeKCUVw53oZ+rm1BDwZYBN88LuMaFSIBmmRz8MDMqhQe83jo2NcGuRaTMpGXb2HvZWn487+hgjZmUmB4bp6QtN2a996YgM0mlKcetVMcfmbGEOMkI+sjMe6Iq/dvKGdPIAMrYTPSZBDGem8jdlkfV6c4ZswKYANySz0BCUQ+50e7oB7wcp4O0HqOMDLisf+aMQeYwy04Y6kUSQFVHVOfLHc6XOwCE1hm8beit4/HhEQ8PDzBGUhzp5JA1CHpSbbSZt98/XrGuV5QiXpSXywX0+IjH69X3/BzvFAghoqwdCwQdc8asJv+1uvMeEYCNMSG9fSXmYgZQYUmh+6CgUhAV1BJgMs+7j/+4Ldp/Ctp5NMMkGkC8y1nS/3OK6th5eMp3hllBEhW955UFErHXWIw14jwu8m4tQC2kcTDD62QxR4xzmwC/WmFl+FBo/0qmCWge9m18GjN2wd1uFHz8Zm2zjoeZT7sFwAhqTQhgArZtW1F0bkOIXVErYJpQOSI72raKZguEfr5iW0/iAXM54XJWrXW6q2/3R/POsG2r0qdebaGCdj6jlAqg6D5fsJwWFAVaEoJAfBOsfdXuGH3qOOjeR2D1TC5zvV6vePPwiOv1IfIQcD5V9Lbi2je0VcyqaVmAbcNLeh7pBdA9k+SqfARTkCWY9jw0dxFM20wtZzNJA2YGzuw7u/huB/a2iTmAbdrn8xnM7Fo/r3u6N+Hat4kBX06LeKPUC8uZeYxYRPBNuPQy5APk8DEzuM7d49hZMiYoe7VsLdwJFzXFlIvQcjhYYHIHMS5MTHG7SD3mGfMAxCkJ+x0MZ2Y9/UjNIC4nNr3ejgMZPt+SPs/p3fJZmVanuTkPEGfAMbgQml/f1etMsh1u/jsxtb8JyeMIUI8KGM0kKdWXAW6ADm0nbtzXU+aHwUAXgBdYmN3Nv4xPao8ysNlbJTPrXVE1vyE1qUp3ULUkoXNjgI0BVxDXuwS9ZWY3h+Me7QqmWH+csWX/zOl5ALJ5fLU8BWR/4o/+JwAzfvtP/bhIt1N54AiQPjDVMXEKXuflMgsh8pdzEePcO+MMx5JDMqsGY2cN1BkesHqyKZ/XzcdtwA3SfZKUefzs5l+sb1qZCRB6Zl12tVbURe7NVfUoDEDuF3PzEC+OKFJ5QdeU9jEjB3bhQtsaHvGAbVskhmkCUdlcH2AnpWGuDcwbMCtpv3aPhAEw4pzQJndgsjEc9mA3cx9IhhFwZX7XHIbMG24WLxw7y8nVH335G1/xD+NXv/4b8OV/9+/sBFjpL28HOLRYByvM6dhy+LhqU5lVcwc7i9Id07k0RviRMcJPdOunDNvYsdLJDTq++cVvIqPNx5P5rFca5CGBPaQxKYgtTlGwer9s6I2wbY8odUFRax1QQWWLqUm6zwLcm45v0FZYKrEuUQbRIkBTnQg7XTYJaA4KQAdA49SGRUgIHDvMO6zaaIQQgRsMRIKbxIrk0ZLqJX100wugeyZJbLf32/cQMHsGdE3cP7uZZdZumNtqTq519TuTyJpjE3dYooDN77Ctq9/NAyQenB0UGcTNgHNZFo2t1UKymgBbZwnomaXCrbUAVwq2ChWN/5LMIJVZaK0HKEx3C7tKwamG6ZK5r88monlj9rZQAZNtwlAmWjfkPFf2t4NPTN8jHaiS48PAV4CSp/Pt33u3fGFSE8BLGDc9uYIjtg+w3GZSS9hjPQNzU6tgTi9svrS2aM+MejMQnPo2e/N0qXMCdRnoST7yZ+NA5J7JXJtZln3OY5Al6WM5PHipNOcmpl3zkczttL97aPuYVTJeurisZ7m3YQwCKTg0MEXaN0rtAI1u4YcpzMIUBRuHgIyBX/701wHM+Kaf+jF51K2s0Gj5b187SgfqSdcBFUW5A8DzkckTMs+TzaEyZvsCEm1EPqt/ABG2Wpl3ZUT9X0DaMdXWlqwdIWdUY1iEKzemu5Tqzq9qqd7BrnuQCQpsS3HoQDRqVvyMkHAFYA2LQCQe964dtTYPV0DIQrG4B71P2p8acUqDtkRrzsZBu/BEfuJYY6BTCvgVyczZjszxnJ6Mfm2YkZ2VPDGPPj9Bm44Bb+yff+nf/CP4377nD+D7vvdfCOY+ZQ6hWNoDmXfUFEtxXxEb+mU1vRwmN60vHqGUP7NuE4LmrU4XdsDpX75Pbb6RhrqsSZTn9YkX7G/kvuiHtCf5M/2+K69gQlxSpzCxdzLA3UFQJ2BrV4nlVhcIOKzguvgh4SDOwRacLrk38TbqcUcFRFcz0LD/u8WslT9NC+nn+wDoQiAX+43WZ0PBDECdqhChUzhUeUkf/fQC6J5JkoDZDPRkhmTSoc5+8C66R/TNTCJPEh6AChpvgHm/LISlVGwK9Jp6niTVyJlHSdPi9SbBZpnZ7+kZEAQiXAEQzkPsud11s8231oqNNt/PDDC59oszoxzaMtPglVrcCyY3du+YVCNvV9fBS60oVWzW5WwMLVzVOyOsYRF6K+o5s6Cbx0ywM67iwIXQegKtt06+GxJ+OWznY0+Bk5+SI2hSEWR6FgytSflnhxeZoXiXNDCXQ+12WA3swsBU2P9mvjSDrx2cM4CFbHyEG8z9UVvtnXGcZuAWpqIB4jKom1vHPUCkg6uJU+KJMXRNZBzxwyFu2rSmgG6+o2p1GSNKBsrGTumaUKYgmY6W1hxUjX2EM5DBVAeNOLhRhlo8FwLZO6H9dpbDhDRbw69/6kvRiFT6rWUqaMvAyQClgbzQChgbE4Mw08mNJZTAc4I/03IxTRIQc3Iz7b57NxBn87ZbaqYa8Wccv46xUAAJZ1iBbEJYk/dgKuTzJZYFrFYUibH0OtmnQMCcCeqUmdU8IvATYVpV5xDny1nvKpsZrp5BBA06HgI8EMKcnMTsnGCWInA6TFz7IPgLplbMCs3xh42ZC0UmyDCs5CRYGieFD6bfoU2MfSpT1v4enrRa8blPfQrnz3xG6/QSdkKd/DdFdVMK7Zw3K7cyNdzkJ9QJpDHWeK4UaYwTqCsKYPK662wKUVujUGBEg2DO2j879zpar7dPHCt3fDP+mk9EaYvF2uMGMHVQCRchpGNeDLhyFzCHpnS5oVTb+xYskDtvHrJD14CFiJGjVHmNZBacAV2MrQHBDr8ImpC17ZcuLIPRbheh8A1Ja8x3R+8bOu39Grykj256CSH/TFIE0jSGj1RAJNIegmiQaq0Aq9ZtXQGWe11V755101xpXoIc5G1r6vqaRi0CUWx4HHHqADigs2dLXQAce9+0JMxJ3GsyDZ2EUyi751mLw2A3rSSSIOP5sM/fSayXDcwGYIuDYLl3KNLsuAOiruJbc7CYTUgJ8PhzeewzQ+K/jRlGYqwyKLD+mVQwF5FAmSKjYDQcoOQ0g5MZzNE7/5i2zd4aTGHdVMRR+PimzlFuzg1DKO3TAQfvw8DOlO4YuJ3mbRwLN7McxuL4fQvhsdP8ZVBoLtaPupHqlHZD6IuTdk7XUr6/l4HADlp6vWW6Q6eAbvKiZhpqmw9xAmRtNqaipzZojCQ1U85rx+bY2rnz6qpz8x1/7odw9xu/hr/w+78nADCFhYB5iDMBUeCaDxGCPDHKOjQDmMta1nEKg57nxLsPc3PeDczdbm3eB+byAli4Fn941zqo3xhIB7lzJ5tbW5O9dTebDy3D2BdbD6T7l3mzLEmAU1TglZGPhMIR80syjYaZslNxs/UQKlGUbXc41Q28rSX4Wgl62tFiDwFErKXkdGJAZ74Kta+zQGcC3kPiqZSpVNrvkj/6L30vPv7zP4/XCuii/Cnv9LdVMJc3Pg0aT0s8jUHyPqrP8pyPcNnOmRFM236aYXTUFVqq+XqGFTpScyrHgJdNT25AHup5Tdhxkp7n/U2+NEFWA/eGv/Wl7+Fvf/n701jHXsfcwHr+N/UBIKEB4qd3+2ninKQ34RUIDtxE85bOPB8XaUfrmwvT5WsVAHIGc7mb6SyjiSZtyXsdEbx8dl73kj666UVD90yS3e9iZtEUVQFkDw8PfsjKwSt3GK7XK3rvuFwuuLu7EzPHxKQRyV24dV3Re8e6XkGFcK4X38zNW6YxawAG00zTvvXecXd3h8vdBUTR1hyPrrUcBy5Amx285/MZBAlpYHdaPOaR9nlofyEsJHfx1m3FBtEwGli0gLm1rt5WuUfXNCadmlwmxxCtNawMnC9nB5Tbuvr9RQMBRIQOuUxdlkXvjADBpikjxd5h2eCRNn9PKotkMyWlePeQ8b31RTC1oamactxkpGn4FfWwz4VxJcU1Uklzesi8whmiXKJXU/QTJwDnAJd3Y3Qkl48DMzFmA9gTzecRqLPfVldIUk0DbjQfDKjnza1SrXnnELjM9+ZgdF6ru6DOY8Gwy/h6wJeCJbUR0DAL2xi6xL/3eVehTqki3OhpbhLwyqytAz8QOrMKQeDjC6jAJI3x3fUR3/6//Hl89is/7WbWzrQnRpoBv3u7Z8STAGBmHKd5Gj8HSLHf+XWbe/GVQ85U+lw4MY/jJqOgmvIDUDeD76hv/G7fFfmWOdrc2TQPMROm/TCt1EDtyVNvM0sJnS/OexPRpNwnvyMsZZe0btWMc5H+12VxYKitBLcGMydbagGWis7hJdnuQZuXwIWqnxPWx9hv03wBYsZMsnZcYGSjxeF11obwuq5u+j+bOZOPXwBhL4vCBFO0VQYk5zmKfdOASRY62by++fjH8c1/9ofxs//k7wKTxq/2xRUFuzByqo0ngt0LkzK4GVtp64iVpuWsjbkP4B5NccsBH/hEqz4oVikNBw8h9gA/T4w2D44MGTO2bX34XuZ83vXGjs9WAR0M6ogzEQBxx49/+kuErrnJXPcKNR8CMUDqJrQxo/cK6hW9N7S2oqljNYk3Z86IrH8VpUKdmnHs+RAg3ZpYI5lgbNtEOL5Q0Tt0tu/ZlRHEntMBJg0bz1200K2ow1/xZSrkF+dMR5NA6u0F0D2X9ALonksioHNIkYqCOt94IMGHSyX1gMjo3ABica61VNRaRPLDIu00c0RQBMssRTxGrnqAmvbtr/8T3+hSVANryyLkFwFop2CyCbBlEGf98cOMlamoVXrSZEOMu0bCqGYPhK49SeX6dwim3oAdUdH+czDevakpJrkGr9vmWsTMqVEB0HQchB33OlOAXe/UTcB1kM3/uJ1nPDDNrCfXObEmH1L1hyWTRg5S1l3TMmhKgVqR22uMEzlTIUNz3EDXxnGikTyUBnhT2chtnYrm8b+xLi1r1JKOWqjMRKSqHLAZQO8G5jjiDGXwYgCtTPVbXutbbrwwqHbAU3qqn9Tb3fAC4J445TXnNpWOCEMr0lDauKPHmpuZq3iNXJPuoDevbeadOZEx1kjrfSgzPU/scfR4YEKNTVbiyGAuPfZ+4VgYEL9y4TQW4BnTnjU07MPSjb3AH7OTqNeSAMHO7BwRaoaKhU2RPlT3QNmmsTWgI6CpNRFSgSju3CUBgQUJZ8id6IWAyuKQpZYC0yu21vBIV/Aqe6zRal6joQ2SDrtZsT7bmSEarTGPz4Hh3ug4n2NycDfjBaOJGVDdKieDFwQQzS8k/IeZXuZ9cG7j8QNyoAYMzdSSAmiQbTEE0SgVW4/7PTj/NVN4XksO8OZxSLkO2z+nCTim7dTndway45HGsbyLtCxfvTBaZgaoG5arqh0jAWpaKKP73sYowJYsB4rE93QHWUkzZzTm8RqV/6JOoVHmBgl5U0YyNgGR7usMILxBkTjBKqRr2LZ/dZDl3pJDNPxicPl80guge0ZJmMnw3ljV5BDp8B9dS0siIiyLBKI1iWrvDURLaJxYzMMA4HQ6ubS2945lWfDL3/I1WNcVUDfW5vXMzGSyFCmDq/CMhqE95sEyb+SlFFSuLnWW4OACrgqKP+/cUbnugKLdAXGTtW4mZA3MoqGrRS4bg9VF+BLt4c7utdDMk6x8cZZS0nd2AN5m2vIBSHZgZubmhmYiBgppfOyAeSJ7Ygwon6Z2IB8AH/uOUobMMHk/tUw3adTPt9qTmYrIEw4pjHk2ADSDq/S6M908MQKjhs6ATOq2ccpINDI1OINI63eOTeXj4WCuozf2ubf1dMi4JTXS2KwPmfeUd4jd5bhCwJqZ3sG6SJnOjJGXlB0GDf2ynATYZZBgKI/bOWhBE/fp4C8BkfSSN9PMTv2BdU/pgsDDdxl0URqOAEScScCBAacxmzqQqX786qBd+zy3WNqjveDW/sDCeHq/tT95LUzrTujUwooU75/Qw6SJFuKBea01zSOzhLaQPT/WppjtxrgT1O29Ar2qFiHWZhCwdNEEt97kTh2FiW1PTrxCE0sKjELMI8Kh1A77f8RHCj7N5DIP6agLO0qG4TKoo5trMD2fQGVi2Ycs+eth7xz2EMmc692BGm3sh54LaXi6wBR0AzYI4Jf74Io4e8Q2JfZlFpWkz4xhzqwvowVJLJb9bJCxKMNg5bPI25S+nAPAZxP1L33zCFDBZ967A0qXcANd782R5qoM+BpSM14woLHphP9g0fSVAHNyziv4s5YZoOsdRA3zORKaYWiIBmt2fGLPYodnUasj0lAUqqPrQUExV+92XrykL/70AuieSaKSg2DDNVoGDPKdN3NOktOyLAMI27YNl8tlCGlgrv5NQ2dmiKUUD1VgAb0BuPfJ1po4SelhXpXDJmQtnZlL1iLmmKaNs7s1DgD1cKwkccoYcV9IPECpJo2C2TcNYtUNm4vc7zCTSdHQFdAWDL6BuVqruP/WuxrSv1HTV0qHXfgXJzOJCxkOq9jOI8Nh1n2atDX2yI8I2mcfU2jOsDsanqg2FTjrSEgPoQB0BqT1sHvH88YYVOMI2LxHKhg/AnQGUAbtmzO/Q8unPnLq9b7/YT4ZWpKRIRNGhw0gMZz+mq1D1dYx0rgAGDQVCeQw4KaYWUM3t87y5TnJ99lMM12oSMy+NFbOwE2TYuskM22Z5xO6MS12rOE8qt/5F3/E8bHTmPXLmJxZ26jo/5D6yFu9a+/cJ2837cc0BBEwagk6zvx5AthDytlcg5PXz9OAYS7MJO43Ouz1JBzn/edprn3ArezOYCoKgibg46PA0Q79smi3nLYcIKoD9W2FgXKZstDm2jlgppX2XakVtXc/Q0q1GJyEoua+pRSwmt17Yzmt6QJQpzQnNpextzIQ9553VhH2Do1/HiZl3HkCPU+km5juify3y4kF9xRFzUKrXPBR9Xk/9EDtmdRS0zNIGqAUh1sn0wYbNDOamAVqH57eIa8fCZwJVLeWKSyDrs1/7m/+PyAA3/87vhrcJX5nJwF0vt90MrvrOFN0vyjM6NCA3QQUVNk39E6q7YVmaUDoCuian3t+DYXHiSGIs5lYhemMmftSi5iU+n5BIAhA9T3NUOxLehbpBdA9k1RI3UDrblGIJPCkMTpJwlpNQ8csDKQGG16WBet1lYv02wZCCvad4tRl8GfPvvpv/hK2bcXf/pov9eeZ8bD7bkAwd9mBSjZxIxJz0aUu2DjuRdRSwYUddGaTzV66mDsgQgtwYWUuyUMXiDfO4oAuQHA4XslttPLFs2XzdodZofzIfbxgdkot6Bv5pn2YjKMaeZWUDoAbQb2rTeCEE6+5rwhWUYC51ATKeXY899CAUTsXZQUgmOvdp5lZyXfVAHZNjIO54WcsdvYqGaaAY/1hAnrUrgMw57/NxCzeCY2c/WV/JyZ6Yn4t2HQGdllj1fPfc8oAj2jwYpnb7E5/7J9KdQdGMY31AGgMjCM0ABFDT+ZaumCSafg6NPL5nv/qv3Rm9HJ/j1/4+m9AI1JN+G1O9wnWdfcX+397xlRHQukGE6AbEb8xUgFWj1sS5CZlGCAfGCpbl+/Up1TwiN/2yXhpxHz53qkhBXyGE83Kj+7vxqyS9YPSuPFIk8waWD32ARu/tjUfCVPM2X3mzgw0HclisTvlbxOGmTVDrBk4PZdS9L5fm6YqBHIGIoa1n/ocnghv0dk44KG9BEwAIcURXM374XhuLD/l/xf//X/PP4fmD3taSXu/C6eGObpZRdDiUJC2n4fXAMi9Rbml5aeB1KjgiBK9OVBNwguRo1Jy1shh+m11ZVBnfc3nUhQX4zCB9fyZAdf2fXLtaCXNXR4kZqFfE/YqwAR36W9vnr9omb1UpfE037pOzD8PESVrJlIhLYnVZhYAqeDaLHdsw6RYeLrn+8j6Q06fvTx4A/wzGUAkHixfPy8yfUlf1OkF0D2TdKqLiH56BzFjKRV35zOWUkCd0bcN3E6gzjjVBW3dsG0N14dHPNZFnJYsJ2z1iod1xcaS7/XdCQXA9fERj+vqGrnT6YRXr15hUy9R3/Sj/zsIwC9+8+9F790dppiW8PHxcTDzNKmuaQszAARSbDwweJ2ead7t/2Pv3WOu3ba7oN+Yz7PW++19PPeeXk6bXklblHIJtkHB1iKNMVr9h0SlUSRi/zAYTbwUkaIxkKoEE0yopgiCLSHaSJTEiFop5RoqF6tpilwKTWl7aI/Qc3r2/t53rWfO4R/jPp9nvd+3zylV9vvOvd9vrfVc5n2OOX5jjDnGtsHOyjXWIOfXDddxlU1JGdRGDR3h6c2cnXBbEPFfAmhk7UNT8wc0qYM4iLliXVaVOAujEmamAowbAf1ipjuyw+R9yzaRYE2PZMIZnCDt1ZPJnzJwFYgFxc/7jmvOoPGlwLA4beEeu2zR9Vuui3lLtI0LZmoazJbkG4yKvOrooDxjbTWAzUwRX2rW0BFqfrnGGVzBPABSKqPA0kOJd3EFzanObODJ+tyYXAVReraSWQ/hW7mU8tA8xTEJAwhQBIKeRQoPtYMZPJksl6Dddl21dn4+LgMG7Sc3ETbvl3oze5AFC5izQ/5QJoVg529jDTYN6wFnoGRu/xO//zvwvf/Mr8YP/NKvxi/8s38mJNYHJtalDYDPIbtSmNiYvvGFgYERDNng2j6Qm58TbPy5jIdpmYOJDYa21HYqO0zL9mtn10qefxz3w46PH7G+LTSArYHFxnN0QMeIEQBn9KGWFTJfxHNxcNfCl9ocJSwUc4SIVRsADVXTdPwHrteOt956S3Lh8K5IFj5hXXFaTyDdK2y+XK7XAlZEeLcAY2AzhyZpXre2gEk1ICxljwzkdB323t2xzR6cCy2Js7pGk20UdH1mIKJorwqGqPwr+E8zmbDIZ/3wX63rHahmiA5mph8D7wIAACAASURBVLEuZZQsnf5bvzFiTwm3+rWeZG/r+HSISw7zihrPHcAC6y41E9SjeAlMCEFkAC1TYQVUpRZmuon8LpS2WBX3O6BVgxj4hT/9Er/7yz7kclD20m0vM6gq7R0mnNA1PAajtQH0RUEXdM23NB6MEMPqXxJ6sAE2BizAt9FqMZHsYrK5LAATFmreD05VJlJB2j+zX1vf58hGSOgnM3uIF9LxfE5PIz0DuieSzNFJZjCzOeN8zwCVBQC/u7vbPWvA7Xw+43Q+45rCFVgAcAu8zSwxYOz5+/t7mDYva/JyypoXIJhosaiIoOFWL48v526ydQNP/zE4zC7tPAml8pLXtyIYnLQdYcqixNbBhIYjWJLYDRFTi2BnS9SjGzkpBiaCPacjsly6zPfEtCNw1C1LQqkeYijptibP8k5n2Uq9o83W3/69ctq1joTkpGMP5g5rocDAGJHQTsh184Ln3vBupNqGYEDsXj5nKdfmMyrsmWTAD8TcDQaYFMBFdFlGgL5sAlf5RIXD6j3N1gugc62HIwsDGXv4YNnNfZHmqTMH7CBbcYyfoQPYzXjYJ5yKEAgO5iQPFObqx7/oSwFmfN6P/DDuXr6Nj/7wX8V2OocGyEIUGLDWtuRk/KgrGXh/s8xGnQ+lbye64m3PDDYnBj5z1ta3pY8nxtz+KbzZPP+Ph8HGKJ8kovKQ9bfecfCRtdRVAAUArAylCFmUUOmzFnTZzlVTeoeTV0ivQhMvv36uSDta+pg8bEDvHQaTDEBKIHvIGlgR3jdH97NMQMw3CWVhzqQa3NS60GiNX6cnwgihjStjbesyAZ1AbRM9NPriVzMNuEEfq8TsBvw4TnnOyNpCgAiQx1f1a7cyLvPQ1tFukeymoo+x01VC45hpxd/P3L5U2dyVRod96fjrjNLY3FGWB2lf2ruExzYlMBiNgR9981wqaWaPg+FhlZxWJmGMzE3TXEv5NMRRHGB8gmgf7Q8sTq1ILX5IncqZ4sz63aptGrrme6PO2wbb0KQLaOpk/WJzYWDeg8j/OP3FXn2z257Tuyw9A7onkogaLtcrTtsmy9y8XBJw3Tbg/h7r+YQ3iNBWif/DkMPkXSXs1BqWdXXA1FUaalLW5eGC3s3U0QLZrnh4eHBPkRbHaAzxuHY6yfV1PblWIUwtqcTgMhDa+4ZlXbG2FRdcHIiJBmQfjw6MOKNBDZ2GAzvz7iXxkNglxbRMHimZXRtE1HxT33pXIKUEvzVsW8eyrFgWIcPiAVPb0juwrmikwX5JpJeNbrB8mVNXJiUzmDPuKZt34XgTa0n10/LJ0mZjyo/KQNqoyLgLckOgYI6RmQr7N7OphYvdbV67fWjm4DlMx2zXEh5AY2KZViwxbwb42B826Sp8027M0Y/OPSUZte/YmftKDCARCA2tcQSVP2IWfQ+nAhBqnygTYYwIeacHEKIwVSPIXPQTTK5VYD+f5GMGVhBVBRg+9hR9BkKaLwmoOvhK6MUYaRj3I+3/Pd/6bWAwfsuv/2cVDEQXz8DZxxfYXdv1Ufkd73D+J31mcOdzZMqqsOW7+VmLjraTTgubEFzWlI/KHGF5ys+0gblm2b+jdYNrClJ8NW+bDU0BpfruGOLxd7BoT9kid49gzvXVliwkWAs2bUfuRrZnnIYyqMWqt/xkrkZw+6Z0HWbyn/qabHycXimjStqHRoBMGDAASuELGOTAsuSJYH9Tc+vMIVRPl4xyQcaZYFYLtkYUxkTeMahB3wn449/8rwIEfN13/OcwYYjP7UwmvSW1/mlQJ6CEVJ+c3zTDgyzU2a+aMmYFObAlLOcoC22ep7EOn4E/IqSxSE5RbAihY5DoRt4pjtbdnPIeJnnLHLEwLs163Tswne30ERGrAk96xr71LmvMTSR1/jFhsLSmMSScADXQAgmZ4VsHadEyt7t6/V5XBqtDlUELMGLNS/mjzB5hhYw/gThB0TFx+kDNw+Q0WnyNyQt7nwjP6d2ZngHdU0mN8PLhHstpBUO9My0LBoDr9YL7hwecX9yBCVjWFbQ0oElcosGiwm/rguW0YlETmW3rck4CwPl8Rlte6uF3QDbgBet6wltvvY2+dY/ZRtQwhr6/bViWFXd3d+LghKEbMOF0auh9+N+6yrm8y+WKN/XsHogULMr5Cgv0LFoQkRYvizAmKwjLsoH5CpMkL6TgM52X62N4OAI34VSHKUBlcq7XzYPstragLSuu24bT6QTAYtWpM5nesRHhfDqhNcK6LFiI0SjV+wDKZGbNN+/MrKWUmZAwtpg53wAxdbcMLZc/mcCDb8EHu21muvJ1fzJt2qHRIGc8KlMxVdcYBf0Sh+7ZQ0iEiZzGBjRtmJbVdW4ZSGBOTmv8E85IZw1OaAPZ+6IReT4O/5yRVkaCgUHDGWE25oXD01nM1To+MU6ZM/KOUJ6TVLjAhWFvMSCpDweAJY1hCE5MQCHVHFPbrZ55DsifacezObS5w3ftCKDjoH3jjHl4McxctrPCzlsn1uZA1OxwJ9V3nwxoVTa7AGIY42Xd6Ow3vGfZmMA9uPIZmuodL2nuTRlz1WRlIGHtmOtVlmhpG6drVnYy8UW8TzDTcDXAYl0PI8CPDa15KrbyT+czyNeP5H29bgmkZWQQni8NKBSLEDKPyKxxvTbVUBjtHWXaujAtl4NglO08uAsDmnnHDEbavHIG+FAAiJzSfNPf0u8FrlSwmQCXNL1S2pxdCMvgc/yHftU3AAD+0e/4duwTlyJjHsR+lM0avZfYvuX37dk6n+1eBmfiIZZ0E2H0wR7GwCw6jLbMgrqs4PR8FfBycTlpO9xkQJkEiOUze/XIbbZ9gCw/K5xgltRtWJ813V+bhpaUZwebZldBnbVJ1y1fu1h5GA1ukjc1AI1Bo4GXhoZFkJ3OQTD0vB6cbo7B2HoHb5vyJAOn0wmNGpjsXKmezx9dxlDHu0HpLNSqiAEahMVNQe3IQENrJ+9Psd4YoGdA92TSM6B7IskO70q8uIGmO0xrzQOuzp4l/SyaHm7PUnTXWGne5jDkmgJZ2nV73jf6lE/358+Jsd0DFUvCJ6k5j9qqh5OVjt6FQa1OWczM0cqtG3Vtl/1j1+WnaBQ5mItG4M4OPtsqIKKRHIyOoL257hySaYrNxGpkfzdiE8td28x5z7OnkoLJNJ7ZAVf9ffxefibu7b7bJn27IklyXZtRy8gcfWYUvFaFmfJxA9WYaspo+JzL73LN1U1kdCOMs2yJiTdg44xKNCrOqSG0F1DMdZBH6QZdB8wGQGrg16Ix5JxPZYR2THXuosyMyqQtppo1sUuow1yS0BowRpjQAUfPxJk5Y87F1DWCcR8WmccizcvQXE4v3QRz+ZH6TBUuTEz5rjp7bWCR2qd671dC1TZGdW2Q03fK653K0smA46h+pS1KB51euXYnmGYHdS1AK4wuje5nzWZ6aG1fluZjDJi1BJf5DoRjE9svxHxyoI/mdQlBG8X66R0bIM6sADeXLz3KCDN4EwakkCV70hJzNGsVKTHyVJ4PWhYk4hGCla+SD6nkxA4JAmD4s7uBLtcpgTTT8FkZ9R2esrCyDIgB3jG35nqpCB981zqwadnJp/EAXPsftDvM2qVoLlUgA2Z0VNoBiKOj+zG2t1piT0dO5GCSETEQrXIy3mm9ce240btE2SC4R0rra5mLrGecLcMg7Jw01JJ17P1dLZWM37K53nwvjdlDqb85rXNZR2Gibk6FzDyZmdGYMBoBO4Hhc3q3pmdA90TSsi4O6h4eHhxsWTgBA3uXy8XPtRGJMw8AyKEG8vm6Ggqhgbnj5cuXYoK5LP4JyNYjGrkF5/MZvXfP/+7uDqfzyetlgNLOyQnDIIfvT+uK+/sHEF1AJO9eLhc8qMnn6XTC3d0Zl8sF27a5+aadEdk87IAQxmUhjGH+vYYzQWBjrg0sdnFqsQgD0vvA5brhTIQFq9edQRhdnLJYu6U87bfrBgw3BqnMl++CVbpddmfXgITJT6COKCu9gABzlYmsySSqpSgUr2jGO0xbaJXI66ZEdQPNDIC0K9Xbcjri/p3nyp4t5Zo4cSBDMV6HkbRGVid7rlHMh2pqGIVlpzpuwqsM4mCVtlpoAANMRBF4WMFadSFvDK0ypMzofe+RMs95z44FVInAJYPeYICK2Y4zswaSDITVsRVTZht7aL8szshvW3eNTmZcgWD4o9/kXRtHczyybVsJtSDnpLTeROrK/qjOMeVsPTCAJXnSzGM2n3XMv4czXtg9u5tzbEM6doy53Ob58VRPbZov2Z3xnc+DWUt+G6Ay9lpcpLlVmd8wh0VxbiHmh8PnkbXTlqxrvmRo0MEaI27F6XTCYHFmtaxLCMrU2/DgoRYXV4BljfQeAcNBYcpsewlrGIPT6Yz1tGJdVizrCmbG5XrBtnWYsMP6q+lRAE7IwgQdWUtrsVLNIQ+1FgDFu8rRWFAlx8t5zI4JJqf1ZHtJ9CXydJtyC5rTVHudvRvanN5Twr1wZHYUwrvq0lSXY6Tn45QkcLEWIefLlLyI1ooAXlzw5Do7MjDHsYYT7czur5zuKC2o7Urr3rKwPYUtJygQtmu5NeRYq6k1jgXn/u++7CMAxGGr0R2iUUE3A6NvIA01xB5MXOYR6aLztuu7o3fJeBFnc1b/PiJ0h5qC+F7QFNwty+K00OaijB2Du/Ago4ujLHGsFfS+WYDzvC9bsPj2rKF7KukZ0D2RtLQAdBYLzpyaGONqHhrl7FuNOZc1dwAcAJoZojGGzIzL5eJOUQwcArHR5uvX69VB4iqHzgqgc+1fC4kWAPS+gRk4nwMwmgmPgUjzuMbqis20MpZ3AB1j7qWvjP03htPaxzxAvHjQcStzDFlGWQJt/ZPNngaL+3m5zli1vAnXlLQzNUIwuxV8HbGeyhTubtxEdFrm9Jwx2oRyyN0rboyUb9XBFLy6DBzyGHtgl7aqxHDtpbYG+PQvObnhZNoZzLQAY3mGnTErcdsWSsyv5TtcQ+cl07EMOYYoNAbGENs8ye21MkwzIlhoqJZ4gOdWJ2a8lGkMLJtX1oAeFdiZYIBUwBEuMENLzTnnBJgyIzqzwQHAh8aYjLp41X2Oc5pHDuaSZgkkWoOsTZ8FENVE+DjF+s99sOe+a4tThcu1Uvi0dhgmDDGTtHk1W7Fl1VB8F6YVquAwDZWU6yA5V93rzt63BBJRlZ7hdQ+oCSRLDPEQetgc772LyfipQc6FdpxOzYUmLnjoJBa9YHTqQDcm3Oo6AI0tNyz8AMxCzc4/a/gXPcvH5gQLcLN2oiaMemM0DjN5TmDH5xyHFp1AcXbLO/0YSPt6mi+mMTewE+vEgPSEncpow4G2X7f9gQLU+Xc+nGVTrSoAy/PI5oxdcG/FpSUz/pvBERLAlYk4iNSxcxLaTSg25+t7kCIz00ZSqvfcZWV7sH0yC2EQYI50Pt9a8U7/tV0/9eKUgOHxs4AIgYgZraX5YrQ777eU2zpg8e/IBpYoaDdb8HFdW7RgUOw5clyulQ3SBYN2Bt/6R/Om6W9uy2O08Dm9u9IzoHsiKYMkCyVwOp2KNs7CCbzxxhtYV5HKWniBrC2b88nE0gCdnCELc5zv/MZfhPe+9714b+84nU4Oui6XS4QLUG1LNvcEoEzm4vWIZJt4eNQz87AxQnswBmscONN8tKIZWRYNDN6XZFLELvUqoLUtWBqlPjNzNN2cJ3PVZue5kihXJG0AVoLv5gfb0QzmGGljfEfpce1cljJnlmC35zHAxGjJdt/qZCZRVt6rkvKTlumrau/ZEk9tMGZD54GY2QjzEZteMMO+wSVQoFBNBb9HHl8BGHBIzHB1M546cSrT9ElmMuPmu7v5PDEtiVmPes7AKUD0DuhFF93uWZ8XmSGIPrC5XeuY6xeaQ6ljL/fC7JK9Jg66gg26WUN5LhVqFxLXOs/pHUBMADo/k+8fpqOYUEfcpz8fZRSG1CpsU937RmmGMabTizG9lD4kxtYBuzPbAfTYytR5zmCPs9nda6UFC7d5jzSfpREmzGtEbuEBqJdVcGgguM5lE5A5AfH2GkOb+p2jbrV+1UvqTOvFs+UkvOHsTILVS+fQ+IvTGL8DHndmiFknQlltOnhhdhmFzLOL0kDnPI75bvY+OJ6laV7AgE6AV0MWtV5T23iqae14qwUstEMDhI5BjzxEcx4Hi7uWHe56x228mYmsnS//mQf8xIsT3lrbdPsVa/yx+mXAemNsHOdqXfSq1MslQzNATnMWas6ZyszCZqu3m2fauBDFexOgm4EctWeTy6eSngHdE0kZiF2vVze1NG0cEbkJ5JtvvunmkqbNAwJYGaHIgC5Mtwau1wu27Q4AXNMHVDM2C2kgZmcRGBwUzFYOgWDlRwpmMICIOjXpQzxD2TalIMrAXPP4csY4NCyLaCb6MCYE6txK7N2BLoeZWZ5vTYOTc+QDirMizGqupFJ7J7ZjJPO1E45adDORF/POMd07ShmY7aW1Mx9zVJfbUkF7OsyTjmW0N8abEhPEEV8sa3Vy/cmeL5ueaaACyIXUPuoS5dszAaYKyJja6kw46WZqppkIaaudR7K5Ud6fAIl958w4FHTCRTtYYNJucCq4N411nqNEuZ6zmVdlPkZixnNx3lcjgb00PjMo36UENI+TihNugDqrn32+ip871AhT6IFLPWccmgDurgm7d2K+lSH0RzOLr0wd8pySJ9VQDaGZSsxkytTyGizS/a5eeUlNtoKxlBxda6JgfLteQSAs6+aWFG0hEBqYhrdlGJhSAEHm2Rdhljx4qHOppGVFmmu9oyvACJpuTLFBVbmaz/VZfet6iXqJIC66NNOs18d1GaaFxUK99xhEycCLdq/G9NCnSzZZI3izWvHTM5MyDeS9o5Qr4PRROm8A6rpf7V6J9IQa7TYE6xGTc7nwoKLFG22Z61x/x/bB+PBlw3d+8YfQ276dRbgK4Ot+4hMgAN/30Q+8Tk9E6XRQ54TokigBE8FDhtM257OQK89f8+gNpz9wHom1I7NgctbOZVAH2BGD5/QU0jOgeyLJtGsG6MyMcjavvFwuDtwMvGXQle/ZdXt/WVYApHnLORkz4VqWBjnDsSm4sjM4ACBBij/yoz+JseSQA8PLlPobWLJzRNIeAYnBnIpJj4CmDFZbW1xjKPXbSv7LsmDpWkceaBxOAUw6bZuIXZd66obHyhSrp78xBrgNwMw0yTwjDvB49QZbJISajJGjAjzySzWPY4bYt1k4sJpSxio7rYSDJL2k3gPNvOsWm1QY2OzuOxBS5EkTM68cFLuEPk5jMNil0jYGoGDyo8/MpIy83Tb/vD8mKaeNqzPO2ohwvJI26gJq9L1kulmZTgEMNmdTI73/hPGt49y0LWVgyIfFgaZ9d1O91lAnRwC6nB1zmBebCZn01awhCW0410E0jiXAL4k26Jt/228CAKyLsn+UGE6rA24zn9Ke12FMs2ZzAlkOvvZz2zVMEGZqj9zSz8I5p8xzHgDc5BKZ8UIA6ATDTfhAE1Ocyyk0ofKMMXuUBjUiDWYcgcSjP2I+ZhPYQQaQ5J/BjOt2BT3Eumhbj/ZrHh72haa2MiVAP8BbgAPfU9oGCQi+YmVWoZjFTo3nncam8Bs+h7Suu9mRaHPuzXcG5KrAgDl04gV27AfuEIOBgI/8jb/uueelM09vL0GfOdoT8jxN1KUAyJEdphRwwUF2OfKZkKEDyhAe6LwSIqeEhoGWQqYg7TIEXfNT+4IIA8yl3tm63569KeBhAZq7y7YeE03/+X/nbQd0Oc9C8xH8xH7dwgfOabqC25qXdQI5zyCaUgOBWbjDXr4fbUlNzWDNKmF7UKH30/Pz9+f07k7PgO6JpLaIA5SHhwc8PDxgXVc3rbS/y+WC+/t7fPjDH4Zp0Uz79vLlSwdyL168AAAHhuZchVrDW2+/jZcvL9i2q8SLW844n0/4J//EXwHA+N++4avw5ptvYF0XnM8nrOsijlI++Sn80v/5L+IHf9mXY1kaxujYto4xetLmrQpIN9zdnbXOVz071/zsjzgjEU3M+XwK06HWsK53csB/iJdMkxafTiuMHL58uXmYBSGaC5ZFzzq5CQ9hWex8IHv+CzWsy4Jtu2L0yGNpDWwgeOu6M0poA0uyV4bEzj73GhyU9woeoP3GlFNcOmZ052us2o+KufJmIxu5uVY+AnQ8fWPO9cgFVmaw1JmCMRvpZXvez8dx2sB0UyQDrVb3zDRwbNRQsDebPfati4t0GHOSTcoMvzA6s8f+sY1627YK5Cif12yHbTXzsdB6G5NOHpLBAWPqXUqMgwkgol8t3zq+cb4VAIaaJ9v6ibpt6m57ZoDMJLP2Rx6fKOML/+aPyHtrnDk14G1zKmod5oTFLM0GwZnMJBgoKRi5o+Tu1Kf+eyw5M6vtNGcOBZRZiAbngBNjvecIS3W5doA/Q7l9thgReC43XeJtLliXRczpqbkDq77ZmWdCIwZjuAaLwR67ywG2OcC6ytlqA4qF8dQ6v/HGG1hpdfOuWYiR10DvcX+Mge16xUbAsm3oaT9q1GChV6LvvXNh4TZIB4fH0PB0CgBz96Z4kO4UN7q+TKBK3+SJncfTady10Y8CDnuSAPya3/zvxGVvU6XpA1FfMpo50f7SRlAYGGT6zOoPJBXhj+U1kKtua59F+8/JqZDROx6MRl1ispFYp6xujq/l+PcAcy6UyftVfp7rp1fPn93r7rQEfa7Sb/uMPVGoyl7YU6+t6+LzPM5wGr0yIKtn9weBNO5uCG5NyAkF1WEpZe+PvqnQL+qQj8HYX3OPs7omeZT7c3stL9+rntOTSM+A7okkArkmzc6tmXYtE4rr9ermiJlxu16v/rwAouHPAlDHJJFPdirRWsOHP/ESQ4O89t6daDlTcNkwlobLm3egdC4v18W0aJeHhyCWulFVCaoQtayVZDZPdxZ/rLmGDbD8QyspXhIZrUU+29b9HIi0NTxIiUc3Ai9QDR3cIQcYICPIJGENDgHNVP95E9oxevOulr1RHufs70ef8cHvCnRmc6xSpOXnTPnEMezaFmXGg77l3663M7GmFZLXGsV5PmPEOD1r2kMG/DsmJqFwMkcbZL5tT+tGbYyHNc6YQ9MYhNMGBYLAboOd528wkLy7Z5pemIR3AjtVO5kXxfC+jzwTEHHnIrZmw1299QOnuR+A0bQpGvfRB549hANx6eyCWYzZqYxqnTwzqNvf31/LDGR90vpV2owp31iXUqeypLzi83vRPDvXwgbmDHykeuXq5CDLCbWVPIurIQW5AeZqbxrob+oxD0R6Zjdo126J6kR2urOrBbvgq5E5dSIwL64FNAuNZV08ZIt5+bW1Ag7QOBIT64IamClyradND4/TNcVK9MoSdO1FoHXvw4kmKM6J19JD+Znbc2U/ntInaXDzXTomiVHsnqYXTSyVL1BIoU1OZdE8fvsx3bck0cX0nPWLOSKaga8IAfRZBtDgtM7oHea9GQmw1eyyrOKwp+uzMV4fetjwvm3g43er91nmXW6lvL/eFvwYgJu+W2OGChIaofG+d2O/EOuKgan/Rgcs/AgCgM1ALfM/El8u5rZPk4OmWp2f09NIz4DuqaREKMxUMjsdydfnOHJEVBypLCr9BeD5GEO3UHNiZ4fS3e37ELe+fevAWZ2O6CYtWgFJS2voVifVeBAiSHdIdyVA+umE1B5lEQsVCwY0g7ocs0WY3DAnjfwCqALCqMgZvSC+zFJ+I2Gmgi1NphQQprdTMOqs0s+j9NhGpMP5aMqg0ABPugscgLodo6x9QmlXvgW6gik3RvZ2vYu0myi9u6+/Vdf4aANKJqm19+Z6+fMZxE5mR3swd1B2rnitoEphERLrmcm0eZeYInN97QDVJMYJbNm42NEHUkY9pL36rjHKzjwSSlemOZC1aXJtZniin7I3W7uXnbgEs0EwPYL358je39JcB+MPf9OvBwD809/1X6Yyk+Te+oE5xm13Pm4P36QUnwiFnQq+LxitHPA4m7TWSSjzUhhPpQ+4MbXT8ol6WxcEUxsBjtO8oIY5y4LrtO7DQJ2qahJeKfWWmIqT86q+oet5yP3zRgfTSuHoR9PIAeLjXehvYnBbNv3SawwMmEfWKIeIsC4LBlVHKgbuyOdLXUc+r3UwB+ezy5G3C+KmUCACBIfPHFZhQ55YQgrIaY1NGaOP2QOl1wl1HloWMZDzPJ2fTkx5yaTcTihsAgzpfgaSVDLB7lfNng+etvuVNphwYdcCLXwMCXWhMjav8ix0MsBsQUF8XfkaixoWBy830kfvN/y195zx/7xxKoDudQDbo0lp5mANeeHzUv68rrEJTD2jzxkY3vUe6vOs5/MpgJrPPw02Lkf8GcfjzOnPKNireYXn9O5Jz4DuiSQCypk4c5cOVEBnZ+vydSJyDR0zu0mMPW8SW/f+qDuMBLBlZ2IAYPSBvm0AizS72Sa99diq1BEJwbxIIqTfiwAoYzBNe5YBnTg+MeYN3hb5LXFlBLw1ZyayFrAtrcTYC02fHuwfHUR2Hs88ZnaM0crmUZh860vUe7fAlKXDzciByP6dQzDC+yfjDBv571laGt9fsaNSAlQZh02aGcukNof0TIx8Z7yiDbFfvSJVkyuZk6UaCZTUt3L5mWnEdD2AHJTRDPBuxVjcIh9/Nd0JJizKC+Ah6ciL2b5l1vccYIagzEjVGO6GIzGqnhcZA5yfkXUTsdxSXQ6dOARzLqZGksef+0d+JcDAN37nd8wTTMdVHdxovYMZmcYoN8QFDWlwfboqGCRMB2wCzPEOMJaOVY2Yf0k1SYz1lK/V2EGP/i1tAnSA08syVoH2Uc4dzQA91SADpziDIwKxbevoPWh6Tqbh9rlccou1L95l1SqB9dylWjoIwxr9bzqans7mLUsTut4algToKvCKdrKfSYp1atPEQBncu7AI6Ia6+u+j65nBCFfj9LJo7B1pp37MhIbSmkn0Mq2zR40i+bWnHgAAIABJREFUbpB1AuM/+wPfDQD417/pVwd93RHpECQEeU3aWukqv/+YEHA/UyvAPNhJ/CJ7W6zhMUtKtVmd0HAInkQoojYe1peAzxFfvzI0Ua+M4nb9koCfZtoLTc/7/acJ5iA0D9xAPMCsgo0ZT5tkRT8qWajg79YuT+mLkTQDdb4/DAk9kvO2mRD55jURV58B3dNJz4DuCaUstd1JQQ1wjeEatxymIMedy6p/0+gN1cTNserCjjxAYwaMlgxcSj3NEYltUsFUh5mlbPrresayNDw83DvTIsA14taZCRkUIC5LgLfcFxaEd1GJddSzbhBZI2nXJSyCuRU2im/aiUixB6XdMm1cM6CYE4MRMv3jLSJr525taFHNYFSOCL8x1PnWDChyVWYNxXGK3Jy5vcEYRV+Qf+T5VMBmBqTO2AcoKncpmNFc1tx3OS8vgmsMsN16IpOMTppivV68CzrQqoA6gzhK1xgMjNJQOIhh1fhmRyxaa1ubc1fkuWjlt0Ye6iOmcnArpt0201fTlueUhURHqWFqG7jWmYVhy88c8HVelvRNSmldUWp0mIxWUBf1riUIM4qb83OuizFaduZGPqXv12Upwi0yDi7NIdEwRWgBqbOsK6/Hjq5MdIAiXw+wzQnY1KXgfTxY/uHo2Ji/lqeCOgcSmratwzwC27m8TD97BzzMwOQoaNfvadxsnVtb3Iy9dL6tZQ0v01P4A2OMncaw96GvU8sDE21OqQC7Q5VR4eR9TG4x8f6O7S1OX7jedrp6kLsBG/asDiBapdx2zZ+lVM5c/lx3X4ixIiuomzTHtiZTl+36Iq9TzyydGzzq6htpBnOvokHze7uqsQAkA3PsND9Amu8wgd3EGkPvZaJeSmEA+tyRaaWfSUbwZDQGeDQRgDoNOdz+PiMg+5z+3k3PgO6JpMEDp9MJd3fiFCTHVzMHKeb45P7+Hufz+fAwLTMXEJdB3XKSGG2X+3usjXB/WnE+rXhxdxZX1x1yCLh30eadTnjPG2+AR0f71L0TSzNdPK0n3D/cY/TVCWQjcUbCLM5RhGitOJ/v0PvL5F1TGNPejdKKyaR42SR35GIaxsvlAafT2c1JmaXPxNnKCuYNp9OKbet4eHhA7x3ns/SdtH/D9QJgMF68eCEmqdpXo3esSyubgZwnHDhlpxS035QsBd9O3hfZw6BLD/M7E+DZa2go/c7mZxQ8IQMeg20qwE3SJiD1KOM7McwAJpf3mfE+zEHdpmduvVbNTFxyn7W2gJ3hCBPEAm5yXbg0KvLnxJQimGuwaK5LdRJjk5ttgocAQz05SpEX8/tsXF32KmlzoYXp6HBm2TQjJhiJoMxJ1oDqoTKY2aGhNWQtSf522N/LUkdDFrCcyIRACzKz7t4yEcB4VYHLhz7+k/ihr/wK/JI//cfRMhi2wXNOiRSwChsVZ19rOphaMRbWp74coi1Sz8SWcmQSghzNYwKdhcnW9dZIPeZSS4IxMVdsOy1d80pmYYKNpcRmG+JkifM65zCH1PoQEdqy6lgB18tVzzkH4xjaqhBqNCJ1NJS1WSEABIe2OIM0mfYDowNbf4nrdsW6hqMnG//hdU4j4qAKUYaatefwNq0RSC0feOQ4c/J+Uyc08pzQ7K1vvgYcsmXaqkDdBDJaGZjOw7xo2rjb/PF5YB5KsrbOykgUINh6KyejE8mvQbQxhtz87GzuLgq6annZmgo8lKmnVc1oJElQd9KcdbNpRuS1xEQK/FpUodLUOdkZa4YIBpqBcOjZMY4lbSDtyGw1Cy8GKGlRU1kcNTsNxmc9bPhfv+iDZf3Y55HQ+qfuTqk89nszCGLWs5QMgAcwIPzEULBFYnGxEkBLAw9g2yBWGYs6WWMLrRHjl9c8IOf0geaCMqFvGTyO2Lt6B3FTus+uObc9ZrFsbWidhj6np5CeAd0TSTzCdFAcmNTzb3Owb7tWTM5gDKh54EumlMrYCYiR83bb9QoeQ8+VBSfJPGQTXhpOpxWndQ1mNpXXGjlTozcBhDtrA5NiPhmhF4zJjhhyUrd8bogoS/CEyV5XkcY1PQcXz8HLsIDk1nfrevI8xhjYVNOYTTfdHNQ3GjgxP0pHoI5u0uQk6Z5ATdmckJwMyBMF2Blzm+87kjkq+5injlul7JtPef3t2qH2b/fmjlvf5RuMQwJ+qc8DCOe6IN2LTd6kqTZsB7AWICoxCGUvT32XkVR8KDgwgIbdPQMyxl5VTaDes/mqHWL38znPfToG6WEGN5CZIXN6RASPPdf7BuO37F0XAvi8zIy0/GP1+Vd+x3+IX/tH/ix+4o/8T/j8H/vRCfhWBtV/WIHTuPvPNJdKW+2hNK09WwPMoJJ91szO2ZuHSy9J22nnhV2QQtYX5AxamFFWDViMkpoFsmjrmtK00cWM0OK/xQqKVM5JKxi0/K28zKbX7p0Y50lzYPMvF1znpPVfOO6pWo0Abwwzm4yOlUeFlReNL8HPOZpwwJoCi9e1OMNPnk8AXJCP/q5NNidimgegTaSxtLUSYkY2Q6Rdf8YspmQ+mSjUft9DaL28lDLPCHKiMoDPUTiAaGe8XH12yESP8im1LWpRjWn3tK/0g10i9SRK8Q7lR1K32T2rgtMTGxwnLlFcpsEffXnFW2vDn/vQm75n4+Aza+r+2y/+EMyEPlsszaBu1iKLUIEBGgHoAOFn1OpicAcNoDUd2yQ0iK1mmkMwqyQLzZSfMWEM6jscbYtuT+vAL+I5PaH0DOieSMqL3wCZaZpMK2V/1+vVwV2RGhczGiqEz0BOJozmLpuZ8eNf+fn41KfeKoT1yLygmuFQqXPVWmUTNdMoVbNOCXfQ0Dv03JuZCwlzsG3hvU3KEE2DgbfsqdPqSg5OMzsVTHOJ95QY2+Ge4WIcXmUKshvDicnlwozohsy1345NTiqYi0/r9yjxHVbw5yQ5U5k2+cxMuYaO6jvxlxjzeaOcy0FlCAEDiyY9tisGzuDgr+7bcS8cjByfa0oNuXH9eK82kBCmlUkTxMm7obc/r6H4bSA3A8H8vIC9gXlamWAkMyllfk3M9N39S7znk58EllbHivyfqYDpM3/dzfE6ammY5izkPu09ve7y2w3qI8kEAGNgUEOjgUGENgZGAzAoFA8k3iM5aVDF1FAFcAqSRFAm1gAiJDKEIBprA/Bual5M27OpJwyJCfOd6CdAevbMGESKCVOEIPtkTlAkviL52VhSTUbQLRaNURKuyLWgv1mT2Fp6Ji16A72ZEsPawWnm0SQoMuwSyKEAZINKYe47QayDeT/f3C/dZAFhQGASOuzeOFj/JqRyfaKBoQPO/QgU3k6fCfGWDp2BaM41HDhlIBpaPatvqUWer9O3nB6SCeKtdCSYPgJwj5lfGh2dbhR6Guh1aEiI5tpRfRyPSGffUTIQtzPtt5v7r8/pXZ6eAd0TSnnhi5nhBRZc3MCcaejO53PR0GWtVAY4ABy8CaAbeoYNCdAN/N9f+wvw8Y9/HMvPfBI5YLiDLKU6Vp9gMNRsx8+tAQClDT5ouZmEzcBMGM3ujIbV2Uwh5mutEZqCWTM/k3ouaK17Oblfl6WpE5iq2WCOfGcw6+8fyD6tPulX2rzTtTrCpS/S5bKjG+Of+y7eOdqWd8W4NH9mlG88nr4cMR6JbTraUBNoDSYw3qNUkT081SyG6gSKZLOwgvtiOTrcwFhuSmZSPJcx0hMIQYW+P5siQttcu4bc1T+lf+SMXAWvCQEkV+t2K2/0s0v1PUAJraWBvxyMPPpdNHQVLsUaUobcrqW1dZQUaghjR8ag7sGZObOQX3tEx/7cjVIeAXP+lDFdaWbVcd9BxD2o1j8T6AyCgLnW0AaLtdYwCb/0MBGB24LsGt/NqGjx721roNaBq8Ri7L2XfpaQFhE2Zrh2gKaaHsCUNFdoVCFQfnP4Gqx97fO7D1DT/cHjLKqTKmWIBeRyWC7CtGoDY6gpWWtSEqvVhagkFIMmIEhpTmif+5qZ6PQ82H7mNOep/9T3jNblHuNpPTk+1u8TfeUAXZlGJepQ+ns/0+wG1Yf85q1ZXen58U4z5TE9FGthX8+buSQSO3elhchgAA05JMJtXHZrV3qjjzhr+whYs+u30iGYy4IME+zuX4TOYLekqKAv5klQkaEtj/ma/4CjORAdeURz9g3afXlOTyA9A7onkrIra0CAk8WjO5/PDuaWZXHNXZg6wgGbaeEAlLwMvAGM08kCkm/YtiuYGcvSsK6LAiyR4rcGLIsAup4YQiNCdlYme+Q0T53GeAbDgiKhNl6ytcW98zEH4Ze2DLdbF15DAd2yYl0WN/eU4OYnLIsECJ/PWBhw3HiLc0zgkMAD6Gp6av1G1n8Tkb4lJeR5V5jH1/NJm/eUT/zca+jm359WepxbOEyfznaz2+hS8bv668PDPCjOeU1MxC2Tnd27BsISp2Hn6rwWBe1lMFdNeSrw4vpelmwrUNonrQTtxz9rrYPxDG1HZkqLpLmAtAr27LsJBuycnq5KBxku8NESPvqjf8N/kbbN25iAKThAW3Tvq2bKMZiT92+xg8fJ55EBkPk+5Wen9Rao0NswAAFzNNCGeJUcpOPRAEIDeIBGi/NUOpYm2DK6Z+fmxmBsW/f6GHAi9/hb51juD69vGu/KEMPLoHTcx0Fb2hecSWU1oQSBeqr/Im1oue5AnI0C69lQhYmsYJf13JGtQ7AHt/YlyayB3MNE1bcDfnzcBVcQEobeadpEm7IHwmYzOHsGjrolbVwi8JlhL8kyyfQZ88N1o6heIfWG99Vxe01eUs6oFhqV8icczP1bBP5gvyrfj9cuD1Ywtn85m4fqrNrR6i9664IveHnFb/0HPrfWJoG5ozXwG/7yTwIAftdXfE55Zq+py/M80eGcn60hTqBONwZO46qPRN/Q0OyVXkLGhQA0a39u061f1in6ObfV96jn9CTSM6B7IunufMbd3R22bcPd3R1677her4WIAUIML5cLrterB4a1sAAPDw9YlgV3d3eu0TPw9/DwADDjdDrhfe97Ly6Xi+ZzAcD40CfexvrWFdc3XuhB/Y7WxEHL+XzGdlrBYI91l83GBHw+4Hw+OzAUpiUcs1ByQHC9XjwcgYBUTl75WA/uhxdOZi4eL8FcwjLYO6fTSYDZZXGmh9nOIJ4lRh2LowjZQJsHghZpuhDYZQl33MfndI4408yw7ljMQ0CX7pYyjjV02XbfADOmZxCgoXzO9T6oxQ1+urAIt3huqy/v+yzMyCozylafHZ+fGfC4mrVVOzC3qw/FwfwD8G3VjToFc23OJ6y/TdvrrBgnZjODOdhZinRejiv4q+ANXraByRBsZGEIooQD5ifnE6BQ6m/eZN0ceeL3MrPEPPAb/qN/L80p0yzBnTNkZwc3E8eYS0YT4xyPAUmivl86BdocFhRzKepFMVilHQ5ibW76XPXKgBXUxdyQPyJowG31FLwsIB2rPghEYj5+Wk+4WxrWhwcs6wnXbXOy0NqqQqc1zp95/gY0A2wah89et+iTmBvuJkTbWUFeWYc+z2LdjdGlrVqOef9zsE+i7e16vjicdgRdMPNPt36ArWkbW3aGWRxedR+fvKbzMMv6zDRqAn7WBuPWyVvr61146ApGfA+dp1JOut6/4fd9B8Ay98ucp/x5nJP0e6J3au5oWmwLPp/n+lEZNiM4lRe0HL4mNWsFHRFTbW6t9U9YUSjAaXo+lMwWRRCLK/kP1mm22rDyDLd81sOG93fGF9xf8Vv//s/BT704PdrnlQ6xD+nsB+DILNOE2hIUXOmrg00VJfQFpPFqQS1Ank1kwLGh0SXbO0SALeERTGjBKiiQM4UxcrlPcn3HJGCZ25E9iD+nd3c6Oi3/nN6FqS3NNXAGxvK5LwNwpoHLUisDO8XBR0rh8U7O4724uxMNF4cL7l/y3X8K//D/+BewLgtg18dQr5ULtjfu8PJuxUf+1iecIOUD/jleUdXSVbfc+bpp+0RTZ22NNq3rqvmbCahu1Ii8zNzT+yKFZog+gsa+k7OAHlDXGfY41wLA87llrz8nY5AgLSvSPslPCzsCcybtT3/1PUzvUcpvzmwCc+845XcUXKSqvzLHxOwYA23/+SP+NRg/6yyXhIIO+z5vhq+qfX1rV3jJzz/Z6nLQx7bmco7zbxgfHg5YvB/msicQOZh9LpvJZAVoj7etzh0r08BcBqfB5LpZKdd8GsV5ry/5K38Jf+Lrvu5xLJ+/0/znI1owizPfdtGbmQFgZiMVuDmA4yLwwa154czTvLamsaE0vxJgyIB3Zjp9/JTxbEvDuqwuXFrXk1gMkDhgakuz0VFmUz8pwigcrVuGAKYSZiYBhjwCMe7maU9+tzQfqIBHZVJT+xTtKi2tc8aSzNkIfzB4oKffrCalfn8krSTSvHYJQm1vbViAtN2zhfbGv3XMM+idCJnNnfRHAH7x934PfvEf+55Cl8samkcqLVN7zul6mv/xiZjir/M3JwO8JmxJCyutOLk6kRDbn1jpry8f68oy2LzvIsS7JQ3gsx82fM0n7vHnP/gCv+0rPoK/dbc+KoiKYXj8/tHzWbAXazRCZ+yuZ3rHadIUOp46y2lA8ladeRdzpMZj91zpMKNfWhe7L06E7P3n9BTSs4buiaTs4VKYgdVdQ5u55OVyca1cBlXmHMWeyxu/fRewd8Ib5zPo7g4Pl4sAt+Td0UyH/HllVNZlAV6c8Yd/+ZfgG//Mj+BnvuhzfDNxs84EJMWjpV7XeFniuLNK24x5BUi1jCaVszwkKHjvG0zDR43UtMcke0hgkkDqfpzZgK9twsHMDAWqeYPODM3M6D2Wiralcha79PoQKzNQlZmZP9/hPviZVuz1s3uHeYY2YebaQhtxE9ccJC5fkgZnvs77v2AA413z4KcTSjMLCXnm5vzMSa1J+h0bvF9l3DDDm5npPZd3C+AHMx7PE4nbcmNMrFurVjfK/I3f+m/gH//zP4J/7rv+65K3lWl0YM+ET1W2tjDgDhpsudDBuz78CdRx/epjEq3zB4pAJfezM9UJZGbGl2KIHeCJEaLkSzzNJqMXaoGwLFjWFesQq4GugqVlWZUuWTOCEScNJwGjZd4dtsgzcInxLECW8nyg+VLqIQvcnefePvaojWuDAkNuCQPq+4x6bRYO6BiB1bF7EvrVcUsZ+QjauFV6kNtU14kNXs7qoB/KNLtNUGj6zgWBobSzUAAt33uROPI4NAM9aj1Ks80ZL+nc9Gvpnjw6++CUm/SKZmeI7UXvKpReco+b0t+NGR/eBr7mEy/RifDbv/TD+Gvvu5P9lV/t1OR1wNz8zGyKKdrGAUZovvVFmd88QDwAf0bmatDOKf8oWMqhIeEemD3EQ1lDZc846LN8jXNP17X4nN7d6RnQPZEUAbbbTkNnQC2fj7PkZzcoYk9l5ygBnESqZFqqRqGVknwlPyOO27ahb1vRGj4sQZgBk+TXAOHWBglHEBq0ul3stXoWCDz3gzg5uai3y+FS7DBZiH4wyZhJypvGkbPnWhOw5+0mUnNLaN9xqv+xhuix9FpE2RjmVz00fX+sKllqfUs7V+rGcS2bQ+5gx0FzHvXE5pxGKufRpgpTQKwxp3K9k/bBwJyDupxD1lJkUJAYS2enpgYZQxoByPfaNvtlWjST5Nr5oh0bkDCpd8PMPBXgWG4gA0zrhjoPhSEMjQlNawD+nlcIiRliqLnQVI46x/h3f9d3gQB827/2L8L6/O7hHsepjpUwvVTA02Mp993NftTv89DbyBa+6GCyMXO57FPSvuQ+TFOHiAWmcbBbNtrMqtEieY7Q3FukCZfAADWSWJeQudOWBdQWEXw5+AFME7a05LF4TB5KjeYNBjUGVHPmzkis8F0HJLCRbpfzkP7ggUMoHYfF4unpPQa7FiRAcC0sz3+GraGIeVjTwVryYXqckITQjaZpML1jqCx7MNx1WVz4ga//VQCAX/THvifllvJMQgyrezD55H1nZp9mKWICRqdOBg5oqlsuzvOq1zzOXqJ1tgfI1A/zSpryLfNB3455bk2c6If1UBqsMzO+/hMv8aml4b/6/A/gT33wTTQCFhvntF8/lrIpOqVrt9IshMtAuYJXmXdtEEYTUNe4yTnTRhKzrh28l+pkvEprUKdAlKa6fmvmoCpp/lH3biK4MDqP/3N6OukZ0D2R1LcwSzQNnWu/ElDLxNE0atk0MwcVB+DEqPfuse5sAwhzmOzoRDZvM/G0/O3MmuVp5bcmxLEnBrG5iU+UXxkK+TOQSRTxXUQjN9DagnVdvD5ZgjxcMp/Nx9g3MYtHx9z9HTejbA3dPGVqMB5qBDbQmJmZbMryThLh03nr00gT4HsUcN3IITPkryruFm/F9XsK/QSmg/hPxkEnr497DV1k7KDuVfU7qlZ+l+snM8JRCs/5O2yI+WeAzsCcd3ziJOiorTfqN4NMr3BBKohxZmcQM2ibtbal/tZ+E3hYbyhYCZPM5JJfBRyvmhGU2mdANzxh4pH5+Mhso/2KO3w6lVEFGdJHZUzm95LW5ChTA3NITKJ5uGRmt1ygRliUa2MAow+fUwBUsLSCeGjQcsL1OtyagZU7Jgu3ohz7YMDCTphTEasdIwRpDi5v9GUeQbM8iG6uQiubEzZ85HNOPAo3hPWCm59lQcGBkM3rkMBcQjCwAkn78FVnNPNqK/MO5Z8yrpM8JO76XPUeKmX9L7/umwEIoMsYscDRBOZuTWkHe6ZFmgFOfq+QE0p/x70SZVN06/zMAaCa62u00Iu3vU/iURTaaCtkYeArX17xxQ8bvveDb+IPfu77PYi8A63DWt+uV6GVVK/deraCuhhbWSjyPc69sZ+TpRaxCmi06BMrPPEVJkzOoZl2dN084yLWVlj5HLehCEOe05NIz4DuiaRPfepT2LYNrTXc3d2JExNNZob54sUL9N5xf3/vppZ3d3cO7K7Xq5tlmumlATxgf8i4auiEupjDk+v1iuv16g5WXrx4gQ4loH4GTcwxjUGxv3Vd/EygXTOJMgB1gAJnagSPGpNyxcPDA4jIPXsCpAfqFzAWNGoYkDYZ0MwayPPpjDFYA7CHuaX149tvv42lEVjNpIAVV1wAwPvBztC9itQGYbcdwK7npypzXd+zdz89or7T0OUso9Bg2Io8+e9CSgy2pWqKmiusfWHaAWe2bX5OjCNQOjYEDH4hwFlhKBJD7NqRxKxrvpmfYrY+szKCsZmfz1qqXL/MxBmIPdKUkDJkMo/r+6a5NqBioM7y2uPFPYIpTA+Sl0szQ57mrpnG7c2J+fY05bjvmjFO/fKKWuZ8bsEtm7rWz23JDLmVleZVZrDMiZP9y4zEjtubXjlWmzZ7SmgnQzyO6JgOAjdGY4afW/OxJhCampovWBazuLiI0GpT5ytJQ2d1XDah2eTBjJvT9BgSwrqe5GwacwDARN8dZEPqZ8x5ZjQDlJmQI4wyTUBBJEI6wxcNDb0TQPnMEAIQpnUiFhoWpiGOAlRBjmqSbE3ldZbmgZFPX9kTzXuUomWSl9e9/8xzIc1OBX5BtSK4wTAgqmsxA+GcRYC6+EJgd2DCbnucG6ITnQzUybWYvwq8jD4VcDrhRAeiFWRleZSYLzcHn0RydEH23agcM/ALHja8bzB+emn4vR95r2jlkOgxdD8mxFlip2XWrVw+s4fvDIzmVGhSEizI1Cb/bpOVoH00BrgDgzXWJDNaGx67lkHu6EoXpgi2+gBxB9PwNnCrE8hB2yQk0YERgXESos8Abjw7RXky6RnQPZF0vVr4gMXNLW3zs009Qg+gEEkP/o2QKM0mCewbeyWWmQARxVm+LEHz8vU5Y5oJcC+ROZlZTdb+UNo9hEGIMmXjj2d639RZy4Cdc8mMeGZaSBksVkaSmppc5qC5uvHLJmWMDWC4I5tY+vO2Eb3m+Ll5S8UyfndOwbbO92bO43YNpMpUy5yYFv/6SmQa43BcU3notjRRGAY3NzEmTcvOuWSwxYlRCBDgP9IGHXXMc7NoCTyj10wTU+n1M6dCaY5Y1SzgsQte8/pBXU88zdXDKiTmmjwW4nTPcw8QJwrD6JhY5znv1MhUP5rydhM67UR3GoTav7txRGUibQ1G3x3NX5snR9Dz9q+jZHkYGxk5xxyxsSPtkIlSab3V6HimY2Ue2lWxHrD7gxnoA7yKd8kA4MHgmzavKZPs401JO5XAm99vIoRa1Ey+O12Xfhbz+QZwd5Jm9PGwD3U+ZNAJA2/6rrSVvHNNqGHhCpq60HSrEAWSs3mrtd6EWPP89J3B1lGKYwgi1PNz85joyLiWD/XZTA853iM+6Bd7lmPuzOVFkPNKZ8mAVXRtWpO1/nluGp1kJIDmz9SUr2UTSigtMiuBozN1ua1OVaduzT1if04PGwE9Gb0y4x+837AC+P0ffhM/8J478LJgbZTWYew3+ZrKrHYNtK7N9Oj7Pve9+s4tumn8jIbOgIkgdC4i+sSEGELYGIyOARatHJEo1qyCaLvtVwQlQUXGUAtN3xCM7wiwWpzSecMlHR2bmZ3YPad3b3oGdE8k5RAE9mkMoQG8CAEQhM40dUcmCPMfgDCjwMTU6TU7M5eTAcdi0iA3QjqlHEVm6hqRegNm/0563aSeLTEWpisYFvKgd91XKAizMjIj1SskdeK+2CTl3kal0BaQPG8TxlQ1xHMucHttOKd5HT5/zKY+nnOY1r1eubczjc11b/po9x8rh6fP16qPMqOmeduBOeZdfqFBlIYwOPbiW3VzUOcXDupKh7/yOBhD4fnqfCtjRdDzfjE3qtYHDvRy3WoK9qwKEGTuDWqQM3L5efLllVq+K2O3zhOT63XS8loqG9BA5M5sqwOBiS5kTUxm0vSmMG9WvgGnV4C6XYseG2wrLGd1MO5lbdt7BpC0LwO/sDP0dXXUnKxfcvFBkhidxLMeLYRlWQG28Bcxvmbu3TyURFhLyJ86VFkq4FvUyQoT4XrdwD1CIcDHyMhDxPrbAAAgAElEQVSvgqjUjNC0GaOe+kRbZOd6gutP7yrQH4PdpI6IxKyCIB7dhwSP9vlIHO/bOgbHHCpjpPR/RiIzUSr56XhTzsNaT/Nr6d/j83tGeCr8SuVaOROxpJg82gTGsH6wOZOf59K9dRWkIai1qCED5ukfeRytnaO+Tm3OJTLU4U88Y5rUNwbjS64dX/1yw1+6W/Etn/devDyJoKHpfNMDETDOIe87gGjGFq3wnvbLdaM5P/iBNw/asm+bC6jJfqV9haLnTBAsoK7rfF4gZ1EZ0LBKFmjO9iCAfW4bLQbMupIqbUu0qwI6pHXKz4DuiadnQPeEUlbHG1jpvZdzbBLrbdlp5AzYASiaPPNaKfmLx0lhdMTpyNYH+mD8xV/9y9HHUA946llT77XBGpNGCFMfcn1liWvXe8e1LULYx8BpXdUFN9x9tbVpaQ1YBVSxSn7NHI2M3wA5AWZmDZ0gwK1vvYBLAwdLW4QRHYRlFROnu7szRh8eygBYQZC8AAnNgCZxw1oTs04wgfU+PIiujRDv+Iy4E0TaN86DZ2em4TYLG9t11l4elsyVUc3lEqj4AtiXx2lHPaioMSFk4CJpgwCYak14xKaMrmh8wDY+CQgwdgxZrmvuOk79Hl1ydPYi7vm7WrcomyPwcWpinHEI7YF747MYWzAhhEhnBbDm9ysjyckNtWmJvG4K2spAJGYVlKccY7DG7bK+TKDNeWEoICEu2ZKJku1x7ZjBSUPGuUe0VN4zGQ4MYiB2gNLLzblxYqQLmsJuHHPukZfNiWziWsukaU7Ec6FlJ9Mgccor/tE+D1hXgXGul9Am9vkW58p4iEdeDzEw2EMHJMqGMM+Eg7a2qHMVEqHTQiS0czD65QoAON/dYfA5necktGUFQBh8leljmgIFlYK9wjvwLExxRViaY0cDYv1YNVDxrS5lITgG4oa5ZzeyXrPeXzxKaY0XIDQ9AkNgRkccXB6S4yL4iAuJSufI7an+ya1JqoxqemdamioofUhyJtFXLtQpitzLay3A4VTFVJ8C8oiLtu6owUYleRpDpwW94wsfrlgJOHXGL377AX/pbsU3feH78eNN6FfrHctgLAsDbXFgBzJnMQkYAiAlJ43Y20rpfmnmRCd0AnqD7F9ZL6aZU8EEAaJpM+Eag7mhdxYZRCPQYLA6ghvqaA1tkftkAmEOeu+lxkI5Eh9IcXKnADeKHNjoTxLmrMszm/9U0vNIP5VEcaYthzAwxyR2nszOtIV0PUIFzOELTLtnTKABOvNC2ZbVnZC89TkfkXN39/dgFuck1+umIQc0LpYS7d7NqyVwOp2xbR1tkTNovffQkFE4aiGoPX0KabBdN5eeOctDwpgC8HutNY+b1/uGE69ODF0buNih5YaVoOD3Dvcv77Gq2VIjAltYA0g/Sf6EpRG2a9dzgufE3FS55g40FYbYLnF561FNG89MxcTpe2GZJZmZzkmjNyGlbNwTe4yZLSkz4UzEVEaqTzl7MyQOj2+uIB1XY2453p/25vm79lJhsEsXpec4H0yvyPUwFVfpCWiFhgzRdhtLZojMWTfvxNDuTHKtTzSvMXID4yshm1+m4L/aESNrMpXDYSC8CQJpHQeNyGbNiY8tbQSRjDOnQNBc65gra2XM1yvjLRM3zs3k+zafgpkWRjIzZBN4sHk1M/dkc6MCOp93xtTqF2Oo5/HaNcYEFFa235nWsg9JrE9fd4h5AWaMPgCWcC/iIEU4a9P9y3MRK1MsMBqWdVVApyBvWYBB2DZg0/N067rifHcHUMOmDqvc7BIE6h1iDioWGEPr6THwWkOHOGTJwCy0eonmWl2PlldauNWkLR5ytjeDuZvJwPHRnSn5OiMv1+ddGeTMfOMGvppBXFz3dWrz6ladD5JrgY/eSrR32HlYXxUS9D6f3TQhQc5b/ldtUu63Hb3BYZ+GlY183A3GV102F1QBwGf3gZWB/+PNM2hp+Le/+LPxf93Jebrt4QJorde2YAGLsLXshwSxeZHfKcIBeAp6TwQNWA8X/P6Cn34bAPCDH3wz5hTtd1nxLssYph9000gGqOmxDsLg7uC2YQEaAxoXsbWGQYTWGLSaJp1hrSClMdYYqeJI+9U0uIALTYSGplDSRDU2pPF562k/UM/pXZmeAd0TSW72ggrS7u/vy5k6AA5kzNmJAT571w7QR2Bu81p5dWawmivGRp6BZD6nt64r2rru9ghj/hy4EaERY10aTsuKa2vgEUHKQWaHbqBAKL6zubaJ8ZAYNrblsTDnIpWUcyxmijm0L+xsS/bcuSyLHnoGAJFeruviTmOoNSyNQOuKpa8CAEbHGBuIxHwqHSk5xA2JddDflbl4TAD92PmqV6V49Zjp8G8T31zeSeWTSVeBMtdyniZJ3Uv6FQQ4iNhVwyvimrBSDUr9pmx5aZZzQzuNTK5DBj17TR4dfo/6KnNKMyCfRtdBXfxFvsBsLhuA/XisDdQd1T0DNsvUtfODgZbBKR3OJ8uXEBp7TsHLjd5843f+bgB77dyHfvJj+Otf8Ln40h/7WG2DtyvOGRmDHeel8jxMC+kGk5/XUp1CHK9ZfyVhQZ7kRDWD6MM9BxxA9NY6VNpDakLsc88AoQHROGs8hvSvradB5PSUwUJLLci4auV6V1qo9R2cvBBrM9uySoy79QQT0bTW0LeO+/tVQd5AI/iZPWke4+HyEKBQr23bplrA4W0VD5/R16LZHr7uWjO3IJzWW3KiQ3U++3lu62cF6DNz/k5TaMaPsynA1L8crA1gCrXB8RjZXrsr/dX1O3o2BV5slOeeQWrtW0rTvNA6AXuAjUeazU16ldUsPGW9q9fPe+hYdT19ybXjB84Lfvi0eH5vLw1/6H0vgNOCpS0etmJQA3TeMiS2IJhxGSz5kWjgGjR+IaBmnDbmpFCIdnXqDKezX/exTwIA/s/3v0gzJX8m2kj2W+kQDBpb+62+FpeWpPug71onDQb3gUEMjQwifT8YY/RC6F1EM0KglnmpwaYdt73D6DID3Hb0+tPnAJ7T32vpGdA9kZSZqAyurterAzdLxtBmV/529sKA1ZFHSwt9kIkPIFq1L/ujPwAG4wf/oa8o+ZdYcUsyQLjBUEudRAK1JOckBsKy6Z5s+ibFCumaMYPO+HNm1qGSZ3IG0so1k9N8VsOZmmGmpsCyLmESoZt2a+JpbkCI8TDzjc+E2hYpOHysfvZSBiiPVgEVjn56dTjWxuzvl7MlXvormDaGenvLLzJyJn7XND+TgGP+m9NjfX/7+ZnZDw3drQmyL+YxLe3URpv4ygQ70KWAEIPHLpdGzV1z52xD0m/5pd9c2/01f/KPambVG923/FvfjG//zf8xfstv+jcPaw9njmx8brXVuwPh/Ga+d4PBSfM487daySlz5b8Q9C/negNWH/5yRxo2P8twsQM9p9+cYoouq9KnoZpbZTobsBjNo5iXni0R1kVMxA10u6OqQpPJzSnDMRbh7nzScAdQL8cb3nzzTaWZrQgOjPG0bqx9w6Wt8ozCMarXvdP9ubQWSz4xGq+kCa9IVduUweRB4rounZIxMC9OAvAtv+6f1zV4Y56+dkq0P5cbK0evUPldtJElJ9r9G21XAOGT124zPjAYX//2FRcirAz8px94Ew8A3iLgfz8voTkjNdEF0EaGX1LnfGbdypF5pGtNBUxMy25851581S4UzTii5yp0y+SZNdeJNhu/YLwCPL9k/ZC/M4twpcnaxVDN6SRQIxP2EiAhkqI8yasB7jnARixp7GCg9BnSPZX0DOieSBoTwTKQcX9/74DOiHsFLtUxim3U8zu9d3Q13zEpfdb0fd4P/SgAFEBnwNDDDaQzUnPKZ9qM4Q2TMIlrtSxmnw7Px/4sDl0Gb3ULMPA3AQftuzaCskceEDMme0aZ4nAiY944G9qi/erS5nkzeywdb/oJ/sS1SfPy6abj18vONoG5+owMy8S+3dBUxHjXcxfzk/4cVUb4ZioMlnmhs16jBOqDiT9iAvN8zGAu9zVNDNL8zvx8bvNOmedCCevC3O+vO66T5pbjLwszbJgy0x9AM0AeKUiyNYQC3PLasTKi/F3/pAYPZnz44z8Fbm1qKxKjnip7c7wDlGbgku4evJJWH9fyOC7uinEGKoM5yuXkiTdzvzPVmbHLNAMV6NHons1gOT/XFhnIDJyLme4E5KxviIBVwxwEExpmgFmYN4aYWAojLu0+nU9ljvTecXd35/UwIOfOqXzS1MR5bOceiUH0zxTkIWiw9VHuR0pvPIL+j+ZEpWSWkWpeUCnUYyuRcmaxEOp916o8ktHrpIq7ipOVLNeIe8k+oKDQEPLU6gqtJMq9LOE0PtwZv+LtK94zGL/zQ+/B97844283wltErkmSwTLrl5irY4SjMiNOJiiJdaj8hhIqOcsrrv2LCTl0tw1c9FrU8rGuF4FsIpYGKhOAKs/C6vQagM7OXg4Gt1HyyxpTgvYZsiOpunaM13nWxT2nZ0D3RFI2WzGCYaaPWUM3a+MAhElkCjBuGjoDVWMMbH3D9Xr1+HBSLof5YcrTzuFdLpcAQAvhfO3iplvraWXUGDPGuMThfzOBjDMtAT6PpG9ZI+cbQGKOinkZZxMHwswsWzmuibP2JIbWHa+MFnUiOIvymaafLSD3+uXdvveqKhSGtoCd1K9Zk5L6UtGEazN8U+d0G9jt5AVglWvBvM/8pbMaB4DMPnO+s8nlLU3e/tmZ54s5fPxu7f/H+vuo+Jx3jW1W2yfvHmfODNfuBG2pT2dwQUT4/l/xKwECvuZPfm8IiwA1C6xlzfOiNgDCXCWWLTOfBN47bbgB7iyHPDsSP5U+9gwTwQBqznffX5z+PUoRqJzS6+xtsUNAzBxaPNQui34igNquFtSagm1530IWiPe91O+DQYMwesfWOx4eHsA8NMyLMNz3L+9dSTG6WGZcr1dndl0LjJgD9Ryt1skaQKn9uXOVNnvoGMld590o5TyWzBT1M0k+R8jG5NPJ4f+jZKggzWADbvN+4atqd93hBQA5JvaPvXXFwsAfet8dfu/734BoZynmmb+nc1MyVuEPAUwYo8P8UzcFbQHqZdxkb4U4GBsMbgDDNHl7gZjxB1YHRoQOmukxuaBgn2JNzc6MMk2qJqsMVuAbgM7mXwi5jTbx4RzmiQBVYfatPeEZzD2nZ0D3ZJJLTiczSgsMnrVx67oePpvBWwYwgJlcdgeImSHbtk0ktghiNcbw4OKn0wnLsuBjH/0g/ubnvA9f+GN/Bx/7eS+87vuNJyTGdi/qas8H0ymHkwE4UZY8xqgE0qW+zozk/htTPYKoi6ZieF8s5phFpeREwNIaelvQWneHL5Q2yJvJGJtHGILHpNCfeZrZ39cFc7fqG4xbniPxPb2dtTkZxBQ0bR8TQzj1mJtm6b2QpKJ+5rdprtsevB0xCa9K+Z0QQOT7WoPC3JcnUM/d3Ur78ZJ1Edq/vIYMWMQz+3aHZPjYBNXZRhJWKTtX+R9+zb8MAPhlf/r7woSQyLXc82o4AsSUPmcvpg6ImKqmIjd+/0a0qfDpXP9lKLNGFXd5PgfzfR4i3l8mv2KAp643OfOkjKL1NRQ5U84t0S3mnGN0S/qPoN4um3gjZihAb+LJt5N6G1ZhXKZ12/UKkHpmZTkDdL1KPn6GUplq6xeyAUlqI0736pJO8SaV0ZfY07E+HxOW5GRrrYwP5ZVex+bRvPyxY7o9U6BbeYCB3/cffBsA4Nf++7/xcVK5u7QHJK8LLnP9HDaV/YyQKzO3UtYK4ysfOr700vGXzwu+9XPeg40kKA+7Bn8Cc9lMk53ygoYSIdYzYg7u0ylIZg9NhDEwGmkIlDT+/mjQVBNGMWVjU51/hy2be2m24qngKj9fAJhZLtg+pr+Tmyq4iWcRcuS61zIBxBniBGKD14m96JAu/13lD57T/5/SM6B7KomBy+VSNEjmobL3jsvlgnVdsa4r3vOe9+Dly5euuWut4e7uDufzGQ8PD8Vbpr0joKq7dzTL/3K54Hq9ivczNeXMQcyt3PP5jHZ3xl/7og/hq37oJxwUZo+cfoh/BKE1htTMN4OYCtEbo4vZEJYJgLKf9wNCQzE4zpAwzAyUPE6S2fi7hqIHY2rn6U7rCesiXkPtWlsWLOsC5lXbpZLQx/YVu3a04f+c0Oi82eu3w3JvVbBez0x/+c2xCfpbSUNnG7KYxClLelAPSv8eVeu2lJ5gnjx5Oj+WN8ZZ42T3Z+HHEaO5AyZlE0YCTzeq6PceH3jncTg/n+vfCjNgjn70LW9raEFK7qWczPBYn5jzJNKJW00tte03Km3mWYza7/YSQUNkJOAW+c0oa2bij7lmTuXNzNW+2eT/Ic+F/cxL/VbRSv1GXn6s98p2mxZyjA40Bo0I0eCaDoSOYfAQmkRpbhnNQgopwUP+QL6ebO5nmns6rRhdwiWIAO6Ch8sDGjWs6wLmbH5v4D28EFMjLGjqeIW9jGileqpMAh0iQltCKCAVHhr4XLwmH1skBD3J9wQsHAEhRhkmcKHH1r+5BNf8WLk5j8PFeyCwAfC3vuhLojzPqz7Ht2PBHBWzf86FG1bH6HVbjjLrZydRiYZx7bmvefuKOwb+4Pvv8N+/74yNomADq+SCBoZF0hyY1xh8PnoHt4bGXJriVVJg19Wxz0YD5j6HOsk8U+1pY7ggAF7kKPUC5rUPuIM0W0sjhREqwhNM89WOjAADEntOzrwxxhAPlwOMpuEOfCwGASPoid4GLUYo2ff/TM2a3fZ7UScaA+7IhbRFI4/gc3o3p2dA90QSEbl3Sj90SwFQLHzBsiw4n8+4XC7FkUoObZBV/1lzB8Dv2fMWsJxTPeYYd0A6p6cUambojFHOJpQB3NQkJwmjjGFlzwtFIwFnLrJ5G6kg0Gz/jWiSRPvcpTDFbH6F3W14bqfWFI1MaxGMXvByHAzrOxzbn4v0akHfMYAr1zQjfsVz9qz0SeVWblVjDyFr1ezcXWI/0iYvZeRzN0eauV2ZmVmfnnud9+vz8TmHijjKIl+b2xFMy/wW+dowYGfArwBrZZxtXUUZx1IHWVs65xMuCjOjWlkXjCQhjEmTM6DL9S6fR13qEyBrWm90lpdjz/Nhnpldpen6UfGPpbLa2WpJ9cUyifUJY0oTgAYQjqlaqg1HW1jHmOsRHaej3U3he+pv8jxtLYjDqYbTaQUR8PBwr4KvAEwSrkb6szUW774UnjBItXPMeXRUeNBzLFEBgWRaVmbXyIxhIDTp4w20SoN3wO3RRGYjobQeB+9n8GZCpjR/pG17+4Cax2M3c33weuDt6L30fpxKS9r2lPHRdjHBssPsV2b8/IeOf+qL349PtjlISGQ+Gw+Q5WG05qD8ut8bLY4c3IEtQzxD0gCRaXIV+/AQ79ZpX7WpPxKoMVKQj4WEyfm8z+R+I1+DrvmlROcTDRUwOIqTF3tuYLgIqGWmhRlAdSiX+zAYktsp7zlSh9fTZD+nd0d6BnRPJBmg634Wghx4AcC2baIlaw3n8xnruuJ6vfr7BtDMHNPyBIKRmyWZdj0zarOZZgZsy7K4pPSWSU0x7+IwvQzgFgQ3Az3bVV16DKjWTa6b0xQtpebjjE1mkoMJDUm9FxOB2BPBN0Z6WZqbKx1ubkUe98iYwra92k8/uwDvFjDI5aWnd5z0nF2YWs1g/fBZZZhejyOa34+6iHYnM2653hSMRtqcM7jL9a1VrBq8W6Aup2OtQq4wrDJgN8Gbx2Eux+bvjA5yuZazcEdhmrQ30zFGvtbLGFr/BxUgUunnXR+kYSymzhZTcAJ0ueKUPw+Sr4JcdGLGS08UBko/ygMUH8bs8e7uPh1O4Wk8eHp0xg/ATmvPCXASiVYNzBBv/1lrOJXHCM1ocm9uHomdkaUasqa1RbxkkiI0ggqiVo3ZuWIM3UdSO8cYoaUAJ6+o0xoyMAQFlqMGSW4GKnU9uefNYcCPfQrG6lCu/tYYPEI+Cm0ICcfBc/lHALmgKK9458YDZYXX5V4zKc2oOTs0TZfdCRQdv7NLtoBu7B/nwegEfGrRMN+3iH0KnyDDwqmdCprzZmnF2x5rz1K0zNexDvHg4UCx5fcBP96hXIof9bCd53d86YcAMm0WwTOempHX0q0tNdNH00Bbtq2Ry4Hle8RxBMlDErJD+BQMAtpQAYysS2vcLGrIAvQD8VUBkc+A7umkZ0D3RBIR+Xk1+50B3fV6BTO7hi48NUrKGjrTyNmfgRc+AGhmDvm33/8C5/Od38shC+wdAYXCPM1EKBOwDKYCpAFZwhbax9AytAZUb5cDzGYiVLWMrOERYFJuY1halK8VlbKWpUjKo086ZubUY9x9xsnOOf1sAric3gmYm3fDeimD4SMpep5rmachB4Bpc80bV0UOLjQQMJibMb8TgETKn5jBG/W0tmTp7jvVxNW87FuYN9YzdrXcXMHEA3teMbfZn8uMVzDCus6ga3Cwe080jZk+mphW0waRX8/gkKAhD6wrj7pD0JqDNmbGxz76BVi2LTH6keLMWgZZ2oYb/OTrpDxmu2oaQ8nYzb0o0P48w4My5gvl4xDM1W+U1pF8CQaSnXEk9W0e0z29Tzq3KUK3iNT+QQONB90T2m4OsbQcErNzNx1vhBcvXmDbruijY6hn45Y9I6sggEc4gzj6M0BXHFcRYD7uZR0MDfOSAoi7Vg4+H+SjnuE67Nwbc6Vo5xzUhZDv9YVkdb64cK6QHKs/lXLjzYkQHRWRm+KaRgWWqSy/dtDwUstJEIBdnYCvfeuC/+YDL0Qzxkfz1WZmpV2mQTsq24RBQNBVIrFkIQSfkvGfgTay4OlNzBlN8NcGY5CE7wDUIY/yASIwqI7I6s5jlWUnna7lpAwhD/qTs2ZOPMS2lkMtmSCc4TY9vIBYTZZBAuoCzQKjiRMYGnDzWY0FSKYBz3tbW1B5pTj/+pze/ekZ0D2RZMAqOyzJZ17ymTUzlcybWD5Xke9lUGde7/J1QDRxf+Rrvxwf+MAH8GZipGYNnZsoAtPGX1MwrDxtCAipM0Tr1rsxVgyglXoZ49o8eLIQU8+foh1GrAUEVmkhEWGxOE62mWl/dT2rksGGbVisoONV2rgdS/kIc/KzbX4Z3X/E1Mb3I8H2McCpIDH3b6m7zRPKrbc5l0o+MLNyifzea8ZUj9v3swlenS8zU7pPt8bgSDPnpXH9TplbBXb3cx7hwISmMeDyr4MvbTcrQ+1gztrEGlSa4uyRgblGrSJu1LXuQNjrkYG0pDHCxG4w4z/57f8F/qVv/52lRzw/185FXt4rGdGVOWH3b4yvdZJ/5nJTfpwyO1pr6d+by+RWykByipnHFB2cy4jxtk89F0RhNn5odEjqec8ZUgHeNATQNTWvtLxtHyBIbNCg9QDQNGwBQBth07PIMyAws7gA7wM50LxpFtjnnzLRBA0WHRpvMbPU9hlnP3PkZQzTnMtA0V+lm+PpQ50I2uF65ujvPa2po+A2CVxHc/cjASnDFbemU+b585QN20SEQxDet9eLsn7Hnl4Txavv6wOftTG++4N3peySoWk5y7IyWgLDyLsysgDLP+NmADp5QAGd9DLBypMwCgw5a0ckpp+yfdS5mZCw/5vpjX3y6IkOWzb5e627ZD/ctN+ysmMnAehInLQxlDeQNelWHqadI9Zzs9DzlErjwWpLymltar0GpTrtNeTP6d2dngHdE0nLsuDh4cEdociB95Ofidu2DUSE0+nkjkryvfP5jPP57PdNA2cavfP5jAs/FK2bETpzumJBzM3080hLZ1QwS+sM7GWAaIRWQGbDttk5ECOYorlj3mCmY0TwOo/B2LaOZVlVSq1OTwy8MYccToFa75vmu2hVxb03nU5YTydAz3iI6RGpeWrH6GqSBwF6i5mnpsMt9u/RZv84OZbd+xaICBOWW+Alm5rm98qvgzJRNrt4J5493Kg5TC5Ljl4JKsxubJbGPKlcW8eEwahn4+I9LnVJZ7t29Q2NrwsZDjrd6mJxGG0Dzn/5uXmznVqs5Srgz88F97IDyfKc3TUuiXd9n+thDTegNaBaNGY3d5vbbAGlTWMHCgdBLjw2h0ApDY2vODXEgSJDzLt78nL5yQ9+GF/1F76/MNGVS91zgbPWoWhtCTuNwMTzez7g5PggcciZuS9+8rT9gbnYS7+5Tq3v7XF7kuvvTAINqHkWaSx3woT03KEggMR80s3QiUSjQazn3oS73LbqBGdZFpxPp2KR0ahhXRoayV6wnVas1xUP9/cKzIDGYsLoAerZnE0xBvciQACSMCEt0DEG8jSyNW/tM7Y/kYcDbMS7NQlSgMW136zzyN7Dwf0Yqn2as3KaFADl6NSZAY+hwHB+r87rvVBmV7ZP4aT98+lwQNeIHIyVowVUS//qt674PR95E586LVh0PmfyIv1KwGDY4QsDZQxChwQHt/eYdZ3aeoLSX0acm24ENiGsPUQAD8amPACBQIOwNPUCS7ZvExqLp1bJSi15APwLf/MTAIA/8IXvj3zLPkgO2Oc001lWUGy0gtSRiWnqbL22FgIKOSKiJpe9wx1w2/oE0IhBjdHAun7h83GMITyF9l/mj9rSREgCWLQTtTZ6Tk8hPQO6J5La0jxekAE6M7cE4ETBzs6Z9s7A2BtvvIHT6eSAkJlxOp1kU982+bxenSHO5zQMFNqfnc2bzTcB4OOf9ffhA29f8cbDhv5GBC/PG3PvHeu6YFmaerAkbNsVzGeX+InESxhvogA9AgBXjHHBtl1xd3d2W3dneIxpQsTUadSUkR9Y16aAtuG6bTi5cwKJ9dS3/5e9tw+2dsnugn7refY5987NvZPJzB2YgZkMgQAGgYkEBWMwlGAVoGDUQihDSTB8o1IlFhJQCUSMVfxJlRGCBVEGlVKrNHzEEpJQgSAhRkACWHyEJJNJmCHDfN2P9z1n9/KP7rXWb63uZ5/z3plQ5p7T95537/08/bF6dS6sjXsAACAASURBVPfq9eu1uvu283wAN1sjs7ru25C058Zyer3yeWfIgOkwSlFaJyU2PathBcBKEWOiCzfYBRkDcOeT/BZ5TCXTpEvkuFWBrSiX0K9QfoVmA/HWfx00arhXVjfjSzyvYG5SLAcdvT83bLu5GMUF2yuXz821ffgJ8AyW4tNShBIZ7pTlD1lRFL7KYCjcobHkOiVLxFDcjXf8HAB+32/+8l6ehKt3Bew6dazxT3ocFqXM9PFBFonEk/odQLgtBeCFKZbI+DID91p+7psMkBeOpPGvRBlEMWwMsTLbLVoE6CRzIfBwLS/6h1kQTNluOhS+Sfj0zJ5qeG3s2wbde907EBScTlfdktsUNzc3ePr0KaC7H5Dii3Dn1kGdZhfL3r9moGPyusr+fggVXUIvHr1wT7OQWp30V8dvXYCx98txTmiTwdf82PuwWlaqeP+3/rk0jmTEq/tPuTjxfjOPkbR4xTKdGGR9kjCwu1D3aqrPcdyfFV1R/AfP9z4AnxsHMjN5pcBZmA/i6S1u9+QVB81pKAmAM4EQlQ5097GH0/u7LbiO6zf8FFWbD8oCi2qyev/YJ7f22JhH/Kt9wjlFfLKxNkbUuacT2XA68cKDxY0xK2IePqajnGG7Ozqg67VoG7C1bojbNmBT8ozopaKddcjqzeekbm0HZCzalcngMbzJwyOgeyCh74vIk6ntcasWNbYwmDWC3S3tnblh8l1TNim4Yjwk27/zZ/4mrq+v8U2/+ud72bwPyeJ/3/text97z9vwOR9/FT/81s9K9AdtBhpCmDlYoKAalx+bADXrHWCHsiC9c0E9JioX9MIXKQd/eN+gTbqstIdCMgAl/Va3dhStBHlSnhTCZwZ9lvd9EnKctSIKkKJLppBLmHJZUgE5ae5hq4P9K0k9iU+fkItCuprIKO59XSiftT78e/UM4H4c1ML6AwO2VTlWFSlxGKwIfSHleZWZreYbWDO3SsF8wMkyDNY7IJK5t1X+Oh8SLWEhmesRP44WHrzFa9OLxAEWMqnDg75VjxmurBqFOq/uGRLPdfXGlDtWsyN+p5n6uAYvBaa8mtyeF1J8TIkmV7gYc8Oi6uArRliDdAXb4u47djWLZsjSTfq1M7bYZpYhvufTwJzh3LBYZku6scCArNgCBi9UkMxM3Rx2JUPmo48t5sdSNhRPh0DIa+l5IGJSPdTGELlnAvjFf/Trna5Dz3CpP9cRK/98geaAVvsai5+WDsDYOsEJ3/fkFicFvuctV92DZeTRBrJhsRn4Z8ylgw4+Mq0hJxCxJomraQDqdwYgHaQbUBTPz+bdhn5yZNo/LQSsMLdl/J71n6iVAbAAc0HfiDU1D783b4wtx2gKoFvr+tqSAe/hPDrYoRqeKCTwp75s9bA0/e/RQvdQwiOge0BhpbhWEGYWLXZ5BMK6xMfxc5AhladN7ot49Uj/ugfjZo9TKy8HW8Xu302Q5VnWhHMIXMNrTBMrMxmgUU7OPyqDFPQBC1PcbpGjzctjAhQr944afkbCohCbmC4BvZn9Ok1aVXmyNjkEj+VdbePk3uZp2M0SBMrq91yXxF2KZ+0XYJ/blZPkif3IrdXeuVVr0W9nixUvDFgdZ65VVT9jgqLKDeASmXLUsMJZZrb/0Plk4E7CnXWJMwggeh34Fm9Zt77x5s4+f+e4YGCP6Rt1jXWelW/LEkxxE69Ptnxwcfc4ldZZmZVALtEUTo/l/SRnVEfM4VhL0dS36oV1gZR72NhTr68qkmukakMbB6SY6/i2bdh2cUBn+yO7W9h5QbMySekNW91YJveFBfi1LpeDOxp6/XrepAz79QlI2vhh1jyujjr3qKUsCIyFESn9pv/7T2gWCDoQcFhKfTYAu19J0F/8mJuG/+Udb8HHTnxYzTzH9nfjt1huUXbAoh7nsOcygJdop7SjtADJpuN6i6awIy5FBPvBXKREybGEPZoXcx+u71beCWylYypCHoZe0cGbhqXR0llczkOjnJq/P3u8h+7BhEdA90ACAw2++82Ej+1t43vqWDiYhc6sdNVStfWTRabnKyXY4huAtD11FqzU6upmNAWg4nJqagZ6s5tUJYsVCNVGgpaFs10gXVQqAr9OZ2v9MmAZfu2uNYVat5nlrvKnPFla6xaKdg2XAAhwP1BX363xQo9DC9rHNKFyj/tZ0jh9QpspWljTyk8BkvLH7kbWh/hYfgbpR1a1iQ7NbmF1oaOu9Lq1wt2SyzgZf65mDD7U0r3u9Dljb02NZHtV+ncDKl3JJORM/467m6j8vC+tKgoaijisHvmwmz/wO74GUOC3fO3vqtReUKYXj+gZGxCV/qHmnBOV4PB0BbI8xrEiz4sF7uy11HcLmCsgL+cZAGymVmpUH8dpgYVkYuy3tNDQNV+rm/jx8p0uA0b9vYk9lT4uN14UhLmg78MFf+zLXJxMybxW/0QsathYsdNUh9iOdubGz5zxA5Kk9FUZYEZNsR75ljHivGQWGnjhscTxXdB4zTwWx6vA6Qd/wucBAN79vd8Dsxs5yeUUSZb+QYcuuw04rucn4eVO00e3GEZ/Ct73EyNVgU0Vb79teJ2v9YkuA+oyiW9WDxC8FgDjliCYHZf5bPWr/AZCltuMmdwaRwlnHVcRoB8ssolA9s17+dHCiETGmQ9Mw6I9Jhljz3lsJL2l6Anb8ByYwPGwqqnxd+y5M9fMUH1CfhTwZos2Swv4Y3jThkdA90CCDBDGFrR+WewVbm5ufP/DkydP/LAUVlZtsrbDUm7HpbRuhdp3nE470OI3AFxdXcWKv4bVykDh06dPse873vKWtwTA1C6MDORZ/FCIz2jjhDZ7H4Jz1FcMgG7uYtn15Y3yCilu7kPdjZKErET+t7dniNiJVXm18nx7a/cioGnDzc1N31t4OtG9TX3l0+7Q6TxiNYWUgEmLh8eICWAW1GswwtI/pzEF8Pj6g/nZJZyY5sCiIZuFLVk6eDWzlleACru4pJX9S6i2skht8gtgx8SL0TTeW/uv6sRA7hLo87o7/R3M9Wsw7BoLZIW2VqGAuMAINmnT71JXDAVo54UaKZ+FZpMTXM9UnufNvDNgOmqgud4feu/neVxPRl+OXcrmB1rezm67pW1rHdPjHFeYxqGwO8lC6YPRBP10Kt/ab9VGUS6PA9KS40nIAD+V19DQVD3KUYYya9ewGKAZY17My6H/tisQrEz2vLBTE9to5+18xnnbUv+/vr6GyA0AxVMjkWSpYuxVRQA+2cT7fr9KYZZjkAHyRp9aCkoxl0t7HzKNF43sOHuhBrJ2U2q3e1nmDXhPjUAQPyXvdf2Gr/5aAIrf8RW/kuqQO+Gdo8GTrRp/kiBUihLAi7axbrcJxv2fwE947RYC4Jvf8Tx2MdkLjBM5HEwZq+16C3UOqB/6kUSGxrZGluT1l8jYR6cBUjbZ+jUZJsshOKu6RXgfh5udRl/yIyWLhPEeYfPSaEe3TwZiTHWs3F7ND6bn8KKfxfXfKpDtDGOQDNOi7bETRddFtg2tnSFiHlP9rsamgK1cqPb761TipHB3sX600D2Y8AjoHkg4UrQNuJm17Hw+47nnnpsOLOG9chYqoNu2HUBLQssPXhmTpSmJRoeVeT6f8913tHI1A7pxkuTGe+BCObP6bpuBPvHJpD8XxN67SGOKb5ozqS6qZ8SJmTRJ+sobXAib5fHq1O+n03Mo3q0ptsMJ+x4hz3uJ1tX3wwR3FSPBs5mAZ80r3O0uTYh55dGehaXg7tDjWbOGRTPfM7W8m2mlSCYyZjC3crVcAaT6Oa3iUtlZ/5M49W2luKEAhvHJVrxuNduX7FvRfOSavaob82IinhpbRN5gL0zU0r/xSPmzgB/7yi6G6bUp8f6OegZnRMfBTzSxtmdPSXGNPDL92gnDNCoklLFllx/amttOtUbWkG1RkVDk6UkfCcQVUuzpnxT6HWDDBbNtfoLgtg9wt3WFe9/34QbXhlKuRCJbDgaINKBm35MwMIWYScpgyRenCExlptn78c0ONnJsrOjblpR4sGgAHoujX+NwjIZF0N0OOU9qn3/igeVjIcMshCcFPnHa0DazdJl8yVn58JfaJ60lxCN1PrRDeSYLPsZCCbrbKB1mlGWeAk2g4+Tq0+h2SrRTMgeaE+g+CNXr4uj9/d4p1Czl5v6+yHdaPEPI04tl1MW+x/CmD4+A7oEEocmPlbV6r1xrzZ/Vd0dKnwG3fd/8OHIDYX7wyhDIVSAaqGut4XQ6wV0p5Nh9cz6cpNewT56z0t2f9+PhO127XzDO9fKV4bIKJ0NhUR1uaAYaNOi0qwrsDqU2XC4VBmZ4QlHo3ZtBIhxK5FB6jsHcXXlQFDWgynndnW6lxzzLNBJgbxwQQGBklUuqa7JsxD8KosGqlDKrK+fH5VwCOEfWuxpW6X1xwQ8wy/tpxOpgCwWseObcF59KWENJEQs65j0dM71HY3/Fg7B6ZxxT06emICVvoiEp9HNt+VeMrMsh924ak2qYzbS8mc+zEVu5IjNNiWeFdscXtk+m1if6pym4eWwYF8WVUlaeA6KarCL+GDadmEX9xywISWbRa5hlT6GyYd8l9ZnTacfp6graGs6tQc+3+TRLMSU/cNzE28RinfXs8psXVe4Kqc96W3SwwO6a3uREIAO9sD4SMiAZtOxrqQLWyHns37ce9w1GluFH56n3m9p/Bc83xT/9yg3+wHvfOg5DoXibYqODFHWgI7tvLvoq8QdD7o24XS9g12zQvaMSvLIOA5R1lSEhTS5qSH3zCPLFh6AEf/XF53ze7knvngtqOAJ2acwjtm0ohturtfkYXy6DpUF0HA2rMWbTAvf4FL/ErjmfVu6V0pnCnHwMb/LwCOgeYDAAYm6XVXG9BOZYuWWhZvFtJ1wFdCxT2KrBh7EAOHRf4wk4yg8QZvOp/Tk4AxyIWd3MchdgD7BJxI9xVlJgRMbdMVFuWgjDsBqOeNC+in0+91XILJTjpKyROe5WQ7ksZmT/Jy34PuvMZPkmmt74BJD0kCUp+WFu15yRTWCWzidIsbXuIxoI0Jk+wUADsQiQwShxdyicta+zC00Fc6zQHrnh5HoL9VPSlp1PZLsxULcAcwLQiZemCCvlKK7c3AXoVnQf9akJ1JpmTtrTJdBotaTqUrVYMUJ6eYSpjkq59whTVhhr34kB4v3wUqaE4BLYjMdLAhQGHE3ptRrkVOlb4lscwDFUVUwcLCCEVWizEqgipWQwZ3q9wE65BNRc+rX1U1L3E66urrrnwvnc7ztE0AVgKKajer4YIIlPl1v1wqt7NLjDVWKvLyp5MBBDYI7zkFCXO4ax/MTHYDl6KNN4UI1nAaf3DV4kzXssLxKFonjx3PDqLvg/P+f5pcVYAs753LFJuEhmG2yaYODu2SpOU+Kd5zEH35lJY0MJhfviKd+Ji8jrT7/jhW5V9vYB4NcCfPo8d0vhIE+VFm1M7tuBMTZnABg3iIOEAPUBmgtUx8LrJUv0Z6Yuj+FHV3gEdA8ssEXMNujWUydZkTPw96wnV/IzEcG3/dSX8dJLbwWA5L5peaf8fdU6n7S5VizFleNOe4MdD9yBlymv/WLbfQ9AmRUlU042UvLjqoHN/fB5ahgTGSvLTSlPpjLza1p5G3H8FLJiwZsUeUnz2WHobTgf5FIpI3JSqau4SbkmQBRWR+P5ipb8bOpTdRKnAgLM4XgOG3n6dKehgLvCUvpRLyJbsMxSe0Qrt+EKsEV9dYqTXTVN4YuqOPS0fq9T6+cgpIqZorJtWTFu0UdX9FS6K2jluqwtc8YjAjCaeVLrsCrbEvooW8mcIyWYy5AM4un4D1LiBo81K4QOb5QAkQ+Q4/ItglofNl54n6b+g1BkI90lJMJ8ZCtSXX/voMkUaB30pr45QIi78o788hUVBkJo8cQ7lPgBJP0MCu1Hxat2l8Vxb9jpdHIXe7umpg2rggj6Zq3KO+cN0TsUfXbbO2KTG8qmnLOcS23u045Qv8mLO/QxAcY0i5Rxsur/TPqlFr/k5vxGAucnd/ARAF6+abhNIpOZG/vgXWZW0Dr6i+0x5LG34mUszNp4I/mt0c9DrpD7rAjU7ncdWTbpadkyLAhZ0J9J3OUJlJ6XW+cuN8s8P6B8X8L6nn9T2G0GZlm0u/o4nuW/AVBf2AZUYhvLvNhYJ9TH8GYOj4DugYTzOJTDLvx++vSpuziyJY0BlgE/1X5pLANAdsuUMXnXi8pPp5MfivLd73oRL7/8drxNNbtiDtD29OlTPPfccwNAbS4R7Q68lYWuAyqztgH9IvGGfY/joGzPWzyPiSOwQr8kHNj97qQAgN1F8zRGSrLmaChm7XzGWRCuKTaZGa2kRG1j07avzNnEJaA9LkUrSfpYBhsH88ygd6yuO+Gx6i9pVs2FrHUIU1Q4/5lIA8NJcXHl5lhJ0aO5R0hVSEB8zsAme4V9jkxFx6EOrgIkEGtAxPd43qG426RZJ/NqnQvSsmIQfdqhizPdLsHdIoGTBBSAJ77WG6eC0qo0AGhTNLSJVqOFPyuNlyzmk4US8EvIvd9hbmtdPLM31ldD4arq72U8JatvY7D7E1o4CiKjfFf/rN9wuYuFj8I5TxvKWY0Y+Q04NfJmBdZHG0DcYNLCojAr5wlGaOUjp+tAUkQh435x63+qoHszo5a79/vOr4aesO+fE+xQKHacTiec2xmQcfeYCF5/+iTkj90HankZRQ4aNFVdvL6F82k1yp5pSt49LLj2WdhYixhN/b2NzbJXD3MQo4PA0kqEeE2p2zlYKjFNjubfHP+Spr7gE7LcirmU4/e+uDfFz/jkU/zWn/Z2bDYGdMhxq4OIAwtQ6nPrIAVD/irg++8MMG9A8uYB4Osr/gMxlyqN06aKm9HfdluEBYbx1/xAe7nn1gBRNOk0CATvvm3YAHz4+atOj/QFMG4wB5ZT+9R9m6t5rC/02uE7zHeuL6TL5rOegdb7Xt8fCGzYugumpwvQtm07NrVD44Yis+3jCNGQ3fb9juXAx/AmCo+A7oGE7nIIB1B2aMdKEWWrnLlC8gEorOjl36H81YvIq+tapq3lu+h8fl67u81ujzEhHJURCggp0P3NqEffRG0nYnq8ASbscJVpEiWemcuRzdfB77g/RodylCZGq7aqu/sIJBUVzhVCnxrzzMXAygArKCvgEWlW77Nuf5Q+u/NccgOd22pRJhUeSvlhljnChXi5rqRkmUKpx4Bn1ccuuWEe0lfAnH9fgShKkZth0FiAXlymbaBmQQbRzvVi0HkXoAtlK5QvBnQW/tm/8M3HBNCwJBV2quxd3X3da2feJRXUT4qjN5pzutcwS3SQ3DJQENq7o0OLcVQPUw7vq5KlSy5MXlKe/twtBr2gyTo4xq/KPh4TrCX8ZHKynbsj3IZuGd60xQKf9D11CoU8fUJ5yPjfKFGsrRiZJxmr3L9lJFWxHp3C7RLyNS5r5x4ERKvar/V45YNS/F8ep4tq1EXDGdzdBeaeLcxzgWAfIOgfPnfy0hwITjSvYavVddRgbqsCfi+FCoKh6vyVzezIQ/7QqY7dQtfxvYG6r/yhTwIA/sv3fQ4U4zYAk7n2YX1eeItEsXx5NTL1MX/Me/PSfOK6THM9A1sfO61h7K3eUv6+UCcy7gw2vWTkP0x9tviuWVF6DG/y8AjoHkgwN8RqgatuVAD81Em+moBPp2SXSXOb7AqgTO8M0H3Bhz6Blz4J/KP3v3VyszTLYLhuRGCXy6iLWd4qOEP5LYgVMlNAZoXTaPfjvAeY4hXRvlI98jSsFwQNpYgBoymJQ2AnMDncQWnVbWqvC4pNVOtZJvZQPxgvpMXtFDe/z4XP7y66i5lePs/nKb/jQCDJ/83cmecsV0NgjSWkjDJxs7VFXKEF8tjIk3dJu4hXXZUnEEQksbqWGVYUuTuUWAWif1Mn3oqLW1UU+Hu2IsYzdtdKFsr0H6m9JF++7AN/+CLtpqj5r9SmF3dNIrdK/zdcBdWtTrCxP8Wn30bzQbmp3x3SVCPYiLY+GW0bxodZMQzlsiuAU2epaLeIP8vT2Up3gzk1/s8AJqn+ozANvrbhDuZ81NHqbVjrWsMZwNXVtcvzfd+RhrtEvivS10Ex3SxuwPu+uC6x665EBvYlE2hkm1zzfKsgEQcKVen/1b/nqw5K72VW93ULPCfdN0hqv/ntPGcCP+vjT/Adn/3ccZ60uFZdS8UXT7nfgaegUZl4l6tzvNAB8PwdE0sHQ9tAZ42bioB0B3VGR0MciuKyx1ZPBDEOCrNND/DoJgPTopzROreVy09IuMH3jaiua20bxmmdzectL6c1NBl62QCDaAJIg9g9d+MuQdFwOX0Mb/7wCOgeSiAgc2lPHAtLVXXQ5/7bBNTYQletdfXvS//OR3F1/Un8yZ/5eel+Ky5zRVMIuI2e0WbnJDCz8hJWhBDvK4tQXyzLvueulqq9W+0RCJfJfhXB1t36rEjntd2PNDY97yztOw0/ooHnGZ+EeCUy3s1gbg3gLhbn7BZ0lzWbH+/OIFqrgjggbXNCuMLFEwI8ruh1JTDA3P2UOANDXV+Y00Q/EuoHRj8rNMTPSOyKc15grfUJ1YbBnBCXHHgqKeNWLilU3r85b1aM2JKgxwe/LPfNAbRYMrIpdc+1mn/Vz6zsyYo96/j87gDxp7I0P0uRQmNFBmERDq9vTGUxr+aFCE1tmVPanWq1iDuKXdCgzFJ/wqBu6m8SsZi4vkDV3/g40a4eyxmuQDY7CAXdLW4f505Yu1j5Yfmpe+fWdVmMxiPd30dKXnjh99w2kzDEkvkrmnxhIy8EsIWOp6l3fc/f76JDMKws65qxjL5bL2eZxNnNO8MykKuIA3j5acPv+0kv5oeVNs97AeroT/mTZJPNnZ63d458kcdSivDi6QBEdsF92wCQ63cTDfd11USP9eRtmhgPsSfRy2OiyDWNKKZKJLdL444D0/F97KfzxThiorVha9pBq6pvtfMTLcdcxMDuzm7zGN404RHQPZCw0YWtInYR+MndLm9vb/1y8RdffBGn0wnX19e4vb11t0tLs++7X5x9GpvLbm5u8or9AIMigueeew7bvvUJezy/urrC888/n9w+fd9eWtqD5wfwxGEKJwBIB1QhtQF0YGUbty30+AxKu4A8n5vn6/stWAkY2p+qjgtxMXiy4fbmFre3N5Br4OT7CAk8n29xZXcyoaeHuaMWTeNAt49DUmylLk3YB4dL5BwSL62uwZMcj+e2FUHczgYEs+UmJ6lgsSq6lYKVgm1TcZpck67JqViVGL9TppRiAl1DiRvtobYvw0sPS4u6i6312QxJ/VL7BErsV6xi972jktKjdRtuWFOHY1HVee0f7krYRjUGvZvQwQJ2CMZoP7BCIth2urvRIYgkXqspH7wAZOPDs8rt+wPv+zwogB//vd8T45lqktyDBpDL/VqnflXDxddOO+VV0kbhdpCOPVKPxAsJYs+EXBJJdjj9g9+9+XksNhQyOOepMjp9LzVmOnVO4ylGst73opU5txgbuW81Gg+mIJ/bOdVNRHB7c9MtBZvg3Bra2dzAWiwiUN+26vKYtIWYZZuOPjcLhPE5GsfayDlGbTM7P2p5TwmMoqJgGw+S/K4STgS3px3f//k/GT/xO759YAaTIUppSAaYtQhAvU4GqQ/megUase0CaQloRJmZau9fum24UsXT06lbvWLQRFyimbNpY9Fn3zYI1E+kNMlt7o9QYLcyiVbdwmplC7+2WIAx35t7pbaG822nbdsaTtJ1jG3cA6Oq0HN4ASVZMupkTr4NLeTNYP1J+O7OLg9bYjQrCWnUOM+Nnk22vi8OMuZy8zIazaWAmE8oTSUSQgPWLxT9TACxk8jHGBPZiNfW/R8tdA8pPAK6BxKypQoO6uzgEwNzT58+hapi33c/0MRAV90/d3t7mwCi8GWfI2zbhtPpNE6PjANNTqeTAz4DjECADeXvWgFLCE0XctqtZOFO2ujOOCCAShd827aPg1BMwcjvBdpPtxTBBkETwW7mlAGotk2wbztucYvz7Rnt1F0rzYYi0H5Yyq3gamdJ3Z08hCdsJDIzAKC5PFyojAfBt2PXQAJZafKP7wb2c+D9A1kBDqWYn1cbpmmNKcuiEFcVKFd7euHTeQALEA0BrIrido9JLSmkxmnLn+Okd6SASplMnadCaWs9xeO5FdEm/EGHs9H1R24I+4xdUdtQlJXK6G7NwSslHiUcJf0QIC7DT4lj8JYULu+VUUuZ6/xf/Y7/HFDg9/6mfzvayN77IgOp5KlPKvzUIAKWNCJchfZ6E0id1HZvN48SX/zY/54rH/5oNz8FJLeycvuUmviJil6mYChb7JVAbt1ebeOnWcMGax1sjH8EmSYas4kWG7dEXV64WTDKw8hf6eCgEc7n5jFsTnj69An2045t64px075HuZ1DwVeAFjJGDmUBju3KWghP7rOjbm6JnvCPpEafmh7Mu3g3jdcUX9OvOUd4l/q/v/jn4fbqCr/gT/wxfNOv+fWAKn7RN3z9sLiQZCvEx9y9lmE8RaS+ZHkp8dfmnDxM45EC7//4E/z37/lsvHJ9NVxGATnw6KncMHrNq2UfNJ3HGkB3ARzjqg9wmn+AJgJpAziJBBhhoQD1tj+Pz23bsJ2E9tPtgDY0nKFqB6rmucb3mYkCWz9YZez4h0BwJjlgli9uA19oW3BE0l/8t/k4NIEx5P44LXYMlP5uQ6fNgN6gDK33uv0UXlEq/bTONuiUsSKrreFWj7d2PIY3V3gEdA8lLCbsqpwtrxCguPbJrpLsDlmVAttfF/tsBikE7CpoS25hpOStQ5/kMrjgP67HKh8hmmPqZkvT5jTF6p3PuYCDvqCbjryXrvysrmRwXq6qNGkYS9JXTbrkV34ig8ZFhqtisn6VcqQqXSZX8g+ZH85xlZSnEpXd1pQO++k0Lep/B5g7tG6SMiE1Cy0/kuIZNFcFkF7BGtHBuysWXgAAIABJREFUHOUbimVmbrJIgBRKyaVN7sGj3ScgthhjdYwDsReQ4/PiiwHaXlTvNFUZjqHISnj0pTQUuSNwP7B7mg6D0jeZnl0MOv8cXOvWTbt0WsoR5NwkqovS8njJrlo5np04GRYUS5uV0ZWrZ4Fp0YcOqm9ykxc8hnRINOKQj0WyUBJFt9rhTC55IGV/EnSUzyG4XEXUBVk6sL9Q1xnwcUJ6U+nwlr/AO4vqdS4LpkaW10WA26srvOuDH8T17Q3+2pf+AgDAL/qGryeQP8pVYF6CiLnqCFhpYpz6mIorOWjsVNBo/VEUJ1V831uucv5lsfBokczBRGlfJm1D34cplRxbsbgAXvucSTKLdQmMRYPUvjHfaBIyPrKibwwSrG5Ngw4HZmxJ1gt9FZlf8d1Kjrbu/cR+d88HbJqFA88LyHVm/Src7rMu9BgeRngEdA8kLJwuloEVPj4Uoe5js2e2ypX2n+niUAXKv8Y1geOHqJR3s8JZv4eC2a103QXDTva0eJzuyCJltHGJMpQDe+4AlOJHfUY+plIPftrJW7YqGZGDP6ykJYUxU8g/cFebroW5Adb1c653ye3OPPPq+kz//aeWo5kyrBh5opxpO7JY3u2eOvoLU1t02pXafpHsgzje3wpP3Vo3yjws794hwNyR5fsSX+piiT0bX1wp7VhuBnNTXgv6GNFl0J+0mfr1oBCOlcezq2mkCKV7Hy2tBuzoYE78Xuz0jEHFCl9QWavqHEObu+qYBEbJJFpAMMODwyzHv8YPLTJGprjjufVRDRnfzgKg76Mzud69Ixq0xW1gXTGuFaAewBhryNd4RreK0QIMaPzkfUtI4+kAUkbpVpQWeezsJaAFOjl0na0RVB6axZPP++zxGHcJybw0dmnVzdJ6v1WjrJaba2qg7z2v3mID8H0vXM9xS/oloJOBRSCQLQBSdlUMnnJe7kVik/UBEFEaY5sqXbNB7p3jWWy5iL7G81iMDUn9Ylku0Z74sVGEQ5pneZvrH+NVvf52/ZLAL6rzuSIvintHMX6wvG7HdXoMb67wCOgeSJh8yOm5haqocZp6wXd34WruNtmf5/vipjusSKgd0bJtm08yK0thBlsZRJnSyp+j4PLb8gKlLzyZ0B9fmdBPDA1ejLzGyqSBRaPVLtTt/vRhyXNeBINgE0v/uKB0sPLr9bgsuDPLD1SZQ22EJ8QDYjSrMzJ9McXvHuqrFPCaKMl9tlqMat+qgIn7N//mZ0kzF1OKTZOPKKxsHdIs9edB/avGwOkP8aP3ppTPSjHhE2uPAO4ShB+s9jpfRfyKBG+Lmg/zv/yOSpICn9KmjymMUZcS5LiFsZWWo5SGCYboyPcYzoTm8Zf7FncZSpDoeBZQp6tOuAJ199Dl2OISC3CZ6TEqjsYkAsyN9HYGlGXQD63o88Q2TiKc20kofq4Ku9yGezLS56R0W78SUtgt/ei7xIjDoTaNCx0yIVkyBw8q7aUeqQdRge7ea3PoUM6FyDx0H7cxWMdioEPvzAFXWVZ3+fby01v8mXe9hI9f750fC8vciif+TtWLUr8fVmF3fjcqracj1hHYOgJGxqckZ9QWq/ohU3FQCNGoYb/+r9/5loTBJBU3g0yPJ/C+43kLdSHxCh7T7npIt8aPb/CDuCzOBOiq3FGKR32Q3PUD0D26XD6U8AjoHnhgcLVScO0332vCIO98Pvsl4duWrQ2rS4kZ0NV3tprGAGV9GqdO3yOrGbTZ6tcstIUEbOaJ0mporH72fJqOU7G4EOkTMGgi6RPc2BauOjYuVzKzFuaWuUsa3rNofgcZ3MNINfHrDryYFfWjAuR+SuZxqG35mQ3JfcWVk1CAqqKbKXsDDaPzeOuPs0ufKY9StMXZOqSeJ4MTgSSXagtHF4dPbpULAOgLHBaf41UZkjOfyhOvVubiStGKkYjoT5L3uq0V86w91iFYYaBMX/g3WU800k5jxh7SQtSRq5qDwEWRKzp0+kauyMt4x4FB3ao4B3KT73HKJC+cNFNIAbRxQJDJftPwvf+M7C/lP6hi67V5Qlhvl0GHN07Rgw3Ied9ZlpDrtIwjkgFYQSZqC3WX5LjVoII0AisG0ia61kRFfB+HCBCrnZiwNucFil2Btz094/V9m2myOq/A/+JZRjp9a0Jvo9hraZ91sW3lrXDYK0Z9LV1r2g9ykW44swVUns8/dH2CHS7M4Jf1jtWioH3awqz/3kLmHR1xZPmOb7A5LLSPzAO0BsUGP5aA5arYFemcufGq8OZg7+NjeHOGR0D3QEIjUOanSdJgd7/xcj+dKYB2iiWAdELmzc2Nu0oasLu5uXEXzX3fse87/rtf/NNwdXWF6/PZn19dXeH6Olw7RMQvIzfBZIBxtrBklSX26wF9ktywbfDDV3o94goGrt/53LDvIWzFJ5+Y+GXUW7UfdNJEAN373XvST7LSkR/UDoPZcb4dFj3oWJm2ug3wV2dphbu/sNvTrFOGyvpsAruu9JXC7Zvm3+s8gmfRJMdqh0/Ma237kEp/ZhN3Qzq5qy5ILPNbLCxc4ltYR4sCqXHAhQEtVxTvi+cIJBrw8n10YuBo7EHSnGZlQbE8kiWtaYC7AQ77QUFx6hsfcGS0VN5UPsV+WUnvVYDWjsBprf+BMzEBJVdyVv2wYouRbqirsKP+L6J+smR0zY7Hm45BF4Caip3qVdS04E0jZREGAjpd6eQ5ofp2AkCbs6KySglK2atf6Y3W3wtQeY9Vns7qRTxrp8E6B2va76ZToMvYjT0beK9S0G94bAbY1E8HUPKeZIq7ten4x/KSnWgmq01hQK6Pv5fpdSwCYAZRC7ZEnpGf84GPNuR+a8CQFplWsi61htct5jAfRqv+QcD4x7/6FALgz7/zxbmMhYzghaGVjPB3YyGzqQBtQxu8ba31w0q0tKtRJHZgTus8oRNh+Qxaa/NzO/t4U7tKaXy2xjJtXNtGyyiiOs65xJAN8ANdJgArI/1YhTJwx3Ob0emuphqLwHEvLaDorsiKcbm4CvQ82lEbpI0FkD3aQQSQflEdVAV+oNv4J+bu7sJ6Pt9Ozf4Y3pzhEdA9lKBF4Tv4q2DPnq0UQdW4p64/74CuXlhuoI6Vw9Pp5H98yiUfwwtgsiiE26NXq8+DafKxea0DO5Hm1xKohqDr6e0ZKROL+V4gw8IWE2W4XAyhi5jYtsEn3QTaDBYUq+SR/uTKwmVr3X1g3OQ+ejGHirRW7xe52AQim2kdB6WRFnRHWFXZ2n25iktl3gfgHroupUiXXhUAx8olMuC6mN9gec3PFSYDE2bCoiZKCq/Sn73T/HmXEh9jK5S2yuu6es1g8qhha7VdaUJtq+Bgr6YtAdQVekZ01p80pVHMvXkFjkwVcvc5DGDHlqI5oxibQxGfFeZjUBlK6XqfrMWR8m2OkwFHPMvxbXze1d3vGg8MSA8yGJ9sQdUOLgZwk9reEvU0Twop/DaZrKl1QawpA7HIsOOeWciHen9YczcXY9byxJNqTUvjNX96FK+wOIirPPb+XOVeZBLPxgKLzR1Rr1JXPmhnHIbyydOG89bLP/KuYbpXlvv63cizk50FtMBh8+344iPdko+53XdK+liT4JvJt+Hiy4tMwZug55d97HUIgG98+1t8sbSKaQOGtd7TWQIK39522GYlP8uzP+fOofB7C6DjYvFez01atLHEwTC2cOdTL5dv9D/uoXsw4RHQPaBwCcQxkOPLxOvJlwzoOA2AfveMSAJhbHWz/OzZ1dUVrq6uHNCpjuOHJcAP08ErbEl7TaIsi+ZtE5zPvIE4p+3PWpHFOS8Zk7ZbM0jJdlfTzVYLGxQNIp0fOi72ZNBnWV9cEa+g7mLEu8KskTJwPcyZddoprk5xDiIuMr0jzuUMvC2PVpCPXIefJbhatiA1Kf+fVl0ivwrmVoBONsHW7GDtAuZWNNKLNCqsL5bV/grmjsIK9PGJcEfhN/wXvzPKW/aT3DcEGO5m651b4QZIScenucK5Fa4o/QLN+/xMQQfCQscpuH28KFMmC7/IsmdKW+0nHn+b5cDMhbnmDoNcnkXNVu2was5LiyKrcK/xpANYJ6BFoN+BjxeKreAXB6D9o3/XGHf2PuhlUNEzz8rzkAuXyCZInkcO51sfpqKP8180ybu+9x9MNHv5K1BHneJoMcq5IUL9zRLO1HEtn79VfMEnnuDrftI7jmqxAGlZ5h71DwNvGwDIWHKgbtDbNdqIl2Z6OfByZlqCuV0O2e+GJjvVW2AH6PzsV7vF6hvffsSZHupCMluVTQ+SXvDh2PH5aAXmVMc8EsDUdZMBFIXSUAY936bA1jrwY/dM0BjSXI/H8OYOj4DugYTqXlX3sK2scfxp381d0lapWLmW8YxBnsX/JX/h76G1hv/9S38KgG6hM5dLu7zc85FtUjKn1S3SDVafEV1SmgiyiAvnjSkB5gYiAN3vpaE49tnKFeg2vENkgMltADq72gAk3OscoPRvtszZuvsbBA+hYXn+Xemp9Q6tQUhxSorZoU4n9G8JE/a4B6jTAlrssUZ2FdTleLr8nii+aNWTjOeCbeODVe6DulAdLllaU1wFtNH9ZKzImbtnQmfIQMZW5acDPHJ9efxXELcCdZU/kxWP+1WpWtdXBe/5vu+xwmflkP7lr737z4DH3h2rkKYxCirL7gqMD5dBzeZhvZlGroQC20Fij8t9Nimmi1Iugzl4mUuQdphiTj89U7XGCsBaWkbL95JB+hlNbADDQIsCKul9j9+tdCIh71zWTqHyJlMoYn101ESp18gBZ23+uCCajhbCDJRUylZ8BoBf83t/Z4lMUMYWIngBsJTp42cW4r5XLqeRNeEj7ou3Z7y6b/gr73gBcX9d8CwtaPDcp+qfVmOvC1nGLIoIyPjNi29way2th/TfJgYdTMUsad/6VX5jpOk27oWMHrziY5ZBM294PCwmMToozka4gdYSfbSl3RHnz7xfchsqgNb1DL8/kPf6y7iYXfr+OIy7+6TXu15v4guDj+FBhEdA90CCAToGdhXUASEAVgAPQLLQVcvZNqxUt7e3yaK37zve/onXkuXudDqhtYbr62vfc+dljM3zVsbKxY7pDSCn5RkrpDPwO16R7hK5+93b/rdwucQQxqakJFc7E7wC9H18s4Wu/0ay9k31wqyQO2k4VhSm6E7vXMJh5p4WPkFUfq7jp6nzgMb7gtIjlbpOgOPpAnw8i4Vudh+i4hfZLPuO9a+FEurA7uAIPANw7kajcx6XK5DBwYYtH36gAGg8He0pPAJuHKd+p6rf3bxCqn2xkC2/19/35QkrVUnhBLx5WMlfFrGgj5RRy2NeC7DFG9gg4hQUTUZco+euCqWSlzQv76d7Fp5NJfQMq8pZv2VayFmWFrJSPfMGSJI1AcicbyTDCkunPKLhM8DTZkiMQBPXYl3B/Gj808sOkGNu+PPYVuTrHyivovRHNQjM+UR1YVjNzPAxlse5eJm1bQWKtz8943brd8SZay3XOS1g0WJfk3F1gOfK7XoPWS8R0/E3wbXIydq4dyKuVxeVQ64BkNbQINDN3BfFeUvFlm8LQEdvtL6hB20gTgGSXM1dgTlEMrS0rSKOhtUBUTcItG+sAyD9Dr+h0HRQ2ffnd5fW3WmP+eQR0D2U8AjoHki4vr7G88+fICK4vr7G9fU1rq6uoKrJ4gbE8eZxmEhLFjTbEweE0HAXBJFkcbMDVPqhIbFadHV1BRHBc889h6dPn+LJkydh1ZO4rJsBJbt25E3O5lrQp6EAjrN7aQ4MVuipwNNbXs4fK3uU310th09760JWm3b69x3m2rVv3bWoT1z99DeRvrH5Iqgbd19N043axLBQEut3GWvdCdByOlaI4pmMyZUBcoDhUKBkgNc0iTOITLq0TbA2aVftk74uNNG+aJoZsgIh97HK1VA389vS8EoRF7LKcpysCuvE5mjTofSO/nI+nxOoA9AP0NlsD8VGIGHBNytzgLim5K4JW4w4snbnsVR5yIs7NX5dGFryfbz7X3/VrwMA/Ot//L9xJT9Oi9sKbCgozll5AbFojp+jaCiMCl+9ryWlOmzZDmvKZlLup7Qj9rbB9roYyZMckpwm5cdVSoA0+r5yRE5W616eHVu9jkIGSMukrjfHotU2FsG2fet/svU+PuXK/QlRloEVVQcpgP1U/w6oA0JbKBtJ/JMXGG30KGe4CEnOuPwLOsOCMgBPER/e7gCEwJXDSgYvTpBWQRz0TN0+CUuPIPkfz9NdxX2xqMuvvQE//RNP8B+9/10+j6sON2pqCuYMgy6FydWYJ6QklGaldbG6KeAQRYZlSztA3F0SSLietn4+5uwmnlkAaD+wDP3uuz4CN++1vpwkcRCV0WB90Wu5zXNpTcPC45LBzwBW/z4WinXoDdMYVhtAox6dBzLy2EbdrE/JtkFUsW0KbCNHXxhsaLePh6I8lPAI6B5IMKFrgul8PuPp06e4ubnBzc0Nbm9vse+7gxcGekv3SplPy3SRSMqeqk6unnYaJhD70sx9weNSGSsg1s5nPH16g33fhjIIL/t8btjkjP10go7736Le5iZhymQo1eKWS17RKkomKdXmeOW+9QQgjf7Ou6y5Te4ygW9IyZR4Z7+OsUhQS4pDXaFll8oZ1HG7xXsGcEpuUiL2PSErUkh1SW9Meq7KcaXp+UyXfTZ2K1mCvvuBubv2DFWNP4GoAeIY0B1a1VaKGKVPLouUPoGlim/MpZLAXQKXE6C5XNVqoVwtgqwWC9gCAwzFeRSYRo4qvvNL/iUAwJd94A97nMQTi9sTRF2YL8smE6QKa1agoFSU67JjlZvqoSUP+xBKqEY2rY5k1gpUG85n00Oj7/Z0tQ4Fls3doNT9CIzJFD0ezGUw1XWBZBlcdgjtS+R265YE7rP7vncgt+1jgY77ak2f68F7lWo9upEmodosz2y8aLSru8BC6PtIGwIvg6JKlto8smiAmoDbsUwhEMHXfv0HACi+6td++ZCtSdCO4mi8Lcr0vVmFR7aHbilrgQB24/sXfOoJ/s5L1/jwW67uM8Xk8sHXDdGhSt5XNcZbLxky9oZtLeZ5y2cj0KyGhsfAESrTOGKLmtwPLbSmuL09Y9/6PXiyCVmwDdiZbmRDUyibMrK97M5zyyrV3foWjbFgh52jSfoRFP2+OcSCE4KgAJuRRsR4PuYQc/1Uxabs+mtt/BgeSngEdA8kaGvYtrCq3d7e4smTJ371wM3NjZ84yQDOrHEsrI8AnUkO3m/n8c3SMPbUWTAAZxeU7/sOW4215/V45E023J7P0CdPcXV9hdNJBqjrlonb21tssuHqaridjesCoEA7h7XNAJzXC31VuYk9B0jCxhxQFNv+t0GkryJqa4DskE2wbzsgbUxsJJTR3ezsABifR1YgwueemJgP1smdRxXUGfjKq9tS0o3cq3ZJdY06r8vNClqJxBNpSRczqmlCQT/nrf79sPrLUFd26/dEi32n9uqUS35XgJxbxSTazVZ0axkMVGZIQGntj/qIWflYQa0gjn87wLoD/FZ+rI4l50WhCuosp2ZKnGaFDvQeI29X7Fvzce+ed4Af/e9Z6LrvlZqn+oaC6JCElMxcp+AZ9wPK3YHZogOOtjw3hVneYyitx0VS4lZgbi4i5SujHscJSu+aACiVz9lM5Fpbm6LN/UkDRA3FuV/bcoJsm98/l4sgq79XIbdtAnWK5LZI9roxBi1Pweb0jDIVvr/bQWXiuWb6TBYd8cmUch5vjKt4TE+IjmkP4KUm+xxdHB/iMsmt2hfLQoXlnxdNIo/Pfe0G/8lP/7FpHBwtih3RwW0V8wBbwTvPt/5PfxYN73nt++b6Q1PDc8GLTbp1yi/wtjkBma/9VdcFdNtwddqxj/vpVt28YdDmybMXAhZpHJgZvyS8aViGeV66GZ6Pqw60zm0IuY7Qw2CAFn1ry75v6eRuBeK+wrSAflk8PIY3V3gEdA8kNG1orY9sPrkynx65Vvrs3dH3SCdJ+PFJl2y94+erz/HDJ4d4lBUvt4gslOKewJS3fsiEaF6FF18BhB+prZBSpwsAhQR6WvWdMQtcIzG9R4aiUeNd0s1A1xg8S3DdowK0qgscZcwT94iZaL9A9PIVabGmwyRQd5zds9b9TivcQXzvWzYxS/D/yBLG4Nt/J9IVDvxqXUIrmQGd/Xalmj4FDhDNDbhpi3volpSsg1tAW5tkwYqPmY5YRS6RLHMuyGOmC3oXCnMCVhrN4f3ZmmAALXvOxRnYFM9ZaH9SNJi3beHHXPd5NLESN4nQRMxx917nSu8W7D0cDjrn1rPMFraLmaWm09HX4h33yw7cdmzSAVws4kX79FyobBOWF8CDzwFWXsUuYlYXEhzCcC8XNXHf870sWCZRl+6j5L47aLW5JpU5+poQX0jxTo18x2JTer58aG6oticu90EL1+eGq6Z4fd8o6eX2uBRYbqR8/GQiXVbRZ1If4zYm13TPhFkm4vkA4/RMGOjrkT50ZfvMilw8/nFBFszB57P6XL2W3vZ5cTL1VsspLaQDgKaFdJuLM13c37d70PwY3hzhEdA9kKAtgNRKYbszfYm7AngiSNY9c6NkYVMB3ervUtnV/YytVYdWKx31l7yvSCUmnljpYiC3sgRxXZwoX6DOChsBQo130yrxM4RLlrmLaQ6SMahzxc3fyRQ35ZtAXSlAjuun6d/4lUAd8f5Z+ulnPCj8ZMnUZwqoM+Utu+wg4gIOEqtrJvfhBN5MWSZeHuXPQM4+PfQTUYKGS9VNixlzOHK77DrxvAvurpZzy4m5Q3mdmCbKTyrfe4Sm9HtFK403swwQBFgGe5+ttgdxj8DcPcMafilWdpqLRRwAuQRwaNAv5e2oOQPcafHCFrAkDsna9314JITl02jSlHfQNNU4yRQqC3Bgx60mU4LiFpmA+4WQ0EVWrDOYi07kADPJQHGZwQuICdKRNdCKdcvnUTDRuBqbq04nvI/wWP5/4cdex5/9sS/i49e79/Uj0HKXdwMQY2WlL1TgYjvbUr15rr80nhadxyy4lrt9byXq173rJQjmLY/rQt5YuCRb4t0C9AGl/83X8DRVqF8tNdOZxh4We8Mfw5s2PAK6BxKaNpzPfTK4ublxV8eVAlfdq8y90p6zm+X5fPa/TbqbzbZtOJ/PePLkCa6vr7FtG77/J78br7z6ipdvLpmsDFgYa2xJENlEc9p33Iht2m4BVJMGmCcxVcW5nYfSqTEnQ/xZa60f3LIN0KtdcDZt3bon0n3/JfLklTPbfwjfgBxiu07mMlbNxKIFyvyRCal9w/3SAp9aFqAulPVLupDFD0MH17mAD2V3PHtE7VRMhtmoU+uQFwl+JMIy30I305/3+9Rk4ZqZ+mYF0BLjbt/2aQGjuov1cX1OVx0k6yIwnb7HvKwWdRvTwFoROAQAQ/nqXcBcJ6sT1JxHakcGaQZSx0FHXUm2r3cPFCE+Rhk9g55lUThXylWxrKWRzOiTGiTnE9r60boHEimm5hVhhruU/TWIWz6brHPcUexjLoutxttwwe9grrub+8nJlLYlugJYZYuz9cMoyejKMLou9gVvu0teyDWxxQUqP3fbIgu5DzadwEKkJ6km7DdoEUdCGd9XV4wAfevDKNO2JdjrpXufanHh4wia71Pk4iowXsS5boq//jlvAXnFwuR57Sc1ffAuAMcZOhaThsukgRBEPEsrIy3D/fjD6COKDS3Lfgh8I17bhjVMB8iOfsX4sbWG8/hpVwtwjr2k4TIpBgn78SNxQTnQoMi9HM44RZYZ3O/EusUQks3pUp8TnR5viH54mipfkQCA7+2VHSJbd7PcNog2bBDsgv5cNpy20K0ew5s7PAK6BxL2bce2hdJm+9+A+ynEdT9NvaOutTY2wAdQvL29dYD33V/8U/HRj34UePXVZKGrVymMF/6eg7l2sUJ70U10NQOS0lJXn/tvo4MsduN9mb9myyFMqR5HD9fiJcDqMwfSu549rBKueCbId9HNSsHFsKjvUby11TDKTirt1L5zv7irDz+r66W1PYB84TSRmlVOvdxGCRvQoQRjFX+5b25h5fRytIBEo7V0Ms43We2onlO9abGF4xyOtVHvbhHwL5bhIKS02fj8H77y38d7vvd74EbxQLqYEwQEkPpsaKCcbBsd2BduAECrY2Uu614WcFPYS1B/xzVcpV0WnYEPKgtWAHI9ii89n+IpYO6KqysPAIzTPgd4G4tvdS/ltPeqYi/a8xk0qqc/Jo5iOzC+ayybHKMnib6Qb0yRKeC6AmP3CdQv4k49TLIigVlCTis28BUGVeHXMc4yVuVnzN+Vt0kP+z0XxC5Z75xe7hdjpHbAXXuwAW/7PZ4KpvjLfX3MPpc7vc489dralir8Hjhz09XR/ipxx2xe7NQoKHMiykx1uhzc/bWAPgZzNa59v6TjpKG2GJfPOvc9hh+94RHQPZDQJ2E7TYmP9r/sgrkSptVP3vPa4747A3T19Eq2Cl66Dw+UxsoRkXGlwYaznotCCwQYCBCWJtKVTKygkJUOt3bwjMvCXv2xHXGsiZchbKtuvhSxRaGqyo8slMh7hRkXLCd3m8xCH3fq7yxiNmZM65j5UuwKQiyPg0NROHfLn9/fR9HI9N7lchy0xl6ZOUr/UP+c2mjWZPqHSkp7J5jjsjR/Mh/N1Sv145E3JOpd+Vb5YWO2ulAd8oxQFu9ZY7b9uO//B5a5K55/9pf9W/iVf+QPwY/vLqzu7CsK+FjlFgRg8ywptb1H/JovZncao+DqJrcM04A6fif1/SLo9C8wMVHmR+t8LtBTwEHk7csKkUhM8ZaxR24bh53sMOXbizIxaY3AJ+KyAFqBFsk1ciU8E4i7nWRTruunF8xWNlQd1DEFSl3pUqkOUgTu+SB9vAcc5T5pyCQ+OKMAczOwmOrCRPL4t7JkHr8/9PwJv+HvfhRf9f534RPPzepglQn3Wfx1QLH1fRPbAAAgAElEQVQaS6NvWDwBsrEbcZ3LCgTGyDZ5hqgX1dndL3W4XKr2wyRF8DU/8DEAgt/93rdVDgWtgpAzzGcWTHPF6XX0Zc69zxHBl4awZFcerrymapzIfT0H9ucLWh/DmzI8AroHEk6nE/b9PAEx+17DSgHmdNXlku/5MUXQ7qLbtg2f/cOfgn78Nbz+XFxubOWwNQAI4ZSsdkEYzLUnVt940higq4A8V/XU/jQ+W/wORWWIZItHU4urH1UxLspyqs/IN5QgTdoZux/F7xyqynXfYAAoyNLymWuWLXP3Ke9ZFK1Vuc+Y54/gBBX9/H6kdHLk2dsmtTsymIP1byKiADr+zgpzUp5LcRMePVDOeIW3Wudmq/QcopupjyEA+I2/76vSe1HFv/aBP4wPfOW/h6/5D38zhhbl9Palc1L4xP9JgC7osczFH+S+byA4McEBSf9QKitxZarnxFOjT8ujZeQ7wmKIGjg46o53ZZ/Ys4jsizijC/lpeWMhzU6vNFe5yEcjX7fOSMov1QHRpy5b5wJkp7Y/CBV05byPwJCWGNb3w6I1uXreMczZ8uRMKml+yQf+SMqSowYoG2DOsjjgVbQrK/jHY5vH8N976TmcFPjav/ZD+J1f+G58/Drc81bW+1V+9XfIj75PbvjjhDHSWWLOjtYXkNKaTPVFJ/CCGcczeZGo9X9FV/v5hzwjAHyfoF5aCKWjsVifp55mvLwIkCMHu7sWzrOxuI3NF7k3jKtDdMhMVfTTdp9F8DyGH83hcbfkAwkd0MX9b+w2WYHJypXm6DTMelomW+EM0AHAP/+nvhO/8Jv/loM9e84ulxG60KpWPadpi81sAcR6uv4wQFtW4OLOOftrXn8gloVJ6I9/beE55q+wwqUUtLxsk1WkY80mfx66epVZgS0y9w7J8sP0Z1lvE6qfUndxaS8xrPNwJvfZA+txhxMRK/GfXonc//NYKGWvSLHGBQGp+rdMFv9BCMzRMytzokutP8Z3z2MTvx7kLhpW9Xf6Fm0/82fBC1j/1wTmlvwd73/p//hH8YOf+3lEKBHu1rfcf32v1qW62Wuqh6t4TJu/m8eVtwcXZIO58qeW7Tw8boj7juPUGzV9+I8kv+7MNhaX4k+8D21i18uMg0727BZf5QhVO+pNf+m/iQ13EHww7u62yOd6xfPatw0scN7GI45b683pjwYagdpUJcUXfdu34ou+7VtTHrxAUWDSoZVFyud9QuXd//vW5/DBt5zwu/7GPwwaF2P8SFYe6RDM/z5li598at42NZ5b7WyMZy6UuazrAbIJNfhghvldah/XfT+8zfdcqfgI54rRHgsaelw9HGpJTvNL6fvvgoY61xwP4Mxjg8cYQG6AOeF9+aPw1uL7Y3gQ4dFC90DCftqxbc3Bkf2FwJ3dG4EQtLbfDoBb5QwU3t7ejme3UFUHjma5M8G4bRuur6/9nV1czgep8P46BqE8wez7jnZuaIh9fPUAFT663erK+wY9XouDVXz/GwnzAICxhzAUtcErtRWzjS5jH3kMlKNNMe3dQX8Xe7QOJuaa6A1hGKFVZ0mZxsp2Vlr68xxvIu2iLnYEigQQWm11JSasJUvMkFZT5756lzvQyoXlKE3C9YuQJnojy8AUgXQvB3EqXrL2Emhh2hi0WRkJxIwmXCocouMaNMpDxK81OOIJ06TaXaZt7PC4WS34AOPAG80Xi/fx01I5tigjqXxeHCFejHoq4Ja67tJpStM4ujsBC1P8UC7BDmXMOlgeCZx+VsjKF++3ppTpeCZWndHPoxxC6sDYP5lLnpQ5LAL346NOWh53awSDrr2TTwryNhbKum7cAZ0VZ4tagOKW+kKwYitl6rgvWemiY0lgjOeiI7ptrCdwxv1A876k+J1B3fkc4IrxjJZ+YJJIlhsKjW5ghawHfvCovX+T3JUcFxhWKUj89vQznKk0Wz4zRl4t+knqfT5uR17f/8IVfuJHXsWv/rs/jG/4/HcQr2Mcc/wVLdyXAAJzyP20A5s+djf0BUS/cw6Ayga0Pj8ItWvvfgK4+6qg2yQasPU5NlBZ50xDv47Ix7vXe9A+IeU6vmeZuVpMqPJ7bj9/6XBQsaZhuXCgvGAaaaTwvI37fLU1yLZBW0M7NzyGhxEeAd0DCabMVTeXvPp9rBjzxLv6znvyOJ+qyBlAY4tftcKNh2uXS6BfEp4mx6oEaSjOtOilUpRkL8sTdkUgNAbP79Jquglo2SQAncThKsOJn9RVJfD2htDZswUNGk0pO4yIroR8psrNP7PSrbJqCJ2+znHeACmlL66+p3EBU0IWgIeBFT+3RQC65gDo/c7A3BH5qX/pYuyMfBPYWSiV/C5WinUJ5qoiXJ8fgd4qLyb6/WEfUKaM/Z6v/xOAAF/9635FgTaIcSqW16wQka7sfdpUI9VIoxXI8Sdr3QMcTE3iSnbR1r3wRVXLdxv6XAtJmejByYWHHf8gLDqV5B+yUAC3fYtDY+xvCyuRy2Qrw4AJId06bli2JDlztJ8Oowkqbwfwymyg/sZios4bMFCX5dhiGqG81pLYqrBOa7RcmE/KwzOdNvhdX/LzAQBf9Be+JYGMGUPK4mqG9RztbElM5doIxct0v3K146++7Xn8C//oVXzzuz4LH3zxOV+4NDAfU+lB/3TMF3rGcsHM8qJ6Gck2Z3JTb2KnZPb+02WpUF03MHWpxr3rBiAsvOi1iQVc63pUnfTZZc88X3jOdy0q8mcCafA8je8JGFPibnHsi9g6zt3svNygSp5OrUFpH/RjePOHR5fLBxIYeLHAXZ0yySdacvqa15Rny4AxKaXjWXX7rECSlYQK6DivNAnaewJwbpmj//idJaxCPNTEMreWVWSJ+cA/twFY92Gh20KlHwUPBbdMpvcJeap61jCm4aGhcJOIZF0hu4EAa+2ElbYIwplCp/9yxJicpZayxku1pFGH+wG8lWvQZB0oZUiikamt9K9dc6IuZIUThGsku0c6oTOtqf9SPI9b/9Pc191iXcbXXbxa8egIzKmPq0V+PSOim8aXlWOprW/6PzjuD5aXzn0rlz2irGiU/Leq3yLH+wXOG4iBNirnlsAVorwjzKorM47yEbi8dFm/b/3U433vC1DmUimb98kq39y6taAu5IXOfXfVj5dMwjLvOVSgZ/TlOUQ108W55+6ybusQgXXQLeg5ohNhFfzUZ78Vf+qX/wp8yf/2PwEA/vSv+gr86V/1FTDF3SyJpTuO5pMEsqfSSZBnbh5Rue7DH3rhCn/tbc/jP/0bH8HnvvJ0uN6aayQVs6IRDv3W3LDp2oAVzTMBXIJ250n/1a9VMH6WccV8Sn3I51ot/WIF/3KenUtDU/AuV+uX6b8U5kWHuRXyQns8c54YeVyf1r2Kugw2Gd/iezOvo8fwEMKjhe6BBHM3vJeCdmElv4bs/hGA7sgtwSxYK2uh0yYkoBfWO58cJObcvP5GEjujMrDi4xMETxRchpWDWEkLAZswIIBuOTxtA9CZhW5oa23UC2qCe6wMKibLy6UwUjFXMxElCEyBCSB3mLcrbwqlVXXPS0gvX+Q1sXsVwWiS+fndQTARlei73E/vu1IZ7XNAnyDaoIIxmvo5fnyVlDbdoWgAjIGZIFxTN4pHSnKi74A92rorpCtPWI+tOiYzT/KY9LSkPLtiXUjKipMB2QvKMI/LMkYmtdEVuUjH9cmMyGmCQi7a8tGUhFr9QjgYBcYEN0VUenDcjgdVWD1LJZMcTW7gImlhLeVDssItcpSP079QUO8MgzVL65LU1qi8zzU96qf2bpV/POZFLUmfWU5EWQHOLK31zcIHzK0vAnzkx7wLb/voR/El3/QnZ14N65By6t4AnquMvrOqt3CG4pcF9H/LgmrPziYiTAz+0AtXAIDf9f98GF/7/nfjgy9eT/y5JGdDFqzbwSKp5TWebINus64PogeIHP0Rir5Mat8jv7qdYTRRd2seLxoUG2p7xf1zI0nJRRGW9eUo608u8cRSO1/s92qOXeS9yMfBmki3xAEQ2aDjJHOojKsSF438GN604RHQPZBwe3uLtrd0suV0/xvg+9FsTxqfWMl75zhUgLjvG1pT3N7e4HZctG0ASQRjr12jyRSZDrIiLN1D7RJNCbC0u5I4shj/seIK8akEGFOoSBbT/NumxQAiQ20cldE2jiDWmOiSokSJDTiGosgzyEIRnb4ww3FZAaR0Di+mfO4HIGtcn1wJ3OVyiZuTZmNHNodifKQym+67CmniXi0+FJDj4OhSiCVRfoiLk6E3IbfbPdT/AvB8oje6o4s6uAiXoHknpv0WSNYomXyBX27L9sRcQ1bESp8x0LRYgMmWeP4wxTEeWh6S2WBFIBRnGakFab8lar+zWDGGbCgdYbk5ZNpTOYs2zqmOAGP8nIamBNe9vw+QZ4AqBQdBi/60VESR2isscCwLGTZFhXnctQa4z5oIbF/ZevFPXS6O4hftVMGRvVmNOSvnqG9zn1q4XQ6F38DXMwflppwV7wQKC/WXgoi5mov/ph7stM9yqL+50xrE8nfEr/0+yc9JxCl+4IUTRJ7Hb//rP4T/4Is/Fz5xU+fovF0DHAc3qZ+w/S5oS+msjkAdRjRNdk5tLjN7nfvCUuzf9fahedDk3v/80nPYdsF5LEyIAk0R/Rt2QbkCYgvPkZekTPviZ+owVKLxI/gQezwx2Lmt2nSwT5TThy4hQAe+rV98Lg190WuziYPa69FC92DCI6B7IOH1J09wvasfPHJ1dYWrqyu3mIn0g0qePn2K559/HqdT7xr7vkNV8dprr+GVV15x4cKHlbDl7XTacH19hU996lP41Kc+hdNpx1vf+iL2sUFXteGVVz6Fl156EadTPwhFBLi+Po28mys3p9OObQthtm39oBRBw7k1tKa4ubmBtjOee/45yPncBZzaaVIN+7ZDNsFp39G0obUzgB3u+iGAaIO2M0ROY4N2CMDW+gbubT/1DdxyhqDX5dzOwGnMBrcdVG7bCTj3qasBXRkFsNn+iTRD8fcuhH2aUlLwEULckXFV/Irf1h3wZQoOOOn3cp5ZrCr65KXiEyeAsZYa2fqaKq1U9uoUZrAFI6J7SQ5h1L9hBgLhdhXWYCoDMVHm52yZY6izViwDSHR6HIDZc6X0Rm+L/KrlsCtzQxHH5t+PXMOixqlqwSwBZEPvl8kS1z+3rVuJWwu3yaYNyXmLDxwaNIPoDiUqlD04H7plqK/G2xtTl3pbv/0f/iD+/ue+B5///R+iPs78z1pndP1Rhr+S8j6UywBKSW32DDlNb6Moj9vU4ctiIQFqR7QbCBp3arm+F/yyem7bBoEO/jckC/yoW7LcsGJJixDuOVBWqOzQKS7T2jBbeANEpQWKNrRiYbfAvNBliqPINuR19NUl6Hf+RJsFzaa0bul1zyuYt1n9O7KAk6nwtg4Z0VyZZ0CSip3GVtznWBXu5Lqc8pRELxJ/4XE2ibnAQLAADvSNv+EqRw066OH+51skZtNfkpfBfpKaNp1Q0zRV/MBzO96vil/7tz6Mr/up76Q23p0HMuILYjyIdBtYlW8OrEeife86xLlp2uIho5F5PtoETv+wp0HRh2jTOIypnVsZlzGJuVUMwLc9P7ZEnM/YtWFvgoYuC/dB4ibALv2UyI2yy5xVaAPOymcHxIJvdGBbSAFYFokMnYHGCny4yaBjbN2QaLNt27BvW6+UnqHnM9qQAfu2Y0PX5zYZmz70Fo/hYYTHPXQPJejB3rYp2jwBX3LH5Gc+4ZNlzQ5L+a5/84vxl/7VL1oqQvZn1r++MpVdMk0QVletroDyBJWViX6KpfmY219D1kbG5zBh+CTtKIqiwZT6ofybkuEKfw5JfbAZcKGchlJ8KYSS/ZkOS8vAMk79XtrT/qlK0PgnJvpl8pHJ5Toaz4PjGWQOvEF9uJR5sZ6Zx2bpvSu4MlcAVe53NK6MLNO0TQeg8TC5Qte8irK4qopA5rbQKDyNcVLa+7H1Y4/VgpaJYyL9UCCz+tMdZgz+rPyoA/Af/7Zfjz/+m36bscwbMJqr9rGok5V92Geoo5miOfMR3GkizaIt+5e5z8s6QR7fmD/92xgzBlJ8L9uW977xnudt38Y+uNFWpxNO+ynti0suhVLy3Ddsmy3o9cUDA/RTvzBSjQ9K48LZn2Vs9dxIfdoXKaj9JDhp+dcmScy02CPPjfhn+WhqrxnMpcUJNctMptHLVyS+1LGV6mgFEb9Ac1gs0tTTQe8IpftN8/HBOOB+x2t/Lh3t2aC9ieDbX34B/8xHX8Nv/NsfPtQZfE1hk46CuMyy6LMW9Vm2SGrLFdDuuRmwE23x/aDeWlLGGoL1Lzv4xRa1ct8Yp5qVXBdl3Tl/p5rjrobPSyv8POrPE4l457B3bUH7Y3gzh0dA9wDDEWhbCW0TsKs0Dpj82Xz9gf198p1vxcff8eKSBgZ0rTV86Avei8/54EdxenLjrp+smMfETUt3lI+thvH9eK7OaSgJQBGpQ/tSzHhuwcUhO8sMaxN1zds1ogv5wfKjmL7YlykxxaMGOfq7oPNWOoCsSEUV413EpfemlFbKeFZN+thCUV+EqusFENFFvbiPVnqfLThgIvovgbtk2VgBB2/b+I/TrsBc4ialpYSVaAIfFKWM3f5I0ycrxwbqjoBcuFhKSmNAjpurcszZOfJ42w9/BFqtgFFQUVuoTnd1aK0cPhjPpS61U01teaHIBBacBg1aSmesbZL5bYsVQoeVEMAT+pRxf+RmB5vEBeChUgcnbAXfLgyPdqP+RiB/3aAOfxz4uKWx1InrJpSnLYRkWRv9fRZEY94pbWHgSiT2Lyf3UpdftaWonbRwSThGaSdrF+TAVtPI+ygOvI3oJeYwD/I67SyjZfJTP8hAxxsj0fDR6x3f/vIL+Fn/+HV8/ide7+lYZ6D+GfBjvQDG82ntB/Z8S88XcEbSB1z+DzBnAFA406iyh5/72i1+zqs3xskUgSWz6Q2qWV/xeP5s0RafZljpD0k2kMzOcXN94tljeAjh0eXygQSF9tVAoIAwuJIwAzT4e2AF4GZBx4ogp1ldacDP7B668/mMD77/J+Cnf+t34+pTr7si0613cOXGDx2REFeTRYNBIyqQqBNvKG32/kgFNCGfxL+uomr5XAdFuPdcDDQhjgqWen16IeNSVp11en9U6qoKwQWlB2vl6j45Xaovg7lwb3kDgUAsA6qke2FuMwHdkcZKYAFZlCCU6Jo3Ms+8n9U4dHQ6l12qE9+PmOJAjAGBJ5oBYFFeTcHVonRY+Ff+2z+U8vN0a2oy3XpXfzmojyn9nbCaa6Z/zmDEZhA8INKdYHKk5HK9DtGR2h0dtBcj7nbWfxHQAvNexhnvQ7E2GsZqS8c1JtvgeYh2t1Btg1RvXyM3dcz4qvWZjbme77bl+0w7C1ItvP+rf+/lq4jTUXuyLYw0Ibcy8Ryj3TXkcxuVs/7pLc5llL2alm+SI9z01LaKtYXIovyjd/4Y7K2lxSmxNlGKO6XGNI4y8JxKOwQyazm+zsUi/uOrDd/3wgk/94dfw9956bksEyiuYWabPqv88Zl0xGtU540yalRncR4RH2RIZLG5zzx6LtfJ+j8A/PJPPIUI8Jc/64Qxmn1xwKS9Dj7WOc8WtylXklF3iwXO60BpeAyP4Q2HR0D3UIKBoSGQGExVQMWhuk+uXKfi+foaAlXFT/nz342nN0/xV97/HgBxObntxdv33Z+F2wycLs5/E0BolbpJS/XodcvKJ69jdV0yhOnKkmIKD9c1JtiRaqzc+SxGSkqUWRVR+u3ARuLurNCicvtJ/rLWT2cAk1eAYx+ZakpYQuUTT2xZuZ2TsrbDkXT+1ybABQCQaTK1PCOHOhXmxYXgheUlhYdzoLr5hBvKSVoxXoCvJbpeALApyIV3y+gyVYH78BI8lkWa/mihProCnt/zmF5Z7OxJG+PBlCReSf7Z3/bnPK/kyndQd6W8cl0xdY6pLwTh8IUPbyYpkShuzYWH6+FwsQ6GARqUh+RFbTMsnas+EEDMVMcEfCi+g32WY0YejzdTV4VUUfs+9vNN+3G5u7HMWbGLZIbV78htLk75La8MkFlf9Lqol+ENY3QoCOTOebXbNtFr4M4bttbJx/NqYC9qVOZGy+N2v8If+42/BV/9m75iLKoKfs9v+bUjXtDJAssv1B55iLn430VEmRhqHWc57sxD6mMU/u5nXeNf/Mgr+MhzO77p3S8NEuNUTuEsi+yJts/z3rH7dhVsBKJExq4Isshp8Mg8Prk5vYoHpY2Zos/lYnKrv22edM1148GzyO6g7O7+xOVkeRx63GEJqS8+I3mP4UdteAR0DySICK6urnBzc+OujfZ833ecTifc3t7i5uZmsqidTieoxkmX5gbZWsPt7a0/b63lI5QRIPDH/e0P4nw+47t+1vsAAE+ePMHrr7+O559/Htu2OW23t7dk1VCcTifPO+a7fpLm6bTj9rRDoU5TnyfskAF1xZEtkK01iOw97lAQtCm09XRWhtByYp9QlCZGBcaGblOMGMoIKQFp7pL1FGEKzKWpYaXIJ81xIbizQnU/xcTA0BpUWb4L+iYLaSHTFM5CfqQ4ALOLUIFpLC5Yu/f8woWH8ywKa1FyXGEknSdZAepnieNKTSmypuWqTpa4+n1BegUmdWEixfG6Tj2v9E+4snDkCpis84NhDYCOg4pq8DHYfyTgWIiLr+N3+uSoUy3yl3rfM2OANFCPRtyigwewyvRriaNKmmYirBIQ/cQWsdjCy/mLK+qas1BWQpUsU4AP4n6ESLQfFG6Oo6642eLPuKfZwLlZSmp/TyBrKLYb1beCuWox94MelJvC8j8QPmJH3A8Ja/18xM9tIfl77XPcF1ftvZK3Vpf8T/ALrZS7Qa+uofuGL/yu/wvYN+IDzQ/DStrrRGywH7QAmTtzBk3KF8BPRKvH40d1fqqzxGtXO77tnZ+FL/vgJ/AzPvY6fv8XvJNkw6BLketVBuSRZa8ymOXVZv8oIJv4Xnnr0UNYwRZM1OZ+jDEI7h+JEQCkyyrr8u0MHYdQWbOfVbGJrvcliWeTajCP8HXSSyFcRmPM8mL8JRf4KrfHwztKfAxvlvC4h+6hBIm9FytlzQCRASq3VBVFjq10BvLYDbMqlJa/0WDfb29v+1UKAzhOLp8jbb5WwZSZrmRsIv7n+zIs5kqw0fNwrYTr7vyIpxa1l0oP+A9jwmBF8S6p/WmGjDk0kXdHqrzCfSn2pzEPOKukfon384XKFhYTFr2SMoVWMGf8AHxeRDTKqtBI4/3iQt1Xyq1/HhThaUTSfii2RjMQZGvbtKCrFHfFpDfabraIsQA6fBiHnWjbyxr8Hwslvm/V5ISaVV3wnV/6L+M7/8VfiLT3SBWf8+EfxKdeeiu+8+d8carqEZi7GGrz0eKQueDlDOM9tMivqWDJFmUqQ3O0KV3/mEGFuZT5fxKfJlRYNw6+WTPV0cCZRx/jO+hsocpliIFCkoeZdO7gtVbUX0TQXXWP916mDu2NPRwjh5wN/mdLo4FSkS0O36G5yXMueQDI1zaUOvQmzfQy6SLz+6lK48tq/rPMIo+ajxgRXsd54YOEC9NWaiPcXisQexhyZ5fy99ppw7e//AK+4BNPYtHWp0AaWwZSF39cVj7YYx0E/d44O29lM5zDNFLbXG6nTEXWVRrO2t1y++nYmvvT4g+oy7jPJnYF8GtkjJ5VHACpz6z2bdYweWK84QnhMfxoC4+A7oGETSQrYmBBKMnqVl0yGQRWQMdWr7o6P1sLAqDVO+3suar2u+to5fVolXdadS1xq4toTLjN86G5OLJJYK64MGnKzevlgtYtQXxgxxtAeItZJNyqMJRIU3pGgpUykTLMIG2BS38Ew4UCTHkrj2r6WRln+jPqWXSN6e9ewYAbKwt3zqhzHv2De9acplrYct+LtvdnLU4kXFnTEmi88C4UfaKV6suHoyxXh4FQnmvDjXxFBN/45V+Jb/zyr0xpmipe/Ng/xr/7+78a3/ElP3/ukAd1OcLO0QtIKSOZsQJpnHbVFx1oDQZZF5g4oRabMI79Pkgz1U1CrjG4DlAnVNSgZbujTWu1B0FVya7Dy+BkgMjcHxPQgs0VeXFtspJx7sYQbxtenGmhWPvCgPGfAW8B79zm9I6v53HiVkq0yDggZiNBcTyeSur1+EjzZc/yD37Vf4Y/+FW/m+ih9naZE3ytoDAdDDZB1Jnv4vWYqQ42EMeKsBQRvHK14xNXO37v3/hw2vdWWJDaPkiUGs3bOxNTsjuQXdGH131+kxks5hnCnsVCnrYQPY36T4Muz4qcrI73mFS8te6YbzOYO3i5CBOY+5Gf2B/D/4/CI6B7IEGku04yoLPnbLmrFrcV2LPAYI6BEof43UWZTaqttXDTJKXRAJ0lqyftmeLOEx64hAn8hXKoOu6V45PYCr2sLKgBJ239PqYCDmG0SExe/i59MoVzuDfUM6Xf1kJNx6/gFGtBnifuu8KzAdClouBK4gwmc7xQwnu8OhEf0xugJ1FT/t5AIIUhFPPy/agyAKrKe0QK8ygBuHYM7vpK8vhr/TMWF1aKPY7pLXVm4LACc1WpnZTn0OaiBViJtnqn+iie/9Qn8dGXX8bttlF/mMibxrg9z2lISXOlkZXVy2xwYMcFjC8GKrg+U/xELagfVQilDuACqIq3g7ebTDlatjCLlZ1UWU8KDPCSaZP8k3LmtpwLjX4adRaro9FyEfgwsKDMkyyjxcPksZGBNRALCSurHLcJW5jXSrI4mGNLnvW31ZgqVXLQxMAuLFc0HwH4ofe+Dz/03vdFXgTkch+geW4AmQTqLozs43bg38eyeWp+Efyld34W3nrT8Nv/5kcOSo2yMw3zuJ11haBnmQfLNkT7bLA7Ty3+JclPB/7T2pGDuRbfYfH8L9ODwzI+E2GWF88aYiHhM0HPY/jREB4B3QMJDNxmYeeK6JQAACAASURBVHsM2iqYWgG6lYtSttyN9S2ajKqSaq5cwHD7tCm8KpCqsNlOJCvOXJceP+jdNqFLymnOp3rNlrisGFKKohvWFXErhwTywQzj07HME7Mu/oOGEhMrnEWh4fydD0H7AsdOVN0VTFcMnbGCqKQFuoJINz0lZRWA89op1fznSh+1C7ztBzdlthKA8rpU36pkhu4eq8K8in4RpPF3o70Atq6wFiubxav/JYV10WdNcZSZZlOgD604Pr5KhRL/yHJCe2w730LBzC7QoZRMrCqN8bO/9f/ASx/9CL7lF//So0YqTXbURzO45wWlCpxYab87/6LEK7dyKd9TgJTx+E1RffwrpTbaYIqwpeP28hJYyccS2DEvluBT+ZkkMBnjdJZOq7ozQDDeJ76TvPDv3AgOQGmJZ1rQGGMmufoXUhiUrfpi4o2wSOdMYBONVP4fgLxjIJugSqbT+6JQk4ZwZVDX427Atnn/MCbaXLYKFQgTi4MyntrsJfENAG43wd9/8Ro//rVbPN80u/KOE0dZv+DP3D+s3Vr8IUxk6zHpvXM53TBoFI+Wl3q4vmYBtuWw9Kc2V22jgA2QDdlZtDuFjoF3QSY5+W8ozH3rUGpFDVXT52N4GOHxUJQHEuzgkdPpNAE5ttCt9tDVA0XqKqq5TipCoPI7P+hE4fnVfLZt88NXnj59mpQBow/ogPPq6gqqjeb+rsju45LcKBsA+nUN27b78x7iwliz2J3P/W9jhbk1KDZoa0BT8nuPiWITYN9i0oqDYepnCRJfDsWzz7Vd0dNxMIsrOgTSJoWRsrhLsNfJ/vLcdI+pyUFMqUopB1jEgUJpg92kf7oCF4pcXjkXf5dBbm9zIb73tDNNMvJwZdkUZwKhoYyTQkQVYaAlQ2kUSHpe0/EzzS/8tytI9kzhtCUFPrQzMKirIbprV244XwOTyf0t8QkQvkNuaEMpFpUp/GzIFwHw3O0NfuZf/ov42Lvee0Ac/NTD2YKbmOTpjhamjrqvjDLSwU6WhHGYLaZMNPaW7r8DPJgyzlcCWD7dvS9IFwWwBRBJ9EkshpksZU4LTFYPWmycEG7hsh0yjTgbBi2yRX0NfEEBHX13uJUzGNVxyIqKtY/1OZYp0W9tXMVCUwBmAdC2LUCddpnaGsl85rvYYSwBfOrY7tsBaPxYmxCvbMwaGgh6bOyD+u1GTUkLZuZyn06azMAmQYwhFLmsaNMtxjwojD6qMuhOJ1NLrqcH47HxFP5Z1hhyisW88cEXrvC5r97g5/3wa/iWd70VUdOxSOVkLsY9GMyRTHHesI1hPQ42yfn117ZUqNZEqdtb26kqfuvLL3hNm45zV7R/t6K6S2nnv4Moses1uG/1L0cgnusvqznR+/9dgfvIYr6hYHqbfd4v/8fwZgiPgO6BhGy5ys/5bxK0WCuBNVTlyZ4ZcPvky28lAbNOl65OqIqj59kSvf6e6sIA0F7O7jakhBE4NcAXFkcl5dAkckybVUd0HYPBXFHkovzlzBTK4koOs8JaymQlZ91mnOG6Tedk9wBvtZQD4u+aWjp3uV1WebN1buRrSqcIsTBKY8WrT/ayqKflkXkk9dcRmAuqM9DSeG7KWld6CuCY+gL6/WA1PwNuDu4Lf6gcTrdSjLygozpoKF/naT8q4jJqG4ujPAY6y/Y2pZh/D9rasNIv0zMwXz7P1YqDJo/a2+q7oo+zIpBsAGBBXwIZmZRFmaGoW3slBbRYRgAGpaNy3EeYWgkyktJZyjfw7c9GtnyiojBVl0SKwvsjW86Xc4j4PyFHmVgRbAMY1HbmmzcNrPIBkCmflLQ5uabgh/eCfUalXKYsqjzPYdZl6B47idKSJbCMe1/s8YoAfprpaF/LR2sdPboEM0gCML0m847X9YISp1w1ro7guovgB164wr/xvR/Dd77zRbx6dRp8ULSx4Dhb5zDJjyUTAw4mySQOpHs/q+1iYA4+bxe5dmleU3KtdBlGbcTzRQH7tjAROR7Mcp82pqLFy/vEJlD3iOceTngEdA8o2J41tnbt++4bxvd9x9XVFV5//XUAwPX1tac1K5qIuEXu+voa+94tX/3EyjP26ytcXV25NdDef8eX/XNduNzcwKxwZpFj4W/vzK3GnrMFsQcGb0KCP/bdtaYQUWybkoADbp7eQE9hNWG3HaOlnc/9rzXI3hVo239nE1ZYO0nhJlhyLHj5PSkNGopixDpQK2h2Xk3UefK0+q+zCX4iUX2kAHCaCQww0BxKih4fZxnzbwFw/JyqMc1NaXV5pUx7nUhRkPx5HBwOTEBuFdX2svkkWqKyG8wE6GgMWHndMlEuKm/q9y5CgE02P9q7k7HI18hnRVKjlZhtDFTrwk6ldVsoa66EW9ryDhhjS9WVOKPtC//it+Brvu4D+Dnf+ufw7h/4/gJ4kRR+thwQfMh9RGprrUelIJRi7yn2xYHKpT4cfcs+je8JfDK4GaRoIpjqWGmsgKhegD2e14UOXVQ5xJSmfu11b1runmM1Pz4mEDVkYWshU+seaQOkPvZEsemeJckAEkJ9Y+YLy8ogVhFH2vM4b1bf+PASO0nbWAAo8kYQwkisW8iob8qsc5DGoscetO/7Pmhu0VOEE9iMoOUKm754I5q4lN73xub9hupsm91SLy9weN7T+InwfS8+h8995Sn+qY+9ju9654v+fAOi79ACW0N45mxeZfOSiVJa6a8uj4Yu0GwMbULtWeWTAbx+vZGOPqIYOoY3krrsaKq94w7DcBMd+gPC+kvg3KWn9pytvnydghDYm+kMfWO1yG6ZK7qexofQTGOT+NBpzm6vpkc9hjd/eAR0DyR0gNMc2NhvtlyZ26OBLQNcAKZ0AHB1deXg8Hw+o52b74Oz9OwCyVbAm5sbv/POguV1c3Pj98IZ7Xxoi4GT/tz2/6mvljnI0wbVzRVoE3I3t7dd+O47TK88n/s+P1uB7y6bnV+bBA90KO0ifbIwpVbd4mBTBCON5dcpsPJ7OeblkFbn0vOsF2VgU79fCjlNz5uBR39un7HsmzRXewhWoywKA8OZFytwWpU1Vq7j+X3AnOu5Q+FmhXkinT7b4lCgBJCMP0rf/z/23j3a1uyqC/zN9e1z7q1HQkJeVSQhkErMUJ7haSQG8dFDZdgt2IpGhFYQEJuBD6Sl6VZ5+UC0YTRDfCCCdmjTQNuKg9i0jQioGBMgSaMiCXlWEvKoIlWpqnvv2d+a/cdac87fXN/a+5yqBAh1zrrj3L3391hrrtec8zfnXGsZ3aI95M0U2abEac3PGtCyZw3UefhVjTzNk+eKKAPKSV8MeugmJdCZkXRWMwkIhtId5VfVHsqMODRaBL/+VT+JT/g3P4qf+dTfiLve9hbP1wBXav5xfJMiu219iXEh5EW5aGqE5t/DbRs05g10QGd9PLyTwmZFUz8h8N7w0qRbRrBGRh6ep8aV+kPeN827JQm0GQ80gnLVh3agcsQV2bXzVZrB/XspxevaUoF5xc2jOtZdSgnQOFCSwl/HIS0RstfGmQ1sG4/RV97uRHfzuHG79YeEeAJIpzYAw/wGAjtMvHTZqDXqwtEsnKFQ+2bfmQ2q8J7FODMerP1QbJo/ZHSQbmSTXsjMaGfZcpuP4/ENT7iGL/ov78bPfvjtuLmUGEY6DCm0Ney1xvFE0uVlrT3MGya3uKD2paABPR57RQRV0Dcrs8Ya+gLER6lf/9wvPQIo8NeffB32ZrU8jC+hRSWUIoAUFO9H9HeCFgvbtIr7eKLkoy/x3tBjZo3P8iKDa3FdJ/PeqGcykk/OBr1Kj890BeguYZoJkVkYI1voef0cPzueBTRuqsLvzfK071y2haSNtM3qsb1nm2Lk8NImZzy4pVeQ8zIhPHqUdPgLpSvU4JkG/OiYKCu+THF+htZjXKAUrz/rT/3CxYDbB5IGtSwJnu2Tjy5txeXhXE2wzd7bvutjoD89tVGrfZDAnSVS5tOngPqRFLsZea4otzVOFXWTf20oDmMLO5DwcZ2BVdSZVQJ00EgkHLHUe3NoKNiutAxK6td96R9ycIa+Rsr4g/GSP/jt34w/930/jE//8R/Fh7/33eGJY77Uy/PvY4PxNxGvf3tBfA1YboMhTxq+QoAwzcreLnZgenuNx3wuevP+jHYDSAefgbd1Cu/rZUmPP9SxYH49fQv00UIuuZ21GQhmYNY8EAbiorE6Ty4QyeHx4d1QmIdRhAIEO3qSVAx5GxIJ9tZ23njdnedY+TGrexWSohzjiqXFgXZM7C33agx78wAp8iAQfMq//YlWhozresf56Mwm5jPVTWl+CBr4HZV8o9C+++HjQ7UYMl5EQLzj9lN8/P2P4LZ9xc2lbPIb08zIuHlm+D1KRPOv1YarE83mKROB843Z9irPOpt7rAJmBR9wfoi846X4GEEvuaUKW/koDuC2Hjj0Pv/lE8Jc7mHJe5Ueb+kK0F2SJCWvLRvXjJlCtSyLM17e1GRdV5ydnWG/33uoJXvhaq3Y9xBFBn7mVfvtf///BQC84gteAqCBtv1+j7OzM6zr6mGf5r2z8o3m3W7nIaMmCEvpXrIifr3tZLlgd7KglAWm6Uhf6C+l+CYOVStrZ63MVSE9vqExZDQuXdv1glBwiyk1pPBsjxvFccTCltbxvYkw0omIyspbBrgHgcIBlXGjyNMieseHE3A06o/ur5x4CemN/p6Axc6g/mwp33gTcFCZcOt/Cm3iNjumXg9tR6Bp42XTqOsUxJECWMzSy8s8XWnNQthpKE3ZTmumepnJAjvooAb2TAmc1TLapFnLa61u+vBwsVJSX6YwysFThm59T2Fj7irS9Fylo0tEBM95/c/h+a/7GbzmEz8ev/VHfmTUdFPZqRbHlKNGzOH7HcxxXRwwCY9MIfwwzDFEM7cPVsSDjGxpnylbkj6YxFGZZ8CJ1LzqeXBpqa9E+lbvVIaFWhKw24SbmieyE9CaaPAhifRNGJfkKWiv8ywfFFu1rtDUD1ZV7e4fVeaD0uuC1AYR1txy2e0W2Ob2GbkEOYeAzNyja+0iDmLN88n1myURwed83/e2Z0tp7TeZo1WjjeD8Jurv5Wnr58zrjRamqXvH3EOnGUwObWDjRTCfXwLgxlLwR//Lu/A3PuYuz6PQ2PfM+6Y0Jh8VMU5i/m1PjhO0c+A8zLv/LjQwqjRwX2IYBRsc5yPnnmRRe2NFHyWiPSwcHaVZ3wxjCLmnVSuqCqREHbPHrL0cgPCDCepGwwKNn6t0KdIVoLskSTCuY0BY0hGAbuah463KRwDI6/HYE8dhkqMiaEyO8+ay13XFO596J57x0A2cYXsWXcsffq3lV906B6pLpbBN+2QFwlqnAbomRIuKCzchBUmsHVlJEc5hZKle6+HXAOAuwnGTVnjkGQdduYyZpfJiBsL+9tFno+As3IZ6a35jdk8nd0eQeZwOf3JC89g7W4EXTs2tRs2eiimgI+19do3JYCV8Vpbn0X9b6JA/q3E/ebPTAottnseSD3XNulgb55kvpCxtPnQdl4sfdGZXEl1xH73sqvjqP/1F+MP//vX4rB/5kVyVzbyl63pgq3NEXWKUDiDH6mnGlUle0V/HJw3pxtvrBuZE5uPiWFIFdT3jslRGxh4ZHDI2y/yUQrW6h4p3skx9KDGHUkhibzsh2pyKcSIOVbdwdc/VKiiSQnIZ0Ks28BnrOLkhutdPrdLj/T6fGHjQzdH2gIlHl/PapsNhjPxSG5OtvcXo8LKZ4Y/Grs5bqB0346vvAk3DxivKG0YdrUvvAwZIo37wqqfcjt/yzgchWj3MM8rahkVbyZxPmNqUxvX2vt8Li4LLfNEIdQzP3RzgGH3juHMZ1i+aXaHabUV4eZXyF1C/NQJS3wxgruVzMbF/kcTzeEwG6q/S5UhX59BdlkQACICDKQZgBsLsPoAUFhkesu1Brba+zO6ZB28Ms5jRwHkC7Ry6V7z4ubjrze/BcrZu6NqsU7Ly24/2/AYACooUFMkhosbUDVhpW9GfFD9TdrgdizTPYAHFzBNj/1BIUf9fDqJ0+Ayh6woZP81yfcjlWBjO4fDAsGonr8QmcaeYQhPvzYuWeV8a2HHrf//js+QQVnNXwygvW9cRJUmX8UOe/Nf/BWmSvh8ChF7eBcbltg/m88w+N2FE3GzDHDRA+Le/9i/jb3/tX7ECAREspWDZ7VCW2Bjjie95N3RiDIpyJP22MnHgL3kbzQgjQS/nm8IDrX3dcGMe+bxOZhpiOtI80P5oLfNpbh0oRcRGA40Kieug+0Vs/XE3zBkYo/okXZDaKxkVbPzXilpXrKsZ/gbwNfwh/a50FqPNr/i0fPoXygPbucb0Uf8lDw2/N9Llc0VoCOVxIfEQlTn2Rfx65Lbbcx0A3Pvsj8S9z35OHgfDkNgYMHPPel3MQMKDQ3zS8+izeZCm0PF0Dup4aCl43+mCP//ad9J83fZJqteBvA4a62zcUh+0w8Sjf6UET6IuPLeeMwpd99G+do//AObGbqTiPyh9n1fH63vhfjiH5g/uC1fp12q68tBdsnQI1GVvVwhj/uT1LuyhC++dpnvLsvgmJpwYBI6ePwOOZ1qhHcSx9zDCSKI+TCMreELWZBmFAigUov81emwTlC44B02KlblUhiuH0qx4XmWl/7cp7IIXTI/yhY3iffRdpvLwg10X9+cDULW2GP0bGcy154bmoa8jUJuVP4K6MZmgNACS8800xzv53ZHmdCErhOcoMD3XsZhJxZDz0vys5WHlmNcOQITIYbKJC8xzEvTNQTQB0AMhislAw/k1d0MMT1KuFICo4h0f+dGWSQKHZq52BZ74joWysfeheZoMVLAiv6lJv5/7dDb20vvSvRJRGcRwiox0+JzRwX1gddi2vMzHw4H8Z6XZeG/dEOPDQA14Dhg4Y6Qvtq6ojyCbg3Z7cL06V+vEeXgaNM29oxUS5DFzbP6EFjwHGYrswQbND8cYGu2BQ3Mg2otseOCOU+J9Mzo1jTnFd/73X4HP/d++J4357/izfx4A8I1/6k/kzCOjJHPUB+Sk3q0yac6NNQJt9R/VHsod+M2FkgD/8YnX8THvuwHQ0RB5N5kJOYconYFaBUQUBQIrwQxVGbYO1zZNysblYR6zPJCuG/Vx03hnUgP8WaPP5hc8JN4GNo1H4ln+9UATnZe8u4f5MBvTx+TSVXp8pStAd1mSHgZzAAEViXBIe87u2zv8PAM6pXvmoRs3SRnPg7N1egzoRrpSNbTFtjug6PpgdekrxumScGBLXumHwrLAbgCvg1Y7w64rR4q8KYIUQYvZjzK4eBf8E0Z6RI0+KkfHsDo12kaAiy1TfyxWwPOSCRTCVl0hdxXen4t3XA3MaaLPOGaYlO3rMPTQE/Ss988M0OW2Cct1QKdMFAEtr69ugNjoIWAlkvMCSAmd5Ne8x6wwzNoiFO1o367weNmmZOW5fSBDlL6sf6o3jx6NfLOvwyIfBvEcS6WUaFniR+Ydv0iaA6MNsQE8WIHLFoaD+YcpPWU6HdOOlPyVjWaaFDouKSmjNAYTLfSDdPdcNwZfgI+74PkIRVstnx6e6Mph5NoYIlhjPiedb4RJY0Gj3lwBoV8G+FMIHq/nZLpsHoL4pXdPlxWmcF+gPkyXdUlrbVbcuSqZfoXiHXc/E2/66HvwDV/5J2CepjzoBAABIZ+wtKmFGzYm9bV1cOj9Cd08NtQqZzDQ04YI0XeO8OjSJ+UWYCZqxcFg3L+VxrpFy4xlG0gD2jq52sck+0oFLfw28NY4EFs9U8joQE+8qqjS1uq1oRL9mufepDEMzh3j2Tx3H+2Ou48hHeX3V+lxla4A3SVJs9C1WQiliGC/3/vzdt3Ok+PnORRyv99jv7b3bBOT09NT3+CEkx1tYIeI7/d7LMviwLCdaRcAL3SmCO3xjSWQt+g3QKPOvLtC0IHcUpbuOSRvY2m2v6oVuu8brpgAVYXWdiYdusAp5u0rAYBNH3JhLqw7bb1WAfySGDwgA7ICql0bc0F6hF8fBFHeWgNNkzIzcOoeyH6d9Vnt2uYW1OW8RqDL6sS5unZS0o/Xh/Nb1zoRxKFahBId6hhGWl1HjFDI8ZnRKxJhQOLv8jvsWeOQywTwRpJ701r48NQTYY+bQqw5J/ZypnZjJXYEigOYq7WO1EGkhJJlZQOxvsqKYCBHtNq9p7zz7fiFj3oWnv+Wt+fmV1epffDpVMuKsL2olmDarwwk2KJOfRYhiLqpQ+n1dEWuZ3YonI4NIRF2Jem7IwjwVxqb3nZMLwKc8Suss2vwftHq42dWfx7H/i5XR8RJLb1SatENg/GQw79nCrEMdebG4lA69Tab8JaBQKbdeL3NSYEMZ8YxMMmtymQZJYxXrNwI1VUHRj/whz4fX/j3/hae8r73AWVpfW+IJBjKpjUY1Ll8620snVfUUlFqcd4haF4lWwtKUxnQrWFFDByBAMhkfHM6zxhiokIM/dh1Pv29f2uGUelhjTbH1qEp+hxD4yEGzIsEnfZXi7QzFBH8xmhgI8m/ve2k17dtSGN9GC1mxt1WlpaKpbb+Ci9rH/eq0CLEx4HYJK1gs6jYnrHGmwv8c1LI39yn8X1mlL9Kj/90tYbukqSpK54mfbJc9etjaKXdm8W6c/gkg8FR8WMmM67PS4rihBklZdeFWCgVTpaaYCerNynYImWjw4rRlLwP/XslRRZcVlhpI8wJILmApEn536bxjqMyfh2hYJpyxvWYvmpStgOcKC7TNCMhAbb+ziyPAJn8bvbiHK/hxLqv498GPqS/8G4YfdmTdDG5ZvUhpX9oexsEDN7cA2zKIin0G2/NtuZUo1CwR5BnY9HWG9W09sifTvPDxgiP6/yH+fWhXJ7bqV/zYIg2YDDXn2MeoPQJzq+/+9V/9kvw8i//KmrTsdFs3uXfkQikjGkEW2O+h0CCtSmV6/W089W8CMnDMylbWyoPWf1lfFKijQ/N+Az7gFSFVFUbT3meOtliRquS+nNWlgGAJi8kjYPZGrTsW9kqvQOhuT65YTYEMUi139EUMbbnjYI+Z6IQYz16hIU7Tb2vBcDrf90L8Mbn3oMX/9iPJhA6guZNHv49+jiHKHNlh/oOVbHnwmiAI/0yAoQsG7f5H2hDbHm/IT2TnTyGZ7Qk6ygQ9CFuRV5I9LNXOsuHdu3lT7iOlz/xOpWP/LyDaO575peIcTK0cwy7uY5kGbAu81gS8700tmZlXqVLk648dJckJcWPwNIMoM3CKs2rZom9Yq70rXUD6iyk8mc//XmAxOHmo3I4hmayBXb8azcYRJECLUL1ImFH95kBCr9XFaptLWA7zkd9K++grzH1jYpACmn7YIBiMHCbcl4XSSYIrLwDT41aY6IF3dgbbTCjUYd3nF7R7TMXwKPcY+P1+fPHEtPOeQZB5wE5HvZWr62ynQHXloq8I+CxzjwvHwBpJ01R2+wnBD+DTBVNyhyDOQst82MLhnWq/JloVFB5MQfr8Gwa7yMYGJX/QbmrNH45VwcFAJ5033ugJfMcJ3DsuPiBTQdsQEifDDbvoznn9QPy/LbWpnzDswjfzt/yPzS+EzlcnaEG/JuV8vY7AHFczMWpArQVpdPNwDR2kmz/WZktUoFtvv0OTfrtkddZSd9UVzh8fVRoD/BIrwi1wyRULYG48fvAHo7NxRkF1iab/U97n+eNI9vzP/6Sz8Tve/nL8Ky3viXnNhbtQ3LYvKVnPu5KqQB5YRvojotHeIwNUgT/L6UmelQ19Weme573ie0knSik/KTVLO5HaOTAPkaKB/rFr0qvqhogs/td7mNgE9YyEi/G+KS5MdbXD2A3UIcAcfPRGmjzPHkQhT86DeDcHDe8+oOa/VX6EE5XgO6SJLcq8W//kS1KI6AzUHfM2uMegwlQq7Xizc+/C9IB3czaz79neW/AKFeGwRpXKikWBOAMLBoztfe8jApVW2endF07mGmKTHvAPkHrUC6IchKl+duxZzPoCEXz4Ksb1MjazXnCxEAOC+ntO1uFeLx3cRXqXKtiqmoouGFVjx3zjP6tcjmqzQcUrfzI9j7NnWQ9J8Ux1dyV2axw8lo6u8UbnoweN5UO2uSAx9xAnRkhajbkbJ83hUWJV0SZDOi4PAM3ofAiGlJiVG9mBCln4/MzT1DQeczfGcDKfue6TjqRdOAROEy73ECV0TmzjNMw2LTJWDaVlWZl/Ld5IYUvbhTRiVLvuEnc6eNryTbN08eIyOQYCh/wY/YTHjNUcJPCMCalg0DOb5ILjyFvAckgKI2O9JUkw2wezECgP8/l95b0gcYjX70J//Ov//V43Sd8Ir7s274l1Sh4qfqFZBSyOe1zfmwR7fImz0fx0pv8IamwqX8estG6XWK2dhm9ibPxq4Co4oX338B33/NkvpxyVwdz4mM6Qkm5CE3vxRfx+yICUTvn0uSfOB5zUOevxyY9Ztf4yLMVqsBbTmKtfPQ96UHaj+UwMe/t0OmZiFwbyUF21khm6Vw4J/b2xYHfuXzvKj0u0xWguyypktizg5yNU40CWk1oBZizzU8Orl/QtkPk6KFTjbV6Bujs2sxTl0CdGJibKKFJFovhMgdUCmLwbEG3Zwc1JQuuMRSsgbwAN0aADPRdnOGOFfGd5Y5kEQqYuiXV6jl9ntrRgYTY+4fDvEbaxl+Hle2jlA9PnlP4ERkUAIqpUcfS8Wd9p2iHHFMeB4s3AIjWRsepzErjECbk/TVFBlQXU7AZ1FE9ufXcY1f7dTGFTvz7+OwY6sMEiM0xfr7GOE8gD5F/Co0C3MvTDiVHumdz6ZN//EfQ+ikAEVS3O1bqOF4AH+2hyYM6KkAUjQkDO83eco5Sw2UOir5/FQIeg5fQu1mi9BFbbYGKxA3JQE5dSc1eMH9TBCIVG49RrhRM5YXlQmPFxkabJmmUoQ8xlBFse6NoetbDxxI52zZPXvPefxbOTy03NTrYGJu0xuHqI+YJbBxM5IkBw1JKqgcb50csigAAIABJREFUUuLZoNUI5vP4AOBdT3safsPrXou77n1baleWZd5kNv+PjtH8js/ikZH1+RRrZsUjKsT7bezLKEINGUVFj6adAosqfvKpt2/blOmk7zFHYvrO0xE5wdNLY9dI8T87U9F9xl7+V93/CFQVX/n0O5mqTVtyO2snlp5GDAvWJUKOM/WcT9BzfPbmNx+9bvGBhnVepV976QrQXZK0LCcABHWFnxEEFJSya0wVFf1UNeyWE5yd7fHwQ480z1xV3LhxA0Bjejdu3ICq4ubNG6h1heqKWvd97cSCmzfPcOPGLdy4cROqgt3uFM95/bugqnjjc5+OtpmdQKRgtzvFbtcWKe/3FSIF167dBqCEsoH27Bh33+gpECnQ2ja+WEo7t24pCwDBuq4oZXFg2nbfXHB26xZu3bqJ5fqC3ekpyrpCa4V2L+MiPZSjNIFTawUEbZct7ey4rpCyZKW5UeXtbgeRJqElg/LUngil1XNhgKABSnW79JUFZGb+evDT2tbAnYEYjG/bc10xCou17aY4lpkFdTwDt0THCGw1M8v1CPJ53YltPuG0VQPaoZDBFEVQyK2U1JahcHtFXOm1UN1QBnPVorYpMwDIhoxQp7ryIWMTtedUoZWA2qjwMQGdptLXgI59bfOlam1tAx6TQPM8U7+J9LlR4NBLFauusWttb/OlzyHujxj30Yiq1UFUmqMQ/N6XfWd/N9awtvWsbbBUH5ONQpVh3vRWDw97KHUbkAU7EJjzjHyoB7YKJQM3yjcpZ9uXiMLeDqTBivSNpLylqdwBLImYJy3ytDK15y2Czjf7Grja1lMuhd7XAHMOan2KxNiw9itukBBiEwEQwiOpKe9Whfhd+37vUvoGUqV420W4rcSmUtQXR5XPbghYlsW9Oy2ahA0O1hc2h9oYLTTmmNdEhIjVI+8uidQuRCIby4y2fm2/LHjVp/9GfPyr/wPquifywzP15X/zm7tRzhilBmB1RdyYEIMOoKikiFPvMvPIqwKiKDT+nL/4FRtbBe7/l/ZZUXPeGLuF+yna2eoIGUKlxfxo0Y4khbxeyyLY7U6iFONnde2bt0TotyxNMNsWTEVb32mt2K3duKyKfVXUCqzaPh1QiWBXxM+Zq0P7AH1+AVjR86gVugBYlmbkXgqWIiidXzZvYKujbcK1IsZUG+/RJgJgVwrEop8crZscUpcdBYu3k/Z2aDxcfSOMMF5LCA/VprRcpUuRrgDdJUlrrVj3tqtkAz3Vd3qEK9K2+yOHaGUAxWBFpn+WWOf52J/8eQDAm+55hoOr8TlTvvlYg20agQP9dgsuusJLillnjOFZsPeDwQe3Vf9HmcMsylFkZ6Ds7erC2QHBMQVlo7049U7FBkAc03imbUYq7+wco6Op23R9bRkr2BmYzXPmqyHJ+RynhIOVx9ww1qwWqv7jUIguldbBpIGq4Sb9Fho7ScFk5VaAUegLaVazkGCFbs7wStn3jNmjPYaEbcKN1XZ23XY5W2RbKJffGEfzuWl6/AB516x8w3PtdpwdaZ+Uy6YdMgj3gvHh73onHrrziXj1b/wMfPJP/pspfbaOd2ZZN+UolHd7KcrK/Ww3eS7bp7pSui3IXqU8NlM15rX3gtJ1ZQqMNjaCzGqfCbHs3IfleVr7Ep1edhqCziPtt3FA3zVR9SAtPtq5bW3M9U2xkmfW21nAfU+kOR1Mk0D6eacB1BMdkwxKsfF3aNSHF8t4+uyZEYbY8QXjmH7TRz8X73rGXfjCv/sdnSbdjNVnvvXNsAgCI3waCnrg+ygPwhhou2DyOMxyJSRKf3egP6IEMi/O3n2lPyIx5RP/j/fyL/UyGEy78cCf6X8uDNhUGCV5d9P31gQhUcdWYza/pXLgL32eRXQOkUm0mXGQ5ZuNLU09pvQ6jzEd+rmPOhsrw9BzmTPKxCs8d2nSFaC7JGnd77HfNzC3rm1r4HVtRwQYE13X6kcJeLz6ANQ4BJP/Zs8dWhR/CLAdAobjOriZEgewctLV+JlsHoFdf35UVIkLwzVDlydWR/apSYg3V6yOqM0X0ah/NVOSFKNywLoFafVC1zZSRHOTenZx/RCYG5P1z/G1dh3Ajjhimm0mrIFYHO8j18tdlfV/0f/8OAE7us8KyQjajoG8VNOhrZJSZHNGkNbnONTld1lp6wp8AnFclmTa7bIfWpCyFUAF9/aDxT/iLW/0BsygPF56wgMP4I/99a/Dv/rcl24BnYGLoa75k/uG+sO0t0lbykBz2ghG6WBmTFLP99CwNYCTrpmiTWPNaI3xGp4fv9T/V63uYUgZ0OjblDshPhT8EYxK5KX8fKjqcZmNDtKV6O5RMcOACMqyOJ/NyihXgeaGsRKJvq5ri6RgsBaKc9AQSwaEeAw6GCRA6YVQOPAmKf0fVxzU9TtVBP/ov/sifPY//QHs1jP3dTGos9/u1eI8J/dT+Zv5P4IejB3TLjlTO/TuwIu2O70MoO5QCt7PUmAmEYA5P+N7cd+Er8Zcw1jNaM/0Jwo7+ZL224af2deNshsTLvNC2PhrIblts7TmuSuJCDle4ahJ/64BCLssZDGq0E27n9dm5z1zlR6/6QrQXZLUwJptSNIsR7bmzQUlbVgCgARiADA+f670M91a2NYK396a3mUF0N630Efede8QmDuWktdwYpVyEJg8PeJn0nl5id72XBZzLFQkgULwe9oZ6cYDECRo5ua/Yom9ihcrdiswDwmLUExCkCeru+Znxzw9BJj7c5I0Xkrvn+vNndzeKJOwntbh+nwbDgYIYygTb2pgz46bHXAZAhwU2OP3mbX/oJeS26V7V0SP9D/1rwCQUpIyk+eykGLclD/Xj6k1IlvFd3zNNwAAvv7LXuoKfNrd1sIv+5vXH3o/7nvq07CWglIjDGwz17l9+P5G0dq2K4eKebjtUZV+nsj43vROkfBEm7K2oSLuK/3kcWjgh9sl+j2oMm+sezyFs+cRnpMMn4wLO8TZNoLEC2Lhf2kKDyB1Np6NLumh1J69+j3zUIQ3IsZ79F+MwyijKfFcsyYiArxZKDy8PW0sb0E596vtFDP6uxXAQ3fcgVe+6DPw7qc/HZ//XX/X+83bmObQ//UHXgqF4ve+/GVOc4iGGJPRZkJg5lAyITSOMu8sJjk+OkDyOnU+YYvBNoa2gYcHjURDf9b6k78fS8d4Gc8fk8qtSdovmyE83lMTkIErwF6fR5Mpz7oRzz+VBgylh6TXXqrZNblIbhNra+6exrMyKA/qY/xrn1fJ24dW90ltr9IlTVeA7pKk/bp2UKcd0IkDOgt/HI8UMODGyiMDPANz9seAjs+usySIdWw55HKrlM9CPPn5EQSOjJS9cJyDSAZz/WIorS4UGXmJ6WReD9OxSHw5bRdPW/XuVyKNNAfYHMLNZEvfcetgynwC/ExRy/nNPHM5dJep3b6X1m9s6npMzLEmCtZiL9QtFt7oSksZjBGkTDOoy5nQMxfw0Nlvttoe8naPdY2NV/rv4RnF0JY2d0RiHZQpmV4OEB7cSaOlNmip2gZNqm1dSleMWpEBXj7lX/8/eMUf/EJ82//8DXjWm9+IF7zuNfi4V71yWz8yoriySVraON6BPG4MGOUxd3h2Cv2fawYHIfx0gH+lyeZ6tP/QyAQOikD4aTCWueGN7rX6Z+XaPVYIxdABAlHrdaHOzaqmlQV/L3YajDYxI5eH7fc+cT7vyn3/3b12qa3VlN0jPSA2UcexHgCPgZs1k/b2paEWhgkcBnQOIEQTNjrb7fCKz/49eOWLPgPPfvMv4H/4hr8QgIOACMuc//CiFwNQfM7/8b1e/jiaGAjOQNQssTGAa74FO8yLt2DODwK/gOEopyj1kNFpvHZIxm/r1msoMWqtT7pUTvUzwObgzUZqH7jNM3cYCCVjD2Wq6J4+4/9SSG7GHDcAd8w+bTLRf8SddK2qpPrkx4hR/CroE1fpQyddAbrLkjpzbZuCtG5flsXBlYjg5OQUJyfXNoBLSj62IMBchFvaegB7j/P1fERwcnKC/X7vHrr9fu+/OY1nZtl3A5wc5sn3oQqU0hbkl+KH3DYCEIByCdpts41lWfpawz0UbTH8YouvCdzY4uYCJP6pUGgl8Ev1GRUWVyJxWKB88FOglnmZmmQKW8ury5csMBiAtSHASvLYf6akMYghwW9eDAIrjyZtQpSU1Ivi6sDmvVERCExPSg6inhuNy5Q8G49JSDNFOgyCfpXKukhI5WNKXRMYPXQjaHRjSSlYSvaYUS2Gd3tllJV7v+TtYc+v6+qga6xtU9AUKoKTmzfxP33Z5+OHf/8fxo3bbsf3fvGX4yNf8ltw/aH347P/yQ/gab/4zk01Q/FioCJ98x2/6b+MbzVMSX1ogHfw+jXPWyj9glDGebzY++btDLCm0RfWWsOwgJAiasCa0IfxtLXazpW9vqrY1zUBsuig8NCKaYbDbPBNc3o9gn/HgOe2SCR7m5TIX7bjam07YvVyLGxy9XfcEFfGM/DgYNmNeC4PrG8aHaUssHll56CWMp6j6h2VGz61x5wHCQQogn/zGS/Gaz/hE/Hupz0dT3vXL+KP/d1vx2f93z/kfVJEUGuhvuQIl9b+y27XDBpA47FaPTTbPJcOilVRS83EKOA7d3FPMelifLAPNOfDBri3zSAGMIkG58ti437aPAfbcNaeo2F3ljZRPmqSM3psPFbFXlkgKFDsRaGlosDxHAqBbahtsOJNhFrXkG8WrdDng1bFWptclBNg18dqa56KRQDCxG3kbowtgKK6bE0iyIAbzSFrI3tTevdUq9PQbtuw3av0eE9XgO4SJQ53jN8GvEAAzdheTzr8gZRwZKFt+TLYGq1zxsQNnBlAY8Dm3o8h7xmTYuFuwi/YvdEA1+7Dc5fBppSCItJ2pgIg6F5GVWy9jdY0Ro8yipmY5WYs91cjHQcH3rS2hoKs64fyGUHSrJb59axah3acx8sxIHPMahyKdQjP2Er6+ElmQd5EaSVLaFiIc36uINHf1LY+avCTuhwMPaW5N/Nkjs/0C7k4nb+jNIZNeW8KkIGDTP6m+WedbxrUWC8Dx32aRvvGs6e3buKzX/ZdgCo+8wd/AG96wW/Az/+Gj8df/pb/FXc88D4AQFlX/O7vfzk+4ZX/LvVsqRWnt245UYS/J207gFNuA65XV9Q8HBBjv2Wg5G3nCjcHfV0gsaLe+YptPur0SYSFu4HkSAmK8DCZx85oakc99ALHMTO0kdeF+w7chsMYFekbpEgHz8UvJzA34c+JSgfcXFZ45RqrzrLJNv+K9/j9Xh9lvgKclYKzkxMfjo/cfjv+3pf9Sdz34R/uFH3lt30LbnvkEXziq18FuXWjtb9E26dhNpnP0tG7iKD0lV6bTUo6naKA1LLpFzW5RmNXhwwczGF+PEIK8eXMD07o8dIFx/NY7sinjqTMfykPGJiPTUgCA9qYMZAKfPtT73AQlebpAfrcUDzldQ3cabHx3vUWmy+dOAPAwi8L+bYPiAgbkxvZ0P+rAIrNxZQ/M/lJxa7S4zJdAbpLkkyJYc/ZcUA3Knv5L+VNwMyE8cZ71/kde+34PfbI2fVG9za0bhZyaUQm1UpYzsSaDH+HpG7Kq19vnrsCsPIxU+Anaa4umpXuQyuxUhMXt1tdB9Cyttgq4FkfZgWw9xu28kXG94fyNl4i0sQOKwODADb5NgF1qUdYBpISH9n0sWubi0w62q3f/d9Y4em1yTjieXKxsMotQJulBKIPPGtAJdQC2hQkphs9PX6bFNr7LXvtOedt4vye+s6346nvfDte+K9+GL/jf/8HuHV6DaqK+55xN7712/8B/vGXfHkqbl0WfO4//C48+w0/T32ZecUz3/gL2N24QSU1YGBq76Y+rjzn8NmNocCUOKrz1CZyDjOIJg6QCTKIuXKr4T27eXqKtz/no1okwXnAUSis1sojHuUgiOjNYW0GSGaVIqMegNMbN/ARb3pjeMfSvB7A3ATQEdEJnAGK993xRLz7rme4jLNCq4Zssee3+XPwYQOLD99+G/7BF/9x3Lh+Wyr5c17+vfg9/+T7UZYFT3rgfbjt5g1Yy+2TdJjRPkoPat8ifdIVUu6NLvEy2tmD1qJeqw4iAkTnUq3s/J79nEqkYbK3YcxeOutX49HmA3/00u2iBjyuncBGWq+VoxlNYzEAXeyaee/J4uveAnQdJr3pG4fwHHmgjTA0j6HbFbx+6UWuHbY9Ryv3HahNBBK01WUAsB96WsZV+pVIV4DukqTRS8ZhK/0qANoSd8IQkrVquGaHh0+BFoAf+iMvwbVr12CBL3wAOZ87lu4dqMdYF79OnxvRYFWSfDMwg2zOTGoAtL2weH0GKEDtEUL3gGAaAef8qV/VNFqseT3GxTI4/5EkO7tidQiIWNibPWvvH/LmHQIxrnAnUMcKM9fVyrOPLXAT0CYnkjdvABDHGYTmwcT0XeTm7TOmi6w5OS+ZWhi7153zvHk1WoGhXnSv2gjh3FMybX85eM+Uopzb9l6aNyJ48nvf47zgafe+FX/7Mz62zV1bxyuCNz/vBfg7X/fN+KlP/fRpU9+8/XZce/hhfNqP/1hWgJglav45hn+ld8hzZLzCeQRXU1jxwnYcOEAiIMXPFZszNZUJbcfT/Njv/F0oZ7dwevMmV+Ngij7OBWX1MXG9/G6fHyOZ9oSV/66778YLX/lKPOstb4KDvTS1NpNsQivV14CUFPzg53wunv72extkkhzGl/iJ1xWhBTOApetf+m1/E7/jX/xQo9Ge6WCmdHngZkelzZ2mgyPmSFXedZNkB8ulPMmCfqc5igljAvHK/BJgxhkJY4XlYRs1RT9fHAxkXjQfAR9omvG7AguzPExv88rF1CwCVJufzuKbt/hgW6sCfUfL1lft3L7mDlvbbfRz4UTiTDjk+TOLDGm6Csu0Y/XPnDF7k7N8vEqXN10BukuSOFb+mEIYoYt8VfJ9U/b736HdMceQzLEcBnXb8h+9UFEiSoc6JiVkorxAIuQy1borV6UrAaFoqVvn7Mq4AH+o8IXr88uRGKhtPWJZ4eRPh8eMcjeZby/n/ssKVT7sIT81GyePBsAkI8WQuQGvAHV2gx9jWsUB2SzEkkEdv+/XmQAabi3kLYOri6wbPBaCedEUiuNxAAy1w2vRFNgyqQvyuHLPedaOwfFEv+61P+Vj6gf/yB/Hq3/zbxt0qfbr7je/EV/8DV/j9H3jd748l2/dporf+T1/B5/8r/8lAODVn/nb8Iov+BIn7vpDD+H6Qw/581/7RZ8HdG/Z3/+LfwWv+c2/Ff/iv/08YKDiye94O5758z8HAHjkzifgDZ/0KakVOT3vZ16F2x58ECKCtz3/BbjvrrsRQCbyve3978fzf+bVnsdrX/ySTV6Wnvn6n8dTfvGdEADvvetuvO2e56X77PH7xH/3E94mP/fxnwBoxVPe8XaDPobB8cIf/zH87pd9N1QV9z77Ofjur/2LMZKH6IQ//te+Cc940xshIvjnL/0C/PSLf3P0EMmSu9/2FnzpN38Tlt0OIoK/8K1/axhTUb/f87J/iJ994Sfh7XfdhfuecRfe+tx7pnUHgE965U/69//0MR+HR+64gyvvdD/tPe/Gc974C/iKb/lruOc//yf8rT/9VQT2AB6XX/ot34xnvu2tWJYF/+zz/hBe9aLfRIaIUPw/4t578RXf+jfa9aXgf/zr35pAH6f/5vv+MT7t3/0EVBWvfNFn4J/9gZcOtY4x8Jf/zFf4Fea5GdjG4PYSNQNRX0VnbFQMAMpUqd9CngG6DTwsaDz0q3NxAhqbtZaPQd4di1LYfFeramuAHIJO8ixYOGx4f+4vPYIK4Ps/7Dav+8x/GXMsZH3oDgpI9Z1lXW+RZhBu3/uRBgYsCYAmbx1hdMTPXGch2jpNYeCL6x41oJbTla/uMqUrQHdJUl3bwn+tAmgP2amSQFjzsmk/hw4QWfpfDofUCpdJWhXrvmJ/tmLdc3hLBloM0lTVN0MxJllKSWGXs01RTOkYgaOXUSuqMV6qO5efwJy2HfegbdMTW1/YGHmFom2qsvR7nqkQ81ez/nX1SULhIV0BI2O1oMVRVP7ypgzc4mpn/JWFBtErgC0MEUT7mRXZPwel4JhQv0jY6mNNLAQtxFZR48iATbOTEGQsONtIZSM0ueB4dubVa68osII8dDF+R1A3A7eH0tE2NEw1taZvHk3rWeeF9aZS86z3mmlbT9LyESTPXnsNL/mn39d2uewejVRGbmYH+GxEAoCyob0pXlp1YyDi/AB0e08LuBIF7nrzG4dnWuU+/kf/JT77e74TAPCOj3ouvucv/ZUtkf3r5//Vb8Ddb34jFMArvvCL8ZrP/K1wTdKHiuKuN78Jf/Trvtb74a/+/Zdh2g8C/K5/9N34pJ/4MQDAT7/ks/CKz/+CzUPmQPiTX/NV7YoA3/W1fwnvfPZH9lBPhCIY/0FEsHQvn4Mff67Vv20k0vjhUkqaAyJwJ6/IdtdiXocG6rc7fuk+fPk3/SUspeCnXvyZ+MHPe+nQO1HGn/36v+Bz6Dv+zFfj7c96Ns2vCPH89Ff+e/y+//P7AQBv/YhntjPnKodQhpzY7XY4OTkJgyPN0dZU1lntsyxLTBmOFKBnaq04269+HJB58Pwx+uLyD4K73/ZWvP1Zz25eJt0a2RRwWWYyxuti9OQSmlDRvsau0nWvW+2sXGwi9DMOs7DyoeIygPsnjvZoPCt4RoCMyfybGOYuyvfTe71stz0oWh20bYBSYaHSbfOiZrwR11sEwKc+cgZV4Ac+7DY/Qy4B0q4/LGXBqrXtxKuxUZstUand6KV1RRX1NlUBlk6ybVhSkjjIfR243CeVg/dwyPI7frph44X9XFEI6I61bUHWhq7S4znJB6JMichjf/kq/YqmP/FHPgsvuOeZuHHjBh544AEAwOnpKZ7y1Cf7erf77rsP9913H65dO8ETn/hE3HnnnTg5OYGq4g1veD3WdcXp6Qme8pSn4Pbbb8fNmzfx4IMP+t+TPuzDcM9zPxrXrl3DjRs38Mgjj+C9730vdrsd/uuffDN2ux1e9bkvwkMPPYQ3vOENuHnzJp70pCfhjjvuwLVr17CuKx588EHcf//9OD09xTf+45/Bz33a87Ge7KCqeOSRR3Djxg3cfvttuH79Ok5PT5tAPTvD/fffj+vXr+Pa6Sl2XWjfeOQGHn74ESyl4Pr160nxeOj9D+GBBx/AbtnhjtvvwMnJCdZ1xdl+j4cfej+KKk52C5a+G+Yigp1974q+1gqtK4oU8mAEaErAbgB0zmIHb9Io9NzymDSDA50scoB16/Apk7sN8MOVDn7UBEyAulSjRNIhoEbAO6Ftaitsq3bIQsve0fGeKRp+XUyJZ6E5tAADU7R9EUVKfm4gbrR9Ti3MSRB3Zbmu5OWI0OdjIIrvHVs7N74fa5hI0ZoA7xSybIqKsocu7xKoUKxr3dDt+q8ry9QCQvDOdSfXqLZHIxAdXoaG51MpM6Pf8wJ6//G4oDKDKBjsdINQB4W73UmMd5sHmfx+zcZYGI0an5Hcp6SMuxIn7bgXpw3ajlUpvT1EEliKeaIoZcG6rm3nSLRyT05O/Ll1NcubBIjtYIY3rpIehdDOKV39vdPTazg52SEAlCQamJ9IiXt2fEetiFD8HkLvuyP3uWUGl9Q+B4whpv0u/YgcW7M9rte+efNmUr7HI3S4DXhssTEgvJUBqqrGZl2xCU3MF9sVWVwexO7PcKDDSxGibPaAt2u1G1YZ0Nkh6SMjynOk0TPuhqk8AdJ8d+BG4K5dH9brKX3v757Uiv/q3gfwJS/+6F6fvHyCn910p/KusvOU7vc2aGA3AK+u7XO/X91IpJ23Vgiq9nN4a0WF4uvf+gAUwFff/QTP56zX2dsEwK6cYL9fm3FDgGUpuPOOO7DrY62ue9R1BdZ91xOkGT8EKKK+o6YNpYXYEVXJo4LYy2jAfdo03aJeukwuNIcdAFJ7v/OBm/ihn33PwTa+Sh9aSUfL+KNIVx66S5JM+eK1c7XGNtVby7Yx0qZ6lGIHgce7/iQxXQ6j5Pw+7L73Y1mWpHiy8JSBqdm9ZV+xnszrNJbBSh+c9iyHtmF0vjS6KRTUPtESqVTYFsR+r3NeIWu0lWVnFtmeePZWCMrsxeA0F3SC8w+YPS+ZXZDAZtdxeUc+q8NMqhg4yVl+4JZAbvtsmd2COX6OLcBpnRMpAcfAXKqXl4nUa/mtyXuTPknnzhFoDOB4fpvNlKMRwM6eS2CY/mdwcghAuieg/SCgFSBrW2Fq5RHMIYM5Bl+HBrPToLlfap0/z2TM9qthKk1JjouHQpPIiCGDTqtAii91RbifUyWbnHJbqgGHPAoy0MoKr0UoaCfEgLopsTrWi94znl7KCOgCRDT+3fb5tWMMttNQeplzw4AZKrhtU90mrazofJL63K5bW8fcEQARDWJH8YztxPzBAN1s3szeaWu4CQDZZ2eUbtzq/LKY8YOMDaZgq0c3wPsA/mx4uY+zT+bXud0GrmWlTPmW5yU2dLW1uRGgzLNMFvAcpe8kY2e0pRJlC0QvEkqfZIGNgY3RM4ZYHp+NKKNSvM6phPRpObc1cQUWneTzG32MigBSINLaz/Uo1X5EioZOYbn2cZRaU2Ks5DFgkjnPF28PbwueXpazeF9uc7hKj+d0BeguSTo7u5UE4Lqu2O/3AOyA8T2FMtoZc80qr6ruqbPQTLceollBT05OUErBfr+HiODWrVs4OzvDuq4e5mLpkGVu/P3vP+HZ+NT/7y34T59yT7KimlJjNJgnwS36aGFZfAYd02qfpVvVPF8ASw8zqlqzQBTLHxDbsIVAnSshfi12rlLHYMFak2J4gZTb72IvhzDka/4tKtbpyttts9JBpQ3KtdNXQmHcguzIIYDPvO8V23FghBvY1I3xYaAlVbgpKOOZVk7L+K4pQpKvAVtwluvjD48tnqElAAAgAElEQVSF+DPp8wLpPAXokHHEPg8rr/k6e+hsgNjZjHYt+qf3gaJ7Ilp+Bgh0VQco3Kc2BFKNfDL052xekRlbud1UW0hnGsNWXzpz0pQ6e7TzhSg2oz3nG2SIUjRQ1rq8RJ0gPk+8HyXmD+82ae0owxmbToeYV1I8vNfGB+fBxrbw9gEcem4VsrOzRMTDxxuPa5mb0pjO5wSPodgl0vhigD/rtHxenV33tlsVkNqAjI0dB2rqoM3m5FqbF69P/mzg6zyFz6WzcTAa9NjzxtfszFP25AHArVu3Nht5JeMmgQPKMAFhWJ0QjzvN/UIADpoXZsioDKi9N6AKFFk6z4kxz/MVNC9o8GT+0n8bTQkgTw+Wh4Og3h1pLPZGGN/w0NG5oecDSxuPH/ElJtoAm/ml7br2tYW2TtB5UcqX37BiyPvbrnTe0HlcEUALapWmL6zo4ww4WYhnCBltnZ+1tlfnV6l6CUdH+1sEQO8bBcIc3b11fbzxGJSylX1X6fGZrgDdJUktnCYAnXvSag/vMKEKExBNSYiQEAtpQQJTljjkxfIen7E0C8mYWaNf9TF348U//dZpfdhL6HlZvqTcWnbuGxsUXi9PtR1ILgLfJY0UljCcKQEfOu+JBWvoXA7iFMOuiohnLpxYjp5j3ZwDnk6J3+sSkBUNNxOKl6FcKZKhToEpa66Hj9ZYU0bpVwdHrmgMgGRKP4MPet4UstFzNan6JE/7GBR+r6tuO+mQviKsHpliTkrWqGxdMM2A3Pg3ez7aQ70PE32TPHQsj+870EIoKqRkN518pXtGR7TIOHrc8zWCSpGwprvy1T6LbI8A8PnMx6L0NU2+roTHB49FKtspDK3OWGFUnO/5LZoDpOCLSIDjnPHAgwbwrbFzHvenqjoIbJijK6u2rtd4j4O2MgA6pbJt3RO3o1VCeviahWrGDqKN7VZ/r+maYXCLWsZos2YzRRRUZa2KutZQSwlsirTz2dqB6FvewDKHvXCzP1PO7X02CNq7LrdgOxyT7OCKUJ+14yGGxrfH3ODgFLMZglqnUj9EPjzzFTEH2MjhcspzO+6dUx6DlrM0L50bzVzWiFd5AzxcEFJ9ByNBev4cmXUsbeSJOFVUMyAPLesB3QCrAEnwZ9r13HpuIPCxroEjO7+BSI8aUF+TpyXW8AXV4pE9uR7G8pS+S4ji/mwYdZy46Cu7R4YQ0By6SpcjXQG6S5JKKTg728OYXCkLVIGHH36YJnzByckpbt646d61UgrWNTYxaR666gxsXSv2+xW3bp3htuuxkH60hgJNIPHxBseUUuAwIxrPvGNlLCv9nTkaMxyU99IVFNsQBSIU8kNABwEOi9CGJqz3Jg3RrjD9SRPsIS6ze5SnsmdE8yOZ21+w7ViZ7i3Gbjmle9LzYNJCE5mVOCiNSP06xZc4ANyI/lleY/3kAoKLwXbuqxEZwO/VDgW2O8DBtYbR25Me0e0Y8Y1Z+GpSqEcwtq3H6LGZbUS09dBVApxbUNer7Mk8Vva5LEAO0xNSgrt3zsCGSGoXm0++UYcD3XiGwVSomXHPAZ5s1/MB5nm3zDo/MF1XI7MEHIfkSnZvolIWqof4cEnKoBigai8tC3xuCtDawwDYwA4MJHEjKNQ39TAFedPui0VPaN/7Qn3uRU1sPlasK63lgimLC/IS+C0Az4aT0teHNT4YoE43z0f7GsiV1F61tLmhVWMeWXvZ+kGI82xbD1ZpHaxtxmJh/Gzg4fBLu3ft2jWfK6OxkUGhyadWz+bhtDWvoUh3+eFew+5l6+XBPc0hY0Yv6rqGN8tC9bc8biIT28CMOUWAzgeRfShBnHHcD2DRo/h1iH5wcWDnzFk12rwwgLLb7YiOVq/M/+ffRz51KGU9ovNSAzSwaWhztYU9VgCl8x2RPua0OPmln/2nQDvUXWIvmSJhZGyArj2431cAKyB9LecOwCp9w7km81UFq/Mdqyf6sfE2fqNu5kG1KWxjyYw2WfBGu3F7kA/Q29j66pDsvUqPv3QF6C5Jsl0kzfpj4VK3bt2isALBbtnh4bOHse7ZY1cTiIrd6Sh2vLYFyTOLKNCZzkRozYDdeUr+LARpkwepiC1MzNRITcyuZzwXKv6YmN4WCly/c4jWpKlOr3F5xrC3eblin24daJ/ZNQlBEGteWDmBW2YJIh3I7XBSzhMXA3P87EWEuinSSRF5NNbHQe8hMwBkrK8cAHIYH8vPbIC9laN0X+M5FtUp34k3YlOdyVxJRoBzGv7QfVcSbUyw1wtwPhJr2WI9bvGNSBjMdpXDgWMYFCwP4ycBkOB5iHYLeNHchzYLeXpojJOwpociq4oUftneN+Rpxpz2s6RNcXIopVu/O7hgUMLPCLWF2C2aa5E9zT7PO/JIQB9myGpUEQQYsspAz763EPu87XyQHEdUtL6JqAy7b7y+jbUAnW5YcBCQ6+UKK/FpsX+93wsBOjZUcLI5w0YF9rZxO9o121F5BBP2m42MJrcsZFVKgEsDEotvWCNuwFCtEbbLjdobJbOqAHQgIJHfGJMAdPRKssUxQ/f6m9xlTjdmGXnZ5ImcbF6MeUfBZvAw0NPqnfvtPD70aFOSlELkTZ4z2alGpwLvOG3GbDv4uypQSvtMLEv7/EZBxQozSJelA8MOCqUU1zRqfzcZlWX0zDl1zJlg/I/ifg6Mgfy7lS15LCS+dYXoLku6AnSXJBUpffeyLAhv3bqFZVl8d7Rl2eFsv/dNVGw7Zg5rMUZlAqoddVBRtR70ENgLF2Xuh8I1mkJRp6AOQAiuwWo5A4ymbLniccjaKcbYA+psQBZJGN1cC+k7g20zpe5YW7iyNCiXkc0UIkxKDjIP0mBaGCscQ3sHUD3g+ZCNbvOo0lxByvU8CuyUv2ZAxdcDpvdeHtY1eV6szAz18XUapGXEmXPtHT+Q3JXpw3NCDsyZWRjmsTYI63XUaZP30H8OKABfh6EaXnYgFFrnB2LeuQnU5f7qQ0p9J708t4Le3uT+ajFU1OvV3+zjtFnIu3ql0WdtDLY5YDMhASZTfAJrJhBr9I1zJWglhWoyLnMXxmhzHGuf6LsvIjx00T3Mw8I7Nuk1KpN5Xbw/YqVWhexNKqX29tVu1DOAV1N92IBn46J5l0puEwdFNqcJPSD3vYO83lrWNpnmeGb0yI1ttq5rumbvjJ6jSTM6aOGySpHEKw3oCe+cmagNg9qGnZ8rEsd5fZwfGC/Ixp35e/1lIkLS+Ca0l8jxQExqk+DRW8PsIU/dRT10nFgW+PTX+M7tlTh6f+Y7nn4n1qoQVDrPDjEPXVD3Q+qJP1QNg0gb58XDLnutoGjrb4vNT1VUYc1ANmOZ+YoCHQDSG4Joa742ts0gBz7YYPoqfWinK0B3SZKU4kJtt9t5GM8jj5y5VVKkLSBf96uvqWMAZ8xp7mGz9XhzQfuW592FsoSwG63Ox7xzo+LJz25Ao32Nt5uiann3OphyTU8hv50CIVjbJCHW1cOk5Y0E6OTaL196tMLRNXFG6H7LRFQWormPLmYBPETXod0ItyA2aZDpnUdd5xl9prTRpym2IwADtoCQ83B13fCEHdzL9ybVmtWFlbNj9R2vJY+OxJx0vU6y8B/n12iYWbqyvtbq4deAYLdbUIodB3IAzM3AHchjp93rWuJdB3RGMLVBG6rbScejdbTNWN/EbyRA5pZ8VTojcJuSN8/A63DcgjjQovqm/ILbtFDY7pnqNDKg8xyIh9Ue0megKKYuHwAfbcXfI4/wsDXSC5Yl8mn1ZBBvYYjUojSuGNRZiTYWzFCgqlBfY0eK/cBjGUAp1NfP2ShynD7MiXGujG02yqXU94jzFwG081V7aJ2XTfW1hmh1av2w60sNVPsmPD1kGao0Zmfj4VgKWdPKs/YMeXaI+3lbSAPYB8skMGcIx8ez4blzCE76QQ1Q1+7N5MaRGl+AnzePqPGAPo75NdNDrFoVBz15nqeNqyk9rS2SMVnQjSALIHbem6Ia8EPbVEnUPNGtSQvlq0OJ3kYdTIcZ+eLKw2xeXKXLka4A3SVJthGKJRO+69p2RVvX2pWzLpDW6h69YJw5BeM95gFr77/m0+5pu13SvceqiB9lUIMmZ0pBWE1J0+qCKsSs3SKlKGQ3GAIK/bUnbUe8LW2hVPHb9k3HSxdKqUcIjB3y1Bxus4GmATiNVnQdPpHacwsqpmOHFetBd55ZdTnvUW4fAjI5qcvErYdsBB+k/LsWtc1xhChcr3RPsPHQ+do8tN3R6oE+O5QupPAMFnp0gGQ4aDocyFLviqCNLbZAq4XsKdparNiA46DeMVFQFICUgsKHkcMwXIXvfqmDMuqgwz5j7Mb8HdqUgCIrTazUm4LsQFxZWw4gAFfwA9QwcIm6HteDrV6igJbcBvwMgBQSqEAPo1OffgG2bL5lJZB5UOuvDg6ieQA0z52IeeYaRWzrCdDG7R/0mZLa2jqArtFdu3Kc6ql9NNgB0Dw/meGIjxpqv63yysY+Nh6yPDLFHIidjwFgv9+74VNUY3fNzg+C5xrN6mGWKwRYBg8dyxe1Nja4njjfZqzMpe4gyyLjacqgjsYoyar8NoHelkF7ZiDEyp6B53ZtC+I2PAmH9YDjPE5jY51B/DSeavfMU8ztqENO/T8xowPdY4MHZDO+nI34mZEFqmsH8G0cNz9gX8vnlWPgZuUPm6BoezfrH1nnmrYMtcu8xlfp8ZyuAN0lSXYItzESO7tHVfqmJ6svMm9Ar+LWzTOcnp6QJXZ7wK1bryA9HGFFrfm8OV6IboBxtmnKY00cGhWeODvgV7CuQjt6ZsAZ6wEj2aGwuYxWgvtX7D/T2rZIJ4R+y9VyCsBgD8nFLHCh8GZB3EhTXwc3A9T2uQF2UZktBarz61JoPRSiDWY0e//O+3lcBzJac1m58IOnByXhwolAnXddr8UGoE1oaU+S4j0DcAfKPeSh474fFZ1RKR09aueB2U3/+3o1HH0v6hpzSnwNVfFt7UUKeejanPFjDXIBAZ0H5aSdPdbaevUDqNUH1uhJERFoP2IkqWmax2lS4JH70I8KEKJJ6a9/pGMBhMYghyaSN0OpjfPosv6dnIVWmyXfxqVA3OPDa/0SP13XINSBpXnnrIxoPwY47GULkNfbTyuUNsUoXtcAcqqZbxt/P+sbZlnhYl0teXb4ekPrW7vL/LOPiegL5l9tlKnmnXEZlHF4pd07PT31djDQZssNTBZayOjZ2RmqKnYiEC204yMBGwfUIVPO9mfY700JD9OFV0uz/KHOTX1BrRVX+n3z/nHYq3PYPL1yTiJoXiQN2rcP9TnJFVa/F3QY2QEO16oA6oa5sEd0TDMj4zGeFmOudj5q/dGu+wHdpY2Pary+AzYj/uvf9j4AwNd8xJ1EDLbGRbAXO+aWLTFp+kwDcycnJxAozm7FGkozfKEb8EpvWxUlgNxHiasJIVfZqCKIeRs6V3uSW8zW8EmvskDHJY1X6XGcrgDdJUlNCWuCzoS7Lfq2awz2gGatXHYLluEcE+bDoSQ0q+1UCVbFE9/zAHa7Ezzw1CckQTz7G9NFQgbYKhqsOxjfRpCKMca8q5c4XVxHxl+dW9qaOOPFI4kJzD325ALRLG/YCp5D6aC3KzIPhSprefbARkMIGUPbb3cweaQWF6D2nERj4wPKTfIPSVpaS2rWcl1JbT7UEPReHRSl9FV9TLgnCDgIhD+YqRnm1XcJ3JjbAbfeY1CgRiW0SNs4qZQ44wyIbbtF+hlmwKZueeMdug50QLc2gKPVAR3vmGt/Z2ctTDx2B2y5DKpk5K+aPEhCm514v1g9a1jq7TkHz+btQLQT8wX2TGwHSA73izYOIGeNUTuoMkC3UWq1n4c52gU2RqgoTx0gR5sYQLBusrbM3aZ0vW98UyL80pRWC2kkYoCluIc3WqZzDQJ1EKBoiTluvDltrGge1NjZ0+phRkIrnyNRPOKEjrix3+OxBQb+yrJAVJt8LAuBY2+SZAyQ7pXb7/dY6+obuxSRMEKNSR2SgMH/obT1hFH/YMKfKMnw5RDLYd4+0upydIhLXIvg5iL4U6+7F//Lx93dQdXFOPRjDwc8wL+GsFIzGI2gZ8xJBSgqqDL3qiv9P4Yhl1Kx7NrOs1J76KXrIRJAfsjPuURq6wD2m7Z5NIZL2Kjq/fbLL2Ku0odIugJ0lyQtZYFIBi+llO6ly94I2yBlXVfUtTbB5AwldrYMJcGsrWzQywrVZ/7w6yBF8M9f+uIUPjQ+a7/Ha4esm4nx8TOet4nLKEsldlfbJAHCEzly9gzmhpvwECamkeTfwLsPyr3zQlDGNT4JWE3en4HsMRwt14S+WZ1YYez6h6shIr6T2ozmsTlSKFXPcBR6s3A5ouCCKfIcN2oTHxWSEHKMJYBD0tRDd4gCl5ftXh23/ObnEPXOHj96TLMHbkwMsPiZmRU750Hr/1wZPjzGWMGtpAwLAJTSlropl2U0iReR5mpX6v2cKyKjamy6ZHzFhof3+Wj0QVeWZjzBx6l60azQO71WiH3w7oT97dJ5XRsiHUGR98nPl9t4LyTTQWNr0z8M8g7o9dYfnIrlb/Q4wEpvJr7N+dlmV6ZEMji3PFqZA3jQinU1b1yfQyN/6XyyrqvPXe3XW7sieM4A7CBwQORGMQMPdY0xQnUZxwADWft+dnbm13gsWFu0NaEt2VEIzRtrbRp1DO8bd5ggyRQbV9bHNletXAljkooBDp6TGUDyOjb3VPucI69/kjED03MZaLc7DXxx8y583FMWsN02FQWveeqd+Lj3PtT0hA0R2zTytvM8dYfkIXvPrC3i0dYBwuPMxppVIxlLeyPTLqLcFvbTNsNRBdZaUeqKBTtf0iLcVp0ODVaT+IsZZ7bGUAHZjNL1EQAeaz+TtR8Mw/JV+rWRrgDdJUllWQDsXSCaNXJZFg9RMcFoIM9CU8oyCRVqHLH/mnvXkvcPjWeOO1Tys2MetQjKWrG7tcfZyfbsKU4s2LMFkwshsSvSlIaojAtp27lvpl2pujo4FTT+nP9HTFwBGYDBIRB06Hd7aUsbK8AzBj+3hA7AVIPuBDlEvIBHB6gmyZS/sXEOpBTGFRdHzfUxJmGoA/eedbq4hHSm3ChT+28L66Xs03PTOl+gGjNL9qO1bB/ACnlOowEXm4fLsrQDxwyQtRf8zCabI9UjrbQPFfW2dP9BV1xCtWx9aN6dMMKESshhjabsj7Vpr9V4VQ3g2D27T2GH5PlxwLcS4DMlsQTwYwWwmIOPeVZSQPv7B/oiAyDySiE+Z0oYK6fQeC/47zgurJ0y3zbvAgObdsachc5aniDQR4Abq9+f1qsXZG02wh4t3XNSqM4DCFvKksCcAa++IpqOXaB7YqGnW3llx/NwOey9MxloIZheD69XyBQB/PBzox9WV4nfbQ70jV02/dj6RdHXCzJ/szlAGCoMZuzpHYDsyHA2k34co+NVettJlPCyukGCgajg/uunOCsP46te83b8zRc+yzcFSvl9UPh1pt08zzHfhrFPANPZiPHxDvZ8JXVfbxeRMOZdG8ruk1+hqLpirYDiBMtSsKu17XJa1418V5Ae1CvBBp0BPzajWS6Z/sY35kmHz6v0+E9XgO6SJAMwwnpLB3RNwMc5PQboWkhKhQVhsyIShwkDM2C3sURrxJWbED3kobP08G2neM1vegE+6j/fi9d/7LNntUq/HES58jzJl/hiEoCBG1w5MpnI9TDh0S8coIUUzkSdTKg6pGrndmFaD1ncDtT4oDBNdbF8lT+JPCGlXLcUz0qYFatUzmGagq6RRv9FStEUeG9+97F2aFvNII6UT3SlgBRpjIrTBZUVG2+KdKTBLL8PVmKFVwyI5drluWfWYh3GLoE5h2sac6UZQAJA2csBkJtKK1bG0GcG3tAPDGe+YFbsdW1guUpF86DbmZpjmBXnGt+TIm/Wa+NLDjytL7oHxEGpVSg0bFH18/mklA6Eu2eJxwzVx8vp9NaqgCiK9PM6bazbpzO04JtA49tudNoMHfaW2h95Wa0dSl/TgwBBu902BF9KO3TZmtRVYI36MFi2FmyGr7axjVottHm9WvvRXKjNU9vmR28jscOerbGoSdDG3LgO28bL7GBx9nDaNQNu3C7V1nBCfK3lKJ5sDI38oNj29TamqmKPfajhJhujV3tfCARBn9D/AzeKrw4uBf30s5w6825tmfltm1LbekX71PT88GIjQMIrqEvB255wHR9282wDSkHjo+U9/2zZ5zkTURRjm/R6a69hH2BGnlDTtWboJ7uJgpoZzb8IH1fFrvb3VhAPIxBpNNXa5rAAKLKglvDQqSAH8nS+Vzti9M3hxvYN0g/K88TjNI8lbj+j98pDd3nSFaC7JKksBWUpqMZlpAnTk9MTQNo22Gvd4+Ytxe133IabN2/i7OwMN2/dQMUeJyc73LrVdsXc78+wrjucni4oAhTRblFqIPDsbN+9e7WfZ2fb/Fq4S5xZZN4HO9fFwkBLaYd/vuW5T8c9r3sLAcWCunaF0phvBYwRV/MmSGkhcICHja2k1LhVvFvs3RratM5QdgAIKV7tocY+Kyt5jQS7nT+dnwaLVmfZpAUTRrG6mX7HGyRUU6D6S0kn54IxXicx4YAoP5OV2FQtWJAN3zPPjAH7jG1mQEsHGoOmpg9OIemGlvF7AqGsnFufpPI4R00fbtNN1vbeVv5oBwKeBSsl8UXShf6ctHa09xtgiXU/vBZpDLM7Fl42SzMvOK9xUc0bb9gzu10TC7b5yGI7uPl4r6kPmw5ToAqs++r6oynDAfIsvCiNIPLKFB+nRpt7PFVRTWFfdlBt9LRdGQHX+ClfoMCqKzXurbUSIEFXBgPcMHCx91VN3esvdGNW20a+5VdKQcHS1mD1w7HXdaURJ15uXSv264q1NoBqPM89IB0otnerHxvAa72kxKZONgxs/aFIC11UkR5OWgNQCLBI6eGz4gCx9BDD1tyCuq5tzvtYbqRV7aGy/TzCdv5oyWMdFDqJeN/njlbU2kCblEK8tW36sjc+DlNK4caD1Q6x75udjGGUI9DjucXr5vzgcAJhENvVUrxc7WeyGi0O9hg5ACiya7y6R6HUWlHXvfNI8PtCtC5LOs6B7ztoQYzL1ModKHC4K/M6D42Vdk90AD2cmzLvpzkq9NH5leVvVbuxK3jeL53h97/+PfiB5z8t8WPRtllaMmwogQ5Qfr6DB121ccDXDWNpiE0F+gZL/THpq9hUUZbGuhaaK7t+mHjpbVx7H9eeV7X+h3rdXUbaeukVUFlQlhPsINidtM131to2TEFfS6nrHrfWPRYR2k28tXmx/nZ+2upbTP8gfp26pnsUW8DBRtD1n0PUyFV6XKcrQHdJklvSSwMwbUvdirIIpBaUWtoOlfsVd9z5JOzXPc72Zzhbz1Bvrbh2cordbkGtK9Z1j3Xdd9DTrFylc9d93+3MwjV9vRzgh2U2gdvW9DkQ62felbJgWXauzIagbiCtFGnhUYSazJrnuEhKsuLXzmCrmvW1v9iyJaYZykaxfLqkEKWd1LoJzyx3Gw8LATNT4kHMWEH3RtAj8HB+AGFcJTBhFkQuKl5nsyC2DH4kgrxFmv5srYgQOMGQVxb9HOr6qEWIWS4n+XNlrVk3r9vzCWkYqBAH86GQbCkUSIThAsPB4v0reVlGy2cCcBJ94TDYyiYwaAr16LX2PGV+rtYhT/ghb6Gq+lrYFMJJfcYeDpu7Xk4HKE0pXDK9kVUfVs3fYN4+lUlfUptb27j1u88tVkQYzDBA8Po4WAKa10460AQsPNHaZ12DD9j4tq3ps9feNrYIdZLvGbhbbQ2gAzEBsPhz6DTYO7WD1bWuuHVrD5SCCmBZ1MeghcM3D0QzTi1d+QcapF5gdapgj4vPg2L9W2lYhmfF2sfDu8iq7+MBBK6dPwK1rtjvjb9X7E5OoGslg5pg2cVGNjZA2jwMmlUVu1KAAgfwVSvWsxYCacDVjHmlFOx1dbnAoMzGI9+zPCwShefD7HsLuWyAzg6QrlWbcaMbLpbFEQM45sLneylYeDzT7sptjlQP7SvSQLXtW+pgxNjFzIATE7a1dQfrMZfJWGSUmnizfZHS+PfuMbQe+fNz9lAfz2yU/MXbT/HM6yd45vtvto1kTDZ0eqx/bLx4fQKKDPIwZEtmaca/GWUOs5P5jdFf+nRwA1DoLIrW16J2bpzxkQwWgTbvVIPUOIi8oJQddssp1lKx7tcWWizNkL5fV+zXFSgFCxZIN2i3/hbv70aXuPEtR1mY/LHR1+unXH8Gf53QAzLhKj3+0hWguyxJeniMM3uEoiZdmAJNYRMLaTEFK44ZaAI0zh2y50xhWtfVLfxAKGLOpErZgD1OMy9EvxPKLP0zccPPOCRxpXuEAcTsB4uk+J/AjgqdqHOU1WStDLVlFivtG6ngh3L9oKZDpSg0tqiW/LQBIUkSc4Awk4w/oBqlRtbJ99wLrVdDieFnj3muUpHDcy5AKcsRwAli/cixemzu9zxS6J09uxHe45lH83kRoW7n1BNbYNi+Rz4AoLX28OvcNlrDKxfAmSqWq95DczWFcM7fyHXP1/J9/6P3jY8VbOdhVqLproDGPY1xek6hFAZpYD1qaKFVgGDp/Rm7YqIprX3L/1IKjaX+e2ll1x7oVcqCPpp7tELbTdLL83W90q3u1fvUlM8AGAjjgbdFA7pBP/WV90/rY2sbKejOx7wGsRTJgBnNi1uFwADMGLciogkyeKp1dSXVW7YIFl2ABQFuu/euAb7qYLL07eJHT7bJFV4bHvRY8+S55td8boQ3sxRBNYkjWRqw7BjESuRpazZdx1Y3hNg5sHWlHXVpnHNK85GpSCAP20Tj9uDp2TBwJz0sVg89FvkMN9965zW88N0P4kmP3ML913c07SegFHksJFKPXus1H85QZHCZK7jVI37oKbf1sz+jObZyfnz/2JrYAFy73YJ1XbCeSTTlLfkAACAASURBVMfG4fUUEY7ajj/n9zGfjqVBVF+lq+TpCtBdlsTWvm6ya+Ee4hYtDispRVAWDumRvpPTijivqDaBu5TN9tBAMGxbW8DegXVdPfzFnrX3ORST87LQzEWKAzogDrN1uWqGKQd1ofhF0gN/vbm60sdiVahOcWWbdHhuo4QPMPRY0sm3TfmEdw7mTfLXRLUfeI1WV6VnmuFWUkY65DOjNZSh2ROsio93BmCZQJpdOwwMDnmmjt1LitxwDRrng7Vych7ZkzN8HiAyAUMCDzNANptLx+rI9G+8fP0/Uzx4zmUVptG1369ufHFQ1F6IVuBxkNFZ++hgzjZzME8ce+q0P38UGLNibJ+aH3KgIjZH2504Y1J9bJpBKPpM4rf3zdjbPXuJjo6Q3BajYOF65pVp4VuNrrLZsbHxVlkWVNhmE3HGla0nc6XTgIRYP7b8ixkGrIUF2O6XyHyNG9QeIsXdx0OryyIFawdpduSFAH3NIAM6aZuqVDtKIrysVWu/bkp8Im6zltr+ylLSb1WF7tcOeGsP/W+h/Xz8DufJMoV3cz7PAGJjJp3BJwa8A+ilJgbxCJ7bPi5p/KvxygpUYN2vqJXOzusGUJQZv4ygdwMRQ89GuQjgLsP7zG/ju42j3leI40POQw8ignfffooHT3Z4+vtv4L2nd+Q2pef4nQDQM/Y5ys2oW/IYwkCd1SGu57Hf0k898bR55LrX1fUDld5WVG4SscH0RnAN05F2O+z2O9zs87rSeYmwHTJNThvPoTqMtEZbpV/Bo+TQG0HnQf56lR536QrQXaLEgtM8bnagani24iweW+emHWDF7pe3HHiVDvRMqLIw5cPEf/S3f2xbK6Dz0DJgK4gzKAold0e7kDmI6IqCKt8xgTa3rrnl3hXWdr0x9VBYLuIBuainJF5A5sIyMOVD5roR42DOzBXgaMp4ka6phIdutlFHCPZoH1ZKMbzBQtS2/D+/SWQk9Nzkauc5QO28a9O8uR9nYG7IJgHRCTn8rocXDuXxvLxIWNijGmdOcyPQwBmX6WUTPZtwzprnSOSI1MmuTxmYc48aIUDl+rCCWn2eR2iRAYH2TK0Vi5fHYCY8d7FRSgdzTDO5pqLvuoLUh2JSjA+MJemeDA/3zE3T6W1ry0ypVzXwCd8Ioyqt8TKAxrpo18YZ2JhxrSylreGBxiYp1HZ2vAmHqzYHk23qketmANXCvZZlafkMnq3SPTh1WZqCWmuXF90o1I+iqLZuj3jJOH/MuOdlo0eNDMY0rS1EdV1Ddpg8yOG4cZ3/xp0vj/EINTDe20qkAKV6PcosBBd9jFce6zoApn6pZlDW1iESqNFxrtn5aDF+qFCj3j9svo0YIL7GxjbZaNcojU2DisPQbZL8tdO/L4Ln/dLD+I9Pvn2g83yD1Ba6HnhOlUluc+tozvQoky3SD98mWeW/R3k4B5ftR+u/pRSc7E6gp239nHbdqcqw62pqi8yfAN5NdFKHjUFrBPJjjfVwQ16lx126AnSXJAkCbB0EdB1DlFKwlAbS9vu9hwAFoDtLgpIXoY/C1kIwf+nD74ztoAcl1j5ZAFteD915Hbc/dAO3PXQDD4uC4++7ZjjU1KzDdGuGi1i5pAtN9zXlAkkCHPO6PZprmzQqOXbpIu8eSqyYUh1JjGw8dIke1llmxyQM/Wd0Bw5ttci4NOBnYKYMeOb12D4z9gWPo1EYzmgd78vQz9xOs8SKkNM0CUPy8MzRG8pgeuhnDrfclHtEIT0vWf9oBw6saItIVyoj5C/R0jPYKA+sWZEWmueOgkOkkopoA6TvLhhGlsNKGteD6bQitY9XcRuDOlgIaiUp2+qUhUKX2trrEiAwPEiF6FJq47ZhlIXpmd5rRiIppYUX2vXumRvHu4XCRV1jExOobQwzARkabRNrzTwTb3+flSIpNH5ZlrbeT6jlDNChbzCBtnmEbZwjUjrfr9h3r5P4/zOTRsgDP/Dd2o/CA9t5hU1BtrYHImQRQJJBI6A7xCO20RNwNuVs0McO9/mWPY9zNnod7YiGvu6slto26bGdPhHRMcynmW0q4GXamDYjDE/Btv5akEeDPbVhThlwxoBpH2aQ6eUp3fPKD9m+9im343e/+T78yDOfjPefLtv2Jf3AwgzT/YGWDxiL6PAJ4JMePIOq4lV37Lw6OeRRkVow9ekW2hlww7Jgd7KD6kmbB7r29bKVxlHwCZOPUYbdFRakUfJcPCL41gBOneKrdFnSFaC7JKlqhfYQRwNyu90O165dw8MPP9w8aVL8KIPdyQ4n9QQ3b97Eft172IqI4Natm9jvz3Dz1i1cPz3Fbrfzw8hNUNphrbdu3YKq4ubNmzg5OXHgttvt0o5+nFgw3v+MJ+GnX/Tr8Ow3/CLeffcTmoV2163QtYXF1b7Q3vBdFqyhsLFVzP5MmIZS01hg27Gu79Q2eiuOAC22orMSMbW6jeuw6OtYQug254A8HX4MgDXftZtmyQulN0Ja4L+j7JDiLKBN0dCep1mTs7fOrnHljldpTKZ8bhQoUrK9jmTAOKZc5DBEJIU9v4S4T7QLJHY+21Lr30UAlP6uthC7dY1DjR8TUDvX0IDuNbENikJ54PAra1cbu7YGaayHdq2y0vOHUgZ2/X0gztVynUn7weyg4bVV/0X6Bjc+3ux63wjJle0GTBvm0YHOCRjncgxUzsCzUH36dwM4DDRX3qBDrZ1KOueNAZcixqltihKIArELJBBgDty3BXYumSt3xTxtxXmv1dTAUZqGHWT6RiYd4Nnv2vvdPYQiqP1AZQWwWxbsdqc+n1aNfjL+UDVHYZgsirkWx0XU1baBb427lAVy0jbOqicxZ02OjJ+x5jt78NigyevtVNvGQaW/wzLDaOPD1y2qRe3IBRCf9DFEoLyfu7cTC/+Mzb3MUJkAGo85DVqCx2YAZt+FM8nDesi05ysEYLqxASabO6gDhM7CizKtLCvy5skO77l+gq987dvwTZ/ynCi7jx032HjbjgaMnA6JiZkUVElLOOMdl53tyme/5xEogJ96whNbO6pEexLLWxFTMM8TLlQ9/He3W9qaThGcnJxA6x6qFfu1zdldWRrfVGC/KpZiY73lWajfxrE3dHFvt9wSptFYzZ1VPQaZcpV+baYrQHdJEiutSw+nbIJtcQXOlRwBWJk1gWfePFNK9vs9at8AZemC3dbGjecefdJPvQnLsuBnPuW5B2k85Fl55PZrfBU5TMTfBpvjTGD6kQmmsDMDVEwkAwk16KacC3ncqD4z79Ch8KOhoPzzwqXSG0rfD1PpT0i+NMGA22CUAEJjMS3sMkDcxRd9P5o081iNoYvjs4c8YukaP7/JqStsNEQCys0B4KYr/HqEODIth2g9lM57znZWTChK0ECoeRZpyLjy3oiK9iVl3LEX9etUIR2SAOFF6CBMgdiBzpXR3LfugUlaW5Q4hpmxlfpc4GnGDHqkJiNMBuZG6NYzZqOAgInWfHYc0MFN8CXp1d14iqsCBRhDCvf7ZgRoRwcoWvBDB7RmxBiMEjEGMxAQn8PN21D7M0qhgB0l+8YkQqDP7kUIZKvHriyumNpOj1iBOpybloxdAohK88hpzf0ibSt3lLbLyNQQQ4mjR7x+g7GtlJI3TxFbv2drwu34EM08wcGc8YIIUw6jSZY5dgZmO05CkbzWtrmWskpOqfPRMJzRvPMv1obEnKiNEcPt/GT9CjiQ8yNHbEigj9leLzvW5jVPeyJ+21vfi2tVcbNQ1A6BXadrU1MGKMTTH4MEnNeLq9j5CsLr6tOPwHN+mSlWQGmHYt/MqBkp9mftiKW23jXKViDWwFqb9hq2HTZpX4Bj9Zg8MB07V+nSpCtAd0lS7VZttk4CSEoGkBVkVyIULvTivCLBut87cDMPCAM6ywMA7nnTeyCl4Kc/+aMBwJnguJ7uuCdMs8YojQFmRS0swrYpAv+RnN0my8++u5XruCJ4EYAwq9/cO5Atbv7sRTRlAgnj9YuJwwEoa4gH5WeShRWuZMwATSj7hyrA9dUc+uklzis+gh9WXkdP6bH37ftwM9d3o4QotffBKiUFJlnuXV/Yjv0ZmDtI5/DcLM3GvXvSVeeDw+aLTEfpYEH2XA9Q0CcW/fbW7X1Wu0ecPYY40L9bcg2NShpNXlabxBnYJIWt+1DsGWMAFt5NaFWNjuAOBECjTkgguW+JLoh1ZgD8bLhOjgBtR8QecNDWoLWz2sou1sDt943HRhh9e78UuCKevdU2ziOsT3q9DFyjt0kFIOvarnl7RACa7dpX0EEm2pqr5uHqdUJBKYAsiwMUFePHvU00wAlHajAQNmOD9w1tSFJKnD03AjUeK6N3fvTqe3/RdzvovXqbGRKKUEv1TWK0HyAdR1/4XNPizznog8QRIAlwRcQBe8KmHDPxhRHURRtuxIC3wSTPAxIij4+4aKGdfTJ5qYDg1q7gHXdcw9e8+i34uk/7KK/fQSnEPE1nNR/eOyKPz0vM1cNIVVC64Ld1tN6mvS+dehn7JIf32vEWu90Oy7Jrc8rPIozIDHDTWU4SP8eInmTkc9oHuWRGNqG2vpjgv0qPk3QF6C5JqmuFqHoYyrhIvH03YBaAzkJ/9h28tXfb+yutdzMP3dnZGW7duuXXLBRT0S19nTFZmAJvhMKK7CHLK6lf6bqIqSusLOQ1FFtB3v/SRXQFJhRBL/scxXmmbB8EDenrZLOMWQEuCA7ToYcYOQl8K5Mf4/YUasegdS5Eo62Fnj1UtCbBbsr5UbDKesBExs/AXKL9wG/P/oDQDBBLhgAveg6ChAZTCisiEKdDfo/G4zvSOJsjh7zcfG/rZWgUW70PGTBcuVPbXU/oL545L6Uutfmmce4he7GOK99RovWVaUm5TnMd0O92NEUws/OFADNA33JcwxNjfGKar4GlQIEJkNpWKkWkHf6N6kBO0cNPq0JLzJXY2KQbwSTKiXXMESpmfROeM3EvoHQAbfSad87CME0xtHXPXmcDG2JhoQKlYwPauupWuzLwuxb+WhKgW9cVZ2f7BhLLgmUJ8DDOM1uD5vQOciP6ej4HRhngnhW67kCwFJQOkgPY5fxq7UdT2PjpQE39Xz92godw53UyjB2V8I62oesMLrO9Yc6b3BN7ZzPQjd+ER/1oIvEhNObzrI1kPMGPKAEgUvALT7odn/6O9+HJZyvuP8m7kI5ZnStXt9J+SvZFOCnblRr7aDzbNoL5/9l7l17btiQ96Isx51r73EdWZVYVTglk7Cq/ZJBtkI1sC4GQBbIRvwAJBKKFaIBEgyYdGrzED6BlIbCgbTqWZXATkEBFlSXjBjJlG9cjcbkemffec/aacwSNiC8ixphz7b1P5s2y6u49jvZZa83HeI8Y8UXEiBDJcAYjZbufqiCbXlfXywWXyxWI4PJusRLv+F8b6zTnWys7z1HeON3r5IwyvaVvemrPP/KWvglp73tsfvN5glkrp2pbRDVZ4RkDEcG6pgfMqqGrQE1VA9Dx8D434tAOFBPNM6JUz/zIfP/AVCfjxft10+/l+5gq61Mvv5wcPqXBu/fMwA9PZQ+MJv8ON1+YVIMJoqRxZkjvkX5ukrOWs5r9vLRi2YyRoQqQUwDPIXk/RV3rPjdoIkq+h/JPtLVzMVNeoSUY5lEfvte/WQPH97uODhpGZw0jwHqqfuf9eh+4Hpm/1HKQqcxnD51BtFXmQc1/MlGa3xtuHgHwGbNU+5+aGNZ/EPIc5khhlMjAnj1zNs2Vc280k8NUF5zMs6OcI1C6t08gfi45NWX1SfF76QmzzoWYJzQ9LLQ7aLNkzFA7f9eG/uPfDI4DtLSGxf8gdd67o4cCLA5MIusk5dwZ1/gZ4wwZ6s4+yX1E44XQlIkHFo+/lrD7bEzmccN9gccciFyifToA9+ax8GT4Y5dI1NXeTKA1zp/aH5JzY57zdSrNtP8MyPhzM2as97XQVQL1Q700hy2FELVU7hP1D7nGve7idPr776745c8f8O/9wv87zUnJPjxcP//LjJOmaPn72BS9yP1v/sQ0FnRmBT3QvLpOq5Da/ApcTUuHHANq4TRnypihnLeJfFDOr6RL9f1ZePGxAsO39Ls7vWnoXkm63W6QpUcwVmrUaqL2bt93SEMAsnVdcfvwGFLe6/UBvXe8f/8e27ahtYbr1Q7DPz4+4vHxMfK6XC54fHzEvlsIXTs8vIaGcNs23G63IUAsiSTB3vd+5lv4U7/9Jd595x1+gJSG7Us9+wCQYeCmMmzqZKCLpNVRwkAUCXg8t4NU9syk58w8on7y+/AM6sbipdWN+QzARp2eAZB8tXKPUWAyVgKMnhnL5oypDbOZz3jN+nw6wXRetTMgxfYJhrYd2ik47HZPaaRqmue6SDpPOH1e3USsMKcD2+Qb9CBl7xp15HvdHR8cNHSehzG2uRafApr32nlPU1Gfo2aotoMyezKf/mCAEZWyFvuNtRkYM3h7eldIE6zLJcsNIU4yJAnga5/RCyHIEZKnDlPvKnTat83rnFopn4AIdqngEEi2McCNVTLq0VXRekcXsaNo3QGMIjQP0eOeJ/OIGRzttLWQ4MV6dAuX++x3CtDc7NDPItFt/9lY7vuOZWlo7WqMZBnjUaLPshdknGiusaRzs+at+7pw15lj3v699459o1bNmPJ1XU140Rm/zYNlk7FEjs/IbGo5010Y/DUdxRAwicfz21uP8AV5FCCFj9WbcjXpn8/TbdORAd673TaI7JCWzlHqaFi5PmcL3dr3PRy50CFNBD0v9CJNR30kfEIS0jJEA1QT9JSyZxIRmp95D5qYein/VSobaxM5PoIE8AqkBo6kq9I5Lqp43kznf+Xzd/iTv/pb+Nf/1q/hv/8j3428gVzP+7YNTqEgS9SDgpF5L5kp5NnvezCGfS6ws3PKdoqgibVLxcZCpJrb+ppNcUL0GfeR2+2GL7/6Cp8C+OSTd2gQ9P2G9x/Ez6MiaKbtDYWXYN1KHeqY97JPm+yl1INAfKIDO2xodh33vrf0zU1vgO6VJO0KOK2sksvk43KT6b1jKRtk9QYmgog7xzwADFLXmdnc990DzBqDRpDIZ6umr77He3/v9/0Mfunnvouf+s3v4x98OoY3INMR5E3GtlD6HRtbATYB/DBvGedw5CXSrlPmqtwLQpxY6MeUnqkrx724038uq2zb/Syf76Fj5twqn0xCkOGg4ATA3Ov7e0DnKQlmanQnIGdVPl5jS7Tcr0AG4/WS1VCXWp9gBpFzetBUvVAKm+ClMoMjY3gX2PaOvXdsW7p/q3Sh1qGhQdZk7rKok/YH4kLpj5SQG54Zx5Ofve8O5roxs2R4g8nk9yKYKYBw7q1w+jD9Zv2q/wpjbv1b5KWlXEnwE0w942/62TenUY3S+wpxJc8j95ZOQQbG3N8nkK7CAHEnFE3EPRZznKppoQc+790DWKf5PePT9WJVAcbTKjQZ6s4eHLSsxZsk67jzncGJjYSWuzrPsvp39D5qZoQItIwHwd+ZuWQFdBHfr4C2GmCcHpgjazEmfQ/NeY8ySZ8khBwUojiOaghBY2sNCxq0gESbR+N8DCBd1wBpRlfo5O6eY3yPysbcfIKUxn438AD5/Zi1PJsfhXETacNvfHLFr372gH/8iw8BZCIOo5fZmwyeJYecBaebTZE3/nDJ65p7caUPaXJp93DaJ/NeF4KvbcPebQ60ZYG0BYC44GXkNCo7QmHT3TSN68xnPZl+lL56S7+r0hugeyXJQNgYYNXA256bNEYPmJSokeinVL6Huc/tdsOyLPjkk09C88aQBdu25SbvzPFg3iIJzqrklPeBZGq3RbCU68HgRgsFDGg7MqqTJBrcDKaHmJ4AWpXpfUob8lFmDpXB5k/mM2Y+VSY/xueeL04Oz2UuZAp0emcGdfd3+fu7kjjXPfbPHRgo43UydgZAMTAl+cr5JndvPM60quP3BP1Ajk1lwOo+WxnXBFHexpCSC6ryZdYkn82xM+A6r5Oz+g/Xjq3PaR+MTQGW9rOYhvZ4RzE+l+UitDJzXauGOaT6pW4EZDXv6tRoqPlJKJFy0+e35sAUoRVLDACI7GNhXwSgaHEtPoX5pMmTBnCPnoUsJT5nk/DgGUoOhYGkAoq7+jk6T+Z0JOnkcD3alPSN9Qx6F3MLpS+7r3EN4NYm5yLRjjaeyBArvOSfqeuoTRnmhsABCuDBLkDtHoDQdln8wxIonHPFBQGmwSxjKEeHJ9x7anvq/nIGAmP8JbVxirqOgEG/rUDGQ3WIVKbo2JYjKB2eF9MC73134UkebSDdUNXiFZagQJkTCnEutLrSDoU5+NEocwYjdawO2mFFoKgYkyzC9wsCcCd1von8nZ/4BH/ml38D3/3iA37ts4fhvei91mJRHGg1x6f0oZI4lQpy7zyl9LFX2v7wn//Bn0JXjm+lt0mPmygENY5idNaQLedJzL19x75ZbMT1smJZFxtjN2nmOglA2zt2yXVqSugGnfaJipZ7aHBHWl/nbOm6p7bkt/QNS2+A7pWk6/WKyzpK/c288ha234BEfDpFmjzu2x5ArzXBviM206+++mowu+F5u23b8P79eyzLguv1il//iXeHc3dAbrDLshw2WhEJE9CUsi4Rp2lpC7p27P7O3rvvgdy0AcBMXNIRDDdkv1cZE02GshpXMD2l6am/X5QE0Lr98L0K5upGG9cdXGtu5S+i1zN4iZ9J9ZNlAeYdUodnz9Pc8rG7JK4NQKow+vyXe/cE2Oq9O+LMp4D2/Mwspa7CiywiTaNSQ1TOzA3tm82hyhyqQK0CVZ/nbWKez9pApuEpDeRdoUKAkGMfJFNiIGPf9zDlo/AjGMkAuKUVBVzd3IwttD1w06LCLCmZmtaM8VV18ODx77q54teifappXZdoywiAx/ZWxo/Bv0uPAkBopIZ5432SY8JnPB4cvRkCw5hQ4t4W0sIlQKNIARXOiHVVYN+t/7vFXauu+glqIAjNT9XMAdSW5hlm8RiH4s6s+CzPKWuAWW8AzUx9nLTML55XU353ELhEWS2Y0947BA3msCXHQ8ScvvAcqZnzS2jLbD949LqZIxjG/ozUYdpKSLh1Z/vrGmb+ZzT4er0O57VHIWXVLHooH7WeIh1OYUeOdcw/r2pr6fDF4r7aXjTEMp3oPgHNRu/Q3j9mdrvkGUr2/bIEXYqZ3DtGDaxg8fOG0YXdnuPMDzDC/7XWp1q0pJgigdFMX5LOWRt7rIXfeljxD99d8M/96m/hL/+B3+NglmVyDpe9X1NdFzuDFLojBLl7eeZ8301cG3pJ74wypv4k74qIedttArg2vXkeqh5yoyCtOv/23qEbcNvMLdHlcsHilkjNz13ufcPiTuXUNXodCN5KmwmDykplA4d26kY+IDfpKpiPOUIp0lt6FekN0L2SNNrtJyNJIlDNUpZlcaajBTFNk8oGkSS63CT5bpgL+eZK88y//Gd+v23i5fl7JmRPacKi/iEOJJHLTTfTOZGfyVshieMrP046WHbVNMnTYCCCkSjPG4kvu2rcOrZzxFJycCpzLsocc4x+ieo9DVYFz2R7XlS+/Oyj+uxj98D1Pc3X2XwjoJ9B7EEDOIDdl5kwVqmwlX3/+RmczZ9n9Z7TDFROrxdmlfHqqpYun09NUDJYfh8EBQWAxVqdNHllHlfGozqPgSIEOnWM8tzjSf9OizuAy4GG2H9RB5Rn9LiaIlvFcLal9mURwwRwlZbjHL1UBEhBe1Wx7Rv63tNcq7Vwg38EHsNE8/I8zh2D1osAyv46kJJoa/wu4z4Il7z/WoxliYlXgbCmFpZCgNBw6iiQqMA+i8qQChSqDQRFU/Bi/ZDzITSL015W1/mZYCC9hmY7QpvsbVaIgyW49pSmg9Y14TClCZoaACcIQ3eLkRKjTiB2RtM9YjY0oGPo96p5FDXhHcFjBZ6aixNJU+wSNUHhaTSlLzlvHPGEefMZna/rieb5yvKPz0R92BYI/sY/9i38q7/0D/DX/8mfxg+ua+xls4a/pqRxpSJntOzenlTfOzySc23YfwP2af4JRo1lbIi5Hmp9VSv9NOHA5fpgni73zecTzJqjsBvd0KJ3nWlkR8FrtnXUOp/xPbl0x754S9/09AboXknqvUPWozaA2i8yl3RkotpwkzTBXKR5bJWG3lNSLCX/+fzCtm24Xq+h9TMX1RbWAMhNiRq9uknNm/Ovfffb+JN/9x/g732+oks9uwN/fmowJXNlP1PlZjTuDaoa0stkyn5nkgZVLyYTZ4AOyUCneVDZEV6E12S4L+VJ1fEdJROGceM5M1PJvGXo17MaHXFlcQfOvtfxDNWhUc+gxjNgM5/5zPofuBF3IpGaq6qBAcbNMxlJxbKkB7w57yrV3/d+yOc5QHdX83anLU8Duezx3bVCeUYqn9ee4QnEzfwG8BPMcM7NJoJewIcC2HcMzAj7MUIVkA5sewDCJg3LkibcHIN933FZjto25YwuAHTuU/Zc82DmASadvQsGk0xxaDRKPn0Kdh3gjd4Xizv/yrhGW5eBCaRjjr67RYSb3EEdGLZxzScjXedO3l+8z3PeMqyMaxbJAFoFnJEsJpfME8ZkLg5sBuccBdyhXLOsNPqyLvacw+rPUZuW4xV5lgELp03dvmtTLMsl5gX3EqYqVGS5gDkFI4AbjxWM9WMfiAhk0oYZQC/MP/vdHzFtZCAqdzCzV2JrIG5xT6VFa6zuTGZZeU9CW8t4f7NQts6r1uxsYGvpbZHgmxqwnC8JLKHuMcctDiLYvXgQ91OCXvuhflVuHMO8eLxc8OufXPHv//zfwX/6Z/+Qe09t6LofSfw0B1nfOpanQJAgcqranFQV//bf+20ogL/4T3zL9zd7VzhlvT8YFxOBT6UI+u7n33vH4+2GZW9Y1wu+/Z2fxhc/+D5+8P3fRINg7x27Auti6xU+hiRfIXwIoZM5bIl+AIJfER/GSot4fWB+3tKrSG+AHJ8VzwAAIABJREFU7pWkKtU/2xTIqHPD6wosYf4DN/WY3rUMD/nzN5kwbrJkXqpGr7qOns3OKiP7i//s78Mf+z9/Cd96v+O3Pq3TVk++8UfddI6IT2RiuOorv0OITpBST26GT4I5lDEoQHD8xnfy/0ODdKbzvln67kVAl3eeBhNPJT0OzJjCb8ALO/2ZTfv0FRm1cU9rs2QoYxQeTL0WfGsCtvmzPA1qwti/Ik8Du3F9ftwYHECdSMwfMv3GKbNV9CzIgMgdOjCuUqbTyNxybg7gozArKRhQBIdb6UitN1ILU8/WVk3X+QTIfIOfifEuK+Awzaa8PPvD/Acc/IztbO74QFpxs0/gXJvb5GR8yaAp+K+a8UW/TfPg2BQrJGhHzDPS5ZaAxIFcpTMD2ZOyEoXtKtrZWj77QMRMO6GxJhg4nfUXSa1YK7FQ932cp9H+MqfYF9Y/4z42a66yb3MP4rk6anz57Cw00dLn3cdaCVRKjwevzOvxocNYxf3ODwpPBV2qNptwwfo++pD18bmkXSHLEdANtGu6V0FqjAeXEP/KmtLy6x5FjteGNK5LKUTwF777k/hzv/T/4WHveE+TTn9epv7/qBTtTmHMUzHMAeC7H3aQFkNh1ive38J9+G6r7+9RMa50IrUo1mXB9XrB7fE9qHmjEKUtK9ay1qTkw/O1JGHjFqpDHeNbAX0kP2k98JZeQ3oDdK8k3QN0Y2DvNLnEnhtdL6CsSoEAhJezurHMjEdrDf/WX/mb6L3jv/6Xfi49gZVzcxH4tm5CE6O7LWkCetY2+z4y2CTaOj03ZRCA9mORwpnG56OAj2BwjX66mRRmOhicp3jaKf/hc3qwFpfMTDW3Gxm+0wbE+9xNX54qWODYysROhOauQtRSzMcCzafAUZqQzSDitPaFvx21k8bHKBhIPZncqV+nMp4DnYd64v6ci7xqvQJYIcaZ9Qe05Ovrnm0bGOt8VzAFM615nvVvcOoJtMj4t9bSE6BQ45PauTOt2zivE8wlgOX17JPUFOUiGrDv8N/QeYiw22QAozk8F2jmj/OCo7ZtbkOf5qIEqC4aeC1Se5iZ3yjUIXhRgCChjAP5+BjZCti8B+iWfgB05TmOeQV6Y3+ZFnBZ0tHVjefZlA5ukMACOcYJshIoH87RlYpQs1dNK2fzyXlPocBwFmYOfV8AiCqwb17/KiDwda5a13uCOtsvx1AJHNMBmINOXjDQPsoAYk+K/cu+74VRr+M8aEbr2OpIU3IsS5gU5l+EN3WO1yYekpYvZcLRxJ/72m1p+JXPH/Af/a//N/6Tf/4P21xzB2soe/5zgIl9c/cZfhECY43xeirlXBgzmigARSaxI2kBgHVeWYDxK9rScLlesa4XAKadGwupdMr3XjX834Z2TnS87htSPkSGa2Oj3tI3Pb0BuleSZkBXr1fJd56h24f7uRlWoZgeTFf4TnWlXZ/hZk9NIA+pzxq6ShwHs5O5XWPBCFhSQd20MyVxDzIaZPrj4MjXlKYNMGP+VGaibP6YiHa0cQQ/ZNRGpFH7bNzEsh+QDOG0pzyfPvYFuQPoSls021ta79U8AqAZ4MyS+CdrXzb2UTN3Vu9kQGRmQFGBmw75zc88VaczgcFTvw/vo8zyaZyDYaxtQo4gpeiHIso8AzxmE8tRky6Lm/7VnOP8DRLEdz+31yTPy9W8q5MLEZjWrx/7KzRiFYwMoKOAqE7HHempkLHiCORsPjZfQ3VdcC6VVaT5AM+yIZ5Ipuv8zBa7NAEr42UCCM2dGzX4XJYAdeMadrf/ZZxYeJIBpwyT9CG8KJa+CwaxgEPOpxnwCYBlWbEsq5+r3rDR+iLWkUZ57Dcp4x75C81Wp0L9Hct/9vo5BiznnlL/5r6PsYt+1TiDaKE6brD4iqmhHDQgmUvkVedCE5jregd0pnmx85KmGHfa1WAhP7hSPZ+MYeljRCBYQGsCnOqpNMEyQR737notPxECm9Dgq2l4x1ZqfvoSiO9lHtQOqvva3/7O5/jTf/8f4tvvN/zGwxJr9h75S3BZ6vBDgRNf18+8WnHWwGvEcq/HA44Z1vW7bRserhe0tmBdL1guF0Aa9m2zeTELREpRrMjAE8n85Dh3+dDZvHxLrye9AbpXkqr060xKWU1XKvii05N7jGObziNUjVuVklZK03uP4Oa1LNZjPjdz2ODP2lcYG4K4MybaNruRIYsbmMwTuPnheca5pqe0dLO0lOWcY4bCVJ1mVv6eS1PD5uqlCQx/A/nQC9teGL8EPPkbOAMkYxZFVnmstyLPqJTrT2raXvjMKKEd+2d8bixcYqM9AT5IBiufNQ1LSvif0wKOdTibPzNYPQONw/1ysU8AikDPbpd2y8ksmIAdC9PyxwdPnyvrsAotyOzO+Yg0d1RR44OhgLciECiVrbhgqPzUR8KAc5QfSKVr3lYZxzTBDxn+Yz8O41I0K4DF1AvPpXpOm0OwMd2LNs/9ynoh5w1BrL1S6vDU3CuALUCfZ6IwZr3zU01QppqOsvZ9j7OZXim0xbwTt4XnrSWtRGDgOdrpPHPEnizAie2eTS3rnKnWJ3WvuacBTzBtgG7fbQ9apv3r+K47+Snk0rSMkuX6POhSnLjAPHq2ZfFznZWoIZziYFoL2nUwUyf4qs+Yia2tr+pIaAR0zMHHmoCuySGwfDTM/z+jw3bTwnVHOT6ICuD71xW//Pk7/Ls////gP/uzf8gEx1Qou4fqIW4H+10kw14QWIXwt9bjnK9RTTw3CnmQfVKeyf5hiIE7bZ0SyzS+aYsSOP+WZcHjBxN2mSdRVrv2c87tmmdxh5bbPtciaYHEaBYBzIHyvqVvcHoDdK8knZkzVLC0LAvWdUn3/mqEiU5MzjRxEMHFHZ6cnX+jwxXGrNuRklOWw+Cu27ZhXW06Vk+Z1dlKMGrc3GdmH/DNRAfGMmg+N/pgspSUcdy4yIgVZrP210vS86CutqNIWlXnZh20bGGu81JyHfnn+1Nz4/rh2lD0/bbr0GexfaZWIJjkA4JLpm2qIysxwEQO51D/Yx/MJon37vH9HC+2g23PNiSDDtQ4VC1OpY+a4co4ZRXTQ58xs2Nw5Vqfszaczb9RYHEOEG09aTICNd+KC8gckoWooKHWp6zBmLtCH4BjPQZepdwjQ9Wqi/VpbY8MWmmbM80ELfF+7Z9hSuWcD20cMyqsEgGYqiJ9r4hHKnCt3QzQivYmGGefter/yHijd2NZvZzbbUuviACkCVZ3cEHTPe06aKFIG9dwiZ6MeuQzdUXv9CzMMR+1sXynJtJt9iEZ/3qNgM3ORd+Q60TdPNX7bbHzhZfLirbkPmO0fw8gZfMiUfEA0NQ8ZLaW57nrvlOFiOP809hbnlofqhphNwjoom8I0siIkwixDNFgqDkmsW8VQCeS2joAaLIUh00lJIlr7WJQurU/4jxqCjl130o4BoJJW4l7Z6iGKnDIzzTf5UgNDR4FCKWvDMzbeFT63IpgZdxje4C6b3+4edihhn23MEeQbn961LwS/HYfWwhDCVj2Kbg4CirZFPW2mpfVmJVeV9qzDJDVy8jWDSCYtEXU6ywBrlQVj4839J7O3tZ1xSeffIqvvvrKAV2LeaCkwVP/0qkU4OusjActIGRqszYp+bCL3iDda0lvgO6VpHsbWd0Yq8kK36nmKv4GKvWZ32GeT5VZgRGlonN8ulp+bMwCXHY9MpL+LE5A61nZWTe/xns4M6Q41rnm88OmZDJHQFfbdAbiVPzzDpmWk/YH7zFwuCeb34ka5gy/DqBCz/rr3jicgSzNtlVAeQfQZf396zPjEKZUTwCiCr4r+JhluXMFjHlK4HoEc4XxG0ssecppnaqEudbz7LmnhAc5FkTOBcyN/2EcN0FwLSdzQk9nWoKFWRM110hV0XqHtMXM2QAPmcD1LmHmFnQAFhaBxmkB5uSsD6f5VKqRnkhlonVWO9IGapZq1glyC50byhbvunktVZqIDNGgqZ1jnk1aronujPNJG4NuC+NrknlOIFXb47gCcOa81ntg5P13nI8u96MehW7FPqE9+HERADRV9Dq25kBusOoQAPu4BoO+p0bK8rZGMJ9ZY8k95CwW3bwXVZoQgNHNLPcwyeVc4R6Z4IdrmzWGcu6jtKvQJ4JTXzksm3kO9fX5w9AGAKCto3WBUiNZxyzKsoJYX44NhTm5VsZ9f5xX2U8z7Zn7tFIA7p0xf2pfl1oWqgczTz4fE5Y50mbXNhbQco/OzFYVhGxV8xvPKNvnpItj5ELT8H7pDw+yR43MoqV1HtK6qYlgvVzQltW0c95HWtZr9FMi56jzLISjMORpsDYKtN/SNz+9AbpXkkYgMxLtMzCXG5MzX9P5D0rH01kKhvzugbpBuo264YxS1UoU19Uk1v/bn/i9+At//W/he7//O6UdJS9UwsuNCwPTGqCtMNoDmxSZ/JipYAEOA4gDBg5y2moT+NxDnneLS8I+9tMpz10S58N9QDQ8Gk4tpvfv1uvpNGti5756Tjt3yO9OY3PuJfsxllXnG8ux5+Y8RhB3JjVmORMweEb48bGprmVARonvwGbNZRP84XBPkONbprCBBGfeRUfnGTIBfPE8q3MOLXUiaKImLQVKSbNiXT/RN2RqhYISZ7wqUzvUyzm1cDobZmfFBJB1nkEce1XpGbGwrpwn3mmK1LzRxK0y+21pAWi6mEaCNBJIx1XLshTQ6ybOXQG3sAiKV+d28rDH2JQ+jjEes6DJr0n5Hpqm1uwc2FrMX1uCQ/bD7hq9qs0MhrXkx3VPIBcCPxEsrsEcq62Hv5rqme75HX6P+IfcO9piYLSAz/yc9i3v5xC6iQA9zRijDO3DPOf+VQWM1WQ4wC2ZexTtr+Z4VnB0BopKT3ldRmA3DH/00fheCscw1AVAidXma72sbQCT0AO2rjCBE1V0KSa0J/WLOh5adH8vkfE//OJPvoP5YXLNttMWAvWPS95e7dDe0HmWEYrb7Raa6LZaOKh3795h327o+xbv5v9PlzLSP84pN0EvtPqH3S/e0u/+9AboXkm6py3jJsWg4fVMQiUMFfCFydiJhK8CxCQ6T9TFGeQ5QGyVuPLe3/yDvwf/2l/7m2h9PIdwXztRAahvEkrGcZZcGVEPmdfIg2bdTwjvmUTzpalqoliLYzOmDc0KPT573LcPv8+B3NkGnr8TGBxrNxczzoW7r41jdtZoSh917PPKTD6XqlbubKM7EzR40dNzGWYgAVoFrmmGNecz5pXMFCHMDCruaRE+Jg3vSDKVKsk2BNs81xkn38szAWxC/4N04oOMQwdUmYOMc0AqWCajWtajwIHKSItY5wroAlypJpOIzEcKw8R79xjZZPD8+VNhAft0BHTqfWmeJvlg3uc48zmClKqFISPfpIXtqsBo1t63oIOLnz9Lk8jsaXoiRhzJUp+/hb4RPGUnjSlADsZny+fwOODAZ8HS0tkFfFjYZhRQmmszY5cys0FD10fNm4igLzt6XwYwYNV6HtCNzdTDu5wz0sTa0trgnbQCUfZN1zS1owUFBNBmWt8AdN4edjsbPNa30CyGFCHYiznKvc/fkDyXy9+O+GK/Tto1rcVIDmoAVzpJmsEDqawva+QM/fgyjIrlVxluenNA7VU4rWkLKnCpOwzbbes3y0N56lQ4FvTK6v5Xv/stG4feo69GLZgEaLUJMfMKWWa9bBq3bnRLgcfHx4jrCwCXywWfvHuHr77quD1+AChgI1ivZygH2pT0VVXNQqHwVqrweQcsc9txzrO8pW9megN0rzCN6ntMG5Uzkhg3sNTiiXlSK9z6GaATaRCk++7//U/8Pnzx5Reef9ahekDTXgiUAtqNQeo977F+XcmojJv3XG8MBlo1j+wPKRuP80ADCVTvp4FZ/BrSAFNmAWb8Hyxx/TnUUQ5vOmOiueuxXfzQeuGJlJsznz9FX/nI3A6Zn5sf0GibDP0gHs4htZLTKD1R55yTMm2M8/dzUJce5EywQGbIyh61C8eymU1lPCx/KflkqkzpXKeaPgbgze1XMqpSAI7aGT628cAQk7lm2XDtA1oBUp4361bWEkTy/GfBrRF8HLa+BXvQFhCACU3byGRzfqSAZmD2rJLe1oRxUc9hPSTIyHXmVS7viLSiWRg1GhKD6+vNA9Fv++6AQAttLIy217P7X/MlERo6FWg70t9K50SuuFwuEZi6anEwvJf0DAEK7FmepwyIP8xT77J9H0xCqWHiA7EviJgpmViMrcCzmgA2mdYjMOL80hzJoU0s18oWP3eowxm1ypCfMfVndGD+FBFc1ou1rQlElkL3Weecp17Bspf1AAcCgXQD1uzbAHo69znL5zyzsesqeY5SyzMxFjaBW9QLUS9qM6U1kw0oj04k7bf9s5WyEXSY/X83HfZIjbbH/AB8/fDs4DET7r0zDeTyGvV8iLlY++35JIV25LEK1jWcKDtNmWua89lLrWNY6meAHVgWe/Rxu+GyX6Oqy7Lg4d07vP/wHntXUMublgrHzTPmbeVX4DRUdZpCBLxfJ5fyln43pTdA90oSQwTs+x6boEk+Ne4DJsn88OEDHm8fcLvdwinJ559/XiSpyWAYsTPCY9LZxc5RaENrK5osEDT87Z/9Lr7//d/G8uUX0C5ozZypfPqJ4MOH93j/1Qd8/tlP4iINj+0RH/ZHfPXVB3OF3VYYMPNAtL2j+WZghMyC2hpnKQEkrR7msKvvin2zZ9pidSQDJZqBcdEznhQmIh4bATBw6gMBVUrBMaLG+Tl4ZgWg+UMDWQ8vYbGRGUMdO7NOWXDjr1mTMSq/580wwFTd3AIA9vHxs5g+weyOzTlsugOm8/MIcnxMhm+aTAZGwPYU+LmXngZzVq8ULCi0nOMEADRBkwWYHLkEozfkW3ItYJU32ZY+PRx1LLWqQOnsWjJQx+SzCJT2UzNcNeAEdWQGq2dZ7QptCnQBUUhoULyPRLo5edlL3Lgm6dDI+1PEYpYFk8U+7wl2VQCISe0bACyFcSphC86b6+BBs89lusuzXrmejfFFs+Z1wEBntUBQoz2mVaIGxwA846yltwayaALwzB7nVOef2hnCRo1c9n+Cb3Olf7lcAkw8vPsEDw/vwukUJfRADQDujVMFZMHSLK/eFWgKKQ5XYqycod13M4vsABY619h37O7A5+JOsHiWqSP710Cdlwst41s+Pch5awt673h8fEywtF6gqti3DXvfbXxaw9oamiwB8Hee2QMGYcAsRSFI2t0pDPcuoHpWBmidcrms4Lk5Mv2m9VT0vXs4g6RD9BLbtWO7bVAo1mVFW5r1S8foNEmqiWGaa0I1zgaS3tMBCrWUCtPOqnZo79g5buuSoTLiDKrNmwXNNEFqDlIqIFL1uGgUVvicW5bF8o8+i44sAhbxEHI5h/JZjv+YOC9FSCvZjw1t8TUil2xD19zPBFiWhtYuHMVhfG0/5Lin8M2EaBJrCxB898MNqsCvXBdbdz3bJ4vxBE3JCxTNbbPxJAjjNFftDvLg/lHs3uNtQ3v/HsvS8K1v/QQ++exTSBN88eUX2K0zsXkZBGnS7AxtE3es401qyO0Gu6JbDkazhGC1CrsACgco+HlL3/z0BuheSbJNZIvvDA1AKdlZuILNPX6JSJgN8B0yugAKIWmASoBE2xgzGDl/qyqaLFiXC65Xc3P9xRdf+DMrWluhatcDnDlws72CzO6MBIx4J6FFgLq66TQI6OuqvpuArRDFYgZRsQf3kXzTGUWwzBN5ZJGeJajwPE6wXvkvASL5ltL2Y1EafVOBUMltajqZl4nxrRtzAYQITcCQCY6/7oAqndpbJdYnwC7LzYuzOeW99JTUfn7m/L5OldLoe5rw8L1kLsZm1bZwLXilzts5Vq5kcCdj5p3i96H20QqCOU2TLVWuZyDXtaItbThzJ1NmKjbPO4FguB0X9BojDGnGHc4tdNRAGb/lwDn60rR4BJVVzMFzatmjOaEGzYIMyxd1jlYd3qwtgiSoS+0PoOjulMW0J0vJR9VcqVtMNe8jkIl1baQTJeUYatZFnMHVbuBJg5pYXmT2F/dEzDWb48mGSUj8Xedn9H1p3q9WblMH4q3HWUFrZwc6Aa9k3D9JkLkUQKfdgIf1yxKgUEvbZsKi6uPidd/3bmEMyro2fjoFHsbkejgbBSH7OLYEzdmxgL+b4IQ0s4KQSu9zTopPq4UeCbuBsL4buGr0eBrDxHXlgFEVTQ1UBG2AxjlTClCgyHOiWsAe1wMK+CvnLeO8puYZtDRL9KMRsWkJGujpNvvHSLm1zYQnglArls0ullEIJrLvFHpKwGKe8z0kACvySFAwjAYsaOgETRWcBrBmzull2PK1eUbQlg2XWIus87/5d38TCuC/+IM/XWiFl+Mr2qeOzdVh05+TrTGuw86yYMtm6x0fHm/4TDuW9YK23sIpEHw8dgqtoFg06ZFZOdl1d6JqvxzsE7yNVgPHGt6R8b2lb2B6A3SvJFHyxrMXDOZKcDeHLTBm1Znhko+ZbuTGUVMYzeiR5/zZv/09fPXVl/j5n3pXaxXmmarAtu1R/rpmkFq7nu9Qim3S6WQQaeueUsN8x6izVY5hC6ih1OqefOACj2xDtPWcdkZx/vqzSabdYjC+4EaqI9M6wgDATDfOKlB/T8DgDASpFmbwvFnqX4bTStEXL2jw/Z3x/Ompnj8Oc5Izc63zMh0CHJ5xtouDxavT7zul+7PPg1J+n8t/6t1amQBxXKnK9XKnntSuaB0zZ1BL/UVybo6A1QFPNxf2ob0DQpPE80mUKEhtn+aZq7EtOe9jJqqeKo4VNOuqANDpgV8zpmgJxo9vChB1J4PJfgEythul9A0ZW03DpFHKOjaNk7oZee+Kbd8BKBrMwUlUk0yzEiwKmno4md0CF4eGLoRVVhlqwMjU51k7jTpD1c/bNDPxdDBHYZwxjR29Fdf9raGpa1z97N8u1qa+76addPDLeoT2AMngm0YLgKYml6DGgFzH5q74zb394iQ8QafGWcWcmmGeufeYe9Jk2O+C7rt5JPs3gni7JjoEYR3YXRtStc4UTjAtbcG6rAEcOSZavDiyE5o0SKOQ1dqy3SyvamKp5bXaRmDcf6vDF95vbfGpWlaqWIgVzlnrzyxH1bSyu0exH6w2uK9aJQd62RYCD7j2/B49OrtOilTbB4RUBM95l763n0jeLu0fzTrFjXqSfldAPuQWbEEFjGNZVAZ2aAgj4PCQR0tEGpZ1xeVywb5tTlsQoQuy93JHJfWKMomEw5dBqc4ZDXzJtvyWvhHpDdC9ohRnHkpMo/H6kl4rBQPRBrhhJBjSEF9FCQOYI1gDBH/qF34Jt9uGn/8Xfg7GRLWhPoDEBt7agnW9YF1Xk962jLEzbt49zK9ExM9aOcPUjOjRRj9MmGIDr0yalg3k5XAjSXvZJAbSO24e8d6Bwt4vMTbVmtspqDnPQ4f7Rad5Dxg5qDtm78xwrXvZT0aG4zylVu38+nPA5OsGc0+fu0npZ16XeHYEeZje/Zg0g/E7T9156DnAy/GOPzID4DwoUE1znXDdzCuCS16H/JNpFxGg5Rk7mq5p12SCFdCIMZX5UMrOguy9nj3MZ89MiAIUzpedy6qAM+qb1gNgzC8ybQ4u994HABBntpC0REtZUbcmaU5cO7skhUnad9a/xpBCgrkK7LqaKZxsgsFcluCodwcM5dwzgVUZsdCalvlPzQjrydAKMygY57+3o3cIOiCMRJitrZ9hWqwJXoyRdSEc0gFKLTu0ZmimXSxr07qqTGqCOQJ5sXGL9mhO4PpeteIIbRv7XzisDAqtA6hsrWHRBdgQ/VrB2dCHzWP5iVhcQunYN6czMZ4lDMAEWM+0cTEWWvsMU+IEdyFMuRZg29vVoo7ZT+yTed5IrKEaduQkKfCdLx/xuJT164KYKlRKwdMxkZ7U3zX/Ad1UbIjJFLHM0eK3NV+ix1tubqV+KG+eNDHGvuZKIbgJqy+4Xq/4oB26b9DQz0kUw5rU5g1WOfC9OPqu9sFbeq3pDdC9klS9SNbvjNlzJvVPiWSbNo0k7IxVBFTGsJjKFMDGLKpWkJpDYyjoxW3Buq64Xq+xuQNHUDQwU03CCuOgPQxzhAJMCzMUG4hTU/K8PxR+cJobmzE+jhm/q31xBvNusTNhP60anYuc0/1g5UqZQI4rgCdjV70kHQDH1wzSPjadSW3L3ZNr4+/6/g+jTfwYDFjLeXG/1YmhyQyADCNkeBRyXu9guGSs9NRiBw8OiPzsmEn+1bVvGmueQZpZtrQWTIvRKQ0AMPZTsDs5Z2XWGhrwq+sw0Wuafye4q9772GaPTVbimq3rxZl6BkInrTMaN2oUZYhHV8GQ0IRQHbjsAE0FRto11kV204rRgmJ268/Ay0F7peF6vUQQ8vAmeEJrCG4HN/L+/KwljoGvfWVerDK35YRGVJBUR7QXIZuDf1DA0CTOFonYme7O58g8t3m/SbCmXY3TCVO+omHCaJIe819ME8pg5vR62dYMKbFjj/a31rAuawBVak67a27ZV1Gun/sLIAUAxeRYVSHLclij8z7Osp8VJg0gkENSNfWlX1Sh2oAoHwPWySFN+ihu3lmFNDHuvrB+8v0jfurLR/zH/8ofr9Xy/VaH/glaJYhQb2WICgibk0z1PKHJ3KNFXKuf4M0wkmvpCiKTEBI4hi9LIGEy81A/U5zAlQKK1hqulwse3r3DFuELEgiCgqIAboK7TQWO467/6PfUt/SPLr0BuleSbrcb+kWGgJf7vuP9+/fYNhcrFqlkBVfX6zXO3InkcxDBuq5uHmkmS7fbDY+Pj1jdrGAOX6Cq8Q43Im7Et9stgB7NLm+327B5WT5JxJr4mRFpAJLxSvOSUeMwt7GH+ZOfJeG5wubmGKhml88TSgHdPScj/TEE9iDN9V3GhIwn+QhQTdDu7euhVdHy2ln5U9ZzmYI7vTAxfc+l5/rkLK9BWn9y/YfTkN3IL+WyAAAgAElEQVSvSzI+clr2GWP6XF3neib/cg4qZ0b6aZPQO20poC7G1K/RFC+07w6sqCXIStKUDlDpo3CkMoIOKMyksjjbsAkcAaZt/Us4E5ECJI25c/AHdc+atf+qGw5rD50DVLBitMeZIq4h5XUGt85zvepSHYUYAO09mDRn5/xs4QI2SpGWCF07tg/vnSlMoEhhEp3HqHekCAGwOfnY9i20Pkuz83J0aLBtW/zhEaV9EqAkwBDMZLC3HkHKt22L/iVtFZFgNL1nh3lUhWl1LqoDqOpswUwazWsqe0vFAUoR+LGO9SwlpAIVn+dNzIR1tbmyLmuc6aSWZt92PD4+JgDiuPt5Qe3mCGTvO/SRTk32eJ6mnJUjr/N527dgwtdmjk6u16sJJG4LbrdbOIoJ0LcsARwBj6e651nzAMmwvSlAKc+jx1KRCMoOVUhvTt8J3PcyHrnPnNIn5ffsY1vzgjiWxv1ReS4268O8Y25AUqDBsmhiWp8NUGbCyKbA+3XB+8sF0D1m3EBHo2zqBKf6lVocEze5IsRCrt/Ds0gQxrGp8q94T9wbraKECbHUUTSGKh6E3EypL6s9R8c/27bh3bt3+OTTTyGtYd9u+PLm89cFyV0adj8wJ83OukIktHfi/c++ewlv8QbwXk96A3SvJBmxaofFzY20mmJSysS4P0tcTybOgrDqAMD6ruFMpU3v1HpUKWpIlYGBgagaROZzj8mvUn2/GJI4Mggh8dICbuwK8peGpNA5V89v+Jg6tlZmfO5j4cU9TWn58UT58z0dLsWrZbM9BXXjbnYXvH1s+p3YVH5UYFdTMj3H/M/KPLv/MtCawI/jf/ZZ83uuHncT3yfvJDKwCcaxAK2bslt7nzMY184M5lSxK2UMLs2m6RYBDjVjdtPc+2uuTYK5YDyFpou5qmjiCVSzuhHMBe0RMkASso84Y9YScDlkDcl/9ExrKJGxogbHtWVgbd/dhLuyXgGgk1kOENJIp+hplIC4RT24CMPkrZRNQMh3dNF4L+KnoXglnoAaBXtZzRLn7GQdmfnp7sA8/5a2YHfhWOV5ybCf0xo4WM82RpvZhgKKmzsnIeMuzcFbT7o9B/om0Nj3fTCpZH5RT833d+xDX0v5x3q1Zp4Zo5wJTMf8CzCl2WY1U150Lce19ZyuRn1L7wwApM734+tWpA7v1p5m1wemdVevhCm5b2a7ck1l34WQgpVVDWuOYeyFtMpMc1X30jf3BGSewwQqj+2UEBq8OJW5StrGlSshibL2iKO/dFBy0uH+ivY+jL2tM6OntD5aL5dcb1CP32mOdDqMDseZduG5TgkQisFsdmyQRJvONPFv6Zua3gDdK0pVm9aKhI3gi05TSGTCHLOctzCmg26Ux4DjCnvndrthXXNqJYEdN9QkdPspo8H71A6eEupg4jFsDFK3pGKSVBnQ59NHAgNnUJ58pEhVX6KVKRdPGaKU1T1TsTvplNG6+/AJkHhBKR8LdJ7K43duc3pK23kOtp5q5zymT2kg5+fOgOqzWrnyft32tXwh82W8ZDLK9G6qzmRKlEFGQfy9E7EIpfQAoN285rUlmNDwfDuMpzm62Ov6zFzIZcbzrQRQpjk4z4kljGKfOCPeEsymxn4U/IBkoXSneXOkmZ3d78XVe/RD8chn5GX0wscykn6axmQpcTID2BRGMAJVl9YwPz4f7Wmp8ZvbV8F3pT2kvyZoq4IzPiOH+bdvO7qYZ8pV1gB3qh29Cgj4XumJANUFSTRpYdVA5nUAzPwhgKhgL8BsXVb0luamVeMY/YNkmgE/ByeCZV1A7SZNJEeNJaJfbWn4XtKKqWNXdPd+Su2fwMaht57v1bWiGib/TUxgeqCt6nEKyzssc6a0M505pUMCLAHWy6gQS1NwAveEGoKVUv+gGznvxnZ5MyJ8UI4ehTIB+MB2HJ0eicxmm0PHDB8VkQnKXBle1uMVyXJEFNIU2se+MG/YnqeYlpHvzsVku6wjQmPpQpp9T8G1WT1dcLmYtpfOdVrQDg16GnS1jqnA6dlRCECxwwC+3wDdq0lvgO4VpTOHKHWjqFq1cJ+tOpypIIGqGrpZGxebbQGPwQgC5VoydWeH9KuJSr0XiRwWSTnBUv1fPShtMFHPwReBFFAWmxGrPxHHeQOhY5aPTWcbMa/7lxfkkbXKfa+Y2Pgtq6jEC6egjn0ZG3OmQy09rzMt6nObyQyK5u8/LPj7erR0WZea949S13tAbgZrc9k1/48pR++UmfP4hDMpcyQYnFjfhXl0Joe5GAMhIzM+ZJ/vk1Gs5kMEO4x7aICtsCjEMsQLQHrJLPM0KEKZ8AEcnU4I47GhA9oidh4BrQLY926AscSkHM+gMWp00SgG/UhgxLaT7RSx2GQKaiqdBjr73p2zJO3jm02a+25JoFIBHkp/pIaB9wSq+0EwRlqeTPQI+BKIJy2mNuxMi8cpIDPd0KKxYb1a5t20mcc/qNPQsYyuPbx8qnZ3GpJtBQiUipdL3uOcdvA4nOH2OSEi6NLRt/SgWYE/+2rbtpyTxERco9xfWpaV7S/Pqmlq994tpiVa0ltkmxUI74ccN+6VdUzq9wGslXkfXSAJGgpc4BSx/ogYcal53IsmLdb6UMYw1cq+KB4PMs2mqRGPCVO+c+xnmjrMMi1l0rUk5r14pgb+SxX/3e//qWF+q5IHse9dw2FrrrDCZzB7aurGmT6eyUxAt7uwQH39L3EkZd+3hLbed2H2DSmjNKbcD8ZWhz6Zwpw3PPdq0huge0WpmshwE6gHqythHpyRIM1w+qTtkpJnk9xclsUIVpyvI1MSIRJWqOpwXq4yS7xWGYbqlRNwxkfJUPkmReknN58CQkePlp5iXzOCLVKZzPtHr++lMMd6AlA8BTZmzU+t5pCnlE16rgE3dR3efjKdgrofIj0FNj7W/ON3WrJ4kKK/AKQ9CcJ/xHQG7D6m/Kqde3GqU4z5CzVryHmn8FABks9CXJtetWxkmGr9cKQ7wbz3YZo3pBl4gjpqx0odJyYqwKICIuYZMe51l8irAmLmZeb4JCurEGzbZjHXiqk6tXMUUpkviCzfHL3474HRlVioHkMcgOaZs9bc3DVjpqU1gefhwcyD8Z7pWP0sTLVEHDQMtBsooCWEakfLgSpwExFs+6QlUvdYWZl4GeemAu6VLzUIKnmO0EC254XU1Lbess4eCiL6xbu59pNpU7LQoMfic6mlueTSlhxXMW+T9QgAtXMBZnc7DxegyoO1k2kOYQGyT2MekrHmuHCvKvUnjadZrrgGj/u0YjyuUMeoDgbzHIEfQgNH4GdWgWWsY+x4PAOhgdz7HmNjCFMOPAOXYRXU5AYlsR5mMDgKgptDmaMFBDXGtbYv2bhmevxr7y7BK9T68LMJgn8QpKYOMDCWQK4AvpJqe8jT0ORy37sHSG8G6JYF2w0J6IUATqHazJsr1GhKkpCxD05SbdOxhm/pm5reAN0rSRUsVW3bhw8fwtQyCRCwexwgETNNqU5RSI+XZcHD9YqHhwcAQJMFDw8PWNcV7969w6effhq//8d//V/E9773PeD73x9MPq/XK/bdDre/f/8eIoJ3794FEfzBD34Q4PJ6vUIguF6u2AE/q9chaEEk1SWf+7ZjDGpudbZNOk1cTFK6Y6cDBMC97fUEUBL/nSflRzIV1fLyOZBzyG4CFvH5AqCQUnbkJkHG2gq0ciuXXTav6sWSTNiZlu7Aod9py/jK8xvL1wXifhht2VPaxZdqGu+O3d33gCM3HjngrNjMT/wZGe6Z1LmMKesvplELMUV8n8otmoBgwCvj5RlTCxPzRk2rVQU/9vQ2AAcynCLA5XLBsqxFuzCDt+ipsc84J4NvFG+P/TK/KRTS7F4vRBgCEQq2rI17T9NGauW6mmdO9DpOCXAZINiYYw8pUIKqV8ZePBxL1ZoJBB8eP0C1h6k74CaN9F6pGcS6NXMSsm0btn07ltPKJyQ8bPa+x9nmbdtCkBYhGISx2hhKYgTk1SNx7x173wK4cM49Pj4Cbp2wLIBqBA5NQRv7FhLtpxZLqyBOR6AJuGOJ2yMnMwAxU8d6HlEEl/WCtpRA9j3BCJ2WLG2x2GkFmK1irNB6WYs2pViGELS6sKBJCkYh5sTmsl6w9z3PNbIdoWVGAr6Wz+y77T8hTChrF87gdxd2mJOWJesu1bqlY9/v0JpCMygAEfG4g07jW4AArjMJ7fSiy+DMhubRdZzEPdxyHQXYVQDURkPQliWcA6kuft+15eLgRRWms+pT/b1eNeik1NsFzQ/Nn7XJGn8iJoiBAydb5Q2LbOhqceWaAL0BbeO+eA4oxfvRHAR5L+gOQPC4bXj/+Ijr5YLLuuLdwydYLw/46quvwvAaO7B7+A8RDW+aNe5t2dqndk5HAZwmn24ib+kbmd4A3StKZxqSkchx0xnfIQCrXuH4m+fyjGBO8qMCIAnKtm07eE8jo7BtW3hf4yZFL5cigsvlAoiZcvbIV9EkJZc0Be3asUgNrFvrTy2Db2aDRiEZw0pAX0QSi0R4eF9fZo43M+bD9wBnnm8FZFMlCOryf39d7rxXgN0LBJ5Tcecg6Dkt1UvB0twPszT169KGHcFd1m0uk+kl9b5Xv+O7RyB49vy9ucR1dljfoSHg9QLihQY9aW7n6K3cR3lXg5lIdt/ylLg7tWpiPOpvdQAYwbvmmuvoZp8gr7V5lqaZ00FrJYruGrO0LjBmlu0PWFrAjThta0X4pCqQ5tqLlrSSAbnNi2I9v5WeCqUrIGk+SdMy89LbQgsYTDIkXMHPa6BJAxaWkYCOzaBzDtKive/oDlDotXEZ2pWahOZmkK2N8+1U4u9lKzQCxtsYuUdG76D62Tpj1eW7LD+CLyM1kaTdAomxizkn2f7hk3VdEuD23s1zaEtz/wCCmmCY3prTqkMPjltEi7dKhlNoMoByapgIGNmXoT0WwSLLcHwh+tnHhc7ISMkJEObYgGxP7wl+57VA7VYq9yTGsoIFClOAnEcso6Oj9QZFn+ZMPeOK7Cf4/BXN3xyfOp+izywshdcYnNAHK4XYzGqKDQ7PpX/5V34bAPBXv/v5WG9/P6iiGGVpJtPh8nKaaGArgJ3mmkeZK9ZPpBOjQyTyLARs8E96tFTSQJEwA2dLuabmPlAt/aWBld/SK0lvgO4VpSrVm8Fd1WL5ldjgKqAbPJu56SQBXXfJbTXpqWCuSonpRnuQwD4+GmgDTgFdaAIXMwcxDSKAhsGttcI3I8EAPrm5zsApAs7CTahUkiHBC8FcZOibOUHdRwK5Z7KOTymfcX8WQPqXF2MeZ+Trtmg8seZ5qSfqWu/cA6cfm9LUJvP6urR4Nc/j9+P6+Ji8ngJ0LwWwZ2nuj6cBJ1KaS+Z74nlE+R+CqxBozAVM4zgAukNdx8yT/0rQSN6Pwp/eGZ+JjOEwo+PdURNQJCYqgCTjibF5zMW1Na5Z6Bru4DPcgdMKEQdxCy5X9qlEXYzpdM0eZqDYIwRMc02UNjPpbOxjAo8yfq0ARFY+nJsU8MC+pFfJ6A8y4HCnHpqmg3TdT40I3wnPxNV8XqTQyzT1O021HQ4aTUMnsFhxEiAuTSLVQxhk2IkcmzSppPdKglwC277T6YkVy/0nTB8L0Yp1sZp2ads3A3QEXeLApzDlPKOoi5l6qgv74HuMw2wDsK6p4rk+aW7J0tsQkJ0mntASSN2fZx+FeR/nngsB1sXCY6gaItjA/ZWOSzAJW3P9VfpD7Te9zXJdDrSj/K5CWN6MvoGi7zZOFVgGbzHRzcGpTykXVXjBNaaKdJLCPHy+kB7VCVgXzEekP/6b7wHMgG4SiOWw52wt8i4B0vRyqIKvG9ZOc1Kqjl6927KEpla9SQN9lQR1taWhRZS5DAyADmFq/YboXkt6A3SvJHHzJpjixkYzRQKnZTGpIenluq54eHgIItF7x/v373G73fDw8IBt2/DhwweICG63bdDAMXxBaw1/7q/9Ar788kv8t3/0Zw4St2oyw6SaTlmqZo+JZVCiHFIxSntlR2sLzAxldwBpZpoqfqjepZ/BbKiiix+Iplc8jFvHIbj3Ca1MifF5usfQP2kCKM4+zRoIYGRmKwrVrEvkxXxEDvVTvw44iAPGZ8tnrdfp9zttssdm4PEy8HcPuLwk3evb+Xpu7PffvZfPmWT8rK2z6U/VWh34lvJc5jFeJ+4atV8ajMHdurPewfSZqaKtfynaAaB6bZQAh8FRFOzX3DsfzZeUb41Md+gdYtlmHgPoqUAODjI03o97hsz8DY25HHVtAAOe764pUwW6KJp2mElYMUfFSFcEDrBCQ6QBRrdtj77i+G6b0a71suLSVjMDLxqN0C45tyjqYEF1YPwDDHENq6/3DrS1aPYmQMM/A0w9zOeZOFcHr5AifgaQTORxbYgI1suaVg3OdPKctEacv2b029+Ns1+cqIoASXFeSgAU74AqOpxfXJo5MenNtX0OhAP8xljlZ9VcVlNLgtVKH+u5zmVZsC4rdhhAli5h5dHVArzXMZppMcd5GGuImS6yLE0QcfH4djMt5LW2LFhAr88jTYk5gqqtG4G4rTFqOBPULUsr2h6pT2dbdJxfjBE416H3bqabgxO0s3nU6kHSMR9IABnLQdDa4sSBT9g8Ie1LoU9tQwWz05/fzz7K/huq1HvSUB2BWx0BnWi4LU8H0T5WvVssyMfHW8TivKwLPv30Uzw+fgtfffUFbo+PWJcF69qgAg9qb8KVfe/uqIV9Sj1iKTfa5JYMFvzgzn7ylr6J6Q3QvZLUJAEdwwpYcN8FvVuogd41ztIBRjyufkaOxHDfN3z11Ze43W74/LPPcNs2yIcPaK3h8cPN8+kRvoCb47d/8wt88uERwLhRVUI7a+yqNKsCugR5Hryz2XkNkjiLJSRYFpfKe10AxXbb3FyzmK1QIqYWG6iJAC4ptXwLYDrpW5l+xO9nCGkFtPHKGQAaX8qsuTlNTDLfOuCe2K9PgBkSxMUzT4Grw4WXgbnjazL0wxHwjM+epadA49zHz/X1WE5u1PP85LVZI32vjvfeZTnjs3P7TrOsTxTGpjAyJXcJBiznT4I5Y/TsjIxdby5Fp6BDM5Y4zOSwhePxYGjVl2Knv8JsO4Bw1V6FC6d9BYl7dAqRwE2w3W7eJxrAc23V3M1vsd0OVJoqujQAe2IeB1DW1CXwRncm0fIyjZFAsIudh+G4324bHm+3CDhNwdm+31ygJcDlgr5t2NXNHbGENuPMxT61VdU8a1mXmCZdLVAgtVPNg5pHo8ap4U42TKtTz0oz/wroek8TunqdnyJm+l6DdAPAZb14fxLICG63Pd5beU4byEDbJJbOqArUwh50pGaM5QuwyIKmLcC/zY8WTk4I7CrACi2ZHK006pkwVfPkGMBzsfN0APB4e7R8Fs9L2zA2nEM2xxOIyJJgE8DQr9RGAoC0hodlDZpO89OuFpOsifj5xjX2rUonR0DezmkdTLMGjI7HWlsBuJawdmyZP2HOXIUoxcxyrgfbWrbXIZl2XJxOTOA0xTEgGJQIxUFMZ+1Qp13npZQ8C51GvF9psGKkx1a2BqBzk3TSFM0/n/QjoIPTOusJtIagFSKPaG3Bshj/9eln38K273j/4b3xUpKCst4VsijQBPu2hRDDJVtke7yfsw690OpWfQG8pW98egN0ryRJE3z22Wf49NNP8fnnn5dzb93jolzx7t07XK9XfPjwITamZFxuLmF6xOPjY5pCMn8p2i7/fQxPkGYy9cwb75+FQGBec5iDMC+ZpPeVGWeZTVpIZv0EQ3aMmmlmSvkQsa2M31CEgfuznYwxZtTJay/VRh00R1OmJ/BpvHqW9fTIs4R+An4yXRullOf1Hop/Anh9zDNPPXsvnZmOPakRPevhiVGaNXFnWrozwDqCTQcOT4HnJ6ZfZSoP5frLCpjmTaupG2L9a+FWGkbNG0c+PbBnW3QoP+8bo5xCmoXCEWfoU0ORzKu44AelbLp2JwPZxDQDl8ulANhiBso+gLcLYoHLa5u7Yo/KlutQtN7RFGgKoHd89f5DOU9HE8XUzNlneuq9XC4G7FrDh/fv8dX7925up7g8XLEW8E/rBdPK9SHwNWkVois0vCuKSoAxAiHABWC7OQ6pYE093l197na7DSC5mtBXKw4yy/UZc8ySwCjnqJlriiwxhDTNqxQ54t4xNECMgc+Z3rF7Py3rggsuuIiZ4W/bhr3vVsZkOs+CRNxrJjT6s2+WF51v7TTzFXMyQ81dkxaCQ5p3qiouawaApsASSE3e0gwkRxw6cTNYdVNUyT404Ovz3s+Rt2kdsx+4DjXoBFwTiiiffc9OSFnJKDCllCMEIaVMV98FaMm9UwYyKCpDjMAz4dssIMg61GMYAFzzpk0BbWM+KtAuQAlf4iXaMItAhffqfvr0nhvPutTm3r7CBjbz8RLKxK7A3l00pm7NA/POyhFqwUtwbgsYx4LrcveztnvvuD5c8fnnn+EHX3yCD48fAAC79nBS0xxYbnvHAsHaLJSKAtg3oIT09KalFYCNxRNm02/pG5feAN0rSY+Pj/GdGi5ucNfrdTggv2238HK57zv6nps8zSrtrMZkruV/lUEYQdZ4Jm8GbuNZgKwrgOHA+YEQO2MQG0gfXZ9DMpgsN/5gRjHimtiMX5he/uR5+hhQ4i8cNiaTSuem/5I8nkQJng7A7Q6Y47MvKf0lAO5j0nPv65Mb91P5zOg3n6sAas6bDExlduqzx3IohX55v8z5HKXL+RzHmYwYTafOwFjVjHkGfn0ERV7o8L6W7qpaPzPh61Bn9CXa61ZTde26VJ/8Z5pOZn0IHJIpLX1W65VdW9Y7/Mgdde4juO2qgHhobHFTtBAm2d+y1HG1+xRQBX0CAoCqg9Lr5YJlaR5gmIx/gwDoO8K0T/vobr5jsiTwsiPGmY9p1TbVhWhzoB1m8uzQonq5LG8D91Z19KNm5ycWH/pVvbx7gC7OyzUHQx6Eue8dvXXsbYfkbCjzyM+l7epAz8PdLKvXI89H65Zayb738B6qsEDhrbcA2DmIpV38rtnn97tmBOMWNoKmky3e632PgNuqo8ZPAbOY0NJmSQ0wx3bW1s1Jp3U63gMbwyvD5xBHD8jzcKIxyJXGca7nnjqaMl72EVjEmlc3qVQL1RDrt4QksmmZnlUF5pzltP+F7+XaqfuAwECyTPPV2IPsjyZ2JlSR5+joj0nFBD9K2q0adYwJM4FNVdO6GdCyv8vDisvDA67Xqzl7cxNoKeeJe5kTloeDurI853YSzLVjHPq39A1Ob4DulaTHx8eB+NIM8Xa7jd65VHG7bcX9uJnWzA5NbFMeg9SSMs4SXcvb8p+vVwJ0D9DNGrqaBMm4UithztKzXsks3pfIqZqDBAlCf2RmTt+uF19AOH9UAJPlSuGiefbqGVh1FGh/VHkJy0sdIsMjwDloGcu9HwbYnYGke6lu4GfPzoDoeB9gX9Z8ZkDH+/fKmutxOodPGLKXanLvpahTld57w8jzz5o1uDDjMItEwIP51HGbxJrSf+ZDLX1PUBfS90BvyUP6OhOoaVyodfEKapcyr7wpbeprfz6ZwCKkyaYT/kV7UjOEAErmvc/l6iEzYXn21zzicLTIAd2gjUDSJHPFb05C1vUCC6FQTL69bGp07P1CR9GgcjLvoh/T5I8aqXjf+5s0cp6/pLlJr2lymtrVu/NrGEu3e4g+p7ZHYzz23iGqxrDuuW8EbV+srQ3Ahs1Dyexoe56TG9aBgzo6NqGmaWnLYOZYHa4EuFON+Gqqii69aB+XdMZSgFlNKRQ5grpqOlv3IAoVl7bEmM3apRAqaJmtBzrjZz1P6C3Pls6C0lgbJ4nr5Oz+mYbOxlxRD5SxLuGpFMe+ka74p3751/E//Ok/CtrIBCBtDdrtvNdQN3ac92RCHFuLKdipfzjtm4Pg7eTaZLtjc04MRho9Mh6BYK4Xhy9CmlDA4VwuAV39W5YV1+sVl6vF7L3t7oUXiqURTI6ATr2v4Wbv7KEEqNn+Mp3e0itIb4DulSSaTNJsUkRS0xbn1faIU3SmhSDYqaY6SwFKlUmoppXz5k0N3Szdi/MLJXHjq262B0JcmNCBgQ0q5nWdGG7hu5UIFuD5w6TDJv6R6WsDe8ecP/qN6J/66d+Hz3Ld9vqRARkfOe/bH1+7x7Lnus3ze7wf316UNz8r41xTFVy8RGP4VJrXzfP9R2EHWRbF2U4v5b8Z1HFs1RnZrjCBDsYHg1EDck4AGdOtAgu+z7z98AfBJjyPWXBA07boh7MW870yNuRc+T3rrmFizjIUHctiZ4yH80Debmqa6rmo3jtu24altbRucDBr404AuEA1vSiGkGtpA/2owC5A2+5xzESw656AjmaWxdU8glanhu4M0I1CNgx9WxnTeGbg8nMAuiokgqKXsrx/xJ8h4CFgmPMWCPbNAN22234UgcADqSFBHRIgdi1aG4IkN1e12e+gxLEAgQe1XosuQLPzelgRZwXZxrYYWBzOH9b2gPPf/7XUzIXmFQJtfp6xK9A7Iiz7vJYpICBQlOMjdVxR5sx4nWNZ9/CytCbgcSDvkBJ+gPlM9L15eI6TCi7asXTFL/7e34Pqu6RqGeffAz2e8nuJ4FB17Afm+Wvvztne2L8dtEoTFAtT1+pp0En3sWR/mrWM2kx1TJPLPf6kCdZ2weV6xeV6tTP+++baP6dTzFusDgw+XmuOKPm4t7zhudeT3gDdK0nbLU0oGTIgzF+KhI1ut5kqeEsJYRuAWWjbyjvV5DJNRDAEtK1JVbGua9ybNTH3AF0CuayrbYISZVbmgWRSuenWHXLgHY/S13NyKYWccjM49v/HgJZTjVFprwJPOiypz+cG/zLCLvP3CczxWn1mYPyfAStn91/aNy/VztXnn5LSnj075n3/+cqAnOUfTHg5v3BW73in7slPPF+vPyc8yPlaxcbHeR23vELfUCUAACAASURBVCLzGAfj62UGsJsAVYA5sXMmvbUEgn4miGZk6o5TCqIroM8zjfbbeqYGQwvTWMtOTottKsKH0s9mrmXrP/Ib2me9cLksDuiOtIpjWxlGBi1vDh4YfBmgk5VCo2DmhwOg0TTHUy3Sf46ia5Wq58cK6DKeJjJfaUP967ysGrr8G+fEeK9qfb09obVBapjq0PmPqiUa86r1XPz8GywUwa5h8r/0BXKtTj/0uDzLZKhAr2s33Z/kPTLvodFUhBkmgdgiS4yTQiMEQQhtXOuHPb1L0nNnlDM7ZPG50ZpgwTKA0dppuQS8P6PLS99PgIH9co/OnYGmgb4fOpJ1GedhAJ6pnAbz6pgk72Qfq+sbY33OgJldkxg7THWpoG0oA+P1Kkz7Sz/7Hfs+tZnAmXU0c3H4VNPwMilI4YxQUFNbq0NvReoF1PHPzLgbLpcrLpcL3i8NfUvBB/Njq/k3zpTgCrzNGu89sYW9pW9gegN0ryStlzWcnlQN2oPbb18ulwB5Dw8PWC9rPHO5XPDw8IDWGrbthk8++QTbtuKTTz6J67ahGJHiO9frFap2kPyXfu67eP/+fXjXXJYltIEElg8PDwOg473WmtVpXfGr3/02fvaXfxO/8DOfgFo1SkFt8xRnDHckI+sMQne3zau4gNbPJOw8JG8bOBnWBEHpHGJgIP3eYdsKid3XnyjFHWh12Um07irJQR0krqdJctuI986+z/XxOg2/8aOBt5eml2q7Zs1vrcs9MEesXxmEMyA3a7Mr83Cm/cu6Azlm4/0zTQ2BlWod2xF7cZAUdIvOtjQ08ShPgsM8Nj6gmBKyjapmdtQJzHQ405F8VtFELGO/9K5en9LKwgQZGNr9HNTYEAkmbo/r4oArvd+JmWJGf4ydkhjH10HRMjXnlGXJytGL52effz6ALzJhbVmwaloi0FEF+8QcuQCXC88Qm+br8fYYgivArCbC2UkTrLKiN3NasuvuppotwN7WN+zbng5JlGVOWlrBACJMGDYK5iqoY90Z2oVMYe+Ic3XDXxnAen1zz8OsRHjUDMBpWs9wRFK1m2rn3HYxpzqsf9VmmKbOwiNIk9hLVqzmXEP8LKCbNbbezCupAsslA4ZHH1VPjWWN7X3HghQ8UutZ1/ay0KGHvbvtWwDToAXNvEQvbQkHMgEORbAuK7rs6HAwKVK03hp03vZBgohRUHVGj2rKMSMtSuBeQTV7wjSaiZ0SUxSQUJ6dP5sf2jKQXAFVFWzN+2oKNfqyQqSjSQfj7wUtRdIl8YwkTrcpLAbITMNrv4xULwUD/l6h4yiAj/QNDVhUgW4do4IQUomgnM0tNMjL792Osti54g1LMw/g276jLSvevfsUn33+E3h8vOH24RE8g8wQHeu6uHllQXllLLnHN+8l8SfDG+dbehXpDdC9ktRaw/V6jcO3eRh+GbRplThXb2lzqoxqgrLRK1rEtAPw83/yD+D73/8+2uPjuJFqBh6fGWAtxJwaur/y5/8Z/Dt/8X8GfuaTUQpMEkYmdLjjEjoUIl7v1o0eaQuv8cu/l73h6xB+nWriXgJ4CniaYRZByCQz9Cef0OlM4O2Q6QtSlSjfk7hmE/T0+pP5/xjBYGWSVHkeYe7DIwNV6zTX76n6PtXke2AuPqdsT4GzP5iiCISgYZi70U5UhOXznWaJqZXLut9pwDFzmIvxuc55nwDiaY0kmWfBUpw1VPCmh9WQ504MmDqzM4wvBmACB2Bn53zrd96LeJ7lk0y5NHM3Txo7rz4zXe1omq70q/aNvxdHyK03dEkvqgT2Nd9B4+tfK6ibAV0NDdN70uBZmFFTr9oNmWlQYeLdw2ejowyRqa/JnEs4KqmazHVZIZAAZYNWtLfYN6CIsA3UiEX+BJZ0wiKj1izCFvD8oWho8wJ4rWuAZj4nLgzk9W3bwokLASD7HWrMPpTOYSwUgS7WPxAXRCIBgpHwBC6krRQ0Dlo2H2NzrDLSg6cAXYBynL3j5RD8cP3d8XKphTj4cg4Tzbiuiuu243FNT53zvA1gB8NZWp0CjdM6xjNoN7XF5emnBGo1VaFcbP6DjGTW6BFIOS0pmmpvbnoLZvmx5oxX2veOfdvRVzu7+fDuAZfrJdZeh2vkVTJMhAJDxaJX3tJbegN0ryaJWPygM7NGElFAhrMBc6wdgGAhiXgFZHTDTEaHEtozDQbfr+U9B+hEBPuwGXielEb5BjjWFb7J2FYQTNAAzoq5SmRbQRMfHDeoM1AnJyDgufRRQEXnetVaWNncUK2ORbL7HOHnpvrCOhwv53hVgFTvz79fCua+zjRv8ufg7AzXJtNxT/v4o4LOWRvH78O9qFB+VqZaoSUYMDmMZMQqiBuEFD7vk0HSYCZHDscZwdpftexhBs0ayFFbTHPAF8kxAJPal1hMtRvGhxPSsngWQWWcBHfozk6Q5uTV6+8ZaDdgMIVSWZbigt7OA66rxZwCcDj7F/mDBqDWr3S7X2OsAUBveRYMfTwvxneHDnHSICKuFRsdQ9XvaQKWe8EZHbP6evDiyuwPedqYN8nzPna+rtB4Oea7exiIMHlcFqt/l3LGUaHuabHuHwR2kApg3US/2b7WYMB5aa59awLZzSqljm2sJ82+gyK0yFUDV4Nu994jrITCwN++7MDibQDDdQDapIy7ExsHyp11CQFDgrze+8FBWNIjc5gyp3x2AnP5QCk/r1fnMrNH05kWGc0/nzUCwd4afvXbn+E/+Gv/B/7Lv/CnAZzHHKUXz1x/OT8OYoNYx8W5GjTmIIZ7mdd/+H99Dwrgv/ojP33oq7B+KAIsttkukOZo9qeXEyRW2OpkJUwYQMFJD/Ns0/wvWNYV14cHDzDfoLr7/M7+NeeiY9y9tJRw/iYAcNLbJ8S4b+kblt4A3StJNF2kRzZuhjR7rOfaGIungqpZohtATO3cS5X0zgftAeDbv/EDXL/4Er/22eUA2uq7vF7vA+MZuvnegTkoeTCl1NkJYLyvKYkmvRaWAYjw+ZS4Sd78YYfjR0rzPjNLDuMjNmj+5aZ4T8Zne1HpAH7eAbCndXoC1NVnPiZVsDjU+4kxeErjc09bmN+nDf1O3veY/ZfW6VlAewLmhnfIfNZLHi+K55vs/FnhScqyOcyIWAsjwxBLjcwKmTECvtouzdqmRpwM0LGJVfsVra2MnMzPtqKFsTw71JnewiCXPgxMeVY+gDwb7E5QWsPtdosXaE5+u5X4bJ6lOTdoCfJgwX17p8Yk6w6kQw3vydJPDoibBPigMw3t6Qm07+l6n2NPLUzlqKkBBHAAc6wPzeXJkOc9QPVcw3GmabQhljx3hDST09bQKhB2sBTBuLWGXFDzIujju8oKXYoGLQBdgi7tmt4sodFfAdrgZpOLBuCLflUDx7PQEdOcMwFGXp/3n0HI42OgaqaYXXuEAKht4PVWhSfO+KuaFi+EBrWPat+rDuOo0zOxtvr43iGVtfds8r6faagJDWueyK1HGv7+d34Cf/hXf918/3cdHqv9GOMiABwgsw+iRAf1Iu6ZVmbamhv5PLcLlUFoXgs/kH+2Bmr3mLn31FcEdSio8SSF8JtaugB0O9Z1wcPDgx1hWZo/w/N5bHetY6HNwGEskm4B1U/QW/pmpzdA90rS7oFsW7MNxIjJhp2ArmVsOJ5XqOYaI7ibiKfGfjS8V817/tz/9IvY9x3/zZ//Y/bKCVCsad6UzuLWDc8Dw2abnKsc3xsYzlIXK41YyMCcxv6cXvpYVCGcP650FyR4XQapZf1hVD77xTdhMt9ntR7AXM2mlDe3OEbpIwHavXSuLRu/PzUP7uV1D8SdCQ9yQzzv+zOgeGRuniurMPp0WqEcI63Fjwx08IwyXSvAzBkhl0IUSTFZGMR45Vv5rd7PdeF9In5OQ/K8XV1PnEMCnfop12EIVrwPZsCTr2n5nZqFxnwo4BEAXd3qKXWEBCUo4LYyecGB+q16zozntwSlggp37oKh/GC+i7S+I4VoZEg5x3gej3VXzbHh2FKT1CTP+1UmmgIoldTuiUgABykgo/4NYNLzoiZtXNk5hjGOPs72aFkjOpqimvv8HuBWYWePjK9Pc0jdC/13k8k6s9kPNjh+zkzTIyVNJ8H5BANnfe9mpinAgmX2hj/0ZWhBpaWJYJ3MkjXi8x1uHurnHyEIEA4gACLBZtcObaP2qzunraKAA5he/jinUihqZwKrgGPcI7Nl871MCVJCk0dvK5xX/r864KZjnkE75wt/WN1FIDOAI667QrO5pgi0ct7nnBQBoG2gQ1EWJyE/Y4P2XEhYlGv8Xl8kOIqrFTBFX4whCaIewx/blkKlg9uVyvM4QLcA44rrYoJ2+jjYJXmTnuTHxyQDmEcrCuIkv2YT800/95rSG6B7Jel2u0FEsbi75n3f8NVXX6LvGxaRCHwrIti2G+Ag73K54PpwDScmZBRaW9CWNTbU1pYg0tyEVBWtMD0AwoEAzQ0ipl1hMkKSte9DftV9uD1bWRBn9JsEDefmZ8zagtam2HnBp5hrazLU1o6AfGNHOp1MduacXEphyK1uSEn2MdfTNILmO98lt5L4SBR2qHpUbsrjpPBBDjmDuvnZyKrkd2be9ZwWa25z3azqp5yU8Vw6k27Pn1VLlNzrgK9CYJC3q9AgemvIk4yCZe/MHtQPuy8JvBWFHZDCOMPrMZmsKdkSzi1BhQZkfFLGMWmwpEVdYhwdbIFzNvp5BAeKjD1Fc7r5vJE08+jHeksTBzXdGNquCUpalpHMJwFEtl1cq0ETK2Ns6BxByj1bxxIeDrm2y3kU8kH+ztIEi2tw9n0DRMy7XRNoW7CsHiBdWtGKKBb/vm/2zuPtEe/fv8ftdsPlcjHzcxiYe3x8xL7vbvrnMex0XB9Ns21d3dV596DDsLN5Cjo/sbN7rTUs0oYxax4MnSBy3zdA3SxxXZw20od/oSShPdvTHN7nE0FmTCHvxgAgooA2LCVmYMOKPSw4OK4aYXSMtrtHTtI0QbQt6Idbley9Y2l2jIBn9ax93fYvn5tQoGnD5XIJOr/BhJhXufqYL5CLYOlL9LWqWt4Qd3Ij3u/2zO12Q/dx5950uRgzzrrcbjdsPIagcA1r8fzq68xivvb43T1Q+mW9hmMytl1Bz7mjAKoKuThnoAS9YygQ0iwugiF+qWbdemjRxjUZNEdHZ2EqMNU0A377GJOmvb+u+PRxw7/xv/wN/KU/+08nLWFdnDYmTTf61+ABueOf08hGwLgaLfFziuoOVVSa/TWM4TxglWXokCB2Xm8CuepihecbuzhQazamTV1YQbrOP+F7Ermy/8n3tG3Bh9uGZbvgAQ3LZcWnn/0E1ssVt8ebjYHXbN93tyrqPn/8D9bGrs4rYTSxHExl39I3Pr0BuleS1sWXupsBbbcbHj+8x2VdsS62CVPapL2j7zv2fcMiDdfLNaS76fjEzllsvml234zofEVEgpnhu4CE50syGIyPNx/WJ9GrDlwI7up3AjjAJJpLs7MiO3rwsxBBU9rnc0NwxsmZu70zZhQZx8JGT/QwhaESm1CmCSidSgfHZwfsBwxg6vyNkn/9RG5G9VkyEEM6AULqZdc6SL1X2vMkjAoJaQKH3PzPHr/TWvZDAXYj6LrvvfI5wHdPA3j2fJ6X4G8JBVitK3me0GmpBhOmOo51mvqc1g7xcJH9AsmgEbiRAUte66hBJ6NDb4ucs5y65rU/QVgd93xHas0AIE3CuppkWGQUZAiBUnWzj+BGYpby+QjSmwCytawnX5WGIQg52y9RnveP6lAPVG1O55yyv+Zncx3zgeZ8QEdXCa0L5SSqHTsZaihu2y3K6/tuDFk3AHHDLVyUm0MR6xPTlhntu6wXiHtIvN0e3WrBXJovWMp8SRRqNJDxQMWBM5eozw1R7NuOTW8R7F0gaM2cLzQCNGLcMl/Zj5yF1GAa2evhDTHosip078O5P3A++p7Se4/g3ebwxcwjd91h5nMOkNZL0P6F3jBV0X3ONV9bm8f9I6AVAIZZrf2tAes6hs/A4gIBkLlOgWKT5h5G53VQtDRKYJtAmqDXji409L7jw+NjngdrzYUJvm+hAHhVbNutWMj4Put7V2iyvA4EsIddgkKPJuZQpJAyaTBHsZrrtHlg7pxSOmaGUZCT+0pZsyAA5/m/1FQPBF/1/2fv3Xpt27LzoK/1Mcacc+19TtUpu27xhaQSySHYQKQklTgYLCQQEoiIEPEETwgJHvgJ/AEeEeLyhuABAQEUpDwglLyAJVAEmFzs4MTxpUjssl2uc6rO2XutOefovfHQrr2PMdfe+1S5nJy1+jlrzznHpd976+1rrfXWcJ4n/MqXPsCXv/PaxwqliCGBAq7mcxwO9iT2mtK2bMhjNIKExhVOZ+QBgJruQ7aoDcCF0Mv3NRl9aYvShEbBKTTrpwIQM4oTD2CysCccuTaG0ES22IrsfV1bxaWu4CvhulaslXE+X3FYFtzdvcA8LY4Jbayu1wvmQpinyfva19dwptWFkMqjvfHs/HP6zKRnQPdEkhNQX94iIV+W2TfOvGGHdHfCrN4q4+xcME7GMzUlZnZOL7xomhRb6Ezn4psjTpedkeukjC3cdkfKzEx+3um7b4L6oHzYv5QfZt80Wg6Iagwd7Od2o8sftyEbpwc4ru2kx/MZnstA8RZg2fk+Pkk7zz4KQFOZt/Ls+/t2nd6mvAzmnPPGbTB269otk8lbQM7N4za9GIOu1ox9G3K5Dlp6MCcMg0MZbHslPRsVsi/9e2zgMLFaDuy2WXdrwPMaz54BxL32xTQzuTrkl1QLZnQjV34zNMEIijT58emWQfRedxDBGUB2oJRAYWJwzNEHQ7WKVj8FRSYIMu0dc0tlh5lUd0ZJGxtmqVKuCL3COgEGGgtQUMBFXO9XdyIl5VooAhgDr8Cz0b63YTfzTMBLaxRzojU0o3UIgD2Vkt5XwEYAF0JT+j5lz5zcwI2EASfT1m2MyiDnC0sKH2MdzXCBYhMGHaQAkk0PAQeSYZVh+0yMs/ivMQ+VDY01/ESWwmm5tv5ibwszS2N4gVj/EeeOFBD7QKcJaGNm429jXqVvp54kxD4nfS2u6+OcIAEeGzbvf7U2TLWhUg+yYw9IZrs+HVUbrqCvUN4LpU9svGP/DgrSNTOBudxWIhvrmHeel9LGvKFlStqSlXR8yriNwjqvWe5Lu2i0R/M3SiUkRkCMmxFTifiALe/JqmZDVNicz0hIAvYyGaKds/UZdFr6s4DVQ+ooqGqwIEnWIrNoqFVNLmvDuorG/rAsmOcFZZqBWpVXERBYaEq8idbbp6b2BBWfB3C6vc8jPKfPXnoGdE8kBUgT4jmV4iaVFs8nazWmaXJTIdtQu7MfgG9ALplO4Cw7MQmp8pawuKlTCjieN7beo1eW3iFtNHZvYNJTiRz0NJfec4e/F4TPGYvvcyL69LW9AQI3j71rtm+TfwZj71qWAtk9U87Ivjc/Gk09t1lu8/Jrj6ON7pnH4fp++jTj1zE9xmwk0Ovg99ESjY0KgK6ndNDAmIoCGGdaqHtuH7UZNwfnNbxOzN3cuKVB9Zy8WpKn8yagYd0rqDWghdDeZ1pngMk1Ra05Ip1KwTTNmA+L5x/CpDFsgzgzaC5cCAQbIE86QEwP5XcAlMnrb2Z90zQHrdSumBQRGLNqHoTZr0UbycbRAFdeDwpCp1KwLFv6XhJdlXUlbZlUCzzPs3h2VHNPQEInlMOiYETpu7GwifN2UzYFGOIsRVvUGqrS8rWugIoT8pmxUoK2NzXNzWe7y0SqNY12UhJoWH3MxHI+zr6X2F4zTQXMU1f30YOkg7thlrqmUueFWZq0VpPQUuuvDi6miR3QTZMKPg3MZxCv763rCujztgbcQiVkI5sUlix5/RJQ1AwzAfnor9zGENI8RqX21m4vUco7n3zWUvC5+zMO1xWX5c3s555ZfKJIqQ/CRNJNJTnaRVTk4BkFsBYNf4g/EunyvCW/rWivZyP0fZK/wm50upPr0L42ehSHxwW+qol1Qd/PMSNTnhT70HBc+PvPezynf2jTM6B7Ikn4jGxKg25zy0wwgA7QmdTSTCEz02zmJpzyHkGi3d9zqZzrMWrjRLLaa+3OywRixhc/PuObdxpkNkkawyYezrTdQHOPctT78PPNKaRnUH4ziReHovPRhU+bQhq3LePmcxi3b319L68dcLa5ciPfnDYjkOtK+xo/6SPRaNlnV9YwZ7fVinm+B+j2QEWXn82dNwDgvbbtgtUsXc+sCCdJ642ybLs2BjZLgTt2ITExm8HoH0rvcXrFWAXlSki+O/OvwKrPO8y181zyVnb9kRiyrq3bFdeNLyWTInvDgJY9P7ybr/r5JNWwESCmeyWsEIKhFs0PaZyw0JapV7oBrIztEACj2h8TQCG0JVzkudaCtrlTENWq5LnkdSYx8Wtal2nqz7LZVHUtDgKImnlm9Im4RBftmAZ/Z9PeFPeoKTGX2S0YuDDmJp4nTVNHSFpKTsZs3jWkoEVaJWWFp7+8l+T4f91Y+2yNficQGlcxifWh9paDEWEN+CDv2ZnDPD9GoY/El4uYcUI/CODwzJk1h01N7jotooJoMDsoNnPXy1XODB4WOSM3lZKOMkDzF6uYukY4BiLgoEcYpK0G2npBZzf/lT7YOOR1yDsbUHQ7AWlubdMW5MYaJkecovePMr75+Zf4kQ8/wb/5c38L/8U//8e9rqMgLguuthYVjBQKfahBDygt/9DyEv7Kj3werCbQ3kFjTxhYz3lzd7v7bkOSyXjUjPaDe/O+5/Dj8YTj8Yj1ckHj2mFkZlZzf1YzVCs09gTycX6Gck8tPQO6J5KmMjkoM5C1rutuQPHrVez5T6cTlmVx0Ha9XnFJ5wJCEhhEeZom3N3d4e7uDqfTCdfrVQ6Qq5nJSLRNq2fgMV9vrXXXAeCyTPgffvYn8C/+H7+C3/qDn08bs2ysFguvqITemKOmwY17RjsYshxT69OiOeMn2HcBY7i3YM7KfxvCuwFjjwC3sQzou+PvTUrS/913NgXcAHqDhmAsw6514+DMcZ93B4QM1G2q0TNjmTnI6dZZuzGfbaP6Mjvw1jGxfX753l59CQWsclzzXOZlDX3YTSfVRtyoLKzXesbM6hwA0IQ7BnS6e7m1GS1RctRCaaKTAQl5hwBMxTzYkTsiGvvI55uCxDGotgPg7g30jo00lWlCmTSQs+ZRazOMZF3p4JRUQyOBv3MpxiArT8qswKNirSvW9epWWw4Ii52/6+vOLOfpqjmOURP2QgSUCfNs2hu1fGDpX6F3OjYqwQ+t0uSWEuHMpJ//ZPHDdF45I+imtIzqHibN6sLqF46nLFRAHitWgOL9rh4ipV4Wy05eKEhm8WR1zM5LVgDArCBlPEed+9OEfjb/zTNmq6o/qfEckWiSLZ6b7XV2tk/AFbQfw/Tf1oOUI85VHNQZ8NO5OtvZOW7gVhy4EYn1yzzPMh9LkT2zikOu2lacHx5ARFivV3HWpWNmINHG+XI5p/BA0q92ZjIchJGbAktf7eyxnM3+BMjLc3WYNxnEhQCAGcN6Mw1XkADT51tsPlMTiUl3AnVEeH1cMCnoHcc6TF4D1I2mmG9tm0LDmoSst1/44ffRWpVzmBzjb2VuYW5OQSccPBc5o89qwUkt0VLD3pTAceJv1nXF9XLBXArmIoKlz3/wAYCG8/mMc12FjkBMoZvRJagW0Mix1izCg+St5xnYPZX0DOieSJpSQO6sbdvbQONsB3Xv1FqRPVICPQG2d0w7N00Trtcraq34S3/yD+LFyxddnbIZZ2a4s8RqjD8HAB8v8ds2MNl0dFPxjSlr74BdwkZ4AwH/HlJilJE2NP/8tIXmPMbrJqbnKG8ESjfzHJjt71fqJZ99OZt6DaBG+E9+vO4IIGffx3uP1m8jAYaX/TZD1D0zgLoxP8+X4goboDXQmsYwg8ItY2UZWl/ldlIaxORAJQEAY46Z456UZ6ETRih7A2imOthjfkYHGVCwn10zpxP+TgkviZkxZyQNWR4nnyfBjI7afKNVyl9JnQphsjPD6bxcrdA+MMaShJ4oGGstvsPAN8U54w3jmJnRJnSpmvArhUfItA4qiCgsJ3Hc5T3YvR1aWUajpS55bGwcRkY95oKBOrtv5pACbicFdSW0kSTx8DLm7faMgnCCwvB+yWOTpo1WTWZGNg+0vgLCfD9r7ARAMdo1xUkdhGYEAk0qqmN4H9ZafX5L8PLa7Q+ZsR8BhQFY1yKmgNuFCriIR8x20fiAU/M1ZUKGaZ48Nt5yWPweWM7KLd2eRlsBlNXPNHnSOSDbv1IbBBxKH5u5qnv64BjErKGL+ZsLvU0BhTyJaabRDA9qQwWP2YR+6/Mv8ZPf+G188OoBH7447j90I21o+aNE+rYFx7hfZEGggND++V26G6Xop5j9gjh3M8RhlFW2z7PWilWFPhZ77ng64nQ6YZ5nXKgXNjGznokFpi432uTv5dys+XP6rKVnQPdE0uJhCYzwi2Q4JG1mggC0Vn1jsGdFspeluXCJIXMQEmM88vm51ho+/NwJ7733AgbpsoTKNIUZaBrQs7gsmWGSgL8jcOtBJbo/Y2Jzj9At+veDSTwwyEPau/NO1R1A0pvet67ZPPMGMLTJI0n09+rUgZaxzATmaHjvVm/dAmPjM2P4jD77dxuHRwryem5KGUB4dhbhVRr6xx4RQJQA11DDfnRHpiEyMXNkY4QzWMpMcVddA53K5OTybbwdWOmait99Zr3J1G5mEEgVpXbPW3m2rrW15iQjziKFNpCt86x/QR1IEHNBiAmW118+7dxaZoQlZhvcQ+M0FfE852Z8Uq91XSUcg2sspIwGgNSTI0EDfnejRw7mHEgAG6BbCiWtQlqm6iRELkLr3JunBaNLEN8ZBmJNWykzOJscljL1AgOKLANsp741806yeWXP2N6hoEUZVune5vNR6jHrsA2C0EjDIwAAIABJREFUhATuLX6cG2Gqg5s85/x5GwOfDlnoZ2CIhvol00ubmSRAscpJQB83QJ9toUE0gDuVSZxmFPEC7dpP7e5lWby+5H0SdbL2WF2YWdzlD8DP+lHMedOQ+9zqSXqW/9lnv07tM88d67/tntrFt8ukKD334fsv8ep0wJc+fu2AbhSIdLnuXXPBRU+30ktOK0aA/lPf/gTMjL/xwd1uOU4HqN/LTAt6K/neZUtPNwOhnRGTMdfF+CDzbNpqxfE4YzkccVgOuMwLuF4hsfDcV6bPuuyYRvLddsPm4nP6zKZnQPdE0uFgDk7kdwZ0snmE90q5Z0SworWanlFRttztJLDGLO05UhlN4gy45bAFWQtof/0ZPynzel0DOPjm4g0DiNwtdbAn4yal71kmNGxAv4fpcSiHvZ1yF2h53R/Lau/98R1lynmn3LdOw3v8JpCUQVoGnDfaRUMZHRb4vdiwvoc8bwuMo52s/2TmifUZA3XGrLj03UAQBeS5Nf6hGdamsF01INczuvvV7Tkyjq/dFdPGWa06WcJOf3D/T3+R2QM8h+KJ+2ed5mjuxB6w2rSCrpbzWsgHlR7QGYNkk5FS/maOx5oXaZ84KFTtyzxPqfykdVNgYvGu7OybseCd9knjxxE0PAyLIxQiMQ/N5oiurap2viYoimgbTeim8UJdmNGPrZC9snNN5pt41ou2GjCMIODw/mHdL3L/2rUAfeauIjSUzpebkJEZRC0Byz3glYFmxFF0QDecCWeWPcPmfdP6jlpde9auT/MEYtWG6nlSy9e0fpbEkY30TWvNYwZOZfL8GAHoLCwPQcDe8Xj0PQ9ez7BcsTOsrTWgMVopwDShwOZYBtaxtnyFksG5tB70CTPFtblkTljejgQmZJ9/+xqmbcB2AOtU8LXf+hB/5ytf6HMbxmLvurbIah/fxz0zgbp8Ru1f+I2PwAz89c+fdvM3c13T1tnaH5qQ6pIpYZwnHl+ggRpmPqjpn/A8JxyWIw6HI+ZpxkUF7AHmwvLBct7/u13n5/TZTM+A7okkA3NZKpQ1Y9nMMlwo91oN2zAkNEF4ChPQVsFo7rUNiODhzIx/9pd+C8fjR/iFn/5ju4DO4tPZe4+ZXIr5jBHhXsJqrE2npQOUJ8wbhEniEphA3gbfHd0xsDHVeOzZjrgDt3fQLBLdu93lub0+AqSN4DTv3m+zk9+4n69Szq+r1LYelO51oG6vnkMd3hbMmTYjS2zflPbYn720B1riZt+fPbBGkjCTg9bQYA4j2+EfZWQ69Yze8TxT0bw1XZTqUTBfeUToVptCc5gbZKCuc+jhYFTNvpwVAVBMO5aeVhf9NGglhu5y7RZAGvDXG9O1q9jZ20QnqGwMU4MOGE2AaYzYXzdgJtofDcxtGq1b65JUOzaRatya0z7tGHUvH30IyqBAw7ZwaJjtjFrZlKlMufd7zB+j+0HX8l+cBWKfIzFmPJGPN1t4inQ+iiHtuVwvmMqMOZ13ZrDH72vNgmcbWSaEY4s0Zgm8RZ36OevCQQQINbaesqlnCcFHa2F+OIZaHrVDUT7p2CvYLgEAa6uuZXPNXiHMU1intBoOXwJM9mfYLUj7Hk2Kfc8QhZXbnI5NzWL+sY+f9K8doQjBBpXSWUbI15gjVpZ7eGWz6Onr1ZMcHt5HaPKNDnH6rtd/6Ue+iH/ub/0Kfu4nfgwfH3Y0sTfGhdlH2p7SOvEmj35nR/fcrWRCHgKclkWW5CbB28Qx70h/wwdD8zaDbl9koaHzc7rC25RpwvF0wuF0Ek+wrcLDMWjuzbKH+Pcdge277HXP6bORngHdE0l2mN7AmzkrmefZrxlYu1wuOB6PXSgDSyZhfPHihT9zPp/x8HCPWiuOp5OfDXl4eMD5LAe7/9hvfgfTNOMX/yx15Z/PZweQAFxyaX85dIJtHq01IbjJK5qDQJOaUk/23Uyh28kzW/N9SHnTyjK7fMaFhwrwjbLHjWkH5Oxdo+G+P3eL6TRgRMnMb3x21L7tZbSjoTOA0oFm2uuH1JadevqT3DNit8wt99r6NqaZ47NIfTMmAjYeOLMpaVfKHqjlmHd5nuZvoWXTJ5W7Yn+XMc5eq3pTBn4EdKmVidew4FA2TuTF8uY9r5nWQ4GQgh4PemyAwBACBejLbezPLDWE4w6ti5kkamXjfJHeZ0YxoKEVsXk0L0of9N1gMuF94wyY874tBR0PxqhMRbU/0VcWyyyHcgkawArmxFEBFwYqvE/MoUdp4lHRtFmlkJzDUok9ACAJyFqtnbZOGFxjFkUIV4q0rWh9RTBn7tp7qghvZ4711judsfpSC5ND08favVorsOgc0HpXdXrCDPX0GEIVaavytQStZz/GeU/o5l7gAh9rt8igVEfLi6SP67pibauMI5nzGatL7CU+H5sE956nScYPwZ+XYmavMcflOQNzIuScOGLNdbSHJeZZbSvqumJOZ9yt3ssy69mqqjESZW6YKW6tFaTC1QDJlL7DywZDzWADwDEDNnXt+dbsyEUPrC3fmDPRlKAhDIxmiRzAP/Ac42GZUEvBdL0CCdDleW1zrwNpSjvDgqivTFgdyBqkbl6z0w4i7sY6JyutTBPQGggyx9GSXjCXmf51LTfYBU1O50nolVRNztWaYHutFddV5uZ1rZjmGR984QsAGJfLBZd6lfE3jTrH2NrqBtQpyrjHPoO6J5OeAd1TSRzMU9aA9UQ7CAwRdWfhLIk75sXBnBFFc35iDE/YhleMaaxDdsiSbcuNAIepkTcFS4tAuXbNzJo8bRjxPWt7Ss/tg563T2YQsSlhU25sAm9XZggJ91j/x9+71ToHb5ziW3X1Q79Zdi9vQd5bteTWexkQEe2Wtbct3QJoeT7lz1vAdswrawG8zo+8O4qy31ZIoPyJAhHKAw1DfRLEnLozbJyeijrLFT8vtNOuVHJXh/EH9f/sJB7yTfml8l0Y4QwmIE5X4GPOOuakTFh6sRMIpKJ1YiedIoXZp3QDu5fFCCqudXYvKUnIk+aJOzSxtUyEAglU7MZVqU2mcTMLAWAbzwyQ83JMCuY0ZEDVd6sKqZhzEGJ4vmCOGHraAS1pmzrwqV43SzHgAdW29Kaq7I23PrQiY+7lPjfG3Hs9ExYKui6PS4w5Y8DZ6901TfIjDXJeLFZfXrt8e+0mQOtIywV/1BElbbEDBFIzUk6Axk1ZmwUsbyDWazov7az5VAowT2iVUBPAYwbqGscULJ5egEDZL6dSgGURz9Eq3OzOdirgNNPNUoI+2H7YmEG1avniCCX6ridJ3vZu4GzMM9DrwZT13k7Xd9diuQ6U7xFC+Nufe4l/96/+PP7DP/dnu+ujZi5fj2ujFnpfaJnpg/U9aT1vC/4yeBfwN54f9h1qoLXek2M3+O8o0+mR8TwcR06WecLxeIfT8Q6lTOgDw4SWLmTF6ZrWi3f68Dl9ttMzoHsqidBtWvaXPVJmQpqDg2fVvQE9izUHCBGUoKoBzLJzE6tAlhyOpjTOkCUC5JvvQJR+7Ydf4HdfHvC1b73Gb/74C3u4k1g7k5ZQIBuPcoPIbcDMp0yZHw0i/vsrJftUZP3TSva6nf4RAJU+u6d2pIycvj+W5zhfQhjwZiDXzUct541AlUKzGcOdgEjKbxdQA8EgD7/J2HUHdZrTIyDWi00FvJPpzU4fx1dZw+5UYk9MkUCNaVzMjM4ZD9ZzTDv1d5BmwIPG3oEGke7f8zNsiPFoqgURkDFyn1bdMBscWiJ9lkw0CRAPLIkxcwGUawWwOU9ndXRTdBdoVbTKKQhxtCcz9lJOuNVfVxPMVcO1KvyyM3NGS2NOjIk58gQ4lROdREjhX+y8m4Iwe4KKjKufIbN+5DA5NGwVZcsvc/Ax2binvxxGIO8Dvo6T9oFJnPJnc81Ok6j5mXZrSgHeOTliyXTC+fqipo8tApwzGGUumGlGpSqaSxJzyzwnpmXCMi8xv1j6yc6Mm+MYWbO9makli0U3lQKaCcu8aD30TJiNBJl2djBj1fnUGoM09EGvpc37MsMc5FifyP19Khhkmvy2eL1U4RNJyAJ/fohN93f/wA/hZ3/x1/G5V/f47ss7fX8/Jl03/om4WV4bmg+4tURo9VObhnc29JHZHSDt8SY+ztD1wBnxBSgMDyk7SdvByquwhsCotWKeJszLgnk5gIpokjn96ZtZFhV03/ohF/OcnkTaBmd6Tp/JlOPF5b95UTA3OAswsDdKmu38nIHArKETJyth4pDNqSQFgc6HlC3fPYK5ZWwY12XC//2HvoDTtabNKIHEKEquI5iQDGy7ZGDWX7hFBhOxzvneevwxNPAIre9ep8Q6Z8DxtultpXQ3nutbjE3fdL9yP47jOfxtC+K+nQOYu/neG9I45/eYpxHUcSr/rcqIwjbXvS92+7dnQHdH9pFqxC0TxqScM5Nzq949kh76OCTzu/1Hfb79OgvhkbltH4VEm7qoS/gscDJzSaTx2hMEWSwvf9aZJA5hD3oNk0jIQ/DkzglUQ+NzMDOG3v6od8RFe1xAZR6A5W9ybZTQnCgntz8EZNHu1sQsvakWqQt9ADhjL6aWRo9zc6TdEYPNAovbKKIb9xiL0s9VpaVTmTxeqXl4NM1Sy6a3MqW8PeYR0oQgBr58PqWx7pn6roK+B1hcwAzubZytr6Iu3JU3ziufk9Sbf+Yg79Mc4zmVKUJLqCMa2yPttzmXyfvrrILR7XoIQUNVpxggxN47zxJ7UeePtUXy3vYTd/MkAsnvQ4CxT4aa+TzZankzQMzzxMC1Az8Q2jTh1770Af69v/rzu7Q5f/Z0Z6BBw3M+f4f3gpeIubsL1nShZNi76aLu2dwFnIl+GsmRUsfjTp8sxIYC9cnnx6I8QPqjHYBnVUkD9gzmnlZ61tA9kXQ6HTX+Dfv5mut6xTLPIJLzBaybIcAokwA3kGxi0yRev6ZqTJM6ClCxrWnipmnqpNKlmNMUOxTPbtayrqtvjvZpDKAR3z6g7uqMV2zGvY08aR0s2C8DIc1kxjzP6jZaJJ9ke4yXPwEWJPWxDnUJsX2ExNAS2XVCmGwQ+WZh/xB2JIR7RaZ8ceOdDSgG5GDEI2AtmhRS79uV2CkzCt8Fcm9KW1ZmW56Bupx3lrzK7RAk2P28ke+ZVObvm43QwICVybydEwNQG4GguWYfGdWunzz6s5TcsuR2kMJu+kcyGLrcdXsucNkyXpzejbUEqGZrF4CaNFnbpoChEwU7TxgMurunZwNR2Ah0hP9K9Uh5dgweibMG71Mtx9a5a/+UzkxO0yQZgwwDNh1TOoDxErSlqFYnTPKSeaWPEnx9i8ldaJkspIIBOOooBXx+Bh00D46s3iyT50o7m6cano5+sGojGcHMtwZQQWj5bNqS0lg7k2jALwFTM1kl8oFflsVnmIdX0MZkz5W91kRqKqDP9oLmbZV9qQENfo1o6oBqa83HUu7HXmHjXBTUW8zAWiv4Ks5l5mnWOQjU1nAohNPh5OfG13VFrSuoSDgK1vlrGiAqhIkNhJMDNWZGXas/V6Yiz4H8bLrTmMZu2QKC70m1VVgACyoiYEVTM13V7HJjoBDYA9HHGDdmVZ03Ad7FZplOC53rsNhxTqZk3hNFYO1pKnrPwJnlYaPZ70TMADcP5Oh7qvUTE7tmU6rAvty++YX38eO/+x382Eef4Jtf/KBbBzbuxif0c6oHfVkDZwILq9yWvku7cqikPYGeAGko3WdRzhMlmqFzngB3VqLtn9Q5T3M6o/1HafWX3uN3rao91rbUWjEvC374S1/Ed77zIdZaYU5/THto5LhpHdHYnblMRmvecT9+Tv/opmdA90TS4XjE4bAI8KpVN5OGw/HghE02aNmYShEJJOlzImGXDfR0OuJ4PPjh7HVdcblcsMwS6y7iI3EH3Ow3EclB38vFpZhZG2gE1kyUjCm8Xhsul4tvmiZty4w4UQQ2tzrkzWGeZyzzjHWtaNQ64VrkZyyipMwLE/lelO4n6h58j/7MTo17UOdgzu759Z00XjdmLV8aX9H3ujf3iHuHFt4NzO3mm0HY+NjOe3sA7rEyxvHuX+9Np0aJ7y0pfH4n53WzTgZeM8ikGE97J7QFAyi1942JHmIlGmOdCsw1U+CIYDapONPMLrRBPKdnf7I7+MzgW/cSkZvARX/3z8aMMk4PaGhqXlWCjdSPqh4u81psWkfTrLgwxccglaWACC7qJ21n9If9ZmNCi8SHK9MEQgT6ttYrv6p15ljTFP1QO80Sg1DUXK9EH+g4larBwHW9tapCIRcqxNwNLSAjm1J2wggQJnW6YQ4gBHwRaDJQE3FCXatIfTuUhweRObwQDY2A00nyS0Ba1gHAXNC4ep2zoMI0dYCMOzd2IMclNA3+rqEoEg1nIztvViJ+n+ZvQFy0Vn3gddHoNR+tosALqb02nxoAaD+v64rL+aIasTkCtnMI+EopuK7X7thAQQKnheS3jrdp/Eyj3Ejjz0Hen+bsyCZrT8nj0BkDX47FNZqiQWxolXTeS/+sVTSyk2t2C1pJFi7abtMglyxAIDVv1ZAItQZdkT0XaZ1n+jjSHFtr8Lb4PcvA3yL935A+wnNHSvenBd/40gf4C//7L+A/+Vf/Gc93BGH5M2sj82ZswhZ5MNZ1fp+I8J/+ia8BLHH88riMZr6+7mDtFlDXRUSBkyO/WJgU/Gn5Cr4Jk8TMNMQLETy4hUCzGIOEBsLKwHw84oe++CX8+q99A5fzA66VwQW6bsMLKgFyno6bxskUD7rPJnhPKz0DuieSXGJGwZzZQe6QbkkMo95sKDPF7BuSxNJZfcMMKVdPjO3et94/4nA4+IZpWjs7j5dj14n5ZksMSzA7FpuuuDkRMIgF/dyHpR6wJVfEBGck4JK3RwBFSpstb0R5GIDe9zkZMKShvrfAkVcvc+/f1wrdBnGeRvAGbOqfn/WvuZiuyO27oxnNqBl7U8omWPrlrfuKduac94syreO8SexRd6UHl7R9IYEduRTnxDbmY/rsXHqA21qBxZWMaUGh0TLhBgmTkSsQYKu76oDG5lpudwaEBqDDNIu6fnZhhPV/YjLJ4m7ZM9CzAykv0t9gOaPWak3n3JSuqfYADFAdTLMKodYrLJusdZoKdWW3xphAsDhqjQ3QRH6FMi1ryZFKPy/9mTT2RoNtGhCF6aeAAPK4huNsijxMiyvjaRxozJO8ZnQERL3g/Wa1qi08bYLCXH5cXz2Yi4oJoxka1r0UZqP9mmwOXk1IAYhXz6IAFZhggoxgyM/ns+5dC1iDvYtTGmGmSyk4LAvWmrVffV+6ySBDNIC1AYUd4Of1QD5PdWXYwdMizHdDAhOFcJgO4tmZ1ZRWjy/ISCQtEqfjE40cOJvJsYflMKERRay+SmpGjDzmpu2UutYaHiTNW2rMlQyMpGaU+6hbp/C6j0TPY9Pp9d/+3Ev8iV/5DfzrP/c38D/+zD+1pV8Y6eG7p96kcn+f6iwBMEzNbk2md/CGPU+QnAqSbC/J6y/ooteNxUqjwIRdBfNyEIGDOcHhOMsMkAI3VhLAYOPDdvbc5/TZTc+A7skkk7wayArvk0bU15XR2qrPsm+m5p4ZEMnQ8bhgWWY8PDyol64zGtt5tl6aZuDsf/r61/Dy5Uu80Hti3lId0JVkZmDvLMviG5ltOAb02lRwd76KRArm/9raQ7rJIgAboi35t71WVNrnmhojvHvUcAe8/b6lcaPbAVY/qKp6fwObejmYHK5vAN4byhg30FGzNpph5uc606cknb2VRqZwF2QaeNh7P316SIixD6KITRrNi+KD0IjBg8i7y9ryVaaaTHPXcriCyDS0fCngdsK0m4bpH3tDpRRzWOJATLVxDl508bhmBup4oNO4wcv3/FOXTaUI1khmXNYT7vURANcqYE5pnsXvmqbZyzcDyDIH8ytniguu19Ul6sUFRtpXVoZqjbQTxWyOQ/OfAV1L2jihsUZj0h8EqKjExsfKy9f2h8c+chzHMG98Dcwl5FU2HhtxQh5fY84D+IWp7MCkW797BAfys3OuYVLg2gFT5sizAMAEBqsGV9doizhtMRMCQICzh2SZ06VU1FrU3H8Gz5EfAW42Os8TlkUsS0xrdr1eAWYfcwM/SbcTLdBxaGQCxgqgCEBm1nCOYU4/qXlpBbtm0erM6hRHexrLYUZr2vfal7Yvupmv9ruDe1ZgagvEppMNPNCFXCGtnYOwjcDLvzlgtjoFYA/wUVxAlGaVzmlbl5k6GiCWeRqWK69PB3zzg/fwlY8+6ej0LWuK7xmhDHP6lgDQvjqIFSQv8xh2MGMf1CnZEC+pYLQbu0S2pjDvv9W08rOY3xYiHE8nXK4XnNdVTXHh/laYgKagjtlWdwjRbm4wz+kzl54B3ZNKdqD+iloFuNlGbgzCuhqgC+2dEHORhsbB/gnresXDwz0ulwsAqGS/P9Nm5pajFNfMDCz8ARBM9vUqkvFlWfraJ0D313/iK/jpX/4Wvvi7n+C3f+g9v+9crW6MRtSY2aXaztZQkOIsBX4XaWAngQT2N5u9awNT/y7JAMLGRNCyygQ8b9j4vQd33rdDHT5N2ZvnTXI6SEuztidfGz9HQDc+M77v15n7WHOpPpQ+N8Oo9bT3xt9vlu72zIUBBGG2OTzv6bN78zYDImPceyZp0MITwc2VvH+GP+S5NjC/DaEo4tCsC0NLKjwpHUDZTo4ksTbtHeKPSgE1jjU+Ag4t2xglP0uldEhPRyVNhjBHnTMWPUuMZF5o7enP6wjjK0Gbo7qmKTRrASqE0sjHMNOeAFOqHWH28ZRpk7Vr6Jh8a3DW7FmAdjtLw1CrL58M7PPI2mHj3M0JnTTmXTUz5Ox9KHl4oO3BbA3Wx97XBo5DK9TaqrWSySWWGCtE13YrSd+LpQerNsk0vzpvONq2LOpgYpmB1cCjmL+u+vikAN81NNpK1jPIBDu7RN3ZPhcgpTns2l5vZ3Mgly1OrBwQRMigZ+fsd5kKpjahUo21NHGYg6ZpxMbN98TRy7Z6xWeeA0gvSiYh/LFA49Gf8k6DofoO1KWsGBwXFeDYHMrPfeNLH+BP/fLfx4/+zkf4/374c105o8Au6vtIyrRlyOPf+MV/AGbgv/2jX/U5OGrnrE0uNLFCXTDCDqaw6fYAeraOCFBhSxBjC9nSrxmkuRUCpuPpDvf3D3jgBzQhs6KlG8ioraNwlLKlj8/ps5ueAd0TSqyMzfl8xvV6jQ3CGB8FU5mpMVNIC/6dva/VWnF/L4CuFJIzK8oIWVlWzrIsHWjKYQ4MTHqQzXXFPM84Ho8bpxdNY+Rdjwt+86ufx8vv3vs9l3Zlpt0+G4upDfoQDMZLWjmNGeUR+PH9BEXfl3wSs2mfeVv+gaZ33Dh26+fM1GMvBqh6bLO6Bd5uSYDzxu73TEAwlGvfs9lYp4W7Va8BjOa5+ljiNPEy81GKzlZjYhHPUHq2EO22e5rkrJJ7k2R2L2s9CNQ6jtVUJs2hSdfX6GmMIp4G1WYog0POOlsbgjs0LVp2KrLh1uxbXu/GKOnTFpgZRsOSAMDeyc5OLPA3Mdy9fLxbkqaAHaQwQU3rVANp4NPKLkWCjKe+sjZnzBOfCmCpB3gxJzRemmlvGqNRYtwN0NkYpj6jDFS9/dtyXFhS9J2Szmel+VZrlf5vaQ08spYN7LAyrebUw8A3gM3+YN9nAM1BdcwAM8X0NiDm5enuDodlwVQKqo7dVMLpV2sNhOoAX9ZLzKnOBT5Fvkjz3dZbt5YHWuXCDaURDAZXCRgOFSrYnivOXibwzJjbjIqqIQzMrhS+dppqdX296Jx176it6T4na8kgiK3RrH2zc/DRnyJUGBe/DLEBFMTk9Zmm/cIJdRioS/cB4LzM+PZ7L/Bnf+kb+O/+zE9GUO5BUGfa4DeDFFs7Qc9tbL74+gITamRh4FiWWCaZhdAO6SPKEzCaSNIvpkHr5r8DQu1/NDSONo08mcyHGae7OyyvX4E+KTreAeYMVttaz6DOaNtzehrpGdA9kUQkG+T5fMZ3v/tdPDw86PUgZOu64v7+Hnd3dzge5czbPM9gZnzyySd+gNzyOZ/P+PDDD3E+n3E4HHE6nSDmMmJqeb1eFewV/Nt/5W+DiPAX//zXHbSZts2cspjWbl1XHI9HvPfee+4YxRyv3D88xJm7RLDNRbZtsJmBN892xSSgg7SylKIOYMLFt7yce9B2NsIuh9Il3v0KjK9+Ssil0j0AvSYsAwogtEmZcbOSM1BJteHh2juBNKJNvhkA+e/h/p6m8fFietD1mEY1H3ofAc02rEauhMtSo557j+mzVh/vryTRH/s/mLm9Nt0ow77sMB8Z1jDD15X1rcURq7WpRqP6mR4mRgPH2QsWE7iNxlO1J8G69jU0dk+kx8rYGwjUd/wMEqABtUmdSkTbDNx4Gx18BQC51hqMqPZvaNG8l0GTglpjkjEA+tSSAIQMrsItLcvS1ZfNwZO+46EOWktxPKX+k3k3ZQbXKmuRQmvDMMBSMM/yHnPDupoZHqGYgiqdX8wgWRxuyHg2tlAL4aWUFZzIO0koQdv8jMk0ywx2La2CKhQHqZ5S57E7WlHhnPZn7luwBm1XZw0GdOdlVkFC0GqxFIF7OPa+KwWHJOjLa9kcvqzrNdaKtvl4OKIx43pdxdy/Vby4e+HzupiDCWb39Gymj1WFiFnjZoIUe4eZQVpP17DYPlMKyjT52neP0PPszmyu1wumacJhWcC6516uV1AhzDSjUMFaxblLKcWvUSGgylw0imLmowJ+9KwfGPMUJtVBD2sngCFSk2TKRzLMUmcYdJupZDjYTEbTGTkOoY3NmUz5SOcoGPh/f/SL+OO/+pv49//nv4b/+F/+0zfpegMD6ciI54PsKIjTvOw9yAoO62lotDE92xoqqIsVmcvy34loM8GBXPZ+Sekv6KjyGi3mb20Nl+sFZZ5w4BMYBaXM+OCHvohrrbi/f8B6vUoui6FQAAAgAElEQVR4gyw3gFFhA3XioAdMYdL5nD7z6RnQPaFkm8nlcgnnIiUIvG1ep9PJQZOFHbher24eaeZLBrJqbTidDrIxD+U4c5kYmjGswej8BLB4d7M/bwDxer3ixd2deDdTCklkZ3eCYXRwkqSMLrFLRNvr4VJn763hc7jO41XumZ3u0a0Ub1fk9y5pAG2brHJbBonxJjkz/L0RfuvzroQM5MZ62f1cJ+Zte3bqP4L2uL11zvBondPz43udlsuAg9XBwETezMe887tIctmdcuSaMRu8yScHTOhAbOpPdjAT+Xp8ttAFyXku5VkZELNFynN0D2CPjFxXqPFuyFVwCf3Yd6mubA5XdNCDaYw/b7sKC1wLZMxk0kiAY25kYOjmh9x7tjOA4yaWdh0CNEzrT4MgAEkA5aZ3xmCbxlMr1JrUm0oJUMPm8ReQc1iE1oBS7DwePA9GmGMRQUwALaSCPuvdtkeuKAGxIApp6lq7o+/FesFoKnm/iiZrAHaJaX9sPVn5PrLDvJjAzvCzuYzfSQIcnT0GM6s2JULkQM+5WXmtNVCtqJS9GZoGN/qmqFt4Y4o7TX0pIfCiEF51wM72ltbEclLbZ3ucgz+dk9DzoHXYJxkAqyMXC8dAhfw4Ahge1H2zNNlH0ed88TOrNvZ5/A3U5HnRg528luydm3R2mIcGmv06j3uihjaYJvzNP/gV/Mzf/gaOa8Vl2bKnptX2edbRv1G4N+wtiDnpraBeS9c1w+n/ThPTPCdEe8xaQdqUW+idEV8Yft7RaYvGoatV4wUqvTidTri7e4Hj6Q7MwHq9yDgR99nmYmLD2TbgOX0m0zOge0LJPFKa05HD4dCBOgNiGdDZ9XVdcXd3p/HgQpMmJpUSDmCe5q6cy+UCZu4krBnQZfNNoojZA0AlhSKitk3aYgVZ3dpUcPdwdUkkUhkjcAgJnEkuOTaH5LEN2KHen4Yg7oC5VJl3z+9GEfk8mdPvETT9INII3Ozy296/lca+5zCrQ/q8BeRGc52cnMlCMAM5vxHQ5bfZ6pYAzcBKbEGgvpP5ncw0WfWzBtJyG3n1vbaOGkhKDI2Z5QHCIE6c3Ox3z4u2OgPm3WTMaf7pfZPOTFJaX9oWKxec33M4OBQj4RC698n6xLR4AlKNcWwsppLmyp2Qgn/XKvGcIPWy+GWiUctLU4CwaeY6vllNOc0hirmrxwQULr3Eng3Qwa+bJL7aORmysAYFrRkrDgXipkWzMAAEFKA0+FxyjVHqwgz4RUtsfvDyXAkmHlqeaegEVJSEFdSsrypAaOI23zIVcBljaxoHm/uUxsw0xiXRdyICCqGwOiVRD4t5f/C+Uw1t1hxJ3aN/5fxXCEkshl1J5o7X66pjLlqwGRJCJwcg93WgAM7B3bA2nCYNwN88xk6mUUxmwFQKCouXUo9XZ/cMaNjRhyKx7S6XSwA5nykxRvYpdQ7QZp5bwWGGaVTLwFo0zWIehpAjUoA/F8okkHJr53FQlztsJ13nCfeHGf/OX/m/8J//Kz8dj+/QI6ed6XcP6raALjdjBHM9LWYFwmVT7lg+yOZDqg9BNXXU0Y6cMuhyixHXNIvTHPs0QHd39wJrXXFdr/Fyn+ON0p7TU0jPgO6JJDubYEBrmiYsy+Jx4IAAYmZqmUFe1rQZwTFPleIuevaD+hnQGXC0lAGdgcl8hs7OTYybuJVVa9W4QRP+2p/+I/i3/qufw4tXD3iFljZ2I6MRRN02xS7ujkr6g3m3ctFJEUfy2JHRLG0MDklv3WaIBXjh5sb2Vskl9KmGI5B9xyxHYe+7pk15GVDtPG+gdLyWGaYNS3EDzOSN+Gb93gFMd0AsMsiFdnXlbuy1niq1t+9d3v7g43W1WZgl0X5/BFXOUAKupQBSOBJdGyTfKlvsI2Pu4kwbc57BuSwDGcGoGXtocJUovFcSlaHfMkO4P9eYBfqp7Z6zSrJeIz5Y95nrw1DzJ3YBB3WZ9/Myay/s05xzrDWCoM+p383srxSo18zsZl/609tozC/ggbXhzKTSrdI6zYMRCaI+Pl0zUGvzwMezB+leD9UYjuuqZ8a1Lwx4JeYWgGjMLL4cA0wMajY/FUiZiZcyporIOnpe7EyhmtKathKpPNNKiaOa8FprY2D7kQn95J3i7wuNz3N6EPRp/mtdHTgb7Z9pFsc+3je8mTuyLgbHOmmg897FHM4tQHLuydYRcd//Nj5OL1KflWlCAfwsumsSO6Cka1Q1O0XjP0b71TdjFuJ4CIs8JxJ9QdAVow8xrznd0+u25iM3zeMGKBqI38TA6briL3/9j3kdstDN+z6tV8tjS9tlnLdlx8Y7CvG6p4Y5Kd+92MjD3zDa6Wgb+cutED0mDBANXThFqY1Ra8O1Nry8u8Pp7g53L17gfH7APV5HNRQ9MsiZit8Hke5z+ocgPQO6J5Ja7c0WSykO6DJIu16vHaDLjk2AIHL5umysxYmn5XM+n13K5UBJ3wVC+mr52kY9mtDZO8bU2Kb23ffv8OEHLzCvDbWIKdDGbMXAY5kkOLoyBxUrLN5QSJFDkvy9Ia23S99LKd17HAZ57wJYvt/pMTB3M3Wg4W0LSgxUl9U+87DXJ6PmLgNBB4fA7lnDNyVnzHKd7NoGvCryeCTdmic89J2YeiUGrAGtiLmgOTgg4WCTAENBp4I493DZWDVIVocEThKTFkBFAQMl5tzBYy+jtuEjCqjmwFZBmTxj42zlybd5Upf8KZZV51TAPApWAdnOEOuYFgdHVlWGhRoAR79eVzlvtRq9ogJSumhaJmlPWDiIuV9Mz6AnBhI4mPDE8BHBnUVkCN8zxAoEmo0dtF5K64g0eDTSO0nLrGXua7LzL/ZxyQ5AzFEMkNaP9pectW6oCIa0uMavuDMO67u8/hozCvdMqHlBlbGTujdWU8Y11sM0VRBJgHHSeWYAuetbEtpvZo4AcL1elfY37+fD4dDRgthTUt84qJAnChE4eYG0/TA0heqMhOXc97peweq232hEUaFDphfmIdXmGoG8frZO+rrKenKvroVDS+1WOAlqsdGEDECt9HyN1ZNoQ2smtAg641pLl2PQiBG9vnnemyAip9IE0P79L33QzZER1DlIGsBZn4Lu3AJtdu2drmeqS9zdAVF/CZsm7uQXfSyfokWttWGtDVgrlsNBtHQvXuDVq0+MeKZm6uhzAZFoWJ/T00vPgO6JpMvlgoeHB/8zByfLsjhYul6veHh4cM2ZvXd/fz9o0wBgxcPDWYSwNIFoApiECK0Nl8uK168fcDweME02zYS02YF30+iZyc35fHYzTWOODoeDA04iSo5ZVgeUtTWs9Yp5WWJjJwCtyQF5CAhcDoubk+EK1LqCwX5WxSXD9IMBdEHqP11Zu8CFaJtrJwZ+BKAkoPSpe+AR8LOb3whyMtDau5ak7aY1Hjf7HF9u1Pb2VaVOQttXK+rlDKj1bf6d+tMZTjaQhDjbqT3qoEmZoqZxu+wwfW5vuPZPdVehQ2YAOtCIXuIrGoOSGNwAYSA9T0cAu3nPiofzOZWnwMzfj+qEkJrSGbySYsyVNKUy+IObQuY+tRABWxDUO7S51MswhsXpFWBn1EKjJY6XwnOiWwGoCXYpE8ps5wyDRVxrU4k5u2bJzAQzYgutmpiei9dE4WKdZkKdqDQJJ4BJQEitDaRRpMhgtTHIDmy5i7ln4GMqk5tHurbWwXtGlGH45VYHlIVpARj93VqxrhXLMrmwTepfcSzHNAekTIkBVztzyFkFhrPG/QMi/uhaaypfw92keWtAUELkzFLvC7CiavcLw3u5CH03TZ5Yi0wO6iQfAkG0xIwIvWOeLBs3rFonGz+wgrApLD6YzUy2udfkMgl4Yy6oTTx9Tpr3ulacL2etnzpM4YLz+cGFJeKQa8bxdHLwxUpHLGwPsxx5IIijHotpeL1eUdWJTpmKz5PWGuq6AqVgOhywLLP2B+vajKMUcvwinzeVeWl9KeuoolYbF/OpmIEUukTp3zxHHAg7/UvnNDX94d/6Nn7ty1/YgLmsmQXgPAUlgdgomCMqLnCwtc/M+Ntf/hyUcRELAKPhRoMVLxITwCRCMtI/ZqHVTm4MRkNfbCJEAsEiq4jxcsBLWce2t0zahgZuK7jOPs/WWnG5rmgMzIc73L1oeP/9Mz7++BWAD9HUKqmRi9PAxda7mWMzNgjzOX1m0zOgeyKpccX9/WtcLmdMU8HxKBIfZsblcsHr1681XMCCZTn4Jn5//4DXr+/VEyX8sG5ddUOpYlIyFTG55CabAjeWzeZImOcFZo8vni+vEO9u4jJd+JfmjMHpdMLxeARgjKudmxikYTBi31zKaWcFCBIbqTb1UFYoXLebjTpXOR8zz5gnIazcNGqnpVACbISOds0l6UTdvf7HDSDFqQDel+Y5w5teIYxEmtLNfktNQtf+mR0g09ety3m3/g4O3jbPIY9bT+c2b8r3LnORMPoG6raZgARRxN4KwLA1OdvTDrvEOQS+fXvsnX4o45rhMgMLaaiEf1DNmpcpTE5LkngzCcvOIJzZV0bJq8Gp7xzQKoASrjkxzxoEGpFHVcBTKMpybaAxOrqmcmO87coUkZ3h6fosABMDKKYJoMz4xbMxMPBp5uU5QGwBbBKjGX0bWiUiwqRatgARASrEpFHeua6re4x0EGAMt/VJa8pYiSfI6I7eBFjO8NUIDq31cQGATydyAROzmfspp8lwE3K5LwHEGXmceyHFCPijqGDGAzDL9a1mRkHzBBdkdN5+KSwoWmP1XDopIADWWsFrYqq9fHLPw1HfVIYy/K4pVgGEC1pcuBhCE+ZtG2uVNtiNZn3kUyz67JrisHILp0JUSMILaJ9QIUzLrGb8cu5u8rh5+pyaW4LhAD/iRsLryq1h1v01NM2IcA5sQhX4vCkgDXJOiFAEAIoeXWDTkPoQ+XjbPBOBgplhmvOwBu5WqA+FzwmoWbaBSImHKfNxrSYAg/exC1idTPYOzJxyEPDljz7Bf/Sv/QyChBGKBX2fBGBa8HprV9YuGjm2ZRLmj9GI//UPf1Xebwwq7OOP1rQ2JowzGh3z0ff4RPN1Bsn4+sDKPcFT7EHg3fTexrRIDVtdsZIInmVsCwokbMUyH/HwcEFthOPdezgcX2Kajzi//gQnmlHmGa1e0GrFcpi8PObahXF6Tp/99Azonkji1vDq1Se4XM5Ylhl3dye8eHHyWHLf+c53cL2uOByOOByOCvSuePXqNT755JWaeuhZnCYSw/NZJITM0DN0E1pVQMeEtYrkeVkO+Jtf/8dxPj/g4eGC8/mCUibM88E3fQOK8zzjdDp5CIQM6EJCFxJcAO7VjAq5dBEE1FXemUoANInbVLsDx6VIwNl6XTW8gXk6C8lX35nYMPadzbqDnO5Ceha68yTWk/fBXECB9K96BtQseuDlAEBrlTdN58iBPXzJObNUZtaYjBoXq4sx43ugb79de02NVlLmIoY8MngZTYVMw2Nu142RImcyxjZxMFbc94ExIvJBNxsSIM7qRd29DE4B482T1JrVkYcOqAMcCxyu1yx+WgZFoGAeMxDKJm4GBp2JVU6lNjGhszqwttHKoxJma8xpDpGagxUxITPAApYzIGQAkZTNTusvOkYrW/IYhnaNleHJGjHrLzl7FY5OskYnnGQkIKplmQv8eZqdrkh3JKaOCFylby6XiwLXgmlehNmaJj8jxurYhFtTkKgQko0lhDLzoplb1xVg7qwAjA6B0xwtNg7mNEXGxsFcAmudAIf6mG37AjCdqSyWhyEEyJoNez7WWSkTJhqc5XDM7VXBLzdGWSbRUpUJtcbZ58YsWsXJzlQqowtyoCdDkM33pY9cm1dEYwLWOTgHqIt2Bm01JyRI4BowZjq0uuYwZK3XtG4AVnBKVMCQ9VJbw2FecFgWf5YrQAp4vb1qnsrQwOs+57LFgMy1Mk0eVgQ6f+Yyg0SFFI5qOEw9Q8AjmloLkcLqJdFHnSMwemhoTQM6oVZyj4rQ5z3unM5HaoZRWK0SZCxdmKTzuNbaOb3p9kWjLWm0cjpcV0yt4TJPNoQgQu9UDYS6rnh4uLeRTiBVCunoedsCOpjwprCuOwY3EpPlZjRFwgIotyHno0sGdMgbRkdb5fII6gzYGX3UeUcTQIxr1dAjxxMKFUxkYG7B8XjCJ5/cY5on3L18D6cX72GaTzhfPpLYitMBl+sF6/WK904HUGMAaonAoyD8OX2W0zOgeyKpcfOza8uyhKfIFsG8iUgdjhQ5O5L+Tqc7Yd6aeRoz06Vgopihni9XZV7gwOVXv/ZVvL5/jfbJx2iNk1lHH7bACHgGa9kz58io+SZd4mwGKbJhI8ekjgv8epgmQZk/42FsA3prEvjWaOX267z5slfEXkGiG9zcSoBzj5bnTfCRGm3vpL2R1VlDFNR9vHUaSws2B723wOGzZ1CtXuH+P4Oyjgl9U30yoEmATkpMQG3Iz0BRMF2UeO3c2ZSql5A4p3lnTHdfAszsCKDN/N/y7gmAkoExY+k4aeXs0dAejtoeY5IbjAHq79kTAGEa55X3Y8fahVmsAUVKjliMISJsAItdykzTKEdw7Vvql9xPvsx86rKfkwMDq8ZBs3xdSECibWoqWKqq6QeAyeaYg9I8tlJpAz/ZBNg0cl05PuTsTHA/tORlGR3LZsgdXdS2+7xR4tC7sY/+SqV4H4uWLq3FDkDJd9ckmfkkxz5hwjrm5g5dyGfMSG+DcPUg0waMN/XsaRl5H1m+zAyLw2gmt8xNtYjF+yKCxkc+2fTPqkBpTiNK8bng7QW62H2khHeBmlqDBSDW6k6LvDzuQXYGgVkYQUSYZxWuaL+2RPMIBmpJHLLkzYEM2BEA884aVi4hBNRnExAxE93IB7HWfVrE3mTXi3YEDZ8A8Ef//u/g537qD+P13TEPaE9rNb8y7Bz5mT16n9fEFz++B4PxOy9PVjmtQwFI1xIKvIW5DbpBGH13FsfXe5g7plfFwQ+U+mrVCbrHUQPUm6+B+eg+CSxeGwGYABJB+OnuBaCC88bQEs3TLSdtI7p+ek6f7fQM6J5IMuAGwJ2hWIy57MVSgoqSAykPAO4bNbskkVs6I8IAN8b1qsEvFSCK9JVdYmkEJ0vU4xyUbCiZ4bF6y3m5hogXJZvad9474ke//Qrf/NIpMZrBBHUbjRPeAHXBJgQf/INKNH6jvCndemu8cRuAdZv3CCr26uP9ZowTENrA0ArGs8aoSDkjBPmeEve59Tlv25yBVMdUeHb7ddtez8y1MZ1vfm8v/y2YS89DNuHoz4CskVUwXrJsGriauV/M5ZbWDoZXnQtlQEKI98xNoDgz67TzSMlUUyUinafOHkG5kEA0GfDxI0A0IdQzpJtPzsxHMDQMY3pIWRZgrT04i3pmxxjbs5E90OE84QWomXc5FXBZoyi9X83brmnpmN1LsLd7cOzkgNSdqERfTKRmc85YoweEY1/7pejLDATC5XmYKTZmdZYiNDAcR2XNaQaZ0V5z/8+utZF52CejpXFWUwBcmGEGUJd9wqFlAqe5naPAIgR16pyHx27pQXI3HsxiPaKgslbZ10qZMC+zhCxIAcw9R1ZYZ5sEqXfJ0o9J07ata/Xzd1olAYiaB4EwYUIrERrh0i567nwVMzsLv6H7G6P34mgawBz6ZyoB6CyVIgGxbWxaC0FnntNUSMFR8fXazWcTjCGa1VP7BGTsT39n2G0xGLOQzgCzabfmxvjVH/niZu12cwCk1gw2FwbBLra0eFwrf+EXfh0A8J99/SeijlamgjYj3QHqghbDpCwZz3t75JsYsvZkWFmQ7nklzAhbCHTCDCYCTRPmMgFU0Lhgmg+4e/ESpcwAbJwLqJhJqpqTGrB8PkP3ZNIzoHsiab1W1MI4HE744IMP8MEHH+BwOOHjjz924Pbee+/jc5/7PEopOJ/P+O53v4vXr1+750siMa15eHjAq1evsK4Vp9MdDocTWgMqNdzfv8K3vvUtMAPH41EdmDT86C99A3Wt+FtfeR+kHjaXZUme4iRoqptFzRNKAc7nC87ne7x+/Qnu7u7w8uV7vqldr1f89z/9NfwH//X/idOXX2CaZ3WKYuRUHELY+ZcpmfHYObplXpKZUnFzp0cQ1ZtTYpIB+w7f6PJzwagYQBrL3a/HyMyMKaqfNlDdbPrP/h0DFiN465+J66EFYeOgtnXJFXhDvzrTkMCDMWaaSUhKEZt1TnuOUrZnMHObOL0bgCCbRcm/0sZbDER2nd5VWZ8ZAU1ORCXlaWaWYuol01HOWtn5tgzUKTEbG6bW60YY42SI2VkwMAYSbZjc/YECjgiaHKasfRsozYkw4Srgrm8ckA7aFDFFLc6U2GevDUlA04aG0GlarN2myZDvFGCtrmGeqbmu5vTDgB0zjsdj0KNlQSHCVWNhZsBkdctgyt3ql9LRuMz0NgWD2SIhj5mVkQUVOXbnqI3LjK+bqamwTWKupXh1UI2ZgxwBOtGkEI7JMzbn9CygVMw/GzOOyxGLBWNXBypOG3Ts5Byhjg+AVmsIBFLb3Lw49Vm02+ZfPrsXGq55nlEm8WpJ0wQQ4eH+3hfkVCaUQ/S30QbRyrKD9ONyABVyQSg3HQfVunn8QUY3FhnA+TOAni0s7uwEECc6y7Lgern01iqItkzTJH3cInyPj3Ox/a7X0pvmzc6XC1iJs5vWr4UIrGfU7D3bJ+3sIgHApOaVLcxIm/VLmqMGBkeqbN5F8/VBBCWeTgtt6De6d3QMtT6530cP2daeLS3Abt4j7bQ557XlgmZ2yi3nnb0Bx2chkvOFAEoRxygGrK3o5oJTOZMIiGBg0nEGgMOyYDm8xPW64ny94HR3wle++lV849f/Hi5tRb2/YCZgKROu6wquK4hXTAWYirlkeU5PIT0DuieSjBGc5xl3d3c4nU6uoTPm43A44MWLF2BmDzuwrqtvZMYYi2OTCwDGPC9OxKWcivP5gmVZPEA5EeFP/j+/isYNf/PLP+WEP5taGjOVtXbGtHgMKD1fZ3VpreF+AtaJMLnpZ+kIpm1sPRMUjgjMs5g8C+g2/D319SC428NbfiPAnICprPWSKt58+UbmvPM9QJy/5V/H2grTtr2Prq7BQKRP7IOV4cVt7XdAmWBiGcj83WrqtU5ACela/pQi9gHg3jOPpVELmct60+t79crMm9YiMcHS0piXkHMYHaDra7YtQ56dLG6VMf76n8vqScFefs1qwcmMkFmP4O0Ad4ZoAXMZbMKBBCw7TeIjYz9cMyYUZOfq8tykbY84mI0GCdhIjGoGvjrXimoj5bzX5KDLQU4pnemYw+TgFGOucsyYMAmP9ZDnZdZM9PMq7hkNAwKIjMKLETjm/paqNdSawVpLzLDQoFKMYbW6jGOo7RfCBWJ2UN1aMM3yqNFXRq3JMQgzKuDWHKU1tASAc1ib7bhKnfaAcB5bi3fHTc6RedgC6sfGmf7aPDwDKaPNjd0BiMfCm6pr0MB21lXjkFF4cpS6pLk3OOgpU8GxHHF/f+9gJoMUIwNZe5zzYBiY9F6I/EtY1bjTE0InhOj6a+hHE+IAArZMYxR0IOa7r7U8P9I42Fpx4U0UBgbw5d/9Do6XFd/84c/17+98J5KThZ0VRV5XN9Jj928JRrJgwwFeY6AkLXquo/ZxiqiSeiKEZU5fbQ46XUx18LO1BcvhgNoY7cyYyoy70x3meUG7NlzXijJL6Iyq/A1xw4T99fOcPrvpGdA9kSTSNJEO3t3dufRZpM1CepZlwYsXLwDAQxisq7r2T+DPYtkxQ91Kq4mGboiXiwC64/EYrpdhzEJI8uwMnzAUIpGy+HdmPpVj05kHzGxe5DHtpjgPkXnNcGedY0Ulop3PkjgD9L0BOkvJWGvIPz9E6M2HjDkzM8fHS7As5J3tEwYU+2ezHDHVdgCRt/eCvPHp78eq+UgjxMXzmHvULgO529nvgYt96Wv+fktjZ5t3X6dgrgzkbMHTKHN+pH5+Dwro7OwO+/VUI/s/rY38zFbq7GUylLE1LRyHJ70OMKaychuU4TDmItq+aZLUo8U7ZgpqcyqYr+JhCxjYxvozoNC1P2nmijkBTx2Z1k8eG7sZa0Q0TCCEBij3l/4Wpw7imMCET9b/hUiAx9771kdeG9gi9Hfz4PVM41bYMM7bLADb09DZc67pAuDhI9IYVTb3/9kk0oCCAb8AeFm40IHnVL8yWRso5ZW1ptjUlVXrVEoR75Nq+j8y69EnMca9BqUHtLm/zVvkpCDHtGwOZlOdahXtayNyA4taq2hPFLiBgTr3gM72SAv4TUTi8MW0ebrezMtpUWuQeZoxzRMezg+uwWMwqPYa2AzmAmxI/cysNfqlYJ5KeKEEQ7bJFnQEN5KCNhvb8M6fzBub6BwzTbD5fAuE52TAzuxowIzPvbrHP/jyB3h9Om7GfJNfKmMEdHtCkXF93dpSRrrRvYO0fgvQWR3b/E59GMQNbv3QFxafDIaFbLE10tjOOQNUCMthEe1bY5Rpwt38AstywPl6wbpW8ZIKwtoqwE3P6+lIP4O6J5OeAd0TSRLrTZgTM3UUTZyekSshib5cLmrqeBECQpNLCNe14nK5Yl2rnrkz99S68VgIgRKBy40Ttg0T4IG4sgMz43dMQmxSaItJZBo/2+QiLk1BuHQPsBFOWyRjl5IaQ0DDBpSI/fdEBo2gb39spJT9BtM/+xZ45i0rszWx3H3y5mbn3/YZ+iz93X/xrZMDOfTQM7Q2jzfklpZjU07a/PfykHe4Y9rG97c136/Lrd9yMRhhIjO1s/mbwVrkEYxtYpSR2p0kxMTCwNvM6pl/YVaKm3wag6HnhbTgPs9bc4liASNJ9TcAK7ywuoTa8k7AKgOI0L4bIOpWlDOu0T+99muaskdcdEKe3BhnNrMQKOXpTJaBCQqNBShp7+x3ytfyznPZ2pzBmtdlYFZ5eO4WmOsZWOMok1ktmjKk3kYVigMAACAASURBVOnSRyW0kD0fmL3EUmLa4xqA7vwXKJjgfp34hO3ABdka0z6uavpOCDNeG3/TsE7TjPlwkD2GuTt7aKDTBAvH4zEJGhp4TaCQqDM5bL4XJSDmYEYBWSthEmvzrjEqVZjJZSkFS1m8X7gxatOz5MQoXFA1rh5BtHXzMqPUgkoV5/NZACY3tGRm2Y8zvN+krk21xxkUGyj0iZVHY0OjRdPYP5fnbisFRb2HusAtg3x7PuehQJHs09rADKoN7796wCcvTp255c20s0aywHYUtmXwL9dj3u7R53EdWniIvKaoxHxoprne0CDy6W60emiIC9X8NwevFFYRhGVeME0XMER4fTgsePn+e+B6xfVyD7MVYIZrCa027XvmH57TPyrpGdA9kWTBu3M8pdYkMKt4MZsc1F0vV1zOZ1zOFxARZg3GLWaR4sXyel1h59P8ML8DrABgIh0N06C1SiDYLGEUCWJVItufhbFzDVZv0eDpW4nRLFPZEHWrh4E20nfCRTa5hq4j7N8vAkg3f2x0ZLIvhlgvzC+TmcaN9G6Y6TFQ1JfX52sb1eN5j7mOpnP7JW5rRLnRu3kkpiRVatzI7XuW5O+9118PQYNfc1CHzfzYA4tj1rtlpTZmBxVy2UDdyHBYBXqtnAGx0BRFNRkA2bknq74+VzS4blOX+03zc22BAZkWjPJem10LY0gggQ8/g+TjaZ/w81RQEGmNdIZSaQKUmRJ6MvSttXsEtQjG18Y/M/FllPQreDMwN0ngNXlPz9XlmHYG6FxAlPMxoPiG+W/rfW8Oj/28p30Yn8varY4Btfns49lregpRb1ZKScvmZew/Z4IxDyOh89OeF1DM3dyVCRqIzoGzmg/WGtotmJBDBR92BKCUCbMKFG0pZW/ONpcA4HA4yP6lWo5aZT3YmWsTGADhJZJQgNa2VM0A1CBV6OZeEpTY3KuostaSt+b8XikF8zSjkmiQcdZzbOqAJ49vDijvIMCApzvBiP3E5uJmNpqAorvUr3Ub/G7nsLltazUlGp7XLtuWpW350offRSsFf/Ff+jO7y2VDA3NZqQ/sOZvb+UzdVrCQaNYNUOfvFNW2GvDPBKgA8OlGvr6sptY7Qav1z/vE/jHhXAjpmmuPobzUJMKEacLheMT777+P68Nr3L+awrxW62Hn5rifos/pM56eAd0TSdd1xeFwwLIsYIY6Qqn45JNPMM8zjscjiArW64oPP/oIH3/8CR4eHvD+++/jxYsXeHg4ozXRzpkp5osXL3RzF8K8ariCw+GAw2Fx80muQWgfHh46MDdNs5/Lk2Dnh8RINtzf3wMAXr58iePxqMwWPD+Tkh7KjFbM9DPi8MzzFIGESTxkresVYPbQDQ4eknRuNxzAWydK/wIdSR2ko/tFbKV5wetmCPQmUk2+70qeAhS7jf5muVswsa2PjWOx4lJOm0u7aDCDi1ErN+7uLse8Ua0RzN1ifm8l2cSjjE5DN1QksyvGGLS3FIU6Y6HMcWasJYmJ3LpWNwsDEJqibY6eb5huJvZL13trqRxbRM6UCxgrAGCBfIlcI+XaIfSmip4H1JzNnToYc94zVjbeHVNrDFlLdkwJoFZUB3ZStmkOw7V6s+BkqY8z8Ggp7zIVcaDkAcaBqVZwKZiY3Xx7mtUyoVZUFuZ6VcGYWSdQSZoapSEd88hx1oihjh/0WYs5Zposy+OWpi7342jaZtdHsAVIYO2ub4eUQa+Z5oKAggmuRbMxloniY+PXSpj+ORNtzGz6x+annccrZcLpeMQ0z94n3JrE/it2NptdUGAxQikBJaNtkj91Z7qtfaF1MiwSGksz+wcEKJnVyTIJe1RbFcCazB6pkGoG4XNwXmZMHntPxup6vTq9YHA3DxniiKVdmjiQUcHmpOEUTnd3Mf+Q6wkwhybLx06ZfxB5P2ZwkcmpreluvnqfDHQUA01WiZebDyOBoxYx7/bmp0+FdG0C4eF0AM0Smv2W9tnzSH2YBTL2rAmrsxDH6ReHltP4jLazNnqtHrSfdE5TC7N1ZrCWJ7KTALmigUQIjymDX1tnrAICKbPVCvPY2xqwrg2XuqLMsztNEW17wT/2438IExGulzPQVnBbQTSBpgKJmshYuaE+q+ieTHoGdE8lMbAsR8yznGmrNcIPmCljKYS1iqnHdb2CWRyRHA4HrGuFHZ43M0jJKwiqMRzLYcE0T8p3NWS3ua01LMuMMQDwuq6uhTOTH4BR6xXzsuB0OmJZptiMEwP08z/2Pv6JX/kd/J1/8seTlIt130mMj4qrmkpdt0wRVIr4gyOADq866fVbvvvIo3uSzm2pb0oZPI7Xt+V82l5z8JeAHd1onLGKXW2oN0eza0BszKNUfJOvMw1voVQBHs1L7vu3XUBpDFTk1YPp3C6rX4BkSl2wNWsbsnGGQoIPqyfXsaLGzEHWjEl75W/HdC5Jfjv8aLcTmIPmyZorIWLE2Vk6qyeP+RnD3AAmiaflykwDdFYe+rEfvwfQgAtvYP3qDH9I4oXZT97xWnNGLTs4yQGdW8rD8vXPwUzNrAusJ/cEEKMGYvSimduW53l+TxyR5L7JgoQABEj1JRBoUg1ZWtkC5Fo3/gBQWNzz+9glsJ2ftJhnplWysmfVPhCA2gECE0SRO6mR7OSaOVTZgBu38iAXjtRWk6Yraw6bgF6OMDywevj68Inj7fLx1LGZIUw3YwJDzq2vdXXQFHOLfB9y7TRkD6zrilmPKizz7H2h06rTPkV7cz23Zwqtn32t79FWq5uPMyLuHDNqWh/5HauDA+SUfy7F1wPS0lbwN68VHdQZaOv4O1t9jJrtDAA3dFGv/6V/+msbgLfR4JeC6gfl8lyS+QuyOJppXVGsJ+k/Fahqb5ALQKVzVETivp02mkGdI3Wt0d8kAoaH8xmnFy+wHI+Y5gX1UrHWhpnUsy4BMMsoPKenkp4B3ZNJpGfaFpdKGjgrpUhAcSpoteF6uaKuIom0M3cPD68ABIMDQJ2hhBMSM7dcllnDDpBKRHsAll2MC28jksq7u2OKBSSZ1lZxKAecTkfMywwqWwL/l3/yy/j6//L3IKTTDpKPG7cBJzEfm6YtoOuY6rfBO+/Q94/lF2Du7VO/J3db543ve4Dl8TJlbLYV77t/6L/HK7p/PwE5AH7OYj+f/b4cmbrx+57G41bKUtxNOXvX8i69eXofZHQMFuAuwvO7G5Bmg0d23/JKTkKEr1CNlYEkBijcpmenKll80U1DZ9ilDR1I0OsjUPVeyODDGAoyBwvCGJnDFGPcu7zIWB2gkYKHHKevWYQn9jpHLL5tsrZGOcm8T+vbslTd2tkaWpOYcw7A0v1uHInEhCwBKu/OzPgDvbAiMVyPaZJzn47zOd8fGdg8DmbWW7JTmdxmc5yT5mwP56BjgeiPuAxoHDUbFLZxSxmIc5k4H2SaP3MGYnmNYNvqU0rp8lvX1cuSYZCz2+Fl0kzYmprNRpy4Usg9tppVR6YbjVRb0vUWvF4ZQLQWcQkDjCK0sESu+SXAz8V5u0hD8WgYh0IEOhzcYZDsY9OmTAHIIehkJGHBsB58fdqCGO5lQJfH1YQZe4I2e8ffTcCtK2Mvb2acHi74sW/+Lv7LP/+z2EuhJevz8jmS8ropOBue/dZ7dz6/sobPBTSmccs1TsKB+C19mYGhgTalmj53lOwMuzOnLULHlKPeptGtrfobIBG68/kBL+7E6RyVCY0Ja22QKB0FZSKgMsA5Gt5z+qynZ0D3RBIRuYkh0BNAc2BihGz0LDnPi0t+83sCvqIMu96ZMmrZ/82f+1P49re/DXr1cecG3Mxs1vUK4BhMV+IDzLul1XGzNSRia/iAE2EkY0AG4t7lZZsE1NzyB5W6TenNj2/34nepq8HaEdiN5Qd4SoL7typzlykdGb9btcrAbszHB9RacANw7YA501y8XdqCMmdyN9ztWHauds8wbwDlIORwt+LoBSAbsGPvJ61ZPn/H9l82CTIGdspnhQAiFnMcZmQfGRL7rT9flmOpsTPBMYlIuRhnNhP4MAbV2swMkIKcvsdlrZoWkUDuXdBBBgjXtd4chwxqAuRYu+0+AGZ18a1M07q6mamBsmpOLFSTAIi5qTvR0AFvzInxLj6XrS8tdpV7WMyCi9afL9xI6Ye27d0fgdz4XmsNa20oJYKgz8ncFIC4zHcQ2q8f62u24PNysyMg4gzGGF6rV4CnYHYJPDGosQeIdi1SNFTADgfws3iEpWUNVO+yXzwapza0AF7uUbkZwG0gktiqk5nVwdavmvrWBiKW+1YmjP9m/25jcrlcUpxIuFbU+mfSc+Wse+x1XVFIY83Nszy/rh4j1fdiPV9u+/T1enXhKTitP+15B17MTr/9JkKgwHkcEyDzR4lACjptjnN+Jj3rIFbXxIaK5vqlPjtcrnh9OuA3vvh5Oa94Yx53axpxbG1cN3va7T36f+u5bK5pxza6ihMBDJ+3lPKwTdX7wzgJX68joEu7i867AJmkP8VzODN07RWs6xUP6wUvX94Bdu5THdYtEwCln9yK3Kc8CZ7TZzk9A7onlCxIqRG4WiuWefEg33YexByRZEluU6m4gC+5bzHobONvVYN1G/BSImnOVJg12O5U9DC6xZkTc04PoqpUr2hQVwOj5mSFlNBlRy8AjB7Ctl2iYCTivp7fgfZFCRRom30huCeud03scjngsQwExKiR0Q3sYje24ItwO6RBgDZgDwDeqI/3WyolMWfy3eqTK/MIIB039p2KbJl6dFLgLO2NltHQH1bf/oxENqsZf4+ajLdKnD52ytlLuby9cgxwGUga3/U/pL4a5oONk7/PcAcerhWiOCQPxHk4Q8jZvKoxo+QgxPY51AM7ayQzVgFQFUSSMTkd9xxMKAI8hrMiDGMPJC8EiCb0TOZYlwhpomKbdM+dJOV2pE/rl6HDpV4Ognqm1utBpC7EEe+M31Pee8GRs5nlnunwrbmV+8fKs+enEqEjFOFGs/Ka14bJx3aOO+Ofy0nge3zTaUqBgDPqw8+Iu/YW2l2jzdoPtVWn6a3ZOUQr25xiNaBpjDbNw0LrmObDHKOEUxTRgPl5yNZQoSCSFq9HtA2xb+h8uq4rqlq1RPiceN41cQTXvpDunxZIPYNBbqFVLAjAYRor4/vNwY91t4BZHTerAw1An8g9VWZtMnk7t/THW5PRr4LdxhG+2gFvEIAubqO93wB85Xe/g4fDsiuUyIK5x9IemLPrI/0HgJ/55d8AM+N/+yN/oKNvGw1dR0t6oOt506ihG8FsBo5wAD7u0/5cWkOc1kKtYinQGDifr3h9/xpf+tIPgWhCmWYwSIUJ4sjJnVOpQ6nn9DTSM6B7Iqm1ls7KFVwuF3z88cf4whd+SByOHE5Y1xXnyxkff/wxmIHT6YU6TnmlB3SvuL8/4/7+jHme8d5776OU4jHrXt+/xvV6deBlUuCPPvoQH330oW6sYY7JXHE+P+By0fzefw/H4wHMDdMs79/f3+P999930LksC873D7i/v8erV69wd3eH9+c7aaMTPwudoB7QiplYVY0zJHGFTqeTnHO4rvoppqbzPGFajDDCjwC6XJPiWkcsbUMp6DZnYbB7m3uT9GUJeC5lzHLLT5pkLzaIyFqub4OTjxL0/r0oO0xho3mU3k+90YFos/0fTJLQp8iyl+bmrS4zvX6NWbU2QAQr3jK3e8nODOW0zwR3kMWfY4zjtGfWmcGdMRN9WQYgvP2askdJey4zcMa8rrWCjdEspGAp5c2hnQuwJvcu61UYCgovj/OyeL+3plqranGt8nms5IUzaXCgvdWYgSp90FTbSEQgXYMgMWGsyqg3NS2bqKDMkzp0kHwtlpfUKUwMO3AJBbYQBjYESDFC2aRc6I0FbY7+JyLxlHg4OMMNEg3cfJzVedSK67q6iVwGghnUO4ObGczEENv4ObMOpSMdCN6aTo79kL35+pgMQDYzqIflgHmK+Wvu1YsJvEjAEXTOTNmDos0t9MBK5gFcYyOBnkvXH5J/f6ar1ubgYppknNf1gsvloW8LJY+jKvzj1nC9XLDMC/5/9t7k17Zuuw/6zbnWrs45996veM+vsC2/uEhCZCMHZGQS7DQQSBEWQhFS0k4Hib+FHg0aVB3SQiAFQg8BIlikgVtUcWLsEDvP/l7eV9x7T7H3XmvOQWOUc661z73f5wB695x5de6u1qzGrMZvjDHHyMOABLDwzVBnRanAeTo7CJH2PDycMYi79zwnzGnG8XQ0z8l8Jg12dqhgE5B2ljg2un3LvsDwTMaIAaVpCmWulUocKgGu9dmIExUVSMb1aKZ2icdSBakq9ByGbOO82Wws5pzOK2QeL52/wzAgj2I+mp3Jt7uu5GajVeaYgv4xgJwq1jtmxltr49I/pWQmxhEYUrgrq8BuUyq+88Ub/Ht/87cWXoh7zVvzXRB69I5P4lqJTtP02Vor/vxnXwEA/u4vfK+pU/dbpWshz8/gObEzqUrm/CkhgbIIAUq1M43HD7If6mpZiL9C3VljNWGuleMxigXFVCre3t7h7v4BD6czvnzzBj/+8Y/xve99B+Nmi1evPsY8nXE83iNvNphrBdWCISXkNIAWkV6f04eangHdE0lRO2catVoxBhNMPcSmaTKppf6mGjHVirUuzWvzm2rThmEwD5Z/7Xf+MXLO+Nv/0p8x5rqUgvP5zJ7AuCY5LLnseZ6bsvRvmia+QC7OWTRv1MBVMRuDMeLxQA6mlqQMu0uHib7hBiib+UV5WA8ovlktscIGtLVaOwd7+n0Eeo8dLi1QhJWxzLOeGinuosVW4Ho++0Dtd4ZWHUA+JsVdY4jfL7WAygC8gKOgnlrkNIbGv+nw/pImUYq91m59RueoYAT5HgDYoYN+VmzNTDGQ4AxP1bwC0BoNDbmmQWnFAZUlduU4OFAXUMIMr5bnDEscE6OJSLOXNGMAVxE8YZKbIPWAjvceAefV415SJbtfuyZ1b++exbKyM6+hrQttRmBK+/h1ykgjJdN0PioqCEIMvWPVaxjWNBaxT/G7PvVAj/sZZUm+/7fltS7x45rx+U9tH6TP0Plmwo11jYnvIqlZQvF5j2/Kc1TPmnliR11q0p8zUGuoT+jLFhgODBVM97QdtY4wT7guBmbq4bCUGHxd26j7qNKYw2SrCSiTTumq9VaU4vRVKxUG9gTP4c/XSqalo+pzVwVKRBVzmdkpjfTVTILtXMg6PFxuqM/H1yaMaemIXEufw1zT/DW22VBup3UO6yTWRVJuTQnTbru6BnohRXROtJaipszHZXkuSDOb8+NdycwnQ7sWeQONFf+9s/gEJPKydf9mTR7/1VoxiQfxEsI4EQHjZovD9Q12d2+xudtxnN8sfJSdoe93bj+nn/z0DOieSFJQpGaUKi3dbsSjVymY52KBw7fbrR1o6giFXZ9XkSqOEuDVN5wyswnLbrcTT5YJ01RxPp/xrbcncbAymvmLAbp5kn0/NZvwNE2mlVPGi23b/Y5fzhkYBgyFsDnPmIdkB+E4OmMLuPmNOUoh1by4eYt6y7ONFfFNCv9jFZR0tkeXE6lU+f3H8FLyg8OZDKnEqwLgWjt/jmj5HHerZ8Y8b/98U99KfxoctJbWgM7K79osBR7x4I6fe8a4/269CS3d7LBXMKcpAwhgt2VAnFG41LV1wAab/6EJphEmFTqQmlklGyPWCMRKAjNjTHhCjXLalIIGOVldsZ4GNAsaMFO1YP7n9IkmX/CyYydjO62vfZ9t9Xl77Hn+G4aBzaNROa4XqYfLJZBrq29jrymjap4NY54oLIA/G0GgMbmBiY3BrclafGH+C0NOF9yKrzGnjwkxLmn3WpK3QNR/0761tLPy4r4WHO6wAyPANHEE0xA38eCsIv1P7tCRzz+IACSFvV7pbnOAeL55+ANAQ3tUBSLhzqOCOr0msAQMkrfmwLIjgDsFVpBnSdo5NACZtT/Z5hiv6XAfCg5KHDgP8NkRALF8G/ulgoi1/UaDjpuzMd2xknsVha0qG6Z+Yiw+N8BsMYSp1TnFfXZtP+/BPYDD8QwKwgWdMzr3onlpNDkG8V7WCzzWhCDvEvT1+de+B2CmlbGvSgxbm7K2TNjjco7HgV3yWRAFEwA7jyq1YppnTLM4aALPnTJXDOMGVzc3uLq9wv3+gPPDV6ABYsCic+aRup/TB5WeAd0TSZvNFkMekdPA0qYKAWCstVOTjmmacTqdMY5b5MzTI262fO9g5ACohTeMea6YzhKDbjNKiIFRDtuCaTqLyefA7Rg85tB5OmGeJwGcfpDP84zz+SSx8/Q3PvBVM8dSzgHTy2v8zq//En7xd3+I/+PPfdcOwpw3aMyAzJxkaDb2RtNYKzbGkFE8bgE4E7AG5lq4ty6VbBOtPvuuRE31XHIvDVzbxFtTTC1gCc5i+c60rAHBlbbJj3YoScPeCer63y9UoKDC+5Sa19U8j0h+9femhgByDRSl8H5lvJzRi9+2vV4Az5A3oQuhoYIGBeOhzCxcggP1UKO2NQK2xBZYavqjACW2I2pVSCZAglyoJ4ipZDXTTzO5UiZc6qIgUCChGQnH3o6oSMqFsadKxpC3/XW661oehoHrCRwlm122gCuOjYZcISKJ5yRMmAKHvNTKN/NGnh06sKGgJsk8v6SdUibY/nSNPAL4I3CLHnmjFnUtLepODsy0+v65FOaMa9lq2KHa3c3mZ0oMyrhAVIT7fupUIqydBBWUVGg4AtMECSDJw9BqhASgDVlj0MmewugPORNqBZKAKZACJNdYqTCS70gnG+9aBFATQGbKyPW6QLOICbICtSV45vh1rg23/SOuQ6hQgQEpAzqysqU7NvlNQxf6ZfVq0HWhjwe85whkFSvAPwge4sD3u5nN5VobB1VRO5YCDaFN7sBcBHvW/tCWP/8HP8Tf+c1f9f1ELH10vscUQR2IHdX0qQdllwFdCmB7uV7WEmdzId/qYaZHha0jmS8XHl9khtOGx4r3xLkUnKdJAB1zJSkPOM0zhnHEzc0N7q5vsL+6wt3bH4MogbKclbl1zvOcPuz0DOieSNqMrYdLO9z0YBMN3Pl8trsD4zgCSGZuwmaOlQFd8HxZ5mKetzhunddVaxFJLW8qriWMWr+CzWZvJpUM6CacTidst66h07ZHpy2qwfvDn/s2/tz//kdBouoMjHK/zDCyt78Yi4vkN/Oo1iILe2dng4KINUJHsWW/jwZGTn//elDuUrp0ZHRS0RUNHX8fn19vkUqc14FgRB2XD4/36us6Em1+jwzzGqB7lynN478Bj9GBK8CFbvb51sFclMJH5q95Thky5ZEUjAljwc86wyBfQLUpCw0ZUvOcdrbC6RkdcqgGQRnrone/aGkCmeTifSezlyoIdm3I6J5CLDmEO39rS8ZBEGtrwl3DQDrXMOUF+ImvoeAGwGj7rEgpv3ZAcy2f9rpCwEfH2KJ7LqYYnLmn2yWGdE0LF/vZz39uTsfct7mhk1qf5fkg1OjauNDCJJ/LZGaw7IXRGOgQK83HTwBhTsjgPTlqPk3TljMyYNcD+HefS0ritmvadp6bNieIOLxEAK6N6ekwhLL090h/oJ9bui6j9UsEdHEMmj2ARHNGNTQ+Cs0CgNPK5dzMSOI1FUB02IEA+LWu4NwsmgR7jfD6pa4YK7EZL6ODxzK0dSPvm/K0TR04TACGueD3v/dpY3ET76XGeRxfm/vpj6R+nbSfew3+ct00dZDvQSycuvC8Chu4BsjjTJNuC7KjhgBk3z8pfF1rxTzNEgeYhdHx6sn2sMN+t8fV9Q2urq7xo8JeupNO/bp+pD6nDzM9A7onkvb7vW3A0zSxi+VSkPOAWkkcnhxxd3dn2rTtdmubeSkV5/OEUgqur26w3+9NU3Y+n3E8HlGJsN/vsdvtAMDuz8UDcxh4k2MJv3vMPBwO2O225lDl/r7g7u4OL168wH6/N0A3zzOOR75Av9vtsN/vsd/vAbxmiVYAiR6fi3c0lhgTtqIl1FSJGq3f+mEh36VgTZ8SGgvHdd6sM3bRL1uG5J9F0vNSQcmSh20BRwvk2nL4dZ35a8uni10xyr/H4buonBFkC1YAEBJq7+UQLcO+BtiWWot1JnotEUjuOUTg2jc7OQPc/rIKOpf1ythYFRRiZomDFJjzuqg/VLGwz115wJgx60dixsSYOoLHbXRQBwFO6q6diCxOnjKuMSyJAaAU7taG+20tCMoYFDiYUMCZ31UwHgAdAJzP5w4EEoY8wMMT8HNrDlW0HjO1lHJVwGWx6eTZ6MDE2hjeE2DCoKhB6EFczGPjRIQ8jg6GIgO/Ath6jV1kgmPfFnkE+8bQE46JCCD1UlxkvNUpjhZqoxyWuGj7oLPQ71IrsaKZvHouVfP9UgtqqTKXRtaS2dKnxZyIWlemO4X2xzztPqBjdzjsjQ5qCcIm/5No4HSabSSvgzauHza/vI3B+Y8AHD7fnEqufSp2xrizntnoqGAwAsAi51WkAxFQ6oxck3t9zhpfUOP0uYOTIWg7K7p9UsczuSim5uz36/iglvO/2LO2bqIDoOoa8L5cQLREOk9Twk//+CvcXu1wO2a/iwu0+wq1ZrspSZ+B5u6/JvNQunIWNAKYBBu3WHZ8bWnOZsXu14wnS6wn84VOF5ATQ7NUw5oxBOefecYKOM+ZvfyEvp/PE5AecJ4m5GGDmxcvgMSmmMfTGa9evsBHH32EeZ5AVPB///7vgqiiVAa+NTjAeU4ffnoGdE8kRdPKaZrCRumx4BTomaMAcWpSK6EW/gMliU3nZpP6lxPHoAN8Q2ItYHvI1ap3Xpx58VAHuuGyJm67dZCnh6E6UYkaPWakVCPoDIlp3JSBTGwa05j0yIHEfHEfbDymYHj0zj2yBU+Sq42x9s9McqZ9vfzb1weOwqoFfOXlXQZ1C40C3qObQaoZGWf9rWcOhpz9Qv57ArP3MatZNivMkQjmFnjjGxyYsUVHYQAAIABJREFUJtXWz3KQpygRD/UGpsvAUMdzG3jumsp9F3ft1M6VKPmWKsFmW22wc2WqIyBpQAhUtgxrt9ahzJ8CKSI4WNUFD/FYSC6ZN/rYHOMCda0rbRJardkac6YhC6KE3zQJyvgrU2p9zmGciBllGz6yvCUys40jkXaqxJWoe4EbzrWgLiYFnJp6pldf+75HwBv1p47PHOwlcobfAmQrcKrk803AR4701vJ0Amm7c3KtW9bYgrp/JFRpTE4JBbJnE3sQ1JAyWULc5MSBx6mCgycjWd+0lyLXcGoTzMx+HAeb4/FuVs4A+6XhcSxlbuav5mm1v7BzUWmvXlT7OahnIL86oGuB6mDtiluJeshc0yRXFfhUWXcpASrQ0PzJg5kvtKoXUgKaeiBrN+t+q793+zLJnJzfpx4ifP/Hb/C3/8qvomxGJPFEq/RQmvbrwWh2YZ5f0ujpb5p+fH1o+xz2s6X2VYU4fJeY1327rmNbmDQpvJedl9oT2FcmVPkHcQvr9ROh1oK5zCAChnHEbtxgLhXH01namzGOG+z3B1zd3GDcbkFlAmoBh/HIeHZy+XTSM6B7IikPblqp2jndxNQhioYfiAHIe2k34BJ6AAbmaq0YRg8YHu/dtWZQfKDr4cabXl4wKSrtVpPKYRjsHsQ8zwYC1dmLsAnG+PDhkEwaZ0wK2vsodujX6Aref1vFQSm8XOLagOY+kTVkJcs3SS3AeuwMdankAmDauZ2azyZ9b6SVzqCvg7mWWBG8Wn/XgFZsDAV/XHpIxoYlZggjg/E+6X3B3JrEtm1k/KIVCHydtjhYUWbFtX/qJGIBGuH0jPG5QoOZiVCmpOtLJbBWCy2Y6yX2QBJX8LBgzikAsrX9QOsARKtgAI/bpUwrl5O4HYWEafa7VMAlDV37Mec22LjW3wO5yBym5P11TaaCAtiYWP7EWkoQgFqhuhKli7pqj3tVHAstNxEttgdfusrldeD4grBijd5raSFUkb40+x7asWcNlY4JGQgELefJWjJvo6G3pqll1IFcu5AO8loi/TpgHoGbepBMNTVzIgoqdB5530Nb5OmOWi5AqMU9LpNjVA0P4v3SPwWnWk4EYIDv9NrnOIaE3pMw543cN68iBVEOQt0BEQtGNF5e0gbzswjCkQtAa9ECXRdKr8SWAUnOWBNwVLaTMHAXQJ4JO/p65Luf/dFXoJzwhz/zU1BP2lGTq+1VIByBlpYVeYXVPaNLEeD9V//CL67SoweH7TpKNha910jL1wM6zabkSNGUvqtb/smUasGfCA7GYcRuv8d5Yqd159MRc6mYZvZGvN/tsd3scK4FhWYMaJ00PacPPz0DuieS9DBXDRc7Nxls09T7c3xvbdsArARn4KKkEkCQPlaktDGzzrgpD8OAf/DTH2Gz3fKhhmCeAzTl9ZK1CNoiSNxut432jjOJy+rkB2CvSeDNto3jpEzFZmDvnXq/zjUAnOL+fpmdsqaEWHVeQAoHpXEN3zj1YI6ac0LP93XerwVr+p1jp5Ypid4tv1YKQNZb/O48ae29fGZHk0tJqn7upazLw/nx5l4aXdfSXaJFn2+dITdTOeokBsRCAP3Xl2OseK3tvS59KnhqNEl9UnTmbsYjoIsCEIjmOSlwhNMuOiloQgDo7ymb6bLWq0xmzgOyaFlSSqiQGFsVdi9PhUTvAnMATJhkoI5gZfd/vsbbOzopzqvI9IS8wzDAxOe9OWYA5Wrehr7c7tn+ewfXLZiLc/gSqOv7uDa/42/Lu4Vet65vAz8RlAVNVT8ujZbMQIM/ol5QFeipgMvuKkOAgZjdp5w5dlY8D8CgkJLf8WThxpIhjnRpk899pWFPx0oVVAgTTSGfgsOBwS7Z6Ae66TmXDdCptq6tq82r+2lrLgvEkDk2riIIMUHFMHIZlcRc1B29DEQYBPTZ/OTCmhY8thva7ibr23gHYu2tBrkmMTHMOVuA9Itlht/204QfffISdbfFIOtRLW30nI/8RqRFL6x63xTP+l5wou27tI7kAZ5jAbT1/WOgGeZgggnYHgNV+iwQ1l5yIZruHsM4YLfb4Xw+Y7vd4nh6wFxmnKYzgITtdoftdofz+chWSjmh5scdKD2nDys9A7onkuzgqhxigN36bwxYqb328XjCixc3sFhP4E1GwVc8MInI4sEpkFKtmP6VMiMl4O/9ys+wx0ph8kyrNwwG2rTMXhuo4EK1c/M82129oTlIlBkSb2lyr4aoNAdEbD+pFKtWJHEcw1iL/GTr9vilVLP9SIjeMZ0Zty29AznfLEXmvAd2oWkBoOj7/kxsNXS9VPJ90/Kw7bUTocLQg0dq+poHd6NtWpG+rn2/UunFao1VD8PXMgXy4zvaqGDukibGKtFzniIA6MBeELo0tSvY0nzvgNK2NrQ9KSETdSDAhTTqKCllAXNZGO9aWUNgYE7jY7kWstfiKMhqJfs+J9NygS3wdKWKXJN594vmoZHGyjxFYMb5XXiTEpuqLVISDai+t6+V0fM1YFL4sAbsNTKVskv0c2Gt7U1/Ow1pT8u1fMu5qt9z65ryEoMmZmJ9E+y1ZibjUO0vyMeLIP4WE1AAyvxbVVf8ApBNaKCMvdz7UqFFFQ2UDhrfLeNyDdQmsrY9zpTrmuJxNEuUklATXwXQuio5aGPzSr/TFoUaTDYNKu4mnDynmZgsRIyCs7adEWD790EoImcakWueC5VmIBUcQx2PkZ9tPR0aSV/cj+MeCoQYg6ndzyk4CyIC5MqCzpFLaTPN+PT1HX7/p6+aOLJxb7kEunzNLD039uCsXwN9mX3Z+mxfTkc4AVjr/YuADvK+O/jjB69DHuy1uGymPARQB3MEt9vvkW/fYi4Fp+MJ45AwbjbYH/Z4uH9rZ4yGPXhOTyM9A7onkoasppCE4/GElBL2+0OjmXt4eMDbt7f4zne+22jEGLhNIFRw/B3dfAvO05lNOGsBQRkpSNDUke8kADgcDh4cfMyY3r4xSdPV1ZWBs2jC2R543Ibj8Yjj8YgXL15YHmMySU08E8ZxI/HuEmo0C00u+YVsnqqh3O/32Gw34hygrm/b2ibHkIibdGRy+DmC+G8PGhM9QL++pDEmZ8S8DX5OR2CyBuiWdS/B37J870JC72SlZ7xJmYDwCr2j1IE9K0meXUVVlufr0+0x5jY+o/OX5/jS7bp0DJEBbrUqkRkjIOVFa0mYrCrChxTmlNbjQMzvvrnjAWEe5CL9YJJcKT/SirQ+MiInlzY0dNF5kdTTYJgPLfPqApZaCDMVA50pJQyJXcwPw2CVlRoDO8sbse00bZNpZXwdpWa+cltqEU8DCUjq+l7/iXfbSuLavAGWqlVbOhOZ59nuhqnW4Xw+t9pUgrmLdzDBhOOg48m0+6y1I1QRJgVOmPlf8rFsJyGs7DhfAKdToyGFM6J9nxTU8l5ejH5RI8Lzlp1elTIbIEspAaOWkdmrotI8CkdINW1tGxfrjdEda6BlHiujaRrXAOzykJFqv0cIk9qFrcmp9VrsblUjXdUEzumn9Y0btsqohUNzcHtc6AioJqx3xpS8/7oXVMKM4mtJ4uWpZ+cijmDGYcAwjiaklKYF+rmTkzwMGEYGuaUW0b6xo6YBXFaCnpEsYB3HkZ0aBRDky7mbX/q/4U2mVQ7jrFcWdI1nvsjI2cJY9kK9CAAJwLe/eIO3+y3+1m/+86CHh2a+LEHuEnTpHdfQVB8LkPcvOHfRM17H/W/+3f8NAPAf/eW/sDJN2vOsmcayDhZLtskTxxFIsoM37108x2Mk+1etFXMh07huNhvkcQvCIE6X+Nzd7g549fGI+7sHEGXcPpzw6uU1rq4O+OiTb+H+/g73D/cCBlmg/ZyeRnoGdE8k+WbpZpDxXlo0vRzH0RgHTaXOYOmhsU4gqqh22VukpgnNxqwb8rffnpCHjNefvDAPY7XWxnQyyQ313uxIGclSqsTKc8+ZLtVTpyjsBzAygMboEPkFYZUsE5r6knirWuzaTMV3Qokl876OTVx3EhrT5QufLtS2BHOrNYX6I2hrv1s+e7nergYtM8ELW2+M/dYf9AkCAB+p5/1ao21aluRS83Uwt2RC+f8sQbPXNHQxcaiMplQGh2jxf2RIvP4ml5uU2RRxqXKCg888DMzQCaDTZ4rOd/2DN6Jl7FqgHuUVSUMEKIxWAIPsEmAJZVIKawt2+70BTYv1ZSaiDWmsD0hqdp1cS0BOfxgTJQXkCHyj9i/kC/Sk1H627wPDx174CGlIVs00TS41lzxDyiqfsfozsmmzbM+Sfwqoe0BHNew7QYgSBQePaZnXBF4AGksKAAbatB88xhnjONh4ajUOdNiENddspn4OXkN9Or3kX0IycNVrZft26ny2e1PyW6lVwhgMdu9b11udxOyVOiCc2vJd8MD0BsAmgQAS+Z29BJjTEC8q3rHm9axALwKMnCRGo/ZFhAkkJm4EYk+xozL2vn/wPMkGHPu7d05vtTSRv5QbMJ9I7rOLdUspBbPNWV+zkDNN96HmCLhwBKWExoulAluAvx/AgLPWKGhigNIUHdbY5jzhB599if/sX/kVW1u2B1i9S4DX8xJxTsW142/IKG0O08LceJ+k1goI53fcxy9k4nABcR+V96zZJwGZJG0kuz5QA52JJUfIecSQR1RkVAIKEUoF8rDBYdxguzsAxLHpch6x2e5xuLrBuNlz3oHXUErTI41+Th9SegZ0TyTlYcDDwxHH49k20pQSjsdjuMuWMI5DFyCVzSZvb99it9tJjLkEoOLh+ICvvvoSlSqur69wfX2NNDCDdjwd8XD/gKlM2Ow2+Kv/4z8EAPznf+3X+IAGgMRmApvtVkycEuZScXf/gLlU7A9X2O72QEo4nk44nTm45jCOSOIZDBKgtYqThVoJG3HOQuI1rRaO5VJrxWb0mHbMb4mbdikT4jqYzGwGMGCo3GIC0sq5sLbZ86HgzLkdSaTfJyzPmMsAr5VIAjE2XCscTavPa/nxQn4EEz0A9balUFfPpAG9ts4k4ghgjYjdKBM9ao5JXV5tUAqEcga/Z/6xevIyo6yHfWqvwRm46YEVP1KptmEL0IHCFGhNznAQwZy3EOB3QyCOXQDXhgXGGCu0YWEDS+T1vhMzHSQBvpV8qs1rzYoW/WK+XZwSNNSWhrOmpErjXcOWbE0MeQAGABJGQmULWn8VTYn1Od5zU/Mx8V6YBQA0jQygyKexesCU7yVfsn44h1qo8jol1tIriFRG08aklCaYtTNWQM6sZTQNFILXTmsSM95Q8Cdu/zWGHYOfwOHJSwYHgbbxlfJUu6fgShlTndjKBLsbfB3nEPdN6UWQtjs7nxLEE7ACI4LG7Ww4UdgWZWUpfWyO2lxVzlVGjYChjz1XCXOZzVwuDwMDANkTjPYBjNhoqpkmujWj4DYn19aGtmmqtbjZYugSj5ncQZNzT2fiOAwoKfn5qOAIEPPiYrRmYEwhMDb3zbxzBmGMOqjJ6oFwZEsWzl8xZCANGeOQbb6XubBJqI4z+BmJfAf1EGreIoNgzU0uVzfGDoCFgdY9huDB41V0QrC54+UE2iv9Ayj71u0D7ncb/N4PvotR2uqP+pibsCrcgde905yXDcFEUYBS3F+gALu4Ri/lBIS7oo+ZhpJIXRQYKs1zkn1PlmZFwiwxFxmHqan6gMGCzIiQpVYkVKgdQgUBAw/Aea5AJWzHkbXhAMf03R+Qhi1ub4/I4wlXN/LMOGJ7uMLd7Vs83N3hcDhgv9/jxYuPcXPzCrdv32I6P2A6n5Hz5mI/n9OHlZ4B3RNJOQ84Hk84nU4AfDOLn3POBuiiJLCUGXd3t9jvFdAxc3E8PuDN29fY7Xb49NOPcXV9hTywtPp0PuH129eYy4z9YW8HW8oeuwkpYbPdYrPdmkOHuRQ8HI8gIuwPB2x3O9RacTpPOE8T5lIwbiSMgR297h2Kqmymegewukkl95NNiBhk6EHCJiRpyC1TA5cyuqMUmBUlEFlhBwsN4JFDzzFdAB3wg6xPl0BedF7QJ2Xy25YtwZd+72e+g8M1gNmDQjKTw9i2tlEGxEQFYKBuzZ5/hQYrrIeVFYjXgh/q6R4ar4wL6fu0GMNLhI1aKn4+gKAIEuHMrDGoOm4h/hYQvbqx5J3jd7XOGxrmPEGCCbd3uwjOYPv4BFCn7HYK8yYQ173qhbwxD7lJmTJwfDcVplkBIoPHr3Z3J4LKAebGvmH04VAsjgABZqbn4waYRgQwJn5ANnrZGNSqYffMY+e42QCkRnlkWv/DduuAighUCkBs+pdzRg1OMVISZlzan4TJU4acKIB3NXVtOqXjkVGCqaImY17JtbEKWBNg9xanya0rNGWdM7LBqSmXb2t6z6vA17ADxQj2rcG2ZQVGGW2/jJFOKvhQSwkW8KlX01ni1KWcmbbDIHPQY3uRFi3rXc8LnV9ZNdKqUSQC1aAV1PlvXRBT/GHAQNkAIc/rCtTgiEXawMIO18Al8nAKRIS5zizoESDL9fLYa+w39ewKE64w/ZOYsUbtVK2y/sWpkDkIkSDtamWch8GA0pAcwMLanMxBkJpKKg2TbYCwuQQFxon8XJO9xLTFKYgIhLat4aPupzxwth/J/pESg5w/+0f/FP/hb/0lM7HV0EfxD/C9MXrM1rWmTc5yPYPITUFzjiCR4RZbg8uEtj1Qz7vL+72sFH4N55yC8ADTOOSHOADSEpU/YXPHDKIKNrfU8EisnWOMmTjMQAW2m9GEW+OwwW63x7i9wh//+A3G3RlTAcY0YDPusNlfYXr9Bm9uH/Dy5RkvXhBuXrzC9c0r7HZf4Hh/j3macHV9vdrP5/ThpWdA90SShiuIQTyreKlSs0siWmyyeqetl5oBvLEOA4NA9UQZy1YJ8iD29noo9N4tewZPN/Begqex8rabHYbBY9NpG7lN3M4hD8jg+EZ69jTmG1yoM5RZZZ2I59QiXZbpPZYc5Nl5+Y0Twe+vXSorXXh/ucz15xxEtt/Fw9zbcVHgqfOF3PHGpXt1iK/63FpZi6aSMJMXehgRR9Py0PumE8wEqGT6gj4RyvAqLFEzM2V4jZEjaphSUvgnTLeZyClm7ejLXW9BUNPeQHw1G4vtSLktrQWxQViReLyJmPl2Rkt7Flx0a49TRs4eXJuxlHuTHHSdD6r9F6k7VavXgaHvPe7QIdn+IfynPsxgIY5jUpAHUIYxlUVpF52JkO5h7kRCx0bv4ilH64wgCWDTUAhOem53dFaiDLeP2yIpYPbiDcxY7anVXjJgjoEUdCiTtbkXwpSioC4KcmBCIP5OA3f7fsD9XK4ba5eO8TAweBStBrOuQKIKDVyu4Bep65PQVgEGQc+BABxlcBVMp5w8mHuYjz4OLagz51nhuSjfMC23tVPGgqqNfRSKqBas3Z2i5rwd2wQGWmquS3p3juJ9Sgf3fOZCVlwSEK/3IfVeXyscM221Cb7sB8UzLTgzQvB9PBOc2DynuDk6sA97aYrldNQwWqeEn/7Rlzjutvgn3/5o0eaYmvVfPVB3BL8piTBOtfJGhq4sMEC19aTgN9TVXuto57n2xk/vy+mSKb+WvTwz+X2R+/pUi2xYsPXE11F2GHc7UM6YSsHdwwl5s8O4TSiUkPKIYdxiLoSHhzO2+wO2uz02uz3yuAHmGWvhMZ7Th5meAd0TSdM04c2bE87ns92RU0cA8zzj9vYWRISbm5vmTt35fMbxeMQ4juGPgRsRYbvdYr/f43A4YLfbQgP4TtOEB7n0vN1uDXzlnHF/f9/k3e12GMfRgKVe6t7tdsYwaDvv7u5wc/MC+/0e4zii1MpxWU5HEGBBz8cN95EKMxkEEqmfaOcCYE2JY7ywMJWljxe3wJUf0oWnAw8YmNCWkbCvF2fB8nDQZ9T00Q+KZcPiOXkJQHp5Wl8L3GJ9/jw9Ul4ArcJINw1JHnIgMjyNW+0VUGe9WwN3ERiGvBEgLt73BNDvQxnKmHUkWfRXYFngcv051Y6QATu/o2R5Yxy2rn8auJjbk619VJShcjCmVGKpOiFnkiDlQlO2PWy0y1xuCoAbNvNrrZhrCEGA3DBoCRA382TOG9SjmmoGSJnecTStCpOqiiaLFBn4uAUw13hCDL3M6gipmyMLU8ggEDLhT62N179hGLAV50oafkA96ZbZ+5bz4Pf8qCLy0kTJ7hGywMzXCwmD3DKMDgyiC39tuD0VAJP/RmZKrsKC+Jxq6NpEYc9rHSTEgM4eDoIpnodsoMZNRxUYiKYi1N1oZgAP8xDW3mYzQhCd9DEbOIx7xVwKUnHti6aUMu/ncxf6JmUxE87Ig84zqTXsv6xdUm23gF+lTW0350LunCsFbTolYBxlLcr6KlW9PA82BqY9JAckKjCJc4UAcx6m57Ku2ZziHdMswocUNMBsbqpOz6KQU0Np+CyIB5FONPLf5KNuYfZd9bwUgJ7NZwWxBKZpjZUASAk/+9mX+I//rd+w9ulYaL+iSSWABqx6v0Moi0TiuIm9k8JGcpkMiDfgkbo1iea9CqLiecSCnM4hEVzwHMMthMXflR3PbNbMzpX3ekq6FyQM44jD1TVuXr7EuLvG7st7zJXw5es3SOMW+6uX2GwOOFy/Qi3ANFd8/uUb/MLPfR+vPv0pvL29w8P9EfNUMZVnL5dPJT0DuieSSik4zSeL4eZSQH49nU5ss73dmnQshgkwD5WysUbtm8eKa0MPzPNsv7lWL5mW0MBXcMKim6W659Wkv0/ThO3LbZOnlMIMAFy6NQSmzzzUiTYBgEll9eBQT4Gg7tB7Z3Jpp3ulTvJ+paAoHkf/9jKIW6b2YOAD6rI55vunr9V5aP+TSkIFXEXvlvbAImtyN/ArLSDAPZUpk4iG52paYfX2Za2BubW0AKDh7UKCrZ2m5nFunzvxoJV5EDXFbU86RNg94exnfLZ9YD1nx9T27W3ooxJrWAiCKIU3EzMFD6JRSZn4vmBJC20DAsBTRtHDBLzfhG3GlFwbqOA9MTftAoM49wKlbI+RzwNgjhwSWLhQS8E8zZimIvtJFq+5I3Ie4U45mOgKTltLgRwEJfzaCkhUkxKYPUcdXathzLQ9R0GTBAdVa4GpAcg4OnMqDXErCQUc8Pa46/tsptLWBluEIhirwZmVlG2gU57XvRnIoaxu/CWfegY15tnywh1xGMBM5u21d3KifT1PE78l4jvSUGdHEUXr6tXxcjqYN1qZV0or1brbvcAAwOPe09/vqhJDzvpszXWww7RTTbADEANusqZUK5f1zmJYz76jeH/iDvnY+lOdvBa2AHML3CYCJTczYJqUilwr7nfbZt+LwoD0CA3MeiG7kyaNSxjztlps33/UYVHst+O0y6dC36a+XUolFWI3z+vfavneGkIKW3l20Ai5Q7fdYbPfY7vd41yY/1HAv9vvOYZjrTjevcXpdMSw2eJwdYObm5fY7vZIeUSpz05Rnkp6BnRPJLHEbm6kYrrZzPOM0+lkICpq6HQD2Ww2brYCGAOj0rMhmFMpY1NKMe1bTBHQxYvPCh4NZHVByqMXTs3bS/Zimca81chU+EYbL1m38ezeP0Vm9xIz/nj6us+3uOMxvPSnKffdyc0+9bOxaOSsGmnjgqSzqbMpUg7m2JC1g/6xDlxqbQCEjyZjDsLDFzKl8Lz2mIGle1kzGJYIHDSYjLmF5bAO2GvLcER2RMo0XBfqD+10syVlPqhhaAAFyS1758wKWWBbNz2ES+NVG6aMO5jRzgTXeEgudTXv4Kv1LrhGZqtxRQBSw9pVaXgJ7bD2hfw69o3GR+aZevOLnubUOkEBHTNuqqFT739cailk93kQ67eh1WdVUt4tMupHZvmUMrKXQB8DbHHO0pLLxm9taacI5uLch8/RDAB6XijNhLYEBv4UtDI5L3powrRhGE3gYR79ukQAqLhWkIiaNupdt0wEDK6ZMmcpCON8gbZIAUTo3Elqmsj0IjEf9aDe3ivTBiugEwDqmnY3HeX1L/M+J7DiLNl+GzVroXkOLSkKIghjuNpguBo+H3XdqcAFgDvZ6WltsQbRvCYIEKLWhNzqwhIcWoN0kUt9v/iHn+H//IWfxt31HuiATzskAZytgD3TBINQqNjnhnYrg21jIuX8T7/4vYv0WORDC8oWZplhnN6XfzASQc1IxfkU+N7dVCpKJaRhwLjZYrPdYX91BTpNEtaAMJeKm5uXvOZTwjydcDo/gChhf7jCzatX2B6ukMYNpuPpvdr1nH7y0zOgeyJpnmcMVMx8KAKeUvh+3eFwwCixcVxDpyBqAw3UDUAkjNW0bAyk1DFAES9qBHXPrKCtVgZuKSWReHt55/MZ0zSLtMtBp+ZTBwZal2nbyDfaGFDYD8IQIweXvGZJzBahV9ya1zbq1L1RU7c175fyE7fVC5WGv8/o9Q8lKG/VSOEvJD9bl+UA7wZyfoYR1s/A1GC2RasXP6yeunzY6/v42uXpGf/3SV8LrCeHfgvGJYy3gtcGYAF8706Qvkrk9d6jxkJrQIeC4QbzLjWNKYx3FCRQ+C/y+y4Mce3Kcn7Hb6hZSyZxDyVb35Jr6JBEG5aBVNPi3qPFsFKJ+8Cu1rOYz8WON2ObnMbUS8s7QMce5Np2NWa/BnydodJeZ9kLdVEpzdSZCNOF7y21YQA0NlQ1bYt6vHRNGYHDuVAY2zC1bSBdWGFzQn+jwER36DeFeZas3hWmcwXkevWdhkS/bwBGyBtAtoIWcwqRAKJwJ1r/D8x3QpIYjO4VMZKDwXVFLSEGYLjjqJpINk6DCxeEZpyvrjgYin1RTZouaKebzzu+q6VaNwdoTAfWYEp7c154CjWFfphtCvQj6GeQ52arenY12jHZG6lW67MLJ1hoWVM1Zy+9CSvP4SX48r0KDuaauSB3+KgV/XgRyZ7R8bMep4TtacLHr+/wd37jV2GCgNiqBUBaArr4/dpz9t3qGWcZjGa/+91PfL2vPhrOn3eAPn6mBaOrZYVdLCFjAAAgAElEQVTPkV7M/4hlAfHYlVpRCRiGEZvtFtvdFofDFQodUU4TagXO04xPv3Vj6/Lt7RtQyphKxWa3Z8coh2sMmy3m+/diMp7TB5CeAd0TSdM0Yxj1Loh7FlNgxpJ89sxVK4diU8lzKYTdbsvS1aRe0ipK4fgnamoJMDBT72vsNZN//+1/49dwPp+srpwHDMMIvX+SEgc8P58nQKS5KeVwN6VYWxA82jV/KYVgmuqYhTdH3vjcFEeDkFeiABBbRvl90/uajb1fep/Nlxav66BsKWH807THQeE7DsJHi1tqSCw/F6KFXc4bwd0Kk2AAo2Pi+rIeQ7Ea0Jvfd0xHeCUBbAkJrdtMZdxaxz5sPhbL4ueqxgdofoEDGWPqje1swWADVZoWanZE49bIx/k80aoICe4JEIBpYNhUTWofPJNqwvVejzHqkcYyVjl5vDIUN1dr7qtEauh4dhSyvoQ89ip5GlCs4E9NC7V9fRtF6MWWBS5ccssGHUt1TCIhGHLGZjM2YI7312XLDWdCwUJqBBq6q8XntRQXGvFTrTYDeNwTbgAygWYVcA+0Pf1jfmB9nTecfJeI29w8IqDc1oOu49BRN/FzEOXANFldBIg3R84zz3MT9iEhYbPdGODjuZf5rND2ZArm4WBxTQTLSi/RyCVrkgDVYQChNKCFIl26MchZNL/yHvB7Yy4wcJAKyDoRhygqtND5UsAaqyp7ThbzY23HJcBhR6f8ayYeOWATSrT54IBPf4+7DwD8zGdf4POPbvBPfuqjhYAg9jV+34M5fe4SYLLfVs45B2cuVEBq63+ftEY/rfNd517fp2RgXYmvKu2wD+SMQUI6bTc7HK6uMVPGTA+oAB5OJ2z3Bxag14rd/grjdoeH4xnbzQaH6xvsr26w2V+hfPXFe/XxOf3kp2dA90TSmzdv8OI7L7HZbMIGlHB//4BpmqE2/sqsqLnl+TyhlIKbmxdypy1hntkcqZQizlB2yJnjyE3ThLdvb1FKxeFwhf3+gJwHfPnxHvf3CafbW9RK2O932Gy2bnJQCbe3dyilYL8/4OrqCuO4MYB4Pp9RK5lWLwI2vrfCm6Wadxa5bzdNE2qp7PVyyCb5LHPBScrcbDhmEKBM3zoN3STJwUA8cJcWiI9xOfE5vPu590quCVqLF7f2vDaixzc8D2rzmV97Vo/rY5AdDtAOuPUQtFNHLcBc6hpDwnQagAAaxiEyUk1ZfU81/zulryTt7sGcjHsDRFM4oCMT4Zoar44WpmS87lotFmfKxuQq1S12WErIMvciUFSAkLOPaaUV75/KrEaQJ2sjVff4qmXPpRoRGdg4wws4o6u0jpoX1sa1GhGCCIuCuXSvvlLwoAAtzhWN46e0UVNrMx3sgb6CuZSaZ/SemH1PhO2GY1VutzujNwfizva51/LruOvdOTV1dQsBZ/x8iShYlHWV4gwOIJfQjK+qfi4xvz4K/r4WFrCRuNRPiTWYdhdNxyDSXtvUa1GI0NeWG83gksFV0FVL4b2biO//QMIQaN1JHCflBMJgjiKiSWgpxegbAV+crzp3koA3qmThHlK4N6j16XwxgEsVhWDhCpJLXQxoEsG9T5pJaqR+BF4RQCQTqibh6XXN+3ziu3Nq/ZJSMk1yFWcnwzBIbDXxeipDOGSPM6t7jc7vRusX5xi6OWbjRrbZ6lln2rrFpkJNvMb98YTvfP4af+uv/npz360Hc9EiIFrY9KAr7nPmQIRc02utWAGOCEDun/vsK1Al/P3vfrya7zGQ1wBI/S7s++0frXwnAJ4IFQmFgLlWVAw83zObJW82W1xdXePqmkHZx5+MGLYPSJs7THPB7d0dChLyuMX+cI0XH32CUive3B/x8UcvsLt5hY+//V28fTjiT3702cX+PKcPKz0DuieSjg9H5PyReXPTDYmBUm1ivugrH5zMaG63W7uUroxKSkmcnmyMcdW7JwCw3W7NsUl0sAKgcbCiaZompJSw2+2wEaYq3uUjIjnE2DSyyG/s+tcDfwLMPMTfBtXcge8FVPKwCsrc2QGDd0GhFUnhoyLqyzl7uND/0oOs5ulHMUmPLt8veXn06HeLFMEcsHBQ8j7wkh9c0U4ok0nUvF8w7aGM0CzpQ8v4vaM3If+aqVFbPulzqX8mMvDrQJva/9rUAWEz8yOZwzmbWRdBBArGuGQgsabNnYP4aBjbHgA4EkDV+2QgTf4iA6iu1jVFJyfGnHcATDXghOANMwLYACAiKF+bO8qw63sDc+bExX/TNtt86Ris2tWXhwFjYm2HAm0HahHQFXOIwmaWTrNaW9DBXUyPrOdlL3XKmmYxCI/6FBnbliF1oEJBSJFEE2B/faOsoXGukkoVBGSHfc/45raPESQpgCToa8yTHISB529OMdoZt5eiRYm8ru51AUgliMdYudvazAl5NkMBRDvntX058XrLRI2XVKtV6rLYprJ2o5OUZOPEeXJe7i1uyssxKzNlibEo9weFlgwEtU5qTSflmarliTlsA8Z8UH1s5TMlX8vNb5K/n4Oet50LH725xxevrvGPvvep0azXuq2ZXK5p5/r3pr3tvkP3XSgZEKHKX/6HPwRA+N3vfYI+0dpaCG2Lr76ntIBOawsigqZfZsaKDLY45zVJck6Q7Mt5GIxv2e/3mCowVeD+eMIs1kyJCGkYsdvtcXXzAndvvuCYhTlhe7jC1c1LID+z+U8lPY/0E0kPxwcDUerdEuDA4rVW09wpuIuADkADzKJkrPViufSYqXHtfvl//vs4HU/473/pUySRLkZpHABzeMLxV7YAYKBMAd04jqxpA1BqwVRmnM3NM8xVuZoilMrBX3vvZyQBxzUIK1TqCjGlkvL+3016EFB/dmCNwVMeueHBF6BOtXT+jEGOd/aH4J12hs7rSKGtDlZSONQeK/ki+nxHw4zZ7jv+SOuXP3amnmvvVyt2JqhnXrVOfiVE88r4RAviIpNPBpQa5n/RXucvCTx3KQG5kvFQRFDngcL4CzOblEVQkYd3LgIEM/VJMKZ09Q6SdUOEOtomZW6CJkUyBqaS26XmzhTa752Qma/ALiWnhwpboqBAGfco2Y/k74Bdoz0N7sZVw6LaHb8fFcfOgxzrnd4aAsVHTatqkRQg6Dpp54CHplgwoKQMbw2AE6vr7DKY82WiDGZKEEGLalzDrGiKJlvX7t1V61ONqjWKy87pwl7gk7SfUyklDBKSI45fZjUdamhnLRUpKwhFoJ/HDDRAmVJYW94fqCKRghAig8tFuF9N7rAlpYSUBwwGqsty21BmXcGcPhDvdAsNGuECaUxBp4kSt5aKOvD4ZwUBepdQASKc9jbOWld3Vq+lCOTCl+1csDnElepe2GjpaPE4DqczSl7bEyXLY3vvI8+pQClq5t6lVVOTy9jKNS3gu9q2oGPcp5v6kp+NAQj6+iBbj/3aYr6lPSd2uz0KBtQ0gNKAuQAPDw/YbDbYjCO2+wOuqeL4cIupMn02uwOubl4gDc9s/lNJzyP9RNLpeDIpdtSSRaCUUrIYcM6U8GEzjqO55AacidCwAxpjRx2XREAHAD/3e3+MeZrx3/78Rwbo4maqIQn03p1q5+aZzS3VxBNgEy4FbHMpmMssoW/Sokxl1lh679yNaRmHpMJfk/q95zmzZLL0i7UCWoR18WenrxWo36w8p1LHZXmX+hC/fxfASyoxtLNwedLHQ4ui7LcHJiuAihAOvP5A1Zr0MOxA3AKchTIR8q7wG/65y9P0HT6uJgGXHy6RzdqrfA4pw6S98bY6eFONQAfmOuZX2W4SRjQRoWYgwQN1NxfjAnDhClZarfMVS9o3jGAKLsNTALbUgkQiAhU2F9Neo1bMNcTySsHDYYj7FcdT6bgG5vr3yhgrE7XaRS1PXqOJl/Yzd8AzQU2mspMQzhhHD685u6l3u39EuroGqFbdfwgaAsHbFGgpDDnfR2akrR5UY9sbkzOiUK+0NbumCjJNpNLV55WuKiTTnxZMvPXRH2qGgIz0y3HJmQFSUq+VHfMr+czLYhXPhjVZKJpaBeQlwJ3R+J0072IVYUtk4j14d5Lo0zm7h9PaeLjMJgzU9pkJoXTQzgKCacYakBrPJZnjFAQAWnZsn+0RGqPMnFsSUAlF6h7kbHPhJFz4sSA8LARLCtIU1co1G2aK2Xxv0XykO77uc7JFJyRc3R/xnc9f4z/4G//aAgRFENaDnbVnmuZfAGCx7fE3XxthnwvCokUR7zj8F/XLft//rkKFXqvHc8ZgOFKC7IncPqrsEbiUWUzSC1KZsdltcMgjkEdUYk+Y7Jl8wHabsd3tkDPw+qutAMKCcbPF7nCNlN0r6nP6sNMzoHsi6XQ+2aapGrqcs4GoqKGLgTJ149IQAmqmCMAA3Vr4AQBmNqlMDoGaurW+COiG4JJ5nme5x3fG6XSSkAZkWkaLQTfPALUmHcYQVY6lxXcmgoYO7qVTP7tUfCl1+8lK8TS+wMy/IymYe8dTDRMSTY0A2GdtxSUApczNo0g6AL/Vsi4B5Xf04HJ9MJBqMehWk7YHQG41GlFAEL0cxjt07rzB++9mVz36bpm1HJhxo3VPn45OPhuStYuERxdc2UiGbXzDHaGGqTecm0TrPXMcKkkW/Jk8XIoGdG7ArLY5MMn8sq6hi3Tpx3htfrnUPFl79NlaingpZAFQTklURAzW9M6uUk+FGNoO3T+JlNF3z7o6tFE4oh40Lbh6aLVpBIml7GpiCGRkjQq/EP5Q/NBSQOp1wOuAM67X1OQP8ymYysbxaKGqjENyxt+nh6whpX9sSwxDIAUZ42trRueimFlCPSyTnR0pZTCezt14VQPN4xjvWCpIr7bGstw74/OE43aN44Ahj35eAY231TCw1jeSsbMzEliE97A1KfcX9czVehQsKpCttbJ5td7hUw2iCj82I8Y0SoDxbHOaEOe9zjIycG4NpADWe/mOPNuArWjnHfYLJgP34/uffYGvXt7g9tUNkvADOq/iGd0DXpt76OY10Dyz9vulpLQMXXLafIPymras5HFtsfNJ8Yw0WsMD0deaBKfz3dIi11PmeQbyjP1mRN5k5HGHUjmQ+Pk8YbfjuTNsdxjHAZvdDqfjA8o8YzNssN0dgFXLkef0IaZnQPdEElXg+HAG1YQys8lNmSse7k+4ueFAlERi5lGAeaqYp4ohbzBuRoASagGm84y3t7d4uH/AZrPDOLD3SwVuKWXc3LzA4XDAMGzAgXhlsyqEh4cTDoc9ttsdxnEroPKMt29vcXV1g5ubGxwO18h5kDhQA+7vj/iTP/kML1++wscff4IyV4zjFuOwxe3bO5xPk8Rk+QwpZ0znSTR6leO4jCPyMKAS4fhwAlUO08B7MbsNZjNFPvjO5yPSAIybcVW6vJpEOgtg1fPi6mFhvFl3sKDTulH7TJSGXoYsfX3KyPUSw9hGzdd75ktNXalrnAN265bXHoGa5GuOlyCRp8Ak+z2dlkIRrLiGQYti5iVH5kCeU+cXkHr0fh8Bqx4UnRZGAai2SnRC3ExjisliUzkgSxB5fVNmBEx6sNudIoLcTyPMpcA91olLa/HMGjUFpRQU0vqZQWBHEw7GknjUM9QmtFVBC5E7GFLBiptSAwniiS0COLgWvFSeAFlitmk/lZHVdiojZebW2Rl8m1cp2RxqAKmM2yTONAwkDgPGzcZilWk+dbphFgFwT4KQZ3JKGETwpMIdBTDncxEBVYGuH+fjuF3DILHVkjsFYkFVMTDhsS6daWfaKOCI5ULMOH2NR+EXOzdJTVw209ZV97rp+E01kCFoeAf6YbnCGrKJ3woRvB5nirOMC8TNf7/1KNgnsIAt50HuB7mZqgkvJP9cZswzA2OltZslAyRzm8PpqAdSDVVDQu8Rmw3/xgLAguPRA6Czp0m9yy1CBtJ9kkFjFk1yKa0HSkWtGkuPw+6cUGXNJrlTWSXges68DsdxQKZsY6lrPcZq1WsFm3E0ekzThDklbOWKA5IIIoitWMpcAh1ycz89AQYAu4GR4OpwwZUIEuI6Z2qs5M3ZnLHYnkcVm1Lx7R9/hX//3/23sdttsdvtLL5sFOC2Wm2y73sNW3SIA+nLNE8LoES1AnWZF5CrGwIsVdgSnRkB0Wyay1Bg36emTsCEckp7AEi1IljSNu2pREhVrH9LAVHCkEeAWMA+jgmJKu7fvsb0yaf46ONPAJpxPs24vZ+w3ezws9//Pn7vH/1jvHnzGg8P99jvttjvtvjBz/08vvjix/jqy8/x9u0b3N4f8dHHn+DNH6925Tl9YOkZ0D2RpCEHNFElFLgEach8b45SG7Q35yy/udagzKVxpKJmX1W0ZhpyoN341LyMD0MOn+Ax6KZpbpgqTaqJ41AH2Txt6gHAcfIK8sBeNqPE0CSYnfSviGODpNqCBGubeREbHHb0pkCX1T58+r4vBvQCtXH6VQfeVp5570rWcGRqXy9liIxmV8Lq86yd4owNAFOGb60R+kzHZPYM59dJTS7VQHTlrpXctBktE2OaBqj0Vb2dheeJgO7uQ2+CR938JAFYbl7Zgi4jU3KGW9fdkDOqSHWTeHrVvtVSuZ05mVfCZAxeux50XUePeHGv6D8vCR1kzrbWYWBCzcyM6UrJ7sAMGCxAM9ShSTMoyeaTziW1FojAth/TBBi4szJVAND1pZe2t5pAZ/D5txS+k76LIGg5tmRluDBE/9iU73KwcdMjeHOt7ravDegliGYgmEoTNVrj2FfXnPn7tRRNxqKWSvO1Tm8QBB+xoYFGtaLa+RAEGlJAmUvQYHbmcWEt8JmRG6afGXXVhjrdqwEPvVuWbUr42CjgZqBWCntDHkRwoHH0CGQeWqsIWUDkwc2FFqVWABWpSlsD6EopcdiOWsJc0S4mFo7w5gXzayJCpZwS0jAgUUZKxcA/hLYUhST9mK6BtTg3ut/7YbTvM5BrRs18T11lV7/0+z/E//oX/gym7cayru0p8X0PNnstXQPe4F5PG54mPB/Ladeij3cPHNc0gpe0hFFYFZMLa9KC7E1DtQyEu3SJjRsSVZT5jIf7O9zfvsXD3R0wJdyfCh6OZxyuEg6HKxz2W6ipMWSuEoBxs8Fuf8D5fMZuv8fh6vpCQ57Th5aeAd0TSZvNprm3BoR7AN3OE91xe5gABzxqdmmBwRMAiSc3q4MStJufH5ppcfiq45O+XQBLJhU86p8+oyaZ0zRBp7IyfVqvclqRCeLvg2c8lbaWilJmf3ZtQ14/4x5JtAqq/v9JXwtqfo0yhWFNOhX8oIuM+CpAiwdt/C6896ocVCcsyboAbrGsUD+F5x/rkZtNdXdOUoQJzrYyU1dMqFCpZzBoQQJlbm2uwunlpjvClIkQYhCmUaW9NdBLW+OhACR/JeRxYLPjDJ/zavYVTKlV0OLmUSGIsjJ/xK/MjLCmqwqTG/tm7ZN6zOMe+b4zgOdMFhqsjW1M42ZjgcUbDVIEeSm5O/wwnjZHdD50+W3tE2EZ+mO5fiJAU7DgcT1bjZnP3GCqbF46dG7r+3aOeS/gwCj7PuvzrANz1rdq/YqNtxaFc6Cd+/6bBZLvaQAXFjStTgn9YMZxgpjfE4X5KsPCYMmdj6gXUS2dQh3M1A5hDFqAFAVY1LSlHXee5ykAPcJcC6Z5xpAzxwTbbl0QWfg3NvknjJsRowokpY+lW1d1GNhjtHhkBYB59vZGDXIEMEMQvmrSWHM0+PkMM0utdtYi9Nu14D4ezbpWoVUH6haaOpnzCuqQAMqslbq5e8Bv//ove/lwnmIBXA3UX9bSRXCnWv1oPWB5i3tObQFc+74vd62eb5JsnZhZ7zJUg9Iw8kQZQE4M7oacMNcZ0+mE+7tbvHn9Gtv95xh2M44z4TgVDudUZlxfX9n6VLqdTny1Zn84GG+1Pxy+UX+e009eegZ0TyRx2AENepvMS1sMNK4mK+y9TU2B2KSIzbGq5SMCNputmDLxgTLLfTbdeBUw9ffu4l8MZxBBnm5S6oVTna+wuUnCLJLT8zRhLgU5s1dMPaD4vbzG96Se0YKWUOoqtWKSw/WbQZ/3PwgMWlzI0sjg/zSAsGOoLkoNmwyAO31oM0TmyJrXOeOI4QVArXalRzSErnsXDtOGEX9HajUWK9q4vo41JpWYtVkjfmSMG+1zjXOPmnnX5W4+Gw0o0l2FH85MUwKSKXSUFZfnxFOgDXhVhkHjyVVQSaDMZlY2PNbWNpae5ovlL7U8/HhGAmUXnMQpk5Whk7tBUROT0Ap3eO2SmywHAI8U4oWJ5i1S0/qxAkQQxgvhe7vbFBhKZzqBaBzMxUT6AJFWNpYNSODfUhAA9NqCr5N0+RB5XTza7Ybny0T38BXviwlsYtfT317bvkYLhQisjDYX5DVxHAEAAux9jwh1p2TaLxj94gjnhpbBMFeoQLKPq8bKwctm3EgdFVSzCAMkH1VUSshQE7yuL+R3m86A31MLZxpB12uYM0JzFWSwWTOhzBwPcAhAT8uJmtAk9EhIBt4VrFEA2QacAd4jwp7H494fAi1AU7r5eF7eYxXsabusvJyAmnF9f4+hVEziuEzbEMHcGqDrP/faMeUp+Gxu6dznXYA28rGpteI/+Y1ffhTY9WWuPbemvevb3//F9tg+RXbpA0jAmMBChPMRd2/f4PX+C+Rhg/FqxlwTzgXIw4j94QrX+53N/vP5jGma8fBwxmYz4rDf89wA4eb65mL/ntOHlZ4B3RNJu+3OzC5TYgnkPBe5/zYI0CPkDEzTbOAt58EAnQfyZkC33e6Q5dI4lzdZDLqU3DSs1oovXu1xPg+NFAto49Mpc1dMcks4Ho/meVMdsCAB0zzjdDrjfJ4wl4o0DsZA6yu7EgCUOdWt2e9YiGQXnCcC0lUm3757D2asYUYee+b/g7SOS94z47sxlP0ujI2COgDufv59mhCB2NrP6EDdCrNu7zpQt/j9Ul/0uQSL8bbWkMAyOYgTU179jSgyKpf7pNo8Y1YDw6R36NgsESCJzSUyCZnXyda1VsTu3n3W810djslYCeHOEBi4NlrHSCxfrwpeG5fu2t7ERCO4hkyIIIGdq2kDtRwArcMIA8HOKOec3XmGMa8Sgw/CvMY/1dp1jKIOQgp1NsyjairJtYl6F5Obpxoi6opsNUcGLlaZVgd8Vs5iYSwnimtKfWAqETJlAxJWXwBzDViSsVBAzSTSe6VhDofxSUh891LbYM0LxpQBHKyDumT5DHpV4vlptPG7Xgrq1kjDn7txNeDKT1aqnUMQIBUgb3fcB5K1kbLQQrSXlYUOLlnRlwxkps88V8zzWe7e+RzSMD9Z16qNEhdTa0WBxiasmHDGUEeQ3CFTwWe0TImALkwEQAGr5COp38YhxZH3fPE708D1Y6Wfc/f5sRTBXQJ+8Ec/wn/3V/4iTvutrelL2jkrolunCwC0Vu3ahppwIZ9q9vyKh/3yqGDl6x+cjwG6vs26plRPzxo6gOYZ59MD7t6+Rh42qARsbypqGlCQMYwbHA5X+KnvvkSFChsmnMqM4/Eer169wv5wYKusnHF98wzonkp6BnRPJF3f3DTeIadpwsPDA3a7XRMvjohwe3trJpCbzQa73c68TZ7PZwtLcHV1Jfn4rtvxgaVEB9lM2PMb4Xw+47/8tR+wm91S7PCKIQmmaRJHKoNdoCYivH79GsMw4OrqCvvdAeOwxTxXPDwc8ebtW5wlGDnfrRMPUaWY6ZdeDteNO4ZVUDBLYHPLeWITzo2apsHt4KOEut/oKTBEa3x7BBURcHxTPJdWa7mcSBtG7VFvwvqAj/x8U80CLI8yrpGBjWdUy5dGejkYo/7w7vKswIqLzycIM3sBLTVlaXseAY1N2Sl5mIu+0KiJAeBAZ4kAV/mOwLRxrRmkLtT1u8SmiEk06Moo1mnGPE0glGAayRWlzFpnLduk2mCAPZkwpsgz2UyX2HlRBZWKSbTl8U+1Hm4upEw/DA+QmPiwUwi/JxT3luZvbRRWmDsFYjo/zJkBwB5sAQ8ojjAuasbd9UX3hDXmW8scfNG0GjEBcK0mQe9BwUzCh6E2zwEsQNNg5DGenQINqcWk+E3DdJxJnFZUQk0VlDkotj7cvgufBaNwCAOYi/s4xys5052QkMfsprZUUQhAjQKEZE5tcgBlUUOu44bE7cyZoZx5d4WaU7qDEiQ2l1XhGhGJBlqH080Vud3M0FrbxSTZrECIME1nm1sWDoL47inJMzkAKp177PRmkHvefAbWWjAMfJ97lDhgofOyFtk0ethuwdYrvG4nsShh4ejMzmEG12a1QoZ2jchstD7MMofyPCPLPcIhs7MZiJBCAZVslrxmo0UFeV+bDVDWen/WxLOu+Q7AR69vcXN3xB/8ws/wuISrG9GUVFN0QmJjtwJ+FloukPEnvZlkLzBmunkvaq0oeTbvoY8CuoEDf2vblW/R+nwfb4FhFD7Fdph/ABHKsQa3gGgWZXHCADFBn464e/0FpmnG/cMDrl6egGELyiPOxyNO93f4+KOP2aw8Z6DMqNMZb778Clf7PYbrK2z3W2w3A7716aeX+/icPqj0DOieSDL3/LJxqrt/1XrFDVM3S92QdCOLd93UgYluyKq9S0gNWCqlYJ4KpvMMqkBOrA2slaXF81RQZr7EPg4b5DQIQGQvYNN5Rt4P5s0MgAHBKYA5ZUwqeUD06AmOfxNprEnIXZpXjcFcetVaSoSbN+tpRbgXwdzKt+8oKzyX0lrxK2VrdpegL+tNfdGhmB60dSf+1wSWDWKMwCrS+uuVCKDzmonYs1B+QK92mL6ruWvakoXajtrnXQwu+XuaLZmBnJN4NozPOyC2bw20sWZGY7r1wgFej8ogeZEJQIV7Z0vmgZFN2dx81J8nK69aV6NJspryVQphThKZuZnO1ZTc3T0ldlAhTYdK0PMwNFo4AMFcLbqpTwbSDKwpMZ0I6+tj5RkFo6qZzwB7J6Bk7dNXpYwzmYDGkovfs7SjWd0AACAASURBVAZ0CMIPH/uoqfC80iSjqbQvpYbW0WSLmfPVJQ8VjYTwidJ9ZzQjSJLWI0Fj3bVxzaxxcOZfNUiuUZN+CkCKAhxdG1wnIeXk9E4eh07bmqw8/qDzvqF/TqbxK3JfMSVgVAdg0pxKFefpbEC0JZTXGdvA+fx6gfZ7sxlRa5YztAKJQac6ZzHQKPO2ho06iWOVURj+HO6DUydsA9DcR81IIryQu6HitVkbF7V5cX+LJ53NnSB9NGBveaPZcvJ9rDtwCP2kBT7+4g1++P1v4e2rGwuxsJZ6LWT/fa+Rjs8xQK/i9AlOa6FF7sfXSwGk3N/6X/4BQIT/+l/8sw0QW4BDrnDRlmj+2X/vwiosBD+67ogAyjwvk7oOkP0/U8Im8xrMqEh1AuYz6nzmOZkqTg93eIuEt6+/xLjbYdxsUOaJ9+EyYzqfcDoesdmMAEhen9NTSM8j/USSeYYLzNE0Tbi+vl4AuujhUoHbLJqvKK2KJpXqFlqB2ZBH5DSgUMU8F5zPk7tTTgOoAqWyh8pSKkun9I4fJQOc0zRjt9tjM25ZmyZgVKWlBuiErdegmvFSuN65MeBGfldCeX1lrJjB7hgZSf7dI3fsInhYSxHIrKn1Vr+ijvHi//rQaM1z74ETlw/Gg2v5neUg/Z0QvcjZjyvpIgCNeS4expeTMfOXfoczNfadMprNWCzzPZZ6ye5FMNcAZKedMQ05IRt4bsFcg8b0lxS93yVh+iP803qqmRbLpPbnAWM6+BmPe+WqnFA+dc4aWkp4kGf1000M2siKiZM3AcTaK+E8YS7ohyF4EuSf51LYXK0UM9scxtHKjeBPql6mAC6Rs32m2L/AxCUBO9xlZehbxt6rdbf76jrfA1F7+JFWjhEAXW11MARyzUxcziKEUsbVNKUXFlYLxHx9qTZtyO4gy7QuNmVb7ZuPqW9OBpj6hdKtq2girWOWc7L2J7Rawn7fVbDBtB28+OR3zwpqc7d03IwewL4UCbdzbjV36o1S26xryP4jGwsN7K7a5lpJrEgKaHYX/MPg8xZEqCBrVwILYAYN1yDadBWS6lqN/acIinJGFiAxjiJI7RwNpXesg177m1ICBh9vey4CFQV1KcTkXCudCPvjGcfDbnUsIyCzce3eRw1dTIu8cDAVXy9DuaDhJ8Knb+9lO7i8y7dCNwea+vmS6Wj7Pc+GHsylzHTMInAh2Tt5680Y8yiCw4JUZ2A+A2UCEZsLn4i1xW9ef4n91RV2hysUCa1SSsH5dMLp+ACqW45N9wzonkx6HuknkhR4RVv2Ukobr0Y2Lg0MHgOGA7DDJ+e88DKlZpLjODYeNUk2n3/nf/hd5Jzxn/7rv9Jo/KZpsvrixq6AU4FlDFIevVvudjvsdjvgBJNc812d6nePhAvQ+zsLllQYUgVz5hKZf13S8k85Fk2JxvwvgZs+vIAske+n+PWFw3aR8X3TYweegzr+nBrtzmMl9s/oZ9OaXTpoexAVwdwjQPpRMHkhMd9TW6AmjV1AuQVTq4yQrg9AA3i3rVrUCr2rlZICUf+ncyHnwfrqEcE0f2/WKL/UakyMOjjRPSDOwZTcJXhOgQFuwL7oYhKBKkCpIolWZzAPb6lhoCNh7UZlYgYmJwZREUAqCG9MqcS80ggU0JL1VSamAjOv1hFVJQJqNa2F7hlRQ6TDx+OhggtrFfxOnZZRodf3YpubEU++x5lEH3HaOlBzWnFjXPBEjmhk6P0p/y/gKJ4nJC7SawYNl9ZJYGCT06b5PblWp9m7AoiLGhMNiG1rtSvP5pLkUwsQNpsvDdhQoF9iTLXE2q4qQD2l4I0zjm32cAF9DD+dW0YuciBHlWOr6vmgNLVzM/FsVoc/GMd17X/D1Ld35fKQRRjazo9owm0av8pOXdLAzwxJHRLpZBDaL4ATmdMm1e5mZKyZVfabZRwDM9lsH8Cnn7/G9jzhv/k3f7Prdoy7uA7wIpjzIVjSMIK3eI3iMbPJxpRz5fcehPUa9PjMWlsp/N+RpBFmOagTL6qZrRTY2RXx+FdCSoMAumQObjjQXwGqCDDOHObp9ZefYxYv4IQkGt2C0+kBt7cJ+/0eu932Ufo8pw8rPQO6J5IioAM8XIA5GgnPRbPKaOeu+WPQYTe39Nh0Cui0nnlmm3VkWKiDGHZAAV0fzoDDEWAB6KKG7nA4CKDjIMJUOTg6VUIexZYd4A0SaDZmTcqQAWumSEumTLgd/7IXyoVkEvl+QIicIZI8i4MSQSreJQNvHdhYtOPCXh6bv46flkAlMp7KNHoZJCDoPT2EauG1WsFmnnXhALpIZi3Lud7L9b7rt+SEo0pmfnaxIaExBgc6QKcAwDIHhjyF/F54ar8kn0cAjGElCnevIpOxwpRUFg1znZnjvlVosG8BixKwehyZWR2knthGZe5YA9LGgmOGZTDm1ZjklYmkdebBnzPgrXsUAjiSflPwcBmneHMfRuofOlRj2q1aDWj0tGpBGIM5XwtrcycC6Nrl9TwGpnMSMBgAWWQoEcw7CY2IxpjTpvZuqYvwgN8mA61qgl4zNetLx0EZ+8ZSg6pVELUjfA8vNRVTJai2VcEHAUhSL1JyjWhcMGE/ZY2jCxo0iDpSFkGG7hlOCy07S/nGdGu/pe8W/83uTyYHKoHZ53LViVA1kKhjqOvMzkW4xUuthIEnkXVP3yQCkBNyBUiNxJuylvf3ojbNNeoirKR2rEyoEPa/VnigDmBU+OFrsN/jghjB2x/HGz5feDwKvvvHn+PzT19h2m6AYA4ZwXj8rG3uBRy9EOQSGOm1ZmspWhboDnMJqK2BuhzqiM807y9VzmjOfm+EBwruUgIyr51ExXikIYEBHwgJFaiF96rMHrjnOmOegddffi4Ch4Q0DkDOoFpwPD6gUgHVApa4XTZ/fU4fVnoGdE8kKaCLG5cCOv1Nn3t4eMB+v29i7qSUTAt3dXWF/X5veeZ5xul04pgne9aYabiCaZo49ABVDOAYPNvttnHMcj6fGZSFtpZScDwesd1ucTgccHV1BcCB3v3DPe4f7vHRxx9jt99j/vIrZJHcllr40ItAFb75M6hUz54JREVCOCSkNDpnGXbrFgRSAA/yuanpQqIVYJfag7N/wn5bAREKAN+tF3tHu9aeTvHQjA2g7rMnYxYCg3+pJTG3MejCgBvplcbLisLdHGugawfUNX6oLzI6fb3xub4vC3wVhryRhCsjqxLsyPxQC7LYvE+ZqUBjoTkDq+yVpmR1VtKgycr4skmzlpGzONqQfKylSuL5TzQVyYUJrL12pk5jemVlSCJTYmBVgYDOvJ6uPEeSOi6Qxilzze7bmcEcaYNBTiENjNsOio+zauhm0a7Zb4G2xhRmDyqu95WU0dfxtTFPrFk0Wms7q9UslppDsHCoiFo63UOnaQaHevHxIxlvBbw6DZUG0WpA54pz8nEekU/HRlhgDwg2kjtpynR3exfPwYqMbHM76mBtVJWeMk9TSkgKRjtUaX0IWK1vt4I2fSIJQxvvb2pZrE0i8IVLAeE2P0THS5W9wwLIIRbb8Xg0cKPfHa6uTVjHe7n3Lwa9n+YZVTw8qxntZrNDSu5QKyUOA7TZ+F29WaxJyjy3oDHpavG9xByFlGpOUWIcVj2T7cxJMKczc5kBqBloNjNOJn3GkFXr20ycIOwIZwrkHldNLjjUsSQ278sCptOQmrkYx/fFm3ts5hn/xV//VxvQE3mH6BzE6B4cpvTAbA08aYoesmN5sq0tkoJ0Pyd5/GP7YluSL2p+yYmdAem87zap2EYVOg9CpFjmmhB5SACGhDITMlWA2Ky4UEWZT+ysrVQM2xegvEFBwlyBqQA/+uyPMU1nlHJGHjZIw4DTwx1u385ASnj18iVe3NzgeLxfocpz+hDTM6B7QqlheIDFez0kooZuzQxCNXf9xrwmcVPtHUub3cOcPq9mnGsbupqE6p8xWuKaupQZGozzh5++QMkZ3//8Fv/X1SD1BbDAhYb2u2mb1OgMLmTzjyJW+fbRtHaarBwAzoFFpKDf9PHAVupNfXv0AOrvOHx9EPf18rWMqPEscSwvgLpH2xHzmSbjcWDHH6MEWvKotP6RS/rrbZSBWw6RMEhL6bDew/Ix97XVaIIojCjFURRAZV78YsXCdOnlNFrpb+UfKLbP0XEAVv5dHtx8s1m3xIx2goIW0VaRstOyZ5B47BN7wyH3BIudVdo4YzSXmdexMKZ2t8nWodZDQOcUJZpf+n6kXyUDKVZ2ciCM5KZ5GT6WRhpyhp73BDW9jIDL++qWBYScK4iyy3zCXPGutZPKSNTyze10si+ajctKcK1JmCcp9B8MbvVunDKorn0JTD2cOVXQyHQjVFLauqbOy5NxUCY3pdB+AZ8p5At0iGXZUpK+EhhQQdqVhxxo0mrY5iIWIWBmfMga7BviJIbfRMBHAuBqqRLUnAE9EVDKLOdWCveRuJ54Jw/kMfaaPSKuUQX2iVUxRIRpniwgdJyjHIXEBTwJELPeZHNURodjS2antZqAmimozmGAhTe2BnVM2sloZ3uuyJStrlbOQNicJvz87/0R/t5f+hVQyogTtdXct4CutxTq8/T546uB4z5180nzeM/9OZ4bvEYTXIiorTTPoIt6wpfdWo3tZMsFXxcNH6WjputDHMUhhTu34mSuFoAoo8xnYCBUDCBKSATM0xHT+YjpfALyBKSMeTrjdDoBCTjvtph2G8znaYVYz+lDTM+A7omkqE1Q88jIRKmXNz3MABgTpPmraD7GDd+Tq1SRyIOD10ri5tklaFyWM8Ztmey6uZSZmZHsklO+JFwNzMU4PSQezTLYQ2BOwN1uxG//xR/gX/6dP8DvHSTuSnKmxhh7IjbzMsAAOdQqkFgzoWyaM7NKRARsR+HLd6T/h703e7atu+rDfmOutfc+59x7v0YNqEEIAUJ8akDCCAuTFFRiQoCkXK5U8pKHvOYtf0We8py8Oa5KuVJ2qpw4NLEppyhXxYUBYSE6CyEB+iSEeunTd+9p9l5rzZGH0c651z73XoFdxXfOvHXu3ns1sx1zzvEbY8wxbA/oPy07SkwYkinLEbh7Wlm5gHTJNvKj1/udHOn3bUAsaQVgm1AKCJw35eDMVrLh1ZIcFJ4AgxmsHQfRDWm0P4f1nqMT36O61Nxvhd6cyoSaiiG6VBlHcka5rYFu/fAeUMZVmFo5hxZtSJ/KfYlXSXNGonUKrBclWqUTN2YUJvx3jgEGB0EMqDmPMjqUs4q2u2SbGWE4eTqRAtPeLM6Y4oGlMANbtua45pVZ1xAoMyQ1Hkppzsg2mIdM82hCJm7fJ9KYg4a+8pix1zzml7Vf7rgpoHX0kem00oj+Wf5ZW+W9ykdvyohxohXnSE+sCzp1SMv1uHtQ5jqDOae51CZbAxVYSTVrAqcVhGKF+HqV4yBGv+s9Bw4xH+3UGluzrEwIEAsNoj5XJaB2cQDVrS0cWmtbHwaYg5r8jJoLq/OZI8GIDRkzADNxLBp7bgAQgko2wKXxTD2OIal5pXsx5ehvY95Rde9c/HiBmwECGLejg7+IiRi61LzuhYY9gTrts0UFtXk7tPdtmRX+oJ+9Srdqer62hr7vU5/DJz76Cj7x4z8cxINMBokG0hpi9c6ArjdJtFSOhESALXoZc2WBrJdO1NzP32hQkYTRPKlZsAFrnRecBA1UKCwYM7F05cm4AfB4nz0jwVDVN+TM8QAiBiw2JMvYVSzAMmNZJql1AYjF2+m0v8F82GOe9qi6PiwMTAexiDqcn+Fw2GKeDysjd5/eiOke0N2RdJgmjOOAw3TA48snuDnsMW432Gw3YADzzDjsRbrDBAzjgHG7UUkoY1pmNfeAHLY9P8OiAGteZtzs92Cu2Gy3GDejhis4YKkzhnFQ4CWmS0udxcabq8TnUU3bdjOCSsE0TajLDBCw3W1QCjAvEqJgGAvqMmO7HfHgwQW2GzGRZK745Pu+Bx/44y/iI19+jH/71gfOtACxUYrkM0unddOVE8q+KYgWT5gi2z6DGYN/WWVfe1zl30MWyM4I9QAqb1FrGVt+aVM3KXpTVt7ArA/yhsrdZ78RG2izC+baHq4JyYVRV5+mFQq81gBa/55p0njtHZNIJzC1FoOuASmajrw0ngCLuV5uLmV8o0OZEDw40ONcLwNLDbpDnMci/6wsvEkhMw9OqEw392waJs0QZnRRQGd5EWlMIoacyVDvixWmuQr6Ns2HCy0SEx9zJUyFGqcR2vd1WeBAtEifWiwzbbDnCQNN1TwbFomzp+Pg5lPWBw1dIMrxCgDCWYXL+wLRHhkjmrhVzT8xxT5H0njDHPvIOA9D8XENttDG2cwZDSywmr+VlH+AQgEOFRZ/bE4hYIiEBkJ7mGuWyCEGCSaggl2H8I7hxMYIMwGwksba10arG7RNkRrmOKFNq0LEeoswFFDa8d5O9IRaURftuwT+fJ2hGDb77bRDpoEy2iD/7cBAtRpSbAnTZZ/LBlCrxq6bo63qndRip1Y1ZXYhEYTWypDoZFk8Nt9QZF+x+ZoFEdYvBQYU4IBSPEAf3GQzv7PZbjKe9b6Xs32q9RJnqhqsfQkT7nQ2mWCP6XpWA8CJo5l2P6z+ZASVn+c5QI3SxsXlDc6vbvB7H/lBoFpfNRTk1FvdegC+LrGvUaGhKwaOKTmxKTZuMYekfZK9tS3PZat39thtGszPfs9bnYgFO9kaKUJkm/+sfUDEElyeCGRxKGydU7ALH9eoAxWgcPT+slA4QrGwKJWFhsqAMhAqCszaeCijCBBKAc8ziAbXFDMGXD65xPzwIeoyYV4qlsoYd2eoy4zDPOFmf43tzcaFBffpjZ/uAd0dScuyiCaO5YyBxaArw+DM1DRPuL659sPjrr2DnJMzSd+oQcOnacJChGmecZj2GMogrscLYVn0LJsGYbUFFaSupPWcmwTkrWIaM5ojlcU1dOO4BSjMXiQ4+oShFOx2W3UVLYvxtBvxD/7zH8X/8H/8G7y8nzG/EIwrI7xf2mLbsExcQVwSs5I2r/zcSroV1B09IDcI3T3un0nfj1RrdITHEr/VAD7fpQOVrOS3Xvl8juG47QYSMnKNvA2QrQGzo9KV6W4YoK420Ub2Z1drniTZz3K9T7n8GClumCMH58aopveapjY/KOVrIKiAqphoZW2Ia5GKnu+pAehMA2XPVLa6FA1NIPMBKmGunDRgen4ozvYkYGMMHanXQFZveo3UPJoFsGgEldasX4QpzX1F0Wkc/W/mkhYEeZ7FqVFm4tPgCUuk65edHVIWPYjf6pXGxIAN1wUVCWz5+dNUT/8l7xci1DT2AZ2UBgmqgWZtm8VZg+dhDD6UGWVdg8wczhzVgDOUdOiJhtK1b5h8yjhZFRgTSfod3vYU18L709rK3h7tO3vX54ve9mWEfU20YRKAo3HgrIz0TgBlOP1SyoATXdjL3guUaNBAH4fnSkDo28DcomAHxTRhXlvvRNPEuhdJEsY7m2fWEiaBFuyPrX3WFzCQIdcLDUE9SRADQPZRkh5iA2CqnZLQPYvPbwMytn44VOHo6yOK7GjeSKPRyPoI5U0DR/M7r1h23tfMNllp/MHlNV75d6/in/+XP4X9bts4t3LqbbaF1gFR9A0rLcf6adeIgOYcor1Xzftorml73MPalfvGfv/2B78POZmWtjqQE5Bmlg+21su6ClARUAyuqbNinw5TYxkFGUqK+UIxNhUi1GMDbqzCHZiDKfOIuaBwBYFlzyVgmSbUeQLXWY6gVMYGW9Q6YZ72OOxvcLPdYFlm3Ke7ke4B3Z1JcV7Nzsrtdjt3ZmKOTW5ubnB2duZeJYHkqVIZwxxyQJye3OBw2ONstwMVakw6zYPlv/7ht+H8/LxxpJIDg2+34V7Xzm5M04Tz83N/3jRn+6sr1OkgQjMAgJjnLEvFzVDwu+94Ed/72jX+kghUBtS6YJqkPNsIijouMBNLc2Ut3s+CqTpmx6UvI/XAwa5lY8mWWfHfWaR3IgWoeErqzLyO3ghO46guGZj154NCmpo3W7lnPIf8KUNiZfumhnZnt5ITMMvfvYaWF4cWznMhWu2R5pxCBwzzGY7VujTvGPNgvaVMqJcdHvfsFQZjnkMabPUM5uW43LosYA1eXWuYLxoD4cx+6heXcFv/lCKMZDEAJ3nNS3UTRQIwDGOKN5mBGh+XIeyEO08x+YEBSzOJNi+AbH2vf8FAGiOms0GZfzeDSmNrY1qSZJ6N1tI4cJXQKAaQTFo/z3NoB7X87A10XhbQYsKcxCTbs3bOysY+SpTHVJMhc8Jcyqtsn62OypwiArvb+SzPR9eeWhiFOTsEjERpzq8EmhOmj33tMnRlTKJhJTfTC+tIz6DG0CpQhAOVoARh4l3TwAl8JSGMPc6mdbF+Y4iDEVJmHnYuO8Y4C0WsD62fQMGgM+BnrZkzs90CAZtrog2OJXaZF5QyYBgIYxmBQTTadiYbkOcNNA+loOx2YK5YZjkSsCwzuC4BGBLdGj2jW2d8balCJxJzTLTbs+2TSl+l1tBsIsBiBmdmCijLQ4AwJx2jZ60TMYNNaw+gkP1ONJXX4TYzPV8KVJfmAA8ur/DKH38Bv/YLH8Nn3vs9CbzaEtACKvveWFZwnE+18/H9dSA098ZT5LBLxg80fdWBtxyeom9ffsfzdVDXjV/6bmvvWp/lOhzlvbIJVPujIkHoAZmwTBaTBuLocsEyTyoYEFPMM7VeqrPwUeNI4khlnrBMB1w+fgxmxm58Bv7hPr0h0j2guzMpBwCvHgpg0jgm8zz732az8fACthDmQN1ALFYmYfTAqAhAB8Df++z3vVU8ZyagtyyL52mLOhCL/zzPqwv2NM26eRSoIQsACVS+LAv+yQffjv/5V/4I33rbjJvzcKZiB52lPCkTaWMopUgcraOe+/eXVvbQo7R2be29NdCwmgRxJYBnTgis/+NRYUwD1InUdDiqk5nUGPN/DCgbcS28tECKTfWaK8EpyP3MSP4V09oma7WgQqmsDtL7pm0SXgFa8sk+IBbLirVTXMtQRachw0ArgK4rMkmb7exPA5gN+CjAsaDDSHWJpuZx7oQNxlR33dJI1lXLZMxorqwwWuFhUsBqddDnTF4C7KnHGymKP0uRF8z5iTlHyp7yGtAUcxqgCHpu5Rylowb7lWyqmunYpoyA5tAgwWkhtKvybAsi5ZxkZh9XEh2PRa4zg/wMUKavnrHOfd/0exKOeP297GgzaTUZcp6P+ndJtJkRKF21cj7XuaGBDNRWm600lZnxMLlLnikbECF/pbTllEK6PqkWUZ8NRjuG1dYkA8SMgprOmFfmiK9Yiq8PxtyTtxctDen3ijhbbmaDtv/YuFDadzN4cdKroV00CwgHhdoLKG0okOpzOrTp0Dr7OmxihLSudEsGHlze4P2f/jz++c/9bXxWwVwkW2O69XxtA9Nkc9TGYs0jZAZz2flan/+xYC479on08refgJnxjUcX0Qfd36nUg7VT792Wx22JfKFDWrd1PV8qlnnxkAbjOICgnlXVc/fCcW77cNijXA/YPNjdUuJ9eiOle0B3RxJRBAbPwcGz1s4A3cXFRRNw3ICbAa/eRt1DHuhGZPkZKAOAzWbTSMlMKwig8WKZUw58nu/N86ISqUHLLABm1/oxEX71fd+N/+zPvoKPv/9dzgACwEAFQxn8Lwd0Fft9MVm73TQvM0Ft6jfA21La+j23vJb3Za6Uku4lxvgZECjBvCau1MicsziYD69kDqQbMBAaiKel6J+11sOZiMwo9X3NiZF8nvQsG7XXpWMq8m0DPMYMGrNUVW0Q5mAWHw3eUDOtrBzn3zLj62AO1IxjgMYEEDKo47hvZpZmJkVaHrmr/dCgmbOEaKPWxeoLY/Oydi6ASmYQ5WdcB6IullcGFcZJ5+9+8wjVR6qmqUnA0rV5HZjz85TVYvDR6tzOxetAwbSb9psS3RkD3wKgBIrUF1Qe29DsJIB4opG5HHR0cHpp6MGcanIMGIEa68uYWyZA4LYzOMBPgw4CDaiGVem4sjKUNsYto8tAE/PU6NgAcb+GtPjZ1iYEnZsQKQG5vFpYP8Q6tvhZP8tDymlNDqO06F4y5hoKhhXU2XMWKkWcA92SMgDQzEspGIfBTYp9z7M+svlEBpy1/RCnZMRw2iSSIOuFw/GQNYid2V+vlzW2B+vWBxeXN/jgpz+PX/3Zj+Iz730nynMCmF5L1ptHNuecE4+R+Yx8Jq5/dq0ea/d+4Tc/BQbwv/2nH3kmUPY84Kx//2nAr60rw00zJQPYhwQeX0DLIr8LUIYNaq2YDgdsqGAc5d1hHDAMBfvDhMP+BvPuVoq8T2+gdA/o7kgiKo0WzjRwZkppi6Xd64GUafUsRo6lWGAHDGUEiCS+kjsAEPD1yhdfAxHhT9/zXQ76shllNrsAYjHMpjmW5nnGdrvFMLRaxHmavT3/6vvfjL//qS/jwZNrfHs3wnivYRwwjhYKochCySGRLSp1NUZH0neyoHODApqNzB/JcOU7S2SMNI7N5543BVObmaf1jc7KXOsbYwiMezgNetO7dNzjvRbhto37dJuec1M2plz/5+jgBOQSo8EhLTftWinF/Iu3425e+4RT03uqZRGxOoYhMTqqwTEAaAApejABaq2Xx3qr2TmJMJwqutChKQ1wN6CJBFb1l/Pyft2YUUYIBTIDhuhzA5ZEJFoDY8QsptjKuPSanTSYALMDusrH5ldZ2x7Bn9VTHsHjkHm+bID1NoJomVsHcw5UO60TMxZyRKdltdqsbLZ3G2WuAZ32bnw6ePNyorxiwAx5XHs6Sm1MYNvyjaWNm3mhlwRcL9WFbAxWE8NkV1oGBf95nUciMgSogK1JXfubTjPg2vZ/FopYXy9LVVAXscHEDHMA0aDm9pq1m8ny0fgjlWV9aTRRqgat75p0CkkVIvBA7oyFATH3VOBrggs+EZBeQhAoTRnQytJlswAAIABJREFU9CIDhGYQ2dByvwYrIfkarunB5R4f+PTn8Ss/++P4k/e+02M/rqXe5HLN9PJp2rT8mU0W+/2o3xPW6nRk7ilfnhlo/VXSWjvX+sUIWkLDiJ7V11ywBAm3PxCYxJpoWRbs93uUcYMNJIbhbrvVIzQHTNMB03TP5t+VdD/SdySZmaOZWBpYsmDhGdRlLRwQi+owDKuADoCDMkKKgcPmQhr4yT/8IhiMz777rWCSMw3ikSy8WuUzOsYvCWjLQcA1GGohjJtRTCS1PgZWiQj7sw3+2cfei5/5wy/g4+95q0vwhzIEQGSEcwLrJ+2rUzze6uV2hzy63W8UnP5Hs8Xq99VC0j17JfDOWrFHJUpVG1+Na0d0UjN4/SaOTWvI/0PLvJwUCaN5JjM+bra0lk+jObC6Pn0jvu2ZhuFIne8OAYwenUFPzIPjgp7pNHOvogxrNjNTJtFcYjP8DFcwoqSAMMCDmTiy0q61qybwmE38GEimXgwKV4QuDQYQccnQtk28XBbzvB1ATf+T/jCaDHDA+tuZUQSoWGPa7LvFuYODwtynqS+MFNyEMUCVaeVIna14rQLx+PNH8/JoCJOQIQkojsbZzt7a+NbQFgq9ZjrOX58yN7q5GSsFRXUc/HtHrK8fXve1xUJz1oFtmF+jNYL3P3P1NpECXkZo8gmEogecG0aZ6Dh/wAFdaC2BkIfltYYtC+8DwDwjJoDlxcU+AoiGLqxUTEBpxwiCfm2FNCBajHZ0QFr7jDxAAXR7mqH8vNVf+64QgTYBDrMTE6hQpHC0vxChluinEBkEAMxn8aKuqfgG2EPpKMYgv3txeY1XPv0qfvVnP4pP/+A7EtjuQRUhn8+1e/1afRuoy+l5wFbOK0D9M+w9z5B6zeJfZ56kqC1TUq42G/3bOl8rJD6o0MMyz+IMZbdD5YrtOODsTL5fXV0Jz3e4D1twV9I9oLsriYDr62sJS5AWu176BYRZTDbFPBwOePjwIbbbLcw8otbqAHGjni8BwjzNofGbxGxSGHWAmVAXxjQtmKcF4zhiHDYgFCxLMq1YGEMZsd3ssBm3et4NWOaKuVYMmw3OLs4xbrdunnI4HHA4HHB2doazszN8+t0X+LlP/Dne/Po1vnQ2uGkLWE0+a8V+vxcQCD3AP9Q4R9eZJFK/gWu/tr+PGaZmY3GGtGU+Ii/OP07c0+8JBxoQOJbmNw3Q19TcEojzNyvJTAiJ4K6jo84CE7LpHnfVXuUrNUMvllONDVQYM5A7h49bFq9ZX57edLP58KnUm/9UXgK4dK3I52cch2iYAj+ID3O20faExWYU5s20GX1vaQBnklAFBGOOxFmJa7+UgTN+vDqHnErVNtSOMSIilGVpmGF/xQCdmpbJHPYXxa1iLc5wGldOBPd412scisWTdEY+AJ+vSWoWCtQA7pTM4RgYxjHWrKQBIgVXJqzJghqjLTeJVLwYGkWK+uuvUiIkQmhNya9Bz9xuNuIt2Jj2WiuGygAWHwWfM+xFC7PmAEf/KNWxHRCtN6mTEw2rogy+/GUaxlGi7kvPmFuNfK4ZfTtKzObXLaCTOaPa0m7NIY51yf83cA7SuIMlzGEZmGuY7bdrYoCIUgxARGuMbsXZUGidpd6LW480beaKWqWNwxA0wGxn0yIoPbROy1J9DW37oXjPOGjLw+idb4IAEYSat1cHZawB0gEJ96BAaxgg7xn9rngZjvkYtDuYoyE2zTaUphKoVNo2ZzqoFQ8fX+G9n/oc/sXPfwyf/cF3YjgBrsLEt9VeNprMBLaiuscauBhHPsrDLHn6fPNnn3rgaXtMrzlcMwlda+davfrnb9Ne2p/sExpb10Gd9mO31YsQRTTM4zBiLAV1WTAtk/JDA8bNiAcPH+LswRZnux32Nzd4cnmJ66vL1brcpzdeugd0dyUxN45I1kwV+sU4263nM3T2jgdXZTONDMlbdsCSz01Y6jV7+XqbZ2x6Jl2198RsNCSZubzNZoPXL3b4Vz/ybvzYn/wl/vJtj1IZi5igzTPmaRaTsGIeHatIZC1M8gqGe2oiQoIs7eJOsVizgbTnyf+vSVDocmhqr0b+wUQZw2SmT2t7VdBT29aVB480cBm43dY8YzKfV/IamjJeZQLWNmUyRpS40QTJh3iaC84PFiM2MQ3KKClzLpq4BGTQMgVZam2McVVmlBkJjKX6WhuU1rwbLb++/zpmzJhfCScXDFj0t2gG2LReztonxsjblRj23LdWHyQgY1oEYzw7AIF+vtgfxNteMXM+MGqpKDWdsbXPxORHxeDj6WAKTVFpkMnd4h8DrJYpGxSsGkix6+Ioysar1RalKh19vz0FcDaQn5EawdaedpzBnM67reTKSsSnn0hMt/w2GgtqACIuX9TmlMAoaC7AXKGCitrQSGgyXKKgOMS8zeY5fUT1kHhvczN/zCmWzDsk8BiB4l1TleabCVJQq8wLo00XArbvNLVJQilrSUk0ZHl5cHKL7daNgexfGXislJfWNUr0CkDXsyzGSGOin5v9hB/+g89iGQf8y1/8KXz2ve9A4XBacgrUuMUATqwpzKt/aylr2nrnaH25a+/a82vXCWHiacdJbgOGa2BvDVie0uadArlOPytsgGHutbxKKVg4zIeXecY0HcB1kaMvmxG73RaHwwGX+3tAd1fSPaC7I6nWipllU7MzcnkBskW4d4aSP815ieXHCqKY2WPW5fLsnmQiH2vl9Y5WbPPNm5y9J0EyCUMZMY4bmEe9yqzBetVMrEj7fuf7vws/+UdfwHc/vsGXH2zBEHNPcRs9K4ATU0yRDmeG0NIaMHmmS02b+weFf6JjSe9a4vy1W+XTK8Tt+2YmaIxgiOVPlJXzov6isvDdRmo/M9O1tkU37KQBuxXg4bnke0nqzFiXnq6lNbD2LGY5GQTy0SMBUNY0nA7YLPivMVCZIWYE6NJ2hUdR8+SX8vR802gYvbYDoDW03xzDj5YW15ippj+UUSSWuFyFNDg1jBEpcJfvuZA2wwBzzBovKXn5W3nW0YoBh9zfCfj6PCAD0G0foJtzCoWOqmhd2HRlej9MS5NpWwaa6VweN0rBXkB2LBCJ7yvrA9CaRPe0lp4TgJOvty8aIw5/VnuVuVkTEDokd/xh9Vydp00/tNU7YmwTM23vOjh2KBrzpLJp2xjmLCJ3jL1vZdncMq1dzPfWrN400uHSHundBdB4hd6xWRBjc0ZBnZn2HoE/az8frdZtv5lGOf05MCwpvIAO1bJUP0Nq182ixGmzK0eJOXo+JlOsPxQ5bBXM/e5PfAC/83c+JK8sk/Zd66AsAxNprmnYjwFdv+6srT1rXilzHjmfUyCvF5Dle7H2R57mZTOnfm9YE3g/DeT1AK9/N8YnjxH0/GYayUT3mVS4SuiSQes/Twcc9jcY1FncZhyx3W5wddSb9+mNmu4B3R1JEnA1AN04tkOfNV+9ExL7bmfogJDE5fN4hUpsxrUmqShgm0V2xGJ59oDOgKCd1wuJt5h4Sgy5QUw1qaAysFSWAK3z4sxBrRWv7UZ84l0v4/1f/Ba+8mALMLtDlnmeAGZsx/ZsoG/Oq6nfMp8vrWCDIxDWp9PGhs+auPu0itxeLt36DKVnoJtNgLlbQwskJt+DjiewljM2xprzxnhrrb/z1Et9nUk/YmYpgWT5YFJPfQ2zEkCLkCXvnJhFeBlZIy4mnzEGDbDtULdpA0lvV3Rgj1tm7xSoy0yMawsIINLQC0Uyd8GNcxZSMCs48IDSqW6w9kGFPap9Kbm/LU9Pdl4pzi0xJIi09Xseq4QUnFGN3moBQTYDtG7tsX0DoI0IMg0mMCdjDwDVmUXTIIXpX84bJ5LlHyjr6SuOdTgA6q7DQIWeezPwREc5SBlp3hngcFDCsRYFICENpl5QUMFLxOKTV7p1QDu6YY6b829mShumkSEsSKPZ1D+brVrsMWmFaaGZU3xHwMcmA0KgmrWwezwGIWIOJjCXV1TTSea+OgJ/Wml7Lu9rq0KlDG445kGtEr/OHA1J/+f532kBm3me5o2tD7q22rqy3R/ww3/0Z/jk3/4gfucnP5iqc8uOSDEm0n/HWrw1MGd8wxqv8bSy+nxXtV5ER0DtSKiR8jgCdd17uay+HGvbWrtPAjmvCHRNSmUaPcdGqbQTyy6gtI4CVMZ0mHBzc41xO2LcbjGMA7bbzdFcv09v3HQP6O5IqksFaaTKzWbTgKisTTMNXb9Iua3/isMUAKqhaxnacHXfahYs5XxbSXaYY9pzdl2cnogGzmJMZQDZOHlZFszThF9+5W348Oe/iTftFzweR/V0Jlq6UuR80GYcAbAv9CfT2t6bmE1tsPXO0bPGmzRMGp18POV5XI8edjYmlE/BgO27J9pLmmvD7AYT1PHeDlIsGHhzBi494t+prz8az5btzafD2jW6XPt9ysQn5xNMpF5L/0f9yG8Sh3t+o0czy/S3EngyZrkuBvCOTXWCFjPT2TLV8qmS6lzXhvHRu36+B2mORp1v65usUXcmJWlVvPwE5jxIuGmw8rrAoQnKzE3GJMYYA63mxs3NKMrJwgQvZ4mYVWUkuP8/AyacAa2UbJqgTPNB2uRrWdBya0qZgYWBijzbj7r36WitSU+dA1pPMk2baYcrK1MoHvKOKZrba8asIkPKNM5eTuIu9bvPndTPJm3IfecMNbrxcOdYVk7bA9bfRBH3MYcwiL2E/b6cZY138/lgGdc8EPGeqcmlSR0wy/3X019yNIb0DBFhpHAQ5LTvoDk+G62f0ZfXm5z+vb3Wv3YuNa+HRL5OxHi37doeJrz/j/4Mn/zJD+ETP/WjgAp5vbxbkq2Zgmnpqc/n957l2VOAqA910Gvo1oDYr/2dDzqYXNOw9WUCwQf1zxz3wdM1dI32T/dxAswIYD1vXVjdEkFqJWd3ywgQY5kn7G+usd1tFegD4zjEsZT79IZP94DujqTDdMC2LM01A3DzPOPJkyfYbDY4OzsLU7P0N46jBxzP0rUmECibdFMcQYgnsQGbzVYKJAtKXTEMEkpgu91htzvDbrdDrRX7/QH7vXhlOj+/AEAeuNzunZ2d4+zsHLvdGealYp5mXF1dO5C7ubmRvPRzHAb83jtfwvd++xqXD3ZYagRf3m7PcH52pmYLenYPeWFt5HRN/x3p8YyBcSn7SuK0kXY5mHfAvtRTmd0OcaIOLoH1PSRvCuuLvWsdLFBwV1S/8Zmb8l56nV44ybsSrQAf/QTg5m1DiyxbKXjOa6WOa7/7OqzfpxWmm5wdym01poaZ1ayQ9XzmoFoMYY7NqYUJNKCOT4JpZu9TcbdvYMNMDaVrTExi4RA8tl1iIEzLsCxVmegwJxNteAT1jdYF82AtrM7cVjFZc/NqMq7YeHbV0Mkz5gwFYNSFfe5Z/YxpFcGOgD8DA4aqCMnciWNtymMyDIMDA3fmtGhIEnVgU7kCC7DwEgBC3w8vo2LeB4LHySQiUDJZZEOugFoHLMkjqgGgDPiFXsRtfpXnTVPLjBMz5nRKINRhhAGSQir0J5OvJOFEBg/mvCQY5KzlJITHUAM2ks+i71KMPcjpvXL1WhHaPL1s1fba3mFx1XLzqRQM1FqBCDmoMxQNFr4ss7fN76kAI/AXYbMZNZ/q/SH7kwEK64fAbRlUppo1zZE2LyD1mkkkQey5djFavW4BfmWtEPDl7nM6UHKUCjCWESYrIKIQsiqArKyhPbS/RRMuTnTSQDRr525e8IE/fhW/89FX8Im//QHwNPl5e5ub1ifZiqDXVtk4rKUs0DFLnP5ev57nvPu1Pf/5Wtfdb+sm6ZsvPtARiHU/52PflzkE0hmIGd/TC5z75460cSt9UagAI4EW8UK8VG5WAaMbi3gDrpinCfNSsTm/0PnHOEwTploxbGQ/2R92qFU9gv8Vwxndp7856R7Q3ZG0LAtooCNN1jAMqLXi+voawzBgt9s1i3YORJ4lTL55NYyOMJRilkn6fYPNZot//Pc+lhbm4uffNpstNpstttudBAVnYJokFt52u4MBOuYZ0zRjWaqDuc1mi6XuMc8L9jd7DEWcoUzThMPhgKvLSwzDgIvzc/zfH343/qd/9gl85aULPHaLMcJmu/HNHmRaJWOV1zWLK1DuO0rk/+nvhqdpgWTDEz2PSB/BKAQjtpZrXxm5X0s9OrAtpju2AUpn2iZnHgfXathIudO1LK13AKrmeVkqbp4ETQoO4AiMNHmnTb203Mwq2Os3Znd0wOz8sgH2YAKCYTZveIKWSM+JLaAi4bdKzlPLKcOAgXI8SDgoLAb8jkzDZCwX9zZojLrUj7VSwUSKgw4GRHJbSgw1AaUWHTe5aBqvI+YUqnlAAaGqcxIoEypATMYDQIEHHg5GL7x7OjBXAqBS5BwrwgEMs5kZdcwwka9LzOq0xnCDAsGmD0yDqYCjLkmqXwqyq/VshndYFh+vBqK58EGBWmUUqs6MA4KvBDJlkL84qHNzwmOyNeqIcUV8pf4+mZBDwYfOSYupBkBdnad5n4RvIlzQuVdMeMHelkG911oIANeIKFq0uShrtABFo58ylAQ5kwZKmXkT5DAiX4K8Z5pgAW1mMinAW7ylDliWGfO8gCjOfocw0klFhYg2DwKoyR4XpAiQ5kMIUltjxuHAMNaYOJtufZsHL+99YD0CYUI3Fa7AabDEetUJWoahIFfJxsiQqN3Kni5FqBFtkTkdDmfOpgU/8pkv4Ld/7H34+EffD1LP1Tn2bD6ikdfJ/FvmTrvO9v2X12373YdNyu8aYM3J+JK11FsaPE37l/eH/t16yEdG2jb1wuzeXNOe68FdD2pt/Aisc6ECSw1BExHczhIM1Ip53mOqjLMHj7AsFfMyY5pnzLq27Pc3mOZJ5yM16919emOne0B3R5IwP+Ed8pTJZd5Q8iKbnaHY4pW9X9LKZmQLXnam0i9m2ewk14eIPERCXgwF9DEuLy8BEA7TAYeDHNjebDbNAjsMA7abDXabLYbtBr/+oXfhpz71Rfx/73pJTF5SHLuhFI3fY8xAJ1l+rkSuwzm+JczU82R9DLvWwhPc8pIxN4krpBVmsU/ZDCo/bLyCARmHvn2+tkEe5YujZ/rr/r1jVOJyKxnOgKw3c2lMXICj36fbrhtrBrRRsaPa1hpABICfbSkGVOUh9zYo57iqBbpqAEXwB6p9cQAWQChrBO2igWP4XGKAFmXSY/41c64AAyemyRl+DhBrY+toFOqN0JgUBXIKCMx7JjA7NFncFT0S0EpMjfYTZfO3Y3ISIFl6KUOAWQcOeqtyBZsnTxaAGNqjMEUzAGGpd8rk61BXMa4pmPQJuuKGgDKd8PGDlHVnRou2aBiIskZ36xRZP1h719cJIxH5a80UM2JQElAzyNz2BMjtioV56LU0eV3QMYh6pGfT9ezKPp7r9yWOAnJvuQOVdi+TMCsFQM/gtmuJvRuCCKDtZNXidmO5nGScDUAyiCREgtGaCStMeCF9zk4H1i1k/7nwgnx9rvYut6NjYJsRwhVAg5mXAtSKzWHGh//kC/itj/wQfuujr6AkoNq0oPu9rjUT4N/Mjby+J0HNbZq4/Ls//nFbWtOU5euWfuIP/xwA8NsffM+t+fV52u9TIC+36dQzmU+y8B/GbgDoHHCtCBNMpGhrB+kxERGLoNYZdRHasP1onu/j0N2VdA/o7kgSz1ilAXSWbIME0Cw4gMR2Y+ZVQGfORRxIpTADdt+keyIljdh2PXisNZhsyz8DNKvn4XBAKQVXV1cilZpn30ilnNB2jMOA3XaL7XaLzTjit973TvzcJ1/FC9cHPLnYePwfYbxNCLbCJD1rIpy0gW8ee2reKxCoY3pW8NpTstKNtmP+nvbe8ca0VhoHM9FLZIEIU9BUpwN7t23WCaBYtZ2V64QBPUPQb+r9Zn8ysQTj9uY1pR/XhBmovPj5H9E6CRMaDCu71pGg3k2ZUDjObsrzjPQK7OxTlE4OnKJ+Rhg6f6n1JsvKhLJEtAJxAipNkGI7J6YmisY3IBhJyw9Jm2jnB2H8OospWtaWmHMKqZ+e1ZUqJ8YtgMvqoADO2PeCDWdgE5gz5tg0IIWKe7Q1YGfS756RLT2g8zw7LCncuns8TFUFEtU7OOL2z0BBylBBXRQUbHIuueuj7qczl0e35AolWoG1L4NWMm2pfnr/K2TgYEBt/afSArZcOT/Kk3CmjH8Bio0VFKSoyTJXB1TDoOAMGnpG7+UlJ0BFcccmYoWyoFZywJG7myg+M8A1MOftTc+3Y5gFGPkMVQLe2qsWysIFK0ygTqsF7Wu3jHAhBSKMipMZx5RJjXCAYe/78iBPlsr4vi9+DW/55uv4Nx/5IfzmR18Rb7Z+FjGe74VAlnqrh4ZKV9bX28BcLs8+jwQpK2DpWQR1fVk/8IWvARBAdxtY7PeJtd/571nAXA6fI6EH2PcXpvhMO1xuSSwgkPXUQJ3dr8uCpcieYo6n5mk6qs99emOme0B3R9K8iDvmHtD1JhC2SGdQNk1T8/ya2YAFFjdtHDPEI6Wep/vZX/89gIBf++kPYZ7lxMCgpjPMwKwmAgYSDaRN0+wb8zyL2eW4GXF1dQ2+vFKGl3B2piaYy4LDYcIyV2zGEbvtGXa7LTabDQ5Dwf/6E+/Gf/fxV/Hxd7+M6fwcwzg4MxPb9jOgsqemDDuelmJRP/3O6byOSzrxrDIzSe57axkn+LJVQJpNhk7mHJx9/FbuqClLr53Em4m5zq6rn6Z1k1dvf6bRwvT1SikYuW4+1GBWSIOGxzshXRWAEKY64erbNn+ol0vjmjl1vGpgFNAEqx1Sbfj8lE3d62GghaL/iMiJqGmXKxwMzMl3Zy6TRrIaiHVJtTwkDHTELLNmmOknEVoHERwU6veO4EgGFqlvOWLbkd3PtKbvem8lhrmjAgEdblKl548Sc9nMoUQz+aSoS9NTtnlmOBvm0yIBMJsbWZqgpGBYnpnD+dApujZUYaAFUA1ay5Da2Fm9jadk9fwYtB11rUhz1PslaFIca7YAxICOt1dpvSBiC2YNHCuylD0gBaZnm19B8y1zXsFcfFSasQV33dXRl9FoGu/+fl515ZnibcvmhHFfOtTMGOXYQRs2AQ09B/0AcHDna0gSAhSiRkPsa4CBjA5oDLXilU+/inkc8Ms/+xP47HvekcBZqxU9BcDWXP1bGT2w6ftwTbtn1zNwPAaMt6enre1PFeJ9h/mtgbqch6/3KyCVGGmU9R3YWmq0mCiBDMAxwAvAyruoF8xaFzXIqGrezZinew3dXUn3gO6OpOkwgVm0Zbvdzp2hZIlYKQWbzcbfYWZcX1/jyZMnePOb37x6CLiUgu12i4cPH+L87ByDbrriaOUSpcgZvRe/9dgXbNOy7XZn2G63KKVgv99jmibs9wdYINjLyyvc3Nw4SLy8vJI6l4Lr62vs9wdst3L+7uJi0LpPmKYZh2nCowcP8fDRQ5zvdhjHEYebG/z+O1/C//utK/zo16/wxbe9VRZPZQYJcPM4aSCOkcnTEqWNfu1lW5ehC3liNJtsTuZ/4rLzqCubljNz1Py2BjZal5V3+/fEm2neIG1jQ4CtxGyaUxbrmQYsdUwsa0bNpufVjby8eol+47EW3K1tzKc2a9cSJ1DSptDkiEMEjvModk4NYc4HBKjI2iNn2sEaO9HmlPWr5OR1aABXdQrr2+xab5JzZnVWgFNaSbQw7eQBne2aCVUyX9IzX9nELOdn6hrWw/hI41AaZiY0+aXYGaBgWh08+vPR0spidh1nCyWZybgzua4t4jiTl55tRpTjrKGd1SMiX2uoMBhFHUtQmhNBe60mIZjv6EQDIOzu7Ql5rNlpi4CYO9q7ebiF+WewOYhJYAo2Gkl4Yh+SLzrG3zSVq5SOZRFHDTUJKgzURxzB0DyId1dWMKhmxa5hTsIAq9cih9iKBRdnctNcmRdoaIa0X0j7M4+XzJfQSptJG0Awh1dZY9x6fczdFfNP8qzduxloDo7DbE0QgeQMZvheK/0D1RQyxrFgsxnjeIKW4WiSGdG7seQtC6MG2gbAqKWgqIbY5tkwDKH3s7WqVpSl4pXPfgGff8db8at/96MomxGbpB1nrpjnNjC4nLsPpy8xd0vT39b+DOjympTniO3pZrFzm2YuxvJ2kJi/Z0uMI0BK7XOn0ppzuL7MBkCnNvdr0boDGaRFT2gu6J19LzVKlNVAtHIERl1mwM6rEqMQY5kPAKsHcNaxn+81dHcl3QO6O5LyAd4+9IAtSDmouJlWTtOEaZqac3d5YRoGAVLbrWjBjCsw5yvutEI3+Owdqz/IPulhbHPUcnV1haurK49/N89zs8gC7OVnkGnS5M0mPHPKYXTGUAr+8D1vxU9//k9w89oVXnv5AZZlAtfFGdCnCOZuT2nRXwNIwXJh/blnLDuDRU4M/xE4OwHmWrAZ8KCvcUMnfR4ttlKm8fmkoFF6fGaNw1F3dJLsk3k+hzS2YQ4olUp2zi1qmvlkRmiFuOY4V6SaChwB177TjJZbTV7br3ZNXq0eh61hSFkhmjIEoATW8nh5MxNK8jaxO0ARZuKUSVEGnh0tMzf03IspPL8ODMmzxqxk4NH3vXg2JCooGLwdXEVjJOC1hDMBZvFwadpEGPC2NcnSgFIYbL7D/Z5qmBhglZTneUBpzHuAbX111HbKThXk3qqJWtNzMYZRhg0G5aKPer/R4GUAaMzjqTdZz4V259W82HTe0Dzp5bG3saGuci19qDnfQCvP63j49wC9UW4ICfK16KNjT5nRdqll2/Z+3DJQyQ6YbK4VP/cq95cEcvK+OsBMjmP/SnXnWAty4e1K14JKfyY79DJQZ3MAAEoBYwEfJnzwT7+Iz73tzfiln/4wiCu2iP0faM+QWtuBCPNgljprAOo2k8P8bOYfeqB0pMG6BXStgbo10HX0Hk7vc31d+nSqrgbkniUwuueFNNR5+dB5yUBHAG2+tVZIBBLiWjMCAAAgAElEQVSzdAC4LmClx1JK+Ey6T3ci3QO6O5L87EpnmmILkQGf8C4WHi5rrdhutw2oy6AsX7fnjxyiZOky4nvebA3QbTYb1Frx5MkT7Pd7cW6iDlLOzs5wsz+glBG7XcH5+QXOz8+9bDs/N4wDtrudgL1SwIsw3pvNBlfvfIT/6++9iP/ql/8tUN+Crz3aiHMXgnuHMxbz+To5M8zr7zLQhETg9qVnSquaP3uf4xk3TcvM+23vH1U2A6t+84SytsZ0dYyQAhcDM3kTXdtQV8sGRFNhl7p7PeNmn0/blI+LytybMu6MjuG3mstDx2CdPGCw81vGpEVlFC92deoYNGfEKT8aHv9qXQBSByqK0hw0Ju+gzvix1TlLvY0JjbaYmVvl6mfcvM7Ia4YNQbqjwDGum7YyYQ5loDP+CU1mC7C8p63u3pfsQIioREB3e5lSjK8yOKATZxT6PvRsIEULsoaCF7lh3gMNGNu/7JjCGnI7nR1L8n1UG5AQ/eIVzNctrwQ+joOBUCwyqTOb9WwVPCbtk1/TOawDLt1LTteVQ4dEHPPUQG5jztv1R7Rf4gW6hm7leRfS8ezrjvSprT3kc0XGYWj6JN7XVpnQhcJjZL+GCZ1XMFMD5kJD1LaDSEMYVNGytNos09ARhiHCakzTAWY142taZB5100oZsEyOWL19C5vJXUUhwjCOoRUHMCyM93/2i/jc296Ef/pTHwLPEwaufu6835efZd3sNWEBcCIfe25N65bvnbrWg7RTGrrvND0NMD6LYDDXt9daAu3eZJ9ZKH28TwstijbahINJkKBlik1+LBlErOb1jDIQhiLHSTbjPZt/V9L9SN+RVJkbb5OALApmdtkDugy2AGC73R4FFmfmI4+Z2Z14E4wcJpGKvC28gJx7O2C/32NZFjcHvbm5wbIsfjbv7Ezi1V1d7zXfLc7Pz3F+fo79fq+mLuIOexzEtHQcRxQAU10k7txmgwcPLvDayxv82n/zU/i5f/KvMb3tBXz14QZlHDW+Vislff7EPTuWbwWjC6DhxU6+dHtqtHIJ/fSahO6l1bqtXTwFAAkGuCyOmhVM6/1H1JpVrmh4josPjcLxrXaj701jMlPwtNRomwy0RMVbiX3bKNluCQ7oTAvh9bE6JAYrwC5ukcIG52ZMpsQxq3DzPSTGW9vhJ4dMK2HMOh1nnZkMA3Pefx3nyNYurIBmy69DwV7+UeHR1CPArj8IEK+gfolRtR+s7pTyEj5d+7gUd7lveRSrd0mFJcZc8LBAPgawG+x87Rr9BJBbY0otv+aN9GxYQnTvd9oZmyvC4NlXA3X2F/M8QFvqSOP6uBnN9r71K2J+Bk3BPxtwzQHCS4k1z+iBkjmkzyvAjvJ6e2sGS7kpCPqsGgMRiPh4Ni+j60nBlM0Xqa8BLWtrCBbie4A57QPODkxCu9eW1w5ZFpBGqIToa7tudRHT3xYE6YPaj1GAjwNXMJXmXGk21yQA1cz/hkHAHQMf+JPP43NvfzP+6d/5EGZewLPUNXuptn5+HuuGPhUfF165vp6eBeQ9y3urWu4Twj2j01vbmurxNC1hXxfTwPfguAV1Yb1kZGjjTkSdx8t2nhPZWq9xc02YoY6CSiGM4wAqBWMX9uE+vXHTPaC7I4krHwGy7BHSAF1zFkIXIzNrzHbwJmU0s8llWUAgdVwyeZ4GxqASJSvPgJyZUU7ThOvray9zWRbs93s35dztdri4uMDFxQW++rVvYLvdYrfbYadauOvra0zThHme/ZygnV+o84x5msFcsd1tJZA4AV/5rhfwL37xx/AL/+zj+PL73gzm4TvBU3+1cdH/n1lrBoCf5flTPOjzJkbndcuy6jMz0BBA7Yjz8ZdbwEcnnvUtrNFgrDHOQa+ZqZLHTzd6VXJqvxOjv94ESiBCXDpk8xtrAccLLjGXO9oHFE064hk6Br1hAiDaA9Dg5Xj9U1ynZZHYgFTKKs24BtGBV2aoyIeqB8zHQFXqKyY+hHWNB6v2M75bowNfhcQ6tEb6S5lqotKcyYMxM/rpwFpp0bRrdr9QcS2SlZpjxFmg8M1mo6y+njcEuXfQPEg9A3rK5CqDuXCOEXTqfeC0184lSrTSgJAjwOw9FgyiZcztk6wIS/o6hZ4AZOKvMrIGjnI+li/5+95m60XTKqxk5/PWzFvR0o3RIRFpHDoBDpT6JYMzAz8BUHK59k4GdAEArT2hZVkHBTYfLQ87UypaOXnGHHzZPjkMxeOemqdOOauZhAOp76KL0tpm9SDrpJjzYBYTTIjzk/d8+Zv4rtee4PWHF/iln/lb4HkCz6FdNUBnfVz1/OLzOCTJAjRz+NKvrcf91nrWfl4Q+azr+lq+33zhwXOV9Sx16YFj1lj2degFj11uMBp2i4CVJ9RAFsCga5rSTpX3CgmtFf27T3cj3QO6O5LmeWpAjgG1b3zjG6i1OjAyL5j7/R6mgTPNWGaWTatmpphmLrnf73F9fY1lWVyrN02TA8DHjx/jcDjg8vJSvWAWr0v2pGmOC1566SU8fPgQjx498vN2FgD9/PwcwzCCWYKPX1/foNYqzz985HU+HA64vr7CWAgPH1xgt9thng7Y39zgTx+OuNwN+N6vXeJr3z0A41+HNCubRR3d6kIb6IasF8PArd3M+5SvHb1zC3A7wil8xOq0+ffPGlgyJjpLDtfKAgBlVs1BimvmlHkxibQ9axJpcOsYwMFiYnb6oLTZW6sxKpk5Wdt4m+Ti9tyA+NH0Oml/DdwwpcaIAuQBfcWkTOvkTiZycGEz/wptQk11a+AvQ7VVDFoWMKgpu1q/mDmzMQeUzqxo37b9bhLi8Hgn3RlaDg+o3PYajBd28yEytiPab1w3g7HMMyoljS3YncT4gFs/dmO03W7QImEo02JjgmByYTRrfSyBqy34tY/uTAAWL5vU5Jy0HGfSE+PdO3pomfB2ToTmRkK0SOyx2gjQXHGok5SA5rxb9GsIDDriaH4qJPRywQyuHH2UXrCzkwaaoOaMVh/TqsXYJzANY2BLtJvTue0E01lp24bUwiEIiK6gSlqXBf15M5vTbaDr1sSvXwvsT85Z5+e7hQ1WL5vrUgfr+35cba6JYMUEDbbuSM8zs3pvnjHPIRjdbLYYBqMFsWihmkEmoRJhGPuz7vEl0y4zi/XJtMCAwDu/+Rjf+83H+PJLD/EP/5Mfw9ff9XagFNBCLowC0FjT2PrT0zQA9zTtPbYi4Mnzol9X89rTA5pTwCeX06dT2rn8fAaNWXjyL//jH7GXoh+fAVCuCrVuqXMvZDx+Ps/luOT0VuAAzeU6vkaLwAIk4VUGEvnLNE8qtGHfe8J50X16o6d7QHdH0qJSNwNztjiLxzhSxyHk4MoW2OwsxUBW3jTDgxf7Rmzgjogc5H3qbS9immfc3FyjVm6crZhm8OzsDNkL5nYrJpWmmTMTTQF/xZkiM7WUcAjAOIqTFgJhUe3cPM/Y7LbOCLAybNc84x/8zPfjv/2NV/GRT30Ff/mOl7Df2bRgLGPB1YPts3VyA9ZWFut8C2gF3adxUZv6/QCJiTYtRJ8R9S/2t1cClVPcO3qb4s+82GXGylEjRUPF+/66yWUD6tIGa6DOGVTdydY28yzBtmvyzvGGna+ZJsc5MgcVwZj2+LvpiBRWIDOfVl9Sd+bugc6hPqd3gGGw9yzPDsdkhj4zsE1PtDQX/UauAXCgrEDJQDU1z6f82eZ7AnNesQCXlkPDpCk9DkOnUWPGwonRWhLjnMr3FiUQQxCzNe/BbpydfsDutCMDkGPNh/VzrIniGr+KMikx2QYI23xaWox7ce2IuW2+tXVqx6AVDDUaJRc8ZLqlJv+slYz+4TS3rQ9s/tgv7/n4lkBArl/OiQhippvoJwur7BqbEMvnuAA9Ow9Zk2bNGVkSzZx5UV7T0BhtHjPQWWPvTzfj0pbHXb79Ws6p+wOgGpjL2m1x8GVrEvRIwKzP6Sg5gNb8dA0fuOKl64MA/QQSzIutjVZdFrznq6/hbJYYZADh8cUO/8svfAzfeHQBHgrOCLHeJmFEBh5yXeL9tUAy6LlfT3vaDtNYHOVhKXuEjD5u44M+r8Yu52OfGWj6Wg80v58JyKXdMX+P+3GvNnT3NEDabi4qBmhzTftkLkumvGhri44bdaE/5C+caN2nN366B3R3JPlGkP6IxESy93qZg4gbwMsbSt4IDPDlBWyeJ5f8Cbhb8GvvfllCE1zfuLtiZpGcnp+fY7vd4oUXHuFwmPD48etgFhPR8/MznJ2JZnG/3+PJkycYx8Elissyq7OIBbWK+eY4FDkIzKIJsPqYNCtLbqdpws35iH/4X3wA7/r2DX76E1/Eg8uDI7OXv3WFywc73JyNwtgUwjfefAH+Du3Sqfveu+H/q6bTWrqeKekYURB6vsUYQoAUt3Bzr5ceh/v04xKOeSLZeILptPIMdFR/Bg4GETjRyuI2v1Ob521SXhsHhSQAUzC4R+DqeHO1FIxRMvlTINAAGgdzMl+Wpbrr+Njn2Zm73N9USLQYzBInLmMKAsybaw88hjIARaS1FcZsB9OQAUEMUdQxnyPKrVco3/S/SZitvqOe5TFyqomJXEoKLm5aPAQ9hAPHAPzlKGyGj2jUzOqqgMfCGJg2icEw3yjWLtFCjM687lXYFYC8XTvbfmo1wflefsZAjP1FvWXgI9sQyySoD6NSpwkIE0g6R0lfyHirAYyOmo+qisxgyjjlumS6J6VHwFhQZrgG2p6ytrarAhzM1QQgDfyBjT6ycIRcM1eSsNFAkwNRpwkDLlBaKalfMxZOINbHpwWrOW9J68wx6dyz8AQAvM4A3JmRnTEvpeAt+wkvHybxTgiZz5wWm3c8ucH1boPrsy2MPpzmE3EwV3zye96CX/qR70fZRGiiUgqGXksEaSCh1aQF/bYC3WhfJ0jjVNdYphpwuPaX+YY10NWnU4DotrSmEVsTADxTXj7duJkBrPd0JXfr5DiD3NZ7df852pOhfcmJru1ZLwnNXLK+RVE6IlQWJzmmce/DtNynN266B3R3JA1FvFGOw+het0oRU6jNuMHZ2Tm2G9FqDfqMSRqZI6aPaL0WzNPs+Zr5kizWS/qruLx84gurnJ+rKIWw3Y4ANnjhhUfupdJMN8UxisSps1g9zKK5u7q6TNJNZQyWBfN8wDAUbDdbbLcbjKOYs+z3N3pOTzcqlaAepglPLi9xOBywGWTj/epbH+H//Pn3YxgKBqogVDy43OPDn/wSipoqvfStG7zvj7+KqwvZZF97+RyPXzqPjqbYaY80ZXLZvzQMXeMpYAVstS/DsEY8vrZhZZbQfms5x/uIX/OaGchCbGyU3+B472jDpGNJpis0yHfCpgbRA9ww8+ybGRxceY94BeASZhjYTDTSMEJeUBohb58BWx2TFPDbmXEO9955DI2xjfZS9J/eI2bV/mStCNwBA1i0zq2kN8CQPN+C9lwHAz25V1mZ5JLH3fhGqVR6J8W+Q2ZEgkmOwnv6YlhYedL2m8fJok5cvKtrcQBoQqIyZNDizW5bZ+PAcc0EDQZSMy2DJDC5Cwy87QlcKZjLcc0AAqnDqDbWWZvknFaruWy0lPpXzEGLDIa93ABfDTDWttdovcdhSp4tNhP6sSnWtDkNWYxaVfoW7tGFKzqHBgLIvDxCqi1CGOvaBDHpqCaxSCVpTqbrtBQmUMctkNS+kT1LBXkwgGZzM2vWQitnMosAcFDwwGCmjpYzuFthtNGuI0eaWqchAnHFD3zzdTyY5hT/UWiFFagSgLdf3eDffN/bMYxD0kqaIAv4zHe/jF9/5XtRNqOf+wQlz6LK9VcVag6lYBhHF3hCBRGAWOiwhvMxUAdAz9Za2yqWhd2xGDP7/MUwpGnueiAff1JhjIxj9f41YZa50oeCFdtLMoD1tcvXRv0zx0jMLvihZDFkY2Ceufsx6r//17/yGwAz/vEvfOxojO1ZAFi0hRVA1XWGKaCVey2h+LQYk3VJ5y9NIGS+BNQZDnMV7ZsJPliM1EMkouDO+1xNyEFgFFgYDDsPKQKMAWb6zJU0s+8MzN6nv3npHtDdkbTZbLDdiMmheYArZdCg3Bd46cWXdCMYsFHgNwyilaq1Yp7E2yQXws3NHofDJBurehyzBdVAmx36fv31b2OeF7yHR5RC+PoL5yiF8PDhQ2y3W7z88svYbLa4ublWT5c32O+vcX5+gRdffAGlEJZFPF7e3Fzj+voau90OwgWIi+ZKjMN+j/PzMzx48BC73RbDULDMszhaqQu2243HqxvGETf7G3zt61/HOBDOX3gkHi5V0gbA0cflwy1+4z96N0xDUirjBz7zdWzmBcPC+InfeBX7sxG2PV0+3OEv3vXiLRLBACKttNVYr9sWXwMHjGY/SXGoHKs0saky400BxLpq9RCMcnnWwgySUkameUp7vre1Yb4yAwFuYoJFDWW3L6TgglL9GKi8aHy4YLCKMcUlzm0Jg2EAKiTrptfIPeO1TfVgY5idUWE/azQvst03AY+pAFS9bO8Htq3Y+HndxFk6x7TGud+EgbZAzVZx8rrIAQnLPw03Jc2OMhaVWczVMCrTTNrLwiyBSFyhwyTlWocUAyyb+7UajA74cfSr/RUCBndJTx4ry8BcXSrKUIKh0/wFPCjISEhkniOmpt1zrXtiuochXLc3YEOfqRynCMOcMrQ5xBxMOqxPqreRwW4+bprZrN0wIIekUWKWsAl2PjK8lUq/ZPMq62YDANYrBlwctLGshczyPqn1gtEunPmWczUGaEVGZ2gKfuZGmHBhCpfKIGgcOgfOaXS7dc7nNaMxC2QtRhjdvKIYmGq1ZAwDcqYVHUITkTSkrdbYxggOjkzTFyaV1n8A87BC10j309lTBR5cF7x4mPGR1y4xBPXASBcAxloxl4J/8cp72n2AxSRvnmfUZcGnXrrAN976Mh48fIBp2nvdjBZrXbDMB9TDjQOj7W7r/TKQeDEcaMTAco7Ujk4sCh4H7b/DNGtoHptXQCXCNu3dokFUoSuFZn8YBoxDUSdGpuGW5OMziDOUqgJWd7CDimrri82jBL6h89Zi5w1EPn6Lzell8bWvkHhvBBUcDgeYBZE5Vtvv9z7vtls5KpGtk3pN2W1ayAlidl29toTq61BGpba3iUkwa4gNEZhILLiBCkAFXCuozJhpAS+Lz4fCAhoLSdCN6CF2uqlMCuoGoEAB+CxxdFHARHp8ZQQ5NCwYxg3u091I94DujqTd7sw1b+aAxM6vmTfKWPR0oWNgu92p4xFxLmLhBMxL5dXlFfY3ez3EztjfXOP6+srPyC3LjDe96WX897/7ZVAp+Ee/+D7s93s/qH5+fi7udYnx5Ilo88wb2DCI8xU7k3d1dYlaZ+x2jzAMBOYF0zTjcJgwDISzsx3OzrYgYhymPa6fXOL65hpnuy0ePXyIBw8uAADXNzeYpllAwzBouALbmtXZBC8oFIyUL6yF8Jn3vcUX/ld/4M144fHeHsLf+s1X8aFPfgmsYrbHj87w1bc9wqyeppYC1IF8P/Okl0zrxnrNk19v0VjP8DYS+R61qST56OYRujud1vKXuqq01oCXoDa9rzpG2ywVKfWOFho9pO2XefO0+F/OGIR2JjP8sTEnhp9rtNNAUdOu7psytZUZs9KfMzIUTjgENDGYZ5GCAwAWZwQDhBsfk7QTHK02yXI2V2JnmNmBIRvjr/caWNoBZyhYYwhzhHlRYFpd8m2awWraltSHxbUL2v8dQbaaEAMoxgTD4zoWEnOgaBck2HGWTicQ3CBrMvAZlwQkoWG+vI+NaWegqjaDUcGLtSCdF1VAbUyhATbj8Ua1DigUMEq0IOZlUQBKxNKEOtJQcG/9CLg5Mqu2ixRoE0EY9BplpBHV7wkk+4JEvj5JGaTuy+XpYvSnHDSjxtgWYdSp2DqUNVwh7hhGAQrzsmCZl9Ae1eq0GSA4gFkej6D/rJWL9zIthbADSi9h4ioe+wb/TSBlaNtg3S4jI+mFYQg6DY0asKmMsWZtV6oXGB/+2mt44TBjLY214h+993vwxUcXvpcaqLCyv/CmFzAls/xsqiv76IRpOqBOB3zrWzcoA3wvHkZhzA+HiqXq3KIKGkaUQTxTmzfnbKo4oLiSty7iqXUcBgyjmBFbLFfbq2PEkcZRPVyy0OrCogVb5rBwKd0RDSlP9ViN2W2kPNcbzRsHDTc0nwBcNuUnLWtaJj9rb215/fXX8frrr/t8fuGFF/Do0SOM49gIDHxfSsKfxoRaC5N1iiCbuQpzQDCTfBPUMCWBiQy23PN1g522UAqoSj+TA93Y/yqHkMa0c7YCElSzXAig0tCe2F9InEMRfgwQD5gDxuEZfQDcp7/x6R7Q3ZG0UccjOTZcPpycz8ZZTDgDXrEJzR6WwBjcw+EAM6ckArguKg2VRfL8/Bwvv/wmjJtvohDhwYOHLtWWhQcACOMonutkMR5F2qdmjgLaDlpGwTgOYJZzCVLXQwq7IPdmfQcQSf1GtZMGSOdldhNUYyYDTNmiz2mxhf9viYhw/egM14/O/Nqv/v0PYnMzO6P0w5/6Cj74e1/yN8ep4kvveISb7RBlWN760JOHWw2mFGX12rOoxDGoa9JzgLW/lqQSS2ebu43fNvX+lXy/+ekPdaDQyzqRj1/TkaMCPw9nr+b+zWAoS/+rubKv/gLpeSwBdIBrpI+kvwJwfKvPjETXH/1ZEdnsizMEBpqMYnp4ZZ1lOWftL+kBj5S7l+FangbQhSmZtyEjqq6NcT2VmfKI/I+Ta9l6hmq1fdy+04Oz9B7rAHOtKY6hCgBSP7X1LAnEAkPJ4BoeAqHon9FixJQzQB5MnFbY3+2naICelpgD6rdXrM7GPJpZL6V8s7kxafkBnPWqrxemr2G4uaY+pxDN54wLI6QzmlFyoN7AOHIFYBBuO4eJ4PtFqz05XjfefL3HqAwtEbljK9HK1pZwmrUTABanwwdzxY9+83U8aTwaWzvk1+++5SX87+99B+pS1dlWOA1ZhgHTRlgnE4put1sHFy7ISfQaghKIhkk7ZJrN4yvcZDDmHueq+T6dPfvac75+EDXPWfu3wya0dwuafKxyptnyuLEpxEQ+h2XP9efgrKq0Auis/v3fkelqHhEDdV1+Nnf7MEo3Nze4uroCAPcoenFxEY7QujX2ZPKxil3fHPZkcHmUF8WYr7Te69AWFesINfNqfT+zCSrY0ATfg2gO3Xwmnl3rv/v0xk33gO6OpFHjwZlmrvdylTeS6+trXF1d4erqyhfuq6srj/PGHGEF7Np+v8dQJMaOmB7J5nFx8QAvv/wmj+l0fn6BJ08uAZi3OlKQZi6v4wyfbfKHw4Srq2utY0Epo4LLBfu9gM+HDx95zDsBmGF+sTHJ5zDgcHONyydPME+zXjPvg8YcQSXQHOfG1nnR9USEw9no52R+/yPvxO9/5J0ApC1v+cpj/PjH/wIPLg+JqfSXcbaf8Y4vPcFrL5012a5tE8abHc5GvP7SxYkd4D98EoY2t2olhSi9/W23T2RsDOfzJpc6O2o/AYsysOAwzau1OnPcgHt/hps2GHNrZothvZi1cziiACkitEZ22N7qslQO1+8wRtqYhah3uMxeax4pI11Qip6NTeDL6iDXrQ2pbYFG+25uGTTVzh1p0jIDqI5Kimlrch92Unt71+MqJRyZ5xKnZ22EKdXDTTlTfeV8VtYaQcwNndkK7ay0zUxEs+fL1N89ALa2GFpa773mqoFItFciPwfOnnGbl5dltA60ptg2DYR2HdyWov2Qme+kBUv52LpZCimwyjVo685gbJcF33cze1mAauUycETQn2l23zwt2FXGNy7OnGYqi7luw6gTjugNgIZrEJrkUvA/fuwD+Myji6MwJw6QagXXBUuZcWA9L64mjVlDaH+G7/lovACLGkZkcV0LRHvCYCxYuKDy0pz/6oGS7bnm0dnMJHMAayA0/RYmyMdi3Dqgs3HN5Vifm9lwkUW84Q/seQMJGXhmcNgDtHx/LV7oKcDRl5G1itn79jAMzoNcXV3BrHy22y1eeumlxqlbzuNUshljAi0D89ZHR8+ndubPPvX3XfCStkJyc+b1PGLvCfA9DIPHb5TahkC91YTfpzd6ugd0dyQNpVXRA/ANwjYJQBabJ0+eeKBuk27ZbwtVYIujvT/PM0i1ZNnE4dGjR3jw4IGfmbH4dbaYG7NaipiSZHt3AC592+/3voBZ3S2MwTRN2G43DiKZWU2EWOLrbbcog2g7bvY3ePz4MQoBm2HA4OcxQsptrh1M2h6c3HrfnlzQe5DCjK+99QH+n5//ITU3SWZQJu1n4Ef/4Cu4uJxOD2azIRC+99XX8KZvXGN5jgCiDMYyFHzpHY/Af40SPNOa3AriVl+kADtrzybm3rUFt9TDtQjKAzugM22XBbXuM7GxrHZuQQO1dn1kMapMiC1S3F6rQH7T7xyBG6GLLQM//PoBI0dbs6TbGIvKjHQcELlTAktwOptowK+i0JxxqH4aLeXMrKrG/CF93p4c9GYhSQKK3uZek/OUuRXvsmouM/Bh9Vjp0Bb5Q/qTUttzQwI8UwcGGvNBrbOd9TEAysjmsk2h6w3i8IQXsQitrNzHqY7MDgY7yGbNk3YAqa9Tn1KbX6PRTz3Wa1UBas6eMaMBbRSLl6+77YTqhCMAvns/4XcfneFbW3GmxYxGk+Q1NKCvIPvPHw345e9/Bw67rQvnpmnymKcZmNlZ6bwuX19fY7vdemzUUgqgTm+sLY1mPglycmo1SVmT3U+OrA2qsGxCgEBgFtNKEHBzuPb92PbY3nu07bd9PXqa7f/yfnG7RgwAkpkrFQdzs57BM62g9XXWoiVxw2r+fR3XnmvATsor37e1xXiBU2VkLeSRBUTKO7Sq+m7ak5Uz6OoSLV3Lc70+bfua/LKAh7r73bP5EIjX0f7MiKRr76m19T698dI9oLsjiYyhVRAAACAASURBVDpAZ6aTGZDZIvjtb3/bvU3aor3f7zFNAjLMJTKA5l0i+IZpC+QLL7yAs7MzgESiud/vcXNz45uulWmAzsrMm4XFpttuZTO3TcbO6c3zrCaVgwNA2/h2ux22OzFhrLXi5voGT548wfnZFmfbC2EYEjNUoI6pmQEyYABkjrkBcCdXy3YDaUDe2qJun4Xwex9++8lxzHlaP/3B35rw7ldfW6tCu+EkxoPBeOdfvI5X/uirmDfPGILhBEPf492jx1bf46Nf++2AP3vXC6iEY7Yw9bUxKQbsTtbKzjowMIwlzGYM2NU0xi0UACPcPpfkyAUK8szLpTWeSkFpAKlU/MG04IPfuMFwSmqr/50vFR9/ywU+9+hMzp0Ng5xd1Wdsg56mBQebbyp4CM+BChZqKwkHSX7jxsyajQzD613L5Of6Sf/1jG2vCXFpuzN44Ul3SE5QrM2cNSNEQT+pDwlyxjXKkPqWcXBw3jBsGeSxxcRiAOa0QeowzbNrOcVB1Ijz83Nh9IfifWBh7RmsbucrBjWvM1PtWiuub/bK7GaQmZhA6Swpv1bMS9V1c0rr7uJCHll6fOSlb5ndksByJ1K3B2TaUGDUs3HFPXZCHKHk/DLh6QcRMG622AwRF3SpFdO0YKlyVm1Z5CzmYgH6UoxFKoMEB6+t50Hvvyp9+FWq+M0Xz4UehwGVGfv9pIytaAaphCbMwBcRYQCD1IzeHHAZyHBGn0J71KdTmhN7J2u7zFlPZvbXQEYPBPvPHiyEYEhDMZQRw2bAYd5jnuNogcVlzYIkE4jmWLJGg339nJlnxQinBDdaRwsDZGko4v3aANw87RtNIDM3RzdabetxH2WB8Vr/33bPTDtjDRK67oVsFiYig84eyK2VuwZsK44BXeQTgpCWziHClwSyVnmAvg5WD533UWaMma3ZdjXXReppQphWox71vU93Id0DujuSDKCZBPDq6grf/va3cXNz42fLjLn4+te/7geKAdk87bDxOI6+kB8OBwdjZ2dnePDgAV588QVfUIlItHOl6HmHiksNFXB2duaLr23OT548wbIsfs82LlsYTfo6LTMO84TDPKECGMYNtrsdKgPzNLnTlu1ui0cvPMLFuXjWnA4HXF5eiqfMjZhhjsVMYDQRQLS+AVjKUkRjeI/u37KReFEULtHt921STS+zk2JeP9ji0x/47tUN/SSgY8afvPJdeMtXn4Dq8bM5/6eZkgCAn+5uNCFRl156n7Oqej7tg3/8dfzYv/uaBsf960lWzql+BWIjfvb8ApjoyJ18fqyMX/qBl/HqixfIJjYGQA77CYdpAnZb/MVLFxhdu1BQGRJPKPX/wsBS47zWUqt7sFuW6p7hMpMKIiy1ujMP12Ivi5S9woSZZ8HwFBhMY2accyplwG535mW4lp0ZSAxGZkbHURh7aaDQQT6vk6XwbvpVkldLZTIlzlwAN2EijQkU0GGMk62BwmwXlCEBunQu6Ow8vOQdpgnTPGPQZzcbOTO1LBVPLq9USweYeVPllvaKho1hhjLuEw6HPea6oHKVWJnzjLrM4LqE4IcF6BEzBhLQtiziJXEsElpgIAIV8SS6KYNaYxT1VFwwbgcMI9Tb64K6LFh0rbe1iohwcX6Os63E/ByGDaZ5xrSIyW2tYoI6LQtuboTWZqW3Wb2+VlbnDNr/YeInWsylLthPE2BOORJtG3izdX/cbEElg/lg6K+vr31cDDBlcJEBgP0ZQDS6z3STgaP1ieyVEwiM7XaT7olppDgSs3PppN4hg+azRs2FHaVgWUanaVYOnQgYqYDLABpDu0hVHdQXC0EQ82YoAzYqNFnQuuqvLE5rKiLsgHmAlD03gatmzwCA6kLVMfXtZrsVutG+Mw+TYzrOYODylHZt7XcPvjMw78fex69WHA6TC22NFlx4rGm327mAOQukfudDPwCidm1pgBdUUFIsUGVpeJpbkyKvXgvKCrQy+Jb22PnbKl5m2QBevx9ZXhpnzte+CJlSqwWuB4iC9u/T3Un3gO6OpKoaLVtg8hk5Y/BsI8ubQzbLzBt0XszHUZichw8feABweybnKV7JYjOx7xnUAe15hrwA9kwkEYl3Tiq+eZrmcVkWjGdn4ngFUo95mVG5ulmobcYi2BIXw4DDEpeCn0rMfLTsPjVRDwFOSQmfHdSsAa2ngUkA4EL42tsenQRszwroREmVAV0GdZ35z0oy5uqL33WBX7+Zm40v12NNkhumuVaeameUWYxnM+MQp3sy47fUimme9J2CQoPWj9UEs6qGQhhYyUni/phGw7z0GX6tpeCwHUFlcBPK3B83NwX7Q1Fvr+MRgKm1BXRqACpS5KxNqDUFtW3niwse+nFjdk9zOQUzIi0k82DaCR6OmbPsZj6dWevOBtm7prmLPEXwkz3XrUm4ezBn13P5pEyRtB2qITMQGSbhWSOU6cEk3N5WNwOPM0XyLCcmPmjQNf3eNvsufWqAeSAGMVDrAC6yBglDbnklWk0mmc0YpPxDvhQFmhORImpm0a2ZcCfPEQP5hwmlLDhMM+bFKl3AbMxq1h5afDOlRfMESEYTsb8A6rUw0xJCqJUFAQbQ+3Hv15IekPWAyv7MIiTfW1tXmCtAKSQEApjanpXrGO0L76g59fW193U0nWjM03R+Pp+Hy0cQ+tRrgvx66mej2X7/zPUULMK+FxPH+joOg4QfSKA379vMou3O5/r6vl0rd60tT7uX17asNdxutz6PATQAPq9Xn3vP27V/1lNrIyBXfL75lei3po5SwWZ+Wt+utlMJzYTetzIcuY4dfafejamP4zX6Pr2x0z2guyMpn11blgVXV1e4vr5uvF1mUGWp1uqmjdmZijFGJgV7+PAhHj16iFE1d0C7oP763/0ILi8vmwPd+buFQcj5540qb6AixBIGbbsRByxW98PhIOUzY9RQDNIOPVdX2T1exoZczXgNZuxgZpjA+sIfDGdsAO0GuT4OtuDbLzso379/W1qTaJ4CTP+hFnTuflnvrW3ofb28/aVgOt88RbJIzZ63Zl7FDAdXwRwZk2agM0vxCbWK97cDA7UK2Bg3I7iKU56FxVFOLZAzhxt14sNyFgYAFqIcMxpgM9eko406j5dJwQ3QMYdZZ/aeKRt3MR8LDVOVmazcr8IYE4jXJcz9O7k++fcamOs1dNnNfB6XpR6bW5VS3P255wf4ec4erOX3187G2HoQZZsjCo1rhdA2WHwqrTVMCJGB4pEZ3woza+Mc5noyZsIYwwVJUY71U5bQD04nXAagMiotPqHCeXnLuOV+i7OW2ZwSXd0lGDFJ57sWwUC9mRcbc84A9vsJlQlEEp8UZDSvYA46J7gVLHBqbja/FyBZkEMe+PUE5py2unXOPk1L1AO5DOjs2QzoAqy3Qo/+WQI0Jp8AXyujf9cEgsAxoMprsmm3jV9flmQeB8lzt9v5/Le90fZLo7WsRczl9PM619GS5ZkBT596IMlLnOXbjIPXLQs0mnArRU3TE4hcE1TmPauv79p45OeFnsM81vgHIvKjIHltsP7rhWVr+1IINtIz3bjmX6vvUhzfaPiYFXDl93weZK4D3bOpbN9jMqBTT7yUgNw9lrtz6R7Q3ZFUSpxRm9QscZomNR+Szc4Akblg7k2a3KOSLkTn5+fYbrfY7XZ49OiRaOfU3HEcwyRlnmd85cEOj+seN4+fJMaMNZ4c1DW0mCaJl0vZmA+HSTV5YXIAxDo7jCLZnOZFzZgm1yZuU7sqL7jZ36DWGbvtiHEoTawXyVS2WCKL48Qh7ToB0G4DKn3KDIwXCBxtWM+bnqcO/36TqgdWys8baM+ArGlk+s/jvI4ZGPmef4emqWVyqGOMFSHpGZ5S2HfQnrEowuX52S6uYo5WlVsjb2OUX4qeMyIzBVx8vIdhwAZhyux9oQwrCCAFdwwFOouE7JjnGdO8xDmsBICMyVmWBYWLAoxo81o/94KUAC3tvd6kMsaxZWxtjAsVVAoX6y3z3TJz1DFw/bj39NPmSV09DVD+/+y9W69tW3Ye9LXex5iXtfbe59Q5PlXlolxVtuJ7HDvYBCLHCuHBISgiEHFVQDyAxAOP/IAgHnhD4s3KGwghFBAICSQHTBQspWITQ4LjchLbYLvKVaZu9jn7tuZljN4bD+3SWx9zzLV3latMcvbqVevsteYcl37v7WuXr1XU2SwvvVuYjCta33JvGTHAZDGSEkvHIGog2MatlCr5LaFzegHoYl83IZiQOCPnCq4JnBKoEhAZM3ViG1Ai1cIbQYuBYQOKSg3pWFXeDZhVTQCkut9q/5sbJhieCmCeJpRKSLkiZQZRdqRDKUkCZLVw1grMZRbXSxeohQwkKjWaZcKNEwCTV7cB5gJzfWdWSxZX36/jXOyswQvAbdcMw9CBj6vKATTFzzBoYvpkqcUSKA3Sf1lAtpEmgVjzg1lsa7PytXG0OM9LQLYkLLM5bcB1TRmzVLIsgdHaWmn7YbOixWLzpJbiYBMAxiG1ea11i942tbbk4HEc7juLlkqtZdvWAB8gfT9i9DrEPoyePZFkLe4l3/PbXwaI8Fuf+fhqXWwevG7p9jyp6CXQtn8W+xZ3Y9WuWysy40jXTj8f7FbyvVWSnKfgBfFQPvzlAdC9ISXlrHE2BYfDAaeTBGG/9dZb3Qa4BHS2WdmhGAOyd7sdmFndLR+BiPDyxQucTmdYzAhRwjyLdfAn/u5v4nt/5+sAM/LQkvZWZnxlP+KvfOaxH2r/7v/6OSQiTPPsvvtJv/vfvvdj+KW3N2AAP/Z7d/jp335fdJ2lesqBnBJ2+6/ir/6L/zSmeUItM/7c3/w1vP3Bc4kxsY1PD7jPf9fb+OUf+QQIwNvPjvipz/5WEPv78tmf/AyevrUFAPzQr3wZ3/WFpwDaZm599uzxFn/rJz8t3xHhn//ZX/NnyOYMP+1/9Yc/ii99+m0AwCe/8AF+6HNfvTqW/8u/8H2QWxn/zGe/gCfPjvIFowl8AL74qbfwD//Yd4KI8PiDA/7E3/w8XJhYNO0Xf/JTePpE2/S5r+CTv/PUn8PhnmdPtviFn/yU3/dnf/Y35CtvENn/8as/8nH8zqekTd/1hQ/wRz/3lfbCAG4ZwM/+udamn/rFL+Ktp8egkWyV/e1PPMYv/9B7ICK89eyEP/23v9Q3JDTvb/zEJ/DBWzsAhJ/4ja/hu3/3eX+pPvf3bzf4az/2MRBJUtZ/+xd+V+smgpnnFwPw2U89wa9/5yPkYcD3feUOf/K33ncQuRRAfuaPfcwFzr/4D7+K9+4mMXDUJjyCgc+9c4Nf/N4nSCnho3cT/sKvfkmFpCZY2Dv+i898BP/vboN5Lvjp3/0AP/b0eJH/Dgz87jbjr3ziiR/6/9H/83XV2pL3aVVB7L9/e4O/fTsCAP7EizP+5fdPF6CcSLTH//H3vedt+vc+//v4+HG6vI4Iv/LuE/z1z3wMAPDx44R/69e/5MNI1IR8BuOv/sAn8XtPbpAo4U//9pfxg1/9IADz1rav7jf4r7734+qml/Af/r0vtvdaLKqC6r/xmY/ic++9hZQSfvirT/FnPv81r98yduY/+4nv873uL/2D38FH78RlPOWWdoHB+JX33sLPffqjYK5499kR/8av/JY+M8QlqpD83/7Y9+Nrjx+BmfHP/sYX8MNf+X2fx245rhVfud3jP//BT6NW8U74y7/+JVhMqbnksSqe/oeP7PF3Hm8AAv6pFxP+pfdPhtc6bwIiwn/6A9/hguW/9utfw3uHCWblk/4St91f/+gjfPa7P4JKhO94fsJf/LXf934ppap+RpQe//X3fARfu9mBKOOnv/wUP/L7dzbdIKBRwO7vbhJ+5uO30qe14i//9gcOQuNMJRD+x/ce4f94sgOB8ePPXuLPf/WFjmFviWcG/pMf+iSgQOnf//zX8Z2nSecRuvn6f73zGH/tn/gOAMB3Hs74d/7vL2FUN1u3IKoXwX/5A5/S9TTjz/7OV/HHP3iJuEwI4rL69dsd/psf/W5kCGD5D/7WP8Cy2Nz/+T/ynfj7H38HSMCPfP0D/Jnf7Pe9KGD/zJ/6IViqgL/wS7+G73h+8L3EASgYf/9jb+Pn/8gnAADvvTjgX/nl3+rmZuzY/+6Pfw++crMFEeGnfu2L+MGvvA+u3HnjAMDvPd7jZ//kH/W//82f/d91jgRcofX9lR//fnzhez4BIsJ3f/4r+NG/++sXyhv7+Z/+1X/Ov/tTP/dLePuDft+18luf/jj+3o9/P4gIH3n6Aj/11/9Pf6+djTZWP/9nfhzP3pH97Ef/zq/hU7/5uwKNF/G9Tz/yGD/3Uz/q7/9L//MvQRTFprhrIPs3P/2xizpFYH+9XA8fWOsPouDtE0EYiWcI++f32egAO9nNAucnaJirZr3MWeKJzUPjobwZ5QHQvSFlt9t68s0XL16gVnGnePTokdM/n04nvHz5Eu+99x52ux02m427V+z3ew2Wz+7C8PjxYxCRW+meP3+OL3/5y3jx4gXee+89iW9LyfPaGYgcLICd3HcMtVaM4+hMlqRwqpSijHjRrsUOTu1Qa4HuFRYXY6D0fDricLjD6SxMXUMOiUZhWmJG4ooECmxyy41wZRN/fUWeFupa0j1q5ZBwd060OKiojXbzQngkgx0pNZDxjdbz/nL9QJP6XFD4WwlALv5uigKzgi01tg5+o3YygKi+gSKRNSscnEmxPaz92vo1IeemPa1sTIwEqCC32W6w3WyVcMAOV2mvpwrQF0l86SiKiHiwJn8xQNS5AzF6C0IcdwBOIT4rCcrlOIiVANysdNx1j6eRhgkmxoop7bbuZISmwFx4oqXelCL+ZG5WpThXo9udCOTN2k6xral9fm1hERGGPLh1K37etOG9djxnUeDY58nmhitA0FzLxhHjKB4B0zwBqYLQrA5GslKV1dIsHuZyaVYlc0e3fdaEyAjSWN97c3ODaRoxT1MHdP06BbbjuMGw3an1tlyskb6fEoiyx4HaM9jWEGvjGciUkHJPYkIAaMjeQQTCfr/F7mYLroTNMAQyKVlvlROoVgxDxm63w/F4bHuVPbOrZWNGFiXh7HVqFkpygOU0/gk+jn0fqLU1eJVEoA9wk+a1TvM04whx+T+dzqilKLGOxVfbfXC3aJtvnj9P+zsK1q1e1KazbUFB6Wb5Dw+HA86nk4cryHfN+rjbCumY5WJ1wEsAcb9HeGiCrhFbu21u2Biv7LMcsHFYy/M8eQx+jLM3BYq/I5xNHouK5oLfHtssqVJXLL5fjOmKJY8AsUbXFD5ortFtX71sY/u9KeE8JpnFmdhi6mNpe2SvvIvf27+XltHQB7E9tPBGsIUS5qrJQ3ZPUhnHgZ0qXfIgHk7DMGAIjLUP5c0o9CpNw703v4oO8KH8I1P+9T//T+Jj7z7Cy5cv8f777zsgu729daHh2bNneP78OT75yU9it9s5gEspOZ2y5X7bbDb4+Mc/7hTL4zji6dOn+NIXv4haK9555x28++67Hq93PB7xwQcf4HA44Pb21gFfrRWHwwHvv/8+5nnGfr/H48dC1HE+n/HlL38Z5v6yv7nBfr/H3fGIZ8+f43A84p2PvIPb21t88P77uLu7Axh48uQxnjx+jHc/8jbAjLuXL/D0gw8wn4+43Q548ugRNkPCmBOGnLDJIrIJBThAsCSwTVW5NtOZGWlxOLirCXrottTWEczFq1x8b8+K/y6/N6vqmmUoXg9E4pDrNMr37QNr1y3/rXK6uia+U6+v9QH1MUnL/iud61aLz5H2NPBXZo2Vi5p3C4Dpkj4nF6Itx9w8F3+2AbiYAsCSEUt+w5DkFkDRHFW1SGwMs9DhVx+vBLKcTjkj5cEPYHN9FtfgEXkYXVg1l+h5nnE6z6ho8XSlVpzOE0pBYzkDAIsp0XpbX9m6Efe/INxBY0rL7Ey1HBLqEZm7dXECodubWxGQhtzNrTjLxR0oOemIKX7GYQBqdZr+7XaL3W4nfamMhyKkwJU7yzHvSmC5tLLZbEC5CbIynxqYMLEIQC+UV6HUNzdti7EbhgFPn73f9r/AcrlTsiWLO9tsd3j06BGqxlvKnpgxbrYe0ysxwlJfc9sEgJ0myp7V5XGeZ8znM2oRxstSCupcwGWWPQmMISXkpH2n6Q7MHXFIyZlDx2FQ5RlQ6wygCign6YOsz8nmJmcxm9VYLAtKhSrHdA7nDMLQGFirpDGokD46nacuzique0dmbIoLBfzDoEItTB8k9wTXXGa4Eq9UBkgSR+/3ex/z6GbXvRfA22+/3X0f3Wtjwm5ALLObccBuu8E4DhjHnpp/meA7Wn0NSNgcO51OvpfZdQZgfV8E0BK3N2VXc7VE12cpyZ40jgNyymBIXkxjo20AyHK2EaZpxjiOkpd1HDEMSvikClPpM7lnGAafCxZDuBl7xunluZRSAxjLcykqdeL5tiROWQM8DszDe4Tl8RKIxXvj/rCs8/Idy+dUZhQlSTOFXzyHWPfL+B5TrpqiMabUsP21lnJ5jx4gpRTMpWAuFeep+Lqa9WeqgKzwhApRnmxuHmG722Gz3QGUUUF4fndAHkYM4wbbzQ7jZoOnT5/iF3/hs3go/3gUtoPrmygPFro3pXCfSHzQfEpGPxw3XCM6sZ9hECHm+fPnTqwCiMbSDsRaK45KJ31zc9PF5Z1U8xg3Z9sgDSROqp1OQeg9HA4OHk0AoZQwTTPmuTSXoJRQuLGBSf23IlhBAv2PxwMSsdAYJ/IfkzHMKtdieAI4ci01ugOJiLocP72Q2VyGOgE4aIdjiUDnPoC2dNl4raFnvjg042fx93jPsg52/9rBqMYmBzzLultZxoMsnxc/X7r9rhfTUCbtW1JtpgmO9lyvbANsC/AQD24ictIOWRsh1xIYUGb5NfISB+3U93d7d3uvga6o+RZQp2ALrBT4jV1xLq3+ZIAxpRZrx9zNF4qWBhNsuLEdggg1xCuxUuVzrX7NOA6rLJyhh0X4U6u87TNEhO04gnJCKZdxPaZsYAPlK+kNlnODfSn1Vok4RkuBE2jzMsYlpSwLewkCzFonYLit7XFMSoU+OPBu4LlZAxjN6mxAgrnF2xEFZkO1HFl7E4Basv4UlDyjzuSgbcwZQ06Yp7NaE2qY5y2XG3QtVrfAGhOozgZmMIcYxKwu8EQgpcI3KzW0ZSkl5JRRqoxX1f1PQGDpQJzN6wbo0NYl9/PUDHOWA5RhijUzVOi6mGeUKkqbmKsurqc1BZStrVgfGzdTSEp+1snHa84CeNN27MhKbG738wt+Di7JN5Zgotvnw3dJrXwdsKm1i42V9ayxfWblI9nvEkFJbFr+xggg7IwVy6rGw2ufm3LCFW3UAMryJ/atK/SqpNZgf1a/NqNSMfZDHKPlfdfeTYZww/OXwM7W8KuAXCxt7qxb3fx3SgC1PJp+foYzM/7Ife3aeLZGmcI0T67MACOBEVO+mKm3nSOaEzVJ35dSQVRQUwOTD+XNKQ+A7g0pjMZgZi6Spils1oIBNzc3uLm5cS2jbXKn0wmHwwHzPPv9xpp11vxud3d3ICJPiGpaKnPzNLAYrRHi6iJaTMsZY0BPyFUEeFpyciNdsWfFHDju2qYCwqzxd+IqkpCSCZBmIwudQ+yi2LfT8NzEX/lLDtEGqu4HL69f4uH3usBvWb6xusQ4Afl77SBdamWBPmn18nCP2szmFvj6YDO+ww9Bbnnc4r0EUlyodPa4tJoyJJ9X0762Z5krnwNcFtIf64sSSImaQJtgjJsx7cakueUqIRzcVfOHpXWHRO6FrOWXSzC5JI6IxdZhI/wo6AWq9QpYjisTfp3YIdxiwqU8vyUdt/xry/FdUzZcUxj038f69tc0ACAAaLvddv1g+6H9XTYbUEpiFcmRjbAJy7KXau4xEHJuWnqgxSFL1cUyJdYpgEpBIkKx+VYLuI6otYBLwfl0bBY5lnxwXJQqn6QPE6Q/Sfc4H2t1wb1vGyAiJJCzjAJqmVNB31n6FLwZyCB5PQZKmEtCtjWwNk7BTRDB3a9ZeC9Lm69w60h0Be7qHyx6y3lxd3d3IWgvFVkGAhLkrEDYJ5YKgqXiyT6zd9teFesRlTKu2JQvujqsAdL4LAOcADrLoF3bKSNCO0XYJ+9LInVb9WeIgkaAJhTg96zTawDW91ZcrsUIaK3usS86cAtctH3t3YzLfrqvLEHo2ufxM1kJBnDRtUtki34xeV2IxJV5cfa2vegV9dW1Ia9QDbK7q/b90gPY5sIN9egoRedZULI8lA9/eQB0b0ghtBw4u93OGSpTSm5Bs3gOA2Rx47YYu1orbm5uPL5uHEeUUvDixQscDkcM6lKSUrPeHQ9H3N3dyX2jgrbKmOqM4/GE8+ms7lkjUpLvxLJngE6S3Z4U/J1V02g58KyeOWUXaERALphOJ9VMEoacWtxFsNh0/WSxG4tN+xvqa6JO3uiFGv1s5b6lgHGt3Ado7vv721Xk4MLiwO2vWR7oy++W/3aWs4X21dsdmm8HZxM4Gh20HIByAzPcXWbZBv9XzWt0BQQUB3SSzNUFJNN4G1hoLZSk98Fl2YQ/E/6j5t8UIaVC3Au5AaRSLVdR77p6fVxMqBCBrQlgLW+WPKOBntYXgMUSxRySRjCQUjfL/f7luFWu3pc2TgLoKpjFLVAAXe203Mu2LJUea0qLJqyjzUmVkuzeCO5Jk3ObcsvmaCmlxUyRxEtZvjqLtxNLX1GG3TPErdesQcCsgM7q3VzxpK+N5KmDPDaePIjFo1Z3lyzzhDpDFQMVVBWo+VyAKyIE0EGsf2yWVOre061bQGIS9XmJksTWVU1WLwYbqRP1bn3G/JoTIeekOSANIATLBZpF2K0sbDUjB/1xh7B11FvBe5CxnOtrgO50OnWgx8YkgjH5STB3+7ZeGCmxW1A6MOqAR9hxq7sCWot1DRG7B4DFWhpAfp19v1/LTaCP/RTbbJbLdoZXAJP3FxqtcQAAIABJREFUu8//nJUhlby9rOs1grl+b23A0t7t8/wKoI59vgao7wNol58ToiXzPmC3tl8sv1/+TQaiwlnW1VXff/FcR4B9u3yur8xVcF9/3dllftizXcEsK8Vcb695rwhQLg+A7g0sD4DuDSkpZw9Wv729xX6/x26389i4eZ47oGcHhrlMfv3rX3d3RrPunc9nTNOEp0+f4mtf+xpqZbz37nsYB2FLLHPBi+d3eP78JaZzAd1kbDY75JxxPAo4e/HiBaZpUj/9LQgJh8MJdy+POB5OeOedd7Df7bHd7HF3d8SzZy/AecD+9hFubm+RQDidJsxTRc4jNpsRFgN0Oh1x9/w5iBmbccR2HCRmKWcXHpo+mdpm+k32cSdcL/bZtY2XyITjpTvJ5QEXr7n2vHj/8ll/kLJe98WzCd5ztNBqrgG1+PnadWsCfeeetxCs5BqzvsYb4UKYaJ6bRtM0/1caHVwwm0DpgM5BQYL5AFq9DewR1CJDEqt11nQhpRRXRpRaMWkKEQN1DgiVIl0r5H2a89DcLFNCUpKfUqpYelKjGB+GASknzPOEUiYwF8Sk2cPQ8nhF4W3pymYMhswluA1GshN1XduMCnKbBr6UArNC2t9mPR+GlgrFFC7RyrIE9MzseSijRYYUdEVB19KfkMZgMXr3rForMhEojdjv9/58y4n5SF3HU0oYxhHTNAEQ91PbY3LOuDscPU/nMGxEuAWBpsn7wGKnxBIo81RidYSAoVICZVk7eRAwl6z9NaPME1ArKkKyaQfAStCTaDGfbW2q9dmBGkm7SWwRlidcQJ3tPc0FEESgyrAkL0QEJpn24iIp7spDTuDN6JbLqRYYAyHjMs+cKX8cBAFIpnTx9WwtEZfRnJLECGm6miXgWCo31vbANQtY+0w6gwiY9ZZ5KjBinFoZXAGSpA3yOct4DnkDZN0H1JCY04hEjJqaVZ8rgCT5U5kqCk8Xrug2F5fWP4tPjfWP8X8A3HoXc602azPrXiHXb8YRQ0iXUquc92A4G6coYGZ/lq1/j89li6WMcc5tnJfpjiKYi2t9CbjjGHbnH5nC4tJqde2sulT4XFcYEQyAK3gK11k8MmpLoB7rRcxdAnZz7wY392UK3/us8/qIlwgxIVUGJUZSbQqL3VCVKeYyrHUiQmXZZ+aiHgNJNhTZtx7Km1AeAN0bUnJKDtYsZ9w4jjgcDp32zawGJkCdz2ccj0ecTic8fvxYXB/R4vEOh4MnQB3y6Pl+APj9ALDb7dyNK6WE4/Howm1KyZP9Wo48I1ux4HKJV5EDcXcjMXLDMOB8OuF0PKHUgu24wTiMLtzNc8E8FwyJMFji5mTMZ0utWCMy6bfwb66QA4m+tG3brpN4mjXBY017CLwazN33jG9XMW3j1e9wKUhd00wvr+8FAZNhA5AMoGJ50NvHOeUGDCpAXcxYEyhjidYe5vB3GMVo/bE0AFYTAC7c13C4m7Um5wyU6kmve9AKUG5xUCJCEoQAJTugSzmDUktGTrUJPyJINaa/+A7rewMs0SJv9YzxrlFwuRSKmqUngkl3rZ4LmEr3HLO2zKrZT0kIipZWkwi+PEZpHLq53oT4KBC2uUTQVAFhbL2eChqiQExEyhbXwK4nfA9WCSsxVoUou6AW2QAt6bkpIVgteYUNSUk/mvAHwOeMgAhG624lClH3SzgRRmN+TMQtR13S/S3Z9+t5zVj3QJvzpRZXXLQxVnfOxL4mLAaLCBhyQtEGGbAwRUScf21uAUxtzVieLSbvFO9vcadnIXtRV/u1+bhUFBGRe5TcJ/i3ZzULZKXmJhnBSHT/jrF4Nrft+dGDJL6XiJBTFnKZKyrEJajx+xbxcXGt2OfNmt7yktm6jwqtWooDELG4ZweNFKxH3h9h/keQZj9lZbyXxT5busjGsbl29v1By1JRuvZdPLtX6xG8d7o2MvtZEL9r62dNabs4zwkAk20HqnDW+RN+Dye8eDVBPFJyHlDKJODRzqyHOLo3pjwAujekpJScudLAHBE5eDL3omEYHNAJmcjR4w+GYbggO3n+/LmwSwLYbEa/3zZms77tdjsHZwb0THNk2muLRTHXThM2a60K/pRkYbt116VpmnE4HiGa8xGb7UaFnepWj6wCsAto2idmnestc717wzdSus2f47Puu+fVh9Xa9/HQWwNwf6hATn5ph9M3WYflYXv1fm5Cg165uD48xw7mFA/ZeG0vCEaNaQ8OqPu+0xY3lo4GMBIATd5rjIA2ZlFjvRQMutgaarFyKRlwZBh7Z0pJrSiXQocLGuErCvU2S1jU4psAUGEuV+q2atYa9P3T4nAMeBopS6tHrRXneYa15ELIWwjY1wTBCOoM0EWB0MYmgvA4ppUb6UPf17IbGGGE1SESesR6MVvMp80H9vqVIi6Ycn0KbUo+RC77QWOQwKCsKQYUcNUyC0GMxyixuzxG8Bx3KrCQ9aixDRzWhFlmhBBlkYA99j+HbcsVGQH86NphhqY9aODA1mMObLIdCYQDzR6wLwvZe4JiA7B1I3u3sXguQcyaC9qlouRyvrWpaN9pI7kEICNuko1J0uZY1TnESKlZbSRezYhxWtx2L8CH9R8r3Sav9x1bx8d62++hr4FmWfPr2chlbDya1XtS0A2YVa0xY8orbHz79CTR3bMbx1Cvtf6OZam4Wf7bd8ni71c8O5YIqJfPXAPbfg/14QPMlvKlIb7V/Sy8s32v47icdytHnG65Yjmn9iOhsPphAJ8pEQqLpT1nsaqzXxt37YfyYS8PgO4NKaQWOgNJFt/24sULB2v2Y0DMXCIPh4PniIuEJnd3d3j+/LkTCJgVztw4zYoX6aVNyDOGOCM92W63Hl90Pp8dgALwz2Z1VTMCg3mecTxJ/qBxHLHZ7bDZbkEQAoppmlBqAZA9vs7ZLF3sUe1Z11l/gH6+RwO4fPw1oIaV73lxSF5797eyvE5bVksAdfFZy39f59lLsMrMKByH6FqOnfv6NgJBOWwjILBrl9ebQGqCswjAweUSTbiSUxU4nYSuvmg8UcxldaGxD65PzECxQ1m7MytAq6HbpB5meewFnMpVLXZi4RG3ul6wHlIOIFKsfKgMi9tIRG7hc6pu1neVCiQVNvUdxubo7qml4Hw6gbh6203IMdfnNYE7jtlyTRggNiun7WcIrp5Ab3WTJO0NrDkQlO7D6XTyZ43jeJGrkmtzPZXnagxRAK/WXgMfPmfUFXIJQOZ5BlLCMDSL4EAJE4DCk7uQllI6ZUEt0YRggl9vKUEUSGExXg3QSZ0W/WzhmQ4CKIiuYZ6xJUcvIR6VvA6iG+hTSACiVEkLa7GDwlbTtnIDLhGqfnEh87QlwIXlbE0x4LGqV76PQrnNnVoL6my/AxIfBzTXY4uzM28PAlEBkblAmjtcRgrWTJmf8L8j+LF+5/C7rXFLy1JLcdBb9Zqk6xl2ti0UNW6VdTdAgFmUBeez5N6TmFGzlkkMGSWCqz+57+NotQyLE7FYXy/TV0RvgNjny/uugTqihI5l6Rsoy3kSQZ1fE343cBU/IOrBmbWNw+/+WXeG8MX3hHAfTBIJChRfD+EcRJurtq8o7xFMQWUKmofyZpUHQPeGFELzqTemvfP5jLu7OwdcFtdjgO54POJwOOB4POKdd97phC5ztzydTu4yaW6Txl55PB5Ra+3y2QHocviY1S/njLu7O0wad2JWu1iX5OxdWWI0jECiVtxsNthspQ5lnjDVinmaVRi2g83cG3txn/w/CCpqNAn9dfu4Oxjk5guNMaIwIdctD7BrwOw+jeQ1y9w1gPiNlFeCr3vqu9SOXgOxrwNY9WUrr+vf4QImmrzksVjM3fcmYLig4k1aHsaxf9ld+CicmxavJXTghFoF0DFX1FI9DYIpNdydbjFGbgkqjSTEBOZMyee0P8vmBS7H2oRGdutF79651DB3c4wNxGo8HekzClBJ3QwrwEoYUWtFnSZRkwTBb54mgGuY98ECBsMerb49EGtWF9s/IpjrAB369REFxeoCT2u7xAgyZhVsTaFl+1Ekgmnuek2QMsKXZSyNucIuXVm7mD/NcWhARlxOxfJUaxErHZpl0sbXAKg1jYhACnCygWS3XilUUkAk4Dz5HPY57utGZzlrSousdtVSPT0HUyMnMbIUqUdrp+1tngg8zEkj2kAYbwErul9qXzRXM4atMKPiJzJghat7T1wDQAMVcU+KcV5WojtyrKOt0+i22doalU7VGWpJwae5SJrlDqDGfsosfRLXrjYy9mfq6tLcHmM9ung7/enOua6uqmyZJsxkhD3ZY2pFgdOe6cRFoQ86cqG4p6RLJdtyf4/77tq42TVr3zOaG+HF+fpNnHFrZ7TqSNwa159jnZqjuw9o+0xfJ7743G5q4+JvRpz3QJjmTP53CXujrKNItBPTjXxrFb0P5R/d8gDo3pBi8RgG5F6+fOnWtf1+78yVwzDg5cuX/v3pdAIAvPXWW+76CADH4xHPnj0DkbBmPnr0COO48TQElsbg8ePHHeEAM3t6AyNmGYahi52LCVBfvnzp7pk3GyEvmOaCw/GAk+a22+/3ePzoEXbbHVImzJOAwGmesd9ssNtuJSFy0jw/MO2YHURi5/E9k+GC5jdafMNWYWq5scfDFhAK8GvaZft9DcgtNcvLcj8oer12xHfHZ15oNUVNuPr+NaC2bNuagLJ+UIu+MieCJ43my/vcqhKAnsVyAnpMqhDjbmZ270VPNDdCJythESjlEJW6MDNSyItFbjqB1DsIPObOPE0TYAQZdUlzTq4e9n4DkMeMgVqScgYwzcXeciHYsRK4tHxpl65OzSpRLwBUJDWIwm6MD2NFGBUV86yCi94nucMmJLVOWkLx5k5dHGzWMndCivXFsk1Wn0bOQm1cF/OqVjE7MdbXC6OByDg+rEKR9wmaoGaCuX3XFGEyCuLNsHVwYsCGFBgPwwYM4HQ+46wubwKaJQl7VcpxpAmsY1whAKrUglmtsVmVVALkEnJKGIfUCXW1VhRIjCIodQDa21mr5zJjc01OCcMwAiSWrTIVTTReMRuzq0m9KWHMg36mc4cI42Zs4ARtjAyUxjFqa0/Xkt5nSgig5UqVesxqdW3zI8Z8Wvvsu6gkiHNpqcxoljxLj0AwMqBuToW5ac9oieOLrzVRJkYrotRpngvO5wljTtgMA0yVFPdWC4uIpdY+OToAXwtt72hJ2H39ZMZWlSCiqCBPDcTVrOdZFRqDD5LN3/1uc7EOfe2HdSckTLmr8/JcW8alroK2xWfxb9nPmtUvjuu1++3aV58xANRuJl+vnaOvru/rFgqWbcd0qn3ys82uJNknmAHUphRgZol3LQwaRle+UNJY7SHfV4WH8iEqD4DuDSmsWuhSCk6nk8fGPX782Cm7gZai4KjMe5bTJiYRt2cwt5x2ItBUnDRNQGR3s8PVPo+ulsaktyRIGYbBrwXgQlPOGYd5wlmTke92O2w3G+Qhu8VjUgtgSoTtbutxddcA2iUoahacb7oslHjx8E/hQLwGyK4BtqgNfR1t5H2WsVc2YeWeJahzAWTlPLtmdVsKUa9Tmta8ARcBUpfU3WslCmE2EUQASJ1mNdQYzeLTQHet1dMWiHUjOaBDKUFgII27Ufe7ADx64NSnc+iEHiLJC8asmLkBGgN0whCowir1mnqzKLU6ad67Rb8uBZwodEUhyUqsoz3XQbQJIAslRFLhwqz4HRCzaxfWj/i+ZZ2NuMX+vQSBQgThbQuCU3wGq4nJ9pa4V+UhWFKCNcdYGc1SFwk+amUXsEvli7ku81jnsLt8NmUFFn0fx6BydL8UJj6xvIlVJJLf2BRmf71o8IXMZIX4afGn2RSYxcXWLcpFY/psvqTkCo7KxrIpe23W9BbkgE5yoYl1e12Qt36Cfae/izALV3K4dRuXzJYG0C8UT+j31SUw6QAbs+/TJthbEmermtxqUnibpykhrDPyH1dKUR9XZ21a1nONUKVZ9pv1eO08WO4nQzhviETAF5dnSSS/fAcYmjJD2WDTZSqEJeOm7U1LQOdjutL/18ramve2cU/SdN9Zujz/lvW9dj6247tXFOLKnNWLuve+ztlGOqddiWf7KC7f1Zwvo7tye3VlxhDAoSvj0gOge1PKA6B7Q0plbsmKVcM8zwWPHj1Wqn/RGpZS8fz5CxyPJ5RScXt7i5ubG40JkEPqdDprzInkiBvHjWpBq+e0IyKPqbPN26yDtVYHbfLe2d0zG7U3eTqFlJKCRklJUOaTuCRxxThk7HZbgIFpOqGWgnk6o5QZY87YK+BraQpiMfc93SBNG8yunG3FMB6359y/X1+6Bl4eZqSxGXX1ulWh9zWE3bXfvx3FQR3M6uX/QTwI1+oV690Bwyt1dw2mH2ZJLGC1vc2ARF3VqjYwR2SuZwnxIG21NgucCbUm2Mj6MEuJa3BVIBeLG7lVws5/IeJRwY0Aro2UBOpsFftJtO0aM8SkxBXNQmRd3IBQIIToAJqy2Bkb4oVAAG13GAsEC5hIpjI+ZqUygEYSO1fRz00TLAi9Fcj6v5FGFBCZ+/XcoWlayYnnXQ12JU8ElWtWABNcLS/aEuxavjhACJ2MJEUA3Rl52DbwSGZts/r7THXQJQK/uvapW1hFE5IF81e3lpV5FrBirfW6t1hLrhXEjLPNK2aNQ8tIbAIhHPQ3a64pflqSZNbhtq62+ckO/EJaAkDyeE6znAsL661shaSCP7srodxvMVghHQaSzw2U3nXP5kTbdxeWs279JoCKX4vwnf3Y/IpW5HEcO1dA2wOSrUldR5SSEr5YP9n+28/zBs5aXaNCoCkyjD2ynQfGPtu8NGpYo+hAvNXVvotgLvZfJPSxZ1g9/Vks6ivhMBL33jwMnurErLwWmoBQBzuHLT/jmsLHzwLmyzFc7Of9nvGNnWnLe2SvsXkW9/C1M6QH8REMtr9l/jKbZT7OefQT7zUKc5usF/1g50J/g89vu9fFE1ISKiYIIY+tCVl/lAaAMpAqUhqQ8oA0PIj5b0p5GOk3pDAD02SuGqrRqYwnT94CEMFewfPnLzDPs4Oyx4+foJQZKWUASS18ZwzDqIBuBFFGLbMDOmPTNFeQnDOmafKYvRivV0qRGLkkwdzb7datgHaAbLdbZGW2LGUWwYkrxmHAbrPBNAlxSpnOEoMyTxiHjJv9DptxAM8zaHUnJvRWC7WGyK+r5b7vrpVOixi0aLUmiBHmejyEjN868HtVWdNSv2597ztYr9zV4blrB/ayXmvvWdeeWr8pq6IDSg6Hnx6/ZIdw1Ew3MIeujwF34awtFq2zypXZlSAO6GCaeAGY8zRrXJHVO2G72YmQlBI8fQFEqB+InL2Qw7yTQz6JmzAnjVcyywABxOKixRSAZhMI5asm2NZSYIe/tdeHSQFFs3wCpLFcOWW3pASZRAQMs4xUSzpt1jV1dUMAdGoZsnFgbq5t8yzERYmExl3IG9pYNQugjUf1fE5AE36XwrCQUairI7Mk4aZG+W6Csb1ns9vJXGHCNIu79na3aQI8BMSKp0KjrGdu4Jw1gbdZG0uZgCrzwwRwI/RIKYkbcEoij4kRV9+RMAwZXEcQM2bI/jmTAKiUxM3SJg9Dc1xVkpRoNo4pIUHcF21+ARZbR4iDypA5Y/tTBVCmGafzpOCoB+YCDmTdMAu9v20BgLHvGaBLKiADqVbRwQQCn2iBBK/vaw5OU5jDHPfS6PpYXBnoFibLParMsTYGKamltEquuMwC3qOrbSw9oIt1i6RGy1QP1ib5e0gZKcu7GZK6Q5Qa7Aqdlri+xa1H61y00C2tTrFODugYsg4gbnuJGMWUBuYCqaCuKS+yv2eezx1gNs+dNeB2zeq17L9uzwrXX1Pu+b+axgOp7e++f/nD+nsvlamXpe03dCkrcPhZadO10r57fYHBQWT33LY2QYSEDKIC3zwogYmR0iCgLjEoD0jDCMoPYv6bUh5G+g0pBML5PKEoA1eihI+8/RGUuYpGOGWUuWA6F9TC2IwbbLZb7LZ7jMMG03nC8XAn7piHE7gCtzePcLPfiy98ZZzPk8TLqHvVdisabouNK6U4G6a5Xp1OZ6UMN9dOS9o74XyekPPgn5kWbj6fsMkZebvBkAmoRawYZcI8nTHPExIYTx4/wZCAIQF5OyKBkbkgwbTisnkzm5asqoY5qXC3tF2EsvgOsEPDYkv6DVwEB7PeBADignQDKNeAzqv+vqaRNImdKQKcoHVW1WN0wyJV4XeaVFw70zj8tz84l5rYa4ffUlMar43aaSIWoVXdxjwdnQO9yxoSN9ZB14YyA8o8Gce2WRzJNfpDziIIpYpsMXA1X1o5TBNfQ49wlfllYAyQzxz4Sb3zMFrvyXzPWZQu3Lt5meBl30UrHBRgUGKdw+oOKHeCiBtRgoIOkbwJ5ibXO4rp/CRjuBQ3N4T5IAKi3JFIyEDmzp0UHr86lRl3hzuxZHGI22Nrn/RvBO4crEuyVpKnIIAL+QlclHHRZ2JILcDw+tQCFM+zKV4Hsn+phluBDkHIKoacpV3u4iopHXLK2AwjGMAwttjJQa2rzIxxHCQXZik4Ho4Ake6JVa2qMzabvRBOVMY8TcIciqr7dPE4p3meQSCJsasz5jJjO2QdC9HQEbEmak8+ZlDLYKYkfWdzMxESZUmZoL2ml8NUJMxAqYxZ3SxLqZhLQQWQyEiuZO/MKfs1RqwhOUF9ygvwNEDCFVxj3KK5VSZPMePKhGqxXLZzL6w2qBpTR6gs1tWi7wApg6jGEqWchPE4ZUPQMocyQJxEYcMFxdheWAAXoeUyFBA2g6paUpHd6pbNUmtrkazG8iwnk6mElA1w+eYT9mwFqym56yelhBEAqbKViPx5mGf/3faIuAcTxCI8ESFXtcAxY0gZldr+ByW+YRBgShi0M8n6Piq74nuMoClaDHvlTK8sXH63fMdaIVJ3UQX3CcnT0piCQ2715B0Xc6Z/INzyZuPbiKbiF9YfUolkZ4XVXw/VqDAAmvsrW/46go+vnyF63iQQsr+LVWZhDIlQIT9zBeY6I+cR0DWd8oht3oLyBqARlSsKZxTOAD2I+W9KeRjpN6RM54IXz16gVklRsN/v8ejRI8xTc92Y5xllrtht5bvb2xuM4wZlrjjcnfD06VO3pO12e7z15G3knJRk5SBkJwBubvbY7bbYbDae+uB0Oqm1T5KTM7OybB4wzzNubm7d1fJ4PKmlb8Lt7S3GUSx6tRZM5zNQZtzePsLNzQ0AgOczqBYkLsioSImx3+7w3jtvo84Ttolwc7NHAmM+HsViwWLhIPkHVa0sgnqSk6REUmGCHw0NGIRiH7nNiNoBZoc3oNpWjgxn1zWIS3Bzn1Wrr0u4jqi5IcYDVCVls0r12lJpZ/yfHXzxTayHHYXPo8Y6HvwxkH9Z9/va7qxqpvlWHGYHZzQMUlaXKY7PJ6Q8tL6sMkpmdUldn0pLShVNfwIwKvtb6F0HVGa9qJUxDQIUxIJn9S4oc0XVwxsMcGmCqgTcAGkYFWyRuzoZi6sIF+T1q0pOUYqAhfN57vqVWAg2KCVhxUwEVhdHj7my0VUgkxKQU8KQJWkzWEhKSPPfcYifNXdUczEzAgv15UKCxEpZHOtmKzG6cyl4/vKlg584PkVjomoGoMnSswJpA0A2MXmetN+SpkxQQZ9avCFzpKBvRBJRCG0xJqS0kQZOCIkGECDpC7KuLwbqpMAqZ2zUZXwYpK9LrZjV7bxWiS+WPfWM4/FOXNTHAWU+y3wos4BhZpyORxwV5A4K1CT1yhnn8wlcK4YhIY87HA8vcZombG53CtgEABIY4yY7kCqloM7KlkoJpQKz0ulvxgE0DD5sXFndiKvvY5UZ51ncSwkZFaSkNYQ0CLkLdB2MecDEQthCJJ4WG/XAqFUIc1CF1j8lIHNjUUw5gVl23JwFHFMS4O57Scpgkj6WOpMo8XTfmmcLJShKgEQ6h6Qu41bYkVM2l0Jzx21ELsySEqX4Z2LdrWFPA8nan4rEgw8po2psKGGDRAKILE9fTgo8dB6XWWLZbU8dhgHD2FJ5pKTxtosfMCMDIvTnjDIMbvWdpskJa5K6TxrpUEvTU3E+AWVu6QlSImzHEdWVNUHRlAFWZVAiAgW3vWgJjWEBNmfsmqUXxppVs4/3vV/5Z/enlLAdNZTD9hCtj9XflaVknjB19dnxPPOTjptVHrEerNZ+O8fNVTgFIiX0YM7qbXGZCKCuyQMQmSMnUBIwTbWikB6sJPUqLPnm5lpQ5oJhs3eL3M3+FpvtLU6FMBwKUh3Awx4170FDIwR7KB/u8gDo3pByPp9xBJRBcodx3KBWxjiOOJ8PePnypbt6bDZbbDZbDINccz6fcDgcNf4ja5zbDgBhmgpOpzMOhztM04xxI8m9swrQjV3PqJHl8DqdTu5SaYLVZrNxtksjZGn58UYcjzNOxxPGcVBff7N4idY9EyNvBox5i/1uh3HIKLUgJ8Kggn5NpMyE2jEGathAQTx0TDtpf8fjY13bJ373175b+Vw1e/Hw+2bdJF+3vNp1spUlwIp1XH1maEunRb/nnfe5wADwGJsWA7MAs6G/lyPjABwNEJG6pZkmO128n9w60toFJyIxNzJmRinZwZvdl2pFqhVzkcT3Ho/nfZDUypNQqcWhFVablwIRs2pbYmki6tzIqro7xrx0zSLXeoOrCPxZY6/MggMAU50U1FeQuoztdzvP/Yja3ruMS7LcV8bEWMqMcymSPy+M95LgIwp3zC5GSfuZkE3b7dbIKIQxCCMsjxpzS3MQBcQoUBmgi+MZWTKNHMLqlBXlLJUPrU1NIIssoOV8xllJoQCgaAoCwCwWrK67AnwrV8zzBIbEq1V12QRvfG9LRMhDwjBmZIg1VFIiCFAAJXAR4dITRqvboAji2QEPqnomJFJrnDDhkWfHkPmRsrKjzjL3gCQWLrMeKyOnE1dNjYAkkmbEKZY3AAAgAElEQVREIdrGR6zdCUSN1ILREnBndQ8zIpYWz5lR3Poj+3nhnrp9sYS7cWN75iyAMxErkGyKmVplrZirai0zKlism53Cqd8Hba+QsIQhtLclQU8ka2wmwnQ+uQW2Fhn3mNYnWreiQiv+Huf4GjlJ/D0RiRKpVlmrRACJ1U5AH6NWUSZVzVF34WVhtqqgfFv7OxN52owl2FuupaWSsl9jrf2XQ7tChKOASRRlYd0GsGgKwd66265bFrfAoc2hV3nJfEMl3NraGs4piHLYvWq0molkPdq6GYYRu+0eu9sb8Imx3e4wVWCz3WOz3eN0vPvm6/hQ/rEqD4DuDSnn8xk3mxE5J2w2I8ZRtLPTdMbpdMThcOeEJGJdk2sFeB1xOh1Fs7sZsd/vsN/vwOrecjodRevIFZtxh3EU97FSmhBlMXN2+FisnWhlW/4bY7xkZo+1k8Nennc8HvD4rVsNclfrih4qwzBgzBk3NzfYqVVAXFX0cGENwCfLoGsCRTuwIgAwudKKHeaIV3YHDnf/LIWKWMxC9rrQ6lsN8F7lAvk671+6RCKMRfzu4rorz19qcWORGDS+6GKznNhhCHe3QUi22saarJ4IAkcUKOrloY8Q07WmUY4AKybw9vxt6jJpT8wpA+oqOFfGzIwy14u+aqyyxujXPu/ARcoXgEkDhlwQQWhmBOZmKbN7l6kA1sZt2RcAKagUlzvWPpZrWiJvuU8jutQaJe8cNEartrgmsyYmgrELuoW3FgjZY+urCBSXc8m+NwBie4URMy3p4aMFIrZfxpq9MyMpRCniPXBSJmEiclZhcye0uGCrwzzP2NqkjFuLTzsSF8GaURWoE1hcNLXuQrxCcDIWUy5wm+8pJVQUMClwszkESGyht7ECBOSqpCilwlK9JQVcYuESavohZ3HBrIC4w4v1zdZH7L9o9YgJqyVOrbHBWn/O0+zKPh0Uq7wo2VICqXUygn2bU6K4CXMBUNZGcU2txBgwqJuiATKNbVU326qidAT/KSVULqCkRCFm6U8JpRZg6kGXxaiZZY2IutgzSrSyptucjfuN99cC9HTKEW5Jv31qJSEzqZpMvNaCWiU+zhSstu4kBjZdrCdQv5fb+7p1E5Qpa4qba+Xad8tzoymS1snClvWLoFdc0lfedw9Ao7RuOVyr4zXwea349QE0R/ni8hhs55vsjQmTAtekHAM3N7eY+CxyXGFsN1tslLDuobwZ5QHQvSFFgppHDEPGOEoSUWZW98YjjseDA7bdbidWsJwwzxOOxwPO55MCvg1ubvZOXHI+nxycDUPGuBkxDCPKXDy1QLTOpZQwz7OnN5DUBUkBnbgmCINm7oQtA3Sn0xEf3X+HBpUndVlS7e8wYr/d4q0nT7DZjDhpvjuLv0uksUUuxJMzml1IU+wmO/QWIbq4nsMzmmBxxYK1eMXrQ7pvbVk7qJYHNPBqIOmHrfxxAebiu9aet/ZOuy5+R6SOrN61lyCxva/Jxy1m0Mys0E/7pM9rfRLrsgQwNtY1XG/ulipGC9GFKgWiFc1yNVHKQCmok5CWMId4C46a/9pcEmtPV540HigCMukrcven1v5eCIptWv6+BNfL8evALeBxg7UWBTuynmMScCsxbUPbF0rnwnU5Txr5C2pjMYzPWbL9XWubuaRFhdGFsEa0CkgcsKIHdEZyMp3PwvKZUpgbvcVVAF/CHGnn9X++h4S65pxRcwbUTTurq+QwDOo+rqCtWD6/KkoIoGOaZF0YDDTyHo05tXoSAcVBqrIo5uR5BYGMnAZ4wmwiZ0BOqdVb7u8BsVseFKx739ZmobL0ODbX+/UNb4OdCVE5YJYzB3Qh9lGs0Cz9RazgM/l4TAq+h80oVsQkIIZ0vcbzy/op5+zENNb/dcE+GcGdkSNFQFe5kSgt3QLXrFyxP+JcX85TX6f6U0oBqxu0rEl5V76wpvXkN0vgafvcNSVPVAit7fXL65f79+uAIpsDyzav7VF21lMtr3z2sr4peAdcs9bHdtx3Vq71hysa0ANCsjOKlvVt70wJKJOw9OaUsNlucHt7g8MEbDdbzJWx226w3YzCivlQ3ojyAOjekEJEuL299cS+tgG9eCGMljEnnFnRpmlyVyUjOdnv99hsROtzOBwwTZMLVOM4iGazFrXcySFpicLtADWXJANszQ3z7OyapkEnIneZMs33drtF1dxgJrBsNxtNYSDWw5wS7ubZD2XUKrENYHF/cfm+xcbZ72azAzMqy8baHz4NsPUb/fqBdA3MLL+PY/WqA+IPs6zV46KdKoSufveK8jqHITMjQYhdGp5bA3Ov7rMWedHu9YPb4tOqWZrasxvYQouVK5ZkuuVvMt+YTMaq2ILfrT1Ga5iYMQxAmksQTBdAFb3A0glhKWPUtRsBRtUX1ioWjTxuAF0zjXExBQt4SwFgFvIIwqz9kQTBadqZAaoYkLDZbjvrlQE6G8P7LA2dhXExLvG6cbPxfcS+X2PcW1pWrO1EhM1m4xY6Y+C14tcH4bYBuuLWUrvWhORZ3fWs15Z1j22OrommgWiCXAN2jfBEdykiibkalMUz5CFk0hgmJUIRoFeVwETmYYsjFGuaafzjvItgoqWdaW0gCICTa+H1IiKkxT5wqXAhj1u7jKslEPV93sZ5oSJbvT8CeVXiLcZfxpW6+ez3k1lhqyonKpIC9wjqGNUtdKwgTuZ37Sz8Fs/HtYJLcVdn69Ocs+S0rKVT5DRX6+p1XwNJthbXirWjIzwhc+EsmGf2/rDzXt6xboHrLFd0aY0ioubmuwJe1p6x3BOWv18rDKwqW+JzAbgSgqFreu2ZBGd3vWhTOCds/twH7OJnEQyvAdmmYFw7W6WVtrRM3pAtvRE9zUXcfGspyCoziUWZlKXYUmb8/6M0fih/+OUB0L0hZbvd4d133xXBQ5nTSil4/vw5drsd3nrrrU4gPBwOOJ/P7iL05MkT3NzcYLvdAhAXzmfPnnl+msePH/vB8PLlHU7HM47HI8ZxxKNHj7Ddbj2Z+fF49LQGMRfdBx88BTPj9vYGNzd73N7eoNaC41Fi/ADG7e2tPuuAaZ6Q04g8DHh0c4MxZ+x2G9zc3GA6n3D38g43NzsAwHQ+izZMtaspEcBi4VN9LlwKAqDMGbqNRqByn/XNhCGg2YjWrpNCi0uuHWLXrCXfirKq1X3NA3n5HFr8/bp1XQp9vbYy1AkKpoKRlExr70PQxktuXL5DOv0awDBygcZyxo7E7KCtFSEvl4W8MYZxA+XSbnVOJhBLvA6zkAEVrqJhRevr6D4W258oKR09Owhz7XzKyMN4IfCVagH8AJCwyQPKPGGeJxdKlhp1U+KcTie3YEWhZA2EsXZAZUYeMm7Hrcj3SWNcI8g04ZkZRYGg5WIDVOiyca4VbuskQhoGZZAEdtttFxNngM7GOVrtrK+iZdOEWAOzZhWKYGsYBiA1EpVG3y4xcVFzb4J1HkbsdlsQJUzqhRD7yp4xjqPk7swZ52nC2fIXqkBcShESEWWCNMDgsXOAEs+o9bZIugywgLrC1YEGAGyGDYYkKV8sV54I7uLqngcD0exrY1mi25bl72OG5y4lBAEWuABZVmqtKGzMrW3fabGhgbafrc9nDEPBqIpEz9lmiy+ubYICJwV0iZo3hwvljMIV03z2NdneyZims6ZVKELQo+vElI8gVu+VGWWanTVVkENLeWDhAyeS2LKsAMOUm8MwYCA5Y+YQU2eER1yKMH4mjWHMWVP3hP0l9G3KGZwuY8sKKzlLTt0ZZ6DT2k9u8WzxkAb0Uk6r740AZamMieXaPVFRu1ZWLX21ufPGEpUkojTzWSHfBVDm55P/9KDSwX/4O55ptp5tb4nFlDzXSt8X8mOyBUfwZvsM7FwI/cqkHgvC7A1mYQjmomE1g5AoJUK6sPQ9lA9reQB0b0ix+DjTAM7zjMPhALOG7XY735DN7dGSfaeUPNWAuRYZqQmRxATI/STxdCdxtSyl+H1m/TMKbrMW2uYnh99BAeAt9vs9xnHA4TBhniVOT6xvewBBcNNA/91uiyFnjQ0Uoeg8nXGDHQClmWYGoaqmzg4VU4IxHDEAiIK/lQbW+nJ5iJG69dxvdTKsuLwqgppviZWOLq1SfX0X9bry2VKYv7hmoZFcO9SvvfsPAlLFsso6hNc1nv1n9UJYYGbX1pId8dye4UK8Yzy519zH8rBxLbgdwKTWuuV7ajEroOb8KqUBntAfIigRGBlCSz90gC4Cwq5PqMX2tIo0YSIqbyI4uQbc7tOot8+EwAPheqsHAAd4YIkDq0RCFKEud5RSW4ssrngIcTn2vGY16q1xUYMehXTv8wC+7O/oFhfbC/TJme2nlApQ1fithYUxJwyDWArnABCXihDzPkg546BeDElp7ykPsBybXAXQcS1OQ5/NlZKBWgrmMjuhCunzGWKhNZBXqAhLZNcHQEomuA+wuEUsBFvpA2uD7QN9fxal9TeLXgQFl5aKxZ6QSNqiyhGiluS61JCEHqQguBGqECzJcrBs+3/bD6Gvy6wpLiTusHfNlLNR2T4X83+1BIURETSXInXnmll1S2oKlEGBmbglJwGOEFsrEaHaHAxAPykoXK9HY+u1+sR/LTVRBHRxTfUKipY8fAlm4jxejrH3/z3nxNJNNNZ32c8dOAvFyE2W13aA8sIlv1mZ186h5V5233m0PJvjmbd2bq9935d1RbF94zrFri2kSunm6i9jJ2y3mQjiNcy4yKn3UD605QHQvSFlHMfuED6fz3jx4gX2+z12u527HqWU8Pz5c0wa/xZj2QA4C+XhcPC8cqa9ZG5sckCLPYjaadNcmctTZKAzVrP9ft9cNGujZB/HAfubnWpoK5pIK7F/mZQVryqV8zyJYMSm0WMMEC122287u5L+wx3rXf/v9cOKuX3fvOOvFxN2BUd++zZdWqDGpaC5PEzvFWDWnq+HKTzJdv+e1y2vOkQBPfaW2spwzbVHNM0mK9lBL2x6O4hQU4Jw8UmJ1gQh5WBPA2FJ6U2gJ0qu9a5cwbPEbVbKFwe7AYTZ18ZlWgdSEDQoyUlkw9MG+T29lc7+FdfBWVN1mNBtP7Y2I6gx98V5njvSlAj24u/meioXFp0CPePk0oIY94ToWmbfG/CK8YL2b7TMxWct6xfvtTGJdY8Wu8iAWWsVa1jurSEpJc05x+4yGEui5EyC8zThfD57u6ydANw9HaqIUMwPsyiRaeZtXKrkX0ycASad+9XTWkxlFitEkoTqVfO7uVqC7C1r60IsHkZ+EpOjy/dxbxCPBk5t3jfFWkUeJX0Do43LUnFQqyQ61+SFMp7VrBmmBNHY0BySZ8uU8mcKbmwpKPRuVJh1kL0dyzVHBAeRhOTKt24OsjBpjnnogQK357aK9f0QFQLGoMpUHHDH68Wi369fDu2K9epiIV9RIrCQtVCBOiuAb+7QkRBIrpdz8r79f3lOrAGk5fVr18bv1p53rQ5W9/sUjGCZD8W8EVLznOjqyaxkQa8P6OL7rp2lsT1r51TXRorSAqO5X8PBmLvCcnuGpyeZxUo3nY4oKvPIHiKkQVeW/kP5EJYHQPeGFHGHNAFKYtwOhwPefvttt7zJRp8xTWd3hRjHQQlSsggR06SslyfXggtwy5imlu+JiNS1SIDgMi7ABFMTJlvsXHaWTTsgxY1GCFeMXdM0m0kP6HEYJN4BqrmeZJOr1dyWRHNVVUBm09j5ZsuqCWNJFaMMe5fFNmL5KwrXzSpzaaG7etDJl98QgPpmytpBuqY1fNUhvWZ18L8V0EVLyX3l2qEZD8XVawzMLQ70Zkm4vIGD4GWJvl1Qs3GQB7lw3T7qA+MZ7OyAdvqasOaHOFqcEAGNcU/fYfOjcoyZWRckEglYjjFN0QpYuXdvExAYYrSQUIqkJ7C8XEPOyGoNYm5udCLwDR0gsn6JTJMNBLbk5wCA2txIIxiw31NIncDMmCbyGLQ1i2Fsl5Am9WO8Nt5x7pg7VySnWArVdl0H6ErBuL0kiRmGATX19/qYUaPRN7BlgHgJXAfNI0bcciGmZDFIDdAZqBNQQGBKANRttUgewlJKSMguFixDiQ4ibJ7771JhAeSMxCwJpQXhyRxHo1Jnho5dYJ1UQViIPQCq5jIWx2xBXW9gP9Ql4XK9rwKAIMzmROCckR1ACcgWhQ1EUO+sNBGEtflFkHb17xUAMARCn64dUZkUqlf1rIoAzD+vzWIe2ypkP73bop2ry37oFTnrc/7aZ7UIyI0KmhjfKvWp7j6+dgYs13KsXxy7e8+IUJbX3Qf8+gc1BdOybv3z216SrtTTLGCxTveBumvz9D4LXbz34swlORsMd7X1qt5A8Ufran9uRrXqzhOm8wnH0wHT+aTkSOKSaWlTHsqbUR4A3RtSkgZxT9OE8/mkVjTGZiPMl0SWZmDSdAJVGTFHBVcCAo/HE87nE2qdsdmMer8wfxmYM4uexRycz2dM0+TfDUMGiDHNZ8zThGk+o9QZ+/0Wu/1OXFBINa5chWzl0Y24VQ4ZDMZm3IA1CNhcZlCVdbBKDiWLFUwAiKtol2FCCIfDuLk72Edr2rX2u0T3LAXLy79fpbGEW4ri87/l1rrF2RIP0DUB6ppm8b4Drj99Xn2Yf6MlapvZ3E+42R0I0HxoaxrsNhas1o3KWMT+WBvsfeZKSZ7EGJBZIgJo9b9lrpKCGs3dZV+gkTA0pb6AX0rNhdfrsGizt2BFqFvOzaVQijCOleydYnnKaj2fS5I4RLVgg0ThIe58IuR7YttqJDDFBcTleJuFSupkAqoBMwEd0gSzbAK15k74Nc2yEHcIlXopswBxkMb2pdDWdeVDtDzGeW2xc0OIRzKX8KWlb03YrArcWn3NFZc9f9qshFI2ZmZ9jZYWI2LJGhuXSRRUa/NX+pZRUJBcgx8EYgdp8H4CJRDBc8chMVLOcNNz0hyIRc6Cypb8uAmWpTAoMZKCtaoAT7lNG0lRsHjHObucn9Jf5EI5Qv9as2ttLq3WfylJonGo4kHuB/KQkIyLqFZQVZbPYOYgIo3JNPCuMWq2XplRIEAWSZSKiQjjMGAcxi7thvR6YNNMGcjatjL7GHdglhngluswkg21FbS+L6+Bo9dVvsXv5tIUrcy9K2V7TnMHvQ+U3TfGyzrEEvdwG+dr71ne1z03KO7uf2dcH1cf35U10Pkqi90S1L7uWdeNn2RzQaqElNj3bFH0tJx4VXQX4oY9iHL7PJ1xd3iJ8flz8ZwCAZQxT5LjssvL91A+1OUB0L0hRQ4yof1/+vQpSil4/PiRWuVEO/zixUs8e/YM5/MZ2+3W49zGccTxeMSLFy9wOBycCOWtt55gu926cHI8HlBrxe3tLW5ubnB7e4vj8Yivfe1ruLu7U5bMHXb7ndfFXDtLmfHud7wrLJxJwKVpl25u9tjvbzAMvavIMGScT0dxcwGJe2aZ1eVSYvxevngB3u+x324AdUEy4VWdi1BVGy2CUgMlnSbPLQZ2SMAP5zVg5zKWg5DLg5YokEAsDrtvZSGQJ+WOh/jynWsa0lj39TZEq5S5g7UDu6vH4hC2ErWtr1M4CALSPggQUUC5Fo4urmgVzAWlspI59Fd2wglUtqVLN0ci0sSurEKzZKMSBnlGHhIyBowK8ioz5tryyp2V2l4scoRh2GCDhEjVLtYrJTAhQmIBh9HtSlySGVzW3LNySMQO5EROrkEK7PIwYhg3GkOVG4X73FICUE1ikaoVsypJTHET3TeFNIFQzGUP6NaBDlH3O2AEJNIeeW5L6C593/YnGxnJF9as49ZfyxQJx+OxI12w729ubvy6OOZ9zFPFoJ4LHaioFaUIeY7V0+MfYcA+UNXnjHHc4Hye/Dk2nyTdy6zxcxmz5dUkbgoLAoackFUmrbUiaYqXlAbkXPQ6WeOlSt2qplfIOSMNo4OcPIwYaAQplmI2ayurEqNZgSclbDGwZcyW0g5JX8BsFlex+MaYRevb6G5/Pk9gvR+A0+F3gLlWlPPJQfMwCHtymWbM06ztF7A6DJJKQQCVMs4WzTOqqRXEGjr73C2VPSWDvWOapC43t7eiOEzGGNgnSrc56Bb3QS2sSQgoiPo+ZFU6JbTzoBHszO4VE+dxtIDL3pUu5uvSddruM0uzW4KzpDU5pzPK3NZ/W29NySB9lbDZbBbtBRASwa+dDx0wW+zz14B9KS2Bea+wu1RUxZ9ESede7/od3bqJCInaHsi+Ky2AMwxUtzrHPfh1rHVLkHvts2Vf2Dja+S8gTq3lLClvGECiilQTuAq5TimyDrabvchdpwkpjzhPM54fzkh5RBpGTNOEYRgxnU8X9XgoH87yAOjemGK+9MUBmYExQDaU0+nkcXXRwmYHhglHKSWn/Lb4EPvOwNY4So4nA4BmndtutxiHAefp7MKbbOyQ78ZBN1WJKRqGrLnxlHEvAduNCqEkOZOq+MCIZa4I89N5OoM9J5CQp7C5SqnNJKnVxjXelow3eLasb+hRr9quWytLF4se/PXa2eW1a8+Idbp2aLTnm1vTeh3X6nR/u6+3D2ggaAkaY93X6rj8/v53xngD/avJ+u1ZHJ2/Qv3Cdct3mcuWaTVLlTYMw+iU41JPi8doIBJklN8U3CvlM67V8yA1YU3fp0BUnnttzIX8IQKY1n890cAaKLcLIzgByfsTtPrhnrm0OBrbM4gkZ5a/mSDsgQrmTHDKLOuRtKPFkNQLXmTgm9SdFNyNCVFzFWwW1H5+LJUFS/fHJaFDBFPRhS6CdSLqYunWUiEYAUEksenWSUCsTcAUhYJZBi2GeZ5nTPOEVCvKPOu80X4lI0BRMLlwH4R9njI4VQcLzJaEXSxqrP3MbidWK1ES4MjdWmigo1PUMNRaan1prtUI9bCE8H0843LPEvKWkA6DL60aTvLgieaDm3GtALc4PXuGz5vUqOqh8wgspFjTJP1diyhZDBR6H+gGFr0mrD72fFaQbfMzdqAxRS7jQe2sMQudKZIsVtNAcARxxuQo7xBiGx09qXN4d1Ro2fU+b4Krtlm2rGn2vkZmI1bP9bPlcp9eFg5X3qccXK7LteculandeUT9dd5nC8UAUcv/uXb2XdYa2geqYCz99a+rdFwqPtfatyztOn9K953h5EZYqe66RVymj8cDkAiniZGHgqxKGsux+FDejPIA6N6QMgzZNZTRf94EjFIKDgdJD/Dee+91THJLDaXlojMrgrk2MjO22x2GweilRXCptWKz2ShL5Q0qF9fo1npEKbNrd1Mit57M86QgT1j9xjFjGAc8vrlV7fYJYMlP5q5O84zT8YDD4YDKQmc+5EHddeA7ouE3YnHrggteFucj/Xaflu3aJs3MEuayiKNbMnzxJS68WqLQGDWSy/qsWdHi2Hn9Qp2WB1U8TF+nPoDbLbG8ZRn3EQ/dtecvgWBsi/wrv6eA4pZPSYCzVVqZ59JSDSDQctszWKwVczEiChMgyOPbPIbItQHWcmU+jHFrDHdRqyqctj5LsBj9EpKFR2KUCEySWdM03sXyr0mH9IQj/v6F0FM0D5bRnycilFpwmmbPg8W1gdmUNclzLUKLbcIxAMoJGUny3yXLRdesCahVlSzaB6WGmEN431MS90WrcwKJSygZvTpcUcPc5nPlS6Bg+1oEbZH0xD6L1gcDHBbPNs+z5+ADgMfhWvv+cDjoHLm0TJgyI67PWquSSyXs93swS56/4/Eo6SvmgkKz64gIwGa7wTgM0hdm0eMm7EtuQU2VkIQhUdzAW7uKJCL0hPQIahABVqysiC1uS4Bb7+poZFpEsW8HbSuQOFqYWl9ZXZdU8jllIJw/JjhHl1exalfdk8VKu1TjIPZ1+DwlYByzrjuAS8F5nnCaznquzFp3wrgZJUn6EM46NMA1KDOoW6ttfRE3wZpZUxyIgE3c78cCqsgBXYyflPhyGYeUs7iFapw6WGLB3XJUZEzrrPGmapmvpYKHoQ0vNzd0LhUl9FMEOnHtxO9KIV9Lr1IYxhIVGksSFwfjK2DOFUzL54SyPC/EqrWu3OzIY6QT2jsR1+ry7LoEYqsWvXjfxfrvratLZWbsB//+ornsa8DvB0GUhdZWSZthbugEwul0wHmewLRBHityZaRSkeYZx8PdqwfwoXwoygOge2NKy/VjAlVkuTNgVkq5yD9lsXcxKe92u/XDe1JGN6KEcdx0GkeLIzGLX84JPJeLjX0YEnKOB4hpyQfkTAAqUh6dpOV8PjXWTD905cA+n88OMHXb1w1dn2wa1qDsa1pF3YCjBnRxqF0De34vmkb8fksaq7MnLg6Ka+Wa5WwNzF27f3nPUji+Vtaua4clALNWAVfbHJ+xppVd1mmtjRTABasQE+UrvzbcWxdtszEWOUilU04Sh0MkRjiNRWptaWNr1lyzmDArIKFuRgmDpVqbXdDlYDkJAmMECQYI3K1qaK5V8XsiydF20ZeLPmbAc8K5pa9Wj61pApklVJbcU6UWd0vrrA4mHKorJNcGApjZQkK6sY0CTkoJxARWq1+cv1F0r7XKOKTIAqhxWOG5kXQkjnEkl7D7l6AlWpRiXzg4Ks3VdJpnlHJpIZQ52QS05fvEygTfa23vksTh6PqGa/vd514UzAXOmZFY+6HNc09yDzQXxLBebdzaclBFhWi89PPmtlcr+94mwM5cHJWqP6eAv3sG0SiwN0AUrH+Ilry290sdo6VLxt2+B3rypbZ3J2AAqApde+EisdXqqdHGy/b8fqx8zpEQ0Fy+Q2enKQY5dH4ADVbGcZQ8cuZOG55vewEgaTzY5mJlYR5dSc9hfex5GvU5F/ul7olxbieKih90dYn7spH5dEySJDNuqXBbnhlL69zSq2B57i/btfZvGzPde65oQeN7l+Ap3nJxbmP97DHF37J+1/5efr58XreeV9oVnqDzqO3JvouzCC2USONZZQ6XeUadC2hIYmal5OM/TQ8WujelPAC6N6QIaUnzW4910vYAACAASURBVF+ycMVUA0ATnkyYubu7c5fKFpdQXDiR5K/jRcyBCVmWkFxy/DSCFiI4+YpZxohC3MAgu1mpAtxSSh1j5qxxRmU6S1B6Kb65gRnzNKEMWbSwSTWliZBMAEf0vb8fiLTN+Vrg89JCcv+G79ah8Pl9gMrqsTwglt9dHIRXa/LtLde0ra8qa23ovgddCE7ywvirWSUu321VWAPAUYA0wcGSFLdnK+OgCx7yPltDVkuGJs8u0QJX1HpCDp6qW6B6AditMwuWvSgspSzJhqMA0ykv2LTa14WJKMwtP18KR3adC4kLgS2CpPisNeHMrosuU0uFRRS2/b2lCnHLwt0x7mvLHHR2jSmY+vlA3fjbc1+8eOHgJAqhFs8XLTdG8EF6TU699XzZvqUGP76/xQ32IMP3U3N57J4JBwedIAtg1jxxZlVKREg1N0QDA2zmNrxcI2bBju+KY6mui+gtFFfBRijmWihttbYnr5vPv9r6IKdLZVtUMLS9vIH2c5k7SyRzU/osAcZyHjrA8327gcOEwNjJ6gYXFAOWEmhQ98443+39sS02d6+txSW4XOvb2J54n/WNucfG98RnLdeu/FK7v5egrrt2eW+4Pt63VIpcA3LLYjkXl33RKavUJbEUydFoe+jFu9Dq8qr3vk6xesT9cbmn2fsFaK6ddaKMcBmCbS4DIO4UEU3M8B1f55POUY6KkIfyYS8PgO4NKdN8Bs9HlFKx3W6w3W2w2Y4AKs7TES9evgCI8fjJI+TBNHgVp+MRh+MBL+9eeGLvzVaYLaf5jPN0dBcNs9wRidvk6XTG+Txjv7/BkydP3DUzDwkvX77E6XTCdiuumDc3e3WBY6RMzTUskee+224H5HwDZlb3qRGn4wHTJNa6RM09Jw8DdtutHLClgJS5LGURthIIWaFBTnowp3Y4i/a7F3RfBUbkYLFDg6EE2t0zus07gMiL71af3R+mywN9qQ1c3r8saxrRNUHidQ5a053GPlsDqPcJIvFdrwZ18lPC335Em8GNLt8NSIwSMyRps6AxGSkiyaVF1N7A0ETiQcirzZWtBgFRyC17i54c3IxSgarEJiYcAdA1MXlC4fhjMaopSYzaUqAT4W9wJUx03ZyMDVCvFXBDagVsrnusdYqpGea5qJCeFYyaICaChaUosFgt+84SHxOEuKCBAYtblb7KSS3yKaGSMLfZuytbzGsDuRL8WsE5gzlhLgxauBBbv8Q4QduLzOqwdKmMAvR+vweReB+Yt4K5jBsbJRFh3GwEvHBzNzfXRNJxyjZ3Kebaa0QcDRhKXzWBVMhCtpsxkGAAQK8QyGn0uTCXgmmeAQeSYr0rrNY5Bs7nSVyUdTwoEZhGMGWJH07KWZl0Ltg+KF9KKobKrqCorH4FSfPSMYES4/9r72ubJMdtNB+QUmZ1tx3ecNxd2P//v13E7p1j7ZnpqsyUSNwHvBCklNU99uxe9BSfiZqqzpQoiq94ABDY962zPtqYjKROrFIAIIrFUntLngjd8hwTtkfSnklyPnKt2DuPgOTnxhgAZwZniY5J6Yus+zlp0nXWXKoSKIkg5znXRYk5evIVx5mF0yIiSW1gwVdyBjP5PrfvO67XqzyXAFT271r/W+G24kiZiSSgCemaKutbVASQu3CmlIPHAkvkUVm03NYDsqBAFrwmpFRob6htXY+kbiB049+hkbr5OJKtSOZGi3jEu0oAljP2dl9M1h7JVCntyMdyWTtrvf/m+N59QBQKSr3vQXxXm+OxvLO9sHAFl2MZlAiWfST557ZuAAsIEps22POYQSzjuRY5liARv3dMfAxMQvdBIK6JzQq3rpI+oLkUbSqYXPtFUc/X5Jzw8nLFy8sVKclGbPnqQBCSeL24Fmzfd9zvd1lMl6vkbwra7lIsiErC5bLier1oTc1H3JKesj5na9pwSl5eS2TLctYoZ+SUsOaMcllVIFJhAPBF2qJLujYXwZ7Dp/Yf3Qh+O1sXc7TP2WdH8jiSubPPI5k7POc3q3Ffx1iPs2d8S4Mb77frnv0tf4Q+MkHONa3waxDqN9bLyRpBXP6sB7TPScP/CeGzfD5jMm1gLyLkRkLHkHtl/ggZiaRPK+Akw9xAWwqNntD1ZK4RFRNMxuibToqqpO2wRzZru52n6q8/3FsqJMFwc8NuUfvavfbe1Hi8EIvWPTBS2xogzEUSdz3LSVdKI0DWRhzuE6J3tBa2+hwjBI7zxshGbOd933G5XLr2PLNwSB0Lam3WuV7rbpaBJmCNhM7q0n40QFNwh42WOSPF/fiN7zsKikGh4NfCA0dJ0mGzQiYNrmF1l3Z2EmGpNcJ62CxWyZ8XxwMGAfggyAbL30jCqfuuuEuZvpVb7uxcWj1TDA1rqv2dVeBflgWFgcxylpGM/ECaq80ns7jhIJQzarOghvbOS0aipXvnfd/xSASumjMsuAZ3Y1utNfYOtldZB1pbmGuzE0Jqrpw2PpgZldq8BoSsWnqMMb/qURH4XOF2hk7RGJ7ZWa+H694jbM9Io499DfgTy4tzxt8LbX2t5UmUzsFD5rfEt8p7T/nqVjg9H+KyC5k1HYgu3tLwJp+YIk3duetZ3OeJ3yMmofsgkLw7zTfeNMCu0d82vLy8SNoA2xTCRrauKz59+oSXlxc/B2JayHVd8enzC67XFz/cbm6aQuhCyGXVbtv5EbO0XS4XQCMCAlCi1/LhmOYXaO6YzOyuTcz6ub7fumTU66pR/HpCIDpghIWxF0PeI0dnaNfHBfz7NgcjE89wtqE9I3dPrVui0P3V+DVt8Ayjm8n3lvnMQjcY3d53J+V2kT+byIUwsRboOZ6BINTKKHuvtW2/WXK0VXbrHQBQWkTBwLLpNmHw2MWmWY3vOxK5SOiSxZlHCzTh6QLCfG1unS1R+NiOoxXWPotkyCxUo1vh8/4Lgj3OXYfPFAFGohpZau8QyZ0WAKYqAYeCVnos11z44r3RQjSmqwAk0NNIpEbLQnPxbgnEY7sw2NMFWEJwc0c3a2a0IIrg1s6nHclcPDN2VOCMmv+eKDYLUFN2sKRaQ7yXfKyyKxaOZUUrhrhltnNvhJZr0NyT6cSiA70a4T0INCS3tiMAxQPtEEkwFUmvkVo00JSQAtlBGHduufD2aQFJiOWs4akgHT6zNonknZlByXL79X22ajRcq4Ptq8wVVQMRRXi/hf6MioxnPxYkrO+fHtFKxMyH6K7AMU9jcpfMY+qJ9wjeWId4Lm/8ztrsGdmJ1z8jdsER5PQZ3uf2DFMe6LQf8wD+VnhmiXsPhF4ZSu3FYK6WqmkUMpd0D5RBI8/1Mlj/VZXsaZql6XL5YTAJ3QeBuCTCyVyMcGmLukWBO1u8l2XB5SKpCO73u29Wpm20FAfxebfbzTXfzBrkIWWUurswZ0nIl2XBY7uDubp/v1jhxKInFjpNfqxCUKJmaSv7Dl419DJZnqQMLru7n5zBDQuAXuOrZfj25L6gTW44YRuH+2j4+ttsa9zkzojRmbBsn8ufv46cPRPcn21YJp4ZufhnnjFuykcyolY0mBDaBKKorIx1ihpjv5bUxczYvO/74kpJAGptZCwGK7F8XTw8z8cP90EexI2wH34mtFqwEYlU2Fvh/PycW+eSC8JRYAelo0voWDkguDNabdWqoFYPE17F1U0Ii5AWsUSa9oOSBe1oOZyYTXiOwWf4dJyeYRzf9mPEy/vPhd2e0I2Ia9poacNwj13j7oxhTbzdbh2pbeXKu0dinXPGtu94qHvmKNyNwrH3oSuV9HyvDhCu5TBlXRinUeEWLCvqgpdyc42kZFFDGzHr62gW4xb4YiT4vfth8bFKSBCH2hbVslkIjrnBTOSMbdGChcTnSjCedm/CYn1o49T61zvTVgjux6VGzaxVAmcJ4db/nZDhSACJTPkYiDOi9fw4row4AuYZIy7CtudGQhHXDKtHRBxH0XX1zOplv8dxJ9fHesL7pzvPZwQCxzX82Tz2dciueWeOGeLcHMt/RhK7OhA6K+N7SqamPMHpeCRADVt9TktmxmlC02/guGf13x0IqGmToxjgbaCVo3ZvAnXWdjCpr78RwPjERmgnPgYmofsgKKXgekkdobPAJrbA2jk4CwwQF6d4jxE6y9lkhC6n5C5d5nJ5vV6d0JnwsxdJVmsRK63c2/0VYrVbfFPcd9EGW9JhNDES7n7AwLbvuFS1yKGlH9h3biHo39XHNdc7LeFwhWmqT+92MtjKO9Osd+UBz4o7xbhp989+DmaIa+J3CNf/POgpgY0WhO8u7WxjNLk+XEOqyRQxsV32tKeUxBF6QcwFZCujArWYUGQ/1BUTyTJDD+vXVi8GuSXH7iXSZOPFXPDEQsGaEiESutHlEujHUUpC5uoQNTaSGH8mVz/DZQ0khHBx165qNImO54co6bkOJwfs/1W0+SVrybkkFPv0TDFwsF65oB+CpvjvfjaPQnUngJ8QqXjdGWkrteJ++9pdb5ZLUPI0KzFPZ60V97sk8c05d8oNI1yjlZNIzlcRzHOAm4vUSb2lLjWcIeqFYkoZlGW+J417kpKmkgjTr18/QiCT1LdRs5RGIbyAqOVxE1LXomKawu3cUkNuUTACYHMp9ltUogjpa8SjKScGTYmXEyJ46jWl7NhTQioECRQB0do8WaOJRNFiZLlbx1JIEE+NCIhlmHyfszOYXCuIs++T67o2S/FA/EeBPxK0M+VEX+dza1UsRz89fN9+o8O3lDJnJGVUtIznKKMyItbtPTJ3eGZ67nkQ28pdxQHfOJwcmTJLButhXdjLrzt7dvYe32or35NN6WqLge1r/k/qFNisaUmEyJEEY9KVnLq9eJRLJn7PmITug2DbNnz+tz+626QlubWcVuu64nq9eq4kAzNrBMulO+weI8mlJJEnJRIZdWTPLHTbtslml4Bte2g9rvjy5Q9qFWRs212J3IunOCBadBNvQQHSogI0kea3u+J+e8V1zVg1SERdVmy+oLKwvpDLRRZ48h2MTxY+ChtA+21U4bhImuYTKhSfbUmHjepXaM/OtJ6jlnMUbPXq7jHPtKNjPb8lgPf3m7B2rm0dy31P43usvz5frWdMLQ9RV64RlVBvSRfXglTEd9m5dq6WDLRzTogh781J164jF3ArN6vUtolrnbVHs3ZIHaPAyyxaeyEm1ib9+0dBSGObdRp+cUOueLs/usivPr7RokMaGYlWhNi28bfN6SiQm6LHEAmQPEM+r6WgBkLnaRdy78Zlgvn9fnelUIyQG9vrKNQO/U7NbW+0btqPeRJY1MEz65O5kFsE3re3G67X68FrgUgii16vV1/7Ho8H3m43vL6+IueMz58/d+3IKlE6IakV+75hWRfN5dfeqQ5RNUX5tfp7PR53d0Gvfv7raL1lFpf0dVnBpaBAgoE0ny0NDhRILfGR9JpgbH2c8xrS3iSACXt5+F5hlrAxdYEI4knnY3tfJoR5Ig2xLIvnFhXhuoBvNz2/LZbjWK4HGPF69+Qgs8w7IVHy/MvlgpUI0DPZ/bi3s6qt7X3u5BawCNwIy+32Cg6WODuaADDqsoAITuZM4ZlgxLH1tdXDcgDGnzhPxrU5tkWcq7ZW2F6/LC2/YZz3QHNJHhUrFCxiI/m0ZzfX4yO5sjRC8TObk2cENM7vcX2yM/SRGBqhjmsFkY0jVhf0vpxq5xapJ2HfIrHvIY6T2G/REhrbbd+pKW7CO4sFMuxjSQxx5FoZ9RRwZaNJJKIuSSx7S+VjNNGJ3y8mofsgqLV4UBOLHkkUkqguiy/0VTWXogWWv5clK/9pm4pdvyyqoWaxOmzbDoBwvV47N0yxEuyaVPUSiGVyYdo2EiFzZ+dK2M/HWL3X9YL7TSKWLVkFQd2M2wJ6JFgm+Jr4GwlcFK57zaHd3ZMDu19kCaMbZ6QvaOyZD3X6HrxHss42onZJv6HZ9V2d3inn7Jn9dU2QelbGef2OWuRTQmeC2tCXbRNWO92gJXWB0cuBjtXgSkXkSeaZo5ZTyWrcdLnVqQU9sU07alzlD9JyoqAViZBSOvTjNRA7bm6e5hboJK1UPB6bkzVvN2puRlIOmh5Ctb8EcndKDs8w66Wdz2ua7qRtK65o5gpqbpskL3bo3zF4i/VLJDfA8yT0sY8ZQCoS/o3RrHqSpLlXasSyo9Bp68foSmeKKCOrRuaMLDKzCsHJrzehfd8lOfhlXSVCrwr8cUwchVcbV/aO8HqPQuCyZBXVRLm1l9JFgrR3HIVcU7Cw+3aGlYmoWWTV0mpHdqxCSa1USObqaoQj+xrLDNRd3VYHQhcJZkoJGdFV1xRrkdDJB2KRCHngmLG7soTVIiik9NTygf5skpx50/mg49zSfcDHhVk/7exRq0t0k+zcLLUwCv1o5CLWvaBgSxKt2cbZtm0SFdYCfJ2Q8nEPGslaPAM3kr9IHLjps3Sen62z/T4Q5x9z+37cL0ZCdkbozkhF7K/x3ce96Pl+8O39MAFgIow18PvaCz7df/4Z9LIBnb7HuNbbZ/K7rd0ivxCI2C11bYCH/Vj/zWweE1DPpomPgEnoPghMQBGSZQlLgVIs8mV2omeaIU+EDISD64yck18fz84xW6hgcam8Xl+6A+8x4IFZCi8aTri6G1GM9CbWEbPs2RrvWlQAS5YzeDFpsxNCoIXfVqE8WnaEH5wTonGzaZ9Byjp1YyAAlsT0/Q3BF+93r3p+X9y4z3AkRz3ZeoaRcJ1tQk/r9o2yTu8JZY+a0fEd/drwKlGjKmQEbaAAYqKDuODGczfjOSstrHm7uHsl9eUN9TP3PCN3x1ceLAVZ/OBSrci1otoZT5i8fU7oamnE0bT/pRQhdNveu0caGTu0sUl09h5qKRnHEg3aeSLkpHMcLZw3wYJVZFCycvRcRxAOx3NDY5/G/jgjfuPfOTcXqqZcWry82DcjoYueBtFiaZa5+NnL5y/NEqNlyFoFv4e5pS8AgMv10qWSOBUwvbw+umPESOgqFyQmMIuFai+NwMf27M/6sQuqQlxEuWF9HLi9a/OT/TuQilYn+UnJgpO0hOKVNTXEtjmhi/V3i16w0ImFRCrRxi/5mm9kyspnLw+eGP2M/ABtLbL6La4EaUR3yRlkgYUU22ZWbmji9F6pSOSai/5B+p6MPnG4k1Ew8GAfLzZ/V81RN0Zeje0e959RuWm/x3E2zqN4XVPejMq58B6h7HFNPkPsp7Fuo/u2Xf+tn/jMrk7DO522wdnefVJvVyRQX9a/in+2jFGBJX8DUDInYx9yVhbsUZ79ftNWcLPOTUL3cTAJ3QcBM7v//igwEqFFEAvkywQWInJXpZjLRTTHiwo9GWBCrTv2fdN7rprvRnOylBY9b1nMzUUOlmNvC3LTQqqlbLTSoQm6pAFUSqmopd843NWJNVAKoPJ5v/E3ftCEnDNCN4Z7Nlhx0lYJ0KxbY/uP/066Or9He842hjNB7lvkKWohW72PGtbvef73YNyUW3ldjbrPzslQ2LDDJ2OtTMCPQiBBuQUkdw+rtaRy1Txy1QuKwpoIZc3SQeg11bUyHurytpeq6QAsb1oGIyGp1F+qjWlJZs8MDyFR0RQWdiarc12qQKEClAomOW9j49uVI3vv2tYJoMH9xyeCEzLTOwSrjlolslrjm+WtJx0m0+YsUWWXdRHrRmVsZe/aX3LTiSu0ta1FgKzMyCmr0kUsfd2YYclR16IDyoNzbZadpPe5qxPDz1eZkBzXLCNoo1Bs65IRM3N5s2v8bJ26OdZADmycrMuCZb04ad+1vFJ2VTYsAEnE0pSTBkFhJUlxzB+FS3FnZ6QkpLkR1dBcoZ5u5WOxvHXzJMwXNmLfnRkm/4mWp/iMnoizpKgppZ0ZDf0FEpJGKcsPghIGcCujtacu/U6OjJgyTKBtFjVJRJ4PfRpJi8H7T+chpYTsZUOtrQ+JsFllnqSUcblesKRFFYuyApnlI2l/EgHr+iIqPXeplTHFOta3fUepFcug3JAARAVAy4MaXSK9V07IThwj8dz7keDFe9nXt+heKetknxh7fGYs/4yEsY6BiHheTuqSXLkyvtd4fjb2ZxydZ3vg0CiIOrmU88mpeMBs3C4DcNNHFf1399yTMuyyOF6j8tAm6Vjng6LN/9a55/Y28Qmo8RsylVrtbNGMKmlG7Lma03PiY2ASug+EMRIlANeKL8viKQCA5n5k31twE9M89oRuFQtItU1z9yTjpikUga9tcjknrGsWwke6sAZCZ5prInG9kQPMTWslGtumQa17C2xgB4ehB4eJJHG4LYIAXNbo/va1lFQIkQ/bZhZbbtQGc1uAiTR3EwW2Ihd2FqmTPuo1pkctpf09bmSjJtXuPyOS43ffY0l7D6YUiG0yCoLtc9k65dH9Jq0SJtr2OmhMuRHTTksbfg7P084lSvAIlTVqjWVMmCAFb+PiAmZ4KzDD3Yq33Sw9dpYsIWUIoVPyXzz/EaMmoCqhFIsIi1AJdBHwLDiKBGUhrUuzNMUk03up3Xx0t8LcgqiYNds2fntNeVWzLpbwliL8xMh4KYw9myJZLeHrIi54XCv2R4tamCBzNychfmyEjkj7smLJCeAEJLuPwnzyHtT5qYQuN0Ji5aeUwKVKgBaNahjdUNs61Lu9SrHk/7ZE4QC6tC6lFCEsnhbCAoXACem6Lvj8+RNSykL4qwTEqKVIQDokIDXXT05ALXunVDgLxmSWpVR7wkZETshHS6crIyxpeOtcKO/Vz4PU21o6CNV2hhGwuypXEDcLVCkFj8ej1RdNkaKsvuVS1CTYXmfA0xNEC5oN1EZsW3u0cd4HEIrtZWvtuEY2Qi5zDilpGoPauc9awKKcM5Y1A4tYoc0lO646ppR5ebli0fPiloy+lB0FIfXBzlhTO1daubqCiXTUmweKWbso1N/e83tIXYSfr5PGV3e85hYLwNcey0/bkTAKtCEMKCcXYQ7VUrrNMvbDM8J6SuiGdT6MgNO+PUDrSdqmdg4w3mu/LWunNs/wtPYXodVptBrWQOQ82q8pDJ7+ABZUiEBqcdN9kG1ERHrXnp1cOWfXKIGDzE9U1lyqk9B9FExC90Hwv/7H/8Tn6wuWvLiQt2877q9v+POf/4y//OUveDwe+PrTz/jjH/+IDAJVxkKy2Oz3B/L1iryIljmDwHsB7wXLesWnlxcx8RfRsD4eD/zyyz/EtfLTnzSKpWwi5q5JKggxVz/k3wSTpmEXSwph3yS33efrF4AJOa/Yt7ufR3jc7liIsC4Sue/Lly+oZceak7hCEbUcdAAgpjsRHFT2MK3eXmRDjsJCTF9lAoWFcbd1mAgumALtszNiRRZkLRC9M5J1tgFZHd5zU/FNNIu1xoSvqGGNZUatayxjtASOLjkAUHZGTFore0ikWU1QbNsTR9rWpHQpGGACISGpkE9ZNqettsA8gG2kzRpL7p8r7mmVGYkW14RzraBKuKSLtmHo4yqkYF0y1vUCrozHY3cFx74XPLaCt9sD+16bZRgAOIFSRUoVKUvgjMvLi1ieckIFcN/FJVmIQRXFx3rprHOsygorv5SKygSiLO6GzJCE50bMjtHvyr4NWmLgsmQsy9qdbf35559RawFx9dQk1+vVBTNrm6SKEWQCYUFJBK4FZXuggJEvMr++vFy9+6CCzXZ/oDw2aRN1b+NSAa7tnQnIpDn3fAwxHvvmDEQE+Izq57mAnDKWnKVvdz3DpePh56+vEngiJ/zpT/+Gl08veDweXa7Mx7bhoQJ4rRVMhK0U8L7j//7Hv7sCqlkxGhHMy4rL9YI//uEPIA/oQri9veL17RVEhJWA5Xpxcp64ggoDVQjsvotAL+VnpAT88ssblmXBly+fnSzVCtxuD9Qq/348Nrc2ptyCUTz2rdVXXRx3CxaRCGldwLWiMOO27ZriJQEpI68vAEuOxVI3HZNh7uMIIR4Vl8sa3BnVrfiSXSlnq+7t/ugJpyoFJR9eQko9iUh5ATJQcyPoa245VPfHjpwZnGSfKqWK9TNlXJcFrPvI42FHCy6+75hVqhS1WJWKxKLOWNfsgYCYK/b7DYUsl13Gy/Ui1kGyfpc22/a7HEW4LlivC9JCShKz90tOyZfFSkARrYC8v+5Fey24ONduc/uxb+D73dttXRZ8efkkc97OgO4F98fmpKmlP2FbmEEAlkRYr2u3dqQkpCIBWHR/yTljyc2FuLAqk7YdO3ZXhIlSI3dnfG3smNIlWlLvt1vz8KGWqsifE5QokQQyA4+tuUYDsseNefasjMO+BiO01WmSRTSFPZcrFg55KPU5WxErq1iLNZopAaQKPVJGSInkPLFrT1iIbkoSkdKVXsk9RSpX1J1RHzGKrfR/1X2g7DsICZecsW0PWUNRQSkDuo5y3VB5Q6nSBjnMqYnfNyah+yC4aKQuoC10EnmyD9JgWrPo9x41Z6Pwn1VII9O6u+bVpGv53ROapnU1H29beO15o9FodCXRUl347dwbWA73kxMHkmTECWBi0V6FZOPcMnX2z3y3RfnkinHh7MnMaQknZO7pEwdi9VvgGan7tc84Xjp+cFbWsc3jd6qk1fKFxATTUlckqTbTIkZ6stVYCODmA/K/tRhj5GjWI5jFAO27JlgsEO18dYJRilDUCnGX5FJB24Y9ZVBJXu3CmrWL7CwRA6j+G9Dk5SFAh6UGiBaYKBSPhM7e2Pp1zc3FOSfV1IOR9AfEruGtej4LmoOuckXZ4G6cBEZOkn4BGuho2ySiojsQx/lo/QBuXcEMaNlsczHJmRCuol3hyhrx0bpOteO19T9BxulCGcimIBgsVlzx9vaGbd+ctMa2sVyYoyKj7ruTv44sa53yImQyadRVSUWxoZaCTARLPk1E2PeCslcX7hiMSubqacFWRCi0elv/mxuotZ+tu6NCJ6Kz2rEmY2dW9yt2S0lT0Jirqox7Gee+nIYRdVwzvC8SgSu1PtDb3KbBJxZEVdiNngnjGhQtOvG73qIDtUDKe1bAPn+DYAAAD7ZJREFUFYPyXWgje7HwmZQjpLJZ/8gtZYkAC3jrd9GxjNgH8X28rkrorH+KnYckIaZmVbL3jkpFAlBCgjR/P+Dpfi3jN1pj+3Z+bwzZ77F//Bx7vD+J/arbjwfEz8d+HxWIYyTdUPNDueMzxnc5e7/ektlb36Sg8EM2dU3GgHscmC6Swc0yjeZS7Be0B7dxTeKdwDZH1YIvQ7M5S4trL+vYaVFi7cyc7I/oLYiwMEoTHwWT0H0QrCHsuAkL9/u9W/gjobONAOitVFHzZpts21QDMWHu1t3zBb7PAXWGcSG2s0rm1tCsMyOpC/f7auyV0ac3UicXQ4WtM8en7wcrU7NqP3cN4VCl8w0Q3/n9P4NvEbYoOH3r+ZFnGfFhJ0nPn2d9GT7pnhmeoJxANc0EfyChkXJzAWL7Jm7u3NxXQqnxse1PtjM9Y/LhhJQkGA9BzjTVau/AKCrAVmZwqeBtB6WqLmfm1qn1N+swt3QJUs0+zYC4aArifLGAC+5OFbTTxNwN62XJ6hrZCJ3Js0TqkhwIndelyrMLAUBGJrVAmwDNFbVICghOGRc9d3bsZ5N6eiFxnBuJ2QNyMIvVpAmWSR+ZDxoEW4t8rEItt7WKFe7xcELHsc3UKmDu4W4hZcbb16/e1qMQa2W4q5+SiLLvqEXOVi0xdQISHnXrz5+BsW+qyDIrB7Vk9pHQ9SQnHfo8ztU4X3297vK6NSIc29HO5jEL4auW60qFRrNKxP5qpEWUGZYfjND6IfyvI3Nn7oHPyEW0kJ55JowE0IKoiGWjiJ9uHIs+FI9EBWC0M2ciSLe6aZN11WvfnyHWPfaPW250z6oQwp/C7mP3HoLTuAt29fER7+naolYl5+fummfolKdP1v6zfmjK3P79z8bNGaEbx0ecf6HAw3vE8T7uV+8pKP07AOMbuqLv2f7NUXHhAoepFdFtLSE1Qtwsk7n8Vt0LCEiURfmsBA1EomRgRuIE944Pco5epnPPPo6MdOIjYBK6DwKLNmlnQB6PB27q8mAkbgyKYiHSzwIJRELX8kcFDVsnmMeFMIZT7hdxu74TTIfNIp4lqrUFQqnqK95vPuQJkZUNGNtywcYW37F+/x3wjeBAat65h//r63dmpYuCVxTE4u9vaU7fe158VsTBGmCaZuqvNw09w0i8XNzIXFfoyAdCXVqdJFBII1M2NjMIyyLEzvLQQUl8KuLOFgNzwDTZpgDJOAino3Y6Cv4jopBDSVJ0RAF/JE+JCMu6SlS/YQ7He0w5M44xq89YZ6Bp2d0KMhC6Mw38e9/H54ykj6umK6jGQvtzoNESIl2+Olnatq0jJN6X5hqrCq9I6B63m79vFMij1cDfHdDgOC2dSnR3q2UgsCJ9uWdCymkgHVWsemV3gT0qz9xl/Qmhie0nxLY4qUupD8Nv18b6MxGynpWTcdRHCz1DIgJS9udau5wRg3EcnL3LeF38bhTYSVlq4qbMsVXACOb4vib8IpQrbRz2oUQwP/xxbxrxnOzSwbroeyg0+FB4T7OERwtYVHgSwQMeidKpEf5IsmIdKvOpkvIZgf4WxmelFM7Cg7txEudkbB/7Hff+uP5FwndG8M/WxnE9+dY7jOU/219ZyVtXLsVRNlLCYY85qb/8TqDQNK3dWKPpcruO1HpXzXPkHGHpn/hgmITugyC6Um6qsb7dbl2eJRNcogXAImPGgCjj+YcxIfBho0UUzvp6xQUcGA+5HxfbqL2reiaq1bcXmsgXXKsbuUaNhjo0YmL1/+fJyffsje9tPOcbyr9uofu1ZXTa5OHzrs1AXQjzeN1ZHb5Vp5FEduUwNDLf8Qygb7AnhM4SMI/v0NUFsU/gCgIR6GSDTkkER2agWmJXux4VlKr4Xla48kQfqHm7JOKaC0KD8BXHd6eY0PeL35ngNypc5AXIz2okIixZ3C3HcRcFMyM4VmdbC0bhdLQYnGrRQztHJcyoLBiF/DOB3b8DPKANVIEwkj4rl4iwpkAuqQlLnSAa3tu+E4tWTyztntFaZqSseQ40a2EjYCLs2pqVkp6VguSUq5Wx8NLVn0POznhfm5O9xeeM0IXGc0untNOzwCu9Yk0iPVpONtH0PxOkvS6BEI9j56yv4jtEt8q4z8Rx+m45MHdGbpZ6bgG17N74zqCwOxDpHLG5ru6PdE5gY3lnYzq2ZfyJ3+eUcFGrcVRo2Nwb7yEijwbr7RA8aez3cd89zr1nY+fZGh3H1nh/JHR2JnTsW+vXWMa4ntnzYt8fXYstGjUd+/M7cEbknvVr+OT5/knU8Tmy/SnKEKEf4zONy49rDYORlNDJu6obMBNqSLXErsU8vMEkdR8Qk9B9ENRacb/f/efr1694fX3FX//61y4lQc4ZP/30kwt1l8sFnz59wrqu3SZrm43dFxOpllK6CJT2/GrnN3zD6VeidZWzLEYyS9m7hbyUgtvt1shc2TUQQtEw9Erukp3lMRe5pIKzRt4zcV+NStRZe/71VZDZ1vdopTwp9+SzZ8LZs832+yr0XCPeV+e87KcWE/v9xE//PQHBcGadHcvo7icbMeEcgtcPQmROCF3r13PrHDMHzSb79QyIlZctnI5s1Sb4+Vk9BogK0l5A+wbsIVKslu0CK62NFGmxHkkxkJ9Yd5lbzU0tJQmrn5cFi56PjUKKBfcxIrQuGTUQL+tHs8DbPE4puSu2zWu7x66La8V4zuVMaD0TmmJ9o8AYCWbXNzYGkgQSYQBc2veRfC6a2HtZZXvLOeOFPvm1TrIhQXBY3c/j97VWCaKUWsRLI6dd3cEe0CnnBWsIcNOEegmEc7/fwcz49OkTLpeLnov8WcK8B6K8LIvnxCtlPyjQmNtaZ/3tbceNlHpbaj2bkFyx70oKSChby8vXiKOdQ5N3rc1NEzj0DwC3QI8WzAgLmGEgIlwul44AM0saBHM5jeknetfD3t1YyJmlpsjISSLbllLw9thO1i5ZJ+y8nJQjZ2NtzkU1T1zPxmAbZ3tdvCaSktg+y7ri5UXSHVh0TGuLXfO5miLBPGZoWbt2iEqg0WvmrJ/GMfOM1IzWvmffdxZ7tFQwEWeKKit3dBkdSbwH/3HLO8Dl3Dp3RrBjHd7b82K/Gdn2NtJFvpWrikUbE2A5Aweru+bR5aaAGvd2ZlbXyqNSK+ncNFlCXDM9Cha8kd1y+EQumKTuQ2ESug+CeBi9aZQZ1+sV6xAwRaKqtXQGMXddXNxHjXqniT+xrsnvPp+bLdryk4NgmVFr6RbAuEm6gKthnyM5MuHc7ms/+m9PUGOa3N++vZ+RHKtfxJnmc/z8vxOjFvHZNc+E9V/7rO95XkR0uXxqLXiixSVye9dJZeR/4Wo5a0aiGLDPKiT25pHQ9efgrI1qtQANKpg/Yuj6Ck6LR1M8I7d2FsxC8QPNDTAKuVEDHJMl23eaWambp1aWCYE5ZzweD//M5h0ANItTG5+dCyD6+TYS/0MfDcLkmXBsBMHntMozVmRUIkXiQ4lAtHZ1MTfYLp1BzkiDNc4FusvlQDJH66S4QDVhMV7bFCCQ83WBgKWcIREH2S1KhqYgqxjXWiGuff+NZDrWr32u+TFDeS5oAr6uev26dVvqaL04CuSOoPAZfyLO6hfH87N9JSpwxmfLPTK3rZwlZ0juvoS3x4YRzNwFpWp911sYx+VirNMZcRqti7H+Q2ESdTe1KMTxLGjvsaKEuOuDo1XQ5qO1lbXNr8H3ED57N++HwYMglgUclXej229su4hoVR+fO64z43ej/BGfM65P45iN62q0uPmaYilB3HJGmipJ+8WMZ0rOuvawcaFBdZ6tkQBaf7P/49lFfi2Hvey9sid+X5iE7oPgf//7f+J+v0vI6/sdt/sdt9sN6+d/yNka1eQSEf7+97/j9e0N27bhlzvh8y87LutXVGaUfRd3zftdLGa7aMMtd8/X1zd8/foKQM67/PRacb3eUatY10RYJLxtGdfrG3ImlFpwv92xbXf89LXi610W8H3fkCjh7//4O/72t180jHVG5f9QjbKETb/f3vB//vOGX+4Jn66bBCOAhFVPSfNlqcYswUIVy+pIAJCa7cVAbDErWk4837eoF7jb5hA0ZSTldZuha9PCpYNyzcoGegHAIuvpFhGuC0R1ECqaFQG6aVgkxbjZUbjeNlJyoTgFdyNWwW43Ul0Z7RxBQqsedQJqeH3dmJpwOFp3LOAGUeuluFGBWSKVat8A7DkJWSV+c2eze2TcVi/HEgt3/SGPUQczK7N427kpTduHuRE6u/d+37HtO3a1dmz7hvtj82TL0qYJy5r8XXNasCSzdEkfGGEdXZCKBq1IlJBzxbIwUi7IS257PLOeq0sd80mABOyo9ob6/sySIHwtHlr8drupULz4mCESV9HswlXy8RAhER9bv4lbtEVWbO5vPgNtnFq9dY5b/5cgGFtfbY/q/eTEOAiSZkW8XG9ef1P81Mqe2sCeSSnhcrl0da614tP16mOxuVxu2La9G7NcJd9YU0i188rWf7fbHa9fX8EAvm6My/WByoy//fSGUgveCmG9CJE2S822PWBng3Pecb0XXN52ddPsg6X4WT0uTga9P4jcilirWNqWRcYNQda64hY/sdpawvc2hmy9VLIcrN9mlUhpAaXsbrF72WVemnIPOmeDUoUSYV12PVvarGr3+w2Px4ZdvTBAkqIiCvfMjLyoRSu4VUaloK0xP7++eYAfI54yHyX3WiOUSV85Ejo7a2ejvCc7jZTKBaW0M93Qd3ZrF+DjkLlizYtHoN62B7bHhvWyYllWbI8Hrpc7liXLmltlroKDUgvwc+Q+13OW1D2dt4Otmf3abn0Z+wTtNZ8rv4CgOGllMLP0u85X+9zWmspV21IsqZEkgeBRdW3spiw5cG0fkrHWXOi7/WFw50TYT6xtIsEblQ1RAVdKwSWtvlZZALa9Fh1mQugANO8gXaMZFmSq7VliKZb5EGUN3uFnW+W5tc17tD1rL1X2lVpQipx3fbtvmoqnAlQBKuBcwh4nbXV/tCBXE79v0GTvExMTExMTExMTExMTPyb+lejsExMTExMTExMTExMTE/8fMQndxMTExMTExMTExMTED4pJ6CYmJiYmJiYmJiYmJn5QTEI3MTExMTExMTExMTHxg2ISuomJiYmJiYmJiYmJiR8Uk9BNTExMTExMTExMTEz8oJiEbmJiYmJiYmJiYmJi4gfFJHQTExMTExMTExMTExM/KCahm5iYmJiYmJiYmJiY+EExCd3ExMTExMTExMTExMQPiknoJiYmJiYmJiYmJiYmflBMQjcxMTExMTExMTExMfGDYhK6iYmJiYmJiYmJiYmJHxST0E1MTExMTExMTExMTPygmIRuYmJiYmJiYmJiYmLiB8X/A6sYiKEJe8ZLAAAAAElFTkSuQmCC\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "#image_id = random.choice(test_set.image_ids)\n", "\n", "image_id = 8\n", "image, image_meta, gt_class_id, gt_bbox, gt_mask = modellib.load_image_gt(test_set, config, image_id, use_mini_mask=False)\n", "info = test_set.image_info[image_id]\n", "print(\"image ID: {}.{} ({}) {}\".format(info[\"source\"], info[\"id\"], image_id, \n", " test_set.image_reference(image_id)))\n", "# Run object detection\n", "results = model.detect([image], verbose=1)\n", "\n", "# Display results\n", "\n", "r = results[0]\n", "visualize.display_instances(image, r['rois'], r['masks'], r['class_ids'], \n", " test_set.class_names, r['scores'],\n", " title=\"Predictions\")" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[ 56 446 2261 1372]]\n" ] } ], "source": [ "from mrcnn.visualize import display_instances\n", "r = result[0]\n", "print(r['rois'])" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "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.7.5-final" } }, "nbformat": 4, "nbformat_minor": 2 } ================================================ FILE: Image Processor/LICENSE ================================================ Mask R-CNN The MIT License (MIT) Copyright (c) 2017 Matterport, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: Image Processor/MANIFEST.in ================================================ include README.md include LICENSE include requirements.txt ================================================ FILE: Image Processor/README.md ================================================ # Mask R-CNN for Object Detection and Segmentation This is an implementation of [Mask R-CNN](https://arxiv.org/abs/1703.06870) on Python 3, Keras, and TensorFlow. The model generates bounding boxes and segmentation masks for each instance of an object in the image. It's based on Feature Pyramid Network (FPN) and a ResNet101 backbone. ![Instance Segmentation Sample](assets/street.png) The repository includes: * Source code of Mask R-CNN built on FPN and ResNet101. * Training code for MS COCO * Pre-trained weights for MS COCO * Jupyter notebooks to visualize the detection pipeline at every step * ParallelModel class for multi-GPU training * Evaluation on MS COCO metrics (AP) * Example of training on your own dataset The code is documented and designed to be easy to extend. If you use it in your research, please consider citing this repository (bibtex below). If you work on 3D vision, you might find our recently released [Matterport3D](https://matterport.com/blog/2017/09/20/announcing-matterport3d-research-dataset/) dataset useful as well. This dataset was created from 3D-reconstructed spaces captured by our customers who agreed to make them publicly available for academic use. You can see more examples [here](https://matterport.com/gallery/). # Getting Started * [demo.ipynb](samples/demo.ipynb) Is the easiest way to start. It shows an example of using a model pre-trained on MS COCO to segment objects in your own images. It includes code to run object detection and instance segmentation on arbitrary images. * [train_shapes.ipynb](samples/shapes/train_shapes.ipynb) shows how to train Mask R-CNN on your own dataset. This notebook introduces a toy dataset (Shapes) to demonstrate training on a new dataset. * ([model.py](mrcnn/model.py), [utils.py](mrcnn/utils.py), [config.py](mrcnn/config.py)): These files contain the main Mask RCNN implementation. * [inspect_data.ipynb](samples/coco/inspect_data.ipynb). This notebook visualizes the different pre-processing steps to prepare the training data. * [inspect_model.ipynb](samples/coco/inspect_model.ipynb) This notebook goes in depth into the steps performed to detect and segment objects. It provides visualizations of every step of the pipeline. * [inspect_weights.ipynb](samples/coco/inspect_weights.ipynb) This notebooks inspects the weights of a trained model and looks for anomalies and odd patterns. # Step by Step Detection To help with debugging and understanding the model, there are 3 notebooks ([inspect_data.ipynb](samples/coco/inspect_data.ipynb), [inspect_model.ipynb](samples/coco/inspect_model.ipynb), [inspect_weights.ipynb](samples/coco/inspect_weights.ipynb)) that provide a lot of visualizations and allow running the model step by step to inspect the output at each point. Here are a few examples: ## 1. Anchor sorting and filtering Visualizes every step of the first stage Region Proposal Network and displays positive and negative anchors along with anchor box refinement. ![](assets/detection_anchors.png) ## 2. Bounding Box Refinement This is an example of final detection boxes (dotted lines) and the refinement applied to them (solid lines) in the second stage. ![](assets/detection_refinement.png) ## 3. Mask Generation Examples of generated masks. These then get scaled and placed on the image in the right location. ![](assets/detection_masks.png) ## 4.Layer activations Often it's useful to inspect the activations at different layers to look for signs of trouble (all zeros or random noise). ![](assets/detection_activations.png) ## 5. Weight Histograms Another useful debugging tool is to inspect the weight histograms. These are included in the inspect_weights.ipynb notebook. ![](assets/detection_histograms.png) ## 6. Logging to TensorBoard TensorBoard is another great debugging and visualization tool. The model is configured to log losses and save weights at the end of every epoch. ![](assets/detection_tensorboard.png) ## 6. Composing the different pieces into a final result ![](assets/detection_final.png) # Training on MS COCO We're providing pre-trained weights for MS COCO to make it easier to start. You can use those weights as a starting point to train your own variation on the network. Training and evaluation code is in `samples/coco/coco.py`. You can import this module in Jupyter notebook (see the provided notebooks for examples) or you can run it directly from the command line as such: ``` # Train a new model starting from pre-trained COCO weights python3 samples/coco/coco.py train --dataset=/path/to/coco/ --model=coco # Train a new model starting from ImageNet weights python3 samples/coco/coco.py train --dataset=/path/to/coco/ --model=imagenet # Continue training a model that you had trained earlier python3 samples/coco/coco.py train --dataset=/path/to/coco/ --model=/path/to/weights.h5 # Continue training the last model you trained. This will find # the last trained weights in the model directory. python3 samples/coco/coco.py train --dataset=/path/to/coco/ --model=last ``` You can also run the COCO evaluation code with: ``` # Run COCO evaluation on the last trained model python3 samples/coco/coco.py evaluate --dataset=/path/to/coco/ --model=last ``` The training schedule, learning rate, and other parameters should be set in `samples/coco/coco.py`. # Training on Your Own Dataset Start by reading this [blog post about the balloon color splash sample](https://engineering.matterport.com/splash-of-color-instance-segmentation-with-mask-r-cnn-and-tensorflow-7c761e238b46). It covers the process starting from annotating images to training to using the results in a sample application. In summary, to train the model on your own dataset you'll need to extend two classes: ```Config``` This class contains the default configuration. Subclass it and modify the attributes you need to change. ```Dataset``` This class provides a consistent way to work with any dataset. It allows you to use new datasets for training without having to change the code of the model. It also supports loading multiple datasets at the same time, which is useful if the objects you want to detect are not all available in one dataset. See examples in `samples/shapes/train_shapes.ipynb`, `samples/coco/coco.py`, `samples/balloon/balloon.py`, and `samples/nucleus/nucleus.py`. ## Differences from the Official Paper This implementation follows the Mask RCNN paper for the most part, but there are a few cases where we deviated in favor of code simplicity and generalization. These are some of the differences we're aware of. If you encounter other differences, please do let us know. * **Image Resizing:** To support training multiple images per batch we resize all images to the same size. For example, 1024x1024px on MS COCO. We preserve the aspect ratio, so if an image is not square we pad it with zeros. In the paper the resizing is done such that the smallest side is 800px and the largest is trimmed at 1000px. * **Bounding Boxes**: Some datasets provide bounding boxes and some provide masks only. To support training on multiple datasets we opted to ignore the bounding boxes that come with the dataset and generate them on the fly instead. We pick the smallest box that encapsulates all the pixels of the mask as the bounding box. This simplifies the implementation and also makes it easy to apply image augmentations that would otherwise be harder to apply to bounding boxes, such as image rotation. To validate this approach, we compared our computed bounding boxes to those provided by the COCO dataset. We found that ~2% of bounding boxes differed by 1px or more, ~0.05% differed by 5px or more, and only 0.01% differed by 10px or more. * **Learning Rate:** The paper uses a learning rate of 0.02, but we found that to be too high, and often causes the weights to explode, especially when using a small batch size. It might be related to differences between how Caffe and TensorFlow compute gradients (sum vs mean across batches and GPUs). Or, maybe the official model uses gradient clipping to avoid this issue. We do use gradient clipping, but don't set it too aggressively. We found that smaller learning rates converge faster anyway so we go with that. ## Citation Use this bibtex to cite this repository: ``` @misc{matterport_maskrcnn_2017, title={Mask R-CNN for object detection and instance segmentation on Keras and TensorFlow}, author={Waleed Abdulla}, year={2017}, publisher={Github}, journal={GitHub repository}, howpublished={\url{https://github.com/matterport/Mask_RCNN}}, } ``` ## Contributing Contributions to this repository are welcome. Examples of things you can contribute: * Speed Improvements. Like re-writing some Python code in TensorFlow or Cython. * Training on other datasets. * Accuracy Improvements. * Visualizations and examples. You can also [join our team](https://matterport.com/careers/) and help us build even more projects like this one. ## Requirements Python 3.4, TensorFlow 1.3, Keras 2.0.8 and other common packages listed in `requirements.txt`. ### MS COCO Requirements: To train or test on MS COCO, you'll also need: * pycocotools (installation instructions below) * [MS COCO Dataset](http://cocodataset.org/#home) * Download the 5K [minival](https://dl.dropboxusercontent.com/s/o43o90bna78omob/instances_minival2014.json.zip?dl=0) and the 35K [validation-minus-minival](https://dl.dropboxusercontent.com/s/s3tw5zcg7395368/instances_valminusminival2014.json.zip?dl=0) subsets. More details in the original [Faster R-CNN implementation](https://github.com/rbgirshick/py-faster-rcnn/blob/master/data/README.md). If you use Docker, the code has been verified to work on [this Docker container](https://hub.docker.com/r/waleedka/modern-deep-learning/). ## Installation 1. Clone this repository 2. Install dependencies ```bash pip3 install -r requirements.txt ``` 3. Run setup from the repository root directory ```bash python3 setup.py install ``` 3. Download pre-trained COCO weights (mask_rcnn_coco.h5) from the [releases page](https://github.com/matterport/Mask_RCNN/releases). 4. (Optional) To train or test on MS COCO install `pycocotools` from one of these repos. They are forks of the original pycocotools with fixes for Python3 and Windows (the official repo doesn't seem to be active anymore). * Linux: https://github.com/waleedka/coco * Windows: https://github.com/philferriere/cocoapi. You must have the Visual C++ 2015 build tools on your path (see the repo for additional details) # Projects Using this Model If you extend this model to other datasets or build projects that use it, we'd love to hear from you. ### [4K Video Demo](https://www.youtube.com/watch?v=OOT3UIXZztE) by Karol Majek. [![Mask RCNN on 4K Video](assets/4k_video.gif)](https://www.youtube.com/watch?v=OOT3UIXZztE) ### [Images to OSM](https://github.com/jremillard/images-to-osm): Improve OpenStreetMap by adding baseball, soccer, tennis, football, and basketball fields. ![Identify sport fields in satellite images](assets/images_to_osm.png) ### [Splash of Color](https://engineering.matterport.com/splash-of-color-instance-segmentation-with-mask-r-cnn-and-tensorflow-7c761e238b46). A blog post explaining how to train this model from scratch and use it to implement a color splash effect. ![Balloon Color Splash](assets/balloon_color_splash.gif) ### [Segmenting Nuclei in Microscopy Images](samples/nucleus). Built for the [2018 Data Science Bowl](https://www.kaggle.com/c/data-science-bowl-2018) Code is in the `samples/nucleus` directory. ![Nucleus Segmentation](assets/nucleus_segmentation.png) ### [Detection and Segmentation for Surgery Robots](https://github.com/SUYEgit/Surgery-Robot-Detection-Segmentation) by the NUS Control & Mechatronics Lab. ![Surgery Robot Detection and Segmentation](https://github.com/SUYEgit/Surgery-Robot-Detection-Segmentation/raw/master/assets/video.gif) ### [Reconstructing 3D buildings from aerial LiDAR](https://medium.com/geoai/reconstructing-3d-buildings-from-aerial-lidar-with-ai-details-6a81cb3079c0) A proof of concept project by [Esri](https://www.esri.com/), in collaboration with Nvidia and Miami-Dade County. Along with a great write up and code by Dmitry Kudinov, Daniel Hedges, and Omar Maher. ![3D Building Reconstruction](assets/project_3dbuildings.png) ### [Usiigaci: Label-free Cell Tracking in Phase Contrast Microscopy](https://github.com/oist/usiigaci) A project from Japan to automatically track cells in a microfluidics platform. Paper is pending, but the source code is released. ![](assets/project_usiigaci1.gif) ![](assets/project_usiigaci2.gif) ### [Characterization of Arctic Ice-Wedge Polygons in Very High Spatial Resolution Aerial Imagery](http://www.mdpi.com/2072-4292/10/9/1487) Research project to understand the complex processes between degradations in the Arctic and climate change. By Weixing Zhang, Chandi Witharana, Anna Liljedahl, and Mikhail Kanevskiy. ![image](assets/project_ice_wedge_polygons.png) ### [Mask-RCNN Shiny](https://github.com/huuuuusy/Mask-RCNN-Shiny) A computer vision class project by HU Shiyu to apply the color pop effect on people with beautiful results. ![](assets/project_shiny1.jpg) ### [Mapping Challenge](https://github.com/crowdAI/crowdai-mapping-challenge-mask-rcnn): Convert satellite imagery to maps for use by humanitarian organisations. ![Mapping Challenge](assets/mapping_challenge.png) ### [GRASS GIS Addon](https://github.com/ctu-geoforall-lab/i.ann.maskrcnn) to generate vector masks from geospatial imagery. Based on a [Master's thesis](https://github.com/ctu-geoforall-lab-projects/dp-pesek-2018) by Ondřej Pešek. ![GRASS GIS Image](assets/project_grass_gis.png) ================================================ FILE: Image Processor/__init__.py ================================================ ================================================ FILE: Image Processor/align_images.py ================================================ import math import pickle from pathlib import Path from random import randint import json from multiprocessing import Pool, Queue import traceback import cv2 import numpy as np from keras.preprocessing.image import img_to_array, load_img from tqdm import tqdm import cv_tools from mrcnn import model as modellib from mrcnn import visualize from mrcnn.config import Config def multi_worker(queue): while 1: try: align_data = queue.get() if isinstance(align_data, str) and align_data == 'kill process': print('Killing listener.') break try: aligned = align(**align_data['mask_info']) padded = pad_image(aligned) cv2.imwrite(str(align_data['save_name']), padded) except: pass except: # prints exceptions from another process traceback.print_exc() pass def vis(image_path, r): img = load_img(image_path) img = img_to_array(img) visualize.display_instances(img, r['rois'], r['masks'], r['class_ids'], ['BG', 'pp'], r['scores'], title="Predictions") def detect(model, image_path): image = load_img(image_path) image = img_to_array(image) result = model.detect([image]) return result[0] def align(image, mask_rcnn_res): top_left, bottom_right, mask = get_best_bbox(mask_rcnn_res) mask_img = (mask*255).astype(np.uint8) centre, e1, _ = cv_tools.compute_PCA(mask_img) # make a binary image to represent the bounding box so we can rotate later bb_mask = make_bb_mask(image, top_left, bottom_right) tilt_angle = get_tilt(centre, e1) rotated = rotate_image(image, -tilt_angle, image_centre=centre) rotated_mask = rotate_image(bb_mask, -tilt_angle, image_centre=centre) top_left, bottom_right = get_largest_bbox(rotated_mask) cropped = cv_tools.crop(rotated, top_left, bottom_right) return cropped def pad_image(image, side_length=512): padded_image = cv_tools.pad_to_square(image) resize_dim = (side_length, side_length) if padded_image.shape[0] < side_length: interpolation = cv2.INTER_CUBIC padded_image = cv2.resize(padded_image, resize_dim, interpolation=interpolation) elif padded_image.shape[0] > side_length: interpolation = cv2.INTER_AREA padded_image = cv2.resize(padded_image, resize_dim, interpolation=interpolation) return padded_image def get_largest_bbox(mask): foreground_rows, foreground_cols = np.where(mask == 1) top_left = min(foreground_cols), min(foreground_rows) bottom_right = max(foreground_cols), max(foreground_rows) mask = cv2.cvtColor((mask*255).astype(np.uint8), cv2.COLOR_GRAY2BGR) cv2.rectangle(mask, top_left, bottom_right, (255, 0, 0), 2) # cv_tools.show(cv_tools.resize(mask, 0.3)) return top_left, bottom_right def rotate_image(image, angle, image_centre=None): if image_centre is None: image_centre = tuple(np.array(image.shape[1::-1]) / 2) rot_mat = cv2.getRotationMatrix2D(image_centre, angle, 1.0) result = cv2.warpAffine( image, rot_mat, image.shape[1::-1], flags=cv2.INTER_LINEAR) return result def make_bb_mask(image, top_left, bottom_right): x1, y1 = top_left[0], top_left[1] x2, y2 = bottom_right[0], bottom_right[1] height, width = image.shape[:2] bb_mask = np.zeros((height, width)) bb_mask[y1:y2, x1:x2] = 1 return bb_mask def angle_trunc(a): while a < 0.0: a += math.pi * 2 return a def get_tilt(p1, p2, tilt_from='vertical', degrees=True): if not tilt_from in ['vertical', 'horizontal']: raise ValueError('Tilt must be calculated from vertical or horizontal') x1, y1 = p1[0], p1[1] x2, y2 = p2[0], p2[1] deltaY = y2 - y1 deltaX = x2 - x1 rads = angle_trunc(math.atan2(deltaY, deltaX)) if abs(rads) > math.pi: rads = -(2*math.pi - rads) if tilt_from == 'vertical': rads = math.pi/2 - rads if degrees: return math.degrees(rads) return rads def get_best_bbox(result): best_index = np.argmax(result['scores']) y1, x1, y2, x2 = result['rois'][best_index] mask = result['masks'][:, :, best_index] top_left = (x1, y1) bottom_right = (x2, y2) return top_left, bottom_right, mask class myMaskRCNNConfig(Config): # give the configuration a recognizable name NAME = "MaskRCNN_config" # set the number of GPUs to use along with the number of images # per GPU GPU_COUNT = 1 IMAGES_PER_GPU = 1 # number of classes (we would normally add +1 for the background) # kangaroo + BG NUM_CLASSES = 1+1 # Number of training steps per epoch STEPS_PER_EPOCH = 1000 # Skip detections with < 90% confidence DETECTION_MIN_CONFIDENCE = 0.9 # setting Max ground truth instances MAX_GT_INSTANCES = 10 if __name__ == '__main__': # LOAD MASK R-CNN config = myMaskRCNNConfig() # Loading the model in the inference mode model = modellib.MaskRCNN(mode="inference", config=config, model_dir='./') model_path = Path('mask_rcnn_model.h5') if not model_path.exists(): download_file_from_google_drive('1gJDCxx1cExbdCxhtPIFfBxa6F4obzRHY', model_path) # loading the trained weights o the custom dataset model.load_weights(model_path, by_name=True) save_folder = Path('../aligned_images') if not save_folder.exists(): save_folder.mkdir() images = list(Path('../images').iterdir()) # just a text file that lists the already done images in case we # want to stop and continue later progress_file = Path('done.txt') if not progress_file.exists(): progress_file.mkdir() with open('done.txt', 'r') as f: done = f.read().split('\n') # alignment and mask r-cnn happen in parallel # alignment uses cpu, mask r-cnn uses the gpu # this way we cut the time needed by a factor of # at least 4 # alignment queue queue = Queue() Pool = Pool(4, multi_worker, (queue,)) for i in tqdm(images): skip = False save_name = save_folder/i.name if save_name.exists() or str(i.name) in done: skip = True try: image = cv2.imread(str(i)) # image not available if image.shape == (81, 161, 3): skip = True except: print('Error in:', i.name) skip = True if not skip: result = detect(model, i) # if mask r-cnn detects a pp, put into # the alignment queue for processing if len(result['rois']): queue.put({ 'mask_info': {'image': image, 'mask_rcnn_res': result}, 'save_name': save_name }) with open('done.txt', 'a') as f: f.write(str(i.name) + '\n') queue.put('kill process') ================================================ FILE: Image Processor/cv_tools.py ================================================ import os import random import cv2 import numpy as np import math import sys from collections import defaultdict from pathlib import Path from typing import List, Tuple import cv2 import numpy as np def show(image: np.ndarray) -> None: """ Displays the image in an opencv window. Args: image: 2D np.array """ cv2.imshow('img', image) cv2.waitKey(0) def resize(image: np.ndarray, resize_factor=None, resize_to=None) -> np.ndarray: if resize_factor is None and resize_to is None: raise ValueError('Must resize by a factor or to a size.') elif resize_factor is not None and resize_to is not None: raise ValueError('Must choose only one of resizing by a factor or to a size.') if resize_factor: if 0 < resize_factor < 1: interpolation = cv2.INTER_AREA elif resize_factor > 1: interpolation = cv2.INTER_CUBIC else: raise ValueError('Resize factor must be above 0, and not 1.') resized = cv2.resize(image, None, fx=resize_factor, fy=resize_factor, interpolation=interpolation) elif resize_to: if image.shape[0] < resize_to: interpolation = cv2.INTER_CUBIC elif image.shape[0] > resize_to: interpolation = cv2.INTER_AREA elif image.shape[0] == resize_to: # resizing to the same shape interpolation = cv2.INTER_AREA resized = cv2.resize(image, (resize_to, resize_to), interpolation=interpolation) return resized def crop(image: np.ndarray, top_left: Tuple[int], bottom_right: Tuple[int]) -> np.ndarray: height, width = image.shape[:2] x1, y1 = top_left[0], top_left[1] x2, y2 = bottom_right[0], bottom_right[1] return image[y1:y2, x1:x2] def compute_PCA(image: np.ndarray, display=False) -> tuple: mat = np.argwhere(image != 0) mat[:, [0, 1]] = mat[:, [1, 0]] mat = np.array(mat).astype(np.float32) # have to convert type for PCA # mean (e. g. the geometrical center) # and eigenvectors (e. g. directions of principal components) m, e = cv2.PCACompute(mat, mean=np.array([])) # now to draw: let's scale our primary axis by 100, # and the secondary by 50 centre = tuple(m[0]) endpoint1 = tuple(m[0] + e[0]*100) endpoint2 = tuple(m[0] + e[1]*50) if display: img_show = cv2.cvtColor(image, cv2.COLOR_GRAY2BGR) cv2.circle(img_show, centre, 5, (255, 255, 0)) cv2.line(img_show, centre, endpoint1, (255, 255, 0)) cv2.line(img_show, centre, endpoint2, (255, 255, 0)) show(img_show) return centre, endpoint1, endpoint2 def threshold(image: np.ndarray, show_thresholded: bool = False, show_morphed: bool = False) -> np.ndarray: """ Main thresholding function. Args: image: 2D np.array show_thresholded: Will display the thresholded image if True show_morphed: Will display the morphologically transformed image if True Returns: morphed: Thresholded and morphologically transformed image """ # Adaptive thresholding to account for lighting thresh = cv2.adaptiveThreshold( image, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 51, -2) if show_thresholded: show(thresh) kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (2, 2)) morphed = cv2.erode(thresh, kernel, iterations=1) morphed = cv2.morphologyEx(morphed, cv2.MORPH_CLOSE, kernel, iterations=10) if show_morphed: show(morphed) return morphed def find_contours(image: np.ndarray) -> List[np.ndarray]: """ Finds the contours in a given image. Args: image: 2D numpy array Returns: contours: list of contours found with cv2.findContours() """ contours, _ = cv2.findContours( image, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)[-2:] return contours def draw_contours(image: np.ndarray, contours: List[np.ndarray]) -> np.ndarray: """ Draws the contours in a given image using cv2.drawContours. input image must be RGB so the lines can be seen """ clr_img = cv2.cvtColor(image, cv2.COLOR_GRAY2BGR) cv2.drawContours(clr_img, contours, -1, (0, 255, 0), 3) return clr_img def draw_lines(image: np.ndarray, lines: List[np.ndarray]) -> np.ndarray: """ Draws the lines found in an image from cv2.HoughLines() input image must be RGB so the lines can be seen Args: image: 2D numpy array lines: lines returned from cv2.HoughLines() Returns: image: 2D numpy array """ for line in lines: # visit https://docs.opencv.org/3.4/d9/db0/tutorial_hough_lines.html # for explanation on each line parameter rho = line[0][0] theta = line[0][1] a = math.cos(theta) b = math.sin(theta) x0 = a * rho y0 = b * rho pt1 = (int(x0 + 1000*(-b)), int(y0 + 1000*(a))) pt2 = (int(x0 - 1000*(-b)), int(y0 - 1000*(a))) cv2.line(image, pt1, pt2, (0, 0, 255), 3, cv2.LINE_AA) return image def hough_lines(image: np.ndarray) -> (np.ndarray, List[np.ndarray]): """ Uses the hough transform to find lines in an image. Converts to a coloured image first, so the lines can be seen Args: image: 2D numpy array Returns: clr_img: the coloured image (which can be used to draw the lines) lines: the lines that were returned from cv2.HoughLines() """ clr_img = cv2.cvtColor(image, cv2.COLOR_GRAY2BGR) edges = cv2.Canny(image, 50, 150, apertureSize=3) # Canny edge detection lines = cv2.HoughLines(edges, 1, np.pi / 180, 40) # Hough line detection return clr_img, lines def filter_lines(lines: List[np.ndarray], angle_thresh: list = [(0, 45), (135, 180)]) -> List[np.ndarray]: """ Filters a list of lines found with cv2.HoughLines() Can filter based on the angles you want to exclude. OpenCV makes zero degrees a vertical line, and increases going clockwise up to 180. Since these lines are of infinite length, this covers a full circle. Args: lines: list of lines found with cv2.HoughLines() angle_thresh: list of angle thresholds, each indicated with a tuple or list. For example, if you want from 0-30 degrees and 150-180, set angle thresh to [(0,30),(150,180)]. Returns: filtered_lines: list of lines that are filtered. """ filtered_lines = [] for line in lines: # theta in radians theta = line[0][1] # convert to degrees degrees = theta*(180/math.pi) for thresh in angle_thresh: if thresh[0] <= degrees <= thresh[1]: filtered_lines.append(line) return filtered_lines def segment_by_angle_kmeans(lines: np.ndarray, k: int = 2, **kwargs) -> List[List[np.ndarray]]: """Groups lines based on angle with k-means. Used to make sure we don't check intersections between two almost parallel lines. Uses k-means clustering to make two groups with different angles. Uses k-means on the coordinates of the angle on the unit circle to segment `k` angles inside `lines`. """ # Define criteria = (type, max_iter, epsilon) default_criteria_type = cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER criteria = kwargs.get('criteria', (default_criteria_type, 10, 1.0)) flags = kwargs.get('flags', cv2.KMEANS_RANDOM_CENTERS) attempts = kwargs.get('attempts', 10) # returns angles in [0, pi] in radians angles = np.array([line[0][1] for line in lines]) # multiply the angles by two and find coordinates of that angle pts = np.array([[np.cos(2*angle), np.sin(2*angle)] for angle in angles], dtype=np.float32) # run kmeans on the coords labels, centers = cv2.kmeans(pts, k, None, criteria, attempts, flags)[1:] labels = labels.reshape(-1) # transpose to row vec # segment lines based on their kmeans label segmented = defaultdict(list) for i, line in zip(range(len(lines)), lines): segmented[labels[i]].append(line) segmented = list(segmented.values()) return segmented def segmented_intersections(lines: np.ndarray) -> List[List[int]]: """Finds the intersections between groups of lines.""" intersections = [] for i, group in enumerate(lines[:-1]): for next_group in lines[i+1:]: for line1 in group: for line2 in next_group: intersections.append(intersection(line1, line2)) return intersections def intersection(line1: np.ndarray, line2: np.ndarray) -> List[int]: """Finds the intersection of two lines given in Hesse normal form. Returns closest integer pixel locations. See https://stackoverflow.com/a/383527/5087436 """ rho1, theta1 = line1[0] rho2, theta2 = line2[0] A = np.array([ [np.cos(theta1), np.sin(theta1)], [np.cos(theta2), np.sin(theta2)] ]) b = np.array([[rho1], [rho2]]) # make sure A is invertable if np.linalg.cond(A) < 1/sys.float_info.epsilon: x0, y0 = np.linalg.solve(A, b) x0, y0 = int(np.round(x0)), int(np.round(y0)) else: x0 = y0 = None return [x0, y0] def filter_intersects(intersects: List[List[int]], pad_thickness: int, height: int, width: int) -> List[List[int]]: """ Filters the intersections found with intersection() Args: intersects: list of intersections found with intersection() pad_thickness: the padding that was set height: height of the image width: width of the image Returns: filtered_intersects: list of filtered intersections """ filtered_intersects = [] for x, y in intersects: if x is not None and y is not None: # the intersection can be between the edge of # the image (including the pad thickness) # and the intersection can be between a third of # the way down the picture, to above the picture (including the pad thickness) if -pad_thickness < x < width+pad_thickness and -pad_thickness < y < height*0.2: filtered_intersects.append([x, y]) return filtered_intersects def draw_intersections(image: np.ndarray, intersects: list, pad_thickness: int) -> np.ndarray: """ Draws the intersections between the lines as little circles. Args: image: 2D numpy array intersects: list of intersections pad_thickness: the padding that was set Returns: image: image with the intersections drawn on it """ for x, y in intersects: cv2.circle(image, (x+pad_thickness, y+pad_thickness), 2, (0, 255, 0), -1) return image def pad_to_square(img, pad_value=0): rows, columns = img.shape[:2] dimensions = len(img.shape) if rows < columns: # image is wider than it is tall # to make it square,, you have to add height pad_height = columns - rows pad_width = 0 elif rows > columns: # image is taller than it is wide # to make it square, you have to add width pad_height = 0 pad_width = rows - columns else: # image is already square pad_height = pad_width = 0 # evenly distribute the padding between the two sides top_pad = bottom_pad = pad_height // 2 left_pad = right_pad = pad_width // 2 # if the padding needed is odd, add 1 row/column if (pad_width % 2) != 0: left_pad += 1 elif (pad_height % 2) != 0: top_pad += 1 # if we don't want the background to be 0 if pad_value != 0: # finding all edge values of the image # concatenates values found in the top, right, bottom, left edges respectively edges = [img[0, :-1], img[:-1, -1], img[-1, ::-1], img[-2:0:-1, 0]] edges = np.concatenate(edges) # pad with the median of the edges (which should be the background) pad_value = int(np.median(edges)) if dimensions == 2: padded = np.pad(img, ((top_pad, bottom_pad), (left_pad, right_pad)), 'constant', constant_values=pad_value) elif dimensions == 3: padded = np.pad(img, ((top_pad, bottom_pad), (left_pad, right_pad), (0, 0)), 'constant', constant_values=pad_value) return padded def find_bbox(contours): xmin = 999 ymin = 999 xmax = 0 ymax = 0 for cnt in contours: x, y, w, h = cv2.boundingRect(cnt) xmin = min(xmin, x) ymin = min(ymin, y) xmax = max(xmax, x+w) ymax = max(ymax, y+h) return xmin, ymin, xmax, ymax def crop_resize(img, resize_size=64, foreground='black', show_bbox=False): """ Finds ROI, crops it out, then resizes to the desired square image. """ if foreground == 'black': threshold_type = cv2.THRESH_BINARY_INV elif foreground == 'white': threshold_type = cv2.THRESH_BINARY else: raise ValueError('foreground must be either black or white') # threshold and find contours for bounding box _, thresh = cv2.threshold( img, 30, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU) contours, _ = cv2.findContours( thresh, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)[-2:] xmin, ymin, xmax, ymax = find_bbox(contours) if show_bbox: colour_img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR) cv2.rectangle(colour_img, (xmin, ymin), (xmax, ymax), (255, 0, 0), 2) cv2.imshow('bounding box', colour_img) # crop roi = img[ymin:ymax, xmin:xmax] # add padding to keep aspect ratio roi = pad_to_square(roi) return cv2.resize(roi, (resize_size, resize_size), interpolation=cv2.INTER_AREA) ================================================ FILE: Image Processor/download_utils.py ================================================ import requests def download_file_from_google_drive(id, destination): def get_confirm_token(response): for key, value in response.cookies.items(): if key.startswith('download_warning'): return value return None def save_response_content(response, destination): CHUNK_SIZE = 32768 with open(destination, "wb") as f: for chunk in response.iter_content(CHUNK_SIZE): if chunk: # filter out keep-alive new chunks f.write(chunk) URL = "https://docs.google.com/uc?export=download" session = requests.Session() response = session.get(URL, params = { 'id' : id }, stream = True) token = get_confirm_token(response) if token: params = { 'id' : id, 'confirm' : token } response = session.get(URL, params = params, stream = True) save_response_content(response, destination) ================================================ FILE: Image Processor/mrcnn/__init__.py ================================================ ================================================ FILE: Image Processor/mrcnn/config.py ================================================ """ Mask R-CNN Base Configurations class. Copyright (c) 2017 Matterport, Inc. Licensed under the MIT License (see LICENSE for details) Written by Waleed Abdulla """ import numpy as np # Base Configuration Class # Don't use this class directly. Instead, sub-class it and override # the configurations you need to change. class Config(object): """Base configuration class. For custom configurations, create a sub-class that inherits from this one and override properties that need to be changed. """ # Name the configurations. For example, 'COCO', 'Experiment 3', ...etc. # Useful if your code needs to do things differently depending on which # experiment is running. NAME = None # Override in sub-classes # NUMBER OF GPUs to use. When using only a CPU, this needs to be set to 1. GPU_COUNT = 1 # Number of images to train with on each GPU. A 12GB GPU can typically # handle 2 images of 1024x1024px. # Adjust based on your GPU memory and image sizes. Use the highest # number that your GPU can handle for best performance. IMAGES_PER_GPU = 2 # Number of training steps per epoch # This doesn't need to match the size of the training set. Tensorboard # updates are saved at the end of each epoch, so setting this to a # smaller number means getting more frequent TensorBoard updates. # Validation stats are also calculated at each epoch end and they # might take a while, so don't set this too small to avoid spending # a lot of time on validation stats. STEPS_PER_EPOCH = 1000 # Number of validation steps to run at the end of every training epoch. # A bigger number improves accuracy of validation stats, but slows # down the training. VALIDATION_STEPS = 50 # Backbone network architecture # Supported values are: resnet50, resnet101. # You can also provide a callable that should have the signature # of model.resnet_graph. If you do so, you need to supply a callable # to COMPUTE_BACKBONE_SHAPE as well BACKBONE = "resnet101" # Only useful if you supply a callable to BACKBONE. Should compute # the shape of each layer of the FPN Pyramid. # See model.compute_backbone_shapes COMPUTE_BACKBONE_SHAPE = None # The strides of each layer of the FPN Pyramid. These values # are based on a Resnet101 backbone. BACKBONE_STRIDES = [4, 8, 16, 32, 64] # Size of the fully-connected layers in the classification graph FPN_CLASSIF_FC_LAYERS_SIZE = 1024 # Size of the top-down layers used to build the feature pyramid TOP_DOWN_PYRAMID_SIZE = 256 # Number of classification classes (including background) NUM_CLASSES = 1 # Override in sub-classes # Length of square anchor side in pixels RPN_ANCHOR_SCALES = (32, 64, 128, 256, 512) # Ratios of anchors at each cell (width/height) # A value of 1 represents a square anchor, and 0.5 is a wide anchor RPN_ANCHOR_RATIOS = [0.5, 1, 2] # Anchor stride # If 1 then anchors are created for each cell in the backbone feature map. # If 2, then anchors are created for every other cell, and so on. RPN_ANCHOR_STRIDE = 1 # Non-max suppression threshold to filter RPN proposals. # You can increase this during training to generate more propsals. RPN_NMS_THRESHOLD = 0.7 # How many anchors per image to use for RPN training RPN_TRAIN_ANCHORS_PER_IMAGE = 256 # ROIs kept after tf.nn.top_k and before non-maximum suppression PRE_NMS_LIMIT = 6000 # ROIs kept after non-maximum suppression (training and inference) POST_NMS_ROIS_TRAINING = 2000 POST_NMS_ROIS_INFERENCE = 1000 # If enabled, resizes instance masks to a smaller size to reduce # memory load. Recommended when using high-resolution images. USE_MINI_MASK = True MINI_MASK_SHAPE = (56, 56) # (height, width) of the mini-mask # Input image resizing # Generally, use the "square" resizing mode for training and predicting # and it should work well in most cases. In this mode, images are scaled # up such that the small side is = IMAGE_MIN_DIM, but ensuring that the # scaling doesn't make the long side > IMAGE_MAX_DIM. Then the image is # padded with zeros to make it a square so multiple images can be put # in one batch. # Available resizing modes: # none: No resizing or padding. Return the image unchanged. # square: Resize and pad with zeros to get a square image # of size [max_dim, max_dim]. # pad64: Pads width and height with zeros to make them multiples of 64. # If IMAGE_MIN_DIM or IMAGE_MIN_SCALE are not None, then it scales # up before padding. IMAGE_MAX_DIM is ignored in this mode. # The multiple of 64 is needed to ensure smooth scaling of feature # maps up and down the 6 levels of the FPN pyramid (2**6=64). # crop: Picks random crops from the image. First, scales the image based # on IMAGE_MIN_DIM and IMAGE_MIN_SCALE, then picks a random crop of # size IMAGE_MIN_DIM x IMAGE_MIN_DIM. Can be used in training only. # IMAGE_MAX_DIM is not used in this mode. IMAGE_RESIZE_MODE = "square" IMAGE_MIN_DIM = 800 IMAGE_MAX_DIM = 1024 # Minimum scaling ratio. Checked after MIN_IMAGE_DIM and can force further # up scaling. For example, if set to 2 then images are scaled up to double # the width and height, or more, even if MIN_IMAGE_DIM doesn't require it. # However, in 'square' mode, it can be overruled by IMAGE_MAX_DIM. IMAGE_MIN_SCALE = 0 # Number of color channels per image. RGB = 3, grayscale = 1, RGB-D = 4 # Changing this requires other changes in the code. See the WIKI for more # details: https://github.com/matterport/Mask_RCNN/wiki IMAGE_CHANNEL_COUNT = 3 # Image mean (RGB) MEAN_PIXEL = np.array([123.7, 116.8, 103.9]) # Number of ROIs per image to feed to classifier/mask heads # The Mask RCNN paper uses 512 but often the RPN doesn't generate # enough positive proposals to fill this and keep a positive:negative # ratio of 1:3. You can increase the number of proposals by adjusting # the RPN NMS threshold. TRAIN_ROIS_PER_IMAGE = 200 # Percent of positive ROIs used to train classifier/mask heads ROI_POSITIVE_RATIO = 0.33 # Pooled ROIs POOL_SIZE = 7 MASK_POOL_SIZE = 14 # Shape of output mask # To change this you also need to change the neural network mask branch MASK_SHAPE = [28, 28] # Maximum number of ground truth instances to use in one image MAX_GT_INSTANCES = 100 # Bounding box refinement standard deviation for RPN and final detections. RPN_BBOX_STD_DEV = np.array([0.1, 0.1, 0.2, 0.2]) BBOX_STD_DEV = np.array([0.1, 0.1, 0.2, 0.2]) # Max number of final detections DETECTION_MAX_INSTANCES = 100 # Minimum probability value to accept a detected instance # ROIs below this threshold are skipped DETECTION_MIN_CONFIDENCE = 0.7 # Non-maximum suppression threshold for detection DETECTION_NMS_THRESHOLD = 0.3 # Learning rate and momentum # The Mask RCNN paper uses lr=0.02, but on TensorFlow it causes # weights to explode. Likely due to differences in optimizer # implementation. LEARNING_RATE = 0.001 LEARNING_MOMENTUM = 0.9 # Weight decay regularization WEIGHT_DECAY = 0.0001 # Loss weights for more precise optimization. # Can be used for R-CNN training setup. LOSS_WEIGHTS = { "rpn_class_loss": 1., "rpn_bbox_loss": 1., "mrcnn_class_loss": 1., "mrcnn_bbox_loss": 1., "mrcnn_mask_loss": 1. } # Use RPN ROIs or externally generated ROIs for training # Keep this True for most situations. Set to False if you want to train # the head branches on ROI generated by code rather than the ROIs from # the RPN. For example, to debug the classifier head without having to # train the RPN. USE_RPN_ROIS = True # Train or freeze batch normalization layers # None: Train BN layers. This is the normal mode # False: Freeze BN layers. Good when using a small batch size # True: (don't use). Set layer in training mode even when predicting TRAIN_BN = False # Defaulting to False since batch size is often small # Gradient norm clipping GRADIENT_CLIP_NORM = 5.0 def __init__(self): """Set values of computed attributes.""" # Effective batch size self.BATCH_SIZE = self.IMAGES_PER_GPU * self.GPU_COUNT # Input image size if self.IMAGE_RESIZE_MODE == "crop": self.IMAGE_SHAPE = np.array([self.IMAGE_MIN_DIM, self.IMAGE_MIN_DIM, self.IMAGE_CHANNEL_COUNT]) else: self.IMAGE_SHAPE = np.array([self.IMAGE_MAX_DIM, self.IMAGE_MAX_DIM, self.IMAGE_CHANNEL_COUNT]) # Image meta data length # See compose_image_meta() for details self.IMAGE_META_SIZE = 1 + 3 + 3 + 4 + 1 + self.NUM_CLASSES def display(self): """Display Configuration values.""" print("\nConfigurations:") for a in dir(self): if not a.startswith("__") and not callable(getattr(self, a)): print("{:30} {}".format(a, getattr(self, a))) print("\n") ================================================ FILE: Image Processor/mrcnn/model.py ================================================ """ Mask R-CNN The main Mask R-CNN model implementation. Copyright (c) 2017 Matterport, Inc. Licensed under the MIT License (see LICENSE for details) Written by Waleed Abdulla """ import os import random import datetime import re import math import logging from collections import OrderedDict import multiprocessing import numpy as np import tensorflow as tf import keras import keras.backend as K import keras.layers as KL import keras.engine as KE import keras.models as KM from mrcnn import utils # Requires TensorFlow 1.3+ and Keras 2.0.8+. from distutils.version import LooseVersion assert LooseVersion(tf.__version__) >= LooseVersion("1.3") assert LooseVersion(keras.__version__) >= LooseVersion('2.0.8') ############################################################ # Utility Functions ############################################################ def log(text, array=None): """Prints a text message. And, optionally, if a Numpy array is provided it prints it's shape, min, and max values. """ if array is not None: text = text.ljust(25) text += ("shape: {:20} ".format(str(array.shape))) if array.size: text += ("min: {:10.5f} max: {:10.5f}".format(array.min(),array.max())) else: text += ("min: {:10} max: {:10}".format("","")) text += " {}".format(array.dtype) print(text) class BatchNorm(KL.BatchNormalization): """Extends the Keras BatchNormalization class to allow a central place to make changes if needed. Batch normalization has a negative effect on training if batches are small so this layer is often frozen (via setting in Config class) and functions as linear layer. """ def call(self, inputs, training=None): """ Note about training values: None: Train BN layers. This is the normal mode False: Freeze BN layers. Good when batch size is small True: (don't use). Set layer in training mode even when making inferences """ return super(self.__class__, self).call(inputs, training=training) def compute_backbone_shapes(config, image_shape): """Computes the width and height of each stage of the backbone network. Returns: [N, (height, width)]. Where N is the number of stages """ if callable(config.BACKBONE): return config.COMPUTE_BACKBONE_SHAPE(image_shape) # Currently supports ResNet only assert config.BACKBONE in ["resnet50", "resnet101"] return np.array( [[int(math.ceil(image_shape[0] / stride)), int(math.ceil(image_shape[1] / stride))] for stride in config.BACKBONE_STRIDES]) ############################################################ # Resnet Graph ############################################################ # Code adopted from: # https://github.com/fchollet/deep-learning-models/blob/master/resnet50.py def identity_block(input_tensor, kernel_size, filters, stage, block, use_bias=True, train_bn=True): """The identity_block is the block that has no conv layer at shortcut # Arguments input_tensor: input tensor kernel_size: default 3, the kernel size of middle conv layer at main path filters: list of integers, the nb_filters of 3 conv layer at main path stage: integer, current stage label, used for generating layer names block: 'a','b'..., current block label, used for generating layer names use_bias: Boolean. To use or not use a bias in conv layers. train_bn: Boolean. Train or freeze Batch Norm layers """ nb_filter1, nb_filter2, nb_filter3 = filters conv_name_base = 'res' + str(stage) + block + '_branch' bn_name_base = 'bn' + str(stage) + block + '_branch' x = KL.Conv2D(nb_filter1, (1, 1), name=conv_name_base + '2a', use_bias=use_bias)(input_tensor) x = BatchNorm(name=bn_name_base + '2a')(x, training=train_bn) x = KL.Activation('relu')(x) x = KL.Conv2D(nb_filter2, (kernel_size, kernel_size), padding='same', name=conv_name_base + '2b', use_bias=use_bias)(x) x = BatchNorm(name=bn_name_base + '2b')(x, training=train_bn) x = KL.Activation('relu')(x) x = KL.Conv2D(nb_filter3, (1, 1), name=conv_name_base + '2c', use_bias=use_bias)(x) x = BatchNorm(name=bn_name_base + '2c')(x, training=train_bn) x = KL.Add()([x, input_tensor]) x = KL.Activation('relu', name='res' + str(stage) + block + '_out')(x) return x def conv_block(input_tensor, kernel_size, filters, stage, block, strides=(2, 2), use_bias=True, train_bn=True): """conv_block is the block that has a conv layer at shortcut # Arguments input_tensor: input tensor kernel_size: default 3, the kernel size of middle conv layer at main path filters: list of integers, the nb_filters of 3 conv layer at main path stage: integer, current stage label, used for generating layer names block: 'a','b'..., current block label, used for generating layer names use_bias: Boolean. To use or not use a bias in conv layers. train_bn: Boolean. Train or freeze Batch Norm layers Note that from stage 3, the first conv layer at main path is with subsample=(2,2) And the shortcut should have subsample=(2,2) as well """ nb_filter1, nb_filter2, nb_filter3 = filters conv_name_base = 'res' + str(stage) + block + '_branch' bn_name_base = 'bn' + str(stage) + block + '_branch' x = KL.Conv2D(nb_filter1, (1, 1), strides=strides, name=conv_name_base + '2a', use_bias=use_bias)(input_tensor) x = BatchNorm(name=bn_name_base + '2a')(x, training=train_bn) x = KL.Activation('relu')(x) x = KL.Conv2D(nb_filter2, (kernel_size, kernel_size), padding='same', name=conv_name_base + '2b', use_bias=use_bias)(x) x = BatchNorm(name=bn_name_base + '2b')(x, training=train_bn) x = KL.Activation('relu')(x) x = KL.Conv2D(nb_filter3, (1, 1), name=conv_name_base + '2c', use_bias=use_bias)(x) x = BatchNorm(name=bn_name_base + '2c')(x, training=train_bn) shortcut = KL.Conv2D(nb_filter3, (1, 1), strides=strides, name=conv_name_base + '1', use_bias=use_bias)(input_tensor) shortcut = BatchNorm(name=bn_name_base + '1')(shortcut, training=train_bn) x = KL.Add()([x, shortcut]) x = KL.Activation('relu', name='res' + str(stage) + block + '_out')(x) return x def resnet_graph(input_image, architecture, stage5=False, train_bn=True): """Build a ResNet graph. architecture: Can be resnet50 or resnet101 stage5: Boolean. If False, stage5 of the network is not created train_bn: Boolean. Train or freeze Batch Norm layers """ assert architecture in ["resnet50", "resnet101"] # Stage 1 x = KL.ZeroPadding2D((3, 3))(input_image) x = KL.Conv2D(64, (7, 7), strides=(2, 2), name='conv1', use_bias=True)(x) x = BatchNorm(name='bn_conv1')(x, training=train_bn) x = KL.Activation('relu')(x) C1 = x = KL.MaxPooling2D((3, 3), strides=(2, 2), padding="same")(x) # Stage 2 x = conv_block(x, 3, [64, 64, 256], stage=2, block='a', strides=(1, 1), train_bn=train_bn) x = identity_block(x, 3, [64, 64, 256], stage=2, block='b', train_bn=train_bn) C2 = x = identity_block(x, 3, [64, 64, 256], stage=2, block='c', train_bn=train_bn) # Stage 3 x = conv_block(x, 3, [128, 128, 512], stage=3, block='a', train_bn=train_bn) x = identity_block(x, 3, [128, 128, 512], stage=3, block='b', train_bn=train_bn) x = identity_block(x, 3, [128, 128, 512], stage=3, block='c', train_bn=train_bn) C3 = x = identity_block(x, 3, [128, 128, 512], stage=3, block='d', train_bn=train_bn) # Stage 4 x = conv_block(x, 3, [256, 256, 1024], stage=4, block='a', train_bn=train_bn) block_count = {"resnet50": 5, "resnet101": 22}[architecture] for i in range(block_count): x = identity_block(x, 3, [256, 256, 1024], stage=4, block=chr(98 + i), train_bn=train_bn) C4 = x # Stage 5 if stage5: x = conv_block(x, 3, [512, 512, 2048], stage=5, block='a', train_bn=train_bn) x = identity_block(x, 3, [512, 512, 2048], stage=5, block='b', train_bn=train_bn) C5 = x = identity_block(x, 3, [512, 512, 2048], stage=5, block='c', train_bn=train_bn) else: C5 = None return [C1, C2, C3, C4, C5] ############################################################ # Proposal Layer ############################################################ def apply_box_deltas_graph(boxes, deltas): """Applies the given deltas to the given boxes. boxes: [N, (y1, x1, y2, x2)] boxes to update deltas: [N, (dy, dx, log(dh), log(dw))] refinements to apply """ # Convert to y, x, h, w height = boxes[:, 2] - boxes[:, 0] width = boxes[:, 3] - boxes[:, 1] center_y = boxes[:, 0] + 0.5 * height center_x = boxes[:, 1] + 0.5 * width # Apply deltas center_y += deltas[:, 0] * height center_x += deltas[:, 1] * width height *= tf.exp(deltas[:, 2]) width *= tf.exp(deltas[:, 3]) # Convert back to y1, x1, y2, x2 y1 = center_y - 0.5 * height x1 = center_x - 0.5 * width y2 = y1 + height x2 = x1 + width result = tf.stack([y1, x1, y2, x2], axis=1, name="apply_box_deltas_out") return result def clip_boxes_graph(boxes, window): """ boxes: [N, (y1, x1, y2, x2)] window: [4] in the form y1, x1, y2, x2 """ # Split wy1, wx1, wy2, wx2 = tf.split(window, 4) y1, x1, y2, x2 = tf.split(boxes, 4, axis=1) # Clip y1 = tf.maximum(tf.minimum(y1, wy2), wy1) x1 = tf.maximum(tf.minimum(x1, wx2), wx1) y2 = tf.maximum(tf.minimum(y2, wy2), wy1) x2 = tf.maximum(tf.minimum(x2, wx2), wx1) clipped = tf.concat([y1, x1, y2, x2], axis=1, name="clipped_boxes") clipped.set_shape((clipped.shape[0], 4)) return clipped class ProposalLayer(KE.Layer): """Receives anchor scores and selects a subset to pass as proposals to the second stage. Filtering is done based on anchor scores and non-max suppression to remove overlaps. It also applies bounding box refinement deltas to anchors. Inputs: rpn_probs: [batch, num_anchors, (bg prob, fg prob)] rpn_bbox: [batch, num_anchors, (dy, dx, log(dh), log(dw))] anchors: [batch, num_anchors, (y1, x1, y2, x2)] anchors in normalized coordinates Returns: Proposals in normalized coordinates [batch, rois, (y1, x1, y2, x2)] """ def __init__(self, proposal_count, nms_threshold, config=None, **kwargs): super(ProposalLayer, self).__init__(**kwargs) self.config = config self.proposal_count = proposal_count self.nms_threshold = nms_threshold def call(self, inputs): # Box Scores. Use the foreground class confidence. [Batch, num_rois, 1] scores = inputs[0][:, :, 1] # Box deltas [batch, num_rois, 4] deltas = inputs[1] deltas = deltas * np.reshape(self.config.RPN_BBOX_STD_DEV, [1, 1, 4]) # Anchors anchors = inputs[2] # Improve performance by trimming to top anchors by score # and doing the rest on the smaller subset. pre_nms_limit = tf.minimum(self.config.PRE_NMS_LIMIT, tf.shape(anchors)[1]) ix = tf.nn.top_k(scores, pre_nms_limit, sorted=True, name="top_anchors").indices scores = utils.batch_slice([scores, ix], lambda x, y: tf.gather(x, y), self.config.IMAGES_PER_GPU) deltas = utils.batch_slice([deltas, ix], lambda x, y: tf.gather(x, y), self.config.IMAGES_PER_GPU) pre_nms_anchors = utils.batch_slice([anchors, ix], lambda a, x: tf.gather(a, x), self.config.IMAGES_PER_GPU, names=["pre_nms_anchors"]) # Apply deltas to anchors to get refined anchors. # [batch, N, (y1, x1, y2, x2)] boxes = utils.batch_slice([pre_nms_anchors, deltas], lambda x, y: apply_box_deltas_graph(x, y), self.config.IMAGES_PER_GPU, names=["refined_anchors"]) # Clip to image boundaries. Since we're in normalized coordinates, # clip to 0..1 range. [batch, N, (y1, x1, y2, x2)] window = np.array([0, 0, 1, 1], dtype=np.float32) boxes = utils.batch_slice(boxes, lambda x: clip_boxes_graph(x, window), self.config.IMAGES_PER_GPU, names=["refined_anchors_clipped"]) # Filter out small boxes # According to Xinlei Chen's paper, this reduces detection accuracy # for small objects, so we're skipping it. # Non-max suppression def nms(boxes, scores): indices = tf.image.non_max_suppression( boxes, scores, self.proposal_count, self.nms_threshold, name="rpn_non_max_suppression") proposals = tf.gather(boxes, indices) # Pad if needed padding = tf.maximum(self.proposal_count - tf.shape(proposals)[0], 0) proposals = tf.pad(proposals, [(0, padding), (0, 0)]) return proposals proposals = utils.batch_slice([boxes, scores], nms, self.config.IMAGES_PER_GPU) return proposals def compute_output_shape(self, input_shape): return (None, self.proposal_count, 4) ############################################################ # ROIAlign Layer ############################################################ def log2_graph(x): """Implementation of Log2. TF doesn't have a native implementation.""" return tf.log(x) / tf.log(2.0) class PyramidROIAlign(KE.Layer): """Implements ROI Pooling on multiple levels of the feature pyramid. Params: - pool_shape: [pool_height, pool_width] of the output pooled regions. Usually [7, 7] Inputs: - boxes: [batch, num_boxes, (y1, x1, y2, x2)] in normalized coordinates. Possibly padded with zeros if not enough boxes to fill the array. - image_meta: [batch, (meta data)] Image details. See compose_image_meta() - feature_maps: List of feature maps from different levels of the pyramid. Each is [batch, height, width, channels] Output: Pooled regions in the shape: [batch, num_boxes, pool_height, pool_width, channels]. The width and height are those specific in the pool_shape in the layer constructor. """ def __init__(self, pool_shape, **kwargs): super(PyramidROIAlign, self).__init__(**kwargs) self.pool_shape = tuple(pool_shape) def call(self, inputs): # Crop boxes [batch, num_boxes, (y1, x1, y2, x2)] in normalized coords boxes = inputs[0] # Image meta # Holds details about the image. See compose_image_meta() image_meta = inputs[1] # Feature Maps. List of feature maps from different level of the # feature pyramid. Each is [batch, height, width, channels] feature_maps = inputs[2:] # Assign each ROI to a level in the pyramid based on the ROI area. y1, x1, y2, x2 = tf.split(boxes, 4, axis=2) h = y2 - y1 w = x2 - x1 # Use shape of first image. Images in a batch must have the same size. image_shape = parse_image_meta_graph(image_meta)['image_shape'][0] # Equation 1 in the Feature Pyramid Networks paper. Account for # the fact that our coordinates are normalized here. # e.g. a 224x224 ROI (in pixels) maps to P4 image_area = tf.cast(image_shape[0] * image_shape[1], tf.float32) roi_level = log2_graph(tf.sqrt(h * w) / (224.0 / tf.sqrt(image_area))) roi_level = tf.minimum(5, tf.maximum( 2, 4 + tf.cast(tf.round(roi_level), tf.int32))) roi_level = tf.squeeze(roi_level, 2) # Loop through levels and apply ROI pooling to each. P2 to P5. pooled = [] box_to_level = [] for i, level in enumerate(range(2, 6)): ix = tf.where(tf.equal(roi_level, level)) level_boxes = tf.gather_nd(boxes, ix) # Box indices for crop_and_resize. box_indices = tf.cast(ix[:, 0], tf.int32) # Keep track of which box is mapped to which level box_to_level.append(ix) # Stop gradient propogation to ROI proposals level_boxes = tf.stop_gradient(level_boxes) box_indices = tf.stop_gradient(box_indices) # Crop and Resize # From Mask R-CNN paper: "We sample four regular locations, so # that we can evaluate either max or average pooling. In fact, # interpolating only a single value at each bin center (without # pooling) is nearly as effective." # # Here we use the simplified approach of a single value per bin, # which is how it's done in tf.crop_and_resize() # Result: [batch * num_boxes, pool_height, pool_width, channels] pooled.append(tf.image.crop_and_resize( feature_maps[i], level_boxes, box_indices, self.pool_shape, method="bilinear")) # Pack pooled features into one tensor pooled = tf.concat(pooled, axis=0) # Pack box_to_level mapping into one array and add another # column representing the order of pooled boxes box_to_level = tf.concat(box_to_level, axis=0) box_range = tf.expand_dims(tf.range(tf.shape(box_to_level)[0]), 1) box_to_level = tf.concat([tf.cast(box_to_level, tf.int32), box_range], axis=1) # Rearrange pooled features to match the order of the original boxes # Sort box_to_level by batch then box index # TF doesn't have a way to sort by two columns, so merge them and sort. sorting_tensor = box_to_level[:, 0] * 100000 + box_to_level[:, 1] ix = tf.nn.top_k(sorting_tensor, k=tf.shape( box_to_level)[0]).indices[::-1] ix = tf.gather(box_to_level[:, 2], ix) pooled = tf.gather(pooled, ix) # Re-add the batch dimension shape = tf.concat([tf.shape(boxes)[:2], tf.shape(pooled)[1:]], axis=0) pooled = tf.reshape(pooled, shape) return pooled def compute_output_shape(self, input_shape): return input_shape[0][:2] + self.pool_shape + (input_shape[2][-1], ) ############################################################ # Detection Target Layer ############################################################ def overlaps_graph(boxes1, boxes2): """Computes IoU overlaps between two sets of boxes. boxes1, boxes2: [N, (y1, x1, y2, x2)]. """ # 1. Tile boxes2 and repeat boxes1. This allows us to compare # every boxes1 against every boxes2 without loops. # TF doesn't have an equivalent to np.repeat() so simulate it # using tf.tile() and tf.reshape. b1 = tf.reshape(tf.tile(tf.expand_dims(boxes1, 1), [1, 1, tf.shape(boxes2)[0]]), [-1, 4]) b2 = tf.tile(boxes2, [tf.shape(boxes1)[0], 1]) # 2. Compute intersections b1_y1, b1_x1, b1_y2, b1_x2 = tf.split(b1, 4, axis=1) b2_y1, b2_x1, b2_y2, b2_x2 = tf.split(b2, 4, axis=1) y1 = tf.maximum(b1_y1, b2_y1) x1 = tf.maximum(b1_x1, b2_x1) y2 = tf.minimum(b1_y2, b2_y2) x2 = tf.minimum(b1_x2, b2_x2) intersection = tf.maximum(x2 - x1, 0) * tf.maximum(y2 - y1, 0) # 3. Compute unions b1_area = (b1_y2 - b1_y1) * (b1_x2 - b1_x1) b2_area = (b2_y2 - b2_y1) * (b2_x2 - b2_x1) union = b1_area + b2_area - intersection # 4. Compute IoU and reshape to [boxes1, boxes2] iou = intersection / union overlaps = tf.reshape(iou, [tf.shape(boxes1)[0], tf.shape(boxes2)[0]]) return overlaps def detection_targets_graph(proposals, gt_class_ids, gt_boxes, gt_masks, config): """Generates detection targets for one image. Subsamples proposals and generates target class IDs, bounding box deltas, and masks for each. Inputs: proposals: [POST_NMS_ROIS_TRAINING, (y1, x1, y2, x2)] in normalized coordinates. Might be zero padded if there are not enough proposals. gt_class_ids: [MAX_GT_INSTANCES] int class IDs gt_boxes: [MAX_GT_INSTANCES, (y1, x1, y2, x2)] in normalized coordinates. gt_masks: [height, width, MAX_GT_INSTANCES] of boolean type. Returns: Target ROIs and corresponding class IDs, bounding box shifts, and masks. rois: [TRAIN_ROIS_PER_IMAGE, (y1, x1, y2, x2)] in normalized coordinates class_ids: [TRAIN_ROIS_PER_IMAGE]. Integer class IDs. Zero padded. deltas: [TRAIN_ROIS_PER_IMAGE, (dy, dx, log(dh), log(dw))] masks: [TRAIN_ROIS_PER_IMAGE, height, width]. Masks cropped to bbox boundaries and resized to neural network output size. Note: Returned arrays might be zero padded if not enough target ROIs. """ # Assertions asserts = [ tf.Assert(tf.greater(tf.shape(proposals)[0], 0), [proposals], name="roi_assertion"), ] with tf.control_dependencies(asserts): proposals = tf.identity(proposals) # Remove zero padding proposals, _ = trim_zeros_graph(proposals, name="trim_proposals") gt_boxes, non_zeros = trim_zeros_graph(gt_boxes, name="trim_gt_boxes") gt_class_ids = tf.boolean_mask(gt_class_ids, non_zeros, name="trim_gt_class_ids") gt_masks = tf.gather(gt_masks, tf.where(non_zeros)[:, 0], axis=2, name="trim_gt_masks") # Handle COCO crowds # A crowd box in COCO is a bounding box around several instances. Exclude # them from training. A crowd box is given a negative class ID. crowd_ix = tf.where(gt_class_ids < 0)[:, 0] non_crowd_ix = tf.where(gt_class_ids > 0)[:, 0] crowd_boxes = tf.gather(gt_boxes, crowd_ix) gt_class_ids = tf.gather(gt_class_ids, non_crowd_ix) gt_boxes = tf.gather(gt_boxes, non_crowd_ix) gt_masks = tf.gather(gt_masks, non_crowd_ix, axis=2) # Compute overlaps matrix [proposals, gt_boxes] overlaps = overlaps_graph(proposals, gt_boxes) # Compute overlaps with crowd boxes [proposals, crowd_boxes] crowd_overlaps = overlaps_graph(proposals, crowd_boxes) crowd_iou_max = tf.reduce_max(crowd_overlaps, axis=1) no_crowd_bool = (crowd_iou_max < 0.001) # Determine positive and negative ROIs roi_iou_max = tf.reduce_max(overlaps, axis=1) # 1. Positive ROIs are those with >= 0.5 IoU with a GT box positive_roi_bool = (roi_iou_max >= 0.5) positive_indices = tf.where(positive_roi_bool)[:, 0] # 2. Negative ROIs are those with < 0.5 with every GT box. Skip crowds. negative_indices = tf.where(tf.logical_and(roi_iou_max < 0.5, no_crowd_bool))[:, 0] # Subsample ROIs. Aim for 33% positive # Positive ROIs positive_count = int(config.TRAIN_ROIS_PER_IMAGE * config.ROI_POSITIVE_RATIO) positive_indices = tf.random_shuffle(positive_indices)[:positive_count] positive_count = tf.shape(positive_indices)[0] # Negative ROIs. Add enough to maintain positive:negative ratio. r = 1.0 / config.ROI_POSITIVE_RATIO negative_count = tf.cast(r * tf.cast(positive_count, tf.float32), tf.int32) - positive_count negative_indices = tf.random_shuffle(negative_indices)[:negative_count] # Gather selected ROIs positive_rois = tf.gather(proposals, positive_indices) negative_rois = tf.gather(proposals, negative_indices) # Assign positive ROIs to GT boxes. positive_overlaps = tf.gather(overlaps, positive_indices) roi_gt_box_assignment = tf.cond( tf.greater(tf.shape(positive_overlaps)[1], 0), true_fn = lambda: tf.argmax(positive_overlaps, axis=1), false_fn = lambda: tf.cast(tf.constant([]),tf.int64) ) roi_gt_boxes = tf.gather(gt_boxes, roi_gt_box_assignment) roi_gt_class_ids = tf.gather(gt_class_ids, roi_gt_box_assignment) # Compute bbox refinement for positive ROIs deltas = utils.box_refinement_graph(positive_rois, roi_gt_boxes) deltas /= config.BBOX_STD_DEV # Assign positive ROIs to GT masks # Permute masks to [N, height, width, 1] transposed_masks = tf.expand_dims(tf.transpose(gt_masks, [2, 0, 1]), -1) # Pick the right mask for each ROI roi_masks = tf.gather(transposed_masks, roi_gt_box_assignment) # Compute mask targets boxes = positive_rois if config.USE_MINI_MASK: # Transform ROI coordinates from normalized image space # to normalized mini-mask space. y1, x1, y2, x2 = tf.split(positive_rois, 4, axis=1) gt_y1, gt_x1, gt_y2, gt_x2 = tf.split(roi_gt_boxes, 4, axis=1) gt_h = gt_y2 - gt_y1 gt_w = gt_x2 - gt_x1 y1 = (y1 - gt_y1) / gt_h x1 = (x1 - gt_x1) / gt_w y2 = (y2 - gt_y1) / gt_h x2 = (x2 - gt_x1) / gt_w boxes = tf.concat([y1, x1, y2, x2], 1) box_ids = tf.range(0, tf.shape(roi_masks)[0]) masks = tf.image.crop_and_resize(tf.cast(roi_masks, tf.float32), boxes, box_ids, config.MASK_SHAPE) # Remove the extra dimension from masks. masks = tf.squeeze(masks, axis=3) # Threshold mask pixels at 0.5 to have GT masks be 0 or 1 to use with # binary cross entropy loss. masks = tf.round(masks) # Append negative ROIs and pad bbox deltas and masks that # are not used for negative ROIs with zeros. rois = tf.concat([positive_rois, negative_rois], axis=0) N = tf.shape(negative_rois)[0] P = tf.maximum(config.TRAIN_ROIS_PER_IMAGE - tf.shape(rois)[0], 0) rois = tf.pad(rois, [(0, P), (0, 0)]) roi_gt_boxes = tf.pad(roi_gt_boxes, [(0, N + P), (0, 0)]) roi_gt_class_ids = tf.pad(roi_gt_class_ids, [(0, N + P)]) deltas = tf.pad(deltas, [(0, N + P), (0, 0)]) masks = tf.pad(masks, [[0, N + P], (0, 0), (0, 0)]) return rois, roi_gt_class_ids, deltas, masks class DetectionTargetLayer(KE.Layer): """Subsamples proposals and generates target box refinement, class_ids, and masks for each. Inputs: proposals: [batch, N, (y1, x1, y2, x2)] in normalized coordinates. Might be zero padded if there are not enough proposals. gt_class_ids: [batch, MAX_GT_INSTANCES] Integer class IDs. gt_boxes: [batch, MAX_GT_INSTANCES, (y1, x1, y2, x2)] in normalized coordinates. gt_masks: [batch, height, width, MAX_GT_INSTANCES] of boolean type Returns: Target ROIs and corresponding class IDs, bounding box shifts, and masks. rois: [batch, TRAIN_ROIS_PER_IMAGE, (y1, x1, y2, x2)] in normalized coordinates target_class_ids: [batch, TRAIN_ROIS_PER_IMAGE]. Integer class IDs. target_deltas: [batch, TRAIN_ROIS_PER_IMAGE, (dy, dx, log(dh), log(dw)] target_mask: [batch, TRAIN_ROIS_PER_IMAGE, height, width] Masks cropped to bbox boundaries and resized to neural network output size. Note: Returned arrays might be zero padded if not enough target ROIs. """ def __init__(self, config, **kwargs): super(DetectionTargetLayer, self).__init__(**kwargs) self.config = config def call(self, inputs): proposals = inputs[0] gt_class_ids = inputs[1] gt_boxes = inputs[2] gt_masks = inputs[3] # Slice the batch and run a graph for each slice # TODO: Rename target_bbox to target_deltas for clarity names = ["rois", "target_class_ids", "target_bbox", "target_mask"] outputs = utils.batch_slice( [proposals, gt_class_ids, gt_boxes, gt_masks], lambda w, x, y, z: detection_targets_graph( w, x, y, z, self.config), self.config.IMAGES_PER_GPU, names=names) return outputs def compute_output_shape(self, input_shape): return [ (None, self.config.TRAIN_ROIS_PER_IMAGE, 4), # rois (None, self.config.TRAIN_ROIS_PER_IMAGE), # class_ids (None, self.config.TRAIN_ROIS_PER_IMAGE, 4), # deltas (None, self.config.TRAIN_ROIS_PER_IMAGE, self.config.MASK_SHAPE[0], self.config.MASK_SHAPE[1]) # masks ] def compute_mask(self, inputs, mask=None): return [None, None, None, None] ############################################################ # Detection Layer ############################################################ def refine_detections_graph(rois, probs, deltas, window, config): """Refine classified proposals and filter overlaps and return final detections. Inputs: rois: [N, (y1, x1, y2, x2)] in normalized coordinates probs: [N, num_classes]. Class probabilities. deltas: [N, num_classes, (dy, dx, log(dh), log(dw))]. Class-specific bounding box deltas. window: (y1, x1, y2, x2) in normalized coordinates. The part of the image that contains the image excluding the padding. Returns detections shaped: [num_detections, (y1, x1, y2, x2, class_id, score)] where coordinates are normalized. """ # Class IDs per ROI class_ids = tf.argmax(probs, axis=1, output_type=tf.int32) # Class probability of the top class of each ROI indices = tf.stack([tf.range(probs.shape[0]), class_ids], axis=1) class_scores = tf.gather_nd(probs, indices) # Class-specific bounding box deltas deltas_specific = tf.gather_nd(deltas, indices) # Apply bounding box deltas # Shape: [boxes, (y1, x1, y2, x2)] in normalized coordinates refined_rois = apply_box_deltas_graph( rois, deltas_specific * config.BBOX_STD_DEV) # Clip boxes to image window refined_rois = clip_boxes_graph(refined_rois, window) # TODO: Filter out boxes with zero area # Filter out background boxes keep = tf.where(class_ids > 0)[:, 0] # Filter out low confidence boxes if config.DETECTION_MIN_CONFIDENCE: conf_keep = tf.where(class_scores >= config.DETECTION_MIN_CONFIDENCE)[:, 0] keep = tf.sets.set_intersection(tf.expand_dims(keep, 0), tf.expand_dims(conf_keep, 0)) keep = tf.sparse_tensor_to_dense(keep)[0] # Apply per-class NMS # 1. Prepare variables pre_nms_class_ids = tf.gather(class_ids, keep) pre_nms_scores = tf.gather(class_scores, keep) pre_nms_rois = tf.gather(refined_rois, keep) unique_pre_nms_class_ids = tf.unique(pre_nms_class_ids)[0] def nms_keep_map(class_id): """Apply Non-Maximum Suppression on ROIs of the given class.""" # Indices of ROIs of the given class ixs = tf.where(tf.equal(pre_nms_class_ids, class_id))[:, 0] # Apply NMS class_keep = tf.image.non_max_suppression( tf.gather(pre_nms_rois, ixs), tf.gather(pre_nms_scores, ixs), max_output_size=config.DETECTION_MAX_INSTANCES, iou_threshold=config.DETECTION_NMS_THRESHOLD) # Map indices class_keep = tf.gather(keep, tf.gather(ixs, class_keep)) # Pad with -1 so returned tensors have the same shape gap = config.DETECTION_MAX_INSTANCES - tf.shape(class_keep)[0] class_keep = tf.pad(class_keep, [(0, gap)], mode='CONSTANT', constant_values=-1) # Set shape so map_fn() can infer result shape class_keep.set_shape([config.DETECTION_MAX_INSTANCES]) return class_keep # 2. Map over class IDs nms_keep = tf.map_fn(nms_keep_map, unique_pre_nms_class_ids, dtype=tf.int64) # 3. Merge results into one list, and remove -1 padding nms_keep = tf.reshape(nms_keep, [-1]) nms_keep = tf.gather(nms_keep, tf.where(nms_keep > -1)[:, 0]) # 4. Compute intersection between keep and nms_keep keep = tf.sets.set_intersection(tf.expand_dims(keep, 0), tf.expand_dims(nms_keep, 0)) keep = tf.sparse_tensor_to_dense(keep)[0] # Keep top detections roi_count = config.DETECTION_MAX_INSTANCES class_scores_keep = tf.gather(class_scores, keep) num_keep = tf.minimum(tf.shape(class_scores_keep)[0], roi_count) top_ids = tf.nn.top_k(class_scores_keep, k=num_keep, sorted=True)[1] keep = tf.gather(keep, top_ids) # Arrange output as [N, (y1, x1, y2, x2, class_id, score)] # Coordinates are normalized. detections = tf.concat([ tf.gather(refined_rois, keep), tf.to_float(tf.gather(class_ids, keep))[..., tf.newaxis], tf.gather(class_scores, keep)[..., tf.newaxis] ], axis=1) # Pad with zeros if detections < DETECTION_MAX_INSTANCES gap = config.DETECTION_MAX_INSTANCES - tf.shape(detections)[0] detections = tf.pad(detections, [(0, gap), (0, 0)], "CONSTANT") return detections class DetectionLayer(KE.Layer): """Takes classified proposal boxes and their bounding box deltas and returns the final detection boxes. Returns: [batch, num_detections, (y1, x1, y2, x2, class_id, class_score)] where coordinates are normalized. """ def __init__(self, config=None, **kwargs): super(DetectionLayer, self).__init__(**kwargs) self.config = config def call(self, inputs): rois = inputs[0] mrcnn_class = inputs[1] mrcnn_bbox = inputs[2] image_meta = inputs[3] # Get windows of images in normalized coordinates. Windows are the area # in the image that excludes the padding. # Use the shape of the first image in the batch to normalize the window # because we know that all images get resized to the same size. m = parse_image_meta_graph(image_meta) image_shape = m['image_shape'][0] window = norm_boxes_graph(m['window'], image_shape[:2]) # Run detection refinement graph on each item in the batch detections_batch = utils.batch_slice( [rois, mrcnn_class, mrcnn_bbox, window], lambda x, y, w, z: refine_detections_graph(x, y, w, z, self.config), self.config.IMAGES_PER_GPU) # Reshape output # [batch, num_detections, (y1, x1, y2, x2, class_id, class_score)] in # normalized coordinates return tf.reshape( detections_batch, [self.config.BATCH_SIZE, self.config.DETECTION_MAX_INSTANCES, 6]) def compute_output_shape(self, input_shape): return (None, self.config.DETECTION_MAX_INSTANCES, 6) ############################################################ # Region Proposal Network (RPN) ############################################################ def rpn_graph(feature_map, anchors_per_location, anchor_stride): """Builds the computation graph of Region Proposal Network. feature_map: backbone features [batch, height, width, depth] anchors_per_location: number of anchors per pixel in the feature map anchor_stride: Controls the density of anchors. Typically 1 (anchors for every pixel in the feature map), or 2 (every other pixel). Returns: rpn_class_logits: [batch, H * W * anchors_per_location, 2] Anchor classifier logits (before softmax) rpn_probs: [batch, H * W * anchors_per_location, 2] Anchor classifier probabilities. rpn_bbox: [batch, H * W * anchors_per_location, (dy, dx, log(dh), log(dw))] Deltas to be applied to anchors. """ # TODO: check if stride of 2 causes alignment issues if the feature map # is not even. # Shared convolutional base of the RPN shared = KL.Conv2D(512, (3, 3), padding='same', activation='relu', strides=anchor_stride, name='rpn_conv_shared')(feature_map) # Anchor Score. [batch, height, width, anchors per location * 2]. x = KL.Conv2D(2 * anchors_per_location, (1, 1), padding='valid', activation='linear', name='rpn_class_raw')(shared) # Reshape to [batch, anchors, 2] rpn_class_logits = KL.Lambda( lambda t: tf.reshape(t, [tf.shape(t)[0], -1, 2]))(x) # Softmax on last dimension of BG/FG. rpn_probs = KL.Activation( "softmax", name="rpn_class_xxx")(rpn_class_logits) # Bounding box refinement. [batch, H, W, anchors per location * depth] # where depth is [x, y, log(w), log(h)] x = KL.Conv2D(anchors_per_location * 4, (1, 1), padding="valid", activation='linear', name='rpn_bbox_pred')(shared) # Reshape to [batch, anchors, 4] rpn_bbox = KL.Lambda(lambda t: tf.reshape(t, [tf.shape(t)[0], -1, 4]))(x) return [rpn_class_logits, rpn_probs, rpn_bbox] def build_rpn_model(anchor_stride, anchors_per_location, depth): """Builds a Keras model of the Region Proposal Network. It wraps the RPN graph so it can be used multiple times with shared weights. anchors_per_location: number of anchors per pixel in the feature map anchor_stride: Controls the density of anchors. Typically 1 (anchors for every pixel in the feature map), or 2 (every other pixel). depth: Depth of the backbone feature map. Returns a Keras Model object. The model outputs, when called, are: rpn_class_logits: [batch, H * W * anchors_per_location, 2] Anchor classifier logits (before softmax) rpn_probs: [batch, H * W * anchors_per_location, 2] Anchor classifier probabilities. rpn_bbox: [batch, H * W * anchors_per_location, (dy, dx, log(dh), log(dw))] Deltas to be applied to anchors. """ input_feature_map = KL.Input(shape=[None, None, depth], name="input_rpn_feature_map") outputs = rpn_graph(input_feature_map, anchors_per_location, anchor_stride) return KM.Model([input_feature_map], outputs, name="rpn_model") ############################################################ # Feature Pyramid Network Heads ############################################################ def fpn_classifier_graph(rois, feature_maps, image_meta, pool_size, num_classes, train_bn=True, fc_layers_size=1024): """Builds the computation graph of the feature pyramid network classifier and regressor heads. rois: [batch, num_rois, (y1, x1, y2, x2)] Proposal boxes in normalized coordinates. feature_maps: List of feature maps from different layers of the pyramid, [P2, P3, P4, P5]. Each has a different resolution. image_meta: [batch, (meta data)] Image details. See compose_image_meta() pool_size: The width of the square feature map generated from ROI Pooling. num_classes: number of classes, which determines the depth of the results train_bn: Boolean. Train or freeze Batch Norm layers fc_layers_size: Size of the 2 FC layers Returns: logits: [batch, num_rois, NUM_CLASSES] classifier logits (before softmax) probs: [batch, num_rois, NUM_CLASSES] classifier probabilities bbox_deltas: [batch, num_rois, NUM_CLASSES, (dy, dx, log(dh), log(dw))] Deltas to apply to proposal boxes """ # ROI Pooling # Shape: [batch, num_rois, POOL_SIZE, POOL_SIZE, channels] x = PyramidROIAlign([pool_size, pool_size], name="roi_align_classifier")([rois, image_meta] + feature_maps) # Two 1024 FC layers (implemented with Conv2D for consistency) x = KL.TimeDistributed(KL.Conv2D(fc_layers_size, (pool_size, pool_size), padding="valid"), name="mrcnn_class_conv1")(x) x = KL.TimeDistributed(BatchNorm(), name='mrcnn_class_bn1')(x, training=train_bn) x = KL.Activation('relu')(x) x = KL.TimeDistributed(KL.Conv2D(fc_layers_size, (1, 1)), name="mrcnn_class_conv2")(x) x = KL.TimeDistributed(BatchNorm(), name='mrcnn_class_bn2')(x, training=train_bn) x = KL.Activation('relu')(x) shared = KL.Lambda(lambda x: K.squeeze(K.squeeze(x, 3), 2), name="pool_squeeze")(x) # Classifier head mrcnn_class_logits = KL.TimeDistributed(KL.Dense(num_classes), name='mrcnn_class_logits')(shared) mrcnn_probs = KL.TimeDistributed(KL.Activation("softmax"), name="mrcnn_class")(mrcnn_class_logits) # BBox head # [batch, num_rois, NUM_CLASSES * (dy, dx, log(dh), log(dw))] x = KL.TimeDistributed(KL.Dense(num_classes * 4, activation='linear'), name='mrcnn_bbox_fc')(shared) # Reshape to [batch, num_rois, NUM_CLASSES, (dy, dx, log(dh), log(dw))] s = K.int_shape(x) mrcnn_bbox = KL.Reshape((s[1], num_classes, 4), name="mrcnn_bbox")(x) return mrcnn_class_logits, mrcnn_probs, mrcnn_bbox def build_fpn_mask_graph(rois, feature_maps, image_meta, pool_size, num_classes, train_bn=True): """Builds the computation graph of the mask head of Feature Pyramid Network. rois: [batch, num_rois, (y1, x1, y2, x2)] Proposal boxes in normalized coordinates. feature_maps: List of feature maps from different layers of the pyramid, [P2, P3, P4, P5]. Each has a different resolution. image_meta: [batch, (meta data)] Image details. See compose_image_meta() pool_size: The width of the square feature map generated from ROI Pooling. num_classes: number of classes, which determines the depth of the results train_bn: Boolean. Train or freeze Batch Norm layers Returns: Masks [batch, num_rois, MASK_POOL_SIZE, MASK_POOL_SIZE, NUM_CLASSES] """ # ROI Pooling # Shape: [batch, num_rois, MASK_POOL_SIZE, MASK_POOL_SIZE, channels] x = PyramidROIAlign([pool_size, pool_size], name="roi_align_mask")([rois, image_meta] + feature_maps) # Conv layers x = KL.TimeDistributed(KL.Conv2D(256, (3, 3), padding="same"), name="mrcnn_mask_conv1")(x) x = KL.TimeDistributed(BatchNorm(), name='mrcnn_mask_bn1')(x, training=train_bn) x = KL.Activation('relu')(x) x = KL.TimeDistributed(KL.Conv2D(256, (3, 3), padding="same"), name="mrcnn_mask_conv2")(x) x = KL.TimeDistributed(BatchNorm(), name='mrcnn_mask_bn2')(x, training=train_bn) x = KL.Activation('relu')(x) x = KL.TimeDistributed(KL.Conv2D(256, (3, 3), padding="same"), name="mrcnn_mask_conv3")(x) x = KL.TimeDistributed(BatchNorm(), name='mrcnn_mask_bn3')(x, training=train_bn) x = KL.Activation('relu')(x) x = KL.TimeDistributed(KL.Conv2D(256, (3, 3), padding="same"), name="mrcnn_mask_conv4")(x) x = KL.TimeDistributed(BatchNorm(), name='mrcnn_mask_bn4')(x, training=train_bn) x = KL.Activation('relu')(x) x = KL.TimeDistributed(KL.Conv2DTranspose(256, (2, 2), strides=2, activation="relu"), name="mrcnn_mask_deconv")(x) x = KL.TimeDistributed(KL.Conv2D(num_classes, (1, 1), strides=1, activation="sigmoid"), name="mrcnn_mask")(x) return x ############################################################ # Loss Functions ############################################################ def smooth_l1_loss(y_true, y_pred): """Implements Smooth-L1 loss. y_true and y_pred are typically: [N, 4], but could be any shape. """ diff = K.abs(y_true - y_pred) less_than_one = K.cast(K.less(diff, 1.0), "float32") loss = (less_than_one * 0.5 * diff**2) + (1 - less_than_one) * (diff - 0.5) return loss def rpn_class_loss_graph(rpn_match, rpn_class_logits): """RPN anchor classifier loss. rpn_match: [batch, anchors, 1]. Anchor match type. 1=positive, -1=negative, 0=neutral anchor. rpn_class_logits: [batch, anchors, 2]. RPN classifier logits for BG/FG. """ # Squeeze last dim to simplify rpn_match = tf.squeeze(rpn_match, -1) # Get anchor classes. Convert the -1/+1 match to 0/1 values. anchor_class = K.cast(K.equal(rpn_match, 1), tf.int32) # Positive and Negative anchors contribute to the loss, # but neutral anchors (match value = 0) don't. indices = tf.where(K.not_equal(rpn_match, 0)) # Pick rows that contribute to the loss and filter out the rest. rpn_class_logits = tf.gather_nd(rpn_class_logits, indices) anchor_class = tf.gather_nd(anchor_class, indices) # Cross entropy loss loss = K.sparse_categorical_crossentropy(target=anchor_class, output=rpn_class_logits, from_logits=True) loss = K.switch(tf.size(loss) > 0, K.mean(loss), tf.constant(0.0)) return loss def rpn_bbox_loss_graph(config, target_bbox, rpn_match, rpn_bbox): """Return the RPN bounding box loss graph. config: the model config object. target_bbox: [batch, max positive anchors, (dy, dx, log(dh), log(dw))]. Uses 0 padding to fill in unsed bbox deltas. rpn_match: [batch, anchors, 1]. Anchor match type. 1=positive, -1=negative, 0=neutral anchor. rpn_bbox: [batch, anchors, (dy, dx, log(dh), log(dw))] """ # Positive anchors contribute to the loss, but negative and # neutral anchors (match value of 0 or -1) don't. rpn_match = K.squeeze(rpn_match, -1) indices = tf.where(K.equal(rpn_match, 1)) # Pick bbox deltas that contribute to the loss rpn_bbox = tf.gather_nd(rpn_bbox, indices) # Trim target bounding box deltas to the same length as rpn_bbox. batch_counts = K.sum(K.cast(K.equal(rpn_match, 1), tf.int32), axis=1) target_bbox = batch_pack_graph(target_bbox, batch_counts, config.IMAGES_PER_GPU) loss = smooth_l1_loss(target_bbox, rpn_bbox) loss = K.switch(tf.size(loss) > 0, K.mean(loss), tf.constant(0.0)) return loss def mrcnn_class_loss_graph(target_class_ids, pred_class_logits, active_class_ids): """Loss for the classifier head of Mask RCNN. target_class_ids: [batch, num_rois]. Integer class IDs. Uses zero padding to fill in the array. pred_class_logits: [batch, num_rois, num_classes] active_class_ids: [batch, num_classes]. Has a value of 1 for classes that are in the dataset of the image, and 0 for classes that are not in the dataset. """ # During model building, Keras calls this function with # target_class_ids of type float32. Unclear why. Cast it # to int to get around it. target_class_ids = tf.cast(target_class_ids, 'int64') # Find predictions of classes that are not in the dataset. pred_class_ids = tf.argmax(pred_class_logits, axis=2) # TODO: Update this line to work with batch > 1. Right now it assumes all # images in a batch have the same active_class_ids pred_active = tf.gather(active_class_ids[0], pred_class_ids) # Loss loss = tf.nn.sparse_softmax_cross_entropy_with_logits( labels=target_class_ids, logits=pred_class_logits) # Erase losses of predictions of classes that are not in the active # classes of the image. loss = loss * pred_active # Computer loss mean. Use only predictions that contribute # to the loss to get a correct mean. loss = tf.reduce_sum(loss) / tf.reduce_sum(pred_active) return loss def mrcnn_bbox_loss_graph(target_bbox, target_class_ids, pred_bbox): """Loss for Mask R-CNN bounding box refinement. target_bbox: [batch, num_rois, (dy, dx, log(dh), log(dw))] target_class_ids: [batch, num_rois]. Integer class IDs. pred_bbox: [batch, num_rois, num_classes, (dy, dx, log(dh), log(dw))] """ # Reshape to merge batch and roi dimensions for simplicity. target_class_ids = K.reshape(target_class_ids, (-1,)) target_bbox = K.reshape(target_bbox, (-1, 4)) pred_bbox = K.reshape(pred_bbox, (-1, K.int_shape(pred_bbox)[2], 4)) # Only positive ROIs contribute to the loss. And only # the right class_id of each ROI. Get their indices. positive_roi_ix = tf.where(target_class_ids > 0)[:, 0] positive_roi_class_ids = tf.cast( tf.gather(target_class_ids, positive_roi_ix), tf.int64) indices = tf.stack([positive_roi_ix, positive_roi_class_ids], axis=1) # Gather the deltas (predicted and true) that contribute to loss target_bbox = tf.gather(target_bbox, positive_roi_ix) pred_bbox = tf.gather_nd(pred_bbox, indices) # Smooth-L1 Loss loss = K.switch(tf.size(target_bbox) > 0, smooth_l1_loss(y_true=target_bbox, y_pred=pred_bbox), tf.constant(0.0)) loss = K.mean(loss) return loss def mrcnn_mask_loss_graph(target_masks, target_class_ids, pred_masks): """Mask binary cross-entropy loss for the masks head. target_masks: [batch, num_rois, height, width]. A float32 tensor of values 0 or 1. Uses zero padding to fill array. target_class_ids: [batch, num_rois]. Integer class IDs. Zero padded. pred_masks: [batch, proposals, height, width, num_classes] float32 tensor with values from 0 to 1. """ # Reshape for simplicity. Merge first two dimensions into one. target_class_ids = K.reshape(target_class_ids, (-1,)) mask_shape = tf.shape(target_masks) target_masks = K.reshape(target_masks, (-1, mask_shape[2], mask_shape[3])) pred_shape = tf.shape(pred_masks) pred_masks = K.reshape(pred_masks, (-1, pred_shape[2], pred_shape[3], pred_shape[4])) # Permute predicted masks to [N, num_classes, height, width] pred_masks = tf.transpose(pred_masks, [0, 3, 1, 2]) # Only positive ROIs contribute to the loss. And only # the class specific mask of each ROI. positive_ix = tf.where(target_class_ids > 0)[:, 0] positive_class_ids = tf.cast( tf.gather(target_class_ids, positive_ix), tf.int64) indices = tf.stack([positive_ix, positive_class_ids], axis=1) # Gather the masks (predicted and true) that contribute to loss y_true = tf.gather(target_masks, positive_ix) y_pred = tf.gather_nd(pred_masks, indices) # Compute binary cross entropy. If no positive ROIs, then return 0. # shape: [batch, roi, num_classes] loss = K.switch(tf.size(y_true) > 0, K.binary_crossentropy(target=y_true, output=y_pred), tf.constant(0.0)) loss = K.mean(loss) return loss ############################################################ # Data Generator ############################################################ def load_image_gt(dataset, config, image_id, augment=False, augmentation=None, use_mini_mask=False): """Load and return ground truth data for an image (image, mask, bounding boxes). augment: (deprecated. Use augmentation instead). If true, apply random image augmentation. Currently, only horizontal flipping is offered. augmentation: Optional. An imgaug (https://github.com/aleju/imgaug) augmentation. For example, passing imgaug.augmenters.Fliplr(0.5) flips images right/left 50% of the time. use_mini_mask: If False, returns full-size masks that are the same height and width as the original image. These can be big, for example 1024x1024x100 (for 100 instances). Mini masks are smaller, typically, 224x224 and are generated by extracting the bounding box of the object and resizing it to MINI_MASK_SHAPE. Returns: image: [height, width, 3] shape: the original shape of the image before resizing and cropping. class_ids: [instance_count] Integer class IDs bbox: [instance_count, (y1, x1, y2, x2)] mask: [height, width, instance_count]. The height and width are those of the image unless use_mini_mask is True, in which case they are defined in MINI_MASK_SHAPE. """ # Load image and mask image = dataset.load_image(image_id) mask, class_ids = dataset.load_mask(image_id) original_shape = image.shape image, window, scale, padding, crop = utils.resize_image( image, min_dim=config.IMAGE_MIN_DIM, min_scale=config.IMAGE_MIN_SCALE, max_dim=config.IMAGE_MAX_DIM, mode=config.IMAGE_RESIZE_MODE) mask = utils.resize_mask(mask, scale, padding, crop) # Random horizontal flips. # TODO: will be removed in a future update in favor of augmentation if augment: logging.warning("'augment' is deprecated. Use 'augmentation' instead.") if random.randint(0, 1): image = np.fliplr(image) mask = np.fliplr(mask) # Augmentation # This requires the imgaug lib (https://github.com/aleju/imgaug) if augmentation: import imgaug # Augmenters that are safe to apply to masks # Some, such as Affine, have settings that make them unsafe, so always # test your augmentation on masks MASK_AUGMENTERS = ["Sequential", "SomeOf", "OneOf", "Sometimes", "Fliplr", "Flipud", "CropAndPad", "Affine", "PiecewiseAffine"] def hook(images, augmenter, parents, default): """Determines which augmenters to apply to masks.""" return augmenter.__class__.__name__ in MASK_AUGMENTERS # Store shapes before augmentation to compare image_shape = image.shape mask_shape = mask.shape # Make augmenters deterministic to apply similarly to images and masks det = augmentation.to_deterministic() image = det.augment_image(image) # Change mask to np.uint8 because imgaug doesn't support np.bool mask = det.augment_image(mask.astype(np.uint8), hooks=imgaug.HooksImages(activator=hook)) # Verify that shapes didn't change assert image.shape == image_shape, "Augmentation shouldn't change image size" assert mask.shape == mask_shape, "Augmentation shouldn't change mask size" # Change mask back to bool mask = mask.astype(np.bool) # Note that some boxes might be all zeros if the corresponding mask got cropped out. # and here is to filter them out _idx = np.sum(mask, axis=(0, 1)) > 0 mask = mask[:, :, _idx] class_ids = class_ids[_idx] # Bounding boxes. Note that some boxes might be all zeros # if the corresponding mask got cropped out. # bbox: [num_instances, (y1, x1, y2, x2)] bbox = utils.extract_bboxes(mask) # Active classes # Different datasets have different classes, so track the # classes supported in the dataset of this image. active_class_ids = np.zeros([dataset.num_classes], dtype=np.int32) source_class_ids = dataset.source_class_ids[dataset.image_info[image_id]["source"]] active_class_ids[source_class_ids] = 1 # Resize masks to smaller size to reduce memory usage if use_mini_mask: mask = utils.minimize_mask(bbox, mask, config.MINI_MASK_SHAPE) # Image meta data image_meta = compose_image_meta(image_id, original_shape, image.shape, window, scale, active_class_ids) return image, image_meta, class_ids, bbox, mask def build_detection_targets(rpn_rois, gt_class_ids, gt_boxes, gt_masks, config): """Generate targets for training Stage 2 classifier and mask heads. This is not used in normal training. It's useful for debugging or to train the Mask RCNN heads without using the RPN head. Inputs: rpn_rois: [N, (y1, x1, y2, x2)] proposal boxes. gt_class_ids: [instance count] Integer class IDs gt_boxes: [instance count, (y1, x1, y2, x2)] gt_masks: [height, width, instance count] Ground truth masks. Can be full size or mini-masks. Returns: rois: [TRAIN_ROIS_PER_IMAGE, (y1, x1, y2, x2)] class_ids: [TRAIN_ROIS_PER_IMAGE]. Integer class IDs. bboxes: [TRAIN_ROIS_PER_IMAGE, NUM_CLASSES, (y, x, log(h), log(w))]. Class-specific bbox refinements. masks: [TRAIN_ROIS_PER_IMAGE, height, width, NUM_CLASSES). Class specific masks cropped to bbox boundaries and resized to neural network output size. """ assert rpn_rois.shape[0] > 0 assert gt_class_ids.dtype == np.int32, "Expected int but got {}".format( gt_class_ids.dtype) assert gt_boxes.dtype == np.int32, "Expected int but got {}".format( gt_boxes.dtype) assert gt_masks.dtype == np.bool_, "Expected bool but got {}".format( gt_masks.dtype) # It's common to add GT Boxes to ROIs but we don't do that here because # according to XinLei Chen's paper, it doesn't help. # Trim empty padding in gt_boxes and gt_masks parts instance_ids = np.where(gt_class_ids > 0)[0] assert instance_ids.shape[0] > 0, "Image must contain instances." gt_class_ids = gt_class_ids[instance_ids] gt_boxes = gt_boxes[instance_ids] gt_masks = gt_masks[:, :, instance_ids] # Compute areas of ROIs and ground truth boxes. rpn_roi_area = (rpn_rois[:, 2] - rpn_rois[:, 0]) * \ (rpn_rois[:, 3] - rpn_rois[:, 1]) gt_box_area = (gt_boxes[:, 2] - gt_boxes[:, 0]) * \ (gt_boxes[:, 3] - gt_boxes[:, 1]) # Compute overlaps [rpn_rois, gt_boxes] overlaps = np.zeros((rpn_rois.shape[0], gt_boxes.shape[0])) for i in range(overlaps.shape[1]): gt = gt_boxes[i] overlaps[:, i] = utils.compute_iou( gt, rpn_rois, gt_box_area[i], rpn_roi_area) # Assign ROIs to GT boxes rpn_roi_iou_argmax = np.argmax(overlaps, axis=1) rpn_roi_iou_max = overlaps[np.arange( overlaps.shape[0]), rpn_roi_iou_argmax] # GT box assigned to each ROI rpn_roi_gt_boxes = gt_boxes[rpn_roi_iou_argmax] rpn_roi_gt_class_ids = gt_class_ids[rpn_roi_iou_argmax] # Positive ROIs are those with >= 0.5 IoU with a GT box. fg_ids = np.where(rpn_roi_iou_max > 0.5)[0] # Negative ROIs are those with max IoU 0.1-0.5 (hard example mining) # TODO: To hard example mine or not to hard example mine, that's the question # bg_ids = np.where((rpn_roi_iou_max >= 0.1) & (rpn_roi_iou_max < 0.5))[0] bg_ids = np.where(rpn_roi_iou_max < 0.5)[0] # Subsample ROIs. Aim for 33% foreground. # FG fg_roi_count = int(config.TRAIN_ROIS_PER_IMAGE * config.ROI_POSITIVE_RATIO) if fg_ids.shape[0] > fg_roi_count: keep_fg_ids = np.random.choice(fg_ids, fg_roi_count, replace=False) else: keep_fg_ids = fg_ids # BG remaining = config.TRAIN_ROIS_PER_IMAGE - keep_fg_ids.shape[0] if bg_ids.shape[0] > remaining: keep_bg_ids = np.random.choice(bg_ids, remaining, replace=False) else: keep_bg_ids = bg_ids # Combine indices of ROIs to keep keep = np.concatenate([keep_fg_ids, keep_bg_ids]) # Need more? remaining = config.TRAIN_ROIS_PER_IMAGE - keep.shape[0] if remaining > 0: # Looks like we don't have enough samples to maintain the desired # balance. Reduce requirements and fill in the rest. This is # likely different from the Mask RCNN paper. # There is a small chance we have neither fg nor bg samples. if keep.shape[0] == 0: # Pick bg regions with easier IoU threshold bg_ids = np.where(rpn_roi_iou_max < 0.5)[0] assert bg_ids.shape[0] >= remaining keep_bg_ids = np.random.choice(bg_ids, remaining, replace=False) assert keep_bg_ids.shape[0] == remaining keep = np.concatenate([keep, keep_bg_ids]) else: # Fill the rest with repeated bg rois. keep_extra_ids = np.random.choice( keep_bg_ids, remaining, replace=True) keep = np.concatenate([keep, keep_extra_ids]) assert keep.shape[0] == config.TRAIN_ROIS_PER_IMAGE, \ "keep doesn't match ROI batch size {}, {}".format( keep.shape[0], config.TRAIN_ROIS_PER_IMAGE) # Reset the gt boxes assigned to BG ROIs. rpn_roi_gt_boxes[keep_bg_ids, :] = 0 rpn_roi_gt_class_ids[keep_bg_ids] = 0 # For each kept ROI, assign a class_id, and for FG ROIs also add bbox refinement. rois = rpn_rois[keep] roi_gt_boxes = rpn_roi_gt_boxes[keep] roi_gt_class_ids = rpn_roi_gt_class_ids[keep] roi_gt_assignment = rpn_roi_iou_argmax[keep] # Class-aware bbox deltas. [y, x, log(h), log(w)] bboxes = np.zeros((config.TRAIN_ROIS_PER_IMAGE, config.NUM_CLASSES, 4), dtype=np.float32) pos_ids = np.where(roi_gt_class_ids > 0)[0] bboxes[pos_ids, roi_gt_class_ids[pos_ids]] = utils.box_refinement( rois[pos_ids], roi_gt_boxes[pos_ids, :4]) # Normalize bbox refinements bboxes /= config.BBOX_STD_DEV # Generate class-specific target masks masks = np.zeros((config.TRAIN_ROIS_PER_IMAGE, config.MASK_SHAPE[0], config.MASK_SHAPE[1], config.NUM_CLASSES), dtype=np.float32) for i in pos_ids: class_id = roi_gt_class_ids[i] assert class_id > 0, "class id must be greater than 0" gt_id = roi_gt_assignment[i] class_mask = gt_masks[:, :, gt_id] if config.USE_MINI_MASK: # Create a mask placeholder, the size of the image placeholder = np.zeros(config.IMAGE_SHAPE[:2], dtype=bool) # GT box gt_y1, gt_x1, gt_y2, gt_x2 = gt_boxes[gt_id] gt_w = gt_x2 - gt_x1 gt_h = gt_y2 - gt_y1 # Resize mini mask to size of GT box placeholder[gt_y1:gt_y2, gt_x1:gt_x2] = \ np.round(utils.resize(class_mask, (gt_h, gt_w))).astype(bool) # Place the mini batch in the placeholder class_mask = placeholder # Pick part of the mask and resize it y1, x1, y2, x2 = rois[i].astype(np.int32) m = class_mask[y1:y2, x1:x2] mask = utils.resize(m, config.MASK_SHAPE) masks[i, :, :, class_id] = mask return rois, roi_gt_class_ids, bboxes, masks def build_rpn_targets(image_shape, anchors, gt_class_ids, gt_boxes, config): """Given the anchors and GT boxes, compute overlaps and identify positive anchors and deltas to refine them to match their corresponding GT boxes. anchors: [num_anchors, (y1, x1, y2, x2)] gt_class_ids: [num_gt_boxes] Integer class IDs. gt_boxes: [num_gt_boxes, (y1, x1, y2, x2)] Returns: rpn_match: [N] (int32) matches between anchors and GT boxes. 1 = positive anchor, -1 = negative anchor, 0 = neutral rpn_bbox: [N, (dy, dx, log(dh), log(dw))] Anchor bbox deltas. """ # RPN Match: 1 = positive anchor, -1 = negative anchor, 0 = neutral rpn_match = np.zeros([anchors.shape[0]], dtype=np.int32) # RPN bounding boxes: [max anchors per image, (dy, dx, log(dh), log(dw))] rpn_bbox = np.zeros((config.RPN_TRAIN_ANCHORS_PER_IMAGE, 4)) # Handle COCO crowds # A crowd box in COCO is a bounding box around several instances. Exclude # them from training. A crowd box is given a negative class ID. crowd_ix = np.where(gt_class_ids < 0)[0] if crowd_ix.shape[0] > 0: # Filter out crowds from ground truth class IDs and boxes non_crowd_ix = np.where(gt_class_ids > 0)[0] crowd_boxes = gt_boxes[crowd_ix] gt_class_ids = gt_class_ids[non_crowd_ix] gt_boxes = gt_boxes[non_crowd_ix] # Compute overlaps with crowd boxes [anchors, crowds] crowd_overlaps = utils.compute_overlaps(anchors, crowd_boxes) crowd_iou_max = np.amax(crowd_overlaps, axis=1) no_crowd_bool = (crowd_iou_max < 0.001) else: # All anchors don't intersect a crowd no_crowd_bool = np.ones([anchors.shape[0]], dtype=bool) # Compute overlaps [num_anchors, num_gt_boxes] overlaps = utils.compute_overlaps(anchors, gt_boxes) # Match anchors to GT Boxes # If an anchor overlaps a GT box with IoU >= 0.7 then it's positive. # If an anchor overlaps a GT box with IoU < 0.3 then it's negative. # Neutral anchors are those that don't match the conditions above, # and they don't influence the loss function. # However, don't keep any GT box unmatched (rare, but happens). Instead, # match it to the closest anchor (even if its max IoU is < 0.3). # # 1. Set negative anchors first. They get overwritten below if a GT box is # matched to them. Skip boxes in crowd areas. anchor_iou_argmax = np.argmax(overlaps, axis=1) anchor_iou_max = overlaps[np.arange(overlaps.shape[0]), anchor_iou_argmax] rpn_match[(anchor_iou_max < 0.3) & (no_crowd_bool)] = -1 # 2. Set an anchor for each GT box (regardless of IoU value). # If multiple anchors have the same IoU match all of them gt_iou_argmax = np.argwhere(overlaps == np.max(overlaps, axis=0))[:,0] rpn_match[gt_iou_argmax] = 1 # 3. Set anchors with high overlap as positive. rpn_match[anchor_iou_max >= 0.7] = 1 # Subsample to balance positive and negative anchors # Don't let positives be more than half the anchors ids = np.where(rpn_match == 1)[0] extra = len(ids) - (config.RPN_TRAIN_ANCHORS_PER_IMAGE // 2) if extra > 0: # Reset the extra ones to neutral ids = np.random.choice(ids, extra, replace=False) rpn_match[ids] = 0 # Same for negative proposals ids = np.where(rpn_match == -1)[0] extra = len(ids) - (config.RPN_TRAIN_ANCHORS_PER_IMAGE - np.sum(rpn_match == 1)) if extra > 0: # Rest the extra ones to neutral ids = np.random.choice(ids, extra, replace=False) rpn_match[ids] = 0 # For positive anchors, compute shift and scale needed to transform them # to match the corresponding GT boxes. ids = np.where(rpn_match == 1)[0] ix = 0 # index into rpn_bbox # TODO: use box_refinement() rather than duplicating the code here for i, a in zip(ids, anchors[ids]): # Closest gt box (it might have IoU < 0.7) gt = gt_boxes[anchor_iou_argmax[i]] # Convert coordinates to center plus width/height. # GT Box gt_h = gt[2] - gt[0] gt_w = gt[3] - gt[1] gt_center_y = gt[0] + 0.5 * gt_h gt_center_x = gt[1] + 0.5 * gt_w # Anchor a_h = a[2] - a[0] a_w = a[3] - a[1] a_center_y = a[0] + 0.5 * a_h a_center_x = a[1] + 0.5 * a_w # Compute the bbox refinement that the RPN should predict. rpn_bbox[ix] = [ (gt_center_y - a_center_y) / a_h, (gt_center_x - a_center_x) / a_w, np.log(gt_h / a_h), np.log(gt_w / a_w), ] # Normalize rpn_bbox[ix] /= config.RPN_BBOX_STD_DEV ix += 1 return rpn_match, rpn_bbox def generate_random_rois(image_shape, count, gt_class_ids, gt_boxes): """Generates ROI proposals similar to what a region proposal network would generate. image_shape: [Height, Width, Depth] count: Number of ROIs to generate gt_class_ids: [N] Integer ground truth class IDs gt_boxes: [N, (y1, x1, y2, x2)] Ground truth boxes in pixels. Returns: [count, (y1, x1, y2, x2)] ROI boxes in pixels. """ # placeholder rois = np.zeros((count, 4), dtype=np.int32) # Generate random ROIs around GT boxes (90% of count) rois_per_box = int(0.9 * count / gt_boxes.shape[0]) for i in range(gt_boxes.shape[0]): gt_y1, gt_x1, gt_y2, gt_x2 = gt_boxes[i] h = gt_y2 - gt_y1 w = gt_x2 - gt_x1 # random boundaries r_y1 = max(gt_y1 - h, 0) r_y2 = min(gt_y2 + h, image_shape[0]) r_x1 = max(gt_x1 - w, 0) r_x2 = min(gt_x2 + w, image_shape[1]) # To avoid generating boxes with zero area, we generate double what # we need and filter out the extra. If we get fewer valid boxes # than we need, we loop and try again. while True: y1y2 = np.random.randint(r_y1, r_y2, (rois_per_box * 2, 2)) x1x2 = np.random.randint(r_x1, r_x2, (rois_per_box * 2, 2)) # Filter out zero area boxes threshold = 1 y1y2 = y1y2[np.abs(y1y2[:, 0] - y1y2[:, 1]) >= threshold][:rois_per_box] x1x2 = x1x2[np.abs(x1x2[:, 0] - x1x2[:, 1]) >= threshold][:rois_per_box] if y1y2.shape[0] == rois_per_box and x1x2.shape[0] == rois_per_box: break # Sort on axis 1 to ensure x1 <= x2 and y1 <= y2 and then reshape # into x1, y1, x2, y2 order x1, x2 = np.split(np.sort(x1x2, axis=1), 2, axis=1) y1, y2 = np.split(np.sort(y1y2, axis=1), 2, axis=1) box_rois = np.hstack([y1, x1, y2, x2]) rois[rois_per_box * i:rois_per_box * (i + 1)] = box_rois # Generate random ROIs anywhere in the image (10% of count) remaining_count = count - (rois_per_box * gt_boxes.shape[0]) # To avoid generating boxes with zero area, we generate double what # we need and filter out the extra. If we get fewer valid boxes # than we need, we loop and try again. while True: y1y2 = np.random.randint(0, image_shape[0], (remaining_count * 2, 2)) x1x2 = np.random.randint(0, image_shape[1], (remaining_count * 2, 2)) # Filter out zero area boxes threshold = 1 y1y2 = y1y2[np.abs(y1y2[:, 0] - y1y2[:, 1]) >= threshold][:remaining_count] x1x2 = x1x2[np.abs(x1x2[:, 0] - x1x2[:, 1]) >= threshold][:remaining_count] if y1y2.shape[0] == remaining_count and x1x2.shape[0] == remaining_count: break # Sort on axis 1 to ensure x1 <= x2 and y1 <= y2 and then reshape # into x1, y1, x2, y2 order x1, x2 = np.split(np.sort(x1x2, axis=1), 2, axis=1) y1, y2 = np.split(np.sort(y1y2, axis=1), 2, axis=1) global_rois = np.hstack([y1, x1, y2, x2]) rois[-remaining_count:] = global_rois return rois def data_generator(dataset, config, shuffle=True, augment=False, augmentation=None, random_rois=0, batch_size=1, detection_targets=False, no_augmentation_sources=None): """A generator that returns images and corresponding target class ids, bounding box deltas, and masks. dataset: The Dataset object to pick data from config: The model config object shuffle: If True, shuffles the samples before every epoch augment: (deprecated. Use augmentation instead). If true, apply random image augmentation. Currently, only horizontal flipping is offered. augmentation: Optional. An imgaug (https://github.com/aleju/imgaug) augmentation. For example, passing imgaug.augmenters.Fliplr(0.5) flips images right/left 50% of the time. random_rois: If > 0 then generate proposals to be used to train the network classifier and mask heads. Useful if training the Mask RCNN part without the RPN. batch_size: How many images to return in each call detection_targets: If True, generate detection targets (class IDs, bbox deltas, and masks). Typically for debugging or visualizations because in trainig detection targets are generated by DetectionTargetLayer. no_augmentation_sources: Optional. List of sources to exclude for augmentation. A source is string that identifies a dataset and is defined in the Dataset class. Returns a Python generator. Upon calling next() on it, the generator returns two lists, inputs and outputs. The contents of the lists differs depending on the received arguments: inputs list: - images: [batch, H, W, C] - image_meta: [batch, (meta data)] Image details. See compose_image_meta() - rpn_match: [batch, N] Integer (1=positive anchor, -1=negative, 0=neutral) - rpn_bbox: [batch, N, (dy, dx, log(dh), log(dw))] Anchor bbox deltas. - gt_class_ids: [batch, MAX_GT_INSTANCES] Integer class IDs - gt_boxes: [batch, MAX_GT_INSTANCES, (y1, x1, y2, x2)] - gt_masks: [batch, height, width, MAX_GT_INSTANCES]. The height and width are those of the image unless use_mini_mask is True, in which case they are defined in MINI_MASK_SHAPE. outputs list: Usually empty in regular training. But if detection_targets is True then the outputs list contains target class_ids, bbox deltas, and masks. """ b = 0 # batch item index image_index = -1 image_ids = np.copy(dataset.image_ids) error_count = 0 no_augmentation_sources = no_augmentation_sources or [] # Anchors # [anchor_count, (y1, x1, y2, x2)] backbone_shapes = compute_backbone_shapes(config, config.IMAGE_SHAPE) anchors = utils.generate_pyramid_anchors(config.RPN_ANCHOR_SCALES, config.RPN_ANCHOR_RATIOS, backbone_shapes, config.BACKBONE_STRIDES, config.RPN_ANCHOR_STRIDE) # Keras requires a generator to run indefinitely. while True: try: # Increment index to pick next image. Shuffle if at the start of an epoch. image_index = (image_index + 1) % len(image_ids) if shuffle and image_index == 0: np.random.shuffle(image_ids) # Get GT bounding boxes and masks for image. image_id = image_ids[image_index] # If the image source is not to be augmented pass None as augmentation if dataset.image_info[image_id]['source'] in no_augmentation_sources: image, image_meta, gt_class_ids, gt_boxes, gt_masks = \ load_image_gt(dataset, config, image_id, augment=augment, augmentation=None, use_mini_mask=config.USE_MINI_MASK) else: image, image_meta, gt_class_ids, gt_boxes, gt_masks = \ load_image_gt(dataset, config, image_id, augment=augment, augmentation=augmentation, use_mini_mask=config.USE_MINI_MASK) # Skip images that have no instances. This can happen in cases # where we train on a subset of classes and the image doesn't # have any of the classes we care about. if not np.any(gt_class_ids > 0): continue # RPN Targets rpn_match, rpn_bbox = build_rpn_targets(image.shape, anchors, gt_class_ids, gt_boxes, config) # Mask R-CNN Targets if random_rois: rpn_rois = generate_random_rois( image.shape, random_rois, gt_class_ids, gt_boxes) if detection_targets: rois, mrcnn_class_ids, mrcnn_bbox, mrcnn_mask =\ build_detection_targets( rpn_rois, gt_class_ids, gt_boxes, gt_masks, config) # Init batch arrays if b == 0: batch_image_meta = np.zeros( (batch_size,) + image_meta.shape, dtype=image_meta.dtype) batch_rpn_match = np.zeros( [batch_size, anchors.shape[0], 1], dtype=rpn_match.dtype) batch_rpn_bbox = np.zeros( [batch_size, config.RPN_TRAIN_ANCHORS_PER_IMAGE, 4], dtype=rpn_bbox.dtype) batch_images = np.zeros( (batch_size,) + image.shape, dtype=np.float32) batch_gt_class_ids = np.zeros( (batch_size, config.MAX_GT_INSTANCES), dtype=np.int32) batch_gt_boxes = np.zeros( (batch_size, config.MAX_GT_INSTANCES, 4), dtype=np.int32) batch_gt_masks = np.zeros( (batch_size, gt_masks.shape[0], gt_masks.shape[1], config.MAX_GT_INSTANCES), dtype=gt_masks.dtype) if random_rois: batch_rpn_rois = np.zeros( (batch_size, rpn_rois.shape[0], 4), dtype=rpn_rois.dtype) if detection_targets: batch_rois = np.zeros( (batch_size,) + rois.shape, dtype=rois.dtype) batch_mrcnn_class_ids = np.zeros( (batch_size,) + mrcnn_class_ids.shape, dtype=mrcnn_class_ids.dtype) batch_mrcnn_bbox = np.zeros( (batch_size,) + mrcnn_bbox.shape, dtype=mrcnn_bbox.dtype) batch_mrcnn_mask = np.zeros( (batch_size,) + mrcnn_mask.shape, dtype=mrcnn_mask.dtype) # If more instances than fits in the array, sub-sample from them. if gt_boxes.shape[0] > config.MAX_GT_INSTANCES: ids = np.random.choice( np.arange(gt_boxes.shape[0]), config.MAX_GT_INSTANCES, replace=False) gt_class_ids = gt_class_ids[ids] gt_boxes = gt_boxes[ids] gt_masks = gt_masks[:, :, ids] # Add to batch batch_image_meta[b] = image_meta batch_rpn_match[b] = rpn_match[:, np.newaxis] batch_rpn_bbox[b] = rpn_bbox batch_images[b] = mold_image(image.astype(np.float32), config) batch_gt_class_ids[b, :gt_class_ids.shape[0]] = gt_class_ids batch_gt_boxes[b, :gt_boxes.shape[0]] = gt_boxes batch_gt_masks[b, :, :, :gt_masks.shape[-1]] = gt_masks if random_rois: batch_rpn_rois[b] = rpn_rois if detection_targets: batch_rois[b] = rois batch_mrcnn_class_ids[b] = mrcnn_class_ids batch_mrcnn_bbox[b] = mrcnn_bbox batch_mrcnn_mask[b] = mrcnn_mask b += 1 # Batch full? if b >= batch_size: inputs = [batch_images, batch_image_meta, batch_rpn_match, batch_rpn_bbox, batch_gt_class_ids, batch_gt_boxes, batch_gt_masks] outputs = [] if random_rois: inputs.extend([batch_rpn_rois]) if detection_targets: inputs.extend([batch_rois]) # Keras requires that output and targets have the same number of dimensions batch_mrcnn_class_ids = np.expand_dims( batch_mrcnn_class_ids, -1) outputs.extend( [batch_mrcnn_class_ids, batch_mrcnn_bbox, batch_mrcnn_mask]) yield inputs, outputs # start a new batch b = 0 except (GeneratorExit, KeyboardInterrupt): raise except: # Log it and skip the image logging.exception("Error processing image {}".format( dataset.image_info[image_id])) error_count += 1 if error_count > 5: raise ############################################################ # MaskRCNN Class ############################################################ class MaskRCNN(): """Encapsulates the Mask RCNN model functionality. The actual Keras model is in the keras_model property. """ def __init__(self, mode, config, model_dir): """ mode: Either "training" or "inference" config: A Sub-class of the Config class model_dir: Directory to save training logs and trained weights """ assert mode in ['training', 'inference'] self.mode = mode self.config = config self.model_dir = model_dir self.set_log_dir() self.keras_model = self.build(mode=mode, config=config) def build(self, mode, config): """Build Mask R-CNN architecture. input_shape: The shape of the input image. mode: Either "training" or "inference". The inputs and outputs of the model differ accordingly. """ assert mode in ['training', 'inference'] # Image size must be dividable by 2 multiple times h, w = config.IMAGE_SHAPE[:2] if h / 2**6 != int(h / 2**6) or w / 2**6 != int(w / 2**6): raise Exception("Image size must be dividable by 2 at least 6 times " "to avoid fractions when downscaling and upscaling." "For example, use 256, 320, 384, 448, 512, ... etc. ") # Inputs input_image = KL.Input( shape=[None, None, config.IMAGE_SHAPE[2]], name="input_image") input_image_meta = KL.Input(shape=[config.IMAGE_META_SIZE], name="input_image_meta") if mode == "training": # RPN GT input_rpn_match = KL.Input( shape=[None, 1], name="input_rpn_match", dtype=tf.int32) input_rpn_bbox = KL.Input( shape=[None, 4], name="input_rpn_bbox", dtype=tf.float32) # Detection GT (class IDs, bounding boxes, and masks) # 1. GT Class IDs (zero padded) input_gt_class_ids = KL.Input( shape=[None], name="input_gt_class_ids", dtype=tf.int32) # 2. GT Boxes in pixels (zero padded) # [batch, MAX_GT_INSTANCES, (y1, x1, y2, x2)] in image coordinates input_gt_boxes = KL.Input( shape=[None, 4], name="input_gt_boxes", dtype=tf.float32) # Normalize coordinates gt_boxes = KL.Lambda(lambda x: norm_boxes_graph( x, K.shape(input_image)[1:3]))(input_gt_boxes) # 3. GT Masks (zero padded) # [batch, height, width, MAX_GT_INSTANCES] if config.USE_MINI_MASK: input_gt_masks = KL.Input( shape=[config.MINI_MASK_SHAPE[0], config.MINI_MASK_SHAPE[1], None], name="input_gt_masks", dtype=bool) else: input_gt_masks = KL.Input( shape=[config.IMAGE_SHAPE[0], config.IMAGE_SHAPE[1], None], name="input_gt_masks", dtype=bool) elif mode == "inference": # Anchors in normalized coordinates input_anchors = KL.Input(shape=[None, 4], name="input_anchors") # Build the shared convolutional layers. # Bottom-up Layers # Returns a list of the last layers of each stage, 5 in total. # Don't create the thead (stage 5), so we pick the 4th item in the list. if callable(config.BACKBONE): _, C2, C3, C4, C5 = config.BACKBONE(input_image, stage5=True, train_bn=config.TRAIN_BN) else: _, C2, C3, C4, C5 = resnet_graph(input_image, config.BACKBONE, stage5=True, train_bn=config.TRAIN_BN) # Top-down Layers # TODO: add assert to varify feature map sizes match what's in config P5 = KL.Conv2D(config.TOP_DOWN_PYRAMID_SIZE, (1, 1), name='fpn_c5p5')(C5) P4 = KL.Add(name="fpn_p4add")([ KL.UpSampling2D(size=(2, 2), name="fpn_p5upsampled")(P5), KL.Conv2D(config.TOP_DOWN_PYRAMID_SIZE, (1, 1), name='fpn_c4p4')(C4)]) P3 = KL.Add(name="fpn_p3add")([ KL.UpSampling2D(size=(2, 2), name="fpn_p4upsampled")(P4), KL.Conv2D(config.TOP_DOWN_PYRAMID_SIZE, (1, 1), name='fpn_c3p3')(C3)]) P2 = KL.Add(name="fpn_p2add")([ KL.UpSampling2D(size=(2, 2), name="fpn_p3upsampled")(P3), KL.Conv2D(config.TOP_DOWN_PYRAMID_SIZE, (1, 1), name='fpn_c2p2')(C2)]) # Attach 3x3 conv to all P layers to get the final feature maps. P2 = KL.Conv2D(config.TOP_DOWN_PYRAMID_SIZE, (3, 3), padding="SAME", name="fpn_p2")(P2) P3 = KL.Conv2D(config.TOP_DOWN_PYRAMID_SIZE, (3, 3), padding="SAME", name="fpn_p3")(P3) P4 = KL.Conv2D(config.TOP_DOWN_PYRAMID_SIZE, (3, 3), padding="SAME", name="fpn_p4")(P4) P5 = KL.Conv2D(config.TOP_DOWN_PYRAMID_SIZE, (3, 3), padding="SAME", name="fpn_p5")(P5) # P6 is used for the 5th anchor scale in RPN. Generated by # subsampling from P5 with stride of 2. P6 = KL.MaxPooling2D(pool_size=(1, 1), strides=2, name="fpn_p6")(P5) # Note that P6 is used in RPN, but not in the classifier heads. rpn_feature_maps = [P2, P3, P4, P5, P6] mrcnn_feature_maps = [P2, P3, P4, P5] # Anchors if mode == "training": anchors = self.get_anchors(config.IMAGE_SHAPE) # Duplicate across the batch dimension because Keras requires it # TODO: can this be optimized to avoid duplicating the anchors? anchors = np.broadcast_to(anchors, (config.BATCH_SIZE,) + anchors.shape) # A hack to get around Keras's bad support for constants anchors = KL.Lambda(lambda x: tf.Variable(anchors), name="anchors")(input_image) else: anchors = input_anchors # RPN Model rpn = build_rpn_model(config.RPN_ANCHOR_STRIDE, len(config.RPN_ANCHOR_RATIOS), config.TOP_DOWN_PYRAMID_SIZE) # Loop through pyramid layers layer_outputs = [] # list of lists for p in rpn_feature_maps: layer_outputs.append(rpn([p])) # Concatenate layer outputs # Convert from list of lists of level outputs to list of lists # of outputs across levels. # e.g. [[a1, b1, c1], [a2, b2, c2]] => [[a1, a2], [b1, b2], [c1, c2]] output_names = ["rpn_class_logits", "rpn_class", "rpn_bbox"] outputs = list(zip(*layer_outputs)) outputs = [KL.Concatenate(axis=1, name=n)(list(o)) for o, n in zip(outputs, output_names)] rpn_class_logits, rpn_class, rpn_bbox = outputs # Generate proposals # Proposals are [batch, N, (y1, x1, y2, x2)] in normalized coordinates # and zero padded. proposal_count = config.POST_NMS_ROIS_TRAINING if mode == "training"\ else config.POST_NMS_ROIS_INFERENCE rpn_rois = ProposalLayer( proposal_count=proposal_count, nms_threshold=config.RPN_NMS_THRESHOLD, name="ROI", config=config)([rpn_class, rpn_bbox, anchors]) if mode == "training": # Class ID mask to mark class IDs supported by the dataset the image # came from. active_class_ids = KL.Lambda( lambda x: parse_image_meta_graph(x)["active_class_ids"] )(input_image_meta) if not config.USE_RPN_ROIS: # Ignore predicted ROIs and use ROIs provided as an input. input_rois = KL.Input(shape=[config.POST_NMS_ROIS_TRAINING, 4], name="input_roi", dtype=np.int32) # Normalize coordinates target_rois = KL.Lambda(lambda x: norm_boxes_graph( x, K.shape(input_image)[1:3]))(input_rois) else: target_rois = rpn_rois # Generate detection targets # Subsamples proposals and generates target outputs for training # Note that proposal class IDs, gt_boxes, and gt_masks are zero # padded. Equally, returned rois and targets are zero padded. rois, target_class_ids, target_bbox, target_mask =\ DetectionTargetLayer(config, name="proposal_targets")([ target_rois, input_gt_class_ids, gt_boxes, input_gt_masks]) # Network Heads # TODO: verify that this handles zero padded ROIs mrcnn_class_logits, mrcnn_class, mrcnn_bbox =\ fpn_classifier_graph(rois, mrcnn_feature_maps, input_image_meta, config.POOL_SIZE, config.NUM_CLASSES, train_bn=config.TRAIN_BN, fc_layers_size=config.FPN_CLASSIF_FC_LAYERS_SIZE) mrcnn_mask = build_fpn_mask_graph(rois, mrcnn_feature_maps, input_image_meta, config.MASK_POOL_SIZE, config.NUM_CLASSES, train_bn=config.TRAIN_BN) # TODO: clean up (use tf.identify if necessary) output_rois = KL.Lambda(lambda x: x * 1, name="output_rois")(rois) # Losses rpn_class_loss = KL.Lambda(lambda x: rpn_class_loss_graph(*x), name="rpn_class_loss")( [input_rpn_match, rpn_class_logits]) rpn_bbox_loss = KL.Lambda(lambda x: rpn_bbox_loss_graph(config, *x), name="rpn_bbox_loss")( [input_rpn_bbox, input_rpn_match, rpn_bbox]) class_loss = KL.Lambda(lambda x: mrcnn_class_loss_graph(*x), name="mrcnn_class_loss")( [target_class_ids, mrcnn_class_logits, active_class_ids]) bbox_loss = KL.Lambda(lambda x: mrcnn_bbox_loss_graph(*x), name="mrcnn_bbox_loss")( [target_bbox, target_class_ids, mrcnn_bbox]) mask_loss = KL.Lambda(lambda x: mrcnn_mask_loss_graph(*x), name="mrcnn_mask_loss")( [target_mask, target_class_ids, mrcnn_mask]) # Model inputs = [input_image, input_image_meta, input_rpn_match, input_rpn_bbox, input_gt_class_ids, input_gt_boxes, input_gt_masks] if not config.USE_RPN_ROIS: inputs.append(input_rois) outputs = [rpn_class_logits, rpn_class, rpn_bbox, mrcnn_class_logits, mrcnn_class, mrcnn_bbox, mrcnn_mask, rpn_rois, output_rois, rpn_class_loss, rpn_bbox_loss, class_loss, bbox_loss, mask_loss] model = KM.Model(inputs, outputs, name='mask_rcnn') else: # Network Heads # Proposal classifier and BBox regressor heads mrcnn_class_logits, mrcnn_class, mrcnn_bbox =\ fpn_classifier_graph(rpn_rois, mrcnn_feature_maps, input_image_meta, config.POOL_SIZE, config.NUM_CLASSES, train_bn=config.TRAIN_BN, fc_layers_size=config.FPN_CLASSIF_FC_LAYERS_SIZE) # Detections # output is [batch, num_detections, (y1, x1, y2, x2, class_id, score)] in # normalized coordinates detections = DetectionLayer(config, name="mrcnn_detection")( [rpn_rois, mrcnn_class, mrcnn_bbox, input_image_meta]) # Create masks for detections detection_boxes = KL.Lambda(lambda x: x[..., :4])(detections) mrcnn_mask = build_fpn_mask_graph(detection_boxes, mrcnn_feature_maps, input_image_meta, config.MASK_POOL_SIZE, config.NUM_CLASSES, train_bn=config.TRAIN_BN) model = KM.Model([input_image, input_image_meta, input_anchors], [detections, mrcnn_class, mrcnn_bbox, mrcnn_mask, rpn_rois, rpn_class, rpn_bbox], name='mask_rcnn') # Add multi-GPU support. if config.GPU_COUNT > 1: from mrcnn.parallel_model import ParallelModel model = ParallelModel(model, config.GPU_COUNT) return model def find_last(self): """Finds the last checkpoint file of the last trained model in the model directory. Returns: The path of the last checkpoint file """ # Get directory names. Each directory corresponds to a model dir_names = next(os.walk(self.model_dir))[1] key = self.config.NAME.lower() dir_names = filter(lambda f: f.startswith(key), dir_names) dir_names = sorted(dir_names) if not dir_names: import errno raise FileNotFoundError( errno.ENOENT, "Could not find model directory under {}".format(self.model_dir)) # Pick last directory dir_name = os.path.join(self.model_dir, dir_names[-1]) # Find the last checkpoint checkpoints = next(os.walk(dir_name))[2] checkpoints = filter(lambda f: f.startswith("mask_rcnn"), checkpoints) checkpoints = sorted(checkpoints) if not checkpoints: import errno raise FileNotFoundError( errno.ENOENT, "Could not find weight files in {}".format(dir_name)) checkpoint = os.path.join(dir_name, checkpoints[-1]) return checkpoint def load_weights(self, filepath, by_name=False, exclude=None): """Modified version of the corresponding Keras function with the addition of multi-GPU support and the ability to exclude some layers from loading. exclude: list of layer names to exclude """ import h5py # Conditional import to support versions of Keras before 2.2 # TODO: remove in about 6 months (end of 2018) try: from keras.engine import saving except ImportError: # Keras before 2.2 used the 'topology' namespace. from keras.engine import topology as saving if exclude: by_name = True if h5py is None: raise ImportError('`load_weights` requires h5py.') f = h5py.File(filepath, mode='r') if 'layer_names' not in f.attrs and 'model_weights' in f: f = f['model_weights'] # In multi-GPU training, we wrap the model. Get layers # of the inner model because they have the weights. keras_model = self.keras_model layers = keras_model.inner_model.layers if hasattr(keras_model, "inner_model")\ else keras_model.layers # Exclude some layers if exclude: layers = filter(lambda l: l.name not in exclude, layers) if by_name: saving.load_weights_from_hdf5_group_by_name(f, layers) else: saving.load_weights_from_hdf5_group(f, layers) if hasattr(f, 'close'): f.close() # Update the log directory self.set_log_dir(filepath) def get_imagenet_weights(self): """Downloads ImageNet trained weights from Keras. Returns path to weights file. """ from keras.utils.data_utils import get_file TF_WEIGHTS_PATH_NO_TOP = 'https://github.com/fchollet/deep-learning-models/'\ 'releases/download/v0.2/'\ 'resnet50_weights_tf_dim_ordering_tf_kernels_notop.h5' weights_path = get_file('resnet50_weights_tf_dim_ordering_tf_kernels_notop.h5', TF_WEIGHTS_PATH_NO_TOP, cache_subdir='models', md5_hash='a268eb855778b3df3c7506639542a6af') return weights_path def compile(self, learning_rate, momentum): """Gets the model ready for training. Adds losses, regularization, and metrics. Then calls the Keras compile() function. """ # Optimizer object optimizer = keras.optimizers.SGD( lr=learning_rate, momentum=momentum, clipnorm=self.config.GRADIENT_CLIP_NORM) # Add Losses # First, clear previously set losses to avoid duplication self.keras_model._losses = [] self.keras_model._per_input_losses = {} loss_names = [ "rpn_class_loss", "rpn_bbox_loss", "mrcnn_class_loss", "mrcnn_bbox_loss", "mrcnn_mask_loss"] for name in loss_names: layer = self.keras_model.get_layer(name) if layer.output in self.keras_model.losses: continue loss = ( tf.reduce_mean(layer.output, keepdims=True) * self.config.LOSS_WEIGHTS.get(name, 1.)) self.keras_model.add_loss(loss) # Add L2 Regularization # Skip gamma and beta weights of batch normalization layers. reg_losses = [ keras.regularizers.l2(self.config.WEIGHT_DECAY)(w) / tf.cast(tf.size(w), tf.float32) for w in self.keras_model.trainable_weights if 'gamma' not in w.name and 'beta' not in w.name] self.keras_model.add_loss(tf.add_n(reg_losses)) # Compile self.keras_model.compile( optimizer=optimizer, loss=[None] * len(self.keras_model.outputs)) # Add metrics for losses for name in loss_names: if name in self.keras_model.metrics_names: continue layer = self.keras_model.get_layer(name) self.keras_model.metrics_names.append(name) loss = ( tf.reduce_mean(layer.output, keepdims=True) * self.config.LOSS_WEIGHTS.get(name, 1.)) self.keras_model.metrics_tensors.append(loss) def set_trainable(self, layer_regex, keras_model=None, indent=0, verbose=1): """Sets model layers as trainable if their names match the given regular expression. """ # Print message on the first call (but not on recursive calls) if verbose > 0 and keras_model is None: log("Selecting layers to train") keras_model = keras_model or self.keras_model # In multi-GPU training, we wrap the model. Get layers # of the inner model because they have the weights. layers = keras_model.inner_model.layers if hasattr(keras_model, "inner_model")\ else keras_model.layers for layer in layers: # Is the layer a model? if layer.__class__.__name__ == 'Model': print("In model: ", layer.name) self.set_trainable( layer_regex, keras_model=layer, indent=indent + 4) continue if not layer.weights: continue # Is it trainable? trainable = bool(re.fullmatch(layer_regex, layer.name)) # Update layer. If layer is a container, update inner layer. if layer.__class__.__name__ == 'TimeDistributed': layer.layer.trainable = trainable else: layer.trainable = trainable # Print trainable layer names if trainable and verbose > 0: log("{}{:20} ({})".format(" " * indent, layer.name, layer.__class__.__name__)) def set_log_dir(self, model_path=None): """Sets the model log directory and epoch counter. model_path: If None, or a format different from what this code uses then set a new log directory and start epochs from 0. Otherwise, extract the log directory and the epoch counter from the file name. """ # Set date and epoch counter as if starting a new model self.epoch = 0 now = datetime.datetime.now() # If we have a model path with date and epochs use them if model_path: # Continue from we left of. Get epoch and date from the file name # A sample model path might look like: # \path\to\logs\coco20171029T2315\mask_rcnn_coco_0001.h5 (Windows) # /path/to/logs/coco20171029T2315/mask_rcnn_coco_0001.h5 (Linux) regex = r".*[/\\][\w-]+(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})[/\\]mask\_rcnn\_[\w-]+(\d{4})\.h5" m = re.match(regex, model_path) if m: now = datetime.datetime(int(m.group(1)), int(m.group(2)), int(m.group(3)), int(m.group(4)), int(m.group(5))) # Epoch number in file is 1-based, and in Keras code it's 0-based. # So, adjust for that then increment by one to start from the next epoch self.epoch = int(m.group(6)) - 1 + 1 print('Re-starting from epoch %d' % self.epoch) # Directory for training logs self.log_dir = os.path.join(self.model_dir, "{}{:%Y%m%dT%H%M}".format( self.config.NAME.lower(), now)) # Path to save after each epoch. Include placeholders that get filled by Keras. self.checkpoint_path = os.path.join(self.log_dir, "mask_rcnn_{}_*epoch*.h5".format( self.config.NAME.lower())) self.checkpoint_path = self.checkpoint_path.replace( "*epoch*", "{epoch:04d}") def train(self, train_dataset, val_dataset, learning_rate, epochs, layers, augmentation=None, custom_callbacks=None, no_augmentation_sources=None): """Train the model. train_dataset, val_dataset: Training and validation Dataset objects. learning_rate: The learning rate to train with epochs: Number of training epochs. Note that previous training epochs are considered to be done alreay, so this actually determines the epochs to train in total rather than in this particaular call. layers: Allows selecting wich layers to train. It can be: - A regular expression to match layer names to train - One of these predefined values: heads: The RPN, classifier and mask heads of the network all: All the layers 3+: Train Resnet stage 3 and up 4+: Train Resnet stage 4 and up 5+: Train Resnet stage 5 and up augmentation: Optional. An imgaug (https://github.com/aleju/imgaug) augmentation. For example, passing imgaug.augmenters.Fliplr(0.5) flips images right/left 50% of the time. You can pass complex augmentations as well. This augmentation applies 50% of the time, and when it does it flips images right/left half the time and adds a Gaussian blur with a random sigma in range 0 to 5. augmentation = imgaug.augmenters.Sometimes(0.5, [ imgaug.augmenters.Fliplr(0.5), imgaug.augmenters.GaussianBlur(sigma=(0.0, 5.0)) ]) custom_callbacks: Optional. Add custom callbacks to be called with the keras fit_generator method. Must be list of type keras.callbacks. no_augmentation_sources: Optional. List of sources to exclude for augmentation. A source is string that identifies a dataset and is defined in the Dataset class. """ assert self.mode == "training", "Create model in training mode." # Pre-defined layer regular expressions layer_regex = { # all layers but the backbone "heads": r"(mrcnn\_.*)|(rpn\_.*)|(fpn\_.*)", # From a specific Resnet stage and up "3+": r"(res3.*)|(bn3.*)|(res4.*)|(bn4.*)|(res5.*)|(bn5.*)|(mrcnn\_.*)|(rpn\_.*)|(fpn\_.*)", "4+": r"(res4.*)|(bn4.*)|(res5.*)|(bn5.*)|(mrcnn\_.*)|(rpn\_.*)|(fpn\_.*)", "5+": r"(res5.*)|(bn5.*)|(mrcnn\_.*)|(rpn\_.*)|(fpn\_.*)", # All layers "all": ".*", } if layers in layer_regex.keys(): layers = layer_regex[layers] # Data generators train_generator = data_generator(train_dataset, self.config, shuffle=True, augmentation=augmentation, batch_size=self.config.BATCH_SIZE, no_augmentation_sources=no_augmentation_sources) val_generator = data_generator(val_dataset, self.config, shuffle=True, batch_size=self.config.BATCH_SIZE) # Create log_dir if it does not exist if not os.path.exists(self.log_dir): os.makedirs(self.log_dir) # Callbacks callbacks = [ keras.callbacks.TensorBoard(log_dir=self.log_dir, histogram_freq=0, write_graph=True, write_images=False), keras.callbacks.ModelCheckpoint(self.checkpoint_path, verbose=0, save_weights_only=True), ] # Add custom callbacks to the list if custom_callbacks: callbacks += custom_callbacks # Train log("\nStarting at epoch {}. LR={}\n".format(self.epoch, learning_rate)) log("Checkpoint Path: {}".format(self.checkpoint_path)) self.set_trainable(layers) self.compile(learning_rate, self.config.LEARNING_MOMENTUM) # Work-around for Windows: Keras fails on Windows when using # multiprocessing workers. See discussion here: # https://github.com/matterport/Mask_RCNN/issues/13#issuecomment-353124009 if os.name is 'nt': workers = 0 else: workers = multiprocessing.cpu_count() self.keras_model.fit_generator( train_generator, initial_epoch=self.epoch, epochs=epochs, steps_per_epoch=self.config.STEPS_PER_EPOCH, callbacks=callbacks, validation_data=val_generator, validation_steps=self.config.VALIDATION_STEPS, max_queue_size=100, workers=workers, use_multiprocessing=True, ) self.epoch = max(self.epoch, epochs) def mold_inputs(self, images): """Takes a list of images and modifies them to the format expected as an input to the neural network. images: List of image matrices [height,width,depth]. Images can have different sizes. Returns 3 Numpy matrices: molded_images: [N, h, w, 3]. Images resized and normalized. image_metas: [N, length of meta data]. Details about each image. windows: [N, (y1, x1, y2, x2)]. The portion of the image that has the original image (padding excluded). """ molded_images = [] image_metas = [] windows = [] for image in images: # Resize image # TODO: move resizing to mold_image() molded_image, window, scale, padding, crop = utils.resize_image( image, min_dim=self.config.IMAGE_MIN_DIM, min_scale=self.config.IMAGE_MIN_SCALE, max_dim=self.config.IMAGE_MAX_DIM, mode=self.config.IMAGE_RESIZE_MODE) molded_image = mold_image(molded_image, self.config) # Build image_meta image_meta = compose_image_meta( 0, image.shape, molded_image.shape, window, scale, np.zeros([self.config.NUM_CLASSES], dtype=np.int32)) # Append molded_images.append(molded_image) windows.append(window) image_metas.append(image_meta) # Pack into arrays molded_images = np.stack(molded_images) image_metas = np.stack(image_metas) windows = np.stack(windows) return molded_images, image_metas, windows def unmold_detections(self, detections, mrcnn_mask, original_image_shape, image_shape, window): """Reformats the detections of one image from the format of the neural network output to a format suitable for use in the rest of the application. detections: [N, (y1, x1, y2, x2, class_id, score)] in normalized coordinates mrcnn_mask: [N, height, width, num_classes] original_image_shape: [H, W, C] Original image shape before resizing image_shape: [H, W, C] Shape of the image after resizing and padding window: [y1, x1, y2, x2] Pixel coordinates of box in the image where the real image is excluding the padding. Returns: boxes: [N, (y1, x1, y2, x2)] Bounding boxes in pixels class_ids: [N] Integer class IDs for each bounding box scores: [N] Float probability scores of the class_id masks: [height, width, num_instances] Instance masks """ # How many detections do we have? # Detections array is padded with zeros. Find the first class_id == 0. zero_ix = np.where(detections[:, 4] == 0)[0] N = zero_ix[0] if zero_ix.shape[0] > 0 else detections.shape[0] # Extract boxes, class_ids, scores, and class-specific masks boxes = detections[:N, :4] class_ids = detections[:N, 4].astype(np.int32) scores = detections[:N, 5] masks = mrcnn_mask[np.arange(N), :, :, class_ids] # Translate normalized coordinates in the resized image to pixel # coordinates in the original image before resizing window = utils.norm_boxes(window, image_shape[:2]) wy1, wx1, wy2, wx2 = window shift = np.array([wy1, wx1, wy1, wx1]) wh = wy2 - wy1 # window height ww = wx2 - wx1 # window width scale = np.array([wh, ww, wh, ww]) # Convert boxes to normalized coordinates on the window boxes = np.divide(boxes - shift, scale) # Convert boxes to pixel coordinates on the original image boxes = utils.denorm_boxes(boxes, original_image_shape[:2]) # Filter out detections with zero area. Happens in early training when # network weights are still random exclude_ix = np.where( (boxes[:, 2] - boxes[:, 0]) * (boxes[:, 3] - boxes[:, 1]) <= 0)[0] if exclude_ix.shape[0] > 0: boxes = np.delete(boxes, exclude_ix, axis=0) class_ids = np.delete(class_ids, exclude_ix, axis=0) scores = np.delete(scores, exclude_ix, axis=0) masks = np.delete(masks, exclude_ix, axis=0) N = class_ids.shape[0] # Resize masks to original image size and set boundary threshold. full_masks = [] for i in range(N): # Convert neural network mask to full size mask full_mask = utils.unmold_mask(masks[i], boxes[i], original_image_shape) full_masks.append(full_mask) full_masks = np.stack(full_masks, axis=-1)\ if full_masks else np.empty(original_image_shape[:2] + (0,)) return boxes, class_ids, scores, full_masks def detect(self, images, verbose=0): """Runs the detection pipeline. images: List of images, potentially of different sizes. Returns a list of dicts, one dict per image. The dict contains: rois: [N, (y1, x1, y2, x2)] detection bounding boxes class_ids: [N] int class IDs scores: [N] float probability scores for the class IDs masks: [H, W, N] instance binary masks """ assert self.mode == "inference", "Create model in inference mode." assert len( images) == self.config.BATCH_SIZE, "len(images) must be equal to BATCH_SIZE" if verbose: log("Processing {} images".format(len(images))) for image in images: log("image", image) # Mold inputs to format expected by the neural network molded_images, image_metas, windows = self.mold_inputs(images) # Validate image sizes # All images in a batch MUST be of the same size image_shape = molded_images[0].shape for g in molded_images[1:]: assert g.shape == image_shape,\ "After resizing, all images must have the same size. Check IMAGE_RESIZE_MODE and image sizes." # Anchors anchors = self.get_anchors(image_shape) # Duplicate across the batch dimension because Keras requires it # TODO: can this be optimized to avoid duplicating the anchors? anchors = np.broadcast_to(anchors, (self.config.BATCH_SIZE,) + anchors.shape) if verbose: log("molded_images", molded_images) log("image_metas", image_metas) log("anchors", anchors) # Run object detection detections, _, _, mrcnn_mask, _, _, _ =\ self.keras_model.predict([molded_images, image_metas, anchors], verbose=0) # Process detections results = [] for i, image in enumerate(images): final_rois, final_class_ids, final_scores, final_masks =\ self.unmold_detections(detections[i], mrcnn_mask[i], image.shape, molded_images[i].shape, windows[i]) results.append({ "rois": final_rois, "class_ids": final_class_ids, "scores": final_scores, "masks": final_masks, }) return results def detect_molded(self, molded_images, image_metas, verbose=0): """Runs the detection pipeline, but expect inputs that are molded already. Used mostly for debugging and inspecting the model. molded_images: List of images loaded using load_image_gt() image_metas: image meta data, also returned by load_image_gt() Returns a list of dicts, one dict per image. The dict contains: rois: [N, (y1, x1, y2, x2)] detection bounding boxes class_ids: [N] int class IDs scores: [N] float probability scores for the class IDs masks: [H, W, N] instance binary masks """ assert self.mode == "inference", "Create model in inference mode." assert len(molded_images) == self.config.BATCH_SIZE,\ "Number of images must be equal to BATCH_SIZE" if verbose: log("Processing {} images".format(len(molded_images))) for image in molded_images: log("image", image) # Validate image sizes # All images in a batch MUST be of the same size image_shape = molded_images[0].shape for g in molded_images[1:]: assert g.shape == image_shape, "Images must have the same size" # Anchors anchors = self.get_anchors(image_shape) # Duplicate across the batch dimension because Keras requires it # TODO: can this be optimized to avoid duplicating the anchors? anchors = np.broadcast_to(anchors, (self.config.BATCH_SIZE,) + anchors.shape) if verbose: log("molded_images", molded_images) log("image_metas", image_metas) log("anchors", anchors) # Run object detection detections, _, _, mrcnn_mask, _, _, _ =\ self.keras_model.predict([molded_images, image_metas, anchors], verbose=0) # Process detections results = [] for i, image in enumerate(molded_images): window = [0, 0, image.shape[0], image.shape[1]] final_rois, final_class_ids, final_scores, final_masks =\ self.unmold_detections(detections[i], mrcnn_mask[i], image.shape, molded_images[i].shape, window) results.append({ "rois": final_rois, "class_ids": final_class_ids, "scores": final_scores, "masks": final_masks, }) return results def get_anchors(self, image_shape): """Returns anchor pyramid for the given image size.""" backbone_shapes = compute_backbone_shapes(self.config, image_shape) # Cache anchors and reuse if image shape is the same if not hasattr(self, "_anchor_cache"): self._anchor_cache = {} if not tuple(image_shape) in self._anchor_cache: # Generate Anchors a = utils.generate_pyramid_anchors( self.config.RPN_ANCHOR_SCALES, self.config.RPN_ANCHOR_RATIOS, backbone_shapes, self.config.BACKBONE_STRIDES, self.config.RPN_ANCHOR_STRIDE) # Keep a copy of the latest anchors in pixel coordinates because # it's used in inspect_model notebooks. # TODO: Remove this after the notebook are refactored to not use it self.anchors = a # Normalize coordinates self._anchor_cache[tuple(image_shape)] = utils.norm_boxes(a, image_shape[:2]) return self._anchor_cache[tuple(image_shape)] def ancestor(self, tensor, name, checked=None): """Finds the ancestor of a TF tensor in the computation graph. tensor: TensorFlow symbolic tensor. name: Name of ancestor tensor to find checked: For internal use. A list of tensors that were already searched to avoid loops in traversing the graph. """ checked = checked if checked is not None else [] # Put a limit on how deep we go to avoid very long loops if len(checked) > 500: return None # Convert name to a regex and allow matching a number prefix # because Keras adds them automatically if isinstance(name, str): name = re.compile(name.replace("/", r"(\_\d+)*/")) parents = tensor.op.inputs for p in parents: if p in checked: continue if bool(re.fullmatch(name, p.name)): return p checked.append(p) a = self.ancestor(p, name, checked) if a is not None: return a return None def find_trainable_layer(self, layer): """If a layer is encapsulated by another layer, this function digs through the encapsulation and returns the layer that holds the weights. """ if layer.__class__.__name__ == 'TimeDistributed': return self.find_trainable_layer(layer.layer) return layer def get_trainable_layers(self): """Returns a list of layers that have weights.""" layers = [] # Loop through all layers for l in self.keras_model.layers: # If layer is a wrapper, find inner trainable layer l = self.find_trainable_layer(l) # Include layer if it has weights if l.get_weights(): layers.append(l) return layers def run_graph(self, images, outputs, image_metas=None): """Runs a sub-set of the computation graph that computes the given outputs. image_metas: If provided, the images are assumed to be already molded (i.e. resized, padded, and normalized) outputs: List of tuples (name, tensor) to compute. The tensors are symbolic TensorFlow tensors and the names are for easy tracking. Returns an ordered dict of results. Keys are the names received in the input and values are Numpy arrays. """ model = self.keras_model # Organize desired outputs into an ordered dict outputs = OrderedDict(outputs) for o in outputs.values(): assert o is not None # Build a Keras function to run parts of the computation graph inputs = model.inputs if model.uses_learning_phase and not isinstance(K.learning_phase(), int): inputs += [K.learning_phase()] kf = K.function(model.inputs, list(outputs.values())) # Prepare inputs if image_metas is None: molded_images, image_metas, _ = self.mold_inputs(images) else: molded_images = images image_shape = molded_images[0].shape # Anchors anchors = self.get_anchors(image_shape) # Duplicate across the batch dimension because Keras requires it # TODO: can this be optimized to avoid duplicating the anchors? anchors = np.broadcast_to(anchors, (self.config.BATCH_SIZE,) + anchors.shape) model_in = [molded_images, image_metas, anchors] # Run inference if model.uses_learning_phase and not isinstance(K.learning_phase(), int): model_in.append(0.) outputs_np = kf(model_in) # Pack the generated Numpy arrays into a a dict and log the results. outputs_np = OrderedDict([(k, v) for k, v in zip(outputs.keys(), outputs_np)]) for k, v in outputs_np.items(): log(k, v) return outputs_np ############################################################ # Data Formatting ############################################################ def compose_image_meta(image_id, original_image_shape, image_shape, window, scale, active_class_ids): """Takes attributes of an image and puts them in one 1D array. image_id: An int ID of the image. Useful for debugging. original_image_shape: [H, W, C] before resizing or padding. image_shape: [H, W, C] after resizing and padding window: (y1, x1, y2, x2) in pixels. The area of the image where the real image is (excluding the padding) scale: The scaling factor applied to the original image (float32) active_class_ids: List of class_ids available in the dataset from which the image came. Useful if training on images from multiple datasets where not all classes are present in all datasets. """ meta = np.array( [image_id] + # size=1 list(original_image_shape) + # size=3 list(image_shape) + # size=3 list(window) + # size=4 (y1, x1, y2, x2) in image cooredinates [scale] + # size=1 list(active_class_ids) # size=num_classes ) return meta def parse_image_meta(meta): """Parses an array that contains image attributes to its components. See compose_image_meta() for more details. meta: [batch, meta length] where meta length depends on NUM_CLASSES Returns a dict of the parsed values. """ image_id = meta[:, 0] original_image_shape = meta[:, 1:4] image_shape = meta[:, 4:7] window = meta[:, 7:11] # (y1, x1, y2, x2) window of image in in pixels scale = meta[:, 11] active_class_ids = meta[:, 12:] return { "image_id": image_id.astype(np.int32), "original_image_shape": original_image_shape.astype(np.int32), "image_shape": image_shape.astype(np.int32), "window": window.astype(np.int32), "scale": scale.astype(np.float32), "active_class_ids": active_class_ids.astype(np.int32), } def parse_image_meta_graph(meta): """Parses a tensor that contains image attributes to its components. See compose_image_meta() for more details. meta: [batch, meta length] where meta length depends on NUM_CLASSES Returns a dict of the parsed tensors. """ image_id = meta[:, 0] original_image_shape = meta[:, 1:4] image_shape = meta[:, 4:7] window = meta[:, 7:11] # (y1, x1, y2, x2) window of image in in pixels scale = meta[:, 11] active_class_ids = meta[:, 12:] return { "image_id": image_id, "original_image_shape": original_image_shape, "image_shape": image_shape, "window": window, "scale": scale, "active_class_ids": active_class_ids, } def mold_image(images, config): """Expects an RGB image (or array of images) and subtracts the mean pixel and converts it to float. Expects image colors in RGB order. """ return images.astype(np.float32) - config.MEAN_PIXEL def unmold_image(normalized_images, config): """Takes a image normalized with mold() and returns the original.""" return (normalized_images + config.MEAN_PIXEL).astype(np.uint8) ############################################################ # Miscellenous Graph Functions ############################################################ def trim_zeros_graph(boxes, name='trim_zeros'): """Often boxes are represented with matrices of shape [N, 4] and are padded with zeros. This removes zero boxes. boxes: [N, 4] matrix of boxes. non_zeros: [N] a 1D boolean mask identifying the rows to keep """ non_zeros = tf.cast(tf.reduce_sum(tf.abs(boxes), axis=1), tf.bool) boxes = tf.boolean_mask(boxes, non_zeros, name=name) return boxes, non_zeros def batch_pack_graph(x, counts, num_rows): """Picks different number of values from each row in x depending on the values in counts. """ outputs = [] for i in range(num_rows): outputs.append(x[i, :counts[i]]) return tf.concat(outputs, axis=0) def norm_boxes_graph(boxes, shape): """Converts boxes from pixel coordinates to normalized coordinates. boxes: [..., (y1, x1, y2, x2)] in pixel coordinates shape: [..., (height, width)] in pixels Note: In pixel coordinates (y2, x2) is outside the box. But in normalized coordinates it's inside the box. Returns: [..., (y1, x1, y2, x2)] in normalized coordinates """ h, w = tf.split(tf.cast(shape, tf.float32), 2) scale = tf.concat([h, w, h, w], axis=-1) - tf.constant(1.0) shift = tf.constant([0., 0., 1., 1.]) return tf.divide(boxes - shift, scale) def denorm_boxes_graph(boxes, shape): """Converts boxes from normalized coordinates to pixel coordinates. boxes: [..., (y1, x1, y2, x2)] in normalized coordinates shape: [..., (height, width)] in pixels Note: In pixel coordinates (y2, x2) is outside the box. But in normalized coordinates it's inside the box. Returns: [..., (y1, x1, y2, x2)] in pixel coordinates """ h, w = tf.split(tf.cast(shape, tf.float32), 2) scale = tf.concat([h, w, h, w], axis=-1) - tf.constant(1.0) shift = tf.constant([0., 0., 1., 1.]) return tf.cast(tf.round(tf.multiply(boxes, scale) + shift), tf.int32) ================================================ FILE: Image Processor/mrcnn/parallel_model.py ================================================ """ Mask R-CNN Multi-GPU Support for Keras. Copyright (c) 2017 Matterport, Inc. Licensed under the MIT License (see LICENSE for details) Written by Waleed Abdulla Ideas and a small code snippets from these sources: https://github.com/fchollet/keras/issues/2436 https://medium.com/@kuza55/transparent-multi-gpu-training-on-tensorflow-with-keras-8b0016fd9012 https://github.com/avolkov1/keras_experiments/blob/master/keras_exp/multigpu/ https://github.com/fchollet/keras/blob/master/keras/utils/training_utils.py """ import tensorflow as tf import keras.backend as K import keras.layers as KL import keras.models as KM class ParallelModel(KM.Model): """Subclasses the standard Keras Model and adds multi-GPU support. It works by creating a copy of the model on each GPU. Then it slices the inputs and sends a slice to each copy of the model, and then merges the outputs together and applies the loss on the combined outputs. """ def __init__(self, keras_model, gpu_count): """Class constructor. keras_model: The Keras model to parallelize gpu_count: Number of GPUs. Must be > 1 """ self.inner_model = keras_model self.gpu_count = gpu_count merged_outputs = self.make_parallel() super(ParallelModel, self).__init__(inputs=self.inner_model.inputs, outputs=merged_outputs) def __getattribute__(self, attrname): """Redirect loading and saving methods to the inner model. That's where the weights are stored.""" if 'load' in attrname or 'save' in attrname: return getattr(self.inner_model, attrname) return super(ParallelModel, self).__getattribute__(attrname) def summary(self, *args, **kwargs): """Override summary() to display summaries of both, the wrapper and inner models.""" super(ParallelModel, self).summary(*args, **kwargs) self.inner_model.summary(*args, **kwargs) def make_parallel(self): """Creates a new wrapper model that consists of multiple replicas of the original model placed on different GPUs. """ # Slice inputs. Slice inputs on the CPU to avoid sending a copy # of the full inputs to all GPUs. Saves on bandwidth and memory. input_slices = {name: tf.split(x, self.gpu_count) for name, x in zip(self.inner_model.input_names, self.inner_model.inputs)} output_names = self.inner_model.output_names outputs_all = [] for i in range(len(self.inner_model.outputs)): outputs_all.append([]) # Run the model call() on each GPU to place the ops there for i in range(self.gpu_count): with tf.device('/gpu:%d' % i): with tf.name_scope('tower_%d' % i): # Run a slice of inputs through this replica zipped_inputs = zip(self.inner_model.input_names, self.inner_model.inputs) inputs = [ KL.Lambda(lambda s: input_slices[name][i], output_shape=lambda s: (None,) + s[1:])(tensor) for name, tensor in zipped_inputs] # Create the model replica and get the outputs outputs = self.inner_model(inputs) if not isinstance(outputs, list): outputs = [outputs] # Save the outputs for merging back together later for l, o in enumerate(outputs): outputs_all[l].append(o) # Merge outputs on CPU with tf.device('/cpu:0'): merged = [] for outputs, name in zip(outputs_all, output_names): # Concatenate or average outputs? # Outputs usually have a batch dimension and we concatenate # across it. If they don't, then the output is likely a loss # or a metric value that gets averaged across the batch. # Keras expects losses and metrics to be scalars. if K.int_shape(outputs[0]) == (): # Average m = KL.Lambda(lambda o: tf.add_n(o) / len(outputs), name=name)(outputs) else: # Concatenate m = KL.Concatenate(axis=0, name=name)(outputs) merged.append(m) return merged if __name__ == "__main__": # Testing code below. It creates a simple model to train on MNIST and # tries to run it on 2 GPUs. It saves the graph so it can be viewed # in TensorBoard. Run it as: # # python3 parallel_model.py import os import numpy as np import keras.optimizers from keras.datasets import mnist from keras.preprocessing.image import ImageDataGenerator GPU_COUNT = 2 # Root directory of the project ROOT_DIR = os.path.abspath("../") # Directory to save logs and trained model MODEL_DIR = os.path.join(ROOT_DIR, "logs") def build_model(x_train, num_classes): # Reset default graph. Keras leaves old ops in the graph, # which are ignored for execution but clutter graph # visualization in TensorBoard. tf.reset_default_graph() inputs = KL.Input(shape=x_train.shape[1:], name="input_image") x = KL.Conv2D(32, (3, 3), activation='relu', padding="same", name="conv1")(inputs) x = KL.Conv2D(64, (3, 3), activation='relu', padding="same", name="conv2")(x) x = KL.MaxPooling2D(pool_size=(2, 2), name="pool1")(x) x = KL.Flatten(name="flat1")(x) x = KL.Dense(128, activation='relu', name="dense1")(x) x = KL.Dense(num_classes, activation='softmax', name="dense2")(x) return KM.Model(inputs, x, "digit_classifier_model") # Load MNIST Data (x_train, y_train), (x_test, y_test) = mnist.load_data() x_train = np.expand_dims(x_train, -1).astype('float32') / 255 x_test = np.expand_dims(x_test, -1).astype('float32') / 255 print('x_train shape:', x_train.shape) print('x_test shape:', x_test.shape) # Build data generator and model datagen = ImageDataGenerator() model = build_model(x_train, 10) # Add multi-GPU support. model = ParallelModel(model, GPU_COUNT) optimizer = keras.optimizers.SGD(lr=0.01, momentum=0.9, clipnorm=5.0) model.compile(loss='sparse_categorical_crossentropy', optimizer=optimizer, metrics=['accuracy']) model.summary() # Train model.fit_generator( datagen.flow(x_train, y_train, batch_size=64), steps_per_epoch=50, epochs=10, verbose=1, validation_data=(x_test, y_test), callbacks=[keras.callbacks.TensorBoard(log_dir=MODEL_DIR, write_graph=True)] ) ================================================ FILE: Image Processor/mrcnn/utils.py ================================================ """ Mask R-CNN Common utility functions and classes. Copyright (c) 2017 Matterport, Inc. Licensed under the MIT License (see LICENSE for details) Written by Waleed Abdulla """ import sys import os import logging import math import random import numpy as np import tensorflow as tf import scipy import skimage.color import skimage.io import skimage.transform import urllib.request import shutil import warnings from distutils.version import LooseVersion # URL from which to download the latest COCO trained weights COCO_MODEL_URL = "https://github.com/matterport/Mask_RCNN/releases/download/v2.0/mask_rcnn_coco.h5" ############################################################ # Bounding Boxes ############################################################ def extract_bboxes(mask): """Compute bounding boxes from masks. mask: [height, width, num_instances]. Mask pixels are either 1 or 0. Returns: bbox array [num_instances, (y1, x1, y2, x2)]. """ boxes = np.zeros([mask.shape[-1], 4], dtype=np.int32) for i in range(mask.shape[-1]): m = mask[:, :, i] # Bounding box. horizontal_indicies = np.where(np.any(m, axis=0))[0] vertical_indicies = np.where(np.any(m, axis=1))[0] if horizontal_indicies.shape[0]: x1, x2 = horizontal_indicies[[0, -1]] y1, y2 = vertical_indicies[[0, -1]] # x2 and y2 should not be part of the box. Increment by 1. x2 += 1 y2 += 1 else: # No mask for this instance. Might happen due to # resizing or cropping. Set bbox to zeros x1, x2, y1, y2 = 0, 0, 0, 0 boxes[i] = np.array([y1, x1, y2, x2]) return boxes.astype(np.int32) def compute_iou(box, boxes, box_area, boxes_area): """Calculates IoU of the given box with the array of the given boxes. box: 1D vector [y1, x1, y2, x2] boxes: [boxes_count, (y1, x1, y2, x2)] box_area: float. the area of 'box' boxes_area: array of length boxes_count. Note: the areas are passed in rather than calculated here for efficiency. Calculate once in the caller to avoid duplicate work. """ # Calculate intersection areas y1 = np.maximum(box[0], boxes[:, 0]) y2 = np.minimum(box[2], boxes[:, 2]) x1 = np.maximum(box[1], boxes[:, 1]) x2 = np.minimum(box[3], boxes[:, 3]) intersection = np.maximum(x2 - x1, 0) * np.maximum(y2 - y1, 0) union = box_area + boxes_area[:] - intersection[:] iou = intersection / union return iou def compute_overlaps(boxes1, boxes2): """Computes IoU overlaps between two sets of boxes. boxes1, boxes2: [N, (y1, x1, y2, x2)]. For better performance, pass the largest set first and the smaller second. """ # Areas of anchors and GT boxes area1 = (boxes1[:, 2] - boxes1[:, 0]) * (boxes1[:, 3] - boxes1[:, 1]) area2 = (boxes2[:, 2] - boxes2[:, 0]) * (boxes2[:, 3] - boxes2[:, 1]) # Compute overlaps to generate matrix [boxes1 count, boxes2 count] # Each cell contains the IoU value. overlaps = np.zeros((boxes1.shape[0], boxes2.shape[0])) for i in range(overlaps.shape[1]): box2 = boxes2[i] overlaps[:, i] = compute_iou(box2, boxes1, area2[i], area1) return overlaps def compute_overlaps_masks(masks1, masks2): """Computes IoU overlaps between two sets of masks. masks1, masks2: [Height, Width, instances] """ # If either set of masks is empty return empty result if masks1.shape[-1] == 0 or masks2.shape[-1] == 0: return np.zeros((masks1.shape[-1], masks2.shape[-1])) # flatten masks and compute their areas masks1 = np.reshape(masks1 > .5, (-1, masks1.shape[-1])).astype(np.float32) masks2 = np.reshape(masks2 > .5, (-1, masks2.shape[-1])).astype(np.float32) area1 = np.sum(masks1, axis=0) area2 = np.sum(masks2, axis=0) # intersections and union intersections = np.dot(masks1.T, masks2) union = area1[:, None] + area2[None, :] - intersections overlaps = intersections / union return overlaps def non_max_suppression(boxes, scores, threshold): """Performs non-maximum suppression and returns indices of kept boxes. boxes: [N, (y1, x1, y2, x2)]. Notice that (y2, x2) lays outside the box. scores: 1-D array of box scores. threshold: Float. IoU threshold to use for filtering. """ assert boxes.shape[0] > 0 if boxes.dtype.kind != "f": boxes = boxes.astype(np.float32) # Compute box areas y1 = boxes[:, 0] x1 = boxes[:, 1] y2 = boxes[:, 2] x2 = boxes[:, 3] area = (y2 - y1) * (x2 - x1) # Get indicies of boxes sorted by scores (highest first) ixs = scores.argsort()[::-1] pick = [] while len(ixs) > 0: # Pick top box and add its index to the list i = ixs[0] pick.append(i) # Compute IoU of the picked box with the rest iou = compute_iou(boxes[i], boxes[ixs[1:]], area[i], area[ixs[1:]]) # Identify boxes with IoU over the threshold. This # returns indices into ixs[1:], so add 1 to get # indices into ixs. remove_ixs = np.where(iou > threshold)[0] + 1 # Remove indices of the picked and overlapped boxes. ixs = np.delete(ixs, remove_ixs) ixs = np.delete(ixs, 0) return np.array(pick, dtype=np.int32) def apply_box_deltas(boxes, deltas): """Applies the given deltas to the given boxes. boxes: [N, (y1, x1, y2, x2)]. Note that (y2, x2) is outside the box. deltas: [N, (dy, dx, log(dh), log(dw))] """ boxes = boxes.astype(np.float32) # Convert to y, x, h, w height = boxes[:, 2] - boxes[:, 0] width = boxes[:, 3] - boxes[:, 1] center_y = boxes[:, 0] + 0.5 * height center_x = boxes[:, 1] + 0.5 * width # Apply deltas center_y += deltas[:, 0] * height center_x += deltas[:, 1] * width height *= np.exp(deltas[:, 2]) width *= np.exp(deltas[:, 3]) # Convert back to y1, x1, y2, x2 y1 = center_y - 0.5 * height x1 = center_x - 0.5 * width y2 = y1 + height x2 = x1 + width return np.stack([y1, x1, y2, x2], axis=1) def box_refinement_graph(box, gt_box): """Compute refinement needed to transform box to gt_box. box and gt_box are [N, (y1, x1, y2, x2)] """ box = tf.cast(box, tf.float32) gt_box = tf.cast(gt_box, tf.float32) height = box[:, 2] - box[:, 0] width = box[:, 3] - box[:, 1] center_y = box[:, 0] + 0.5 * height center_x = box[:, 1] + 0.5 * width gt_height = gt_box[:, 2] - gt_box[:, 0] gt_width = gt_box[:, 3] - gt_box[:, 1] gt_center_y = gt_box[:, 0] + 0.5 * gt_height gt_center_x = gt_box[:, 1] + 0.5 * gt_width dy = (gt_center_y - center_y) / height dx = (gt_center_x - center_x) / width dh = tf.log(gt_height / height) dw = tf.log(gt_width / width) result = tf.stack([dy, dx, dh, dw], axis=1) return result def box_refinement(box, gt_box): """Compute refinement needed to transform box to gt_box. box and gt_box are [N, (y1, x1, y2, x2)]. (y2, x2) is assumed to be outside the box. """ box = box.astype(np.float32) gt_box = gt_box.astype(np.float32) height = box[:, 2] - box[:, 0] width = box[:, 3] - box[:, 1] center_y = box[:, 0] + 0.5 * height center_x = box[:, 1] + 0.5 * width gt_height = gt_box[:, 2] - gt_box[:, 0] gt_width = gt_box[:, 3] - gt_box[:, 1] gt_center_y = gt_box[:, 0] + 0.5 * gt_height gt_center_x = gt_box[:, 1] + 0.5 * gt_width dy = (gt_center_y - center_y) / height dx = (gt_center_x - center_x) / width dh = np.log(gt_height / height) dw = np.log(gt_width / width) return np.stack([dy, dx, dh, dw], axis=1) ############################################################ # Dataset ############################################################ class Dataset(object): """The base class for dataset classes. To use it, create a new class that adds functions specific to the dataset you want to use. For example: class CatsAndDogsDataset(Dataset): def load_cats_and_dogs(self): ... def load_mask(self, image_id): ... def image_reference(self, image_id): ... See COCODataset and ShapesDataset as examples. """ def __init__(self, class_map=None): self._image_ids = [] self.image_info = [] # Background is always the first class self.class_info = [{"source": "", "id": 0, "name": "BG"}] self.source_class_ids = {} def add_class(self, source, class_id, class_name): assert "." not in source, "Source name cannot contain a dot" # Does the class exist already? for info in self.class_info: if info['source'] == source and info["id"] == class_id: # source.class_id combination already available, skip return # Add the class self.class_info.append({ "source": source, "id": class_id, "name": class_name, }) def add_image(self, source, image_id, path, **kwargs): image_info = { "id": image_id, "source": source, "path": path, } image_info.update(kwargs) self.image_info.append(image_info) def image_reference(self, image_id): """Return a link to the image in its source Website or details about the image that help looking it up or debugging it. Override for your dataset, but pass to this function if you encounter images not in your dataset. """ return "" def prepare(self, class_map=None): """Prepares the Dataset class for use. TODO: class map is not supported yet. When done, it should handle mapping classes from different datasets to the same class ID. """ def clean_name(name): """Returns a shorter version of object names for cleaner display.""" return ",".join(name.split(",")[:1]) # Build (or rebuild) everything else from the info dicts. self.num_classes = len(self.class_info) self.class_ids = np.arange(self.num_classes) self.class_names = [clean_name(c["name"]) for c in self.class_info] self.num_images = len(self.image_info) self._image_ids = np.arange(self.num_images) # Mapping from source class and image IDs to internal IDs self.class_from_source_map = {"{}.{}".format(info['source'], info['id']): id for info, id in zip(self.class_info, self.class_ids)} self.image_from_source_map = {"{}.{}".format(info['source'], info['id']): id for info, id in zip(self.image_info, self.image_ids)} # Map sources to class_ids they support self.sources = list(set([i['source'] for i in self.class_info])) self.source_class_ids = {} # Loop over datasets for source in self.sources: self.source_class_ids[source] = [] # Find classes that belong to this dataset for i, info in enumerate(self.class_info): # Include BG class in all datasets if i == 0 or source == info['source']: self.source_class_ids[source].append(i) def map_source_class_id(self, source_class_id): """Takes a source class ID and returns the int class ID assigned to it. For example: dataset.map_source_class_id("coco.12") -> 23 """ return self.class_from_source_map[source_class_id] def get_source_class_id(self, class_id, source): """Map an internal class ID to the corresponding class ID in the source dataset.""" info = self.class_info[class_id] assert info['source'] == source return info['id'] @property def image_ids(self): return self._image_ids def source_image_link(self, image_id): """Returns the path or URL to the image. Override this to return a URL to the image if it's available online for easy debugging. """ return self.image_info[image_id]["path"] def load_image(self, image_id): """Load the specified image and return a [H,W,3] Numpy array. """ # Load image image = skimage.io.imread(self.image_info[image_id]['path']) # If grayscale. Convert to RGB for consistency. if image.ndim != 3: image = skimage.color.gray2rgb(image) # If has an alpha channel, remove it for consistency if image.shape[-1] == 4: image = image[..., :3] return image def load_mask(self, image_id): """Load instance masks for the given image. Different datasets use different ways to store masks. Override this method to load instance masks and return them in the form of am array of binary masks of shape [height, width, instances]. Returns: masks: A bool array of shape [height, width, instance count] with a binary mask per instance. class_ids: a 1D array of class IDs of the instance masks. """ # Override this function to load a mask from your dataset. # Otherwise, it returns an empty mask. logging.warning("You are using the default load_mask(), maybe you need to define your own one.") mask = np.empty([0, 0, 0]) class_ids = np.empty([0], np.int32) return mask, class_ids def resize_image(image, min_dim=None, max_dim=None, min_scale=None, mode="square"): """Resizes an image keeping the aspect ratio unchanged. min_dim: if provided, resizes the image such that it's smaller dimension == min_dim max_dim: if provided, ensures that the image longest side doesn't exceed this value. min_scale: if provided, ensure that the image is scaled up by at least this percent even if min_dim doesn't require it. mode: Resizing mode. none: No resizing. Return the image unchanged. square: Resize and pad with zeros to get a square image of size [max_dim, max_dim]. pad64: Pads width and height with zeros to make them multiples of 64. If min_dim or min_scale are provided, it scales the image up before padding. max_dim is ignored in this mode. The multiple of 64 is needed to ensure smooth scaling of feature maps up and down the 6 levels of the FPN pyramid (2**6=64). crop: Picks random crops from the image. First, scales the image based on min_dim and min_scale, then picks a random crop of size min_dim x min_dim. Can be used in training only. max_dim is not used in this mode. Returns: image: the resized image window: (y1, x1, y2, x2). If max_dim is provided, padding might be inserted in the returned image. If so, this window is the coordinates of the image part of the full image (excluding the padding). The x2, y2 pixels are not included. scale: The scale factor used to resize the image padding: Padding added to the image [(top, bottom), (left, right), (0, 0)] """ # Keep track of image dtype and return results in the same dtype image_dtype = image.dtype # Default window (y1, x1, y2, x2) and default scale == 1. h, w = image.shape[:2] window = (0, 0, h, w) scale = 1 padding = [(0, 0), (0, 0), (0, 0)] crop = None if mode == "none": return image, window, scale, padding, crop # Scale? if min_dim: # Scale up but not down scale = max(1, min_dim / min(h, w)) if min_scale and scale < min_scale: scale = min_scale # Does it exceed max dim? if max_dim and mode == "square": image_max = max(h, w) if round(image_max * scale) > max_dim: scale = max_dim / image_max # Resize image using bilinear interpolation if scale != 1: image = resize(image, (round(h * scale), round(w * scale)), preserve_range=True) # Need padding or cropping? if mode == "square": # Get new height and width h, w = image.shape[:2] top_pad = (max_dim - h) // 2 bottom_pad = max_dim - h - top_pad left_pad = (max_dim - w) // 2 right_pad = max_dim - w - left_pad padding = [(top_pad, bottom_pad), (left_pad, right_pad), (0, 0)] image = np.pad(image, padding, mode='constant', constant_values=0) window = (top_pad, left_pad, h + top_pad, w + left_pad) elif mode == "pad64": h, w = image.shape[:2] # Both sides must be divisible by 64 assert min_dim % 64 == 0, "Minimum dimension must be a multiple of 64" # Height if h % 64 > 0: max_h = h - (h % 64) + 64 top_pad = (max_h - h) // 2 bottom_pad = max_h - h - top_pad else: top_pad = bottom_pad = 0 # Width if w % 64 > 0: max_w = w - (w % 64) + 64 left_pad = (max_w - w) // 2 right_pad = max_w - w - left_pad else: left_pad = right_pad = 0 padding = [(top_pad, bottom_pad), (left_pad, right_pad), (0, 0)] image = np.pad(image, padding, mode='constant', constant_values=0) window = (top_pad, left_pad, h + top_pad, w + left_pad) elif mode == "crop": # Pick a random crop h, w = image.shape[:2] y = random.randint(0, (h - min_dim)) x = random.randint(0, (w - min_dim)) crop = (y, x, min_dim, min_dim) image = image[y:y + min_dim, x:x + min_dim] window = (0, 0, min_dim, min_dim) else: raise Exception("Mode {} not supported".format(mode)) return image.astype(image_dtype), window, scale, padding, crop def resize_mask(mask, scale, padding, crop=None): """Resizes a mask using the given scale and padding. Typically, you get the scale and padding from resize_image() to ensure both, the image and the mask, are resized consistently. scale: mask scaling factor padding: Padding to add to the mask in the form [(top, bottom), (left, right), (0, 0)] """ # Suppress warning from scipy 0.13.0, the output shape of zoom() is # calculated with round() instead of int() with warnings.catch_warnings(): warnings.simplefilter("ignore") mask = scipy.ndimage.zoom(mask, zoom=[scale, scale, 1], order=0) if crop is not None: y, x, h, w = crop mask = mask[y:y + h, x:x + w] else: mask = np.pad(mask, padding, mode='constant', constant_values=0) return mask def minimize_mask(bbox, mask, mini_shape): """Resize masks to a smaller version to reduce memory load. Mini-masks can be resized back to image scale using expand_masks() See inspect_data.ipynb notebook for more details. """ mini_mask = np.zeros(mini_shape + (mask.shape[-1],), dtype=bool) for i in range(mask.shape[-1]): # Pick slice and cast to bool in case load_mask() returned wrong dtype m = mask[:, :, i].astype(bool) y1, x1, y2, x2 = bbox[i][:4] m = m[y1:y2, x1:x2] if m.size == 0: raise Exception("Invalid bounding box with area of zero") # Resize with bilinear interpolation m = resize(m, mini_shape) mini_mask[:, :, i] = np.around(m).astype(np.bool) return mini_mask def expand_mask(bbox, mini_mask, image_shape): """Resizes mini masks back to image size. Reverses the change of minimize_mask(). See inspect_data.ipynb notebook for more details. """ mask = np.zeros(image_shape[:2] + (mini_mask.shape[-1],), dtype=bool) for i in range(mask.shape[-1]): m = mini_mask[:, :, i] y1, x1, y2, x2 = bbox[i][:4] h = y2 - y1 w = x2 - x1 # Resize with bilinear interpolation m = resize(m, (h, w)) mask[y1:y2, x1:x2, i] = np.around(m).astype(np.bool) return mask # TODO: Build and use this function to reduce code duplication def mold_mask(mask, config): pass def unmold_mask(mask, bbox, image_shape): """Converts a mask generated by the neural network to a format similar to its original shape. mask: [height, width] of type float. A small, typically 28x28 mask. bbox: [y1, x1, y2, x2]. The box to fit the mask in. Returns a binary mask with the same size as the original image. """ threshold = 0.5 y1, x1, y2, x2 = bbox mask = resize(mask, (y2 - y1, x2 - x1)) mask = np.where(mask >= threshold, 1, 0).astype(np.bool) # Put the mask in the right location. full_mask = np.zeros(image_shape[:2], dtype=np.bool) full_mask[y1:y2, x1:x2] = mask return full_mask ############################################################ # Anchors ############################################################ def generate_anchors(scales, ratios, shape, feature_stride, anchor_stride): """ scales: 1D array of anchor sizes in pixels. Example: [32, 64, 128] ratios: 1D array of anchor ratios of width/height. Example: [0.5, 1, 2] shape: [height, width] spatial shape of the feature map over which to generate anchors. feature_stride: Stride of the feature map relative to the image in pixels. anchor_stride: Stride of anchors on the feature map. For example, if the value is 2 then generate anchors for every other feature map pixel. """ # Get all combinations of scales and ratios scales, ratios = np.meshgrid(np.array(scales), np.array(ratios)) scales = scales.flatten() ratios = ratios.flatten() # Enumerate heights and widths from scales and ratios heights = scales / np.sqrt(ratios) widths = scales * np.sqrt(ratios) # Enumerate shifts in feature space shifts_y = np.arange(0, shape[0], anchor_stride) * feature_stride shifts_x = np.arange(0, shape[1], anchor_stride) * feature_stride shifts_x, shifts_y = np.meshgrid(shifts_x, shifts_y) # Enumerate combinations of shifts, widths, and heights box_widths, box_centers_x = np.meshgrid(widths, shifts_x) box_heights, box_centers_y = np.meshgrid(heights, shifts_y) # Reshape to get a list of (y, x) and a list of (h, w) box_centers = np.stack( [box_centers_y, box_centers_x], axis=2).reshape([-1, 2]) box_sizes = np.stack([box_heights, box_widths], axis=2).reshape([-1, 2]) # Convert to corner coordinates (y1, x1, y2, x2) boxes = np.concatenate([box_centers - 0.5 * box_sizes, box_centers + 0.5 * box_sizes], axis=1) return boxes def generate_pyramid_anchors(scales, ratios, feature_shapes, feature_strides, anchor_stride): """Generate anchors at different levels of a feature pyramid. Each scale is associated with a level of the pyramid, but each ratio is used in all levels of the pyramid. Returns: anchors: [N, (y1, x1, y2, x2)]. All generated anchors in one array. Sorted with the same order of the given scales. So, anchors of scale[0] come first, then anchors of scale[1], and so on. """ # Anchors # [anchor_count, (y1, x1, y2, x2)] anchors = [] for i in range(len(scales)): anchors.append(generate_anchors(scales[i], ratios, feature_shapes[i], feature_strides[i], anchor_stride)) return np.concatenate(anchors, axis=0) ############################################################ # Miscellaneous ############################################################ def trim_zeros(x): """It's common to have tensors larger than the available data and pad with zeros. This function removes rows that are all zeros. x: [rows, columns]. """ assert len(x.shape) == 2 return x[~np.all(x == 0, axis=1)] def compute_matches(gt_boxes, gt_class_ids, gt_masks, pred_boxes, pred_class_ids, pred_scores, pred_masks, iou_threshold=0.5, score_threshold=0.0): """Finds matches between prediction and ground truth instances. Returns: gt_match: 1-D array. For each GT box it has the index of the matched predicted box. pred_match: 1-D array. For each predicted box, it has the index of the matched ground truth box. overlaps: [pred_boxes, gt_boxes] IoU overlaps. """ # Trim zero padding # TODO: cleaner to do zero unpadding upstream gt_boxes = trim_zeros(gt_boxes) gt_masks = gt_masks[..., :gt_boxes.shape[0]] pred_boxes = trim_zeros(pred_boxes) pred_scores = pred_scores[:pred_boxes.shape[0]] # Sort predictions by score from high to low indices = np.argsort(pred_scores)[::-1] pred_boxes = pred_boxes[indices] pred_class_ids = pred_class_ids[indices] pred_scores = pred_scores[indices] pred_masks = pred_masks[..., indices] # Compute IoU overlaps [pred_masks, gt_masks] overlaps = compute_overlaps_masks(pred_masks, gt_masks) # Loop through predictions and find matching ground truth boxes match_count = 0 pred_match = -1 * np.ones([pred_boxes.shape[0]]) gt_match = -1 * np.ones([gt_boxes.shape[0]]) for i in range(len(pred_boxes)): # Find best matching ground truth box # 1. Sort matches by score sorted_ixs = np.argsort(overlaps[i])[::-1] # 2. Remove low scores low_score_idx = np.where(overlaps[i, sorted_ixs] < score_threshold)[0] if low_score_idx.size > 0: sorted_ixs = sorted_ixs[:low_score_idx[0]] # 3. Find the match for j in sorted_ixs: # If ground truth box is already matched, go to next one if gt_match[j] > -1: continue # If we reach IoU smaller than the threshold, end the loop iou = overlaps[i, j] if iou < iou_threshold: break # Do we have a match? if pred_class_ids[i] == gt_class_ids[j]: match_count += 1 gt_match[j] = i pred_match[i] = j break return gt_match, pred_match, overlaps def compute_ap(gt_boxes, gt_class_ids, gt_masks, pred_boxes, pred_class_ids, pred_scores, pred_masks, iou_threshold=0.5): """Compute Average Precision at a set IoU threshold (default 0.5). Returns: mAP: Mean Average Precision precisions: List of precisions at different class score thresholds. recalls: List of recall values at different class score thresholds. overlaps: [pred_boxes, gt_boxes] IoU overlaps. """ # Get matches and overlaps gt_match, pred_match, overlaps = compute_matches( gt_boxes, gt_class_ids, gt_masks, pred_boxes, pred_class_ids, pred_scores, pred_masks, iou_threshold) # Compute precision and recall at each prediction box step precisions = np.cumsum(pred_match > -1) / (np.arange(len(pred_match)) + 1) recalls = np.cumsum(pred_match > -1).astype(np.float32) / len(gt_match) # Pad with start and end values to simplify the math precisions = np.concatenate([[0], precisions, [0]]) recalls = np.concatenate([[0], recalls, [1]]) # Ensure precision values decrease but don't increase. This way, the # precision value at each recall threshold is the maximum it can be # for all following recall thresholds, as specified by the VOC paper. for i in range(len(precisions) - 2, -1, -1): precisions[i] = np.maximum(precisions[i], precisions[i + 1]) # Compute mean AP over recall range indices = np.where(recalls[:-1] != recalls[1:])[0] + 1 mAP = np.sum((recalls[indices] - recalls[indices - 1]) * precisions[indices]) return mAP, precisions, recalls, overlaps def compute_ap_range(gt_box, gt_class_id, gt_mask, pred_box, pred_class_id, pred_score, pred_mask, iou_thresholds=None, verbose=1): """Compute AP over a range or IoU thresholds. Default range is 0.5-0.95.""" # Default is 0.5 to 0.95 with increments of 0.05 iou_thresholds = iou_thresholds or np.arange(0.5, 1.0, 0.05) # Compute AP over range of IoU thresholds AP = [] for iou_threshold in iou_thresholds: ap, precisions, recalls, overlaps =\ compute_ap(gt_box, gt_class_id, gt_mask, pred_box, pred_class_id, pred_score, pred_mask, iou_threshold=iou_threshold) if verbose: print("AP @{:.2f}:\t {:.3f}".format(iou_threshold, ap)) AP.append(ap) AP = np.array(AP).mean() if verbose: print("AP @{:.2f}-{:.2f}:\t {:.3f}".format( iou_thresholds[0], iou_thresholds[-1], AP)) return AP def compute_recall(pred_boxes, gt_boxes, iou): """Compute the recall at the given IoU threshold. It's an indication of how many GT boxes were found by the given prediction boxes. pred_boxes: [N, (y1, x1, y2, x2)] in image coordinates gt_boxes: [N, (y1, x1, y2, x2)] in image coordinates """ # Measure overlaps overlaps = compute_overlaps(pred_boxes, gt_boxes) iou_max = np.max(overlaps, axis=1) iou_argmax = np.argmax(overlaps, axis=1) positive_ids = np.where(iou_max >= iou)[0] matched_gt_boxes = iou_argmax[positive_ids] recall = len(set(matched_gt_boxes)) / gt_boxes.shape[0] return recall, positive_ids # ## Batch Slicing # Some custom layers support a batch size of 1 only, and require a lot of work # to support batches greater than 1. This function slices an input tensor # across the batch dimension and feeds batches of size 1. Effectively, # an easy way to support batches > 1 quickly with little code modification. # In the long run, it's more efficient to modify the code to support large # batches and getting rid of this function. Consider this a temporary solution def batch_slice(inputs, graph_fn, batch_size, names=None): """Splits inputs into slices and feeds each slice to a copy of the given computation graph and then combines the results. It allows you to run a graph on a batch of inputs even if the graph is written to support one instance only. inputs: list of tensors. All must have the same first dimension length graph_fn: A function that returns a TF tensor that's part of a graph. batch_size: number of slices to divide the data into. names: If provided, assigns names to the resulting tensors. """ if not isinstance(inputs, list): inputs = [inputs] outputs = [] for i in range(batch_size): inputs_slice = [x[i] for x in inputs] output_slice = graph_fn(*inputs_slice) if not isinstance(output_slice, (tuple, list)): output_slice = [output_slice] outputs.append(output_slice) # Change outputs from a list of slices where each is # a list of outputs to a list of outputs and each has # a list of slices outputs = list(zip(*outputs)) if names is None: names = [None] * len(outputs) result = [tf.stack(o, axis=0, name=n) for o, n in zip(outputs, names)] if len(result) == 1: result = result[0] return result def download_trained_weights(coco_model_path, verbose=1): """Download COCO trained weights from Releases. coco_model_path: local path of COCO trained weights """ if verbose > 0: print("Downloading pretrained model to " + coco_model_path + " ...") with urllib.request.urlopen(COCO_MODEL_URL) as resp, open(coco_model_path, 'wb') as out: shutil.copyfileobj(resp, out) if verbose > 0: print("... done downloading pretrained model!") def norm_boxes(boxes, shape): """Converts boxes from pixel coordinates to normalized coordinates. boxes: [N, (y1, x1, y2, x2)] in pixel coordinates shape: [..., (height, width)] in pixels Note: In pixel coordinates (y2, x2) is outside the box. But in normalized coordinates it's inside the box. Returns: [N, (y1, x1, y2, x2)] in normalized coordinates """ h, w = shape scale = np.array([h - 1, w - 1, h - 1, w - 1]) shift = np.array([0, 0, 1, 1]) return np.divide((boxes - shift), scale).astype(np.float32) def denorm_boxes(boxes, shape): """Converts boxes from normalized coordinates to pixel coordinates. boxes: [N, (y1, x1, y2, x2)] in normalized coordinates shape: [..., (height, width)] in pixels Note: In pixel coordinates (y2, x2) is outside the box. But in normalized coordinates it's inside the box. Returns: [N, (y1, x1, y2, x2)] in pixel coordinates """ h, w = shape scale = np.array([h - 1, w - 1, h - 1, w - 1]) shift = np.array([0, 0, 1, 1]) return np.around(np.multiply(boxes, scale) + shift).astype(np.int32) def resize(image, output_shape, order=1, mode='constant', cval=0, clip=True, preserve_range=False, anti_aliasing=False, anti_aliasing_sigma=None): """A wrapper for Scikit-Image resize(). Scikit-Image generates warnings on every call to resize() if it doesn't receive the right parameters. The right parameters depend on the version of skimage. This solves the problem by using different parameters per version. And it provides a central place to control resizing defaults. """ if LooseVersion(skimage.__version__) >= LooseVersion("0.14"): # New in 0.14: anti_aliasing. Default it to False for backward # compatibility with skimage 0.13. return skimage.transform.resize( image, output_shape, order=order, mode=mode, cval=cval, clip=clip, preserve_range=preserve_range, anti_aliasing=anti_aliasing, anti_aliasing_sigma=anti_aliasing_sigma) else: return skimage.transform.resize( image, output_shape, order=order, mode=mode, cval=cval, clip=clip, preserve_range=preserve_range) ================================================ FILE: Image Processor/mrcnn/visualize.py ================================================ """ Mask R-CNN Display and Visualization Functions. Copyright (c) 2017 Matterport, Inc. Licensed under the MIT License (see LICENSE for details) Written by Waleed Abdulla """ import os import sys import random import itertools import colorsys import numpy as np from skimage.measure import find_contours import matplotlib.pyplot as plt from matplotlib import patches, lines from matplotlib.patches import Polygon import IPython.display # Root directory of the project ROOT_DIR = os.path.abspath("../") # Import Mask RCNN sys.path.append(ROOT_DIR) # To find local version of the library from mrcnn import utils ############################################################ # Visualization ############################################################ def display_images(images, titles=None, cols=4, cmap=None, norm=None, interpolation=None): """Display the given set of images, optionally with titles. images: list or array of image tensors in HWC format. titles: optional. A list of titles to display with each image. cols: number of images per row cmap: Optional. Color map to use. For example, "Blues". norm: Optional. A Normalize instance to map values to colors. interpolation: Optional. Image interpolation to use for display. """ titles = titles if titles is not None else [""] * len(images) rows = len(images) // cols + 1 plt.figure(figsize=(14, 14 * rows // cols)) i = 1 for image, title in zip(images, titles): plt.subplot(rows, cols, i) plt.title(title, fontsize=9) plt.axis('off') plt.imshow(image.astype(np.uint8), cmap=cmap, norm=norm, interpolation=interpolation) i += 1 plt.show() def random_colors(N, bright=True): """ Generate random colors. To get visually distinct colors, generate them in HSV space then convert to RGB. """ brightness = 1.0 if bright else 0.7 hsv = [(i / N, 1, brightness) for i in range(N)] colors = list(map(lambda c: colorsys.hsv_to_rgb(*c), hsv)) random.shuffle(colors) return colors def apply_mask(image, mask, color, alpha=0.5): """Apply the given mask to the image. """ for c in range(3): image[:, :, c] = np.where(mask == 1, image[:, :, c] * (1 - alpha) + alpha * color[c] * 255, image[:, :, c]) return image def display_instances(image, boxes, masks, class_ids, class_names, scores=None, title="", figsize=(16, 16), ax=None, show_mask=True, show_bbox=True, colors=None, captions=None): """ boxes: [num_instance, (y1, x1, y2, x2, class_id)] in image coordinates. masks: [height, width, num_instances] class_ids: [num_instances] class_names: list of class names of the dataset scores: (optional) confidence scores for each box title: (optional) Figure title show_mask, show_bbox: To show masks and bounding boxes or not figsize: (optional) the size of the image colors: (optional) An array or colors to use with each object captions: (optional) A list of strings to use as captions for each object """ # Number of instances N = boxes.shape[0] if not N: print("\n*** No instances to display *** \n") else: assert boxes.shape[0] == masks.shape[-1] == class_ids.shape[0] # If no axis is passed, create one and automatically call show() auto_show = False if not ax: _, ax = plt.subplots(1, figsize=figsize) auto_show = True # Generate random colors colors = colors or random_colors(N) # Show area outside image boundaries. height, width = image.shape[:2] ax.set_ylim(height + 10, -10) ax.set_xlim(-10, width + 10) ax.axis('off') ax.set_title(title) masked_image = image.astype(np.uint32).copy() for i in range(N): color = colors[i] # Bounding box if not np.any(boxes[i]): # Skip this instance. Has no bbox. Likely lost in image cropping. continue y1, x1, y2, x2 = boxes[i] if show_bbox: p = patches.Rectangle((x1, y1), x2 - x1, y2 - y1, linewidth=2, alpha=0.7, linestyle="dashed", edgecolor=color, facecolor='none') ax.add_patch(p) # Label if not captions: class_id = class_ids[i] score = scores[i] if scores is not None else None label = class_names[class_id] caption = "{} {:.3f}".format(label, score) if score else label else: caption = captions[i] ax.text(x1, y1 + 8, caption, color='w', size=11, backgroundcolor="none") # Mask mask = masks[:, :, i] if show_mask: masked_image = apply_mask(masked_image, mask, color) # Mask Polygon # Pad to ensure proper polygons for masks that touch image edges. padded_mask = np.zeros( (mask.shape[0] + 2, mask.shape[1] + 2), dtype=np.uint8) padded_mask[1:-1, 1:-1] = mask contours = find_contours(padded_mask, 0.5) for verts in contours: # Subtract the padding and flip (y, x) to (x, y) verts = np.fliplr(verts) - 1 p = Polygon(verts, facecolor="none", edgecolor=color) ax.add_patch(p) ax.imshow(masked_image.astype(np.uint8)) if auto_show: plt.show() def display_differences(image, gt_box, gt_class_id, gt_mask, pred_box, pred_class_id, pred_score, pred_mask, class_names, title="", ax=None, show_mask=True, show_box=True, iou_threshold=0.5, score_threshold=0.5): """Display ground truth and prediction instances on the same image.""" # Match predictions to ground truth gt_match, pred_match, overlaps = utils.compute_matches( gt_box, gt_class_id, gt_mask, pred_box, pred_class_id, pred_score, pred_mask, iou_threshold=iou_threshold, score_threshold=score_threshold) # Ground truth = green. Predictions = red colors = [(0, 1, 0, .8)] * len(gt_match)\ + [(1, 0, 0, 1)] * len(pred_match) # Concatenate GT and predictions class_ids = np.concatenate([gt_class_id, pred_class_id]) scores = np.concatenate([np.zeros([len(gt_match)]), pred_score]) boxes = np.concatenate([gt_box, pred_box]) masks = np.concatenate([gt_mask, pred_mask], axis=-1) # Captions per instance show score/IoU captions = ["" for m in gt_match] + ["{:.2f} / {:.2f}".format( pred_score[i], (overlaps[i, int(pred_match[i])] if pred_match[i] > -1 else overlaps[i].max())) for i in range(len(pred_match))] # Set title if not provided title = title or "Ground Truth and Detections\n GT=green, pred=red, captions: score/IoU" # Display display_instances( image, boxes, masks, class_ids, class_names, scores, ax=ax, show_bbox=show_box, show_mask=show_mask, colors=colors, captions=captions, title=title) def draw_rois(image, rois, refined_rois, mask, class_ids, class_names, limit=10): """ anchors: [n, (y1, x1, y2, x2)] list of anchors in image coordinates. proposals: [n, 4] the same anchors but refined to fit objects better. """ masked_image = image.copy() # Pick random anchors in case there are too many. ids = np.arange(rois.shape[0], dtype=np.int32) ids = np.random.choice( ids, limit, replace=False) if ids.shape[0] > limit else ids fig, ax = plt.subplots(1, figsize=(12, 12)) if rois.shape[0] > limit: plt.title("Showing {} random ROIs out of {}".format( len(ids), rois.shape[0])) else: plt.title("{} ROIs".format(len(ids))) # Show area outside image boundaries. ax.set_ylim(image.shape[0] + 20, -20) ax.set_xlim(-50, image.shape[1] + 20) ax.axis('off') for i, id in enumerate(ids): color = np.random.rand(3) class_id = class_ids[id] # ROI y1, x1, y2, x2 = rois[id] p = patches.Rectangle((x1, y1), x2 - x1, y2 - y1, linewidth=2, edgecolor=color if class_id else "gray", facecolor='none', linestyle="dashed") ax.add_patch(p) # Refined ROI if class_id: ry1, rx1, ry2, rx2 = refined_rois[id] p = patches.Rectangle((rx1, ry1), rx2 - rx1, ry2 - ry1, linewidth=2, edgecolor=color, facecolor='none') ax.add_patch(p) # Connect the top-left corners of the anchor and proposal for easy visualization ax.add_line(lines.Line2D([x1, rx1], [y1, ry1], color=color)) # Label label = class_names[class_id] ax.text(rx1, ry1 + 8, "{}".format(label), color='w', size=11, backgroundcolor="none") # Mask m = utils.unmold_mask(mask[id], rois[id] [:4].astype(np.int32), image.shape) masked_image = apply_mask(masked_image, m, color) ax.imshow(masked_image) # Print stats print("Positive ROIs: ", class_ids[class_ids > 0].shape[0]) print("Negative ROIs: ", class_ids[class_ids == 0].shape[0]) print("Positive Ratio: {:.2f}".format( class_ids[class_ids > 0].shape[0] / class_ids.shape[0])) # TODO: Replace with matplotlib equivalent? def draw_box(image, box, color): """Draw 3-pixel width bounding boxes on the given image array. color: list of 3 int values for RGB. """ y1, x1, y2, x2 = box image[y1:y1 + 2, x1:x2] = color image[y2:y2 + 2, x1:x2] = color image[y1:y2, x1:x1 + 2] = color image[y1:y2, x2:x2 + 2] = color return image def display_top_masks(image, mask, class_ids, class_names, limit=4): """Display the given image and the top few class masks.""" to_display = [] titles = [] to_display.append(image) titles.append("H x W={}x{}".format(image.shape[0], image.shape[1])) # Pick top prominent classes in this image unique_class_ids = np.unique(class_ids) mask_area = [np.sum(mask[:, :, np.where(class_ids == i)[0]]) for i in unique_class_ids] top_ids = [v[0] for v in sorted(zip(unique_class_ids, mask_area), key=lambda r: r[1], reverse=True) if v[1] > 0] # Generate images and titles for i in range(limit): class_id = top_ids[i] if i < len(top_ids) else -1 # Pull masks of instances belonging to the same class. m = mask[:, :, np.where(class_ids == class_id)[0]] m = np.sum(m * np.arange(1, m.shape[-1] + 1), -1) to_display.append(m) titles.append(class_names[class_id] if class_id != -1 else "-") display_images(to_display, titles=titles, cols=limit + 1, cmap="Blues_r") def plot_precision_recall(AP, precisions, recalls): """Draw the precision-recall curve. AP: Average precision at IoU >= 0.5 precisions: list of precision values recalls: list of recall values """ # Plot the Precision-Recall curve _, ax = plt.subplots(1) ax.set_title("Precision-Recall Curve. AP@50 = {:.3f}".format(AP)) ax.set_ylim(0, 1.1) ax.set_xlim(0, 1.1) _ = ax.plot(recalls, precisions) def plot_overlaps(gt_class_ids, pred_class_ids, pred_scores, overlaps, class_names, threshold=0.5): """Draw a grid showing how ground truth objects are classified. gt_class_ids: [N] int. Ground truth class IDs pred_class_id: [N] int. Predicted class IDs pred_scores: [N] float. The probability scores of predicted classes overlaps: [pred_boxes, gt_boxes] IoU overlaps of predictions and GT boxes. class_names: list of all class names in the dataset threshold: Float. The prediction probability required to predict a class """ gt_class_ids = gt_class_ids[gt_class_ids != 0] pred_class_ids = pred_class_ids[pred_class_ids != 0] plt.figure(figsize=(12, 10)) plt.imshow(overlaps, interpolation='nearest', cmap=plt.cm.Blues) plt.yticks(np.arange(len(pred_class_ids)), ["{} ({:.2f})".format(class_names[int(id)], pred_scores[i]) for i, id in enumerate(pred_class_ids)]) plt.xticks(np.arange(len(gt_class_ids)), [class_names[int(id)] for id in gt_class_ids], rotation=90) thresh = overlaps.max() / 2. for i, j in itertools.product(range(overlaps.shape[0]), range(overlaps.shape[1])): text = "" if overlaps[i, j] > threshold: text = "match" if gt_class_ids[j] == pred_class_ids[i] else "wrong" color = ("white" if overlaps[i, j] > thresh else "black" if overlaps[i, j] > 0 else "grey") plt.text(j, i, "{:.3f}\n{}".format(overlaps[i, j], text), horizontalalignment="center", verticalalignment="center", fontsize=9, color=color) plt.tight_layout() plt.xlabel("Ground Truth") plt.ylabel("Predictions") def draw_boxes(image, boxes=None, refined_boxes=None, masks=None, captions=None, visibilities=None, title="", ax=None): """Draw bounding boxes and segmentation masks with different customizations. boxes: [N, (y1, x1, y2, x2, class_id)] in image coordinates. refined_boxes: Like boxes, but draw with solid lines to show that they're the result of refining 'boxes'. masks: [N, height, width] captions: List of N titles to display on each box visibilities: (optional) List of values of 0, 1, or 2. Determine how prominent each bounding box should be. title: An optional title to show over the image ax: (optional) Matplotlib axis to draw on. """ # Number of boxes assert boxes is not None or refined_boxes is not None N = boxes.shape[0] if boxes is not None else refined_boxes.shape[0] # Matplotlib Axis if not ax: _, ax = plt.subplots(1, figsize=(12, 12)) # Generate random colors colors = random_colors(N) # Show area outside image boundaries. margin = image.shape[0] // 10 ax.set_ylim(image.shape[0] + margin, -margin) ax.set_xlim(-margin, image.shape[1] + margin) ax.axis('off') ax.set_title(title) masked_image = image.astype(np.uint32).copy() for i in range(N): # Box visibility visibility = visibilities[i] if visibilities is not None else 1 if visibility == 0: color = "gray" style = "dotted" alpha = 0.5 elif visibility == 1: color = colors[i] style = "dotted" alpha = 1 elif visibility == 2: color = colors[i] style = "solid" alpha = 1 # Boxes if boxes is not None: if not np.any(boxes[i]): # Skip this instance. Has no bbox. Likely lost in cropping. continue y1, x1, y2, x2 = boxes[i] p = patches.Rectangle((x1, y1), x2 - x1, y2 - y1, linewidth=2, alpha=alpha, linestyle=style, edgecolor=color, facecolor='none') ax.add_patch(p) # Refined boxes if refined_boxes is not None and visibility > 0: ry1, rx1, ry2, rx2 = refined_boxes[i].astype(np.int32) p = patches.Rectangle((rx1, ry1), rx2 - rx1, ry2 - ry1, linewidth=2, edgecolor=color, facecolor='none') ax.add_patch(p) # Connect the top-left corners of the anchor and proposal if boxes is not None: ax.add_line(lines.Line2D([x1, rx1], [y1, ry1], color=color)) # Captions if captions is not None: caption = captions[i] # If there are refined boxes, display captions on them if refined_boxes is not None: y1, x1, y2, x2 = ry1, rx1, ry2, rx2 ax.text(x1, y1, caption, size=11, verticalalignment='top', color='w', backgroundcolor="none", bbox={'facecolor': color, 'alpha': 0.5, 'pad': 2, 'edgecolor': 'none'}) # Masks if masks is not None: mask = masks[:, :, i] masked_image = apply_mask(masked_image, mask, color) # Mask Polygon # Pad to ensure proper polygons for masks that touch image edges. padded_mask = np.zeros( (mask.shape[0] + 2, mask.shape[1] + 2), dtype=np.uint8) padded_mask[1:-1, 1:-1] = mask contours = find_contours(padded_mask, 0.5) for verts in contours: # Subtract the padding and flip (y, x) to (x, y) verts = np.fliplr(verts) - 1 p = Polygon(verts, facecolor="none", edgecolor=color) ax.add_patch(p) ax.imshow(masked_image.astype(np.uint8)) def display_table(table): """Display values in a table format. table: an iterable of rows, and each row is an iterable of values. """ html = "" for row in table: row_html = "" for col in row: row_html += "{:40}".format(str(col)) html += "" + row_html + "" html = "" + html + "
" IPython.display.display(IPython.display.HTML(html)) def display_weight_stats(model): """Scans all the weights in the model and returns a list of tuples that contain stats about each weight. """ layers = model.get_trainable_layers() table = [["WEIGHT NAME", "SHAPE", "MIN", "MAX", "STD"]] for l in layers: weight_values = l.get_weights() # list of Numpy arrays weight_tensors = l.weights # list of TF tensors for i, w in enumerate(weight_values): weight_name = weight_tensors[i].name # Detect problematic layers. Exclude biases of conv layers. alert = "" if w.min() == w.max() and not (l.__class__.__name__ == "Conv2D" and i == 1): alert += "*** dead?" if np.abs(w.min()) > 1000 or np.abs(w.max()) > 1000: alert += "*** Overflow?" # Add row table.append([ weight_name + alert, str(w.shape), "{:+9.4f}".format(w.min()), "{:+10.4f}".format(w.max()), "{:+9.4f}".format(w.std()), ]) display_table(table) ================================================ FILE: Image Processor/requirements.txt ================================================ numpy scipy Pillow cython matplotlib scikit-image tensorflow>=1.3.0 keras>=2.0.8 opencv-python h5py imgaug IPython[all] ================================================ FILE: Image Processor/scratch.py ================================================ import math import pickle from pathlib import Path from random import randint import json from multiprocessing import Pool, Queue import traceback import cv2 import numpy as np from keras.preprocessing.image import img_to_array, load_img from tqdm import tqdm import cv_tools from mrcnn import model as modellib from mrcnn import visualize from mrcnn.config import Config from mrcnn.config import Config from mrcnn import model as modellib from mrcnn import visualize import mrcnn from mrcnn import utils from mrcnn.utils import Dataset from mrcnn.model import MaskRCNN import numpy as np from numpy import zeros from numpy import asarray import colorsys import argparse import imutils import random import cv2 import os import time from matplotlib import pyplot from matplotlib.patches import Rectangle from keras.models import load_model from os import listdir from pathlib import Path import tarfile from xml.etree import ElementTree from download_utils import download_file_from_google_drive import os import random import cv2 import numpy as np import math import sys from collections import defaultdict from pathlib import Path from typing import List, Tuple import cv2 import numpy as np ================================================ FILE: Image Processor/setup.cfg ================================================ [metadata] description-file = README.md license-file = LICENSE requirements-file = requirements.txt ================================================ FILE: Image Processor/setup.py ================================================ """ The build/compilations setup >> pip install -r requirements.txt >> python setup.py install """ import pip import logging import pkg_resources try: from setuptools import setup except ImportError: from distutils.core import setup def _parse_requirements(file_path): pip_ver = pkg_resources.get_distribution('pip').version pip_version = list(map(int, pip_ver.split('.')[:2])) if pip_version >= [6, 0]: raw = pip.req.parse_requirements(file_path, session=pip.download.PipSession()) else: raw = pip.req.parse_requirements(file_path) return [str(i.req) for i in raw] # parse_requirements() returns generator of pip.req.InstallRequirement objects try: install_reqs = _parse_requirements("requirements.txt") except Exception: logging.warning('Fail load requirements file, so using default ones.') install_reqs = [] setup( name='mask-rcnn', version='2.1', url='https://github.com/matterport/Mask_RCNN', author='Matterport', author_email='waleed.abdulla@gmail.com', license='MIT', description='Mask R-CNN for object detection and instance segmentation', packages=["mrcnn"], install_requires=install_reqs, include_package_data=True, python_requires='>=3.4', long_description="""This is an implementation of Mask R-CNN on Python 3, Keras, and TensorFlow. The model generates bounding boxes and segmentation masks for each instance of an object in the image. It's based on Feature Pyramid Network (FPN) and a ResNet101 backbone.""", classifiers=[ "Development Status :: 5 - Production/Stable", "Environment :: Console", "Intended Audience :: Developers", "Intended Audience :: Information Technology", "Intended Audience :: Education", "Intended Audience :: Science/Research", "License :: OSI Approved :: MIT License", "Natural Language :: English", "Operating System :: OS Independent", "Topic :: Scientific/Engineering :: Artificial Intelligence", "Topic :: Scientific/Engineering :: Image Recognition", "Topic :: Scientific/Engineering :: Visualization", "Topic :: Scientific/Engineering :: Image Segmentation", 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', ], keywords="image instance segmentation object detection mask rcnn r-cnn tensorflow keras", ) ================================================ FILE: README.md ================================================ # TDPDNE A StyleGAN2 model to make AI generated dicks #### Website [https://thisdickpicdoesnotexist.com/](https://thisdickpicdoesnotexist.com/) #### Make your own dicks [Google Colab](https://colab.research.google.com/drive/1DoCxr2pYlxCRv6RmITtFWahVXsbTexYp?usp=sharing) #### Inspiration * [https://thispersondoesnotexist.com/](https://thispersondoesnotexist.com/) * Too many women asking for my dick pics, now I can send these instead * StyleGAN2 Paper: [https://arxiv.org/pdf/1912.04958.pdf](https://arxiv.org/pdf/1912.04958.pdf) * StyleGAN2 Repo: [https://github.com/NVlabs/stylegan2](https://github.com/NVlabs/stylegan2) ## Model Details 42,273 dick pics were scraped from Reddit that were posted on these subreddits * r/penis * r/cock * r/dicks * r/averagepenis * r/MassiveCock * r/tinydick The scraping procedure was done by first [downloading all submissions](https://files.pushshift.io/reddit/submissions/) from the year 2018. These submissions were then filtered down to image submissions in the above subreddits. Since pushshift only stores the image URLs, these images were then fetched from reddit using the stored URL. A model was created with these images, but the model suffered from mode collapse. The solution was to train a custom Mask-RCNN model (in `Image Processor/Dick_Pic_Mask-RCNN_Trainer.ipynb`) to segment the penis. With this segmentation, PCA was used to find the tilt, then rotate so the penis was vertical (in `Image Processor/align_images.py`). However this results in some penises being upside down. A possible improvement could be training another Mask R-CNN to detect the head of the penis and make sure that is always at the top half of the image. The training was done using a TPU v3-8 trained for ~9 days (25,000 KImg). Gamma was started at 100 and decreased by 25 each 10,000 KImg. The resulting model still suffers from some mode collapse as the generated dicks seen on [https://thisdickpicdoesnotexist.com/](https://thisdickpicdoesnotexist.com/) are lacking of the African American variety. This was found to be surprising as there were many coloured dicks in the dataset. The generated dicks on [https://thisdickpicdoesnotexist.com/](https://thisdickpicdoesnotexist.com/) used a truncation_psi of 0.7. [Email me](mailto:hello@thisdickpicdoesnotexist.com) if you have any questions. ## How to use ### Download the dataset 1. [Here](https://mega.nz/file/f91lBAzA#1wvrbxh89bJ8MAUiGjHwIZnZ97P8vzflQJaBL_ALpeM) 2. Unzip the tarball and place in the root directory of the repo 2. Tell all your friends you have more dick pics on your computer than them ### Run The Image Preprocessor 1. Train the custom Mask R-CNN model using `Image Processor/Dick_Pic_Mask-RCNN_Trainer.ipynb` 2. Align the dataset and resize using `Image Processor/align_images.py` ### Get a Google Compute Platform TPU instance 1. Apply for [TFRC](https://www.tensorflow.org/tfrc) if you haven't already 2. Start the instance 3. Install python 3.7 4. Set the right environment variables export NOISY=0 export DEBUG=0 export LABEL_SIZE=0 export MODEL_DIR=gs://your-gcp-bucket/model export BATCH_PER=4 export BATCH_SIZE=32 export RESOLUTION=512 ### Train the Dick-GAN 1. Convert the images to TFRecords using `stylegan2-tpu/dataset_tool.py create_from_images ~/datasets/aligned_images_tfrecords_dir ~/aligned_images` 2. Train the model `stylegan2-tpu/run_training.py --result-dir=gs://your-gcp-bucket/model --data-dir=dataset --dataset=aligned_images_tfrecords_dir --config=config-f --num-gpus=8 --mirror-augment=true` ### Generate Dicks 1. Run `stylegan2-tpu/generate_images_tpu.py --model_dir=gs://your-gcp-bucket/model --save_dir=generated_fakes --truncation_psi=0.7 --num_samples=10` ================================================ FILE: stylegan2-tpu/Dockerfile ================================================ # Copyright (c) 2019, NVIDIA Corporation. All rights reserved. # # This work is made available under the Nvidia Source Code License-NC. # To view a copy of this license, visit # https://nvlabs.github.io/stylegan2/license.html FROM tensorflow/tensorflow:1.15.0-gpu-py3 RUN pip install scipy==1.3.3 RUN pip install requests==2.22.0 RUN pip install Pillow==6.2.1 ================================================ FILE: stylegan2-tpu/LICENSE.txt ================================================ Copyright (c) 2019, NVIDIA Corporation. All rights reserved. Nvidia Source Code License-NC ======================================================================= 1. Definitions "Licensor" means any person or entity that distributes its Work. "Software" means the original work of authorship made available under this License. "Work" means the Software and any additions to or derivative works of the Software that are made available under this License. "Nvidia Processors" means any central processing unit (CPU), graphics processing unit (GPU), field-programmable gate array (FPGA), application-specific integrated circuit (ASIC) or any combination thereof designed, made, sold, or provided by Nvidia or its affiliates. The terms "reproduce," "reproduction," "derivative works," and "distribution" have the meaning as provided under U.S. copyright law; provided, however, that for the purposes of this License, derivative works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work. Works, including the Software, are "made available" under this License by including in or with the Work either (a) a copyright notice referencing the applicability of this License to the Work, or (b) a copy of this License. 2. License Grants 2.1 Copyright Grant. Subject to the terms and conditions of this License, each Licensor grants to you a perpetual, worldwide, non-exclusive, royalty-free, copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense and distribute its Work and any resulting derivative works in any form. 3. Limitations 3.1 Redistribution. You may reproduce or distribute the Work only if (a) you do so under this License, (b) you include a complete copy of this License with your distribution, and (c) you retain without modification any copyright, patent, trademark, or attribution notices that are present in the Work. 3.2 Derivative Works. You may specify that additional or different terms apply to the use, reproduction, and distribution of your derivative works of the Work ("Your Terms") only if (a) Your Terms provide that the use limitation in Section 3.3 applies to your derivative works, and (b) you identify the specific derivative works that are subject to Your Terms. Notwithstanding Your Terms, this License (including the redistribution requirements in Section 3.1) will continue to apply to the Work itself. 3.3 Use Limitation. The Work and any derivative works thereof only may be used or intended for use non-commercially. The Work or derivative works thereof may be used or intended for use by Nvidia or its affiliates commercially or non-commercially. As used herein, "non-commercially" means for research or evaluation purposes only. 3.4 Patent Claims. If you bring or threaten to bring a patent claim against any Licensor (including any claim, cross-claim or counterclaim in a lawsuit) to enforce any patents that you allege are infringed by any Work, then your rights under this License from such Licensor (including the grants in Sections 2.1 and 2.2) will terminate immediately. 3.5 Trademarks. This License does not grant any rights to use any Licensor's or its affiliates' names, logos, or trademarks, except as necessary to reproduce the notices described in this License. 3.6 Termination. If you violate any term of this License, then your rights under this License (including the grants in Sections 2.1 and 2.2) will terminate immediately. 4. Disclaimer of Warranty. THE WORK IS PROVIDED "AS IS" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WARRANTIES OR CONDITIONS OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE OR NON-INFRINGEMENT. YOU BEAR THE RISK OF UNDERTAKING ANY ACTIVITIES UNDER THIS LICENSE. 5. Limitation of Liability. EXCEPT AS PROHIBITED BY APPLICABLE LAW, IN NO EVENT AND UNDER NO LEGAL THEORY, WHETHER IN TORT (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE SHALL ANY LICENSOR BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR RELATED TO THIS LICENSE, THE USE OR INABILITY TO USE THE WORK (INCLUDING BUT NOT LIMITED TO LOSS OF GOODWILL, BUSINESS INTERRUPTION, LOST PROFITS OR DATA, COMPUTER FAILURE OR MALFUNCTION, OR ANY OTHER COMMERCIAL DAMAGES OR LOSSES), EVEN IF THE LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. ======================================================================= ================================================ FILE: stylegan2-tpu/README.md ================================================ ## StyleGAN2 — Official TensorFlow Implementation ![Teaser image](./docs/stylegan2-teaser-1024x256.png) **Analyzing and Improving the Image Quality of StyleGAN**
Tero Karras, Samuli Laine, Miika Aittala, Janne Hellsten, Jaakko Lehtinen, Timo Aila
Paper: http://arxiv.org/abs/1912.04958
Video: https://youtu.be/c-NJtV9Jvp0
Abstract: *The style-based GAN architecture (StyleGAN) yields state-of-the-art results in data-driven unconditional generative image modeling. We expose and analyze several of its characteristic artifacts, and propose changes in both model architecture and training methods to address them. In particular, we redesign generator normalization, revisit progressive growing, and regularize the generator to encourage good conditioning in the mapping from latent vectors to images. In addition to improving image quality, this path length regularizer yields the additional benefit that the generator becomes significantly easier to invert. This makes it possible to reliably detect if an image is generated by a particular network. We furthermore visualize how well the generator utilizes its output resolution, and identify a capacity problem, motivating us to train larger models for additional quality improvements. Overall, our improved model redefines the state of the art in unconditional image modeling, both in terms of existing distribution quality metrics as well as perceived image quality.* For business inquiries, please contact [researchinquiries@nvidia.com](mailto:researchinquiries@nvidia.com)
For press and other inquiries, please contact Hector Marinez at [hmarinez@nvidia.com](mailto:hmarinez@nvidia.com)
| Additional material |   | :--- | :---------- | [StyleGAN2](https://drive.google.com/open?id=1QHc-yF5C3DChRwSdZKcx1w6K8JvSxQi7) | Main Google Drive folder | ├  [stylegan2-paper.pdf](https://drive.google.com/open?id=1fnF-QsiQeKaxF-HbvFiGtzHF_Bf3CzJu) | High-quality version of the paper | ├  [stylegan2-video.mp4](https://drive.google.com/open?id=1f_gbKW6FUUHKkUxciJ_lQx29mCq_fSBy) | High-quality version of the video | ├  [images](https://drive.google.com/open?id=1Sak157_DLX84ytqHHqZaH_59HoEWzfB7) | Example images produced using our method | │  ├  [curated-images](https://drive.google.com/open?id=1ydWb8xCHzDKMTW9kQ7sL-B1R0zATHVHp) | Hand-picked images showcasing our results | │  └  [100k-generated-images](https://drive.google.com/open?id=1BA2OZ1GshdfFZGYZPob5QWOGBuJCdu5q) | Random images with and without truncation | ├  [videos](https://drive.google.com/open?id=1yXDV96SFXoUiZKU7AyE6DyKgDpIk4wUZ) | Individual clips of the video as high-quality MP4 | └  [networks](https://drive.google.com/open?id=1yanUI9m4b4PWzR0eurKNq6JR1Bbfbh6L) | Pre-trained networks |    ├  [stylegan2-ffhq-config-f.pkl](https://drive.google.com/open?id=1Mgh-jglZjgksupF0XLl0KzuOqd1LXcoE) | StyleGAN2 for FFHQ dataset at 1024×1024 |    ├  [stylegan2-car-config-f.pkl](https://drive.google.com/open?id=1MutzVf8XjNo6TUg03a6CUU_2Vlc0ltbV) | StyleGAN2 for LSUN Car dataset at 512×384 |    ├  [stylegan2-cat-config-f.pkl](https://drive.google.com/open?id=1MyowTZGvMDJCWuT7Yg2e_GnTLIzcSPCy) | StyleGAN2 for LSUN Cat dataset at 256×256 |    ├  [stylegan2-church-config-f.pkl](https://drive.google.com/open?id=1N3iaujGpwa6vmKCqRSHcD6GZ2HVV8h1f) | StyleGAN2 for LSUN Church dataset at 256×256 |    ├  [stylegan2-horse-config-f.pkl](https://drive.google.com/open?id=1N55ZtBhEyEbDn6uKBjCNAew1phD5ZAh-) | StyleGAN2 for LSUN Horse dataset at 256×256 |    └ ⋯ | Other training configurations used in the paper ## Requirements * Both Linux and Windows are supported. Linux is recommended for performance and compatibility reasons. * 64-bit Python 3.6 installation. We recommend Anaconda3 with numpy 1.14.3 or newer. * TensorFlow 1.14 or 1.15 with GPU support. The code does not support TensorFlow 2.0. * On Windows, you need to use TensorFlow 1.14 — TensorFlow 1.15 will not work. * One or more high-end NVIDIA GPUs, NVIDIA drivers, CUDA 10.0 toolkit and cuDNN 7.5. To reproduce the results reported in the paper, you need an NVIDIA GPU with at least 16 GB of DRAM. * Docker users: use the [provided Dockerfile](./Dockerfile) to build an image with the required library dependencies. StyleGAN2 relies on custom TensorFlow ops that are compiled on the fly using [NVCC](https://docs.nvidia.com/cuda/cuda-compiler-driver-nvcc/index.html). To test that your NVCC installation is working correctly, run: ```.bash nvcc test_nvcc.cu -o test_nvcc -run | CPU says hello. | GPU says hello. ``` On Windows, the compilation requires Microsoft Visual Studio to be in `PATH`. We recommend installing [Visual Studio Community Edition](https://visualstudio.microsoft.com/vs/) and adding into `PATH` using `"C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat"`. ## Preparing datasets Datasets are stored as multi-resolution TFRecords, similar to the [original StyleGAN](https://github.com/NVlabs/stylegan). Each dataset consists of multiple `*.tfrecords` files stored under a common directory, e.g., `~/datasets/ffhq/ffhq-r*.tfrecords`. In the following sections, the datasets are referenced using a combination of `--dataset` and `--data-dir` arguments, e.g., `--dataset=ffhq --data-dir=~/datasets`. **FFHQ**. To download the [Flickr-Faces-HQ](https://github.com/NVlabs/ffhq-dataset) dataset as multi-resolution TFRecords, run: ```.bash pushd ~ git clone https://github.com/NVlabs/ffhq-dataset.git cd ffhq-dataset python download_ffhq.py --tfrecords popd python dataset_tool.py display ~/ffhq-dataset/tfrecords/ffhq ``` **LSUN**. Download the desired LSUN categories in LMDB format from the [LSUN project page](https://www.yf.io/p/lsun). To convert the data to multi-resolution TFRecords, run: ```.bash python dataset_tool.py create_lsun_wide ~/datasets/car ~/lsun/car_lmdb --width=512 --height=384 python dataset_tool.py create_lsun ~/datasets/cat ~/lsun/cat_lmdb --resolution=256 python dataset_tool.py create_lsun ~/datasets/church ~/lsun/church_outdoor_train_lmdb --resolution=256 python dataset_tool.py create_lsun ~/datasets/horse ~/lsun/horse_lmdb --resolution=256 ``` **Custom**. Create custom datasets by placing all training images under a single directory. The images must be square-shaped and they must all have the same power-of-two dimensions. To convert the images to multi-resolution TFRecords, run: ```.bash python dataset_tool.py create_from_images ~/datasets/my-custom-dataset ~/my-custom-images python dataset_tool.py display ~/datasets/my-custom-dataset ``` ## Using pre-trained networks Pre-trained networks are stored as `*.pkl` files on the [StyleGAN2 Google Drive folder](https://drive.google.com/open?id=1QHc-yF5C3DChRwSdZKcx1w6K8JvSxQi7). Below, you can either reference them directly using the syntax `gdrive:networks/.pkl`, or download them manually and reference by filename. **Generating images**: ```.bash # Generate uncurated ffhq images (matches paper Figure 12) python run_generator.py generate-images --network=gdrive:networks/stylegan2-ffhq-config-f.pkl \ --seeds=6600-6625 --truncation-psi=0.5 # Generate curated ffhq images (matches paper Figure 11) python run_generator.py generate-images --network=gdrive:networks/stylegan2-ffhq-config-f.pkl \ --seeds=66,230,389,1518 --truncation-psi=1.0 # Generate uncurated car images python run_generator.py generate-images --network=gdrive:networks/stylegan2-car-config-f.pkl \ --seeds=6000-6025 --truncation-psi=0.5 # Example of style mixing (matches the corresponding video clip) python run_generator.py style-mixing-example --network=gdrive:networks/stylegan2-ffhq-config-f.pkl \ --row-seeds=85,100,75,458,1500 --col-seeds=55,821,1789,293 --truncation-psi=1.0 ``` The results are placed in `results//*.png`. You can change the location with `--result-dir`. For example, `--result-dir=~/my-stylegan2-results`. **Projecting images to latent space**: ```.bash # Project generated images python run_projector.py project-generated-images --network=gdrive:networks/stylegan2-car-config-f.pkl \ --seeds=0,1,5 # Project real images python run_projector.py project-real-images --network=gdrive:networks/stylegan2-car-config-f.pkl \ --dataset=car --data-dir=~/datasets ``` You can import the networks in your own Python code using `pickle.load()`. For this to work, you need to include the `dnnlib` source directory in `PYTHONPATH` and create a default TensorFlow session by calling `dnnlib.tflib.init_tf()`. See [run_generator.py](./run_generator.py) and [pretrained_networks.py](./pretrained_networks.py) for examples. ## Training networks To reproduce the training runs for config F in Tables 1 and 3, run: ```.bash python run_training.py --num-gpus=8 --data-dir=~/datasets --config=config-f \ --dataset=ffhq --mirror-augment=true python run_training.py --num-gpus=8 --data-dir=~/datasets --config=config-f \ --dataset=car --total-kimg=57000 python run_training.py --num-gpus=8 --data-dir=~/datasets --config=config-f \ --dataset=cat --total-kimg=88000 python run_training.py --num-gpus=8 --data-dir=~/datasets --config=config-f \ --dataset=church --total-kimg 88000 --gamma=100 python run_training.py --num-gpus=8 --data-dir=~/datasets --config=config-f \ --dataset=horse --total-kimg 100000 --gamma=100 ``` For other configurations, see `python run_training.py --help`. We have verified that the results match the paper when training with 1, 2, 4, or 8 GPUs. Note that training FFHQ at 1024×1024 resolution requires GPU(s) with at least 16 GB of memory. The following table lists typical training times using NVIDIA DGX-1 with 8 Tesla V100 GPUs: | Configuration | Resolution | Total kimg | 1 GPU | 2 GPUs | 4 GPUs | 8 GPUs | GPU mem | | :------------ | :-------------: | :--------: | :-----: | :-----: | :-----: | :----: | :-----: | | `config-f` | 1024×1024 | 25000 | 69d 23h | 36d 4h | 18d 14h | 9d 18h | 13.3 GB | | `config-f` | 1024×1024 | 10000 | 27d 23h | 14d 11h | 7d 10h | 3d 22h | 13.3 GB | | `config-e` | 1024×1024 | 25000 | 35d 11h | 18d 15h | 9d 15h | 5d 6h | 8.6 GB | | `config-e` | 1024×1024 | 10000 | 14d 4h | 7d 11h | 3d 20h | 2d 3h | 8.6 GB | | `config-f` | 256×256 | 25000 | 32d 13h | 16d 23h | 8d 21h | 4d 18h | 6.4 GB | | `config-f` | 256×256 | 10000 | 13d 0h | 6d 19h | 3d 13h | 1d 22h | 6.4 GB | Training curves for FFHQ config F (StyleGAN2) compared to original StyleGAN using 8 GPUs: ![Training curves](./docs/stylegan2-training-curves.png) After training, the resulting networks can be used the same way as the official pre-trained networks: ```.bash # Generate 1000 random images without truncation python run_generator.py generate-images --seeds=0-999 --truncation-psi=1.0 \ --network=results/00006-stylegan2-ffhq-8gpu-config-f/networks-final.pkl ``` ## Evaluation metrics To reproduce the numbers for config F in Tables 1 and 3, run: ```.bash python run_metrics.py --data-dir=~/datasets --network=gdrive:networks/stylegan2-ffhq-config-f.pkl \ --metrics=fid50k,ppl_wend --dataset=ffhq --mirror-augment=true python run_metrics.py --data-dir=~/datasets --network=gdrive:networks/stylegan2-car-config-f.pkl \ --metrics=fid50k,ppl2_wend --dataset=car python run_metrics.py --data-dir=~/datasets --network=gdrive:networks/stylegan2-cat-config-f.pkl \ --metrics=fid50k,ppl2_wend --dataset=cat python run_metrics.py --data-dir=~/datasets --network=gdrive:networks/stylegan2-church-config-f.pkl \ --metrics=fid50k,ppl2_wend --dataset=church python run_metrics.py --data-dir=~/datasets --network=gdrive:networks/stylegan2-horse-config-f.pkl \ --metrics=fid50k,ppl2_wend --dataset=horse ``` For other configurations, see the [StyleGAN2 Google Drive folder](https://drive.google.com/open?id=1QHc-yF5C3DChRwSdZKcx1w6K8JvSxQi7). Note that the metrics are evaluated using a different random seed each time, so the results will vary between runs. In the paper, we reported the average result of running each metric 10 times. The following table lists the available metrics along with their expected runtimes and random variation: | Metric | FFHQ config F | 1 GPU | 2 GPUs | 4 GPUs | Description | | :---------- | :------------: | :----: | :-----: | :----: | :---------- | | `fid50k` | 2.84 ± 0.03 | 22 min | 14 min | 10 min | [Fréchet Inception Distance](https://arxiv.org/abs/1706.08500) | `is50k` | 5.13 ± 0.02 | 23 min | 14 min | 8 min | [Inception Score](https://arxiv.org/abs/1606.03498) | `ppl_zfull` | 348.0 ± 3.8 | 41 min | 22 min | 14 min | [Perceptual Path Length](https://arxiv.org/abs/1812.04948) in Z, full paths | `ppl_wfull` | 126.9 ± 0.2 | 42 min | 22 min | 13 min | [Perceptual Path Length](https://arxiv.org/abs/1812.04948) in W, full paths | `ppl_zend` | 348.6 ± 3.0 | 41 min | 22 min | 14 min | [Perceptual Path Length](https://arxiv.org/abs/1812.04948) in Z, path endpoints | `ppl_wend` | 129.4 ± 0.8 | 40 min | 23 min | 13 min | [Perceptual Path Length](https://arxiv.org/abs/1812.04948) in W, path endpoints | `ppl2_wend` | 145.0 ± 0.5 | 41 min | 23 min | 14 min | [Perceptual Path Length](https://arxiv.org/abs/1812.04948) without center crop | `ls` | 154.2 / 4.27 | 10 hrs | 6 hrs | 4 hrs | [Linear Separability](https://arxiv.org/abs/1812.04948) | `pr50k3` | 0.689 / 0.492 | 26 min | 17 min | 12 min | [Precision and Recall](https://arxiv.org/abs/1904.06991) Note that some of the metrics cache dataset-specific data on the disk, and they will take somewhat longer when run for the first time. ## License Copyright © 2019, NVIDIA Corporation. All rights reserved. This work is made available under the Nvidia Source Code License-NC. To view a copy of this license, visit https://nvlabs.github.io/stylegan2/license.html ## Citation ``` @article{Karras2019stylegan2, title = {Analyzing and Improving the Image Quality of {StyleGAN}}, author = {Tero Karras and Samuli Laine and Miika Aittala and Janne Hellsten and Jaakko Lehtinen and Timo Aila}, journal = {CoRR}, volume = {abs/1912.04958}, year = {2019}, } ``` ## Acknowledgements We thank Ming-Yu Liu for an early review, Timo Viitanen for his help with code release, and Tero Kuosmanen for compute infrastructure. ================================================ FILE: stylegan2-tpu/align_mammos.py ================================================ import argparse, os import numpy as np from PIL import Image from tqdm import tqdm parser = argparse.ArgumentParser() parser.add_argument('-i', '--input', type=str, required=True, help="Input directory of images to resize.") parser.add_argument('-o', '--output', type=str, required=True, help="Output destination to store resized images.") args = parser.parse_args() # Artistic crop: In-frame, centered mammogram. def flipImage(image): def isLeftEdgeBlank(image): return image[:, -1].sum(axis=0) > image[:, 0].sum(axis=0) return image if isLeftEdgeBlank(np.asarray(image)).all() else image.transpose(Image.FLIP_LEFT_RIGHT) directory = args.input target_directory = args.output # This is a waste of memory and compute, # but it's nice to have an idea on the progress of the script. filescount = 0 for dirPath, subdirList, fileList in os.walk(directory): filescount += len(list(filter(lambda x: x.endswith(".jpeg"), fileList))) with tqdm(total=filescount) as pbar: for subdir, dirs, files in os.walk(directory): for file in files: filepath = subdir + os.sep + file if filepath.endswith(".jpeg"): if "._" in filepath: continue im = Image.open(filepath).convert('RGB') img = flipImage(im) img.save(target_directory + '/' + file) pbar.update(1) ================================================ FILE: stylegan2-tpu/convert_ckpt_to_pkl.py ================================================ # ~~~ aydao ~~~~ 2020 ~~~ # # Convert a StyleGAN2 network stored in ckpt files to a .pkl # import argparse import pickle import numpy as np import warnings warnings.filterwarnings('ignore', category=FutureWarning) warnings.filterwarnings('ignore', category=DeprecationWarning) import tensorflow as tf tf.compat.v1.logging.set_verbosity(tf.compat.v1.logging.ERROR) import dnnlib import dnnlib.tflib as tflib from training import misc def main(): parser = argparse.ArgumentParser( description='Creates a pkl from a ckpt of a StyleGAN2 model using a reference pkl of a network of the same size.', formatter_class=argparse.RawDescriptionHelpFormatter ) parser.add_argument('--ckpt_model_dir', help='The directory with the ckpt files', required=True) parser.add_argument('--reference_pkl', help='A reference pkl of a StyleGAN2, must have the exact same variables as ckpt (will not be overwritten)', required=True) parser.add_argument('--prefix', default='') args = parser.parse_args() model_dir = args.ckpt_model_dir name = args.reference_pkl tflib.init_tf() G, D, Gs = pickle.load(open(name, "rb")) G.print_layers(); D.print_layers(); Gs.print_layers() var_list = [v for v in tf.global_variables()] saver = tf.train.Saver( var_list=var_list, ) ckpt = tf.train.latest_checkpoint(model_dir) sess = tf.get_default_session() saver.restore(sess, ckpt) out_pkl_iteration = ckpt.split('ckpt-')[-1] out_pkl = './'+args.prefix+'model.ckpt-'+out_pkl_iteration+'.pkl' print('Saving %s' % out_pkl) misc.save_pkl((G, D, Gs), out_pkl) if __name__ == '__main__': main() ================================================ FILE: stylegan2-tpu/convert_pkl_to_ckpt.py ================================================ # ~~~ aydao ~~~~ 2020 ~~~ # # Convert a StyleGAN2 network stored in a .pkl file to ckpt files # # Warning: it worked for my use case, not fully checked # import argparse import pickle import numpy as np import warnings warnings.filterwarnings('ignore', category=FutureWarning) warnings.filterwarnings('ignore', category=DeprecationWarning) import tensorflow as tf tf.compat.v1.logging.set_verbosity(tf.compat.v1.logging.ERROR) import dnnlib import dnnlib.tflib as tflib from training import misc def main(): parser = argparse.ArgumentParser( description='Creates a ckpt from a pkl of a StyleGAN2 model.', formatter_class=argparse.RawDescriptionHelpFormatter ) parser.add_argument('--ckpt_model_dir', help='The directory with the ckpt files', required=True) parser.add_argument('--input_pkl', help='A StyleGAN2 pkl', required=True) parser.add_argument('--prefix', default='') args = parser.parse_args() model_dir = args.ckpt_model_dir input_pkl = args.input_pkl prefix = args.prefix tflib.init_tf() with tf.Session() as sess: G, D, Gs = pickle.load(open(input_pkl, "rb")) G.print_layers(); D.print_layers(); Gs.print_layers() var_list = [v for v in tf.global_variables() if 'Dataset/' not in v.name] saver = tf.train.Saver( var_list=var_list, ) saver.save(sess, model_dir+'/'+prefix+'model.ckpt') if __name__ == '__main__': main() ================================================ FILE: stylegan2-tpu/dataset_tool.py ================================================ # Copyright (c) 2019, NVIDIA Corporation. All rights reserved. # # This work is made available under the Nvidia Source Code License-NC. # To view a copy of this license, visit # https://nvlabs.github.io/stylegan2/license.html """Tool for creating multi-resolution TFRecords datasets.""" # pylint: disable=too-many-lines import os import sys import glob import argparse import threading import six.moves.queue as Queue # pylint: disable=import-error import traceback import numpy as np import tensorflow as tf import PIL.Image import dnnlib.tflib as tflib from tqdm import tqdm from training import dataset #---------------------------------------------------------------------------- def error(msg): print('Error: ' + msg) exit(1) #---------------------------------------------------------------------------- class TFRecordExporter: def __init__(self, tfrecord_dir, expected_images, print_progress=True, progress_interval=10): self.tfrecord_dir = tfrecord_dir self.tfr_prefix = os.path.join(self.tfrecord_dir, os.path.basename(self.tfrecord_dir)) self.expected_images = expected_images self.cur_images = 0 self.shape = None self.resolution_log2 = None self.tfr_writers = [] self.print_progress = print_progress self.progress_interval = progress_interval if self.print_progress: print('Creating dataset "%s"' % tfrecord_dir) if not os.path.isdir(self.tfrecord_dir): os.makedirs(self.tfrecord_dir) assert os.path.isdir(self.tfrecord_dir) def close(self): if self.print_progress: print('%-40s\r' % 'Flushing data...', end='', flush=True) for tfr_writer in self.tfr_writers: tfr_writer.close() self.tfr_writers = [] if self.print_progress: print('%-40s\r' % '', end='', flush=True) print('Added %d images.' % self.cur_images) def choose_shuffled_order(self): # Note: Images and labels must be added in shuffled order. order = np.arange(self.expected_images) np.random.RandomState(123).shuffle(order) return order def add_image(self, img): if self.shape is None: self.shape = img.shape self.resolution_log2 = int(np.log2(self.shape[1])) assert self.shape[0] in [1, 3] assert self.shape[1] == self.shape[2] assert self.shape[1] == 2**self.resolution_log2 tfr_opt = tf.python_io.TFRecordOptions(tf.python_io.TFRecordCompressionType.NONE) for lod in range(self.resolution_log2 - 1): tfr_file = self.tfr_prefix + '-r%02d.tfrecords' % (self.resolution_log2 - lod) self.tfr_writers.append(tf.python_io.TFRecordWriter(tfr_file, tfr_opt)) assert img.shape == self.shape for lod, tfr_writer in enumerate(self.tfr_writers): if lod: img = img.astype(np.float32) img = (img[:, 0::2, 0::2] + img[:, 0::2, 1::2] + img[:, 1::2, 0::2] + img[:, 1::2, 1::2]) * 0.25 quant = np.rint(img).clip(0, 255).astype(np.uint8) ex = tf.train.Example(features=tf.train.Features(feature={ 'shape': tf.train.Feature(int64_list=tf.train.Int64List(value=quant.shape)), 'data': tf.train.Feature(bytes_list=tf.train.BytesList(value=[quant.tostring()]))})) tfr_writer.write(ex.SerializeToString()) self.cur_images += 1 def add_labels(self, labels): if self.print_progress: print('%-40s\r' % 'Saving labels...', end='', flush=True) assert labels.shape[0] == self.cur_images with open(self.tfr_prefix + '-rxx.labels', 'wb') as f: np.save(f, labels.astype(np.float32)) def __enter__(self): return self def __exit__(self, *args): self.close() #---------------------------------------------------------------------------- class ExceptionInfo(object): def __init__(self): self.value = sys.exc_info()[1] self.traceback = traceback.format_exc() #---------------------------------------------------------------------------- class WorkerThread(threading.Thread): def __init__(self, task_queue): threading.Thread.__init__(self) self.task_queue = task_queue def run(self): while True: func, args, result_queue = self.task_queue.get() if func is None: break try: result = func(*args) except: result = ExceptionInfo() result_queue.put((result, args)) #---------------------------------------------------------------------------- class ThreadPool(object): def __init__(self, num_threads): assert num_threads >= 1 self.task_queue = Queue.Queue() self.result_queues = dict() self.num_threads = num_threads for _idx in range(self.num_threads): thread = WorkerThread(self.task_queue) thread.daemon = True thread.start() def add_task(self, func, args=()): assert hasattr(func, '__call__') # must be a function if func not in self.result_queues: self.result_queues[func] = Queue.Queue() self.task_queue.put((func, args, self.result_queues[func])) def get_result(self, func): # returns (result, args) result, args = self.result_queues[func].get() if isinstance(result, ExceptionInfo): print('\n\nWorker thread caught an exception:\n' + result.traceback) raise result.value return result, args def finish(self): for _idx in range(self.num_threads): self.task_queue.put((None, (), None)) def __enter__(self): # for 'with' statement return self def __exit__(self, *excinfo): self.finish() def process_items_concurrently(self, item_iterator, process_func=lambda x: x, pre_func=lambda x: x, post_func=lambda x: x, max_items_in_flight=None): if max_items_in_flight is None: max_items_in_flight = self.num_threads * 4 assert max_items_in_flight >= 1 results = [] retire_idx = [0] def task_func(prepared, _idx): return process_func(prepared) def retire_result(): processed, (_prepared, idx) = self.get_result(task_func) results[idx] = processed while retire_idx[0] < len(results) and results[retire_idx[0]] is not None: yield post_func(results[retire_idx[0]]) results[retire_idx[0]] = None retire_idx[0] += 1 for idx, item in enumerate(item_iterator): prepared = pre_func(item) results.append(None) self.add_task(func=task_func, args=(prepared, idx)) while retire_idx[0] < idx - max_items_in_flight + 2: for res in retire_result(): yield res while retire_idx[0] < len(results): for res in retire_result(): yield res #---------------------------------------------------------------------------- def display(tfrecord_dir): print('Loading dataset "%s"' % tfrecord_dir) tflib.init_tf({'gpu_options.allow_growth': True}) dset = dataset.TFRecordDataset(tfrecord_dir, max_label_size='full', repeat=False, shuffle_mb=0) tflib.init_uninitialized_vars() import cv2 # pip install opencv-python idx = 0 while True: try: images, labels = dset.get_minibatch_np(1) except tf.errors.OutOfRangeError: break if idx == 0: print('Displaying images') cv2.namedWindow('dataset_tool') print('Press SPACE or ENTER to advance, ESC to exit') print('\nidx = %-8d\nlabel = %s' % (idx, labels[0].tolist())) cv2.imshow('dataset_tool', images[0].transpose(1, 2, 0)[:, :, ::-1]) # CHW => HWC, RGB => BGR idx += 1 if cv2.waitKey() == 27: break print('\nDisplayed %d images.' % idx) #---------------------------------------------------------------------------- def extract(tfrecord_dir, output_dir): print('Loading dataset "%s"' % tfrecord_dir) tflib.init_tf({'gpu_options.allow_growth': True}) dset = dataset.TFRecordDataset(tfrecord_dir, max_label_size=0, repeat=False, shuffle_mb=0) tflib.init_uninitialized_vars() print('Extracting images to "%s"' % output_dir) if not os.path.isdir(output_dir): os.makedirs(output_dir) idx = 0 while True: if idx % 10 == 0: print('%d\r' % idx, end='', flush=True) try: images, _labels = dset.get_minibatch_np(1) except tf.errors.OutOfRangeError: break if images.shape[1] == 1: img = PIL.Image.fromarray(images[0][0], 'L') else: img = PIL.Image.fromarray(images[0].transpose(1, 2, 0), 'RGB') img.save(os.path.join(output_dir, 'img%08d.png' % idx)) idx += 1 print('Extracted %d images.' % idx) #---------------------------------------------------------------------------- def compare(tfrecord_dir_a, tfrecord_dir_b, ignore_labels): max_label_size = 0 if ignore_labels else 'full' print('Loading dataset "%s"' % tfrecord_dir_a) tflib.init_tf({'gpu_options.allow_growth': True}) dset_a = dataset.TFRecordDataset(tfrecord_dir_a, max_label_size=max_label_size, repeat=False, shuffle_mb=0) print('Loading dataset "%s"' % tfrecord_dir_b) dset_b = dataset.TFRecordDataset(tfrecord_dir_b, max_label_size=max_label_size, repeat=False, shuffle_mb=0) tflib.init_uninitialized_vars() print('Comparing datasets') idx = 0 identical_images = 0 identical_labels = 0 while True: if idx % 100 == 0: print('%d\r' % idx, end='', flush=True) try: images_a, labels_a = dset_a.get_minibatch_np(1) except tf.errors.OutOfRangeError: images_a, labels_a = None, None try: images_b, labels_b = dset_b.get_minibatch_np(1) except tf.errors.OutOfRangeError: images_b, labels_b = None, None if images_a is None or images_b is None: if images_a is not None or images_b is not None: print('Datasets contain different number of images') break if images_a.shape == images_b.shape and np.all(images_a == images_b): identical_images += 1 else: print('Image %d is different' % idx) if labels_a.shape == labels_b.shape and np.all(labels_a == labels_b): identical_labels += 1 else: print('Label %d is different' % idx) idx += 1 print('Identical images: %d / %d' % (identical_images, idx)) if not ignore_labels: print('Identical labels: %d / %d' % (identical_labels, idx)) #---------------------------------------------------------------------------- def create_mnist(tfrecord_dir, mnist_dir): print('Loading MNIST from "%s"' % mnist_dir) import gzip with gzip.open(os.path.join(mnist_dir, 'train-images-idx3-ubyte.gz'), 'rb') as file: images = np.frombuffer(file.read(), np.uint8, offset=16) with gzip.open(os.path.join(mnist_dir, 'train-labels-idx1-ubyte.gz'), 'rb') as file: labels = np.frombuffer(file.read(), np.uint8, offset=8) images = images.reshape(-1, 1, 28, 28) images = np.pad(images, [(0,0), (0,0), (2,2), (2,2)], 'constant', constant_values=0) assert images.shape == (60000, 1, 32, 32) and images.dtype == np.uint8 assert labels.shape == (60000,) and labels.dtype == np.uint8 assert np.min(images) == 0 and np.max(images) == 255 assert np.min(labels) == 0 and np.max(labels) == 9 onehot = np.zeros((labels.size, np.max(labels) + 1), dtype=np.float32) onehot[np.arange(labels.size), labels] = 1.0 with TFRecordExporter(tfrecord_dir, images.shape[0]) as tfr: order = tfr.choose_shuffled_order() for idx in range(order.size): tfr.add_image(images[order[idx]]) tfr.add_labels(onehot[order]) #---------------------------------------------------------------------------- def create_mnistrgb(tfrecord_dir, mnist_dir, num_images=1000000, random_seed=123): print('Loading MNIST from "%s"' % mnist_dir) import gzip with gzip.open(os.path.join(mnist_dir, 'train-images-idx3-ubyte.gz'), 'rb') as file: images = np.frombuffer(file.read(), np.uint8, offset=16) images = images.reshape(-1, 28, 28) images = np.pad(images, [(0,0), (2,2), (2,2)], 'constant', constant_values=0) assert images.shape == (60000, 32, 32) and images.dtype == np.uint8 assert np.min(images) == 0 and np.max(images) == 255 with TFRecordExporter(tfrecord_dir, num_images) as tfr: rnd = np.random.RandomState(random_seed) for _idx in range(num_images): tfr.add_image(images[rnd.randint(images.shape[0], size=3)]) #---------------------------------------------------------------------------- def create_cifar10(tfrecord_dir, cifar10_dir): print('Loading CIFAR-10 from "%s"' % cifar10_dir) import pickle images = [] labels = [] for batch in range(1, 6): with open(os.path.join(cifar10_dir, 'data_batch_%d' % batch), 'rb') as file: data = pickle.load(file, encoding='latin1') images.append(data['data'].reshape(-1, 3, 32, 32)) labels.append(data['labels']) images = np.concatenate(images) labels = np.concatenate(labels) assert images.shape == (50000, 3, 32, 32) and images.dtype == np.uint8 assert labels.shape == (50000,) and labels.dtype == np.int32 assert np.min(images) == 0 and np.max(images) == 255 assert np.min(labels) == 0 and np.max(labels) == 9 onehot = np.zeros((labels.size, np.max(labels) + 1), dtype=np.float32) onehot[np.arange(labels.size), labels] = 1.0 with TFRecordExporter(tfrecord_dir, images.shape[0]) as tfr: order = tfr.choose_shuffled_order() for idx in range(order.size): tfr.add_image(images[order[idx]]) tfr.add_labels(onehot[order]) #---------------------------------------------------------------------------- def create_cifar100(tfrecord_dir, cifar100_dir): print('Loading CIFAR-100 from "%s"' % cifar100_dir) import pickle with open(os.path.join(cifar100_dir, 'train'), 'rb') as file: data = pickle.load(file, encoding='latin1') images = data['data'].reshape(-1, 3, 32, 32) labels = np.array(data['fine_labels']) assert images.shape == (50000, 3, 32, 32) and images.dtype == np.uint8 assert labels.shape == (50000,) and labels.dtype == np.int32 assert np.min(images) == 0 and np.max(images) == 255 assert np.min(labels) == 0 and np.max(labels) == 99 onehot = np.zeros((labels.size, np.max(labels) + 1), dtype=np.float32) onehot[np.arange(labels.size), labels] = 1.0 with TFRecordExporter(tfrecord_dir, images.shape[0]) as tfr: order = tfr.choose_shuffled_order() for idx in range(order.size): tfr.add_image(images[order[idx]]) tfr.add_labels(onehot[order]) #---------------------------------------------------------------------------- def create_svhn(tfrecord_dir, svhn_dir): print('Loading SVHN from "%s"' % svhn_dir) import pickle images = [] labels = [] for batch in range(1, 4): with open(os.path.join(svhn_dir, 'train_%d.pkl' % batch), 'rb') as file: data = pickle.load(file, encoding='latin1') images.append(data[0]) labels.append(data[1]) images = np.concatenate(images) labels = np.concatenate(labels) assert images.shape == (73257, 3, 32, 32) and images.dtype == np.uint8 assert labels.shape == (73257,) and labels.dtype == np.uint8 assert np.min(images) == 0 and np.max(images) == 255 assert np.min(labels) == 0 and np.max(labels) == 9 onehot = np.zeros((labels.size, np.max(labels) + 1), dtype=np.float32) onehot[np.arange(labels.size), labels] = 1.0 with TFRecordExporter(tfrecord_dir, images.shape[0]) as tfr: order = tfr.choose_shuffled_order() for idx in range(order.size): tfr.add_image(images[order[idx]]) tfr.add_labels(onehot[order]) #---------------------------------------------------------------------------- def create_lsun(tfrecord_dir, lmdb_dir, resolution=256, max_images=None): print('Loading LSUN dataset from "%s"' % lmdb_dir) import lmdb # pip install lmdb # pylint: disable=import-error import cv2 # pip install opencv-python import io with lmdb.open(lmdb_dir, readonly=True).begin(write=False) as txn: total_images = txn.stat()['entries'] # pylint: disable=no-value-for-parameter if max_images is None: max_images = total_images with TFRecordExporter(tfrecord_dir, max_images) as tfr: for _idx, (_key, value) in enumerate(txn.cursor()): try: try: img = cv2.imdecode(np.fromstring(value, dtype=np.uint8), 1) if img is None: raise IOError('cv2.imdecode failed') img = img[:, :, ::-1] # BGR => RGB except IOError: img = np.asarray(PIL.Image.open(io.BytesIO(value))) crop = np.min(img.shape[:2]) img = img[(img.shape[0] - crop) // 2 : (img.shape[0] + crop) // 2, (img.shape[1] - crop) // 2 : (img.shape[1] + crop) // 2] img = PIL.Image.fromarray(img, 'RGB') img = img.resize((resolution, resolution), PIL.Image.ANTIALIAS) img = np.asarray(img) img = img.transpose([2, 0, 1]) # HWC => CHW tfr.add_image(img) except: print(sys.exc_info()[1]) if tfr.cur_images == max_images: break #---------------------------------------------------------------------------- def create_lsun_wide(tfrecord_dir, lmdb_dir, width=512, height=384, max_images=None): assert width == 2 ** int(np.round(np.log2(width))) assert height <= width print('Loading LSUN dataset from "%s"' % lmdb_dir) import lmdb # pip install lmdb # pylint: disable=import-error import cv2 # pip install opencv-python import io with lmdb.open(lmdb_dir, readonly=True).begin(write=False) as txn: total_images = txn.stat()['entries'] # pylint: disable=no-value-for-parameter if max_images is None: max_images = total_images with TFRecordExporter(tfrecord_dir, max_images, print_progress=False) as tfr: for idx, (_key, value) in enumerate(txn.cursor()): try: try: img = cv2.imdecode(np.fromstring(value, dtype=np.uint8), 1) if img is None: raise IOError('cv2.imdecode failed') img = img[:, :, ::-1] # BGR => RGB except IOError: img = np.asarray(PIL.Image.open(io.BytesIO(value))) ch = int(np.round(width * img.shape[0] / img.shape[1])) if img.shape[1] < width or ch < height: continue img = img[(img.shape[0] - ch) // 2 : (img.shape[0] + ch) // 2] img = PIL.Image.fromarray(img, 'RGB') img = img.resize((width, height), PIL.Image.ANTIALIAS) img = np.asarray(img) img = img.transpose([2, 0, 1]) # HWC => CHW canvas = np.zeros([3, width, width], dtype=np.uint8) canvas[:, (width - height) // 2 : (width + height) // 2] = img tfr.add_image(canvas) print('\r%d / %d => %d ' % (idx + 1, total_images, tfr.cur_images), end='') except: print(sys.exc_info()[1]) if tfr.cur_images == max_images: break print() #---------------------------------------------------------------------------- def create_celeba(tfrecord_dir, celeba_dir, cx=89, cy=121): print('Loading CelebA from "%s"' % celeba_dir) glob_pattern = os.path.join(celeba_dir, 'img_align_celeba_png', '*.png') image_filenames = sorted(glob.glob(glob_pattern)) expected_images = 202599 if len(image_filenames) != expected_images: error('Expected to find %d images' % expected_images) with TFRecordExporter(tfrecord_dir, len(image_filenames)) as tfr: order = tfr.choose_shuffled_order() for idx in range(order.size): img = np.asarray(PIL.Image.open(image_filenames[order[idx]])) assert img.shape == (218, 178, 3) img = img[cy - 64 : cy + 64, cx - 64 : cx + 64] img = img.transpose(2, 0, 1) # HWC => CHW tfr.add_image(img) #---------------------------------------------------------------------------- def create_from_images(tfrecord_dir, image_dir, shuffle, res_log2=7, resize=None, max_images=None): print('Loading images from "%s"' % image_dir) image_filenames = sorted(glob.glob(os.path.join(image_dir, '*'))) if max_images is None: max_images = len(image_filenames) print(f"detected {len(image_filenames)} images ...") if len(image_filenames) == 0: error('No input images found') if resize == None: img = np.asarray(PIL.Image.open(image_filenames[0]).convert('RGB')) else: img = np.asarray(PIL.Image.open(image_filenames[0]).convert('RGB').resize((resize, resize), PIL.Image.ANTIALIAS)) resolution = img.shape[0] channels = img.shape[2] if img.ndim == 3 else 1 if img.shape[1] != resolution: error('Input images must have the same width and height') if resolution != 2 ** int(np.floor(np.log2(resolution))): error('Input image resolution must be a power-of-two') if channels not in [1, 3]: error('Input images must be stored as RGB or grayscale') with TFRecordExporter(tfrecord_dir, max_images) as tfr: order = tfr.choose_shuffled_order() if shuffle else np.arange(len(image_filenames)) print("Adding the images to tfrecords ...") for idx in tqdm(range(order.size)): if resize == None: img = np.asarray(PIL.Image.open(image_filenames[order[idx]]).convert('RGB')) else: img = np.asarray(PIL.Image.open(image_filenames[order[idx]]).convert('RGB').resize((resize, resize), PIL.Image.ANTIALIAS)) if channels == 1: img = img[np.newaxis, :, :] # HW => CHW else: img = img.transpose([2, 0, 1]) # HWC => CHW tfr.add_image(img) if tfr.cur_images == max_images: break #---------------------------------------------------------------------------- def create_from_hdf5(tfrecord_dir, hdf5_filename, shuffle): print('Loading HDF5 archive from "%s"' % hdf5_filename) import h5py # conda install h5py with h5py.File(hdf5_filename, 'r') as hdf5_file: hdf5_data = max([value for key, value in hdf5_file.items() if key.startswith('data')], key=lambda lod: lod.shape[3]) with TFRecordExporter(tfrecord_dir, hdf5_data.shape[0]) as tfr: order = tfr.choose_shuffled_order() if shuffle else np.arange(hdf5_data.shape[0]) for idx in range(order.size): tfr.add_image(hdf5_data[order[idx]]) npy_filename = os.path.splitext(hdf5_filename)[0] + '-labels.npy' if os.path.isfile(npy_filename): tfr.add_labels(np.load(npy_filename)[order]) #---------------------------------------------------------------------------- def execute_cmdline(argv): prog = argv[0] parser = argparse.ArgumentParser( prog = prog, description = 'Tool for creating multi-resolution TFRecords datasets for StyleGAN and ProGAN.', epilog = 'Type "%s -h" for more information.' % prog) subparsers = parser.add_subparsers(dest='command') subparsers.required = True def add_command(cmd, desc, example=None): epilog = 'Example: %s %s' % (prog, example) if example is not None else None return subparsers.add_parser(cmd, description=desc, help=desc, epilog=epilog) p = add_command( 'display', 'Display images in dataset.', 'display datasets/mnist') p.add_argument( 'tfrecord_dir', help='Directory containing dataset') p = add_command( 'extract', 'Extract images from dataset.', 'extract datasets/mnist mnist-images') p.add_argument( 'tfrecord_dir', help='Directory containing dataset') p.add_argument( 'output_dir', help='Directory to extract the images into') p = add_command( 'compare', 'Compare two datasets.', 'compare datasets/mydataset datasets/mnist') p.add_argument( 'tfrecord_dir_a', help='Directory containing first dataset') p.add_argument( 'tfrecord_dir_b', help='Directory containing second dataset') p.add_argument( '--ignore_labels', help='Ignore labels (default: 0)', type=int, default=0) p = add_command( 'create_mnist', 'Create dataset for MNIST.', 'create_mnist datasets/mnist ~/downloads/mnist') p.add_argument( 'tfrecord_dir', help='New dataset directory to be created') p.add_argument( 'mnist_dir', help='Directory containing MNIST') p = add_command( 'create_mnistrgb', 'Create dataset for MNIST-RGB.', 'create_mnistrgb datasets/mnistrgb ~/downloads/mnist') p.add_argument( 'tfrecord_dir', help='New dataset directory to be created') p.add_argument( 'mnist_dir', help='Directory containing MNIST') p.add_argument( '--num_images', help='Number of composite images to create (default: 1000000)', type=int, default=1000000) p.add_argument( '--random_seed', help='Random seed (default: 123)', type=int, default=123) p = add_command( 'create_cifar10', 'Create dataset for CIFAR-10.', 'create_cifar10 datasets/cifar10 ~/downloads/cifar10') p.add_argument( 'tfrecord_dir', help='New dataset directory to be created') p.add_argument( 'cifar10_dir', help='Directory containing CIFAR-10') p = add_command( 'create_cifar100', 'Create dataset for CIFAR-100.', 'create_cifar100 datasets/cifar100 ~/downloads/cifar100') p.add_argument( 'tfrecord_dir', help='New dataset directory to be created') p.add_argument( 'cifar100_dir', help='Directory containing CIFAR-100') p = add_command( 'create_svhn', 'Create dataset for SVHN.', 'create_svhn datasets/svhn ~/downloads/svhn') p.add_argument( 'tfrecord_dir', help='New dataset directory to be created') p.add_argument( 'svhn_dir', help='Directory containing SVHN') p = add_command( 'create_lsun', 'Create dataset for single LSUN category.', 'create_lsun datasets/lsun-car-100k ~/downloads/lsun/car_lmdb --resolution 256 --max_images 100000') p.add_argument( 'tfrecord_dir', help='New dataset directory to be created') p.add_argument( 'lmdb_dir', help='Directory containing LMDB database') p.add_argument( '--resolution', help='Output resolution (default: 256)', type=int, default=256) p.add_argument( '--max_images', help='Maximum number of images (default: none)', type=int, default=None) p = add_command( 'create_lsun_wide', 'Create LSUN dataset with non-square aspect ratio.', 'create_lsun_wide datasets/lsun-car-512x384 ~/downloads/lsun/car_lmdb --width 512 --height 384') p.add_argument( 'tfrecord_dir', help='New dataset directory to be created') p.add_argument( 'lmdb_dir', help='Directory containing LMDB database') p.add_argument( '--width', help='Output width (default: 512)', type=int, default=512) p.add_argument( '--height', help='Output height (default: 384)', type=int, default=384) p.add_argument( '--max_images', help='Maximum number of images (default: none)', type=int, default=None) p = add_command( 'create_celeba', 'Create dataset for CelebA.', 'create_celeba datasets/celeba ~/downloads/celeba') p.add_argument( 'tfrecord_dir', help='New dataset directory to be created') p.add_argument( 'celeba_dir', help='Directory containing CelebA') p.add_argument( '--cx', help='Center X coordinate (default: 89)', type=int, default=89) p.add_argument( '--cy', help='Center Y coordinate (default: 121)', type=int, default=121) p = add_command( 'create_from_images', 'Create dataset from a directory full of images.', 'create_from_images datasets/mydataset myimagedir') p.add_argument( 'tfrecord_dir', help='New dataset directory to be created') p.add_argument( 'image_dir', help='Directory containing the images') p.add_argument( '--shuffle', help='Randomize image order (default: 1)', type=int, default=1) p.add_argument( '--resize', help="width/height of the image (default: None)", type=int, default=None, required=False) p.add_argument( '--res_log2', help="image width and height should be multiple of 2**res_log2 (default: 7)", type=int, default=7) p.add_argument( '--max_images', help='Maximum number of images (default: none)', type=int, default=None) p = add_command( 'create_from_hdf5', 'Create dataset from legacy HDF5 archive.', 'create_from_hdf5 datasets/celebahq ~/downloads/celeba-hq-1024x1024.h5') p.add_argument( 'tfrecord_dir', help='New dataset directory to be created') p.add_argument( 'hdf5_filename', help='HDF5 archive containing the images') p.add_argument( '--shuffle', help='Randomize image order (default: 1)', type=int, default=1) args = parser.parse_args(argv[1:] if len(argv) > 1 else ['-h']) func = globals()[args.command] del args.command func(**vars(args)) #---------------------------------------------------------------------------- if __name__ == "__main__": execute_cmdline(sys.argv) #---------------------------------------------------------------------------- ================================================ FILE: stylegan2-tpu/dnnlib/__init__.py ================================================ # Copyright (c) 2019, NVIDIA Corporation. All rights reserved. # # This work is made available under the Nvidia Source Code License-NC. # To view a copy of this license, visit # https://nvlabs.github.io/stylegan2/license.html from . import submission from .submission.run_context import RunContext from .submission.submit import SubmitTarget from .submission.submit import PathType from .submission.submit import SubmitConfig from .submission.submit import submit_run from .submission.submit import get_path_from_template from .submission.submit import convert_path from .submission.submit import make_run_dir_path from .util import EasyDict submit_config: SubmitConfig = None # Package level variable for SubmitConfig which is only valid when inside the run function. ================================================ FILE: stylegan2-tpu/dnnlib/submission/__init__.py ================================================ # Copyright (c) 2019, NVIDIA Corporation. All rights reserved. # # This work is made available under the Nvidia Source Code License-NC. # To view a copy of this license, visit # https://nvlabs.github.io/stylegan2/license.html from . import run_context from . import submit ================================================ FILE: stylegan2-tpu/dnnlib/submission/internal/__init__.py ================================================ # Copyright (c) 2019, NVIDIA Corporation. All rights reserved. # # This work is made available under the Nvidia Source Code License-NC. # To view a copy of this license, visit # https://nvlabs.github.io/stylegan2/license.html from . import local ================================================ FILE: stylegan2-tpu/dnnlib/submission/internal/local.py ================================================ # Copyright (c) 2019, NVIDIA Corporation. All rights reserved. # # This work is made available under the Nvidia Source Code License-NC. # To view a copy of this license, visit # https://nvlabs.github.io/stylegan2/license.html class TargetOptions(): def __init__(self): self.do_not_copy_source_files = False class Target(): def __init__(self): pass def finalize_submit_config(self, submit_config, host_run_dir): print ('Local submit ', end='', flush=True) submit_config.run_dir = host_run_dir def submit(self, submit_config, host_run_dir): from ..submit import run_wrapper, convert_path print('- run_dir: %s' % convert_path(submit_config.run_dir), flush=True) return run_wrapper(submit_config) ================================================ FILE: stylegan2-tpu/dnnlib/submission/run_context.py ================================================ # Copyright (c) 2019, NVIDIA Corporation. All rights reserved. # # This work is made available under the Nvidia Source Code License-NC. # To view a copy of this license, visit # https://nvlabs.github.io/stylegan2/license.html """Helpers for managing the run/training loop.""" import datetime import json import os import pprint import time import types from typing import Any from . import submit # Singleton RunContext _run_context = None class RunContext(object): """Helper class for managing the run/training loop. The context will hide the implementation details of a basic run/training loop. It will set things up properly, tell if run should be stopped, and then cleans up. User should call update periodically and use should_stop to determine if run should be stopped. Args: submit_config: The SubmitConfig that is used for the current run. config_module: (deprecated) The whole config module that is used for the current run. """ def __init__(self, submit_config: submit.SubmitConfig, config_module: types.ModuleType = None): global _run_context # Only a single RunContext can be alive assert _run_context is None _run_context = self self.submit_config = submit_config self.should_stop_flag = False self.has_closed = False self.start_time = time.time() self.last_update_time = time.time() self.last_update_interval = 0.0 self.progress_monitor_file_path = None # vestigial config_module support just prints a warning if config_module is not None: print("RunContext.config_module parameter support has been removed.") # write out details about the run to a text file self.run_txt_data = {"task_name": submit_config.task_name, "host_name": submit_config.host_name, "start_time": datetime.datetime.now().isoformat(sep=" ")} with open(os.path.join(submit_config.run_dir, "run.txt"), "w") as f: pprint.pprint(self.run_txt_data, stream=f, indent=4, width=200, compact=False) def __enter__(self) -> "RunContext": return self def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None: self.close() def update(self, loss: Any = 0, cur_epoch: Any = 0, max_epoch: Any = None) -> None: """Do general housekeeping and keep the state of the context up-to-date. Should be called often enough but not in a tight loop.""" assert not self.has_closed self.last_update_interval = time.time() - self.last_update_time self.last_update_time = time.time() if os.path.exists(os.path.join(self.submit_config.run_dir, "abort.txt")): self.should_stop_flag = True def should_stop(self) -> bool: """Tell whether a stopping condition has been triggered one way or another.""" return self.should_stop_flag def get_time_since_start(self) -> float: """How much time has passed since the creation of the context.""" return time.time() - self.start_time def get_time_since_last_update(self) -> float: """How much time has passed since the last call to update.""" return time.time() - self.last_update_time def get_last_update_interval(self) -> float: """How much time passed between the previous two calls to update.""" return self.last_update_interval def close(self) -> None: """Close the context and clean up. Should only be called once.""" if not self.has_closed: # update the run.txt with stopping time self.run_txt_data["stop_time"] = datetime.datetime.now().isoformat(sep=" ") with open(os.path.join(self.submit_config.run_dir, "run.txt"), "w") as f: pprint.pprint(self.run_txt_data, stream=f, indent=4, width=200, compact=False) self.has_closed = True # detach the global singleton global _run_context if _run_context is self: _run_context = None @staticmethod def get(): import dnnlib if _run_context is not None: return _run_context return RunContext(dnnlib.submit_config) ================================================ FILE: stylegan2-tpu/dnnlib/submission/submit.py ================================================ # Copyright (c) 2019, NVIDIA Corporation. All rights reserved. # # This work is made available under the Nvidia Source Code License-NC. # To view a copy of this license, visit # https://nvlabs.github.io/stylegan2/license.html """Submit a function to be run either locally or in a computing cluster.""" import copy import inspect import os import pathlib import pickle import platform import pprint import re import shutil import sys import time import traceback import threading import dnnlib.tflib as tflib import tflex import tensorflow as tf from enum import Enum from .. import util from ..util import EasyDict from . import internal class SubmitTarget(Enum): """The target where the function should be run. LOCAL: Run it locally. """ LOCAL = 1 class PathType(Enum): """Determines in which format should a path be formatted. WINDOWS: Format with Windows style. LINUX: Format with Linux/Posix style. AUTO: Use current OS type to select either WINDOWS or LINUX. """ WINDOWS = 1 LINUX = 2 AUTO = 3 class PlatformExtras: """A mixed bag of values used by dnnlib heuristics. Attributes: data_reader_buffer_size: Used by DataReader to size internal shared memory buffers. data_reader_process_count: Number of worker processes to spawn (zero for single thread operation) """ def __init__(self): self.data_reader_buffer_size = 1<<30 # 1 GB self.data_reader_process_count = 0 # single threaded default _user_name_override = None class SubmitConfig(util.EasyDict): """Strongly typed config dict needed to submit runs. Attributes: run_dir_root: Path to the run dir root. Can be optionally templated with tags. Needs to always be run through get_path_from_template. run_desc: Description of the run. Will be used in the run dir and task name. run_dir_ignore: List of file patterns used to ignore files when copying files to the run dir. run_dir_extra_files: List of (abs_path, rel_path) tuples of file paths. rel_path root will be the src directory inside the run dir. submit_target: Submit target enum value. Used to select where the run is actually launched. num_gpus: Number of GPUs used/requested for the run. print_info: Whether to print debug information when submitting. local.do_not_copy_source_files: Do not copy source files from the working directory to the run dir. run_id: Automatically populated value during submit. run_name: Automatically populated value during submit. run_dir: Automatically populated value during submit. run_func_name: Automatically populated value during submit. run_func_kwargs: Automatically populated value during submit. user_name: Automatically populated value during submit. Can be set by the user which will then override the automatic value. task_name: Automatically populated value during submit. host_name: Automatically populated value during submit. platform_extras: Automatically populated values during submit. Used by various dnnlib libraries such as the DataReader class. """ def __init__(self): super().__init__() # run (set these) self.run_dir_root = "" # should always be passed through get_path_from_template self.run_desc = "" self.run_dir_ignore = ["__pycache__", "*.pyproj", "*.sln", "*.suo", ".cache", ".idea", ".vs", ".vscode", "_cudacache"] self.run_dir_extra_files = [] # submit (set these) self.submit_target = SubmitTarget.LOCAL self.num_gpus = 1 self.print_info = False self.nvprof = False self.local = internal.local.TargetOptions() self.datasets = [] # (automatically populated) self.run_id = None self.run_name = None self.run_dir = None self.run_func_name = None self.run_func_kwargs = None self.user_name = None self.task_name = None self.host_name = "localhost" self.platform_extras = PlatformExtras() def get_path_from_template(path_template: str, path_type: PathType = PathType.AUTO) -> str: """Replace tags in the given path template and return either Windows or Linux formatted path.""" if path_template.startswith('gs://'): return path_template # automatically select path type depending on running OS if path_type == PathType.AUTO: if platform.system() == "Windows": path_type = PathType.WINDOWS else: path_type = PathType.LINUX path_template = path_template.replace("", get_user_name()) # return correctly formatted path if path_type == PathType.WINDOWS: return str(pathlib.PureWindowsPath(path_template)) elif path_type == PathType.LINUX: return str(pathlib.PurePosixPath(path_template)) else: raise RuntimeError("Unknown platform") def get_template_from_path(path: str) -> str: """Convert a normal path back to its template representation.""" path = path.replace("\\", "/") return path def convert_path(path: str, path_type: PathType = PathType.AUTO) -> str: """Convert a normal path to template and the convert it back to a normal path with given path type.""" path_template = get_template_from_path(path) path = get_path_from_template(path_template, path_type) return path def set_user_name_override(name: str) -> None: """Set the global username override value.""" global _user_name_override _user_name_override = name def get_user_name(): """Get the current user name.""" if _user_name_override is not None: return _user_name_override elif platform.system() == "Windows": return os.getlogin() else: try: import pwd # pylint: disable=import-error return pwd.getpwuid(os.geteuid()).pw_name # pylint: disable=no-member except: return "unknown" def make_run_dir_path(*paths): """Make a path/filename that resides under the current submit run_dir. Args: *paths: Path components to be passed to os.path.join Returns: A file/dirname rooted at submit_config.run_dir. If there's no submit_config or run_dir, the base directory is the current working directory. E.g., `os.path.join(dnnlib.submit_config.run_dir, "output.txt"))` """ import dnnlib if (dnnlib.submit_config is None) or (dnnlib.submit_config.run_dir is None): return os.path.join(os.getcwd(), *paths) return os.path.join(dnnlib.submit_config.run_dir, *paths) def _create_run_dir_local(submit_config: SubmitConfig) -> str: """Create a new run dir with increasing ID number at the start.""" run_dir_root = get_path_from_template(submit_config.run_dir_root, PathType.AUTO) if not os.path.exists(run_dir_root): os.makedirs(run_dir_root) submit_config.run_id = _get_next_run_id_local(run_dir_root) submit_config.run_name = "{0:05d}-{1}".format(submit_config.run_id, submit_config.run_desc) run_dir = os.path.join(run_dir_root, submit_config.run_name) if os.path.exists(run_dir): raise RuntimeError("The run dir already exists! ({0})".format(run_dir)) os.makedirs(run_dir) return run_dir def _get_next_run_id_local(run_dir_root: str) -> int: """Reads all directory names in a given directory (non-recursive) and returns the next (increasing) run id. Assumes IDs are numbers at the start of the directory names.""" dir_names = [d for d in os.listdir(run_dir_root) if os.path.isdir(os.path.join(run_dir_root, d))] r = re.compile("^\\d+") # match one or more digits at the start of the string run_id = 0 for dir_name in dir_names: m = r.match(dir_name) if m is not None: i = int(m.group()) run_id = max(run_id, i + 1) return run_id def _populate_run_dir(submit_config: SubmitConfig, run_dir: str) -> None: """Copy all necessary files into the run dir. Assumes that the dir exists, is local, and is writable.""" pickle.dump(submit_config, open(os.path.join(run_dir, "submit_config.pkl"), "wb")) with open(os.path.join(run_dir, "submit_config.txt"), "w") as f: pprint.pprint(submit_config, stream=f, indent=4, width=200, compact=False) if (submit_config.submit_target == SubmitTarget.LOCAL) and submit_config.local.do_not_copy_source_files: return files = [] run_func_module_dir_path = util.get_module_dir_by_obj_name(submit_config.run_func_name) assert '.' in submit_config.run_func_name for _idx in range(submit_config.run_func_name.count('.') - 1): run_func_module_dir_path = os.path.dirname(run_func_module_dir_path) files += util.list_dir_recursively_with_ignore(run_func_module_dir_path, ignores=submit_config.run_dir_ignore, add_base_to_relative=False) dnnlib_module_dir_path = util.get_module_dir_by_obj_name("dnnlib") files += util.list_dir_recursively_with_ignore(dnnlib_module_dir_path, ignores=submit_config.run_dir_ignore, add_base_to_relative=True) files += submit_config.run_dir_extra_files files = [(f[0], os.path.join(run_dir, "src", f[1])) for f in files] files += [(os.path.join(dnnlib_module_dir_path, "submission", "internal", "run.py"), os.path.join(run_dir, "run.py"))] util.copy_files_and_create_dirs(files) def run_wrapper(submit_config: SubmitConfig) -> None: """Wrap the actual run function call for handling logging, exceptions, typing, etc.""" is_local = submit_config.submit_target == SubmitTarget.LOCAL # when running locally, redirect stderr to stdout, log stdout to a file, and force flushing if is_local: logger = util.Logger(file_name=os.path.join(submit_config.run_dir, "log.txt"), file_mode="w", should_flush=True) else: # when running in a cluster, redirect stderr to stdout, and just force flushing (log writing is handled by run.sh) logger = util.Logger(file_name=None, should_flush=True) import dnnlib dnnlib.submit_config = submit_config exit_with_errcode = False try: print("dnnlib: Running {0}() on {1}...".format(submit_config.run_func_name, submit_config.host_name)) start_time = time.time() run_func_obj = util.get_obj_by_name(submit_config.run_func_name) assert callable(run_func_obj) def thunk(): sig = inspect.signature(run_func_obj) if 'submit_config' in sig.parameters: run_func_obj(submit_config=submit_config, **submit_config.run_func_kwargs) else: run_func_obj(**submit_config.run_func_kwargs) kws = submit_config.run_func_kwargs tf_config = kws['tf_config'] if 'tf_config' in kws else {} if 'TPU_NAME' not in os.environ or 'NO_SWARM' in os.environ: tflib.init_tf(tf_config) thunk() else: threads = [] tflex.trainers = [] tpu_core_count = 1 if 'TPU_CORE_COUNT' not in os.environ else int(os.environ['TPU_CORE_COUNT']) tpu_core_offset = 0 if 'TPU_CORE_OFFSET' not in os.environ else int(os.environ['TPU_CORE_OFFSET']) for i in range(tpu_core_count): def worker(i): _id = i + tpu_core_offset spec = '#%d' % _id print(spec, 'Initializing...') tflib.init_tf(tf_config) sess = tf.get_default_session() cores = tflex.get_cores()[tpu_core_offset:tpu_core_offset+tpu_core_count] sess.id = _id tflex.trainers.append(sess) if False: tflex.set_override_device(cores[i]) with tf.device(cores[i]): print(spec, 'Running thunk...') thunk() else: tflex.set_override_cores(cores) print(spec, 'Running thunk...') thunk() if tpu_core_count <= 1: worker(i) else: thread = threading.Thread(target=worker, args=(i,)) threads.append(thread) thread.start() for thread in threads: thread.join() print("dnnlib: Finished {0}() in {1}.".format(submit_config.run_func_name, util.format_time(time.time() - start_time))) except: if is_local: raise else: traceback.print_exc() log_src = os.path.join(submit_config.run_dir, "log.txt") log_dst = os.path.join(get_path_from_template(submit_config.run_dir_root), "{0}-error.txt".format(submit_config.run_name)) shutil.copyfile(log_src, log_dst) # Defer sys.exit(1) to happen after we close the logs and create a _finished.txt exit_with_errcode = True finally: open(os.path.join(submit_config.run_dir, "_finished.txt"), "w").close() dnnlib.RunContext.get().close() dnnlib.submit_config = None logger.close() # If we hit an error, get out of the script now and signal the error # to whatever process that started this script. if exit_with_errcode: sys.exit(1) return submit_config def submit_run(submit_config: SubmitConfig, run_func_name: str, **run_func_kwargs) -> None: """Create a run dir, gather files related to the run, copy files to the run dir, and launch the run in appropriate place.""" submit_config = copy.deepcopy(submit_config) submit_target = submit_config.submit_target farm = None if submit_target == SubmitTarget.LOCAL: farm = internal.local.Target() assert farm is not None # unknown target # Disallow submitting jobs with zero num_gpus. if (submit_config.num_gpus is None) or (submit_config.num_gpus == 0): raise RuntimeError("submit_config.num_gpus must be set to a non-zero value") if submit_config.user_name is None: submit_config.user_name = get_user_name() submit_config.run_func_name = run_func_name submit_config.run_func_kwargs = run_func_kwargs #-------------------------------------------------------------------- # Prepare submission by populating the run dir #-------------------------------------------------------------------- host_run_dir = _create_run_dir_local(submit_config) submit_config.task_name = "{0}-{1:05d}-{2}".format(submit_config.user_name, submit_config.run_id, submit_config.run_desc) docker_valid_name_regex = "^[a-zA-Z0-9][a-zA-Z0-9_.-]+$" if not re.match(docker_valid_name_regex, submit_config.task_name): raise RuntimeError("Invalid task name. Probable reason: unacceptable characters in your submit_config.run_desc. Task name must be accepted by the following regex: " + docker_valid_name_regex + ", got " + submit_config.task_name) # Farm specific preparations for a submit farm.finalize_submit_config(submit_config, host_run_dir) _populate_run_dir(submit_config, host_run_dir) return farm.submit(submit_config, host_run_dir) ================================================ FILE: stylegan2-tpu/dnnlib/tflib/__init__.py ================================================ # Copyright (c) 2019, NVIDIA Corporation. All rights reserved. # # This work is made available under the Nvidia Source Code License-NC. # To view a copy of this license, visit # https://nvlabs.github.io/stylegan2/license.html from . import autosummary from . import network from . import optimizer from . import tfutil from . import custom_ops from .tfutil import * from .network import Network from .optimizer import Optimizer from .custom_ops import get_plugin ================================================ FILE: stylegan2-tpu/dnnlib/tflib/autosummary.py ================================================ # Copyright (c) 2019, NVIDIA Corporation. All rights reserved. # # This work is made available under the Nvidia Source Code License-NC. # To view a copy of this license, visit # https://nvlabs.github.io/stylegan2/license.html """Helper for adding automatically tracked values to Tensorboard. Autosummary creates an identity op that internally keeps track of the input values and automatically shows up in TensorBoard. The reported value represents an average over input components. The average is accumulated constantly over time and flushed when save_summaries() is called. Notes: - The output tensor must be used as an input for something else in the graph. Otherwise, the autosummary op will not get executed, and the average value will not get accumulated. - It is perfectly fine to include autosummaries with the same name in several places throughout the graph, even if they are executed concurrently. - It is ok to also pass in a python scalar or numpy array. In this case, it is added to the average immediately. """ from collections import OrderedDict import numpy as np import tensorflow as tf import tflex from tensorboard import summary as summary_lib from tensorboard.plugins.custom_scalar import layout_pb2 from . import tfutil from .tfutil import TfExpression from .tfutil import TfExpressionEx # Enable "Custom scalars" tab in TensorBoard for advanced formatting. # Disabled by default to reduce tfevents file size. enable_custom_scalars = False _dtype = tf.float64 _vars = OrderedDict() # name => [var, ...] _immediate = OrderedDict() # name => update_op, update_value _finalized = False _merge_op = None def _create_var(name: str, value_expr: TfExpression) -> TfExpression: """Internal helper for creating autosummary accumulators.""" assert not _finalized name_id = name.replace("/", "_") v = tf.cast(value_expr, _dtype) if v.shape.is_fully_defined(): size = np.prod(v.shape.as_list()) size_expr = tf.constant(size, dtype=_dtype) else: size = None size_expr = tf.reduce_prod(tf.cast(tf.shape(v), _dtype)) if size == 1: if v.shape.ndims != 0: v = tf.reshape(v, []) v = [size_expr, v, tf.square(v)] else: v = [size_expr, tf.reduce_sum(v), tf.reduce_sum(tf.square(v))] v = tf.cond(tf.is_finite(v[1]), lambda: tf.stack(v), lambda: tf.zeros(3, dtype=_dtype)) with tfutil.absolute_name_scope("Autosummary/" + name_id), tf.control_dependencies(None): var = tf.Variable(tf.zeros(3, dtype=_dtype), trainable=False) # [sum(1), sum(x), sum(x**2)] update_op = tf.cond(tf.is_variable_initialized(var), lambda: tf.assign_add(var, v), lambda: tf.assign(var, v)) if name in _vars: _vars[name].append(var) else: _vars[name] = [var] return update_op import os from . import tpu_summaries tpu_summary = None def get_tpu_summary(model_dir=None): global tpu_summary if tpu_summary is None: if model_dir is None: model_dir = os.path.join(os.environ['MODEL_DIR'], 'autosummary') tpu_summary = tpu_summaries.TpuSummaries(model_dir) else: assert model_dir is None return tpu_summary # TODO(joelshor): Make this a special case of `image_reshaper`. def image_grid(input_tensor, grid_shape, image_shape=(32, 32), num_channels=3): """Arrange a minibatch of images into a grid to form a single image. Args: input_tensor: Tensor. Minibatch of images to format, either 4D ([batch size, height, width, num_channels]) or flattened ([batch size, height * width * num_channels]). grid_shape: Sequence of int. The shape of the image grid, formatted as [grid_height, grid_width]. image_shape: Sequence of int. The shape of a single image, formatted as [image_height, image_width]. num_channels: int. The number of channels in an image. Returns: Tensor representing a single image in which the input images have been arranged into a grid. Raises: ValueError: The grid shape and minibatch size don't match, or the image shape and number of channels are incompatible with the input tensor. """ if grid_shape[0] * grid_shape[1] != int(input_tensor.shape[0]): raise ValueError("Grid shape %s incompatible with minibatch size %i." % (grid_shape, int(input_tensor.shape[0]))) if len(input_tensor.shape) == 2: num_features = image_shape[0] * image_shape[1] * num_channels if int(input_tensor.shape[1]) != num_features: raise ValueError("Image shape and number of channels incompatible with " "input tensor.") elif len(input_tensor.shape) == 4: if (int(input_tensor.shape[1]) != image_shape[0] or int(input_tensor.shape[2]) != image_shape[1] or int(input_tensor.shape[3]) != num_channels): raise ValueError("Image shape and number of channels incompatible with " "input tensor. %s vs %s" % ( input_tensor.shape, (image_shape[0], image_shape[1], num_channels))) else: raise ValueError("Unrecognized input tensor format.") height, width = grid_shape[0] * image_shape[0], grid_shape[1] * image_shape[1] input_tensor = tf.reshape( input_tensor, tuple(grid_shape) + tuple(image_shape) + (num_channels,)) input_tensor = tf.transpose(a=input_tensor, perm=[0, 1, 3, 2, 4]) input_tensor = tf.reshape( input_tensor, [grid_shape[0], width, image_shape[0], num_channels]) input_tensor = tf.transpose(a=input_tensor, perm=[0, 2, 1, 3]) input_tensor = tf.reshape(input_tensor, [1, height, width, num_channels]) return input_tensor num_replicas = None def get_num_replicas(): assert num_replicas is not None return num_replicas def set_num_replicas(n): global num_replicas num_replicas = n def _i(x): return tf.transpose(x, [0, 2, 3, 1]) def _o(x): return tf.transpose(x, [0, 3, 1, 2]) def autoimages(summary_name, images, grid_shape=None, res=None): """Called from model_fn() to add a grid of images as summary.""" # convert from [batch, channels, width, height] to [batch, width, height, channels] images = _i(images) # All summary tensors are synced to host 0 on every step. To avoid sending # more images then needed we transfer at most `sampler_per_replica` to # create a 8x8 image grid. batch_size_per_replica = images.shape[0].value num_replicas = get_num_replicas() total_num_images = batch_size_per_replica * num_replicas if callable(grid_shape): grid_shape = grid_shape(total_num_images) if grid_shape is None: w = int(os.environ['GRID_WIDTH']) if 'GRID_WIDTH' in os.environ else 3 h = int(os.environ['GRID_HEIGHT']) if 'GRID_HEIGHT' in os.environ else 3 grid_shape = (w, h) sample_num_images = np.prod(grid_shape) if total_num_images >= sample_num_images: # This can be more than 64. We slice all_images below. samples_per_replica = int(np.ceil(sample_num_images / num_replicas)) else: samples_per_replica = batch_size_per_replica if res is None: res = int(os.environ['RESOLUTION']) if 'RESOLUTION' in os.environ else 64 num_channels = int(os.environ["NUM_CHANNELS"]) if "NUM_CHANNELS" in os.environ else 3 image_shape = [res, res, num_channels] sample_res = int(os.environ['GRID_RESOLUTION']) if 'GRID_RESOLUTION' in os.environ else 200 sample_shape = [sample_res, sample_res, num_channels] tf.logging.info("autoimages(%s, %s): Creating %dx%d images grid at resolution %dx%d channel count %d across %d replicas", repr(summary_name), repr(images), grid_shape[0], grid_shape[1], image_shape[0], image_shape[1], image_shape[2], num_replicas) images = images[:samples_per_replica] def _merge_images_to_grid(all_images): all_images = all_images[:np.prod(grid_shape)] shape = image_shape if shape[0] > sample_shape[0] or shape[1] > sample_shape[1]: tf.logging.info('autoimages(%s, %s): Downscaling sampled images from %dx%d to %dx%d', repr(summary_name), repr(all_images), shape[0], shape[1], sample_shape[0], sample_shape[1]) all_images = tf.image.resize(all_images, sample_shape[0:2], method=tf.image.ResizeMethod.AREA) shape = sample_shape return image_grid( all_images, grid_shape=grid_shape, image_shape=shape[:2], num_channels=shape[2]) get_tpu_summary().image(summary_name, images, reduce_fn=_merge_images_to_grid) def autosummary(name: str, value: TfExpressionEx, passthru: TfExpressionEx = None, condition: TfExpressionEx = True) -> TfExpressionEx: """Create a new autosummary. Args: name: Name to use in TensorBoard value: TensorFlow expression or python value to track passthru: Optionally return this TF node without modifications but tack an autosummary update side-effect to this node. Example use of the passthru mechanism: n = autosummary('l2loss', loss, passthru=n) This is a shorthand for the following code: with tf.control_dependencies([autosummary('l2loss', loss)]): n = tf.identity(n) """ tf.logging.info('autosummary(%s, %s)', repr(name), repr(value)) get_tpu_summary().scalar(name, value) return value tfutil.assert_tf_initialized() name_id = name.replace("/", "_") if tfutil.is_tf_expression(value): with tf.name_scope("summary_" + name_id), tflex.device(value.device): condition = tf.convert_to_tensor(condition, name='condition') update_op = tf.cond(condition, lambda: tf.group(_create_var(name, value)), tf.no_op) with tf.control_dependencies([update_op]): return tf.identity(value if passthru is None else passthru) else: # python scalar or numpy array assert not tfutil.is_tf_expression(passthru) assert not tfutil.is_tf_expression(condition) if condition: if name not in _immediate: with tfutil.absolute_name_scope("Autosummary/" + name_id), tflex.device(None), tf.control_dependencies(None): update_value = tf.placeholder(_dtype) update_op = _create_var(name, update_value) _immediate[name] = update_op, update_value update_op, update_value = _immediate[name] tfutil.run(update_op, {update_value: value}) return value if passthru is None else passthru def finalize_autosummaries() -> None: """Create the necessary ops to include autosummaries in TensorBoard report. Note: This should be done only once per graph. """ global _finalized tfutil.assert_tf_initialized() if _finalized: return None _finalized = True tfutil.init_uninitialized_vars([var for vars_list in _vars.values() for var in vars_list]) # Create summary ops. with tflex.device(None), tf.control_dependencies(None): for name, vars_list in _vars.items(): name_id = name.replace("/", "_") with tfutil.absolute_name_scope("Autosummary/" + name_id): moments = tf.add_n(vars_list) moments /= moments[0] with tf.control_dependencies([moments]): # read before resetting reset_ops = [tf.assign(var, tf.zeros(3, dtype=_dtype)) for var in vars_list] with tf.name_scope(None), tf.control_dependencies(reset_ops): # reset before reporting mean = moments[1] std = tf.sqrt(moments[2] - tf.square(moments[1])) tf.summary.scalar(name, mean) if enable_custom_scalars: tf.summary.scalar("xCustomScalars/" + name + "/margin_lo", mean - std) tf.summary.scalar("xCustomScalars/" + name + "/margin_hi", mean + std) # Setup layout for custom scalars. layout = None if enable_custom_scalars: cat_dict = OrderedDict() for series_name in sorted(_vars.keys()): p = series_name.split("/") cat = p[0] if len(p) >= 2 else "" chart = "/".join(p[1:-1]) if len(p) >= 3 else p[-1] if cat not in cat_dict: cat_dict[cat] = OrderedDict() if chart not in cat_dict[cat]: cat_dict[cat][chart] = [] cat_dict[cat][chart].append(series_name) categories = [] for cat_name, chart_dict in cat_dict.items(): charts = [] for chart_name, series_names in chart_dict.items(): series = [] for series_name in series_names: series.append(layout_pb2.MarginChartContent.Series( value=series_name, lower="xCustomScalars/" + series_name + "/margin_lo", upper="xCustomScalars/" + series_name + "/margin_hi")) margin = layout_pb2.MarginChartContent(series=series) charts.append(layout_pb2.Chart(title=chart_name, margin=margin)) categories.append(layout_pb2.Category(title=cat_name, chart=charts)) layout = summary_lib.custom_scalar_pb(layout_pb2.Layout(category=categories)) return layout def save_summaries(file_writer, global_step=None): """Call FileWriter.add_summary() with all summaries in the default graph, automatically finalizing and merging them on the first call. """ return global _merge_op tfutil.assert_tf_initialized() if _merge_op is None: layout = finalize_autosummaries() if layout is not None: file_writer.add_summary(layout) with tflex.device(None), tf.control_dependencies(None): _merge_op = tf.summary.merge_all() if _merge_op is not None: file_writer.add_summary(_merge_op.eval(), global_step) ================================================ FILE: stylegan2-tpu/dnnlib/tflib/custom_ops.py ================================================ # Copyright (c) 2019, NVIDIA Corporation. All rights reserved. # # This work is made available under the Nvidia Source Code License-NC. # To view a copy of this license, visit # https://nvlabs.github.io/stylegan2/license.html """TensorFlow custom ops builder. """ import os import re import uuid import hashlib import tempfile import shutil import tensorflow as tf from tensorflow.python.client import device_lib # pylint: disable=no-name-in-module #---------------------------------------------------------------------------- # Global options. cuda_cache_path = os.path.join(os.path.dirname(__file__), '_cudacache') cuda_cache_version_tag = 'v1' do_not_hash_included_headers = False # Speed up compilation by assuming that headers included by the CUDA code never change. Unsafe! verbose = True # Print status messages to stdout. compiler_bindir_search_path = [ 'C:/Program Files (x86)/Microsoft Visual Studio/2017/Community/VC/Tools/MSVC/14.14.26428/bin/Hostx64/x64', 'C:/Program Files (x86)/Microsoft Visual Studio/2019/Community/VC/Tools/MSVC/14.23.28105/bin/Hostx64/x64', 'C:/Program Files (x86)/Microsoft Visual Studio 14.0/vc/bin', ] #---------------------------------------------------------------------------- # Internal helper funcs. def _find_compiler_bindir(): for compiler_path in compiler_bindir_search_path: if os.path.isdir(compiler_path): return compiler_path return None def _get_compute_cap(device): caps_str = device.physical_device_desc m = re.search('compute capability: (\\d+).(\\d+)', caps_str) major = m.group(1) minor = m.group(2) return (major, minor) def _get_cuda_gpu_arch_string(): gpus = [x for x in device_lib.list_local_devices() if x.device_type == 'GPU'] if len(gpus) == 0: raise RuntimeError('No GPU devices found') (major, minor) = _get_compute_cap(gpus[0]) return 'sm_%s%s' % (major, minor) def _run_cmd(cmd): with os.popen(cmd) as pipe: output = pipe.read() status = pipe.close() if status is not None: raise RuntimeError('NVCC returned an error. See below for full command line and output log:\n\n%s\n\n%s' % (cmd, output)) def _prepare_nvcc_cli(opts): cmd = 'nvcc ' + opts.strip() cmd += ' --disable-warnings' cmd += ' --include-path "%s"' % tf.sysconfig.get_include() cmd += ' --include-path "%s"' % os.path.join(tf.sysconfig.get_include(), 'external', 'protobuf_archive', 'src') cmd += ' --include-path "%s"' % os.path.join(tf.sysconfig.get_include(), 'external', 'com_google_absl') cmd += ' --include-path "%s"' % os.path.join(tf.sysconfig.get_include(), 'external', 'eigen_archive') compiler_bindir = _find_compiler_bindir() if compiler_bindir is None: # Require that _find_compiler_bindir succeeds on Windows. Allow # nvcc to use whatever is the default on Linux. if os.name == 'nt': raise RuntimeError('Could not find MSVC/GCC/CLANG installation on this computer. Check compiler_bindir_search_path list in "%s".' % __file__) else: cmd += ' --compiler-bindir "%s"' % compiler_bindir cmd += ' 2>&1' return cmd #---------------------------------------------------------------------------- # Main entry point. _plugin_cache = dict() def get_plugin(cuda_file): cuda_file_base = os.path.basename(cuda_file) cuda_file_name, cuda_file_ext = os.path.splitext(cuda_file_base) # Already in cache? if cuda_file in _plugin_cache: return _plugin_cache[cuda_file] # Setup plugin. if verbose: print('Setting up TensorFlow plugin "%s": ' % cuda_file_base, end='', flush=True) try: # Hash CUDA source. md5 = hashlib.md5() with open(cuda_file, 'rb') as f: md5.update(f.read()) md5.update(b'\n') # Hash headers included by the CUDA code by running it through the preprocessor. if not do_not_hash_included_headers: if verbose: print('Preprocessing... ', end='', flush=True) with tempfile.TemporaryDirectory() as tmp_dir: tmp_file = os.path.join(tmp_dir, cuda_file_name + '_tmp' + cuda_file_ext) _run_cmd(_prepare_nvcc_cli('"%s" --preprocess -o "%s" --keep --keep-dir "%s"' % (cuda_file, tmp_file, tmp_dir))) with open(tmp_file, 'rb') as f: bad_file_str = ('"' + cuda_file.replace('\\', '/') + '"').encode('utf-8') # __FILE__ in error check macros good_file_str = ('"' + cuda_file_base + '"').encode('utf-8') for ln in f: if not ln.startswith(b'# ') and not ln.startswith(b'#line '): # ignore line number pragmas ln = ln.replace(bad_file_str, good_file_str) md5.update(ln) md5.update(b'\n') # Select compiler options. compile_opts = '' if os.name == 'nt': compile_opts += '"%s"' % os.path.join(tf.sysconfig.get_lib(), 'python', '_pywrap_tensorflow_internal.lib') elif os.name == 'posix': compile_opts += '"%s"' % os.path.join(tf.sysconfig.get_lib(), 'python', '_pywrap_tensorflow_internal.so') compile_opts += ' --compiler-options \'-fPIC -D_GLIBCXX_USE_CXX11_ABI=0\'' else: assert False # not Windows or Linux, w00t? compile_opts += ' --gpu-architecture=%s' % _get_cuda_gpu_arch_string() compile_opts += ' --use_fast_math' nvcc_cmd = _prepare_nvcc_cli(compile_opts) # Hash build configuration. md5.update(('nvcc_cmd: ' + nvcc_cmd).encode('utf-8') + b'\n') md5.update(('tf.VERSION: ' + tf.VERSION).encode('utf-8') + b'\n') md5.update(('cuda_cache_version_tag: ' + cuda_cache_version_tag).encode('utf-8') + b'\n') # Compile if not already compiled. bin_file_ext = '.dll' if os.name == 'nt' else '.so' bin_file = os.path.join(cuda_cache_path, cuda_file_name + '_' + md5.hexdigest() + bin_file_ext) if not os.path.isfile(bin_file): if verbose: print('Compiling... ', end='', flush=True) with tempfile.TemporaryDirectory() as tmp_dir: tmp_file = os.path.join(tmp_dir, cuda_file_name + '_tmp' + bin_file_ext) _run_cmd(nvcc_cmd + ' "%s" --shared -o "%s" --keep --keep-dir "%s"' % (cuda_file, tmp_file, tmp_dir)) os.makedirs(cuda_cache_path, exist_ok=True) intermediate_file = os.path.join(cuda_cache_path, cuda_file_name + '_' + uuid.uuid4().hex + '_tmp' + bin_file_ext) shutil.copyfile(tmp_file, intermediate_file) os.rename(intermediate_file, bin_file) # atomic # Load. if verbose: print('Loading... ', end='', flush=True) plugin = tf.load_op_library(bin_file) # Add to cache. _plugin_cache[cuda_file] = plugin if verbose: print('Done.', flush=True) return plugin except: if verbose: print('Failed!', flush=True) raise #---------------------------------------------------------------------------- ================================================ FILE: stylegan2-tpu/dnnlib/tflib/network.py ================================================ # Copyright (c) 2019, NVIDIA Corporation. All rights reserved. # # This work is made available under the Nvidia Source Code License-NC. # To view a copy of this license, visit # https://nvlabs.github.io/stylegan2/license.html """Helper for managing networks.""" import types import inspect import re import uuid import sys import numpy as np import tensorflow as tf import tflex import threading tflex.network_lock = threading.RLock() from collections import OrderedDict from typing import Any, List, Tuple, Union from . import tfutil from .. import util from .tfutil import TfExpression, TfExpressionEx _import_handlers = [] # Custom import handlers for dealing with legacy data in pickle import. _import_module_src = dict() # Source code for temporary modules created during pickle import. def import_handler(handler_func): """Function decorator for declaring custom import handlers.""" _import_handlers.append(handler_func) return handler_func class Network: """Generic network abstraction. Acts as a convenience wrapper for a parameterized network construction function, providing several utility methods and convenient access to the inputs/outputs/weights. Network objects can be safely pickled and unpickled for long-term archival purposes. The pickling works reliably as long as the underlying network construction function is defined in a standalone Python module that has no side effects or application-specific imports. Args: name: Network name. Used to select TensorFlow name and variable scopes. func_name: Fully qualified name of the underlying network construction function, or a top-level function object. static_kwargs: Keyword arguments to be passed in to the network construction function. Attributes: name: User-specified name, defaults to build func name if None. scope: Unique TensorFlow scope containing template graph and variables, derived from the user-specified name. static_kwargs: Arguments passed to the user-supplied build func. components: Container for sub-networks. Passed to the build func, and retained between calls. num_inputs: Number of input tensors. num_outputs: Number of output tensors. input_shapes: Input tensor shapes (NC or NCHW), including minibatch dimension. output_shapes: Output tensor shapes (NC or NCHW), including minibatch dimension. input_shape: Short-hand for input_shapes[0]. output_shape: Short-hand for output_shapes[0]. input_templates: Input placeholders in the template graph. output_templates: Output tensors in the template graph. input_names: Name string for each input. output_names: Name string for each output. own_vars: Variables defined by this network (local_name => var), excluding sub-networks. vars: All variables (local_name => var). trainables: All trainable variables (local_name => var). var_global_to_local: Mapping from variable global names to local names. """ def __init__(self, name: str = None, scope: str = None, func_name: Any = None, reset_own_vars = False, **static_kwargs): tfutil.assert_tf_initialized() assert isinstance(name, str) or name is None assert func_name is not None assert isinstance(func_name, str) or util.is_top_level_function(func_name) assert util.is_pickleable(static_kwargs) self._init_fields() self.name = name self.scope = scope self.static_kwargs = util.EasyDict(static_kwargs) # Locate the user-specified network build function. if util.is_top_level_function(func_name): func_name = util.get_top_level_function_name(func_name) module, self._build_func_name = util.get_module_from_obj_name(func_name) self._build_func = util.get_obj_from_module(module, self._build_func_name) assert callable(self._build_func) # Dig up source code for the module containing the build function. self._build_module_src = _import_module_src.get(module, None) if self._build_module_src is None: self._build_module_src = inspect.getsource(module) # Init TensorFlow graph. self._init_graph() if reset_own_vars: self.ensure() def ensure(self): for k, v in self.components.items(): v.ensure() if self._need_reset: self.reset_own_vars() self._need_reset = False return self def _init_fields(self) -> None: self.name = None self.scope = None self.static_kwargs = util.EasyDict() self.components = util.EasyDict() self.num_inputs = 0 self.num_outputs = 0 self.input_shapes = [[]] self.output_shapes = [[]] self.input_shape = [] self.output_shape = [] self.input_templates = [] self.output_templates = [] self.input_names = [] self.output_names = [] self.own_vars = OrderedDict() self.vars = OrderedDict() self.trainables = OrderedDict() self.var_global_to_local = OrderedDict() self._build_func = None # User-supplied build function that constructs the network. self._build_func_name = None # Name of the build function. self._build_module_src = None # Full source code of the module containing the build function. self._run_cache = dict() # Cached graph data for Network.run(). self._need_reset = True def _init_graph(self) -> None: with tflex.network_lock: self._init_graph_() def _init_graph_(self) -> None: # Collect inputs. self.input_names = [] for param in inspect.signature(self._build_func).parameters.values(): if param.kind == param.POSITIONAL_OR_KEYWORD and param.default is param.empty: self.input_names.append(param.name) self.num_inputs = len(self.input_names) assert self.num_inputs >= 1 # Choose name and scope. if self.name is None: self.name = self._build_func_name assert re.match("^[A-Za-z0-9_.\\-]*$", self.name) if self.scope is None: with tf.name_scope(None): self.scope = tf.get_default_graph().unique_name(self.name, mark_as_used=True) # Finalize build func kwargs. build_kwargs = dict(self.static_kwargs) build_kwargs["is_template_graph"] = True build_kwargs["components"] = self.components # Build template graph. with tfutil.absolute_variable_scope(self.scope, reuse=False), tfutil.absolute_name_scope(self.scope): # ignore surrounding scopes assert tf.get_variable_scope().name == self.scope assert tf.get_default_graph().get_name_scope() == self.scope with tf.control_dependencies(None): # ignore surrounding control dependencies self.input_templates = [tf.placeholder(tf.float32, name=name) for name in self.input_names] out_expr = self._build_func(*self.input_templates, **build_kwargs) # Collect outputs. assert tfutil.is_tf_expression(out_expr) or isinstance(out_expr, tuple) self.output_templates = [out_expr] if tfutil.is_tf_expression(out_expr) else list(out_expr) self.num_outputs = len(self.output_templates) assert self.num_outputs >= 1 assert all(tfutil.is_tf_expression(t) for t in self.output_templates) # Perform sanity checks. if any(t.shape.ndims is None for t in self.input_templates): raise ValueError("Network input shapes not defined. Please call x.set_shape() for each input.") if any(t.shape.ndims is None for t in self.output_templates): raise ValueError("Network output shapes not defined. Please call x.set_shape() where applicable.") if any(not isinstance(comp, Network) for comp in self.components.values()): raise ValueError("Components of a Network must be Networks themselves.") if len(self.components) != len(set(comp.name for comp in self.components.values())): raise ValueError("Components of a Network must have unique names.") # List inputs and outputs. self.input_shapes = [t.shape.as_list() for t in self.input_templates] self.output_shapes = [t.shape.as_list() for t in self.output_templates] self.input_shape = self.input_shapes[0] self.output_shape = self.output_shapes[0] self.output_names = [t.name.split("/")[-1].split(":")[0] for t in self.output_templates] # List variables. self.own_vars = OrderedDict((var.name[len(self.scope) + 1:].split(":")[0], var) for var in tf.global_variables(self.scope + "/")) self.vars = OrderedDict(self.own_vars) self.vars.update((comp.name + "/" + name, var) for comp in self.components.values() for name, var in comp.vars.items()) self.trainables = OrderedDict((name, var) for name, var in self.vars.items() if var.trainable) self.var_global_to_local = OrderedDict((var.name.split(":")[0], name) for name, var in self.vars.items()) def reset_own_vars(self) -> None: """Re-initialize all variables of this network, excluding sub-networks.""" tfutil.run([var.initializer for var in self.own_vars.values()]) def reset_vars(self) -> None: """Re-initialize all variables of this network, including sub-networks.""" tfutil.run([var.initializer for var in self.vars.values()]) def reset_trainables(self) -> None: """Re-initialize all trainable variables of this network, including sub-networks.""" tfutil.run([var.initializer for var in self.trainables.values()]) def get_output_for(self, *in_expr: TfExpression, return_as_list: bool = False, **dynamic_kwargs) -> Union[TfExpression, List[TfExpression]]: """Construct TensorFlow expression(s) for the output(s) of this network, given the input expression(s).""" assert len(in_expr) == self.num_inputs assert not all(expr is None for expr in in_expr) # Finalize build func kwargs. build_kwargs = dict(self.static_kwargs) build_kwargs.update(dynamic_kwargs) build_kwargs["is_template_graph"] = False build_kwargs["components"] = self.components # Build TensorFlow graph to evaluate the network. with tfutil.absolute_variable_scope(self.scope, reuse=True), tf.name_scope(self.name): assert tf.get_variable_scope().name == self.scope valid_inputs = [expr for expr in in_expr if expr is not None] final_inputs = [] for expr, name, shape in zip(in_expr, self.input_names, self.input_shapes): if expr is not None: expr = tf.identity(expr, name=name) else: expr = tf.zeros([tf.shape(valid_inputs[0])[0]] + shape[1:], name=name) final_inputs.append(expr) out_expr = self._build_func(*final_inputs, **build_kwargs) # Propagate input shapes back to the user-specified expressions. for expr, final in zip(in_expr, final_inputs): if isinstance(expr, tf.Tensor): expr.set_shape(final.shape) # Express outputs in the desired format. assert tfutil.is_tf_expression(out_expr) or isinstance(out_expr, tuple) if return_as_list: out_expr = [out_expr] if tfutil.is_tf_expression(out_expr) else list(out_expr) return out_expr def get_var_local_name(self, var_or_global_name: Union[TfExpression, str]) -> str: """Get the local name of a given variable, without any surrounding name scopes.""" assert tfutil.is_tf_expression(var_or_global_name) or isinstance(var_or_global_name, str) global_name = var_or_global_name if isinstance(var_or_global_name, str) else var_or_global_name.name return self.var_global_to_local[global_name] def find_var(self, var_or_local_name: Union[TfExpression, str]) -> TfExpression: """Find variable by local or global name.""" assert tfutil.is_tf_expression(var_or_local_name) or isinstance(var_or_local_name, str) return self.vars[var_or_local_name] if isinstance(var_or_local_name, str) else var_or_local_name def get_var(self, var_or_local_name: Union[TfExpression, str]) -> np.ndarray: """Get the value of a given variable as NumPy array. Note: This method is very inefficient -- prefer to use tflib.run(list_of_vars) whenever possible.""" return self.find_var(var_or_local_name).eval() def set_var(self, var_or_local_name: Union[TfExpression, str], new_value: Union[int, float, np.ndarray]) -> None: """Set the value of a given variable based on the given NumPy array. Note: This method is very inefficient -- prefer to use tflib.set_vars() whenever possible.""" tfutil.set_vars({self.find_var(var_or_local_name): new_value}) def __getstate__(self) -> dict: """Pickle export.""" state = dict() state["version"] = 4 state["name"] = self.name state["static_kwargs"] = dict(self.static_kwargs) state["components"] = dict(self.components) state["build_module_src"] = self._build_module_src state["build_func_name"] = self._build_func_name state["variables"] = list(zip(self.own_vars.keys(), tfutil.run(list(self.own_vars.values())))) return state def __setstate__(self, state: dict) -> None: """Pickle import.""" # pylint: disable=attribute-defined-outside-init tfutil.assert_tf_initialized() self._init_fields() # Execute custom import handlers. for handler in _import_handlers: state = handler(state) # Set basic fields. assert state["version"] in [2, 3, 4] self.name = state["name"] self.static_kwargs = util.EasyDict(state["static_kwargs"]) self.components = util.EasyDict(state.get("components", {})) self._build_module_src = state["build_module_src"] self._build_func_name = state["build_func_name"] # Create temporary module from the imported source code. module_name = "_tflib_network_import_" + uuid.uuid4().hex module = types.ModuleType(module_name) sys.modules[module_name] = module _import_module_src[module] = self._build_module_src exec(self._build_module_src, module.__dict__) # pylint: disable=exec-used # Locate network build function in the temporary module. self._build_func = util.get_obj_from_module(module, self._build_func_name) assert callable(self._build_func) # Init TensorFlow graph. self._init_graph() self.reset_own_vars() tfutil.set_vars({self.find_var(name): value for name, value in state["variables"]}) def clone(self, name: str = None, **new_static_kwargs) -> "Network": """Create a clone of this network with its own copy of the variables.""" net, finalize = self.clone2(name, **new_static_kwargs) finalize() return net def clone2(self, name: str = None, **new_static_kwargs) -> ("Network", Any): """Create a clone of this network with its own copy of the variables.""" # pylint: disable=protected-access net = object.__new__(Network) net._init_fields() net.name = name if name is not None else self.name net.static_kwargs = util.EasyDict(self.static_kwargs) net.static_kwargs.update(new_static_kwargs) net._build_module_src = self._build_module_src net._build_func_name = self._build_func_name net._build_func = self._build_func net._init_graph() def finalize(): with tflex.network_lock: self.ensure() net.ensure() net.copy_vars_from(self) return net, finalize def copy_own_vars_from(self, src_net: "Network") -> None: """Copy the values of all variables from the given network, excluding sub-networks.""" names = [name for name in self.own_vars.keys() if name in src_net.own_vars] tfutil.set_vars({self.vars[name]: src_net.vars[name] for name in names}) def copy_vars_from(self, src_net: "Network") -> None: """Copy the values of all variables from the given network, including sub-networks.""" names = [name for name in self.vars.keys() if name in src_net.vars] tfutil.set_vars({self.vars[name]: src_net.vars[name] for name in names}) def copy_trainables_from(self, src_net: "Network") -> None: """Copy the values of all trainable variables from the given network, including sub-networks.""" names = [name for name in self.trainables.keys() if name in src_net.trainables] tfutil.set_vars({self.vars[name]: src_net.vars[name] for name in names}) def convert(self, new_func_name: str, new_name: str = None, **new_static_kwargs) -> "Network": """Create new network with the given parameters, and copy all variables from this network.""" if new_name is None: new_name = self.name static_kwargs = dict(self.static_kwargs) static_kwargs.update(new_static_kwargs) net = Network(name=new_name, func_name=new_func_name, **static_kwargs) net.copy_vars_from(self) return net def setup_as_moving_average_of(self, src_net: "Network", beta: TfExpressionEx = 0.99, beta_nontrainable: TfExpressionEx = 0.0) -> tf.Operation: """Construct a TensorFlow op that updates the variables of this network to be slightly closer to those of the given network.""" with tfutil.absolute_name_scope(self.scope + "/_MovingAvg"): ops = [] for name, var in self.vars.items(): if name in src_net.vars: cur_beta = beta if name in self.trainables else beta_nontrainable new_value = tfutil.lerp(src_net.vars[name], var, cur_beta) ops.append(var.assign(new_value)) return tf.group(*ops) def run(self, *in_arrays: Tuple[Union[np.ndarray, None], ...], input_transform: dict = None, output_transform: dict = None, return_as_list: bool = False, print_progress: bool = False, minibatch_size: int = None, num_gpus: int = 1, assume_frozen: bool = False, **dynamic_kwargs) -> Union[np.ndarray, Tuple[np.ndarray, ...], List[np.ndarray]]: """Run this network for the given NumPy array(s), and return the output(s) as NumPy array(s). Args: input_transform: A dict specifying a custom transformation to be applied to the input tensor(s) before evaluating the network. The dict must contain a 'func' field that points to a top-level function. The function is called with the input TensorFlow expression(s) as positional arguments. Any remaining fields of the dict will be passed in as kwargs. output_transform: A dict specifying a custom transformation to be applied to the output tensor(s) after evaluating the network. The dict must contain a 'func' field that points to a top-level function. The function is called with the output TensorFlow expression(s) as positional arguments. Any remaining fields of the dict will be passed in as kwargs. return_as_list: True = return a list of NumPy arrays, False = return a single NumPy array, or a tuple if there are multiple outputs. print_progress: Print progress to the console? Useful for very large input arrays. minibatch_size: Maximum minibatch size to use, None = disable batching. num_gpus: Number of GPUs to use. assume_frozen: Improve multi-GPU performance by assuming that the trainable parameters will remain changed between calls. dynamic_kwargs: Additional keyword arguments to be passed into the network build function. """ assert len(in_arrays) == self.num_inputs assert not all(arr is None for arr in in_arrays) assert input_transform is None or util.is_top_level_function(input_transform["func"]) assert output_transform is None or util.is_top_level_function(output_transform["func"]) output_transform, dynamic_kwargs = _handle_legacy_output_transforms(output_transform, dynamic_kwargs) num_items = in_arrays[0].shape[0] if minibatch_size is None: minibatch_size = num_items # Construct unique hash key from all arguments that affect the TensorFlow graph. key = dict(input_transform=input_transform, output_transform=output_transform, num_gpus=num_gpus, assume_frozen=assume_frozen, dynamic_kwargs=dynamic_kwargs) def unwind_key(obj): if isinstance(obj, dict): return [(key, unwind_key(value)) for key, value in sorted(obj.items())] if callable(obj): return util.get_top_level_function_name(obj) return obj key = repr(unwind_key(key)) # Build graph. if key not in self._run_cache: with tfutil.absolute_name_scope(self.scope + "/_Run"), tf.control_dependencies(None): with tflex.device("/cpu:0"): in_expr = [tf.placeholder(tf.float32, name=name) for name in self.input_names] in_split = list(zip(*[tf.split(x, num_gpus) for x in in_expr])) out_split = [] for gpu in range(num_gpus): with tflex.device("/gpu:%d" % gpu): net_gpu = self.clone() if assume_frozen else self in_gpu = in_split[gpu] if input_transform is not None: in_kwargs = dict(input_transform) in_gpu = in_kwargs.pop("func")(*in_gpu, **in_kwargs) in_gpu = [in_gpu] if tfutil.is_tf_expression(in_gpu) else list(in_gpu) assert len(in_gpu) == self.num_inputs out_gpu = net_gpu.get_output_for(*in_gpu, return_as_list=True, **dynamic_kwargs) if output_transform is not None: out_kwargs = dict(output_transform) out_gpu = out_kwargs.pop("func")(*out_gpu, **out_kwargs) out_gpu = [out_gpu] if tfutil.is_tf_expression(out_gpu) else list(out_gpu) assert len(out_gpu) == self.num_outputs out_split.append(out_gpu) with tflex.device("/cpu:0"): out_expr = [tf.concat(outputs, axis=0) for outputs in zip(*out_split)] self._run_cache[key] = in_expr, out_expr # Run minibatches. in_expr, out_expr = self._run_cache[key] out_arrays = [np.empty([num_items] + expr.shape.as_list()[1:], expr.dtype.name) for expr in out_expr] for mb_begin in range(0, num_items, minibatch_size): if print_progress: print("\r%d / %d" % (mb_begin, num_items), end="") mb_end = min(mb_begin + minibatch_size, num_items) mb_num = mb_end - mb_begin mb_in = [src[mb_begin : mb_end] if src is not None else np.zeros([mb_num] + shape[1:]) for src, shape in zip(in_arrays, self.input_shapes)] mb_out = tf.get_default_session().run(out_expr, dict(zip(in_expr, mb_in))) for dst, src in zip(out_arrays, mb_out): dst[mb_begin: mb_end] = src # Done. if print_progress: print("\r%d / %d" % (num_items, num_items)) if not return_as_list: out_arrays = out_arrays[0] if len(out_arrays) == 1 else tuple(out_arrays) return out_arrays def list_ops(self) -> List[TfExpression]: include_prefix = self.scope + "/" exclude_prefix = include_prefix + "_" ops = tf.get_default_graph().get_operations() ops = [op for op in ops if op.name.startswith(include_prefix)] ops = [op for op in ops if not op.name.startswith(exclude_prefix)] return ops def list_layers(self) -> List[Tuple[str, TfExpression, List[TfExpression]]]: """Returns a list of (layer_name, output_expr, trainable_vars) tuples corresponding to individual layers of the network. Mainly intended to be used for reporting.""" layers = [] def recurse(scope, parent_ops, parent_vars, level): # Ignore specific patterns. if any(p in scope for p in ["/Shape", "/strided_slice", "/Cast", "/concat", "/Assign"]): return # Filter ops and vars by scope. global_prefix = scope + "/" local_prefix = global_prefix[len(self.scope) + 1:] cur_ops = [op for op in parent_ops if op.name.startswith(global_prefix) or op.name == global_prefix[:-1]] cur_vars = [(name, var) for name, var in parent_vars if name.startswith(local_prefix) or name == local_prefix[:-1]] if not cur_ops and not cur_vars: return # Filter out all ops related to variables. for var in [op for op in cur_ops if op.type.startswith("Variable")]: var_prefix = var.name + "/" cur_ops = [op for op in cur_ops if not op.name.startswith(var_prefix)] # Scope does not contain ops as immediate children => recurse deeper. contains_direct_ops = any("/" not in op.name[len(global_prefix):] and op.type not in ["Identity", "Cast", "Transpose"] for op in cur_ops) if (level == 0 or not contains_direct_ops) and (len(cur_ops) + len(cur_vars)) > 1: visited = set() for rel_name in [op.name[len(global_prefix):] for op in cur_ops] + [name[len(local_prefix):] for name, _var in cur_vars]: token = rel_name.split("/")[0] if token not in visited: recurse(global_prefix + token, cur_ops, cur_vars, level + 1) visited.add(token) return # Report layer. layer_name = scope[len(self.scope) + 1:] layer_output = cur_ops[-1].outputs[0] if cur_ops else cur_vars[-1][1] layer_trainables = [var for _name, var in cur_vars if var.trainable] layers.append((layer_name, layer_output, layer_trainables)) recurse(self.scope, self.list_ops(), list(self.vars.items()), 0) return layers def print_layers(self, title: str = None, hide_layers_with_no_params: bool = False) -> None: """Print a summary table of the network structure.""" rows = [[title if title is not None else self.name, "Params", "OutputShape", "WeightShape"]] rows += [["---"] * 4] total_params = 0 for layer_name, layer_output, layer_trainables in self.list_layers(): num_params = sum(int(np.prod(var.shape.as_list())) for var in layer_trainables) weights = [var for var in layer_trainables if var.name.endswith("/weight:0")] weights.sort(key=lambda x: len(x.name)) if len(weights) == 0 and len(layer_trainables) == 1: weights = layer_trainables total_params += num_params if not hide_layers_with_no_params or num_params != 0: num_params_str = str(num_params) if num_params > 0 else "-" output_shape_str = str(layer_output.shape) weight_shape_str = str(weights[0].shape) if len(weights) >= 1 else "-" rows += [[layer_name, num_params_str, output_shape_str, weight_shape_str]] rows += [["---"] * 4] rows += [["Total", str(total_params), "", ""]] widths = [max(len(cell) for cell in column) for column in zip(*rows)] print() for row in rows: print(" ".join(cell + " " * (width - len(cell)) for cell, width in zip(row, widths))) print() def setup_weight_histograms(self, title: str = None) -> None: """Construct summary ops to include histograms of all trainable parameters in TensorBoard.""" if title is None: title = self.name with tf.name_scope(None), tflex.device(None), tf.control_dependencies(None): for local_name, var in self.trainables.items(): if "/" in local_name: p = local_name.split("/") name = title + "_" + p[-1] + "/" + "_".join(p[:-1]) else: name = title + "_toplevel/" + local_name tf.summary.histogram(name, var) #---------------------------------------------------------------------------- # Backwards-compatible emulation of legacy output transformation in Network.run(). _print_legacy_warning = True def _handle_legacy_output_transforms(output_transform, dynamic_kwargs): global _print_legacy_warning legacy_kwargs = ["out_mul", "out_add", "out_shrink", "out_dtype"] if not any(kwarg in dynamic_kwargs for kwarg in legacy_kwargs): return output_transform, dynamic_kwargs if _print_legacy_warning: _print_legacy_warning = False print() print("WARNING: Old-style output transformations in Network.run() are deprecated.") print("Consider using 'output_transform=dict(func=tflib.convert_images_to_uint8)'") print("instead of 'out_mul=127.5, out_add=127.5, out_dtype=np.uint8'.") print() assert output_transform is None new_kwargs = dict(dynamic_kwargs) new_transform = {kwarg: new_kwargs.pop(kwarg) for kwarg in legacy_kwargs if kwarg in dynamic_kwargs} new_transform["func"] = _legacy_output_transform_func return new_transform, new_kwargs def _legacy_output_transform_func(*expr, out_mul=1.0, out_add=0.0, out_shrink=1, out_dtype=None): if out_mul != 1.0: expr = [x * out_mul for x in expr] if out_add != 0.0: expr = [x + out_add for x in expr] if out_shrink > 1: ksize = [1, 1, out_shrink, out_shrink] expr = [tf.nn.avg_pool(x, ksize=ksize, strides=ksize, padding="VALID", data_format="NCHW") for x in expr] if out_dtype is not None: if tf.as_dtype(out_dtype).is_integer: expr = [tf.round(x) for x in expr] expr = [tf.saturate_cast(x, out_dtype) for x in expr] return expr ================================================ FILE: stylegan2-tpu/dnnlib/tflib/ops/__init__.py ================================================ # Copyright (c) 2019, NVIDIA Corporation. All rights reserved. # # This work is made available under the Nvidia Source Code License-NC. # To view a copy of this license, visit # https://nvlabs.github.io/stylegan2/license.html # empty ================================================ FILE: stylegan2-tpu/dnnlib/tflib/ops/fused_bias_act.cu ================================================ // Copyright (c) 2019, NVIDIA Corporation. All rights reserved. // // This work is made available under the Nvidia Source Code License-NC. // To view a copy of this license, visit // https://nvlabs.github.io/stylegan2/license.html #define EIGEN_USE_GPU #define __CUDA_INCLUDE_COMPILER_INTERNAL_HEADERS__ #include "tensorflow/core/framework/op.h" #include "tensorflow/core/framework/op_kernel.h" #include "tensorflow/core/framework/shape_inference.h" #include using namespace tensorflow; using namespace tensorflow::shape_inference; #define OP_CHECK_CUDA_ERROR(CTX, CUDA_CALL) do { cudaError_t err = CUDA_CALL; OP_REQUIRES(CTX, err == cudaSuccess, errors::Internal(cudaGetErrorName(err))); } while (false) //------------------------------------------------------------------------ // CUDA kernel. template struct FusedBiasActKernelParams { const T* x; // [sizeX] const T* b; // [sizeB] or NULL const T* ref; // [sizeX] or NULL T* y; // [sizeX] int grad; int axis; int act; float alpha; float gain; int sizeX; int sizeB; int stepB; int loopX; }; template static __global__ void FusedBiasActKernel(const FusedBiasActKernelParams p) { const float expRange = 80.0f; const float halfExpRange = 40.0f; const float seluScale = 1.0507009873554804934193349852946f; const float seluAlpha = 1.6732632423543772848170429916717f; // Loop over elements. int xi = blockIdx.x * p.loopX * blockDim.x + threadIdx.x; for (int loopIdx = 0; loopIdx < p.loopX && xi < p.sizeX; loopIdx++, xi += blockDim.x) { // Load and apply bias. float x = (float)p.x[xi]; if (p.b) x += (float)p.b[(xi / p.stepB) % p.sizeB]; float ref = (p.ref) ? (float)p.ref[xi] : 0.0f; if (p.gain != 0.0f & p.act != 9) ref /= p.gain; // Evaluate activation func. float y; switch (p.act * 10 + p.grad) { // linear default: case 10: y = x; break; case 11: y = x; break; case 12: y = 0.0f; break; // relu case 20: y = (x > 0.0f) ? x : 0.0f; break; case 21: y = (ref > 0.0f) ? x : 0.0f; break; case 22: y = 0.0f; break; // lrelu case 30: y = (x > 0.0f) ? x : x * p.alpha; break; case 31: y = (ref > 0.0f) ? x : x * p.alpha; break; case 32: y = 0.0f; break; // tanh case 40: { float c = expf(x); float d = 1.0f / c; y = (x < -expRange) ? -1.0f : (x > expRange) ? 1.0f : (c - d) / (c + d); } break; case 41: y = x * (1.0f - ref * ref); break; case 42: y = x * (1.0f - ref * ref) * (-2.0f * ref); break; // sigmoid case 50: y = (x < -expRange) ? 0.0f : 1.0f / (expf(-x) + 1.0f); break; case 51: y = x * ref * (1.0f - ref); break; case 52: y = x * ref * (1.0f - ref) * (1.0f - 2.0f * ref); break; // elu case 60: y = (x >= 0.0f) ? x : expf(x) - 1.0f; break; case 61: y = (ref >= 0.0f) ? x : x * (ref + 1.0f); break; case 62: y = (ref >= 0.0f) ? 0.0f : x * (ref + 1.0f); break; // selu case 70: y = (x >= 0.0f) ? seluScale * x : (seluScale * seluAlpha) * (expf(x) - 1.0f); break; case 71: y = (ref >= 0.0f) ? x * seluScale : x * (ref + seluScale * seluAlpha); break; case 72: y = (ref >= 0.0f) ? 0.0f : x * (ref + seluScale * seluAlpha); break; // softplus case 80: y = (x > expRange) ? x : logf(expf(x) + 1.0f); break; case 81: y = x * (1.0f - expf(-ref)); break; case 82: { float c = expf(-ref); y = x * c * (1.0f - c); } break; // swish case 90: y = (x < -expRange) ? 0.0f : x / (expf(-x) + 1.0f); break; case 91: { float c = expf(ref); float d = c + 1.0f; y = (ref > halfExpRange) ? x : x * c * (ref + d) / (d * d); } break; case 92: { float c = expf(ref); float d = c + 1.0f; y = (ref > halfExpRange) ? 0.0f : x * c * (ref * (2.0f - d) + 2.0f * d) / (d * d * d); } break; } // Apply gain and store. p.y[xi] = (T)(y * p.gain); } } //------------------------------------------------------------------------ // TensorFlow op. template struct FusedBiasActOp : public OpKernel { FusedBiasActKernelParams m_attribs; FusedBiasActOp(OpKernelConstruction* ctx) : OpKernel(ctx) { memset(&m_attribs, 0, sizeof(m_attribs)); OP_REQUIRES_OK(ctx, ctx->GetAttr("grad", &m_attribs.grad)); OP_REQUIRES_OK(ctx, ctx->GetAttr("axis", &m_attribs.axis)); OP_REQUIRES_OK(ctx, ctx->GetAttr("act", &m_attribs.act)); OP_REQUIRES_OK(ctx, ctx->GetAttr("alpha", &m_attribs.alpha)); OP_REQUIRES_OK(ctx, ctx->GetAttr("gain", &m_attribs.gain)); OP_REQUIRES(ctx, m_attribs.grad >= 0, errors::InvalidArgument("grad must be non-negative")); OP_REQUIRES(ctx, m_attribs.axis >= 0, errors::InvalidArgument("axis must be non-negative")); OP_REQUIRES(ctx, m_attribs.act >= 0, errors::InvalidArgument("act must be non-negative")); } void Compute(OpKernelContext* ctx) { FusedBiasActKernelParams p = m_attribs; cudaStream_t stream = ctx->eigen_device().stream(); const Tensor& x = ctx->input(0); // [...] const Tensor& b = ctx->input(1); // [sizeB] or [0] const Tensor& ref = ctx->input(2); // x.shape or [0] p.x = x.flat().data(); p.b = (b.NumElements()) ? b.flat().data() : NULL; p.ref = (ref.NumElements()) ? ref.flat().data() : NULL; OP_REQUIRES(ctx, b.NumElements() == 0 || m_attribs.axis < x.dims(), errors::InvalidArgument("axis out of bounds")); OP_REQUIRES(ctx, b.dims() == 1, errors::InvalidArgument("b must have rank 1")); OP_REQUIRES(ctx, b.NumElements() == 0 || b.NumElements() == x.dim_size(m_attribs.axis), errors::InvalidArgument("b has wrong number of elements")); OP_REQUIRES(ctx, ref.NumElements() == ((p.grad == 0) ? 0 : x.NumElements()), errors::InvalidArgument("ref has wrong number of elements")); OP_REQUIRES(ctx, x.NumElements() <= kint32max, errors::InvalidArgument("x is too large")); p.sizeX = (int)x.NumElements(); p.sizeB = (int)b.NumElements(); p.stepB = 1; for (int i = m_attribs.axis + 1; i < x.dims(); i++) p.stepB *= (int)x.dim_size(i); Tensor* y = NULL; // x.shape OP_REQUIRES_OK(ctx, ctx->allocate_output(0, x.shape(), &y)); p.y = y->flat().data(); p.loopX = 4; int blockSize = 4 * 32; int gridSize = (p.sizeX - 1) / (p.loopX * blockSize) + 1; void* args[] = {&p}; OP_CHECK_CUDA_ERROR(ctx, cudaLaunchKernel((void*)FusedBiasActKernel, gridSize, blockSize, args, 0, stream)); } }; REGISTER_OP("FusedBiasAct") .Input ("x: T") .Input ("b: T") .Input ("ref: T") .Output ("y: T") .Attr ("T: {float, half}") .Attr ("grad: int = 0") .Attr ("axis: int = 1") .Attr ("act: int = 0") .Attr ("alpha: float = 0.0") .Attr ("gain: float = 1.0"); REGISTER_KERNEL_BUILDER(Name("FusedBiasAct").Device(DEVICE_GPU).TypeConstraint("T"), FusedBiasActOp); REGISTER_KERNEL_BUILDER(Name("FusedBiasAct").Device(DEVICE_GPU).TypeConstraint("T"), FusedBiasActOp); //------------------------------------------------------------------------ ================================================ FILE: stylegan2-tpu/dnnlib/tflib/ops/fused_bias_act.py ================================================ # Copyright (c) 2019, NVIDIA Corporation. All rights reserved. # # This work is made available under the Nvidia Source Code License-NC. # To view a copy of this license, visit # https://nvlabs.github.io/stylegan2/license.html """Custom TensorFlow ops for efficient bias and activation.""" import os import numpy as np import tensorflow as tf from .. import custom_ops from ...util import EasyDict def _get_plugin(): return custom_ops.get_plugin(os.path.splitext(__file__)[0] + '.cu') #---------------------------------------------------------------------------- activation_funcs = { 'linear': EasyDict(func=lambda x, **_: x, def_alpha=None, def_gain=1.0, cuda_idx=1, ref='y', zero_2nd_grad=True), 'relu': EasyDict(func=lambda x, **_: tf.nn.relu(x), def_alpha=None, def_gain=np.sqrt(2), cuda_idx=2, ref='y', zero_2nd_grad=True), 'lrelu': EasyDict(func=lambda x, alpha, **_: tf.nn.leaky_relu(x, alpha), def_alpha=0.2, def_gain=np.sqrt(2), cuda_idx=3, ref='y', zero_2nd_grad=True), 'tanh': EasyDict(func=lambda x, **_: tf.nn.tanh(x), def_alpha=None, def_gain=1.0, cuda_idx=4, ref='y', zero_2nd_grad=False), 'sigmoid': EasyDict(func=lambda x, **_: tf.nn.sigmoid(x), def_alpha=None, def_gain=1.0, cuda_idx=5, ref='y', zero_2nd_grad=False), 'elu': EasyDict(func=lambda x, **_: tf.nn.elu(x), def_alpha=None, def_gain=1.0, cuda_idx=6, ref='y', zero_2nd_grad=False), 'selu': EasyDict(func=lambda x, **_: tf.nn.selu(x), def_alpha=None, def_gain=1.0, cuda_idx=7, ref='y', zero_2nd_grad=False), 'softplus': EasyDict(func=lambda x, **_: tf.nn.softplus(x), def_alpha=None, def_gain=1.0, cuda_idx=8, ref='y', zero_2nd_grad=False), 'swish': EasyDict(func=lambda x, **_: tf.nn.sigmoid(x) * x, def_alpha=None, def_gain=np.sqrt(2), cuda_idx=9, ref='x', zero_2nd_grad=False), } #---------------------------------------------------------------------------- def fused_bias_act(x, b=None, axis=1, act='linear', alpha=None, gain=None, impl='cuda'): r"""Fused bias and activation function. Adds bias `b` to activation tensor `x`, evaluates activation function `act`, and scales the result by `gain`. Each of the steps is optional. In most cases, the fused op is considerably more efficient than performing the same calculation using standard TensorFlow ops. It supports first and second order gradients, but not third order gradients. Args: x: Input activation tensor. Can have any shape, but if `b` is defined, the dimension corresponding to `axis`, as well as the rank, must be known. b: Bias vector, or `None` to disable. Must be a 1D tensor of the same type as `x`. The shape must be known, and it must match the dimension of `x` corresponding to `axis`. axis: The dimension in `x` corresponding to the elements of `b`. The value of `axis` is ignored if `b` is not specified. act: Name of the activation function to evaluate, or `"linear"` to disable. Can be e.g. `"relu"`, `"lrelu"`, `"tanh"`, `"sigmoid"`, `"swish"`, etc. See `activation_funcs` for a full list. `None` is not allowed. alpha: Shape parameter for the activation function, or `None` to use the default. gain: Scaling factor for the output tensor, or `None` to use default. See `activation_funcs` for the default scaling of each activation function. If unsure, consider specifying `1.0`. impl: Name of the implementation to use. Can be `"ref"` or `"cuda"` (default). Returns: Tensor of the same shape and datatype as `x`. """ impl_dict = { 'ref': _fused_bias_act_ref, 'cuda': _fused_bias_act_ref if 'TPU_NAME' in os.environ or 'NO_NVCC' in os.environ else _fused_bias_act_cuda, } return impl_dict[impl](x=x, b=b, axis=axis, act=act, alpha=alpha, gain=gain) #---------------------------------------------------------------------------- def _fused_bias_act_ref(x, b, axis, act, alpha, gain): """Slow reference implementation of `fused_bias_act()` using standard TensorFlow ops.""" # Validate arguments. x = tf.convert_to_tensor(x) b = tf.convert_to_tensor(b) if b is not None else tf.constant([], dtype=x.dtype) act_spec = activation_funcs[act] assert b.shape.rank == 1 and (b.shape[0] == 0 or b.shape[0] == x.shape[axis]) assert b.shape[0] == 0 or 0 <= axis < x.shape.rank if alpha is None: alpha = act_spec.def_alpha if gain is None: gain = act_spec.def_gain # Add bias. if b.shape[0] != 0: x += tf.reshape(b, [-1 if i == axis else 1 for i in range(x.shape.rank)]) # Evaluate activation function. x = act_spec.func(x, alpha=alpha) # Scale by gain. if gain != 1: x *= gain return x #---------------------------------------------------------------------------- def _fused_bias_act_cuda(x, b, axis, act, alpha, gain): """Fast CUDA implementation of `fused_bias_act()` using custom ops.""" # Validate arguments. x = tf.convert_to_tensor(x) empty_tensor = tf.constant([], dtype=x.dtype) b = tf.convert_to_tensor(b) if b is not None else empty_tensor act_spec = activation_funcs[act] assert b.shape.rank == 1 and (b.shape[0] == 0 or b.shape[0] == x.shape[axis]) assert b.shape[0] == 0 or 0 <= axis < x.shape.rank if alpha is None: alpha = act_spec.def_alpha if gain is None: gain = act_spec.def_gain # Special cases. if act == 'linear' and b is None and gain == 1.0: return x if act_spec.cuda_idx is None: return _fused_bias_act_ref(x=x, b=b, axis=axis, act=act, alpha=alpha, gain=gain) # CUDA kernel. cuda_kernel = _get_plugin().fused_bias_act cuda_kwargs = dict(axis=axis, act=act_spec.cuda_idx, alpha=alpha, gain=gain) # Forward pass: y = func(x, b). def func_y(x, b): y = cuda_kernel(x=x, b=b, ref=empty_tensor, grad=0, **cuda_kwargs) y.set_shape(x.shape) return y # Backward pass: dx, db = grad(dy, x, y) def grad_dx(dy, x, y): ref = {'x': x, 'y': y}[act_spec.ref] dx = cuda_kernel(x=dy, b=empty_tensor, ref=ref, grad=1, **cuda_kwargs) dx.set_shape(x.shape) return dx def grad_db(dx): if b.shape[0] == 0: return empty_tensor db = dx if axis < x.shape.rank - 1: db = tf.reduce_sum(db, list(range(axis + 1, x.shape.rank))) if axis > 0: db = tf.reduce_sum(db, list(range(axis))) db.set_shape(b.shape) return db # Second order gradients: d_dy, d_x = grad2(d_dx, d_db, x, y) def grad2_d_dy(d_dx, d_db, x, y): ref = {'x': x, 'y': y}[act_spec.ref] d_dy = cuda_kernel(x=d_dx, b=d_db, ref=ref, grad=1, **cuda_kwargs) d_dy.set_shape(x.shape) return d_dy def grad2_d_x(d_dx, d_db, x, y): ref = {'x': x, 'y': y}[act_spec.ref] d_x = cuda_kernel(x=d_dx, b=d_db, ref=ref, grad=2, **cuda_kwargs) d_x.set_shape(x.shape) return d_x # Fast version for piecewise-linear activation funcs. @tf.custom_gradient def func_zero_2nd_grad(x, b): y = func_y(x, b) @tf.custom_gradient def grad(dy): dx = grad_dx(dy, x, y) db = grad_db(dx) def grad2(d_dx, d_db): d_dy = grad2_d_dy(d_dx, d_db, x, y) return d_dy return (dx, db), grad2 return y, grad # Slow version for general activation funcs. @tf.custom_gradient def func_nonzero_2nd_grad(x, b): y = func_y(x, b) def grad_wrap(dy): @tf.custom_gradient def grad_impl(dy, x): dx = grad_dx(dy, x, y) db = grad_db(dx) def grad2(d_dx, d_db): d_dy = grad2_d_dy(d_dx, d_db, x, y) d_x = grad2_d_x(d_dx, d_db, x, y) return d_dy, d_x return (dx, db), grad2 return grad_impl(dy, x) return y, grad_wrap # Which version to use? if act_spec.zero_2nd_grad: return func_zero_2nd_grad(x, b) return func_nonzero_2nd_grad(x, b) #---------------------------------------------------------------------------- ================================================ FILE: stylegan2-tpu/dnnlib/tflib/ops/upfirdn_2d.cu ================================================ // Copyright (c) 2019, NVIDIA Corporation. All rights reserved. // // This work is made available under the Nvidia Source Code License-NC. // To view a copy of this license, visit // https://nvlabs.github.io/stylegan2/license.html #define EIGEN_USE_GPU #define __CUDA_INCLUDE_COMPILER_INTERNAL_HEADERS__ #include "tensorflow/core/framework/op.h" #include "tensorflow/core/framework/op_kernel.h" #include "tensorflow/core/framework/shape_inference.h" #include using namespace tensorflow; using namespace tensorflow::shape_inference; //------------------------------------------------------------------------ // Helpers. #define OP_CHECK_CUDA_ERROR(CTX, CUDA_CALL) do { cudaError_t err = CUDA_CALL; OP_REQUIRES(CTX, err == cudaSuccess, errors::Internal(cudaGetErrorName(err))); } while (false) static __host__ __device__ __forceinline__ int floorDiv(int a, int b) { int c = a / b; if (c * b > a) c--; return c; } //------------------------------------------------------------------------ // CUDA kernel params. template struct UpFirDn2DKernelParams { const T* x; // [majorDim, inH, inW, minorDim] const T* k; // [kernelH, kernelW] T* y; // [majorDim, outH, outW, minorDim] int upx; int upy; int downx; int downy; int padx0; int padx1; int pady0; int pady1; int majorDim; int inH; int inW; int minorDim; int kernelH; int kernelW; int outH; int outW; int loopMajor; int loopX; }; //------------------------------------------------------------------------ // General CUDA implementation for large filter kernels. template static __global__ void UpFirDn2DKernel_large(const UpFirDn2DKernelParams p) { // Calculate thread index. int minorIdx = blockIdx.x * blockDim.x + threadIdx.x; int outY = minorIdx / p.minorDim; minorIdx -= outY * p.minorDim; int outXBase = blockIdx.y * p.loopX * blockDim.y + threadIdx.y; int majorIdxBase = blockIdx.z * p.loopMajor; if (outXBase >= p.outW || outY >= p.outH || majorIdxBase >= p.majorDim) return; // Setup Y receptive field. int midY = outY * p.downy + p.upy - 1 - p.pady0; int inY = min(max(floorDiv(midY, p.upy), 0), p.inH); int h = min(max(floorDiv(midY + p.kernelH, p.upy), 0), p.inH) - inY; int kernelY = midY + p.kernelH - (inY + 1) * p.upy; // Loop over majorDim and outX. for (int loopMajor = 0, majorIdx = majorIdxBase; loopMajor < p.loopMajor && majorIdx < p.majorDim; loopMajor++, majorIdx++) for (int loopX = 0, outX = outXBase; loopX < p.loopX && outX < p.outW; loopX++, outX += blockDim.y) { // Setup X receptive field. int midX = outX * p.downx + p.upx - 1 - p.padx0; int inX = min(max(floorDiv(midX, p.upx), 0), p.inW); int w = min(max(floorDiv(midX + p.kernelW, p.upx), 0), p.inW) - inX; int kernelX = midX + p.kernelW - (inX + 1) * p.upx; // Initialize pointers. const T* xp = &p.x[((majorIdx * p.inH + inY) * p.inW + inX) * p.minorDim + minorIdx]; const T* kp = &p.k[kernelY * p.kernelW + kernelX]; int xpx = p.minorDim; int kpx = -p.upx; int xpy = p.inW * p.minorDim; int kpy = -p.upy * p.kernelW; // Inner loop. float v = 0.0f; for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { v += (float)(*xp) * (float)(*kp); xp += xpx; kp += kpx; } xp += xpy - w * xpx; kp += kpy - w * kpx; } // Store result. p.y[((majorIdx * p.outH + outY) * p.outW + outX) * p.minorDim + minorIdx] = (T)v; } } //------------------------------------------------------------------------ // Specialized CUDA implementation for small filter kernels. template static __global__ void UpFirDn2DKernel_small(const UpFirDn2DKernelParams p) { //assert(kernelW % upx == 0); //assert(kernelH % upy == 0); const int tileInW = ((tileOutW - 1) * downx + kernelW - 1) / upx + 1; const int tileInH = ((tileOutH - 1) * downy + kernelH - 1) / upy + 1; __shared__ volatile float sk[kernelH][kernelW]; __shared__ volatile float sx[tileInH][tileInW]; // Calculate tile index. int minorIdx = blockIdx.x; int tileOutY = minorIdx / p.minorDim; minorIdx -= tileOutY * p.minorDim; tileOutY *= tileOutH; int tileOutXBase = blockIdx.y * p.loopX * tileOutW; int majorIdxBase = blockIdx.z * p.loopMajor; if (tileOutXBase >= p.outW | tileOutY >= p.outH | majorIdxBase >= p.majorDim) return; // Load filter kernel (flipped). for (int tapIdx = threadIdx.x; tapIdx < kernelH * kernelW; tapIdx += blockDim.x) { int ky = tapIdx / kernelW; int kx = tapIdx - ky * kernelW; float v = 0.0f; if (kx < p.kernelW & ky < p.kernelH) v = (float)p.k[(p.kernelH - 1 - ky) * p.kernelW + (p.kernelW - 1 - kx)]; sk[ky][kx] = v; } // Loop over majorDim and outX. for (int loopMajor = 0, majorIdx = majorIdxBase; loopMajor < p.loopMajor & majorIdx < p.majorDim; loopMajor++, majorIdx++) for (int loopX = 0, tileOutX = tileOutXBase; loopX < p.loopX & tileOutX < p.outW; loopX++, tileOutX += tileOutW) { // Load input pixels. int tileMidX = tileOutX * downx + upx - 1 - p.padx0; int tileMidY = tileOutY * downy + upy - 1 - p.pady0; int tileInX = floorDiv(tileMidX, upx); int tileInY = floorDiv(tileMidY, upy); __syncthreads(); for (int inIdx = threadIdx.x; inIdx < tileInH * tileInW; inIdx += blockDim.x) { int relInY = inIdx / tileInW; int relInX = inIdx - relInY * tileInW; int inX = relInX + tileInX; int inY = relInY + tileInY; float v = 0.0f; if (inX >= 0 & inY >= 0 & inX < p.inW & inY < p.inH) v = (float)p.x[((majorIdx * p.inH + inY) * p.inW + inX) * p.minorDim + minorIdx]; sx[relInY][relInX] = v; } // Loop over output pixels. __syncthreads(); for (int outIdx = threadIdx.x; outIdx < tileOutH * tileOutW; outIdx += blockDim.x) { int relOutY = outIdx / tileOutW; int relOutX = outIdx - relOutY * tileOutW; int outX = relOutX + tileOutX; int outY = relOutY + tileOutY; // Setup receptive field. int midX = tileMidX + relOutX * downx; int midY = tileMidY + relOutY * downy; int inX = floorDiv(midX, upx); int inY = floorDiv(midY, upy); int relInX = inX - tileInX; int relInY = inY - tileInY; int kernelX = (inX + 1) * upx - midX - 1; // flipped int kernelY = (inY + 1) * upy - midY - 1; // flipped // Inner loop. float v = 0.0f; #pragma unroll for (int y = 0; y < kernelH / upy; y++) #pragma unroll for (int x = 0; x < kernelW / upx; x++) v += sx[relInY + y][relInX + x] * sk[kernelY + y * upy][kernelX + x * upx]; // Store result. if (outX < p.outW & outY < p.outH) p.y[((majorIdx * p.outH + outY) * p.outW + outX) * p.minorDim + minorIdx] = (T)v; } } } //------------------------------------------------------------------------ // TensorFlow op. template struct UpFirDn2DOp : public OpKernel { UpFirDn2DKernelParams m_attribs; UpFirDn2DOp(OpKernelConstruction* ctx) : OpKernel(ctx) { memset(&m_attribs, 0, sizeof(m_attribs)); OP_REQUIRES_OK(ctx, ctx->GetAttr("upx", &m_attribs.upx)); OP_REQUIRES_OK(ctx, ctx->GetAttr("upy", &m_attribs.upy)); OP_REQUIRES_OK(ctx, ctx->GetAttr("downx", &m_attribs.downx)); OP_REQUIRES_OK(ctx, ctx->GetAttr("downy", &m_attribs.downy)); OP_REQUIRES_OK(ctx, ctx->GetAttr("padx0", &m_attribs.padx0)); OP_REQUIRES_OK(ctx, ctx->GetAttr("padx1", &m_attribs.padx1)); OP_REQUIRES_OK(ctx, ctx->GetAttr("pady0", &m_attribs.pady0)); OP_REQUIRES_OK(ctx, ctx->GetAttr("pady1", &m_attribs.pady1)); OP_REQUIRES(ctx, m_attribs.upx >= 1 && m_attribs.upy >= 1, errors::InvalidArgument("upx and upy must be at least 1x1")); OP_REQUIRES(ctx, m_attribs.downx >= 1 && m_attribs.downy >= 1, errors::InvalidArgument("downx and downy must be at least 1x1")); } void Compute(OpKernelContext* ctx) { UpFirDn2DKernelParams p = m_attribs; cudaStream_t stream = ctx->eigen_device().stream(); const Tensor& x = ctx->input(0); // [majorDim, inH, inW, minorDim] const Tensor& k = ctx->input(1); // [kernelH, kernelW] p.x = x.flat().data(); p.k = k.flat().data(); OP_REQUIRES(ctx, x.dims() == 4, errors::InvalidArgument("input must have rank 4")); OP_REQUIRES(ctx, k.dims() == 2, errors::InvalidArgument("kernel must have rank 2")); OP_REQUIRES(ctx, x.NumElements() <= kint32max, errors::InvalidArgument("input too large")); OP_REQUIRES(ctx, k.NumElements() <= kint32max, errors::InvalidArgument("kernel too large")); p.majorDim = (int)x.dim_size(0); p.inH = (int)x.dim_size(1); p.inW = (int)x.dim_size(2); p.minorDim = (int)x.dim_size(3); p.kernelH = (int)k.dim_size(0); p.kernelW = (int)k.dim_size(1); OP_REQUIRES(ctx, p.kernelW >= 1 && p.kernelH >= 1, errors::InvalidArgument("kernel must be at least 1x1")); p.outW = (p.inW * p.upx + p.padx0 + p.padx1 - p.kernelW + p.downx) / p.downx; p.outH = (p.inH * p.upy + p.pady0 + p.pady1 - p.kernelH + p.downy) / p.downy; OP_REQUIRES(ctx, p.outW >= 1 && p.outH >= 1, errors::InvalidArgument("output must be at least 1x1")); Tensor* y = NULL; // [majorDim, outH, outW, minorDim] TensorShape ys; ys.AddDim(p.majorDim); ys.AddDim(p.outH); ys.AddDim(p.outW); ys.AddDim(p.minorDim); OP_REQUIRES_OK(ctx, ctx->allocate_output(0, ys, &y)); p.y = y->flat().data(); OP_REQUIRES(ctx, y->NumElements() <= kint32max, errors::InvalidArgument("output too large")); // Choose CUDA kernel to use. void* cudaKernel = (void*)UpFirDn2DKernel_large; int tileOutW = -1; int tileOutH = -1; if (p.upx == 1 && p.upy == 1 && p.downx == 1 && p.downy == 1 && p.kernelW <= 7 && p.kernelH <= 7) { cudaKernel = (void*)UpFirDn2DKernel_small; tileOutW = 64; tileOutH = 16; } if (p.upx == 1 && p.upy == 1 && p.downx == 1 && p.downy == 1 && p.kernelW <= 6 && p.kernelH <= 6) { cudaKernel = (void*)UpFirDn2DKernel_small; tileOutW = 64; tileOutH = 16; } if (p.upx == 1 && p.upy == 1 && p.downx == 1 && p.downy == 1 && p.kernelW <= 5 && p.kernelH <= 5) { cudaKernel = (void*)UpFirDn2DKernel_small; tileOutW = 64; tileOutH = 16; } if (p.upx == 1 && p.upy == 1 && p.downx == 1 && p.downy == 1 && p.kernelW <= 4 && p.kernelH <= 4) { cudaKernel = (void*)UpFirDn2DKernel_small; tileOutW = 64; tileOutH = 16; } if (p.upx == 1 && p.upy == 1 && p.downx == 1 && p.downy == 1 && p.kernelW <= 3 && p.kernelH <= 3) { cudaKernel = (void*)UpFirDn2DKernel_small; tileOutW = 64; tileOutH = 16; } if (p.upx == 2 && p.upy == 2 && p.downx == 1 && p.downy == 1 && p.kernelW <= 8 && p.kernelH <= 8) { cudaKernel = (void*)UpFirDn2DKernel_small; tileOutW = 64; tileOutH = 16; } if (p.upx == 2 && p.upy == 2 && p.downx == 1 && p.downy == 1 && p.kernelW <= 6 && p.kernelH <= 6) { cudaKernel = (void*)UpFirDn2DKernel_small; tileOutW = 64; tileOutH = 16; } if (p.upx == 2 && p.upy == 2 && p.downx == 1 && p.downy == 1 && p.kernelW <= 4 && p.kernelH <= 4) { cudaKernel = (void*)UpFirDn2DKernel_small; tileOutW = 64; tileOutH = 16; } if (p.upx == 2 && p.upy == 2 && p.downx == 1 && p.downy == 1 && p.kernelW <= 2 && p.kernelH <= 2) { cudaKernel = (void*)UpFirDn2DKernel_small; tileOutW = 64; tileOutH = 16; } if (p.upx == 1 && p.upy == 1 && p.downx == 2 && p.downy == 2 && p.kernelW <= 8 && p.kernelH <= 8) { cudaKernel = (void*)UpFirDn2DKernel_small; tileOutW = 32; tileOutH = 8; } if (p.upx == 1 && p.upy == 1 && p.downx == 2 && p.downy == 2 && p.kernelW <= 6 && p.kernelH <= 6) { cudaKernel = (void*)UpFirDn2DKernel_small; tileOutW = 32; tileOutH = 8; } if (p.upx == 1 && p.upy == 1 && p.downx == 2 && p.downy == 2 && p.kernelW <= 4 && p.kernelH <= 4) { cudaKernel = (void*)UpFirDn2DKernel_small; tileOutW = 32; tileOutH = 8; } if (p.upx == 1 && p.upy == 1 && p.downx == 2 && p.downy == 2 && p.kernelW <= 2 && p.kernelH <= 2) { cudaKernel = (void*)UpFirDn2DKernel_small; tileOutW = 32; tileOutH = 8; } // Choose launch params. dim3 blockSize; dim3 gridSize; if (tileOutW > 0 && tileOutH > 0) // small { p.loopMajor = (p.majorDim - 1) / 16384 + 1; p.loopX = 1; blockSize = dim3(32 * 8, 1, 1); gridSize = dim3(((p.outH - 1) / tileOutH + 1) * p.minorDim, (p.outW - 1) / (p.loopX * tileOutW) + 1, (p.majorDim - 1) / p.loopMajor + 1); } else // large { p.loopMajor = (p.majorDim - 1) / 16384 + 1; p.loopX = 4; blockSize = dim3(4, 32, 1); gridSize = dim3((p.outH * p.minorDim - 1) / blockSize.x + 1, (p.outW - 1) / (p.loopX * blockSize.y) + 1, (p.majorDim - 1) / p.loopMajor + 1); } // Launch CUDA kernel. void* args[] = {&p}; OP_CHECK_CUDA_ERROR(ctx, cudaLaunchKernel(cudaKernel, gridSize, blockSize, args, 0, stream)); } }; REGISTER_OP("UpFirDn2D") .Input ("x: T") .Input ("k: T") .Output ("y: T") .Attr ("T: {float, half}") .Attr ("upx: int = 1") .Attr ("upy: int = 1") .Attr ("downx: int = 1") .Attr ("downy: int = 1") .Attr ("padx0: int = 0") .Attr ("padx1: int = 0") .Attr ("pady0: int = 0") .Attr ("pady1: int = 0"); REGISTER_KERNEL_BUILDER(Name("UpFirDn2D").Device(DEVICE_GPU).TypeConstraint("T"), UpFirDn2DOp); REGISTER_KERNEL_BUILDER(Name("UpFirDn2D").Device(DEVICE_GPU).TypeConstraint("T"), UpFirDn2DOp); //------------------------------------------------------------------------ ================================================ FILE: stylegan2-tpu/dnnlib/tflib/ops/upfirdn_2d.py ================================================ # Copyright (c) 2019, NVIDIA Corporation. All rights reserved. # # This work is made available under the Nvidia Source Code License-NC. # To view a copy of this license, visit # https://nvlabs.github.io/stylegan2/license.html """Custom TensorFlow ops for efficient resampling of 2D images.""" import os import numpy as np import tensorflow as tf from .. import custom_ops def _get_plugin(): return custom_ops.get_plugin(os.path.splitext(__file__)[0] + '.cu') #---------------------------------------------------------------------------- def upfirdn_2d(x, k, upx=1, upy=1, downx=1, downy=1, padx0=0, padx1=0, pady0=0, pady1=0, impl='cuda'): r"""Pad, upsample, FIR filter, and downsample a batch of 2D images. Accepts a batch of 2D images of the shape `[majorDim, inH, inW, minorDim]` and performs the following operations for each image, batched across `majorDim` and `minorDim`: 1. Pad the image with zeros by the specified number of pixels on each side (`padx0`, `padx1`, `pady0`, `pady1`). Specifying a negative value corresponds to cropping the image. 2. Upsample the image by inserting the zeros after each pixel (`upx`, `upy`). 3. Convolve the image with the specified 2D FIR filter (`k`), shrinking the image so that the footprint of all output pixels lies within the input image. 4. Downsample the image by throwing away pixels (`downx`, `downy`). This sequence of operations bears close resemblance to scipy.signal.upfirdn(). The fused op is considerably more efficient than performing the same calculation using standard TensorFlow ops. It supports gradients of arbitrary order. Args: x: Input tensor of the shape `[majorDim, inH, inW, minorDim]`. k: 2D FIR filter of the shape `[firH, firW]`. upx: Integer upsampling factor along the X-axis (default: 1). upy: Integer upsampling factor along the Y-axis (default: 1). downx: Integer downsampling factor along the X-axis (default: 1). downy: Integer downsampling factor along the Y-axis (default: 1). padx0: Number of pixels to pad on the left side (default: 0). padx1: Number of pixels to pad on the right side (default: 0). pady0: Number of pixels to pad on the top side (default: 0). pady1: Number of pixels to pad on the bottom side (default: 0). impl: Name of the implementation to use. Can be `"ref"` or `"cuda"` (default). Returns: Tensor of the shape `[majorDim, outH, outW, minorDim]`, and same datatype as `x`. """ impl_dict = { 'ref': _upfirdn_2d_ref, 'cuda': _upfirdn_2d_ref if 'TPU_NAME' in os.environ or 'NO_NVCC' in os.environ else _upfirdn_2d_cuda, } return impl_dict[impl](x=x, k=k, upx=upx, upy=upy, downx=downx, downy=downy, padx0=padx0, padx1=padx1, pady0=pady0, pady1=pady1) #---------------------------------------------------------------------------- def _upfirdn_2d_ref(x, k, upx, upy, downx, downy, padx0, padx1, pady0, pady1): """Slow reference implementation of `upfirdn_2d()` using standard TensorFlow ops.""" x = tf.convert_to_tensor(x) k = np.asarray(k, dtype=np.float32) assert x.shape.rank == 4 inH = x.shape[1].value inW = x.shape[2].value minorDim = _shape(x, 3) kernelH, kernelW = k.shape assert inW >= 1 and inH >= 1 assert kernelW >= 1 and kernelH >= 1 assert isinstance(upx, int) and isinstance(upy, int) assert isinstance(downx, int) and isinstance(downy, int) assert isinstance(padx0, int) and isinstance(padx1, int) assert isinstance(pady0, int) and isinstance(pady1, int) # Upsample (insert zeros). x = tf.reshape(x, [-1, inH, 1, inW, 1, minorDim]) x = tf.pad(x, [[0, 0], [0, 0], [0, upy - 1], [0, 0], [0, upx - 1], [0, 0]]) x = tf.reshape(x, [-1, inH * upy, inW * upx, minorDim]) # Pad (crop if negative). x = tf.pad(x, [[0, 0], [max(pady0, 0), max(pady1, 0)], [max(padx0, 0), max(padx1, 0)], [0, 0]]) x = x[:, max(-pady0, 0) : x.shape[1].value - max(-pady1, 0), max(-padx0, 0) : x.shape[2].value - max(-padx1, 0), :] # Convolve with filter. x = tf.transpose(x, [0, 3, 1, 2]) x = tf.reshape(x, [-1, 1, inH * upy + pady0 + pady1, inW * upx + padx0 + padx1]) w = tf.constant(k[::-1, ::-1, np.newaxis, np.newaxis], dtype=x.dtype) x = tf.nn.conv2d(x, w, strides=[1,1,1,1], padding='VALID', data_format='NCHW') x = tf.reshape(x, [-1, minorDim, inH * upy + pady0 + pady1 - kernelH + 1, inW * upx + padx0 + padx1 - kernelW + 1]) x = tf.transpose(x, [0, 2, 3, 1]) # Downsample (throw away pixels). return x[:, ::downy, ::downx, :] #---------------------------------------------------------------------------- def _upfirdn_2d_cuda(x, k, upx, upy, downx, downy, padx0, padx1, pady0, pady1): """Fast CUDA implementation of `upfirdn_2d()` using custom ops.""" x = tf.convert_to_tensor(x) k = np.asarray(k, dtype=np.float32) majorDim, inH, inW, minorDim = x.shape.as_list() kernelH, kernelW = k.shape assert inW >= 1 and inH >= 1 assert kernelW >= 1 and kernelH >= 1 assert isinstance(upx, int) and isinstance(upy, int) assert isinstance(downx, int) and isinstance(downy, int) assert isinstance(padx0, int) and isinstance(padx1, int) assert isinstance(pady0, int) and isinstance(pady1, int) outW = (inW * upx + padx0 + padx1 - kernelW) // downx + 1 outH = (inH * upy + pady0 + pady1 - kernelH) // downy + 1 assert outW >= 1 and outH >= 1 kc = tf.constant(k, dtype=x.dtype) gkc = tf.constant(k[::-1, ::-1], dtype=x.dtype) gpadx0 = kernelW - padx0 - 1 gpady0 = kernelH - pady0 - 1 gpadx1 = inW * upx - outW * downx + padx0 - upx + 1 gpady1 = inH * upy - outH * downy + pady0 - upy + 1 @tf.custom_gradient def func(x): y = _get_plugin().up_fir_dn2d(x=x, k=kc, upx=upx, upy=upy, downx=downx, downy=downy, padx0=padx0, padx1=padx1, pady0=pady0, pady1=pady1) y.set_shape([majorDim, outH, outW, minorDim]) @tf.custom_gradient def grad(dy): dx = _get_plugin().up_fir_dn2d(x=dy, k=gkc, upx=downx, upy=downy, downx=upx, downy=upy, padx0=gpadx0, padx1=gpadx1, pady0=gpady0, pady1=gpady1) dx.set_shape([majorDim, inH, inW, minorDim]) return dx, func return y, grad return func(x) #---------------------------------------------------------------------------- def filter_2d(x, k, gain=1, data_format='NCHW', impl='cuda'): r"""Filter a batch of 2D images with the given FIR filter. Accepts a batch of 2D images of the shape `[N, C, H, W]` or `[N, H, W, C]` and filters each image with the given filter. The filter is normalized so that if the input pixels are constant, they will be scaled by the specified `gain`. Pixels outside the image are assumed to be zero. Args: x: Input tensor of the shape `[N, C, H, W]` or `[N, H, W, C]`. k: FIR filter of the shape `[firH, firW]` or `[firN]` (separable). gain: Scaling factor for signal magnitude (default: 1.0). data_format: `'NCHW'` or `'NHWC'` (default: `'NCHW'`). impl: Name of the implementation to use. Can be `"ref"` or `"cuda"` (default). Returns: Tensor of the same shape and datatype as `x`. """ k = _setup_kernel(k) * gain p = k.shape[0] - 1 return _simple_upfirdn_2d(x, k, pad0=(p+1)//2, pad1=p//2, data_format=data_format, impl=impl) #---------------------------------------------------------------------------- def upsample_2d(x, k=None, factor=2, gain=1, data_format='NCHW', impl='cuda'): r"""Upsample a batch of 2D images with the given filter. Accepts a batch of 2D images of the shape `[N, C, H, W]` or `[N, H, W, C]` and upsamples each image with the given filter. The filter is normalized so that if the input pixels are constant, they will be scaled by the specified `gain`. Pixels outside the image are assumed to be zero, and the filter is padded with zeros so that its shape is a multiple of the upsampling factor. Args: x: Input tensor of the shape `[N, C, H, W]` or `[N, H, W, C]`. k: FIR filter of the shape `[firH, firW]` or `[firN]` (separable). The default is `[1] * factor`, which corresponds to nearest-neighbor upsampling. factor: Integer upsampling factor (default: 2). gain: Scaling factor for signal magnitude (default: 1.0). data_format: `'NCHW'` or `'NHWC'` (default: `'NCHW'`). impl: Name of the implementation to use. Can be `"ref"` or `"cuda"` (default). Returns: Tensor of the shape `[N, C, H * factor, W * factor]` or `[N, H * factor, W * factor, C]`, and same datatype as `x`. """ assert isinstance(factor, int) and factor >= 1 if k is None: k = [1] * factor k = _setup_kernel(k) * (gain * (factor ** 2)) p = k.shape[0] - factor return _simple_upfirdn_2d(x, k, up=factor, pad0=(p+1)//2+factor-1, pad1=p//2, data_format=data_format, impl=impl) #---------------------------------------------------------------------------- def downsample_2d(x, k=None, factor=2, gain=1, data_format='NCHW', impl='cuda'): r"""Downsample a batch of 2D images with the given filter. Accepts a batch of 2D images of the shape `[N, C, H, W]` or `[N, H, W, C]` and downsamples each image with the given filter. The filter is normalized so that if the input pixels are constant, they will be scaled by the specified `gain`. Pixels outside the image are assumed to be zero, and the filter is padded with zeros so that its shape is a multiple of the downsampling factor. Args: x: Input tensor of the shape `[N, C, H, W]` or `[N, H, W, C]`. k: FIR filter of the shape `[firH, firW]` or `[firN]` (separable). The default is `[1] * factor`, which corresponds to average pooling. factor: Integer downsampling factor (default: 2). gain: Scaling factor for signal magnitude (default: 1.0). data_format: `'NCHW'` or `'NHWC'` (default: `'NCHW'`). impl: Name of the implementation to use. Can be `"ref"` or `"cuda"` (default). Returns: Tensor of the shape `[N, C, H // factor, W // factor]` or `[N, H // factor, W // factor, C]`, and same datatype as `x`. """ assert isinstance(factor, int) and factor >= 1 if k is None: k = [1] * factor k = _setup_kernel(k) * gain p = k.shape[0] - factor return _simple_upfirdn_2d(x, k, down=factor, pad0=(p+1)//2, pad1=p//2, data_format=data_format, impl=impl) #---------------------------------------------------------------------------- def upsample_conv_2d(x, w, k=None, factor=2, gain=1, data_format='NCHW', impl='cuda'): r"""Fused `upsample_2d()` followed by `tf.nn.conv2d()`. Padding is performed only once at the beginning, not between the operations. The fused op is considerably more efficient than performing the same calculation using standard TensorFlow ops. It supports gradients of arbitrary order. Args: x: Input tensor of the shape `[N, C, H, W]` or `[N, H, W, C]`. w: Weight tensor of the shape `[filterH, filterW, inChannels, outChannels]`. Grouped convolution can be performed by `inChannels = x.shape[0] // numGroups`. k: FIR filter of the shape `[firH, firW]` or `[firN]` (separable). The default is `[1] * factor`, which corresponds to nearest-neighbor upsampling. factor: Integer upsampling factor (default: 2). gain: Scaling factor for signal magnitude (default: 1.0). data_format: `'NCHW'` or `'NHWC'` (default: `'NCHW'`). impl: Name of the implementation to use. Can be `"ref"` or `"cuda"` (default). Returns: Tensor of the shape `[N, C, H * factor, W * factor]` or `[N, H * factor, W * factor, C]`, and same datatype as `x`. """ assert isinstance(factor, int) and factor >= 1 # Check weight shape. w = tf.convert_to_tensor(w) assert w.shape.rank == 4 convH = w.shape[0].value convW = w.shape[1].value inC = _shape(w, 2) outC = _shape(w, 3) assert convW == convH # Setup filter kernel. if k is None: k = [1] * factor k = _setup_kernel(k) * (gain * (factor ** 2)) p = (k.shape[0] - factor) - (convW - 1) # Determine data dimensions. if data_format == 'NCHW': stride = [1, 1, factor, factor] output_shape = [_shape(x, 0), outC, (_shape(x, 2) - 1) * factor + convH, (_shape(x, 3) - 1) * factor + convW] num_groups = _shape(x, 1) // inC else: stride = [1, factor, factor, 1] output_shape = [_shape(x, 0), (_shape(x, 1) - 1) * factor + convH, (_shape(x, 2) - 1) * factor + convW, outC] num_groups = _shape(x, 3) // inC # Transpose weights. w = tf.reshape(w, [convH, convW, inC, num_groups, -1]) w = tf.transpose(w[::-1, ::-1], [0, 1, 4, 3, 2]) w = tf.reshape(w, [convH, convW, -1, num_groups * inC]) # Execute. x = tf.nn.conv2d_transpose(x, w, output_shape=output_shape, strides=stride, padding='VALID', data_format=data_format) return _simple_upfirdn_2d(x, k, pad0=(p+1)//2+factor-1, pad1=p//2+1, data_format=data_format, impl=impl) #---------------------------------------------------------------------------- def conv_downsample_2d(x, w, k=None, factor=2, gain=1, data_format='NCHW', impl='cuda'): r"""Fused `tf.nn.conv2d()` followed by `downsample_2d()`. Padding is performed only once at the beginning, not between the operations. The fused op is considerably more efficient than performing the same calculation using standard TensorFlow ops. It supports gradients of arbitrary order. Args: x: Input tensor of the shape `[N, C, H, W]` or `[N, H, W, C]`. w: Weight tensor of the shape `[filterH, filterW, inChannels, outChannels]`. Grouped convolution can be performed by `inChannels = x.shape[0] // numGroups`. k: FIR filter of the shape `[firH, firW]` or `[firN]` (separable). The default is `[1] * factor`, which corresponds to average pooling. factor: Integer downsampling factor (default: 2). gain: Scaling factor for signal magnitude (default: 1.0). data_format: `'NCHW'` or `'NHWC'` (default: `'NCHW'`). impl: Name of the implementation to use. Can be `"ref"` or `"cuda"` (default). Returns: Tensor of the shape `[N, C, H // factor, W // factor]` or `[N, H // factor, W // factor, C]`, and same datatype as `x`. """ assert isinstance(factor, int) and factor >= 1 w = tf.convert_to_tensor(w) convH, convW, _inC, _outC = w.shape.as_list() assert convW == convH if k is None: k = [1] * factor k = _setup_kernel(k) * gain p = (k.shape[0] - factor) + (convW - 1) if data_format == 'NCHW': s = [1, 1, factor, factor] else: s = [1, factor, factor, 1] x = _simple_upfirdn_2d(x, k, pad0=(p+1)//2, pad1=p//2, data_format=data_format, impl=impl) return tf.nn.conv2d(x, w, strides=s, padding='VALID', data_format=data_format) #---------------------------------------------------------------------------- # Internal helper funcs. def _shape(tf_expr, dim_idx): if tf_expr.shape.rank is not None: dim = tf_expr.shape[dim_idx].value if dim is not None: return dim return tf.shape(tf_expr)[dim_idx] def _setup_kernel(k): k = np.asarray(k, dtype=np.float32) if k.ndim == 1: k = np.outer(k, k) k /= np.sum(k) assert k.ndim == 2 assert k.shape[0] == k.shape[1] return k def _simple_upfirdn_2d(x, k, up=1, down=1, pad0=0, pad1=0, data_format='NCHW', impl='cuda'): assert data_format in ['NCHW', 'NHWC'] assert x.shape.rank == 4 y = x if data_format == 'NCHW': y = tf.reshape(y, [-1, _shape(y, 2), _shape(y, 3), 1]) y = upfirdn_2d(y, k, upx=up, upy=up, downx=down, downy=down, padx0=pad0, padx1=pad1, pady0=pad0, pady1=pad1, impl=impl) if data_format == 'NCHW': y = tf.reshape(y, [-1, _shape(x, 1), _shape(y, 1), _shape(y, 2)]) return y #---------------------------------------------------------------------------- ================================================ FILE: stylegan2-tpu/dnnlib/tflib/optimizer.py ================================================ # Copyright (c) 2019, NVIDIA Corporation. All rights reserved. # # This work is made available under the Nvidia Source Code License-NC. # To view a copy of this license, visit # https://nvlabs.github.io/stylegan2/license.html """Helper wrapper for a Tensorflow optimizer.""" import numpy as np import tensorflow as tf import tflex from collections import OrderedDict from typing import List, Union from . import autosummary from . import tfutil from .. import util from .tfutil import TfExpression, TfExpressionEx try: # TensorFlow 1.13 from tensorflow.python.ops import nccl_ops except: # Older TensorFlow versions import tensorflow.contrib.nccl as nccl_ops from tensorflow.python.framework import ops as tf_ops def all_sum_plain(g, colocate=False, *args, **kws): r = [] for i in range(len(g)): if colocate: with tf_ops.colocate_with(g[i]): r.append(tf.add_n(g)) else: r.append(tf.add_n(g)) return r try: # TensorFlow 1.13 from tensorflow.python.ops import nccl_ops except: # Older TensorFlow versions import tensorflow.contrib.nccl as nccl_ops def all_sum_gpu(g, *args, **kws): return nccl_ops.all_sum(g, *args, **kws) from tensorflow.python.tpu.ops import tpu_ops #def all_sum_tpu(g, *args, **kws): # g = tpu_ops.cross_replica_sum(g, *args, **kws) # return [g[i] for i in range(shape_list(g)[0])] def all_sum_tpu(g, colocate=True, *args, **kws): #import pdb #pdb.set_trace() #r = tf.reduce_sum(g) #r = tf.reduce_sum(tf.stack(g), axis=0, keepdims=True) #r = tpu_ops.cross_replica_sum(g, *args, **kws) #r = [r[i] for i in range(shape_list(r)[0])] return all_sum_plain(g, colocate=colocate, *args, **kws) def all_sum(cores, g, colocate=True, *args, **kws): if any([':TPU:' in x for x in cores.keys()]): return all_sum_tpu(g, colocate=colocate, *args, **kws) elif any([':GPU:' in x for x in cores.keys()]): return all_sum_gpu(g, *args, **kws) else: return all_sum_cpu(g, *args, **kws) class Optimizer: """A Wrapper for tf.train.Optimizer. Automatically takes care of: - Gradient averaging for multi-GPU training. - Gradient accumulation for arbitrarily large minibatches. - Dynamic loss scaling and typecasts for FP16 training. - Ignoring corrupted gradients that contain NaNs/Infs. - Reporting statistics. - Well-chosen default settings. """ def __init__(self, name: str = "Train", # Name string that will appear in TensorFlow graph. tf_optimizer: str = "tf.train.AdamOptimizer", # Underlying optimizer class. learning_rate: TfExpressionEx = 0.001, # Learning rate. Can vary over time. minibatch_multiplier: TfExpressionEx = None, # Treat N consecutive minibatches as one by accumulating gradients. share: "Optimizer" = None, # Share internal state with a previously created optimizer? use_loss_scaling: bool = False, # Enable dynamic loss scaling for robust mixed-precision training? loss_scaling_init: float = 64.0, # Log2 of initial loss scaling factor. loss_scaling_inc: float = 0.0005, # Log2 of per-minibatch loss scaling increment when there is no overflow. loss_scaling_dec: float = 1.0, # Log2 of per-minibatch loss scaling decrement when there is an overflow. report_mem_usage: bool = False, # Report fine-grained memory usage statistics in TensorBoard? cross_shard: bool = False, # Use CrossShardOptimizer? **kwargs): # Public fields. self.name = name self.learning_rate = learning_rate self.minibatch_multiplier = minibatch_multiplier self.id = self.name.replace("/", ".") self.scope = tf.get_default_graph().unique_name(self.id) self.optimizer_class = util.get_obj_by_name(tf_optimizer) self.optimizer_kwargs = dict(kwargs) self.use_loss_scaling = use_loss_scaling self.loss_scaling_init = loss_scaling_init self.loss_scaling_inc = loss_scaling_inc self.loss_scaling_dec = loss_scaling_dec # Private fields. self._updates_applied = False self._devices = OrderedDict() # device_name => EasyDict() self._shared_optimizers = OrderedDict() # device_name => optimizer_class self._gradient_shapes = None # [shape, ...] self._report_mem_usage = report_mem_usage self._cross_shard = cross_shard # Validate arguments. assert callable(self.optimizer_class) # Share internal state if requested. if share is not None: assert isinstance(share, Optimizer) assert self.optimizer_class is share.optimizer_class assert self.learning_rate is share.learning_rate assert self.optimizer_kwargs == share.optimizer_kwargs self._shared_optimizers = share._shared_optimizers # pylint: disable=protected-access def _get_device(self, device_name: str): """Get internal state for the given TensorFlow device.""" tfutil.assert_tf_initialized() if device_name in self._devices: return self._devices[device_name] # Initialize fields. device = util.EasyDict() device.name = device_name device.optimizer = None # Underlying optimizer: optimizer_class device.loss_scaling_var = None # Log2 of loss scaling: tf.Variable device.grad_raw = OrderedDict() # Raw gradients: var => [grad, ...] device.grad_clean = OrderedDict() # Clean gradients: var => grad device.grad_acc_vars = OrderedDict() # Accumulation sums: var => tf.Variable device.grad_acc_count = None # Accumulation counter: tf.Variable device.grad_acc = OrderedDict() # Accumulated gradients: var => grad # Setup TensorFlow objects. with tfutil.absolute_name_scope(self.scope + "/Devices"), tflex.device(device_name), tf.control_dependencies(None): if device_name not in self._shared_optimizers: optimizer_name = self.scope.replace("/", "_") + "_opt%d" % len(self._shared_optimizers) self._shared_optimizers[device_name] = self.optimizer_class(name=optimizer_name, learning_rate=self.learning_rate, **self.optimizer_kwargs) if self._cross_shard or 'TPU_REPLICATED_CORE' in device_name: print('Using cross-shard optimizer for %s' % device_name) self._shared_optimizers[device_name] = tf.contrib.tpu.CrossShardOptimizer(self._shared_optimizers[device_name]) device.optimizer = self._shared_optimizers[device_name] if self.use_loss_scaling: device.loss_scaling_var = tf.Variable(np.float32(self.loss_scaling_init), trainable=False, name="loss_scaling_var") # Register device. self._devices[device_name] = device return device def register_gradients(self, loss: TfExpression, trainable_vars: Union[List, dict]) -> None: """Register the gradients of the given loss function with respect to the given variables. Intended to be called once per GPU.""" tfutil.assert_tf_initialized() assert not self._updates_applied device = self._get_device(loss.device) # Validate trainables. if isinstance(trainable_vars, dict): trainable_vars = list(trainable_vars.values()) # allow passing in Network.trainables as vars assert isinstance(trainable_vars, list) and len(trainable_vars) >= 1 assert all(tfutil.is_tf_expression(expr) for expr in trainable_vars + [loss]) assert all(var.device == device.name for var in trainable_vars) # Validate shapes. if self._gradient_shapes is None: self._gradient_shapes = [var.shape.as_list() for var in trainable_vars] assert len(trainable_vars) == len(self._gradient_shapes) assert all(var.shape.as_list() == var_shape for var, var_shape in zip(trainable_vars, self._gradient_shapes)) # Report memory usage if requested. deps = [] if self._report_mem_usage: self._report_mem_usage = False try: with tf.name_scope(self.id + '_mem'), tflex.device(device.name), tf.control_dependencies([loss]): deps.append(autosummary.autosummary(self.id + "/mem_usage_gb", tf.contrib.memory_stats.BytesInUse() / 2**30)) except tf.errors.NotFoundError: pass # Compute gradients. with tf.name_scope(self.id + "_grad"), tflex.device(device.name), tf.control_dependencies(deps): loss = self.apply_loss_scaling(tf.cast(loss, tf.float32)) gate = tf.train.Optimizer.GATE_NONE # disable gating to reduce memory usage grad_list = device.optimizer.compute_gradients(loss=loss, var_list=trainable_vars, gate_gradients=gate) # Register gradients. for grad, var in grad_list: if var not in device.grad_raw: device.grad_raw[var] = [] device.grad_raw[var].append(grad) def apply_updates(self, allow_no_op: bool = False) -> tf.Operation: """Construct training op to update the registered variables based on their gradients.""" tfutil.assert_tf_initialized() assert not self._updates_applied self._updates_applied = True all_ops = [] # Check for no-op. if allow_no_op and len(self._devices) == 0: with tfutil.absolute_name_scope(self.scope): return tf.no_op(name='TrainingOp') # Clean up gradients. for device_idx, device in enumerate(self._devices.values()): with tfutil.absolute_name_scope(self.scope + "/Clean%d" % device_idx), tflex.device(device.name): for var, grad in device.grad_raw.items(): # Filter out disconnected gradients and convert to float32. grad = [g for g in grad if g is not None] grad = [tf.cast(g, tf.float32) for g in grad] # Sum within the device. if len(grad) == 0: grad = tf.zeros(var.shape) # No gradients => zero. elif len(grad) == 1: grad = grad[0] # Single gradient => use as is. else: grad = tf.add_n(grad) # Multiple gradients => sum. # Scale as needed. scale = 1.0 / len(device.grad_raw[var]) / len(self._devices) scale = tf.constant(scale, dtype=tf.float32, name="scale") if self.minibatch_multiplier is not None: scale /= tf.cast(self.minibatch_multiplier, tf.float32) scale = self.undo_loss_scaling(scale) device.grad_clean[var] = grad * scale # Sum gradients across devices. if len(self._devices) > 1: with tfutil.absolute_name_scope(self.scope + "/Broadcast"), tflex.device(None): for all_vars in zip(*[device.grad_clean.keys() for device in self._devices.values()]): if len(all_vars) > 0 and all(dim > 0 for dim in all_vars[0].shape.as_list()): # NCCL does not support zero-sized tensors. all_grads = [device.grad_clean[var] for device, var in zip(self._devices.values(), all_vars)] all_grads = all_sum(self._devices, all_grads) for device, var, grad in zip(self._devices.values(), all_vars, all_grads): device.grad_clean[var] = grad # Apply updates separately on each device. for device_idx, device in enumerate(self._devices.values()): with tfutil.absolute_name_scope(self.scope + "/Apply%d" % device_idx), tflex.device(device.name): # pylint: disable=cell-var-from-loop # Accumulate gradients over time. if self.minibatch_multiplier is None: acc_ok = tf.constant(True, name='acc_ok') device.grad_acc = OrderedDict(device.grad_clean) else: # Create variables. with tf.control_dependencies(None): for var in device.grad_clean.keys(): device.grad_acc_vars[var] = tf.Variable(tf.zeros(var.shape), trainable=False, name="grad_acc_var") device.grad_acc_count = tf.Variable(tf.zeros([]), trainable=False, name="grad_acc_count") # Track counter. count_cur = device.grad_acc_count + 1.0 count_inc_op = lambda: tf.assign(device.grad_acc_count, count_cur) count_reset_op = lambda: tf.assign(device.grad_acc_count, tf.zeros([])) acc_ok = (count_cur >= tf.cast(self.minibatch_multiplier, tf.float32)) all_ops.append(tf.cond(acc_ok, count_reset_op, count_inc_op)) # Track gradients. for var, grad in device.grad_clean.items(): acc_var = device.grad_acc_vars[var] acc_cur = acc_var + grad device.grad_acc[var] = acc_cur with tf.control_dependencies([acc_cur]): acc_inc_op = lambda: tf.assign(acc_var, acc_cur) acc_reset_op = lambda: tf.assign(acc_var, tf.zeros(var.shape)) all_ops.append(tf.cond(acc_ok, acc_reset_op, acc_inc_op)) # No overflow => apply gradients. all_ok = tf.reduce_all(tf.stack([acc_ok] + [tf.reduce_all(tf.is_finite(g)) for g in device.grad_acc.values()])) apply_op = lambda: device.optimizer.apply_gradients([(tf.cast(grad, var.dtype), var) for var, grad in device.grad_acc.items()]) all_ops.append(tf.cond(all_ok, apply_op, tf.no_op)) # Adjust loss scaling. if self.use_loss_scaling: ls_inc_op = lambda: tf.assign_add(device.loss_scaling_var, self.loss_scaling_inc) ls_dec_op = lambda: tf.assign_sub(device.loss_scaling_var, self.loss_scaling_dec) ls_update_op = lambda: tf.group(tf.cond(all_ok, ls_inc_op, ls_dec_op)) all_ops.append(tf.cond(acc_ok, ls_update_op, tf.no_op)) # Last device => report statistics. if device_idx == len(self._devices) - 1: all_ops.append(autosummary.autosummary(self.id + "/learning_rate", self.learning_rate)) all_ops.append(autosummary.autosummary(self.id + "/overflow_frequency", tf.where(all_ok, 0, 1), condition=acc_ok)) if self.use_loss_scaling: all_ops.append(autosummary.autosummary(self.id + "/loss_scaling_log2", device.loss_scaling_var)) def finalize(): # Initialize variables. self.reset_optimizer_state() if self.use_loss_scaling: tfutil.init_uninitialized_vars([device.loss_scaling_var for device in self._devices.values()]) if self.minibatch_multiplier is not None: tfutil.run([var.initializer for device in self._devices.values() for var in list(device.grad_acc_vars.values()) + [device.grad_acc_count]]) # Group everything into a single op. with tfutil.absolute_name_scope(self.scope): return tf.group(*all_ops, name="TrainingOp"), finalize def reset_optimizer_state(self) -> None: """Reset internal state of the underlying optimizer.""" tfutil.assert_tf_initialized() tfutil.run([var.initializer for device in self._devices.values() for var in device.optimizer.variables()]) def get_loss_scaling_var(self, device: str) -> Union[tf.Variable, None]: """Get or create variable representing log2 of the current dynamic loss scaling factor.""" return self._get_device(device).loss_scaling_var def apply_loss_scaling(self, value: TfExpression) -> TfExpression: """Apply dynamic loss scaling for the given expression.""" assert tfutil.is_tf_expression(value) if not self.use_loss_scaling: return value return value * tfutil.exp2(self.get_loss_scaling_var(value.device)) def undo_loss_scaling(self, value: TfExpression) -> TfExpression: """Undo the effect of dynamic loss scaling for the given expression.""" assert tfutil.is_tf_expression(value) if not self.use_loss_scaling: return value return value * tfutil.exp2(-self.get_loss_scaling_var(value.device)) # pylint: disable=invalid-unary-operand-type class SimpleAdam: """Simplified version of tf.train.AdamOptimizer that behaves identically when used with dnnlib.tflib.Optimizer.""" def __init__(self, name="Adam", learning_rate=0.001, beta1=0.9, beta2=0.999, epsilon=1e-8): self.name = name self.learning_rate = learning_rate self.beta1 = beta1 self.beta2 = beta2 self.epsilon = epsilon self.all_state_vars = [] def variables(self): return self.all_state_vars def compute_gradients(self, loss, var_list, gate_gradients=tf.train.Optimizer.GATE_NONE): assert gate_gradients == tf.train.Optimizer.GATE_NONE return list(zip(tf.gradients(loss, var_list), var_list)) def apply_gradients(self, grads_and_vars): with tf.name_scope(self.name): state_vars = [] update_ops = [] # Adjust learning rate to deal with startup bias. with tf.control_dependencies(None): b1pow_var = tf.Variable(dtype=tf.float32, initial_value=1, trainable=False) b2pow_var = tf.Variable(dtype=tf.float32, initial_value=1, trainable=False) state_vars += [b1pow_var, b2pow_var] b1pow_new = b1pow_var * self.beta1 b2pow_new = b2pow_var * self.beta2 update_ops += [tf.assign(b1pow_var, b1pow_new), tf.assign(b2pow_var, b2pow_new)] lr_new = self.learning_rate * tf.sqrt(1 - b2pow_new) / (1 - b1pow_new) # Construct ops to update each variable. for grad, var in grads_and_vars: with tf.control_dependencies(None): m_var = tf.Variable(dtype=tf.float32, initial_value=tf.zeros_like(var), trainable=False) v_var = tf.Variable(dtype=tf.float32, initial_value=tf.zeros_like(var), trainable=False) state_vars += [m_var, v_var] m_new = self.beta1 * m_var + (1 - self.beta1) * grad v_new = self.beta2 * v_var + (1 - self.beta2) * tf.square(grad) var_delta = lr_new * m_new / (tf.sqrt(v_new) + self.epsilon) update_ops += [tf.assign(m_var, m_new), tf.assign(v_var, v_new), tf.assign_sub(var, var_delta)] # Group everything together. self.all_state_vars += state_vars return tf.group(*update_ops) ================================================ FILE: stylegan2-tpu/dnnlib/tflib/tfutil.py ================================================ # Copyright (c) 2019, NVIDIA Corporation. All rights reserved. # # This work is made available under the Nvidia Source Code License-NC. # To view a copy of this license, visit # https://nvlabs.github.io/stylegan2/license.html """Miscellaneous helper utils for Tensorflow.""" import os import numpy as np import tensorflow as tf import tflex # Silence deprecation warnings from TensorFlow 1.13 onwards import logging logging.getLogger('tensorflow').setLevel(logging.ERROR) import tensorflow.contrib # requires TensorFlow 1.x! tf.contrib = tensorflow.contrib from typing import Any, Iterable, List, Union TfExpression = Union[tf.Tensor, tf.Variable, tf.Operation] """A type that represents a valid Tensorflow expression.""" TfExpressionEx = Union[TfExpression, int, float, np.ndarray] """A type that can be converted to a valid Tensorflow expression.""" def run(*args, **kwargs) -> Any: """Run the specified ops in the default session.""" assert_tf_initialized() return tf.get_default_session().run(*args, **kwargs) def is_tf_expression(x: Any) -> bool: """Check whether the input is a valid Tensorflow expression, i.e., Tensorflow Tensor, Variable, or Operation.""" return isinstance(x, (tf.Tensor, tf.Variable, tf.Operation)) def shape_to_list(shape: Iterable[tf.Dimension]) -> List[Union[int, None]]: """Convert a Tensorflow shape to a list of ints. Retained for backwards compatibility -- use TensorShape.as_list() in new code.""" return [dim.value for dim in shape] def flatten(x: TfExpressionEx) -> TfExpression: """Shortcut function for flattening a tensor.""" with tf.name_scope("Flatten"): return tf.reshape(x, [-1]) def log2(x: TfExpressionEx) -> TfExpression: """Logarithm in base 2.""" with tf.name_scope("Log2"): return tf.log(x) * np.float32(1.0 / np.log(2.0)) def exp2(x: TfExpressionEx) -> TfExpression: """Exponent in base 2.""" with tf.name_scope("Exp2"): return tf.exp(x * np.float32(np.log(2.0))) def lerp(a: TfExpressionEx, b: TfExpressionEx, t: TfExpressionEx) -> TfExpressionEx: """Linear interpolation.""" with tf.name_scope("Lerp"): return a + (b - a) * t def lerp_clip(a: TfExpressionEx, b: TfExpressionEx, t: TfExpressionEx) -> TfExpression: """Linear interpolation with clip.""" with tf.name_scope("LerpClip"): return a + (b - a) * tf.clip_by_value(t, 0.0, 1.0) def absolute_name_scope(scope: str) -> tf.name_scope: """Forcefully enter the specified name scope, ignoring any surrounding scopes.""" return tf.name_scope(scope + "/") def absolute_variable_scope(scope: str, **kwargs) -> tf.variable_scope: """Forcefully enter the specified variable scope, ignoring any surrounding scopes.""" return tf.variable_scope(tf.VariableScope(name=scope, **kwargs), auxiliary_name_scope=False) def _sanitize_tf_config(config_dict: dict = None) -> dict: # Defaults. cfg = dict() cfg["rnd.np_random_seed"] = None # Random seed for NumPy. None = keep as is. cfg["rnd.tf_random_seed"] = "auto" # Random seed for TensorFlow. 'auto' = derive from NumPy random state. None = keep as is. cfg["env.TF_CPP_MIN_LOG_LEVEL"] = "1" # 0 = Print all available debug info from TensorFlow. 1 = Print warnings and errors, but disable debug info. cfg["graph_options.place_pruned_graph"] = True # False = Check that all ops are available on the designated device. True = Skip the check for ops that are not used. cfg["gpu_options.allow_growth"] = True # False = Allocate all GPU memory at the beginning. True = Allocate only as much GPU memory as needed. # Remove defaults for environment variables that are already set. for key in list(cfg): fields = key.split(".") if fields[0] == "env": assert len(fields) == 2 if fields[1] in os.environ: del cfg[key] # User overrides. if config_dict is not None: cfg.update(config_dict) return cfg def init_tf(config_dict: dict = None) -> None: """Initialize TensorFlow session using good default settings.""" # Skip if already initialized. if tf.get_default_session() is not None: return # Setup config dict and random seeds. cfg = _sanitize_tf_config(config_dict) np_random_seed = cfg["rnd.np_random_seed"] if np_random_seed is not None: np.random.seed(np_random_seed) tf_random_seed = cfg["rnd.tf_random_seed"] if tf_random_seed == "auto": tf_random_seed = np.random.randint(1 << 31) if tf_random_seed is not None: tf.set_random_seed(tf_random_seed) # Setup environment variables. for key, value in cfg.items(): fields = key.split(".") if fields[0] == "env": assert len(fields) == 2 os.environ[fields[1]] = str(value) # Create default TensorFlow session. create_session(cfg, force_as_default=True) def assert_tf_initialized(): """Check that TensorFlow session has been initialized.""" if tf.get_default_session() is None: raise RuntimeError("No default TensorFlow session found. Please call dnnlib.tflib.init_tf().") def create_session(config_dict: dict = None, force_as_default: bool = False) -> tf.Session: """Create tf.Session based on config dict.""" # Setup TensorFlow config proto. cfg = _sanitize_tf_config(config_dict) config_proto = tf.ConfigProto() for key, value in cfg.items(): fields = key.split(".") if fields[0] not in ["rnd", "env"]: obj = config_proto for field in fields[:-1]: obj = getattr(obj, field) setattr(obj, fields[-1], value) # Create session. config_proto.allow_soft_placement = True session = tflex.Session(config=config_proto) if force_as_default: # pylint: disable=protected-access session._default_session = session.as_default() session._default_session.enforce_nesting = False session._default_session.__enter__() return session def init_uninitialized_vars(target_vars: List[tf.Variable] = None) -> None: """Initialize all tf.Variables that have not already been initialized. Equivalent to the following, but more efficient and does not bloat the tf graph: tf.variables_initializer(tf.report_uninitialized_variables()).run() """ assert_tf_initialized() if target_vars is None: target_vars = tf.global_variables() test_vars = [] test_ops = [] with tf.control_dependencies(None): # ignore surrounding control_dependencies for var in target_vars: assert is_tf_expression(var) with tflex.lock: try: tf.get_default_graph().get_tensor_by_name(var.name.replace(":0", "/IsVariableInitialized:0")) except KeyError: # Op does not exist => variable may be uninitialized. test_vars.append(var) with absolute_name_scope(var.name.split(":")[0]): test_ops.append(tf.is_variable_initialized(var)) init_vars = [var for var, inited in zip(test_vars, run(test_ops)) if not inited] run([var.initializer for var in init_vars]) def set_vars(var_to_value_dict: dict) -> None: """Set the values of given tf.Variables. Equivalent to the following, but more efficient and does not bloat the tf graph: tflib.run([tf.assign(var, value) for var, value in var_to_value_dict.items()] """ assert_tf_initialized() ops = [] feed_dict = {} for var, value in var_to_value_dict.items(): assert is_tf_expression(var) with tflex.lock: if isinstance(value, tf.Variable): try: setter = tf.get_default_graph().get_tensor_by_name(var.name.replace(":0", "/setter_variable:0")) # look for existing op except KeyError: with absolute_name_scope(var.name.split(":")[0]): with tf.control_dependencies(None): # ignore surrounding control_dependencies setter = tf.group(tf.assign(var, value), name="setter_variable") # create new setter ops.append(setter) else: try: setter = tflex.get_default_graph().get_tensor_by_name(var.name.replace(":0", "/setter:0")) # look for existing op except KeyError: with absolute_name_scope(var.name.split(":")[0]): with tf.control_dependencies(None): # ignore surrounding control_dependencies assigner = tf.assign(var, tf.placeholder(var.dtype, var.shape, "new_value")) setter = tf.group(assigner, name="setter") # create new setter ops.append(setter) feed_dict[assigner.op.inputs[1]] = value run(ops, feed_dict) def create_var_with_large_initial_value(initial_value: np.ndarray, *args, **kwargs): """Create tf.Variable with large initial value without bloating the tf graph.""" assert_tf_initialized() assert isinstance(initial_value, np.ndarray) zeros = tf.zeros(initial_value.shape, initial_value.dtype) var = tf.Variable(zeros, *args, **kwargs) set_vars({var: initial_value}) return var def create_var_with_large_initial_value2(initial_value: np.ndarray, *args, **kwargs): """Create tf.Variable with large initial value without bloating the tf graph.""" assert_tf_initialized() assert isinstance(initial_value, np.ndarray) zeros = tf.zeros(initial_value.shape, initial_value.dtype) var = tf.Variable(zeros, *args, **kwargs) return var, tf.assign(var, initial_value) def convert_images_from_uint8(images, drange=[-1,1], nhwc_to_nchw=False): """Convert a minibatch of images from uint8 to float32 with configurable dynamic range. Can be used as an input transformation for Network.run(). """ images = tf.cast(images, tf.float32) if nhwc_to_nchw: images = tf.transpose(images, [0, 3, 1, 2]) return images * ((drange[1] - drange[0]) / 255) + drange[0] def convert_images_to_uint8(images, drange=[-1,1], nchw_to_nhwc=False, shrink=1): """Convert a minibatch of images from float32 to uint8 with configurable dynamic range. Can be used as an output transformation for Network.run(). """ images = tf.cast(images, tf.float32) if shrink > 1: ksize = [1, 1, shrink, shrink] images = tf.nn.avg_pool(images, ksize=ksize, strides=ksize, padding="VALID", data_format="NCHW") if nchw_to_nhwc: images = tf.transpose(images, [0, 2, 3, 1]) scale = 255 / (drange[1] - drange[0]) images = images * scale + (0.5 - drange[0] * scale) return tf.saturate_cast(images, tf.uint8) ================================================ FILE: stylegan2-tpu/dnnlib/tflib/tpu_summaries.py ================================================ # coding=utf-8 # Copyright 2018 Google LLC & Hwalsuk Lee. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """Provide a helper class for using summaries on TPU via a host call. TPUEstimator does not support writing TF summaries out of the box and TPUs can't perform operations that write files to disk. To monitor tensor values during training you can copy the tensors back to the CPU of the host machine via a host call function. This small library provides a convienent API to do this. Example: from compare_gan.tpu import tpu_summaries def model_fn(features, labels, params, mode): summary = tpu_summries.TpuSummaries(my_model_dir) summary.scalar("my_scalar_summary", tensor1) summary.scalar("my_counter", tensor2, reduce_fn=tf.math.reduce_sum) return TPUEstimatorSpec( host_call=summary.get_host_call(), ...) Warning: The host call function will run every step. Writing large tensors to summaries can slow down your training. High ranking outfeed operations in your XProf profile can be an indication for this. """ from __future__ import absolute_import from __future__ import division from __future__ import print_function import collections from absl import logging import tensorflow as tf summary = tf.contrib.summary # TensorFlow Summary API v2. TpuSummaryEntry = collections.namedtuple( "TpuSummaryEntry", "summary_fn name tensor reduce_fn") class TpuSummaries(object): """Class to simplify TF summaries on TPU. An instance of the class provides simple methods for writing summaries in the similar way to tf.summary. The difference is that each summary entry must provide a reduction function that is used to reduce the summary values from all the TPU cores. """ def __init__(self, log_dir, save_summary_steps=32): self._log_dir = log_dir self._entries = [] # While False no summary entries will be added. On TPU we unroll the graph # and don't want to add multiple summaries per step. self.record = True self._save_summary_steps = save_summary_steps def image(self, name, tensor, reduce_fn): """Add a summary for images. Tensor must be of 4-D tensor.""" if not self.record: return self._entries.append( TpuSummaryEntry(summary.image, name, tensor, reduce_fn)) def scalar(self, name, tensor, reduce_fn=tf.math.reduce_mean): """Add a summary for a scalar tensor.""" if not self.record: return tensor = tf.convert_to_tensor(tensor) if tensor.shape.ndims == 0: tensor = tf.expand_dims(tensor, 0) self._entries.append( TpuSummaryEntry(summary.scalar, name, tensor, reduce_fn)) def get_host_call(self): """Returns the tuple (host_call_fn, host_call_args) for TPUEstimatorSpec.""" # All host_call_args must be tensors with batch dimension. # All tensors are streamed to the host machine (mind the band width). global_step = tf.train.get_or_create_global_step() host_call_args = [tf.expand_dims(global_step, 0)] host_call_args.extend([e.tensor for e in self._entries]) logging.info("host_call_args: %s", host_call_args) return (self._host_call_fn, host_call_args) def _host_call_fn(self, step, *args): """Function that will run on the host machine.""" # Host call receives values from all tensor cores (concatenate on the # batch dimension). Step is the same for all cores. step = step[0] logging.info("host_call_fn: args=%s", args) with summary.create_file_writer(self._log_dir).as_default(): with summary.record_summaries_every_n_global_steps( self._save_summary_steps, step): for i, e in enumerate(self._entries): value = e.reduce_fn(args[i]) e.summary_fn(e.name, value, step=step) return summary.all_summary_ops() ================================================ FILE: stylegan2-tpu/dnnlib/util.py ================================================ # Copyright (c) 2019, NVIDIA Corporation. All rights reserved. # # This work is made available under the Nvidia Source Code License-NC. # To view a copy of this license, visit # https://nvlabs.github.io/stylegan2/license.html """Miscellaneous utility classes and functions.""" import ctypes import fnmatch import importlib import inspect import numpy as np import os import shutil import sys import types import io import pickle import re import requests import html import hashlib import glob import uuid import errno from distutils.util import strtobool from typing import Any, List, Tuple, Union # Util classes # ------------------------------------------------------------------------------------------ class EasyDict(dict): """Convenience class that behaves like a dict but allows access with the attribute syntax.""" def __getattr__(self, name: str) -> Any: try: return self[name] except KeyError: raise AttributeError(name) def __setattr__(self, name: str, value: Any) -> None: self[name] = value def __delattr__(self, name: str) -> None: del self[name] class Logger(object): """Redirect stderr to stdout, optionally print stdout to a file, and optionally force flushing on both stdout and the file.""" def __init__(self, file_name: str = None, file_mode: str = "w", should_flush: bool = True): self.file = None if file_name is not None: self.file = open(file_name, file_mode) self.should_flush = should_flush self.stdout = sys.stdout self.stderr = sys.stderr sys.stdout = self sys.stderr = self def __enter__(self) -> "Logger": return self def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None: self.close() def write(self, text: str) -> None: """Write text to stdout (and a file) and optionally flush.""" if len(text) == 0: # workaround for a bug in VSCode debugger: sys.stdout.write(''); sys.stdout.flush() => crash return try: if self.file is not None: self.file.write(text) self.stdout.write(text) if self.should_flush: self.flush() except Exception as e: if e.errno == errno.ENOSPC: pass # fail silently when disk full else: raise def flush(self) -> None: """Flush written text to both stdout and a file, if open.""" try: if self.file is not None: self.file.flush() self.stdout.flush() except Exception as e: if e.errno == errno.ENOSPC: pass # fail silently when disk full else: raise def close(self) -> None: """Flush, close possible files, and remove stdout/stderr mirroring.""" self.flush() try: # if using multiple loggers, prevent closing in wrong order if sys.stdout is self: sys.stdout = self.stdout if sys.stderr is self: sys.stderr = self.stderr if self.file is not None: self.file.close() except Exception as e: if e.errno == errno.ENOSPC: pass # fail silently when disk full else: raise # Small util functions # ------------------------------------------------------------------------------------------ def format_time(seconds: Union[int, float]) -> str: """Convert the seconds to human readable string with days, hours, minutes and seconds.""" s = int(np.rint(seconds)) if s < 60: return "{0}s".format(s) elif s < 60 * 60: return "{0}m {1:02}s".format(s // 60, s % 60) elif s < 24 * 60 * 60: return "{0}h {1:02}m {2:02}s".format(s // (60 * 60), (s // 60) % 60, s % 60) else: return "{0}d {1:02}h {2:02}m".format(s // (24 * 60 * 60), (s // (60 * 60)) % 24, (s // 60) % 60) def ask_yes_no(question: str) -> bool: """Ask the user the question until the user inputs a valid answer.""" while True: try: print("{0} [y/n]".format(question)) return strtobool(input().lower()) except ValueError: pass def tuple_product(t: Tuple) -> Any: """Calculate the product of the tuple elements.""" result = 1 for v in t: result *= v return result _str_to_ctype = { "uint8": ctypes.c_ubyte, "uint16": ctypes.c_uint16, "uint32": ctypes.c_uint32, "uint64": ctypes.c_uint64, "int8": ctypes.c_byte, "int16": ctypes.c_int16, "int32": ctypes.c_int32, "int64": ctypes.c_int64, "float32": ctypes.c_float, "float64": ctypes.c_double } def get_dtype_and_ctype(type_obj: Any) -> Tuple[np.dtype, Any]: """Given a type name string (or an object having a __name__ attribute), return matching Numpy and ctypes types that have the same size in bytes.""" type_str = None if isinstance(type_obj, str): type_str = type_obj elif hasattr(type_obj, "__name__"): type_str = type_obj.__name__ elif hasattr(type_obj, "name"): type_str = type_obj.name else: raise RuntimeError("Cannot infer type name from input") assert type_str in _str_to_ctype.keys() my_dtype = np.dtype(type_str) my_ctype = _str_to_ctype[type_str] assert my_dtype.itemsize == ctypes.sizeof(my_ctype) return my_dtype, my_ctype def is_pickleable(obj: Any) -> bool: try: with io.BytesIO() as stream: pickle.dump(obj, stream) return True except: return False # Functionality to import modules/objects by name, and call functions by name # ------------------------------------------------------------------------------------------ def get_module_from_obj_name(obj_name: str) -> Tuple[types.ModuleType, str]: """Searches for the underlying module behind the name to some python object. Returns the module and the object name (original name with module part removed).""" # allow convenience shorthands, substitute them by full names obj_name = re.sub("^np.", "numpy.", obj_name) obj_name = re.sub("^tf.", "tensorflow.", obj_name) # list alternatives for (module_name, local_obj_name) parts = obj_name.split(".") name_pairs = [(".".join(parts[:i]), ".".join(parts[i:])) for i in range(len(parts), 0, -1)] # try each alternative in turn for module_name, local_obj_name in name_pairs: try: module = importlib.import_module(module_name) # may raise ImportError get_obj_from_module(module, local_obj_name) # may raise AttributeError return module, local_obj_name except: pass # maybe some of the modules themselves contain errors? for module_name, _local_obj_name in name_pairs: try: importlib.import_module(module_name) # may raise ImportError except ImportError: if not str(sys.exc_info()[1]).startswith("No module named '" + module_name + "'"): raise # maybe the requested attribute is missing? for module_name, local_obj_name in name_pairs: try: module = importlib.import_module(module_name) # may raise ImportError get_obj_from_module(module, local_obj_name) # may raise AttributeError except ImportError: pass # we are out of luck, but we have no idea why raise ImportError(obj_name) def get_obj_from_module(module: types.ModuleType, obj_name: str) -> Any: """Traverses the object name and returns the last (rightmost) python object.""" if obj_name == '': return module obj = module for part in obj_name.split("."): obj = getattr(obj, part) return obj def get_obj_by_name(name: str) -> Any: """Finds the python object with the given name.""" module, obj_name = get_module_from_obj_name(name) return get_obj_from_module(module, obj_name) def call_func_by_name(*args, func_name: str = None, **kwargs) -> Any: """Finds the python object with the given name and calls it as a function.""" assert func_name is not None func_obj = get_obj_by_name(func_name) assert callable(func_obj) return func_obj(*args, **kwargs) def get_module_dir_by_obj_name(obj_name: str) -> str: """Get the directory path of the module containing the given object name.""" module, _ = get_module_from_obj_name(obj_name) return os.path.dirname(inspect.getfile(module)) def is_top_level_function(obj: Any) -> bool: """Determine whether the given object is a top-level function, i.e., defined at module scope using 'def'.""" return callable(obj) and obj.__name__ in sys.modules[obj.__module__].__dict__ def get_top_level_function_name(obj: Any) -> str: """Return the fully-qualified name of a top-level function.""" assert is_top_level_function(obj) return obj.__module__ + "." + obj.__name__ # File system helpers # ------------------------------------------------------------------------------------------ def list_dir_recursively_with_ignore(dir_path: str, ignores: List[str] = None, add_base_to_relative: bool = False) -> List[Tuple[str, str]]: """List all files recursively in a given directory while ignoring given file and directory names. Returns list of tuples containing both absolute and relative paths.""" assert os.path.isdir(dir_path) base_name = os.path.basename(os.path.normpath(dir_path)) if ignores is None: ignores = [] result = [] for root, dirs, files in os.walk(dir_path, topdown=True): for ignore_ in ignores: dirs_to_remove = [d for d in dirs if fnmatch.fnmatch(d, ignore_)] # dirs need to be edited in-place for d in dirs_to_remove: dirs.remove(d) files = [f for f in files if not fnmatch.fnmatch(f, ignore_)] absolute_paths = [os.path.join(root, f) for f in files] relative_paths = [os.path.relpath(p, dir_path) for p in absolute_paths] if add_base_to_relative: relative_paths = [os.path.join(base_name, p) for p in relative_paths] assert len(absolute_paths) == len(relative_paths) result += zip(absolute_paths, relative_paths) return result def copy_files_and_create_dirs(files: List[Tuple[str, str]]) -> None: """Takes in a list of tuples of (src, dst) paths and copies files. Will create all necessary directories.""" for file in files: target_dir_name = os.path.dirname(file[1]) # will create all intermediate-level directories if not os.path.exists(target_dir_name): os.makedirs(target_dir_name) shutil.copyfile(file[0], file[1]) # URL helpers # ------------------------------------------------------------------------------------------ def is_url(obj: Any, allow_file_urls: bool = False) -> bool: """Determine whether the given object is a valid URL string.""" if not isinstance(obj, str) or not "://" in obj: return False if allow_file_urls and obj.startswith('file:///'): return True try: res = requests.compat.urlparse(obj) if not res.scheme or not res.netloc or not "." in res.netloc: return False res = requests.compat.urlparse(requests.compat.urljoin(obj, "/")) if not res.scheme or not res.netloc or not "." in res.netloc: return False except: return False return True def open_url(url: str, cache_dir: str = None, num_attempts: int = 10, verbose: bool = True) -> Any: """Download the given URL and return a binary-mode file object to access the data.""" assert is_url(url, allow_file_urls=True) assert num_attempts >= 1 # Handle file URLs. if url.startswith('file:///'): return open(url[len('file:///'):], "rb") # Lookup from cache. url_md5 = hashlib.md5(url.encode("utf-8")).hexdigest() if cache_dir is not None: cache_files = glob.glob(os.path.join(cache_dir, url_md5 + "_*")) if len(cache_files) == 1: return open(cache_files[0], "rb") # Download. url_name = None url_data = None with requests.Session() as session: if verbose: print("Downloading %s ..." % url, end="", flush=True) for attempts_left in reversed(range(num_attempts)): try: with session.get(url) as res: res.raise_for_status() if len(res.content) == 0: raise IOError("No data received") if len(res.content) < 8192: content_str = res.content.decode("utf-8") if "download_warning" in res.headers.get("Set-Cookie", ""): links = [html.unescape(link) for link in content_str.split('"') if "export=download" in link] if len(links) == 1: url = requests.compat.urljoin(url, links[0]) raise IOError("Google Drive virus checker nag") if "Google Drive - Quota exceeded" in content_str: raise IOError("Google Drive download quota exceeded -- please try again later") match = re.search(r'filename="([^"]*)"', res.headers.get("Content-Disposition", "")) url_name = match[1] if match else url url_data = res.content if verbose: print(" done") break except: if not attempts_left: if verbose: print(" failed") raise if verbose: print(".", end="", flush=True) # Save to cache. if cache_dir is not None: safe_name = re.sub(r"[^0-9a-zA-Z-._]", "_", url_name) cache_file = os.path.join(cache_dir, url_md5 + "_" + safe_name) temp_file = os.path.join(cache_dir, "tmp_" + uuid.uuid4().hex + "_" + url_md5 + "_" + safe_name) os.makedirs(cache_dir, exist_ok=True) with open(temp_file, "wb") as f: f.write(url_data) os.replace(temp_file, cache_file) # atomic # Return data as file object. return io.BytesIO(url_data) ================================================ FILE: stylegan2-tpu/docs/license.html ================================================ Nvidia Source Code License-NC

Nvidia Source Code License-NC


1. Definitions

“Licensor” means any person or entity that distributes its Work.

“Software” means the original work of authorship made available under this License.

“Work” means the Software and any additions to or derivative works of the Software that are made available under this License.

“Nvidia Processors” means any central processing unit (CPU), graphics processing unit (GPU), field-programmable gate array (FPGA), application-specific integrated circuit (ASIC) or any combination thereof designed, made, sold, or provided by Nvidia or its affiliates.

The terms “reproduce,” “reproduction,” “derivative works,” and “distribution” have the meaning as provided under U.S. copyright law; provided, however, that for the purposes of this License, derivative works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work.

Works, including the Software, are “made available” under this License by including in or with the Work either (a) a copyright notice referencing the applicability of this License to the Work, or (b) a copy of this License.

2. License Grants

2.1 Copyright Grant. Subject to the terms and conditions of this License, each Licensor grants to you a perpetual, worldwide, non-exclusive, royalty-free, copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense and distribute its Work and any resulting derivative works in any form.

3. Limitations

3.1 Redistribution. You may reproduce or distribute the Work only if (a) you do so under this License, (b) you include a complete copy of this License with your distribution, and (c) you retain without modification any copyright, patent, trademark, or attribution notices that are present in the Work.

3.2 Derivative Works. You may specify that additional or different terms apply to the use, reproduction, and distribution of your derivative works of the Work (“Your Terms”) only if (a) Your Terms provide that the use limitation in Section 3.3 applies to your derivative works, and (b) you identify the specific derivative works that are subject to Your Terms. Notwithstanding Your Terms, this License (including the redistribution requirements in Section 3.1) will continue to apply to the Work itself.

3.3 Use Limitation. The Work and any derivative works thereof only may be used or intended for use non-commercially. The Work or derivative works thereof may be used or intended for use by Nvidia or its affiliates commercially or non-commercially. As used herein, “non-commercially” means for research or evaluation purposes only.

3.4 Patent Claims. If you bring or threaten to bring a patent claim against any Licensor (including any claim, cross-claim or counterclaim in a lawsuit) to enforce any patents that you allege are infringed by any Work, then your rights under this License from such Licensor (including the grants in Sections 2.1 and 2.2) will terminate immediately.

3.5 Trademarks. This License does not grant any rights to use any Licensor’s or its affiliates’ names, logos, or trademarks, except as necessary to reproduce the notices described in this License.

3.6 Termination. If you violate any term of this License, then your rights under this License (including the grants in Sections 2.1 and 2.2) will terminate immediately.

4. Disclaimer of Warranty.

THE WORK IS PROVIDED “AS IS” WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WARRANTIES OR CONDITIONS OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE OR NON-INFRINGEMENT. YOU BEAR THE RISK OF UNDERTAKING ANY ACTIVITIES UNDER THIS LICENSE.

5. Limitation of Liability.

EXCEPT AS PROHIBITED BY APPLICABLE LAW, IN NO EVENT AND UNDER NO LEGAL THEORY, WHETHER IN TORT (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE SHALL ANY LICENSOR BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR RELATED TO THIS LICENSE, THE USE OR INABILITY TO USE THE WORK (INCLUDING BUT NOT LIMITED TO LOSS OF GOODWILL, BUSINESS INTERRUPTION, LOST PROFITS OR DATA, COMPUTER FAILURE OR MALFUNCTION, OR ANY OTHER COMMERCIAL DAMAGES OR LOSSES), EVEN IF THE LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.



================================================ FILE: stylegan2-tpu/docs/versions.html ================================================ StyleGAN versions

StyleGAN2

Original StyleGAN

================================================ FILE: stylegan2-tpu/encoder/__init__.py ================================================ ================================================ FILE: stylegan2-tpu/encoder/generator_model.py ================================================ import math import tensorflow as tf import numpy as np import dnnlib.tflib as tflib from functools import partial def create_stub(name, batch_size): return tf.constant(0, dtype='float32', shape=(batch_size, 0)) def create_variable_for_generator(name, batch_size, tiled_dlatent, model_scale=18): if tiled_dlatent: low_dim_dlatent = tf.get_variable('learnable_dlatents', shape=(batch_size, 512), dtype='float32', initializer=tf.initializers.random_normal()) return tf.tile(tf.expand_dims(low_dim_dlatent, axis=1), [1, model_scale, 1]) else: return tf.get_variable('learnable_dlatents', shape=(batch_size, model_scale, 512), dtype='float32', initializer=tf.initializers.random_normal()) class Generator: def __init__(self, model, batch_size, clipping_threshold=2, tiled_dlatent=False, model_res=1024, randomize_noise=False): self.batch_size = batch_size self.tiled_dlatent=tiled_dlatent self.model_scale = int(2*(math.log(model_res,2)-1)) # For example, 1024 -> 18 if tiled_dlatent: self.initial_dlatents = np.zeros((self.batch_size, 512)) model.components.synthesis.run(np.zeros((self.batch_size, self.model_scale, 512)), randomize_noise=randomize_noise, minibatch_size=self.batch_size, custom_inputs=[partial(create_variable_for_generator, batch_size=batch_size, tiled_dlatent=True), partial(create_stub, batch_size=batch_size)], structure='fixed') else: self.initial_dlatents = np.zeros((self.batch_size, self.model_scale, 512)) model.components.synthesis.run(self.initial_dlatents, randomize_noise=randomize_noise, minibatch_size=self.batch_size, custom_inputs=[partial(create_variable_for_generator, batch_size=batch_size, tiled_dlatent=False, model_scale=self.model_scale), partial(create_stub, batch_size=batch_size)], structure='fixed') self.dlatent_avg_def = model.get_var('dlatent_avg') self.reset_dlatent_avg() self.sess = tf.get_default_session() self.graph = tf.get_default_graph() self.dlatent_variable = next(v for v in tf.global_variables() if 'learnable_dlatents' in v.name) self.set_dlatents(self.initial_dlatents) def get_tensor(name): try: return self.graph.get_tensor_by_name(name) except KeyError: return None self.generator_output = get_tensor('G_synthesis_1/_Run/concat:0') if self.generator_output is None: self.generator_output = get_tensor('G_synthesis_1/_Run/concat/concat:0') if self.generator_output is None: self.generator_output = get_tensor('G_synthesis_1/_Run/concat_1/concat:0') # If we loaded only Gs and didn't load G or D, then scope "G_synthesis_1" won't exist in the graph. if self.generator_output is None: self.generator_output = get_tensor('G_synthesis/_Run/concat:0') if self.generator_output is None: self.generator_output = get_tensor('G_synthesis/_Run/concat/concat:0') if self.generator_output is None: self.generator_output = get_tensor('G_synthesis/_Run/concat_1/concat:0') if self.generator_output is None: for op in self.graph.get_operations(): print(op) raise Exception("Couldn't find G_synthesis_1/_Run/concat tensor output") self.generated_image = tflib.convert_images_to_uint8(self.generator_output, nchw_to_nhwc=True, uint8_cast=False) self.generated_image_uint8 = tf.saturate_cast(self.generated_image, tf.uint8) # Implement stochastic clipping similar to what is described in https://arxiv.org/abs/1702.04782 # (Slightly different in that the latent space is normal gaussian here and was uniform in [-1, 1] in that paper, # so we clip any vector components outside of [-2, 2]. It seems fine, but I haven't done an ablation check.) clipping_mask = tf.math.logical_or(self.dlatent_variable > clipping_threshold, self.dlatent_variable < -clipping_threshold) clipped_values = tf.where(clipping_mask, tf.random_normal(shape=self.dlatent_variable.shape), self.dlatent_variable) self.stochastic_clip_op = tf.assign(self.dlatent_variable, clipped_values) def reset_dlatents(self): self.set_dlatents(self.initial_dlatents) def set_dlatents(self, dlatents): if self.tiled_dlatent: if (dlatents.shape != (self.batch_size, 512)) and (dlatents.shape[1] != 512): dlatents = np.mean(dlatents, axis=1) if (dlatents.shape != (self.batch_size, 512)): dlatents = np.vstack([dlatents, np.zeros((self.batch_size-dlatents.shape[0], 512))]) assert (dlatents.shape == (self.batch_size, 512)) else: if (dlatents.shape[1] > self.model_scale): dlatents = dlatents[:,:self.model_scale,:] if (dlatents.shape != (self.batch_size, self.model_scale, 512)): dlatents = np.vstack([dlatents, np.zeros((self.batch_size-dlatents.shape[0], self.model_scale, 512))]) assert (dlatents.shape == (self.batch_size, self.model_scale, 512)) self.dlatent_variable.load(dlatents, self.sess) def stochastic_clip_dlatents(self): self.sess.run(self.stochastic_clip_op) def get_dlatents(self): return self.dlatent_variable.eval(self.sess) def get_dlatent_avg(self): return self.dlatent_avg def set_dlatent_avg(self, dlatent_avg): self.dlatent_avg = dlatent_avg def reset_dlatent_avg(self): self.dlatent_avg = self.dlatent_avg_def def generate_images(self, dlatents=None): if dlatents: self.set_dlatents(dlatents) return self.sess.run(self.generated_image_uint8) ================================================ FILE: stylegan2-tpu/encoder/perceptual_model.py ================================================ import os import bz2 import PIL.Image import numpy as np import tensorflow as tf from keras.models import Model from keras.utils import get_file from keras.applications.vgg16 import VGG16, preprocess_input import keras.backend as K import traceback def load_images(images_list, image_size=256): loaded_images = list() for img_path in images_list: img = PIL.Image.open(img_path).convert('RGB').resize((image_size,image_size),PIL.Image.LANCZOS) img = np.array(img) img = np.expand_dims(img, 0) loaded_images.append(img) loaded_images = np.vstack(loaded_images) return loaded_images def tf_custom_l1_loss(img1,img2): return tf.math.reduce_mean(tf.math.abs(img2-img1), axis=None) def tf_custom_logcosh_loss(img1,img2): return tf.math.reduce_mean(tf.keras.losses.logcosh(img1,img2)) def unpack_bz2(src_path): data = bz2.BZ2File(src_path).read() dst_path = src_path[:-4] with open(dst_path, 'wb') as fp: fp.write(data) return dst_path class PerceptualModel: def __init__(self, args, batch_size=1, perc_model=None, sess=None, optimizer=None): self.sess = tf.get_default_session() if sess is None else sess self.optimizer = optimizer K.set_session(self.sess) self.epsilon = 0.00000001 self.lr = args.lr self.decay_rate = args.decay_rate self.decay_steps = args.decay_steps self.img_size = args.image_size self.layer = args.use_vgg_layer self.vgg_loss = args.use_vgg_loss self.face_mask = args.face_mask self.use_grabcut = args.use_grabcut self.scale_mask = args.scale_mask self.mask_dir = args.mask_dir if (self.layer <= 0 or self.vgg_loss <= self.epsilon): self.vgg_loss = None self.pixel_loss = args.use_pixel_loss if (self.pixel_loss <= self.epsilon): self.pixel_loss = None self.mssim_loss = args.use_mssim_loss if (self.mssim_loss <= self.epsilon): self.mssim_loss = None self.lpips_loss = args.use_lpips_loss if (self.lpips_loss <= self.epsilon): self.lpips_loss = None self.l1_penalty = args.use_l1_penalty if (self.l1_penalty <= self.epsilon): self.l1_penalty = None self.batch_size = batch_size if perc_model is not None and self.lpips_loss is not None: self.perc_model = perc_model else: self.perc_model = None self.ref_img = None self.ref_weight = None self.perceptual_model = None self.ref_img_features = None self.features_weight = None self.loss = None if self.face_mask: import dlib self.detector = dlib.get_frontal_face_detector() LANDMARKS_MODEL_URL = 'http://dlib.net/files/shape_predictor_68_face_landmarks.dat.bz2' landmarks_model_path = unpack_bz2(get_file('shape_predictor_68_face_landmarks.dat.bz2', LANDMARKS_MODEL_URL, cache_subdir='temp')) self.predictor = dlib.shape_predictor(landmarks_model_path) def compare_images(self,img1,img2): if self.perc_model is not None: return self.perc_model.get_output_for(tf.transpose(img1, perm=[0,3,2,1]), tf.transpose(img2, perm=[0,3,2,1])) return 0 def add_placeholder(self, var_name): var_val = getattr(self, var_name) setattr(self, var_name + "_placeholder", tf.placeholder(var_val.dtype, shape=var_val.get_shape())) setattr(self, var_name + "_op", var_val.assign(getattr(self, var_name + "_placeholder"))) def assign_placeholder(self, var_name, var_val): self.sess.run(getattr(self, var_name + "_op"), {getattr(self, var_name + "_placeholder"): var_val}) def build_perceptual_model(self, generator): self.generator = generator # Learning rate self._global_step = tf.Variable(0, dtype=tf.int32, trainable=False, name="global_step") self._incremented_global_step = tf.assign_add(self._global_step, 1) self._reset_global_step = tf.assign(self._global_step, 0) self.learning_rate = tf.train.exponential_decay(self.lr, self._incremented_global_step, self.decay_steps, self.decay_rate, staircase=True) self.sess.run([self._reset_global_step]) self.generated_image_tensor = self.generator.generated_image self.generated_image = tf.image.resize_nearest_neighbor(self.generated_image_tensor, (self.img_size, self.img_size), align_corners=True) self.ref_img = tf.get_variable('ref_img', shape=self.generated_image.shape, dtype='float32', initializer=tf.initializers.zeros()) self.ref_weight = tf.get_variable('ref_weight', shape=self.generated_image.shape, dtype='float32', initializer=tf.initializers.zeros()) self.add_placeholder("ref_img") self.add_placeholder("ref_weight") if (self.vgg_loss is not None): self.vgg16 = VGG16(include_top=False, input_shape=(self.img_size, self.img_size, 3)) self.perceptual_model = Model(self.vgg16.input, self.vgg16.layers[self.layer].output) self.generated_img_features = self.perceptual_model(preprocess_input(self.ref_weight * self.generated_image)) self.ref_img_features = tf.get_variable('ref_img_features', shape=self.generated_img_features.shape, dtype='float32', initializer=tf.initializers.zeros()) self.features_weight = tf.get_variable('features_weight', shape=self.generated_img_features.shape, dtype='float32', initializer=tf.initializers.zeros()) self.sess.run([self.features_weight.initializer, self.features_weight.initializer]) self.add_placeholder("ref_img_features") self.add_placeholder("features_weight") self.loss = 0 # L1 loss on VGG16 features if (self.vgg_loss is not None): self.loss += self.vgg_loss * tf_custom_l1_loss(self.features_weight * self.ref_img_features, self.features_weight * self.generated_img_features) # + logcosh loss on image pixels if (self.pixel_loss is not None): self.loss += self.pixel_loss * tf_custom_logcosh_loss(self.ref_weight * self.ref_img, self.ref_weight * self.generated_image) # + MS-SIM loss on image pixels if (self.mssim_loss is not None): self.loss += self.mssim_loss * tf.math.reduce_mean(1-tf.image.ssim_multiscale(self.ref_weight * self.ref_img, self.ref_weight * self.generated_image, 1)) # + extra perceptual loss on image pixels if self.perc_model is not None and self.lpips_loss is not None: self.loss += self.lpips_loss * tf.math.reduce_mean(self.compare_images(self.ref_weight * self.ref_img, self.ref_weight * self.generated_image)) # + L1 penalty on dlatent weights if self.l1_penalty is not None: self.loss += self.l1_penalty * 512 * tf.math.reduce_mean(tf.math.abs(self.generator.dlatent_variable[:,0]-self.generator.get_dlatent_avg())) vars_to_optimize = self.generator.dlatent_variable self.vars_to_optimize = vars_to_optimize if isinstance(vars_to_optimize, list) else [vars_to_optimize] if self.optimizer is not None: self.min_op = self.optimizer.minimize(self.loss, var_list=[self.vars_to_optimize]) else: self.optimizer = tf.train.AdamOptimizer(learning_rate=self.learning_rate) self.min_op = self.optimizer.minimize(self.loss, var_list=[self.vars_to_optimize]) self.sess.run(tf.variables_initializer(self.optimizer.variables())) self.sess.run(self._reset_global_step) def generate_face_mask(self, im): from imutils import face_utils import cv2 rects = self.detector(im, 1) # loop over the face detections for (j, rect) in enumerate(rects): """ Determine the facial landmarks for the face region, then convert the facial landmark (x, y)-coordinates to a NumPy array """ shape = self.predictor(im, rect) shape = face_utils.shape_to_np(shape) # we extract the face vertices = cv2.convexHull(shape) mask = np.zeros(im.shape[:2],np.uint8) cv2.fillConvexPoly(mask, vertices, 1) if self.use_grabcut: bgdModel = np.zeros((1,65),np.float64) fgdModel = np.zeros((1,65),np.float64) rect = (0,0,im.shape[1],im.shape[2]) (x,y),radius = cv2.minEnclosingCircle(vertices) center = (int(x),int(y)) radius = int(radius*self.scale_mask) mask = cv2.circle(mask,center,radius,cv2.GC_PR_FGD,-1) cv2.fillConvexPoly(mask, vertices, cv2.GC_FGD) cv2.grabCut(im,mask,rect,bgdModel,fgdModel,5,cv2.GC_INIT_WITH_MASK) mask = np.where((mask==2)|(mask==0),0,1) return mask def load_images(self, images_list): assert (len(images_list) != 0 and len(images_list) <= self.batch_size) loaded_image = load_images(images_list, self.img_size) return loaded_image def set_reference_images(self, images_list): return self.set_reference_image_data(self.load_images(images_list), images_list) def set_reference_image_data(self, loaded_image, images_list=None): if len(loaded_image.shape) < 4: loaded_image = loaded_image.reshape([1] + list(loaded_image.shape)) self.loaded_image = loaded_image self.images_list = images_list self.image_features = None if self.perceptual_model is not None: self.image_features = self.perceptual_model.predict_on_batch(preprocess_input(self.loaded_image)) self.weight_mask = np.ones(self.features_weight.shape) if self.face_mask and self.images_list is not None: self.image_mask = np.zeros(self.ref_weight.shape) for (i, im) in enumerate(self.loaded_image): try: _, img_name = os.path.split(self.images_list[i]) mask_img = os.path.join(self.mask_dir, f'{img_name}') if (os.path.isfile(mask_img)): print("Loading mask " + mask_img) imask = PIL.Image.open(mask_img).convert('L') mask = np.array(imask)/255 mask = np.expand_dims(mask,axis=-1) else: mask = self.generate_face_mask(im) imask = (255*mask).astype('uint8') imask = PIL.Image.fromarray(imask, 'L') print("Saving mask " + mask_img) imask.save(mask_img, 'PNG') mask = np.expand_dims(mask,axis=-1) mask = np.ones(im.shape,np.float32) * mask except Exception as e: print("Exception in mask handling for " + mask_img) traceback.print_exc() mask = np.ones(im.shape[:2],np.uint8) mask = np.ones(im.shape,np.float32) * np.expand_dims(mask,axis=-1) self.image_mask[i] = mask else: self.image_mask = np.ones(self.ref_weight.shape) image_count = self.loaded_image.shape[0] if image_count != self.batch_size: if self.image_features is not None: features_space = list(self.features_weight.shape[1:]) existing_features_shape = [image_count] + features_space empty_features_shape = [self.batch_size - image_count] + features_space existing_examples = np.ones(shape=existing_features_shape) empty_examples = np.zeros(shape=empty_features_shape) self.weight_mask = np.vstack([existing_examples, empty_examples]) self.image_features = np.vstack([self.image_features, np.zeros(empty_features_shape)]) images_space = list(self.ref_weight.shape[1:]) existing_images_space = [image_count] + images_space empty_images_space = [self.batch_size - image_count] + images_space existing_images = np.ones(shape=existing_images_space) empty_images = np.zeros(shape=empty_images_space) self.image_mask = self.image_mask * np.vstack([existing_images, empty_images]) self.loaded_image = np.vstack([self.loaded_image, np.zeros(empty_images_space)]) if self.image_features is not None: self.assign_placeholder("features_weight", self.weight_mask) self.assign_placeholder("ref_img_features", self.image_features) self.assign_placeholder("ref_weight", self.image_mask) self.assign_placeholder("ref_img", self.loaded_image) def optimize(self, iterations=200): self.fetch_ops = [self.min_op, self.loss, self.learning_rate] for _ in range(iterations): _, loss, lr = self.sess.run(self.fetch_ops) yield {"loss":loss, "lr": lr} ================================================ FILE: stylegan2-tpu/ext.l ================================================ (def image-to-discord-file (img name: name kind: kind) (set kind (or kind "jpg")) (set name (or name "test")) (let f (BytesIO) (f.write (image-to-bytes img)) (f.seek 0) (let picture (discord.File f) (set picture.filename (+ name "." kind)) picture))) (def listtab (l) (with r (obj) (step (k v) l (if (number? k) (set (at r k) v) (set (get r k) v))))) (def tablist (h) (with r () (each (k v) h (add r (list k v))))) (def assoc (key al) (let-when i (first (fn (x) (hd? x key)) al) (at al i))) (def alref (al key) (let-when l (assoc key al) (at l 1))) (def union (f xs ys) (join xs (rem (fn (y) (some (fn (_) (f _ y)) xs)) ys))) (define-global testify (x test) (if (function? x) x test (fn (y) (test y x)) (fn (y) (= x y)))) (define-global find (x t) (let f (testify x) (each x t (let y (f x) (if y (return y)))))) (def saveable-vars (network) (map (fn ((k v)) (list (cat "G_synthesis/" k) v)) (list x for x in (synthesis.trainables.items)))) ;(go (chan*.send "hi" file: (image-to-discord-file img))) (import tflex) (define-symbol chan* tflex.message.channel) (from training import misc) (def rand-latent (seed shape) (let (shape (or shape '(1 512)) seed (np.random.RandomState seed) latent (apply seed.randn shape)) latent)) (from pprint import pprint) (from io import StringIO) (def bytes-to-discord-file (bs name) (let f (BytesIO) (f.write bs) (f.seek 0) (let f1 (discord.File f) (when (is? name) (set f1.filename name)) f1))) (def image-to-discord-file (img name: name kind: kind) (set kind (or kind "jpg")) (set name (or name "test")) (bytes-to-discord-file (image-to-bytes img) (+ name "." kind))) (def pps (x) (let f (StringIO) (pprint x stream: f) (ellipsize (f.getvalue) 1190))) (def netrun (network latent label |**kws|) (let latent (if (or (nil? latent) (isinstance latent int)) (rand-latent latent) latent) (network.run latent label |**kws|))) (defvar target-size* nil) (import asyncio) (def go (coro) (asyncio.run_coroutine_threadsafe coro (asyncio.get_event_loop))) (def prfile (f text: text name: name chan: chan) (set chan (or chan chan*)) (go (chan.send (or text "") file: f))) (def numpy-to-image-grid (result drange-net: drange-net) (let (drange-net (or drange-net '(-1 1)) n result.shape.0 grid-size (get-grid-size n) x (misc.create-image-grid result grid-size) img (misc.convert-to-pil-image x drange-net)) img)) (def primg (img text: text name: name) (let (img (if (numpy? img) (numpy-to-image-grid img) img) img (if target-size* (resize-image img target-size*) img) f (image-to-discord-file img)) ;(set (get f 'filename) name) (go (chan*.send (or text "") file: f)))) (import os) ;(set (get os.environ 'TPU_NAME) "tpu-v3-32-euw4a-4") (import dnnlib) (import tflex) (set me (dnnlib.EasyDict tflex.self)) (from training.networks_stylegan2 import *) (from training import misc) (me.init) (defvar G (tflib.Network "G" num_channels: 3 resolution: 512 label_size: 0 func_name: "training.networks_stylegan2.G_main")) (defvar Gs (G.clone "Gs")) (defvar model-dir* nil) (defvar model-step* 0) (def checkpoint (path i network: network) (global model-dir*) (let (path (or path model-dir*) network (or network Gs)) (set model-dir* path) (let path (if (is? i) (os.path.join path (idx "model-{}.ckpt" i)) (or (tf.train.latest-checkpoint path) path)) (me.load-checkpoint path var_list: network.trainables) path))) (def grab (latent ckpt network: network label: label truncation_psi: psi) (let network (or network Gs) (when ckpt (me.load-checkpoint ckpt var_list: network.trainables)) (primg (hd (netrun network latent label truncation_psi: (either psi 0.7)))))) (def latent-grid (seed n) (rand-latent (or n 9) seed: (or seed 0))) (def o (seed n) (gen-images (rand-latent (or n 9) (or seed 0)))) (mac see args (let (args (keep (fn (x) (not (= x "seed"))) args) (path seed n offset) args a (or offset 0) b `(+ ,a ,(or n 9)) n 100) `(do (checkpoint ,(escape path)) (primg (gen-images (np.array (array (cut (rand-latent ,n seed: ,(or seed 0)) ,a ,b)))) text: ,(escape (cat path " seed " (str seed))))))) (mac seevid (path _ seed x y dur fps) `(do (checkpoint ,(escape path)) (interpv ,(or dur 2.0) ,(or fps 'nil) ,seed ,x ,y))) (defvar latents*) (def lerp (a b t) (+ a (* t (- b a)))) (def lerp-latent (a b t) (np.array (list (lerp a b t)))) (def latent-range (a b) (fn (t) (lerp-latent a b t))) (def interpolator (seed x0 x1) (let (seed (or seed 0) latents (rand-latent 9 seed: seed) a (at latents (or x0 0)) b (at latents (or x1 1))) (latent-range a b))) (def i args (interp (apply interpolator args))) (def time-percentage (duration f) (fn (t) (f (/ t duration)))) (def then-image (latent-maker) (fn (t) (let latent (latent-maker t) (image-to-numpy (gen-images latent))))) (def to-numpy (x) (if (image? x) x (image-to-numpy x))) (def pimg (x) (primg (to-numpy x))) (def interp (f n) (let n (or n 10.0) (step t (np.arange 0.0 (+ n 1.0) 1.0) (pimg (gen-images (f (/ t n))))))) (def i (seed a b n) (interp (interpolator seed a b) n)) (def prfile (f text: text chan: chan name: name) (set chan (or chan chan*)) (when name (set f.filename name)) (go (chan.send (or text "") file: f))) (mac after (x rest: body) `(let ((ok v) (guard ,x)) ,@body (if ok v (throw v)))) (import os) (import tempfile) |sys.path += ["/home/train/.local/lib/python3.6/site-packages"]| (import moviepy) (import moviepy.editor) (unless (%in "gwern#1782" me.admins) (add me.admins "gwern#1782")) (def videobytes (make-frame duration fps) (set duration (or duration 0.5)) (set fps (or fps 10)) (set vid (moviepy.editor.VideoClip make-frame duration: duration)) (let ((fd path) (tempfile.mkstemp) path "test" path (+ path ".mp4")) (after (do (vid.write-videofile path fps: fps codec: mp4-codec bitrate: mp4-bitrate) ((idx (open path "rb") read))) ;(os.remove path) ))) (def interpv (duration fps rest: args) (set duration (either duration 0.5)) (set fps (or fps 10)) (set vid (videobytes (then-image (time-percentage duration (apply interpolator args))) duration fps)) (set res (bytes-to-discord-file vid "interp.mp4")) (go (chan*.send file: res))) (mac check (path) `(let s (me.shell '(gsutil-checkpoints ,path)) (go (chan*.send file: (bytes-to-discord-file (s.encode "utf8") "checkpoints.txt"))))) | def get_grid_size(n): gw = 1 gh = 1 i = 0 while gw*gh < n: if i % 2 == 0: gw += 1 else: gh += 1 i += 1 return (gw, gh) def gen_images(latents, outfile=None, display=False, labels=None, randomize_noise=False, is_validation=True, network=None): if network is None: network = Gs n = latents.shape[0] grid_size = get_grid_size(n) drange_net = [-1, 1] with tflex.device('/gpu:0'): result = network.run(latents, labels, is_validation=is_validation, randomize_noise=randomize_noise, minibatch_size=sched.minibatch_gpu) img = misc.convert_to_pil_image(misc.create_image_grid(result, grid_size), drange_net) if outfile is not None: img.save(outfile) if display: f = BytesIO() img.save(f, 'png') IPython.display.display(IPython.display.Image(data=f.getvalue())) return result import discord import tensorflow as tf grid_size = [1,1] image_shrink = 1 image_zoom = 1 duration_sec = 5.0 smoothing_sec = 1.0 mp4_fps = 20 mp4_codec = 'libx264' mp4_bitrate = '5M' random_seed = 82 minibatch_size = 8 num_frames = int(np.rint(duration_sec * mp4_fps)) random_state = np.random.RandomState(random_seed) # Generate latent vectors shape = [num_frames, np.prod(grid_size)] + Gs.input_shape[1:] # [frame, image, channel, component] all_latents = random_state.randn(*shape).astype(np.float32) import scipy all_latents = scipy.ndimage.gaussian_filter(all_latents, [smoothing_sec * mp4_fps] + [0] * len(Gs.input_shape), mode='wrap') all_latents /= np.sqrt(np.mean(np.square(all_latents))) def rand_latent(n, seed=None): if seed is not None: if seed < 0: seed = 2*32 - seed np.random.seed(seed) result = np.random.randn(n, *G.input_shape[1:]) if seed is not None: np.random.seed() return result sched = dnnlib.EasyDict() sched.minibatch_gpu = 1 | nil ================================================ FILE: stylegan2-tpu/generate_images_tpu.py ================================================ import argparse import os import pathlib from pathlib import Path from pprint import pprint as pp import numpy as np import tensorflow as tf import tqdm from tqdm import tqdm import dnnlib import tflex from dnnlib import EasyDict from training import misc from training.networks_stylegan2 import * try: from StringIO import StringIO as BytesIO # for Python 2 except ImportError: from io import BytesIO # for Python 3 def rand_latent(n, seed=None): if seed is not None: if seed < 0: seed = 2*32 - seed np.random.seed(seed) result = np.random.randn(n, *G.input_shape[1:]) if seed is not None: np.random.seed() return result def tfinit(): tflib.run(tf.global_variables_initializer()) def load_checkpoint(path, checkpoint_num=None): if checkpoint_num is None: ckpt = tf.train.latest_checkpoint(path) else: ckpt = os.path.join(path, f'model.ckpt-{checkpoint_num}') assert ckpt is not None print('Loading checkpoint ' + ckpt) saver.restore(sess, ckpt) return ckpt def get_checkpoint(path): ckpt = tf.train.latest_checkpoint(path) return ckpt def get_grid_size(n): gw = 1 gh = 1 i = 0 while gw*gh < n: if i % 2 == 0: gw += 1 else: gh += 1 i += 1 return (gw, gh) def gen_images(latents, truncation_psi_val, outfile=None, display=False, labels=None, randomize_noise=False, is_validation=True, network=None, numpy=False): if outfile: Path(outfile).parent.mkdir(exist_ok=True, parents=True) if network is None: network = Gs n = latents.shape[0] grid_size = get_grid_size(n) drange_net = [-1, 1] with tflex.device('/gpu:0'): result = network.run(latents, labels, truncation_psi_val=truncation_psi_val, is_validation=is_validation, randomize_noise=randomize_noise, minibatch_size=sched.minibatch_gpu) result = result[:, 0:3, :, :] img = misc.convert_to_pil_image( misc.create_image_grid(result, grid_size), drange_net) if outfile is not None: img.save(outfile) if display: f = BytesIO() img.save(f, 'png') IPython.display.display(IPython.display.Image(data=f.getvalue())) return result if numpy else img def grab(save_dir, i, n=1, latents=None, **kwargs): if latents is None: latents = rand_latent(n, seed=i) gw, gh = get_grid_size(latents.shape[0]) outfile = str(save_dir/str(i)) + '.png' return gen_images(latents, outfile=outfile, **kwargs) if __name__ == '__main__': parser = argparse.ArgumentParser(description='StyleGAN2 TPU Generator') parser.add_argument('--model_dir', type=str, action='store', help='Location of the checkpoint files') parser.add_argument('--save_dir', type=str, action='store', help='Location of the directory to save images in') parser.add_argument('--truncation_psi', type=float, action='store', help='Truncation psi (default: %(default)s)', default=0.7) parser.add_argument('--num_samples', type=int, action='store', help='Number of samples to generate (default: %(default)s)', default=1) parser.add_argument('--checkpoint_num', type=int, action='store', help='The checkpoint to use to generate the images. The default is the latest checkpoint in model_dir', default=None) args = parser.parse_args() # environment variables os.environ['TPU_NAME'] = 'dkgan-tpu' os.environ['NOISY'] = '1' # --- set resolution and label size here: label_size = 0 resolution = 512 fmap_base = (int(os.environ['FMAP_BASE']) if 'FMAP_BASE' in os.environ else 16) << 10 num_channels = 3 channel = 3 count = 1 grid_image_size = int( os.environ['GRID_SIZE']) if 'GRID_SIZE' in os.environ else 9 # ------------------------ print('------------------') print('Initializing model') print('------------------') # set up model dnnlib.tflib.init_tf() sess = tf.get_default_session() sess.list_devices() cores = tflex.get_cores() tflex.set_override_cores(cores) # Options for training loop. train = EasyDict(run_func_name='training.training_loop.training_loop') # Options for generator network. G_args = EasyDict(func_name='training.networks_stylegan2.G_main') # Options for discriminator network. D_args = EasyDict(func_name='training.networks_stylegan2.D_stylegan2') # Options for generator optimizer. G_opt = EasyDict(beta1=0.0, beta2=0.99, epsilon=1e-8) # Options for discriminator optimizer. D_opt = EasyDict(beta1=0.0, beta2=0.99, epsilon=1e-8) # Options for generator loss. G_loss = EasyDict(func_name='training.loss.G_logistic_ns_pathreg') # Options for discriminator loss. D_loss = EasyDict(func_name='training.loss.D_logistic_r1') # Options for TrainingSchedule. sched = EasyDict() # Options for setup_snapshot_image_grid(). grid = EasyDict(size='8k', layout='random') # Options for dnnlib.submit_run(). sc = dnnlib.SubmitConfig() tf_config = {'rnd.np_random_seed': 1000} label_dtype = np.int64 sched.minibatch_gpu = 1 if 'G' not in globals(): with tflex.device('/gpu:0'): G = tflib.Network('G', num_channels=num_channels, resolution=resolution, label_size=label_size, fmap_base=fmap_base, **G_args) G.print_layers() Gs, Gs_finalize = G.clone2('Gs') Gs_finalize() D = tflib.Network('D', num_channels=num_channels, resolution=resolution, label_size=label_size, fmap_base=fmap_base, **D_args) D.print_layers() grid_size = (2, 2) gw, gh = grid_size gn = np.prod(grid_size) grid_latents = rand_latent(gn, seed=-1) grid_labels = np.zeros([gw * gh, label_size], dtype=label_dtype) tfinit() print('-----------------') print('Initialized model') print('-----------------') # ---------------------- # Load checkpoint print('Loading checkpoint') saver = tf.train.Saver() # ------------------------ model_ckpt = load_checkpoint(args.model_dir, args.checkpoint_num) model_name = model_ckpt.split('/')[4] model_num = model_ckpt.split('-')[-1] print('Loaded model', model_name) tflex.state.noisy = False # --------------------- save_dir = Path(args.save_dir)/model_num # generate samples for i in tqdm(list(range(args.num_samples))): grab(save_dir, i=i, truncation_psi_val=args.truncation_psi) # modify seed ================================================ FILE: stylegan2-tpu/mammos.py ================================================ import sys import os sys.path += [os.path.join(os.path.dirname(os.path.abspath(__file__)), '../pymen/bin')] if 'COLAB_TPU_ADDR' in os.environ: os.environ['TPU_NAME'] = 'grpc://' + os.environ['COLAB_TPU_ADDR'] os.environ['NOISY'] = '1' # --- set resolution and label size here: label_size = int(os.environ['LABEL_SIZE']) resolution = int(os.environ['RESOLUTION']) num_channels = int(os.environ['NUM_CHANNELS']) model_dir = os.environ['MODEL_DIR'] count = int(os.environ['COUNT']) if 'COUNT' in os.environ else 1 grid_image_size = int(os.environ['GRID_SIZE']) if 'GRID_SIZE' in os.environ else 9 batch_size = 1 # ------------------------ import numpy as np import warnings warnings.filterwarnings('ignore') import tqdm from training.networks_stylegan2 import * from training import misc import dnnlib from dnnlib import EasyDict import tensorflow as tf import tflex import os import numpy as np tflex.self = globals() train = EasyDict(run_func_name='training.training_loop.training_loop') # Options for training loop. G_args = EasyDict(func_name='training.networks_stylegan2.G_main') # Options for generator network. D_args = EasyDict(func_name='training.networks_stylegan2.D_stylegan2') # Options for discriminator network. G_opt = EasyDict(beta1=0.0, beta2=0.99, epsilon=1e-8) # Options for generator optimizer. D_opt = EasyDict(beta1=0.0, beta2=0.99, epsilon=1e-8) # Options for discriminator optimizer. G_loss = EasyDict(func_name='training.loss.G_logistic_ns_pathreg') # Options for generator loss. D_loss = EasyDict(func_name='training.loss.D_logistic_r1') # Options for discriminator loss. sched = EasyDict() # Options for TrainingSchedule. grid = EasyDict(size='8k', layout='random') # Options for setup_snapshot_image_grid(). sc = dnnlib.SubmitConfig() # Options for dnnlib.submit_run(). tf_config = {'rnd.np_random_seed': 1000} label_dtype = np.int64 sched.minibatch_gpu = 1 def with_session(sess, f, *args, **kws): with sess.as_default(): return f(*args, **kws) async def with_session_async(sess, f, *args, **kws): with sess.as_default(): return await f(*args, **kws) def init(session=None, num_channels=None, resolution=None, label_size=None): label_size = int(os.environ['LABEL_SIZE']) if label_size is None else label_size resolution = int(os.environ['RESOLUTION']) if resolution is None else resolution num_channels = int(os.environ['NUM_CHANNELS']) if num_channels is None else num_channels dnnlib.tflib.init_tf() session = tflex.get_session(session) pprint(session.list_devices()) tflex.set_override_cores(tflex.get_cores()) with tflex.device('/gpu:0'): tflex.G = tflib.Network('G', num_channels=num_channels, resolution=resolution, label_size=label_size, **G_args) tflex.G.print_layers() tflex.Gs, tflex.Gs_finalize = tflex.G.clone2('Gs') tflex.Gs_finalize() tflex.D = tflib.Network('D', num_channels=num_channels, resolution=resolution, label_size=label_size, **D_args) tflex.D.print_layers() tflib.run(tf.global_variables_initializer()) return session def load_checkpoint(path, session=None, var_list=None): if var_list is None: var_list = tflex.Gs.trainables ckpt = tf.train.latest_checkpoint(path) or path assert ckpt is not None print('Loading checkpoint ' + ckpt) saver = tf.train.Saver(var_list=var_list) saver.restore(tflex.get_session(session), ckpt) return ckpt init() load_checkpoint(model_dir) import PIL.Image import numpy as np import requests from io import BytesIO def get_images(tags, seed = 0, mu = 0, sigma = 0, truncation=None): print("Generating mammos...") Gs_kwargs = dnnlib.EasyDict() Gs_kwargs.output_transform = dict(func=tflib.convert_images_to_uint8, nchw_to_nhwc=True) Gs_kwargs.randomize_noise = False if truncation is not None: Gs_kwargs.truncation_psi = truncation rnd = np.random.RandomState(seed) all_seeds = [seed] * batch_size all_z = np.stack([np.random.RandomState(seed).randn(*tflex.Gs.input_shape[1:]) for seed in all_seeds]) # [minibatch, component] print(all_z.shape) drange_net = [-1, 1] with tflex.device('/gpu:0'): result = tflex.Gs.run(all_z, None, is_validation=True, randomize_noise=False, minibatch_size=sched.minibatch_gpu) if result.shape[1] > 3: final = result[:, 3, :, :] else: final = None result = result[:, 0:3, :, :] img = misc.convert_to_pil_image(misc.create_image_grid(result, (1, 1)), drange_net) img.save('mammos.png') return result, img ================================================ FILE: stylegan2-tpu/metrics/__init__.py ================================================ # Copyright (c) 2019, NVIDIA Corporation. All rights reserved. # # This work is made available under the Nvidia Source Code License-NC. # To view a copy of this license, visit # https://nvlabs.github.io/stylegan2/license.html # empty ================================================ FILE: stylegan2-tpu/metrics/frechet_inception_distance.py ================================================ # Copyright (c) 2019, NVIDIA Corporation. All rights reserved. # # This work is made available under the Nvidia Source Code License-NC. # To view a copy of this license, visit # https://nvlabs.github.io/stylegan2/license.html """Frechet Inception Distance (FID).""" import os import numpy as np import scipy import tensorflow as tf import tflex import dnnlib.tflib as tflib from metrics import metric_base from training import misc #---------------------------------------------------------------------------- class FID(metric_base.MetricBase): def __init__(self, num_images, minibatch_per_gpu, **kwargs): super().__init__(**kwargs) self.num_images = num_images self.minibatch_per_gpu = minibatch_per_gpu def _evaluate(self, Gs, Gs_kwargs, num_gpus): minibatch_size = num_gpus * self.minibatch_per_gpu inception = misc.load_pkl('https://drive.google.com/uc?id=1MzTY44rLToO5APn8TZmfR7_ENSe5aZUn', 'inception_v3_features.pkl') activations = np.empty([self.num_images, inception.output_shape[1]], dtype=np.float32) # Calculate statistics for reals. cache_file = self._get_cache_file_for_reals(num_images=self.num_images) os.makedirs(os.path.dirname(cache_file), exist_ok=True) if os.path.isfile(cache_file): mu_real, sigma_real = misc.load_pkl(cache_file) else: for idx, images in enumerate(self._iterate_reals(minibatch_size=minibatch_size)): begin = idx * minibatch_size end = min(begin + minibatch_size, self.num_images) activations[begin:end] = inception.run(images[:end-begin], num_gpus=num_gpus, assume_frozen=True) if end == self.num_images: break mu_real = np.mean(activations, axis=0) sigma_real = np.cov(activations, rowvar=False) misc.save_pkl((mu_real, sigma_real), cache_file) # Construct TensorFlow graph. result_expr = [] for gpu_idx in range(num_gpus): with tflex.device('/gpu:%d' % gpu_idx): Gs_clone = Gs.clone() inception_clone = inception.clone() latents = tf.random_normal([self.minibatch_per_gpu] + Gs_clone.input_shape[1:]) labels = self._get_random_labels_tf(self.minibatch_per_gpu) images = Gs_clone.get_output_for(latents, labels, **Gs_kwargs) images = tflib.convert_images_to_uint8(images) result_expr.append(inception_clone.get_output_for(images)) # Calculate statistics for fakes. for begin in range(0, self.num_images, minibatch_size): self._report_progress(begin, self.num_images) end = min(begin + minibatch_size, self.num_images) activations[begin:end] = np.concatenate(tflib.run(result_expr), axis=0)[:end-begin] mu_fake = np.mean(activations, axis=0) sigma_fake = np.cov(activations, rowvar=False) # Calculate FID. m = np.square(mu_fake - mu_real).sum() s, _ = scipy.linalg.sqrtm(np.dot(sigma_fake, sigma_real), disp=False) # pylint: disable=no-member dist = m + np.trace(sigma_fake + sigma_real - 2*s) self._report_result(np.real(dist)) #---------------------------------------------------------------------------- ================================================ FILE: stylegan2-tpu/metrics/inception_score.py ================================================ # Copyright (c) 2019, NVIDIA Corporation. All rights reserved. # # This work is made available under the Nvidia Source Code License-NC. # To view a copy of this license, visit # https://nvlabs.github.io/stylegan2/license.html """Inception Score (IS).""" import numpy as np import tensorflow as tf import tflex import dnnlib.tflib as tflib from metrics import metric_base from training import misc #---------------------------------------------------------------------------- class IS(metric_base.MetricBase): def __init__(self, num_images, num_splits, minibatch_per_gpu, **kwargs): super().__init__(**kwargs) self.num_images = num_images self.num_splits = num_splits self.minibatch_per_gpu = minibatch_per_gpu def _evaluate(self, Gs, Gs_kwargs, num_gpus): minibatch_size = num_gpus * self.minibatch_per_gpu inception = misc.load_pkl('https://drive.google.com/uc?id=1Mz9zQnIrusm3duZB91ng_aUIePFNI6Jx', 'inception_v3_softmax.pkl') activations = np.empty([self.num_images, inception.output_shape[1]], dtype=np.float32) # Construct TensorFlow graph. result_expr = [] for gpu_idx in range(num_gpus): with tflex.device('/gpu:%d' % gpu_idx): Gs_clone = Gs.clone() inception_clone = inception.clone() latents = tf.random_normal([self.minibatch_per_gpu] + Gs_clone.input_shape[1:]) labels = self._get_random_labels_tf(self.minibatch_per_gpu) images = Gs_clone.get_output_for(latents, labels, **Gs_kwargs) images = tflib.convert_images_to_uint8(images) result_expr.append(inception_clone.get_output_for(images)) # Calculate activations for fakes. for begin in range(0, self.num_images, minibatch_size): self._report_progress(begin, self.num_images) end = min(begin + minibatch_size, self.num_images) activations[begin:end] = np.concatenate(tflib.run(result_expr), axis=0)[:end-begin] # Calculate IS. scores = [] for i in range(self.num_splits): part = activations[i * self.num_images // self.num_splits : (i + 1) * self.num_images // self.num_splits] kl = part * (np.log(part) - np.log(np.expand_dims(np.mean(part, 0), 0))) kl = np.mean(np.sum(kl, 1)) scores.append(np.exp(kl)) self._report_result(np.mean(scores), suffix='_mean') self._report_result(np.std(scores), suffix='_std') #---------------------------------------------------------------------------- ================================================ FILE: stylegan2-tpu/metrics/linear_separability.py ================================================ # Copyright (c) 2019, NVIDIA Corporation. All rights reserved. # # This work is made available under the Nvidia Source Code License-NC. # To view a copy of this license, visit # https://nvlabs.github.io/stylegan2/license.html """Linear Separability (LS).""" from collections import defaultdict import numpy as np import sklearn.svm import tensorflow as tf import tflex import dnnlib.tflib as tflib from metrics import metric_base from training import misc #---------------------------------------------------------------------------- classifier_urls = [ 'https://drive.google.com/uc?id=1Q5-AI6TwWhCVM7Muu4tBM7rp5nG_gmCX', # celebahq-classifier-00-male.pkl 'https://drive.google.com/uc?id=1Q5c6HE__ReW2W8qYAXpao68V1ryuisGo', # celebahq-classifier-01-smiling.pkl 'https://drive.google.com/uc?id=1Q7738mgWTljPOJQrZtSMLxzShEhrvVsU', # celebahq-classifier-02-attractive.pkl 'https://drive.google.com/uc?id=1QBv2Mxe7ZLvOv1YBTLq-T4DS3HjmXV0o', # celebahq-classifier-03-wavy-hair.pkl 'https://drive.google.com/uc?id=1QIvKTrkYpUrdA45nf7pspwAqXDwWOLhV', # celebahq-classifier-04-young.pkl 'https://drive.google.com/uc?id=1QJPH5rW7MbIjFUdZT7vRYfyUjNYDl4_L', # celebahq-classifier-05-5-o-clock-shadow.pkl 'https://drive.google.com/uc?id=1QPZXSYf6cptQnApWS_T83sqFMun3rULY', # celebahq-classifier-06-arched-eyebrows.pkl 'https://drive.google.com/uc?id=1QPgoAZRqINXk_PFoQ6NwMmiJfxc5d2Pg', # celebahq-classifier-07-bags-under-eyes.pkl 'https://drive.google.com/uc?id=1QQPQgxgI6wrMWNyxFyTLSgMVZmRr1oO7', # celebahq-classifier-08-bald.pkl 'https://drive.google.com/uc?id=1QcSphAmV62UrCIqhMGgcIlZfoe8hfWaF', # celebahq-classifier-09-bangs.pkl 'https://drive.google.com/uc?id=1QdWTVwljClTFrrrcZnPuPOR4mEuz7jGh', # celebahq-classifier-10-big-lips.pkl 'https://drive.google.com/uc?id=1QgvEWEtr2mS4yj1b_Y3WKe6cLWL3LYmK', # celebahq-classifier-11-big-nose.pkl 'https://drive.google.com/uc?id=1QidfMk9FOKgmUUIziTCeo8t-kTGwcT18', # celebahq-classifier-12-black-hair.pkl 'https://drive.google.com/uc?id=1QthrJt-wY31GPtV8SbnZQZ0_UEdhasHO', # celebahq-classifier-13-blond-hair.pkl 'https://drive.google.com/uc?id=1QvCAkXxdYT4sIwCzYDnCL9Nb5TDYUxGW', # celebahq-classifier-14-blurry.pkl 'https://drive.google.com/uc?id=1QvLWuwSuWI9Ln8cpxSGHIciUsnmaw8L0', # celebahq-classifier-15-brown-hair.pkl 'https://drive.google.com/uc?id=1QxW6THPI2fqDoiFEMaV6pWWHhKI_OoA7', # celebahq-classifier-16-bushy-eyebrows.pkl 'https://drive.google.com/uc?id=1R71xKw8oTW2IHyqmRDChhTBkW9wq4N9v', # celebahq-classifier-17-chubby.pkl 'https://drive.google.com/uc?id=1RDn_fiLfEGbTc7JjazRXuAxJpr-4Pl67', # celebahq-classifier-18-double-chin.pkl 'https://drive.google.com/uc?id=1RGBuwXbaz5052bM4VFvaSJaqNvVM4_cI', # celebahq-classifier-19-eyeglasses.pkl 'https://drive.google.com/uc?id=1RIxOiWxDpUwhB-9HzDkbkLegkd7euRU9', # celebahq-classifier-20-goatee.pkl 'https://drive.google.com/uc?id=1RPaNiEnJODdr-fwXhUFdoSQLFFZC7rC-', # celebahq-classifier-21-gray-hair.pkl 'https://drive.google.com/uc?id=1RQH8lPSwOI2K_9XQCZ2Ktz7xm46o80ep', # celebahq-classifier-22-heavy-makeup.pkl 'https://drive.google.com/uc?id=1RXZM61xCzlwUZKq-X7QhxOg0D2telPow', # celebahq-classifier-23-high-cheekbones.pkl 'https://drive.google.com/uc?id=1RgASVHW8EWMyOCiRb5fsUijFu-HfxONM', # celebahq-classifier-24-mouth-slightly-open.pkl 'https://drive.google.com/uc?id=1RkC8JLqLosWMaRne3DARRgolhbtg_wnr', # celebahq-classifier-25-mustache.pkl 'https://drive.google.com/uc?id=1RqtbtFT2EuwpGTqsTYJDyXdnDsFCPtLO', # celebahq-classifier-26-narrow-eyes.pkl 'https://drive.google.com/uc?id=1Rs7hU-re8bBMeRHR-fKgMbjPh-RIbrsh', # celebahq-classifier-27-no-beard.pkl 'https://drive.google.com/uc?id=1RynDJQWdGOAGffmkPVCrLJqy_fciPF9E', # celebahq-classifier-28-oval-face.pkl 'https://drive.google.com/uc?id=1S0TZ_Hdv5cb06NDaCD8NqVfKy7MuXZsN', # celebahq-classifier-29-pale-skin.pkl 'https://drive.google.com/uc?id=1S3JPhZH2B4gVZZYCWkxoRP11q09PjCkA', # celebahq-classifier-30-pointy-nose.pkl 'https://drive.google.com/uc?id=1S3pQuUz-Jiywq_euhsfezWfGkfzLZ87W', # celebahq-classifier-31-receding-hairline.pkl 'https://drive.google.com/uc?id=1S6nyIl_SEI3M4l748xEdTV2vymB_-lrY', # celebahq-classifier-32-rosy-cheeks.pkl 'https://drive.google.com/uc?id=1S9P5WCi3GYIBPVYiPTWygrYIUSIKGxbU', # celebahq-classifier-33-sideburns.pkl 'https://drive.google.com/uc?id=1SANviG-pp08n7AFpE9wrARzozPIlbfCH', # celebahq-classifier-34-straight-hair.pkl 'https://drive.google.com/uc?id=1SArgyMl6_z7P7coAuArqUC2zbmckecEY', # celebahq-classifier-35-wearing-earrings.pkl 'https://drive.google.com/uc?id=1SC5JjS5J-J4zXFO9Vk2ZU2DT82TZUza_', # celebahq-classifier-36-wearing-hat.pkl 'https://drive.google.com/uc?id=1SDAQWz03HGiu0MSOKyn7gvrp3wdIGoj-', # celebahq-classifier-37-wearing-lipstick.pkl 'https://drive.google.com/uc?id=1SEtrVK-TQUC0XeGkBE9y7L8VXfbchyKX', # celebahq-classifier-38-wearing-necklace.pkl 'https://drive.google.com/uc?id=1SF_mJIdyGINXoV-I6IAxHB_k5dxiF6M-', # celebahq-classifier-39-wearing-necktie.pkl ] #---------------------------------------------------------------------------- def prob_normalize(p): p = np.asarray(p).astype(np.float32) assert len(p.shape) == 2 return p / np.sum(p) def mutual_information(p): p = prob_normalize(p) px = np.sum(p, axis=1) py = np.sum(p, axis=0) result = 0.0 for x in range(p.shape[0]): p_x = px[x] for y in range(p.shape[1]): p_xy = p[x][y] p_y = py[y] if p_xy > 0.0: result += p_xy * np.log2(p_xy / (p_x * p_y)) # get bits as output return result def entropy(p): p = prob_normalize(p) result = 0.0 for x in range(p.shape[0]): for y in range(p.shape[1]): p_xy = p[x][y] if p_xy > 0.0: result -= p_xy * np.log2(p_xy) return result def conditional_entropy(p): # H(Y|X) where X corresponds to axis 0, Y to axis 1 # i.e., How many bits of additional information are needed to where we are on axis 1 if we know where we are on axis 0? p = prob_normalize(p) y = np.sum(p, axis=0, keepdims=True) # marginalize to calculate H(Y) return max(0.0, entropy(y) - mutual_information(p)) # can slip just below 0 due to FP inaccuracies, clean those up. #---------------------------------------------------------------------------- class LS(metric_base.MetricBase): def __init__(self, num_samples, num_keep, attrib_indices, minibatch_per_gpu, **kwargs): assert num_keep <= num_samples super().__init__(**kwargs) self.num_samples = num_samples self.num_keep = num_keep self.attrib_indices = attrib_indices self.minibatch_per_gpu = minibatch_per_gpu def _evaluate(self, Gs, Gs_kwargs, num_gpus): minibatch_size = num_gpus * self.minibatch_per_gpu # Construct TensorFlow graph for each GPU. result_expr = [] for gpu_idx in range(num_gpus): with tflex.device('/gpu:%d' % gpu_idx): Gs_clone = Gs.clone() # Generate images. latents = tf.random_normal([self.minibatch_per_gpu] + Gs_clone.input_shape[1:]) labels = self._get_random_labels_tf(self.minibatch_per_gpu) dlatents = Gs_clone.components.mapping.get_output_for(latents, labels, **Gs_kwargs) images = Gs_clone.get_output_for(latents, None, **Gs_kwargs) # Downsample to 256x256. The attribute classifiers were built for 256x256. if images.shape[2] > 256: factor = images.shape[2] // 256 images = tf.reshape(images, [-1, images.shape[1], images.shape[2] // factor, factor, images.shape[3] // factor, factor]) images = tf.reduce_mean(images, axis=[3, 5]) # Run classifier for each attribute. result_dict = dict(latents=latents, dlatents=dlatents[:,-1]) for attrib_idx in self.attrib_indices: classifier = misc.load_pkl(classifier_urls[attrib_idx]) logits = classifier.get_output_for(images, None) predictions = tf.nn.softmax(tf.concat([logits, -logits], axis=1)) result_dict[attrib_idx] = predictions result_expr.append(result_dict) # Sampling loop. results = [] for begin in range(0, self.num_samples, minibatch_size): self._report_progress(begin, self.num_samples) results += tflib.run(result_expr) results = {key: np.concatenate([value[key] for value in results], axis=0) for key in results[0].keys()} # Calculate conditional entropy for each attribute. conditional_entropies = defaultdict(list) for attrib_idx in self.attrib_indices: # Prune the least confident samples. pruned_indices = list(range(self.num_samples)) pruned_indices = sorted(pruned_indices, key=lambda i: -np.max(results[attrib_idx][i])) pruned_indices = pruned_indices[:self.num_keep] # Fit SVM to the remaining samples. svm_targets = np.argmax(results[attrib_idx][pruned_indices], axis=1) for space in ['latents', 'dlatents']: svm_inputs = results[space][pruned_indices] try: svm = sklearn.svm.LinearSVC() svm.fit(svm_inputs, svm_targets) svm.score(svm_inputs, svm_targets) svm_outputs = svm.predict(svm_inputs) except: svm_outputs = svm_targets # assume perfect prediction # Calculate conditional entropy. p = [[np.mean([case == (row, col) for case in zip(svm_outputs, svm_targets)]) for col in (0, 1)] for row in (0, 1)] conditional_entropies[space].append(conditional_entropy(p)) # Calculate separability scores. scores = {key: 2**np.sum(values) for key, values in conditional_entropies.items()} self._report_result(scores['latents'], suffix='_z') self._report_result(scores['dlatents'], suffix='_w') #---------------------------------------------------------------------------- ================================================ FILE: stylegan2-tpu/metrics/metric_base.py ================================================ # Copyright (c) 2019, NVIDIA Corporation. All rights reserved. # # This work is made available under the Nvidia Source Code License-NC. # To view a copy of this license, visit # https://nvlabs.github.io/stylegan2/license.html """Common definitions for GAN metrics.""" import os import time import hashlib import numpy as np import tensorflow as tf import dnnlib import dnnlib.tflib as tflib from training import misc from training import dataset #---------------------------------------------------------------------------- # Base class for metrics. class MetricBase: def __init__(self, name): self.name = name self._dataset_obj = None self._progress_lo = None self._progress_hi = None self._progress_max = None self._progress_sec = None self._progress_time = None self._reset() def close(self): self._reset() def _reset(self, network_pkl=None, run_dir=None, data_dir=None, dataset_args=None, mirror_augment=None): if self._dataset_obj is not None: self._dataset_obj.close() self._network_pkl = network_pkl self._data_dir = data_dir self._dataset_args = dataset_args self._dataset_obj = None self._mirror_augment = mirror_augment self._eval_time = 0 self._results = [] if (dataset_args is None or mirror_augment is None) and run_dir is not None: run_config = misc.parse_config_for_previous_run(run_dir) self._dataset_args = dict(run_config['dataset']) self._dataset_args['shuffle_mb'] = 0 self._mirror_augment = run_config['train'].get('mirror_augment', False) def configure_progress_reports(self, plo, phi, pmax, psec=15): self._progress_lo = plo self._progress_hi = phi self._progress_max = pmax self._progress_sec = psec def run(self, network_pkl, run_dir=None, data_dir=None, dataset_args=None, mirror_augment=None, num_gpus=1, tf_config=None, log_results=True, Gs_kwargs=dict(is_validation=True)): self._reset(network_pkl=network_pkl, run_dir=run_dir, data_dir=data_dir, dataset_args=dataset_args, mirror_augment=mirror_augment) time_begin = time.time() with tf.Graph().as_default(), tflib.create_session(tf_config).as_default(): # pylint: disable=not-context-manager self._report_progress(0, 1) _G, _D, Gs = misc.load_pkl(self._network_pkl) self._evaluate(Gs, Gs_kwargs=Gs_kwargs, num_gpus=num_gpus) self._report_progress(1, 1) self._eval_time = time.time() - time_begin # pylint: disable=attribute-defined-outside-init if log_results: if run_dir is not None: log_file = os.path.join(run_dir, 'metric-%s.txt' % self.name) with dnnlib.util.Logger(log_file, 'a'): print(self.get_result_str().strip()) else: print(self.get_result_str().strip()) def get_result_str(self): network_name = os.path.splitext(os.path.basename(self._network_pkl))[0] if len(network_name) > 29: network_name = '...' + network_name[-26:] result_str = '%-30s' % network_name result_str += ' time %-12s' % dnnlib.util.format_time(self._eval_time) for res in self._results: result_str += ' ' + self.name + res.suffix + ' ' result_str += res.fmt % res.value return result_str def update_autosummaries(self): for res in self._results: tflib.autosummary.autosummary('Metrics/' + self.name + res.suffix, res.value) def _evaluate(self, Gs, Gs_kwargs, num_gpus): raise NotImplementedError # to be overridden by subclasses def _report_result(self, value, suffix='', fmt='%-10.4f'): self._results += [dnnlib.EasyDict(value=value, suffix=suffix, fmt=fmt)] def _report_progress(self, pcur, pmax, status_str=''): if self._progress_lo is None or self._progress_hi is None or self._progress_max is None: return t = time.time() if self._progress_sec is not None and self._progress_time is not None and t < self._progress_time + self._progress_sec: return self._progress_time = t val = self._progress_lo + (pcur / pmax) * (self._progress_hi - self._progress_lo) dnnlib.RunContext.get().update(status_str, int(val), self._progress_max) def _get_cache_file_for_reals(self, extension='pkl', **kwargs): all_args = dnnlib.EasyDict(metric_name=self.name, mirror_augment=self._mirror_augment) all_args.update(self._dataset_args) all_args.update(kwargs) md5 = hashlib.md5(repr(sorted(all_args.items())).encode('utf-8')) dataset_name = self._dataset_args.get('tfrecord_dir', None) or self._dataset_args.get('h5_file', None) dataset_name = os.path.splitext(os.path.basename(dataset_name))[0] return os.path.join('.stylegan2-cache', '%s-%s-%s.%s' % (md5.hexdigest(), self.name, dataset_name, extension)) def _get_dataset_obj(self): if self._dataset_obj is None: self._dataset_obj = dataset.load_dataset(data_dir=self._data_dir, **self._dataset_args) return self._dataset_obj def _iterate_reals(self, minibatch_size): dataset_obj = self._get_dataset_obj() while True: images, _labels = dataset_obj.get_minibatch_np(minibatch_size) if self._mirror_augment: images = misc.apply_mirror_augment(images) yield images def _iterate_fakes(self, Gs, minibatch_size, num_gpus): while True: latents = np.random.randn(minibatch_size, *Gs.input_shape[1:]) fmt = dict(func=tflib.convert_images_to_uint8, nchw_to_nhwc=True) images = Gs.run(latents, None, output_transform=fmt, is_validation=True, num_gpus=num_gpus, assume_frozen=True) yield images def _get_random_labels_tf(self, minibatch_size): return self._get_dataset_obj().get_random_labels_tf(minibatch_size) #---------------------------------------------------------------------------- # Group of multiple metrics. class MetricGroup: def __init__(self, metric_kwarg_list): self.metrics = [dnnlib.util.call_func_by_name(**kwargs) for kwargs in metric_kwarg_list] def run(self, *args, **kwargs): for metric in self.metrics: metric.run(*args, **kwargs) def get_result_str(self): return ' '.join(metric.get_result_str() for metric in self.metrics) def update_autosummaries(self): for metric in self.metrics: metric.update_autosummaries() #---------------------------------------------------------------------------- # Dummy metric for debugging purposes. class DummyMetric(MetricBase): def _evaluate(self, Gs, Gs_kwargs, num_gpus): _ = Gs, Gs_kwargs, num_gpus self._report_result(0.0) #---------------------------------------------------------------------------- ================================================ FILE: stylegan2-tpu/metrics/metric_defaults.py ================================================ # Copyright (c) 2019, NVIDIA Corporation. All rights reserved. # # This work is made available under the Nvidia Source Code License-NC. # To view a copy of this license, visit # https://nvlabs.github.io/stylegan2/license.html """Default metric definitions.""" from dnnlib import EasyDict #---------------------------------------------------------------------------- metric_defaults = EasyDict([(args.name, args) for args in [ EasyDict(name='fid50k', func_name='metrics.frechet_inception_distance.FID', num_images=50000, minibatch_per_gpu=8), EasyDict(name='is50k', func_name='metrics.inception_score.IS', num_images=50000, num_splits=10, minibatch_per_gpu=8), EasyDict(name='ppl_zfull', func_name='metrics.perceptual_path_length.PPL', num_samples=50000, epsilon=1e-4, space='z', sampling='full', crop=True, minibatch_per_gpu=4, Gs_overrides=dict(dtype='float32', mapping_dtype='float32')), EasyDict(name='ppl_wfull', func_name='metrics.perceptual_path_length.PPL', num_samples=50000, epsilon=1e-4, space='w', sampling='full', crop=True, minibatch_per_gpu=4, Gs_overrides=dict(dtype='float32', mapping_dtype='float32')), EasyDict(name='ppl_zend', func_name='metrics.perceptual_path_length.PPL', num_samples=50000, epsilon=1e-4, space='z', sampling='end', crop=True, minibatch_per_gpu=4, Gs_overrides=dict(dtype='float32', mapping_dtype='float32')), EasyDict(name='ppl_wend', func_name='metrics.perceptual_path_length.PPL', num_samples=50000, epsilon=1e-4, space='w', sampling='end', crop=True, minibatch_per_gpu=4, Gs_overrides=dict(dtype='float32', mapping_dtype='float32')), EasyDict(name='ppl2_wend', func_name='metrics.perceptual_path_length.PPL', num_samples=50000, epsilon=1e-4, space='w', sampling='end', crop=False, minibatch_per_gpu=4, Gs_overrides=dict(dtype='float32', mapping_dtype='float32')), EasyDict(name='ls', func_name='metrics.linear_separability.LS', num_samples=200000, num_keep=100000, attrib_indices=range(40), minibatch_per_gpu=4), EasyDict(name='pr50k3', func_name='metrics.precision_recall.PR', num_images=50000, nhood_size=3, minibatch_per_gpu=8, row_batch_size=10000, col_batch_size=10000), ]]) #---------------------------------------------------------------------------- ================================================ FILE: stylegan2-tpu/metrics/perceptual_path_length.py ================================================ # Copyright (c) 2019, NVIDIA Corporation. All rights reserved. # # This work is made available under the Nvidia Source Code License-NC. # To view a copy of this license, visit # https://nvlabs.github.io/stylegan2/license.html """Perceptual Path Length (PPL).""" import numpy as np import tensorflow as tf import tflex import dnnlib.tflib as tflib from metrics import metric_base from training import misc #---------------------------------------------------------------------------- # Normalize batch of vectors. def normalize(v): return v / tf.sqrt(tf.reduce_sum(tf.square(v), axis=-1, keepdims=True)) # Spherical interpolation of a batch of vectors. def slerp(a, b, t): a = normalize(a) b = normalize(b) d = tf.reduce_sum(a * b, axis=-1, keepdims=True) p = t * tf.math.acos(d) c = normalize(b - d * a) d = a * tf.math.cos(p) + c * tf.math.sin(p) return normalize(d) #---------------------------------------------------------------------------- class PPL(metric_base.MetricBase): def __init__(self, num_samples, epsilon, space, sampling, crop, minibatch_per_gpu, Gs_overrides, **kwargs): assert space in ['z', 'w'] assert sampling in ['full', 'end'] super().__init__(**kwargs) self.num_samples = num_samples self.epsilon = epsilon self.space = space self.sampling = sampling self.crop = crop self.minibatch_per_gpu = minibatch_per_gpu self.Gs_overrides = Gs_overrides def _evaluate(self, Gs, Gs_kwargs, num_gpus): Gs_kwargs = dict(Gs_kwargs) Gs_kwargs.update(self.Gs_overrides) minibatch_size = num_gpus * self.minibatch_per_gpu # Construct TensorFlow graph. distance_expr = [] for gpu_idx in range(num_gpus): with tflex.device('/gpu:%d' % gpu_idx): Gs_clone = Gs.clone() noise_vars = [var for name, var in Gs_clone.components.synthesis.vars.items() if name.startswith('noise')] # Generate random latents and interpolation t-values. lat_t01 = tf.random_normal([self.minibatch_per_gpu * 2] + Gs_clone.input_shape[1:]) lerp_t = tf.random_uniform([self.minibatch_per_gpu], 0.0, 1.0 if self.sampling == 'full' else 0.0) labels = tf.reshape(tf.tile(self._get_random_labels_tf(self.minibatch_per_gpu), [1, 2]), [self.minibatch_per_gpu * 2, -1]) # Interpolate in W or Z. if self.space == 'w': dlat_t01 = Gs_clone.components.mapping.get_output_for(lat_t01, labels, **Gs_kwargs) dlat_t01 = tf.cast(dlat_t01, tf.float32) dlat_t0, dlat_t1 = dlat_t01[0::2], dlat_t01[1::2] dlat_e0 = tflib.lerp(dlat_t0, dlat_t1, lerp_t[:, np.newaxis, np.newaxis]) dlat_e1 = tflib.lerp(dlat_t0, dlat_t1, lerp_t[:, np.newaxis, np.newaxis] + self.epsilon) dlat_e01 = tf.reshape(tf.stack([dlat_e0, dlat_e1], axis=1), dlat_t01.shape) else: # space == 'z' lat_t0, lat_t1 = lat_t01[0::2], lat_t01[1::2] lat_e0 = slerp(lat_t0, lat_t1, lerp_t[:, np.newaxis]) lat_e1 = slerp(lat_t0, lat_t1, lerp_t[:, np.newaxis] + self.epsilon) lat_e01 = tf.reshape(tf.stack([lat_e0, lat_e1], axis=1), lat_t01.shape) dlat_e01 = Gs_clone.components.mapping.get_output_for(lat_e01, labels, **Gs_kwargs) # Synthesize images. with tf.control_dependencies([var.initializer for var in noise_vars]): # use same noise inputs for the entire minibatch images = Gs_clone.components.synthesis.get_output_for(dlat_e01, randomize_noise=False, **Gs_kwargs) images = tf.cast(images, tf.float32) # Crop only the face region. if self.crop: c = int(images.shape[2] // 8) images = images[:, :, c*3 : c*7, c*2 : c*6] # Downsample image to 256x256 if it's larger than that. VGG was built for 224x224 images. factor = images.shape[2] // 256 if factor > 1: images = tf.reshape(images, [-1, images.shape[1], images.shape[2] // factor, factor, images.shape[3] // factor, factor]) images = tf.reduce_mean(images, axis=[3,5]) # Scale dynamic range from [-1,1] to [0,255] for VGG. images = (images + 1) * (255 / 2) # Evaluate perceptual distance. img_e0, img_e1 = images[0::2], images[1::2] distance_measure = misc.load_pkl('https://drive.google.com/uc?id=1N2-m9qszOeVC9Tq77WxsLnuWwOedQiD2', 'vgg16_zhang_perceptual.pkl') distance_expr.append(distance_measure.get_output_for(img_e0, img_e1) * (1 / self.epsilon**2)) # Sampling loop. all_distances = [] for begin in range(0, self.num_samples, minibatch_size): self._report_progress(begin, self.num_samples) all_distances += tflib.run(distance_expr) all_distances = np.concatenate(all_distances, axis=0) # Reject outliers. lo = np.percentile(all_distances, 1, interpolation='lower') hi = np.percentile(all_distances, 99, interpolation='higher') filtered_distances = np.extract(np.logical_and(lo <= all_distances, all_distances <= hi), all_distances) self._report_result(np.mean(filtered_distances)) #---------------------------------------------------------------------------- ================================================ FILE: stylegan2-tpu/metrics/precision_recall.py ================================================ # Copyright (c) 2019, NVIDIA Corporation. All rights reserved. # # This work is made available under the Nvidia Source Code License-NC. # To view a copy of this license, visit # https://nvlabs.github.io/stylegan2/license.html """Precision/Recall (PR).""" import os import numpy as np import tensorflow as tf import tflex import dnnlib import dnnlib.tflib as tflib from metrics import metric_base from training import misc #---------------------------------------------------------------------------- def batch_pairwise_distances(U, V): """ Compute pairwise distances between two batches of feature vectors.""" with tf.variable_scope('pairwise_dist_block'): # Squared norms of each row in U and V. norm_u = tf.reduce_sum(tf.square(U), 1) norm_v = tf.reduce_sum(tf.square(V), 1) # norm_u as a row and norm_v as a column vectors. norm_u = tf.reshape(norm_u, [-1, 1]) norm_v = tf.reshape(norm_v, [1, -1]) # Pairwise squared Euclidean distances. D = tf.maximum(norm_u - 2*tf.matmul(U, V, False, True) + norm_v, 0.0) return D #---------------------------------------------------------------------------- class DistanceBlock(): """Distance block.""" def __init__(self, num_features, num_gpus): self.num_features = num_features self.num_gpus = num_gpus # Initialize TF graph to calculate pairwise distances. with tflex.device('/cpu:0'): self._features_batch1 = tf.placeholder(tf.float16, shape=[None, self.num_features]) self._features_batch2 = tf.placeholder(tf.float16, shape=[None, self.num_features]) features_split2 = tf.split(self._features_batch2, self.num_gpus, axis=0) distances_split = [] for gpu_idx in range(self.num_gpus): with tflex.device('/gpu:%d' % gpu_idx): distances_split.append(batch_pairwise_distances(self._features_batch1, features_split2[gpu_idx])) self._distance_block = tf.concat(distances_split, axis=1) def pairwise_distances(self, U, V): """Evaluate pairwise distances between two batches of feature vectors.""" return self._distance_block.eval(feed_dict={self._features_batch1: U, self._features_batch2: V}) #---------------------------------------------------------------------------- class ManifoldEstimator(): """Finds an estimate for the manifold of given feature vectors.""" def __init__(self, distance_block, features, row_batch_size, col_batch_size, nhood_sizes, clamp_to_percentile=None): """Find an estimate of the manifold of given feature vectors.""" num_images = features.shape[0] self.nhood_sizes = nhood_sizes self.num_nhoods = len(nhood_sizes) self.row_batch_size = row_batch_size self.col_batch_size = col_batch_size self._ref_features = features self._distance_block = distance_block # Estimate manifold of features by calculating distances to kth nearest neighbor of each sample. self.D = np.zeros([num_images, self.num_nhoods], dtype=np.float16) distance_batch = np.zeros([row_batch_size, num_images], dtype=np.float16) seq = np.arange(max(self.nhood_sizes) + 1, dtype=np.int32) for begin1 in range(0, num_images, row_batch_size): end1 = min(begin1 + row_batch_size, num_images) row_batch = features[begin1:end1] for begin2 in range(0, num_images, col_batch_size): end2 = min(begin2 + col_batch_size, num_images) col_batch = features[begin2:end2] # Compute distances between batches. distance_batch[0:end1-begin1, begin2:end2] = self._distance_block.pairwise_distances(row_batch, col_batch) # Find the kth nearest neighbor from the current batch. self.D[begin1:end1, :] = np.partition(distance_batch[0:end1-begin1, :], seq, axis=1)[:, self.nhood_sizes] if clamp_to_percentile is not None: max_distances = np.percentile(self.D, clamp_to_percentile, axis=0) self.D[self.D > max_distances] = 0 #max_distances # 0 def evaluate(self, eval_features, return_realism=False, return_neighbors=False): """Evaluate if new feature vectors are in the estimated manifold.""" num_eval_images = eval_features.shape[0] num_ref_images = self.D.shape[0] distance_batch = np.zeros([self.row_batch_size, num_ref_images], dtype=np.float16) batch_predictions = np.zeros([num_eval_images, self.num_nhoods], dtype=np.int32) #max_realism_score = np.zeros([num_eval_images,], dtype=np.float32) realism_score = np.zeros([num_eval_images,], dtype=np.float32) nearest_indices = np.zeros([num_eval_images,], dtype=np.int32) for begin1 in range(0, num_eval_images, self.row_batch_size): end1 = min(begin1 + self.row_batch_size, num_eval_images) feature_batch = eval_features[begin1:end1] for begin2 in range(0, num_ref_images, self.col_batch_size): end2 = min(begin2 + self.col_batch_size, num_ref_images) ref_batch = self._ref_features[begin2:end2] distance_batch[0:end1-begin1, begin2:end2] = self._distance_block.pairwise_distances(feature_batch, ref_batch) # From the minibatch of new feature vectors, determine if they are in the estimated manifold. # If a feature vector is inside a hypersphere of some reference sample, then the new sample lies on the estimated manifold. # The radii of the hyperspheres are determined from distances of neighborhood size k. samples_in_manifold = distance_batch[0:end1-begin1, :, None] <= self.D batch_predictions[begin1:end1] = np.any(samples_in_manifold, axis=1).astype(np.int32) #max_realism_score[begin1:end1] = np.max(self.D[:, 0] / (distance_batch[0:end1-begin1, :] + 1e-18), axis=1) #nearest_indices[begin1:end1] = np.argmax(self.D[:, 0] / (distance_batch[0:end1-begin1, :] + 1e-18), axis=1) nearest_indices[begin1:end1] = np.argmin(distance_batch[0:end1-begin1, :], axis=1) realism_score[begin1:end1] = self.D[nearest_indices[begin1:end1], 0] / np.min(distance_batch[0:end1-begin1, :], axis=1) if return_realism and return_neighbors: return batch_predictions, realism_score, nearest_indices elif return_realism: return batch_predictions, realism_score elif return_neighbors: return batch_predictions, nearest_indices return batch_predictions #---------------------------------------------------------------------------- def knn_precision_recall_features(ref_features, eval_features, feature_net, nhood_sizes, row_batch_size, col_batch_size, num_gpus): """Calculates k-NN precision and recall for two sets of feature vectors.""" state = dnnlib.EasyDict() #num_images = ref_features.shape[0] num_features = feature_net.output_shape[1] state.ref_features = ref_features state.eval_features = eval_features # Initialize DistanceBlock and ManifoldEstimators. distance_block = DistanceBlock(num_features, num_gpus) state.ref_manifold = ManifoldEstimator(distance_block, state.ref_features, row_batch_size, col_batch_size, nhood_sizes) state.eval_manifold = ManifoldEstimator(distance_block, state.eval_features, row_batch_size, col_batch_size, nhood_sizes) # Evaluate precision and recall using k-nearest neighbors. #print('Evaluating k-NN precision and recall with %i samples...' % num_images) #start = time.time() # Precision: How many points from eval_features are in ref_features manifold. state.precision, state.realism_scores, state.nearest_neighbors = state.ref_manifold.evaluate(state.eval_features, return_realism=True, return_neighbors=True) state.knn_precision = state.precision.mean(axis=0) # Recall: How many points from ref_features are in eval_features manifold. state.recall = state.eval_manifold.evaluate(state.ref_features) state.knn_recall = state.recall.mean(axis=0) #elapsed_time = time.time() - start #print('Done evaluation in: %gs' % elapsed_time) return state #---------------------------------------------------------------------------- class PR(metric_base.MetricBase): def __init__(self, num_images, nhood_size, minibatch_per_gpu, row_batch_size, col_batch_size, **kwargs): super().__init__(**kwargs) self.num_images = num_images self.nhood_size = nhood_size self.minibatch_per_gpu = minibatch_per_gpu self.row_batch_size = row_batch_size self.col_batch_size = col_batch_size def _evaluate(self, Gs, Gs_kwargs, num_gpus): minibatch_size = num_gpus * self.minibatch_per_gpu feature_net = misc.load_pkl('https://drive.google.com/uc?id=1MzY4MFpZzE-mNS26pzhYlWN-4vMm2ytu', 'vgg16.pkl') # Calculate features for reals. cache_file = self._get_cache_file_for_reals(num_images=self.num_images) os.makedirs(os.path.dirname(cache_file), exist_ok=True) if os.path.isfile(cache_file): ref_features = misc.load_pkl(cache_file) else: ref_features = np.empty([self.num_images, feature_net.output_shape[1]], dtype=np.float32) for idx, images in enumerate(self._iterate_reals(minibatch_size=minibatch_size)): begin = idx * minibatch_size end = min(begin + minibatch_size, self.num_images) ref_features[begin:end] = feature_net.run(images[:end-begin], num_gpus=num_gpus, assume_frozen=True) if end == self.num_images: break misc.save_pkl(ref_features, cache_file) # Construct TensorFlow graph. result_expr = [] for gpu_idx in range(num_gpus): with tflex.device('/gpu:%d' % gpu_idx): Gs_clone = Gs.clone() feature_net_clone = feature_net.clone() latents = tf.random_normal([self.minibatch_per_gpu] + Gs_clone.input_shape[1:]) labels = self._get_random_labels_tf(self.minibatch_per_gpu) images = Gs_clone.get_output_for(latents, labels, **Gs_kwargs) images = tflib.convert_images_to_uint8(images) result_expr.append(feature_net_clone.get_output_for(images)) # Calculate features for fakes. eval_features = np.empty([self.num_images, feature_net.output_shape[1]], dtype=np.float32) for begin in range(0, self.num_images, minibatch_size): self._report_progress(begin, self.num_images) end = min(begin + minibatch_size, self.num_images) eval_features[begin:end] = np.concatenate(tflib.run(result_expr), axis=0)[:end-begin] # Calculate precision and recall. state = knn_precision_recall_features(ref_features=ref_features, eval_features=eval_features, feature_net=feature_net, nhood_sizes=[self.nhood_size], row_batch_size=self.row_batch_size, col_batch_size=self.row_batch_size, num_gpus=num_gpus) self._report_result(state.knn_precision[0], suffix='_precision') self._report_result(state.knn_recall[0], suffix='_recall') #---------------------------------------------------------------------------- ================================================ FILE: stylegan2-tpu/prepare_image.py ================================================ #!/usr/bin/env python3 # Copyright 2018 The TensorFlow Authors. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import argparse import datetime import os import shutil import subprocess import sys import tensorflow.compat.v1 as tf class Namespace(): pass me = Namespace() def _int64_feature(value): """Wrapper for inserting int64 features into Example proto.""" if not isinstance(value, list): value = [value] return tf.train.Feature(int64_list=tf.train.Int64List(value=value)) def _bytes_feature(value): """Wrapper for inserting bytes features into Example proto.""" return tf.train.Feature(bytes_list=tf.train.BytesList(value=[value])) def _convert_to_example(filename, image_buffer, label_int, label_str, height, width): """Build an Example proto for an example. Args: filename: string, path to an image file, e.g., '/path/to/example.JPG' image_buffer: string, JPEG encoding of RGB image label_int: integer, identifier for ground truth (0-based) label_str: string, identifier for ground truth, e.g., 'daisy' height: integer, image height in pixels width: integer, image width in pixels Returns: Example proto """ colorspace = 'RGB' channels = 3 image_format = 'JPEG' example = tf.train.Example( features=tf.train.Features( feature={ 'image/height': _int64_feature(height), 'image/width': _int64_feature(width), 'image/colorspace': _bytes_feature(colorspace), 'image/channels': _int64_feature(channels), 'image/class/label': _int64_feature(label_int + 1), # model expects 1-based 'image/class/synset': _bytes_feature(label_str), 'image/format': _bytes_feature(image_format), 'image/filename': _bytes_feature(os.path.basename(filename)), 'image/encoded': _bytes_feature(image_buffer) })) return example class ImageCoder(object): """Helper class that provides TensorFlow image coding utilities.""" def __init__(self, session=None): # Create a single Session to run all image coding calls. session = tf.get_default_session() if session is None else session self._sess = tf.Session() if session is None else session # Initializes function that converts PNG to JPEG data. self._png_data = tf.placeholder(dtype=tf.string) image = tf.image.decode_png(self._png_data, channels=3) self._png_to_jpeg = tf.image.encode_jpeg(image, format='rgb', quality=100) # Initializes function that converts CMYK JPEG data to RGB JPEG data. self._cmyk_data = tf.placeholder(dtype=tf.string) image = tf.image.decode_jpeg(self._cmyk_data, channels=0) self._cmyk_to_rgb = tf.image.encode_jpeg(image, format='rgb', quality=100) # Initializes function that decodes RGB JPEG data. self._decode_jpeg_data = tf.placeholder(dtype=tf.string) self._decode_jpeg = tf.image.decode_jpeg(self._decode_jpeg_data, channels=3) def __del__(self): self._sess.close() def png_to_jpeg(self, image_data): return self._sess.run(self._png_to_jpeg, feed_dict={self._png_data: image_data}) def cmyk_to_rgb(self, image_data): return self._sess.run(self._cmyk_to_rgb, feed_dict={self._cmyk_data: image_data}) def decode_jpeg(self, image_data): image = self._sess.run(self._decode_jpeg, feed_dict={self._decode_jpeg_data: image_data}) assert len(image.shape) == 3 assert image.shape[2] == 3 return image # Parse individual image from a tfrecords file into TensorFlow expression. def parse_tfrecord_tf(record): features = tf.parse_single_example(record, features={ 'shape': tf.FixedLenFeature([3], tf.int64), 'data': tf.FixedLenFeature([], tf.string)}) data = tf.decode_raw(features['data'], tf.uint8) return tf.reshape(data, features['shape']) def parse_tfrecord_file(tfr_file, num_threads=8): dset = tf.data.TFRecordDataset(tfr_file, compression_type='', buffer_size=buffer_mb<<20) dset = dset.map(parse_tfrecord_tf, num_parallel_calls=num_threads) return dset def init_dataset(dset): tf_iterator = tf.data.Iterator.from_structure(dset.output_types, dset.output_shapes) tf_init_ops = tf_iterator.make_initializer(dset) return tf_iterator, tf_init_ops from tensorflow.python.framework import errors_impl def iterate_stylegan_records(tfr_file, session=None): if session is None: session = tf.get_default_session() dset = parse_tfrecord_file(tfr_file) it, init = init_dataset(dset) session.run(init) with session.graph.as_default(): op = tf.transpose(it.get_next(), [1, 2, 0]) try: while True: yield sess.run(op) except errors_impl.OutOfRangeError: pass def _is_png(filename): return filename.endswith('.png') or filename.endswith('.PNG') def _is_png_data(image_data): return image_data.startswith(b'\x89PNG') def _is_cmyk(filename): return False # TODO def get_coder(coder=None): coder = me.coder = me.coder if hasattr(me, 'coder') else ImageCoder() return coder import requests def getfile(path): if path.startswith('http'): r = requests.get(path, stream=True) if r.status_code == 200: return r.raw.read() else: raise Exception("Couldn't open URL: %s" % path) with tf.gfile.FastGFile(path, 'rb') as f: return f.read() def _process_image(filename, coder=None): """Process a single image file. Args: filename: string, path to an image file e.g., '/path/to/example.JPG'. coder: instance of ImageCoder to provide TensorFlow image coding utils. Returns: image_buffer: string, JPEG encoding of RGB image. height: integer, image height in pixels. width: integer, image width in pixels. """ coder = get_coder(coder) # Read the image file. image_data = getfile(filename) # Clean the dirty data. if _is_png_data(image_data): # 1 image is a PNG. tf.logging.info('Converting PNG to JPEG for %s' % filename) image_data = coder.png_to_jpeg(image_data) elif _is_cmyk(filename): # 22 JPEG images are in CMYK colorspace. tf.logging.info('Converting CMYK to RGB for %s' % filename) image_data = coder.cmyk_to_rgb(image_data) # Decode the RGB JPEG. image = coder.decode_jpeg(image_data) # Check that image converted to RGB assert len(image.shape) == 3 height = image.shape[0] width = image.shape[1] assert image.shape[2] == 3 return image_data, height, width, image def tf_randi(*args, **kws): assert len(args) > 0 if len(args) == 1: lo, hi = [0] + [x for x in args] else: lo, hi = args return tf.random.uniform((), minval=lo, maxval=hi, dtype=tf.int32, **kws) def tf_rand(*args, **kws): if len(args) == 0: lo, hi = 0.0, 1.0 elif len(args) == 1: lo, hi = [0] + [x for x in args] else: lo, hi = args return tf.random.uniform((), minval=lo, maxval=hi, **kws) def tf_biased_rand(*args, bias=1, **kws): x = tf_rand(*args, **kws) # simple technique to bias the result towards the center. for i in range(bias-1): x += tf_rand(*args, **kws) dtype = kws.pop('dtype') if 'dtype' in kws else tf.float32 x = tf.cast(x, tf.float32) / bias x = tf.cast(x, dtype) return x def tf_between(*args, bias=1, **kws): if bias <= 0: return tf_randi(*args, **kws) else: return tf_biased_rand(*args, dtype=tf.int32, bias=bias, **kws) def random_crop(image_bytes, scope=None, resize=None, method=tf.image.ResizeMethod.AREA, seed=None): with tf.name_scope(scope, 'random_crop', [image_bytes]): shape = tf.image.extract_jpeg_shape(image_bytes) w = shape[0] h = shape[1] channels = shape[2] x, y = 0, 0 n = 3 image = tf.cond(w > h, lambda: tf.image.decode_and_crop_jpeg(image_bytes, tf.stack([x + tf_between(w - h, seed=seed), y, h, h]), channels=n), lambda: tf.cond(h > w, lambda: tf.image.decode_and_crop_jpeg(image_bytes, tf.stack([x, y + tf_between(h - w, seed=seed), w, w]), channels=n), lambda: tf.image.decode_jpeg(image_bytes, channels=n))) if resize: image_size = [resize, resize] if isinstance(resize, int) or isinstance(resize, float) else resize image = tf.image.resize([image], image_size, method=method)[0] return image # with open('test.jpg', 'wb') as f: f.write(tf.get_default_session().run(tf.io.encode_jpeg(sess.run(random_crop(open(np.random.choice(list(glob('*.jpg'))), 'rb').read()))))) IMAGE_SIZE = 224 CROP_PADDING = 32 def distorted_bounding_box_crop(image_bytes, bbox, min_object_covered=0.1, aspect_ratio_range=(0.75, 1.33), area_range=(0.05, 1.0), max_attempts=100, scope=None): """Generates cropped_image using one of the bboxes randomly distorted. See `tf.image.sample_distorted_bounding_box` for more documentation. Args: image_bytes: `Tensor` of binary image data. bbox: `Tensor` of bounding boxes arranged `[1, num_boxes, coords]` where each coordinate is [0, 1) and the coordinates are arranged as `[ymin, xmin, ymax, xmax]`. If num_boxes is 0 then use the whole image. min_object_covered: An optional `float`. Defaults to `0.1`. The cropped area of the image must contain at least this fraction of any bounding box supplied. aspect_ratio_range: An optional list of `float`s. The cropped area of the image must have an aspect ratio = width / height within this range. area_range: An optional list of `float`s. The cropped area of the image must contain a fraction of the supplied image within in this range. max_attempts: An optional `int`. Number of attempts at generating a cropped region of the image of the specified constraints. After `max_attempts` failures, return the entire image. scope: Optional `str` for name scope. Returns: cropped image `Tensor` """ with tf.name_scope(scope, 'distorted_bounding_box_crop', [image_bytes, bbox]): shape = tf.image.extract_jpeg_shape(image_bytes) sample_distorted_bounding_box = tf.image.sample_distorted_bounding_box( shape, bounding_boxes=bbox, min_object_covered=min_object_covered, aspect_ratio_range=aspect_ratio_range, area_range=area_range, max_attempts=max_attempts, use_image_if_no_bounding_boxes=True) bbox_begin, bbox_size, _ = sample_distorted_bounding_box # Crop the image to the specified bounding box. offset_y, offset_x, _ = tf.unstack(bbox_begin) target_height, target_width, _ = tf.unstack(bbox_size) crop_window = tf.stack([offset_y, offset_x, target_height, target_width]) image = tf.image.decode_and_crop_jpeg(image_bytes, crop_window, channels=3) return image def _at_least_x_are_equal(a, b, x): """At least `x` of `a` and `b` `Tensors` are equal.""" match = tf.equal(a, b) match = tf.cast(match, tf.int32) return tf.greater_equal(tf.reduce_sum(match), x) def _decode_and_random_crop(image_bytes, image_size, resize=True, method=tf.image.ResizeMethod.AREA, aspect_ratio_range=(3. / 4, 4. / 3), area_range=(0.08, 1.0)): # AREA is much higher quality than BICUBIC """Make a random crop of image_size.""" bbox = tf.constant([0.0, 0.0, 1.0, 1.0], dtype=tf.float32, shape=[1, 1, 4]) image = distorted_bounding_box_crop( image_bytes, bbox, min_object_covered=0.1, aspect_ratio_range=aspect_ratio_range, area_range=area_range, max_attempts=10, scope=None) original_shape = tf.image.extract_jpeg_shape(image_bytes) bad = _at_least_x_are_equal(original_shape, tf.shape(image), 3) if resize: image = tf.cond( bad, lambda: _decode_and_center_crop(image_bytes, image_size, resize=resize, method=method), lambda: tf.image.resize([image], [image_size, image_size], method=method)[0]) else: image = tf.cond( bad, lambda: _decode_and_center_crop(image_bytes, image_size, resize=resize, method=method), lambda: image) return image def _decode_and_center_crop(image_bytes, image_size, resize=True, method=tf.image.ResizeMethod.AREA): # AREA is much higher quality than BICUBIC """Crops to center of image with padding then scales image_size.""" shape = tf.image.extract_jpeg_shape(image_bytes) image_height = shape[0] image_width = shape[1] padded_center_crop_size = tf.cast( ((image_size / (image_size + CROP_PADDING)) * tf.cast(tf.minimum(image_height, image_width), tf.float32)), tf.int32) offset_height = ((image_height - padded_center_crop_size) + 1) // 2 offset_width = ((image_width - padded_center_crop_size) + 1) // 2 crop_window = tf.stack([offset_height, offset_width, padded_center_crop_size, padded_center_crop_size]) image = tf.image.decode_and_crop_jpeg(image_bytes, crop_window, channels=3) if resize: image = tf.image.resize([image], [image_size, image_size], method=method)[0] return image import os from tensorflow.compat.v1.distribute.cluster_resolver import TPUClusterResolver def get_target(target=None): if target is None and 'COLAB_TPU_ADDR' in os.environ: target = os.environ['COLAB_TPU_ADDR'] if target is None and 'TPU_NAME' in os.environ: target = os.environ['TPU_NAME'] if not target.startswith('grpc://'): target = TPUClusterResolver(target).get_master() if target is not None: print('Using target %s' % target) return target def main(): from tensorflow.python.framework.ops import disable_eager_execution disable_eager_execution() parser = argparse.ArgumentParser() parser.add_argument('infile') parser.add_argument('outfile', nargs='?') parser.add_argument('-r', '--resize', type=int, default=0) args = me.args = parser.parse_args() with tf.Session(get_target()) as sess: image_data, width, height, image = _process_image(args.infile) image_out = sess.run(tf.io.encode_jpeg(sess.run(random_crop(image_data, resize=args.resize)))) if not args.outfile: args.outfile = os.path.basename(args.infile) if args.outfile == args.infile: print('Implicitly overwriting infile not supported; pass `%s %s` to confirm' % (args.outfile, args.outfile)) sys.exit(1) with open(args.outfile, 'wb') as f: f.write(image_out) if __name__ == '__main__': main() def convert_to_example(csvline, categories): """Parse a line of CSV file and convert to TF Record. Args: csvline: line from input CSV file categories: list of labels Yields: serialized TF example if the label is in categories """ filename, label = csvline.encode('ascii', 'ignore').split(',') if label in categories: # ignore labels not in categories list coder = ImageCoder() image_buffer, height, width, image = _process_image(filename, coder) del coder example = _convert_to_example(filename, image_buffer, categories.index(label), label, height, width) yield example.SerializeToString() def main2(): parser = argparse.ArgumentParser() parser.add_argument( '--train_csv', # pylint: disable=line-too-long help= 'Path to input. Each line of input has two fields image-file-name and label separated by a comma', required=True) parser.add_argument( '--validation_csv', # pylint: disable=line-too-long help= 'Path to input. Each line of input has two fields image-file-name and label separated by a comma', required=True) parser.add_argument( '--labels_file', help='Path to file containing list of labels, one per line', required=True) parser.add_argument( '--project_id', help='ID (not name) of your project. Ignored by DirectRunner', required=True) parser.add_argument( '--runner', help='If omitted, uses DataFlowRunner if output_dir starts with gs://', default=None) parser.add_argument( '--output_dir', help='Top-level directory for TF Records', required=True) args = parser.parse_args() arguments = args.__dict__ JOBNAME = ( 'preprocess-images-' + datetime.datetime.now().strftime('%y%m%d-%H%M%S')) PROJECT = arguments['project_id'] OUTPUT_DIR = arguments['output_dir'] # set RUNNER using command-line arg or based on output_dir path on_cloud = OUTPUT_DIR.startswith('gs://') if arguments['runner']: RUNNER = arguments['runner'] else: RUNNER = 'DataflowRunner' if on_cloud else 'DirectRunner' # clean-up output directory since Beam will name files 0000-of-0004 etc. # and this could cause confusion if earlier run has 0000-of-0005, for eg if on_cloud: try: subprocess.check_call('gsutil -m rm -r {}'.format(OUTPUT_DIR).split()) except subprocess.CalledProcessError: pass else: shutil.rmtree(OUTPUT_DIR, ignore_errors=True) os.makedirs(OUTPUT_DIR) # read list of labels with tf.gfile.FastGFile(arguments['labels_file'], 'r') as f: LABELS = [line.rstrip() for line in f] print('Read in {} labels, from {} to {}'.format( len(LABELS), LABELS[0], LABELS[-1])) if len(LABELS) < 2: print('Require at least two labels') sys.exit(-1) # set up Beam pipeline to convert images to TF Records options = { 'staging_location': os.path.join(OUTPUT_DIR, 'tmp', 'staging'), 'temp_location': os.path.join(OUTPUT_DIR, 'tmp'), 'job_name': JOBNAME, 'project': PROJECT, 'teardown_policy': 'TEARDOWN_ALWAYS', 'save_main_session': True } opts = beam.pipeline.PipelineOptions(flags=[], **options) with beam.Pipeline(RUNNER, options=opts) as p: # BEAM tasks for step in ['train', 'validation']: _ = ( p | '{}_read_csv'.format(step) >> beam.io.ReadFromText( arguments['{}_csv'.format(step)]) | '{}_convert'.format(step) >> beam.FlatMap(lambda line: convert_to_example(line, LABELS)) | '{}_write_tfr'.format(step) >> beam.io.tfrecordio.WriteToTFRecord( os.path.join(OUTPUT_DIR, step))) ================================================ FILE: stylegan2-tpu/pretrained_networks.py ================================================ # Copyright (c) 2019, NVIDIA Corporation. All rights reserved. # # This work is made available under the Nvidia Source Code License-NC. # To view a copy of this license, visit # https://nvlabs.github.io/stylegan2/license.html """List of pre-trained StyleGAN2 networks located on Google Drive.""" import pickle import dnnlib import dnnlib.tflib as tflib #---------------------------------------------------------------------------- # StyleGAN2 Google Drive root: https://drive.google.com/open?id=1QHc-yF5C3DChRwSdZKcx1w6K8JvSxQi7 gdrive_urls = { 'gdrive:networks/stylegan2-car-config-a.pkl': 'http://d36zk2xti64re0.cloudfront.net/stylegan2/networks/stylegan2-car-config-a.pkl', 'gdrive:networks/stylegan2-car-config-b.pkl': 'http://d36zk2xti64re0.cloudfront.net/stylegan2/networks/stylegan2-car-config-b.pkl', 'gdrive:networks/stylegan2-car-config-c.pkl': 'http://d36zk2xti64re0.cloudfront.net/stylegan2/networks/stylegan2-car-config-c.pkl', 'gdrive:networks/stylegan2-car-config-d.pkl': 'http://d36zk2xti64re0.cloudfront.net/stylegan2/networks/stylegan2-car-config-d.pkl', 'gdrive:networks/stylegan2-car-config-e.pkl': 'http://d36zk2xti64re0.cloudfront.net/stylegan2/networks/stylegan2-car-config-e.pkl', 'gdrive:networks/stylegan2-car-config-f.pkl': 'http://d36zk2xti64re0.cloudfront.net/stylegan2/networks/stylegan2-car-config-f.pkl', 'gdrive:networks/stylegan2-cat-config-a.pkl': 'http://d36zk2xti64re0.cloudfront.net/stylegan2/networks/stylegan2-cat-config-a.pkl', 'gdrive:networks/stylegan2-cat-config-f.pkl': 'http://d36zk2xti64re0.cloudfront.net/stylegan2/networks/stylegan2-cat-config-f.pkl', 'gdrive:networks/stylegan2-church-config-a.pkl': 'http://d36zk2xti64re0.cloudfront.net/stylegan2/networks/stylegan2-church-config-a.pkl', 'gdrive:networks/stylegan2-church-config-f.pkl': 'http://d36zk2xti64re0.cloudfront.net/stylegan2/networks/stylegan2-church-config-f.pkl', 'gdrive:networks/stylegan2-ffhq-config-a.pkl': 'http://d36zk2xti64re0.cloudfront.net/stylegan2/networks/stylegan2-ffhq-config-a.pkl', 'gdrive:networks/stylegan2-ffhq-config-b.pkl': 'http://d36zk2xti64re0.cloudfront.net/stylegan2/networks/stylegan2-ffhq-config-b.pkl', 'gdrive:networks/stylegan2-ffhq-config-c.pkl': 'http://d36zk2xti64re0.cloudfront.net/stylegan2/networks/stylegan2-ffhq-config-c.pkl', 'gdrive:networks/stylegan2-ffhq-config-d.pkl': 'http://d36zk2xti64re0.cloudfront.net/stylegan2/networks/stylegan2-ffhq-config-d.pkl', 'gdrive:networks/stylegan2-ffhq-config-e.pkl': 'http://d36zk2xti64re0.cloudfront.net/stylegan2/networks/stylegan2-ffhq-config-e.pkl', 'gdrive:networks/stylegan2-ffhq-config-f.pkl': 'http://d36zk2xti64re0.cloudfront.net/stylegan2/networks/stylegan2-ffhq-config-f.pkl', 'gdrive:networks/stylegan2-horse-config-a.pkl': 'http://d36zk2xti64re0.cloudfront.net/stylegan2/networks/stylegan2-horse-config-a.pkl', 'gdrive:networks/stylegan2-horse-config-f.pkl': 'http://d36zk2xti64re0.cloudfront.net/stylegan2/networks/stylegan2-horse-config-f.pkl', 'gdrive:networks/table2/stylegan2-car-config-e-Gorig-Dorig.pkl': 'http://d36zk2xti64re0.cloudfront.net/stylegan2/networks/table2/stylegan2-car-config-e-Gorig-Dorig.pkl', 'gdrive:networks/table2/stylegan2-car-config-e-Gorig-Dresnet.pkl': 'http://d36zk2xti64re0.cloudfront.net/stylegan2/networks/table2/stylegan2-car-config-e-Gorig-Dresnet.pkl', 'gdrive:networks/table2/stylegan2-car-config-e-Gorig-Dskip.pkl': 'http://d36zk2xti64re0.cloudfront.net/stylegan2/networks/table2/stylegan2-car-config-e-Gorig-Dskip.pkl', 'gdrive:networks/table2/stylegan2-car-config-e-Gresnet-Dorig.pkl': 'http://d36zk2xti64re0.cloudfront.net/stylegan2/networks/table2/stylegan2-car-config-e-Gresnet-Dorig.pkl', 'gdrive:networks/table2/stylegan2-car-config-e-Gresnet-Dresnet.pkl': 'http://d36zk2xti64re0.cloudfront.net/stylegan2/networks/table2/stylegan2-car-config-e-Gresnet-Dresnet.pkl', 'gdrive:networks/table2/stylegan2-car-config-e-Gresnet-Dskip.pkl': 'http://d36zk2xti64re0.cloudfront.net/stylegan2/networks/table2/stylegan2-car-config-e-Gresnet-Dskip.pkl', 'gdrive:networks/table2/stylegan2-car-config-e-Gskip-Dorig.pkl': 'http://d36zk2xti64re0.cloudfront.net/stylegan2/networks/table2/stylegan2-car-config-e-Gskip-Dorig.pkl', 'gdrive:networks/table2/stylegan2-car-config-e-Gskip-Dresnet.pkl': 'http://d36zk2xti64re0.cloudfront.net/stylegan2/networks/table2/stylegan2-car-config-e-Gskip-Dresnet.pkl', 'gdrive:networks/table2/stylegan2-car-config-e-Gskip-Dskip.pkl': 'http://d36zk2xti64re0.cloudfront.net/stylegan2/networks/table2/stylegan2-car-config-e-Gskip-Dskip.pkl', 'gdrive:networks/table2/stylegan2-ffhq-config-e-Gorig-Dorig.pkl': 'http://d36zk2xti64re0.cloudfront.net/stylegan2/networks/table2/stylegan2-ffhq-config-e-Gorig-Dorig.pkl', 'gdrive:networks/table2/stylegan2-ffhq-config-e-Gorig-Dresnet.pkl': 'http://d36zk2xti64re0.cloudfront.net/stylegan2/networks/table2/stylegan2-ffhq-config-e-Gorig-Dresnet.pkl', 'gdrive:networks/table2/stylegan2-ffhq-config-e-Gorig-Dskip.pkl': 'http://d36zk2xti64re0.cloudfront.net/stylegan2/networks/table2/stylegan2-ffhq-config-e-Gorig-Dskip.pkl', 'gdrive:networks/table2/stylegan2-ffhq-config-e-Gresnet-Dorig.pkl': 'http://d36zk2xti64re0.cloudfront.net/stylegan2/networks/table2/stylegan2-ffhq-config-e-Gresnet-Dorig.pkl', 'gdrive:networks/table2/stylegan2-ffhq-config-e-Gresnet-Dresnet.pkl': 'http://d36zk2xti64re0.cloudfront.net/stylegan2/networks/table2/stylegan2-ffhq-config-e-Gresnet-Dresnet.pkl', 'gdrive:networks/table2/stylegan2-ffhq-config-e-Gresnet-Dskip.pkl': 'http://d36zk2xti64re0.cloudfront.net/stylegan2/networks/table2/stylegan2-ffhq-config-e-Gresnet-Dskip.pkl', 'gdrive:networks/table2/stylegan2-ffhq-config-e-Gskip-Dorig.pkl': 'http://d36zk2xti64re0.cloudfront.net/stylegan2/networks/table2/stylegan2-ffhq-config-e-Gskip-Dorig.pkl', 'gdrive:networks/table2/stylegan2-ffhq-config-e-Gskip-Dresnet.pkl': 'http://d36zk2xti64re0.cloudfront.net/stylegan2/networks/table2/stylegan2-ffhq-config-e-Gskip-Dresnet.pkl', 'gdrive:networks/table2/stylegan2-ffhq-config-e-Gskip-Dskip.pkl': 'http://d36zk2xti64re0.cloudfront.net/stylegan2/networks/table2/stylegan2-ffhq-config-e-Gskip-Dskip.pkl', } #---------------------------------------------------------------------------- def get_path_or_url(path_or_gdrive_path): return gdrive_urls.get(path_or_gdrive_path, path_or_gdrive_path) #---------------------------------------------------------------------------- _cached_networks = dict() def load_networks(path_or_gdrive_path): path_or_url = get_path_or_url(path_or_gdrive_path) if path_or_url in _cached_networks: return _cached_networks[path_or_url] if dnnlib.util.is_url(path_or_url): stream = dnnlib.util.open_url(path_or_url, cache_dir='.stylegan2-cache') else: stream = open(path_or_url, 'rb') tflib.init_tf() with stream: G, D, Gs = pickle.load(stream, encoding='latin1') _cached_networks[path_or_url] = G, D, Gs return G, D, Gs #---------------------------------------------------------------------------- ================================================ FILE: stylegan2-tpu/projector.py ================================================ # Copyright (c) 2019, NVIDIA Corporation. All rights reserved. # # This work is made available under the Nvidia Source Code License-NC. # To view a copy of this license, visit # https://nvlabs.github.io/stylegan2/license.html import numpy as np import tensorflow as tf import dnnlib import dnnlib.tflib as tflib from training import misc #---------------------------------------------------------------------------- class Projector: def __init__(self): self.num_steps = 1000 self.dlatent_avg_samples = 10000 self.initial_learning_rate = 0.1 self.initial_noise_factor = 0.05 self.lr_rampdown_length = 0.25 self.lr_rampup_length = 0.05 self.noise_ramp_length = 0.75 self.regularize_noise_weight = 1e5 self.verbose = False self.clone_net = True self._Gs = None self._minibatch_size = None self._dlatent_avg = None self._dlatent_std = None self._noise_vars = None self._noise_init_op = None self._noise_normalize_op = None self._dlatents_var = None self._noise_in = None self._dlatents_expr = None self._images_expr = None self._target_images_var = None self._lpips = None self._dist = None self._loss = None self._reg_sizes = None self._lrate_in = None self._opt = None self._opt_step = None self._cur_step = None def _info(self, *args): if self.verbose: print('Projector:', *args) def set_network(self, Gs, minibatch_size=1): assert minibatch_size == 1 self._Gs = Gs self._minibatch_size = minibatch_size if self._Gs is None: return if self.clone_net: self._Gs = self._Gs.clone() # Find dlatent stats. self._info('Finding W midpoint and stddev using %d samples...' % self.dlatent_avg_samples) latent_samples = np.random.RandomState(123).randn(self.dlatent_avg_samples, *self._Gs.input_shapes[0][1:]) dlatent_samples = self._Gs.components.mapping.run(latent_samples, None)[:, :1, :] # [N, 1, 512] self._dlatent_avg = np.mean(dlatent_samples, axis=0, keepdims=True) # [1, 1, 512] self._dlatent_std = (np.sum((dlatent_samples - self._dlatent_avg) ** 2) / self.dlatent_avg_samples) ** 0.5 self._info('std = %g' % self._dlatent_std) # Find noise inputs. self._info('Setting up noise inputs...') self._noise_vars = [] noise_init_ops = [] noise_normalize_ops = [] while True: n = 'G_synthesis/noise%d' % len(self._noise_vars) if not n in self._Gs.vars: break v = self._Gs.vars[n] self._noise_vars.append(v) noise_init_ops.append(tf.assign(v, tf.random_normal(tf.shape(v), dtype=tf.float32))) noise_mean = tf.reduce_mean(v) noise_std = tf.reduce_mean((v - noise_mean)**2)**0.5 noise_normalize_ops.append(tf.assign(v, (v - noise_mean) / noise_std)) self._info(n, v) self._noise_init_op = tf.group(*noise_init_ops) self._noise_normalize_op = tf.group(*noise_normalize_ops) # Image output graph. self._info('Building image output graph...') self._dlatents_var = tf.Variable(tf.zeros([self._minibatch_size] + list(self._dlatent_avg.shape[1:])), name='dlatents_var') self._noise_in = tf.placeholder(tf.float32, [], name='noise_in') dlatents_noise = tf.random.normal(shape=self._dlatents_var.shape) * self._noise_in self._dlatents_expr = tf.tile(self._dlatents_var + dlatents_noise, [1, self._Gs.components.synthesis.input_shape[1], 1]) self._images_expr = self._Gs.components.synthesis.get_output_for(self._dlatents_expr, randomize_noise=False) # Downsample image to 256x256 if it's larger than that. VGG was built for 224x224 images. proc_images_expr = (self._images_expr + 1) * (255 / 2) sh = proc_images_expr.shape.as_list() if sh[2] > 256: factor = sh[2] // 256 proc_images_expr = tf.reduce_mean(tf.reshape(proc_images_expr, [-1, sh[1], sh[2] // factor, factor, sh[2] // factor, factor]), axis=[3,5]) # Loss graph. self._info('Building loss graph...') self._target_images_var = tf.Variable(tf.zeros(proc_images_expr.shape), name='target_images_var') if self._lpips is None: self._lpips = misc.load_pkl('https://drive.google.com/uc?id=1N2-m9qszOeVC9Tq77WxsLnuWwOedQiD2', 'vgg16_zhang_perceptual.pkl') self._dist = self._lpips.get_output_for(proc_images_expr, self._target_images_var) self._loss = tf.reduce_sum(self._dist) # Noise regularization graph. self._info('Building noise regularization graph...') reg_loss = 0.0 for v in self._noise_vars: sz = v.shape[2] while True: reg_loss += tf.reduce_mean(v * tf.roll(v, shift=1, axis=3))**2 + tf.reduce_mean(v * tf.roll(v, shift=1, axis=2))**2 if sz <= 8: break # Small enough already v = tf.reshape(v, [1, 1, sz//2, 2, sz//2, 2]) # Downscale v = tf.reduce_mean(v, axis=[3, 5]) sz = sz // 2 self._loss += reg_loss * self.regularize_noise_weight # Optimizer. self._info('Setting up optimizer...') self._lrate_in = tf.placeholder(tf.float32, [], name='lrate_in') self._opt = dnnlib.tflib.Optimizer(learning_rate=self._lrate_in) self._opt.register_gradients(self._loss, [self._dlatents_var] + self._noise_vars) self._opt_step = self._opt.apply_updates() def run(self, target_images): # Run to completion. self.start(target_images) while self._cur_step < self.num_steps: self.step() # Collect results. pres = dnnlib.EasyDict() pres.dlatents = self.get_dlatents() pres.noises = self.get_noises() pres.images = self.get_images() return pres def start(self, target_images): assert self._Gs is not None # Prepare target images. self._info('Preparing target images...') target_images = np.asarray(target_images, dtype='float32') target_images = (target_images + 1) * (255 / 2) sh = target_images.shape assert sh[0] == self._minibatch_size if sh[2] > self._target_images_var.shape[2]: factor = sh[2] // self._target_images_var.shape[2] target_images = np.reshape(target_images, [-1, sh[1], sh[2] // factor, factor, sh[3] // factor, factor]).mean((3, 5)) # Initialize optimization state. self._info('Initializing optimization state...') tflib.set_vars({self._target_images_var: target_images, self._dlatents_var: np.tile(self._dlatent_avg, [self._minibatch_size, 1, 1])}) tflib.run(self._noise_init_op) self._opt.reset_optimizer_state() self._cur_step = 0 def step(self): assert self._cur_step is not None if self._cur_step >= self.num_steps: return if self._cur_step == 0: self._info('Running...') # Hyperparameters. t = self._cur_step / self.num_steps noise_strength = self._dlatent_std * self.initial_noise_factor * max(0.0, 1.0 - t / self.noise_ramp_length) ** 2 lr_ramp = min(1.0, (1.0 - t) / self.lr_rampdown_length) lr_ramp = 0.5 - 0.5 * np.cos(lr_ramp * np.pi) lr_ramp = lr_ramp * min(1.0, t / self.lr_rampup_length) learning_rate = self.initial_learning_rate * lr_ramp # Train. feed_dict = {self._noise_in: noise_strength, self._lrate_in: learning_rate} _, dist_value, loss_value = tflib.run([self._opt_step, self._dist, self._loss], feed_dict) tflib.run(self._noise_normalize_op) # Print status. self._cur_step += 1 if self._cur_step == self.num_steps or self._cur_step % 10 == 0: self._info('%-8d%-12g%-12g' % (self._cur_step, dist_value, loss_value)) if self._cur_step == self.num_steps: self._info('Done.') def get_cur_step(self): return self._cur_step def get_dlatents(self): return tflib.run(self._dlatents_expr, {self._noise_in: 0}) def get_noises(self): return tflib.run(self._noise_vars) def get_images(self): return tflib.run(self._images_expr, {self._noise_in: 0}) #---------------------------------------------------------------------------- ================================================ FILE: stylegan2-tpu/random_crops.py ================================================ import argparse, os import numpy as np from PIL import Image from random import randrange from tqdm import tqdm parser = argparse.ArgumentParser() parser.add_argument('-i', '--input', type=str, required=True, help="Input directory of images to randomly crop.") parser.add_argument('-o', '--output', type=str, required=True, help="Output destination to store randomly-cropped images.") parser.add_argument('-n', '--max_images', type=int, required=True, help="Max images to randomly crop") args = parser.parse_args() def random_crop(image, target, samples, file): x = image.width y = image.height for i in range(samples): x1 = randrange(0, x - target) y1 = randrange(0, y - target) image.crop((x1, y1, x1 + target, y1 + target)).save(target_directory + "/" + str(i) + file) directory = args.input target_directory = args.output max_images = args.max_images added = 0 with tqdm(total=max_images) as pbar: for subdir, dirs, files in os.walk(directory): for file in files: filepath = subdir + os.sep + file if filepath.endswith(".jpeg") and added != max_images: if "._" in filepath: continue im = Image.open(filepath).convert('RGB') random_crop(im, 512, 5, file) added += 1 pbar.update(1) else: break ================================================ FILE: stylegan2-tpu/repl.l ================================================ (%block class Namespace (do)) (defvar args (Namespace)) (set args.batch_size 1 args.randomize_noise false args.tile_dlatents false args.clipping_threshold 2.0 args.model_res 1024 args.lr 0.02 args.decay_rate 0.9 args.decay_steps 10 args.image_size 256 args.use_vgg_layer 9 args.use_vgg_loss 0.4 args.face_mask false args.use_grabcut true args.scale_mask 1.5 args.mask_dir "masks" args.use_pixel_loss 1.5 args.use_mssim_loss 100 args.use_lpips_loss 100 args.use_l1_penalty 1) ;(set args.batch_size 1 args.randomize_noise false args.tile_dlatents true args.clipping_threshold 2.0 args.model_res 1024 args.lr 0.02 args.decay_rate 0.9 args.decay_steps 10 args.image_size 256 args.use_vgg_layer 9 args.use_vgg_loss 0.4 args.face_mask false args.use_grabcut true args.scale_mask 1.5 args.mask_dir "masks" args.use_pixel_loss 1.5 args.use_mssim_loss 100 args.use_lpips_loss 100 args.use_l1_penalty 0) (import os) (import pickle) (import PIL.Image) (import numpy as np) (import tensorflow as tf) (import dnnlib) (import dnnlib.tflib as tflib) (defvar config (Namespace)) (set config.cache_dir "cache") (import websockets) (import datetime) (import asyncio) ;(import ganlib) (from encoder.generator_model import Generator) (from encoder.perceptual_model import PerceptualModel load_images) (from keras.models import load_model) (from importlib import reload) ;(import matplotlib.pyplot as plt) (defconst URL_FFHQ "https://drive.google.com/uc?id=1MEGjdvVpUsu1jB4zrXZN7Y4kBBOzizDQ") (defconst URL_FFHQ_RES 1024) (defconst URL_PERC "https://drive.google.com/uc?id=1N2-m9qszOeVC9Tq77WxsLnuWwOedQiD2") (defconst URL_ANIME "2019-04-30-stylegan-danbooru2018-portraits-02095-066083.pkl") (defconst URL_ANIME "https://drive.google.com/uc?id=1pWnrmlP1aDv3bp1evzspH4ke9RdnP4aj") (defconst URL_ANIME_RES 512) (def load-generator (url) (with (dnnlib.util.open_url (or url URL_FFHQ) cache_dir: config.cache_dir) as f (pickle (.load f)))) ;(ganlib.load_model (or url URL_FFHQ))) (def load-perceptual (url) (with (dnnlib.util.open_url (or URL_PERC url) cache_dir: config.cache_dir) as f (pickle (.load f)))) ;(ganlib.load_perceptual (or url URL_PERC))) (def init-generator (url res) (global generator_network) (global discriminator_network) (global Gs_network) (global generator) (set generator_network, discriminator_network, Gs_network (load-generator url)) (set generator (Generator Gs_network batch_size: 1 randomize_noise: false model_res: (or res URL_FFHQ_RES) tiled_dlatent: args.tile_dlatents)) generator) (defvar reference-images* (list "/drive/stylegan-server-cache/217677dfe303180f7736ca5ecf0868a3_aligned")) (def init-perceptual (url res) (global perc_model) (global perceptual_model) (set perc_model (load-perceptual url)) (set perceptual_model (PerceptualModel args perc_model: perc_model batch_size: args.batch_size)) (perceptual_model.build_perceptual_model generator) (let img (PIL.Image.new size: '(256 256) mode: "RGB" color: "black") (img.save "/tmp/reference.png" "PNG")) (perceptual_model.set_reference_images (list "/tmp/reference.png")) ) ;(tflib.init_tf) ;(set sess (tf.get_default_session)) ;(init-generator) ; (set vs (+ (list x for x in (perceptual_model.optimizer._get_beta_accumulators)) (list (perceptual_model.optimizer.get_slot generator.dlatent_variable x) for x in '(m v)))) ; (set state0 (list (x (.eval)) for x in vs)) ; (list (x (.load v)) for x, v in (zip vs state0)) ; stochastic clipping doesn't play well with facial directions! (def reinit-perceptual () (let scope (tf.get_variable_scope) (with (tf.variable_scope scope reuse: tf.AUTO_REUSE) (perceptual_model.build_perceptual_model generator)))) (defvar ff-model* nil) (defvar resnet-path* "data/finetuned_resnet.h5") (defconst resnet-download-url* "https://drive.google.com/uc?id=1aT59NFy9-bNyXjDuZOTMl0qX0jmZc6Zb") (def init-resnet () (global ff-model*) (unless (os.path.exists resnet-path*) (os.makedirs (os.path.dirname resnet-path*) exist_ok: true) (with (dnnlib.util.open_url resnet-download-url* cache_dir: "cache") as f (with (open resnet-path* "wb") as dst (dst.write (f.read))))) (unless ff-model* (set ff-model* (load_model resnet-path*))) ff-model*) (def image? (x) (isinstance x PIL.Image.Image)) (def file? (x) (os.path.isfile x)) (def numpy? (x) (isinstance x np.ndarray)) (import requests) (def GET (url) (requests.get url)) (def convert-image (img) (img.convert "RGB")) (def fetch-image (url) (if (image? url) url (file? url) (PIL.Image.open url) (numpy? url) (PIL.Image.fromarray url) (let resp (GET url) (when (= resp.status_code 200) (PIL.Image.open (BytesIO resp.content)))))) (def image-to-numpy (x) (if (numpy? x) x (np.array (fetch-image x)))) (def bytes-to-numpy (x reshape) (if (numpy? x) x (let l (np.frombuffer x dtype: np.uint8 count: (# x)) (if (is? reshape) (l.reshape reshape) l)))) (def numpy-to-image (x) (if (numpy? x) (PIL.Image.fromarray x) (fetch-image x))) (def expand-image (x) (let-when img (numpy-to-image x) (let img (convert-image img) (let-when data (image-to-numpy img) (if (= (# data.shape) 3) (np.expand_dims data axis: 0) data))))) (def resize-image (img size) (img.resize size PIL.Image.ANTIALIAS)) (def image-to-target (img size) (let (size (or size '(256 256)) img (resize-image img size)) (image-to-numpy (img.convert "RGB")))) (def thumbnail-image (img size) (let img (img.copy) (img.thumbnail size PIL.Image.ANTIALIAS) img)) (import time) (def current-time () (time.time)) (mac timeit body (let-unique (t1 t2 r) `(let ,t1 (current-time) (with ,r (do ,@body) (let ,t2 (current-time) (print (cat "time: " (- ,t2 ,t1) " seconds"))))))) (from keras.applications.resnet50 import preprocess_input) (defconst default-dlatent* (np.zeros shape: (if args.tile_dlatents '(1 512) '(1 18 512)))) (def estimate-dlatent (img) (let result (let-when model (init-resnet) (let-when data (image-to-numpy img) (model.predict (preprocess_input (np.expand_dims data axis: 0))))) (if (is? result) result (default-dlatent*.copy)))) ;(tflib.init_tf) ;(with (dnnlib.util.open_url URL_FFHQ, cache_dir=config.cache_dir) as f ; (set generator_network, discriminator_network, Gs_network (pickle.load f))) (defvar latents* (Namespace)) ;(set latents*.trump (np (.load "ffhq_dataset/latent_representations/donald_trump_01.npy")) ; latents*.hillary (np (.load "ffhq_dataset/latent_representations/hillary_clinton_01.npy"))) ;(step x (list "smile" "gender" "age") ; (let path (cat "ffhq_dataset/latent_directions/" x ".npy") ; (setattr latents* x (np (.load path))))) (from glob import glob) (for k, v in (list (list (hd ((at (x (.split "/")) -1) (.split "_direction"))) (np (.load x))) for x in (glob "trained_directions/*.npy")) (setattr latents* k v)) (for k, v in (list (list (hd ((at (x (.split "/")) -1) (.split "_direction"))) (np (.load x))) for x in (glob "../facetrickery/data/directions/*.npy")) (setattr latents* k v)) (def file-to-bytes (path) (with (open path "rb") as f (f.read))) (import json) (def file-to-latent (path) (np.array (json.loads (file-to-bytes path)))) (def load-latents () (let i 0 (for path in (sorted (hd (list (glob "/drive/stylegan-server-cache/*_latent")))) ;(for k, v in (list (list (hd ((at (x (.split "/")) -1) (.split "_latent"))) (np (.load x))) for x in (let (name (% "i%03d" (inc i)) v (file-to-latent path)) (setattr latents* name v))))) (def upload-variable (variable value) (variable (.load value))) (def fetch-variable (variable) (variable (.eval))) (def as-latent (latent) (let-when x (np.array latent dtype: np.float32) (x.reshape (if args.tile_dlatents (list -1 512) (list 1 -1 512))))) (def upload-latent (latent) (let x (as-latent latent) (upload-variable generator.dlatent_variable x))) (def fetch-latent () (fetch-variable generator.dlatent_variable)) (def upload-step (i) (upload-variable perceptual_model._global_step (or i 0))) (def generate-image-array (latent) ;(generator.set_dlatents latent) (upload-latent latent) (at (generator.generate_images) 0)) (def generate-image (latent) (let (img-array (generate-image-array latent) img (PIL.Image.fromarray img-array "RGB")) img)) (def disk-image (latent fname) (let img (generate-image latent) (img (.save fname)) latent)) (def zspace-to-wspace (dlatent) (let dlatent (dlatent (.reshape '(1 -1))) (Gs_network.components.mapping (.run dlatent nil minibatch_size: 1 randomize_noise: false structure: "fixed")))) (defvar image-path* (os.path.join "/tmp" "images")) (defvar error-image* (PIL.Image.new size: '(16 16) mode: "RGB" color: "black")) (defvar saved-image* error-image*) (def next-path (base) (with i 0 (while (os.path.exists (% base i)) (inc i)))) (def image-path (idx) (let (fmt (os.path.join image-path* "image_%05d.png") idx (if (is? idx) idx (next-path fmt))) (% fmt idx))) (def save-image (img idx) (os.makedirs image-path* exist_ok: true) (let fname (image-path idx) (print (cat "Saving " fname)) (img.save fname "PNG") (global saved-image*) (set saved-image* (img.resize '(256 256))) img)) (def calculate-latent (spec) (with result (np.zeros shape: '(1 18 512)) (step (weight x) (pair spec) (let-when latent (if (string? x) (getattr latents* x) (array? x) x) (inc result (* weight latent)))))) (def generate-image-from-spec (spec) (let (latent (calculate-latent spec) img (generate-image latent)) ;(save-image img idx))) img)) (def randf () (np.random.uniform)) (def generate-random-image () (let spec (list (randf) 'trump (randf) 'hillary) (generate-image-from-spec spec))) (import tempfile) (mac with-temp-dir (var rest: body) `(with (tempfile.TemporaryDirectory suffix: ',(compile (cat "-" var))) as ,var ,@body)) (import PIL.Image) (from io import BytesIO) (def image-from-bytes (s) (PIL.Image.open (BytesIO (to-bytes s)))) (def image-to-bytes (img rest: args) (with-temp-dir tmp-image-dir (let fname (os.path.join tmp-image-dir "image") (apply img.save fname args) (with (open fname "rb") as f (f.read))))) (def image-to-bytes (img format quality) (let bs (BytesIO) ;(img.save bs format: (or format "PNG") quality: (or quality 95)) (img.save bs format: (or format "JPEG") quality: (or quality 90)) (bs (.getvalue)))) (defconst regen-delay* 3) (async def handle-serve-1 (websocket path) (let now (cat (datetime.datetime (.utcnow) (.isoformat)) "Z") (await (websocket.send now)) (await (asyncio.sleep (* (randf) regen-delay*))))) (async def handle-serve-1 (websocket path) (save-image (generate-random-image) 0) (await (websocket.send (image-to-bytes saved-image*))) (await (asyncio.sleep (* (randf) regen-delay*)))) (defconst ellipsize-limit* 240) (def ellipsize (s limit) (let n (either limit ellipsize-limit*) (if (> (# s) n) (cat (clip s 0 n) "...") s))) (async def handle-serve-1 (websocket path) (let x (await (websocket.recv)) (print (ellipsize (repr x))) (save-image (generate-random-image) 0) (await (websocket.send (image-to-bytes saved-image*))))) (import reader) (def image? (x) (isinstance x PIL.Image.Image)) (def bytes? (x) (isinstance x bytes)) (import inspect) (define-global awaitable? (x) (inspect.isawaitable x)) (async def awaitable (x) (if (awaitable? x) (await x) x)) (def gathered (x) ;(if (awaitable? x) x ((async fn () (if (function? x) (x) x))))) (if (awaitable? x) x ((async fn () x)))) (def current-task () (let ((ok v) (guard (asyncio.Task.current-task))) (if ok v (do (asyncio.set_event_loop (asyncio.new_event_loop)) (asyncio.Task.current-task))))) (import threading) (def current-thread () (threading.current_thread)) (defvar id-count* 1) (defvar id-lock* (threading.RLock)) (def get-id (x) (global id-count*) (with id-lock* (if (hasattr x "lumen_id") (getattr x "lumen_id") (with i (inc id-count*) (setattr x "lumen_id" i))))) (def current-task-id () (let task (current-task) (if task (get-id task) (get-id (current-thread))))) (%block class (Tagged Namespace) (def __init__ (self tag rep) (set self.tag tag self.rep rep) nil) (def __repr__ (self) (cat "Tagged(" (repr self.tag) ")"))) (def tagged? (x) (and (hasattr x 'tag) (hasattr x 'rep))) (def kind (x) (if (tagged? x) x.tag (type x))) (def tag (x y) (if (= (kind x) y) x (Tagged y x))) (def rep (x) (if (tagged? x) x.rep x)) (def make-thread-cell-value (cell value) (with self (tag nil 'thread-cell-value) (set self.cell cell self.value value self.rep self))) (def thread-cell-value? (v) (= (kind v) 'thread-cell-value)) (import weakref) (defvar preserved-thread-cells* (list)) (defvar preserved-thread-cell-values* (obj)) (def add-preserved-thread-cell (cell) (add preserved-thread-cells* (weakref.ref cell))) (def set-preserved-thread-cell-values (id vals) (set (get preserved-thread-cell-values* id) vals)) (def grab-preserved-thread-cell-values () (list (make-thread-cell-value cell (thread-cell-ref cell)) for cell in (array (map call preserved-thread-cells*)))) (def get-preserved-thread-cell-values (id) (has preserved-thread-cell-values* id)) (def find-preserved-thread-cell-value (vals cell) (step x vals (when (= x.cell cell) (return x.value))) cell.default) (def current-preserved-thread-cell-values args (if (none? args) (grab-preserved-thread-cell-values) (let vals (hd args) (step x preserved-thread-cells* (let-when x (x) (let v (find-preserved-thread-cell-value vals x) (thread-cell-set x v))))))) (def make-thread-cell (v preserved?) (with self (tag nil 'thread-cell) (set self.default v self.values (obj) ; (WeakValueDictionary) self.preserved preserved? self.rep self) (when preserved? (add-preserved-thread-cell self)))) (def thread-cell? (v) (= (kind v) 'thread-cell)) (def thread-cell-ref (v id) (let id (if (is? id) id (current-task-id)) (if (has? v.values id) (get v.values id) ;v.preserved ;(step x (get-preserved-thread-cell-values id) ; (when (= x.cell v) ; (return x.value))) v.default))) (def thread-cell-set (cell v) (unless (thread-cell? cell) (error "Expected thread-cell")) (let id (current-task-id) (if (nil? v) (wipe (get cell.values id)) (set (get cell.values id) v)))) (def create-task (f) (let (loop (event-loop) vals (current-preserved-thread-cell-values) thunk ((async fn () (current-preserved-thread-cell-values vals) (await (gathered f)))) task (loop.create-task thunk)) task)) (def schedule (f) (create-task f)) (define-macro thread body `(schedule ((async fn () ,@body)))) (defvar websocket* (make-thread-cell nil true)) (def current-socket args (if (none? args) (thread-cell-ref websocket*) (thread-cell-set websocket* (hd args)))) (async def send-full-image (img format quality) (let val (image-to-bytes img format quality) (await ((current-socket) (.send val))) img)) (async def send-image (img) (await (send-full-image (resize-image img '(256 256))))) (defvar data* (list)) (async def repl-print (form) (let ((ok v ex) (guard ((idx compiler eval) form))) (if (not ok) (print-exception v ex) (is? v) (let v (await (gathered v)) (do (print (ellipsize (repr v))) v))))) (async def handle-serve-1 (websocket path) (let x (await (websocket.recv)) (if (bytes? x) (do (add data* x) (await (websocket.send (cat "data*." (edge data*))))) (let form (reader.read-string x) (print (ellipsize (repr form))) (let (result (await (repl-print form)) result (if (image? result) result error-image*) ;result (result.resize '(256 256))) ) ;(await (websocket.send (image-to-bytes result "PNG")))))))) (await (send-full-image result))))))) (async def handle-serve (websocket path) (while true ;(load "repl.l") (current-socket websocket) (await (handle-serve-1 websocket path)))) (defvar start-server* (websockets.serve (fn args (apply handle-serve args)) "0.0.0.0" 5679 max_queue: nil read_limit: (* 100 1024 1024) write_limit: (* 100 1024 1024) max_size: (* 100 1024 1024))) (defvar server* nil) (def event-loop () (asyncio (.get-event-loop))) (def serve () (global server*) (set server* (or server* (asyncio (.get-event-loop) (.run-until-complete start-server*))))) (def setup (model-url perc-url model_res: res) (global sess) (tflib.init_tf) (set sess (tf.get_default_session)) (init-generator model-url res) (init-perceptual perc-url res) (init-resnet) (serve)) (def run-forever () (asyncio (.get-event-loop) (.run-forever))) (import os) (import sys) (import bz2) (import argparse) (from keras.utils import get_file) ;(from ffhq_dataset.face_alignment import image_align) ;(from ffhq_dataset.landmarks_detector import LandmarksDetector) (import multiprocessing) (defconst LANDMARKS_MODEL_URL "http://dlib.net/files/shape_predictor_68_face_landmarks.dat.bz2") (def unpack-bz2 (src-path) (let (f (bz2.BZ2File src_path) data (f.read) dst-path (get src-path (: -4))) (with (open dst-path "wb") as fp (fp.write data)) dst-path)) ;(defvar landmarks-model-path* ; (unpack_bz2 (get_file "shape_predictor_68_face_landmarks.dat.bz2" LANDMARKS_MODEL_URL cache_subdir: "temp"))) ;(defvar landmarks-detector* (LandmarksDetector landmarks-model-path*)) (def get-landmarks (img) (list marks for marks in (landmarks-detector*.get-landmarks img))) (def face-align (img) (let (img (numpy-to-image img) marks (get-landmarks img)) (if (none? marks) (do (print "No face detected") (img (.resize '(1024 1024) PIL.Image.ANTIALIAS) (.convert "RGB"))) (image-align img (hd marks))))) (def fetch-downsize (url) (let-when img (fetch-image url) (let img (convert-image img) (img.thumbnail '(1536 1536) PIL.Image.ANTIALIAS) img))) (def fetch-aligned (url) (face-align (fetch-downsize url))) ================================================ FILE: stylegan2-tpu/requirements.txt ================================================ absl-py==0.7.0 astor==0.7.1 certifi==2018.11.29 chardet==3.0.4 Click==7.0 Flask==1.0.2 Flask-Cors==3.0.7 gast==0.2.2 gevent==1.4.0 greenlet==0.4.15 grpcio==1.19.0 h5py==2.9.0 idna==2.8 itsdangerous==1.1.0 Jinja2==2.10 Keras-Applications==1.0.7 Keras-Preprocessing==1.0.9 Markdown==3.0.1 MarkupSafe==1.1.1 mock==2.0.0 numpy==1.16.2 pbr==5.1.2 Pillow==5.4.1 protobuf==3.6.1 requests==2.21.0 six==1.12.0 tensorflow-gpu==1.15.0 termcolor==1.1.0 urllib3==1.24.1 Werkzeug==0.14.1 wget==3.2 ================================================ FILE: stylegan2-tpu/run_generator.py ================================================ # Copyright (c) 2019, NVIDIA Corporation. All rights reserved. # # This work is made available under the Nvidia Source Code License-NC. # To view a copy of this license, visit # https://nvlabs.github.io/stylegan2/license.html import argparse import numpy as np import PIL.Image import dnnlib import dnnlib.tflib as tflib import re import sys import pretrained_networks #---------------------------------------------------------------------------- def generate_images(network_pkl, seeds, truncation_psi): print('Loading networks from "%s"...' % network_pkl) _G, _D, Gs = pretrained_networks.load_networks(network_pkl) noise_vars = [var for name, var in Gs.components.synthesis.vars.items() if name.startswith('noise')] Gs_kwargs = dnnlib.EasyDict() Gs_kwargs.output_transform = dict(func=tflib.convert_images_to_uint8, nchw_to_nhwc=True) Gs_kwargs.randomize_noise = False if truncation_psi is not None: Gs_kwargs.truncation_psi = truncation_psi for seed_idx, seed in enumerate(seeds): print('Generating image for seed %d (%d/%d) ...' % (seed, seed_idx, len(seeds))) rnd = np.random.RandomState(seed) z = rnd.randn(1, *Gs.input_shape[1:]) # [minibatch, component] tflib.set_vars({var: rnd.randn(*var.shape.as_list()) for var in noise_vars}) # [height, width] images = Gs.run(z, None, **Gs_kwargs) # [minibatch, height, width, channel] PIL.Image.fromarray(images[0], 'RGB').save(dnnlib.make_run_dir_path('seed%04d.png' % seed)) #---------------------------------------------------------------------------- def style_mixing_example(network_pkl, row_seeds, col_seeds, truncation_psi, col_styles, minibatch_size=4): print('Loading networks from "%s"...' % network_pkl) _G, _D, Gs = pretrained_networks.load_networks(network_pkl) w_avg = Gs.get_var('dlatent_avg') # [component] Gs_syn_kwargs = dnnlib.EasyDict() Gs_syn_kwargs.output_transform = dict(func=tflib.convert_images_to_uint8, nchw_to_nhwc=True) Gs_syn_kwargs.randomize_noise = False Gs_syn_kwargs.minibatch_size = minibatch_size print('Generating W vectors...') all_seeds = list(set(row_seeds + col_seeds)) all_z = np.stack([np.random.RandomState(seed).randn(*Gs.input_shape[1:]) for seed in all_seeds]) # [minibatch, component] all_w = Gs.components.mapping.run(all_z, None) # [minibatch, layer, component] all_w = w_avg + (all_w - w_avg) * truncation_psi # [minibatch, layer, component] w_dict = {seed: w for seed, w in zip(all_seeds, list(all_w))} # [layer, component] print('Generating images...') all_images = Gs.components.synthesis.run(all_w, **Gs_syn_kwargs) # [minibatch, height, width, channel] image_dict = {(seed, seed): image for seed, image in zip(all_seeds, list(all_images))} print('Generating style-mixed images...') for row_seed in row_seeds: for col_seed in col_seeds: w = w_dict[row_seed].copy() w[col_styles] = w_dict[col_seed][col_styles] image = Gs.components.synthesis.run(w[np.newaxis], **Gs_syn_kwargs)[0] image_dict[(row_seed, col_seed)] = image print('Saving images...') for (row_seed, col_seed), image in image_dict.items(): PIL.Image.fromarray(image, 'RGB').save(dnnlib.make_run_dir_path('%d-%d.png' % (row_seed, col_seed))) print('Saving image grid...') _N, _C, H, W = Gs.output_shape canvas = PIL.Image.new('RGB', (W * (len(col_seeds) + 1), H * (len(row_seeds) + 1)), 'black') for row_idx, row_seed in enumerate([None] + row_seeds): for col_idx, col_seed in enumerate([None] + col_seeds): if row_seed is None and col_seed is None: continue key = (row_seed, col_seed) if row_seed is None: key = (col_seed, col_seed) if col_seed is None: key = (row_seed, row_seed) canvas.paste(PIL.Image.fromarray(image_dict[key], 'RGB'), (W * col_idx, H * row_idx)) canvas.save(dnnlib.make_run_dir_path('grid.png')) #---------------------------------------------------------------------------- def _parse_num_range(s): '''Accept either a comma separated list of numbers 'a,b,c' or a range 'a-c' and return as a list of ints.''' range_re = re.compile(r'^(\d+)-(\d+)$') m = range_re.match(s) if m: return range(int(m.group(1)), int(m.group(2))+1) vals = s.split(',') return [int(x) for x in vals] #---------------------------------------------------------------------------- _examples = '''examples: # Generate ffhq uncurated images (matches paper Figure 12) python %(prog)s generate-images --network=gdrive:networks/stylegan2-ffhq-config-f.pkl --seeds=6600-6625 --truncation-psi=0.5 # Generate ffhq curated images (matches paper Figure 11) python %(prog)s generate-images --network=gdrive:networks/stylegan2-ffhq-config-f.pkl --seeds=66,230,389,1518 --truncation-psi=1.0 # Generate uncurated car images (matches paper Figure 12) python %(prog)s generate-images --network=gdrive:networks/stylegan2-car-config-f.pkl --seeds=6000-6025 --truncation-psi=0.5 # Generate style mixing example (matches style mixing video clip) python %(prog)s style-mixing-example --network=gdrive:networks/stylegan2-ffhq-config-f.pkl --row-seeds=85,100,75,458,1500 --col-seeds=55,821,1789,293 --truncation-psi=1.0 ''' #---------------------------------------------------------------------------- def main(): parser = argparse.ArgumentParser( description='''StyleGAN2 generator. Run 'python %(prog)s --help' for subcommand help.''', epilog=_examples, formatter_class=argparse.RawDescriptionHelpFormatter ) subparsers = parser.add_subparsers(help='Sub-commands', dest='command') parser_generate_images = subparsers.add_parser('generate-images', help='Generate images') parser_generate_images.add_argument('--network', help='Network pickle filename', dest='network_pkl', required=True) parser_generate_images.add_argument('--seeds', type=_parse_num_range, help='List of random seeds', required=True) parser_generate_images.add_argument('--truncation-psi', type=float, help='Truncation psi (default: %(default)s)', default=0.5) parser_generate_images.add_argument('--result-dir', help='Root directory for run results (default: %(default)s)', default='results', metavar='DIR') parser_style_mixing_example = subparsers.add_parser('style-mixing-example', help='Generate style mixing video') parser_style_mixing_example.add_argument('--network', help='Network pickle filename', dest='network_pkl', required=True) parser_style_mixing_example.add_argument('--row-seeds', type=_parse_num_range, help='Random seeds to use for image rows', required=True) parser_style_mixing_example.add_argument('--col-seeds', type=_parse_num_range, help='Random seeds to use for image columns', required=True) parser_style_mixing_example.add_argument('--col-styles', type=_parse_num_range, help='Style layer range (default: %(default)s)', default='0-6') parser_style_mixing_example.add_argument('--truncation-psi', type=float, help='Truncation psi (default: %(default)s)', default=0.5) parser_style_mixing_example.add_argument('--result-dir', help='Root directory for run results (default: %(default)s)', default='results', metavar='DIR') args = parser.parse_args() kwargs = vars(args) subcmd = kwargs.pop('command') if subcmd is None: print ('Error: missing subcommand. Re-run with --help for usage.') sys.exit(1) sc = dnnlib.SubmitConfig() sc.num_gpus = 1 sc.submit_target = dnnlib.SubmitTarget.LOCAL sc.local.do_not_copy_source_files = True sc.run_dir_root = kwargs.pop('result_dir') sc.run_desc = subcmd func_name_map = { 'generate-images': 'run_generator.generate_images', 'style-mixing-example': 'run_generator.style_mixing_example' } dnnlib.submit_run(sc, func_name_map[subcmd], **kwargs) #---------------------------------------------------------------------------- if __name__ == "__main__": main() #---------------------------------------------------------------------------- ================================================ FILE: stylegan2-tpu/run_metrics.py ================================================ # Copyright (c) 2019, NVIDIA Corporation. All rights reserved. # # This work is made available under the Nvidia Source Code License-NC. # To view a copy of this license, visit # https://nvlabs.github.io/stylegan2/license.html import argparse import os import sys import dnnlib import dnnlib.tflib as tflib import pretrained_networks from metrics import metric_base from metrics.metric_defaults import metric_defaults #---------------------------------------------------------------------------- def run(network_pkl, metrics, dataset, data_dir, mirror_augment): print('Evaluating metrics "%s" for "%s"...' % (','.join(metrics), network_pkl)) tflib.init_tf() network_pkl = pretrained_networks.get_path_or_url(network_pkl) dataset_args = dnnlib.EasyDict(tfrecord_dir=dataset, shuffle_mb=0) num_gpus = dnnlib.submit_config.num_gpus metric_group = metric_base.MetricGroup([metric_defaults[metric] for metric in metrics]) metric_group.run(network_pkl, data_dir=data_dir, dataset_args=dataset_args, mirror_augment=mirror_augment, num_gpus=num_gpus) #---------------------------------------------------------------------------- def _str_to_bool(v): if isinstance(v, bool): return v if v.lower() in ('yes', 'true', 't', 'y', '1'): return True elif v.lower() in ('no', 'false', 'f', 'n', '0'): return False else: raise argparse.ArgumentTypeError('Boolean value expected.') #---------------------------------------------------------------------------- _examples = '''examples: python %(prog)s --data-dir=~/datasets --network=gdrive:networks/stylegan2-ffhq-config-f.pkl --metrics=fid50k,ppl_wend --dataset=ffhq --mirror-augment=true valid metrics: ''' + ', '.join(sorted([x for x in metric_defaults.keys()])) + ''' ''' def main(): parser = argparse.ArgumentParser( description='Run StyleGAN2 metrics.', epilog=_examples, formatter_class=argparse.RawDescriptionHelpFormatter ) parser.add_argument('--result-dir', help='Root directory for run results (default: %(default)s)', default='results', metavar='DIR') parser.add_argument('--network', help='Network pickle filename', dest='network_pkl', required=True) parser.add_argument('--metrics', help='Metrics to compute (default: %(default)s)', default='fid50k', type=lambda x: x.split(',')) parser.add_argument('--dataset', help='Training dataset', required=True) parser.add_argument('--data-dir', help='Dataset root directory', required=True) parser.add_argument('--mirror-augment', help='Mirror augment (default: %(default)s)', default=False, type=_str_to_bool, metavar='BOOL') parser.add_argument('--num-gpus', help='Number of GPUs to use', type=int, default=1, metavar='N') args = parser.parse_args() if not os.path.exists(args.data_dir): print ('Error: dataset root directory does not exist.') sys.exit(1) kwargs = vars(args) sc = dnnlib.SubmitConfig() sc.num_gpus = kwargs.pop('num_gpus') sc.submit_target = dnnlib.SubmitTarget.LOCAL sc.local.do_not_copy_source_files = True sc.run_dir_root = kwargs.pop('result_dir') sc.run_desc = 'run-metrics' dnnlib.submit_run(sc, 'run_metrics.run', **kwargs) #---------------------------------------------------------------------------- if __name__ == "__main__": main() #---------------------------------------------------------------------------- ================================================ FILE: stylegan2-tpu/run_projector.py ================================================ # Copyright (c) 2019, NVIDIA Corporation. All rights reserved. # # This work is made available under the Nvidia Source Code License-NC. # To view a copy of this license, visit # https://nvlabs.github.io/stylegan2/license.html import argparse import numpy as np import dnnlib import dnnlib.tflib as tflib import re import sys import projector import pretrained_networks from training import dataset from training import misc #---------------------------------------------------------------------------- def project_image(proj, targets, png_prefix, num_snapshots): snapshot_steps = set(proj.num_steps - np.linspace(0, proj.num_steps, num_snapshots, endpoint=False, dtype=int)) misc.save_image_grid(targets, png_prefix + 'target.png', drange=[-1,1]) proj.start(targets) while proj.get_cur_step() < proj.num_steps: print('\r%d / %d ... ' % (proj.get_cur_step(), proj.num_steps), end='', flush=True) proj.step() if proj.get_cur_step() in snapshot_steps: misc.save_image_grid(proj.get_images(), png_prefix + 'step%04d.png' % proj.get_cur_step(), drange=[-1,1]) print('\r%-30s\r' % '', end='', flush=True) #---------------------------------------------------------------------------- def project_generated_images(network_pkl, seeds, num_snapshots, truncation_psi): print('Loading networks from "%s"...' % network_pkl) _G, _D, Gs = pretrained_networks.load_networks(network_pkl) proj = projector.Projector() proj.set_network(Gs) noise_vars = [var for name, var in Gs.components.synthesis.vars.items() if name.startswith('noise')] Gs_kwargs = dnnlib.EasyDict() Gs_kwargs.randomize_noise = False Gs_kwargs.truncation_psi = truncation_psi for seed_idx, seed in enumerate(seeds): print('Projecting seed %d (%d/%d) ...' % (seed, seed_idx, len(seeds))) rnd = np.random.RandomState(seed) z = rnd.randn(1, *Gs.input_shape[1:]) tflib.set_vars({var: rnd.randn(*var.shape.as_list()) for var in noise_vars}) images = Gs.run(z, None, **Gs_kwargs) project_image(proj, targets=images, png_prefix=dnnlib.make_run_dir_path('seed%04d-' % seed), num_snapshots=num_snapshots) #---------------------------------------------------------------------------- def project_real_images(network_pkl, dataset_name, data_dir, num_images, num_snapshots): print('Loading networks from "%s"...' % network_pkl) _G, _D, Gs = pretrained_networks.load_networks(network_pkl) proj = projector.Projector() proj.set_network(Gs) print('Loading images from "%s"...' % dataset_name) dataset_obj = dataset.load_dataset(data_dir=data_dir, tfrecord_dir=dataset_name, max_label_size=0, repeat=False, shuffle_mb=0) assert dataset_obj.shape == Gs.output_shape[1:] for image_idx in range(num_images): print('Projecting image %d/%d ...' % (image_idx, num_images)) images, _labels = dataset_obj.get_minibatch_np(1) images = misc.adjust_dynamic_range(images, [0, 255], [-1, 1]) project_image(proj, targets=images, png_prefix=dnnlib.make_run_dir_path('image%04d-' % image_idx), num_snapshots=num_snapshots) #---------------------------------------------------------------------------- def _parse_num_range(s): '''Accept either a comma separated list of numbers 'a,b,c' or a range 'a-c' and return as a list of ints.''' range_re = re.compile(r'^(\d+)-(\d+)$') m = range_re.match(s) if m: return range(int(m.group(1)), int(m.group(2))+1) vals = s.split(',') return [int(x) for x in vals] #---------------------------------------------------------------------------- _examples = '''examples: # Project generated images python %(prog)s project-generated-images --network=gdrive:networks/stylegan2-car-config-f.pkl --seeds=0,1,5 # Project real images python %(prog)s project-real-images --network=gdrive:networks/stylegan2-car-config-f.pkl --dataset=car --data-dir=~/datasets ''' #---------------------------------------------------------------------------- def main(): parser = argparse.ArgumentParser( description='''StyleGAN2 projector. Run 'python %(prog)s --help' for subcommand help.''', epilog=_examples, formatter_class=argparse.RawDescriptionHelpFormatter ) subparsers = parser.add_subparsers(help='Sub-commands', dest='command') project_generated_images_parser = subparsers.add_parser('project-generated-images', help='Project generated images') project_generated_images_parser.add_argument('--network', help='Network pickle filename', dest='network_pkl', required=True) project_generated_images_parser.add_argument('--seeds', type=_parse_num_range, help='List of random seeds', default=range(3)) project_generated_images_parser.add_argument('--num-snapshots', type=int, help='Number of snapshots (default: %(default)s)', default=5) project_generated_images_parser.add_argument('--truncation-psi', type=float, help='Truncation psi (default: %(default)s)', default=1.0) project_generated_images_parser.add_argument('--result-dir', help='Root directory for run results (default: %(default)s)', default='results', metavar='DIR') project_real_images_parser = subparsers.add_parser('project-real-images', help='Project real images') project_real_images_parser.add_argument('--network', help='Network pickle filename', dest='network_pkl', required=True) project_real_images_parser.add_argument('--data-dir', help='Dataset root directory', required=True) project_real_images_parser.add_argument('--dataset', help='Training dataset', dest='dataset_name', required=True) project_real_images_parser.add_argument('--num-snapshots', type=int, help='Number of snapshots (default: %(default)s)', default=5) project_real_images_parser.add_argument('--num-images', type=int, help='Number of images to project (default: %(default)s)', default=3) project_real_images_parser.add_argument('--result-dir', help='Root directory for run results (default: %(default)s)', default='results', metavar='DIR') args = parser.parse_args() subcmd = args.command if subcmd is None: print ('Error: missing subcommand. Re-run with --help for usage.') sys.exit(1) kwargs = vars(args) sc = dnnlib.SubmitConfig() sc.num_gpus = 1 sc.submit_target = dnnlib.SubmitTarget.LOCAL sc.local.do_not_copy_source_files = True sc.run_dir_root = kwargs.pop('result_dir') sc.run_desc = kwargs.pop('command') func_name_map = { 'project-generated-images': 'run_projector.project_generated_images', 'project-real-images': 'run_projector.project_real_images' } dnnlib.submit_run(sc, func_name_map[subcmd], **kwargs) #---------------------------------------------------------------------------- if __name__ == "__main__": main() #---------------------------------------------------------------------------- ================================================ FILE: stylegan2-tpu/run_training.py ================================================ # Copyright (c) 2019, NVIDIA Corporation. All rights reserved. # # This work is made available under the Nvidia Source Code License-NC. # To view a copy of this license, visit # https://nvlabs.github.io/stylegan2/license.html import argparse import copy import os import sys import dnnlib from dnnlib import EasyDict from metrics.metric_defaults import metric_defaults from tensorflow.python.platform import gfile #---------------------------------------------------------------------------- _valid_configs = [ # Table 1 'config-a', # Baseline StyleGAN 'config-b', # + Weight demodulation 'config-c', # + Lazy regularization 'config-d', # + Path length regularization 'config-e', # + No growing, new G & D arch. 'config-f', # + Large networks (default) # Table 2 'config-e-Gorig-Dorig', 'config-e-Gorig-Dresnet', 'config-e-Gorig-Dskip', 'config-e-Gresnet-Dorig', 'config-e-Gresnet-Dresnet', 'config-e-Gresnet-Dskip', 'config-e-Gskip-Dorig', 'config-e-Gskip-Dresnet', 'config-e-Gskip-Dskip', ] #---------------------------------------------------------------------------- def run(dataset, data_dir, result_dir, config_id, num_gpus, total_kimg, gamma, mirror_augment, metrics): train = EasyDict(run_func_name='training.training_loop.training_loop') # Options for training loop. G = EasyDict(func_name='training.networks_stylegan2.G_main') # Options for generator network. D = EasyDict(func_name='training.networks_stylegan2.D_stylegan2') # Options for discriminator network. G_opt = EasyDict(beta1=0.0, beta2=0.99, epsilon=1e-8) # Options for generator optimizer. D_opt = EasyDict(beta1=0.0, beta2=0.99, epsilon=1e-8) # Options for discriminator optimizer. G_loss = EasyDict(func_name='training.loss.G_logistic_ns_pathreg') # Options for generator loss. D_loss = EasyDict(func_name='training.loss.D_logistic_r1') # Options for discriminator loss. sched = EasyDict() # Options for TrainingSchedule. grid = EasyDict(size='8k', layout='random') # Options for setup_snapshot_image_grid(). sc = dnnlib.SubmitConfig() # Options for dnnlib.submit_run(). tf_config = {'rnd.np_random_seed': 1000} # Options for tflib.init_tf(). train.data_dir = data_dir train.total_kimg = total_kimg train.mirror_augment = mirror_augment train.image_snapshot_ticks = train.network_snapshot_ticks = 10 sched.G_lrate_base = float(os.environ['G_LR']) if 'G_LR' in os.environ else 0.002 sched.D_lrate_base = float(os.environ['D_LR']) if 'D_LR' in os.environ else 0.002 sched.G_lrate_base *= float(os.environ['G_LR_MULT']) if 'G_LR_MULT' in os.environ else 1.0 sched.D_lrate_base *= float(os.environ['D_LR_MULT']) if 'D_LR_MULT' in os.environ else 1.0 G_opt.beta2 = float(os.environ['G_BETA2']) if 'G_BETA2' in os.environ else 0.99 D_opt.beta2 = float(os.environ['D_BETA2']) if 'D_BETA2' in os.environ else 0.99 print('G_lrate: %f' % sched.G_lrate_base) print('D_lrate: %f' % sched.D_lrate_base) print('G_beta2: %f' % G_opt.beta2) print('D_beta2: %f' % D_opt.beta2) sched.minibatch_size_base = int(os.environ['BATCH_SIZE']) if 'BATCH_SIZE' in os.environ else num_gpus sched.minibatch_gpu_base = int(os.environ['BATCH_PER']) if 'BATCH_PER' in os.environ else 1 D_loss.gamma = 10 metrics = [metric_defaults[x] for x in metrics] desc = 'stylegan2' desc += '-' + dataset resolution = int(os.environ['RESOLUTION']) if 'RESOLUTION' in os.environ else 64 dataset_args = EasyDict(tfrecord_dir=dataset, resolution=resolution) assert num_gpus in [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192] sc.num_gpus = num_gpus desc += '-%dgpu' % num_gpus assert config_id in _valid_configs desc += '-' + config_id # Configs A-E: Shrink networks to match original StyleGAN. if config_id != 'config-f': G.fmap_base = D.fmap_base = 8 << 10 if 'FMAP_BASE' in os.environ: G.fmap_base = D.fmap_base = int(os.environ['FMAP_BASE']) << 10 else: G.fmap_base = D.fmap_base = 16 << 10 # default print('G_fmap_base: %d' % G.fmap_base) print('D_fmap_base: %d' % D.fmap_base) # Config E: Set gamma to 100 and override G & D architecture. if config_id.startswith('config-e'): D_loss.gamma = 100 if 'Gorig' in config_id: G.architecture = 'orig' if 'Gskip' in config_id: G.architecture = 'skip' # (default) if 'Gresnet' in config_id: G.architecture = 'resnet' if 'Dorig' in config_id: D.architecture = 'orig' if 'Dskip' in config_id: D.architecture = 'skip' if 'Dresnet' in config_id: D.architecture = 'resnet' # (default) # Configs A-D: Enable progressive growing and switch to networks that support it. if config_id in ['config-a', 'config-b', 'config-c', 'config-d']: sched.lod_initial_resolution = 8 sched.G_lrate_base = sched.D_lrate_base = 0.001 sched.G_lrate_dict = sched.D_lrate_dict = {128: 0.0015, 256: 0.002, 512: 0.003, 1024: 0.003} sched.minibatch_size_base = 32 # (default) sched.minibatch_size_dict = {8: 256, 16: 128, 32: 64, 64: 32} sched.minibatch_gpu_base = 4 # (default) sched.minibatch_gpu_dict = {8: 32, 16: 16, 32: 8, 64: 4} G.synthesis_func = 'G_synthesis_stylegan_revised' D.func_name = 'training.networks_stylegan2.D_stylegan' # Configs A-C: Disable path length regularization. if config_id in ['config-a', 'config-b', 'config-c']: G_loss = EasyDict(func_name='training.loss.G_logistic_ns') # Configs A-B: Disable lazy regularization. if config_id in ['config-a', 'config-b']: train.lazy_regularization = False # Config A: Switch to original StyleGAN networks. if config_id == 'config-a': G = EasyDict(func_name='training.networks_stylegan.G_style') D = EasyDict(func_name='training.networks_stylegan.D_basic') if gamma is not None: D_loss.gamma = gamma sc.submit_target = dnnlib.SubmitTarget.LOCAL sc.local.do_not_copy_source_files = True kwargs = EasyDict(train) kwargs.update(G_args=G, D_args=D, G_opt_args=G_opt, D_opt_args=D_opt, G_loss_args=G_loss, D_loss_args=D_loss) kwargs.update(dataset_args=dataset_args, sched_args=sched, grid_args=grid, metric_arg_list=metrics, tf_config=tf_config) kwargs.submit_config = copy.deepcopy(sc) kwargs.submit_config.run_dir_root = result_dir kwargs.submit_config.run_desc = desc dnnlib.submit_run(**kwargs) #---------------------------------------------------------------------------- def _str_to_bool(v): if isinstance(v, bool): return v if v.lower() in ('yes', 'true', 't', 'y', '1'): return True elif v.lower() in ('no', 'false', 'f', 'n', '0'): return False else: raise argparse.ArgumentTypeError('Boolean value expected.') def _parse_comma_sep(s): if s is None or s.lower() == 'none' or s == '': return [] return s.split(',') #---------------------------------------------------------------------------- _examples = '''examples: # Train StyleGAN2 using the FFHQ dataset python %(prog)s --num-gpus=8 --data-dir=~/datasets --config=config-f --dataset=ffhq --mirror-augment=true valid configs: ''' + ', '.join(_valid_configs) + ''' valid metrics: ''' + ', '.join(sorted([x for x in metric_defaults.keys()])) + ''' ''' def main(): parser = argparse.ArgumentParser( description='Train StyleGAN2.', epilog=_examples, formatter_class=argparse.RawDescriptionHelpFormatter ) parser.add_argument('--result-dir', help='Root directory for run results (default: %(default)s)', default='results', metavar='DIR') parser.add_argument('--data-dir', help='Dataset root directory', required=True) parser.add_argument('--dataset', help='Training dataset', required=True) parser.add_argument('--config', help='Training config (default: %(default)s)', default='config-f', required=True, dest='config_id', metavar='CONFIG') parser.add_argument('--num-gpus', help='Number of GPUs (default: %(default)s)', default=1, type=int, metavar='N') parser.add_argument('--total-kimg', help='Training length in thousands of images (default: %(default)s)', metavar='KIMG', default=25000, type=int) parser.add_argument('--gamma', help='R1 regularization weight (default is config dependent)', default=None, type=float) parser.add_argument('--mirror-augment', help='Mirror augment (default: %(default)s)', default=False, metavar='BOOL', type=_str_to_bool) parser.add_argument('--metrics', help='Comma-separated list of metrics or "none" (default: %(default)s)', default='fid50k', type=_parse_comma_sep) args = parser.parse_args() if not gfile.IsDirectory(args.data_dir): print ('Error: dataset root directory does not exist.') sys.exit(1) if args.config_id not in _valid_configs: print ('Error: --config value must be one of: ', ', '.join(_valid_configs)) sys.exit(1) for metric in args.metrics: if metric not in metric_defaults: print ('Error: unknown metric \'%s\'' % metric) sys.exit(1) run(**vars(args)) #---------------------------------------------------------------------------- if __name__ == "__main__": main() #---------------------------------------------------------------------------- ================================================ FILE: stylegan2-tpu/test_nvcc.cu ================================================ // Copyright (c) 2019, NVIDIA Corporation. All rights reserved. // // This work is made available under the Nvidia Source Code License-NC. // To view a copy of this license, visit // https://nvlabs.github.io/stylegan2/license.html #include void checkCudaError(cudaError_t err) { if (err != cudaSuccess) { printf("%s: %s\n", cudaGetErrorName(err), cudaGetErrorString(err)); exit(1); } } __global__ void cudaKernel(void) { printf("GPU says hello.\n"); } int main(void) { printf("CPU says hello.\n"); checkCudaError(cudaLaunchKernel((void*)cudaKernel, 1, 1, NULL, 0, NULL)); checkCudaError(cudaDeviceSynchronize()); return 0; } ================================================ FILE: stylegan2-tpu/tflex.py ================================================ import tensorflow as tf import numpy as np from glob import glob import os import re from tensorflow.python import pywrap_tensorflow import tqdm import h5py import shutil import tempfile import traceback import time import threading from tensorflow.python.framework import dtypes from tensorflow.python.distribute.cluster_resolver import TPUClusterResolver as BaseTPUClusterResolver from tensorflow.python.training import server_lib from tensorflow.core.protobuf import rewriter_config_pb2 from tensorflow.contrib import tpu class _DefaultState(threading.local): def __init__(self, **kws): super(_DefaultState, self).__init__() for k, v in kws.items(): setattr(self, k, v) def save(self): return [(k, v) for k, v in self.__dict__.items()] def restore(self, state): for k, v in state: setattr(self, k, v) local = _DefaultState() lock = threading.RLock() def with_defaults(thunk): with lock: state = local.save() session = tf.get_default_session() or get_default_session() graph = tf.get_default_graph() or get_default_graph() def f(*args, **kws): with lock: local.restore(state) lock.acquire() with session.as_default() if session else nullcontext(): with graph.as_default() if graph else nullcontext(): lock.release() result = thunk(*args, **kws) lock.acquire() lock.release() return result return f def get_default(name, required=True): with lock: value = getattr(local, name) if hasattr(local, name) else None if required: assert value is not None return value def set_default(name, value): with lock: setattr(local, name, value) def ensure_default(name, value): with lock: current = get_default(name, required=False) if current is None: set_default(name, value) return value def get_default_session(required=False): return get_default('session', required=required) def get_default_graph(required=False): return get_default('graph', required=required) class Future(object): def __init__(self, dependencies, thunk, *args, **kws): if isinstance(dependencies, Future): dependencies = [dependencies] self.dependencies = [defer(_) if callable(_) else _ for _ in dependencies] if thunk is None: thunk = lambda: None self.thunk = thunk self.args = args self.kws = kws self.result = None self.complete = False self.thread = None self.daemon = True self.error = None def run(self): try: self.result = self.thunk(*self.args, **self.kws) except Exception as e: traceback.print_exc() self.error = e self.complete = True def run_async(self): assert self.thread is None def thunk(): [_.join() for _ in self.dependencies] self.run() self.thread = threading.Thread(target=with_defaults(thunk), daemon=self.daemon) self.thread.start() def join(self): if not self.complete: assert self.thread while not self.complete: time.sleep(1.0) return self.result def defer(thunk, *args, **kws): dependencies = [] if 'dependencies' in kws: dependencies = kws.pop('dependencies') future = Future(dependencies=dependencies, thunk=thunk, *args, **kws) future.run_async() return future def parallelize(xs, thunk, *args, daemon=True): threads = [] for x in xs: thread = threading.Thread(target=with_defaults(thunk), args=(x, *args), daemon=daemon) thread.start() threads.append(thread) return threads def parallelize_verbose(label, xs, thunk, *args, daemon=True): xs = [x for x in xs] with tqdm.tqdm(total=len(xs)) as pbar: pbar.set_description(label) def run(*args, **kws): try: return thunk(*args, **kws) finally: pbar.update(1) return parallelize(xs, run, *args, daemon=daemon) def parallelize_verbose(label, xs, thunk, *args, daemon=True, synchronous=False): xs = [x for x in xs] if synchronous: for i in tqdm.trange(len(xs), desc=label): x = xs[i] thunk(x, *args) else: with tqdm.tqdm(total=len(xs)) as pbar: pbar.set_description(label) threads = parallelize(xs, thunk, *args, daemon=daemon) while len(threads) > 0: for i in range(len(threads)): if not threads[i].is_alive(): pbar.update(1) threads.remove(threads[i]) break time.sleep(0.1) # http://stackoverflow.com/questions/1624883/alternative-way-to-split-a-list-into-groups-of-n import itertools def group(n, iterable, fillvalue=None): "group(3, 'ABCDEFG', 'x') --> ABC DEF Gxx" args = [iter(iterable)] * n return itertools.zip_longest(*args, fillvalue=fillvalue) def tuples(*args, **kws): return [x for x in group(*args, **kws)] class Namespace(object): pass if 'state' not in globals(): state = Namespace() if not hasattr(state, 'noisy'): state.noisy = 'NOISY' in os.environ if not hasattr(state, 'debug'): state.debug = 'DEBUG' in os.environ if not hasattr(state, 'noisy_backtrace'): state.noisy_backtrace = 'NOISY_BACKTRACE' in os.environ if not hasattr(state, 'break_next_run'): state.break_next_run = False def reroute(addr, host=None): if host is None or host is False: return addr if addr.startswith('grpc://'): return 'grpc://' + reroute(addr[len('grpc://'):], host=host) if not re.match('[0-9]+[.][0-9]+[.][0-9]+[.][0-9]+[:]8470', addr): return addr if not addr.endswith(':8470'): return addr a, b, c, d = [int(x) for x in addr.split(':')[0].split('.')] if a == 10 and b in [48, 49]: assert (d == 2) port = b * 1000 + c elif a == 10 and b in range(2, 66) and c == 0: port = b * 1000 + d else: return addr return host + ':' + str(port) class TPUClusterResolver(BaseTPUClusterResolver): def __init__(self, *args, host=None, **kws): super(TPUClusterResolver, self).__init__(*args, **kws) if host is None: if 'TPU_HOST' in os.environ: host = os.environ['TPU_HOST'] self._host = host def master(self, *args, **kws): ip = super(TPUClusterResolver, self).master(*args, **kws) return reroute(ip, host=self._host) def cluster_spec(self): spec = super(TPUClusterResolver, self).cluster_spec() r = dict() for k, v in spec.as_dict().items(): r[k] = [reroute(ip, host=self._host) for ip in v] return server_lib.ClusterSpec(r) def init_tpu(name, host=None, timeout_in_ms=600 * 60 * 1000): tpu_init = [tpu.initialize_system()] cluster_resolver = TPUClusterResolver(name, host=host) config = tf.ConfigProto(operation_timeout_in_ms=timeout_in_ms, graph_options=tf.GraphOptions( rewrite_options=rewriter_config_pb2.RewriterConfig( disable_meta_optimizer=True)), isolate_session_state=True) cluster_spec = cluster_resolver.cluster_spec() if cluster_spec: config.cluster_def.CopyFrom(cluster_spec.as_cluster_def()) init_sess = tf.Session(cluster_resolver.get_master(), config=config) init_sess.run(tpu_init) return init_sess, cluster_resolver def get_session(session=None): if session is None: session = get_default_session() return session def get_devices(session=None): session = get_session(session) if hasattr(session, '_cached_devices'): devices = session._cached_devices else: devices = session._cached_devices = session.list_devices() return devices def has_gpu(session=None): session = get_session(session) if hasattr(session, '_has_gpu'): result = session._has_gpu else: devices = get_devices(session=session) result = session._has_gpu = len([x for x in devices if ':GPU:' in x.name]) > 0 return result def has_tpu(session=None): session = get_session(session) if hasattr(session, '_has_tpu'): result = session._has_tpu else: devices = get_devices(session=session) result = session._has_tpu = len([x for x in devices if ':TPU:' in x.name]) > 0 return result def get_cores_from_devices(devices): cores = [x for x in devices if ':TPU:' in x.name] if len(cores) <= 0: cores = [x for x in devices if ':GPU:' in x.name] if len(cores) <= 0: cores = [x for x in devices if ':CPU:' in x.name] return cores def get_cores(session=None, devices=None): if devices is None: devices = get_devices(session=session) return get_cores_from_devices(devices) def get_cpus(session=None, devices=None): if devices is None: devices = get_devices(session=session) cpus = [x for x in devices if ':CPU:' in x.name] return cpus def get_tpu_resolver(tpu_name='auto'): # Get the TPU's location if tpu_name != 'auto': return TPUClusterResolver(tpu_name) elif 'COLAB_TPU_ADDR' in os.environ: return TPUClusterResolver() elif 'TPU_NAME' in os.environ: return TPUClusterResolver(os.environ['TPU_NAME']) def pretty(x, ellipsize=120): r = str(x) if len(r) > ellipsize: return r[0:ellipsize - 3] + '...' return r def print_backtrace(): try: raise Exception("Printing traceback...") except: import traceback traceback.print_exc() class Session(tf.Session): def __init__(self, target='auto', graph=None, config=None, init_tpu=False, id=None): if config is None: timeout_in_ms = int(os.environ['TIMEOUT_IN_MS']) if 'TIMEOUT_IN_MS' in os.environ else 10 * 60 * 1000 config = tf.ConfigProto(operation_timeout_in_ms=timeout_in_ms, graph_options=tf.GraphOptions( rewrite_options=rewriter_config_pb2.RewriterConfig( disable_meta_optimizer=True)), isolate_session_state=True) config.isolate_session_state = True resolver = get_tpu_resolver(target) if resolver is not None: target = resolver.get_master() cluster_spec = resolver.cluster_spec() if cluster_spec: config.cluster_def.CopyFrom(cluster_spec.as_cluster_def()) elif target == 'auto': target = None super().__init__(target, graph=graph, config=config) self.id = id self._tflex_resolver = resolver self._tflex_target = target self._tflex_config = config ensure_default('session', self) ensure_default('devices', self.list_devices()) ensure_default('graph', self.graph) @property def _spec(self): return '#%d' % self.id if self.id is not None else '' def ensure(self): if self.init_tpu: print(self._spec, "Initializing TPU...") #sess.run(tpu.initialize_system()) init_tpu(session=self, timeout_in_ms=20000) self.init_tpu = None def run(self, *args, **kws): if state.break_next_run: import pdb; pdb.set_trace() if state.debug: check_commands() if state.noisy: print(self._spec, 'Session.run', *[pretty(x) for x in args], *[pretty(k)+'='+pretty(v) for k, v in kws.items()]) if state.noisy_backtrace: print_backtrace() start = time.time() result = super(Session, self).run(*args, **kws) elapsed = time.time() - start if state.noisy: print(self._spec, 'Session.run (finished in %.2fs)' % elapsed, pretty(result), *[pretty(x) for x in args], *[pretty(k)+'='+pretty(v) for k, v in kws.items()]) if state.noisy_backtrace: print_backtrace() return result def split_by_params(vs, n=20e6, f=None): if f is None: f = lambda x: np.prod(x.shape.as_list()) i = 0 xs = [] for variable in vs: xs.append(variable) count = f(variable) i += count if i >= n: yield xs xs = [] i = 0 yield xs def latest_checkpoint(checkpoint_dir, latest_filename=None): paths = [x for x in glob(os.path.join(checkpoint_dir, 'model-*.*')) if not x.endswith(".tmp")] ctrs = np.array([[int(y) for y in re.findall(r'model-([0-9]+)(?:-[0-9]+)?[.](?:npy|hdf5)', x)] for x in paths]).flatten() if len(ctrs) <= 0: ckpt = tf.train.latest_checkpoint(checkpoint_dir, latest_filename=latest_filename) return ckpt ctr = ctrs.max() return os.path.join(checkpoint_dir, 'model-{}').format(ctr) def truncate_value(variable, value, reshape=True): if not reshape: return value shape = variable.shape.as_list() params = np.prod(shape) params2 = np.prod(value.shape) if params == params2: return value print('Truncating {} from shape {} to shape {}'.format(variable.name, value.shape, shape)) value = np.array(value) value = value.reshape([-1]) value = value[0:params] value = value.reshape(shape) return value from tensorflow.core.protobuf import config_pb2 def initialize_tpu(session=None, timeout_in_ms=None): session = session or get_default_session() with session.as_default(): op = tpu.initialize_system() options = None if timeout_in_ms: options=config_pb2.RunOptions(timeout_in_ms=timeout_in_ms) return session.run(op, options=options) def load(variable, value, session=None, timeout_in_ms=None): session = session or get_default_session() ops = variable.initializer vals = dict([(variable.initializer.inputs[1], value)]) #for x, (k, v) in zip(variables, vals.items()): # print(x.name, x.shape.as_list(), k, v.shape) options = None if timeout_in_ms: options=config_pb2.RunOptions(timeout_in_ms=timeout_in_ms) return session.run(ops, vals, options=options) def eval(variable, session=None, timeout_in_ms=None): session = session or get_default_session() options = None if timeout_in_ms: options=config_pb2.RunOptions(timeout_in_ms=timeout_in_ms) return session.run(variable, options=options) def grab_values(variables, reader, reshape=False): for variable in variables: name = variable_name(variable).split(':')[0] value = reader.get_tensor(name) value = truncate_value(variable, value, reshape=reshape) yield variable, value def assign_values(variables, values, session=None, timeout_in_ms=60000): session = session or get_default_session() variables = [x for x in variables] values = [x for x in values] ops = [x.initializer for x in variables] vals = dict([(x.initializer.inputs[1], value.value() if isinstance(value, tf.Variable) else value) for x, value in zip(variables, values)]) # TODO: bfloat16 support #for x, (k, v) in zip(variables, vals.items()): # print(x.name, x.shape.as_list(), k, v.shape) options = None if timeout_in_ms: options=config_pb2.RunOptions(timeout_in_ms=timeout_in_ms) session.run(ops, vals, options=options) def load_snapshot(ckpt, session=None, var_list=None, reshape=False): session = session or get_default_session() reader = pywrap_tensorflow.NewCheckpointReader(ckpt) vs = var_list or tf.trainable_variables() for variables in tqdm.tqdm(list(split_by_params(vs))): values = [value for variable, value in grab_values(variables, reader, reshape=reshape)] assign_values(variables, values, session=session) def get_variable(name, var_list=None): name, num = name.split(':') if ':' in name else (name, '0') num = int(num) name = os.path.join(tf.get_variable_scope().name, name) vs = var_list or tf.trainable_variables() for x in vs: if x.name.startswith(name + ':%d' % num): return x def load_weights(ckpt, session=None, var_list=None, reshape=False): session = session or get_default_session() vs = var_list or tf.trainable_variables() files = list(sorted(glob(ckpt + '-*.npy'))) for out in tqdm.tqdm(files): for name, value in np.load(out, allow_pickle=True): variable = get_variable(name) if variable is None: print('Warning: variable %s not loaded' % name) else: value = truncate_value(variable, value, reshape=reshape) variable.load(value, session) def load_variables(ckpt, session=None, var_list=None, reshape=False): session = session or get_default_session() vs = var_list or tf.trainable_variables() with h5py.File(ckpt, "r") as f: for variables in tqdm.tqdm(list(split_by_params(vs))): values = [truncate_value(x, f[variable_name(x)], reshape=reshape) for x in variables] assign_values(variables, values, session=session) def maketree(path): try: os.makedirs(path) except: pass state.cache_ops = {} def cast_variables(variables, graph=None, cache_ops=None): if graph is None: graph = get_default_graph() if cache_ops is None: cache_ops = state.cache_ops if graph not in cache_ops: cache_ops[graph] = {} cache = cache_ops[graph] ops = [] for variable in variables: if variable in cache: op = cache[variable] elif variable.dtype == dtypes.bfloat16_ref or variable.dtype == tf.bfloat16: op = tf.cast(variable, tf.float32) else: op = variable cache[variable] = op ops.append(op) return ops import re def variable_name(variable): if re.match(r'core[0-9]+/', variable.name): return variable.name.split('/', 1)[-1] return variable.name def save_variables(ckpt, session=None, var_list=None): session = session or get_default_session() vs = var_list or tf.trainable_variables() maketree(os.path.dirname(ckpt)) fname = ckpt+'.tmp' with h5py.File(fname, "w") as f: for variables in tqdm.tqdm(list(split_by_params(vs))): ops = cast_variables(variables) values = session.run(ops) for value, variable in zip(values, variables): name = variable_name(variable) shape = variable.shape.as_list() dtype = variable.dtype dset = f.create_dataset(name, shape, dtype=np.float32) dset[:] = value print('Writing snapshot %s' % ckpt) os.rename(ckpt+'.tmp', ckpt) def fetch_variables(session=None, var_list=None): session = session or get_default_session() vs = var_list or tf.trainable_variables() for variables in tqdm.tqdm(list(split_by_params(vs))): values = session.run(variables) yield variables, values def partition_variables(session=None, var_list=None): session = session or get_default_session() vs = var_list or tf.trainable_variables() for variables in tqdm.tqdm(list(split_by_params(vs))): yield variables class Saver(object): def __init__( self, var_list=None, reshape=False, sharded=False, max_to_keep=5, keep_checkpoint_every_n_hours=10000.0, name=None, restore_sequentially=False, saver_def=None, builder=None, defer_build=False, allow_empty=False, write_version=tf.train.SaverDef.V2, pad_step_number=False, save_relative_paths=False, filename=None): self.var_list = var_list self.reshape = reshape self.sharded = sharded self.max_to_keep = max_to_keep self.keep_checkpoint_every_n_hours = keep_checkpoint_every_n_hours self.name = name self.restore_sequentially = restore_sequentially self.saver_def = saver_def self.builder = builder self.defer_build = defer_build self.allow_empty = allow_empty self.write_version = write_version self.pad_step_number = pad_step_number self.save_relative_paths = save_relative_paths self.filename = filename self.checkpoints = [] def restore(self, sess, save_path): if save_path.endswith('.ckpt'): load_snapshot(save_path, session=sess, var_list=self.var_list, reshape=self.reshape) elif save_path.endswith('.hdf5'): load_variables(save_path, session=sess, var_list=self.var_list, reshape=self.reshape) elif os.path.exists(save_path + '.npy') or os.path.exists(save_path + '-0.npy'): load_weights(save_path, session=sess, var_list=self.var_list, reshape=self.reshape) elif os.path.exists(save_path + '.hdf5'): load_variables(save_path + '.hdf5', session=sess, var_list=self.var_list, reshape=self.reshape) else: raise Exception("Can't load checkpoint %s" % save_path) def save(self, sess, save_path, global_step=None, latest_filename=None, meta_graph_suffix="meta", write_meta_graph=True, write_state=True, strip_default_attrs=False, save_debug_info=False): if global_step is not None: name = '%s-%d.hdf5' % (save_path, global_step) else: name = '%s.hdf5' % save_path save_variables(name, session=sess, var_list=self.var_list) self.checkpoints.append(name) if self.max_to_keep > 0: while len(self.checkpoints) > self.max_to_keep: fname = self.checkpoints[0] if fname != name: print('Truncating %s' % fname) try: with open(fname, "wb") as f: pass except: print('Failed to truncate %s' % fname) self.checkpoints = self.checkpoints[1:] def fetch(self, sess, var_list=None): if var_list == None: var_list = self.var_list for variables, values in fetch_variables(session=sess, var_list=var_list): yield variables, values def variables(self, sess, var_list=None): if var_list == None: var_list = self.var_list for variables in partition_variables(session=sess, var_list=var_list): yield variables def assign(self, sess, variables, values): return assign_values(variables, values, session=sess) class Commands(object): def __init__(self, path='commands'): self.path = path self.commands = [] self.args = [] self.keys = {} self.frozen = False def has(self, name, **keys): if 'action' in keys: action = keys.pop('action') for name1, action1 in self.commands: if name == name1 and action1 == action: return True else: for name1, action1 in self.commands: if name == name1: return True return False def add(self, name, action=None): if not self.has(name=name, action=action): self.commands.append((name, action)) full = self.full_path(name) maketree(full) def full_path(self, name): return os.path.join(self.path, name) def check(self, *args, **keys): if not self.frozen: heartbeat() ops = [] seen = set() for name, action in self.commands: full = self.full_path(name) if not os.path.isdir(full): if name not in seen: seen.add(name) ops.append(name) for op in ops: self.run(op, *args, **keys) return ops def run(self, op): ran = False for name, action in self.commands: if name == op: print('Running command', name, action) if not ran: full = self.full_path(op) maketree(full) ran = True if action: action() if not ran: raise Exception('Commands.execute failed: no such command: {}'.format(op)) def run_with_args(self, op, *args, **keys): with CommandArgs(*args, **keys): return self.run(op) commander = None def commands(**keys): global commander if commander is None: commander = Commands() cmds = keys.pop('commands') if 'commands' in keys else None if cmds is not None: for cmd in cmds: action = None if isinstance(cmd, str): name = cmd elif len(cmd) >= 2: name, action = cmd elif len(cmd) >= 1: name = cmd[0] else: continue commander.add(name=name, action=action) return commander class CommandArgs(object): def __init__(self, *args, **keys): self.args = list(args) self.keys = keys.copy() self.cmdr = commands() def __enter__(self): self.args_prev = self.cmdr.args self.keys_prev = self.cmdr.keys self.cmdr.args = self.args self.cmdr.keys = self.keys def __exit__(self, *excinfo): self.cmdr.args = self.args_prev self.cmdr.keys = self.keys_prev def check_commands(): try: cmdr = commands() return cmdr.check() except: traceback.print_exc() def check_commands_with_args(*args, **keys): try: cmdr = commands() with CommandArgs(*args, **keys): return cmdr.check() except: traceback.print_exc() def add_command(name, action=None, **keys): cmdr = commands() return cmdr.add(name=name, action=action) def register_command(*args, **keys): fn = args[0] if isinstance(fn, str): add_command(fn) else: name = fn.__qualname__ name = name.replace('..', '_command_') if name.endswith('_command_save'): name = 'save' name = name.replace('___', '/') action = fn print(name, action) add_command(name, action) return fn def has_command(name): cmdr = commands() return cmdr.has(name) def run_command(command_name): cmdr = commands() return cmdr.run(command_name) def run_command_with_args(command_name, *args, **keys): cmdr = commands() return cmdr.run_with_args(command_name, *args, **keys) def command_arg(x, unset=None): cmdr = commands() if isinstance(x, int): try: return cmdr.args[x] except: return unset else: if x in cmdr.keys: return cmdr.keys[x] return unset def command_args(): cmdr = commands() return cmdr.args, cmdr.keys @register_command def attach_debugger(): import pdb pdb.set_trace() from pprint import pprint @register_command def print_status(): args, props = command_args() for k, v in enumerate(args): pprint(v) for k, v in props.items(): pprint({k: v}) # # return current UTC timestamp. # def utc(): from datetime import datetime d = datetime.utcnow() import calendar return calendar.timegm(d.utctimetuple()) def heartbeat(): pongfile=os.environ['PONG'] if 'PONG' in os.environ else 'pong.txt' with open(pongfile, "a+") as f: nonce = os.urandom(8).hex() now=utc() out="pid{}_time{}_nonce{}\n".format(os.getpid(), now, nonce) #print("PONG! Writing {} to {}".format(out, pongfile)) f.write(out) f.flush() import time @register_command def freeze_forever(): cmdr = commands() if cmdr.frozen: print("Already frozen.") return prev = cmdr.frozen cmdr.frozen = True print('Simulating a freeze; going into an infinite loop:') prev=time.time() try: while not should_quit(): elapsed=time.time() - prev print('Frozen for {}s'.format(elapsed)) time.sleep(1) check_commands() finally: cmdr.frozen = prev _quit = False import sys @register_command def quit(): global _quit if _quit: print("Failed to quit; running sys.exit(1)") sys.exit(1) else: print("Quitting...") _quit = True def should_quit(): return _quit @register_command def save_and_quit(): global _quit if has_command('save'): print("Saving...") run_command('save') quit() @register_command def throw_exception(): raise Exception("This exception should be caught and logged by the tflex command system") import tensorflow as tf from contextlib import contextmanager @contextmanager def nullcontext(enter_result=None): yield enter_result def set_override_device(value, session=None): session = get_session(session) session._override_device = value return value def has_override_device(session=None): session = get_session(session) return hasattr(session, '_override_device') def get_override_device(session=None): session = get_session(session) if hasattr(session, '_override_device'): return session._override_device def set_override_cores(value, session=None): session = get_session(session) session._override_cores = value return value def has_override_cores(session=None): session = get_session(session) return hasattr(session, '_override_cores') def get_override_cores(session=None): session = get_session(session) if hasattr(session, '_override_cores'): return session._override_cores def device_for_tpu_core(task=0, core=0, job_name="tpu_worker"): return "/job:%s/task:%d/device:TPU_REPLICATED_CORE:%d" % (job_name, task, core) def device(name=''): if has_override_device(): return nullcontext() if has_override_cores(): if name is None: return tf.device(name) if name.startswith('/gpu:'): i = int(name.split(':', 1)[-1]) return tf.device(get_cores()[i].name) if name.startswith('/tpu:'): i = int(name.split(':', 1)[-1]) return tf.device(device_for_tpu_core(core=i)) if name.startswith('/cpu:'): i = int(name.split(':', 1)[-1]) return tf.device(get_cpus()[i].name) return nullcontext() if name is None: return tf.device(None) if 'gpu' in name: if has_gpu(): return tf.device(name) if 'cpu' in name: return tf.device(name) return nullcontext() def tuples(l, n=2): r = [] for i in range(0, len(l), n): r.append(l[i:i+n]) return r import hashlib def sha256hex(x): if isinstance(x, str): x = x.encode('utf8') return hashlib.sha224(x).hexdigest() def sha256label(x): return [int(x, 16) / 255 * 2 - 1 for x in tuples(sha256hex(x))] ================================================ FILE: stylegan2-tpu/tflex_test.py ================================================ import sys import tflex import time def make_future(label, delay=0.0, deps=[], thunk=None, args=[]): def toplevel(): if delay is not None and delay > 0.0: time.sleep(delay) nonlocal thunk, args if callable(thunk): thunk(*args) nonlocal label if callable(label): label = label() print('Future {}'.format(label)) return tflex.defer(thunk=toplevel, dependencies=deps) def warmup(): make_future('warmup', 0.0).join() def test1(): a = make_future('A', 0.1) b = make_future('B', 0.0, deps=[a]) c = make_future('C', 0.0, deps=[a, b]) make_future('done', 0.0, deps=[a, b, c]).join() def test2(): a = make_future('A', 0.1) b = make_future('B', 0.0) c = make_future('C', 0.2) make_future('done', 0.0, deps=[a, b, c]).join() def test3(): tflex.local.foo = 'foo' make_future(lambda: tflex.local.foo).join() def test4(): tflex.local.foo = 'foo' def bar(): tflex.local.foo = 'bar' make_future(lambda: tflex.local.foo, thunk=bar).join() make_future(lambda: tflex.local.foo).join() def test5(): tflex.local.foo = 'foo' def baz(): tflex.local.foo = 'baz' def bar(): make_future(lambda: tflex.local.foo, thunk=baz).join() tflex.local.foo = 'bar' make_future(lambda: tflex.local.foo, thunk=bar).join() make_future(lambda: tflex.local.foo).join() def run_test(name, thunk, *args, **kws): print('Running {}'.format(name)) sys.stdout.flush() start_time = time.time() result = thunk(*args, **kws) end_time = time.time() print('Finished {} in {:.2f}'.format(name, end_time - start_time)) print('--------------------') def run_tests(): run_test('warmup', warmup) run_test('test1', test1) run_test('test2', test2) run_test('test3', test3) run_test('test4', test4) run_test('test5', test5) if __name__ == '__main__': run_tests() ================================================ FILE: stylegan2-tpu/train_tpu.sh ================================================ #!/bin/bash source "$HOME/bin/activate-tf1" set -e export NOISY=1 export DEBUG=1 export TPU_NAME=grpc://0.tcp.ngrok.io:12547 cores=8 #config="config-a" # StyleGAN 1 config="config-f" # StyleGAN 2 data_dir=gs://sgappa-multi/stylegan-encoder/datasets dataset=animefaces mirror=false metrics=none export LABEL_SIZE=0 #export LABEL_SIZE=full # uncomment this if using labels export MODEL_DIR=gs://danbooru-euw4a/test/run50-danbooru-512-conditional-subset-128 export BATCH_PER=4 export BATCH_SIZE=$(($BATCH_PER * $cores)) export RESOLUTION=512 set -x exec python3 -m pdb -c continue run_training.py --data-dir "${data_dir}" --config="${config}" --dataset="${dataset}" --mirror-augment="${mirror}" --metrics="${metrics}" "$@" ================================================ FILE: stylegan2-tpu/training/__init__.py ================================================ # Copyright (c) 2019, NVIDIA Corporation. All rights reserved. # # This work is made available under the Nvidia Source Code License-NC. # To view a copy of this license, visit # https://nvlabs.github.io/stylegan2/license.html # empty ================================================ FILE: stylegan2-tpu/training/dataset.py ================================================ # Copyright (c) 2019, NVIDIA Corporation. All rights reserved. # # This work is made available under the Nvidia Source Code License-NC. # To view a copy of this license, visit # https://nvlabs.github.io/stylegan2/license.html """Multi-resolution input data pipeline.""" import os import re import numpy as np import tensorflow as tf import tflex import dnnlib import dnnlib.tflib as tflib from tensorflow.python.platform import gfile from tensorflow.python.framework import errors_impl #---------------------------------------------------------------------------- # Dataset class that loads data from tfrecords files. class TFRecordDataset: def __init__(self, tfrecord_dir, # Directory containing a collection of tfrecords files. resolution = None, # Dataset resolution, None = autodetect. label_file = None, # Relative path of the labels file, None = autodetect. max_label_size = None, # 0 = no labels, 'full' = full labels, = N first label components. max_images = None, # Maximum number of images to use, None = use all images. repeat = True, # Repeat dataset indefinitely? shuffle_mb = 4096, # Shuffle data within specified window (megabytes), 0 = disable shuffling. prefetch_mb = 2048, # Amount of data to prefetch (megabytes), 0 = disable prefetching. buffer_mb = 256, # Read buffer size (megabytes). batch_size = None, # Fixed batch size num_threads = 2): # Number of concurrent threads. if max_label_size is None: if 'LABEL_SIZE' not in os.environ: max_label_size = 0 else: try: max_label_size = int(os.environ['LABEL_SIZE']) except: max_label_size = os.environ['LABEL_SIZE'] assert max_label_size == 'full' or isinstance(max_label_size, int) and max_label_size >= 0 self.tfrecord_dir = tfrecord_dir self.resolution = None self.resolution_log2 = None self.shape = [] # [channels, height, width] self.dtype = 'uint8' self.dynamic_range = [0, 255] self.label_file = label_file self.label_size = None # components self.label_dtype = None self._np_labels = None self._tf_minibatch_in = None self._tf_labels_var = None self._tf_labels_dataset = None self._tf_datasets = dict() self._tf_iterator = None self._tf_init_ops = dict() self._tf_minibatch_np = None self._cur_minibatch = -1 self._cur_lod = -1 # List tfrecords files and inspect their shapes. assert gfile.IsDirectory(self.tfrecord_dir) tfr_files = sorted(tf.io.gfile.glob(os.path.join(self.tfrecord_dir, '*.tfrecords'))) assert len(tfr_files) >= 1 # To avoid parsing the entire dataset looking for the max # resolution, just assume that we can extract the LOD level # from the tfrecords file name. tfr_shapes = [] lod = -1 for tfr_file in tfr_files: match = re.match('.*?([0-9]+).tfrecords', tfr_file) if match: level = int(match.group(1)) res = 2**level tfr_shapes.append((3, res, res)) # Autodetect label filename. if self.label_file is None: guess = sorted(tf.io.gfile.glob(os.path.join(self.tfrecord_dir, '*.labels'))) if len(guess): self.label_file = guess[0] elif not tf.io.gfile.exists(self.label_file): guess = os.path.join(self.tfrecord_dir, self.label_file) if tf.io.gfile.exists(guess): self.label_file = guess # Determine shape and resolution. max_shape = max(tfr_shapes, key=np.prod) self.resolution = resolution if resolution is not None else max_shape[1] self.resolution_log2 = int(np.log2(self.resolution)) self.shape = [max_shape[0], self.resolution, self.resolution] tfr_lods = [self.resolution_log2 - int(np.log2(shape[1])) for shape in tfr_shapes] assert all(shape[0] == max_shape[0] for shape in tfr_shapes) assert all(shape[1] == shape[2] for shape in tfr_shapes) assert all(shape[1] == self.resolution // (2**lod) for shape, lod in zip(tfr_shapes, tfr_lods)) assert all(lod in tfr_lods for lod in range(self.resolution_log2 - 1)) # Load labels. assert max_label_size == 'full' or max_label_size >= 0 self._np_labels = np.zeros([1<<16, 0], dtype=np.float32) if self.label_file is not None and max_label_size != 0: with gfile.GFile(self.label_file, 'rb') as f: self._np_labels = np.load(f) assert self._np_labels.ndim == 2 if max_label_size != 'full' and self._np_labels.shape[1] > max_label_size: self._np_labels = self._np_labels[:, :max_label_size] if max_images is not None and self._np_labels.shape[0] > max_images: self._np_labels = self._np_labels[:max_images] self.label_size = self._np_labels.shape[1] self.label_dtype = self._np_labels.dtype.name self.tfr = list(zip(tfr_files, tfr_shapes, tfr_lods)) def finalize(): # Build TF expressions. with tf.name_scope('Dataset'), tflex.device('/cpu:0'): self._tf_minibatch_in = batch_size if batch_size is not None or batch_size <= 0 else tf.placeholder(tf.int64, name='minibatch_in', shape=[]) self._tf_labels_var, self._tf_labels_init = tflib.create_var_with_large_initial_value2(self._np_labels, name='labels_var') with tf.control_dependencies([self._tf_labels_init]): self._tf_labels_dataset = tf.data.Dataset.from_tensor_slices(self._tf_labels_var) for tfr_file, tfr_shape, tfr_lod in self.tfr: if tfr_lod < 0: continue dset = tf.data.TFRecordDataset(tfr_file, compression_type='', buffer_size=buffer_mb<<20) if max_images is not None: dset = dset.take(max_images) dset = dset.map(self.parse_tfrecord_tf, num_parallel_calls=num_threads) dset = tf.data.Dataset.zip((dset, self._tf_labels_dataset)) bytes_per_item = np.prod(tfr_shape) * np.dtype(self.dtype).itemsize if shuffle_mb > 0: dset = dset.shuffle(((shuffle_mb << 20) - 1) // bytes_per_item + 1) if repeat: dset = dset.repeat() if prefetch_mb > 0: dset = dset.prefetch(((prefetch_mb << 20) - 1) // bytes_per_item + 1) if batch_size is None or batch_size > 0: dset = dset.batch(self._tf_minibatch_in) self._tf_datasets[tfr_lod] = dset self._tf_iterator = tf.data.Iterator.from_structure(self._tf_datasets[0].output_types, self._tf_datasets[0].output_shapes) self._tf_init_ops = {lod: self._tf_iterator.make_initializer(dset) if batch_size is None else tf.no_op() for lod, dset in self._tf_datasets.items()} self.finalize = finalize def close(self): pass # Use the given minibatch size and level-of-detail for the data returned by get_minibatch_tf(). def configure(self, minibatch_size, lod=0): lod = int(np.floor(lod)) assert minibatch_size >= 1 and lod in self._tf_datasets if self._cur_minibatch != minibatch_size or self._cur_lod != lod: #self._tf_init_ops[lod].run(*[{self._tf_minibatch_in: minibatch_size}] if not isinstance(self._tf_minibatch_in, int) and self._tf_minibatch_in is not None else []) self._tf_init_ops[lod].run({self._tf_minibatch_in: minibatch_size}) self._cur_minibatch = minibatch_size self._cur_lod = lod # Get next minibatch as TensorFlow expressions. def get_minibatch_tf(self): # => images, labels return self._tf_iterator.get_next() # Get next minibatch as NumPy arrays. def get_minibatch_np(self, minibatch_size, lod=0): # => images, labels while True: self.configure(minibatch_size, lod) with tf.name_scope('Dataset'): if self._tf_minibatch_np is None: self._tf_minibatch_np = self.get_minibatch_tf() try: return tflib.run(self._tf_minibatch_np) except errors_impl.AbortedError: import traceback traceback.print_exc() # Get random labels as TensorFlow expression. def get_random_labels_tf(self, minibatch_size): # => labels with tf.name_scope('Dataset'): if self.label_size > 0: with tflex.device('/cpu:0'): return tf.gather(self._tf_labels_var, tf.random_uniform([minibatch_size], 0, self._np_labels.shape[0], dtype=tf.int32)) return tf.zeros([minibatch_size, 0], self.label_dtype) # Get random labels as NumPy array. def get_random_labels_np(self, minibatch_size): # => labels if self.label_size > 0: return self._np_labels[np.random.randint(self._np_labels.shape[0], size=[minibatch_size])] return np.zeros([minibatch_size, 0], self.label_dtype) # Parse individual image from a tfrecords file into TensorFlow expression. @staticmethod def parse_tfrecord_tf(record): features = tf.parse_single_example(record, features={ 'shape': tf.FixedLenFeature([3], tf.int64), 'data': tf.FixedLenFeature([], tf.string)}) data = tf.decode_raw(features['data'], tf.uint8) return tf.reshape(data, features['shape']) # Parse individual image from a tfrecords file into TensorFlow expression. @staticmethod def parse_tfrecord_tf_float(record): img = TFRecordDataset.parse_tfrecord_tf(record) return tf.cast(img, dtype=tf.float32) # Parse individual image from a tfrecords file into NumPy array. @staticmethod def parse_tfrecord_np(record): ex = tf.train.Example() ex.ParseFromString(record) shape = ex.features.feature['shape'].int64_list.value # pylint: disable=no-member data = ex.features.feature['data'].bytes_list.value[0] # pylint: disable=no-member return np.fromstring(data, np.uint8).reshape(shape) #---------------------------------------------------------------------------- # Helper func for constructing a dataset object using the given options. def load_dataset(class_name=None, data_dir=None, verbose=False, **kwargs): kwargs = dict(kwargs) if 'tfrecord_dir' in kwargs: if class_name is None: class_name = __name__ + '.TFRecordDataset' if data_dir is not None: kwargs['tfrecord_dir'] = os.path.join(data_dir, kwargs['tfrecord_dir']) assert class_name is not None if verbose: print('Streaming data using %s...' % class_name) dataset = dnnlib.util.get_obj_by_name(class_name)(**kwargs) if verbose: print('Dataset shape =', np.int32(dataset.shape).tolist()) print('Dynamic range =', dataset.dynamic_range) print('Label size =', dataset.label_size) return dataset #---------------------------------------------------------------------------- ================================================ FILE: stylegan2-tpu/training/imagenet_input.py ================================================ # Copyright 2018 The TensorFlow Authors. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== """ImageNet preprocessing for ResNet.""" from absl import flags import tensorflow as tf #FLAGS = flags.FLAGS class Namespace: pass FLAGS = Namespace() FLAGS.cache_decoded_image = False def distorted_bounding_box_crop(image_bytes, bbox, min_object_covered=0.1, aspect_ratio_range=(0.75, 1.33), area_range=(0.05, 1.0), max_attempts=100, scope=None): """Generates cropped_image using one of the bboxes randomly distorted. See `tf.image.sample_distorted_bounding_box` for more documentation. Args: image_bytes: `Tensor` of binary image data. bbox: `Tensor` of bounding boxes arranged `[1, num_boxes, coords]` where each coordinate is [0, 1) and the coordinates are arranged as `[ymin, xmin, ymax, xmax]`. If num_boxes is 0 then use the whole image. min_object_covered: An optional `float`. Defaults to `0.1`. The cropped area of the image must contain at least this fraction of any bounding box supplied. aspect_ratio_range: An optional list of `float`s. The cropped area of the image must have an aspect ratio = width / height within this range. area_range: An optional list of `float`s. The cropped area of the image must contain a fraction of the supplied image within in this range. max_attempts: An optional `int`. Number of attempts at generating a cropped region of the image of the specified constraints. After `max_attempts` failures, return the entire image. scope: Optional `str` for name scope. Returns: cropped image `Tensor` """ with tf.name_scope(scope, 'distorted_bounding_box_crop', [image_bytes, bbox]): if FLAGS.cache_decoded_image: shape = tf.shape(image_bytes) else: shape = tf.image.extract_jpeg_shape(image_bytes) sample_distorted_bounding_box = tf.image.sample_distorted_bounding_box( shape, bounding_boxes=bbox, min_object_covered=min_object_covered, aspect_ratio_range=aspect_ratio_range, area_range=area_range, max_attempts=max_attempts, use_image_if_no_bounding_boxes=True) bbox_begin, bbox_size, _ = sample_distorted_bounding_box # Crop the image to the specified bounding box. offset_y, offset_x, _ = tf.unstack(bbox_begin) target_height, target_width, _ = tf.unstack(bbox_size) crop_window = tf.stack([offset_y, offset_x, target_height, target_width]) if FLAGS.cache_decoded_image: image = tf.image.crop_to_bounding_box(image_bytes, offset_y, offset_x, target_height, target_width) else: image = tf.image.decode_and_crop_jpeg( image_bytes, crop_window, channels=3) return image def _at_least_x_are_equal(a, b, x): """At least `x` of `a` and `b` `Tensors` are equal.""" match = tf.equal(a, b) match = tf.cast(match, tf.int32) return tf.greater_equal(tf.reduce_sum(match), x) def _decode_and_random_crop(image_bytes, image_size): """Make a random crop of image_size.""" bbox = tf.constant([0.0, 0.0, 1.0, 1.0], dtype=tf.float32, shape=[1, 1, 4]) image = distorted_bounding_box_crop( image_bytes, bbox, min_object_covered=0.1, aspect_ratio_range=(3. / 4, 4. / 3.), area_range=(0.08, 1.0), max_attempts=10, scope=None) return tf.image.resize_area([image], [image_size, image_size])[0] def _decode_and_center_crop_image(image_bytes, image_size, crop_padding=32): """Crops to center of image with padding then scales image_size.""" image = tf.io.decode_image(image_bytes, channels=3) shape = tf.shape(image) #shape = tf.image.extract_jpeg_shape(image_bytes) image_height = shape[0] image_width = shape[1] channels = shape[2] padded_center_crop_size = tf.cast( ((image_size / (image_size + crop_padding)) * tf.cast(tf.minimum(image_height, image_width), tf.float32)), tf.int32) offset_height = ((image_height - padded_center_crop_size) + 1) // 2 offset_width = ((image_width - padded_center_crop_size) + 1) // 2 if 'RANDOM_CROP' in os.environ: image = tf.image.random_crop(image, [padded_center_crop_size, padded_center_crop_size, channels]) else: image = tf.image.crop_to_bounding_box(image, offset_height, offset_width, padded_center_crop_size, padded_center_crop_size) image = tf.image.resize_area([image], [image_size, image_size])[0] return image def _decode_and_center_crop(image_bytes, image_size, crop_padding=None): if 'NO_CENTER_CROP' in os.environ: image = tf.io.decode_image(image_bytes, channels=3) image = tf.image.resize_area([image], [image_size, image_size])[0] return image else: if crop_padding is None and 'CROP_PADDING' in os.environ: crop_padding = int(os.environ['CROP_PADDING']) if crop_padding is None: crop_padding = 32 return _decode_and_center_crop_image(image_bytes, image_size, crop_padding=crop_padding) def _flip(image): """Random horizontal image flip.""" image = tf.image.random_flip_left_right(image) return image def preprocess_for_train(image_bytes, use_bfloat16, image_size): """Preprocesses the given image for evaluation. Args: image_bytes: `Tensor` representing an image binary of arbitrary size. use_bfloat16: `bool` for whether to use bfloat16. image_size: image size. Returns: A preprocessed image `Tensor`. """ image = _decode_and_random_crop(image_bytes, image_size) image = _flip(image) image = tf.reshape(image, [image_size, image_size, 3]) image = tf.image.convert_image_dtype( image, dtype=tf.bfloat16 if use_bfloat16 else tf.float32) return image def preprocess_for_eval(image_bytes, use_bfloat16, image_size): """Preprocesses the given image for evaluation. Args: image_bytes: `Tensor` representing an image binary of arbitrary size. use_bfloat16: `bool` for whether to use bfloat16. image_size: image size. Returns: A preprocessed image `Tensor`. """ image = _decode_and_center_crop(image_bytes, image_size) image = tf.reshape(image, [image_size, image_size, 3]) image = tf.image.convert_image_dtype( image, dtype=tf.bfloat16 if use_bfloat16 else tf.float32) return image def preprocess_image(image_bytes, image_size, is_training=False, use_bfloat16=False): """Preprocesses the given image. Args: image_bytes: `Tensor` representing an image binary of arbitrary size. is_training: `bool` for whether the preprocessing is for training. use_bfloat16: `bool` for whether to use bfloat16. image_size: image size. Returns: A preprocessed image `Tensor` with value range of [0, 255]. """ if is_training and False: # a bit of a weird hack; we override the training pipeline in the eval functions. img = preprocess_for_train(image_bytes, use_bfloat16, image_size) else: img = preprocess_for_eval(image_bytes, use_bfloat16, image_size) #img = tf.transpose(img, [2, 0, 1]) return img # Copyright 2018 The TensorFlow Authors. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== """Efficient ImageNet input pipeline using tf.data.Dataset.""" import abc from collections import namedtuple import functools import math import os from absl import flags import tensorflow as tf #FLAGS = flags.FLAGS def image_serving_input_fn(): """Serving input fn for raw images.""" def _preprocess_image(image_bytes): """Preprocess a single raw image.""" image = preprocess_image( image_bytes=image_bytes, is_training=False) return image image_bytes_list = tf.placeholder( shape=[None], dtype=tf.string, ) images = tf.map_fn( _preprocess_image, image_bytes_list, back_prop=False, dtype=tf.float32) return tf.estimator.export.ServingInputReceiver( images, {'image_bytes': image_bytes_list}) def _int64_feature(value): """Wrapper for inserting int64 features into Example proto.""" if not isinstance(value, list): value = [value] return tf.train.Feature(int64_list=tf.train.Int64List(value=value)) def _bytes_feature(value): """Wrapper for inserting bytes features into Example proto.""" return tf.train.Feature(bytes_list=tf.train.BytesList(value=[value])) def _convert_to_example(image_buffer, label): """Build an Example proto for an example. Args: image_buffer: string, JPEG encoding of RGB image label: integer, identifier for the ground truth for the network Returns: Example proto """ example = tf.train.Example( features=tf.train.Features( feature={ 'image/class/label': _int64_feature(label), 'image/encoded': _bytes_feature(image_buffer) })) return example class ImageNetTFExampleInput(object): """Base class for ImageNet input_fn generator. Args: is_training: `bool` for whether the input is for training use_bfloat16: If True, use bfloat16 precision; else use float32. transpose_input: 'bool' for whether to use the double transpose trick num_cores: `int` for the number of TPU cores """ __metaclass__ = abc.ABCMeta def __init__(self, is_training, use_bfloat16, num_cores=8, image_size=224, prefetch_depth_auto_tune=False, transpose_input=False): self.image_preprocessing_fn = preprocess_image self.is_training = is_training self.use_bfloat16 = use_bfloat16 self.num_cores = num_cores self.transpose_input = transpose_input self.image_size = image_size self.prefetch_depth_auto_tune = prefetch_depth_auto_tune def set_shapes(self, batch_size, images, labels): """Statically set the batch_size dimension.""" if self.transpose_input: if FLAGS.train_batch_size // FLAGS.num_cores > 8: shape = [None, None, None, batch_size] else: shape = [None, None, batch_size, None] images.set_shape(images.get_shape().merge_with(tf.TensorShape(shape))) images = tf.reshape(images, [-1]) labels.set_shape(labels.get_shape().merge_with( tf.TensorShape([batch_size]))) else: images.set_shape(images.get_shape().merge_with( tf.TensorShape([batch_size, None, None, None]))) labels.set_shape(labels.get_shape().merge_with( tf.TensorShape([batch_size]))) return images, labels def dataset_parser(self, value): """Parses an image and its label from a serialized ResNet-50 TFExample. Args: value: serialized string containing an ImageNet TFExample. Returns: Returns a tuple of (image, label) from the TFExample. """ keys_to_features = { 'image/encoded': tf.FixedLenFeature((), tf.string, ''), 'image/format': tf.FixedLenFeature((), tf.string, 'jpeg'), 'image/class/label': tf.FixedLenFeature([], tf.int64, -1), 'image/class/text': tf.FixedLenFeature([], tf.string, ''), 'image/object/bbox/xmin': tf.VarLenFeature(dtype=tf.float32), 'image/object/bbox/ymin': tf.VarLenFeature(dtype=tf.float32), 'image/object/bbox/xmax': tf.VarLenFeature(dtype=tf.float32), 'image/object/bbox/ymax': tf.VarLenFeature(dtype=tf.float32), 'image/object/class/label': tf.VarLenFeature(dtype=tf.int64), } parsed = tf.parse_single_example(value, keys_to_features) image_bytes = tf.reshape(parsed['image/encoded'], shape=[]) # Subtract one so that labels are in [0, 1000). bias = int(os.environ['LABEL_BIAS']) if 'LABEL_BIAS' in os.environ else 0 label = tf.cast( tf.reshape(parsed['image/class/label'], shape=[]), dtype=tf.int32) + bias # Return all black images for padded data. image = tf.cond( label < 0, lambda: self._get_null_input(None), lambda: self. # pylint: disable=g-long-lambda image_preprocessing_fn( image_bytes=image_bytes, is_training=self.is_training, image_size=self.image_size, use_bfloat16=self.use_bfloat16)) return image, label def dataset_parser_static(self, value): """Parses an image and its label from a serialized ResNet-50 TFExample. This only decodes the image, which is prepared for caching. Args: value: serialized string containing an ImageNet TFExample. Returns: Returns a tuple of (image, label) from the TFExample. """ keys_to_features = { 'image/encoded': tf.FixedLenFeature((), tf.string, ''), 'image/format': tf.FixedLenFeature((), tf.string, 'jpeg'), 'image/class/label': tf.FixedLenFeature([], tf.int64, -1), 'image/class/text': tf.FixedLenFeature([], tf.string, ''), 'image/object/bbox/xmin': tf.VarLenFeature(dtype=tf.float32), 'image/object/bbox/ymin': tf.VarLenFeature(dtype=tf.float32), 'image/object/bbox/xmax': tf.VarLenFeature(dtype=tf.float32), 'image/object/bbox/ymax': tf.VarLenFeature(dtype=tf.float32), 'image/object/class/label': tf.VarLenFeature(dtype=tf.int64), } parsed = tf.parse_single_example(value, keys_to_features) image_bytes = tf.reshape(parsed['image/encoded'], shape=[]) image_bytes = tf.io.decode_image(image_bytes, channels=3) # Subtract one so that labels are in [0, 1000). bias = int(os.environ['LABEL_BIAS']) if 'LABEL_BIAS' in os.environ else 0 label = tf.cast( tf.reshape(parsed['image/class/label'], shape=[]), dtype=tf.int32) + bias return image_bytes, label def dataset_parser_dynamic(self, image_bytes, label): return self.image_preprocessing_fn( image_bytes=image_bytes, is_training=self.is_training, image_size=self.image_size, use_bfloat16=self.use_bfloat16), label def pad_dataset(self, dataset, num_hosts): """Pad the eval dataset so that eval can have the same batch size as training.""" num_dataset_per_shard = int( math.ceil(FLAGS.num_eval_images / FLAGS.eval_batch_size) * FLAGS.eval_batch_size / num_hosts) example_string = 'dummy_string' padded_example = _convert_to_example( str.encode(example_string), -1).SerializeToString() padded_dataset = tf.data.Dataset.from_tensors( tf.constant(padded_example, dtype=tf.string)) padded_dataset = padded_dataset.repeat(num_dataset_per_shard) dataset = dataset.concatenate(padded_dataset).take(num_dataset_per_shard) return dataset @abc.abstractmethod def make_source_dataset(self, index, num_hosts): """Makes dataset of serialized TFExamples. The returned dataset will contain `tf.string` tensors, but these strings are serialized `TFExample` records that will be parsed by `dataset_parser`. If self.is_training, the dataset should be infinite. Args: index: current host index. num_hosts: total number of hosts. Returns: A `tf.data.Dataset` object. """ return def input_fn(self, params): """Input function which provides a single batch for train or eval. Args: params: `dict` of parameters passed from the `TPUEstimator`. `params['batch_size']` is always provided and should be used as the effective batch size. Returns: A `tf.data.Dataset` object. """ # Retrieves the batch size for the current shard. The # of shards is # computed according to the input pipeline deployment. See # tf.contrib.tpu.RunConfig for details. batch_size = params['batch_size'] # TODO(dehao): Replace the following with params['context'].current_host if 'context' in params: current_host = params['context'].current_input_fn_deployment()[1] num_hosts = params['context'].num_hosts else: if 'dataset_index' in params: current_host = params['dataset_index'] num_hosts = params['dataset_num_shards'] else: current_host = 0 num_hosts = 1 dataset = self.make_source_dataset(current_host, num_hosts) if not self.is_training and False: # Padding for eval. dataset = self.pad_dataset(dataset, num_hosts) # Use the fused map-and-batch operation. # # For XLA, we must used fixed shapes. Because we repeat the source training # dataset indefinitely, we can use `drop_remainder=True` to get fixed-size # batches without dropping any training examples. # # When evaluating, `drop_remainder=True` prevents accidentally evaluating # the same image twice by dropping the final batch if it is less than a full # batch size. As long as this validation is done with consistent batch size, # exactly the same images will be used. if self.is_training and FLAGS.cache_decoded_image: dataset = dataset.apply( tf.contrib.data.map_and_batch( self.dataset_parser_dynamic, batch_size=batch_size, num_parallel_batches=self.num_cores, drop_remainder=True)) else: dataset = dataset.apply( tf.contrib.data.map_and_batch( self.dataset_parser, batch_size=batch_size, num_parallel_batches=self.num_cores, drop_remainder=True)) # Transpose for performance on TPU if self.transpose_input: if FLAGS.train_batch_size // FLAGS.num_cores > 8: transpose_array = [1, 2, 3, 0] else: transpose_array = [1, 2, 0, 3] dataset = dataset.map( lambda images, labels: (tf.transpose(images, transpose_array), labels ), num_parallel_calls=self.num_cores) # Assign static batch size dimension dataset = dataset.map(functools.partial(self.set_shapes, batch_size)) # Prefetch overlaps in-feed with training if self.prefetch_depth_auto_tune: dataset = dataset.prefetch(tf.contrib.data.AUTOTUNE) else: dataset = dataset.prefetch(4) options = tf.data.Options() options.experimental_threading.max_intra_op_parallelism = 1 options.experimental_threading.private_threadpool_size = 48 dataset = dataset.with_options(options) return dataset class ImageNetInput(ImageNetTFExampleInput): """Generates ImageNet input_fn from a series of TFRecord files. The training data is assumed to be in TFRecord format with keys as specified in the dataset_parser below, sharded across 1024 files, named sequentially: train-00000-of-01024 train-00001-of-01024 ... train-01023-of-01024 The validation data is in the same format but sharded in 128 files. The format of the data required is created by the script at: https://github.com/tensorflow/tpu/blob/master/tools/datasets/imagenet_to_gcs.py """ def __init__(self, data_dir, is_training=True, use_bfloat16=False, transpose_input=False, image_size=224, num_parallel_calls=64, num_cores=8, prefetch_depth_auto_tune=False, cache=False): """Create an input from TFRecord files. Args: is_training: `bool` for whether the input is for training use_bfloat16: If True, use bfloat16 precision; else use float32. transpose_input: 'bool' for whether to use the double transpose trick data_dir: `str` for the directory of the training and validation data; if 'null' (the literal string 'null') or implicitly False then construct a null pipeline, consisting of empty images and blank labels. image_size: size of input images num_parallel_calls: concurrency level to use when reading data from disk. num_cores: Number of prefetch threads prefetch_depth_auto_tune: Auto-tuning prefetch depths in input pipeline cache: if true, fill the dataset by repeating from its cache """ super(ImageNetInput, self).__init__( is_training=is_training, image_size=image_size, use_bfloat16=use_bfloat16, num_cores=num_cores, prefetch_depth_auto_tune=prefetch_depth_auto_tune, transpose_input=transpose_input) self.data_dir = data_dir if self.data_dir == 'null' or not self.data_dir: self.data_dir = None self.num_parallel_calls = num_parallel_calls self.cache = cache def _get_null_input(self, data): """Returns a null image (all black pixels). Args: data: element of a dataset, ignored in this method, since it produces the same null image regardless of the element. Returns: a tensor representing a null image. """ del data # Unused since output is constant regardless of input return tf.zeros([self.image_size, self.image_size, 3], tf.bfloat16 if self.use_bfloat16 else tf.float32) def dataset_parser(self, value): """See base class.""" if not self.data_dir: return value, tf.constant(0, tf.int32) return super(ImageNetInput, self).dataset_parser(value) def make_source_dataset(self, index, num_hosts): """See base class.""" if not self.data_dir: tf.logging.info('Undefined data_dir implies null input') return tf.data.Dataset.range(1).repeat().map(self._get_null_input) # Shuffle the filenames to ensure better randomization. file_patterns = [x.strip() for x in self.data_dir.split(',') if len(x.strip()) > 0] # For multi-host training, we want each hosts to always process the same # subset of files. Each host only sees a subset of the entire dataset, # allowing us to cache larger datasets in memory. dataset = None for pattern in file_patterns: x = tf.data.Dataset.list_files(pattern, shuffle=False) if dataset is None: dataset = x else: dataset = dataset.concatenate(x) dataset = dataset.shard(num_hosts, index) if self.is_training and not self.cache: # We shuffle only during training, and during training, we must produce an # infinite dataset, so apply the fused shuffle_and_repeat optimized # dataset transformation. dataset = dataset.apply( tf.contrib.data.shuffle_and_repeat(1024 * 16)) #dataset = dataset.repeat() def fetch_dataset(filename): buffer_size = 8 * 1024 * 1024 # 8 MiB per file dataset = tf.data.TFRecordDataset(filename, buffer_size=buffer_size) return dataset # Read the data from disk in parallel dataset = dataset.apply( tf.contrib.data.parallel_interleave( fetch_dataset, cycle_length=self.num_parallel_calls, sloppy=True)) if self.is_training and FLAGS.cache_decoded_image: dataset = dataset.map( self.dataset_parser_static, num_parallel_calls=self.num_parallel_calls) if self.cache: dataset = dataset.cache() if self.is_training: # We shuffle only during training, and during training, we must produce an # infinite dataset, so apply the fused shuffle_and_repeat optimized # dataset transformation. dataset = dataset.apply( tf.contrib.data.shuffle_and_repeat(1024 * 16)) return dataset # Defines a selection of data from a Cloud Bigtable. BigtableSelection = namedtuple('BigtableSelection', ['project', 'instance', 'table', 'prefix', 'column_family', 'column_qualifier']) class ImageNetBigtableInput(ImageNetTFExampleInput): """Generates ImageNet input_fn from a Bigtable for training or evaluation. """ def __init__(self, is_training, use_bfloat16, transpose_input, selection): """Constructs an ImageNet input from a BigtableSelection. Args: is_training: `bool` for whether the input is for training use_bfloat16: If True, use bfloat16 precision; else use float32. transpose_input: 'bool' for whether to use the double transpose trick selection: a BigtableSelection specifying a part of a Bigtable. """ super(ImageNetBigtableInput, self).__init__( is_training=is_training, use_bfloat16=use_bfloat16, transpose_input=transpose_input) self.selection = selection def make_source_dataset(self, index, num_hosts): """See base class.""" data = self.selection client = tf.contrib.cloud.BigtableClient(data.project, data.instance) table = client.table(data.table) ds = table.parallel_scan_prefix(data.prefix, columns=[(data.column_family, data.column_qualifier)]) # The Bigtable datasets will have the shape (row_key, data) ds_data = ds.map(lambda index, data: data) if self.is_training: ds_data = ds_data.repeat() return ds_data ================================================ FILE: stylegan2-tpu/training/loss.py ================================================ # Copyright (c) 2019, NVIDIA Corporation. All rights reserved. # # This work is made available under the Nvidia Source Code License-NC. # To view a copy of this license, visit # https://nvlabs.github.io/stylegan2/license.html """Loss functions.""" import numpy as np import tensorflow as tf import dnnlib.tflib as tflib from dnnlib.tflib.autosummary import autosummary, autoimages #---------------------------------------------------------------------------- # Logistic loss from the paper # "Generative Adversarial Nets", Goodfellow et al. 2014 def G_logistic(G, D, opt, training_set, minibatch_size): _ = opt latents = tf.random_normal([minibatch_size] + G.input_shapes[0][1:]) labels = training_set.get_random_labels_tf(minibatch_size) fake_images_out = G.get_output_for(latents, labels, is_training=True) fake_scores_out = D.get_output_for(fake_images_out, labels, is_training=True) loss = -tf.nn.softplus(fake_scores_out) # log(1-sigmoid(fake_scores_out)) # pylint: disable=invalid-unary-operand-type autosummary('G_logistic_00/total_loss', loss) return loss, None def G_logistic_ns(G, D, opt, training_set, minibatch_size): _ = opt latents = tf.random_normal([minibatch_size] + G.input_shapes[0][1:]) labels = training_set.get_random_labels_tf(minibatch_size) fake_images_out = G.get_output_for(latents, labels, is_training=True) fake_scores_out = D.get_output_for(fake_images_out, labels, is_training=True) loss = tf.nn.softplus(-fake_scores_out) # -log(sigmoid(fake_scores_out)) autosummary('G_logistic_ns_00/total_loss', loss) return loss, None def D_logistic(G, D, opt, training_set, minibatch_size, reals, labels): _ = opt, training_set latents = tf.random_normal([minibatch_size] + G.input_shapes[0][1:]) fake_images_out = G.get_output_for(latents, labels, is_training=True) real_scores_out = D.get_output_for(reals, labels, is_training=True) fake_scores_out = D.get_output_for(fake_images_out, labels, is_training=True) real_scores_out = autosummary('D_logistic_00/real_scores', real_scores_out) fake_scores_out = autosummary('D_logistic_01/fake_scores', fake_scores_out) loss = autosummary('D_logistic_00/fake_loss', tf.nn.softplus(fake_scores_out)) # -log(1-sigmoid(fake_scores_out)) loss += autosummary('D_logistic_01/real_loss', tf.nn.softplus(-real_scores_out)) # -log(sigmoid(real_scores_out)) # pylint: disable=invalid-unary-operand-type autosummary('D_logistic_02/total_loss', loss) autoimages('D_logistic/images/real', reals) autoimages('D_logistic/images/fake', fake_images_out) return loss, None #---------------------------------------------------------------------------- # R1 and R2 regularizers from the paper # "Which Training Methods for GANs do actually Converge?", Mescheder et al. 2018 def D_logistic_r1(G, D, opt, training_set, minibatch_size, reals, labels, gamma=10.0): _ = opt, training_set latents = tf.random_normal([minibatch_size] + G.input_shapes[0][1:]) fake_images_out = G.get_output_for(latents, labels, is_training=True) real_scores_out = D.get_output_for(reals, labels, is_training=True) fake_scores_out = D.get_output_for(fake_images_out, labels, is_training=True) fake_scores_out = autosummary('D_logistic_r1_00/fake_scores', fake_scores_out) real_scores_out = autosummary('D_logistic_r1_01/real_scores', real_scores_out) loss = autosummary('D_logistic_r1_00/fake_loss', tf.nn.softplus(fake_scores_out)) # -log(1-sigmoid(fake_scores_out)) loss += autosummary('D_logistic_r1_01/real_loss', tf.nn.softplus(-real_scores_out)) # -log(sigmoid(real_scores_out)) # pylint: disable=invalid-unary-operand-type with tf.name_scope('GradientPenalty'): real_grads = tf.gradients(tf.reduce_sum(real_scores_out), [reals])[0] gradient_penalty = tf.reduce_sum(tf.square(real_grads), axis=[1,2,3]) gradient_penalty = autosummary('D_logistic_r1_02/gradient_penalty', gradient_penalty) reg = gradient_penalty * (gamma * 0.5) autosummary('D_logistic_r1_02/reg_loss', reg) autosummary('D_logistic_r1_03/total_loss', loss + reg) autoimages('D_logistic_r1/images/real', reals) autoimages('D_logistic_r1/images/fake', fake_images_out) return loss, reg def D_logistic_r2(G, D, opt, training_set, minibatch_size, reals, labels, gamma=10.0): _ = opt, training_set latents = tf.random_normal([minibatch_size] + G.input_shapes[0][1:]) fake_images_out = G.get_output_for(latents, labels, is_training=True) real_scores_out = D.get_output_for(reals, labels, is_training=True) fake_scores_out = D.get_output_for(fake_images_out, labels, is_training=True) fake_scores_out = autosummary('D_logistic_r2_00/fake_scores', fake_scores_out) real_scores_out = autosummary('D_logistic_r2_01/real_scores', real_scores_out) loss = autosummary('D_logistic_r2_00/fake_loss', tf.nn.softplus(fake_scores_out)) # -log(1-sigmoid(fake_scores_out)) loss += autosummary('D_logistic_r2_01/real_loss', tf.nn.softplus(-real_scores_out)) # -log(sigmoid(real_scores_out)) # pylint: disable=invalid-unary-operand-type with tf.name_scope('GradientPenalty'): fake_grads = tf.gradients(tf.reduce_sum(fake_scores_out), [fake_images_out])[0] gradient_penalty = tf.reduce_sum(tf.square(fake_grads), axis=[1,2,3]) gradient_penalty = autosummary('D_logistic_r2_02/gradient_penalty', gradient_penalty) reg = gradient_penalty * (gamma * 0.5) autosummary('D_logistic_r2_02/reg_loss', reg) autosummary('D_logistic_r2_03/total_loss', loss + reg) autoimages('D_logistic_r2/images/real', reals) autoimages('D_logistic_r2/images/fake', fake_images_out) return loss, reg #---------------------------------------------------------------------------- # WGAN loss from the paper # "Wasserstein Generative Adversarial Networks", Arjovsky et al. 2017 def G_wgan(G, D, opt, training_set, minibatch_size): _ = opt latents = tf.random_normal([minibatch_size] + G.input_shapes[0][1:]) labels = training_set.get_random_labels_tf(minibatch_size) fake_images_out = G.get_output_for(latents, labels, is_training=True) fake_scores_out = D.get_output_for(fake_images_out, labels, is_training=True) loss = -fake_scores_out autosummary('G_wgan_00/total_loss', loss) return loss, None def D_wgan(G, D, opt, training_set, minibatch_size, reals, labels, wgan_epsilon=0.001): _ = opt, training_set latents = tf.random_normal([minibatch_size] + G.input_shapes[0][1:]) fake_images_out = G.get_output_for(latents, labels, is_training=True) real_scores_out = D.get_output_for(reals, labels, is_training=True) fake_scores_out = D.get_output_for(fake_images_out, labels, is_training=True) fake_scores_out = autosummary('D_wgan_00/fake_score', fake_scores_out) real_scores_out = autosummary('D_wgan_01/real_score', real_scores_out) loss = autosummary('D_wgan_00/fake_loss', fake_scores_out) loss += autosummary('D_wgan_01/real_loss', -real_scores_out) with tf.name_scope('EpsilonPenalty'): epsilon_penalty = autosummary('D_wgan_02/epsilon_penalty', tf.square(real_scores_out)) loss += autosummary('D_wgan_02/penalty_loss', epsilon_penalty * wgan_epsilon) autosummary('D_wgan_03/total_loss', loss) autoimages('D_wgan/images/real', reals) autoimages('D_wgan/images/fake', fake_images_out) return loss, None #---------------------------------------------------------------------------- # WGAN-GP loss from the paper # "Improved Training of Wasserstein GANs", Gulrajani et al. 2017 def D_wgan_gp(G, D, opt, training_set, minibatch_size, reals, labels, wgan_lambda=10.0, wgan_epsilon=0.001, wgan_target=1.0): _ = opt, training_set latents = tf.random_normal([minibatch_size] + G.input_shapes[0][1:]) fake_images_out = G.get_output_for(latents, labels, is_training=True) real_scores_out = D.get_output_for(reals, labels, is_training=True) fake_scores_out = D.get_output_for(fake_images_out, labels, is_training=True) fake_scores_out = autosummary('D_wgan_gp_00/fake_scores', fake_scores_out) real_scores_out = autosummary('D_wgan_gp_01/real_scores', real_scores_out) loss = autosummary('D_wgan_gp_00/fake_loss', fake_scores_out) loss += autosummary('D_wgan_gp_01/real_loss', -real_scores_out) with tf.name_scope('EpsilonPenalty'): epsilon_penalty = autosummary('D_wgan_gp_02/epsilon_penalty', tf.square(real_scores_out)) loss += autosummary('D_wgan_gp_02/penalty_loss', epsilon_penalty * wgan_epsilon) with tf.name_scope('GradientPenalty'): mixing_factors = tf.random_uniform([minibatch_size, 1, 1, 1], 0.0, 1.0, dtype=fake_images_out.dtype) mixed_images_out = tflib.lerp(tf.cast(reals, fake_images_out.dtype), fake_images_out, mixing_factors) mixed_scores_out = D.get_output_for(mixed_images_out, labels, is_training=True) mixed_scores_out = autosummary('D_wgan_gp_03/mixed_scores', mixed_scores_out) mixed_grads = tf.gradients(tf.reduce_sum(mixed_scores_out), [mixed_images_out])[0] mixed_norms = tf.sqrt(tf.reduce_sum(tf.square(mixed_grads), axis=[1,2,3])) mixed_norms = autosummary('D_wgan_gp_03/mixed_norms', mixed_norms) gradient_penalty = tf.square(mixed_norms - wgan_target) reg = gradient_penalty * (wgan_lambda / (wgan_target**2)) autosummary('D_wgan_gp_03/gradient_penalty', gradient_penalty) autosummary('D_wgan_gp_03/reg_loss', reg) autosummary('D_wgan_gp_04/total_loss', loss + reg) autoimages('D_wgan_gp/images/real', reals) autoimages('D_wgan_gp/images/fake', fake_images_out) return loss, reg #---------------------------------------------------------------------------- # Non-saturating logistic loss with path length regularizer from the paper # "Analyzing and Improving the Image Quality of StyleGAN", Karras et al. 2019 def G_logistic_ns_pathreg(G, D, opt, training_set, minibatch_size, pl_minibatch_shrink=2, pl_decay=0.01, pl_weight=2.0): _ = opt latents = tf.random_normal([minibatch_size] + G.input_shapes[0][1:]) labels = training_set.get_random_labels_tf(minibatch_size) fake_images_out, fake_dlatents_out = G.get_output_for(latents, labels, is_training=True, return_dlatents=True) fake_scores_out = D.get_output_for(fake_images_out, labels, is_training=True) autosummary('G_logistic_ns_pathreg_00/fake_scores', fake_scores_out) loss = tf.nn.softplus(-fake_scores_out) # -log(sigmoid(fake_scores_out)) autosummary('G_logistic_ns_pathreg_00/fake_loss', loss) # Path length regularization. with tf.name_scope('PathReg'): # Evaluate the regularization term using a smaller minibatch to conserve memory. if pl_minibatch_shrink > 1: pl_minibatch = tf.maximum(1, minibatch_size // pl_minibatch_shrink) pl_latents = tf.random_normal([pl_minibatch] + G.input_shapes[0][1:]) pl_labels = training_set.get_random_labels_tf(pl_minibatch) fake_images_out, fake_dlatents_out = G.get_output_for(pl_latents, pl_labels, is_training=True, return_dlatents=True) # Compute |J*y|. pl_noise = tf.random_normal(tf.shape(fake_images_out)) / np.sqrt(np.prod(G.output_shape[2:])) pl_grads = tf.gradients(tf.reduce_sum(fake_images_out * pl_noise), [fake_dlatents_out])[0] pl_lengths = tf.sqrt(tf.reduce_mean(tf.reduce_sum(tf.square(pl_grads), axis=2), axis=1)) pl_lengths = autosummary('G_logistic_ns_pathreg_01/pl_lengths', pl_lengths) # Track exponential moving average of |J*y|. with tf.control_dependencies(None): pl_mean_var = tf.Variable(name='pl_mean', trainable=False, initial_value=0.0, dtype=tf.float32) autosummary('G_logistic_ns_pathreg_01/pl_mean', pl_mean_var) pl_mean = pl_mean_var + autosummary('G_logistic_ns_pathreg_01/pl_mean_delta', pl_decay * (tf.reduce_mean(pl_lengths) - pl_mean_var)) pl_update = tf.assign(pl_mean_var, pl_mean) # Calculate (|J*y|-a)^2. with tf.control_dependencies([pl_update]): pl_penalty = tf.square(pl_lengths - pl_mean) pl_penalty = autosummary('G_logistic_ns_pathreg_01/pl_penalty', pl_penalty) # Apply weight. # # Note: The division in pl_noise decreases the weight by num_pixels, and the reduce_mean # in pl_lengths decreases it by num_affine_layers. The effective weight then becomes: # # gamma_pl = pl_weight / num_pixels / num_affine_layers # = 2 / (r^2) / (log2(r) * 2 - 2) # = 1 / (r^2 * (log2(r) - 1)) # = ln(2) / (r^2 * (ln(r) - ln(2)) # reg = pl_penalty * pl_weight autosummary('G_logistic_ns_pathreg_01/reg_loss', reg) autosummary('G_logistic_ns_pathreg_02/total_loss', loss + reg) return loss, reg #---------------------------------------------------------------------------- ================================================ FILE: stylegan2-tpu/training/misc.py ================================================ # Copyright (c) 2019, NVIDIA Corporation. All rights reserved. # # This work is made available under the Nvidia Source Code License-NC. # To view a copy of this license, visit # https://nvlabs.github.io/stylegan2/license.html """Miscellaneous utility functions.""" import os import pickle import numpy as np import PIL.Image import PIL.ImageFont import dnnlib #---------------------------------------------------------------------------- # Convenience wrappers for pickle that are able to load data produced by # older versions of the code, and from external URLs. def open_file_or_url(file_or_url): if dnnlib.util.is_url(file_or_url): return dnnlib.util.open_url(file_or_url, cache_dir='.stylegan2-cache') return open(file_or_url, 'rb') def load_pkl(file_or_url, filename=None): infile = filename if filename is not None and os.path.isfile(filename) else file_or_url with open_file_or_url(infile) as file: return pickle.load(file, encoding='latin1') def save_pkl(obj, filename): with open(filename, 'wb') as file: pickle.dump(obj, file, protocol=pickle.HIGHEST_PROTOCOL) #---------------------------------------------------------------------------- # Image utils. def adjust_dynamic_range(data, drange_in, drange_out): if drange_in != drange_out: scale = (np.float32(drange_out[1]) - np.float32(drange_out[0])) / (np.float32(drange_in[1]) - np.float32(drange_in[0])) bias = (np.float32(drange_out[0]) - np.float32(drange_in[0]) * scale) data = data * scale + bias return data def create_image_grid(images, grid_size=None): assert images.ndim == 3 or images.ndim == 4 num, img_w, img_h = images.shape[0], images.shape[-1], images.shape[-2] if grid_size is not None: grid_w, grid_h = tuple(grid_size) else: grid_w = max(int(np.ceil(np.sqrt(num))), 1) grid_h = max((num - 1) // grid_w + 1, 1) grid = np.zeros(list(images.shape[1:-2]) + [grid_h * img_h, grid_w * img_w], dtype=images.dtype) for idx in range(num): x = (idx % grid_w) * img_w y = (idx // grid_w) * img_h grid[..., y : y + img_h, x : x + img_w] = images[idx] return grid def convert_to_pil_image(image, drange=[0,1]): assert image.ndim == 2 or image.ndim == 3 if image.ndim == 3: if image.shape[0] == 1: image = image[0] # grayscale CHW => HW else: image = image.transpose(1, 2, 0) # CHW -> HWC image = adjust_dynamic_range(image, drange, [0,255]) image = np.rint(image).clip(0, 255).astype(np.uint8) fmt = 'RGB' if image.ndim == 3 else 'L' return PIL.Image.fromarray(image, fmt) def save_image_grid(images, filename, drange=[0,1], grid_size=None): convert_to_pil_image(create_image_grid(images, grid_size), drange).save(filename) def apply_mirror_augment(minibatch): mask = np.random.rand(minibatch.shape[0]) < 0.5 minibatch = np.array(minibatch) minibatch[mask] = minibatch[mask, :, :, ::-1] return minibatch #---------------------------------------------------------------------------- # Loading data from previous training runs. def parse_config_for_previous_run(run_dir): with open(os.path.join(run_dir, 'submit_config.pkl'), 'rb') as f: data = pickle.load(f) data = data.get('run_func_kwargs', {}) return dict(train=data, dataset=data.get('dataset_args', {})) #---------------------------------------------------------------------------- # Size and contents of the image snapshot grids that are exported # periodically during training. def setup_snapshot_image_grid(training_set, size = '1080p', # '1080p' = to be viewed on 1080p display, '4k' = to be viewed on 4k display. layout = 'random'): # 'random' = grid contents are selected randomly, 'row_per_class' = each row corresponds to one class label. # Select size. gw = 1; gh = 1 if size == '1080p': gw = np.clip(1920 // training_set.shape[2], 3, 32) gh = np.clip(1080 // training_set.shape[1], 2, 32) if size == '4k': gw = np.clip(3840 // training_set.shape[2], 7, 32) gh = np.clip(2160 // training_set.shape[1], 4, 32) if size == '8k': gw = np.clip(7680 // training_set.shape[2], 7, 32) gh = np.clip(4320 // training_set.shape[1], 4, 32) # Initialize data arrays. reals = np.zeros([gw * gh] + training_set.shape, dtype=training_set.dtype) labels = np.zeros([gw * gh, training_set.label_size], dtype=training_set.label_dtype) # Random layout. if layout == 'random': reals[:], labels[:] = training_set.get_minibatch_np(gw * gh) # Class-conditional layouts. class_layouts = dict(row_per_class=[gw,1], col_per_class=[1,gh], class4x4=[4,4]) if layout in class_layouts: bw, bh = class_layouts[layout] nw = (gw - 1) // bw + 1 nh = (gh - 1) // bh + 1 blocks = [[] for _i in range(nw * nh)] for _iter in range(1000000): real, label = training_set.get_minibatch_np(1) idx = np.argmax(label[0]) while idx < len(blocks) and len(blocks[idx]) >= bw * bh: idx += training_set.label_size if idx < len(blocks): blocks[idx].append((real, label)) if all(len(block) >= bw * bh for block in blocks): break for i, block in enumerate(blocks): for j, (real, label) in enumerate(block): x = (i % nw) * bw + j % bw y = (i // nw) * bh + j // bw if x < gw and y < gh: reals[x + y * gw] = real[0] labels[x + y * gw] = label[0] return (gw, gh), reals, labels #---------------------------------------------------------------------------- ================================================ FILE: stylegan2-tpu/training/networks_stylegan.py ================================================ # Copyright (c) 2019, NVIDIA Corporation. All rights reserved. # # This work is made available under the Nvidia Source Code License-NC. # To view a copy of this license, visit # https://nvlabs.github.io/stylegan2/license.html """Network architectures used in the StyleGAN paper.""" import numpy as np import tensorflow as tf import dnnlib import dnnlib.tflib as tflib # NOTE: Do not import any application-specific modules here! # Specify all network parameters as kwargs. def _i(x): return tf.transpose(x, [0,2,3,1]) def _o(x): return tf.transpose(x, [0,3,1,2]) #---------------------------------------------------------------------------- # Primitive ops for manipulating 4D activation tensors. # The gradients of these are not necessary efficient or even meaningful. def _blur2d(x, f=[1,2,1], normalize=True, flip=False, stride=1): assert x.shape.ndims == 4 and all(dim.value is not None for dim in x.shape[1:]) assert isinstance(stride, int) and stride >= 1 # Finalize filter kernel. f = np.array(f, dtype=np.float32) if f.ndim == 1: f = f[:, np.newaxis] * f[np.newaxis, :] assert f.ndim == 2 if normalize: f /= np.sum(f) if flip: f = f[::-1, ::-1] f = f[:, :, np.newaxis, np.newaxis] f = np.tile(f, [1, 1, int(x.shape[1]), 1]) # No-op => early exit. if f.shape == (1, 1) and f[0,0] == 1: return x # Convolve using depthwise_conv2d. orig_dtype = x.dtype x = tf.cast(x, tf.float32) # tf.nn.depthwise_conv2d() doesn't support fp16 f = tf.constant(f, dtype=x.dtype, name='filter') strides = [1, stride, stride, 1] x = _o(tf.nn.depthwise_conv2d(_i(x), f, strides=strides, padding='SAME', data_format='NHWC')) x = tf.cast(x, orig_dtype) return x def _upscale2d(x, factor=2, gain=1): assert x.shape.ndims == 4 and all(dim.value is not None for dim in x.shape[1:]) assert isinstance(factor, int) and factor >= 1 # Apply gain. if gain != 1: x *= gain # No-op => early exit. if factor == 1: return x # Upscale using tf.tile(). s = x.shape x = tf.reshape(x, [-1, s[1], s[2], 1, s[3], 1]) x = tf.tile(x, [1, 1, 1, factor, 1, factor]) x = tf.reshape(x, [-1, s[1], s[2] * factor, s[3] * factor]) return x def _downscale2d(x, factor=2, gain=1): assert x.shape.ndims == 4 and all(dim.value is not None for dim in x.shape[1:]) assert isinstance(factor, int) and factor >= 1 # 2x2, float32 => downscale using _blur2d(). if factor == 2 and x.dtype == tf.float32: f = [np.sqrt(gain) / factor] * factor return _blur2d(x, f=f, normalize=False, stride=factor) # Apply gain. if gain != 1: x *= gain # No-op => early exit. if factor == 1: return x # Large factor => downscale using tf.nn.avg_pool(). # NOTE: Requires tf_config['graph_options.place_pruned_graph']=True to work. ksize = [1, factor, factor, 1] return _o(tf.nn.avg_pool(_i(x), ksize=ksize, strides=ksize, padding='VALID', data_format='NHWC')) #---------------------------------------------------------------------------- # High-level ops for manipulating 4D activation tensors. # The gradients of these are meant to be as efficient as possible. def blur2d(x, f=[1,2,1], normalize=True): with tf.variable_scope('Blur2D'): @tf.custom_gradient def func(x): y = _blur2d(x, f, normalize) @tf.custom_gradient def grad(dy): dx = _blur2d(dy, f, normalize, flip=True) return dx, lambda ddx: _blur2d(ddx, f, normalize) return y, grad return func(x) def upscale2d(x, factor=2): with tf.variable_scope('Upscale2D'): @tf.custom_gradient def func(x): y = _upscale2d(x, factor) @tf.custom_gradient def grad(dy): dx = _downscale2d(dy, factor, gain=factor**2) return dx, lambda ddx: _upscale2d(ddx, factor) return y, grad return func(x) def downscale2d(x, factor=2): with tf.variable_scope('Downscale2D'): @tf.custom_gradient def func(x): y = _downscale2d(x, factor) @tf.custom_gradient def grad(dy): dx = _upscale2d(dy, factor, gain=1/factor**2) return dx, lambda ddx: _downscale2d(ddx, factor) return y, grad return func(x) #---------------------------------------------------------------------------- # Get/create weight tensor for a convolutional or fully-connected layer. def get_weight(shape, gain=np.sqrt(2), use_wscale=False, lrmul=1): fan_in = np.prod(shape[:-1]) # [kernel, kernel, fmaps_in, fmaps_out] or [in, out] he_std = gain / np.sqrt(fan_in) # He init # Equalized learning rate and custom learning rate multiplier. if use_wscale: init_std = 1.0 / lrmul runtime_coef = he_std * lrmul else: init_std = he_std / lrmul runtime_coef = lrmul # Create variable. init = tf.initializers.random_normal(0, init_std) return tf.get_variable('weight', shape=shape, initializer=init) * runtime_coef #---------------------------------------------------------------------------- # Fully-connected layer. def dense(x, fmaps, **kwargs): if len(x.shape) > 2: x = tf.reshape(x, [-1, np.prod([d.value for d in x.shape[1:]])]) w = get_weight([x.shape[1].value, fmaps], **kwargs) w = tf.cast(w, x.dtype) return tf.matmul(x, w) #---------------------------------------------------------------------------- # Convolutional layer. def conv2d(x, fmaps, kernel, **kwargs): assert kernel >= 1 and kernel % 2 == 1 w = get_weight([kernel, kernel, x.shape[1].value, fmaps], **kwargs) w = tf.cast(w, x.dtype) return _o(tf.nn.conv2d(_i(x), w, strides=[1,1,1,1], padding='SAME', data_format='NHWC')) #---------------------------------------------------------------------------- # Fused convolution + scaling. # Faster and uses less memory than performing the operations separately. def upscale2d_conv2d(x, fmaps, kernel, fused_scale='auto', **kwargs): assert kernel >= 1 and kernel % 2 == 1 assert fused_scale in [True, False, 'auto'] if fused_scale == 'auto': fused_scale = min(x.shape[2:]) * 2 >= 128 # Not fused => call the individual ops directly. if not fused_scale: return conv2d(upscale2d(x), fmaps, kernel, **kwargs) # Fused => perform both ops simultaneously using tf.nn.conv2d_transpose(). w = get_weight([kernel, kernel, x.shape[1].value, fmaps], **kwargs) w = tf.transpose(w, [0, 1, 3, 2]) # [kernel, kernel, fmaps_out, fmaps_in] w = tf.pad(w, [[1,1], [1,1], [0,0], [0,0]], mode='CONSTANT') w = tf.add_n([w[1:, 1:], w[:-1, 1:], w[1:, :-1], w[:-1, :-1]]) w = tf.cast(w, x.dtype) os = [tf.shape(x)[0], x.shape[2] * 2, x.shape[3] * 2, fmaps] return _o(tf.nn.conv2d_transpose(_i(x), w, os, strides=[1,2,2,1], padding='SAME', data_format='NHWC')) def conv2d_downscale2d(x, fmaps, kernel, fused_scale='auto', **kwargs): assert kernel >= 1 and kernel % 2 == 1 assert fused_scale in [True, False, 'auto'] if fused_scale == 'auto': fused_scale = min(x.shape[2:]) >= 128 # Not fused => call the individual ops directly. if not fused_scale: return downscale2d(conv2d(x, fmaps, kernel, **kwargs)) # Fused => perform both ops simultaneously using tf.nn.conv2d(). w = get_weight([kernel, kernel, x.shape[1].value, fmaps], **kwargs) w = tf.pad(w, [[1,1], [1,1], [0,0], [0,0]], mode='CONSTANT') w = tf.add_n([w[1:, 1:], w[:-1, 1:], w[1:, :-1], w[:-1, :-1]]) * 0.25 w = tf.cast(w, x.dtype) return _o(tf.nn.conv2d(_i(x), w, strides=[1,2,2,1], padding='SAME', data_format='NHWC')) #---------------------------------------------------------------------------- # Apply bias to the given activation tensor. def apply_bias(x, lrmul=1): b = tf.get_variable('bias', shape=[x.shape[1]], initializer=tf.initializers.zeros()) * lrmul b = tf.cast(b, x.dtype) if len(x.shape) == 2: return x + b return x + tf.reshape(b, [1, -1, 1, 1]) #---------------------------------------------------------------------------- # Leaky ReLU activation. More efficient than tf.nn.leaky_relu() and supports FP16. def leaky_relu(x, alpha=0.2): with tf.variable_scope('LeakyReLU'): alpha = tf.constant(alpha, dtype=x.dtype, name='alpha') @tf.custom_gradient def func(x): y = tf.maximum(x, x * alpha) @tf.custom_gradient def grad(dy): dx = tf.where(y >= 0, dy, dy * alpha) return dx, lambda ddx: tf.where(y >= 0, ddx, ddx * alpha) return y, grad return func(x) #---------------------------------------------------------------------------- # Pixelwise feature vector normalization. def pixel_norm(x, epsilon=1e-8): with tf.variable_scope('PixelNorm'): epsilon = tf.constant(epsilon, dtype=x.dtype, name='epsilon') return x * tf.rsqrt(tf.reduce_mean(tf.square(x), axis=1, keepdims=True) + epsilon) #---------------------------------------------------------------------------- # Instance normalization. def instance_norm(x, epsilon=1e-8): assert len(x.shape) == 4 # NCHW with tf.variable_scope('InstanceNorm'): orig_dtype = x.dtype x = tf.cast(x, tf.float32) x -= tf.reduce_mean(x, axis=[2,3], keepdims=True) epsilon = tf.constant(epsilon, dtype=x.dtype, name='epsilon') x *= tf.rsqrt(tf.reduce_mean(tf.square(x), axis=[2,3], keepdims=True) + epsilon) x = tf.cast(x, orig_dtype) return x #---------------------------------------------------------------------------- # Style modulation. def style_mod(x, dlatent, **kwargs): with tf.variable_scope('StyleMod'): style = apply_bias(dense(dlatent, fmaps=x.shape[1]*2, gain=1, **kwargs)) style = tf.reshape(style, [-1, 2, x.shape[1]] + [1] * (len(x.shape) - 2)) return x * (style[:,0] + 1) + style[:,1] #---------------------------------------------------------------------------- # Noise input. def apply_noise(x, noise_var=None, randomize_noise=True): assert len(x.shape) == 4 # NCHW with tf.variable_scope('Noise'): if noise_var is None or randomize_noise: noise = tf.random_normal([tf.shape(x)[0], 1, x.shape[2], x.shape[3]], dtype=x.dtype) else: noise = tf.cast(noise_var, x.dtype) weight = tf.get_variable('weight', shape=[x.shape[1].value], initializer=tf.initializers.zeros()) return x + noise * tf.reshape(tf.cast(weight, x.dtype), [1, -1, 1, 1]) #---------------------------------------------------------------------------- # Minibatch standard deviation. def minibatch_stddev_layer(x, group_size=4, num_new_features=1): with tf.variable_scope('MinibatchStddev'): group_size = tf.minimum(group_size, tf.shape(x)[0]) # Minibatch must be divisible by (or smaller than) group_size. s = x.shape # [NCHW] Input shape. y = tf.reshape(x, [group_size, -1, num_new_features, s[1]//num_new_features, s[2], s[3]]) # [GMncHW] Split minibatch into M groups of size G. Split channels into n channel groups c. y = tf.cast(y, tf.float32) # [GMncHW] Cast to FP32. y -= tf.reduce_mean(y, axis=0, keepdims=True) # [GMncHW] Subtract mean over group. y = tf.reduce_mean(tf.square(y), axis=0) # [MncHW] Calc variance over group. y = tf.sqrt(y + 1e-8) # [MncHW] Calc stddev over group. y = tf.reduce_mean(y, axis=[2,3,4], keepdims=True) # [Mn111] Take average over fmaps and pixels. y = tf.reduce_mean(y, axis=[2]) # [Mn11] Split channels into c channel groups y = tf.cast(y, x.dtype) # [Mn11] Cast back to original data type. y = tf.tile(y, [group_size, 1, s[2], s[3]]) # [NnHW] Replicate over group and pixels. return tf.concat([x, y], axis=1) # [NCHW] Append as new fmap. #---------------------------------------------------------------------------- # Style-based generator used in the StyleGAN paper. # Composed of two sub-networks (G_mapping and G_synthesis) that are defined below. def G_style( latents_in, # First input: Latent vectors (Z) [minibatch, latent_size]. labels_in, # Second input: Conditioning labels [minibatch, label_size]. truncation_psi = 0.7, # Style strength multiplier for the truncation trick. None = disable. truncation_cutoff = 8, # Number of layers for which to apply the truncation trick. None = disable. truncation_psi_val = None, # Value for truncation_psi to use during validation. truncation_cutoff_val = None, # Value for truncation_cutoff to use during validation. dlatent_avg_beta = 0.995, # Decay for tracking the moving average of W during training. None = disable. style_mixing_prob = 0.9, # Probability of mixing styles during training. None = disable. is_training = False, # Network is under training? Enables and disables specific features. is_validation = False, # Network is under validation? Chooses which value to use for truncation_psi. is_template_graph = False, # True = template graph constructed by the Network class, False = actual evaluation. components = dnnlib.EasyDict(), # Container for sub-networks. Retained between calls. **kwargs): # Arguments for sub-networks (G_mapping and G_synthesis). # Validate arguments. assert not is_training or not is_validation assert isinstance(components, dnnlib.EasyDict) if is_validation: truncation_psi = truncation_psi_val truncation_cutoff = truncation_cutoff_val if is_training or (truncation_psi is not None and not tflib.is_tf_expression(truncation_psi) and truncation_psi == 1): truncation_psi = None if is_training or (truncation_cutoff is not None and not tflib.is_tf_expression(truncation_cutoff) and truncation_cutoff <= 0): truncation_cutoff = None if not is_training or (dlatent_avg_beta is not None and not tflib.is_tf_expression(dlatent_avg_beta) and dlatent_avg_beta == 1): dlatent_avg_beta = None if not is_training or (style_mixing_prob is not None and not tflib.is_tf_expression(style_mixing_prob) and style_mixing_prob <= 0): style_mixing_prob = None # Setup components. if 'synthesis' not in components: components.synthesis = tflib.Network('G_synthesis', func_name=G_synthesis, **kwargs) num_layers = components.synthesis.input_shape[1] dlatent_size = components.synthesis.input_shape[2] if 'mapping' not in components: components.mapping = tflib.Network('G_mapping', func_name=G_mapping, dlatent_broadcast=num_layers, **kwargs) # Setup variables. lod_in = tf.get_variable('lod', initializer=np.float32(0), trainable=False) dlatent_avg = tf.get_variable('dlatent_avg', shape=[dlatent_size], initializer=tf.initializers.zeros(), trainable=False) # Evaluate mapping network. dlatents = components.mapping.get_output_for(latents_in, labels_in, **kwargs) # Update moving average of W. if dlatent_avg_beta is not None: with tf.variable_scope('DlatentAvg'): batch_avg = tf.reduce_mean(dlatents[:, 0], axis=0) update_op = tf.assign(dlatent_avg, tflib.lerp(batch_avg, dlatent_avg, dlatent_avg_beta)) with tf.control_dependencies([update_op]): dlatents = tf.identity(dlatents) # Perform style mixing regularization. if style_mixing_prob is not None: with tf.name_scope('StyleMix'): latents2 = tf.random_normal(tf.shape(latents_in)) dlatents2 = components.mapping.get_output_for(latents2, labels_in, **kwargs) layer_idx = np.arange(num_layers)[np.newaxis, :, np.newaxis] cur_layers = num_layers - tf.cast(lod_in, tf.int32) * 2 mixing_cutoff = tf.cond( tf.random_uniform([], 0.0, 1.0) < style_mixing_prob, lambda: tf.random_uniform([], 1, cur_layers, dtype=tf.int32), lambda: cur_layers) dlatents = tf.where(tf.broadcast_to(layer_idx < mixing_cutoff, tf.shape(dlatents)), dlatents, dlatents2) # Apply truncation trick. if truncation_psi is not None and truncation_cutoff is not None: with tf.variable_scope('Truncation'): layer_idx = np.arange(num_layers)[np.newaxis, :, np.newaxis] ones = np.ones(layer_idx.shape, dtype=np.float32) coefs = tf.where(layer_idx < truncation_cutoff, truncation_psi * ones, ones) dlatents = tflib.lerp(dlatent_avg, dlatents, coefs) # Evaluate synthesis network. with tf.control_dependencies([tf.assign(components.synthesis.find_var('lod'), lod_in)]): images_out = components.synthesis.get_output_for(dlatents, force_clean_graph=is_template_graph, **kwargs) return tf.identity(images_out, name='images_out') #---------------------------------------------------------------------------- # Mapping network used in the StyleGAN paper. def G_mapping( latents_in, # First input: Latent vectors (Z) [minibatch, latent_size]. labels_in, # Second input: Conditioning labels [minibatch, label_size]. latent_size = 512, # Latent vector (Z) dimensionality. label_size = 0, # Label dimensionality, 0 if no labels. dlatent_size = 512, # Disentangled latent (W) dimensionality. dlatent_broadcast = None, # Output disentangled latent (W) as [minibatch, dlatent_size] or [minibatch, dlatent_broadcast, dlatent_size]. mapping_layers = 8, # Number of mapping layers. mapping_fmaps = 512, # Number of activations in the mapping layers. mapping_lrmul = 0.01, # Learning rate multiplier for the mapping layers. mapping_nonlinearity = 'lrelu', # Activation function: 'relu', 'lrelu'. use_wscale = True, # Enable equalized learning rate? normalize_latents = False, # Normalize latent vectors (Z) before feeding them to the mapping layers? dtype = 'float32', # Data type to use for activations and outputs. **_kwargs): # Ignore unrecognized keyword args. act, gain = {'relu': (tf.nn.relu, np.sqrt(2)), 'lrelu': (leaky_relu, np.sqrt(2))}[mapping_nonlinearity] # Inputs. latents_in.set_shape([None, latent_size]) labels_in.set_shape([None, label_size]) latents_in = tf.cast(latents_in, dtype) labels_in = tf.cast(labels_in, dtype) x = latents_in # Embed labels and concatenate them with latents. if label_size: with tf.variable_scope('LabelConcat'): w = tf.get_variable('weight', shape=[label_size, latent_size], initializer=tf.initializers.random_normal()) y = tf.matmul(labels_in, tf.cast(w, dtype)) x = tf.concat([x, y], axis=1) # Normalize latents. if normalize_latents: x = pixel_norm(x) # Mapping layers. for layer_idx in range(mapping_layers): with tf.variable_scope('Dense%d' % layer_idx): fmaps = dlatent_size if layer_idx == mapping_layers - 1 else mapping_fmaps x = dense(x, fmaps=fmaps, gain=gain, use_wscale=use_wscale, lrmul=mapping_lrmul) x = apply_bias(x, lrmul=mapping_lrmul) x = act(x) # Broadcast. if dlatent_broadcast is not None: with tf.variable_scope('Broadcast'): x = tf.tile(x[:, np.newaxis], [1, dlatent_broadcast, 1]) # Output. assert x.dtype == tf.as_dtype(dtype) return tf.identity(x, name='dlatents_out') #---------------------------------------------------------------------------- # Synthesis network used in the StyleGAN paper. def G_synthesis( dlatents_in, # Input: Disentangled latents (W) [minibatch, num_layers, dlatent_size]. dlatent_size = 512, # Disentangled latent (W) dimensionality. num_channels = 3, # Number of output color channels. resolution = 1024, # Output resolution. fmap_base = 8192, # Overall multiplier for the number of feature maps. fmap_decay = 1.0, # log2 feature map reduction when doubling the resolution. fmap_max = 512, # Maximum number of feature maps in any layer. use_styles = True, # Enable style inputs? const_input_layer = True, # First layer is a learned constant? use_noise = True, # Enable noise inputs? randomize_noise = True, # True = randomize noise inputs every time (non-deterministic), False = read noise inputs from variables. nonlinearity = 'lrelu', # Activation function: 'relu', 'lrelu' use_wscale = True, # Enable equalized learning rate? use_pixel_norm = False, # Enable pixelwise feature vector normalization? use_instance_norm = True, # Enable instance normalization? dtype = 'float32', # Data type to use for activations and outputs. fused_scale = 'auto', # True = fused convolution + scaling, False = separate ops, 'auto' = decide automatically. blur_filter = [1,2,1], # Low-pass filter to apply when resampling activations. None = no filtering. structure = 'auto', # 'fixed' = no progressive growing, 'linear' = human-readable, 'recursive' = efficient, 'auto' = select automatically. is_template_graph = False, # True = template graph constructed by the Network class, False = actual evaluation. force_clean_graph = False, # True = construct a clean graph that looks nice in TensorBoard, False = default behavior. **_kwargs): # Ignore unrecognized keyword args. resolution_log2 = int(np.log2(resolution)) assert resolution == 2**resolution_log2 and resolution >= 4 def nf(stage): return min(int(fmap_base / (2.0 ** (stage * fmap_decay))), fmap_max) def blur(x): return blur2d(x, blur_filter) if blur_filter else x if is_template_graph: force_clean_graph = True if force_clean_graph: randomize_noise = False if structure == 'auto': structure = 'linear' if force_clean_graph else 'recursive' act, gain = {'relu': (tf.nn.relu, np.sqrt(2)), 'lrelu': (leaky_relu, np.sqrt(2))}[nonlinearity] num_layers = resolution_log2 * 2 - 2 num_styles = num_layers if use_styles else 1 images_out = None # Primary inputs. dlatents_in.set_shape([None, num_styles, dlatent_size]) dlatents_in = tf.cast(dlatents_in, dtype) lod_in = tf.cast(tf.get_variable('lod', initializer=np.float32(0), trainable=False), dtype) # Noise inputs. noise_inputs = [] if use_noise: for layer_idx in range(num_layers): res = layer_idx // 2 + 2 shape = [1, use_noise, 2**res, 2**res] noise_inputs.append(tf.get_variable('noise%d' % layer_idx, shape=shape, initializer=tf.initializers.random_normal(), trainable=False)) # Things to do at the end of each layer. def layer_epilogue(x, layer_idx): if use_noise: x = apply_noise(x, noise_inputs[layer_idx], randomize_noise=randomize_noise) x = apply_bias(x) x = act(x) if use_pixel_norm: x = pixel_norm(x) if use_instance_norm: x = instance_norm(x) if use_styles: x = style_mod(x, dlatents_in[:, layer_idx], use_wscale=use_wscale) return x # Early layers. with tf.variable_scope('4x4'): if const_input_layer: with tf.variable_scope('Const'): x = tf.get_variable('const', shape=[1, nf(1), 4, 4], initializer=tf.initializers.ones()) x = layer_epilogue(tf.tile(tf.cast(x, dtype), [tf.shape(dlatents_in)[0], 1, 1, 1]), 0) else: with tf.variable_scope('Dense'): x = dense(dlatents_in[:, 0], fmaps=nf(1)*16, gain=gain/4, use_wscale=use_wscale) # tweak gain to match the official implementation of Progressing GAN x = layer_epilogue(tf.reshape(x, [-1, nf(1), 4, 4]), 0) with tf.variable_scope('Conv'): x = layer_epilogue(conv2d(x, fmaps=nf(1), kernel=3, gain=gain, use_wscale=use_wscale), 1) # Building blocks for remaining layers. def block(res, x): # res = 3..resolution_log2 with tf.variable_scope('%dx%d' % (2**res, 2**res)): with tf.variable_scope('Conv0_up'): x = layer_epilogue(blur(upscale2d_conv2d(x, fmaps=nf(res-1), kernel=3, gain=gain, use_wscale=use_wscale, fused_scale=fused_scale)), res*2-4) with tf.variable_scope('Conv1'): x = layer_epilogue(conv2d(x, fmaps=nf(res-1), kernel=3, gain=gain, use_wscale=use_wscale), res*2-3) return x def torgb(res, x): # res = 2..resolution_log2 lod = resolution_log2 - res with tf.variable_scope('ToRGB_lod%d' % lod): return apply_bias(conv2d(x, fmaps=num_channels, kernel=1, gain=1, use_wscale=use_wscale)) # Fixed structure: simple and efficient, but does not support progressive growing. if structure == 'fixed': for res in range(3, resolution_log2 + 1): x = block(res, x) images_out = torgb(resolution_log2, x) # Linear structure: simple but inefficient. if structure == 'linear': images_out = torgb(2, x) for res in range(3, resolution_log2 + 1): lod = resolution_log2 - res x = block(res, x) img = torgb(res, x) images_out = upscale2d(images_out) with tf.variable_scope('Grow_lod%d' % lod): images_out = tflib.lerp_clip(img, images_out, lod_in - lod) # Recursive structure: complex but efficient. if structure == 'recursive': def cset(cur_lambda, new_cond, new_lambda): return lambda: tf.cond(new_cond, new_lambda, cur_lambda) def grow(x, res, lod): y = block(res, x) img = lambda: upscale2d(torgb(res, y), 2**lod) img = cset(img, (lod_in > lod), lambda: upscale2d(tflib.lerp(torgb(res, y), upscale2d(torgb(res - 1, x)), lod_in - lod), 2**lod)) if lod > 0: img = cset(img, (lod_in < lod), lambda: grow(y, res + 1, lod - 1)) return img() images_out = grow(x, 3, resolution_log2 - 3) assert images_out.dtype == tf.as_dtype(dtype) return tf.identity(images_out, name='images_out') #---------------------------------------------------------------------------- # Discriminator used in the StyleGAN paper. def D_basic( images_in, # First input: Images [minibatch, channel, height, width]. labels_in, # Second input: Labels [minibatch, label_size]. num_channels = 1, # Number of input color channels. Overridden based on dataset. resolution = 32, # Input resolution. Overridden based on dataset. label_size = 0, # Dimensionality of the labels, 0 if no labels. Overridden based on dataset. fmap_base = 8192, # Overall multiplier for the number of feature maps. fmap_decay = 1.0, # log2 feature map reduction when doubling the resolution. fmap_max = 512, # Maximum number of feature maps in any layer. nonlinearity = 'lrelu', # Activation function: 'relu', 'lrelu', use_wscale = True, # Enable equalized learning rate? mbstd_group_size = 4, # Group size for the minibatch standard deviation layer, 0 = disable. mbstd_num_features = 1, # Number of features for the minibatch standard deviation layer. dtype = 'float32', # Data type to use for activations and outputs. fused_scale = 'auto', # True = fused convolution + scaling, False = separate ops, 'auto' = decide automatically. blur_filter = [1,2,1], # Low-pass filter to apply when resampling activations. None = no filtering. structure = 'auto', # 'fixed' = no progressive growing, 'linear' = human-readable, 'recursive' = efficient, 'auto' = select automatically. is_template_graph = False, # True = template graph constructed by the Network class, False = actual evaluation. **_kwargs): # Ignore unrecognized keyword args. resolution_log2 = int(np.log2(resolution)) assert resolution == 2**resolution_log2 and resolution >= 4 def nf(stage): return min(int(fmap_base / (2.0 ** (stage * fmap_decay))), fmap_max) def blur(x): return blur2d(x, blur_filter) if blur_filter else x if structure == 'auto': structure = 'linear' if is_template_graph else 'recursive' act, gain = {'relu': (tf.nn.relu, np.sqrt(2)), 'lrelu': (leaky_relu, np.sqrt(2))}[nonlinearity] images_in.set_shape([None, num_channels, resolution, resolution]) labels_in.set_shape([None, label_size]) images_in = tf.cast(images_in, dtype) labels_in = tf.cast(labels_in, dtype) lod_in = tf.cast(tf.get_variable('lod', initializer=np.float32(0.0), trainable=False), dtype) scores_out = None # Building blocks. def fromrgb(x, res): # res = 2..resolution_log2 with tf.variable_scope('FromRGB_lod%d' % (resolution_log2 - res)): return act(apply_bias(conv2d(x, fmaps=nf(res-1), kernel=1, gain=gain, use_wscale=use_wscale))) def block(x, res): # res = 2..resolution_log2 with tf.variable_scope('%dx%d' % (2**res, 2**res)): if res >= 3: # 8x8 and up with tf.variable_scope('Conv0'): x = act(apply_bias(conv2d(x, fmaps=nf(res-1), kernel=3, gain=gain, use_wscale=use_wscale))) with tf.variable_scope('Conv1_down'): x = act(apply_bias(conv2d_downscale2d(blur(x), fmaps=nf(res-2), kernel=3, gain=gain, use_wscale=use_wscale, fused_scale=fused_scale))) else: # 4x4 if mbstd_group_size > 1: x = minibatch_stddev_layer(x, mbstd_group_size, mbstd_num_features) with tf.variable_scope('Conv'): x = act(apply_bias(conv2d(x, fmaps=nf(res-1), kernel=3, gain=gain, use_wscale=use_wscale))) with tf.variable_scope('Dense0'): x = act(apply_bias(dense(x, fmaps=nf(res-2), gain=gain, use_wscale=use_wscale))) with tf.variable_scope('Dense1'): x = apply_bias(dense(x, fmaps=max(label_size, 1), gain=1, use_wscale=use_wscale)) return x # Fixed structure: simple and efficient, but does not support progressive growing. if structure == 'fixed': x = fromrgb(images_in, resolution_log2) for res in range(resolution_log2, 2, -1): x = block(x, res) scores_out = block(x, 2) # Linear structure: simple but inefficient. if structure == 'linear': img = images_in x = fromrgb(img, resolution_log2) for res in range(resolution_log2, 2, -1): lod = resolution_log2 - res x = block(x, res) img = downscale2d(img) y = fromrgb(img, res - 1) with tf.variable_scope('Grow_lod%d' % lod): x = tflib.lerp_clip(x, y, lod_in - lod) scores_out = block(x, 2) # Recursive structure: complex but efficient. if structure == 'recursive': def cset(cur_lambda, new_cond, new_lambda): return lambda: tf.cond(new_cond, new_lambda, cur_lambda) def grow(res, lod): x = lambda: fromrgb(downscale2d(images_in, 2**lod), res) if lod > 0: x = cset(x, (lod_in < lod), lambda: grow(res + 1, lod - 1)) x = block(x(), res); y = lambda: x if res > 2: y = cset(y, (lod_in > lod), lambda: tflib.lerp(x, fromrgb(downscale2d(images_in, 2**(lod+1)), res - 1), lod_in - lod)) return y() scores_out = grow(2, resolution_log2 - 2) # Label conditioning from "Which Training Methods for GANs do actually Converge?" if label_size: with tf.variable_scope('LabelSwitch'): scores_out = tf.reduce_sum(scores_out * labels_in, axis=1, keepdims=True) assert scores_out.dtype == tf.as_dtype(dtype) scores_out = tf.identity(scores_out, name='scores_out') return scores_out #---------------------------------------------------------------------------- ================================================ FILE: stylegan2-tpu/training/networks_stylegan2.py ================================================ # Copyright (c) 2019, NVIDIA Corporation. All rights reserved. # # This work is made available under the Nvidia Source Code License-NC. # To view a copy of this license, visit # https://nvlabs.github.io/stylegan2/license.html """Network architectures used in the StyleGAN2 paper.""" import os import numpy as np import tensorflow as tf import dnnlib import dnnlib.tflib as tflib from dnnlib.tflib.ops.upfirdn_2d import upsample_2d, downsample_2d, upsample_conv_2d, conv_downsample_2d from dnnlib.tflib.ops.fused_bias_act import fused_bias_act import functools from dnnlib.tflib.autosummary import autosummary, autoimages # NOTE: Do not import any application-specific modules here! # Specify all network parameters as kwargs. def _i(x): return tf.transpose(x, [0,2,3,1]) def _o(x): return tf.transpose(x, [0,3,1,2]) #---------------------------------------------------------------------------- # Get/create weight tensor for a convolution or fully-connected layer. def get_weight(shape, gain=1, use_wscale=True, lrmul=1, weight_var='weight'): fan_in = np.prod(shape[:-1]) # [kernel, kernel, fmaps_in, fmaps_out] or [in, out] he_std = gain / np.sqrt(fan_in) # He init # Equalized learning rate and custom learning rate multiplier. if use_wscale: init_std = 1.0 / lrmul runtime_coef = he_std * lrmul else: init_std = he_std / lrmul runtime_coef = lrmul # Create variable. init = tf.initializers.random_normal(0, init_std) return tf.get_variable(weight_var, shape=shape, initializer=init, use_resource=True) * runtime_coef #---------------------------------------------------------------------------- # Fully-connected layer. def dense_layer(x, fmaps, gain=1, use_wscale=True, lrmul=1, weight_var='weight'): if len(x.shape) > 2: x = tf.reshape(x, [-1, np.prod([d.value for d in x.shape[1:]])]) w = get_weight([x.shape[1].value, fmaps], gain=gain, use_wscale=use_wscale, lrmul=lrmul, weight_var=weight_var) w = tf.cast(w, x.dtype) return tf.matmul(x, w) #---------------------------------------------------------------------------- # Convolution layer with optional upsampling or downsampling. def conv2d_layer(x, fmaps, kernel, up=False, down=False, resample_kernel=None, gain=1, use_wscale=True, lrmul=1, weight_var='weight'): assert not (up and down) assert kernel >= 1 and kernel % 2 == 1 w = graph_spectral_norm(get_weight([kernel, kernel, x.shape[1].value, fmaps], gain=gain, use_wscale=use_wscale, lrmul=lrmul, weight_var=weight_var)) if up: x = _o(upsample_conv_2d(_i(x), tf.cast(w, x.dtype), data_format='NHWC', k=resample_kernel)) elif down: x = _o(conv_downsample_2d(_i(x), tf.cast(w, x.dtype), data_format='NHWC', k=resample_kernel)) else: x = _o(tf.nn.conv2d(_i(x), tf.cast(w, x.dtype), data_format='NHWC', strides=[1,1,1,1], padding='SAME')) return x #---------------------------------------------------------------------------- # Apply bias and activation func. def apply_bias_act(x, act='linear', alpha=None, gain=None, lrmul=1, bias_var='bias'): b = tf.get_variable(bias_var, shape=[x.shape[1]], initializer=tf.initializers.zeros(), use_resource=True) * lrmul return fused_bias_act(x, b=tf.cast(b, x.dtype), act=act, alpha=alpha, gain=gain) #---------------------------------------------------------------------------- # Naive upsampling (nearest neighbor) and downsampling (average pooling). def naive_upsample_2d(x, factor=2): with tf.variable_scope('NaiveUpsample'): _N, C, H, W = x.shape.as_list() x = tf.reshape(x, [-1, C, H, 1, W, 1]) x = tf.tile(x, [1, 1, 1, factor, 1, factor]) return tf.reshape(x, [-1, C, H * factor, W * factor]) def naive_downsample_2d(x, factor=2): with tf.variable_scope('NaiveDownsample'): _N, C, H, W = x.shape.as_list() x = tf.reshape(x, [-1, C, H // factor, factor, W // factor, factor]) return tf.reduce_mean(x, axis=[3,5]) #---------------------------------------------------------------------------- # Modulated convolution layer. def modulated_conv2d_layer(x, y, fmaps, kernel, up=False, down=False, demodulate=True, resample_kernel=None, gain=1, use_wscale=True, lrmul=1, fused_modconv=True, weight_var='weight', mod_weight_var='mod_weight', mod_bias_var='mod_bias'): assert not (up and down) assert kernel >= 1 and kernel % 2 == 1 # Get weight. w = graph_spectral_norm(get_weight([kernel, kernel, x.shape[1].value, fmaps], gain=gain, use_wscale=use_wscale, lrmul=lrmul, weight_var=weight_var)) ww = w[np.newaxis] # [BkkIO] Introduce minibatch dimension. # Modulate. s = dense_layer(y, fmaps=x.shape[1].value, weight_var=mod_weight_var) # [BI] Transform incoming W to style. s = apply_bias_act(s, bias_var=mod_bias_var) + 1 # [BI] Add bias (initially 1). ww *= tf.cast(s[:, np.newaxis, np.newaxis, :, np.newaxis], w.dtype) # [BkkIO] Scale input feature maps. # Demodulate. if demodulate: d = tf.rsqrt(tf.reduce_sum(tf.square(ww), axis=[1,2,3]) + 1e-8) # [BO] Scaling factor. ww *= d[:, np.newaxis, np.newaxis, np.newaxis, :] # [BkkIO] Scale output feature maps. # Reshape/scale input. if fused_modconv: x = tf.reshape(x, [1, -1, x.shape[2], x.shape[3]]) # Fused => reshape minibatch to convolution groups. w = tf.reshape(tf.transpose(ww, [1, 2, 3, 0, 4]), [ww.shape[1], ww.shape[2], ww.shape[3], -1]) else: x *= tf.cast(s[:, :, np.newaxis, np.newaxis], x.dtype) # [BIhw] Not fused => scale input activations. # Convolution with optional up/downsampling. if up: x = _o(upsample_conv_2d(_i(x), tf.cast(w, x.dtype), data_format='NHWC', k=resample_kernel)) elif down: x = _o(conv_downsample_2d(_i(x), tf.cast(w, x.dtype), data_format='NHWC', k=resample_kernel)) else: x = _o(tf.nn.conv2d(_i(x), tf.cast(w, x.dtype), data_format='NHWC', strides=[1,1,1,1], padding='SAME')) # Reshape/scale output. if fused_modconv: x = tf.reshape(x, [-1, fmaps, x.shape[2], x.shape[3]]) # Fused => reshape convolution groups back to minibatch. elif demodulate: x *= tf.cast(d[:, :, np.newaxis, np.newaxis], x.dtype) # [BOhw] Not fused => scale output activations. return x #---------------------------------------------------------------------------- # Minibatch standard deviation layer. def minibatch_stddev_layer(x, group_size=4, num_new_features=1): group_size = tf.minimum(group_size, tf.shape(x)[0]) # Minibatch must be divisible by (or smaller than) group_size. s = x.shape # [NCHW] Input shape. y = tf.reshape(x, [group_size, -1, num_new_features, s[1]//num_new_features, s[2], s[3]]) # [GMncHW] Split minibatch into M groups of size G. Split channels into n channel groups c. y = tf.cast(y, tf.float32) # [GMncHW] Cast to FP32. y -= tf.reduce_mean(y, axis=0, keepdims=True) # [GMncHW] Subtract mean over group. y = tf.reduce_mean(tf.square(y), axis=0) # [MncHW] Calc variance over group. y = tf.sqrt(y + 1e-8) # [MncHW] Calc stddev over group. y = tf.reduce_mean(y, axis=[2,3,4], keepdims=True) # [Mn111] Take average over fmaps and pixels. y = tf.reduce_mean(y, axis=[2]) # [Mn11] Split channels into c channel groups y = tf.cast(y, x.dtype) # [Mn11] Cast back to original data type. y = tf.tile(y, [group_size, 1, s[2], s[3]]) # [NnHW] Replicate over group and pixels. return tf.concat([x, y], axis=1) # [NCHW] Append as new fmap. #---------------------------------------------------------------------------- # Main generator network. # Composed of two sub-networks (mapping and synthesis) that are defined below. # Used in configs B-F (Table 1). def G_main( latents_in, # First input: Latent vectors (Z) [minibatch, latent_size]. labels_in, # Second input: Conditioning labels [minibatch, label_size]. truncation_psi = 0.5, # Style strength multiplier for the truncation trick. None = disable. truncation_cutoff = None, # Number of layers for which to apply the truncation trick. None = disable. truncation_psi_val = None, # Value for truncation_psi to use during validation. truncation_cutoff_val = None, # Value for truncation_cutoff to use during validation. dlatent_avg_beta = 0.995, # Decay for tracking the moving average of W during training. None = disable. style_mixing_prob = 0.9, # Probability of mixing styles during training. None = disable. is_training = False, # Network is under training? Enables and disables specific features. is_validation = False, # Network is under validation? Chooses which value to use for truncation_psi. return_dlatents = False, # Return dlatents in addition to the images? is_template_graph = False, # True = template graph constructed by the Network class, False = actual evaluation. components = dnnlib.EasyDict(), # Container for sub-networks. Retained between calls. mapping_func = 'G_mapping', # Build func name for the mapping network. synthesis_func = 'G_synthesis_stylegan2', # Build func name for the synthesis network. **kwargs): # Arguments for sub-networks (mapping and synthesis). # Validate arguments. assert not is_training or not is_validation assert isinstance(components, dnnlib.EasyDict) if is_validation: truncation_psi = truncation_psi_val truncation_cutoff = truncation_cutoff_val if is_training or (truncation_psi is not None and not tflib.is_tf_expression(truncation_psi) and truncation_psi == 1): truncation_psi = None if is_training: truncation_cutoff = None if not is_training or (dlatent_avg_beta is not None and not tflib.is_tf_expression(dlatent_avg_beta) and dlatent_avg_beta == 1): dlatent_avg_beta = None if not is_training or (style_mixing_prob is not None and not tflib.is_tf_expression(style_mixing_prob) and style_mixing_prob <= 0): style_mixing_prob = None # Setup components. if 'synthesis' not in components: components.synthesis = tflib.Network('G_synthesis', func_name=globals()[synthesis_func], **kwargs) num_layers = components.synthesis.input_shape[1] dlatent_size = components.synthesis.input_shape[2] if 'mapping' not in components: components.mapping = tflib.Network('G_mapping', func_name=globals()[mapping_func], dlatent_broadcast=num_layers, **kwargs) # Setup variables. lod_in = tf.get_variable('lod', initializer=np.float32(0), trainable=False, use_resource=True) dlatent_avg = tf.get_variable('dlatent_avg', shape=[dlatent_size], initializer=tf.initializers.zeros(), trainable=False, use_resource=True) # Evaluate mapping network. dlatents = components.mapping.get_output_for(latents_in, labels_in, is_training=is_training, **kwargs) dlatents = tf.cast(dlatents, tf.float32) # Update moving average of W. if dlatent_avg_beta is not None: with tf.variable_scope('DlatentAvg'): batch_avg = tf.reduce_mean(dlatents[:, 0], axis=0) update_op = tf.assign(dlatent_avg, tflib.lerp(batch_avg, dlatent_avg, dlatent_avg_beta)) with tf.control_dependencies([update_op]): dlatents = tf.identity(dlatents) # Perform style mixing regularization. if style_mixing_prob is not None: with tf.variable_scope('StyleMix'): latents2 = tf.random_normal(tf.shape(latents_in)) dlatents2 = components.mapping.get_output_for(latents2, labels_in, is_training=is_training, **kwargs) dlatents2 = tf.cast(dlatents2, tf.float32) layer_idx = np.arange(num_layers)[np.newaxis, :, np.newaxis] cur_layers = num_layers - tf.cast(lod_in, tf.int32) * 2 mixing_cutoff = tf.cond( tf.random_uniform([], 0.0, 1.0) < style_mixing_prob, lambda: tf.random_uniform([], 1, cur_layers, dtype=tf.int32), lambda: cur_layers) dlatents = tf.where(tf.broadcast_to(layer_idx < mixing_cutoff, tf.shape(dlatents)), dlatents, dlatents2) # Apply truncation trick. if truncation_psi is not None: with tf.variable_scope('Truncation'): layer_idx = np.arange(num_layers)[np.newaxis, :, np.newaxis] layer_psi = np.ones(layer_idx.shape, dtype=np.float32) if truncation_cutoff is None: layer_psi *= truncation_psi else: layer_psi = tf.where(layer_idx < truncation_cutoff, layer_psi * truncation_psi, layer_psi) dlatents = tflib.lerp(dlatent_avg, dlatents, layer_psi) # Evaluate synthesis network. deps = [] if 'lod' in components.synthesis.vars: deps.append(tf.assign(components.synthesis.vars['lod'], lod_in)) with tf.control_dependencies(deps): images_out = components.synthesis.get_output_for(dlatents, is_training=is_training, force_clean_graph=is_template_graph, **kwargs) # Return requested outputs. images_out = tf.identity(images_out, name='images_out') if return_dlatents: return images_out, dlatents return images_out #---------------------------------------------------------------------------- # Mapping network. # Transforms the input latent code (z) to the disentangled latent code (w). # Used in configs B-F (Table 1). def G_mapping( latents_in, # First input: Latent vectors (Z) [minibatch, latent_size]. labels_in, # Second input: Conditioning labels [minibatch, label_size]. latent_size = 512, # Latent vector (Z) dimensionality. label_size = 0, # Label dimensionality, 0 if no labels. dlatent_size = 512, # Disentangled latent (W) dimensionality. dlatent_broadcast = None, # Output disentangled latent (W) as [minibatch, dlatent_size] or [minibatch, dlatent_broadcast, dlatent_size]. mapping_layers = 8, # Number of mapping layers. mapping_fmaps = 512, # Number of activations in the mapping layers. mapping_lrmul = 0.01, # Learning rate multiplier for the mapping layers. mapping_nonlinearity = 'lrelu', # Activation function: 'relu', 'lrelu', etc. normalize_latents = True, # Normalize latent vectors (Z) before feeding them to the mapping layers? dtype = 'float32', # Data type to use for activations and outputs. **_kwargs): # Ignore unrecognized keyword args. act = mapping_nonlinearity # Inputs. latents_in.set_shape([None, latent_size]) labels_in.set_shape([None, label_size]) latents_in = tf.cast(latents_in, dtype) labels_in = tf.cast(labels_in, dtype) x = latents_in # Embed labels and concatenate them with latents. if label_size: with tf.variable_scope('LabelConcat'): w = tf.get_variable('weight', shape=[label_size, latent_size], initializer=tf.initializers.random_normal(), use_resource=True) y = tf.matmul(labels_in, tf.cast(w, dtype)) x = tf.concat([x, y], axis=1) # Normalize latents. if normalize_latents: with tf.variable_scope('Normalize'): x *= tf.rsqrt(tf.reduce_mean(tf.square(x), axis=1, keepdims=True) + 1e-8) # Mapping layers. for layer_idx in range(mapping_layers): with tf.variable_scope('Dense%d' % layer_idx): fmaps = dlatent_size if layer_idx == mapping_layers - 1 else mapping_fmaps x = apply_bias_act(dense_layer(x, fmaps=fmaps, lrmul=mapping_lrmul), act=act, lrmul=mapping_lrmul) # Broadcast. if dlatent_broadcast is not None: with tf.variable_scope('Broadcast'): x = tf.tile(x[:, np.newaxis], [1, dlatent_broadcast, 1]) # Output. assert x.dtype == tf.as_dtype(dtype) return tf.identity(x, name='dlatents_out') #---------------------------------------------------------------------------- # StyleGAN synthesis network with revised architecture (Figure 2d). # Implements progressive growing, but no skip connections or residual nets (Figure 7). # Used in configs B-D (Table 1). def G_synthesis_stylegan_revised( dlatents_in, # Input: Disentangled latents (W) [minibatch, num_layers, dlatent_size]. dlatent_size = 512, # Disentangled latent (W) dimensionality. num_channels = 3, # Number of output color channels. resolution = 1024, # Output resolution. fmap_base = 16 << 10, # Overall multiplier for the number of feature maps. fmap_decay = 1.0, # log2 feature map reduction when doubling the resolution. fmap_min = 1, # Minimum number of feature maps in any layer. fmap_max = 512, # Maximum number of feature maps in any layer. randomize_noise = True, # True = randomize noise inputs every time (non-deterministic), False = read noise inputs from variables. nonlinearity = 'lrelu', # Activation function: 'relu', 'lrelu', etc. dtype = 'float32', # Data type to use for activations and outputs. resample_kernel = [1,3,3,1], # Low-pass filter to apply when resampling activations. None = no filtering. fused_modconv = True, # Implement modulated_conv2d_layer() as a single fused op? structure = 'auto', # 'fixed' = no progressive growing, 'linear' = human-readable, 'recursive' = efficient, 'auto' = select automatically. is_template_graph = False, # True = template graph constructed by the Network class, False = actual evaluation. force_clean_graph = False, # True = construct a clean graph that looks nice in TensorBoard, False = default behavior. **_kwargs): # Ignore unrecognized keyword args. num_channels = int(os.environ["NUM_CHANNELS"]) if "NUM_CHANNELS" in os.environ else num_channels resolution_log2 = int(np.log2(resolution)) assert resolution == 2**resolution_log2 and resolution >= 4 def nf(stage): return np.clip(int(fmap_base / (2.0 ** (stage * fmap_decay))), fmap_min, fmap_max) if is_template_graph: force_clean_graph = True if force_clean_graph: randomize_noise = False if structure == 'auto': structure = 'linear' if force_clean_graph else 'recursive' act = nonlinearity num_layers = resolution_log2 * 2 - 2 images_out = None # Primary inputs. dlatents_in.set_shape([None, num_layers, dlatent_size]) dlatents_in = tf.cast(dlatents_in, dtype) lod_in = tf.cast(tf.get_variable('lod', initializer=np.float32(0), trainable=False, use_resource=True), dtype) # Noise inputs. noise_inputs = [] for layer_idx in range(num_layers - 1): res = (layer_idx + 5) // 2 shape = [1, 1, 2**res, 2**res] noise_inputs.append(tf.get_variable('noise%d' % layer_idx, shape=shape, initializer=tf.initializers.random_normal(), trainable=False, use_resource=True)) # Single convolution layer with all the bells and whistles. def layer(x, layer_idx, fmaps, kernel, up=False): x = modulated_conv2d_layer(x, dlatents_in[:, layer_idx], fmaps=fmaps, kernel=kernel, up=up, resample_kernel=resample_kernel, fused_modconv=fused_modconv) if randomize_noise: noise = tf.random_normal([tf.shape(x)[0], 1, x.shape[2], x.shape[3]], dtype=x.dtype) else: noise = tf.cast(noise_inputs[layer_idx], x.dtype) noise_strength = tf.get_variable('noise_strength', shape=[], initializer=tf.initializers.zeros(), use_resource=True) x += noise * tf.cast(noise_strength, x.dtype) return apply_bias_act(x, act=act) # Early layers. with tf.variable_scope('4x4'): with tf.variable_scope('Const'): x = tf.get_variable('const', shape=[1, nf(1), 4, 4], initializer=tf.initializers.random_normal(), use_resource=True) x = tf.tile(tf.cast(x, dtype), [tf.shape(dlatents_in)[0], 1, 1, 1]) with tf.variable_scope('Conv'): x = layer(x, layer_idx=0, fmaps=nf(1), kernel=3) # Building blocks for remaining layers. def block(res, x): # res = 3..resolution_log2 with tf.variable_scope('%dx%d' % (2**res, 2**res)): with tf.variable_scope('Conv0_up'): x = layer(x, layer_idx=res*2-5, fmaps=nf(res-1), kernel=3, up=True) with tf.variable_scope('Conv1'): x = layer(x, layer_idx=res*2-4, fmaps=nf(res-1), kernel=3) return x def torgb(res, x): # res = 2..resolution_log2 with tf.variable_scope('ToRGB_lod%d' % (resolution_log2 - res)): return apply_bias_act(modulated_conv2d_layer(x, dlatents_in[:, res*2-3], fmaps=num_channels, kernel=1, demodulate=False, fused_modconv=fused_modconv)) # Fixed structure: simple and efficient, but does not support progressive growing. if structure == 'fixed': for res in range(3, resolution_log2 + 1): x = block(res, x) images_out = torgb(resolution_log2, x) # Linear structure: simple but inefficient. if structure == 'linear': images_out = torgb(2, x) for res in range(3, resolution_log2 + 1): lod = resolution_log2 - res x = block(res, x) img = torgb(res, x) with tf.variable_scope('Upsample_lod%d' % lod): images_out = upsample_2d(images_out) with tf.variable_scope('Grow_lod%d' % lod): images_out = tflib.lerp_clip(img, images_out, lod_in - lod) # Recursive structure: complex but efficient. if structure == 'recursive': def cset(cur_lambda, new_cond, new_lambda): return lambda: tf.cond(new_cond, new_lambda, cur_lambda) def grow(x, res, lod): y = block(res, x) img = lambda: naive_upsample_2d(torgb(res, y), factor=2**lod) img = cset(img, (lod_in > lod), lambda: naive_upsample_2d(tflib.lerp(torgb(res, y), upsample_2d(torgb(res - 1, x)), lod_in - lod), factor=2**lod)) if lod > 0: img = cset(img, (lod_in < lod), lambda: grow(y, res + 1, lod - 1)) return img() images_out = grow(x, 3, resolution_log2 - 3) assert images_out.dtype == tf.as_dtype(dtype) return tf.identity(images_out, name='images_out') #---------------------------------------------------------------------------- # StyleGAN2 synthesis network (Figure 7). # Implements skip connections and residual nets (Figure 7), but no progressive growing. # Used in configs E-F (Table 1). def G_synthesis_stylegan2( dlatents_in, # Input: Disentangled latents (W) [minibatch, num_layers, dlatent_size]. dlatent_size = 512, # Disentangled latent (W) dimensionality. num_channels = 3, # Number of output color channels. resolution = 1024, # Output resolution. fmap_base = 16 << 10, # Overall multiplier for the number of feature maps. fmap_decay = 1.0, # log2 feature map reduction when doubling the resolution. fmap_min = 1, # Minimum number of feature maps in any layer. fmap_max = 512, # Maximum number of feature maps in any layer. randomize_noise = True, # True = randomize noise inputs every time (non-deterministic), False = read noise inputs from variables. architecture = 'skip', # Architecture: 'orig', 'skip', 'resnet'. nonlinearity = 'lrelu', # Activation function: 'relu', 'lrelu', etc. dtype = 'float32', # Data type to use for activations and outputs. resample_kernel = [1,3,3,1], # Low-pass filter to apply when resampling activations. None = no filtering. fused_modconv = True, # Implement modulated_conv2d_layer() as a single fused op? **_kwargs): # Ignore unrecognized keyword args. num_channels = int(os.environ["NUM_CHANNELS"]) if "NUM_CHANNELS" in os.environ else num_channels resolution_log2 = int(np.log2(resolution)) assert resolution == 2**resolution_log2 and resolution >= 4 def nf(stage): return np.clip(int(fmap_base / (2.0 ** (stage * fmap_decay))), fmap_min, fmap_max) assert architecture in ['orig', 'skip', 'resnet'] act = nonlinearity num_layers = resolution_log2 * 2 - 2 images_out = None # Primary inputs. dlatents_in.set_shape([None, num_layers, dlatent_size]) dlatents_in = tf.cast(dlatents_in, dtype) # Noise inputs. noise_inputs = [] for layer_idx in range(num_layers - 1): res = (layer_idx + 5) // 2 shape = [1, 1, 2**res, 2**res] noise_inputs.append(tf.get_variable('noise%d' % layer_idx, shape=shape, initializer=tf.initializers.random_normal(), trainable=False, use_resource=True)) # Single convolution layer with all the bells and whistles. def layer(x, layer_idx, fmaps, kernel, up=False): x = modulated_conv2d_layer(x, dlatents_in[:, layer_idx], fmaps=fmaps, kernel=kernel, up=up, resample_kernel=resample_kernel, fused_modconv=fused_modconv) if randomize_noise: noise = tf.random_normal([tf.shape(x)[0], 1, x.shape[2], x.shape[3]], dtype=x.dtype) else: noise = tf.cast(noise_inputs[layer_idx], x.dtype) noise_strength = tf.get_variable('noise_strength', shape=[], initializer=tf.initializers.zeros(), use_resource=True) x += noise * tf.cast(noise_strength, x.dtype) return apply_bias_act(x, act=act) # Building blocks for main layers. def block(x, res): # res = 3..resolution_log2 t = x with tf.variable_scope('Conv0_up'): x = layer(x, layer_idx=res*2-5, fmaps=nf(res-1), kernel=3, up=True) with tf.variable_scope('Conv1'): x = layer(x, layer_idx=res*2-4, fmaps=nf(res-1), kernel=3) if architecture == 'resnet': with tf.variable_scope('Skip'): t = conv2d_layer(t, fmaps=nf(res-1), kernel=1, up=True, resample_kernel=resample_kernel) x = (x + t) * (1 / np.sqrt(2)) return x def upsample(y): with tf.variable_scope('Upsample'): return upsample_2d(y, k=resample_kernel) def torgb(x, y, res): # res = 2..resolution_log2 with tf.variable_scope('ToRGB'): t = apply_bias_act(modulated_conv2d_layer(x, dlatents_in[:, res*2-3], fmaps=num_channels, kernel=1, demodulate=False, fused_modconv=fused_modconv)) return graph_images(t if y is None else y + t, res=2**res) # Early layers. y = None with tf.variable_scope('4x4'): with tf.variable_scope('Const'): x = tf.get_variable('const', shape=[1, nf(1), 4, 4], initializer=tf.initializers.random_normal(), use_resource=True) x = tf.tile(tf.cast(x, dtype), [tf.shape(dlatents_in)[0], 1, 1, 1]) with tf.variable_scope('Conv'): x = layer(x, layer_idx=0, fmaps=nf(1), kernel=3) if architecture == 'skip': y = torgb(x, y, 2) # Main layers. for res in range(3, resolution_log2 + 1): with tf.variable_scope('%dx%d' % (2**res, 2**res)): x = block(x, res) if 2**res == 64 and False: print('Adding self-attention block to generator') x = non_local_block(x, "SelfAtten", use_sn=True) if architecture == 'skip': y = upsample(y) if architecture == 'skip' or res == resolution_log2: y = torgb(x, y, res) images_out = y assert images_out.dtype == tf.as_dtype(dtype) return tf.identity(images_out, name='images_out') #---------------------------------------------------------------------------- # Original StyleGAN discriminator. # Used in configs B-D (Table 1). def D_stylegan( images_in, # First input: Images [minibatch, channel, height, width]. labels_in, # Second input: Labels [minibatch, label_size]. num_channels = 3, # Number of input color channels. Overridden based on dataset. resolution = 1024, # Input resolution. Overridden based on dataset. label_size = 0, # Dimensionality of the labels, 0 if no labels. Overridden based on dataset. fmap_base = 16 << 10, # Overall multiplier for the number of feature maps. fmap_decay = 1.0, # log2 feature map reduction when doubling the resolution. fmap_min = 1, # Minimum number of feature maps in any layer. fmap_max = 512, # Maximum number of feature maps in any layer. nonlinearity = 'lrelu', # Activation function: 'relu', 'lrelu', etc. mbstd_group_size = 4, # Group size for the minibatch standard deviation layer, 0 = disable. mbstd_num_features = 1, # Number of features for the minibatch standard deviation layer. dtype = 'float32', # Data type to use for activations and outputs. resample_kernel = [1,3,3,1], # Low-pass filter to apply when resampling activations. None = no filtering. structure = 'auto', # 'fixed' = no progressive growing, 'linear' = human-readable, 'recursive' = efficient, 'auto' = select automatically. is_template_graph = False, # True = template graph constructed by the Network class, False = actual evaluation. **_kwargs): # Ignore unrecognized keyword args. num_channels = int(os.environ["NUM_CHANNELS"]) if "NUM_CHANNELS" in os.environ else num_channels resolution_log2 = int(np.log2(resolution)) assert resolution == 2**resolution_log2 and resolution >= 4 def nf(stage): return np.clip(int(fmap_base / (2.0 ** (stage * fmap_decay))), fmap_min, fmap_max) if structure == 'auto': structure = 'linear' if is_template_graph else 'recursive' act = nonlinearity images_in.set_shape([None, num_channels, resolution, resolution]) labels_in.set_shape([None, label_size]) images_in = tf.cast(images_in, dtype) labels_in = tf.cast(labels_in, dtype) lod_in = tf.cast(tf.get_variable('lod', initializer=np.float32(0.0), trainable=False, use_resource=True), dtype) # Building blocks for spatial layers. def fromrgb(x, res): # res = 2..resolution_log2 with tf.variable_scope('FromRGB_lod%d' % (resolution_log2 - res)): return apply_bias_act(conv2d_layer(x, fmaps=nf(res-1), kernel=1), act=act) def block(x, res): # res = 2..resolution_log2 with tf.variable_scope('%dx%d' % (2**res, 2**res)): with tf.variable_scope('Conv0'): x = apply_bias_act(conv2d_layer(x, fmaps=nf(res-1), kernel=3), act=act) with tf.variable_scope('Conv1_down'): x = apply_bias_act(conv2d_layer(x, fmaps=nf(res-2), kernel=3, down=True, resample_kernel=resample_kernel), act=act) return x # Fixed structure: simple and efficient, but does not support progressive growing. if structure == 'fixed': x = fromrgb(images_in, resolution_log2) for res in range(resolution_log2, 2, -1): x = block(x, res) # Linear structure: simple but inefficient. if structure == 'linear': img = images_in x = fromrgb(img, resolution_log2) for res in range(resolution_log2, 2, -1): lod = resolution_log2 - res x = block(x, res) with tf.variable_scope('Downsample_lod%d' % lod): img = downsample_2d(img) y = fromrgb(img, res - 1) with tf.variable_scope('Grow_lod%d' % lod): x = tflib.lerp_clip(x, y, lod_in - lod) # Recursive structure: complex but efficient. if structure == 'recursive': def cset(cur_lambda, new_cond, new_lambda): return lambda: tf.cond(new_cond, new_lambda, cur_lambda) def grow(res, lod): x = lambda: fromrgb(naive_downsample_2d(images_in, factor=2**lod), res) if lod > 0: x = cset(x, (lod_in < lod), lambda: grow(res + 1, lod - 1)) x = block(x(), res); y = lambda: x y = cset(y, (lod_in > lod), lambda: tflib.lerp(x, fromrgb(naive_downsample_2d(images_in, factor=2**(lod+1)), res - 1), lod_in - lod)) return y() x = grow(3, resolution_log2 - 3) # Final layers at 4x4 resolution. with tf.variable_scope('4x4'): if mbstd_group_size > 1: with tf.variable_scope('MinibatchStddev'): x = minibatch_stddev_layer(x, mbstd_group_size, mbstd_num_features) with tf.variable_scope('Conv'): x = apply_bias_act(conv2d_layer(x, fmaps=nf(1), kernel=3), act=act) with tf.variable_scope('Dense0'): x = apply_bias_act(dense_layer(x, fmaps=nf(0)), act=act) with tf.variable_scope('Output'): x = apply_bias_act(dense_layer(x, fmaps=1)) scores_out = x # Output. assert scores_out.dtype == tf.as_dtype(dtype) scores_out = tf.identity(scores_out, name='scores_out') return scores_out #---------------------------------------------------------------------------- # StyleGAN2 discriminator (Figure 7). # Implements skip connections and residual nets (Figure 7), but no progressive growing. # Used in configs E-F (Table 1). def D_stylegan2( images_in, # First input: Images [minibatch, channel, height, width]. labels_in, # Second input: Labels [minibatch, label_size]. num_channels = 3, # Number of input color channels. Overridden based on dataset. resolution = 1024, # Input resolution. Overridden based on dataset. label_size = 0, # Dimensionality of the labels, 0 if no labels. Overridden based on dataset. fmap_base = 16 << 10, # Overall multiplier for the number of feature maps. fmap_decay = 1.0, # log2 feature map reduction when doubling the resolution. fmap_min = 1, # Minimum number of feature maps in any layer. fmap_max = 512, # Maximum number of feature maps in any layer. architecture = 'resnet', # Architecture: 'orig', 'skip', 'resnet'. nonlinearity = 'lrelu', # Activation function: 'relu', 'lrelu', etc. mbstd_group_size = 4, # Group size for the minibatch standard deviation layer, 0 = disable. mbstd_num_features = 1, # Number of features for the minibatch standard deviation layer. dtype = 'float32', # Data type to use for activations and outputs. resample_kernel = [1,3,3,1], # Low-pass filter to apply when resampling activations. None = no filtering. **_kwargs): # Ignore unrecognized keyword args. num_channels = int(os.environ["NUM_CHANNELS"]) if "NUM_CHANNELS" in os.environ else num_channels resolution_log2 = int(np.log2(resolution)) assert resolution == 2**resolution_log2 and resolution >= 4 def nf(stage): return np.clip(int(fmap_base / (2.0 ** (stage * fmap_decay))), fmap_min, fmap_max) assert architecture in ['orig', 'skip', 'resnet'] act = nonlinearity images_in.set_shape([None, num_channels, resolution, resolution]) labels_in.set_shape([None, label_size]) images_in = tf.cast(images_in, dtype) labels_in = tf.cast(labels_in, dtype) # Building blocks for main layers. def fromrgb(x, y, res): # res = 2..resolution_log2 with tf.variable_scope('FromRGB'): t = apply_bias_act(conv2d_layer(y, fmaps=nf(res-1), kernel=1), act=act) return t if x is None else x + t def block(x, res): # res = 2..resolution_log2 t = x with tf.variable_scope('Conv0'): x = apply_bias_act(conv2d_layer(x, fmaps=nf(res-1), kernel=3), act=act) with tf.variable_scope('Conv1_down'): x = apply_bias_act(conv2d_layer(x, fmaps=nf(res-2), kernel=3, down=True, resample_kernel=resample_kernel), act=act) if architecture == 'resnet': with tf.variable_scope('Skip'): t = conv2d_layer(t, fmaps=nf(res-2), kernel=1, down=True, resample_kernel=resample_kernel) x = (x + t) * (1 / np.sqrt(2)) return x def downsample(y): with tf.variable_scope('Downsample'): return downsample_2d(y, k=resample_kernel) # Main layers. x = None y = images_in for res in range(resolution_log2, 2, -1): with tf.variable_scope('%dx%d' % (2**res, 2**res)): if architecture == 'skip' or res == resolution_log2: x = fromrgb(x, y, res) if 2**res == 64 and False: print('Adding self-attention block to discriminator') x = non_local_block(x, "SelfAtten", use_sn=True) x = block(x, res) if architecture == 'skip': y = downsample(y) # Final layers. with tf.variable_scope('4x4'): if architecture == 'skip': x = fromrgb(x, y, 2) if mbstd_group_size > 1: with tf.variable_scope('MinibatchStddev'): x = minibatch_stddev_layer(x, mbstd_group_size, mbstd_num_features) with tf.variable_scope('Conv'): x = apply_bias_act(conv2d_layer(x, fmaps=nf(1), kernel=3), act=act) with tf.variable_scope('Dense0'): x = apply_bias_act(dense_layer(x, fmaps=nf(0)), act=act) with tf.variable_scope('Output'): x = apply_bias_act(dense_layer(x, fmaps=1)) scores_out = x # Output. assert scores_out.dtype == tf.as_dtype(dtype) scores_out = tf.identity(scores_out, name='scores_out') return scores_out #---------------------------------------------------------------------------- NORMAL_INIT = "normal" TRUNCATED_INIT = "truncated" ORTHOGONAL_INIT = "orthogonal" INITIALIZERS = [NORMAL_INIT, TRUNCATED_INIT, ORTHOGONAL_INIT] #@gin.configurable("weights") def weight_initializer(initializer=NORMAL_INIT, stddev=0.02): """Returns the initializer for the given name. Args: initializer: Name of the initalizer. Use one in INITIALIZERS. stddev: Standard deviation passed to initalizer. Returns: Initializer from `tf.initializers`. """ if initializer == NORMAL_INIT: return tf.initializers.random_normal(stddev=stddev) if initializer == TRUNCATED_INIT: return tf.initializers.truncated_normal(stddev=stddev) if initializer == ORTHOGONAL_INIT: return tf.initializers.orthogonal() raise ValueError("Unknown weight initializer {}.".format(initializer)) #@gin.configurable(blacklist=["inputs"]) def spectral_norm(inputs, epsilon=1e-12, singular_value="left", return_normalized=True, power_iteration_rounds=1): """Performs Spectral Normalization on a weight tensor. Details of why this is helpful for GAN's can be found in "Spectral Normalization for Generative Adversarial Networks", Miyato T. et al., 2018. [https://arxiv.org/abs/1802.05957]. Args: inputs: The weight tensor to normalize. epsilon: Epsilon for L2 normalization. singular_value: Which first singular value to store (left or right). Use "auto" to automatically choose the one that has fewer dimensions. Returns: The normalized weight tensor. """ if len(inputs.shape) < 2: raise ValueError( "Spectral norm can only be applied to multi-dimensional tensors") # The paper says to flatten convnet kernel weights from (C_out, C_in, KH, KW) # to (C_out, C_in * KH * KW). Our Conv2D kernel shape is (KH, KW, C_in, C_out) # so it should be reshaped to (KH * KW * C_in, C_out), and similarly for other # layers that put output channels as last dimension. This implies that w # here is equivalent to w.T in the paper. w = tf.reshape(inputs, (-1, inputs.shape[-1])) # Choose whether to persist the first left or first right singular vector. # As the underlying matrix is PSD, this should be equivalent, but in practice # the shape of the persisted vector is different. Here one can choose whether # to maintain the left or right one, or pick the one which has the smaller # dimension. We use the same variable for the singular vector if we switch # from normal weights to EMA weights. var_name = inputs.name.replace("/ExponentialMovingAverage", "").split("/")[-1] var_name = var_name.split(":")[0] + "/u_var" if singular_value == "auto": singular_value = "left" if w.shape[0] <= w.shape[1] else "right" u_shape = (w.shape[0], 1) if singular_value == "left" else (1, w.shape[-1]) u_var = tf.get_variable( var_name, shape=u_shape, dtype=w.dtype, initializer=tf.random_normal_initializer(), collections=[tf.GraphKeys.LOCAL_VARIABLES], trainable=False, use_resource=True) u = u_var # Use power iteration method to approximate the spectral norm. # The authors suggest that one round of power iteration was sufficient in the # actual experiment to achieve satisfactory performance. for _ in range(power_iteration_rounds): if singular_value == "left": # `v` approximates the first right singular vector of matrix `w`. v = tf.math.l2_normalize( tf.matmul(tf.transpose(w), u), axis=None, epsilon=epsilon) u = tf.math.l2_normalize(tf.matmul(w, v), axis=None, epsilon=epsilon) else: v = tf.math.l2_normalize(tf.matmul(u, w, transpose_b=True), epsilon=epsilon) u = tf.math.l2_normalize(tf.matmul(v, w), epsilon=epsilon) # Update the approximation. with tf.control_dependencies([tf.assign(u_var, u, name="update_u")]): u = tf.identity(u) # The authors of SN-GAN chose to stop gradient propagating through u and v # and we maintain that option. u = tf.stop_gradient(u) v = tf.stop_gradient(v) if singular_value == "left": norm_value = tf.matmul(tf.matmul(tf.transpose(u), w), v) else: norm_value = tf.matmul(tf.matmul(v, w), u, transpose_b=True) norm_value.shape.assert_is_fully_defined() norm_value.shape.assert_is_compatible_with([1, 1]) if return_normalized: w_normalized = w / norm_value # Deflate normalized weights to match the unnormalized tensor. w_tensor_normalized = tf.reshape(w_normalized, inputs.shape) return w_tensor_normalized else: return w, norm_value def graph_name(name): name = name.split(':')[0] name = name.split('/strided_slice_')[0] name = name.split('/Identity_')[0] if name.startswith('D_loss/G/G_synthesis/'): name = name.replace('D_loss/G/G_synthesis/', '') return 'G_' + name elif name.startswith('D_loss/D/'): name = name.replace('D_loss/D/', '') return 'D_' + name def graph_spectral_norm(w): w1, norm = spectral_norm(w, return_normalized=False) value = norm[0][0] name = graph_name(value.name) if name is not None: autosummary('specnorm_' + name, value) else: tf.logging.info('ignoring autosummary(%s, %s)', repr(value.name), repr(value)) if 'USE_SPECNORM' in os.environ: tf.logging.info('Using spectral normalization for %s', repr(w)) w_normalized = w1 / norm w_normalized = tf.reshape(w_normalized, w.shape) return w_normalized return w def graph_images(images, res): value = tf.identity(images) name = graph_name(value.name) if name is not None: autoimages(name, value, res=res) else: tf.logging.info('ignoring autoimages(%s, %s)', repr(name), repr(value)) return images def conv2d(inputs, output_dim, k_h, k_w, d_h, d_w, stddev=0.02, name="conv2d", use_sn=False, use_bias=True): """Performs 2D convolution of the input.""" with tf.variable_scope(name): w = tf.get_variable( "kernel", [k_h, k_w, inputs.shape[-1].value, output_dim], initializer=weight_initializer(stddev=stddev), use_resource=True) if use_sn: w = spectral_norm(w) outputs = tf.nn.conv2d(inputs, w, strides=[1, d_h, d_w, 1], padding="SAME") if use_bias: bias = tf.get_variable( "bias", [output_dim], initializer=tf.constant_initializer(0.0), use_resource=True) outputs += bias return outputs conv1x1 = functools.partial(conv2d, k_h=1, k_w=1, d_h=1, d_w=1) def non_local_block(x, name, use_sn): """Self-attention (non-local) block. This method is used to exactly reproduce SAGAN and ignores Gin settings on weight initialization and spectral normalization. Args: x: Input tensor of shape [batch, h, w, c]. name: Name of the variable scope. use_sn: Apply spectral norm to the weights. Returns: A tensor of the same shape after self-attention was applied. """ def _spatial_flatten(inputs): shape = inputs.shape return tf.reshape(inputs, (-1, shape[1] * shape[2], shape[3])) with tf.variable_scope(name): h, w, num_channels = x.get_shape().as_list()[1:] num_channels_attn = num_channels // 8 num_channels_g = num_channels // 2 # Theta path theta = conv1x1(x, num_channels_attn, name="conv2d_theta", use_sn=use_sn, use_bias=False) theta = _spatial_flatten(theta) # Phi path phi = conv1x1(x, num_channels_attn, name="conv2d_phi", use_sn=use_sn, use_bias=False) phi = tf.layers.max_pooling2d(inputs=phi, pool_size=[2, 2], strides=2) phi = _spatial_flatten(phi) attn = tf.matmul(theta, phi, transpose_b=True) attn = tf.nn.softmax(attn) # G path g = conv1x1(x, num_channels_g, name="conv2d_g", use_sn=use_sn, use_bias=False) g = tf.layers.max_pooling2d(inputs=g, pool_size=[2, 2], strides=2) g = _spatial_flatten(g) attn_g = tf.matmul(attn, g) attn_g = tf.reshape(attn_g, [-1, h, w, num_channels_g]) sigma = tf.get_variable("sigma", [], initializer=tf.zeros_initializer(), use_resource=True) attn_g = conv1x1(attn_g, num_channels, name="conv2d_attn_g", use_sn=use_sn, use_bias=False) return x + sigma * attn_g ================================================ FILE: stylegan2-tpu/training/train_runner.py ================================================ # Copyright 2018 The TensorFlow Authors. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== """Bypass TPUEstimator for ResNet-50 Train.""" from __future__ import absolute_import from __future__ import division from __future__ import print_function import math import threading import time from absl import flags import tensorflow as tf import tflex from tensorflow.contrib import tpu from tensorflow.contrib.tpu.python.tpu import tpu_function from tensorflow.core.protobuf import rewriter_config_pb2 from tensorflow.python.data.util import nest as data_nest from tensorflow.python.framework import graph_io from pprint import pprint FLAGS = flags.FLAGS _INITIAL_LOSS = 1e7 def device_for_tpu_core(task=0, core=0): job_name = FLAGS.tpu_job_name or "tpu_worker" return "/job:%s/task:%d/device:TPU_REPLICATED_CORE:%d" % (job_name, task, core) def wrap_computation_in_while_loop(op_fn, n, parallel_iterations=1): """Wraps the ops generated by `op_fn` in tf.while_loop.""" def computation(i): ops = op_fn() if not isinstance(ops, list): ops = [ops] with tf.control_dependencies(ops): return i + 1 return tf.while_loop( lambda i: tf.less(i, n), computation, [tf.constant(0)], parallel_iterations=parallel_iterations) def tpu_ordinal_fn(shard_index_in_host): """Return the TPU ordinal associated with a shard. Required because the enqueue ops are placed on CPU. Args: shard_index_in_host: the shard index Returns: The ordinal of the TPU device the shard's infeed should be placed on. """ return shard_index_in_host % FLAGS.tpu_cores_per_host class TrainRunner(object): """Remove init overheads in TPU Estimator via direct session.run calls.""" def __init__(self, iterations, train_steps): tf.logging.info("TrainRunner: constructor") self.feature_structure = {} self.loss = None self.infeed_queue = [] self.enqueue_ops = [] self.dataset_initializer = [] self.iterations = iterations self.sess = None self.input_sess = None self.infeed_thread = None if train_steps % iterations != 0: train_steps = iterations * int(math.ceil(train_steps / iterations)) self.train_steps = train_steps self.input_graph = tf.Graph() self.init_graph = tf.Graph() with self.init_graph.as_default(): tpu_init = [tpu.initialize_system()] self.tpu_shutdown = tpu.shutdown_system() self.cluster_resolver = tf.contrib.cluster_resolver.TPUClusterResolver( FLAGS.tpu or FLAGS.master, zone=FLAGS.tpu_zone, project=FLAGS.gcp_project) self.config = tf.ConfigProto(operation_timeout_in_ms=600 * 60 * 1000, graph_options=tf.GraphOptions( rewrite_options=rewriter_config_pb2.RewriterConfig( disable_meta_optimizer=True)), isolate_session_state=True) cluster_spec = self.cluster_resolver.cluster_spec() if cluster_spec: self.config.cluster_def.CopyFrom(cluster_spec.as_cluster_def()) self.init_sess = tflex.Session(self.cluster_resolver.get_master(), config=self.config, graph=self.init_graph) self.init_sess.run(tpu_init) def device_for_host(self, task=0, cpu=0): job_name = FLAGS.tpu_job_name or "tpu_worker" return "/job:%s/task:%d/device:CPU:%d" % (job_name, task, cpu) def build_enqueue_ops(self, input_fn, params, host_id): """Build enqueue operations for the input pipeline in a given host. Args: input_fn: dataset input graph generation function params: input function parameters host_id: host identifier """ iparams = {} iparams["batch_size"] = params["batch_size"] // FLAGS.num_cores iparams["dataset_num_shards"] = FLAGS.num_cores // FLAGS.tpu_cores_per_host def get_enqueue_ops_fn(): """Generate the enqueue ops graph function.""" iparams["dataset_index"] = host_id dataset = input_fn(iparams) iterator = dataset.make_initializable_iterator() self.dataset_initializer.append(iterator.initializer) def enqueue_ops_fn(): """Generate the infeed enqueue ops graph.""" per_host_sharded_inputs = [] control_deps = [] with tf.device(self.device_for_host(task=host_id)): for _ in range(FLAGS.tpu_cores_per_host): with tf.control_dependencies(control_deps): features, labels = iterator.get_next() self.feature_structure["features"] = features self.feature_structure["labels"] = labels flattened_inputs = data_nest.flatten(self.feature_structure) control_deps.extend(flattened_inputs) per_host_sharded_inputs.append(flattened_inputs) infeed = tpu.InfeedQueue( number_of_tuple_elements=len(per_host_sharded_inputs[0])) self.infeed_queue.append(infeed) return infeed.generate_enqueue_ops( per_host_sharded_inputs, tpu_ordinal_function=tpu_ordinal_fn) return enqueue_ops_fn with self.input_graph.as_default(): with tf.device(self.device_for_host(host_id)): self.enqueue_ops.append( wrap_computation_in_while_loop( get_enqueue_ops_fn(), n=self.train_steps, parallel_iterations=1)) def initialize(self, input_fn, model_fn, params): """Build graphs for the TPU device and the input pipelines. Args: input_fn: Dataset input graph generation function model_fn: Model definition function params: Parameters to input and model functions """ tf.logging.info("TrainRunner: initialize method") def infeed_thread_fn(): """Build and infeed session.run calls in a background thread.""" i = 1 while i < FLAGS.num_cores // FLAGS.tpu_cores_per_host: self.build_enqueue_ops(input_fn, params, i) i += 1 # Build infeed sesssion self.input_sess = tflex.Session( self.cluster_resolver.get_master(), graph=self.input_graph, config=self.config) self.input_sess.run(self.dataset_initializer) # Run infeed session.run calls self.input_sess.run([self.enqueue_ops]) self.build_enqueue_ops(input_fn, params, 0) def get_tpu_step(mparams): """Get the TPU graph generation function.""" def tpu_step(loss): """Generate the TPU graph.""" del loss values = self.infeed_queue[0].generate_dequeue_op(tpu_device=0) unflattened_inputs = data_nest.pack_sequence_as(self.feature_structure, values) features = unflattened_inputs["features"] labels = unflattened_inputs["labels"] estimator_spec = model_fn(features, labels, tf.estimator.ModeKeys.TRAIN, mparams) loss, train_op = estimator_spec.loss, estimator_spec.train_op with tf.device(device_for_tpu_core()): with tf.control_dependencies([train_op]): return tf.identity(loss) return tpu_step tpu_step = get_tpu_step(params) @tpu_function.on_device_training_loop def tpu_loop(): return tpu.repeat(self.iterations, tpu_step, [_INITIAL_LOSS]) (self.loss,) = tpu.shard( tpu_loop, inputs=[], num_shards=FLAGS.num_cores, outputs_from_all_shards=False, ) initializer = tf.global_variables_initializer() graph_io.write_graph(tf.Graph().as_graph_def(add_shapes=True), FLAGS.model_dir, "graph.pbtxt") # Build tpu train model session and initialize graph self.sess = tflex.Session( self.cluster_resolver.get_master(), config=self.config) self.sess.run(initializer) self.var_list = [v for v in tf.global_variables() if 'Dataset/' not in v.name] pprint(self.var_list) self.saver = tf.train.Saver( var_list=self.var_list, ) if FLAGS.restore_dir is not None: ckpt = tf.train.latest_checkpoint(FLAGS.restore_dir) assert(ckpt is not None) else: ckpt = tf.train.latest_checkpoint(FLAGS.model_dir) #ckpt = 'gs://danbooru-euw4a/checkpoint/test3/model.ckpt-742400' if ckpt is None: self.cur_ex = 0 tf.logging.info("TrainRunner: Saving initial model...") self.saver.save(self.sess, FLAGS.model_dir + "/model.ckpt-%d" % 0) else: self.cur_ex = int(ckpt.split('-')[-1]) tf.logging.info('TrainRunner: Restoring %s' % ckpt) self.saver.restore(self.sess, ckpt) # Complete infeed graph generation and session.run calls self.infeed_thread = threading.Thread(target=infeed_thread_fn) self.infeed_thread.start() def train(self, num_threads=2): """Run the Train steps on the TPU device. Args: num_threads: number of outstanding checkpointing threads """ def checkpoint_thread_fn(saver, sess): saver.save(sess, FLAGS.model_dir + "/model.ckpt-%d" % (self.cur_ex)) cur_step = 0 thread_id = 0 checkpoint_threads = [] tf.logging.info("TrainRunner: step %d", cur_step) begin = time.time() for i in range(num_threads): checkpoint_threads.append(None) while cur_step < self.train_steps: start = time.time() tf.logging.info("TrainRunner: start next %d steps", self.iterations) cur_step += self.iterations self.cur_ex += self.iterations * FLAGS.train_batch_size loss = self.sess.run([self.loss]) if cur_step % 10 == 0 and cur_step > 0: if checkpoint_threads[thread_id] is not None: tf.logging.info("TrainRunner: waiting for checkpoint thread....") checkpoint_threads[thread_id].join() from pprint import pprint #pprint(self.var_list) #tf.logging.info("TrainRunner: saving checkpoint....") checkpoint_threads[thread_id] = threading.Thread( target=checkpoint_thread_fn, args=(self.saver, self.sess)) checkpoint_threads[thread_id].start() thread_id += 1 if thread_id >= num_threads: thread_id = 0 end = time.time() tf.logging.info( "TrainRunner: step {} kex {:.3f} loss {} step time {:.2f}s total {:.2f}s {:.2f} examples/sec" .format(cur_step, self.cur_ex / 1000.0, loss, end - start, end - begin, self.iterations * FLAGS.train_batch_size / (end - start))) self.infeed_thread.join() for i in range(num_threads): if checkpoint_threads[i] is not None: checkpoint_threads[i].join() checkpoint_threads[i] = None def shutdown(self): self.init_sess.run(self.tpu_shutdown) ================================================ FILE: stylegan2-tpu/training/training_loop.py ================================================ # Copyright (c) 2019, NVIDIA Corporation. All rights reserved. # # This work is made available under the Nvidia Source Code License-NC. # To view a copy of this license, visit # https://nvlabs.github.io/stylegan2/license.html """Main training script.""" import os import numpy as np import tensorflow as tf import tflex import time import dnnlib import dnnlib.tflib as tflib import traceback from dnnlib.tflib.autosummary import autosummary, get_tpu_summary, set_num_replicas from training import dataset from training import misc from metrics import metric_base from pprint import pprint #---------------------------------------------------------------------------- # Just-in-time processing of training images before feeding them to the networks. def process_reals(x, labels, lod, mirror_augment, drange_data, drange_net): with tf.name_scope('DynamicRange'): x = tf.cast(x, tf.float32) x = misc.adjust_dynamic_range(x, drange_data, drange_net) if mirror_augment: with tf.name_scope('MirrorAugment'): x = tf.where(tf.random_uniform([tf.shape(x)[0]]) < 0.5, x, tf.reverse(x, [3])) assert lod == 0.0 if False: with tf.name_scope('FadeLOD'): # Smooth crossfade between consecutive levels-of-detail. s = tf.shape(x) y = tf.reshape(x, [-1, s[1], s[2]//2, 2, s[3]//2, 2]) y = tf.reduce_mean(y, axis=[3, 5], keepdims=True) y = tf.tile(y, [1, 1, 1, 2, 1, 2]) y = tf.reshape(y, [-1, s[1], s[2], s[3]]) x = tflib.lerp(x, y, lod - tf.floor(lod)) with tf.name_scope('UpscaleLOD'): # Upscale to match the expected input/output size of the networks. s = tf.shape(x) factor = tf.cast(2 ** tf.floor(lod), tf.int32) x = tf.reshape(x, [-1, s[1], s[2], 1, s[3], 1]) x = tf.tile(x, [1, 1, 1, factor, 1, factor]) x = tf.reshape(x, [-1, s[1], s[2] * factor, s[3] * factor]) return x, labels #---------------------------------------------------------------------------- # Evaluate time-varying training parameters. def training_schedule( cur_nimg, training_set, lod_initial_resolution = None, # Image resolution used at the beginning. lod_training_kimg = 600, # Thousands of real images to show before doubling the resolution. lod_transition_kimg = 600, # Thousands of real images to show when fading in new layers. minibatch_size_base = 32, # Global minibatch size. minibatch_size_dict = {}, # Resolution-specific overrides. minibatch_gpu_base = 4, # Number of samples processed at a time by one GPU. minibatch_gpu_dict = {}, # Resolution-specific overrides. G_lrate_base = 0.002, # Learning rate for the generator. G_lrate_dict = {}, # Resolution-specific overrides. D_lrate_base = 0.002, # Learning rate for the discriminator. D_lrate_dict = {}, # Resolution-specific overrides. lrate_rampup_kimg = 0, # Duration of learning rate ramp-up. tick_kimg_base = 4, # Default interval of progress snapshots. tick_kimg_dict = {8:28, 16:24, 32:20, 64:16, 128:12, 256:8, 512:6, 1024:4}): # Resolution-specific overrides. # Initialize result dict. s = dnnlib.EasyDict() s.kimg = cur_nimg / 1000.0 # Training phase. phase_dur = lod_training_kimg + lod_transition_kimg phase_idx = int(np.floor(s.kimg / phase_dur)) if phase_dur > 0 else 0 phase_kimg = s.kimg - phase_idx * phase_dur # Level-of-detail and resolution. if lod_initial_resolution is None: s.lod = 0.0 else: s.lod = training_set.resolution_log2 s.lod -= np.floor(np.log2(lod_initial_resolution)) s.lod -= phase_idx if lod_transition_kimg > 0: s.lod -= max(phase_kimg - lod_training_kimg, 0.0) / lod_transition_kimg s.lod = max(s.lod, 0.0) s.resolution = 2 ** (training_set.resolution_log2 - int(np.floor(s.lod))) # Minibatch size. s.minibatch_size = minibatch_size_dict.get(s.resolution, minibatch_size_base) s.minibatch_gpu = minibatch_gpu_dict.get(s.resolution, minibatch_gpu_base) # Learning rate. s.G_lrate = G_lrate_dict.get(s.resolution, G_lrate_base) s.D_lrate = D_lrate_dict.get(s.resolution, D_lrate_base) if lrate_rampup_kimg > 0: rampup = min(s.kimg / lrate_rampup_kimg, 1.0) s.G_lrate *= rampup s.D_lrate *= rampup # Other parameters. s.tick_kimg = tick_kimg_dict.get(s.resolution, tick_kimg_base) return s def get_input_fn(training_set, batch_size): zz = training_set.get_minibatch_np(batch_size) features = zz[0] labels = zz[1] dataset = tf.data.Dataset.from_tensor_slices((features, labels)) def input_fn(params): batch_size = params["batch_size"] #features = {"x": np.ones((8, 3), dtype=np.float32)} #labels = np.ones((8, 1), dtype=np.float32) return dataset.repeat().batch(batch_size, drop_remainder=True) return dataset, input_fn def get_input_fn(training_set): def input_fn(params): import pdb; pdb.set_trace() batch_size = params["batch_size"] features, labels = training_set.get_minibatch_np(batch_size) features = tf.cast(features, dtype=tf.float32) labels = tf.cast(labels, dtype=tf.float32) dataset = tf.data.Dataset.from_tensor_slices((features, labels)) return dataset.repeat().batch(batch_size, drop_remainder=True) return input_fn def set_shapes(batch_size, num_channels, resolution, label_size, images, labels, transpose_input=False): """Statically set the batch_size dimension.""" #import pdb; pdb.set_trace() if transpose_input: #if FLAGS.train_batch_size // FLAGS.num_cores > 8: if True: shape = [resolution, resolution, num_channels, batch_size] else: shape = [resolution, resolution, batch_size, num_channels] images.set_shape(images.get_shape().merge_with(tf.TensorShape(shape))) images = tf.reshape(images, [-1]) labels.set_shape(labels.get_shape().merge_with( tf.TensorShape([batch_size, label_size]))) else: images.set_shape(images.get_shape().merge_with( tf.TensorShape([batch_size, num_channels, resolution, resolution]))) labels.set_shape(labels.get_shape().merge_with( tf.TensorShape([batch_size, label_size]))) return images, labels import functools from tensorflow.python.platform import gfile def tf_randi(*args, **kws): assert len(args) > 0 if len(args) == 1: lo, hi = [0] + [x for x in args] else: lo, hi = args return tf.random.uniform((), minval=lo, maxval=hi, dtype=tf.int32, **kws) def tf_rand(*args, **kws): if len(args) == 0: lo, hi = 0.0, 1.0 elif len(args) == 1: lo, hi = [0] + [x for x in args] else: lo, hi = args return tf.random.uniform((), minval=lo, maxval=hi, **kws) def tf_biased_rand(*args, bias=1, **kws): x = tf_rand(*args, **kws) # simple technique to bias the result towards the center. for i in range(bias - 1): x += tf_rand(*args, **kws) dtype = kws.pop('dtype') if 'dtype' in kws else tf.float32 x = tf.cast(x, tf.float32) / bias x = tf.cast(x, dtype) return x def tf_between(*args, bias=1, **kws): if bias <= 0: return tf_randi(*args, **kws) else: return tf_biased_rand(*args, dtype=tf.int32, bias=bias, **kws) def random_crop(image_bytes, scope=None, resize=None, method=tf.image.ResizeMethod.AREA, seed=None): with tf.name_scope(scope, 'random_crop', [image_bytes]): shape = tf.image.extract_jpeg_shape(image_bytes) w = shape[0] h = shape[1] channels = shape[2] x, y = 0, 0 n = 3 image = tf.cond(w > h, lambda: tf.image.decode_and_crop_jpeg(image_bytes, tf.stack([x + tf_between(w - h, seed=seed), y, h, h]), channels=n), lambda: tf.cond(h > w, lambda: tf.image.decode_and_crop_jpeg(image_bytes, tf.stack( [x, y + tf_between(h - w, seed=seed), w, w]), channels=n), lambda: tf.image.decode_jpeg(image_bytes, channels=n))) if resize: image_size = [resize, resize] if isinstance(resize, int) or isinstance(resize, float) else resize image = tf.image.resize([image], image_size, method=method)[0] return image def _decode_and_center_crop(image_bytes, image_size, crop_padding=0): """Crops to center of image with padding then scales image_size.""" shape = tf.image.extract_jpeg_shape(image_bytes) image_height = shape[0] image_width = shape[1] padded_center_crop_size = tf.cast( ((image_size / (image_size + crop_padding)) * tf.cast(tf.minimum(image_height, image_width), tf.float32)), tf.int32) offset_height = ((image_height - padded_center_crop_size) + 1) // 2 offset_width = ((image_width - padded_center_crop_size) + 1) // 2 crop_window = tf.stack([offset_height, offset_width, padded_center_crop_size, padded_center_crop_size]) image = tf.image.decode_and_crop_jpeg(image_bytes, crop_window, channels=3) image = tf.image.resize_area([image], [image_size, image_size])[0] return image from tensorflow.python.data.experimental.ops import readers from tensorflow.python.data.kernel_tests import test_base from tensorflow.python.data.ops import dataset_ops from tensorflow.python.data.util import nest from tensorflow.python.framework import constant_op from tensorflow.python.framework import dtypes from tensorflow.python.framework import errors from tensorflow.python.framework import test_util from tensorflow.python.platform import test type_map = { 'int32': dtypes.int32, 'int64': dtypes.int64, 'uint32': dtypes.uint32, 'uint64': dtypes.uint64, 'float32': dtypes.float32, 'float64': dtypes.float64, 'string': dtypes.string, 'i32': dtypes.int32, 'i64': dtypes.int64, 'u32': dtypes.uint32, 'u64': dtypes.uint64, 'f32': dtypes.float32, 'f64': dtypes.float64, 's': dtypes.string, } def parse_header(x): if '=' in x: name, kind = x.split('=') return name, constant_op.constant([], type_map[kind]) return x, constant_op.constant([], dtypes.string) def csv_dataset(path, spec=None, **kws): columns = [] if spec is None else [parse_header(x) for x in spec.split(',')] column_names = None if spec is None else [x[0] for x in columns] column_types = None if spec is None else [x[1] for x in columns] return readers.make_csv_dataset(path, batch_size=1, column_names=column_names, column_defaults=column_types, **kws) def imagenet_dataset(path, resize=None, seed=None): print('Using imagenet dataset %s' % path) #dataset = csv_dataset(path, "name,width,height,channels,format,data", header=False, shuffle=False, sloppy=True, num_parallel_reads=16) dataset = readers.make_csv_dataset(path, batch_size=1, column_names="name,width,height,channels,format,data".split(','), column_defaults=[dtypes.string], select_columns=['data'], header=False, shuffle=True, shuffle_seed=seed, sloppy=True, num_parallel_reads=16, ignore_errors=True) def parse_image(x): x = x['data'][0] data = tf.io.decode_base64(x) #img = random_crop(data, resize=resize) img = _decode_and_center_crop(data, resize) img = tf.transpose(img, [2,0,1]) label = tf.constant([]) return img, label dataset = dataset.map(parse_image, num_parallel_calls=tf.data.experimental.AUTOTUNE) return dataset from . import imagenet_input def get_input_fn(load_training_set, num_cores, mirror_augment, drange_net): self = training_set = load_training_set(batch_size=0) def input_fn(params): batch_size = params["batch_size"] #import pdb; pdb.set_trace() #num_channels = tfr_shape[0] #resolution = tfr_shape[1] num_channels = training_set.shape[0] resolution = training_set.shape[1] resolution_log2 = int(np.log2(resolution)) label_size = training_set.label_size def get_tfrecord_files(tfrecord_dir): assert gfile.IsDirectory(tfrecord_dir) tfr_files = sorted(tf.io.gfile.glob(os.path.join(tfrecord_dir, '*-r%02d.tfrecords' % resolution_log2))) assert len(tfr_files) == 1 return tfr_files lod_index = -1 for tfr_file, tfr_shape, tfr_lod in training_set.tfr: if tfr_shape[1] == resolution and tfr_shape[2] == resolution: lod_index = tfr_lod assert lod_index >= 0 #num_cores = batch_size if False: training_set.finalize() label_size = training_set.label_size dset = training_set._tf_datasets[lod_index] dset = dset.batch(batch_size) def dataset_parser_dynamic(features, labels): features, labels = process_reals(features, labels, lod=0.0, mirror_augment=mirror_augment, drange_data=training_set.dynamic_range, drange_net=drange_net) return features, labels if False: dset = dset.apply( tf.contrib.data.map_and_batch( dataset_parser_dynamic, batch_size=batch_size, num_parallel_batches=tf.data.experimental.AUTOTUNE, drop_remainder=True)) else: dset = dset.map( dataset_parser_dynamic, num_parallel_calls=tf.data.experimental.AUTOTUNE) # Assign static batch size dimension dset = dset.map(functools.partial(set_shapes, batch_size, num_channels, resolution, label_size)) return dset elif True: #dset = training_set._tf_datasets[0] #dset = tf.data.TFRecordDataset(tfr_file, compression_type='', buffer_size=buffer_mb << 20) if 'context' in params: current_host = params['context'].current_input_fn_deployment()[1] num_hosts = params['context'].num_hosts else: if 'dataset_index' in params: current_host = params['dataset_index'] num_hosts = params['dataset_num_shards'] else: current_host = 0 num_hosts = 1 set_num_replicas(params["context"].num_replicas if "context" in params else 1) def load_stylegan_tfrecord(tfr_files, to_float=False): dset = tf.data.Dataset.from_tensor_slices(tfr_files) dset = dset.apply(tf.data.experimental.parallel_interleave(tf.data.TFRecordDataset, cycle_length=4, sloppy=True)) if training_set.label_file is not None: training_set._tf_labels_var, training_set._tf_labels_init = tflib.create_var_with_large_initial_value2(training_set._np_labels, name='labels_var', trainable=False) with tf.control_dependencies([training_set._tf_labels_init]): training_set._tf_labels_dataset = tf.data.Dataset.from_tensor_slices(training_set._tf_labels_var) else: training_set._tf_labels_dataset = tf.data.Dataset.from_tensor_slices(training_set._np_labels) dset = dset.map(dataset.TFRecordDataset.parse_tfrecord_tf_float if to_float else dataset.TFRecordDataset.parse_tfrecord_tf, num_parallel_calls=2) dset = tf.data.Dataset.zip((dset, training_set._tf_labels_dataset)) return dset if 'IMAGENET_DATASET' in os.environ: dset = imagenet_dataset(os.environ['IMAGENET_DATASET'], resize=resolution, current_host=current_host, num_hosts=num_hosts) elif 'IMAGENET_TFRECORD_DATASET' in os.environ: if not 'IMAGENET_UNCONDITIONAL' in os.environ: if current_host == 0: print('Setting labels') training_set._np_labels = np.array([[1.0 if i == j else 0.0 for j in range(1000)] for i in range(1000)], dtype=np.float32) #training_set._np_labels = np.array([tflex.sha256label(str(i)) for i in range(1000)], dtype=np.float32) training_set._tf_labels_var, training_set._tf_labels_init = tflib.create_var_with_large_initial_value2( training_set._np_labels, name='labels_var', trainable=False) with tf.control_dependencies([training_set._tf_labels_init]): training_set._tf_labels_dataset = tf.data.Dataset.from_tensor_slices(training_set._tf_labels_var) training_set.label_size = 1000 #training_set.label_size = len(tflex.sha256label(str(0))) # 28 label_size = training_set.label_size num_channels = int(os.environ["NUM_CHANNELS"]) if "NUM_CHANNELS" in os.environ else 3 assert num_channels == 3 or num_channels == 4 path = os.environ['IMAGENET_TFRECORD_DATASET'] ini = imagenet_input.ImageNetInput(path, is_training=True, image_size=resolution, num_cores=num_hosts) iparams = dict(params) iparams['batch_size'] = 1 dset = ini.input_fn(iparams) def parse_image(img, label): img = tf.transpose(img, [0, 3, 1, 2])[0] if 'IMAGENET_UNCONDITIONAL' in os.environ: label = tf.constant([]) if num_channels == 4: r = resolution n = 1 c = tf.reshape(tf.tile(tf.tile(tf.constant(0, dtype=tf.float32), [tf.math.ceil(r / n)])[0:r], [r]), [r, r]) img = tf.concat([img, [c]], axis=0) else: #label = label[0] #label = label[0] #label = tf.gather(training_set._tf_labels_var.initialized_value(), label) if num_channels == 4: r = resolution #n = label_size #tf.size(label) n = 1 c = tf.reshape(tf.tile(tf.tile(label / label_size, [tf.math.ceil(r / n)])[0:r], [r]), [r, r]) img = tf.concat([img, [c]], axis=0) label = tf.one_hot(label[0], 1000) return img, label dset = dset.map(parse_image, num_parallel_calls=tf.data.experimental.AUTOTUNE) print('Using imagenet dataset(s) %s (host %d / %d) channels=%d label_size=%d' % (path, current_host, num_hosts, num_channels, label_size)) if 'STYLEGAN_TFRECORD_DATASET' in os.environ: sgpaths = os.environ['STYLEGAN_TFRECORD_DATASET'] paths = [x.strip() for x in sgpaths.split(',') if len(x.strip()) > 0] for path in paths: tfr_files = get_tfrecord_files(path) dset = dset.concatenate(load_stylegan_tfrecord(tfr_files, to_float=True)) print('Using stylegan dataset(s) %s (host %d / %d) channels=%d label_size=%d' % (sgpaths, current_host, num_hosts, num_channels, label_size)) else: tfr_files = get_tfrecord_files(training_set.tfrecord_dir) dset = load_stylegan_tfrecord(tfr_files) shuffle_mb = 4096 # Shuffle data within specified window (megabytes), 0 = disable shuffling. prefetch_mb = 2048 # Amount of data to prefetch (megabytes), 0 = disable prefetching. tfr_shape = (resolution, resolution, 3) bytes_per_item = np.prod(tfr_shape) * np.dtype(training_set.dtype).itemsize if shuffle_mb > 0: dset = dset.shuffle(((shuffle_mb << 20) - 1) // bytes_per_item + 1) repeat = True if repeat: dset = dset.repeat() if prefetch_mb > 0: dset = dset.prefetch(((prefetch_mb << 20) - 1) // bytes_per_item + 1) dset = dset.batch(batch_size) #dset = tf.data.TFRecordDataset(tfr_file) def dataset_parser_dynamic(features, labels): #features, labels = set_shapes(batch_size, num_channels, resolution, label_size, features, labels) #features, labels = set_shapes(None, num_channels, resolution, label_size, features, labels) features, labels = process_reals(features, labels, lod=0.0, mirror_augment=mirror_augment, drange_data=training_set.dynamic_range, drange_net=drange_net) #features = tf.cast(features, tf.float32) return features, labels #import pdb; pdb.set_trace() if False: dset = dset.apply( tf.contrib.data.map_and_batch( dataset_parser_dynamic, batch_size=batch_size, num_parallel_batches=tf.data.experimental.AUTOTUNE, drop_remainder=True)) else: dset = dset.map( dataset_parser_dynamic, num_parallel_calls=tf.data.experimental.AUTOTUNE) #import pdb; pdb.set_trace() # Assign static batch size dimension dset = dset.map(functools.partial(set_shapes, batch_size, num_channels, resolution, label_size)) #import pdb; pdb.set_trace() # Prefetch overlaps in-feed with training #if self.prefetch_depth_auto_tune: if False: if True: dset = dset.prefetch(tf.contrib.data.AUTOTUNE) else: dset = dset.prefetch(4) else: #training_set.configure(batch_size) features, labels = training_set.get_minibatch_tf() features.set_shape((batch_size, num_channels, resolution, resolution)) labels.set_shape((batch_size, label_size)) features = tf.cast(features, dtype=tf.float32) labels = tf.cast(labels, dtype=tf.float32) dset = tf.data.Dataset.from_tensor_slices((features, labels)) dset = dset.repeat().batch(batch_size, drop_remainder=True) return dset return input_fn, training_set #---------------------------------------------------------------------------- # Main training script. def training_loop( G_args = {}, # Options for generator network. D_args = {}, # Options for discriminator network. G_opt_args = {}, # Options for generator optimizer. D_opt_args = {}, # Options for discriminator optimizer. G_loss_args = {}, # Options for generator loss. D_loss_args = {}, # Options for discriminator loss. dataset_args = {}, # Options for dataset.load_dataset(). sched_args = {}, # Options for train.TrainingSchedule. grid_args = {}, # Options for train.setup_snapshot_image_grid(). metric_arg_list = [], # Options for MetricGroup. tf_config = {}, # Options for tflib.init_tf(). data_dir = None, # Directory to load datasets from. G_smoothing_kimg = 10.0, # Half-life of the running average of generator weights. minibatch_repeats = 4, # Number of minibatches to run before adjusting training parameters. lazy_regularization = False, # Perform regularization as a separate training step? G_reg_interval = 4, # How often the perform regularization for G? Ignored if lazy_regularization=False. D_reg_interval = 16, # How often the perform regularization for D? Ignored if lazy_regularization=False. reset_opt_for_new_lod = True, # Reset optimizer internal state (e.g. Adam moments) when new layers are introduced? total_kimg = 25000, # Total length of the training, measured in thousands of real images. mirror_augment = False, # Enable mirror augment? drange_net = [-1,1], # Dynamic range used when feeding image data to the networks. image_snapshot_ticks = 50, # How often to save image snapshots? None = only save 'reals.png' and 'fakes-init.png'. network_snapshot_ticks = 50, # How often to save network snapshots? None = only save 'networks-final.pkl'. save_tf_graph = False, # Include full TensorFlow computation graph in the tfevents file? save_weight_histograms = False, # Include weight histograms in the tfevents file? resume_pkl = None, # Network pickle to resume training from, None = train from scratch. resume_kimg = 0.0, # Assumed training progress at the beginning. Affects reporting and training schedule. resume_time = 0.0, # Assumed wallclock time at the beginning. Affects reporting. resume_with_new_nets = False): # Construct new networks according to G_args and D_args before resuming training? tf.logging.set_verbosity(tf.logging.INFO) if resume_pkl is None and 'RESUME_PKL' in os.environ: resume_pkl = os.environ['RESUME_PKL'] if resume_kimg <= 0.0 and 'RESUME_KIMG' in os.environ: resume_kimg = float(os.environ['RESUME_KIMG']) if resume_time <= 0.0 and 'RESUME_TIME' in os.environ: resume_time = float(os.environ['RESUME_TIME']) num_gpus = dnnlib.submit_config.num_gpus # Load training set. def load_training_set(**kws): return dataset.load_dataset(data_dir=dnnlib.convert_path(data_dir), verbose=True, **dataset_args, **kws) input_fn, training_set = get_input_fn(load_training_set, num_gpus, mirror_augment=mirror_augment, drange_net=drange_net) def model_fn(features, labels, mode, params): nonlocal G_opt_args, D_opt_args, sched_args, G_reg_interval, D_reg_interval, lazy_regularization, G_smoothing_kimg assert mode == tf.estimator.ModeKeys.TRAIN num_channels = features.shape[1].value resolution = features.shape[2].value label_size = labels.shape[1].value G = tflib.Network('G', num_channels=num_channels, resolution=resolution, label_size=label_size, **G_args) D = tflib.Network('D', num_channels=num_channels, resolution=resolution, label_size=label_size, **D_args) G.print_layers(); D.print_layers() Gs, Gs_finalize = G.clone2('Gs') G_gpu = G D_gpu = D reals_read = features labels_read = labels minibatch_gpu_in = params['batch_size'] G_opt_args = dict(G_opt_args) D_opt_args = dict(D_opt_args) sched_args = dict(sched_args) G_opt = tflib.Optimizer(name='TrainG', cross_shard=True, learning_rate=sched_args['G_lrate_base'], **G_opt_args) D_opt = tflib.Optimizer(name='TrainD', cross_shard=True, learning_rate=sched_args['D_lrate_base'], **D_opt_args) with tf.name_scope('G_loss'): G_loss, G_reg = dnnlib.util.call_func_by_name(G=G_gpu, D=D_gpu, opt=G_opt, training_set=training_set, minibatch_size=minibatch_gpu_in, **G_loss_args) with tf.name_scope('D_loss'): D_loss, D_reg = dnnlib.util.call_func_by_name(G=G_gpu, D=D_gpu, opt=D_opt, training_set=training_set, minibatch_size=minibatch_gpu_in, reals=reals_read, labels=labels_read, **D_loss_args) # Register gradients. G_reg_opt = tflib.Optimizer(name='RegG', share=G_opt, cross_shard=True, learning_rate=sched_args['G_lrate_base'], **G_opt_args) D_reg_opt = tflib.Optimizer(name='RegD', share=D_opt, cross_shard=True, learning_rate=sched_args['D_lrate_base'], **D_opt_args) if not lazy_regularization: G_reg_loss = None D_reg_loss = None if G_reg is not None: G_loss += G_reg if D_reg is not None: D_loss += D_reg else: if G_reg is not None: G_reg_loss = tf.reduce_mean(G_reg * G_reg_interval) if D_reg is not None: D_reg_loss = tf.reduce_mean(D_reg * D_reg_interval) if G_reg is not None: G_reg_opt.register_gradients(G_reg_loss, G_gpu.trainables) if D_reg is not None: D_reg_opt.register_gradients(D_reg_loss, D_gpu.trainables) G_loss_op = tf.reduce_mean(G_loss) D_loss_op = tf.reduce_mean(D_loss) G_opt.register_gradients(G_loss_op, G_gpu.trainables) D_opt.register_gradients(D_loss_op, D_gpu.trainables) inc_global_step = tf.assign_add(tf.train.get_or_create_global_step(), minibatch_gpu_in, name="inc_global_step") G_train_op = G_opt._shared_optimizers[''].minimize(G_loss_op, var_list=G_gpu.trainables) D_train_op = D_opt._shared_optimizers[''].minimize(D_loss_op, var_list=D_gpu.trainables) if lazy_regularization: if False: G_reg_train_op = tf.cond( lambda: tf.cast(tf.mod(tf.train.get_global_step(), G_reg_interval), tf.bool), lambda: G_reg_opt._shared_optimizers[''].minimize(G_reg_loss, var_list=G_gpu.trainables), lambda: tf.no_op()) if G_reg_loss is not None else tf.no_op() D_reg_train_op = tf.cond( lambda: tf.cast(tf.mod(tf.train.get_global_step(), D_reg_interval), tf.bool), lambda: D_reg_opt._shared_optimizers[''].minimize(D_reg_loss, var_list=D_gpu.trainables), lambda: tf.no_op()) if D_reg_loss is not None else tf.no_op() else: assert (G_reg is not None) assert (D_reg is not None) def G_fn(): with tf.control_dependencies([tf.train.get_or_create_global_step()]): G_op = G_reg_opt._shared_optimizers[''].minimize(G_reg_loss, var_list=G_gpu.trainables) return G_op def D_fn(): with tf.control_dependencies([tf.train.get_or_create_global_step()]): D_op = D_reg_opt._shared_optimizers[''].minimize(D_reg_loss, var_list=D_gpu.trainables) return D_op def G_else(): with tf.control_dependencies([tf.train.get_or_create_global_step()]): return tf.no_op() def D_else(): with tf.control_dependencies([tf.train.get_or_create_global_step()]): return tf.no_op() G_reg_train_op = tf.cond(lambda: tf.equal(tf.mod(tf.train.get_or_create_global_step(), G_reg_interval), tf.constant(0, tf.int64)), G_fn, G_else) D_reg_train_op = tf.cond(lambda: tf.equal(tf.mod(tf.train.get_or_create_global_step(), D_reg_interval), tf.constant(0, tf.int64)), D_fn, D_else) else: G_reg_train_op = G_reg_opt._shared_optimizers[''].minimize(G_reg_loss, var_list=G_gpu.trainables) if G_reg_loss is not None else tf.no_op() D_reg_train_op = D_reg_opt._shared_optimizers[''].minimize(D_reg_loss, var_list=D_gpu.trainables) if D_reg_loss is not None else tf.no_op() minibatch_size_in = batch_size Gs_beta = 0.5 ** tf.div(tf.cast(minibatch_size_in, tf.float32), G_smoothing_kimg * 1000.0) if G_smoothing_kimg > 0.0 else 0.0 Gs_update_op = Gs.setup_as_moving_average_of(G, beta=Gs_beta) loss = G_loss_op + D_loss_op if G_reg_loss is not None: loss += G_reg_loss if D_reg_loss is not None: loss += D_reg_loss with tf.control_dependencies([inc_global_step]): with tf.control_dependencies([G_train_op]): with tf.control_dependencies([G_reg_train_op]): with tf.control_dependencies([D_train_op]): with tf.control_dependencies([D_reg_train_op]): with tf.control_dependencies(tf.get_collection(tf.GraphKeys.UPDATE_OPS)): train_op = tf.group(Gs_update_op, name='train_op') return tf.contrib.tpu.TPUEstimatorSpec( mode=mode, host_call = get_tpu_summary().get_host_call(), loss=loss, train_op=train_op) use_tpu = True training_steps = 2048*20480 batch_size = sched_args.minibatch_size_base pprint(sched_args) model_dir=os.environ['MODEL_DIR'] if 'MODEL_DIR' in os.environ else 'gs://danbooru-euw4a/test/run30/' tpu_cluster_resolver = tflex.get_tpu_resolver() run_config = tf.contrib.tpu.RunConfig( model_dir=model_dir, #save_checkpoints_steps=100, save_checkpoints_secs=600//5, keep_checkpoint_max=10, keep_checkpoint_every_n_hours=1, cluster=tpu_cluster_resolver, tpu_config=tf.contrib.tpu.TPUConfig(iterations_per_loop=256)) # Uncomment for warmstarting from checkpoint # ws = tf.estimator.WarmStartSettings( # ckpt_to_initialize_from="gs://tpu-mamm/warmstart", # vars_to_warm_start=".*") estimator = tf.contrib.tpu.TPUEstimator( config=run_config, use_tpu=use_tpu, model_fn=model_fn, train_batch_size=batch_size, # warm_start_from=ws ) print('Training...') estimator.train(input_fn, steps=training_steps) import pdb; pdb.set_trace() grid_size, grid_reals, grid_labels = misc.setup_snapshot_image_grid(training_set, **grid_args) misc.save_image_grid(grid_reals, dnnlib.make_run_dir_path('reals.png'), drange=training_set.dynamic_range, grid_size=grid_size) # Construct or load networks. with tflex.device('/gpu:0'): if resume_pkl is None or resume_with_new_nets: print('Constructing networks...') G = tflib.Network('G', num_channels=training_set.shape[0], resolution=training_set.shape[1], label_size=training_set.label_size, **G_args) D = tflib.Network('D', num_channels=training_set.shape[0], resolution=training_set.shape[1], label_size=training_set.label_size, **D_args) Gs = G.clone('Gs') if resume_pkl is not None: print('Loading networks from "%s"...' % resume_pkl) rG, rD, rGs = misc.load_pkl(resume_pkl) if resume_with_new_nets: G.copy_vars_from(rG); D.copy_vars_from(rD); Gs.copy_vars_from(rGs) else: G = rG; D = rD; Gs = rGs # Print layers and generate initial image snapshot. G.print_layers(); D.print_layers() sched = training_schedule(cur_nimg=total_kimg*1000, training_set=training_set, **sched_args) grid_latents = np.random.randn(np.prod(grid_size), *G.input_shape[1:]) #grid_fakes = Gs.run(grid_latents, grid_labels, is_validation=True, randomize_noise=False, minibatch_size=sched.minibatch_gpu) #misc.save_image_grid(grid_fakes, dnnlib.make_run_dir_path('fakes_init.png'), drange=drange_net, grid_size=grid_size) def save_image_grid(latents, grid_size, filename): grid_fakes = Gs.run(latents, grid_labels, is_validation=True, randomize_noise=False, minibatch_size=sched.minibatch_gpu) misc.save_image_grid(grid_fakes, filename, drange=drange_net, grid_size=grid_size) tflex.save_image_grid = save_image_grid def save_image_grid_command(randomize=False): if randomize: tflex.latents = np.random.randn(np.prod(grid_size), *G.input_shape[1:]) if not hasattr(tflex, 'latents'): tflex.latents = grid_latents if randomize or not hasattr(tflex, 'grid_filename'): tflex.grid_filename = dnnlib.make_run_dir_path('grid%06d.png' % int(time.time())) use_grid_size = (2, 2) latents = tflex.latents[:np.prod(use_grid_size)] tflex.save_image_grid(latents, use_grid_size, tflex.grid_filename) print('Saved ' + tflex.grid_filename) tflex.save_image_grid_command = save_image_grid_command @tflex.register_command def image_grid(): tflex.save_image_grid_command(randomize=True) @tflex.register_command def resave_image_grid(): tflex.save_image_grid_command(randomize=False) # Setup training inputs. print('Building TensorFlow graph...') with tf.name_scope('Inputs'), tflex.device('/cpu:0'): lod_in = tf.placeholder(tf.float32, name='lod_in', shape=[]) lrate_in = tf.placeholder(tf.float32, name='lrate_in', shape=[]) minibatch_size_in = tf.placeholder(tf.int32, name='minibatch_size_in', shape=[]) minibatch_gpu_in = tf.placeholder(tf.int32, name='minibatch_gpu_in', shape=[]) minibatch_multiplier = minibatch_size_in // (minibatch_gpu_in * num_gpus) Gs_beta = 0.5 ** tf.div(tf.cast(minibatch_size_in, tf.float32), G_smoothing_kimg * 1000.0) if G_smoothing_kimg > 0.0 else 0.0 # Setup optimizers. G_opt_args = dict(G_opt_args) D_opt_args = dict(D_opt_args) for args, reg_interval in [(G_opt_args, G_reg_interval), (D_opt_args, D_reg_interval)]: args['minibatch_multiplier'] = minibatch_multiplier args['learning_rate'] = lrate_in if lazy_regularization: mb_ratio = reg_interval / (reg_interval + 1) args['learning_rate'] *= mb_ratio if 'beta1' in args: args['beta1'] **= mb_ratio if 'beta2' in args: args['beta2'] **= mb_ratio G_opt = tflib.Optimizer(name='TrainG', **G_opt_args) D_opt = tflib.Optimizer(name='TrainD', **D_opt_args) G_reg_opt = tflib.Optimizer(name='RegG', share=G_opt, **G_opt_args) D_reg_opt = tflib.Optimizer(name='RegD', share=D_opt, **D_opt_args) # Build training graph for each GPU. data_fetch_ops = [] shards = {} def get_shard(i): with tflex.lock: if i not in shards: shards[i] = dnnlib.EasyDict() return shards[i] def make_generator(gpu): me = get_shard(gpu) prev = None if gpu <= 0 else get_shard(gpu - 1) with tf.name_scope('GPU%d' % gpu), tflex.device('/gpu:%d' % gpu): # Create GPU-specific shadow copies of G and D. G_gpu, G_final = (G, None) if gpu == 0 else G.clone2(G.name + '_shadow') D_gpu, D_final = (D, None) if gpu == 0 else D.clone2(D.name + '_shadow') with tflex.lock: me.G = G_gpu me.D = D_gpu me.G_final = tflex.defer(G_final, dependencies=[prev.G_final] if prev else []) me.D_final = tflex.defer(D_final, dependencies=[prev.D_final] if prev else []) print('Making generators...') tflex.parallelize_verbose("Generator", range(num_gpus), make_generator, synchronous=True) if False: print('Finalizing clones...') def make_shadow(gpu): me = get_shard(gpu) me.G_final.join() me.D_final.join() tflex.parallelize_verbose("Finalize clone", range(num_gpus), make_shadow, synchronous=False) def make_shard(gpu): nonlocal data_fetch_ops me = get_shard(gpu) with tf.name_scope('GPU%d' % gpu), tflex.device('/gpu:%d' % gpu): # Create GPU-specific shadow copies of G and D. #G_gpu = G if gpu == 0 else G.clone(G.name + '_shadow') #D_gpu = D if gpu == 0 else D.clone(D.name + '_shadow') G_gpu = me.G D_gpu = me.D me.G_final.join() me.D_final.join() tflex.break_next_run = (gpu > 0) # Fetch training data via temporary variables. with tf.name_scope('DataFetch'): sched = training_schedule(cur_nimg=int(resume_kimg*1000), training_set=training_set, **sched_args) reals_var = tf.Variable(name='reals', trainable=False, initial_value=tf.zeros([sched.minibatch_gpu] + training_set.shape)) labels_var = tf.Variable(name='labels', trainable=False, initial_value=tf.zeros([sched.minibatch_gpu, training_set.label_size])) reals_write, labels_write = training_set.get_minibatch_tf() reals_write, labels_write = process_reals(reals_write, labels_write, lod_in, mirror_augment, training_set.dynamic_range, drange_net) reals_write = tf.concat([reals_write, reals_var[minibatch_gpu_in:]], axis=0) labels_write = tf.concat([labels_write, labels_var[minibatch_gpu_in:]], axis=0) data_fetch_ops += [tf.group(tf.assign(reals_var, reals_write), name="fetch_reals")] data_fetch_ops += [tf.group(tf.assign(labels_var, labels_write), name="fetch_labels")] reals_read = reals_var[:minibatch_gpu_in] labels_read = labels_var[:minibatch_gpu_in] # Evaluate loss functions. lod_assign_ops = [] if 'lod' in G_gpu.vars: lod_assign_ops += [tf.assign(G_gpu.vars['lod'], lod_in)] if 'lod' in D_gpu.vars: lod_assign_ops += [tf.assign(D_gpu.vars['lod'], lod_in)] with tf.control_dependencies(lod_assign_ops): with tf.name_scope('G_loss'): G_loss, G_reg = dnnlib.util.call_func_by_name(G=G_gpu, D=D_gpu, opt=G_opt, training_set=training_set, minibatch_size=minibatch_gpu_in, **G_loss_args) with tf.name_scope('D_loss'): D_loss, D_reg = dnnlib.util.call_func_by_name(G=G_gpu, D=D_gpu, opt=D_opt, training_set=training_set, minibatch_size=minibatch_gpu_in, reals=reals_read, labels=labels_read, **D_loss_args) # Register gradients. if not lazy_regularization: if G_reg is not None: G_loss += G_reg if D_reg is not None: D_loss += D_reg else: if G_reg is not None: G_reg_opt.register_gradients(tf.reduce_mean(G_reg * G_reg_interval), G_gpu.trainables) if D_reg is not None: D_reg_opt.register_gradients(tf.reduce_mean(D_reg * D_reg_interval), D_gpu.trainables) G_opt.register_gradients(tf.reduce_mean(G_loss), G_gpu.trainables) D_opt.register_gradients(tf.reduce_mean(D_loss), D_gpu.trainables) print('Making shards...') tflex.parallelize_verbose("Shard", range(num_gpus), make_shard, synchronous=True) # Setup training ops. data_fetch_op = tf.group(*data_fetch_ops) G_train_op, G_finalize = G_opt.apply_updates() D_train_op, D_finalize = D_opt.apply_updates() G_reg_op, G_reg_finalize = G_reg_opt.apply_updates(allow_no_op=True) D_reg_op, D_reg_finalize = D_reg_opt.apply_updates(allow_no_op=True) Gs_update_op = Gs.setup_as_moving_average_of(G, beta=Gs_beta) tflex.parallelize_verbose("initialize optimizers", [G_finalize, D_finalize, G_reg_finalize, D_reg_finalize], lambda f: f()) # Finalize graph. if tflex.has_gpu(): with tflex.device('/gpu:0'): try: peak_gpu_mem_op = tf.contrib.memory_stats.MaxBytesInUse() except tf.errors.NotFoundError: peak_gpu_mem_op = tf.constant(0) else: peak_gpu_mem_op = None tflib.init_uninitialized_vars() print('Initializing logs...') summary_log = tf.summary.FileWriter(dnnlib.make_run_dir_path()) if save_tf_graph: summary_log.add_graph(tf.get_default_graph()) if save_weight_histograms: G.setup_weight_histograms(); D.setup_weight_histograms() metrics = metric_base.MetricGroup(metric_arg_list) print('Training for %d kimg...\n' % total_kimg) dnnlib.RunContext.get().update('', cur_epoch=resume_kimg, max_epoch=total_kimg) maintenance_time = dnnlib.RunContext.get().get_last_update_interval() cur_nimg = int(resume_kimg * 1000) cur_tick = -1 tick_start_nimg = cur_nimg prev_lod = -1.0 running_mb_counter = 0 need_warmup = True while cur_nimg < total_kimg * 1000: if tflex.state.noisy: print('cur_nimg', cur_nimg, total_kimg) if dnnlib.RunContext.get().should_stop(): break # Choose training parameters and configure training ops. sched = training_schedule(cur_nimg=cur_nimg, training_set=training_set, **sched_args) assert sched.minibatch_size % (sched.minibatch_gpu * num_gpus) == 0 training_set.configure(sched.minibatch_gpu, sched.lod) if reset_opt_for_new_lod: if np.floor(sched.lod) != np.floor(prev_lod) or np.ceil(sched.lod) != np.ceil(prev_lod): G_opt.reset_optimizer_state(); D_opt.reset_optimizer_state() prev_lod = sched.lod # Run training ops. feed_dict = {lod_in: sched.lod, lrate_in: sched.G_lrate, minibatch_size_in: sched.minibatch_size, minibatch_gpu_in: sched.minibatch_gpu} if need_warmup: i = 0 all_ops = [[G_train_op, data_fetch_op], [G_reg_op], [D_train_op, Gs_update_op], [D_reg_op]] for ops in all_ops: tflex.parallelize_verbose("warmup %d / %d" % (i, len(all_ops)), ops, lambda op: tflib.run(op, feed_dict)) i += 1 need_warmup = False for _repeat in range(minibatch_repeats): if tflex.state.noisy: print('_repeat', _repeat) rounds = range(0, sched.minibatch_size, sched.minibatch_gpu * num_gpus) run_G_reg = (lazy_regularization and running_mb_counter % G_reg_interval == 0) run_D_reg = (lazy_regularization and running_mb_counter % D_reg_interval == 0) cur_nimg += sched.minibatch_size running_mb_counter += 1 # Fast path without gradient accumulation. if len(rounds) == 1: if tflex.state.noisy: print('G_train_op', 'fast path') #tflib.run([G_train_op, data_fetch_op], feed_dict) tflib.run(G_train_op, feed_dict) tflib.run(data_fetch_op, feed_dict) if run_G_reg: tflib.run(G_reg_op, feed_dict) if tflex.state.noisy: print('D_train_op', 'fast path') #tflib.run([D_train_op, Gs_update_op], feed_dict) tflib.run(D_train_op, feed_dict) tflib.run(Gs_update_op, feed_dict) if run_D_reg: tflib.run(D_reg_op, feed_dict) # Slow path with gradient accumulation. else: for _round in rounds: if tflex.state.noisy: print('G_train_op', 'slow path') tflib.run(G_train_op, feed_dict) if run_G_reg: for _round in rounds: if tflex.state.noisy: print('G_reg_op', 'slow path') tflib.run(G_reg_op, feed_dict) if tflex.state.noisy: print('G_update_op', 'slow path') tflib.run(Gs_update_op, feed_dict) for _round in rounds: if tflex.state.noisy: print('data_fetch_op', 'slow path') tflib.run(data_fetch_op, feed_dict) if tflex.state.noisy: print('D_train_op', 'slow path') tflib.run(D_train_op, feed_dict) if run_D_reg: for _round in rounds: if tflex.state.noisy: print('D_reg_op', 'slow path') tflib.run(D_reg_op, feed_dict) # Perform maintenance tasks once per tick. done = (cur_nimg >= total_kimg * 1000) if cur_tick < 0 or cur_nimg >= tick_start_nimg + sched.tick_kimg * 1000 or done: cur_tick += 1 tick_kimg = (cur_nimg - tick_start_nimg) / 1000.0 tick_time = dnnlib.RunContext.get().get_time_since_last_update() def report_progress_command(): total_time = dnnlib.RunContext.get().get_time_since_start() + resume_time tick_kimg = (cur_nimg - tick_start_nimg) / 1000.0 tick_time = dnnlib.RunContext.get().get_time_since_last_update() print('tick %-5d kimg %-8.1f lod %-5.2f minibatch %-4d time %-12s sec/tick %-7.1f sec/kimg %-7.2f maintenance %-6.1f gpumem %.1f' % ( autosummary('Progress/tick', cur_tick), autosummary('Progress/kimg', cur_nimg / 1000.0), autosummary('Progress/lod', sched.lod), autosummary('Progress/minibatch', sched.minibatch_size), dnnlib.util.format_time(autosummary('Timing/total_sec', total_time)), autosummary('Timing/sec_per_tick', tick_time), autosummary('Timing/sec_per_kimg', tick_time / tick_kimg), autosummary('Timing/maintenance_sec', maintenance_time), autosummary('Resources/peak_gpu_mem_gb', (peak_gpu_mem_op.eval() if peak_gpu_mem_op is not None else 0) / 2**30))) autosummary('Timing/total_hours', total_time / (60.0 * 60.0)) autosummary('Timing/total_days', total_time / (24.0 * 60.0 * 60.0)) if not hasattr(tflex, 'report_progress_command'): tflex.report_progress_command = report_progress_command @tflex.register_command def report_progress(): tflex.report_progress_command() def save_command(): pkl = dnnlib.make_run_dir_path('network-snapshot-%06d.pkl' % (cur_nimg // 1000)) misc.save_pkl((G, D, Gs), pkl) metrics.run(pkl, run_dir=dnnlib.make_run_dir_path(), data_dir=dnnlib.convert_path(data_dir), num_gpus=num_gpus, tf_config=tf_config) if not hasattr(tflex, 'save_command'): tflex.save_command = save_command @tflex.register_command def save(): tflex.save_command() try: # Report progress. tflex.report_progress_command() tick_start_nimg = cur_nimg # Save snapshots. if image_snapshot_ticks is not None and (cur_tick % image_snapshot_ticks == 0 or done): def thunk(_): grid_fakes = Gs.run(grid_latents, grid_labels, is_validation=True, randomize_noise=False, minibatch_size=sched.minibatch_gpu) misc.save_image_grid(grid_fakes, dnnlib.make_run_dir_path('fakes%06d.png' % (cur_nimg // 1000)), drange=drange_net, grid_size=grid_size) tflex.parallelize([0], thunk) if network_snapshot_ticks is not None and cur_tick > 0 and (cur_tick % network_snapshot_ticks == 0 or done): def thunk(_): tflex.save_command() tflex.parallelize([0], thunk) # Update summaries and RunContext. metrics.update_autosummaries() tflib.autosummary.save_summaries(summary_log, cur_nimg) dnnlib.RunContext.get().update('%.2f' % sched.lod, cur_epoch=cur_nimg // 1000, max_epoch=total_kimg) maintenance_time = dnnlib.RunContext.get().get_last_update_interval() - tick_time except: traceback.print_exc() # Save final snapshot. misc.save_pkl((G, D, Gs), dnnlib.make_run_dir_path('network-final.pkl')) # All done. summary_log.close() training_set.close() #---------------------------------------------------------------------------- ================================================ FILE: stylegan2-tpu/view.py ================================================ import os if 'COLAB_TPU_ADDR' in os.environ: os.environ['TPU_NAME'] = 'grpc://' + os.environ['COLAB_TPU_ADDR'] os.environ['NOISY'] = '1' # --- set resolution and label size here: label_size = int(os.environ['LABEL_SIZE']) resolution = int(os.environ['RESOLUTION']) fmap_base = (int(os.environ['FMAP_BASE']) if 'FMAP_BASE' in os.environ else 16) << 10 num_channels = int(os.environ['NUM_CHANNELS']) model_dir = os.environ['MODEL_DIR'] channel = os.environ['CHANNEL'] if 'CHANNEL' in os.environ else 'chaos' count = int(os.environ['COUNT']) if 'COUNT' in os.environ else 1 discord_token = os.environ['DISCORD_TOKEN'] grid_image_size = int(os.environ['GRID_SIZE']) if 'GRID_SIZE' in os.environ else 9 # ------------------------ import tqdm from pprint import pprint as pp from training.networks_stylegan2 import * from training import misc import dnnlib from dnnlib import EasyDict import tensorflow as tf import tflex import os import numpy as np dnnlib.tflib.init_tf() sess = tf.get_default_session() sess.list_devices() cores = tflex.get_cores() tflex.set_override_cores(cores) #synthesis_func = 'G_synthesis_stylegan2' #kwargs = {'resolution': 512} #synthesis = tflib.Network('G_synthesis', func_name=globals()[synthesis_func], **kwargs) #sess.reset(os.environ['TPU_NAME']) # don't do this, this breaks the session train = EasyDict(run_func_name='training.training_loop.training_loop') # Options for training loop. G_args = EasyDict(func_name='training.networks_stylegan2.G_main') # Options for generator network. D_args = EasyDict(func_name='training.networks_stylegan2.D_stylegan2') # Options for discriminator network. G_opt = EasyDict(beta1=0.0, beta2=0.99, epsilon=1e-8) # Options for generator optimizer. D_opt = EasyDict(beta1=0.0, beta2=0.99, epsilon=1e-8) # Options for discriminator optimizer. G_loss = EasyDict(func_name='training.loss.G_logistic_ns_pathreg') # Options for generator loss. D_loss = EasyDict(func_name='training.loss.D_logistic_r1') # Options for discriminator loss. sched = EasyDict() # Options for TrainingSchedule. grid = EasyDict(size='8k', layout='random') # Options for setup_snapshot_image_grid(). sc = dnnlib.SubmitConfig() # Options for dnnlib.submit_run(). tf_config = {'rnd.np_random_seed': 1000} label_dtype = np.int64 sched.minibatch_gpu = 1 if 'G' not in globals(): with tflex.device('/gpu:0'): G = tflib.Network('G', num_channels=num_channels, resolution=resolution, label_size=label_size, fmap_base=fmap_base, **G_args) G.print_layers() Gs, Gs_finalize = G.clone2('Gs') Gs_finalize() D = tflib.Network('D', num_channels=num_channels, resolution=resolution, label_size=label_size, fmap_base=fmap_base, **D_args) D.print_layers() def rand_latent(n, seed=None): if seed is not None: if seed < 0: seed = 2*32 - seed np.random.seed(seed) result = np.random.randn(n, *G.input_shape[1:]) if seed is not None: np.random.seed() return result grid_size = (2, 2) gw, gh = grid_size gn = np.prod(grid_size) grid_latents = rand_latent(gn, seed=-1) grid_labels = np.zeros([gw * gh, label_size], dtype=label_dtype) def tfinit(): tflib.run(tf.global_variables_initializer()) tfinit() saver = tf.train.Saver() def load_checkpoint(path): ckpt = tf.train.latest_checkpoint(path) assert ckpt is not None print('Loading checkpoint ' + ckpt) saver.restore(sess, ckpt) return ckpt tflex.state.noisy = False # https://stackoverflow.com/a/18284900/9919772 try: from StringIO import StringIO as BytesIO ## for Python 2 except ImportError: from io import BytesIO ## for Python 3 #import IPython.display import numpy as np def get_grid_size(n): gw = 1 gh = 1 i = 0 while gw*gh < n: if i % 2 == 0: gw += 1 else: gh += 1 i += 1 return (gw, gh) def gen_images(latents, outfile=None, display=False, labels=None, randomize_noise=False, is_validation=True, network=None, numpy=False): if network is None: network = Gs n = latents.shape[0] grid_size = get_grid_size(n) drange_net = [-1, 1] with tflex.device('/gpu:0'): result = network.run(latents, labels, is_validation=is_validation, randomize_noise=randomize_noise, minibatch_size=sched.minibatch_gpu) #if result.shape[1] > 3: # final = result[:, 3, :, :] #else: # final = None result = result[:, 0:3, :, :] img = misc.convert_to_pil_image(misc.create_image_grid(result, grid_size), drange_net) if outfile is not None: img.save(outfile) if display: f = BytesIO() img.save(f, 'png') IPython.display.display(IPython.display.Image(data=f.getvalue())) return result if numpy else img def grab(name, postfix, i, n=1, latents=None, **kwargs): load_checkpoint('checkpoint/'+name) if latents is None: latents = rand_latent(n, seed=i) gw, gh = get_grid_size(latents.shape[0]) outfile = 'checkpoint/%s_fakes_%dx%d_%04d_%s.png' % (name, gw, gh, i, postfix) if not os.path.isfile(outfile): return gen_images(latents, outfile=outfile, **kwargs) def grab_grid(i, n=1, latents=None, outfile=None, **kwargs): if latents is None: latents = rand_latent(n, seed=i) gw, gh = get_grid_size(latents.shape[0]) #outfile = 'checkpoint/%s_fakes_%dx%d_%04d_%s.png' % (name, gw, gh, i, postfix) return gen_images(latents, outfile=outfile, **kwargs) import discord import asyncio def post_picture(channel_name, image, text=None, name='test', kind='png'): asyncio.set_event_loop(asyncio.new_event_loop()) loop = asyncio.get_event_loop() client = discord.Client() token=discord_token async def send_picture(channel, image, kind='png', name='test', text=None): img = misc.convert_to_pil_image(image, [-1, 1]) f = BytesIO() img.save(f, kind) f.seek(0) picture = discord.File(f) picture.filename = name + '.' + kind await channel.send(content=text, file=picture) @client.event async def on_ready(): print('Logged on as {0}!'.format(client.user)) try: channel = [x for x in list(client.get_all_channels()) if channel_name in x.name] assert len(channel) == 1 channel = channel[0] print(channel) await send_picture(channel, image, kind=kind, name=name, text=text) finally: await client.logout() #@client.event #async def on_message(message): # print('Message from {0.author}: {0.content}'.format(message)) client.run(token) all_labels = np.array([[1.0 if i == j else 0.0 for j in range(1000)] for i in range(1000)], dtype=np.float32) n = grid_image_size labels = [all_labels[i] for i in range(n)] labels2 = [all_labels[0] for i in range(n)] for ckpt in tf.train.checkpoints_iterator(model_dir, 1.0): print('posting ' + ckpt) saver.restore(sess, ckpt) seed = np.random.randint(10000) for i in range(seed,seed + count): print('------- %d -------' % i) result = grab_grid(i, n=n, labels=labels, numpy=True) post_picture(channel, misc.create_image_grid(result, get_grid_size(n)), "`" + ckpt + ' seed %d`' % i)