├── README.md ├── evaluation.py ├── generate_emb.py ├── glove_generate.py ├── main.py ├── main_multiclass.py ├── model.py ├── plots ├── convergence_compare │ ├── Convergence_compare_plot.ipynb │ ├── convergence_compare.npz │ ├── filter_size.pdf │ ├── filter_size_compare.ipynb │ └── yahoo_iteration.pdf ├── correlation │ ├── Covariance_matrix_yahoo.pdf │ ├── Covariance_matrix_yahoo_label.pdf │ ├── covariance.npy │ ├── paper_plot_covariance_yahoo.ipynb │ ├── yahoo_legend.pdf │ ├── yahoo_tsne.pdf │ └── yahoo_tsne2.pdf ├── schemes │ ├── scheme_a.pdf │ ├── scheme_a.png │ ├── scheme_b.pdf │ └── scheme_b.png ├── text_attention │ ├── attention plot.ipynb │ └── yahoo_examples_1.npz └── yahoo_partial │ ├── SWEN_plot.ipynb │ └── yahoo_partial.pdf ├── preprocess_yahoo.py └── utils.py /README.md: -------------------------------------------------------------------------------- 1 | # LEAM 2 | This repository contains source code necessary to reproduce the results presented in the paper [Joint Embedding of Words and Labels for Text Classification](https://arxiv.org/pdf/1805.04174.pdf) (ACL 2018): 3 | 4 | ``` 5 | @inproceedings{wang_id_2018_ACL, 6 | title={Joint Embedding of Words and Labels for Text Classification}, 7 | author={Guoyin Wang, Chunyuan Li, Wenlin Wang, Yizhe Zhang, Dinghan Shen, Xinyuan Zhang, Ricardo Henao, Lawrence Carin}, 8 | booktitle={ACL}, 9 | year={2018} 10 | } 11 | ``` 12 | 13 | 14 | 15 | Comparison Illustration of proposed **LEAM** with traditional methods for text sequence representations 16 | 17 | Traditional Method           | LEAM: Label Embedding Attentive Model 18 | :-------------------------:|:-------------------------: 19 | ![](/plots/schemes/scheme_a.png) | ![](/plots/schemes/scheme_b.png) 20 | Directly aggregating word embedding **V** for text sequence representation **z** | We leverage the “compatibility” **G** between embedded words **V** and labels **C** to derive the attention score **β** for improved **z**. 21 | 22 | 23 | 24 | 25 | ## Contents 26 | There are four steps to use this codebase to reproduce the results in the paper. 27 | 28 | 1. [Dependencies](#dependencies) 29 | 2. [Prepare datasets](#prepare-datasets) 30 | 3. [Training](#training) 31 | 1. Training on standard dataset 32 | 2. Training on your own dataset 33 | 4. [Reproduce paper figure results](#reproduce-paper-figure-results) 34 | 35 | ## Dependencies 36 | 37 | This code is based on Python 2.7, with the main dependencies being [TensorFlow==1.7.0](https://www.tensorflow.org/) and [Keras==2.1.5](https://keras.io/). Additional dependencies for running experiments are: `numpy`, `cPickle`, `scipy`, `math`, `gensim`. 38 | 39 | ## Prepare datasets 40 | 41 | We consider the following datasets: Yahoo, AGnews, DBPedia, yelp, yelp binary. For convenience, we provide pre-processed versions of all datasets. Data are prepared in pickle format. Each `.p` file has the same fields in same order: `train text`, `val text`, `test text`, `train label`, `val label`, `test label`, `dictionary` and `reverse dictionary`. 42 | 43 | Datasets can be downloaded [here](https://drive.google.com/open?id=1QmZfoKSgZl8UMN8XenAYqHaRzbW5QA26). Put the download data in data directory. Each dataset has two files: tokenized data and corresponding pretrained Glove embedding. 44 | 45 | To run your own dataset, please follow the code in `preprocess_yahoo.py` to tokenize and split train/dev/test datsset. To build pretrained word embeddings, first download [Glove word embeddings](https://nlp.stanford.edu/projects/glove/) and then follow `glove_generate.py`. 46 | 47 | ## Training 48 | **1. Training on standard dataset** 49 | 50 | To run the test, use the command `python -u main.py`. The default test is on Yahoo dataset. To run other default datasets, change the [`Option class`] attribute dataset to corresponding dataset name. Most the parameters are defined in the [`Option class`](./main.py) part. 51 | 52 | ## Reproduce paper figure results 53 | Jupyter notebooks in [`plots`](./plots) folders are used to reproduce paper figure results. 54 | 55 | Note that without modification, we have copyed our extracted results into the notebook, and script will output figures in the paper. If you've run your own training and wish to plot results, you'll have to organize your results in the same format instead. 56 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /evaluation.py: -------------------------------------------------------------------------------- 1 | from collections import defaultdict 2 | import csv 3 | import json 4 | import numpy as np 5 | import os 6 | import sys 7 | 8 | from sklearn.metrics import roc_curve, auc 9 | from tqdm import tqdm 10 | import pdb 11 | 12 | def intersect_size(yhat, y, axis): 13 | #axis=0 for label-level union (macro). axis=1 for instance-level 14 | return np.logical_and(yhat, y).sum(axis=axis).astype(float) 15 | def macro_precision(yhat, y): 16 | num = intersect_size(yhat, y, 0) / (yhat.sum(axis=0) + 1e-10) 17 | return np.mean(num) 18 | 19 | def macro_recall(yhat, y): 20 | num = intersect_size(yhat, y, 0) / (y.sum(axis=0) + 1e-10) 21 | return np.mean(num) 22 | def macro_f1(yhat, y): 23 | prec = macro_precision(yhat, y) 24 | rec = macro_recall(yhat, y) 25 | if prec + rec == 0: 26 | f1 = 0. 27 | else: 28 | 29 | f1 = 2*(prec*rec)/(prec+rec) 30 | return f1 31 | 32 | def precision_at_k(yhat_raw, y, k): 33 | #num true labels in top k predictions / k 34 | sortd = np.argsort(yhat_raw)[:,::-1] 35 | topk = sortd[:,:k] 36 | 37 | #get precision at k for each example 38 | vals = [] 39 | for i, tk in enumerate(topk): 40 | if len(tk) > 0: 41 | num_true_in_top_k = y[i,tk].sum() 42 | denom = len(tk) 43 | vals.append(num_true_in_top_k / float(denom)) 44 | 45 | return np.mean(vals) 46 | 47 | def micro_precision(yhatmic, ymic): 48 | return intersect_size(yhatmic, ymic, 0) / yhatmic.sum(axis=0) 49 | 50 | def micro_recall(yhatmic, ymic): 51 | return intersect_size(yhatmic, ymic, 0) / ymic.sum(axis=0) 52 | 53 | def micro_f1(yhatmic, ymic): 54 | prec = micro_precision(yhatmic, ymic) 55 | rec = micro_recall(yhatmic, ymic) 56 | 57 | if prec + rec == 0: 58 | f1 = 0. 59 | else: 60 | f1 = 2*(prec*rec)/(prec+rec) 61 | return f1 -------------------------------------------------------------------------------- /generate_emb.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import gensim 3 | import cPickle 4 | 5 | loadpath = "./data/yahoo.p" 6 | x = cPickle.load(open(loadpath, "rb")) 7 | train, val, test = x[0], x[1], x[2] 8 | train_lab, val_lab, test_lab = x[3], x[4], x[5] 9 | wordtoix, ixtoword = x[6], x[7] 10 | 11 | class_name = ['Society Culture', 12 | 'Science Mathematics', 13 | 'Health' , 14 | 'Education Reference' , 15 | 'Computers Internet' , 16 | 'Sports' , 17 | 'Business Finance' , 18 | 'Entertainment Music' , 19 | 'Family Relationships' , 20 | 'Politics Government'] 21 | 22 | filename = './data/glove.840B.300d.w2vformat.txt' 23 | model = gensim.models.KeyedVectors.load_word2vec_format(filename) 24 | vector_size = model.vector_size 25 | embedding_vectors = np.random.uniform(-0.001, 0.001, (len(wordtoix), vector_size)) 26 | glove_vocab = list(model.vocab.keys()) 27 | count = 0 28 | mis_count = 0 29 | for word in wordtoix.keys(): 30 | idx = wordtoix.get(word) 31 | if word in glove_vocab: 32 | embedding_vectors[idx] = model.wv[word] 33 | count += 1 34 | else: 35 | mis_count += 1 36 | print("num of vocab in glove: {}".format(count)) 37 | print("num of vocab not in glove: {}".format(mis_count)) 38 | 39 | print("load class embedding") 40 | name_list = [ k.lower().split(' ') for k in class_name] 41 | id_list = [ [ wordtoidx[i] for i in l] for l in name_list] 42 | value_list = [ [ opt.W_emb[i] for i in l] for l in id_list] 43 | value_mean = [ np.mean(l) for l in id_list] 44 | 45 | cPickle.save(open('./data/yahoo_emb.p', 'wb'), [embedding_vectors, value_mean]) 46 | 47 | -------------------------------------------------------------------------------- /glove_generate.py: -------------------------------------------------------------------------------- 1 | 2 | import gensim 3 | import cPickle 4 | import numpy as np 5 | 6 | def load_embedding_vectors_glove_gensim(vocabulary, filename): 7 | print("loading embedding") 8 | model = gensim.models.KeyedVectors.load_word2vec_format(filename) 9 | vector_size = model.vector_size 10 | embedding_vectors = np.random.uniform(-0.25, 0.25, (len(vocabulary), vector_size)) 11 | glove_vocab = list(model.vocab.keys()) 12 | count = 0 13 | mis_count = 0 14 | for word in vocabulary.keys(): 15 | idx = vocabulary.get(word) 16 | if word in glove_vocab: 17 | embedding_vectors[idx] = model.wv[word] 18 | 19 | count += 1 20 | else: 21 | mis_count += 1 22 | print("num of vocab in glove: {}".format(count)) 23 | print("num of vocab not in glove: {}".format(mis_count)) 24 | return embedding_vectors 25 | 26 | if __name__ == '__main__': 27 | 28 | loadpath = "yelp_full.p" 29 | embpath = "yelp_full_glove.p" 30 | x = cPickle.load(open(loadpath, "rb")) 31 | train, val, test = x[0], x[1], x[2] 32 | train_lab, val_lab, test_lab = x[3], x[4], x[5] 33 | wordtoix, ixtoword = x[6], x[7] 34 | 35 | print("load data finished") 36 | 37 | y = load_embedding_vectors_glove_gensim(wordtoix,'glove.840B.300d.w2vformat.txt' ) 38 | cPickle.dump([y.astype(np.float32)], open(embpath, 'wb')) 39 | 40 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Guoyin Wang 4 | 5 | LEAM 6 | """ 7 | 8 | import os, sys, cPickle 9 | import tensorflow as tf 10 | from tensorflow.contrib import layers 11 | import numpy as np 12 | import scipy.io as sio 13 | from math import floor 14 | 15 | from model import * 16 | from utils import get_minibatches_idx, restore_from_save, tensors_key_in_file, prepare_data_for_emb, load_class_embedding 17 | 18 | class Options(object): 19 | def __init__(self): 20 | self.GPUID = 0 21 | self.dataset = 'yelp_full' 22 | self.fix_emb = True 23 | self.restore = False 24 | self.W_emb = None 25 | self.W_class_emb = None 26 | self.maxlen = 305 27 | self.n_words = None 28 | self.embed_size = 300 29 | self.lr = 1e-3 30 | self.batch_size = 100 31 | self.max_epochs = 20 32 | self.dropout = 0.5 33 | self.part_data = False 34 | self.portion = 1.0 35 | self.save_path = "./save/" 36 | self.log_path = "./log/" 37 | self.print_freq = 100 38 | self.valid_freq = 100 39 | 40 | self.optimizer = 'Adam' 41 | self.clip_grad = None 42 | self.class_penalty = 1.0 43 | self.ngram = 55 44 | self.H_dis = 300 45 | 46 | 47 | def __iter__(self): 48 | for attr, value in self.__dict__.iteritems(): 49 | yield attr, value 50 | 51 | def emb_classifier(x, x_mask, y, dropout, opt, class_penalty): 52 | # comment notation 53 | # b: batch size, s: sequence length, e: embedding dim, c : num of class 54 | x_emb, W_norm = embedding(x, opt) # b * s * e 55 | x_emb=tf.cast(x_emb,tf.float32) 56 | W_norm=tf.cast(W_norm,tf.float32) 57 | y_pos = tf.argmax(y, -1) 58 | y_emb, W_class = embedding_class(y_pos, opt, 'class_emb') # b * e, c * e 59 | y_emb=tf.cast(y_emb,tf.float32) 60 | W_class=tf.cast(W_class,tf.float32) 61 | W_class_tran = tf.transpose(W_class, [1,0]) # e * c 62 | x_emb = tf.expand_dims(x_emb, 3) # b * s * e * 1 63 | H_enc = att_emb_ngram_encoder_maxout(x_emb, x_mask, W_class, W_class_tran, opt) 64 | H_enc = tf.squeeze(H_enc) 65 | # H_enc=tf.cast(H_enc,tf.float32) 66 | logits = discriminator_2layer(H_enc, opt, dropout, prefix='classify_', num_outputs=opt.num_class, is_reuse=False) # b * c 67 | logits_class = discriminator_2layer(W_class, opt, dropout, prefix='classify_', num_outputs=opt.num_class, is_reuse=True) 68 | prob = tf.nn.softmax(logits) 69 | class_y = tf.constant(name='class_y', shape=[opt.num_class, opt.num_class], dtype=tf.float32, value=np.identity(opt.num_class),) 70 | correct_prediction = tf.equal(tf.argmax(prob, 1), tf.argmax(y, 1)) 71 | accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32)) 72 | 73 | loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y, logits=logits)) + class_penalty * tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=class_y, logits=logits_class)) 74 | 75 | global_step = tf.Variable(0, trainable=False) 76 | train_op = layers.optimize_loss( 77 | loss, 78 | global_step=global_step, 79 | optimizer=opt.optimizer, 80 | learning_rate=opt.lr) 81 | 82 | return accuracy, loss, train_op, W_norm, global_step 83 | 84 | 85 | def main(): 86 | # Prepare training and testing data 87 | opt = Options() 88 | # load data 89 | if opt.dataset == 'yahoo': 90 | loadpath = "./data/yahoo.p" 91 | embpath = "./data/yahoo_glove.p" 92 | opt.num_class = 10 93 | opt.class_name = ['Society Culture', 94 | 'Science Mathematics', 95 | 'Health' , 96 | 'Education Reference' , 97 | 'Computers Internet' , 98 | 'Sports' , 99 | 'Business Finance' , 100 | 'Entertainment Music' , 101 | 'Family Relationships' , 102 | 'Politics Government'] 103 | elif opt.dataset == 'agnews': 104 | loadpath = "./data/ag_news.p" 105 | embpath = "./data/ag_news_glove.p" 106 | opt.num_class = 4 107 | opt.class_name = ['World', 108 | 'Sports', 109 | 'Business', 110 | 'Science'] 111 | elif opt.dataset == 'dbpedia': 112 | loadpath = "./data/dbpedia.p" 113 | embpath = "./data/dbpedia_glove.p" 114 | opt.num_class = 14 115 | opt.class_name = ['Company', 116 | 'Educational Institution', 117 | 'Artist', 118 | 'Athlete', 119 | 'Office Holder', 120 | 'Mean Of Transportation', 121 | 'Building', 122 | 'Natural Place', 123 | 'Village', 124 | 'Animal', 125 | 'Plant', 126 | 'Album', 127 | 'Film', 128 | 'Written Work', 129 | ] 130 | elif opt.dataset == 'yelp_full': 131 | loadpath = "./data/yelp_full.p" 132 | embpath = "./data/yelp_full_glove.p" 133 | opt.num_class = 5 134 | opt.class_name = ['worst', 135 | 'bad', 136 | 'middle', 137 | 'good', 138 | 'best'] 139 | x = cPickle.load(open(loadpath, "rb")) 140 | train, val, test = x[0], x[1], x[2] 141 | train_lab, val_lab, test_lab = x[3], x[4], x[5] 142 | wordtoix, ixtoword = x[6], x[7] 143 | del x 144 | print("load data finished") 145 | 146 | train_lab = np.array(train_lab, dtype='float32') 147 | val_lab = np.array(val_lab, dtype='float32') 148 | test_lab = np.array(test_lab, dtype='float32') 149 | opt.n_words = len(ixtoword) 150 | if opt.part_data: 151 | #np.random.seed(123) 152 | train_ind = np.random.choice(len(train), int(len(train)*opt.portion), replace=False) 153 | train = [train[t] for t in train_ind] 154 | train_lab = [train_lab[t] for t in train_ind] 155 | 156 | os.environ['CUDA_VISIBLE_DEVICES'] = str(opt.GPUID) 157 | 158 | print(dict(opt)) 159 | print('Total words: %d' % opt.n_words) 160 | 161 | try: 162 | opt.W_emb = np.array(cPickle.load(open(embpath, 'rb')),dtype='float32') 163 | opt.W_class_emb = load_class_embedding( wordtoix, opt) 164 | except IOError: 165 | print('No embedding file found.') 166 | opt.fix_emb = False 167 | 168 | with tf.device('/gpu:1'): 169 | x_ = tf.placeholder(tf.int32, shape=[opt.batch_size, opt.maxlen],name='x_') 170 | x_mask_ = tf.placeholder(tf.float32, shape=[opt.batch_size, opt.maxlen],name='x_mask_') 171 | keep_prob = tf.placeholder(tf.float32,name='keep_prob') 172 | y_ = tf.placeholder(tf.float32, shape=[opt.batch_size, opt.num_class],name='y_') 173 | class_penalty_ = tf.placeholder(tf.float32, shape=()) 174 | accuracy_, loss_, train_op, W_norm_, global_step = emb_classifier(x_, x_mask_, y_, keep_prob, opt, class_penalty_) 175 | uidx = 0 176 | max_val_accuracy = 0. 177 | max_test_accuracy = 0. 178 | 179 | config = tf.ConfigProto(log_device_placement=False, allow_soft_placement=True, ) 180 | config.gpu_options.allow_growth = True 181 | np.set_printoptions(precision=3) 182 | np.set_printoptions(threshold=np.inf) 183 | saver = tf.train.Saver() 184 | 185 | with tf.Session(config=config) as sess: 186 | train_writer = tf.summary.FileWriter(opt.log_path + '/train', sess.graph) 187 | test_writer = tf.summary.FileWriter(opt.log_path + '/test', sess.graph) 188 | sess.run(tf.global_variables_initializer()) 189 | if opt.restore: 190 | try: 191 | t_vars = tf.trainable_variables() 192 | save_keys = tensors_key_in_file(opt.save_path) 193 | ss = set([var.name for var in t_vars]) & set([s + ":0" for s in save_keys.keys()]) 194 | cc = {var.name: var for var in t_vars} 195 | # only restore variables with correct shape 196 | ss_right_shape = set([s for s in ss if cc[s].get_shape() == save_keys[s[:-2]]]) 197 | 198 | loader = tf.train.Saver(var_list=[var for var in t_vars if var.name in ss_right_shape]) 199 | loader.restore(sess, opt.save_path) 200 | 201 | print("Loading variables from '%s'." % opt.save_path) 202 | print("Loaded variables:" + str(ss)) 203 | 204 | except: 205 | print("No saving session, using random initialization") 206 | sess.run(tf.global_variables_initializer()) 207 | 208 | try: 209 | for epoch in range(opt.max_epochs): 210 | print("Starting epoch %d" % epoch) 211 | kf = get_minibatches_idx(len(train), opt.batch_size, shuffle=True) 212 | for _, train_index in kf: 213 | uidx += 1 214 | sents = [train[t] for t in train_index] 215 | x_labels = [train_lab[t] for t in train_index] 216 | x_labels = np.array(x_labels) 217 | x_labels = x_labels.reshape((len(x_labels), opt.num_class)) 218 | 219 | x_batch, x_batch_mask = prepare_data_for_emb(sents, opt) 220 | _, loss, step, = sess.run([train_op, loss_, global_step], feed_dict={x_: x_batch, x_mask_: x_batch_mask, y_: x_labels, keep_prob: opt.dropout, class_penalty_:opt.class_penalty}) 221 | 222 | if uidx % opt.valid_freq == 0: 223 | train_correct = 0.0 224 | # sample evaluate accuaccy on 500 sample data 225 | kf_train = get_minibatches_idx(500, opt.batch_size, shuffle=True) 226 | for _, train_index in kf_train: 227 | train_sents = [train[t] for t in train_index] 228 | train_labels = [train_lab[t] for t in train_index] 229 | train_labels = np.array(train_labels) 230 | train_labels = train_labels.reshape((len(train_labels), opt.num_class)) 231 | x_train_batch, x_train_batch_mask = prepare_data_for_emb(train_sents, opt) 232 | train_accuracy = sess.run(accuracy_, feed_dict={x_: x_train_batch, x_mask_: x_train_batch_mask, y_: train_labels, keep_prob: 1.0, class_penalty_:0.0}) 233 | 234 | train_correct += train_accuracy * len(train_index) 235 | 236 | train_accuracy = train_correct / 500 237 | 238 | print("Iteration %d: Training loss %f " % (uidx, loss)) 239 | print("Train accuracy %f " % train_accuracy) 240 | 241 | val_correct = 0.0 242 | kf_val = get_minibatches_idx(len(val), opt.batch_size, shuffle=True) 243 | for _, val_index in kf_val: 244 | val_sents = [val[t] for t in val_index] 245 | val_labels = [val_lab[t] for t in val_index] 246 | val_labels = np.array(val_labels) 247 | val_labels = val_labels.reshape((len(val_labels), opt.num_class)) 248 | x_val_batch, x_val_batch_mask = prepare_data_for_emb(val_sents, opt) 249 | val_accuracy = sess.run(accuracy_, feed_dict={x_: x_val_batch, x_mask_: x_val_batch_mask, 250 | y_: val_labels, keep_prob: 1.0, 251 | class_penalty_:0.0 }) 252 | 253 | val_correct += val_accuracy * len(val_index) 254 | 255 | val_accuracy = val_correct / len(val) 256 | print("Validation accuracy %f " % val_accuracy) 257 | 258 | if val_accuracy > max_val_accuracy: 259 | max_val_accuracy = val_accuracy 260 | 261 | test_correct = 0.0 262 | 263 | kf_test = get_minibatches_idx(len(test), opt.batch_size, shuffle=True) 264 | for _, test_index in kf_test: 265 | test_sents = [test[t] for t in test_index] 266 | test_labels = [test_lab[t] for t in test_index] 267 | test_labels = np.array(test_labels) 268 | test_labels = test_labels.reshape((len(test_labels), opt.num_class)) 269 | x_test_batch, x_test_batch_mask = prepare_data_for_emb(test_sents, opt) 270 | 271 | test_accuracy = sess.run(accuracy_,feed_dict={x_: x_test_batch, x_mask_: x_test_batch_mask,y_: test_labels, keep_prob: 1.0, class_penalty_: 0.0}) 272 | 273 | test_correct += test_accuracy * len(test_index) 274 | test_accuracy = test_correct / len(test) 275 | print("Test accuracy %f " % test_accuracy) 276 | max_test_accuracy = test_accuracy 277 | 278 | print("Epoch %d: Max Test accuracy %f" % (epoch, max_test_accuracy)) 279 | saver.save(sess, opt.save_path, global_step=epoch) 280 | print("Max Test accuracy %f " % max_test_accuracy) 281 | 282 | except KeyboardInterrupt: 283 | print('Training interupted') 284 | print("Max Test accuracy %f " % max_test_accuracy) 285 | 286 | if __name__ == '__main__': 287 | main() 288 | -------------------------------------------------------------------------------- /main_multiclass.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Guoyin Wang 4 | 5 | LEAM 6 | """ 7 | 8 | import os, sys, cPickle 9 | import tensorflow as tf 10 | from tensorflow.contrib import layers 11 | import numpy as np 12 | import scipy.io as sio 13 | from math import floor 14 | 15 | from model import * 16 | from utils import get_minibatches_idx, restore_from_save, tensors_key_in_file, prepare_data_for_emb, load_class_embedding 17 | 18 | from evaluation import macro_f1, micro_f1, precision_at_k 19 | from sklearn.metrics import roc_auc_score, f1_score 20 | 21 | class Options(object): 22 | def __init__(self): 23 | self.GPUID = 0 24 | self.dataset = 'mimic' 25 | self.fix_emb = True 26 | self.restore = False 27 | self.W_emb = None 28 | self.W_class_emb = None 29 | self.maxlen = 305 30 | self.n_words = None 31 | self.embed_size = 300 32 | self.lr = 1e-3 33 | self.batch_size = 10 34 | self.max_epochs = 100 35 | self.dropout = 0.5 36 | self.part_data = False 37 | self.portion = 1.0 38 | self.save_path = "./save/" 39 | self.log_path = "./log/" 40 | self.print_freq = 100 41 | self.valid_freq = 100 42 | 43 | self.optimizer = 'Adam' 44 | self.clip_grad = None 45 | self.class_penalty = 1.0 46 | self.ngram = 55 47 | self.H_dis = 300 48 | 49 | 50 | def __iter__(self): 51 | for attr, value in self.__dict__.iteritems(): 52 | yield attr, value 53 | 54 | def emb_classifier(x, x_mask, y, dropout, opt, class_penalty): 55 | # comment notation 56 | # b: batch size, s: sequence length, e: embedding dim, c : num of class 57 | x_emb, W_norm = embedding(x, opt) # b * s * e 58 | x_emb=tf.cast(x_emb,tf.float32) 59 | W_norm=tf.cast(W_norm,tf.float32) 60 | y_pos = tf.argmax(y, -1) 61 | y_emb, W_class = embedding_class(y_pos, opt, 'class_emb') # b * e, c * e 62 | y_emb=tf.cast(y_emb,tf.float32) 63 | W_class=tf.cast(W_class,tf.float32) 64 | W_class_tran = tf.transpose(W_class, [1,0]) # e * c 65 | x_emb = tf.expand_dims(x_emb, 3) # b * s * e * 1 66 | H_enc = att_emb_ngram_encoder_cnn(x_emb, x_mask, W_class, W_class_tran, opt) 67 | H_enc_list= tf.unstack(H_enc, axis=-1) 68 | logits_list = [] 69 | for i, ih in enumerate(H_enc_list): 70 | logits_list.append(discriminator_0layer(ih, opt, dropout, prefix='classify_{}'.format(i), num_outputs=1, is_reuse=False) ) 71 | 72 | logits = tf.concat(logits_list,-1) 73 | prob = tf.nn.softmax(logits) 74 | # class_y = tf.constant(name='class_y', shape=[opt.num_class, opt.num_class], dtype=tf.float32, value=np.identity(opt.num_class),) 75 | correct_prediction = tf.equal(tf.argmax(prob, 1), tf.argmax(y, 1)) 76 | accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32)) 77 | 78 | loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(labels=y, logits=logits)) 79 | 80 | global_step = tf.Variable(0, trainable=False) 81 | train_op = layers.optimize_loss( 82 | loss, 83 | global_step=global_step, 84 | optimizer=opt.optimizer, 85 | learning_rate=opt.lr) 86 | 87 | return accuracy, loss, train_op, W_norm, global_step, logits, prob 88 | 89 | 90 | def main(): 91 | # Prepare training and testing data 92 | opt = Options() 93 | # load data 94 | loadpath = "./data/mimic3.p" 95 | embpath = "mimic3_emb.p" 96 | opt.num_class = 50 97 | x = cPickle.load(open(loadpath, "rb")) 98 | train, train_text, train_lab = x[0],x[1], x[2] 99 | val, val_text, val_lab = x[3],x[4], x[5] 100 | test, test_text, test_lab = x[6],x[7], x[8] 101 | wordtoix, ixtoword = x[10], x[9] 102 | del x 103 | print("load data finished") 104 | 105 | train_lab = np.array(train_lab, dtype='float32') 106 | val_lab = np.array(val_lab, dtype='float32') 107 | test_lab = np.array(test_lab, dtype='float32') 108 | opt.n_words = len(ixtoword) 109 | if opt.part_data: 110 | #np.random.seed(123) 111 | train_ind = np.random.choice(len(train), int(len(train)*opt.portion), replace=False) 112 | train = [train[t] for t in train_ind] 113 | train_lab = [train_lab[t] for t in train_ind] 114 | 115 | os.environ['CUDA_VISIBLE_DEVICES'] = str(opt.GPUID) 116 | 117 | print(dict(opt)) 118 | print('Total words: %d' % opt.n_words) 119 | 120 | try: 121 | opt.W_emb = np.array(cPickle.load(open(embpath, 'rb')),dtype='float32') 122 | opt.W_class_emb = load_class_embedding( wordtoix, opt) 123 | except IOError: 124 | print('No embedding file found.') 125 | opt.fix_emb = False 126 | 127 | with tf.device('/gpu:1'): 128 | x_ = tf.placeholder(tf.int32, shape=[opt.batch_size, opt.maxlen],name='x_') 129 | x_mask_ = tf.placeholder(tf.float32, shape=[opt.batch_size, opt.maxlen],name='x_mask_') 130 | keep_prob = tf.placeholder(tf.float32,name='keep_prob') 131 | y_ = tf.placeholder(tf.float32, shape=[opt.batch_size, opt.num_class],name='y_') 132 | class_penalty_ = tf.placeholder(tf.float32, shape=()) 133 | accuracy_, loss_, train_op, W_norm_, global_step, logits_, prob_ = emb_classifier(x_, x_mask_, y_, keep_prob, opt, class_penalty_) 134 | uidx = 0 135 | max_val_accuracy = 0. 136 | max_test_accuracy = 0. 137 | max_val_auc_mean = 0. 138 | max_test_auc_mean = 0. 139 | 140 | config = tf.ConfigProto(log_device_placement=False, allow_soft_placement=True, ) 141 | config.gpu_options.allow_growth = True 142 | np.set_printoptions(precision=3) 143 | np.set_printoptions(threshold=np.inf) 144 | saver = tf.train.Saver() 145 | 146 | with tf.Session(config=config) as sess: 147 | train_writer = tf.summary.FileWriter(opt.log_path + '/train', sess.graph) 148 | test_writer = tf.summary.FileWriter(opt.log_path + '/test', sess.graph) 149 | sess.run(tf.global_variables_initializer()) 150 | if opt.restore: 151 | try: 152 | t_vars = tf.trainable_variables() 153 | save_keys = tensors_key_in_file(opt.save_path) 154 | ss = set([var.name for var in t_vars]) & set([s + ":0" for s in save_keys.keys()]) 155 | cc = {var.name: var for var in t_vars} 156 | # only restore variables with correct shape 157 | ss_right_shape = set([s for s in ss if cc[s].get_shape() == save_keys[s[:-2]]]) 158 | 159 | loader = tf.train.Saver(var_list=[var for var in t_vars if var.name in ss_right_shape]) 160 | loader.restore(sess, opt.save_path) 161 | 162 | print("Loading variables from '%s'." % opt.save_path) 163 | print("Loaded variables:" + str(ss)) 164 | 165 | except: 166 | print("No saving session, using random initialization") 167 | sess.run(tf.global_variables_initializer()) 168 | 169 | try: 170 | for epoch in range(opt.max_epochs): 171 | print("Starting epoch %d" % epoch) 172 | kf = get_minibatches_idx(len(train), opt.batch_size, shuffle=True) 173 | for _, train_index in kf: 174 | uidx += 1 175 | sents = [train[t] for t in train_index] 176 | x_labels = [train_lab[t] for t in train_index] 177 | x_labels = np.array(x_labels) 178 | x_labels = x_labels.reshape((len(x_labels), opt.num_class)) 179 | 180 | x_batch, x_batch_mask = prepare_data_for_emb(sents, opt) 181 | _, loss, step, = sess.run([train_op, loss_, global_step], feed_dict={x_: x_batch, x_mask_: x_batch_mask, y_: x_labels, keep_prob: opt.dropout, class_penalty_:opt.class_penalty}) 182 | 183 | if uidx % opt.valid_freq == 0: 184 | train_correct = 0.0 185 | # sample evaluate accuaccy on 500 sample data 186 | kf_train = get_minibatches_idx(500, opt.batch_size, shuffle=True) 187 | for _, train_index in kf_train: 188 | train_sents = [train[t] for t in train_index] 189 | train_labels = [train_lab[t] for t in train_index] 190 | train_labels = np.array(train_labels) 191 | train_labels = train_labels.reshape((len(train_labels), opt.num_class)) 192 | x_train_batch, x_train_batch_mask = prepare_data_for_emb(train_sents, opt) 193 | train_accuracy = sess.run(accuracy_, feed_dict={x_: x_train_batch, x_mask_: x_train_batch_mask, y_: train_labels, keep_prob: 1.0, class_penalty_:0.0}) 194 | 195 | train_correct += train_accuracy * len(train_index) 196 | 197 | train_accuracy = train_correct / 500 198 | 199 | print("Iteration %d: Training loss %f " % (uidx, loss)) 200 | print("Train accuracy %f " % train_accuracy) 201 | 202 | val_correct = 0.0 203 | val_y = [] 204 | val_logits_list = [] 205 | val_prob_list = [] 206 | val_true_list = [] 207 | 208 | kf_val = get_minibatches_idx(len(val), opt.batch_size, shuffle=True) 209 | for _, val_index in kf_val: 210 | val_sents = [val[t] for t in val_index] 211 | val_labels = [val_lab[t] for t in val_index] 212 | val_labels = np.array(val_labels) 213 | val_labels = val_labels.reshape((len(val_labels), opt.num_class)) 214 | x_val_batch, x_val_batch_mask = prepare_data_for_emb(val_sents, opt) 215 | val_accuracy, val_logits, val_probs = sess.run([accuracy_, logits_, prob_], feed_dict={x_: x_val_batch, x_mask_: x_val_batch_mask, 216 | y_: val_labels, keep_prob: 1.0, 217 | class_penalty_:0.0 }) 218 | 219 | val_correct += val_accuracy * len(val_index) 220 | val_y += np.argmax(val_labels, axis=1).tolist() 221 | val_logits_list += val_logits.tolist() 222 | val_prob_list += val_probs.tolist() 223 | val_true_list += val_labels.tolist() 224 | 225 | val_accuracy = val_correct / len(val) 226 | val_logits_array = np.asarray(val_logits_list) 227 | val_prob_array = np.asarray(val_prob_list) 228 | val_true_array = np.asarray(val_true_list) 229 | val_auc_list = [] 230 | val_auc_micro = roc_auc_score(y_true=val_true_array, y_score =val_logits_array,average='micro') 231 | val_auc_macro = roc_auc_score(y_true=val_true_array, y_score =val_logits_array,average='macro') 232 | for i in range(opt.num_class): 233 | if np.max(val_true_array[:,i] > 0): 234 | val_auc = roc_auc_score(y_true = val_true_array[:,i], y_score= val_logits_array[:,i],) 235 | val_auc_list.append(val_auc) 236 | val_auc_mean = np.mean(val_auc) 237 | 238 | # print("Validation accuracy %f " % val_accuracy) 239 | print("val auc macro %f micro %f " % (val_auc_macro, val_auc_micro)) 240 | 241 | if True: 242 | test_correct = 0.0 243 | test_y = [] 244 | test_logits_list = [] 245 | test_prob_list = [] 246 | test_true_list = [] 247 | 248 | kf_test = get_minibatches_idx(len(test), opt.batch_size, shuffle=True) 249 | for _, test_index in kf_test: 250 | test_sents = [test[t] for t in test_index] 251 | test_labels = [test_lab[t] for t in test_index] 252 | test_labels = np.array(test_labels) 253 | test_labels = test_labels.reshape((len(test_labels), opt.num_class)) 254 | x_test_batch, x_test_batch_mask = prepare_data_for_emb(test_sents, opt) 255 | 256 | test_accuracy, test_logits, test_probs= sess.run([accuracy_, logits_, prob_],feed_dict={x_: x_test_batch, x_mask_: x_test_batch_mask,y_: test_labels, keep_prob: 1.0, class_penalty_: 0.0}) 257 | 258 | test_correct += test_accuracy * len(test_index) 259 | 260 | test_correct += test_accuracy * len(test_index) 261 | test_y += np.argmax(test_labels, axis=1).tolist() 262 | test_logits_list += test_logits.tolist() 263 | test_prob_list += test_probs.tolist() 264 | test_true_list += test_labels.tolist() 265 | test_accuracy = test_correct / len(test) 266 | test_logits_array = np.asarray(test_logits_list) 267 | test_prob_array = np.asarray(test_prob_list) 268 | test_true_array = np.asarray(test_true_list) 269 | test_auc_list = [] 270 | test_auc_micro = roc_auc_score(y_true=test_true_array, y_score =test_logits_array,average='micro') 271 | test_auc_macro = roc_auc_score(y_true=test_true_array, y_score =test_logits_array,average='macro') 272 | 273 | test_f1_micro = micro_f1(test_prob_array.ravel() >0.5, test_true_array.ravel(), ) 274 | test_f1_macro = macro_f1(test_prob_array > 0.5, test_true_array, ) 275 | test_p5 = precision_at_k(test_logits_array, test_true_array , 5) 276 | 277 | for i in range(opt.num_class): 278 | if np.max(test_true_array[:,i] > 0): 279 | test_auc = roc_auc_score(y_true = test_true_array[:,i], y_score= test_logits_array[:,i],) 280 | test_auc_list.append(test_auc) 281 | 282 | test_auc_mean = np.mean(test_auc) 283 | print("Test auc macro %f micro %f " % (test_auc_macro, test_auc_micro)) 284 | print("Test f1 macro %f micro %f " % (test_f1_macro, test_f1_micro)) 285 | print("P5 %f" % test_p5) 286 | # max_test_accuracy = test_accuracy 287 | max_test_auc_mean = test_auc_mean 288 | # print("Test accuracy %f " % test_accuracy) 289 | # max_test_accuracy = test_accuracy 290 | 291 | # print("Epoch %d: Max Test accuracy %f" % (epoch, max_test_accuracy)) 292 | print("Epoch %d: Max Test auc %f" % (epoch, max_test_auc_mean)) 293 | saver.save(sess, opt.save_path, global_step=epoch) 294 | print("Max Test accuracy %f " % max_test_accuracy) 295 | 296 | except KeyboardInterrupt: 297 | print('Training interupted') 298 | print("Max Test accuracy %f " % max_test_accuracy) 299 | 300 | if __name__ == '__main__': 301 | main() 302 | -------------------------------------------------------------------------------- /model.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | import numpy as np 3 | from tensorflow.contrib import layers 4 | 5 | def embedding(features, opt, prefix='', is_reuse=None): 6 | """Customized function to transform batched x into embeddings.""" 7 | # Convert indexes of words into embeddings. 8 | with tf.variable_scope(prefix + 'embed', reuse=is_reuse): 9 | if opt.fix_emb: 10 | assert (hasattr(opt, 'W_emb')) 11 | assert (np.shape(np.array(opt.W_emb)) == (opt.n_words, opt.embed_size)) 12 | W = tf.get_variable('W', initializer=opt.W_emb, trainable=True) 13 | print("initialize word embedding finished") 14 | else: 15 | weightInit = tf.random_uniform_initializer(-0.001, 0.001) 16 | W = tf.get_variable('W', [opt.n_words, opt.embed_size], initializer=weightInit) 17 | if hasattr(opt, 'relu_w') and opt.relu_w: 18 | W = tf.nn.relu(W) 19 | 20 | word_vectors = tf.nn.embedding_lookup(W, features) 21 | 22 | return word_vectors, W 23 | 24 | def embedding_class(features, opt, prefix='', is_reuse=None): 25 | """Customized function to transform batched y into embeddings.""" 26 | # Convert indexes of words into embeddings. 27 | with tf.variable_scope(prefix + 'embed', reuse=is_reuse): 28 | if opt.fix_emb: 29 | assert (hasattr(opt, 'W_class_emb')) 30 | W = tf.get_variable('W_class', initializer=opt.W_class_emb, trainable=True) 31 | print("initialize class embedding finished") 32 | else: 33 | weightInit = tf.random_uniform_initializer(-0.001, 0.001) 34 | W = tf.get_variable('W_class', [opt.num_class, opt.embed_size], initializer=weightInit) 35 | if hasattr(opt, 'relu_w') and opt.relu_w: 36 | W = tf.nn.relu(W) 37 | word_vectors = tf.nn.embedding_lookup(W, features) 38 | 39 | return word_vectors, W 40 | 41 | def att_emb_ngram_encoder_maxout(x_emb, x_mask, W_class, W_class_tran, opt): 42 | x_mask = tf.expand_dims(x_mask, axis=-1) # b * s * 1 43 | x_emb_0 = tf.squeeze(x_emb,) # b * s * e 44 | x_emb_1 = tf.multiply(x_emb_0, x_mask) # b * s * e 45 | 46 | x_emb_norm = tf.nn.l2_normalize(x_emb_1, dim=2) # b * s * e 47 | W_class_norm = tf.nn.l2_normalize(W_class_tran, dim = 0) # e * c 48 | G = tf.contrib.keras.backend.dot(x_emb_norm, W_class_norm) # b * s * c 49 | x_full_emb = x_emb_0 50 | Att_v = tf.contrib.layers.conv2d(G, num_outputs=opt.num_class,kernel_size=[opt.ngram], padding='SAME',activation_fn=tf.nn.relu) #b * s * c 51 | 52 | Att_v = tf.reduce_max(Att_v, axis=-1, keep_dims=True) 53 | Att_v_max = partial_softmax(Att_v, x_mask, 1, 'Att_v_max') # b * s * 1 54 | 55 | x_att = tf.multiply(x_full_emb, Att_v_max) 56 | H_enc = tf.reduce_sum(x_att, axis=1) 57 | return H_enc 58 | 59 | def att_emb_ngram_encoder_cnn(x_emb, x_mask, W_class, W_class_tran, opt): 60 | x_mask = tf.expand_dims(x_mask, axis=-1) # b * s * 1 61 | x_emb_0 = tf.squeeze(x_emb,) # b * s * e 62 | x_emb_1 = tf.multiply(x_emb_0, x_mask) # b * s * e 63 | 64 | H = tf.contrib.layers.conv2d(x_emb_0, num_outputs=opt.embed_size,kernel_size=[10], padding='SAME',activation_fn=tf.nn.relu) #b * s * c 65 | 66 | 67 | G = tf.contrib.keras.backend.dot(H, W_class_tran) # b * s * c 68 | Att_v_max = partial_softmax(G, x_mask, 1, 'Att_v_max') # b * s * c 69 | 70 | x_att = tf.contrib.keras.backend.batch_dot(tf.transpose(H,[0,2,1]), Att_v_max) 71 | H_enc = tf.squeeze(x_att) 72 | return H_enc 73 | 74 | 75 | def aver_emb_encoder(x_emb, x_mask): 76 | """ compute the average over all word embeddings """ 77 | x_mask = tf.expand_dims(x_mask, axis=-1) 78 | # x_mask = tf.expand_dims(x_mask, axis=-1) # batch L 1 1 79 | 80 | x_sum = tf.multiply(x_emb, x_mask) # batch L emb 81 | H_enc_0 = tf.reduce_sum(x_sum, axis=1, keep_dims=True) # batch 1 emb 82 | H_enc = tf.squeeze(H_enc_0, [1,]) # batch emb 83 | x_mask_sum = tf.reduce_sum(x_mask, axis=1, keep_dims=True) # batch 1 1 84 | x_mask_sum = tf.squeeze(x_mask_sum, [2,]) # batch 1 85 | 86 | #pdb.set_trace() 87 | 88 | H_enc = H_enc / x_mask_sum # batch emb 89 | 90 | return H_enc 91 | 92 | def gru_encoder(X_emb, opt, prefix = '', is_reuse=None, res=None): 93 | with tf.variable_scope(prefix + 'gru_encoder', reuse=True): 94 | cell_fw = tf.contrib.rnn.GRUCell(opt.n_hid) 95 | cell_bw = tf.contrib.rnn.GRUCell(opt.n_hid) 96 | with tf.variable_scope(prefix + 'gru_encoder', reuse=is_reuse): 97 | weightInit = tf.random_uniform_initializer(-0.001, 0.001) 98 | 99 | packed_output, state = tf.nn.bidirectional_dynamic_rnn(cell_fw, cell_bw, X_emb , dtype = tf.float32) 100 | h_fw = state[0] 101 | h_bw = state[1] 102 | 103 | hidden = tf.concat((h_fw, h_bw), 1) 104 | 105 | hidden = tf.nn.l2_normalize(hidden, 1) 106 | return hidden, res 107 | 108 | def discriminator_1layer(H, opt, dropout, prefix='', num_outputs=1, is_reuse=None): 109 | # last layer must be linear 110 | H = tf.squeeze(H) 111 | biasInit = tf.constant_initializer(0.001, dtype=tf.float32) 112 | H_dis = layers.fully_connected(tf.nn.dropout(H, keep_prob=dropout), num_outputs=opt.H_dis, 113 | biases_initializer=biasInit, activation_fn=tf.nn.relu, scope=prefix + 'dis_1', 114 | reuse=is_reuse) 115 | return H_dis 116 | 117 | 118 | def discriminator_0layer(H, opt, dropout, prefix='', num_outputs=1, is_reuse=None): 119 | H = tf.squeeze(H) 120 | biasInit = tf.constant_initializer(0.001, dtype=tf.float32) 121 | logits = layers.linear(tf.nn.dropout(H, keep_prob=dropout), num_outputs=num_outputs, biases_initializer=biasInit, 122 | scope=prefix + 'dis', reuse=is_reuse) 123 | return logits 124 | 125 | def linear_layer(x, output_dim): 126 | input_dim = x.get_shape().as_list()[1] 127 | thres = np.sqrt(6.0 / (input_dim + output_dim)) 128 | W = tf.get_variable("W", [input_dim, output_dim], scope=prefix + '_W', 129 | initializer=tf.random_uniform_initializer(minval=-thres, maxval=thres)) 130 | b = tf.get_variable("b", [output_dim], scope=prefix + '_b', initializer=tf.constant_initializer(0.0)) 131 | return tf.matmul(x, W) + b 132 | 133 | 134 | def discriminator_2layer(H, opt, dropout, prefix='', num_outputs=1, is_reuse=None): 135 | # last layer must be linear 136 | biasInit = tf.constant_initializer(0.001, dtype=tf.float32) 137 | H_dis = layers.fully_connected(tf.nn.dropout(H, keep_prob=dropout), num_outputs=opt.H_dis, 138 | biases_initializer=biasInit, activation_fn=tf.nn.relu, scope=prefix + 'dis_1', 139 | reuse=is_reuse) 140 | logits = layers.linear(tf.nn.dropout(H_dis, keep_prob=dropout), num_outputs=num_outputs, 141 | biases_initializer=biasInit, scope=prefix + 'dis_2', reuse=is_reuse) 142 | return logits 143 | 144 | def discriminator_3layer(H, opt, dropout, prefix='', num_outputs=1, is_reuse=None): 145 | # last layer must be linear 146 | biasInit = tf.constant_initializer(0.001, dtype=tf.float32) 147 | H_dis = layers.fully_connected(tf.nn.dropout(H, keep_prob=dropout), num_outputs=opt.H_dis, 148 | biases_initializer=biasInit, activation_fn=tf.nn.relu, scope=prefix + 'dis_1', 149 | reuse=is_reuse) 150 | H_dis = layers.fully_connected(tf.nn.dropout(H_dis, keep_prob=dropout), num_outputs=opt.H_dis, 151 | biases_initializer=biasInit, activation_fn=tf.nn.relu, scope=prefix + 'dis_2', 152 | reuse=is_reuse) 153 | logits = layers.linear(tf.nn.dropout(H_dis, keep_prob=dropout), num_outputs=num_outputs, 154 | biases_initializer=biasInit, scope=prefix + 'dis_3', reuse=is_reuse) 155 | return logits 156 | 157 | def partial_softmax(logits, weights, dim, name,): 158 | with tf.name_scope('partial_softmax'): 159 | exp_logits = tf.exp(logits) 160 | if len(exp_logits.get_shape()) == len(weights.get_shape()): 161 | exp_logits_weighted = tf.multiply(exp_logits, weights) 162 | else: 163 | exp_logits_weighted = tf.multiply(exp_logits, tf.expand_dims(weights, -1)) 164 | exp_logits_sum = tf.reduce_sum(exp_logits_weighted, axis=dim, keep_dims=True) 165 | partial_softmax_score = tf.div(exp_logits_weighted, exp_logits_sum, name=name) 166 | return partial_softmax_score 167 | 168 | -------------------------------------------------------------------------------- /plots/convergence_compare/Convergence_compare_plot.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 5, 6 | "metadata": { 7 | "collapsed": true 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "import numpy as np\n", 12 | "import matplotlib.pyplot as plt\n", 13 | "import seaborn as sns" 14 | ] 15 | }, 16 | { 17 | "cell_type": "code", 18 | "execution_count": 6, 19 | "metadata": { 20 | "collapsed": true 21 | }, 22 | "outputs": [], 23 | "source": [ 24 | "data = np.load('convergence_compare.npz')" 25 | ] 26 | }, 27 | { 28 | "cell_type": "code", 29 | "execution_count": 7, 30 | "metadata": { 31 | "collapsed": true 32 | }, 33 | "outputs": [], 34 | "source": [ 35 | "iteration_lstm = data['iteration_lstm']\n", 36 | "accuracy_lstm = data['accuracy_lstm']\n", 37 | "accuracy_a = data['accuracy_a']\n", 38 | "iteration_cnn = data['iteration_cnn']\n", 39 | "accuracy_bi = data['accuracy_bi']\n", 40 | "iteration_bi = data['iteration_bi']\n", 41 | "accuracy_cnn = data['accuracy_cnn']\n", 42 | "iteration_a = data['iteration_a']" 43 | ] 44 | }, 45 | { 46 | "cell_type": "code", 47 | "execution_count": 78, 48 | "metadata": {}, 49 | "outputs": [ 50 | { 51 | "data": { 52 | "image/png": "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\n", 53 | "text/plain": [ 54 | "" 55 | ] 56 | }, 57 | "metadata": {}, 58 | "output_type": "display_data" 59 | } 60 | ], 61 | "source": [ 62 | "fig=plt.figure(figsize=(5,4.0))\n", 63 | "stride = max( int(len(accuracy_a) / 8), 1)\n", 64 | "\n", 65 | "stride2 = max( int(len(accuracy_a) / 20), 1)\n", 66 | "\n", 67 | "\n", 68 | "iteration_bi2 = np.array([0.0, 0.01]+ iteration_bi.tolist())\n", 69 | "accuracy_bi2 = np.array([0.3,0.4]+ accuracy_bi.tolist())\n", 70 | "\n", 71 | "plt.plot(iteration_a*14000, accuracy_a, '-', label='LEAM', marker= 's', color='k', markevery=stride,lw=2, mec='k', mew=1 , markersize=10)\n", 72 | "plt.plot(iteration_cnn[:70]*14000, accuracy_cnn[:70],'-', label='CNN', marker= 'o', color='r', markevery=stride,lw=2, mec='k', mew=1 , markersize=10)\n", 73 | "plt.plot(iteration_lstm[:21]*14000, accuracy_lstm[:21],'-', label='LSTM', marker= 'v', color='orange', markevery=stride2,lw=2, mec='k', mew=1 , markersize=10)\n", 74 | "plt.plot(iteration_bi2[:27]*14000, accuracy_bi2[:27], '-',label='Bi-Blosa', marker= 'p', color='g', markevery=stride2,lw=2, mec='k', mew=1 , markersize=10)\n", 75 | "\n", 76 | "\n", 77 | "leg = plt.legend(fontsize=22, shadow=True, loc=(0.5, -0.0))\n", 78 | "plt.grid('on')\n", 79 | "\n", 80 | "plt.xlabel('# Iteration', fontsize=16)\n", 81 | "plt.ylabel('Accuracy (%)', fontsize=16)\n", 82 | "\n", 83 | "ax = plt.gca() \n", 84 | "ax.yaxis.set_label_coords(-0.09, 0.5) \n", 85 | "ax.xaxis.set_label_coords(0.48, -0.11) \n", 86 | "# X-axis label\n", 87 | "plt.xticks( (0.0, 0.1*14000, 0.2*14000), ('0', '2K','4K'), color='k', size=14)\n", 88 | "\n", 89 | "# Left Y-axis labels\n", 90 | "plt.yticks((0.50, 0.6, 0.70, 0.80), ('50', '60','70','80'), color='k', size=14)\n", 91 | "\n", 92 | "plt.xlim(0,4000)\n", 93 | "plt.ylim(0.45,0.80)\n", 94 | "\n", 95 | "plt.legend()\n", 96 | "plt.show()\n", 97 | "\n", 98 | "\n", 99 | "fig.savefig('yahoo_iteration.pdf', bbox_inches='tight')\n" 100 | ] 101 | }, 102 | { 103 | "cell_type": "code", 104 | "execution_count": 30, 105 | "metadata": {}, 106 | "outputs": [ 107 | { 108 | "data": { 109 | "text/plain": [ 110 | "array([ 0.00714286, 0.01428571, 0.02142857, 0.02857143, 0.03571429,\n", 111 | " 0.04285714, 0.05 , 0.05714286, 0.06428571, 0.07142857,\n", 112 | " 0.07857143, 0.08571429, 0.09285714, 0.1 , 0.10714286,\n", 113 | " 0.12142857, 0.12857143, 0.13571429, 0.15714286, 0.16428571,\n", 114 | " 0.17142857, 0.17857143, 0.2 , 0.20714286, 0.22142857,\n", 115 | " 0.22857143, 0.24285714, 0.25714286, 0.26428571, 0.28571429,\n", 116 | " 0.29285714, 0.30714286, 0.32857143, 0.33571429, 0.35 ,\n", 117 | " 0.36428571, 0.37857143, 0.39285714, 0.42857143, 0.44285714,\n", 118 | " 0.45 , 0.47142857, 0.49285714, 0.5 , 0.58571429,\n", 119 | " 0.60714286, 0.61428571, 0.67142857, 0.72857143, 0.74285714,\n", 120 | " 0.77142857, 0.89285714, 0.94285714, 1.04285714])" 121 | ] 122 | }, 123 | "execution_count": 30, 124 | "metadata": {}, 125 | "output_type": "execute_result" 126 | } 127 | ], 128 | "source": [ 129 | "iteration_a" 130 | ] 131 | }, 132 | { 133 | "cell_type": "code", 134 | "execution_count": 59, 135 | "metadata": {}, 136 | "outputs": [ 137 | { 138 | "data": { 139 | "text/plain": [ 140 | "array([ 0. , 0.6298, 0.7018, 0.715 , 0.7209, 0.7253, 0.7265,\n", 141 | " 0.7265, 0.727 , 0.7361, 0.7361, 0.7412, 0.7412, 0.744 ,\n", 142 | " 0.744 , 0.744 , 0.744 , 0.745 , 0.747 , 0.7472, 0.7477,\n", 143 | " 0.749 , 0.749 , 0.7504, 0.7504, 0.7504, 0.7507, 0.7507])" 144 | ] 145 | }, 146 | "execution_count": 59, 147 | "metadata": {}, 148 | "output_type": "execute_result" 149 | } 150 | ], 151 | "source": [] 152 | }, 153 | { 154 | "cell_type": "code", 155 | "execution_count": null, 156 | "metadata": { 157 | "collapsed": true 158 | }, 159 | "outputs": [], 160 | "source": [] 161 | } 162 | ], 163 | "metadata": { 164 | "kernelspec": { 165 | "display_name": "Python 2", 166 | "language": "python", 167 | "name": "python2" 168 | }, 169 | "language_info": { 170 | "codemirror_mode": { 171 | "name": "ipython", 172 | "version": 2 173 | }, 174 | "file_extension": ".py", 175 | "mimetype": "text/x-python", 176 | "name": "python", 177 | "nbconvert_exporter": "python", 178 | "pygments_lexer": "ipython2", 179 | "version": "2.7.13" 180 | } 181 | }, 182 | "nbformat": 4, 183 | "nbformat_minor": 2 184 | } 185 | -------------------------------------------------------------------------------- /plots/convergence_compare/convergence_compare.npz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guoyinwang/LEAM/bfd341ccd92009ab6b9e6b0578216f57bb2b921e/plots/convergence_compare/convergence_compare.npz -------------------------------------------------------------------------------- /plots/convergence_compare/filter_size.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guoyinwang/LEAM/bfd341ccd92009ab6b9e6b0578216f57bb2b921e/plots/convergence_compare/filter_size.pdf -------------------------------------------------------------------------------- /plots/convergence_compare/filter_size_compare.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": { 7 | "collapsed": true 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "import numpy as np\n", 12 | "import seaborn as sns\n", 13 | "import matplotlib.pyplot as plt\n", 14 | "from matplotlib.ticker import FormatStrFormatter" 15 | ] 16 | }, 17 | { 18 | "cell_type": "code", 19 | "execution_count": 2, 20 | "metadata": { 21 | "collapsed": true 22 | }, 23 | "outputs": [], 24 | "source": [ 25 | "%matplotlib inline" 26 | ] 27 | }, 28 | { 29 | "cell_type": "code", 30 | "execution_count": 3, 31 | "metadata": { 32 | "collapsed": true 33 | }, 34 | "outputs": [], 35 | "source": [ 36 | "x = [1, 11,21,31,41,51,61,71,81,91]" 37 | ] 38 | }, 39 | { 40 | "cell_type": "code", 41 | "execution_count": 4, 42 | "metadata": {}, 43 | "outputs": [], 44 | "source": [ 45 | "# yahoo \n", 46 | "y_1 = np.array([73.1, 74.225, 74.405, 74.485, 74.633, 74.65, 74.7183, 74.705, 74.6683, 74.6]) + 2.6\n", 47 | "# dbpedia\n", 48 | "y_2 = np.asarray([98.5071, 98.8943, 98.9343, 98.9671, 98.97, 98.9257, 98.94, 98.92, 98.94, 98.91])+0.05\n", 49 | "# yelp\n", 50 | "y_3 = [93.7684, 94.66, 95.1947, 95.2854, 95.2316, 95.1474, 95.1759, 95.1868, 95.3105, 95.2316]\n", 51 | "\n", 52 | "# yelp full\n", 53 | "y_4 = [61.09,63.98,64,63.9,64.01,63.926,63.91,64.088,63.772,64.09]" 54 | ] 55 | }, 56 | { 57 | "cell_type": "code", 58 | "execution_count": 39, 59 | "metadata": {}, 60 | "outputs": [ 61 | { 62 | "data": { 63 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAAU8AAAEUCAYAAACrhLTGAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzsnWd4VNXWgN+EACEBpAWkdxZFBAQkICgqxcJFUSwXFQGx\nYgPbtYtdsTf0ioJy4V4rfGABVLAQitIRyAoJHZTekkBCkvl+7DMQQjKZJFOSmf0+T57MOWfvs9bJ\n7Kyzy9prRbhcLiwWi8VSNCKDrYDFYrGURazxtFgslmJgjafFYrEUA2s8LRaLpRhY42mxWCzFwBpP\ni8ViKQZRwVYgHBGRd4AuwDmqmu2cKwf8BsxV1ccKqDcJ+FNVX/GRHr2Bp1S1ty/uZwkeItIESAFW\nO6cigWPAm6r6qYg8BYwCtgMRQAVgGXCbqh7Oc90FlAN2AXeoalIR9KgF7FbVCBEZCPRR1btL/oSl\nD2s8g8P9wBLgYeBZ59zDQBbwZLCUspR5jqhqR/eBiDQGfhKRNOfUZ6p6p3OtHDAduBt4Lu91p8xd\nwFTMi77IqOoMYEZx6pYFrPEMAqp6VET+CSSIyDeYnsAdQFfAJSJvAvFAFefaSFVNcKr3EJEFQB3g\nT2CIqqaJSC9gHBADZAKPqeosABF5HPgnxjgnAXeq6t8BelxLkFDVzSLyBPAAMCvP5WggFvjLwy1+\nAl4AEJHTgDeB9kB559oDqpolIldgDHA68Ie7sogMAwar6gARiQdeBioCdYEfVPWmEj9kELFznkFC\nVVcDjwITgI+Bm1R1O9ANqAd0V9W2wCfAv3JVrQ/0AVoBDYArRKQm8CVwj6qeCdwI/EdEmorIcOBi\noKtz7U9gUgAe0VI6WIkxeADXiMgKEVkF7ADigK/zqyQiUcBNwDzn1OvAUlXtDHQCagFjRKQOpv1e\n6VzbXIAe9wBPqGo3oC0wUEQ6l/jpgog1nkFEVd8G0oBFqvq9c24h8Bhwq4i8AgwGKueqNl1V0525\n0j+B2hiDm6yqi517rAESgN4YwzlRVd1DtzeBC0Wkgr+fz1IqcGF6hGCG5R2dl2gt4Afgs1xl3cZ1\nBbAK07Zudq4NwLTJFcBS4GyMUe4JrFbVtU65DwrQ40agmog8AryHGSFVLqBsmcAO24PPRsxEPwAi\ncinGwL0K/B+QCFyfq/yxXJ9dmGF9fi/BSMzwKu+1SMz3HlFSxS1lgq6cWEQ6jqoeE5EJGEPo5qQ5\nzzyUA65S1XUAIlIN0/4u5OS2lFVA/d8wveBZwOeYF36ZboO251n66AvMVNXxmPmjyzEN1xOLABGR\nszEf2gHnAj8Ds4HhIhLrlL0b+FVVM1T1Z7vSHrqISCvgccyLOD8GAb97ebvZwGgRiRCRipiFoDsx\nRrGdiHRwyg3LR4/qmEWnh1T1a8zUUwsKb9elGtvzLH28D0x15qWygV+BK0WkwBedqu4RkauAt0Uk\nBsgBhqtqkogkAw2B3517JAPXATiuJLep6iX+fSRLgKjkDKvBtIGjwMOq+q2IdMUMy3tieozRwAZg\nqJf3vhszIlqNGdH8CLzs9GCHAFNEJBP4JW9FVd0vIi8Ay0RkL7AHM63UArPwVCaJsCHpLBaLpejY\nYbvFYrEUA2s8LRaLpRhY42mxWCzFwBpPi8ViKQbWeFosFksxCAlXpd27D5/kMlC9egz796cXVNzv\nWPmBkx8XV8XvjtalrX2VBh3CRb6n9hUSxjMvUVHB9b0tS/Jr165a4LVduw75XX5ZpDQ8X7B1CHf5\nEKLG02IJN/zxErR4xhpPS4GMHn0nVapUpWrVqlSpUoWqVU/Lc1yVmjVrUa1a9WCravHAW2+9Rnp6\nGmlp6aSnp5OWlkp6errzk0Z6ejqtW7dh7NjnqVOnTrDVLTNY4xmGbNu2lR9+mM0PP+QN8XgyU6Z8\n6tX9atWqRcuWQosWrWjVqhVdu3YiLq4B9es3IDLSrkkGm2effarAa1FRUVSoUJG1a/9k3rwfeeGF\nVxg0aDAREWU6ZkdAsMYzDMjOzmbp0iX88MMsfvhhNmvX/ulVvYULl3Lo0CEOHz7s/D7EoUMHTzre\ntWsn69cnsXjxQhYuTDipfkxMDM2bt6Rly1a0aiW0bNmKli2FZs2aU6FCySPiZWZmIiJTgWbAIUwa\niSqY+AAZwApMjNMcdx1nf/97QAenzEhVTS6xMkFi9+7dvPfeWx7LTJ36BTExscTGxhITE0tMTAwx\nMTHExlamQoUK5OTkMGnSRzz99OPcdttNzJgxnZdffp3atWsH6CnKJtZ4higHDuznl1/mMWfOLH76\naQ779u0DoGLFilx4YV/69r2Ivn3707nzGQXeo3nzll7LO3r0KCkpySQnJ7F9+yZWrFhFUlISSUmJ\nrF698qSysbGV6d37Avr1u4gLL+xX7H/SmTOnAaSqaryICPAOUBO4W1UXiMizwBDgP7mqXQ5Eq2p3\nJ7r5q8BlxVIgiOzatYuxY59j0qQJpKd7XnXu06e/x+uRkZGMGHEz559/IffeO4rvvpvJokUJvPTS\na1x22RW+VDuksMazDJCens727dvYt28fBw7sZ//+fezbt++k3+7P7utHjx49Xv/00+tyww3D6Nv3\nInr1Oo/Y2FgP0opHdHQ07dqdQbt2ZxAXV4Xduw8Dpte7desW1q9XkpKSWL9eWbgwgW+/ncG335r0\nNp06nUXfvhfRr99FtG/fwesh48aNGwHcQaRVRNoAFVR1gVMkAWMYcxvPnjgpKVR1kYgUKz9PsNi5\ncyfvvvsmn3zyEUeOHKFu3Xo8/vhYHn74gRLfu2nTZkyb9i0fffQBzz77FDffPIyZM/+PF198lVq1\nahX7vqG6mBUSUZXy+uHl/ucNBr6Sn5OTwyeffMwzzzxJamrh96tSpSrVq9egdu1aVK1aja5du9Gv\n30WcccaZAZ3D8ub5U1LWM2eOmXddtGgBWVkmhu7pp9elT59+9O17ETfe+M8C6+/adYj/+7+vGTfu\n+Y+BkZjgugmY+JT/UtVfROQ9oIqq3uCu5wQA/soduV9EtgDNVLWgIL5kZWW7gu0a89dff/Hyyy/z\n/vvvc/ToURo0aMDDDz/MTTfdRMWKFT1+v8X5H1+/fj3Dhw8nISGBuLg4xo8fz5VXXlks3X2tW4Ap\nUHlrPP2AL+SvX5/E6NF38vvvi6ha9TT+8Y/LqFGjJtWr16BGjRpUr17jpM/VqlWjfPnyPpNfEooq\n/9Chg/z889zjUwx79+4ttM6uXYfIysqid+/4NzDR0hOA84EbMHEny2MC9Z6mqqPd9UTkNUzak8+d\n422q2sCTrGC2r507/+btt1/n008ncvToUerXb8A999zH3XffzqFDmX6VnZ2dzb//PZ4XXniao0eP\nMmjQlbzwwivUqFGz0L+By+Vi48YNLFu2hDvuuLnAcsXteeaWn5OTw7JlS5g9+3tmz/6O3bt38c9/\n3sDNN99G3br1inX/XHLCy0m+LJOZmck777zBa6+9TGZmJgMGXMYLL4yjTp3Tg62a36ha9TQGDhzE\nwIGDyM7OZvnypfzwwyxef91zevrExLUAP6nqaGf43Ri4FLhOVfeKyNs4w/pcJAD/AD535jxPSVFR\nGkhPT+fNN19h/Ph3nJ5mQ+655z6uvfY6KlasSMWKFTFJUv1HuXLluP32O+nbtz933XUb06Z9xfz5\nv/HKK28ydOi1J5U9ePAAy5YtZdmyJSxd+gfLli05Ps/uiYceGkP//hdzzjnnOs/kHWlpaXz33TfM\nmfM9c+bMYs+e3YCZ04+NjeWdd97ggw/e5YorruL22++ibdt2RXt4L7A9Tz9QXPlLl/7BmDF3sW7d\nWurUOZ0XX3yVSy/9R8Dk+wpfyS9sruzAgQMMGNDnJ0wK3QOYbI+dgWcwSc/mqeqjACLyKSax3jbM\navuZmCHZcFVN9KRHoNvXrFnf8eijD7J16xbq1avPffc9xDXXDDnJQyHQ33F2djbjx7/DSy89S0ZG\nBtdddx0dOnQ5bijXr086qXyjRk3o3LkzZ53Vhccff7jQ+8fGVub88y+kX7+L6NOnf75zrH/9tYM5\nc2Yxe/Z3/PbbL2RkZABQq1Yc/fpdRP/+l3Duub0pV64cX331Oe+999Zxvc4//0LuuONuzj23d5Gm\nsDz1PK3x9ANFlZ+amsqLLz7Dhx++j8vlYujQETz++FOcdlq1gMj3NYEyno6sgO9t99ffd/PmTTz6\n6IPMmTOLqKgobr/9LsaMeTDfBb5gfcdJScpdd93K8uXLjp+rXLkKnTp1pnPnLnTu3JVOnTqf5EHh\n6XucNu1bZs36jtmzv2PTpo2AWf3v0uVs+ve/hLPO6szChQnMnv09K1cuP17vjDPOoE8fs8h41lld\n8vUnzsnJ4ccfZ/Pee2+zYMF8p96Z3HHHXVx22RXHp7k8YY1ngCmK/Llzf+D+++9l27atNGvWnNde\ne5sePXoGTL4/sMazaGRkZPDuu2/yxhuvcPToUc45pxcvvvgqIq0LrBPM7zgrK4sffpjJvn2H6dy5\nKy1btqJcuYIX1Lz5Hl0uF+vXJx2ft1yy5Hdyco675xIVFUX37j256KKL6dfvYrp0aV+k51+2bAnj\nx7/DzJnTycnJoX79Bmzfvq1QvazxDDD5yffUgKKiorjzznsZM+ZBoqOj/SI/kFjj6T3z5v3Eww/f\nz4YNKdSuXYexY5/jiiuuKnRoGSrfcUHs2bOHH3+czZ9/rqJLl7O54II+VK16Wonlb968iQ8+eJep\nUyd79I+1xjNIFNV4zp2bwBlntPer/EASSPll1Xju2LGdxx9/mJkzpxMZGcnIkbfy4IOPnGQgPBFO\n37E/5O/fvw+RJgVe98Z42tX2UoAvDaeldHPs2DE++OA9XnnlRdLT0+jS5Wxeeuk12rc/M9iqhRXV\nq9co8T2s8fQjhw8f4ttvZzJ9+lfBVsVSCliwYD7/+td9JCauo2bNmjz//Mtce+11NnhKGcUaTx9z\n5MgRvvxyNpMmTebHH2cfd6ewhDerV69i0KBLARg6dASPPvqET3o/luDhV+MpIsOAYc5hNNAR+Nn5\nDNAEs9vj2lx1ylzUm2PHjvHLL3P5+usv+f77b0lLSwWgVSth0KDBDBp0JfHxZwVZS0swWbhwPi6X\ni3Hj3uDGG0cEWx2LD/Cr8VTVScAkABF5F/hYVf/tHFcH5gGj81QrM1Fv1q9P4v333+Wbb6azf/9+\nABo1asxdd91J//4Dadu2nY2LaAHA7Yd/9tnxQdbE4qakQUkCMmx3ts61U9VRuU6PBd5W1b/yFC8T\nUW+mTfuS0aPvJD09nbi42owceSuDBg2mS5ezqV276ikrgWU5eoyl5Kxbt5aoqCiaN28RbFUsPiJQ\nc56PYIwlACJSG7iQU3udAFWBg7mOs0UkylPUm+rVY05JCBUXV6VEChfEsWPHePDBB3njjTeoXLky\nU6ZM4ZprrjnFSdhf8r0l3OWXJlwuF6qJNG/ewidBoC2lA78bTxGpBoiqzst1ejAwVVWz86lyCBMN\n3E2kJ8MJnJKC1F8+aDt3/s3IkTeyePFCWrUSJk6cQsuWrdi3LzDyvSWc5JcFI71jx3YOHz5E69Z9\ngq2KxYcEwkfiXOCnPOf6cGq0GzcJwCUApSnqzaJFC7jwwl4sXryQgQMHMWvWXFq2bBVstSxlACf6\nk8ftlpayRyCG7QJsKOxcrqg304C+IrIAJ+pNAHQsEJfLxQcfvMvYsY8D8PTTz3PrraPsQpDFaxIT\nzWJR69Ztg6yJxZf43Xiq6rh8zp0SXE9Vh+Y6vM2vSnlJamoqo0ffyf/939fExdVmwoRP6N79nGCr\nZSljuHuebdq0CbImFl9ineQLYP36JIYPv46kJOXss+OZMOETTj+9brDVspRBEhPXUbFiRZo0aRZs\nVSw+xO4Ly4eZM/+Pfv16k5Sk3HLL7Uyb9q01nJZikZOTQ1JSIi1bisewbZayh+155iIrK4vnnhvL\nu+++SUxMDB988DGDBg0OtlqWMszmzZs4cuQIrVvbIXuoYY2nw4ED+xk+/HoSEn6jefMWTJw4xTZ4\nS4lJTFwHYNtSCGKH7Q4fffRvEhJ+4+KLBzBnzs+2sVt8gqo1nqGKNZ4OS5f+AcCrr75FlSoFBy62\nWIrCCR9PazxDDWs8Mb6cK1Yso2HDRvlm7bNYisu6deuIiYmlYcNGwVbF4mOs8QS2b9/Gnj176NjR\nho2z+I5jx46RkrKe1q1b24DHIYj9RuF4GtUOHToFWRNLKLFx4wYyMzPtkD1EscYTjueD7tTJ9jwt\nvuPEYpHdlhmKWOPJiZ7nmWd2CLImllBi3TqzWGRX2kOTsDeeLpeLlSuX07x5C047rVqw1bGEENbH\nM7QJe+O5cWMKhw4dtPOdFp+juo7TTqtmt/aGKGFvPFessPOdFt9z9OhRNmxIQaS1DV8YooS98Tyx\n0m6Np8V3JCevJzs72y4WhTBhbzxXrlxOZGQk7dufGWxVLCGEe6XdxvAMXcLaeGZnZ7Nq1UpEWhMb\nGxtsdSwhhHuxyPp4hi5hHVVp/fok0tPT7M6iMopxQJepQDNM4sBRQCzwPpAFJAEjVTXHXUdEygOf\nAE2AbOBmdSdV9yHuPe122B66hHXPc8UKu7OoLDNz5jSAVFWNB+4C3gGeBJ5W1Z5AReDSPNUuAaJU\ntQfwNPCcP3RLTFxHrVpxNlZCCGONJ3alvayyceNGcLKwqqoCbYDlQA0RicCksD6Wp1oSECUikUDV\nfK6XmLS0NDZv3mT9O0Mcvw7bRWQYMMw5jAY6Ao2AD4HqQDlgqKqm5Km3DDMMA9ioqn7JoLlixTLK\nly9P27Zn+OP2Fj/jpH4eICLTgW5AfSAFeBuTifUg8HOeaqmYIXsiUAsYUJic6tVjiIo6OYWGp3zx\nmzaZWYBOnTr4Na98sHPWh7t8vxpPVZ0ETAIQkXeBj4GXgSmq+rmInA+0xjR4nHLRQISq9vanbpmZ\nmaxZ8ydt255BxYoV/SnK4icuvXQg48Y9fwj4DUgAlgKvA71UdY2IjAJexcyFuhkNzFbVh0WkITBX\nRNqr6tGC5Ozfn37ScVxcFXbvPlygXosWLQWgceMWHsuVhMJ08DfhIt+TgQ7IgpGIdAHaqeooEXkA\nWCUiPwKbgHvyFO8AxIjIHEe/R1R1kaf7F7VnALBs2TIyMjKIjz/bL2+wYL8Vw0H+8uXLAX5S1dFO\nG2uMGYq7Ry07gLy5ovdzYqi+DyiPGQH5DPeedrvSHtoEarX9EWCs87kJsF9V+4jIE8BDwBO5yqYD\nrwATgJbA9yIiqppV0M2L2jMAmDdvPgCtW7f3+RssXN7KwZZfuXItgHtF5FHgAHATZuX9fyKSBWQC\nNwOIyKeYofzrwMci8htQAfNyTvOlXieiKbX25W0tpQy/G08RqQaIqs5zTu0FZjifZ3LqamcSkKyq\nLiBJRPYCdYGtvtTLrrSXfapVq4aq9slzOr/eJqo6NNfh1f7UKzFxHXXr1rOBZkKcQKy2nwv8lOt4\nPsZdxH1tTZ7yIzDzVIhIPcww7C9fK7VixXKio6PtiqjFpxw8eIAdO7bbdhUGBGLYLsCGXMf3ARNE\n5HbMaugQOGlY9REwSUTmAy5ghKche3E4cuQI69atoVOnzkRFhfU+AYuPMR5T1jk+HPC75VDVcXmO\nNwN98ymXe1g1xJ86rVmzmuzsbOvfafE5J3YW2Z5nqBOWTvJ2vtPiL6zxDB/C1Hi6Y3h2DrImllDD\nvU2+VSu70h7qhKnxXEblylVo3rxFsFWxhBjr1q2lUaMmNkpXGBB2xjM19TDr1yfRoUNHm0vb4lP2\n7NnDnj27bQzPMCHsrMeqVStxuVx2vtPic9zO8XZnUXgQdsbTnXbDrrRbfI1dLAovws54rlxpV9ot\n/mHdOve2TOvjGQ6EnfFcvnwZ1atXp3HjJsFWxRJiqK4jMjKSFi1aBlsVSwDwykneCRzbHTgfE9jj\nNMwe9S3AHFVd4i8Ffcn+/fvYvHkTvXtfYNPBWnyKy+UiMXEdzZo1Jzo6OtjqWAKAR+MpIhWB2zBh\n45pwwmCmY6J21wOeFZGtmEhI/1bVDH8qXBJsjnaLv9i5828OHjxAr17nBVsVS4Ao0HiKyLmYsHD7\ngLeAr1V1Sz7lWgP9MeHARovICFX92T/qloyVK43xtDnaLb7mRAxP6xwfLnjqeb6MySz4i6cbOJkH\nE4E3RaSPU+9s36noO+xKu8VfuFMNt2ljF4vChQKNp5ORsEio6o/AjyXSyI+sXLmc2rXrcPrpdYOt\niiXEOBEA2RrPcCFsVtt37tzJjh3b6dTpLLtYZPE5iYlrKV++PE2bNgu2KpYAUaSQdE5ytqeBK4HT\ngV3AdOAJVQ1e3gcvsP6dFn+Rk5NDYmIiLVq0onz58sFWxxIgihrP8zVMcON/YRJp1cOsxH8MXOVb\n1XyLne+0+Itt27aSnp5mcxaFGZ5W23uo6oI8py8ABqpqUq5yO4H/+Uk/n2FX2i3+4sS2TDvfGU54\n6nn+V0RWY7ILrnLOLQTeEZEPMD3P04ExmLzZpRaXy8WKFcto2LARtWrVCrY6lhDDvdJujWd44WnB\nqCUmcdtsEfmviDQH7gD+xAzfvwVeABYDN/pb0ZKwffs29uzZY+c7LX7BbTytj2d44clVKRN4XUT+\njeldLgKmAU+r6hhvbi4iw4BhzmE00BFoBHwIVAfKAUNVNSVXnUjgPaADkAGMVNXkIj1VHtzznR07\n2iG7xfckJq6jUqVKNl5CmFGoq5KqpqnqM5iFov3AChF5VURqelF3kqr2VtXewFLgbowT/RRVPReT\nLTPv6/pyIFpVu2MWpl4tygPlh3u+s2NH2/O0+Jbs7GzWr1datWpNuXLlgq2OJYB4NJ4icoGI3Cci\nVwD7VfUh4AxMLzJRRJ4SkSqFCRGRLkA7Vf03cA7QQER+BK4Dfs5TvCcwC0BVFwFdivhMp+DueXbo\n0LGkt7JYTmLTpg1kZGTYIXsY4mm1/QlMz28l0Apj6K5U1b+BUSIyDngKWC8ir6jqKx7kPAKMdT43\nwRjiPo6Mh4AncpWtisnn7iZbRKI85W6vXj2GqKiT3/pxccamu1wuVq1aTsuWLWnRoqEHFX2LW36w\nCHf5gcLG8AxfPK22jwKGq+pnzmJRkog0UNVtAKq6CRgmJufAMwXdRESqAaKq85xTe4EZzueZwHN5\nqhwCcv/nRXoynAD796efdBwXV4Xdu43P/oYNyRw8eJALL+x3/Jy/yS0/GIST/GAb6RPbMm3PM9zw\nNGzPxsTtBKgGRAA5eQup6jpVHezhPudiVu3dzAcuyXVtTZ7yCe7rIhIPrPZw70Jxh6Gz850Wf2Dd\nlMIXTz3PF4D3ROQpoCbwsaruKIYMATbkOr4PmCAit2OG50MARORTzALSNKCviCzAGOzhxZB5nBMr\n7TZHu8X3JCaupXLlKtSv3yDYqlgCjCdXpbdFZA5wJrBJVf8ojgBVHZfneDPQN59yQ3Md3lYcWfmx\ncuVyIiMjad/+TF/d0mIBIDMzk5SUZDp06GSDzYQhnhaMyqmqAlqUGzr1skusmQ/Izs5m1aqViLQm\nNjY22OpYQoyUlGSysrJsDM8wxdOwfaWIPKaq0729mYhcDTwJtCuxZj5g/fok0tPT7M6iECUzMxMR\nmQo0wyw0jgJigfeBLCAJs8nipLl6EXkYGAhUAN5T1Y+KI9+mGg5vPBnP6zFzky8CnwFfA3/m7lWK\nSHmgK9APs0UzFRiaz72CwooVdmdRKDNz5jSAVFWNFxEB3sHk13paVb8TkSnApRivDgBEpDfQA+Nv\nHAPcX1z57pV243BiCTc8zXmuEJFuGP/O0cDjQKaI/I1poKcBtYDywFqMz+d/SsuQHXIbT9vzDEU2\nbtwI8D2AqqrjNjcBqCEiERiXt2N5qvXHeHBMw/gUP1Bc+dbHM7zxGM/TMYSfAp+KSFugNyenHt4K\n/JQ7RF1pYsWKZZQvX5527doHWxWLH2jZshXAABGZDnQD6gMpwNsYz42DnLqDrRbQGBgANAVmiEhr\nVXUVJKegTRjr1ydSs2ZN2rVrHpQFo2D7uIa7fK+DIavqWkwPs0yQmZnJmjV/0qZNOypWrBhsdSx+\n4NJLBzJu3POHMCEREzDxE14HeqnqGhEZhYmNMCpXtb1AohP4RkXkKBCHyYqQL/ltwtiyZRcpKSnE\nx/dgz55Unz6XN4TTRohgyvdkoEM2h1Fi4loyMjLsfGcI4yzY/KSqPYEvMP7E+zCLRwA7MNG7cjMf\nuEhEIkSkHmaBaW9RZa9fr7hcLrtYFMYUNQ1HmcHuLAp9GjRoBHCviDwKHABuwqy8/09EsoBM4GY4\nsQlDVb8RkXOB3zGdh1HFmac/kafdGs9wJYSNp11pD3WqVauGqvbJc3oHZiX9JHJvwlDVB0sqWzUR\nsHnaw5mQM561a1c96fiCC078H+3adShvcYulSORtX5dddvHxz7Z9hRdezXmKyDgROcPfylgsFktZ\nwdsFo4GYHUcrRGSMiNT1p1IWi8VS2vHKeKqqAPEYn7kHgC0iMltErheRGD/qZ7FYLKUSr12VVPUP\nVb0X44g8ANiECVu3U0Q+EZHz/aOixWKxlD6K7OfpBFk4ABwGjgKVgPbAHGdYb7fzWCyWkMfr1XYR\naYcJXHwtZovmWkwK4f+o6g5nHvRb4H+UkqhKFovF4i8iXK4Ct/QeR0RWA20xOzH+C3yiqsvyKfck\ncI+q1vC1ohaLxVKa8LbnqcCjwHeFJGObDPynxFpZLBZLKcernieAiDQDzlHVyc6xADcAH6jqVv+p\naLFYLKUPb53ke2Lyt+eOfVgdE/h4uYjYBEEWiyWs8Ha1/SXgB+B4CkpVXQS0AH7BhAGzWCyWsMFb\n43km8I6qnhSV24mJOB6TisNisVjCBm+N5wGgoNhbLTC5iywWiyVs8Ha1/TPgWRHZD3yjqodEpApm\np9FzmFQdYYeIvAN0wSykZTvnymEim89V1cc81H0WqOzs2vJW3nzMDq+DgAuoCCwGblfVox7qjQQG\nqOrlRZDVEJiqqr1EpDnwgqpe7W19S+AIQjv8D3A+sDvPpX6qWmBEfhHZhrEZtYBXVLWjtzJLI94a\nz8eAVhiV+0wRAAAgAElEQVQ3JJeIHMMkfosAvgEe9o96pZ77gSWY53/WOfcwJu3tk36SOdqdDlpE\nIoGvMMn3/uVLIY4HRS/nsCnm+7eUToLRDsep6ht+uneZwCvj6fRqBopIB0za1uqY3s8CVV3uR/1K\nNap6VET+CSSIyDeYl8kdQNdcPYDLgUcwL5s04D5VXZz7Ps4b+XPgXExyvXGq+m8v5OeIyDzgAuc+\n5wEvA9GYKOqPquqcPLLOwcQkiAbqAt+r6i0i0gL4EUgGGmLc0OYAtTF50OuLyHeYnm5zd3BhR+Yr\nqmrnvYNEsNthnnv8B1jiNqx5j0OJIu1tV9WVqjpeVZ9X1XfdhtPJ3x6WqOpqzAaCCcDHwE2quh1A\nRFoDY4H+qtoJ06CniUh0PreKVtUuwIXA8062Uo+ISA3gamCeiMRhGv4oVe0AjACmikijPNXuAR5R\n1bMxu8YGOy9FMFklH3eiaO1zni8TuM181EuAfwOXiUg1p86tGONqCSJBaIcPOLEs3D/Dff1MpR2v\nep6OcbwFOA8zz+bOsxoBxACdgLDdkqmqb4vIYGCtqn6f61I/zBzlPLOnADBzlc3zuc07zr22iMgP\nQF/yz1b6uog8xYnvYIZT91JMVsglzn1Wi8hizHeWmxuAS5y8P60xPdDKmN5IJqZn6elZ/xKRWcB1\nIvIZptc70lMdS2AIcDu0w3Yvy72M6bGsAuoARzCTxe2BCsDTftGubLERkzM8N+WA2ap6nfuEsxCz\nPZ/6ube9RgIFJSU7PueZG2f+My+RmGGau0wEJkXvEmA2JohLD04Y4iNO1KzCeBfj2xsFfK6q6YWU\ntwSOQLXDgnBxoj2BsQ8hibfD9quBl5zVsbeA5araDeOmlEyuf1DLSfwEXCwirQBEZCCwAtPby4t7\nDrEJZsg0q4iyFgLtRKSLc5/2mERoP+cqUxPoCDykqtMww/SmmH8uT2SR6ztW1V8x/xT3YofsZYFA\ntsPdmJV/RKQ2+STjCxW8NZ5xmJ4KmG2a3QBUdQfwPMa4WvKgqquA24HPRWQl8AQwsICeWgsRWYYJ\n6zdKVZOLKGsncA0w3omCNRm4QVU35CqzBxgHrBCRpZhV2gWYl6AnVgPlRGRhrnMTgS2qmt+QzlKK\nCGQ7BN4EGotIIvAJJ7+8QwpvQ9Jtx/gSznBWZRWorap7ndXW71Q11s+6hixu/zdVXRFsXbzBmQOf\nAUxQ1a+CrY/FN5S1dhhsvO15zgaecgIipwC7gFGOI+5VwE4/6WcpZThBYHZhhmfTgqyOxRI0vO15\nno4xoHtV9QIRuQnjspKDMcBjVPVNv2pqsVgspYiixPOMAOqr6jbn+DzM3OcfqjrPfypaLBZL6cPb\nnudS4LE8vmMWi8UStnjr59kCkymzVLJ79+GT3gDVq8ewf3/wXA+t/MDJj4urElF4qZJR2tpXadAh\nXOR7al/eLhh9BDwqImeKSCXfqOU/oqIKc1u08kNZvr8pDc8XbB3CXT543/PsBXQA3HvZ0/Jcd6nq\nab5UzGKxWPxJ7dpVC7y2a9ehQut7azy/cX4sxaSkX1SocPDgAdLS0qhXr36wVbGUcnJycti582/q\n1q0XbFXyxduQdGP9rYgltDly5Ajvv/8Ob731OmlpqXTu3JXBg6/hssuuoFatWn6TKyIPAwMx20nf\nU9WPnPNDgLtUtbvfhFuKxYED+/nss6lMnDiBDRtSuO66oTz33MvExMQEW7WT8Daq0tDCyqhqWEaT\nt3gmJyeHr7/+gueeG8v27duoVasWZ53VmYSE31i69A8ef/xfXHBBHwYPvoZ+/S726T+IiPTGBD45\nBxP9637nfCfgJk4OYGEJMqtXr2TixAl89dXnHDlyhIoVK9K4cROmTPmUJUt+58MPP6F164KyARWN\nY8eOFV6oELwdtk8q4LwLyMDkMLLGMx/S0tKYNu1Lj2Wuu+4q4uPPoUePczjzzI6ULx8acVYWL17E\nk08+zLJlS6lQoQJ33TWae+4ZQ9Wqp7Fz599Mm/YlX375OXPmzGLOnFnExlZmwICBDB58DT17nkvd\nutULvLeXUx39MfvypwFVMTEoa2LiMdwLfFjypywaLpeLjIwM0tLSSEtLzfM7jfT0tOOf09JSycnJ\noUOHTnTt2o2aNWv6TI+srCxWrFjG/Pm/Mn/+b2RmZtC+/ZmceWZHzjyzIy1btiIqylvzUHwyMjKY\nMWMaEydOYMmS3wFo1KgJw4bdxJAh1xMbW5mxYx9jwoQP6N+/N88++xLXX39jiWRu2bKZW28tefhR\nb/0881sMqoyJOP08cL2qJpRYm2KS15UkLq4Ku3cfDpY6xMVVYcGCpUyaNIHPPvsvhw4d9LpuTEws\nXbueTY8ePenevSedOp1FxYoViyw/mM9/+PBuRo++nxkzzO7Nyy+/gkcffYrGjZvkW141ka+++pyv\nvvqcrVu3AFCnzuns3Pl3gTLcxtOTK4mIfIiJHDUAEz3qG0xsyn9hwir+T1XjC3uerKxsV0lXdzdu\n3Mh5553Hjh07yM4uapQ3Q+vWrenZs+fxn2bNmhERYR7f/Ts/XC4XOTk5rFy5krlz5zJv3jx+/fVX\nDh8+0UYiIyPJyTkRjbBSpUp06NCBs846i7POOovOnTvTtm1bKlQoeoQ5T7rFxcWxe/duIiIiuOSS\nS7jjjju46KKLiIw82RFo+vTpjBgxgv3793PttdfywQcfULVqwesIBTF9+nSGDx/OgQMHPJbLZRcL\nVN7rHUYF4WzVvN2JPh0USovxPHbsGLNmfcuUKZOYO3cuALVr1+GGG4bx6qsvFVhv5cpEFi5MYOHC\nBSxcOJ+kJD1+LTo6ms6du9Kv38UMHnwNcXFxheoRrOc/ePAAb7zxKh9+OJ7MzEw6d+7C00+/QNeu\n3byqn5OTw++/L+bLLz9jxoyvPTZwL43ni8BuVX3VOT4CbMLEYojGRNL/uLDkZ75oX1OnTubee0fR\nokVLGjRoSGxsZWJjY52f/D6b35mZmSxbtoTFixeyZMkfpKWdSFRbu3YdunXrTrdu8Tz2WMEprC69\ndCALFvzG/v37j59r0aIlPXueS69e59GjRy8qVarE2rV/smrVSlatWsGqVStJTFxLVtaJ8J4VKlSg\nTZt2nHlmB845J57KlasTHV2JSpUqER1diZiYSlSqFEN0dPTx3xERER4XS6tXr86QIUO58cYRNGnS\n1OPfcNu2rdx66wj++GMxzZs3Z/z4j+jY8Sxv/vxkZGTw9NOP8+GH71OpUiVeeOEV7r13VIHlvWlf\nvjCefYCZqho0/89gG8+//trB5MmTmDx50vHeUs+e5zJ8+EguuuhSypcvX6TV9t27d7NokTGkCxYk\nsG7dGlwuF1FRUfTrdzFDhlzPBRf0LXBYVZTn94UXQFZWFp9+OpFx455n7969NGrUiEcffYrLL7/S\nY6/DExkZGTRsWPCLwkvjOQATxLsfJl/Tr4CoarYTr9Krnqcv2tczzzzJ22+/zowZs4iP71Gkum6y\nsrJYu/ZPFi9eyIoVS/j119889s5z07BhI3r1Oo+ePc+lZ89zOf30uoXWycjIYN26NY5BXcmqVctZ\nu3YNmZmZXutcqVIljhw5UuD1zZt3UqmS96bj2LFjvPzy87z11mtERUXxxBNPc8std3hsZxs2pHDL\nLcNZtWoFIq2LNHdaYuPp5MrJSyRQDxO/L05Vz/BKGz8QLOO5YUMKzzzzJLNmfUt2djZVqlTl2muH\nMHr03dSq1cBncvbs2cO0aV8wZcpk1q79EzDD2quv/if//Of1tGjR8qTygTKeLpeLn36aw1NPPUZS\nklK5chXuvfc+HnnkQVJTszzW9ZVuhe0wEpGXMWlyIzG5m2Y755sQQOM5bNh1fPfdTP78M5natWsX\nqW5+xMVVYdeuQ2zZspnFixdy5523Flj2jz9WFThlUlSOHTuGaiKbNyexadN2jhxJ5+jRoxw5ks6R\nI0eO/xw9euL38uXLCrxfcd30li9fyHXXXc+ePbvp3/9i3nzzPWrUOHVOePr0rxgz5m5SUw8zZMgN\nPP/8uCItSvrCeOZgFodOqY/ZtnmVqn7rtUY+JljG8+KLL2Tp0j9o374Dw4ePZNCgwcTGxvpNvsvl\nYvXqlUydOpmvvvqCgwfNsPbss+MZMuQGBg4cROXKlX1mPIcOHUFq6mHS0lJJTU09/tv9k5aWisvl\nIjIykuuvH8aDDz5C7dq1ffb8vjCevsAX7eu88+LZtm0byclbi90b96RDoP2IAz26yU/+n38mc8cd\nN/Pbbz9Tr1593n//Y+LjjefZkSNHeOyxfzF58kRiYmIZN+51rrrq2uLIKbHxHMapxtMFHALmqar3\nKyJ+IBjGc/XqlVx4YS/69OnHlClfnPQPEQj5R48e5fvvv2Hq1Mn8+uvPuFwuYmJiufzyK7jjjltp\n2bI9ERER5OTk8Pfff7Fly2Y2b97E5s2b2LJl8/GfHTvyS2OTP5UqVSI2tjKVK1c+/rt+/QbcffcY\n2rZtd7ycNZ4nk5OTQ+PGdWjdui0//PCLT3SyxtPIz87O5q23XuOll54jIiKCBx98hEsu+Qe33DKc\ndevW0K5dez78cNIpo7MiyCmwfXnrJD/JCUnXWlXXwfH8JGcCwVvWDSKTJn0EwPDhI33Skygq0dHR\nDBo0mEGDBrN16xY++2wq//vfFKZOnczUqZNp3LgJ5cqVY9u2rfnOUUVGRha6y2f+/D+oXPmEsSxX\nLrD7iUNl59X27dvIyMigefP8klVaSkK5cuUYPfoBunfvyW23jeCFF57hxRefxeVyMWzYTTz99AtE\nR+eXqqnkeOsk3xD4DuNo7G4BZznnFonIQCc/Tlhw6NBBvvrqcxo2bMQFF/QNtjo0bNiI++//F2PG\nPEhCwm98/fX/+Prrr4mNjeWMM9rTqFFjGjVqQqNGjWnc2PyuX78BFSpU8NgraNVKCrxm8Z6UFJMG\nqFmzwlJFFZ/S/KIJhG7x8d2ZO3c+o0ffxaJFCbz88utcdtkVfpXprRfs65j5zePaqOosJy3HZ8Ar\nwDCfa1dK+eKL/5Gens7o0cMD3hvzRGRkJL16nccVVwxg165DQekRW07FbTybN/ef8bRAjRo1+eST\nqeTk5JziJ+oPvDWe5wNDVXVl7pOquk5EnsCk5AgLXC4XEydOoHz58gwZUuiu1aDhreEszT2WUGHD\nBms8A0kgDCd4H88TzJC9oHsUbQtMGWbhwgSSkpR//OMyrxzWLZYTw3Y75xlKeGs8fwLGikij3Ced\nudCngB99rFepZdKkCQAMGzYyyJpYygopKcnExdWmalUb8jaU8HbYfj+QAKwXkTWY1LNxwBmYrW5j\n/KNe6WLnzp18++1M2rRpS7duNpKZpXAyMzPZunULZ59dqC++pYzhravSFhFpC4wAugM1gA3AfzB7\ng/P18xSRisBEoBnGJ3QUJqDIN8B6p9h4Vf0sV51I4D1M5PoMYKSqJhf90XzP1KmfcuzYMW688Sa7\nGGPxis2bN5GTk2PnO0OQosScSgXmuPOze+nneTOQqqrxIiLAO8AXwGvuYA35cDkQrardRSQeeBW4\nrAh6+oXs7GwmT55ETEwsV111TbDVsZQR3POdTZva+c5Qw6s5T2duczUnp+I4C5gDzBeRgkKBtwW+\nB1BVBdoAnYFLReRXEflIRKrkqdMTmOXUWQQELVpTbn78cQ7btm1l8OBrqFKl6KGwLOGJdVMKXYri\n5wlF9/NcAQwQkelAN6A+sASYoKpLReRR4EmcCN8OVYHc0wDZIhKlqgVGmqhePeaUbHpxcXltcsmY\nOnUSAGPG3O3VvX0tv6iEu/zSgnVTCl387ef5Maa3+RtmwWkp8JWqugM1TgPezlPnEJD7Py/Sk+EE\nTsnf7Ou95Zs2bWTWrFl07dqNevWaFXrvYAcjDif5pd1Ip6QkExERUWisSkvZw99+nl2Bn1S1J2au\ncwMwW0TOdq5fiDGouUkALgFw5jxXF0FHv/DppxOP75W1WIpCSkoyDRs28tv+akvw8Lbn6fbzXKyq\nW9wnnbnQsRTs57keeMYZnh/AJN06HXhbRI4BfwO3OPf6FHgM0xvtKyILMFtCS55spARkZGTw3/9O\npkaNGvzjH5cHUxVLGSM19TA7d/5N794XBFsVix/wq5+nEyykT57TOzDZDPOWzb3X8TYv9fI7M2dO\nZ+/evdx5572292ApEhs2pAB2vjNU8WrY7vQ22wIPAklOvQ3AQ5jV8aD2Dv3JxIkTiIiIYOjQkH1E\ni5+wxjO08drPU1UPY1JuvCki5TH+mDcB4zDG9Cl/KBhM1qz5kz/+WMwFF/SxE/6WImP3tIc2RUrM\nLCKtgZHADUAtzJD9HWCK71ULPicCHt8cZE0sZZFAxPG0BI9CjaeIVAKuwRjN7ph815WAO4EPVDXH\nQ/Uyy+HDh/jyy89o0KAhffr0C7Y6ljLIhg3JlC9fnoYNGxVe2FLmKHDOU0S6iMj7mBXxCUAaMBRo\nhVkFXxOqhhPgiy8+Iy0tlRtuGFaqAh5bygYul4uUlBSaNm1m20+I4qnn+TuwBngC+FxV/wIQkZCP\nq+Vyufjkk4+Iiooq1QGPLaWXvXv3cvDgAbp3P8WxxBIieDKeKzGBP4YCcSIyxZ38LdRZvHgR69at\n5fLLr6BOnTrBVsdSAkTkYWAgUAETrWshZkdcBMYPeWRhO9iKg93THvoUOGxX1U4Y4/kTZt/6nyKy\nBBNWzkX+edxDAhvwODQQkd5AD4xf8XlAQ+B54BFVdXcJ/+EP2XZPe+jj0c9TVdeo6oNAI8yWSQUe\nwby1x4nIHSISUl2z3bt3M3PmdERa2yFX2ac/ZnvvNGAmJirYlar6q4hUwOx2yzcWbUmxPp6hj7fB\nkHOA2Zh96ZWBqzDuSm9j/D7nq+r5/lMzcPz3v5OdgMcjbMDjsk8toDEwAGgKzABai0hjzJbig5jp\nKY8UJ2rXtm2bADj77I5+C14S7KAo4S6/SH6eAKqaiokOP9HZ2z4UuN7XigWD7OxsPv10IjExMVx9\n9T+DrY6l5OwFElU1E1AROQrEqepmoKWIjAReA270dJPiRO1auzaR2NjKREbG+CXCVDhFzgqmfE8G\nukQ5OlV1q6o+p6ptSnKf0sLcuT+wZctmrrzyapusKzSYD1wkIhEiUg+IBT4SkZbO9cOAz93tcnJy\n2LgxhebNW9jRSwhT5J5nKOPeUWRDz4UGqvqNiJyLcbuLxCx2HgYmiUgmkI7Z/OFTduzYztGjR2ne\n3G7LDGWs8XTYsmUzP/44h86du9K+fYdgq2PxEc6CZ178uhJot2WGByUatocSX3/9BS6XixtvHBFs\nVSxlHOvjGR5Y4+kwf/5vAPTte1GQNbGUdayPZ3hgjSeQmZnJH38sok2bttSsWTPY6ljKOG4fTxuK\nLrSxxhNYsWI5R44csU7xFp+QkpJMrVpxnHZatWCrYvEj1ngCCxfOB+Ccc3oFWRNLWSczM5MtWzbb\nXmcYYI0nsGCBMZ7x8bbnaSkZW7ZsJjs72853hgFhbzyzsrL4/ffFtGolxMXFBVsdSxnHrrSHD371\n8xSRipitnM2AQ8AoVV3vXBsC3KWq3fOpt8wpD7BRVf2WfW3VqhWkpaXSvXtPf4mwhBHWxzN88LeT\n/M1AqqrGi4hg8h31F5FOmORxp+xdE5FoIEJVe/tZNwAWLEgAoEcPO2S3lBzb8wwf/D1sbwt8D6Cq\nCrQRkZqYmIr3FlCnAxAjInNEZK6IxPtTwQULjH9njx6252kpORs2JBMREWGzrYYB/u55rgAGiMh0\noBsmGO0kYAwmkVx+pAOvYPImtQS+FxHxFO27OCHDwERR+v33RbRs2ZIzzmhZaPmiEOxwWeEuP1ik\npCTToEFDKlWqFGxVLH7G38bzY6AN8BuQgIk+3wwYD0QDbUXkDVXN3QtNApJV1QUkicheoC6wtSAh\nxQkZBrBy5XIOHTrEwIGDfBreKlzCdZUG+aXJSKempvL3339x3nkhEdrWUgj+HrZ3BX5S1Z7AF5hE\ncu2c+cxrgbV5DCfACOBVACeMWFXgL38od2K+0w7ZLSVn48YNgJ3vDBf83fNcDzwjIo8CBzCLRPki\nIp8CjwEfYUKGzcf0VEf4I0EXnHCOt8bT4gvce9qtg3x44Ffjqap7gD4FXNsExOc6zp3jd4g/9QIT\nsHbRogU0btyEevXq+1ucJQywK+3hRdg6ya9du4YDBw7YXqfFZ1gfz/AibI2n20XJBgOx+IoNG5Ip\nX748DRs2CrYqlgAQxsbTLhZZfIfL5SI5OZkmTZoSFWUTNIQDYWk8zXxnAg0aNKRRo8bBVscSAuzb\nt4+DBw/Y+c4wIiyNp2oi+/bts0N2i884sdJujWe4EJbG0x2Czg7ZLb7CrrSHH2FpPBcutPOdFt9i\nU2+EH2E3s+1yuViwYD5169azwRvCABF5GBgIVADeA5YCbwPZQAYwVFV3llSO7XmGH2HX80xOXs+e\nPbvp3v0cIiJOiYhnCSFEpDfQA5On/TxMYJo3MXFkewNfAw/5QlZKSjIxMbHUqXO6L25nKQOEXc8z\nIcGGoAsj+gOrgWmYGAkPAB+oqjtWQhRwtKRCcnJy2LgxhRYtWtkXchgRdsbT7mcPK2oBjYEBQFNg\nBtAaQER6AHcC5xZ2k8JCHm7dupUjR47Qtm3rgEZ5CnZEqXCXH1bG08x3JhAXV9vOTYUHe4FEVc0E\nVESOAnEicj7wKHCpqu4u7CaFhTz8/fcVANSv3zigofjCJexgMOV7MtBhNee5cWMKO3f+TY8ePe3w\nKjyYD1wkIhFOeMNY4GJMj7O3qm7whRC7WBSehJXxdG/JtM7x4YGqfgMsB34HZgKjgNeBKsDXIvKz\niIwtqRy3m5I1nuFFWA3b3c7x55zTK8iaWAKFqj6Y51QNX8uwcTzDk7DpebpcLhYuTKBWrVq0aiXB\nVscSQqSkJFOzZk2qVasebFUsASRsjOfmzZvYvn0b8fHWv9PiO44dO8bmzZvsnvYwJGyM54ktmXa+\n0+I7tmzZRHZ2tp3vDEPCxni65zu7d7f+nRbfYVfaw5ewMZ4LFyZQvXp12rRpG2xVLCFESoo7IIg1\nnuFGWBjPbdu2smXLZrp160FkZFg8siVA2J5n+OJXVyURqQhMBJoBh4BRqrreuTYEE6Che546kZjo\nNx0wUW9GqmpySfQ4Eb/TzndafMvGjabn2bRpsyBrYgk0/u6G3Qykqmo8cBfwDoCIdMLkcM9v2fty\nINoxqv8CXi2pEjZ+p8VfpKQk06BBQypVqhRsVSwBxt/Gsy3wPYCqKtBGRGoCzwP3FlCnJzDLqbMI\n6FJSJRISfqNq1dNo1659SW9lsRwnLS2NHTu207SpdY4PR/y9w2gFMEBEpgPdMPEUJwFjgCMF1KkK\nHMx1nC0iUaqaVZAQT1Fvtm/fzqZNGxkwYACnn16tuM9RZIId8SXc5QeCjRvN1vjmza3xDEf8bTw/\nBtoAvwEJgAsz/zkeiAbaisgbqpq7F3oIs/fYTaQnwwmeo97MnDkLgM6d423EmxCUH0wj7d6WaReL\nwhN/D9u7Aj+pak/gC+BzVW3nRPG+Flibx3CCMbKXAIhIPCaYbbE5kZ/dLhZZfItdaQ9v/N3zXA88\nIyKPAgcwi0T5IiKfAo9hon73FZEFmAWl4SVRYOHC+VSuXIX27TuU5DYWyym4jaf18QxP/Go8VXUP\n0KeAa5uA+FzHQ3Ndvs0X8nfu3Ely8nouuKAPUVFhFUDKEgBSUpKJioqiUaPGwVbFEgRC2mN80SLr\nomTxHxs2JNOkSVP7Yg5TQtp4upO92eDHFl+zb99e9u/fb+c7w5iQNp4LFyYQExNDx45nBVsVS4jh\njh5v5zvDl5A1nnv27EE1ka5du1G+fPlgq2MJMU4sFlkfz3AlZI2n3ZJp8SfWx9MS4XK5gq1Didm9\n+/Dxh6hdu2qB5XbtOhQQfcLJST3Y8uPiqvg9LUBpa18QXt9xMOV7al8h2/O0WCwWf2KNp8VisRQD\n66BmCWlE5GFgIFABeE9VP3LOv44J9vV+MPWzlF1sz9MSsohIb6AHcA5wHtBQROJE5HuMQbVYio3t\neVpCmf6YwDLTMKEOHwAqA08BFwdPLUsoYI2nJZSpBTQGBgBNgRlAa1XdKCJeG8/84sXmR6DD4wU7\nZmq4yw8547lr16Ggu1FYSg17gURVzQRURI4CccCuotwkd7xYT+0rkG0u2G08XOR7MtAhYTzz88UK\n9lvJyi8VkeTnA/eIyGtAXSAWY1CLRGlsX6VBh3CXbxeMLCGLqn4DLAd+B2ZisrdmB1crS6gQEjuM\nLBaLJdDYnqfFYrEUA2s8LRaLpRhY42mxWCzFwBpPi8ViKQbWeFosFksxCAk/TzciEgm8B3QAMoCR\nqprsZ5nlgY+BJkBF4FlgK/ANJvUywHhV/cyPOiwD3MEkNwLPAZMAF/AnxkUnx0+yhwHDnMNooCPQ\nnQA+f6Cw7Quw7es4IWU8gcuBaFXtLiLxwKvAZX6WeT2wV1VvEJEawArgaeA1VX3Vz7IRkWggQlV7\n5zo3A3hMVX8Wkfcxf4Np/pCvqpMw/0iIyLuYf/TOBOj5A4xtX9j25SbUjGdPYBaAqi4SkS4BkPkF\n8KXzOQLIwny5IiKXYd6O96qqv/aSdQBiRGQO5vt8xJH/i3P9e6Affmrcbpy/dTtVHSUi4wnc8wcS\n275s+zpOqM15VgUO5jrOFhG/viBUNVVVD4tIFUwjfwyzo+UBVT0X2AA86UcV0oFXMBGEbgOmYHoK\n7t0Ph4HT/CjfzSPAWOdzIJ8/kNj2ZdvXcULNeB4Ccm94jVTVLH8LFZGGwDxgsqpOBaap6lLn8jSg\nkx/FJwH/UVWXqiZh9m7XyXW9CnDAj/IRkWqAqOo851Qgnz+Q2PZl29dxQs14JgCXADhzUqv9LVBE\n6gBzgIdU9WPn9GwROdv5fCGwNN/KvmEEZu4NEamH6R3NcQIBg4lb+Zsf5QOcC/yU6ziQzx9IbPuy\n7ft9AtIAAAcSSURBVOs4oTbnOQ3oKyILMPNDwwMg8xGgOvC4iDzunBsDvC4ix4C/gVv8KP8jYJKI\nzMesfo4A9gAfikgFYB0n5sz8hWCGT25uB94O0PMHEtu+bPs6jg0MYrFYLMUg1HqeFj/h+DgeAPqq\n6mIRuQp4WlXb5FN2ACYEXC9VnZ/rfB3gLyATqK6qR3Jduxr4DGgHXA3cr6qVS6jzJuAbVb2zJPcp\nosyKwGiMi1FzjD/oCuBtVf0qV7mfgVRVHRAo3Sy+JdTmPC3+4wygPLDMOe4OLCig7K9ANhCf53wf\nzGp1Bcw8Vm56An+p6lpgAnC+D3QOBp8A92GGu5cCN2CGnF+KyO25yt3hlLOUUWzP0+It3YGlqnos\n1/FH+RVU1UPOrpTueS71AeZiemR9gdm5rp3jXENVtwHbfKd6YBCRJsA1wLV5drzMdFyNxgLjAZyX\nhKUMY42nxSPO0LdxruPck+TxItJTVYflU/VnzNA1N32Al4HNGOPpvmdljDP2O87xU+QatjsyhwMX\nYXpzGcB/nDJZTpnTgbcxDtupwMP5PEst4AXMCnENYBHwoKouEZGOmKjz56vqz075e4HXgQtVda5z\n7j7gQeD0XL6ObuKc3/mN6F4GFotIeVU9lnvYLiKTgBvzqQPQVFU3iUgs8CJmSqMqsBgYrarLC6hn\n8TN22G4pjEGYHuRGjIN2d8yK61FMTvRnCqg3D6grIo0BRKQ10AD4AfgR+P/2zjVEyjKK4z+zIkQQ\nESSIPkkcMu1Lil101axdaKsvZSlBJLEgVFQUEmRklBDdKCkw/FBUhlKIEeiSK5umruYQbhb4pzZE\n7aJSFmlXsT6cM+07szPv2MD66fzgZd59LjPPPMP+3/Oc81ymhw8UfHg/ltrpKPW8DBzHl0i+BjwI\n9MR7j8Wt2Bl45PUR3Mq7pFo5BHoXLuCP4RbiGGC7mU0HBvHI7fWFz5wXr7MLaV1AbwPhBPgc+BZY\nbWbPm9ncWN6IpL2SXihY7kWexvu1enUBJ3BL/LCZjcFP/lyE/wYL8f7/2MymNO+yZDRJ8UxKCctm\nELgUeF/Sbtz3uU/SgKShJlU/wZcSVofuNwJHJB3Al/adxoUMXJy+lnSopCm7JD0gaaukJ3Er8abI\n6wauBBZLWi9pHXAbtSOrJbi7oFvSO5I+xEXqOLAixLCX8LVGgKwjPmdOpF0U95ua9NWf0ZbDwKO4\n9f2zmW0xszubfTFJQ5J2R9/uAe7DV/YsijOXOnFRXyxpTZzNdDMu9o+X9FkyiqR4JqWEVTcDOAV8\nE8sRrwYqZnZ+iMwIJJ3EJy9XxfMG3OJE0il8yLwg8mZTbnUS5YscwU/DBPeXngjxqX7+Z8DBQvkO\n4MuirzGOJN4AzI2kXmCWmY3DxXg88Arunhgb73EBtb7a+u89CEyPNq0kXAHAOjN7t8V3BFiBuxUW\nSjoeafNxMd0WfV59KHzEcB8m55j0eSatGGLY5/lXXd79eHT5niZ1+4EF8c8+D48wV+kD7g5RmgW8\n3qIdv9X9fYbhh/9EfOJ2PT8U7icCRxuUOYr7EMHF6DxczKcClUgbjy8B7AQGJJUuRwwrdldcy81s\nMu6PXWxmawrLDGuIjS6ewDe6GChkTQLGMbL/ARq5AZJzQFqeSStuwYepbwEzcYvqHzxwMRO3lJrR\njweCrsEFqq+Q14cPoztxC7KhoJwlPwKTG6RPKtz/RO2a7CoXR30kncA3nZiPW5nbJX2P79wzB3c9\nbG7WCDN70cwq9emSjjG8CmbEvNioeznwNrBe0qq67F+AY3h/11/XNmtPMrqkeCalSNqPC1O/pAoe\nyf4b2CipIulgSfWdeFBmKbBfUtHy+xTfaKMHGJTUyHI8W/qBCWb2X7DHzAwX5yo7gCtCpKplLsQD\nYjsL5Tbj4nkdPl+VeL0DH4439HcGXwFXmVlng7zL4vWL+gwzmwBsxF0RPQ3q7sAj+SejzyvxW9zF\nyBkNyTkih+1JKeHTnMrwJhjTgANNosY1SDplZnvx6PCrdXmnzWwbHviot7T+L1twgVtrZstw/+wz\n1A5z3wAeAjaZ2XLcmnsYt0ZXFsr14psNn8FFi3jve4HvJO0racebuAtjY2zcuxX4Hd//chnwgaTt\nDeqtxXeKXwRMrfMjD+GrtfZG258CDgG3426QpSXtSUaRtDyTVkzBjz+oBlqm4VNyzpZ+PMjS1yCv\nL/JaBYtKCR/jrbjwrQJW40I2WCjzKz4U34NPdVqHC2RH3VzJCh6BH5RUPXqiuPFvWTv+wKPiz+JD\n/PeiTUuAl/CHSCO68VVXG6J9A4WrOyLuXfhD4jnc+p0DLJHUylecjBK5MUiSJEkbpOWZJEnSBime\nSZIkbZDimSRJ0gYpnkmSJG2Q4pkkSdIGKZ5JkiRtkOKZJEnSBimeSZIkbZDimSRJ0gb/AvFKfXDY\n/kwwAAAAAElFTkSuQmCC\n", 64 | "text/plain": [ 65 | "" 66 | ] 67 | }, 68 | "metadata": {}, 69 | "output_type": "display_data" 70 | } 71 | ], 72 | "source": [ 73 | "# fig=plt.figure(figsize=(5,4.0))\n", 74 | "\n", 75 | "fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2,2, sharex=True, figsize=(5,4.0))\n", 76 | "\n", 77 | "\n", 78 | "stride = max( int(len(x) / 3), 1)\n", 79 | "\n", 80 | "\n", 81 | "ax1.plot(x,y_1,color='k', marker= 's', markevery=stride), ax1.set_title('Yahoo!')\n", 82 | "ax2.plot(x,y_2,color='k', marker= 's', markevery=stride), ax2.set_title('DBPedia')\n", 83 | "ax3.plot(x,y_3,color='k', marker= 's', markevery=stride), ax3.set_title('Yelp Polarity')\n", 84 | "ax4.plot(x,y_4,color='k', marker= 's', markevery=stride), ax4.set_title('Yelp Full')\n", 85 | "\n", 86 | "plt.xlabel('# Window Size', fontsize=16)\n", 87 | "plt.ylabel('Accuracy (%)', fontsize=16)\n", 88 | "ax = plt.gca() \n", 89 | "ax.yaxis.set_label_coords(-1.41, 1.1) \n", 90 | "ax.xaxis.set_label_coords(-0.10, -0.16) \n", 91 | "\n", 92 | "fig.savefig('filter_size.pdf', bbox_inches='tight')" 93 | ] 94 | }, 95 | { 96 | "cell_type": "code", 97 | "execution_count": null, 98 | "metadata": { 99 | "collapsed": true 100 | }, 101 | "outputs": [], 102 | "source": [] 103 | }, 104 | { 105 | "cell_type": "code", 106 | "execution_count": null, 107 | "metadata": { 108 | "collapsed": true 109 | }, 110 | "outputs": [], 111 | "source": [] 112 | } 113 | ], 114 | "metadata": { 115 | "anaconda-cloud": {}, 116 | "kernelspec": { 117 | "display_name": "Python 2", 118 | "language": "python", 119 | "name": "python2" 120 | }, 121 | "language_info": { 122 | "codemirror_mode": { 123 | "name": "ipython", 124 | "version": 2 125 | }, 126 | "file_extension": ".py", 127 | "mimetype": "text/x-python", 128 | "name": "python", 129 | "nbconvert_exporter": "python", 130 | "pygments_lexer": "ipython2", 131 | "version": "2.7.13" 132 | } 133 | }, 134 | "nbformat": 4, 135 | "nbformat_minor": 2 136 | } 137 | -------------------------------------------------------------------------------- /plots/convergence_compare/yahoo_iteration.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guoyinwang/LEAM/bfd341ccd92009ab6b9e6b0578216f57bb2b921e/plots/convergence_compare/yahoo_iteration.pdf -------------------------------------------------------------------------------- /plots/correlation/Covariance_matrix_yahoo.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guoyinwang/LEAM/bfd341ccd92009ab6b9e6b0578216f57bb2b921e/plots/correlation/Covariance_matrix_yahoo.pdf -------------------------------------------------------------------------------- /plots/correlation/Covariance_matrix_yahoo_label.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guoyinwang/LEAM/bfd341ccd92009ab6b9e6b0578216f57bb2b921e/plots/correlation/Covariance_matrix_yahoo_label.pdf -------------------------------------------------------------------------------- /plots/correlation/covariance.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guoyinwang/LEAM/bfd341ccd92009ab6b9e6b0578216f57bb2b921e/plots/correlation/covariance.npy -------------------------------------------------------------------------------- /plots/correlation/paper_plot_covariance_yahoo.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 3, 6 | "metadata": { 7 | "collapsed": true 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "%matplotlib inline\n", 12 | "import numpy as np\n", 13 | "import matplotlib.pyplot as plt\n", 14 | "import sklearn.preprocessing as sp\n", 15 | "import seaborn as sns" 16 | ] 17 | }, 18 | { 19 | "cell_type": "code", 20 | "execution_count": 4, 21 | "metadata": {}, 22 | "outputs": [], 23 | "source": [ 24 | "m = np.load('covariance.npy')" 25 | ] 26 | }, 27 | { 28 | "cell_type": "code", 29 | "execution_count": 5, 30 | "metadata": { 31 | "collapsed": true 32 | }, 33 | "outputs": [], 34 | "source": [ 35 | "class_name = ['Society Culture',\n", 36 | " 'Science Mathematics',\n", 37 | " 'Health' ,\n", 38 | " 'Education Reference' ,\n", 39 | " 'Computers Internet' ,\n", 40 | " 'Sports' ,\n", 41 | " 'Business Finance' ,\n", 42 | " 'Entertainment Music' ,\n", 43 | " 'Family Relationships' ,\n", 44 | " 'Politics Government']" 45 | ] 46 | }, 47 | { 48 | "cell_type": "code", 49 | "execution_count": 8, 50 | "metadata": {}, 51 | "outputs": [ 52 | { 53 | "data": { 54 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYkAAAE4CAYAAACuSw9tAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzsnXWYXNX5xz+7IYHgBAvuvEjR4u7uVkrR4FKsEAIJLsXd\n3V2Lw68FGrxFin+RAqE4JbiG5PfH9wx7s80m925msrvJ+TzPPjty550zd+6c95xXm4YNG0Ymk8lk\nMiOiuaMHkMlkMpnOS1YSmUwmk2mTrCQymUwm0yZZSWQymUymTbKSyGQymUybZCWRyWQymTbJSiKT\nyWQybZKVRCaTyWTaJCuJTKadRES39D//jjJjLfnizmTaQUQ0S/olImYEDomIZTt6TCOjtSKLiKaO\nGktm1HSmhUdTLsuRybSPiJgGuBa4HvhP+ntN0pAOHVgrkkIbGhG9gFmBjyR90MHDGiuonds6y+yW\nFiBNwLKSHq2n/Kp0Gm2VyXQFWq3wtgB+Av4KHAzsA1zeAcMaKUlBzADcD2wM/DUi1oK8oxgd0mQ+\nNCJ6R8SqETFPPeQmBdEM3AxsERFrjK7MiJitva/NO4lMpiSFFd7kwHTAD8C+wI/AhcCMwFrAIfVe\nXY4OEdEdOA0rifuAf6X/x0n6rCPH1tWJiOmAG4F/An+R9FCd5B6Hr6uT09+HwPWSXm+HrEmBc4DX\ngTckXV/l9XknkcmUpOCDeADYD1hY0j7Ag8AfgCOBqzqDgig41Zsk/YwniHWxclgNeAPYsJ2yx9nd\nR0Q0RcTi6X8TcCjwgKT9JD0UEdtExCrtkNut1UPT4Pn5Cny9zQ0s357xSvoKOB84BFin+FwZGVlJ\nZDKjICKWS/+7A4cD50vaBbgjIvYF3gW+A3aW9HLHjdQUnOozASelMX4EzAO8CswO7AY8UkHmvBHR\nJ92dqN5j7kIsBMwANEsaBrwEvFMwQ85dVWBhh9ocEX0iYj3geOBWrCT+Bkyb3quq3GHpun0H2BNY\nJiL+CJDGP0qyuSmTGQkRsTTQAxiY7M/nAc9LuiA9fx1whCR15DhbExFTArcBNwEPA/8GfgdMCCwO\nHC/p1YoybwDmA/pJursRTtvOTCEAoAm4CrgdL7S3Tvenwed4B0lvVZTdhM1WnwELAE8CZwF7A7MB\nV0i6o4q8pCCmB47Du5GbsUn0IbxA+KekM0clK+8kMpk2iIjZJT0B/B3YLyJ2AG4B5k4rvnWAOYAv\nOnKcRQomhGWBDySdJelFYDFgSUlnA7uXVRCtHPUvA0OBNcEO8fqNvHNTcFJPghcNVwC7AB/jCLcZ\ngIXxbrKUgkjO7qnT3aOBYZJ2B1bGO5L1gYOAndqpIKYAjsHX5yrAAcB/gRWAIdj0OEqykshkRkBE\n9AT6R8QZ2P/wBfAbYEHsAF4SRzftIOnjDhtoojCZj5/+vwR8ERFrpvu9gC/T7e9LyqxNjM0RMRdw\nHbAS0DMiTouIGSNiqvp8gs5LmnRr5rvrgQOBx/AK/RDgR0mnA7uW3VGmaLMekj6NiIWwyXKOiFgu\n+ZAuwCamXyR9XmW8SUFMhHeRb0naFzgbmCSN/Xtgx7JO8GxuymRaUViJzYOjVu6U9PuI2AJYAnhJ\n0uURMYGkHzp2tMOZQabHIbjP4HHPBswMTIr9ELtX9Zkk5XM1nli+B/6BbeQnAYsAm0t6oU4fpdMS\nERPjHcN5tKzMnwK6Y1v/7yV9XVLWr2a6iNgOmBO4F5uCtgKewFFyx0u6v8IYu0n6pXC/Hw6oWCUp\no8Xx7uQMSf8tKzcriUymQMGJOD4wGY4oORyHHx6XTE4z4B9aqUlhTJAS5QYAg4ApgJ+B17CJaE7g\nBUnvtkPusdjpfQPwF+Au4DJJ70fEvFX9Go2g0b6RiBgP6Ak8h80/e2Nl0R9YDu8kKi0WkllwKqzE\nNwQGY8U+B1Y6V0g6u+xnKywUZgL2wmbB04E9gDWADSV9EhHjS/qxylizkshkEq1W5Odgm+0twDDg\ncTxJDAKOlfRl25LGHGmyGQ+4A/gy7XgmxtFLMwE3SHq8grzWq9GjsJJYBjtqJwB6Srqojh+j3RS+\ns6lw7sqQeiquZHa8DIc398ILh0+wbf9cYFtJn5aUdTxwkqT/RsTNwCxY2XyEd6g/4utsJuwA/3PF\n725q4BrgVBzq+lu8IzkU+6RWw36PSpN+9klkMola9iw2KzyKf2T98KpsSTw5XNgZFEQhrr5bsmEf\nDCwWEZtL+gYn970FvFlBZi10tikilkmr0ttxOObnwP9h5fN2PT/L6JC+s+mAe4C1cTb5eqMjs+is\nl/Q9MBA4Ezt7/4Uz6y8F+pZVEIluwOMRcS7O0t8Br/KnAJ4FJsahqndi38cod36tch2WBl4AhHck\nNwB/kNQX+J2koVUVBOSdRCYzHBGxFf4xX4dXZdPi3cNpkp7ryLHVaGVaOAX4Btu0PwYuAo6WdHXN\nt1JSZs0P04TNSuBV88k4LPMQ4GtsdisdadNI0li74USxB/Bu6un0d5ykSsosyZtc0uCUpbw88FdJ\nPyTfwdbA/sB72On8SUm549XqeUXE3vicLiXp2YhYAp/b24F7ajLLmJkK18FEkr6NiN8Af8KLm23x\nru8AYDtJ31Y5F0XyTiIzThMtmck9IqIHnmCmAq7ETr+bccjjRx02yFakiWEKHAFzHl5Fn4GVxY7A\nASlUsxRpsqkpk4NxHsj6OCxzL2BSSesBfTqDgijsoprS5PsEzv14AJtZHgWWi+qZ4dcCA9POZE1g\nA2C9iJgAXw+f4Iim7yooiG6ShkTEeBGxQMpLOAq4JSJmkvR0kvl8UWYJBdFU2EX9NUXhzY0XCk9h\nB/VxwJGjoyDAtsxMZpykVWjjmThr+s94ZboujjT5A16JfdhxIzWFlWN3vMB7Gzuot8fKYV0cF790\nMpOUkVmsOLo3nmg+jYhJJD2YFOchEfECrh/UocT/lmh/ATuVl8DKYT4csrx5O0wrjwOr4t3CmXgl\nviTQlG5/Ahwo6aeSY61dX83YhPRMRPSSdExEfJLuL5YURWmKOwh8fV6Cs+AXwtFnn+CFzjWS/l1F\n9ojI5qbMOEmrKKbTsK35B6Avzn9YCk+6/TtTBE9yTl6FHam7YNPCn7Aj9XRg4yrhjUl2Ew5p/Q/w\nCl6N/xO4NzlZp1InKgRYcNA+iHMB3sW7nrfwDuAISa+1Q+6M+FqYGdv2j8TO3kWw6Wmrdso9C0/c\nZ+FdRC+SGQh4StLDFWTVroPeeEEzHo6yeg8Xm5wDmwTrVl48m5sy4xyF1egM+Ac2JXZIX4Ft/A9g\nZ+XmnUFBwK8mpsnxLmegnAl+P57MV8XO5T3LKohWpphjgA0knS7pAZwotjSwcbKnd7iCaDXexYHP\nJJ0k6R1gXmASSZfh5MZSE3mkWknpdndJ/8GRTP1wSOoxwP/JRRxXqSC3dbG+wTgR81y8o3gdWFnS\nCZIermIWK1wHh2KF3g3YBvuPzsAhz2+UlVeGrCQynZIR/NDqRiFk8nS8exgC3BgRk0q6FE8SQ4qh\noB1Fq/NQi8WfKTkrr8cr6GtxBu2LZWW2MsUcDbwXEacASLoJ1/Z5TJ2ggVLNZ5LCUcE7hk8jYsl0\nfyFa5rIq+QonARdHxPnAnsns+AmwRYoI+h44Jp2vUqVXCguQ5ojYMyKWwv6MmnP6PbxT+9UMVMUs\nlsx/lwATSjoJ+5Bmx5nUk0o6T3WuAJDNTZlOR2FL3YxX+i8Bg6tsy0chvzs2JSwhabVkcjoKTzab\njq6jr96kHc9mOMroYbxifAPH0X9VUVbx3F6PJ8Uf8YR5I06626uOwx8tWuWuXIQjza7CjtkeeAU9\nC7CvqmeTz493jp/jENQtcLLcfrjk+00RMW3ZSbcw1iY8kc+Ew1EH4XybJYBd8fdWOZM6InpI+iki\nVsCK/XRJt0XEHNjkeGhVU2MZspLIdErSD+0ebPqYCK+WzqiSXNRKXu0HXPuhrYxtuI9JOjGtUgcA\n50p6v04fo12kzz6XpNfDLVLvwGGT++Loq7NwLZ5ncPRK6WzjJLsJx/k/iSvFvopt5DfgHcTWgNoT\nU98I0jk4Ak/k8wK/4DDdH4CpgVeT2amKzNrEuwDeUZ6anpoZh4++L2mzdoy1CUcVfSnp+IhYERfs\n+wUr9x5VzHeF63ZGbGqsNSL6GTgBm0lvKIbZ1ptsbsp0GlqZVn6DnXrHYOfsv/CqsT1yi6vRayJi\nH5xBfAowQ0QcKul7Sf07WkEkbscVRcHJVvfgSfFH3C51DryzuLCsggg3yplN0rD0mi+wyeNMnNQ1\nFfbNLCnptY5WEDU7ffp/FrCQpIsl/QmbgXbC5TDuraIgwuVLwAmSJBNdP7wSnwSHFa+DdxRlZRav\n24lxdvOc4dpej+AQ3UmAKSsqiFqYay/gRKzQr8LmxWa8qNkmIiZupFkwK4lMp6CVLXcP3CBn+4h4\nBJuG7sfluitXHS380G7ESXI/4dXdzHhCnrYweXQoKXJnAmBoRGyCzRXLYwf1trR0wRtWUaH9ADwR\nEXeFq45+j1eiT+FS6L/DiWSdwQ9T80FMkJTVvsAsEXE4gKTDsfO3kkM9ImYGdo+IZUjNgdKO4h/Y\npn8gsL2kwSpf7rvYMGgLvPjog3tL7J92rvcDJ6hCcl/hHEwCbIJLjlwu6XZcj+lBvJvYTM6wbxhZ\nSWQ6BYUV8Q3ANMl5egneUfTESWOnVd2qF+5OgmsxPYFtz+dgZfEcjn2vVI65UchlHq5Of+umCexf\nuFzDpjjs8VSVLNJWOwdpxfwQLS0wz8SfvRfugHa4OkE118KubwbgnnCS2EI4DHWTiDgBQNJxqp67\n8j4upX4zDnEGGJYm+mdwrslfqwhUS47J7VhB9MO7nAH4XB+WjivtKxhBuPN3eNfXLyKmlHQvsDnw\nhcZAFeLsk8h0KFEoHZEciccA/5W0U3psa1xg7/32OK7Dxe5qvRT+hRXDWriM9rHAOp1BQbRyev4W\n73R2xRPXM9iEsTAuW152lVt0Uo8PTI+dvFfhUtffY7PTDJ0l1Bd+9UFchXd9zXhCPA5Xtb0TWA9f\nI2VLjvxatDBcXmMDfD2cKqlSS9CCzKWBlyV9lcyXi0raLj13K07suxKYJSmgqvJ7YR/EU5JOiYiV\n8HfWDJxcNtqqHmQlkekURMQuOJ78HZxB/KmkI9opqz8ucPcttuNOjRXCq3ibfiI22Wwv6ZXRHPpo\n02r1vB8+B/fhulGXAftLuquizO6Sfi6scrvj2kBnR8QGOFLobWATSR/U8eO0i1aLheWxQvwLXol/\nhVflR2MlWcVRXzu30wKr4xyYwcDu6T0eBZ6V9HwFmTMBy0m6LvkjVsALj9MkfRQRa+E8iNJ+jeJY\n0+1pcKLgY/gcDMWJfUsB5zQiiqktspLIdAitVnfdcbx3rXbSx9iZ+rmkQyrK7YWzpmcEJseTobAZ\nYSc8KcwMfC1pUH0+zeiTJrGrcdOgWo+BjfGu4hjct+C7MhNkwU7eHdvzhwAvAhvhcOILgfmBCZI5\nq0OJ4bPfa6WC1qGlfefSePdwjCqUmSgoiGnwruRHHJb6B3yNbYH9PJuWvRYiYmHgY0kfRsS+ePJ+\nG2d6/xvXz9oJOExSqfagrcZaqxv1fpJ7NvbHnZGen1DSd2Xl1oPsk8iMcSJiioKCWFMudX0i8Cme\nHHrjHsJXV5S7dDIdnYRDOefEXeRew5PMLdjR93JHK4hwOe450kQOsCje5TyBzQpnAyulHcSykr4p\nqSC2BC5IcrfBSuJmSf+HQ2kXxU1tXu4kCmI8tdRiugG4G4jkk5oAh+Mehqu6VqpDlCbVSYGLgYsk\nrYOV8J+BmSSdhVf8Va6FZuCMiDgCm+oWASbEdZ++wO1tD6qiIApjnRZ/R0NwSO6mODR5U1xXizGt\nICAricwYJq2UVoiI+ZOd9ZaI2F7SD5LOwFEhywH/bocpaL5wwbeL8Db9TuDIiJhbLvNdKwLXoSQf\nwf1YmT0fztH4EpfXuISWhvW/j4gJseOyLK9h88yhcvb43djpj6QHsaL8axWTTaNI0UtDImJKvEi4\nBtvx/xIRs+Ncjolwa9BKfTEKd8dPf78DkHQKzg85LNylrVRkULSUzhiEI6O2wAuR4/HKfyLgVkl7\nSXqonWPdDDeJuhqbxHpjM+Gm+HvrELK5KTPGiIjfSHopIk7GP7KdcVG5W/Hq7nlsdz6iirOvlS33\nEWBWSbOEq2T+EZsrDlTJxu+NJE0KF2OTxcERcR3wgKTLIuJsbAa6Ehd/21PVs4ibcCXU3XB9oyMj\n4hJ8Tlat64cZDSLidzg57m3soN9F0kLpuZ1wgtsSVRcKrcw2y2Pzz4u4Be0PStnk4WqspQIW4n+7\n9S2Jd6nr4bDZObF5dICk96qMN8mbBliJlEWPfWhr42CFtYH91IHlUfJOIjNGCGe2vhARy2Hn4X/x\nhDgIr5S2xqvJi9qjICJiiuSP2BG4KCKekMtr3IfNGA2NJS9DmsBvxKGLB6eHX8KrUNIEdiruXbFL\nVQWRZAzDhd/OB6aKiAGSdgQ+iIjF6vAxRotkZlsZ73jewZV2nwf+GRFnpt3FxTgX4Oeq8tWSNHk5\ndvxvixPljsA1r2qZ1YNLjrdmDmuOiGsj4m7sO7sd7ySuxruU49qjIBKT4et/InxOBuHzchRwfkcq\nCMg7icwYIP3QhkTEujijdSe85e+L/RCP4dDUd+WuYKU6qhXkTo+jmJ7FJRrOTPH06+CEq00klZoU\nGklErIJ/+PtLejoi/ownmG9x5NUUuCzIbRVkDrfKLTzehEtY7Ad8ICegdShpF3Uz8IikMyJiYxwV\n9Agu2rc2dizvrpI9G1rJr3XXOwqXD/8rNt/9H6559RbQXSWTEKOlhMt42PT1BK66uiveqT2DdwA/\ntDM8uwcu1PdFuKXpOfh6XQJHXl1XxczWKLKSyIwRUqjgVMCseELfEm+v98KRPNtKerYdcqfGq/Mz\ngElxTP1tki4NZ9a+L2mUvYLHFBGxK54AJsWRPDvhFeQMOMTxlrITQyEqqBmvPB8tKsOkKOYHhnZ0\nqG8a46XAIEmHFR7fDJtVXsQT+0p4N1m6kmnhPNQWDbthE9AC2Bw0P679dVyZxUdhXAvirPRZcMjs\nAbjg5Az4fO8l6eZ0fNmFTU2RTYB3N1PgXd/8OPpsG5VsGDWmyOamzJhiDRzzPxibl64G5pfUH1i9\nioKIiNvTKhw8wd6BdxErYVPLduESDk90FgURLZnPF+BImKmAKyR9LekjSc/I/QVKrxwLCuJ6vCL/\nTZp8as8Pk/RSRyuIxOVA75qCiIgTI6JPmmRfxvH/0+NEsSoKotb9bXrg7BTdNRCfj+fxBL8bcHtZ\nBZH4ATuNd8bK6x680n8Y784+xqYhoFy572gptTEZLrL4KP7uzsAh2/Phc1B0lHc4WUlkGk664J/E\nP4jDsIlpa+C6tBMo3T86OSSnBvaOiP5ycbe3ccvJ/XHU0AfApRUnhYaSbOXjpdtX4WiV9SJiw2jp\nk1CKGL6g3P7YVNcPh0keFhF712nYdSGFoT4LPBcRS4WTHafDuQu18/EY8LAqlJkoTLqTYl/OJ7gZ\nz29JeTbAisBuZf07te8IR4Xdjf0au2OT1QtJ7h1AX0n/rDDWWrG+6WlRDH/AuRvrYdPYIFwttlKP\niUaTzU2ZupNWtxNK+iYiDsQ/rv/DFTJ3x1Ene+PSCpXLC4Tr6f8eWBa4S9IhEXEbLjMxHw6Z7PAy\nE9GqD0DxsXR7H1zR9WCV7GHRysS0B1awK2Lz1V+wE3RySaeORMwYJ9xuc13sg5lM0pLp8QmqKIaC\nvGJ9o82AGSX1j4i58I71FkmnVZRZO7fdcDjyO1jhzIkV8fO4K97Tcge/qmOeGIdlX4YVUK0Y4N6j\n4fRuOFlJZOpKuJ/v5NhpujQt2c83yK0aN8A+iLPl3IUyMpuAuSUp3Z+Bltjxq3AS2tnAVrjdZKna\nRo0khi+1cSJWYAfJPaOLIbuTV1WU6Xz8Gde0OhIncy2G8ymOxE1t/q+OH6cupAl9Y2x/v1nSwHbK\nqdn1p8IT7nt4sl1T0iMRMS8uYLilqvf7rpnvPsOK4StsDlsIm0pPTu89Sh9E+p4Ww87uZ7Bp9GKl\nPhVpB3QG7qPe4aVR2iKbmzJ1I1yxc0L8g91Z0s+SjgXexH6Co3F1zAvKKojEE8BjEbFTWil+gCvD\n7oJLN+wA/FHSBZ1BQcCv5qWpsePzIWzfPjfc6axWyI+yCiKGT7paE+eZPJVW4T/jXhC7A6d0BgVR\nHG/hs36Kdzv/wmXgV2+P7DRJT5RkPSJpD+w7uCwiVku7yHWqKojEHtg0+kdgSax4a2Vd7qophhIK\nohlXDTgAf19D03f9TURcmw5bETvUOzV5J5GpCxGxKG4huW2634wXIXPiH9p8uEfEK1W36hGxO85O\nfhqHUC6Eo0wOTP8nBqZQhXr9jSbZts/CHeZWS4+dic/H9pI+qSCrZgZpAubCZpDf40iuAUrF6cIZ\nxKVKiDeSwninwn2X/93q+emxOeeB9kQxFe6fhHeP80n6Mlwkcl9sIvpR5cqYnI53Cz9IOi7cy2Qh\nbL67Ci9G5gOOLSMvyazlw7ysVKQyIvbH5qU9cUXbKXHwwi6dJLCgTbKSyNSFcCOb/rhe0C9KCUDp\nx7GcpE0Kx1YKF0y3fw+chlfQ8+OKnsvh7Oxz6/152kPBxFQLxVwYR/VcJ+mEdMwpuER1pQ54Sene\nh6O3VsKhw4vhhjT7V3GiNpKCKWgGHMH2CHCNpDdaHTfC/I6RyC2a7/bFu5Fr8c50Y2AVOcdmMklf\nlpR5AvYJnYPNogfjqKWHaKlGfBNWEFWK9a2Ke4Hsn+7/GRdt/Ax3/lsqKdCfy461I8nmpky9+AHb\nyCdLE2QtAuclnA/xK2UjN2q233T7OhxXfhmOLtkChyI+XI/Bjy5p0quVg7g2Io7DfQs2BZaMlq5q\nf2qngjgMuFfSvji/YiscX38tDqfsFKglB+B8bG75C7BvRPQL9wupHVepA146t1NgX8OEONfkNFwC\n/j7coKgJ+LqMvKQgeknaTK619DTQJDcyWg34EFegPbGKgkhMhXMpCBdafE7SHyTtA7wfLgnyWVdQ\nEJB3Epk6klbJC+EEscE45vt87EitshIbbqcRhSbvyRxwPF6RdXgEU5Hkg7gZO9T/hv0RL+JQz6Px\nynRwyV3U/MAicrE3ImJHnBw2e5I7A+7gd3b9P0l1is74dP98vDhYDRcY3ABnk1fJh2kCdpR0cXLy\nHocj4g6PiNnwrnUW7JuaQiW7FqZr6EhJU6f7u+HQ2YdwjsVH+Pv7puyCppX8efBv4DgV6kOFGx5t\ngaPvvqoqt6PIO4lMu4gRJPvITeofxdv2S3Hs+gkVFcSvCUcRMVNETFrcmSTT0n64nHKHExHnJxMI\nuNvds5LOlDue7Yd7NvwL2FzS5xV2US8Du0TEF2lyeRmvnr/GjvuDsempwynuoiLi2HBV1ytw1Nnh\nOF9hDir2pMY7pM+Sf6cWJjtTRAQ2B12HgyKmKqsgEhcCL0fE8RGxLTZXHY2d00tis+kC7VEQiQ/x\nAmn3cM0ywv3KtwEO6EoKAvJOIjOaREQ/7OD7sBDW2QtH8zSreh/immPzVrya2wTXXnqluKPoLIT7\nIHyOV/nvYfPX6pLejYjtcfmRjbAjtaof5ne4ON2jkvaPiPXxTm0h4JJ2mEEaRjgP4ga8i/oYr8h/\ng/1HGwJ7VHHQtto9Xo1DiPfCDZi+wyHVla+Jgr+oOzaFLQjMI6mUmaqE/JrvpDc2V02Lld1EOAHv\ntXq8z5gkK4lMJWL4GP9e2HF4uqRBkVpmjqb8CbDf4WqchftPnHjUXyVr/48JkjloIpwluyhwF47e\nWhznKlyHTS07tGdiiIidgfEknRcR92NH7eXp/YapZPLdmCIi9sQ7qfOwiVF4V3kTMFGV1XNhop0E\n+7m+w34o4evtNLybOr7s9TaiYIm0O30QeL7gZB7ObFZhrL9GlhWc992xtWZ8HMzRqb6zsmRzU6YS\nteidcBbx57jN4gnpuXYpiIKTGznu/3m8wrsZT7Sv4yztzsT4eMJ6BCdKbYR3Pv/AdaoeALYqqyCK\n5yDcaKibb8bqOFN5TrxKX6gzTDa18UZLZ70v8Yq5L85ZeBsnUw5tp4KYHpt/LsSVczfASvh0bMa7\noMr1VtidLZX+j5+c52sAy0fERem49iiI6YGbImKtJLemjIZI+lHSV53hO2svWUlkShER80XEDunu\n2cBZEXEI7gL3n2QnrlyYLP3QfomIGSNiQET8AU82G+OJdnrsmKzspC6Opeq4RjZegOSAfQ3X3llI\n0l9wMtsLwHSSBqpC3kY6B00RsZzcovIaHHHzO2BVOYR4VUmPVRhrt1EfVZ1oKao3E3BaRByPfQQn\n4PIri9OSVV/JVJEm3SmxT+s4rBTWwma39XF+waQqmWcS7gPRnG5vhP0CSPqxYKpaGpcUr0RhrDfi\nRlGTACtFxGrp+bHCTJOVRKYsrwLrRsTf8URwBg71ux3H7a8P1X8YamlUf1V66F+4c9sDOJO4Hy6v\n8E4VuYUtf8/2jKsNmb/WC4qI3+L4+l1wNvmawHO4o1ylRLnC3cWA8yNiA7k67LU43HXziJhGFUo3\nRKHGU0TsGxGzJgfwaCvMdF4nx+G3t+Fdz9G4F8QQUuVVtcqNGMV4V46I+dLdHsC92MezM16I7Awc\nJmnzsgoijXUoLSHC9wFzhyvFUguIkDRE0pMVxlr8zmZP4xyME+UWB9ap16KkMzDeqA/JjMvUJsY0\nMbyCHZGLyyWe94+IRXCG604RcZsqlMUo2H83BN6UdEx6fEUcs35aRFyqCvHk6ce5naTLk/Pw0oh4\nHzgXeLG9ju9oqeI5HfY/PIsnwy2xr6APEHi1X7brWW0X1YRXy6/gqq4HRsQwbMKZFCcMlp4YYbgy\n4tdg+/1cwHcRMUQl23aOYLxFu/7sOOLqRVx64lpc7vtitS/r+3Pg+oj4NzZZPY9Dhs/FRQv/nt6j\n7FiPAcaXdCBwTUQ8gRXa0fh7+/X8VxlkQfn2xr6oCbGJcSFcknwWbA6bEDeT6vLknUSmTaIltLEp\n3Jj+alyObmy5AAAgAElEQVR5dZqIOCX9UN6R203+DdvpS8lNN2uLlJeAL8Px5eBwydoPrGq4YC/g\n9HAy26HYr/EJ/gEvHC2loCuRlOTEeFV7BI6yacY281dw29Q1KyiImtJpwk7ZbfDuqVeSuRUu4neZ\npBfKjjMi5i7c3QQ3tTkGZynvAxwcw9eBKiu3Fpo8YXroTaA33j3tg5XmBtjkUkluuvkedkzPj6vY\nPgIMxXW5zgdOKrszCYedngNsGK60eyTOK+kHnAxsGRFzVfE/1EgKYjpsYlodX/+n4p32GlgJ7duV\nfRCtydFNmZGSfsS1EMTvcfGzgcApOOxzU+ALvOLbV63q9IxIXsHZdxqOXnoC1yL6Eq/AFsRdvyrl\nAUTEgpJeSLLvBb6WtFx67lDs+DxZFYoLxvClvbuncX6AeyffiMMyxwPWas8uJSJOw7umfSNiQWxq\n2x/7IyZStXautczs2XBjozfxLq07jhAbhluE/rGK+S1awkanw2Guz2HF/l9azsfiwK6SXqwgt1jN\n9WLsh/gJ51bsiBcL3XH00Uivq4LMOYGlJV2V5P4dOE/SWUnBHYBX/S9i5Tl0VMoiKfLlcCjysHCf\n7K+VWsKG27DOhK/lj8qOtauQlUTmf4iIRZNjtla+4D0cWXMbrod/Kc5KnVcpVh1PaGVr5kyFnZxv\n4i37E3glCjA38NcqZquC3J1xFNDbeFX+KG6FWfsx9wMul1SqyVEMXy9oG+wvGYwdnS9hn8nWOLO2\n7CRWVDrTAIfgc7CZpE/SyvdHSeeX/dxJVm0i74ajwQZLWiw9txYuVLcnVpKV8yvCJTEOxl3avsRF\n797Bu6BZcJvYSuVGktxJsUnsn5KOTI9tjp3WLwA7ld2dpdfWzsNBeAd5O74ObpB0VDpmCWBDuSti\nGZlz4AXR3ZJ+TtcZeJc3JCKOBJ6UdG/ZcXYlspLIDEdaia0p6Zx0/xg8MayIJ4QJgB6SLknPl44r\nTyvdbrh73CBJ24dLWRyJM4nPqOKcLcg9B5u7nsUr6BckrZlWvg/gmkd9q8pNsntjp/o/gRslPRcR\nJ2Kz0LI40a9U5FVh5dyMw2cfx597CZzpewupsq1cT6jsGGvKrAcuWfIYtou/IWmHiFgDm3Ek6Z4K\ncs8mZSfTUiPq9/g73ABXcn1Y0g1lZSa5rau5XoB3kH2Vki/DVYUHq2SEWCvl2w2HTm+Or7UHsI/j\nGkkDImJlrITW0yjKiUfEkvha/TAirsRBG4Ox+fJ6fB1sCvRRhdazXYnsk8j8SprE3pR0TrgH8ZZY\nMZyGW44+AOyKlQZQLq48hs+D+BnbbbcIR/F8im38PWh/qY27sM19VRxl9VZEHJAmnE1xWOJUZSNO\nWh23gYetg5OCWApPEhfizOqyCqJbwcRzKt6NrIkjw57Du5/jcD+Ih6JC+GrBt3EsMLGkW5KZbd6I\nuCO9z7mS7il7DhID8G6vFoI6BS5z/hM+5/dRscBiDB/y3D/cavUIvCsbkEyFSHq2goKoheQ2p897\nGA6VvQr7CdYFFsEKg/SZyjYk6gkcExEH4F3JNvg6vQD7X+bEu52xUkFA3klkEiMwg8yLk5hOwZEn\nh+BV77WS7qggt7bKnRHbgD/B/oJvsU3/T5JuqbIjaS073V4JK5+j8arxZOxIfwmbWL6vKHuyNMbV\ngJWxSenLNFkMk3RK1XGmCXo37Jj9c0QshvsbD8FJectiM86BKtFnodXnXxCHJd8FXKFUyyjcw+J2\nSX+rMN7itTAbzgfZGvtJLgZu02iUZ0+7x9vwrmcXWq6v47EC3r9s1FGrse6EI8zewH6Zl7BZdFvc\nFfCj1ruYkcg9C1+v0+LCfy/hNqnT42vrcknXlP7QXZisJDKtzSA34oiiG3Gi2OE4suTuiJhQTvSq\nKn9qnGx0Fv6RHY4n3jnxLmUx4PsqSqIw8U6D/Rj/wdE2J2NF8SjeRTwp6fWyMuHXlfmFePI+FU9e\ntczpJbHjt2wmdVFBXIY//zc4eeterBjWxpPvUFwl9CqNouZVxHCNiFYC3kpjWwO4B3i8qGiqOL/V\nEuq7Br4OZsDZz31xuOfpwDZlfVBJ7sySBqXb6+MGPMdiE9tjuEHPLRHRux0+o2b8PY2PndQvhOtm\nLYj9SHeqZNhvOp9zYz/cMNx6d/w03vnwwmlZnLextbpYsb72kJVE5leSDfqLZLdtxj+GX/BuYlNc\nxK/UBZMch5dI+iyceLYZjow5Dk+Q06eIk4nUznDB5FC+DkfXfIodoOAw1QFVdjwFmT0lfR9uj3kl\n9nNchyecGXA3tdJJYgW5hwKTSOobEbvile6jku6KiClqztmoULAufUd3488+O1Y0EwCr4AKJt6gd\npVKSH+YmrCDeSmaq3lhR7oAn3SpF9SbHk/iruIzLM7gvxIzAOjgyaE9cFrzSIiRN6qfgz92Edw6X\n4yKDWwMDJfdGLylvWVzBdh+8630ImzFfxRn1qwFPAaeVNFd1ebJPYhwmYrg+xD2xE+4R+NXX0B9P\nQOtI+qCsgkg8gPv5zo93JHNgO+4x+Ae8QbgMeHsVRE9cHuQ4PEnMhSeFSXDW8/MVZO0WEauku1dH\nxB/SuLbBPo6DgPsknVNWQcTwtZgmxavQyZNiuwyfg9UjYqpi9E6ZybfgVzgEr8C3xY7qjXFE0CXA\nq1UURCtfxUF4x3AHsEdEPIgDF34LvFRRQTTJvZ2vxjvIddKk/Rje/WwFnIjNeaUURKuxHolNQn/E\nEXMTYEU2HV6klFYQAHLZk32xP+Yn7M+4Fgi5u+CZ2Jw3TigIyEpinCWGT5SbBWe1Xg+sHxGLh+vy\nTIzDMauEIHYHkHMR1seJUEPxpPMejjc/Etiv6lY9/jcJ7CFsz94HO5JnBv4AvC7pXUqQPuekwBop\nouYinD2+aZq0zsMKaKIq4yw4UrfDTuoz8Ep3c1zO5EzcxrR0H4Ro6alRU9afp8ebJP0D+wyWkHS/\n3MOiNMncOGk4ofEOvGs6AtgDK7XpJL1VZRdVc9ana+JVHPSwWET8Tg5HPQyH0W6tkvkVrQIAwOHT\nPYFN5dItV+Lvs7nKoiZaChY2Sborje1c7JfqAzwYEctIurM9O8muTDY3jYO08kFcg23vU2JTwP24\nq9YQnGPQHif1dHg1dgUuUDc/zn6eHCeeva+KCUcF2b2waWUQnmyXwU7Fr/FKcjdJ/ykps2bXXwKv\nnj/EpoqJsNJ5CCuInSpE2tTG2Q07kV/Hu6iBOKN4Exxdc3yKEipFK/v7dknWzNhU8wstJpy9JA0s\nK7coH0+Gv8Wr/sdpydjug0ueVzHbFHtdn4R9RLcmeXfjkOXXJJ1cQWYtB6KW6T4ZjrqaHe8e7pJ0\nU1XfWeHcTo8XMO9gs9VLeJfTFyf1faSxOIqpLfJOYhwk/Xi74aS4tyVtA+yNI5r+i802u0i6IyqE\nTKql2cottPS7PhyHzJ4JfCtXR62qIKYv/IgfxGGpj+BJchLsM7gMOLisgkjjrZVY+DPOwP2Blgzy\nLfBEsXtZBZGo/aZ2wMpwnyRrbrw6Pwi4tYqCSGMdmlbkV+Cy5Oun9/gJn4NdcFRUaQVR+25ru0qc\nnfxykr8i3vktTkUFkcY7LEWIHZnkTINzQL7DPpNPsbIoO9YeSUE04ev2BeyU/jtWmNcBG0XEtFX9\nGoXr9mqs1J/Cu55F8cLjGOAf46KCgFzgb5wiRZX0Au6XwwE/w+YgJL0ZEX/D4Z2/mkBKRsR0x8XU\nvsGTyt+S87tHuB/CPfgH/UU7xrwXMElE3IoLvh2FV+ibYYfiQXhV+nGZqJi0Cu2P8xG+wzuRpyQd\nEa5PtR227x8r6YgK4zwYO2L/g5XOIGDliJhJ0nvh+P3V5Kil0t360nc2OY4u2g34t9zjeQpsCvpa\n0hnJv1Olb0PPdPN74KKIOE3SixExBO8Ct8aRYrurWrJkf+ykbsaOdKVrYVZcIuRgnDR5cIWxHobN\nVTdhx/GXeCfxJ5zkKGzSKxU6nGQ24ai6Qek1i+Lr4KT0/M/Yf3JeRAxU+4oWjhXkncQ4QkScjM0G\nC+DIGrCv4Po0mS+Gk6Z+aEPEiGQ2R8RNeHV7Y9qd9MA/ZNJqeQmcwX2lUghkRV7HJorlsVllfbyb\nWBWbBfpI+lcFBXE5TjirrTZ/KYz339hs1UyFwoLhDOzA2bgPp4cH4Xj9fcPx+0di5Vaawne2EDYD\nLQtMkcwjg/F3NV06vFTXvmhJODsduCqcpf0BcEREzJvOwVvYFj+4ooK4HJ/bb+V2oM8DS0TEfMlf\ncDfesZV2+kbEScBckm5KDz2S/i7EJrE9sdKdSCWz9dNYb8OLgSfDJcp/AlYoHDYvMGu45Eyn6YjY\nEWSfxDhARPQFZkimj1qpgamxo7Mvrr0zNbaTl6rrk1Zi1+ES3wNi+PaNZ2DlcBM232zfHmdfwVa8\nCM5VuA//kD/ATvZzsMNylLLTxHAxDuPtnx5bXtLAiLgcm4PuxEpo67ImsYjYFNcB2rbV4/PhLN9h\neIL/i1zZtBQj+M5mxSvxvfEE/yGeII+R9NeSMpuxY/4TnJ/SF4fJPhFuP7o+nsSXwxnJZZ3/Izq3\ny0h6PO0CfgMcnXYqVUJ8L8Qmyv3S/ZXxav+7iOiPS3ks045zcCHeefZPcn6RdHxEXIqV/V04qmkn\ndcGe1PUmm5vGctLqflrgkXD/6CNw/Z2n8ITxG2wnnlDVwvrWxpPCgHT/rIiYOb3XRsDC+PqqrCAi\n4ghsA67ZrNfAkVYzYmfyTOkz/K6C7FuBbpL6pPc4DpveBso1pDbHNYl2qOgz6YFNabVzPTQ9thk+\nPxdFxI1lJ8aCnNbf2Ta47PlsuELqYDzxls6kxudgPEk7pvdZCpgnfW/r4J3P3MClZRVEQe6Izu3j\nko6KiKOBQyJiu7K+mHC5763x90xE7ILNjetFxE/Av7GCOLGsgmg11p3S/Z6knY2kPuFSNN8BN7dn\nYTM2kpXEWE5yzj6KFcL9+EexiqS30lb+N2mFW6lsBXZGrpJWez3x5LU5tpv3xVE2lbepETE+dhhv\nFREf42ziBSUtGxELY4fiE3hlXsrHkXwm/4fDLxfEZrXZcbkGwgXwHtUospzbYBCuQ3WnpNfT7ufH\ncNOgmt2/are+EX1nK6Tv7D/Y77EZsExEPFnGUdvqHCyMncefYR9MPxyBtJWkB6qMtcS5XQ1HCI1X\nxVmfdh0bA30jYkO8SNhCLZnT10XE9clBXjabfERjnRWbAmvve33ZMY4rZHPTOEK4uus3wM+S/hsR\ny+AyGX1UMaa+IHN9nIn8qqRb02ObYf9B6fo7I5DbE0+C+wE/SFqm8NyyuLpppU5tSeamuJ/A95KW\nTo9vmR7bouIOoiZ3Iuw8/won3L2U/Dvn4f4apXtSj0D2iL6zc7EpBJxEuJdK5lq0Ogc/SFoqPb4F\nbqCzh9qXoT2yc3sQrpRbJUKsKHstnBx4lKQL0i5rWFlfySjG+l3t2oqI7u357OMCWUmMQ4RDSHfF\nu4YtcdGz+0f+qlJyZ8OJYr/FdvI9Jb08mjLHx+aGNYETJD1Th3EWZfbFTYj+hMdbqr5TG3Jnwudz\nYxySuRJwqKQH6zDmNr+zKvb9grziOTgI2+D3w0q93d9Zo85tkr1WknmRpOtGR9YIxlqXa2tsJiuJ\ncYhweYjNcUjlPyT9vQ4ya2UQNsCRQgeNroIoyO6JE7q2wSGplZPERiKzL45i2nR0J7Ekt1YYrgd2\nhFbqqjcSuf/znUUhd6WdJr3W52CTetjfG3Vuk+z1cBb0+sAn7fncreTV/doaW8lKIjPapDDK8bBD\n8Os6y54QK6CBakfnszZk9sQT71NStSSxsYWCSe/pep6DRp7bcJ2r0mVMSsir+7U1NpKVRKbTU9Yx\n2dEyuxqNOgdd6dx2pbF2FFlJZDKZTKZNcsZ1JpPJZNokK4lMJpPJtElWEplMJpNpk6wkMplMJtMm\nWUlkMplMpk1y7aYuym8GPNiQsLTzt12sEWK58ZVRVvKuzJBfGhOZN2GPrrV2mn7SHg2Re+fz9f/O\n9lxx1rrLBHjyvUqdcEtz8vrzlG66NSJ6LrJX6Yv0++fOHq33ahRd69eQyWQymTFK3klkMplMo2jq\n+uvwrCQymUymUTR36+gRjDZZSWQymUyjaOqUboZKZCWRyWQyjSKbmzKZTCbTJnknkclkMpk2yTuJ\n+hMR/YDVgO64qfwBVTpHRURv4DBJe7Tx/ATA1pIuLilvF9zFamgaU39JD4/k+I8k9U6N3KeoR2Of\nTCbTRRkLdhKdSs1FxHy4CcjqklbEbRUvrSJD0kdtKYhEb2CnkuPZEvf+XVXSSlhZXBURU5V4+abA\nfGXeJ5PJjKU0dyv/10npbDuJL4GZgT4RcZ+k5yNiCYCIWAQ4C7fI/AHYWdKgiBgAbIQ/y3nA/cD1\nkpaKiBWBY9Nr3sK9gvsD80XEYbjH7S6SXo6ItYH1WymYXXHv358BJL0dEQunpvSXp/e5L/Xg3VLS\n9mmsMwDbAz9FxLPAjcA8kn6IiOOB14B3gBOAn4ALgUGtx5obs2cyXZyxwNzUqT5BaiG4AbAs8ERE\nvAasl56+CNgr7TDOBU5NimNtYElgCdxjuAl+7Tl8Ee7fuyLwPp64jwVekXQUcDGwXZLfJ90vMj3w\n71Zj/G/Jz3E5cKqkp0dy6ASSlgeubmOsmUymK9PUVP6vk9KpdhIRMSfwlaQ+6f5iwL0R8RAwvaTn\n06F/B44HAvfo/QWvwP8UEbOmY6YGpgNujAiAnsCDrd7yRuCZiDgZmFHSs62efxeYCe9wamNcE3ih\n1XFVvuHisbUewGXGmslkuhp5J1F3FgTOjohaxbLXgS+wAvggIhZMj6+YnnsNWDQimiOie0Q8CIyf\njvkM+A+wYfInHAv8DTugmwEkfQs8BJyBV/OtuRQ4NCLGA4iIufFuo2bymi4dt+gIXvvr+9SOTbub\nhVsdM7KxZjKZrkxTc/m/TkqnGpmkW4GBwD8i4jHsXzhQ0pfAzliBDAT2AfZLO4v7gMeAR4FrgB+T\nrKHpuLsj4nFgD+Al4BOgR0SckN72ImDD9NrW47keeBJ4NCL+DlyGI6M+wcpiv4j4P2CGEXycZ4C9\nImJl4ETgnvQ3eATv09ZYM5lMV6Zbt/J/nZSmYcMaU265qxARiwN/lLRtR4+lCrlUeC4VXiOXCu/E\npcJXPa58qfC/HtIpHROdyicxpomIvYAdgS06eiyZTGYspBObkcoyTisJSWcDZ3f0ODKZzFhKJ45a\nKss4rSQymUymoeSdRCaTyWTaJO8kMplMJtMmnbjcRlmykshkMplGkc1NmY5i3/Xnbojc1fuc0hC5\n5562S91lTjlBY0I/n36/MeGUC/WeuCFyZ5p4wobI/eSb+pcOm2mSxoz1SRrznY022dyUyWQymTap\n004iIppxzbqFcMLwTpLeHMFxFwKfS+pXlzemk2VcZzKZzFhF/cpybIQLgi4N9AP+Z8sfEbsCC9T7\nI2QlkclkMo2ifv0klsMliJD0JDBcaYSIWAZXw76g7h+h3gIzmUwmk6hfqfBJKVSjBn4pFB6dDjgc\n2KsRHyH7JDKZTKZR1C+66StgksL9ZklD0u3NgalwAdHewIQR8Zqky+vxxllJZDKZTKOoX3TTY8D6\nuOfMUsCLtScknQmcCRAR2+MumJfX642zkshkMpkG0VQ/JXEbsHpqJdAE7BARWwETS7qwXm8yIkap\nJCKiH7Aa0B03yTlA0jNtHHs6btk5qK6jHPF7DQMukLRb4bEzgQ0kzTqS1+2C+0IsC+wmacsGj3Mv\nSWenPtgzN/oLzWQynYd6KYnUc2a3Vg+/NoLjLq/LGxYYqZKIiPlIPaclDYuIhYErcKzu/yBp33oP\ncCT8F1ghIsaTNCQiugGLl3jdIcCVjR3acAwAzpZ03xh8z0wm0wloah77k+m+BGYG+kTEfZKej4gl\nACJiSeB0HCH1PvAH4F6s7T4ELgGmTHL2lvRiRLyBbWsBfAxsCvTAK/tZ0u29gH8C5wNzJfkDJD3c\namxDgIeB1dP7roH7Qm+bxrci9vg3AxMDWwHLY8fO9Wnsc0XEvcA0wJ2SjoiIBbB9rwkroj7AIsDB\nOIllpjS2VbCyPEPSeRGxGbAn3nENAzYGdgV6RcS5wNPYVtgvIgbguOfxgPOw4r0RmAyYEOgv6YFR\nfDeZTKaTU0dzU4cxUte7pPdJOwngiYh4DVgvPX0B0EfSksDdwLyFlx4C/FXSysAueCIEmB04NCWE\nTI1X/rsB76THtsSxvjsBn0laAbcWPaeNIV6bXgNWAsUWpPPjVqMrAbcCm0u6BPio8JoJ8GS9PC3h\nYxcBe6bX3QP0TY/PiJXa7nh3sA2wNlYEAHMD60paDngFWFPSsTj7cY/aoCJikfS6JYEl0uvmwNEJ\n6wO/J/uKMpmxgqamptJ/nZVRmZvmBL6S1CfdXwy4NyIeAnpLehUgTb5ERO2lCwCrRMTv0v1e6f9n\nkt5Lt9/Dk3TgnQCS3gBOTyvv5dNuBWC8iJhK0methvgYcG5ETIl3Le8WnnsfODMivsE9qB8bwUd8\nSdKPaey1cLJ5k0zwruCNwrE/R8QXwFuSfoqIwekzgHtnX5Hebx7giRG8H+nzPi3pF+AX4E/p/S8A\nrkvveWYbr81kMl2Izjz5l2VUQbwLAmdHRK2S2uvAF3hy+yAi5gKIiIMiYuPC614DTkur8S2Aq9Pj\nI+r3+irJlxARs0fEten116XXrw3cBHze+oWShuHV/nnA7a2evgjYQdL2wAfYfAR2vtc+94jGI2Db\n9N59gbtGcixp3JMBR+Idyk7A94X3a32VvAYsGhHNEdE9Ih6MiIWASSStC2wHnNXWe2UymS5EU4W/\nTsqozE23AgOBf0TEY8D9wIGSvsRmlksj4hFss7+n8NJjgS0i4mGcSv7SSN7mAmD2JOdK4NT02Dzp\nsceBd5N3f0Rcg01iN7V6/GpgYBr3JMD06fGBaaxtfS27A1dGxKPA8cALIxl7ja/wTuWJJP/7wvu9\nEhE1JYmk5/E5eQx4NI1fwEoR8ff0OQ4r8Z6ZTKaTMzaYm5qGDWtzgZzpxFz81LsN+eL++KeLGiE2\nlwqn65UKv10f113mxvNMW3eZADe98lFD5J68/jyjNXv32uba0r/Tz6/aqlNqiuwgzWQymQbRmXcI\nZclKIpPJZBpF19cRWUlkMplMo8g7iUwmk8m0SVYSmUwmk2mTcaEsRyaTyWTaSd5JZDqMlz76riFy\nrzlnz4bI/cP2x9Zd5h3XHF53mQA/DWlMWPiTgxoTWjt1jN8Qud/93FZqUvt5/tMv6i4T4PNvf26I\n3NElK4lMJpPJtElWEplMJpNpk6wkMplMJtM2XV9HZCWRyWQyjaK5eVQ1VDs/WUlkMplMg8jmpkwm\nk8m0TdfXEVlJZDKZTKMYG3YSXd9gNoaIiJUi4vpWjx0fEdtXkDFrRDyZbq8QEQum242pc5zJZDqU\nsaGfRFYSHUcfWhoTZTKZsZCxQUlkc1MdiIg/A8sD3YBTJd0UESsCh2NFPDGwFfBTOv63wFq4jekr\nwPipbevMwH+BzSR1zhTSTCZTmrGhdlPeSVRjlYh4uPaHJ/6ewGySlgNWBvpHxOTA/MDWqVf2rcDm\nNSGSnsEtTPtKGoSVyCFJxmS4HWwmk+ni5J3EuMffJG1ZuxMRx+P+2b9NSgOgOzAr8D5wZkR8A8yA\ne1q3xeeS3km3PwIa048yk8mMUTrz5F+WvJMYfX4AHko7hlWAG4G3gIuAHSRtD3zA/wbDDaXl/OdG\n45nMWEhTU/m/zkpWEqPP18A3ETEQeAYYJulr4GpgYEQ8hncbrZ3UTwHHR8S8Y3S0mUxmjJHNTeMQ\nkh4GHm71WL+RHL9/G08tlZ6/ALggPda78LotR/SiTCbT9WgeCxzXWUlkMplMg6jXBiEimoFzgYWA\nH4GdJL1ZeH5ToB82XV8j6Yz6vHM2N2UymUzDaG5uKv03CjYCJpC0NFYGp9SeiIhuwPHAasDSwB4R\nMVXdPkO9BGUymUxmeOrouF4Oh80j6UlgsdoTkn4B5pX0JTAlztf6qV6fISuJTCaTaRB1dFxPCnxZ\nuP9LRPzqLpA0JCI2Af6Ffaff1uszZCWRyWQyDaKOO4mvcJRkjWZJQ4oHSLoV52T1ALat12fIjusu\nyrzT9myI3Jtf+Lghco86bb+6y9zwwOtHfVA7OOrAdRoit1Fhjm8M/qYhcr/76Ze6y1xrrt6jPqgd\nPPz64IbIHV3q2HToMWB94MaIWAp4sfZEREwK3AmsIenHiPgW52HVhawkMplMpkHUcV1wG7B6RDyO\nE3N3iIitgIklXRgR1wB/j4ifgRdwnlZdyEoik8lkGkS9do+ShgK7tXr4tcLzFwIX1uXNWpGVRCaT\nyTSITpxIXZqsJDKZTKZBdOZyG2XJSiKTyWQaxFigI7KSyGQymUaRazdlMplMpk2yuSmTyWQybTIW\n6IhySiIiVsLNdF4pPPyppM1bHbcb0FvSEaM7sIhYAfhC0gsRcaukTUZD1uXAosDnOMZ4SuAUSZeN\n5DUnAGsDe6cy4ZlMJlOJcW0n8bcx3OugD3A98MLoKIgCfSXdBxARvYCXI+JySW11hdscWCg1EMpk\nMpnKjAU6YvTNTRGxHHAGMBgYAjwZEbMC10taKh3zJLAlLjp1BTA5XtFvC3wPnAdMAEwHDADeA9YC\nFo2IV4CnJfWOiEWAs4BfcNvQnXH9qevSa+ZIx+4+imH3Bn6QNCwiZsJJKD3TWHYBdsCd5O6OiDWB\nw4DlcXXFUyXdlHpafwL0AtbFtd7nSuMZIOnhiHgBeARYENd53xDXYDkLWALXWDlc0h0R8efW71Hq\nC8hkMp2WscFxXaWwyCoR8XDh78D0+HnA7yWtBrw9ChkDgL9IWgb4E54o58Gmn9XxBL2npGdwWdy+\nkgYVXn8RsJekFfGkfGp6fG5gxyRvnYgYUYGYEyNiYEQMSq+rmcpOBs5MPapPBo6XdBTwEbAGsBIw\nm0qqSf8AAB1QSURBVKTlgJWB/hExeXrtdelz9wE+k7QCVgTnpOcnTcesCLyPzVcbAVNJWiLJWywi\n1h7Je2QymS7KuNa+tC1z07SSXk+3HwPmHMExtTMQwKUAkh4HHo+I+YEBEbEjXm13H8kYppf0fLr9\nd9xoA+DNmlkoIj7Eu5LW9JV0X0SsA5wAvJUeXwA4JCIOSuP8udXrFgB+m3YOpPHNmm6rcMzyEbFk\nuj9eoenHc+n/e2lcswJPpHMwGDg0Ivq28R61z5rJZLognXnyL0s9ShS+HxHzptuLp/8/ANNERLe0\nIp4tPf5q7ZiIWCE5h48GrpS0DfAQLQpl6AjG90FELJhurwjUlFNbfoX/QdI9wO201Dl5DTgo7SR2\nBVqbeV4DHkrPr4Id+DUFM7RwzHXpmLWTjM/bGFvxHEwWEfeP4j0ymUwXpY6lwjuMKjuJVQor3Rpr\n44n1yoj4CvgaGCzpo4h4EPgHnuxqvViPAy6NiK3x5LkjsCRwckQcDPwHqK3AnwKOj4iiCWtn4OyI\naML+jx0rjL/I0cBzEbEucABwXkRMgP0S+7Q69k5gpYgYCEwM3Cbp64goHnMBcFFEPIJNTOdKGtrq\nmBp/AVaLiEfx+T8Sm9b+5z3a+dkymUwnYWzYSTQNG1Z6EZ7pRFzw5DsN+eIeeeOLRohlkZkmGfVB\nFTnspHvqLhO6Xj+Jycbv1hC5Tw2q/zrl0FVHZI0effrd/WpD5F637SKj9aWtfMbjpX+nD+2zTKfU\nKDmZLpPJZBrE2BDdlJVEJpPJNIjmscDclJVEJpPJNIixQEdkJZHJZDKNYmxwXGclkclkMg1iLHBJ\nZCXRVVlwqsYkZE/dc/yGyJ2z18R1l9mj33p1lwnQb/+zGiL3yVuObIjcC/7xXkPk7rnkzHWX+dEX\nP9RdJsD809c/eq4eZMd1JpPJZNqkiawkMplMJtMGY8FGIiuJTCaTaRTZcZ3JZDKZNhkLdERWEplM\nJtMocjJdJpPJZNokRzdlMplMpk3Ggo1EXfpJABAR80fE3RHxUET8IyKOTCW9xwgRsUtEjKxhURVZ\nK0XE9aM4Zq96vNcI5E4QETs1QnYmkxmzNDc1lf7rrNRFSaTGQtcD+0paGVgKd2vbtR7yS3II7g89\nphjQILm9gawkMpmxgKYKf52VepmbNsTtTd8AkPRLRGwL/AQQEacAy6Vjr5V0RkRcjluFzgKMj5XM\n+sDMSd5MQH/c/a03cKGkc1Ljo90kvRYRu6Xn3kv/rwc2iog/A8tjpXGqpJvS6z4BegF74jaqQ7Ci\n3ErSCNNWI+IF4BFgQdwoaUNgL6BXRJyLmxSdD8yVZA2Q9HBEvIQ75/2EO8/NBkyTPu9+ku6PiBWB\nY4FfcHOmXdNnni8iDku9tjOZTBelXiGwEdEMnAssBPwI7CTpzcLzvwf2xXPai8AekoaOSFZV6mVu\nmh74d/EBSd9I+iki1sMT5FJYUWwVEQukw96RtAZu6TmbpHWAW7CyAJgB2CC9dr+ImGZEby7pEuAj\nYMuIWDvJWg5YGeifdjrgFqOrAasBT6f/hwOTjeSzTZpetyLwPrC2pGOBzyXtgVf9n0laASuQc9Lr\nJgaOLvQF/1HS2lip7JdMcRcBmxRkb4+VxitZQWQyXZ/mpvJ/o2AjYAJJSwP9gFNqT0RET+AYYGVJ\ny+L5rG41a+q1k3gXWLT4QETMhncD8wIDJQ0Dfo6IJ4H50mHPpv9f4NU2wGBggnT7cUk/JnkvAXO0\net8RndoFgN8WWq12B2ZNt5X+XwIchNuGfolNVSPjufT/vcLYiu+3fEQsme6PFxG1FqwqHNdaxtTA\ndMCNqc1pT+DBUYwjk8l0IeoY3bQcnq+Q9GRELFZ47kdgGUnfpfvjAXUrklWvncRdwFoRMQdAciCf\nCvwG7xKWKzy+DPBGet2oWvstHBHdImJCYP70uh/w5ArDK6ah+PO8BjwkaSVgFeBGbMqpHQNe8Q+U\ntCpwE1YYI2NE46x9+6/hncZKuOf3TcDnrd5vRDI+wz29N0yvPRb4W+FzZDKZLk5TU1Ppv1EwKV7Q\n1vglIsYDkDRU0scAEfFHbMWo24KzLpORpK+A7YCL0gr+SeBfwHmS7gLejogn0uM3S3q2TWHD0x24\nFxgIHCPpM+BM4NyIuJ/hHdUDgXuAO4FvImIg8AwwTFLrZr3/BI6KiL8BuwHtKfv5SkRcDVwAzBMR\njwCPA++WsQWmY/YB7o6Ix4E9gJew36RHRJzQjjFlMplORB3NTV8BxVK3zZKG1O5ERHNEnAysDmya\nLDd1oWnYsLrJqisRsRJ2UG85qmPHRZ5484uGfHEffvt9I8Q2pFT4Q//f3p3H2zXdfRz/3AQJlcTY\nUoqgvqjQVhGEkCZIW0OVp6RKUrNHUaqmtHSI8jytKq0hCPXSUGnxGEqpiCGhabVBJfnVFDNFjJUg\nw/PHWrc9vTkn99x7907OPf2+8zqvnLv3Omuvc4f9O2utvddv1quF1wleKrzVoZ9Zu/A6359XyFzq\nIu54qpzfhdFDN+zSeNGoax6p++/08v0G1DyWpC8Bu0fESEkDgdPzHGfr/ktIw07HFDVh3co305mZ\nlaTAS1uvB4blUYcWYJSkEaShpT8BB5NGUybmOc6fRsT1RRy4YYNEREwCJi3lZpiZdVrPgiauc+/g\niDabZ1Y8L20es2GDhJlZd+elws3MrKYmiBEOEmZmZWnkNZnq5SBhZlaSJogRDhLd1UZrFH9JKcAK\ns8tZI7HXssXXO2qrdQuvE2DY/32/lHq3O7GQi00W8cj5+5ZS73LLFD8XOuf9+YXXCbCHPlJKvV3l\nOQkzM6upp4OEmZnV0gSJ6RwkzMzK4iBhZmY1eU7CzMxqck/CzMxqaoKOhIOEmVlZlmmCKOEg0QGS\nTialPF2WlBzomxHxYBfqOzoiflZU+8yssTRBjHAGtHpJ2pSUb3tYzkn9DWBcF6sd3eWGmVnD6tHS\nUvejUbknUb83gXWAr0m6LSKmSdo6Z+KbCWxMWuf9yxHxkqQfk9O2AuMj4qeSrgBWzY9bgFUkXQCc\nC1wOzCMF7hERUU4mGTNbYhr43F839yTqFBHPk3oS2wP3S5oJfCHvnpLzVP8KOFXSF4D+wEBSoBgh\naUAuOzEitouIMcDsiDiKlHJwKmko63Sg3xJ6W2ZWogLTly41DhJ1krQh8FZEfC0i1gEOAC4CVgEm\n5mJTAAGbAPdGxMKI+ICU23vTXCaqVH8Z8AZwG3A0qUdhZt1czx4tdT8alYNE/TYHfiZpufz130gn\n9vnAlnnb9sCjwAzyUJOkZYHtgMdymcr8s62/GXuSgspngQnASSW9BzNbgtyT+A8SEdeRcsj+UdJk\n4HfAiaS5ipGS7gY+D4yJiJuBpyTdT+pF/Doi/lyl2umSriLlqP2epImkFIXnl/+OzKxsLR3416g8\ncd0BeR5hTOU2SccBp0TEzDZlv1nl9SPbfL1zxZeDMLOm0sg9hHo5SJiZlcRBwshXNZmZLcIL/JmZ\nWU09m2DW10HCzKwkjXwndb0cJMzMSuI5CTMzq6kJOhIOEt3VvU++Ukq9KyxTzq/E2AeeKbzOgRus\nXHidALdMe6mUeg/cd8v2C3XCRp89oZR69z/p8MLr3HnDlQqvE+Ciu54qpd7JJ+7Ypdf3aOD7H+rl\nIGFmVhL3JMzMrKZlmmBSwkHCzKwkRfUkJPUALgC2AN4DDomIx9uUWQG4Azi47QoQXdEEV/GamTWm\nApMO7QX0johtgZOBH1fulPQZ4B5gg8LfQ9EVmplZ0tJS/6Mdg0ipBIiIB4DPtNnfC/giKQFaoRwk\nzMxK0qMDj3b0Ja043Wq+pH9OF0TE5LKyWXpOwsysJAXecf0W0Key6ohYIsnJSg0SknYCrgWmkxLs\n9AKOjIi/dLCe6yJi7+JbuMhxRgLfA56s2HwOKfvc7Ii4sew2mFnzKDBITAZ2B66VNBB4pKiK27Mk\nehITI2I/AEm7AN/nX7mh67IkAkSF8RFx8hI8npk1qQIvgL0eGCZpSq52lKQRwIoRMba4wyxqSQ83\nrQz8HUDSJOCIiJgp6QhgDeAsUs+jH7ACcFpE3C7ppYhYI79mGrAZaYxu34h4WtLXgRHAQuCaiDhP\n0t6kNKAfAC8A+wHbkq4K+AB4F9gnIt5ur9GSzgBeIk0KnQS8D6yfjzVG0makHkdPYDVSb2mKpMdI\nnwAEvAx8CVgOuBxYNz8/mpSZ7iLg46ThydERMalj31ozazRFdSQiYgEpa2WlRSapy0hdsCQmrodI\nmpRTeV4OXLOYshuQTrK7A/tTPYhNjYihpOuB95e0KfBl0uz/DsBekpRf/78RMQi4mRRU9iIFocHA\nhaSg1daI3N5JkiZU2b8u6WQ/EPhW3vYJ4ISco/psYFTevj7w7XzZ2urAVqQf9Ky8bT9gG+AQ4NWI\n2JGU7/rni/kemVk30dLSUvejUS3p4SYB90taq02ZFoCIeFTSxcDVwLLAeVXqa53PeJbU+9iMdOK+\nM29fmfSJ/HjglNzLmAHcAJwJnJbLPg/8oUr97Q03PZInjOZJmpO3PQ98O3/dhzTJBOnE33rFwbNA\nb1Kv4tb8fh8DzpV0AbCDpG1y2WUkrRYRry6mHWbW4Jrh8tEl/R5erng+F1gzP/80gKQBQJ+I+Dxw\nEHB+lToWtvk6gEeBnXNX6wrgYeAw4IyIGEwKQl8EDgCuyLmlH81lOqrt8SEFs9Mj4iDShFLLYsrO\nIPUokLS+pPGkbuPVuf3DgQnA7E60zcwaSIE30y01S6InMSTPJcwnfco+PiLmSDoPuEDSM6RP4gCP\nAadL+i9SAPtOe5VHxEOS7gTuk9QLmJrrmwrcLOlt4B3SkNOGwKWS/gEsoHNBopqrgAmSXgeeIw2Z\n1XIxME7S3aQ5jONIgeWSvK0vcEEegzSzbqyRh5Hq1bJwYbUPu9bobnj4xVJ+cF4qvLylwgesW057\nL/luOVNYXiocJp+4Y5fO8tc9VP/f6d5brNmQEcU305mZlaQZehIOEmZmJen+IcJBwsysND3dkzAz\ns1qaIEY4SJiZlaWlCQacHCTMzErSDD0JXwLbTf1+xqul/OD69Vq2jGpZoVfPwut84a057RfqhKff\nereUetf8UO9S6n3hnbml1HvWhEcLr3PcYQMLrxNg1Q8tV0q9m629YpdO87c9+krdf6e7fWL1hgwp\n7kmYmZWkGXoSDhJmZiVp5OU26uUgYWZWkh7dP0Y4SJiZlcVXN5mZWU1NMNrkIGFmVhb3JMzMrKb/\nuDkJSTuR0n9Or9j8SkTsu5jXHAZcHhEf1FF/b+CAiLh0MWWuAQ6MiPfrbngnSVoF2C0ixrfZPgn4\nSERsUrFtb+A3QP+ImNWBY5wLnBMRxa+lbWZL1X/q1U3/TEdap1OBK4F2gwQpHekhQM0g0cFjd9Xm\nwB7A+Go7JX0yIqblL/cDnu7oASLiuM43z8waWfcPEQUON+VP19NIOaf7AvsCQ0kn/muAvST9ENiB\nlJHtnIiYkF/3d2AV4ClgU0nfAcYBF5LyQq8JjI6IGyTNAjYGLgLeA9bL+0dGxJ8lPQ5MATYi5bLu\nB2wNRER8VdLHgLHA8sAcUna6nqS82s8CGwBTI+JIUj7sLSQdFhFj27zlq4H9gWmSVsrtfCl/L84A\nXoqIiyRtDFwUETtJGgPsTPq+/yYizs7v/wjgNeAXwEqk360Dcw5sM+ummqEn0Zkc10MkTap4nFix\nb2pEDAXuAPaPiMtIJ879JA0nDcUMIp0oT8snV0j5nYcCY4DpEfE9UiD4cUQMI53I/7tKW56OiF1J\nubBbU5GuB4wmBaNjgAuAbYBB+Xg/As7L+aR/BJyVX7cRcDApoHxO0hq5PROrBAiAm3K5FmAf4Nd1\nfO++AozIbXujzb7RwI0RsR1wQm6HmXVjLR14NKqih5v+kv9/ltSDqDQA2DJ/cgZYlnRCB4gqdb0I\njJZ0MLAwl1/c8bbPz19rHd+X9I+ImJ6fv0n6tD8AOFXSSaSfTesw2OMR8XYu+2Iuuzhz8vG3BfYi\nDTcdVaVc5c//K6SgtAZwa5tyIvWeiIgppN6QmXVnjXz2r1NnehKLU20xqwX5ODOBu/In+CGkCfAn\nKspUlgX4PnBlRHwVuIvq3+5qx2tvQa2ZwEm5HYcDE+poey3jgeOB1yPinYrtc0lDYACfBpDUizQE\ntz+pJzVS0roVr5kBbJXL7ijp7Hbeh5k1uB4tLXU/GlVnehJDKnoDrYYvpvy9wG9JJ8adJN0LrAhc\nHxFvS6os+3dguXyCnAD8SNIpwHPAap1oazXfBC7MV1ItDxy7mLJPAAMkHRcR51bZ/3vSPMKoNtt/\nBVwraTDwIEBEvCdpNvAAqRdyO1B5RdOZwDhJB5AC1sEdfmdm1lAa99RfPy8V3k15qXAvFd7KS4U3\n7lLhf3zqzbr/Trfq368hY4pvpjMzK4nvuDYzs5oaeKqhbg4SZmYlKSpGSOpBupx/C9L9YYdExOMV\n+3cHvgPMA8ZFxCUFHbrwq5vMzCxraWmp+9GOvYDeEbEtcDLw49YdkpYFfgLsAgwGDpP0kaLeg4OE\nmVlJWlrqf7RjEHAbQEQ8AHymYt8mpPu8Xs9r2t0H7FjUe/BwUzd1+xOvlVLvp9dasZR6L76nw8ta\ntWuTtVdqv1AnvPh6OVc3/eO9eaXUO2/+gvYLdcJmG69eeJ27nXJ94XUCnHrk4FLq3WztDbv0+gKn\nJPoCb1Z8PV/SMhExr8q+t0nLERXCQcLMrCzFRYm3gD4VX/fIAaLavj4suuxPp3m4ycysJC0d+NeO\nycDnACQNBB6p2DcD+LikVSQtRxpqur+o9+CehJlZSQq8BPZ6YJikKaT+yShJI4AVI2KspOOB35E+\n+I+LiOeLOrCDhJlZSYoKEhGxgJRSoNLMiv03kVamLpyDhJlZSXzHtZmZ1eQ7rs3MrKYmiBH1BwlJ\n6wEPA3+u2DwxZ5HrMEmfBPaIiO9Jeiki2iYpqvaaWaTltReQUo6uCBwaEX+qUX4ksHFEnFxj/yrA\nbhExXtLJ+f1M7cz7aVPvIu8nt2V2RNzY1frNrJtogijR0Z7E9Jysp8siYhopJ3ZH7RIRcwEk7Qqc\nAXyhk83YHNgDGB8RZ7VXuCsi4ooy6zezxtPIyYTq1eXhJkk9gYuBj5Gysd0YEaMlXUFKDbou0Au4\nBtgdWAfYM5c/ojUVqqR+pF7KRhExPyceejAirl3M4dcFXs+vH0zKST2flCzo8Dbt/CHpVvZVgYci\nYhRwGrCFpMOA7XIb7wQuB9Yn9VbOiYhf5URL04DNSHc47gu8TMqw1w9YATgtIm4Hekkan9/ra6Qc\n2KeR8n3PzM8XkNKYjo2In0s6Cjgob/9jRBzT7jffzBpa9w8RHb+ZblNJkyoea5FO9g9ExK7A1vz7\nZVqzImIX0s0e/SPic8BvSMHi30TEm6Q1R3bNgWc4cEOVNtwuaaqk5/LxvimpBbgE2DsiBgPPAyNb\nXyCpLynF6DBSoBiY2z6GNMQ0tqL+w4FXImI7YCjwA0mtWfGmRsRQ4A5SGtINSBnzds9ftwbdFYFT\nI2IQKYB8qs17WIvUgxkIfEPSh0nZ7Y7OC3jNkOT5IrPurqUDjwbV5eGmfALeStLOpNvDe1Xsbp2/\neIN/XdP7OlArRdclwDGk4PX7vFhVW7tExFxJZwL9SSlPVyf1Yq7N6VCXJ53IW5fSnQN8WNLVwDuk\nk3itFGybkNKSktOrTicFA4C/5P+fBdaIiEclXQxcnes7L++fHRGz8vOXSL2MSlMi4j0ASX/N9Y8i\nBbz+pLslG/jXxszq0QyXwBaxLMdI4I2I+App+doV8id7SLma6xYR95FOmAcDl7VTfDTwUeAo4FVS\nHuw9cxAbA0ysKDsc+FhE7A+cSgoiLaShnbbfgxnADgCS+gADgKeqvR9JA4A+EfF50lDR+dXKVfFJ\nST0lrQB8AngMOJQ0/DaY1PPYrp06zKzBFbgK7FJTRJC4E9hN0j3AhaQT3ke7UN8vyZ/SF1co34F4\nCClYrAEcC9ySb1s/CvhrRfGpwPq5jb8GnsxtfAIYIOm4irJjgVUl3QdMAr4bEX+v0YzHgJ1yvRNI\nST/qsSxwK3Av8IOIeJW0Fsu9kiaSekd/qLMuM2tQTTDaRMvChR36sF86SScCr0XEuKXdljJI2omK\nCfvO+tbNUcoPzkuFe6nwVn2WrzUi23m33/pw4XVCeUuFf3vYhl06fz/5yty6/07XX713Q8aKhpoc\nzVdEfZQqE9tmZt1NIw8j1auhgkREjFzabShbREwiDWOZWZNrghjRWEHCzKypNEGUcJAwMytJM1wC\n6yBhZlYSz0mYmVlNPZogSDTcJbBWnyv/9GwpP7gt11y5jGq5+W8vF17nOv16tV+oE956v5xLVd+Y\nM7+Ueue8X84lsH179yy8zqO2X7/wOgFWHnJ6KfXOuee7XTrNP/f6+3X/na698nINGVLckzAzK4mH\nm8zMrKYmiBEOEmZmZXFPwszMamppgijhIGFmVpLuHyIcJMzMStMEHQkHCTOzsvzH3nGdl7u+FphO\nSrCzPPDLiDi/Rvn1gGsiYqCka4ADSTkgtoiImySdS8ol/Uwn2zMUOIWUFW8eMAs4NqdE7XYkHR0R\nP1va7TCzLur+MaJLSYcmRsROEbEzMBg4QVK7C/xHxH45LekQYPu87bguBIgtgP8BDoyIQTkz3UPA\ntzpTX4MYvbQbYGZd1wxJh4oabuoDzAfmSfoUKY3nfGAuKS3nP0maRUrZeTIp1ekU4HjgCOA14BfA\nSqTv24HAh0lpUT8A3gX2iYi3K6o8gpTd7fnWDRHxk4rjDQN+kNvyGvA1Uga5hyLiF5LWAG6JiC0l\n/ZCUurQnqWczQdIkUqa4VUi5rHcl5azeADg7Iq7IZR4CNiPl0L43l1sJ2CVvuwj4OCkwj46ISZIe\nBu4GNif1yPYEjgZWkXRBRBxV37ffzBpRjyaYlOhKT2KIpEk53eYvga9HxDvAJcDROVfzBcA5VV47\nHzgLGB8RN1ZsHw3cGBHbAScAWwN7kYa2BpPSo7ZdN6I/8DiApP65TXdLui/n2h4L7J3bc3c+xqWk\nnNQAXwUulzQc6B8Rg4CdgdMqekZXR8TQ3O5+EfEFYA9SoGs1NSI+SxryejcihpGG4waT0qy+GhE7\nkgLBz/Nr+ua6BwPPA8MjYgww2wHCrPtrhhzXXelJTKyRgvOjETEtP7+HFAzqJWAcQERMAaZI+i1w\nGimX9vMsmvv5WVKgeDginiLlnO4NzARWA96q6GXcA5wZEdMlLSNpXeDLwFDgMGDL3CuAlId6vfw8\nKo7X+t6eBXpXbP9z/v8NUnAAeD2XGQDsIGmbvH0ZSavl53+pUZ+ZWU2SlgeuIo22vA0cFBGvVCm3\nOjAZ2Dwi5nb0OF3pSdTygqTN8/PBwN9qlFtQ5fgzgK0AJO0o6WzgAOCKPPfxKOlkXukiYLSkNSu2\n7UwavnkV6Fuxr7I9l5HmMqZHxBukoHJXntMYQuq9PFHR1la1Fuxa3EJeM0k9hp2A4cAEYPZiXtfA\nnyvMrF4l9ySOBB6JiB2AK6kylylpV+B20oVCnVJGkDgU+Jmke4FjgW/UKPcIsKekyt7ImXnbJOC7\nwMXAVOBSSXeSTt5XVlYSEQ8CJwK/kHSXpKmkQLJPRCzM7blO0mRSj+H7+aUTSPMGl+avbwLeye1+\nEFjYZu6jKy4GNpZ0NzAFeDoiFrd053RJVxV0bDNbSlo68K8TBgG35ee3ks5vbS3I22dX2VcXLxXe\nTXmpcC8V3spLhTfuUuFvzV1Q999p3961s09IOphFP3C/TJr/nSGpB/BMRKxd4/WzgI07M9zkm+nM\nzEpS1IR0RFxGGiL/J0nXka4sJf//RjFH+3dlDDeZmRmlDzdNBj6Xnw8nXXpfOPckzMxKUvKlrReS\n5mLvA94HRgBIOh54vM3tBZ3mIGFmVpIyY0REvAvsW2X7IvemRcR6nT2Og4SZWVma4GJ2Bwkzs5I0\nw7IcvgTWzMxq8tVNZmZWk4OEmZnV5CBhZmY1OUiYmVlNDhJmZlaTg4SZmdX0//hrBKKuzTJqAAAA\nAElFTkSuQmCC\n", 55 | "text/plain": [ 56 | "" 57 | ] 58 | }, 59 | "metadata": {}, 60 | "output_type": "display_data" 61 | } 62 | ], 63 | "source": [ 64 | "plt.imshow(m, cmap='Blues',)\n", 65 | "plt.colorbar()\n", 66 | "plt.grid(False)\n", 67 | "ax = plt.gca();\n", 68 | "ax.xaxis.tick_top()\n", 69 | "ax.set_xticks(np.arange(0, 10, 1));\n", 70 | "ax.set_yticks(np.arange(0, 10, 1));\n", 71 | "ax.set_xticklabels(class_name, rotation = 45, ha=\"left\",);\n", 72 | "ax.set_yticklabels(class_name);\n", 73 | "plt.savefig('Covariance_matrix_yahoo_label.pdf', bbox_inches='tight')" 74 | ] 75 | }, 76 | { 77 | "cell_type": "code", 78 | "execution_count": 24, 79 | "metadata": {}, 80 | "outputs": [ 81 | { 82 | "data": { 83 | "image/png": "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\n", 84 | "text/plain": [ 85 | "" 86 | ] 87 | }, 88 | "metadata": {}, 89 | "output_type": "display_data" 90 | } 91 | ], 92 | "source": [ 93 | "cax = plt.imshow(m, cmap='Blues',)\n", 94 | "plt.colorbar()\n", 95 | "plt.grid(False)\n", 96 | "ax = plt.gca();\n", 97 | "plt.xticks([], [])\n", 98 | "plt.yticks([], [])\n", 99 | "\n", 100 | "# Add colorbar, make sure to specify tick locations to match desired ticklabels\n", 101 | "# cbar = plt.colorbar(cax, ticks=[-0.1, 0.0, 0.1, 0.2,0.3, 0.4, 0.5])\n", 102 | "# cbar.ax.set_yticklabels(['-0.1', '0.0', '0.1', '0.2', '0.3', '0.4', '0.5'], fontsize=20)# vertically oriented colorbar\n", 103 | "\n", 104 | "plt.savefig('Covariance_matrix_yahoo.pdf', bbox_inches='tight')" 105 | ] 106 | }, 107 | { 108 | "cell_type": "code", 109 | "execution_count": null, 110 | "metadata": { 111 | "collapsed": true 112 | }, 113 | "outputs": [], 114 | "source": [] 115 | } 116 | ], 117 | "metadata": { 118 | "kernelspec": { 119 | "display_name": "Python 2", 120 | "language": "python", 121 | "name": "python2" 122 | }, 123 | "language_info": { 124 | "codemirror_mode": { 125 | "name": "ipython", 126 | "version": 2 127 | }, 128 | "file_extension": ".py", 129 | "mimetype": "text/x-python", 130 | "name": "python", 131 | "nbconvert_exporter": "python", 132 | "pygments_lexer": "ipython2", 133 | "version": "2.7.13" 134 | } 135 | }, 136 | "nbformat": 4, 137 | "nbformat_minor": 2 138 | } 139 | -------------------------------------------------------------------------------- /plots/correlation/yahoo_legend.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guoyinwang/LEAM/bfd341ccd92009ab6b9e6b0578216f57bb2b921e/plots/correlation/yahoo_legend.pdf -------------------------------------------------------------------------------- /plots/correlation/yahoo_tsne.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guoyinwang/LEAM/bfd341ccd92009ab6b9e6b0578216f57bb2b921e/plots/correlation/yahoo_tsne.pdf -------------------------------------------------------------------------------- /plots/correlation/yahoo_tsne2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guoyinwang/LEAM/bfd341ccd92009ab6b9e6b0578216f57bb2b921e/plots/correlation/yahoo_tsne2.pdf -------------------------------------------------------------------------------- /plots/schemes/scheme_a.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guoyinwang/LEAM/bfd341ccd92009ab6b9e6b0578216f57bb2b921e/plots/schemes/scheme_a.pdf -------------------------------------------------------------------------------- /plots/schemes/scheme_a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guoyinwang/LEAM/bfd341ccd92009ab6b9e6b0578216f57bb2b921e/plots/schemes/scheme_a.png -------------------------------------------------------------------------------- /plots/schemes/scheme_b.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guoyinwang/LEAM/bfd341ccd92009ab6b9e6b0578216f57bb2b921e/plots/schemes/scheme_b.pdf -------------------------------------------------------------------------------- /plots/schemes/scheme_b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guoyinwang/LEAM/bfd341ccd92009ab6b9e6b0578216f57bb2b921e/plots/schemes/scheme_b.png -------------------------------------------------------------------------------- /plots/text_attention/yahoo_examples_1.npz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guoyinwang/LEAM/bfd341ccd92009ab6b9e6b0578216f57bb2b921e/plots/text_attention/yahoo_examples_1.npz -------------------------------------------------------------------------------- /plots/yahoo_partial/yahoo_partial.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guoyinwang/LEAM/bfd341ccd92009ab6b9e6b0578216f57bb2b921e/plots/yahoo_partial/yahoo_partial.pdf -------------------------------------------------------------------------------- /preprocess_yahoo.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Mon May 1 01:53:46 2017 4 | 5 | @author: DinghanShen 6 | """ 7 | 8 | import csv 9 | import numpy as np 10 | import os 11 | import re 12 | import cPickle 13 | import string 14 | import pdb 15 | 16 | def is_number(s): 17 | try: 18 | float(s) 19 | return True 20 | except ValueError: 21 | return False 22 | #============================================================================== 23 | loadpath = './test.csv' 24 | 25 | x = [] 26 | with open(loadpath, 'rb') as f: 27 | for line in f: 28 | x.append(line) 29 | 30 | def clean_str(string): 31 | """ 32 | Tokenization/string cleaning for all datasets except for SST. 33 | Every dataset is lower cased except for TREC 34 | """ 35 | string = re.sub(r"[^A-Za-z0-9(),\.!?]", " ", string) 36 | #string = re.sub(r"\'s", " \'s", string) 37 | string = re.sub(r"e\.g\.,", " ", string) 38 | string = re.sub(r"a\.k\.a\.", " ", string) 39 | string = re.sub(r"i\.e\.,", " ", string) 40 | string = re.sub(r"i\.e\.", " ", string) 41 | #string = re.sub(r"\'ve", " \'ve", string) 42 | #string = re.sub(r"\'", "", string) 43 | #string = re.sub(r"\'re", " \'re", string) 44 | #string = re.sub(r"\'d", " \'d", string) 45 | #string = re.sub(r"\'ll", " \'ll", string) 46 | string = re.sub(r",", " , ", string) 47 | string = re.sub(r"br", "", string) 48 | string = re.sub(r"!", " ! ", string) 49 | string = re.sub(r"\(", " ( ", string) 50 | string = re.sub(r"\)", " ) ", string) 51 | string = re.sub(r"\?", " ? ", string) 52 | string = re.sub(r"\.", " . ", string) 53 | string = re.sub(r"\s{2,}", " ", string) 54 | string = re.sub(r"u\.s\.", " us ", string) 55 | return string.strip().lower() 56 | 57 | 58 | lab = [] 59 | sent = [] 60 | vocab = {} 61 | 62 | for i in range(60000): 63 | # lab.append(clean_str(x[i].split(",")[0])) 64 | m = re.search(',', x[i]) 65 | rest = x[i][m.start()+1:] 66 | m = re.search(',', rest) 67 | temp = clean_str(rest[:m.start()]).split() 68 | # temp = clean_str(x[i][m.start()+1 : n + 1]).split() 69 | temp = [ j if not is_number(j) else '0' for j in temp] 70 | if len(temp) > 300: 71 | lab.append(clean_str(x[i].split(",")[0])) 72 | temp = temp[:300] 73 | sent.append(temp) 74 | elif len(temp) <= 5: # remove too short question 75 | continue 76 | else: 77 | lab.append(clean_str(x[i].split(",")[0])) 78 | sent.append(temp) 79 | t = set(temp) 80 | for word in t: 81 | if word in vocab: 82 | vocab[word] += 1 83 | else: 84 | vocab[word] = 1 85 | 86 | loadpath = './train.csv' 87 | 88 | x = [] 89 | with open(loadpath, 'rb') as f: 90 | for line in f: 91 | x.append(line) 92 | 93 | train_lab = [] 94 | train_sent = [] 95 | 96 | for i in range(len(x)): 97 | # train_lab.append(clean_str(x[i].split(",")[0])) 98 | m = re.search(',', x[i]) 99 | rest = x[i][m.start()+1:] 100 | m = re.search(',', rest) 101 | temp = clean_str(rest[:m.start()]).split() 102 | 103 | # temp = clean_str(x[i][m.start()+1: n+ 1]).split() 104 | temp = [ j if not is_number(j) else '0' for j in temp] 105 | if len(temp) > 300: 106 | train_lab.append(clean_str(x[i].split(",")[0])) 107 | temp = temp[:300] 108 | train_sent.append(temp) 109 | elif len(temp) <= 5: # remove too short question 110 | continue 111 | else: 112 | train_lab.append(clean_str(x[i].split(",")[0])) 113 | train_sent.append(temp) 114 | t = set(temp) 115 | for word in t: 116 | if word in vocab: 117 | vocab[word] += 1 118 | else: 119 | vocab[word] = 1 120 | #============================================================================== 121 | 122 | print('create ixtoword and wordtoix lists...') 123 | 124 | v = [x for x, y in vocab.iteritems() if y >= 30] 125 | 126 | # create ixtoword and wordtoix lists 127 | ixtoword = {} 128 | # period at the end of the sentence. make first dimension be end token 129 | ixtoword[0] = 'END' 130 | ixtoword[1] = 'UNK' 131 | wordtoix = {} 132 | wordtoix['END'] = 0 133 | wordtoix['UNK'] = 1 134 | ix = 2 135 | for w in vocab: 136 | wordtoix[w] = ix 137 | ixtoword[ix] = w 138 | ix += 1 139 | 140 | def convert_word_to_ix(data): 141 | result = [] 142 | for sent in data: 143 | temp = [] 144 | for w in sent: 145 | if w in wordtoix: 146 | temp.append(wordtoix[w]) 147 | else: 148 | temp.append(1) 149 | temp.append(0) 150 | result.append(temp) 151 | return result 152 | 153 | train_x = train_sent[:1100000] 154 | train_y = train_lab[:1100000] 155 | val_x = train_sent[1100000:] 156 | val_y = train_lab[1100000:] 157 | test_x = sent 158 | test_y = lab 159 | 160 | 161 | train_text = [' '.join(s) for s in train_x] 162 | val_text = [' '.join(s) for s in val_x] 163 | test_text = [' '.join(s) for s in test_x] 164 | 165 | 166 | 167 | train_x = convert_word_to_ix(train_x) 168 | val_x = convert_word_to_ix(val_x) 169 | test_x = convert_word_to_ix(test_x) 170 | 171 | 172 | 173 | 174 | cPickle.dump([train_x, val_x, test_x, train_text, val_text, test_text, train_y, val_y, test_y, wordtoix, ixtoword], open("yahoo4char.p", "wb")) 175 | 176 | pdb.set_trace() 177 | -------------------------------------------------------------------------------- /utils.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import tensorflow as tf 3 | from tensorflow.python import pywrap_tensorflow 4 | import sys 5 | import os 6 | 7 | def prepare_data_for_emb(seqs_x, opt): 8 | maxlen = opt.maxlen 9 | lengths_x = [len(s) for s in seqs_x] 10 | if maxlen != None: 11 | new_seqs_x = [] 12 | new_lengths_x = [] 13 | for l_x, s_x in zip(lengths_x, seqs_x): 14 | if l_x < maxlen: 15 | new_seqs_x.append(s_x) 16 | new_lengths_x.append(l_x) 17 | else: 18 | new_seqs_x.append(s_x[:maxlen]) 19 | new_lengths_x.append(maxlen) 20 | lengths_x = new_lengths_x 21 | seqs_x = new_seqs_x 22 | 23 | if len(lengths_x) < 1: 24 | return None, None 25 | 26 | n_samples = len(seqs_x) 27 | maxlen_x = np.max(lengths_x) 28 | x = np.zeros((n_samples, maxlen)).astype('int32') 29 | x_mask = np.zeros((n_samples, maxlen)).astype('float32') 30 | for idx, s_x in enumerate(seqs_x): 31 | x[idx, :lengths_x[idx]] = s_x 32 | x_mask[idx, :lengths_x[idx]] = 1. # change to remove the real END token 33 | return x, x_mask 34 | 35 | def restore_from_save(t_vars, sess, opt): 36 | save_keys = tensors_key_in_file(opt.save_path) 37 | #print(save_keys.keys()) 38 | ss = set([var.name for var in t_vars])&set([s+":0" for s in save_keys.keys()]) 39 | cc = {var.name:var for var in t_vars} 40 | ss_right_shape = set([s for s in ss if cc[s].get_shape() == save_keys[s[:-2]]]) # only restore variables with correct shape 41 | 42 | if opt.reuse_discrimination: 43 | ss2 = set([var.name[2:] for var in t_vars])&set([s+":0" for s in save_keys.keys()]) 44 | cc2 = {var.name[2:][:-2]:var for var in t_vars if var.name[2:] in ss2 if var.get_shape() == save_keys[var.name[2:][:-2]]} 45 | for s_iter in ss_right_shape: 46 | cc2[s_iter[:-2]] = cc[s_iter] 47 | 48 | loader = tf.train.Saver(var_list=cc2) 49 | loader.restore(sess, opt.save_path) 50 | print("Loaded variables for discriminator:"+str(cc2.keys())) 51 | 52 | else: 53 | loader = tf.train.Saver(var_list= [var for var in t_vars if var.name in ss_right_shape]) 54 | loader.restore(sess, opt.save_path) 55 | print("Loading variables from '%s'." % opt.save_path) 56 | print("Loaded variables:"+str(ss_right_shape)) 57 | 58 | return loader 59 | 60 | def tensors_key_in_file(file_name): 61 | """Return tensors key in a checkpoint file. 62 | Args: 63 | file_name: Name of the checkpoint file. 64 | """ 65 | try: 66 | reader = pywrap_tensorflow.NewCheckpointReader(file_name) 67 | return reader.get_variable_to_shape_map() 68 | except Exception as e: # pylint: disable=broad-except 69 | print(str(e)) 70 | return None 71 | 72 | def get_minibatches_idx(n, minibatch_size, shuffle=False): 73 | idx_list = np.arange(n, dtype="int32") 74 | 75 | if shuffle: 76 | np.random.shuffle(idx_list) 77 | 78 | minibatches = [] 79 | minibatch_start = 0 80 | for i in range(n // minibatch_size): 81 | minibatches.append(idx_list[minibatch_start: 82 | minibatch_start + minibatch_size]) 83 | minibatch_start += minibatch_size 84 | return zip(range(len(minibatches)), minibatches) 85 | 86 | def load_class_embedding( wordtoidx, opt): 87 | print("load class embedding") 88 | name_list = [ k.lower().split(' ') for k in opt.class_name] 89 | id_list = [ [ wordtoidx[i] for i in l] for l in name_list] 90 | value_list = [ [ opt.W_emb[i] for i in l] for l in id_list] 91 | value_mean = [ np.mean(l,0) for l in value_list] 92 | return np.asarray(value_mean) 93 | 94 | --------------------------------------------------------------------------------