From c62f5bd2dc283b24b1d4377392c7ad0551bd461a Mon Sep 17 00:00:00 2001 From: lxr-tech <1838593642@qq.com> Date: Mon, 30 May 2022 22:48:28 +0800 Subject: [PATCH] update example-12 lxr 220530 --- tutorials/fastnlp_tutorial_1.ipynb | 2 +- tutorials/fastnlp_tutorial_3.ipynb | 2 +- tutorials/fastnlp_tutorial_e1.ipynb | 990 ++++++++---------- tutorials/fastnlp_tutorial_e2.ipynb | 300 +++--- tutorials/figures/E1-fig-glue-benchmark.png | Bin 0 -> 158817 bytes .../figures/E2-fig-p-tuning-v2-model.png | Bin 0 -> 50517 bytes 6 files changed, 599 insertions(+), 695 deletions(-) create mode 100644 tutorials/figures/E1-fig-glue-benchmark.png create mode 100644 tutorials/figures/E2-fig-p-tuning-v2-model.png diff --git a/tutorials/fastnlp_tutorial_1.ipynb b/tutorials/fastnlp_tutorial_1.ipynb index 09e8821d..db77e6c3 100644 --- a/tutorials/fastnlp_tutorial_1.ipynb +++ b/tutorials/fastnlp_tutorial_1.ipynb @@ -1325,7 +1325,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.4" + "version": "3.7.13" } }, "nbformat": 4, diff --git a/tutorials/fastnlp_tutorial_3.ipynb b/tutorials/fastnlp_tutorial_3.ipynb index 8c3c935e..353e4645 100644 --- a/tutorials/fastnlp_tutorial_3.ipynb +++ b/tutorials/fastnlp_tutorial_3.ipynb @@ -288,7 +288,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.4" + "version": "3.7.13" }, "pycharm": { "stem_cell": { diff --git a/tutorials/fastnlp_tutorial_e1.ipynb b/tutorials/fastnlp_tutorial_e1.ipynb index 628dd7ae..6ec04cb4 100644 --- a/tutorials/fastnlp_tutorial_e1.ipynb +++ b/tutorials/fastnlp_tutorial_e1.ipynb @@ -4,7 +4,22 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# E1. 使用 DistilBert 完成 SST2 分类" + " 从这篇开始,我们将开启**`fastNLP v0.8 tutorial`的`example`系列**,在接下来的\n", + "\n", + " 每篇`tutorial`里,我们将会介绍`fastNLP v0.8`在一些自然语言处理任务上的应用" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# E1. 使用 Bert + fine-tuning 完成 SST2 分类\n", + "\n", + " 1 基础介绍:`GLUE`通用语言理解评估、`SST2`文本情感二分类数据集 \n", + "\n", + " 2 准备工作:加载`tokenizer`、预处理`dataset`、`dataloader`使用\n", + "\n", + " 3 模型训练:加载`distilbert-base`、`fastNLP`参数匹配、`fine-tuning`" ] }, { @@ -48,22 +63,64 @@ "\n", "import fastNLP\n", "from fastNLP import Trainer\n", - "from fastNLP.core.utils.utils import dataclass_to_dict\n", "from fastNLP.core.metrics import Accuracy\n", "\n", "print(transformers.__version__)" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1. 基础介绍:GLUE 通用语言理解评估、SST2 文本情感二分类数据集\n", + "\n", + " 本示例使用`GLUE`评估基准中的`SST2`数据集,通过`fine-tuning`方式\n", + "\n", + " 调整`distilbert-bert`分类模型,以下首先简单介绍下`GLUE`和`SST2`\n", + "\n", + "**`GLUE`**,**全称`General Language Understanding Evaluation`**,**通用语言理解评估**,\n", + "\n", + " 包含9个数据集,各语料的语言均为英语,涉及多个自然语言理解`NLU`任务,包括\n", + "\n", + " **`CoLA`**,文本分类任务,预测单句语法正误分类;**`SST2`**,文本分类任务,预测单句情感二分类\n", + "\n", + " **`MRPC`**,句对分类任务,预测句对语义一致性;**`STSB`**,相似度打分任务,预测句对语义相似度回归\n", + "\n", + " **`QQP`**,句对分类任务,预测问题对语义一致性;**`MNLI`**,文本推理任务,预测句对蕴含/矛盾/中立预测\n", + "\n", + " **`QNLI`/`RTE`/`WNLI`**,文本推理,预测是否蕴含二分类(其中,`QNLI`从`SQuAD`转化而来\n", + "\n", + " 诸如`BERT`、`T5`等经典模型都会在此基准上验证效果,更多参考[GLUE论文](https://arxiv.org/pdf/1804.07461v3.pdf)\n", + "\n", + " 此处,我们使用`SST2`来训练`bert`,实现文本分类,其他任务描述见下图" + ] + }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ - "GLUE_TASKS = [\"cola\", \"mnli\", \"mnli-mm\", \"mrpc\", \"qnli\", \"qqp\", \"rte\", \"sst2\", \"stsb\", \"wnli\"]\n", + "GLUE_TASKS = ['cola', 'mnli', 'mrpc', 'qnli', 'qqp', 'rte', 'sst2', 'stsb', 'wnli']\n", + "\n", + "task = 'sst2'" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "\n", + "**`SST`**,**全称`Stanford Sentiment Treebank`**,**斯坦福情感树库**,**单句情感分类**数据集\n", + "\n", + " 包含电影评论语句和对应的情感极性,1 对应`positive` 正面情感,0 对应`negative` 负面情感\n", + "\n", + " 数据集包括三部分:训练集 67350 条,开发集 873 条,测试集 1821 条,更多参考[下载链接](https://gluebenchmark.com/tasks)\n", "\n", - "task = \"sst2\"\n", - "model_checkpoint = \"distilbert-base-uncased\"" + "对应到代码上,此处使用`datasets`模块中的`load_dataset`函数,指定`SST2`数据集,自动加载\n", + "\n", + " 首次下载后会保存至`~/.cache/huggingface/modules/datasets_modules/datasets/glue/`目录下" ] }, { @@ -84,7 +141,7 @@ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "253d79d7a67e4dc88338448b5bcb3fb9", + "model_id": "adc9449171454f658285f220b70126e1", "version_major": 2, "version_minor": 0 }, @@ -97,9 +154,16 @@ } ], "source": [ - "from datasets import load_dataset, load_metric\n", + "from datasets import load_dataset\n", "\n", - "dataset = load_dataset(\"glue\", \"mnli\" if task == \"mnli-mm\" else task)" + "dataset = load_dataset('glue', task)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " 加载之后,根据`GLUE`中`SST2`数据集的格式,尝试打印部分数据,检查加载结果" ] }, { @@ -111,62 +175,89 @@ "name": "stdout", "output_type": "stream", "text": [ - "{'input_ids': [101, 7592, 1010, 2023, 2028, 6251, 999, 102, 1998, 2023, 6251, 3632, 2007, 2009, 1012, 102], 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]}\n" + "Sentence: hide new secretions from the parental units \n" ] } ], "source": [ - "tokenizer = AutoTokenizer.from_pretrained(model_checkpoint, use_fast=True)\n", + "task_to_keys = {\n", + " 'cola': ('sentence', None),\n", + " 'mnli': ('premise', 'hypothesis'),\n", + " 'mnli': ('premise', 'hypothesis'),\n", + " 'mrpc': ('sentence1', 'sentence2'),\n", + " 'qnli': ('question', 'sentence'),\n", + " 'qqp': ('question1', 'question2'),\n", + " 'rte': ('sentence1', 'sentence2'),\n", + " 'sst2': ('sentence', None),\n", + " 'stsb': ('sentence1', 'sentence2'),\n", + " 'wnli': ('sentence1', 'sentence2'),\n", + "}\n", "\n", - "print(tokenizer(\"Hello, this one sentence!\", \"And this sentence goes with it.\"))" + "sentence1_key, sentence2_key = task_to_keys[task]\n", + "\n", + "if sentence2_key is None:\n", + " print(f\"Sentence: {dataset['train'][0][sentence1_key]}\")\n", + "else:\n", + " print(f\"Sentence 1: {dataset['train'][0][sentence1_key]}\")\n", + " print(f\"Sentence 2: {dataset['train'][0][sentence2_key]}\")" ] }, { - "cell_type": "code", - "execution_count": 5, + "cell_type": "markdown", "metadata": {}, - "outputs": [], "source": [ - "task_to_keys = {\n", - " \"cola\": (\"sentence\", None),\n", - " \"mnli\": (\"premise\", \"hypothesis\"),\n", - " \"mnli-mm\": (\"premise\", \"hypothesis\"),\n", - " \"mrpc\": (\"sentence1\", \"sentence2\"),\n", - " \"qnli\": (\"question\", \"sentence\"),\n", - " \"qqp\": (\"question1\", \"question2\"),\n", - " \"rte\": (\"sentence1\", \"sentence2\"),\n", - " \"sst2\": (\"sentence\", None),\n", - " \"stsb\": (\"sentence1\", \"sentence2\"),\n", - " \"wnli\": (\"sentence1\", \"sentence2\"),\n", - "}\n", + "### 2. 准备工作:加载 tokenizer、预处理 dataset、dataloader 使用\n", + "\n", + " 接下来进入模型训练的准备工作,分别需要使用`tokenizer`模块对数据集进行分词与标注\n", + "\n", + " 定义`SeqClsDataset`对应`dataloader`模块用来实现数据集在训练/测试时的加载\n", + "\n", + "此处的`tokenizer`和`SequenceClassificationModel`都是基于**`distilbert-base-uncased`模型**\n", "\n", - "sentence1_key, sentence2_key = task_to_keys[task]" + " 即使用较小的、不区分大小写的数据集,**对`bert-base`进行知识蒸馏后的版本**,结构上\n", + "\n", + " 模型包含1个编码层、6个自注意力层,详解见本篇末尾,更多细节请参考[DistilBert论文](https://arxiv.org/pdf/1910.01108.pdf)\n", + "\n", + "首先,通过从`transformers`库中导入`AutoTokenizer`模块,使用`from_pretrained`函数初始化\n", + "\n", + " 此处的`use_fast`表示是否使用`tokenizer`的快速版本;尝试序列化示例数据,检查加载结果\n", + "\n", + " 需要注意的是,处理后返回的两个键值,`'input_ids'`表示原始文本对应的词素编号序列\n", + "\n", + " `'attention_mask'`表示自注意力运算时的掩模(标上`0`的部分对应`padding`的内容" ] }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Sentence: hide new secretions from the parental units \n" + "{'input_ids': [101, 7592, 1010, 2023, 2028, 6251, 999, 102, 1998, 2023, 6251, 3632, 2007, 2009, 1012, 102], 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]}\n" ] } ], "source": [ - "if sentence2_key is None:\n", - " print(f\"Sentence: {dataset['train'][0][sentence1_key]}\")\n", - "else:\n", - " print(f\"Sentence 1: {dataset['train'][0][sentence1_key]}\")\n", - " print(f\"Sentence 2: {dataset['train'][0][sentence2_key]}\")" + "model_checkpoint = 'distilbert-base-uncased'\n", + "\n", + "tokenizer = AutoTokenizer.from_pretrained(model_checkpoint, use_fast=True)\n", + "\n", + "print(tokenizer(\"Hello, this one sentence!\", \"And this sentence goes with it.\"))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "接着,定义预处理函数,**通过`dataset.map`方法**,**将数据集中的文本**,**替换为词素编号序列**" ] }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 6, "metadata": {}, "outputs": [ { @@ -189,66 +280,27 @@ ] }, { - "cell_type": "code", - "execution_count": 8, + "cell_type": "markdown", "metadata": {}, - "outputs": [], "source": [ - "class ClassModel(nn.Module):\n", - " def __init__(self, num_labels, model_checkpoint):\n", - " nn.Module.__init__(self)\n", - " self.num_labels = num_labels\n", - " self.back_bone = AutoModelForSequenceClassification.from_pretrained(model_checkpoint, \n", - " num_labels=num_labels)\n", - " self.loss_fn = nn.CrossEntropyLoss()\n", - "\n", - " def forward(self, input_ids, attention_mask):\n", - " return self.back_bone(input_ids, attention_mask)\n", + "然后,通过继承`torch`中的`Dataset`类,定义`SeqClsDataset`类,需要注意的是\n", "\n", - " def train_step(self, input_ids, attention_mask, labels):\n", - " pred = self(input_ids, attention_mask).logits\n", - " return {\"loss\": self.loss_fn(pred, labels)}\n", - "\n", - " def evaluate_step(self, input_ids, attention_mask, labels):\n", - " pred = self(input_ids, attention_mask).logits\n", - " pred = torch.max(pred, dim=-1)[1]\n", - " return {\"pred\": pred, \"target\": labels}" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Some weights of the model checkpoint at distilbert-base-uncased were not used when initializing DistilBertForSequenceClassification: ['vocab_projector.weight', 'vocab_layer_norm.bias', 'vocab_transform.bias', 'vocab_projector.bias', 'vocab_layer_norm.weight', 'vocab_transform.weight']\n", - "- This IS expected if you are initializing DistilBertForSequenceClassification from the checkpoint of a model trained on another task or with another architecture (e.g. initializing a BertForSequenceClassification model from a BertForPreTraining model).\n", - "- This IS NOT expected if you are initializing DistilBertForSequenceClassification from the checkpoint of a model that you expect to be exactly identical (initializing a BertForSequenceClassification model from a BertForSequenceClassification model).\n", - "Some weights of DistilBertForSequenceClassification were not initialized from the model checkpoint at distilbert-base-uncased and are newly initialized: ['pre_classifier.weight', 'classifier.weight', 'classifier.bias', 'pre_classifier.bias']\n", - "You should probably TRAIN this model on a down-stream task to be able to use it for predictions and inference.\n" - ] - } - ], - "source": [ - "num_labels = 3 if task.startswith(\"mnli\") else 1 if task == \"stsb\" else 2\n", + " 其中,**`__getitem__`函数各返回值引用的键值**,**必须和原始数据集中的属性对应**\n", "\n", - "model = ClassModel(num_labels=num_labels, model_checkpoint=model_checkpoint)\n", + " 例如,`'label'`是`SST2`数据集中原有的内容(包括`'sentence'`和`'label'`\n", "\n", - "optimizers = AdamW(params=model.parameters(), lr=5e-5)" + " `'input_ids'`和`'attention_mask'`则是`tokenizer`处理后添加的字段" ] }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 7, "metadata": {}, "outputs": [], "source": [ - "class TestDistilBertDataset(Dataset):\n", + "class SeqClsDataset(Dataset):\n", " def __init__(self, dataset):\n", - " super(TestDistilBertDataset, self).__init__()\n", + " Dataset.__init__(self)\n", " self.dataset = dataset\n", "\n", " def __len__(self):\n", @@ -256,16 +308,27 @@ "\n", " def __getitem__(self, item):\n", " item = self.dataset[item]\n", - " return item[\"input_ids\"], item[\"attention_mask\"], [item[\"label\"]] " + " return item['input_ids'], item['attention_mask'], [item['label']] " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "再然后,**定义校对函数`collate_fn`对齐同个`batch`内的每笔数据**,需要注意的是该函数的\n", + "\n", + " **返回值必须是字典**,**键值必须同待训练模型的`train_step`和`evaluate_step`函数的参数**\n", + "\n", + " **相对应**;这也就是在`tutorial-0`中便被强调的,`fastNLP v0.8`的第一条**参数匹配**机制" ] }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 8, "metadata": {}, "outputs": [], "source": [ - "def test_bert_collate_fn(batch):\n", + "def collate_fn(batch):\n", " input_ids, atten_mask, labels = [], [], []\n", " max_length = [0] * 3\n", " for each_item in batch:\n", @@ -280,35 +343,136 @@ " each = (input_ids, atten_mask, labels)[i]\n", " for item in each:\n", " item.extend([0] * (max_length[i] - len(item)))\n", - " return {\"input_ids\": torch.cat([torch.tensor([item]) for item in input_ids], dim=0),\n", - " \"attention_mask\": torch.cat([torch.tensor([item]) for item in atten_mask], dim=0),\n", - " \"labels\": torch.cat([torch.tensor(item) for item in labels], dim=0)}" + " return {'input_ids': torch.cat([torch.tensor([item]) for item in input_ids], dim=0),\n", + " 'attention_mask': torch.cat([torch.tensor([item]) for item in atten_mask], dim=0),\n", + " 'labels': torch.cat([torch.tensor(item) for item in labels], dim=0)}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "最后,分别对`tokenizer`处理过的训练集数据、验证集数据,进行预处理和批量划分" ] }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 9, "metadata": {}, "outputs": [], "source": [ - "dataset_train = TestDistilBertDataset(encoded_dataset[\"train\"])\n", + "dataset_train = SeqClsDataset(encoded_dataset['train'])\n", "dataloader_train = DataLoader(dataset=dataset_train, \n", - " batch_size=32, shuffle=True, collate_fn=test_bert_collate_fn)\n", - "dataset_valid = TestDistilBertDataset(encoded_dataset[\"validation\"])\n", + " batch_size=32, shuffle=True, collate_fn=collate_fn)\n", + "dataset_valid = SeqClsDataset(encoded_dataset['validation'])\n", "dataloader_valid = DataLoader(dataset=dataset_valid, \n", - " batch_size=32, shuffle=False, collate_fn=test_bert_collate_fn)" + " batch_size=32, shuffle=False, collate_fn=collate_fn)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3. 模型训练:加载 distilbert-base、fastNLP 参数匹配、fine-tuning\n", + "\n", + " 最后就是模型训练的,分别需要使用`distilbert-base-uncased`搭建分类模型\n", + "\n", + " 初始化优化器`optimizer`、训练模块`trainer`,通过`run`函数完成训练\n", + "\n", + "此处使用的`nn.Module`模块搭建模型,与`tokenizer`类似,通过从`transformers`库中\n", + "\n", + " 导入`AutoModelForSequenceClassification`模块,基于`distilbert-base-uncased`模型初始\n", + "\n", + "需要注意的是**`AutoModelForSequenceClassification`模块的输入参数和输出结构**\n", + "\n", + " 一方面,可以**通过输入标签值`labels`**,**使用模块内的损失函数计算损失`loss`**\n", + "\n", + " 并且可以选择输入是词素编号序列`input_ids`,还是词素嵌入序列`inputs_embeds`\n", + "\n", + " 另方面,该模块不会直接输出预测结果,而是会**输出各预测分类上的几率`logits`**\n", + "\n", + " 基于上述描述,此处完成了中`train_step`和`evaluate_step`函数的定义\n", + "\n", + " 同样需要注意,函数的返回值体现了`fastNLP v0.8`的第二条**参数匹配**机制" ] }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "class SeqClsModel(nn.Module):\n", + " def __init__(self, num_labels, model_checkpoint):\n", + " nn.Module.__init__(self)\n", + " self.num_labels = num_labels\n", + " self.back_bone = AutoModelForSequenceClassification.from_pretrained(model_checkpoint, \n", + " num_labels=num_labels)\n", + "\n", + " def forward(self, input_ids, attention_mask, labels=None):\n", + " output = self.back_bone(input_ids=input_ids, \n", + " attention_mask=attention_mask, labels=labels)\n", + " return output\n", + "\n", + " def train_step(self, input_ids, attention_mask, labels):\n", + " loss = self(input_ids, attention_mask, labels).loss\n", + " return {'loss': loss}\n", + "\n", + " def evaluate_step(self, input_ids, attention_mask, labels):\n", + " pred = self(input_ids, attention_mask, labels).logits\n", + " pred = torch.max(pred, dim=-1)[1]\n", + " return {'pred': pred, 'target': labels}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "接着,通过确定分类数量初始化模型实例,同时调用`torch.optim.AdamW`模块初始化优化器" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Some weights of the model checkpoint at distilbert-base-uncased were not used when initializing DistilBertForSequenceClassification: ['vocab_layer_norm.weight', 'vocab_layer_norm.bias', 'vocab_projector.weight', 'vocab_transform.bias', 'vocab_projector.bias', 'vocab_transform.weight']\n", + "- This IS expected if you are initializing DistilBertForSequenceClassification from the checkpoint of a model trained on another task or with another architecture (e.g. initializing a BertForSequenceClassification model from a BertForPreTraining model).\n", + "- This IS NOT expected if you are initializing DistilBertForSequenceClassification from the checkpoint of a model that you expect to be exactly identical (initializing a BertForSequenceClassification model from a BertForSequenceClassification model).\n", + "Some weights of DistilBertForSequenceClassification were not initialized from the model checkpoint at distilbert-base-uncased and are newly initialized: ['pre_classifier.bias', 'classifier.weight', 'classifier.bias', 'pre_classifier.weight']\n", + "You should probably TRAIN this model on a down-stream task to be able to use it for predictions and inference.\n" + ] + } + ], + "source": [ + "num_labels = 3 if task == 'mnli' else 1 if task == 'stsb' else 2\n", + "\n", + "model = SeqClsModel(num_labels=num_labels, model_checkpoint=model_checkpoint)\n", + "\n", + "optimizers = AdamW(params=model.parameters(), lr=5e-5)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "然后,使用之前完成的`dataloader_train`和`dataloader_valid`,定义训练模块`trainer`" + ] + }, + { + "cell_type": "code", + "execution_count": 12, "metadata": {}, "outputs": [], "source": [ "trainer = Trainer(\n", " model=model,\n", " driver='torch',\n", - " device='cuda',\n", + " device=1, # 'cuda'\n", " n_epochs=10,\n", " optimizers=optimizers,\n", " train_dataloader=dataloader_train,\n", @@ -318,42 +482,35 @@ ] }, { - "cell_type": "code", - "execution_count": 14, + "cell_type": "markdown", "metadata": {}, - "outputs": [], "source": [ - "# help(model.back_bone.forward)" + "最后,使用`trainer.run`方法,训练模型,`n_epochs`参数中已经指定需要迭代`10`轮\n", + "\n", + " `num_eval_batch_per_dl`参数则指定每次只对验证集中的`10`个`batch`进行评估" ] }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/html": [ - "
[21:00:11] INFO Running evaluator sanity check for 2 batches. trainer.py:592\n", - "\n" + "\n" ], - "text/plain": [ - "\u001b[2;36m[21:00:11]\u001b[0m\u001b[2;36m \u001b[0m\u001b[34mINFO \u001b[0m Running evaluator sanity check for \u001b[1;36m2\u001b[0m batches. \u001b]8;id=22992;file://../fastNLP/core/controllers/trainer.py\u001b\\\u001b[2mtrainer.py\u001b[0m\u001b]8;;\u001b\\\u001b[2m:\u001b[0m\u001b]8;id=669026;file://../fastNLP/core/controllers/trainer.py#592\u001b\\\u001b[2m592\u001b[0m\u001b]8;;\u001b\\\n" - ] + "text/plain": [] }, "metadata": {}, "output_type": "display_data" }, { "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Output()" - ] + "text/html": [ + "\n" + ], + "text/plain": [] }, "metadata": {}, "output_type": "display_data" @@ -370,16 +527,23 @@ }, "metadata": {}, "output_type": "display_data" - }, + } + ], + "source": [ + "trainer.run(num_eval_batch_per_dl=10)" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ { "data": { "text/html": [ - "
----------------------------- Eval. results on Epoch:1, Batch:0 -----------------------------\n", - "\n" + "\n" ], - "text/plain": [ - "----------------------------- Eval. results on Epoch:\u001b[1;36m1\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" - ] + "text/plain": [] }, "metadata": {}, "output_type": "display_data" @@ -387,473 +551,155 @@ { "data": { "text/html": [ - "
{\n", - " \"acc#acc\": 0.871875,\n", - " \"total#acc\": 320.0,\n", - " \"correct#acc\": 279.0\n", - "}\n", - "\n" + "\n" ], - "text/plain": [ - "\u001b[1m{\u001b[0m\n", - " \u001b[1;34m\"acc#acc\"\u001b[0m: \u001b[1;36m0.871875\u001b[0m,\n", - " \u001b[1;34m\"total#acc\"\u001b[0m: \u001b[1;36m320.0\u001b[0m,\n", - " \u001b[1;34m\"correct#acc\"\u001b[0m: \u001b[1;36m279.0\u001b[0m\n", - "\u001b[1m}\u001b[0m\n" - ] + "text/plain": [] }, "metadata": {}, "output_type": "display_data" }, { "data": { - "text/html": [ - "
\n", - "\n" - ], - "text/plain": [ - "\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
----------------------------- Eval. results on Epoch:2, Batch:0 -----------------------------\n", - "\n" - ], - "text/plain": [ - "----------------------------- Eval. results on Epoch:\u001b[1;36m2\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
{\n", - " \"acc#acc\": 0.878125,\n", - " \"total#acc\": 320.0,\n", - " \"correct#acc\": 281.0\n", - "}\n", - "\n" - ], - "text/plain": [ - "\u001b[1m{\u001b[0m\n", - " \u001b[1;34m\"acc#acc\"\u001b[0m: \u001b[1;36m0.878125\u001b[0m,\n", - " \u001b[1;34m\"total#acc\"\u001b[0m: \u001b[1;36m320.0\u001b[0m,\n", - " \u001b[1;34m\"correct#acc\"\u001b[0m: \u001b[1;36m281.0\u001b[0m\n", - "\u001b[1m}\u001b[0m\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
\n", - "\n" - ], - "text/plain": [ - "\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
----------------------------- Eval. results on Epoch:3, Batch:0 -----------------------------\n", - "\n" - ], - "text/plain": [ - "----------------------------- Eval. results on Epoch:\u001b[1;36m3\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
{\n", - " \"acc#acc\": 0.871875,\n", - " \"total#acc\": 320.0,\n", - " \"correct#acc\": 279.0\n", - "}\n", - "\n" - ], - "text/plain": [ - "\u001b[1m{\u001b[0m\n", - " \u001b[1;34m\"acc#acc\"\u001b[0m: \u001b[1;36m0.871875\u001b[0m,\n", - " \u001b[1;34m\"total#acc\"\u001b[0m: \u001b[1;36m320.0\u001b[0m,\n", - " \u001b[1;34m\"correct#acc\"\u001b[0m: \u001b[1;36m279.0\u001b[0m\n", - "\u001b[1m}\u001b[0m\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
\n", - "\n" - ], - "text/plain": [ - "\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
----------------------------- Eval. results on Epoch:4, Batch:0 -----------------------------\n", - "\n" - ], - "text/plain": [ - "----------------------------- Eval. results on Epoch:\u001b[1;36m4\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
{\n", - " \"acc#acc\": 0.903125,\n", - " \"total#acc\": 320.0,\n", - " \"correct#acc\": 289.0\n", - "}\n", - "\n" - ], "text/plain": [ - "\u001b[1m{\u001b[0m\n", - " \u001b[1;34m\"acc#acc\"\u001b[0m: \u001b[1;36m0.903125\u001b[0m,\n", - " \u001b[1;34m\"total#acc\"\u001b[0m: \u001b[1;36m320.0\u001b[0m,\n", - " \u001b[1;34m\"correct#acc\"\u001b[0m: \u001b[1;36m289.0\u001b[0m\n", - "\u001b[1m}\u001b[0m\n" + "{'acc#acc': 0.87156, 'total#acc': 872.0, 'correct#acc': 760.0}" ] }, + "execution_count": 14, "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
\n", - "\n" - ], - "text/plain": [ - "\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
----------------------------- Eval. results on Epoch:5, Batch:0 -----------------------------\n", - "\n" - ], - "text/plain": [ - "----------------------------- Eval. results on Epoch:\u001b[1;36m5\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
{\n", - " \"acc#acc\": 0.871875,\n", - " \"total#acc\": 320.0,\n", - " \"correct#acc\": 279.0\n", - "}\n", - "\n" - ], - "text/plain": [ - "\u001b[1m{\u001b[0m\n", - " \u001b[1;34m\"acc#acc\"\u001b[0m: \u001b[1;36m0.871875\u001b[0m,\n", - " \u001b[1;34m\"total#acc\"\u001b[0m: \u001b[1;36m320.0\u001b[0m,\n", - " \u001b[1;34m\"correct#acc\"\u001b[0m: \u001b[1;36m279.0\u001b[0m\n", - "\u001b[1m}\u001b[0m\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
\n", - "\n" - ], - "text/plain": [ - "\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
----------------------------- Eval. results on Epoch:6, Batch:0 -----------------------------\n", - "\n" - ], - "text/plain": [ - "----------------------------- Eval. results on Epoch:\u001b[1;36m6\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
{\n", - " \"acc#acc\": 0.890625,\n", - " \"total#acc\": 320.0,\n", - " \"correct#acc\": 285.0\n", - "}\n", - "\n" - ], - "text/plain": [ - "\u001b[1m{\u001b[0m\n", - " \u001b[1;34m\"acc#acc\"\u001b[0m: \u001b[1;36m0.890625\u001b[0m,\n", - " \u001b[1;34m\"total#acc\"\u001b[0m: \u001b[1;36m320.0\u001b[0m,\n", - " \u001b[1;34m\"correct#acc\"\u001b[0m: \u001b[1;36m285.0\u001b[0m\n", - "\u001b[1m}\u001b[0m\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
\n", - "\n" - ], - "text/plain": [ - "\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
----------------------------- Eval. results on Epoch:7, Batch:0 -----------------------------\n", - "\n" - ], - "text/plain": [ - "----------------------------- Eval. results on Epoch:\u001b[1;36m7\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
{\n", - " \"acc#acc\": 0.875,\n", - " \"total#acc\": 320.0,\n", - " \"correct#acc\": 280.0\n", - "}\n", - "\n" - ], - "text/plain": [ - "\u001b[1m{\u001b[0m\n", - " \u001b[1;34m\"acc#acc\"\u001b[0m: \u001b[1;36m0.875\u001b[0m,\n", - " \u001b[1;34m\"total#acc\"\u001b[0m: \u001b[1;36m320.0\u001b[0m,\n", - " \u001b[1;34m\"correct#acc\"\u001b[0m: \u001b[1;36m280.0\u001b[0m\n", - "\u001b[1m}\u001b[0m\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
\n", - "\n" - ], - "text/plain": [ - "\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
----------------------------- Eval. results on Epoch:8, Batch:0 -----------------------------\n", - "\n" - ], - "text/plain": [ - "----------------------------- Eval. results on Epoch:\u001b[1;36m8\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
{\n", - " \"acc#acc\": 0.8875,\n", - " \"total#acc\": 320.0,\n", - " \"correct#acc\": 284.0\n", - "}\n", - "\n" - ], - "text/plain": [ - "\u001b[1m{\u001b[0m\n", - " \u001b[1;34m\"acc#acc\"\u001b[0m: \u001b[1;36m0.8875\u001b[0m,\n", - " \u001b[1;34m\"total#acc\"\u001b[0m: \u001b[1;36m320.0\u001b[0m,\n", - " \u001b[1;34m\"correct#acc\"\u001b[0m: \u001b[1;36m284.0\u001b[0m\n", - "\u001b[1m}\u001b[0m\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
\n", - "\n" - ], - "text/plain": [ - "\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
----------------------------- Eval. results on Epoch:9, Batch:0 -----------------------------\n", - "\n" - ], - "text/plain": [ - "----------------------------- Eval. results on Epoch:\u001b[1;36m9\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
{\n", - " \"acc#acc\": 0.8875,\n", - " \"total#acc\": 320.0,\n", - " \"correct#acc\": 284.0\n", - "}\n", - "\n" - ], - "text/plain": [ - "\u001b[1m{\u001b[0m\n", - " \u001b[1;34m\"acc#acc\"\u001b[0m: \u001b[1;36m0.8875\u001b[0m,\n", - " \u001b[1;34m\"total#acc\"\u001b[0m: \u001b[1;36m320.0\u001b[0m,\n", - " \u001b[1;34m\"correct#acc\"\u001b[0m: \u001b[1;36m284.0\u001b[0m\n", - "\u001b[1m}\u001b[0m\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
\n", - "\n" - ], - "text/plain": [ - "\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
---------------------------- Eval. results on Epoch:10, Batch:0 -----------------------------\n", - "\n" - ], - "text/plain": [ - "---------------------------- Eval. results on Epoch:\u001b[1;36m10\u001b[0m, Batch:\u001b[1;36m0\u001b[0m -----------------------------\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
{\n", - " \"acc#acc\": 0.890625,\n", - " \"total#acc\": 320.0,\n", - " \"correct#acc\": 285.0\n", - "}\n", - "\n" - ], - "text/plain": [ - "\u001b[1m{\u001b[0m\n", - " \u001b[1;34m\"acc#acc\"\u001b[0m: \u001b[1;36m0.890625\u001b[0m,\n", - " \u001b[1;34m\"total#acc\"\u001b[0m: \u001b[1;36m320.0\u001b[0m,\n", - " \u001b[1;34m\"correct#acc\"\u001b[0m: \u001b[1;36m285.0\u001b[0m\n", - "\u001b[1m}\u001b[0m\n" - ] - }, - "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" + "output_type": "execute_result" } ], "source": [ - "trainer.run(num_eval_batch_per_dl=10)" + "trainer.evaluator.run()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 附:`DistilBertForSequenceClassification`模块结构\n", + "\n", + "```\n", + "
\n", - "\n" - ], - "text/plain": [ - "\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "trainer.run(num_eval_batch_per_dl=10)" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " " + ] + }, { "cell_type": "code", - "execution_count": 20, + "execution_count": null, "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/plain": [ - "{'acc#acc': 0.644495, 'total#acc': 872.0, 'correct#acc': 562.0}" - ] - }, - "execution_count": 20, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "trainer.evaluator.run()" ] diff --git a/tutorials/figures/E1-fig-glue-benchmark.png b/tutorials/figures/E1-fig-glue-benchmark.png new file mode 100644 index 0000000000000000000000000000000000000000..515db700127d0d2f4dc7b139a29bf1749419f2c3 GIT binary patch literal 158817 zcmcG#WpEuyuqJ9TGc#Ds%*@PWF<2H^Y%w$Ih?$wmVzii
{%+)wbF~--jxD7_0H_*5lDgQCt!RL>=MhC4NCnZk6_L|-%ru< z!~1{pa&BQJ_=@Z&ZfOl_@a{`O()2wF{^9S^LT4}ln-8?wj}m{c+_iIEYmSmc@%^@p zTcXnoYCO5ENc>^?IrR3>?Jly-_Xfh+6`=Sh8UrsHSPo(+AQvYht@(9APJ<&gOfwX0 z%$>>h-8w;a4JWzbHspS_iejBsLPL(<*oenUug?b}CS~>6h<9@tb3nGcE|30`MpJjw zjrSqw)e6=?M#?Pw8vifFiV~NR3Fqqn7g8;fw4x%CgoMQZDXC|+SP=yc?W@ASBV=+aN~7D%^z-M>zS8!) zYTW-K?%bPh38UluOCS30(|G>v>HjD9=Ys@7A40Huc1mlTQQ4SFBtHQtRz?QC$rCo( zSqr@NA!7!&LCPXk&Uoc=z=fpyh#0(qvbj`5rThd|JDCv(4&3~dzciQ|-jgXWxV1{u z)Ge=$iy35msiF*dx7sM4c(~K7Y{jYIZ9vFkZ{Oe1Qle@LvKEfeFQ~|oV*+v&0T9Ls z{avnUv>JB9<+CRsVoBGZf3x}LS(LN(fCXNQ10CtgadAWIh3f!;ai*?!%gdpa>#kD` zx~qLb9PU&il<`mCzu0(Bkv~{iYOH{i`FCWEM+|gzzwtc#kTnc zy!YePa}IGOdarFA`H~O3bzaCKOs3>pCs&1~Mo6M=##8MO-IV7VDV=kpxXMrMY+oe0 z2ctiAx#1F*CW2z J07^f7`R{-iKO7|1*l-y;GbF2kt H9N|IN1|(wq^0y*d$Zr 4JprY6V$JAKxZnFh(6Z1q+a#0WV zFv8GR$__%34SI<8k3Hct>_Lr)x(b0i`QL|5eo1nsXQ%@UF*Bztt2(*vNTi6Lv`{{k zfjwIMAF|2m)xdv1kc*H%Lu1PE25!l5cI_cfq^!+@j&MrsN=r1iL4mTWJFDBjH}4RF z%IooRgKlUl04vG`jW@KPG)O6?5U>DkTi3mYeeDP154$DB&5rL}3Y)j$-|M(oLpB8A z9qRNjfUg&S_{H$P45Mr`J6zN0zM0e;k%d33gl fm zWAJL0bNeMJV9e_gE<*fyd*LYGuI2TMU#+bU6OOXt#n$W9Z1WKwwVY}GA5E A){KfX#)5Kg4cBOiD$;;VkzOsNZvs+ zp;SjKK9L>7syA+c0y~|Nx*5-e`S}v<)$XH;=XyCajh33wOQGhL*Om?&wOJG{Jx`94 z9@HFu4Mb-u9+dw2Kv}2L^!2Kj>*Fm$V`Nzvu>Wl8vRnY0$CylFat$W?6c^o?zsAv$ z=$5bxd=-)4&$V!a(nvdpgzbZHG;iPM{9~(It-6MZW_-i#z}55>54zWK@5h7cwDxyc zV4unpwVHD(2?NpbY?wTxU8{YW%y*5;0i_PGvwZp`m(GE9Qq`s5LmL`2I8k~y>%o`w zlQ$4-6e?GP+HsDsgFs* ~{r$Gyl znX*#MIl#CaEDDumqExBERLzgO+JN`rs}|bcir;~sZrJlaC>2A|b5p%hV!jDOdw%GQ zARRop`E|N%kW@DUGh8N@lBqHkV+4WU*VR6(f~?au5Y2Jr&qAZX^Y~`4>Y^8N6?fo+ z4$ mA>LoXlY-aHzfRrrJcaHH(T$)CaK3sH+ZAP;YF1ffsr}$#@cmZTE zs=qMh3U=k2M6OhUFS|i(n3xDe#j#Q~PTNuUD47gQmyjv}T#T4TumnC}o}mIo_yfL) z!fP}(fky|YGaFKS2>Ke9ZL4X${^F4zR@1Ue*6r~t_p#q?`n$+vpId>eNV><8@@&6N z0@Z{Hq%B3Uu}U2FLhjRpN?*(Js2eu4L%kjZH7c0-xF!WzEIM&HPlx%yIn*r+bx;qZ z9Qhz9YFr{ttn+EXWxi?D9kjcXxnGD#MrlzFWx7X<-faJFQYZ7ushZr9rf3=K2cbn{ z(&(k8L`ETX!&vE6J04k<2+3 {Btzhg&)T$x*~@vQd?0ym)8z@`*K*gH2HTe zGl4zQPzd|_-^D1>ftU1iUTsW?(rYld*5qG1%2 DQbY;fysYuOUN|MDVdD5MDb_QYd8RmN_aIF=$l z{2h|Y$SfjH#ec*b+uL9XZ$A83RKJ}$_^t$`g$3Tl=CKG#4BH7l{T|Y{g65BcCqhB} zqbByuI4p}PGAUf62mp~?>6L)nXsx9%#bpF@LX@^wD1(yy!rvwe4g}_*)@3sQAIUT2 zhH2=?*)#?x!8g-dSxOq>#i+}~=)#h!j8XDxpm!=i7=NUOw|P5#oNyqscgC&Q@PrRN zah5ZfVI4Og8P(3`LVyohBev~QG5F-#_VOhnI)%NEP>$_pZu=t8w$mp3dhg88x`0rK z81W!!qL*673|@YdYpm^8z`fFgakl#ok<5%$ADMKH?f1ZX&H&sb328JKU^@}8wwYSp zmy>W%toNjQr(T}|l0C#wNe?Hk&J#2M+3n89F3W*PLFe8?BSHm7e=zms?k~UO3GHvk z?!^|}L8!X0c>9wV^uvV?O0?v1#0!t2-XesELBiBk-+(_Smn{NchIA|e_D&(JQ{Z;C zGx^V0Ma?B6iGYBBHUCHnQ@a%LmO47=>;NX!mq8x&TqJU!F-tVcWf9pL*P%agBIUxJ zRe(mNc35`S61qN0bo9JY8g{rYe}7g!)6lpxxd>M&ln**hzeq{}R2a?}EF6gVl}O5W z#{^Eq9y&NvF3d3TvIpDMwW<8Xlg!Rtw`5Y!Gh5k6oRmhDo$ITm (puC~0H- z07*h#rh*KmeuY-Q00v =QXx8y64YXFA_a?N$S1ddO<(-i)6Vtv!x*u;V4-Z t z*yXX)Lcz-5-&1{VIOs2p&AP|9#$E~g(vx-|Gn48x_@Mz1G7YfP)!|2tDr4(zMsPt+ zoIg@~GJXIeG<#i;IU9J9aDbY|rT=4J*#Fp9D60KODBLRxk{T7e=z6uw_G8@w6)8DY z7GYmi1kt6!Z*9M%$L%KO68$X@?+ 95WSI4Gj$(!6b4+GEKAJEeHV_HV?g0Q#SB^@6~lxuboipx_qc%G06C# zQ)7dbv?L(XJsMv@->!)8%ZPCl?|q^uoCdet8!l?D7rC)F)=(ifTnX~wHTV~{MiS*y zmd5aBYOEd|zpKs>)ggGNW|zdQ7@Zz3n}0uyi25306y>4;(A_oudxsYo_-BVN%jp#~ z>=uj#CNOxZ;d8*#N6qV TLPPIaX~Q+h!{B zwBajhqZdZt!8%Q(bGehTMT|7Sb~C)#k;uS~5=PXTOcI_>zx~V(xc{+2?uhZJ?kcXQ zYANOVU-sCr7$@nH0AjWX)f`yo?oM4BIqeGgF*xbmW*6{~tRK_ M@=Nl(&SBQ2r|nf8weZY|jXCVSRjG-epqMh$0iQ`0UIM(Aj8H zBL`Qzde?e!2FsOLO9UX&lbpn^k{KR1+z_k2Ym+sd{Pp2-P5XE5!9B`RuI@K(#IZM+ zgWqKkH0VlYo6 5lW&gz!t8gsQI+J4<2KOV 6=v zzCnbEA-TIB>zqkTsR0m3Xy$6TkI~86d6M|o;gCSo30V%cO#E~{iOprt= 5>d+ s1eir z0eJu-Yez2kVDpR3=JlC!V&FLUHD($6EQi&m;~GQ1RI(n8#--Znxl#2eKAV$)IIK$j zZ}7mOA #STN#sA #kA3r_9bFyUhSSLkbou~H6ItOG1|N)BQdZs zv|u$>QeW%wnXzaWt9mcsD05V2YcEe(Fgp4I#_S(uW%DL0Y?T&MkewY^(iSX3NH)g@ z k{T`|vsrS3I%-z+w{Bt?ixd}OpDaVDdL)jx z8HwXW=ER_ncNPRfl5mM0Kv74^!-+B||FK ME#G*%6`Wln$ui;pWwZ6eC2Yg?F=#KmUh320-m2{Y11ozrp{tEh9oHUY#IsRu9l ztY5gb{&FGjsi!)}V?Vdi7p^!PxngY$ZKW=O%2JKQmAR@(=rkrHE+<<<>0k-d(($>s z-DENbIaqfGXZkm`3dB_DAnlyKnA5h&qD{resd&e7bKM=_@dHx)Tr=+7i#^`DJC3wV zlVUOAf_s5Cw2($CguK4vw-*7QAfhu|^@#8x@?&lN0l+7-E)jC(#|1j6DV5&G3nlJy z4mixbOWfhIQpkl*VSr6FyGO!dL*@V{3nkbYmj_vFYK&;p@~ -QZ(_bHhVidCFUj5@^> z2AsVtI+B~K#28luI#E*bLXF5{W5Yx_)4Ya~>t(5^h?}+*Wnj7avw2oAC{p*a$;cRw zr9?IK3hl-pN>PWcUR*7|+vI!;apz7A19M9E3Uwgtt3JA4aJ!Z7T2a$2;)e{Ypqf8s z58JP3lQSw^jp&qe#7ib_sS!kNVP39Jk T=Qamh9g+JWur4B7|SNMIf}lQZYhcpXe1=M$peyz*4qH&V7x zz{9C5WA>U)cwhYd#|h;jJN5~TO!`~Bz_%?-CHVQd^{qr^SLY9gc7J_g{Sid<@}*q0 zT>MRg34%Sx=2tE_tTN94l164|7>}@_6jw3|a#9i=aQy@4Ev>NZ?Z!qgL_!NC;^R^% z!j71{giQVl`OP~UKe~1o?AOt=A0*6cc!YkaTI#iuS8`BQq3*B%Nk(Ff`_YY++e}-f zA!c=ak@gPc0vZ@zDA| ZN6!9WZ>$1+`k}`)kpkFi=aykU}ch z?R;MiEe&7_;b3ROUHkHhVP%YwPj{kn$XFA~)!w5nM{1Ee{$7Cqc7J8i)lMqGGssy5 z3oCZ^c65L#sb!>hmseuncQ9*IJBfhUWB#?$V|%m#eyxUl-i(TVB7HGHx}>@8$1@=? z|J=N %$xvqnJ{UdXvN)^x z1Sh0y$ERD7- gnt3jviTeQC!oJ-b^T2Sf8YF7{P#j>l|FZv!KR~0-Q(l(8ODEg`7gmsA!;4& zPI9R%;u#}4A7vohiv~VHZEbD;bA+(;Gw1K|`J}r4e+}?4|5v#0zlZ97liW9wi~t?3 z*?oC~&=;}v-9B2Iv_~{Q2fg@O%@dpy*w?iTl^Y4yKWkaY0)5 zJ_@7QiJY|W3?z#pJU*{rONYyC8SC4df9*rDSp5YUUpO!!nEBqw&bxmpBvug@IS$#? z0-@;E0%j1_)KImY|M~X9A97D7uRss%7vVeqzUL~~c<@hAbB0k=<|a;)g`wz@9YZ8u zUf!kU)!y25CC{!~=+}+%y0Sl+pFs`FcLbyA
dzV%6gA;S$4?P{kGrU3q1GzP2-<)#KqwfO4%Vj z{C_K6qCa5fs_r0~Z`@kp&$6LYp}0C@6d_{FD5b~Ml(E8u^!%zK?B}ODp2H?c ^Oo7+?q3$QU^_IL>ZB!7r+4is4gOf|aW zq-Y)oIBmdQ!F}#ASX^Dkr@guDNr&>hg9{X_sTneC8B%z*fl6_Y7%)CT>l-5RxR{iw z;023YKD+tIT_cH9D+jva1wGp`@@+Fk$c0=V{C)Vvu^KFKsYnH2%0Rw*!UXjCe8z8S z961nGFhD-xF^n{g-k9+Ew@ku=L*38wy$kEo&{`Y}Y8A3K)w#IV_dBsi4SDI21jD~# z387%mbH@N=BSclzc2A*~4^DsW72J5W=7BkB&>YEmpJrKVAd5EawU$=ME!$=QJdX`> z6-`n#HAVt<9RN~i1ls-1!X6P-(R7LdSGyK`+4BysB@9KVR7pu@2=Q1|MrO)Zri*X3 z#XUi|-pX8@#^?s)E$JC72|zvUqb^HR(y~DQeZ~j@qMemlP32D-;&;*_1eO!!U!)qZ z$N9=CD!Zo7ooR%^Hj1iMg~`yLA7vf(pEd~<-^7os=C{OI#0vT0gf-_X5S^(TmU|~7 zZ19TPV?b_+)MHz$TT@d?9fJ%2cVebkj5IXp24&f1v?ztGVZ81PsT5iAb6O%Q2xQqs zeqY<3bgA1+?m@##x{x%VC&X6D_vKPGR3plVoD&&)vR*n#4`3jbZn`=sa+PZ#j1CPA zy`3EWf{&}G;W#l*U|n#HTB2K kt=l6*9VoTn8 zQr)8UK$WalRKS9bULAT(?wGY9P5*3|Z-$*km>yW>V4o!i=~hc)$218%j@8bYlu!)h z=MR=H6_mQkdKniWrItxzgktsbI+TX4o_zIVcX1-Z7!$if##`7Bw_i10d7T|Wbmkd$ zvLW+$3u-wb?0CX9uETmyYePJm7K8QrJyP>~h?0N|$0R$%WnVM0c5SE^Upwg1YnJKg zVo-`&2}$+ik+31EubPE+H 8*+{oZkYd2U_E2kJq zAFwCQ$yIYXq9cIi3kV6#l%vn1*>P@}N|~YqOI-YKD|(gf{@hKw<}pL~nn?lH7^w|C z;rHty!$mhX$c8G=^zf)H^X_rlC*`sECv2`A@Scq($_J>hdsHdMmMou+&C{KjQRN(M z&R> @X~>yu*zrYaJKI31s`;QradA7{9z-xAd_4~AZ>Nl! zb)6-bB=J*-j}{ w{zb^AfX%e{er<-3RL z(4k2bekWuH+xs1{RBOu0VXN@=vp<&? EJMK zzEN3=l9f1(AeP7X%3TdF3-5J&IN`dPB*E|43Z6P8JW-SAeprFQ=Y9Axxw(Ry9%<)- z1iqgqk&J(ih?Gh6y<-!$PZIn@*VYf(n=sW`U(Fr`S|O7Ng>k}^D9GC>l5iD0h)gCB zUn_|I8v=9zZ1+Z2bhl+6_S_8GfvI#*^TBzu_dXFmk2{D>>Q|$7EDl7MftfaYsc0`h z;=3m=6v|f`LVdiDUbiE?KJr1Jc#Pe7fI<5ng)pkf`ovDC9lgPQwC8VpVwq_7aNYyJ z&aJ$G*s;Fr@HF(i^hrRkK1{8yU&^K26*HfPt_w?^Xu~E%h}co&Lypj`s%8eSH~hi* z<5!8)(7w|uZoT2y%Qh!mNj-)gVZ&3MS!wm3U(PcH!$m{%?3VdY&vxX=f_i#+<+K2> z(*jubr@LO6kh~;geC@e}bz&H20TF`=K!K+HTE%Y;*lTN9VT%DVw(hz;_Q_V49)%v{ z @yHfQlN>;hc2i1N{^&MFwsGm@~dUo!T-f%&`pR--+{ z3&-Tk#Q&hmTF)99F&@jlnI=1Xf`kACjEkEM?x)nBalF1=0Jqv1N(_%e{b;L6t^*8a ztL==>gwcuE;MrxJx(@|RNi-o%HnZE1$Brb=hfkR-@9mb3#CLkes;5l5-2y2>w)*P3 zwNU2atQsc+O`d<#eNz!=gM1*9O-Ucgjf5EpVD;JY$=AtIsT5w?jSYa60>bg}Fhg1Y zv{vrg^!&-|L?EzDR10y;O2*6(Ogfx=c~fG9&Hl!y>&*~US}LsXY>g^28r$63j)k8t z_vd{OCWgWtSiON^v}plx{@oqT@3 hfAi^&zv2oXGUvME|eDo9_<`!H-{bm+#RAewBg9mh+@!JqI+MyRhl6 zz2F%%Q6X8;S}irEhk-R^kv9Af#?CS*uD0vaNpN>}cXx-z9U6BF?(Ptzad&rj0tAQP z?(V_eHR$lX^U3>7%~Z|b?o+3K^nFh4z1OwZIxF=!hDr4_$oFwIf4z9VsZJJqAdxcS zaUk_d8xwZaxH`OC+O#lK@v!Y*^`2n13p>{#dIO5<58UX-Sg;xi5mHITAN|Gh(rA<{ z#c {A=k zp2{Uo#>#P4uZqt5_^wAE*QY#Cg$&1)OY8`JJB+CC Vf _=?n%5`p3Jc8)uS<^{L1O&~qPLBqj6EQlRm&gD;#xJ49HE5;_%Bqo{MmM0L(4Ry zc^vcgHj1m5H5=LyYq6?21^`rF$&AMzP$r&2(tDk)M9Exn(AUDT5$UP q=5|oW zK(V<*y7nV~vdqNf{5nP{soHhq)kj@-mpXK(Y&EqoFy0_)N{`vWfQhoPUT5?h{UB#Q z383BFIIUMk!0aYxSi#oMK`r=#G%-QzHl@EAg_f}f@7QPb7yTAL6ONS^(wpaENUSQ+ zFfeC9lX$aG)2jciDWPZcGWpQ)q)W5uF7fCoTz_Y~ud|kk+(6}+>jnOsrnG^EDeG|| zz2qL7Kk7v+O@e2|Zy|Wzd7l*6!88+6AJZ#Xakx~P3!Fm-5iwZPXJK{nHvSf+N*K(} zn^9+-t>jI#D ^o*MTp{McN>4Za23WYgAX2p)4|B zg*$1M%?_cZxw&R&bF-o3P%;pO%(gH&>8U8@FCroU-5-6fcSrfiHP;XnrX#>he*-%y zdI@SiZzeY0`a;WqUz)Sq(HMZ+lyG!#ccQAoZO?DBIh5$(1;4_nEhh*|BLAAtdn_$H zYb 3go3e?YrNMgwln{7jc1TV)~S#&K}3GJX^6_-|C zGE?acL`}$WE44-0DTttIYz-yg&^x0%t4v|_VB^6+t5NLZWjFBMhCvq`D+@<%E-nt8 ziEr!;NO=9Qkpxk&((=9Qu3mB!xC4n^-Ww$w2q-`>mQwMvqQ_FJY2D#2-fq55qYnAs zMQ}vSOXo>%2XBugyuOhJC*nv`JnwN|imZ0*?$Rb09d9;@QeDbizhpjZj)9nMrQqyf z_-djkyW2G^4v!+pLzCpJUGu|bW2TFJZ_C~Lp4rc0=UglgEh?xrkZ|=P+vIcsl8ont ze>?GjLG>>*eU@ftXmJS%V(~+g%33&5>K%~xIZcTdpi1X(O{Z*~R9NVxTJdwtdB+{Q zn+4r9$Ga =aKTU14q%2}2eYzJCHw3S|wgiMa4}C?1#dDW#qht9WKXEK{Jq=Cx3@f5ml7y zeVvlWyKXs$c0p^G8Ky%TxJnu9?OGoySuh`HXP|e#GZOM(dl)Z65H0$%e{0Cke}}i2 z^{})VF!4#sjdGp@Sz1r^ouAOUG{=ixyYQL4`yklk6$Fyj?)XotIBZ$MJxo~z0AHUz zyrn`ee{CN%)Z_c{b>Vi7n$DT-2_@X|LQ13hV&fFYKA35?k;{=gUim#~M(K<==)EKO z`Oly P7o=vPEmIySJqKI_SCdK#6VtOAvp)Y~D;#m)#$zP=Udi-b j!1G8qpUGFsCYC;|Rt~+R%t(A4J;&8dyhJha)n3h}{1X=yLLW2mU zmz0q#nGIPz-KIXGd(TZX>&Y6THWRedqyFluOtmlPHn6!XakQ_iVot30a6PQ-JnzxS z5)Z&|gzvV$l96>++lIOxif6@U`9-)X=wgMcKSVB4U>|%ZJAqs*n*r^(jEA%p7JMlJ z#IE*RkNB&1ZbX^d+qfxpS6d3DR>gPWVWsle;w;N@nZ%G4s;;o6QSOQ5GN cE>W)=txscpcwGu(WGC@ zd%I_MUf&9`jORP@$!J1<&Q~p2H@z5pKmUN3hLSveuW#QsXL`o?In7tp>bagfeTCr7<>wQERmn4m#_>xd|Y8q7~ z<+7KsI3hkD89>=)0~zgDGPJiI9Gl+-!dl>o0lL_L-8twl?9*mjxu@!t-rr=}-*~Ym z1>5(399MS%|EVCeW4SAgeU0+vxuK_<;iCUCVUmm bF(o;eh<%Q7UYvgMz`9 z%>EA*R35|3_CSkBgyd^Jm}3&IQRn6j>lJH5L9RhsPVpRb76AlOe0zKi@60FqE^Cm+ z-BOJcMlxh&GPh!jZO{x&KGR(PGghf*h0<+zk|Hr Wk2I+4g1J%jk5M z8C*XtfOa*g|G%~5LLMmsR26iFl6Dpoc6>Hu*I+H!N7 (lebJg<>&H!PG j_) zcYMh5-3OiY{H4VqXt<6aIIB`&SKgrxuRYet10)C0Qcr~B5K7BpREepW;@6~Jab-(H zmHPgucK9wLaieIb&rQ (zgVvet9mNeW57s06Lfn;kjq(A}1JRq$| z?|m6OZ z%2!_B$Nz81;igifjX*d+;)SL7T3Gp555*^2ePJMj-2PH`SP+=O=8gbXd zN=uX$tt&pSF1lI?ab{A6Y5^XTfyM@G%_oVI?V*btAXtb4r6Ukm>6Q{QKaLJs_*>rf z72c(wt-l}q1WR^ijJXJFs$sHr?-z&C0zC|uzfDleF4v!54?Ba)$3aSfPLF>bWsw_t z^LU*V;ahd){6DC7^wb(t?UX{-3sLKeG6R{(a```$XSniiH0(=x&bqMTYfR*R2VG zLk)6ByglE~37%saETPM(&QM)1Nig}DacLx7=?Q%y=<*K9IrS6I#RR*08L(a!tbmNd z@LT4vgZ8`j=x#8dw}5_DO%cVo{>HS$O+)*1p&y0Ne7U`MQMp6xM&FF??hjas=i5$A z3Y4^#*lrg+3Fx?i!- k3g;jc`-Oj5THb%H k&laZMsJ~s)-jv zzZ8TYi S)e%0s&FOBiUu9Jn j{DSa0%XI E T}h{D_W!rhf) zTb4$#&h*v8Mv |sOZmDij*LkDwMX ww2MB9Q- z*-4S#d0MYv*$3kMl8OC&5!W7JF<#PCG+pz+2S0v(0VB9ac6EY61X1?5j*(zL68wN| zTgn@U6 O8P|=dv-UUsKKG1$Q?uz*!QD@VN=K6V_&0a z2A>Exv0gxifV;uyT@IxPQj6tiaWX}t >}0u$C2rKK1J|o=r~#LbOb%#O zBGy>v3lvpskn&FOaoBa!oJ^(D#vMQaRd4Y}kZB1_7Qu#$b-~&DZu!xwJ;8~^!53RC z1fBDJDm|C4!JA+o!b)opnzIYfZx<2N2D@rius1jNw|`L3aqvSFg;R}#^L#7o{D$<` z%NG=VHnV(H0V0}DOr50>jpSZ_=k$B!!AYT&+x+{G8Bs)GKQC>5qmpm+D0V{a#OD3d ztSh41bSn4Noh_iQ?!0oilTweRuRuQgiG(%F$j@Vii2H*V5~iii1d7o{FS>oATf$xz z>dx8jTVI;vTkKH=vyZw*RDMpxL+Av+w%-^WlarE&+A~of%+yb8?h>-70nhZ2F{Gi4g&@O3A1ooHtgudl=XP#2 zX(>5{Y9KU5cv8|CULSmg;Y|j}LPa$@stnoD3{!%>v($H!yOx@8dzpocTngSum%B4h z-tjsN3sI4x2rQ$Jei{8dGhMhq!JD#Xun+#y3byB(XUuWpH~rxlhE>>sE9_^p`}>uq zog-GWIC5~pbZa-Pm&Ep}xQb@m{}|S1`^URzh80wB;*p4=qOYU|w-8MEp=5yMP)rYl z$T!j5-s9*Z^iYp;5kPX=5g&E#W^Z;Jz=G9E^O;U%fkXD3=on+%UB-a%ywpnT!ktpQ zefOn)A^+nU{y?rX{P}II>)y+hDCR&r3~MK1(voJ{0$+lQ9y**BmnrgopruxBz 77F|mV*!^S0h1CsR*48eWCjundo!jZA=*adzhprXz0L}rMk)kaf> z4`a*EQnB{a1-S8YZ2k|pDZAX;|3BF#UaXv|KsHDYE P~-FMhZICpy=Z_BU4jp8C5Kgf)8Fg(oUFsT4l&eXt+yxpF5c9A z6 4o%IY2UX3Ck7 zG5BYkNoZSa^|qZhI9oH~9_gILZ$Xz`7VnH4qDN$P^XnZg{&u=SdR~O+)p@7paw!Gm zIkV_oia5vDM2}M}`enRO-iedqSeKmiM()+-S~B!NXc#WPp#(CNjPp7hbgRgCQCfhP zJ)C;ZA_5yk$Kx9qS3ZE#M# uwMbomc_5=q4a*SLmrfw5J32dsk%= z_=Az)^-3H3{I?iXj=8;1d56`QsDvVgtdOzp2mhY71Y4598NAf;%K`g9Z={clR5sd( zcHWHq#F0IvW{^S=Nq3_Ge5=M4!x)p~rXFuypk`ZNiRCW+9^nKRtye)oVov* _yJqEpbDe{N8{ zrO_}2?9;h+#6l|nwxcUjicdRc4ImsuO4K*80k(7jQKpfHQ-^Ygs~msg!6b7xm_oF; z?HOvSDX^( 6R;w%|I*ZDF-L1cY%VpcwJOY@nx2IYV{_&SrO$|LPAfGF$*O@%T@xKMPZsq6#lZa z|F*pj1! f4P24SF-hqR2gd46f+MCWeM}k zrbmC@MZv1vM4_q5E;W>b;7R)0&RnD{8 a--G5#ePMKZaw~OdV;ELo2FkNvLYLp-bqGbL zcp2~Ia*Y--qGD;aWN5^@Avj>t3dRxDF4$lKu^78>OeC Py P6r33WUQ)X5`0p5oB;S zp)&5`r-02H#~J}PGRh1(NxB45OPf`&Ut0Q?cn+#9+*jF3kro >Lt6e54k zw^ FSU}gxk z39Mku!k?1+kQbS&M$ywVi~ygK>ZwJ{KzC9F1m011R^$2JG&FaHr{GqW<%+0M<(k<6 z?9P2^5yP+V-v`)u>zybOYBY4;1mz~$Oes!grcFy}(zcqiI*W!H&7GWo(i=+>P%#t; zExw5eMO%s|SGeSRmd;<6DBfovA~g}Gi^bXuX3b6l`AeEM=-DrsL+8Urn_Ws!M7>qG zO7qz-r%h!1Gi#sqI+rZRUT5aV0gPFSFgR+*vbX9)6tQWCF22!hD`QQEHHIsg>^75r z*BS=jApU+d#0?@GD@5DEmP3(Z)uP0SnaLp9KF FQ#-d!Tlmme2p z@8LNHq_|W|4bIMQ!7inO(5fFNo-RH ^wu(n&WEsHJ$r-BVc-_vZ;M$h^hRxlNbU)0RjvdK{s@4t*Bv(^HP~ z1^Mqum!Y5?)jfMcT%(2P$!0Z7(-BX?AcA`VCC8~!?B7yqYL)4MtX!FeXwaSPvb#xp zSL3Fvrq-Q!###$F%sp4aaP&yYfY|CY@s9^2cB}{GF{ HfK??|Hk@R|Jy*Uv*F#KX>7yi9f-?`5 z_1;I|=kb-mo7Z%7K~7e2lMq57Z-xg6iRjA(`^zKR9v$U^*2N>9v4wXm=^ppv*K3_d zp_--UU(-m1-J~zQy?;?BrNepOj@mJ(hJ`q~C^qua&n2d}8 ^LZR3B6Q_@n13Ku%8L)K8CyFth zb4t{?Fl(jxPTDtRpE|YSvvakxqXs-|mfQtAgWG0*5w$6UzMa_0luKoA-*xxppg-PV zz6q>_pTRfX$`gc6->|)BG?9DRmR?7Xj|e;aR?IP>IUR9kBAT{bx%B50uspaP56NBH z#qzPm&~oU=Y}%6>(0oqe$$l~#WUoeP3;Ww{iDzOW6k|?=&a}PM@37jJ!t==A@~tTw zk?69&P%+8Gh^o&lM8Sj+XXq|P7f`BGl=(!8u$xZ8<1RG8aNyNNF$RZ?(FPs&o?Mn^ z260ZLpt}&4rgzWetTBO-WTbnr)aM>I@XO+O>B%8RdMqj5ejWaL;QyYS%9>IO<2jeU zz~11jCGV+NU@x0(UPYQZ6prrTC@^uMF5 !M)KXyFbM-AKB7H{U-Q1~swWguZy zUQaqyvAu(%Tc%YY6IUy>^u$(TCb0Y0T#bCBg+=56yUm8LOm~~JCZdOLT8K8ZDS`kV zt~0Gd*2waqWWl@S@bpc%Sg^->P_sXFL9zt3krpBbU9u?3Mmvf9rx|@KR|lAJzCpz| z+Lg3@uXV7L<^(d|KVD;SB-gCy^))f89M#0CQfxA?0c)L7NfmlH6tfC-$Oh|ne`*ZC zfw1V}IH4J3T8rdwcC;_X<;FqV`&f~vh!50^o8yYGw}IxtG-q_llOFEM7@^4aOyK1* zy^}qtl=ia1PHkDFu!;hN+n`4Dv$JZW44$`$Es#FN%dTPk4EJ`!x8%2VWcmgXwNO;c z%law$|AaiHg$TEaQO@>5mr)Vx6osTbJSBe5ccIFdw}CRAc3^yRL1YTu;G-J!p#_(6 z8bVR@k2)H&YI2s$cn97JyK6T-`+i=*uUyM;e)SZ83=MRnx}~9SZ^VMj1!#{Ydixzb zyuks+Y7_!pR^+7XYhVGWbgI%iLofdWKi&E~aph3_2qIr)BkwfWD$9GfiFBbCQ*aKf zsCRY)0wGAkVM1cvkrT#8^MRk1JhiZnB%4>T!2F_YF#4^GAJD w}FF?%{259wd1rXY&0%_qO}5qIK>UZ4{EG1MX4a$zxP z@Ix#W=V)~eM<7EZz;)ogW!ZwojAOe8?Q_GKWl#{~r{}k8`%l=DC>r&vx%&1{tBwPk z1SDAyw8s{bux1kB=pr>-B2ylZhW0wT^rjtjie~=xmBIC6!X)!y{(t;34nO3-M^VHw z|9?eRB>Uqcqt_z8?$H2DFm~XHS@_YFWgJQ2KA}#J8+P<#A!#uW3-rzFL?kL6*noGY zxH8nzm7(GY@vFW{ZqFyy9P-H9P0{}ZIt3LgmNmjWw>-+DM33gop(DMQ)X-xOk=C!$ zp>{))(W7*znEJTXv&{aXTFpslo-h^k9|lTu2K*U^dIY=p?S+-ZH+n*@Ck)l*A@93R zqRbvl4Rvbq1}ERYit=%ryv>bc;9wM7*!+GnQ>V64K{9Z)gM4BARkmbHZ}!2APLQ=E z`ho^Q_`Z&Uaeii)Iu|R-_j;-C1ty_xOlUJ0%!x>Cqz%7lDqG;7tiz7igjqAQo^ZuN z{+v5tU$~a%*5{|`afWkeb8c8u`=)^L6CtQ_#oU*1f#{_IyPglV;)+g_&z5 3cg(TwLu`|in3})-r@2nl3d2xZVi)w4Tc~24(BxEYbl&+`{TjoUDN)vc zuF)tkUt?KjAPP$C`g-N|C{p*~IbKT;d_Lyh$MA=zQAnAD_lf0|G$Q|PK6%+~7@~AC z3pCdJ;BoPS-PPlkcIJd>uF(2tI%XklW#U_H4!?xb-P&abrJ!bv-MRT6uY8Fk0UvCy zraH;|w9=MFJNnhfXRw@0J8#3*_*ZbK(q{4ElOV^&z3*q84&eR@L_bp0WB@OV9u$Q3 zFL2(SeJD&bK>-0GA+hv=pB)TkojZF#qnK#alO@Zu78U9HdFkUE#%Z*P|9jZ=o3~+q zpg_w9t2>G^Mh9BoT1@Z2DxHJR2XB?;10H9)?qJ9P5=%oQ+xwjwR0cW)Zp?4R$d?{o zmiO-C{o57f-Ws5M5|bS$W1*TD>yY*HF*`$}VhE7o7%Oa1lUHqi4t9Q;+UH*O7k$GW z>PYY~!`B-7u4*<9BZGce4CLPcY%q+MOo-cF>H+VRv}sX zCrFhJsTXn5y#?FP4xFD!OQ6OTDY>uKv|E{esXkYYm%tzE(2w7td7G)HMA*P8YUmR4 z@-k#sV (%P8op+dC=7?HS1`!sk25dkzX {5>PEKy*+ j@~5YZbCG3P+dts-gF3YJCX4gvw+BELOZ?PEsOj~|oBC|f<5 zz0QcQiM%6t-LrVAYoMc0&0$D1S?#k&!+JeG1MVZ<@UAtmcGp~E^O!9|j~mu{<+5_q z8&&CC?Dg5lpz+-=h!rH%#Sd#RHa9$q!bCJ3h`)iU2=ze6zRmI;jww$r!m{qG*kpFY zBFz$dtL$9on>ZwDh?XimT%NhrhQWwBXk)|X{&CpzWu`@bo5wheA?j=8dk<5lBxM {QzeAiP5{l03itnAzRQ;C|LV@kDT+ENhNa7D zrPxssb?{LNLQvloEr+PuASwTS`=2oQzs622eEi=U?3@(;jl(>!BEBLI_VOT;TaKY! zg~E!>?tiO`TJu $d_fys zwlt!cRHQSZk|a~T)nf(}xbz8?nsTKa_UAx*lI;*9Fp{Y(JxCiHiW2y{ a?q_jB=-Sa~H6Y8LFh+DtfFMTbflv$0rTY36_b?L-~uc1J4%lp1L~ zRKIDh4@!|EkSrYZkr$%h5^n~m^zUy{q{P6pQGpE+9UFxVs0_QRFGR&M_dm@P--{0G zE5?rFMdyj1KF(5fBcamVNbG3g+LP%jwt58zNd3LRj&9;24i|$C<-9%Cl|mJ8{~L3X zp^;Cb!zKVo*pX?dF!Ko}8N5WTCNfs^@;aEe=qJ_genj23WTy0-TSSpB-w)fe=pIvE z?W#jsU}uu|Wz)N2x!^l`+0-lFIvQcO^x*r+wpdsYQ)rRd{2Yd{=WYWdf3gxbntr5Q zAK*P~^1(H~T!4%-OaU(a_2+qeI$`9-iwdD#QMf{kDo`r3Xut}1*!5Pnm6v ip!yI* k0xoAfa4eQWLw3V zEZJL*Tz1c9#WR#wIXYJCzvAgdPp4QW88ut AWEW+ujr)!H22t z&Ov24!pVME$5%`==%_uvAfwrZBQJC!Ded@iz@2n=GsrYQ0?^C-OpDmPw20L~r!nxJ z4p=!K2I!e3WB@x^Dvw&4ISZ8~T4vQrqM{Kh=ftq;<#PId;*AmA{Q4?Fa6CC#1SwwB zD^8+YhMK>l*^0%$y(4QM%{ZFs;${X$OG=KI5duX5RKIBY5%Y9FALx4p2@c|7urm}6 zY4R_6;VIwx*&Mkd`4%a|0izU8Yg>L9c4@IVF3nyS4VFIoxfr+@e4raPP04PL<{cc8 zeyUR4YL|5F@_pt<+#hK?D9%DgxG80+64({0V*xzm`GgKGmF^qJjB)AOG@j&g!K7cF zW@XA2rvF^t8V|{N3V@peeaE&Zw}(zYP^Y2=dQlTdBb&pltevmik4RIAs`9VM37loj z8aL0=>q_@zW|yVK)nG5CD?SDf7b=l|u9DOai&5vH*Hwsinw^zEF(pz{ynd5+r58s1 zEIJ(d1)}CnB-j_hju*6q3Cq9cM->e<*UYexOt7NQ5(Lddf|CfAkc-b=E1OC~;$YOy zWSX6KNN%4jPHSpp=xB8M!BuP&kjbwzl!Q7W9sA2iOOe)!&DoW3WghHl1_$N$|KPYw z4i6@Ws47#a#c6!$k(H5wDTPxZDE}cQVJd-NI$t<)qq$7Q^luR6>=5;~7Y#i}{v;l7 zC`1|9ze1xr*1 l9CLdVa4^K97sE2RX&@tmDo#iwZfZ)bb&Wgk zy{OPuIzj)r|Dh-UZmQf4;hNQw*{Bx4?e)}M0?;y0NG{osYac0t7gE@z#RVR3@*R0< zi?D)T-!DWLooLe8b%mROrx4*>mS!9R`7zfAPi8dk{&}me2NpN#rh6uBuIJbjHipzm zx$vy&9T uU^ H!1ji%O6SHqQptv&E&5nAs4a5fY*8crH+m@ z?DDF_SG0 -OnrJT$1rY7D3Yi}|s`HHyPlQrY**K +tdc=$iTFRLHkMFq{+)M7!t)-RXp7Y2qt!db7jMfF{q`Ta9SW# z-1!@>szBX%)ciNGcQ!>W?y=w*pgUWb;e1g#kn672hBg&Vg=Zvi{FzPx>viLdHsMt< z>9i0Yy7N0FE^)(M!^KOpyje#PEmWrpe)PT`8cGyx4CY$28{sY8kGbedU+jM2MbBA5 zn~a)^*e8ed@vb!C1~6|p)7SWv@=3&Mjqa%$-B8%-$^x;n;NteBQX3&DqSIvAYds+< z=Izn`mhXxwq<(hl{?gZb=2iuhi4~It^Yroz``fX5)Z?jZpZeY`o2-17x?)=GmN5l{ z< omnXzHZ^kx=rXt0{3Na zms9=xnhf!i(aj`UB@ymt pZ8Kpkcm{u)jO8VCk*p3>wLI-VcXdHXx~)|u_ }6$qF2*ABY5Y)c)x}EuYmp44tVnt3w1`-U+5K>#3P (nS$ND%{gyUF*+JOa3@01Xktdb@mnO7xQu@(-yl=n zVnOEhZaw%aBF3T0E}~!QT+|)4932>b<^Q>PR$82bnwE}%`A*S4G-U4Kc4f a~uZF6Z8eNHZ?CaGEN-^;`JR9W^Zt8}8#XLl9)uoEd3?;s$6C*fz||^<$1p zOV6)sqfqBgdHSF||L)mawWQ9E2-gq7QDZ;O`5(An;~%Q6RgiBE>b!-f!LX$(Hb>9; zZS0?V6X;Qx8IIDi&k0C(@uVmR7&n}!X~_EQxN4%m^c{j>UgC(1oSb3R 7Y|eD9V=GmJPX+Eeh@NGDcK;6efr-`3nfY=T~9;YAzfF zMsY$g2OWxw=CWB7H rSbQVEvB8- z2jw!Osvlc5j@UPmLz!gPl|J>}*O2R7?x^jxUBk*0&)vq0Z~mGB1+4JBwMO^D5@oaB z@j2JSW!5Cs?#P}(kmc6KL&sJcxHBJkVk^1q`|ckoUe{-&bb0AMM1H38yhk?Lqmoc3 zsIU*+UdB=wn0`AeOzdfqGU{k+0E459?n&yt=xwa%RQjU9MPSi+bM>Peh!hf%4!e@R z=fd+j7V_B4(6Z_x5oZO?r<>lOJymS6i_1`NQcr(6vJ?o++xMu03yQA7l}D`_CN+TV z)gRV-w#SyN<2ZZa*)3uRGY&M2@PM9&$+nQ=Eb+$OXC^YIc3u}UTh6`kQvEKd=Y2Ls z8JBG5&Cs(5_QC|Zan^j 6&Iotha`d^j4RswhynTi^2B>dZh;i`8&q zV|K~J2m%oVL-Po5GW@H*;Oh0D3Q82T1lm7~IfI*;vosGPN!{1YGH98Jlbut&q53LU z6e;O|QYiQBf@QH(j}Pe2Z=WE>PyC|whEnrgQOe^q`3HLRum&!jM863n0_%SM9DS;% z|4Qb0U??+K7@c_KJo~sT*o_lB@e@hd&J+Qz6})0;M(d7rMsx%?z|JsLH1Ek48q)#? z<+vjb;c}vVPS6QkREO7&+kl7D>%J=mue19G>Mmh~DNUX1o55 4e}9z3jVKv*Ut$>?;14J;6inhPnK;r z6H!q7bC^;Wt4J+&`OyY*64M%EwN>3;>l{+pYWg*sv<24jI-FQW*ul_Z5upk9Uj@<) zSb5uRpwbU`afhqSeT?*a7+4rn&->`AKuc3EUv5OAh-Zj|?dM0#7E1A*BL#bQf>~ZD zj1O>fau^y@G2&MtkAti+*Hb>@r|D be|j^w$|NG;PEh7hLmlOhOV2BEh|jEDGU-{PU@|Nr6G6v$N>`;U9#vNl_O3 z(KV9hR*R?3bp8XrGa~p>Uwp{Pdc`{-#Ud=^!KsXtsE6;Cju&)`i-m`jfZhAkCY>G^ zddKnl4@~fyAE<`oXDgYR5`hXQgXqu>)Amg#+kvhph2J#H8saaeKxs=V{v?}3K^?qxZ_@vw9g`$-acl~FUWW>Kp+5r|G_!iZjk(c->`{Aql| z8n@>R*4!7@x6jS>J!&5eGFiE`L&-_?X?yZK)jnx1nWYxFG@-XjTfPiSmV)ju3guir z|7Il|!8=&S(E|#;CNoH1;~&s$BFphE>}l8tk`}!EtPk`!lI7fKhcn6(E9|X;;p1k9 ze8S<4vT4NZV2nbJWCiBJX>6kNGnzx(Z1O;_ZB!DC3Vs1P?7i`aN8!SXK?FoiWl zVMXT+Sk;HmsYUmm9$270Pf{|`@AceCbFCIN>UsBcis?#KxP^g3u)EP@(CcsAR~NxC z1L1tt*wV64nWl=*dB0e%7YEi4voF#URk}(fcTem-&J`#rwMU3!@bc!rD^F$X9F}hB zFJl_;<1|FK1Y@Z4T4K?Lz}P5NE1>!BW5LteMN1bccjO4Ju^j%0agX{fAT&9}QIGx~ z)K`x^Wn^xF&8|L>dfnc0Tihz>M
2xmNBVwGJvud29IJ2{!e*{#57ssG;XC(V+)d+yhwEkkzi6)U77T# z1}{g}X2#rNEvgf)h+@W9%w3Zhx}B0qydaT{wo92%X3NcsPzM?zb4f(R3xsxCYUn;V zjx)oRy8S{1%l%zBYeHtwWbCc2n4;Z8%pH!{0*jJKJ~+{NfZnd(H*7a9Kk$~Aol7R* zw4z5d{wNA28V;7vFkFAqR*8F?6w}Wg!4=9K5aQjyL(^XGLve|V{9V1SDdG1UmpQzq z6NFKlBiS>g-`g#{@%^aD@Y#$5GTjL)osOpT`gP{*7y4Gzl>D{tchLsdhbx*#$wYxG zg#`Vr=`<+#=z-|ly?IGW;GK@CFM6Lgo6L9{kanT9m+DdH%ZTTz#r~^}4q{C?OGaD8 zK7))r^jP1^*zHgT)qp!UwQ!E?`~o1wht-JlC3q$OQC;}qX{&OKT0b9>4tid TQmlpfGFOLaPR8d&uBV@vJOj)+%C5XAJ<0*k|+bo z?#Z}G3UZ6))C77#m4wea77@~MHE1S>4@F#JC)sN&0WH4lUHhuW#3+}#oJ9_9j70g# zXlZt#W$!qk(mUnPT2l=m3VG+wgsa6{w=bwDC+%Kd4_gIWLBTFU`#j`N`(N2Qi$UZ@ zn@2d 6`v)MJSogjK}r(oiU|t%%iiI`}HVN%?{ZCLD|1&?~#mz{4fqU$C$~hLX=OH z9crjWvx)?>*x+;0WWqIS=YytUJs(dscD#z~+;Rd*F!q!n&wAq|7+8!iWUBNY`7jlZ zf=f&UW=ySW YlwpU6&-e%6hDyArFPrSh8VUEKB7Sm9o$#6C^0O?2@*tLrGr?ad zq2HleusTB9a3p`aSGW*_DGaEEaa~4{SO!s@4A*@2R#?}z@Seosc5=1i7}|G*g4Nc_ z$*bpOQ(-XdMjq}~hL%zirfbvlZ+^VB%xL5rdB;t(N|AoPWv 8m!@E^DZ 4+uMPsjg QX z$uhb@U}Rw_poloxmL=-o>~XQ`Z+9x7*_?~?^k$)aq7340=|Qj2az@Es|B)z4qm2 ztJuw|U=D6Np2Zy4_Uo7&e%acY=w4;GC@d^@bHpGAV~w90f^>AHayL=)Om%9!i~Ebq ziD7l=-|Q+ExQvbiR**$6b;zV*wZh=ZQvYc5NX@0!O@ueVeCb{6GuhX2k&LCW^rFGP z6iqPpX#6C7zO~9r0Cl$cT#ik>b$Yk|OIwQ{r)y>229xD=2)o-~5-)5FfCkrOft?!! z``8%6+RS{i 6QXN+_W`yb#S^nfZ&KJYEObUQTyxVFihK zE^{iuK~jmjUp|mW!)`uEeX?4FgP`dqGCtH$kT)d6RT=?krRk%yhKQgtw>($uD~m~Q z^CSLmVyY{bWyYE>+WvdZhNLTw@Mj{&hS^;H{5X%S3~X0jM%U$mFlfFTZBz|Wf$g|i zpjo jf^IfVB|Ubhk0|tcA@;%5zX%FvQw2xTd{C{xOty1C!}Mg-awU2n z>z~Yr@55- hg2<;yAbPkC$E~N6GlbXB7nzdNdP1C~*e*rWn2qRFt>x(W2a* z30` Ms8sUE`CVo@?%yB3&r%s5bSMKa0tBT%qb4x_t`TIr0Nr!tC zW1stqQJTb|9V;BzL{}(w@NWI-(Baq#Q5)wm9HCk0b)Hej`hEvcK_Nmyr-zo7WA^C? ziu lLCt^f5sU>SL8xyIu|y>F_iPpm_Vy-LG6vB;*smN6-TYHuTBz3d zT-`*9!$5hXV<}nz)3Er- *ga4GG_EjF70uW^B5PG} z(ssvRF%K^L%VNCXZ*G1KTVMjgCfgXM=>0^;`|=UYS~vO71fhj8+Mp z-ZG!$b!xs?{^C!bR6qHC4yQFb@Jkg18lL8hY-E%Guj=+YG~;)KF)lu@y?@?(x;dQ0 z|BJSFj?V1q_I*3HZQHh;bdpXwHaoU$+qP}nHaoU$=cfDj?!DiA&mQNTamTp-WUVCi zRIOT7PtB^DpZd=K1WV55y4lSBA}s&kCC~mh;$r`3Q~seL^urCqu>M`f3<9FR%Wh&} z0fkPh9lq! XIByG;3y7Avr1GB`>8JraWHQY8*7E;qT%eudY9 z_a7bZzXjCL0Y&-z*Kg)Fe`M+YCBRlY@KEoY|6fvR^|A2or^K|cgQ0VHD)RJ}8SUZa%2~niO<>Nc hYhJ zR?}DcdY*dt=Xqd(a6gU@BwND#7} cBe1AcA`FE{tJ+y(D3^LWEd=?b-&t` z?yu0EM=o+E)lA(v`dMOBkHqFT=eAe; BA+0TuSizJ6|`HZeq3px z;$8tG#@;|_caH|? bat_4{vxj8|j{sGML`0dWO6_F5fGSP-Mu3~DFu+r7%_AHObuGXKg-b;=dVh$g3D zWrncvAoX!uA2&l)K6i}LTWj0;vsI>ZLoInPmxJ9&!3MR7=~Ut>{}|v2dc9|QI-Hi% zu!fprDhp;p`j)v8q6@a!44N(H;eT4w%w}br}%Rmr-+Pi5;u2jZaPw-$SPdkA)D< zzkN9`dv!Zpe_paf2%pZ$N2rzlN=w<#<1}>7^tm-X1NA3UU{J+$zKiA{<36f?4`1P> zjDIu3lFn@dlBvt_J1RXk*LsGK9{z(cR7}I&bZz*zje!%atvxP6RCmyZa}LLYuz!no z_lOiOxZ4=%90|evId>%ZY3CVEibGT^T&)+RFrULf%kGf%MWl6Pe2DnCY0n-xcZVJB zknE TO3IDfCTlyZpNYlS`!NB&9|U~DY({6PGkmMlWWae2v{+5weAB?kMQ@b zj$7}rou{3rOGtchc?AV<5xH)yYASL^{een3{RmB@fn;OzVg}Q<)f$nA!HozIHz*}x z5P+I&Uwq$LuC?{osSO;((Hzpo=L5UIjEszw442!&vvDlgpj*RkGI(}u*u%K~Z|9)) zel7mdsLc@XsZM^YBRU3fhQ!6oX4I~wUCyLI&U&xDGe;UjfQc}ky{h-QATG-; Bia_s;H{<6u#SIw?8A>e4WicbNI%6;2tsB0H$|eu@qqG_CxqfR(b>08r$nz zlzhK9j7ku%;`y{oN)soHEjLFEdYmhp7|Jc>QS~yC4;WcrO)Sa@yOVHQ;6w52gcA28 zN(f*~lBZA )FpW<|IbHLD0Q|TV{q{p#`Ty5SHy*yw9 ziLAoyZq4=-D{nyGi=B7-J$khExJf^z<#)OU$JMR$4i+-Jw0#} sVop6{YH0GN5%p6&Wq)v~^8 dbfDNnxGsLYy*$#-D{>dEGIg@oxu_jtvk_7Wqh%G{ z2bG>~mFC%l>7<|CL5e1w4ea!UXn@LA&%uTkkpORh1ZS)vpj@yBtej-&9t;;}G7lK3 z%-CMGBYn_lfqc|*to8_VmTq;A(q*Z~zx^HPkYwvVD%};}L3TIerlYz4iuN6I2Wb|6 zc2Uf6) zl7~YQU(X;O+D_rK&iB_sy+#Ic3B$WHwMQD6q#yW;kKnA9%iaxCo&&OdT-lDhm)68N zkghbGzUxS(HS{dbQMsepVjKp@ijiln!U13Iz269qE9TARn}C%UOfzLZEaT_c4CeO) z)R*$91IGdPW^@Nyxpb5Pi*`*t6=^u(1$yW#m>~cW_1WTgeop)^Zc 8Su9c z_}O;>5WI|9p&z-T(W=Ag1lqY6sQ+?KyZW*pLANA5|1uG8o4x(cB!bpqj$GLc{+f%MEe7k8Kl zbah1VHQixz#psV4fno?#HrI!kqX4zkH?Xi-R|4D!v51Jv^kNYzy}c+o@eMGehe!f8 zy8(_o;h3ASfuTmr4YqW>3supM9&|Ek4+37RxzOtvd5?`^!Oortd`mwHv16QIcl~9# zgJYwkqZ4cuSK?KRVb05iLv_qGLf@stWn`3KNB5#0bcXmw=*w5>rywxf18z0lx9 zZm76hE~C1QX1bLplj|Rt-!flxv&`(`6$?dfAIZz1nQ6sPeHrQO?d2E`xk72C&2-$7 zgZIH7TSJF9z_xP{$qkeBImI+E4W;Yx5oeR0c<0Chq%%_KW!ijNEYx+^Na?^I#7Ghb zw~BfSC7&hRJi&2uAc4)#q8cmI^BP{3%%q4*IoY!t 9xBk!b)Df7$}YqmKGMcn{*pu3TG8W zUvWih8g@Y} PTL&7ISSy7&zd4IkTzezx>mz zdPWw#rf_F;BdmD23XYnEA)b!GTcU*B`7%8yBu}&Eq7lJ#B|#5J{r+9hrS4d|%?%5H z5dj)H0&@6vhcHlL7eS@j97Kuw6{l+=Baq=;t!IOHYOG_<&EV!@zgRhsld>jXPLNtJ z44y*nzy=T#tV;DI-0cnY5n&+*$pz(tC@m*&SH=7$QqIdk8UJBh-#-pvrPXC?t;Ozl z7nHJf-zjQ4?PsLSi{#X0$Yaa}H#x5URIl_^s~x0UW&7xoY)$X(9~*}Tmc_sIW%6XB z=i9`#uLlJ_^w8PT{nyD7vm-*1BQCRcrZ1#U-0%pFWvz8$i7+EO1J!;i={=Wk8=J`O z@W5n;W#==IMw*5r9y?tRjs6rDZ}sm`F3Zi5a*4nkydwjnAE_Y_)h-L5pi0tTyh^P8 zk#+pZO8n*L$N&$ywn>c&+XTAY=h+bA2)(<@9>aylNX5Uz9^%R~c_B_bYS}=_R42_2 zNI^$XUee3|sSo|TlJO!rHg*tnOU@ZL{na4WE8;Q!LL=CMVbFs#^_X|?;LF9zdj*3x z02TE$7_)0*yZ y{7+*FLUAvP ~-JY_Dcf!SNp+NNTLw%uwy~d?y>2_2#}KT=LeYHo0hGk$3I)7 zg}x_noz4gj!)gId)dsP9uAxy7YNE%FZUjk7jEMh=qCyUJpH22^ejcLoO-xL@F|$xJ zmHd!RyznW}Hx=Ugp#Jsl3={!Y@8|QPq&tj@J7lwo9BdC0onbF1Z_D_q+%ucW)cAIz zhVF6TNHdd9l8PRTf4d$Kk%Tl~2?#m7Uz$Lg|KXJrou1HfB1-@VmFIjJBZ1r0L^;$x zjNtwoDM~jAKqx)CRyO%vLCZ#76OFjfMT12q3y=UzS$7G@;Q&KPY?DN++A|tMm_Zid zPBJo9T0PeXm*65FOXCsv@B !xt%Xx~zw zM>Wf=)n}vt(gOjtl)?rnH*8Sfw!6d?1n}3*GjNQ`O1J!85DHLN58)IzEASZU!;5V> zPZD^=s1Utfe8)-xL6lIs4ti89JYJH%^+;u$zZ?V>qM<=?dOZE(7cW+i7`6PA&XA8U zVl4(bJEuqsc+<>Y>>DLExfO7j0D4IdGBWCnt_Or(;}au}>c1YgZo|=yr~E+My9d*x zLJ2+-<-UFBh2kW*7hRN3n9)KqG+2keN&M+NKyIN6>QMtN@R{D{w GPA|Z~TrJ5K+bbj`p8&Co1e>bo2KnGPP$oKZ733D`zr+e;wk?g_zt!maVxU&uC zwrNAxg;4CM;QZ;fn*|uHQBVLkGO5ZR9witON+^ xlwE{e&Rv;m@5sF*Xu~M$Mm}{UUZM=hq1^`c@#bAG`Jn$uYh-Kx_H6fFy^gp9s zQrHQz*x&Y-&(|!~PNAmBC(j#!x z)qaJ>V{|pwC)@#l?VJgw);J4@p00T6l}~Z1sC0rT7${>EApLD~9mL}mxu}$~ P(S z#84YZ-e(m{CZ<#Bx9#x 8?zJp3TJx#9-*AsU^etG z061%1O?wRS{pA%n8dJrRw3s#}+KQ7pgZm58 n!5 zP;%~cYrG!0UcbMTv$tl8Zqc4r3>y;Tn&lX7Ci-jCm0-BuANss)ZoIFYwxk1Dn%l)9 zO^ENVO4d-7mugH>KK0~2Q@oD#LkQu-zbngrjN)cR$rfwDcRXRgT$bf!g5XjABmQa! zvjWdpOn%?(NKWKXm-*B?>(_Jl-<2k6%oUtj``;;~L`*pTCVYH}A)L@~%+(pK WB9n+7`UMzC@B9X=;R0UP9N`5K{wTQP0wurf{@p{qDB<)chj1c` zP7;QI%xq )fY!F+PWnJWEF6PRv^*=m!EuDqTgcWxT1>ll08=>1~oF1glI zuR8xRTZjLct*`lq)L9OJ^~yTzp(70cZ&}^J{hy?Vz`cD9#(iS>Uo*F_A=>up0`co= z-HB~LXS3T4i`~8#6%F=!y^D=kkG1J1i~B}a3 Zns zS-)XKH0n_peGEw|oOWavs)G*(8}%n0k=XEW#bhowDobMV>?)*y?lywp;2FUIP88i? zKEpo`5Oh1zZGr#y?oYOVDnWtBdpY&5`@feW@h4!wzoq`I<5%H?+eqO5y8q`A>M#4h zWa9Iu)BI z!xO5%_5F{umq<`hQ1w=uTK}Z_V;ldgNNvzH(EmT4`v0oxSDi5f1k^_inO%~?tt%4v zEH@;2dnZtnSouT#TgPF*!}Cj@s3UalTUhCZoiE&S#DfF^Ih{|+;)76l+U^IxpKS1> z2EM{T1V1Z}#q~X3<#$2$cDTvH-)Ca_cxl7g{&@qphJ=KHFPERu%ug2|FkY_CJH7Wh z#5KslqxM6ob73>0+UEt|5V=Y7&L4;1X}F0fB1&mivmcMLX0}G;%b&g+F)v+$fiDrl zgb1(7kUT<2$!dy19z` B06f(nOwby_<^&1g{{snfQli>mzq=?Ve zxzLQ~1`Bd}gp74tJ-{S@m(KB^AG_NJq&p#&uHltQIL*}l^CteH85C;eN {YFP^K{5&kO8_22e(0WnSb1|4%>}&T(zy5r4noz#DHd^|DL!8-_p(g< zHxC1b!*B5%4B^`NC1m?|dYacthJ=J*akW+kX`btw3FlauIdZBHMvXdxAPObgy#C-J z`}ZqJ%+1;KdSOIH8+0MJtZM!`@q%tm{o>9V|NKH}liq_< X!h{u+%pc~Ju@hhzAhedEt!knM zmg*6v^TjczMqes@dKtg!pJJj9ZDWo6XR>Gw#i1=sJ4oBDIbP?*n`MXA4yTV`6^Hr9 zPXcA!)bL6=m62=t)z-cz)rXIdG^$;2m&^5Kj^7XD&zUon)XK?V=z7IUVK4}^u~a~O zmfK$M3TBGVe10!bQ^POGpwgVkQD#q{ihS~8u1-f)jpC4^=ye$P#8k;V##qEvkK&ZL zmXtN!!}v0h5Sp6|A($x&IUz~&3A>ti|IrT5)md-@`#)M@8R{Dv@N=EhHS2Jj>?&WU z{LVH=&6_n*Sq=SBfb~>XR&xDM5+P}@6ka5qNf0CxnZz(CPCetvBP1hQw_oqcYU~sY z@lQBE*j!0vNJ?=>1d9;O8M9azeJWLaV+&c0=Pdx0GPr$Oq#Y1;J8+4_Dn+7gseA#a z9-~B)td_P}S%Oxtf2wfQBa9wCNfukE;rS`22M)QDp%Z|NP>6WQJo}2b21lTs= GmpGbmMAvaK$Zm~Z^sUk710osnB&y4qiFK`9EV-|!pS+nf5*pblG~um zENps_AM3u=K7bNyAUah^Y~d!$kk(TpxItHA9o4-D@lXnX`-~txgjHw=cS6CUwG*c_ z8Ok-VVQ6r08fA?UK`KYNl@Jr=2?h#O!JAuiy|U8}ckl1$p2varB}OYLm96w>S= 19<(3-Csiwf*kY8V6mg^94`kL;i=(Qau20ut&Ip ne z6gd8UZyT}x-4N2&C=Irhlg$r=Di6`Mr8V3t+ZiW{bB #78O{$ds; z!7kiEQC*E!ND|#U;`TSxiJ)>3`(<(W=@Vyiqb~E!)L et%YeGcFr>_c5 zx)A~x!DWcntBTzjSAGz8ujre=u4nL(OuN6iLl>8BbY3mGM*lTCGB!`-g~ttMQN8Fz zvG5~(Hr5MD_h=t$ o!v1=$de9rcHW8iN#vUjL|VB eNbR#$fjOJ= zLb~dm1N-WEVq>$ $ela XTFw-ke4H4h=lNo2|;IQs3CA!5hKo?bnsR2c8(>%S8c&Rlim?xO52}F zLy6n3+5+pm@CIwbI-OO$yXuoZz{7QXDD|$lW^K}2v10nJiU1|(-mK5hHrd_J2;HF| ziJv(xKsxn0F-j1w+MFSi-icHw!|=~Z-083lbwB;OkKP#BVd&n0awIo^G&nsWorrAJ z^5^J1YE`&99B|1Zzk(oH1MZcSJQvdN98k2=rFW-bMImS&*%C|+1ri>Eyj5llYz9Sb z=U$Ep8qnd)2(Z~4B!hiiyF~T_9(J?bC&57+S|8anQ`(>Tj6eGk$_e+phT<`vVb3VE z$bW5qyI+vU`fi`2Rhn|m<-s4hKpt9xpqW#%@PNv8&~5dnU^%Ck#Yl>sja6fNB!c(X ztk(Ju1HLjI*U%|G_Vyyg^?BD*KTud^@cHZ>b|9qVi&2` Yr@>N0)RW_==szMH5?ZD!jC%2a@gpak} zzM>FbI10CH6d9I0q2lJ|fU>YKpKk8LYRu{k1dDky1|S(##Fi_bX~7De91LRTD5Ehq z$IR R0NRQ8UgZu}{K*p1F#qr?J#pT{;gMR`sOgQN>xjzlMR6 z_AoGt&w)InTwUJ;ggu1UorlaI544ygtH@=qbud9Jj{)vGY1v(_YazFg3&}~>6{vpt z(py>10aXN~HqRWS+99`$6Q2d)Dp-G5b!1=_R;cNkXS9S`tlB`6=v;PZU|UVrNQWI% z=}_^bWI|8lS~W_`!L+BvPK^1yO`d~5-Tp-(pYI8ZNd2+DN?BiZ_X?4$sKMK?AcsA< z`~g4uC`yy>K_ts2tor>*fEq^wZhzuLe?AgytKpDH3?YI_%B`=*h8vb!(ubYp+v$r! zfaam$FtQU0WP58T>SlvQR16jO*5?_j(nC# ^w80$=hRw|u6>DG;x8mW-K8j3J~>SJ11^7zJZd z#9cf=PQ_RSNT{S#mQEtH;arHm{~o7|Mz;sO)hO+&oD*F8fg2Vd3FZ|ce45#{V@iz$ z)Xp7ZLPITQawM?0V#lui%~Ty6FIa(-X(cd~#+|=5T>VbUf(B9GyP@lc2%X)Ekrb!w zu7z3jX@Wv-eHe32tj^hwG&NeNNegIMTp2SpGpIgyMm!tefJ#ABB>td7$DB}3Ld0X` z0^PRES*!!-eOZ%|yhM5ue#OqN?;IA11)!F>xChiSH4qJI7qS=>Vn^yfd%EL-!(Yzx zh#UAOS7Z6%B5CqB6k){2@ 5~O5gu_m6x$g>aVn%D3(y;h#)Tn zo<0zuDL#F>MgHJeZu-t6wp*T(-U+s=8zL4Ilj6vedY;CG7P2sh!J^7DqAScmqQeAZ zI+Jja1?N?#^*)r}4xVl1Ci>HXCb~GEg$3_S^wpBLV7hy(-Xt6-0TJpV!o(-)r6X2m zmRt(LWFcKfE2RpvEyjW`qqW 2g0?{1d^v!X;+7&n3s@tMC$EeN16fYu^niKU0&m?NQ_?4i zZ3Z3eK-t==-J3B^bOx&=4_4gVTnI+<*X(w;@o4nW^g>F6xGXVg9_}hdsD!Qgw8hOD zOK7QNigupsyhAS`r>hHJ%e{%D^dPoQE3<^(9m5{N_=G |STE%H2d2h4}Azk0?fVxO5%!^Bs0Bh^G%?v>H6?TxKnW^11!We&{64FT%2bEa{n zhFd=|IS;l4a7Q;GI9+v^CXOwIUSy<>OVsS`u5tfNtDmoi|Ibcb1I&%YnK(YT*ory9 zn+eN&1<`tu*7@%9NXf?$+-XEHO~eqY>FT`Sqhh%2i7QEnG5I^}oLSH9u_`MIOOc>w z5%O9iL@Ine`G7DysS9eg2ezavj=#s VgE<4!lUk#(Cl zheU6HP|;PZnvwm~nsz#!{}EM}ZuY5WvpJ79#w6Z`xM2vS;!JZL(OJC+{Be_a+3WW^ zQymyPE-`3z5Ad |jl6etKmq}_fz*}!Ye;~)Im*Q= z=ovWY* %Ymhx5F3}i_<*P} zv+Xxb6N>1g!w7GC2571Uk-Eys;v6!-0*u@R17%cM+3__y5ao5Z>~wbNuP%*D0PY^| zz5L4S9N!YpUql-SZ3!-sdh*k1_IV)LZUq!5NJ-i97!f|rLFDm(#3#OOxoMMZ=md6h zNL0-oa8`I_dI}Yo^kQF!TvBkWL#(t`sw<#?uY9mfhG}bM_{XuBO1aA7KG=8L((utn zrD?S9(8ecK^oUct)5qlTr(1wxJPqo!;0znDDju3)4JTQzsSV4n+bOmnf4cKqjJUmy zshQubo^NktL(=VQwvvg3_!#R@b*2M;f>`(Ki+;j~ &6!SnjbSIhFugf9=$NvM zsD8Wf_f+iA8yp6U9%1`hs^Mi_*3dm=XWLCYpQ&7*s&odEbCV~Y`##>KgC7@4(~BYy z1q7gidK!SumCj)OC|len9E}%zA!%^$Hg85^$-(jnPeX!l&%|9G8v!x?VL`In2|QR& zsI?%12%gY!oH9LOGpp6(1EtolDB6S)Xf{vtRLf2mk-l|u|J_-N_mei1;1>{DOeC%3 z!S}>vzz)#Hpb(Wv>#8zmYJ0+PH~rN-aPF?Bx)V*qm}a{tVD}w}_;_!BY(L~09YaM0 z$VJxuTXGrwyNw5MgekfmBSrk+b~|)3_Z@+Fe}4_1U=XJG=^2_7sf&Kp4*Kd2i2fUE zXH7*X|M_6acwgPfb=jR+L)}~w`9eAdD&v}2@bcn#7W2_V#Z$~eSyMkwmWUWfecF{q z%phqkx$=0DV&(%fXjYWo?|t_|xZsMwI{KfD#_O$Lj$tTu!m{3;9M*7os8!ji=jng* zol8E)iEQ+2Bk=~43Carsn$39MrM1=Y@%wX1W7WYr!QSC8y!Hw`U1H~&hy594LwX+q zifxa!cKqEB;gU7H7QRlu;Bxp9jc#tT+gy;o$+YJFnuP5CvrQ;mey-4Xy0S7oX}Tj! z&q_P+K|)MMM)kU5vIN&dq~PNn@jk;^7GWBprA{cf&;!sAA;0kD@gu*yq2WwJ?2WP< zVpv>P&W#qL#YUxr8;ChK%3cXB;9u^ OBh(s%?nf|CvBz0kQhq7)?%oisvBXS)_frRL1(jn(PPVQU8B7KhD4P(o5Z;cq5r zdc@?9>Xbe vZ5NpkLRe5#pMa>v_JIxT z;iTawtwsw#mAY2*n;RK2kI2}w_5bAWPY{CNd3#5oUh=K9+-7xSzE`FXVRt%W&i&5S zO;V>^N#J_#mgiMhYi0E#Mb13+3PIlMkpGvf zeQsDJCKJ~_pb9;Z^v485;qHi!gta+4=8~y&&***~eR~0jWHH!LYV60}H&PDP{v)#n zdc%F&am)=w)UTNUFb|KWuIaZxQqoHgs^G%oIF*NfS6Nx}lxe_UJK!3cT!=CeK{{=- z&H9k?vnpsbCmg=J&UD9d#P1NW-))8aW|n@KjY?8yv0&5CNYa;#3H#*lDZm%tpFK+< zbF)>JbP0-c2MHDB>a6sD(1fvhb+ <(#CyBQ;paj9ZY^Q0E$xG<`w&UUEY0?pd zVhSdz)H@d^W5%t;d0r7bu;yjrb-tAnhW{87)~G}yg(-)oFx<*~Tec6*~}55 z@lpJ2SZ1umlq4s#)|2!aZ@yw}JGILVa_j@k4pjiw%gC-+#ckIF3yq_54GbhFs0cSz z46~CLWu&d~vC5xVI#MbM{!N;(V!d7qoH5!NI5h8*ypK`T*&}d6g3XBmkyh1~b7XEm zkVum8 wPmH-PSrV3sJF}`XEyw`{JcmrzMXd2VMF)c`By&RH ssq4w(K`lSxfs3sJr*F34aIt0h zOt5w6B u^Aud4(mQy>EAnq0o#L?9N0|BzyQjQgD3DQJn#OqT|!U_wx6! ze}a=to1c+0FCYmZykZ)@L<}s6o~Q#7`+Z+ml_S3~1>-P~B=hw}{;eA-J$=x0p1f-e zELRJc2!nZj@ZqXAg^GTWcEtRQ5Y|-zOv7q@ukpsS2!dQ&DS!}$MJ1{`xanRZIFr9S z8NtPWD}Wwt2jsaT^|am|r3^B0MylN}z AWJ~uwVQAV5U6ADjjr**s4(i zzXk6b=Mfi-FdRn&JVWNjiv$r zzNU&bF3fNI2rMyecjAp2NJ#8PI|%&f))Gnl(?6@byg)fepL%gQE0nqYt}WzMHB@Z5 z(;BjBtWoSSv4xtvcz6L9N?wiorV8WB`!`2o#YK*99Jp3VlGZ2;#3Q&S!Pa~MG1<|} z`~aHxod;5NQdCkN1PH9j-*b?r{KXMN9xPJKj)&E}`Y6K3LW*F2*8O|S3jC(yWJiP= zf-QWRqoF4^v+#YVl(oS-esYN374uQTY(n32`g1iB_znIOi0JNb9=tDTjWK2!wg))L zHX5B>|E~C@1(Y%L=@9& ck5B--R >kOqE(k?6X?lKGL11 zr@-RXX4X_0-YUm2>Dp=!9~gHohbbDm-{jGmnK|aB$QT%B+6`M-t{rI-5g^ct4k}uJk1_&Z@5Zo3 z2iE;LszsgJ4$zdWmvba`b$>gw@D+}_3Y((jc$@*F=DIh`h=`S556BL|;J*_t*^t2h z!dnDuZ$x~SHqc@+>g|Eg(<2j{N_F0DOn#6? rf!{nPyW3D#Qrl)?x{zHuMJn zrmE51H66#>#E{VkoW390aPA8vI^5+q|CT2&A8a77+_8+41oUQOcuDwu!#b=%!T(6C z^Xkj^X4PvYUkeGL{{WWpxb$~D57G%;C476ig|9dL -`$<5 zw$z`u bM8ci8JDpc(z&Qy=dfJMb--hcAEJM-HF8nE>vc%ucA zf??dvD=e}AqH6m~0d$_~n<`${YW5^~nRuXT5`pR >-n=L+Y-VH23=23sl6*ii`to+k8CcU6$aO45(2CQI?|zX9J!M@hi8YDm;!RV?w6` zGg;5KmS}sM64QByHS?9@IAJ*0Pe~-Vc|s!8Ol#SELz#)r49T!h&-7h$SB?%|j?B^% zaMV2EeB~CP2)izR<;U@Y>-91tzA_5|njq=C0I*A=j08>kn!P3`)O!m92~c?k6RgxY z4 xcoQ~! zq8|`+M=LKr24pCs86!d>MwqOp-Y+Gx!S!PHzvdWUTGD6|;7PC!eN7Wnz{ZV^@n&4QLJT#q$3bY9xmR?f4&Tgg^VG1&)7~ z_N0K0@N1iUKCg|4;}KIrKd3EQe;ssw?wmQ`0J&;ein* F_VAQUGS(I zpD9t6FgDRj#10Od;IU+Vq%&X5YPoIt4#jPRipom=c=qhTpmZFK0z-vs&fkI;*;WTW zMM9W*?PlI|g9Ndi?EFOJ<@ Sqx*?2