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 1/3] add fastnlp_tutorial_1 lxr 220503
---
tutorials/fastnlp_tutorial_0.ipynb | 16 +-
tutorials/fastnlp_tutorial_1.ipynb | 1156 +++++++++++++++++
.../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 zcmdqJWmH^S6E=t?fh4#D3-0c23GRW=G!6+C+}#rh?(PZh1b0brPmspl-QDIi n{6EPk!m`DVTp~<%)_Rd~5LPRh4{p=0ud%=LmW285+T( zEIn5dN7bq -Y5O{t-qhr`KYiwTqL4}`I{P+6`Q7n_+u17dd6#M6xj2J>q&4B zNy7CPY4zZNC4ESc0_d7OuB#9E4sYg2_%rYjKKiuoRF&yH;d)$W7(;}JdN;Gn22q4$ z4{4*|B4@kSVH?t3dye!hD#^Psn=&G06w#XKLB jez(PJkvHTd@XN7g;#7cD?=LFF!@0OA1Tv zpVo+Z2rC4{B7b+DAqCt({Ng1t^ajpw8VAl&@m=5&t;?N?Au-Zt^RF36(clqIoE%=_ zenxuGT0|B?M3?l{f(-#2niLFN2IUFN(dqVh%f-?Q^d6)IET+FJ1G@NxE ?5%MMx5*dU9t=E(XFJC;IfdX8&{@iou@=FQctazYsimo#11n8z8 z_m&|KNV!YhdI7zpQ_eeKIsttc_CF{1E~2Xu>A#Ni@4vvB@DC#Y52yOXr9b&`RSa*D z20^d7rea~+w3BLL%TN284#Z_n##sXaDQzJLk9U`XgOe*!`0O7N3|;E2!nb?tyQ8)y zoci6}eUpjJ%$(Tj!M*Eel6aCKWezkia14#}u*EY~cL<9EE4tExRvj++-2|?|O@)P@ zi1VWvR^=RS)x`<^jJY4Q-i4Js36`08uFYM1V_uWnkM1^VBj{Tb3;8*Y?zOJ6u}pXC z&p7hJQ$z!*K;Z5lqeV>3ll(vrn?jpLFj}?eHev=7UI$fhh`LSh@}tzr33 >N8MtA@g<+zlY&L_N%ql%6hpeuK992^`vFO3j~8Rt;#e|4Bx%>s5& z-1YeJy#VB58_a|_jUvrZuN;4S_w|fv-=m^Ic5}P8G|#btJEPjEkhT^f_~=_g{0F YTo~3R>AP1^Zw;%geM>QBlCPS3Y4!we-?beL^y#FnPNZSd zAk2FxKYuit08F^ a44uiR aP|W8qx$!sE1yy~j)tm3M?*ffaP3D^ToeFOe`qxLTuCWCJ zw9A`Jq+a*FkEkgwWtk@7 7&l?j@~ZX5i?U+b!5U9GS7ch;ufk>=vH!W`7I~ zA~!%Z?b@$svxUA!dLxqa>{`uVU@OHSadvj)NEhTWa8}oQyw_)Fm}b2$x;I%dYB-eE zHc6MH{kpiyN?om#DM*K_%frOpGEvA!J+^3iY^p#)aE~E|@@L;DsH=kw>~3~v #1f;N}4{E+I*mtoT;0sZ2t`<}6_w}zKXt-BFFtl!6K26~cKloMc= zW)BL{DgP5kJ^@DI>)FWj3~Cfn2s@#)Io(?a-D#}-i~NJ^@fY^9XjP7K+Mlk;NZ^K_iElB+o zdj!KWP^0EFH!_vJsDG32G0cR*9PvQX5YM2|H^2f;Bj*!2WtFDhi2qB-uP9kjUf5}U z*9zFesq-1VaSz2OOm8d8CRJ6v8mmCORSYeb#kZ3=AwOSpdbm^#;ginKVdfgN z=;1OsM+ZLR-qSRr|0Lu|H#C=!Zm~ncIZ^F-&gPaLrRjLkvuAjT zU0mJUUFA}1^g6~bfJ3YdBteF z^>tIfJGXRtb4N+6Bl+5RJ5<;0g2^qI^TL=C-!+x0O{#-ui;H55b4Q!L;Z)I@#%MZb zY)#!O?BgSq6wnsg#kuzA3p#@ v-|Ja%VHHMJEj)62i@=&e7^0bTn_l0Kws3NF|cn~%b}jb8u&hDHkK z`VBOj0FL!bet#Cviyu?$sE$F{n>a>gEN8QPm-aOtRfRacFt}bPko46gp`)9l=d4@R zkm*N gQ#-wZ=$a0+v=j@gxsF%NZHqkI`@i6VVrvJu0 z#wv2vNXU}I@h jjj#FSrr7AI4Cio RyHWX*Jr&x<-1G(d`m zLJtZ)V2>HXA8sD@hy<4-Qb_lrMxe^m$ hdqL#;?_M!4_Z$B#y7rq~Fw%Q5vuKtF?t_s{iq^c;2f~Fmt{wWvZ!L zUDad>$Fz1^q7g0smpMGt*wyOlW?r=dd#Ba4J%^eWizb6(Iv$$CMaNw2BrM$wEabg} zky?g%!TBl;@wk1iCuqV$39*@#rqL;>x5=KL<`FMu;_{~zl{uQq*6YoT VJ znAIP|d1^^qGJ1AAv6a}m4uJ`@{4CO=H6Jeb&eIqiQXsix+p=D JoR^>n17{5S L)R^pD4<;_$qW~M!BKVGgGcG($vR=p=EbfX Ju{elcC z4r=f5Z;6cv&37zx(-PcgES_zMMjFFs>M}u&-^}6LtXIt+EG_(my7- $MD{iYrS;eX4jd+F@89OA6HiK zR?vcf_p*<^++tSdH14}cN7TDs&JWJAxsjZFZBoJ6;X)IR8!^MPW#$Un9SWOoD6&ao ztDc*(Xesbje^s8?7S(iS)To5~`pwp+MHNs;ThtMJ>OXyDIC!}j%T_kCm+w65AH(qR z?B=F3?MZB!E?(_c;9H?j?~_*DLf;8-g7 3O?_0eH=0&9Q+zyBA!BQlsPP z`-0`u6%^ZC%E1jzyzbdTBj$;4zY{FtwPv!nE75KbEC&CUBS=6km+}o2rw01kH`cp) z3pA#0>i7vH)ML_f#<- @Q)WvjejQH<}wfKN#*qOvCr$i*2Q*Q}Qd`D`A(nEuD3Ej9p@n zrIF(} $qZ%d|Q<9u(dJNhbqcUo%IK7>9W zUn*|_g^jLYJ7`AxB_d+PY+RU30OF&_%iA1|wZj*Wj{`BgzB@_q{ctL}lJ0mkE!s8r zUg6Xr-qDm!gK=9pQ^riTtB6f=?~4wn+q4@YbyyP>JfZN|2;;Ud=bKL^H98LAOXFuw z9I|L2TV1Cue74-J%e1Esan9*tE&kOF?Tz?XIDQOoMn7LEBs(FF&oa^H*HJjc^{?)Y z;2W(?u0f_{WexY7zDhQ7=l1ACkc}kAmZ#iWx=G3wP5kjXs}eQFdSeQH4Yp+;$3HyI zNTD-UX>>?zZ*8jZGsH@6#5Etm!M#8G?PDZ z|AM+Sb#-!T94?nz{Ex~7cy zzXaiJiLFNMZp|#b_D8AQ`aEFqyT4JZE=|*D@Kv@^p=067Ihp85nru-LeJan7B8kW} zJBp>L1M|S#Mh@^Pk0O0ysd?;e9AA8GRTR-^(P-3WuXes^bldcmod8)`6UGI|sKKGQ ze$&%{f%g;mgmA8ez$9C75R}Hi_}ZbqyxyUrd>Ast@Zkd{AJX7{cl=u<&LPH%_&vtq z3de@}aZe*`Z0;Um2mXzUtyegn;T)4qyyCVA(pJ^V(dK8<-UNSl*G?4yuqQDSL`$!s zvBj6d`uc1)ncGUI&UW?Y^7zY_FYAM;4bF#4?BZaIVf7Rl3^?w6bwSUYi z#$zh_x6J?e-w5{qKQ{?@1NX&Zd;4fzC96Nbd!85f%h?BI1jLiQqG)cB-jw>AQ^6*5 z+;Gyr0SBELsIqx%pF(3Rniawn#7f6#fBVRyT9y|G|8x7oT4h@HD%zqg`%jx?r+4d5 zhBZ!AC_ZDMK1oz-A09Wf>euna_1n2lm3z!C?d(3I&Rj&(j|X{!aD{4B)kpK>8NUT3 z9#I=I7sI^PtOXqwukrTp5_b7)90hixby}Htw(~a*0hNArLBqu>{fZU8*|-XQ1LPP! z^k`Ik_!OFPa;~z%&E@1oyun;@
~~%+XKUf{HL9;UP=%Tn;@pI%fy{TT#23TiKtR{-CuD z26k2V=8%C!PmKXeB?rjl>Kf`jXF1 { z@nv<>3|-KuQ(RHVk^*RCN=9or-h7_LzCPb>;D &>bAFxva$1)p0s^(GRY@y@qY zdis^V9|izOk)XS~Jo)~yq_&X*NWm^t)DfsX`bK&SsXK+4Z)UBG$rKcqy^I|hrL|cL zGwj>N29Z_2K&j7YhjrSDN$vPbf?E3w>Ain%LTeY1<#&lG%9l)+>Dq?3`<0F_wkY4! zbK$W0;72Ppf-~l4i~EkoEF$2ifA+013I7dDtWe7I3+j_-sGGIp!un4WF6f2WJue7b zvotLB;F%(n1M6F15_HBeFtQAlLX0Gh;{+{H8pCHng@Oo{{aTzML$HtME5!h3z7wN1 zglYAF34*-wLm42$pDaq^V%ubsJ8?vaxC+ YK7>J1w*kvyN8 tlNlBuvHM^e=5eG^1TkczgVqXdVQ_3#Wy^ZrV4%PK>S|56Yku&iQ%AW== zDoo|}1K&@fD8C+KW-fS6*Hc}!9)BDoZ&F>OD$4>9%F)|N=m}^dW$#SdN79k4EOVy$ zxx77Isyl|lo5=FvS4Z%xp)|qdg~4Sage4#En<%pI<;6GRQxa5Q$t0d-D4iii1@{HH zkHC<5zH!P}o^>LHsv#-1fNy>dha|YnTsNyYv)VKSUuMjL-xE@KuI#<0k+(NP$~$qJ z5`x|-(K#uf7s6U3bA wYL6#s1R+u^kci_C*mc>r?iR zK`?)o6I=;#;h~(=PeiGr+Wg+>T(arkCX?ed2W^Qg3 #3?*XR4cL z7cV1w3RCOHutwUPejLC>DyElN`&B0Q#0fd!K-j^Lq2MCQF+fGZIo<{h8YHwZNn8oX z!%>%^?jsf;5>KJV<+u_0JK+yuPR(rdSPA|QM-$u;!ycNef*pCYjEeMVyfTpfRTahb zT3kxFlnA(cyhIx_lHsyWqNq>)F)p&fW^^fe!n{O<3JyUsz_Kc@VybXr=!-wmV3T*1 zHGcW2j^(XcO>SOb`zZO4Dqg{E(FsawsVhF?y0}pc_vdPJx&1*t&f8kgm9;S1$b^dc ztc&l|8&Qo~Y=4q2Q=|{OZ2(jeU<@Y~zI?g)fgcKa0?=qCn^(UvvNMzEcl44(RZKN! zvxi96sYo8%zCdxbL=1*QP02LWXIs^T?`meH#CS1NUu#ABOHFub4wDcHLn3}7D6fP& zyyXvgK*$);-a`8CmG4r7y*#b0-<97 C{?(I9%#DDx4Z$fBuWQOTR-Fu^rz>y}}3^2PX)$+=)&bQss~7 z;pVI;c8{m`Z>!`l7!pebkkeK;4E$fH@R;JD%De&s{2#BUYX5?%zn3UM(Zm&bE6ihZ zeyrCXl9UiYcbufd;yl2(f8X~O83l^b%sWJue-Yc?OEMIJ5PECu{p3IQ{d) 2I1CI2g7k7#Q|J6Xu87GaAU z Wx9AvN}$H$ z^Kf-HCeXS{<0b#wd5QYmiWoI<;5DUvo;!CuFgmId+4V^u{sr~JVrbYvn$FWRe)p&v zk S~O!6q32*SIUS4iRy%${^p%UptwTe{&400sA39opFXfeR9694+TFy-<_NW7 znt;tx`{8m|U%x38n0lGuNjmhK?HIuEFbE=>KWq$Or=G+1$m|YbYZDA5u ew&{WYAM|Sqnk@ zo6M}??r?}QLosiD0^toxKR_+!_*uZ^UyV ?gI_W0 z)Z6FR)Qm5yA~N3}px#@r^(Vg1Rq!|+1B*^r*f+>X CJXJ_I4~8XNRE%s`R8&;MUcD^wcADGXA+E}>Ymc@| zawxIzoVyti kY>%^T_O$Pk=WjaEwp^=3y4d)1%MAhpZus|V+h`&& zrN2>rKSEdj++$r~G!Vu7Bt$hBhmp_guJQa8!d&OJd}CizDjVNA0vs9(;NHn5)(>s< zJH&u9DS3Hpbh0k`-S+}(l%46qtmcPxnD^n9v$Mzd3||LADow8V-ywKYz~WGnOnMv3 zrH65ao#;!oA5Kk8y-cLWS5sN_y6N)54eKp8Se|hw;}qu#mWs17p7S`@J}&+?^aXd@ zO!rztK_SfFp8F+>tZwEzVV9*q>X09GHnN^Adrjv$i3UQS^SJ2j;9wC${9ulp8BRVy zo8u%&2qyt$pY$(R?AKGB=9)b;vC11!kdehlirQaauSk||4rbraIbn?VwF->P`yO>h zhhNtV#3`PAT5cs#o)(4;geTBYn$r`a@BM6;sWs UmoDJ*rFM9@52T1_dax zZD!*o@@WF NyoC^eivv=N)7s)Gd3M hYpQWHBGNahwN@^@OG*z@>m29G}(N)^cJT+c*2v+6 Mwl$b>#QQ(#h&J?OH6lmks=pWbl*8#Y0F)`lB7!6O;AsEWACV$ zeg%ESp%0&-{U8zoi5?I=xkeVC9WD_8^xxD~K>}%97D;*NN>msYXsHa60(I!Z)r0mO zCBwtROI=$m8g#n9rS^}6uqa8C#e{168k7{o7&AlLx&_r6xDawtL~?Z8qS06x+^7h2 z^+M5dPc8Z1N`KQ&l)qgHW^Q!j5^K1Gz@rL$)9ux@t>B9LrF(xh&Q_z 3b7Qr^2QVDv*~J#-c42* z3o4s#SL5*u_hiepM e^b;$fgu@>w&jl%KdLe(q1Cg?j!6v@epNU6e>#R!&P>bD-B*&CNwr4 #42>MVA4?V;Xr4YaqR$7B(DB z1vAFyj>r0()>4#2459x>ZP*^KDM*Ji_bXR#n+?W{T9lyd%ed9{IXE4$qy5{ted#*h z(uBzoYv(uVXx`r903i|lE$``L!h>QdK#@ikwCvHLWribE`e9{q8eGrx4ZoMVe609G zu@U{P%T<$~qMb3)peL8IV8UEfLgK4Bk#4j5WbO4~7jaEZ4M9BgY$BoHgu dqjXaA6lGM3fWEa5mSGsvhSyz(wDE{k;1SZONa=1Qrz zS^oMV#wDXlsT(kOG(5PiAWoFWJpQ }T70UJ zxJAjn2UA}{Xl$$P(Yn{&x+|83D<<*{G>QDq{uxT?)*`*3xl)hlR;H^+$7M0aQQ=o! zSLWXvJ8@Lga%(Zm{HHS`Vtpvx%D2m~jZQFzam~ezf)bK?G?@bQjYI&9vzGdwBO|%p zX4WW>qy#i0h9GuynG(U!Qz$0C{Usocqi-;pTG4eUZ^a@wD>lwvT_Q!@Ah$%I$xNn4 ztuu;rg(a)@PfPb&`t6Q!XSU7o$cX-6w_y1P3Hn c*DS?{=; z)PmB%|7V)5e&{*dz;*ilWqJn->Uc=+Qf60-`Ep!}np5vg5TNr`ITFK9pSs-vfBMHJ zy<2gSy4UHIcrYk#fB`Xz;?aeLZ=Z+~pSthO)HOFZvpOo+eerJAQfCt9aP0?iZH2gh zJRunqYY6*+GMQ&$!;q-Oh*>a@89viemy<%!wz-P)Y>Ym6`YA`AKXRZet=+TdFJ5%; zbCoHMN($h#BxniZxK=*E_eYNlz=ze3wEm5ww*S*rel}rYrG8QBTN@tossV$=z^yfk z4+TZ*$`*zDM(xXgUG(vA(tx@qO|16ozYg}GLf{)f%i@=RSl@qC`nMEWkcM&Dk@hwF zZwG=JpwwHqtTmbcd;{&JkB@Fs9=AUHir&GWr*L}+y?uSNFKVCj`^3e?{RsaFgBD;1 zU}_#O?*wSI3ivu1%fWut)w}LxDN GBQnubB}g^84#dkUnhml%4x zHZO&+ NcLO(n39-$-nD z`B~1^I~=dcyTmRJ^6v{covI9NmK>lCBBFV>N+C2~f(ZCrC`4u+HsF(ofmkL05svMZ zRKAT+%*M>zBKiWX_ta l%S;cbH}HT zP8N*tmNtBqJfDy(aP>IPoi0{XD9Y2MTwL}c<&hvDgb0fPY}P#h+n9BmZ#rJ-cF$89 zx+C)Cz5pT~1;WZXhcuPOwpZlKPa`?<$s8ubF|_YPFcbh~c4J1&zwzjhT=6$*pP)vQ zabcM2^)(G72o`9z-;BD;x4&zg@b~sZlX?y(ed?lehto4|2h{Rbk%Z-EYKf6pig?td zXx9i)TUL>GJob?cr6akD@l{0Uvrf7@!c+{tBEK*rbbEZy(Vu-GLF)}oJpsU=K(p;? zuW`DEBQX9-Vx9p_iYRbbR-brW!+r{Nr~~t;95|PD6s4@6D5!vf6iHF!zAahB%M Z6iXnmy N@vhlvai3 z)Tp}>61AQH^Me fw-a7{^H=aT>l; yV zSHhInmH!4IBq-mK#HWDAZJDAI#e%Ygh_ICEeb=zL+i@xCui(D#_LVNKujd7hGdPn% z3GhVB)1IYQ|M;5{)i NgpmOJlnw!p|1DSUQDoz)gz2g&o@(zwrZwkOB|M0}8VLOiJJSv&qVa}Jm| zN) xCtpn`zNMn8!fULdKIklxuSa=M zWjq~JiLO2H40UIJL*qwYd+~3Fk=`Lkw_d_B$=Bne&YC8#-CrL%DfkJM40}zmH7z{L zqI^&T1vV_IUy4feG6TYrUu&1!Spdu3LUz2RZd1Xuz wq)0&s(!n&Jf7K30pN+S5vbCt$?j^ZAr;D&44f-20-+^zncr^$4d*F*NS zb#B3OPu)%yj?3>;A$$E-Pm8(Jv5T 1@qL8Y-9?a)ye#fB88Hr-iZ^ zt nyc;VJs1twXYvE6Uqn+R9=_TqGf8IPfn| DB~Y4f7{k)~Ebj8I zzwZaHsiNWZ7S{FCinoIg%}X}|B%bjhM-S=m Lem?YhWF-vE8MZ>KXhN-!6s^c*Ek=V-bB!lXHwBkFKToi>*1a=tfH ze1^%A{=Q`wd_v*~bUR5MXcXVfRX6`K|1$c!-&)-eMR%Icf2R4zZ!EW(!kjKeyS7Em zrPNrGdu#ZArgNZCe96zdpEz!;BPu~-4UBp>B8+FGD5DrZ*&&T9 v8#8Pka20gwHHB56P}doC8rjeB`GsM@h9wt}n}MxLiw>q>-|;E#+94uh zrPO-!gQT?L+Gp8gt}dM#X7|yBV}89y9X`{f9~N`yYA|l!8X0oa>By#fsAT<1a*B{F zBF@ 9BdZO^USP8)9@(E|6}%v4pOnndRX^Y0oTSzyy9edc5) zfD~N4&n@vZKsq@Z*ax{8t*}}8pJoAl&W{?u7?rlG?>Nfs{9<_@Xv;@{H$lpByREBx zb2c3nCR^<^yspuQqIjhEtFOH2{mw)nB|7jtLG?@ZJ}ir@EXNn-R}nuo)Byg7TF*_+ zifgCjOptrRVg9{OFq(yVb?g|il?6zFv9DCq%&VGK-^$S7*0EqPyn2opzF$u5Zl$ zu)=8_76f*xF)B@`tcb4&3PPsbnfgKZUS8z&=pyC&FI$Gb66FpfeZBR&gE7kz9VJQJ zQ;^y +h5o-D>HrDkq3A4gtRn%gNd8N{aoQdsDQ`Ird^fC3S9xLqwr^R2C7ORjRtQ zF_SU3#Sncnlrb$omh@GN;9Wksv<9 pWj@?+(H-nno5&7hp*}>P| z*d2=-eSK%Db>%HK^BS5yQOSwMRvdJNi;z=?@(&=e<>XHd@fFv*E24Of>J7cAFE3)4 z{C&G5dFu`Kvw5+%gcIYL=(L5wUlu*sN<91Sao$zn5XDnDAg@tpqf8uXG&G`A?-t2M zHkF&lh7D47azDw$ZMXQh0PztcCF!X*P^dC@6*w;IvQIZSbI9QFCyoQU(bc{tqcTz9 zriu984tu;sz+`OU%j9+p-hzBB`Kw+k#mVaTrf9WNsf#He3y gvG5x`?u5MJ4)m9n&kLJbq4w1ygXr>^8-DT-AB zO*6jwnEt9N&7{$n6CI-Ag>_XG>ohLa<>lF^u{d~v-?XFan?40)>Bgt#?+8y9hE!%o zmEBEF`qU?BIL-8_l#-5q4k1+c(V`paKBk`|n8T#6Xm+%$DlVa}QB;5D_`?o 1> z=3}1(T3}Eh0SNBKO){+8vpcHUY>N#1bcVu4XmeJKDEyT1+cS-^P#2JTEw7L_%OwnUzEM~Zq!<2aXb z_l7Y=X54v*CD<-J{R?uGY`?0>+~s8E*CAOK<*-Y^t&jR1!3>lYcZZax*W5Kin>VIy z#`Mo0^8RBf9TnuwAf-U(Wupp^B}B{oKe0Z63>V{aA^U@a` nwnb?oUN|^m*dbq46FF-h=bppIz +0NQcday;F%w>($hfPe`WF%XPb1N;y8ks2-3+m$KV&7J^;+7t6qf#@ z0$ {&%k1G%5rj#wz%MX5ooA!SKl7Y?)kS___v@$0v=iusP39( z_JMqsZ%d+M)Lf(K`yl+TjKd=aigE+s8HFiV16w6FG!l2vqZ*@mAu+BMevZ z;dQu~HB{X8%briZ@O!9o|0$0}J_F;?dUs+IuaSBjCvoaNW@&sazz5}^III=WmO6%| zne~?cBtx&^;p6@kr8&sWQT*p~=dM5HG^BjFj;&=XKXj}q#+Vk*1T@Y4(!uhN6C)9k zI0Tjc36o&apyFU5XZCkG4dwLdaZatDV+zU478Lo8v0pEYdxqgUJc}$&be<6uXkZ6M zqk7Sk61?A4J+F10)6{5i%B7^n)CwEHXBv@r7_LeJ7nNiP`YH}^z&t)z@gMQc0kY)T zt-A_qqZ|a+EUIXn_WhV)Yk^!W$9Srt%)nZ!9Z$HPVv^l6{rutik?N7OmPWE^NU@4l z >>z~u2Ufg6sB ztEb^Y0rm6CZ}KK_` z$$uZ;`ny3A8=yFZcdwo*0E5EwC%=O(DRL>NYk1PQ{TxG?#&~JqBCtv)eo+B-_P3BP90nN82fB%u$l8K L)mx!3n;u0+F9G(p)ly1&G z5jLQpvuoLQ%%&t2);c_5s4OFR#YBQ;0q1oTd!KaeedV-28-DLG&(EJ}fwC-0@&}P{ zlE(@ZJehwaNL_=S^kV7Yrn?i{%HUpadduEw`dOIy%^iWPPN>_fCc#XA^2NmjI4hWo z%GX~F%Pg}+KL;f-Y4heP*_)`JW;_!Qm&R2U7P~W{ZV|NK5nNSKbTrA$$rvlYV=t(z zw(qB_SQXj;Rn# GmXO*Nr0tu$ zGY&kLK5_fhAlqN~-Abt&LyR$RztY9udUm%wDoIw^xJPSGsQ80XnuTRkQ>Dt9r?GRp zn_be*6I!+=b=tnk{c5Mm_Mq3d#=89W66jfuV>XoBcE#wz%)R-x5*?cH(l2NDHPs}_ zdV+s)S@;}Up}zj4ibYI%6|$7GyT@b;bnnGtMRX)Kqn_MzI^4YeC_YtrJ*X`-JLW}F zfWyiIRQKBmPaTWZ#%xv8XLQP@G>K6wxvL2Ur^??>et8>q`Yg}`Er0>4vBnAmn<9&9 z_Pm7e3Mx#KC4 wLvhZ%vUZ^G oZo$t4(^$iP zYa%}^&+L!5-3xn*qG^VBCGH+F!Gbp=I*3@7{4Tc1Mn&Ddl4jwZ!LxTe0_92$A8iIS zOI^+MO`@Bx#spCU<7 ? zPVZKM_DJ@z%D|Uh?SeQ1XH$LJW46|D1l!BKR@qde;xf=BQD=pUwzj*5w)T$a3P-A? zsV(!7$LfCa6T973$1%2=6+*Z`5t8M;7yC&&ccBShHRiIrI{(Z92wm;?-Y28i+igze zu0@v2*Bdnh*8|Nq0$4`tq5z&dA4Q9zamJZ5)q(4b?`AD6h21q@9k-*Qj3X~}n4C9_ zT?d+ZfnhD-yP uNpCVGQ!b+P}ee4ieFZ 6JmoNdA%I5%$<%J2-O7BzI`CDe@9vLHYE6B3$ z M^(@e#Q}vu4_g4eYbBpqB&hs&Y$3A^Z`-IjA0m$e`7@5202j4f^VSi2ttO z(AZu+Do$J&9tlvV*64b+Rlx|4!@DGCaM8-t_ZFMNfoUA{I!d|a@X-k7g05G$*Tm7t ziT#|X&z0GnBys`_km_AI@RnD-nD4HI2WeO<%TB1)mC5iYjE4yBSBTrCD!3rY0biDK zhNvVyh|q+nrihT-A-=3^DH+goG|@jKX|hhXgDnle>?yw)&(EL)*&Ehv9bDhSZ-raG zhQHmH9S^QxFGBscrJv9EYu1&(6fj^US>XAgAK^G%Q2YoyA0#D@%9@W#9mLH%@}7tw zF5wjyf#0y$+lJ273B|n@dQFv@Ay1;T=yh!-4UN$T9m}HTILs!o8A5f^Xa2vYU&@f6 zEhD6CT?A&>bBm^44ZpwW&5@bzXPpT#2l;)y+;Ga%RQ8}G7xcCnW^cw2u_ypU2$c8k z84J91KYVzY&l#y(V>N6py~o@%uvg{;L~IUG$sOhB6gpL(f3`k I&Tx6bD$9Nw?6cRWh(Su0s`djT}w^Y$d8e*1+s2y>cB^1%vn_XvI$5DB*kR4uq zyMJ$V!cd@g|6D|; Xs$Dww->Krv9EiqI^77Tv=bJt}`?;#2V>vPl) zCFh##e;TbmxTGQ{JQ73*Mo^~>V22~48rV`Qx}S|@@3c3QHn8YOC*Ur{8{11`o8}?D z4r~t{DBG|D4;s)1yE~e7A03wz$A+3lvFvDut8B$bf%|FBd61BvhYQvD0 DzRj-3cIkq^{6MDrRaS$+^BS8?n~b4> zGn!H6FCvQ-#Lr0q3#k;ZmxRYokF=MmdDnLjO0aZTSTHis+)Z@_+6wN#h{}Ivw##H& zMH!Qku|F_e7KZQ?U#i*<8OvRjfAB6+gS=uSpnQ`a;!U<8WP<3kfk~sKTvAzCS)}oO zR7JIjNp74GAD3r%ZgfM9OugXrGfndr&eNO)BqGT}A65>8k6}ReStCMv`u8+5LPN2% z%GQ!t2?QW7+lUaw;#wm^k5#K`ktfSd(<)jylIyLfH97Z%HQXw*9YMj8t|dp5mIIj% ziz)}94Rp`JxteTb3#n0zr!vq^yaG~|&dmk5spVp>gT3WwUF3>*EX(UwJl*M;=jl>w zi`$J2VF{1C(#m{mgJPD~ZqMQ{f&hWJW{X>4Q>m=dk!g*6$zcNzBdm6~SG=ne#BltC zR>ml;*na;krRd@u5tRh(3xWYK{$W&}^>y!V;YS(WMZ^6n<)j)<5Lfaz1^?6V+uQrY zCVE>eMuSg??KnOsW2McpWrg{Nr*WB*sd0=tT6ezqa$(4#sfWws)6Y~j|8&7O;IC?W zcW`2}e)KdKX@3r68lTbdFwT%~q0tE;pz&$w(>&+z>t@qFZli62=Ig%GW#)cV(67k# zB{ElQuB)FO6R7DgE9FUgZejmLJ11<@IK-v+>fx~-AtH-A{R|m>#C953q}K%Oaiw#$ zOOg0|TM~e@L$$|ydDCBD(E>1hepyf}T2}Blx-M>691VF{ME<4*yUm_yZ-FfOpZH;O z25XvzLp;5}e>P~_!#Ku*dYMZrGqSqO@m@pwP$GIWr}V^KK8dVmAMY273%HngCMG%T z>wDPkQ&{;GtK9d#;2k9aKhn|Eok-laxLV7uM#+~$ZZ`1L#ac8q)+{@DZx23dD+<~G zqlLA5zRhf@b+~aohqp;YiQXK8^)bpxgP6l&%7bi;+#IG2FrM#J5zSZ6ID@gpvAf~P z&jf#%`SE3@{5}kbsYUXkAdlcXC0Z}4F0#7$%~ON;hDtkmU3(t*v7WVoWZ)-nc)jj! z78Vxj?AC$Nk&B6O0pXYGI|5+^t7A;GN>8lOBsIpGbLgs4ao! ZvMx7?a8_zgxfFkqD0C@oP>KPQ QDV6$Rv;1otF5fvtmZq8_yB+=j0pkaDh@HSw?TxqOYd(U2ZG<>51-p zYdZcYRjBn5$=+>Y83{Aq+iScMBEFdx_2R{`g$78cn@yqFw~5b~1n+IGl*xZHYAS9< zw*df$FHY&x3!mTU2MU>-an169HJ!uqdKPVapZizlmLn#97)%bHRmoQ%goz8uE?h8r zZSk`B=K&8XQ9Spt30#tryNYC`H=ZbYeEjLxw^6Va@Jl-`;=P2oy4oFsX>*HdV--sD zY6bd#7Vg?EKlU88S?qE7p3!j-sgq-B^!*=neFace-xn^zMFCMdlm_XPltw9O=?+P0 z=}u{+ySoLXI|Sj<-QC^YymPUB@Bik_oN?~pz2~gG_u4DIy}orepFtxZ5FXquObhwv zen4sP*}HY)y{WOF4j?zjz4w3JrqYAV{SAk*xV>eQA|5;dm?~rtLRCX;j o^)+U z`=+2&WX$*lD$s!gLKk|4;xY2-hy|f&?IAo3QU%(Le5%_f4oxxLrk*KtJ7pPXX5A;~ zBN?r1G>cOoqQ~)7c^fxBBBvWkp|I7_^@;j1a4bY?SR1uBHa-<7CeDwD#JW}{tsaf? z&0aUFFE%I(298e)9s2&DJO2I*T%jrABoH#NRYAJtv?J&HGurL`4lHCya5o(;qI!3G zzSNY$a>`Q{*50ALThpBrBqm9SED!CGIT( ZH zdEfgL(w&CseRl5(6ATo#s#&lXiMJ1D>f;-WW=eBffFj^(nla_W4pF?A3>B5qwX0Ss zJ@hAa;WMKcyhH$JP$0vxxbk$<>ogv}SCB}o^T>B>W0jaC$fkbY$tF)&@0QVza+rj< zM7yS^loe;wG=EZ(8ZUm^>Q{k2uq- nE$X@da0YpbaK zl+Kh!zKk&-;bkQLYpr|E24h_k3R-g8^Stq?Ct?BR E&j_`7gW1*3MX_ zS-Y23ZdT8H&fbPZbrO@&j=+z#BUhCzl_DCpkx<+8jP;MQE-}VDR1yQB!Eeas)l(qx z{2- wDPGh;tV99lg^^@vORxsY-Sy$)p^4g)OgvOgL*j z$Stj99~$~>lt!_Skk_SkEnoY=RktGlxiusJap#i*0(7t^FM$2=O`RvgX+kNd;Lo`5 zvEnik06aEPIfozLXk p5|17sj&My5icdyHw*#3-jy6C{|k12^rJ*+`Co`c>_!ZdP-W+ z;VgB9F!2VnUDR6>T!k&{C}Hlw7>)I4ycxxv#ukT>Xay>z&&stWkd;-SNq-JP4QxhI z#1*CSU24X0+XOE)TZ 9^lyGTwQ!NmK2+1YYeMHi zJbn(rt=b;F<5fq`HU6<`7|tT$fSFW@O)Q65Z!(EP+6u)R`>8k|4&eL|K(7_;016S? zxZIIRl#uB6 6%ju4YRk(r{Po?o^2e_x6jYpC5@&E!_+G` z!Y~-48?uQ(s6J3(JzfrxZ^EHK**%wQw{Amsb#`|OUM1C5*X?b``(x@?3!0=~xg5rH z;1>uVnzI45NB~`hrx?QXN`QS@9u!}BT}WYUoUoEIf4%h#*k?P<)>dC}IF*ka(PL;G zb!WFBJ$!g`ymeO?xeX+L9qB`Z$i$P}_6hc*uuJ_`5>nh=k<3+FFD(~EMeMtX3zW_T zxj#evrB#rAC~$M|>MZ8v+-B5omA&2dB5ODHC#5s?=<%`^UtmI1+7jjBqJi5W zXa0IL>YPq(wJezV{({ZPWsVUcW6pU@QSoJatQ1}1MJGF$dJT2i`6koJ+TmNwd#=ks zDOXCgLIZtXUb7bKjF-Q8IXn=PS<*`}r)#XPZ%2pNS1>zNLuP8iJ;ad?f<$r!ElQmA z=P|*#w1|+}F+ycHwFY~cekVrHR;G2Ht^K{xK$yenoAxNA;^gZn-f^xjUo-XVliQ{y z>myD5+aL21wb$GDb~O*}D?CEcv~+Sxh-rVZ#LU0V4)D~17)eLtbO`D=1kWiMI3B7# z>`_Cj55Ha(plRR`Ojc{p)jLqL?!7z!g?5ZDox b*15$S&5qp)b`f#vzAh9s#O}$@x|9bvhEh{2Br%saFtt)d|`h3c7a*c`U zUi;>2TQZ&DIMx%5u$9p@)!{XlZ86Ph )B zj^(STX91(GRH}Qu1=kZa*b^1nQT7cJA>fj3-Bk7DvB7AJu4Kh3jCL~BZ=TIcKz; z7gG7hK!L>h%D0o4Jo_hzdWAnUWvHOVt?~2o^U&7lY{5jxH11ezPkC4II$XP{-S2Q` zI4{NE*IX~g``dAANB&$CxyPx H7XIhy4=` zd~IX-=Py5l_*sRxtmUeAM`!Twe2CV(}GEhtgW zqxH8ix||{z=?1w|g+2*iOk31p1X3#U;o)}0Kljk~cQ4V2*s*lJPbn9hnV|6Zj5F#Z zWf6=XFKJPSsToxzGK_yL-i|-HVbqu}NXw&gom;?nZ78|LtTwLP<}AByRo%YPVE9a^ zT%s`TG&eXSr_pi^Mm8aj)r)t1B#cZRm%b?Ppv=r}Vmb6RO0jS|Dk2&`AzN6MnA7@U zI0HxqFy-&<$ZVE+ybckB{}w|6o_m1Ne3pAttcl=uW+WYHR8BerpE%1pYwH`Oa=Zff zRpY&2d4?@^3qrK1(|u47wTiWQNaYBt9`$}fcjhXx0V^H*i}pxa;kge@%oN4AhAK92 z{-4y9TTvMzPSVLS$Geu@AfOYk3hzkr00D@YPfKl#&9!=CljNv>pc4f<>Q5g7h-S&O zOC(+{*ku$4VJN1r9C4c`jRaSn MQAIvV5Ls6afO?L^Qm2gpQEDmE31v|J4@*?LGOfw~Y?Uo%<_W ztY?!?-nrQ1C0q;^_!lwfQ*L@sCl-9j;Ob=kFkKF1=Gd;tY rzUMsVPN@p8UZfw$HkSDao}4a2T3g^Jqq4pO+J3T`&G6h$Mj=V1+^=-SeA)eC z`+KuRxyu?k>@}{Si+l{K4ZebcF7I{OHUGKBan3nnPShA4#*@!Wl#dJ-O&D9 {SkE9E5h)Lp><8Q8q3|GRb$2C+0df>WEQus#BhKs_Tf3d=EHMB z89-{?@AVc7nHae~3rKzc7KtPU8f#06H!fgZ<3bv!grkx}%kOv+0`mjVE!qWFxm*2A zhS?R09ArNozyiN & z)mGP$ibxHqVdcn(bbFd)6_7JRc#ENcbp*rT`&lr2g!g;Z2;qZLkJD*3o?VV^^V}xd zj^E~;J2SDc$gjMfnjk0sb^6RVyZT;2xS_gU&4SEY0h6At_~xzP$6Ehje5%MSuuwkT za4$tld#Ne@r(ljN4AR*Q2Jx81cGSbkrH@MjRmj)?V+ddW#|zMsU-RiUo6{UGcj*sV zgC4wi={JT$nE>Yu#(|5GdJlp 9wtW%ZA6G&rw7sJxmM!Dv?^WCdtcHvF1 *|pg0?`xWX49fddmHq>|C{W#`qqO%8CrT%C(D? z-hEPtr9t@|beU=7j}{wMHkoTrB6R+*?E>v^^q8LDH2be7C^{e+dN<3RwF;>=s>$;= zz}ClRLb3w3{yd1zZPAIfLPK@5eV8EOwae8?X9T%q;v3f+`#9w!uZRNQa{ky3JCH27 zL|5(l$9d+5%C^uMP-0w7@K}-K2+8Ky(ouX@z^M18B+r8py&s&)pe>c0%+S9?HNac; zHRdjJswxdBHD*5sK%EiF+3XCxQ7!|Iar8ZDr>7mP!?7sb@}ov#Vq(ih0WG7OjY7|9 z(OwWGDhbWEO~wR9z9p=L&pf+Za!PSMv3hMeI4rC`cdlfj8fXJ(P((A_piT~J@^4~m zgzaL &7cTP2JSTEr5ACVpqZLLSw-o;|w#@)FXr-9J7`un(wyR zX#VQWcWEI#;#u#f-OWWpmvpTzoVm^4a#%syVSHWF_g6}}D~G$&Rpx-V2RQl1>-|X2 zpC@zL?Jczh_M@x&3pSO&Lm!H3d3l5Jr|et2;5#d~lztu*s#X R3t$E>RPvAG5eOn4r|Y3FzXR&V zJJj${zgk0k_@N%u0PI{7E*O5)Z3N{mpkUqhcr3^mz*cP_b|C$oR@cwGBb=8}X)mnh zplO3}VstwcBsU!;I;%%dT>L4!ZzjnD67{a|G{8c97#+o8)s1I^K`+|h?UdNOm>h$t zD`ykBOvavBq%M7hP5bAVLpB}lAQ)i8Hl)-XqNqvsC36EUBj{5a4?OHxL;=+GJ*txZ zeER$6F{wHZ2IemVGp4?7by;>+WZ{}BpXNH{(^Tk8?sqcfb44F6rI}*G< wx}g>Agrov$7ZILNQ(eY+#Y0bP2abQd=Z%%maqx=^;+^3Uov zphz8n|Ep0bW^9iNxmi}jqr0u&cNNA19`Dt=Pui%p!!4%8dz6}L8ZYcT97L=%H1=vl zxvkYU;GqY}0FZi0%KeZCneb7_0AL9dQfhtWMFS$q`L77f&nbZ!L``!4G#N4dZcq0C z)1zOxZP)Q#B-#;thi=JLG$Wze5LD$q-kM2h0aRs4CK~vYi@bYaOmnsHk5`lsMG5D2 z(*6luAd UU5T9tXI-xD=j7Fu@~k>#wYp7b|}Fsvtp@ zKVJa8OY{KcVLr`6Gw=z8TZ~6;$)pC@QMv%Vd?NM7uQ~jEyLayiS+;R_5kJ}uMWGY{ zB;g>msXhQ;5|LbJAK 3 zK0+ZlFB$yp;e0`y?nJ3e5dB}iE!eLr_K`<52?JoGFOyImXqsfxLxE-hG))S`v2n6^ zb|I)={!@&loybSAT2h@a1;TLP0-OzStCTf8{fZ4;c5PhH+FPL8R>!%7cKD5?|2s?( z8U$t6vK4_5#;G@B_?TzErxdbSuK)sTm(J~Qy>ny?(jkPk`e=^08d)7W-D`C~r{jpq zS8c1wc#!4m;C~)Y7^(%KRKNx~8^!eRq0WXQ9inoRnI&qOW6k(;J-SR9LQ==rUJqmY zg7Sa;>HzePCd50&**T{F&@#P=jO#6~7as_&qd4kodXtdW8=v3P{2(76D(d@&o6eGi zaUP8RUpPfiDB(he^LvJ&|4TCc)lsj8*_-s?V`Kp5+Z1#_4psl;m;BR z IRSNRPS0QN+H zgm6mf>@=3!snSG~SFbBlzzWHY5Lpp)GRvpyn^ax;QintU=&e9BfC%Z#0#PGiP{*_?dXb25UcPfb uxil{n+Zpk2P9n~Ig=t7jra7KC=hgu2v2PZEb> z4?rSr_Z7kiU%<3*{V_*N;qJNGmvD3`Z8l-z8*k`Rh=s_JADvQDE9P_Ea(N`SMukF{ z-iV}lK;+RWu+SQO@3bGHakKe)cD)UWT9~_G-+nP{U1Ko9#%1ELg-luHn}Wv8$ z9 w;uWGI&U^mzBF#;=VDi)!E zqmoc}=euZ3fNex*hD*qm&rhfZvi|t(-qFVx@hZpwI!|_AIdeLN!$O~n({mT1-NZtv z$8Fd5SDHN;c=BaNm+Tyx&RfOzZOHw?ZdWoM{O}Y%Dr#vQd}+jZtS?&kZ$@v|q 4_DpNjErF&kmkuk5VM2HW(RQwKQ}MR=O?(B^>8?3@><23=h*#$4s2 z-L?}hi?m}*`!`ziNbWY`d`D3VRA;6|0|!m5Y`Ot_SW6sa9o9n)6cRlJwV!m0FTWz> z8>)O|-%$ )?uyq(XJ@h-Bw z$&67to!8hy$8;6b2)Ub9g~>L8!SiJnQ^2Z4P$xB|-)t4RyoIGVm1nse#H$Og&X05T zX=ar*PyFj1JgR|ABX}F^dkCmxCcN{&dMFVVw{mLd?4Ypb$x CAD;>#+N_)Tiq5V-!LgabS`(BLsexz-n z;Q$=ko6QgFOa=z===*+{_G9AoZmX?FD5@8Y$_F#Gg2g)@))nvNYqEPz<3^F_Y4Ixs zs&*#=yPM9^_a(VR`SlWntJMAp{e~2XHY5pf^#QvkB1G7rmB%4G#nPmbB7EDUVuiZ% zio~<-kL~0m{0W@b`(jhfLbd=OUsA3~GGn3h=avo$Ji7Z)_91#ao3-Mxb?Jm~%e;)f zZiTYXospZ0GiYkQ-NaY_$TR+e?i&``+*0*GB-0|!7m?ca+Lyf|np)F3*4K5Rcudrj zj@GS$r|fD|n}jlk^#mqv@@ROrl3`ll{GTWufVD!~__%}sEWIl<61tmgZ{cZ|W|O@@ zw>8Va<#JARLCrT3i%;;ix~``vv<4N^w&1A)N6&4=yQ?@X6^_S o1IW!f8^J(ua+S~j;#WWi_h7Mt*EOW?R_SBz0}I60n0VKf=)64$lIZ7( zchk9Mj&k~E?`3bhoZ`!CA01Kia*w3q%Hq2&vg_38WLVq<;%(!?at1dLW9~7CRz&0k z&KB4F$4wm&G8CO-&2yd&zq=&om|Vt>c^LA7MCwA83$NqhM;0F%ppK%V@Qd%T@OImx zBdr=`0yY8Xm9gF-8-c_*i=S@$-bEc&vPE2uf`k1a)3)nKNnW#}O&7$C{q}f>(3Ix) z+d7cct48DGBrNWnTYu((kIu)1iv99sEzta}!gw4wK(z-L;Xi)-01_R*UvaL7dFRl_ zVj+SvtR@gWs>#0}GzuQ!aG1?h13*Ky-Qy<@AqBF>d5X)~GPl#uwBnsPm;HQs_!VWX zqVH#K7&J!y;d#H766in*Ft qK*m1H G5J*2A7llDXr~<}`2ol@SWML>%(OcVGbjxd57q z@BqA9fW#ZX)o6UyqjW|vO&H1riq%fy>VGNqpK!^O5P7L*lsJU+6HUv-P?i|bStWE= z=*xG1GGH#=z-=78!Q~zXI{5q>8So+$iVUzPKabmXL; ffm0`F_RRH8|;^deIeLVf=GUcz;dD-x+Or z3n8QSl9dh&ihlv>&i=*AkdJ r)#d8n&
x5V13BTg|2} }(@n`5 zq#yke6$+Y13Tm&UpI2KP8N}DT2@+-GPwwxSQSX8!__$drPFJI<@nT=WQP)l=aRIR` z=qGdTPK4BGqw#Le^<-|O*Bi97F=~V|nWbz!ob6u8*&c3FWlxsrZv}6WAfx?t9k4)u z4sqG_*X98xh>ncU;ElwzAjjiA4OQoF^}!8i80%m0b7czlqr=Oj_GC5Af2c&u7tlEQ zEQ)7Wr)7Ln+VpL!5X#u*xevXZ&hTwN+Nw55Dmq%4d|f|Q&i8R$ZmkNOi5 *U{~=mV zR=II>)R-ienEDNpZZ^y @C!u#kGB3EGe+A5pW|4@}Zfr^We=S4bz>xpkVL{hiOc-?Z+ zZHlsB9-Y$0sU9U$!S)K$lr?F=lNm(*iOFi1Iwq3&5!T_f+(&<=5bBX88S+ARMC%Mh zGn*$tk_zAT`Ws02X`U+7M(Oj+(+^t;Q_|_!iqBbAHag0b?pRV&7i6Tkv v2$RFd1Ncdu61zY9)Flwy5!u8+eD) z-<6yva^EP~=Mw7y0Wz3^Cbl*}uWMDES}wG5zR%G-RTN));t=uEEdFt+eD9>N(%n`J znKuP>N?WE{yiPfFYpbJddNGMSIcaChl)011@YolXzqdv{5P|l?zh2R4%LGQKCdhY2 zn>7@m^45a~rThcNOOfFG{Dc7$HN>PyN%-28o6)YWE$RM=lt?km7gK?x19J_wF!R$U z-$XWbLrh;TOT+$0!9|;!wv%4Z?uFzi@_k? ;c@Q8`VVD|r*rpH zT8ULZ(G(L3f1#G=QhE51;+KVa*wrCuaDI-KSs_v=!!VFJB!93O%E@8myP_`1Nv<@S z<$fF)OAh(yMH4+slNc7=V#m41mTAcW8Og63b2x3GEa8hyM79CE}M`Bz$_pTXD} zc iRoA%cXK|wc4Km``KTwiM20!!XU zjvRCQW2)y9CV#fE*2xB~J}b5_`8vjWkHp})ZbOESjD9g~G6A@&U9rWU1GVPlecWjM zaC Ndrx~42_-s8RE!z-rS?s#)NwRDwvtz#4{bvD9p dqSjg+NhI(Rte!joIzbbB^$xuQ<;@PujK(8a2J4in|XCNdZ*qc8GKXtAt zF=uMt;cK>nKWX6gx$~*?bqnM=f6>ec5pIC^z(r-Mzous7s5x8WTs$^)G)sMi$f|;# zcg+BQ=T2#*(AkHo$$DrZ*>3jbr=qCwjQ`BwudTA{0XPgz*Dkwx%!&OuI%l61B=a{H zXh3J9mBJ(#&I48Se=ei>9Bv?=xYpTRBUajpgzqVoi|eygaxU3waPk4VnjU}uG~$ns zLxbCWl4@wM(G4SP*{j1#2wPS61?PC`oJS7-UB5&q_V)7Y5V|a6Z0z^XAJ^;kJ%I&! zHi9Qir4aT?rax49q&Gulj2Ls*y{KP}9Vjx@LY9NLr{BJ#4vvEEwW(c`!?C`O4hcqw z)ZPWZ;q4DKyErIr!Ub{Ys?5S1DHb(714foG*z*aHNC7nkgIGa)F)Q 2j*ChPeoihyN@MMDMJ zwf@S`sZds`Tz>uhxR0;k3<^!rkGp>GUOta%vFKqI #Q5!r@hPfBcqd96CWT^xyeYL?)#7+>v_+272daEF*4^3x?D= zd7m<%f_l*0eNB>s&{QCP-r-OVMI_*b{KW2^J-MGrF>!P~_6tX+?{AzeY0&U@@Mi|^ z>AiXVPPHdXq|-sFUA!75ezgTmr}b4hRw0*NTWC#c`vi`G#2& wN1>bLO+cs{?knyT(%>k>fDhUr32GaqyT#7EC5WLq{ u*%7e*18gWWYzihM$GNH4LeUYvGiyREP=9R$IVz#1CvkiEVJw%filzi_5(REL zuw$G ?AurIT;cT_GyCqsNSwg9EI37t=&mU}|B z>L^Y@p+G^F8joVB_lZnO%Rb$}S5~~6O{HBu3z-$u07puOZeeLQ;?T;?x)*MRsU<%J zb|%U696>kNfhn%0A0QI)S;>hLBgI8)RQWr6K=|V*77(CC6N5NA(M4>%F*^XKcklwx z&!jVoPV!7ra2JPBm$2X?RXUCy`$3lC98aAL0eIHv?Y`|9odA7mSCd&-g$#kH8e~h7 z%gT?XL1Q@7PC1=n8WyR0THZefF^;ul1>&FRi=bN|Gg+!vXCL#{V4h>)2Ug2Vi$=sZ zY n{AW+< iTa+z$a;R73`KK4Iw9R8&J_2IjWf^r211 z!_f=Wl_xl|>}1Lm#b3TX0~c63?fRJ6SmXrnv<|GBwN7@V`xd_^A(}}dW9Oo}Q_AeS z%rvW5-x7S@)y#U|>Eb$kI;RbnWM^#k<>No&VFe%Rw4>$``WT3toIszyM+_(DQQeQ7 zCU8^@mqLSul%oxcqPY0+mr3arfnI+$)M5&Qg;v5mH!C%c8f)HVG3GvVeG1{jqq0rD zapsoUqN3-dY>op+d+iYtRW=Bz){|>rm*??fx7{88>dCJUnxw!W6;o&u6xaDOMjx>l zY}YvTR1vGjHdXV*+ttlzO_ZZyr$*2_MzOlmH^bJZ4K$Q3T1j3vMA6Qh4Lrs87v4M= zat(pz4wob1x{vv^AUW3sJ6`qWj9|mnZ)=4-3dqNX*ApWQc>g1T0Sbe_Xd)?!C08_* zX(=Adf#eZ}grb7+l(=!Y1WZR2Xj4I97&-Y^*{XV7ZiweIN0D+#&Vw&YKEa*Vg8#D< zf7@YSAO_tbLTWK%(!jyDJumc#Gz}~jDX>LJ=&H@vM3IQgl~9d}Ple*8qS&m9eA!r` zglh?=_37=*S(zEnmtGRp*IQ_H9G8pKsi4_2sGOR#d}7g1h1RB`5TNislJ66{w~fx7 z)?1IsSW+VR%EaqUiE&*G)@k_Fv>q{kyXt3F6X`lVF81-7Mw%H`Cbb3Jp7W1NY)?$# zygs4y2(L?zRw_eGGlOUFi_@93)@3FB+6yzg Yzm3Q`ccN^!_shuT| zDt1pbYh->+ko?raF8|mUsPyf%ZnVZMG0ZaTZ8K(T6XlqRoew9kC(A;L;SVm#&As|Y zRBV&?JtFQ#%F+yjNbVv;<7K4<#*A@Re9wAolq15|bEF3Ea|_YMoWRFbZh#lirZc8X zNp#~;*6@dhvw!KaRI_~TeIgZC*HCFnQ!vd@>edu`sA@bV)R0?YPp3@WSQ^l#e;&o{ z=YLK1OyajzEChm})05RU1CNhZ*= =y^oO7$FZ;9e4k!4*l%xbg>M(yZ8 z*eoZ;QY=TQ_re&~-0}7{U&0WH3c7PQ$LtWvdf9+SHo%;esu8ep7s%**&BTy=E@50> zflIaiGV607UedHunTx5$3xAs4>3avEQdN0QQ({xEKEpG9 P?H-}h!tr4TKoM)xR4;+(-v$x#6j_P9^(q6w`jph`O~*o8G_etSE Ax{?5lEe=!z8mJvy6vuhs}AnRF3T@vecKmf7Mt%9lw#badBB z4oNpu$#~1?!$AA8-#U=$f(B@HRKKP*p1g;e?>gFqN7kAQT|h;+lvrKhDMqcGr8{M% z$rg?*6KrVbeP(Ro8?RS8S65$Q31T@Sn5{AdqzmbXAMcb)%!jR;_XUwNNj_CARxL(B zK V{9o<)t^OJH?yQRyH63tC4EErd1dF zAJE)$;CCKeZbtIE++@YEGfq!420;HF33>LyF=zqbX`940gmc{;vzxA*eI_`Fk-XQa zp=KZb+j9ZmGs#qj0?jS6NAHwv)$UCeT~DHQ;^1qYL~*0Su()GPC5xz&IaAIM%i1Pj zgnM0_8V{2fYo}V4f(p*|Ia*jThB25vkCY9An<7)iEOO+!h9c9CtVX74FD J*I rZYd%|U zcNk8pWymSSvzscxUiOqk`x;h6>-vaKld^8O*q8Ke%6=|wZuu4|*Wg4yE#bwqWDCYd zt5nXD5ZC42N-mv4xWqvVOOdHOVt Czdl*rK@y2dV_PoX+Jh{(m0TJK }cPeV Ch8adS`FfV&gc;eVyY7mRxrPsawa|dzo zkG2vn&_H4cK~#XJ3gY8SXx^Yjf1)tP>RZq3g1&t++o|F*KOk~U*&qFVfbA8XDnM^C zGCE1xagplm>>ex3ex4Lb=X7)?Mm^K>ZUDw$f0}=7lLig|E%da%4(BWgcvRqwm2Ff( z355F{=wEXBl}hmxE|-;v Uvp~DBtDT z>>0Rm*SKZZurmHd*)$qd&uARTQTXLP!E>P1g_r_mE^Uvask~s`Sfz%%l-*qNH?82T zDOV=UH!cX0s7g+ryFY^WFg|Km-EhN-MU$y1L;=gSsT_al+$8?i<1#(IY;67K&8PCe zIXiIZCS%3!OOpAJzw3a+Wn?(XvT23cf%{>7dYZ&4Z4~$sU >5u{i(_T zG{5r>CO{mf#j6s|vmpydA4|ZLj>!wxdAcS27j-!hfPUY*>MsS$3P3dFXwY363ZiZ- z(yN}1%{O{aq^Js!+19tpUO!!f2#JA>dPg{!FNz__Vxy|Kn_U$<$FV;ll*P(O)R`96 zu$l9kJHPoaHnK1XL4P*DFw1~?az(kLM(g^Xcr}^6-!Un!C`FSe!<)Q!kT?=sWUei$ z{CsTO?t3ytJ*<4opYq~mgfaj;&|2l c2|t&lat`>8Qt7Qh6Q3AUaCa vR z`TOd`gpZZfFZuW&aAq=S4gvu-KZoA&%ibB8wSF%pG-JtQ1{h^BVS;0!LeC`uX?vz3 zx5_kb4t*` zw8cigQu6J1QXgBXXP<&cNr^v#7 zSb2PG4w{+mZo0n3in;Cc*RIJ`CHuCj_a+V(7J)|ug6tfXXv+Y)SVSJm;5HvUnen95 z%2A~yK1%pcEr3NBS`-PKf3QgBq+&h$7g~6;YihddFBNfvwGp|Gg}R>{za(GMXPx4O zrQX=V`h+6Ck=ffW6+qapp<1u}eEc}9lBy!epC-Cg3JU@g!RXoq82zAKzXA}?6p{n0 zTiBF@h$whiubXV06`g#=1sEwAsIu;T&3)GO{S{tSl*JFnruPkO7lT+Z@6vDU&OX0) zKYhED`R!Z?3Hd-D+7*1XoMiJ|_WuQph|zulM$h|y0_r;816m7$+qP2t-qh5TlA?(d zzxa3*z?%NQkkAsV3flxUBoi=#cG(X}Yf9T)oF_i*neKJztzbfdjWDcTOxn+vR2%m> z&c1&hsVM=pVimu~O9aY~fY T$p>Q{H+9menpOPETV=8h(1(`4U2fhx{Dzwvw& z{p|C%3UEt?b84X6=SxYNi@7BuN93Yw@{{ZG@)Rp8|9hAO)>)>Ho@fMKcK+{9ChC&0 zzQO*(QIQX zwO-s@ekD7o7vrF&e<162^0cw7q(lu40skGaO?
safS_yV@~*F6AdmD? z)A)q_Ho(99?1DOouJDq6Z#bMyuqM0M<-4C0(MDKWJq>0qIr}J{Ps7%DO+r~BUDalK ztPwdv!As5?W=_kfTM~lp#)W~?{&|+9NSL*-^o9Amn2n_XMA}Gmr&SmH(e+vM<4@1( zSJjtX->T<@h*GkzGp|M)W2wjICME=UQp14+xbsvm7XL=53nCzGrtM%o$MCn`VIgty z6w)J(MSo5mJja KyPa{faxuVd3 zG}dsREeFh!kAU949>V|P9bU(*{EY*Z(pe~_YPD#prC6(>4cm;4#2XE1|F%($!&t3X z|5X(`v`>xJ@z*+cRdckG*@x@PK{;J*_KXz)_+;M9o6(#R+E<^Pm=vcA#L9=yEC-r- zDO|~(5gDAe+ocTebeQi<7<>k6giuSIL^#U@6a;GTvV;&ftD!j5oNC_EYl=%g&FO7R zH;iM}+?Lc-y{VmA*glG7aOiloxK%VRa4e@6uX3yCmbFg2we?xJIv>ZZ!4Cj==pB_9 zFd#Eh{}l@F+maq;s~Q$sYKWI*jS|vNW3+?IvfJ{U-METJZ`0MOu%r!%bEv=fYjF%H z)tojJ=Dhj2Sc+pEcHH@;YNhl@zN?GONJXiSzc@QNQ++M0skh03kT8FAsyC)DHUoWv z9{BmOz )^1E$(bY@lN#mz>jc%1Ue5B;1p#$Dez(>j!*8^!dRcrQSDJm%qIA_)M8fHNmmBhv zmkP5TJZ@dV*B>V0gvTASYM{^O66o(TxA=Lu>_PxqNPg6OxTZufb5qv4V{ch!YDUsh z%!ChT#6Ymou<`MS9AtAIyoB!IHZwCc(s$daU5>8fw5i`cl6NbPgF>`<=5bV@s7`_{ zV@f)(Jx8a`xj4?NYQbKWa$jhtjQO4j?0!vf*0hV?w4fT5?E0?7pj&6x)FzLvNfnVP ziyl_o)VT2?qlqV^3j1!A+mu;KEkm+k`0{f%tYwG8lcu7o;Vo;|0;&VO>3ql9tbr1v zFBbfp!feL(c_-yN;FQo|G-3YiBDVrZZh)M} 5s{Bux9eQA1%-7BoCgWKUeZ6;*kI>rxdS-`16My?gvGio1JRGe;ZVwSfo*B zTiDnd#L5UV0^*MmPzSe<`8S`XXs3I#b4%`}a2<|vfBK~?nyzQ}H?jL^4SFpqPF2)a z81b-nTQZ0PGb$!05 cZ#Wu= z^Mx*Q(x(17AM}O)V4Yu6 J~#DQ*T{z#--LPYdKyuu+1DHzAy1Ju6OEtHO4}?or&$Lc&IkLiKRWg-o9KD z^M?a%2+%FT`71t8;=HfhZ>&>YcXuFZNu v 3-ax;1}!@P4PS({1!3SLt<9xCCp4lNE}^hZcSWxRO%R{x}9^c{$0gN>xR z%Fxj76??8&_|NkG^nkTv8!oodsQMS&nE3K4ooIVN V4jpvQt;9~~@%jE>1FH#D6vG9*7 z_&4+1WWVf9V-Ql=gBl}$m*hL2_dE^Wc<|eeZ{08Tkv@rgM@tnv@5UgBL+{_=+8JG_ z_Ggwk$z=h-%LnngfcY!rHqNfFMA73j!y+6SbgAubREh&fYy(_GKA2GqkpV@MnW~M( z@ja;k{P(fN`Ri5!^phTvAg{nO;++}Vbrt5PF=IE1=diw!P>k#c%z3FE^hX=qNjX_R ztBPZCmoMXoK5UAC5^X`G*Q>&kUKDpHq%yHj;Vz&atrq7XiGyT;X@0nhNd_*C4}tE) z=q~T|5ZI(}m#m0 dCeIWt82Gej+h*%FKq%qmZA=%^yM;GF*+4|D3 qt(>h?=ogk3N9h*=#B z7LM)G8o^qX5U(sMhHBVHc4(=%EvRZb1~SFebKf0I_1ntKY*CCWi+gpR8$n81n8Ih* zlE%!id1)dz+xu4Flpow36Ug=U__ObN`cCZXv}2n~{W=!ncR`xV^pPMjAjY`W>vidP zzEL{(SeBErR3fT8WU5KnZ^)>Rif8Q6F}iRJqX}hag8)YMBcr1Cl(Ci>j$us`DUF4x zF-l)b_fbBVI(^G*7xYw{zfRQ>0v^~7GUDx>QKu5*HCEd`s)M9fx0WaN8?uXZ 7Dz!$*rj+KAca6KdBHD*LN5@liEoZf}wIh>r?Ob-{w+K)Ae9U(=_6C5% zjNdV%8FZhfX=lAIFK@grP~M2<$@5D^*HLqes7O7Ke2C0;)QTXdAHRQK2uj??r)Kgp z-!YVWdFBpvr@*nu^dWYXKC|g2zB16Cx;t3b%!Zfg=`+!Qb(z(RLKZn$;mdLvpodx6 z%1eGWqpWX=aU|ev(sQXa9`7wR!ct~wMTHUye#&v6Z{k`sLl91>^-KQt921H>mff9i zFKM%YC6?&8J$ho0=Z^bJI>^7DpFYZ=EwT-)_y7$NPDA(?PA7b#PcWH;r$_`3-(bYn zqo~(F#a&v*Y;#T?N3bF>M9MgbRC##2G8Q&mS|gPAjoE7IdqCpRjuH;Idlo4Ai7bXX z`Erzf+C3bz$t_6wp|G6Bc+Jf<=60}KW!)7)`@>&A0_sse5%R!kA9h MY36WFynsH?vKD43An-Lsd6{Qmw~0SL^fs>0<;@ezH4WH?2{5 zUM-Ibe53~jemEoHN`b;ubh=~m^oA^!I3d~bmmbi^AZvkFg%c&{*LqgZc3D1zBNk-r zCf+qqUVn8S9}_8)uJIr0xC^)LY5%eDpn@7wP-*Xq-MnI<;5vY?b@|JKR?@v1;FLKC z5|OgE)KD)K)inJ$W?Voe8WNeeW%2Zn=0bv7Ng#Hd6~U O znM$Gg_CtZuo?ZHxz~9 t2 zAv^bK CJEpo)7Rus$4?$9B2#=-M|T6a7KNI~>jPX! zSy@?r{?;t97zjBHcrztXS9`uQdAxY%;#S`*C0k0>ZuG=fK-PB4Y_sF&YxQdV`35bR z5$z)BnYWkM;Lx7>iaz)>r#0YI(YmL(RE7jenO$FbzHjbVQ4S@$?cA$nke0S^ SsjpKIIvfftusgJo1_by#W#_|lqywCo- zjm+zpe`W@lpJrF+M^TzRujXSPw|}MDv30AzMP-0~h(9Sk2E10p9pmC$)XqvQiHJ?I zvG7jO6Kcp6NMFfuv$B@$#pZ|j@D<8tyrNvm;s$FBZJ1igx7-}nUg|p;Q#bHBj4P59 zYt-4_EwOh6`aJ#jRG>cm4Bx3$)-&k8it_6-9VEDJb0@<8_w_&PhyzE+62rztIspe! zz&;|a_$4t}vy+*nUV3k1*0dp2c=0 p5ks9 Gtr$BMn;BLX)odN|~+Fv28soDcXxM!{ps`C_s=lQ&Lp$Ro|D~k?#u4( zQ9k$Ldde}QQt6A;7BW;$mHM8{`Rt^^3lvRq1j7YZKfz~T*(bj=0MgyP+d&)S(cPK; zF+|2UUXFU0ZmpaZpTN@tl1TjTlATMiojwOzn-a`h{|2>eGAgA)ddW_m;IuEWhBj+o zjPRtmt+$VnFFA$oXt9cGtcL~uI7k(&@DV?c*sBZJgwiX(C5K|GVulyp1Dx!pUR&-t zCVX`N{r&O!`EoWvUo}?Q5MA^Pm(+X{e-xDSJy9kMGpQ;^d(Ci1v!cI}co_Nt-j0RN zUivALrBFe f4(OFT_8@h|Neyob_zv?uYl7gsg0GzMdPgCFMi)fW{zuYg#NH zF5rnDVak#T3FtYG@;I=A1%tM&xy>^F1+<6fE>xK4pUV_ncz-H KX>3S6;MTf1!tj*@OFoE0?^f5LQ2~qVe66}@yi=?JMe0BXO z#Pi&K#vdPVb&NH4tcKH`Zl52c+FvZG2C3XpH{9IA8u(jJP9)(`CdC~N{k=b$SZ4%a z=cdcm?5W+L_8K}M4&}U0$@+R~?Uq4t>o#u558RN8D)Uy8XwcU@x$iSfe}Z+*pKi5g z&zk7zig79pUfYNgpr7E|(Nl9@C*9wWz_?FN@*6(V{EIB8Aw|?_5U7B;((+{>XTRf| z_K_~GA97DiqyRZaa}sh;9z+O5JG#!5xL92AoMIr>y_3&|rtu&-pLVWW0DZIM?kNRn zOYS!N2Ee`4ZCkG-R|mZ~?6X9pIJ2J9ZdT?(>(9xQC*allCWR71tXfmsD#wLc@+CT= z*Vrdm51VciSkj_uFw4O b zOuHp1jp$rHWn6UlyNdoi8_7-@!>J%{u9mJBuWzc`jaf{+xricYnpDZ*aYjMd2yJ zwAO6(R$!_QD? 3-XUC@zoTr7DAfBm&+AD zE)D!bfV6B!=P4KjGp3&=rM8Z}y>SzMm;i78K9KS**_|tTr-1EL(XM~HL9inE>m9-E zBKA!p|NA)4MfX<-JkmmqIF>feM|Hk{
dW2;0NYR@b;=@Dm--_Op@PR6;7J~UMG3N@x@(_!So?6@k>KJ;!-(F`X% zQ&m+>s)wm8yS6Twks>@aY<$T&xuhRYOj3$^o1{Xi@Uu*`^mg%0(-kq=2{Nkv9+i3W zobgluK55zo-(6Fq(hm9z;NoYr)fX=zy-n7GEiqnhgVCy-kPB24ye@L_gmjeU()Vx9 zPrhdv?oS~k6_-{D1Kz}@-NrRTqb{4KaNgK}wRENGi17ibw`cn|wFzp+JY=e2$Df1b z_NM(!X)qk!=X5T*;ui2!9g7bscH-}Q@R?U`s~&g}vI>~JX1=T _HkwiTou`K4-f80`^+jM*$YG$M@2aTP#s3;LmQj zIM|c9L#aX@zOC;$ekj-%{^&uh%^FXn9SX|hD@62g)j+(6pdCn9yxUDhm|Q!px;iw< z8U5j1w7d=iQHEoQi=M99wk1|dP2-TnvC~Ov+>DDBV}^CA&qXUXGN-Lk_~3u>MWRz` zI8|61rZ7p_Q#t*3pRCt0ah503LS?WRM# Z#dZT862&UtvE<{FnGj-;RO?Q>(#-& z$9;SI7LfqSpQmDQ3P Hi Wu`z-f%Akto)O8wFy*+7Y~+WQ+xFy2Wslo-Qvy>&YEW)L)i}4oV$Iu0IT)lW z-dpUF?72c&7O98MoZZRDrPZU4js{mXcNu^o18g)t!_j}_pj}Gpg2m1hc-gC3s?yf( z;Y%rD?Eircs%Pmd{I*K%14}7SiwkJPU`Pg811e($?5G->k$3uzITfmYrSKfikqwfK zJeKtSlvcjy@$-s#d@!IsDP{wV^s5vrm!7X%#J4ncJ|(faPVrY8I-$qie-8`|?pLXd zX9r@3JHI={LX71P1Hu*{e6C3-k2z@c#h64KTpk9b6ZVf0R627P&hb5SIZV{a;(ax@ zll{faXH|;t+T1^hCzy_?I+3@zUp( fKtnJ9MV?wTtR zH~aJJn_DCV$ cgN1C3;BZh-K;|(fAHycKvw jS>sCDIR@x_)x@Ms@JrG9V?F zW4D;?4GF=FIx4 ^$Lv6pJFb3^GIRAMQiI3hqHXEfp&b7ga_KB$tWP%$#KZGL zN_AHPXq+iqcKc!1+fo6+(m6*B9R`MLwzT~ik3>gqb$>Xm2MTHFE0bP@6tl%A)q~AP zmpG94)1`~^or-8vdG9uC*bhI{S=+!8Sluro4HEPZBsY6zRnAfNRxya1N0&D+YHrjI zjq^%eq2wVFo2G=?9ut)IOA$r8V&uLcu?ibC{1M_6=3Jlt#iPq1?E_|f30BRrd3Sm* zO+?Dw^^1+dqCFg4@HiVS{#49`#M>mkInHaN3oa0jXH B<9iXZ`Tu zGC@7`9|^G;)+x)4dgP6T?Bup+Z-<$iQ)P==VrdD<>3YnWRU><8c|4kT-eRlSwsJga z_z?}B^EdiX2$I`1jz*7Fj?~+qgeqr*ov+PxzzU ~tx=*xlc%ICobD+0nRT z`n@M7)oI%?G&wm_(O7BW^Z2GKvk+2R> DtpR +WJl2E1YXPAVTYomr&&jQY*7M|ICnc(s!%)ec=W?9Q43 zr{jHBu^H$C1HCa~MvV#!N|?%uOaKvvvnH!u`Lx~m@DW3{Gw(++z1v)SBcx> iHin0At1(c(ixiZjX5$M`q39k$B+DIJ#Bp!yb0`yd0}b!u;2mzp$Ly{)d>amxZ># z*XoBGed7!S$A%HL`RM##C`<4h9C4p7N-V0fFQh}uC#s_A`u1d8oKY1&<}Ef2@rD&U zy!< Cxo@F1lr0#sWL*D9H zz}*#IKNmXL7HlJ*)Vyh1U5kF`M4*G7;~Wlz&}3)Q^kR9+1>4RmV5=>CgRHSsxxnv} zC19W(KRv1{Gl0jecVh6$m= 1@p=xA35&Iu4@s3oW@iOE>%y?( zcHdEP`+8RC0izG+EF{B7htCa3jR|uZwVQ6Q1KI6)n6y=ohz%7v3k@c-(I|C5+>eQ~ zq{ihG@4y1hDfl$MO1O$z`@FOT7FTl>B^>-}zu4gMU1R1RYMn1{*hHq>Slq}=e@7E* z4woqltIzmF!m*6ONMjY%-EcUx fC&($MhS{T1K@Jn#lwDIYauIpji@b<(x}Osb*r@TY zbY%2g)ys>>xC0(C)~mU;)gDIw?Cpizbmpu|%fpev3hDN?^YA2aGxn~ichy$e@>r3; zp8`i{;?C#h2?gn~-!Joyf5j-^mJwN<5XA=S05;>M^w0I?h==kCSP&A|bE;lOI1$Y8 z8=1?a8J9V)qNGI2vRKqTxxJ_s&_}zwjy=@GxJwR;c{#6m?2a0F+~=Z5y*=KW8<8rw zj(F$EP+FaNMK|kg8ODKGPnfLpVwo@9mr0nu;ZMnJ1Y7nuXT>DLB71eG1)sU!at~M{ z&1q)FPJ;5ke0(3ew-W#Y)7Me7iqgY&?(R)ca(};1t8e_;UkGR(7vGKJi0@_6q$G@g zv!>SNDou)&iXA svzpuFJ4EjjNIPm&>uHsExex`&syu; z=6m^6>wa@b>ghC{h!5XwV82D;Qiu=vfg%GqRp T!_eY`htZ(2js2OKI7 zJ7+un3^t5U1SF3*6NKwe!HZk~SYzN-M0NEzw&jdV#=iUux6}0;%WSH0xcT18kVQ{^ zyvE59Hu=YGJ~#zXEx7`$-%{7PFD=ixxmDXn>(zF?Jgw3=;Y||gra%KTh?BBW^C^4? z$Yy^33;){yHr7|Q6lvSXbgzTpq(h8t!>Ob)z$lEpuWhWn@O Oj#y{a!Js|7#nq0k^yp^4-pTDUn)$-ci@ zB%ISqr&t$291~s522j1>Ec=)2Rp|edz22`kKC+$%a+v>1!5X9-{qZXZe}cw1GPUmD z4P$$HD;q$AZqS`EPSsjGYPo8T#GInZ`k;5GI_ksT=*kCk&f252nDS@Um0Ds*OjI(C zPex;?Wu698d84D+4M0UC-U?7wlm#S!hmEI)p~?v4|NQyk9u2ipb7(S-^I5^ct5?&y zBGI{deG-?1(wpWm-XFJek;LAhk#K|_Xh?$pnU3 j2=-BR| zzp5xM-aM#BPD7A6Jnc0zM80m;0CPIAA#>kfGV;2;qU+UNXi<6=6 MkXHDZA1=b=aZli>y>ol6#}&`%>!s(X&H4$w4hcuA-LI7Y (eRqKSbk4N=wNm*;!6S7;;VRLac1s*FTxZlb&3ljKj z*Otk{f;4Cc*Vwec;?AaBN0EIGpKPL6$*Qkofa0>)e1qdH=A9Jhdg#`{LSaghE4U_+ zi!u-vZLr$_=XE@tW4ha1*<^|7BuTB3vM@YH;} lzUZ?&m<`M{a& Kq(T9P!8~FF6XeLbV{k*1_mQdm=3(GG$n$;4R8&=+9Qeu)Z$v4 **$yn{Txyt~9hE<`dwPBpUwKd7!&}KO#abM%pHrRp0kfQ;FV@R2?Bz)@Ky1Nx z;DBG9K7W92D7CG&XZH55#8?T(MVIBE(Pn^VI<;PBhEX5Fo0@DdRvo zqOdy8Va_w<$|}Cvg(>!QTDgHgbd~GW9nwD%9{#J4TGWfSs_3IF2Q@U_-Jbcb!v-t> z+5&6M;o;OS^D0`bEg*~?{=@}eM!ZO(P*qG?mACo`sYD6)us(Ua`$ezLYbd!}!G6 zOtD1N^u$u~vpRtY7T`PZmW^||St|sD((=XKYN2ahjk#_E_PB#Lw!M?Irs5e;X^3{Y zBLL#{9j!D(YSmXZ-hzaov}Qr~D&WiG$pZ8^ige}TsGi)kJjeG8!grA2dVdsRI{JEj zZ@WsB9>Jvb6D+Q#u`=s!J2YwqK=EiIq^x|xBBxGd{h=VX#lX(#DEO+mcQH1VR|JVG z5KF5x&g{%#jyhwy)rd$CPozKV?Zr&q;q+mi$yoAz>}5g+C2dtb#n^lKF^82r3LU4` z-qI-@Do{w?Jo-gaeMVCE=EhelL3;1IY~2k!;E9gLP~>6NnIgO*cp2f%1(YL9jH`6) zh{^i}hdkL2N>#@NC4YlA7n|&ter@-se#YAMb)#eLJpmK&3( D!0mAd ls#ub$Jb`#eJN+$6lA0YW^r8MyHKLSGD1r93i{kVmqAK^vxTcSJ#!f7w1K z713&}U5_HkQLY(W8rtR8zuWlH9~4%6==))UEJ&mC>%i;{Vh`)rqaOtI@6Es>*3D^= z#@^PgZgo jzfOAJhxAlbTHt!z)d;KWAy8bPYR&^MRt z>gCly)bS8M?rCZ6$`g_6M&yhzR5rr(_HeEmE>UpSViSWuuxbbqXFU#;qLO)y`t6pI zX@l}g18o)we3x0{6?N{$lBDB`si0-^)G7?5{N5^C6?2BU9|z3ioVJP>G&T5AUil^k zGd*UtIJmYa_vkT0L8)XLAs;q&8n4CaYr*@f95vg9+%%ctj+}T>-AA zmn?WToygGi;xZpQ7aC&ZxlunW2RZ&y$!EBjNZ{Km46KrANmg^hMI{#aVB&Ts2Etvr zET!$nrVrn#+DO~gqOsz>?t;EdfmdFaNY`1@@@>_!oT2dGa z*qrR)rQybz$3$BnY@5sc zeeu>;U{a}o-<&P1%8paJRdt_fBhtDd{9nTSNM_mJ_VFgr{$*S3Gp+dXq`GaBf(ccX zw30$p^n_~LsaUHtvJ5|7+v_f*IIz8Za?A0@h0Yb(NL01jx+Tz%GtZhvc23q$2&x&t zgICev4+ =J2sd*x9*GK AM5C!KP+BN@-oW*>_N!GM&h zl{rFpg3zb)g|GsrA~t<7V%}3KUN`e?@BTGulJhTcT`$v>d3(uL@9|GAJQX~qtz611 ze_RorWPZ97qA~IT*7f*{x-sDG7?d)Jtma;=#o07)mm=I$Jd|%R0TioR@6=;oXYkN_ zu21$FP5}8UqMIvqIM(rTfrc#4nzkahkAzVFp|k#Rb-E(?`4&*Cxd)Q{C1Nup-hNB6 z)4wu7&l#NDhPxa04t7hX_yoM1TK8UqcvVHCYD3_QHUJ+IBs<^2Y=7UQa_>T{fKe0? zDe*D+w?6y6)YAABf+;q|Us5;}$0*s+EC7X4#)XjPnknwh7x$S9|Jr}ilArYa;DQ36 zZvYj16z|_ma;~&YPYN0)??uV!X1(o8x~$?6*Nkrw=XyP7;1mAU5H3j8P%>Sl*7tT> z@@(z+m2geuA>l(V(Zh#+RTRCkl$?@cvuxGkd^O*Ffj^Q4D31;Y!q5EgKRAMB8^w3g z*iQHER1)z@rsk|6UE1b+yrDu(F=XuD-{>C&!7v$|66Pi%gA1R1-z=J$=f3#LScZq; zjQHVyXM>*>&V_Md3 %waqrN)sSNws#FUViq ze8_kSe?$KJhOtH0*1Ok@P<1WFAnKhdV)}Y+=7foK1f+k-7F=2U<}u?TF1;d0H%1G* zI3EYk#o(6>^0GkQK@W{QOy@ZvW{77I6|=>&F5)P?IZgf-;mf=D{p9P(gl@lcD&5lo zCh`c|!@hQWr{@2E!T%>eXcwIePLU-i5pWwVNZb&3oTps@Fk<@0iBEjiOr}(+=EVe& ziY++NlbSYcpP(783;4)Wx|^Hv#~)r|YPcrS{4d)9{u>m$r(D&&>mD3mdVBd I4;=IS;g1E#m-`_Z#OfRF&nt zJ-P1sy9 Grsf@7jJDryc5`<-1$%dg zU&)kP>D3ySV@#pOc0;tRcIhRib3ekSk9=4eby$9SQ{}fZ(6LWMSS>J%@g7zWeZrx9 zcdCfUHQP6h%;|dOSJhqTY|Z>A3yI-jQHy>(q_O4%sXYIIg^$BjDDB$nIJOCrBmJ FATp#7{(meQToyR1x~;++&jzJ3J5V$K(4LDK+&&e=&Nb2f)hs`1tzH zjwv`pWM~F*Kb&O;2c(ZH%lQ;Ihx6SR;9ZWRGit_ChzBZYHEdes5KfJ&m)*uC5KaeV zW|p}x;5`KScwpCo5-u1n8`yqy|DFH(_nEAzMk@`^C2hvkm~mdi*tL{C>G%DwonCP7 zpRt6N%Y+dU6mfOpOcLL9$nK4fGv33=KT3~{?Wt#vbgTOH5;5SVY^g-dtF+m3Ce&|H z8rn~)R?OhMI-`}~&yBr4yZL&%Vs(tJ`lfTm4)vG|>4UH5O$if9n6zNf_eCg8C(F9a z&+<#b9`8;m5X)qSrn1gLIva1axlRSWhVoR0n#`!c-O;*+=Si8J16Z-ZrI8@f*JsE( z3g9a4#$-h?Fx|@-lVmHkvNA?@Q++I{25^gFq1 NN=wys)~tm*2`qzJHRr&a}X;y=I^xOiI$gDb;aS&NiOH zUcVv;bm8M R~Y1PxtX#2>9h%7wr;Wx>{j3yl2BpeA1V- B`_qiWv9H+c+VB~EDns6kVsg84`K)h#|Ksfy5OHGR$2M2^cFTbcsmSC{ z-8Mh9`QW;q5YwJ)a$akRI~-1OfRI-FtQjP<{*-B@oYy@YM31~+)}XyKi+46dD>v&m zQUv`d&^14@Yzmx)V$6&ao^AdR8u(!=^vB;7nIwL=t5XdEe42 lSr(7bE2HPx~;a8w1T&J6d^TWDo6_$be{QzH$|U({l(_HT+B4{!%4$C8FD!s z+)*+`Dy26cudObNq5b{E2f19w<0(@hLy?SBT*()6Jx{xN5}Af(C)?X5np#KMS5vuc zT)e3|$@2>mV9TWq7?X(mt(Vs$BCvPa_31!296LZb1|V>m=QFB(eHNjsp<1g*lHK68 zsr!*gn^6HrheYIx#pZBOQVK1usGjn7v9s$O%-`;{X)Wp2oTQwOvu)x!nv$(k`y{dA zUiK971lsVzYB# VB3a-Yr6MJ=f#3rrr6z@rzmBx3DlmAPd2r9Dw_G~i`&a`MCDqxKF7A-z?U%M(+Y zW4KSk%EQj@VXu|TgLk0BSs%4MCEkB7f96?uz=_KM*7~BZ0L_*WL-@u9-E48Z(7W7*04bw z+(#--bhaRNzkHyyE^QSje+2$;PKyQqXFWGFMY?X|uF!>f44+4U;K`_^GFSI%&*svX z8%Phc9_4vaXsX6wYg0_biB|}~Hw_%_(s;KnZ;o-;$!RF=Ebc5hWn0DB899AgHJ{wQ zj`EnI9vU}@uV1UeV}}kz_?P`%|H?u$KJauv`*#bz*C9_yQdbW-HvA@IlW8SNz#|aV zp)AcK`3%zHB;)UhMzxqG5DBO%<1*>0?y+~I52G(GrhGr?OR3Q_5bboPzKwy(TO7rj zi23c~02_^pq!sW4dX9CFYyVm`;``Fd$D2^> `{(h$e4-%zy46t+*dkIxjUA zILhSf$ 5~%lQN=x7;dMl52~s z|7}x(X5OS_w>PkYy!?zj|I6w|)3R*JlZ;OIbgKY38_TGoq`YLlb^4HcKAs~6_@&}C zzsbRN)Slc=R&&ekv;Ly4-@QGMdqU?UHBaSrBDgDC3LpK4j?u`Ma4*Z^fkHkix_$#@ z3nNohwK0B+*K;yE0!byYs;a7T-#MM{Rp42<5(RAx@=oI`(NYgRh3GYN>bm-_`BZV8 zR%Rk^|D%a)S9?PP*~-GM`SQEGe45%HZ@a)sArDQb20^_5K3H%Pa7^DkHsOGIuDU;@ zjLY%oQIhK7hR*xTaIK^>9IN_Qd_wJ iP$ex>P_OqmZl}hE*IaoRHE@ll?V@9>Bo4K} zkDel#WudKe45dsvLp2HYv0rwyU8ar_u {8tXYS^W^|fl35|x`?8m+i0xQaZgk}&+ zanuoK9{#{U93ULAqEX58>aO>x+AXeuW p^c26XWMd$YXu=L?;GlOyj*VH z(5b&a&^CeB1n_)AxMP{0o7qK