From e3b4cee023008a343f1f32e2c05a4a387eeb5e9b Mon Sep 17 00:00:00 2001
From: lxr-tech <1838593642@qq.com>
Date: Tue, 3 May 2022 22:24:27 +0800
Subject: [PATCH] add fastnlp_tutorial_1 lxr 220503
---
tutorials/fastnlp_tutorial_0.ipynb | 16 +-
tutorials/fastnlp_tutorial_1.ipynb | 1156 ++++++++++++++++++++
tutorials/figures/T0-fig-trainer-and-evaluator.png | Bin 104863 -> 100764 bytes
3 files changed, 1163 insertions(+), 9 deletions(-)
create mode 100644 tutorials/fastnlp_tutorial_1.ipynb
diff --git a/tutorials/fastnlp_tutorial_0.ipynb b/tutorials/fastnlp_tutorial_0.ipynb
index 28fcfddf..26675ecf 100644
--- a/tutorials/fastnlp_tutorial_0.ipynb
+++ b/tutorials/fastnlp_tutorial_0.ipynb
@@ -136,7 +136,7 @@
"在`fastNLP 0.8`中,使用`pytorch.nn.Module`搭建需要训练的模型,在搭建模型过程中,除了\n",
"\n",
" 添加`pytorch`要求的`forward`方法外,还需要添加 **`train_step`** 和 **`evaluate_step`** 这两个方法\n",
- "***\n",
+ "\n",
"```python\n",
"class Model(torch.nn.Module):\n",
" def __init__(self):\n",
@@ -177,9 +177,7 @@
"\n",
" 从模块角度,该字典的键值和`metric`中的`update`函数的签名一致,这样的机制在传参时被称为“**参数匹配**”\n",
"\n",
- "***\n",
- "\n",
- ""
+ ""
]
},
{
@@ -206,7 +204,7 @@
" 而在`Trainer`和`Evaluator`中的参数`model_wo_auto_param_call`被设置为`True`时\n",
"\n",
" `fastNLP 0.8`会将`batch`直接传给模型的`train_step`、`evaluate_step`或`forward`函数\n",
- "***\n",
+ "\n",
"```python\n",
"class Dataset(torch.utils.data.Dataset):\n",
" def __init__(self, x, y):\n",
@@ -253,7 +251,7 @@
"id": "5314482b",
"metadata": {
"pycharm": {
- "is_executing": false
+ "is_executing": true
}
},
"outputs": [],
@@ -641,11 +639,11 @@
{
"data": {
"text/html": [
- "
{'acc#acc': 0.43}\n", + "{'acc#acc': 0.29}\n", "\n" ], "text/plain": [ - "\u001b[1m{\u001b[0m\u001b[32m'acc#acc'\u001b[0m: \u001b[1;36m0.43\u001b[0m\u001b[1m}\u001b[0m\n" + "\u001b[1m{\u001b[0m\u001b[32m'acc#acc'\u001b[0m: \u001b[1;36m0.29\u001b[0m\u001b[1m}\u001b[0m\n" ] }, "metadata": {}, @@ -654,7 +652,7 @@ { "data": { "text/plain": [ - "{'acc#acc': 0.43}" + "{'acc#acc': 0.29}" ] }, "execution_count": 9, diff --git a/tutorials/fastnlp_tutorial_1.ipynb b/tutorials/fastnlp_tutorial_1.ipynb new file mode 100644 index 00000000..11bd2219 --- /dev/null +++ b/tutorials/fastnlp_tutorial_1.ipynb @@ -0,0 +1,1156 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "cdc25fcd", + "metadata": {}, + "source": [ + "# T1. dataset 和 vocabulary 的基本使用\n", + "\n", + " 1 dataset 的使用与结构\n", + " \n", + " 1.1 dataset 的结构与创建\n", + "\n", + " 1.2 dataset 的数据预处理\n", + "\n", + " 1.3 延伸:instance 和 field\n", + "\n", + " 2 vocabulary 的结构与使用\n", + "\n", + " 2.1 vocabulary 的创建与修改\n", + "\n", + " 2.2 vocabulary 与 OOV 问题\n", + "\n", + " 3 dataset 和 vocabulary 的组合使用\n", + " \n", + " 3.1 从 dataframe 中加载 dataset\n", + "\n", + " 3.2 从 dataset 中获取 vocabulary" + ] + }, + { + "cell_type": "markdown", + "id": "0eb18a22", + "metadata": {}, + "source": [ + "## 1. dataset 的基本使用\n", + "\n", + "### 1.1 dataset 的结构与创建\n", + "\n", + "在`fastNLP 0.8`中,使用`DataSet`模块表示数据集,**`dataset`类似于关系型数据库中的数据表**(下文统一为小写`dataset`)\n", + "\n", + " **主要包含`field`字段和`instance`实例两个元素**,对应`table`中的`field`字段和`record`记录\n", + "\n", + "在`fastNLP 0.8`中,`DataSet`模块被定义在`fastNLP.core.dataset`路径下,导入该模块后,最简单的\n", + "\n", + " 初始化方法,即将字典形式的表格 **`{'field1': column1, 'field2': column2, ...}`** 传入构造函数" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "a1d69ad2", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+-----+------------------------+------------------------+-----+\n", + "| idx | sentence | words | num |\n", + "+-----+------------------------+------------------------+-----+\n", + "| 0 | This is an apple . | ['This', 'is', 'an'... | 5 |\n", + "| 1 | I like apples . | ['I', 'like', 'appl... | 4 |\n", + "| 2 | Apples are good for... | ['Apples', 'are', '... | 7 |\n", + "+-----+------------------------+------------------------+-----+\n" + ] + } + ], + "source": [ + "from fastNLP.core.dataset import DataSet\n", + "\n", + "data = {'idx': [0, 1, 2], \n", + " 'sentence':[\"This is an apple .\", \"I like apples .\", \"Apples are good for our health .\"],\n", + " 'words': [['This', 'is', 'an', 'apple', '.'], \n", + " ['I', 'like', 'apples', '.'], \n", + " ['Apples', 'are', 'good', 'for', 'our', 'health', '.']],\n", + " 'num': [5, 4, 7]}\n", + "\n", + "dataset = DataSet(data)\n", + "print(dataset)" + ] + }, + { + "cell_type": "markdown", + "id": "9260fdc6", + "metadata": {}, + "source": [ + " 在`dataset`的实例中,字段`field`的名称和实例`instance`中的字符串也可以中文" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "3d72ef00", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+------+--------------------+------------------------+------+\n", + "| 序号 | 句子 | 字符 | 长度 |\n", + "+------+--------------------+------------------------+------+\n", + "| 0 | 生活就像海洋, | ['生', '活', '就', ... | 7 |\n", + "| 1 | 只有意志坚强的人, | ['只', '有', '意', ... | 9 |\n", + "| 2 | 才能到达彼岸。 | ['才', '能', '到', ... | 7 |\n", + "+------+--------------------+------------------------+------+\n" + ] + } + ], + "source": [ + "temp = {'序号': [0, 1, 2], \n", + " '句子':[\"生活就像海洋,\", \"只有意志坚强的人,\", \"才能到达彼岸。\"],\n", + " '字符': [['生', '活', '就', '像', '海', '洋', ','], \n", + " ['只', '有', '意', '志', '坚', '强', '的', '人', ','], \n", + " ['才', '能', '到', '达', '彼', '岸', '。']],\n", + " '长度': [7, 9, 7]}\n", + "\n", + "chinese = DataSet(temp)\n", + "print(chinese)" + ] + }, + { + "cell_type": "markdown", + "id": "202e5490", + "metadata": {}, + "source": [ + "在`dataset`中,使用`drop`方法可以删除满足条件的实例,这里使用了python中的`lambda`表达式\n", + "\n", + " 注一:在`drop`方法中,通过设置`inplace`参数将删除对应实例后的`dataset`作为一个新的实例生成" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "09b478f8", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1969418794120 1971237588872\n", + "+-----+------------------------+------------------------+-----+\n", + "| idx | sentence | words | num |\n", + "+-----+------------------------+------------------------+-----+\n", + "| 0 | This is an apple . | ['This', 'is', 'an'... | 5 |\n", + "| 2 | Apples are good for... | ['Apples', 'are', '... | 7 |\n", + "+-----+------------------------+------------------------+-----+\n", + "+-----+------------------------+------------------------+-----+\n", + "| idx | sentence | words | num |\n", + "+-----+------------------------+------------------------+-----+\n", + "| 0 | This is an apple . | ['This', 'is', 'an'... | 5 |\n", + "| 1 | I like apples . | ['I', 'like', 'appl... | 4 |\n", + "| 2 | Apples are good for... | ['Apples', 'are', '... | 7 |\n", + "+-----+------------------------+------------------------+-----+\n" + ] + } + ], + "source": [ + "dropped = dataset\n", + "dropped = dropped.drop(lambda ins:ins['num'] < 5, inplace=False)\n", + "print(id(dropped), id(dataset))\n", + "print(dropped)\n", + "print(dataset)" + ] + }, + { + "cell_type": "markdown", + "id": "aa277674", + "metadata": {}, + "source": [ + " 注二:在`fastNLP 0.8`中,**对`dataset`使用等号**,**其效果是传引用**,**而不是赋值**(???)\n", + "\n", + " 如下所示,**`dropped`和`dataset`具有相同`id`**,**对`dropped`执行删除操作`dataset`同时会被修改**" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "77c8583a", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1971237588872 1971237588872\n", + "+-----+------------------------+------------------------+-----+\n", + "| idx | sentence | words | num |\n", + "+-----+------------------------+------------------------+-----+\n", + "| 0 | This is an apple . | ['This', 'is', 'an'... | 5 |\n", + "| 2 | Apples are good for... | ['Apples', 'are', '... | 7 |\n", + "+-----+------------------------+------------------------+-----+\n", + "+-----+------------------------+------------------------+-----+\n", + "| idx | sentence | words | num |\n", + "+-----+------------------------+------------------------+-----+\n", + "| 0 | This is an apple . | ['This', 'is', 'an'... | 5 |\n", + "| 2 | Apples are good for... | ['Apples', 'are', '... | 7 |\n", + "+-----+------------------------+------------------------+-----+\n" + ] + } + ], + "source": [ + "dropped = dataset\n", + "dropped.drop(lambda ins:ins['num'] < 5)\n", + "print(id(dropped), id(dataset))\n", + "print(dropped)\n", + "print(dataset)" + ] + }, + { + "cell_type": "markdown", + "id": "a76199dc", + "metadata": {}, + "source": [ + "在`dataset`中,使用`delet_instance`方法可以删除对应序号的`instance`实例,序号从0开始" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "d8824b40", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+-----+--------------------+------------------------+-----+\n", + "| idx | sentence | words | num |\n", + "+-----+--------------------+------------------------+-----+\n", + "| 0 | This is an apple . | ['This', 'is', 'an'... | 5 |\n", + "| 1 | I like apples . | ['I', 'like', 'appl... | 4 |\n", + "+-----+--------------------+------------------------+-----+\n" + ] + } + ], + "source": [ + "dataset = DataSet(data)\n", + "dataset.delete_instance(2)\n", + "print(dataset)" + ] + }, + { + "cell_type": "markdown", + "id": "f4fa9f33", + "metadata": {}, + "source": [ + "在`dataset`中,使用`delet_field`方法可以删除对应名称的`field`字段" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "f68ddb40", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+-----+--------------------+------------------------------+\n", + "| idx | sentence | words |\n", + "+-----+--------------------+------------------------------+\n", + "| 0 | This is an apple . | ['This', 'is', 'an', 'app... |\n", + "| 1 | I like apples . | ['I', 'like', 'apples', '... |\n", + "+-----+--------------------+------------------------------+\n" + ] + } + ], + "source": [ + "dataset.delete_field('num')\n", + "print(dataset)" + ] + }, + { + "cell_type": "markdown", + "id": "b1e9d42c", + "metadata": {}, + "source": [ + "### 1.2 dataset 的数据预处理\n", + "\n", + "在`dataset`模块中,`apply`、`apply_field`、`apply_more`和`apply_field_more`函数可以进行简单的数据预处理\n", + "\n", + " **`apply`和`apply_more`针对整条实例**,**`apply_field`和`apply_field_more`仅针对实例的部分字段**\n", + "\n", + " **`apply`和`apply_field`仅针对单个字段**,**`apply_more`和`apply_field_more`则可以针对多个字段**\n", + "\n", + " **`apply`和`apply_field`返回的是个列表**,**`apply_more`和`apply_field_more`返回的是个字典**\n", + "\n", + "***\n", + "\n", + "`apply`的参数包括一个函数`func`和一个新字段名`new_field_name`,函数`func`的处理对象是`dataset`模块中\n", + "\n", + " 的每个`instance`实例,函数`func`的处理结果存放在`new_field_name`对应的新建字段内" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "72a0b5f9", + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Output()" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "\n" + ], + "text/plain": [] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "\n", + "\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+-----+------------------------------+------------------------------+\n", + "| idx | sentence | words |\n", + "+-----+------------------------------+------------------------------+\n", + "| 0 | This is an apple . | ['This', 'is', 'an', 'app... |\n", + "| 1 | I like apples . | ['I', 'like', 'apples', '... |\n", + "| 2 | Apples are good for our h... | ['Apples', 'are', 'good',... |\n", + "+-----+------------------------------+------------------------------+\n" + ] + } + ], + "source": [ + "data = {'idx': [0, 1, 2], \n", + " 'sentence':[\"This is an apple .\", \"I like apples .\", \"Apples are good for our health .\"], }\n", + "dataset = DataSet(data)\n", + "dataset.apply(lambda ins: ins['sentence'].split(), new_field_name='words')\n", + "print(dataset)" + ] + }, + { + "cell_type": "markdown", + "id": "c10275ee", + "metadata": {}, + "source": [ + " **`apply`使用的函数可以是一个基于`lambda`表达式的匿名函数**,**也可以是一个自定义的函数**" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "b1a8631f", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n" + ], + "text/plain": [] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "\n" + ], + "text/plain": [] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "\n", + "\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+-----+------------------------------+------------------------------+\n", + "| idx | sentence | words |\n", + "+-----+------------------------------+------------------------------+\n", + "| 0 | This is an apple . | ['This', 'is', 'an', 'app... |\n", + "| 1 | I like apples . | ['I', 'like', 'apples', '... |\n", + "| 2 | Apples are good for our h... | ['Apples', 'are', 'good',... |\n", + "+-----+------------------------------+------------------------------+\n" + ] + } + ], + "source": [ + "dataset = DataSet(data)\n", + "\n", + "def get_words(instance):\n", + " sentence = instance['sentence']\n", + " words = sentence.split()\n", + " return words\n", + "\n", + "dataset.apply(get_words, new_field_name='words')\n", + "print(dataset)" + ] + }, + { + "cell_type": "markdown", + "id": "64abf745", + "metadata": {}, + "source": [ + "`apply_field`的参数,除了函数`func`外还有`field_name`和`new_field_name`,该函数`func`的处理对象仅\n", + "\n", + " 是`dataset`模块中的每个`field_name`对应的字段内容,处理结果存放在`new_field_name`对应的新建字段内" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "057c1d2c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n" + ], + "text/plain": [] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "\n" + ], + "text/plain": [] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "\n", + "\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+-----+------------------------------+------------------------------+\n", + "| idx | sentence | words |\n", + "+-----+------------------------------+------------------------------+\n", + "| 0 | This is an apple . | ['This', 'is', 'an', 'app... |\n", + "| 1 | I like apples . | ['I', 'like', 'apples', '... |\n", + "| 2 | Apples are good for our h... | ['Apples', 'are', 'good',... |\n", + "+-----+------------------------------+------------------------------+\n" + ] + } + ], + "source": [ + "dataset = DataSet(data)\n", + "dataset.apply_field(lambda sent:sent.split(), field_name='sentence', new_field_name='words')\n", + "print(dataset)" + ] + }, + { + "cell_type": "markdown", + "id": "5a9cc8b2", + "metadata": {}, + "source": [ + "`apply_more`的参数只有函数`func`,函数`func`的处理对象是`dataset`模块中的每个`instance`实例\n", + "\n", + " 要求函数`func`返回一个字典,根据字典的`key-value`确定存储在`dataset`中的字段名称与内容" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "51e2f02c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n" + ], + "text/plain": [] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "\n" + ], + "text/plain": [] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "\n", + "\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+-----+------------------------+------------------------+-----+\n", + "| idx | sentence | words | num |\n", + "+-----+------------------------+------------------------+-----+\n", + "| 0 | This is an apple . | ['This', 'is', 'an'... | 5 |\n", + "| 1 | I like apples . | ['I', 'like', 'appl... | 4 |\n", + "| 2 | Apples are good for... | ['Apples', 'are', '... | 7 |\n", + "+-----+------------------------+------------------------+-----+\n" + ] + } + ], + "source": [ + "dataset = DataSet(data)\n", + "dataset.apply_more(lambda ins:{'words': ins['sentence'].split(), 'num': len(ins['sentence'].split())})\n", + "print(dataset)" + ] + }, + { + "cell_type": "markdown", + "id": "02d2b7ef", + "metadata": {}, + "source": [ + "`apply_more`的参数只有函数`func`,函数`func`的处理对象是`dataset`模块中的每个`instance`实例\n", + "\n", + " 要求函数`func`返回一个字典,根据字典的`key-value`确定存储在`dataset`中的字段名称与内容" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "db4295d5", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n" + ], + "text/plain": [] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "\n" + ], + "text/plain": [] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "\n", + "\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+-----+------------------------+------------------------+-----+\n", + "| idx | sentence | words | num |\n", + "+-----+------------------------+------------------------+-----+\n", + "| 0 | This is an apple . | ['This', 'is', 'an'... | 5 |\n", + "| 1 | I like apples . | ['I', 'like', 'appl... | 4 |\n", + "| 2 | Apples are good for... | ['Apples', 'are', '... | 7 |\n", + "+-----+------------------------+------------------------+-----+\n" + ] + } + ], + "source": [ + "dataset = DataSet(data)\n", + "dataset.apply_field_more(lambda sent:{'words': sent.split(), 'num': len(sent.split())}, \n", + " field_name='sentence')\n", + "print(dataset)" + ] + }, + { + "cell_type": "markdown", + "id": "9c09e592", + "metadata": {}, + "source": [ + "### 1.3 延伸:instance 和 field\n", + "\n", + "在`fastNLP 0.8`中,使用`Instance`模块表示数据集`dataset`中的每条数据,被称为实例\n", + "\n", + " 构造方式类似于构造一个字典,通过键值相同的`Instance`列表,也可以初始化一个`dataset`,代码如下" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "012f537c", + "metadata": {}, + "outputs": [], + "source": [ + "from fastNLP.core.dataset import DataSet\n", + "from fastNLP.core.dataset import Instance\n", + "\n", + "dataset = DataSet([\n", + " Instance(sentence=\"This is an apple .\",\n", + " words=['This', 'is', 'an', 'apple', '.'],\n", + " num=5),\n", + " Instance(sentence=\"I like apples .\",\n", + " words=['I', 'like', 'apples', '.'],\n", + " num=4),\n", + " Instance(sentence=\"Apples are good for our health .\",\n", + " words=['Apples', 'are', 'good', 'for', 'our', 'health', '.'],\n", + " num=7),\n", + " ])" + ] + }, + { + "cell_type": "markdown", + "id": "2fafb1ef", + "metadata": {}, + "source": [ + " 通过`items`、`keys`和`values`方法,可以分别获得`dataset`的`item`列表、`key`列表、`value`列表" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "a4c1c10d", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "dict_items([('sentence', 'This is an apple .'), ('words', ['This', 'is', 'an', 'apple', '.']), ('num', 5)])\n", + "dict_keys(['sentence', 'words', 'num'])\n", + "dict_values(['This is an apple .', ['This', 'is', 'an', 'apple', '.'], 5])\n" + ] + } + ], + "source": [ + "ins = Instance(sentence=\"This is an apple .\", words=['This', 'is', 'an', 'apple', '.'], num=5)\n", + "\n", + "print(ins.items())\n", + "print(ins.keys())\n", + "print(ins.values())" + ] + }, + { + "cell_type": "markdown", + "id": "b5459a2d", + "metadata": {}, + "source": [ + " 通过`add_field`方法,可以在`Instance`实例中,通过参数`field_name`添加字段,通过参数`field`赋值" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "55376402", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+--------------------+------------------------+-----+-----+\n", + "| sentence | words | num | idx |\n", + "+--------------------+------------------------+-----+-----+\n", + "| This is an apple . | ['This', 'is', 'an'... | 5 | 0 |\n", + "+--------------------+------------------------+-----+-----+\n" + ] + } + ], + "source": [ + "ins.add_field(field_name='idx', field=0)\n", + "print(ins)" + ] + }, + { + "cell_type": "markdown", + "id": "49caaa9c", + "metadata": {}, + "source": [ + "在`fastNLP 0.8`中,使用`FieldArray`模块表示数据集`dataset`中的每条字段名(注:没有`field`类)\n", + "\n", + " 通过`get_all_fields`方法可以获取`dataset`的字段列表\n", + "\n", + " 通过`get_field_names`方法可以获取`dataset`的字段名称列表,代码如下" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "fe15f4c1", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'sentence':,\n", + " 'words': ,\n", + " 'num': }" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dataset.get_all_fields()" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "5433815c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['num', 'sentence', 'words']" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dataset.get_field_names()" + ] + }, + { + "cell_type": "markdown", + "id": "4964eeed", + "metadata": {}, + "source": [ + "其他`dataset`的基本使用:通过`in`或者`has_field`方法可以判断`dataset`的是否包含某种字段\n", + "\n", + " 通过`rename_field`方法可以更改`dataset`中的字段名称;通过`concat`方法可以实现两个`dataset`中的拼接\n", + "\n", + " 通过`len`可以统计`dataset`中的实例数目;`dataset`的全部变量与函数可以通过`dir(dataset)`查询" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "25ce5488", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "3 False\n", + "6 True\n", + "+------------------------------+------------------------------+--------+\n", + "| sentence | words | length |\n", + "+------------------------------+------------------------------+--------+\n", + "| This is an apple . | ['This', 'is', 'an', 'app... | 5 |\n", + "| I like apples . | ['I', 'like', 'apples', '... | 4 |\n", + "| Apples are good for our h... | ['Apples', 'are', 'good',... | 7 |\n", + "| This is an apple . | ['This', 'is', 'an', 'app... | 5 |\n", + "| I like apples . | ['I', 'like', 'apples', '... | 4 |\n", + "| Apples are good for our h... | ['Apples', 'are', 'good',... | 7 |\n", + "+------------------------------+------------------------------+--------+\n" + ] + } + ], + "source": [ + "print(len(dataset), dataset.has_field('length')) \n", + "if 'num' in dataset:\n", + " dataset.rename_field('num', 'length')\n", + "elif 'length' in dataset:\n", + " dataset.rename_field('length', 'num')\n", + "dataset.concat(dataset)\n", + "print(len(dataset), dataset.has_field('length')) \n", + "print(dataset) " + ] + }, + { + "cell_type": "markdown", + "id": "e30a6cd7", + "metadata": {}, + "source": [ + "## 2. vocabulary 的结构与使用\n", + "\n", + "### 2.1 vocabulary 的创建与修改\n", + "\n", + "在`fastNLP 0.8`中,使用`Vocabulary`模块表示词汇表,**`vocabulary`的核心是从单词到序号的映射**\n", + "\n", + " 可以直接通过构造函数实例化,通过查找`word2idx`属性,可以找到`vocabulary`映射对应的字典实现\n", + "\n", + " **默认补零`padding`用` `表示**,**对应序号为0**;**未知单词`unknown`用` `表示**,**对应序号1**\n", + "\n", + " 通过打印`vocabulary`可以看到词汇表中的单词列表,其中,`padding`和`unknown`不会显示" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "3515e096", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Vocabulary([]...)\n", + "{' ': 0, ' ': 1}\n", + " 0\n", + " 1\n" + ] + } + ], + "source": [ + "from fastNLP.core.vocabulary import Vocabulary\n", + "\n", + "vocab = Vocabulary()\n", + "print(vocab)\n", + "print(vocab.word2idx)\n", + "print(vocab.padding, vocab.padding_idx)\n", + "print(vocab.unknown, vocab.unknown_idx)" + ] + }, + { + "cell_type": "markdown", + "id": "640be126", + "metadata": {}, + "source": [ + "在`vocabulary`中,通过`add_word`方法或`add_word_lst`方法,可以单独或批量添加单词\n", + "\n", + " 通过`len`或`word_count`属性,可以显示`vocabulary`的单词量和每个单词添加的次数" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "88c7472a", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "5 Counter({'生活': 1, '就像': 1, '海洋': 1})\n", + "6 Counter({'生活': 1, '就像': 1, '海洋': 1, '只有': 1})\n" + ] + } + ], + "source": [ + "vocab.add_word_lst(['生活', '就像', '海洋'])\n", + "print(len(vocab), vocab.word_count)\n", + "vocab.add_word('只有')\n", + "print(len(vocab), vocab.word_count)" + ] + }, + { + "cell_type": "markdown", + "id": "f9ec8b28", + "metadata": {}, + "source": [ + " **通过`to_word`方法可以找到单词对应的序号**,**通过`to_index`方法可以找到序号对应的单词**\n", + "\n", + " 由于序号0和序号1已经被占用,所以**新加入的词的序号从2开始计数**,如`'生活'`对应2\n", + "\n", + " 通过`has_word`方法可以判断单词是否在词汇表中,没有的单词被判做` `" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "3447acde", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " 0\n", + " 1\n", + "生活 2\n", + "只有 5\n", + "彼岸 1 False\n" + ] + } + ], + "source": [ + "print(vocab.to_word(0), vocab.to_index(' '))\n", + "print(vocab.to_word(1), vocab.to_index(' '))\n", + "print(vocab.to_word(2), vocab.to_index('生活'))\n", + "print(vocab.to_word(5), vocab.to_index('只有'))\n", + "print('彼岸', vocab.to_index('彼岸'), vocab.has_word('彼岸'))" + ] + }, + { + "cell_type": "markdown", + "id": "b4e36850", + "metadata": {}, + "source": [ + "**`vocabulary`允许反复添加相同单词**,**可以通过`word_count`方法看到相应单词被添加的次数**\n", + "\n", + " 但其中没有` `和` `,`vocabulary`的全部变量与函数可以通过`dir(vocabulary)`查询" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "490b101c", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "13 Counter({'生活': 2, '就像': 2, '海洋': 2, '只有': 2, '意志': 1, '坚强的': 1, '人': 1, '才': 1, '能': 1, '到达': 1, '彼岸': 1})\n", + "彼岸 12 True\n" + ] + } + ], + "source": [ + "vocab.add_word_lst(['生活', '就像', '海洋', '只有', '意志', '坚强的', '人', '才', '能', '到达', '彼岸'])\n", + "print(len(vocab), vocab.word_count)\n", + "print('彼岸', vocab.to_index('彼岸'), vocab.has_word('彼岸'))" + ] + }, + { + "cell_type": "markdown", + "id": "23e32a63", + "metadata": {}, + "source": [ + "### 2.2 vocabulary 与 OOV 问题\n", + "\n", + "在`vocabulary`模块初始化的时候,可以通过指定`unknown`和`padding`为`None`,限制其存在\n", + "\n", + " 此时添加单词直接从0开始标号,如果遇到未知单词会直接报错,即 out of vocabulary" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "a99ff909", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'positive': 0, 'negative': 1}\n", + "ValueError: word `neutral` not in vocabulary\n" + ] + } + ], + "source": [ + "vocab = Vocabulary(unknown=None, padding=None)\n", + "\n", + "vocab.add_word_lst(['positive', 'negative'])\n", + "print(vocab.word2idx)\n", + "\n", + "try:\n", + " print(vocab.to_index('neutral'))\n", + "except ValueError:\n", + " print(\"ValueError: word `neutral` not in vocabulary\")" + ] + }, + { + "cell_type": "markdown", + "id": "618da6bd", + "metadata": {}, + "source": [ + " 相应的,如果只指定其中的`unknown`,则编号会后移一个,同时遇到未知单词全部当做` `" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "432f74c1", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{' ': 0, 'positive': 1, 'negative': 2}\n", + "0 \n" + ] + } + ], + "source": [ + "vocab = Vocabulary(unknown=' ', padding=None)\n", + "\n", + "vocab.add_word_lst(['positive', 'negative'])\n", + "print(vocab.word2idx)\n", + "\n", + "print(vocab.to_index('neutral'), vocab.to_word(vocab.to_index('neutral')))" + ] + }, + { + "cell_type": "markdown", + "id": "b6263f73", + "metadata": {}, + "source": [ + "## 3 dataset 和 vocabulary 的组合使用\n", + " \n", + "### 3.1 从 dataframe 中加载 dataset\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "id": "89059713", + "metadata": {}, + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3dbd985d", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4f634586", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "5ba13989", + "metadata": {}, + "source": [ + "### 3.2 从 dataset 中获取 vocabulary" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a2de615b", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5f5eed18", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.4" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/tutorials/figures/T0-fig-trainer-and-evaluator.png b/tutorials/figures/T0-fig-trainer-and-evaluator.png index a98ab83b48b29a07ba450f077a95fc5fcf5a8659..6e95650decb06472515c89f5ab7d51cda1f30499 100644 GIT binary patch literal 100764 zcmV+W{{#SuP) zRrnSboRvsRU3Db-acRa%t2X`|Fo^mX5l2T#+KSJ7vFzZCkc4f($OLRIHg|o`-g{|n=&*sq;Nn00uX=z1Rwwb2tWV=5P$##lAFM| z eToceI0WlRQt{-BO8=s;bNe%(` zApijgKp++fAdh3=DPRKxAOL|N35Y7befzfYI`RD8AUmQN1Y&`}?6t9A1vWqc0uX>e z(h@)(C+(xhaR@*l?g{9s_@?W)b?er|xc3PMlA3_Lr6rJ@)Ch1M0uX=z1fog+c^p;z z3=RPZKp TE 2)8m zcW0!{h@8WW1OW&@00Iz50s>5~PJ)Mwix7YS1VT=r|8V~D!@U-|?d|Vr*y*FDmA20A z`v*rEM~ty`C<_*4XQ&lLqgL!3t% {f8~n3w}UaLI45~fB*zy zlR#>0nuS#mfB*y_5ZeT1<#ab@FIOD !0B&NXSS zD@AFyXN#b 7%E2a{Uf% bSr6}SCox|H0#MJ9tidhmJK|4wUnW_^R!o6ic?3d Fdg`sCK(IqPBOdDYyiS@}QWPVRO`;%C^-h z_6=r*oV8}d&>HtP5^%1c?fQ~JWwmgGuM*sw`o792?mYca!}86`UY_OHo)ahp-+fXF z0SG_<0uYE30?6Yyc~F=M0SG`K<_P38byg}>2M+WXJ43q*N}INiHFj#%ONjtiH8yuE zd9{^KDT8e?5&Fd0*Bobz<~g}abB#ZRoU^VrGrRuqx}t~l`fcksS1+g>a>lm@e=9m) z4=Een4WG!&XD_uccl!^otm$))(+-NrtX@#+H|{;$r;jsH!Ur7{%MSH46-5f^uoY=l z`?i!SX=vkNB%DD20uX>eau7fsC&zQfO9(&!0^uMaG30&W5pS~I*gNKIc0od{qK$Ji z700pH9Eu{-xfkSaTDr(tMU7f7S=ay0O55&+$9+u9&RX-VV~xl^=j!5;=eIbF;o9G* z?k+g!KC9UnS%ma5yK$vt&uLYZf`g}*{I;sK%T~7OP+k6sXZ2~`y*qcS{RGVC)NlJ0 zJ&0Yhy=h1t%2SZHt* G9LtaQK#ZXC=r#+<-F( zKmY;|fI$2bKpw~Mv%_)-KmY;>K|rPl`&frO>YQYm-QDE!UsZk0_PNUQ?#pFmo^a ^jVY$c>hQ>(G0fpR&NG+z zblniOc1&G@>-+GGrYdT@SLC#oRm-D^D<&+7ptJN2i)=%uZCWi=6RN^Ex8R_jkxR{b zU6(B(Un5@XCO*ww_q-;a=DJGe=dP`NNSj1m+-X0PZ>vbr6s&pKuvXQdI(79UOQ4r; zey`dyBbRYItS3Du1{Kp1Zi!mA^{0`YE3C}v90Cx400d%<0P;B2o(T3p00Iz*Z30@R zXd@-HTVT_N4A#PuOG7yU+hcmO0jt{g++f#zPX#VQw6WP%R)4&;RXMdRzizGl*`|!a z9W{M UX*0d-J^mrM<+ zmk}Dt)=e)f>$W>njvE!bYTjsD z{} z2nPW*vvIN3u}I$o3q51J?jgtaW6iQO*UviM;H)#IH*3wc>B@?0l5_u{nk8G4b~z(V z71q;wNvrJ-9a!F)Q@vrYA{nqZ=hs$to^EQ}DLW54*AF`!eR bGukErrUTe3N6b-iR+`UY`Ca_gHo+mq(2^*&nfB*y_kOTyf$4T&z zaS;L#fIy@ONIoi6S-DomsyigvDve-lsI3q=y1ClW#_C?mr_>;DkvhXU#a8EYiz96> zsE#g~P`$5M*;!ZJt*n);r_{Zm7PTpAlv{S9>e~NK?-~iNswu2 HtC$~U&wbaW}1YiqYOsTr_~haOjRYiG|<@@!>gOCKsNGNh(!Qnwcl3B|9= z&Q$iF?NvtFQOW%a0(~{L?zoq!UPGt_89A~7xm2c+=U2QpyeC#>eeK+8TU}3XpR%Cr zVCM#=Rr`cTAp{@*0SF{E0pxLFKVQ6q00bZqAp&}!Ro$3Zm4%yA_Ln&tl&yAI5**5z z)h1_5apV4;hL;aiAD^p>x?YJP7ug(kdv<=^d$rGMVs*G(R>tfcTiIT9YH?46rsSRT zqO~oWrC!$Kxp_6+>TXraJFVTBWuD>jo(fxs=>HPs4YkvZ;&t=wDb74z1qaRRpVhS9 zP3v~rSJt#vA6H6?^pLx>QIm=}vx<4IZO)L<&qzis?-||da6XQ~2FWF6t2FQY?4y=f zkvu8K{2q0&u``yQS^xNw`u&?*pEQEuUTr9V00bZa0SF{I0pxL_KVkfX00bZq2?C}- zt11h(Jhgszc7C78woXrZ>B|~f#H;R*WIi$%y7o6RmulyOz3p$Tlw{YovV%)!9avvi zZCBRTmO8X)%xZ2eNg1t%aBV}Khx7AAs29{%FR5}Rooaizwb`yT+g-z%W+^*^-Wd;- z<+irIIasQ6cje~pb+^B5y=3z$I4JSqcBfsM6knng4eprJxGdj2-?dsrmhUzN5I@hD zm7}z3lboIXn|^5D2>9HVsoPIdG`+Fsx@%{bSw%S#OV1aQwPkC&rQfuwhO$;Y^L9w* z!<$^-6ao-{00bZq(*%&mG5vTj4gwH>KztDBmq2U5reRH$mMwFX<**;9SeiCUU~@Q? zv=v` rCYTM>&mqc{U zOji3Dj+CmqJt>>iNzrnoRaF;M+jg&1)HGdgQQZEX*N)3JORoG?E_<_7?JWz2y*8uL zx^>mE_%r7zo3iXsPg9Y1)ZHubwU1TS8lMFo+a3EH+KfvA=~|tP;=Q%q*?#7w`|O26 z2tWV=5P(1;5g3<9&fp6KAOHafM1_EaWV>vOTrpD7T@u1oW$I98ZjYqA+9}d8REJ2! zEso9&n&g)A4NYrQZQR>_xMKO{Wyf=6ezj8@t9vQWQZmx2wr?2f+@kMVJZyxlA65!n zdRU#GoL9TVWxt{nEve7#>l&`$YNySYHj-4kN<;j!WNCq7Kh`#SuY(O$t%}6ShrgAO zjj494dt5#5Ev? AF^_&abOz58+cY4ZtY`AOHafKp=(*Adh4C z;b0mBAOL|lAfSrjWwORtlVmQLsxAXoWvZmP?krPkHs`PJaqW0Cc9+teI~Yq({XK0v z?fJ_qvTfZ;^_HQ1#gb6UHDP#5r;#-}!$^yzk3QIT=# dSzgwyO$xRz=k@hi5isQK#N3b$vRVS?{x0Ej+t*|EZknEuGG# z#m))C+SKb2(m1O&4{cXt&O7QGmx&V2%~kqE%xl9)WHn!n$__pLjx1fyS0a QX+uw8G%>!HWTh+~|a|(~Hvn1;_Qj5EHIeeu)(`=an(3owPT->GWv=II9ZO$M70SG_<0tre0d7PjR7PlY( z0SJVZfVS#Y)njUQXjMMRY0362>Q1>{LQZxPYTD;L-B)r}c`oAhVX``q8p-v2i1wEK zndImnY =eo9U&4jzite-KzXs=s2(}|BPyn?w74{NZXvLvr|zOvcux` z#eLQJ71f?27I+r8t|h~^ MVFRUFM3e)n1o^V zL*$=!^4mkl-cwHXWS4eoDq1b;Kch-(OUJA-TkeBiHGA8894C&wCIcKl)zdBOgf&5E zX}4Z=kK)(%cQi{7RdQc<>KZbq>iM1qb(VOaM8Ai&yTrU2`WA&OLDYi!PMdcK*WE5F zsktO|mdxeu(;8;x+2+>UOG{<$cZNs2H>b&7kRsEYm9m`uZhJ>dtk}_i_O(N26hUfN z9anNQ*BbHjqMRycRJ?VW#K66?g=G|*yclfL78w8b(1B(}@e!iWC~n&B?jlzZfB*y_ z0D*)ifILp<$BT0ifB*!-Kp;yN$J%B)gNhmIMCFq0>fGQRhYqyrg3WEv%)DH=o?B+l z7o}#acB|y~B180^ORSnJoj9 B75G*|UFPb- 3(D^IcQh(9Nw-QX{ArjRh}#@9d)|0x^=U% z($?B6VPO+G3C{1xmqH0O&n>f;?k&=@cDuUQer6RFH_1PBJLt3O7Z!exG}*m5MRJ%) zZ?;mCZ1&rL8xVj11Rwx`#3qn3G&Gdh9^xGYAOL}cByjuo?VC4mUb%AR{Q2{PgM;VJ zox6DP;xk2864F_mN)iG$?^!*5{P>iVlqB&NHz5E42tXj#2#~ot)}9FVKmY;|fB*y_ z009U<00IzzKokfdkD~ycAt3+(2tWV=5P$##AOHafKp@r#Adh41iC_-|AOHafKmY;| zfB*y_009U@fdKM23eXu60uX=z1Rwwb2tWV=5P$##VvPXuIM$vB_CNpv5P$##AOHaf zKmY;|fIt)oAdjN}ogpCr0SG_<0uX=z1Rwwb2tXj#2q2GR?TKIy1Rwwb2tWV=5P$## zAOHafM1cVEI111i5&{r_00bZa0SG_<0uX=z1Y(T<@;KI>2=+h#0uX=z1Rwwb2tWV= z5P(1w2q2H60G%Nr009U<00Izz00bZa0SG`K)(9YvW9^Ax4+J0p0SG_<0uX=z1Rwwb z2t ~zfB*y_009U<00Izz00d%<0P;B2o(T3p00Iz*K>~wq>+AC8RHV$Q z$lo~_gZ5!k1PJu*tdloD%AC6V^*y~27>^+!009U<00I#wfIN;kat4F|1RxM^1lrbb zUS{v>@@=+DIj`?=-tRwLv0QXiT|>X`2EI$%?Yi{RTJ=;Uf)o!0nOMZq*JW?aUVa#b z?E9TeDFh$@0SLr1fz)_59@`-R0SG`K`~> z(5^F0r4~*zX6GqNmooQ3b%?Zuxr)-Q 7 zALuWx@_awU=Ci;m2tWV=5P*PH0?1>lq^Ji02tXj23FOr-@zTah@6O$-HqI?O*ifw9 z?WxeT@ml+qrlR;&wjp@ViA*LVXI*V(b4>^+(FFt`009U W;VUMHQQK+tSD{k)r4LtrV>SwiN|VTMZ2k4 z#;ly-tF#9f$VKKt@437Eht&*W%MZJaINWfQGpojo(v8*I{>kWztG$ E zMZuG?Y>ZXEsRscFKmY;|h*tv0<9K~?*bM;)Kp^S_N}ey11;dK06V{K6;!QSn$#Gux z@XYFx?OW=lg1ylY!_JAvw#ud=S3~t@PSfe8p?$?!T3N~VrlHdtyqC82zS*s22 _MxCE50oc|z-O_;f?mW<}MdNh{+5ncYNX;>jv2M&rE^`k8 z5P$##AdmnAkjDw|5ODzl5P(4V2n@Ep+$xIHcb2S-;!ai5+DcsGmu%lKbh@c?&9FR{ zJX=-!D%UECGnCqYcx6qWOu%+*H${tG%}4#2^?0r($jhE`lh&iQGb)7A7^71kC!>+k z9qHQtjw%21;DP-zS-l`Q*TzC7U}Lm|Va@f2+n8VN 5t+5Q1)6^+(=8k2{?G;rbwhIorqQn7r>Xe =)oqXi+ri7_E gt33p6%v?2$&jA4lKmY;|NGt+u?37r~6K@~@0SJVOfEtY~*3xKg zu9lU )M}Lhe!!RaB2oODvkq3bp z5P$##Vv|5xRkZ{;6;(!#n0oY4 zq^tbauG}(Ny&U8kU5m!F+r{Rt+=BWBTlgZnS!+ty)-*OBI=oQnkaT6G-WyqsPQ+DX z%w$4ojLWDb|EbI4o32Ad^0aBwdV71%oH>)^WN;q>(Is%#U3We5$RlC{Iyt%zA~r`y z9>?Z$!72zq00Id^pr=9vt%OE9^(Dt@?&$aCG*;)=DS<0w)AmKhCBbA1vuaH5iBsAR zQXSPVFRBVE$+orUm-CcOX|}gkOEA_xreN%t$%wrnGsc?l30_OIv3MxK ttk|K}e;Xy^(MkZHBnmFS@00Iz5CIW*E%Nu1c-@Mvq zO)=P aAvxInoQx61M#kAq zsEjeJO7auY#u7OeRea^jl}|tY^xU~~UwrXJk~6`52*d~h{R^xZF$ObYiU85$n0g!- z0|5v?Ai)SothlMl+ovMi&}rG%DDcCXFf8zfYKwr3(L eToWLA9M_Kz;~@Y6 z2t `iN;v!9b0u~lRGwIti-mYk1B zKv&4uu3Zz6Ecv-ctjkRZKmY;|h%y19$5DO&3=aVaKp@r$WE5|*wJx)FEX$YlS~5*~ zOJ@vdxiCU&x2LFy#MC3tRvD`8tn?0@uX-9S=S60eH-ffoOz+M*HT}4L aS{R$h-U&skK_62VLJpM0D*`QDA~T{pe-{mB4fqMAd<7% zzNIsaNx4)<^KuIgc5VoZ0uP*{Wn(hsTLZ_wF(ncU+`71LA;MTc;@%S+fB*y_kkABD z l3uuQVe#U{@~hg{=L*6n$797y2*etJS+iyp78Z(C rj`}0O00=+;0uX=z1Rwwb2tWV= z5Qshj jz4gm;200J>V0C^k}j{zef009U<00PNFz>vfujOAP$zkAmFsrQwp zq@*Md1U!WR1Rwx`7$kr^j=_h5Nf3Yl1Rwx`L?hrWi46~DetF*HxlfK8r!M$HAsbjY zfdB*`0D;I8Kpsb)IU_;<0uX=z1d@Wl2$I #S4NV@sy3ef*!1bsCr_R{apJ`B 6z8KmY;|2sZ)bakvT7KLj8E0SG`Kxd?bK zJVqNQ*E;}jApijg#4Q2jaoj#S42J*&AOHaf#3TWag~w>)n0!hY1px>^00KS;r1~hM z2m%m*00bZa0SE+3z`XDnZ5%Acq-d9)pD#OmdANG()~$;dFJ8KIskgV+<5mbS|L_n0 zaOTXJQ>RXS_0?BH*ll#XN=T=oi 1^(xgfA=FMBNVns4Jjjs@ZK$Hm}kE8qm7#;!; zfB*y_kVpjdg~w>)M0%!?@#X5(t5>u`CRdwB6p@TVHUr@t0uTr*0VY?66)&Ab00Iz* z1c8*4lt>K27!a^PKo%aOjV*AZiYI~o{{FY$ep@fi%F0@>V8Qh1)AdVH$VEj(?d|QJ zZCuxnJo1Qs8txU#GD>h`jiprtoN|HWCj=m%Adh(yKmY;|h+_gGjCE}+uj9rsAt;U? zWx|+#bKKpxrxnbYF+ ^QCd_UH+Tj{KgRK zdbL2uGCE(fWQmCUJMOr{D3KFMpe3R55mJK5aI >%aWaHd? zA~i)ei%6DlXWo7HUGuG=&x082YhU|XPEL-8bT CUD9-ggq$%fLL---PnUlaKqlJeE)PXyd>jQrkZPi31y2QQlxaE6Rdpqg>v5 z`nl-RuYUEbp_0c&|JKJcYvb$JuS>&g*RD;TJXs7gj5NA6P9$J%_$%LaN|0G@$uE~K zv*iSZY_Q@40%0P6JPs3Bx`hA)AP`;xB1_~DZ7dNI`LHFDSVZ#8n>R%shj-v4?tO-9 z0~* HDB8-3bv!8i%D292I z$fc}LHYStH_X4lK{<={|RI&Vu$)&u?)N5n2E3@%|I%Rau2?QWuCV)IP)8HHe5P(2D z5zr^Kiaee+ZJMYNQ6>^?5S=VXJh>4+w$60LuF}%d;>YSRS}I@ANbmAK6eS>1L_WC7 zyHQR=Eu)RY$URxRHUy^*K&D=MlMpd1dnOxSV2u!`^=>;tNuXnyP5t7FFT8s;M7#Oc z0}ni)U&>!{vo@B(U;p~oGPhj6Ye;BwTh1W>flv`Z9*2q~{XhT$5Qr!NU75&-FcBpB zE7~~R4`7B%9vdIN!#!eL^e;+S4tW!bDwbC{ jPb tSz8NG^LHK&F)%ENII+*p!5OAMCf#NGm4MDp+b-tS4dIj@-6({Ok}pAdk6MFPlU zi=e0m0SG_<0uX=z1RxMm0%mO~Gn0+6Wz!~Oj 6IZ%gkyKn|d<|=Njd*rLaemXG>jMt~B nv5|LL 5E%mMiZu=hKmY;|fB*y_009WZ4gryl<{ E-~7hVrNNCQd%sEO zTjaV3d$C_nDmHD}G_!@Wxv_`JmDuvPzx{39FVV)Lkmt{zZ-mEX!zw+LE#`T9Bqi3J z^4Xk12tYt5fIQ}%009U<00I!OL?Hd^FIuWcB?v$uL w}1%G|SGD zCr^6psN`*nq?ML*Sw@^$WT&n?y=zLzSjLhe P)plBYM27K<^xxT)>F?LRKgMhwVSuRC1ddyWe>WqA1^dQwlyN<99*{Er8ESX#_ z6RORlkKDhxrkoqY>E#v&)hnCZ1~jOL4T*Xwa|a3w3&lG&u}{=TJQly0Ts;`8=c2tWV=5P$##AOHafKmY;|NJ0Xn=1Rhcj>`~$00bZq z41s}Py{I>11LR=v(FOwU1j@_H-3z!1JAsy#mavb(01$|C0?6Yye}I?|0SG_<0+Avx z@b9(yP{`v*A!i&2KmY;|fIvhEAde%8o53Ie0SG_<0uX=z1cU&QOx^|%fItiqVC``X zJ`_xX00bZa0SG_<0uX=z1Rwx`NE1LFN18a}K>z{}fB*y_009U<00IzzKnxN<9>?HA z!6XPk00Izz00bZa0SG_<0uYEa0pxL{i8CGqAOHafKmY;|fB*y_009WZAOYlY3_cW0 zf&c^{009U<00Izz00bZafk+cT9!Huu<3Rud5P$##AOHafKmY;|fItiqKpw~7L%}2n zKmY;|fB*y_009U<00Iz*Gy&vsq=_>g1Rwwb2tWV=5P$##AOHaf#2^9WaST2bOo9Le zAOHafKmY;|fB*y_0D(voNR9M>j0XV-KmY;|h))9Pe^e8nhGR7ZAOHafKmY=k2q2Fw zVWJWQAOHafKp_3=F9HDq5P$##AOL{`CcxzC1b(=<1_1~_00Izz00bZa0SG_<0#*qi zkFAoT9t0o&0SG_<0uX=z1Rwwb2qZ88 e z=;g8TkyQU+I`RBoC_?}OF+pJV+L$mS{6^@1g>K!tb@S#;d6nbNJMTPq^;FO4uJ8}e z2oQk4NCdw5RU0~aBtYDQ00bZafv6G)u{_p4mC8p_{g6+k6Qk-LgF^rU27%=HNUHxK zx^d&i)vH&pUArbHa-917#G&8V4H}$400L1VfIN;0b_Rt21Rwwbiv&U`kL4q&93qM3 z^Qe3(l|w#~erd8rOQ;3`2tXhN1dKmK*RNmy{PWK*U%vds7hlNVC1rdFI;RT=Kp-Rp z c~t%u$=7otjOA~U9J2OUnUNGv87CnS`vj8eZ;}2u zbdfBt)2C0DwI27~cVFy3CM<+N!V{2R$%OY22ZJCG%8i}$zy7*BzH;TtXP x#=RDXUG{+Z$+1R#*u z1VSl~g_Qo0R1~sIYm~T+d@4
r4Uc9)&a_Y1EP@SBdHw8hZK(?5TgW)&uTGhUwF(CueFb+ zw^@1|9>DYp0SNddpnv!_UZvi}ix=fpLI{4_a03Dm2tNT?ay5A}>5;+@IzC4Ty*$?c z8xR`$r_%Vug4Ga!Ktd6aKSv4W56(aU0&z${{t$^gme1wPt&78_hsg;=Kr-Y>7J!6u z31>n_AjFfa4a4{_YM|f*0uX=z1Rwx`BqX3`=ayIFBnctlG6dq3z(@7 vh6I!+lkZk%3{Fb?7f1mc~5{=4bz z#rZ>rPJHishANiJ$qN>ESED3R2_TOX^~vHF1Rwwb2tWV=Q6`{&{`U7NJj%u~JOm)% zPT=amfaCe+MGqUrB8=}{waU2UBpC>VYjSlmu!{*F+wJ+w?QQ*$v!%EFa6@}fultC- zJ0opI (@R{@<&R>4G*FvM-{+@=NK5ANN>+HUNaFlVx7+Z(3U{Q94 zT2VA=#m>>1ID71=SYDUEv&XZ4)w{Zi_K`ZtQqEM@pH;LGUCjp%?CNEt!VB@@0(ORw0F$c&g*hvyyD@vY;@DT5r8Vtsx9>2f zU>rZCD$ee{E?2Lu%0r!N(p*=H(r(WdL2LEMtnb`V |>wt09_vrR`LXeM^%`%4QYWIy-0Q=lfU4B7kceE9Q&%Ok0?% zyr=d)*ihA~Jh?>|gl&f;7G0^!et$!Im-oKe-KF$( J a%|5D z6oT(QDTM$8AOHafKmY;|h)Dti|KoprSXUR5rbW#tiJwa>{hn`s`%6ogM$L$54~#qx z;tAw5byg}>2M+WXJ43q*N}INiHFj#%4v7F)H8yuEd9{^KDT8e?5&Fd0*Bobz<~g}a zbB#ZRoU^VrGrRuqx}t~l`fcksS1+g>a>lm@e=9m)4=Een4WG!&XD_uccl!^otm$)) z(+-NrtX@#+H|{;$r;jsH!Ur7{%MSH46-5f^uoY=l`?i!SX=vkNB%DD20uX=z1Rwx` zL?rOQ-~5fND;9+;3y%}gzu zSM(ru$@Zopbtq3k-nPENY=hL$%y3y{4qw|Uhuprf&=h;OtER_KbHm|V;+>Ts|8N7& zAOHafKmY;|fB*#Ig@DW-mes|Qm|Esn5B}3X8D>vPPnX%nNf|xo;SbsIIN=`n=nf%|M`tv8 z4SQpXDY80T-!q0ee8+j_5}&RcqSlV7OK^Q3p3ziAjrWS2*0O4OG;zg*B@uL%-eHk# z=(J6%rD{S|80Quo)H8CaS+DD|CFE $d(hvU7!%Ih{iQ0uX=z z1Rwx`*dZ|e>tA2|_S=$ p(whURz6m6uWb_;C! zkilA5a%m_hV0%n&HteqUJvZ2O-&28$5N&L>mDL|_ZB ~+OR59O+X#g;U!ap>ScsRvUStT z%DU~&l;cLlu9`R6*0|@+}5w$w`qSER32;^^F>-s&uq{LiA>P1Tx)TpLiSBS~5>Nt&gUIku~*xpJyE zIP7!Py`W^br_)WFl- )D=@1;2v>OYy6E-GC=SA*ewGOm8h{}xcQ79N)- zbq(exr4HEfTD!asw(YD-k-f5Pm5$CO#y16{7{qM|KmY;|fB*y_0D(jyAj!I9PPJ@$ zJoB-~bf0AQb)q _6M9jI^VYvHscFfx4PncihWVuOZZej2u~kTq@JZ^DEvP z-V-aczIJZ4t*$4xPgziQuyX^`s(r$v5CRZ@00bZa0SF`s0a =9*^}cpa)vjjd@jBxH)BinWI73YL_L!p`2N5vQkTPB@tlJ#{E4FFCVBr zK35lYz5RnCcO7 vq~#*0fe1S4xYD zT}G%$#hh8iyw^5o$mnMzqn7uKZdY@UpMwpOOUzbj-uc<1hR;iRQjYmO>SAMki!3Fx z{_!RC`!}~f>HKQLXDbRJ009U<00Izz00feXfGkK(Dt~cSCxAR2<2%6=XjNt5mZ#S5 z&d%=>+1BYPFMSQ9P7iK%zmd7nwZD;jxm*qQw!g7bCKcPt4lbQ_V0~S+U0GXO>X0?S zdTuRA8LftJZ9|=h^YcZh7t~iTsd6QqYJ0i0*{(F(UBk&N ux_u(NqJp$>-*|<$9rNd5*-=^Mzz>+1hT|?kTORp{!NUyzOIjS2KP> z00Izz00bZa0SG_<0trn3c|5kq+b@CEf=$DkDlJ>)D9d3#P_Z;^l)&b2DrqY==n^qg zc3_gIZ^QE4?>$-SIIT}bmbuouWkcZl&L%a9v rCYTM>&S86WT%w)Bn z;Yg`EKUvwNPKuTzt*W}9+O~V8qNeF`i{ke8ymnkxHM{axx$MnSwYMx7_S%d}>(*7v z;?JC?Y|64jJxxX4QFpJz*IELt9JdXbG(HPFwmbGYv>BHK(zQAn#d~YJv;E9V_t^`D z5P$##AOHafKmY;|fIxx~7?)uFMA#h($#&TmxniVRhN>D>rVe%HswuB_j-G4EvcVz| zw>UaCXp&pbH#Du$g2wHKCEM1r 3}k6=%la|dIo(%;jz)1JS)BHPxj zRBw^=)RIujHDP#5r#9VM?I^=Yi=}rv*mmfY(%rFaPF=-L=|Lo=A(gcXYA{?*I<|&V z*y}@Ecr9AA*22&-!(1kaYbmVjD%Kxv>z6s_hgZtPa=WMEbsti)h}rY=8+#U1dVXc# zswWEhpiOC(?==F>yzT0OpAdim1Rwwb2tWV=5P(435@2$5(2p*yWcvok^MfK;+tyde z+~z#l5XjJ_(yOYFXH`@kb9iQB7Io^qQrD*$na(}eeB3;{b^ocH>MfnlrNzz(!`jsA z5z;uTHV ~f?pGnUAzY-?1zW$5vDWa)Cg5}8z0B5vO~aH#ve zr4ks=Sy!8xZR|oUiN};2^}7c5L(R5bWRtSq{+ >U3}02aas~{u@hPje8fpJ);By5Ev5y k?Jv2LY9f{L0hT{)*wbZJ@j zq6bBfNf=f?ME+?fzddy9J>^tSc4?=kqSdngGpe+ 9ZSSQCVncI#F5D1L2!N3#S`CHHlwt|4=(p6_W;XNmVo^m}N#OU$dGZ&An+L@lWA zw0Vbc-R-iHnoCk=$z1L}tzl-KZEn52v{dGPXL!VWbDHc0DKfoTDa+aKws*9|iXHuD zUpsV05u|q2aV0l%tr0&j%BgZj#aow24BR_gSVpnQi@`Q+f$?t-9cWe*A0hgT;->BH zE^-9{2t<`YUPkGX1^+d5{2gLN+O+%5T|V8_e;}$BF*pPu5bFd6cCA>|a#UH|Ua{I+ z9}l!Qwj4d$vO?K|LXPzZiG2`=ECJ+k0KBtgajb2&GpLxMPE;=0uFehKap*v+F4){U z%goD_>$zp-d{Jt)YPU*$FET{$xx}iu(uo7hY82@?M }IlQeu$0HKkD}i5Swp-V#o9;)(l7n_d&*AO5kyiTTT;<8q z(ov@?t6MiKD{ZaK5*9Y0lS%A5@}*Eh&2!7_rF)C?tlh5ewVzo<#ZB^0-46P!`h|tx zBTaU1PLUjD(wnW+B%A#<;06Q|jKFvP;Du=uXIgaX*r|@FYtcn>3v_L)+bow+H_0MB zszD%L2o!ERd2*X(tjNkoYmdf@-Tv%6vQc$nam`z=dTV28lfL@ZJr0SNx2#%`?Wc;r zo+*a_1QMD6@;IQ!o73beS<`e$rbH^(s80P|6OhfO%Id0J)1~uN&4cY-s+MGUYGWz$ zGQigaa{2DSOPyw|u~qpV# -7x@NxQ90Cx4fExiV zaIA WQzpKc%hIZ?d3kX0UIS7!sIys&*UP1r@5Qt|2KmN~` zE_^QO_tZnA@<04i-?CgU;1vQ8fPk66z^?DB(eLs-qlw=1)jz0NtSG8L9x!*nIRqe( z!~~GXN&N6}9Rd(YRsx@0{hg>y
BLnU*BzP+~Hy%-xfg`&%x@xXivCFffd$SN-9cfa< z@#2~a3yH-Hf!rj O0__YRf#9hd27r9))uGH%tFfUsLTEJofkh z=Y_IIsvf!T8 rY z@2)6;K>QGJF6xzu%WrKfOjqqzH%O8M(LNUNw$#>25Vw5K544)jgkNEop-y$Y#In>y zAFGd%0|F3m5nyt)iv&L*009U dLApQspw7;&+TXtz<@gTi$n{xrLkNL^6{MV_XB~^4~x$5xy{R8Tca2*5v z?@QN C5hg@*a)cc@!ZeI+A3fN|0@z7jxfszLw)iA{jX z)rtLl@eTqIfIxT&$Xex&-k-^AYKh89^i>~h)>Nm|G{!#lS>Ffe-}ji V~HH$Wu zY7*L&OY^L3nYk_hj2?`M(?-b%CwkCW^zE-tcS+W3nFw8w`J_IOyvn7yXSp=A^x&nB zw*Bw_X7ntoSpNz@Ud2J_%DClyViARRLrNeJF9dY$d9?P?c`|J}CXXP3$Kr=3+>fgA zzA!x|-NGmcKp=7ih#p6dH6uX)0uV?r0wM?{kF>67MLNo*?x09ekIB;i>+p9yw6WBb zhUQI`t#8F_1*2%=H;(^A7qlXV`+xVI(dxb#^Nn*kSv0pmzmz6sZ7hX{-utmpQ`Sx! z=iVpQQFynd1OgC%00bZaffyk`^f*Qy1ZF@00uYEZ0wN~O>QSu!-IX)ObZbduZN;A( zH?JAh?w&H+I3N3o#Es3d=yO-jWGjn&c5BG;^RBIxjcSrG>|2ji>X(vN%qaIb2?+|1 zKDmTI3=+_ztTJhOv<-!$Z2M71zbuNjZbUFMvaR<{O$b0Bt_UEH 4OoYCA^K+j)%gkz{ zeEOujWD2)&>2adZ&GsnNFM~kgvmXi}5aR^2MY=}=6`zrGO1DtU|5cc7b>QG;WLxc> zdJup>d=Wq%$Jg`1S_nV@0 z{}NH7ATjg1ssvF4gF8$8ww!yX7kmcWsX^H#OE4cW44p0mI- zo4Rn@TQ%=LT6?smc2$c 1kB&8rppBE5j8)g$ z)^A>B_fxsuo?`0|=~dskp(>-NVoqbTr-UACSiZTs+toa`%(1UHnhI@ngI%VM>1T|2 zt@_f}WpB(r9&P?(qDo^3#3%s?9UC*2uim)gks3PcMw{0p&$#pMsM~`95Qq|i!fhu{ zZnHRcdg1DA^3Q*5k Q!yb1%(wgi(6`s)_#9i(da3}jx^PZ$}g|9qNK-c z867|X0&zfK-1RFT$AOtKYhwT5t*SOIIM~@Vbh^nibeu6ePqlpRgBkLgwlG({$eAC* z;pMn9SS329BWukDd2mCWm20J&?(PGU>XHKj5C|y&a|-J(Zd~!```#Jp9wiaJloVo; zcUm7bZQ6Yz<|AwX!$AN7p(c>N`Uf?O6-5=u10(i5uxo`nqnyz3h?KYqfg~f4I`tms zthTIg{LnbJ2tg)Yo9A8MzJ2@V&6`)QTseRK{NUi=xpU_(UcC6&*E~NAS?oNHs^!%# zDNzM*5Jy_ozNRX*ofc3HqJy|>5_?`} S{T0aYNsE=#0qAKjR7(qF=` zfnDF%BFB41k1;1TOq_>6k`YK1Rh(olN8H`q+1U{vb4&xqoxx-B*4a2~{#-@rcu%6o zL4MN_3M1$P0*OdKq-H_pllt0YdHu78D<1#Kx5d#>vslX>OaAH oO%|LgE~cl_x--9niME XbXYR5%5l cJ_O(s31dc^MOW^n|f9g3fho}t!2qX%Daf#wcO!|>AD`(iQ zvDl{Hh zBNJN7=?wx9@F4L1;M+!ts8A8ThVK1;Km56ID~cy?9RGnq%|fAuxjG&b)a&Lh>fzHXUa(k~l_T0xoL)Kp}YC|2so%4jPF_rBRJ zX}Xo}*4NsLOH4xy4>snrQC*f1taxOl&X|p*0|-E16axS7%bNf8$F*Ncdqj`W>a`{6 zd+bz)#Fl^m{>MgXAO72tNn8H?_u{{wHT6ETk;cek?YYaRjZ01-5LE(!q|u71q5cPt zkPD)a3;h_8zIxjT$;JFMq8I`YNPGgw Py!9?^ELF2Iikljg9x-75JH2aUBPcB=cK4~* z+6PODw6xe6X(ih?IHj_)Z!2|1FvI;;MserqV)vpDURiNjhO^?4l{zlVGm7`tc4ybL zF3WFq?ZxG~#ZL%8AVdT#itrGP7GyVZVPufL(F_6*fB*y_0D%z+u=aRFJXUTx2CdWz zw$9*tvMX|KZmGwL<&1~Qv~8laZquq7%GT!gHQP4J;^h40_J;OBkCn+HCN0zn*2WOG zv*NN0X~iQeb }B<~Or^V{+O|1+PMxP!R_cV%qzH6n#Um?qbW{5eudM0lvXwd1 zC%d7_ ;Pt*W{}+V`9YUjSL39^8FEHXJe^ z{qM9&RC&RyEK^}tQE}Dw4WipcC+8^=OtyPxmbOyI)MZpo18`aFv*MAJI!gZ;bs70m znXJwM0SG_<0uYE0fzQwW{A641$G=>8?ZR+^_Xv&6Fc5$M1R&r=AocPm$8KKxRLZB` zvnX}qOs@(Qj7UJs=QLuCG2TooeKNDUyRW*+{-A65ac}$Kl{PIU*ivoZsQ$whRc97f zFDWfb)1_TjkxadA?GpWL99HTWl}A0%mtN #Akc14v2~a_Zq1$}d7 V>ith&IsI??D3?FnCn9;~gU`>%`m2<26T>|;{X+l(5P*O; z0Ww#6Gl{j5w5oku9$deBtG!Rpm96AvuC0EyNl#KO#!AX%yRxIcySdxB^>JQqL0R>Z zDx-qMI+pzo_r^|Y+O3gYw&;-+GM2rjA_NkK0Flgud6YPk00gGY`R4t9(*C=5{#Jys zxO4l)#q;mhUHaf(C5$|I)?*3aATB@v0uYEV0?6a2KCdF%&}o|m3$%@zw)?FpYipb2 zpWplH4J&m7(z$j2k;y@_H1PEqY|#>)sQmWIv~cWaKhEXHFpi0SG`K0t6;Zoqz8i z@0A#`h~%4}e L+@3;_WMKmY zfMt}r= eauN9Wy*+1-|KrF$-}}{-_by!JvyL?X_&0lf-ZBcK z-h9?qR~p8cPcEGJ$vMX><`Uz4{G@wyd90U6Jo$@Hekl{JXJ$V?Zo+h<8Yd8d00bZq zJ_5+&v9Zl4-ehZCW_K X&1bTPYWvjwiJG}Roj;JjR1_1~_AXx}p zy?9d3doqH m*L@C1;^*W&dE9>*+`0oCp!iTq&jEx8F0Js$h>AAObV*vFuU zFcHXFvtejWnEIw$2tWV=5b#al-i0ggy8kiX_gtlurl-43J%7ri>rwaGh}q^dGyh`z zjK!WVY1bDAUXkS0=3CR|ed|kK+Yq-~Jq;Y$)znz~{u6J#x;owLme={fuEv(5QhK!I z_4bO@ekxn;&8z#^EEw3eVwHHk*pJ7t%VeNkp4QQp70RAhw-v@FTdab>SO_4G$3l;` z5P$##AOHaf1WZ7*>zy-#&)6Z&M^L|`S`(S(LqkJ8ExBXr1Cvs|>~ZVbg||O>`+r>j z>^-A=;+Gz|`{A02cRga1#NkQ*8?~zbdty}6(^prPzb;yFarqNP>Hcb4?#*8ZF;#wK z m@a@yxG$_x{J* zlT90&cqGH=z^?C0;8-c&6VJjjef1A&WQ~9-kOz|Cq2XgP5kMX%)6>RR2tWV=5P$## zVu^sUW0UN1eE*-cOWfEfiGrDG&LuTPme;YuT?4t*TOnzh2292t+30G%szoh6TKlN0 zK>KM<>NH%}S;c%)>vOoq=)GwTMzl?>q4lVaqo=-d<^xlksWyZ^=hTrVRU9v_sqnLI zci7{QF%hpv#u5w@Lm)SirAvF~@scnEQm5XtNOvZ6;>?8c3P&IS0SG_<0uX>e>=V#3 zZ{0oVOTQoe+|;5E)l^ZV9wMc5rRuCHS(;Wo`o8}~w4-(y!U~pcd;g7%D_V4KkG9k{ zWh?Ki%cSKHXErW58OD@TN8V7sG$^keX qDBpAPq%jTHxoTDloz+ghwWr*Dl5OEOy@Qh{_mr#cCH<7EK>KNyp2KzD za*n39FdxG;M(xdlZAQ;WMH{Pz>BF|v)@oP!5byU781+Ja;#9{={L9H $JppXqLoIn5q5P*P* zK>F&+@>)r`C26+Q)KSKvPPaBLIDr5JAdv6`kjDxCh;cAs35X=VbouJ#E7vYxzV`Xm z>puOQcGvx>_k1%oHC5y>+Sn%|3LyXi2tYvH 4e$ z+BA{Jdh~eY`rL&81Rwx`q$QxMoTIO|9~qFtKZe33>RwGPt5$5>b!52OfUHyAxMHK% z?mk-NQaM`teRF01osV*7wB7= nbz3)5`+^}9LyX2m#t1JKg2$nFjPwy>1X3@5 za_r`{PsJ+P_c(Rp%osBdb07c#-vlmy;d?f @+5P*OW0;=|W zeN~I>I<$E4V&&*jb^9Uh(1fsKSkWr!t6zO9V^>q->n%nlS*84hs-azNhJT7Q+mr29 zclci5XQTEOkZpmFACeZjK9)fJz-r(6IIvMhWg^{$3(LT+M)@woeLJYYtfw{vVv#_~ z+yDAlsO0hO+qZAtym{rymGkG%4-O8VJ9qBl#f#4rU5Q1%u?Yh4OkjkC#~#{v!h{LQ zw(3~K@U2_7u3o(=e}6vt n{1E6l;%jVAl!>35(M4NV+w!YvZG}ngsH=5o->_lRf@m$CD4Lt$Li> zG#Ma{9FRF>ci(-t7%YE_;>hf9oBIB<&wjjTkBst_-MjBywJO}h#ccn)Ct~)|U>F4a z67Ux~MjM-v$rpC=@l-#|<(xwR0uX?JJAr}r*VS-wd8KDOGrcH#v3pgn#!Mi6^$%)< zs=6k7V9cFGs{_&aTB`G!3LldOqGc50LLejr$Xp!~jC2Blh!XI*@EC1uJOe`#>k3)Q zuU)%#^VW@PH?J9WIDr5JqC#NG#HsQd8kM0LbW{Q@jT@I_$W~72dQHi=)%1OdDa-uX zCyJb9`W;@!MnDzFuS>YT_R) #1G}_0M){r?+~F&-Bp59b2_TOX@u}id zq7(3r9;1!DpSkf7Tu#oOJ$uibFQ2~ffp;}ZAOL|#5?FZOqDT&xpksMwZyJlE+KlST za>=!&9Bo`yuZvhY~`ncYSkn`s#5My77##JI%?1Rwwb2)Gd_+;;M +!0V8^hHXh;0>Ct1f@d${x1%YT0(0@InH9F%$00Izz00c%LfIJ=n z4!0l>a|Dcq$7thGpN;Vm+&CGv2^Am!0SG_<0uX=z1d^Em@;I5FKEB5v0X=k#Hn#ZW zh#p%6MKuUO00Izz00bZa0U?k&^&aOI3#k)lhL8y1nh?UID+m|_WZ^N|*r34)1Rwwb z2tWV=5P$##LP#Jr>l;4|VRzD%5w4LFNsSZQ&gl&TNlxI#&^@=O=gpWgW6G2%6DLlb zFku48nUnl2f%_1E00bZa0SG_<0-+)hmW`d{^LlD(s(f&l !F&1qspXTqp z^UmA1Z;L{f*P)@I2spzK5J)fr`Y)9H5>1*kNtef>kkQ5o_LOl40uX=z1Rwwb2tXi4 z2!v7|>(i=58_S$e`2;VLSVZ#8n>R%s$B4I>0fD$9Fn;`a`JEDZEWcBtkS9-`EWcJF zn3+=@caIW-ApijgKmY;|fB*zyoIoh$vAC*F1QmHaZQ3;X1TUZFWoEVLWI19S1m-~? z)(FV=O=6P#PKiPmNh}IkezW96)H2#Q)*cr2KmY;|fB*y_009Uj0D(}-WBt>-e3X|D z@%k&;I04=wxDZ_eqJ-tpW61I 6eUC+K zU yAbB)a&T0;N=5P$##AOL|xBOuyX_Vt)O zd$w#}KV{04L~{>+AP`ps^xZ&Yhn={x8e=0w0C^lC& (8D&d;a|S3l}aVAqQNBKokk+-%m}PIC0vvX)|ZeoH1jDd|eeqdl)*F3GmK{<)?#f z5P(3u5cu%NPc47x=)*5`?EOx9kT!R`u=2TAe!b|Kb=zJle;~*{Xa)fY#2f+RbNQWj z-udpk@7}s~E9OkZAP6Kn0r@qQuc+j=PgJq|Cf>Ml pw2q2Gxp+*}B zKmY RX&~Hym|BX z@l5Ea001BWNkl )-j{8T50}y~fVh|{JY45u)C59__0RadoqKD;>h_QSemlOFoF4~w> zK)f>`5Jdud76AEW6rD@}If@S=#)n28$M^%nJP1Gl0uX=z1mco_sABmDE}zA9kxb|~ zE}tSsClCSkD=Sy3JpDX@oWqrn5kMY?3?&^w00PNG;KPppd+(24{OK{>=fw{zM?Jmo zc;S)fUeS|vec18BCRtjnR$lz{3-z1KON+H?=C)7&=)+9~=7NEiX9{*4Q+(z9a^CW2 zVj50S7A=1Ix%y27>E<34i?+G7;Q|5>2#|n${+1S^kmVq593VWZLm*rPbYZOjdWLHZ z`i*A-sZ;M+q}!i5ab`R_g6$B100bgNp!3E1|N39dqa9VVYWX=jUwrDX|HTl`M}PWK zfkO!>!L_<9d50`ZK6LoQ@BG#M=21R4{BNq{ex}eQr#)>ucJ!yu6*&B))E={KW@|Wy z00g`U=pV#I8}nJ*iwy-3hz }h8fB*y{PeAr? z(zNm7bwBEO``r)Ke{CIq_pQY~E&26J1*$e)^y1&OsWtb#pjP|!OF!x~Y8SlZ?Bv~! zb f^R-8r^ohpeBdh4et!7YepQx#>znzmVwY{t=)BC9+{RJ;=RW &J)j z5P(3W34GA!kRca6S)j??(MMnO;=UIPO*5i1GW~^!N9-%V_!+sc&aXDA=`*X%mUx$F zmG6J_NeLh;j=tfxdM6>W&9I0Q2tWV=5P$##AQ0aKNX-@B&kyS%0D%Y-IO$O5GiPU- z6z_-@c-BlWf91pS5nK4aS@7JtMX&5o=U4w#xu(qZnbi+3EgrT+x9!-A%fI%b?@l~Q zLuH#sw_HL10uX=z1Rwx`I3+;zI8GlNW F8|dz(k~r#=C9W0QJa!- zsiV%zR BfdB*`009U<00I#3MIiO^C&zAH`&4epzQ?H(XZor` z83Z5z0SLGVq?bSU%#Pke&IP|yJMqq{)-*!90fa$y&@LwFiN$Pr;FXMxq<)$AOHafKmY;| z@E|a*_ZQzg_R~W7Cpy{V9+wb+00bc5O`zbVeLs5fVKs&<$Kr>zt%HZtN9)DmdM#Wj zn;0KE`fFwJHy=&+HHc)!?)bYGo^hF{R(W{QGwXiTv8ljUb;=+B0SG_<0uX=z1PlTx zZ~yCKpMLanxnA`2k(u{BX58Qe0uX>eJQ5fh8oG7s*0pQbE?&HN?%cV-!NK$A&(EGc zJLi#wr!SZn49BB$*bITVC$R9oMe-XuZrr$(l$5x41_vMj0SF`zf%l(%_TxQ!#G$Y3 z-hJ)LVi=1oaWsZ5&re;qgpZwNpjx&;1b>AVH^P9}gH-KW6l5P$##AOHafKmY=< zOd!PaSVG4)Zru3di!VO^{PU| ^_|k0odqq0SG_<0uX=z1Rwwb2tWV=2|yq<>l;4|xf`O8WtO#skwe}y9YO#C z5P$##AOHafKmY;|fB*!-K_JAFtIZ~|(9ukTa|l2H0uX=z1Rwwb2tWV=5Qt?0Ax_N| z%dTP@1Rwwb2tWV=5P$##AOHafK)@dX N%XLB z6#@_l8-Wjh{L~{~yMN`62f{XjtK*IrR(|dNN1l11 b@hqWMXEO q5F_puKP6+~nT{Lfb1?BR8*4{H~*6i7HWoDQee%tvlYp=`mJnOqh<(X%# zXMq3+fB*=900=mR0Ni7zV1y75009ti3xS&LYxBxTQ)%A*&uiSG5lTP+1V8`;KmY_l zpxqGgzw%4z#ZyJ}YHYaJZf1>%f&d7BfOirIPtHh*Ceve5hCUVUol}6-AOHd&00JNY z0wCb21Oh6*m`T1dnHMvvu-pCdo@yuT0s#;J0T5sW;<7iFX9EQYfB*=900@8p2!Md| z31D%x^O-^-2!H?xfB*=900@8p2!H?xfPmK#fP3t9j|>Kb00?*jfx6-iSt%iuj!S-x zoS%I})2cekq{X|XjLa&o5xUiEmz%T_dg+?7iuK)#=jwIolp31!U4-|VlC8#iw-(k3 z%}UXtZ6>`@0RkWZ0w4eaAOHeBPXO+*&p%>J5ClNL=>$qLL!Qsb++E5AA7SaTOfI=w zUK#IJdSrJ-oZt+zjl?vl?2}K`zH9BL``M_Jgg6tS)+-9LQsSm%8|%$Z-ON30S%Nj& ztgAr}5C8!X009sH0TA#t0&tIg?TKPOAOHd`CO~I6P1{8}2F_kve5|~Vz4jI7j2@^` ztM8VQvrq0*UiZOTmQ|}PdxqgmrnsS_Xjtio#kEGG>puUG`P-w1#`5a8Y@M$1;@L60 z*0exj=Tzpm$D|mUH#a3x=xdX0LVpxN00ck)1V8`;K%iX^fP3679y2Bh0wCZt0)?B| zI_iP5_w7lJ3)e{v4G-<5QczR;iP9}QHdNOX5|^Ddm%QjB%QqJ4dnY7}rs5IfQ=0T+ zCno5-+5BF-cDWpO&dJLb&5M1BZn+S>{C$>f w%ewm0#zUY z0w4eaAOHd&;JXA6J@(yai tM)1O!09Z3Nir=maskTYJLzV5hL&EDKjm<_CF`#BQ1fvQ^F5M_B&q zmnMZME1$)rT$*FFE5pNjQ=+dURVO9M!rE_pY}3|*S`YvM5C8!X009v2Ndkx-`{ZNA zq(A@!Ttz_kEv3?mT0wz65wuVh8cB|-s+-VkTnwF*P6@i?{ME|J>QT?wpOi}$8QO~_ z(B8dv1K- zy&(?vJNeKu|Xyog=0N0w4ea zP9qTd%usf&Qr@)8LfHkaDcL&md6vssbtx&S^QNWD-CkV7+v;iyw`Y#bD&`fsf}Eg> z)>jwG`K}#1?wE -Z;^QiN3p`MDP zo-w|sJ9Yqa-tJFUNu}C(r%N(J {jl?CETHtHm|K1pOIHqnm28jkv*f< zX7j=J*~W*V00JNY0w4eaAOHfsO#q9lef#-hb|3%(&L -Cg%XlNDcG;$vgLe=B0T2KI5C8!X@NEKqEiEn1nqhNu^Nkxfu3Wit_Uzd+XU@=1 zk{p-#` A*x%pZ&(F`dnb5y!O-)S=4GotrT~hunI)DCr&z?OW?%(&v3w*h;Z!^H`K)`be z^u0fZ{)V=Pe~Uc#8Nf0S009utBJh1$+RwSU)bhZlP4`Tgpw*>a)FE@VFF)pI9_;>D z K-Y$HG z T~+n8=ro6 z!E$G@RT(Hodd1c@FH?#yvccX-wYk|a00ck)1V8`;K)^- ?*Nytpjr?{ba zMD*=nRb3Ld`zq6SY*cH|UAxhwETs Jz_Q?;m=LB7q{_T+|COcZ}?R2SuBCjZ&Z)k#D&v?ZG|A z&YH%?Y1GhuJw(q_HN4Glmyhn%^EO66yp&0;N$E2+@3>fxG6;YG2!H?xfPhyMATNS0 z@{sAYzpGcTl7~!tkG* WmWmce6o**>- LdUVk(o VwI=)Bm376JhF%@FYH|9ObZ6@cL-|_-gioWs9rslI( zZt~VPFVHs;+&5NiBlD=B7)F+phur2y!T=Be0T2KI5C8!u5+GlKBF41wm^@@!Urj%q zC>)|d00exG0Ni8eJX3NzNf7y3|99e7S|q&pU+1{rMb4zM&DB(sW1~#vn5z-PzZ5`L zx;@xaxAK`*R;yN1D;+4}%?DDS!tXB7j5Zzo=~(S$aZ==Mih3z9%STZ+B9OM}yBUA2 zps~b6?Aaz|dIbFYi=TdNP;4Xfs6ca6Od=1NmR`4sc~A-hAOHd&00JQ33Ia-;jXTK{ zNp^)6$OHip@EHPdkDc}?$tR>G$I3ct%11>3TP`}xc+oYlr-EanL(1-kV~S=g zer(+ZR-;6fxe#(A`Lca74u+IM4AU?NfdDqGjd(Hrt?3! z7WWq(i?~%$N|Tzs>x5{)?jyhO+weP#mdEpY6hHt3KmY_l00g|60C~vD<<+x*@gM*K zt|kEY*lC2nuDL93$31iDhApBU8)b`RRUh(l$up!%9^?J?$E$RE?S^i3ai@;#!_en$ z!`aB9hp$K@A>5rNIXo) O~I9z&8KMeSXvR-eL%ycWZNlVE_n#00@8p z2!Mcd36Oj2T!D}V0wCaf1aPpE)1Ij+|JL=JI=9oZ0>?&KmT9h)JVPGiB`;Uy#NKr) zOIFdXb4Nb> ^E z++f(W6BwYAFM5?WelNfUx}ng$v*B}2`@NMd-)_(g6(9ftAOHd&00JNY0w4eaUPQpi zeexo^VX7?zRDR%hKV9Raj%nqr=B++f5c6sK*wio`5C8!X009sH0T2KI5C8#Z5ims6 zoFx%*JeB}$vK=+>PVyB^S5|A O *(es>KmY_l00ck)1V8`;KmY`MiGY9CJ7c=tA5X7 CJjv>00JNY z0wCav1OlR-T o5qAG7^Ar 4|L;aK2wTsB`Uu6U+4G`6hOctfx6-io7ZMmJX^f^ zrErTKo!eNmeQjPDi7d_A|9M8TTU9%4B5j1uY4$@92!H?xfB*=9fX@=Z;%e`EwBk}> z#ro5i45881&xicpTCEe0xn%N 5vHmAOHd&00JNY0_~UpGFP|i;fu?6Re~tSYkDe@ z(#Nq;qI_~V=@4UO`LsDL77P$YiEE_AdQw5Rv=^5z(x&v+mQ#FDE4^rIw6gqL?62uj zb9DqnbJVzZzvX>+!2&(r$3lTTe`;0jJtnW1+ fRZ71I?naMZKY$G?=I zOL3=E%F>jg@^jSMy7_Tp1(j>Ir^GEUP01 P3Vz-X0$pZbaA~rM56ptPvi)PVfA< za3e!){+t+%!VL(300@8p2!Mbq2*5pd1y#rd0T2KIPM{=n &R)@T%%N0nmKJ)1^LXemWOGzmSl!Z z+a)&WeR#3X=~HmBz{0GQRK0sI+f9Ts;Uv6Si5YO-y7x>YlRR3i%rok)Kkw@;Nab zfEo}00T2KI5C8$E6TseMrz3?x5C8$+C6F**mkX*cXEd871&8(7q2wG hk>|-51m^+YK%Cgs%=sVDR@0gU?Yl}b7Oa5SO3TrIQ+$ 5A_;@N?l-kZj-&6k}^m@y(XP6$!Wy|Np> -62pT7BQpN%JYsmaxz_BraR=y(?;J^quT|Psz#4 z)~%)vos=$n^7czB+{{AI1848sL+0r$2n`SIWnzrer{F|^wHwy6=(hkwl8EqT`8$ZR zPd=^Vv$093%}k`4;!hNM`UfHF&0^n=99h1xkgGKmEPqZ6{ZIk{5C8!X009ti83F$* zzm#4)RYb4GhKnxK0>K~v0wB;%3D64OOmP=+M5GNz5QX;Ah|t;$kQ`d0b<_?@tF2-u zhsXRr&Y?}q4k|T2Nyh}%ef}X^xITKQdSQ9oQ1(4V>4(MqdkQVpYNfU_sr__6Z8bNc z7xL8aSunq%%HWnOdL8 jIf`{P?7s(lUJ z_Q$^MYr^emwwf8U+Y E00JNY z0wCZv0&tHVM2!HWgWxa>1VBI}P?(jG$L?w0sjvo{vN}C4q@ETBxVy}j0gH>nB_$p! znBnv(I8&g!I@*xLTQIx2iiM6J4AU(gw@0aUCXy7^n-)=*sgh$0>QMv%5C8!X009v2 zL;^_7<%v%PHh};Lv=ai#URFwfHBse)dcgc;2Tv-k5I5)QvoQ @=M_~x~{fx^J~V3^x7-aS^Yzw85)yWR+=|0 zbEq8It|{3%Lp)Adr^o&&SV3pMKua@@%a|RLx145?BIPXAC6TTxo;zO-&X3B_pDb;o zQX82tgAx)(OS^Y5y|Xhi_$P#(Z}G-eRnP31A7{yGN80}KW6_$QK6hlKo5yGd^WAI% z)VZF(gSXtj^5Kck-qqjrs-OV`%o6A{bY`d6mz3t4RsXo0n_;#q8bCl#0PeA#1l~aa z1VF$J0_=#U?9| t86qD+ zZ0NH)BZS32>2lQy-tgp%l;yPcdspi7>}(|YB3&63&npYUbyc=bLD!wmH?o4xR)MxL z2~S>{xqq1K=MR(DvFq)iGphw3)kdW@GGRJmGmB?e#F1xC3=N+US^KDG^hV$v1bmgi zcb8AS_5J_0H}|;9=%xN$x~raP%gy?xvnQL+*EJl@S2a2Dw)69E1l--rzx(|cm;KI( zV!5bWCamRUIGG#;3O-2yi>rO|v0_pn00OQjkT8GWmf52RvU7S`!kU#w001BWNkl =$SeRp_M6 z#!reM&t6-+Sq|6pk+v$ejfpIlvQHQ1%uUe)WOa&a!7b 6V} &+`A#hO-r{O{ z5U%?t^!v25pL27G{{x#g-7{f=6CZ?ki9+<)yPg-U1pyEM0T2KI5C8!X@N@#?1~*;& znO-f8H$+=0z)N9du?A%j00EC8fW5~a^*CS*2!H?xfB*=900@A9*Ar;?=f~IguT-WH zG$<+fKT n5WXy)jO6+i`#S&1pgjvdyZX`a?CtM7w50QwE9!g zWtVweX7E#g^b5Ylv9VkT3LZiL?y-kF2$%r^AOHexAYhu#N>eGNtx|2x)$E2!5C8!X z00HX+C@B}cZk_tqfP4BVy#qpZSsnOb+Lj#9^FjY^J^ca#c_kG(4|}!gY>gs8tQS{1 zTdu!evQ_0M+N(>H??9Qp3+QlfU;p5)d~B!0SDJqO*4!5a4x7gYhWv)FZ|6Cyxn9iz zjp`UNNZht*T6B~}aSO59Dnz~Tw6$Aph-l_Zh84%RXD=dbQ zAOHd&00JNY0w4eaAmCjDF0J`5?$eStMY*Q0eXxj6A?T5zyet-|Cppy}hP~?7xtp_` zF1P8Tm}(~qs~S7}G&^#Y{UaaizTnXH&)+qjlmq6GqTt{Dm+0b(3@wyzd*yu|)#u$5 z^Jopc v 6SZ_V)|%%GgsTIOSIGWa?rp(D1IglA!qf*cc0Vj$Zzb}XK=?}k1I{|lYCT)tBYdo zHIE{|ToHM>^ rP)={JPrU>++Z|dB`N;>aN#B^HgP;TK!jl zrRO5*>TpN6svB;-hydJUFM3!o6$C&41iXv@9jxMI7Q 9(&+Jfk_|$0wCb^1Po4)>>&qs47#WLedo;orsDMz#sq95Kqq$6 zQM9)8MK5O(Ajeqojg_Cy6b)H66KMSD`;L*1+1#CVY`Iy_` O(#} zcaJGqnyQuGl3z`ZG{2=n^MzA5ar7MoD^A_8!az35@VR1g3G5bzoT%sp;yX=-MF z=(^*UyE}Ef?ebNBubBW0bq#^?t5;nk7*cH|(CgkVT|42|KU;A*x1ay5cUcxlA;*CG zANIfP9>3sQm7ab=!e`54?QM0bF27q0Go>#DOl@nv_@lo*kGB~9 # z%LQ`Cc?Z9)x6|r$eyb|*W!tKHx~0&uYJ+h@=|?wf|Ect}#o;%Vi5gEJfPWu7;VHld z5C8!X@F@av=vZoOYPxyz=8c9Mjg5`f^(Xv8?tFF4H$F8_Oa=tJkieg&J{%o+D`LoP z^631#bT{a2Y%rANZN{`&mxnaPCa0Il^K_doGG5bBq} dGyLPRrsMI<$!|;-xIg4gdU@@1ebA!diQ`D{~c^1$XLF4A9(KZ1hdR)eGEI z_n6mo{)di{I-NJG{&6`sgBySX2n1aDrL?huEpO<0XG}nl;X5s$0Ra#I0T2KIhY3)0 zs=2v^dB_bnD1aOo(CDxz3 v7 z+ jIf`{SKE|GV$LyIbdgc_YG{D;Cl~00itM5O#YoVg>d>L;qG1pa>PEDQ;?Nym8}( zgj~g~q>14m00Q1jfFh`L*e{=fn9NyBaokd`-aXslt|&grmI67zJo0SX-?_R><@1`R zb0@i191u2u*DD1&*h&0GfE(<9c}9wi4`HH%i22FJDg)@diQwP @Xz|009s% zLx7wvB|S2QGy_6@Bj((qjK}6y^U|?Ebdax-;fV^J5;FKfL1y&G)j|X{=r<#{w`pmJ zBsr){lEk#nqKfA8bv!rKmAn}}79Lev$rJ82=kIg|lF~|EYv4l(d|=a$-}16pu+hAm z#}5WR@T4-3m{W+JRMRaLc)ci=mz&PkaOat==nlSx$Mbm~a^stR`Zu2xuSdbR2{_+9 zCdXLujg_CijSsT}0T2KI5U@@__uqo`j_3gbAOHfsL4f&Y4`@t Q0YqqoOT2y`{hSYged;>B~q9R2>1X2<*%m?OaxN^0T2KI5C8$M zBhdKs@rz5I6n#i#3O7$2;&UN~jhsF1?=}2uKW{QuxVq~#@-ulW`E`l}a!Pq6FSJq@ zmt(a+5ptTZg>Gc?#bv)!b#TDE`r?hWms=%AxwTC1`seS8135RMr})O2GEwRC1e_c_ zR{6%KPoHjVYOXzV&F48{f*|1G1bW`ysiS|3zrWMI5%ci*`mlM$bH``omBpmYUYea8 z>c)B27H;3TYX7byWqO^_bBi~>6t2I+I|zUP2!MbV0SXsWOtR_paasm!>KH2{Xgx43 z2Byu)N-$HYY`XaKjq(Bts0KYUR7 BJPW>xiEo{_geA9Ye#_}xPQG}M3Qg`ef ztMWF v#grzDlxCH@s6QCTz5?o_vQm-rCuz77}#j|d95o@-u z&0`K~Y2N q{c;pT;KbkU`8MS0>%VtKh4}-Dn&nQT NwjRB? zu(<`v4w$F;U4R7@Vv_^v#NjCW5&@^V$K(<#Ua{#|XBB1_B@e0w4eaAmDBS&R=cGyktK=nuqe!-4lX75C8!X00HL` zsIDp{fe(fuZtPsHkOl%E00JNY0wCaN1f1_4D>H;|>}gLL_J9EXRyyG`P?*&(q`&-{ zwu^}?%Z^iSbw4u;4N8jVQswxqHB?ha`Lt4$fg`iz8bdc~rL0$(Bgg9{_fMfdh3Z@& zvNTawR yaEv|NpwNL^AAOHehN1!Bg )3UinsjM_}+OUe8^6Xd}$IIPHGDDQF0Q7_MruECym+3u4 zB~Y!jENkX}ewY2x%Ub7t3Sv+M0T2KI5C8!X00GY-5YY9`7{!`^pl+UH7Aye)5C8#B zB# 6*g}Cfvx-G{Pt&LmGRy&)!@|M%y 9E!e)wBuQvSiOUw$CMaiJIq0w4eaUPGYA!lPbeD-3lD0f*ClyTv*vF-yQd z>dBQcqYCN8{baL!(EtJ<00JOjKY`I(C=RS7d=7bO`Y0ygyOVsibLgb`dD+Q&- j5dOs)jD9loPW7?lAtie_?csWrGM1cSZfB*=900@8p z2v{fJs&kL6Yeo+c00EyPu&U}KkMoT^8**(`1v7Bq?1|$3WU2OqXPXV{KmY_l00ck) z1VF$i3BWz}$;XOGfk4|3___W<+bC`Wt#ZCAsVsZO_Tn1H)rUs*W`mFH|6C`ej`ks^ z(1F7a=jC$T7K{V|5C8!X009sHf%Z-Si>urFCjj#Y0ap+xj9nCe$HT6WY*l7UOG{Hz zQ$s_;rAwF2o;`c!%$f7&&-d)v^Wpw|f4sm?Q?e??Y6o^iQ+DcZ>B#boxaGX}=q<-G z6ZoACg@lCB((Ya4X2 ypIc8bk&fa%tgzQ%CDLHoDB;y2NVn>ug z00ck)1V8`;KmY`6BjA7Km(q);is;qYaM89Q=mi2G00JN&NeT1!ZJ9lKV07zP#AX)f z2tuM`QgZecZ_aqIby6`J1V8`;KmY_l00cn5egXlNU(6)mm m z0w4eaAOHd&00JNY0w4eaE+zo?*u{V$9t1!D1V8`;KmY_l00ck)1VF$W2p~0=H#{ZS z2m&Ag0?r{|n&L}SZuH#Z%`b&(Hlfm62~7TdcvAd*n%3tR{jl!C8qFqDf&d7B00@9U zyCMMhxLrMNOcn${00cn5B?O-Pk9(f{&Fxl2fAP 1d_9f^PHWd3y2OY)kRw#S?5Z z)9@xPR|%R@I;Q;i}a>?Yu+Y{73KV9@NeuVEP~c0w4eaZAHLa_a4_4y|XZBNOWX( z{cFg!lWoP&J$kFRCDCN9O!MHpAqzKEx5l8_qM51l3R)upW7{) vVF{(+r41o``U z>%T4S`SD@yzD md!00@8p2sl8%E2GD?n}$5M2n(*%kDIVe z-EmkN@X3U 9&L9$170)f%Zn= zMq~5E%QrP=edT(iW<4rF00ck)1V8`;Jb{2Wy2k~%vTq#o#?Gv?L`VHVPk`@K8;WMK zuM7q(`6%CE-!Coa&9RSe>hw3fg79MW*%+-rX}u#!Z8jhzq`L{rvS&sI{Ar090-5_ z2!KG_5%5Cy_+(`z@fxrMzOmtBbMl?kiMf(AXwHh(_{NI7#07;*DidBWT{L;y(+9?d z8I+&|0#*qG`UOw`nYzI}w#o_}+Btz`8U6TPWm@NK&Yk}F|NW1^0NqxFRrx2l_xt*| zKE3bnN_%v9tHN{2$cVZ#*FXC5XWp|loW*Uxv?^N^CE96sb8v@UnS-dONRl2$a$<<) z6LCLDXaoTe009tiGl77vcg83x1A?rl+;p>Xj;lLaux _w$b$ln$Bp%D8y@lnOek4{ln$eo-#7imm~Jq@zm7 eHh$Kx|Q?+ui&_%z6TU}3GLetjG`FOyxqp#-{P0^mdAO}Sd-~^Pt$82%6 =qH8mkO z<_*owv;_;3#^iI)^Jwm}gmQ`b%u;9+i=b9kS4+k&uA;TJnk^)YiHg$QZknvh7Dh@- zC*~foQ>h|Nl1%2S_qz2R4DSaEa_J^%n%QO5gBKs2^F8^xxl`v2*E{o!l58-2L15%F z>*Yo~IbzVVqlfbg3Kqm8N0*)o-mMV`^6yBYW9robnX9d_LOTeQo%ofz$B*>7)f5PC zrCeW2wjCEcocQtT_qCT-?m8h>itZwXPwCczXDAMIdf8s{#Fg6?R&=ZEB ;l&>VtF z?;@agkXy)Xa*sRQ6VmCP2fS+vuoeVBz- Q1*>u#_s&6>OvWN9bGe)99@ZR zrah?wdw5v_^NlIXm)!a2oB`C~@Ur#nWTViCeyZN$ZEYos5=TYw;Bdc~u}jtz9+fpJ zN?G^PMXL{r!&uppQn@dk;Us?-Fn|OqQ@HR^;m#yxo9R{X8T*=G!qf4lO}r*z+=?YJ zbhl&7!Xl-TQKC}J8|%#NE)ISAMR~|x6Z;hj_z40U1cExS%+(Y__Q&FC4Lqo7F9axx zOPgj*U*!0S2*{VaTHmPDDBi5tO0F8eH9akv{5_R#Or6QW6MOPtGMD4Ff*Z`EEyR3+ z^!35$%)<&03i-aV@!x;{`V60}Wk;8MV;ZY`k3io+(5*6%{A$Y!v$=c}JedGF#)^5| zL*_M}Y&L8I0T5_I0^Z^tCoa(Wx);hePGGz!T+C~zpg)DEcGGeeWFE`TCDLzBju^c7 zz?!jCd-%X-8fOA0ZKSBO(m7(>v 2(u z-a8IWTe)TN6k+`~DczaG`jpqGeR5W7Rw=dV7fVwP>cRTVSfOE2k!+mFrAt)SM?YDU z4oZb?JF%2MaVELD2j|J|H&L>Xn>y^-A 47zj`1?muJsbbtAue^Zq)q z@~88L 94P{ncN5%!0Z}iR$&hgA*r6J90}u z{-oCUOki4Zy+B+$t+>Pr{xG(3x|F%f%z0MUFzXi^SJ!+`o%)6A-B+y#78ObEC118J z^suB CVkeZnmH;`w z!`EwB|HRuBCDZA%FZJ&Ggd~mZT`@U!`N)!W!%X^CR(v~S_>7(U?yNnKEv^od_a6I6 zPmCF1I>=Z`<;PhwW_ c%(^{*o-m=_yhq;(8cpt_qwkOpA)SR?sf~? zr$86QGtF&+rSRs1p|{-GJ?Iv_BiE%<2W6Be{B)^#x8JJcLo*d)=6vEmpKs`OukM!| zzD%9BDg`=%OU0JHiQvxmx({nq{c-E11jsigA6bbT|N85%E%n!%uUz!fxxnmpPN2gb zJ+T79)t>>~{~WGX<1YD?Rm`0;1a%F1MZecjE3S@~Ys02&shXm1SNz-K6iE)1*c#@T z0fS0+>^- WcQ}OM`|?qwToDVq@WO zDasE09PN3w!8dNpsVOV5nFWWdG?tmSrD@RJHUvJNOsl7Lswtd2`QvXj>=?FgZ~B)r zdh?EAmtpHln|5cGg_|NdMkZe0ww6;^W&+i=@eh3(ljX-)syo{37I|F zH}+)nIBgVskHD<2KJ?o&I&kM7-~7kt;_UqNmsp812!H?xXcF)-_gIeiYEIPVMaaTv zd3CY8d6=!N9`NFm@oc#@t*@30ex}^LXy#OwAB*iM7Is7{iM|AR_7qvhY@ fi)4}lRQA6~!bV`lI1RaxJ>J$po7P1}d9 zt9U!TZ*R>u@@*@ahrFD**@6DF?KrSYhhTrnx_`{P<0sypZEXRzwpL%Ott;M;l@c<3 zYmK#u)ofpzS4N#m^Y(vkwX-#0k|#^EYP_#>5O>KcYk VESyw-(>pr6Wgo@rogm%qvmwJpvz``lsaAcr)nS!k^y0 zednA#Cn{);de>O@?t8Pwj6eVcoJ+vR++)R|)uo;mNL6pk$)#I<4wKMisi>?juBv7` zjbqqm;KZjX#TTuwmIrZZ$_i)s y KKzU^r>)L23YLl$ 6bQS;etZK5N^Gu1a)3T4Y$>~jZb_-G&rrf&CJc_Gx12nf5-_yfj;mMz`@y;mt zFo9K%j`eTUt-LrNRPl%M|9R}A)u*mrq5n?& _~G}~~F{#Sk} zy?CmKUX2ZH|CMv=K@3jUonVwYuRy=@u=?P<$;>m9CZt xRxdj`Xvovd z^<^o(Xnpni
#`1XV~ayl+uR_z^QQa7n$)S?U}UTr!3nAjg>uOtwqKf9Y3D3Gi; zs=dj5T|eC5q*6(9fweGi7CrV4r0iVs-s5kMoA+w>P1Z;ZM!Snmu8OyxkRCSP4lO8b zkHxs`&E<8+^0JddoiTeCNegj?ZS6;fn3%fv{atyEE=tN}>iUZ5l&@Yl W!?)lE;0rd`}T0#9Eem|`?17WH0DV0c)ssv$Xp{GZ~p zIObRU(81~Hhxfyy;7m{e0T8fEz`yc~nWeiE=tX|A<*we*sz1S~bjO(IBD>R3Owo}8 zrtXlFQ5CKnZ0{VDgkC%3mDOSLVA&nbry4N DB8M0Qe{W2$mkb=!a0kx%>*L%W@5WpzMMkbi*u#pahg zKi2k-DN;<%ae8{X$0LG)Am9jrzyLp5?yLFI6i4ZxD4UnkL~bWvIIWqKOO(* !Fk_|8&eeQR(j