From 8ec76b6d368facb596b9b70782761ca607b652a7 Mon Sep 17 00:00:00 2001 From: zsdonghao Date: Mon, 15 Jan 2018 10:20:01 +0000 Subject: [PATCH] update TL to latest version --- README.md | 3 + main.py | 4 +- tensorlayer/__init__.py | 3 +- tensorlayer/activation.py | 29 +- tensorlayer/cost.py | 312 ++-- tensorlayer/db.py | 2 +- tensorlayer/distributed.py | 308 ++++ tensorlayer/files.py | 1028 +++++++++-- tensorlayer/iterate.py | 13 +- tensorlayer/layers.py | 1614 ++++++++++++++--- tensorlayer/nlp.py | 773 ++++---- tensorlayer/ops.py | 77 +- tensorlayer/prepro.py | 1572 +++++++++++++--- tensorlayer/rein.py | 65 +- tensorlayer/third_party/__init__.py | 0 .../third_party/roi_pooling/.gitignore | 3 + tensorlayer/third_party/roi_pooling/README.md | 56 + .../roi_pooling/examples/__init__.py | 0 .../roi_pooling_minimal_example.ipynb | 148 ++ .../roi_pooling/roi_pooling/Makefile | 18 + .../roi_pooling/roi_pooling/__init__.py | 0 .../roi_pooling/roi_pooling/roi_pooling.cc | 162 ++ .../roi_pooling/roi_pooling/roi_pooling.cu.cc | 214 +++ .../roi_pooling/roi_pooling_ops.py | 51 + .../roi_pooling/roi_pooling_test.py | 110 ++ .../roi_pooling/roi_pooling_animation.gif | Bin 0 -> 578933 bytes .../roi_pooling/roi_pooling_example.py | 63 + tensorlayer/third_party/roi_pooling/setup.py | 32 + .../third_party/roi_pooling/test_roi_layer.py | 66 + tensorlayer/utils.py | 39 +- tensorlayer/visualize.py | 130 +- 31 files changed, 5706 insertions(+), 1189 deletions(-) create mode 100644 tensorlayer/distributed.py mode change 100755 => 100644 tensorlayer/layers.py create mode 100644 tensorlayer/third_party/__init__.py create mode 100644 tensorlayer/third_party/roi_pooling/.gitignore create mode 100644 tensorlayer/third_party/roi_pooling/README.md create mode 100644 tensorlayer/third_party/roi_pooling/examples/__init__.py create mode 100644 tensorlayer/third_party/roi_pooling/examples/roi_pooling_minimal_example.ipynb create mode 100644 tensorlayer/third_party/roi_pooling/roi_pooling/Makefile create mode 100644 tensorlayer/third_party/roi_pooling/roi_pooling/__init__.py create mode 100644 tensorlayer/third_party/roi_pooling/roi_pooling/roi_pooling.cc create mode 100644 tensorlayer/third_party/roi_pooling/roi_pooling/roi_pooling.cu.cc create mode 100644 tensorlayer/third_party/roi_pooling/roi_pooling/roi_pooling_ops.py create mode 100644 tensorlayer/third_party/roi_pooling/roi_pooling/roi_pooling_test.py create mode 100644 tensorlayer/third_party/roi_pooling/roi_pooling_animation.gif create mode 100644 tensorlayer/third_party/roi_pooling/roi_pooling_example.py create mode 100644 tensorlayer/third_party/roi_pooling/setup.py create mode 100644 tensorlayer/third_party/roi_pooling/test_roi_layer.py diff --git a/README.md b/README.md index 19f0cc07..ac5add90 100755 --- a/README.md +++ b/README.md @@ -64,6 +64,9 @@ python main.py --mode=evaluate * [1] [Photo-Realistic Single Image Super-Resolution Using a Generative Adversarial Network](https://arxiv.org/abs/1609.04802) * [2] [Is the deconvolution layer the same as a convolutional layer ?](https://arxiv.org/abs/1609.07009) +### Author +- [zsdonghao](https://github.com/zsdonghao) + ### License - For academic and non-commercial use only. diff --git a/main.py b/main.py index d9828842..0d1ff6f5 100755 --- a/main.py +++ b/main.py @@ -278,8 +278,8 @@ def evaluate(): # print(valid_lr_img.min(), valid_lr_img.max()) size = valid_lr_img.shape - t_image = tf.placeholder('float32', [None, size[0], size[1], size[2]], name='input_image') - # t_image = tf.placeholder('float32', [1, None, None, 3], name='input_image') + # t_image = tf.placeholder('float32', [None, size[0], size[1], size[2]], name='input_image') # the old version of TL need to specify the image size + t_image = tf.placeholder('float32', [1, None, None, 3], name='input_image') net_g = SRGAN_g(t_image, is_train=False, reuse=False) diff --git a/tensorlayer/__init__.py b/tensorlayer/__init__.py index bdb2b987..0a45da2e 100644 --- a/tensorlayer/__init__.py +++ b/tensorlayer/__init__.py @@ -21,12 +21,13 @@ from . import prepro from . import nlp from . import rein +from . import distributed # alias act = activation vis = visualize -__version__ = "1.5.0" +__version__ = "1.7.3" global_flag = {} global_dict = {} diff --git a/tensorlayer/activation.py b/tensorlayer/activation.py index 7b6b6402..a5e38360 100644 --- a/tensorlayer/activation.py +++ b/tensorlayer/activation.py @@ -1,7 +1,5 @@ #! /usr/bin/python -# -*- coding: utf8 -*- - - +# -*- coding: utf-8 -*- import tensorflow as tf @@ -13,7 +11,6 @@ def identity(x, name=None): x : a tensor input input(s) - Returns -------- A `Tensor` with the same type as `x`. @@ -37,14 +34,13 @@ def ramp(x=None, v_min=0, v_max=1, name=None): name : a string or None An optional name to attach to this activation function. - Returns -------- A `Tensor` with the same type as `x`. """ return tf.clip_by_value(x, clip_value_min=v_min, clip_value_max=v_max, name=name) -def leaky_relu(x=None, alpha=0.1, name="LeakyReLU"): +def leaky_relu(x=None, alpha=0.1, name="lrelu"): """The LeakyReLU, Shortcut is ``lrelu``. Modified version of ReLU, introducing a nonzero gradient for negative @@ -67,16 +63,33 @@ def leaky_relu(x=None, alpha=0.1, name="LeakyReLU"): ------------ - `Rectifier Nonlinearities Improve Neural Network Acoustic Models, Maas et al. (2013) `_ """ - with tf.name_scope(name) as scope: + # with tf.name_scope(name) as scope: # x = tf.nn.relu(x) # m_x = tf.nn.relu(-x) # x -= alpha * m_x - x = tf.maximum(x, alpha * x) + x = tf.maximum(x, alpha * x, name=name) return x #Shortcut lrelu = leaky_relu + +def swish(x, name='swish'): + """The Swish function, see `Swish: a Self-Gated Activation Function `_. + + Parameters + ---------- + x : a tensor input + input(s) + + Returns + -------- + A `Tensor` with the same type as `x`. + """ + with tf.name_scope(name) as scope: + x = tf.nn.sigmoid(x) * x + return x + def pixel_wise_softmax(output, name='pixel_wise_softmax'): """Return the softmax outputs of images, every pixels have multiple label, the sum of a pixel is 1. Usually be used for image segmentation. diff --git a/tensorlayer/cost.py b/tensorlayer/cost.py index 65554b13..941b5c5b 100644 --- a/tensorlayer/cost.py +++ b/tensorlayer/cost.py @@ -1,8 +1,7 @@ #! /usr/bin/python -# -*- coding: utf8 -*- - - +# -*- coding: utf-8 -*- +import logging import tensorflow as tf import numbers from tensorflow.python.framework import ops @@ -32,19 +31,19 @@ def cross_entropy(output, target, name=None): - About cross-entropy: `wiki `_.\n - The code is borrowed from: `here `_. """ - try: # old - return tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(logits=output, targets=target)) - except: # TF 1.0 - assert name is not None, "Please give a unique name to tl.cost.cross_entropy for TF1.0+" - return tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(labels=target, logits=output, name=name)) + # try: # old + # return tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(logits=output, targets=target)) + # except: # TF 1.0 + assert name is not None, "Please give a unique name to tl.cost.cross_entropy for TF1.0+" + return tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(labels=target, logits=output, name=name)) def sigmoid_cross_entropy(output, target, name=None): """It is a sigmoid cross-entropy operation, see ``tf.nn.sigmoid_cross_entropy_with_logits``. """ - try: # TF 1.0 - return tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(labels=target, logits=output, name=name)) - except: - return tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=output, targets=target)) + # try: # TF 1.0 + return tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(labels=target, logits=output, name=name)) + # except: + # return tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=output, targets=target)) def binary_cross_entropy(output, target, epsilon=1e-8, name='bce_loss'): @@ -76,55 +75,94 @@ def binary_cross_entropy(output, target, epsilon=1e-8, name='bce_loss'): (1. - target) * tf.log(1. - output + epsilon)), axis=1)) -def mean_squared_error(output, target, is_mean=False): - """Return the TensorFlow expression of mean-squre-error of two distributions. +def mean_squared_error(output, target, is_mean=False, name="mean_squared_error"): + """ Return the TensorFlow expression of mean-square-error (L2) of two batch of data. Parameters ---------- - output : 2D or 4D tensor. - target : 2D or 4D tensor. + output : 2D, 3D or 4D tensor i.e. [batch_size, n_feature], [batch_size, w, h] or [batch_size, w, h, c]. + target : 2D, 3D or 4D tensor. is_mean : boolean, if True, use ``tf.reduce_mean`` to compute the loss of one data, otherwise, use ``tf.reduce_sum`` (default). References ------------ - `Wiki Mean Squared Error `_ """ - with tf.name_scope("mean_squared_error_loss"): + with tf.name_scope(name): if output.get_shape().ndims == 2: # [batch_size, n_feature] if is_mean: mse = tf.reduce_mean(tf.reduce_mean(tf.squared_difference(output, target), 1)) else: mse = tf.reduce_mean(tf.reduce_sum(tf.squared_difference(output, target), 1)) + elif output.get_shape().ndims == 3: # [batch_size, w, h] + if is_mean: + mse = tf.reduce_mean(tf.reduce_mean(tf.squared_difference(output, target), [1, 2])) + else: + mse = tf.reduce_mean(tf.reduce_sum(tf.squared_difference(output, target), [1, 2])) elif output.get_shape().ndims == 4: # [batch_size, w, h, c] if is_mean: mse = tf.reduce_mean(tf.reduce_mean(tf.squared_difference(output, target), [1, 2, 3])) else: mse = tf.reduce_mean(tf.reduce_sum(tf.squared_difference(output, target), [1, 2, 3])) + else: + raise Exception("Unknow dimension") return mse def normalized_mean_square_error(output, target): - """Return the TensorFlow expression of normalized mean-squre-error of two distributions. + """Return the TensorFlow expression of normalized mean-square-error of two distributions. Parameters ---------- - output : 2D or 4D tensor. - target : 2D or 4D tensor. + output : 2D, 3D or 4D tensor i.e. [batch_size, n_feature], [batch_size, w, h] or [batch_size, w, h, c]. + target : 2D, 3D or 4D tensor. """ with tf.name_scope("mean_squared_error_loss"): if output.get_shape().ndims == 2: # [batch_size, n_feature] nmse_a = tf.sqrt(tf.reduce_sum(tf.squared_difference(output, target), axis=1)) nmse_b = tf.sqrt(tf.reduce_sum(tf.square(target), axis=1)) + elif output.get_shape().ndims == 3: # [batch_size, w, h] + nmse_a = tf.sqrt(tf.reduce_sum(tf.squared_difference(output, target), axis=[1,2])) + nmse_b = tf.sqrt(tf.reduce_sum(tf.square(target), axis=[1,2])) elif output.get_shape().ndims == 4: # [batch_size, w, h, c] nmse_a = tf.sqrt(tf.reduce_sum(tf.squared_difference(output, target), axis=[1,2,3])) nmse_b = tf.sqrt(tf.reduce_sum(tf.square(target), axis=[1,2,3])) nmse = tf.reduce_mean(nmse_a / nmse_b) return nmse +def absolute_difference_error(output, target, is_mean=False): + """ Return the TensorFlow expression of absolute difference error (L1) of two batch of data. -def dice_coe(output, target, epsilon=1e-10): - """Sørensen–Dice coefficient for comparing the similarity of two distributions, - usually be used for binary image segmentation i.e. labels are binary. - The coefficient = [0, 1], 1 if totally match. + Parameters + ---------- + output : 2D, 3D or 4D tensor i.e. [batch_size, n_feature], [batch_size, w, h] or [batch_size, w, h, c]. + target : 2D, 3D or 4D tensor. + is_mean : boolean, if True, use ``tf.reduce_mean`` to compute the loss of one data, otherwise, use ``tf.reduce_sum`` (default). + """ + with tf.name_scope("mean_squared_error_loss"): + if output.get_shape().ndims == 2: # [batch_size, n_feature] + if is_mean: + loss = tf.reduce_mean(tf.reduce_mean(tf.abs(output - target), 1)) + else: + loss = tf.reduce_mean(tf.reduce_sum(tf.abs(output - target), 1)) + elif output.get_shape().ndims == 3: # [batch_size, w, h] + if is_mean: + loss = tf.reduce_mean(tf.reduce_mean(tf.abs(output - target), [1, 2])) + else: + loss = tf.reduce_mean(tf.reduce_sum(tf.abs(output - target), [1, 2])) + elif output.get_shape().ndims == 4: # [batch_size, w, h, c] + if is_mean: + loss = tf.reduce_mean(tf.reduce_mean(tf.abs(output - target), [1, 2, 3])) + else: + loss = tf.reduce_mean(tf.reduce_sum(tf.abs(output - target), [1, 2, 3])) + else: + raise Exception("Unknow dimension") + return loss + + +def dice_coe(output, target, loss_type='jaccard', axis=[1,2,3], smooth=1e-5): + """Soft dice (Sørensen or Jaccard) coefficient for comparing the similarity + of two batch of data, usually be used for binary image segmentation + i.e. labels are binary. The coefficient between 0 to 1, 1 means totally match. Parameters ----------- @@ -132,35 +170,50 @@ def dice_coe(output, target, epsilon=1e-10): A distribution with shape: [batch_size, ....], (any dimensions). target : tensor A distribution with shape: [batch_size, ....], (any dimensions). - epsilon : float - An optional name to attach to this layer. + loss_type : string + ``jaccard`` or ``sorensen``, default is ``jaccard``. + axis : list of integer + All dimensions are reduced, default ``[1,2,3]``. + smooth : float + This small value will be added to the numerator and denominator. + If both output and target are empty, it makes sure dice is 1. + If either output or target are empty (all pixels are background), dice = ```smooth/(small_value + smooth)``, + then if smooth is very small, dice close to 0 (even the image values lower than the threshold), + so in this case, higher smooth can have a higher dice. Examples --------- >>> outputs = tl.act.pixel_wise_softmax(network.outputs) - >>> dice_loss = 1 - tl.cost.dice_coe(outputs, y_, epsilon=1e-5) + >>> dice_loss = 1 - tl.cost.dice_coe(outputs, y_) References ----------- - - `wiki-dice `_ + - `Wiki-Dice `_ """ - # inse = tf.reduce_sum( tf.mul(output, target) ) - # l = tf.reduce_sum( tf.mul(output, output) ) - # r = tf.reduce_sum( tf.mul(target, target) ) - inse = tf.reduce_sum( output * target ) - l = tf.reduce_sum( output * output ) - r = tf.reduce_sum( target * target ) - dice = 2 * (inse) / (l + r) - if epsilon == 0: - return dice + inse = tf.reduce_sum(output * target, axis=axis) + if loss_type == 'jaccard': + l = tf.reduce_sum(output * output, axis=axis) + r = tf.reduce_sum(target * target, axis=axis) + elif loss_type == 'sorensen': + l = tf.reduce_sum(output, axis=axis) + r = tf.reduce_sum(target, axis=axis) else: - return tf.clip_by_value(dice, 0, 1.0-epsilon) - - -def dice_hard_coe(output, target, epsilon=1e-10): - """Non-differentiable Sørensen–Dice coefficient for comparing the similarity of two distributions, - usually be used for binary image segmentation i.e. labels are binary. - The coefficient = [0, 1], 1 if totally match. + raise Exception("Unknow loss_type") + ## old axis=[0,1,2,3] + # dice = 2 * (inse) / (l + r) + # epsilon = 1e-5 + # dice = tf.clip_by_value(dice, 0, 1.0-epsilon) # if all empty, dice = 1 + ## new haodong + dice = (2. * inse + smooth) / (l + r + smooth) + ## + dice = tf.reduce_mean(dice) + return dice + + +def dice_hard_coe(output, target, threshold=0.5, axis=[1,2,3], smooth=1e-5): + """Non-differentiable Sørensen–Dice coefficient for comparing the similarity + of two batch of data, usually be used for binary image segmentation i.e. labels are binary. + The coefficient between 0 to 1, 1 if totally match. Parameters ----------- @@ -168,32 +221,37 @@ def dice_hard_coe(output, target, epsilon=1e-10): A distribution with shape: [batch_size, ....], (any dimensions). target : tensor A distribution with shape: [batch_size, ....], (any dimensions). - epsilon : float - An optional name to attach to this layer. - - Examples - --------- - >>> outputs = pixel_wise_softmax(network.outputs) - >>> dice_loss = 1 - dice_coe(outputs, y_, epsilon=1e-5) + threshold : float + The threshold value to be true. + axis : list of integer + All dimensions are reduced, default ``[1,2,3]``. + smooth : float + This small value will be added to the numerator and denominator, see ``dice_coe``. References ----------- - - `wiki-dice `_ + - `Wiki-Dice `_ """ - output = tf.cast(output > 0.5, dtype=tf.float32) - target = tf.cast(target > 0.5, dtype=tf.float32) - inse = tf.reduce_sum( output * target ) - l = tf.reduce_sum( output * output ) - r = tf.reduce_sum( target * target ) - dice = 2 * (inse) / (l + r) - if epsilon == 0: - return dice - else: - return tf.clip_by_value(dice, 0, 1.0-epsilon) - -def iou_coe(output, target, threshold=0.5, epsilon=1e-10): - """Non-differentiable Intersection over Union, usually be used for evaluating binary image segmentation. - The coefficient = [0, 1], 1 means totally match. + output = tf.cast(output > threshold, dtype=tf.float32) + target = tf.cast(target > threshold, dtype=tf.float32) + inse = tf.reduce_sum(tf.multiply(output, target), axis=axis) + l = tf.reduce_sum(output, axis=axis) + r = tf.reduce_sum(target, axis=axis) + ## old axis=[0,1,2,3] + # hard_dice = 2 * (inse) / (l + r) + # epsilon = 1e-5 + # hard_dice = tf.clip_by_value(hard_dice, 0, 1.0-epsilon) + ## new haodong + hard_dice = (2. * inse + smooth) / (l + r + smooth) + ## + hard_dice = tf.reduce_mean(hard_dice) + return hard_dice + + +def iou_coe(output, target, threshold=0.5, axis=[1,2,3], smooth=1e-5): + """Non-differentiable Intersection over Union (IoU) for comparing the + similarity of two batch of data, usually be used for evaluating binary image segmentation. + The coefficient between 0 to 1, 1 means totally match. Parameters ----------- @@ -203,23 +261,59 @@ def iou_coe(output, target, threshold=0.5, epsilon=1e-10): A distribution with shape: [batch_size, ....], (any dimensions). threshold : float The threshold value to be true. - epsilon : float - A small value to avoid zero denominator when both output and target output nothing. - - Examples - --------- - >>> outputs = tl.act.pixel_wise_softmax(network.outputs) - >>> iou = tl.cost.iou_coe(outputs[:,:,:,0], y_[:,:,:,0]) + axis : list of integer + All dimensions are reduced, default ``[1,2,3]``. + smooth : float + This small value will be added to the numerator and denominator, see ``dice_coe``. Notes ------ - - IOU cannot be used as training loss, people usually use dice coefficient for training, and IOU for evaluating. + - IoU cannot be used as training loss, people usually use dice coefficient for training, IoU and hard-dice for evaluating. """ pre = tf.cast(output > threshold, dtype=tf.float32) truth = tf.cast(target > threshold, dtype=tf.float32) - intersection = tf.reduce_sum(pre * truth) - union = tf.reduce_sum(tf.cast((pre + truth) > threshold, dtype=tf.float32)) - return tf.reduce_sum(intersection) / (tf.reduce_sum(union) + epsilon) + inse = tf.reduce_sum(tf.multiply(pre, truth), axis=axis) # AND + union = tf.reduce_sum(tf.cast(tf.add(pre, truth)>= 1, dtype=tf.float32), axis=axis) # OR + ## old axis=[0,1,2,3] + # epsilon = 1e-5 + # batch_iou = inse / (union + epsilon) + ## new haodong + batch_iou = (inse + smooth) / (union + smooth) + iou = tf.reduce_mean(batch_iou) + return iou#, pre, truth, inse, union + +# ## test soft/hard dice and iou +# import numpy as np +# y = np.zeros((1,10,10,1)) +# # y[0,0:5,0:5]=1.0 +# o = np.zeros((1,10,10,1)) +# # o[:,:,:,:] = 0 # what we want: dice=0 iou=0 OK +# # o[0,0:2,0:2]=0.3 # what we want: dice larger iou=0 OK +# # o[0,0:2,0:2]=0.6 # what we want: dice larger iou small OK +# # o[0,0:3,0:3]=0.6 # what we want: dice larger iou larger OK +# # o[0,0:3,0:3]=1 # what we want: dice larger iou same OK +# # o[0,0:5,0:5]=1 # what we want: dice=1 iou=1 OK +# # o[0,0:5,0:5]=0.3 # what we want: dice smaller iou=0 OK +# # o[0,0:5,0:5]=1e-2 # what we want: dice≈0 iou=0 OK +# # o[0,8:10,8:10]=1.0 # what we want: dice=0 iou=0 OK +# # o[0,8:10,8:10]=1e-10 # what we want: dice=0 iou=0 OK +# # y[:,:,:,:] = o[:,:,:,:] = 0 # what we want: dice=1 iou=1 OK +# ## why in u-net, dice=1 hard-dice=1 iou=1 exist?? print bug? +# +# d = dice_coe(o, y, 'jaccard', smooth=1.) +# hd = dice_hard_coe(o, y, smooth=1e-5) +# i = iou_coe(o, y, smooth=1e-5) +# sess = tf.Session(config=tf.ConfigProto(allow_soft_placement=True)) +# # sess.run(tf.local_variables_initializer()) +# print(sess.run([d,hd,i])) +# # p, t, i, u = sess.run([pre, truth, inse, union]) +# # import pprint +# # pprint.pprint(((y>0.5)*(o>0.5)).astype(int).tolist()) +# # pprint.pprint(p.tolist()) +# # pprint.pprint(t.tolist()) +# # pprint.pprint(i) +# # pprint.pprint(u) +# exit() def cross_entropy_seq(logits, target_seqs, batch_size=None):#, batch_size=1, num_steps=None): @@ -242,10 +336,10 @@ def cross_entropy_seq(logits, target_seqs, batch_size=None):#, batch_size=1, num >>> targets = tf.placeholder(tf.int32, [batch_size, num_steps]) >>> cost = tl.cost.cross_entropy_seq(network.outputs, targets) """ - try: # TF 1.0 - sequence_loss_by_example_fn = tf.contrib.legacy_seq2seq.sequence_loss_by_example - except: - sequence_loss_by_example_fn = tf.nn.seq2seq.sequence_loss_by_example + # try: # TF 1.0 + sequence_loss_by_example_fn = tf.contrib.legacy_seq2seq.sequence_loss_by_example + # except: + # sequence_loss_by_example_fn = tf.nn.seq2seq.sequence_loss_by_example loss = sequence_loss_by_example_fn( [logits], @@ -283,14 +377,14 @@ def cross_entropy_seq_with_mask(logits, target_seqs, input_mask, return_details= losses = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=logits, labels=targets, name=name) * weights #losses = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(logits=logits, labels=targets, name=name)) # for TF1.0 and others - try: ## TF1.0 - loss = tf.divide(tf.reduce_sum(losses), # loss from mask. reduce_sum before element-wise mul with mask !! - tf.reduce_sum(weights), - name="seq_loss_with_mask") - except: ## TF0.12 - loss = tf.div(tf.reduce_sum(losses), # loss from mask. reduce_sum before element-wise mul with mask !! - tf.reduce_sum(weights), - name="seq_loss_with_mask") + # try: ## TF1.0 + loss = tf.divide(tf.reduce_sum(losses), # loss from mask. reduce_sum before element-wise mul with mask !! + tf.reduce_sum(weights), + name="seq_loss_with_mask") + # except: ## TF0.12 + # loss = tf.div(tf.reduce_sum(losses), # loss from mask. reduce_sum before element-wise mul with mask !! + # tf.reduce_sum(weights), + # name="seq_loss_with_mask") if return_details: return loss, losses, weights, targets else: @@ -308,10 +402,10 @@ def cosine_similarity(v1, v2): ----------- a tensor of [batch_size, ] """ - try: ## TF1.0 - cost = tf.reduce_sum(tf.multiply(v1, v2), 1) / (tf.sqrt(tf.reduce_sum(tf.multiply(v1, v1), 1)) * tf.sqrt(tf.reduce_sum(tf.multiply(v2, v2), 1))) - except: ## TF0.12 - cost = tf.reduce_sum(tf.mul(v1, v2), reduction_indices=1) / (tf.sqrt(tf.reduce_sum(tf.mul(v1, v1), reduction_indices=1)) * tf.sqrt(tf.reduce_sum(tf.mul(v2, v2), reduction_indices=1))) + # try: ## TF1.0 + cost = tf.reduce_sum(tf.multiply(v1, v2), 1) / (tf.sqrt(tf.reduce_sum(tf.multiply(v1, v1), 1)) * tf.sqrt(tf.reduce_sum(tf.multiply(v2, v2), 1))) + # except: ## TF0.12 + # cost = tf.reduce_sum(tf.mul(v1, v2), reduction_indices=1) / (tf.sqrt(tf.reduce_sum(tf.mul(v1, v1), reduction_indices=1)) * tf.sqrt(tf.reduce_sum(tf.mul(v2, v2), reduction_indices=1))) return cost @@ -359,14 +453,14 @@ def li(weights, name=None): my_scale = ops.convert_to_tensor(scale, dtype=weights.dtype.base_dtype, name='scale') - if tf.__version__ <= '0.12': - standard_ops_fn = standard_ops.mul - else: - standard_ops_fn = standard_ops.multiply - return standard_ops_fn( - my_scale, - standard_ops.reduce_sum(standard_ops.sqrt(standard_ops.reduce_sum(tf.square(weights), 1))), - name=scope) + # if tf.__version__ <= '0.12': + # standard_ops_fn = standard_ops.mul + # else: + standard_ops_fn = standard_ops.multiply + return standard_ops_fn( + my_scale, + standard_ops.reduce_sum(standard_ops.sqrt(standard_ops.reduce_sum(tf.square(weights), 1))), + name=scope) return li @@ -414,10 +508,10 @@ def lo(weights, name='lo_regularizer'): my_scale = ops.convert_to_tensor(scale, dtype=weights.dtype.base_dtype, name='scale') - if tf.__version__ <= '0.12': - standard_ops_fn = standard_ops.mul - else: - standard_ops_fn = standard_ops.multiply + # if tf.__version__ <= '0.12': + # standard_ops_fn = standard_ops.mul + # else: + standard_ops_fn = standard_ops.multiply return standard_ops_fn( my_scale, standard_ops.reduce_sum(standard_ops.sqrt(standard_ops.reduce_sum(tf.square(weights), 0))), @@ -467,10 +561,10 @@ def mn(weights, name='max_regularizer'): my_scale = ops.convert_to_tensor(scale, dtype=weights.dtype.base_dtype, name='scale') - if tf.__version__ <= '0.12': - standard_ops_fn = standard_ops.mul - else: - standard_ops_fn = standard_ops.multiply + # if tf.__version__ <= '0.12': + # standard_ops_fn = standard_ops.mul + # else: + standard_ops_fn = standard_ops.multiply return standard_ops_fn(my_scale, standard_ops.reduce_max(standard_ops.abs(weights)), name=scope) return mn diff --git a/tensorlayer/db.py b/tensorlayer/db.py index af9f5ba7..3858224b 100644 --- a/tensorlayer/db.py +++ b/tensorlayer/db.py @@ -1,5 +1,5 @@ #! /usr/bin/python -# -*- coding: utf8 -*- +# -*- coding: utf-8 -*- """ Experimental Database Management System. diff --git a/tensorlayer/distributed.py b/tensorlayer/distributed.py new file mode 100644 index 00000000..6e9c223a --- /dev/null +++ b/tensorlayer/distributed.py @@ -0,0 +1,308 @@ +#! /usr/bin/python +# -*- coding: utf-8 -*- +import tensorflow as tf +from tensorflow.python.training import session_run_hook +import os +import sys +import json +import time + + +class TaskSpecDef(object): + """Specification for the distributed task with the job name, index of the task, + the parameter servers and the worker servers. If you want to use the last worker + for continuous evaluation you can call the method `user_last_worker_as_evaluator` + which returns a new :class:`TaskSpecDef` object without the last worker in the + cluster specification. + + Parameters + ---------- + type : A string with the job name, it will be `master`, `worker` or `ps`. + index : The zero-based index of the task. Distributed training jobs will have a single + master task, one or more parameter servers, and one or more workers. + trial : The identifier of the trial being run. + ps_hosts : A string with a coma separate list of hosts for the parameter servers + or a list of hosts. + worker_hosts : A string with a coma separate list of hosts for the worker servers + or a list of hosts. + master : A string with the master hosts + + Note + ---------- + master might not be included in TF_CONFIG and can be None. The shard_index is adjusted + in any case to assign 0 to master and >= 1 to workers. + This implementation doesn't support sparse arrays in the `TF_CONFIG` variable as the + official TensorFlow documentation shows, as it is not a supported by the json + definition. + + References + ---------- + - `ML-engine trainer considerations `_ + """ + + def __init__(self, type='master', index=0, trial=None, ps_hosts=None, worker_hosts=None, + master=None): + self.type = type + self._index = int(index) + self._cluster_spec = None + self.num_workers = 1 + self.num_ps = 0 + self.shard_index = int(index) + self._master = True + self.trial = trial + self.ps_hosts = ps_hosts + self.worker_hosts = worker_hosts + self.master = master + + if ps_hosts and worker_hosts: + ps = ps_hosts if isinstance(ps_hosts, list) else ps_hosts.split(',') + self.num_ps = len(ps) + worker = worker_hosts if isinstance(worker_hosts, list) else worker_hosts.split(',') + if master is not None and len(master) > 0: + self._cluster_spec = tf.train.ClusterSpec({'ps' : ps, + 'worker': worker, + 'master': master}) + # master is a worker too + self.num_workers = len(worker) + 1 + if self.type == 'worker': + self.shard_index = self._index + 1 + self._master = self.type == 'master' + else: + self._cluster_spec = tf.train.ClusterSpec({'ps' : ps, + 'worker': worker}) + if self.type == 'worker': + self.shard_index = self._index + self._master = self.type == 'worker' and self._index == 0 + + # create server and join if it is a parameter server + self._server = tf.train.Server(self._cluster_spec, + job_name=self.type, + task_index=self._index) + if self.is_ps(): + self._server.join() + else: + self._server = None + + def is_ps(self): + """Returns true if this server is a parameter server""" + return self.type == 'ps' + + def is_worker(self): + """Returns true if this server is a worker server""" + return self.type == 'worker' + + def is_master(self): + """Returns true if this server is the master server""" + return self._master + + def is_evaluator(self): + """Returns true if this server is the evaluator server""" + return self.type == 'worker' and len(self.worker_hosts) == self._index + + def device_fn(self): + """Returns the function with the specification to create the graph in this server""" + current_device = '/job:{}/task:{}'.format(self.type, self._index) + ps_devices = '/job:ps' + return tf.train.replica_device_setter(ps_device=ps_devices, + worker_device=current_device, + cluster=self._cluster_spec) + + def target(self): + if self._server is not None: + return self._server.target + else: + return None + + def user_last_worker_as_evaluator(self): + """ Returns a new :class:`TaskSpecDef` where the last worker has been removed from + the list of worker_hosts, so it is not used for training anymore. You can call + is_evaluator to know whether this server is the evaluator one or not. + In case there is only one server for training this method raises an exception, as + you cannot use any server for evaluation. + """ + if self.worker_hosts is None \ + or len(self.worker_hosts) == 0 \ + or (self.master is None and len(self.worker_hosts) == 1): + raise Exception('You need more than one worker instance to use one as evaluator') + return TaskSpecDef(type=self.type, + index=self._index, + trial=self.trial, + ps_hosts=self.ps_hosts, + worker_hosts=self.worker_hosts[:-1], + master=self.master) + + +def TaskSpec(): + """Returns the a :class:`TaskSpecDef` based on the environment variables for distributed + training. + + References + ---------- + - `ML-engine trainer considerations `_ + - `TensorPort Distributed Computing `_ + """ + + # TF_CONFIG is used in ML-engine + if 'TF_CONFIG' in os.environ: + env = json.loads(os.environ.get('TF_CONFIG', '{}')) + task_data = env.get('task', None) or {'type': 'master', 'index': 0} + cluster_data = env.get('cluster', None) or {'ps': None, 'worker': None, 'master': None} + return TaskSpecDef(type=task_data['type'], + index=task_data['index'], + trial=task_data['trial'] if 'trial' in task_data else None, + ps_hosts=cluster_data['ps'], + worker_hosts=cluster_data['worker'], + master=cluster_data['master'] if 'master' in cluster_data else None) + + # JOB_NAME, TASK_INDEX, PS_HOSTS, WORKER_HOSTS and MASTER_HOST are used in TensorPort + if 'JOB_NAME' in os.environ: + return TaskSpecDef(type=os.environ['JOB_NAME'], + index=os.environ['TASK_INDEX'], + ps_hosts=os.environ.get('PS_HOSTS', None), + worker_hosts=os.environ.get('WORKER_HOSTS', None), + master=os.environ.get('MASTER_HOST', None)) + return None + + +def DistributedSession(task_spec=None, + checkpoint_dir=None, + scaffold=None, + hooks=None, + chief_only_hooks=None, + save_checkpoint_secs=600, + save_summaries_steps=object(), + save_summaries_secs=object(), + config=None, + stop_grace_period_secs=120, + log_step_count_steps=100): + """Creates a distributed session. It calls `MonitoredTrainingSession` to create a + :class:`MonitoredSession` for distributed training. + + Examples + -------- + + A simple example for distributed training where all the workers use the same dataset: + + >>> task_spec = TaskSpec() + >>> with tf.device(task_spec.device_fn()): + >>> tensors = create_graph() + >>> with tl.DistributedSession(task_spec=task_spec, + ... checkpoint_dir='/tmp/ckpt') as session: + >>> while not session.should_stop(): + >>> session.run(tensors) + + An example where the dataset is shared among the workers + (see https://www.tensorflow.org/programmers_guide/datasets): + + >>> task_spec = TaskSpec() + >>> # dataset is a :class:`tf.data.Dataset` with the raw data + >>> dataset = create_dataset() + >>> if task_spec is not None: + >>> dataset = dataset.shard(task_spec.num_workers, task_spec.shard_index) + >>> # shuffle or apply a map function to the new sharded dataset, for example: + >>> dataset = dataset.shuffle(buffer_size=10000) + >>> dataset = dataset.batch(batch_size) + >>> dataset = dataset.repeat(num_epochs) + >>> # create the iterator for the dataset and the input tensor + >>> iterator = dataset.make_one_shot_iterator() + >>> next_element = iterator.get_next() + >>> with tf.device(task_spec.device_fn()): + >>> # next_element is the input for the graph + >>> tensors = create_graph(next_element) + >>> with tl.DistributedSession(task_spec=task_spec, + ... checkpoint_dir='/tmp/ckpt') as session: + >>> while not session.should_stop(): + >>> session.run(tensors) + + + Parameters + ---------- + task_spec : TaskSpecDef. The task spec definition from TaskSpec() + checkpoint_dir : A string. Optional path to a directory where to restore + variables. + scaffold : A `Scaffold` used for gathering or building supportive ops. If + not specified, a default one is created. It's used to finalize the graph. + hooks : Optional list of `SessionRunHook` objects. + chief_only_hooks : list of `SessionRunHook` objects. Activate these hooks if + `is_chief==True`, ignore otherwise. + save_checkpoint_secs : The frequency, in seconds, that a checkpoint is saved + using a default checkpoint saver. If `save_checkpoint_secs` is set to + `None`, then the default checkpoint saver isn't used. + save_summaries_steps : The frequency, in number of global steps, that the + summaries are written to disk using a default summary saver. If both + `save_summaries_steps` and `save_summaries_secs` are set to `None`, then + the default summary saver isn't used. Default 100. + save_summaries_secs : The frequency, in secs, that the summaries are written + to disk using a default summary saver. If both `save_summaries_steps` and + `save_summaries_secs` are set to `None`, then the default summary saver + isn't used. Default not enabled. + config : an instance of `tf.ConfigProto` proto used to configure the session. + It's the `config` argument of constructor of `tf.Session`. + stop_grace_period_secs : Number of seconds given to threads to stop after + `close()` has been called. + log_step_count_steps : The frequency, in number of global steps, that the + global step/sec is logged. + + References + ---------- + - `MonitoredTrainingSession `_ + """ + target = task_spec.target() if task_spec is not None else None + is_chief = task_spec.is_master() if task_spec is not None else True + return tf.train.MonitoredTrainingSession(master=target, + is_chief=is_chief, + checkpoint_dir=checkpoint_dir, + scaffold=scaffold, + save_checkpoint_secs=save_checkpoint_secs, + save_summaries_steps=save_summaries_steps, + save_summaries_secs=save_summaries_secs, + log_step_count_steps=log_step_count_steps, + stop_grace_period_secs=stop_grace_period_secs, + config=config, + hooks=hooks, + chief_only_hooks=chief_only_hooks) + + + +class StopAtTimeHook(session_run_hook.SessionRunHook): + """Hook that requests stop after a specified time. + + Parameters + ---------- + time_running: Maximum time running in seconds + """ + + def __init__(self, time_running): + self._time_running = time_running + + def begin(self): + self._end_time = time.time() + self._time_running + + def after_run(self, run_context, run_values): + if time.time() > self._end_time: + run_context.request_stop() + + +class LoadCheckpoint(session_run_hook.SessionRunHook): + """Hook that loads a checkpoint after the session is created. + + >>> from tensorflow.python.ops import variables as tf_variables + >>> from tensorflow.python.training.monitored_session import SingularMonitoredSession + >>> + >>> tensors = create_graph() + >>> saver = tf.train.Saver(var_list=tf_variables.trainable_variables()) + >>> checkpoint_hook = LoadCheckpoint(saver, my_checkpoint_file) + >>> with tf.SingularMonitoredSession(hooks=[checkpoint_hook]) as session: + >>> while not session.should_stop(): + >>> session.run(tensors) + """ + + def __init__(self, saver, checkpoint): + self._saver = saver + self._checkpoint = checkpoint + self._loaded = False + + def after_create_session(self, session, coord): + if not self._loaded: + self._loaded = True + self._saver.restore(self._checkpoint) diff --git a/tensorlayer/files.py b/tensorlayer/files.py index d97d4dbe..06446a1e 100644 --- a/tensorlayer/files.py +++ b/tensorlayer/files.py @@ -1,5 +1,5 @@ #! /usr/bin/python -# -*- coding: utf8 -*- +# -*- coding: utf-8 -*- import tensorflow as tf @@ -12,6 +12,7 @@ import zipfile from . import visualize from . import nlp +from . import utils import pickle from six.moves import urllib from six.moves import cPickle @@ -20,7 +21,7 @@ ## Load dataset functions -def load_mnist_dataset(shape=(-1,784), path="data/mnist/"): +def load_mnist_dataset(shape=(-1,784), path="data"): """Automatically download MNIST dataset and return the training, validation and test set with 50000, 10000 and 10000 digit images respectively. @@ -28,15 +29,16 @@ def load_mnist_dataset(shape=(-1,784), path="data/mnist/"): Parameters ---------- shape : tuple - The shape of digit images, defaults to (-1,784) + The shape of digit images, defaults is (-1,784) path : string - Path to download data to, defaults to data/mnist/ + The path that the data is downloaded to, defaults is ``data/mnist/``. Examples -------- >>> X_train, y_train, X_val, y_val, X_test, y_test = tl.files.load_mnist_dataset(shape=(-1,784)) >>> X_train, y_train, X_val, y_val, X_test, y_test = tl.files.load_mnist_dataset(shape=(-1, 28, 28, 1)) """ + path = os.path.join(path, 'mnist') # We first define functions for loading MNIST images and labels. # For convenience, they also download the requested files if needed. def load_mnist_images(path, filename): @@ -83,8 +85,7 @@ def load_mnist_labels(path, filename): y_test = np.asarray(y_test, dtype=np.int32) return X_train, y_train, X_val, y_val, X_test, y_test - -def load_cifar10_dataset(shape=(-1, 32, 32, 3), path='data/cifar10/', plotable=False, second=3): +def load_cifar10_dataset(shape=(-1, 32, 32, 3), path='data', plotable=False, second=3): """The CIFAR-10 dataset consists of 60000 32x32 colour images in 10 classes, with 6000 images per class. There are 50000 training images and 10000 test images. @@ -97,34 +98,17 @@ def load_cifar10_dataset(shape=(-1, 32, 32, 3), path='data/cifar10/', plotable=F Parameters ---------- shape : tupe - The shape of digit images: e.g. (-1, 3, 32, 32) , (-1, 32, 32, 3) , (-1, 32*32*3) + The shape of digit images: e.g. (-1, 3, 32, 32) and (-1, 32, 32, 3). plotable : True, False Whether to plot some image examples. second : int If ``plotable`` is True, ``second`` is the display time. path : string - Path to download data to, defaults to data/cifar10/ + The path that the data is downloaded to, defaults is ``data/cifar10/``. Examples -------- - >>> X_train, y_train, X_test, y_test = tl.files.load_cifar10_dataset(shape=(-1, 32, 32, 3), plotable=True) - - Notes - ------ - CIFAR-10 images can only be display without color change under uint8. - >>> X_train = np.asarray(X_train, dtype=np.uint8) - >>> plt.ion() - >>> fig = plt.figure(1232) - >>> count = 1 - >>> for row in range(10): - >>> for col in range(10): - >>> a = fig.add_subplot(10, 10, count) - >>> plt.imshow(X_train[count-1], interpolation='nearest') - >>> plt.gca().xaxis.set_major_locator(plt.NullLocator()) # 不显示刻度(tick) - >>> plt.gca().yaxis.set_major_locator(plt.NullLocator()) - >>> count = count + 1 - >>> plt.draw() - >>> plt.pause(3) + >>> X_train, y_train, X_test, y_test = tl.files.load_cifar10_dataset(shape=(-1, 32, 32, 3)) References ---------- @@ -132,7 +116,7 @@ def load_cifar10_dataset(shape=(-1, 32, 32, 3), path='data/cifar10/', plotable=F - `Data download link `_ - `Code references `_ """ - + path = os.path.join(path, 'cifar10') print("Load or Download cifar10 > {}".format(path)) #Helper function to unpickle the data @@ -218,40 +202,17 @@ def unpickle(file): return X_train, y_train, X_test, y_test - -def load_ptb_dataset(path='data/ptb/'): +def load_ptb_dataset(path='data'): """Penn TreeBank (PTB) dataset is used in many LANGUAGE MODELING papers, including "Empirical Evaluation and Combination of Advanced Language Modeling Techniques", "Recurrent Neural Network Regularization". - It consists of 929k training words, 73k validation words, and 82k test words. It has 10k words in its vocabulary. - In "Recurrent Neural Network Regularization", they trained regularized LSTMs - of two sizes; these are denoted the medium LSTM and large LSTM. Both LSTMs - have two layers and are unrolled for 35 steps. They initialize the hidden - states to zero. They then use the final hidden states of the current - minibatch as the initial hidden state of the subsequent minibatch - (successive minibatches sequentially traverse the training set). - The size of each minibatch is 20. - - The medium LSTM has 650 units per layer and its parameters are initialized - uniformly in [−0.05, 0.05]. They apply 50% dropout on the non-recurrent - connections. They train the LSTM for 39 epochs with a learning rate of 1, - and after 6 epochs they decrease it by a factor of 1.2 after each epoch. - They clip the norm of the gradients (normalized by minibatch size) at 5. - - The large LSTM has 1500 units per layer and its parameters are initialized - uniformly in [−0.04, 0.04]. We apply 65% dropout on the non-recurrent - connections. They train the model for 55 epochs with a learning rate of 1; - after 14 epochs they start to reduce the learning rate by a factor of 1.15 - after each epoch. They clip the norm of the gradients (normalized by - minibatch size) at 10. - Parameters ---------- path : : string - Path to download data to, defaults to data/ptb/ + The path that the data is downloaded to, defaults is ``data/ptb/``. Returns -------- @@ -261,14 +222,12 @@ def load_ptb_dataset(path='data/ptb/'): -------- >>> train_data, valid_data, test_data, vocab_size = tl.files.load_ptb_dataset() - Code References + References --------------- - ``tensorflow.models.rnn.ptb import reader`` - - Download Links - --------------- - `Manual download `_ """ + path = os.path.join(path, 'ptb') print("Load or Download Penn TreeBank (PTB) dataset > {}".format(path)) #Maybe dowload and uncompress tar, or load exsisting files @@ -295,8 +254,7 @@ def load_ptb_dataset(path='data/ptb/'): # exit() return train_data, valid_data, test_data, vocabulary - -def load_matt_mahoney_text8_dataset(path='data/mm_test8/'): +def load_matt_mahoney_text8_dataset(path='data'): """Download a text file from Matt Mahoney's website if not present, and make sure it's the right size. Extract the first file enclosed in a zip file as a list of words. @@ -305,7 +263,7 @@ def load_matt_mahoney_text8_dataset(path='data/mm_test8/'): Parameters ---------- path : : string - Path to download data to, defaults to data/mm_test8/ + The path that the data is downloaded to, defaults is ``data/mm_test8/``. Returns -------- @@ -318,7 +276,7 @@ def load_matt_mahoney_text8_dataset(path='data/mm_test8/'): >>> words = tl.files.load_matt_mahoney_text8_dataset() >>> print('Data size', len(words)) """ - + path = os.path.join(path, 'mm_test8') print("Load or Download matt_mahoney_text8 Dataset> {}".format(path)) filename = 'text8.zip' @@ -327,11 +285,11 @@ def load_matt_mahoney_text8_dataset(path='data/mm_test8/'): with zipfile.ZipFile(os.path.join(path, filename)) as f: word_list = f.read(f.namelist()[0]).split() - + for idx, word in enumerate(word_list): + word_list[idx] = word_list[idx].decode() return word_list - -def load_imdb_dataset(path='data/imdb/', nb_words=None, skip_top=0, +def load_imdb_dataset(path='data', nb_words=None, skip_top=0, maxlen=None, test_split=0.2, seed=113, start_char=1, oov_char=2, index_from=3): """Load IMDB dataset @@ -339,11 +297,11 @@ def load_imdb_dataset(path='data/imdb/', nb_words=None, skip_top=0, Parameters ---------- path : : string - Path to download data to, defaults to data/imdb/ + The path that the data is downloaded to, defaults is ``data/imdb/``. Examples -------- - >>> X_train, y_train, X_test, y_test = tl.files.load_imbd_dataset( + >>> X_train, y_train, X_test, y_test = tl.files.load_imdb_dataset( ... nb_words=20000, test_split=0.2) >>> print('X_train.shape', X_train.shape) ... (20000,) [[1, 62, 74, ... 1033, 507, 27],[1, 60, 33, ... 13, 1053, 7]..] @@ -354,6 +312,7 @@ def load_imdb_dataset(path='data/imdb/', nb_words=None, skip_top=0, ----------- - `Modified from keras. `_ """ + path = os.path.join(path, 'imdb') filename = "imdb.pkl" url = 'https://s3.amazonaws.com/text-datasets/' @@ -415,14 +374,14 @@ def load_imdb_dataset(path='data/imdb/', nb_words=None, skip_top=0, return X_train, y_train, X_test, y_test -def load_nietzsche_dataset(path='data/nietzsche/'): +def load_nietzsche_dataset(path='data'): """Load Nietzsche dataset. Returns a string. Parameters ---------- path : string - Path to download data to, defaults to data/nietzsche/ + The path that the data is downloaded to, defaults is ``data/nietzsche/``. Examples -------- @@ -432,6 +391,7 @@ def load_nietzsche_dataset(path='data/nietzsche/'): >>> words = words.split() """ print("Load or Download nietzsche dataset > {}".format(path)) + path = os.path.join(path, 'nietzsche') filename = "nietzsche.txt" url = 'https://s3.amazonaws.com/text-datasets/' @@ -441,7 +401,7 @@ def load_nietzsche_dataset(path='data/nietzsche/'): words = f.read() return words -def load_wmt_en_fr_dataset(path='data/wmt_en_fr/'): +def load_wmt_en_fr_dataset(path='data'): """It will download English-to-French translation data from the WMT'15 Website (10^9-French-English corpus), and the 2013 news test from the same site as development set. @@ -450,7 +410,7 @@ def load_wmt_en_fr_dataset(path='data/wmt_en_fr/'): Parameters ---------- path : string - Path to download data to, defaults to data/wmt_en_fr/ + The path that the data is downloaded to, defaults is ``data/wmt_en_fr/``. References ---------- @@ -460,6 +420,7 @@ def load_wmt_en_fr_dataset(path='data/wmt_en_fr/'): ----- Usually, it will take a long time to download this dataset. """ + path = os.path.join(path, 'wmt_en_fr') # URLs for WMT data. _WMT_ENFR_TRAIN_URL = "http://www.statmt.org/wmt10/" _WMT_ENFR_DEV_URL = "http://www.statmt.org/wmt15/" @@ -505,8 +466,554 @@ def get_wmt_enfr_dev_set(path): return train_path, dev_path +def load_flickr25k_dataset(tag='sky', path="data", n_threads=50, printable=False): + """Returns a list of images by a given tag from Flick25k dataset, + it will download Flickr25k from `the official website `_ + at the first time you use it. + + Parameters + ------------ + tag : string or None + If you want to get images with tag, use string like 'dog', 'red', see `Flickr Search `_. + If you want to get all images, set to ``None``. + path : string + The path that the data is downloaded to, defaults is ``data/flickr25k/``. + n_threads : int, number of thread to read image. + printable : bool, print infomation when reading images, default is ``False``. + + Examples + ----------- + - Get images with tag of sky + >>> images = tl.files.load_flickr25k_dataset(tag='sky') + + - Get all images + >>> images = tl.files.load_flickr25k_dataset(tag=None, n_threads=100, printable=True) + """ + path = os.path.join(path, 'flickr25k') + + filename = 'mirflickr25k.zip' + url = 'http://press.liacs.nl/mirflickr/mirflickr25k/' + ## download dataset + if folder_exists(path+"/mirflickr") is False: + print("[*] Flickr25k is nonexistent in {}".format(path)) + maybe_download_and_extract(filename, path, url, extract=True) + del_file(path+'/'+filename) + ## return images by the given tag. + # 1. image path list + folder_imgs = path+"/mirflickr" + path_imgs = load_file_list(path=folder_imgs, regx='\\.jpg', printable=False) + path_imgs.sort(key=natural_keys) + # print(path_imgs[0:10]) + # 2. tag path list + folder_tags = path+"/mirflickr/meta/tags" + path_tags = load_file_list(path=folder_tags, regx='\\.txt', printable=False) + path_tags.sort(key=natural_keys) + # print(path_tags[0:10]) + # 3. select images + if tag is None: + print("[Flickr25k] reading all images") + else: + print("[Flickr25k] reading images with tag: {}".format(tag)) + images_list = [] + for idx in range(0, len(path_tags)): + tags = read_file(folder_tags+'/'+path_tags[idx]).split('\n') + # print(idx+1, tags) + if tag is None or tag in tags: + images_list.append(path_imgs[idx]) + + images = visualize.read_images(images_list, folder_imgs, n_threads=n_threads, printable=printable) + return images + +def load_flickr1M_dataset(tag='sky', size=10, path="data", n_threads=50, printable=False): + """Returns a list of images by a given tag from Flickr1M dataset, + it will download Flickr1M from `the official website `_ + at the first time you use it. + + Parameters + ------------ + tag : string or None + If you want to get images with tag, use string like 'dog', 'red', see `Flickr Search `_. + If you want to get all images, set to ``None``. + size : int 1 to 10. + 1 means 100k images ... 5 means 500k images, 10 means all 1 million images. Default is 10. + path : string + The path that the data is downloaded to, defaults is ``data/flickr25k/``. + n_threads : int, number of thread to read image. + printable : bool, print infomation when reading images, default is ``False``. + + Examples + ---------- + - Use 200k images + >>> images = tl.files.load_flickr1M_dataset(tag='zebra', size=2) + + - Use 1 Million images + >>> images = tl.files.load_flickr1M_dataset(tag='zebra') + """ + path = os.path.join(path, 'flickr1M') + print("[Flickr1M] using {}% of images = {}".format(size*10, size*100000)) + images_zip = ['images0.zip', 'images1.zip', 'images2.zip', 'images3.zip', + 'images4.zip', 'images5.zip', 'images6.zip', 'images7.zip', + 'images8.zip', 'images9.zip'] + tag_zip = 'tags.zip' + url = 'http://press.liacs.nl/mirflickr/mirflickr1m/' + ## download dataset + for image_zip in images_zip[0:size]: + image_folder = image_zip.split(".")[0] + # print(path+"/"+image_folder) + if folder_exists(path+"/"+image_folder) is False: + # print(image_zip) + print("[Flickr1M] {} is missing in {}".format(image_folder, path)) + maybe_download_and_extract(image_zip, path, url, extract=True) + del_file(path+'/'+image_zip) + os.system("mv {} {}".format(path+'/images',path+'/'+image_folder)) + else: + print("[Flickr1M] {} exists in {}".format(image_folder, path)) + ## download tag + if folder_exists(path+"/tags") is False: + print("[Flickr1M] tag files is nonexistent in {}".format(path)) + maybe_download_and_extract(tag_zip, path, url, extract=True) + del_file(path+'/'+tag_zip) + else: + print("[Flickr1M] tags exists in {}".format(path)) + + ## 1. image path list + images_list = [] + images_folder_list = [] + for i in range(0, size): + images_folder_list += load_folder_list(path=path+'/images%d'%i) + images_folder_list.sort(key=lambda s : int(s.split('/')[-1])) # folder/images/ddd + # print(images_folder_list) + # exit() + for folder in images_folder_list[0:size*10]: + tmp = load_file_list(path=folder, regx='\\.jpg', printable=False) + tmp.sort(key=lambda s : int(s.split('.')[-2])) # ddd.jpg + # print(tmp[0::570]) + images_list.extend([folder+'/'+x for x in tmp]) + # print('IM', len(images_list), images_list[0::6000]) + ## 2. tag path list + tag_list = [] + tag_folder_list = load_folder_list(path+"/tags") + tag_folder_list.sort(key=lambda s : int(s.split('/')[-1])) # folder/images/ddd + + for folder in tag_folder_list[0:size*10]: + # print(folder) + tmp = load_file_list(path=folder, regx='\\.txt', printable=False) + tmp.sort(key=lambda s : int(s.split('.')[-2])) # ddd.txt + tmp = [folder+'/'+s for s in tmp] + tag_list += tmp + # print('T', len(tag_list), tag_list[0::6000]) + # exit() + ## 3. select images + print("[Flickr1M] searching tag: {}".format(tag)) + select_images_list = [] + for idx in range(0, len(tag_list)): + tags = read_file(tag_list[idx]).split('\n') + if tag in tags: + select_images_list.append(images_list[idx]) + # print(idx, tags, tag_list[idx], images_list[idx]) + print("[Flickr1M] reading images with tag: {}".format(tag)) + images = visualize.read_images(select_images_list, '', n_threads=n_threads, printable=printable) + return images + +def load_cyclegan_dataset(filename='summer2winter_yosemite', path='data'): + """Load image data from CycleGAN's database, see `this link `_. -## Load and save network + Parameters + ------------ + filename : string + The dataset you want, see `this link `_. + path : string + The path that the data is downloaded to, defaults is `data/cyclegan` + + Examples + --------- + >>> im_train_A, im_train_B, im_test_A, im_test_B = load_cyclegan_dataset(filename='summer2winter_yosemite') + """ + path = os.path.join(path, 'cyclegan') + url = 'https://people.eecs.berkeley.edu/~taesung_park/CycleGAN/datasets/' + + if folder_exists(os.path.join(path, filename)) is False: + print("[*] {} is nonexistent in {}".format(filename, path)) + maybe_download_and_extract(filename+'.zip', path, url, extract=True) + del_file(os.path.join(path, filename+'.zip')) + + def load_image_from_folder(path): + path_imgs = load_file_list(path=path, regx='\\.jpg', printable=False) + return visualize.read_images(path_imgs, path=path, n_threads=10, printable=False) + im_train_A = load_image_from_folder(os.path.join(path, filename, "trainA")) + im_train_B = load_image_from_folder(os.path.join(path, filename, "trainB")) + im_test_A = load_image_from_folder(os.path.join(path, filename, "testA")) + im_test_B = load_image_from_folder(os.path.join(path, filename, "testB")) + + def if_2d_to_3d(images): # [h, w] --> [h, w, 3] + for i in range(len(images)): + if len(images[i].shape) == 2: + images[i] = images[i][:, :, np.newaxis] + images[i] = np.tile(images[i], (1, 1, 3)) + return images + + im_train_A = if_2d_to_3d(im_train_A) + im_train_B = if_2d_to_3d(im_train_B) + im_test_A = if_2d_to_3d(im_test_A) + im_test_B = if_2d_to_3d(im_test_B) + + return im_train_A, im_train_B, im_test_A, im_test_B + +def download_file_from_google_drive(id, destination): + """ Download file from Google Drive, see ``load_celebA_dataset`` for example. + + Parameters + -------------- + id : driver ID + destination : string, save path. + """ + from tqdm import tqdm + import requests + def save_response_content(response, destination, chunk_size=32*1024): + total_size = int(response.headers.get('content-length', 0)) + with open(destination, "wb") as f: + for chunk in tqdm(response.iter_content(chunk_size), total=total_size, + unit='B', unit_scale=True, desc=destination): + if chunk: # filter out keep-alive new chunks + f.write(chunk) + def get_confirm_token(response): + for key, value in response.cookies.items(): + if key.startswith('download_warning'): + return value + return None + URL = "https://docs.google.com/uc?export=download" + session = requests.Session() + + response = session.get(URL, params={ 'id': id }, stream=True) + token = get_confirm_token(response) + + if token: + params = { 'id' : id, 'confirm' : token } + response = session.get(URL, params=params, stream=True) + save_response_content(response, destination) + +def load_celebA_dataset(dirpath='data'): + """ Automatically download celebA dataset, and return a list of image path. """ + import zipfile, os + data_dir = 'celebA' + filename, drive_id = "img_align_celeba.zip", "0B7EVK8r0v71pZjFTYXZWM3FlRnM" + save_path = os.path.join(dirpath, filename) + image_path = os.path.join(dirpath, data_dir) + if os.path.exists(image_path): + print('[*] {} already exists'.format(save_path)) + else: + exists_or_mkdir(dirpath) + download_file_from_google_drive(drive_id, save_path) + zip_dir = '' + with zipfile.ZipFile(save_path) as zf: + zip_dir = zf.namelist()[0] + zf.extractall(dirpath) + os.remove(save_path) + os.rename(os.path.join(dirpath, zip_dir), image_path) + + data_files = load_file_list(path=image_path, regx='\\.jpg', printable=False) + for i in range(len(data_files)): + data_files[i] = os.path.join(image_path, data_files[i]) + return data_files + +def load_voc_dataset(path='data', dataset='2012', contain_classes_in_person=False): + """ Pascal VOC 2007/2012 Dataset has 20 objects : aeroplane, bicycle, bird, boat, bottle, bus, car, cat, chair, cow, diningtable, dog, horse, motorbike, person, pottedplant, sheep, sofa, train, tvmonitor and additional 3 classes : head, hand, foot for person. + + Parameters + ----------- + path : string + The path that the data is downloaded to, defaults is ``data/VOC``. + dataset : string, 2012, 2007, 2007test or 2012test. + The VOC dataset version, we usually train model on 2007+2012 and test it on 2007test. + contain_classes_in_person : If True, dataset will contains labels of head, hand and foot. + + Returns + --------- + imgs_file_list : list of string. + Full paths of all images. + imgs_semseg_file_list : list of string. + Full paths of all maps for semantic segmentation. Note that not all images have this map! + imgs_insseg_file_list : list of string. + Full paths of all maps for instance segmentation. Note that not all images have this map! + imgs_ann_file_list : list of string. + Full paths of all annotations for bounding box and object class, all images have this annotations. + classes : list of string. + Classes in order. + classes_in_person : list of string. + Classes in person. + classes_dict : dictionary. + Class label to integer. + n_objs_list : list of integer + Number of objects in all images in ``imgs_file_list` in order. + objs_info_list : list of string. + Darknet format for the annotation of all images in ``imgs_file_list`` in order. ``[class_id x_centre y_centre width height]`` in ratio format. + objs_info_dicts : dictionary. + ``{imgs_file_list : dictionary for annotation}``, the annotation of all images in ``imgs_file_list``, + format from `TensorFlow/Models/object-detection `_. + + Examples + ---------- + >>> imgs_file_list, imgs_semseg_file_list, imgs_insseg_file_list, imgs_ann_file_list, + >>> classes, classes_in_person, classes_dict, + >>> n_objs_list, objs_info_list, objs_info_dicts = tl.files.load_voc_dataset(dataset="2012", contain_classes_in_person=False) + >>> idx = 26 + >>> print(classes) + ... ['aeroplane', 'bicycle', 'bird', 'boat', 'bottle', 'bus', 'car', 'cat', 'chair', 'cow', 'diningtable', 'dog', 'horse', 'motorbike', 'person', 'pottedplant', 'sheep', 'sofa', 'train', 'tvmonitor'] + >>> print(classes_dict) + ... {'sheep': 16, 'horse': 12, 'bicycle': 1, 'bottle': 4, 'cow': 9, 'sofa': 17, 'car': 6, 'dog': 11, 'cat': 7, 'person': 14, 'train': 18, 'diningtable': 10, 'aeroplane': 0, 'bus': 5, 'pottedplant': 15, 'tvmonitor': 19, 'chair': 8, 'bird': 2, 'boat': 3, 'motorbike': 13} + >>> print(imgs_file_list[idx]) + ... data/VOC/VOC2012/JPEGImages/2007_000423.jpg + >>> print(n_objs_list[idx]) + ... 2 + >>> print(imgs_ann_file_list[idx]) + ... data/VOC/VOC2012/Annotations/2007_000423.xml + >>> print(objs_info_list[idx]) + ... 14 0.173 0.461333333333 0.142 0.496 + ... 14 0.828 0.542666666667 0.188 0.594666666667 + >>> ann = tl.prepro.parse_darknet_ann_str_to_list(objs_info_list[idx]) + >>> print(ann) + ... [[14, 0.173, 0.461333333333, 0.142, 0.496], [14, 0.828, 0.542666666667, 0.188, 0.594666666667]] + >>> c, b = tl.prepro.parse_darknet_ann_list_to_cls_box(ann) + >>> print(c, b) + ... [14, 14] [[0.173, 0.461333333333, 0.142, 0.496], [0.828, 0.542666666667, 0.188, 0.594666666667]] + + References + ------------- + - `Pascal VOC2012 Website `_. + - `Pascal VOC2007 Website `_. + - `TensorFlow/Models/object-detection `_. + """ + path= os.path.join(path, 'VOC') + + def _recursive_parse_xml_to_dict(xml): + """Recursively parses XML contents to python dict. + We assume that `object` tags are the only ones that can appear + multiple times at the same level of a tree. + + Args: + xml: xml tree obtained by parsing XML file contents using lxml.etree + + Returns: + Python dictionary holding XML contents. + """ + if not xml: + # if xml is not None: + return {xml.tag: xml.text} + result = {} + for child in xml: + child_result = _recursive_parse_xml_to_dict(child) + if child.tag != 'object': + result[child.tag] = child_result[child.tag] + else: + if child.tag not in result: + result[child.tag] = [] + result[child.tag].append(child_result[child.tag]) + return {xml.tag: result} + + from lxml import etree # pip install lxml + import xml.etree.ElementTree as ET + + ## + if dataset == "2012": + url = "http://host.robots.ox.ac.uk/pascal/VOC/voc2012/" + tar_filename = "VOCtrainval_11-May-2012.tar" + extracted_filename = "VOC2012"#"VOCdevkit/VOC2012" + print(" [============= VOC 2012 =============]") + elif dataset == "2012test": + extracted_filename = "VOC2012test"#"VOCdevkit/VOC2012" + print(" [============= VOC 2012 Test Set =============]") + print(" \nAuthor: 2012test only have person annotation, so 2007test is highly recommended for testing !\n") + import time + time.sleep(3) + if os.path.isdir(os.path.join(path, extracted_filename)) is False: + print("For VOC 2012 Test data - online registration required") + print(" Please download VOC2012test.tar from: \n register: http://host.robots.ox.ac.uk:8080 \n voc2012 : http://host.robots.ox.ac.uk:8080/eval/challenges/voc2012/ \ndownload: http://host.robots.ox.ac.uk:8080/eval/downloads/VOC2012test.tar") + print(" unzip VOC2012test.tar,rename the folder to VOC2012test and put it into %s" % path) + exit() + # # http://host.robots.ox.ac.uk:8080/eval/downloads/VOC2012test.tar + # url = "http://host.robots.ox.ac.uk:8080/eval/downloads/" + # tar_filename = "VOC2012test.tar" + elif dataset == "2007": + url = "http://host.robots.ox.ac.uk/pascal/VOC/voc2007/" + tar_filename = "VOCtrainval_06-Nov-2007.tar" + extracted_filename = "VOC2007" + print(" [============= VOC 2007 =============]") + elif dataset == "2007test": + # http://host.robots.ox.ac.uk/pascal/VOC/voc2007/index.html#testdata + # http://host.robots.ox.ac.uk/pascal/VOC/voc2007/VOCtest_06-Nov-2007.tar + url = "http://host.robots.ox.ac.uk/pascal/VOC/voc2007/" + tar_filename = "VOCtest_06-Nov-2007.tar" + extracted_filename = "VOC2007test" + print(" [============= VOC 2007 Test Set =============]") + else: + raise Exception("Please set the dataset aug to 2012, 2012test or 2007.") + + ##======== download dataset + if dataset != "2012test": + from sys import platform as _platform + if folder_exists(os.path.join(path, extracted_filename)) is False: + print("[VOC] {} is nonexistent in {}".format(extracted_filename, path)) + maybe_download_and_extract(tar_filename, path, url, extract=True) + del_file(os.path.join(path, tar_filename)) + if dataset == "2012": + if _platform == "win32": + os.system("mv {}\VOCdevkit\VOC2012 {}\VOC2012".format(path, path)) + else: + os.system("mv {}/VOCdevkit/VOC2012 {}/VOC2012".format(path, path)) + elif dataset == "2007": + if _platform == "win32": + os.system("mv {}\VOCdevkit\VOC2007 {}\VOC2007".format(path, path)) + else: + os.system("mv {}/VOCdevkit/VOC2007 {}/VOC2007".format(path, path)) + elif dataset == "2007test": + if _platform == "win32": + os.system("mv {}\VOCdevkit\VOC2007 {}\VOC2007test".format(path, path)) + else: + os.system("mv {}/VOCdevkit/VOC2007 {}/VOC2007test".format(path, path)) + del_folder(os.path.join(path, 'VOCdevkit')) + ##======== object classes(labels) NOTE: YOU CAN CUSTOMIZE THIS LIST + classes = ["aeroplane", "bicycle", "bird", "boat", "bottle", "bus", "car", + "cat", "chair", "cow", "diningtable", "dog", "horse", "motorbike", + "person", "pottedplant", "sheep", "sofa", "train", "tvmonitor"] + if contain_classes_in_person: + classes_in_person = ["head", "hand", "foot"] + else: + classes_in_person = [] + + classes += classes_in_person # use extra 3 classes for person + + classes_dict = utils.list_string_to_dict(classes) + print("[VOC] object classes {}".format(classes_dict)) + + ##======== 1. image path list + # folder_imgs = path+"/"+extracted_filename+"/JPEGImages/" + folder_imgs = os.path.join(path, extracted_filename, "JPEGImages") + imgs_file_list = load_file_list(path=folder_imgs, regx='\\.jpg', printable=False) + print("[VOC] {} images found".format(len(imgs_file_list))) + imgs_file_list.sort(key=lambda s : int(s.replace('.',' ').replace('_', '').split(' ')[-2])) # 2007_000027.jpg --> 2007000027 + imgs_file_list = [os.path.join(folder_imgs, s) for s in imgs_file_list] + # print('IM',imgs_file_list[0::3333], imgs_file_list[-1]) + if dataset != "2012test": + ##======== 2. semantic segmentation maps path list + # folder_semseg = path+"/"+extracted_filename+"/SegmentationClass/" + folder_semseg = os.path.join(path, extracted_filename, "SegmentationClass") + imgs_semseg_file_list = load_file_list(path=folder_semseg, regx='\\.png', printable=False) + print("[VOC] {} maps for semantic segmentation found".format(len(imgs_semseg_file_list))) + imgs_semseg_file_list.sort(key=lambda s : int(s.replace('.',' ').replace('_', '').split(' ')[-2])) # 2007_000032.png --> 2007000032 + imgs_semseg_file_list = [os.path.join(folder_semseg, s) for s in imgs_semseg_file_list] + # print('Semantic Seg IM',imgs_semseg_file_list[0::333], imgs_semseg_file_list[-1]) + ##======== 3. instance segmentation maps path list + # folder_insseg = path+"/"+extracted_filename+"/SegmentationObject/" + folder_insseg = os.path.join(path, extracted_filename, "SegmentationObject") + imgs_insseg_file_list = load_file_list(path=folder_insseg, regx='\\.png', printable=False) + print("[VOC] {} maps for instance segmentation found".format(len(imgs_semseg_file_list))) + imgs_insseg_file_list.sort(key=lambda s : int(s.replace('.',' ').replace('_', '').split(' ')[-2])) # 2007_000032.png --> 2007000032 + imgs_insseg_file_list = [os.path.join(folder_insseg, s) for s in imgs_insseg_file_list] + # print('Instance Seg IM',imgs_insseg_file_list[0::333], imgs_insseg_file_list[-1]) + else: + imgs_semseg_file_list = [] + imgs_insseg_file_list = [] + ##======== 4. annotations for bounding box and object class + # folder_ann = path+"/"+extracted_filename+"/Annotations/" + folder_ann = os.path.join(path, extracted_filename, "Annotations") + imgs_ann_file_list = load_file_list(path=folder_ann, regx='\\.xml', printable=False) + print("[VOC] {} XML annotation files for bounding box and object class found".format(len(imgs_ann_file_list))) + imgs_ann_file_list.sort(key=lambda s : int(s.replace('.',' ').replace('_', '').split(' ')[-2])) # 2007_000027.xml --> 2007000027 + imgs_ann_file_list = [os.path.join(folder_ann, s) for s in imgs_ann_file_list] + # print('ANN',imgs_ann_file_list[0::3333], imgs_ann_file_list[-1]) + + if dataset == "2012test": # remove unused images in JPEG folder + imgs_file_list_new = [] + for ann in imgs_ann_file_list: + ann = os.path.split(ann)[-1].split('.')[0] + for im in imgs_file_list: + if ann in im: + imgs_file_list_new.append(im) + break + imgs_file_list = imgs_file_list_new + print("[VOC] keep %d images" % len(imgs_file_list_new)) + + ##======== parse XML annotations + def convert(size, box): + dw = 1./size[0] + dh = 1./size[1] + x = (box[0] + box[1])/2.0 + y = (box[2] + box[3])/2.0 + w = box[1] - box[0] + h = box[3] - box[2] + x = x*dw + w = w*dw + y = y*dh + h = h*dh + return (x,y,w,h) + + def convert_annotation(file_name): + """ Given VOC2012 XML Annotations, returns number of objects and info. """ + in_file = open(file_name) + out_file = "" + tree = ET.parse(in_file) + root = tree.getroot() + size = root.find('size') + w = int(size.find('width').text) + h = int(size.find('height').text) + n_objs = 0 + + # print(file_name, w, h, size) + # exit() + for obj in root.iter('object'): + if dataset != "2012test": + difficult = obj.find('difficult').text + cls = obj.find('name').text + if cls not in classes or int(difficult) == 1: + continue + else: + cls = obj.find('name').text + if cls not in classes: + continue + cls_id = classes.index(cls) + xmlbox = obj.find('bndbox') + b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text), float(xmlbox.find('ymax').text)) + bb = convert((w,h), b) + # out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n') + out_file += str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n' + n_objs += 1 + if cls in "person": + for part in obj.iter('part'): + cls = part.find('name').text + if cls not in classes_in_person: + continue + cls_id = classes.index(cls) + xmlbox = part.find('bndbox') + b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text), float(xmlbox.find('ymax').text)) + bb = convert((w,h), b) + # out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n') + out_file += str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n' + n_objs += 1 + in_file.close() + return n_objs, out_file + + print("[VOC] Parsing xml annotations files") + n_objs_list = [] + objs_info_list = [] # Darknet Format list of string + objs_info_dicts = {} + for idx, ann_file in enumerate(imgs_ann_file_list): + # print(ann_file) + n_objs, objs_info = convert_annotation(ann_file) + n_objs_list.append(n_objs) + objs_info_list.append(objs_info) + with tf.gfile.GFile(ann_file, 'r') as fid: + xml_str = fid.read() + xml = etree.fromstring(xml_str) + data = _recursive_parse_xml_to_dict(xml)['annotation'] + objs_info_dicts.update({imgs_file_list[idx]: data}) + + return imgs_file_list, imgs_semseg_file_list, imgs_insseg_file_list, imgs_ann_file_list, \ + classes, classes_in_person, classes_dict,\ + n_objs_list, objs_info_list, objs_info_dicts + + + +## Load and save network list npz def save_npz(save_list=[], name='model.npz', sess=None): """Input parameters and the file name, save parameters into .npz file. Use tl.utils.load_npz() to restore. @@ -520,16 +1027,13 @@ def save_npz(save_list=[], name='model.npz', sess=None): Examples -------- - >>> tl.files.save_npz(network.all_params, name='model_test.npz', sess=sess) - ... File saved to: model_test.npz - >>> load_params = tl.files.load_npz(name='model_test.npz') - ... Loading param0, (784, 800) - ... Loading param1, (800,) - ... Loading param2, (800, 800) - ... Loading param3, (800,) - ... Loading param4, (800, 10) - ... Loading param5, (10,) - >>> put parameters into a TensorLayer network, please see assign_params() + - Save model to npz + >>> tl.files.save_npz(network.all_params, name='model.npz', sess=sess) + - Load model from npz (Method 1) + >>> load_params = tl.files.load_npz(name='model.npz') + >>> tl.files.assign_params(sess, load_params, network) + - Load model from npz (Method 2) + >>> tl.files.load_and_assign_npz(sess=sess, name='model.npz', network=network) Notes ----- @@ -561,40 +1065,6 @@ def save_npz(save_list=[], name='model.npz', sess=None): # np.savez(name, **rename_dict) # print('Model is saved to: %s' % name) -def save_npz_dict(save_list=[], name='model.npz', sess=None): - """Input parameters and the file name, save parameters as a dictionary into .npz file. Use tl.utils.load_npz_dict() to restore. - - Parameters - ---------- - save_list : a list - Parameters want to be saved. - name : a string or None - The name of the .npz file. - sess : None or Session - - Notes - ----- - This function tries to avoid a potential broadcasting error raised by numpy. - - """ - ## save params into a list - save_list_var = [] - if sess: - save_list_var = sess.run(save_list) - else: - try: - for k, value in enumerate(save_list): - save_list_var.append(value.eval()) - except: - print(" Fail to save model, Hint: pass the session into this function, save_npz_dict(network.all_params, name='model.npz', sess=sess)") - save_var_dict = {str(idx):val for idx, val in enumerate(save_list_var)} - np.savez(name, **save_var_dict) - save_list_var = None - save_var_dict = None - del save_list_var - del save_var_dict - print("[*] %s saved" % name) - def load_npz(path='', name='model.npz'): """Load the parameters of a Model saved by tl.files.save_npz(). @@ -612,7 +1082,7 @@ def load_npz(path='', name='model.npz'): Examples -------- - - See save_npz and assign_params + - See ``save_npz`` References ---------- @@ -636,25 +1106,6 @@ def load_npz(path='', name='model.npz'): # exit() # return d.items()[0][1]['params'] -def load_npz_dict(path='', name='model.npz'): - """Load the parameters of a Model saved by tl.files.save_npz_dict(). - - Parameters - ---------- - path : a string - Folder path to .npz file. - name : a string or None - The name of the .npz file. - - Returns - -------- - params : list - A list of parameters in order. - """ - d = np.load( path+name ) - saved_list_var = [val[1] for val in sorted(d.items(), key=lambda tup: int(tup[0]))] - return saved_list_var - def assign_params(sess, params, network): """Assign the given parameters to the TensorLayer network. @@ -673,15 +1124,13 @@ def assign_params(sess, params, network): Examples -------- - >>> Save your network as follow: - >>> tl.files.save_npz(network.all_params, name='model_test.npz') - >>> network.print_params() - ... - ... Next time, load and assign your network as follow: - >>> tl.layers.initialize_global_variables(sess) - >>> load_params = tl.files.load_npz(name='model_test.npz') + - Save model to npz + >>> tl.files.save_npz(network.all_params, name='model.npz', sess=sess) + - Load model from npz (Method 1) + >>> load_params = tl.files.load_npz(name='model.npz') >>> tl.files.assign_params(sess, load_params, network) - >>> network.print_params() + - Load model from npz (Method 2) + >>> tl.files.load_and_assign_npz(sess=sess, name='model.npz', network=network) References ---------- @@ -711,6 +1160,7 @@ def load_and_assign_npz(sess=None, name=None, network=None): Examples --------- + >>> tl.files.save_npz(net.all_params, name='net.npz', sess=sess) >>> tl.files.load_and_assign_npz(sess=sess, name='net.npz', network=net) """ assert network is not None @@ -724,7 +1174,202 @@ def load_and_assign_npz(sess=None, name=None, network=None): print("[*] Load {} SUCCESS!".format(name)) return network -# Load and save variables +## Load and save network dict npz +def save_npz_dict(save_list=[], name='model.npz', sess=None): + """Input parameters and the file name, save parameters as a dictionary into .npz file. + Use ``tl.files.load_and_assign_npz_dict()`` to restore. + + Parameters + ---------- + save_list : a list to tensor for parameters + Parameters want to be saved. + name : a string + The name of the .npz file. + sess : Session + """ + assert sess is not None + save_list_names = [tensor.name for tensor in save_list] + save_list_var = sess.run(save_list) + save_var_dict = {save_list_names[idx]: val for idx, val in enumerate(save_list_var)} + np.savez(name, **save_var_dict) + save_list_var = None + save_var_dict = None + del save_list_var + del save_var_dict + print("[*] Model saved in npz_dict %s" % name) + +def load_and_assign_npz_dict(name='model.npz', sess=None): + """Restore the parameters saved by ``tl.files.save_npz_dict()``. + + Parameters + ---------- + name : a string + The name of the .npz file. + sess : Session + """ + assert sess is not None + if not os.path.exists(name): + print("[!] Load {} failed!".format(name)) + return False + + params = np.load(name) + if len(params.keys()) != len(set(params.keys())): + raise Exception("Duplication in model npz_dict %s" % name) + ops = list() + for key in params.keys(): + try: + # tensor = tf.get_default_graph().get_tensor_by_name(key) + # varlist = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, scope=key) + varlist = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope=key) + if len(varlist) > 1: + raise Exception("[!] Multiple candidate variables to be assigned for name %s" % key) + elif len(varlist) == 0: + raise KeyError + else: + ops.append(varlist[0].assign(params[key])) + print("[*] params restored: %s" % key) + except KeyError: + print("[!] Warning: Tensor named %s not found in network." % key) + + sess.run(ops) + print("[*] Model restored from npz_dict %s" % name) + +# def save_npz_dict(save_list=[], name='model.npz', sess=None): +# """Input parameters and the file name, save parameters as a dictionary into .npz file. Use tl.utils.load_npz_dict() to restore. +# +# Parameters +# ---------- +# save_list : a list +# Parameters want to be saved. +# name : a string or None +# The name of the .npz file. +# sess : None or Session +# +# Notes +# ----- +# This function tries to avoid a potential broadcasting error raised by numpy. +# +# """ +# ## save params into a list +# save_list_var = [] +# if sess: +# save_list_var = sess.run(save_list) +# else: +# try: +# for k, value in enumerate(save_list): +# save_list_var.append(value.eval()) +# except: +# print(" Fail to save model, Hint: pass the session into this function, save_npz_dict(network.all_params, name='model.npz', sess=sess)") +# save_var_dict = {str(idx):val for idx, val in enumerate(save_list_var)} +# np.savez(name, **save_var_dict) +# save_list_var = None +# save_var_dict = None +# del save_list_var +# del save_var_dict +# print("[*] %s saved" % name) +# +# def load_npz_dict(path='', name='model.npz'): +# """Load the parameters of a Model saved by tl.files.save_npz_dict(). +# +# Parameters +# ---------- +# path : a string +# Folder path to .npz file. +# name : a string or None +# The name of the .npz file. +# +# Returns +# -------- +# params : list +# A list of parameters in order. +# """ +# d = np.load( path+name ) +# saved_list_var = [val[1] for val in sorted(d.items(), key=lambda tup: int(tup[0]))] +# return saved_list_var + + + +## Load and save network ckpt +def save_ckpt(sess=None, mode_name='model.ckpt', save_dir='checkpoint', var_list=[], global_step=None, printable=False): + """Save parameters into ckpt file. + + Parameters + ------------ + sess : Session. + mode_name : string, name of the model, default is ``model.ckpt``. + save_dir : string, path / file directory to the ckpt, default is ``checkpoint``. + var_list : list of variables, if not given, save all global variables. + global_step : int or None, step number. + printable : bool, if True, print all params info. + + Examples + --------- + - see ``tl.files.load_ckpt()``. + """ + assert sess is not None + ckpt_file = os.path.join(save_dir, mode_name) + if var_list == []: + var_list = tf.global_variables() + + print("[*] save %s n_params: %d" % (ckpt_file, len(var_list))) + + if printable: + for idx, v in enumerate(var_list): + print(" param {:3}: {:15} {}".format(idx, v.name, str(v.get_shape()))) + + saver = tf.train.Saver(var_list) + saver.save(sess, ckpt_file, global_step=global_step) + +def load_ckpt(sess=None, mode_name='model.ckpt', save_dir='checkpoint', var_list=[], is_latest=True, printable=False): + """Load parameters from ckpt file. + + Parameters + ------------ + sess : Session. + mode_name : string, name of the model, default is ``model.ckpt``. + Note that if ``is_latest`` is True, this function will get the ``mode_name`` automatically. + save_dir : string, path / file directory to the ckpt, default is ``checkpoint``. + var_list : list of variables, if not given, save all global variables. + is_latest : bool, if True, load the latest ckpt, if False, load the ckpt with the name of ```mode_name``. + printable : bool, if True, print all params info. + + Examples + ---------- + - Save all global parameters. + >>> tl.files.save_ckpt(sess=sess, mode_name='model.ckpt', save_dir='model', printable=True) + - Save specific parameters. + >>> tl.files.save_ckpt(sess=sess, mode_name='model.ckpt', var_list=net.all_params, save_dir='model', printable=True) + - Load latest ckpt. + >>> tl.files.load_ckpt(sess=sess, var_list=net.all_params, save_dir='model', printable=True) + - Load specific ckpt. + >>> tl.files.load_ckpt(sess=sess, mode_name='model.ckpt', var_list=net.all_params, save_dir='model', is_latest=False, printable=True) + """ + assert sess is not None + + if is_latest: + ckpt_file = tf.train.latest_checkpoint(save_dir) + else: + ckpt_file = os.path.join(save_dir, mode_name) + + if var_list == []: + var_list = tf.global_variables() + + print("[*] load %s n_params: %d" % (ckpt_file, len(var_list))) + + if printable: + for idx, v in enumerate(var_list): + print(" param {:3}: {:15} {}".format(idx, v.name, str(v.get_shape()))) + + try: + saver = tf.train.Saver(var_list) + saver.restore(sess, ckpt_file) + except Exception as e: + print(e) + print("[*] load ckpt fail ...") + + + +## Load and save variables def save_any_to_npy(save_dict={}, name='file.npy'): """Save variables to .npy file. @@ -757,30 +1402,35 @@ def load_npy_to_any(path='', name='file.npy'): exit() -# Visualizing npz files -def npz_to_W_pdf(path=None, regx='w1pre_[0-9]+\.(npz)'): - """Convert the first weight matrix of .npz file to .pdf by using tl.visualize.W(). - Parameters - ---------- - path : a string or None - A folder path to npz files. - regx : a string - Regx for the file name. + +## Folder functions +def file_exists(filepath): + """ Check whether a file exists by given file path. """ + return os.path.isfile(filepath) + +def folder_exists(folderpath): + """ Check whether a folder exists by given folder path. """ + return os.path.isdir(folderpath) + +def del_file(filepath): + """ Delete a file by given file path. """ + os.remove(filepath) + +def del_folder(folderpath): + """ Delete a folder by given folder path. """ + os.rmdir(folderpath) + +def read_file(filepath): + """ Read a file and return a string. Examples - -------- - >>> Convert the first weight matrix of w1_pre...npz file to w1_pre...pdf. - >>> tl.files.npz_to_W_pdf(path='/Users/.../npz_file/', regx='w1pre_[0-9]+\.(npz)') + --------- + >>> data = tl.files.read_file('data.txt') """ - file_list = load_file_list(path=path, regx=regx) - for f in file_list: - W = load_npz(path, f)[0] - print("%s --> %s" % (f, f.split('.')[0]+'.pdf')) - visualize.W(W, second=10, saveable=True, name=f.split('.')[0], fig_idx=2012) + with open(filepath, 'r') as afile: + return afile.read() - -## Helper functions def load_file_list(path=None, regx='\.npz', printable=True): """Return a file list in a folder by given a path and regular expression. @@ -853,18 +1503,19 @@ def maybe_download_and_extract(filename, working_directory, url_source, extract= and optionally also tries to extract the file if format is ".zip" or ".tar" Parameters - ---------- + ----------- filename : string The name of the (to be) dowloaded file. working_directory : string A folder path to search for the file in and dowload the file to url : string The URL to download the file from - extract : bool, defaults to False + extract : bool, defaults is False If True, tries to uncompress the dowloaded file is ".tar.gz/.tar.bz2" or ".zip" file expected_bytes : int/None If set tries to verify that the downloaded file is of the specified size, otherwise raises an Exception, - defaults to None which corresponds to no check being performed + defaults is None which corresponds to no check being performed + Returns ---------- filepath to dowloaded (uncompressed) file @@ -900,7 +1551,7 @@ def _dlProgress(count, blockSize, totalSize): _download(filename, working_directory, url_source) print() statinfo = os.stat(filepath) - print('Succesfully downloaded', filename, statinfo.st_size, 'bytes.') + print('Succesfully downloaded %s %s bytes.' % (filename, statinfo.st_size))#, 'bytes.') if(not(expected_bytes is None) and (expected_bytes != statinfo.st_size)): raise Exception('Failed to verify ' + filename + '. Can you get to it with a browser?') if(extract): @@ -916,3 +1567,48 @@ def _dlProgress(count, blockSize, totalSize): else: print("Unknown compression_format only .tar.gz/.tar.bz2/.tar and .zip supported") return filepath + + +## Sort +def natural_keys(text): + """Sort list of string with number in human order. + + Examples + ---------- + >>> l = ['im1.jpg', 'im31.jpg', 'im11.jpg', 'im21.jpg', 'im03.jpg', 'im05.jpg'] + >>> l.sort(key=tl.files.natural_keys) + ... ['im1.jpg', 'im03.jpg', 'im05', 'im11.jpg', 'im21.jpg', 'im31.jpg'] + >>> l.sort() # that is what we dont want + ... ['im03.jpg', 'im05', 'im1.jpg', 'im11.jpg', 'im21.jpg', 'im31.jpg'] + + References + ---------- + alist.sort(key=natural_keys) sorts in human order + http://nedbatchelder.com/blog/200712/human_sorting.html + (See Toothy's implementation in the comments) + """ + def atoi(text): + return int(text) if text.isdigit() else text + return [ atoi(c) for c in re.split('(\d+)', text) ] + +# Visualizing npz files +def npz_to_W_pdf(path=None, regx='w1pre_[0-9]+\.(npz)'): + """Convert the first weight matrix of .npz file to .pdf by using tl.visualize.W(). + + Parameters + ---------- + path : a string or None + A folder path to npz files. + regx : a string + Regx for the file name. + + Examples + -------- + >>> Convert the first weight matrix of w1_pre...npz file to w1_pre...pdf. + >>> tl.files.npz_to_W_pdf(path='/Users/.../npz_file/', regx='w1pre_[0-9]+\.(npz)') + """ + file_list = load_file_list(path=path, regx=regx) + for f in file_list: + W = load_npz(path, f)[0] + print("%s --> %s" % (f, f.split('.')[0]+'.pdf')) + visualize.W(W, second=10, saveable=True, name=f.split('.')[0], fig_idx=2012) diff --git a/tensorlayer/iterate.py b/tensorlayer/iterate.py index 9778fc6f..d6c973dc 100644 --- a/tensorlayer/iterate.py +++ b/tensorlayer/iterate.py @@ -1,5 +1,5 @@ #! /usr/bin/python -# -*- coding: utf8 -*- +# -*- coding: utf-8 -*- @@ -21,11 +21,6 @@ def minibatches(inputs=None, targets=None, batch_size=None, shuffle=False): shuffle : boolean Indicating whether to use a shuffling queue, shuffle the dataset before return. - Hints - ------- - - If you have two inputs, e.g. X1 (1000, 100) and X2 (1000, 80), you can ``np.hstack((X1, X2)) - into (1000, 180) and feed into ``inputs``, then you can split a batch of X1 and X2. - Examples -------- >>> X = np.asarray([['a','a'], ['b','b'], ['c','c'], ['d','d'], ['e','e'], ['f','f']]) @@ -41,6 +36,12 @@ def minibatches(inputs=None, targets=None, batch_size=None, shuffle=False): ... (array([['e', 'e'], ... ['f', 'f']], ... dtype='>> network = tl.layers.DynamicRNNLayer(network, - ... cell_fn = tf.nn.rnn_cell.BasicLSTMCell, + ... cell_fn = tf.contrib.rnn.BasicLSTMCell, ... n_hidden = embedding_size, ... dropout = (0.7 if is_train else None), ... initializer = w_init, ... sequence_length = tl.layers.retrieve_seq_length_op2(input_seqs), ... return_last = True, - ... name = 'e_dynamicrnn',) + ... name = 'e_dynamicrnn') >>> return network >>> >>> net_train = embed_seq(t_caption, is_train=True, reuse=False) @@ -116,13 +115,15 @@ def set_name_reuse(enable=True): """ set_keep['name_reuse'] = enable -def initialize_rnn_state(state): - """Return the initialized RNN state. - The input is LSTMStateTuple or State of RNNCells. +def initialize_rnn_state(state, feed_dict=None): + """Returns the initialized RNN state. + The inputs are LSTMStateTuple or State of RNNCells and an optional feed_dict. Parameters ----------- state : a RNN state. + feed_dict : None or a dictionary for initializing the state values (optional). + If None, returns the zero state. """ try: # TF1.0 LSTMStateTuple = tf.contrib.rnn.LSTMStateTuple @@ -130,11 +131,11 @@ def initialize_rnn_state(state): LSTMStateTuple = tf.nn.rnn_cell.LSTMStateTuple if isinstance(state, LSTMStateTuple): - c = state.c.eval() - h = state.h.eval() + c = state.c.eval(feed_dict=feed_dict) + h = state.h.eval(feed_dict=feed_dict) return (c, h) else: - new_state = state.eval() + new_state = state.eval(feed_dict=feed_dict) return new_state def print_all_variables(train_only=False): @@ -151,7 +152,7 @@ def print_all_variables(train_only=False): t_vars = tf.trainable_variables() print(" [*] printing trainable variables") else: - try: # TF1.0 + try: # TF1.0+ t_vars = tf.global_variables() except: # TF0.12 t_vars = tf.all_variables() @@ -171,7 +172,7 @@ def get_variables_with_name(name, train_only=True, printable=False): if train_only: t_vars = tf.trainable_variables() else: - try: # TF1.0 + try: # TF1.0+ t_vars = tf.global_variables() except: # TF0.12 t_vars = tf.all_variables() @@ -199,7 +200,6 @@ def get_layers_with_name(network=None, name="", printable=False): if name in layer.name: layers.append(layer) if printable: - # print(layer.name) print(" got {:3}: {:15} {}".format(i, layer.name, str(layer.get_shape()))) i = i + 1 return layers @@ -222,19 +222,52 @@ def list_remove_repeat(l=None): [l2.append(i) for i in l if not i in l2] return l2 +def merge_networks(layers=[]): + """Merge all parameters, layers and dropout probabilities to a :class:`Layer`. + + Parameters + ---------- + layer : list of :class:`Layer` instance + Merge all parameters, layers and dropout probabilities to the first layer in the list. + + Examples + --------- + >>> n1 = ... + >>> n2 = ... + >>> n1 = merge_networks([n1, n2]) + """ + layer = layers[0] + + all_params = [] + all_layers = [] + all_drop = {} + for l in layers: + all_params.extend(l.all_params) + all_layers.extend(l.all_layers) + all_drop.update(l.all_drop) + + layer.all_params = list(all_params) + layer.all_layers = list(all_layers) + layer.all_drop = dict(all_drop) + + layer.all_layers = list_remove_repeat(layer.all_layers) + layer.all_params = list_remove_repeat(layer.all_params) + + return layer + def initialize_global_variables(sess=None): - """Excute ``sess.run(tf.global_variables_initializer())`` for TF12+ or - sess.run(tf.initialize_all_variables()) for TF11. + """Excute ``sess.run(tf.global_variables_initializer())`` for TF 0.12+ or + ``sess.run(tf.initialize_all_variables())`` for TF 0.11. Parameters ---------- sess : a Session """ assert sess is not None - try: # TF12 - sess.run(tf.global_variables_initializer()) - except: # TF11 - sess.run(tf.initialize_all_variables()) + # try: # TF12+ + sess.run(tf.global_variables_initializer()) + # except: # TF11 + # sess.run(tf.initialize_all_variables()) ## Basic layer @@ -259,10 +292,10 @@ def __init__( name ='layer' ): self.inputs = inputs - scope_name=tf.get_variable_scope().name + scope_name = tf.get_variable_scope().name if scope_name: name = scope_name + '/' + name - if (name in set_keep['_layers_name_list']) and name_reuse == False: + if (name in set_keep['_layers_name_list']) and set_keep['name_reuse'] == False: raise Exception("Layer '%s' already exists, please choice other 'name' or reuse this layer\ \nHint : Use different name for different 'Layer' (The name is used to control parameter sharing)" % name) else: @@ -270,13 +303,13 @@ def __init__( if name not in ['', None, False]: set_keep['_layers_name_list'].append(name) - def print_params(self, details=True): + def print_params(self, details=True, session=None): ''' Print all info of parameters in the network''' for i, p in enumerate(self.all_params): if details: try: # print(" param {:3}: {:15} (mean: {:<18}, median: {:<18}, std: {:<18}) {}".format(i, str(p.eval().shape), p.eval().mean(), np.median(p.eval()), p.eval().std(), p.name)) - val = p.eval() + val = p.eval(session=session) print(" param {:3}: {:20} {:15} {} (mean: {:<18}, median: {:<18}, std: {:<18}) ".format(i, p.name, str(val.shape), p.dtype.name, val.mean(), np.median(val), val.std())) except Exception as e: print(str(e)) @@ -410,7 +443,7 @@ class Word2vecEmbeddingInputlayer(Layer): name : a string or None An optional name to attach to this layer. - Variables + Attributes -------------- nce_cost : a tensor The NCE loss. @@ -488,26 +521,29 @@ def __init__( embeddings = tf.get_variable(name='embeddings', shape=(vocabulary_size, embedding_size), initializer=E_init, + dtype=D_TYPE, **E_init_args) embed = tf.nn.embedding_lookup(embeddings, self.inputs) # Construct the variables for the NCE loss (i.e. negative sampling) nce_weights = tf.get_variable(name='nce_weights', shape=(vocabulary_size, embedding_size), initializer=nce_W_init, + dtype=D_TYPE, **nce_W_init_args) nce_biases = tf.get_variable(name='nce_biases', shape=(vocabulary_size), initializer=nce_b_init, + dtype=D_TYPE, **nce_b_init_args) # Compute the average NCE loss for the batch. # tf.nce_loss automatically draws a new sample of the negative labels # each time we evaluate the loss. self.nce_cost = tf.reduce_mean( - tf.nn.nce_loss(weights=nce_weights, biases=nce_biases, - inputs=embed, labels=train_labels, - num_sampled=num_sampled, num_classes=vocabulary_size, - **nce_loss_args)) + tf.nn.nce_loss(weights=nce_weights, biases=nce_biases, + inputs=embed, labels=train_labels, + num_sampled=num_sampled, num_classes=vocabulary_size, + **nce_loss_args)) self.outputs = embed self.normalized_embeddings = tf.nn.l2_normalize(embeddings, 1) @@ -543,7 +579,7 @@ class EmbeddingInputlayer(Layer): name : a string or None An optional name to attach to this layer. - Variables + Attributes ------------ outputs : a tensor The outputs of embedding layer. @@ -611,6 +647,7 @@ def __init__( embeddings = tf.get_variable(name='embeddings', shape=(vocabulary_size, embedding_size), initializer=E_init, + dtype=D_TYPE, **E_init_args) embed = tf.nn.embedding_lookup(embeddings, self.inputs) @@ -620,6 +657,88 @@ def __init__( self.all_params = [embeddings] self.all_drop = {} + +class AverageEmbeddingInputlayer(Layer): + """The :class:`AverageEmbeddingInputlayer` averages over embeddings of inputs, can be used as the input layer for models like DAN[1] and FastText[2]. + + Parameters + ------------ + inputs : input placeholder or tensor + vocabulary_size : an integer, the size of vocabulary + embedding_size : an integer, the dimension of embedding vectors + pad_value : an integer, the scalar pad value used in inputs + name : a string, the name of the layer + embeddings_initializer : the initializer of the embedding matrix + embeddings_kwargs : kwargs to get embedding matrix variable + + References + ------------ + - [1] Iyyer, M., Manjunatha, V., Boyd-Graber, J., & Daum’e III, H. (2015). Deep Unordered Composition Rivals Syntactic Methods for Text Classification. In Association for Computational Linguistics. + - [2] Joulin, A., Grave, E., Bojanowski, P., & Mikolov, T. (2016).`Bag of Tricks for Efficient Text Classification. `_ + """ + def __init__( + self, inputs, vocabulary_size, embedding_size, + pad_value=0, + name='average_embedding_layer', + embeddings_initializer=tf.random_uniform_initializer(-0.1, 0.1), + embeddings_kwargs=None, + ): + super().__init__(name=name) + + # if embeddings_kwargs is None: + # embeddings_kwargs = {} + + if inputs.get_shape().ndims != 2: + raise ValueError( + 'inputs must be of size batch_size * batch_sentence_length') + + self.inputs = inputs + + print(" [TL] AverageEmbeddingInputlayer %s: (%d, %d)" % (name, vocabulary_size, embedding_size)) + with tf.variable_scope(name): + self.embeddings = tf.get_variable( + name='embeddings', + shape=(vocabulary_size, embedding_size), + initializer=embeddings_initializer, + dtype=D_TYPE, + **(embeddings_kwargs or {}) + # **embeddings_kwargs + ) # **(embeddings_kwargs or {}), + + word_embeddings = tf.nn.embedding_lookup( + self.embeddings, self.inputs, + name='word_embeddings', + ) + # Zero out embeddings of pad value + masks = tf.not_equal(self.inputs, pad_value, name='masks') + word_embeddings *= tf.cast( + tf.expand_dims(masks, axis=-1), + # tf.float32, + dtype=D_TYPE, + ) + sum_word_embeddings = tf.reduce_sum(word_embeddings, axis=1) + + # Count number of non-padding words in each sentence + sentence_lengths = tf.count_nonzero( + masks, + axis=1, + keep_dims=True, + # dtype=tf.float32, + dtype=D_TYPE, + name='sentence_lengths', + ) + + sentence_embeddings = tf.divide( + sum_word_embeddings, + sentence_lengths + 1e-8, # Add epsilon to avoid dividing by 0 + name='sentence_embeddings' + ) + + self.outputs = sentence_embeddings + self.all_layers = [self.outputs] + self.all_params = [self.embeddings] + self.all_drop = {} + ## Dense layer class DenseLayer(Layer): """ @@ -686,12 +805,12 @@ def __init__( self.n_units = n_units print(" [TL] DenseLayer %s: %d %s" % (self.name, self.n_units, act.__name__)) with tf.variable_scope(name) as vs: - W = tf.get_variable(name='W', shape=(n_in, n_units), initializer=W_init, **W_init_args ) + W = tf.get_variable(name='W', shape=(n_in, n_units), initializer=W_init, dtype=D_TYPE, **W_init_args ) if b_init is not None: try: - b = tf.get_variable(name='b', shape=(n_units), initializer=b_init, **b_init_args ) + b = tf.get_variable(name='b', shape=(n_units), initializer=b_init, dtype=D_TYPE, **b_init_args ) except: # If initializer is a constant, do not specify shape. - b = tf.get_variable(name='b', initializer=b_init, **b_init_args ) + b = tf.get_variable(name='b', initializer=b_init, dtype=D_TYPE, **b_init_args ) self.outputs = act(tf.matmul(self.inputs, W) + b) else: self.outputs = act(tf.matmul(self.inputs, W)) @@ -778,7 +897,7 @@ def __init__( print(" lambda_l2_w: %f" % lambda_l2_w) print(" learning_rate: %f" % learning_rate) - # Mean-squre-error i.e. quadratic-cost + # Mean-square-error i.e. quadratic-cost mse = tf.reduce_sum(tf.squared_difference(y, x_recon), 1) mse = tf.reduce_mean(mse) # in theano: mse = ((y - x) ** 2 ).sum(axis=1).mean() # mse = tf.reduce_mean(tf.reduce_sum(tf.square(tf.sub(y, x_recon)), 1)) @@ -1099,8 +1218,8 @@ def __init__( print(" [TL] DropconnectDenseLayer %s: %d %s" % (self.name, self.n_units, act.__name__)) with tf.variable_scope(name) as vs: - W = tf.get_variable(name='W', shape=(n_in, n_units), initializer=W_init, **W_init_args ) - b = tf.get_variable(name='b', shape=(n_units), initializer=b_init, **b_init_args ) + W = tf.get_variable(name='W', shape=(n_in, n_units), initializer=W_init, dtype=D_TYPE, **W_init_args ) + b = tf.get_variable(name='b', shape=(n_units), initializer=b_init, dtype=D_TYPE, **b_init_args ) self.outputs = act(tf.matmul(self.inputs, W) + b)#, name=name) # 1.2 set_keep[name] = tf.placeholder(tf.float32) @@ -1169,7 +1288,7 @@ def __init__( if act is None: act = tf.identity with tf.variable_scope(name) as vs: - W = tf.get_variable(name='W_conv1d', shape=shape, initializer=W_init, **W_init_args ) + W = tf.get_variable(name='W_conv1d', shape=shape, initializer=W_init, dtype=D_TYPE, **W_init_args ) self.outputs = tf.nn.convolution( self.inputs, W, @@ -1179,7 +1298,7 @@ def __init__( data_format=data_format ) #1.2 if b_init: - b = tf.get_variable(name='b_conv1d', shape=(shape[-1]), initializer=b_init, **b_init_args ) + b = tf.get_variable(name='b_conv1d', shape=(shape[-1]), initializer=b_init, dtype=D_TYPE, **b_init_args ) self.outputs = self.outputs + b self.outputs = act(self.outputs) @@ -1218,8 +1337,8 @@ class Conv2dLayer(Layer): The arguments for the weights tf.get_variable(). b_init_args : dictionary The arguments for the biases tf.get_variable(). - use_cudnn_on_gpu : an optional string from: "NHWC", "NCHW". Defaults to "NHWC". - data_format : an optional bool. Defaults to True. + use_cudnn_on_gpu : bool, default is None. + data_format : string "NHWC" or "NCHW", default is "NHWC" name : a string or None An optional name to attach to this layer. @@ -1277,9 +1396,9 @@ def __init__( (self.name, str(shape), str(strides), padding, act.__name__)) with tf.variable_scope(name) as vs: - W = tf.get_variable(name='W_conv2d', shape=shape, initializer=W_init, **W_init_args ) + W = tf.get_variable(name='W_conv2d', shape=shape, initializer=W_init, dtype=D_TYPE, **W_init_args ) if b_init: - b = tf.get_variable(name='b_conv2d', shape=(shape[-1]), initializer=b_init, **b_init_args ) + b = tf.get_variable(name='b_conv2d', shape=(shape[-1]), initializer=b_init, dtype=D_TYPE, **b_init_args ) self.outputs = act( tf.nn.conv2d(self.inputs, W, strides=strides, padding=padding, use_cudnn_on_gpu=use_cudnn_on_gpu, data_format=data_format) + b ) else: self.outputs = act( tf.nn.conv2d(self.inputs, W, strides=strides, padding=padding, use_cudnn_on_gpu=use_cudnn_on_gpu, data_format=data_format)) @@ -1383,9 +1502,9 @@ def __init__( (self.name, str(shape), str(output_shape), str(strides), padding, act.__name__)) # print(" DeConv2dLayer: Untested") with tf.variable_scope(name) as vs: - W = tf.get_variable(name='W_deconv2d', shape=shape, initializer=W_init, **W_init_args ) + W = tf.get_variable(name='W_deconv2d', shape=shape, initializer=W_init, dtype=D_TYPE, **W_init_args ) if b_init: - b = tf.get_variable(name='b_deconv2d', shape=(shape[-2]), initializer=b_init, **b_init_args ) + b = tf.get_variable(name='b_deconv2d', shape=(shape[-2]), initializer=b_init, dtype=D_TYPE, **b_init_args ) self.outputs = act( tf.nn.conv2d_transpose(self.inputs, W, output_shape=output_shape, strides=strides, padding=padding) + b ) else: self.outputs = act( tf.nn.conv2d_transpose(self.inputs, W, output_shape=output_shape, strides=strides, padding=padding)) @@ -1446,8 +1565,8 @@ def __init__( with tf.variable_scope(name) as vs: # W = tf.Variable(W_init(shape=shape, **W_init_args), name='W_conv') # b = tf.Variable(b_init(shape=[shape[-1]], **b_init_args), name='b_conv') - W = tf.get_variable(name='W_conv3d', shape=shape, initializer=W_init, **W_init_args ) - b = tf.get_variable(name='b_conv3d', shape=(shape[-1]), initializer=b_init, **b_init_args ) + W = tf.get_variable(name='W_conv3d', shape=shape, initializer=W_init, dtype=D_TYPE, **W_init_args ) + b = tf.get_variable(name='b_conv3d', shape=(shape[-1]), initializer=b_init, dtype=D_TYPE, **b_init_args ) self.outputs = act( tf.nn.conv3d(self.inputs, W, strides=strides, padding=padding, name=None) + b ) # self.outputs = act( tf.nn.conv3d(self.inputs, W, strides=strides, padding=padding, name=None) + b ) @@ -1506,8 +1625,8 @@ def __init__( (self.name, str(shape), str(output_shape), str(strides), padding, act.__name__)) with tf.variable_scope(name) as vs: - W = tf.get_variable(name='W_deconv3d', shape=shape, initializer=W_init, **W_init_args ) - b = tf.get_variable(name='b_deconv3d', shape=(shape[-2]), initializer=b_init, **b_init_args ) + W = tf.get_variable(name='W_deconv3d', shape=shape, initializer=W_init, dtype=D_TYPE, **W_init_args ) + b = tf.get_variable(name='b_deconv3d', shape=(shape[-2]), initializer=b_init, dtype=D_TYPE, **b_init_args ) self.outputs = act( tf.nn.conv3d_transpose(self.inputs, W, output_shape=output_shape, strides=strides, padding=padding) + b ) @@ -1626,6 +1745,237 @@ def __init__( self.all_layers.extend( [self.outputs] ) +# ## 2D deformable convolutional layer +def _to_bc_h_w(x, x_shape): + """(b, h, w, c) -> (b*c, h, w)""" + x = tf.transpose(x, [0, 3, 1, 2]) + x = tf.reshape(x, (-1, x_shape[1], x_shape[2])) + return x + +def _to_b_h_w_n_c(x, x_shape): + """(b*c, h, w, n) -> (b, h, w, n, c)""" + x = tf.reshape( + x, (-1, x_shape[4], x_shape[1], x_shape[2], x_shape[3])) + x = tf.transpose(x, [0, 2, 3, 4, 1]) + return x + +def tf_repeat(a, repeats): + """TensorFlow version of np.repeat for 1D""" + # https://github.com/tensorflow/tensorflow/issues/8521 + assert len(a.get_shape()) == 1 + + a = tf.expand_dims(a, -1) + a = tf.tile(a, [1, repeats]) + a = tf_flatten(a) + return a + +def tf_batch_map_coordinates(inputs, coords): + """Batch version of tf_map_coordinates + + Only supports 2D feature maps + + Parameters + ---------- + input : tf.Tensor. shape = (b*c, h, w) + coords : tf.Tensor. shape = (b*c, h, w, n, 2) + + Returns + ------- + tf.Tensor. shape = (b*c, h, w, n) + """ + + input_shape = inputs.get_shape() + coords_shape = coords.get_shape() + batch_channel = tf.shape(inputs)[0] + input_h = int(input_shape[1]) + input_w = int(input_shape[2]) + kernel_n = int(coords_shape[3]) + n_coords = input_h * input_w * kernel_n + + coords_lt = tf.cast(tf.floor(coords), 'int32') + coords_rb = tf.cast(tf.ceil(coords), 'int32') + coords_lb = tf.stack([coords_lt[:, :, :, :, 0], coords_rb[:, :, :, :, 1]], axis=-1) + coords_rt = tf.stack([coords_rb[:, :, :, :, 0], coords_lt[:, :, :, :, 1]], axis=-1) + + idx = tf_repeat(tf.range(batch_channel), n_coords) + + vals_lt = _get_vals_by_coords(inputs, coords_lt, idx, (batch_channel, input_h, input_w, kernel_n)) + vals_rb = _get_vals_by_coords(inputs, coords_rb, idx, (batch_channel, input_h, input_w, kernel_n)) + vals_lb = _get_vals_by_coords(inputs, coords_lb, idx, (batch_channel, input_h, input_w, kernel_n)) + vals_rt = _get_vals_by_coords(inputs, coords_rt, idx, (batch_channel, input_h, input_w, kernel_n)) + + coords_offset_lt = coords - tf.cast(coords_lt, 'float32') + + vals_t = vals_lt + (vals_rt - vals_lt) * coords_offset_lt[:, :, :, :, 0] + vals_b = vals_lb + (vals_rb - vals_lb) * coords_offset_lt[:, :, :, :, 0] + mapped_vals = vals_t + (vals_b - vals_t) * coords_offset_lt[:, :, :, :, 1] + + return mapped_vals + +def tf_batch_map_offsets(inputs, offsets, grid_offset): + """Batch map offsets into input + + Parameters + --------- + inputs : tf.Tensor. shape = (b, h, w, c) + offsets: tf.Tensor. shape = (b, h, w, 2*n) + grid_offset: Offset grids shape = (h, w, n, 2) + + Returns + ------- + tf.Tensor. shape = (b, h, w, c) + """ + + input_shape = inputs.get_shape() + batch_size = tf.shape(inputs)[0] + kernel_n = int(int(offsets.get_shape()[3])/2) + input_h = input_shape[1] + input_w = input_shape[2] + channel = input_shape[3] + + # inputs (b, h, w, c) --> (b*c, h, w) + inputs = _to_bc_h_w(inputs, input_shape) + + # offsets (b, h, w, 2*n) --> (b, h, w, n, 2) + offsets = tf.reshape(offsets, (batch_size, input_h, input_w, kernel_n, 2)) + # offsets (b, h, w, n, 2) --> (b*c, h, w, n, 2) + # offsets = tf.tile(offsets, [channel, 1, 1, 1, 1]) + + coords = tf.expand_dims(grid_offset, 0) # grid_offset --> (1, h, w, n, 2) + coords = tf.tile(coords, [batch_size, 1, 1, 1, 1]) + offsets # grid_offset --> (b, h, w, n, 2) + + # clip out of bound + coords = tf.stack([tf.clip_by_value(coords[:, :, :, :, 0], 0.0, tf.cast(input_h - 1, 'float32')), + tf.clip_by_value(coords[:, :, :, :, 1], 0.0, tf.cast(input_w - 1, 'float32'))], axis=-1) + coords = tf.tile(coords, [channel, 1, 1, 1, 1]) + + mapped_vals = tf_batch_map_coordinates(inputs, coords) + # (b*c, h, w, n) --> (b, h, w, n, c) + mapped_vals = _to_b_h_w_n_c(mapped_vals, [batch_size, input_h, input_w, kernel_n, channel]) + + return mapped_vals + +class DeformableConv2dLayer(Layer): + """The :class:`DeformableConv2dLayer` class is a + `Deformable Convolutional Networks `_ . + + Parameters + ----------- + layer : TensorLayer layer. + offset_layer : TensorLayer layer, to predict the offset of convolutional operations. The shape of its output should be (batchsize, input height, input width, 2*(number of element in the convolutional kernel)) + e.g. if apply a 3*3 kernel, the number of the last dimension should be 18 (2*3*3) + channel_multiplier : int, The number of channels to expand to. + filter_size : tuple (height, width) for filter size. + strides : tuple (height, width) for strides. Current implementation fix to (1, 1, 1, 1) + act : None or activation function. + shape : list of shape + shape of the filters, [filter_height, filter_width, in_channels, out_channels]. + W_init : weights initializer + The initializer for initializing the weight matrix. + b_init : biases initializer or None + The initializer for initializing the bias vector. If None, skip biases. + W_init_args : dictionary + The arguments for the weights tf.get_variable(). + b_init_args : dictionary + The arguments for the biases tf.get_variable(). + name : a string or None + An optional name to attach to this layer. + + Examples + -------- + >>> network = tl.layers.InputLayer(x, name='input_layer') + >>> offset_1 = tl.layers.Conv2dLayer(layer=network, act=act, shape=[3, 3, 3, 18], strides=[1, 1, 1, 1],padding='SAME', name='offset_layer1') + >>> network = tl.layers.DeformableConv2dLayer(layer=network, act=act, offset_layer=offset_1, shape=[3, 3, 3, 32], name='deformable_conv_2d_layer1') + >>> offset_2 = tl.layers.Conv2dLayer(layer=network, act=act, shape=[3, 3, 32, 18], strides=[1, 1, 1, 1], padding='SAME', name='offset_layer2') + >>> network = tl.layers.DeformableConv2dLayer(layer=network, act = act, offset_layer=offset_2, shape=[3, 3, 32, 64], name='deformable_conv_2d_layer2') + + References + ----------- + - The deformation operation was adapted from the implementation in ``_ + + Notes + ----------- + - The stride is fixed as (1, 1, 1, 1). + - The padding is fixed as 'SAME'. + - The current implementation is memory-inefficient, please use carefully. + """ + def __init__( + self, + layer=None, + act=tf.identity, + offset_layer=None, + shape=[3, 3, 1, 100], + name='deformable_conv_2d_layer', + W_init=tf.truncated_normal_initializer(stddev=0.02), + b_init=tf.constant_initializer(value=0.0), + W_init_args={}, + b_init_args={} + ): + if tf.__version__ < "1.4": + raise Exception("Deformable CNN layer requires tensrflow 1.4 or higher version") + + Layer.__init__(self, name=name) + self.inputs = layer.outputs + self.offset_layer = offset_layer + + print(" [TL] DeformableConv2dLayer %s: shape:%s, act:%s" % + (self.name, str(shape), act.__name__)) + + with tf.variable_scope(name) as vs: + + offset = self.offset_layer.outputs + assert offset.get_shape()[-1] == 2 * shape[0] * shape[1] + + ## Grid initialisation + input_h = int(self.inputs.get_shape()[1]) + input_w = int(self.inputs.get_shape()[2]) + kernel_n = shape[0] * shape[1] + initial_offsets = tf.stack(tf.meshgrid(tf.range(shape[0]), + tf.range(shape[1]), + indexing='ij')) # initial_offsets --> (kh, kw, 2) + initial_offsets = tf.reshape(initial_offsets, (-1, 2)) # initial_offsets --> (n, 2) + initial_offsets = tf.expand_dims(initial_offsets, 0) # initial_offsets --> (1, n, 2) + initial_offsets = tf.expand_dims(initial_offsets, 0) # initial_offsets --> (1, 1, n, 2) + initial_offsets = tf.tile(initial_offsets, [input_h, input_w, 1, 1]) # initial_offsets --> (h, w, n, 2) + initial_offsets = tf.cast(initial_offsets, 'float32') + grid = tf.meshgrid( + tf.range(- int((shape[0] - 1)/2.0), int(input_h - int((shape[0] - 1)/2.0)), 1), + tf.range(- int((shape[1] - 1)/2.0), int(input_w - int((shape[1] - 1)/2.0)), 1), indexing='ij') + + grid = tf.stack(grid, axis=-1) + grid = tf.cast(grid, 'float32') # grid --> (h, w, 2) + grid = tf.expand_dims(grid, 2) # grid --> (h, w, 1, 2) + grid = tf.tile(grid, [1, 1, kernel_n, 1]) # grid --> (h, w, n, 2) + grid_offset = grid + initial_offsets # grid_offset --> (h, w, n, 2) + + input_deform = tf_batch_map_offsets(self.inputs, offset, grid_offset) + + W = tf.get_variable(name='W_conv2d', shape=[1, 1, shape[0] * shape[1], shape[-2], shape[-1]], + initializer=W_init, dtype=D_TYPE, **W_init_args) + b = tf.get_variable(name='b_conv2d', shape=(shape[-1]), + initializer=b_init, dtype=D_TYPE, **b_init_args) + + self.outputs = tf.reshape(act( + tf.nn.conv3d(input_deform, W, strides=[1, 1, 1, 1, 1], padding='VALID', name=None) + b), + (tf.shape(self.inputs)[0], input_h, input_w, shape[-1])) + + ## fixed + self.all_layers = list(layer.all_layers) + self.all_params = list(layer.all_params) + self.all_drop = dict(layer.all_drop) + + ## offset_layer + offset_params = [osparam for osparam in offset_layer.all_params if osparam not in layer.all_params] + offset_layers = [oslayer for oslayer in offset_layer.all_layers if oslayer not in layer.all_layers] + + self.all_params.extend(offset_params) + self.all_layers.extend(offset_layers) + self.all_drop.update(offset_layer.all_drop) + + ## this layer + self.all_layers.extend([self.outputs]) + self.all_params.extend([W, b]) + def AtrousConv1dLayer(net, n_filter=32, filter_size=2, stride=1, dilation=1, act=None, padding='SAME', use_cudnn_on_gpu=None,data_format='NWC', W_init = tf.truncated_normal_initializer(stddev=0.02), @@ -1661,7 +2011,6 @@ def AtrousConv1dLayer(net, n_filter=32, filter_size=2, stride=1, dilation=1, act ) return net - class AtrousConv2dLayer(Layer): """The :class:`AtrousConv2dLayer` class is Atrous convolution (a.k.a. convolution with holes or dilated convolution) 2D layer, see `tf.nn.atrous_conv2d `_. @@ -1696,15 +2045,15 @@ def __init__( ): Layer.__init__(self, name=name) self.inputs = layer.outputs - print(" [TL] AtrousConv2dLayer %s: n_filter:%d filter_size:%s rate:%d pad:%s act:%s" % - (self.name, n_filter, filter_size, rate, padding, act.__name__)) if act is None: act = tf.identity + print(" [TL] AtrousConv2dLayer %s: n_filter:%d filter_size:%s rate:%d pad:%s act:%s" % + (self.name, n_filter, filter_size, rate, padding, act.__name__)) with tf.variable_scope(name) as vs: shape = [filter_size[0], filter_size[1], int(self.inputs.get_shape()[-1]), n_filter] - filters = tf.get_variable(name='filter', shape=shape, initializer=W_init, **W_init_args ) + filters = tf.get_variable(name='filter', shape=shape, initializer=W_init, dtype=D_TYPE, **W_init_args ) if b_init: - b = tf.get_variable(name='b', shape=(n_filter), initializer=b_init, **b_init_args ) + b = tf.get_variable(name='b', shape=(n_filter), initializer=b_init, dtype=D_TYPE, **b_init_args ) self.outputs = act(tf.nn.atrous_conv2d(self.inputs, filters, rate, padding) + b) else: self.outputs = act(tf.nn.atrous_conv2d(self.inputs, filters, rate, padding)) @@ -1792,6 +2141,7 @@ def __init__( self.all_layers.extend( [self.outputs] ) self.all_params.extend( variables ) + ## Initializers for Convuolutional Layers def deconv2d_bilinear_upsampling_initializer(shape): """Returns initializer that can be passed to DeConv2dLayer to initalize the @@ -1851,7 +2201,7 @@ def deconv2d_bilinear_upsampling_initializer(shape): weights[:, :, i, i] = bilinear_kernel #assign numpy array to constant_initalizer and pass to get_variable - bilinear_weights_init = tf.constant_initializer(value=weights, dtype=tf.float32) + bilinear_weights_init = tf.constant_initializer(value=weights, dtype=D_TYPE) #dtype=tf.float32) return bilinear_weights_init ## Convolutional layer (Simplified) @@ -1871,6 +2221,23 @@ def Conv1d(net, n_filter=32, filter_size=5, stride=1, dilation_rate=1, act=None, dilation_rate : As it is 1D conv, the default is "NWC". act : None or activation function. others : see :class:`Conv1dLayer`. + + Examples + --------- + >>> x = tf.placeholder(tf.float32, [batch_size, width]) + >>> y_ = tf.placeholder(tf.int64, shape=[batch_size,]) + >>> n = InputLayer(x, name='in') + >>> n = ReshapeLayer(n, [-1, width, 1], name='rs') + >>> n = Conv1d(n, 64, 3, 1, act=tf.nn.relu, name='c1') + >>> n = MaxPool1d(n, 2, 2, padding='valid', name='m1') + >>> n = Conv1d(n, 128, 3, 1, act=tf.nn.relu, name='c2') + >>> n = MaxPool1d(n, 2, 2, padding='valid', name='m2') + >>> n = Conv1d(n, 128, 3, 1, act=tf.nn.relu, name='c3') + >>> n = MaxPool1d(n, 2, 2, padding='valid', name='m3') + >>> n = FlattenLayer(n, name='f') + >>> n = DenseLayer(n, 500, tf.nn.relu, name='d1') + >>> n = DenseLayer(n, 100, tf.nn.relu, name='d2') + >>> n = DenseLayer(n, 2, tf.identity, name='o') """ if act is None: act = tf.identity @@ -1959,14 +2326,14 @@ def DeConv2d(net, n_out_channel = 32, filter_size=(3, 3), assert len(strides) == 2, "len(strides) should be 2, DeConv2d and DeConv2dLayer are different." if act is None: act = tf.identity - # if batch_size is None: + if batch_size is None: # batch_size = tf.shape(net.outputs)[0] - fixed_batch_size = net.outputs.get_shape().with_rank_at_least(1)[0] - if fixed_batch_size.value: - batch_size = fixed_batch_size.value - else: - from tensorflow.python.ops import array_ops - batch_size = array_ops.shape(net.outputs)[0] + fixed_batch_size = net.outputs.get_shape().with_rank_at_least(1)[0] + if fixed_batch_size.value: + batch_size = fixed_batch_size.value + else: + from tensorflow.python.ops import array_ops + batch_size = array_ops.shape(net.outputs)[0] net = DeConv2dLayer(layer = net, act = act, shape = [filter_size[0], filter_size[1], n_out_channel, int(net.outputs.get_shape()[-1])], @@ -2112,10 +2479,108 @@ def MeanPool3d(net, filter_size, strides, padding='valid', data_format='channels net_new.all_layers.extend( [outputs] ) return net_new +class DepthwiseConv2d(Layer): + """Separable/Depthwise Convolutional 2D, see `tf.nn.depthwise_conv2d `_. + + Input: + 4-D Tensor [batch, height, width, in_channels]. + Output: + 4-D Tensor [batch, new height, new width, in_channels * channel_multiplier]. + + Parameters + ------------ + net : TensorLayer layer. + channel_multiplier : int, The number of channels to expand to. + filter_size : tuple (height, width) for filter size. + strides : tuple (height, width) for strides. + act : None or activation function. + padding : a string from: "SAME", "VALID". + The type of padding algorithm to use. + W_init : weights initializer + The initializer for initializing the weight matrix. + b_init : biases initializer or None + The initializer for initializing the bias vector. If None, skip biases. + W_init_args : dictionary + The arguments for the weights tf.get_variable(). + b_init_args : dictionary + The arguments for the biases tf.get_variable(). + name : a string or None + An optional name to attach to this layer. + + Examples + --------- + >>> t_im = tf.placeholder("float32", [None, 256, 256, 3]) + >>> net = InputLayer(t_im, name='in') + >>> net = DepthwiseConv2d(net, 32, (3, 3), (1, 1, 1, 1), tf.nn.relu, padding="SAME", name='dep') + >>> print(net.outputs.get_shape()) + ... (?, 256, 256, 96) + + References + ----------- + - tflearn's `grouped_conv_2d `_ + - keras's `separableconv2d `_ + """ + def __init__( + self, + layer = None, + # n_filter = 32, + channel_multiplier = 3, + shape = (3, 3), + strides = (1, 1), + act = None, + padding='SAME', + W_init = tf.truncated_normal_initializer(stddev=0.02), + b_init = tf.constant_initializer(value=0.0), + W_init_args = {}, + b_init_args = {}, + name ='depthwise_conv2d', + ): + Layer.__init__(self, name=name) + self.inputs = layer.outputs + + if act is None: + act = tf.identity + + print(" [TL] DepthwiseConv2d %s: shape:%s strides:%s pad:%s act:%s" % + (self.name, str(shape), str(strides), padding, act.__name__)) + + if act is None: + act = tf.identity + + try: + pre_channel = int(layer.outputs.get_shape()[-1]) + except: # if pre_channel is ?, it happens when using Spatial Transformer Net + pre_channel = 1 + print("[warnings] unknow input channels, set to 1") + + shape = [shape[0], shape[1], pre_channel, channel_multiplier] + + if len(strides) == 2: + strides = [1, strides[0], strides[1], 1] + + assert len(strides) == 4, "len(strides) should be 4." + + with tf.variable_scope(name) as vs: + W = tf.get_variable(name='W_sepconv2d', shape=shape, initializer=W_init, dtype=D_TYPE, **W_init_args ) # [filter_height, filter_width, in_channels, channel_multiplier] + if b_init: + b = tf.get_variable(name='b_sepconv2d', shape=(pre_channel*channel_multiplier), initializer=b_init, dtype=D_TYPE, **b_init_args ) + self.outputs = act( tf.nn.depthwise_conv2d(self.inputs, W, strides=strides, padding=padding) + b ) + else: + self.outputs = act( tf.nn.depthwise_conv2d(self.inputs, W, strides=strides, padding=padding) ) + + self.all_layers = list(layer.all_layers) + self.all_params = list(layer.all_params) + self.all_drop = dict(layer.all_drop) + self.all_layers.extend( [self.outputs] ) + if b_init: + self.all_params.extend( [W, b] ) + else: + self.all_params.extend( [W] ) + ## Super resolution def SubpixelConv2d(net, scale=2, n_out_channel=None, act=tf.identity, name='subpixel_conv2d'): - """The :class:`SubpixelConv2d` class is a sub-pixel 2d convolutional ayer, usually be used - for Super-Resolution applications, `example code `_. + """It is a sub-pixel 2d upsampling layer, usually be used + for Super-Resolution applications, see `example code `_. Parameters ------------ @@ -2165,16 +2630,21 @@ def SubpixelConv2d(net, scale=2, n_out_channel=None, act=tf.identity, name='subp scope_name = tf.get_variable_scope().name if scope_name: - name = scope_name + '/' + name + whole_name = scope_name + '/' + name + else: + whole_name = name def _PS(X, r, n_out_channel): if n_out_channel >= 1: assert int(X.get_shape()[-1]) == (r ** 2) * n_out_channel, _err_log + ''' bsize, a, b, c = X.get_shape().as_list() bsize = tf.shape(X)[0] # Handling Dimension(None) type for undefined batch dim Xs=tf.split(X,r,3) #b*h*w*r*r Xr=tf.concat(Xs,2) #b*h*(r*w)*r X=tf.reshape(Xr,(bsize,r*a,r*b,n_out_channel)) # b*(r*h)*(r*w)*c + ''' + X=tf.depth_to_space(X,r) else: print(_err_log) return X @@ -2187,7 +2657,7 @@ def _PS(X, r, n_out_channel): print(" [TL] SubpixelConv2d %s: scale: %d n_out_channel: %s act: %s" % (name, scale, n_out_channel, act.__name__)) - net_new = Layer(inputs, name=name) + net_new = Layer(inputs, name=whole_name) # with tf.name_scope(name): with tf.variable_scope(name) as vs: net_new.outputs = act(_PS(inputs, r=scale, n_out_channel=n_out_channel)) @@ -2199,7 +2669,7 @@ def _PS(X, r, n_out_channel): return net_new def SubpixelConv2d_old(net, scale=2, n_out_channel=None, act=tf.identity, name='subpixel_conv2d'): - """The :class:`SubpixelConv2d` class is a sub-pixel 2d convolutional ayer, usually be used + """It is a sub-pixel 2d upsampling layer, usually be used for Super-Resolution applications, `example code `_. Parameters @@ -2252,31 +2722,12 @@ def SubpixelConv2d_old(net, scale=2, n_out_channel=None, act=tf.identity, name=' if scope_name: name = scope_name + '/' + name - def _phase_shift(I, r): - if tf.__version__ < '1.0': - raise Exception("Only support TF1.0+") - bsize, a, b, c = I.get_shape().as_list() - bsize = tf.shape(I)[0] # Handling Dimension(None) type for undefined batch dim - X = tf.reshape(I, (bsize, a, b, r, r)) - X = tf.transpose(X, (0, 1, 2, 4, 3)) # bsize, a, b, 1, 1 # tf 0.12 - # X = tf.split(1, a, X) # a, [bsize, b, r, r] # tf 0.12 - X = tf.split(X, a, 1) - # X = tf.concat(2, [tf.squeeze(x, axis=1) for x in X]) # bsize, b, a*r, r # tf 0.12 - X = tf.concat([tf.squeeze(x, axis=1) for x in X], 2) - # X = tf.split(1, b, X) # b, [bsize, a*r, r] # tf 0.12 - X = tf.split(X, b, 1) - # X = tf.concat(2, [tf.squeeze(x, axis=1) for x in X]) # bsize, a*r, b*r # tf 0.12 - X = tf.concat([tf.squeeze(x, axis=1) for x in X], 2) - return tf.reshape(X, (bsize, a*r, b*r, 1)) - def _PS(X, r, n_out_channel): if n_out_channel > 1: assert int(X.get_shape()[-1]) == (r ** 2) * n_out_channel, _err_log - Xc = tf.split(X, n_out_channel, 3) - X = tf.concat([_phase_shift(x, r) for x in Xc], 3) - elif n_out_channel == 1: - assert int(X.get_shape()[-1]) == (r ** 2), _err_log - X = _phase_shift(X, r) + X=tf.transpose(X,[0,2,1,3]) + X=tf.depth_to_space(X,r) + X=tf.transpose(X,[0,2,1,3]) else: print(_err_log) return X @@ -2301,7 +2752,49 @@ def _PS(X, r, n_out_channel): return net_new +def SubpixelConv1d(net, scale=2, act=tf.identity, name='subpixel_conv1d'): + """One-dimensional subpixel upsampling layer. + Calls a tensorflow function that directly implements this functionality. + We assume input has dim (batch, width, r) + + Parameters + ------------ + net : TensorLayer layer. + scale : int, upscaling ratio, a wrong setting will lead to Dimension size error. + act : activation function. + name : string. + An optional name to attach to this layer. + + Examples + ---------- + >>> t_signal = tf.placeholder('float32', [10, 100, 4], name='x') + >>> n = InputLayer(t_signal, name='in') + >>> n = SubpixelConv1d(n, scale=2, name='s') + >>> print(n.outputs.shape) + ... (10, 200, 2) + + References + ----------- + - `Audio Super Resolution Implementation `_. + """ + def _PS(I, r): + X = tf.transpose(I, [2,1,0]) # (r, w, b) + X = tf.batch_to_space_nd(X, [r], [[0,0]]) # (1, r*w, b) + X = tf.transpose(X, [2,1,0]) + return X + + print(" [TL] SubpixelConv1d %s: scale: %d act: %s" % (name, scale, act.__name__)) + inputs = net.outputs + net_new = Layer(inputs, name=name) + with tf.name_scope(name): + net_new.outputs = act(_PS(inputs, r=scale)) + + net_new.all_layers = list(net.all_layers) + net_new.all_params = list(net.all_params) + net_new.all_drop = dict(net.all_drop) + net_new.all_layers.extend( [net_new.outputs] ) + return net_new ## Spatial Transformer Nets def transformer(U, theta, out_size, name='SpatialTransformer2dAffine', **kwargs): @@ -2521,10 +3014,10 @@ def __init__( # 2.1 W n_in = int(self.theta_layer.outputs.get_shape()[-1]) shape = (n_in, 6) - W = tf.get_variable(name='W', initializer=tf.zeros(shape)) + W = tf.get_variable(name='W', initializer=tf.zeros(shape), dtype=D_TYPE) # 2.2 b identity = tf.constant(np.array([[1., 0, 0], [0, 1., 0]]).astype('float32').flatten()) - b = tf.get_variable(name='b', initializer=identity) + b = tf.get_variable(name='b', initializer=identity, dtype=D_TYPE) # 2.3 transformation matrix self.theta = tf.nn.tanh(tf.matmul(self.theta_layer.outputs, W) + b) ## 3. Spatial Transformer Sampling @@ -2620,6 +3113,7 @@ class BatchNormLayer(Layer): The initializer for initializing beta gamma_init : gamma initializer The initializer for initializing gamma + dtype : tf.float32 (default) or tf.float16 name : a string or None An optional name to attach to this layer. @@ -2637,6 +3131,7 @@ def __init__( is_train = False, beta_init = tf.zeros_initializer, gamma_init = tf.random_normal_initializer(mean=1.0, stddev=0.002), # tf.ones_initializer, + # dtype = tf.float32, name ='batchnorm_layer', ): Layer.__init__(self, name=name) @@ -2657,10 +3152,13 @@ def __init__( beta_init = beta_init() beta = tf.get_variable('beta', shape=params_shape, initializer=beta_init, + dtype=D_TYPE, trainable=is_train)#, restore=restore) gamma = tf.get_variable('gamma', shape=params_shape, - initializer=gamma_init, trainable=is_train, + initializer=gamma_init, + dtype=D_TYPE, + trainable=is_train, )#restore=restore) ## 2. @@ -2671,10 +3169,12 @@ def __init__( moving_mean = tf.get_variable('moving_mean', params_shape, initializer=moving_mean_init, - trainable=False,)# restore=restore) + dtype=D_TYPE, + trainable=False)# restore=restore) moving_variance = tf.get_variable('moving_variance', params_shape, initializer=tf.constant_initializer(1.), + dtype=D_TYPE, trainable=False,)# restore=restore) ## 3. @@ -3431,29 +3931,130 @@ def mean_var_with_update(): # self.all_layers.extend( [self.outputs] ) # self.all_params.extend( [beta, gamma] ) -## Pooling layer -class PoolLayer(Layer): - """ - The :class:`PoolLayer` class is a Pooling layer, you can choose - ``tf.nn.max_pool`` and ``tf.nn.avg_pool`` for 2D or - ``tf.nn.max_pool3d`` and ``tf.nn.avg_pool3d`` for 3D. +class InstanceNormLayer(Layer): + """The :class:`InstanceNormLayer` class is a for instance normalization. Parameters - ---------- + ----------- layer : a :class:`Layer` instance The `Layer` class feeding into this layer. - ksize : a list of ints that has length >= 4. - The size of the window for each dimension of the input tensor. - strides : a list of ints that has length >= 4. - The stride of the sliding window for each dimension of the input tensor. - padding : a string from: "SAME", "VALID". - The type of padding algorithm to use. - pool : a pooling function - - see `TensorFlow pooling APIs `_ - - class ``tf.nn.max_pool`` - - class ``tf.nn.avg_pool`` - - class ``tf.nn.max_pool3d`` - - class ``tf.nn.avg_pool3d`` + act : activation function. + epsilon : float + A small float number. + scale_init : beta initializer + The initializer for initializing beta + offset_init : gamma initializer + The initializer for initializing gamma + name : a string or None + An optional name to attach to this layer. + """ + def __init__( + self, + layer = None, + act = tf.identity, + epsilon = 1e-5, + scale_init = tf.truncated_normal_initializer(mean=1.0, stddev=0.02), + offset_init = tf.constant_initializer(0.0), + name ='instan_norm', + ): + Layer.__init__(self, name=name) + self.inputs = layer.outputs + print(" [TL] InstanceNormLayer %s: epsilon:%f act:%s" % + (self.name, epsilon, act.__name__)) + + with tf.variable_scope(name) as vs: + mean, var = tf.nn.moments(self.inputs, [1, 2], keep_dims=True) + scale = tf.get_variable('scale',[self.inputs.get_shape()[-1]], + initializer=tf.truncated_normal_initializer(mean=1.0, stddev=0.02), dtype=D_TYPE) + offset = tf.get_variable('offset',[self.inputs.get_shape()[-1]], + initializer=tf.constant_initializer(0.0), dtype=D_TYPE) + self.outputs = scale * tf.div(self.inputs-mean, tf.sqrt(var+epsilon)) + offset + self.outputs = act(self.outputs) + variables = tf.get_collection(TF_GRAPHKEYS_VARIABLES, scope=vs.name) + + self.all_layers = list(layer.all_layers) + self.all_params = list(layer.all_params) + self.all_drop = dict(layer.all_drop) + self.all_layers.extend( [self.outputs] ) + self.all_params.extend( variables ) + +class LayerNormLayer(Layer): + """ + The :class:`LayerNormLayer` class is for layer normalization, see `tf.contrib.layers.layer_norm `_. + + Parameters + ---------- + layer : a :class:`Layer` instance + The `Layer` class feeding into this layer. + act : activation function + The function that is applied to the layer activations. + others : see `tf.contrib.layers.layer_norm `_ + """ + def __init__(self, + layer=None, + center=True, + scale=True, + act=tf.identity, + reuse=None, + variables_collections=None, + outputs_collections=None, + trainable=True, + begin_norm_axis=1, + begin_params_axis=-1, + name='layernorm' + ): + + if tf.__version__ < "1.3": + raise Exception("Please use TF 1.3+") + + Layer.__init__(self, name=name) + self.inputs = layer.outputs + print(" [TL] LayerNormLayer %s: act:%s" % + (self.name, act.__name__)) + with tf.variable_scope(name) as vs: + self.outputs = tf.contrib.layers.layer_norm(self.inputs, + center=center, + scale=scale, + activation_fn=act, + reuse=reuse, + variables_collections=variables_collections, + outputs_collections=outputs_collections, + trainable=trainable, + begin_norm_axis=begin_norm_axis, + begin_params_axis=begin_params_axis, + scope='var', + ) + variables = tf.get_collection(TF_GRAPHKEYS_VARIABLES, scope=vs.name) + + self.all_layers = list(layer.all_layers) + self.all_params = list(layer.all_params) + self.all_drop = dict(layer.all_drop) + self.all_layers.extend( [self.outputs] ) + self.all_params.extend( variables ) + +## Pooling layer +class PoolLayer(Layer): + """ + The :class:`PoolLayer` class is a Pooling layer, you can choose + ``tf.nn.max_pool`` and ``tf.nn.avg_pool`` for 2D or + ``tf.nn.max_pool3d`` and ``tf.nn.avg_pool3d`` for 3D. + + Parameters + ---------- + layer : a :class:`Layer` instance + The `Layer` class feeding into this layer. + ksize : a list of ints that has length >= 4. + The size of the window for each dimension of the input tensor. + strides : a list of ints that has length >= 4. + The stride of the sliding window for each dimension of the input tensor. + padding : a string from: "SAME", "VALID". + The type of padding algorithm to use. + pool : a pooling function + - see `TensorFlow pooling APIs `_ + - class ``tf.nn.max_pool`` + - class ``tf.nn.avg_pool`` + - class ``tf.nn.max_pool3d`` + - class ``tf.nn.avg_pool3d`` name : a string or None An optional name to attach to this layer. @@ -3508,7 +4109,7 @@ def __init__( assert paddings is not None, "paddings should be a Tensor of type int32. see https://www.tensorflow.org/api_docs/python/tf/pad" self.inputs = layer.outputs print(" [TL] PadLayer %s: paddings:%s mode:%s" % - (self.name, list(paddings.get_shape()), mode)) + (self.name, list(paddings), mode)) self.outputs = tf.pad(self.inputs, paddings=paddings, mode=mode, name=name) @@ -3517,6 +4118,49 @@ def __init__( self.all_drop = dict(layer.all_drop) self.all_layers.extend( [self.outputs] ) +## Object Detection +class ROIPoolingLayer(Layer): + """ + The :class:`ROIPoolingLayer` class is Region of interest pooling layer. + + Parameters + ----------- + layer : a :class:`Layer` instance + The `Layer` class feeding into this layer, the feature maps on which to perform the pooling operation + rois : list of regions of interest in the format (feature map index, upper left, bottom right) + pool_width : int, size of the pooling sections. + pool_width : int, size of the pooling sections. + + Notes + ----------- + - This implementation is from `Deepsense-AI `_ . + - Please install it by the instruction `HERE `_. + """ + def __init__( + self, + #inputs = None, + layer = None, + rois = None, + pool_height = 2, + pool_width = 2, + name = 'roipooling_layer', + ): + Layer.__init__(self, name=name) + self.inputs = layer.outputs + print (" [TL] ROIPoolingLayer %s: (%d, %d)" % (self.name, pool_height, pool_width)) + try: + from tensorlayer.third_party.roi_pooling.roi_pooling.roi_pooling_ops import roi_pooling + except Exception as e: + print(e) + print("\nHINT: \n1. https://github.com/deepsense-ai/roi-pooling \n2. tensorlayer/third_party/roi_pooling\n") + self.outputs = roi_pooling(self.inputs, rois, pool_height, pool_width) + + self.all_layers = list(layer.all_layers) + self.all_params = list(layer.all_params) + self.all_drop = dict(layer.all_drop) + self.all_layers.extend( [self.outputs] ) + + ## TimeDistributedLayer class TimeDistributedLayer(Layer): """ @@ -3576,8 +4220,8 @@ def __init__( with ops.suppress_stdout(): for i in range(0, timestep): - with tf.variable_scope(name, reuse=(False if i==0 else True)) as vs: - set_name_reuse((False if i==0 else True)) + with tf.variable_scope(name, reuse=(set_keep['name_reuse'] if i==0 else True)) as vs: + set_name_reuse((set_keep['name_reuse'] if i==0 else True)) net = layer_class(InputLayer(x[i], name=args['name']+str(i)), **args) # net = layer_class(InputLayer(x[i], name="input_"+args['name']), **args) x[i] = net.outputs @@ -3607,11 +4251,11 @@ class RNNLayer(Layer): - see `RNN Cells in TensorFlow `_ cell_init_args : a dictionary The arguments for the cell initializer. - n_hidden : a int + n_hidden : an int The number of hidden units in the layer. initializer : initializer The initializer for initializing the parameters. - n_steps : a int + n_steps : an int The sequence length. initial_state : None or RNN State If None, initial_state is zero_state. @@ -3626,7 +4270,7 @@ class RNNLayer(Layer): name : a string or None An optional name to attach to this layer. - Variables + Attributes -------------- outputs : a tensor The output of this RNN. @@ -3652,27 +4296,25 @@ class RNNLayer(Layer): -------- - For words >>> input_data = tf.placeholder(tf.int32, [batch_size, num_steps]) - >>> network = tl.layers.EmbeddingInputlayer( + >>> net = tl.layers.EmbeddingInputlayer( ... inputs = input_data, ... vocabulary_size = vocab_size, ... embedding_size = hidden_size, ... E_init = tf.random_uniform_initializer(-init_scale, init_scale), ... name ='embedding_layer') - >>> if is_training: - >>> network = tl.layers.DropoutLayer(network, keep=keep_prob, name='drop1') - >>> network = tl.layers.RNNLayer(network, - ... cell_fn=tf.nn.rnn_cell.BasicLSTMCell, + >>> net = tl.layers.DropoutLayer(net, keep=keep_prob, is_fix=True, is_train=is_train, name='drop1') + >>> net = tl.layers.RNNLayer(net, + ... cell_fn=tf.contrib.rnn.BasicLSTMCell, ... cell_init_args={'forget_bias': 0.0},# 'state_is_tuple': True}, ... n_hidden=hidden_size, ... initializer=tf.random_uniform_initializer(-init_scale, init_scale), ... n_steps=num_steps, ... return_last=False, ... name='basic_lstm_layer1') - >>> lstm1 = network - >>> if is_training: - >>> network = tl.layers.DropoutLayer(network, keep=keep_prob, name='drop2') - >>> network = tl.layers.RNNLayer(network, - ... cell_fn=tf.nn.rnn_cell.BasicLSTMCell, + >>> lstm1 = net + >>> net = tl.layers.DropoutLayer(net, keep=keep_prob, is_fix=True, is_train=is_train, name='drop2') + >>> net = tl.layers.RNNLayer(net, + ... cell_fn=tf.contrib.rnn.BasicLSTMCell, ... cell_init_args={'forget_bias': 0.0}, # 'state_is_tuple': True}, ... n_hidden=hidden_size, ... initializer=tf.random_uniform_initializer(-init_scale, init_scale), @@ -3680,10 +4322,9 @@ class RNNLayer(Layer): ... return_last=False, ... return_seq_2d=True, ... name='basic_lstm_layer2') - >>> lstm2 = network - >>> if is_training: - >>> network = tl.layers.DropoutLayer(network, keep=keep_prob, name='drop3') - >>> network = tl.layers.DenseLayer(network, + >>> lstm2 = net + >>> net = tl.layers.DropoutLayer(net, keep=keep_prob, is_fix=True, is_train=is_train, name='drop3') + >>> net = tl.layers.DenseLayer(net, ... n_units=vocab_size, ... W_init=tf.random_uniform_initializer(-init_scale, init_scale), ... b_init=tf.random_uniform_initializer(-init_scale, init_scale), @@ -3691,34 +4332,34 @@ class RNNLayer(Layer): - For CNN+LSTM >>> x = tf.placeholder(tf.float32, shape=[batch_size, image_size, image_size, 1]) - >>> network = tl.layers.InputLayer(x, name='input_layer') - >>> network = tl.layers.Conv2dLayer(network, + >>> net = tl.layers.InputLayer(x, name='input_layer') + >>> net = tl.layers.Conv2dLayer(net, ... act = tf.nn.relu, ... shape = [5, 5, 1, 32], # 32 features for each 5x5 patch ... strides=[1, 2, 2, 1], ... padding='SAME', ... name ='cnn_layer1') - >>> network = tl.layers.PoolLayer(network, + >>> net = tl.layers.PoolLayer(net, ... ksize=[1, 2, 2, 1], ... strides=[1, 2, 2, 1], ... padding='SAME', ... pool = tf.nn.max_pool, ... name ='pool_layer1') - >>> network = tl.layers.Conv2dLayer(network, + >>> net = tl.layers.Conv2dLayer(net, ... act = tf.nn.relu, ... shape = [5, 5, 32, 10], # 10 features for each 5x5 patch ... strides=[1, 2, 2, 1], ... padding='SAME', ... name ='cnn_layer2') - >>> network = tl.layers.PoolLayer(network, + >>> net = tl.layers.PoolLayer(net, ... ksize=[1, 2, 2, 1], ... strides=[1, 2, 2, 1], ... padding='SAME', ... pool = tf.nn.max_pool, ... name ='pool_layer2') - >>> network = tl.layers.FlattenLayer(network, name='flatten_layer') - >>> network = tl.layers.ReshapeLayer(network, shape=[-1, num_steps, int(network.outputs._shape[-1])]) - >>> rnn1 = tl.layers.RNNLayer(network, + >>> net = tl.layers.FlattenLayer(net, name='flatten_layer') + >>> net = tl.layers.ReshapeLayer(net, shape=[-1, num_steps, int(net.outputs._shape[-1])]) + >>> rnn1 = tl.layers.RNNLayer(net, ... cell_fn=tf.nn.rnn_cell.LSTMCell, ... cell_init_args={}, ... n_hidden=200, @@ -3727,7 +4368,7 @@ class RNNLayer(Layer): ... return_last=False, ... return_seq_2d=True, ... name='rnn_layer') - >>> network = tl.layers.DenseLayer(rnn1, n_units=3, + >>> net = tl.layers.DenseLayer(rnn1, n_units=3, ... act = tl.activation.identity, name='output_layer') Notes @@ -3814,7 +4455,7 @@ def __init__( else: self.cell = cell = cell_fn(num_units=n_hidden, **cell_init_args) if initial_state is None: - self.initial_state = cell.zero_state(batch_size, dtype=tf.float32) # 1.2.3 + self.initial_state = cell.zero_state(batch_size, dtype=D_TYPE) #dtype=tf.float32) # 1.2.3 state = self.initial_state # with tf.variable_scope("model", reuse=None, initializer=initializer): with tf.variable_scope(name, initializer=initializer) as vs: @@ -3871,11 +4512,11 @@ class BiRNNLayer(Layer): - see `RNN Cells in TensorFlow `_ cell_init_args : a dictionary The arguments for the cell initializer. - n_hidden : a int + n_hidden : an int The number of hidden units in the layer. initializer : initializer The initializer for initializing the parameters. - n_steps : a int + n_steps : an int The sequence length. fw_initial_state : None or forward RNN State If None, initial_state is zero_state. @@ -3883,7 +4524,7 @@ class BiRNNLayer(Layer): If None, initial_state is zero_state. dropout : `tuple` of `float`: (input_keep_prob, output_keep_prob). The input and output keep probability. - n_layer : a int, default is 1. + n_layer : an int, default is 1. The number of RNN layers. return_last : boolean - If True, return the last output, "Sequence input and single output" @@ -3896,7 +4537,7 @@ class BiRNNLayer(Layer): name : a string or None An optional name to attach to this layer. - Variables + Attributes -------------- outputs : a tensor The output of this RNN. @@ -4014,11 +4655,11 @@ def __init__( # Initial state of RNN if fw_initial_state is None: - self.fw_initial_state = self.fw_cell.zero_state(self.batch_size, dtype=tf.float32) + self.fw_initial_state = self.fw_cell.zero_state(self.batch_size, dtype=D_TYPE) # dtype=tf.float32) else: self.fw_initial_state = fw_initial_state if bw_initial_state is None: - self.bw_initial_state = self.bw_cell.zero_state(self.batch_size, dtype=tf.float32) + self.bw_initial_state = self.bw_cell.zero_state(self.batch_size, dtype=D_TYPE) # dtype=tf.float32) else: self.bw_initial_state = bw_initial_state # exit() @@ -4041,6 +4682,7 @@ def __init__( ) if return_last: + raise Exception("Do not support return_last at the moment.") self.outputs = outputs[-1] else: self.outputs = outputs @@ -4072,6 +4714,300 @@ def __init__( self.all_layers.extend( [self.outputs] ) self.all_params.extend( rnn_variables ) + +# ConvLSTM layer +class ConvRNNCell(object): + """Abstract object representing an Convolutional RNN Cell. + """ + + def __call__(self, inputs, state, scope=None): + """Run this RNN cell on inputs, starting from the given state. + """ + raise NotImplementedError("Abstract method") + + @property + def state_size(self): + """size(s) of state(s) used by this cell. + """ + raise NotImplementedError("Abstract method") + + @property + def output_size(self): + """Integer or TensorShape: size of outputs produced by this cell.""" + raise NotImplementedError("Abstract method") + + def zero_state(self, batch_size, dtype): + """Return zero-filled state tensor(s). + Args: + batch_size: int, float, or unit Tensor representing the batch size. + dtype: the data type to use for the state. + Returns: + tensor of shape '[batch_size x shape[0] x shape[1] x num_features] + filled with zeros + """ + + shape = self.shape + num_features = self.num_features + zeros = tf.zeros([batch_size, shape[0], shape[1], num_features * 2]) + return zeros + +class BasicConvLSTMCell(ConvRNNCell): + """Basic Conv LSTM recurrent network cell. + + Parameters + ----------- + shape : int tuple thats the height and width of the cell + filter_size : int tuple thats the height and width of the filter + num_features : int thats the depth of the cell + forget_bias : float, The bias added to forget gates (see above). + input_size : Deprecated and unused. + state_is_tuple : If True, accepted and returned states are 2-tuples of + the `c_state` and `m_state`. If False, they are concatenated + along the column axis. The latter behavior will soon be deprecated. + activation : Activation function of the inner states. + """ + def __init__(self, shape, filter_size, num_features, forget_bias=1.0, input_size=None, + state_is_tuple=False, activation=tf.nn.tanh): + """Initialize the basic Conv LSTM cell. + """ + # if not state_is_tuple: + # logging.warn("%s: Using a concatenated state is slower and will soon be " + # "deprecated. Use state_is_tuple=True.", self) + if input_size is not None: + logging.warn("%s: The input_size parameter is deprecated.", self) + self.shape = shape + self.filter_size = filter_size + self.num_features = num_features + self._forget_bias = forget_bias + self._state_is_tuple = state_is_tuple + self._activation = activation + + @property + def state_size(self): + """ State size of the LSTMStateTuple. """ + return (LSTMStateTuple(self._num_units, self._num_units) + if self._state_is_tuple else 2 * self._num_units) + + @property + def output_size(self): + """ Number of units in outputs. """ + return self._num_units + + def __call__(self, inputs, state, scope=None): + """Long short-term memory cell (LSTM).""" + with tf.variable_scope(scope or type(self).__name__): # "BasicLSTMCell" + # Parameters of gates are concatenated into one multiply for efficiency. + if self._state_is_tuple: + c, h = state + else: + # print state + # c, h = tf.split(3, 2, state) + c, h = tf.split(state, 2, 3) + concat = _conv_linear([inputs, h], self.filter_size, self.num_features * 4, True) + + # i = input_gate, j = new_input, f = forget_gate, o = output_gate + # i, j, f, o = tf.split(3, 4, concat) + i, j, f, o = tf.split(concat, 4, 3) + + new_c = (c * tf.nn.sigmoid(f + self._forget_bias) + tf.nn.sigmoid(i) * + self._activation(j)) + new_h = self._activation(new_c) * tf.nn.sigmoid(o) + + if self._state_is_tuple: + new_state = LSTMStateTuple(new_c, new_h) + else: + new_state = tf.concat([new_c, new_h], 3) + return new_h, new_state + +def _conv_linear(args, filter_size, num_features, bias, bias_start=0.0, scope=None): + """convolution: + + Parameters + ---------- + args: a 4D Tensor or a list of 4D, batch x n, Tensors. + filter_size: int tuple of filter height and width. + num_features: int, number of features. + bias_start: starting value to initialize the bias; 0 by default. + scope: VariableScope for the created subgraph; defaults to "Linear". + + Returns + -------- + - A 4D Tensor with shape [batch h w num_features] + + Raises + ------- + - ValueError : if some of the arguments has unspecified or wrong shape. + """ + + # Calculate the total size of arguments on dimension 1. + total_arg_size_depth = 0 + shapes = [a.get_shape().as_list() for a in args] + for shape in shapes: + if len(shape) != 4: + raise ValueError("Linear is expecting 4D arguments: %s" % str(shapes)) + if not shape[3]: + raise ValueError("Linear expects shape[4] of arguments: %s" % str(shapes)) + else: + total_arg_size_depth += shape[3] + + dtype = [a.dtype for a in args][0] + + # Now the computation. + with tf.variable_scope(scope or "Conv"): + matrix = tf.get_variable( + "Matrix", [filter_size[0], filter_size[1], total_arg_size_depth, num_features], dtype=dtype) + if len(args) == 1: + res = tf.nn.conv2d(args[0], matrix, strides=[1, 1, 1, 1], padding='SAME') + else: + res = tf.nn.conv2d(tf.concat(args, 3), matrix, strides=[1, 1, 1, 1], padding='SAME') + if not bias: + return res + bias_term = tf.get_variable( + "Bias", [num_features], + dtype=dtype, + initializer=tf.constant_initializer( + bias_start, dtype=dtype)) + return res + bias_term + +class ConvLSTMLayer(Layer): + """ + The :class:`ConvLSTMLayer` class is a Convolutional LSTM layer, + see `Convolutional LSTM Layer `_ . + + Parameters + ---------- + layer : a :class:`Layer` instance + The `Layer` class feeding into this layer. + cell_shape : tuple, the shape of each cell width*height + filter_size : tuple, the size of filter width*height + cell_fn : a Convolutional RNN cell as follow. + feature_map : a int + The number of feature map in the layer. + initializer : initializer + The initializer for initializing the parameters. + n_steps : a int + The sequence length. + initial_state : None or ConvLSTM State + If None, initial_state is zero_state. + return_last : boolen + - If True, return the last output, "Sequence input and single output" + - If False, return all outputs, "Synced sequence input and output" + - In other word, if you want to apply one or more ConvLSTM(s) on this layer, set to False. + return_seq_2d : boolen + - When return_last = False + - If True, return 4D Tensor [n_example, h, w, c], for stacking DenseLayer after it. + - If False, return 5D Tensor [n_example/n_steps, h, w, c], for stacking multiple ConvLSTM after it. + name : a string or None + An optional name to attach to this layer. + + Variables + -------------- + outputs : a tensor + The output of this RNN. + return_last = False, outputs = all cell_output, which is the hidden state. + cell_output.get_shape() = (?, h, w, c]) + + final_state : a tensor or StateTuple + When state_is_tuple = False, + it is the final hidden and cell states, + When state_is_tuple = True, + You can get the final state after each iteration during training, then + feed it to the initial state of next iteration. + + initial_state : a tensor or StateTuple + It is the initial state of this ConvLSTM layer, you can use it to initialize + your state at the begining of each epoch or iteration according to your + training procedure. + + batch_size : int or tensor + Is int, if able to compute the batch_size, otherwise, tensor for ``?``. + """ + def __init__( + self, + layer=None, + cell_shape=None, + feature_map=1, + filter_size=(3, 3), + cell_fn=BasicConvLSTMCell, + initializer=tf.random_uniform_initializer(-0.1, 0.1), + n_steps=5, + initial_state=None, + return_last=False, + return_seq_2d=False, + name='convlstm_layer', + ): + Layer.__init__(self, name=name) + self.inputs = layer.outputs + print(" [TL] ConvLSTMLayer %s: feature_map:%d, n_steps:%d, " + "in_dim:%d %s, cell_fn:%s " % (self.name, feature_map, + n_steps, self.inputs.get_shape().ndims, self.inputs.get_shape(), + cell_fn.__name__)) + # You can get the dimension by .get_shape() or ._shape, and check the + # dimension by .with_rank() as follow. + # self.inputs.get_shape().with_rank(2) + # self.inputs.get_shape().with_rank(3) + + # Input dimension should be rank 5 [batch_size, n_steps(max), h, w, c] + try: + self.inputs.get_shape().with_rank(5) + except: + raise Exception("RNN : Input dimension should be rank 5 : [batch_size, n_steps, input_x, " + "input_y, feature_map]") + + fixed_batch_size = self.inputs.get_shape().with_rank_at_least(1)[0] + + if fixed_batch_size.value: + batch_size = fixed_batch_size.value + print(" RNN batch_size (concurrent processes): %d" % batch_size) + else: + from tensorflow.python.ops import array_ops + batch_size = array_ops.shape(self.inputs)[0] + print(" non specified batch_size, uses a tensor instead.") + self.batch_size = batch_size + + + outputs = [] + self.cell = cell = cell_fn(shape=cell_shape, filter_size=filter_size, num_features=feature_map) + if initial_state is None: + self.initial_state = cell.zero_state(batch_size, dtype=D_TYPE) # dtype=tf.float32) # 1.2.3 + state = self.initial_state + # with tf.variable_scope("model", reuse=None, initializer=initializer): + with tf.variable_scope(name, initializer=initializer) as vs: + for time_step in range(n_steps): + if time_step > 0: tf.get_variable_scope().reuse_variables() + (cell_output, state) = cell(self.inputs[:, time_step, :, :, :], state) + outputs.append(cell_output) + + # Retrieve just the RNN variables. + # rnn_variables = [v for v in tf.all_variables() if v.name.startswith(vs.name)] + rnn_variables = tf.get_collection(tf.GraphKeys.VARIABLES, scope=vs.name) + + print(" n_params : %d" % (len(rnn_variables))) + + if return_last: + # 2D Tensor [batch_size, n_hidden] + self.outputs = outputs[-1] + else: + if return_seq_2d: + # PTB tutorial: stack dense layer after that, or compute the cost from the output + # 4D Tensor [n_example, h, w, c] + self.outputs = tf.reshape(tf.concat(outputs, 1), [-1, cell_shape[0] * cell_shape[1] * feature_map]) + else: + # : stack more RNN layer after that + # 5D Tensor [n_example/n_steps, n_steps, h, w, c] + self.outputs = tf.reshape(tf.concat(outputs, 1), [-1, n_steps, cell_shape[0], + cell_shape[1], feature_map]) + + self.final_state = state + + self.all_layers = list(layer.all_layers) + self.all_params = list(layer.all_params) + self.all_drop = dict(layer.all_drop) + self.all_layers.extend([self.outputs]) + self.all_params.extend(rnn_variables) + + + # Advanced Ops for Dynamic RNN def advanced_indexing_op(input, index): """Advanced Indexing for Sequences, returns the outputs by given sequence lengths. @@ -4147,7 +5083,7 @@ def retrieve_seq_length_op(data): >>> data = [[[1,2],[2,2],[1,2],[1,2],[0,0]], ... [[2,3],[2,4],[3,2],[0,0],[0,0]], ... [[3,3],[2,2],[5,3],[1,2],[0,0]]] - >>> sl + >>> print(sl) ... [4 3 4] References @@ -4186,7 +5122,6 @@ def retrieve_seq_length_op2(data): """ return tf.reduce_sum(tf.cast(tf.greater(data, tf.zeros_like(data)), tf.int32), 1) - def retrieve_seq_length_op3(data, pad_val=0): # HangSheng: return tensor for sequence length, if input is tf.string data_shape_size = data.get_shape().ndims if data_shape_size == 3: @@ -4198,7 +5133,6 @@ def retrieve_seq_length_op3(data, pad_val=0): # HangSheng: return tensor for seq else: raise ValueError("retrieve_seq_length_op3: handling data_shape_size %s hasn't been implemented!" % (data_shape_size)) - def target_mask_op(data, pad_val=0): # HangSheng: return tensor for mask,if input is tf.string data_shape_size = data.get_shape().ndims if data_shape_size == 3: @@ -4224,7 +5158,7 @@ class DynamicRNNLayer(Layer): - see `RNN Cells in TensorFlow `_ cell_init_args : a dictionary The arguments for the cell initializer. - n_hidden : a int + n_hidden : an int The number of hidden units in the layer. initializer : initializer The initializer for initializing the parameters. @@ -4237,7 +5171,7 @@ class DynamicRNNLayer(Layer): If None, initial_state is zero_state. dropout : `tuple` of `float`: (input_keep_prob, output_keep_prob). The input and output keep probability. - n_layer : a int, default is 1. + n_layer : an int, default is 1. The number of RNN layers. return_last : boolean - If True, return the last output, "Sequence input and single output" @@ -4279,19 +5213,19 @@ class DynamicRNNLayer(Layer): Examples -------- >>> input_seqs = tf.placeholder(dtype=tf.int64, shape=[batch_size, None], name="input_seqs") - >>> network = tl.layers.EmbeddingInputlayer( + >>> net = tl.layers.EmbeddingInputlayer( ... inputs = input_seqs, ... vocabulary_size = vocab_size, ... embedding_size = embedding_size, ... name = 'seq_embedding') - >>> network = tl.layers.DynamicRNNLayer(network, + >>> net = tl.layers.DynamicRNNLayer(net, ... cell_fn = tf.contrib.rnn.BasicLSTMCell, # for TF0.2 tf.nn.rnn_cell.BasicLSTMCell, ... n_hidden = embedding_size, ... dropout = 0.7, ... sequence_length = tl.layers.retrieve_seq_length_op2(input_seqs), ... return_seq_2d = True, # stack denselayer or compute cost after it ... name = 'dynamic_rnn') - ... network = tl.layers.DenseLayer(network, n_units=vocab_size, + ... net = tl.layers.DenseLayer(net, n_units=vocab_size, ... act=tf.identity, name="output") References @@ -4400,7 +5334,7 @@ def __init__( # Initialize initial_state if initial_state is None: - self.initial_state = self.cell.zero_state(batch_size, dtype=tf.float32) + self.initial_state = self.cell.zero_state(batch_size, dtype=D_TYPE) # dtype=tf.float32) else: self.initial_state = initial_state @@ -4482,11 +5416,11 @@ class BiDynamicRNNLayer(Layer): - see `RNN Cells in TensorFlow `_ cell_init_args : a dictionary The arguments for the cell initializer. - n_hidden : a int + n_hidden : an int The number of hidden units in the layer. initializer : initializer The initializer for initializing the parameters. - sequence_length : a tensor, array or None + sequence_length : a tensor, array or None. The sequence length of each row of input data, see ``Advanced Ops for Dynamic RNN``. - If None, it uses ``retrieve_seq_length_op`` to compute the sequence_length, i.e. when the features of padding (on right hand side) are all zeros. - If using word embedding, you may need to compute the sequence_length from the ID array (the integer features before word embedding) by using ``retrieve_seq_length_op2`` or ``retrieve_seq_length_op``. @@ -4498,7 +5432,7 @@ class BiDynamicRNNLayer(Layer): If None, initial_state is zero_state. dropout : `tuple` of `float`: (input_keep_prob, output_keep_prob). The input and output keep probability. - n_layer : a int, default is 1. + n_layer : an int, default is 1. The number of RNN layers. return_last : boolean If True, return the last output, "Sequence input and single output"\n @@ -4511,7 +5445,7 @@ class BiDynamicRNNLayer(Layer): name : a string or None An optional name to attach to this layer. - Variables + Attributes ----------------------- outputs : a tensor The output of this RNN. @@ -4633,15 +5567,22 @@ def __init__( # cell_instance_fn=lambda: MultiRNNCell_fn([cell_instance_fn2() for _ in range(n_layer)]) self.fw_cell = MultiRNNCell_fn([cell_creator() for _ in range(n_layer)]) self.bw_cell = MultiRNNCell_fn([cell_creator() for _ in range(n_layer)]) + + if dropout: + self.fw_cell = DropoutWrapper_fn(self.fw_cell, + input_keep_prob=1.0, output_keep_prob=out_keep_prob) + self.bw_cell = DropoutWrapper_fn(self.bw_cell, + input_keep_prob=1.0, output_keep_prob=out_keep_prob) + # self.fw_cell=cell_instance_fn() # self.bw_cell=cell_instance_fn() # Initial state of RNN if fw_initial_state is None: - self.fw_initial_state = self.fw_cell.zero_state(self.batch_size, dtype=tf.float32) + self.fw_initial_state = self.fw_cell.zero_state(self.batch_size, dtype=D_TYPE) # dtype=tf.float32) else: self.fw_initial_state = fw_initial_state if bw_initial_state is None: - self.bw_initial_state = self.bw_cell.zero_state(self.batch_size, dtype=tf.float32) + self.bw_initial_state = self.bw_cell.zero_state(self.batch_size, dtype=D_TYPE) # dtype=tf.float32) else: self.bw_initial_state = bw_initial_state # Computes sequence_length @@ -4672,6 +5613,7 @@ def __init__( outputs = tf.concat(2, outputs) if return_last: # [batch_size, 2 * n_hidden] + raise Exception("Do not support return_last at the moment") self.outputs = advanced_indexing_op(outputs, sequence_length) else: # [batch_size, n_step(max), 2 * n_hidden] @@ -4709,10 +5651,12 @@ def __init__( # Seq2seq class Seq2Seq(Layer): """ - The :class:`Seq2Seq` class is a simple :class:`DynamicRNNLayer` based Seq2seq layer, - both encoder and decoder are :class:`DynamicRNNLayer`, network details - see `Model `_ - and `Sequence to Sequence Learning with Neural Networks `_ . + The :class:`Seq2Seq` class is a Simple :class:`DynamicRNNLayer` based Seq2seq layer without using `tl.contrib.seq2seq `_. + See `Model `_ + and `Sequence to Sequence Learning with Neural Networks `_. + + - Please check the example `Chatbot in 200 lines of code `_. + - The Author recommends users to read the source code of :class:`DynamicRNNLayer` and :class:`Seq2Seq`. Parameters ---------- @@ -4724,17 +5668,19 @@ class Seq2Seq(Layer): - see `RNN Cells in TensorFlow `_ cell_init_args : a dictionary The arguments for the cell initializer. - n_hidden : a int + n_hidden : an int The number of hidden units in the layer. initializer : initializer The initializer for initializing the parameters. encode_sequence_length : tensor for encoder sequence length, see :class:`DynamicRNNLayer` . decode_sequence_length : tensor for decoder sequence length, see :class:`DynamicRNNLayer` . - initial_state : None or forward RNN State - If None, initial_state is of encoder zero_state. + initial_state_encode : None or RNN state (from placeholder or other RNN). + If None, initial_state_encode is of zero state. + initial_state_decode : None or RNN state (from placeholder or other RNN). + If None, initial_state_decode is of the final state of the RNN encoder. dropout : `tuple` of `float`: (input_keep_prob, output_keep_prob). The input and output keep probability. - n_layer : a int, default is 1. + n_layer : an int, default is 1. The number of RNN layers. return_seq_2d : boolean - When return_last = False @@ -4743,13 +5689,27 @@ class Seq2Seq(Layer): name : a string or None An optional name to attach to this layer. - Variables + Attributes ------------ outputs : a tensor The output of RNN decoder. + initial_state_encode : a tensor or StateTuple + Initial state of RNN encoder. + initial_state_decode : a tensor or StateTuple + Initial state of RNN decoder. + final_state_encode : a tensor or StateTuple + Final state of RNN encoder. + final_state_decode : a tensor or StateTuple + Final state of RNN decoder. - final_state : a tensor or StateTuple - Final state of decoder, see :class:`DynamicRNNLayer` . + Notes + -------- + - How to feed data: `Sequence to Sequence Learning with Neural Networks `_ + - input_seqs : ``['how', 'are', 'you', ']`` + - decode_seqs : ``['', 'I', 'am', 'fine', ']`` + - target_seqs : ``['I', 'am', 'fine', ']`` + - target_mask : ``[1, 1, 1, 1, 0]`` + - related functions : tl.prepro Examples ---------- @@ -4781,7 +5741,7 @@ class Seq2Seq(Layer): ... initializer = tf.random_uniform_initializer(-0.1, 0.1), ... encode_sequence_length = retrieve_seq_length_op2(encode_seqs), ... decode_sequence_length = retrieve_seq_length_op2(decode_seqs), - ... initial_state = None, + ... initial_state_encode = None, ... dropout = None, ... n_layer = 1, ... return_seq_2d = True, @@ -4791,14 +5751,7 @@ class Seq2Seq(Layer): >>> y = tf.nn.softmax(net_out.outputs) >>> net_out.print_params(False) - Notes - -------- - - How to feed data: `Sequence to Sequence Learning with Neural Networks `_ - - input_seqs : ``['how', 'are', 'you', ']`` - - decode_seqs : ``['', 'I', 'am', 'fine', ']`` - - target_seqs : ``['I', 'am', 'fine', ' + """ def __init__( self, @@ -4810,7 +5763,8 @@ def __init__( initializer = tf.random_uniform_initializer(-0.1, 0.1), encode_sequence_length = None, decode_sequence_length = None, - initial_state = None, + initial_state_encode = None, + initial_state_decode = None, dropout = None, n_layer = 1, # return_last = False, @@ -4836,7 +5790,7 @@ def __init__( cell_fn = cell_fn, cell_init_args = cell_init_args, n_hidden = n_hidden, - initial_state = initial_state, + initial_state = initial_state_encode, dropout = dropout, n_layer = n_layer, sequence_length = encode_sequence_length, @@ -4849,7 +5803,7 @@ def __init__( cell_fn = cell_fn, cell_init_args = cell_init_args, n_hidden = n_hidden, - initial_state = network_encode.final_state, + initial_state = (network_encode.final_state if initial_state_decode is None else initial_state_decode), dropout = dropout, n_layer = n_layer, sequence_length = decode_sequence_length, @@ -4858,18 +5812,27 @@ def __init__( name = name+'_decode') self.outputs = network_decode.outputs - rnn_variables = tf.get_collection(TF_GRAPHKEYS_VARIABLES, scope=vs.name) + # rnn_variables = tf.get_collection(TF_GRAPHKEYS_VARIABLES, scope=vs.name) + + # Initial state + self.initial_state_encode = network_encode.initial_state + self.initial_state_decode = network_decode.initial_state # Final state - self.final_state = network_decode.final_state + self.final_state_encode = network_encode.final_state + self.final_state_decode = network_decode.final_state # self.sequence_length = sequence_length - self.all_layers = list(network_decode.all_layers) - self.all_params = list(network_decode.all_params) - self.all_drop = dict(network_decode.all_drop) + self.all_layers = list(network_encode.all_layers) + self.all_params = list(network_encode.all_params) + self.all_drop = dict(network_encode.all_drop) + + self.all_layers.extend(list(network_decode.all_layers)) + self.all_params.extend(list(network_decode.all_params)) + self.all_drop.update(dict(network_decode.all_drop)) self.all_layers.extend( [self.outputs] ) - self.all_params.extend( rnn_variables ) + # self.all_params.extend( rnn_variables ) self.all_layers = list_remove_repeat(self.all_layers) self.all_params = list_remove_repeat(self.all_params) @@ -4953,20 +5916,20 @@ class FlattenLayer(Layer): Examples -------- >>> x = tf.placeholder(tf.float32, shape=[None, 28, 28, 1]) - >>> network = tl.layers.InputLayer(x, name='input_layer') - >>> network = tl.layers.Conv2dLayer(network, + >>> net = tl.layers.InputLayer(x, name='input_layer') + >>> net = tl.layers.Conv2dLayer(net, ... act = tf.nn.relu, ... shape = [5, 5, 32, 64], ... strides=[1, 1, 1, 1], ... padding='SAME', ... name ='cnn_layer') - >>> network = tl.layers.Pool2dLayer(network, + >>> net = tl.layers.Pool2dLayer(net, ... ksize=[1, 2, 2, 1], ... strides=[1, 2, 2, 1], ... padding='SAME', ... pool = tf.nn.max_pool, ... name ='pool_layer',) - >>> network = tl.layers.FlattenLayer(network, name='flatten_layer') + >>> net = tl.layers.FlattenLayer(net, name='flatten_layer') """ def __init__( self, @@ -5026,6 +5989,39 @@ def __init__( self.all_drop = dict(layer.all_drop) self.all_layers.extend( [self.outputs] ) +class TransposeLayer(Layer): + """ + The :class:`TransposeLayer` class transpose the dimension of a teneor, see `tf.transpose() `_ . + + Parameters + ---------- + layer : a :class:`Layer` instance + The `Layer` class feeding into this layer. + perm: list, a permutation of the dimensions + Similar with numpy.transpose. + name : a string or None + An optional name to attach to this layer. + """ + def __init__( + self, + layer = None, + perm = None, + name = 'transpose', + ): + Layer.__init__(self, name=name) + self.inputs = layer.outputs + assert perm is not None + + print(" [TL] TransposeLayer %s: perm:%s" % (self.name, perm)) + # with tf.variable_scope(name) as vs: + self.outputs = tf.transpose(self.inputs, perm=perm, name=name) + self.all_layers = list(layer.all_layers) + self.all_params = list(layer.all_params) + self.all_drop = dict(layer.all_drop) + self.all_layers.extend( [self.outputs] ) + # self.all_params.extend( variables ) + +## Lambda class LambdaLayer(Layer): """ The :class:`LambdaLayer` class is a layer which is able to use the provided function. @@ -5044,9 +6040,9 @@ class LambdaLayer(Layer): Examples --------- >>> x = tf.placeholder(tf.float32, shape=[None, 1], name='x') - >>> network = tl.layers.InputLayer(x, name='input_layer') - >>> network = LambdaLayer(network, lambda x: 2*x, name='lambda_layer') - >>> y = network.outputs + >>> net = tl.layers.InputLayer(x, name='input_layer') + >>> net = LambdaLayer(net, lambda x: 2*x, name='lambda_layer') + >>> y = net.outputs >>> sess = tf.InteractiveSession() >>> out = sess.run(y, feed_dict={x : [[1],[2]]}) ... [[2],[4]] @@ -5076,8 +6072,7 @@ def __init__( ## Merge layer class ConcatLayer(Layer): """ - The :class:`ConcatLayer` class is layer which concat (merge) two or more - :class:`DenseLayer` to a single class:`DenseLayer`. + The :class:`ConcatLayer` class is layer which concat (merge) two or more tensor by given axis.. Parameters ---------- @@ -5089,29 +6084,27 @@ class ConcatLayer(Layer): An optional name to attach to this layer. Examples - -------- + ---------- >>> sess = tf.InteractiveSession() >>> x = tf.placeholder(tf.float32, shape=[None, 784]) >>> inputs = tl.layers.InputLayer(x, name='input_layer') - >>> net1 = tl.layers.DenseLayer(inputs, n_units=800, act = tf.nn.relu, name='relu1_1') - >>> net2 = tl.layers.DenseLayer(inputs, n_units=300, act = tf.nn.relu, name='relu2_1') - >>> network = tl.layers.ConcatLayer(layer = [net1, net2], name ='concat_layer') + >>> net1 = tl.layers.DenseLayer(inputs, 800, act=tf.nn.relu, name='relu1_1') + >>> net2 = tl.layers.DenseLayer(inputs, 300, act=tf.nn.relu, name='relu2_1') + >>> net = tl.layers.ConcatLayer([net1, net2], 1, name ='concat_layer') ... [TL] InputLayer input_layer (?, 784) - ... [TL] DenseLayer relu1_1: 800, - ... [TL] DenseLayer relu2_1: 300, + ... [TL] DenseLayer relu1_1: 800, relu + ... [TL] DenseLayer relu2_1: 300, relu ... [TL] ConcatLayer concat_layer, 1100 - ... >>> tl.layers.initialize_global_variables(sess) - >>> network.print_params() + >>> net.print_params() ... param 0: (784, 800) (mean: 0.000021, median: -0.000020 std: 0.035525) - ... param 1: (800,) (mean: 0.000000, median: 0.000000 std: 0.000000) + ... param 1: (800,) (mean: 0.000000, median: 0.000000 std: 0.000000) ... param 2: (784, 300) (mean: 0.000000, median: -0.000048 std: 0.042947) - ... param 3: (300,) (mean: 0.000000, median: 0.000000 std: 0.000000) + ... param 3: (300,) (mean: 0.000000, median: 0.000000 std: 0.000000) ... num of params: 863500 - >>> network.print_layers() - ... layer 0: Tensor("Relu:0", shape=(?, 800), dtype=float32) + >>> net.print_layers() + ... layer 0: ("Relu:0", shape=(?, 800), dtype=float32) ... layer 1: Tensor("Relu_1:0", shape=(?, 300), dtype=float32) - ... """ def __init__( self, @@ -5127,8 +6120,8 @@ def __init__( self.outputs = tf.concat(self.inputs, concat_dim, name=name) except: # TF0.12 self.outputs = tf.concat(concat_dim, self.inputs, name=name) - self.n_units = int(self.outputs.get_shape()[-1]) - print(" [TL] ConcatLayer %s: %d" % (self.name, self.n_units)) + + print(" [TL] ConcatLayer %s: axis: %d" % (self.name, concat_dim)) self.all_layers = list(layer[0].all_layers) self.all_params = list(layer[0].all_params) @@ -5197,7 +6190,7 @@ def __init__( self.all_params = list_remove_repeat(self.all_params) # self.all_drop = list_remove_repeat(self.all_drop) -# Extend +## Extend class ExpandDimsLayer(Layer): """ The :class:`ExpandDimsLayer` class inserts a dimension of 1 into a tensor's shape, @@ -5265,12 +6258,102 @@ def __init__( self.all_layers.extend( [self.outputs] ) # self.all_params.extend( variables ) +## Stack Unstack +class StackLayer(Layer): + """ + The :class:`StackLayer` class is layer for stacking a list of rank-R tensors into one rank-(R+1) tensor, see `tf.stack() `_. + + Parameters + ---------- + layer : a list of :class:`Layer` instances + The `Layer` class feeding into this layer. + axis : an int + Dimension along which to concatenate. + name : a string or None + An optional name to attach to this layer. + """ + def __init__( + self, + layer = [], + axis = 0, + name ='stack', + ): + Layer.__init__(self, name=name) + self.inputs = [] + for l in layer: + self.inputs.append(l.outputs) + + self.outputs = tf.stack(self.inputs, axis=axis, name=name) + + print(" [TL] StackLayer %s: axis: %d" % (self.name, axis)) + + self.all_layers = list(layer[0].all_layers) + self.all_params = list(layer[0].all_params) + self.all_drop = dict(layer[0].all_drop) + + for i in range(1, len(layer)): + self.all_layers.extend(list(layer[i].all_layers)) + self.all_params.extend(list(layer[i].all_params)) + self.all_drop.update(dict(layer[i].all_drop)) + + self.all_layers = list_remove_repeat(self.all_layers) + self.all_params = list_remove_repeat(self.all_params) + +def UnStackLayer( + layer = None, + num = None, + axis = 0, + name ='unstack',): + """ + The :class:`UnStackLayer` is layer for unstacking the given dimension of a rank-R tensor into rank-(R-1) tensors., see `tf.unstack() `_. + + Parameters + ---------- + layer : a list of :class:`Layer` instances + The `Layer` class feeding into this layer. + num : an int + The length of the dimension axis. Automatically inferred if None (the default). + axis : an int + Dimension along which to concatenate. + name : a string or None + An optional name to attach to this layer. + + Returns + -------- + The list of layer objects unstacked from the input. + """ + inputs = layer.outputs + with tf.variable_scope(name) as vs: + outputs = tf.unstack(inputs, num=num, axis=axis) + + print(" [TL] UnStackLayer %s: num: %s axis: %d, n_outputs: %d" % (name, num, axis, len(outputs))) + + net_new = [] + scope_name = tf.get_variable_scope().name + if scope_name: + whole_name = scope_name + '/' + name + else: + whole_name = name + + for i in range(len(outputs)): + n = Layer(None, name=whole_name+str(i)) + n.outputs = outputs[i] + n.all_layers = list(layer.all_layers) + n.all_params = list(layer.all_params) + n.all_drop = dict(layer.all_drop) + n.all_layers.extend( [inputs] ) + + net_new.append(n) + + return net_new + ## TF-Slim layer class SlimNetsLayer(Layer): """ The :class:`SlimNetsLayer` class can be used to merge all TF-Slim nets into - TensorLayer. Model can be found in `slim-model `_ , more about slim - see `slim-git `_ . + TensorLayer. Models can be found in `slim-model `_, + see Inception V3 example on `Github `_. + Parameters ---------- @@ -5283,10 +6366,6 @@ class SlimNetsLayer(Layer): name : a string or None An optional name to attach to this layer. - Examples - -------- - - see Inception V3 example on `Github `_ - Notes ----- The due to TF-Slim stores the layers as dictionary, the ``all_layers`` in this @@ -5334,7 +6413,8 @@ def __init__( class KerasLayer(Layer): """ The :class:`KerasLayer` class can be used to merge all Keras layers into - TensorLayer. Example can be found here `tutorial_keras.py `_ + TensorLayer. Example can be found here `tutorial_keras.py `_. + This layer will be deprecated soon as :class:`LambdaLayer` can do the same thing. Parameters ---------- @@ -5372,7 +6452,8 @@ def __init__( class EstimatorLayer(Layer): """ The :class:`EstimatorLayer` class accepts ``model_fn`` that described the model. - It is similar with :class:`KerasLayer`, see `tutorial_keras.py `_ + It is similar with :class:`KerasLayer`, see `tutorial_keras.py `_. + This layer will be deprecated soon as :class:`LambdaLayer` can do the same thing. Parameters ---------- @@ -5445,7 +6526,7 @@ def __init__( # with tf.name_scope(name) as scope: with tf.variable_scope(name) as vs: - alphas = tf.get_variable(name='alphas', shape=w_shape, initializer=a_init, **a_init_args ) + alphas = tf.get_variable(name='alphas', shape=w_shape, initializer=a_init, dtype=D_TYPE, **a_init_args ) try: ## TF 1.0 self.outputs = tf.nn.relu(self.inputs) + tf.multiply(alphas, (self.inputs - tf.abs(self.inputs))) * 0.5 except: ## TF 0.12 @@ -5556,7 +6637,7 @@ def __init__(self, # ---------- # layer : a list of :class:`Layer` instances # The `Layer` class feeding into this layer. -# n_outputs : a int +# n_outputs : an int # The number of output # name : a string or None # An optional name to attach to this layer. @@ -5653,9 +6734,9 @@ def __init__(self, softmax_loss_function = None # Sampled softmax only makes sense if we sample less than vocabulary size. if num_samples > 0 and num_samples < self.target_vocab_size: - w = tf.get_variable("proj_w", [size, self.target_vocab_size]) + w = tf.get_variable("proj_w", [size, self.target_vocab_size], dtype=D_TYPE) w_t = tf.transpose(w) - b = tf.get_variable("proj_b", [self.target_vocab_size]) + b = tf.get_variable("proj_b", [self.target_vocab_size], dtype=D_TYPE) output_projection = (w, b) def sampled_loss(inputs, labels): @@ -5680,9 +6761,9 @@ def sampled_loss(inputs, labels): cell = cell_creator() if num_layers > 1: try: # TF1.0 - cell = tf.contrib.rnn.MultiRNNCell([single_cell] * num_layers) + cell = tf.contrib.rnn.MultiRNNCell([cell] * num_layers) except: - cell = tf.nn.rnn_cell.MultiRNNCell([single_cell] * num_layers) + cell = tf.nn.rnn_cell.MultiRNNCell([cell] * num_layers) # ============== Seq Decode Layer ============ # The seq2seq function: we use embedding for the input and attention. @@ -5895,42 +6976,43 @@ def get_batch(self, data, bucket_id, PAD_ID=0, GO_ID=1, EOS_ID=2, UNK_ID=3): return batch_encoder_inputs, batch_decoder_inputs, batch_weights ## Developing or Untested -class MaxoutLayer(Layer): - """ - Waiting for contribution - - Single DenseLayer with Max-out behaviour, work well with Dropout. - - References - ----------- - `Goodfellow (2013) Maxout Networks `_ - """ - def __init__( - self, - layer = None, - n_units = 100, - name ='maxout_layer', - ): - Layer.__init__(self, name=name) - self.inputs = layer.outputs - - print(" [TL] MaxoutLayer %s: %d" % (self.name, self.n_units)) - print(" Waiting for contribution") - with tf.variable_scope(name) as vs: - pass - # W = tf.Variable(init.xavier_init(n_inputs=n_in, n_outputs=n_units, uniform=True), name='W') - # b = tf.Variable(tf.zeros([n_units]), name='b') - - # self.outputs = act(tf.matmul(self.inputs, W) + b) - # https://www.tensorflow.org/versions/r0.9/api_docs/python/array_ops.html#pack - # http://stackoverflow.com/questions/34362193/how-to-explicitly-broadcast-a-tensor-to-match-anothers-shape-in-tensorflow - # tf.concat tf.pack tf.tile +# class MaxoutLayer(Layer): +# """ +# Waiting for contribution +# +# Single DenseLayer with Max-out behaviour, work well with Dropout. +# +# References +# ----------- +# `Goodfellow (2013) Maxout Networks `_ +# """ +# def __init__( +# self, +# layer = None, +# n_units = 100, +# name ='maxout_layer', +# ): +# Layer.__init__(self, name=name) +# self.inputs = layer.outputs +# +# print(" [TL] MaxoutLayer %s: %d" % (self.name, self.n_units)) +# print(" Waiting for contribution") +# with tf.variable_scope(name) as vs: +# pass +# # W = tf.Variable(init.xavier_init(n_inputs=n_in, n_outputs=n_units, uniform=True), name='W') +# # b = tf.Variable(tf.zeros([n_units]), name='b') +# +# # self.outputs = act(tf.matmul(self.inputs, W) + b) +# # https://www.tensorflow.org/versions/r0.9/api_docs/python/array_ops.html#pack +# # http://stackoverflow.com/questions/34362193/how-to-explicitly-broadcast-a-tensor-to-match-anothers-shape-in-tensorflow +# # tf.concat tf.pack tf.tile +# +# self.all_layers = list(layer.all_layers) +# self.all_params = list(layer.all_params) +# self.all_drop = dict(layer.all_drop) +# self.all_layers.extend( [self.outputs] ) +# self.all_params.extend( [W, b] ) - self.all_layers = list(layer.all_layers) - self.all_params = list(layer.all_params) - self.all_drop = dict(layer.all_drop) - self.all_layers.extend( [self.outputs] ) - self.all_params.extend( [W, b] ) diff --git a/tensorlayer/nlp.py b/tensorlayer/nlp.py index 13b1e55f..fe1273bd 100644 --- a/tensorlayer/nlp.py +++ b/tensorlayer/nlp.py @@ -1,11 +1,9 @@ #! /usr/bin/python -# -*- coding: utf8 -*- - - - +# -*- coding: utf-8 -*- import tensorflow as tf import os +import re from sys import platform as _platform import collections import random @@ -15,7 +13,9 @@ from tensorflow.python.platform import gfile import re -## Iteration functions +# Iteration functions + + def generate_skip_gram_batch(data, batch_size, num_skips, skip_window, data_index=0): """Generate a training batch for the Skip-Gram model. @@ -44,9 +44,8 @@ def generate_skip_gram_batch(data, batch_size, num_skips, skip_window, data_inde Examples -------- - >>> Setting num_skips=2, skip_window=1, use the right and left words. - >>> In the same way, num_skips=4, skip_window=2 means use the nearby 4 words. - + - Setting num_skips=2, skip_window=1, use the right and left words. + In the same way, num_skips=4, skip_window=2 means use the nearby 4 words. >>> data = [1,2,3,4,5,6,7,8,9,10,11] >>> batch, labels, data_index = tl.nlp.generate_skip_gram_batch(data=data, batch_size=8, num_skips=2, skip_window=1, data_index=0) >>> print(batch) @@ -72,14 +71,14 @@ def generate_skip_gram_batch(data, batch_size, num_skips, skip_window, data_inde assert num_skips <= 2 * skip_window batch = np.ndarray(shape=(batch_size), dtype=np.int32) labels = np.ndarray(shape=(batch_size, 1), dtype=np.int32) - span = 2 * skip_window + 1 # [ skip_window target skip_window ] + span = 2 * skip_window + 1 # [ skip_window target skip_window ] buffer = collections.deque(maxlen=span) for _ in range(span): buffer.append(data[data_index]) data_index = (data_index + 1) % len(data) for i in range(batch_size // num_skips): target = skip_window # target label at the center of the buffer - targets_to_avoid = [ skip_window ] + targets_to_avoid = [skip_window] for j in range(num_skips): while target in targets_to_avoid: target = random.randint(0, span - 1) @@ -91,7 +90,7 @@ def generate_skip_gram_batch(data, batch_size, num_skips, skip_window, data_inde return batch, labels, data_index -## Sampling functions +# Sampling functions def sample(a=[], temperature=1.0): """Sample an index from a probability array. @@ -109,10 +108,9 @@ def sample(a=[], temperature=1.0): Notes ------ - No matter what is the temperature and input list, the sum of all probabilities will be one. + - No matter what is the temperature and input list, the sum of all probabilities will be one. Even if input list = [1, 100, 200], the sum of all probabilities will still be one. - - For large vocabulary_size, choice a higher temperature to avoid error. + - For large vocabulary_size, choice a higher temperature to avoid error. """ b = np.copy(a) try: @@ -138,6 +136,7 @@ def sample(a=[], temperature=1.0): # print(b) return np.argmax(np.random.multinomial(1, b, 1)) + def sample_top(a=[], top_k=10): """Sample from ``top_k`` probabilities. @@ -154,7 +153,7 @@ def sample_top(a=[], top_k=10): probs = probs / np.sum(probs) choice = np.random.choice(idx, p=probs) return choice - ## old implementation + # old implementation # a = np.array(a) # idx = np.argsort(a)[::-1] # idx = idx[:top_k] @@ -166,117 +165,125 @@ def sample_top(a=[], top_k=10): # # return choice -## Vector representations of words (Advanced) UNDOCUMENT +# Vector representations of words (Advanced) UNDOCUMENT class SimpleVocabulary(object): - """Simple vocabulary wrapper, see create_vocab(). + """Simple vocabulary wrapper, see create_vocab(). - Parameters - ------------ - vocab : A dictionary of word to word_id. - unk_id : Id of the special 'unknown' word. - """ + Parameters + ------------ + vocab : A dictionary of word to word_id. + unk_id : Id of the special 'unknown' word. + """ - def __init__(self, vocab, unk_id): - """Initializes the vocabulary.""" + def __init__(self, vocab, unk_id): + """Initializes the vocabulary.""" + self._vocab = vocab + self._unk_id = unk_id - self._vocab = vocab - self._unk_id = unk_id + def word_to_id(self, word): + """Returns the integer id of a word string.""" + if word in self._vocab: + return self._vocab[word] + else: + return self._unk_id - def word_to_id(self, word): - """Returns the integer id of a word string.""" - if word in self._vocab: - return self._vocab[word] - else: - return self._unk_id class Vocabulary(object): - """Create Vocabulary class from a given vocabulary and its id-word, word-id convert, - see create_vocab() and ``tutorial_tfrecord3.py``. - - Parameters - ----------- - vocab_file : File containing the vocabulary, where the words are the first - whitespace-separated token on each line (other tokens are ignored) and - the word ids are the corresponding line numbers. - start_word : Special word denoting sentence start. - end_word : Special word denoting sentence end. - unk_word : Special word denoting unknown words. - - Properties - ------------ - vocab : a dictionary from word to id. - reverse_vocab : a list from id to word. - start_id : int of start id - end_id : int of end id - unk_id : int of unk id - pad_id : int of padding id - - Vocab_files - ------------- - >>> Look as follow, includes `start_word` , `end_word` but no `unk_word` . - >>> a 969108 - >>> 586368 - >>> 586368 - >>> . 440479 - >>> on 213612 - >>> of 202290 - >>> the 196219 - >>> in 182598 - >>> with 152984 - >>> and 139109 - >>> is 97322 - """ - - def __init__(self, - vocab_file, - start_word="", - end_word="", - unk_word="", - pad_word=""): - if not tf.gfile.Exists(vocab_file): - tf.logging.fatal("Vocab file %s not found.", vocab_file) - tf.logging.info("Initializing vocabulary from file: %s", vocab_file) - - with tf.gfile.GFile(vocab_file, mode="r") as f: - reverse_vocab = list(f.readlines()) - reverse_vocab = [line.split()[0] for line in reverse_vocab] - assert start_word in reverse_vocab - assert end_word in reverse_vocab - if unk_word not in reverse_vocab: - reverse_vocab.append(unk_word) - vocab = dict([(x, y) for (y, x) in enumerate(reverse_vocab)]) - - print(" [TL] Vocabulary from %s : %s %s %s" % (vocab_file, start_word, end_word, unk_word)) - print(" vocabulary with %d words (includes start_word, end_word, unk_word)" % len(vocab)) - # tf.logging.info(" vocabulary with %d words" % len(vocab)) - - self.vocab = vocab # vocab[word] = id - self.reverse_vocab = reverse_vocab # reverse_vocab[id] = word - - # Save special word ids. - self.start_id = vocab[start_word] - self.end_id = vocab[end_word] - self.unk_id = vocab[unk_word] - self.pad_id = vocab[pad_word] - print(" start_id: %d" % self.start_id) - print(" end_id: %d" % self.end_id) - print(" unk_id: %d" % self.unk_id) - print(" pad_id: %d" % self.pad_id) - - def word_to_id(self, word): - """Returns the integer word id of a word string.""" - if word in self.vocab: - return self.vocab[word] - else: - return self.unk_id + """Create Vocabulary class from a given vocabulary and its id-word, word-id convert, + see create_vocab() and ``tutorial_tfrecord3.py``. + + Parameters + ----------- + vocab_file : File containing the vocabulary, where the words are the first + whitespace-separated token on each line (other tokens are ignored) and + the word ids are the corresponding line numbers. + start_word : Special word denoting sentence start. + end_word : Special word denoting sentence end. + unk_word : Special word denoting unknown words. + + Attributes + ------------ + vocab : a dictionary from word to id. + reverse_vocab : a list from id to word. + start_id : int of start id + end_id : int of end id + unk_id : int of unk id + pad_id : int of padding id + + Vocab_files + ------------- + >>> Look as follow, includes `start_word` , `end_word` but no `unk_word` . + >>> a 969108 + >>> 586368 + >>> 586368 + >>> . 440479 + >>> on 213612 + >>> of 202290 + >>> the 196219 + >>> in 182598 + >>> with 152984 + >>> and 139109 + >>> is 97322 + """ + + def __init__(self, + vocab_file, + start_word="", + end_word="", + unk_word="", + pad_word=""): + if not tf.gfile.Exists(vocab_file): + tf.logging.fatal("Vocab file %s not found.", vocab_file) + tf.logging.info("Initializing vocabulary from file: %s", vocab_file) + + with tf.gfile.GFile(vocab_file, mode="r") as f: + reverse_vocab = list(f.readlines()) + reverse_vocab = [line.split()[0] for line in reverse_vocab] + # assert start_word in reverse_vocab + # assert end_word in reverse_vocab + if start_word not in reverse_vocab: # haodong + reverse_vocab.append(start_word) + if end_word not in reverse_vocab: + reverse_vocab.append(end_word) + if unk_word not in reverse_vocab: + reverse_vocab.append(unk_word) + if pad_word not in reverse_vocab: + reverse_vocab.append(pad_word) + + vocab = dict([(x, y) for (y, x) in enumerate(reverse_vocab)]) + + print(" [TL] Vocabulary from %s : %s %s %s" % (vocab_file, start_word, end_word, unk_word)) + print(" vocabulary with %d words (includes start_word, end_word, unk_word)" % len(vocab)) + # tf.logging.info(" vocabulary with %d words" % len(vocab)) + + self.vocab = vocab # vocab[word] = id + self.reverse_vocab = reverse_vocab # reverse_vocab[id] = word + + # Save special word ids. + self.start_id = vocab[start_word] + self.end_id = vocab[end_word] + self.unk_id = vocab[unk_word] + self.pad_id = vocab[pad_word] + print(" start_id: %d" % self.start_id) + print(" end_id: %d" % self.end_id) + print(" unk_id: %d" % self.unk_id) + print(" pad_id: %d" % self.pad_id) + + def word_to_id(self, word): + """Returns the integer word id of a word string.""" + if word in self.vocab: + return self.vocab[word] + else: + return self.unk_id + + def id_to_word(self, word_id): + """Returns the word string of an integer word id.""" + if word_id >= len(self.reverse_vocab): + return self.reverse_vocab[self.unk_id] + else: + return self.reverse_vocab[word_id] - def id_to_word(self, word_id): - """Returns the word string of an integer word id.""" - if word_id >= len(self.reverse_vocab): - return self.reverse_vocab[self.unk_id] - else: - return self.reverse_vocab[word_id] def process_sentence(sentence, start_word="", end_word=""): """Converts a sentence string into a list of string words, add start_word and end_word, @@ -318,6 +325,7 @@ def process_sentence(sentence, start_word="", end_word=""): process_sentence.append(end_word) return process_sentence + def create_vocab(sentences, word_counts_output_file, min_word_count=1): """Creates the vocabulary of word to word_id, see create_vocab() and ``tutorial_tfrecord3.py``. @@ -336,9 +344,9 @@ def create_vocab(sentences, word_counts_output_file, min_word_count=1): -------- - tl.nlp.SimpleVocabulary object. - Mores - ----- - - ``tl.nlp.build_vocab()`` + Notes + ------- + - See more ``tl.nlp.build_vocab()`` Examples -------- @@ -375,7 +383,7 @@ def create_vocab(sentences, word_counts_output_file, min_word_count=1): # Filter uncommon words and sort by descending count. word_counts = [x for x in counter.items() if x[1] >= min_word_count] word_counts.sort(key=lambda x: x[1], reverse=True) - word_counts = [("", 0)] + word_counts # 1st id should be reserved for padding + word_counts = [("", 0)] + word_counts # 1st id should be reserved for padding # print(word_counts) print(" Words in vocabulary: %d" % len(word_counts)) @@ -393,7 +401,7 @@ def create_vocab(sentences, word_counts_output_file, min_word_count=1): return vocab -## Vector representations of words +# Vector representations of words def simple_read_words(filename="nietzsche.txt"): """Read context from file without any preprocessing. @@ -406,39 +414,41 @@ def simple_read_words(filename="nietzsche.txt"): -------- The context in a string """ - with open("nietzsche.txt", "r") as f: + with open(filename, "r") as f: words = f.read() return words -def read_words(filename="nietzsche.txt", replace = ['\n', '']): - """File to list format context. Note that, this script can not handle punctuations. + +def read_words(filename="nietzsche.txt", replace=['\n', '']): + """ File to list format context. Note that, this script can not handle punctuations. For customized read_words method, see ``tutorial_generate_text.py``. Parameters - ---------- + ----------- filename : a string - A file path (like .txt file), + A file path (like .txt file) replace : a list [original string, target string], to disable replace use ['', ''] Returns -------- - The context in a list, split by space by default, and use ``''`` to represent ``'\n'``, + The context in a list, split by space by default, and use ```` to represent ``\\n``, e.g. ``[... 'how', 'useful', 'it', "'s" ... ]``. - Code References + References --------------- - `tensorflow.models.rnn.ptb.reader `_ """ with tf.gfile.GFile(filename, "r") as f: try: # python 3.4 or older context_list = f.read().replace(*replace).split() - except: # python 3.5 + except: # python 3.5 f.seek(0) replace = [x.encode('utf-8') for x in replace] context_list = f.read().replace(*replace).split() return context_list + def read_analogies_file(eval_file='questions-words.txt', word2id={}): """Reads through an analogy question file, return its id format. @@ -487,21 +497,22 @@ def read_analogies_file(eval_file='questions-words.txt', word2id={}): questions = [] questions_skipped = 0 with open(eval_file, "rb") as analogy_f: - for line in analogy_f: - if line.startswith(b":"): # Skip comments. + for line in analogy_f: + if line.startswith(b":"): # Skip comments. continue - words = line.strip().lower().split(b" ") # lowercase - ids = [word2id.get(w.strip()) for w in words] - if None in ids or len(ids) != 4: - questions_skipped += 1 - else: - questions.append(np.array(ids)) + words = line.strip().lower().split(b" ") # lowercase + ids = [word2id.get(w.strip()) for w in words] + if None in ids or len(ids) != 4: + questions_skipped += 1 + else: + questions.append(np.array(ids)) print("Eval analogy file: ", eval_file) print("Questions: ", len(questions)) print("Skipped: ", questions_skipped) analogy_questions = np.array(questions, dtype=np.int32) return analogy_questions + def build_vocab(data): """Build vocabulary. Given the context in list format. @@ -518,7 +529,7 @@ def build_vocab(data): word_to_id : a dictionary mapping words to unique IDs. e.g. {'campbell': 2587, 'atlantic': 2247, 'aoun': 6746 .... } - Code References + References --------------- - `tensorflow.models.rnn.ptb.reader `_ @@ -539,6 +550,7 @@ def build_vocab(data): # print(word_to_id) # dictionary for word to id, e.g. 'campbell': 2587, 'atlantic': 2247, 'aoun': 6746 return word_to_id + def build_reverse_dictionary(word_to_id): """Given a dictionary for converting word to integer id. Returns a reverse dictionary for converting a id to word. @@ -556,7 +568,8 @@ def build_reverse_dictionary(word_to_id): reverse_dictionary = dict(zip(word_to_id.values(), word_to_id.keys())) return reverse_dictionary -def build_words_dataset(words=[], vocabulary_size=50000, printable=True, unk_key = 'UNK'): + +def build_words_dataset(words=[], vocabulary_size=50000, printable=True, unk_key='UNK'): """Build the words dictionary and replace rare words with 'UNK' token. The most common word has the smallest integer id. @@ -592,7 +605,7 @@ def build_words_dataset(words=[], vocabulary_size=50000, printable=True, unk_key >>> vocabulary_size = 50000 >>> data, count, dictionary, reverse_dictionary = tl.nlp.build_words_dataset(words, vocabulary_size) - Code References + References ----------------- - `tensorflow/examples/tutorials/word2vec/word2vec_basic.py `_ """ @@ -616,11 +629,12 @@ def build_words_dataset(words=[], vocabulary_size=50000, printable=True, unk_key if printable: print('Real vocabulary size %d' % len(collections.Counter(words).keys())) print('Limited vocabulary size {}'.format(vocabulary_size)) - assert len(collections.Counter(words).keys()) >= vocabulary_size , \ - "the limited vocabulary_size must be less than or equal to the read vocabulary_size" + assert len(collections.Counter(words).keys()) >= vocabulary_size, \ + "the limited vocabulary_size must be less than or equal to the read vocabulary_size" return data, count, dictionary, reverse_dictionary -def words_to_word_ids(data=[], word_to_id={}, unk_key = 'UNK'): + +def words_to_word_ids(data=[], word_to_id={}, unk_key='UNK'): """Given a context (words) in list format and the vocabulary, Returns a list of IDs to represent the context. @@ -651,7 +665,7 @@ def words_to_word_ids(data=[], word_to_id={}, unk_key = 'UNK'): >>> print(context) ... [b'hello', b'how', b'are', b'you'] - Code References + References --------------- - `tensorflow.models.rnn.ptb.reader `_ """ @@ -680,6 +694,7 @@ def words_to_word_ids(data=[], word_to_id={}, unk_key = 'UNK'): # # print(data[0]) # return [word_to_id[str(word)] f + def word_ids_to_words(data, id_to_word): """Given a context (ids) in list format and the vocabulary, Returns a list of words to represent the context. @@ -701,6 +716,7 @@ def word_ids_to_words(data, id_to_word): """ return [id_to_word[i] for i in data] + def save_vocab(count=[], name='vocab.txt'): """Save the vocabulary to a file so the model can be reloaded. @@ -735,209 +751,296 @@ def save_vocab(count=[], name='vocab.txt'): f.write("%s %d\n" % (tf.compat.as_text(count[i][0]), count[i][1])) print("%d vocab saved to %s in %s" % (vocabulary_size, name, pwd)) -## Functions for translation +# Functions for translation + + def basic_tokenizer(sentence, _WORD_SPLIT=re.compile(b"([.,!?\"':;)(])")): - """Very basic tokenizer: split the sentence into a list of tokens. - - Parameters - ----------- - sentence : tensorflow.python.platform.gfile.GFile Object - _WORD_SPLIT : regular expression for word spliting. - - - Examples - -------- - >>> see create_vocabulary - >>> from tensorflow.python.platform import gfile - >>> train_path = "wmt/giga-fren.release2" - >>> with gfile.GFile(train_path + ".en", mode="rb") as f: - >>> for line in f: - >>> tokens = tl.nlp.basic_tokenizer(line) - >>> print(tokens) - >>> exit() - ... [b'Changing', b'Lives', b'|', b'Changing', b'Society', b'|', b'How', - ... b'It', b'Works', b'|', b'Technology', b'Drives', b'Change', b'Home', - ... b'|', b'Concepts', b'|', b'Teachers', b'|', b'Search', b'|', b'Overview', - ... b'|', b'Credits', b'|', b'HHCC', b'Web', b'|', b'Reference', b'|', - ... b'Feedback', b'Virtual', b'Museum', b'of', b'Canada', b'Home', b'Page'] - - References - ---------- - - Code from ``/tensorflow/models/rnn/translation/data_utils.py`` - """ - words = [] - sentence = tf.compat.as_bytes(sentence) - for space_separated_fragment in sentence.strip().split(): - words.extend(re.split(_WORD_SPLIT, space_separated_fragment)) - return [w for w in words if w] + """Very basic tokenizer: split the sentence into a list of tokens. + + Parameters + ----------- + sentence : tensorflow.python.platform.gfile.GFile Object + _WORD_SPLIT : regular expression for word spliting. + + + Examples + -------- + >>> see create_vocabulary + >>> from tensorflow.python.platform import gfile + >>> train_path = "wmt/giga-fren.release2" + >>> with gfile.GFile(train_path + ".en", mode="rb") as f: + >>> for line in f: + >>> tokens = tl.nlp.basic_tokenizer(line) + >>> print(tokens) + >>> exit() + ... [b'Changing', b'Lives', b'|', b'Changing', b'Society', b'|', b'How', + ... b'It', b'Works', b'|', b'Technology', b'Drives', b'Change', b'Home', + ... b'|', b'Concepts', b'|', b'Teachers', b'|', b'Search', b'|', b'Overview', + ... b'|', b'Credits', b'|', b'HHCC', b'Web', b'|', b'Reference', b'|', + ... b'Feedback', b'Virtual', b'Museum', b'of', b'Canada', b'Home', b'Page'] + + References + ---------- + - Code from ``/tensorflow/models/rnn/translation/data_utils.py`` + """ + words = [] + sentence = tf.compat.as_bytes(sentence) + for space_separated_fragment in sentence.strip().split(): + words.extend(re.split(_WORD_SPLIT, space_separated_fragment)) + return [w for w in words if w] + def create_vocabulary(vocabulary_path, data_path, max_vocabulary_size, tokenizer=None, normalize_digits=True, _DIGIT_RE=re.compile(br"\d"), _START_VOCAB=[b"_PAD", b"_GO", b"_EOS", b"_UNK"]): - """Create vocabulary file (if it does not exist yet) from data file. - - Data file is assumed to contain one sentence per line. Each sentence is - tokenized and digits are normalized (if normalize_digits is set). - Vocabulary contains the most-frequent tokens up to max_vocabulary_size. - We write it to vocabulary_path in a one-token-per-line format, so that later - token in the first line gets id=0, second line gets id=1, and so on. - - Parameters - ----------- - vocabulary_path : path where the vocabulary will be created. - data_path : data file that will be used to create vocabulary. - max_vocabulary_size : limit on the size of the created vocabulary. - tokenizer : a function to use to tokenize each data sentence. - if None, basic_tokenizer will be used. - normalize_digits : Boolean - if true, all digits are replaced by 0s. - - References - ---------- - - Code from ``/tensorflow/models/rnn/translation/data_utils.py`` - """ - if not gfile.Exists(vocabulary_path): - print("Creating vocabulary %s from data %s" % (vocabulary_path, data_path)) - vocab = {} - with gfile.GFile(data_path, mode="rb") as f: - counter = 0 - for line in f: - counter += 1 - if counter % 100000 == 0: - print(" processing line %d" % counter) - tokens = tokenizer(line) if tokenizer else basic_tokenizer(line) - for w in tokens: - word = re.sub(_DIGIT_RE, b"0", w) if normalize_digits else w - if word in vocab: - vocab[word] += 1 - else: - vocab[word] = 1 - vocab_list = _START_VOCAB + sorted(vocab, key=vocab.get, reverse=True) - if len(vocab_list) > max_vocabulary_size: - vocab_list = vocab_list[:max_vocabulary_size] - with gfile.GFile(vocabulary_path, mode="wb") as vocab_file: - for w in vocab_list: - vocab_file.write(w + b"\n") - else: - print("Vocabulary %s from data %s exists" % (vocabulary_path, data_path)) + """Create vocabulary file (if it does not exist yet) from data file. + + Data file is assumed to contain one sentence per line. Each sentence is + tokenized and digits are normalized (if normalize_digits is set). + Vocabulary contains the most-frequent tokens up to max_vocabulary_size. + We write it to vocabulary_path in a one-token-per-line format, so that later + token in the first line gets id=0, second line gets id=1, and so on. + + Parameters + ----------- + vocabulary_path : path where the vocabulary will be created. + data_path : data file that will be used to create vocabulary. + max_vocabulary_size : limit on the size of the created vocabulary. + tokenizer : a function to use to tokenize each data sentence. + if None, basic_tokenizer will be used. + normalize_digits : Boolean + if true, all digits are replaced by 0s. + + References + ---------- + - Code from ``/tensorflow/models/rnn/translation/data_utils.py`` + """ + if not gfile.Exists(vocabulary_path): + print("Creating vocabulary %s from data %s" % (vocabulary_path, data_path)) + vocab = {} + with gfile.GFile(data_path, mode="rb") as f: + counter = 0 + for line in f: + counter += 1 + if counter % 100000 == 0: + print(" processing line %d" % counter) + tokens = tokenizer(line) if tokenizer else basic_tokenizer(line) + for w in tokens: + word = re.sub(_DIGIT_RE, b"0", w) if normalize_digits else w + if word in vocab: + vocab[word] += 1 + else: + vocab[word] = 1 + vocab_list = _START_VOCAB + sorted(vocab, key=vocab.get, reverse=True) + if len(vocab_list) > max_vocabulary_size: + vocab_list = vocab_list[:max_vocabulary_size] + with gfile.GFile(vocabulary_path, mode="wb") as vocab_file: + for w in vocab_list: + vocab_file.write(w + b"\n") + else: + print("Vocabulary %s from data %s exists" % (vocabulary_path, data_path)) + def initialize_vocabulary(vocabulary_path): - """Initialize vocabulary from file, return the word_to_id (dictionary) - and id_to_word (list). - - We assume the vocabulary is stored one-item-per-line, so a file:\n - dog\n - cat\n - will result in a vocabulary {"dog": 0, "cat": 1}, and this function will - also return the reversed-vocabulary ["dog", "cat"]. - - Parameters - ----------- - vocabulary_path : path to the file containing the vocabulary. - - Returns - -------- - vocab : a dictionary - Word to id. A dictionary mapping string to integers. - rev_vocab : a list - Id to word. The reversed vocabulary (a list, which reverses the vocabulary mapping). - - Examples - --------- - >>> Assume 'test' contains - ... dog - ... cat - ... bird - >>> vocab, rev_vocab = tl.nlp.initialize_vocabulary("test") - >>> print(vocab) - >>> {b'cat': 1, b'dog': 0, b'bird': 2} - >>> print(rev_vocab) - >>> [b'dog', b'cat', b'bird'] - - Raises - ------- - ValueError : if the provided vocabulary_path does not exist. - """ - if gfile.Exists(vocabulary_path): - rev_vocab = [] - with gfile.GFile(vocabulary_path, mode="rb") as f: - rev_vocab.extend(f.readlines()) - rev_vocab = [tf.compat.as_bytes(line.strip()) for line in rev_vocab] - vocab = dict([(x, y) for (y, x) in enumerate(rev_vocab)]) - return vocab, rev_vocab - else: - raise ValueError("Vocabulary file %s not found.", vocabulary_path) + """Initialize vocabulary from file, return the word_to_id (dictionary) + and id_to_word (list). + + We assume the vocabulary is stored one-item-per-line, so a file:\n + dog\n + cat\n + will result in a vocabulary {"dog": 0, "cat": 1}, and this function will + also return the reversed-vocabulary ["dog", "cat"]. + + Parameters + ----------- + vocabulary_path : path to the file containing the vocabulary. + + Returns + -------- + vocab : a dictionary + Word to id. A dictionary mapping string to integers. + rev_vocab : a list + Id to word. The reversed vocabulary (a list, which reverses the vocabulary mapping). + + Examples + --------- + >>> Assume 'test' contains + ... dog + ... cat + ... bird + >>> vocab, rev_vocab = tl.nlp.initialize_vocabulary("test") + >>> print(vocab) + >>> {b'cat': 1, b'dog': 0, b'bird': 2} + >>> print(rev_vocab) + >>> [b'dog', b'cat', b'bird'] + + Raises + ------- + ValueError : if the provided vocabulary_path does not exist. + """ + if gfile.Exists(vocabulary_path): + rev_vocab = [] + with gfile.GFile(vocabulary_path, mode="rb") as f: + rev_vocab.extend(f.readlines()) + rev_vocab = [tf.compat.as_bytes(line.strip()) for line in rev_vocab] + vocab = dict([(x, y) for (y, x) in enumerate(rev_vocab)]) + return vocab, rev_vocab + else: + raise ValueError("Vocabulary file %s not found.", vocabulary_path) + def sentence_to_token_ids(sentence, vocabulary, tokenizer=None, normalize_digits=True, UNK_ID=3, _DIGIT_RE=re.compile(br"\d")): - """Convert a string to list of integers representing token-ids. - - For example, a sentence "I have a dog" may become tokenized into - ["I", "have", "a", "dog"] and with vocabulary {"I": 1, "have": 2, - "a": 4, "dog": 7"} this function will return [1, 2, 4, 7]. - - Parameters - ----------- - sentence : tensorflow.python.platform.gfile.GFile Object - The sentence in bytes format to convert to token-ids.\n - see basic_tokenizer(), data_to_token_ids() - vocabulary : a dictionary mapping tokens to integers. - tokenizer : a function to use to tokenize each sentence; - If None, basic_tokenizer will be used. - normalize_digits : Boolean - If true, all digits are replaced by 0s. - - Returns - -------- - A list of integers, the token-ids for the sentence. - """ - - if tokenizer: - words = tokenizer(sentence) - else: - words = basic_tokenizer(sentence) - if not normalize_digits: - return [vocabulary.get(w, UNK_ID) for w in words] - # Normalize digits by 0 before looking words up in the vocabulary. - return [vocabulary.get(re.sub(_DIGIT_RE, b"0", w), UNK_ID) for w in words] + """Convert a string to list of integers representing token-ids. + + For example, a sentence "I have a dog" may become tokenized into + ["I", "have", "a", "dog"] and with vocabulary {"I": 1, "have": 2, + "a": 4, "dog": 7"} this function will return [1, 2, 4, 7]. + + Parameters + ----------- + sentence : tensorflow.python.platform.gfile.GFile Object + The sentence in bytes format to convert to token-ids.\n + see basic_tokenizer(), data_to_token_ids() + vocabulary : a dictionary mapping tokens to integers. + tokenizer : a function to use to tokenize each sentence; + If None, basic_tokenizer will be used. + normalize_digits : Boolean + If true, all digits are replaced by 0s. + + Returns + -------- + A list of integers, the token-ids for the sentence. + """ + + if tokenizer: + words = tokenizer(sentence) + else: + words = basic_tokenizer(sentence) + if not normalize_digits: + return [vocabulary.get(w, UNK_ID) for w in words] + # Normalize digits by 0 before looking words up in the vocabulary. + return [vocabulary.get(re.sub(_DIGIT_RE, b"0", w), UNK_ID) for w in words] + def data_to_token_ids(data_path, target_path, vocabulary_path, tokenizer=None, normalize_digits=True, UNK_ID=3, _DIGIT_RE=re.compile(br"\d")): - """Tokenize data file and turn into token-ids using given vocabulary file. - - This function loads data line-by-line from data_path, calls the above - sentence_to_token_ids, and saves the result to target_path. See comment - for sentence_to_token_ids on the details of token-ids format. - - Parameters - ----------- - data_path : path to the data file in one-sentence-per-line format. - target_path : path where the file with token-ids will be created. - vocabulary_path : path to the vocabulary file. - tokenizer : a function to use to tokenize each sentence; - if None, basic_tokenizer will be used. - normalize_digits : Boolean; if true, all digits are replaced by 0s. - - References - ---------- - - Code from ``/tensorflow/models/rnn/translation/data_utils.py`` - """ - if not gfile.Exists(target_path): - print("Tokenizing data in %s" % data_path) - vocab, _ = initialize_vocabulary(vocabulary_path) - with gfile.GFile(data_path, mode="rb") as data_file: - with gfile.GFile(target_path, mode="w") as tokens_file: - counter = 0 - for line in data_file: - counter += 1 - if counter % 100000 == 0: - print(" tokenizing line %d" % counter) - token_ids = sentence_to_token_ids(line, vocab, tokenizer, - normalize_digits, UNK_ID=UNK_ID, - _DIGIT_RE=_DIGIT_RE) - tokens_file.write(" ".join([str(tok) for tok in token_ids]) + "\n") - else: - print("Target path %s exists" % target_path) + """Tokenize data file and turn into token-ids using given vocabulary file. + + This function loads data line-by-line from data_path, calls the above + sentence_to_token_ids, and saves the result to target_path. See comment + for sentence_to_token_ids on the details of token-ids format. + + Parameters + ----------- + data_path : path to the data file in one-sentence-per-line format. + target_path : path where the file with token-ids will be created. + vocabulary_path : path to the vocabulary file. + tokenizer : a function to use to tokenize each sentence; + if None, basic_tokenizer will be used. + normalize_digits : Boolean; if true, all digits are replaced by 0s. + + References + ---------- + - Code from ``/tensorflow/models/rnn/translation/data_utils.py`` + """ + if not gfile.Exists(target_path): + print("Tokenizing data in %s" % data_path) + vocab, _ = initialize_vocabulary(vocabulary_path) + with gfile.GFile(data_path, mode="rb") as data_file: + with gfile.GFile(target_path, mode="w") as tokens_file: + counter = 0 + for line in data_file: + counter += 1 + if counter % 100000 == 0: + print(" tokenizing line %d" % counter) + token_ids = sentence_to_token_ids(line, vocab, tokenizer, + normalize_digits, UNK_ID=UNK_ID, + _DIGIT_RE=_DIGIT_RE) + tokens_file.write(" ".join([str(tok) for tok in token_ids]) + "\n") + else: + print("Target path %s exists" % target_path) + + +# Metric +import subprocess +import tempfile +from six.moves import urllib + + +def moses_multi_bleu(hypotheses, references, lowercase=False): # tl.nlp + """Calculate the bleu score for hypotheses and references + using the MOSES ulti-bleu.perl script. + + Parameters + ------------ + hypotheses : A numpy array of strings where each string is a single example. + references : A numpy array of strings where each string is a single example. + lowercase : If true, pass the "-lc" flag to the multi-bleu script + + Examples + --------- + >>> hypotheses = ["a bird is flying on the sky"] + >>> references = ["two birds are flying on the sky", "a bird is on the top of the tree", "an airplane is on the sky",] + >>> score = tl.nlp.moses_multi_bleu(hypotheses, references) + + Returns + -------- + The BLEU score as a float32 value. + + References + ---------- + - `Google/seq2seq/metric/bleu `_ + """ + + if np.size(hypotheses) == 0: + return np.float32(0.0) + + # Get MOSES multi-bleu script + try: + multi_bleu_path, _ = urllib.request.urlretrieve( + "https://raw.githubusercontent.com/moses-smt/mosesdecoder/" + "master/scripts/generic/multi-bleu.perl") + os.chmod(multi_bleu_path, 0o755) + except: # pylint: disable=W0702 + tf.logging.info("Unable to fetch multi-bleu.perl script, using local.") + metrics_dir = os.path.dirname(os.path.realpath(__file__)) + bin_dir = os.path.abspath(os.path.join(metrics_dir, "..", "..", "bin")) + multi_bleu_path = os.path.join(bin_dir, "tools/multi-bleu.perl") + + # Dump hypotheses and references to tempfiles + hypothesis_file = tempfile.NamedTemporaryFile() + hypothesis_file.write("\n".join(hypotheses).encode("utf-8")) + hypothesis_file.write(b"\n") + hypothesis_file.flush() + reference_file = tempfile.NamedTemporaryFile() + reference_file.write("\n".join(references).encode("utf-8")) + reference_file.write(b"\n") + reference_file.flush() + + # Calculate BLEU using multi-bleu script + with open(hypothesis_file.name, "r") as read_pred: + bleu_cmd = [multi_bleu_path] + if lowercase: + bleu_cmd += ["-lc"] + bleu_cmd += [reference_file.name] + try: + bleu_out = subprocess.check_output( + bleu_cmd, stdin=read_pred, stderr=subprocess.STDOUT) + bleu_out = bleu_out.decode("utf-8") + bleu_score = re.search(r"BLEU = (.+?),", bleu_out).group(1) + bleu_score = float(bleu_score) + except subprocess.CalledProcessError as error: + if error.output is not None: + tf.logging.warning("multi-bleu.perl script returned non-zero exit code") + tf.logging.warning(error.output) + bleu_score = np.float32(0.0) + + # Close temp files + hypothesis_file.close() + reference_file.close() + + return np.float32(bleu_score) diff --git a/tensorlayer/ops.py b/tensorlayer/ops.py index 608799c6..012d1b68 100644 --- a/tensorlayer/ops.py +++ b/tensorlayer/ops.py @@ -1,40 +1,76 @@ #! /usr/bin/python -# -*- coding: utf8 -*- +# -*- coding: utf-8 -*- import tensorflow as tf +import tensorlayer as tl import os +import subprocess import sys from sys import platform as _platform +from sys import exit as _exit -def exit_tf(sess=None): - """Close tensorboard and nvidia-process if available +def exit_tf(sess=None, port=6006): + """Close TensorFlow session, TensorBoard and Nvidia-process if available. Parameters ---------- sess : a session instance of TensorFlow TensorFlow session + tb_port : an integer + TensorBoard port you want to close, 6006 as default. """ - text = "[tl] Close tensorboard and nvidia-process if available" - sess.close() + text = "[TL] Close tensorboard and nvidia-process if available" + text2 = "[TL] Close tensorboard and nvidia-process not yet supported by this function (tl.ops.exit_tf) on " + if sess != None: + sess.close() # import time # time.sleep(2) if _platform == "linux" or _platform == "linux2": print('linux: %s' % text) os.system('nvidia-smi') - os.system('fuser 6006/tcp -k') # kill tensorboard 6006 + os.system('fuser '+ port +'/tcp -k') # kill tensorboard 6006 os.system("nvidia-smi | grep python |awk '{print $3}'|xargs kill") # kill all nvidia-smi python process + _exit() elif _platform == "darwin": print('OS X: %s' % text) - os.system("lsof -i tcp:6006 | grep -v PID | awk '{print $2}' | xargs kill") # kill tensorboard 6006 + subprocess.Popen("lsof -i tcp:"+ str(port) +" | grep -v PID | awk '{print $2}' | xargs kill", shell=True) # kill tensorboard elif _platform == "win32": - print('Windows: %s' % text) + print(text2 + "Windows") + # TODO else: - print(_platform) - exit() + print(text2 + _platform) + +def open_tb(logdir='/tmp/tensorflow', port=6006): + """Open Tensorboard. + + Parameters + ---------- + logdir : a string + Directory where your tensorboard logs are saved + port : an integer + TensorBoard port you want to open, 6006 is tensorboard default + """ + text = "[TL] Open tensorboard, go to localhost:" + str(port) + " to access" + text2 = " not yet supported by this function (tl.ops.open_tb)" + + if not tl.files.exists_or_mkdir(logdir, verbose=False): + print("[TL] Log reportory was created at %s" % logdir) + + if _platform == "linux" or _platform == "linux2": + print('linux %s' % text2) + # TODO + elif _platform == "darwin": + print('OS X: %s' % text) + subprocess.Popen(sys.prefix + " | python -m tensorflow.tensorboard --logdir=" + logdir + " --port=" + str(port), shell=True) # open tensorboard in localhost:6006/ or whatever port you chose + elif _platform == "win32": + print('Windows%s' % text2) + # TODO + else: + print(_platform + text2) def clear_all(printable=True): """Clears all the placeholder variables of keep prob, @@ -92,13 +128,26 @@ def set_gpu_fraction(sess=None, gpu_fraction=0.3): ---------- - `TensorFlow using GPU `_ """ - print(" tensorlayer: GPU MEM Fraction %f" % gpu_fraction) + print("[TL]: GPU MEM Fraction %f" % gpu_fraction) gpu_options = tf.GPUOptions(per_process_gpu_memory_fraction=gpu_fraction) sess = tf.Session(config = tf.ConfigProto(gpu_options = gpu_options)) return sess +def setlinebuf(): + """Set buffer mode to _IOLBF for stdout. + When running in container, or other environments where stdout is redirected, + the default buffer behavior will seriously delay the message written by `print`. + TODO: this method should be called automatically by default. + + References + ----------- + - ``_ + - ``_ + - `man setlinebuf `_ + """ + sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 1) def disable_print(): @@ -184,10 +233,10 @@ def get_site_packages_directory(): import site try: loc = site.getsitepackages() - print(" tl.ops : site-packages in ", loc) + print("[TL] tl.ops : site-packages in ", loc) return loc except: - print(" tl.ops : Cannot find package dir from virtual environment") + print("[TL] tl.ops : Cannot find package dir from virtual environment") return False @@ -196,7 +245,7 @@ def empty_trash(): """Empty trash folder. """ - text = "[tl] Empty the trash" + text = "[TL] Empty the trash" if _platform == "linux" or _platform == "linux2": print('linux: %s' % text) os.system("rm -rf ~/.local/share/Trash/*") diff --git a/tensorlayer/prepro.py b/tensorlayer/prepro.py index 0503b869..11272a1e 100644 --- a/tensorlayer/prepro.py +++ b/tensorlayer/prepro.py @@ -1,5 +1,5 @@ #! /usr/bin/python -# -*- coding: utf8 -*- +# -*- coding: utf-8 -*- import tensorflow as tf @@ -30,17 +30,20 @@ from skimage import exposure import skimage +from multiprocessing import Pool + # linalg https://docs.scipy.org/doc/scipy/reference/linalg.html # ndimage https://docs.scipy.org/doc/scipy/reference/ndimage.html ## Threading -def threading_data(data=None, fn=None, **kwargs): +def threading_data(data=None, fn=None, thread_count=None, **kwargs): """Return a batch of result by given data. Usually be used for data augmentation. Parameters ----------- - data : numpy array or zip of numpy array, see Examples below. + data : numpy array, file names and etc, see Examples below. + thread_count : the number of threads to use fn : the function for data processing. more args : the args for fn, see Examples below. @@ -62,6 +65,15 @@ def threading_data(data=None, fn=None, **kwargs): >>> tl.visualize.images2d(images=np.asarray(X_), second=0.01, saveable=True, name='after', dtype=None) >>> tl.visualize.images2d(images=np.asarray(Y_), second=0.01, saveable=True, name='before', dtype=None) + - Single array split across ``thread_count`` threads (e.g. functions with ``multi``) + >>> X, Y --> [batch_size, row, col, 1] greyscale + >>> data = threading_data(X, zoom_multi, 8, zoom_range=[0.5, 1], is_random=True) + ... data --> [batch_size, 2, row, col, 1] + >>> X_, Y_ = data.transpose((1,0,2,3,4)) + ... X_, Y_ --> [batch_size, row, col, 1] + >>> tl.visualize.images2d(images=np.asarray(X_), second=0.01, saveable=True, name='after', dtype=None) + >>> tl.visualize.images2d(images=np.asarray(Y_), second=0.01, saveable=True, name='before', dtype=None) + - Customized function for image segmentation >>> def distort_img(data): ... x, y = data @@ -87,58 +99,47 @@ def apply_fn(results, i, data, kwargs): results[i] = fn(data, **kwargs) ## start multi-threaded reading. - results = [None] * len(data) ## preallocate result list - threads = [] - for i in range(len(data)): - t = threading.Thread( - name='threading_and_return', - target=apply_fn, - args=(results, i, data[i], kwargs) - ) - t.start() - threads.append(t) + if thread_count is None: # by Milo + results = [None] * len(data) ## preallocate result list + threads = [] + for i in range(len(data)): + t = threading.Thread( + name='threading_and_return', + target=apply_fn, + args=(results, i, data[i], kwargs) + ) + t.start() + threads.append(t) + else: # by geometrikal + divs = np.linspace(0, len(data), thread_count + 1) + divs = np.round(divs).astype(int) + results = [None] * thread_count + threads = [] + for i in range(thread_count): + t = threading.Thread( + name='threading_and_return', + target=apply_fn, + args=(results, i, data[divs[i]:divs[i + 1]], kwargs) + ) + t.start() + threads.append(t) ## wait for all threads to complete for t in threads: t.join() - return np.asarray(results) - - ## old implementation - # define function for threading - # def function(q, i, data, kwargs): - # result = fn(data, **kwargs) - # q.put([i, result]) - # ## start threading - # q = queue.Queue() - # threads = [] - # for i in range(len(data)): - # t = threading.Thread( - # name='threading_and_return', - # target=function, - # args=(q, i, data[i], kwargs) - # ) - # t.start() - # threads.append(t) - # - # ## wait for all threads to complete - # for t in threads: - # t.join() - # - # ## get results - # results = [] - # for i in range(len(data)): - # result = q.get() - # results.append(result) - # results = sorted(results) - # for i in range(len(results)): - # results[i] = results[i][1] - # return np.asarray(results) + if thread_count is None: + try: + return np.asarray(results) + except: # if dim don't match + return results + else: + return np.concatenate(results) ## Image def rotation(x, rg=20, is_random=False, row_index=0, col_index=1, channel_index=2, - fill_mode='nearest', cval=0.): + fill_mode='nearest', cval=0., order=1): """Rotate an image randomly or non-randomly. Parameters @@ -157,6 +158,8 @@ def rotation(x, rg=20, is_random=False, row_index=0, col_index=1, channel_index= - `scipy ndimage affine_transform `_ cval : scalar, optional Value used for points outside the boundaries of the input if mode='constant'. Default is 0.0 + order : int, optional + The order of interpolation. The order has to be in the range 0-5. See ``apply_transform``. - `scipy ndimage affine_transform `_ @@ -176,11 +179,11 @@ def rotation(x, rg=20, is_random=False, row_index=0, col_index=1, channel_index= h, w = x.shape[row_index], x.shape[col_index] transform_matrix = transform_matrix_offset_center(rotation_matrix, h, w) - x = apply_transform(x, transform_matrix, channel_index, fill_mode, cval) + x = apply_transform(x, transform_matrix, channel_index, fill_mode, cval, order) return x def rotation_multi(x, rg=20, is_random=False, row_index=0, col_index=1, channel_index=2, - fill_mode='nearest', cval=0.): + fill_mode='nearest', cval=0., order=1): """Rotate multiple images with the same arguments, randomly or non-randomly. Usually be used for image segmentation which x=[X, Y], X and Y should be matched. @@ -209,7 +212,7 @@ def rotation_multi(x, rg=20, is_random=False, row_index=0, col_index=1, channel_ transform_matrix = transform_matrix_offset_center(rotation_matrix, h, w) results = [] for data in x: - results.append( apply_transform(data, transform_matrix, channel_index, fill_mode, cval)) + results.append( apply_transform(data, transform_matrix, channel_index, fill_mode, cval, order)) return np.asarray(results) # crop @@ -220,9 +223,9 @@ def crop(x, wrg, hrg, is_random=False, row_index=0, col_index=1, channel_index=2 ---------- x : numpy array An image with dimension of [row, col, channel] (default). - wrg : float - Size of weight. - hrg : float + wrg : int + Size of width. + hrg : int Size of height. is_random : boolean, default False If True, randomly crop, else central crop. @@ -278,7 +281,7 @@ def crop_multi(x, wrg, hrg, is_random=False, row_index=0, col_index=1, channel_i return np.asarray(results) # flip -def flip_axis(x, axis, is_random=False): +def flip_axis(x, axis=1, is_random=False): """Flip the axis of an image, such as flip left and right, up and down, randomly or non-randomly, Parameters @@ -347,7 +350,7 @@ def flip_axis_multi(x, axis, is_random=False): # shift def shift(x, wrg=0.1, hrg=0.1, is_random=False, row_index=0, col_index=1, channel_index=2, - fill_mode='nearest', cval=0.): + fill_mode='nearest', cval=0., order=1): """Shift an image randomly or non-randomly. Parameters @@ -368,6 +371,8 @@ def shift(x, wrg=0.1, hrg=0.1, is_random=False, row_index=0, col_index=1, channe - `scipy ndimage affine_transform `_ cval : scalar, optional Value used for points outside the boundaries of the input if mode='constant'. Default is 0.0. + order : int, optional + The order of interpolation. The order has to be in the range 0-5. See ``apply_transform``. - `scipy ndimage affine_transform `_ """ @@ -382,11 +387,11 @@ def shift(x, wrg=0.1, hrg=0.1, is_random=False, row_index=0, col_index=1, channe [0, 0, 1]]) transform_matrix = translation_matrix # no need to do offset - x = apply_transform(x, transform_matrix, channel_index, fill_mode, cval) + x = apply_transform(x, transform_matrix, channel_index, fill_mode, cval, order) return x def shift_multi(x, wrg=0.1, hrg=0.1, is_random=False, row_index=0, col_index=1, channel_index=2, - fill_mode='nearest', cval=0.): + fill_mode='nearest', cval=0., order=1): """Shift images with the same arguments, randomly or non-randomly. Usually be used for image segmentation which x=[X, Y], X and Y should be matched. @@ -409,12 +414,12 @@ def shift_multi(x, wrg=0.1, hrg=0.1, is_random=False, row_index=0, col_index=1, transform_matrix = translation_matrix # no need to do offset results = [] for data in x: - results.append( apply_transform(data, transform_matrix, channel_index, fill_mode, cval)) + results.append( apply_transform(data, transform_matrix, channel_index, fill_mode, cval, order)) return np.asarray(results) # shear def shear(x, intensity=0.1, is_random=False, row_index=0, col_index=1, channel_index=2, - fill_mode='nearest', cval=0.): + fill_mode='nearest', cval=0., order=1): """Shear an image randomly or non-randomly. Parameters @@ -434,8 +439,14 @@ def shear(x, intensity=0.1, is_random=False, row_index=0, col_index=1, channel_i - `scipy ndimage affine_transform `_ cval : scalar, optional Value used for points outside the boundaries of the input if mode='constant'. Default is 0.0. + order : int, optional + The order of interpolation. The order has to be in the range 0-5. See ``apply_transform``. - `scipy ndimage affine_transform `_ + + References + ----------- + - `Affine transformation `_ """ if is_random: shear = np.random.uniform(-intensity, intensity) @@ -447,11 +458,11 @@ def shear(x, intensity=0.1, is_random=False, row_index=0, col_index=1, channel_i h, w = x.shape[row_index], x.shape[col_index] transform_matrix = transform_matrix_offset_center(shear_matrix, h, w) - x = apply_transform(x, transform_matrix, channel_index, fill_mode, cval) + x = apply_transform(x, transform_matrix, channel_index, fill_mode, cval, order) return x def shear_multi(x, intensity=0.1, is_random=False, row_index=0, col_index=1, channel_index=2, - fill_mode='nearest', cval=0.): + fill_mode='nearest', cval=0., order=1): """Shear images with the same arguments, randomly or non-randomly. Usually be used for image segmentation which x=[X, Y], X and Y should be matched. @@ -459,7 +470,7 @@ def shear_multi(x, intensity=0.1, is_random=False, row_index=0, col_index=1, cha ----------- x : list of numpy array List of images with dimension of [n_images, row, col, channel] (default). - others : see ``shear``. + others : see ``tl.prepro.shear``. """ if is_random: shear = np.random.uniform(-intensity, intensity) @@ -473,7 +484,77 @@ def shear_multi(x, intensity=0.1, is_random=False, row_index=0, col_index=1, cha transform_matrix = transform_matrix_offset_center(shear_matrix, h, w) results = [] for data in x: - results.append( apply_transform(data, transform_matrix, channel_index, fill_mode, cval)) + results.append( apply_transform(data, transform_matrix, channel_index, fill_mode, cval, order)) + return np.asarray(results) + +def shear2(x, shear=(0.1, 0.1), is_random=False, row_index=0, col_index=1, channel_index=2, + fill_mode='nearest', cval=0., order=1): + """Shear an image randomly or non-randomly. + + Parameters + ----------- + x : numpy array + An image with dimension of [row, col, channel] (default). + shear : tuple of two floats + Percentage of shear for height and width direction (0, 1). + is_random : boolean, default False + If True, randomly shear. + row_index, col_index, channel_index : int + Index of row, col and channel, default (0, 1, 2), for theano (1, 2, 0). + fill_mode : string + Method to fill missing pixel, default ‘nearest’, more options ‘constant’, ‘reflect’ or ‘wrap’. + + - `scipy ndimage affine_transform `_ + cval : scalar, optional + Value used for points outside the boundaries of the input if mode='constant'. Default is 0.0. + order : int, optional + The order of interpolation. The order has to be in the range 0-5. See ``apply_transform``. + + - `scipy ndimage affine_transform `_ + + References + ----------- + - `Affine transformation `_ + """ + assert len(shear) == 2, "shear should be tuple of 2 floats, or you want to use tl.prepro.shear rather than tl.prepro.shear2 ?" + if is_random: + shear[0] = np.random.uniform(-shear[0], shear[0]) + shear[1] = np.random.uniform(-shear[1], shear[1]) + + shear_matrix = np.array([[1, shear[0], 0], + [shear[1], 1, 0], + [0, 0, 1]]) + + h, w = x.shape[row_index], x.shape[col_index] + transform_matrix = transform_matrix_offset_center(shear_matrix, h, w) + x = apply_transform(x, transform_matrix, channel_index, fill_mode, cval, order) + return x + +def shear_multi2(x, shear=(0.1, 0.1), is_random=False, row_index=0, col_index=1, channel_index=2, + fill_mode='nearest', cval=0., order=1): + """Shear images with the same arguments, randomly or non-randomly. + Usually be used for image segmentation which x=[X, Y], X and Y should be matched. + + Parameters + ----------- + x : list of numpy array + List of images with dimension of [n_images, row, col, channel] (default). + others : see ``tl.prepro.shear2``. + """ + assert len(shear) == 2, "shear should be tuple of 2 floats, or you want to use tl.prepro.shear_multi rather than tl.prepro.shear_multi2 ?" + if is_random: + shear[0] = np.random.uniform(-shear[0], shear[0]) + shear[1] = np.random.uniform(-shear[1], shear[1]) + + shear_matrix = np.array([[1, shear[0], 0], + [shear[1], 1, 0], + [0, 0, 1]]) + + h, w = x[0].shape[row_index], x[0].shape[col_index] + transform_matrix = transform_matrix_offset_center(shear_matrix, h, w) + results = [] + for data in x: + results.append( apply_transform(data, transform_matrix, channel_index, fill_mode, cval, order)) return np.asarray(results) # swirl @@ -661,7 +742,7 @@ def elastic_transform_multi(x, alpha, sigma, mode="constant", cval=0, is_random= # zoom def zoom(x, zoom_range=(0.9, 1.1), is_random=False, row_index=0, col_index=1, channel_index=2, - fill_mode='nearest', cval=0.): + fill_mode='nearest', cval=0., order=1): """Zoom in and out of a single image, randomly or non-randomly. Parameters @@ -670,7 +751,7 @@ def zoom(x, zoom_range=(0.9, 1.1), is_random=False, row_index=0, col_index=1, ch An image with dimension of [row, col, channel] (default). zoom_range : list or tuple - If is_random=False, (h, w) are the fixed zoom factor for row and column axies, factor small than one is zoom in. - - If is_random=True, (min zoom out, max zoom out) for x and y with different random zoom in/out factor. + - If is_random=True, it is (min zoom out, max zoom out) for x and y with different random zoom in/out factor. e.g (0.5, 1) zoom in 1~2 times. is_random : boolean, default False If True, randomly zoom. @@ -682,6 +763,8 @@ def zoom(x, zoom_range=(0.9, 1.1), is_random=False, row_index=0, col_index=1, ch - `scipy ndimage affine_transform `_ cval : scalar, optional Value used for points outside the boundaries of the input if mode='constant'. Default is 0.0. + order : int, optional + The order of interpolation. The order has to be in the range 0-5. See ``apply_transform``. - `scipy ndimage affine_transform `_ """ @@ -703,11 +786,11 @@ def zoom(x, zoom_range=(0.9, 1.1), is_random=False, row_index=0, col_index=1, ch h, w = x.shape[row_index], x.shape[col_index] transform_matrix = transform_matrix_offset_center(zoom_matrix, h, w) - x = apply_transform(x, transform_matrix, channel_index, fill_mode, cval) + x = apply_transform(x, transform_matrix, channel_index, fill_mode, cval, order) return x def zoom_multi(x, zoom_range=(0.9, 1.1), is_random=False, - row_index=0, col_index=1, channel_index=2, fill_mode='nearest', cval=0.): + row_index=0, col_index=1, channel_index=2, fill_mode='nearest', cval=0., order=1): """Zoom in and out of images with the same arguments, randomly or non-randomly. Usually be used for image segmentation which x=[X, Y], X and Y should be matched. @@ -740,7 +823,7 @@ def zoom_multi(x, zoom_range=(0.9, 1.1), is_random=False, # return x results = [] for data in x: - results.append( apply_transform(data, transform_matrix, channel_index, fill_mode, cval)) + results.append( apply_transform(data, transform_matrix, channel_index, fill_mode, cval, order)) return np.asarray(results) # image = tf.image.random_brightness(image, max_delta=32. / 255.) @@ -757,7 +840,7 @@ def brightness(x, gamma=1, gain=1, is_random=False): x : numpy array An image with dimension of [row, col, channel] (default). gamma : float, small than 1 means brighter. - Non negative real number. Default value is 1. + Non negative real number. Default value is 1, smaller means brighter. - If is_random is True, gamma in a range of (1-gamma, 1+gamma). gain : float @@ -793,19 +876,185 @@ def brightness_multi(x, gamma=1, gain=1, is_random=False): results.append( exposure.adjust_gamma(data, gamma, gain) ) return np.asarray(results) +# illumination +def illumination(x, gamma=1., contrast=1., saturation=1., is_random=False): + """Perform illumination augmentation for a single image, randomly or non-randomly. -# contrast -def constant(x, cutoff=0.5, gain=10, inv=False, is_random=False): - # TODO - x = exposure.adjust_sigmoid(x, cutoff=cutoff, gain=gain, inv=inv) - return x + Parameters + ----------- + x : numpy array + an image with dimension of [row, col, channel] (default). + gamma : change brightness (the same with ``tl.prepro.brightness``) + - if is_random=False, one float number, small than one means brighter, greater than one means darker. + - if is_random=True, tuple of two float numbers, (min, max). + contrast : change contrast + - if is_random=False, one float number, small than one means blur. + - if is_random=True, tuple of two float numbers, (min, max). + saturation : change saturation + - if is_random=False, one float number, small than one means unsaturation. + - if is_random=True, tuple of two float numbers, (min, max). + is_random : whether the parameters are randomly set. + + Examples + --------- + - Random + >>> x = illumination(x, gamma=(0.5, 5.0), contrast=(0.3, 1.0), saturation=(0.7, 1.0), is_random=True) + - Non-random + >>> x = illumination(x, 0.5, 0.6, 0.8, is_random=False) + """ + from PIL import Image, ImageEnhance + + if is_random: + try: + assert len(gamma) == len(contrast) == len(saturation) == 2, "if is_random = True, the arguments are (min, max)" + except: + raise Exception("if is_random = True, the arguments are (min, max)") + ## random change brightness # small --> brighter + illum_settings = np.random.randint(0,3) # 0-brighter, 1-darker, 2 keep normal + + if illum_settings == 0: # brighter + gamma = np.random.uniform(gamma[0], 1.0) # (.5, 1.0) + elif illum_settings == 1: # darker + gamma = np.random.uniform(1.0, gamma[1])# (1.0, 5.0) + else: + gamma = 1 + im_ = brightness(x, gamma=gamma, gain=1, is_random=False) + + # print("using contrast and saturation") + image = Image.fromarray(im_) # array -> PIL + contrast_adjust = ImageEnhance.Contrast(image) + image = contrast_adjust.enhance(np.random.uniform(contrast[0], contrast[1]))#0.3,0.9)) + + saturation_adjust = ImageEnhance.Color(image) + image = saturation_adjust.enhance(np.random.uniform(saturation[0], saturation[1]))# (0.7,1.0)) + im_ = np.array(image) # PIL -> array + else: + im_ = brightness(x, gamma=gamma, gain=1, is_random=False) + image = Image.fromarray(im_) # array -> PIL + contrast_adjust = ImageEnhance.Contrast(image) + image = contrast_adjust.enhance(contrast) + + saturation_adjust = ImageEnhance.Color(image) + image = saturation_adjust.enhance(saturation) + im_ = np.array(image) # PIL -> array + return np.asarray(im_) + +# hue +def rgb_to_hsv(rgb): + """ Input RGB image [0~255] return HSV image [0~1]. + + Parameters + ------------- + rgb : should be a numpy arrays with values between 0 and 255. + """ + # Translated from source of colorsys.rgb_to_hsv + # r,g,b should be a numpy arrays with values between 0 and 255 + # rgb_to_hsv returns an array of floats between 0.0 and 1.0. + rgb = rgb.astype('float') + hsv = np.zeros_like(rgb) + # in case an RGBA array was passed, just copy the A channel + hsv[..., 3:] = rgb[..., 3:] + r, g, b = rgb[..., 0], rgb[..., 1], rgb[..., 2] + maxc = np.max(rgb[..., :3], axis=-1) + minc = np.min(rgb[..., :3], axis=-1) + hsv[..., 2] = maxc + mask = maxc != minc + hsv[mask, 1] = (maxc - minc)[mask] / maxc[mask] + rc = np.zeros_like(r) + gc = np.zeros_like(g) + bc = np.zeros_like(b) + rc[mask] = (maxc - r)[mask] / (maxc - minc)[mask] + gc[mask] = (maxc - g)[mask] / (maxc - minc)[mask] + bc[mask] = (maxc - b)[mask] / (maxc - minc)[mask] + hsv[..., 0] = np.select( + [r == maxc, g == maxc], [bc - gc, 2.0 + rc - bc], default=4.0 + gc - rc) + hsv[..., 0] = (hsv[..., 0] / 6.0) % 1.0 + return hsv + +def hsv_to_rgb(hsv): + """ Input HSV image [0~1] return RGB image [0~255]. + + Parameters + ------------- + hsv : should be a numpy arrays with values between 0.0 and 1.0 + """ + # Translated from source of colorsys.hsv_to_rgb + # h,s should be a numpy arrays with values between 0.0 and 1.0 + # v should be a numpy array with values between 0.0 and 255.0 + # hsv_to_rgb returns an array of uints between 0 and 255. + rgb = np.empty_like(hsv) + rgb[..., 3:] = hsv[..., 3:] + h, s, v = hsv[..., 0], hsv[..., 1], hsv[..., 2] + i = (h * 6.0).astype('uint8') + f = (h * 6.0) - i + p = v * (1.0 - s) + q = v * (1.0 - s * f) + t = v * (1.0 - s * (1.0 - f)) + i = i % 6 + conditions = [s == 0.0, i == 1, i == 2, i == 3, i == 4, i == 5] + rgb[..., 0] = np.select(conditions, [v, q, p, p, t, v], default=v) + rgb[..., 1] = np.select(conditions, [v, v, v, q, p, p], default=t) + rgb[..., 2] = np.select(conditions, [v, p, t, v, v, q], default=p) + return rgb.astype('uint8') + + +def adjust_hue(im, hout=0.66, is_offset=True, is_clip=True, is_random=False): + """ Adjust hue of an RGB image. This is a convenience method that converts an RGB image to float representation, converts it to HSV, add an offset to the hue channel, converts back to RGB and then back to the original data type. + For TF, see `tf.image.adjust_hue `_ and `tf.image.random_hue `_. + + Parameters + ----------- + im : should be a numpy arrays with values between 0 and 255. + hout : float. + - If is_offset is False, set all hue values to this value. 0 is red; 0.33 is green; 0.66 is blue. + - If is_offset is True, add this value as the offset to the hue channel. + is_offset : boolean, default True. + is_clip : boolean, default True. + - If True, set negative hue values to 0. + is_random : boolean, default False. + + Examples + --------- + - Random, add a random value between -0.2 and 0.2 as the offset to every hue values. + >>> im_hue = tl.prepro.adjust_hue(image, hout=0.2, is_offset=True, is_random=False) + + - Non-random, make all hue to green. + >>> im_green = tl.prepro.adjust_hue(image, hout=0.66, is_offset=False, is_random=False) + + References + ----------- + - `tf.image.random_hue `_. + - `tf.image.adjust_hue `_. + - `StackOverflow: Changing image hue with python PIL `_. + """ + hsv = rgb_to_hsv(im) + if is_random: + hout = np.random.uniform(-hout, hout) + + if is_offset: + hsv[...,0] += hout + else: + hsv[...,0] = hout + + if is_clip: + hsv[...,0] = np.clip(hsv[...,0], 0, np.inf) # Hao : can remove green dots + + rgb = hsv_to_rgb(hsv) + return rgb -def constant_multi(): - #TODO - pass + +# # contrast +# def constant(x, cutoff=0.5, gain=10, inv=False, is_random=False): +# # TODO +# x = exposure.adjust_sigmoid(x, cutoff=cutoff, gain=gain, inv=inv) +# return x +# +# def constant_multi(): +# #TODO +# pass # resize -def imresize(x, size=[100, 100], interp='bilinear', mode=None): +def imresize(x, size=[100, 100], interp='bicubic', mode=None): """Resize an image by given output size and method. Warning, this function will rescale the value to [0, 255]. @@ -841,6 +1090,36 @@ def imresize(x, size=[100, 100], interp='bilinear', mode=None): else: raise Exception("Unsupported channel %d" % x.shape[-1]) +# value scale +def pixel_value_scale(im, val=0.9, clip=[], is_random=False): + """Scales each value in the pixels of the image. + + Parameters + ----------- + im : numpy array for one image. + val : float. + - If is_random=False, multiply this value with all pixels. + - If is_random=True, multiply a value between [1-val, 1+val] with all pixels. + + Examples + ---------- + - Random + >>> im = pixel_value_scale(im, 0.1, [0, 255], is_random=True) + + - Non-random + >>> im = pixel_value_scale(im, 0.9, [0, 255], is_random=False) + """ + if is_random: + scale = 1 + np.random.uniform(-val, val) + im = im * scale + else: + im = im * val + + if len(clip) == 2: + im = np.clip(im, clip[0], clip[1]) + + return im + # normailization def samplewise_norm(x, rescale=None, samplewise_center=False, samplewise_std_normalization=False, channel_index=2, epsilon=1e-7): @@ -934,11 +1213,11 @@ def zca_whitening(x, principal_components): An image with dimension of [row, col, channel] (default). principal_components : matrix from ``get_zca_whitening_principal_components_img``. """ - # flatx = np.reshape(x, (x.size)) - print(principal_components.shape, x.shape) # ((28160, 28160), (160, 176, 1)) + flatx = np.reshape(x, (x.size)) + # print(principal_components.shape, x.shape) # ((28160, 28160), (160, 176, 1)) # flatx = np.reshape(x, (x.shape)) # flatx = np.reshape(x, (x.shape[0], )) - print(flatx.shape) # (160, 176, 1) + # print(flatx.shape) # (160, 176, 1) whitex = np.dot(flatx, principal_components) x = np.reshape(whitex, (x.shape[0], x.shape[1], x.shape[2])) return x @@ -988,7 +1267,7 @@ def channel_shift(x, intensity, is_random=False, channel_index=2): # x = np.rollaxis(x, 0, channel_index+1) # return x -def channel_shift_multi(x, intensity, channel_index=2): +def channel_shift_multi(x, intensity, is_random=False, channel_index=2): """Shift the channels of images with the same arguments, randomly or non-randomly, see `numpy.rollaxis `_ . Usually be used for image segmentation which x=[X, Y], X and Y should be matched. @@ -1076,13 +1355,13 @@ def transform_matrix_offset_center(matrix, x, y): return transform_matrix -def apply_transform(x, transform_matrix, channel_index=2, fill_mode='nearest', cval=0.): +def apply_transform(x, transform_matrix, channel_index=2, fill_mode='nearest', cval=0., order=1): """Return transformed images by given transform_matrix from ``transform_matrix_offset_center``. Parameters ---------- x : numpy array - Batch of images with dimension of 3, [batch_size, row, col, channel]. + An image with dimension of [row, col, channel] (default). transform_matrix : numpy array Transform matrix (offset center), can be generated by ``transform_matrix_offset_center`` channel_index : int @@ -1093,6 +1372,15 @@ def apply_transform(x, transform_matrix, channel_index=2, fill_mode='nearest', c - `scipy ndimage affine_transform `_ cval : scalar, optional Value used for points outside the boundaries of the input if mode='constant'. Default is 0.0 + order : int, optional + The order of interpolation. The order has to be in the range 0-5: + + - 0 Nearest-neighbor + - 1 Bi-linear (default) + - 2 Bi-quadratic + - 3 Bi-cubic + - 4 Bi-quartic + - 5 Bi-quintic - `scipy ndimage affine_transform `_ @@ -1104,7 +1392,7 @@ def apply_transform(x, transform_matrix, channel_index=2, fill_mode='nearest', c final_affine_matrix = transform_matrix[:2, :2] final_offset = transform_matrix[:2, 2] channel_images = [ndi.interpolation.affine_transform(x_channel, final_affine_matrix, - final_offset, order=0, mode=fill_mode, cval=cval) for x_channel in x] + final_offset, order=order, mode=fill_mode, cval=cval) for x_channel in x] x = np.stack(channel_images, axis=0) x = np.rollaxis(x, 0, channel_index+1) return x @@ -1118,7 +1406,7 @@ def projective_transform_by_points(x, src, dst, map_args={}, output_shape=None, x : numpy array An image with dimension of [row, col, channel] (default). src : list or numpy - The original coordinates, usually 4 coordinates of (x, y). + The original coordinates, usually 4 coordinates of (width, height). dst : list or numpy The coordinates after transformation, the number of coordinates is the same with src. map_args : dict, optional @@ -1146,7 +1434,7 @@ def projective_transform_by_points(x, src, dst, map_args={}, output_shape=None, Examples -------- >>> Assume X is an image from CIFAR 10, i.e. shape == (32, 32, 3) - >>> src = [[0,0],[0,32],[32,0],[32,32]] + >>> src = [[0,0],[0,32],[32,0],[32,32]] # [w, h] >>> dst = [[10,10],[0,32],[32,0],[32,32]] >>> x = projective_transform_by_points(X, src, dst) @@ -1252,7 +1540,7 @@ def binary_dilation(x, radius=3): """ from skimage.morphology import disk, binary_dilation mask = disk(radius) - x = binary_dilation(image, selem=mask) + x = binary_dilation(x, selem=mask) return x def dilation(x, radius=3): @@ -1270,6 +1558,706 @@ def dilation(x, radius=3): return x +def binary_erosion(x, radius=3): + """ Return binary morphological erosion of an image, + see `skimage.morphology.binary_erosion `_. + + Parameters + ----------- + x : 2D array image. + radius : int for the radius of mask. + """ + from skimage.morphology import disk, dilation, binary_erosion + mask = disk(radius) + x = binary_erosion(x, selem=mask) + return x + +def erosion(x, radius=3): + """ Return greyscale morphological erosion of an image, + see `skimage.morphology.erosion `_. + + Parameters + ----------- + x : 2D array image. + radius : int for the radius of mask. + """ + from skimage.morphology import disk, dilation, erosion + mask = disk(radius) + x = erosion(x, selem=mask) + return x + + + +## Object Detection + +def obj_box_coords_rescale(coords=[], shape=[100, 200]): + """Scale down a list of coordinates from pixel unit to the ratio of image size i.e. in the range of [0, 1]. + + Parameters + ------------ + coords : list of list for coordinates [[x, y, w, h], [x, y, w, h], ...] + shape : list of 2 integers for [height, width] of the image. + + Examples + --------- + >>> coords = obj_box_coords_rescale(coords=[[30, 40, 50, 50], [10, 10, 20, 20]], shape=[100, 100]) + >>> print(coords) + ... [[0.3, 0.4, 0.5, 0.5], [0.1, 0.1, 0.2, 0.2]] + >>> coords = obj_box_coords_rescale(coords=[[30, 40, 50, 50]], shape=[50, 100]) + >>> print(coords) + ... [[0.3, 0.8, 0.5, 1.0]] + >>> coords = obj_box_coords_rescale(coords=[[30, 40, 50, 50]], shape=[100, 200]) + >>> print(coords) + ... [[0.15, 0.4, 0.25, 0.5]] + """ + imh, imw = shape[0], shape[1] + imh = imh * 1.0 # * 1.0 for python2 : force division to be float point + imw = imw * 1.0 + coords_new = list() + for coord in coords: + assert len(coord) == 4, "coordinate should be 4 values : [x, y, w, h]" + x = coord[0] / imw + y = coord[1] / imh + w = coord[2] / imw + h = coord[3] / imh + coords_new.append([x, y, w, h]) + return coords_new + +def obj_box_coord_rescale(coord=[], shape=[100, 200]): + """Scale down one coordinates from pixel unit to the ratio of image size i.e. in the range of [0, 1]. + It is the reverse process of ``obj_box_coord_scale_to_pixelunit``. + + Parameters + ------------ + coords : list of list for coordinates [[x, y, w, h], [x, y, w, h], ...] + shape : list of 2 integers for [height, width] of the image. + + Examples + --------- + >>> coord = obj_box_coord_rescale(coord=[30, 40, 50, 50], shape=[100, 100]) + ... [[0.3, 0.4, 0.5, 0.5]] + """ + return obj_box_coords_rescale(coords=[coord], shape=shape)[0] + +# coord = obj_box_coord_rescale(coord=[30, 40, 50, 50], shape=[100, 100]) +# print(coord) #[[0.15, 0.4, 0.25, 0.5]] +# exit() + +def obj_box_coord_scale_to_pixelunit(coord, shape=(100, 100, 3)): + """ Convert one coordinate [x, y, w (or x2), h (or y2)] in ratio format to image coordinate format. + It is the reverse process of ``obj_box_coord_rescale``. + + Parameters + ----------- + coord : list of float, [x, y, w (or x2), h (or y2)] in ratio format, i.e value range [0~1]. + shape : tuple of (height, width, channel (optional)) + + Examples + --------- + >>> x, y, x2, y2 = obj_box_coord_scale_to_pixelunit([0.2, 0.3, 0.5, 0.7], shape=(100, 200, 3)) + ... (40, 30, 100, 70) + """ + imh, imw = shape[0:2] + x = int(coord[0]*imw) + x2 = int(coord[2]*imw) + y = int(coord[1]*imh) + y2 = int(coord[3]*imh) + return [x, y, x2, y2] + +# coords = obj_box_coords_rescale(coords=[[30, 40, 50, 50], [10, 10, 20, 20]], shape=[100, 100]) +# print(coords) +# # ... [[0.3, 0.4, 0.5, 0.5], [0.1, 0.1, 0.2, 0.2]] +# coords = obj_box_coords_rescale(coords=[[30, 40, 50, 50]], shape=[50, 100]) +# print(coords) +# # ... [[0.3, 0.8, 0.5, 1.0]] +# coords = obj_box_coords_rescale(coords=[[30, 40, 50, 50]], shape=[100, 200]) +# print(coords) +# # ... [[0.15, 0.4, 0.25, 0.5]] +# exit() + +def obj_box_coord_centroid_to_upleft_butright(coord, to_int=False): + """ Convert one coordinate [x_center, y_center, w, h] to [x1, y1, x2, y2] in up-left and botton-right format. + + Examples + --------- + >>> coord = obj_box_coord_centroid_to_upleft_butright([30, 40, 20, 20]) + ... [20, 30, 40, 50] + """ + assert len(coord) == 4, "coordinate should be 4 values : [x, y, w, h]" + x_center, y_center, w, h = coord + x = x_center - w / 2. + y = y_center - h / 2. + x2 = x + w + y2 = y + h + if to_int: + return [int(x), int(y), int(x2), int(y2)] + else: + return [x, y, x2, y2] + +# coord = obj_box_coord_centroid_to_upleft_butright([30, 40, 20, 20]) +# print(coord) [20, 30, 40, 50] +# exit() + +def obj_box_coord_upleft_butright_to_centroid(coord): + """ Convert one coordinate [x1, y1, x2, y2] to [x_center, y_center, w, h]. + It is the reverse process of ``obj_box_coord_centroid_to_upleft_butright``. + """ + assert len(coord) == 4, "coordinate should be 4 values : [x1, y1, x2, y2]" + x1, y1, x2, y2 = coord + w = x2 - x1 + h = y2 - y1 + x_c = x1 + w / 2. + y_c = y1 + h / 2. + return [x_c, y_c, w, h] + + +def obj_box_coord_centroid_to_upleft(coord): + """ Convert one coordinate [x_center, y_center, w, h] to [x, y, w, h]. + It is the reverse process of ``obj_box_coord_upleft_to_centroid``. + """ + assert len(coord) == 4, "coordinate should be 4 values : [x, y, w, h]" + x_center, y_center, w, h = coord + x = x_center - w / 2. + y = y_center - h / 2. + return [x, y, w, h] + +def obj_box_coord_upleft_to_centroid(coord): + """ Convert one coordinate [x, y, w, h] to [x_center, y_center, w, h]. + It is the reverse process of ``obj_box_coord_centroid_to_upleft``. + """ + assert len(coord) == 4, "coordinate should be 4 values : [x, y, w, h]" + x, y, w, h = coord + x_center = x + w / 2. + y_center = y + h / 2. + return [x_center, y_center, w, h] + +## +def parse_darknet_ann_str_to_list(annotation): + """ Input string format of class, x, y, w, h, return list of list format. + """ + annotation = annotation.split("\n") + ann = [] + for a in annotation: + a = a.split() + if len(a) == 5: + for i in range(len(a)): + if i == 0: + a[i] = int(a[i]) + else: + a[i] = float(a[i]) + ann.append(a) + return ann + +def parse_darknet_ann_list_to_cls_box(annotation): + """ Input list of [[class, x, y, w, h], ...], return two list of [class ...] and [[x, y, w, h], ...]. + """ + class_list = [] + bbox_list = [] + for i in range(len(annotation)): + class_list.append( annotation[i][0] ) + bbox_list.append( annotation[i][1:] ) + return class_list, bbox_list + + +def obj_box_left_right_flip(im, coords=[], is_rescale=False, is_center=False, is_random=False): + """Left-right flip the image and coordinates for object detection. + + Parameters + ---------- + im : numpy array + An image with dimension of [row, col, channel] (default). + coords : list of list for coordinates [[x, y, w, h], [x, y, w, h], ...] + is_rescale : boolean, default False + Set to True, if the input coordinates are rescaled to [0, 1]. + is_center : boolean, default False + Set to True, if the x and y of coordinates are the centroid. (i.e. darknet format) + is_random : boolean, default False + If True, randomly flip. + + Examples + -------- + >>> im = np.zeros([80, 100]) # as an image with shape width=100, height=80 + >>> im, coords = obj_box_left_right_flip(im, coords=[[0.2, 0.4, 0.3, 0.3], [0.1, 0.5, 0.2, 0.3]], is_rescale=True, is_center=True, is_random=False) + >>> print(coords) + ... [[0.8, 0.4, 0.3, 0.3], [0.9, 0.5, 0.2, 0.3]] + >>> im, coords = obj_box_left_right_flip(im, coords=[[0.2, 0.4, 0.3, 0.3]], is_rescale=True, is_center=False, is_random=False) + >>> print(coords) + ... [[0.5, 0.4, 0.3, 0.3]] + >>> im, coords = obj_box_left_right_flip(im, coords=[[20, 40, 30, 30]], is_rescale=False, is_center=True, is_random=False) + >>> print(coords) + ... [[80, 40, 30, 30]] + >>> im, coords = obj_box_left_right_flip(im, coords=[[20, 40, 30, 30]], is_rescale=False, is_center=False, is_random=False) + >>> print(coords) + ... [[50, 40, 30, 30]] + """ + def _flip(im, coords): + im = flip_axis(im, axis=1, is_random=False) + coords_new = list() + + for coord in coords: + assert len(coord) == 4, "coordinate should be 4 values : [x, y, w, h]" + if is_rescale: + if is_center: + # x_center' = 1 - x + x = 1. - coord[0] + else: + # x_center' = 1 - x - w + x = 1. - coord[0] - coord[2] + else: + if is_center: + # x' = im.width - x + x = im.shape[1] - coord[0] + else: + # x' = im.width - x - w + x = im.shape[1] - coord[0] - coord[2] + coords_new.append([x, coord[1], coord[2], coord[3]]) + return im, coords_new + + if is_random: + factor = np.random.uniform(-1, 1) + if factor > 0: + return _flip(im, coords) + else: + return im, coords + else: + return _flip(im, coords) + +# im = np.zeros([80, 100]) # as an image with shape width=100, height=80 +# im, coords = obj_box_left_right_flip(im, coords=[[0.2, 0.4, 0.3, 0.3], [0.1, 0.5, 0.2, 0.3]], is_rescale=True, is_center=True, is_random=False) +# print(coords) +# # ... [[0.8, 0.4, 0.3, 0.3], [0.9, 0.5, 0.2, 0.3]] +# im, coords = obj_box_left_right_flip(im, coords=[[0.2, 0.4, 0.3, 0.3]], is_rescale=True, is_center=False, is_random=False) +# print(coords) +# # [[0.5, 0.4, 0.3, 0.3]] +# im, coords = obj_box_left_right_flip(im, coords=[[20, 40, 30, 30]], is_rescale=False, is_center=True, is_random=False) +# print(coords) +# # ... [[80, 40, 30, 30]] +# im, coords = obj_box_left_right_flip(im, coords=[[20, 40, 30, 30]], is_rescale=False, is_center=False, is_random=False) +# print(coords) +# # [[50, 40, 30, 30]] +# exit() + +def obj_box_imresize(im, coords=[], size=[100, 100], interp='bicubic', mode=None, is_rescale=False): + """Resize an image, and compute the new bounding box coordinates. + + Parameters + ------------- + im : numpy array + An image with dimension of [row, col, channel] (default). + coords : list of list for coordinates [[x, y, w, h], [x, y, w, h], ...] + size, interp, mode : see ``tl.prepro.imresize`` for details. + is_rescale : boolean, default False + Set to True, if the input coordinates are rescaled to [0, 1], then return the original coordinates. + + Examples + -------- + >>> im = np.zeros([80, 100, 3]) # as an image with shape width=100, height=80 + >>> _, coords = obj_box_imresize(im, coords=[[20, 40, 30, 30], [10, 20, 20, 20]], size=[160, 200], is_rescale=False) + >>> print(coords) + ... [[40, 80, 60, 60], [20, 40, 40, 40]] + >>> _, coords = obj_box_imresize(im, coords=[[20, 40, 30, 30]], size=[40, 100], is_rescale=False) + >>> print(coords) + ... [20, 20, 30, 15] + >>> _, coords = obj_box_imresize(im, coords=[[20, 40, 30, 30]], size=[60, 150], is_rescale=False) + >>> print(coords) + ... [30, 30, 45, 22] + >>> im2, coords = obj_box_imresize(im, coords=[[0.2, 0.4, 0.3, 0.3]], size=[160, 200], is_rescale=True) + >>> print(coords, im2.shape) + ... [0.2, 0.4, 0.3, 0.3] (160, 200, 3) + """ + imh, imw = im.shape[0:2] + imh = imh * 1.0 # * 1.0 for python2 : force division to be float point + imw = imw * 1.0 + im = imresize(im, size=size, interp=interp, mode=mode) + + if is_rescale is False: + coords_new = list() + for coord in coords: + assert len(coord) == 4, "coordinate should be 4 values : [x, y, w, h]" + # x' = x * (imw'/imw) + x = int(coord[0] * (size[1]/imw)) + # y' = y * (imh'/imh) + # print('>>', coord[1], size[0], imh) + y = int(coord[1] * (size[0]/imh)) + # w' = w * (imw'/imw) + w = int(coord[2] * (size[1]/imw)) + # h' = h * (imh'/imh) + h = int(coord[3] * (size[0]/imh)) + coords_new.append([x, y, w, h]) + return im, coords_new + else: + return im, coords + +# im = np.zeros([80, 100, 3]) # as an image with shape width=100, height=80 +# _, coords = obj_box_imresize(im, coords=[[20, 40, 30, 30], [10, 20, 20, 20]], size=[160, 200], is_rescale=False) +# print(coords) +# # ... [[40, 80, 60, 60], [20, 40, 40, 40]] +# _, coords = obj_box_imresize(im, coords=[[20, 40, 30, 30]], size=[40, 100], is_rescale=False) +# print(coords) +# # ... [20, 20, 30, 15] +# _, coords = obj_box_imresize(im, coords=[[20, 40, 30, 30]], size=[60, 150], is_rescale=False) +# print(coords) +# # ... [30, 30, 45, 22] +# im2, coords = obj_box_imresize(im, coords=[[0.2, 0.4, 0.3, 0.3]], size=[160, 200], is_rescale=True) +# print(coords, im2.shape) +# # ... [0.2, 0.4, 0.3, 0.3] (160, 200, 3) +# exit() + +def obj_box_crop(im, classes=[], coords=[], wrg=100, hrg=100, + is_rescale=False, is_center=False, is_random=False, + thresh_wh=0.02, thresh_wh2=12.): + """Randomly or centrally crop an image, and compute the new bounding box coordinates. + Objects outside the cropped image will be removed. + + Parameters + ----------- + im : numpy array + An image with dimension of [row, col, channel] (default). + classes : list of class ID (int). + coords : list of list for coordinates [[x, y, w, h], [x, y, w, h], ...] + wrg, hrg, is_random : see ``tl.prepro.crop`` for details. + is_rescale : boolean, default False + Set to True, if the input coordinates are rescaled to [0, 1]. + is_center : boolean, default False + Set to True, if the x and y of coordinates are the centroid. (i.e. darknet format) + thresh_wh : float + Threshold, remove the box if its ratio of width(height) to image size less than the threshold. + thresh_wh2 : float + Threshold, remove the box if its ratio of width to height or vice verse higher than the threshold. + """ + h, w = im.shape[0], im.shape[1] + assert (h > hrg) and (w > wrg), "The size of cropping should smaller than the original image" + if is_random: + h_offset = int(np.random.uniform(0, h-hrg) -1) + w_offset = int(np.random.uniform(0, w-wrg) -1) + h_end = hrg + h_offset + w_end = wrg + w_offset + im_new = im[h_offset: h_end ,w_offset: w_end] + else: # central crop + h_offset = int(np.floor((h - hrg)/2.)) + w_offset = int(np.floor((w - wrg)/2.)) + h_end = h_offset + hrg + w_end = w_offset + wrg + im_new = im[h_offset: h_end, w_offset: w_end] + + # w + # _____________________________ + # | h/w offset | + # | ------- | + # h | | | | + # | | | | + # | ------- | + # | h/w end | + # |___________________________| + + def _get_coord(coord): + """ Input pixel-unit [x, y, w, h] format, then make sure [x, y] it is the up-left coordinates, + before getting the new coordinates. + Boxes outsides the cropped image will be removed. + """ + if is_center: + coord = obj_box_coord_centroid_to_upleft(coord) + + ##======= pixel unit format and upleft, w, h ==========## + + # x = np.clip( coord[0] - w_offset, 0, w_end - w_offset) + # y = np.clip( coord[1] - h_offset, 0, h_end - h_offset) + # w = np.clip( coord[2] , 0, w_end - w_offset) + # h = np.clip( coord[3] , 0, h_end - h_offset) + + x = coord[0] - w_offset + y = coord[1] - h_offset + w = coord[2] + h = coord[3] + + if x < 0: + if x + w <= 0: + return None + w = w + x + x = 0 + elif x > im_new.shape[1]: # object outside the cropped image + return None + + if y < 0: + if y + h <= 0: + return None + h = h + y + y = 0 + elif y > im_new.shape[0]: # object outside the cropped image + return None + + if (x is not None) and (x + w > im_new.shape[1]): # box outside the cropped image + w = im_new.shape[1] - x + + if (y is not None) and (y + h > im_new.shape[0]): # box outside the cropped image + h = im_new.shape[0] - y + + if (w / (h+1.) > thresh_wh2) or (h / (w+1.) > thresh_wh2): # object shape strange: too narrow + # print('xx', w, h) + return None + + if (w / (im_new.shape[1]*1.) < thresh_wh) or (h / (im_new.shape[0]*1.) < thresh_wh): # object shape strange: too narrow + # print('yy', w, im_new.shape[1], h, im_new.shape[0]) + return None + + coord = [x, y, w, h] + + ## convert back if input format is center. + if is_center: + coord = obj_box_coord_upleft_to_centroid(coord) + + return coord + + coords_new = list() + classes_new = list() + for i in range(len(coords)): + coord = coords[i] + assert len(coord) == 4, "coordinate should be 4 values : [x, y, w, h]" + if is_rescale: + """ for scaled coord, upscaled before process and scale back in the end. """ + coord = obj_box_coord_scale_to_pixelunit(coord, im.shape) + coord = _get_coord(coord) + if coord is not None: + coord = obj_box_coord_rescale(coord, im_new.shape) + coords_new.append(coord) + classes_new.append(classes[i]) + else: + coord = _get_coord(coord) + if coord is not None: + coords_new.append(coord) + classes_new.append(classes[i]) + return im_new, classes_new, coords_new + +def obj_box_shift(im, classes=[], coords=[], wrg=0.1, hrg=0.1, + row_index=0, col_index=1, channel_index=2, + fill_mode='nearest', cval=0., order=1, + is_rescale=False, is_center=False, is_random=False, + thresh_wh=0.02, thresh_wh2=12.): + """ Shift an image randomly or non-randomly, and compute the new bounding box coordinates. + Objects outside the cropped image will be removed. + + Parameters + ----------- + im : numpy array + An image with dimension of [row, col, channel] (default). + classes : list of class ID (int). + coords : list of list for coordinates [[x, y, w, h], [x, y, w, h], ...] + wrg, hrg, row_index, col_index, channel_index, is_random, fill_mode, cval, order : see ``tl.prepro.shift``. + is_rescale : boolean, default False + Set to True, if the input coordinates are rescaled to [0, 1]. + is_center : boolean, default False + Set to True, if the x and y of coordinates are the centroid. (i.e. darknet format) + thresh_wh : float + Threshold, remove the box if its ratio of width(height) to image size less than the threshold. + thresh_wh2 : float + Threshold, remove the box if its ratio of width to height or vice verse higher than the threshold. + """ + imh, imw = im.shape[row_index], im.shape[col_index] + assert (hrg < 1.0) and (hrg > 0.) and (wrg < 1.0) and (wrg > 0.) , "shift range should be (0, 1)" + if is_random: + tx = np.random.uniform(-hrg, hrg) * imh + ty = np.random.uniform(-wrg, wrg) * imw + else: + tx, ty = hrg * imh, wrg * imw + translation_matrix = np.array([[1, 0, tx], + [0, 1, ty], + [0, 0, 1]]) + + transform_matrix = translation_matrix # no need to do offset + im_new = apply_transform(im, transform_matrix, channel_index, fill_mode, cval, order) + + # modified from obj_box_crop + def _get_coord(coord): + """ Input pixel-unit [x, y, w, h] format, then make sure [x, y] it is the up-left coordinates, + before getting the new coordinates. + Boxes outsides the cropped image will be removed. + """ + if is_center: + coord = obj_box_coord_centroid_to_upleft(coord) + + ##======= pixel unit format and upleft, w, h ==========## + x = coord[0] - ty # only change this + y = coord[1] - tx # only change this + w = coord[2] + h = coord[3] + + if x < 0: + if x + w <= 0: + return None + w = w + x + x = 0 + elif x > im_new.shape[1]: # object outside the cropped image + return None + + if y < 0: + if y + h <= 0: + return None + h = h + y + y = 0 + elif y > im_new.shape[0]: # object outside the cropped image + return None + + if (x is not None) and (x + w > im_new.shape[1]): # box outside the cropped image + w = im_new.shape[1] - x + + if (y is not None) and (y + h > im_new.shape[0]): # box outside the cropped image + h = im_new.shape[0] - y + + if (w / (h+1.) > thresh_wh2) or (h / (w+1.) > thresh_wh2): # object shape strange: too narrow + # print('xx', w, h) + return None + + if (w / (im_new.shape[1]*1.) < thresh_wh) or (h / (im_new.shape[0]*1.) < thresh_wh): # object shape strange: too narrow + # print('yy', w, im_new.shape[1], h, im_new.shape[0]) + return None + + coord = [x, y, w, h] + + ## convert back if input format is center. + if is_center: + coord = obj_box_coord_upleft_to_centroid(coord) + + return coord + + coords_new = list() + classes_new = list() + for i in range(len(coords)): + coord = coords[i] + assert len(coord) == 4, "coordinate should be 4 values : [x, y, w, h]" + if is_rescale: + """ for scaled coord, upscaled before process and scale back in the end. """ + coord = obj_box_coord_scale_to_pixelunit(coord, im.shape) + coord = _get_coord(coord) + if coord is not None: + coord = obj_box_coord_rescale(coord, im_new.shape) + coords_new.append(coord) + classes_new.append(classes[i]) + else: + coord = _get_coord(coord) + if coord is not None: + coords_new.append(coord) + classes_new.append(classes[i]) + return im_new, classes_new, coords_new + +def obj_box_zoom(im, classes=[], coords=[], zoom_range=(0.9, 1.1), + row_index=0, col_index=1, channel_index=2, fill_mode='nearest', cval=0., order=1, + is_rescale=False, is_center=False, is_random=False, + thresh_wh=0.02, thresh_wh2=12.): + """Zoom in and out of a single image, randomly or non-randomly, and compute the new bounding box coordinates. + Objects outside the cropped image will be removed. + + Parameters + ----------- + im : numpy array + An image with dimension of [row, col, channel] (default). + classes : list of class ID (int). + coords : list of list for coordinates [[x, y, w, h], [x, y, w, h], ...] + zoom_range, row_index, col_index, channel_index, is_random, fill_mode, cval, order : see ``tl.prepro.zoom``. + is_rescale : boolean, default False + Set to True, if the input coordinates are rescaled to [0, 1]. + is_center : boolean, default False + Set to True, if the x and y of coordinates are the centroid. (i.e. darknet format) + thresh_wh : float + Threshold, remove the box if its ratio of width(height) to image size less than the threshold. + thresh_wh2 : float + Threshold, remove the box if its ratio of width to height or vice verse higher than the threshold. + """ + if len(zoom_range) != 2: + raise Exception('zoom_range should be a tuple or list of two floats. ' + 'Received arg: ', zoom_range) + if is_random: + if zoom_range[0] == 1 and zoom_range[1] == 1: + zx, zy = 1, 1 + print(" random_zoom : not zoom in/out") + else: + zx, zy = np.random.uniform(zoom_range[0], zoom_range[1], 2) + else: + zx, zy = zoom_range + # print(zx, zy) + zoom_matrix = np.array([[zx, 0, 0], + [0, zy, 0], + [0, 0, 1]]) + + h, w = im.shape[row_index], im.shape[col_index] + transform_matrix = transform_matrix_offset_center(zoom_matrix, h, w) + im_new = apply_transform(im, transform_matrix, channel_index, fill_mode, cval, order) + + + # modified from obj_box_crop + def _get_coord(coord): + """ Input pixel-unit [x, y, w, h] format, then make sure [x, y] it is the up-left coordinates, + before getting the new coordinates. + Boxes outsides the cropped image will be removed. + """ + if is_center: + coord = obj_box_coord_centroid_to_upleft(coord) + + ##======= pixel unit format and upleft, w, h ==========## + x = (coord[0] - im.shape[1]/2) / zy + im.shape[1]/2 # only change this + y = (coord[1] - im.shape[0]/2) / zx + im.shape[0]/2 # only change this + w = coord[2] / zy # only change this + h = coord[3] / zx # only change thisS + + if x < 0: + if x + w <= 0: + return None + w = w + x + x = 0 + elif x > im_new.shape[1]: # object outside the cropped image + return None + + if y < 0: + if y + h <= 0: + return None + h = h + y + y = 0 + elif y > im_new.shape[0]: # object outside the cropped image + return None + + if (x is not None) and (x + w > im_new.shape[1]): # box outside the cropped image + w = im_new.shape[1] - x + + if (y is not None) and (y + h > im_new.shape[0]): # box outside the cropped image + h = im_new.shape[0] - y + + if (w / (h+1.) > thresh_wh2) or (h / (w+1.) > thresh_wh2): # object shape strange: too narrow + # print('xx', w, h) + return None + + if (w / (im_new.shape[1]*1.) < thresh_wh) or (h / (im_new.shape[0]*1.) < thresh_wh): # object shape strange: too narrow + # print('yy', w, im_new.shape[1], h, im_new.shape[0]) + return None + + coord = [x, y, w, h] + + ## convert back if input format is center. + if is_center: + coord = obj_box_coord_upleft_to_centroid(coord) + + return coord + + coords_new = list() + classes_new = list() + for i in range(len(coords)): + coord = coords[i] + assert len(coord) == 4, "coordinate should be 4 values : [x, y, w, h]" + if is_rescale: + """ for scaled coord, upscaled before process and scale back in the end. """ + coord = obj_box_coord_scale_to_pixelunit(coord, im.shape) + coord = _get_coord(coord) + if coord is not None: + coord = obj_box_coord_rescale(coord, im_new.shape) + coords_new.append(coord) + classes_new.append(classes[i]) + else: + coord = _get_coord(coord) + if coord is not None: + coords_new.append(coord) + classes_new.append(classes[i]) + return im_new, classes_new, coords_new + + + ## Sequence @@ -1342,7 +2330,34 @@ def pad_sequences(sequences, maxlen=None, dtype='int32', padding='post', truncat x[idx, -len(trunc):] = trunc else: raise ValueError('Padding type "%s" not understood' % padding) - return x + return x.tolist() + +def remove_pad_sequences(sequences, pad_id=0): + """Remove padding. + + Parameters + ----------- + sequences : list of list. + pad_id : int. + + Examples + ---------- + >>> sequences = [[2,3,4,0,0], [5,1,2,3,4,0,0,0], [4,5,0,2,4,0,0,0]] + >>> print(remove_pad_sequences(sequences, pad_id=0)) + ... [[2, 3, 4], [5, 1, 2, 3, 4], [4, 5, 0, 2, 4]] + """ + import copy + sequences_out = copy.deepcopy(sequences) + for i in range(len(sequences)): + # for j in range(len(sequences[i])): + # if sequences[i][j] == pad_id: + # sequences_out[i] = sequences_out[i][:j] + # break + for j in range(1, len(sequences[i])): + if sequences[i][-j] != pad_id: + sequences_out[i] = sequences_out[i][0:-j+1] + break + return sequences_out def process_sequences(sequences, end_id=0, pad_val=0, is_shorten=True, remain_end_id=False): """Set all tokens(ids) after END token to the padding value, and then shorten (option) it to the maximum sequence length in this batch. @@ -1409,6 +2424,63 @@ def sequences_add_start_id(sequences, start_id=0, remove_last=False): sequences_out[i] = [start_id] + sequences[i] return sequences_out +def sequences_add_end_id(sequences, end_id=888): + """Add special end token(id) in the end of each sequence. + + Parameters + ----------- + sequences : list of list. + end_id : int. + + Examples + --------- + >>> sequences = [[1,2,3],[4,5,6,7]] + >>> print(sequences_add_end_id(sequences, end_id=999)) + ... [[1, 2, 3, 999], [4, 5, 6, 999]] + """ + sequences_out = [[] for _ in range(len(sequences))]#[[]] * len(sequences) + for i in range(len(sequences)): + sequences_out[i] = sequences[i] + [end_id] + return sequences_out + + +def sequences_add_end_id_after_pad(sequences, end_id=888, pad_id=0): + """Add special end token(id) in the end of each sequence. + + Parameters + ----------- + sequences : list of list. + end_id : int. + pad_id : int. + + Examples + --------- + >>> sequences = [[1,2,0,0], [1,2,3,0], [1,2,3,4]] + >>> print(sequences_add_end_id_after_pad(sequences, end_id=99, pad_id=0)) + ... [[1, 2, 99, 0], [1, 2, 3, 99], [1, 2, 3, 4]] + """ + # sequences_out = [[] for _ in range(len(sequences))]#[[]] * len(sequences) + import copy + sequences_out = copy.deepcopy(sequences) + # # add a pad to all + # for i in range(len(sequences)): + # for j in range(len(sequences[i])): + # sequences_out[i].append(pad_id) + # # pad -- > end + # max_len = 0 + for i in range(len(sequences)): + for j in range(len(sequences[i])): + if sequences[i][j] == pad_id: + sequences_out[i][j] = end_id + # if j > max_len: + # max_len = j + break + # # remove pad if too long + # for i in range(len(sequences)): + # for j in range(len(sequences[i])): + # sequences_out[i] = sequences_out[i][:max_len+1] + return sequences_out + def sequences_get_mask(sequences, pad_val=0): """Return mask for sequences. @@ -1435,171 +2507,165 @@ def sequences_get_mask(sequences, pad_val=0): ## Tensor Opt -def distorted_images(images=None, height=24, width=24): - """Distort images for generating more training data. - - Features - --------- - They are cropped to height * width pixels randomly. - - They are approximately whitened to make the model insensitive to dynamic range. - - Randomly flip the image from left to right. - - Randomly distort the image brightness. - - Randomly distort the image contrast. - - Whiten (Normalize) the images. - - Parameters - ---------- - images : 4D Tensor - The tensor or placeholder of images - height : int - The height for random crop. - width : int - The width for random crop. - - Returns - ------- - result : tuple of Tensor - (Tensor for distorted images, Tensor for while loop index) - - Examples - -------- - >>> X_train, y_train, X_test, y_test = tl.files.load_cifar10_dataset(shape=(-1, 32, 32, 3), plotable=False) - >>> sess = tf.InteractiveSession() - >>> batch_size = 128 - >>> x = tf.placeholder(tf.float32, shape=[batch_size, 32, 32, 3]) - >>> distorted_images_op = tl.preprocess.distorted_images(images=x, height=24, width=24) - >>> sess.run(tf.initialize_all_variables()) - >>> feed_dict={x: X_train[0:batch_size,:,:,:]} - >>> distorted_images, idx = sess.run(distorted_images_op, feed_dict=feed_dict) - >>> tl.visualize.images2d(X_train[0:9,:,:,:], second=2, saveable=False, name='cifar10', dtype=np.uint8, fig_idx=20212) - >>> tl.visualize.images2d(distorted_images[1:10,:,:,:], second=10, saveable=False, name='distorted_images', dtype=None, fig_idx=23012) - - Notes - ------ - - The first image in 'distorted_images' should be removed. - - References - ----------- - - `tensorflow.models.image.cifar10.cifar10_input `_ - """ - print("This function is deprecated, please use tf.map_fn instead, e.g:\n \ - t_image = tf.map_fn(lambda img: tf.image.random_brightness(img, max_delta=32. / 255.), t_image)\n \ - t_image = tf.map_fn(lambda img: tf.image.random_contrast(img, lower=0.5, upper=1.5), t_image)\n \ - t_image = tf.map_fn(lambda img: tf.image.random_saturation(img, lower=0.5, upper=1.5), t_image)\n \ - t_image = tf.map_fn(lambda img: tf.image.random_hue(img, max_delta=0.032), t_image)") - exit() - # print(" [Warning] distorted_images will be deprecated due to speed, see TFRecord tutorial for more info...") - try: - batch_size = int(images._shape[0]) - except: - raise Exception('unknow batch_size of images') - distorted_x = tf.Variable(tf.constant(0.1, shape=[1, height, width, 3])) - i = tf.Variable(tf.constant(0)) - - c = lambda distorted_x, i: tf.less(i, batch_size) - - def body(distorted_x, i): - # 1. Randomly crop a [height, width] section of the image. - image = tf.random_crop(tf.gather(images, i), [height, width, 3]) - # 2. Randomly flip the image horizontally. - image = tf.image.random_flip_left_right(image) - # 3. Randomly change brightness. - image = tf.image.random_brightness(image, max_delta=63) - # 4. Randomly change contrast. - image = tf.image.random_contrast(image, lower=0.2, upper=1.8) - # 5. Subtract off the mean and divide by the variance of the pixels. - image = tf.image.per_image_whitening(image) - # 6. Append the image to a batch. - image = tf.expand_dims(image, 0) - return tf.concat(0, [distorted_x, image]), tf.add(i, 1) - - result = tf.while_loop(cond=c, body=body, loop_vars=(distorted_x, i), parallel_iterations=16) - return result - - -def crop_central_whiten_images(images=None, height=24, width=24): - """Crop the central of image, and normailize it for test data. - - They are cropped to central of height * width pixels. - - Whiten (Normalize) the images. - - Parameters - ---------- - images : 4D Tensor - The tensor or placeholder of images - height : int - The height for central crop. - width : int - The width for central crop. - - Returns - ------- - result : tuple Tensor - (Tensor for distorted images, Tensor for while loop index) - - Examples - -------- - >>> X_train, y_train, X_test, y_test = tl.files.load_cifar10_dataset(shape=(-1, 32, 32, 3), plotable=False) - >>> sess = tf.InteractiveSession() - >>> batch_size = 128 - >>> x = tf.placeholder(tf.float32, shape=[batch_size, 32, 32, 3]) - >>> central_images_op = tl.preprocess.crop_central_whiten_images(images=x, height=24, width=24) - >>> sess.run(tf.initialize_all_variables()) - >>> feed_dict={x: X_train[0:batch_size,:,:,:]} - >>> central_images, idx = sess.run(central_images_op, feed_dict=feed_dict) - >>> tl.visualize.images2d(X_train[0:9,:,:,:], second=2, saveable=False, name='cifar10', dtype=np.uint8, fig_idx=20212) - >>> tl.visualize.images2d(central_images[1:10,:,:,:], second=10, saveable=False, name='central_images', dtype=None, fig_idx=23012) - - Notes - ------ - The first image in 'central_images' should be removed. - - Code References - ---------------- - - ``tensorflow.models.image.cifar10.cifar10_input`` - """ - print("This function is deprecated, please use tf.map_fn instead, e.g:\n \ - t_image = tf.map_fn(lambda img: tf.image.random_brightness(img, max_delta=32. / 255.), t_image)\n \ - t_image = tf.map_fn(lambda img: tf.image.random_contrast(img, lower=0.5, upper=1.5), t_image)\n \ - t_image = tf.map_fn(lambda img: tf.image.random_saturation(img, lower=0.5, upper=1.5), t_image)\n \ - t_image = tf.map_fn(lambda img: tf.image.random_hue(img, max_delta=0.032), t_image)") - exit() - # print(" [Warning] crop_central_whiten_images will be deprecated due to speed, see TFRecord tutorial for more info...") - try: - batch_size = int(images._shape[0]) - except: - raise Exception('unknow batch_size of images') - central_x = tf.Variable(tf.constant(0.1, shape=[1, height, width, 3])) - i = tf.Variable(tf.constant(0)) - - c = lambda central_x, i: tf.less(i, batch_size) - - def body(central_x, i): - # 1. Crop the central [height, width] of the image. - image = tf.image.resize_image_with_crop_or_pad(tf.gather(images, i), height, width) - # 2. Subtract off the mean and divide by the variance of the pixels. - image = tf.image.per_image_whitening(image) - # 5. Append the image to a batch. - image = tf.expand_dims(image, 0) - return tf.concat(0, [central_x, image]), tf.add(i, 1) - - result = tf.while_loop(cond=c, body=body, loop_vars=(central_x, i), parallel_iterations=16) - return result - - - - - - - - - +# def distorted_images(images=None, height=24, width=24): +# """Distort images for generating more training data. +# +# Features +# --------- +# They are cropped to height * width pixels randomly. +# +# They are approximately whitened to make the model insensitive to dynamic range. +# +# Randomly flip the image from left to right. +# +# Randomly distort the image brightness. +# +# Randomly distort the image contrast. +# +# Whiten (Normalize) the images. +# +# Parameters +# ---------- +# images : 4D Tensor +# The tensor or placeholder of images +# height : int +# The height for random crop. +# width : int +# The width for random crop. +# +# Returns +# ------- +# result : tuple of Tensor +# (Tensor for distorted images, Tensor for while loop index) +# +# Examples +# -------- +# >>> X_train, y_train, X_test, y_test = tl.files.load_cifar10_dataset(shape=(-1, 32, 32, 3), plotable=False) +# >>> sess = tf.InteractiveSession() +# >>> batch_size = 128 +# >>> x = tf.placeholder(tf.float32, shape=[batch_size, 32, 32, 3]) +# >>> distorted_images_op = tl.preprocess.distorted_images(images=x, height=24, width=24) +# >>> sess.run(tf.initialize_all_variables()) +# >>> feed_dict={x: X_train[0:batch_size,:,:,:]} +# >>> distorted_images, idx = sess.run(distorted_images_op, feed_dict=feed_dict) +# >>> tl.visualize.images2d(X_train[0:9,:,:,:], second=2, saveable=False, name='cifar10', dtype=np.uint8, fig_idx=20212) +# >>> tl.visualize.images2d(distorted_images[1:10,:,:,:], second=10, saveable=False, name='distorted_images', dtype=None, fig_idx=23012) +# +# Notes +# ------ +# - The first image in 'distorted_images' should be removed. +# +# References +# ----------- +# - `tensorflow.models.image.cifar10.cifar10_input `_ +# """ +# print("This function is deprecated, please use tf.map_fn instead, e.g:\n \ +# t_image = tf.map_fn(lambda img: tf.image.random_brightness(img, max_delta=32. / 255.), t_image)\n \ +# t_image = tf.map_fn(lambda img: tf.image.random_contrast(img, lower=0.5, upper=1.5), t_image)\n \ +# t_image = tf.map_fn(lambda img: tf.image.random_saturation(img, lower=0.5, upper=1.5), t_image)\n \ +# t_image = tf.map_fn(lambda img: tf.image.random_hue(img, max_delta=0.032), t_image)") +# exit() +# # print(" [Warning] distorted_images will be deprecated due to speed, see TFRecord tutorial for more info...") +# try: +# batch_size = int(images._shape[0]) +# except: +# raise Exception('unknow batch_size of images') +# distorted_x = tf.Variable(tf.constant(0.1, shape=[1, height, width, 3])) +# i = tf.Variable(tf.constant(0)) +# +# c = lambda distorted_x, i: tf.less(i, batch_size) +# +# def body(distorted_x, i): +# # 1. Randomly crop a [height, width] section of the image. +# image = tf.random_crop(tf.gather(images, i), [height, width, 3]) +# # 2. Randomly flip the image horizontally. +# image = tf.image.random_flip_left_right(image) +# # 3. Randomly change brightness. +# image = tf.image.random_brightness(image, max_delta=63) +# # 4. Randomly change contrast. +# image = tf.image.random_contrast(image, lower=0.2, upper=1.8) +# # 5. Subtract off the mean and divide by the variance of the pixels. +# image = tf.image.per_image_whitening(image) +# # 6. Append the image to a batch. +# image = tf.expand_dims(image, 0) +# return tf.concat(0, [distorted_x, image]), tf.add(i, 1) +# +# result = tf.while_loop(cond=c, body=body, loop_vars=(distorted_x, i), parallel_iterations=16) +# return result +# +# +# def crop_central_whiten_images(images=None, height=24, width=24): +# """Crop the central of image, and normailize it for test data. +# +# They are cropped to central of height * width pixels. +# +# Whiten (Normalize) the images. +# +# Parameters +# ---------- +# images : 4D Tensor +# The tensor or placeholder of images +# height : int +# The height for central crop. +# width : int +# The width for central crop. +# +# Returns +# ------- +# result : tuple Tensor +# (Tensor for distorted images, Tensor for while loop index) +# +# Examples +# -------- +# >>> X_train, y_train, X_test, y_test = tl.files.load_cifar10_dataset(shape=(-1, 32, 32, 3), plotable=False) +# >>> sess = tf.InteractiveSession() +# >>> batch_size = 128 +# >>> x = tf.placeholder(tf.float32, shape=[batch_size, 32, 32, 3]) +# >>> central_images_op = tl.preprocess.crop_central_whiten_images(images=x, height=24, width=24) +# >>> sess.run(tf.initialize_all_variables()) +# >>> feed_dict={x: X_train[0:batch_size,:,:,:]} +# >>> central_images, idx = sess.run(central_images_op, feed_dict=feed_dict) +# >>> tl.visualize.images2d(X_train[0:9,:,:,:], second=2, saveable=False, name='cifar10', dtype=np.uint8, fig_idx=20212) +# >>> tl.visualize.images2d(central_images[1:10,:,:,:], second=10, saveable=False, name='central_images', dtype=None, fig_idx=23012) +# +# Notes +# ------ +# The first image in 'central_images' should be removed. +# +# Code References +# ---------------- +# - ``tensorflow.models.image.cifar10.cifar10_input`` +# """ +# print("This function is deprecated, please use tf.map_fn instead, e.g:\n \ +# t_image = tf.map_fn(lambda img: tf.image.random_brightness(img, max_delta=32. / 255.), t_image)\n \ +# t_image = tf.map_fn(lambda img: tf.image.random_contrast(img, lower=0.5, upper=1.5), t_image)\n \ +# t_image = tf.map_fn(lambda img: tf.image.random_saturation(img, lower=0.5, upper=1.5), t_image)\n \ +# t_image = tf.map_fn(lambda img: tf.image.random_hue(img, max_delta=0.032), t_image)") +# exit() +# # print(" [Warning] crop_central_whiten_images will be deprecated due to speed, see TFRecord tutorial for more info...") +# try: +# batch_size = int(images._shape[0]) +# except: +# raise Exception('unknow batch_size of images') +# central_x = tf.Variable(tf.constant(0.1, shape=[1, height, width, 3])) +# i = tf.Variable(tf.constant(0)) +# +# c = lambda central_x, i: tf.less(i, batch_size) +# +# def body(central_x, i): +# # 1. Crop the central [height, width] of the image. +# image = tf.image.resize_image_with_crop_or_pad(tf.gather(images, i), height, width) +# # 2. Subtract off the mean and divide by the variance of the pixels. +# image = tf.image.per_image_whitening(image) +# # 5. Append the image to a batch. +# image = tf.expand_dims(image, 0) +# return tf.concat(0, [central_x, image]), tf.add(i, 1) +# +# result = tf.while_loop(cond=c, body=body, loop_vars=(central_x, i), parallel_iterations=16) +# return result +# +# +# diff --git a/tensorlayer/rein.py b/tensorlayer/rein.py index 9ad3de7c..f37561e4 100644 --- a/tensorlayer/rein.py +++ b/tensorlayer/rein.py @@ -1,5 +1,5 @@ #! /usr/bin/python -# -*- coding: utf8 -*- +# -*- coding: utf-8 -*- @@ -60,26 +60,75 @@ def cross_entropy_reward_loss(logits, actions, rewards, name=None): Examples ---------- - >>> states_batch_pl = tf.placeholder(tf.float32, shape=[None, D]) # observation for training - >>> network = tl.layers.InputLayer(states_batch_pl, name='input_layer') - >>> network = tl.layers.DenseLayer(network, n_units=H, act = tf.nn.relu, name='relu1') - >>> network = tl.layers.DenseLayer(network, n_units=3, act = tl.activation.identity, name='output_layer') + >>> states_batch_pl = tf.placeholder(tf.float32, shape=[None, D]) + >>> network = InputLayer(states_batch_pl, name='input') + >>> network = DenseLayer(network, n_units=H, act=tf.nn.relu, name='relu1') + >>> network = DenseLayer(network, n_units=3, name='out') >>> probs = network.outputs >>> sampling_prob = tf.nn.softmax(probs) >>> actions_batch_pl = tf.placeholder(tf.int32, shape=[None]) >>> discount_rewards_batch_pl = tf.placeholder(tf.float32, shape=[None]) - >>> loss = cross_entropy_reward_loss(probs, actions_batch_pl, discount_rewards_batch_pl) + >>> loss = tl.rein.cross_entropy_reward_loss(probs, actions_batch_pl, discount_rewards_batch_pl) >>> train_op = tf.train.RMSPropOptimizer(learning_rate, decay_rate).minimize(loss) """ - try: # TF 1.0 + try: # TF 1.0+ cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(labels=actions, logits=logits, name=name) except: cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=logits, targets=actions) # cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(logits, actions) - try: ## TF1.0 + try: ## TF1.0+ loss = tf.reduce_sum(tf.multiply(cross_entropy, rewards)) except: ## TF0.12 loss = tf.reduce_sum(tf.mul(cross_entropy, rewards)) # element-wise mul return loss + +def log_weight(probs, weights, name='log_weight'): + """Log weight. + + Parameters + ----------- + probs : tensor + If it is a network output, usually we should scale it to [0, 1] via softmax. + weights : tensor + """ + with tf.variable_scope(name): + exp_v = tf.reduce_mean(tf.log(probs) * weights) + return exp_v + + + +def choice_action_by_probs(probs=[0.5, 0.5], action_list=None): + """Choice and return an an action by given the action probability distribution. + + Parameters + ------------ + probs : a list of float. + The probability distribution of all actions. + action_list : None or a list of action in integer, string or others. + If None, returns an integer range between 0 and len(probs)-1. + + Examples + ---------- + >>> for _ in range(5): + >>> a = choice_action_by_probs([0.2, 0.4, 0.4]) + >>> print(a) + ... 0 + ... 1 + ... 1 + ... 2 + ... 1 + >>> for _ in range(3): + >>> a = choice_action_by_probs([0.5, 0.5], ['a', 'b']) + >>> print(a) + ... a + ... b + ... b + """ + if action_list is None: + n_action = len(probs) + action_list = np.arange(n_action) + else: + assert len(action_list) == len(probs), "Number of actions should equal to number of probabilities." + return np.random.choice(action_list, p=probs) diff --git a/tensorlayer/third_party/__init__.py b/tensorlayer/third_party/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tensorlayer/third_party/roi_pooling/.gitignore b/tensorlayer/third_party/roi_pooling/.gitignore new file mode 100644 index 00000000..08030a8f --- /dev/null +++ b/tensorlayer/third_party/roi_pooling/.gitignore @@ -0,0 +1,3 @@ +.ipynb_checkpoints/ +build/ + diff --git a/tensorlayer/third_party/roi_pooling/README.md b/tensorlayer/third_party/roi_pooling/README.md new file mode 100644 index 00000000..d597cea9 --- /dev/null +++ b/tensorlayer/third_party/roi_pooling/README.md @@ -0,0 +1,56 @@ +# Hint from TensorLayer +- This implementation is from `https://github.com/deepsense-ai/roi-pooling`, date: 31 Aug 2017. +- To install this, you have to clone TensorLayer from Github instead of pip install. +- Remember to modify the `CUDA_LIB` in Makefile before running `python setup.py install` in this folder. +- Make sure `roi_pooling_example.py` and `test_roi_layer.py` is runable. + + +---- + + +## RoI pooling in TensorFlow + +This repo contains the implementation of **Region of Interest pooling** as a custom TensorFlow operation. The CUDA code responsible for the computations was largely taken from the original [Caffe implementation by Ross Girshick](https://github.com/rbgirshick/fast-rcnn). + +For more information about RoI pooling you can check out [Region of interest pooling explained](https://deepsense.io/region-of-interest-pooling-explained/) at our [deepsense.io](https://deepsense.io/) blog. + +![Region of Interest Pooling animation](roi_pooling_animation.gif) + + +## Requirements + +To compile and use `roi_pooling` layer you need to have: + +* [CUDA](https://developer.nvidia.com/cuda-toolkit) (tested with 8.0) +* [https://www.tensorflow.org/](TensorFlow) (tested with 0.12.0 and 1.0.0) + +Only official TensorFlow releases are currently supported. If you're using a custom built TensorFlow compiled with a different GCC version (e.g. 5.X) you may need to modify the makefile to [enable the new ABI version](https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_dual_abi.html). + + +## Install + +Since it uses compilation + +```bash +$ git clone git@github.com:deepsense-io/roi-pooling.git +$ cd roi-pooling +$ python setup.py install +``` + +Right now we provide only GPU implementation (no CPU at this time). + + +## Usage + +After successful installation you can use the operation like this: + +```python +from roi_pooling.roi_pooling_ops import roi_pooling + +# here obtain feature map and regions of interest +rpooling = roi_pooling(feature_map, rois, 7, 7) +# continue the model +``` + +Working example in Jupyter Notebook: [examples/roi_pooling_minimal_example.ipynb](https://github.com/deepsense-io/roi-pooling/blob/master/examples/roi_pooling_minimal_example.ipynb) + diff --git a/tensorlayer/third_party/roi_pooling/examples/__init__.py b/tensorlayer/third_party/roi_pooling/examples/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tensorlayer/third_party/roi_pooling/examples/roi_pooling_minimal_example.ipynb b/tensorlayer/third_party/roi_pooling/examples/roi_pooling_minimal_example.ipynb new file mode 100644 index 00000000..c1edc353 --- /dev/null +++ b/tensorlayer/third_party/roi_pooling/examples/roi_pooling_minimal_example.ipynb @@ -0,0 +1,148 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "* blog post: [Region of interest pooling explained - deepsense.io](https://deepsense.io/region-of-interest-pooling-explained/)\n", + "* repository: [deepsense-io/roi-pooling](https://github.com/deepsense-io/roi-pooling)" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "from __future__ import print_function\n", + "\n", + "import tensorflow as tf\n", + "import numpy as np\n", + "\n", + "from roi_pooling.roi_pooling_ops import roi_pooling" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# 4x4 feature map with only 1 channel\n", + "input_value = [[\n", + " [[1], [2], [4], [4]],\n", + " [[3], [4], [1], [2]],\n", + " [[6], [2], [1], [7]],\n", + " [[1], [3], [2], [8]]\n", + "]]\n", + "input_value = np.asarray(input_value, dtype='float32')" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# regions of interest as lists of:\n", + "# feature map index, upper left, bottom right coordinates\n", + "rois_value = [\n", + " [0, 0, 0, 1, 3],\n", + " [0, 2, 2, 3, 3],\n", + " [0, 1, 0, 3, 2]\n", + "]\n", + "rois_value = np.asarray(rois_value, dtype='int32')\n", + "\n", + "# in this case we have 3 RoI pooling operations:\n", + "# * channel 0, rectangular region (0, 0) to (1, 3)\n", + "# xx..\n", + "# xx..\n", + "# xx..\n", + "# xx..\n", + "#\n", + "# * channel 0, rectangular region (2, 2) to (3, 3)\n", + "# ....\n", + "# ....\n", + "# ..xx\n", + "# ..xx\n", + "# * channel 0, rectangular region (1, 0) to (3, 2)\n", + "# ....\n", + "# xxx.\n", + "# xxx.\n", + "# xxx." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[[[[ 3. 4.]\n", + " [ 6. 3.]]]\n", + "\n", + "\n", + " [[[ 1. 7.]\n", + " [ 2. 8.]]]\n", + "\n", + "\n", + " [[[ 4. 4.]\n", + " [ 4. 7.]]]]\n" + ] + } + ], + "source": [ + "input_featuremap = tf.placeholder(tf.float32)\n", + "rois = tf.placeholder(tf.int32)\n", + "input_const = tf.constant(input_value, tf.float32)\n", + "rois_const = tf.constant(rois_value, tf.int32)\n", + "y = roi_pooling(input_const, rois_const, pool_height=2, pool_width=2)\n", + "\n", + "with tf.Session('') as sess:\n", + " y_output = sess.run(y, feed_dict={input_featuremap: input_value, rois: rois_value})\n", + " print(y_output)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 2", + "language": "python", + "name": "python2" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.12" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/tensorlayer/third_party/roi_pooling/roi_pooling/Makefile b/tensorlayer/third_party/roi_pooling/roi_pooling/Makefile new file mode 100644 index 00000000..db9de786 --- /dev/null +++ b/tensorlayer/third_party/roi_pooling/roi_pooling/Makefile @@ -0,0 +1,18 @@ +TF_INC = $(shell python -c 'import tensorflow as tf; print(tf.sysconfig.get_include())') +CUDA_LIB = /usr/local/cuda-8.0/lib64 + +all: clean build test + +build: roi_pooling.so + +roi_pooling.cu.o: roi_pooling.cu.cc + nvcc -std=c++11 -c -o $@ $? -I $(TF_INC) -D GOOGLE_CUDA=1 -x cu -Xcompiler -fPIC -D _GLIBCXX_USE_CXX11_ABI=0 + +roi_pooling.so: roi_pooling.cc roi_pooling.cu.o + g++ -std=c++11 -shared -o $@ $? -I $(TF_INC) -fPIC -lcudart -L$(CUDA_LIB) -D _GLIBCXX_USE_CXX11_ABI=0 + +test: build + python roi_pooling_test.py + +clean: + rm -f *.o *.so *.pyc *.npy diff --git a/tensorlayer/third_party/roi_pooling/roi_pooling/__init__.py b/tensorlayer/third_party/roi_pooling/roi_pooling/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tensorlayer/third_party/roi_pooling/roi_pooling/roi_pooling.cc b/tensorlayer/third_party/roi_pooling/roi_pooling/roi_pooling.cc new file mode 100644 index 00000000..d1f123dc --- /dev/null +++ b/tensorlayer/third_party/roi_pooling/roi_pooling/roi_pooling.cc @@ -0,0 +1,162 @@ +#include "tensorflow/core/framework/op.h" +#include "tensorflow/core/framework/op_kernel.h" +#include +#include +#include + +using namespace tensorflow; +using namespace std; + +REGISTER_OP("RoiPooling") +.Input("input: float32") +.Input("rois: int32") +.Attr("pool_height: int") +.Attr("pool_width: int") +.Output("output: float32") +.Output("argmax_output: int32"); + + +#define Dtype float + +void RoiPoolingKernelLauncher(const float* input, const int* rois, int n_rois, int channels, int height, int width, + int pooled_height, int pooled_width, Dtype* output, int* argmax_output); + +// IMPORTANT(maciek): need info about storage of the data in memory, assumed something but need the docs confirming it + +class RoiPoolingOp : public OpKernel { + private: + int pool_height_, pool_width_; + public: + explicit RoiPoolingOp(OpKernelConstruction* context) : OpKernel(context) { + OP_REQUIRES_OK(context, + context->GetAttr("pool_height", &pool_height_)); + + OP_REQUIRES_OK(context, + context->GetAttr("pool_width", &pool_width_)); + } + + + void Compute(OpKernelContext* context) override { + // Grab the input tensor + const Tensor& input_tensor = context->input(0); + const Tensor& rois_tensor = context->input(1); + + auto input = input_tensor.flat(); + auto rois = rois_tensor.flat(); + + // Create an output tensor + Tensor* output_tensor = NULL; + Tensor* argmax_output_tensor = NULL; + + auto input_shape = input_tensor.shape(); + auto rois_shape = rois_tensor.shape(); + + int n_rois = rois_shape.dim_size(0); + int height = input_shape.dim_size(1); + int width = input_shape.dim_size(2); + int channels = input_shape.dim_size(3); + + TensorShape output_shape = TensorShape({static_cast(n_rois), + static_cast(channels), + static_cast(pool_height_), + static_cast(pool_width_)}); + + OP_REQUIRES_OK(context, context->allocate_output(0, output_shape, + &output_tensor)); + + OP_REQUIRES_OK(context, context->allocate_output(1, output_shape, + &argmax_output_tensor)); + + auto output = output_tensor->template flat(); + auto argmax_output = argmax_output_tensor->template flat(); + + RoiPoolingKernelLauncher(input.data(), rois.data(), + n_rois, channels, + height, width, + pool_height_, pool_width_, + output.data(), argmax_output.data()); + } +}; + +REGISTER_KERNEL_BUILDER(Name("RoiPooling").Device(DEVICE_GPU), RoiPoolingOp); + +///////////// RoiPoolingGrad + + +REGISTER_OP("RoiPoolingGrad") +.Input("orig_input: float32") +.Input("orig_rois: int32") +.Input("orig_output: float32") +.Input("orig_argmax_output: int32") +.Input("orig_output_grad: float32") +.Attr("pool_height: int") +.Attr("pool_width: int") +.Output("output: float32") +.Doc(R"doc( + region of interest pooling grad +)doc"); + +#define Dtype float +void RoiPoolingGradKernelLauncher(const Dtype* orig_input, const int* orig_rois, + int mb_size, + int n_rois, int channels, int height, int width, + int pooled_height, int pooled_width, + const Dtype* orig_output, const int* orig_argmax_output, + const Dtype* orig_output_grad, + Dtype* output); + +// IMPORTANT(maciek): need info about storage of the data in memory, assumed something but need the docs confirming it + +class RoiPoolingGradOp : public OpKernel { + private: + int pool_height_, pool_width_; + public: + explicit RoiPoolingGradOp(OpKernelConstruction* context) : OpKernel(context) { + OP_REQUIRES_OK(context, + context->GetAttr("pool_height", &pool_height_)); + + OP_REQUIRES_OK(context, + context->GetAttr("pool_width", &pool_width_)); + } + + + void Compute(OpKernelContext* context) override { + // Grab the input tensor + const Tensor& orig_input_tensor = context->input(0); + const Tensor& orig_rois_tensor = context->input(1); + const Tensor& orig_output_tensor = context->input(2); + const Tensor& orig_argmax_output_tensor = context->input(3); + const Tensor& orig_output_grad_tensor = context->input(4); + + auto orig_input = orig_input_tensor.flat(); + auto orig_rois = orig_rois_tensor.flat(); + auto orig_output = orig_output_tensor.flat(); + auto orig_argmax_output = orig_argmax_output_tensor.flat(); + auto orig_output_grad = orig_output_grad_tensor.flat(); + + // Create an output tensor + Tensor* output_tensor = NULL; + auto orig_input_shape = orig_input_tensor.shape(); + auto orig_rois_shape = orig_rois_tensor.shape(); + auto grads_shape = orig_input_shape; + + int mb_size = orig_input_shape.dim_size(0); + int n_rois = orig_rois_shape.dim_size(0); + int height = orig_input_shape.dim_size(1); + int width = orig_input_shape.dim_size(2); + int channels = orig_input_shape.dim_size(3); + + OP_REQUIRES_OK(context, context->allocate_output(0, grads_shape, + &output_tensor)); + + auto output = output_tensor->template flat(); + + // Call the cuda kernel launcher + RoiPoolingGradKernelLauncher(orig_input.data(), orig_rois.data(), + mb_size, n_rois, channels, height, width, pool_height_, pool_width_, + orig_output.data(), orig_argmax_output.data(), orig_output_grad.data(), output.data()); + } +}; + + +REGISTER_KERNEL_BUILDER(Name("RoiPoolingGrad").Device(DEVICE_GPU), RoiPoolingGradOp); diff --git a/tensorlayer/third_party/roi_pooling/roi_pooling/roi_pooling.cu.cc b/tensorlayer/third_party/roi_pooling/roi_pooling/roi_pooling.cu.cc new file mode 100644 index 00000000..bbacb552 --- /dev/null +++ b/tensorlayer/third_party/roi_pooling/roi_pooling/roi_pooling.cu.cc @@ -0,0 +1,214 @@ +#if GOOGLE_CUDA + +#include +#include +#define EIGEN_USE_GPU +#include "third_party/eigen3/unsupported/Eigen/CXX11/Tensor" + +// CUDA: index helpers +#define idx4_4(index, d1, d2, d3, d4) (index % d4) +#define idx4_3(index, d1, d2, d3, d4) ((index / d4) % d3) +#define idx4_2(index, d1, d2, d3, d4) ((index / d4 / d3) % d2) +#define idx4_1(index, d1, d2, d3, d4) ((index / d4 / d3 / d2) %d1) + +// CUDA: various checks for different function calls. +#define CUDA_CHECK(condition) \ + /* Code block avoids redefinition of cudaError_t error */ \ + do { \ + cudaError_t error = condition; \ + if (error != cudaSuccess) { \ + return 1; \ + } \ + } while (0) + +// CUDA: grid stride looping +#define CUDA_KERNEL_LOOP(i, n) \ + for (int i = blockIdx.x * blockDim.x + threadIdx.x; \ + i < (n); \ + i += blockDim.x * gridDim.x) + +// CUDA: use 512 threads per block +const int CAFFE_CUDA_NUM_THREADS = 512; + +// CUDA: number of blocks for threads. +inline int CAFFE_GET_BLOCKS(const int N) { + // TODO rewrite this part to be consistent with tf conventions + int optimal_number_of_blocks = (N + CAFFE_CUDA_NUM_THREADS - 1) / CAFFE_CUDA_NUM_THREADS; + int max_number_of_blocks = 65000; + return std::min(optimal_number_of_blocks, max_number_of_blocks); +} + + +#define Dtype float + +__global__ void RoiPoolingKernel(const Dtype* input, const int* rois, + int n_rois, int channels, int height, int width, + int pooled_height, int pooled_width, + Dtype* output, int* argmax_output) { + int output_size = n_rois * channels * pooled_height * pooled_width; + + CUDA_KERNEL_LOOP(index, output_size) { + // (n, c, ph, pw) is an element in the pooled output + int pw = idx4_4(index, n_rois, channels, pooled_height, pooled_width); + int ph = idx4_3(index, n_rois, channels, pooled_height, pooled_width); + int c = idx4_2(index, n_rois, channels, pooled_height, pooled_width); + int n = idx4_1(index, n_rois, channels, pooled_height, pooled_width); + + auto bottom_rois_act = rois + n * 5; + + int roi_batch_ind = bottom_rois_act[0]; + int roi_start_w = bottom_rois_act[1]; + int roi_start_h = bottom_rois_act[2]; + int roi_end_w = bottom_rois_act[3]; + int roi_end_h = bottom_rois_act[4]; + + // Force malformed ROIs to be 1x1 + // NOTE(maciek): roi_start, roi_end seems to be inclusive + int roi_width = max(roi_end_w - roi_start_w + 1, 1); + int roi_height = max(roi_end_h - roi_start_h + 1, 1); + + // divide the ROIs into smaller regions for max pooling + Dtype bin_size_h = static_cast(roi_height) / static_cast(pooled_height); + Dtype bin_size_w = static_cast(roi_width) / static_cast(pooled_width); + + // compute the precise coordinates of each pooling subregion of the ROIs + int hstart = static_cast(floor(static_cast(ph) * bin_size_h)); + int wstart = static_cast(floor(static_cast(pw) * bin_size_w)); + int hend = static_cast(ceil(static_cast(ph + 1) * bin_size_h)); + int wend = static_cast(ceil(static_cast(pw + 1) * bin_size_w)); + + // Add roi offsets and clip to input boundaries + hstart = min(max(hstart + roi_start_h, 0), height); + hend = min(max(hend + roi_start_h, 0), height); + wstart = min(max(wstart + roi_start_w, 0), width); + wend = min(max(wend + roi_start_w, 0), width); + + //printf("%d %d %d %d %d %d %d %d\n", n, c, pw, ph, hstart, hend, wstart, wend); + + bool is_empty = (hend <= hstart) || (wend <= wstart); + + // Define an empty pooling region to be zero + + Dtype maxval = is_empty ? 0 : -999999999.0; + //Dtype maxval = is_empty ? 0 : -FLT_MAX; + // If nothing is pooled, argmax = -1 causes nothing to be backprop'd + + int maxidx = -1; + auto input_act = input + (roi_batch_ind * height * width * channels); + for (int h = hstart; h < hend; ++h) { + for (int w = wstart; w < wend; ++w) { + int bottom_index = (h * width + w) * channels + c; + + // bottom index is relative to 2d image only + if (input_act[bottom_index] > maxval) { + maxval = input_act[bottom_index]; + maxidx = bottom_index; + } + } + } + output[index] = maxval; + argmax_output[index] = maxidx; + } +} + + +void RoiPoolingKernelLauncher(const float* input, const int* rois, int n_rois, int channels, int height, int width, + int pooled_height, int pooled_width, Dtype* output, int* argmax_output) { + int out_size = n_rois * channels * pooled_height * pooled_width; + + RoiPoolingKernel<<>>(input, rois, n_rois, channels, height, width, + pooled_height, pooled_width, output, argmax_output); +} + + +/////////////// Grad +__global__ void RoiPoolingGradKernel(const Dtype* orig_input, const int* orig_rois, + int mb_size, + int n_rois, int channels, int height, int width, + int pooled_height, int pooled_width, + const Dtype* orig_output, const int* orig_argmax_output, + const Dtype* orig_output_grad, + Dtype* output) { + + int orig_input_size = mb_size * height * width * channels; + + CUDA_KERNEL_LOOP(index, orig_input_size) { + // (n, h, w, c) coords in bottom data + int c = idx4_4(index, mb_size, height, width, channels); + int w = idx4_3(index, mb_size, height, width, channels); + int h = idx4_2(index, mb_size, height, width, channels); + int n = idx4_1(index, mb_size, height, width, channels); + + Dtype gradient = 0; + // Accumulate gradient over all ROIs that pooled this element + for (int roi_n = 0; roi_n < n_rois; ++roi_n) { + const int* offset_bottom_rois = orig_rois + roi_n * 5; + int roi_batch_ind = offset_bottom_rois[0]; + // Skip if ROI's batch index doesn't match n + if (n != roi_batch_ind) { + continue; + } + + int roi_start_w = offset_bottom_rois[1]; + int roi_start_h = offset_bottom_rois[2]; + int roi_end_w = offset_bottom_rois[3]; + int roi_end_h = offset_bottom_rois[4]; + + // Skip if ROI doesn't include (h, w) + const bool in_roi = (w >= roi_start_w && w <= roi_end_w && + h >= roi_start_h && h <= roi_end_h); + if (!in_roi) { + continue; + } + + int offset = (roi_n * channels + c) * pooled_height * pooled_width; + const Dtype* offset_top_diff = orig_output_grad + offset; + const int* offset_argmax_data = orig_argmax_output + offset; + + // Compute feasible set of pooled units that could have pooled + // this bottom unit + + // Force malformed ROIs to be 1x1 + int roi_width = max(roi_end_w - roi_start_w + 1, 1); + int roi_height = max(roi_end_h - roi_start_h + 1, 1); + + Dtype bin_size_h = static_cast(roi_height) / static_cast(pooled_height); + Dtype bin_size_w = static_cast(roi_width) / static_cast(pooled_width); + + int phstart = floor(static_cast(h - roi_start_h) / bin_size_h); + int phend = ceil(static_cast(h - roi_start_h + 1) / bin_size_h); + int pwstart = floor(static_cast(w - roi_start_w) / bin_size_w); + int pwend = ceil(static_cast(w - roi_start_w + 1) / bin_size_w); + + phstart = min(max(phstart, 0), pooled_height); + phend = min(max(phend, 0), pooled_height); + pwstart = min(max(pwstart, 0), pooled_width); + pwend = min(max(pwend, 0), pooled_width); + + for (int ph = phstart; ph < phend; ++ph) { + for (int pw = pwstart; pw < pwend; ++pw) { + if (offset_argmax_data[ph * pooled_width + pw] == (h * width + w)) { + gradient += offset_top_diff[ph * pooled_width + pw]; + } + } + } + } + output[index] = gradient; + } + +} + +void RoiPoolingGradKernelLauncher(const Dtype* orig_input, const int* orig_rois, + int mb_size, + int n_rois, int channels, int height, int width, + int pooled_height, int pooled_width, + const Dtype* orig_output, const int* orig_argmax_output, + const Dtype* orig_output_grad, + Dtype* output) { + int out_size = mb_size * height * width * channels; + RoiPoolingGradKernel<<>>(orig_input, orig_rois, + mb_size, n_rois, channels, height, width, pooled_height, pooled_width, + orig_output, orig_argmax_output, orig_output_grad, output); +} + +#endif diff --git a/tensorlayer/third_party/roi_pooling/roi_pooling/roi_pooling_ops.py b/tensorlayer/third_party/roi_pooling/roi_pooling/roi_pooling_ops.py new file mode 100644 index 00000000..5c46dc37 --- /dev/null +++ b/tensorlayer/third_party/roi_pooling/roi_pooling/roi_pooling_ops.py @@ -0,0 +1,51 @@ +import tensorflow as tf +from tensorflow.python.framework import ops +import os + +module_path = os.path.realpath(__file__) +module_dir = os.path.dirname(module_path) +lib_path = os.path.join(module_dir, 'roi_pooling.so') +roi_pooling_module = tf.load_op_library(lib_path) + +def roi_pooling(input, rois, pool_height, pool_width): + """ + returns a tensorflow operation for computing the Region of Interest Pooling + + @arg input: feature maps on which to perform the pooling operation + @arg rois: list of regions of interest in the format (feature map index, upper left, bottom right) + @arg pool_width: size of the pooling sections + """ + # TODO(maciek): ops scope + out = roi_pooling_module.roi_pooling(input, rois, pool_height=pool_height, pool_width=pool_width) + output, argmax_output = out[0], out[1] + return output + + +@ops.RegisterGradient("RoiPooling") +def _RoiPoolingGrad(op, *grads): + orig_inputs = op.inputs[0] + orig_rois = op.inputs[1] + orig_output = op.outputs[0] + orig_argmax_output = op.outputs[1] + + orig_output_grad = grads[0] + output_grad = roi_pooling_module.roi_pooling_grad(orig_inputs, orig_rois, orig_output, + orig_argmax_output, orig_output_grad, + pool_height=op.get_attr('pool_height'), + pool_width=op.get_attr('pool_width')) + return [output_grad, None] + + +@ops.RegisterShape("RoiPooling") +def _RoiPoolingShape(op): + input = op.inputs[0] + rois = op.inputs[1] + + n_rois = rois.get_shape()[0] + n_channels = input.get_shape()[3] + pool_height = op.get_attr('pool_height') + pool_width = op.get_attr('pool_width') + + #TODO: check the width/hegiht order + return [tf.TensorShape([n_rois, n_channels, pool_width, pool_height]), + tf.TensorShape(None)] diff --git a/tensorlayer/third_party/roi_pooling/roi_pooling/roi_pooling_test.py b/tensorlayer/third_party/roi_pooling/roi_pooling/roi_pooling_test.py new file mode 100644 index 00000000..c5f1b361 --- /dev/null +++ b/tensorlayer/third_party/roi_pooling/roi_pooling/roi_pooling_test.py @@ -0,0 +1,110 @@ +import tensorflow as tf +import numpy as np +from roi_pooling_ops import roi_pooling + + +class RoiPoolingTest(tf.test.TestCase): + # TODO(maciek): add python, implementation and test outputs + # TODO(maciek): test pool_height != pool_width, height != width + + def test_roi_pooling_grad(self): + # TODO(maciek): corner cases + input_value = [[ + [[1], [2], [4], [4]], + [[3], [4], [1], [2]], + [[6], [2], [1], [7.0]], + [[1], [3], [2], [8]] + ]] + input_value = np.asarray(input_value, dtype='float32') + + rois_value = [ + [0, 0, 0, 1, 1], + [0, 1, 1, 2, 2], + [0, 2, 2, 3, 3], + [0, 0, 0, 2, 2], + [0, 0, 0, 3, 3] + ] + rois_value = np.asarray(rois_value, dtype='int32') + + with tf.Session(''): + # NOTE(maciek): looks like we have to use consts here, based on tensorflow/python/ops/nn_test.py + input_const = tf.constant(input_value, tf.float32) + rois_const = tf.constant(rois_value, tf.int32) + y = roi_pooling(input_const, rois_const, pool_height=2, pool_width=2) + mean = tf.reduce_mean(y) + + numerical_grad_error_1 = tf.test.compute_gradient_error( + [input_const], [input_value.shape], y, [5, 2, 2, 1]) + + numerical_grad_error_2 = tf.test.compute_gradient_error( + [input_const], [input_value.shape], mean, []) + + self.assertLess(numerical_grad_error_1, 1e-4) + self.assertLess(numerical_grad_error_2, 1e-4) + + def test_shape_inference_1(self): + pooled_w, pooled_h = 2, 2 + input_w, input_h = 200, 200 + n_channels = 3 + n_batches = None + input = tf.placeholder(tf.float32, shape=[n_batches, input_w, input_h, n_channels]) + + n_rois = None + single_roi_dimension = 5 + rois = tf.placeholder(tf.int32, shape=[n_rois, single_roi_dimension]) + + y = roi_pooling(input, rois, pool_height=pooled_w, pool_width=pooled_h) + + self.assertEqual(y.get_shape().ndims, 4) + self.assertIs(y.get_shape()[0].value, n_rois) + self.assertIs(y.get_shape()[1].value, n_channels) + self.assertIs(y.get_shape()[2].value, pooled_h) + self.assertIs(y.get_shape()[3].value, pooled_w) + + def test_shape_inference_2(self): + pooled_w, pooled_h = 3, 4 + input_w, input_h = 200, 300 + n_channels = 3 + n_batches = None + input = tf.placeholder(tf.float32, shape=[n_batches, input_w, input_h, n_channels]) + + n_rois = None + single_roi_dimension = 5 + rois = tf.placeholder(tf.int32, shape=[n_rois, single_roi_dimension]) + + y = roi_pooling(input, rois, pool_height=pooled_w, pool_width=pooled_h) + + self.assertEqual(y.get_shape().ndims, 4) + self.assertIs(y.get_shape()[0].value, n_rois) + self.assertIs(y.get_shape()[1].value, n_channels) + self.assertIs(y.get_shape()[2].value, pooled_h) + self.assertIs(y.get_shape()[3].value, pooled_w) + + def test_very_big_output(self): + """ + This test checks whether the layer can handle a corner case + where the number of output pixels is very large, possibly larger + than the number of available GPU threads + """ + + pooled_w, pooled_h = 7,7 + input_w, input_h = 72, 240 + n_channels = 512 + n_batches = 2 + x_input = np.ones(shape=(n_batches, input_w, input_h, n_channels)) + n_rois = 5000 + rois_input = np.ones(shape=(n_rois, 5)) + + input = tf.placeholder(tf.float32, shape=[n_batches, input_w, input_h, n_channels]) + single_roi_dimension = 5 + rois = tf.placeholder(tf.int32, shape=[n_rois, single_roi_dimension]) + + y = roi_pooling(input, rois, pool_height=pooled_w, pool_width=pooled_h) + + with tf.Session('') as sess: + y_output = sess.run(y, feed_dict={input: x_input, rois: rois_input}) + + self.assertTrue(np.all(y_output == 1)) + +if __name__ == '__main__': + tf.test.main() diff --git a/tensorlayer/third_party/roi_pooling/roi_pooling_animation.gif b/tensorlayer/third_party/roi_pooling/roi_pooling_animation.gif new file mode 100644 index 0000000000000000000000000000000000000000..9d35d21a901061f8b0fd3995306e0a0e03dabdcc GIT binary patch literal 578933 zcmWhzWn2?p8(p(8y1Qc_AYF>mor+33LP}ahP|*!G7(G&&(IcgVQ942z94JVO0!pbM zsG$Dm>-*t;dA{BAd!FZ>d(JVlFxA%a6azbfegXghBoF{$g1{jFE&xCf0ODo@fH(nQ zApnvOz|G6U2?5E17}XdR)B#|aG>8|4ez8w+nu+$&U4#dE%LgYxxc!Z z@44#%YEA*VH}0#O-;?vZEgKVnx^++6|A9=@J&lMEK`%cGb1S1TOCyu}hS#EPZ%0~W zYDZ9XLsBKxQ=Ju3B6PchWSU~-n;*$kKRDMKi|Tlw(RELw`|icwNR7_>x;^)`yJFPq zqEN-bc3D@ib=ieAT3O}-IO?+q~QyJJqdcfISrebe3G?uekGD;EbMoW?w^PTq)~ zvk98H<~!vYIOXa);S@RJcyHPzaQ1p6%`tk`A!^noYTD9d@b<(YUHoxvX2asN21w**vV#zMk4h&dTZ^*^v;zx8-7FmVkYVs6P)Jf49--%m96HLsS=cV(Kk!sPNvMGO!X>th!^~3~;V!U{6s(4W{DmM{@&r-=w7bf9_ zNJ+wV@thSoQZ?~Xb@B2|akABT`L;Nn27+5}qD^y(Pbc2|Npk22?#5uk)Xdc6^vKlA z>@;oi@87>?zkht({`hX=ePv@&e5{oC83d5`Zw$o$B5h3^uNoQHo2V)&gMt4_3jYq^ z|6>Ax(*fTRLgp=`fp|ElyxUky`A{O8q-C*rYsJeHKDEHrvDV7b3^Ai*A&a)E@od!9 zdbjbm>d7a{-V?R#8{S6Y@>KC7Q^ zaB2@+n|Rjn_9=QOS=g$xajD(^b-nv!XVXeo*ycouRaf&`Z}jor+GN+$cP}ttq=+@8 z<^2$W^PI;NrFCFYlJM60wav+eKszQ5Rh``t``@6WFr zL-Z8Uj2O|g#7T`?VO3hTNg=JI)Y<$)wAI2#6l z<~iHUKmJ~cVK!n!8v%5U>C3x2hhZAWtAetxL^ zI{HU~Td^N1Iz=28|IP5NEqd?R@ABbpw@3|ST%PR`&WXOOc|+Z+X`vJD4S~6Jj7Vxr%t$)HryArguV2L)SfGO7Uhxm2kDwng&o3x2 z7k?Z0&ZrbMqvV%%<%13|ayy1>=4&-{7n*F49OHv49>)};^o8L$87eue&A(KXi|{X#Mn`DE?+>b8eR zBjC8PRyyZOjmu%Ci;_<5(oeD7>JyFLm5ZOR4Hcd4eSGq__nl<#Bk#uzysSSCV0#|l zUPCHh{r*c$Sv$J_q<5(QyzeJLzJ-IA)aUGtL2{nXfV0ZJzpIV6V=DyGj60sU?Pf^+ zF}j)2X7VxB!~Nds zmrU2iSWk#oqUPQ97sGc zdzty38JC@6I3Y3egIIWn*>8kHYC>^^>>Wo#(e$=3{>huaqm3;sn!ja)TT1`u6F02z zA@g#hl*F6mx0l<-Z~G$MR_VWXxDg`}QU)hCpu)9Qipg^+-%@G@ICS*SeY48wQkZ;e z%cJS>+#!}D$QO*bp|1>UFTDAO#5cP*Y4t0j#B#v*vy|*BtIpO`8M?Kvrk+>TgVW=( z9~3kFzq_vX$1$XWik>yVqLUa8S9XM5GgdD%29klSc$Ua=HjUf*#|GEibt9XU zP4=B-@7t3XG#b_W&*?KPFFZ~DUMZp2VE1@=HrJH9g z2>?8SVtf^QohK74+8GxW^7YTT0EySzE1~-S4!2#VA{MO3DfHl5Kuiw^LIMD&pM!%_ zT-TO0yE^(6_h9y}Z?>Z-o!no-kwmvQ{9*uD^p`u{=iGN}Z}iNjHQz0{y><|CqjzRr zDZ2IC`qwKzdlvQ1$COX5?fJg#--MpuV>?{g7+L6S$qfd6b9MW@{^Z4UaC4A%%F_Am zg%0xP0|1QV3cZK$eR^9? z?E!*|wgFYf3?MziZYhK=O*$=n%X`V>tLV2h>7{vxUikLnN7WZpi2Nz0_!`?M*5U4% zs2R1A?I4iee)ml5^Y#*G$tSKqF*A|29TmLOJEj+Y&1Q(4R9vNkcpk<;Z_aeoXie|h zJ}7*hM^|NR)8D(2Ex=e~`>g)P^xpMeU8GfKe50SuzRSw51`3{H1yC8=3`ffK0JJ0rp$}{or=1iP@h?WiqSbe% zUEQP8Un096tbIxE5@YdX6#YXL+~hOUnwVvN_@Gko>A3`qwzY zz76=ht|8XvVG+biAr%r-!`~srWvXKHnLl=vep%$3%WB+~glx>X-TF~Z{OYzML(EjD z_?@(?l|0=$6eS;zl#)%iPnQ|)(+ozk5`x=Av0xzu$o${~Xxt=X&s>_Z{$j^a$_zQ3TvX)Nue|6XeBNJa$o5vm7xUDsr6v?%_wH z$1$(6ADxt&{r5@3E{S$EjwFsfB_QL$`o71{eg@OS$LIg7{~Y8~ zRmK7na)WQL$FDr0g2j}8ggvk!TU^WYA3!=gVQ;hiH|CW7V~F+9=ak34KfHSW-Q<0I zls{PT>!_)2hr#0@+z|c8i_4ln9{&x)843OQ^!QiTV+i3fbnG!8|1pSL<*Q6jR_VFBxaa|j6Qj~a&vAAyixbtIi=LpE>0OlH)VS$TKcY9a}Il-5faEmQ5{4^l|l^DR67z9s@ zFi(t)P7KLU3?{&0iHJ-9f}W+1Ahr;4(TLnbc;+EI$s9o>5Hj_XGBAW3OcId|k#q_t zQIhiE$+-YT`C?LreR3fQk*AMn&RWL9{-e{)0BR`)MsN% zT~4Xb{8KuknMO%W9gE24Xr^;)fYU?6=|rRaq2NUQ*gdUB%Qqgao~CW^rO!Wsm!m@= ze2<}v%rI>Xgq%*lhk;U<|Lc0Zm!H0@i~*ao^r4Y*@Hm0fI8h3cu1)--jg;QO3gi=I zZxFfiiS1%Ux;FODPMnfIQa>MQ9*v|N#%sWFg3j^kV{xK&aq8xo+KZV&<8kr?`t( z&j}U~$!p5Y+#g@?D{zL{u9H@ZEQiqkj zS0rnWmC`2i`D1&Rup$(!m<~=pKhF3xeq0W#K+ZZxh?MWnG9e)UoEFbGmzdL|u@p>Z z7YP~s39q74dI6E3V}aL`%hr;^@9N;~$4W0NGx)<3ZTWK@oXaBp%g%Ii9SU-;%Ei=g zz@55tUAl8K{YhD95@UTXw4Rh`PJ%5bWur+%G9nX=$k@m$V0)k%mNFXlq?fN^)G6iB zSqd(oqMMNVB0v9meyUu3Y8RX-B`G+~*>qzlI0+qFBA0$~Ijvy45-SF;-2iW}v9!db zF9M2w-K+ZURM^U2)D-a8j4{JTH)D~MA-G5s=gWL4SL|F*WN|J67gT#sWN1(_DJ}6b z1(}LYIP*_6^5iU~#gZ|LOrE6p$cc>0C|oxN*@q7ISj_(KdMW**bLkol|7kZnAvt@u z4*%Z*ez%)h-x*fU79EI!nbeip?Uvau)fEQjgrH&);7P1KBr=(l8%<)AN01ju$e!Gw z@w^%`BK0t@0Rs|VP7$AYB3EBAou4nVoO(AYMM6GbQXqfAJVjLikm_71eDts+3_fpG zu<93^-;!3^9b1xAu-R2v$`7yF0E754HV@MsEUR}Yg-rof4uMrClnfRfVxMy{C4l(6 z0Q*di$ah-w)`AENc*+TnpRUV%yHqQu9Z&1dTrP++*@^d+$1*2rZx%TSW z7?bj-jO2-2mc68^I2sBUcQKRlKA; z>t|z{)lQoUOj`go%}vCvyEHBLbOyOLtt>Yg1y-+xWk65Uo5u_5bqWu(3(0kl|6?fH z#1#HAe=4y&@jIq(zi6A^{_^#zpn zR>pD`%X*`Rc80*d694i%0AddLghHRFKwrooB2-A!S5RrGcg9nw`V}6oDKC0bKlFkC zw8mQxF6gxdM*$v{Ev2oRH-%cgSPG0K=*O=8N=ssEUbgS552*U)kAbdML76hhbyXJk zyFT?i-fqeGk3iJedCI60=W5ygbD1bY9^j@BISPvBbXu8v;{?Ww`Oe~mk|Kr1i)9o_ z5`PZ@FT`^YkY3UFv_0l_WOh<=_SMDKW>>sK5k9=D?Lk+W((Rm6i!znoI*TBfV;y7t zME&Fn3F?x^URci>m~6100uS(;bX)>)z!juCzm2=GKJ@2 z96X6QxH~YAR3x1G6qu699aB?yVURl@{&N1{deVd{QxI-i-4(cr`#%e1it{HkouCrh2*@{$F^5LW!2Fl zF#X!9p>v|6UAv;c{>e&Fs&w+mKyvB}mwdOPilp%rugS&`+-R6O+Ye>HtZvhPztb-C zzzJ;W1$70>mT;qA;LL|z_kNGT2#=596hh+|bd0$#jMD8q-p!wxl|mHxlhJR{%>&Q; zBQSW*KT`*eL)@mvzpWeOJe_!THZf(>3(+#wsKxQl)e&e;hoIiA#IOSVeyryO{VEyV|)OJ+>=fZ6`2GaO*nYtIjCS zXm@@pvWES;Je$unD9f*C^|*;xF1U2%xzko?0zxyH;(sG(XnoB)5R z^nR;A!)txLwu?*4m#wGV!-hwv5^b0g3wnCLk55e~)Pr=(s|!h9Nz>JZ(_G1`lUDWZ z_sdhm8oKH76&}4aH;Wd;_ZD!7x5GXCgN*s%Hm}rm-+EO_5akLk7ruyXYFfF62oPd#*(#+KqqE49*} zODc+s^9AGCJ$h$&yj2a6t&~2wbqGeKz^s`2 z%z`(m4Q*Ptb6s^vT+8#h(S2l>`SIA7iTR{VzJ6ZIeoMh8N2w#xbu$w3Oq+uFBd1TO zdkxDMp4pY=(@^VMC8JPm=bYAyhl(`4iOwQK^CdABaP-)3Ef#FayL#s?o4u;^hmR9` zs_2ZA$4>RLLSscGK~H7LPdhETvu$cz?#E>dx5xy)pO!0WE}oEOde5=gB4IsL9b3ZK z8^5N5?E^3mSodB!3l+JrQpNJ7cdDo6OQ{||^U5LE#69PZAIwWRrz?H4du`ZaIwxCp z-h6#}GI(oBao+V}2g#|gz^Q+ZdDQ>U0cEG$d1j&Ce*5M9?U&>=hYPQ!ZrEs8O00Cg z3T#-vJkfNR_EAsw-FDC8J2O;AUFt5G_Q$X5tn0D0{6N1PF>Yp2pm?@$^{IAIx{g(cz1k<6@FPnzSknm%+iWows^^{v}4A8Ga|h{Au(y z^Ml@=^fwwS&>3seb%m`N!H(+(q?G8bSH$HCTb|17NhmAa#=jKM+H``;LuzlZduhtfma(2I~rWms2JZ*Omo#>^S@cN^6zw?K@f^LukVc>byG@x|WUfzkt? z-8`$6@}=I9#DbA8K?|eA8L7Zj*Oifv4}R~SOWT}28N9Q8ujJ!FQ{`91bS$0p<%_^L zRHz!1_^w$8vqGfN-6_)UJKSSM>7O&Yx_5pv#^s!wOLs4xsjKBWizitv3tJ3vS+ywi zEh!4UX1J_ZH;Cs808`6&2nqZG9~n~d|rR7EX));dvkX6lYNn4;w9DlIkGlZ z+3F^3IRW#`0{x9YyrQP+TRa9SjNVbt_UE5EJrg;;Z~ggto9l~9`_DRgTeyJ-yF*1c zzIr^5{f`b6aymp0;+aKFi=B?VM$&}A>!WW=F}6tnAP3ius@QaqUMT&`fzHXN*)oG{ z9^(lHO4$3B{*lhwE3;28POLt-F6Fk_RY1+SMMf$HRjt+ zXR&12rOC7K?de?CzhB(?er!#LZudN!)cxg7iP~+71t!D zF2g#c-Xg2&zQhE%@KGF2wjy#aoLn5WH=boy+Gd=6&7O$mZ(bgpkZ)>aygiN@^|ESc zE1XJhXj$YiRqTkXLzaz>NVQw5y)ss_(Riz_pc=c{=ZCRn>84w=y|x`Xww*cYYgeCz z=)6n}?^t5iHoC(Zq8-%X(9vmnOVHNPqdp}>_fOuYQt$S}gXUhF%GXMc`yIVs^1dza z+v)va>R>f+T|PeFPv^jW@B8CpLc4xSdob_l^m_;@86h=HFi4RRG8gj^HYAjXNFCHj zBr+AkD@8w|EQ~X4KXg_qJ!fWj;~o;ul;jNnMWD|g+%mC} z(7BQz`&u=nQF?Q)-s(K!Bcq}$qVq~44iPdZ&jX>P*rc2v(e_T$`p9=)>$ryjW2-y> zR-3cF3LzRp1|XRxhj6Kn`9J%ZSc@)CR@q*#+gHfET1a0^m|Y6IljdOjEFjn+m~R?( zWs%S1m;E~rEA_4qh4C}G&X(1-7n~_Y_$SS`4Zcw9+ne!E_J2u!@3qykd8QM%QE8_K z-qqCL{jv9mo7dGT?b#RS;M}izJ)eJs@_KO1weW?K@ec))l5=;&{E-3)Bqrgl8mH;9 zG))(L-z*_D)cF8poawe#ks4~G0%j&o=xo;Qe0+HRJfu5FtR|hChG8&9gXrgfw2t9|Y>UUIZmEjH4TL1r3J^F6 zrEr6b_J?fwWVAmh9FBxZ#9>fNau= zt8>2ruXK8+;V)S}?J%4*mUb1X%V8e+aW>=W$96O5U0Wl@r0XiWH&Vyhr37ZhMzxex zQmdzp;s#&=9}a}&AzZd^6(X%oAF#6AAUw(3z$xn-IL99{s#SiGk2`H0bq})-?+CK$9*JGa;m4L7DEEfgk z8U+)E1mB$krAEV1K~>;HnA|8U<6UxC@rj^XwTo>GxTwL|GH5y6fW?Id(lunzdB-oW z5!N!iCsoVyCJei1`dzcjll|hv(FeuABavS;6$Tv|^!=ARrB$8!ygh`?2c`0F%D+|c z{3vHtDjaI~n?J$3btoj(uR@OxFKE zP$P+R`JI~Y`N&PKVz+XtbK({BT9?$u-n&+;H46C$Ou9yuvnEjxYD@TJ$2UBjIj9;n zQLL-&8%^%XH^$!|&bcnvNaULU88b@TlqC2OQ1uO8ou-OZG{gutumkEWEk0Cb{JjFido9OfoAA=BX504h0>WV!u-FEWH(ya_JRArY z3j;7v0Jlq2bCE(}7*>1P3rjKc+!=ww?mNLZp6Rz`U9~s8%I=@6wDZqex8HW@v()Rs z9D}nIu)3qqZbVL2y1idqL}q%!q@(pgQugtp_O=mgWGsXOgJCcSz+ToHRNPGk*gnDV zty87iMcy#m&ZV1(AYSsRZlGZYBrab}iQje$2FOMNfcdC+m0mFDq!0ky`Oac*oRzV| z!PyE;meFp-!cZ9M_`$Yv(l{E3(g(k)g4mVTVSTmG;37)W&*&;naqKIO;{0T$2|1=8 zbOR%pu=xr2y4WiZ>aBBfL@F4yhUNQX$p3-l@kUsGbqL08Yfu}(By8=ZLJfFtz z=6SJ*ZD3fU(FdY5Xk@w(l2v;H$f}LWP18l{P83Yu?Zk6EJuZ<-I0_9^Z&w;&0kvNc zgWj5Xb#ikX=V#9qm?i+50Ac3tg9+On@T^2sN-al`mC)pvM;|&!eqaV(sZ^ND#oh~*w0oS`&V5#GT0q{|Ee2Q7LNkkEBb4?*fcn^XDB zu?xL=vGMv($+g~#S*J^)o@}Itg!3uh13Zxi;ED6`^4+>XoY4*huz|UTCd2$O4u>u5 zZJ44Vh@&zd)`D?xQWgqAUERR~De-jOmTXRO{rnc=FnW2eSI){#0xmVd(-tE&b^ zXUMtM3ytAx>oZ;qur~iH0`Fe*Bl09~404dLp+qcK5fG1-iV#Z(g^!5RfF>(?USf^> zBrI1Yu&+>R+=B3Kh=7gGV`1lA8V7+kFw-soSXj0F4q2gYXu1&CPv6X<^i$eXAHt`?N z08v8BdG3b;r6=QM#@TUm3=jAK^fcka9m3z-uxOmtjYbC)(=;fhFuo8OBhbzQyV_Eb8ywUYzjZlVsz^EgZhf=ZI!nNCy z^Sq8#)lij}Rzx?w2(TAo>oCk1H^y8pKIcxemi%oLNX7@~7en6X4jQoCq?&}#q`XmB z07eRn0s`}a1`>I=!vrsDQ^YCk{ghN_G!}%y^7HX9>%c?(Vef|wt~(&{KE z)4wzYp~QX>08o}*&_SF;w%oYTw9Fqb$OmA-NI%&T&IoJb-Iexm(S+(lZHW-u4FD94 zw;>_SH*k;sBsx-?9K$-_c|lLC@E-(ZeB&~U*_6JjXn~nh8Ue5gTz^c3H9wyP$5wLK z9`smM`#`nUi$vwt#&Dn=9yG|}y|tPEwLN6MRPcm^#+>AT$kfS1{#5=v#GnHO$FfI< zfOfDBwAB0o+|N~jaSND*bj4a5V$24BQNRv65Rr~K7FTgONLp#7z*{~Bi(^>OSVHYN zjKGe{;$ni|MJ!6+h{v0&JOzWIU?5^ub>(%dn4F=Df`J$Sgo^Dd#CINJ%+&?k%V94g zfmdc()bC(~Hl~Cy75x|F6_B}_oW;jsZx~LE+(`*s$^h0KR?tz=jR0eC%haDkj8iT~ zDjqP|D0uy-=s$m!pXMwcR1;)t59AaUs15{>fqpv)UYW%HLM$(p%E=~0%Oq+(1Tw}D zuzY#U{5+!h;48_(YW@HipxSLB4j2Z~!ANr-RjFV=04nARtz?nD8+S$d`9An^E}Z7` z8fU|1UPZ8nQsRBCl;ZlqjMWh2HOz9>3$<$izg`@+@kwADB-WrykO1_=q(C3`1`>gu zL?EX*h6@GbsLE1chw+R#2*kqJ4=~_-tF|)Xg+o(PATr?a%q>dKoY;3xFZ?^ z(}x;R!Gb~4BdnZCIROX}bEPCI z-Je-YN3d}37%e&i<@PEp8|CY>xPOd61L4N>KpIqa(2W({u42jRwqdQYjF&_Lzyts* z#hC$(ZTf(3Nq%`^E(9@H7;QE6CSc&F=R!_l0&olm_1wGPSU4O2fn$)T4R%AO-hh$O zC0O5_l>YMiyG^2wy|9x!KH9B%0UP&UPJ9rM*BPW^HNBqsBl>`+SHr)CzGuK*a-a&-AC zfCoVfDhCO*7y3g_6F@}Uw=F$Lw#F_61|0~CZY0;La)pcpH!s|nmj-PcSY<)W)8X7U zpCv#*ECcGL`!#IKo|`2*tCb4(wSPo19wU@5=#KKy_*K+(rPz()%zK()n!3(&D$lKq zVbMP~WyP(N)i7nn=69Ig=vH>y;Vcqgtfdoo@FHxO3t`JR0oM!VVr;+54cQw%Ff(uz0T23yB1l-c zxlxYcX4olK00j^@#fDQbAmxOJ#hz8Cp0{jm`!p7t5bQ@XbQEghx&c*+V;NO2`JV3x zIRw~VddZraluo!~=C5IQyPP-UTC z6S{Ur<90jk3w!C&DV^|n&BUAV5l=LYfRA&872{4}OsOM&yFw9c>+d*c5>YpfzALDq zpfIA@l1_Zc7DnZiXR@&5O7z=@(|OBsAt2gY&hDE;0^%Bt-Hc7LkRfp9Tr=`e8&AiYAVh#pP5=Fz`bDToa=1&hKYPt0R z2>UJyr3_7_@@Ut3_%F#0BtJFJ_daYU1@E%_48w3tNIwHlDvOKx0HlP<1rM-wO=RdI z#=#zP(Fw{d21vMXCk262ieQ-YU0U^+8S6=zg=x70i60ab7x)tQ8|lC>`yRn_*w>Xn zzJIZ_GHlKjb>VyI1meg{D8ffG?v2oenB zJl~DI^(!ChA#U?`0~+{w=97kpeY-7i$JO@;=108#Y`P0Am3Q;aE!t*+FGfM|4i(U$0^i?8z!f{cPSq9HN2m-`6^5gL5K3L4?moX$ zT@Vcx5&aDW$3XZ102JW4#t?w;3xooYGcY>W92fKDmc$rdgjWQhwm*%%0oxBBVI%@K zZns%TGAIM&FZ=@@ATKy?6<$==Q~#rdWwm%}Uj3ZT(>6E#h8J}iE|@LIz{TsO0ABM1 z!&>!gRWJ4Cif+8mwLcGMW`|p(^n0Bq&^2+`^>p99!CTX#rlD-70%4y6-3gO1Y~$T| zY8c_S4pIBprJ2w_oZ^L5(A8H+H)HQcopi*aoSF`_IqZg1U!+-@$dBvn8w;$Y`U za*W8%tJ}vwoe|fU2YT*7FkpFyN!kAQ6-nU@?BK69F)mEZCRPbFzcWPIML=d zw4~3BFdQS#V;``2x^?j@k9Zb2Y#OHtprzlOs(cA{ zCl5q5+z7$~y#;xdgmm0GgQmSMrYt9dMFQs|jsS)%E=q1w_pO5kG*}rN?Tbv#;u%=U zvJgPI*Fy75m+!Ri0VUkewJT`*!&)ys87v&Jg%0n=H&6FOtks(+nlXUoBi{VWyuJiO zbchd>H?Ygi?h7x~M(#(6W?odI)(FiW1G!8z zveg4-Hd>cYmCg9w^F2-Z%Y6(0u+p3>6CkD>RT!5&!4oFn zpV|rrXyt&s66t=a4vb)APTWYMZ#17&rXg&}Br%rEF)mrC?S+tyLbVvk7nA1n!PnXb zCuDMr2gha55fxZ~TSy$jt}ZBR;xgmv075FmcyOyYL*1fQrqJozn7r1Qn6>i6322HD z9%*l*ta|ZKUwLqtEnX#l0s{c4jDw*MU3 z&;cCL?bF)pIh)hk@7&m^OzV-H=RLXZNb~9Ry}3T=)xHH70CGkGzA=pqd#Siy3T%jKUbvqTziulzsBV~<-xHkNJVaK2h4Mlq8nJohJxI{#W78tN-)(9L}I9~%L-{J=gR`?cP3>b z(T0fYY)sdmQ3Eo+LDeiZ*c=g+j!cf+r0W~?ZVoMRJbhv?HSz$CSS2pA3y~pcDCoOY zpcpqS+F7s&Bw&LLiz;vXNA!^=8*FhXaS3%m6VxBTE(gS2eTi=BpWbNWo!~3-EUA`9>~Ir& zML(@#H$3~zj-(iP7sK#Sk+=I00Abqzuyt(QHWXa;B1EaLoqXgSArK!(!OBB(#DE|I zmGKdv+|HnxkJpLqgVbRhRoFijN;cTo`B54YB>7~aaaHq?a-tfb?v6WOysYM-BFyK# zsW%z3hjWD4DUd)BJN92L@%AX-4Da;{W_{63gz5RjSqxP|qziwtZfjs-fY;WKv+fPT z`YbpyFpzvM-Rh4q0S`a6a~>%GlP((6*{Mg1f)EmyhxO1Zv$wgLe&p?a ztz=;LmPioas(py-1FLR^`6fg9Y%w2(OG*Xj#T21E`}tCbq(oYI?|a3$=x4X99`Nik z8SV{DXHDAfKz85bw#9%YhSPPY|ucOz7Jx9`b=abM3S1KXA8GUMgLO8%0-VJb+VKlI)GI zjpz>7dUz48&xU6tJ=+xjtU1vZjL)EU8wQSgt&NWH59!Zj^Hh`2@ds`EUwJ-^Z#Jr662rJaX~Fn%d9;;#{WTw z{wTA+f?lLX?1P<2&o2?HMBhq5MHR-FN<`#FGk-{80x!Eo|GqRw?Y*vERl+ZGQAYO5 z;|vJ%)UVX2`m0!Es-ERy()?3;9_NvIYha40;ltLM9n<()M22c*Z3#%_kE1}H!GIm# z)FM}h#k^;3RN&SA=pWCpjE=T?(P9Hcu}dBbU&6C{S6f`_FCB;j&<-Y}`a*5JYc@Wj zuUy%jus5>%vrPL9W74qvsV{fx)6O#{Gy}|-&MQxvlY%w10z{7U?p*al*?oAY0 zIUK0I`zb&y=KejC^BQxXm+)#hGV6cpq74kzvL4wPdy!dJ-;6%_e&eqeN5cX{Qb8r? zhXdv6EwlM}yWA+2;~cCX13kQp!KaNd5p>1Y43`&VJ9aXlFIOYO|>wF`Oo z-f!z&Z~uiEcU>Bx);7M4y?pjGK!{=ce2sDPEqdze#>>3P)i75Do~+KLgOIT7`zdB^ zExu8w!}pGt)>9LMgT2$GOw#>UYkqWEWcP!7j@ah3u)p7BQPao;wC&zbL z{xdiG#c+agsOfSIR9WQQt(fs6n!8u2k_L7&^FyCDgw&>t=}MCOliK%NGWuC#zKPF?<(>n35pP`A?ZddWiGyxkcXV z&0qE3V3RgP39;uM6`|>lOE2o!1$6k)RSsF1XiqnDoxaSx_omU>LJDWrlE5@?r|Y!E z1eW^sA!nhYy2O&RkwV3UyE`MKGZFu3jB(N7)YzgwHPKEKG|w+N_E6h?e-QNwvHy zK0uh&Wt2(TgPJY73f#d!qb{8aVBs1_oCH#3TjNL9U36-|tw5qGWFJ*D9WY*PS`mlO z_K0~n2csQHUh)F#j;U;H-AI?P(i?9+Y&nZC{&3yCX8rM6!HZj|!vm$Bc#(th_2B~N zQJnK$?vj^}Go7YBQns{In#Q0ZUoJPEd6$}2RFD;dA1ygbC}a23%o`0>#X&soJoK_y9&L`AN+|G8H3=cSA2 zy61nlGTyFPn4KZ)m~nr*OFHGy?G_Sdfv(`R35hFCt?q*O*cHeCAF8Ixvf0Okw33=x z(c?pc?eW>LI1@cLu1dxAVvMry;?IASKzERkA6M)-V1wIY-rC;7CCE8N@wJdiASrxp`aMNKQ8N*lS zCL<6D@#;_eInPgF`~!_T7zl*YK;Div5$6IdZ-u{C6&&F$FX)yrSXuplEQ1`4(` zX)T_=o*M5GY@*e%fskjXwxT)Q;bEn-n?SdJb~qK|A$gWs^q=)mx5!AV$NqPcq)qjn zbKb~ZH?0Vv;C_CNFZ|ahmi**wZhV0qwWi6{nT@_ob2Syc+h2Jydu!^SbJ4kZ5>w7O zjm<26dy~cga@0+Jq5-OE+2qWnWccPAJ+k4Yn)&%clQo1X!nLd;!>?Z0cW&)(xQsnr zZ^c{$oOsP^Ie4YjM8ZIuWYt`g^4!0>e1*XiB*Hc+H|QF&{1LWLW2;%3Q@3H)LmH?< zGv=Yuv}+zf$sqgfV4o!x9-jS}+9(O{d#0 zvWp%afwuJD4IIjzgull*z791hd#qkqyj;nDpMZfOZh~s`VLo*+=DfJL*TRbr^$f+X zlSL*(-=4j%Sa$hkQ-Y0gk8_TbRCWT^_$M2(CC$4h-SS;Qpx0vkmxPU$HPC=CiPUEK zhV+$p(~D34*ay`}e0aHHDK=;`w_+_~2&dOX*p@1mI(*`m^E|zVu0yLIg6KKR2~VKY zs#j`ANx!tH_SCtp7U9j|vHdm8Ec#o*Y@>5vzfEA>s-KDX4GD2B8Rqk1qP$-| z@mfBa9uK%UD0yK8^?;@#=OUbR&vKps+Edi^a^uX;k`s^@{7 zr%c_WA^=%_GF@rcg@_uIw|ql(8b7e+;17w|u>Rps%Oge9h_!0^z4&|(!SdO`bbt2J zZcy}6p$*SV_R741Qf1rSm=kA?tZnVNf(LPx6Bb#sII{_9&peOn8#QL3EoPx61m2!H z9?N&%K7T5g`LJuFPpZC z^v%iArz%YrLAl|rM5!4n#-N-5hRsPHfDn?-Bi=%w!m&ubguqzZX@nnE4kRvpRS zwGgPBXZ|>B#`n08djIB&idOwS@6)uKXLWH8x$^<6A>K8|e{|{rm*a*leOh*p#2;<_ zm8OAYAZ59r>S{oRzJ7;DM))3a~}uiR=e{M z{h9kpmbQ=)aw^ddbkb4~xKt_Q8Bg@H zk@aWa(8{He3W{>Y?$z9LdC^&N%JI^3`MduD?b4qIIu!7EYH#*&8&`0rLb1Pil71%= zR({}co^Gb*{H4H4F~?yK%2Ho>UJiaEwG~}L60J6MA8ZzlgL;X9Vv0%s19d=(zq5{K zk3-4HB%rk=EEq+$HL4VYU9-xm*tN*kHC<;pst81>JcHT!0;=ZSd5`%)n?&jo(Yy5+ zx~RF0w%aQH7@X6px=gYN3Bo4(02pBd(CRK_C(&f%cXEa_In*#M&;saHrJ6P6bV4PT zw(?5fAWLs&W_9>Bf+Oy=jc0+Q$kA4M_(t!YD>)L)?rG&N$W5Ih+H_G!e25`4w|ZS} z!%|yFTtWyr41?z2qwL7IpiXtt?Q5yYAz?;>{v({3EK#pN{+5d>#2Dh>s-j zc>Lvfo_yUTSi&YSSTSrYwNc{8ZaZCjd$lp}W_F5~XK>1rxw?<8OGYvt1Oit<#Zwdu zR0smS+j~{Wd%eqhj^&sQ;kygv`&0BgybA&*B!Vg6IX0xj8ZA+u^II(j>BH}$V3dO| zKqr;T2Alcd#6vtsMPXGm3h;nyt+V z_4B#oe4aY_uK3Kk@Y=8S{LsC~#85bBbkPu1~w07t0RU%h^nPbQ$> z)?4Z-(7;I@8%TO=WxGEJtV&gD&+vZeOu&R|q|RFYYIwh4>uMbjp0bwS^117lRI0gl<+4R}*H)ulsaC~ml&meR zW6h@RnoDa}Tv>175^D^>PyonD5}geFu}nd06q{y@I3J-PR;d z7c`;DST@szb7#+;Lv=>;`EzK{q)~?+-6zu|OOqa1dNkX$Y)Ft`%bv8G_v}ZwT~C7a zXt!_KuXhix6kIqYN|Ii$(jnv7F=fZFD`R$SJN9G9xGPhJ?D}=`*R7*ZuRgo@^WuSd zzrMnNJ$?7_=hwfVfBt{}{{ak8zyS#?(7*!`Oi;lE8Eo*seei=&pL_u5UV3|B#@~A51-Rc{iuo59V2YWcm|}eCMF#rt zxlcj|G0s@yjXCbv86!_T56}Mj=Jipp@!NQUwElu>!*2fK`uAjV$&?J zy7EdYvCfj}OS#B$8!ooMyy{K1&W?c`Y<_5>n;))eg2x~FCR}j7hZy`C!nF}xn;#PY z;c>zKAtzk&%Q25Uacr94`v-dHnFI7WNC$oN&`m!*b<;_2UG&!JDFyY=ODUao(Ltx9 zlv5JPL>1o?QRR2xRYB!<-;ozSdF6!961Z`}y04WE)Jl0R(((r{m+@TETK|>e*For>-;S6Oc#23zkiCp`WS=>~Wv_(-)W-I=i zSF(Z?u(VApb)(bT+(ai_;DQ(Nc*hyhh(>p$@f~YCqZ{9tMmVyujcSae9O?LuANT+U zK0pB<|L6lh`jG~L{9_;wiAX*!(vN+F0SbQ5$3sT)kb{)uBX@uWH1J@PXy^kEK>0~f za&nZL93?3~`AJWn5|o`JB@aZ|N>sM;3~{IjJmi5(cQz1-rC~Rs)*%IWgE**r6?y`=pqJYR00x~fCM8bK?ze;!V<1()v9ils#HBf zR;jAhBP?O8VWp}&yt-8*AOWgTUBWw}Q4D4j!x-_37s7-=*J9)~ug1{pUhDd>zy>z2 zd!=h(`^wjc9oDcj_yIh&zy&s}VGCbaLmak{SvG884Qu#9W--eJGO&RSpAEwnHf!0+ zR@SqbrR)~sP}98{F`QHUw9=!fk_a{@pO#;~KZP%5?)A zjN9Ab`t}XL1@0QGYlSEbARiX1=6AsxUh#(an)$(|Hnq5mWaM-zK3VU2cYzG}`s6Lh zK!#7AWMB181sChRZ+qVo-}d^%7kdlG2ahBUY#`L2HDjTI6)Gf&F7z7L_$WGx;Eo~$ zAqYkAa1hv`Qg;Ml#6-|=5ine04XYHz96s?nNE`$qj9A1P=J19)?9q6{pr>9OYFwgd zrnsnuDr<@ho80y$DIS?kY{^QM#@N)S0^ta3U2B!A%vK~EANli1vzb*jtGBRf zE}S~ItX?&$W6gzDr&`yzzV)efy9PF>0lQ9M=6I2vY-KN7W98KkHUppnbRuJn)wcE+ z(OGR@j1$}0PG>rIQPXdaQQX@Ww>X_-ZF8D1g$@oOL{aF_lDIqG3k@MQ5bW-EtOFe* z?l2L8unr+~R0!)Rf)EhSj)cn?;SJYl!xdiegC~5WB1JfkgV1kwl*1QFo+6*j^e3V2 zlq-MI=}>d()3lsP$zrie+N5j*Ft2sXMp%LoaQ^<(n}2nxU;XONuS!;%U$v@BxVe|V zdexuHysI}~LOfs~*LVqR>U$*yG3;trsb5_f!=UdhvX&M0WbZEQS(CQ2e5Wkl!P3eJSQ*4$$N1s{};fgC+`DFPhH4B_vBzO3$Za#h2GmG2;M&T zQCQHDmRJZx0QkV)vC)A)oE=0^I7iq2{{Ddv-2L$%IQ-qw@F1Aj9qXWB4CKbilx%FM z!YGbxEto8dwj!rIZY|aV!b}$Bo!R_cF?&2T} z=#H}lZ?ib-vxM!lS`7-JaMyOtv;MBMR_zO%@U*@l3@&R5lIysVE4g-Sy3DY;+JMx8 zE4i>s4KWY7eoGD05cGJ9@CeThR4?{muMhq352r~&>>=9ZM4Yaz+PqD@c;OHkQQgEX z85Z%{yiMH-Y@xCNCA2SvGLhcC{ttvQvEGh^qXe$uNRbp>EXEM7!~BimI1J!8EEQvn z9Y8GN5RM2o%oW#Y5r@pDx`@7{Xyw{MPmJO$$^tBgs!bL!iu#1Uc%iALs^^$4%w(?S zW=_mxZmq5n%(QW;#BAoIQL4mj%e0`4W`G##jOyep>#~mQ#%>+sg&oxq9^cU&=dlQj z0S4;94Y&ZfFzfC}>mP+J@(ypZ2=X5}Px2zK?+9|Y4AKoq%OU%&?@|p9@sPAC5)ToN z*n|!8hOHw{%_4{GB8P1aDiYY-fFy@a50A~+0I?-q@+CRuVrb6<847Blc;*rf%KH|I6TxqVT4II3K^8|0;h3QO z_RlMYpa|HZ2n>$H%reGGEZ|6tEQ(Re8_uMAn+U#wSbKclI!rIlh{OWILTAEMv^3h4N<|f^c*re*#J@r@6;BL zvedv0w*Cu#=yOv!wNssG_U@Ar1GGP{jX+8DR4I`h!hwSpv=dwPp(K<-8w?vRbjCPp z7Gcc8VC+^^s-zJx4%YA=xtZgT32 zplGQYljy#zs*sMYR4_`#HA#`K%BU0^pK(do$^xGhT{F0fh9#-u*QERiB5brk9VDrvS>vSVyEAAFn*akMUu1h1UtFx4|4M@@r*f1p>^(5C& zV*@p~NDcEKPh&4tQ8Us~FVzVKpkg}pWnmU3CFH!MZ9flj67lm8Ytq`{iJrzOpv28o z{;kaybmT}N)DyFBK{@dfH?hGcEQBmfqv{Xg`me)Mal~j57G+WX>XYU8U-)knX9lQ3avO1?7zFz%Dg$5FYhx2*I=mr%vqj^%=ah>fWvmB+Ct4OC#|P zVGq{t0&-3z&mm6|@Cc6y^K|hNwX-}HA&G4}Nme5j6(vb;IHyzCCN=SlH#>#GV#wIbrl5!`sK|?a z!fl@{Z|Tb`+7_qg_D!0~1lKC6E>IgkIO(V~>6#P>un{!jwQ#{~TszYUfZ(kh#&d~K z?Anp*_-Y<$xQ5&DONSv|KsR2Bfrim8?B?pRf(uYND-KR_3t~5Q{W0qZl<_(XW6e-ecNZY*G$ct6WKot-u}fnWRg6OtwTkW7p!bd8SlRYr5LIAjZSrPu z_KxqkCrOn+Yibb(6elb3-eNUEdu9_Iv=ccoYPS;N-WL{QEXK~S{L20>{}ir&vzA!j zSAGXh#sW^G?s6F2!cJ@|jCP7GdWyXYu#~?9PUZqG-Xs}o^vO23s;IPG!*NNwEa*Hl zGDn!poGt`USk0Og&H5Gz;=y64F6@BVOF!4@`1OYOHHW2nhwl+!nfN5_&L8I#PZ4j} z0hDMoc zZ^5;L#dUGp)#tb|s=UksFH_6{7X-D8%#yT9mF}&6K(2Clh?&`kbr|fZ8Hiu=9fNr6 zpgFAV%FeEN)qsmQyEAsXxlTC???8+6XqU87&0u|3Vb9Z1DfRSpOJjj8o*^%u?-003 zPq@7KPd7{QfcLWYP@paQvg?PAc{ZMcmU@dXXOT~#9hwn)68ZFoh2D*Q!7phw+7lzx zePxlvN|E7Qx@+~%Ed7mGHR=@K?|m&9fNixM=HZ-jp%x4fE6~KIyXb84R>|;IN8vVs z_tH#$>MC;7Nt%jp;gzkhYUUglNq-Kj8dqI$u1QBQ{;Hl4m$gypLQ|RNkq76I81zie zoZ;(eGd0<|tu0sUsG01Jp%;w7h+|D4CyxmM^}yL6oEh&Q`}(pBlJHWOA)^?u54N%I zaPl;AP!D^|Z{o3KzP zZ^IoMP&Y50P5n~M__#7}4d)pTf0wY^_@7sN)@l7g@+X^AfO-#l62r-!#%SBF4cI#y z+d5ml(kTYmt!D~ZRwq=o(|1BGOe@ci;FA3QsP+^~F+@wTx2b&L0Pa>v%td2B7lx5f ztm4OX+D+glF~_KG!U!pa3`~@9D$bo4o66@xaI7}dt+r8@J5zDl+{$P!N>BLT@!bgC z!M)otbi>*l)A3%_IyTo4ntzxb_3RzpPE7$7P7lw(-TAUWp6~n)wO}pq?i#x~-HPj! z)G&NJeV0&E^6?;&(&JRONUb1C59a>Im?5jHvTOb4fxbToTAK`U61BHfUwl6oQ5Wz@ z`Vu{GRewG2|rx> z_8GlQa(DRh;Zbu99jq-LOn0EcW(=Yr<n?L=#BsQ-?N|vG{=M1Nsh9ncJ}%0iH{v|w6P5l ztIyud7ouX7X%8&>vTvfiU;g`!R-vL@{jL_n4zAlvdi`E8>}jknY0TjIFaFz4eoagk z-EX5_6v|pIy#QjDEnBy8?Ygzg;4WOaa@oQq(BQ3y4i^^0rOTEsj1FxbymbrW#2E3C zEHPq4$q^+gkGNE_WC@ZbE0HKcas&wyAW4km1adN`N-Zu|7DZxYCeo!xmfS@0?ng0Z z&xBdEO6)4JV#b6OE2b4})~i^bJtLNNtT44#i=Fja)vB={R@Q8Bx3zt^i zxpUvjem#?3B#r_wr4;E!|e=t z{o>9mS+a$=cr}Dr{yX>e<-y}p|K0m`^T^7DyN@3~Hf{OCVe6j_Hvj$SpEdys7~p}~ z=J3>q-ggZg7GgpH0un|fIhE59 zJ|RJrmpSRA(@Qwvv;+`Kk;!IJZZ@S95Gp0rluJpxGs9F^S@l&_S$*}DS75ERCt1t{ z+SXOixCIyfS%uE<13YnT(S{p{3HBFmj~Ob=*Udfsm5i+%T{BOrm}jN@Q9=`eU-H}VolV7>zT z*Pk}+u#?1u?6kO!h3+JrqQVLjp>T*3#wbKPDzd}Gg(R9N1Q8epLBxeIx>$}c6%B+g zksTq#&_D?xl;q4*E_6^rSYk=#Km;vG(2yYILQ)bs(Ftc$PQ_$|Of~7GrcNv&Wdsl| z#Wem@OIj$A6ih0qbmmP<#FHm8V-YiqFw8JR)}L3gy|$x#dgWDDZPP6`S&PB|kEL$J zG3l#Y#8IkWml~Fu8+5qw1{|rX5yupHO~zTWkD2PKr;uf)X=H^VW>{yY1{T{IZM=aO zUVAmJ8enmJrk8A=0ahBOxanrkwYu-ld+)yg4m@%81fVT@xCHY{FzcDOU6kd1CndV< zZsh!S;&QhxFTQ9`j(*r=voF8i-xr`Z-Gn1=e*fw>@PPPbqs}T82%)N zU}f=rMyC!M^|B{*q`m#DzPH!VdbT|)^>auO9{u+34uP@560 z!VG5^u_|%#%Aux0mADOxQCbm3Rj8Piy}<)8c)8SJkoB0>5XMwbz)KuZ2f5KT#xJgW z)nzsp88~hM3!XF9X4-&9z{qMcouSQVHnY0Ug<%Swn#~kURhZay=61UYo+BR#$w*3) zch>REKJr04?(AY*!HAM4!v(JN{9-)Fz=e32x2|*jLVBWH&qBWQ3tyZsU+~k0fwHk6 z0EGj5{z=Dz=taI=`ZAaI37GhH3BPqj2!IOw5ITy04hz}O9SX$Q#h?kz{umLEMd%1Z ziyWrS1a6Fg?0CmJbc7`d4lNh8s0Bz4qKkG)DQ6#HXOt?E5NcQ{Nc{BRK?Z^lUKEXM zD*-~&aB_qqa1CoX@d-+jP!t;~bR|Vd2^D5SLoXflXkVI1OxPh6vt1=^!$1oX*G3h! zIinfTc!o2cF+{eR#Vjvv;-cn8H@29i7?JW@WwyYDUh$=KTUZQG2_u-G3QjLU{Z&!9 zz=b`sDm0-v++t$G8aTk=HgO16XQE0NsQ!gZbCygrG$n|Qv#l*(nLXV1uQUyTN2$;jIqSj8B}?x5QX83v?xk$ zjM^y->fuwuq~Uapd0noG>N>zh#tl!P1MU8%m)3|;GP`=CX3p9d*EFuIm0|-Siz*w) zxPgw4lU(CSbGk~!=5(R^%drrr20G|Qu6Ql7k&ldI=v4mlH~ZMf@QSw`bScl1x=*wZ+v4M>D$j_@#T$j%$Yyq zkn=a@QH^H|JJ>OgD@1__?4VfvV#EX{%p(f%kn}th_6|-* zVIGm@^u-uRgp#eOwIE6vFQBxGS!nPUwcteyT)<^r1gV0=rA7{F!DV+&P@mN3atnw{ zT!a`GN(u=HmIgwSE}_IHMW{y=u7GVOv}6fPAX9p)P=!ugAtp<>_7$vvZ6I9XBo5^+ zO5QXzB*Y`6Wcf-kWMGV7*zKiP0mi*$AOjk7W&Ul@AVx0$4sc@-0~(3iilPFnC}Z%= zE~Yz{;uMDkEYzh{cv(ZnGcJ#h)8UM8h{MOR;Nj1l4vr?y+~!utnI~+44j(twX*?4L zE6^MZAewFuB477(jppFyI7NsDe$nwiK}0Bq=AE z$$kCACmD1g0SJ&l34qZRgJKLaPy}>PPy4 zgdz-c0S|9*7jAG!@*sX0z=QtkiUSY@KkyFm5FtZgBBSRHp{9vf@F5381S#So9^x?$ z^bif<5!9dp2G9XHAejyj0s4eb?1Y#TfB?jIB()#`4xj=#-~#S6LPSC{A(0T+)m&Rr ze=A`GKQI6$a0Q*Fe)Z^4HsJ#SifvM0kU9ZwS1<+G#)?t!Ze!vTPqP$0R)5I$(whI4D)b7E?3>G06pZ z@daV9EKitm>W2kxH5h+01t{kR7%%`%um)B@lUU#h3s3<`I4XicEVN@8nF2;!#Fc;H z1O#BD{#c-XR{lI8f>YbkL+&x^v=3W3+QDNL4$FgoQ+QmwyVVfw~;ovMn1i zb_XDtZP)>bx-Dr25z9ag9q@HxxC>+F0A+SO9&i9=hY@VpEve)SZYB=;F%BhA06(xF zr5XUnFb?oDFX8YFawh`?Z~@;is+lMOQ9uLV;0+D3cmQHBG*UlIPy(X&4nbgx1MmaO z#34+O0mj*z=5%V7#ttxmizw0|xQUFb1|si}BSABJk$M2XwhNJJ04^|V29ZwGpsCvO zY`ky)6F_Et)dFq!Bs!z6&_@sjQ8W$Z64zG%QQ$&V@T^VXeo4Uu@gRQkfNj_&Lr$Uo z1WbT#C;$Lauw6*uCDlhz8M`%6aiY)A3ppAL!VnCK83R+HM0CS&T%iMa7z{I@m^wfV z(cq#7Py)Tsl2%kGI$I1dAP;Q77;Ufxa`3ELx&|0P09P<6Qbl4xXewsJbF@kaR9GsF z5l61#a$dR`bEJxs|D!+{;y)PjTR(CTEdT)! zKn)&Y3*Y$x4p9)fph3G(3zEv7&84{Fn0yc50>8F10s#>oK|(-6G$rvhEAb8$zyK~( zZZtpuDBylJu>@DJ01|)!l_$LNWdv8?1Hroh>&9IT#X|^HeMj(|Ge8W-APms(494Jq zBU=o;umTTYkuG&oYf}|05TdeX67UY~kZAy_dMUyV?J$u12mlL!oD?zyATdfQ@SC zP7tvWKf^&iauM1Ee<*PU3{U}AAVX1ri&UTmNKpmLQiQw6{s05Oen6lmrT2NvJfKHF z6f%*)2xSy2K{h-3k{f9^#Q?)1Y8GsRC@&e2F`#dXX#&Pz3^>|k#+H&ekCB5qIVqvyaYh*iT!1;5qZv$HM|5g@UQz{2V1zgD-t*9eSD*w3%>)yC0TJK?^=KwCwB8rW zLiY6oMgQoF))`@a0U5^yVI&z)IfJg^7i=(Lj)SB!9t8^Ugkwz^j3dWM z*@Ilr26mbkR31Q8IN6T$?<+%ZL9F+%Xn>!9BZ@MzZ?1q=|d z+-gAJlxhiNArX=?60t#s49-CEogToQ_=FK2aIU0zm_x?RDBT#@<69x#0HhI#aiCuahYQ@2hdXhw0u1BdbAguksD@82QnE4 z8BhRl9Hdn~8h5-%i-a3}e79iE^iA(O*70P`6D1Jv0MxJy?_mOIZXOP?9WtP}m1$VK z5Kk?z0x6IK;H`D0WIXH93*FOMt~(B-jxVkYx+h@h-$M>35CAU#12jMb0U!Z1@B^fH z+Tq|0HGsOd+aI^t+p5k4y&DA)!UQl7+!cZjrPWOCFzT>=F+!la7w``D!y%^?BNBo@ zHsT@W^gugP5YOlU%cZ{L{#!wl%reN1u0Wy-nhF9FqzhC}j?}eWBh(}Myub73H1Tlp z>!t-u(8oUT-d__BCMXYDPz3R?n?67jMKLx$P{8u{eqqujFL4CslqVq!7S#{|4`2*z zgTeuj0>;2_GRzDzyaEXDkqu5L`St=PAOksYhP?m~#hwWxC~ROsg9MKi`vEV`mNjnN z&||;=%fmQM2snwuW(ymTYTjVUFu)0&HEL9ALYW0D^cLbxN+LB zbt_%~Kmq{*02DZ(P1|m4*uE8qF)llA?AXBb#>S4F5FzK;F}ZM+T@WTG2>f^_B#3$; z?t&B%GA}`edDwAhy%GTUfr)pD2x7qj^Fxn8A_g??ofvMxWfxm;v89<Bv0g4i9jl zmfCFDMZ*?6aKMFIcG*Q27YvY~1zc(g#sLVZ!7P_sdc?5DTXM0b#av>DCy6DFFhYqX zuDF1JD~|qr=Y#@$sNzZ{sPfd^y|#ue*4`^F}v<@OtQ#oF~I>3a;QZHNLzq$gBiI*$Bg+^UUwk14ymYiF=Y<4H_-5t=A`lLSAHucwq)? znkeU+afZ+#f&{)9kGyoA4o91J^g|E5c4#1=ge%@*A^`@jXy=C}%wwVnuZ6h6gaJ-q zVnGBeVuFbw@^fbhchGxJ2qMf|a2WM*%Xs23{(=E~pfgS+mN3FjI+37L2_^D;=Z9yW5w#d&RzRSH{$ONa zID$lDh@lwxV@Tiu7Gy96QG=K2Ix4spH zC&YnWBk{oiZot4TNW==s%au`}MU^cCv4JZ2)mn5ChbX+oUsI%F6|HzhEM^fe_83^n zbRhu;bif0lQvqirZ~$F!rUhbrfB--s#@awYjH5vS)?-l)Fy$g zm4E>RfWh1tumJSL<0U0H0V)|Vgmw(*doOuM+Vm5IzTL+@K^Rcp+@Z?~!Olgt$N>lr zFaZxh-~f*Soda6XBMx-{0s)wS7(G*q4;UbfDtbT;D#sZYxkyNe!v&CvbR;^}2~F+E zfC*MO0WNTY1yqR%NC4|PjF}|}MX zfe!uT&6Mq6&jP%Kf_Jpz9T9-#+%B+6@0I{T>?lIsp7aA;4&gn*B*J|L)VHf0^Bv`g z!H``jy`Z1%pQOm)Tjk#9S{Hn9DuU5@cv8-R1iAUvVaVsAbv823_9=t14Q6c#4tujdl9J9Lin^E1qLvR@nq;qKn4ID;6ZX)5P|Hp7&EBH zP;H_?k}TlHPKfIi^cmGHJfT}9WMB%{picl0pa59i!9zX*5uE%g(Jj;p7j~i&7{+B7ET95b$QDuEu)$Ym)hjqr$wyYTl9c>PUI4&{VqN`eSjSq{cX6x=ZX+4g zv|wYX5!vW+k+EEiPS`Erg~)W#0vSjQkC?&5{x2j}GJ@fz9JLisI>htHNFIkbxz*Wj zvXKqsOgkLlKHAKX#>wh-@*3+1!qwIz1o^&WJxnkUdgfLi@pg>~^GFYRiV$xm-3&vc>DD0Vvd&ol|=g~S(RJb4+ zu1CC(or&*+Cp{VOOGBnY72mHtFd_5u;IY~yi=uQhr z5Mvl47*dDd0I4nvU^F@EO)dsbqfS1lPaRaHLbEVL#Z!f>xgKl?gG2%w)r*K^DsiAg z9L)8FT+v|)Y5`&1YY3|;eBsb7T;Wdski`~=*d!{jY6(K1DDOJL+qmcmRzw>JgBmu!{q+)(H~M zz=aL7IL|1#AZZZ`fsAyDKnw|u)-e$wX&qcJ5++$Fn8TBZf+#eJr#ykEGf@(yh5yTTBOM*O65+=zLb^!jLfyk(WP=*0&6j31tMqvg_2^3#2DPdp+jVcsqIEG9i zyHhy`GZTn{V1^lJ2&(9nkLZ=MN(q&qi7Du+p6Dv6GQ6AEf-s~jTR9d#TQspEHDzIy zH(&!8f+00PyCq3A0$m;!BSptV3lU*UoV!ihEjtYpa+7aG0PYeYwUL`P&Sx?nxY zNQM)c4B0ao4Adjga5g-eyWe<>3x|~%4&^|;>mUzS1P|qs zKIFp=T^x_^c$($IhHEencc`!VJCA-_Km9n5yy-vt5T#?X4|LF*1tF&TYd7*kj|kB} zVqypWdcYPzoY&C>*8Uk1|MD=@IS~wLI2Wln40#>IS;q`%CmuPu9Vr}JFp@mco|jva zI>{4;VuFV{0wBN>h`JsoffFH{6Eukv7#zszX+fiFs3p*XBX|cGC7z>_`n@X z9`32Z>nSni)Pf?@o+U_vm$Q@E!IOCS0jH}JVki}6aE3eqFfvYRG}NGr9Vu*wE{7f3q`p!kTV^h&o7OS3Fd6Ft#>skKkMql}?Fy>wA8x}(^V z43bIy#o;Ty>C?sLTfR?HOsHX*m7vPPH|rIU z7)mxgmN{gWqD-^|T^3`x31ty0Q_YD(e98z7(X~h+3T2>Ior$T6ij^3ORUtL61U*|# zwTN(n!9r1C9adr$41ig^E~-nte63~GL}qnXz5K-3pe=9XjUELg@AFYx4ANcHR-OK_ zwqUHcX%t4#{7k*Uzx(PNs}Uw?>^ES7($MU`ZS=PZ>8~=~%?`s?#32&PDV*Ho(s|?& zeic*QY@H0;QqPc`;N;UKp`8;f6NW;%d^E^At)7Nb5~PdRip9C#yg`fl0UiuOMHL1> z;Ycc!PmUbfVh}=+Ei*J5pZF}49c+j<5Q;ZD7M}Qt!&{+6(^;MkD;DZm1m()GD#}9K ziFT<H(I z+4zMM!3~s2%pesHZuM4e%~ovn#pb&P$9#}s?7wog#;eJ{`f?Csv=6KK%>K+wQes*V zgKIa0dk0@QCw`sBa_m=f{8A7DF?oE)4FpFZfkz*)kPvG*gS1oZkyCvL>#EY`!LvK_t|ZB~M5Up_M1 z*Wv}-ctz}pn(UZcA*EYh+}7$+u6j$4Y5XO=2~GWzQiL<5z%@p8%^P64#`E~U(3BAV zG7$?|Ck)o$k~3J=8OIP?CkcF=5$;mgRMQN`;5QvIg2XwOvy;usQGH$ol{{rx zQ10d4LsSbdl!~ZqqND_@?OlskecDw8to~%sc|l(|j$=q-mUBkqL@Z~dh0v}tRYsI!e9q^?lEk@KUmKmh-_yhv?PIeQTY}D` z3z3ZbE#&Xx#pTP^Ts-7%_1|wzWJs3Af@9afCE$cpk7Xp_`ue59wMM@&xRB0LU(i6$ z{ak_--8KEvHQh}g0XfTAoqZh=#9_7|(FM{CvL%sWm}4l0>c@!!&W+V!8;sZ?E0gQw zp6aPxM9nGjA>y1mS*kW-va{+Sj^-wYhdC6`#6!xWW!j(E!Yo!$a`p+Nd_#9p3wZA0 zkicH2O(9-Y#6xT#yH3@R@WQ^zS`yV~zz%FH+6VqRhOD}jUxJ<(O?=~hy(T=u8|PD<+Mf+t5dGe}PGiHf)ol4{ zrezCKd)1|tYrcb*WJ$a?7Hk7Qa4Mq2l9@|fqu*xDnD&kEJVpjzNX-1DXv*FVyQS#; zEsxQzWC_`12EGq;)jxF2WWG@kgd1FibN*ySCRYm4KyqBi)oGE?;M~J;MAK%8!;(6Dh5W9ooBF`}E{hq~btMDBj<9@xFu(w!(F`(b1rVwT+M_(bBT`_8f( zVrNz}C1!}VAqOlm2wjkYKat`c{o(xAII-3h8Yus!PurTwy}?WO=j#nV@XJ3U$bQ?sm74( z*_V{Y*w>JVQezh_NYSRTh9pUw`s(NR&wZZz-@VU0&pDs-zUT9L9qX9YiV!@oEs&WP zz`6N`j=tZDKPkDln~X`1I?DK}cBfn>(r(1T*~C?W=i^WFsxI#Z1=zIy7sY?Cyt#AU zs78F+aQ)aYvT*r?V7t<3)8pq-|8aM<_;tnY6f`=GX|D(L4`*k9xH+Xyca7M;iE_ZN zh_4xR`4BCS;eUsTTUr?$hJSHB)fI!gxteV6hS-dM-xN z+vOLsxJ_k&F#4S0TH+jVL08W3rmNd+prXhff;k=xZxAyKXS;>X@pJt@} z_t(rbmm_&TYCXEpv47#f+ja27@}~fNI7sR8ZO2Dfg=y3w^PKC+VefQ7c@9U1(s+)N zvkB4okxU^~-zN>xQe(N;<8-9_?vhd3pDhu`6BRXQ_&y!(;ZHQvN> zy(WCT?ZLc;?`RhM>@%#^6YMfi{w6qnngr+B!_gr*J);LHT=JR)X<{++ zRacMFG0b%F;$f7v!g?nq^U+R0VV3UuJ>P8A{h1>!4tg@hxr;0Js;?QYak*;Gdo34x zk;-a?JWaj6mw5W-Tv_ony&)LjmT*(X%`K2)K-wUtb=lQ$T-xpA=^lp2Yn6~6#aYxq z=1F(I)YkKL)TFpTo1nmlujhkol%hS)w3f@h<+IKf5{M<5yun_Y9c;2PPmb9ob>`Gyxh?-avn00f9t}h*K(*!yBnNG z+xypgu3Y*fL!i=x5POW|Cl8}>olnghS~|nRo$}6yhDST1MRG9*ZTFT7JllHLN`6gQ z$#<;Cs%Weg*=DKs>8fU{{HELF9On>xdF}7+_^hMZe--F~4c+1#ZEtvVO-Xzly!MoT zz(`b~zt)Xco@nQcm#*GvSA-1`7nkOIBMx4c`q6yc=C4Q9y*?QjX4H)dEckl2Q{}R^ z==Ja}NyOW5ljgw2=cNm;Ji_n4tb>MFJoq*g)nt7_T+KDIG_;w4|0y5adMQyn{=>`V zQK5)?e4Jt{zY(YDpW*iuZ~y$PfAnJXm&~3k91`n{t|@zW_FZ1YJZ|ytk@XK97i=&V zWbT_{y(@*z-o2~)H_Gt#Kb~Q#KPry6INSYLn`Nr50Pv#RV?qZ{s;@!+q}ypDxt)gf z%~At|`J%7LxP1}(*XFvz6U31;Vu_Cw^8WH*nOij-4#W6fuFVd-c`nBMtnV8WZFm0^ zzIgYEb3eYHOCg-d?M#96B{g;#<1bWlCUhsZFNxD2xkr zUctf5eSp0C;zz=Qhs2f~PyMFOWfzcc9|iNp>RCOxAC;V4`O8M(KWpEC2+bl%y|40= zlVv9!rq&P_S1nJ!@jdiuA7UlHX1SUc2<5Eg5;tV*vl@}U2RwfLqf;$8ssgtD&tl8e zr&|&eG_x!BhC7eH{^EE=e|84{^3Dv3qM54n^v|1*1WOSgcyqK1zN${XS+d@>rSqAr z)5uNRm>Adk%-kmCko*_g*by&xPtKeXtner&>1a6b`@>+!58mv#u~?Fd1mgk)he@w@ zWiDsFwgDY^=Kkk5uln4Nd*Wn`>oYg%(q>!>1X_pHRS-|Cg^y;_n9$p88QKw2wH}*Y(ybuUTCfNX7BfgSlO@@Ux*SNMC->7YBpqJ1@>f_{`8}CbaJ=Etw(d1BDUy z&Jr5JBn;~Zy*~1+N|32^R4xnp?$jK^?3@iB&G8`h6Xj>$hkyq6OzOgh&_LgZ_Yv{s zxP>pwgnrv|7RXqi5Ans>GS~0l&Wy^(Kiv=(?)`PU;#b%Q$We3Q?a=&+OHL{0+D+=S zmh2)4;*aL)* za^Q!m#?2#4%0|5W@wd)D302t@n?-VJ*6Tert^9T)$M$OKVd{4Cy~eFSN_xkZr2yG; zq$7blbm3w4)L}wi#rJvLe3CJpV;{>D><>OLbI^ZL7O#o)N2Nr@LgJWMExid+u5)R% zSe1%alcz+ebLr4*^Y-IL&!?d-&3!MAmw|65??7>YvVdtdOi%T(QyW5#`qPy{I<-%8Hlm0AOs(1L zJn&<02;ur*L`yPX%x2fS8_z?wEjtXJm8PaBF0wy*(hbOkscF21i}IJwNpn~3Btxv> z+w2bmANY8WvT!SS;orRGJShbghN}vP&;pa(7|bsK8%0Y&2l8CioPW2b^+@m8+1zh8 zf4=)@#GCl+@r`df@5FgrX`F_e1ABD`$8T=fU)!IpI@oJ8=-;F~>U-I95PP2ZpXZMq zjn|VAKX@++;eT)$quG4ddd7x6AIh}fZXCq-j$PbNyn12b&!vR^}#abzqeUjBs^p7ziKu@pQZM1I{izWFC~BP`S;(}bK`4@JI8)coHqJa@g?aaFNkT9 zehF1~^rEEKql8)B$-TSJ|LZY*^v87k()SOPiyi)#B}}N~W1FOFKOcSgZIfaf;!+qlUm+z5@Ux03`DP6<~D|KY`k*MFrbaJI!z$Zd48h zT&FyapTOWV#R<^7CJ&wB*Qpa6C&xQzK=%9By=?A5ocX$l$-5!IG+EFRBSuIDY2Q zT^~urlB5t5OJE*_Ey=A*5>mlE@G2CZB%>`Uh)d>kV+uqtdAyfo)0n)YCUR~|GNE|X zP7wi7#XoDZ*9tk%N0P|XOG-_r$w!j)r+k&0ZmDb^UWZV)qJ7Dt!&|jcUxOACqB=-? zctGP4Nj!;!G4<23uGYLn()O0pj#$}8q{!d_1c^=&s`L^1K_=5BO%$Xt>O+Tb zZep||f`yonYlOfi#BghqOI5^i76J+w6^$cDsn$&^uW!~I184%aB+>B|+ZlhmH!F6} zYJ}L*cAG2qKiJ4$U?NwodQ_DBfz7x7Ry-m*d4&-1)LHBpV}p1|N0ONNut3Z z6b?jf^QFkVq9l>FKbGWL7gU{-6`sWYayF>a{n3%0Ey=%3#TSWBqj^51Y))VBR6HEU~-ZC za*>GoXnauQc3?CjD7s)k_yGtN#Zl~EbZl_B^ue<6;BtISkYW7C6T>43gHlEXPMDk1 z2Bs!X+5s-2tCYcdN}W&A!}<&60ZB{s7w{&|O+Lb4h}BYxRm%$PfIs-wO@9;ikd4Ox zKUPw3ye5T0;#tG-di(Mqe0bHxc)f#DciH^r!MxUlR23i56~@fS5N~RgI#(?b8DRRX z$~u6Kr1s7NXAFYVnO(wh$y zO9F{FN@0Tiv^O`jel%8QE>|K#H4CI}ftz#!ml@uEVgSe>b1v3Z&g8M*u}!I3%40)t zO>OR#SSPqi)yTk0KRsflDtbt~Nm9f^`kHwSS%2jqi|*6-%15lO$+5}Dk?upx^RE!tTcaf1!+^!F_R{RzLMs?O2wR}&HD%laz#>FA1@7N<}ZakrFWYZ4M2YKB3$X*Rc; zKEHY67zk4A31~)-x2Ehe-lZ{g;CFKlzf*`Pk3|^#wQ!){& z!awSX4U49MD=V*pFTZM7af?`ums}yMn7>+=@UA_Y7T_)F>!uLmu{}`Gq*AE9v5~uq z?cCl}3BeLK-0K27$jsA-Kq^n2PaCt$d%{m4kSbfJAoOL&D6rNzgfIv?(>YZBa3gRN zf8Abn?0RGQ^}4->jp}ZJ1;_8{U&8ug0vW8-2R6k9+pCoo8YNjcc|I%!E9W>s?znc_wM0uVU6+wVWB2 z-7RUMzDFJ<5ZOK(YXkiX@{$U^Qk$!C{#^yWGLjK{SfeG8Z&f0HJ&Mwpvdma&oo1;@ zWU0Np%_B_|qsvMPlmV_w5mHy?@ss+rG@7{OP`@$SwxKk-5u6z*(;T_q*Ye-yMwPbK z0eEx2^Wck%#ofO~S`&jLuk5jLsPi13!Y1PSsWNCm!c8-fM(z zU;O)LEA64A<0*<_@!Q68!8tLXbKc2|imXyvHXICfVNr&vOl2eCD6SSWsbv)Ozu z{wTk%50Sie+1D!$yQh9u!TIQDWF7vQdb+YNfKgX*F zCWN(_2uy*VT)+LBEcFDhQ042#@U5OK=+P~Zn(W+qVjn~lYeiX}7`XENB&|um)35HJ zbLi3uI3ICfn_=cY*Xe<2C6$<{Wq*G8hCsTUqgvGJ=zFHwx|MEm&!i-j9QxTf@>}cL zCY(DyJ?ossy&7KKFwymIX_PR&#C2psgMfE@cFOuOzxDUe&U~0SbNr~L@ij?`N(ANL zm$QBVjI%dW^t=mMWg=;KfYoakPBKkwSJa!jF ze$~qG|Frs`sbIfhedo7TeV5hGHiaf%!_?DznQP_VUsNsyR;DNg2Zl?D`Jsp)3HI&Z zi35`bG0r;Q&s%7@$R#or6PY&E`$ln91tjqYBmt#%FX@c)xjeT<9qL)_#A5 z`)8|R0>Mt`lmFy5f6w?kCf$b5chaqsjXs^ND{3{lUFD)M#5os4NnAYcsnL6Ub?M-o zYFB*W$AHhdZJ#q^MV_mOUhVjFJzB&7Pw0{<*p<1{ujzAXqe9@Xl}&Pm)WE>y#sQ7G z7eI{fkLdWIFMHOiBNc1vZhu4F{$6*x9UfsAwB4nTCJEr~Ru64C4=Kr;e19ykS;*iN|N0reQlax?zKm-}K-EH_5`JC6kam>v9k0EGG%8k%&P%?yk7l*MYIyD{KUy_y4 zyu9c{zLV5MxcBN~o=%%nV3m5(J(}o+d4UUkK-hb%_J=phSD&>mxZ%6_+ul9AmlmP; z?ot00m77tq_sI%v!c7Wm+OeTO^~E|D#X5skvwg_7wJ}U%`QTXdTVGEwRl>)#`>&}L zS|2=U?!fuVlw2muv(EU5M)++<{b-~n|JBPa3esGciDs9MA+j$1ZH}@kvh4hWdw1}!{Rnpi z(x5r(?XP!Ws9gR;}%8Qz}auEYSV6+RR7vIDKn% zx?263fHKomFUJ2iRnzif=WjULz9MmN1@y8oXo_(mRY*cX(_z}-d^rD+P>opu1cKH z<;&U`9o^d>;y$CleSQmlCj7WiCgr#9>)lda>XI$&+wac6XJsZAM&F%}U7x+Rd=FGG ze2NcGF5r^n_v|*n-%q%I$Ide$a$zWibNb8$-AKu;Lv6=y8{Woetjy~8L5P!o{1(5@ z=mVa@RjX{#UWg|jyVB_Ur`J6R|FD;met+AT>$!aN@}>X&{Qmj#-%-}zEf6kK9;4oX zP~ai2Gvr$=EeD{rWn@H(P!W^CA>RTvfx^k@CaB{{!7wVZX}iqNewM4u&q(xksh_)b zM~!zTTz(`=H_>Snqa2ejlB>;pEbEy40N!})#=dDoZGn2G6(e;&~^n%8l=hT-o zx)($h74H-=eBlcGdrgYXQ?WKr+n!M-n|r3n&KZ(iVoSvSDZX&E{#_Tj=f~da*{Y2K z9I+Axzio?DW4F9GCF07`v$LNKa;0=mYJY0coFE=MqB%7r1vos{>tN@I`L}`Z&&YEO5ioaX59)l`x#l-$xwM zY@nr>a4Jd@1}|&a=Hb%o{9tCn#nF7y)NHlrrH$OL>E^lG+qL>WNduPVBB%damf?=C zwF#pwAHxriyUwH#>aIg&cokD7M64>iy40;J3o>^L9qXnBZF=8?TV^yjplm`Ks-7w2 zbgz(^lFi8th)<21v)n|MxPg*GJYv$O{myq$Cb9FkudTy@+zmAnp!G>Pc;zw*h@J^s=Wx89j# z!9mycq>fxLe*FvfboVUKNmAxN{BrfXQ+rNj zSp$#+=@@74MvTha#|}lzTE@;mkUjk*=!m6e#r)yyC*?u7mnYkTvr}?$qzlaesYfP4 z!lDaal+WOWxN{rr!uYCAJbWb_|F>54Gu6{?xSOZ%Ky8hfMK9t>n3p5}wonMrO!C;B>ana}JCZg?% zY}wtco@ZRMw_M+4HxY}6m3Ql6%<_&1(49xub`Z?_kL_Y&Q}kwK8zuq1w^83h|Iv!jdFDEG&rYY|Y}RHXBU8Nvs^WUlP3K!QcDA%!U3+{5!9|^6OPg zXalDav9WCOZ)!nhfo&z`Y>>mmYwDl86T#czox)`fgiLV}#R=88x?=|oZ> zMZjHUQcH#)>7LhjIML6RiEoA+I9+(N_!=hDosj!9E%(hwG{>8A`ld4SM!rd%da>?P zXj}AUsiz;LmtnGho4D3lIU*rLJkLT@wEKPwiUtHYy-sqf?#^%6bca8pM%7CvbWK~A zb===X^J7*onxC8$6A1Yp9Uophe||>L< z&uebHcngsD&RW zB`w1n6Us=j$|;!k@kTd^1A4L;lcnupq9v>9^}~nfDgf1u@?lh13yS>e?s+G~*OPRA z);}golu$R3Ua@&6EW6rC>j&&a=frvob22z!AWdg3&SC}M>V((*8M8`&UH$Y?xuC1z zfn0{4c|7M5Z#|cYtfx$zOV@;3=XdD=%N6_Yo?)IJJRTLGn-Vicsc_P`ZCO{%Lmn{a zW%-&E@kGZ|kxq7s+FcyVXTzK>`Rer|zd7sIssH@_kE7;zTh@=v#ErK47AY)`5MPvg zm#03dN5dCPw_oR6lwDDJzk)mk7SOK8qbAy>Y+^Qlx~p^7Cs$`YcB$fiGyAn+I8THU zednX^n)&mYrsXTS2k>vcv+v|A@BTjGpd=oA9n(bNi^#n7)pL1er`)LLL1wP!jR4pY z=!9D0Ojoa-W#qD$q+z|b;Xl3Tc)#Y4JT}@-_~a+FyC?Vi)4g6X-=As@u?rfudFA9?&!94W;J^hFLvHo-)i4pD7T;gd;+3A5?GN?H~q|) zEac&+82p?6)hu1`<>eBkz~s&s<6y0pu6ETV(l^8RuY`?PGaM75&l$+`Bqg@_QSASI zUZC9Vc`BZZJfC$iRLjC$J*Kn$ySM*allq;hMf#{#yIw?8_RhD{@}K?=mWzK>(64yD zxarPXI&${hck`lXIWsx)>4ciQ$ox~b9>Y!7w0%9-Im`dt$g&^>Wh&5J?aTYc^rHkG;4CY}+oJKGuG18Jvj6pa0*EgS}F3Fi?OJe9% z{gj%P2ERDnC5~%8{ky8Ae+ipB8>N<{vIFbenT_pOOWqiA;5lY{W@9;1{&ukK7~Pzn zB#Um6?aX7}8I`uPza7#=wVfq%=d!ubJaF4D+&T>vm0J^2WbTD3u334_ItV85@*WCo`+he1qKZGxs&iPJW1U6s^w}{cTdPDT7dIgh~t=HyM8sT_Qj6M@(>D zd{XmSGmDH#y)eU?pH;iqH&GLR)l7R(xUcoH+s6c#!NKix{g{lM6*(zchuyYTX(b2V zea3>y^FZS&-k4EKp>eq==7JGOaxq7ai_p>TKVG>a@QlVC{ydCr440Nxxsi>Wi?Ti7 zU$LDU#2GdqSnbHCOA~z|icjRZ4ryEp+gC6Uhc_^Zc^|GcoclTcW&E>AS|`yu%yBqd z^<8)sF<%q5nW;a-T^XY>jLXoK%0PVN)^$?wd-mKhh5uAamP+g2cRmsdV;|{5?z1zl zzRPR+n;&yi&bDQp?Fu{Vzbuh7AdG|gH<{+Z@?fR+Eu z=Rji;nw*TzcEsOKr6u_qSPh^pebBizyksAAp9Y!?LT7KttsNoA1|#wq2qhbME)8Mi ztaX|K&7nPhpr&c^LTpH$w14)ySEOQ5+Lg^gVtjhULX|j^A-)4eO=m2ZQL#)ab}bn` zF?uLSfKT{DVB3i4&q*(Rx?xw5vE1D44D<@kIZ%^l1u&1?GxOo$USpemG&WZ>$@m+t zrJkZxJK38`gD)&1))pnwSQ0MNI`fMX1vo5|Vf}FtQAX3NOo6xIumyV(u{`&UC;q0h zCCoSRN`r%p7rKk}(lx8XjBk1a3cKVj-LruHqh{flgDAY$5r3BbD=6b(ys`%OOUE;I z;Fl1wTDB4^8qtP>99ot!EY3DYlD;Js`;rrL*k;NACjl3l*iNd(6k#@aM(s$6@}Q6s ztLCX6%>t&+28rXqZpIGR1_o0Xg(=2hEbD}UF^tVAn(OSw%LYlagx$bHNh^4=FFqJ7 z#Y-_T@qq|Y0R;vpS&}Z>z^Oz7WaBtf<(M z1TB^8FqJku){zE6P(cLOJ8ewFCAQ~nW42qQve$F&qgNcDwQv=hvlIZ^g7SWocd}*x zPzIpg4FJ=qw;&jT23*1s4y0C}psH1Nh-#^XD3uX&sW{3_YLDoq`ie2dEFO4R3|e8V zD$$((2}1leUDP4ye`&5ttp{Z^mwzugWv}XlnuI*k3W8HXX#q1>?I000w2YyR{@j-) z1%DHKKXU+6@X{FLLNTgYRrr=XH(Z z)R~i=f-{3iY!*U+2B-rN%+Dyj@p-5wr7n3Sfy&+$ zN*zx=Kq~=&HiHvG13GcMzi>f6aK|oCDS8Y}1uCG;Htd}PC(xg(QzNdz z094q}eL>j5fcP#wB8?5@VnOYVQythp}!aI@~N4xBqP9Ln>!H0J%X+=fFYQjd>~$Eq%0fMaJR4S*7GgH(~yETM8vCOQ;<3 zJ<344I_~3^Ty1P90+(tw&v~vI-r|~S^&Ltb(al@#eb{h-XXd#akYUm+kp7_$0RXwN zq=Mxzm+nGig+c3ky6}_d@)vzeoXs}nENxT0nE6qPuL~rt3Z`<6(^?TsM)dD*r#<;i zTUeYh0Md@r>__vAc7TP9wOXm-&XHt>9lUG;%Dr^5MB_4@#K8l&-+FQ4pS?bXt#|7M z6wH7!?;HYTI5NvsPaucyMFhk{J%XOJ8CMCwXprnF0SpV=r4@uCpp~egzocVUi>Gt) zI1LvA$W`cu9$CP~NJCxW)k;VMt5D5Y>oygH$Emy`9x?AMQo~`FK%~QRI@cOuPX*Zm z08%@ZfA%ptTmif<%Y6k-r2^J8tI1>#o(4Y{d_um;fWmNyLrIq7z9TF^d}6+;8sPo3 z}$Hw-oFwp7%&`#a=jbNn5 zH(iUL@wy^$*lcG{Gbv|R-z{?Y3c#wcY96_8rO{4KU^x2rQsFpkDlYf@vnfXlYn?Ot zsi_=ECprBY94H+4VU`ywlw(&DW6J`pS-y0ia!){iV_F*j<#{2Lcd8V1#8ks<(Mrk~Ma8Jwi*HCF!Zd$@j+)DW_)Lsr8Q>Sk zu9-}Rr_QLPu{jX{2k{4|zvUBlh67fH7@=QZyUx7=(2iAUtN;)$Y`2i`hwi) zZW=389wHU!1h`f5R~kfJA5zh(In&G%_(MaiJryX>WG;|G?DP>#oK@`}f}o3~2VfP1 zIR+1Ana0+AbcT4^z#uH6gO8MpK1w(;fNmk3`NIYO9LV$s_&VF9 z+!!o`L(Kck*aLt)6+XdV6I1Q}L=%s2IP8Fm7-;%p2Y@JSkG{{vbt%09{ld>6ZxVXk zQd~X21#bdsT8)_M8lEpSPJjC><@93vaQq)W6$ydwei2P>qXO#M5N+3&CIU?$2H26E za;p3W6j|&dXo_RL^&iGGfk0TC`*HGXJ0Rbt<=~}dOPnVIX2Swd0GOT-;m4Q{$^6uE zQ%32zWL6*=!vI@W@pj!2;G$MMeQ!B>9srE}@30MTM#&ow2*6li^Q!mp_+WlZ?woKE zWFKL)e_@7*fB`sr%SJK>yjT$mLyohh25ACrc`nfumc;`BDAR=$v%YVZ^KsvhuPGJYo9eiHUBPe2Zdx$QF&h|8<}T&f!rk3<0s();$)4-hbc zF-4!-{!0&h$TeJi_|Ho+)Tje9F24BV=o|Ochi@84eo3mNMf)^ND%Ms%$Wlr^q?m1E zH7?oyiRO>b{UE3a+j3X+8^9U^bzAO4Auen2Z|`l&)R)E>9ECK-m3FEO3U|(Na42PS zv_#SG)dRhD@3G24oo@W01Zrn_@|MG+hyVTg_3hJ#=Z_x!`v<@XY#LN37(dYwA*+g3+%>n1_4DUlQ|Gz2GvK@CHN~t z5JmZlON9(*q!0)9X2ggCRw!H53G~n)NW#S#OYDbl*dSoBRAi9^7mbGWx}Ilz2pn4W zQuT+u=GI{4%^hT^YUb@)VK35l;e@I~F%^L^_4+YbEU(}y_Iwh*H9_1xkAw3F0Whn) zn4}&=K%%Cs2#Mnx4cJ@jRb$u-)Wk-HQ0P}al&gD(F~?U&5R_jekZ5KYfL+;LY>MxyaP+VmOsL*>+D-hgFFO(gO(D69*DA39 zq0@QMZsHEQi>5H7u9G`8wZHbOXBx*34sl~NpP0aw>4gCUGFSdEua4THJ)ep6B9DMM z@xVs|(Ka$bjDqKinjdbr8&*m+AKi@*zCHVWCv=RUUnTuA!)`R51P$Aq4w9{}o# zV2D>)T4RwN$u|w-4uYaw)(`8k-5OA;;8}@F$!WSCJ{(i&Hcr2D4JnJb9G78@6xDz< z2`}h?G2{>8@nanF{KJ}rn{Y17d2Bq4%V7n=+oGKPC7A!?-ud-uM+D)#%dMcBLaDwN z<)C|vV@EHpsAX~>%lHw58iFC>XcAXwCI@84cmsP8Km^xa4^5P>3ktUHwX{BH07LL7 zB^f121Tdd%*+uOIjhk>=+#|z;*wAxqCB%vJt8lI;ju#@_@W-MV{6#Y4o0eu0w&{S= z1GALyWNwL1RL=V?9J%KYOVV$@M&UxJE9W0bK{(E3-ggHN#dSfw%{3?V=|E~5&FplH zZn5|~{xl^N011>#8QA3zl0yPnr>EU9+jI`366>^x0FsLIYge8DaamrtiYUiH6COyJ z$ekOTd^eCgCjK<{L>cNH`3?X^8H0%WCsDa>6=QqT!MFIzBj{b?4e+2dW58&EH7c9R z1&JSvHaiF$jkIZ@T$wmQv{KP z5F0=NNmNPcyiEjzaL5ljEQawl;1lU&vMnK}T7b`|_s{NOHtjVO8pdN17j6oPcMY>N>!R*EfgX>gPRg5gp*#Y{%3N0CAEU6Sr%^Iue zC8|9z>r95H2)E~50jSe{5@FS&y4;<3u4J_&rKh}(e@yD{Dc$Sj8=Nl5+nB4#z80T7 z#(_TAfs~(=g~w%o4k!|WzBlyKdzw$;YMlrw?&kTRRScSG^! zRS}FH!K%%YtSs&f@g3_P*{ANi#-dsZJ5&X8)h3*))2`xb%t$L zfXI6;3w@9Gx~kF~bEh&2zL**p`sbx2ZEL{Ph-$W07$jKk3nsj7SX|z|y?W z&YCO`zB4g|GH=ETI)DJsAZy>CC!ft_*ssW6L=dkK$W>0Tyuoqt@y_2$#qyi~!Jkyl zd=R-uUE|A4MR>nMP6(Rk5i}R2Pv{N+wvLBfVYi>gL4%C**?ug?KeIkgvW!dp6(jkXO zpwmXim^LK5vnr^jBmnWtgFM0zIraP(;a7i?y=Qk%KAs@)Pzh%8YX$DtLX=Kp6`y#H zVm$EoAn)-eJAq{=juUQ+5_ab@yU*0!Ie!D^84DG)+Tk&91_X_jvrVBT)0Vlj7&Awn zX-6a?L877tqK<-m){G@_%Bbf#mg8*p)AjF=<^2&(?C3n5F1Cm?gA2qMH=K! zyqTcHr0`oapcayXh1$He(I71ra9Rs$i#uWXmFJKHDdPyvu5+^*h8hk)Gk+dwuHrFR zR57a&Y|w_bz%V`_q7Xw;2PJP0oHXUSw)id`uks z0Z7CW;ruQ<4TBJ46<<2=@n`Jh@(Uu4O##%$z(S!MP7AnL2PBR{O7U_vzbLg0oK-uA z_>_d^m~4I*%RmucXmaXc0nFx#V&Hj>`@a%En!>g?r6F<O$eXiTtZA!JHa+Ntl^5PS{0{QZY;61+v1QOPim=Rz zWO}TQ+%ak`rkde)%PGH=I1G)LBEqaNAFgubeHRS+dNC?l_>V5;=J$&;^`znPj(lr)Je0cSZt)-uwBZ=w4gpe z1o@gn=7Iv`2In{RBU1); zVm4al*vYewjx(|)%;V*hW6Y_5+VKF!6lap7d}K_*DOtJm0hd zirak^OmH(pj^FcMg#|;uN~f8_DSJ}g^)e^4pSvn7RyY#pp(>^R zGql>Y-Lg?ey?feXmPtdD6-bAQkQ^UqHK~7Z(lmAC;S;l7o$k61>CC)NXHlaDcDnAG zN{2&^ggeVlI+tH0V5|1%N@92RJRkiqzzHQ>;pxzgLY4?5P^ygAZ2Q3aQR+6u2a`rZdP5gkrSLGWJ{8AkULo(5UOM3}92IQ(91!*5t z^X~B+o8T>(rH&bX>tb3vx?h_Q+B~ z+FG*|NV1viBBl2H^4sAtf=R88>XB0;4KNemm;CVe{3oY*HrPBnzPaY6EsAQ>zj}Gz z^(EajtKv9IWRKnAf77>CA07gI|G3Wl{v^zfsyVcZ(fQA_Yw@;1bvyf**W_e7;bisp z)&9P(I zDVhG_N)%PUM?ARuhQ9ccq!FQROxOOb72Zzc119^4(%Qhr^qd1&I{XDaXmCzEd;SvF zL|~_*hSKXK>M^2MML|wN;vY)4QF?t^dox;=5;XtBOLj(MC?Tjx;d?;*{b#hn zxXZiUUT(+VXAkPO$k$#^$c=#|O%8ptRT}9$Xuf`@S&Mux_VIH$Nqfg)lDPKzhc zl9rsG_WOh9cf&T#FYj&3*#6fP|2{)J8HRJYjwnCP~$EN(sDNPy=mc8o!N6~#pv-$pg0MC$EK@fx*v162& zMOBm7JN7D#n62$=SKCC4P!zR`#;Bqws;a6QTNOo7RBdXP4%OxNc>cLh{>eE>&dGhQ z>$*Sh*SqarX;1Xa%a!eyec62)TE*L%GZE_Ztxz&@g~8n?F;0?)w5taMcgj#JyWLPA8ki)ov`1`|ku#?IPI}ROc1U zTuVok{9(H{2$AwKgc~AA-Dw&}SGMAk#>|K#81U`R_k;hP-c-}l2(W6?{eUxv9% z-2LCMt;Oqw{{d{IErlrdP_uH0hxA%loI1mTCn16(9@)*&SuSDAv8TkrZ zvh8Yot!(iabnVdHv{_T}K~pBsd}epcE?xW<52|C{diOvt`quDMyPC;L(|byWafs8c zM-NSLtp5<#*?1b=U)Yu>NGbB2cOR6HQ^Z*TephZo zb>x6PyY{ZsIwjjZE=u?UHnCljM>r-_f^nNyHphS^eDh6#nqNUx?Dyq88oQ~j!O%-T zw4~8@B=@XAzQF5frs{AB!=fIu3dE-EtclOavT@0i`pqYNz{71Y1`A}CYQloK3@|u| zfOiv)Su7EQXO*pL!m|r5Ff-zrXsc|fD!>F?9)@QTr?SX%8zdnm&>YF978cY#q+dF> z5&vU=N=A$?+DJDQZ^nu&vL7Cj%(In{laVkbCF@DP=jD;fC*vr&1iiV+M-LJ@cH|#s zRhZqa$cmG{Tan50&AculPJTpLKbEA_0^@mH-`dsk?Xk`esXOm1#|9q=W2duKcjj z&?I9sOIM2Z4_>Sm^Y%DiiF|dS6P<=S`zExTkC0z%zXo^Sxt?}c@VinPm+rB|Ji6j* z)4xo~Vpp?TUE=SjpYi{_GrZs)`N8M8d-S;xI3s2s$Vip5_pU*m3LJg9U>MJ>gDw}g z?rUB~1k|exiuC3=R$PA=Ia8gpNVPWk8($JG@vZttaMzI@e=^i|!Jb#4ZUmO*{lMPi zy{z)+6ganLKH?j%?IZxif*);p{JD9!LO~J#&dj9#=?To7t@1S+yK*$sx5pw8Cvkz- z8S-n7TOy=N<97Pc-#VHalgka%(`zi9@)k(#_K z{>1BB)hAjdafk!68147yRn*6j!Am~@+ZjD+H@k(95P$RCfIv{BOrVK4*J1am5q~dRhC|*I>?3MK4w%m#<&ZJ@hpdzsK`lfZohLXG{<| zTZlL|frBTEC)hqlT+GZ8T%{FR!<4G>fy94Zoag$3)_0 zcYZ068O{^^xKD*Mb)ascIgOA>!uGi;3A$Sv_%)=uSlmHp=ih8~*7s`ne0s`C3k zu20V48>ZkB!L+hAWDev^(EEVz=cjGSq z9&3?cHOcN>tK$U46XU!TQ@q_%Ov>t(a$avSt{&pCFSy^#QIX2sgVfvPZDcIR8UK zrl~>WNm?H4OY*seg{G2PQ%laH&Dw}t&&-gsHsY^Y4oc-z9s{xayHSF zCKeD;@mWynp}G(a<;T=?Q^Onj0G!&UDpz*uYom}OX18^wm{s~vtna--C#!@?JXL(i zdP`Q#PQk`V=8?g4EvZ6&*jMnav#$@EYoWPQE~2T8S%0 zKza`nbnoa+RjX+myAo72N!#M8ft@ukj`4`B-+NYJC2~izO>cAjlXv6({kp5?{nJggU~a^3CMEPN)S&rv$na-}QbaBBlW_NoQAJf+ zg!{S##nRJQvuHgwRcIoZ!gU8_t{iYK&ehQFj%2@c-Eh-adll_|baS9|^#`ZzGq~PL z`v!*gcYX2+l1*HfO6Qjd6o96k8nT+Rn2!mk*Yx-n+CCqc*Oc2rzxn=9Io79VUR|+&Pt1(r)0 zx(vnWU!y%~0v$S9h0!nAotXN+J!iYV72*=`K5mh}b=-l~n0V)X3MLVy{%wY`vOKN) zFmj+(a+h)qk^EsI@xoTjX~%3hz)0}^m02M?y&y&7;mo04> zI9>K&2>p2Ocq#DUaJlOH-AEIS>-Q7o6wTgX&d_9?ag}-hHj$R*knnnlF2_8Pfh-ok z_AR43meb266UClS;y$BG=J?#hggK=^yW@EqnC{PX*(kbj|1KxJn5zJpIvLv#N5xt8 z&@#M4CW>eo42cX%_wf6MN!}iDDLhzEO$U^9`wnO=PHmGlTcDdeKL@nCBM>jgqD7^i zy+~Ckym9nYkWTweP8Cr{7iOgv4$(5nsrjfJj9HF)Nve7-YbqmEpT*dU|+51 zZ(R}L@PTtB`!gD*$pi(qEe7Kg+$um|onpiFqURVy)1;uopDcAP(5smA*W+}*>nSzm zLL9#}g5s*VhF{w*^u4ADagdl>*fX52w7mo534rokax+{aIL;OKPuCdQvgW1AuzvZ-#gHPc$%1aQI|;e%MH zdY?q7sY&okzQ&cIhD(`?^kd^a>tJgCrievE^1Pyax0l@CGl zNRHRq8T{08_VdKcqXq~sA%!**uogB!L+ig4fwHo8n3y1RqFkO2Equ}#Cz;7LDaa?TlH#P zLv}15O&9W5S3}N)mqmK0V>m_#enTjzN5-bgI{Kuk5v*vgonGHuTosX5A20is4Q%_Y zepo(Z6fC2}^&!8z@fGYul7KAY!0 zW9e>-h9EIe|Ip-RX($QsVEJb9vf<*ogU6b~qNmp4hL49I3hIYU_H|wqL_^fJ67~(j zYFO%*eULiK)uRoM1H-e2UQ1sfOZyyGziTWViY$Hkk#OK}RT&LdMN^fqF7NZ^@;9#L z>@WQ^Yk(NP|K%lYP;r$^Nut!R6%Oc49CZ3Oz^`q%Q{{ zp=UIX=gG1^idj@J8QMlX8yolaf6J-_WiA7X9agIxCJ4)bRkc1kMSgT~H$&;UiEDlo zOLlv{vGQ(tMNG9t(gY-VV^unIRknIn+JsZmBtf!iRn{s~3X>ptpM)+WZAPR>$E-f8 zBqx;}rB zfzi5=rnj-)y0M41sjs&_G7(>+Y4`3W&SQttb zSzJ*&1c~Z_F*o$tj(3Pq2}CESoWCbbBAjg2V2U{W0LncH3wE@MZHR@ zSEaH@vSZuo9w50flAPvRsjrv39tfk{)>;$)ZUn2h%?b4s*R+m9GU1!nTlE5-dF(!uVZxIGo@p|5GzPSZCO*&HeKi*F zOeXQE5|iyAg@l6IZ$d*@Jc5zQ15tsyK6^W7@44hND6`>PxWOF^9SPoZ@C|hE-Rlj8 zhM<$h=v1|s&8f{zztfFxpFIAa2Z#6u&E4`1Iof+)p+<4-HFF&TxlS-& z5*KHW%=};M(K3Qq|ID_3*K8$`fpGw^3X+;D1I~bwvIe&9aUT8+zLw>9O>}YP9djVO7z$O?194sev46Oxe7x;->AG^;A?MFkzUQHB zL#xq+DJgWXBme7Sa+cp1J6VjKN7Z2=RhH?!Yd79LZF`4ACU}!KS za7=V#R4-6F<-eWMz)Md8$yR$FM*9n=J~IRR-lE`-{1FSHU{BwmVE#?R!64Pp2)ux= zx|ZLrOz>yTV2dvYdq(T4eZjjk!Jn0at(|r)-W?nqL|j4z`oqyb0S}HPjDKZD?lw;z znJIrgl@IwtOU*bR^1JcJpGE(d-B+Jo+J;=+zGHRvQyt#X1LrDHGrN}VMuqweZh=3C zVCYo2_HA~qqmVC$AzVkH|BEU)I1GJ9LI_059*6QMgZ}$6UR@S;wLL8E=T3Fk(VeWH zYxmJN-~IeDdqg{d=-*!LGaB}ZMnZ>g^q;txb z@3%rue>6sZ@8W6}lg~Ao{hdtFrX8x$sDB(*{hW^PI9^jeQ(HH;o*9M)yxwB^@+J4! zzx&IVuDjF?m>0q+I_zqE*w4`OO3{M_@f?29ngi^dOWYV;E+X>e)@Avmj<9=85_P9P z>0gtswzEtL+--Cm1Q097^-pHMtX)>xeV%;ss_iSIZT<4>*Qd93UmOIqb?u&C3NRno z{djv9bNg%eG0-_G(2;XvC~A*j^vkAtaR>5iCn$D*FmNaDTkh*yS;`xe`PBO#eoc2> zEw%PF`}_+pKviS;jkAt;@cimNU+^<%Wc}sf{p5fK<{x+{iyoDYL&`Z6^#ISt%xN~8 zC4TxKvBIPrE|Xr=pU!`Sb&bX?Iha18l{_+ZREY68cb;@*?(xP@#$ftCI&(FwP>nd0 zbp+b<6I9l_oijK0-rPpjFK3l$&F9*Ls_y;MD;>Q4?;a4hsG4YK&q6Wx+CauE=C~oHEEe?j^AcA?y10=bDa*!4kX_Rsng~~QE>A+b#&}W% z!)KSN$h2-x0e|w>EF9bUzHvNfgEI{a6Jhq!S5Gj8XUer`jT@kmk|QcoD%45ibFmQ< zL<#XuT#dqi`n#DDF={wi($FSjyc;&EefqpayqDE! zLF~PY(?ax|AfAn5eNJ}y)=q=Kax3WgQCa-I34tZbSYg3ZEGSOleB5C+xL4Q@GqjQ- zls3DPv>&DQr4SwkT%mf!I429blPe@*;G;Da`k;QaR|c0zx|cqLH{A=*X47hG%ny8T zV=iPWCv7Gj#Poi^{*2Nb&}XA2SYGOPnR382#QIv3_PncYF2okuJLv8s9u)_B^ba7e z?>jKL#=h~1px=~v_1)d_oTtD8Qz@Ioi(f|Qa}SHJ4-0x1Nk<`lO2dEq`;+ zHipFkq9R_xJZl ziF79Ih=m@o?7|=1#mRPw9<{|;NpmyJYc^RbN%oT_=yG*w)0z8KHd*6pb|ZNgIFjDy z8{&K%3JoYOeD}{U*;kK*>m=n`>x%z?l$y2o3b+Jz=LwvVJgs^Z!}I^WVJ|DLcuO-KK8R|&gx^sFNSh4WAhOhB&#ADql z`SJKBpN_c<6aAx{(mk})li0{+m_K8@P*e)a%lAb**g~`iM(Ruwz8ez}A<1B}rKO5U zddbHwnwzw|%1)}6{=mE5pO{#M_E|?R-|uyBgo@wiHk3UGa4Bd^cv`=g?qj>n^R|l# zNe?F~5tll#@xlk+{go0x%l09^66 zuNm=CeOfdoymHNX=&_K@+mwq;T#+?zM1)uOlg0$|BS^@Sb=sid`Yiu?kArAr8FRSB zl}EP~e?AD(7z>|ueZ;$6Df*SJ5Y-$oe)-c6ag~zH^wai_<1h8LmDCD>91l=sq8rF& z+BB_#@y*>Zo4GS%%;c_$Ew|yVT$O_KTtTD_tGL23&s+7DSX-g(?`@w=B5c0muoF^6 zdfN{lHSNi8hQGJ1$IF!aOUtg`dtlWCNCcJHQf{xlzmkTnc?g6nH7L5;-6KA8wZ#

IXSK>Dm^#ZfjhkY~UE3kW|_w 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 yXeSS8xm?;ntYljn>8wX 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

!h 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

nQ^b_^!kd`X5;oNKIz)bDNmD@5 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

O`4#=0RZUB_~7mz?W@`C z#UG>~LNP?bk9>WO;cy&~!z~G%pbaiSZr)R%DN`Bd}uN$=wz|(XO zE9J;6wdlgJfKP0hh*idK00G>-j)hn~cLC+7_8VP&(c4elNeAk#Rgy{-JR0AZa8Qyi z4kUp|GS>a2Mz&w9X==#Hi_m5%O0=rG91~8D_d>eQLf}l;c-WLXL*0D8HBb?DT?_}t z0}S;rAPO|Pp9gbf1AhsCxouR_$qL)@^TstjGKi;+dd(wPDsbaUrVNs9OYW6^?Z@a7 z4xvcMItx%tI{wyl8IqC14eC5l=CCiJr`RPeRMw`CAo{X#GL1n^UTtF7H*{VcpPc2K zU(5bGYoWeZ6WNC1Y}6VPel)zF6GV9b#c-d#?B4HhkM#acZIHNIrN3*MlfaJm`5jEKq)zYGXgwzqe!8p+WBkEqg-CQ>V|) zoQ;}Tx?q-=e;(pqe^XeGN212^Lb3s#eY<`tAJ?SsbWQkVd$x%Go-2BD)`^6lM>lTSF#WTe}WUHUl=x}{6n+%_GSR6Uz zR_mzYN_i4^B-?O#qxjL^M*s;b`f*Jb5*14s&|Win?FlECNoOrEc`XBYEj?KPUC^sK zVx12m%IVSu5_{_2(F!opk~0Wa=|nnvT?;!cdV$Sh>nV0rD#8W1Yj3i%L9pleII>FI z5uVzk9YySw0;UQM7^`Wys%dLnZlPEBJGqYI(xR_l7annmo_@GQ+B{(e#ms#q-QJeV z9vhfTBk^#v@^UEVYa?~w=}Jy{irj~N?&;ASV}=W352&|S=?|0F^8kiFlDYp}e?Rpk zx4bd8XtoOTn38A4wV-5z_j^_S->rWrBH7S`|6%!~aY_Oyk0aI`=C@&2^1$vilNAqv z$Pqy?I;_@il-2J#32YQx1@OTdQ6^fVaH;4+jG@>ZUlkhh0x-xAMslUH3Oq!KRI-W> z_3dDLHw=j8zxlgqZ^XeHxAPo~r~ zH2Mnqg>OYwGm9)FLS{G;?amEz^Hx38YsS^rtPTuvIbzBVNqo8wGAfYv7-0s8>P;RjZa?}j-A0&gSh#{$=qV>b4)f6> zQLLAj_BK(hW{r|+(_w&@C^z^-ZN&5`!J;3rBXE_as2ve=xiM9WwXMbWT38Me+!u)! zf}h>7qv%jRTc3K{&4NSP6`oZWC7&_=Zb!!NT#UK3jBHv_4C^Yq9CZwKj@0Xk{I0Cj z+{we_BGovSOtib&IE@!jYHW|69L>lmP3X!A za<@;6KbeuhGXQKk0TEsT5q12(ANlD$5ac3U%TCZkLs*Mz;Lr+TJ%Ul_FiX5nt+QJ% ziC=ujnyxO(bNiyD>{IZBl6%dm*xF0nn#Mfm3!tJApk?HDPT3g5Z|(=CA5JiQ z>XjXl44VA%Y|yu+04=t&vvulgy6lx-vzGV$shJ=XzqOWyVxldE>pt6OvKyv8T>6?j zWYkTy*2?s2yL)z5P=ig(weld*mqE3YO?v79A9?aW3l)em4OUhhZgOK*BKjSx$k*dW zpY?G)N|JpvG(n&L#nW}US`Egpo;&lpg{N9V2m`9A&@ub5xbEY!H7@S)$1qPvV(<6C zpq^Y(UG^S-jF7?J*1rs|vAg^g*C)+^=5`|@dV~khVmv1Adg!{Hv^J9cN2VXtiaCW{51sg7yd!`q_E zKH^>F!XY0LB6X_mAAe?^l==PD~$C*=+bYL*6IM)}ARkWq#nn zfdbriw$ndY-5YiP32YgkaMhC%^t2T8GJ5YpRWqKl<>9b*!VyphqI@5BIO=oKnD}^f z`Tb~xh=IBh;Hgkn;%s%!PIm6nL`y(+A{u%KG+C~B{`+zMUenBP|C!A?>n28Xwp)Gt z%@!ifJAT<+4pV(sh^XE}cYev&{LhOcMmqeSEt^XI1g*TJz7f(R-22AQ&Qy!1>Q?lx z&4G=BzCq8^iDNk&IB^6-xNA3b{ZTsW7qydvpU1WCOpj|)x6b(Y&P*PA82M<+e|aqN z_!p%I58FwZ9m7AhA->Rn(Zr_49qv7K{L(Mn!AWM;8zFmdQWLpXL?<0Ws|o65I51fb zpxER;rsBf?ehlZMEo8ezgF#wzjh6Uaqgf_?pT|q_)>GRGTMIf$$--!DC25&YgAzmm zvp@kB=G8ZqN;S>)q0ccr&%RCj4gUHlJyL&K61=s0)5XX%gH}kb%l!|z-sNPx+Ln8p z}B(`=I*m6Vi(0k{{pNMvk2f4hw1zR6KrPRG{cImfQ z;pTq^z<%;CZg?o9k@w}FI}H@P0r1GH3J23qfepF^10M&0MJnu4&;pgbK`kEn>RQ%E zLK3N=_=xXQhrZX@M(9|di9DZcpTkPcl!|lLhbudd`U;EPLW(OK41Qt4u5?~cn^FML z9Su}o6y8^~L@_?}wwu{JdVMR-Uy6BwLeUGH#K3Y_j{7f_*CV=Ix5It5^W%F={+x7m zJ~ehbGi`tD1*dg=^cYXnl5Q8|bj^IO%Ih|Kx<@XaOA#4Q{Id6ZOV2+^Ftdbj;c1q{ znbtcIkyJ<O)1EU+#-3B75u#k9nDP#&f!EIQnvqx$gc3fj_yLd7tR{7>(VHjU9{B4N-Trkp`R!(6o4R)KV7OtJu-FC0o4bB6 zJi<^Vusu$g)}`53L(vz}5iKI)5aCGgsF+IrPxd%P|06ZGC0`edAU%_)oD#-~IF%S& zRF>1tqgk4J(A}-N?P>i;M!kl*HgoF&*n08vd44lxvcKSfPa{u|PjQsLU+V6^e@^4D zvy9M-M+TYDN0F>L`3K8_F=4!4eTKhMzj*5HCcGbcJ@J>vzC?b-cZ7n)?)7t{;B%jk z1lcvxcj;#F=bh}%e92o%56$#UBb$W`r7mAYyli`T8Bs0g8uofZG~G3c*~&E?<=db6 zBmKI___n0-wF_5e8or%2t*2p+_4jzCBWoSJ8o9-O)pt}n9X*-+`N#ynUs&FFxaAkK zXj-mtEnxVadU&9bbW4ZW^P9;zbcwHuhsoFR;m0E9vHM4P{+;)~MVgNqmx|~uN;`IP z>)n*8oM-avh~Pq9t7Mgeb$(XrPK)qAo1+u#km?X-68y2+9`TarMrF(~cij!e{9sFV zyPBJAgU6smTIxTEr{@FiKTr8m;@h@%+^xUz<^D|qh_7IpOhYq2#M@ z{Uf(i+2892BYqLdB{HNO4bW@VZp zWJY3Y@J*IMjqPKN^II93++25^6e;%3=c-jlipuM@hPmr91Rf8{AF8VO3~KwTXgu}N z%aasRdg_`t3L}nDwe#QoTT@p4-fyS)?H+hkHL(5h!Cgv=g_mcp#@FgE(f{#?V2w-4j) zTzuOeyRY%+Zrq=X_etDuzqyd(O_BvqwfljT{H-)Vn!mL;jo+BMelV*TDNo~fBYsew z3^(t$jIr~rNu+KcuTB=~-Q!7Qlm4PZD=ac5SR9@)QJe2&JuzCYsQjdk)8cTvmiy`x zvev!~lqp2W_V9mFAG78sa=#*mQmBz2YuWH1Tv+7Yv!EXDvXwfW_@D=rDA)-`=`yila0-io%`pU`>rk< z;^i#JaedW)B+=zn&jRvw+YjF5fu(ByPJoyq4Qi#~T>ocXpVo9bkC)ei22d-G!EHa8 zXhUd}E@-IZqS7lF?fHdj7(SISyD;&w-MY{1Jt55G?D0!#^sZ-Jo9kT~vhOG-kg05o zg@^i*SQVvZ`Hm1ClWF)!Vsl)mp(4ESnz*hWU1Pm}PfB^~A}EW)XOTm+sV&*Us;SN6 zO}W_pn-XDSK9kbM?7q8RJ2~Q0B*>g@dC=NH!-G99zeeWI$%l`pi8^^kECp93Zv7{{ zmWF-g-mlLmV2*{Y3oeewo$RN|$E}|PO9BkVigpV=#2fm&eEW~=Ncs$7UN0LgQri3G z$)FL7cP%<)SMDdfV*9ynO1*dbF|G7%{fGO&f+V*e#VVc zjI3MB$-@D@7!DiMHKjf(Q+!L(gO6@w$|F3U!HKj=;x(t)gHM1`=?M?m`T)SqUo-op zGJUm^g1iS=rGf^u2Ab4#3`w%PJhbHoy0G^A#IrP-Vc_$0WU`B3`wIVapjtvYpALAS zPG=WNn?8kLlgrnX3~0@ADQjnz`~nrR%9ykooriT;*P{YRlWcwMrO&Fo_3*zYtw29Y zWPQCQ-C7ZiCc3fu_Jw5gR4JdkNYBGRWtS#C{P~*R%%5jdY08M;Ks&yw4D44_9r-PuO-&ByYUEmZ1Vrd zW{2m{X`TA9>-uj}HIzZ#HNHe&X?Ocdv%Jjtxlv4YGQmFDce%YXCE%t2;=|;mXM6F3 zCKbi6xsyKUZTThodNsTBe@=(*3bGqo5u^nIERlv9tmUH-TJ6P4H87HSvp@M`h|{i! zLeGSAi%Qj>^)Ff%-3zx*ZkOC~;y!bOiGKk`zET07{O*6X%lIvN-y-L}Zb+6Ty#2cbz85{a1-N+m_CL9yd*HvWP@2`ZAoW&OI#mj=_T_-j zr54*Ri5eALHgrlPrD?9a)23Yxof0S*1*hJS~c=LJ0D)!f-9^c@K`V9A^oz&sYoj_R|%t zOz9Mj`)1ihm7R2l49Ah(SmidyzQQx@8GMlbgO8f~Dr3>_LwxjA$YkVA<>y13$r1W` zK_PFqECoDYZX8>;beiPvzV}q_2^?wXcgh*>@3u1-Y|v;<=Hu5~BnaN7(|eE{(OCwx{^3`^8 zszlYtO+RyOw(|$jxV$@C0F4WF!YnN1c{S=5UXgvRA12@AzC-;|afoLIpQ8}FL-(zF zWP?abl~mo~Qcz;7!p1+HFZ(PW`Rm<95e;}4b8T!kWjffDEakk;drkFi&-+^se>~XY z*q48)^gb{*yGm%|i?V)<5(x2A`jHZ^+r!^Wtd*!+@PX-QTMF8E9HbQtghvKZDBGfv zc{;&xR|=5w;>@{Ct=dT-^DE`UmRy^TIJn0(6*SyAH#@3H=#c(HKu37HP>zmB8LT|O zY&1%+EBW3l;#or*2|UdWq|_(I?yJ3zw*D{vhuxRI2Wt0X7Hc2=c&LB-i{m}W!Y%TO zx?QSF(0|A;M0J)Ke5zDz-X9`j>*9s*o73RDzdIEFop&pcNe||-S!a{BdG24bY27`| zy2*{Y3FtZRcz&9%;Itd$t9?H7A6~vMVcU0Hi+z(Om>l|26JejP@NbLe-X)@H-G3HD z-hWQsMQxr3|F;Z4%@R;kDAasBs=^I$0^H-rgM??p0!&m-GyzVy$zFcu_-&>LAZuq6 zb0-oKr}-{c6B1m_jKl9Mwi@^HL(H&{SNzbpgz@Aiu)BH5CiE-6$KfIpjzCP458uxQ z!5671Cr+lRP^4uZcp~A5fL|iuIpYabkFZqV0*+hIh;JsGHTa|N$k}yGz6zZe$mfQa z`@-sio`-3kim-W;Jx@a7o#Gi-HsV}w8m@N?&nB!~qL;|Ci|XR&e^|;(5={<{lBxhr zIrq~9#pM&fnw+Fq6Ub7fsaWOCl1xsbuN7y(7O+TLFsQX%s28kZ3+RPU>E&n{oI_aC z-C>&p>uhK$i6+#fIO^~5*4p%XyW9FIj`;&|E24mT$&KZ98#B}t_~AP6_9^r20xA}X z9fqLYrh>otknLGFHpATQdE7RC(6;;u`$!wxMy zi|Ydv$wRB^1uTs@Vi`GWqw}jmw2af=>GbE;6hkCZYU!UfuMVPEwg?D`DdvS~=6h|3 z)vFsMPCUF$JUeElSs+eb$3la)V%xCC%?P1fpqvCssAX5k6eT3VBGs|YhTTzI*dCYK zkuTc8F6Eof@8dfFC+Omc%K14yX=s#-MvyB5_3^W*Vccn$Vw z_k`*{Q!?cPbJbTxsw=s({+RBkl=FpCRE9WUZL$ykX?kkqh;T~oy z4tX>xlAZo z@(;_cAKw&95FZoZt0$D&p=z&+jufS1we+sF9o$7ew|TBFytiLbY8%<23mP05$sHItsEss=S@e;)tveGBfxW2a&x{w zGkz)cg}}!m-=t-#u^&`hQv$l}NYTBR#~J=5SI}?bi&SY`Gv$IJ$U9=kHtQ<|E{C=N zBP!4d=Rbq9Ff8*jEQN}%wA0bPm;V`l9B}#qo{iJ?MA5O*a>d58h)K~`H#69G>e5`` ztHnc53LzP_uswHFCvJynmi4}@!GT;@(j1FSq)SfQf4fWTYt07DopK??GDsJ@kzo!KBEd?IExOpc+?Rq=;W_9VT7x60l zBD75LGP&kug`t;MmJqF^p{0*klMb^BM)UUZ&)HI~59dJ(rNO5!XjmDv+?(TR%CtJ# zX;^6&2Mbwxmn7H~LX=i@R4#QIrbF)WFdZbYGNPqE9*0WZcPS4yj9lDuD|5MbDk*&5 z6>7Q@S}Ys<^0t(WoYaDhV_2F+k;%)swCGj#xw+e8f$SeJpO4^C)ry(TlOu-(o<%Pe z%}7y2H{L}gfH~*KE1F=z+tHe>%rSV2v21wrMa+Mb78%R@wIshKQ@9-+DKY+=oivrz ze6H^I+&@v2JS7P3lAF^K@2PXf%?0PqDCP-T1)8b2ILlaH(TWzbSL`{3P|)^wm-jzc zna<@If(}aUERF*vmf?4aL3g@>6ncJE(9vF;uMjjDzJ@ZgudFpOGT5Bys;#mL(K_8M z*U3OJHRPc-^O$(#Sv^@&yUtwpZCn}{(mtZ3WLBJW%3WTc0$!fFm8?e4%A4F-jd(X5 zZg?L^i#BE~1q#RmB=j>s^gQ@E&LuCeII-#p{5f{m1EH|w;hb0e86DGc!^g8U+P5_4 zzn+|pY`@p}$5+YNuZp>8%efD1RW}x@hv*Ua^Q}g1d|RvLa3LCTND8UJ?)B_n!zvk7 zfrPj3@8h?bJl@^Cl>npbEZJVx{Mo8S5we(Vqn*HbhNfL6ixk_H;Iu^<(2}bcUg0{; zIi)HE_su%R$G+>R&EeTE98=13MT<#jUSrMj@|IjdEyfaE^>@t)2 zPjtrABg$T%wiTbih#aUWM-vZcER)r?zk zxL^8)`TRm=zvrvGP~1Jjw#s#)td$Ni%%oP%*j}1@YYDpF8ZPpS{@@!SsJ}27u%=h=?oo{i$gE zD&Oz+-w_+tp2-B5ow8BYt`Jw=y_0J%zU~)L2G7-iZiQ8QWWM9ni!RP_3%+LE-c6-)HSvb1o=qX$m9h!*tn_=-pP9}9 zwSNoy+MX1zz|lq7u4pLxoi-(>CFYNV#!L_mbi1z8oo1OSy;$Y3DYlk`+;<%aN2g<* zP)Y-7{^$4+4ab`gY5Ngz^v~#FzqT#mD#Z$+*#!4QCoA!=|i#jwTAMSyq`hY>cnp-s!H=+%){A zEH@ppUHajl9eK-+YiRj2Lo;sAkF4rNJ?M_jCO7&>>u9>svwxf zPJ`aD5s{QR|EfQCjQnA#wyNyX{S&J%H?|_vsa?W%$Gw})3>AInn#^cjea1Dr7(*}7 zg*}DS7OiXek{c`MkGCU&)4CcgnwMrd18<9qHuupgnFW`;625PPr+CAlAVn`Fb*X&m zNY7j*Ss+HU$>2SQs#`?$Ep8F!oC~Bjjy}5n7i&n{@oC~TCAzJN{ruA(#s%SjY!iX* zS&Ggt=h!CB0RJitx)?6#`yy|>xzOZP)lti?52znwfmYs_q*B>WKrSU{zH`YR68Njo z6QvY9oBjM`*^l!M-$%kikl%$EycDPYh?8t-_+8c0QZ>!ChPyX6>%~#wGgy3+&=X!^ zj==g5(HE8cb7IruVOh3Cb=1I`QVFNt@DFs2w{D=Kj0!oFcCdzYd_uX$ZAW(mEVwMVjRa-reV3%dw*8~5F`v<0tTF9Q5JizXwLJHO1;8CR<3 zD0dw$H95Yzi&A-U^r6#nONO{pdP3gl3qJndWvtNR*c0??-np+^(sd+KK_TexW$6A` z@WER1vl~6Ph`mYgN~d34p6AS|B z{@Zs&|Dl8@CxEGe+;Qi?Mpu>3N9|eS;3X|{aTeaXtW?mpM>Xzctl}(=;zJ=K73vQ6 zxQZfr@JMuVBpc_5yaAZ$>9+3D=`q@SL3Fu#b_?=xT-Aj-LX6uMI?R5HUUWu(^OIH7 zXT26JOlZ44Uw7u}VlXv~JD4)nQA&AiDKk5y#~$p}Wy5YyaJOZT{2;et>rVjMvjrbN zDY5rUmt%5?Ubbm;iAOoGk{{hU{Lt_q^StDSOa5^=i~T+K!;;!tM?En1;DBZOz{d|W z{hvN0wQuD&hx9zZqCTQkBa3g$_hn^$&4e};u=qsKMNBk0}BPaGXZDe-D7w@F$ z=)>lHXT{Yr{bRXh56>$dK%0JG)Q;VcO=Zd!8CR7rjoMr2UnrjBxYI6hb>gpo7ZM3% z+H~$-0BnE|N8R#?It82~#HR^qwyVwNj8NPe5LJ)m%#x!r&I*zVQbeai#TRpRsBiDi zX`8W0&FgA(>(o!MG{-`iu$ufG6Rht1^ZL}R+qv?xfgc2{hLLJhvp(NtP3CS=e_F6~ z{jQTO;|KfUjk5mri@f9z{{+h99QtO7@o^AP?}fKR!4j;hL@=hoI)6cCxDG!^XOKqGgYJGwlb2AnfsxBRZFaXO%50P9U;2!rhHq{k8f>WASWh^-fiFpGK~ zso*~E?+RdDPm4CVbQPP{@wXoMf4Q;u;+o;{0`?wa$>#_- znx7e7$1g7Icf)7{&?&v?Kom;j zdgZxz5{rm@?wKdo#3N}SP2;N7Z}wyNCpY|GL)3X9v%n8NL%4gM`o~XP=j*`i9p7|! z83(&RY64a4UGBf!8u_NI4@xVxpW55S5%w zCN$}z%PmV<>Sm~!yjgd=GG)pH0g1s|pu!SA#eH2`&4Zh?#&&mi|T%SS}Yp41TL zF=~56e)dOAt?!k*nWfVa z{c0vuo21OhzGqL@SwcjrItTl+{m-D!(?8EUVzimZ6!i`XGWyKoH|wRGOU)8QxPHb{ zsD9}gjen(0+(_AXAhtc=sjbfiLp9;0*7xtN>Jol22x%N@QP8I66O1HiILSPxXNpS8 zaQ9HoLm|5{tzBcsS&*KDbh?CPF~T9v#&i1M(rh(mB={iB-@{)8v8~cl@%Dx?ieH8PMTTagR{7 zcWPy|9>X+Q$A5@G<<25=t$)$nGT6U{X+6&SAfNxE4XyVkA36i6dIvGYPcV*g5p#dG^QTe_OZR7B?pXQ92@PNvge zYUCy_-V8huV9RqC+lN$!&$|n^#{XE*+?-*92=ad`X6w^frv5nKNz-`*egs1ShX79x z&t?L-BgNd;zu4_2f3jM-Z7uig#|cgEWTqPBgd4M*1UK176~$ubOJ+MaE=UcKLM1Q2 z$6(bd+0)(2yzkQW{D)`7z4~|ggf!#X{nF{U{-F8nSosAImfmXW1^f&VRO|cF#VS9yF_8saL4(7!m*@$-Gl(Fk3?5c4kaVII}H>0hz ztD{P?D|DqjP6NG=Da^tTw^Pa~ZCsC-hTmW{$9p#sOmJGxACtl+^26-JZ}*ARC&$Jc7Wova zRhT>>-$FNwc>U9&t=Q`l?{Q?x)wte$YS#Yw`3=`Hn{|*&K20q<;xSSjVyH2PTJ+0s->}oMgxr&Z0_~uMKkwO)sDW_k zWG5f@HXkjm02)YhqaDesgB$@MWpUtsb7Y^JpwD+iKPdrYhkW0fu*HBBHUNL#O*GqP zsE0C+nuBFX)P4kLQoC9A2rSeMYD*G~`T?u{4%1dlJ|!gEVkqPnlidbbBD9#@BF#N% zMdW0!ne!)WcbmmZU%R0RH5yMgDr4~_nraJCkb`%av$R+(!&ze%oVPwl-u6w4{GwR8 zz}}5RU@;&D>=n}v#sZYzY$LkR;CokaC^kJ;U+iuafa0o2CLe*d;baKq5Vdiwc^M;; z51_;Yn$Gkh5U1NXVottsWL?H4CD- z;?PL|H4LpqKM;unK>Eo5F*Fov5XuA8w6LVLrIU-c1>b{b$^(#G)<`)Lh#3c@!~uED z!G;z{Swf-M6Oi_)rs|yRwwIOzA5*tCl#7&ieO5RC044KNAPfOi#B69kAeaaXngy~E zve<~pbhpi-J%r$LLeVnGxE=s<7Gg{C^TS=`@e8IEvyt)6rmH}@9ssAC6EHrfaA3V_)0)K@CnQj4-jz!GsOd>iOO>x;_D%(&;1~%Ie>#0^V}Z5?9 z?PP81FPf?V5cdf$4aXHt)DOBM0$yJlLfWrJ0eB_+;Do?!f_Wg8pARNNjxe^)0@x9m zu(4LD?Ib*7JfK7gC;{+7c9bz-%cb&pAq5C2xALowCPpG2W}$K6dylgN&Am^{11x|L zf#R3~H2_UPNvIKkh6@W|Ypom?h8{i!a?Aq7Fxecf@r!3T)0zUtf`s8&B>NY7Y06BI z)Uk8tNcxAmiV4 z5z>m)TJ_dz5b8sqZaGYxRBvGqz)!%`x}9@DtdhHob@TVrG8;2~v-Sw;^;9eO5JANm zcMA=HUvFfL7u=PldeluozQKavSP=Fqei#iB4>y$URI6M~O2AtQI+%Lq?4>^MZDriFAza6EU0L*tTSGnMGGNC0Q2Gj2i;OV zc;LYkFeyo0c*mF~%$P9}&C-y^b`zpz4iF`h?^yKb3l)W0?zD;mXlwvbt5#`|i+g(J zP#d=@Q%vZ8KWGb<__RDA$2cENW~8Kfg)9yw8xLT>GK{n$Iqi`0m=3N+5R3qlGe=6g z0Yu{yr85AsgqxaFa-mE}YfZ=7+mN`Y$*#hsG18BNzr#Xjfu@;S)_ABjng)R@3G`qr zoWJH^k&+jxi0XpXN(02P$u^`C>sE`1A6=mYnA6ufTL9D+_d<(>##p4(xAMi~RJmVX zjhU0(Iaz6Ya#1rpAXxt0sp{uhX`%xOi1FE+>_)N7$etk}k`M5_AEyzz$SyI+{u&*) zVriXT2Z9p8T~^d>#>lY>)EYSg^@#wYZUv7W=o5)3C?05P4&KC2R|~5GmsQq(aesnA zj4|2$*C59ES?Yu!M}gOC2app0&C;a17b8R*3z%)R`QXW2FROO3O)b~YOQC=gzynTK zJc~r}D)J#amrtZHUT;DGEZ8So6nso!oU$HyoQWa#p!7zwc@TVoE*eVR3rS(Lzp^ab z;$wm7kQs)stEI~17YO4iSc{HeuoH@&laURfe`k)AWlI{E9fX^MUlWn?2@E3ya6KiG zr@Yg64j~HYl+Td$mNuQhA#WA>h4NBxp#dS~Fy}kaZ~V-5?u?G21*=eKk2kaeTWPkM z&FZYv2O5^l^21^`AfVGVZ+b>d$EY>6-{Ho$dr*3f)Kag0tND77@f>`vlX z%zk&0$@q)MX@ejzBM#V4V(&&j;Ulm=bFc!RJ~>$7!QwNOu^ewmEzIT_J#PACpV-$z z0ynl%Ohmvv2Ci0-%okxOxqN^awvTrf)x}5M{wt$&cHq`F=bk!LlSFgCH8oBQ-*(}8`7vIX zGP&J^=LdFtountc_}ql_=aL>89bU#5UOqV@HB}R>1p!E74pk|HsH0z6&D!Z<$ZgEC zKt%bJC01Iuf7WCc#9$A_&|XImgy?Xb=A(-4c^ac=;IH06C@^F!!e+{X9 z=ivwzDPe*fGza6vKw|!aUhVX})<^@6)DeM_(R!%=RiElC*w)R=`wIS5190M#Q_f+h zH~<@Qq*Y)vDv{ZFPUw~!6iFzpc>%kQ1*nl=p@nAFb=|;OAl=BY4ZhCS9KhwK5JAV{ zuhw|WEwVC!CIz{gaID({V@pV5fA6lxaHW>f*O0&h`2a|$yQ|L`ZxQ0rO2P93%6lws z00#4nz|N;pot90GlN(ahO!#NSS^d^YP}dRXjyW|m9@umrz(Gb=^xOeH&ZucST6?+A zxtdQ+9K~q1LWZ20*ABr{Zg2QsP`}Tp67L5BiGWoV%;`25fd{_vReP6YxK$+q>1a7t zMlTRnlkNBv08hVrqNVgS>MC>J$fD}90E}*r=;Hx@vo!n}q&O2b=x-vZ3PN(^pfn_a zb*qg1B2Xv{XGMez*}YLC0Y0-sHL!zf*n;_Eh!v5V1I6!}Dh*(u<*5)DHAkK(F{l7L z)H8kbq-1dxNalQiGzlRt29U%gO8m$C%)188O=$N}+0JV`JsQS08FQFA<_i4#qMV6qjL z`Hhz4Sa9i;Rdye8;}zF>di6dR=mVw8u#E| zz$XB=E!_iSfX8xg^9hDVoRocHzHvgx7Vq~s-Q(Wsu@N1mKEZ*ZSsLjL<3Pt;3M}YV z|J`3Ga24wPjt~fB{#1zo{w4zYWQYEnt-)Q$)0=;fmq);=KObaAYl_*n93?`~07Xpv zsav*9>wp1%YIY;v0wcp)OPlkPjFw9pl=MTYo?g93fuCiOQc4RN?hGc|9dJBQ0r8IV z%E8|Xf|8!~wF<2B*O`P3|A^OeIeqDM3+kMIb)wK<`{XPsAq#Rz&rha;QJC#9aMVV~ z0-@mWLHN!wEZ*^jpA|Id_~m205h=-KTQ}`w1dHdF@AppSU6WEY46bEm?Yq*PHw`ul zk63l%p7<1hk-$G>wc@PujH-Bw9Lq=l_?1I}1>*Wv-&HF=6A|m*v5KkdtKSFo`@5}R z!S&HiT|=mbSYU?;O$Zpe%d{s*?4OfS#Ka&tU3VfGg=S&`mU5Q6R9z1;CXCT)+>#~45 zLWl))`dKeRZ%>M9!KiEYgvWx`0!Or%<+FMRGAGg^XR>Y3GAJVe|3~Q);vL)pB)%)e za+yxD0Ahy?+rTqO`gd3s&A)aioawKz2cbt?_`3l|_N^YTUCeRjm;ov4`uS^G zDWI%n$$rDI?uPf@T>BHCG=fg6B=_MAMoFLb)l<*$0s*tf>#Gle%soLHlS@6I6u-%c zUy0qkD-ttZ@}K5;265R=H zVv^8_qem*x!LEig{5t}a4$Z*bq@>`o^BA~YisuDTkA9$m|62okr2kQe(CSdHgf!fD z2za8)>=aP`IFagco9=xl18jVOQStx;vY5c(peKtRqyYM!`CCj+Iz${mAMzIp?ZEkq2|EeUn*5z~-WWI`O{iCumof@2gn7u9o?epziZR%M ztG5Y(xVWj-=`;BAvBhTUG{@2z5ybL@vZQq3$1DgTz-WytCZ?JtGxL{sxi>^B9>kXT zOQ6ih1iF{P>>I^1;UTyq#FwSmo6dWa@GBivo16Iw`0R-78HHk$C7-11TH|06uqDc~ zp?8*$37~HA_vDwaF!H|^l=oSlU#`XhocXk6elSxI{za2ozQ&u+NkmqNkQuQQ1s3nx zX|Dm$Y^M05D*=q$sUeA_s@U@%7a=+Pn4U2b$qi%4Y{4-82saWz!9_A{@NiDsFw(KmHxz*r+eH!K&c1N>)VWF58Qv3{Uxd5 zPbW}>E5uq9mmHXH#fM>^ex~PLN0l1`00Knu$^Hl66wM%O12p*#vBKZhWZ57{+%MyjKx?|IE1qsc}@|#>guew|6ni5)u;c zL2$A`V93{NORC(H;yG}juIw%5fC#EYKEq-zFca|{8 zN{)n>+iymn1}=bDXsK!ZhBooxk-Eq+8YVyGRz4RULu&1xocK zy`_OLJc8{ySt?~JSMGxlBX0qldU*rE@azBP_sb?;iW7Yf2mW%;40SymRd3xz&5R=KY#&h6QK!+Gz8lq^iwA8y~&Lq-jxbO%aRv& z6UFMMz;|$3%#MZ{!snPMD>MpVPoE?@o)C0LTI(m#0+JevFnb^y&zvbOs>3dB^1vuw zEfz_A$&kQSYl-^jjRaCLC$K%w1?t7f+=BIs^HqXANV!5X3v4jt{i6nd6+`n*RqDv) z0BII0(qlbCi7-@8I!k9T#3^YCrhx#^t_&39;rOtZq~1}^_jvLyBXcpg->lG&!E8A9o+nHJfitamLD$G}WFLHcnr-4SDz0`@(Ge=z5rYFP0-|faA z9Ui$P^@koq6*Wi&zve#j!-0^C*JUsh1l!voT~Ga701%DoQ=QU<=yZb^1OY%9B>P*% zJt~bxi6_sYt8{|5%aW6XbP}_qVVh zeA7J962w|a%+^l|=YO7h1hGb9$^6sV*h&FSzDO(xjfPwU3t&$840rW0kkc6l$TwI# z)1OR$4a=*G9A6Abx!#ms%Ku0b~9FSeExBb&%K~XM|kk zzuP%_b*t}o6mxb;XBE0bvI5DJfRs@fnrHo<)MfGe{P5A+X0Uf=r^FUMCy!G*?y%#VQrqQJw?;DR621I+^RzOkqx zYZ}r_7JzCQ7kAJIRiMWJfa>c2=n$YOJ>>ZRT+t)7A~S`pMZ4$U1q{_;*3DbMXL2|S z8$erY%?Wvtf9`Mncg7sF+!!D;8bEb`8bZ=&B|OaNHW#}xo6)*=<9>kWy-ey8kA}K0ieWAkC`YXm3xrY9?_qQc5#W zGK{%U+=pf}Z3_#0sr4D+qD~lYu1m@#B>6;X<(852_%!)M)lFF>3vxB_|H!-lwUWIB z5_6#{c%HAr#}icwf*Z&4RDkXi3pUH*#ia|jQ1QI<&lD;_N`HA?g!O7Y70o^sJ?%+N zFJ(rHl5-qDG7!mHmCy=b-l8q_M9gDX(Q&PDmMl2=zm`-7hUfRu36i4E>kn|9F;w}0 zw$6A^Q55(_E?AV92DQ``$EB0C$_G;_SPH;56R4Uo8JzZfH&Ve*^84>3f}EmpO3D+% zwqT{wntTIS~7un8U{=hh!HZ~`;JGr|B znbwC)q@qadOHRLmnqY5q=~d<>i)ZVnb7`gjE6YXaLoqS=)XkEM+_2JVi@tb=9&wm7 zv&?XBIgfQRsresQ)K=w8Zl1^?zq2{R{gu4;aPIP*O3zltPm>Ie%aE>ZQJosm2k|o7 zV$}lpc-~YVb%}WX+#dd+=Jerafw^Y_=h)29-tT{Tgw7d-yi?c_kDZAvR(#10hB~f* zqJ&hPr_|);Sl*|x$?kJHsFBC%rKy?ca&B<)TB93I(Z!@{IDas()Qw%y-^HY?yQC@? z=MTK${fRY!eV}KHRUkiY_=MHl9efi<#eb^ttUS$|kKd||s!Te4C879nug4#}3L3+1HzUJ~_E}&Z zJspsN>>no+c9J!uiTTrHMET_7utxAZRo)OSHoG47c?O3AE-81Js8Pmy-bT`&j5I%0 z4}_&0@l8qc8Ov{0Oa4&1b@*&erdmgaxhv5^=P60FmyDS}o$O_soKCdxI-eRH;pN$# zPar0l5mGay$$73G|LM^Ij1~c7Qi8D=Vl*X$(^h$m9+wfTs6lZs79>SKASlcF{5*|z zB~9^U`rS_PO2xZp^rg=XSc_7v9vdtYVix)G7puJ4;?puXUEkFWPgl>qlIMQ;;^4N< zZEM{m_~b&$#)t&ZCw7f;(=7x2na#4z>AL$&*$$;yA@WG)6ZTLXT}|GbKi$cD^yR;x ztUXo8^h&{tsiTr!ZNihpX?2FaB`1lv#spG#u ztw|ouwF2Rv+Q;+Fnz6mT^>=gluhmjeC-3AxKFP!WrWX+MDMI_gXrA@@_R06R?nQ?8`5%e|Z<(EiQMsLRdR&P6m=jP)2ibD_7g zpB$$g^{=XodOO)sQTaHbN_^6Wbbr(^u!_OUx5{^S*s~VPR`-#PTl-jMo<##B24;Fk zVB&++-~gVv8PGw#NG=8?X>SK3+P+lywyEJZ))qzvfT{gBi6Cs$owl!MQhvQC#_ z(ae9oSl_L?x>M|L0qe0`EPbWhfY)u2F7?K)dsD6uI3!MfzEBQ$SK6^YQffyyW$h6K z1en;L-rP9N8dSBMx$pO~@k3oBH-7P&6%o5p9g@7RmDBak*`8+gSnET-hYI4&P=ANR zGZ(H3IcX;iF0dT&Qq<<3bw$N$?muOQDDk(;77VNvlXZnlzD3-#n@e6>sw_V%83Gwt zU3wf&RJB41P$5Pd)`j#pNz59*7&(e%rWB^=c6s33V@f?DRSC(%l|}#M*{(ikNq+a) zxE`8JgF9s>cY?~th^7m|N?Zh`*z8M1>^)c?kXZ)u<*N@s7+In%kj z>(g@h4dp=i7%n9Ue9}vhPi7T28l3WXhVG$3ayFGW@(iodlc%zvME(f-RQo7gJ_oZ?shOn1|Bkz3n?#HiG==41+zIB3qX zx6Gy|7m8dspYK~GvFNNm-&6Nn5RSVS=#-2su&jf-ZTvP-60)*PD5ig_%fMJuOv9Fd z;+IQyI|knpfB4Sbe|uiyQ#|mNV%+T@nNQD=5*nu7NoNz@VH?d28)w}5tqS_)yIf|U zlRA>F&kH2!Xhr|n{(+nWu+L$@V--XzZ7%EsvdJY^v~e$5b-7dNoW&I!(a67<#|pfA zqh^xj?`S2DqwnoJ+>#CL)#^-*O^olJ%$iZQtFM*}5BrcU*#2ax&2 zqmLe?pG`(QtMiw+20r&LrLJ&)%R=nm>v0W`8I+QAiY84*1@22rBBB)C9(8&t=?y3f z+ez(d%CCPT@eS(sEy=;qv%9t4=RT zOyg&Z%korCbDI2f*KT-C)P$=<+VWs(5^|nKbrsYMd(wW ze}s8id)2)cO)}xV9oF-GnX>c&%~F4#H8+Z~ABBoN`^ZLa?88d#TfHo(_f14MYJ#y^fz{^bLCj zsT31l=nc&kD@1|SvV(7Lgp0;lPkC;%aPPET{hFMyPu=!U{dGw1wSyg@V+3+}Ffu&5 zxdaGXb=9pjR1`9Ku?lgS9KP8w4%Fg6xZtlwD>OF+OSsGA9m~}n?W#Stvqfla^4Nk? zR!N(?Zjzqe4r(`E`_BB%4|uXR1G&F9!_)o1Q;X0$%seg>xts|Q7n+$$7k#YxfOpp6 zXMnI*Z7XH{vTYe=zjx)QW2M)5@_vv^t?ZtkV)6QnPOVI}+e^vA??0W$o@6|?^*5c3 z$|}j!^t|;qz#e^WP2F^mYi4TkQlR?j<9|0ptl3s)<92@0r}Q5+^cz<8_i#RIpoiI2 z_D2VBDEX9cM_g;?$Hgevmmy4hXm2Us==?|<#lQ)n(Q3uWwF$=P6-dm=u7;TByvAOX z#*|Co*N*DbpsqDk%c)Myv93>H&VuLYT3_@&luz$xaA4R<#PUhpXJBoLV0uOm2b?rf zAEZH{snFmSy|l$petyh-@~=2bO0QN{(G9X6CRdF3&NNv2IqKa;Y{SF%zplayUJD!~ z+S8;wk$B7Rd{B328_{#;cd-bkwSq%Q+;70utn2R1s}Le2J7CxYUD)}u~6GykWW} zOk}oN^AU(fJY00XR`1cC9FhNHN8^*o&!@Y7C0)&?U9Ru!KYYE@YF82X!DB%0I^{W2 z{VqB3=IUVJ#;8Xd>zab!;S$7-!d)siA}$5Mz94C^K7yqJQ!da3Yjf7W-_qxUjU(qw)l%s+`T@1t;?k=F;?ooUR`H5HQTYG}sCx@9}sSPoPtj zAW3_jq|K)UZN$Z%|NQrl0*ASx>7$mBn_JXl4d~u9PatdgfkQIM7D7l`%&PslC=Q-N zdJfpVgL!=)ot->=R^3Dk4k4dkH99Ol@AY&98}lG~e)8^{oVTe@7A$Uo*z0q(8SU!x z^l3eEENwPV?^rom?0&GZy#rw>vT;)IuyVEgK&2A!Zr4W9C7GQ~*`v{8&u$qV#^!?T zuPbwYK!de)OB2$wbIoH|g1ZIlHJ0GQB?mvc9u9%;ct5W4bnqFekJG`&^7~4E3wp_iB87LzhBCxbN>h-PV5a7qU$) zb9t5W_~97H);ad_Gn+r=R3l>}_VvYyDJsB#tR@Tmuyig7?6OR9N#V6DolD$}iJH$4 z43uBcXR8UxOXso>7042+E!|4-9-6n*GyrjRTP&C>p+0^W`6{uG1K=e8A#rnSy@ zSy`W>cOUMHuRI;LuL@fc+oY8ro4G52nUH-Z5l6VZQXwtlY>VB4MAE zOfr>2awj0AsGvgS38I`Th=cPL72^xej=T;d-VQ#uCoEMY_;6A{ZfbJ&%}-(7M^Cn^ zpB;mws24R2HAXTfO!>5h?%KO1dAxe<^+8aYJIrmV%qN+P_TFNhVQ=Y2^mfUt_`eTw zGr?PsK2Hpg#@kb2%rVS;XO?}r@(67+BUSTaqQbvmJ#y8z#J=NEeyz3tseZ+>e5>LB zG+S*{SZQk~UG)ivS@2J= zz3Ii$JabGo#oB+WIG1f6UGw)yyELAQTVneaO$YtDY$Bz;SiX3$XL0eYd|ol>y4=y+ zs_&_Fppig%6QqgznUQI`)9D~4LPXI#_`yw zC#7i8%$AuvLn>FKJ1;v>c_LN+WhzA1oIw+rI3{-!|r`zubRW zKGCma`;GUbbu{;Ws#nPtgG02@ZmVT9Me)<{-In68N~+q{yHR7C{ftc}o;BUK&i>B! z=R&ku_^pyPaTJ{XiTO0TGoeM><~!0}$L}brFq0Tz=JIF=&`7M~1o9_brd(==k#!NItaSu*{8B`_}ig z+5VOzc2Daz`? z)HZ#SvR^{r{gFK`+m&>c=3zivU5-VTgKxf-&UWG4nwCWFFeL4UgKJOoP@@#jJ5%ih>XtRvnvZWL6krZpflLtaP2xLc^Z5SmWF^cLpH6$FR%cm~k}{drX@4FEMuU%Y7drY$qK)+| zgE3uHbXC?qH;$#=`4jd5s`qE)Ae(jI&G*nX`_zy7D~LLUgAyTdxBhpe|Mv&mtD?Vc zY{wi=M)q&-Mn8iONqL($Or4DyfpZuMQffts&Vz0iUm@dCRMeSATM+p-Nv|~rU+4Io zy$%BYb!h+N?mr{|HHLy1vgs3LrBF~EIA}WQ1k68v2~}p(Vu*S{CQOflBF_o*afmQJ z=oM7P8MMfm;DIAa)j(}Yz(qgl;KiMIvAaP=lIC^49ZL7aZ2e$M!%mT`ANkovwX;rw zd#K#Qua3a4Art<@>}Op^enyxE2v*F=^7oY*#w?!kERN@At`Vhy=w;_{UnMzf&E5L~ zzzi*vMr^U1C`*P0IuKrFx$IoLA)Vlum3_lQJbkWwW6;&ap(Wwwmo7>lHdM8z@ zQ_(=hudsThy;c%PV~?g+_(UK3fpg=Wa6jSeXXLvDq5saOZ(VccXD|0l0xxceX>vk2 zF)O=jms`9qP0zCE!0kwK#by+Z`&`^LM}quY%1i36v!sjd|E|t9UjF;B@!x-cHm*J( zrE(!Eg?KmCqp8l2l&3hTB=&*H|CoXFSPJTL zCC2yPz=kBV%M~!;zaCx&j!j8_$E#0xYEdAAAWCfr%*wnD&#sAj3TDr)QM;@XmvOr0 zKXAlta<=ky&E=@!wdtmjJYQ>gF7P}To4g=b1k9D^tcLdtpgxztiNtbByK+iz3D`g8 ztVI1rZLu5h3)u4uI&Cqb`2}qr3t83*t8OumXp5ECiY<(ZRlADUZmD(GijTUI#9nNP zO=wG~qJV2-FY-1dPq$KpG9|^+m`1?r)B-Z2V=}DUG8}HQ9NX8|U^!MddGT#&**aMs zH<~pXdG~9sslcv>fQ-qyQnG+Nb%Ij7fHDlco0lLbfl~~vR$jtWj{~_fM@0)!>`_|m zsUY^$QH>=x_BW_oqXdn!I?V|bd*&!|6m@GwK$~#~wIaZNu&uLFcWY@|)YeVUcSkSO zT|Z_=ANJXajC<++F<*!Gd3iPWB#yG=Yv8_(6=~LlKej9B1W8+Pz~hboYX29Vukv zx=SaGVqo4v)Oy&rHXu3y0LFLs?ljm)B+&Zc`#!h6g^1iDHf3x15ceol(sR0q>@!o^Nek3iaeor5AurK3`jQW_2vbL#!>R7CXf*aH$jP(8LxwK-v~MOzh$QbjbYR*oeY z9mLCuCg_PKDIO$xdM7n%r$inkz_5wc+G>{=&Sn%_IDxZXH2pg07==xL0nBXl&g?wM zoH@vdA*2sBr>}^nPl#rbywiCqxaheVm{FDEX=PQcRdbb$b6jZU7W%ohX$`T$V!I-n z7Bv$ev;>yZll-b1{GeYrHd9P$t+8yv(|>)hyjo0(Uc0>bOBuOH`9z~kyN^F;j0y_S zJlJx)`0}`ResoP6AP>AAj2eF5TJct9QQtb%uk2_-oo1^ikGT4Kq;%GJhL3XZphEXhJpLe_9p6s=CWN3@ z_f~7imN*X-!~^{nz6I=E_w58}@tgpAK=Ftj@!l=0h&Pbc`&(1Mw?TfwU@f{S$q!ad zc;f5%r1r*>Y(JRqjp6)nk+F8y9hayonq=9Wvh^)~y)9ws#*4@Um0y0(`43XGMB_c1 zRi&|9u|T$9EL=ijO!IJ5Q-Up)z?O;~(`q00Y#%rEeq-aA?m7YqwwQHNgVrLVcUWJDONK zf*L&+(#0291LiwkT_QGw&+X7_7@!A6Zya6zqa9pzb7nxQ!&U-kVSDCNaWNu zv+W$DpB`{pUyGm**lfGfUAr<~pw9Ax{?;~Ul>1*S9dNpP&fX*xS&B`&_@J%7Olh|h?kx|2NIjys%&fvj^0 zG^yo_gN;5Ml3=#LO)crF-j?!mv7pmN83{0R#h0q}M!9K>sKkCqcAyBC*Fo~}K}-m| zE)X6TFVcM6RI~r6yy;Qzk0X0e&N>m7-Vl!c&PT&PqVq*u7G$Dbv1;-Ms)9kPI$f#& zAVF5@rTF(Bs^3pJr1+I&)tblXx>0PUhdK7A=f&SMe1mdozo)+t&3x-E3Kq+%4pL;e zS7sqbnyEQ0Am=U~4xM@tTBIuW4uUOkwPQg0Ont7}eI+b|=&l&ttKjb>w>qJJDF&gF zlP>upMGuzaJ+4?6mT?c38NoQjpD4KX;ZuW|Oi=ZEH)*;$&@f@;F=^$BFq%g{RSM*2 zI2-9cVyYMe+8Jg1viH1gj=fnWnOA)@7Ug`5f^V(%kvZJFmE$SHyuWwW+Q~1{Dfx>V z;n%Ag-mUmco9bH!`L|BVZ{5D~?CyR~2{knl_Yu{?}Jf9S>WlNkB% zq;T%XK*UB;BERg9EqQ^Be$&-&C+ls`BSqDqzZr+HY_V7ix9=8RQt38_7m^D9v?8qU zlKicWe_QW+XOaMwWaLveV#Tj|Z_Iu#jQdRzZn-<_ILCncd>%Ttw6`ICa}(C-L)r^! z+}kKOpJ(jY82-I+8s9Y7*en*{^R>mrBg}w8$$MW6SoPXO&N?~igmIcEVNZJJE2FyUX^{_%Pu zZ3Dvl+77=0|0xFTM~1FPc7G*ww@N@PSxk9|_qVVVdBZ2)3~oFL!QW(5 zM@0`OB=jcWIYNI*%ATIJ{RH*iu2YH!`KwOfP-Dh&jsV%vT^76w|4awQ?As@|?#Ge# zmExL$tiJzw1&VrP7Qx0$Hb0+}&l+qj4wQVP0K6X|LGfAQqrZ5C0>hBDin)`sndG8) zfZxi1bJ)=P>b;E%f9Kb}O_F1?pblTNfNBsX$N$J>F)Hg{_TMaN7I>q_x^&%W2i4uP zn%+M5)!?;jIkW2?tRi5&8pwQjlQrCPjw7IqR)#nuRw*ghcnS&@4y$sC-nNmJg3EU> zwguF6>LeU%g^dPuJuPce5g`)FH_n9To(8N&YHQ06#@QS1cXE|@aX*oN{O9kti|A;^ zi<(FBb;Vxw!`l3HV@do$sY^EyY`y%Cyzz>?DU7`d$p`Uz-&LsxxPpTwU4uw}B_qya zf-bVZ|8Ded^^$GtQvDZs`ul~qC+inLm!qpF>hWP$fhT#j`WMDRx@&JYa37NNlB*}7 zMoPP{^ogg;ulU9VVSlS&@+U3DbU({ra!lI6auuy;hrX%EU zhQIAP?*-)XHoA_gJr@Ax{fqK^+|4}Hhh)21Zgad<>*)&?DKa}IG>J8a{tfW_=PfR| zMH;2fj2EGPQl{O{Rwr3i5E8!dw{j|aPuPz=1^4LG!-YfNxq8GyZ;#VKc=fDd>UGFu z!9J(<6VJF6c0u5enKnYUQnZ{@DoiTAb8I%@e$%Z36$E$UAlM?T%VLUjKQm4?+xNT3 z1KEqfu8bI|Oeck0-`;brtBhXkyo;Uv<6`tl3~9;mn$05NH9P0k<*{wMHM`vdLeG7aN zvh(8)I40sz8}H+K73Qu}#^(Zb?TsS6QC%>su}N3=Re zw1IWlq@2hYna_1`c%^&rNQ=Hi1GTiHB?u*`{xf|Rhfv_O@{WK(9;becASL4)dZBO0 z^nCff_f!JL^BipT>lLaaPca zcpLW5^muLPd+=5v=WLK^#mT|a73X=?)00GmZvu%QLK!Kz`o!%~KDT<* z_pQlCuj4dFB9Coz1zmE;jPvERW+)9yOg~@!`}<+{5Xfb&YD>{|Pm_*Bb3X zz`YBtH-@Lxncm5Na4dMI_*tjT^cVj>@%wMgtvox# zC7u?BF1D(xv4|Un4Hx=%`B_FUvg$-1Kiy1T-B}{-d%n8!anCoP^W(O1%?D*u^{2JV ze+K^nN4}Ho)2fX=bIbX0{6c$+;w(K$>eG0m0skj~7rOf|f){U|gn_la?uO49>i^*) z|LriE75lT{zB40Rc`lI(_5R5^z1(>B25cjDI|X6Ouay>A4EXXozp%N~ElUpMTD5y~ z#ydJ)q19V}FZF&(sX<*jyGWb%m8D19ZPx$%W_75_6a)*Xe^yuTK7LHPIJ&0m0utBz zy0s~j;-wR{GF=#VOWq)kD9ukE1G0qS)8_BkCvtHzfm$5qKIvjM7lj{$qXv5)eia*m zzFRUF$gE545cd5x4pZCY+<;Ti4FOrHf1I?glMWh_hvyU4T|X%8k8~?}Ac~_&i7KZf zA|aO2@sZO75@&*Y_9uLm%=yIjV*_KgX`^_0I2qZ0IMaKV78Gh6^|ay5fsRMARbR)G zI>WnZb#An>JqHx?C(Qkzf*Q^rGv@0rC%w@EFK(yUGw1P1xCn_ER_ob}cJFlP2(tPZ zjtY9_W!lxpAoJnIn0m6zAuz`})26pzgrdlubSwKdqk64@0;+tNwWW;nQlwUSvn}Mt zpT%9t=ugJZ@eL+_a8@<)i*OAFX*0~iw9My|L@fqSm^nQ&C}Xc5VA?^>7(P)lB8a;E zun}$vdrYRidpjQ`UM%&@T2)tc(C~^>3-AANTV%!a$u8m=TUlPwQTX#l?1iU_%J_bG z_BQ1=dPzzv94jMpO#7iA0UBRsZcSOoT6cp>S%s2?l@kRKi_!f3>n5#oo=8ST=6rhykY<$?GTKpt`Y_qnt~`+DM5m z{aafMxs1gOhOLPO^65_Wg~a@W+nKH(+Mo=}E`qs+5Rn~u-r{aWO$m!!YjZvpv-C{@ zrG2Z|V@8o?41;j&C1W?1J|R;a zVtWh(Jg4rK%56As<#%ho_0**-x)vnc_rU~A>nn5rbV|)vnz}psMC|kUd#FR$;4@7~ zwPmlhkJVY3?NTC~)aL6F!hsj2gCBE069HD)7N%d6yKjk#MM_za&HAnvEl-*P|9F}kg^aNk08;TwAN zHhZrcJv$lSjoxi@FMaFEy%4@Z&eTMs+cm2+f;ql`^=#H?^-POW*BL6s#15r;-l95R zR{tY1T{$5qonU#kX?v%apFB)8>ck8fL|W2iC{LJw23S}Xy-j(4_Ue+AK6cJ^R3to zN<-10`cI{_6a#@ zQq41imHV|O2b2s8wyi*{-_#HLJ!!Y#P$oj*8Rge(N zZB02A$wl|^xxJGVt1%n%+mqsebH%4(&e2nSlRN-=j^UeB5QyR)CfVpcJ2jUm#MQ;@ z=tX7?tD1th|4%l2bNXT5M3h0<*Zu}wBh?J-QMq}yVb4|J5V6gFaMFv8Q}Qw5*9n}RwIpL(^Ffiw)Ke~nrD#E4-J-`Xq5If=&W|AoDO&Cbv51!8 zV*#g=UIx^^kU2(!=hn*SC446th;g)*_mR`Jj*P-*X*ByV_VrTt%%NT__j|qqMSdZ8 zrXX62Ae@;e+73;`xow#WO1D2S5<9b=^ea4Klh5pb;Xj_a39lsh4*JAbYgsA3DsJUB znHcYuoTYd~55ylHl(*(Io4&rBAO^f^1N7Y6oWZjerv@Z}k!K|rn0KGcTa z{uJ|ZmAQ%qe(BF2e`p}|cBHW?(2(6mH}GO_+UX7Ls)X{{oU)Vd(5aykX@y*n2KKx0 zRcblpcO_N&;5KFM!QPN|jkvfSy#V8fv1d@STNuE>N!{~OQ{+rW_zaLqKLwSDX4=$+ zrsHV(@hmTCU%trB;n>n~oM)xj`j0eA_3I7rcZPOU6F{I_h+hk;-V%e5aE+sJD@Krs zr4^shv`+qRG1xeeO~;(OZIjuy9oWEhN~w~rO{aYP_au#^6bM!EKe+R&r8*{o zx}QjqZ>-66B)q*1cm2Oups*a!$y%LDv8V{oQI=rAQ|6fDj$^o+o)yJFh<-j03D+r zIcMpLghBa1$E`*J%qB;U@$io*14mbb)GXIjq@kLPMA7wZKes(=e$xw0Gqfc?&sABmVlH=Udq#4LFdhP2;t&k^?mK zjU-Q1XI_J72QS~TBR$1wf66VSUsF8E7h%?^AZrtnw@75Xdpr>Se(%od-gbB!Q*}Z0 z!6aQ#m`WYf(u%UG}lm?&>uUR z5xZO4SICa5H{RU8!ZPKLxK?JxW~pvPN-nHW#juW#ECUY?1R@ZLOM>;?5cBn?t z+O9`z0VyAdxNqc*5@1982m&N#2>KQXU6LhyHHEHsMkO{yz5UI9!bnJ`5tQ_YA`KHA z4T-fN_k8T_SDxazo9s3%;{2(`mo!$S@ay90;yDWnp)Nxv8<+1*6u(_~Dx@jfkgjcj z-g^1TavxYT1}4l3OFpE8y18xF!0OY?Nt%PD$nV}n7fx}A*(N328^hs^q3RR#i~+(i ze4f}E@>c$ixJ`B^8wz*UJEy-Y>s`(Kw8(wIPpY?>)Co*F1SUlnm4~|T6l;8Rfqtl( zq}VZ^o+Y0T{whKdfqR)djCKFU<=m78VZ@r*864Cz6xK@QZbiHCWf+N3@DTZ6;@j%o zP|YYywK&-?mik;11j<+>PbuJ@X9V}sHKPZ~Q;Fo+ak+*hEpXkZoWOE(m5gW}-FZ~R zeV*gwsZTuuplv6HcVIq%C|Ns@Ozn7>9v`jw$4FPU$Zd?h#g0yt7k>2gJ}tH04K2!I zJa;VuM#RFE^w^7#LA#rzs465JHOF0yr_BAxU2H)K_k^=e>aWZQW$rwX*7a<`Qt67a zV_ckF=GeS34?S$o8n^n>YaRxjjWupj5kz8_=egO6AN?!w+N-C8HORH$!K`Q?97mxS zDOFFTsAq=RV}MXJP##C28Ud@sVJI*_W%RmcF~>A6HCn4hM=}EBE-inEOPcmJ~MW|CZJnde{mr%F(qN4PfN%iervOg{ZqGa1 z69fw3PZX&v4HGvOh73e!lPH%F&RoC3)$ka09A)!wJFlDZlxP494JclQk!ykB=pr=$ zZDZ&CvsbLT^88CKF&|3-jM0>dc!78{r82VE?T_xv0CHoJg zGQY>5Dh(UicG!~WFd*A=3&B?q_ox)Vp{h9SLyIVoFp|ujZbkIeY?8jjx6$Q_4F?|X z?g#Z`p18H)%QSG{Ys|z~vft8*ZW?HSJhJAx*17&YCI2$m7JvOodIqUL`V0C^uWbz3 zrp(9icq0A6x2UB6Kpo`u2fQ}fB5R&#qEw=B01gCM)V07DK&Df}6ommOVkml*0p-ec-n&Yv zel}|+$_ClNGw8YcHkdpbppJv^T%%T&?RakPH{!3KRKd0wh%$~M9cPR9#$6Z%s6~cI zyw2wCu*Dg`*04~~+XWwOA-0$gvXsh z=#h|>5|B6m9=q%tvk6(g%kF(mLO?<=SkZG%a&$4(L)#AfWa&H(T0b}6?-J-O5__RZ$~C1fysd60^~q4Yho$nQSJM&Kym={c`|K-+0bB^TBkNFn;8Fd z7*>lL=f%K!$7)-lId=g(&1i4@Xl8T?5Ke>% zlhO7AmWb%c4gkdg8Exfnnsy>pJB~*k1F*i^d?Csz_MVS+T5qX_f*c8{#f08o`)KbP zrGo!hho(d{MirwM9dOaSXkaZ8x^8*z;W$5k{DT<6pYRia9@5hX0Tczmvt8K7%cv@1 zsjz%+b#a}fbQBpQ@huj`9>+JjA)cV;XV_WmsaUz|@Io@#{1MqXWi!6)OXS{l>0>QX zT0Q~heL2yFzuvu}Gnnh03}BCR-;MmNmGf&T+=pW~HZG>gg-CtBoZNrO>tmrQ8g z!vuqLnUM$p68kuA>q|f+Am%lJ`%vJP<-_Y)oc|DkvZQEO&?S9Q z4q@3KvN3>Y)o}oMz9m&OpdCTo{Ew>nq4tZUZ8J8w@TVW2q5 zeW(Fjd$Al~^pg97n;Z~I#oo6PHss*DC&KeXBQ`F?&I(W(Ks-B=lYs$;}LL)U5&t<_+N zWi`W9VzrXq##3>#(nqOzz=~+W!Rl~xWCD}8<&0?Y>CUu$??aZy1Q4k!d9vb_w>b`w zX)BGEq#rua{mCZf^*W9Ne8w--?TpfQEX80(sTMSSwoE)t{@ivNx6cF(v@CL)R;nwY zi9U#5aXvIzXQ4c7fTShKtF7_c;Pj;=GvtZEtCy{{GlDVHC8Q z(ZrPO7%+=~`=yhZ4bXXs_c+>-03cO2Am`!VkZz>91U+$_*%o1eOJ-**tw|>1&r78L z+8k!8`Zcw0985a|PE`HUFO8=@u1}az`PM#$0#ZVW01C|^t6J6V;1i5G4>J+0_O-oW zra+jsg_hpDTy&f+aAZ@LEocPzI@D%lUYG4Q*&G>HaO@`O6`OzLrY`(0*&MdiIs8Ww z%l)lxJjlkDuv?57p4{b($o`bXb&J|1xAsK+1kY$p-IJIpF(j9$sw3J%Mg>051yGof z^(3m(Ng!rbkvaq|fCRke0Hq~bPtTy;{?lCT_`P|73_;Lp+7o}$OD%mP^^98TrO=qM z^mEpqqh$QCo(X_nJ`4sTHFuIBqw%-jUsmmhJBL&|5N&q%pt0?E_;B#s@v{@(A~QgW zm`(9LI`jEuW>fk(6iXH=kJkkfH8%!sx3qvz0I6{(DsJiK@9yyG%?UU6JcT8uB9-lF zvyn@!+aMNiP7|q)7C>h2bLO$t+p~Z$lpdj#gunxt+YwqI<~a;g?{i8&d+F8kvy9*h zVjhJ^RTStgh%;(5Ev!6t-%uoaZQgKkp9Y5s$Hls?#Z-CA;>mHDSzJ6HHbW?Q{JUOH zvYHDfkJFKFaV9a_o~Qw+9{L>o0X*u%5jL#gGP+D;zi?jxZ2TeP$+n3@d{{Egyzva} z#<3aY?Cic76|HG=0M&NA_U^t!FdjrDPEEwn)wXSqWu7)8@r)a}qGaiorj%}~g4K1j zOabj*bW3cIcnk~1X*1}59GzuURNvQt@AS|^Hw@h{gp{B&bTh$uRAcL)eL zq=1050qBqd0@4D~4FXasD9-QC`>u7@UFXwX_pW>Phkf?m&y#Ckt-oE!Lmi-jNgko5%dl}NCpB)!(v=Jyk-R8r)bbO@RmMvL|1 z+9!O1U1NsvNgCLo>_4IY=q9CK=*Y9ay`;Se0L+9$){gCL(@_2<$S8?l9E0_>B7*16 zl5X+#P&9>faRzk&fToy1dvJd@&!59s>}j!inq1GL+#L#A(L_5QVz_vJv=dE!1ZN)@ zc8NPcnAK~j{j!2dV1_`}X0}w|QSduG9ZIt}!#)nn9I^INcwYeA?+J*S(iUxdy|@#k zL!?eM`TR76zF1WbbDa0HaSF`eN_ zl!!(>h-VoMrd-C&HTNl)V(>s-+VlBE%femzEy|zg}E<7C8r_Nc7_te8gu+rIk* z%2SXJGm+|g%{v4P04e*h)6%WGCq~~SSY@N0`GNEIP zj)Dvz*0cd{AC_;gz<2DDE_U@o?`JL!5i$bqmt#eWoOm|6Rgq1m2>Yzb1YKCE6atF54YzTT`34d~Z@+}Y;x#mXDpi3ci2x;=0K)#1 z6bY4GAY~I9-a)cikZtpe`c+1AW_^90D~rNTw8FyURd}1=l4FxXpFro z6EWT~xOG!phx&70Jr+izFwvCs9pu7vdlqIDKAGmLp{9n_5&P5Y93)%8F~AQ~Qs|Sl z$klMmJz{jrc9qu@U;*2pB%f#fVih&KCmphu$eeY>wyqotOUhw%HD6cy%poy8zgD0o ziU9Y#gNTNZiSyrGlvE%QL4>PzZ@_-`#c|>U? zCR*T70#HZg#uU}hfJqRlEU)nB>cc8=W#=B2n_UFgLSvZ!$r?ZZ*dc*L`#^aa^c@<3 zx=AFk*GCp^qD12f0kpi>5UcBR;dB||1okt67TEXjGiO1{T@=Vrb~=MOCsSD3wo}UE zID#e1V@%M2kJ@|iJxdQU+T7k5@L-tC>A4mx<-0@UbA~IU9Z$KRMahG!^rBi^O^GeA zq(}^MVlw#`zq4PM9=P1QYL_z zVq`E9?Trl{^<4_D%wX)b1WNF&Jxp;xLkrW%bi96&i#Vk5^|1z2os;5o|%BH`ETijcR3dij`#l=*HERjVJ`bFtow*LyARu!$LFe zBD^9Wn({K`-~|985fOr>L=yo%6y;*sN5c);JYMthY(kUYIi`?pz8`v$*^ zuG$U>dIS+%3vh>xM#C;iafBdERx^y85Ma&U*9}GX!fKbinsWJHv zW;f>IgqHCKTeMh6zQiewjAFyTdXwo)$IwaY&^9Jkj4bxG`B^=Y)3Pwc& zKAb{gWnt#akB3B3)+;g83@Nv>0^TFSQe;{BE~`A858&D9zSA*s2sC&S3(4`Nv%OiJS03~P%Kpd_^_12;amqt6wA^6{sKI^IQW(}9@eP5qzC)(ASjF;W`u_6 zqhPa5V441uLo=BAC`1aM&34HbyL@{&v?YEzSHNAJv&J z0BXj1eq_Ky0#lDFTLs8I>;$BUPSn@{t1?+mNO1;;PM*O2d7M)&@~HqGly`$cUXvj| z9AK*l3lPE5hv4@N)DjpF69#;BLVh8h(Yb|j02jG`xK!0Z;VdlhX1(=x`k!!ge z0#smTSgkR}<`@{-#ptmm`f;f-hX$QK(nLmymbKnW0uSO7hVC5#Ff)?_Gl2C_HS7;y zgs!{&A`4T)D5%}jQQE|zR+q`S0R1T}wBjNdBEhVX)i0D;XxZLqf?X~MVVs-bDs z-Wui)&8xW&OKG)5jbkjL*{W}kTTtN=V5ee|X5#87s8#D#O@NMSS+!OZNIkAJBmv?m zEH!_8!m(9j7s{O3n%*2I2zvPBA&4I%FN5b`3IHlu(*>%*LVv)6{T#@88yRo1+>j^Z zyqvT;y^WGWvMThlmi`)`lF?a*`kX>p8Fl_liIoV$3a5?kfM8Umthz7^-8V4oea(k5 zJ2zQvHb_8xI@IG(XF)`AT_cf+RFbdDutixiJ>JMjc*@sYME?+A1t3cr41W-EJF{V( z7)U9BOZnX41we_e7oov$yF|Vi9-~-e0eJ*B-)N$kr3bA3UV)Gx0^3~I^bLhQ9j^!Q z&YVKb%&?ETfJ@BnyOA9A6b{ zg>o$e&NJXJ1eDbb_})XSGagMx1Yb*|-8AEOdq*o?4aboE#wS4+h?2?f*Z^p%5H|Ok<<(BWhc`5$CmRs~0Maa} z9K=bV$Ixo~@U7cxWkb#Dow(nq`af+SFWQ*T0pO>`oj_d0eREcjCaWtYJIpBH4m5zO zCY8qM&aVtv3DL%rMD{l!iEWp|$;gK!6eF)>TE&>uJ*KVzZ3RV~!do}r99;!2ie}6n zSBXORK{}U({1v&2jG{w|{xO9jG^I&t_upTN!u>pC;eHBN3~!(7r6?jIEFJorFDk&> z$fufR-&*CJ4*pyg{dJu$^j4JfI~6xuvqH^hYZ%&yDq4+zK9is-k9O$&0YOhuv&}4* zy&e_Jc%Q{FKdA|d>4Vu@y!RXzaX!55L=gVmq(-ze-?S8QglifdXofSWZa@w)Z)%92)lqT4_I6B#JW=lBhF+ChAH2J(KUZ=%VxD$U904 z{?$2&N*nNG5Wqnu0}^Ya8S%_=*Trp}!nwhSE0j8AG> zx(;V)81R+V7R_GBJd%_y+gp};MYEV>jP)~Q=f?7eVtC#o%&#cha z$vDU*w<@Q9%hFK!T#@fAe3ia=_-8nVI^v6Lgw5RO?^geTK*xP+Ji4)Bzno78Xthh? zHLc-8wg&Jw1}-!k!z1vv)Ik-V{MHOY5ggDx*LULXG2hc%LX&8%a-GGuR6N<#JVYnl zDr26j2)kfJhm`ZY0x;nW@0 zc^z>S-}kDv%5%D)e;SL0V$%c)&Rzv_TQ~W%k7B4LF1}R3Y?5+9kJK1AhB%XgzoaVC zw*@tIz(0)jzn)N=&H7h#{E#V+EX=ZN)CqhVzEj4g-#p8q$&xF?&Kb!T-_XGQ%I*gS zBJjLR=OjeVmE$T%u23Wiy02Tvce8dw3M{42)}OAd+M`aP^pL2alhjQerZ1d(Zeaw^m!1yk|G7<+%PsMP^#>Ovz;{MxR49CgL@)QJz00}RbH2-S2u#f-c13Mqw0B{2s$rC-wq-ipVW@n| z?oQ7%NGVW&#|^`7Xs_~BFzRkw&o?W)?J_N2Muc+Zn+IzP!Gl@5+&OTaoKktU?oww9 zu$dCr%xYEe(wXck3U|Yeu82+MZIItARXy`2FnS7J}lNr zCJ%dBM~4oPU5YB-$h~cmI``(dL~LjH{vh)H3CZ>f0u`q>u%*zmR&+dKZCX#_!}u!9 z!C(Ao{5ZlC+V$T{4o(Gz5woN7>aJJMj-WJa&O(w(&JX)!J}S^FfIQ2Ec~62I$1F3q zJ{gapE3Xuy>{06fCOiBcsZOtddGibsq%qUG^e-@1;N@&#L?RDAS29^zPB3C;M{Bt1 z6|D(W`>s`PpT>fU$Mz18E?uY^zDr&5m+#Z(XVMPs?dJ?fiL4U-iy`4_|6;NB)zhP(%=P(HF|g2L53z2tf% zif@&cd=ukn{q!HdP0Nk?SM3q(w|>2vdF|R>$06^Yb7R`+^N@wL;huNB>p*2i$DQA- zuUWx+I}>l{4)I;lG`uY0BIe8`vJ^xH4Irr*O zq+9JDu0KuN?%fB&CeOU7%nJ|ZXQQ^%UY#j9=|^&*+Sb~)PyU&I zPl^8Oro=Ox!X-+dpF%7R>w=Sfg2!k`-iyR^AuJySB*5<*c6FindQcRU`a_4Ef>FvI z=m_$p^A=YG9NdMDq->=InH<_~KN(k(G1i36;b+GlR;!tTaoJ7x@e&VoK58 zFS%SQtEJiB%<#Xe!6SV?=Qb5o)v0V%M;J;u<^+z^Hga9bV#WXI5|KC86>71vG}XRh zZ7tP=APDQ-?be(w!b)9P3i@lTuwv7e+$#SBc|fh?Q=5HbF)H$9%xU00mZ!d9Gk;RdJh@Y=AnteB<4gN!c-VH< z;(N=DGv- zjJ0}wU!pT@rKPg5a`K&2a>&)SmXP!$mZTEK=i5*oz=}vd^hd6sGywL0%SwahBc^UL`7gxo3Zl%4 zAW!`&8UFLOVR-IbMWAagXCt(dWTr97&*;=VXNAtduGNc+oPd1IMUx*5V1=s1|z@O@Io5g?d>+~qZ+Jk&N+O!+=!Vt%oa zUeQj!o9S^^{sCG{Rj8*nf$$p2!z-3Fo;&%3AUZ(P_d^sV!QJ*ok}RaH@(+ z`4#is%hfFO8pbkh=9}{T$s7k(K3$g{P9?Y|@Gf>LJd7$!6&(qPA|ve@U#b_5M(~`< zM1orI*9k>YX_Ozn^D%2=SX~fCcQ|))R zpfIFN-ehvDx5TF5^Bb+|f}wGkq&tXNUHj_I@toj*q`P2dtCKG?M&T`uvowBx@`&NT zEGc0N)_$ymqcOstW1c+Xe1o|%yOGr^?VLW%{=JKtJ)<`<0O!Yfw90(k{5kD+_0Ih% zp%;&a5!V)bZ#=enUnJ*=t9-M-!%+5{sH4%SwO@{k(K;c-RQRB3NvG30eKl2Sltt<9f)gPN#mq-m}`ecxd;XNe633oJiWD#5u>WtGO! z*hHW#^C}!x$R+(r#i44_?OjG!^_j6{)ZivZHv^0R&wcS1;7cjhRabu2+5YGT5qyF& z=K!u#=?(jEjqQo6_(Zir6W{P1q8f*iQTmm4c_seeSKs)U59X)4)M!f$X0w(&l$MEV zdOmfL$UZ|)7t;SV^q{{k^xgOCk4?V5Ul!mE?#*iZzS0v;9CeJQ7EezcBg+Z4-ebrWw9mL@5g%?zc@r{) z6~1zGKi}rFr5Rb=hnnH4C>Gah9)mKzUKpRx9!A^L>So7YqFp9l#-!tWgL&Pex>jKZd&2Q1VcoYE9H={?C-m~Xqd#!DZ_fRHs9UHe57f6VQ<|$th&3f}h_RX?; zYr$O=!=ObLd!2aQ=ph&Bu1It0%-{(1kc-qOk{@_*B~(tZ{GDD1h2HsO^R-)VBTg>G zar!pM(BJ!FWfGe~xi6GD<|J}Ou5;rd-}G)5A1I(IC{ORDC2?!uBeV;k={Zcp9;C;i zAoF9v{C`1D-{p)0-@PkJu*1eNz4*px^Y-{SqcSQigp`f_DjN9NBEQWQV@q0tCq=2|{wJnpQX_srUu zH@d&5;*>60Fca9c~=VvliHBi8#+KyuCq`yZU)D{b}eRI1ZIhrzu zC978cvJ#V4%j$z;sZpCJ(uCxOyAj(AJ1YhZ)Pr2qeKb1wBs=uk)zL!4+2C4S`U$0CC+#Fx_a&% zn3I9OD*d+@dxHz4UQDC@o1+}myT zX7H9m=<^7%`Zx0gn*N3oiNrVk;w+u zWECw_yl*yn%_h#vrmB&e)KBVu>pgp1#fsJZ^dBMh;fnkzo5E$nqHfsiq#tpf&o71n z|GN2F><`ZZNkM2=H=HY(;F>!Yz!S-&M+bVrtRH(U`@ZzKUMV9o<6VErx8?)|RpW08 z$?JLv&3a@xRl#!xjQM+^hb=;ZXykh#aN`w8yN_9qTa?%`U2ZCt+k#)raFij7U2Y-@ zs1u0y@`W%7FMJR$w&T&jVCh?m7Z}M>YQBfL;WcS|?X#6~5DiL&m)y5m`YB(wJ+JfM z<XO$8=*ZilU+YA{g+PXmUimOpMR#C#Pcn7$VZg^dgtpl9Kc+ z|LT$7>+#L%8AAq2ns}9=`bqN&XjBFV1tQoMoL4oFqmU0*mB8(l=W!8FlUjb-tI7mm zWb`0%IAM^QB8rMq2sK!QP%sy+w`_0(Qhnws>(_-l0upZ& z2qE#xpnrVZ8$JEK&bn0eRg4`C_{1!rPAGttK@)5#G`uQ z**M9#FS*zXa%O%lhy>J7SQuB(S5v^6(f9kc^7SP5)mr(?V!f&j4AS{nu5$C_CRS>*%iBS5DC=pr?3ZE6os+x04@e~xU&xBGJ%;+V_}j5KI(5YhbZ0O+-DO|9`#1L zaMMT+unYmH<(YjWr#6rn^%ij#JQ>g+1n6Uj;R7kLQyNd`iEPDVxF zMnbE!CGTgJ{@*6{n7A)(8WkP8@%Kd)4K6;a%3`k;Q*;hebd0}31Dt%=%$hNY2f5*7 z4q|xQ0H?Qe>G(IQ2?+tih6G;&+Ky%Ow<;o|V1ldLG>O^Xnop^-9{~hJgj9liTP`UG zVDW%?@p^E7^!%q}`%mTIeqZ}fh4T;M=7&4x2g2+Jd*_FS=Px_`@BrMK7(Q*iFzM!i z*K?Q(bKoGtXL}dEW-rWkEL<+WO)X6QT$n5m=VpUhpkNjN%pC7%ZtG}f>$nMnnT9xS zWjmS%IPSJAZf`j5IXLe1I$DqxH=`XlxuZY#+Mil4ohHwV+Aa+`EPcMebavl9Bo6$L zEmo8*HZTqG&jI|N${5c4roY+ZjWrfDp@Vi6J=85CqNd8@< zwj-Q;DXk6k4IS6Kg3awN?xb#R0)QrfLk-5?t~4E=_@hY zajn!rcbEZy0MvUX_H8FEdZvtQryh8w!gtbzy)sw`Ni2k{YdfiqURi!#K!{hOA|bV6 z=b7V9?zCst2haT0?c6@EBKR(mWw)4iCxv#WfW@mwdbf<0P)h3sB6(IWdJ%u^6kgjY zt?)`(+^#+Fs^kGTV_7bDI|L0qC)^=a;UOy?eIA?F5!l#(LGuXE`G`&|e zvRCcCGkmb~8NNRzyg#nEKcTZfY2!Pk2teyy(0d7v1f#aX{khit>TN1g*xtgXZ+GQ3 zk;S)&)^C`{Z^Y4e!p5t5dS|U-Z`IvzDEMG&aqmT|*XA#uoxX$7U|%PI&S@F;<1#R; z&0GQh09V>g)Q^PfJ}0wLuk`&(Lxn4`&~b)u;b8x--`?=qe%XlMs)^Tf&fez_ek(CM zUq1NM9Q`}LzVoBq{%>2kx#3lUxA<3ZqeaJomX~__glCxLS|>E?)w+V06L|> zmm}Vdecm8tfTLgZj=foci~rGw1V^*cWS1X@eMg6i{CVheV*8CY@R-FM<&w<&nt&2XA^>r>!wS`dcm&RbpVwfKrOm;_u3YG^d#WG9h>^o z*YT$c!oz1|{SMjP{p#XR5BIIhyUXVNhvfU}ty`~0wxLAOEcw878}_4)w&`tPOYSf4 z_QKzFqMW=w8;5@GvHoaY>LAYJK)QMUSYRW1@!pLG_jP~YfAC=2_d&?h2OBiep(3yi zA()7#gSTkRlOGSBZ2fjYhIk`G!hb&?{Qmt^Cd3~d5~&mtrF-V$xxf(@YhHiG6az{8 za>lfImiz;sj5tsJa+dt@OnLc?R`_8i?|I^XAzRtML!Lf-h={h(d+_+dgL|ocGVvzu)Cbq2Gi;E1rgOD2LAahClRlPW>2?qI6#O z1E1~hocVj1Y`z`JN)FBX@h8dOxl!a%%hJ3^@G4gw`0bY!w9V=}#41+|qMgpABlWK+ z?W*V#mrwUE!;j$h)ZYoE?0y~Yq2&J?{^>W5&%m?bpLIvofd3zNk)W-|ani>~0EPvk zaOi*IB4Jo0bb|HYIPX84=fAJl!=_Wi#(4kD@kW_$L(R9tUD#rrJ>kv(d5IUkECLVO z{^tigS>}D>jE?d1j9K{+wi)}xIfT6J@x+-xcHWNJ{_$_|H=H*Pf&n1%$VjFKklr*x3tN>5Lhz-OjUuy>m znRpc`MCpB5sqRgRP_;JFOD`efkS9KZQxUce_|D6*{GG;)!5lea56Xh14L#lS0z1T2TwFa=YUN5$K>vvjGx2C>xs$5SI z^?KIRpWdRI!X$g#id<~h&RV{*`c;qqy}`_{D_yKVmOn<$iXYwT#Q^{SH6xBCvc7i8 zlWB6Dm0*AE_%Sqav&K$-bF#|3)I=(@>Gf!y6C3H}55o;&;cA*;U-h#~c2o zGDf!YLBqLIFHB8xAOF76G#mynoV~yx{p8V4DHI{e;axrx$#g*k**-QG9~?Y}+m8>< z?&2A@66ccC0E^-C_T-PhMF921iKHCyvx@o!ma?ntBF%Z`Kw!OKEO_U3+GFG@H?M}U z%6gji@z`4M^=lNaJcV)N8nPqMrXjfzYWXCCo3y3nInLG1NyhjhFUvgFxhQvx+g#bW z{4G_@A?lNRN6xJL2}jYa_HlfbFQOQ3Zoi035UnJ-#hpdJ5Y`FxjIj?Gi)Jw!%I>k( z>X{OAHlSviaVcS0*>QY4tbGH27pAjYts62Y#$c|7;s%&UM=jhN&dIB@ZtWNOcJ42e zh4VcdC~oa}4htJf8dkAKvSVZb{PVlB-fdEE7DE3@yxqUq;;2!ItPa54*bC$J(4KihDL7Mh0lIo2{vB$(wb4OFKTj10xRDi}@OUoi!L zmFw*JJT2AV8O`nx<-B9#MsW6GyA_DLy=3pBUAp|pQs|5=ha5yNYUhHvf42PSW1tSh zK6SBoO(>|36(2S=RlOC<4Vu}!|8GOw;U2s5oqJhhW=5W4E){u=pW0cZyx)9=*ZO>1 zrIl*@Ao@44WhUW~+VOzIN41mT6Zg7%#2yL%_DHLz9q*?;w}t(hzY*5)>l>X5k{2+H zbCQSgKRya$Q!+9N-(`#o`1|v2O+5xl$M|2^>0Ntg8(Wr~*UdxPa`LmoF2DF86*X>3 zkLIIEKu&#{GZmL?zGekWMk3OepQk5IkGcd`>U9`NLotwA^E+Nby;OJrdkZtE__A=Q zEXJOS)97tq;_KSvI}+@aGVZ8YjPe1E+jf`5V7;;sk2F~_;cCHhWl2w^UZ7;^UjyQY zE~R#Jn2tX|gMQw*y1l*{6MJs&d~J(WA;>$qP;-s*NbbF;GFlZ*B+wG*+nfjdf?qx~ zZiwrxx!$UySVU3QjG3UiGYe5#58@FN5F609I1WjTD!Qa;7XD-^aU#4O$(Un~Gk?;U z^+K!XEcaPtW;e#q{yAzzh4uOMO$6=^wv5L&vVz+@pBYZgDL* z?ZZm3r)_4j7^pG3vAnzd?x;eZ*f3SYw&v{sEA~D-+yuR^t1GdUnibqEu+Uk6#BGhu zi760O_H~(7G_R(!2;QgAV3H5fDfG!mVims4PHwmDn~pf5R_Hi1@^q=3M!iqEY^f`@ zulB^fVM+?W*3E|OolsL~W|k#wQzh?qEi%1fGOV?daM_MvK-?eih!+jK?35}k>aUck z+&~x{PC73$NZ3^wSm`iN*(Xt2nbJFBjE$?!Ph7;`*GsEr+ZoF}S$Q=zPy3*Ab;w<7 zqGqO{!j|AOEK_a$+@P_g)-O!L{?T1Jdk`AD15Uladu7nv(c^W6Bvj&v($=ErST*`= zOq2>|aKHAY`d>zr{I618K)dxBSioH#Zexe{4sJRbs3D1eqgESOc|OLaY1`#BcSq-L z{>v~a#Rf0A?DT%~ly4E(L%iVK>cpZ8GWA>rs_`4GO|AC_shih+5WZZUcjlAu38#D4 zQ!XW?DT=J!zQ?L+wqwF%Oi?>9%@TTPTw-kt_~Ti$h>3X#6*o`Rv?^;Siqik|GMCGi zDRnep)~2X7J+6IS@}5{_U7U^#DzJWeCMVvC0#ybXRoB@3v@HMNo%E_L+tpq--|>=! z+7(KJMo>&Qa!}cI?pk|>(m!{!`hGJoOg8DZMNbs z50ZnT4`!F1{fhl~D$9P|#IKPA?jsI?;|7gKd@xl*)E7p2aR$v}NnPNW*;XTe$>-^d zW>*DR`B3hDbwnGUH!u_IdSSaYnN>flVx$!I##{H!T$^gH;L5Mr!W)#gsBVw95Q2S6 zWt^K!94ubOjO>hw4^$f`fyR}ny~`tR*|WT|$nJJCr#_~E7^S~;y71HfQ0G{(92e4) z9gLIG<1RF(DUIR_pp>n;Wwh(qTkYINdGC?eE=ME>4BlKP*ZBt~r_)q}zt5)l{G9uT z$;H*%EyC=BHwA&cqki_xw)xF#5B$7+zV7W@iH_ZOoSL@m2&Dl#ovjwNJBj&cGDTv! z5|^?;AJ8CX(J+%ur%r_HVT8oc@~vMuE`|pJEN()Yg3symXxL(&2hNAnE69)J=*tD< zgj2sWMvfb7k5uVH1%KRAAya7Ec0Fsm>-EnESLm&gWbg$OtK!4?MZ&k6ozkIHD)$p- zYrS_a!&u<{!jA>677L-Sdx3_6C9jGkQB(?!a=u?@>FeItm?pY zZ^l6j-q`Vj#lZJw47Wd(S<^RS+ungdRkKgk3_OwPnUo5zJNOAtf+lUst?HIcv zV!}`B5U0tPA?#y*deePc@9Z|byC*NG^zodX!@ioH|1A6b-Oan69oBP$*%I3&`aAE$ zb~1F9vNCs9wMr2*eGkap|BW6}35j?Zc%E-HQ>TUUX~wBCDLV~1U0?Y+8P`}_#XUwG z%_75y#Qv{__rvX}r%=t^Y|PKOsvI1$(&x(6OGls>!5G)cImu!AfKc^I;?N}cIkORJipCc z$k@_<_`N5mNiU2A`9oARsfJ1O7c?faBMef#tb~ah_d3gS z$sC5~g4Koj<@at*{-j`Rn0)Eh&uVS*ip{pJH$5WHz>2?*t%IArAsWV$&0y6D(Sjpx z>NFfKG!w0tz2H>A@B_9)v~yp*{d2p61=&L|rrCDwN~yzQIrSXc&&ct^_P0=XVvYH;a6@W)_B5=Z6>ivu@0k$*a)YMY&iKUM`a{wAS;+ zM5sw=NH`ZZoSr)ToBD?1RA-|aRD5)qitlD(ujJ5_?S>SAX#yKNyF0Nx|T|mEmY!KGoHcj!_x4 zZWE&$=l>$|0|r7=BIPHez6|g_hj!n8g0zd9o5T$or`%jZ5z9&839I$eC(yoT%v|&lm`H0xn-Gx z!xPD&c`&LY;8s~r`~98q;;F5Gi!t4mRl_r*FCCcpi8G}5K;kIZO;>Je_uVg#sHwxT z{g2m8!r*k&H z!zeub)6LX-xzZ%HhVG;EL!!o(EuYsh^4RO=Hup4->Kk6{JU5%0UEVQWAHAplGRIYC zlwIUcxRtWl2*@V-1xEYP&w-cey{xYNPvZM;pkc)|9P4;;p`~)l(=hX>;RMNDm_b_Ht9MtMu}5h)jxW62{&u^a{E>~#of`}Q-d2+ zNNhdBtGPNU`>I>-&FHpQZc$Ri|Kxh5H|e|3XYuhg+r?%vbiUvTlUJAzM1>k6OAXmI zPI>}mlow@pEB~U%X0)#1?jHT!-OpV%B#$*eiTz?NadHW8Dc(vb_~2;o#ju{3h1>Ej zzQ!WRGR~e?w4=RVjGMIMJ?_M1fpv~Ek=d3MEtdImtQ0M=n#}%&_Ev$bTH3t>y2oAe zcn;2G?ZnRrfTn$Hz-*8x+1|pxG$q5-cXOrL#Cx>lbbnLn%#p@WuVCW%oK+ z_hGwxuxbV!=m+gNm<~ga%NE8vJ79S(WH<30&PS&t%qSv7 z19^25q3XgeS7^#W7VW$E=1yzx5j3l4&lk_N6mPbAXC+7BU-E8>ou{ygji`B+ckdE@ zA~Bbm-E(Ci0Lq)W2xwg;+sY)w3hcc7EfO=7;}flWIl=* zb8%g6NO#!UdmW}@`&4);vT&?Eeo*vV$tw?8G-Q^;GkhA5(ejNew}v(KKv}6I z|E5QZGt@`a%kthm_VIk*Y%(9G^^%FMDft zndPO!r4@W2X&K#5NxJ`4%FCl5vI?`Euq2YTo{v=8VIFcJD!Q$LJs~P{AU?A#Cj3WU z9DBPFvlH?ldG<;m4(1C&z+R?_e#PNmjP)c24pl9NEQo@u;pgS3mLHIGMTaru1F>r z;|xr!<-Uwdem#!|$C!`i44V2HY@w#=dMWAApqKXdEr+=!z?{}o=@S((jc4hyR#J)F zMVGsynN8FF30xA- zpOOPSdxnpEUUe2XxynJJqLQR3BIV=mbTJjIkP)k0u~%umt}5oKzc%tL+RXKx9}H-S zQ-EESyg3eOb~rChaOKP2WTM%3N*}I#g=iYGh7;a@|wuKw5X^6Yp0-{ z6@NRL9ImXt=LKf{`UT{Eiany1F&n@B!932Frr<4wK%JHxfoYhZxIF5!gr+x1(6gNk zHh}idrowt}sNAMJ=1t26_^Y^_YqtGC%G6-_41cB1s2hGsIYs1COa%C+ z4_GuU;&dpnW8kw$6j&@uLv+uOkGd;0Ga@sxOKyo%l1BeSvcLt=k$g{6*5^E@`{Zfa zm!1F>nn|qep6QCBW-oQOe3nXQ@AlR4yIqrx1+X;swEst>lR($Ig-7P!F)ynSmy&Iw zItxGHiUeMeSsHV;T;jX~<6y&<{?fxDgs#-5U|mtx1)H9-L~!{d4c_Ak5hGR65VK!X z!rDpAf1~&00SL_~aE0WJv4``nY0-?5?7^C{r(L|)A+pV?H7pR>d+|B0R`=brj#(i5 zx(V^9_bXN2O7uzoWCKWyGUg?zn~9{!WQAjD z=Z7~MFbLw9dLA*Ug)m$)(fhBewYP;|D!R%CIq47UtfcB%RcY3{YE$7g`Q@+v{%J^p zcQRf;n{02b?S8G(Ia*il^H2+TyN`}iMM{z`!4=$(Bhr54{yZeXQP}yMH8SH`=xyK6$U}lMD%dh!sQAs7D`(5Y-@(mo8rbS7Rx5hy_Vv3)%MykLr42 zmZq6BY2pAFngE*tFf%(cA?xy$B$ycqr2OwY;4KqJhMEy5+i7Kej17Hm7%)yg$GVj1 z{hg5kAPOKZ+f}Ao^~?qZ`3@n91&G-0udkg*-lHho z3IO9IJz?JKP5dg&$tr9_M1$cykxbNRWt0U}D}gEeNWA}!i<~RdqYeOX`r<>_mB7u( zcbOihFRq8fnN_nq%}aIDg{|Lbd0CeH0<@AjRwhJDIgy0rF#@(i?J@WWq_EAH3Z@Ss z#9;ufN*obR+>lkuL|=0O!8n*azbvQ|fFrT88&;{#Lnr|rn>{d?S)AkJjPT_Fsq?ou z+>@FJFpPacl1e~lPXh#%Yo+;SV`qEkYYtiS)-OJUkuS!rCn`L$MKcZ#s*9>}aHoET zxvMd>Gg_uepeY^9YG@?j5Z^hvm}KrgGI}6~e;Hn z3V1H1q6H2L6(wxv(bJJo0?eMdquox}f>Cz%Q@Kmyt}*VTrzU&-N;fXo?xX34c~@ zM5KgW2$8^(p}ZQ$pP{EgK@L%4BS2VemoFPm67bF-8dMkoU?~$_Me<+tOny;L+*U|H zlriAZPD#!bxqVtFJ~^k*oekF8N$2HFR;FBWtat)05Jn%oQ2xxq^iMQ@B;EjC&Pq-C zROOcEJ3Z@BoNP1a^(?|b9H{&wm4#HT)3^W5{f}znW@ci?072-9>!6bS0T$5_ppyh>(+kc z$Np@^O;NTL5HM1%V?%G|eT(jNPil|nBn(pX_k zvNU8R^680%%G#bYz*17#6%XUdT}28cn3Zsc6gYLpi&kLyFZgq9!H+`%gdD?u2ECfxu>-O0s+)ocmjcHbQw)Ln|d7*e%)f_2Wy>% z4jJYz#OP+87|DIQjKHyJ(EsYWX%Tos^ct36`u5T}fq(w6M26n#T_dMO)!E|x|whaEaeU>k~KQ_0dxau@V*zA_Wjqu3ZR z;aYQLJ=aLSe}%){UigY=rsiZ1Nlreh*i2`_7?GinFxL~9a+f+%n57<2k14*#r_90C zMUX$N{~twX;n&pLhv99&sL{2J8r?9uag5R3Au$^15-D|zPALHi9Vy*i(%m6Q_@hJ= z0~Hlf=ga#ioaghLbH2~#x$o-=goJq5M-Fx*N`zOSg2qXNQAiw6+9%*Cl=S}91*MrB z4*33>R0Q4%G^>3sN_{Z;L5;Ggo+ZWQ9WViZfuQ1Mb`N9nJp%e%WMJu!G4gskNYGn| zcWeq)jvhxrOao>xNoPZEsu@%XlZG(kGq#DdNrf=E_$X2-BZqo-=*lY&0ZM)2(QjzB zUO+O6Hq;PS^ki|2IZ3iA)yQ?k7&=3_!aaLPUijXsObLY(#!69f2?Ln+%oBKoH7WnE z9Y6Y#^;!F-a8FogOk2s)6xg8D$zG>Z@f5jH2~g?U%BneS)<_3xU1##R-a6Bl@_EHL4QfQ5?OVSBMA2xNuTIweqk(Z7_o5 zET2_njf_Czii~GDr3Y~MBY>nUxZDv-@F6a%vnz@}l3!n+^f5IvgAYI$JW8&4fdzaS z)w=Hhl``=dOZ-wt6=TrX-M#-NkNPV-dWnyM{7Wc|vpzeiwk?DGT@V>he@?5)^945q zwQFX%rgRbz^4Fa6ds`!U4 zQZNR0A+FlNOCXb%#*M|^>Ytx1-+xVM)21y&Q5!0So59?^6~Z>;Bi{@>itC4V#?dcS z1NWkBd6x2|M)Li{v9R>`{?+1H@gxx2xRIjA0Td32=a|5LXB9yLfd~}oYhkdLZ#IB^ z1w{tR2I4fwUoGPoI?6M(?s4cRnIj3n%3wyGW3psv=AT{rFzxbYg04~|0zl>ic$}n0 zb(qo&@yC0tja+cb3bWDwWe_0cMYX6=pqVzC=3-xi2t)t?1+caAmJ~RLqrHS8pa|c&qqe0`a<` z7kJnjY4t{kEA{{B2M)jagcC)K2kb{!Hb|@A%N^>GrND}}J=BgpmCpWL;^BlFW0c48 z99<+pjntErTdjraNqeZH&?bn684#`0`;;-al~f2SN`W!?rh#@?_z ztN^wQTmMn0ftXS{-&>I*9A&Cz8xmJ`_?vwZZE4o^E(pK)2ihI3t zly2Ap)?qKjl^N$TvJ}`82M|8+u^H3k)h6#7JXTHN%bIcbZ8j{>IQ(WKl26-oN$T3T z7Js0CmE=E2B#l$I5@DY3W4a>T0vys-ofmkd`ch2RAcw0j~(8Ois!s=0#Q zA%iHd3~)9pAZM-0D1oSJwD5UiZZXn%!Bl**x|W0xRfpAn%9-Mv94)mickxT~B0iUkcgndi?+Ej*FORl&{8 zAFD-SNTy&S|B^zX+x5@VjC||?&7Zoxse?zwD_)rA;SSVlE2)qS?=kEYlYyV2kC=~+ zD?kC&Ma-5^TWM0Ns8RE;+kfr00uR0%Y`7&8OajL-*C#nWZ4d_&0u(d{H8e>-1CU3j z0fSR0Xkba}D#(Ht>NW;&JSfSyC=m<-;pxK!AAvBu3%G3XXF=H0QD~qCbVLLijiEee zpe-^sI+~>d6DGQ`kbrY)J#w$eEaSmkY8~LCW)xLfR^(LhGk~b^>jQ|Awn@Rr`wA4L zgYUW82wk23M=*k`^LaVN2<1t_Tm|++G=d6~M)3eac_2AuB}&DC0<>m;LJw^pj6Re^ zk>f?df=dWN^u#|@71OvdxOwwZrYan%j@cW`<8&!OS|8vOjvFJROxs_MR z*^k-l?Z1hGagAj!z4IJ|{+&P)qLOBy$2(Cd&iM+#d?Ug-szhPvnA`Ep8rjSm2*Bx^ zZ*n|LYCNO>97dCp4wGHLc!Jt!AWJJhLZ8@3BD9~D7t>FJt&o_=J1^j93L2x4o3Ptu zGE01Dp|T;T4MqV&Y4zqZ??w>g0nLcW2bjq218V+8 zjW{sDB%?HeTrrsB=~@CoNg$>MASqH$QTm*`23K97J9AXdnS!9Q!vb!obb_K(jP+y{ z2(uH5IjWHN8y9o$m*zFb9_&FvoDrY7^aLL8fPZAgnRT#ntioh!84aa*v7oP3M|Olc zLAP(#uJSgOWGn5HiD%W&9CMAY=-X5PQoV91J)lz{lgnHpiLT7$T(#7SU*i-NJ<*N6 zBCkWdGL;eFKEngu2-!3NOAnv9^4Cb$mV<8&n=>rHD`Nm70%|wju`wef=+2HG)$h1a zSo>UxNp5NnfK>4L8qHHtU`bX)uwf0|pdSV+BKt&V!`xCG&F2BRwNriuKvD`UYGD$y zTO+C=;-|z+kADo%i(>|jNK+$FfCF)r!)A*$&E?8KF8(*!b*c2Ic}&%o4+4f2fJIV5 zu>@J4gA#uav|DSi&Bz7m^a#FOrK@)JMR9`GYa8f6V2HUmLf0nk_SeV|5=(xNhF zBYY@&8@*s6dE6X)UhoNm1Jwed28rN5Vgk%)02X2O5cmZ$Wl>0FBh2gSj0M>Mf;och zOz_qj+9LphyyxA!_C0r>xv>VB6K?|uw=t=&G~(!GH0jdhv-RTW4S>w7xCV5KD26hU z4afE*kM0Mm<$6vTSdJW)l56i^>G@hJ`*WKlv0klN>Dw2-eLb*XM5C;FcT)AF9DN$`$xik zXMA+8YnTE*DQb-}`Tu0PJaCI+17XTV0q^=yagwLJBme?sB!T$~;mN?Cs2_ZYy$t;7 z_0>wEm=OnZenaL<(26bxyU~D&>AWfBVU_P-;bwwSz!$MHn2ZabaS=-Pcdr7QNi-Iy ziWcuR1J088pB57U!9+mh16?r&%Db$Do9vnYyi8>NC*yLQN$yBh!3{@}AbF_CRjW() z1V?$`N|}K*W09vi;K@EX4CI_6sRzWWytin5OK&@8vEa=>KIXOGs3)f5YEgA_4AgS) z^k%>X<1~360Ks3IgCZh8Zm9W49ve}gIt5v)oJ1CJwvs6}}bK7^|>e zL{bI<6rglf=dRXDiJN}le3_u&Y-z~B%?9IlMiogO00hD8GyoDC6xoAo9^oSp(t}43 z1x~m)$!I;v4M+PIKpha2yZl*^&(&29^nA#36n5^}k#|v{m_`&-6bLGf?m#g12EFT- z>}|YLWjJdlLG4SCkx>CCBvC_IL?1j7@T6)N3Zh9QyX+&+z*2#&ryUMj?QxW(Z|^@#3yI{sSRe%fIPqR73QLj_1LQ?8nFLAw;7u6; zNhJwORph}M>HhSWgKK{Q#7DrsC}=Akkc#@Y2m(ltb$wu5Itxs1-38N+fJKklOUgN4 z^>p;d-C-9Af0{r&gJM#_^}=xE;CB_H!H_@Sl?%L-s@!Q)e!Cn3RP4ZiId*ze`1bkh zG~a5aVDx)pUiE9liRna(Q4pNMnMi+DBvN3RSTXb#GMdfQnsx<4`0^4orWoa>WpM<< zwL|TAfe-{g936){OwPPUD`AT8aaMi$vrfHJg=)}fELW8o#G68oA+>`c!_QtW1i;^EJWK zpKlB!G{&H>6zbK!yl;A^XI8jUq&Rp5wlhCn=;}sM>js!E4EA(86-SpI z!U`PjxJ2p}x9{a&_Id9^ukxNnvv1WbsYD2~}J5 zfhOH3x%5vpvv%+0&yiF$Bb+;~6c^j?e{Ih#WKqD&D6TzB{$VW0MnIuFFNMZBeoxto zQrOCM1VhMe!7a}b&-v7jWTWa4vE_(_L@P(tZa>g+@X!}d7X|NCC%j$@m2pep=Su~N z{vWuOuSa>M)=}R)8|5U{(Je3_33D`-s1kpOG|(9w;(@kOzSq zO5}w^DBY*^_1kN8zAQc0qb^Bv3CVV*@s@)rvjv53e%wg zw<=-!HkYLWiLfa#`_>d%PRU*9hvST>ps8Sy@x=KeX|KUp z5k5gr11Z~)Vf}s@Ftf0;Q)VN3r+n@4fOrWN))H(asQcom{p1!>dle-Qi5t zo=^LOF~5m4YP}bS6Y1>#0$PxV6y*S#XpI?V0y-A(5lEUs_YAex5cY^mZ-56C2V&uU z#2I_}@y&C0a{hX9>CnX_8h1heU4=i3#gy|eGLb(vb!n9sR>&70?r!%G@Sq>MF1UY` z>lq1DHfJOpZaAP0l;enW3VJ)dcAeED@{9-S=r4W5>Y2a*hB?lp@FojqYED5FQ`-`u z9>GdFDH>_pln6WpF_%0-_b9|e1iv?$j4&6BIzi}iMNL26`7(NfxGnnY^9TbS zVu>Sl!2XJU%%Fn^A#ECoPAp(FS28OCGW)!=_oy*ec;z!Z^UBcc@%J@*ni;6Ok<6At z#EMT2&qR7@M$-=vpoNn>Xz=TjVbIWz*Xf^wXGPe6!b>^791&Xqy00U4hNjEH4>(Ja z(cAagILDlc4ltJo%-7QpxgF>>M0S^coJN{D*Zn^nIZ-zYKdz_r70E<3Zj?xL8Z>_R z?-xQho3keJ___MN+)=Vv-2_htNAcBRGFNfi;i?#!y-v1Ff#wuz84@P=1c!VgP_PNi zO@3^{Rk#1x>~vH&cT@d|Q-O{~>U2!#vsY;8!4L0NN;#GDAtj7o7Sm-XAob6mMhTv* zK4rD;RMh3+foDj|Um@vCO|*;iErKD57RI7AqEqZOUR)y2>&KWyEb0t5C+l1@cyz2= zf5@}ix#x7*GDeBCZCUr@wO`u0c4-%U8m@TE(r#-lZRdIeV-4^+*XV9?-!x#|@rmFL zTaY5o{^50Se*(;N@F=){%R#DXXux#%(+j$Xf4(l8-U|55`Z6ejEUZUhbo=9I@;OQf zyCuo9UN*$1uf3)tEv@-+)CZiA47;>@R9=0Zd)5*bMvcPMIl1wP6lpUNwUNn z$&)S=^i|{6tm7dqGG^AgaRxtkeE&_J_h>pc|C`#~C_31S6-c*-Nb#!Gc}$m8raR); zaL&iDu-e|pTjN`L#9`%w1^*h^XOzZXuOA_4F18BmE6XmFgxp@mnIN8iYYn2UP}{l# zRVZ738lVF)7K;ai6;rsWhQ8rhFQL+coiw3J?g^JqUd>^Dv_C1kxV0DwUW&cqW6-9G zxCPQehjr$bM%I>df*2nqTy`R=^#ov>uk>eHF`5$rer87%xdx)zt*$}_cIR$;&7|wS z(v)!8_T6y?03Jx@(MvKaNZj!!TUWm=D*fV3G@LC&;?Fp!~MgNKDT_+sc<_gcUKlE72$-cS;Fs^EOI+-8Q zCgyY)&DuG*7PVr?CY5atb78iWe_{5)?LkO}bGWJFi8}-t6W8ofH81l>o=qxk_9hk} zTU;g4bjLJ(XUB*Mu<+`?sJU^j#A@B{rB#y&R^gs_CvqGFvy3=eZ~KeQema(YKqdw? zeZ-zjtxu2#ugc_R#pGtr&72^F@ww+~2# zET~e%H}j25~B|fyFLf<&sjd9KXyd7Jj=hSrmt9MQ)~ig~;MO)P`N9ax^} zhHqnMt+x7jvDCr=I>}4k&HY=gb7Sj?y~ zO<}J@g(8Y_B4npPE&iQww)SGYuJSt$Yn?8h$I!&r306)_Wn_zaivHOIH7dLL`M zdpgbO%asT8Exe#3UTB4N(fF8*y7|4mxF~f!ls*{WUgtXF5ML&{q>YU=%fNk|Ub`L@ zsb#g#mMHGD@pqW+D7oKIVqBwtK^w8cbRoWFx_I* z`X~@-7D{f`?k865;>df?f?2>kU%tP9pBVYp4?D)M%EB1XE~F$(A1EUnJ>mZ-OgJim z{zyUh;FO^vPLVFhb;69~86dO!^g+7iqB(0e zv!QAZK&W=G>dcyI@4XmptVb-5_%u_pW`u3{877yy zwC7TUrzCm-4(=b3r{)N!e&_W*Ws}|na{Z@?q(2rQclVAvz5VuQ>W(?Zf8m1afIF;V zGNM-8tRUQ1jM?ZUWaol=ip8m|NM?Ccy65apC;*Rg!<^q`Z2iIGg^jBUb=GB)ZxWO< zCvkqyB5%!f&*2z~guTw0NPT$fy8I?|?9sD`r;;K~EW$ z0RbuP(C8{GCy!8|Okl=WaB2dR@~Uh82J;^s72KtDE0g=93AdJ?B54@C7B-O^tX!8{ zFxi&sU>HkaIm>KVOr$hvLxMqDMa(qFR-2H#+zx*oFL6o&=kD>$_@chI279gvsT;L_ z6yiCr2>jNs*Jlq9C+{4TxH2nAfqQ z?zXzuVHMtvE&fFvIw8n68eMOzB4Zx(8!T#?qvEBlk})A_t)${6oYct1^4H7Vt2_qr zE~z@41y+|6o#-*cr1rv6jB8eH&K&r-%hT=@x|$1nf$~aqg+YI+L&@`!9!tEm^xDdk zJo*6@|C#qT_31kpd*}~JTFbP5?ws1XT&KWiWS6ODqnsq}oRlQDQEc4v*)n48JZu>5 z{0PMOUBu#wDf>xUqcDWJKON>#VE^_`2nuX5YR-HX;g;;o(N)MP5XV&;aqz~hu|SST zAksO^LJaOgbmvvH#T13*6>TULiPT#ftnWX}Sw+!AT3VD3_8X-j4#Mh0Q!MV@^H)8BEAyvs@|6#HVG zEza8DsTCVdk9*eplKHMr z-&5A*z#n`Jqtk=|pCO)6PjG&|^NeErS!~j?qbrA}*Ieg^97!*^$8UQ5FPB9}d5CDzSS-kQ_wlK)<-W%RL9l5G{trb-DK5YAZaE29es1{f#CFI_++RvO$9 zDvuMG2VhJ^>ngI{*7~a|RH=zhbE1wc`ns+qm)*?XqGETb3_`ANY%T`6Q*3vkx#Ov- zx3HuOOn?Ldp%W$v5g{W4o9DZBi4wA>DYdotMQgnjVEaOK(qbLYyS#q5*PXsa_9Y^( z*XwA;J5EoK8ZlgIsuTnSw@)8;Pi;YQ0ZxP&K~s#oItgcSR)xuRovh4%z#TvwZ0tQ8T&*2#Tya;qbZn?$J`G+CopUw##7vV z_f3p!Nj%2+w+hYoxVN5#7CCZX49%GZ3b6xnpINeA7h6Vp^N0MdSfLW!p%RP}@h3}q zT&djq$)L(8F{=1ok7DhU=-&+gS@y`EI*df#Xxc*xBTk7?~6gXS$ zBXj!=G>H@f@Dsp3UovRlIQiK!Rn_m|H<-z`bmx^a1^O*gW2^3IF*5#wQs-Qz#fMwi zT~-*w-Co}yZl&4lAS)lQ*$sE%+JFqDI2~-72P($76gs>Al$)k9=Ma@Q)slC`g4Zap z$S#H7kMG^cYR69TKPLU6o?A+onX#Q>M@OoR<`iL5l|Ovu7Jo#>@Fmpz5z?Nsgh(^~ zuGP9Y)pPP>EbrmrP_ub-Vl4yIS3b0^XN>W@tKY{VqEKKfm%%bUPGs@cYnzMeR}yav zYV%mKx4ZpA;z(vN-(2E-1w7?CL|82JO{{wErriw)`%&-Y7xCpwJe}q%fR=J6O`eHz zj0xdvSwn2`6Ix~LS{vNKMYV}XtG`$35OIts(mwrqW7A|~i4@)LiryLn+yuayi>QW>fT+NhsMAY%a`%THLrk8YaiU6IeVitb$5Oo51a-sH z6*{J`JkUn-cLeig8fj#KjMJPO1dR){8fcawkq?FLen)0LU+X;fes{jtX{nY^I)P98 ztFsyUp2bbeVo1RpJt7Bp31MHCkq}7Gckuy1?pF%wUXQRq=4XowR7|`cbGml5=^+Ruq`DNaC zaSr{|lYOsZ?ioOr-MkLa62pkV!E-~w-2tU{WyF%lOCqWCJtZ*di>2(3M^d!;fAAf} zi(#NLq?ggLLKfHc6JzkWH>G9%^In-7Qa&GPS5p8_=i*KfN0&(njy1GPe3UQnol}F;myda2KT)qQwpMKt*x&zVH{fGvGCKfM0eo4~rxEzT@kyRRuX zuGs^>YxFj)C%S=ZOcx={J9D;+zAR^Rm|;?iv!mTp;lrqWjcfD*mjL!x7P~)xu?VuX z)LFwzN82)YrT~GTXsilRY`6deM6rbq}vzQ8_AAeqpYuVe-6DHqGa>>vQTegTOnurJfU=kPmEz&KSrBXK%eHt z<$JEJSfx}?!9Ym?zX9H?bAtJjbAi{j*@yAw@7cy-et(Sb7EGzC4n63$2+iv#_jKd)`5l+(iQ!(MOW#;C~+}iO^lxBJQGDR-4ps;G>ye&y3Y^-1yM$$r~n)b{^*u z$}*(F-d~sP-u(oTUwx%yyTDbQt^ttHH4+8jUdMdPvJb5kn_P&sZ% z5z4bUG{|Fi<@(#EI)yY*CaEOv$dxV{!}9~XZyT;qJIK zCxmq1AZh8P!n%p~xT)GU~msElX)viHhZe&*~; ztorrM=Si7tkjxwVsZ(K@rz-n>d=x8XE%;9dzYJI#?b>2{qd7}-{q34#FAiqo-)1?W zT!)q>`3n4m%q4s-sBE^8Qr=0_OsCp*A+4T|1a!UpjlR0OC6qCgNH3=sA%is1zktY1 zo+!Faj6_)`eLqtS9?WNmFIKqoGT3U_=6-*;uT-74C{3lq5=Dv9M?|i!r?w`4aQ&a^$)hYp2xBz6FL(%dDrVoez{2F|J{`oug!~1_O z`HY5LE>&w#zi>eC3*y3Mj3yxVGA9^KCDwU?hRALNYtgD+UTD#4F^6Cn4duRIm{s?@ z(J^~BIRFbxjybcLS81CLyXS=TG-uf57hU$43s*3AlK7e)e=5JsEMK~##jIeZ|JPaJ z!crkx@s5mR1Brpluk%Vevlg_-`45bGa_d%Mi*nwGQ`ijtm4C+=V_t`e+nJnro7!9c znkDr&{HLaqS0}R2e5HoxPt8x;c(bBAGjtcC8|h`U^m)2ESM`LNyq_BNBpk2nNtb!& zN1x2dS%}$`kyG8<3Gseu=T~iQ;}CGyo6|99vCGyaY;%({k}Eg|1Sh;|Owx>rnt7$k zz?l#AVMy#I+WS^6D(u1ueG#{VT>v9bndjwyI)<-X-*bxCm6zsb0|pZkxuSjIoTEQ> zvANv;GSuVz@cYND*RZR_oj` z9|jJ596k(Wvw@a>=J*7@@A3ID3AfY)CA&&n>8FWiSCxFi* zLwb3fuR@E+-$uSI6nYT-cK%Q>^1t~$Fh^)?3lA=KkL6+P*LlT%v6s?&*zw_YVevsKDy^bqUaRhV&2Q6dBWaGF3Q)rmUIi(!1_aih{ zQD$;36ec9{cA7L1ad^ZZ1ji{43H;9(o2XT`lp_U%rGABNB$!9uQAvxfJv&jVsvP1v zGtRkYrb*pzsyMhx6Uc8)v4iDh>|4zY#L}kef6!5AUZn{@gs__$RVXBkXbT6Lrymgk zXocLF%*8vE>05rg+X5ahD`s~IU7##xKoGsq$az2=;z ztg)*~88;N33A09;r#8y3j|J)5Fy<9CdI$;4>g(gb=H>7U2%4K28295zrOl?0gu|RP zHB$Hj;Te*!nw^HiK$mc365ROtfEzMUM@F?y!e~y?2rc|3#z*Gp0px~Cacqs~D743A z2IENB*CxOUU428r;g%dP&%6}czR(0Ge1pG4yj30@H3@ZIFSc0#EA>mq1NQjt|32}) z_4k+QWmC%iPcbgi^xt1(@LS>5>;Lg3MNk) zrFJ?XkQhf>FjQRP1^T%#4Tlq(DlKj*=8HQ`Gm;v^dsQ*ye%{B_2?1 zRQ9*BNiL8f16M7b5v!@D8%faR$jt_okg(e)Zj5=!)`2PJnRWu?Ha(hIsr2sbE4WJC zX7G$M6-fch7Yc;LSBCVByUi>-9y$~vwkVJV`&cAc+-@|@^ugEGcP15F})=wh-!G zT>vXoSE-$0>88?O@={MoVdu`?F;!vN*rHD8K$Nk+nPui&D1-6s=rZYyiExRb`H`LI@f@Uec%~01NoJ)n$KX2M0fdFrL^)V{@{Va<8g<1d=868`a+Am9>*XMl z$zed7RJQ8|(#F?*G}^s2@EERi3RbR9)8YEIJr%o`q-*v&=Wi4#U+ZA;?Kj09 z{W`y9L#rEfeq1y7ls3T&Jrf1#cGD&U3s|1fggu#F@LZJX?r?OL^@OQ z&*HM%9vA$9=A#vYJ|b+AWn8V&&mj@_hZ%ogVcM{!e);*%WAH zvS!OL+=ah0+=ssO#i->3&};G5Rf{3$`f}WlSi0Eb`20T>2MvFPWiy#ii95I1O=rOt zoB|Um;TrZSx_gI|$-N%-ZNVvdzgjmVr-(?rN7~u1tVqtNS$$^*jdk{({zO5gM%a>{ z!M)xsA4#U84#tsj`OQkO}55MCv;kFL|Ok@gxo&rmCS(K_}0 zFJsz&Ho9`AErBU5LVErX>ffWYHdJ_f1Am$Uvt3TwpWW(vAIl6>KkZIM>_$;RLOX8n z`*{)Tup1t&0FjdDsV zSD%NSIFR(u-~SZcR2yq3^pkyxJ9_o;gZm%6|BF5BT8Z3024FKV=b?V`zsduNs%vyx z|C+ud<)TNam~Iol3H^?HF#=bfA?%obC+qx=NL&x9ROsIof&W(MTPN!~e?dIvYh6_oU*)ru-ykD*4hQlkB1DDV0hq?!A*} zbyi35^mHW{MwW?QBD1$PZ=iB#wG__dZ?5IuQ$Oy|9Nx#I!B zGZK|!6^)a;PJQ?1#p#_V{gQxIjgRbFGU8fRmhxoLElu$%3VYSx4TZnUP}+5L)w?6w zEL#g5S_{*V1?cWyTCJ@ygyL(mkZ%fPq>8?>Bff^H-j42n)Fb5vBSiKda!5PHL>q;X zVnA?D0InkaJ>NsWre@{ASG%YU_~b)k$&i+T_B=aSw|Eqa5l4nK!Uub&$CT3j5|eND zCgwH58?|ST2DjWP_jhG?ziGO2jIGJkY~hCjk#ay(r@)F}aFNDakmRZR@Y`HD(Y-NW zhv#qcLQmp5{Qz3ha$4a=x_AH3fA)K1?XE?Xc~Oupd|BD0xS(>i18*Twp!hwmcB$JT zCgLvEs+f`t_ff!v5BQd-1{&4_{U@G(Mf$KS-W#82sGl*|8}Msw6HXh%t)p;Zd;{>3 zp*3061_~NAnTg*$nxSAuy&>C~$<4gcjgm&TPNiv(Y}vwWN=zb0m8^Sy$=>`BH>q-7 zdNscz8n7)9)LIi1j6O+kCf>6cj&KtyK1SE8DB+K#s&`Cx zRc`mc+cQ3X7#)Ar?%leO5>fI&Ou*GZ#-1v>dqsOYMGVO-Bk9e7O>M(b+pb*<9a_oT z(ZEpJLQMQrz>6q1x`X+pX zeo43{G+!THIxDHAWIx!O+%PG5tj0*__-o!|C8v+rE3R;yA{Z%eTcW*lr#>)GpHfTu ze(ejXGB6$(d$W#ixYW74>?^0{zH+owFjlz^*X?$EQMYaylhOaTle_OwN@X8jR7AdZ zfLAO+7EmcbRE@x#-9;cHvfC@5hC1!i1%TWHmG#VQl>+>CoeOqkX+lpfRB>o`LY`M_ zDVA55SSj&n4>eqz5;HJjWh{ZlFHVV##<1&8xF@-%#I1%k##689SLkzAix-QlPmdXw zBy{*5^t#<#5V6l~IoR-PO}&fd6Ht@8DF;$tBsC;F4+5y@%Qk=fvlMuL*f@RoKt|(@ z#c(L|e3-vwM8MWZ3q$f+AZlm1&qFJ^aeW{`s=-oARc=7*uPsIbsr7y9SJ;ME9;Q2f zK+kESKOTc=G$I>ZFyq`b-fL?!=vm@7H{w@|scag-Z{lS2=kkWAJ@jMU7biP98fMLT z1S~keuR1qsJ8!Heg(+=>iCfDgX@>E+f%*oh#xk%b?o~@7cO|@vYzp$o3)!E3Eo~+S zujv%4ZXKVm=~m9w8f)m4XoOhU-uvj#@?EGaR=56GC8a_uvEDWvx|^Oh{nsGX>!Rz* zuQeN_hx#C#XR+a?T8_z|nb{M8+_ls8$0Wwu>2WAF!)01S6`5$v=`&Hx^5!|HS!=RJ z*1Kw==_zBXo5JkuLYaecmiA-O`paJjxyjbtx-<_<8(-&-77I8j|AuF)?NqQR?WEff z-pE#qOL1?T9OETLN;~VD3?#)hq{N47Gn)PNmXA9sf?9zUza7ppox^jMDWleZrdT?x z%Xi%$|7lTBH}I@CT!46z5ry5j(MCOB-oDmy$ve_oUAawr*T|r0B{9HG?*mbxOmwe( z&5rBXg?_TFld5snayI*q*m6LV<-*?VvO;m=)b@JA^4K(L|0oy+h!3Zfs8zG%2b;hIp~i5zCQs8gt971XPe)dU>x?PulDvg_w?!VsOW=esMQ#3NBgYZWZlUifPw)Yn;F#0$x{q69z z{(6Z*Os{?@Sw{NFGLt$t%^JjH=q87vm?!HQ*`8WVVR(At`A6|R|CwE}?OvLWnKM3= ziaY|}7xsNFNMij2WNEi#^YM?3FV%e8f@e1Eo%@8>zpUgNI&ABySMqe;xnVn>Dj?PF-Il z%=e|Ewjv|HLoSws-=f4?eSPyFWx(5|bMn6%$fo65*pho*yot}`$=eNeZV%V}zL&mh zH6`(9p>7)AGCBj*CExl!Z~D_0SUeo_i)@f~-cv3BYVrmO= z`Te^8!nzi_Qd>B-E6Ey<;Z*g!p#~_3P_%7Fj?(w^%+?VV+uvgt3*;Y)fX>!Z3JD7;+BHSyJBvcXhRDv09wK}oYNyMM!^ z!Mh3}(G%BtQp4s>*Vl_C&5whW+1$>Z%qK(`tG+X%TcBjP*qLhCL620TZpVSD%Zp;m+1 zdC$z<%GujV@Q3ZU>YFSR_-y5R<0}s)d4Wp?y{;b{C&m_+ulbjKKiM(AERl=zMJ7ef zrxfD&ENN;`vYS?yVoM(>+}FNTG_9GwmiX{TB3#rq>N+Wa<@IT_(6I`+Xo61^{M$$6 zpwl&nn}O=~)3A)64qb9Be{;5O_0`@nAAeN%%uO#z^BmrhT9Bbs^{<=zZ(4s^ZJbgo zVof-nMC*cDwpHc|R3ep`ZD3Y#q(yjsi`-y<_>}i<&5lTUMLBIUhUMEG4?Af>+G&Cj zszyp|LBC?Of@P?A@R+RGD zv-XD;v-ep>4xEQXmS!Et@yvV}rm)@;|~UR@vH}`NUJ10}oqPHdJ+ z6uBqoZde{o0!D$mgDjQ$9k=HT{AJ_)jsl5YW&e|=RQ9*- zj=jO#FRGu5EbYkqzgfH;W6G`iFhrL0pz;xpgwc)=N6uSBz*Ea?6XNO6(DDQ(3%l|} zHn*Y!4f5BrW#P>9TaPK2jm+X`Mo2BUkPH5v<7CVT)F_z@vzC#}MC}DH8EdVXJJu?o zi$%KkFk%Z5I=Gq$bsjvNWDAZw90idgS4i`Xqk&0mHb}D(04UZTKoXR4LoE#+SxqRk zja;oM2^xFl#TK%GV$@`1AdRPBLYT!-_tEFCN=zg8#!@J)5NPcl`jfE~ax*}@42kk( zHmY~~$(q3lF?&2;;ben=22t8!NzAu=jyDwcde25`W!oo=6=iEtz&g?V@r`;D>CHPv zWhP{Hj#@`WBcyEGW*OEK8QNL0l4CxjWb$h3TP_RYeB-qW*>Co&_T{!9c6f$LBS>D( zODLs)k=YSNma%ZCLOI_*peVY`kT`NB zIrH4>%ycxlxq*5nq z=`t`L5)v}z6-iJP@}xax2x)_(uNIMblv`64LA7r3`YN`YEc`8%y18=w2)>qLrZrPR z!|sL`qAWF24Jau0piVOCrSb!9Iwgr7R#w*%}&e7 zBl$RvU(pi#Z8c!AB)-33@Tf7@cn~wdXB(*dt6#B4JeQpPzuu(CQdTaNYjVJkD>(P> zv*}wPnQZ*VbP~jajt&UGOk|I~UIJxMW=J5Ha5_%WqttFIh&-}hRHiSAq{U1tNY2hg z7Vx%bczY5yF;kADeVZs5TMoJ14+5$nsf_Jhfsj@-wErSWDu0$LIEAD*5P%a*7!7r$ z&?2V@jt5XM8P>(D=eI*J#>C4nA;l2pOea z2%b5T-bGlLVOYH5e+->vTvKfrhZk(XHjv&(X=z4-fDT4?cZ?3{P95FdrL=%3AfYJY z=rQEmX8lwc0?8a(WPhK+M{1Tu77C0F*{yu&yNX%SLCO~M5 zkp+r()^TO@lLG*7Fo0=1^@;=UAL{(TaRcWDTscPc+WT% zVGr#GYYUmuUJF1&it&rFodyhmWG_v^kv83x1dNi>0NnYKTa6=x#Fzj@>_D#y`dD8H zsQ+|9;yk7hH{Zj43&e8Q;4YukD;@j8*u1SuZ9b1GM71@5@-AQstrJ-4TbzWzSEYHa zHF}8^tEpTJQrV++-+{YT)$*&rxdQr(y_G+uRHo z;*sUK?sA@|)#tXC5FpxAXYe3bd8RT=GCWW$Xa~&9z6BD_X}IS^PtW`Sf=*>)ZhzAT z0wSzOOv_Iaps~ru z5FHz0dfp^a?to|jn)wCqM%@0IXkl-F08<{-O*H^T^WVw1h&3Nch4r0F7do@6`Z-Tk z4%^iYy!=8K0WDEy$vXR~+*Q6{IxSHGS!_`N8|Lmq{0IoE?|?!@1{V1NO4cJ(XQL^_ zhc}-Tzel!6*|u~EzW<_i6SD=-E5s3nBN>fA6nOmgQiI=nU;}MZWZ4FyQ8bc#*xrU; z_q#Zb&O2g&o@5p%-t%(fnRPiS_wVk(xtHWMtuKx)p3Cx%Rq651xyBqt!jm7+Mf1dA zg;>M^aWiNVl}kMccV*p59#%45Q+B1PaT9ki!14YV;qP#A`%WD8!K82AsbNe!>F;sJaBXDTv=Ap9kEKB1 zVHy;RqjR!01aR{RZ^B53ds-14-d@V_Sw>R0tnR|z9NU$hK+}#uy(0(x=sm!vB(f*8 zkb&&t0$3$k*Am3MhXA|GCQG09CeOLW1^|k|x2ec|G>lSN$X^>$vY_$M)A}*|>Dt_QfS!9%qLWKm~Lm)}VtDeM)>cAdx z42Y8HlkdgWUG@(dVur~Fhs9DWk_Ue_#H$>U$Qpe5b2#YJs4tTr2d7D(7{%Xe#Hf5_ z*o;pFH4`gk4q-B9B#`6rER|XNOPufdkgyrt%o*ahN`NP8W%+4=ED4sAB{B%?EKiAb zPrltsad%LnOECtrk>=^efzVWQ4WlZm0KDzdE{>*xXFy&2h8c59Tw0Z-__pnZ;_S{D zK%0(YTSKhMSg}dx=YD|p6II(OZsKKyHOz3#WEKq=sJ478lRhGINdVj6gE6`kHfFLm z*t?hv*%b_E5);9`=%l1O*@)lpGLqxo3FYQ|PXm8DP^kg_Z^X{yHQs6o8z)f1=kQG?8kzqv49+6 z)M^K7ZN@cw{PTBE3cse0Yk=q_8M3oDV~>h#&UKz15uLaz&7Hj-$G~ zVaE}w#C7YJNFUjNzv&)-{OSG4F4=R8bC4S#HR-xKJG#aG&G)OS4<~?P10pq8NT!o6 zAgsRCI+cZE{_Vm1ia#Z{n4Bey0I*OhH2Dx*Ma~lS2_Q-6sUT-TV1Oie5DDP~N_ZWk z*DdFE+&mo~KpU%zT@^|dO~wNW1W9587lGBLmX5oQuNY&*@<{B~t5_S7i}L2n_yz-Q zxnfVC7sBskLEEO77UwCGJC&g1`u&GRNs6j84XW{l2ajO25~b% zs-WvCG8q0B4`GCICwZsAk0s8*xkQkiKI^U;IT;?DH*8?)P-M$Ero2Qpd*V>eNa{OF zFc}bHiIZq8L3fyeY@TcxO|XkkSTC~hULh#_v}8!IB*6n&{<)@ubh$sWILy9Eaq}jG zV;iePK@DH0{Fs=+s{uDpUct<1SjpCcRtjIxD|8uFJqx_^%Q6!8NY_aml!zvai~ zM=FsRON{V1M!QZ!G?|XbC6{A4xdiE95EUA*USyE4SQof*^%5eLWSI_`V`edNB6aT% z%P2$I^wIMjTuK3fTYwU@W~j6h&n}_O?B_wceMGcU^W!_3LM$~b8)OCpYS)ws{TKul ziF}_1;>-u@Y%F3^9#f}s#_Jq+-XC{G53fXY+jvXk5Ca%yc>Q0RlXD`>a+Rzc&&Y&uon#$fqay!4q}Q>3M^VDR zSltyK_CF0ukVyPaBlN@iaX=hDAtA8_+J1fv-x9% z-Tv&BPV^+{%p?Gy&}6)Rneq3r30T;?XBB9HM=TP&`$oNskI#GZ$a)Cg!UHyj&wr&< z!pL^B7nifH>)U|HW~00StC)O)lxro;-RyN_aSS~b9-1DTJJ^(0oI)%K0|0H582O$d zM}v<$^gL@wqK;C?{*YH*f>JidfG9lhnxpbg7Uo2=QvL}r8E{YSyW0oxw=c6^ToTH1 zQV|xFGgJ_{%k2N|5<0wCWpSvd`e`>ULdjR<8RQcwxhu(l9d8owf8P>rDLzSO5y541 zQ$!kTn;M``P@@8@d13<+hbB%Pv4$_w-qqq^-X)lYw0Ftb*!R!`W=2Y5e3RS4@h;8KE3)5E`~+D z?wTqdk&8-_Jv$1HD!k=~e^xsaVZ$4Zb6pV9{Wu+l+`Sw$CiZwJb>hqSSG;bUpDLeG z==m>luG5i@eApQdOfaV^^KUvI|4_JZG>MpulYEzQSpK4HHmZ!9vQ%igS9qFv@~V8| zN^bm|xr0)PFD_O%OGQIP%ZpY?sB7Mr#K~>k(bsrkUHld3@Rv%$pAeWKy9DG#mVSqz zIGFT7l0`ykZ6nq~6GUG0h9c*anhZeAe1mTzZpi#>2FGF^fU+WSfDC9Dn3*KBru}w_ zhq{qT7DfBH`mMTScy?v@%_2@2tE&vdKPL|lXH_crD&a#x(l1%r z&6i`1eCuUj_kMXx8g&^tJv;K{ej!WuL-NAXsU9XbBI~iMbcWG~up!z8^9vE%GJhlAv^p^xOgStDD`uc* z%dtt1Pc47lR51tQDZW7cQL6Q1%w|%SZ4Md^PkQT=kJMl3VRbGTv&FN#!zj z#WJBEui?MYGZpGj?Ka;8%6@n!l*Kh*9%er}`uCW=_d4vy&cZYGM7Dc>e;==oAZOBS zUd8M|J((|W69B+HeFBJr#IFqSBp{h1pusbd8#+?m)R@@7IZ~S@o|~-)N_boX z;in1V9Otb}G|J(jwW;z@Ey`5>5nmM~zD-Z75ti84Ah6M-?l|nI(aiDuIA^rAi6&PF zJ_{qn_!Gu>S^U5C@0Sh{Y0_JSK8=eLTORy*Lo?BbSoqR9#0F=-y|fWUJ1zUUJa78$ zSA{9I4gl57WFkHgTDqAC{3fjgKR29JiA*17{FH6{O-`gVFaNF9vq&E~(U*TY-<%Yu zy-53xw`@`TyH(b5&-e@W{N2U;U!I}wq#CNAGu%G-+i{BrbKpi1w=D_X5A!pf%6y}RB%*EIB3E7CH3@h} zYdf}LbJ-EgR^>sCpXo#OgNlX%Y$JXQ(c(Hhczs-G#{J6eHrhrLi@6g^q8{nIWNhQU zKRP-b=~dsXIFm}_;1B&3Aolv>UDn`U6gGNN64?&l?Hz36c$w?{p7r-e@b9qOlX_}t zAiLzUuLe6V%xC-Ck@1${dyjs3Lp2f-zscz}{uln|Nl7F&lW8*VR!LoB{n~M3U47QQ zhTXXH;}+_m+eGlyx@+}IE@A}Vn(NzADvpGYA|c#Jxv^I6jtobaTE<~^>NnGMc_E)w z)Uf_TL=z4UMQi2zCw~@I)*9V@1aIJJVG^1c4$ggR6ZT?3kzWLtFuQG_IR{3?#)mA zXlRglYzT`~+10xcaH%+9q)^!NC|H^`e_YS;)#E^ZiD@D5MwqCM`LJdBXy=1E_$Y^& z>Pn-HZBGc-nPKU>4$~lUr_aUlamLZjY1ueb_l1Aq!Ehk;NPcrNxlpNAoiX=l5M&e4 z{5dq9Fks$Z3%BY#Q9!xL=3thF=RKawX<63dsFw~U`MFNpx!S^h(iuB+2w{=fDyA)2 zy~*m+O1&Gfh3!CRM0R7_SN_D8w4=UM`JC zX-+>C_M$*Ux>L+a)uX)|i|s-zcsaU6#ClmAi<^P+AD%Zl%`P6Bb+4IDTz?blb25<$ z21|UB%nBpE;b)^~3|4R>+cmV^TCHs=dKc!XAL)K=CpsU9xT+M5_6jP!_oL*oQOVOv z$hp%s-CGNXATSq0Ndxg4WFk>WP;l0Eyr3U?+PvMQXnK3@h^4S!v+ zL88_!t0wW9QCn4y(%!VKStV<6y&mAzaF1+6j!=cR4LNE+{>zN=CBpQ@z0|xJnQH zKmnYWo~MgZ$ zL+)?Cd!H*%*%-TqH-=c8Z}mU^gl+zdg58e^)5SzK7i1UGH#_j8dBeqO&C~0;+UZG@ z(}{Ut`)(J; zNh3HEVefH+CJ&=8_zyQadw=yn@bo9c(hOm(c+=Z46hhB@6f7_lc3#U=ce7)N>i4~v z3peOkmFV@dA*u{MZ{OLk$+FIMStif3Rs|&+u*4Ph?9dn3v^{eRknK-+ z;3v7moo4)%hK3s}pfL3{3x7;+v#`OfP%)0qzV7#@LlpTsOgPkPElF^!C*F$tX`G{b z*3GxTwo>?Ku~CoF+Zcd464on&oHLhs{QA<*==)(o@za+c=8uZ&`E|3SAL=$^6?T~Y z-hbD;{l0%B^ShxMGx+17jlb?()P~g~CT8~kxUc(cJQz~`$_V4Wc418#$%yLW#|6`= z=)wLlHL25O;o9Pjx~ku0+m{!|NZO%JzIlIGN)Tw&x(f-F_y z1e!lF8F#n7jkbM&jnj2iJbprkGEbY!?$z;J(L?ih+9hI76HuP@A1V{U?e*??hMw>C z={*X4M0Bz?=Tl^Y@0u#gR(_hE5-a_^Kiw2{VB8wh#T07|`Tcv**bJrj5XOD_W_XLp zr38)VME5_s+mxdPQW4O%5{DP^)q>>Gx$`*|QG9tmwVlc-cT$z(tj0S|puYQcgWn)8 z-tcP%QNGG|eq^Ny6|Oz7!@l0aWI7&R-{uE}D zcfy)U*j*C0H)3mKBAi@3>zk*wTxVgj)k$vqFynYvc}bV)deW~S$!FeRDGA`HKSJNG zDQ2NlpU8A?HVXw1`XS7(EdWx*miZE`GGNl!ZqlganL#B;$)mHw2vhzg>pL`Ex2N-s z7o!=gH{ombm4wfqFV~TuO|W3NdY^&kmFq1xo7NAHoqtF09VSws+4qAeYZ_k+c0&io zVNT;3>SD3pYo*!9$effHqQH1JL!$G$hS|x(q14_M*NsWieWlIgX5(c_iYXEKX#?XM zoAbk}Papxp=+kc(&%Z5>W)6b0dR(^|yxFJyPyHZD1V<&J3Ypa&FE?kcg+TTW`o%)2 zsudzxgT@f7iR*AzwnnGy@#gr6>`^s=YHV5TATv&`}_?A6ipwP!M= zoN~oZFT_7HZj#Tu#!Pp(QLIyCR@Xm)!k<(pX7+>4G9B(kR58;~vUbuuycjjNno*{6 z^cntn(^eKLs}hQH@kwE>?L=APcYhNKEWW;zjGLF# z|E2dr)FpNswe6Xj>3`CN7RXFutgM3WVg8k4r*nUnPfnkN{c<11BC~;J`3|y;;{U-; zT6=Q7Uu$}dw_#rYd_W0fWfg8$1NkftTY`SfmqXg$EMP^N?v@2K*ZS6LMH6=3|K|31@-Dhu6Uc!da37u;I)gGYKVNsIK7S_egX zRYDpB*HT5vbI7Db>9EGT$1f>2R#JO>0#J>I*otl0YEsHAK>C|4iZCc5s9nb1nP}L2zaLJn~{%;7L0RO}se`IvcPz zM^(%Ik<^P!#funcjuPP3<1FYsyZbxPo6k>BLs_R2#8Y}hr3bQG_T_%7w9F9rfv+_sfbZZQ)zBrX+kwLRCF98Ay%9vmOEaQJ3dyeWAtbYjh_|m2eLQ= z07CgD`er82TEt)Ixxj{`hsjmy&;oWLjBYd1@qMNqTqv(NsZg^*wmP}JW3wT4^T>91 z_Ppv$qj9F0(cU;b^};-58J>BOCd*@9QYg0{Ls6Ib-=)y($2tTI}XD%nC(7q9GSXUl2FPB!dU+p*P-|1G7?e(0l?!Gm{e=jyTU}_=} z|F#_xNkqBG1fdFJ%$~M3Q*z2=CxwQZnR%GX6e^i%nuPhzhgJZ?KWU+2f2zFQHG9i$ zzKxUXxlH^1#cZTFyd*Sz=+bNeC;t(UJ`$Gx4wa!F#O97O8N@~bbQl*kvc6U>@5J|d%t!Y=iX|J;11?T+Ujp~lcp`_Pn` zfuIiGs}sm0-7pJ2<$>aD^Te34Tn7dXe5^xlzC{%iAeTh^N1^W(iEN9FS?n*f>OvPr zy$t0--|#zTJ0y5ZbuUJ}f@)@i%c-a>lLt2vmMZ9$z~AN)R8I`5_h(rGN7>t}HqWgx z;!HSab+>x&&$b>1jP(F8ilEgG3{goER_WsUZs~BmBfJ-zFw`e}7OoS*zeeRcwmhh8 zx}1buv zR_!i(oheh@E=QfERh?UD-7W#P53KWGdTJQKw$ld-SgUinTbJ;rE^rOD6O-xBk(Jir zIf_L_nP?>CE2Psh25rl>+|BZLkR6L_Optul~5A`5n_WU z;go-Qr|c!aJXGNCOD_3#p2&8&x9y)lzf_g)5L<_sRYI&P$^9^$mTyV@wmOaFJIipL z_Um1ik)3YLU7>F~o#bCVVkQk?CN+}>G8watD>+X9S;m!E2vx81-*yiubyt+VDJy%^ z^0&LOEVqTZvaRgRL=}rC1`t+UHSt%{G!HuM6jkK;X^`mOk=w0<{eR8P&(g(oe6@Ps`E|xh4cwF^F$41aS=b zb0EF?82qXje6|@pfddjfgT8$X0USfB*9TQ787%0-MpC>(P{+vAB(~q9|lB%XrQ;%6Y5yK#B5A&%~#`i2;Sl zM#99H&E&ua#q`F+f(_+L)YNDE#9IZnt!>t=zUgg;=`S18zsje-m(TpWo<5J7A&s6r zzh>PppN6o`v=D9^^v&J2r8nrKW2>0wkDg~$oEP1kXSH3BdpCbaab8Rj#FPiERATOk zL3zTN%%Yc!E0(JImK-XUoD~1sRV=%0F4`(C8CIa2F#zSIp160&7D^~6eCEPS(WeS| zY@v|;flC;?v+uR6r zU>b~GfBSE9q=F#`upx21{(f_FsDeSfXSD6j#uDow>AevNmLc<~LAc$3)b*h6#x{lB zRBsenXa?7+4G-Y1=tqYB3WnFw>q@;0u1XBf4oEFK2I+@e+QeNq2c*X1b?t}i zn#4U1wo!WmY$HrHlt{6NOONh77_m^@TseqgJA5TeQOI=^Of*}?9d61VRbgQD_~XWh z$4}YG>)B!T7+BY1SQFbxAMr~c@pz#3_*L(h=Z}v!0c;yU*b4x?0FXu~=GzgG=A`%A z5gYB{xx`e@jyzA^UE=qV9FO=J4F3b$8d{;tMPOO>UCKB=P$ z3}2DCbzbFfoInuxwfKs&n(u!E0MO~U)w+uFj7{XY^xAvrZ0jc%ZttzC-Z0#?+Yi3K zF~vIQ60_mNb~zAz8EOCf)4$)r+nd1-zmslnWZ3WDR~QKdK2x&!^FRqHt?-+iID)kq zaM&1me}8b~$=@a0LAi~MSN06!il5!Ke=9{X;n+UkzxVmR-L90~hBn)-;p6`dd)GhQ zW_Kp1lYLOxjP&p6`7vKtrJQ7oQg+s8a~MpeGMR#T*{fK>Juu;@V&avky~Cq82>9egbgMVv zfCkKxz5)kco@qYT>3;cnqFCa=$I0&YgPBTf8k_E$j-!PJ?7Gw2LS+&AS5bWz2|Cgz zD{XG;k2A_beOJ3A5P1n|d`mOtKqAz~`sCjRHKjOLdX`^|X$ZrbCG-1eC?p7>xOc^dr z!9-FO)2XAO9ZM~Z`R{$!I3+4;IcOX=#* z#a1C#qlI=6-JeUX?->=ES$46$1s7x0JUANF-BF#(wn(E-MAytaUpWggBC*+6%jR&ivK`> zi?HMK54a@Zixp?LE+%V`4hAez_sx~X=iQR4;IoFVDNmo_r3}xekNdF4!4niKHl33@ zZcl=bX;z*^9LIz{XqQl#;!^icZ#05tA7eJ7&}1@RPslq~EnUQ*JT(UL);`x%2eYc|80Lq#-2;U$6kEj<)Q!9Mr}LKCWO$_T$UOZC1So=WKy;d7hWnC% zwodi6cyTXTjYyy-V&OU$sYafN>MJ(+aM70a((*JGHCYKAfeI|YhBCIr(l@S|u~>cH zkMB*UCr@ZEqw4qe8M7>E%dfe6bSR*_+PzINz%%e&mQrCM+3XSD0hG$S9X9%TMtlV2^MmaC`rkbR(p3$apc4{@ljJb1Y#nTKz-+nkx9e+z2;hk zi$#hGPv^^*FN(9GjjHC$6_W2Lie-xgUEKzkail9VW{Z+JGu@tA23hWiG+?# z*xA*`c~uc4V|SZAQRPX$&oPA=zHZuD5%6v0&uYD{7i9h;VE#6@>eI_#LyMY$NwY^; zkJhla|ERd#D~NPFSOY)zO?VJ+5OshLqK2PTPNcPy)gUSQRYmWO$T=(2sOfa%&{E&Z zU}Q8zk{wsy`lqb|zlmd3;%m4ODG>?HkJZFNYBKdE)$s8vwAIc9g;G0$Cr&CwW^457 zDzVyV-MkWF!+f%O?PR@$Bl#b>3t#wYVCq30|M{_U(K#WL_Z0Y&8Z&z2$$lt|cX70})J&t>Lw4Yt%)9^pX~9 z>lK7QO#j2oS$7{YM1sm#0ETeISsE|7tGI4p@Y6J_ji=6}AP%y*Q`^qb3PPs20^M_W zd!Hz<(tk_U(cvVjo(j*C7_4X%r}q#Hoec)9fUGBoF-?qTN=_}i*d3RX>Q*Udn$}bB zDZeU>Wt*jzxf=cR;_rF5Hjlu-2qX1!m;62w=xj4X`Ws18F=K6<5L~s`jQ7-2>)%8u zgou)21h9)+X0${dXxmSCbxJ*8o`(5zEW344l=9JKHX0o+t)~}AFBw&YfQp*Cp)V|= z7q$@@OU*sv>H**YuK>OzmJ9Zz)|&O1&T{(O166s+1z*f!zbvpv=#I$$DsAq*mR|in z3*vZ>^?t9MKb(I3EsU&_EQ=nRd;0^my>Dg1xk*3GDu^8JCOdW}#5;=lL(Rkb&xt*+ z5|YaqN+UW@tMe+Tpz-xsx2JgCpW58sVyh1{HOsfLJWb9IH-x1|e(;}}jc**q9vU4 z#a&p4P5k>XEYl+iMV?-p*Ba&B*X|QR2kD%V*QL`zFWs!>{C}iL&{?7;E?2q;Vh=*y z)HxoJjoDK@&(RNBOD5B|r&;x9%469mQdwoS=(WgK8sEb#b7z};WMl6<@a9L!=o)I4 zXnkNQEEIV)gCD2OvZ^s=1dU$I)A%7uJ0NE`$ESl;lV4uvPq-K4+ zgZf|s;R&<{zIHWj*`e@GUSKBH)0?_3iAv}vmoL7fx7%d7)#k|8Y++Ko|9pD?(@!qB zNl1udVchxWNk$9Kosm|?7uDfi^k19=M~`wS?Gwf>6CsefEhp9%s^&ZRh`ibV{0>aE?eN1~)j3ZjYbt;>=O9YPUj+bYi zUIuET<2^g%evb%FQ(w@^n&(wV zY?L%Rw`qNvWmB)%rTL_%ZLp8|Hk9H4`)hkMn>_lHuzO#uc5L(=Rm&}g7$4cp%?}-_ z99T>!Z6*yp7W?w@KN*oV?NIXI!@j!#-uQQXUsiknT$x%MNTpVB(CNmiI%xm5B3+U# zR-&2h7m&+tyE^Xc=JIV>BgMej{s;Z+=X;JXZKQtP6a0l2F*dF;At$c5-0@YSyj5fu zEQZQ^ih86ZnV!oR5hDdA31>|dzTa$%ws;Ee|rG~SD|B9D6-H=f}6R^zBN<%wa2Dp;;7~< zd?_ZnK@$A8R(}8*b?PW;hEsDGQFzLuAim=j+TjG`;vCFVSTgf=G@zlQcR7DWb1#6V zwa!Jh-`e%J81aBhsh>vNFx2w{S16Ka*_58O0)+U0H1{h5ZWTT@g9wi zW>W46fmj`Ip}^=Yt2B4KN5lg{Ai&=jhllXV2K);|gbyVT;Ty9&G9-*|z zz(;E})}S!j+reV$u`c*zhLLT%OA)fpLd@QL$S`z zrJ>=I&-bR$wdviT~O_Pu;M`B1ZoQRZhwaS=}GPnDTR zN2NQfg}=Pi6?Kc38xfRFN|gC6GZ;`X?w`4lo4G}l)%&F+SB1U%pV)0B45<^HlYU511*Q8;nT4{6A#wSg zL?fj{2fQ(QYljIvfF#YjAk5$bgGAY!rNB~n=j%2wK*6DJ=S(k zco3c_tfrs4Bzqo@UFORIS0(ykoQaNTqAD*}Ljfc}_Msd@2rMsnZ9kEe-$e;%Ev5X( zKw42G=MlA&m>f+tJv}$~n%Gxf7j?kB26pmYb46Vn7p_mLnBogh{PJ9=S+;8ge_S)7qv-NTW?>y6bF8l~`qfi|pwmXc_JUc(+0N zzu~yuyI{8alJO^U@+5zP7Iz+xQ^Wlra`SsK1Ii+cv2ycIA53$yf1t70 zGmJi!ds2mkFC5%n%XK()5Xs?TwH>?LYp&lAD1ZDjbK?#x3S{sG%oQ$+cFk`BA5r@! z2V3Gfm!uyKEl`yesAZEUKa?eEJj~B_chiVpq-BVM$Wx0ke=Z3j72`C9rQ>acv6`i$ zu2P?QAIH-h#uy2n*UXn{+Hh+6hLq7^z?||54%y(@|k+Ft^Pg}u*6nu*lTq0)~2Rv>5X?h*3vrZmx!%01S&GPdloZ>?6KvTB!2Kj)7L$%Dq zq^LG>9NtPheobbJm(qWd$401c$k29$>~JOHP_VyZWNv0=MrB3x1~J}1KVqO= z#vI>GR@Vs3AF_=gdCC_rh%y*(OPb>=Q}?&hYRP8qE(*wRiGe>urgv2{7sy8n1+loK z*4wG-xF#Up;1QDQ8U0DDT{5f?LpX$kRSXTM78IJND?E|I&c(3IKb4(+C7j-#U^)6$ z$y|0pyy07X=Jy{K?*cgVk??sx`4CIdmwuHk&)CVt;p9Ip+%H9B3aR+}6YWnQJ_$y< zcQo0awh#Uibv04w!8#)ipZT7W_-s95OyDv;<+>%I_%GDQ-~xOAy`|>ob6Ds@Ys{se zO_wzonr}i+{59a}Xvq6Lj^12}_jz}yJt)=0-?py!ekje089zxqEYi@GscEC9e&d2O%J6mKxY#}30MKQgpb8jp%O z=5g=_uJ)w|aN3_N4S|)NaqnidE6;*hO9U$65uywnXm(DhBUP^@Rd3QYCrKT|acfj8 zpf~fnJ>DyuK}? z#0pP@<;l{+UpGr?)%d;*b#0rFKfm`@rzQACWJUpqA2#V#&vXWr1m<5CEu;xusRS-OU_H-o{FY)_f1&%SxXnR9^;STFYLK3h zWV=$((2gX<0qXWAcfI+i3A5GFaH}HZyoh+D{IVEDOBs7Z+}#CSAnBhG$HgKwUMP1J zmDMc7iJ*|J&;bosONy%c?v{-ewDK9GmS>`CB_eQiQ~&*HXdIXP?ww^zfb%@ zs}F#zIJsJVR%CVo*9EV5{6Ynz^fWsZ7S{slt z(bKblG_DiO0U|sdl-8Dy)a3FXy8=zDPUqXMvLFR$PnpiV2J}kcB@bBsT@OiCg1cMc zxrvDGO0XmbE=gu4ME8a@(Q}yu+>w#dEe=PY4xy>QAv%>5-tdlpL)sQY-JqZ)b$EBi z1{%<)ETh`3yFTG9Yb;4o^Dq8Wu|8qh!hQ92C#{-23%KJewv7t@`rXC?VLjMVl$`=B zm%ZMQ$3bQ*8f=-R@P#@H0rdlrno*IOl9En>pZVe-H8{vQ4g#_ZCb|Y~nE|-`44x_M zJJJ1s22eeUOV;>q070>Ja{W;-Hh>_Bl!mRehWKq1+bt6VhzUC(b+6iB-{rYSX%U{h z(GT_%PhJF&;Qvfkgx-Cc4GVy4$?NS(Ws;xmy7JM|f9RZKz)<+bAk&rI4D8${adw-g z2uTBk6#jFt>kA7?M9>8yQr_gLb9j>Lsw-Q!V8g8|Dgj}SdNezT77aw+O!5LE>!T4| zen2`jkc=H9hBqthf(se|NezIU0PrG4rpqzFp@8|g>dDlcC)xnyZwKT8fZyGLqcI>( z4DjaF#R#)8O>k~BkQ4(#6Ef%@wCbG=`P~E3ZxKQ528|a=a4~ieJ=H;5q@M8}s72&} zl7^kYaC?o_3u+WNkEYZs+2_$v;p-v7ZsE=CE0RRU-* zq$(fre%7Qk**|Y%$O9rJ3UIL7**|GcfdP@4g(kLlq_l)I!G7DAq1hu^3{VtbJ3EU2 ztAnL059lyJ&epS(dAI=kIUTVQ6y)j_-*2MpBB_+(?q+v!28&zBhD-VZN!dZ1e!v@I zVLGKCJ?@Z;9mH0Y-`ffz#R0=VUfe}96Yz+_<(7u0aRhPQyO={xG^jiCxI>VNi|T+J z2N1!qE`sLiaR4X=Bsqa=f)-98XE+rp(!XE&-&Qe_9PUJ4`BNUVv$A$%gXw1vxVA3Q zfCnyPL08lq!Ipn{@PD`f9D8D-TzCK(?iiiT-iG^=aUaBEa42{B(e;qEJzJiF$-5as z%7g*1;=xR4fbQ0(;7e%WEb!nF5x50how-r#f>~REBwN4-Vd}Q0O$}1&s)f$?{i>ym zP60{;Y#J#MT&klPOESjDZQKyXPKZ$@rBr;V(#S*1V|<$qe|bjjy?!IlClS-CWLBpol0$_s!|q(kcfLqwu{AhTa$36LYNa@ zm$bf~PE<_1kbQvwTwELtlw1CCovu)P1ZA~4bDyu%eWF%jb?&+R+_tO>X?8*4*=vKM zs)~cAlhf62{)B9Nc!4C~&SJ&-31lvB@rK0!a3Uo&nd9ZpgozJr)@uo*Bj4a9B9e za4ovXs@{JaKwZ0_)awCi7A4p?&N{?{ZAOO}Y`m)K?js#%6Bw-TEvmk=@@$3_(SI?{ z>c9TE0D)epB|8+d>>0QASU8qIu|!Jt?f2KXVpS$992KyStWGGa=k`R|K18tRbSF(@ zI;w^oba!?TCdl9ppcLx~i<=gGi64N;?i>=>Wj`MFrzxnX48#GN!?5Y1JybPmcfq## zaLIRmbTFYzvZLhC2&%&hz9x&U7(OGW6qufQLp4mGKFkr84m!n{@-@j4!EkPkH=VUM z{))Q@34`!4ni6ys82`vfZb*<^r0rP1m@a#ZPDif_8}lf?e~{N$r?1vp9o^Wp+WgS- z2IOj#0{{RQS<_Gs$&C9D5|heACMLet%Hoky@_KtmPrz`Aeb7x1q1&?|CJ~p~Edyjq zbZ|vQCpaKJj<5u#7b6j^2U1!0p>obS>b%{~d6sFq(g40$VDWL#=unYOQyj3^I35w*Y$`~>FP4akO~@9i<%Xzi zG3Eji1oM@7Gf@m=bhFPja67jFm4hZI4su6eC1qpsAdepKxv`2P{qkK^0UZwEfQ&So zsU6rGXD$E?5QmzjQWH}_1DWXJ>;*6wijB|3LF1u!9|) zCmCgXP}CKD#SWu*r#oOL)R3&2c;Q_7lkTK(GiaQR!Hp>hn<(xRS8dJC<)*t15y$&8 zQ{(Pn#a2}P9vcJ8Of%&Bt|-G|!PRftMl){Q>8rfxSjc&@m(5$&2rrI|JskpsHy|cD zio2>~DMRV;-*RD`0kE*~4w9EiY1=WVhJ}0@kZzolO@h8zI?O$hN{EPiP7TY~Waaa= zHOcWBdCS?@f>+E`LItZl9}56p6sbe8uGC`D+VZbLj&X6pLPhs~Mham^M10KMji zyBHYLma6mKh0MUs$uOiu?t7}l=X#U-GT zf6FL=dhjI!nXs5LMB^DHU{nQ4XOM5IQzu|?HD*@tD8e|-Yd?(}wiGcKa71HKf@nNN z?2mMZQ#jMKEWBUD06;$pN$U4Yln7cW61WF_Va)E8@Pi{Ry9Q8;hFLxxmaH-0ba~ei*SQ!xzQ7#O1XtG-EW|Ze9F#nYT+b)cAHbzd*g#tAV13x%gc3Yj~;PD;Fji((!VLg*t(UpV7llBwNkbO$m;?{GXw-aBJ$1 z!uVYPW7LSzF}g-~h@%^6X-9{El!}PDjgT$@DPg3vlnMyA(On{fqEaFt3Ih5A#QEcS zzJI{I=ef_l_nh;-pLZT$Md@xtJbizDE*|nG3seE$rINk~j1MO+@HC@J3kw!+z z1Arq846s!*3ZgtkMDWOBowpR`>#9T40KyLtxd>e!4N^F`SuoOr0!f`1$`>uAHL}Ek zX)qWty*|e(hhd9_bODa}{Caz2M#;NyY9WiT(kDWkqwYxt3CASHo1q>-c?o!HS2 zR0fj9yyY@#N_2!E=Bq0ikt+psb6&>AOM%=il6OyLyexEs)I6@S z!JlsbHefYly2B1F|9mK6__dDe1{#P%&IwVEztv4rURLkCH>&5XiD8T)#?j|tFt2s} zGJDJ?k7CEz+cCFR7V;rqrvEbrnN7=FUbxnt4nVqwW`4vJtIF@7_@N;loa{spNZJW> zX0gCAcpxqpugglI!(uM6ynR3?SW2pOtE{R*qOQO!FV01l z(Qm?~ff#26#irQD0ssr~k7RU;Z*AW!3nqL}a$b~&Mq+O+<^`_5NFwfz%?6i$Ij4)y z0Ric>3TCRL^GYPA(s2T^hT7Ma@@*cQUMb>KTs^LJcpbC&veYNgo{P$g;l1Yj8u^c{ zmC-GbxHCr_wPmHzO|J_gpbPHZdbUeghVJsp*T!%bsmyRC)6c&}>e&BvWiOMquEo6k zY9@SvFQ64Nc-i%fy|ZwjL?*Tz0`G{x{BmzjKd$-UTB8~^PR2yihzM}0$UaADGF^xQ zX-=7Om8vcWIqwJ}r!Hd6g80CSgil3@`vY>Q?9RA2(C1|hT}gQc9E9l=7)%1~D?Hjh z1xp8jd8Ol&%300UF!Vf+R%zKd8d))9jpDm;rNsn+lP+uBq*R;&yLueE7B~&Sft-+% z(Mg~%utaB)B#9ti3uZ?Fsfx*N&UKJoO%WVH1Cvm6rd5t>3-wG1I;HWOQ?wvLi=FD3 zX7kNkk`W|DA4zz1biH4=QayK1i%C!DDhIZuXTYiF&Yi@rQE4%$!S+rLBt<>V7fa8l zi9>cO4HG$&xe_}SE6gVw-k4u{cQkkfI%K_>W(&dD-(`g3KnoEdXc+#@JmdK8lTWCZ zHG&AJ>ClfXChk$L{ZXzTvk9x%KCh!DKQB?20+}x;5a~3N+cTR?7IjSm1x?^N!$7YE zS%5j-6$R0@Q{D@$7D!g`=9 zE_Z;V!t%3tlYev(YU22fv&p7{670ud)mg%EU@HYL5uF95WCsya2!twWJ!$niDS1LF z79^%EAekg-S6BO=LYwO{QdqiMPJ)Wm4y`%CN&I0a)~LBa{U9w4$JR~M z%t|(wf5n7(6_#9IA66f^tj}G6A95;aN-_6@QQx_P_sOF3j27}oNeAE(xvf(#uv-33 z1-n=S<4Vp!9LH_RUi07z%WujyRg>c#7X5@v%S41utG|q^bxtE2l8BB%LFOxvNdNm-M;{Pfrh{$$XK2m}kMzz<|h-W7op(_fQ<}_&l zW7&z$2Rt3wRB?N9);W1G2o17}!C_3zI&Rx0?hyv|a1{rt1*1uXU(A4b7}7DDAQcUqha;oq z`Nc^R61jxiSP)f9f4&sa-G*3j*sm5xEXzTK)e#Xe96h*4%{v~>0(Ss_jvi=5)&N{l z3qgu+ik@!(;E_M!d8XQpX7tQqoHw#KQT2E%rlC71(SVowqSl>moTzS`R%L2;i}G+s z!N{Hvi1ctmWI<15;Soh}h<0_7o*6$rmhegaIp;-ToVY)k;5ci!rdO!$jt#jid=ono52qrjd0t&%=qqy)I{VodE=Y(C&=7+Mk?C${72LSIjj(WCM-sEYVCM%6FD`t6? z*@2i4kR+u(hnIkfJLM6a@+6Z8R9iT9ERgG^z}SLi$0c#vmASSeYYf^%)CscZdM07< zkHg}hCcvK%<3i_>Yc8eKwj^H%Jub)PR~EdNW#G^bW{+gnzPYB)9ma9rG!@*5L$1)e0b^S)t3{nBfS-in^;rd}WYr1gr* z``*0@fMd4N6_@eGZ2EfdBBT}5b?3jw0FonPr~mNRRy+W z-mn!5L~%oEH)u(l&e-8|b)Jo>Vc>j!lTUU0 z#&zO^zb2VM1REzdCDzy%$hPQBfgVZaNCoFSZ4D6TSR&leH?S0*%S znn&_AFn19HmQ6btJQ7&q7GWIj#ywVEGOWQnGWIqKDu-NK+@DuFgj+oq6uS_mGs?&t#4CCng4hrHFiM-8&HJmM+7&uH^W*Bb^&G zH+2()6k_V1LMKcqbx5=c_-Zn^$Po5RV~71ZEIJ7+<&-C|jg&lL10Kv}qmtt>iaDKZ z`C-W_4e?Da@up!eaG_mzSxUVHReRd|+IW;_c|3!$OZ}{w{1m*|avcW4-2~xu*e>b& z6nFvD9uf^N^HLLZQ(r#+Iqb&y@@@D%N$FP=bV4x}Rwa|Kj1EQq8Q4||Dk7Z<)HU#7^`3Ob(?AtQcSssI?ZSlNWxy0kJo%z0R$t?epjbU)l z9omLyXd{9{%^Uji_gQEq*ll3EEcK4H0qy2@RbsIcroe&?F9u7#vP+Zeb zg+ysia01T_YXG+ZM#*QFuJJI*%pBVMLX)W(M;0?YU@z)S`#fd~yU9$vAjBalvlWz; zm|GlT-xMtJ+FtB6#beq}>of0dALe})5|?N8M@HU3a<)r9Zv%N`z-Gk${X6^bESoZ! zClRCnqNAewF8VqqZ;?pgZ|3s*DA19$IP-`TKB`C7yqHku4 z>Gp_ z=BHtaX~G;QOOO95jbA@lwU`+%l)9obdwhNMgz9HYrPRy9r>8?}FeVS)w<9{$2^McV zK-R&Jn(e76ERE#8o3YdOKfZ)E9OW5{f^3*RO#A(+%6fb03S9ERryoX>t;`@=#LOv+ zp}Q;_YZ=D#HyP;#{R=bs!D`K*89xY@D&rveTGAYdQ8Ml!1FFlVoRjQs;I*1)N zP&5>uD${vTY8tUcpReR6p__9dHWfCy%6BPfVLQn2Sw^QOyy4gN<%Y~*#h9v_Xtz#} z*Rm10W?)X&`uU5?nAy|G64q8N{s8_ zuZi1o5ANLq`qi#I`1SMYHJQ#Og1Joh>|k-SqpOhL$9~$6E zc(HxRpK{cDl}<*oJ82z#X1U>&)@JeMbLxx9L$3_E!E9>|X6FU#EMe2CEDllRojGG8 zt4$G8(_6~(CaiqN)NKBpN4a*I^sLI>W)O{w^*gCE$-Sm3dn->6E0BO-nrnlXn&D{IC618{%7;Ra1 z5J$I8-!rDm_>Z>sbIS2wj=B)0SyrUOjF8f6a zCKUHGWJ!>~BNQ#1pB?w4BZ z2lmaRH&(xujNbVbAphiM%&&Ll8Mh>Bs(;Qn|LYijZO$z0Z~@B!v(}QR6vIL&FJpM* zp z$E~-w47(@X1EOGUj&ZV3!N|80E`PnA+=JIt@-m=3A(c;%tHi7fU-WHjgmx4dI&@50_*Xt-~_ti?59?{!I86hvn|%2iRY2(u`WlQFRqm>nPK z`@OScoo1bT&T9x6f(|J5hYkBtI8?7VOIxP zR6J0!wI?=sGhy1}=Ny&trCdP~_++w#i`O@wcLHHjX`a0eUO$_+TQWd1-mfmQ4Q~CX zfC>i*UJ3I!YC#$A)+tz;X44jDRTw>P3XCzq_m>>PMs;d@%NY&JPUnp~63i-Cu1p}Q zQfyw2V8`v9r1Jn>zMvDUitk>b#Kk-$5i7?UplHQ{+5^XG79u%x$Qt?ekZ_da8;g=JUebR!|T^e_6#jXAjREQ`bo^!IXItz3tToL@J|9Hq=a zdWwng7>IEzTWCt4*6%|dm>W|q_g5w?PI_fAOHq!ENZoekXjjB99X2?>dh1xs{7bNZ z+zhQ}Jnz#9uS9cK>Il#EmG`BiT+Oe}*Ro`{^DJ8Xr1gC)Z|vw*J&V2bwuq@MfA3R~ z@Un)2i>zkFgLh{H3Hac%1N-?Oo08S(AwO?_+jAP~$;wu1+!LLSq$w)0wcgQX&vt3ymP!Q+E))x-Ph$x6 z=yYc;eT>$Ms8ZJ$eC6SFuM`_jg!$8X+AA=chq^BPIr*Do#WIDF^gd~`7$`SKCvmsz z+C`Mi29@0N;Xg9})FlkQfq5AfRacpZ z?(H?sWvSL4kNL`GI~h7_e}L(~7tIDnYp?Uzsa&}^o?Su9gEcuD9Z!mSDF=`)l{9`2 ziG1Z~OHFE)NGk2k{?j$V&`y2BxzyplasJNfmrV+GiT~+1LPtiVMq$Hk5~6ETB$kp@ zYW~>&-mgFI`L2kHrj+fN*GYzyi1qa2;tE{0o##(jTxA7Z2G+oLCsa;EN6a(b0O_LkJYa_koEFKL9zSy<}^NCq_< zKRi1hlGfo))74Ub!C8;aZ)pY68f^UBa^ywxnoNs7dRyqZ+s&eevt;ZrRzbagKK<*{ z>2t?#o-@>LJBCJ%d*3gz;t1nv3~bfxs0g!Exp~9N4Yyu$dq_hC^XG-5lBgXb&+4A@ zw39Pyl1K^h?L<-(Y;#F(uG zN^6=;92_?s;&Lu1kQm~bvl;KQnWV~1n8MnLfY@SZlHG^gf)`U51obcF9&k;yNKP59 zIV~(*sSZnDWOEK&&G*ZqMyk4ocurB?aw1M{mUGB*pPol?F+W~ ziw)g@o2}cI2 zE8hf%82ZPK&j$-fi58u-Ow(gbEb~8py(jh zU+^p!RuKr%Eej63_V!-6+I``$a6YQZg^0PS&y!P~HdkdVt@9*PSJfwEv$9;svl|PQ z0_)}SYuCOkRc;i(@bXwjhHQs53fGz->ke$4DI^a77rD-jrdnWK4L@z%dt~6Usys@{ z%w6?Js4&0`)*{)ZLfy2Ig+|$+W*9^J5;vJPH=pJ8$31Beo0um`-0Veir^uYokb;4< zDRT$Br&;;4A357XAjYPa**4UsH| zzl(W&iIsujv^~LLkA8+?0v14Sq%p7@=q{v{vkUcFvTEwv=u{(P7XC(!Bk$*mCbQMo znsGXcMuHey-Fv)ojyaWMigXLOsQV#CQ$6WM~{P2>(&Ce|>m z*4HH)k!;eUo3Bk}Pb~d5G|1zSDcx`5z2-GxaK$={*6*(n%dY7eVngqA1=Te4qsy?h zl^sytIKtbr5vJzd$1`bX-$IRYoS#JeuFdRAQIGlfr}cwl{)S9zPGn;B3T_$Q>Tds* z&o$=iU*xoQ;$uo@Z3cyp(P7#6E3CrZkrhGZl1wi`rphKVe7eIdlu(Pbp|!Yg#Y?T} zBW6~Wj{TGw<)s%;5_hSf_70X4nR!@1{3!v=4>09Bee&@B>`1g-$dFH#b#7vk4`W!{F@wN|^@(yW&}s-Dc=B}(rRlQKyctfFac2KHWfJkpI; zFDc$6fWmFS8PBFs!?7p5pNoC13FQgUm995Ua=&7cvNbU!GTyVf>#)a$Wf#GKg)#ll zn5W84#@wO}MLIG?&Rv8pa`~(GPLhJh4lU-K64H@;{s;(GzKl)m3&6)`n_(ZKk>iVo zsKEi9(fT?5@1bsA)D_>YqIV>b6BilL8u{fiA8fUHbr#uOF{c@2vTniDB~ z{M!{{Z1zr;@w7}qx_;?~A`7ykIp{Y%eq(3!Vz|8@FJ}0AgZIy5-4Ij4!H(%`hKGDS z^7I3$z;OGHqiv3n&pCQY;z_$r`c#eC-0ncQkjzP<+;z6cfISd#Y8mM+zTET?`utgb zc%j_6US!&=>|THI&UYX|lMD$%HwfwVioaMhvD^i5s1I)H$+BFz$RBB@aJk{RFh4Nb z2CV)+ShSj1ZnPSP4Swy1Y_CI+xMrTTpS#VWmfB>t5`}Fc5Kr+B&R4BA#86&yvUSf7 zOO!6t?xf4b^c>oTqS^l$>bOtcCJc@E4v!F`i8$asJb2nbZ>7~nJKN!GjkqedYlA@N9l60i9oRX5=k+S&_9VSxQT#3Q$NcHxS%EYL0 zTKnoWEPo!M`Ltd04Pq_kJM3sg{n>?Q7+@Sdg0GSoMwKporbOzzJ7QSD&`m~O`V)!S zXxI63bZMepcmL?}yCb^e_Dh)rE{hJXV36Upj*DY-L)qA0+4w<+(SR;xPBj4X8?Ry(KL6jkqD$O{bEaIg zyqwgp+}1t4n}aIo@)6ew%PYtunQcNO0I43**R}>>Uqd|Y$XYN}Pp02mgZf^qzrC1L zy^Vi+X}$1L`|YiC%ggwdHi?8D)I*Qzp(pkH_f7mMtn?Rar+}xb7w39|>h%FIIri4| z*CYOSe`k>Tl~-_=lfaS(s*>lbVKizI$G5^b)WUhx!v3g6{CN=pQIm)zpmOz4CjX)A z|3h)=NxI#>#nX>s)4Rz-5Hz?Q9rqs!(SQ3f7#08W_O+KN>`N3>?`HAKyG(khSb`v+ zCz+*3;}c2WgP}ja{Q#nl`}5xerAQpp30^!J&(ukW=)?(h(hcJ1sxZ_(7`U~1f@^ew zt9s(q=!e%k6a71r9;zq%M<-wH1h1x0MeA$e^wo0*QeUa7lho55Ley7I(mq6|emzOw zS5JGTp8h#H?Q3-Ehm+LT(Hf%|&_RHUng%5z=LXdvgVfIRn`}yFX9N$Whi)4;qkQiC ztzgNY`6W|gD{IY-Yyok%khyD5xjVXwpMkiEAhs5KQ5lGh2r79-e)6=d__IdIhDQ9^ zX^}p@^eMiq{gk^?S9=gZN8du5=!ZPKRW$()GLKUx^;ehOsvPMLy!$)Q^(=6PP;*-o zZ4g&I1FkZL1YCCBmYAIdUxOa*Ys5F9^_)?qh!-Wa1M&*(R+F0 z?u*I`cI~T|sah{0{|F?#60jf$W>Na#n>b~Aefls>^dLqhp!;d2CK?(`%8XIrJtup| zkXg0KsWAf&Vw4RAXbS*%0Wj>}GwgakbfahFLG1ADp5fG$o&aTvl zkjaMw8iU$XJa^Qw5Y>hAiGkSZcd?V+0~%O}`f*R%3@%(#V_y0zr!AN4+Vg_fzuu&3 zVS9kRH)4xlr`2(moxYGX8K-y z=-d0Cv-eqNf1_{j(Om%qL4X%5ctOsz*RP2@8!Y=hcqNu(tY4@0pl(1<+TiuE>*XW0 z%g0yae#<>L`ifERBn-uApFVzlT6S4F=`!2`7;n&4pVXcl_@}ngqY?{Ijg3=Tjh%-4 zote;{rn!W{4J3YF!NhIB2z35oL{iwgAB^-g)5|cGL&0yMGuzuZQ$RP7O(Vz0^pUtt zjlIS^Kk!&ql5}u0RcxwIC48%=u)XG)`vp@GYR1aZ?Do>9$F-7biu-BEG;u6qSdzQp zdZUZwqrB_yYMt6czf&~xzrEsYtujr0&ffI?`CDvjo|v@k$LHbuZ3!wI`yNhhi#6%& zGEE(?TVPjS=}K9n^zWWP*V}0hH!k5(M{C}N5u4K`(vibGr;0vf=?Zp<7RxhbI?w(d zC;u(F74p74WMVkv!_1GBmv;pe4R(h;0!3WN;|iVcv0tY=pGTBxb9;TAsT>Nb{;TQc zH23OS=GM5u>0zT&;nmlr_s)LrS!P|^r}WUWAw9sI*0L*IVRSSuqukf2h2$}b2xSu@ z0ntOv129O{62sa|zZP?WJN>H}H1=i(m~`oF2AOTT#V-S50QJ+#_%wquwQz^bHAulv1CRp5GKhuXe!yyc~DJ!q>1?#iQ= z`hi+is#=JUg_k;PzPSj!Jyd)rZ&jcujgv>+R$c(HL6)1PmQ6)-kO*OF-7ktO&vShA z=f^8YEUub+w=T&RJglcvC4z@^yh*Zn!wR=dtgnGHlwhiw)Ly=m8}#5K-vF0DhVh#B z|6crkmIw^`zB?FTzTy^s%X0D=AuzgV=V@UqeEg~VUUgsu*HMUqapQErz*+-JOuB*Z zG27Cr_+2*^w5mj@FLxd!GSy_ALO|-Z) zyl}YQ;E4xOJJwQjTzw0_{`vHC-PwP9vZfozd8ZF|3BIbdIhKT;9AfN3obJhr_~r1_ z#RsrMwYY=yc;P|Uj)P$YwWl!8DlQ3tzf|X%&Pr725Hwo(#R8utM*eK0?RAXra)q^u z=M9X>M(MJ;pGfnE0y&vWB>8y3V60Q&_--SM{2P@o^pMDT?#2UxB|h0ZAkf?u_Ne+r z?znow^3v^<+I(khy?h`(Aus%=%Dvc9|CW~{80y1JV)>*1{m+Nf7F%lH+8KoY zP_VF{d2;u@MT-29cP=&+nX*+Ypjv{pKX+B|cTB?LBOTwucZlQm&)%2S)w4=Fi;8Om z-l3vR`h|i2Xd^JY6;qFhq1hx>MZ+HPysR}uASzlej}KC7wUO0&KZc<8NW*G5rdb56 zM55a9mKvGMib-W!6l?;}$7~Cs`T``h$X8SCm2=%hsu`>UQ=GaLs}i$+q*g20?l?Zw zRJNuJy1;$`f-bi+52{KRwAN$e#_s9X&&Bvy^IYuWhS5%m3J z^3~pU=WQ_4Rx!hAj4)5(w7ptuYoJB=d!8r5x%ag4>a6}@AFi#eLhWPnlvfWa^<3!^zeyeGd5z8LJaDm9RX`mRdVj)Ci6$Z= z#M4|i%5pZo^Gj3Grhdu2U*E2QJ~Xp_pM9thA+G&->{0Zm_*VTATKQWFSEOp!r2I{6 zAJy8*HwOPU`6Ci=xo*DYLFi8@n<}Sqv3esVmp~u?6}s`1t33guU`uz!4ZX`X`T09( zcY1r@l*RB|%00`!QyfTtLvo<_zwZlARelYKP;hqdj<=YKeL_Wiy+3Z*{)fol1?au9 z<2aXo*4Ix4*_pqESJtbsGc{b9fCKSpJONIpax&rFhy_UG6-? zq|{YjiPXn~Ei!Gb$~X0g_3uunv3`=P*wgyp1l14EeovTVryuHU>NdD+4C^6O3tZl$Tz}EVwPsd) z;0(DVcuj*h$R;z!;FJ@+8LTW^K1-KWpUBL7hal&3a`Dxc2zX@j!Aph`lQ2}p6VUvi zSCg-@Q9hVFU(X-3`D#H`Hb^jzZ>8Hq zkbg*gY(*O$khH$@2WPi+Gj5-0(B?+O0bPLhyJd~2=E%F=&QkZUJT!ApO?<}roj+dq zd^UaydB+X()3A7CF7T!)puMDb{r$~&)WQcncpK`Wk7oQ6Mw$dsy`a2jC0|4Z#Vs-j zsjjPDV#cNwNy!lg*E-GyG3C70I^ubPP2|)D@7C=IblyCkYKMkSm2`L~?>6dqImqJs z?U<`lDn*m`-DfyM!@sc)ppE?FXWIlH8$X>6xNEH?9Qc8DC}csKl6cQMk>S61cAkP= zHuaAKl7-ilXicTQQ%5ai*#D#7b}$>6N&Xz!`2O1s_wtBoTt@WZh+`wAf26T^X4UDT zsl{V;3_r{CqQ?2HogP2#Uq#ee5Bd~{NUPL-P=U!rc-h^Lb|MdN6a%R~p=>26$hC8! zl*tdtksPNY*B<}5%I?%799vqR>U^G!EM##Zn2BOt_I|N@s(GmIiu&H}aDV>p@Ynl~ zU(T`Dw%xF^ZMuyMR)pj4zEQUdPv8B^a-nAXZ5@}LYi@JGc<)n4mst6v7bGypNG<=H z4g0LE9xx3St~;}|?;M|A-}@X8IMY22`Mx(Jdqqbg={11XAy6bkCR3bXd+WR;9t*hy z$L$U6AIIxKH)_7{zzq`U*Y#{e|HH|{^qc+zP-07g92uVCvc}1w%@Jnwr}sm*BGx5D zzFr#zmsvd=uFXtsS!ZY=NRs*&iL0KSOlY4;Y>D286W!i{UWV+}c~Mie*ti#4lDF!v zcZ&h{`iyUI;tCLkXbwjFzLMSSpLss>K}`4qZyeLGF(|c04Ymfl4FON>0fIwM`^9T= z#USh8;B_zg2;lQEdZrUHTTwZ)ho0#(yL$fpkW+@Fy?->mJBzEPa_ zF|uUM3=X}w<#=Jfy;Mv0KNVNAc7;-3@Nd?92uaUhCgz@rqGtc{9I?pb@Vv@Jj)$s7KMqnRL;Qt=uPnv?h>m-D@}oO+Lyb{hm5+GOIXj*0|p{+wn(JNmS>t$@ACbZd~-9LKW|!ceT{1T%HQ$L4E7^$ z1jHQGKEl2$cWC{0tHt*>RLIll2mA|@nEpQ)=x+T5r#Ak>;|dYURd#{=KJW-qzdb{j)aiC)*9jo)j~;HK;{cNW7trSjMG_ zNS!@z@S*o*5?(^T_HqTSOZQMy0K$bWSnEJtC=_22sQ_ib)uNlKO(3ih;9ukAVmJ{UwihF?f%q5aZMhm{S1tN5n@u~i}ne9cFe zBZ`bRL~}%ds3Sn9x5$?R`_YARmu=9-yYrHx@;e1pvSlI+<)I8O`gz{~@X0w|@!ai_ zAI6jYX+#DK5i{A^^a^N>{!A5v44fLFh}gOz_}_jffLF?W>R9*H3TlH0_q!r>sPsDc zt~v{gBxrv+tt&RpnG(6Hq8QFH^ANEVELXn<-7=O@_O-KDaFx8Fu3J}k9MaJJ3p_H= zs3}Kyp-iZ;(;VA%YCIC<$MTkpSq!zmaSG7Or^PhmC79AI@6EXoBl>@jTQU5`s>Q=* zlCN+$a1gE}^L~4Rn&3Ez;>i?T^b<-ZA{MvX7b7N3J8;C+xtr8*yCwpB31vFyC0(zV z`aT?8TVbEKH0^ea-Xm*3@ali7jxuqUol^*E!2r7;LDpiex*e`K78*{a}8S)voRH?o&~3QLX!|&^c8z@qIU{@4+3)M-irL zPUY_JD%VjA6l&K1)Jh76sjObkA@`5GH`8QY@M9F9#@k8jiM$0(r1@#2TSb+ zO7{uLkASgNn^d>NeHUxrw+&|aJd~eLLfJKB1hLDY>?}&@*;~FV6+c9@8>{S!T%BT6 z+`}qD6;#;97#TekbsklPB0I&}s)H+4zGLs<{fx_zv6+6x?{44A^sDjOV3uLF)!b>Y zz~L3EHQdVOxku%S%zC*c)VTK9{$ADG3|>8#k#SjrMkTMQ%Z1*hD%f6xDgyJHWI?D9 z-vLF8rCxNmf#3PF0#bW1`tIqSen`07^DzICK7 zS15=pNH^;8W9u8b9Jd5ZLm88Dw#9NP>|P3`bdVT2^`e?#@B_u0u%MffjeJ^p@>j(9 z2jpnB!O?lQqr<;uG}p_!NJoD++1ndYht0qD$x~>fQE?DfZWm{!O+c*50u3C7cN!)F z{FJzDM9QVRKc(CFvQ~^o;JavgTyfNAG(d61(X3n zKI<86kk1Xe$F4#9oPnK19PhZK0cv{@jwoC)UJ#zmB+=#OBfM$S@ZpZmZ-no(*)x!pLlTWHzDJrxn*(oQh0bxwE(uSX{X4 zEZ0~I-hMoOtZq`Rx&3X*ZFOpwPNtr0ru(x(KU|K)P4x+#*ZS7%-8Vm!t6 zH#p2?twLssbc@5E{45DAXOGZ@ieWE2ZdA4M+_XpzFAP)y05PJdapkn$cV9?ipaGs= z+vaQ@GD!r5$h8wBH*s)nEQlHhioq}@#!D?-n6*gom{kz$Li<9bIpBgTV?pe=t_EP3 zIubp6An)1s?NcLE>>~CS3uPIQ0}gd;UxD4QK2?I$QdlrOvA0?f_mrWc!{>G%7R-i%oOfUB zN$F6>Nk9i=n7%5s|RBRQ9jH2-1V38`mUO0Rt@b&=q>3T;jTk zzKxH%8$Z;Dfl!kmE;ta3NL%IQNm;_KpQqaWoh#1PnmEVi1a+AU4!0&wYf1J_6!f1rKLhXi{~GfxrQ% z-s)#1ye)B}_8SI}>RA&gWr3BmT_6Z_aBDOGSPze2!Dn-wvizM^)xzNyVXr^;LJ#jk z`&@dhP&A7?({@^UkvOOkcK7N1-epb4G`quQeRn>~UIpCbPHe~u-}Hp`voEi}(ACM$ zZ*`Bgs?=u;;MoKM+>)rj$$<3BDQ;JChJFLJcqt-(@ zBIdsZ?fo$@2WIBPvo|A|e0t^3oC^CLY`kstF0kq;CBy{Wge{+LJe?7_Y-+0N`~D$I z9lb`C;iE+achKK2d%{q|Gt6^jzK~{a=5YQZvg^(9C?&zKK`k64K zChyJ~?_4M!EHvcGmNvk0KNxJ7Oe+a{YHbas@*I|g`pD9swl<6;+E^ffi+iEj==U|h z8fpYW>I|O}vAQd2!At!K-=0hxgOOCSNdx(oFW@&edg@F_dL_?ydhYyd_TXDd15S?b z{A1MVIr+IcQG7X5r}ymF-iKEYm@fC7pB_)_^E{AyPJt^2B&!1uc}f=vMF1&Sv`;9! zTy3M1g{0sx^j)ZSb6HUo5klWJs|W@QZ&%R8y;_NwkR`3;n9GWs=~dAGY;2|GR;(Z= z(m?EW4Y?ho!Zwh>#PT67$AA_b($U_N3aP+oibE>9%=H7780L*M$KhzByx>7ree`_n zsV^f3FXFMXaIL5%x@{0_&WN|l^te713#>MS5x7OQ6l<%w5>@k!O`!F4%9;%iM%Tougq{NF*3OvUjC zj70p2F03hG#f-(0*?uifA_J~ug&QEqmP=^W3r5z`?v_q_@~-wLk7hY}$&!-f zLG1K?Aq_0Ch&6Qp>vD>jpdwcNq*tu6=Wq0nm{FYaJy%Q;3DNgAC( z>5PGS^65R;=|gei+^FIllYd39Y!gWE_YKB9X}p*f@NRb)u@kn7xuqq3DXNHOog zJvQ0U5u1%9_pEy;r&&<3;aUdKTOQ5WG=E0cLKYb6VK$jQkmZ5`Q-J~1nx<35W-$gQ z4e)Sar!=O2rn8eM!G3)p;~Vhv6hnpjwY(%m$3kK9ABSFp6!JTXsU-2&h#=)p*_clx+oelsXBJ+kR zEw@x&mYYzAJ#x)o#3s-v#4TU#JWfc<3>#c=(BT=B}Li(<|Yelhc#M@BuL(`r3KisiYyA&9VPG>ko8er zq0WS)Wiq=Rqb@8cJp<~m0hCBAr36QWp`UGU!K_x{kx%Me9qWu3t$}{l^J*meVz024 zmv@)1Mwt~=;QL9@aiH^y(s_l2iw!9cm#mUZb=@fljKzoh2=lz-H0GK3sSv(E1m?<} z)vbm>i_zX`Uq+2aeOdrF_7R#-Vd+ziaeP^))ZD<|%_;1D`d34H^I=u{H}#U*TDm48)) z+g&i+o|wbF6h;Mx0W_v<{ooWIDknuE&D8^vr5eKBul}l$YYZ73Z9Ju6xq)^Hd0cd6 zKzOzSD9h>X=F z2QgIyIGJ%3BIRyo%fDn-dbWnRkJxqIUax`fy_7*slFRC|uXUDufeK%|Gt5l#J36k* zUHf8QK5oE(EB-!v&og&!>Y`$Ua5@_Zxe_Q<-8=(Qom_0OUk$MIC*k8pfC0 zkTB-W7&5vRVhwOD_@%9PCbId5fsl(z4-qrI?Jf2zAlVUGc$A#>Ci(D zo#N09L#If0g9wT^Fm!i=v>>Q780bg|NP~oeQUVeR0*Z+9e|f*059i(wXWetxK6~x6 zpWmaY0zDG*xkbHi`~L32y3~^xOtwAJ5|GzuNW#jQ(ZFd|b;=b5?J74{YB%-&P1eE%tXb-d}nj z^Q-f}WpofV)dv%2_UB87NSam<*B0+mkD{5xm>AEkR?Kf~u=){OR4ihmyZ1$KnUKEE zbAjsw;KxKq#=5#dHa0|vbtI9caT)}Y<27 ze8EnfT!PgW9V%M;#ir5)!mKN86f}=uQ!F- zFN_)sK$MmFVHJbUTT%0Fb1`j?d0y7-P>ry5ll3j*r_)HcV{x5&)@^Bx&%7817h})2 ztWHCo5?dNSL6mMG-v2_aAF4;@9N#GeCe>Ga;k3N;%W=*AOqw23i@wBSDgXfiW0PxNqYM{jMW`?dQV-paebz zYZ3rj6?ii^9fXIf|AgV!VE)1B<{Hq_0i)6@Bg+oh`%Zx?NFkwLWey-=1*B{b1K7*m zy2StvV-Q4Uvvvl1So5d=z=CwiDzq4Cwj!`14q4ESN!Jji2f`m>%@Xio{|$x$0U!z{ zc-;{Y3ZNfj0Lj_FtLOmNju2dC!puBGZZ9~G8GRdr_|yp|9(z?g070?zJ+3#ZaXEF) z6cL0RFo6DAaJ-ofJOP)J-)g}-WPVlaqe#RuThUWXIkO1YS@FsO1*ef8HCUXAz#li1 z1G|I$fGVdO8mA!507aXuV@bjzNrIPVU;!!^#ReNFyr;t+8^Ip4OFc_3U4Wrsv`G2l zOnuLaX3z`(&j!HJSIS<1)Bq5Q1Ah;e?ym-Y1*Gn*Y0J*teci^@nv`1ct>ht_{bM-5 zluwR>KbnLE_HNrt5hy=AlEXUdI}Pw+;wVX2YUNh@g+j`KM7a+NWt|C>OB8&?dC+G} zhO1ows;WSnX^8(?09SCi&d;0H(=abQG?b)hRRv(Di?MDu3I|t~%{e{K%dFcp-f_>8 zz*!<$C1$a5k86dtd8x^BYqvl>f-#_2@Hc_i10h$93)OUZG=LsmM917fK?y`c*68R% z=$M(2NB|I=>Pp1rJ|LKJnyGOKF5)*#?F1Y}JdP2W9Ug;brt?K6V3}0u z=o{!jH(c_iX2MKjnJfgEx#%dLk*uugBm8;1@2P|M@zeo7z5Hi*Jc|n48H7Hd@7#N9 zb;N-BFpW%jgiQ^>#&xqrb{D3^vJn;% z3>FK11PliHb|z1|aH!!p#e#hw_xOfu>GIUdlp{*h#u_t_vOPuY2+}}b(Y%6BB*=T(#oIu1c#=vP>#H;JEn8c0Gtd%mLOg}o>@6gy-25PVcPyh$?rKg_5 zVjXR)1=d(@o*b zk7M>*eJR8@|y#Q^%W+60(=q3MY&XyOX#0zsIj@wE3h+9fq~S2!+&)E!8i+ZRv;Y? zz(4}$<18{5fIt$!NCz&4c&m@FG)9=X#IbmM?YPUMY)em#LBIa5tKcpW>=WV{%6i8i z)@6yOEy0PQdUeB@dK#Lf-&piR{)ofdYGf;-^(MB*3 zfv5SFoxFqP+Q4#bWYa7VQf{hps^Ln)^OKtw@4f=ke3VMfd;jkK!Mo4ErrPCu7zVVk zM!=AQe3b*GQyyi15pRdj$g{ut9UmX_fp|Y8lI4WV(~CNkUiH|@Ygz12K2;l4OW>4UPKCh3pKH!r^Mpl_lONBVQ>8iH&F^E{7q1)niINz zOn4xjea5aPaqe8^Dhm0k${34*G1Hfs3&)Z|>4Cz}Tw|v$>CfHiTXXwmU671z=JkO7 zskq5**BSwrnrb>G!7+1Vb&tt@98dl2P_sKe(&HgK^;Zm#eMr4!vbbO;YnYVeXNE5S zh0YKd##5?Go3qGuEGZ|)+WWaArREShRP*93`x_t)K~8FuZukv7%>kOGD5^2!BfD8V zwZJOplbIrkjFR$XyU4o62M2RE?x#K`C$qlt8R7aD59LFd&v_=X%;p@S;ISm z<7rXmeR-R*PB!z4e&6KQhXOF44^CkJHY^amU`NMS2!1l7JeGDsBZ;N1B0BeoQ6GI} zJvLap$BUV%%3>*6{04tU4Uc`PNvQxpLe8!yx4XvT+OCC|HRh5EbF*99F`rt(Hdb7x z4q`F>3=_He0y(t;$GBf$@fi&`e-3;KWNsrQibq*0UfG7ovsy-K2n@1HtFoBit(Q&r zRC{4{3K|rjN5XF2!C88zB&{U4%!HrKK*NemAU?(QcI(r_A98xQ-MG>}6^(>wr|e4+ zn&;%)qB1}9UZkdCjU=-6{pf z@ncJ$1-`mpU7I;Bw}YN~<|jzfO^W5mEYj?6LWoZNy|zW0*BSxCtYZ}`ZckSxDzM4A zHu5dkKx=@UB)g=Scf;nTZ1R2Q0(6(Ndz*`VAC7QDe&)D)+51g=m&on6UonD_rat=j zxLdJ|sU~_J=AWAXB|wJ!ZFuN0M#G`UPw9O)Y*b6Yix5=tS}80KW=De2yk7fYw`LvM zJnsjU1W2N2l>dX9vSfx3L13GwDxqA9-Q^)2G2=`70?Mt<90ell(GwEiH!`TzWGWA^ zmCNV(n_DMlyioJsMhq$`TMDV7j}9%KOfV^3#Q&yZWau>U4}JQL_l|#L-K|1F(v$Ch zl00Xe>))Y!f5B3PsK^k#X=9&Qr!JT#DWmP%#`|koz-N6=KQtst^FS_ z9u5UQD~vOf+kMDhV7eK0@N^?Cvv1;=^k&Pf$n~C&Q__edMsbBm;`Ick&w;fn3BLt_ zjCguWuIvuFbEMIb=ZD}rCy9E~eXG_gE7?~G){i3|00)mjn*O=_Go&9#H}47RBVEge z(q~#}Nkz#Hy8g{OpQ%49{ga9zQ_JM_5>j^7uFpNbBeR{|Tef`Mll51Juhg)X_vP6< z-y8H_u1iuBWzmZKg6Gdb#+Mx>UnHkSSF9h%OP{?-6N-`G~#JFBrZ4UTnC7G7mixC$JJaKkEONpV9oZ;xwDo!X)sZHIiF_+ z-Equm0*1CqcCY*O^Xjgw?H#oJpr@Yit)JMoNzcqTSu_}zNZhyo@EGyfv`D9GjA;l0 z1OVWzSej2t{!8uk9vn2E6nX;Z62U?Wj@|y=1BV5E6Oy<5L#IaXtJthiU3ox>d#)@U zyN%=sm^L^r|MVCykqg>hSw8Wat`_(~j5ckt1u};I8M|%BDsk&w#Get9u;UJF&um-DN9R$cQiie=ZU)9(f&*WJjY z<*B0InXtbvQLUDfrOeGSVwZoczCV-=2u; z4&(LC!cn!gqGJ^~8>_C%@{jb>{{b9pQT>_Drey}N*ACDrz1YppWJ=xT$)ub0u1z>- z-9@uU`H$49;ds9$db`F7y!Lg!D?m{m+MgwWanN{NYWp~63RmbnEi7D>icA%F*b<%4 z+}x?b*ev(bUZz>r_bna)ZPyP5qbNE{JzN^ zw4Vn{Ut-O)%bFHkj@N}gQlmBnxVr{xv=uZ{a2;Mn?@%Q%9|3s zg5gbO`!%4)A63&Nm>c*wkzYKEJrz@Iz^mU-tvrc(RGZ5=CQv9}*f1fxz9M2$y52d) ztn`*a6hQe3;f3u1+%&}dFSSwPuY;Mz#BmQyM9chUzvYPsdjfE6h8+uc{hpFv{<_#7 zF{sA8AHiKfn$|nAubeEI7Og z)_h>h)HaX`e;vZZ#xpi^XO)Y=$u%`E9tyL;oBzQSng#k8NZpZ6#rS6BHZ*RJrVlgQ zcvd1sS~gDAqUEdGm$#eocwFop=g~HY|I_D;Q)-llj6Q0V*LO`%{9#V@SpvMP zX@$u{1o5$y?rV!zAPgkQ*>a?$EX0zTlXAf`j%m<2IGjh})~-m9H;(Msna!*?Ah2(j zK)KNVQATmMq(*=tfpoyLK94HBhUaxXQ5F#X~6^ zavLAdnnIQHa!qRMj@|stOkS82p9fmdes*>&jv*~8Bjv7mlhfFe-gV#l83Qr1S<&7* z%%`jA(OAA)*L*xd&v?5w%6p33VQHb{94)7sc1|WG|)g8fc{*6axRs<_Q~zf zrQ+*mh&d>{-9o+}$O>W*@d3s2^U;2Ib3T-X)uVjp0tzOXHdxk+did0FN3tV#8w%>` zghOY$-`anWWtBVs&>H%uxtw6eqnQ?FbYXQ;3*Z!QeFXgIyXl5KL?s3MVWVM7{ z-j^86R#RJn(hx3TWta9h4;mC-3P?*uJT6;JlWQ!FTjDY6)&Zw_>!!{R722l?AUP7lqo@YJ_@dQ~)e*Ny9Vl^757sZhM?stnV>sEPQP7x_?>u&v?z3 z)fHP7F#D}{_8gKwb5s6=JiGsI-!SD+)?G$gH0{0mW(#%TOIwacjq^;G zYT%3Up|1!RB}-o!QPrIp8jeOfu$%qaxYnge40h2-dS7>Co27xEtf1t=zU#T81JR|a~JnV;X5&H|;cD}SF8M0K2+p;UDrn4h@8 zK*tR##(QI#_U#Y1JFW0|U}`3qlSnTzJ8cXW za!WramQ$>Bc9|$UhP;>e{t;CMHyHW8ZXL-G>DXRhh%EaoyWBvy*!(tU$1_obIe%_T zNR5_Cx4DM_RBFdO?z`{&I<}ZxNpbUhfHfu?iUV4en*Y)EylBhlEA!f?4tZy=7upus z|5&sjNT*9){250^>)&_kxO|cAMy0BgxJ(=fB#8amVf22Yj48S>Y@bZH)1g8Cn%8xM zQ8#?Di(Pd1t*wK&DZSqANB#%HeRZ8o+`O8QkrSJ*yhU=P?6?g z(zqr|Q_0T4^fR;Sg*=13gwsW)fdA8@Y_ZYSrsl zY6-oCO|k{R>!SvJkI%8EX4g&UIv-sz1ak9`Yhvw3C7N+^wqa7J4oViHl2(e`Kc4*1 zZ1H;|>Ne3s`RvLywTwViJI^?}frI&)`)i&SYJ3y5vp0>i6wj_Ntw?h_(`@^WH~3)g z^|y-`tmozaqX?Ic$6*}L&Nf9R+YpE5Z>|8E&lm*9%n)-vno$U$_S^w7U(Vl??7+B+ zKqM+c|IrX1DGjBnv03xN7v8%!z>G`rb;cr^NvX9BshTY@8mT4ItuiGoGHhM5CnTeM zy?M%qjA7TwuP{wv*?qdReVOHywx1Z!Q@YF?OWC*NY>o5_F6(M)31+_aR-;WDx%xYN znKvWry?wGoRYdkKXb#L>+#R(ywLWuMonIFI}aj z3YE%uL~6+%{JCD+2vAS$99d}2V;qNtv|iJ2kt0W`qtcBGFGjktO=}MNn^K(M+9~ZEee>Vuo|gQ9-EzrjBK=ZGbL?pH4K%|`WGjS9kw^Gd z7CeP%BsMoWR!|Co5ar8|LhOy^D$V8+`WbS2QF%To89?Np=#*k~Y_etE4dk>z`N-&t z5#^kuAVrE0)M#I8qiwBJjWE@JZ2H}i&*wBs{TnGc=8b3$@lS+bAd6vLW{F?WGaCS! z8C8Lg02=!o=Gl0C7k}gJTr*L_>NhU5&ao3G&ckjinQXZR!3bSBm1l>%CckP$d|wU! z!%NQa@X8Zo5j>EvmL9?WH;czN!~%*~M_D6};i+gV@)@6<_e?`57D(Tp;LusQw5{B8B!_o_qE1A)48=JiAL9DmE@RCVqfC( ztv4HUTBLF{#4|)n5!dro5EQj-MzsGd@wbJIs{!mJYKt={{ml%EibTi8gbi<{r*IPM!fMNy`9I<7N+0s9}!Orwqa^B!7OY6Y7QFpm&&V)jD=vYn7 zg410f*Y5CNRE>v$$ygMr-J)ZqrM&$U=VvCa&!@ER3>7@3u%og>-{e``Ihf}8n}~AW zd(;pOQubl_;{6gE6~pGc+Cl`jN1{m68|e6WGh1#%C$SOoeXGJCa)~@Nm#nY1q(-p) z91GVtBBmVLM*bx7naQ3H=H>zBeb2M3;d*D$h&*UX(QUgtd@ezjt!61Aztu1QRV1Jqq5lM&0Xl2{ zRuh0U&H!%b3p5Z>>5ME~Lj@z5vKg6D&%y36e?^qUZ$9Dm-q%(JO*jMvk?n7q|=7B(VTMwHU58Gc`SNvM9#;=}@U%i51 zUL+5v?_ZsqV7F*IUAVXHB`Dk^D54ZS-Ap_^0=GlFJ-suxJ)K~o*`86Y0Ob_GNtaWg z4m6PL8BF69NCORG*$L7~FvWTWPR0XzDFkD@BAwD}(g4OJ@ICUCPa@HDgs3|0b)DoD z^V;kB`OZC-_^U~c)*WLy@3@7XnD0B}=wA?X@7P<4iSAgK8xH1#g*hq0-1HKiNV^%^ z-fnQ8%wN!4GBo$|ZpOl{o3l@*^|y?|Z<*WBEB_F7QmjQQM2`@!cl1pUzE{cO`!F$H zHxg2#w)fC!PZ!`@tFu>Qy;mdXYY5+aoEdMZm;h7F+tRPJ@lN=DyjSlHeG2pIkl5eS zPi-T2)+sW!ZdZ1aeOt+UHs^bc_$$#m%XF-danrS@*kz_IF?N%eIC& zpC`Q0@wWngd$j;{Dn4+JWX_oMb3bSLs+YKOp5W=67;vQ-L{oTT17h(T4%} z!vIvk2SJKZy2N>wfW_D3!^NkE3k!$yF^2)uiJ;t47DI}V?9#W26tylCVYY#O!QVGM zuSkx8CINws^??!2a=rM#7OteQb68L-0iZ~Yz$R$f#%ndkYvJRyaPeBULBBnJoW%tF ziTLp+=EtwXpv#4z%kMwPom<6jhN=ITz+vitYs9Z?c;9LFWWf4xp*ujYC%^>|xE2_21$)%b3SUSJpRYXC z`w^gL6JWp^5TM8&hD{2?pIJVjY!NRF!k;}fyWL`Z`>{5EswDvtMh`0H2q51*c2UN#Wz;&=cB;EsH7FvSPRts`2= zJ7G8Oge&}x`3x~50Xd7p(!N8T){e)zk8?9mSarXZE*vXn{VtX8LA^V6%f8cReVi*F z&f62pAGAjn?eP`7=38I*^I;%FDC_*8XK17KdHw4>y=h;0n=m=aFl$s;wq#V7{GU2P z!Ygin<)SdB>0_m=sKR$A1D{V+O%qjqgq8m|Df*pI@jFW8KPYEbloR~W&wS8b^tZ$I?^_gwzgh+y2i3*}on6)MgMxe?MfmAL{I6a9jS2c)8E-&$6hwPx zWN|!7@DA-xFhx)F^|d3y=cBN9!D0VFt|Hv9&T-L~UFIF{sGx6UIzH+>$7!!aP>X(r zJG++8$v%WTQBews12Kv55BCJJBI}3GG0)D|gvc8=V$ymd#ebhm{s_%~K+bs(lmE!i zwlz$dHdOW6!K_UI=Z%Aft55qTrtr%j^`fw-MRMV@-yA{VPPQ=fFL$5(2xv&UFiE;t zd>X#|`hiK$MdQPZzYp&c=o-X1<->N6rGGsqKRyqK&AAMCPM|fzSlTK&tm)U45?I7d zj1*=Zd&2~UxH)$KfcF3fBV+q~Z}XZGIX{!o_+7!N%IkM7sF0@(yjuCYkk&^*!gCEK z4>dAGZi{?)Z2io2;_+?K#iveh;;8T4{$hSlY)bwp-b=jF*#FDxRet#QM_o~C{e2w^ z;!djMyDBNU$7zet++IbpZGLSok{lY%R{DP1|7hJQoAN|s`+c$0@G$o8g@=FW=DSy! zJcbSDN0OY4V(O{KiTlcD zdvkXBcRcz&i0-ZGWBk&4J3Ve~2q&qn^e(OqkK7g5*FImoIBU-P)BnY(Z)3Xpo)lvh zwjbM(ArEEHTa*7pg+j~pXXmXEsTnZNvA{saYV0Q?y>%j^nj&7G#%`Wob17aXR~=Eo zNR!4NF+Z&#^n4eui?Xw1&{?RPn^9ybhY}!-{Jf0Dspql?yyl-l_q-IUuUp2+MjI4l z^WS3Hg|-f%%k@RK;@BFB-AwB1Ej*#i08Hdohz(EVw}d3_`!manWs%JNi#H!aVB=TB zQ`j}hEP=u$p9Jn-J1*IMMMlvZ$GqNk@xq0+ZaV@nDy(98jiY}ds)!?`>)WqS!F`7d zBf*1EFHZh?iN$i!senf}MVA7K_QN~(*tx{k#k;xPlbVFSI1fKvxKUg zYiUyv_x+!8M0C=4HaLTbR_k@{jooZfEP|>T~nRy6OCV zYKzxlwi}pHVmV7T(`EXHa))3?!x@cJFdBJzmKsVPcvgj`t^B-cAWqFaj+5Lz!k6dR zK5AYaWexG`)_#Nz{4nIneS1~gi#z%-q2pFmNP7xK{F0&5XV|~tb8Yf~+O>C8tIHZ%SzQUbs zuM%Y)6t6mrnF(tkZmso0d)s+)T7m6;t?PjpjcTnfyLkSzrU)WX}ud(Gr+#i~h$f8kX} za@LLah{|c>?s@;>#=VlQ0?h4I5(IEvkIhO_{X5l7nj!}tuT>pdIlE1M+V19ZJVO$@ zHfZiRSEmgmz=E4|tnX4KT{F;6!x~V2g#XDC8#abXpSn4Aqvn-pGQKMdcldFS` zpN4Mx;=kgAvV+GZ`1}6qrR4V3W@EMZs7GydFrm43|9t0%{ec}>4r9yEO@b~=V|kq2 zs#`o722+}2?^<_;75b$zL&K4FofH7MGY^T)+PulVdEJ+Q2Ix;E`wyJ;Y#$tvY7@%i zUQ`_q8|)IX4=%K$l{-pi&w1t2d?thoH@lz`6jm;N&R|Bp$7IBqj#a;Y<|h+?0;Ps7 zv9*ro$%~Uz6o!~krcPUTca;67>a40!ntK;WNc;l+J-%;*#ouhXu9Bxn7a8?>i|Ji? z3a#Lf-J2f)?~-vFHEHhdy8nsHkeGNG;=YMG|K7N%?&^i*{^KnmZnt#3Kuch=J|~J< zrP5upyRMRR$PKY7=B2W4*SORMd^laJ`QK8zQrlM(ngTX%fF?MTS5PL|{nlo#RA~*{ zV_%5^ek-1DZ)S1gc8MGO;2|E88Py)kzJ3RVihb!_!SsV%zfNUFsVLRnWaRstc9c${##9H*`Dd7m`ZV1A+s)l2k(YD& zB6nU4q&f=D%I1GFbps@EKNY0x6TbAVD(XW06AMeu6}5Ts_}i_qgvn42Uz-O#O$(j! zn&>q>UHNThn&eJ6?{!|34%#()#Tddvqcf@%xu`-E-_p8)B(SCwB^$`nx<3E)DCPaR zX^g#ohZMJbTN<^X_(bop|8q9qFSCL_jAhB5+n-9NJOSx%QG(r%T-*)C6HvwcQw0~ndc%`7BV}!q1-kBa3+yuje-?OTtF<$-vOGn7xX-Z6?VSg$>1Ro>Z1`{-ldN;-^$yJgWl?)6el1Qr#pV;%1g=j&>Yx*JW4e}Kek0bch%~OmO z?@axEnc#*)mact?TPzU&(O`I%{wbI|+iomODTygoi({(R-} zKtOD=I=wX3?oEMpM)O%BIOOPX%O~SyjJqy+hL`bn{$P$}2>*3_@bUhO=>qdBAVMR0{4zqrGLXIqmg!p$w<88^&s~Z6iSs2YZ8h zkM%QV0q33mric5lmhwdc!DaZ*iH}}C?+HAYT>XN@n;@7=x@Jq8md&1DsaE2EI!Teo zW1^Ota%&oQcQfuoOpMNqqr5-WuTdZhEZui!UCR@rlh<@V;J2J7Y0Vhv1JY{6?T1`O z<6~R`kf=GgWU3ic|?zaEXdT4Y7L_`#vAoH z$@)f9`U`{n2y;xrNr($8O2p(rHUMUx{_vHR6WHp*u$%*Niy! zv?m5f|6stMWh=c$-g!~w`kuOY59(gQ>D{!C&-f|^pn&5Y$-5TXHcH*IU(MbGe zf{rhiCL2nvdj@jDRMw)>qIRb)&$4&}%z30?*w%NtPi}cRzpry)?7@O%2Mc6UJ`=r@ zpSPycKlXPrW~!XkZ&dGyMr~0At}9XOckXnp|&cyTFQ#WiEVsuv093Qc}yWQ zU<{QJ{f29AzAb>&js@ch`cw%*kBr& z957LfMuuFCmT@<%<=U2)7p$}5+`%Nr_^{J+YdvZsYT0V4JWf^%EoQ3rq;b_e#A>Pb z)iM=m>A=;qf@hL|IDi<{u~yyFrX`~#d#3O9(`WI)mGq}#54Cx{LQS$tWVPE@wS{_z z1h>?)-mVJ`rZ`1|I5&VoYj1_zy&}3tuU+TRUl@O%u0f4U_1bk`*h;$Jmp^?zQ8ld# zUuN+F5OdqEU8uY2&QLtk6EOW}X=Y#Z@f61ISQ9kQ)QGncUSItrwJlIQ`KJJ`Em>9 z$tK;pmwL0Cig`Oma4E}V8CkeuA~(G{QQp(g#T*{n!fgL_(a{b}=NSLS9g_4!?`?Ln z9vrBGiC6iarWHM)aNs1bs+GB0%j7~-u*ETgaDfsUS}ar3)D;6p8UlD0{94nAqUk%M zx=@gBmC4lXA@ug}dPJa5R#$aI~dCauHJ-oTc8b$QdRLuwzuweNSrcr1tksq?lr`TUuFd+cjeJQsaGClm| z_>*X#Msny^M6yTu^2QTAie!nkCt8h(I!PcMUD;$CIY63QRiZ$}p6lhPpcQ#y9k8q` zHN0-A<8?WTZBKgOo|~=CEJ;U{!LJZ-M0xk^+Mz1qkRPB(sUak|k zum(QngDTLW*QrZBY{^su@uX;J9i(gdy{=V{A7EJ8E{mZbrh62mHd^r+@|5l22>YX| zcK`ROL5GY1d62g#SXJ9Yu6=r|g4wGPQm0Jav~wCAupPJX9R31DIrl zCeDyY=Y|D7polZd#24l|R$TTokcowOY76#y{&4D#mNm~l?=7=aJbmHt<(~-jgE^SH zS=7Hs^o6VV>;6>(qOb&7L=bJQit{xWO>h#H!wY!Y|Y)m_uIvWySYSpEzez_v^x4^87wg$seU64OkXpQ zs1F$e@f7=_lsK^ zJDh&-v!&(z-5C7zDp*;*ziBZZfIk`(s)HU zvuJqsSFuXhM9(DK?iz%<$Ldc5(LnF;5m)#%G`t5CiAR(FquF$8S*>=a_VR`q&c2hn zq}W`0=hv1G)MfbZ@uyG6Aeo9PZ1?~zqG?D8E)(+p<;p%boVahj66d~67n?TBoGhQL z$s`3)(V{O(9r(@_znA?@0j{o+yZysA{whoyZEWs;&bc1&pVHtfrJISm$>rH62kmXr(98seyX% z1~-ceR$XaiKrvZUzmZR6a84n4Krx-DdJZs4BYN8pD4Y|_(gqH8lS!AGEPpk z6b^C#^pA&wX#D|B3IJMss4zJQ0Hz`VusFECv_APvwCLy5rH3n;7duUW<4F)p5^|bk zZ$2y0NPt_CAb0}&6+m}+v8xXNLgRerC<2spYH^<%6kCOEf&`-p5DbZ;B~Ag%{AnH- zWJsdG$0;nvf-pUylmyT`5I=fzvGa+)>^r37nosrA!)R(af)3h0#NIU@KNT7xb%Ll@xmPk;300_`aO*Md}8<4@{Kvm~S%>XIK)`mN3x%9pYH1yv%{naW;fJB~%%&T|mzJve>!jAn*@?U{%WNNF04a61! z(F;Q6lYsf8t4#)`1A5;F*wnN}6yYLFuY{J35#=~2oB*uCB|qJ;QfsE_0ZIHRnN7Zc zIFjK05x$xdvNUd23xX#TfOwolJWQ4sj4f9I@kdI2Tx`WY(ReSgdzX?(MO1JEfRYKw z{7cGku&k`6j5nWD)hp!4Wy;HN1txIwCjxaNf%+AIE+1dVnC`0Nn=){vO&xc@ z0mpG%K`1&~q9Xh`vK9BCgM@lSoM#14ECDF^|0(uvj&iX)s?fC3#bHjR1n?TI#H-(1 zg{x61UyG_t;T{(O*D)}7g1Z`(at6QU91WUWI%<(4s2ooItiKd%AC<#IY6t>w@Tzt} zEP(swmz#hKkawI={7+CL0+R;X%mcxxaGE}kI*h%}Dza#M>ZDP<@K-EUtuLZic08HR z{l0>zS_ptf!o72i*lPgT{EM#6FL$+5FR094KB4AohtvPlPcKxE$l2 zx`G51J48++9#O3|()o#=1%OIPa3cV$P6in)pP2X+w2eccNbssKq!A85*hQqP9Mu9u zlNVR}gC#&(&DI~n1vZD8i=N%;bK*ovWx%MB%mgkAc*|lNEB(D0TNfM@n=njxQj7+v zr#rsM=Gpq%Y$F-p7xTveX3@~*IZm$1*t4j+r{{NmlewZJ zk2gn)6drKjzk9a7+@lZ_6n+V>l8;5Ljm|wXQl9Eh z)E1*Dj$R-hc)3~2s47dotjkk5?*(TW%QE4a*qCa*2|D9zfW_`H^y>sx0&u&?Ej_kL zFd-a=i+4;{f}wmxdYu#U17)|Xu04<%VRcIXHdI9n#t$**p;I95E!FSX~&JsSD<<^>EwzPPT_|9d_SSXgzDC zYD0q?gS~V~q86QS37c@QGX&z^;=_{=Q=)HIVtb)2R9WnjSnld9=2;w&sNMu~ttwe~ zRGEC-&Cv!{ybphQQeiDoW9gS#aQ)xo5 zv~&veS_39pKI$b2F?M>qNY7Wt2?%R^gT7mgC5DaFZLN(rSF4ziICl#*%F17K2puI) z-Zx`OviS8XbjnaI8^EX_WoJC8xAF=SDJf}Z5o;0uZgxUkYI$x#x9*+!#kU{ngQgbH z+h606Vz<8*Fq&hXA-cCh1lXD6wb!GWklNMroCb}g`#Q$dOw;%?(=K+8Y#(!;*8mt) zY)8qhcMTxXm?I^~n&+lU$EHpn+ma0g)8k2e!wiUaegzepjYd}Sq;jxHSV)Y@gBMsUvc+ zPN&JW^RT{1)`SPP4J%sWuRM`Y&4bi%@K1(W=LM~Wt`4@>-wG`1rb4|4FxH( z0BA$$iunh4O)e6oeeWQ4)j^C+$<(D|gQbQmqYO=olfvd9NDDYRs?X4(G;>ox_n^rn zB6YBU|KlSLMc;cXd6qPg0wO(U6+|dGvC2LclpSixE<{GXh3Kpy8Kc7?XMDg0eEp4o zUujwX)6_G(D@8(Xf%vG@NpRnO65E6c&s;AqT?<6T-YR>0FIp(yd-esp@%P*RslX(4 z6rZ``NuZ%4eFa-ZCRaN8TjSm^C>?I)mt3Z_eIOu?)A$>t^KHul}!XGh7 zEKiQ9uU&bKgZJN4!SF@7E`l6lRem@7Fpz-a5G)z_j!O~^$@w59Q`E#ac7%DjWz^3^ zhne6H)Jy`=wKH^910pdL+e_ z_GN790B5umg?uZ|JH;42k7MDC06ZmdYrKJ>1P_464V3Fwxf=3RX>y_I0Km0$`TX-k z3jDgXk#dH-ac$=HN{7I(ha9WlGQUSOP!d|B;($xcW?y2!secmhfT`)UoT^A6YX&R1t!Ch!F z)aaJt~jFqmD)6DX1q7~loBP*PP}_c@ltu1URUhNY)+TW1_ z;~0lvoKUjOIv}y}N z_(2hhsDvp9fE;fd7u-5KZYa~;e)qp0{#|Q#1n{!~2-y2{m%N?vStQejVUZWaFNdemeUR-rhE&cwDY=<)>V z?xcDo>Pxcc=^|wUILf6y>Ql<@1WZ7ELW)urrBS>m1yFzlFu);5pcPU@?Cz%;S|O)u z;w5gx7aR-*Frp+7K!Iwas%Ro8FbEi)Bo`d)1zlQt8sv69O_sGNAxKKokTa4@BVu3P2Pbq!0!nM9^jcLcrcWAp!>n z4*(&WMr6NOC7Wg>R%m3w;;=~)3?W8`0^-o+l3^DpKmZKj0NUy$DPSR-#7U@X2BD-S zmSsvT0ivV_Oca1-;6wp>aOu9}pVZ_y+5}DjfDU{Rplpny>ZDFA!B0TtQ3QfesEm6s z!2SRl#RT%FdnSeJBn1U>-~bFj0Mb$b*3wc;Knl&!rt&8S3c{UUVk9Rgs`L(=lqKW{ zC?XbUfDFI@5P&e(asn3OM_dAc>h2|6Lh+`BTA+a#L?8jWr5m0>1q`6lh@l&@r5m^* z(}qEu5TF>;LKt>}8NA^I3P1(mh4jK=Ug%|BmS`101~3lB2iV~p*x`(1@h|>@FVev+ zoWNYfK^!nf1`1{zWZ;S(3yz5M92BNx49fzRk2I3Q4q#>gZYwoHKxTx)4mPP0D4`Ni z%Q!5FHpcHbP$7~uDI1p~+`erc;gQ_z5kK=&KbLFW*iB{J4HQ1%3K~#stSbWc{w)*C z;12$80Th4~0#XzffB{HhZzQBZH$ZJfBt#qpL^LGfaLEE&Krv?m7&7NqoN5DkVHaLt zAv%Hr65s`QdBa0_qVHL}>uPFyaMbps9i)C2C-UV8R7ffJay0 z0?4OF7ig<0EJv~lCR&9To?$2Q1sWnzD7v9227E}C@_p#cbhK0pBk1ONg;AOx!I zZam>{K!9U0bOS&^5HwOl@j$*dazh?R8D3DqoazFo;(`!h1#V)g{EGq%00VAR1Xkb$ zGQt^xWJdl@Mow--WukLnC!6TWcJQPT0%~_Y;2$I)0G?8JxJ3SV{()-i0LAzTOU&d0 zu#`+9N(r}=>6~ut;zv^MbOI)T1T<;_qRhu80Hg}Vez@mSxaWPOP*6zaeo6&V%J3Cn zK^G>+x8CRk*4R^R|)fJGWeR|1F)Wr8MRf*71Z zHK|1yY5*lfKm}%21~~7o;%Zn_;B^7)1-hXdY=8n>R|VMWhq7h#4vkmOVp=%O(`c_U zgkT(ImILgn0Bk@Ad|+mM;2g#wjBNJ;yog!TAvp`+0$4xpxeiwoR_1C$b0ffty8*<=1d zK@adC69kR`-m4-TU;qL#ym+8uEBJ2sh6gr)0SG`sLm)pe5)Yt>Wk*E6TEHeMj2D8T zrz~g!0L%qiBpD<{BxoQe5g;ZH-~cYb7apjmdP)T*AO@Di1r0(55zm`o?r9^TN~|QH z!sIyUAQd1XYrP~ARv|WYqYh31DuZ$rax4{%Sy5mMSS~;CB-Mz%D=rgn<}_!3Jjb z0BYAN#)7Xs zyod!7;}$ie*Q8ThKZ6-ZBLD!YlYHv~AV2{kfRKa(Lz}G*z!8jtqa7&$ZWJH@0>I~{ z?>P)uXUr7$OI~H~T1q43=v=cUg6E*=9K%o;jVWRcJLYqlMI6*%|;iBsc z4+P;3IDv8IYXVDpL>xy3Dq^cV2U!G&MPj1Dj;g0-WJV&QrVnCrj3HQPq$OJ7Ms$+G zT*XCrVZ+3D=CEW3Urb5?ib)|#N%QIcc_1oFE`f{Hn5(N&da$~Uv2uH)!35IhOgW0j zE+rbGEC;Ue1ll?W_!LoGffWFytpito@R}7;1yB{@!k$DSScC?EO7J+&M!+c|b~>?7 zBqlCmMiN4k`%5v=%td74(7fU-J~J4Kff|6Q8<+wr9E}{BA+(DDu2S4jZPz%1Gft*` z0U!cG!DWQQkhBdIZmV2VquGQ5y9-GX?BHo`%M?(-HMCo22wFMplcC$&y%824|C9c3 zi4!XNnFOJ}DKOy0-P!=Av?z;E<^e>5G`bBP*RdU&Lz60@ z5}2boCgD8Qv0T;9y8dH}xR!>KXu}Ua38CLx)@Pj_7uF&}LqYR zCUW`EoS`h3A}KJNgk;+*^vZ}NvnkH%tVSp)h^P})mw1QS(1xM5jubr| zfZNcGQ984s{*C~quy~C#;>a?DZ?vMjG`ua;p(FgFLzCpwxB_-Q$sRfgTHM&1*4y6g z+izhTWN__y$|i?cNL#K+q$G-|SjBN{qFnrpM?Wf0U+I!CqSp9MoY2MvK2Yj9 zrONKcMP++}+)+$G8pO`*LWSSS4$A~$7G{TZU4+{IC&C-3!XrE*JjbRV$eVtI!XMN4 zTZMF~{p1ucU#6uenqssqk-*iGiDDUuwgrA&D=R4)`Vb7XD(f~bLPy2BY5tcL2TnJ0N4m1f~iD{5=|00 zX_BHuC`*n+$uecjmWWU)in;P7%a|!A(E)HzpU-_hg9;r=w5ZXeNRujE%CxD|r%&ivK*=jNkn55GP<`sdXw^9udASFgdo41c!V%NMZ3$Sl@hV!qh-SYy4+ z=gWSLAyeReh#5v%FT-rZ%!L<{!;CN-Hp2`#9y+5Th8H&D;f32kW8sFvkjTt7EyDQX zio#fEp)lHLbIn8N^aznP*7(?Ckl`3KWRDRUdCovRJ_KYz7bQ8+L+KDX&I23;;87(r ztyGgsHigMjNiUH}CQ69lgeFNl^>o#naKRIf<1Ow zf}lReOERz~mdt9fS%S%JxJA;)ZLmeM8zjBqMjUL9Sn>$5$1RJTZpxhy9eCkM+lnhD zh?iY^&|$Z&d)HoDo^EnjayIB>qp~^J7@1@`OagfhI~fVUkp!lgG>IjNC~~HlCyC^=Of8Ls2qTH$ zG>MvGCPE1v0px?{*I_WUUjWRV{H!JRU2OJ?PV)&D=`%QnKAc` zme^wmf7T1)4$4STA`z)b0u^YalqD$~>42cihV+dp4T)z9!A3UHk&Y#0WKSPa z+DJkoCamRTX)i&M^%Eg>4#f z9M}Bnb*FP(ZgLZx+L*32rYqJZVs`^+0qF-?jBaS790FNVLB8QLm6;4mPx=u8tr3oJ zWYb5}^ch8%M35k1!wDMUNCZ$}v=J(zX=?h?n8N;~LX<4Rglh`ZNwyXMd))A!01c=> z2WpfYb_5iOQcGO!Kt#R0B`lmEB3|-8d5$~}xU^%)80g}Ql?iEoDl;FyWQ7o_mxU$!~FMs#VoifZfB2s#Zf8oHPw# zv>U4kWpaF!fgY&xGp|!p?ya<%U}+(n1hlP{(a;YEO_|@6!(Icgo?$t!{tL1CDo`kkHu2Jknm_E z464N_hG3*}kV*NhpvMHLF|H~MX+U+1GCJl|!C1{6mjww)2sJjU!*s8FgWfk9wGqI9 zZ*87M-`SZ9Jl|p@xoW3s_e3X>;L0x}tK*#fzJdh0&{u!*WuX2XY*q*&&4Vh};jwZU zVV*hZg%g}AWQ-55vE0Urr2Re{>6OGEa#1rDh9P5G=$O*}5H3;lOeWb3XF5hwkXGgp za9YEHLjEylgOm*+>}-PB;OsX(xDhR}^CVtst!e=-a4@M>CNBhl*T&57hCBS9293ZD z@j}G8822uKP>b8dg52T$5{kGEVHdD54aQ;ZLKFS6H9nT||?Hfx&D;mJ(Y4DVwmW5&} z_>^0+HJ&{D^{|h9owm{y0DR>wd{K*U)AB?@CCV&t{=HeAxQXRn$~1Og&>63HIm#%y zK$nBerzS*Q=YRf}R;eMMNn<5m_4eHR%_6mMcq)EQqxY!M+Llyzw>##XU_IoCf2@~B z^{I!41j-l{sS+fg&LIZ6b)_$ua#9M?IR=XN18?XSisF5g?$FISEo4pt2fy#2ZQnRNhB^ zfVevCb^ba?)ko5@E%)^ttk52d_>){9M|IBu3(jVDBeiSP!(ovVQr3eS z1F~yjcT%Adc4O2kzu-#n0%FdPG5^zT(FShOCW{b5i#8H%)7DptM@wUE$ZQs@E3oQXgeYq9@t?ntbl(D z{vsIpf+;ZhQDW3C_98~86ge%~lK5dO3sObAkUr#)BL7n%i5E;Tc9btRBm0w-MOh;i z!Xh+gVUg9)0F%qpMPhZk{vZW79NREIRm|wPpK9LVjh)}>c7RXhFR=AFvz?gb7H=RId zZ`N^9ln2bk7&^ConbbJ~sC?5yIRhA)R)i_{F@TgaVZcxfEx>b_7HYymEW(jGt0R%M z317h>8-o~;5g9G-_nWk1JlSC_)&Ys{*9zJ4o5#6ownIDAqCBkje$B&Dgt1}%JxPk6 z^dHtaVG~w&Bjq0n=#n-$A83bH?ZZn?*-I~0Aw+3nFZN=>z@G3qSiBTW&Cm_)2_rc| zZ$L0)5Ya*Z>5K~zK?5o?41qEXai9$$md@BsLb5><5e}pEWJU9q@{}gpSSI)+aNP(d zDlsNr_LqV=q9htngy|Cz=Lu!uTfWDlPc&z6As2b^qGv&wej*nP1yO&IXVB#zqcUC7 zB^in{DyK4}qcWtKQ=~5EAn&3$w&J8is);pFQ=-#!^Tku=H-6~Vbm_&Vrh`-|V4TXC zoWN-U%7dKBNt}l`rr!Y_!|9wRV4S@}0w)jy(;ykjz*1qKVR2B1q)GCpz$4i;fR-@pzllMx265el$Qti>fHR5dJddfb?yVS<-6 z;Rjw;qR#rP|HOnj6aWxF3Z4K8pm43(x~<%*t=@XA-ioc-+O6VRuH)(n*GdYaKm#=J zAHdMA)Zj1j>L0+63-Kzi_=>Ohim&v#ulbs<_UbRxumh@)3I=#-dBu_bG=BmR2=ADgl%Te2$Ku_61i zIWV)hpbYK$uetEA^{TV}lCwPfvpRdT?E0?7P_#ySv`Cw@N?WwVu(VEF48x$bP3r^W zAP!YK4p^JDSi1z`V6|O)wN^V0<&d@I;I&|Twq`pHLO``&i?u$0PSpqiL}N5twvAb1 ztXWf+EKv!~3ax(ow_@{`_)vS)+5m=oxQLs$iW>ond$h#LWn3jqm00hpV) zm|Fpw+qs_GxfAfYqC2{ps{j&kx~QAFs*AcGu)3<-x~?0$5&*la3%d${0TnO-xmy7W zkh{98yA{B@ySux;3%tL(yS@9n2@t#!0K5v|yu@3){+#Q%p-Z}$TfNqsz1nL57C-^q z>%HCEz2N)3-V45%OTOQmzUEuL=o`N0%f1P~z4B`T4nV*4d%xUUzx2Dm`g_0nyT1Tz zzX0q2_}jl1K)?YIx7Es8P;-|uffFXAdJc?wEyT9~U=Jb+xEj2{bTYWL_rV|>!smF7 zA>0)tT*6rb00I!VUBSW}5w|X^!YC}maoejO%)%!O0180D3ZTP1?5iRC!$17NJv_uf z+`>9sdkXNw)wse!^TaJ2!wLY!Q4GUW?8GYU#814%C=A0dTzf1W#z;KFU%U}E48~nd z#$~L=A$-Oo3;-t_$8fw6)tJL`e8+Yy!+1>o!sjRe0g%T5AbNUfm#O7i+lV#B+6R2e z!HnFWpe zFcNm4G;#?OF#*k0lO|Hr2gHgd*laZzS~WTm05P=7=6uct1;U@a#=^Y9>a54_Y{^-S z#%bKdE{w%Uyw1oB&ywuU{2b4fY{l{n00vNvXUxw2T*jY##rIsoy{gYM4AEmu&lK&& z^DNH^O~?M6(R$3$TinDajL$@D3Y7lvT9i-;C2`V~Pzi)E36wAiij2~PaMCG_(v|Si zFzwQlaMLP5(>#6Cln~S@Z3;w)&PILIK5-8p3;|4y0TAHS5OBLpJ=IPP)l%KmOnuc) zoz+mi)luEm7;w8wtN;lx0SR!{WKGry@Vsb!)@$9?YpvFBz1C*^)^m;4a&6aZ-P96* z0evk2Pwm%W4cL86)r9TTh3(f~{nV#h)q$PZ5RljsFxCg40F{jZQ;Yxxpa7c9*_*w@ zo4wfrfB=8;-1oe6cIaAbzm^6kj=u+RN`!}(0f5xw8Z9MAf_$?m++zI@Q^9LZGd z-ysaq5^diMKGD7$$0Pj5cs$1v4##h7;S}C)7|zEUzTq2D5Az-3j?54Ba1Zuy;wXON z_>kf(-r_F);xL}#`C#JrFyrOPUJ;SPQCNGCpIIilf4(0X04}K}) zw9dg9JVUoWW+z%UxnAqOUKG8)54|oYB3fp{{_Dsdd&i#aX0z$^h96uMt}53pY%$<^i1FMPXF{!AN5i{^;BQ=R)6(apY>Y5^<3ZeUjOxA zANFED_GDl7W`Fi*pZ03M_H5twZvXahANO)U_jF(Pc7OMHpZ9vd_k7>?e*gD?ANYbl z_=I2hhJW~opZJQu_>AB9j{o?OANi6$`IKMzmVfz}pZS`<`JCVRu@?{kA^8LVmH+?% zEC2ui03ZWc0*3(s0sspE00IjJ3J3rc000{R0u%}W0}}uP903a#1r!z*6bS++0|_<+ z8#e&}DH{Pa78oc9B{l#!HUKCm3AwDl9D`8z)ISEDuQzE=&ar zPct%YG9_RvO;G_*Y!6s!BNa1ADKJtuI&UExM@2GyML2jwH*H5bO%hB`ElgJyYfv$B zRy0OtD_3beS9>x{a4BeOCwXc)XL~JgbQ@u3NlQ;eY)V5%dO=ltL`!R0ZF6atEHsQ* zE{bwGxN9b@eJZYgDX4lYv3)1Bdo{OqIkt8+xph3dbUM0uHn(~-sdp)yYfq9>N|bIz zzHUgnX+penNVs=bwR%vjcW=6JVyRR+!Eso~UQ^3gchXH|&0A{BTWZZ#bk0?F&01^G zR&&u)c+pXI(OPuPN<_hIRmNpm#$;K@WK_gySjT8l$8>4RV|K=8cgA>X%5_noH>$8R zkenj9-W-f{yX*B@#PuoPl`KBg*#J)HdTu`RE#uSi#b}0H(P`_ zSCTMUi7sr7EN6)`VvR9sj5lY6D|3w|evT=6jVN}8Hg<+BZILcyk}+(NHDi%1a*-x} zkt%$VCv=lEc9R}_i$Ow#LPm)}Q;0%shdw=p9h`({Vj%brcUw(Z-v zbL-yCySMM(z=I1PPQ1ABZAN{06?lgY%qYWoC>f&uNnxz!jci3NGb&jxIk=~w(ip@1X*Zpn(qh)YECa_4HG(mHYVfDY-iMsqc>WE-SCI1K|T} zuK{0)>%)A7+2KI;0I&d_0MKh5KZ9;cBZ8|66mUEP9SY*4NM?-goC9&FLCE^BsbrS} z1#HiXFzc|uqxHNw>DIYtlWI z)iR%X%2C$qj*%v^K;R)NB|qv9Qp!s((P;hko&;`^0p)4-H1k;P#V=Hh>-<8 z2}Tl;pir2YK#fe!f#AyG1A8R9gE%pRMZ!s%5CWkGb&W+oR2mV<7NZ{uByHwX(BU3r zy17XXfM??n`6!qr4e>(&8sMVHP}m>+5h+iJyOG%JNW>~-D@Nu?q)Vt6ku8BSCzq_^ zTw=J9DM@i860^}h^3f)Y>0mt^lU(pXRx=dpV{IpkZ7yZgqaLa1p#XygY>4s<;Ch@#IGqjDV)|lYI9-&b2}Y2CWF+U3GI^wJrc|6f zaiRse_{H`;aiubCA0;_*(w9P!XkyaYu&A~qL468=NAuPI{-mW8ZUB;`s$=A=nIU6s zpipK?NIi7GCIx6f9$AZ!Qa50N+6ho+xztq4TmY)2kxCz?T0kyU1;nu#EqGjI=2b(Q zC_Z8-N?meT2BoMYz_O@}E@kPAuqendrj(OfgsDi%NF{G-^P5m~=|gsU(@xs-vlI!_ z4KJctL0++oq8+L1WV)rxK5$4*+WzKXL5o?PlD2}h^(k(jR9L^-mbSf>>`yp55|b9U zwx;DKX!jvnE|v7NBh6$^6T4D=q{){}y=-Y^#97r=gt*Er%9SYl+{l*Kyd)Lwadk_R z(z5rbyM?c29lH<=zI47>q%7tB!zYFf3Yt;$qBj|9S@QZewTL<| zAlanZ#&*21?Q4TGtl`937^kl7YXkH9+6F@xv)~;_b9GXwilSM; z{Huv&>)Z}!_d^tp(s)Ijs2tb0$U|TG+0(M?QER>{8D< z*}C4fuaRx*WhdL!!Hzbrb4_e+cYE00CbqP1{p(&U+uEIm4 zVBcEQ(jN7sCw*;8o0{Lg_P3{7ZESq+yVa>ScBM(JZ-aMw;KtrJstNw-ikn)~3jegP zlkM+ZL;KpU&WE}FL2he=GaK8qZnv|^eGjvux6uwRoB$3GfSTJp006+b&2x_Pob#OL zIR4}j)uk@=sWaW`RR8+a!#;Mc z4p5Wvi5et@>CUF`>0yW8d7_PWnK?sZ=~+ue?Ly6b)KeTVzo;|_Pc2VU-i7kuCI zes{XhT>wsJdH~W+d8SL<@@Y2!u5ucfD0+sQHANx7w9{Eg1yTvRIdANJN z`lNq5_C5apbip&7@Y zfg9L?9*BV$_<X!g9|7F zG5`bp2LoDggqm=KO1Okf*o02_gisiTQQ&@cP=!`_g;jMK2#A14 zi2jEth>A#vfmjHo5ClRX4&tB6`G4&YFU-4Kf1zzv)j zisE32tEh>sXo{@JiRC~J;NT6spbOIw3o}3qwlE8|Pzy6q3$tJgzgUdE2#ms5jI>Y- zw{VQX=!>_ojJ2?g%NUHe@QbuC1Hp)mzc>xkkPF3F3%QUBw{VT(c#gF|jOcg^;~0+M z2#(hXj5?ZIlQS8TD!B)zfC)m037JronScqBK$Jx(lt*clOSzOv>6Dpp2~g>j zm~aV0`IJmql&i137XhInyWdQrHPuZ*_y7Y4doyMzc>rKU<cre z*q_?~pa80${W+lhDWC;Ppr?qR`AH7tAOvz?255kiW>5xbu%T$+1zy0R7iys#Y6f0F zq95v^Ac~?RDxw=oq9)p*C5obZU|Munfr{480%>UHS~dunfl_49BnxTw11G zdJI{*rEA&?$8ZeEkPK{Ure5l%!jPxWK&NFY3^<^deCd}UaXbD2pb3@Wn1^YYiIAv_ z+Nh37n3UiLfba>BD4LxKo1poc;()21IGWsW4WEjsp!u1iNvfopspY^6zsZ}s>6^^? zs?DjK#aWKV*^K5njJ7(Qx6qu;S*y&6oz=;X?dhJ`*`4TFj>4*)@Tr~d$)3~stkjtc zy4jt^T8_5h3(YVLMA+$)Dv4uBaHU1i7F2*$qK32WQ}+WniHq zilO#;ulSm;E~>96S)%z`241iSm0$^t&2#@dxL0Ygq`UngQr3_oJ5X-O$OR)~y zuuIwq7pt)sdkK#qrK#YRTI!{6ItEs5@n&3bVG{CE@ikrdNs%V>>$l126x}3ObtGSAtv#Oirn4996o4cx=dAqmP z%AM|Mt>n0?*qNQ=IG=~BorOD}=Q)qoi3`8*4Bi^9{mHHidbtfsxs%(jlUuI(DFpE9 zuNe9X8H%Bzo1v$Bx~6-t^SZD2+PWA@2AwdYk-)JE`v@MJun3#5yxY6J%ex4>ySJ;m zyc-F;tFazC36U_RQfj3yJF{PEvpFlXEPD*V{t&%4d%a^?vM{^7z>u<98nZ3Sy}}R- zdT9?qn`K#&4~1F?l4`U_JGGC>w1)}5g9!+X$*86f1V-Sspt-5A8LFV_wUY>&T05Er zOb)!ztGhXzzuBw6*_*7&wzqn#%vqeyd7Q>coX9$l9=x5<`mFN_p3|wU#QGa zo`D;mcN?wOxvRXuklHW|{>i!D>aE?tt~*?yJ*>G7x(${~pyav@`1!7~3zPb)y7?-) zOx&;cs=BIs2D6(A4y(JuOT1TnyuE9?zk9q{{0PR&#UI-U$=e945Ck`%vMdV>EBmEy z45v05vu`}dJ1Y#|`@Pjm$8Ze3(_6CszyP%AD-!q6zKHM#fN-=;`?T~czmCetgb4^z zdzgnX3Q!;fubG;odBFbL$=3kD{>u#u{J;~uwy+wV#7VcjxvQ(pwh~OMu56ymshiE3 zp5i%<^H{>>DXqM`p6ocS?zzk7smp~6t>dVk#Ja2YiJJsC#QW;a{2I>x8nBhH#bLa==nTACtgukp#W~u$!7IE4d&ZXVv6tYy)tjeq zO0s>*$0=K;CA+h5th0dZrE~no`pl+nEXadwMOorJn&7^N49So@zm7bZicGbIc?hNe z1p_>)LJ*py8Oo&^zzA%rnY{kBsanChinhAywy}!A!nv!*oUo5;~T)Vn!#vdCAUHO&E z@V(QE(9ck0hEtJrW%y)`S)a=OofECA@+&>8U`>>JS-UD1Y_w2bW8^PACy2?!h= z1lF*%rdrZnE5M#Cs-MXX&PtuRoVWZaxy-<>L)@)cJ9Q1T3nctiWcQ ztE;NhuBx^)jjXKf>o*O-tlZMWeZtCG!reKY!Hk`^Jk08uw}V@bw``q+d%`h1)Z{3i zynvBH48%B0=21=6Rc+=uOvL#Kx?}L6Zf&n_9?oVR#qh16UZ4k-K(JVxu*M6qWc zEzi5Fv5vqB^31!6e#ZDbzW;o^kZrvNoxKrny$p`B3hwY{s--I{mU>B4pH30~@!^%= zv?YH2>X5p$CT`J=dbLns>oG2y{(Gt^ZPJ~r>&)4z(OJQ=3gj&P(mc<>bDPRVZmY7a ztkEjCx$NA*%*)*wxJiGk*M7pnimY1BxVZ_{-s;^9O3jvQ&FPNrKn$QooS*Niq1-G6 z?A@X4P48#TuVqlh4jT!^Ti^c;@Lvqi{(Z&gjPT1#rHYWoYuvIsJK@!9vv};_f=}6o z-^PoN_#`{{Us~B3-j^SLU*_RA5iOXBjN&Jr@{OG8i>$O3&C!?a$)W1nDV@ob$hBX~ z$+A5Iyb#>a`J8I&^D@2Dz)keWsoSkg-0mr!z)!-)s<+Y#!cL9U*zWAnI;~C}!^r;c z!PknB_$i=ckIgsi<P)=J>j=zy&t7S#nZC1&@7Oil3jmRU^kZrjLhgB@G;Hg2$M&z5~Vw(f1(Xv_9(8@9G?-Lx^&CS+b2FJ{J=Y5vI! z^y$^DU&o$(dUNgA(RkTYDN>_Hm5^F3o%0vSVH8mC6{w1^2b^+`$!0HUG zEywV@#WY-gA%+~@a6|OB+j!&6xY}A1ZW~Aw^(}}wsOv6MO)=dRyE4i^V~4qF~h}$i;)((wSQruWZlx5#0h2m1~IJNF(>&m!J4DFi!(>dtu%J^iDLoOk2)%*IR zPu8aWa}_^S*^Bj&^U`~-5&m$!guojP1a??tA?yVh3lY39?Xu6daG4AVT2{fbKg70f zyYI$3Z)vp^v8J131h=Rfc{KN2!gT}}$S0$!m&kaTblj>Wg)Fk18F;}{U$(Fuc;B@Q zt_xwq@)B5d&+q#DEztrMEws$+e7$wkLfee?G}BbP(r{$AVU5q!XaZ^1X_B7U<4&NK?;84MVeU3 zw+gpG4xY-UGn6mgPqAT zmca#RD7Gg$weB;N0hyafgC{^eMop8c4DGHoG1jeSILlLB%e1IP=*0tjCN;T9m}pBQ7mU%k2uGAr5~YJYq7ffH5d?N=gB$T; z;p4OsOL(d98ZJ}|o^B|*!IaK(mg%Kj7XDU?G8t@4G(-$%G~=eu0A@2lvbMl=TLT%oC$;n#UWIDeq)LkOOs|lQT2$EN9*GLOyZE zy_!27?9?K!?apA-`v2yjsX5H#|MPkg!)L=-hA zLGfu$Zu+gD{sDwgxP~?Cm6aoXB^zSdN;bHnRjpV>t5m&8M_R)XUL~Lz3?e9d~ZAX zlnxs6d4}!q>^sf*j&^LzJ?Mlg6>@Y>(i|}f`NYS$O>^#jAi*9vQq2*Pa46HF2A^Bm zPgghipD=u}z-1+)krRqgM38ZejE*-VZYvukk0B7Zozy~&bV&a?#HBA2OiOXwD+R*7Y< zF}bLPE&}_ey$qdYK$Be?pM6iy?Vla0b4g6ZNDXR#v4t7yvDX8Mmj#A$8j~k z%GQ+{SrcC;m0Eww+>6kJmL-z=v{GBHQpfg=obB16AJrEf5 z-%{RXFFBxJy81B*NMD5-6QnSAgOW}^3?=IQ_iX*D1w8SGzCg}@C)=W0Gnz}!aj3cf zMW|2k!tasuVG8+uk+y-ogs&2jpnF$rig}H4l5E!7CjHBcB{6-Pi+K?Q9QZY zIKn*!N45&P?Lz3Ap(gveF?H6&*nOZ*9YOdwd1jcx>GE5O<@rsA1+IO`3ibS3`==AQ zPm!Fg%<}ftO79~^pl@+WxRi;^^^GLf?LpvLyGnyQdgPm}>~rz8=CW2+ez{S=rBAN4{z!=vRO@k{MX4sJ7>9djJQqzwF1M=nNolDTDKN#bCr9|ZG#tA1hcqCwLa2c*i)iF8%wM$7i9I zAskft-pfBpQmnsTPF%G~N1$BPM=?l8zn)svyI-nDwYMp}`gWD$VDxIBC=>*fmD{Va z;Rb@Z;>qyDqnHO3Kxhb_{0r(HS&u`$Dv(yL{)crttP(K=gb?FE4A0W5NP zO#TQK*CD#%#4Z?R@kpg-Tt|sR1~XuYf{3qSE#_!Sq;Cc=)&LcT^6Zb*5wIc3!HyxW zW-&yk=pB;Go;kC=U=kw{0GY(I4FU^7Yi~^wD6er5L_8&t&@w|1wZcmp0ifmi^SPPp zaw6;53Thryj|eTM=y;SX0O|`+z(B4Greq2kQ~(dc0YD+6P`n7rc2tKApj#7vcPUE( z6K?{e{?}V@aokU1i-!~g6y>CE#&_!;E1k09At>NtS*s38nWh3@!3NaFm&)%^|08zW zpOkub)_V>TXhSq8vwns??NdQ7^gmw_^Q59- zK7GkwxF^DzUj&o!)*X|n$U&%W@iZ794W6d9DnV61l`I>8K@;E@07ee-gp`Z_Z)F0K zf;St4!z62~zrdfkRtC6=2m1n{5jte`1Zr+_K43B%4iB6JU}5BUQhOm%0Jdl*gk!r+ zoVf65d)4zqj%(tM0FW+v3QfGBR0*L2Xdu+^HF-@{O^FOzcsjX^s+l2|FXJhU)C(z(7$!?0_!TGJn}V?T8qk>y4N%Z$hF1-CY>7Bn<$W0-A{z!*Y+j1qE(H1aif{p=tnq;U7GTMrGc3(V5t)El|e>_%}WxN%yfoE|H1zVvA zkPC8~=6EAlYJ-C=qYHA2zvQ%-G0U=qYvT>{=x_iW1^Leq_n&a$og0a;5P-SBO8|xtaRY*Z0TfecPQIqr zQLtge#RH0YL+XKKzJxeB5MmI}SW$Zm1%k5S8S4idX_He{01#AMvScOLD7{KE!(I*u z#sTdy5;U=uPpcBq#XzJSKFcB9ua}fKKCI8LOc-8}Ks%)Xi)#o4op=OF zW8QW6K^c$^g>T-PcB)UL)dR?mB{D}ZPr$gQH;Q>d9BaND?)3z)FM;?RD8@GXk$`kR zfO;H5vDY0&DoKtTsxwB=7z42RCgs_Q=)s>1L?8p}ImVQvM51S(y#cGoW=T$VeZnLP z6BTLE0Fme{iTdZ_n8X-Y0QE+K22bnJj)?hg{||vz3bp`RwL~L12t_g8>T9(nMtemQ zVvNS$M-3Pi<6&|G(}n|QgnFmu0=41C>Y%3{#}H;cJZ&$*fPLOoFUdzO$^AGnY);wD z)l^-&?I$JFt0IY&q&Cu~|J3WoizHVRFszXLaz0+$)@aW(=r`*lfdm>1fC2*6#9T|j zAR(1B=Gg$aZ6eqqF_QseNsI>`>qc~vfr#;t)A-vSjfn}Mwhf9JMpqDe0r_G%H%5HZl_E3bTJYsF5T}&aGgA+{4kS2@@LZjg&c#6R0-&;t z;3z=pcTkl1xg$07ncC2`QX?~DX*i`{a?ckCswd>ir|0G5%igjQJA-zQ3O8vk4waX@ zRcj%Q7*Q#AiAZ4}C>UPjEKVE)1Wd;D#Z#%Dg02@qEkdgQ4_MqcO8^E?aP4v)8;t=` z11d%J1`}w|cmug^Bb2s{*}%ml*oJ6qb)aMwz4m3`tz~_`*>da6#ZnTQ+AszDB_k#7 z7$V;S?0gQC9{_sWUGs{b{{DC~$SUPz*d+Ypxcjj{yIoT1h4eFcPJ;9f**GhZo5*Y#SQcV4!!w~k^gojrZf36${k5E#B*gVg3qlXi zL2NH;2GDJ^JGnM>*F)%ihZ0YiP-ld8k&Jud?7b3sk1Vf8PXNRLaI8294KuiARM9oR zei$Gur%WKro; z$OZsX;#X&>4&A7f)ZYH+1z-R0aI-`}AK1N{%sM;aatiEzMgFY-eCUMtVBa(@#+#P| z4A9ETVGMuZ*&)&>AGsti7?hHTzb$f8-5P~}H+T_I9;9MI_yEC^E-3?)M5_j1#%14g zmibH3K(&i9)YwV%_I+NG8UYqEQ`@x!Bq$0j+-pu41cJ?vuhY-**OGLDjnp6Mc;Lms zb;XKxaI09#sRdPH1S)U7HV=*lP#!1M3nbG85>Q`-N+9;ZYUb|;p+Q6-WD@w#62Rsv z?m*EVdxB+Wo#(1flzXwquBa~bdGBF9L`YD9rFT#Ip(V=#Q{pD=k~-bk-n5^9rO zP8t|6%=eh=AU8e3PXGv1)1<=@0*r>8b|4K}U&o@^#}^=)9FGFcJSoi-!*I}tG9|6m zA0V-sL9w0sCs2slH{t@+v}NRNwx{JIGLlhs%T^@7;&@v!+Kbk;>z=>VHE`TEk?QR; zCySJL(8cWTYYxfdZMP`y8Z5QG8N{o=+q~1+zrfg_9t=PctN{ZS*DBFtXBuDa>!$Fo z9AMQ8cHDY!f<)=VYFbkVoD`wgI`RvKB&Y_Saj-3pxS!lhpp0H}{;d2LJj{C04dKGL zlugN!dYkPFT8{U;uIW4+{mWU^s?A#Q~tPT_|vt zecT&gu8{CBj3VJVwCXOPVvZtk5J)eQO#dE=odiPafmpy7%IoUGNe-I?fC30PT7$LH zgABQ89ZO8liU|_6K&M_(A5NRVyim#d`c}L54ToZaOdUab%wX0oU1+hXmnfdlka3*~ z=_L09anR%duq>WscYyWz?Ibz^)R_V(om?#;fM;kqJne?OGayq4$Se)4a*2jo*f5Jp zC7GY^G799If4VNY(3cB$Loj7S|4*jdW#phB$5jq;zhOJ=WK9$~+Xd#XCCB zzWJiKl+?BDpCwnnAz-Eyvy_F~8GRo^eX|-s)2n2|x_jUElRk#px_<7yE9BGx50rzr zljFZa2kry#_Xokr2CZw)r9llQDHY#oVM!;TBo4Wop5;CWcoHKD5Tq*@e+)_21JJ>e z+y$WC?Wh>iQKDBv4GDT2yZ&F{aZSl2dFTzCT0Pj@%qC6e7&!)qih*g&77XeWEGqEy zj1bKYGYSR>28Yjg@?#l-vkHQfR#b1_4!wp`1uX~#*`7RPw1-)JpsqMU*Di+PL&lyo&s(MI9;a%yC~3z49_e9<)}-XT!Pn3xEblhCMo_MT$TsN1!cFZ|Tat{~PN= zAuKL-%6!0t%iG9LgjD~ZG7Y{SzJ=R@*xXgC@rlS+>q z_ZB`6xG)C^&?`I#B76z%7hJ)(5!MS&4Y4QdlU%cnkF1=2ULU{3FS5j=y)^z(y>ZVX zNv6bsFu?Tz5sMIj%^Lk$E5Au|0>B(>ZI$SCPx?q&TMw1(FqQC{P5b(^b6}Hr9}S>g zm@_hi+_ZwI#tEFcie55jJC$U!hWJGNlxB7v^fH3FdWuo&<0&VV&#C5JCjsDMf+ty0 zbWz!r4k|%liI+9H$L}1cY zvm6EC3^|^y03@S=Fv+wc{<-Cp4xLelrP8;?6DcIUw;Ln(22+`z`fl!#c+)>i(ZhUK zo@qC&B_dSZM{(FeaHfMvuwaW~k&yMXr-Mh01x?8i#Ipb4l2=t6{N>Y#)gNU|g{kdB zA<9|J*rFDPWl>mbB7$kzX*uX{x;y=>#j!V9`pvk}o2P->{cc3p47Q#?3Ca%#Pmxap z!iL=tQ?80KeL=GRESj%`pMHC{NSIjT(@H59cb+X*KW!i*vvBS&PX*y$Ju&fJD-sM( z%1?&at7OVbzBMcaaOmYoynjc!52WyY$5E%WG|6407dHi_ulO;^U9!=RXD^Z4gC*p- z#!=jeEbo{GBa|+v0slNDrnno;Fd)7(HZ(lpf!5L_?*qr^DPB^ZR>w4z+}U1+*dW-l zOniWcECWG4382gy=Lx684NRI5AVU|qMq&dnZX+>Sp6nsySit8Qaj&pGqr!ca#EiEVdU%E{Eu#b>EnNV_wqM?1%X0ApfZsqMxZL@$YWm_=xZ^>ejl)xEWi!M zq+#>%8XABk`Xw`L6&R->_}`X!8muTS*I%#zV3EoP%nn&-y07GUgA29!C7ZKO?Znu8 ztIJhQ{3CvOjwpjCvyl1NUxNoOQn}(m@*kuEyP&WN0CXGu^U&jteFN# z(w5B#?y>lDW2Dcw@aTEtXW9`U>nuKf4DN_C_T%`zbmH8z6=&$*d!dmLObo3ymQ?{R z&*9!uI%vvn1D<4td^mP22aSK5HI^0SSkE$BXY9*3S=UOgBKRx;qQ{$CNVv<&Gkqs$si62mZ;@UsUnC~X*|-- zAo$0$rnqSkS3TD*fJfjFTnIoE(C4n@j^6p4CuhN()&ve6DI7qDYmQ4Qk!6VUvW1Z0 zh5;qKIBBz~KZoNLf<`z|%#H@mx9&EHvdFHr&%4AIdg@)C>i<&t*Y=%%$``xo|Msgc z^B+?KN~NSebGGM(7}V3~VGMZhtei9mAj}s0d25At1_iZ%U=RR{2l3$9DX*eixb!hsZz#W-8a!r!jD=?qBw4Rb8@Vg)0LyU~KOne-R3Z?VL3eK@HMs3~ z{>pVSbFtu@-?ODsH#SlWD{}xryk9*pNS>Bleq>0pza7aYOiuRpKqtueG%xU50D9_o zW^hH`^cP`cD$k8q(R!5-PzGML##N1MkH{gCu}gQpISTj>^XOUNzA`230rT)$&mjzk zBnggiScGEO+)@}2>e_rJ>I8T_h_2c78car0Y2?U7*N7Sd43?xC1$5F@+$v|s?WQb` z`RYiAY4Hftq^=DCqI$n3meHDl{J|bjih2t%e;k<`c*>CCdIM$*@d(4YnTICTAh9&c zUmElc?e=Jk6u$5QKX}CQDGM4{HZB!(NSXc)vC?Ft6{4Yc1*>HPfJgik)F{Bc0!#{6 z50C((1dw0_0$S``W&oOOH88Z;1sgUt2>p^qix$^LB@ml$d2+MvxV|R8hTfB{0Q@}; zp>h>#nPCx{6u?P5N}~!H+T6{`i3U(jWAiIhJepz$cBCi88ERMJ983EKiwr`5;L!@9 z^jZowLp%sU=}N|j8*+UjUg~!s3Qatm8J1Ya^-a#Y*4$?HKBr{_dk%upYJ+f`2Y~|R z&DbqKfXZO-lof;EXL`n-LS}Ip`qyn*{s^nA)48%S%=C5;8PRG^8SFU-aAUu*m}2ha zLEpm1>pMhr)yN8@tY*$z;n96cU=0N5%8e|P3dQ574+obJH3tBo29b;$jHe>`js)L- z8|4DZt_t#o5rq)|&>>8Za)v&e>DV<@w?a?-6a5fK$2A$X>h_Qh4d9#hBd7WMo)ar! z9>>##hyRTSmvHkZQPEc~wFgBO`Z_&8UsgN2HiMXb36T7JN*7xU(C8Tf0#gGVdzSx+PQwGPysA-7A?+17 zPd0Vppdc2b0aMhgxbC9YeqIO#jou&ti6T4+fY7LJRT8MQMzH{_diKRC&)bVZGRo_a zQO9bwRfY*?^;}l6E?1wK*G(wrusnl#6pxfAqkMEbaon>`+?`ZO>)k+GV82la{iiSp zMB#8P9}K;-2_hrCaYbHY!eWw=JiaED2>QP>AkpF^kq{b&LgRQSOb!o-b0Q$}d71j; z)N^j&<78QSq*xVs{Kks|os~TL2TzdlVdO2wOz~`UgLqKdVx|?DBTyP!8WVb+%Qji( z`(2tPGPiU39mD~j_T>TIB^+=!k?F{xB6&WcZ3+Z4@?^gGjuc_4W@@crID z#hs5te z88wM@)ZiY3CFNT#2Ac4xO)9MFr7>(PkTzkkTvxb>(`re@>Ml%mb5K>Cx)2<%wODZm zo66ZS!F}7IGRPN?pjU%vZnvlE23qMkmEbb0&cPgXGL_f7%wPTamvW<6Tz1W%9hn_N zo6&03i2<)sfhOLKDe5iOb@dxVB4zhzhwu#ZGnS^!w>>M5^e4@l7d0#e9#au$hA~D= zQwYx78LAvczq>T2yt7UVW8>MJ{>rm6Y)s+IOWfW`efm{>hoHIQGH!{)F!8FHe5mN( zVM+Yb<(N*)5T{_vW5F!<$ojq2jH+1V4!>N*ebh3UNyWQpAaG3=k6Q+vyGz{Fka7ZL zNDU_%vB!;Wtf=d8$6}yMbfkm;*NoAP&lqm0#w>(0=)umlu`>TGf?L*K|4fZquQv58 z!$a?9*0#B6eno1jEBt{QHT`(C(kpJ|#uDWYJ0o)jbktkTfL$wN3e|HDRS?g<7npvq z@^FCVuo9~w>Zy^GPAQe>ly75+nLUDVjeK+CgmRtQc{1@n_SJVk6J+8kE%Pg{c^>J) z8^h^msxn`m~B$7U^=)boWsupK?FC{a)bG(d<&M#eH zmn-DPu~EwgBtvNd3oq zRfW2JX)_%#fkukQu&dIWB~jzv40D`j^X(ig3#YM=kspiEu#snH0i)B0#2@0bPNNyK z`B3ih48McKiBZqrhuR~;OkR^8f}T-go!tA?Ik_UW!#<3go_pSadWF~RT}t!E?y^R} z2mqT}ks$v68q38<tXvuE;zR}F{pa08)9A-nRFW#Ii!--ac6ZuH7t#RxI)hgEQH6SUyV57ksy5W_7-x+9GNE`s#0q&d!$W1TRtg zejB?G9~;3Z`GNWU;h)3UZ=R(V`c>HcvfG=LD&o5uzhmrU*19BQ&TmTc{O9#qV0c^z z%WG{?5p}dTTkv@nn3Z6s@mWhl{B7PVUhbq(^ut%5CDVA5JYA*gOn4mM3*iCZ)E>x2 z3=XhR~k-4u&*rNvMhZ=O8+7U(44+@N99Zjq^vR%mKu6OMK z*02~%wW;0L?A>Z#qx&TrBSfk9tUllSW&V{ zqkP&{e5v78%Z`+}?PHMe-C>g)N`IQV)NO5eO)fWq<@z4|M4sY{gERA4YzctpV9ciV z(|+^(a>9|{Ft#A_@blYMJYylJSEF$ zgU9tf)!?hME+^VYQ)esNcd110=?Lco1k?yC_Zs1G7T-SF5Fuob>Vg`ptw8%E1^X$A z8c&P5gWO7MCvVM;BJW2*K8?FgzgK6qy0R&sql7<#S#00cG`-e9 zGgHHC(tIS>S~A(VUrYn1X4{C+bHJUK3&Yx~bOp2)M`o zTFC#cz;_eR9|Hm-#oqpLG{<}`{8ZxE2DiFso`i@VItvT-Pw{XOl145xNRpKCg)uiS zS|6|5`$^pNkyRTRoYNF}og7btDG{xhz3cNIDU(UdvaE`VZTWEPi`aJQj#Q~n=G~ot z�(~+-6wg8-Bc)iGZ-L8ik)n2vLyWY$ z|CMjfaE8&1&oc`~vl-?=5=>&k`=rpeh!inN%@Z?{r{oMYk}cEXAJoEm>wds#eCA2i z5BJ&3ljzY~e=VFO3OiZeHQbK*NwI`ZY{}v}n0!2JLi@=}mGz*Smh{76#H&;|e)pMI zbqDwM)kj)JDVJZ7zkI(aQx3X|O1UM6Xxu;MxtXAYR@ZsXqG2MXH)*D=DAU^|YTi#g z;+l+zLG6;}ZNzlm7Su$$!QmC>9aF+28mCtXbrB2ZyrbQ z$=p^Op$LL$)a)=8c{jmD(6he16fz*{_o1>swrdFe?r7*>p7f*nmBeFTc~%4J;4luK zu&l?qPrJHkeT<)aVo!WcIYS@BxeNIT{^FC4wL4jdMy?CZMTfSB6@^M${tUZ+x}(J% zQ|P6ccXs&`NqA3`ggXNo8;q4X>L-0XC46hd7UP*|6>QirjiQd6)vrEU{pn<;M zoej#?bf-fO$N2(29h_QR{+|1g{i81L1tp4Akc*j?m-I<&`GbGg_^kt%5KHk!vCg&2 zq>Nvj7B0FLQ76y5V;>lHhpih+*$pf8HAL-y&Y3urdoLy(ChPF&BaMo%k|rGUE3}|3 zm5kgM{5{m!AV}X_asF4oauxMcrgI)LIaQrHp3`Zp-h!4-m)9MM8QN%K2-&x#prfCS z^RI(CH-+Y6dgr5_>a2Ossc~ZEGr}G+Vnf|eIQWfKNZ(IOpxISAVGYoq(2qgnzas9n z6}X@LY~>7cM~2rz4Iyz**Y*O$Ml*!aq>)Va_D8vHVC3D2twgw(h| zm}3=;ua+D>{(uG|KzE;w>ORs zIJb$xdklQDOgLuH@n_5Dg@Fz|!Mo!HibX+A&;L95wEDa#*yZJY;Qj!Unq{TpJ<^4G zb9B4ALE1kaDEJ`MT@{a!^^V>A;We8te&f;KeY1MZyVhEphb&wEA+KAzvyh7CUsm=4 zn)r%Jqk>l3W(wYWr8BnKJ&l?xE%@6j;xJKk<382Z?^B1RK&O{SY%!-t-9cWeCNsZV zoO(jAJq2Ht{y2OOFL}vuf4%i$_rKlJ@BJ@Gf4_bIcjx;6=^&oE$fb0%t}LhmtE(P3 z$*jW~1YPp3py2H{V?{jQJk~(=v>&U7VQLmMXc%~s*?bdS7rQuZEf1%BSe;&yBb>GagZjLWxh!v7i~tdF9{VmgiN0$g|eFTP#L&>PIQx9%zsN zo{N(dK%ONX!N`1b9T6`pb0hv6;C5pMrr=@eG% zrx4!^@v!m~?o= zw)C`?ifG=rO=&sKbcEk31T`Db~ON}LzA6_%H|Y9DBfyt#gHR3`go zx?xD}sMylvnM*_2(M|7$8&B=VNCh5LgS*pB=WkABT*OoY_R~!re-ow82O?Ue&sF|R zZ<`if+{1dSLr&+I#$IcVI$>h>=ajLD%&%Zo$>`UU2=O$2XPva-2ffjsyk^nJY-b@q zzH*yK4cBv0&%WtL{HLLa6xMHI~mT!Vtyi7joBh7>CM4lQQ$`Um4DI81 z3wzGIB(7f(Tx3LiCQ`h_JTZe1(Y%tmh)1q$AkpHD3-!J#lZ8_B6IpvHHA7n zNL0vT>l>f^HEVq`!l3NE64+1AgQb6)Po{0LjM9!<(`j|ty8UVapG=lPCVNMhtE1892+wGMC*^Ep_+TbyrJx`(fL4x%KKbX zQH5!RGdx1RA45Z*fB^@_a*u3I;*u08-36jIVC=7sr4!8d=q05`jD8Z+C1>5R{TE|8 za>b|vaccQ*#S>x06A$!H-rok7(5rBC1l5ZxuvSs za4{6_gz=gzezYncrY+bB6QUUMGPK>CEj$hrGRgTQaWih#oALA^A~Z$v&TR(FwJAG* zgz{CVW?6`Ts$PkF=&LOjvnYpG2OQHo=$n=<6%@{>upNNV-(1OY0N@i@zM6f5X(jQ>ee~u_Sm8q54hYfj)#% zbRm^q{!oAWu9m+D+u#WM5nfmE@{kIT=zmAXA3a24a!g?TyMt7{7$)Ng#e%U5I9MDi z00mATQG?+oqbmekPclXZ_gG}*r!-%jV0`=EGpqidxxoR(0o!JG5XY7h6XK^JnxOOXd*Z3y`T^ALv5B4dBm zLY^AWPaVI;|3&;Kt0DjYfw6GYP=NN;KaB=*9vl9SD-l zMvLM=Hw?*`h#>xKa4MDzc*wq1f!M$!U*HiPc!YB{!Z8Hd>xvA>M(kiHp8=?Pcc6C{ zpm&eSgR^1Ds4vbas*OQt-ZA-040KZsxiW~XUqHUDKsK5oTaPJPvJnj-h&QejJqr}u zYLtD~PWWTwmKw4Nh1hnbYQ-FKWghOdQXL*s{n9G^u?z66P|3#DkV2S1<|ue5s-O~e zwLtw3hhh?^VW(k+nxnAh)*V<@h3{v$_D34?r#Mm$-G42#Erg#7mFy`1xWOWQDjpUc z%&>}O&~K;LU1UfF{7Nxpd;^4Ml+kZ|2$)kttr)$$>_Ens}3^tD0 zT9I!rctp%rE2D)Ypu)<-!GJPX*jg~`RWN+=!Bruib^ZZc51y?Az&0huK9cjdH}q;L z6#f*zu^D=`5e!Sh!?%W@g}cm`q0E3K=29#M7{*+_i+MPNp^?BMJ22E8%v4KQnhp$u z1eRZdEAbi=h)2HNLAIJ9mv$(Wm$a689}@W}akAARvi(Dt`os5?Fj4AY zk>wvESF|E`39M>ubkg5(fs-49>f%UA8yRsM+cx$E0xSzJVc8Dz4rY2&3B#Sj6(sK+MZvga`uu@Z$;*j?huM zVTMkrR9fr=Zl3x*(jh6Yo+`Zz7k*TU4#0D~2EYQdkz20tU00+%iX13KZk|g~MSCMO z1l}G7|COiiK!l`cBkNtE>(>#{Arv#$v|2NYh6SGAos{dY6oI)Ezv(n<7qlel`CCw$ z`c??Z2>7<^4Q`~cUzg6yT&jIhDCyN!1c7OfRwNQDdWTnUJ51ys)%UpFF-)F1?_xiY%|!dWi@IOPtG(X9E#i3o;uDmS)Raz=p>z}rM%iCSLr1;t$wYX z!B(WsRl<#AJ7L0>45@8wvAdU!1~uium$teQ{SVS>>M!fZB21>4o4g`5{F!2R-(}}r zUA9>anajT;1{P#@^J{^3urT%YA9VQS0UOxq=0ztANWG>Pm zF9u~@oQ+T9O)T+dxHOsU0x)rhA|V9%0`R3U8=86y^)Z9?0Vqos;19Fm@n%rCmEFHQ zm`jMm`VPe?4iPSac(R~9LZloEaeRr=+$K^?Eoj-DaaT*|^yT^obU7cc-k4ev&ZNh! zOW@WmME`WV{AOSV$+-URb|sTh4FS?h&WjJN7%HBub38rcqLY?iHqw;zxRJ*s^3=#O z2c~w7o@X@GZW+VDHXbPl-}I$BNqsc)Bg0#W(WqB3l1 zNg4|E&BOa{igP5(_${~lj)cOEezKO}{odqUWixWjwXp|O03Yu9LBoV!t{XR(s zOsy$zpDLP$FuSfQNAhvs$)$)lLjt7K_RrN18FjwP1phqOwCqx4kWvRm@XJe4!2jc) z$yP=5X#F|WdO{3=^gvi;Lm@?4)ge?*mpEVt&eH#d^UvM-MmWNJQ=?^cn{RRXmmRTg z;ig}NGXGEH-vYBJ&6&)Jo9Y8`RT}p|0X7XArpK-x^DC0(Cmte&9xmq5nKz^L#m{k! zrsk&%Ibt&Ux`SucwdLQd!)(lM<;es`rP(Gsm`&H5izukCa;)aW9xht#ir@X3L*h6T z=V&Utn;iAmERr*ofSqu^HDc*=+yk7UQ;Gbf7^xGu8g*-+P#FQokpe%q9h4Bf=!3jCy(#v&f_%78Uv{)l}@Pb(d8o z%GjfgL6y;TU7evXI=!bjy06${KrX|)Q(9c|dgkym8mpRb&dj_TL4*uH63Ft&Qv+FN zeVvo_u~goW_&ZH))nLii9u64FQBaQbEdbno6PjK96mBF9r@RdyD*>#N9>_nJR9+1a zoL>u=Da=zY$(tz5iyVi30>=BH_%+XjzRIY7W(;XxQRjl=U1t6XYl`-euw;v%kGSNLzLMujB8_~ycj#086_gTeQ>f3AA&ks1V@xbI zXH_@O_@2^D{HALkVtLVPtX@bTD$ZaXe*S^}TutU8jQaeW-MQM@!(FLNr$Q!ZO|5;S zeMgTfefRHj8Z{I0KlIiWrpe~Z@p4`Oj#8W4uc3bICG2#4Ig9H#WPRBTn^r}PciTIC zWlJq@b}LT|ThGYkBZ^gIZwEZy%~Rb(A4$eNT!Mz0!CmAFnIoQ%{(JUh|6JAQ_LG8a z=tEi^c_~WGvpB^rijvC^NqX&gJI9we{?OxuTAcb5Go6QhO#_$yRkx`lS5g*pn;nW= z>8RbT|2z3Bq5p>aY8Xy@F^Y~ZZAw0Bky+}y)%A+OGVq@3>L#kE?!Q?i)h#^+ zHjL?5GfbbJXU{V=3Yg_Yr*$L_@(EvGrM7nt9qX9xXbTNvnlFdvNuR#|U3m~YKW|Bn zQp~eqFTilFiu-fg`5n@9Pl>_v@qbGP*}H(X`+0cFOQpp;{6k>C7^AXu-@T!=-t9a* zLkQvB8Zs!PVI4rlfv)F_2>LI#z=gT!s!%<6K^>A`=+H+h6AfI=5Y_&^khZKbUEGFW>l8WQ#t&ROWUt$EP3nLo%OIR@|r*W zUg1^qHQtgDdi*tK(SL@$RHApGI|R$hwb%wmjz8b8gqZzv*6#im>)!ljRf4(79|Qze zpr4-KN*rQ#U%j;$75G)QFS#r)@%gM^h)T(uz&W6CucUT&|ZmaEY z73@0%HNA19mQA#bF49~PFkNY&%hzftE7IQ}V1LDlk$PV8-d+0Vo*ZfAI`>-dO0dw-W~yp?`O64#&Q4mUWpR&RZX<4Ok>c$W#nN8p47y4le^@-FWu!u# z9?wW!xX-hvh*!3xIO>#5jMX}34Gfl#3}S@6pYu-YvO0zgvd;$hJhYLAANvKD`Omch z9y?Bt<^1j1z8n0edu9N>GXz}LYdNqcFYpP!aX9b7JZ-jnypoE+ie`G{pe+R*p$Pf+Vi<~Gue{#BoK+!ORggt&BptkjTgx@BjY z_OkmMDQVU4^auE8U@KeDV7jj)i?nV8%c^bvUB>g$ zDtpkCrGM=5NH6jblN>cYmvWnD&&Ixf-(tVyK~i2htUfOOtDoj{pjp!!tTwEj)zj8> zv&^q;>*=bpJR)T3;oz1j1KW-6ZlK0gF0Xze%yHNglgCF{*4t?wP(n-{O<+DLiZs2CX&w9)G~!uRBr^sTMl-OW6tsi;zT*c9CA z2}`Bgy0F*l2;@qQf1}M^59uaTS<_7`>o1X?OJy9JF0DpZzuG;~eJN_)sbc`RbNS`< zK)P((+kx0Wmsbcm;?7V4f>k9$u6=JT;gCJ05>fPFD)+uQiGlg%CzpQVufvYNCB5eQ zg>F4nidpw_elh7pMy~iYAY{|~%?st{QAeaV&%9hLds^9PxDM0MEtbIjOI^?4L? zH0AU79_jXm%H`JShHrkPcd2KNSDgS!^kL{4vsgx$H?x2Co<##8w_xpB+x|0&HLxG>q2#wBmK*%PwjSocM~FS$u}HuB=kV8C!Z>5S z{e9@$I786`=3)fCr^d&n8_?)8bElt24x0iohG7$oaX_~OT7zg*JQbJKQ9Lp(CFt4L zpp8*RDmV>Ih7v`mkq+D44<2GN=jf%E+$~Z|!>?d|BZ`3`yLq`bG}cyDEF;~^Oa@T| z`f-`S67eElMQQIc_t0i*yTF|YI5|JyWZm+HQo$w^ehy@L5ekqECGg)0)GHveq<`_Dl{H#(us$7%Lo>MP>7IU>iAy4Mrc zx|oM=f*q2Zw!)ST9z_j9Ze~&b7-DJ>A@A^UxxcFLmE+DlS9(Cq_7Q(z?Bw~AZ|@}r zM^Gs+W}dyipU)I`pV3s!RP=qn_h=!ZN;W6qIb6Eydlor&z+yUv`ET2>=v!Z!Y~kO& zG&w;bi{orcs|oaMdj7K?OsrW7@=cA!yCp0vLL+UM{6c|Dzt()B9KF@2Kl5{`>rR-XkMxJY9FU>Q-4thJ?g&^D8Z=bk=abUxy4cG$~2? z1Bz9SxGUJXn-s8lP*LA{LSmtGj}LG&WR-bADDS1=x7Jgepc$5A`{McpHk{)YmcY&a zb%z*46vfU*uKXTJHR5Pl(#oIte&87;V)8OV6>q+}oK<7NKo5At^9_uO{n_MH)S!u$*+%d#-WU z;w=A_YBsn8&keVY!?a&i6}>>J9S4fBatp>|!Bj-Zf`vn2ZeflzuOZJH+HxWjf3@$D zu@wvA&s$GknTTD%0xPl$N56v8#P5Q;>71l{@L5-i@Zy+FT@`S)l%`vne~y2lgcM!N zq8hHWblAvGCeoN>qzyHH!t5%)0A=0AqvG2Iu>or6#!&ZT78WH|xtZI@sI%;(5p&(f z4Ah7f@FZyLb6I18<;XJ{b%jlN4dlqOrcJ?n=&Jn#&x((a|3#$RAB0lJbP2Rvp^xmB zs@z3ei#dcl$U~tDX2_k&HW@0dtX9eORD0d31WI+SK&8b2mJb-odqL`mP;x4{AJ5f; zw75hB{V{@jx_R_uy#FlV`Yeq7N!DO;ndlJ~fpO(u;$FE#DGJ9du9^I?T%@Tz$IX0x zhF)JvA^+%2v)2}eO-8&$b~#PFsqQl+4ZPk@`==Z#c$i{Q;lu=yX16~HU7GS{Ou$*I zbu&#lU6P%SMNVR=XBeS$UJr#Y2eAf?0$CTP>tqIobmU(!zv`-;V|ktJ6O|jE5Oax2 z8i$)kb-W+>AooOZZYoRh%jW#<);a7A;f=yH4JFA@%KkEEEf!+@Q72!{GU+Y~4Gu3uk1pejjjlES)vp$}t)f)dO#Zdh~QrOR#Q8;p19y#wX4 z8zy=RYev(#p|O!YL|xGUKDs8f&E_#gG?akA+@ZT!u`(qs|53lfb7W=**KYD^HJ{Jn z7H{7YG)pkm*u-zdcFTvSI|f4K)oo$zsFYt)yNXm+Y<_T`@&jgntT-|5lP8y^w9X-E zuk>X~z*;Z!rjC<%Tuw*ny6tC-%498LPaqx6|OISqr zux$fw?nPBri!FoZ3BW4l1={A$<%oHp$dQUe`BwM2rg>^3R7EesJ+@a{#Id}K{W_KX z8`?9GRxkl$U^a}xtW@0L9ipi9xCS^sL`8~w!l(!-I#6cXR8$7H6bnw*Jy$WEzM7er z#)1%d*2WrG(=d#oWqT2l_&zdhSPR=^)!bFXZ$5<7<+{O8AtiC{_HC0V>8)AELTz(4 zWWsNb_h$LTfMn?B*B?65(nFiq9e!+>XteeWe7`cR3AB+IDjxFT%1ig5S|FJZUB_@o z5i;T>HzmN1JG#98Q*_o*Q9XSa-zGL#x?$;trCXO2kXVo|mu_5XRCMW-ZUHF)=`I0j z0R<6I5D{r<0TmH-e=qMp_ndp?k2~kwx!<`n^E{vD00$+P+Z1^r{Z$f9X&vnqS(v{< zTOv2bK<(~Px1Vp4}uBH=BSA!8Sb^Yy)#4kznRx72PFuk6T*%aHMBHQY z8v4;QIDI4CwuG`@6MjH2`&-mk9VW)iXM4^)qtupRp!lY!v@_qb%7VXzam}t&hGOSp zIlFRz-|P2(k^8=>yZp#wzK^*z`L=I^(c|Rgb+fL_BQA_g?%P2zm7XbMaOv3CxUsKw zMN#Jvp{gu0rmRm;=`2vgl7O8`j51I&t_n}QcflTL|mF6-r@N)E5O`gV02)7cCA^P@N zYzQHb7xB)kpbBC+t8&b%0y>rCD!-wCrwyw1N!<$N;?bMNN7G9aB17pY>3tPsd~x#p zr$jZr5vW(X^Bo-1b!l0vC?~uOlZ&aP-?my^B|VLdNG$#jn>JW z7)w^v@RN#W^m``ri1Fs(JWPG(erQ5`xHZdgo?+Ih>EANA>c9LAvD{FAY8l zso*$1ft-<`XD1Mxxt7ie!~~ywf`Og^Xu5>8&DN5~^iu9*Jp#WM-5L@-MvGfkN*qfg zJFlpxB)C}@yscScSNiJFU|B43%vp)r8gBOMvFxDEfi(Q{w)V&{{AO;XlmL$<0cuT1 zGh9Ov7J@IFp(lhi>$MPa0@R8GwZuY>OrdLWLsdXveyD^BhvLH6xg5K}3DH62{7!(ItZ+DHddod8RNk=vyJs!{+o3BUwEc4iaFQ`eX(V@&Z!ffpSFcy?0=NlOpDHU^|g}IZEPOI`ybUxiBuohydljB2UZ$ zGzifA9Y?VQsMIX*+ee@V0d0K(M3SB$PeA9pjwMw<_glY=h~sf&j|^(=|2ENEa(W zDHL4S!IbpN<2s)9hk5T&ihF$KDEvjU~L#eep^6t69C-lV3sRzGeBW|&8;b; zKp6`Frvok0sD-mV3a_@9GHj-dlt(h-fuV)f!vVpIo}dUXASDjGYbx=6DL2#` z#Egd@uiHNk4E~$JojI!NvOEcyt9qCwc^4%0z(7Y!y2V!JCG^t(3B2LOi5UUdryAyge^S=tF(vAD$FP3j6) zH5`m**2`i|rUR#3K4u~S$G_qVPalii1ZR{X`qn^H1duEd9Bd1`MuJZP*dh#!7~;VR zHtg~QfCM&a`~<*)OX3ScegtS<(Q|1|fM8-l^EwhZ3%W{m{ESbkC0iJGvMEXkL7*p~ zQDGCCwSX{UPAVF$RhN0MBMcYs)!5M+QDP$A6MXN)rJB#8m%+ zAV@h}?#e)wUfjEe@5O^C(O`Al z4qnA5n3JIRX7oS3wDXB(vq4?&_L9=*+o206G!Lz8CL-+5U|oY?@T z&9KQTs7*5!0$<7efnKFeMy5jA?yg#}^{7nvC|Uk4(``eSKw_sUY1D==7J#m@WAD(; zV7hZ^a436+@VqO${?%YR&7XAZtXQ~DI6$2UE<7EG@|35qM$D(TN~005);zMHh#(R0 z$cq$TC!G890TVN-B@($Y3xZ)F7|0Y1k68bDcXbv-Lj)HrBR5Wvn*;zW20A{NxD|T0 z%d~Froyl<0^A~!MLo}%T5cN`rW5fVphJhZVQ|{1eOlEDKw z#PnJ;XW_77IzR?qMnwdx&>cH~hbi_ER4HKvqIQ!O0-_oNFn$7>pHN%pK zeYTeCYrskan*|1_gJkn=!0v}OJ+xVr1t(RD=PO|A<15u;{ z^94k1b;@V2!)@HzS4lt`fC3AoH?5%ei?)Ii0icY5!tkK(`^e8%jGfs6mXrLRCmI!* zyFGO2pi{Dd0=dGU;Mc^$=q2b|&TgS6~%at-4aD0#f;vJzZ& zHuvm4Ci?*hUc=RsPC7OPg@%)|?Lo`7S8|G%MqQrC96`7eH2QQkl=*1^_6L4ptt_m%`Y3 z^Rf3Ob6|f!{zyEU=7GSmMMosmgmiuXB}f7dpus@K)mBV!S9xKOIVZ@!Y|f+Rm3n9V zgtRtjj%&rJJAqT;8h(;9hr0_KB!~ede+ufrO;Qnog6Kvn92l<08h6VK9ULs=cH^!G zbm2Y}B)tYZ0hwbVR9;ZCwI@<&h>6`dixV%6*(Wa~p_b`sl1t>^l4vP<=N3T~+PAoF zKD#U0H<)@BG(@Che@6#(NATE!ne=zr$YrdATG>B7J>TgVfYLvRQ2HIlyMS-nccGX5 zRaWmUr8XJW8~|p7@2}dfi13xV1`JBljJIg-y$*BItBT%T@soD6ez-oDPN&z||csTcy2g z7}V-4a{C0#QVP&4we58()U4zjTt}e+z^)6(G5O@h2&>kN6T}3aV%^*+b;aia(nzI$ zI3}Ua^8(-hee-Gze^mB)Ap*FYaI|Iz%AgGfI8THYkh+L7S1Et#OW@hG#{zELZ=n)w zP)T7KZ^T-&LHew=S}7H+>LnLI6_9>fdIj-lHbhTjn+r8aP~sNE4uCc!g2Q)LO* z6^iTc&J-h^Xk%Hy?!f3K=h2i&z1gV3(S(sCD)0wh4VcUDy>)ykE)Ky=O=k^&&9UlT z*_#;Y&-|y~%A2=hchlXF97?tnJQYvg><(r?%A~YbF~H2 z3y{zdp*U3L$GbqzTGzKEgt*&NOt5_t z5n{0m>DkV;&u&|b@*BWDz!xW6`X^$F6;h%TKsRE64(u0q9mcDtYtdTgK`OmOo~gSc`MbEzpC( z>GW`shj`Jd{3kIV^?98OgL7HfSJz)7m8!e}Af?qPt)you`%%gL3%gO&uk$bU>#H|- zyiu)}bUqHH`)+Vy$?mX&$I7jqq?Y<+A_K(to8QQDv2qL`MtnS$F9z63tbmUt^lnHf zcHX=BrHu@;b3whvM*F#D-cBR{DBl!dF7zUnQLG!}^Du9g@ZH%dxU;#<>^hr_ed04dvX=Xb*5BlGgA-{ZKFmqUl^#_bT+&5;xVm zGMM@68+#&GR|G=fokeCBYdJ+S#)6?4KrU0b#ciHOZXUonvFh%R2a%l z=-dqg%724w-jt(+Nd|=IRemm|5U3$h1xc42+aG!7{~ZhK+l2ccHn5Yq@gzkIe<~9T zfMO$oCT78%1h`tafB~e4)>F*C$~hQv!%k`>Qi)CHn2H-iVpu6l73#wPG{d6y`MXej z9Fba*GB}DYS{2?wJ_v;1o-VkU%D13Llrt+Z(ug_skGQ7Y?F2Bx(Ph*%6EVzVuZ zE}ImKf&k!0Bbsp0?Nq!?B(V1sp1t~^#uy}a=X-S4Ho^S-_n*WK8%n=Ix0-jk`OG){sJBbAxq#2#Zt zLcJ-I@RTw>p$)z$mOi<0%bR zc+cBq6qO|zh6iDvJvUYtW+D3@{><&oZD7%&i~Sc(*D zYN&9KTmg_YRJAco5@T?E@T4&N7t6-G{o*7Hq|A$c;}xP9fM#Kpi<9=p;+!sqYx$l> zLO+CnUDgI!bp0^cBwz}=IRK1CtXsrpSTvq(ak|_^c#Tv=GV*|ht$A2*D^3-cKG)4uytql zv!+X1FuTsUt*emT$Jg#5WRGLhC&w}IX{=Z13qwL=?aUhxV*)GA2p@&KT2OyL(ZK5e z&3}pY=voy?>wOswzn#sOy_PQ-qgz0t=>~vdO9F~A1b}01bk4s$O2vUl14KJ+ou=6& z`o!lpRm5gc6nuqVrkO<34gjqfVj~AP&H8Al9E=PDF_UBP}3t(yp|(u`_9EmPP7IX1fx* z!fA7Eh=}U4gcU{Pi2<03@UghW(*XD)8%R&eo~2hItqr9<^@ zKjpv!0U9k=n%)$IIYvOKnbhsD7RA(!gAG~}uA)*-T&8inZ=5YCn)Xu~2l$%q4<$9` zAfjLl80sW_^*+i9AF$kx_^m_`W%mUD9fP438lCE!nX@v}8kf2*7ePsw1%M6*kZ~zJL!pf_Oqob z6na;I+r-Gzlc-Eebd6enMam~aV+foE6r&ih_G}kKaaS1D5l%v2+5Lp$DexqJrSzXl z=({W=rt~!86>5~Abo)8*R$)3tiTJ4+9Ei5rh%`Pg)BlPz*bf(5!-KVq^fN zXQYs)@=zHAPpLAp2YZJuGgt|P3XEs3iB&4dlq{$`=qAzENH|<^Q7KF8(qB?50f5b^ z)Yf!`%0ORwVfN%KLBrI~&$G}K#cafc*x9H2o}iS=EBYJ&c2Odl527TH&hJL)mNBrz z01Mba!WSfgxgj(sd&Vo$fViE7;L6js=Shgwy zydJ}B3Z`xkqvoF~i!Liu@deoTfwr^|uUc8Iu+{yzx&=5h$A&mR`Cdv3x}k!S_3Y-2 zVEY>(3y8(Jc#q^r&?sG@DQYFDK(GMlHo>~R3k=T`x~7uKr8j1rS)e-f*#F6^6D1nR zXxwk%_<)l*|NJM-`ZSg@=)Kw}0lP5AD_bB@D)CTnKtzKwvC&s4elDYE;(2rKO{|CW z5SKWJ?Exq}3>4-m$j4I51fla4&AclbMJ!Ze^U4USWm}Fc@v3QH&5yGMG*bu>vZEpVP}fpto<%`f5X0|A{_PMn;enZ`2Ycv`gRK7L{-&jAMO%%_)j! zw5=Yg@dU*@SLV z!Pj)Q%8w03y^-uEv1g-fN+PHo+qWybs7h14m9^Ng7flekbfPs4*eUIf@X*g1J&GZ{ zd-VDVn@@bOpkQLvgmN*m4vR3IMBS|#jT8*V$FpgG7S<=ZM22}PGq|V(k*1sVRACqT`!~$bd_S6&(IV{X1EEdCV%p|f~i z|JHPYpLYRsBvbleK1#EkUh&jfMNH)Is>Ij$(kpb&tYtt0Eoyp}^Y<(d6&>>RENTQ; zHu8>Jt8ndIrqXkIrJlzE1)NICg`3hPA#Cpyy@UjNpd!i!A|GSbcy1cnFc|iz{yL?P zT)P=X$%sA3lF>3NTm~gsjNTGqC`@{4`2Z$4Rx4o?=Vp`Zl|d;P%qZ!QTde|f`Z$N` zrJC{8DZ=nPO)$so_v<0chbEXb8q5^|#;plSMvu#E4wGMj ze|8IAonLQ|lT^QLRCBZt4lH<$wP-i8>#%s7H}rTnpYCZ7TX&8fNE;TX{_;!rr*Cq4 zH#TB-(KMiTw(reveIBR(>=q#Z)*IYCGr2eN_7XDNKO_J`#{XN+;KOoKPEQ7H&k{Rk z^VEcL3^N9Q)0U26-{=gpX;fFdTdX~J&+bt3RRbk(6&Y2^xlYR^Vw&ZkM=xj3#Wqc6 zw+7uT;4)QCxa@f$h@DH6m(dI2PWdVPhl*QB50rK$EJV=ma{;BbTAMm)|Chv+xf|=Q z)Sdvi)d(ufz{E)!-2yD772nAy+q5!K!=1A{k8Qs z39r=6^qxn)-H9?O$RJysd9FWC?7a8^b)6`rqQz72OnOJGG&ouQIdk&Wne~fU-!15Th@=+{ku4I=tKZ|TvgC@(en4og+3?DCjOU0V|Q z&HA|q7^V~@qE0EGLm87Wa*fukao#bp__f;cYiZS1zBcY8&aD^8tAh9hat0GBiYc9v zrzBuYHoATZj3fy>?5@m1)8aek!9?QMRyPN%cA_oO0Lwhyu2 zy4hTbFkt^P9&#?4yYYiJqkdxxjKKDpc=_RVF^8D02babyYgu=QKygUt2GRR#m}4>f ztaM|0)~Dc2ab*LRpF-<s^7zd#NF!#_Jc`oc(GtvQr{G@%OJ{(|-ziXynx-~n?IUMZ& z6}~-77SQ!zs|SY6Sw&eKKAF#K(l(9JSz0tLi85Z|hI`ijF^ECBsC&gf*?+AxYMqd~ z^seM}!h7q&LXm`ro@NXaD0Tg~qbNa@$3i9olFe=M3*Xh1Q&5AG6Vm!LvU7y$7 zx)1DVS30H`Fxo-M7tc%wd`xN$+jfxTvp&8(k$+r;s@wap-8s1C{+DTg)cZ{Gj@xUB zr+hdYi37HC3y+c;jh0=Y2a1k0-@Ydtbk5xA5*%`*`^v+US^D>z5bTiehh@+-c8--! ztSTdX=ivVu7}H{LSWAS15XWQR$~7y#pw+NJ3HyF6o_e96LsHKR4od%Esp?n7pP0H!RiH$@Y!0*i+0xzq#A z{$K6~>~M9IIKssgdBt8%Z#lwi+zGdLrk{N%>!c%C4ICdbtxYBw*K*zY?jNX_RuP(V z!!g3$E9=fhNSAwKVB@s|2jMi1khqC$fo?ASgn9RWlKQcN=fnb-t!VY~eR9im zm}$jUuC4fgb%ek*D|bR0$!)Kb@GKTFNF7?K!1wOQ{48DPo?L_C)6jcXtc-#_JDE<; z6Tda(epB!Iez9t?JL^Q|3i?YnxwEtGy{%cp#MZe^c^p!e;g@t8Wt6Q$+SGjH0Ap6_~W_cORo8w!M*X{LnyA9 z?`m&XaBWwA@UOHC4FP`Ykoq&xyjDTrdr%YF+jM^c_kJ4ZZkW^%k+0IcLyOT`8 zN*cjPiq_c7-xBY>l2FnU#~y+$u?j0HzeFh8R>IBpb|YDGW+fB&i=V%!vrc4cQwibz zcY6A(_%^@EnZVmOJlET6Ub*fwzexzwdB?}RI`7uS##`pNE&g^|g1fx5HiicsV!c-eDwDQ@<;9~wfH;kk`G9OKjF+nkznZAh7KMh8Qb^p zpIO39E3E6xROIV?d(dy6<(BF}K zXx-uSC8R&+eVu(P;mG@QM;%Np)F}6_!!SP;y}+X!G?StAB;Bw+n=GrE5|Li;Cfd$_ z*!uhS%c4Ahf9qJWD$iIh75$F5e9J=JE#|-vw$_IWoyCmwy5fp{OPvvK1>-(-c`qyM zw%Ba$OtVS)t|;B+bGUc5=d)mbJB#B*u)<`U&(oRDe}YcD7wkQvKTn6Be|>uY_9Lzr zmzU=suit1Ie|+!gXAj}mYOudHElK?nlV2JImsu)}rqN_6i=j8OE+fY>JLi|hu?H-b z#WU{&;t=pX-glY^9#^ymO|cTKHdNwAx}?NhH(vYY8g51(bDEHOV=0A!UthCuf%c}9 zba0j-P9!$Qz1k>>o$F+b^~}j+fLFZRm#;%XUEPvILE!f&CSBn%6e>@ z$?k5$dqEqw@Mk&p_lM@S>GfH1^XUxDbF~T4)ZVNvxwO=_ZjaQ@7YWg#maK$0svT`N zgF%-O-`>yT%fyD$56j+7|8hm|ROe2y`PB@Etc3ax@^C)dwPAJ)*)siA%x0g^HnQ7P9^VPXK?b@Fh zrSiu@DE=|LMJUb(`B#H;c>g#v5&cS{#BW^ zpS;@=)jR##l-mrYHTy>50{sz`oK0U$;~gJOdijXAeEyl|*fMmS_q6@u*(-0pa;TmUcdBLsZ zRJiQQ{cjZa3$WAp+wzf>QIQ*mpn7E#&LnlCABwuN1tY z(>5MY#1C@vY@F67EiS@ZeZNl!obt+fCW$zR5DNbN_H>SC)Rl<}x2;6v6aabCeIoB_ zdYR3qbPYB5l^HPlTfS%C$ljOliL~(9a*qyOYe4$Vrm|mT6`yW-TZ=$w!p!x=2OK<9 z1dEuq>N~{Qj^ks18zx(qZQNu}5B0cDCSMIbM)`Q96AiTUdRay#X^Rtd=bqA zb0(6Uob;qZzP?BYcjX_h2K`89`~GkR{R5E;5avD zUTKyZGYfqvllA)7R;#QW?UwN-`^~pZJuRD+YA$SH#vlqUwh32%1m(as!XJu zjiK)sBEJrvRH zVL2!8GL(6m7`ji5*{o#ewyva9cu&Ho(PUP={_byLo2pxO{;=HsbX~LPjW_?X2*_(G zPn%rWWtX$LwQDj?NdpnnZfj0#3w;fWBflTZ=3a_a_4+-pOWgKL0xI^rJF@c62Xh?n z6x;q5wH8s^Y2I})9HJ77OG@6^&SjK%EiHNXdxpK;dvGb;Jt5^lVP2I#`-?9@x%T_! z4(h+5QV%{%B>nJBPBvt4WTY9QB{#5ptWX4rYadN-ZXp?MKx1&2(n@N97MAPT%~4R0uc3%19@E+yXx8 z%{N6gdqsMsxOeZMOeDb1nd_fHEL_MI_`LwX+S=`iJITdt7FH8 zbF8BomHn?B1iWqMX@_Kg`MHu8u*jPp3G!J3^C=Bcd6!?q-&nf0>aX*-VKK?JdWk7^ zo2QS``nrH>=7er;>l(&7-O^c2Ok}cLQ5j@XlWki(Iw~X?;xgLKAkE^!U|{4FuS&$X z^>G9k`K;IcaV*TuyLNWpgOxjrVzTWd5-R?{E2=8B3Npf?D_baH>sqzLQmoS8NtvAj z)Sw?M|1DzXXa}Q+4OG~efaNs@Skw(#I^w5ySa%{`Nj(J{_D%hY-S+yn=BQWVTGFBV z{q#x42E7r7_sq5V*7eFR@Efwu7Yphu)mydd(VoDycMfvPyo?#r>$j}(F-|?4GL)9O zaj{Dy1NVQXwXV~tooRE{83|hyZX7uNvK5v3E#Gom=8)-@o6x>>eEytFn_g?I$NhV* z4z9X_xu5qcKgQA9EitS(P)?i8Z?_g)pDehcv6J=W$D1n3iph~R^WNNm8)8=9aU0!& zU);X?Tigy5wcCJM7)7vqH`{i-=to;exvzg=L5?t;C8sLWJBIYMaXb* zC$md#E*ZSFkL<7lC48S3y{-KEwObklt?(f6kohXSalbj8?JM<1=b7*s*(b?v$x|!| z$1+imt?A`b7L_hp3myg$$#VZvZsuLi6_+6SOgY(&7xffo$__#>>*Kq)8>$ni5Z)N| zBTq$5!(n4cFox&YFZBLOIH*5(SLN__{C&gvxwgd_@$`9JZU@&YW}z2uOv+Ej-mtt4 z8=;|N9w5cj{cU|2AUkE2l9ZC)h4+7RN5gEa|L@lxwVEk7kj?1v6LF^z_nw{|-=~Fb zA;I4fpX6NDp4-5r+kLL~PSUyj^`tmZNW&w;71e3}x1*oxPBuO@D2E?uIxYezMCF9? z=L+i1j=Z~kfd_Lh%}kiZfBn1p=;fxjXLQ@nJO{D7Xh`De^?wK7Fu$98nukbw$59#S zE2o-?TQkV3kb0mYfJ{A#ycqsZ2Lezjl|qjKc_C5@q^%sVBF+JJZCmh{zRnjTIiCG0PBKatO|=foLSac_V4-OKCAf=-pCU@gd|f2E_$rP}86t zEvBu+pvFI=)rRQT02*Owl5ZyZFr}}<-fAbrO4_e$r;nwOp#7t_m~=}o3}YlPTAEwK zDO&(Fj>y|`LuiiKpfYw(B@Irx9Ahu)yUIxw7gTpm8Dm7Ol!s&UWAnH^tF+2SnL zyTRV=Ocw9t74O^-ZFLqgbCyh$YJ>*kPaZx7mDHFlUC45SSF3P?mimjWbcQq{194u2z{}64F%+cR9=U>FaQ)UX?NvmY+EpA)bjaC2C7bC?lu9002Ijob#g z6Xw7K)Xr_DDko}p!oY}=prG@BmKwrc4N}E0%8j+%aTCn%UArAkMPlfSzC8@~jN9?Z z6!d(!;~7`wS-azv>+V(P?%lfMxq%bY0L#5`_uJ4F8;kR&(-Ql61yfwbz`kNoTGAIg zn9PxVRv}(cwZ%FKIRO+Y8WJ|F4zm5q`T!&{F~n;4HN>ns)c7l_o=|YAW>B0^cwu!| zfKW(Wb#P&1$c&cv)Yk`d9udo5BQ~ldS~*Qt*5GtQ@XP8)WDi3!V3!0F{=_3p65NeC zuST#%!kK`mIk5U0tynY9Sm#}}(Gd<$&p2mKwXoe-OHZZ*&$w}LVxe%nrEtOwSX~XM zq2NS^05V)`(klV!FZmvCc&6@qK6d1%rK?OG*iAkcP95-k?7eL*x|b>AmF2%3=>H53 zASw9?y4&vML@h_HfPs2IM(ZJVYoJ=C2BUc-qoGEDtp=Mlu&~kVN$vAO%gFqyy&~J8 z!t%W*yGI++8@V!WOx01M*wT9%(X4Mw-wYPgzfxEcDi)Ac}`My)N^^<~;^g;T@O8T_jhbk+T#>+TqN>OZ$ZUyy78MRh9*>@&N^euI5 zg@U)gIJg{kR7pOR=J$I`_Qg(+0Bc$~&g8xK&PTNJ@6;hU2D}EF;Sf{h&{C$~$HIoC zLcir)iRIdcWfbt^Ks53Kgq@YZa)4#{wO03!R+B`(2!dq*(W_iqt4y_DY#}mh4PWRa zKf}P!?}4~>fm{0;T*P4vLX&GNlFMFlr%IH|SCZ>6a;w~X>s;fjrsQs_KNn&J#TQ>c?6nhbH=iK?5GE1aNGnf`P#2zzr*?Q+s@3%k0cm7UE z{mIn$`w+;Eh@@N5#=n6iKR*1A47$>po&0wx1$;XSxCwp3_Nk>qOBn~Q+838WNLDjR zLfO67jEPX8XsD2ul->y}`UC=(tX^&?n;HbJjYPQ}QMX~~c@qAvYb`ngmoi0)EQj)q zhe~R_P+v}#s=Nv=Px4n!Xwr_*Z$-M8?$UlaL1)9(?$yqmYpya$%!*3XaEVr!?N^8% zm2qjkJ=eTt1A%I_FbipUFX1?LYwONy8&^fy7rn0rCi8-K<3Mfga!cKg27BnR(1lA^ zrbq{!*jK1b8D#**3f94Oz%4t}jtap1*K%wr)}k3e-&cHoulORW={)3)V0@F{ZK;dS z10lORhBeXss7SU48e|rZ!_n5Wp(u@^#xqgA!%?<+F)?u#mip17^s3o8D3@Bm{!=wVkN`Np^Qh3lQ|YaAuF)Jo0IkNXaD@%`JT${sZ-7 z5B>5vZgDSfe@}G{PzIB%n3E_khrJ`$`>FXUo18Md7++_qtuXBM(A|GXIH zf$)*wK+zDbT4|-mx?%srInl#8@7e(WTHVIILPf5v)7?}_Aw$V~b-!3C4_fHHp@o|; zBV`ZCvKnlC>qlq)q(71m16PkWx=xdHjXlKZXRm4%ST*LS(5()u_yFr$KYPr&tscq8 zjnplwE2-juRFZ-=7AC<}UlqF%;Lx@?w{IX0=GPT0j3`EP^vEFdpR8L5L za!>3M7#Jq8G@ya1eqI#IV)&h3YHh2F3Gwb!ax+ZnoL=1;D= zeQ$TB{a9D`xbYsT?eYwEhxFoJB)Hr2uVnp~#-|7$MviV(B_&nj9Se#VLLT2Nm|qCr zmx}X|vThrRz78C!4fw-$cv;mdD&*UqCEt1b#jx%D&O53d_f>67>e)`#Y9i$@a;2d9le=9n)AQwsw(R7?JvuH#b=?K4+23#gZmAgryPM%wSxaRf2`cQ3r>9$g9@@?mZS@CAxt-~lb;LLr&WN4o-np=B zy+HkG4Lutu^br{mi(!sT@X-(*`Dy<|DJkoMIa^6m>Tr#3Aj#yu#K@3CHDQHSA-TVP zvR2htDbPqfaHsCi_J1A5=ho6JS~CNI(`mBv*FyIG9PaUn&MZIhw(oQoYnb&F~~n-}@mEAsLDq?lbQAn^C#f4&rO?>U8VDgK6c z*N!TkuQS<6pTAXm=l-Z11V*K3KI4w4ooi_{Q=e}OdT*uv{?$wNYS9n3fL&x6F|vsm z`TL{){#-8r#bkl9YTc0In1RX4tsfJ2&(gw3DR&DOKxag&^%13eN zS8moVQa68s-)&zWggry|ZIdsUEl-)SD&rw#@h| zLOK94N!xJH?j1bG=)1(L-xqLHSgE(v=>92kI;q3qMZj1RkluZ<5qmr2{yJmTqP3LE zgNV;Z_kT%Z2ZEvO=XTvzO|FxqpVWfjE3xU5Uw-F*S%W;^Rp{p_M6d;Wzpu0D3i-zt z;`_1fX6UM~6fRxFtENxiMPT~dnimYje65fA^vjDhF`5#!?z`KTwb-v@^=+gY$1tzh zwGYXEq^Gh3OcWk*S<9S$6>0LgbFKgPSr+3bmTmnsF17n7Ym?DJ*Z-aDR%Ve;P9QYK zboN&PM~pxC(?E>A={T@*PkI&z$#Ie**{S526s^sWK}AQ?T0Y89Equ3>!HB`Ml+i|8 zuPla(tvo5g5|miM6(N`SDlG~z`6}=phZ$#D0?Wo@so`!f5v9tgIpGpw5}lA(;8ei# zvd(t8YOxI7O+kfHoMv(NvdVCA_uz*2bnplJ?+KkdkUELRH*>X|yv>=n#Q0k?eOPYu zs>0s6Lb43|bop*c6}a(sz|AIkvkd1ZQ>D$-38S}CUKqXv>%xHKv-LL$%jOO_?=2l7 z7(ZCMF-lm>_`@;OqEQu5J^Ll>smg096{w!Qk~-(5^-Lo^?bR?NEme=fI>USy&4@d# zZW}jsS@imY-}bp|WXbja$OS6e5s2MVgUC-mX;#VTt*w{HqmHiC`#&dU>F+5XZXrY& z*z&cR9n=yC(Tuub39L6b@^#sG0)&u!Ga15@8FNnY&req_fhjZV`0&V^scyS>LF?oc)F9lN4358FcVfo2^Gb`?tQIt53f5 z`HV?WuT`-;pdO;){=2wFX~m)9OyiN;y@g=*KizF@i?k&q^<=kBkoRw{;H7>(2pa9) z4zWG1-Og=#d6M*og++IdUz36v(mX^yyO8?w`42r&>&v(8rk8Nl9xTnqpFfq!JeKvm zJc4tii_(}vy}Or8w3^mD8wQBek=-(GrP1idc+X_H!re9(z6iCmf81Ygv~KYq(X^5; z%Lw39Y?z>^;Wc>aOlLbo5$i0;Hp_d70mO4SO%s!FNF= zb|alaPJx1}*#f5a;WD|LOJ0S3U|Rah*Vke0p*ccMua zUC|q&j-j^o>!aF z-8(=2&Y~*ia}-d7V>Iz0XA|y^8GayW@l_ZwA#Dge+fSEW_9!BX+I(%5w}<&!%(F5l zY7OfjyfA5fO+(!=uPDaGyb8f=em=q934dkWuk#eNX6q$A{c}&7zMSM0X;VH21heE6 zygw9Hm!&ofp^C5NHxe@`UA9vSi>V2Q=Ciby!g>M>TgB%ke9Ld{-7C|Q&omB}Z|4bh zzZjNsoU$#dNO9`DReK*zTfArfRpnzrAs>o-fV8paXoBU9?qYq21J1dOaq>_{(;@0p z4$3W57yF3LYt~nKo?Xj)2p5)GRV9Q+M-XMLobH0;hw|L=_Gc2aKcOtGbuMvouB9Os z6S($U=`Z|4rIw*)n*ZLR2Wzk~ai$tn5T8oTdQ3Xgb~XllQ*VejmoHW>GBa7NHZ_}H zCcV4qp_;e8&WhsuRFWa*Prhe2R=QF%dk`ciqa=wD?QE=?S0pv!7V`uH4&n}MFr69( zCky7H8wK#;!#<^Pos4x2+f5T3uS@3W@*0qWv8iS*HEKU~{6gYwMIfI;UG+YC^`nCW zD(qC1KiRx}7-A99hFn8f;fMQyO1y{o4e~EoC7%9><0<8*GO>Q8G7HLUUie9QTe=D+(4AWs z-kd+~8?Uk=ZM0EK;k)veHyjjbr2n&=rL48y`9r?ln}?FOBKCMZ3szi(uK$+1vG9JQ zwWj+_#5n1%xTkMj&Gtv*79u%bHkJ2|&(=Wu*IUAB3!(haBzT#X%jQKF5wCtLe5>hE zJy+(6JJi9LWCv+Inu+E*fAbmm(YQ)Rohv#_5mWGx7kM+^^fBAcB!fdC&xY)TG2gg8 z6K(K4NV1;A<}12v#;|O4%>q%Wvw>{296n(?3Tv0nXF?8Pk<7VsGxZA}L^K2zd$#6` zh5_*uAD%bw;)dx`3UY&Mmb^mD++p$w8*Mdicx#O)RqFS4+I!ZqE_`X&4UVTg(W2O- zbq=KZv*T}&MV6a!XMKAP-$GWwR#|l(0kz=bNdJt0AN(uXU+}Zr=3j{x!WX{lPT(n& zpn4kJqD;}y^a)9BT8B)Y`N)yvp=~oC{9eZ8aM!vtlX~K9c+lcgp!RMSH(OdnV|rW| z#VW91NK2hF;V~?3VOIy`q-VquT-y~Br)P$Fn(H{S{9@JQVdcx~%S->%qV}y9-}0(? zze>kuPNn!(y6QU90iK*)FHLtaAjaC{5FMCo0Y-&V|Tu;Wt}I_8!Iu=rwj(c&9fH;u`?YdDFf*fJ&Xg+ zDz!ELqv$-Nn&{dtJgI~bAoNfT9h4G!$3W=4h$2!#6%dgQB5DX#YADh~484d*6Hx&} z2Px7-9u*8lq=|r_V9ERO{W~+iX00z+M(UwheQ4j%D|!T#-_(to-7!gN9e-|2|D zp?Bf6;khI}i+z%rR77j+rp~nCn@i0+tnYH2NKXy)C%OfAP-5ICh~WhTXoO6s=~Ve0 zmkCqG+k9uR_nk!VIEkHtDyg9c+3~c#kovwJDoZI8)rt3mnw>@0HEsmjK$D8*42%A< zDVQ{WZvFWQ%OUweR__FykfIDz)PH)I zYsXx;r?v|Ms)!m}vN=tFRxU!DGx$T&f! zOn!|G8Ss?4$1GNFbdX-RrTEW9BDX6gPqpv0iI{gP>Hgny^C+~i-_D(kL?2B*iIQpQ^-1>%%4f^e$FCkmE&VPpJp2IXRk_S}`>HPw!5Ln%cRk?kB2 zLUucJvc1o$V=ExN2OWy|ilpIg`(!`zO2^L7G#cF7%e4c8nc`750 z7+LfrO1I;$dcpm|RvIG=PYJbbB(kh_Gs$c7YQ}Yh)QEK%bzrZG-!a3w#!uj6t?0Pn zzq)UO9a6fxUY#GrQ(`O?W3Rz8&)H8BbSFcS&o;DlL4s5V%k>oxccxX&w=M0&1C$M| z&M8%%tfO|b%U0L0bs3sJb1ntlV5#_`@N-3|J9NKG9IglB@9@2_BA#XEpK(BTSn_vs zSFU!*{o8Iky)kIeb8S7SiQztw&E>i~4K?Ac9R4bCFZXPYw!crD$YxJqRqh=J6H1y9 zw&Jy_pLhe(d{VT*N9pmpquFV7sP(9smlr5y0OVmVOln6upupbp zsb#U#Sl5+lINu6b=THs5VET1Jq^$W&@fXpl^s%ah%iPSd*Y zQbn)*5PIv&AF(0ibRjZsZ&fVNtm!!~tA&T35^;ugGasNM>=ysP>iAH9Yu56Whs#%9^-m-&TX@v| z@?kRANqWgZ4R9S-zH$zm{)uIGR-X2s%mS=yesV_-u(NCX^iZmq!S|W#5+21y>0~2~ zI`G|z7a36<%p1$1G90q}=CNgyw>2ZhF3R6;oJ6=p4mgaOP4)^olg~<4NHT7`b5;^( zq)QQN?n;cG|EGeQB%*5i3aEYffcx>9XbZ5a;ggo)59KbaUf*dIi1~N~^u0~deQU(i zy+h?9=nwfc?74Nr);o<4FutX8q5LA>`K?Cy#0L4%V|;1lVm#jA=fAf0-9HYBXj^lN zyi|B&kKS6OoD8k4s1 z0fkZbc1g=1mS%jni%-IpHBWA`GJ?rGnq)4cXTDt!)@8I8&G&{@ z*DG*;QA84A>pkIvGI~b4e161R!|&}%<41B0;)b8Yxy~xtr<9MFz~R`)%a`&rv~Faj zvgG(i5lA2;6-35I6%%6d{BVI&dI%L_rA2MVv*;7^1?dpK?@y)-FBRpV%Q+w| z!!2mwvox>|7V~mF`?e@tnFcO<0SyK^vzGa*3X8aCU}YlwbxlS=dQz_FZ!|PUxA(Rw zwICjE&E!+9yUazRLR?;ercU0Hh|r~CkT!t$?W_HRJ0>WY9TRGIds4WORKQHl7cBC> z)nP;j!Lg?R1Ui)iewj?Y-$L_Lu=Y}@XFh%mv>}l$bPz)X04L&woL9sKenOBm;9_j` ze;{%H7@@>dYabxRVCn6#aZ)qf`GmcG?|Q0naegH|E!t1oxfnpuPJV^muhdMg zsWNwjG-Im?092a)xJYohXEp3U$Fk(0KTxdnUOSo;Vh3$Bp&Vesp9lF~JwCf4BKcn(J z#XQ*npcPnTsSsdD1rH4aCd4Yz zz{#(m7BoI`{FRX>x>>eLU#45n3(xsNK34$gQLD&`|4)fWwa^~NS2{eFLBIiMD=Dgl zBoecV)Fy$dup&(Wbtm9w)?ry0!X*gn`uUr3;;p#qk6_+c%E*2`AL6Y9QH(1cZ~>ACH4a&q#n7_4K8~B}Rql_j;WESJWkew&L$@&@{|LVP#q-G+=E*-F;W9dG=96$UUPMYnMCiQ>LB=S( z7sI)#;E(UTONYnOi+{!P|BS^|J^XNkc3SWYi+u{^#(%gEn*G(6QR907^JZf0dMjb^ z==@^jx5!7Q@Op=rQML4T2x%=E_ABz?{51_0@R2YTJFzOtV4*JyH(|@H^6n)Pv;}s9 zdiqPa04BIN#sUBZQ*+)WBp0Vsi65qE{k4}5SH7D4XeA^>-dI1vWXarZQhVCCR3`SZ`{yp^I=7HvED3y~NVAqcA4^+ls~S|Vri3+52Ic|UzE;6a zJ94KiP6j)WniDFIxZw0&L0BjH4C*gMIao+Xe7iL5mKR{c0x?{uConyeb*wd-)Vtk~ zHGk175IR#nS!C-z70zwU6CpMqF@zNk<4pCvsUShG#SPPntv(IMNfTg)C*;~PBoUkNa9D`o9v}Yr zdG#`@e$2{BhQ{vkD#cXcWKH}7fo5ZClQYDl=b=>14Z}Zvk>!l0-ar^gF!x)Yf#LzE z0m%-4T=I9X&QpI`_iFbdEg?bW6F*xGOas%PQQ|Fd>_H#X<;o~ifqGjppLU=bvc&y1 zCz9L*Vytd$4YHz8RUs8AA`e4WMx|LbX?44MdkPBEHq#{Qr0q+4 zLJ?Mc3o|N*H2@zV9(>&^TWS4g7i1tH_B8SeYq|u2jnnhV1O}Q6RipMPnE}V7DSa8! zaW8=%MI%=0N-46UeoNxOIg5Tl)!Ih>Z*_^~ulfXIA`E~X67teWALL@#X`Y@Gb%_Q> z!GQ!}J?3b~&YE-=)ugjs2|Ur2E&$#om2lyIf#ta45yo~|^Q9qz7z`b95MqjUmxhXVQ322~Eu1aDe5Etba|=asUUd`<_# z{qn9dK=rBSmzf<37^;lRs?wvu$2hWd5Zn2&N=Z!--G{E&pYYKUB{rvjn2~lIfWFYt zUiKdbVFu!-_{u2<`QU{_!dwjssxrm?Y2r=ePg!!=!&bMl^4C*3V-qvv&i_-gbgE zZ0jz-PXvr3_2LY{dB|`Xi<p>}EnO;-^H0E)} zTpKgz4Vq~#kSznnA}%x=IzL3R2e>VF-u}tKo2-&6qwARIHwaU z#bEEb)BjxkxX}IB3p$VmdE!7BzINB{6YuHtedR?v&-bLlT3iq!oGRWdNFz-qin87L zj={X7-ct4#g~F%$hRq0=oE)$t7A-D(&&_nEAqwF#>!MROr4oZVVD2Z!bEQQ=#m#E9 zOZ?X6%djv(sDX$MjUHa<9sE={Q~OQvP5R6aT^2j>O7xM&sv7pL7{sF1n>M8`K+)}` zMzG|fTsSrK=2;+O`mCH*EQRp`o$*2onv+oL=@l_2EGHZblTMM>E*FRXt%5A#Ko%IDm9RsS&1JK|$Xj%oc(Ze*E3g1{ zg^N@_K0dHwJnX3&*C{cM%;X8BgS#2wd0X6292%-a1%d2JbUmZXWeARF1)`He4Tk5u z1pC9E00tL07|9!_#D=XK%>WP@Ed~CA_0EVJZ+yz<2|0g@@{d2;`L;k2|vq+X0ovCSj^7^*I6_Au3;^pc_+chK^TuDR-RdY<2+b z#2IQwd9?Ej>|CkVW^jEM3q{e-ZJJ##;uf5a6y60`LkLoXL@EC;h~{1}n=AzKK8KeM z`P(Z=o+YicoKeP|;fLwRLn60DbD@Ro9DP=DT9v9Ul|vGh95WvF0P)BNwjWX^dJ07$ zg{p*>DS*ULL}donR8G-T0yPET&|qd4Py3lL2W4#sFuVGm9#^$)Y%WNO1PbnV!`OlD zf~8Epg5PsNlyPp|bTE${=v2ydSV+W3>VKY<9HZ2xt)L%z>6c=WjmqFtTiWTjSUH`U z6%Ul}F_)8)Iq+Z!G^m=4#_yTv08j}4insH*-{*LWI^o`Dc58-NG|MmNa-On0vA8M& z9Qmuc;f3b9GgA#l4IK7KSGD6|7|_i!XV?|u&BX&l3(vqUlEP=apmE|U;1gnkW%E>G z+oZF>DIk-?Qg&?m#tNH#j^JuDTaWXlq)5JXuu^!4X+zE_TU1%6xz3&fYc>HwDGcSL z(6T)j{(Kmi6%Ez_z^5A_jK2J^x-7cNr2f9?+PvT%CDmB93P%(qyg6M{O}Ke8+Szm< zpfdpE9s*>Drc6ZMAtgeM?bu4W}bKV~`r(jx5u>D@|^-o1N486{01_DQPTL{WLH1fl4S&iR?m2m3>|*Xad7c0d2D& zXFJ<{XlP}>r+gt?NyE+Ujc{)>g$FIA%Y=GOmA?8?`V{TUgsydQMoG!GF=4&$R!F9Z z$#4Z~^7}%n=(WgpChA^Y(J~-Yt-p;tPu*k2V?hSs7pW(*!HkG|AOMOyjPjOhhzU7Y zmU>$I17%6)XALoIKAT{g19u=jLj#c4xf~XxXsjvhQR+(%wMMD^5^K9grwCrdDX>)n zh@GX0-45{UWjnJ6z$sxjA{DDQxSLbEEFv0L0t4fejK88EJ~qIFPB}aLt`c75|El%$ z9HcqlNq~rkot;)?#a+hEmZ_?k%wFPuvJ7nwy>5Ypdgg=~P_lP%p(iptgx}hE1A?!V zaLxzdx(JN~ry>QtE925XFh&p#YF(X~f=h?FXb-5DjvTm?V6?i+FhcW4ebAtw0=Ns;@?-Hhs7Dti?-qmRX77!4xg>{OY6O6okIyp z>&FJ-F}8EYQg&K>QOfQ^SiR(#j$Yi*AA8+XE%xechX%TT&M8;#qKuz6)_a3F?ScOG zY~3TgETvWU?g(>CK zu4jTLooensve!*0zxdpKYsg$!82q+B_*aSH?qfCN@mE?n7V^Je?qchxc*q%|riQE( zfIDlYqdNtC(tidq05!4IsqoYZ8<;&zkarkRtkB_D)F~!RA3`O$ze)6P=_>_che)kL zpUjVz&0UoHzVGW@6`C2Ov&3_?yQf;f4)h#`?Zdy;qI-)<_oA|1puhH`GYuWtT4s+4 z!{x|1R6dipIx?^sid&OkUKtT=cj|w@@oHscb%o1u>Q!e02hW`RFq!+}L+;jlICbvy zR(_)hC&C8Mv=eg4CyA}vneVEV} zn$lcKkZOYR2@6vYUBH-nJLN(agJIU&$RoUszmCzFoZWvt8$U6}VTL{DHi(`5oq<*R zHG|c&7u9pWI-BTb@%E~fy>F!mpxh~>>w$5eq6vR8yT(2>P=H(SPOV*gZKud)?FrT@+7^UamNoB2!#}Xp|d}w@Tu8 z%HK$wkY`f3==1P>^*ndD)1^}bh~pYh*mQSOT!4^`ajGxh?Reh`BggskEoKkKa&H#8d3diYnwO-3`^kpz?e6tuK{_QVRWYb*FOM9~X2)}3$8A1cB- zeFROM>rRkA@buBKElC)3Kc2pJFheKA*Um}etaAUv$+)y`EGK+qabB`Et@Tp~?B?45a6SHf8zgAllZEA&%P(9P&fhV8=<71F zzWV25nM^>cURUFUwUYcbi(TqIzhK36b8zupkn&RJ1r7hdGakX3+?}Xf zZ-lu|xBheAhn?}8#e%-AbDrNvntnQsVP_x`(a%3k{7W#l`YP0spj(%q5SAZi z(;+f6?c=Di-2XxTYzQsSGGf+TJPNhR(cd{&kkq&F*(q^xe<>|&?y@=>rF1UqD3g0LGOhW^PcikrL90Eh+r?um z3j+9lm%XLk8HT+Op=^y?=)+77be>nZ5$0xwb%QCpduaX+Z?o+9W`1RKXBCfIVVC((PM}Gzftj3K#*;BP%{_s3sr^9}o+v>khDxsg=>uq=m{+${4D_B#F zxxbl|@Y@=r+5Q?8P&^pkZ|+;U;bIsMn;CNL*+|v#JAeK2h4;*UQFDZEks|j$;~z50 z+>^5c;4aPEy}#cnCm!`9*#Z0N(SmrVq6@|X$hTc0iT;4G3E@0?5}CQA+3a!F z*YVW7DN1URZzo)&o(qEIF;PDmR_B!0blLj|#gv(gEL=1_h%Z z=5-k#^vIK;<}bVkW0|*oQKyP&cbYsrs`HW}F)dH{O59FS+h~^fFAKk*){Xu?lB8vn z=CdsyS|a}`Ext_u!?Ww3haO(}6};4a`+sl|*W-|t!OSzJWv(ZCw?I`^<|@8v_cvxf zn+>ydzlq!o=(;=Xo`k%=OX#|!bw0_WIZ)4?b#ZT^STa9G1F~qaA*2jp~Gn|dWV!PygM8|F{*r7|;+RNb;g~EL=>XYmc z-#^my4i0Qj$Y>qi@jk)~9)E0X>(82g`g-hu%Z}zF0F_dYDavxY)n;vrh+c!^g^a<( zP!p922Nkrk2VX=8KSPX#w+QaY0%vm2wGSQO)QSr=;?((z8^joJ?-TSaR5=FtH4^vx zZR;?7T{6YZV&$o6s)$jkoN<2(kw-zT!^we7hGKkg#WSudn-7dyN3GRE zSIi%ZE|I(&>M{%iWh%j}{k9cF0u9&jN8HGI9QfG}yT&PAB%8^%z^e~m0+xNuopXU> z@@;F%@18u@?G{ut|I@(j1hLF)p==avswP=h=5B-;;mj zZz|m#F>7n87y0RD`I8qiLl1)&7b+bKUj_>|*j!ndo-J7XSwUcrI+|(jW56eI;y?GD z`J$(uxxjYDX@KIZ9Thi&Jh}4&8S%Y_wi5arL)n%+3j?}_>oKcY{qI8t(3V5}>4Ilo z)|Hp3&1^6V`N0mO@r`>NhEn9$_n;IKBs7Ji=TK6k#YfV|@Pjs`rl!^jCw-kWPy5u- zcaGJQ?Q&7tg)Qznf>Y9U50-qYgFg>vEBbnDtA+g>FF}*?#oiQmzkZ%vXqmaC7+~J# zK|UtDY7`Ig3uRKOGA;JiO%1Od6?yDJC?3P0l-bEkq!qPdrYAM$dtTbM_*7~u7ffed zH4^9l1_EShS$Z?0^Dh@>b5_24F%ah>;6OljU(@NR3;jE6E{y<;v3J44>FiH9}9qi!Kw{aACATt)Puv@~UL9uLQ)S zZ?Be@bzXOB?y4btkUdaFcF21=IWi#8-$+t>T2=p0{U?^T-9ZXoG{B;=WP1W>n9p(XPy(XIko_4@JlEDBo1@JMAwJu3<(KVnAV8NL#mZe!#yeS z%gnCXmsOSJCyKOBMzm6K&z^963AzFaBEmkt@8z9uj(3|wFRy34nvj>zJIJs7a3U+z z(H64zri!oEdG@xb)x{!%3{vBJ>TQ!DRS?Yjh$v1=i zyfrMt+mmA-WNhP`<6z6YXbR-WXqGNKd+YM$$D}H$ zDMGOc>GAYN;HAnzCu#PG=90-}PAz+RIfYLj7Th~M@izz02{f%IpZ}Y$g|le=7P8}$ zZ3i7(H*P)KlTL)IWb}VC#n?a>dXTZBlT>vzr17ZS*;Yr#P>(oA@f3jzn zT}7L2KQyeA_}LQR*~qSR)Iah&v-PI^SKY;Bw(+$2bmoS(qtaW8f^SdC7+t8y$amBo z!|#`zb%y!9@_))vUoNz&VI98sQQ`oRa$%gr2?Dygb8N9wXm81@iZr9DE zF$OaCnA#HKoC+P3BlFuOKVO+2zmHT(<>J=lEJ@rHx4j}@VUSbMSPkYCJ@&0*+Ppe@of=$Pz`g5Y5 zry`(K7F-SSqqezK)A*}roHB1T58ik1?9FnM_MzD5HOccgXQz3!Z{XQ)hW&YXGduss zqqp+r_FE?(`-YKweLVWFF;s7&{m~T5Jl~nQN5sobeE%G}Au*(t$#hcx#ieQv+dFxT>c5gngVcp^iBFez@g??R zP+5_)DFHd;{SCGpPTBDPdVeh#>|r!Frh2C=6K=A|o>18b3{aoigydFQ{_B^X27|651k-WG{DeO?L(Ii{(dBzx3;q{rMlg>iJrkE9Fdn zl%OxhpDJyinuLF>-^fYvXF9YzwQ_P*U%@FGFxOW;E<$sOH@~dx%zF)%3q;ab`*EHS z+P|^$Pc`!elw01A@e*_v=EMiDD77y_T3(5Q`L7xCUrBe2KTTg7z9w`saIBu2>RzJq zDc-tgAoAzDbjO={k{P+Z-bO<{0k2-#&=#icdO)@YO?idCEx1d3 zVcKLfM0UyxY#eB1=#G&kpT;?Dx-X5c>HX? zp*=1142RMPX$@l|({6z4Q7uCJF=$I}21_xke^ubLF0(|LW{=;J z4Xd2uxY2x7awLWMewB8<>S!^^Jg?OJ*jqs1CRytktc-od@>nf|Q<~R;`^jdS$2pzm z7dX#X&73OIoqOpolq%X6SYCuO)yJhvQ)=r6-bBS%yfSBzrddeS1-md}H))`Lgp5@# zU*g!Hdr%o;DvT#AJacX@yT9LXXj^*d%9G>@1K-23*KtpJ=2F%X;4ON=a)pV(fjE7- zAQ`O?tXepoZnAh2p_aho5tA|9T!t_o#^u(hSn6`E$tB)u+GTFfzE_l`br!>~^=lN9 zJBmpVl4LVzx3O!`m1+3iJAvLLOVV4 z|FI|$RYaS{v^AX*?4V+uN);CpY2tL2P71BtE*;cdlng_a#otddUp^7epZO#_8ywaH`elzWINjm`7x1Ier>Xw4j~o#hbb`KXu}<8ilo|L^tK-v`{gVFV zsMNf@2hCk!+6MnP@1y7T&RvKMVcru5SD4QcgfG;3&vljH%vfJv^-8GheBFOm&H^fD z2y(JzZEV{VP{*}68{wO(xO@GbI{cZWN6K4VX%{1%9AD%=bEd)OxS#9r2+AZA8JZdJ zfbMxT{Pt$YALk-xe*3Tdb)**xWy&(7efFa#D7r;7 z@DcG0B!ozQS7-TEj8(Qvq${FnA-yRiFJt?S!WnM^u6OhO#-EhE?A6m!&UKQ9y2)}h z@Nnd(XzHi2XRdE1$YWnVjlOf8ge}JGeH!kLCnAyssmX#ei?eErGj49PdW-KO-4=Y^ z{;N)&zwfr-v^f7{ac&XhAd_U@j9z9 z^ElJ-`HyhQpD&)G$tfriFGvB?nMscyNlfBHU=Z($)R4zb=fxpfMSQDe#;ww=P;`&? z#X*%`xi@`NTeYM3=UmpG)T6www$#M|!2eUGu_O=)K*Rug!6eft1gAHXppg8sQ>=00@y}%(kZI?gPiK z`T4E;C9nJcTqOjrGuioFoAuYOsQjiOHJJMZcKjt3d_p zL6d%lY-_=O02m9v%m5au&J2AOy#^ystK-v7}>AF&3iz*dZ#!Gs@OR5PDe3%tjUls_|1wQTx ztSbwAvb*`jWb1*{7L|9qg?Ib0)Hb6fE3k5M^QrrG6MU;GdHbn;;6t`+ogIOI|F!a^ z&6n_N52b*vj_p#mZ4i2=M?I)sYU|X@+Tb2k&9+rK8AvU-Mw`FZuYTZ~RG)cmq;^+Lc9)j|8*GAWgLl6s?`{b?mP7>};3qo*GKuJu7?bpD{$a zzs>RepbWLYYc*{(3{rCa9QFOzdZwD#_Rjq7Nz?Z~Q9|0~%Aw4w*kcDe+@9aLc*`o(AeWzV5q$D#HAe5^l5STlXGWs0ZeiCj*lP;E?U`|kcGzYP{b{3NkaApH@VzdJ^v!oE zeK;oLdCdCaamLr<^zSkDd&hR@69;sXgA7d8&dr;6QlJ43j5#StxmlQUQWAZ$IQyiu z_N3_fNx>yIp;RUZ^lwe{?{baU@4_DLsGa(_yEEHUG%y4t^7lfOqyW5@3Pt*ZT9 z#pGFg_4oJtD}R!_W;Jfh1bfUyf1bPg?_IQqoSBO35E!u$z(W6}?vcUr=m+S(A6kV! z1_i(4v@@B1?Wup>16^KS%sO7bWN*j>Fe8%i*hB+t;L$A0(w+XQSBw7l?>qeO@Lew;HTZ2R$Bqew z*y0Ic=M*vta%LDNunY43kTS|DQuZ35fWl3zhO&L|x%?_MsA3hLHyN9nCTsln1>ZIc zwN3k(_GR<_*WVZjRj1s?V~U5mo7#k8x}W~v>Z za0Y&epp+SuoAl!R8l9EByAvmPq)9w-KtpcCKJS3`TpH!TLW8M@;`UP)>Mr;;|7(Du~QH4!NlTe@;@Z4xLSJFJ<+~$)3 z^IQoFGCR}mgX2BAdFde=TinTy#TUirdJnK9I}mU1@zxg>Ota7DUdWFmR8jQd+HB#a z&ySz}`p#HdetqLLBQBQz)ET(_{eS0A^9h>Rc$h#8mdt#%6Pv)QeT+@yu+S7u_=%Ft zhfoiDP0x@+7MN1ckUN)CB@0GG)5K%_#nR)T2P-lL5&bBY2?~KNvwy0SHCrQBB_nG* zNM)STPw$+_BIK&9sh?+ztl}mR^{aU%;1`+b@O*o?fM3wPp#s-nSrd#`GQX677wM+d z18mD^ZizqX1*gDO$_fw#KFlX)sAzcB-zA8d zkb#@j49`%Bx*1rgG8Xfp9#`=}a!a`+OFOXcF}b9^wk}X$Kv(}i3logce`zxoFA5m< z9yj$C@S8OCg0JnE48s2m2ECAvPi&hsyk*oryZ`XfKkNYtjAARDK$X#3C!w zImKivxS0%7vFYHm^#cM|##^vtDCdE+0h-{gBFpt6OldJFZwjZtWsb@}_iEf*>El#f z^`!B^!o(ZG8(CLYRq$)y7IS|+?~t{ZsS zn}_=s%3UJwn_?575zNvFP7=@tqfuU%%`JX`1% zd;7z&d*-hd&DES)r^4EF<^)Yt7$x2WLkwxZyy26!%+aF!EW!j+`)G-yxU++I$g-1j zTYLM-rFrcZA6m{3=dR{5^jX`tn$nOr#u~0+eMjoL2j;phaW`JV_?|=(0-_U?{&n0E ziTS?rv8?O+&vy?`j*gt3#;x9d?-qOV?K$q>(Z{>z87JGe#D2oQ`N#keqm*O4CnmIO{_Yvp+uJ^0i^^$76oE=o7ChxbHIz-GB zJu5g8FXcgkU<}_2%(HT$Y6**h2>xW1qVRNDCl;(fS# zXerYhDT!L<3hpe~%r+rORZ;D_xQme@Skg|AG-hYIuxl!*%%}9b-eIe4_oS)*j~6Mr zpAFtC#qBEsP^&Y47S5M;=kWT_Kf5g=%H6zl|Cs~tQ^M7j< zeEZ9#^oVI~KFL%JM}XOY*?;*VM&f=Od5``aN@xB)5huahsf<6|b?3bcs#Rh}Es4s^ z)~d=GuBe#^uX>*Mh zP8bsi!4}Zsd~ldW5gK)~aG80jD3cpmV9xC7*gCS5>6ugU=UsD=vET+rt;>|4NC?0p zFO4m~pCGy8nS*z>5%bh~1IY?*HMQK$kk&ntwN<2j)xUNBt!uyBy6W^}YO+~$I>kA0;31^Fl!8~$A2M1$Ynw%ROxzlYTu6`S7(d?UdjW>Au zwsq;KrhnlKVf#w^iIQ}7oX_BT4f8FxoxFSEmw}+Cm`$y>F^Tp1$Fv(BgAv(r3o80C z^_Imo*X2uQ8`ssuo@Vp+c3u%7KC3IO!w2sDnFi(oFAcCX|K6>}l zuxv`d-&mz?pp+l_TPWteQ?@Jxs&*pY-ehnyxFFQKFGp;jyXZidaW>|H`STXgk z>sklv&051-{DY@$VPn{lEU3d`&u>G^5GU{GXo=_w$8&BvoZ693hnl(*`i1=Re55I@ z%nyRT1SjV`ST4%doG}o29yR-C6;zPV_LL2J041@6n7S{w@cm8HQgq*9xpU-DI5PS^ zlqfOl`ai>yv3^Cy{0H1#p0>3i9x8&hwQR?iK@2 zctKI(pbz*w%!qM}C8XwNa-%p?U!8oI%TlhFX{nLrFMGLJpBr*x)HMz<+AWnqTk0wC z-DHW|)?1a|#2W*Xju0^~ZM%E;6`1iR%&ta_V8>}J)>>`VQjo17HsU{<-p{v=KYd}| z@4@|~^Z~g>yGEjW%VV!V;z0yNurpQ0asrMTdVXzP;6&^M>3v#(j#B43f!PNbRXgBC zuA_B_4O8eUiuB0BH4R4SgNyGF7 zv*+_>n!}Dh^V_bCg0N<0Hyu2N%=FY|fccYvR*+fEI>_rT$D4+}f2iDP{tPeZTBE<1~u_ z?~6|>GO>>{69WXl@2*E?3yL^Z|5fL;;J+8cS!eOvVz$=BvdDR|c}pvaH}=*RzS}v* z%;9cham;_!OiV^tGSNi)juS)D!Mw_Z0V@HV@H)v$N&DV$FdP?IA>%DMEOLeLy`!ev z1<9$9m0NdQ#OEwLC}x#L{Isf?f?KQF^Jy*HouVrjhHcq)s`yzw5HSmUl_0PAz_x(A z=Gid~Azy;cJLfyoKCvq>adRJ!6|E}do_3MlET3e;2lVy}bE;j=L-U~C7x-x3frq7D zX6qsjsb4rm;xQBce7oUdMvwIQFUoO6%C^KIb|Y!&Mj%>*+r^*HESv_=X3GOEQ>z?D*WL62EJ)7pb#9#AevjXPF z1?Ee2HCu1SPu)LO6G(G&tJ-6oQ}XFhBuL8NH8+g|_wJ#eaNoCKcK$r?ngyTlAm_+> zjw)HA?1y`a%@~5O$SK)dYEiP(H~TT9a;3s&o6~wU^#PS^K`RZdFwd{Clg3ulyvcMx)#7%R z5ka7q2duTWWoYSB$HzEhlu@hN$xT&59o1xxUy!Sftkwmo7F};SUt2Z~man9Wu0%^w z*2Hhrnz>Y;LD~!NFNS?|WU5=c^XB_or_PMhq-hP~clSOoY)QT*+rHa+Hqr9AP>sOm z;K%9gD$!ChtMH$-&-Q73s4GEMANLIQtIONvU}~4JK4xV^k|3h`I>q>hm>NT(R~S450lt1bjP0i zj_sXae8f2e+D&a%?5x&YpGwVqMoJ52L1D~J;SQ9JQx7(0KTd_H0{O~#2>+LBXgG7% zmQ#-Gd&+>WMF=#LxLd<}uy6FeZ5=hT&JuC@nwhrPbOq49o}2lc5ne6^R<)_VLeD%m z4NyCNAk=ZJ{;&m-;S7rWl+YBQwYv-WR(Y~<;au)3UDsLk=}_$BgEO)m`+r+`2$KeG zx(UpZfm4!K@3nbRGM}&R*&yzz6~KBg4^mFDtg8NBc|rM(t4sOOy`5AaJlVAJ^SpRq zIFH=9vvH6Ofe`{j>8fDs>{zWaDt%*ie zd4>}E)p`%(nj!Up!;m6E1AYn>d(eR7p7zf@j{LmD*J+B@o3_*9wchLXKz6>i`peBH zn;N_~&g(Gq$aJ@8SOMw#@<@G|OC~?o#v(?4sN_QEZcrJr&0ZBXvR^cz@;6O|PD)C& zFnKhwn~eQUnphv@`aWhc+Kt6$o(_Ao*RAbRj#5vc^O=COY)Bej&}s!ogC)Pzq_84ZSo@Ymei$>KuNnKxG}Z|;OH+4Z}d#>C24 z->OJ7x-)-?^A>CC;UzHy844J-1$e(tVL<1#`*{gzElz z0slLGLYU!^-QC#}d-gr9PjQHs#rv7+1z!4x^J1&Vxa02uZqH6117Fe@`PL?l3i3*G((g2M2A_)`D zTENz6j3w&=-uQIub)@*hfqEmi>5L{ATOd>Su-%bOO1*lc-_~!rH!tvLv^8T?a5VMJ z)Ef?;)>|=_&4cAtlNt(gl2>hqoR$z-X6Uup*#? z-IL2@h9Aqjtw-KkJeya(bj1Qwx%yXM>+X-o=}7TW09=L)s!bn`JYHs4rh#h9(_{e! zlg(ywrpa<-knEYOOn!snQb4b?0lm%Dg1zuUjusqA>L9^C)@by#;#=eb6a927O)JUx z%n~D27%;^#K(4At6&MBb6b>U(jLT6R^pj-%Q(d`$A(@|A9TJ5i1;dN2qe-DsuXBkkLXHFk`?O5cgk#zICo)&LqJ z<5zLFu`oN#=^wAr?3N$<%*Ba9e5GPQ*N5mATZ#1x2mKE`%tel#h`@i!=W`-W^?CU8 zIMTKhvj}C?Vlm*@-T?6Fay)y7d zcrvz(Nj4V%Mv%ZOM!yZLn1HFw2mnwU0B^W>0geL@n1Kiy3mlXQgXI8me>}4o<~KZB7W*0ws+Znr#pe|HqM0O&o0U*2KvgTEk%$nu6lW#IZycBV3RMdP zfmzf;keN6VhzW!N#6V|9Fc)7`z)XT>D^(ybX|>(|FHG8%sSll?{nAnPZ#69I0xXN9 z4m+QbXe1yRWmTg8tFw34{)$yDzs4R!X1VqV1%R{DhHnw3NWX?->d8zH{s0I&RPjrf z|DbmXzJO+YQ!wt8r#1;SMCTb_ly0(qRIc)5Qi!=2cxEKM_D3;z`B`OL@XNbKnfwM- z@u9EoIo@*{s7eTb)5!R8i%$WFKs$)BRI>1%sbZz>9qy(@-?Ca~q^^YbO&I0{G9AHTv{IW2>dj)g zg&74%a3Uf9G zcOh_@SUi{NfLkzq>|`t_1$xV}`asW7-+_v7IIGVBGMl1JOU?)&f(R4XR3#(dkcC^a zp!!kqlQ1KeUl9F}KELtGpqj$kH2x^e4wOk%HpuWt-)a*QJ*_Dm>7Ok~5xf-ZK!pHB zT?#~)fLztcSO&jwo?1L&6Q(vgUk8BWZ+eewk0Tu?rY&nzcs&J&=Yi1fN#mv2I1!WF zb7PZTu+b@P6MVU~V1Sjqx*TfP!T2T(=s@p1(F9u^Hw3*mx$ue?g`~RjI?O-oPSR?d zt)J7!{d!Shv+E5-3c_X46%Q3@bVVGunmIHq4J(Zl;0!?vKI6fxL&KV%%#ExT)_2}!y0+aJ>Hl1nx)FX%j&4gl|%G|Rh z)p1`o=EAq4x&P9Df)}&yLk#+dI8NgDpR5FCyTisgR^FsNCM)aJZnRq`)INKg%^pp4?VOCRmuu(k;!jh!U6CsW; z;~jkkD!g;Z5*+rnQV4C1hFppO3vHk?v8O~BF}@zDga>f$NuP_wfrXBfC~K;u^uGV@ zsVL)doWJ|1&ov|rZ?Lbu+o9Hr9cLlXvN(Q*uR0W-l7+bE+_XE6qu64$&4RK(z`9OW zrvN|RAcA)uy!?sk>12E$U_@F7@Kl~#93dgg`xPb#uG-@q3%LG`!Z^oCFaJP^E%GQX z6`O)>(dFB`F-#4mf+4Cn(DdP16n#htYyW!ldjt)25C6 zn)j^Qe;4@k1+e@tc9^@y6`PD13Z$ZxlXQ$&&&lHSH_%LqXBFkfer-H!U690n zS2kb4VcXmyvP9w->ro;pVw$m$^AzIWhz?W)1!1~=T$sgbHAnnNThAfL62Mw#clquK z`@|BH;H3s+0E?y>a0RTE68|OKPuOeqa3Q}3-M}nFuryxcWYH)<`2!Xj@ z4#(U}ec|?BR!sTRwf#{ZQaMK*mtPSHY-N;X2m`SI5~FTIjqI;-y7La1DbMfSBwoD^ zLM-Xh7y z3R*($OvwI!rwB^r4vr4=$m-?sW&tax=iK)QVS8M0k|wi4mbM6~^Xj6KC17LHzLseY zJKLsREQG045LED!D)u6q;>EClP2p6dbbY3JKQ=tT?|0Ga*t}WS*|5gPMxpZci?X+` z`@TQydT+4`py8=mB<5_WhAoo**syOd5{hd80?=cK*F5p#rfCjv;*(Us3mGj-4aWZh z9wFZnD5<&JhW_zjq4&*008iW_kcR(rU(aAjr;}SPXKgN#RaD2Jx~B$iTnZ+Z{CLgo^A6B^TaqyV7h8eA)E)@iG|_up zEw3;)fUx%^v1sTFXh1@)0hqt((U^?oa|?s^1S`6E|K&NtglEwU{8d@t4Vs-2oWyw{ zI;(9E&h4H=0(#1_IK=5!YAaqM28l()Sg$q+^p^GEP>2%~|Ju(c%>`e!9`qN*4 z!O=9NHxB0#YV?=#9FY0EV2W&$wT<@+!J}R9e!HmPAyaa~8N3c5UWG^Nh~uj9sd46` z#_$Q)gO+$a8st5G=6t!Lk3#6zj%xY=pOCMB7(he`8KMu+l?DLHGI?>eVA}l}5FzO| z-TD+TnH+pTok&*QKG0MEH?Pl7XPJu7&KUWIwU?zM$HU5IoTNS>Yw zEU@=JV`?o*{d$}614m@;q_gg206R$vVIZ*@fDf78wlgM;zomdzVx@t);2DI@&!DZk z-$5v#H&s{zdWJ}0;zV(aO7y7jXV2zCq2}1m|Gg1PSKeu692|=sW6$YrGEkN_(dKK* z_Y;2u!a=OmG)f}g2F^C5$uJ)3S5N)W1l5imFV<##>NbU|s(m_`BeK>6Mc{G~=EnI{ECmvBS>HpCh=3!A=F!! zeQ1LQ8@~zgHifz6Z7)q(crcFwsM?0LcY6!i-EDaDayZU~SvtT%$UA|ZWPm0xgmcQ8 ztOzGX*ivS#9*ov0Vx1tI$l3ZYp#R-SF*>3i{62Al&R$aSJ^J08+pxts6Sh}ZmO7^y zBN5w;9!7C?lTPtN&S~3d3ePZ&3hSJ9?xywQMlHzO>4dHXo5|K4YMb~M>9tz9cIr>e zmzZ{dLKU6Cnt}z;(X4BJUMx7a=0aax8X%3v_SWcTcG|B3fJ_m9wFtn@8NSS8Ej+?} zjRa&S--i_WDGT`%)o054yHGSye*3elh<~c6 zle`<|9|lDu*y#V7{SgN(i6j#^WZmk3@E)bA-7lesJblvHCJePO${G^J&_KCp!)zny z*`?qTDx9^8(~cFklLJp1PyOWFoMdN)G7tRBf&POIhy{>d;1WEP*@bWt{K2r#ifo?7 zri_^ceSqsYDQ27i;U_TD2-}xC!Nyz9sj+vW8eq*l0P~2kx1B(OIUF}MRKsrD&6vMz z?8j+sR1iV|>f?CTQ+e?KfTkbUT7cdW!B&z@d2{qYQ>q~ujl`=XYtU0G7SrD?j(+m^ zrPT_U@7<6zfkqLY@o?84K$OaW_4BiK7%P??ASXpi^}NgpIhL89WN~r0H5MYCw)C~E zl>`N)(&RWx?N!sev<|{U*5?fWyC*xKb>Pj?TRFLf)rH+Eajm?-B=B)Y9r@!z~6cmqXFRDNEHa`3_SomRgmN(n;EDZ z!I(KGNq1%my!~eJrsUdQ+zZbM_7ypHHX2ag0w$lysVX}>PB1Czw&2OMxC{|*bDq?DWa^=nSJnhKvKM)Om{*biNU`LGmhLt*|WsgzWOtDUCnIfzd)el6sQu{utyrzQ=M#$^+q8g5orH z$4s)j+JCmPzV(wa6&K7$$?hFl;(RN^*i3^#&;%z2h9R2#<-FptO!^s00*2l z7L^IV1#?xMRO_M3=8^6TScP{PHmNG7`|duv{^gDO&%%OkPC}~r6_!vgu|>^_I)qIv z+^ROj1P%WV2m$Q!Mk}vrhCWFN4@*--q!9$OS_CVALRmv#-n^L;lhSA^^f#Ef#;-IN z$jpNSA47>KbMP4kfFk*7^@?p^61yfP06)Kds~xbMorbJ&gu(f zwk(-*nd!(Z%Mn7B0<+pK6>u3>l+I)t6 z*xPYuZ{PjOBLD#)M#+++ue0RQnd&mK+Ucw=vONF#2=5H+DI`p|&GA9vPuYSbidM2>)Ia281vC%Yd! zx<14d-7ijp;Aw1(!W_6c4G5`%AW3Uw&@ja52h~tL*icw@E>ayifI^fa=-?x;GG$13 zz8?7m$o$*b0JD61h~1F9Ug8}~C#p*7%t!rf6NXKYseK7WM=_UaK*Milc8yhRvaGCt zDkqs?JPv)Clpsns3sIMMXU3Ds_|}uag3-?vqpxCJ;ycmxE+Pb1wFW>GlZUw!K%O@tH}>qO9Kus~Vz=7bm(A~$AVmi- zI3p5%kY2N1P6HUzne3!k=tivSki>l{z!~#Yj0B{pWu7^CFP||f{xB_Cd1rOVrXBk{ zh*5kt>lsXih>SgGw6Rwp{lc0~&*H4^76>HsOOK zQ5C5bjG%!7A@CUtMs@MJSVO5IZDqa*>T+{EDD-J8y}V{<^GHEjr&E~!C7Jv^-bRvD z5GBEx8`qK%>y{Vd1A!rJV#um&`lB{lAu+>*tyuCMb4ffoN|R`zH_QltRMdf^BHGN* zxd!z`!(ePD9yDCb>fE(0UGof8KQT_6Ufyf=DXw+Y0F1LQ@jJjf@q zJO!yzBeo7Z6{MY_t(^akb_w<*43g9)rYaHQY^`!VT6!?$$7m7pP(2iST8fQ4eM)L1 zyQqBAZ~V5*rjX5*#0~&eB>19e0H;XV29k`YD70Xel^XcikT`U=PPUhLe?`8tNyA&I z=?`*dMHQv|c_aVRupcKKAWsGH;O4iDq4?gnN;Ia~javtGy`3spI{xj}qrtiV*7j9y zFrQcvCzA!2{mGNygpvOWH^0`*WjAT?TA;4A}GMIf-pZ~=rVr+$RQ7IYVJVvih2^hjiR%P|Fa7S3=m2Ec^sF^jgRQ`Tmv)Iz8 z+L{x9IHFkvP9O|{K}#!F7DdL-h|Up)bDK+uWpa}45JJ~zuB{uE7K0~=Rn@<=reiFc(gTz+@qBh>+nD4qSjdN zj95v*(EXZpRc209^MX~}lIx%Ng2v0?b+UOhR`TmIe=n^zRL6={R=_*9J$csa8kC*v zENb0_qF35?P&zlSCD#k;uYS%M#8(eI6yDunyiDoc-ud8yt530OP! z!jJ#+Ss3_n?V{nA(knl?{5B23WRV|<5vco=w1utEp8&mv@#4C3p!=J8vfpv04u-^J zWA~KjswvS=q&MDCHdHzVJwl@+w1f1bnwVu1G!3opF2-kzgl6{MDX~mw;HSyovv322 z)jEX%(`GAF1MwOF5}cIokObnGR?C`4IVYW*vXW!Yv_WCp^(1W;`@8vYVO`j2aDe%( zWbGh`1{($IH$z@+csyH)A!sE?gLe*AZ2ZS^f!1YbsNLY1Tr^+V>~439ZvLuGReWow zuX@I6g+S)40LG7{$S4jvi&XVnVNe{|p}7?pzrpI-tM2p)wdnC#zIWdv-#!Xpo%T8AxL`5-p3Rtg71Mu1HQ5&EYj=Vip@%w`QrgQ=-zgZ+@03&{EOqHvPIe-?eUl zXQ6=}`c9_&(%m_8lF|p0f$W;z7rHmJ(wP2ec>lx((5|EZ4LnQi_%cufR^uEj?;xl` zR$gTq4*dRh@b2jiuJeO`f1U2Xd!B#(Ipe>-fBrnb#1#d=qpVP5kwofQVbY}Ixs+&0 zJW45{u6e;Z{YPGZW)$Q@NohmhjPtSF@PWf)N|+y8;s%HMuAg39P23iH+8r zwh5=se1sZIN1hYBg?SHWsKL}`Va3F3Bk9#yO>0h*MtF1y+PsYT(+n=;amYtO21T?; z83j_&6x@X}?2ceS)P=H2B0-K)emw&Vm4itlNRUQ+^Te5nQpgFy;O{|QJFdALAYorjk(wk zASL#(oy#S&SZxUQrC`A5>*Wg>jZBoTz-sOZukf?=h{UL074TguLYsR|44Sskh`#pqf7z!=Z2@09t&0@?)w6Rtw5{9~t-?gahR_*8L0 z{IIFqufk{^7Z+Cf$%s{{!Qz!r;O`Jrso`jxX^C#DH$FnuaA=PN~yC?aP%T>Wvoz|VfR7(nk22d!30LCf4N8lBn z8bT+T1?6Xfwj0kisa{7~q`lcSYaf@Wp*u{ZNvJ_%M@R0gBZAY1uCgdiDez3-QHx!*+8Y0d<-0bi64co+q@H23A@DXtoV@nbD5 zoyCg^vs}#Nr|@Q0@lO1kJEmyv5oj!ab{)FGq?+h=>*{UqjoFiSMbRj0e|fOrEO}z` zzFbTQw%90kydWpyMMB!z8tQlSq}8=NiEMAyT`?Y(;^r5UB7$TY&DVU5jF3g=0r}GA zCv|$a)o0x-u~5edafRUMz(lReX_wBT+)s0xSK}P5za4_ghY1~+E&16WupY%H5eg~; zk~xnCU-N5s0)2`WW&!2%&w-29YD*0lgO~V(N!$l&ua=sC@6F~Q(&W@3xz!ly@1mPF zpY&+d7uf5>7ulB4dfT}uy;qMrvn%10zX$iu|6_HyJ`G1hismznOL*$8$%Z;xJIo^j zvZxs>Av_!4b5WD1n$Qq1lyZ51Yh^E-GjIBvC60HqER&Dfmt4#-h4-t1&pwGM(S-5noGq z)YrPTh^1RkGg@q}tjP&pw<=It2)z^{|4QtWBz(+omyt(Nz!0n1NC0iR{d>^{G}AX- z3p07=Ld24}KFrPPanxukOUdg#V?9KNs*IaaS59FXfAgvATP3=xjrWoO(!XfNE4_C4@!^|}>l#Lc8V%G?2~FrX(-~U$ znKTa@erGD6nD90}H;lUpv-fxB&a*B$q%aO~h=Dy?SS@AA2ZpRjg9V@8Izt#=tG=du zWg$1Jw?1&$n;9`lWhtskRVUUS7~?ac$ps7M@gov$?narNLf8r*M@al!xQo*Uul*NO zRHJ%>YzEQt{$zvr)Lf)#+QNIbM@>B|SS(|)$A9Z^#Tm3PSTCNyOe^SUrE?SY%ZugLO>05~QU*qXM1c{U-GH$fBV;Tch*zjgFZ@h>Ec_Ab}iuWN(zO3H}vI&MPit(@SvagbdA;P;*3uA~KE zB$iNeum7{rdi`C_Z_U=C26K(IXyw>>?r*sv+9HlweNl(|v9fUcnFkre!em)2*wRLk zXRQKqt9(xg?^FLj-U0qG=ZW~JtBiY2*u%@^bwYZyxM~0OH_ci)U6ytk!F_^A8yS_k zvokjua5rR<2N!84B|gPvxu5X=BBAyEFD{FX-5L1F#Cm>5*jg(A zj3+TAdb?_c@~WaegB?6Fx%pikg*H%nr>Ii5)HkJ}wk9lYUt!jZ9I{2?){7d4-<*QK zN~(!VS=Dijb(-CCGqc;0WEj+$so`N)dJ<>N6BAvugV0c&QmLJw6|~C)X(5Ek7O}xqHE`5^hmx#%}6eZe0TURj0|b{`wD25l@*z znj!A)3kpdIyi@g7U;(b@WW`h?0kbCLmcPX+?}h)Q;4$0+uNDLLUK!++D!l_Sn~(y3 zsCnL5P@abf0hZ3^F9`nEb4}&S`KHDTOItRF#)A9h!fei}k`l&aj;fc(h52}m&E2z? z9kX?Uv2C(qBV+N{wGOH0)zDl-)R}W#d{}*$1&x#Rc{LV#uE@cmCsi6` zCSND%5vQr6>g;RE&~n(4Ff*1&(9*Ikl2nt;`=!AgZ|stUAbX1&1d*Tyfr=)s(%H;9 zyDX6*Sb@@X;p;rE?pfRyKKtTTN_QYOcc! zF7qluQ#^;P;-wJtBi3uiDd}bx=A2??K-b<8i{jANqKuSoBnAWkm~&*$6L$pfh6q6< zt``*+gX^!|mJ$S!um4vkXw`ZBejs-8m{(iNYsV$dPA7yX-e_bU)5GH3f|o}$ggl)r z_1P^2h@*G_Y-5S0RC5jXZgnz7-MmN5bSuGRlSelmO`ea!I;CCoH=}42 zzvZ?iuFB|!U40y$X({;*XP%X=t%pwxa3Wmd$)El%?LoB2-ZX#jWUg{Q+ddf z(u-46j%li_OTt;U(LK{gC^i8h<(Pu2b#O*cR)lgH*9x2gs?feKNw;Eq!a_{U`uf5c zef()%{90|7HKksgs(VTWBFGuRmGk4$x~=tPIyx^GBN7n}m(`(%NWzuceAWeEBRrWo z3Exuh*HY~2VpZ@jtC6D)pHF742QYnbu=1*Pe^~GSd;&9O(iHO6Dum5?m~^(+tZGiL zb`oL3?#O6bHD1$j)fm~|t2nVy)K3;jwi2K_H9KoI6L7^3Vjy1QkaxX7Ymkz~08a_6 zmga<-d>}?NSeV6x<43$bJl&30qII~dR}%uYyYt;rD3Um5X6AB6hcLVKSTo(YThf-uaB?P=yL3w~ z?X~;#aOfDD@2Mq0)}?ijG8BPG!`8&}LONF+Wq>;Z)jxP$oASo%?93E?uHga?&mZY7m?y@1DU&**xnO~`$6GtG$krP3F zY}{;3(L7mO`MZ7iT}tEK9-W+1Zg+WNKD*vaxoM)1o>m=b&4?UIaWM$0xDWd|LTtR6uvw}Q|ex>=(n)8MLe|TEn4F%~~Q)z&v z3x}cw;^5I7MY=}Eq%Mi4WIvMeIa2JPgI#C%oLfO=ryqk!hfNd5t5num`_!tE%-f)F z>8^G4U4=`*NJNXUv>jBsKPMnOHRdLE^sxfc@8k)&3Mri=ptg#9)6h~?1yQ{~TZ?mgJcO4s*D>R$kgtYx@|;H%YGGNb)m-nuq`3+gQD4k?A2P`>8^d=Wq0 zu5R;kJ#}yFcK<6~?dzy`86h3$z%RGTf5XVo>^s9?X+&wt=|V=U$BW7oy8pFd;W2~T zJ!O06!AmuuxUpkijOY)cL#MlKW7qkq?EiBYt=(fkLbNi6Q9rxbJxRFX(B_p@7SiQ8 z0k)l&Cv$+?fgxI@GNH?x|{uBnxIEG-SVtIM}P-&dxJoQ({H~xXn!-fD0H_kIVn$XBf}4NBEh3 znRf3_#n5=4vs%-PXYCzlkAqa*9WR~7>O0<%_m1g&L1%}^z$35%28zp3LmsJB(n(!X z8IA!r&_!EkPx^yDu25Q3_*obfS0#Uaj~;XC5;^^+n&b5`KpUoW&AS|P3D z2a@(}p7G6-y(oSAR#(|6yT+Wh4x&iY&E7Edp@tQN9@q{>(@8QcUsP1mAE7W9G+03nhAg6DDtLob@@*#SBc#Qx(RiP zTOW#J4vQPa$nPUy>IAV`+by#P=aTf_Jxg}o33B+kpJ1b$%gN%y70Z%Fl`|@kj1n-@ z-dM=`b(sKp^qEiVf%J}Ln&cHdm?nl9CY_WwMbpQ>^5|Y$_`Vj@T^Vtrb#o>^&+9|` zg@R8?M28CQ|FRp=+{2vcCHd6hDkAtLLI0VFdyI!3@SeU<=##oXkG*TH>NjB80E5{G zIuZR8!Q8AgwH$n33E|!xevN)zUVz6=SzRY~kH_}h;EVCLp3Q^xafS1ymNgWPU`epZ z@Nw(nkX@jSY6%B+P{Us969b0|5ZP9kH@ExpTDfgMl~k!&Cm{9QYICq}Zi3%6_m#$T z?jm$5U`7TixkZObmpWbkV>%Z3NJTr(GoV6NDb3lKGwjgWq(W=P{JnmL6o6s@IX6xH zn;uLZdRvC?(wDoDcle(!-fL2~z8KAWL+&mw??O{H$v2k>nkqT z?MO_DgSaJ>z0Fjdwr{+tSG+^GeV*;Xw`VU$9ODMD-oFaO>Lb4d+iwkcSk^$FbG~n5 z?>0e}eweDrg`G@4U^t6EfaWDW6}Lm|_%faYs@GzjA7#oxVlnx#jEGCVN70am7}NJy zrGDRerBElh4Zb7IE?IPW$mBnG-o9*>%M9gE$M_4LwUim_2h&;Ck7%^ypK|M6B#J)g zb6bC0TU6NFvD^7SUbkbu7^?HTSc8D$%(VV{5`Xx&Kmyh&7B&>cIpe?Cz~*c}>y!oL zmwC=Zz$sn@^KZlU5Numh8!P_7Hm|EVeCIUt+TDvbr6bBztw$o)D81bAt$!l^JqZ-u zz*0B-jDzyO|Ko!HhHy%H%+rm?tbED=EAuEr0Jnq{3ttwz)+Ak-vpew^jy6K+1U-}G zkwo8;J=m#74?38}MLbrDCYM*e+~9*>BI>6{YF5i9mYi_FMIAm8IP5|J_;NW%T08mtdDA}8O|cLzYcUT-`Kh4iJ{~D*=35NCqzMoE5saz zR9SQ#E6eTZqao?Hp~0*y<@jME*zM?HRw%oT@vziebk`8G68RJGCZv-Ny%_N|(EK9l zm`U(M&_RZ|aPUFlglOo}Lb*uz*0F$i=7HIn#WLozrEGmktd)FQ?}?RS&r+rRfN3rP7j;q@8A&G=O9*387`JkuYa(=Tp3-5h*Jz=vQ`p zAG!75)%{1Cv?qDGdj)@N-FK5Y?6fBDu}slBdkLCMh`rQBGLW*NRf)(OzSeQ z%fA9E{L7Mp%7!2~(iwxmC<{gCL}%4prPKzaDV#!-+FN$NgX^#M`F*~Z4}BZle2ug2 zl}`5y(0=>VohSP`{S4jk_K8Dv_KsJ}LSGUIv|4DtAL(k;ll{IwQO`E7|M?=cRr8KA z$Vbx&mLpL>A)~yX1Y^(?{F>e57k%&J3DNwNn8`8jI^heq<+3Y-%Fv8^f{WHN1G2B2 ze|Udex&s_I4fYTik0Un6tba#F=c9kT_t73=`f&B1!4KZ#kMAL(HgwS|+dlI{Oxss} zpnvRK`RGHT9xj<@efhNn6%wIx8>gWAj-6A4M?dqRz@)PJMEyjT<_6`+_2U|PYkD8o~E73pB9ep>7j3h;}1f!W}v5uD;c zR_|Gz15ioA0cYEIA$#0o(s-{wI%BM29TtigZNtwZN2qAK2n^RLY5h!4WdQiF zIJ{yV_g4v1aow()w&V@odmf`nODN=X7AU6wCp!k}pYxn?REHeG-@52vA~@s#6@1)p zrhT0|&wtholhS2IXy?wQv5dnMG1>y_B;ofYW3B#Ljwlh;!t||iP3Y>a2ycJkx0nDe z*-(6B%BJwGlr2pWok_f>YT+CD2Q(|5)1}Bn!AkBu#>pMwUZh-Rj%8Cbe3Kj1kXK3- zhU$3#vJT39AU{n_Wpg6f_&>lg&3Ff~xt(=XHPI?3Y=&4Hrfh=5dMf5hcCe*Ww*Gdn z_++$))T*(i?dpL@y_jv62g9%+o4`A6zzbMvZLu$>M2*F|r9p9>eZl>&S2y}onfSi~ zE{Plo(`n|K?Z+Gu-s!b(`k|WQY>u{8r?o4c45;Sd!a_a~EW*CstnuLZR`zvuVSWw^ zP1^Bd)CvlqAna!wne1G>;}YcCT?t5O1^9bNDVRuwIo@h5t(Vql(T3!3?7&BVKt3Db z$wZeHdDAvdY@2_7m|MN)>t-?R&DeROaA_*Lcjs}=^AHKIcTdc{dlzyEuzJ-4D|gL4 zzT82o0y6HH-8XB2%Cmk>>%q{ZnRJ=R&A@}d$Uh#F@~U0$e+Ecgvn)v{s#o}>&xTF= z#oJ0=F5M!GJEjan;WOeRspE%Rw_mPo}m0s_^_wmi7 zFhx7lv)6bY^-U&>VNeN)*Cr>0@+#*)i-|7}f$VP}dL&9`O8qLmzTiM};R zFgRz3#_OAWEAK&XJ-=Ct+5H8_aP5+M{)Z|z+&vfni|wrg^nJe3Q^*lBS<<8%7@aQq zmjJzLi87eG;LsDR2;<&A8_wzX-=5$g9E!;@YWrVm z46>PRQzaKTp-I8Ig|@#IdWD2(Uq8M&IqmjHUP9oqMq5!~ikpl?l0f{!{gTxz_CDpx zseT;PXH#fg+1|esfFv=IJMocbZAK$(3QbdLvou<$K&-n95a8 z!=7aY%k`eHf#KrSzPkQ?rl@*`==+fML2;%rCFN*2gI)8dApVEf#+up+b9d8}+7}IJ70B|`*#}A+H?EUc07O0EOk8jTV`quMqT8WL8s-v@Q?VarNJX6&8{!uP5~c( zykRyx()szvsqzDO_*K*8hxe~Zu?laA`E}Dc6P#R@ls^q`*jc$b*(}9z@d*tIhPh-} zA%d${S{yR=+&|VcUH$a#gTeBZ!C!YSX^RL>J*TN&9BO_u=yYM7^`BY!pS>eZ-De%s zD`ptBX^Zh-Zy!y*j*Pp-use0b{OBKk9T|1o>$K70+T(!?CY`&EQLgR+JzoD) zY=2zy$+_+KQj+F)1#sS%!oRW#W@y~Vxb@LrFMcrU?$hh*dOwQX)Q8jtE`R)wafNm+ z;2nqB_@&7^M9;wOnwbmFT;Uy2-1VAcFOcJp?-UjjvzQEw4zGMNIQRNSI^(PP@&>IG zecW#>k~^8DU3TH+w#<2v^~kZ4(Zco|EIR-^j@0pA^c{E&-UXNh1@|eK5fscx%Wy7Lmj90zAp1w+5e7-^m-TO zvbpE;>)xks<;#CN_zx;I6Aj0DKA>ce41+)FJyPb%MA>tB(0RJ(CL&dVsy8k;EG8prCl15uO{wx|D|KJVIBdoXj}V864wIO{*|wAg65EKeG!Uavo= znP8&%Z@2^a^eN@H%CmPJ(F{BW;L*t)VdkDPRxUTh3xaa@JgaZjueW;U?J^V}t|d&( zOcw5bv8hEwn4i-hC$#}pj4A!URaL~bm(>PRz4|586{Oq84aBt{u~F7G?|#rz92aLc zNo!x>qp|+{$fDIdIE0(VhSNsdW5$Ftt1iPbz0xZ$;6Favo2gSwTvvc3^~opB~(+nI&(wjGcD)Sxz(aMo3pvgO2lSB241Mc+5*U^ zBfs(!uBSt~<4V6il+5v4$j9uha_X$67z+H`KRwgGM(j);TD3`x2;K9B0~;v|WI(sO zyNZf0my|D;EHDVX!1)q329(W+0*4O#K%M+e;JnFf8;E=elLs({WVt6Al);=pw{=Ug zdm2g=l)-h9PGb0>&D%j^j7lFY#;MY`ru?cfU=JcZIICnh)yvA*L$WTr%BnQa+EchT zx;Vn}hTikSwH!G%Q~ooz1i36sq;(X>uJ8$Xvbi%f3OXaLS;|XSBG6hwLk7*u(D5Z_ z@W)3h$j3Cgh1^5&OTUDi%sY(CMvH|*M6G$mI;~s8iA2PW*PIov+p8oCXAKc+*-_p`KxY)tYK zNJ4bK+M+q=s4#7ftb!X>OmW()=@G)-@$Bsm*L#UjTn+|$Tv3Z82QVR|hC zt+Tz%$CaB$ye!n5b4Q=(R-!ltIyA0-tkew^)$n63Kv#P*kQ0x?n}DM zG&(>uzYt}}_FKq@{8Xevx{hrHS}>=r<4i>iJFNRm&`eeQ6R!Zo06@Y3ApnPP_y%#% zuK;5}m^?|Cv`v+4z}bwu0GrKJtbqYwMWroX;}s!Uv;eS(Qpuy%D}A@=jLxH?m7y#K z(7{?T?YFGe+U~TsFQCf1BDnBnD{Sn_wsljzYR|R`28UxkWiZS7bjyu{OFhNgk8A!* zpYWvug}#^5C!T{;=wq#h<)wrL&2D8mip{NRaLmdqS*M%KOhqmR_E_NR+*h!=W!S6} z{kli|%>858vAf99oY4mu2L`Owh_XNedr7%lsTL--|AH^tea#CL$(8It;yqp+-eH(w zRsiU><($r;yr<^u#hf?}8Vq8ggu$%PyzTT(F$GVq&009fqA`Lp_k`1klTWN1IJ6bZ zyMo(p+??SGs16caqLYUL1Ka)OTI@V5@mhTkGugIoZ2WQH(`icd~!TckPk;L6(bKzY*WsEMV`06iS6VhbM*=tZmn|x)GE@>%|%U3{JFiovL@eFG{Xbi(HTH6^m1-$#V9oeq$=Jl%WCKO{ zO5t6V;flHj)&#JH>P?dlZP8u`AMQ4pR!$WZ%If+ynJ(g@a%o)*4(t@htZmBe?LjD> zDmlP`J!;RkWin=d!mQk4_KZ*Wd`7UG!aBX?#KO;P-a>bs>+f3owEY{JUa0=Il5)=TSI$~ag=?y!Mzkc55 zRp}tcTCVNEA_F}hA|f0ku&l;qe$V0dvV}ueHMYD(2L-0Ej?g^LGp}~Ja~8WnZN6DcwA!+!dS*J`a=LmRNIrzLe*V}*rn(gPG_OG2 zb~aH)WKmQdUC```OcsK0IEPd`hsP$x&Q@U|U161+%?Bs2O_X5-lPOlNa6(U7rkyZu z3o0I(>7r8U)$V2K{kEy?#a;}HEI^N|3c~How=ez(4;vFA_ux*b%nvi2@n)v7uY6`I zJ3V<_&#<&{v&x01rrC3Rv))U~KLxox?a#YaB|a;PKRdn`9knpbUsRL6ckCsXlVb>t zxrHUBi-pY1ec<7Gw7RZLX%|&O&THM0NcyV^HYfH+q`wa9EVgFz`?jT6{mA|~2iT?E zO?)U)^hC@)Fk>51*aXF0?Ju{BD5D+pLJ#=kE$tP8ULN|2qUbPtf(8(q9a|E&?Q(_= zt7#G&s?#|qWWmlbAcL#AF*4YArrfbG82OKvDjMT4rvw9@-t;WM0WFhpB&4ewakyZJ zD=1S}yMpG{lUJm+t6ASYZ}2^BxQ6*ntp0smB%((oZ2&%00`f*Oq{GszTo>oi>Q-E8 zAyf*c)AB6FHNMX>_Pd-%(g`N4+lB)5r4M7dpR4jld+Vl?wBQOZNu#DoyQbWNg-Uz6 zyvOoRRRQ^PhHobd0wpa&Qzh{xif*_%t4DluS5>gvEIu3I{V`z!42Rt8wFA4^1XQ;9 zG6!bksF1SV`(h}DQepqvHH#8yfnWU{MrkYb3LMCaVt9t}G8W9cFq|+a%FBw-fgxG? zYZkgN+QA8D(7aCn0{@VzC;9>|kgAc#^e2j{^C;IC8+n}8H!lDJ^Vg{SWUDRWg&RpLCtIT{w)w6s{#(|oBOSNGa$qyc;#W^fB>dlo2KuCZTr7at#%)`< zZr#L@)5dM#z-|m5a#P67;4pH-m@#WcY*?{v#GExNR%}?sW*9GeBc{^iFpne25hK^F z7`colo3*rvG2_N=IGa7I1`Ae-R2H|Dwk~}DVXlYX3dOY0H7Ga18>-} zVJn9X+czWM9#gi4P4nYy=dg(rcbOez&ELv}vv%zpXK>f7!Cw6swq|hRYzVNYZ#VDW zzJCJ`E_^ug;>M37Pp*9aIrHYupF@wX{N7^47L2JBY0MZfVZ!7J(FkimF5eFDxgz?1~aUgic7hsH`U>FF-k;NvYkdj3f zaf}hhfLRcDp@0K|7@~+E%2C5F$|&=TiYwX@%ndUHqhgH8AcKo9%IKoYG}BO{B8tic zQ%esw1fvWuDbk3{iYwysi;_23P#p$Bl%tI}-Dp#eH{RgjO*aW?bB#FKD71|?#%w9X zmkV9ljSy(AsgOesaRUxRTXbP$l1keFV@zJ;bVQOyI2c2XF}{Sy3^Cm>GYnA1 z;7}M&k>VE^VIKZHLjzJNobYK1E0CIkRieJK)TpFZl|ojevTD_-t++B4Q?+K*)hn-5 zbHX#kY|{*2m~Mx|4c^=*m`B?MW1bMj7(@(r?csofMtcsnkxIczYk>fZVK5G6;A9id zmfnmbj%u`JV~#c1KqiisLVyF#WZ#H04!WXU5R1rT6B00S7nK+s_vn1vPu6fmOL zBhG;XivCRk^Gl2~c#OaWC#12=Pyxs$Y=zWO zDx7eE_7|+MRrcCffWit@K}8l>u9Ah6E55cQsa(c*OnL6l5SpFIGGhRD-H=NOP*%E{ zxeRiH5zI)`f|$h!U`p8d%r(LxgcdyD0T9T6x-|2y&3FbIdz@#FPGNJ;INJ1GDMli(aWfnqFpBq*vI6a);Cx(J!36>uP>|h55FFea6T5o6W4PBCP_MP^+Q2QMQAMtJ56O5NZF2FQTRss$fvP-BZX7)djPfe|sP z1~ecGM>_)q^$HlaZtXMoy1_<;so(72#41X2ug2*CgV z$u$rdQV#zKgB?x#AO8y_<#b`G!du1HzC{rok6tG4N7NV zOC>PC4M3NJW74U0^Oo;G1|k@f6d20ybzTbwu<(qK{$o!KZV%-Wco+;IF#$EG2sAQM zug0OXs%3EaF1#6uWFF*u5ZA%+Er1WdTV06gAKgoI1rKn+};F;s;ANu2@Yz%nqy zHaJ5xk%UFSgke~qGlYt+sDSpA4^gPthh^A5p@6Bpf<4XLs;oeV$(&WVLX9z$tK3Rg zv;qxK1F&cdVk9207(?SN5jo5UG-$)*6@vzzRZoZn4%m`=b%aJ}i#EkXH&8?RO^Hxl z!w5Y<2Yo|!y?{6nOxoR)5P+Z%B*6X$L=`yD;REEr++l!BT}BPPiwDt=zq0py!OOi@O0 z$p>5!oruFWJQG8#2}F2=Mf`*@R2=^hLk%2&3rLhZP1zK z{7b<6%LqZhIE+KKsY^BppaK}c092O{jKjMGB3DvXHe5!$;0B*LVqMzhU2fH&`Nlp# zqQ=0-$^-+Z-N0E%lwD++fysatmB3zw$4F>e256iwjD&Y+V$THD7nvT=JWbJnfh%?Z zhjixGfIt>N&3~L$9FPKJ)dPWCRs(bZDR|ZZU+i zhYKi}H&lc}o?tk!1zV_u^dtif%nDM#pesxT3mj+4naT-xn5m#-_Hd6su>cBezy+Wf zSI|nyA;nYh9FG0U^c=>@REo6RCw7oTI603DBxV5NK$Ve0211bnEYTO{M_?f7l})Eq zmWvQTKn7SPHfZM?enV>9)W6jo9hy)!XoC^h02VbB<#+?Y{L5>+P$AX^-z6emvT2*T z>B8uxZ$P5{0Q}#T8K^LP5q<#!GwA2yiHD{^WHBtmfZhOPxj8)s7{Crts)ig^9K_!4Z3rCGD*WoxxE^LyNc*!-aBVAz$IAj<934uaf!$3Tfc-g=) zsmV6f0O^=z!({+`&DX#wAbmYgOSF`MR>Uw^V$DR{Nz_D0P+ZLj!|}L)H{1Y})xeKB zB!jL~jxK1#0mTWBg^S*kQXIt!9H&({MGDLyh^D~GaYa+;U`J8~t&oKZ#1B%?z*#)g zpaTA628;wVctg7GDKj(=G;oWJ2I!BHqO=%;6@3$YYRX`U6P6L6H-y7Ee1kV2UN>CB zIe6I%d;`G1Wte3^3ynhwiH0}`0R!aHHF!f&)tv{a23MjfHiUx>;n16E?bdQFbo6C% zJ)p}FijNiPd_-D!2t%PJ7pO@Klp#=&y%Ue&DWu(nFhIlUsS&L`NC#-m>qP-Aa>#>3 zsu*ZN(rAIugu!D;fQ1z9E{ZB5nU?V}lJX%#EUaanoRhuzSpDInIB-L>CPcK3(EoKqIsS-4 z$mW0)WLF7z!$W`I*b*rRb{t031T&Bc4tPwnAYNS6YXBT-N3^Ru zEyDuYL`F~pEjUF|B!&18>;SMhsTA0O@ul2Dr==He7=dWWWQA1DAn= zc5)CK!kZ8X0S*wL4S>TqkexXYfzoEB-ED>uyoQ|x%-$i)ns#jxEAbNVMxgmBnq&YLc!1bC=~ekibVno`2HVyw6exM zLnc;4|2R*fDnKx}lS*I&#nIL5;6%(OX$dQab&-oTh=WsY$?;D95e*ALz=VTS8Gu=y zF1r2}{sEasA0T+qJy#(!Mpy^fd9bGc3iWS-W0s5*s7Y2y5X2HN?P)^}uX#(p}Gh46Ks3B>=SjLNWl!`00XlVF2r@ zP53PdlAMUQO{bTjPI|R~qIg5;d=3uO9eJ7~y;ht-e2%(pa=%H0cizcE$V5NN4nC$U zHE>CHLCd{1G@=N~GaMIPd4qqpfDE{R25?aeERZ^lpv3;Epfix1s&JS|mXG#W#R}Y9 zRhSqHkjgv5TvfbS1(?8B(3py5MUCNDM70&Lctfn_7sVMUrF@f0REv3Jmw`Tmra4)? zo>li!*-LcGOAP=EM-^x^s}MW^IbwkE(l8tf0eHSZ4WK6m^kGNWp%GkA0knX+gu^uq zj5UCRX24~d9&t@;_=W>sobtv^ONn+sW(HhTIbm=Dn8(T#6J++(cE|wM{HF`Fz@g^r zcYvW6h2D1*0~&$I9S;pDbiiWmKm!m!6m(_>5CADaP2vW5;9>~TL`dSonyG5YA(2)b zEK>Q2TZ(w`6`4TF#K14)LdwX9w`hO~n1BnIK>p{l77dhu1{^>&t$DM}YT=OEFMwl2 z_Z#bULk0}Mj4u^3laN7>!^&h4JvtufU{MROn|qZ*w6^EBUV}5ir^r1f1lzXN=qIkCoY zpr%RA0bszr3d1sN(I;j)a+QD#Fe;P@{(t}=B{|_|8pK2{?4a6g?Gv z5;|$im%ud-w?vpl(Cg^r%~CGIGvCGNOwP*GfJWfNHat!%SHL$#7+&P4O_+qLkDRB3 zMN*uAi6MY>H--2hEcl2I$dt;cY(NFLq(~;zjJ1!3c@L=ka~L%PH0US(C_n_|&Z6B? z6Y+iCu*?#oOeY@GcKn=1R#{*EK_zuf374VpH*f<6JrxIqgE%ZzHwZDjScW*XU2W*! zzy6had=NMo3!&L>Mqx;=}=SaEz9N2gAS_XmDXfiD0yh0Rv}Fjb9r#D#P_F zn66;cIBpD&o$u(`&( z#m)P6+uLDwi4j{{cU%6mw|Sen9jv(7vlFc-S8kO;g^CrKRkX^CxpL+eDKKOH%=vT* z&y-!Ya+Tt>YS)yj#ZsoY@UXF*sNj8R(`t>^WV3N>n22ewru3BmA3{CoB8_r!PyvqPoDq<9FV{Q z4LlIR1QlG6!3G_C5W)y0oRGo_ExZsyd!z$E0pkjDMwr5gaYn>qL?kA}5l;+p7-39A z@x&Nq9I+T1=5Qz?fxrku$Axt4aiSo3+%ZTY7n%o$U`mQfCy;jHC>NVJN=eF%K63IG zoTyy#NosxqO8x*0jOhv~vAW>~s;|5f3o59}0!y2)#CmhAI>#z%Ic6LSY_a9=@-r{T z?BcVn!N`H^t!5f46tHF(V zhL~+~Ym1m}-f|2sKH1vFEoPjn)z5Br-Bqw%jfoDZ0Wk0eoO8kfC!2GwA#Xlwt|>1+ zY^JU6ylTmNHoN@N$&XrVt=%ubY4a1uh5!J>kll9OeHY$%<(-#a3h&v_0$_3@1{xA) z6wzP3M6?S;fK?O`nuGoQkeFs{#L>qhC7$RDh9m-V;)5KLqlS-gLgvaTx1_R3o2c9} z%Z@^}{z=Oxb@>t~3%HV#n``VOt4^BhwAn1MZl-gru&OeQ7(El!4bemuJK9gdmiF^$ zsGA#R8Mm5Ih8ET`-Bg9GH{J9V6;kke(^6mi^tIX2?yRzEl4)UTWZL6(sJaEgq23>XQ-JJ8zJ^vi^(Dyko zpA8@I@ZZ9OAxw1>hgsO*+=_9=8E8^uYxaasd^qFYG44I$A}fZ2V!efG#M)wJ(ZPcK%W0;K7VOZ(qHe1h@sCz4ux^g|vl{(d_C_@8kIA>SI&>OJw)*SRraB6TH4h94e z6by`GJ>a=qxUdB-@|;jx)5^xPR#-0cXlrri$_9AO<)3wh4u?6^;SPD&!_rB|0>)s` zzW&v(!szZew(}Pf8FsLL*@bt%3m%asB1Pc!4kI}D1u%Yr3uMG(Njf3f@;Xw+GD0t9 z(R-3ISYm+=0tEw7U!aVDRs$tc~^qxWu>CbQsa7`|c@`rIPE_r1@2iDcSf+;YK1 zHYQS&=@bFkW*JwwqHAEglxr$kNlP(MZI?NlY*uv~S?O(Rbu)~gfVCF8y-NNtx*Aqc z0`LHDe8XAS3P=Iqf!XFd~}(UfL`?ghkRyr?j_ z`w;A6m%8J`NMJJxkuZcXhl=Isid9VK6)~cbCv{O7$TOpqQc};Ic=0CmT;s}&hl_ar zq6gIz6FGEdN1p9bdq3mjoW25%uWW;EhWgX|p7xiDn(t78NerzH`6opYs(g~7R0?1L zi>+6s=+E(u>~3xlwbv!)10`a5?B-zj0BnC8)5+gQVAqSoRDhq)U3XPRLZ>sZOkISmCRO#X7Yo$9#xFA}x2 zo80u5GX&No3YVY;>y#7>>T&BP%f3Be9D@Ug2(eMP{Or;`P&Lm~c{$a`sW5Sj zD;Kr;qq(x47rp6KuYg8ZptA<0L)`@DTvg{y*rf=Gbe$c*plHr@_Enu1o1(-xHl>{u z7G?HKqZn=C&wQRNCu;oC%ZkN-Ski#{)OKn7b#*#2IhiM3sj#L z#f)R@@p-?Xo^+124LKcjEOw+LWxK~= zJ)TlAdJ6UY@FG8nqLO_bO>v@}1DR)31ICy6T5KwVNg9KyfUpTw0ttvf*t7-~t#BJ| zjtomwE0@SdzFXex0v+ijh<++L63@3@gsj!Ce&d&kh@7>?whQR4fUVNLo>p#OZsQhzA4FhB=BEk~u-JW$hYKu?Cbh4%Mwi ziK^DjxW}@6#?q9{%DjCOZ_7q?PvgQtpakGpOPy|g!m-rIJq}z?kJeV9ZY^WdN6U+w zdVao9g8(%1++i2{*ek^5mE*{9_!MKR=B5Y)?BxF27u(pJZHUb#z$xF~mW^U%f zDsGQF4WaDFvIJ={lICef&2B!|Z>}IrVg^`%S8J;0)WUBUPj<;@0=2nBZWaCuO zCdXuh27rvGD9Bfcj5&@E`Fc*3VE$#68m=6YC2*##t0pI_q~+=CziC1eqp& z5G62DYZxSBf4*jcd@D5k=WA4I*J2NVT(I_RBgl3t2q_2%kxl4^uNIBL5Y^2amg*ax zulvNyaU@5os^!Y)W4o}93Q;I>t_58H0PMby8mrOF%r321XRY*tM3|^x)~<=d5nvK# z{X(P|@bAxx#P9e|V#Hwo{?ri+z5q!KFrJdfjQ)^iQs(jK(ExX1dMNDSG>_u;=(4WC z)6N1Czao%kC0CjTQ4ndhGHSIrv1tSaYX0KIOr4O3?0w=A>%)+{N2RHFuA@dS<`$X>F7ASi>1>{XP@xb%V-DeVc&Lma?^%COFH zM+%K{~iEU>}?F)uAbuM!3G*W?V?B#H66%mv&!luR&Xf`BsQ>uX$9>`ZH$aRM9=Pr>g z4uiRZC02@#mX2k+U=ymOr9OW0M6V1tAqSX(>DnfTT9|1#XOu=k2P%cAVMJt{>`%{B zBt?GIiBkTgVAx7^-YoC%a7TDVARGcoFM>&_(;*<@A|&ETpL9y6v`Vow9%>*MltC9j z;)_rwO8U@b5-%r=Qp4KB zR~E%Nly5CQ^ppgK0}EqOm5-+?v{z0u1)qTwU*Q!bX(V4!Hc*kqa?ZB`Xq3hVG*naazhB_feqr3 zNd6iEN%P7|E#{mc=3R>fNAm3spY)Yq0}f=wC?$~R zUvc3EF5uaOAWrfq^S+`S@<@B!q%XPQViR#JE;gcW5ieXdeO$>^JS$cggJhA*kz(a9 z^yIb3VHsX+K}9koVeZCMN+S;x6(w_QGD$*jgM9b}n~Y1jWF$4=f^`7HLuW;I^a2Mm zU;vKJmR`tlx=;I}CHktRaBy>L$7B17wHdL6aF!)qsuf$)R&5u=DFviB)lg5~P*-v) zr|9Z9$RSs1hf!c9SB&OZeao3{oHkEy$;OaRpa4 zF{7*^Fsvea^#ptyNqiwi8&(j;TEkKobbVg|7Fy~uehpJf>XH~VQ!KT9OT|;v*A=Sa zens^%Xkh0;3!<2|(F*>Q&@!+Bn&O!2801fMPwOZ1V(Ph9Ag-U$H_!?)J0(a7)Gv%Rfxd` z2x3RzU<~k(Nyp%bm)Ihd*ocjI3?KpzEg}wxn1W2qnPi7pS2w;m8}}L~UY zDIP9S8@LRW^9}pr{l4i#k(MoIhT*9Fows3{J*_#REhrmPuZh$y~ft>z>!8g!3oy(ael7l$N zIXToBp50lU%~=YvfD{OVAPPdC3&Nk{APe?cpaB}6_nDtb;h+t=p#52(^O>LP0S9hi z8m6HKZr}z+A{Tmq8hU`DExMvBdIoNw2SWOz<#+~WKo>k(rDvd`MS2=iTB4~z7j$8x z1B%jaz#F`Q8gkkj_=2bTf-i8|8-&0caDbUxzyXB20g9WrjT^a*d$^OExtrU$pS!pfzydD7wlCneuN%9wTf1-Dy0@FVx4X$^ zG6Q70w#nPIUHbvf`@GXzz1!Qp*W0znTfK4nyy=_1ZM(kb+r4AkzFm6*F5m(xK)@^D z0ydxm3_QRC+`tL^zyF)SA6&sBT)-84!X4bfCtSc0e8H`|yk(oV`MbkmJH+oB#OHgr zrB*r=AhOGrs>tQC8HX4_`01qOC!fl*Gq}1k{s)Cmo5!ye{m=@?r6asIM97JJ$b)=C z1mMV#ipZP%=$stNqa4ZuAOOO9YL)zrlpLu#NXxr?%fTePxg5;5Jj~Hb%ZYqyiv`Kk zd?uG%&8L>l-CW9>%7UEOaSh@Sm4~q!Nkemh|Lcm&IP^6uUydcoR;=n z&mY~%865!pd?tay0HgpMhVmP*;~PXf7{y__f)#|xqv=S!aKM3Cd((27E}KIe9LmA# zrm<~%oYs{xoFN_8bA8a|yvUJU%8y*qD_zZXo!E;#(v2P2lU>=Do!N;!*qa^N|9l+E z;Tm2&2|@kUMH|$UFxy4j+q=Enxn11;MVs5d{oAj7TBotr*F89IJ=)(L-s4@~=bhe@ zoY}Md(aRjs_Z`oh9nkxI*z3H@v3$(EoZ!!V;J-ZK2jJkb{K&@{8X{hTprIHd-r~2x z;x9hqCEntL592xB;w!%5DL&)1VH+f<2E>isSAHq?!QBOY;KQ8DXI|l%T+9*P=J9>z zhg{6-J>QYM;cZ^%Z+_@wzUB#@&V%9rfZfdXozH`vt${k(nr~Ju% zo#*}C=ZT!s!`{w?JOP5CQ1GsTxRT;q2b*q3FVs+WYRBzzqhHPt@7%5!WI*Lv-tVaq z{Sv^tVY|Br-|!Fry9s}~CmjC33EaA^o4}{LyDNb3AAhB})8v?Q)0)YDg9-slVU;7&XxWQlh$DjOz zTl~*I{IlQt&%XgC0RH1&{^y_m>)-zGAO9zS0MJSSf}t3+0U(G86j*H7z=Hw}A|zH& zpfiLI2PzyGv7xYHH3Z<($FZZwk03*e97(dI$&)Bks$9vkrOTHvW6E5a4}eXZ3VKYN zc0=cl8M=DtqNZz_(Ec7brUCWYBNx)0x_}xjnpEgio<@aI>%o=l3?9>H@tDz-M~|^z z$%6gbd8lq2O|^`8q)5fdB1g`qELmpL-c4#Z?%r~;^cGJ1 zx9>Q^b@x_28#wMPSgu6BLcMzR>C>ramu}rUmhIfHcc%_7-W4sYQmI0f>J%ze>s6^b zwI2Tb`s>}_$A2FcegE(QXrFxVt+&bqHwjRHPz(*W8hp@`af%ayk164V6(*d#y&V9i3ypl3=` zi!^6?iRqa;b$V&1)6Al&rnBfN!#r?+;c6CNvCp za!Dlqk6a?}ypO~yuf6l;d+)ybUV`tv|HhjMB$=Rs;7u6Z(9Jf*SV)XB3PDH_gcJ`{ zu`m${BeBICi#QNQ0@%aRJ~5VT^2sQttTM_Zhh&ds08}soFhe4fB$PJ)X!FfG_voaL zJ@$wU&^`{Gq%z9z!sybwF#6@9UoPFH)KPP3%Pxyv*|gMDgSpErO=G>w*i2(B=h$bP zeKwxA?2?PxY_pAZF1FlBH!go!V3`FoocT4Dv&h-$;9kN>c&D~ZBTL{~V!f)aVT94e z7nE0S`Q?;{ak=J|cfmR4po1O;7+g@X#pzpAu>})b48gkUs&A3T5LLX+dbPEu9{c|3 z(q`L4>Z`BL1Qkpazs2vXQ-MY*kxbG^B#uPVNF$RtGClQ?xbZ>vcieGA6++W6LBf#107SO30vhmu2uz>?_3^U3 z=|UMn^AVDifg}kAjephpPKT0PpX%1OAF{1(hr-&U+Bc~l4C;kiVw0y1mnA7u@l00K zl3!}^nqE;(SGuyCtHc<_T8Z(CU(j3_!B|Exo-tOHg985~!dBcRBA7kZ?r39wA9cG~yBPs@EkmImu2!Vv?7nq$WWb zO6bYU5tldx`y!RFVL-!v3lRo1HpZccVdz2%fyONl(u|4;&>k&YpfHC?%wihzBMrQX z1#~nd3TiND&)nb!g+xK5We^wEbW$_1i3_E532cme)0^Og!g87ra4`(0n4orxLD_g(louMbC*sH;pr#LyTwJ&^E*?6%>g?#0A#scDEVINwaMGCl3|1 zD6I9M0!&l@56;x5h}yPrTbgK_v;?P(&MFM8A{MQdg;FrKs&ZotF67L}#*`+@jLbc* z=A1Qzaq&@iOlU$H($EBHK?_SDe zUXJ)=y^@-}PeLM+^~zqnE@?0TL`p%yXwd(9*$fatq<#_6C59d{A!3mA!4$y=0Mz={ z4tw~+AofUH2T*}&NQs*e6p{vqmNRVjsIY@Y5??pyGZ^0tn}=GVm_~@DMb%TwVS+QS*XQ=eDT1>KG~&>_Z+N{c#emhBeMTl7G0lG?y*38!1zW^}Th zDpPOC{5WKlG^A+sXtK0W#?gJzjmKqHaPwR&FaYUy(k=0cmwe(_!pTfuw6iLte{ zYzo4rOJ7ezu@l8|Xo^+%!DRzyeIXKo6vG(Kva@ zu^7GW70;|i8OY%bXdLOCGlyK{mUQ89?6YzePAp%sQI1yFLdJWyy4q#Dcz6V)x%P;= z-U+e_O&C}4_E^V^_jGxop5#+Wt<;*!{Cq^UIaEV=bAJ)|U}-jT7(lNkIx-WHlV6nsWmcP(H4Vqf2*&CT}6j z%W~aGOLn~PV-*-_3iduC6ZU?qb6V7MsaNZB0W9=(by9 z<5<@QPDwTXL*aH&eAU1%%{;5FuJ>IbmIsC z1$7KYcc+d{l@<_{Zlwhglok~f6cp6o{PTbNym-!Y&VA1P+~@vY*XQHZ8>4Ut&A6V+ z{I4jQO*exaRoLinsZavB{l-P9L@%mdB2rKJ)ud#-e%R9F9Tg?L`@Sk-#RhFcQW1^@ z6HBh!E2^ByZsSW**>3c)4~$t!hpqJHZsxbMumYox9)~dA}D1T z+ma%wIm-@y32^SnFoA=o5JbD!JBVH$^2 z{UM}Ft@}1AEu$`^9);NwNxSpZOoh`-i%luAQ=z&rGzw$xm~WnCudTD^Xc=Wb2X%6Y zx;nL7zpQ6Y^wO^EPzr6vGbuE{Avlj6_KIp@1p}I)YOB6#m*w6Jx7#jQYOAS2E3HYr zYv*AfS*2TQTwgYj2+OW91uAxM|MfA~4=KgFD-W{*tsArhHWJ(|AsSbEN286qS)KbI zknPs4&9}O^+9<;&Kq&{7mLEgDL1XD*ESds3we{XdJWC3?Ttd@%++b6#neK0;UM@5F zE+m>NG&xv~nKn_0$Wt3GPq9svDKbS|nrP&E#U-0-Dn?%q5OWR3iz5jQ4$gzkYGIwIEO5h#Tl2aZvTj_ij{R$>75EwIzD*xuCb^n77hy6%9kE=5D(l(0*3 z+JligKO922U<7i~lu+;2IJRrsBSSLqbPbYIy4p)r3TS(~}NVv|F6F zYio`4+ZF3$j5<&;qCBdk@yyV3vRRegM!Uu4MA)V%ikk1YM&Iwqf7$|LcmbLrTC?P2 zCK)&aBxp{V`{b;fmAr6o)~UxgNLJyqMrk8$maKz94Xx@(Paj_1M7DOe);>u$iqR%d zJRmidXpU~eaQY~0D#AM26#ktKgGMLJ$XZp@DD&uA z;n0$Ik{wr}khS(*S8ZUH86OqqtP6_;XpCO3BG7DKspCkiUA}Ur@J$ z)PGxrz;O%KVIgj1BO<9}xmQ{UrR*5`{w(^9UaVr+49aC_vH&zlyUE)LO>Zs_fizS&Y>5lXO;^9~(vd zgd|gAa)#H9;llzIQ}E6+0fg)=x-es4MiAcLm{zL?UNPM~%M=g`)bBuMeGfLUs(qP5 zzMouJbLWshiFU64>8qk(__BOSb#2m&SLYziIUJ8uQB3~gK;f?xs`6O1)H!u# z_(I3$JW+9J5O%LhM8j9qKv|KqvG1(EBATF3lTPr0ig!wge5eps9TH1+wq&U5Z<%Sk z%y729{U8kRkj78h1+MHig>&ChcGZMN*(pmwpl&SlkNjK;w4wbNNY4a?b#J0ELT$?# zVm7a;J*e9FBeP{!WdWoAqPSSdPwE5>@i@sURiw@sRR6F1B`#|C7sRxN&2}DY7PA0BfA`0-1dyH z2xs&EZqf2(bxv(8L=M-q=A+`#Tq@N8o`{-~>WmJ5CfXE_RE@L46mJww<*!=ljTM76pk^tE{x!eS9>$)WL@?29ye{6hv$4?IZtGs%I6TG99SL=PQQz(tY|_!^7(nw%J1#p7?kYF6F^@Ja>*GQT;fWv%sFEhcMy#6Pq2UoW)A@li_3u zI!{LSdeiiVXS>~+V7tdkO%imH8esDy;q+aC3zBjy58`n}(02-*b^xh`VcrD~{T8`mJ2-;_;L~zCuRWG;VL^X4NI!`! zT(J;(>={>#oh;6whWy|w#Zw=u8`Wjel;Gp$lBv(*$uzYZHf?DyOr5b{EHlR-!j3&< z97{Wdr5(i5LaL0}ProR^kCgD>$8So9If3mQd!6HPvdJ>&g*=2IvESlXXy+>Llob?Z>$!e zVk>j40v$KSwt`=~>2h?OH$m}oV@<{|QSA4TMqw!bS9UB&D)d0mpn*xa{b&l3FUNf~ zqk+r=EaxTie?VgCDd{W#kU;xZd0}w%i9E#lu8+SqMOD5QAFkO5NXkXafMlap$~niq&uk1r}gu4xl{&y}=MAiaX;E5(^Yry zLd`FKls-qHfiO*=papd)LOt7px&Z;oesVb}8o2)`5XhNq5$l0)2XZ37qx5uiBDBx3 zw8}YO*|0!iz#sSyObY*pV++*F736MQ#-;~voIRet-$NHVbUg>iiU)}R{@Z(O+HV2u zzX=j1A+GO&sIb8GY=H3mRY5vcF#@T0AeTsIrgj^+a}&gF0Tk5)JJkq_z`xSq09ya# z4V3BFaR5Nrmd+zba*yw(c+5Ovm`K^MNl0m7lTKZdMxZ=~K?IJa;Qi_DATDWUR+I1w z#Yb-*IcX^R%7=MCM_u6&j|O~TtB=amB>`7*Fbo5s)7McaN5B`t+(r9354u7Df{6sM z6#6iVq|va&%$M1=G+L(UF>pN+7UJVTyRY?UE>!_iczLOGQkf5C*p)&*%>x;ID5*dK z-@^moo;WHHufh58Gj>{@9_(5FCXAB4P{6sK*6?bSlME8T%J;%<8nTK6lsNPaUw~8C z`3bb81R{Wf1FcCx-9fy?x-*h0r~JUzIA1K%M7NCP(<0KKQAd*F^yV-@r5LGxXYbIm z{yt2H{FhnF10!OXFUwi2x&5$`Q4p;>`~jsFbGjv}ZsY?Z;XCkLo=Nfb9A2^p2rxUk zQ8URiMXdhHW-n7uq;;CCqJXh9R+adL`?o>pm{CI<9w{E}y6njU)?RyxAbh!s)X6Gc7 zZWr^JC=F8h#8B6Z^N02dfGPYhbU9rKTE4|D_o$Pq-SOKH6Q8J3A9hU0?azr6CMO)Z#`!F@BH+HUG9ead#B&uSoB ziYHiGOd**~q^Cx6_0GW8)bwR<*X9~qFrrZ~8=k8~uD8J;kvoIjHw2=^`G<{prd@KE zx`kd9-G;*k1vtF$SJMif!~kDi4v)yBvDdBzKtOCY@_FQvxxV_X6??zUDY2$5Y!cSU zU@J-emKYHDHg|{^omK#JW9MfkpPdg%E?srqV-R$O6!URk7i}R>Ok+Z1 zHrpm9pPEXRt#ckOb(*H_jAo`B_ZCPFLu9a_cG<{EEUi*rYwX~-UiPQ*87x|f+8iSJ zoUhOeo*`k{T+N6IvDpk6hn!MYj0He!vX!PPl`>#wTejHIgIZi7gJsRXqTu|xACUTQSI7f@3sB)3MC%{hg+r2H_p$1v)84l=s& z?6UXI`=TQSUaJ+#vAcKhX#`>5U&*;f?Ciao@-!G&kZA&2vUq`IZ}kg?dNkC!kEVGx z8gncIb5uB8fl45X%37BwM%NpvT!A%4lv&Z0qyoL>~QLqEZZ0s1vBA6 zYW^&IE`t(FO4Bwbno=yy=}_uA7Ab$t1ZEc!$ewZa+520t?u_`E%3pwn*22>#(qBg6Uc6_-TFGob6$2F-k^O`k1SDXI^0gjR zwu2a;$_W9&LIPfEBe0g7(1YMtsSqO22JkC+v5HS2C z!&knh;5AlHI?MtL?M85Rs=*~QwN!anyhEc-4&-rWz;V+6Od&HRa*r%wHdr!Mr1vK(U&t8EoMfkoybqKnMT;rjSa~_yLiND$J-E z8ia^%g;Ck#0TgW(L@@^~8VWp+HA;kMlZAvv<28X;JW$u74}LKmIA%EzC>J+s2LLicD8OxHyasT7TZ0|dhr!P4WFaGfW)Oe| z4V5Xeq{UKwg;H`Q(Xw2n_ghnR(XvSprX2jOhkph}CtbG6BxpGpy*O8Vo}{B}zzZv@ zTa@}S!>nee;y`S9KmN)r`&Mlq$nbD5#t$7uB)A{#;QPNYmv7D z*_%ePaSs42CiW8?gefH1TXm_P3}XTSks|Oys2O}r%!;v6AVv0*ku=qh(l+l(;SylA zk;0;K$Q&CL4-LbeHZvB~b6d{8R82UK0!|lz)8-32rQ@)00HZfl<0P!aei)oLy@9fq ziKmvu#WR}(x%j3AmM_RAq&SArhG8`+1r34`u&Q84G7w$!|kYAM^uFZ7ssJj&bS zkx%80ldv9C(V{Bdwe~Go1qa!Q=||^oVp?vf12|lUeCV))tR;gK6^;UY(8=eVAHPd`{lUCeTI>2JPOL2Oc=4?wYNM!EjAO6MsGuhdcFS6tAhHrsyvrQe@yIhMYEq~D zHr)n!(v-D^0swuznc-IUj{Q}m<%f*Z4C?knoB}SMathC_#Pi!3$~A=tHv;cPK%Kr{ zcaW`r{i%YB5fJCl3mYAzUDjObOHS&<2T)bONJ+PcA(B^MU~y$wzNkYVo*N|!FUtpf zsefD&uPN47IMbjd(7>`sM8_%{03U{(HhwLIxZ-Gh1yEUtVLl~bJ&7o1h-fQmw6;v? zn56#GhjLyct%Y^y%f$0xi^>~Q%O`ocVyNt|{yl5>zX3&*&Z&htDs3|)-=>bxKTX9o z@szv3pPcQS%*9AGV5tOqjRkeTGkX(ew9BFTK3S|9io^5lfO`7bmA62X<<(F6+3yPo zPR+B!QFua=j>-?YzR$28>{Y|^xm*V!ZwMr!Bq@f%v(HyoR+Rz~c!`|SE1I*|q=W>3 zP7)6s%4;Q+mX>mIkp$>9*1P|;Q5XWs&r3Ac`WcQQDC~N()|r6Est}WT4JLydCL}4w zlCmwP$Gx``cevn}Uy_c}p3c9<6baR?F8aDoQBKrcCu01hcn%A8=9I?sQhqKWnC%oP zp^+FcUtfTw4gzZXShAj#GMAqeT%~&h&;`zoX~`u`v;?u*nh_c$Re=Aq20&wF86@a* z2veFwTra2+N)I3bGfE(iXcndX<^T&AZ#BDWI)_*q0Wt`i>l8$nfEf_@Vds{~bg&c( z&x_KXN$JX%%INWjElJRe#w430P`()i#ZnVWJm|y+3FCodt1Q7II8Kr~Jd(Tjk|FY_ zhq5=`j{{0Og@1ONeAV~k<}^s6cFgs~CHXl({jpGBSh^folCD5Y3HP=e3Ngg8Y&q;b4D=@c{?7|5YTb0nxNfxrmh{U(lu z-SkOvuejxIsXPZAXtKsGwnR3M)5^G8lEfK(etC7FtR8&ThAuL8A6Tq1K~-p z8IzbS@Z5-sQzJYV0_uS>zaIg;{9H|p$*8vQz*eME65Ry{v<}9?{l|&R--~H zle_S&CJzFX`X2YjXV%6uE<>a(0bC`(KqY00=kbq8ZQLYY6~n&p-%N+V2T64XshU)5 z{g5&p0Lvj8-yuzehxoJDKJ4i#yv~qWDSiN4IN+RWV@Oq?o04KnRr@E!ekg^^H^{~{ z+mYv4RCffV=ub;NQG%2(Q{7Q1!LYfvQ(HG_S6QgmD8=vPI`+U8>N=h|S{8HQ5v1m% z8iWAfBro&HVw6YK^CROKQU-dGFk~Wu+$rV>Y!RrYZCeLU@4=*Uz;{!@%5AXr#j0^N z6P>!Q`9n^L6j1q)ZVak)@(xI>kznlnYCV?oULRp@kPr>e9Q6dCRcamzNX|a5ks=YK z4Tv_TWrhxAD|s50WdPg3L>(+qCs3n{@y1sK(zcE3lQ!{30(TEETMuEk&}|0fs2FaF zzaG;i5D1z_QAeQtcLJe zu-DbnJN8F zIY~@7y9?cTHfI`Sve)cI3qpwZ9J4pf)D@zPr`a83G^0%rpvT&gNz{@ zU<@N@u=MU)PW9{>>^i(##6Poi2=ok1N42KwLN-xwspXWRk7qw@K>%tP3^LfMfQ~bg zyUbjq%XcDcAcc9tKJ%u{t;ALJ?Bm9S4#u30DGF63hO;d$6RK?M9xmGlcx#6np8E`+ z2PnLc6>$)1YB z|7){)x_=OQaKN*`2)F;-hkjkuuc6a*Z7=fYMkN zq;?0J>vX(gYJ?upX^n;3X(_5S{`#1SA-EcZYegZ5Q#mjpjNsVfsN4lXnUp{e_nI)0 z(0`X6zfh&|qfRI03XEk}V0>%EqfZVICly8t)_;b-$o5r-`x6sMl_cx7MB&PAzR z5Jm348k20Sy4}eGl14Ij--0=49-5-uvFv`??ouA5#g{ zc)O|^VBzMV{C0>>6-XXptW83THQcR(2If>MG_|QU%6O+bRCPxvcH*^omI${8nK=%!ANUU?HIWZZpwQ>qKIJ zWV?_mDr_9I1H8~kt0{p7_uZ^%vvNWdQ+am6|9e&w&T?&&rIV_^K1uFHL2*mC{F7w>oV~06kAIrbtjCIU}A_qd*)=uS)vXVG8JRsda(?sdO^46`l6IAhor4NOxXI zvaJ32B<8usi<-@mZgGEtumO1AEAg<=))>ug4K@2@T-%YWas6X=ZP=z!&I@C>^rv8r zZsiHf@0;9Y1f_2;Jmyci6{c=vDuf1@bRbpdx?cC$=S;^hm!jzne#DosWWN9A%+%f> z<`G)svXac(Mh(l)Q|)8Pcu?r9?7BsS3X9$1MC*DKu=sij;7&aJpoS5*6}b2 zMU|=xi;|hPbbLtUaQZ95RuuCo-!qk){;<@nh_3vkwq`39Q&c{Pu~lAY7@c`JbE|X% zB2&rVX|dFXO%3;;ZnJ22y}8s$5_pl3tQ9niCPj-arW+JU2rZ^}Yb1GhVAE^am z9W(kDys4i(h;f&&Hjchc<7lx|9YYg#xoFtr51(6XL!_`qv$t;v7ncHj#l>#3qII ztu%2!9y3a8sToi1@olg0nR)Zr@mc7U_wAXhWRj%&dO=@av2n3{&}L-cBAaQg*3I>1 zg)erGovj*%H;7$!QY{uC+hvBf_EIj_Q{Q*}mStab)p`D6pj$%x6(1WE)Hts#`ku7( zUE@{X(i7{Kk_}@O`!)yCjw%7K%M?xZ)X>-$gQc`0CLBucBKN0;9Xk)Mxk!$X#s1ru z|F~2ooNUN@ARmZ!QM?}}Cv3_k63|TBl&6|mDAHf*;4xgARwzDk)ibn$D2MIN#fsi| z@%MMp$G7G3hG67Mjb64ik^eq*-o@Byp5QE< zIT*^i$ayVVnJX{OBucxkh#}0e-cXIY?!a0?{oKat=3|xyOG7cA221iy*@J^h+^~G1 zL(iV)8@p?-D6C1IA;PRKy@)YXtxc71kyAJ|A_ovA>jr|w)5SKr^u9F2b1f4W%wxNk3&eM=MUfCnq@ z!L6&)uQ7q?GT1#iPKG$RByq!(qEucZW0MF#rioLW%s6MzfXoDMY(}lRxf5vyGwof< zr~~sk+n;vuO_ZH=#CU(lO!_xvIO!gjezd&xy6Hz*xU5|P`9T;TQM5u{Chd)ll>lV5 z+DYL*l#Q9b59_jvvg>(`+$oy9o@RqJA1lFo)swG(a97;e@5!S;@8&6S&dr)`5y#et zb-s>|BAt`Up7fH9qJ41|j4sS}-jpGs6OQfNU2_WWM|Tz!oh!oMh!r~@2U0aPuqRvpag4_+(JJ`r;~QdyNN2&vJi2 z?J6PrPwi~s$05>H$QYShBvxL~QR-IhBJxVawQs)^Ddr`+a+__XXi;_QQ^NzyJNX7v zBT-@7a>e#r)=So$d-rWh>=Y7snggxN)9icM1{;@$t;i+)0ER#-m{V^mD%hI4QM$LM zX9~+#ar!PmPy6ZGmXuxjw)2NT-C^dRGzzzOGq@XZkGy^SuGZ~!SV_0!<`ypb_2=z_ zfm@G)e5C2t#Lc308dAdFPPm-jss8+PLO0a!uGleCb-(B9jW8 z6iV%r<2s_LzIe9DFDoPeb*(IO{d0)rQ;Py;jVYE!O*;HvurN@UTI?s$N_u5CUUG80 z*vhr7D9Mofoy}PDT*V17Jht$C)VTz9S{zqMR`#IT9we?>j60;}n|0v~bawr}s$4H% z`=~Y{wdZfGYDyxonT1h{EVkU*xxM+tO!UDU%hQUSHHLfS1YH2tAn55A&ynx9+vJ+V zGH3!BWwKVy{RSJMV0;ZPbMrh=wyR31`n{%}$cqAt)NI$`_n3a9hO}d(iTDiPuf?-T zGclsM$|uf$?^iXhZ-2XYVNFw!){{0PRMocK^&g5nG^# z&SUiO+w;@BD?0um_cW9KKS_UW38$=Wnd*Ktrw%&JsTi1NEGhR^;2+iERoK8cL}u3P zqG0ii_tjl97}vs~-=bR6lY4lk0#q*dawiIHWm7sO-M`4z2stUR3KOoE1k4N{);1+w zvV=wi7!MqNFOeE(zGm4g;c^)mdSCT`(pG8sRogah!;jt>+N-fTCYZMsZIU!gw6?a zca?3yl(>&xf(iR#vwfu8wE)1ckDBEt3K1m2O_J_N(2(um{PZ;iIsFQM-+V{hz5x9r zbfWb95KC!^j*#ro*5AQ&4Qp?Eth@fTTTKxfEE+^SdTcEeh3WwEwkM}2S9xHIMmRzK zK0{RFtU~hR;~I(`pOkj{O~A&jQq-@=y>%q7c0U^XUg#^#U{?6uAP<)#7SW~WeGllg5E?}0lX z)s2&2C(k2jfKOLmt^~FmZ+;H?Eb+<5SJa8RjiNdtNA(F4c z>^5gaNqMMxW=uoNwS|QTABWVjS(q;SgJ8GoQo9+jX zpAQVps+8581egn4*KnMkEbwx%S^grp$!sih`$m;OU7jVIQA1RcRkfIuh?OPF+ji*9 z=y$QRRl%wjPY(+3JXLR?lmDS9js}}6L+Wp8WJGVP8RKt2Lct@DgrXjJ_v>%z?dm{OjylQ&Cv+5ALTbTq#pdn8T~nSNOT#@@>~{w_WQ8w+u^G z{u-VLSuOmy!{w#*G%9y!5_Ok@m^*@W^LoM#6-sF;8MFDPaWV1%nd|Y~Xi+hBDtO>r zdoe1Gd$VUc@QYK*Mv?i=2HA~W`x}venx5)8@6Byg_Ak7981uFYH}-s=MNB4*M8OBH z9wW)a*Enn?mvxMfh|!gF($5{;491}9dTb>*ai#2W@ekroUyaaZwT#*am)M6Kjo(DW zYN;I};klg@B~jjGyA^!NudLY!kf;8o=)RGsLrEEZP^hNVSe2T^Ln=xk8xXTS z9c#{wn2@b<^&}pOe40y6I{|CEM@eziTr`mNjW{6Zpw?ZntPZ7g`t78HR#tkaEc~sF ziEX%x*z4|%6{Sr5SB49-j1S$K(od#bPSioI`?)`)wA<)1Qa!3zq05}7W{O!0XOIHF zOaY}Np%p3T%+gA|jkQZ}n~U1rpMTeMUh(UPBo-YJWKnO0w?E8v8S+E7`0hCyKQb?` zEpT=rXA16Y76&j{beD^y<`vbA)yQvwY)$K22JxEng1PMOCKh`#D~&j$Uh}KwL};5o z--ncW@06Uw?NX{xR_gHgaSBV_O8Q}d7#U@t#`Mk@gS~F=g9F>Ov!u?y7u`Gy< z*(z6Pb_Uzdb^Bxkk1j&1O%l~o6z-&;Ps|7=MT4Z2MO!;oa=sR8xl)#}<2^ghH&i+c zYx1PT+1d~M`#*b^C-tw7P1fDz*fLs! zEsRv-)W7!SKYQ82j|%=YGF;h~LZ#k{^VSN`7~O&t0tMK?d+O9Q5=vn?r_DrMZ!Ky&GZ~WdyYilx3Zkn)8(H( znA}E&vy^b9y#6Xsg>2(e`J{hGe(lqRt@4mHQLBngYLa;Pnv=0$u`k80d4Vh+RigN{ zjDX*ciE1i-ZK;uxQ4l=$YP5(yz-DT|i~rK{?GXR(w;67EHvHAD=A(&sKZ|Zwmb=jl zHcQqP?{AWq3!G8@S8}EZOH)##Rh>(Hl;ak*OUKU*tp>cDQmrxDopV zkp3X#!DHM5bdwFj#LT`@3qM0PF;$zX%5Z!d zn8?%Er^DrHoWB0KQg$x2$$Dop74=0S>Y>9uv2HtwiQ2m3m`zs#Z_jD&AEG(W3qQli zpsBy2bAxlg2W%Emba~30n|!!5~6*yxn|D+;?<3FxwE4#;G`vj^GqDji= zRsX}WWl2M7T(TULW0FRsCAVccrA|{J%C-%&R&I&NCozp; zpc!V-=?iGD2H>aK!lUit=AbHpIg=gaUwIH$mjO-9`x5R#xp;YV+;t$ zvlS$TSW~;cJMX8X*V12i9v@=}?(OnO0YT1JOn0Q=9fbc;HI=1p6X z7PP@EU<)CYRa2dfdN_#Py^xgg~p>NQ?{V)qaVyTN6um(End zr_?9OY={wQ8~)lnqpFM%S^Fw9DJ^lfawlb-*%(BAJ@xpce?oOC^u7s3WDE9PZ~F?f z-sSe@mSRQ{(zQ*7YIs=_WHaj+^@RInSQa*@ptm8YlK+m|F$TN*tF|FFPzQq_HE|?5 z>|L|m!$?u(NO$qt$rGhDuZBAi2gweA%$PjKTRXMy#wVDiBZvv(nAznV>TS!zJDk=g z?4~iqP2!@wji&BTK!ZHI{tbabbxeMK*lllEeimS<$!C|5=G8U2<3SWL0z=~MZmh(-FXEXUBr`q|5G^F4@uIShKDEJ3^#*mME zKI>pYs1s1l9HurQr-p-tAt%(BlbN>2Kh!>UvYz2?{OVM*k7xRe6VU|S_9kGi$stCn36x!1Z$_#_X4f}r1VFcw7rA$R6jkwXkrNJ?_Q>_SPo64X4M66u$2R=B9h9KR zlAyRXc>9~Y1-lYYasXfHl)(w;s`jRz$}q(Ejr%^1BV-%FU8l|I2>mNnJlE?DC( zR5LDE2eeb}$EX#=sAXKJw#KBtj7fjen?4bfGNF{7-IQ-5+qMzB=;z! zP|)m;Iyvmh*%Huv{ywt1l5&oOa<+b7KC?1|i{>!^Pf-9Wj<}7Aye*aiDv9VT$-gW~ zzAUZjD@(X6F1{>DCx}rDBd$i9JOlwaNMQN$3indU4-()ZAhs?APWr@VFG&m-fxpU? zFwjHMe$vNF#D?;NZ?~&HD5Gfm#R@=FlYlEOZ$m_XL-L)51eK=r-;K$?8;XB7)buw! zQE8aaq-_IG;sCJ8{??`6t-HS;eNlNl*Z=5`O52A!kAB=~1OEZ-!Jv}~N{QOa^0CVJ zkxqS8C6hm0#o*2xs$JHxJ=aycB2;_qRiE0ccB{tHaSV2GDfL@R^tj=rshBSPQ>90b zwHT}}xN&g9u{^JJ>^YdWV8~zgj5H|k|k!GH+H>kgF zP)D3S|L|w%!=L9LKE%KK0~9DAzy_J4?5BH9rXhI@SJu|hHyupeT zHxv^`PLjc=+%HcV?w<(V_`!Z(sbb_C?EY2o_j|&KG9IkxaQ~<34W+d~t;@*%Lf7U^a2*6Gf0nAT3_F8Js2aE9+26>tYkrFAa| zWy1itE6IHt1HV?{#hG#>%ECg6aKWR}f0kojODN+zzHKA6*sPv!C!EM4!LNz`i}+5K zi#p=J;k)p__D}L7Cu8hto_cK&6RFGpUC+5SD!9&y$J4fjO`=AEtKC4aTu4&k z=;I=#qLzuraN{i7%hSCXajQf&^|Hu-r3TCLdxf65#0oH91~{7DIVAYau;ZVoKjjJ$ z-6I|~uH~*u>q8-{uN60Xx`Wqp9y-%M?@{6go_tz*Q5hTk?ZZ$q`;7;2w|{(GXt00z z;BM@%Z`%z|ia#^N4iK->8~w#WG>8jM^%QkQ1iNr=Hogz_%#NZWblNB$O`3#xD&gBSfh& z%C!uQ^*ct5LVcg7MTHAlY8k2?d=`f{7FjV#w@*&X8h1|abQntwNzTk%TTw}u(xDO4 zrR1umo-NFkOxI(xe_!#V-G67GQ%3nC?I*L>EJ6Y1YBk#eWs6P$!re%4;AMSywt&+tYwO&UWv2q z%5Gp#p~@iv*1*F}Te7nHbUVxWYu~5(@;BcOYMu}{zyI+W@&T^Sy(L3epE$Tg3cz2! zWSo04q_}vvgOEmYJrxM1GxE=jSQ#9k6Mqf4OH$|``|CWn=@8AuCvTLhtMO~aK8opP ztxtW7waX_xK9@i3EF}83%|^uJCwbGm+*udfNqvDajW-TDyp6NT6UfrN8+!CVvN~z{ zgiPtxn3`&aJe7|UXBBIz%6=H;iTRgaPycst-Q2>2{Abr*Y;nHi;9=kr`Dvq$dLV>* zkjo5>;CASn4i12oH{(aT_wYg?C75!EhcJ)BRC6fr*%qZ12Zk|_(&4OqP#(1UbW|o3 zcMn{Fhe!6lm^umL{LJ=Ii6WPPeT^s>f$y_e^#%F778FYx%dkLR%h-bni5gj^IxRDn zPNJf(FH$i@OfYeF2V;RbcvPZ|aJ9Ucp{4k4UKx8~N>#1|{t#^UzNA3%)ffYAA#c3H zdjkD7H~Y;I9wCpvHN8(PDt0?D~w zYw1+;^Sb5&K3u*6`HF@uhZ%^3EBP*ASH(HB9^2xImKh5vUMh;O<8X=3&-SmybD9i5 zWs#6hC-d5{w;tEk&q(p!T2R4MT`B+S zYd1>w+`~OZjs7k(N%eelKi;7F7N>)@JVU~blsWS2LGvgvNfN*|Z|KfDvV0!LYJ}w5Al>0EYTcekjqwHM;fPb4AV;03EhQw$tG})cQtWE z$O;4W`(BzAh2t%qxy*Gr%Rn!Z3g^X=DMswbS$3S1)?HIj>0GYL^`mjck=w7Y2cz*< z#^V;(^UwCtw!;+;_?xpfMe$^7#JJRJ$NPWg9IYLCfu9IYp*aToy*ZD=?gnYA?NupV zuJ?sR`3tgE#aF!-7L408K*|vOGRph~d4%oQepMUlnaF4IotZt<%r&wqn;57@WgAqP zy8U?LKhTU5HVGa|4|=xe^frxJ3OfbU{wDY?$AgwJ*@Br4%Sgw%9EmRGeCWd=r#si? zZC*xe7{MK}k(J_YUR1gyQD0P6{+5#9J`aFzC!K(`&#_+zZJ9hI9UL>SWbAg z;Wkv4Ls=Q5&D&FfRsE}+ZXzW7FU{UaG2xoBdYF)iaxSw^0h5>tR9Egziotu^Mw*mg z>E_#MCz{;tEf*!XVP0OjhN{BNC-EkT@<+kP9c*i#-*gwCt({)%IcYk)HR1Zh_a$af z<$HIw8Bu1cd_F@oW+A|Afz{n>{;$Y5sn0y?Ev=*(+{Rob^I7(9{v}OE%~Op*?tl^D zkdl1=vtgqJTivczw%)^l0fMNg(bPhiQ2>*B0Tb;BYOv zR;XW#`zrx~{@;jztzkMX8}r-bw<(l~rDGWm1!k;;jdz7FyVIPb1sT=D^c1V+%zooj z=D423&`K=&RdzVZ)ASkW8ZJ8U1*(T-#~QDI^MkZR4001MO{4RyeNhozqqNig-=m%? zgU>^?Lh88;zkEOe>5Sr&!vjFynxbyJO*`2^0yts_VYR>CI}-w5xXsj!wQvos7t}!4 zrp_j`_`==y6H2BDB2C$jt)5aSr++dE_ZPW5=)NduuP^&15&YrK?A{+4w?U7H9A@dW zjSnuGTQiMj8@T7FWTf5;c5I5h<&4-H;~8rBRu39@=<=t_Mf8|UE6BSxqX=c#acuv> z>T861wuxuppR;=Q$*f^ANKWS2uje(eZ&kW_X15prY`)Xi2msuf%Mw)EhGkut-LVe@ z6f9?T7AamNedfv3dVXvk)~$3)1%V_8*;QGDwX6ChDwjw}*8t?dIj5hd-AYD(dl4 zrf`36X1o{bLo;GVp_@;pkmXAKh7jsk+cm>ZZ+Zfs+0_KV=>y58cwDmrJr%%nWL_}D zX7qq({R^Rg{JS{$D|eJoaE=hqV}X_)nsaX)G~nc=5j`gpk{#ZF!{NeQ3@C5T-Asc} z{qlNbV5-?n{pPE9gs;>gJtjQn@v!tq3_fM0!lKP8*;G1Rhh^l?+SDH$B@&yc)9AnY zeoQxJ5EOG19S52;`68A$A-*v`fhS~SRl_U%Jlj0~&3eXq2gT0rZ8RrK0T#OdqP;H| zHc(pLixd<#npYhf^oHLUhlK?fPDpY@?!cRQcMrJx=-XB%=;chonIvAetw0C-%w!>u zzHz%tB%#PisbgE&!Q#6(!wbF?f;j#4)+*}_m^J3+Ss;!hRc6VC0r0cF6o=Ey(`DaE z(}dPKlD++}HYLiMTqk+&i+iDME}55+2HcFE7wcPeID^PmNI0%h(3|Ailfr9?bnh|u z^-b2Z!o=;2$s7{Ve}$3bbJ0{<>r`4|ga*;agfCeHIFp_SOmpF1wj32>bTr!60kmiIi|k{ZOdLd!Oh#d-@n4JvY<4jz^R4a|}x;v#9bIeou)@cl>)C48Ptf zr<~L?o5^UeMOhvHby-yQHw9bFxP^GlrdyTSopB2T!QQW<0N~uc?}?{6sdHyX0e|%y zqNe4Y5;XWU`9`-120lu%{_(Xn!Sm@9AA)Q#IYIY!xp`0o5h?Me4%O!oiCMX=So*Nn z&A)n?ZbVg4Zqu;i=6~h@lj3rI#XWICVj=_yf{VJ&jR5+4(gKMof^RxjLLXg9Czea^ z@ve=s`VJnR36CwO3fZKwS{XE(~Y06<);pDDqK-G&ZyM>0Q^HgZ>{z`(1VO z%yj>N<9`&LWmuDM8;92$8!@_Jbi?QnVT|q+X-9X52&kjG8xco`h=72osB{U^2#PpD zPy_@-M8*AI-fz$Ie7}$9y07E+J5LE>=(0SUUv9sf`PIACKmXLiL$%6Th9z&KskVTc z2aNYLQu&w3%P^Z%j)ZWZ>2rl`siorroun^yP54j`7*nEdfQU{>;HV&z?4Qqjr&QfZ z`=Wi1#%ZL|Cb$S{pS-7_rjEXPl@CKepjFHIapy2uNKM&sCFn z8<4VPjek5(j&S+PtnohLiV6*2KM{ed`?+kLTsg=7V{tKLw*2j+eI5`|`#F?nNm@cO zoJ)~r&)SmP?Yuo1xnD38-Ns3?*nXJ5HzjsM1@B>~<8d#Iy55JifmZvwFCl`TY42zZ zeS*2}-)$5@xx*jr6-8=r%gVxw1FEmxQtUwv=>B*tANp`j_+;Xc?lAh=p_#Sf*BrqZ z8^fzebK9_WCs(;>jQOEdgYdDeoAt2%S+M_SHW?C}K~VF3c=`Mfds<0{{UZAdCRVq{H)y=WzV0Cbi+n7R zQhfOE;>XKeo5(Jq2zwfw?}4R2w+4NYfS(qYyB50}in{Uc3t?0sU`)?y*e0@uDX!I^ z1~k!xm%AG!aTM~N+G}F4Njzy&(o9d%%*%J$bW%>39xEq<3y*Ez_9=e%)PN-P##{K^ z#K*eohQ8~<*9skO!{p1B%$gKsk+kG6@g~~0$C9%F>4i^5{kbfJ)GESD1Vt0?Y>Cc| z2F}1ZDZfrkK6A7iodRygv#VS^Spvmi*rK%H`FvONwaSH6SVQQpaW7T0<)v8I!{TI=OV z)wctx8lRntt%%w}E}SZ*k?iV&;V@9K`SDi5-<|%8?j*XKZ4ATg6u#2WNbj?Afv{f! zgDU_{``&hJ>F+jTs@)@$@RSqmG7qc2{K^-NP>X$J|NpM9->Dng5O_+xnJT)6|Bv<2)s`s0wQs%Wc-`R)Y-3#b~jXo+f zbJHm*5jDmoOyujihJm(O1m!9}qCC{v>$q92-g<>^OB&IP_nhC3EPbR_8e6Uz;0n9M zs5;PT&?Mnv2(7W?;PpaQFAUpg46F%=xZjbK*&do#Pl0V-vJUFQ+Q`UG!edQ+8c|7_ z=g*c-)KHsz_h>-LzhWM{28P$p-g}RUtdWTeGU1?=n988l{+$nx_8Oto!=o{o&=tKJDMS?`FfsFcZ*h_2ta3@$!(FjgbObn z%kukx7!t^&Lj)p7K%IW37?$ckzi;w&J{_)Oz_~*BNdVz~TBpSW@oMybKiJKA{>_Xe zHE@{<1JWVUo`Ym4{3pgej_|#S!#K=a`u-Uj--h>wGxVgHtrwq6h%=x2-c#LPKMS<@ z;~|`E+{on#wdf}*0icLA1r-8#?e<4&@)|1%WJl_^^bM5l=kz!(>aK?J;DB=du;FTD zFLv9AAx^n|fCCQE&d8NSf?{z%Cc;K)MG%e3mXpxK-tZAs9`~ zY^AtLS(wKf2u*-_5m=*LADX^`m=I=C`_2g8HKOP=$qqYRbB>)PFcJg7k-!KHvP+eZ z)CW)lKyYL*jwJnrG?o1dh`=DQCAe?$U#5QZXuHkGkawuKtF8>f&(|QEeIUtuuyZa7 zw38cX(l2OhwEDhIS0O_7K^b}-!K5<)Mi3wdI1m!Y2-_fNa3ff7^ZI}zRcBF!cpyIk zLL?o3L-VC3kka72KfcgeeE_rIj;>+=3e^m_6iLJYZC}%g2nL`>UPb|rbV(AAiSzSqNZ6<%^cZJB(kN4L!Lua2w&6P3SAuX<*Y6EiM-f zkQxI9;JIFee3ldSIj%`gfUm#0{Uk-otv6(sU#}H$c#j5fetPQyL6N&$nF<h=1=2yGA?}y6)G6_QEAUUlZ(pu z?j$Jtvkh({Mb~ zd8m+aAB?(f|C;v5Baf#}@9RQ2&0%!*opq5VQ8fuvyy__~dBWK&yFPOkHYx*&`dMI6 zw^|&5|7;ei5Ivi*bZgnqVcyR$bEGzbSjk{S4;qFSHGptB=}2a+1kuaw?kTqhuT{!}v=;nGEvZWsPJ^MK#rL z{RlplhqCHDom`;qna55`k8fLnKv&m@Zz$B#WTj&JS2-hZ>^=WkX{!g?jlx{{sPjgc zFD=9%po7h_9_v_kb-+oQ0A3}I)%COBOB@tl5l2W=Ws%&cja-2Rx3jiKZ2i_CWi+c zPMhEXkwm<~%>?2m5nNw}HxOe`!65k}(d|Rx`$D%L-1$w#kcPR?l`@FC131}OzGEW? z0yZ+?m8c+WRtCfx1I&Q9K#5#D-2HZGHW;?&N0R|= z7C4WK3^7APmbR&RFr1~G#e4!M9W__n$)%eJRWP=i?<{#)w}H%hHpn3^aEYqeKn9`9 zoHYOmpvxLDhB(x>5-B5|Cjn5b%%Zz{o-!4(BhUW9PC-;efRQVdWsDt(q*Y4%kf-Oa z9-XWZLj=7Kpa`>=Y-jnYEwDRW>Wft7%rLK>DAkRapcjCHamY~K3Mdg0Ih(Xf1R%8m zd;nZoKLAFKS3BKDpAR@JBYeAYM?f?YoEI~zoldt}4Tu6Hf5Jg}09pO$Sj+%`h*Q$8 z9HXtCg?zvt!(aX5E6Cn=;DcRP;pUQMDL1CwwJ6kKHLNwLZl?LnGnVK)PgE4|?H_d7 z$Pg9^H!@3@FS32ACgDr~cEsvRShNF~&dnlSS}y;^Hyb{bVW92(^T@R>Q?lnoC36}x ztO}bS91RB3q0{~lLNxqM1i8q)Jhd*EWX){t2U#&hnk0)vIDx=b;lQgTe$t$gBtWqN z<~^WDXUt{!Mbw^e-Du6IL80tO@Bu7}Cd3-&8Qo6o-prN`%V%Q5^h2M`>O!Ezc$a^Z z4g}RV_F=%mHxXJi!M%70CIqS&vVjb3-so8ggZ|&Sj6r}P7Yx!v1_Lw+zi|LOmW}vK zw^d`Yn%cmtecOoyZ~8hw72+;uKZQ|vre!MWu?OZ|gDLTT=m$zhaV<7^wd4zow^<`{wU#tqa#Ze*{6DG=bu~x@G8$`Ta7$WY-b!?X z4EyeV|Gs#ufu=W{YgGlV(sxXx-WKEB=pT46Y?-4Izs0dRPE1I)AnNPta48aqz`6_| zUjoox`WDU=@;;0`z=H)Y52IKH6T<}k8F=IAOMT0%>lCl8CLsq z*>+ck*_l@#v~KL8$DH&0bwg`3ecXW2TwKEDvLJeZ)-tLIyb9R{GQ^bt_(LSam?1%$ z=ex9b?W8lEPM>Mj>Opf{;-x+3j9GOPKlXOCjoFfYZauvD$wcn^-FG(el&XnYyphO2 zc~BH(C7WpgyI#nmW{ z<4_*636NdG8gzC@qfV75=Wy_-`gh8+nY*uAINoH`sipWzyAe6POjjkACX-EK2}O0M z!yqbLzd5A^<#9gQ=#&~p!?p0}X$U(g&^NKXxuvwz-4y^C2VLKCWs__bl7@%^AW>LA zdrN$4A>YFX!Gb6UlG&pqShkPSR=FMKW!t=+90)BU0KwoCQehVZAakx<_A`(N1Q&iz zM8LQ|ELMfg3}NQe21h)wP)?>_Vo4YhcyI9zy!#_C>F&i5A8u+2$apfu zO)ZPT*zgzkFl&WlY>-HwMsy^pPSngY{c6+~eI!dCG{{S>3{|tn%_G=Dn34*(qok~U9(9fdMgi~cwTS`kAbN5FM7?WcZGRSabR2r^|2{(L0H2u$1$ zr`<)<*37%%8WXRKCtek0XlIaM?Pmm?S{cSiNFCwClTkv7G($B^p7hl6IPhhjQW?w1 zPGIT5v0P#ojK?Bz^(?U)Fh86Ob)L388VW;0{L$>rN77(Iia!~49j$HI&XP_KwM5hX z0f9jBwlO{4v1i^-a9j!3?U(kAxKr?H10Qx?c3WNNfW@zj*|LUFHZvEMR#+r6cvJE%jw$D0mhmm_oxM zV#yLp3x(0rH-xKxNmTSLRGzTJ!vQR4>hVqq=V}xO5ukv>T~+lo4h0KQF2{5d6Sa-? zb2O7s2td|?MX_7U>86wi5U&vdy+nQ4^j`}>gCHdBkoKDibAU5BHhVM(NQC;%LIeA+ zrE7Ux9eLi`VY$=Ga#Fx9z!-ghPJnYuHdkJ79!qmyOO{)JM&n5Bq`_Fd^LmLeO_BkZ zzz^Mt4Y`_jgWDMW@PDyG=M>xdNnaW9FxLm zvY*Pq@dPx^RJK;E+T_Y{*Z?YdA}hHmE1Cyr54}?f6rwb`yNC=4E`>P%_e%|xdgBBk z5)QgzI|%9(5T=30Q%{84Phq6ybA3|_cq>5r#u|Vpqb0tQU={$Rg*TW4C_e#C3($VG z5WB>q?6eo~d((@)7gO`LRQXyXgRE_-xlEKvJOO%Wt5|7_7C9h_<&T)`s+rXDQQ8%# zt0ecOL6lH8lh;P_jd&D>2_F=n0!4$;T`zBWUY6KW*~QfFVXXFm(sWrFhjxI=PHI7Q zsne|Y9bs@keYC)WPwE($32Y|nk)lTHH)w$jw>(c7l z_>-+nv$HX|S+(8T?psstPO)z*-ve4vVbKsEe%|!oXQAWzkd7fxsx3((1PD~U(a#vK z8V|H0iR`1rAxEHfEG;4h_?ei%&n_;L2Zr7Q1M`65Y*#n7F0FL=s$>h8QX<`wnB>!N z*^CbMhaJ+uB-K#h0twZf2ZWP=!Wf(^wvOEb*q4Xu!ALsr0faD5298jwwjf~=v-D5Y zyMp5R1g51hCdYK|ynHA(1$Q~ifoa-hu4Cc8w`9V{+4umU>&y^)k~R$hWN!?((F~36 zz3GHy4+QiS3^b&lv0HANiV}diH=CGe*}n>Nw7CL_tf;LFkoX%;<85}qM7a{x@~b3L z)vn#~0EVYMLy!yvqAMCOK*$k~f;NBw2NEO$x>PD~H~=jU)V^Z(G2X!PGCfTHeAS+R zqa&l!R@q~rx8Vp*kOvf?AWTPw$ww{p{ed_P2uiy2^R^=AUwlkMq_!iu2!cY1*wF}} z96!eoFOz|7WVNh7nMrCTghGQn6%}&(EYj+USPViEqqU2_+BDtKDO;V z*%XC-N%@vZ+BMc=6ooJi5I!DNOU;5{eC_N6z-CCoCIRvZKr8m^65&jnbt3W?Re;BJ z>>L&RUDRMSu~c~0aT%CoZ!P?<7S)48IphN-99f=|WV?x|7g#V=9^f*ZR(KP5WfUbu z0w69)eEmh-i_Cqb$SXfl1As11AU=RCEnvKa+5$jh(H&qXWBUeXLxl1YhS6wfVu#JX z6~JZ^A4F=1J!W$k!Uy57ooJs2K+bu8;Ip|#4lox_VcELi-AY-SryGOW0_EZYsL@bt z#lo#=*_L~M{HSq&s-HYbWFQoPOt3&SVEpMV09C~bjlY{|EdbQmdspQZe_2v^<8cmk z9K5gLK}0|xJpsT#P_FgueS8XM<_8ibfs>_5m*YPFrOS#Nu1h8Ye!w|6wnkaOLiy>kbEI7BdBMNCQ$j;(vkDSETuHd7+Sih1gZ-l9RUF6gJ2Ps^d|HNU`r8E zajA*{szu%`C|KZx|HZ->EvXuKPl z6#vB-WKoztktEn7)(52GlKRO~TlY#%_MD4kMa22l5J^TDK2 zuXi{7_SUZ-(RzDgai((mI$UL5Sop#l{b9lP#yWErX@t{;CRvopuv{z`vQ8IKm&~hC z%j+f;7e|P#adgPgMKl?-tXmo+NAOnk8IGLCQ z^~d)aJG0jqA`|Ea#Fmdfr1H}h zPwitl-*OAmA`*4>t->8rkGQWf@{(DDFbqM-x8Ly99E>j+XdWJ{QuQSd0VVmrnQu;2 zX1n}Lb2(2x9N%8GEHGI^e*Z!{z0(~mZb5W@CG7O-^Piu=gjZ%?)Cm;{Ymqr?(N!9O zX0uUd9kS;%km?$SYEdW+Z8bmOH+h$H=9pt?_R2GNyipy~{g3KeU(`P{uU@VD=#2aL z=%Zaa6E<0@^l%-y<7MUOrD*-c`TO`J%*cfD_OzK_r6hK@tsv1476 zyJUL#a-JW$RmYso)wdFMD%+R)7`^=hM&F-Zv3M}RmwRl=#k1c#5K--Shl>3(kpG<7uRV16RLR4 zoi}56^G@PQEFJpp1-0P0K8ZIGLeI>v(rz)Bf`H>I4bZa>lIvA;3YRP^B<$O830ce% z4w8BEExLum{+|sC=j@(u@+}CqmdL4Q6tQI2ncB}q_xWAxx`wPXwC1|zVDojM-YlQP zlcRfYp;kg1Kvn|`sRXRHyIxUdaa8H@nMsk)WLdN8*&TNKdzLNr{<-_7gcq?aLH0dL zF!I9nl_S^TbY>Z^wUuM{@q8ik2B*~%|7;D&(QZ@Vb@I~#+=nF=yawZ`{sP5+ec zIoE}L{gdpVB;(xXS@`yT%+JRZj_->RmJ6f39O8aOkE;ihjX5^`NR47aec30QiyvB_ z6>weo`F&+co%OMB6?Ms+Pj`{-!>w3{Lr=qdBO1$Dc8993ei=yocjqi&FOB7=-Ck4b zBaK2*k@h)S2d%*scQk-Q_|6V!LsSLP2>HsRA-F)+kro{ldxy4$dKNk_h4z+cO$NW* z7fd=bAx)Rfzi1AlV<7-3~3(S2%VBEQ7+BvxZJ@G4+b_Ce)<<{)mg!U4taiOx;xL)} z`d8gtPvgJ$-Z-gZg0KFL?gf~&u`t!;qPYbHbz=CKEc0T2($Ejb z{5o(SX8d{8V+cW)o>mZl=;Ncu;XO5{r^%H=pU>vX^d$#xG^h2!&PQ~DIk1^4>{XTD z=0I_|6Oz4A!hCbQQP6ams-aLP0czU1l9jRB-1dikx|Lyj?_mhiQ-ZT+Fv0lIvp*i+ z9)+JOJbctJbL-6>p3?DbhtoirIX0m4jndzMF7_W&3#hQfgQdB={DbayCfYmQ>rM;0 zK~9J3kCyxXQgj!|6_JS2D zYLE4tR&C!i|G0FerQ|A)IFS`Vg{Ozmqv>|s3H03C*r9dQ@^zhcYeAKf%^#+rZrQwl zhFsH_=cBi>=xWm3auhRQEDy@!3>*C1EWZksgeu8>5a^CfPPzAC=J$?pc9EV>)r<|J zPg7iwwS;-T##q~Hm1#+0we{j2g!WbCXLE3u!_vM7i#8wH>aT$#R4Q7F+6xA#nvtf$yu{6>?$(e&<-&A}<-bPk+w;n6Ju^%g-?Uef^`8j$_ zW!E)#*9)fhoA@vSmN6<>QN|(D?xs5u(#^h3bA2fuSNVF$rFM zH$ODmrxN`gLXV)I5Y?ZPNXyw9SI?df#jww5<#}i&UJrO9=#r6=AJ!vOK5Zf_)?p}c zUl64ud}91~Wp$=)v#7;`q0o(i(K@R@Q{g2@jMENRnbhC-gw04QQOy|iSgHSY?@6)g zw>J(ht4;b;7%Pr#Pnp}ljS0eDfe)IAmlf&3*WA|16HdZ%x5Mu-9qy^91%S~bU>^TJ zvvyYmXDEv0*SPp&bRt&wmWi-M9T8ZX#`jxpMCznY`{7jQ&dagK>nRC`;nxi~Eqy(O zXun&P|A4o^BGEucM&n$|m9dtd=V#Mc%K98#5y3!D1%nbC0o8sk6udwi7MzsV8ET~0 z{q42UFxoTs@$y6d!%Y~K0h~4YIKYK0w361pg7LJFYU2gwgv-YfO%TviBkJJ{q&>sk@ zJtd7aPH8MLFq`M0RHBc+fYD!KUX&RDgF-e3gjydG?-zH2tFogtL3 zNlEpd)c^$Fg1ge^2xjPi(}kd`BEJk>^pAzz{wk2SNc9x)o4zQmC{IbgS-?L^zDQ@Q zuxh`~JEiMbw*F55|*fv4aRPq>q*>pcvGWS%6+x|Q1YusV~Dyq;6;+(&6j^a zHd zdcXYCK-H3$%7l#F?V&1RTHDI~W?jQY@Wha~0aF4%=cT%2-&jpPf!|DkT?948$QMw} z_GC+2AVVLAHOYzE-X9e|t`*QtyuBCxsibqUt{@@FNWfW8u!G6**Y6%v$z)&aWy-15 zMLiMxPXew|CQR#J29|Pbu891Hf3xRu&~&@Q!LgrS>8Qbe+8@?n^NfMxcZ_2BQTC5( z-vU||4HzF?uF8nNTUAf`ms0-LH#p8%zdei2(Tq1$_%c8AwxqQ&P0rHIMJW3n_1L$} zGdUj*u#pAP%r@KeVwVs7eiT-0yTl$Y>dXGTBj+nYlY=>3AW%x4_nqxKxuJRepq=_$ zb@qlo64r&DeiODf45q<^p}hQ#X6eGh=oJ+U?i2gm12n zqX5t;!rS_o@3yxKT^=@|ueVgw$hrNf7(7@_4HZ)8?3}pKt@f~OIpOHa>k$gWFSgLg zCn1}=prWJ5PDZDj*SaM4n>XmozbtUWzPwg**1OF-82$I+U80=hYLctRQfp9$@3-ie zvt}OdcaK)`ok|$_z6tI=%cja7(684W)e(|JWh6HWY7`j=n7kHZoGq)_Z$K&gOu*hF z{WwH|1v8!*G49zvH~HA+FZJC0JL57Blo(g!c;N5-!fTD1h=OPbi&uWAJkYpDH>kY6 z`+1}-`irT*l~&rhkoq>6`ergv#lUh;Svz$3;8c2J3 z@XcHE!_wWda7PmS?!w-E^R1TClbV-;am+Flx70yCX2 zKV+7r`iib5HmN;N|8ZX_e^5nozQ_*SYXQrk-#Zvf6c*FUoxY}jK zb1Iw6#?rm1{B@QOYVz>)LM1m+1y&dD+f)Lpg(CNJ6Roi&X*EAdy)WlWX2jCRt#zs| zOShZ@bf{W-fsP6BT0HjZ1cN}*F?XV?=uZB?hszqAe^X|3RnF?wN^IwE1itF;%X?p` z3RV?mCR9oOyam8Er49{|I$qPTLGeZ8_9oJsF*U#d<9DTKCx$~tn+bF>*y$)8vL&r_ zp%(&q9RA`GGb8Nv{>9&iS5)ua>sQrxYI^*%B_}Y0tD6JItJeR0MR*u2!j8!koyUb6 zssL9@1d**JDh8;4bkX^~xw#T_R;d+RzNMt71}2HIu9c#&*}Da#XFk=TW@noZQ?z|j z#o3z1`hsVt8e-=NWff&LK&C(N;oVv2mO5t8ans-h%aOo^?((BwUu4|Rf9@8cCehXW z7%_CelLLFNzD?jo&_ZULF-ifY-_knSkf9lwslAw{>aZax68_G?*ss(0BT!H&r7~x%+YWJESb5gXs2u#&@Ax+gx|1zV8PG&oT_kJa6 znzLWl2q({LUOfLMzK+$usZJB~W zl(gZn`4ZXyZ1T7Cw9MRh8$eWVqv;RqZ85D$zkzrwEg%h>(x3ZDa)zpS!;b+w5s zR|NMW&*4V8G?ghPv2OlC^_S`(8fr=!f3&BKw6ka?@o{*XWZaK`?&hupILZ*ek{U)H z{8&`spVcM{d5ul1S96sfuxr_ov=UIf_w*r=FrM5#5ACeeY@g&@AT+c-7k`MPy-+jv z)arj7%i@1BglnZeQD;%cV8iD`kIQpG6nc?&q1bFIx~;-=P45b9A9K?g)b_Jv_ z-KA+#rDRcldnz+$s%3tLA}mAGJv?)Er^wc$>UiWse?35mlFvhw|7AY+>Fgb6LqMB$sUp8-5ZuKe8Hpc(y^YDB2w;I@5XrHN-JY^b= zT~j{p;{z$sDvyIW$X9{s$-d)sh^%DVh#Gbu1MtI|i01wR_WSQF=|COkzP&1@FSzr- zwK=B-3))u`I2KX#9n9$#ddvulezs_ar*7K#OM8VpMvHVw{(^g!*Gifh%EgxQRLXO{ zJUaqDP?q8?Rax@0d(J4NB&Y)Aoc+QPz8#I_RGCw%Y4jN)YG2gw`Pejnrvv! z^e3XEhhb5O)F2PrmPZZ~(QgOSUh@#Fo^8FKKTq}*%_giQJEavbve7uG7F%o42#+K? zu4LO9W_Nx}c1AclwI`E9z_%F}f|1v!*{!=zWnNy*) z(|=1Qor7^rNr*tzkM$G?j({L%>n?=l<9opsg^GgDY#i(u3Xc{`LtKs~Y>ti>`NfvL zKv(gd>-fpVYmZXQPh2V=t=eaIwiwLGhECT6D1Dx<2*!dM%BAtYQ^GCawcIFa>eNU! zRFna{GX$e+nfio07(9L>e7tbSEi>XA7O4V{!r4B&O+e&iJ+%g~IbMOdsx~;*H@JE> zl%rF5Sll??Zt(AHaA>#*?6`8!ZbpXyxzpUls@%le+$3JPNxpUC78QaXr&=MBtq|^( z=bKnscPvFZSypLFjy73d*j+JdOFm~yxnxU532H40wMHagVM&(laaUl0UZsWN4!5o> zyDO}3U1jmW*?L%`ll53U)JNU*cic74;H;#0douJ^4V0s-#5XFj!3kZw~H4Wg4mTwh;;G(a$1BC zO}0$)wqk=u=Xl5V?8dzEzP-L{Rkmxn0=a#-8`tA)W#P)D;*(_NlkDP?66BM5=L;n< zCH|Tn)TYTN^Oa9lgHP7FPtKuFZrhh@WdO%(M9~yCZtT|rv#+9Fz`_(a77O1Zjjy6g z@dbB$xk+Cu+I$NsWNzXHC()H!+O-exQ@mIFyl3|wQT*Cz{X2NRwF-ah6!v!$g?CHCZ&~;U+xd3~`S(_R>%QaP+vDF; z_3ddCENu2$?;u%T+Rat=pYY3%I4w!#Yi3oDegzf?rcF{U@0z$pk3OaFNeu{Jcll%L$cYS%TY36 z1!&U?F;odQQ3*E0em}MS{v##nr$+FPl3>GrhygL_tR(4gRq)@O?|-U-Pc?#V&_DpO z6loV<c4QJiV2+_<2#Z*=JY0ELJ zpOQtT0@WozblV}ib`ae!r^eq;b&eu*4IpN8Kh1U{EXN|u%^}vmB5ZaejE*AoNJ&Ob zU;ruL&D%(UYp=t@i5A2_g7U!!+Ot`uB(s$ObwrfsjkCqGB+I6F0^o4h40eNbcA%GX zupH!Zl)QPC9C-I|3wHC6Hu%6SDB%0q0VVLDEsDVQ{iN!BN6!S?lo8pbj=+saHN<2JZ7P)NR|xI*qqLjR`TZg3ze2JepVMkG z*kO*@u7?I|9x}sISaOeF0AWG!Lmt-O`KiZjnxWfg$7SXzJj%C<{yPzVa3Y->Ch{&! z{O*b3;}em`CxN|T^4>6!;FD_a6REKi?A@3^QUzW)H5{AzQ4&RQj)0Zi@Hc={mO6Ex zrZg$S+e<&`biiO{Owx;{Ev&I!V=1B00LNm0@mPfEb%+rOVs$gpGC0zb_ov-|e@%bI z4wU}XAw@clMLOTO;6M0zLnP{*-kB%enTPVh1aF|3XyClpN+Ug86C5jJr`KH;&nOZ;^MRf^Qrj1|0{& zgO0D?-KJ0&9*0)&-raM7)v^AO8N1c^I;@`ekIcLO9y|>r5=H~c`U9tWXatl4_y!Ze zbbjDe8b`J89Z{>UsN*%AjGec)udu$|9LZyw3G8Ay;TnrrwsSC6K6aW4|2palATbh? zY%Ar{H86Ub5`}*tU@(5@cyf}Z6CW$w?s<3Yjb&>KqC<)x!UP9Q)But zO6o)BS=3(9kr>^_=eLelrXSu6t}>%U|B909Vx4KU#1envQ&z6ac}x`iwu+-(+4ks< z18S$NhRF<%t9iezER)-wC^K~D`MCP-33n6LupmNA>EL~jkZu9Q_gCP0Uc`SeTJ`h& zwI}WmE84C5Q<%kEo^2i@OCH*`wLR<&`lt5m@PqTq$@SanzmFGh%vr$p<>W?Qn@PCv zI=qTI|F-pXCeGoN+vv|N$1~%&R|@j8mu3#|v^GSxb{3Dk>OqbN(RW!S(efx*$io5? z$w{=djFxI#_CMy8<;odpP2|cA3NwXXA*@Vf;&m9a`2rz~#w%Gr`ptkQA(Q4AOu8Nx znOs6l);iMVX@z>02_9C)N>ERVPzA(dNh2_HwZ8O50((Q5dx8CO$)7%GDY*JezW%+) zf4bKz#pdIfit(ic^VCeig()CHg@3Z+@OLszP?oXFQBra=z)J@a!VY zzWvvuUE}s+s)y_yrOa1a1WImYGb=OvN_h zx>O@(mQTHgsl0x-4d(4;FE3JdR0neZ}_d#z{YRgH@vlr^U5mN z@Af;!GEliX5)K(!Hk$-zuR|v>->G`m%gv&rs{IXbV`d=tEaJQVU(i%RrUW#=+TiIM z3V#l7vjWyE#4yCDNRNMHQNWDvZfLRI)d?mcD^K6f(*^4rFMrP0a=mkk{aTqyAl^2= z{wsP)74cT`2eme~+>o-v`!`Fqi=Cph7OOIk;>1l9|7*N(bm$ri;-yU7?^B>X9_ zm*O<5oMhfp$RKqfQNod>Wfsr0%@-moidSc1O;ORQPU{nNk&#U`wn(5^n?_{t9hWK= zvDF55r3oKDFICJU6!HuR84SgiFQ&u8q)rfja$ z1P@@j3;sQF&`ar_JqBuDszrv@6zIK@)6J;0ffIZ%3_+v00Og4!+S=uz#b4!3s`d$aT&I{`EO((>%H?#)nL zU+Ep=W=x(7Ti#k1c=V<$hi}y?Z%5%NY2lV}IM0b~>f(}gDE)969|-=+_NEN0eMeNs zR_QCZr)rEFhg_>=rHV03fMhBv(IS;9&g|{FJJOG%rx+)XvNqc#<}7oO&Z63!9KsrH zR9>Nb>(hHWmM;)HagyPM{Dz@ybCS~qCgEInIcm#?so%;~uvh+<_EQtDN+Vxwg8?NA zR9fBIYoMv5F*E(z|Hyt%Ip1yxAlaMXuqSt&d#e6ce|W;{YzyC0S(e)n$PkdP&F-J- z@*Ng$(SH<718%d^HIZjnJB%BGSAxu;1IJ0U$>FJ}_jyX>yp$(A9Y0QW=wKE80%{ zXa9;WT_A@pO+s}UKrhAThhdg5;}-91dxUH@AIF0*6i$=R=+2{w3XpX@&YE`DTKO6| zB*(GmgGJu8CrQPva?$snEg^#qUkcrFJ66_{`jI>|?6;X?ILIs~9rg~i>o|~1O2PU# zdoOL+e|k|JbgdAx_a3I=@JlC$Fyyk|WT|FrRr~s_S-TpCq>({FfpEhRC&Ic_Lx{6z zoS%~1Q7p7>tzyEIvs(LvpGP*`I7+xRfU4$$zyaoW!u!LGR@3`f>gsbQ+|tEY1*z=Z z*+Xkl&5z5YHB{3!W_0;PZFDk$+_bN;7UI|_b!8fzLdH& zV74H4s$}cuQI%RjW{HJm>usf9jZ?|PkZX$Z(5{RU*U`7pWkwQ*cPwm|#z*oVIk@<_ zj+Wn`nU38txi-Y!5^_@RB;Pb4l_)4U0}DeBPPm42RV?wTE7UmtuJj3s6A%(*r_z_6 zA7+n_8{kUsdQCeuod3i_M?D4yV1NN+OM3s= zKRcTD&nhTk+;~#Xb2Mn6Ps?uq@@RpS_Eqx(gVC7nhfmcFJl#GbG;CllPhj}of{^m> zqKErmLsgi$>_KFZ`cb_^=aa*_&4a_63nw=RD%c;M?P`#@o!TkRF207vw<+nhd$Dax z)Li^&6&u6f(KpM6E+)J0akwEIbM10sLf<1!-&?+RJAM30?tDw=LE2CY<7rA%r>s>3>CKp~IU&ra4hmB}?I?vR$(+tv?$@Sl zPAiYtH|Pu4c$=wjG?ie!4zzWw5Vp1cFrk71dEM;vw&Qqb3Dq)WIso(ZTp!CtK#BoP z`AR+h!xM5Dd_1`Ean|%dt+89Zc;AocKMII8o!8s%Ea-k>00%YMItUyEA86TwbHmqa{MgwrH8VfyX>nNTb-rO zH>mBzhB5JD@#MdpO9}F{>q_!Q6?)UHKxKsMHxC2I9jmr@wO^O_c7orA*1fI?o~9BW zNP=@T{+^)w0=u(wSNhv80~k!fJ&eF_K>^*%EgJ-E1AQZFKzZwJKzlYfmP0=&+v`rw z=Yu%V1UrxVw8NGcQv`7D0<-4-rqc+<(Fm&GKP>5iE{}=xYIu@9Om|3P>i(Kjssed3 zJa6^I?|GQ>^+#p)*ydTcVOyEjnHp+inULZ*6;muEk+?k;E1LLseAY9XFSe2?eijYo zfhbTX+R3ibT}}I%2bLvUAa+)hFo=|-%@^ZleJc5x*g1*Gw+z|q`W}h&9*K%c+G+~< z>K()Cie*+v6O}A5KjyqPZjpYgDoUiaHv z(*QgTYsx&=p?g3R-ygBn=3ZAp(b9%Enzd#}g%#)4CgLU6D|(x^Y{E!eY5U)ZQAr@X zWIsOg>!(PYp=g`Lo4T1XSR*-6u*^8x$ncE}b*8FWCJ1S~flZ-)IcCr^W?)3y(|?VI zK2cCfTRtyQens$UT&CUq93|Y)trBK?dly=E#NCg~L}(d9Gp2TW!6vLicZ!id#6hY5 z4b$ymYot%Z2QiKfoB@=|2-WSE$osvJN6*Ntd9T>wv zQx*a|K3g~1MfvJ|+=Lta;z1%1VP&OS$~k%D-jRuapsQDzy9a36ouF5JG3e1sM;6p> zSINF2tc|_2xbEA=g)m?tU=6uaK@WUDfUnsAuZ4Za%9mPS9*goGzHs(D!4h4s+ik_!F z=!O3*uVwX1$ycJ?DBHTlz+q-;J~W% zKw|xxvBl>MyCmbOH2TYKpODYk$2X5Bhjsc5#*S&Tjtty3NKN!JKlW=<+k}Sg5`?hJ zY+C-q2vQWaDBMKf&>f0yse50Y0V0x#XLl{e@YR$+qX!9|D)(E!=h;0Fg%-d*V0QbDc!=d zbP9q93P?%Ai(fx&)nB_p2KeR zrg=fNro@FS*}e1I*Xm?p&IKNf9RRn^3!LBoZ-@J~w>4MhYFS6*=bWR!*J62ZFoZk9 z<|%V8cJ5=5pW3~a7jauyu}?t;8eRa0kVM5!c-B>{T$Bl;wN z-kO;#Q_nNg`EcE(hS$Q=^j!Rg<(@MgS;OCoE`qer*QS`nK~Juu!9MwtvkV&By}`Z< zkjycP$F#`CbOI37YrDeGYYu2qdXH=+@DCeyMcxS*|6rig}Nqj*K zSG+ub;jp{rJ$J_?L0=6b3X*nsJ3UHX>>KUFMLE{^Zmp3u7tKUdtz%kLNG!R(Ct-ioip zsBrL!84N-2_BYP_MzLU8ktXMH@AoC8?>Tk+#>M+Evf+2b8M!1;QT}QvEL>3m1h9eH z@K?042WpH8UCYwycX=nra&it(pAaO{1Y7E$Dw;w~OtR@w3bIi$q*@9bdJ5?#v6Lfa z-m~(kXm}PwpVjcEO^WY0g70xSR3$u$E?duGKK>;uNJ&#bzIoU%IhtuQ>vL@3u;TRD ziVV$NH;Z02fnYZa-t-DlPlq^k;2ART;V7p*;#6g59V*~3v&f)SXL z5h%v^u|&S6PpiFoOMw5efCa`P02QFyDd3Buk$}}d+_Mn#!9+byC|$WzWhJEy=zQ2C zCAPd30oq{jerpYrKNtmQkT3#a5RDYSNTFafgb{$q0%X0v^dLKOAGICYnO#fUjq|WD z3mmKqM`gcp!wP<*9UXNS3(H1R$)@N}p}|NjC2;oxh

lx~c&dbRJSSCD!KAoJL24 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≫RfR{q{7 z_j=}SexafC_=kj7%u}bp0y01Hj3R6iX^J*|p(2{HH2viu0~TqZY1psEg;oBZ(Sznp z1whkfnW^nSfdQqla~}HmXeV;H1lrcEHXp9@SKXWRl1UujTHJqX=RhB^BgsDaRKz4K z80oC{;W!k0KU@Ie>}d25)sAE9?2HY29L;F{b=Pfn{}mFHGHNbOPC^ZEZ`caCl}$7M zt4ul;Pm>DOERlNky>v|`lsGwGrQ)Rc`)XFmT8>`9==nUEH#aBDm5+G#AMO2jq zehJkUP`5^v3LmN5LzqPscFZzaTdQ5@Gwmq4^eDIc1JQiu(f)3z?jSGh28&J1*WV#A zcC_{5h1e`bu2D3`K=Dk!T%yDtU?!wQ$LjmoPV%U(gC09&8B1XaZTKpXdBKrkcV^t7 zHk|KIaiOFT(2kn7Q^@YS%;%>;X>QtbwI(&Ed|qI$^J>YnQ}tDXF@NS3LMLd@F-$9n z^*8iUN$(-E?jLN|l|sT~p3WPm_@X`EX=L3Ua=mYeN=V9nsE-m$>V9U2YD~)BI~AX_ z%VyKeyCn5Usj>9cqzAWr3L;q%PH)R)5g_WS2~S}WFklhrXZ`!O@08hAz)T(D)H9ru zDdG0tn2=yapLCcWZzkwPL>Z<-^Fmkm-AIa*7+A2Q`|f+agK=Tt3VA4V1xwbai5yd| z(ErZ<+cojkaH6nJvZYV5Q9rLHeBxM78mjrC1z+4ec>t-k$qhJBOhL~O*c_74!y`dN zOY}SjazB0!Ze|BfW^;IC5?cFHzQn~}9m~2L|2^g2+AkjV0mO0lgD=0OCxKUT6Yu?} zDQGig_t2TP;lZ;|=%Y*jlMo*6?>MzegKc}HybKJ}4Lv+4wkk)Gu z`uvFcS%SSLI%I~>r-yV7yuYUH$$H{naDuap^GK-F*0gNOjg7b0~i;ZUGZW758oC2BiyJ>_xi}k+p<6#Wy3qSk834_kljs{4rCA9sg*7xmi#TH`mwYG;BA1T~wN!rDR2jzICj9(kK$bCl zKmhY5Nm>hOC$jR&n3JzB7!aU9d6j5~Jg<#%@ldC)E)Y6VCm$>z*`>p4f*gLa6Lgf$ z%_BReLCr!adS@{pO7&XY0zyk^_wwYky4`|9jlUM^CD&(`DF;~HkOJr%rUI^Q7usgy zv&t^TV6=zWd;6tT1GmvQxS%0}a^URY((8(tGUY%kRVe0AMoK>c7O=m|O%`%YJ^dr% zV8-_8#nsfVb@=78SaUKm>C~st5Gr!0qYqOgDlkfO4RT$m^dyyelH$%Amtx7VWF{N| zkMPLml_>SbBnN}RvKr?dQ|)wEB6}d#mX|ed=Freb?KtJ!9bahzQ=y((Woc>8%QLJr zV%K0wqeyRFWs%U=WxW%3uvkoX!^oo20hqrt}d zIo!Vz=mm!Gdiakn6WEQ1D?vO-di5xu`;7IXE+$x{aSHK!5&b)-ZTiyE+;iqQ z9XZK21c+uR=rb{%dQeyu2cP)EGpM}&cq}f(JG)6Q5tf;kb=SX3kqRM;S|O9Y)7!@G z@^eih6Fxq;F9|7Fb#}&|=HR7-cOe(^bh%8= z9hH|w2H6<-XCCYI{8aY&#;m#cq~9BdHARpxm$pkwkt98YXEr-2h0e*Qo-| z)#!=vOJX-R63SRl4W;zC?AV$cH%v&P5&)u4vA{TYuNIa7JRk+Gwa7vMs_k=pmA99jUolzZ0 z3XWsu&(D7_u$n|SifUUt;qSA!l3olLQpm4pRh z4X&rx-&-uJVg^?xNorH*trvsU{gHHhLJO+uKdGE7NGzbWuTv1D$DO8Oh>AUB=sBMk zHxuT>#|De-S{`vVqxso**Pq`plDZ5}$`z3>MEM*xia`CB(X`B|hrHnaFnup-x|%~W zFcax@EujM4H=Hzd4|_vfiL_hnTB}$|3B*^@iAXXg0izOOIIZ`*hj9{GDgVnxt)*@3GQGZi=Bed~Md z(BEogig@XDYjC4}Re2cLCULZ8{Zk)ZGl!@Tqc@nLQ4e~Po37Yp{lXi7F-x&yGQVK5 z1XCA*&C7=6-R~sS2yR3nH}8XY+rR~MVlm*LjT4bw)Z(kU=jtJ4@bGKCJE79|&QY&I zPuJeXNa+-oA7Kv+&ydi|%Vt8qib{F`n;y1cm?tw0Upgj6;>~L7RWH{oA81?V#}B}$ zUif4_ES{cQl&Yv}pZvD!tLnw8u0bwNu*Ikd^?=wbbh{YR=Jr?CFTB=>X*k3nS_FX7 zFhX>Nr2^J_>A*+~!;8ual_#7mfy4J^6O>7h*~LJOxs$?y^E`HkiSU0E1M~&kw=Z^q zYzB>NLR7D}sB(37uOIwh$fi|{b*uUlHiGGBTw)-)pLY-|0BdpW@2U<^<<&F9e6g7Rhb-#U}dt1D55agGK=168I5ptY1<$k_P~<9JvRU!UXc6 zSCyM6mA@^dDn3R*6t%f-l4KlDi^FJ*D0nZu>$U^uDuuvC#9V^;Cvpv&=xTS1)^b1E z`KzniQ=X(k08L6iRJ)nTrwvc+U?KtAwfb87DnT+MDQGT2KGQj);qom;+q^*zx@oa1 z8hU#VfP(&dYb>3uS!J}P>OJO=n$eFTuI<3M+1~KECdw{ z%JGHus`3v-LuY!g7^w9E8?YSWjDRHD^2)GBq-@tq==!^~-f1oLnaZ$Mg~ zFenRMnOHrLg*4!^qh>2Pcsf%EylO5$kb7=TAa)ZZt#yx7DpK3`9m-4fzlT^SPTpE& z%`Ftbg#74!x!t3j7wOL_sFh0>sf-zXdpBQ?Vlw)&0u+K8`O0qAGXne6LtzW-SwjAm$a#!3I zjR!yUbj5`80B6m;yn0(9qF3IdjyDt^#EtvCoh09OX6KDE6sfFMAVW{s;M8lgB2$LdO-Fj6zUL3e(176JPZC|7|vzd#&xT2Qlhft zpw1m&JOyCB3|adzDn7L>o=(-jrn@r5A@b^w4o6K=V9iiKP0){0_#Gs2T)=c*HN2Ug z5EzcWnewNj5z({K4sDwY?FHeGMsAbyPLEW|MgCsd^d(dH!)jullJ0d?0<{POqm}u_ zEwHG)OVfZ$jmS^NRo%;vcii^4&XH={m3dSH%?^pBF{IA+{^T*9o#xOcXO_suT6LLJ z$pzO7bC(V|B9X`F*>K;MW3j=t25eR(bRxk_l}yD1 zo62)GT`wRV$GljjaCeyzFLQH=Vb3fD`3lx#L53?-@=4i31n|82AW;`_UfH20D4VNV zq=;LtQ*g>d+^P%e-9st16pJ?1Yd=)~8=I8EmGo58QlY@&-c^p%K3RE6ur7s7AGm^3 zPylVR#WTtsXf}s(49>Dog&NNC`Sv z9|Vv2gX@L7dasI0_Vub!30u1aeF}5WU=`Zo($8e-snImt;nJ?W_;QoW5C@3B-J49d z+a^4FS`Q1xt1pfeLi>Q&L^ut}K6BCCZl(1$fNh}qTpB8Wn8IeIr}1M@eQl6*T*(Q} zNQYIiX-$^GDEe-=O|HJSY#`t56@(j{GlpnjM?6YM5kGh+f$L?c_5}yl{UNQC7XqC# zS1PQ07*Z+Fq(jTiW!U|CrY0h51PuplT;>X!fLCV$!SK2cs`$E)b zkk2bJm}z-u$TTReoHc(8e)%N{DH4@`uF4YYT{`tD!naNLm|tte8agJjWvi|%Cq149 z=@9@>yTnqQL(lp}U(2JOjvHfq4>RDaYZ_t*pUQBlU@2R$5s|{s2j#rhiocU@AO%|| z*RtkvSWXhQyKw5SQ~-rT)ZHc+v{Ue2hGjIv1J!Qo7nRI^lvx@hx(?rWqnaMX z8s9I66!JxPuMcR~n(H$p>3@5K8N~y$$Z`&e(=tzPn2T_8Jt7Y?ufSRLG#;V;Rv zCc;Id(&dcc5^__LMGTFR*A&AMN&ui5UW^q(*Q|cCPKD0+Jb6hnw2xYJ&tL{|fuAnq=NfDD_Q~YO>Y%H7OlTt});iX|1M~=_&C_K;QVYNh`RH0DeLdjqcIch;Q#(cw{3-|$ zO%cIufFx?7e8h81LAA~VFiHGE(u%SYL0QP_9OQ^PCsergaSA?;l#6>R&F{>TrGMRC zci!tKB=G_L`m)yeH_v*JhS8(FL?8joex+HN1h|e^sa=3Ev>Wy}YG* zO1H-mx}p;j#wytq-cd@X&tC|~GNfYeQfiDqR*u{2s=pIRSkznXVI0@-&qjU%Qx}e9 zIvLOcXK9Yko5itAD#ij*fB+?b7jtc-%F?8P4g>{&2g-+}8Va?P6u{{iUpi1@B$DDYGmTMi^!(;20^@<-b6POGkEivU^AnL7YrGzWvo zu!x2ixSo+OT5MBW1Dh(cuCdNb$c=0EGYd3Pc&BMWF>Gj?jQ$vIR@kqpg=>-C$RGZ; z!;?;J)-YWnQd?aVH{dl=%>d-GZ9A=j4%&OmPNtUnV)XSDrc>ggo5dxt_}ixzq3sQK z_zIBv4Nm8?H5(9}SVNQsDo1BgOa?Qc0ENh7B;^S7+6+lg1COLYu2=eqVlSU^-ETLjnRMhTWU{ha|pctWhxjaSl-pnNtNd^r?I z5Af7W?glnlQ3K*d2I705p7&SUgR^dWdgoZY-TX>0TO7Z4H#u-vfyK>y;h98`v7V*& zPG0UhvI!qIhSa{jrrx>vy1^1~!R`sG2sa7JmOzHv0S(v_XINL>hwpG;o+?1Rr@;d~ zsR48g68ajkb<8HbKC$eyEYDsi!%b8@L`vBN&r$9~jF6I)Q1R*2){t`C+=+{j;*L1p77GLA)_;XDl&S_32ac=IG1b~6GaV7iljN2pxA z$mB$n%@34AyA$v0ujB5M@!TKWo8ayaxKnY2N5B<&0|mDx_!*|y{pOOjP7Gre8@391 zTW&7HbHS$uQJMJR9eE+YTcArsz?mh3wO<8Z!~3f04}49>Swii2J7cVEzQ|m?{-*jY zQm~(3*4mHLX`q={nz0{_PF7@2f|4I7%8>CD1qKFvEqKKHxA~@Fy z@Hc^tD=}T@bkReBORp3D{`nVl;%-&JVI~MNBu|PArt+!FJ3zzN_0xcY zR&LvH-|-CKzwg@6aIdjkIY~9g+EQh|!F1Iio-BSvudxdDHPXvxyIxBbsu!K*KL#%h zlH=~~KRVr87)w)K!{6-=2{qoXl=iN-;8pdVjD6F(i7Wpe(B*N`gMV3m6g2IB=M6Q1 z@0;&pj7h=0OkQgi(0U;zT{r`Q9~L1Y^r1-%@*3sB)qA6YS1FR)Yu&g(B0CC=yPmSz*{ z{VHyw;`)_ACFHPLpOb-yp;tSWJGe7O)Isi(qJTc5azRZ;0X_tRFKO&FT>TF$F*AV>J(M zqY8a0!6kFo&->TNQRmz1@}RE1d0EC~$@%R1u3qJ;chCQ2cM(1XZ)nqfQrpmImyc-Y zw$Bdzs56MvNDhTdInX%dkjtKiiKrd?kuj!9zKf|RnhA?7j9it;(Vq=iM>@*poY+USApj$ z^wkr|QB37^uGX9^3eBMSmPLP)+qxUt5ND&0&yE`~hCc%ja-dw-?W)|`Hl=AT4_4?pU4Z+hg^rEZP7oiOwUu{h8 zeY*be^(?G+QD94;cZys6>fZs2t*enIoWVn7jPJJYDHBCt^E(qa0sgs)wN+jVO^6}T zsUT^`#OEWUK|iapQbC@Sp_pB6JKsP%ovFV8XP^ZcdrG;hdC`wiDUUfjQH-xi%Gl!f zRCYO!s!wfWfGQt{QXx>(o68{3ou41(Sc~GHI1fxJ^*+v`8|1t9L;mbcmrpvtFL4{f z=ou?MwK_o5KJUQ5P5HNn8zD++1I!n~D~yHmHHR1jvjxJ_1li~tOKrgR*=tZEFn5mS z#sH{Vw8%CISTvItm`A}Hqi@F+Vqb*bc)mC4On%y2Nn4gdyuNf_@-pM7P5M#ni0IhS z6LmgJ)Z44`W@CQMMLG@<63WuGFdrsjxz|8F@5a@M-il=1FT?e>4lj}v5B%QzeMG%B znKltz{eJ9kcnv~r`%CT}s=uty4(9g-AOl|6@$GG@E2iNwl!)G6eaHS*RtvV9QLWCWjoj^nz;}-xDBryNxnft#Jf36A6wYn zc+Q^zNKhT^Xuk0%IOO3~Ge$z6jd9U@&BbFO1D&_p_?r`>7AU9gM?0#UhP?rh7lCVU z10e59-UV3oRQ%@m9W}l)@#=wZ9;aQV=X*=w00KaXd=i>npu5lh-v1ltM>s8UuFfb9Ny+kJJ8kZu)VG(m7oCu_65p%)(T* z0I#R_E2f9pXN>4!FP<;mHwI-x+cJ{r=lU=i#ZlMB{J0Fvzl!%M%0$h2^%Qvz2D2%p zB8>ve+gL&yua{A6pDLGDty4SSx%YTRC_AG0@C7@}6RW^n*aPr} z{Z&svr--^2u$X5Kc^1Z<L4O=J)2xY_HIX z9GVEi9K&;;aU>wX&m-^u$fXcYJVSVoVAgT zDy!w$UZlDQ;Eir=s^Ewru_|T_oElBV%6&yJ(bpfQnIMwfk*v zJC!2iXgdjp755t^#X8 zyFpwAZJ{RYo(sjMpPfwe3b`szu!v4AS3MaiYP<)OUwL_kLLPogeUrQlH!UW))p_g9yG?!Oyp0>V5TK{femf z=q<_HYsW%7g~rX#B2=A)kp))DC4PV>ewCB@1gER#OgL1>)wC4`sdYV!NmTcZbVFqW zEY~%6Z(Gv>Lv#Hb!}N&`&SK8WuwH*Rm1>x!nD{j=kH}<+tJCh0N$L{Vq~YNtFE2?o zqnOvmNt8_*Smrwi_ms!owb&&ohtl)W!v_;3&saH%eHjYNXpFVwWT<6$dfBW`N{9orKY?}g2!56F#Qi7(3w8-HrnIAFHeFZZ!Vr!7jS8fac9!qiAW zO{km`Z4}}Vm-$W-MhE2kJQZ^2BLFp*OT;5?911aUMjlfHQQpGARK>Mg*DX(B{+in- zdFXjPB^nTLXvj2GU_HU<#(ZS0d*U}ihvFwH(+%Dce;Va|;#R2!!-{g3M%!30*p^UX zSKixbsa#WB52&t34Z+0&V&EJO@bLB|mjOjrE{)&@iK`sO!PP+${^GGEMj!oS>3?Od z(z-O!o>EHR?Wxq*+dkR4T_z@B!~zrSU2y!>#FUzokSBei#lN}RlP@`znm)|;{1%;C z7f{|{N;>u73p>5axgb{$w zO@PuZzg?qCF%*op5!$S}4O14DK8f&;Mz21XP;8P2+*Djz7xeRjKbQyBqHTU0E4P10 z*K<}DvAgp|)h4lCB&`Z+IK0)3#RJ=U76X43B!Q793L*X;=95>{fe{IJl{VF`1JbD6&4j6 zhUF7MW+HywA#%;rYEeaaFA@Jh^&WRSWWh&BeeSjauQjO>dhu9KRn)&dML%0cMDQsx zPpe6*UxWl_GTQ=K)`-#nc~I_D=_766ni_yHEOs>!H7;l#N)a2vG~AJvyj5Tqm~0&7 zCmHknA>H?D7qL~Ksbbq&VOTgl@p+cw3zN5eCjU}mGfgm$zcbAO{rbM5|aYsk+_A?)6@hkA)0au@CSzO?glGs>&} z@?Q4RF|Y@3Ao)p+76Ou%7o~6gsqy{Uo<9_mkp00hilC@tns(u#>p@$=g^O0zDS``4 zx0m$pZ^kvDIP~*J)3rF8o;lvJ<5fA*yeeS__Bc_Uptr66*!;4zeUv*&QguV>Xi-S2podm0ikn6!(kw*yY*K!(lFQo|J6EP$zaLy5FsLXv|#!+>ig}vRTEO zbx7(&ez^X(8S!-P=D*FG@9DzEmGdS!b^Sl;QWjir#ZUTymi-M+k`QgMzZOI4_?;=V z+H=KU;g%OJD*mLjMb8Ru4_vw6067yW3?KCSscEw>?SJ|C{e$0nqGC}y3ra8!8^cJ| zQtA!Ox38E}60sctgLUoaZMJg??X`kyLkNu+o@CogNoIQ;%vEsyavy5DfuA!YkmG<`Iq5j1i*GL^tLq>^7)XW_Q# zJ20g1yI%JTj znT`?JPrIWVlWsV4=Z9bV?{yL8Es#!9fLR_2D$`7VrP7W)(@DD6i>@-jB16dmhBRWE z!a`h=;6Yv;;nfoLDM|cSs%{!cO8KiNwo6RW36qlsH{Ya!oVOA;D!LcmMzyntfPzs2V z2+m@Wk=s2cY)jp87@I*?u@}sadkCdK3N!#r#9165>BA70!#~{qaa*>-@sq>Lgq+J6 zl4G_uoOK_C+NWVuPS|O4=LJD%_8lwd9Uv1jbWkz^pl1Q1GYAq29}+Htrp2e&p1u2u zQW-*A?4Ad5B4TNv428W;^TyV7pxMh%`zfjiJ$C!4HT?-hFTzCH<;`HkYj85iEwv^b zEf9QsMrv{pYtkK48*73yCdXRI_eD8$gelRgDC&5>Uu%OV(F9LWIDk@wktdW2rYiL4 zz)%=Ts6tjqAy(*`D@Y;KQqisCwiU==6em^|vuxE@-4_~6xK6q93~iW!K}Jg790 zD3fo@^O|*aErnJHktRNb7+JQFag+r=j`c1IJGvHE*VF!V9AlQw29d-z_nk{@olH#F zN8G1sR%UCEK?2|(?`H^r(5bZ5#Q^O*?}z?h&u z8^^0%B&m&-2Cc>{GIdMC3?i2{_#s6ql|^il5G1HxhkUes*_P%dUeVZ>R8Vpb|2{gDQ~{meSIT0}_?8R46*YHNX|XK$%3%RppIU-6j>7q!n0&RmRY^ zT?JLN^8!_^Vpwh8_Z=99i>0$CkyT22X^2W%DjEMxJ-^JTLqjh1v!={JKY3lcf@s&B z3%a6v*9x0i*#t89kp^d0yXKeJJn1p#aWO8Jr~V}#TG#Q3d!}fL5DG{6GMxRM?#Z(5 znW-*2A}FMP1ASdOa%wALU7?nNK6_E7RfisvW$tF~Dgujn7DUSDFHJvzx`4DIx-G3CA2iA_)Hc6(VRX@Z? zc`m`{z0~HK=l+-s?)@t2Dg*S5--nLq^}QBk_{$fGaHXL=w$#hRd@Yg@n^NW|^3Bto5g|-Z7t5yRXYIYT(XNtcp?@ zpEKjAK*u4$KI|WKp2c1>ve}KQm0V``V2HAbult^F;pbmt0ore zCRR>fu4YnQQc@%swQ8dfX+$@36DLk9o`5|D^VQ~F5E5-35gb7%Fa5t`9w-3ptj+dc z{GP2i@s2`46j${OZhJe61f;hj)DNFJNCBk$7?7+2q%Z&gu$<@}-|?>J2b5t5tJE!w z%1ZyrEq#?j4^l0#G#aTe8l&I>$H6|y6fY5*KOyP4++Yj{TZa!W9G6u;l~phb1G}Pi zehrhcw|>qssZOv<1~ut0XaL2z3)xT!XvVIdpN+f#6;J{d+V?zL5<((;;6gBj3`3Od z(d%4MckOHsBbU~^UkOn*Vu4rw<3zRgH|#}I7D_j*Rz`9XzA?xp#rmse0HI}4C0;To z4xtk7kgV!RC~*E?`jzjLayW#NIg>x|mlG45EC3e})S)sAw$kwWc&=Bd-m1JRKzcjh zR-`>KkME|{9&h`yJg)^JG>y@yBH|d((x^XHXoR2$|7r*@j~TjeLf-THeP9Yx;KI?+ z^SA+~D``K;K|j27OvO~!&2SvXWK6_h4966)+J74@86M=T>;H2mtUHtCp&sEelL-?Z z+mR61aS+>49^SP;r+^)F01#)?oN55TU;qiIO7S7okPn|eejxHO^spjBi+v19>_do; zpNoD#QuK(CqM?SMLOuTUD9V%z8@`6g95(Y=&6><+)}*;pr>|$eWIp?a^C!-pIBnK6 zM$;G#d#B8(p+knwoKs@Xj2Uz0%$zxNu9~5vhUy$OUdNa*vo<)^TC`|w_b|QH(Wp{|1Y{opea+4_T+`WSb!5{zu z7Ha(RW$f2$U$0@yj_oU$?AyPR(boMs_pe~FS<4m%Omh|56!1X<50p?sdg`$7!c!`|a6=32=#axYJhbo>4n+jfLVD;qg~U4S zG3_)5PQh|_7#n`M)U``B-SksXKlL{#tCW#gbXcAr+dT6AxMj8eixY@>tZMu1ohHbbZ+iWAmjz++>*G9W-BgQdeZ2-5~X6>)L z;b!i-Aygne48AdEaC5>bd~n0Z8N3_B7bl!?#tnDe9K{cpoN>Yp-^LuwZ3sXgT0HVsaQ_uB83SZ>*#pcPqUqX80e6nZ2AJi8RKD zdgkDYE3lj&Lk#DmA7c*cuLnze=f!}&`sl$2OAP9_55IbPW++Y=VSW)N7hr%9rkY^l zw?F=B*axN>`}Nmf{^H#4e(nok{Msjs7zpe%8L&Y&x-kW9q|Je1bD%f8!416`;TqWR zM%cPxL2rDp8{im+1wR-<3}R3T+vuPJvC$0{ZetwbC`S#4R}Nx4gBZ>zhck$QLm&3= z8QgeT$a=U#Vl?ArCgX+=OV*4emh6W=>>=aD_EW0F7dBgBXJpBr&29jU*Z)8c^hh zHx4<-Lmm=}h(x3yi-AZ(?(9l|5C8@IZWtnS67h;r4j-8lOFJ{?COyec;#rAj#B-99o>B+tLGO9{^d49G zIlbrobD#VaC_(x8ygAfi2EPEtGL``h_z6&ex(MJyA1YD#-LE(owf
  • UY0h1Y;Kp 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 Z#&3Mbe|*S~e951D%CCIOpOAn606S;EsG0x( literal 0 HcmV?d00001 diff --git a/tensorlayer/third_party/roi_pooling/roi_pooling_example.py b/tensorlayer/third_party/roi_pooling/roi_pooling_example.py new file mode 100644 index 00000000..7d9b7b63 --- /dev/null +++ b/tensorlayer/third_party/roi_pooling/roi_pooling_example.py @@ -0,0 +1,63 @@ +from __future__ import print_function + +import tensorflow as tf +import numpy as np + +from roi_pooling.roi_pooling_ops import roi_pooling + +# input feature map going into the RoI pooling +input_value = [[ + [[1], [2], [4], [4]], + [[3], [4], [1], [2]], + [[6], [2], [1], [7.0]], + [[1], [3], [2], [8]] +]] +input_value = np.asarray(input_value, dtype='float32') + +# Regions of interest as lists of: +# feature map index, upper left, bottom right coordinates +rois_value = [ + [0, 0, 0, 1, 1], + [0, 1, 1, 2, 2], + [0, 2, 2, 3, 3], + [0, 0, 0, 2, 2], + [0, 0, 0, 3, 3] +] +rois_value = np.asarray(rois_value, dtype='int32') + +# the pool_height and width are parameters of the ROI layer +pool_height, pool_width = (2, 2) +n_rois = len(rois_value) +y_shape = [n_rois, 1, pool_height, pool_width] + +print('Input: ', input_value, ', shape: ', input_value.shape) +print('ROIs: ', rois_value, ', shape: ', rois_value.shape) + +# precise semantics is now only defined by the kernel, need tests +input = tf.placeholder(tf.float32) +rois = tf.placeholder(tf.int32) + +y = roi_pooling(input, rois, pool_height=2, pool_width=2) +mean = tf.reduce_mean(y) + +grads = tf.gradients(mean, input) +print(type(grads)) +print(len(grads)) +print(grads) +print(input_value.shape) + +with tf.Session('') as sess: + input_const = tf.constant(input_value, tf.float32) + rois_const = tf.constant(rois_value, tf.int32) + y = roi_pooling(input_const, rois_const, pool_height=2, pool_width=2) + mean = tf.reduce_mean(y) + + numerical_grad_error_1 = tf.test.compute_gradient_error([input_const], [input_value.shape], y, y_shape) + numerical_grad_error_2 = tf.test.compute_gradient_error([input_const], [input_value.shape], mean, []) + print(numerical_grad_error_1, numerical_grad_error_2) + +with tf.Session('') as sess: + y_output = sess.run(y, feed_dict={input: input_value, rois: rois_value}) + print('y: ', y_output) + grads_output = sess.run(grads, feed_dict={input: input_value, rois: rois_value}) + print('grads: ', grads_output) diff --git a/tensorlayer/third_party/roi_pooling/setup.py b/tensorlayer/third_party/roi_pooling/setup.py new file mode 100644 index 00000000..de392a9d --- /dev/null +++ b/tensorlayer/third_party/roi_pooling/setup.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python + +from __future__ import print_function +from distutils.core import setup +from distutils.command.install import install as DistutilsInstall +import sys +import subprocess + +try: + import tensorflow +except ImportError: + print("Please install tensorflow 0.12.0 or later") + sys.exit() + + +class MyInstall(DistutilsInstall): + def run(self): + subprocess.call(['make', '-C', 'roi_pooling', 'build']) + DistutilsInstall.run(self) + +setup(name='roi-pooling', + version='1.0', + description='ROI pooling as a custom TensorFlow operation', + author='deepsense.io', + packages=['roi_pooling'], + package_data={'roi_pooling': ['roi_pooling.so']}, + cmdclass={'install': MyInstall} +) + + + + diff --git a/tensorlayer/third_party/roi_pooling/test_roi_layer.py b/tensorlayer/third_party/roi_pooling/test_roi_layer.py new file mode 100644 index 00000000..5ca6a12a --- /dev/null +++ b/tensorlayer/third_party/roi_pooling/test_roi_layer.py @@ -0,0 +1,66 @@ +from tensorlayer.layers import * + +from tensorlayer.third_party.roi_pooling.roi_pooling.roi_pooling_ops import roi_pooling +# from roi_pooling.roi_pooling_ops import roi_pooling + + + +# input feature map going into the RoI pooling +input_value = [[ + [[1], [2], [4], [4]], + [[3], [4], [1], [2]], + [[6], [2], [1], [7.0]], + [[1], [3], [2], [8]] +]] +input_value = np.asarray(input_value, dtype='float32') + +# Regions of interest as lists of: +# feature map index, upper left, bottom right coordinates +rois_value = [ + [0, 0, 0, 1, 1], + [0, 1, 1, 2, 2], + [0, 2, 2, 3, 3], + [0, 0, 0, 2, 2], + [0, 0, 0, 3, 3] +] +rois_value = np.asarray(rois_value, dtype='int32') + +# the pool_height and width are parameters of the ROI layer +pool_height, pool_width = (2, 2) +n_rois = len(rois_value) +y_shape = [n_rois, 1, pool_height, pool_width] + +print('Input: ', input_value, ', shape: ', input_value.shape) +print('ROIs: ', rois_value, ', shape: ', rois_value.shape) + +# precise semantics is now only defined by the kernel, need tests +input = tf.placeholder(tf.float32) +rois = tf.placeholder(tf.int32) + +# y = roi_pooling(input, rois, pool_height=2, pool_width=2) +n = InputLayer(input, name='in') +n = ROIPoolingLayer(n, rois=rois, pool_height=2, pool_width=2, name='roi') +y = n.outputs +mean = tf.reduce_mean(y) + +grads = tf.gradients(mean, input) +print(type(grads)) +print(len(grads)) +print(grads) +print(input_value.shape) + +with tf.Session('') as sess: + input_const = tf.constant(input_value, tf.float32) + rois_const = tf.constant(rois_value, tf.int32) + y = roi_pooling(input_const, rois_const, pool_height=2, pool_width=2) + mean = tf.reduce_mean(y) + + numerical_grad_error_1 = tf.test.compute_gradient_error([input_const], [input_value.shape], y, y_shape) + numerical_grad_error_2 = tf.test.compute_gradient_error([input_const], [input_value.shape], mean, []) + print(numerical_grad_error_1, numerical_grad_error_2) + +with tf.Session('') as sess: + y_output = sess.run(y, feed_dict={input: input_value, rois: rois_value}) + print('y: ', y_output) + grads_output = sess.run(grads, feed_dict={input: input_value, rois: rois_value}) + print('grads: ', grads_output) diff --git a/tensorlayer/utils.py b/tensorlayer/utils.py index 0dbdbdc1..12a3f4bb 100644 --- a/tensorlayer/utils.py +++ b/tensorlayer/utils.py @@ -1,5 +1,5 @@ #! /usr/bin/python -# -*- coding: utf8 -*- +# -*- coding: utf-8 -*- import tensorflow as tf import tensorlayer as tl from . import iterate @@ -67,11 +67,11 @@ def fit(sess, network, train_op, cost, X_train, y_train, x, y_, acc=None, batch_ ... X_val=X_val, y_val=y_val, eval_train=False, ... tensorboard=True, tensorboard_weight_histograms=True, tensorboard_graph_vis=True) - Note + Notes -------- - If tensorboard=True, the global_variables_initializer will be run inside the fit function - in order to initalize the automatically generated summary nodes used for tensorboard visualization, - thus tf.global_variables_initializer().run() before the fit() call will be undefined. + If tensorboard=True, the global_variables_initializer will be run inside the fit function + in order to initalize the automatically generated summary nodes used for tensorboard visualization, + thus tf.global_variables_initializer().run() before the fit() call will be undefined. """ assert X_train.shape[0] >= batch_size, "Number of training examples should be bigger than the batch size" @@ -130,7 +130,7 @@ def fit(sess, network, train_op, cost, X_train, y_train, x, y_, acc=None, batch_ result = sess.run(merged, feed_dict=feed_dict) train_writer.add_summary(result, tensorboard_train_index) tensorboard_train_index += 1 - if (X_val is not None) and (y_val is not None): + if (X_val is not None) and (y_val is not None): for X_val_a, y_val_a in iterate.minibatches( X_val, y_val, batch_size, shuffle=True): dp_dict = dict_to_one( network.all_drop ) # disable noise layers @@ -178,7 +178,6 @@ def fit(sess, network, train_op, cost, X_train, y_train, x, y_, acc=None, batch_ print("Epoch %d of %d took %fs, loss %f" % (epoch + 1, n_epoch, time.time() - start_time, loss_ep)) print("Total training time: %fs" % (time.time() - start_time_begin)) - def test(sess, network, acc, X_test, y_test, x, y_, batch_size, cost=None): """ Test a given non time-series network by the given test data and metric. @@ -237,7 +236,6 @@ def test(sess, network, acc, X_test, y_test, x, y_, batch_size, cost=None): print(" test loss: %f" % (test_loss/ n_batch)) print(" test acc: %f" % (test_acc/ n_batch)) - def predict(sess, network, X, x, y_op, batch_size=None): """ Return the predict results of given non time-series network. @@ -281,7 +279,21 @@ def predict(sess, network, X, x, y_op, batch_size=None): if result is None: result = result_a else: - result = np.hstack((result, result_a)) + result = np.vstack((result, result_a)) + if result is None: + if len(X) % batch_size != 0: + dp_dict = dict_to_one(network.all_drop) + feed_dict = {x: X[-(len(X) % batch_size):, :], } + feed_dict.update(dp_dict) + result_a = sess.run(y_op, feed_dict=feed_dict) + result = result_a + else: + if len(X) != len(result) and len(X) % batch_size != 0: + dp_dict = dict_to_one(network.all_drop) + feed_dict = {x: X[-(len(X) % batch_size):, :], } + feed_dict.update(dp_dict) + result_a = sess.run(y_op, feed_dict=feed_dict) + result = np.vstack((result, result_a)) return result @@ -349,7 +361,6 @@ def flatten_list(list_of_list=[[],[]]): """ return sum(list_of_list, []) - def class_balancing_oversample(X_train=None, y_train=None, printable=True): """Input the features and labels, return the features and labels after oversampling. @@ -430,6 +441,7 @@ def class_balancing_oversample(X_train=None, y_train=None, printable=True): # ================ End of Classes balancing return X_train, y_train + ## Random def get_random_int(min=0, max=10, number=5, seed=None): """Return a list of random integer by the given range and quantity. @@ -445,6 +457,13 @@ def get_random_int(min=0, max=10, number=5, seed=None): # return [random.randint(min,max) for p in range(0, number)] return [rnd.randint(min,max) for p in range(0, number)] +def list_string_to_dict(string): + """Inputs ``['a', 'b', 'c']``, returns ``{'a': 0, 'b': 1, 'c': 2}``.""" + dictionary = {} + for idx, c in enumerate(string): + dictionary.update({c:idx}) + return dictionary + # # def class_balancing_sequence_4D(X_train, y_train, sequence_length, model='downsampling' ,printable=True): # ''' 输入、输出都是sequence format diff --git a/tensorlayer/visualize.py b/tensorlayer/visualize.py index 33868274..86b65f07 100644 --- a/tensorlayer/visualize.py +++ b/tensorlayer/visualize.py @@ -1,19 +1,50 @@ #! /usr/bin/python -# -*- coding: utf8 -*- +# -*- coding: utf-8 -*- import matplotlib -matplotlib.use('Agg') -import matplotlib.pyplot as plt -# import matplotlib.pyplot as plt +## use this, if you got the following error: +# _tkinter.TclError: no display name and no $DISPLAY environment variable +# matplotlib.use('Agg') + import numpy as np import os +from . import prepro - -## Save images +# save/read image(s) import scipy.misc -def save_image(image, image_path): +def read_image(image, path=''): + """ Read one image. + + Parameters + ----------- + images : string, file name. + path : string, path. + """ + return scipy.misc.imread(os.path.join(path, image)) + +def read_images(img_list, path='', n_threads=10, printable=True): + """ Returns all images in list by given path and name of each image file. + + Parameters + ------------- + img_list : list of string, the image file names. + path : string, image folder path. + n_threads : int, number of thread to read image. + printable : bool, print infomation when reading images, default is True. + """ + imgs = [] + for idx in range(0, len(img_list), n_threads): + b_imgs_list = img_list[idx : idx + n_threads] + b_imgs = prepro.threading_data(b_imgs_list, fn=read_image, path=path) + # print(b_imgs.shape) + imgs.extend(b_imgs) + if printable: + print('read %d from %s' % (len(imgs), path)) + return imgs + +def save_image(image, image_path=''): """Save one image. Parameters @@ -21,9 +52,12 @@ def save_image(image, image_path): images : numpy array [w, h, c] image_path : string. """ - scipy.misc.imsave(image_path, image) + try: # RGB + scipy.misc.imsave(image_path, image) + except: # Greyscale + scipy.misc.imsave(image_path, image[:,:,0]) -def save_images(images, size, image_path): +def save_images(images, size, image_path=''): """Save mutiple images into one single image. Parameters @@ -53,6 +87,78 @@ def imsave(images, size, path): assert len(images) <= size[0] * size[1], "number of images should be equal or less than size[0] * size[1] {}".format(len(images)) return imsave(images, size, image_path) +# for object detection +def draw_boxes_and_labels_to_image(image, classes=[], coords=[], + scores=[], classes_list=[], + is_center=True, is_rescale=True, save_name=None): + """ Draw bboxes and class labels on image. Return or save the image with bboxes, example in the docs of ``tl.prepro``. + + Parameters + ----------- + image : RGB image in numpy.array, [height, width, channel]. + classes : a list of class ID (int). + coords : a list of list for coordinates. + - Should be [x, y, x2, y2] (up-left and botton-right format) + - If [x_center, y_center, w, h] (set is_center to True). + scores : a list of score (float). (Optional) + classes_list : list of string, for converting ID to string on image. + is_center : boolean, defalt is True. + If coords is [x_center, y_center, w, h], set it to True for converting [x_center, y_center, w, h] to [x, y, x2, y2] (up-left and botton-right). + If coords is [x1, x2, y1, y2], set it to False. + is_rescale : boolean, defalt is True. + If True, the input coordinates are the portion of width and high, this API will scale the coordinates to pixel unit internally. + If False, feed the coordinates with pixel unit format. + save_name : None or string + The name of image file (i.e. image.png), if None, not to save image. + + References + ----------- + - OpenCV rectangle and putText. + - `scikit-image `_. + """ + assert len(coords) == len(classes), "number of coordinates and classes are equal" + if len(scores) > 0: + assert len(scores) == len(classes), "number of scores and classes are equal" + + import cv2 + + # image = copy.copy(image) # don't change the original image + image = image.copy() # don't change the original image, and avoid error https://stackoverflow.com/questions/30249053/python-opencv-drawing-errors-after-manipulating-array-with-numpy + + imh, imw = image.shape[0:2] + thick = int((imh + imw) // 430) + + for i in range(len(coords)): + if is_center: + x, y, x2, y2 = prepro.obj_box_coord_centroid_to_upleft_butright(coords[i]) + else: + x, y, x2, y2 = coords[i] + + if is_rescale: # scale back to pixel unit if the coords are the portion of width and high + x, y, x2, y2 = prepro.obj_box_coord_scale_to_pixelunit([x, y, x2, y2], (imh, imw)) + + cv2.rectangle(image, + (int(x), int(y)), (int(x2), int(y2)), # up-left and botton-right + [0,255,0], + thick) + + cv2.putText( + image, + classes_list[classes[i]] + ((" %.2f" % (scores[i])) if (len(scores) != 0) else " "), + (int(x), int(y)), # button left + 0, + 1.5e-3 * imh, # bigger = larger font + [0,0,256], # self.meta['colors'][max_indx], + int(thick/2)+1) # bold + + if save_name is not None: + # cv2.imwrite('_my.png', image) + save_image(image, save_name) + # if len(coords) == 0: + # print("draw_boxes_and_labels_to_image: no bboxes exist, cannot draw !") + return image + +# old APIs def W(W=None, second=10, saveable=True, shape=[28,28], name='mnist', fig_idx=2396512): """Visualize every columns of the weight matrix to a group of Greyscale img. @@ -75,6 +181,7 @@ def W(W=None, second=10, saveable=True, shape=[28,28], name='mnist', fig_idx=239 -------- >>> tl.visualize.W(network.all_params[0].eval(), second=10, saveable=True, name='weight_of_1st_layer', fig_idx=2012) """ + import matplotlib.pyplot as plt if saveable is False: plt.ion() fig = plt.figure(fig_idx) # show all feature images @@ -138,6 +245,7 @@ def frame(I=None, second=5, saveable=True, name='frame', cmap=None, fig_idx=1283 >>> observation = env.reset() >>> tl.visualize.frame(observation) """ + import matplotlib.pyplot as plt if saveable is False: plt.ion() fig = plt.figure(fig_idx) # show all feature images @@ -176,6 +284,7 @@ def CNN2d(CNN=None, second=10, saveable=True, name='cnn', fig_idx=3119362): -------- >>> tl.visualize.CNN2d(network.all_params[0].eval(), second=10, saveable=True, name='cnn1_mnist', fig_idx=2012) """ + import matplotlib.pyplot as plt # print(CNN.shape) # (5, 5, 3, 64) # exit() n_mask = CNN.shape[3] @@ -216,7 +325,6 @@ def CNN2d(CNN=None, second=10, saveable=True, name='cnn', fig_idx=3119362): plt.draw() plt.pause(second) - def images2d(images=None, second=10, saveable=True, name='images', dtype=None, fig_idx=3119362): """Display a group of RGB or Greyscale images. @@ -241,6 +349,7 @@ def images2d(images=None, second=10, saveable=True, name='images', dtype=None, >>> X_train, y_train, X_test, y_test = tl.files.load_cifar10_dataset(shape=(-1, 32, 32, 3), plotable=False) >>> tl.visualize.images2d(X_train[0:100,:,:,:], second=10, saveable=False, name='cifar10', dtype=np.uint8, fig_idx=20212) """ + import matplotlib.pyplot as plt # print(images.shape) # (50000, 32, 32, 3) # exit() if dtype: @@ -311,6 +420,7 @@ def tsne_embedding(embeddings, reverse_dictionary, plot_only=500, >>> tl.visualize.tsne_embedding(final_embeddings, labels, reverse_dictionary, ... plot_only=500, second=5, saveable=False, name='tsne') """ + import matplotlib.pyplot as plt def plot_with_labels(low_dim_embs, labels, figsize=(18, 18), second=5, saveable=True, name='tsne', fig_idx=9862): assert low_dim_embs.shape[0] >= len(labels), "More labels than embeddings"