From 92a77d367d215bec4729dc87416a9110cc2b713f Mon Sep 17 00:00:00 2001 From: Jiajun Li Date: Wed, 17 Sep 2025 12:19:03 +0000 Subject: [PATCH 1/4] update doc Co-authored-by: Yuzhen Zhou --- README.md | 230 ++++++++++-------------------------- README_zh.md | 218 ++++++++++------------------------ imgs/eval_dapo_qwen.png | Bin 0 -> 158478 bytes imgs/partial_scheduling.png | Bin 0 -> 55091 bytes 4 files changed, 125 insertions(+), 323 deletions(-) create mode 100644 imgs/eval_dapo_qwen.png create mode 100644 imgs/partial_scheduling.png diff --git a/README.md b/README.md index c9e3f13..e6c5b89 100644 --- a/README.md +++ b/README.md @@ -1,202 +1,96 @@ -# slime +# APRIL: Active Partial Rollouts in Reinforcement Learning to Tame Long-tail Generation +## About +### Background: Why the sampling-training loop of synchronous RL is dragged down by the "long tail" -[中文版](./README_zh.md) +In on-policy RLHF/GR?O training, the system enters an update phase only after collecting **N** rollout samples in a "round." Due to the inconsistent lengths of generated samples, the system has to wait for a few **long-tail samples** to complete before starting the training phase. This leads to decreased GPU utilization and lower throughput in the later stages of the rollout phase. -**slime** is an LLM post-training framework for RL scaling, providing two core capabilities: +### What We Did: Active Partial Rollout (APRIL) -1. **High-Performance Training**: Supports efficient training in various modes by connecting Megatron with SGLang; -2. **Flexible Data Generation**: Enables arbitrary training data generation workflows through custom data generation interfaces and server-based engines. +**Core Idea**: In each round, we **over-sample** (N' > N) and **actively interrupt** the remaining in-progress requests once the target of **N** completed samples is reached. The **unfinished responses** are stored in a **buffer** and are **prioritized for continued rollout** in the next round, thereby mitigating the efficiency degradation caused by long-tail requests. -## Table of Contents +![scheduling](./imgs/partial_scheduling.png) +### Highlights - - [Architecture Overview](#architecture-overview) - - [Quick Start](#quick-start) - - [Environment Setup](#environment-setup) - - [Examples](#examples) - - [Dense Model Examples: GLM-4-9B and Qwen3-4B](#Dense-Model-Examples-GLM-4-9B-and-Qwen3-4B) - - [MoE Model Example: Qwen3-30B-A3B](#MoE-Model-Example-Qwen3-30B-A3B) - - [Multi-Turn + Tool Calling Example: Search-R1 lite](#Multi-Turn--Tool-Calling-Example-Search-R1-lite) - - [SFT Example: Qwen3-4B-Base with OpenHermes-2.5](#SFT-Example-Qwen3-4B-Base-with-OpenHermes-25) - - [Checkpoint Format Conversion](#checkpoint-format-conversion) - - [Starting the Training Process](#starting-the-training-process) - - [Argument Descriptions](#argument-descriptions) - - [Developer Guide](#developer-guide) - - [FAQ & Acknowledgements](#faq--acknowledgements) +- **Over-sampling**: Assuming the training phase requires `rollout_batch_size=32` complete samples per round, we actually initiate a larger sampling request, i.e., `over_sampling_batch_size=64`. +- **Stop upon collection**: As soon as the number of collected complete sample groups reaches `rollout_batch_size`, an `abort` signal is immediately sent to the sglang router. +- **Collect and reuse**: Upon receiving the `abort` signal, sglang stops the ongoing generation tasks and returns their partially generated portions (half-completed trajectories). This partial data is not discarded but is stored in a buffer. When the next rollout round begins, they continue generating from where they left off, along with new prompts, thus achieving seamless reuse across iteration steps. +- **Elegant implementation**: Slime's partial rollout provides a more native and lightweight optimization solution that is less intrusive to the original pipeline. You can enable it out-of-the-box simply by setting the `--partial-rollout` flag and specifying `--over-sampling-batch-size`. -## Architecture Overview +## Three Steps to Get Started -![arch](./imgs/arch.png) - -**Module Descriptions**: - - - **training (Megatron)**: Responsible for the main training process, reads data from the Data Buffer, and synchronizes parameters to the rollout module after training. - - **rollout (SGLang + router)**: Generates new data (including rewards/verifier outputs) and stores it in the Data Buffer. - - **data buffer**: A bridge module that manages prompt initialization, custom data, and rollout generation methods. - -## Quick Start - -### Environment Setup - -Based on the `zhuzilin/slime:latest` image (pre-installed with SGLang 0.4.7 and Megatron): +### 1) Environment Setup (Requires an AMD GPU) +**Start docker** ```bash docker run --rm --gpus all --ipc=host --shm-size=16g \ --ulimit memlock=-1 --ulimit stack=67108864 \ - -it zhuzilin/slime:latest /bin/bash - -git clone https://github.com/THUDM/slime.git -cd slime -pip install -e . + -it rlsys/slime:slime_ubuntu22.04_rocm6.3.4-patch-numa-patch_sglang0.4.9_megatron-patch_ray2.47.1_apex_torch-memory-saver0.0.8-patch-vim /bin/bash ``` - -- If you prefer not to use Docker, or if it's inconvenient, please refer to [Setting up the Environment from Scratch](./docs/en/build.md). -- For AMD support, please refer to [AMD Tutorial](./docs/en/amd_tutorial.md). - -### Examples - -#### Dense Model Examples: GLM-4-9B and Qwen3-4B - -We provide examples to use [GLM-4-9B](https://huggingface.co/THUDM/GLM-Z1-9B-0414) and [Qwen3-4B](https://huggingface.co/Qwen/Qwen3-4B), please refer to: - -- [Example: GLM-4-9B Model](docs/en/models/glm4-9B.md). -- [Example: Qwen3-4B Model](docs/en/models/qwen3-4B.md). - -#### MoE Model Example: Qwen3-30B-A3B - -For MoE example, please refer to: - -- [Example: Qwen3-30B-A3B Model](docs/en/models/qwen3-30B-A3B.md). - -#### Multi-Turn + Tool Calling Example: Search-R1 lite - -For multi-turn and tool calling, we also provides an minimal reimplenmentation of Search-R1, please refer to: - -- [Example: Search-R1 lite](examples/search-r1/README.md). - -#### SFT Example: Qwen3-4B-Base with OpenHermes-2.5 - -slime is not just a RL framework, we support a diverse set of post-training setups. For an SFT example, please refer to: - -- [Example: Qwen3-4B-Base with OpenHermes-2.5](docs/en/sft.md). - -### Checkpoint Format Conversion - -Since slime uses Megatron, and Megatron does not support loading Hugging Face checkpoints directly, we need to convert the model to the `torch_dist` format that Megatron supports. - -#### HF → Megatron torch\_dist ckpt - -We recommend using [Pai-Megatron-Patch](https://github.com/alibaba/Pai-Megatron-Patch) for mcore checkpoint conversion. - -If the mode you are using are not supported by Pai-Megatron-Patch, you could use [mbridge](https://github.com/ISEEKYAN/mbridge.git) for conversion: +### 2) Install APRIL ```bash -cd slime/ -PYTHONPATH=/root/Megatron-LM python tools/convert_hf_to_torch_dist.py \ - --hf-checkpoint /root/GLM-Z1-9B-0414 \ - --save /root/GLM-Z1-9B-0414_torch_dist +git clone [https://github.com/RLsys-Foundation/APRIL.git](https://github.com/RLsys-Foundation/APRIL.git) +cd APRIL +pip install -e . ``` -⚠️ If you encounter an issue where slime cannot be found, please run `pip install -e .` in the slime directory. - -#### Megatron torch\_dist → HF ckpt +### 3) Run an Example -To convert a `torch_dist` checkpoint saved during training back to a Hugging Face checkpoint: +All scripts are in the `scripts/partial_rollout/` directory. ```bash -cd slime/ -PYTHONPATH=/root/Megatron-LM python tools/convert_torch_dist_to_hf.py \ - --input-dir /path/to/torch_dist_ckpt/iter_xxx/ \ - --output-dir /root/GLM-Z1-9B-0414-iter_xxx \ - --origin-hf-dir /root/GLM-Z1-9B-0414 +bash scripts/partial_rollout/qwen/grpo/run-qwen3-4B-dapo-partial.sh ``` +### 4) Parameter Details -⚠️ Since the `torch_dist` checkpoint converted by mbridge does not currently save args, you cannot convert the checkpoint from the previous step back to HF format. - -#### Any Megatron ckpt → HF - -Applicable for custom save formats (e.g., `--ckpt-format torch`). - -The principle behind this conversion method is to reuse the function that updates parameters from Megatron to SGLang during training. This means reusing the training script and changing the original command from: - +The core functionality of partial rollout is controlled by the following parameters: ```bash -ray job submit --address="http://127.0.0.1:8265" \ - --runtime-env-json='{ - "env_vars": { ...} - }' \ - -- python3 train.py \ - ... # Other training args +# Enable the partial rollout feature +# Set this parameter to enable the mechanism of stopping generation upon reaching the target count + recycling unfinished samples +--partial-rollout + +# The batch size for sampling. This parameter controls the sampling granularity per round. +# If this parameter > rollout_batch_size, over-sampling is performed. +# If this parameter < rollout_batch_size, sampling will continue at this granularity until rollout_batch_size samples are collected. +--over-sampling-batch-size 16 ``` +For other parameters, please refer to the arguments in [arguments.py](./slime/utils/arguments.py). For more details, you can consult the original [slime](https://github.com/THUDM/slime) repository. +## Results and Comparison (Abridged) -To: - -```bash -torchrun --nproc_per_node ${NUM_GPU} tools/convert_to_hf.py \ - --load /your/saved/megatron_ckpt \ - --output-dir /your/converted/hf_ckpt \ - ... # Other training args -``` +| Dataset | Model | Metric | APRIL vs. Baseline | +|---------------|----------|------------------|-----------------------| +| DAPO‑Math‑17k | Qwen3‑4B | Rollout Throughput | **+17%** | +| DeepScaleR | Qwen3‑4B | Rollout Throughput | **+21%** | +| DeepMath‑103K | Qwen3‑4B | Rollout Throughput | **+35%** | -That is, keep all other arguments the same, and: +![evaluation](./imgs/eval_dapo_qwen.png) -1. Change the task launcher from `ray` to `torchrun`. Set the number of GPUs to the minimum required for Megatron's parallelism without data parallelism (DP). For example, if you are using `tp4`, set it to 4. -2. Make sure to change `--load` to the path of the checkpoint you want to load. -3. Add the `--output-dir` argument to specify where the converted Hugging Face checkpoint should be saved. +## Frequently Asked Questions (FAQ) -## Starting the Training Process +- **Q: Will APRIL affect policy purity and convergence?** + - A: It will definitely have an impact on policy purity; the proportion of off-policy tokens in one round is about 40%. However, from both an engineering and experimental perspective, partial rollout has not introduced significant instability under the current settings. Further verification is needed for tasks with a much larger `max_response_length` (e.g., agent tasks, multi-turn tasks). -The entire program needs to be launched using Ray. First, you need to start a Ray cluster. On node 0, run: +- **Q: Are changes to the decoding kernel required?** + - A: No. APRIL operates at the **system scheduling layer** and does not conflict with inference acceleration techniques like speculative decoding or continuous batching. Instead, they are complementary and can be stacked. -```bash -# Node0 (HEAD) -ray start --head --node-ip-address ${MASTER_ADDR} \ - --num-gpus 8 --disable-usage-stats +## Directory Structure -# Other Nodes -ray start --address=${MASTER_ADDR}:6379 --num-gpus 8 ``` +APRIL/ +├── scripts/ +│ └── partial_rollout/ +│ ├── deepseek/ # Experiment code for deepseek-r1-distill-1.5B +│ └── qwen/ # Experiment code for qwen3-4B +├── slime/ +│ ├── backends/ +│ ├── rollout/ +│ │ └── sglang_example.py # Core sampling code +│ ├── ray/ # Core scheduling logic +│ │ └── buffer.py # Buffer implementation code +│ └── utils/ +└── tools/ # Megatron format conversion tools -After the Ray cluster has started, you can submit a job from node 0, for example: - -```bash -ray job submit --address="http://127.0.0.1:8265" \ - --runtime-env-json='{ - "env_vars": { - "PYTHONPATH": "/root/Megatron-LM/", - ... # e.g., no_proxy, API variables, etc. - } - }' \ - -- python3 train.py \ - --... # Other Megatron/SGLang/slime arguments ``` +## Paper -### Argument Descriptions - -Arguments are divided into three categories: - -1. **Megatron arguments**: slime reads all arguments set in Megatron via `PYTHONPATH`. You can configure Megatron by passing arguments like `--tensor-model-parallel-size 2`. -2. **SGLang arguments**: All arguments for the installed SGLang are supported. These arguments must be prefixed with `--sglang-`. For example, `--mem-fraction-static` should be passed as `--sglang-mem-fraction-static`. -3. **slime-specific arguments**: Please refer to: [slime/utils/arguments.py](slime/utils/arguments.py) - -For complete usage instructions, please refer to the [Usage Documentation](docs/en/usage.md). - -## Developer Guide - - - **Contributions are welcome\!** If you have suggestions for new features, performance tuning, or feedback on user experience, feel free to submit an Issue or PR 😊 - - - Use [pre-commit](https://pre-commit.com/) to ensure code style consistency for your commits: - - ```bash - apt install pre-commit -y - pre-commit install - ``` - - - For debugging tips, please refer to the [Debugging Guide](docs/en/debug.md) - -## Hardware Support -- Nvidia: refer to this repo README -- AMD: refer to the [tutorial](docs/en/amd_tutorial.md) - -## FAQ & Acknowledgements - - - For frequently asked questions, please see the [Q\&A](docs/en/qa.md) - - Special thanks to the following projects & communities: SGLang, Megatron‑LM, mbridge, OpenRLHF, veRL, and others. +(TODO: arXiv link for the paper) \ No newline at end of file diff --git a/README_zh.md b/README_zh.md index f1f347e..8d4459c 100644 --- a/README_zh.md +++ b/README_zh.md @@ -1,198 +1,106 @@ -# slime +# APRIL:在强化学习中通过主动部分 Rollout 驯服长尾生成 -[English](./README.md) +## 关于 -**slime** 是为 RL scaling 设计的 LLM post‑training 框架,提供两大核心能力: +### 背景:为什么同步式 RL 的采样—训练闭环会被“长尾”拖慢 -1. **高性能训练**:通过连接 Megatron 与 SGLang,支持各种模式的高效训练; -2. **灵活的数据生成**:通过自定义数据生成接口以及 server based engine,实现任意的数据训练数据生成流程。 +在 on-policy 的 RLHF/GR?O 训练中,系统只有在每一“轮”(round)收集到 **N** 个 rollout 样本后才进入更新阶段。由于生成样本长度不一致,系统必须等待少数**长尾样本**完成,才能开始训练阶段。这会导致在 rollout 后段 GPU 利用率下降、吞吐量变低。 -## 目录 +### 我们的做法:Active Partial Rollout(APRIL) -- [架构总览](#架构总览) -- [快速开始](#快速开始) - - [环境准备](#环境准备) - - [示例](#示例) - - [Dense 模型示例:GLM-4-9B 与 Qwen3-4B](#Dense-模型示例GLM-4-9B-与-Qwen3-4B) - - [MoE 模型示例:Qwen3-30B-A3B](#MoE-模型示例Qwen3-30B-A3B) - - [多轮对话 + 工具调用示例:Search-R1 lite](#多轮对话--工具调用示例Search-R1-lite) - - [SFT 示例:Qwen3-4B-Base + OpenHermes-2.5](#SFT-示例Qwen3-4B-Base--OpenHermes-25) -- [Checkpoint 格式转换](#checkpoint-格式转换) -- [启动训练流程](#启动训练流程) -- [参数说明](#参数说明) -- [开发指南](#开发指南) -- [常见 Q&A 与致谢](#常见-qa-与致谢) +**核心思想**:在每一轮中,我们进行**过采样**(N' > N),一旦达到 **N** 个已完成样本的目标,就**主动中断**其余进行中的请求。**未完成的响应**会被存入**缓冲区(buffer)**,并在下一轮中被**优先续生成**,从而缓解长尾请求带来的效率下降。 -## 架构总览 +![调度](./imgs/partial_scheduling.png) -![arch](./imgs/arch.png) +### 亮点 -**模块说明**: +* **过采样(Over-sampling)**:假设训练阶段每轮需要 `rollout_batch_size=32` 个完整样本,我们实际发起更大的采样请求,例如 `over_sampling_batch_size=64`。 +* **达标即停(Stop upon collection)**:一旦收集到的完整样本组数达到 `rollout_batch_size`,立刻向 SGLang 路由器发送 `abort` 信号。 +* **收集并复用(Collect and reuse)**:收到 `abort` 后,SGLang 会停止正在进行的生成任务,并返回其已生成的部分(半成品轨迹)。这些**部分样本**不会被丢弃,而是存入缓冲区;在下一轮开始时,它们会与新的提示一起**从中断处继续生成**,从而在迭代步骤间实现无缝复用。 +* **优雅实现(Elegant implementation)**:Slime 的部分 rollout 以更原生、轻量的方式优化,对原有流水线侵入极小。只需设置 `--partial-rollout` 并指定 `--over-sampling-batch-size`,即可**开箱即用**。 -- **training (Megatron)**:负责主训练流程,从 Data Buffer 读取数据,训练完后将参数同步至 rollout 模块; -- **rollout (SGLang + router)**:生成新数据(含 reward/verifier),存储至 Data Buffer; -- **data buffer**:桥梁模块,管理 prompt 初始化、自定义数据与 rollout 生成方法。 +## 三步快速开始 -## 快速开始 +### 1)环境准备(需要 AMD GPU) -### 环境准备 - -基于镜像 zhuzilin/slime:latest(已预装 SGLang 0.4.7 和 Megatron): +**启动 docker** ```bash docker run --rm --gpus all --ipc=host --shm-size=16g \ --ulimit memlock=-1 --ulimit stack=67108864 \ - -it zhuzilin/slime:latest /bin/bash - -git clone https://github.com/THUDM/slime.git -cd slime -pip install -e . + -it rlsys/slime:slime_ubuntu22.04_rocm6.3.4-patch-numa-patch_sglang0.4.9_megatron-patch_ray2.47.1_apex_torch-memory-saver0.0.8-patch-vim /bin/bash ``` -- 对于不方便使用 docker 的场景,请参考 [从零搭建环境](./docs/zh/build.md); -- 对于 AMD 支持,请参考 [AMD 使用教程](./docs/en/amd_tutorial.md)。 - -### 示例 - -#### Dense 模型示例:GLM-4-9B 与 Qwen3-4B - -我们提供了 [GLM-4-9B](https://huggingface.co/THUDM/GLM-Z1-9B-0414) 和 [Qwen3-4B](https://huggingface.co/Qwen/Qwen3-4B) 的使用示例,可以通过他们对 slime 的使用方法有个基本的了解: - -- [示例:GLM-4-9B 模型](docs/zh/models/glm4-9B.md) -- [示例:Qwen3-4B 模型](docs/zh/models/qwen3-4B.md) - -#### MoE 模型示例:Qwen3-30B-A3B - -我们也提供了 MoE 模型的示例,请查看: - -- [示例:Qwen3-30B-A3B 模型](docs/zh/models/qwen3-30B-A3B.md) - -#### 多轮对话 + 工具调用示例:Search-R1 lite - -针对多轮对话和工具调用场景,我们提供了一个简化版的 Search-R1 复现,请查看: - -- [示例:Search-R1 lite](examples/search-r1/README_zh.md) - -#### SFT 示例:Qwen3-4B-Base + OpenHermes-2.5 - -slime is not just a RL framework, we support a diverse set of post-training setups. For an SFT example, please refer to: - -slime 不仅仅是一个 RL 框架,我们还支持了各种后训练流程。如果想使用 SFT,请参看: - -- [示例: Qwen3-4B-Base + OpenHermes-2.5](docs/zh/sft.md). - -### Checkpoint 格式转换 - -由于 slime 使用 megatron,而 megatron 不支持加载 huggingface checkpoint,我们需要将模型转换至 megatron 可以支持的 torch_dist 格式。 - -#### HF → Megatron torch_dist ckpt - -我们推荐使用 [Pai-Megatron-Patch](https://github.com/alibaba/Pai-Megatron-Patch) 进行转换。如果你目前在使用的模型不被 Pai-Megatron-Patch 支持,可以使用 [mbridge](https://github.com/ISEEKYAN/mbridge.git) 转换: +### 2)安装 APRIL ```bash -cd slime/ -PYTHONPATH=/root/Megatron-LM python tools/convert_hf_to_torch_dist.py \ - --hf-checkpoint /root/GLM-Z1-9B-0414 \ - --save /root/GLM-Z1-9B-0414_torch_dist +git clone [https://github.com/RLsys-Foundation/APRIL.git](https://github.com/RLsys-Foundation/APRIL.git) +cd APRIL +pip install -e . ``` -⚠️ 如果出现找不到 slime 的问题,请在 slime 目录下 `pip install -e .`。 - -#### Megatron torch_dist → HF ckpt +### 3)运行示例 -将训练过程中的存储的 torch_dist ckpt 转为 hf ckpt: +所有脚本位于 `scripts/partial_rollout/` 目录。 ```bash -cd slime/ -PYTHONPATH=/root/Megatron-LM python tools/convert_torch_dist_to_hf.py \ - --input-dir /path/to/torch_dist_ckpt/iter_xxx/ \ - --output-dir /root/GLM-Z1-9B-0414-iter_xxx \ - --origin-hf-dir /root/GLM-Z1-9B-0414 +bash scripts/partial_rollout/qwen/grpo/run-qwen3-4B-dapo-partial.sh ``` -⚠️ 由于 mbridge 转换的 torch_dist ckpt 目前不保存 args,不能基于上一步的 torch_dist ckpt 反转回 HF。 - -#### 任意 Megatron ckpt → HF - -适用于自定义保存格式(如 `--ckpt-format torch`)。 +### 4)参数说明 -转化方式的原理是直接复用训练中,从 megatron 向 sglang 更新参数的函数,也就是直接复用一下训练脚本,将原先的: +部分 rollout 的核心功能由以下参数控制: ```bash -ray job submit --address="http://127.0.0.1:8265" \ - --runtime-env-json='{ - "env_vars": { ...} - }' \ - -- python3 train.py \ - ... # 其他训练 args +# 启用部分 rollout +# 设为开启后,将在达到目标数量即停止生成 + 回收未完成样本并复用 +--partial-rollout + +# 采样批大小。该参数控制每轮的采样粒度。 +# 若该值 > rollout_batch_size,则执行过采样。 +# 若该值 < rollout_batch_size,则按该粒度持续采样,直到收集满 rollout_batch_size 个样本。 +--over-sampling-batch-size 16 ``` -改成: +更多参数请参考 [arguments.py](./slime/utils/arguments.py) 中的参数说明。更详细的信息可参阅上游仓库 [slime](https://github.com/THUDM/slime)。 -```bash -torchrun --nproc_per_node ${NUM_GPU} tools/convert_to_hf.py \ - --load /your/saved/megatron_ckpt \ - --output-dir /your/converted/hf_ckpt \ - ... # 其他训练 args -``` +## 结果与对比(节选) -即,保持所有的参数不变,将: +| 数据集 | 模型 | 指标 | APRIL 相对基线 | +| ------------- | -------- | ----------- | ---------- | +| DAPO-Math-17k | Qwen3-4B | Rollout 吞吐量 | **+17%** | +| DeepScaleR | Qwen3-4B | Rollout 吞吐量 | **+21%** | +| DeepMath-103K | Qwen3-4B | Rollout 吞吐量 | **+35%** | -1. 任务启动从 ray 变成 torchrun,把 gpu 数量保存为 megatron 并行的不带 dp 的最小 gpu 数,例如如果是 tp4,就设成 4; -2. 确认把 `--load` 改成了需要 load 的路径; -3. 增加 `--output-dir` 对应要保存的 hf_ckpt。 +![评测](./imgs/eval_dapo_qwen.png) -## 启动训练流程 +## 常见问题(FAQ) -整个程序需要使用 ray 进行启动,首先需要启动一个 ray 集群,即在 node 0 运行: +* **问:APRIL 会影响策略纯度与收敛吗?** + **答:** 会对策略纯度产生影响;单轮中 off-policy tokens 的占比约为 40%。但从工程与实验观察看,在当前设置下,部分 rollout 并未带来显著不稳定性。对于 `max_response_length` 大得多的任务(如智能体、多轮任务)仍需进一步验证。 -```bash -# Node0(HEAD) -ray start --head --node-ip-address ${MASTER_ADDR} \ - --num-gpus 8 --disable-usage-stats - -# 其他 Node -ray start --address=${MASTER_ADDR}:6379 --num-gpus 8 -``` +* **问:需要修改解码内核吗?** + **答:** 不需要。APRIL 作用在**系统调度层**,与推测解码(speculative decoding)、连续批处理(continuous batching)等推理加速技术并不冲突,且可**叠加使用**、相互补充。 -在 ray 集群启动后,可以在 node 0 提交任务,例如: +## 目录结构 -```bash -ray job submit --address="http://127.0.0.1:8265" \ - --runtime-env-json='{ - "env_vars": { - "PYTHONPATH": "/root/Megatron-LM/", - ... # e.g. no_proxy、接口变量等 - } - }' \ - -- python3 train.py \ - --...(其他 Megatron/SGLang/slime 参数) ``` +APRIL/ +├── scripts/ +│ └── partial_rollout/ +│ ├── deepseek/ # deepseek-r1-distill-1.5B 的实验代码 +│ └── qwen/ # qwen3-4B 的实验代码 +├── slime/ +│ ├── backends/ +│ ├── rollout/ +│ │ └── sglang_example.py # 核心采样代码 +│ ├── ray/ # 核心调度逻辑 +│ │ └── buffer.py # 缓冲区实现 +│ └── utils/ +└── tools/ # Megatron 格式转换工具 -#### 参数说明 - -参数分为三类: - -1. **megatron 参数**:slime 会读取 `PYTHONPATH` 中的 megatron 里设置的所有参数,可以通过传入如 `--tensor-model-parallel-size 2` 的方式配置 megatron; -2. **sglang 参数**:支持环境中安装的 sglang 的所有参数,这些参数需要以 `--sglang` 起始,例如 `--mem-fraction-static` 需要通过 `--sglang-mem-fraction-static` 传入。 -3. **slime 自身的参数**:请见:[slime/utils/arguments.py](slime/utils/arguments.py) - -完整使用说明请查阅 [使用文档](docs/zh/usage.md)。 - -## 开发指南 - -- **欢迎贡献!** 若有功能建议、性能调优或使用体验反馈,欢迎提交 Issue / PR 😊 - -- 使用 [pre-commit](https://pre-commit.com/) 保证提交代码风格: - - ```bash - apt install pre-commit -y - pre-commit install - ``` - -- 调试技巧请参考 [debug 指南](docs/zh/debug.md) +``` -## 常见 Q&A 与致谢 +## 论文 -- 常见问题请见 [Q&A](docs/zh/qa.md) -- 特别感谢以下项目 & 社区:SGLang、Megatron‑LM、mbridge、OpenRLHF、veRL 等。 +(TODO:论文的 arXiv 链接) diff --git a/imgs/eval_dapo_qwen.png b/imgs/eval_dapo_qwen.png new file mode 100644 index 0000000000000000000000000000000000000000..7caf4fd4a06a30e7182fd9808f3698d94e9b7042 GIT binary patch literal 158478 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 =#7^rjYSHuIDT&@JuiR^ z6|K=WA#<} zeQul#w!9}$i;ho@uQ2ypcjvIJvmCNRf)3g3jb01wJ(}az_WQ(BO(P?(6gXl(wgfE6 z*55(iE_%k##%^%=CVW3&KC8SNrYS_+f21fizD6V!K4elM63`;|S4R0}H=;w@ZLQ}i zMhZxuCaD>mN)$w4;F!EUr_7p82qQCO-4?9CNBLl{n@lSd+ng2GXM+~^s!Syw#oI?2 z-w5dXr7=GJm-+$5wY{jsn1~$MpXB@@txn?=y25Bo2#XIcyg=5~9?M(H$s>3aY1iM+ zi6ok6Gh!v@G4uda)8hs=PO2MDh1%e{dC6}oZ(7)948uJw!l&?uFt}3J0N5$~g0hAL zMfGaPwo#H+nK39-c#%gK;a*m2%~cpu>Cp2OHGqFpHc!#`d`$gzNFVUk1jMfyC_0^I={J%sxg%M7#P#zD{0}Tw8jc62E6-Cs=7C!1KZZ2d!pR&q3br+H0TSS{f;mz zZ`$~}3H#O6(?tPYlbU>3C4*RLhM5s<8FLsuOcwdwFVo1uB7hY{rrvaQIQkvXm$tRm zL#bNeNdO)|%jaha&EQ_BkQu`zopmh_i05fvounLdiRrWGJ;7N zzqu-bGLHOGDBrvo-yvc8S&(i#^BdMVW@j%=YQ-L*k#smu%chPR1mvEg&_(>y{NeT0 z{xMh6_9&eiX2Rnj)+RcPbYr4#4pKoOBc?p{&dKx+R0`|IiS{E55V$&0ItTl5ooX#Q zy@B%K`>>J+Y&v!lhr8V`ybwQz%&B^)n~gxsx$7BXb0&JKc&8?YmYtw;`!|-!hczb= ziVWqw(-u+~H?2fhqYC1wV{qk8bL+ch(RggLFZK+$eNI3K5o1m*5ch@_XwJIq0$IRM zna&8M{$^tmrAC!}8282goyTU>67$MB9>JIC;drVH5`&zNhzx8_4Y(HWC1Oizi$B<+ zmV3hIMConwidE53j2p#xT2cn~Qn95$i&E|0b)eM`QdM{IoL<3*oAi+SHc;0h-mM%b2` zAJ&Z1lvpu)>J?|{JkxSJJ-ndcr^cy{erJ(2Wjh-eIfXXz#jdTcw%t5CGbNjRZ(&+N zP2#s*b!m215}+bFliDB4n)jK7GMH$GfxR{qNJbnHz49>mu#(Sux1sIhW+qRiblb11 z@vSK8;nJOATNyw5gk`B+Nq;@dzMa}Lk16)w8m7g|oD&pF&dz)5D!B{}lsZAHX+x6d zOJOuZ3nW0G)2N@?-76vhuH1wK3>BZn-fv<_|GJ*W2h!gB(H#VP%Z}R?Y3_|~;;K#{ z_DDwo80juEHX5TEK@Rg`R?#ivu17017-Z>{fm0Rb)&J~nFnpUnvb(BW$1e;TpnYiq z8|H!=iaP&^X86^&xe)&Kk&Gb9zSuzrGA4+Q?h~qZx4%hGSpBOzm(O~OVcQrQUUh)r z^P?{TRjgXP08tm(GcP3QL6ELHFH%)qZlkjC@o}FWDfQM`1E7h0=-fLImsfH-^^@Bo zmA=V$J)h&_Qc#WpHG;;+f#mJC*DHOBWAYp3sbQFOWdLT1v4%bdh5mz`Q8*;eV~bj% z$aSRk^OV;8s*0xHI3xi}S;-7tyw8Ue{r)POLwH(3tPmxq1qeX2NCUBUs!d%%4&QUH z$JDX+hqWzw{CN+=v93>WI8UHKDG_0=&dxrX3nUCo{>nFd2pM$s7Tt| z!yb{I&LSO(JID>Q;0G!Bckc%6lM*$2VPX9H%BlXV{9&QkE}R$-Fg$##aPA9$bYWIiPpNdsFcRG4|rog&^W$iif-*`7eM;R46lB?58Wy9im3>quyIRaO%r8r*HVm>YWN)LNsPb*1U%q54H-bIcQJpo zh_?g&c=MjymEMKGL*6O#$xoj%dGfE^$jq{wKc+UVEzp7ZPr)rArA3Zf=305$V))Zu ze*NrXxF5EkSzAOz2k^XOKiJFyVAvDd0-2>=Pc!9jpAC*}4e6RV~ zJ2qIE$inM0E8G)Nn}lUy+!(?5F^mab8Akc2AFT3b=puCg)c5?h(Yn*2%enqF{d0{& z+Zkc~J_5d*93B2zDF8*jTqU>8L#=_k5d+H9;@W9;_(@Qt7i+%{gX%nNEgJAOr=Y`M z)*K4~b@&mTq3oE=$NMvX`ecZ~M)pjl#P{+1R+UuuK0b}OCWPhQIzagb6M zQT9n2+Zjwg>w|09-@fkIKl(ai;_8YZYSVtJ+&osf8}PyjB9?9zymV z?V^h*@z$;VBAWDL7E8fCC`clbL@wg9yn&fC__ta0pf)NlI?d?f>q?3FG`;LFf_xxU zoDuYZA-h!+F?Wg(#tfe;OK)6vJxh#nyV3Q%3$?sGHk$O7AV zU_Rr&^$nA@*FT&kAkaR~PZ5UzmueWYJPU&17+P7nv=0l`L*cnhuS6Ixn8tO+f>}kq zrYCiN(r5X&?~v%O|5>~V&*!o+#mKNd-oo(%m#o4A7&7m2-xnI*~>3C+dK|8w8 zJh{-=!RanGF&Z%Gm_XhcOWBlo&KJdO_D?`TN}Y1d9_<;O{eCHbUmU@|W)g0?6bjBrq>pVxSNtkb3&Cy3;IP5I%8p?iC!Me8REc4Zb)oV*=5xr|40 z2ba^J&_h!|)(KFfm(F-m5*_gWhTP|hMw?8Dxjkb+Ji&U#_%Q?OuS03DGNd)-g;p83 znC2Kl-A8hn^GmB6Lc;>M?FH8OtQUGI10VN!kYW_xENtt({@c%<35LMV=M5qIiKrZ8 zt{$#hbvNgse4QSKOsXhyNR)Q|J*I|qTud)%>D_*r6r*EhI-cOtJ4JB!iy{gil3{So zwK_>C;Wc|0eR{-0mEiS=b6*^k55Xw=(^;F?i?Nb6M@wXc<$0regow3U#f8?R1RtUw zYe2ciAD2)_=AhkmB2v|7<^z9U7J0oB4)P5NCfj0J{vi-d2yUP;4ova>eRgGP+O0Sg z$eqKe=QZr2SVs5oe{d)MpRa_PBmGHa&lggbD3atmB|#L5>oqh_>{llXHArCIb32SM z&VF(Pes@?byzEc4?u#FY;x(zCXxTzXjM^W$Fzl>u)iQ$if(MCPzU(k_aQE}%C!?^505_}jSWte}4{glo5NqVoiU3j3Jo6se{n4kJDn~`etRNos4 z%%;6~($EXrh?GxcH8RXHoSu3fGt8)wbSHayeq^tP9* z0Wmg(WeVyIqv6MIlQorFarduCLjEXa`%a(ThY$dDCCGvCpBZQ3Z-gikQT)Wnx;tmO zMg~|&7CSD5Gs=8Sz)ttJw;2EOE3joZsD~82k2P0_9A0PHtV2zI2vg82!?Z zJ}t%FGKowTZ7fr&dBX^|5Z?NUEvtIVbLZ$q8vZyxSJ~^vpq|m};yM1X@36LDU|Nw( zU!>yOt~=Pa)>1g1jHNmF{@mTF zPX5(`744DDy-!+@Eym*ef#*#!M14DXM_mca$+2fm#0(6)ova(H-RXCOPj(^u>FoP+ zW)K+W`(Y+iSv(#4mY3>Ri)I3CZq57pcZ)Vx>Vgeo)GSQl0-XWJUokRB^xw_j?^7|F zxKaD2Qm++~>R;6|g)g{2k+buRc7Q41Nc2pK_dhaA*d%sq3}dUy^UIri>b-wXZu6>> z_B8=zAHB>MJl>5!;bYEam^CGvbh6y1huUhSRj;o}RrcHvqd` z53riI!2nfUYCWeM9o~d(%Nyw+E*pi}ZQGqHbzsYNxoLA-uBw)n&HX`*QHd~5$($3E z*LAraRy%;5g{)MK5)vNnGf*i$L7nsE>4~=`p4M_xMBAzmIs_CFvDc^Wai-~{fadg2 z5isfh%R&=NG!pU5|A%^hCAYqPnUSQ7^-gv3h2|amoWr-J$$0W&n~71r=1PX;+>rM? zWbiLk_x_p03{dDJWk$tr56n$I@g#03)cS)P`D4qo;p(C*%{F>_qJ&R8ch6YnbYS@S z#a2wR6n&gg_|a58s`kSHd#}Tx=T*d~Z#o?EeSRZEsOG;xuQ4B!IZy*@g5^!9Rrz`L z@kXuaBOjv4E(Wl&tbmy3XGRnOZpTaIMZJ+bMMsH|nn2=f(c+c9|5R9c>lS|H;>{bn zO%BM4z%4E2h~bFtdKFF_U-Wx22Ly4bMJ(p^xIXcSUJ>Q}@>V)QkotI+lra#YM03k` zrO5nnHv;9x57`dvQnRvi8d-1*IImg+$#?cIjOdTH)5YLJn8~_*vkkgh2XPn0ICp+^26Pa4vMLKfyPO5*Ndn>JkZ^Qp5<#*q;C&XQii^alRbVOvQL#eh;4?8yjf z;g|&Ael;D-=aIfVT6Ck#Fd%lIq5S@{^a|5Nz;&UDc1s5+x4 zOZI~fnJI~0VMG9)=)ImW{Q9XkuJU#X$I9}UZ1?EUotW2&omRE~-a3Vzope9*356Sbg7?Mt&f zv#GYc>-3m>KfruKVfL}toxz&qDBi~Cak;PSyqt=h(W-kc@0Y$WO|DX4qG>E-H{r7k zbknLjFA$D?e8+XntGDN4_&@Rh6JSik&||QEJ)8O>5$a^TG{RSMPqd}=+u3isF=Hc^ zm&``X14Hcn?{S_$RmM9%C1=PYBwnM=w$RL(HFuc-=xjAN0M!WqywFbh) zZ7mF=G5$pwdxiQ?_Gov_{@+aO+)y2W3y;l8|j=dMJpGmX>(BmT(+0tyGJ_St~J2o zT3^d2VZ1WO2ou3#__6zrkgszPq&?VceLQ=y`WdHQaG3JoE_N%U<(KURIc9U|(rt>w zl1ne&6!`l0m=Vr+=VT>651YSx{*)w*#+TzI!uQR78NZb}F&)1jk`pBkBbTkvd}aT;oMfel6kFYunX+GKc0D0uW( z;G7M=rv29WS$|%=*=~KO_(BW=E}HbQV+Z78Yq#XU%qpGh|aFbYUdyG6g zWQ|>i+8O>3cs-)ldPiDc1fCoWQ53M1aI*DGQthr7+ss(>@3$Ck9)_Us z6)R?Hn($(++3s)q2mLm$q@ZW0%~?~7;ms)wiA$3VH+&MDohFIhtmPd6EdB<@cAqup zCePC6?4Qub70$?Z~8QBoLU zbzy3t!$It2TkU5PqRogU6D`*h1`R(q#1cdLpLU*v91IVt)fF70-UfNX{Co6BtEvMk zP5~vEbJVu6*2`nHc*(`{s9+|qW}RJ$1od7038>rr9(IGMsA@bK6N8wk6jD6duaJb* zbtue*^=<(>Fqx`GdTo~fN6P5S%|?<3PumT{$+^^tOPbZo%egWJ7E0fH0AdjFJ()vl z)2NfbBCMga@;S&R|LKH80Y~~~lR=YxlPWf3YhvJ>8?UUSY#SZL$Pq@%m_gycq?A7e z&V+&gmgwF&2o{*TAkVK$qdb+a<~=sBW)r zvVGq#MFa*>)U)_9;VGsl5)n{eeet3Sph0l<_8^!5Qj~ReScsY$L1E7zi`XJ9h=<5|XR+2b}bpTiVYW@>OsfqLV40YA`s!siM)qNny3>g)#E6{L+QA@J(k% zZ|~W4!f1cQ8T~P8NXDdlcztF6=aBB_A4kp@5b+N(v6e$Mc{XA7Kn}rL*7NI=9$RUM z%@!q=e|AWkKH?FsQ~tz3ohQ&d2Bp4m1hIh{V}-VfxDnk{+S0%GX~F1|@z5M`qqKJp zl^jJ|lPfQ1$0JK$kh~ryn*IoG{>-v7M~78^K9G-RwDh%J>dF>4z{$G2mnU z+Vo-`Pg0>A9HkVu7yf=S!;QoYBxbsXgIz9QXi%YQ-`)Fjdwp@=KTcTK-5~$3)?5k_ z0A!-PjD#oJDjUgEu(WLa{2pG2DfGNGL06KOe7S`QRx1F4h%$TQzx(j&_l&HYZn+zC z+9MqQMBAaxljpipWXGbIgAu&2S7GvgX$1En&2N(FwUb{q`YV`LMdIiuNQ*GS}oI6nT zIZ(3ax)sl+!|kU!jhgXZ)w48z6V+`4;T(F#j%7H`t$Nq&PvSt`MyzDcqo_d@7wm*< z0m(^v_ufDmPtbHOb%Vx?6u+=9+ilyoG#I+O0Me_!H`T+v#3y~$G2h;+>kdX|r)cgs+V7jVelAIS9>1#LC^Jmr%}ksU8rKb^j@*}#Q6qF5Z z*Y`3-t=22dnqIBGEI`F6`Puev?ff*myU7Ihp{$v#MJYT1KPX%(O(0-1ga@PzS$gQ; zrAeRsALA7qc20qxi$$6HJ{LV`z`wv3s^diPZbSjwQ^(MeEG-WG`MOZ`^rWfWOjISM z^o5vo&JXsuc?UWf#^brPIkp}StQFGhK>8R^6Ukz$l+5|}wAUUxV_Yw3Rd2AGVK&$* zycalEB^f89GWqPMqBuV^PY%C#)6n4b&tUX3gdX>3&}-42As|Ctv> zI1#izQO23v@e<*9KAktit8Q_7omES{G2A_!y<%*WatU9B?@xry`HX4zJ03f>eIF)A zH~b-fe*0AfAHNa>o!V9q-2wW7Wy?_@ls4)UhK5vPis-|q!Oi(UJ{T|<90|8VKt@!7 zQF*ZUo99y$Muq*tTYC1}O!K;U-W!EgM6Ej#K}Hyh(zI=#Fw%JJL^1kqO~R3R1TFoC zegmNbMK^i5b+@HVnRNR=iI?eSoo}ZyA+9ze+m!`lF*!|IuFM|_8 zZfR>&{~uT1z+P9ot{dC7tp-hFHf+>1YHZt>jcu#3Z5xdmqp@u@m`P@EX1?#7v)9_! zHU7Z+j%Pd?H{v1iDQwM0T}S?K%lwvrCrHX~9)H+P0JSL;PJHb3X0!8s1X!+_!=vC< z%Nop}V{hMi42xnELp?X6+*y|YW=DkHe7^(-zkhpm!jVHd$TQX9FBVvI=qja5w9F}_ z&9W*}bE4Ohl?9Pe25V_BI=sJvK-_SS0ehG~ei1cD=YHuUUYcX5i45;%LVx7#bWGJZkR=i+htYdEWelaj5pK{p{<;NZx1@u zFdJzgM~<*v{^wbeBYqJgNs~GDK&~tsTT3c6G?~hvbY&du--bwWy(_&IPU{o<^PQC>v-nCQc*e<30#vKr)?n#M1;A|>~vI! zqw*mSaXS!7{b6zf9X`r}&jJMudr)}V9NLsJnF!giIL;GP5&;gY)jnRyFsJ(!Df6TB z8h`o)%z+4-+pskPcgZSN+ut^4y6*RXOp3IwD<93Klrj(ye?wM)^W%yvSy<|sd;1^W?_>?-D%Hx>RtXD8gl zizmXcKW;T+dFEl{!qO4nggm0h6d9Osm-O$Ow}i0`u$IPb-Hf!>OQY*|#Vw5$U?^vM zFNxxw|4D8U;tx>Nm>grpx~7OCZ;ppnp1)`aAV#l*hSK*PbH9krhtSmd#3Nu9i4a~D zd#31*VMl9w2z0l0QQ_;17J9;f`yeQsJWYNdSl+XP*vWR3as7+ma#_);z0br zN{%JAIZd1Q3qK-LDk-KiYna15hM~`Ab#DhrGol>ka)$XpOCY@h-kdP;pII7cWussW zhj?OD&+})IcJkIW-9AS$P1qIQuNK@&@k55j`6k~aY`WEpCVU`^A?$}box(n1_@ZMK z>rzW-a9OaImsW7VdR|FRv1Y3!eClOINQAMo@ri6)NBe0>8oI=BF8G zFxDXhch$b>IU_WUAxQQ6*4*3|knW|~04M_{n^He1-dZ8w()#UCywq;;5dVb&&m7l} zPb&ZQnGJE_=JIDrI*z>7b^HAnZMB^8@^cX!=MzIA3w+b`Lchfj=P6ruv?mot@9Hv8 zW=x0J0FteKKkdlC`M^M66fEi`Khe^MVlXVm3iQ?$81&xi9!VF-I<=U?LVurJK{@2U zXDzxq;DuOZx3wOH$o_rbOd#5KhN5LIwPoPumc63)Xq5yG=$PbnGK_zmQEwKW2HK5ZcVG0s_G?L55YJAugztu@ z=lP|P3EJ=4p#_qd@=JqN;grBMBOF~$-)?u3ors=#QAe-OB45!o&Fpcqj{Skf``*qe ze31s9E;;5>Iqdg>jT}i+G|K>Y6yhsI#&FNS51mjN!oUiRxX2s z(rKSof?MgekM1<7WYHdy05_xaDvP?$b(MIZ z6e4QD$a{o-59)Uux)5i(cJ~tM_J;{fW_h|+$|JgPA;`Eac^+)SU>53PNyNAfz8DJ} zUR_F3$kN{-e&3;7cZ069cO0CC8rFOA07_;&Tg^ zc`GRfsjZa?>=HtpHqaOUsFMAfWD0>D5@@W`X|x@0K_fW~{rX2%`^`iW znGJkg(h^FX+5*8F9NA|FaoZ{6iqCc z&8ni`4rhpXCN3x$VPR2d)488{kRsf8g)=%HO!3&i2l|jCN25L|=&Md7D&!mxq1Qj& zD2SARPCVy@e)_1uU87KGEsGx6O%&(sp816yWrhARO3ZseIQ{#w7CuJ zZYtMlz-Jk-Ig+vO`klfe^s8cq0mi&g-xb7y94Y^EmyLoTM`LkpG%3$`lJ#kPvJ3E^3#T1H%Lub&@1Z)z69rYrcf3FiA^iF|Q1I^Rw|B&&Qhycf8 zr$J90`itFPeA>**Paq=r9hs|FUileeQgTRoVLkgqOhqt|gn(cK2`hI@r^F zIyMH9(A|-W0X67;GX>c$`A_vorg_a6pu$jQ+#zOu;>tj z`%NI-3D!wW7^0+j#s~*k@Yue#vW5GoL}m~o^_dQx4joNdDhm?)vHW1xvv4IJ)*6Q6 zXOY`>^PG9{H0C-l#347hH0yU2c+W^2<0)1*LDSzLTtBO2IRjD~Uya^s@(g(mDUDfN z9TS&!)?jV1qL0oS-1*7z0&|UQKU49i>WaCZ8txpg_C{XUCI1s@%y)v6=n-} zCw-F;6XU~4!7dK;p#>OzTob+JLJ)f;^AoaKA+1SJXU z-)?;+Xe~+=sh6+50E2)z!vk5ulC#8?`3fY@)^X~zr=G%A7eDqdrmzduD1F=flaFQ| zh26nidPtT|(e*7i#UKG&&$B#rB zUYe*Dl;Grc-NKH0+evKJ&d9(Kn^K&p)tzlWq#RU%5?2)cnxQUQ-&6@|TW2GR@*~EE ztbbI=n)9AOsuGZcktmBVv^!ImY{G0-AMx_CdI)~L|-gkId z?e5hNX(wdDc-p0|Nxg{h(myc&qGU%CsSt2fdt9s;7554GoibL<{cRsrG=uaW!FR5^ zCBc!;`ZO+IMlzVG@ae~IWy1h=Cia3zJRK2|0Vl-w#9#ZrqzhxC95{L!cYOLy;^+Ml z#v5OY2a^EV>Q=w90NJ6Y4_CX56I*sb0g zj`NplBbF$;VL)*QK8My~B7wWyGFm!FR45j{tFLY*zY#)JHhgO`E+eUC_@i^yjs@C3 z^k})pfT%Wj`90zhW2s6dk8BmP)9|vzFyI#RD}%8pGw1kSVU&n4{)EO4i(qaEh(@Zt zLAXVfadG*bCn8sD@2)4J?Q&b0}2soUf_oTBx% z(Z2G~7sBtl%h=?#Uar-(pwCbOLggxd?a!@h!0F-Y_khFqA=~;g++BiuWW$P^u^*rE zNE$=+I{_0-nxQEfTDjzL4Ddta{xLQFbI0AHuhynS3z#4B)`j1*DdH1`L^wyHjDKOo z1zZm~XI&lZjg8U|aL^d2yUJy_d*&GN9kEpWRUvCfln{(_71|4R# z?M@DLB6bPwds31AFGw39m@USI!4@HfkFYD5BiVuEZHAF!zhnL|4AiEnK?Alh{Hr|nEz4$KOc zxUXKjHvhL`BB8&c{a0%gpMP@o0~CAjOI6Q`N&+At{L&}_xwvLE1Kww7(An?GyHR~a>}9IlrDS8LU(KN z`_iDdFEGN2>_*tUDvKypTv4Dg7WO4%^TKpL9lq}Ofi$EN!iJ~p z_|}D$v@M16oW$67l*V+AY$!(}2cusTsD15ssUXYy&xgzSs=FmUs`IgWEz%D|P(ZgA z;!QBhO1M(X*Vm7%0t_W`DxG_pv@(B9L-Ghb!UtK4rLnwt>JaEm-6OAcja2VOBj%@;3I)Qh)KB7$qnq6j z-VVt#GC~JCI9S#g_ah$qQ<_n^pWpe8_Z*#9+VOtpDex>V-^6Gxxq2F-NwYt(!P(4; zs={@-8DD9kTxE7{g9}9Dr6vsr0BlLVBQ#Rq9GvNP0}XVdTFd_I0OzcuoKPEeh-sRD zufpO2c=HS3d-aEM1rIX4+AeC?kKeY;TD;B=WoxUw_wm4VsP@p9@&lnBwWcYb@St-r zk>B&hvmCJ3>QmIR{6v?DY!^dp2C}JtFcu{l9^jMK)`HPl_0=;p2w0&R&P8mJG%yn< zv9N!;Q96}|@#`y+9rYn65{yf@1|*xa%QObEPh3@2cP`rgGoge;zKfy(M?^El0FKiK znoiCo{tV_dDioZlU&CfnHg-7IaZG~k=o*c=(RL%o`I7&bAPDduCa$d*eoe!wk+ebg zWAFHJ$BDSkyjWSfaq()5=cB}=N$S=0gG!q0LGY5tXu!@Mcr6HX)R~KV>~Un2C6-Up zq{-RO_m{STT4S#B(4FS{rOs2HeA^~LtHsN;eK{Dxu6me$cvm3o5%YADHi_qtAZ5ES z!Z-xjod0!_qZpnh*_-z1H;1U$@M`{1p<{|1$I#2jWtYsfemnBAk^OjYbnAXFV@M>; zVVB*z@>_rD|57EEh6{K1UxJ@pK36NzKMSeA_*6ZWupkFg9$$K(AzY#1p00AjF%n5>@@nJ@t?Af@tQ6MQoJ5Z zlSBypcYJ?+$dUVLdK=nHYXFpzpm^L+PppR@ZUnq7+O8%Md$s+B}TNt7m&1{Emg5Ix5arObhXo&*CQ z&>#OLd@m}*@5;id{nGcVh!zRLNTZPd_Y}uKQb*4kX)|&jx~aUiUliX4Tx(l$&Aazn zU(?#58GAGz_@^5f9+(j*rYN|Pa=+;-K1_mPwxRIoMK$m5H1W$<^yoSHbise+Zt4IZ zJ$kSyrC^N-TT4ldNQ+6s95I$gVKB)(jfHhYd0;mb9Ms{AOd97F_Pp@N*Dh@B9&>hc zr!jDKGq0N$|Ne|MO2lY0-{h<)kJY#G4k}+N?g*=Ye5Q#3} z--SQm-{sHeVf?fJW!Nz8USnm+{bE$NmX(MCPd|{o$=oY;z11B1j&2k(PCl8CzJrx8 zZrk{=@MfSp3Z)DD&7twNUdLmiLIi8NfW6{8`r;k-Zxd34dRHH~ZQx$GS{N0Ze%t0v z@KLM$#mB=I)J#V*HTI7riN98jb)V-z8@b(Gjrrs}h-rzj zZtjEea@tZZ*W;un7rWX7VIZeCl{Nm6aFRJYMw+!rMA!uEJVqBa!Y6{%W>y_?s$X|s z!PQvhN(0XAz4<_-{jX6IX7>UmOqs-Xah)_{IzoKw!vCYfLo!w1-L${?XTJBQ~F1ri|Bus(Eu3znRIM zU*zuP+bM0=Ii+Bwv1dFy7}82`yR&v#8j$_5mqUbLOUBEVWT|C~Kfx~$pKm>RF~?k= z{Uh{uUv>I}T7Q}7Pk|O$@XnL5b-CoysW(l~T!;}mJ`Fgx8zLDQf7m+%1HGe=mKsw=j;@590^ zpEfJuBn}(DCo{A+Y_#pOT8bj9v>kcxo!E&yr}_LL4V1~Tz<+5qm~0@C6oTAG09;CQ zOv?TmPeXX_W|vgt`5XQw=n;pf!p#uC_p(_QKwLk0CDw>>C;2-V9}R+_RnHPtcz^jZ&u+H0Vdy{AW?Tb&ja(aE1vE9B}ue58@dpw ztgFBdYqffOMO`c!lk-f)JSH!gvmI@8Iv>#k54w59J(%E9Pm(sXv51uzw(x_8u2$K>V%JQDD{l#`uX^>)YGg!CF*!RCw2}m`~p$$Yc zp3)@t!6$rwjD!BEoicuLl29tWs2RhCd}WPFk4E~Ipz=YCcEr0^A)DEJnORYm&#Ll4 zm?qBEJV;KxQwR9758v;9f(A87HXkDoWRHXamj)RMZ<~z*ud+K1Y5utx6Kb)~`c~TT zk_sFn{;o4_60M$|weZk7h6&kYP)>i8c|V3>5<zzW*pe(J5Fa zSs@WhRHKOvh{di#SLW~PBDO=alWN`OYFom#m}pV8wyRmP&DVmWGR}^=5)+iTy)MYS zSj>9oR{CWonEDeUzPcq*7k5BC_WZ$j8XsX_#0rJh`2{1%X9oZ>d@=!H&?R>25&Za+5!)|)`F6PgqshnUCd_H)>^BDtohGh0e)b*Btv4@fs?I;FFuf$%`9~BqJnQfe0u5^hqTuyE%8$?IY5;ry7K7jN zPt@>rvxwJR)*F+cj5~?2WPnpUx$hSdEwqo&MiOn$nqq)`#%=&A>uHYFQMm#!f6eeZgCPEsZ&u2Muu>R-!q5UO+dB1l8*({zg-T6IOfVNIlLPR2}y)`vyXeF@Cx zJxYsyLoa9GB}0hO47vYp9ZQwViVgqjvL3QgU+@Ii@83IKSX;VoUxYsNP0I>&jZ}4RM3PBLmt*uX=h9#%Ndfe30Q$hdRdVut1&iQadM`p zDjg@`Gutrg>y(tCwFNO$ak7OlNo+(v3EXqYnCnKaZ`3sw_28cS*u3offLDg2*0nTb2iHMw1uHwR_VwHqt39<^=i7^!llD)Ni=X7ep``{Jc}iycRiC0qFpN+l z0<=DRRW0YSAqLmu;2=t=cEW>qZT^Cqb!m(33D!IL=fIy${;PscFM~CEY-?uWhZ~Ud ztShhG2tku$*=tVtX~(A(L))l%Q*auXoSGu;N0ra03jjFp@V%W_N%15t$y`RVlmJ&%U{BUwjhR zQG7b{+3VDtq*uf&1hijKB1ve?jpe9KC=(|8s)9wlTRr+#H0>t+r~Q-&cn8XIG8Oed zNYm}PI@fFC3^LttGHmdMvHC;*T;ZkY3?8(Ai|xD9!)e5CvY)dD!*=87$p?7P8eBke z6o0@f0W>b}OtPmA7nhugM1LWs{J*nvTjDVP=tb(9Si|JTEL9JHt~>zDCQ zaQBPR{kN7c8KNU5+F8=XUVSFJ*NXSr`U(FSJ(^MR>*X05OtD+>CM&JT$PtPi^4;`2 zG`W4;Qp@#T7@M580q+dn+Xmq-T~?zK-o8iIb*|%K*tT7l&I;}qnNRYY;f|3jqUqb1 z(C`kbbL~wJ3l&E%NGS4GmGG_IkpXUl?GD|LD6cRgIem|dnPa@Y#k)q+AKXPA5JkH8 zF42$Z$A-`3Mz^MT4I>s-q{tk=_QrdJ^cGi2((HzxAV@nh4;d0us-nh!cy+6vIR`<9 zm=+6m?;g44eP{T$G=o9C|HBrCoBXXt`BL3gPOkK+L-8X9P-buS0*wlXgflGOPi_@N zvKHqRJJ`1)AkabCj}M!J2-$`pM$Zs_2&v(K*%{WBru*$8*vZ)f(j~HA5TH^Sxw)HSKxalBo4pHvmUS8dYbJqL`rE(*Dvlz#!VR5dB5(WggGHzlmMRQ}-9x6na3(#; zA)W#>+c$pojk?GH(x;CY1-fgz@M#Q?f*%e9=QubVsi^f5>8U$kMs^Q8?pyvgY3ThZ zxiT39n79%V!@Kxv!tFvGCabVQWlQep0wN9IQj9X2);1&eE|KA}Z;4T+Y5Xq{PUc{D z|DlP3VHHBn9H^gL3_L5$azpE33)S2g38U#l?B9TtwF zVc|6WG_AjFw`{cCB#YakH5+*v;5aP=hh}Urk(Il)4}|(Z;Yn!z>2W8POs2uTx7zUD z+!E68`NmC_Rh0Qe(@w0_h>GhR4W*2jiJFOgjyIvZmEas;yfPEEeMG#$s5s0V=WIu% zJ&A|kLFqKt-rUrXflLF}gU?I-gB#T33*_{@%6}KVqW+aPbxp>HR33wc-DSk6m$92n zxeL(YfM(sWN5Q{CNh|chnBRo$gS(y58wG|D%EzZe|62gD|C@x3=orj^sqZ)3R=W1F z9~3qMm%2l?t?SYch44yB>*Ww71(-PnK9wEVG&qEKW|$6n|e`gP)Lr|AIV261GjGBh+b2D=)Qvr%yIejU0gd&d9>T9~)+M>yBt%2X0?^*;daXtPrqg3X_3@DdtB~!8(p6+&!LWr5# zZ=S&`ovsQ^c=@1O+>NG^yF=g7(G0di*Ne_mr+Lr)I3K4EB#((q^$8x5OJu(zXw)`-ae7y)$h0;q#YB|RNq$!^!P%A%Kn_8Mv%RQBD`_T-84-3 zHv$6K3I9XL{~}&A9@`ldERK+bkwfuak(p#0${(GB?ZMr;C@teBhva%QT)?;325#sb zf)*}`9SRais9|fpxNX^hnCQ~vAhsmQ(=Xu?d9NRLZCik3iLmGAk=!hQ*)H%sw~018 z@Abi$CO`%MO%8s=6E*$u()Nv(++d70=&F6C?FkO6v+j@m(}gf5*OGq1mRo3=P7swc zg9CJNyR7n>GBPbm!LK^WzObD9+EsG#PxwhFkq?=elK~z~>(wh=&sO~EBf2H`cB{zy zZ0yiT*!SM1W=h}p`ZB)f^}5<590L}`Pkg-&KI;^Ft0&}tIUyfX@F-Z3u<0Voml${Qrha!zgx`-`* z(faO39$pS%dn)(j6O>Vb;{`v1j^vKzXgfucQAS|fSfelU^2$f66SrN5&#XPCj;{A_ zfY6oKDQ7iM(e5p;FWtZjl|!Mz>8rHbKItVLW|Pz8VEM}y^%E{MybqDXtcteUITFOs zOol#Hp8yx7Sli8BL;0q~bkDEaqeac~vt#@BJ4rKkDd!rAN9O}7C@*li4cB=Nue(H9 zEp8GB8B;N@vq^TFXnGMu$%GRS$hmZ4A}JO7uK_yoKmw?@jUH2jjFdhd6lt*C@Ru#9 zO?Q9GeYW20FBPBH=*M2(-W)}y4jjc)bsPrIJ#LS#0fJ}rmPDEuQ#XlwoCb+bhfjm#dDrQQ3vLy<0g7Gejwo^5;a=S~JfdBy$`vD-6JHLTk)lcK6M z1!{zFCeXIU916b$yke4-iD!4Kr~vQs^zeP^s6rPSBYgg;gxBiHhjmi8vIe2{bJ3vu zR9m9zgd~6D7N3qHr?=OL>Vp)&hSxvN2iY6mwl#O>ulFh)7k@qKy9(>Ivzht#-(EhK zJ6s&z=B5nV>*jvJ*Dqu0X_ZyGY?YpWeXiAO8CorQKG!>?{&5GhO3CSAqtP54(UQZh z=lx6n66h_jX5UdE;M*Ta^SepFMAwf%s}^G* za0vY4&aU&inaSs+!|Iajtq6%+Sn2!~6dEwyF{k=)bchA=F*mG`G_4(FvAHY1rDprF z*T8z3;=35Cy06jF7(`t!@@XSewMj*C-{xoS>ODPrSE|s>29YO==lIb)YKp4MDbTS7 z1p3Z8pzz)lzf@a^>WX1)kmtv7;%`DSn)es<1BJASE?v;S18Mh&8hh{@pn*!3%JBn zij5;SbtH4?GIsBhx=8O|wbA@nulu^WT;wL8T;#92TF0fB+Vc?buKmLM2I?lUE74CL zo|F)pPy1M>dymPt!}BfG4Kh5DRa9dyTQKS zi19q06(~6@-i_B15Ts$(u2us$mQKy!+i+Xq@Gb%&WDi#bv{4Vw)HG@5=$9oe0&ni` z94T{x|NcDtbNnTlQ!Jrby{@RC8ixP>s@4;+SAr`$c4n$f+MSCqhn~Ufq0&QpJgcqy{!U zBHXynkx(hxlQ$a0bUa4M9PL{(Cyx#x>stMC?84l+^j|U-Uw1Ku7f{mAmxrhoQ1_-{ z;lt)8C(r`-R`-&t0Oct{DSb3muZrkHcRo{Wj`|&+$X3cZ6Kf2d`|X)(^!jeSlAByQdiaN4;srlGU{jobsPx>r`g^q3}+(sJUh-yL_)Tia~3}!;OKg1-%axK^7E&|z*7sKEiBj~meCYrzeC*+dX;cK=- z*SC8Y6PmHTG{uWfmFb}`j~DTg40jLi2JQ!<%fc#^*ed=O(5ta73iY13_m1bDSVNHe z{Wa}a&dUm^f=T(>8tkreFsv(tq2|+7X*QWPBL*A=7OU=u2)MLrJ}ez#2i{vS|I`a+ zZrN>B6KSleaq}d_y%hEZP$48_rEfs1mZ>g?Ne@Ms9u5$yu?O0G(({@ax21(vSHFDr zW+y1wnAGnOReQY;(aUz*bYA31;^M0!s_Cpgi51Q(2foUx`8anl={r_2dB4#=(MWEq z=zr_DTt;8~rSiH?t`5+DYG=~D;!^88U{muw85|H^3RZfovN7qMsLl2Igp+M<6uVf2 z%Vqrh8?aC%6mEmw^@dtHKP+=4jJ(f%Z0WTyex}b(_Dkz@{zIP{JTw6f!Emfj{O+X) zN6*_CE)fU)JR~>_l{r!j-DfpJj()T$EO}qqa9bO*(w#LYSFiVXQ8QIL2_XokJ^?1a zxt8|?NtHhrx;vgXajSWrB{{Wpphw}sjBI$_iTAT;#`+&&q^*`8wr*VJf3hyG5m*9P zDTS`JIXjhKJye%(xaJ^!7TNJmkF60+?!&$V%@?ikvyx^4PKipiGqA_h2{r6{q-%O$ zy0C)osLHe&sqOU{y)TEK+Qw4#jm_NDLA&}|UI6?aAhuffDS5fes=nHtyYIA6_n1i6 z7u>0yujem|JgVDkQ>Po7_pj@8gd|+P7ry0PZx6*xuZN5C8~EMDpRaZnCl}vhK!oY{ z!f$G7PuoT1UZ=X{w}Fv&f|{|VN4+(gu*ut+%{Q3zwkc~mhqW3haty+DXIn{})&0F` z5!V*vw+3-rL8Cgki81to3U7~kBEa`5!rQK94D9&v=j$@~61Vu(IN`;N#I-{U*vd?0 zSv6GV(_fhg&-dSEtW5YEzj_AEji@Lzzaz)yq;v<-Rc7{k9h zxqK_kY*9L9*XlvD&xug+Dk==TIBqC$T{_E5SAFz-@k8S&GU5%lej1glxf4Us${&dH z$G&s6b@!>>s=w*VXY$@ew~)ivw@fjko?ql24^xeFoAo%5e944e?=G}CC|2n{1~R?% zO&#T2e#8}a$zB0H`<}k;6-BbC?B{Iemba`IS^0X&%)ebnT^O^`YxP4$uQz`?CUal* z-cR;ad)-AY_gW-Zef(?fijge>+O3)bOqLjb{$LIBF96$-!`9(U4Z3jz9E`mT1?D_L9q2m4>a;PI zA{@Ep%gV;kT8Lf00{kC$oR?K;j^-hyOY;}+tE&}olAKpS0YCGJm?j-j(+fwOSW&-1zMq@r)g%Dp2Pv3gy!0#!yA3-D9!ha zSI4_{mVvb@mp3d{k=$>t11Lm4-EtKWr*8rJ6{q(^!OkKj`f}%a(i1|Q79XG4sZAM5 za;9#PYu;Wgxp=ysoRnLZ%GSUw>GNP$`48Zx>TZ!nva?k`Kwq6J^w7|aJl>DH+FN2a z98O4PXO;f$-dQp8lQXr>;-(_9oSD=o&aVZ}ok0h~!2%symnDd2^NgIL8?AL3ohV+@ zGRM*%=rQ{Prl4Po#n8{@g`BXsN3&(N%illU0@}<(sRrele^O!#&@`?VWYCtyWZY#e zm2$@=y2FsT$Wo)!ES6T?eSZMdQedTVnS%_qCR+tCtd16Fe!@*;3}|bFv}WP)j2jnA zF!;Vu_cvBWjJ5%-MdX^i{O{?i>%9GT=Nr<&s^z6fPxY77%|g7%r^L~&Q`Yq%iS9=H zNl?9>-qY{os#W%o#?6^aHCJ}>t7tW6r@WQd%x^PQspqa}3+rtQ!pD;XNj^f4?mo5F zv3s93j7>bz$5Max3HH1t4v-yYjmQR$s_>}+UZcu0nNH3*7-orN;7o17256)N%1?p7 zxg0(FlFHS^xC-)^RSNriuJUw;AF>#gslZzD==QCqOOw;!O@%czni z;=uN-pBycn!)v$XbL!I_-yqZSyJS{`XXS=2vgWmE+MLHC5g&&X=+%8-f;qJ58G=IooAH!QsZIb6m9%}-T{i&%)eO+(I;{V1$1! zDWOVNgLW))TNx|kil3C?fOjJ%JqxBY0@#Ll!!t@nSxEggaTw%|ubt|l){ zVXM+Jx-(&iZ@(ESRT}M^)Uqx<_z{_k!MYd5x=fFCq*_^FswnGbd{V18C@ZYzR)Cn* z*u4FDY}{FIW`?5vl72Y9k=j#7uKw0@d6a@Ld;5t!P-OH|w#cPI(^U0&rcHaIoVUv4Q6sdH zvs{&CbwXC5Rg|ypi^xsc(D*ri7#V&+j3EKzBW$PI9HjyJ{9P8C?}hYBoo{K^ls7j* z39#EUyj<9Gh(!VK_OANl{B!EzonO+a#<@m??1SptDt0?hV=c5ZEowJymDDXLDQ`aH ze4ZJ1!!fZzS#`d}t;?0Qk+nhz|CW;n{IeP_YiC0PaS4h1rEhgZtnc51rj56m{ z#s1<-LSvEVK`q#_XofWnf-~@}5L;W-XMLQH@}DwrG`?Z_Dpz z3j{Q9YKq67kS=)AeUGK$dQdO7n|$m}5ag>%&hhazN(ZfI$|9L5;46@*6BfF|*6wuG zasCGD>;&Xes@1$_@|kt<^OEhtXAO2VKbS_hT1nDMJ;$nYC6>n;+X4Us6FoYUIg`~f zu^j)AUYo<9wrm4?2rCH0PP~o_0_=5+^w&4##Z!F9H{rI1Sy!eNUb`!FiHeh(b?1jKr=jUhONR6`WgQ zoJMG2-o{q5mFC5&!dJ{J4inUFl*_Z9d|mMiG|dSDZFmEwP2k;q8HlCmc)vA)&bxY@gi5GJNXA%FF8l%3blu{cex z1Ox+Cn@cusLu|+5n>5;t%U||QMjUs%hHE$UIH13_TNms5$YaEqfO6UnOeP_tGyJaU z0<)!*Vq$I}>cJPWTdmFQ)-xuJn!Fyg4zF0w>iS*t3qpqixAh7nL@bu&V%(qD&YZo125u8~nG>gXFM zN49D8CpuawGSfo9U_Mg2VoV_I=Im6~c96u^s+E11K%3Ln7o#{q&v-#mR!NUY$`O_HWuMdBOgDK zk=`z$v9FGa4!oxivHXA1M`jhjV)?kjiM98h=Lc!MR8@uHV{QXHkWfmOtyOjjt01>G zFX?6X`qBxYB&|*;&^8&XEdN}}M-k}fGpxxk!>W5Vx3tkECYqk#@_0|W%72voxD-{M zEl&<6lXEqr^Ap^vO-MrcVkzADe~ouQ&EQ!TT-2gomIojK6bpSmzhY5!PL2*HBuqhC&Kl}};Sw;CFQ zKQ%%Jg`!l%Qe?lnTl(f{XP8CKAUbZ-Co3&M3^nO>2xqN`8|LWK%wWY5lQ^T74#$4b zI>Dnh5%>-YKKw`1!ULY;6#K;y(+f2mNmh%gY%9VF@>l&l)>k@Qb`H#3X;WTXY^N}= zM@Lf^Et=Fx2nAKis80?2`ygEQUHVEISxTQz@R~sO&6;&5;7q5BbWu>R&FJ&E2-2uF%c*@dCd*y-L z-)@$f-X@*-oB6`jBasl9ZZ6+~gekW>y=TYo^j6mL--tjD!G{-Z<$v8a?2YR`wnnI$ zPbu%ygPpwg5xLBBNEvv>K!m2u$qgtU2^+I`L%i*G@0l@CY~;9|+?s8}`S=JLaU)Ph zkW4UjEDb$#E}zQj6=lGAVhe%bbo8RO5EQMov@SR8`NyTgz^?LVZAU25p|TnLK;j~K z$)ex#YWz#B@g%wYC>jJ)EdKuZ&kwa6!!qA7(n?Bm(U9Rj$vdVy-vNEUJp#SQYj9p~ zQ&nG<@h1{sHkeMk4>tZ_AxY!pu$8~>RMtSw{Cj9mHj8uTN@AB=GDS`fgJL0x?61FJ z-)JQ0`w+9I`P~HgW-D@iTUsWVTh_`-PHf#PR-k>=?n<)NqFWSCM(>B1?awqKy}pRt zucoT{I3}j=CPL6mSf5E~Oyn>=8Ul5I%;>WTiB$W;Q>9PV=gChmnL710MfHtNvT{sz zcdyAsL_c(vAPuP1hG!3?r&_#A;=?!KCkz7a%cEH64g46Eb4)}MD%cve);Fh&s#~GJ zpU@HVf2^K>48iLguTnoWgYU^+ViG4HztV&q77TmU&{8=mx8qe%n z-K}nWRRMw_of?`lO|?GHQcec?zR$91yucfuEw9NEwe!55bXqXgzN|&5)M%ZNx7?{c zA1N09&wbXa)eTQZd%kw@Uu&OJ4D+!}i6uFAEJ`;FA$t|KlNPcuRh?oh;@z&p`k3wR z9lQBXy~`Jp##wi^*;SE=B=C4tepUA2*cV^;n!Jjhle2Rurn5y#&wBrQuH7D#+e#}9 zf7G~k`-u=vWtjspn05{%edRolwhmxE2r@0_KucWzBZoy|pk$pr*MFaH3{^+F2y=*p? zO$DI;u;SzQlpR}ok_Gf)UVXVPn(cBb&v(1noPk!Xe)f=LeFg@MdNbg|tg_B^6#v;! z0f{x;k}j?a?TZFE&bN#8T%aUhh>eBdh?SxgGQ^VGmCc;*$@J{Go`~-55zc$O(y9UW z9M!rGebgTBY|DS_e^9;l?Jl_Qe(tflY|vMJMECj9V?P-_cTnQpXD!chWXV%Mm6DSk zb)LGx-0~gx>w;(HLl^oA_)(c|_Bk=8!WdHvq6A(eoO%8!+JM#9D)Vx{5aZZnn zm?P{Ss(`^l1#3=kAVCa?wsJDxQX2y2{vP@!NO-DQzqS$es943q?zr}5&r%I=q^#EV zYNqz=yQv-=`-2XlsUT4mPNTZ3uE~l&q!ZWyyexlwOH)E=G#BBkNa=1XT&U605OBXN z?J5D@J~iuNPG1FrhMY!gS7Fk&A$Y7^TM?L8Iy%)2;pLL1R}&6rZ<^;s4k?bmE~rM* z#rwnES(AJPA!^^PMcv9>CTlaC)^=R{@3%h$P`5ey%P!p^VCs@-6 zN0}LCxe+1 zP|jT+_^+8&-iEonYWthNg7igl?}dT?cLy_;)!x4P`~Oh&-hpg??fZE9rc|xAimKV6 zT56QqtEj52Bowt;qo`3MMkHFZ+oo!7k{UG$>jVP|X3_o;U_*2~Vp)Fyai4k%gn-%@qpX<7Uwq9$Bjl)`{XqU9(Hq z!;)sO)wnAw9#KjNSt;Y?3s&EWi^eCi>td-df8KS*i^oSEEsA1Xj4%-|i-z{E8QS#X z^BpE2)sUHX$72(vmDIOupCO`l{Aszw&J*IZapGvSwi5=e(xUzYSLmR1b_MdI*j@Bg z0M~m-M-3c4c@9E1h2xz-_z$|4PibB?II3;KrjPSg;4=5Bp_=!#FYAEYnZ^Hvjvt(9 zIX^DcI+UTRKj5Rf;P_S>c8#27&f;!-sygFBX$ND2{__mx6+uDKlk^?_DM5G9>sLV1 zAzH|>`eEN!oLaF~tGrrDT1RLONTw)wpbQP$1Kx>NY;aoa}M zo82T;@+tp+3QVh;`<{a{l9gJ47dwJC??RqOBhox=C5r0*`RBKDiz!6FvZ%43+FfNum`cjpDGR0Au&-^v;oy}RG52RWO`uYNMpfK532_yhfo4KCPu=3ukyQA zbf{*}cfXkAVP6>Q_8|WP%F_t$g1+6yR^d%B18J~B#Z`DECB2LQ_a)|*WSQKFs@rL) zV|ePilI4Zeog8H&cy#(dIN>?*(jog;CJL^b^k6SRVZgKKvj^(O(*(NPM(U@g1HYf6}V3* z$O}d;N3eX-L1(CLX*lns4Jd0mRu~6qB#2yliJdi1<1DS$7*bh2TB^ZrV45)U%e!~h z@R+lPbw_>bsva9PRN&OML#CA~g}A)*?y8uOvwAhh6yJ3*lj`SVz7j7TTSnN#L;zT@ z)C7+NktmnA3?=5xUAcI75KN2JnlxDUiXSomwhm?>);$(q>oAflb-OggQ?#{r6G+$U z%%%(pYku63H|5`3OS(~Q9M>Yu+@6oLy73;1o@H^Po`3&ch`mAVB>oIBZqX(5?e!}u1UVApTv34}%IPsMbx$z5iZ7BG63N05$4a)H7bx4bP zX+_wcQdSo9T_WUItXY-AyUI4WD_Xw}>e=!uzsPei?ApDnCA{M&>d$(?DKg>?!z-Ic zbevk;xlDo1fg#uU$6!9H{b0|VQfJN`)Rsmh`DrM1S>&hwyRK=|5ZqU^cv~V02&i5u?CPNbPlgwEaGf@I*eKVqP-Xy8+x$1nq2r6 zAYQ4um2GYho)lkn^hNfT(+t+7tQhP0U1!R?AqhHbSAbLJ{S3zi`2)c7kioU{7Bo@n zc29?Ez+OEj-B`58q(if(7=?K_KhsnKorJd%eSZ=0}(%(`s}rL zwGx|$4&<*f3TQ1j#N5S5kkX0?vF3=jmHQFcRZSD*hjWh9s_rFkOqw?S{% zo(@$rbO{rqLK1M)i+Y`n$;SuP8~u`6$lBZbS4eM;7wYBf6Gv|$ygDaSCSWg_Lj;zE zdJ_iZ-asTj>>JY#(+>i{5qJBIa{$a@_2NhU_axAqpVbo*FWhT%HEYshzwYj`@`^qJ z^+KhF+yp{!p)eonpu-TcD_(D&Ke_*j{UfUUWVV1(#8eUY@%S?(s+AdAu&@fK$?GQW zA(KJMu`q>8{Nf4lKi^gFFU%KcnDEoW?dcKdjPJee!BS{i+$C|8UT(E5)2-wgQJY?g zS8xuD3fr^bk?~hbsz5262(0;hxUil3o%wD;QM8fyI6;E;*&M)Qh(%2)vIq479s_rA zUIF~y9@_YiOMk^D3qy2>huzFOFO#z(yw7d$d+Ph5Hd9Us21q+peTfWq$0mZR84Nk{ zyX+&3(GU;3<|nTrXX1SI5uf55H_uR{lBXlTU?#u>8n}kh03b;9$hhxcxqGvis@9{q zJp2cxLo!$2H6Z5NvhV5RMvIej-%hJmsPK(;zACssNmwSD!HLM1oxbL$e>xZVNJe7SR-e%Ldm7rU!eS8nM9G*1b=sZ!0OMX@E8GVl${g$NXum9F!=#u<7n zbdQ?_quxM|PFiA1SoS4Z_7|GnL*-Gd#nBOS%RD#94I6RNSnC7B=V@GYB%z%6vCmQ| zKB&nQdvsKro^h*GR(d_1&pPL!TQ%A73EA^ok7Yj<$5U!7e5g*WOajKG=dldzq20{AmPcLN^vH0jZfubZV&`Pz z-|_8#^i^0-e42a!YM8vHWQnR%<@29~?rnun#0_Y&TqEx$dl}kZ-042ba;z}F1n|5` z-?_j?Z|wNLh>N(p<6dy9qC|NE@%Mpi(YJ4g8CpDar>Qp$#FC|Fus|-37 z27M6<0`;5->ekf1+x?-{*O-+HEiD@_a^PaJw~FDOSF#iAo3^FzyhUc92Fw@=>YfQw zdH=>;(+U2NS^d#3r>}X>ksg5!rb8mB=bI;_o!aXU@e|v~kjbMy_n&XrXpI(tM5dG@ zJi*`R7>m=I)L2JYo(d`eqq=tA32?Qgf7*)N2+Ayig@<&7Pia#+*ll3R5+2*d#)1L; z5UA9ib%^@G*R9wZXT&Qe_8+v#yxY7RI*ZWrdnK2uEm-~uvBpucO*XDm|9}S*9hle zQzk4^vnSdU7aqZK9+@xbnToq9;=V3beDccp+WXNf(8Bgh9piMY{zrMm;!Db>gJTDz zE(3!zBTyM*aTYm~Lpa&6h4<>p*YbiepG8&Umr~P*rRw`b5gx}ct^qr$CD*UbvFC>G zZd>^bn@{wd3Uz}wk~O}I{HfF_Y5xZj6DtTZ1fOQHQ>n|T(kgx&8a|@$$q^!n*LI+L zawlI69LL?}m-_s1T1hV-jy^2bI#pvWu0L!^W+KWeAa~xJw0o277w9E%lKYHqp{#27 zXoCmk7+eWc-%$+D#%qo>3iF#=f5LzbjM1J3ynsO8m~x$#kl8uIc-qFW5bJ zE3OF|!u3r=Tm{P(^HzIr*)v)FBjAUD+CtVKk3K6m=bDnwia!uN9Erm(iGVAt_1yAu zkuH1N7A9@?mdITdJ|zePDt0x?HcNnc*EuFj=Az$~@7@;fvkW`k=>!skw0aZ0{NfuB zy**IaGqURPC%C7^w{PUu>BOELVR9fBMLJ-#l6>_s1gVs^A!(FK)>%+@TIIy4g^Dlx z4(rU1UtB}Cxd;Ycq|clMU23If<_o?a;QndHB$f;Vh0r!k>@`8=aobA97Gw{JIewp} z@+}grR5;*x|D3w%wxyMjYHzbuSg^hEA4BA*mwPn)Y;+FJbXpw|#zZ6Qw^l#HG$1Or zcUK_GYm{#|O>iCsOhO|&^y_7hWX3%PUFU0V*URRrL?!X6b8Pat;8vC3qG-wXj_g`4 zgF4~DSucKcGeJSW8iPK4nW(RV?p?gN<8AgFd=Z^<&gjXBb&+q43w-or_l+8;p~izj zV^&6(4Jo2nL^FZhN8t~2m&hcpdCl!O~B4#kK+rUrv`5w*!HvX9&X^I^sPpNEKs zU6n{HZ8!HhStA5Q7fCanL;?s?mUX=S%U%1m5#rM+^7MKyIA63^zbZ2R&Z9y>wtnha zd4DFuHtwJbBo~vVOgu3aV~jsM`s!9mxcD=LKd-;=T06mB?+tBzkYpU|5$t?bY+)Vb zqS;Q5`)tvsAvq3zF8E~r{xiV8F?{Uf3A?N^5W9RdK-54f$@OLX!|StOIes@r{Z!cT zw2%WPUpK0a1R4Y`+zsydqE?y3#NB7We>Ox7`B`cmA*Kb0McQgZX}SUJjDV%wQh7TG{J|e)@-p;W>()AJ;O;oMc_^Xu_xv-+dVe= z&0*uBBQ?I#D*?oK1TBhvwvlWqDsjI_6r_hPU2xHLPMU5AeoN$sc$FDYA zpbJfMo!S^e2B2IH*tI)@#Ae-lQCyW)$*w+g>vJV@rXA3_zr!rWviQUu6Q|gKI+x;?oHsO z1I7eJc7qbyJ(DxbF6x%lxT{oxW7YiI^JSY%OsyYThXj87dl$@RGw*!<@b=#ffb(m$ z>N9M@<$-FV3(EOn9xJ!F zhqE43S@yb|zAP~O>-yzy2yESli9iVE4*ENPCAw^jwEvo;(Qs@Ewx~gj#i}BMgs$~{ zaA$DRkN$F+iS@&Zj~BJq@R`P$#w_PECbhxTXJ$^Bi#4rGN03@dm6-B+A;-Rq&nV9H z$xrYXWan8OdF2|Rkncwz^TS9N9`_E~gRoJOQ%_^-*$EoE>?R5fIZ8huf+3gL(u~*|XiL*iJm)8!;bZ=U{v9-d;M{$@Uuawmsg;%e4uWZ9c$?#pHyRCx!m1L%*ISi z$z;-K_T|zO(t7m5B3HxX+x}q+FFjL3zc9)_N1a>Yws+V(R)5{xyrpE_UT5+ulkMe= zN@O-}7ip1(kg3xXvO*p2X#9O-RvAo7C$5 z<#9Ll6}Z4p=+@xT%lRaO{!LD!B~w$pzFq}(qN}ZZ##aVHauN>YqbG-z{8>Y@Z}F$* z0uAC`l{PsXK(+~*%Bf^3y6G6&?X`kazmYXru?!{Du0Oj>d=*+T$?Pi<@S^p^+dmZ% z-@UewXXdUREq9cCghb^?E zD`j**4&HtS73t9~r0uC1{A99~Lr>ovoLKrJl?8Q`d;Lvbq8D;tDL14M{Yv?y6MUKK zB{~?;3(j&C89K|-m}HYPK7dh4r;Ocp7tti?l={(nq2U{puzT2Sh;1)qRM^aK+p1XD z4N2%G*baEnB6Ag8MI=rMa6~ zaqo0zeRgM2J8Zoet9shLUKYixm9w6ON6hudOz)}-MHMFbny-{Qbev`0R(ngAW0;Ln zd>JX0lk=jylWvfg4;4qMsNc$1$mn+!W||F$ydI&h_6-&AKBL8vI4QJczh;(9uGM&C zIOH)i4%4&(s=Jj|2;Sa`RuAl_g+D~nHZ*|cmbgCgaonIB=L?GJmu$S2XY2){SpK>Q zs4-{z+*&^$<4?PYgC8G-L3*~v&7f0#3JpQ+5rtQCZ4UwzO>Qx2QGT%JY2a=~DDgQ~Tf{xZ8RE&! z0?2qTm6_CYk-1|xuN!e31o~vqx&dEG%0`90<-XOnO6`U!T|w`=#CJGu>dKwY-hm2> zlY(?L`>#f7b@k)8IIGnc4A{>J#KF~}Cg0-E1kl0~JQi}>!d^#)2fu7*b z=rR-4Ubm{ndE|s-uRV`54RDGaIG8uU6>S&X@)BOp-GU(HpMi?q z0x@Hc2-KA>zm>R*D$amk_nDrs{X@}UwoI;4Ijna-)h|53v^9ARP@eM%n8FnT1aAR> z4f`Cx!-F7t)fQsLJQcciWY@govG64&G8asn9F4Co@<2v-0G<8gENTI}&yPm2)%|K6gt3hh01ijDa#B!Xh zGKzitq@5n0?fGor&7w{Aa_1dpMmo0DWj&w$41p?tb?OA${b{ov{a&DVK`Tq~;VP=9 zk=rEdCvga+0~Si5bM!B&;iL%f%S6V28{^AO-qq~RcKNea*xHoZ1T$%`xZTLb zMci~!p~k^bj*Urvz&zR;Jxv~es?x*sJBx`?{lP4BgpN3zUNWD!B`Ac0m83~nP3`L* zyY)&ttM|3mVtg9Gi|FY-5dCg3k37H6G&1rE@=X22%+L7gr7+On9{i=yaoUcHY}%UT_1RZ9i2*n}3jBV-ASkAlz|o)P80P7T^qL$Wx9sj-3$<~W z-YO;{+RorCpFr1e@ zOTMV#RCvzh#0NWqyLi@TvmzuV?oC@1#d^id0{y&Kvm$YK!M-?=0ye6IBl{$`UFH+MSKy;pVqW$o=%bc# z3i<7%s`bcmoNYD;_8bV9t@J4yGHe)MC{W@SGw>i8-3D0)!{*_k{3&TVxSwEQai1JZ z>_l`b^?u3fRDQT73H{DC`%a2$_kpsfi(IA67}Bueh;Y0G3&9}aU%OR}zYmK7Ka0bM ze8Ni@Hqfk4m;r@QDITX;zH4uz{}{PyZ`=zRtX#H7`^oQW$O6X{XkH66P49**XFQoY zi%zXyz)m$mGe7T(U@g8s$E3FkX)>g*gH_RV`-U9TDlgbfi=i~Jy9Scm?G{+7z^Y5m zyNs?3*KqyuQD$}ED20;HwW1GHesO&l%8+9@Mq46lq&-aw`s6GK=c4Ak`<_W@nDesO z4+`mR>Q@(t)3*rh2di0I`8cpFE>I>HZ~y;(f;$0I?*sUgG-(SD?IviWZ-!m_n)QUj z4VY)8(OdU%*3pGEXX%ggdxh(Wx=6O<(Ky%gVme90d;wz`tk~0Y&Z?V8=_6iycJrL~ zf|-2z6-!mlk7DZA$+T32mamjwv%RD2PSCc{Sq2he_6OI~Md9hPNF-PWn+uApIosF?U%tNq1iexLKm;Qh%WIY`%D%Vc! zkyl?zK}r}@dhZ9-sI_n!ciir82;Y)loL$*mr;N&%(O2gT_%Bp09TDE!tjRN(%2xsC!KV`V>0N4s>=-wm)onACNX zt>SoHX2pKN|7P1pjBtg5rM7yC;q?IAvOv$7pgvBA401B=J6L*te|5W@`jR7~oq=bP z9cyvogvXZtJuSd)Zu2i@Fa1bW(3Q(}`v}YmY@ zbetIN+ZUmLnu7c7)5UfsY(MY9LaDc|N8uZGUrD*#HQDEL^SRURJ%QYzntNW~UE>)N zvm+U*cA|eT)S()rAm})8aAIfXz{PtGTX#MeRb%j|%-8M~@C@=}c{!UnE$~*Ewcxt+ zvyi^c6Ghd8P#U^l@?VR|#PERLsgm}S4tAr{%6RRe_@3YThUZznlE5=ga$Ph$4UcS(esPZo&L&~IyR#Ce!#53{N;2Q@itvAVc zlSxX3R-{W;T1nzoa>Y|3iH%Ld zHYMkH6BS2yO`qSf?8ShU_D9~xrEhawlWOKWwYzddvScJY6JC-krn7lYMo z+_4F~A8}#~C}v`MKtrJ2LD0b|i!!mCkcW^z=@mw8>z>)>Ev=nEMSMl%Z_UG%N|<@s zYDfI$;|&Q0D{nXSH}zk+5-5EB^yK9-+C83)$wogD)3VjM5+J!((kD)i^?nKxx;5#^ zdb7>j-&`cjfu$iZ7%(p9ud>OZA=na{bco`|`RUjQM4gg!gQ1Zn@g6Ti-rJ94LoBQU zc`-CDxsJ*!6>4($Q9s>?rhVzYHP}WLH4!|krynd--u3aS*t4Cr*Atmr%}NO^k4H`a z*?Pzg?dR{NIz7vf%JcNET$VO{@x3)+UQqLZCZE(qU~tMF%fcP2C*1eVm$)NzZ@{2* zok^@}K59}#e?amTQuLT(`VR)-#EEu#PGQSb+(fLP2BH!+ug#KkgrQBMay5|;?}Nik zP5Mh&rJEaxx0|=yyRqBSXx9y__`jVijpZuUXT*3CrY^Ev;EP6(4bZ`6a29`q6;_uv zb1;WDXjozZqEKrU0cNd7Bdqd4cX&sdU!k!}1# zC)Kt634`UAP}2(quJqzv{O(ora>d~0?+hh@%V5(_8u+DNSB^yrm^FxFn%DyMiW45D*oMAYBO>s} z`dLmx4Dq3BH!VtNL+RPTkB>#q>ewR*(7I7daHf*nk=q9&W__mio`Xz~Nbly+EovSi z=v{>dPl1&#TZH=ljYuHV9BY(K*&kz^csa`-I5GF)paF0$|N0Gm9*GewX z=HpM|_v0lr!pxJu%%B&uEs%2DA_nv-7Wk3@aI(tLD2MqF#rf{YO_hKtt%QTIl5*|3 z*6`ZO20(^hxP2R>p>oGw*aeaAQ0e&?aB zTA$b#i_jlMJ5rlE5OxoD4BlxCJiYOAyKDTsE4Yp*{b$=J983SSsX`YoZ$M>FFKR{O z8)0Vuq}jux+6`PZ87Iewxclk2Z2);ByP{MO*!z|RYJspV>mA#nN#YIiV$ayPKg~x1 z&2{UMw%3>(35&@t=n9T*dalCS$7|L-st>pbu-C^0}Otvca(7mE+5wsHEj`WUz*)V)&<#j->dA zJi1+Odq06)3k5u2qD^0ol$%Vt*^3R7b5m<5j*fpG8+n1vAR|v(#k&PK#=-VHG^m8{ znj+j$_-5*%gm+W;A1vMp-|_$JTohM>7v}kZ!hYQL1H6;9Im>$W5p+0o<9%{auOp5c=2bu}?%=R{ggnoQtsQjN+d z0u@ZX8?%pD#Ezhf15^{c_+5Z|n;{+)I#@4q{>Klf=Ig8}gw|4gGy} z2M+%h!y7cTVEav zX^Hgh>O4hjV(IV}Q2*rW-8Z$RuPPXl!w*0DdguKs3ojWTO`oCn+5YmVifrG64-q?n^cy^}pMVE&4B2BCiV7toRM4%YrSeYk$dfKMBO666T=_0%D~yq}lOQq1JcPk9KT7 z9M*&3=O#22j>&M9bwbmQF)dR|_wY0FSS|cMFgx2~+hMDH`>;KWImJk#Ni*>L*gG7) z3X(!g(lr+?Cs`1kA_f0h8Iz*zsJf5#vLro#^LEt!WTC_g=^>=4ujD$=>pAX>k|9^n z--%d$zb6llau6xzJX)ks;}%1nWmGA+aq(J(A$Pebq+;PHbf(27>~%^iYL!!n*XorgF6x2lZzZi|g6P=~ zHAnuKlHE2d9&=ig|JHlq01TD?U?~-Y`jV+WY!&KZ1RxM~_Z`BVFOK{HhG4H+Dc@o}IY% zDx;^S+&q-UHMZBAp={IS>N3#oMWo2h$@^EzX<8R>xYvwC^TG(V`}J-ho_)=wz#HoR z8}DJ2C90hd8#m9>W8LhqhmsIa{o}(!-X-AgqI?({U52RC6zt)5UI>smJLA1%@ItjE zhksR7T1=|{WEb+T_*4OA0^CJ&BW6fc(c;n#^#_Xd!vL)}&n_*u*LjIOkP;`nK9S@>?K zTU5}%6ccVkRIeK|XUY0zHw{41qj7GH-H-`ovYIVlHr3aJIMtL(?-H9^5H1K_t9C$~ z((%9AP*Q&ywyoooSDTuUlak5>y4&Ye`$p;c(6*h=RZ`&F8OE+3#m(xY^V`EXP0mRC zhI`xGOrdeJQ$rO)9SzwyZQQ4K z84c1DZfku)e-(B`A$;oe5DCz@*mKu~WN{U`HlfS74BMmIZcK{;L4Iv3GUF$OGj1|< zBqzxqG~brI_nZ#f2`^TgO-)fl8u@LV`+FA!)IveAV2~bD4*vzd9@BqP4-Oq+FEUi2 zoBZC&PVJ7?u94(BC)czRJsi;XEa|BP|z6gAQzcMtMu`NQPahbg_Qb-&v5XQNQkzmfTg`@N51 z@cM3i`P&O1I+*j)=8O1EK_U^JSn#LU-sQCTebrZ1w|S)L@7vHqYrs%NQ=eTgyQ|m)zw3rsSL_|z+bOc%z9Th4pa3wvNkVZ{Z(=-7P;&0dh)=>k`5*5#1=<*MQ8P#zg zcw=pORjU?;x{gj1>RdYXx$x67<*D>?#&pNavIm`H_;QxFS8)@~iu8^JySuwBwxT4& z$Tw4GI}QH(iF24MiG6S_$fsw0FlrPgtl&TaO?;acTec(nj^pC9V34qQK&6 zqe;o1BJl?ydZk5C5LCsPB_*eO~OYdOyLZet@|#0 z+_I$i5Fq#8Lz(>#{q2+!rMnWoO0O<<&OEp%e)1gv&7m!G*2T!jEePDfIkR;NVoR}1 z6$!dm-7y*F7Z@PG&!cF`{|39B-cUifZ+^1^`~r;AgCS5~BRykmlV7K>S_S|qedwdy zXs6vMosw7j-Mq&}v3PPv_8ot<4>1)S*tLeL!ZGW9d;T7ckq>~9Roaa_59NzW0UZ;Z z9cbD^pKfnjXPgqQSetWkg*M%+cu@+h7H~c@I3auW_PqbSU7XWK!O)r4|H;R1u>21{ z4N07!P1-`o@ouKerMY4|^rKlvn*PjCrWVS_+9PHufvNF<@%?yd{F!Sys=T(`(~lI& zWgF{mKe&1EUd3Y0>jxGzp$b>TnYaswCvP76gx~FwX{bCjGUxPU`3^eXfBq)}i=>(4 z^nB{sUqenz=HMg+d#K~dXRNJbJ6A@v%s%A)BH)l2(dx%&Yy9p~xsZ`a_@iqNQpVsV zm&tp2s;W19N?I+5K>prdFS(Kwnp$#_cl*#3VX#By?_E<8*jZOlM_Jix=CyAW2Z7_C zuYJ_2%ZWc@BY5zQQQR1(8S-KRW2fNs`y`Mt$RcY+?dQ|vo!wM&rSvC{-Kbqg>j|&r zFT97unn4IP3ZAYDDXQ=z^_NXC`@eAlZOWm3cS~TJ?W_W==$c{EAVqpIoR~dPT(aln zzHuN1EKF4Ppz{&0D((N0+5m->&$Z!YNeR$iB95uu$yD~iyW(rDZ|?d`e|QS+3R=sX z=CsPr_|HL{{=X*#r*PdTYqx#lBxNSWVDZ*TAI0-~s{gc#^J1m+qlHH(( z`hh6>62}i1!jZPzvf!X&GJ{HHO$vOAz&~{f+C>MpmiI=?{YUgPK6n&+KBja0f9Y4CxnjQg}Dc1jnnAQCM1z&Tt zZE$fx$JJZjPCCA9JIQf=rLS-8u9$u;vYcoEHj|W5(Z>m^8jYesu2z`qK?QW!n`slp zPN;Hs(rERig4+1}U&^pODu4TK03!MWU|eqkwlTCY#z@NvEZV#QjQ%WfYNsVPft=Xf z;dlPKWoI||T4mq`6Brw?Zq-x zoh79GZwrzRkvASkhlO@=qIzdOM$Rl6_b(D#>p;s2W>0169kHA#cEgH|!y<2(bw{sy zVy0FDuwaM7x4kA>R+fEJ5ikvZ8=zR%icL@b(E)Fc)&*$DF;raj5<2lXf2N+YAXat<7G`~)e-xjSKD9g><*A7 zUIS)?nf<fj9w(cKTURdCA z5u`IY?3A%+{0G2Jx2NTGa1xy9?eVst=JL_98<4(c^4<7Yd=82qEUy(jqpmuhBZtag z^)U*@J@vU}QYyd*Y3t1J^^NFnUI5CKWO*`W8(+z3Cx36`K>uB>lGOi70^+(hR;)4A z;Fpl#B9~aki1Rxf5m6shHmyy)mz=<7VkM%B^oSxl6nn-ZdSR zW|AA=Xg!Xq-YDI8tMqOPWxF(f_gpAOR?NnEz!)8lQ7(Y>XOAAIHZOL(s_niw;#l^e zzqj{*HpjJ0^OsU)qsybv=?_Y0{@1aWuV>TqOiD%)vd{li7f5`XIeL;M145>Umh#FkS9u_Pqxv`i3ag_n%%S2m0ZQX;EZmKoJ zolaAEVMB80(DnDyX;4Ki@^HLW#gxVgPVnOH9NMpj##{ZhweR!68r;shz5V0g?HkcM zUXm&=Kt>s{_*QakialOsePigLt+Tg|d;!65M#z%vRpZfiT=)D{9Uvktr?2csnSMxn z&(u*T)jY&q7i+Iv@Oi%v-I9i>`2ueYBH^%=S`k}!46LThK+`W$CuwOlK-zCHwBi6Z zrA$ReBO;Q&OP@#ZhJgf&MVSNS;Jx@UL>tQ!M_5})*&(N$VO;pi;6xX zeav6{^?7&S{g;Z1EMMQfE(qc*{e@`$72E9{=nHvIzWeGX(~ozo-(AcUtcBgye3{&m zptCCLeM+zMo_BO<76ax0TP^(a~Tlvj3w^Z~vzUKVr)q^HknOo4%B zlaZA_sd=dY_Ip%c9cO2~J)LHzNiMiwK}Tpff%UBX(}dN_#7&LiKNe?T8+vyBl{a!W z=!Q1%f7;E7(qSmF8H$|NL@+5X{!J=RD24uzT{ltbKARO(((wYKU z{{l@drC=I2x#582EumFW8+IZ=|Dda}IPad6bAEMEw}yd~zqfa0Jl~BTNfC|Z`Cgj- z)A^HD?e`XndiOKeLp~|_wT+ix7M&T@M@T2)}Q*o7` z=}6e-VE+NFfsPx^z>&j3NDIv$AJ8qhNXw7o`*B$Hi|4ZfUkHI(eF9x)vyG}MB>(n0rAf3XQ=Ik;-Um^7wMTzOd z>2m4?U=cCJq+N!9|M_BZq40!eG2^0&er%)eud%7)&l!VX;Uf{=AK=ymQ>>Wu}3Zod1Is@M&1AN@Z%f9dVg zv6(zU&1vJSDU2#1T?so_<7!+D5RgYhO1I{d{VY{;4o@=aMtJiH$QzhgDqF}c^8DS0 zQpNIw;Kl^Hkx+NWO1o$OICHFZxhoE*)8i`HQ0cFkIS~@R+4Ix$!4vQ}%+Hh4c4e$Q zl5i67=xgEm(BI)ak*muK!nf88{G4o2^+oTUD8CR6>S`#L#T`@eMl!e-Uc{B+@4`iQQN`IIhQQm&5`7#lr9u(eiBus^t)w;8Z^Ml@4}K0b`~cT|2>?a8odDY=?;WY>R{W5kLGU?gwhF+wZ`Ma4uk7V0Wrbv!k`9)zNGdEb~jD zcife=Yvl&c5a+CgrD%VGRSd;4x;|EY|%Z`fI|qZ684Vsd1Le;!v*oL48xO$%g%88PQW$*=i>;85`&y7XaG8 z51xbp&hQ>tn$=lrKJd1L8?fg(Y(rayFP%4(-|mTZ8~HWHYa3x}sBI+%D1WZM_GUF1 z=?z&-#vy&El~kHCFtp5h@ki3=%VNK;)-d0D!DapX%C%BxHp zv@`HHQ|QjlhiU@Bd=~9D`}Q+6)8VUN*8EcO^pfUBHJ_u_Fk92WAh4d#+^QXAUyCBv zT&h!h!`&gjedEI(1-pBpq6v`?Ylz}HcY>~o_J}1X-sm9gU-wF&ESmj~biizvH}2qR z8Dyr@`%D~ngl{0FAG&-cZBh{#w1c5u=68P!;Mrcr@Ia>5x8u`3&S6>LmpxbXFQkGTUHIaNVy0oet!_JaMA)2;i% zEG;2!O~n?EY$^7awq0ETgAB2aYNNX(1a`Fu?lCLDdT^WmBpPtQ;qpM#@&7CCyZ_l- z|G4#Zs8;FWw5nE@YVA_Hq`S5jp~S4Bs7;huEvmz4si>_bM(i2Hc3Q32#EKXtc48$` zBRqF1dis5yKj6tPUNY|cy07bVeXh@Zza{Lce74zJg918FUms_^Ue&F_l+F4$o0<~m zy{HoN9Ne*Avbw{;FDx%No_oXC6fnQ)jGs9*h!T^~)pMbJBUQ$_Nn#!6^OVaMmqc={qdM_X^#(hM`X58nXO)uv z6|1tJ-GP(c+XC!ViW(J=<@b9!>~g*%iWRTDvVIo7*_t?1ZKp^5;iTD~wK8Gr@lfTk z_6X~l)3Y)}pT%hYS1aZti;g8~(sD0R+lmWjuW}>jg>CJ>j*eIdNVb=6GR;I%y8#?FjAd35da7!}%%@rS+bT#}l+`cy_K6S?*Pev;)7; zA%hV1 zl+2teMEGl@r@#2Dw^Cx1_7efm=S&@X#5 zZ~|~<$CL4tDmQnI^wy8C$LDLR5HYVxE8dNCavUk}52&)1EHkT!Rv=7HwTdC$bey2o zukXNHc~cHFx~EW5yq0<1B8z^Yuuq)I*(&THu2&6usGJ4b`knzU-V2nR63SJs?(SPR ze`uQ2y(wAo(8f+Pb3RsM5-X@NlG{`*%b>%&;4{%1^EmQqrK!(Oivx@C*KaD)(u+HZ zs72Kf6htOZw{K&ypDh(ko=nmAp2v+$AN;i#Pfq-X5sWZ^c5F0Q8))_Guf`vF%q{6Q z{?;Es>64%a&9(C0D~K#96nNT^ESDpIf;+HBA|83K!!SPU3(bgw-}GVZZq9YRpL|=G zjF8QQ<;O#nXcYgXZV?}v~xSP-rfFDj&Vf%I5F#Tu$r&*%t z0sape33(}H4#q*ju!n{zDF!{Zn`d3u+xi*=d!kfIef;`l$wVTWwmm%G?~$KBQtd5$ zIBV4lWr#%S3pKx+BPYS2z1{2n0Zwsi$#Z^8754ctmIg` z2mrm$jQ>)QBv2aPHSQTZra6SwH#2@fL0#OU+W6@~FP8Me!d{FDBZ{=FZ?R|vFW|5^t1ROOaP0z$%d+x>t|2yUSy!ob+pd2n!_lhk}dJPYk)G&ilh@P}nn!UjmPyqH5^9#mi z#WujCQpCX~yPz_Git^GNb(&oi6XUcmNbCx-k(F(+QOgl<%~pKKfb+K@QgRn}KSGp?E)j9bG$9Z+m0H==#~R%>scXept6C%ktVj zTCG@l^2c{aoNV2UB^)%xvH=8onerc~=+fdYORtbZo>Nz0=ekTGhDiOj9kIONUk_7X zB-a;%w^XCPeTf%~{g!zl@4ClFbg96UI`)%)qVJ7RshG@+7w~gQKGydXN{&_u5gQF@ zediFdB_T_)9?nk0tnhhR<3>lj*TpMMC-9`l9~+)l_^F=M(!-i13{jd$_YIHR0z~fE zr{L-E>|;O_JkxVCYJ*cJp^`W}YgE%F<1Fz0j8@;RDK)0i+>L_FqLTtp4IO7Ar<|>Q ztoNIo{}$X2K9u4-GA;XSyid6P@GD492KdO|+7np(3kZ?Q} zDeODtuwjd=t7&cx7s9D8?ngwqO>c z<&n!%AL7@SO5=T~`cs7iD?y*`xI36TX27#sstt9=bDPGoVU{Rv(c&wW*>7TZ3<#qz zr{iv1bs~F3~U4j@?LG#oIr84HB`#4@>|7XhoG9K48Bk zOTN$PV2I?nO;%KYQe6MpFzcL!=Ds9aMXhutVep)%#B?Al+!rLy(ib_KH7|JG9GS8gWs7_A{mz zz>A;4?*xhMdo~X0(2*OnNh=cYDEQ*+<@eb_QKd7#U7s^{-%JX+a8e*eLu6w|Yf<`_ zC^1?5S*rxuS;fOGuI_B>WUX{K-w*ExC>XTIl+*K9!h^FEMcat%7qgk=d&g(1*luQy zD&=L2%HfM5Jslt213(dU3GH#(__YfWtmT(F#A=+HUc4cz@GBjgWzGi-P7h1e)3lYC zx`6y@RYX>en# zHo3T}8uMIq5p^w@Rr|Ey>ip4~vc!FzNodPM;W6LYE*||g_6TJkXhJexN^ME(!gV`M z?d%OJ9b`8(fFpQBN(~nFqrVQg@RmB3|7Q-e?wKxF`yYKPThQ$oAj&*YQ{^=E^C`Q% zQs?*zHP-WEjlb4B?e=oWXMvXiHpbcZ0S(#c1Zs+xZGY>sj7Ua}YRjAXQY3&|jvRKg zm5d4S3>7x>P7tQ8tijhC$T_3sPp2D0JM_vx*HRNXGs$N>+9N?K=+7RV)AKbe+pUSsN8o;A(FqG<~v zbc}9d(igOB)FOq!JKp`qwe$fX?u?uFEZ*>=FQ zQlM*UC;UFL%4ha_dxI-s8Tc0MMN6+v=!H+#ng&2c&Jr$f9%xpR0(qkUVTzN<*`5xf zh3)Ru<^L%FG8|M!r{4PD6rZ2{BS{Vli5oUyxjcRM=~7Ve_XEf(P`a0ey1C{ zHS;PZk5lv?&s$WyQ^{pBZpd|#P1E1wnxsjkA z06_ZJ3B$zeWyK8@O0s^{9*ZjiIzwNI>3`VG)>^E;{ZmC9=V=_-$`>ml83Fw z0i@+Kbv(9B2kHr|mejt8osFZghSbP#>_{UimGCWa^GP#BDRyo(x8THeX!j4bfV&^m zZFWl|U(FeWI`H^1|h%>n1 zRdr3}@M|u}tsgeo3!yD)HRUzaxhC#GY++u&Nr7D6!r0spv2ACK;x?K#lbQd1w)((Y zS>P=!dRbuVdhF8FCY>H2xs9N*d!43{4R4~mcz)>~b-qc@3gD2+d)q;C+-O#DNuTYoTa-Tb zOZMwe@8UOqd5JG4G*7{6`GjWLc(YHk8K?fU1~hAvfSPO&IcvzT0OVo~*cTs=adYjLSDbb|}YsW0R>#tsqXkfwii7~|PX z&0#>LB}I_$5~e;<(Squ40G9z$;7OYk`OW|#!B*@J@6I}<9J%@xE-$L5zX({_9Y^1UXBuL&c`Uao+A27^^dc%5hF3#l@Snq3#SGPpS|M z7{j=T@X$<@4N~`itKZy$#u~KlF3fSE_{h7IU(`H&dV`L*R~1KzK?+BBQe_Q>nk?ny zauUCL_&rAKc*^_c54)7GA*=x?L9b2HJqT=Rd~Df1z)w?#`eu9nO{uM`gZ~qVIiI$w z2pC&7%X*{CYix#+Xns}N=NaoQ+tg@=0|M0V&+zxSnNE(P;r`-+@bClrDQwntlA93(G2%8)sWpc*(w^Szo* zylePE;~)xMH&Nk!6zR5_^y>hu-@pqzz~UAk0C>`Ts*+{^692|@x(<$h=>_aXR)&6W<;w|`^e;HiEFGC+8;lAs+EFs-0i zE$%yWjehnSxw>~4w6`V-`~H;Ps6{Mp4{WZlEe$16%wi9WywBcfwWF6s+9xK4ndYlo zuO1$><~t)b5W$mR6QN77<^-w5YmU@ zo?pa0Tg*NX?>g@2E>{qcQCZ?J<+&j@m8FvE_v^K~JCU74-F`Z8}Zy+;|^7#h1?1~msQn;tJ*TZfaM-%Cb zHK@X=)L>S9o`dBoF*Vq-Au#%rFfqT{^Bw$h)fNyqq)qmewr;?NH~8mIt{0t<48VW}VCj7b1{^niorT~OHKiFF zeaTl=FY5>K!z-v8PnIgb0)Dl~EW0qy;NL-BGenuGgm?besqMPmRb%26^??eJ7o74F zgo$on0L$GVN+b-g(6e#j>cHdEn>DrlV0VY+fDtF`ctjeVi;d8sXh`%U>=+|cVL$SU ztMfN*!Y<`O;=Y}US3Zo)iIonD6}JSp#EcA<&Wb?RvzCMyK6{ z;N1i7xMl67YfYVkKAka17!-IXsg63ooM9#(-BTr{l(nL5#3vpz7Npw-2H5Ggt4YP? zMaj^l#>w=+1NGrpa**uMwBDzaQtjm|`EO@|&YO*;CR-x`+D7^5hBNU-n{Re4Z>E{i z|5VDO0lpqNV+DVJ1nlfZvS(X;l>1wNTuOEffN4;iX?w`0a=6?6wpmJbyQE$AXVe|` zhAM~_$u;@*p|8ETGh}~CH#=lRi01RM;&RZM#C$lsL71@vn)-G-3}3d8f(w=My`cBM zp#SC^?wi}#<}ju&!WaDg>#BBcO;_g2p4z0_GQa-d7zk27cB9&@ zJG8Iy@=xrK@T3o)O6E6kXLRp~=Yc&2YT`)iFgsXx&c=(;97x81KWX=Q>d*ey^hX!9 z0b-4}|I8ffpCVdr67lC!FPr4$8Z>O`C-J5a_hGmDNWEph{Dh0G0I`(O<6}t)W$|_R z^EDj_;2s_&YeczUUAnQ~z~p4$wOCD8q1`+qfbb=tjOO%#9_6cQZ{G|$u6{T%Cp&{D z;80VN=~5FZm|!>SQseUs+n^gK`YDfG&E_z5)E}sGFO)upV>S`4?s)jn{pCOzmOLtsnODiU*Wi&!6bWs|r?+K(7S(e6=H;piK`xbtHV&k$)B$UG7$; zsD~B0#P-53T*{jJ6(?iT#=@)zl04vN70sQzj-U}pw5waO1K6u)EiT#os{6*6a-U_? zb@Q7LRA(*!%4t65gvV$1tIsuyWWY>sjJmPVnyLl*EvdS13URQ6$y#PC2)8B}o87~* z+j+q>cIG!eJX+71y7d{U>_zXoOoC|}PHbul+~H84?}X;iDC$2Y3VLvuwnS3#T06W! zfuQhX1CE*K*jYMCLkz zTxp7W289eA(sc3C`8H=IMRv>*Wnv5Vya9v_cANqFC~l%{S5d+LI7 zAWajwdP!EezXjy={NZtQR)=>-+zkWKw!ao5Mt_gGt1XZrV zM?pjQLF{TYS;}SN(tPisf8$zbFN<;C*A1<|EEm2T`KZJqYc2S5j?zXDGel)osY@5d zGI#LO3da_FfDffdl=AcST?vpY?K%qh^>X;dw9P7y`ko^E(h2 z5sa6;?|C%e-oU~CXH~Hci7(BV=%14I6&LC`1{xhXk`83@3%nd~t+Tm`dSL7<&>ux) zsV#kEQ)-_J6?mqL?4oRAEj~Z$8Qr8mud}OBn!uJrMNj42^)fSBJdM2<*0506mINaz)ThQ6$?Y5+V)^z6O4J)F$b*9ig=~ z4niC*1L{7+4O(d3kUv%dqCNLt^W9;Pt%Ut!U=9b!4% z9^XX=r`yGTf?HYA=OD)0CyuUL9b z1_ukC81+e#`#S$GLpD19rzF$g?hd#d2YElx;z;<)oLkkVCSKY0{Q)*x7;UrybCBzw zfH^Sp_I$lyjqvQ`$lw^|xO)>Q9h&AGc`I%yzdOjlWf}M$|12Nt{mP1r9ljH#3$Kha zPDhwciHj$2PatIV^spwHIUJi+Knri!v$m>iHghdQJG?6d1~hmYTW8jky(!%PuAUrB-bd8aNo|5=i?8zZp ziEL=SwN9w*w9*=gedCqTwPgLzm|c&UslEe5-1!YEjfPmG_`-?`ZGq0jcMu5-N`i;E zoVh&OnY|QYj`An61gX8TsQ=am#Q1?~JGzO3%{S8Gzp96X&&rC~*iz0ulg7R=f-+w7K*S3-a5< z3x)$RcIto19#Dnohby;$%n`t8W#ywO$76N6P%*>UN5KX?;7`Eh*k~&O5MQL=eS(mR z{GDe<`3`L^6sqX@<)=8vnHDnilSOrB30k9rWO2Nu?3lDwN_2u=`(wArS=akXNaUQR zCZP&Ne2kWtcDK2U*4$T$BBDd4TV#Oqb#wCqcDh(Jzm6dzF1&YsBkrTY(0=>ZXLDII z1}-n~F;haS*xnB*S5aYZUsCGIoovE{Op}zs z*dXv-8I;#nprW~?yRl5U=6$mTekdB?Brk%l*l1S+f$kt;Va7bWi4o)pd&8cE%uZe) z^_AczG^ai!I5--f+gHG5i}C_A&xNz71K-cw5gRbM3>>PT?e!~7~kD^ z`^A7H;0&|da&CYlqvt%z^5Tc0qM5ol_rZx&v6z1Rf^$cEp6ZKzfI5d>zLICaSeXgo z#L$b@83q!+XaemT>Avg&bPeJyzj~3$s~KdGC)T$Ws4#^Xa_q@P8G_{uGzUx<{m&eT z?3po1GBv+y={0k9USzxaY6nAMSzH4`QFl6=yu7jOk7_oJ+sV0Z7c<-PmTh3pau}ke zTTeLvumH5{0datvazg>)!udWb5v6*sRcuTg7-r+xANk14>;*I2(tbR!s^c|9Zn(H4 zs&k|QjuSWdnmfIlt+x`Zaz8V#(Wwg0et?_lYBrzx!_L!R3|wJ5(W#KXoEd`B-2b27 z25`JpR^p9o7VtVwXbq8V;+1IwQ$9(JPF`%TKFzVH+J0)`=!Sz=N0nzMvE2jY-TBag zxL^DeY8Y;Ck#W7X-*%^xmNm6KUjRCNbURFUko{S|>=teUXh`%-y(UoNSIuWu9wIGm zYqOBkf$b^dx)M3wE)mcD{q($zWJ~erb(2Gg4>&1RMlD6)#M@;2Wgn;w`TN?+oBwwulLzbw>tQAV}43VyAHzw?=q& zp5J6xYX1{S$;?`Cf~y19Ey{Mr?063FNne_%Ko-Pr<1+kIKl0Vc&COPc<*9 zDr+X3BkA$^p8faQGY0Nvh-m_q`>m=MgC4i|$a@DAwu<^Oc3R-Xh5r#iVRX&9;(~0D zq@w%LjdHhpJIDC{!SUb*$+xBoQ&*I`n@mU&M4hT4$43{gF5Yc~*6^dZebU)_8G{Rx z@quQ}4Ca~iv%7P_$y&BPcY#>+#%S}MlCIvf?tYhTcm|VkHk+?9=11$wJC$EK@i3L{ zpKZ%)BJtgm;VaR`uq^WIF0o74e=1N5zRtakd6Q%ppqaKY6I#f= zq3%g}`VkomhT)tD;^Onf&!_#DhKo3^-Sqhcz#ZvcagVBup#?&W_-aPxQN zP*Qm@%%;7-q+RmkkBaw!MvVlUNMS{+W2N_8{L#Tj*_DvdbxTyqU}Z{q;#HT6nK20oGVY2FRTmdz!T6Qk@>V7$;-5wzFi|*i zdU=m4I3Z{Dor1Q@xq3%ZC?4`1C>pCoEG}wKy)YZK`!>;+L8H8@W%wja*E>ibl+g(g zrAitLQGk1u11h`&MaFN>fP z(CcS_D1~sO2urNsV<-?4SCd82IREm25P*(7-08dXBO^W1+fWk|c-p_BY6Wl{J34{T z1^ULg80#OQr@2COAxZ$6aN|^Dns!Zv=ME4@?3aCXYk5lBjQw^tYJ933D8yh@=MKiR zF$(#aj%WV1(d?Q?x(bKU2?-Dz(sIw!kNeKWJ}L({Ee9>E-yu9rD1>!TV9ydx3Pq5o z#Sx1ge3>fKDBW!BFI2X@CEDsNQL^rE0_OphOlWWE)n`a;Lr+gnUX~Js54s53`Mk7b zLQC4+|M1AI0FpfAAZP);!#E&b{n@sm<#| zZi)`}huoeDws#_aLlhZO``vI+YRpU@*k-c&HKe&|L_7kAU{dNbbR2i)-Rrtt#`Wbcp zWLrG2U-H9W%{rRF6f%V~*YrzNeoCu^18xidS1ZQzPn`Rm9!dIC%(Lk+pe#^VGfV)3 z&5`TRJ*<|PpO=hh&FN#68e8e;#PnD5$nWDz*3!$_-dzUdqHV$a{%O^%!)O#QZEN>y zOi{m&rG!GX5MUOB4wn7otF0ZA5V%VzD=u7uq{Zcs7CReU=jZ3x}yv zWCvEsz@OSQ=&5g&W9h`0=vSP7gewwSNXZp~hN1ZI@SmNPvJgG&?07JqqfqH!^YCsn z7E|Drf?d{kuSgSVRf6u8Y))IRzL;EM?NEDi^nl92-LVEr{HgeZ@yb2V%jLejKY39X zugvPyMTro1XG|E=HSz*bpVEC5-V=sNf$CGB6sy_o-+_unfxA z3G3{vYi_;wJ^53+RokFO()QK9tsBCKc$^!CuB#(Ue3EN;v&_B9jJ*QP(V8`a_}R5OM2B4-YB zalz^M?}z#iGAbCqze{v8NMA7_0x7X!iF)L#&e)I4!Ss3IXEmG+MAzyYQVw!L1@br< zenI_1mOuOgz>KW#b&~-nEN66D&{<{aFPGyCEfEpTT&_*kSMeI#~nvmmw-{^k!UD)q$tdU`V?x%*R=a&T+@+AtzcI8Ua z2k=Y?>UT_Om;^dyf%R1S>I%?V<4halpzS>9+)Hr)-p+Gm2QYnoT!Zl4$3CSD7?+hD zbgcRv(Ax(`(UCkp(4G=l>gk+gK!V!_vb)(V$muL-#Ak>w8quiqwmJEk%>@zkMDc^J zUzHrd=G#wLkoO;`X)NCj30yA@Zxi#J5UbN0T^}d>f{O*!ti;Y?`$r9Abz}COtD6@? zPmn-|RvSsx(>jW!<=FoGd8DoRvpYaDO7gY*Yujt>`DRX@N70CTDDqq_HIh9}p>}4& zY^7u#n;@h;@0kz>xeow|p62ri&0N}e?NneiK#8vR^|w@`W5$#HtfK-X#PdGF&e`wA z5$+8rKXe+zT6$UKSx)UfJX7Aq47a%#DJIyHY#OPXWOs?#&3`lmJqcxUv)AQMKU|zT zs`wNb8BYRk&bEKMin#o^YU<@^x&9Nt2R1b5$Lfghgs|cAlJM33wKG;4PiQ}*I}S#2 zoAR@vd#Y_L1vDDnjZW6oUHeLIO|0~?{lB)9s3AZjt+*#HLxW=veIC{QY~ewU%U2b9 zds}N6iib84H~F7E^xJI2^zt~Tbfd%|6xx`%KtGCLD^W9dh_aNXGxyFUH#cv-`R%qZ zs&F&g*1UUO=y?^uS;28l0}QP#%jdY|KldmNSA+NSvb6_z_YgN! z+|0d|-5^s!V6=c2UHwz*u{QR|q8kil5eTIN{pP>&Cx&y{w5zZb3C@&_mmc#+SgU<3 zJ@x*`^x*m(KZq{K&WeN5h$)zN8F=~Qv)%wvKB8(CoA_ntpN8z^1fB@pC_B)Ybdl$z#^&F4V2=FK5s{Nv z0;ukR>1GbZ^Q^;1eNPbeN6ws~+-SD=)-3i0&%07f>QrBO)z3HcLpSY=BF%@NCHPl6 zDT z8d5WUnfIiIOj)UDk#ecy(P)>LGX3kLu$@~~K8mE}?w5Go=VIU<4xf8!h1=h(bmoqm z@~@(~Oh4grgZER@3zaYqq*DKzQy8~ObGhF^Xh5;bqsD}7GbtRq)t*e(Ro@AeLwf)?7r25T;>QsZ%`bUWA7z*g8M!%d&>@y2BfM*3o7*nOod~y;JTmTbV`Bw=U2Pl{8F0o zs3~C~o!?K}ac!rV?R9|H;{NPIMjy7cjp3^EQIv2oeBWdhkF%akG-0rhfBXi2o=~#C zisyisqi(wC8`k^Wgo^y+#tUO`=w*&VXUD}EZ(z;g{lk|RR9x+E`YnDI>5b_h`G@u2 zLA5`e7bjtKXrov;JDp#I{#sa=^2`z)UnF|r1rGFbn1N`+n7OVxP@Z$BGJrg-$mIVc zd)hO`Oa5KCUyb!T1W*Ofg#{1S?ljyZyI%;w*VR&hc0r?|G}WWgPrj56Pd^Xk@4=YC zR)d}5&aF;v7mJVk|Bzj%B}9zQzcYLBtTF)J|FmDnxcHmHH?B3ZgAXk)dhQ+owJ9+1 zz!|oe^^7cp$;WGN?#0eu0i*(KZv;<8XzPCAHzN zw29*5>FJK%mrv*m+nFf{H(-SUZva+aN=f$mC$IodT-clYEVm)UZ%6$Hi25{lQg69dZa{OK6fY)HXt@V+y;H*%QG__Q=Kk#%gw*l6%R!EJE(FPB~-F^24V%)~rP( z3l{K`XIFNbY?|m5F-HG+{n-nLzH(T~N%~KE$pC*;E&yl_PBmMn>bvd^91BZ{iJ@3= zLNy2|G7Y{x8tVAYlIkk`JF*UJ(=ee%CyOomkmx-dpkRFcPX%#Hl!yPjgm|L$4f_8qRs1%5$&C^dqCeZckU0G z7Qmcqw?2tIry|!uoSZ!mQYK@UyLGpKtI}T?58@^#J%)Yh_mE#dD71{B-+JY?8B|}0 z1s$0HV3I&hDirs^ zM)mLSb&x*pC9GU}L)<$mSW90>;^3X50`OOm&tI?4yWwlatvW~ z95?RWwN59X_`hHG{E91Wbq}336W@s}UR|KwgP1(0S>bU)mV%e_)z;BJ8Vm>TYNEp062Ey|?tS zm=hHAC@8fS)^*|+_ZDq(#XM`;+(#>XTj9vqPdmVtm}h54u1Zws*KExt*f^oTAWnE< zJ?pxt(X(82Rp5@dt83q-=b}Q=T&0EcP{@ zLQ|g1@0L5eKNUg0MMQ0^Q&6RRV{R5I+mW_yHB7v+>#9kBA!}&jZsn4AF$BLBxwLde ztmjVbmPwn0cmiyFGSYc7JO0u=YT*%NLRQ`i5z>r9=q;J;B565=e4uB% za_c4>R8O!a#4a7HtJDK+`>|ikU1SCb=)8!0UONv2VC>h(A64!Wl=?{2xt@-m-ly}C|pxK1ulRsy_Q)uXfhbL*Kx8Ewk@SfiBl1D2vwyaUYZ(j$A8 zTxrCk5_$kdQcGQl5T@w#Hq3Nec6!lsY;2HI-)$Jbf!=)7L@I5zhu8J*V+D9CT$^3= z;dKq`PJUN|-Md|6?dip|yqFe}aZP?cdRf-*t~WqU&`KG(>KtWW<#xSAV4jK1e5ep2 zd_%nAr?4lnzzHkHA-ah%MBXtlpn*yW8Ytg&xWx2$EzF zu*b>T6y5>1Kn%hl#va^JqMewmKS~=XY_PjBrF}7jp5TJwwyoG{L>3?!>g&oDFbHpc zFVRaUo2hkF6Z~G_RI9i1cf0k6`i5em@m~V?iIR$7V z!$+9W!EXD>HqK1Qi@9I&_iG^-Y_$sT82s8%Pm}%I;cbq7*)hByOl}?wJGp)*{vW89 z@x|B&Em9Ehxn_SdyQc=Sb28FxeS){X;eEsGWF!f76Fh1c3EsQ|xp|ePr%`>E9_kbF zfIQQhSCOWaDjpy3v*ZZ-{W!uyVE2x>d{+~h?eSYa(VtyL(NfllSe{uVh%zJvUUQ^r zJDE*qMXrL3FaNc(W$tzrEetvaoW(rnN|sQh{mnM!0(h&0isX;+SKQYIg*hrC-Icqqqy<=BA6ok0F^fSbZYo7s;sxZohu*3bCJ7Z zPu@h0de-H)ZqLTlvF2B`toX$(_T9V12*fA=Cz~rxX?=qGlxdQ`QA=@p$=5DWGJ&hu zr1nHVCotmrhA7NuLbq+DrjL(Jdn*N@Y(QKjRS4@eI*nO;?-x+$o3uZ+4pZ`dYO7!X zs1W&U<0|-Z)m#457FTXAXr_We37{p%EWUlun-B22r@`}yp;xZ{ve*tOjc(tB2T2M0 zWSY9zU&a^JQvhQy6v8uFKZDYGgtabyJqh?^!`JnqPv9`DZIfft=3MEfEPisfh zXo-Y}Z7Wp8z#vX8i%eQ=tJi!Q1HiSdD0cy_AwB6fTLEmvGarK9?{g09>X~JK%zgZp zcwN-y?K{lX?{BzH)=J#rzqfrj7W9?-_Wn~U>!!Z+!=(8Ka1?ybLp)an&V|5-9Pt{j z$}6!xEY=>KN=(c`r=1v2%xeTF%U#jnOsdTqlP|6SnC} zaX($1^{q06MQB^1w*HDSPwxViBG}`|tT9LqT!QBID>x{F?xAnQ7M4{5X`v_P-bAgc zAOF<5d|MXw+ee@}k~wAzMVpbn@8O&3)(;2tI%>00rfZq`W!;%rqfEB9TIQY0$T*a? zj%LoHsmC46_Y6SG{amEDl${DF*dKat`(z}4v{3|B6!`B{E^vC5RaXHS{^&Xcf=SSq z)%KUlxOYolsBDLA9thacx86_Zk7}?oC1_yRc_=k2%f z{i=d;+D-;(n!Z~tO8*VPpCdBPUA?@%-ZHr@1KOAnNG~8@rSgm~JX(X!w&=GN!u+OV zMNWP+@5(ONw+~1m+Be**5YxbwJjoP3&vRsK%o80Zwb5M88YpP~A&rU#Vh6oL8yS_c zI<<+IW&WB16Enwvbzs(jgL(X;W|!6dj3t)5QeZKj*8&bUjwEEBr38-LKNHCdar>bj zQ8u$Iqz7si24*@<@bd4IcI;csiEg(`J_~|;0YPY!*>v#8lUrkNf2{^qiRs1i)))~Px%Q-#-6YN6tr+9BIY@*7}h1&pLLHPCRJXe#;^?D z{{wxyr|qXX*|zLgP&GD~I<|QcU;w_xxdi z-=Y@C!bb=k-n%WY8CNPsKI|LK3%tR#Vb0&ce(g(ZV*wf6w#MLQ05^(4p@97OX}hBk zty>GyWp6;O)U4WZ*^2E|(z|PLnD9vU&XRxd=P6dlWe37PPkV3vfAmb;HUkF^L5wc9 z@<8%8Dk(ij+cuVaNPb0_3^Ifs#{8BlMMn>a_>SZ%Dx>{c85|td$_nr?K zMwpk91_+ft8=&cE@iPmx znIw}|eibX~%eE)HyjE7Cf|Wta2pcO)-k19-7FMKB+#!l*fJS`+M>Jm2<|fvHkzGA9 zt^8}Iea?0Qe84APk$B9-Ozwy-kAQa^h}#zmTp_^1I^wu^1Nf)sd=I-ZtKK^wLP8<~N9AMU+key34e{_R zGc((@Se3H}8`E)=?dMeB-HF#{8hsGypFe*to2V=-f%s z_EX-VzF(CAAL20iP6YF)Kde5i;vFw3EG#T3DM?J64pY*MG9Zo&i%O#Leus-)|8p{( ztZ(ipTy=hazEAM%?GxQ%RRep=annO%xiS$iyl0%8{ey#D2eY=zy)-HEJY?|$*`Mw` z!d#)+@v7}6QUrZOyI$dlu8->_W%C#=6Iq1GNP!++sYZoucB&yFJ;t=$@D8HBNZ&u4 z`i+Xv!j#@K|Gs5;1UauI^>#+-q@%=65`FIa^78g63Xwi$TETQ&G4{hENfyypR8UZG zd|&9U_w+)-+bg>-F7BL`rtSLZeZQWbo`+*eZaLq-YscFaxt*gwaE?w+3VDrTPfE!!Uj8D8Aczq&sbw=q7Ai;Fu^-;Cil+gMxc9}{Eo^z_6&W~Vh7H!Yo{ zIw(=hEUvB=+HQ76`8x|Goc*S(xE^)m&6`!ROWw1lbIj%C<&KVyE32z|beN0m_iOvu znfohn{MY$QU92yKfTtA zd$Gx9JnE;-dDeE1OH3ym*M`|5+EWZwss0)+x5-3@t&JMx+LWo|d5Kg9l&LdEwA0kr zQFD!!+ZY)cW%ezHI?PmQZkCvg%~bcak{1^h_4oI;;G-Q`Jl{Tlr>+RX0Ba(I1`@NVca~Ju)a=%Vd;0r}c)G3igQ9|UsfVgvPN~`Y6VwvA7q{)T zXWJXn1T7eq*MwYzrWQJ5_NfZe(&#o8yxo(7y-jUQOiUbOt|gG*=I_Pw-MiJe&@U&w zNJ;9fmObcldLYF;f8Mc~54)+sS7@VAidHv3r*urOC2^8e0(R-u%a^?BA8t?Ds@=I67K;kj)(O-Y<(sHmx}TJu5CKq3=_6wGyL0>YZ42)b3g_$YFK(velkxnvt+*S&q2v+(7mk@NDZs@d1b5`F;8yJwN1>FE z>91p@W;L_^{Bz`_P9{o95sbwatJ$SZf?uCgQF&Z*ue)*`Z`^S;JAZSRKFuZ<9@*Ig zX8)Smm8pB9YGAX#+F`@o82p_D_*p4z%8qWVJfe$j$yyA1YGFa&g&@3{!by_;J}!3J z>ghjDC(CJJvH?OTAJ$&Ib~;$I;ES6!KN?U%`WbDS^Nfy-t=m>~>W9Qw+uEL>T&4Qr z9are9uqr0d?MSpN{r=f*ck_DPvUMB9TsKrN@$s!`FUl1Y3b(WEhK#2S3^6e=^E-(m zUULlNIT{t(q-zruO7#1^5-gnyt@TA`u5Pf+G&D4jNF*zfv9Yl{V*l`PXkg%)`wMXb znRo$*y`^`{gAtNLbTw0(`;M^Kb91|=&A--98zi`JMFs2oo6@vE^?!#T7jjnq`KvEY zMxyXKg+0|lmDe?D-u-mBG--I3ojLKF5m!DxH;(w1F5dppUpGEP+phG}xBe4AAxMIY z4gWGenR7z1YcJqU?6T&=pBX3^e)ak1=Tuzw!P8&u#x0sP>?UZu28WHNoOe5aq;N$? zM^|d*&N<2|!;#zA*sv1$`nb#%6&H(#vdFx1a;gYr5`CS}{b0y-As~3|1@rmLgPK6$ z!?h8PS%#a8w{{qzH%YG7U8nR#$t8pwx#J5(PAew96>GwsbUQ~`D2a=Hk`YF6nx3+_ z9k>5T_c@;xMvGKyHkm}^-0C%XICuqL;IARsg)E1|3A_33_;`vk1>>o&JS;V51+pI( zyW%Xy%xX}!BlWleB!#jX8cgrfCrl#_!@3uZOilfzJfL>#hK4)m*JRXt;jg|(?$keR zb~_VI>2D383n^PyNK$j?=8uzhQ4j0XAFFaIovgw2dC^yNaA1pSkyBBjucCKDts>jQ zp$6_dhRJqzb~+Zqd%B&Lx=D8tDOVK^LF_h`xa zTn`Eps|)txi!eRXwp zy0-qjPJ2C~v+=u58)eO_`ztJ&u0`HX`wR>W8q7-U2_thCr#B0bCU@xcbn09a5%zUr z+FXpM7%J>@D)X}=3qi5qqScZy(-7e)*sjof%z0+~oq|2CUH%NEFN*(Wj%F3#K{qkQ zj)G+8|teYg!iigVyH|3Oa+&pdfs`bl`bVyA|tb%%JG27yTqC$dceS{Yct=$a}8Fp z*U)O1kam8EL2EI9tHaM%uJ7F};p6A0sp?HqSk@Vsno6+Wv8lrxV(GpT&I;+UOu{P4Fwa* zmNg$KDQOe|&a%G%2KnQ(!qR5tOt_hrJoYnRr#YuQTswI0I1=eFANC^?5HQ_?xzo9z z$D)LD6hW0;UDC_Dy_1v7Nyp)&4r6CW&B6!A&IFX!c6QCu4+DseM~lQ|%n8K5Fkbh| z>|JCGA+nfl@)M`{xNuGpNJXuj1LQQX>jkCJ&s#fFAF8GY-GHBve%b@wrXZ^vH z`)WATpL1XhXqHn_N(;@%&MsEXHZ6r_20#dUuVd9DwHG;RwFaG;YWVqiEv&T3%8_+j zv&qV`A3uJSl-Qa+CWdl7Yt2_by#=q(^8ys?0+2BDDT)P;QYb5Q$FZuhu~F96!J({v zn#cTiZ4`&Wf_a*lr;x2=H$U}9bs>oi@y$p;els)L7vyKo5Bi*Nf<-a$_lyjL=RRO1 z&S%e-Z`!D-#f+`vVY^4C3huN#_U6XLb~i0mbMtf&Lc%A?emvZmC}=b-ZI4fI-Vqnn z-#K=E_UxHO1p+OYdU*V;J$r$&KnaR1cM&vpMhl)qsP&h;3AO@Uf7zh zFL)jqSmCes&9!`;P9`22d%xWez4q`V(SW9n&e`o)J{urhT~IVf5a|F*{QdE0r8Na? zD_k}wtAg#s`jyqy$45t_=ZK1Ees9~)b*@?S0myEjFHp^fEw#Eo32oRS&OLC6yXM%B znhIbRz%AJ@a(-LDuu^^gl)^&uEm9Hf0CLQ#kM+F^X;LyWGkxM1GV=4^ec6Qisd;%R zI+`S{kACxs#?EHGnpu^CzeIsZ=0L`x=q~<9ii{#aKK|$(RpJN4{Ket+E9q%_uQV^y zmyVgR5&>+bUWn;-*dj#%yD-*i5j_DYNKT!W`@3(s0*Tpv03^(~)GFv60%digWp zFvTV!J~BL&2MTkau;+M<4GnoM=l-5M?cJ$9-KaQ6pYH2>Z=NY3 zU7iu)HZeUI>+5^$Ln?5(R%qD}GaxE%yWhdlE%xZRo)XO(<%Q44SbsM34jT)rg$%S3 z1?IKN&F1u+`4vr`on&=;eLK+%qq>CSv&~y`KQAPWc8sJ!^&sciEjPJ5ynndT!HViH z9-9?;xaeyKU0q#JGM=Uo&Z-TZ4{!faAD-A6!l~Z%*jJwwZuK~K*;~Fgk~p@0aEh|H zgS$X=@7DbX4~(M2k7i%U$;pABppL*vzSBgC5lCt!lR2bSR8+=oRZPv=C=6;Xw*Uo7 zmO3X(>P7OXl8HUI&@Hf7?}}%|+s}Ca@L<7g`X~*Clz~fq!98D23cSmqDG(pqLoH9u z;nUK*K=)W$wCr_n*M3F-;kM-=gOavvEwtY+m(KiGq$-@n%*R65@M@)|x4r5CuO{b< zAv><)V=xuRw!MI!o*qlpUN3Yb?KF<5GAlZZTJ1>F3E7SpukZ|T{S5#6O0=_IT-%I3E_p#Wse!AhcF33Z)dns2g zVPWMp=*Jm|quH%uUi%4PV`J|X6TK1z~l_^^&o0k+;D|<^=nD zdpvPn<~&)U~0lx zpB^sOCtsWMxPVEwMUW0J8|MCIp)B7?U`Z|iHbQ^Y?j@`7Qh%h}Mee^9M9fLGP%U%2 zDbkLWS*5{SqmLKU+6#f-^QQFo$p~x6$ra8Gz+qCUyvBF*q1a0;zr|?ewtIMp>YSR2 zSb2)26{VWB?Fs4|yFSysTV)fb(9Vig0d&r(UWgK)>fOeMpJDb5toRw}mx*uXaY@leuT#D@N1s!;bbDhl`cz&kB=W5RFvx5 zC|}K4KKL~{bu#4DHLQEm#U#v1<<=g zu9a6*0I4@$8_r+eka*L&+-DfaWATU#kDttcXU8%{{@uGEb^iI}1&c!(ZZlYnCMJT; zN9Jp7sg^9zmKJmZ1PSrHQu08wR8u=$PD^OQbLyx3(YIVQVmvW1fdP+)&FkhR0u%v5 zt1jD(5AHs&60lwh2I9~^9foW;?H2wO@%4ms6jHK44Wtns=&pS0W(wKrj*WoN`>5P+$3!%j}Z)>sj zyY2(0<4S)z=(T=tGBYy)#m^P+IPU#hBw(`=TAdG?3a#l7H^6B5K2F1t;b9)D+rfzq zTzARI$-VK_Nq{+4WdK;De@=g2Eu+ZS$QjQqp5ny6DtK)6g{OzM^5i+>`$0+;o9=(A()1l$5wj)8tJztoimy zw5J5}2ma{IuabIRBd6d4+$(I?Wf2(Cc}||tJv2T}HWrbVk~T zfVVeC3h7ER`yU4gJkqFN=sW)R`}ddenM#@tG`1Dpiy>(3lfL_la1#{~f+tH!P!~^{ zpmkqVqqCLFTv}xPbiLR7voN|9%JXf?Fj)Xb{iM|Ap(UUiu#~_OMwN{g8ps$Y|1mE9 zGP2lZOzTU(PRS9%D1wyRgk~9tV(ivEY7?zdR9187Mf}PotPu^VNGr*f^6=n z_6mN3-|`p`ZrPOyyQ#Qo|Gk)&$Y$PCXxjgVI>O%9;YP0+2#4I9O{)}taxeJPGWv8g zpyDI!RCadGNjGSoHj$bw?J_fQrB8>enTl7gs7;-O7*_EdA<`-6DqKp5}_GPoR#CK zwwx07_p6&1FHZJ(ogmB*^i@SVZFi|B=|n(NqVK*@D@dOpTY{*xva&KPzVYDWIs3Q1 z&BMdJy(KF@!LzM;rK)M`-GAAtFB&FRvQJ7^Asl;(fg&h9drZ;2O@5>XOOi!-x(lgx zlMZy-Pl*qn?B;fVlN^NQ3OcRz-J)($Sb36JuF(C!A&}x$2{Tf{Gb6)CKj#v9YmR(s0yAb*X}fm+EG(*UzV2TB zTgT2qWq)Dln#|gYeQ-_7jRv{|XIU9OXCWk*EWvivpa5FC^G)B{k$s?y1!nLkfVLo2Ui2f$U$vQGy3mkL;q#A0~iE2c4}m zhPz^7V`gRsc8IsI_A@T7kI{rTuIALB9ZSbFG&MElgsE@6%(e1`$I_35uZu%yPh54W^zh5&u(ArP~a1okAV-vD0~F- z9kxmwq1iH6=cr9L;i%wb7Za0g&i&aZaCsy_ySu`vEEtN#4$0U|eC&d&J3CzPG>_jjj@JBU@QEivM}^BXnf0C5~gb-NOofRelJI@spCK6YUnd2P|l;-QXQLuk(H30QLQ|U=9hb7u2qk z!siuV`olP~o1M@PkDF5L&Q0mvOlJR+1ziQoykD*~ zpA#?3lSRs*F1;)rzMfDu*7&5i5_KNGatqxNx){Om zo56^da)$jlpM~3SPvH{QCp{lf?>^~K)1cT1+*mM+KD_Y%fnb4R)AB`?WMN_9CITHO z5$w0>>T0mAb5uaB9QgR`jJI@b0wlRx9@=WQHa0*HG6(o31RXIB`>+1~Q2Pf^Oi!vn z&ninv(R)G3fH~A>A#8`EGiH;coFh)LV}XLfDEPRk~Zgr@|G-!j{| zA84qZb?!VXZ8x$;DV651SS-Z&=>KR{U2nQ=bUt=_Xxy-sLE|SPpWV+3*AF=jZ88bE0%J5!tI`?+pl&*zj@S}zC7B1mKmwX~=#bU^gRxbi^k45QoU zZ+X1L;PD$|!mi_syG%>7@!pEcilH@J&GJv&{QZ&DoV`Qb!-cxnvZ!fwOuZZ9jY=X5 zclFwb8-D%Xa)_6~N_kCs%Q7qfx)(zdY7tuqVWUx)bU*xlZh2Rv9tj!W7^$mU8+Lf* zvxPMQop5pbXLpFniEFG)eSE}%^cVs!6`jWcUKy_H7XE}Gw{S-E1AujZ?gDo~i7^<&2P zsJ?F6%3^)D^R-bC>E1bs@0&gXLZACfaK{MeKIE$v`0;u)#f}FnB&gdvm7n_*|11zF ze9cT+__t^;E{k$1sO}hKKPL)(*ll0QP2t_UhYyD^m zuy7anye;sV4Z9lB3YU_XiGg2L;I-i66y#@Tn>72A1AE8Vhw*|=3zfTbVI$S=BGnid z$Aelebi(PIIRf7vKEqqvY89`0??=cX&tM)St#W(uO^r9Erk`4w*9wL*k{_RX$gGZ#XEX z9*xzY)NU3+TVxgw&l_8ZYg7(WlN)+B0auy)WwoqpGT1|81z<_=?ap5)K0tuPKp%1g&w+O0?q0U@GlXZ?I5Wj3Ck ztE_SCW882zLwdy40(OmxNtup~b~*?pG!1814%+=D-Kg1lg+wGd;6lwawqB<&%C^x7 zuWKp2Or2EpLF9!$7Z+PU_fdY&ho>4)nJgnWHG;Z$eq4WsVm%3IW24-kFR^%b30 z-4JDfS@BX$>Ztj?TkVX;Mvp>fT_S{6N!QAzqxt3J*%d$fW3>@i;R} zo$~7cXqk&tf6~D)$nEd1Q7zDW*t|=(+!)YEd+sJKyv+j(<&4aPorISZO?5xz{iR>R z43E#icvD0`sgferXQ~3g8(O}c8Z%R(q^Q_-an5#V#GC3ev1)CNN&>eoL3Y>lUy(Xp zU22t1NC(V~<_-zDo6bDFlH=23BVL>%5>Y=w(SbZL?7MT*W!|8Y&GjIi&IT2~nK}?}jBt)nj z-}beDA~}wK(kjrG(-gm#w-86kTrFLbSt1 zMoLObV&V(>{iURUt{PSsj|OF6k*3$08s7%$gjppKkACpbiw&i7zbl2sv9#`XSl+AV zr;@r)6Z0}c_$E?F&NyEUCszTXL3W}Y&)c)ZJz=@%@5oOL+K^@`^SMQ14T>hLAT5g`tzwtB*yV`7P_FkB$ z$BX!|7uwfJJzpjQr}%*l8l|NA)US2hb`PMjU+do!m;T^f#b+*Q{XlJ@bF>phtWW*= zku>L}4lMz8%hX&6MO_w+suu}J^#v?x8yg=Z&%UMmZ&E)~lJT|UlPXg$tewp$Ap4y7 z+gLTT|6%kC7w?pWsy-JRc=sivpiAonL(=q*sqQ_)-{Pu$ibvwR z&S(Dn?=Ma%`u)vw^rnxaXyV%^QTpJXgyEbtXy)sR>CE(c`MmJ_+>k%#QfBW={j)Nx zkagZWwF5<87el0aYT)thclVS&3R^<|#}q}_Vhc&rua6(ZFt6)V^Vt}%ZjmQGS4 zO8qQ)i>>jfKtZ+W1;Z0Lghy_y%C<;*K5jOkpD3n~o|cg-xJ?YXfWSLcaTqtC` zLve>Ay;~Erw)?!V0K;RDBj{5qHO)ZE{<5i#Ox?;Zos2H{Y+VLqG49N;bc_ZGX}ZH1 z)s^|qyuIl!fo2cnnEx^5bS*1*C`{8yNf-Ux6R=n7=I$bkZ8L?uQ~f5AVp$Gxe<3Wn zsP;A6E-e2Lqmm~nl5QuLsm_y|!(|cZ{#)&`8nnH`El2aqT_bq{jh-r!F&-%oPHVPs zkxLyT$NA^FLSGr(-=V3y5nwA2PX~!o1l?HXpE~aPBC5(2)46Q@G$kG~0}afoAnx|g zuV9oJZquo14SJiomY{|vL^>!U^btbp&+C(rUH4KCn|hZs_nAIkVz@~cjg=}Vzoq9j z-f*`KP*mT3h?J3d{F_|Xk*3&Tvuh{kH%`LkANtW0?8!E`&{KQq_{;i{2Mj zob<4c^PiNiXw@0v<0unjZ85a^wyBd{6hjse>`Uv! z=tAV#%mYOFb1FzufdIWH$o=fuz~JE16bK^dJkFS?uxppxCD6JFx-`Uvj2;a9-r`jm z{}oJ`U~qqKG*nh3X}U4zedF&}cWbR5_1r8AJmODdYmfc*jZg{OQ$=ubQu0jEd}Ag8 zsasG<908aT=~H|s*ab4P${E=X|u)o0Y)BNy6O0)YaXiZNPv;&T#5S0iwi-C8d#) z=G^TdRGU8O$#35=!iGB%DjVV1)sDY!luhb%IyGPrTrd~*@!HUnlsTi7wpv3@Rt9J_ zWR%(!A4et3LU7#c7x#C)a2`~&e`5etvWhSb(hHrxUfBBK>n~ju`Vw_ImK4P;H>A3T zuI1U@19Hm|-Hxh~qlF*X(7`M-q59viRJ}nMQ0Z2H+f+OlGnjF-9O>1JtzzRc|FFA_ z3J?Ow*g^@Lr8TH^Fqd?R{z)}dD={tujUCi_=8B0N?r?=WdZF6vkQxYQQj2#v7{Met z+2_r9Vx<>1CMwc8(!l6+J6$iu$a;IHs5-5;eMPV;mq}PKm@YK8OmHkxuH4Z*+Z?6K z8En$g%1$(&+0qtYZC7XU{iYT|MCS^?f}$?~nH%#L)GVE$mFfwMUf|3L`5}87pfOEZ zEZq^wI|92Oj|a*9q+OlS?RZ@bo1A>D*YP?!Lv`NmGc80)$H7}sCO82oOXB61A(4Fb zMzo0~j`Zm7yCr%wByo}jDU&|J;X?Af$0)3PxJSI*I;_0BbxthgK?Ztc0U$Nm=Zt23 z|Ne-?uj^yCZADdC8Sn7{cn$Clqd}t|^IakvStYYgZ4DJmvi=f&?{f80; zXn@hdXm8g2>_CW}Ynaqk7?Punv2k>L4J*DXv?Gs1h8mrvlOocnDeWJrP}whV)xxWS z&wGpn*n@4o&9M87)_BKO1YpNRTx z)5I;w%MylB2?$!mp~$Q9Az{j>v*AlvwLACh&zFpM8UMJjpijj862_!)lt2D)>O4w! zt0^J#uJ>var?v0P{KkbAkn;tb@}HVp-D?|SHcVnl3FjIw zG9)6&{dtuYdGM}a1sW2W-MF|YpR8YA1g{~M^ndeNmg2TXR98Pb!;nJ^wQBhhG_ix z3x~8fBwA<|qhr8YJUMX$#nmtxqToMeKV;kLyw?;DuNxjapZvX5)=yY?mC+&P0+TfX z!~!NSY2Sh+D^YD1Rj>;uUb5L>uq`i^F=YrG?2hH;!e|Fcb9Hmpam>tr;@R zmE@#`*?CvQnjUqx-4KSH1q}x@4)e7ZA;6U2$WzEjNVIRyHXBTOPnd!UX~RSIC*T{` zedEQ=LMWvW=}iYuB89cP*X@3&u-_ZGjHfDy#_-j-akh4?jzBM5Dvv*62lC+A-@YV; zk|RxIfNh6#kLO-~bL++mBsjS_tjo!Mhd69Q%)+w?Tj=bpnBL5krK&SFPMFVCZ<|4b zPhTfT7X|GJ-|u#$Zy82_vGOUzZPISH$#)1>RHl8ec+^IW^15_PV)h@}OluQxMJ#2F zF=S7n(murwYM2@GQ>M{Cou?gK3($3W0B5S7T0Ib+*$p0SDO9Y^$zdkew+AzD`Q^Wm zMh1grHKU?nY~6AieC{|Iac~HxW&?zC4$lzxQA&0B-VX(PRkz{X#B$N}PQ#aLfA-#L zr|tj+DD#jc@GC>NF@4D}G5Hl;s+)zL&DhXWnV3f3@+ibVivyAoTcYt}xGM4)bMX&X zh1sAWXh&HWka1zn8Nkk_>Z9uefcA$qa}xGZN+6NIN(W8JSy;5`8)=CEC)XAbTa1Fn z)*fo48dhGOr@W+Bx`S%3IrEWin>MEoQD*Xk(?}8MfWra~|GlTRTEcCO_fY?%j|w}0 zk(IMt={JvYcQ55}e%l#(ngabnyCwr#(g%CvxAetNOL-tQBIXyAUk4ZIWbP%E>6;kc z&@ASNq_)sPL^f+sD_hyy$iw*_*??VU&1FAm6RzU)dcb3M*gxwrvGX!t!I#sxK}dmu ziwlhz1dq(j#hOeoPRo8SbVGvGx0mvXLR4*5ku0(UcRi1H@9bD zto_9F^!L_?K%s~K_viZ2yJRvzw?VwZkaO2WAJxGux=dFWzZglV2Uoj#+dCzYRcynMCCMit6_eqaY=^rKgyx)5^fq(gWItw@C9P ztsu$6&XpZ=jbdp>HQkoCdYBuc@d!k}f{Z5I(wQH(8czDYB;NH_ z8o4#pjy3tg+S2-Lr#4K}bzg>MP97KM3AN=kG&W=HtvTlfY3@9pgD zSc&8jym4JqXA9gCvh0M)`SW}!@>3}RaIHS!KDv941h?tOI`IHEVeJ=IVyj)NBKiv2 zY_a2oN6QV-NA`3{K@A7f?FMspm$Ax0qbm4oFqC7X5$|OO+kMrYA$5x7+0t{)m+@ir zlfW8==`%~rrkG!Z#Vg##mAv!1SznVm!Uz!NuFBwF^vN<;x;JgG!h`2j9P}lO-7cw= zG7O|#662sDbPBKIA@u%ksJu0VVs=J}3BK$CCb^vG%yRImjv1FLZ z0m){t_+WvsP+5xPVYlirrxYY1EEotjrfQHi<6w^d`o%hL!q3MiD`dgH5McQGQgRz0 z3rh(_JyI)#l3CvUoCM!DQ1BLXud!agR>qamzcs8yYrR$Z-}JLhwdsyBVpW1mkJ$Ha zP*34B{!Gp{pVAX-C-}3LQW{mbTl~eSrLgzfDrt^0OhPCjU_yp@r3x1hk9h^nM#+Br z?CsA@0<65@rpJ##3O$9DrfVrMh7n%4i3(tYc56^;UT4LD;-V{5{p)vI0&n7lZk8Il zQgb#E>dsI|fNjw(nQr-zfLNxIu!R$_AC%J856Pf8Qj2T>kKvF+dF%ZRq}XXG(JNFI zU_7YkYzL6y4U^5SL7#*URquB3Bj_t8s)_9UbXji;eCj6&@QuBRng)anlxEZ`p~e<^ zoDB0-X8gm};v^lInWOr|NwxbAe!%UVBg#dnH!W8O0F)B&d$$bj&^wip_#s_yb_X6e zej@%;LH>}=R!UCgD{Sk52HDQgyO<*+=oLT*9~>$G1k$CtSi(6J<#3bRV4AE{-cNGXiFsHb<>TIWdcjOoojF7X2&}rx5uE)!VBZb|IpgYG%QX>@@~x` zKG=(YyB40#>!rd*N4G~NL)vjY;m(?^6V+e;=H?!rq9FXTx=&j&Qe@aSZfjaNf^j+F zD9m}(<>c<#WkX)E)6Dg5X?{w|d`r+{%d(0JHF}$whMT2hOllDNAWr!4DV0>;9;}e3 zDP0<8AM_GPE-QN$VKjEV^2WkTREpJQPnzXH0_3!OI8e;^NJ2B6v4Kk@lE(8*y+>K& zF|X=cc|L|kF!q5O^4TFPs19y1^<8}s5Zc85o)jO~?a(lqcp`l4g&BvS(ZOI74`{|_ zW?+dsFQ-I6Hj@w+Td$&heiY6Ei5fscj-{a_f>{ZSUWESQ{rmURz}kiATsun**^R4n z3&5gAAkEc0D{eeBFff03s#6Nul}meyM8v}O^GjImfBXLJEttm0G|DfJQ}27~kOL=JKdYq8AA=QT$W9Vvx!=tL0%ExGTA98? z2^-y5;N$uzQ993;?v%R^5m5SD-hyQ`^VRL-xGzhZzBiO?L#2nf_B$W}38kyg}c zh5Q3^1?Rt6X?7U1IEkI|+J~=KX9=8)56VY;O8H%B(TuVaie7mt>#Ktop2kb*b*v8D zMiawrYS*q#3P;22FC(ka5a9ekFpmqXZlW-gyjYCBe+G%QUiVa7*&U1yMxO~3R_Ju` zW0JOnIp1H`W!Bge&M}2P#n369;rDeGkFJrsuUR{jGDIp7cwziD$SQq7(={{fSQ1qHHG!y_ZdFv|vV4kHmRf*4<5s}|B?#)Tt=Ba9ul$nDQdGEgewZOAXmgWQkAHgAG=-=(( zpvcrs@4C1PN@(&dd=X%9hpD}d@iMuc#~R?4UcC&1jvtJT#|sSts!;%i!*Got;#x2d z2}1Du;86o{7ns=F4}ZX-DUSfS;Ux61P9+Pj5oFn^@_i$au4PqKF0GHURmj&qQP0Qt z42F%fi@5)n1)BFrt4#SnhTOqH4fm06fm7ZCr37iu2*Rq*kG_(BhVk!nWqS zQ;l$`CZHcRX6A%&u-&{za9?e$F|(Ss`77Y_lu%xN;cnxn3^_cc=)l=4GwR?^e<5SC zg}s~hD>6i_U?l{{tT}!W8ePaej2m=^ypwAIJ^>UT^^o}xoX_(8{>KRPfD%Gw2T@Z{ zt}e|Bb`&^p;dLLnx=QCP@NQqK~M5Q4>*X{ZW8 zZUBPg*-&|V(U{CXSO@Y5hpI^!r#-%R7kv24OqeGe9U6Mz_hw#3ycmz1kF(}_be54% zjY_$rNc_m7w6{o#HA|nN2xC|n5vka^wCn+OtTsAj zSSmU05O=Z@nPd*Km<)(r8Bs~?*=~1s&e-t{XS8l>`75`sTC;lR<~i4@ZXF4W^bz&vLjWRkfDj^>HKHAafrbIcglU;>;d5tWgPf6Xq){JA$6&Sv zmL#@2j4bXrAH)jq4r`DsSNyLmFVuY^>KA4BKiFAf80ihLRj5*H_ot*;rSQrpRAGCj zDj4tB4gE^5#0=a{x}-Z*^&Wrv2v{BjKC?UKlyL^1K|}vPnWt^~9uAGc?#%}g#6Ts8 zPQKd@3|UHgNGP-S);BN8G@yC^5A^K5lY+L}@g&-g+^9Mw6if_HmIRex$9zaB?!)yV zDwGUr-TvXK2K#mUeHV8x_QX~8pODC^pU$hFjx^;=xaju*aZ?}pkf)5k^aM-JdX;t{f-p+XXA$a&}ByQ?7WWP8d{RL zwTivwcq=pMp$^@S&Tfp0!j^;sMsUJ@T<|-wL50=uypLEurn+aAM{QB?i(Lk_zjZka z{(1erF*wATScU6~E00Q0s`LJQmX7%m8H=N8lG|Y0gIgXje;y_alc#$-2__TsmML44 zk3(i*g(#e7URn4@*QTt4t#z)r29DElR)zP(vwx0zZQ{Pt~_|e}Ql@;v+k@gS~NH>A6O=&m&@}i!c{56N?X-0IN>IC{j&*IWWMR zUzIbohUU5|Dwg0XGnWi2%@f8H>?U`<(%tKAxz^elL)3jDd$2Bj3Jk2pc1WtVLKL4}0|l#6ZdlmJ^L*vg@h>`TZ7B;a{hsvHpJnW$ z$Vj!=ZG!&DQ|k~Q5( z$S?dn2bZJflW zaPl};Q#D5$l-ye&jL0oRoi&=eGW_fqj4;MzZ%E@vNY(DCt%X-(*kTpWc& zfjT$y>p?!tp6dD=33N0_5Dbhu9q>I6u-FuHHJMuFpWN&9B2$!?FDflvHGyyW2rY&0 zg~;zD6oF9!`04@9?Be2Q9(@Dd&UsfBlBkAgtp;}_*s-t*L6lNWnh4ZmT}i4vk(a41 z`;fh#`X_WUo$qsY_-z?Doj%m^q@YRkVa|!rGU*!p$&Z-S@9ILvoe!WT5_Sd=MoKRG zkaMv}*E2gpeNm5LYnKnyq3K58sKD&A&jx0i7zYwPD>D-kPwqw6XT!LEm1ge6T#L-K zSiK5L>3YYvv*fJMTen?fS5!aEcWJTGnudz2(WQ}myP?&{prR44#|q&n|G3@{kothO zDf8wrXpi1B`w}Dzok4lR zYi8nF$8*9N&_f7vgT>X-)KC7Z{T89~^euu0J^w%>3h1|K8wB?6k1+=TmKNA`VGdJfRr`uCX3)1gA59LT zJ4B{;N6I?&A-9Xc1eyWONp>xmzIQPQ<@ir3j0JyHX}S9P*eC^g^YPZ_C=H66QV#l2 zX3TAD_gB*5vDiC@8}gvc8Te1Qg3L>E$sqfF13jpn9mLS6u`wY%HzCd9VeN=#=}`xq zQZ&aakoE!5BTN?DIM9|xK0w%tWrSJ;Pvtke#;+ILa%)pHZWHA;0fGn0tVCI0q#FNY zs5%o^OAY*MF~IFCX=oL6|1d0uL6}T{`F5RBu}h#0FT|KhkE_8+!SL7kQ*q7U>-_LF zE1T00!AdSC)G8w-6H*eeh=Zt?;tyBrwF2MnX8?0m&4N9Oc;8-O@Ksb!z3)u?ZdovU zEd|+i0@q)&S_a@?MYXORpf>A$Pl#c)_HzLdEfWXP*K_x=e`W4}EX0_Z9C8ZM&}X;7 z5&#SbVG0IN$uFQFTRXK?JVX~jhn0GF92r54bV=#=@R`tSybmgl4NYka>2pVYsW*=q zO`_gFWo&^#%Z-|IG|XsVsK09sk_!eE)A}3$+E3aHY2>%#v}ODa({bV(m1SkeFo@^8 zQMQO7<9J?rzSHpSDsFp8lr++NIfl_i;)!!mkj63UDboH(=1vs!-l`HFbQ+G@v?K2g z!12pg0tvU>c;=(#p*|N@%ccKIUi*k0aJhki>1@OU-!jYh0_;1j9;FhD2kM1j+p$=P z=vq44pCOKR45%l>IEnqJIS3U_Kz$vI^yPI7WaDD9)+?r8T zZKDuc+l>cZb(xXllfBQWuSfUhb~lQ3t{e6?VDnN}O=(@PC=>4sQ6;=x#mP-o7Fd#o zTvI*Zwe{&A*Bb0cd^R`9uGJ#LF|6uE3DPGGA7ddbzcsw2|hm<;}HE$MkK7w;nd>)JJXH2oxWDd(U=| zN5xW?%-bydQ|2CioH)m`zv*b1UuhywC?1N&mTl!4miYR{8@&3PECgNQ_KZ30OWjCI z;cr>1(UD8LTTKo<|e?$Dow{j~9nU_n&X6`V{h?EPAc@ zpZQ5Ftl!jsW*V`u%n2^W$AO0O{O?~A7E8_2M~-2pfsf#Ap#HZK@9!Z987_PQE-7F^BU^16V_Sb7Xeadibj4I77d%ezWPw-|<{>P2(mp2)= zlJ|S!)&PBY`@y{OudoME|6fe~|HsedztZdf_K4d$oc>fA%SUgW%tfXmvs3lUw{@JV zB}!iys3JA0zeQ=Lv&0h^vv3RZaDSI@Vz`miY|PTlx#ecZ*2>!5kK;#hF8b$aB$Eq8pB8B$%LBT&F(cev z9%;5HLT1vO@l9Q(qaP<|vnK0}vP=B#PdY?r0@9Pl?~(aw#zHTS=CYvnq#Tl;wf0kb ze-6te;{zPle3F|Xmf3P@V)XvRjwiQPZ!cD}Q7CcUweBHExK%=%N9QgdeYIqT?2}?S zoEI+n>yydN-CMy7hOF;CKEGqK9@_j`RL96{q%yJr2ieO~EjU^i&Ke{_6$}}qtZYw* zvVVbT-tlgJjCz~DeTC>CFBvsu94SSuCrxrJQ#WT0yu4q`ZT&bb9Yaa@XAcCHsYQ5g zwNvC+tBW?DBYT;i+K1=v#|M}V_4aOro$ZIog;9k{(@J62P1d<>%>j%Hy1$(WyTg%VOgI$05>#NIVvGjhBV}q?zR#q0q zhNET!Sm7+Zx%Eh?0C2+s_p#E7ijfHiS63};ZazMfNLw+K8F)f~C!Lk8EwL1El|X{^ zi0QNAd^ae+?1id7DZ9Jhq%GLnIqUQO9sG7LtR=PB-Hl8Hf#9HN%-zu1?mCTOn7&i; zIhRd8lWA$8>DS1lQ`5k?>|>iq zeL&OXYU8SX=->QLGMW|ysBq<=4gh})z`C&gr7|qzGu#fh7f~n@{b852v624%sBKMh z0UIHQLBPuKD1>hNJ+ZY_!l|2E0-HZeD=YXm=%(b}QY@~n+S=L0OpSugLunzSh)+gb z>%hJ9lKJrgGDmNE63MX*w&JTgq9V3liH&Hqe-1YwtMJfj>lVcA<{=>$p*|ht-@D3- zJPUn`-%jq{W^?auV?|$X<%2Gf7j(nN;p(WosH$5*C5ir`9qjOIO;w^nn+?SPz#gCK z>uUi!3?fZHp|CH=%9Z~Dng|L}XwjMt9X>nhADt+hOx56m`i^;y3)&xz4vG~wJWiVYMcz@@qL+QY&! z16G#)`jG@0+z5*bDIp4RuzDky-e{rjd2G&CWiR9j-d;3KNiGj1ZY`v4J@Fq#da6#K zstVhn20lyi>Z`80Ov!7nwjNdkmG?2kKKnIO1_rc<`(|AY4D+4*olUN6?o)j^$3HrH zFW~k{IAz!mwu|PyFLp|TbLNW-=D>hPdUms_@N$=g4#@2mTmfljn5$zy0a9^Z%n*lnd&i?4^jxYF=;2K7M1n;u!+fWnx zNt^FRLY2p58DgMp5Mkgj?rIb3h<|XDxx@P8nYZ>q`*JYuwrJk3dml>^Umzs2VP!Zn zl0kkxu1-x%9OLq$P%5p$0o%(56Cxfd~5pb?RWF@v?{cm~U;y78v*>@duw=nJ)FAvKNDw|g8eT4yv|B(VUGJg|_- zEh$mM-WV+Kc79Q_w6^AbywQTT0{KqrKZ zb*!G5mi@?8(4^=?(eH5B>$NK%c8e)n3L@whsYOgy$!lby-P@dDrHgC`f+cVM(#yCt z{crYsUmKcl+{mgZlw*D8He_nUckiUZIGatkELHNRl-?~b3y@}{5$7}4$;=TwohUVa zZmoG>_F>y!p`goKr!4!kM#ijZ+CyoW{xGcz&$hsR24fwnngC{SU?n#alPKy|Tw7}} zfs#iNqyl^mn*;7j&%xGw9x)CLZA2>=+t`&)y~d#U_FY@yhu3~~No4lW@wnF-qeJ7D zB4(VFvBKUR5{uXV@bI-2kU#Ut%64-E<^D?GhXT3_K} z^__K-HMpWWqYw5r+-->t)NYi=bkS*M0A^@W9u$V@5CT^Q8?6iMxy5n-Nm z1lU?R3asr@BfrCXIECNtv7#STsM05JMP3;(NnZyQ$h~}%=A7UXEXPm4V zV8BWa+5hU4n{)Eh){=I_De)s{zF0{S5UTv{URK;10@au);bj)N0vr?e@ib6kU(Ek{ z>&od($oGx6pLC1re4w!4OOEZlf4Ml(K$X5nGSx(V_FR1_%*M@c(uo^h6D_?L9H-f{ zw@HwrF_@*b@r9w|D37VIoyy0=7f*M&6tIgjjx`$CI`fNd#uFRZv=d=#l$+E;;TdnJ zq@Z!&Ucge4^s4u=?j#sVRFQbq?_f-Uu&-aew7O%60{M@dNmo37NrAsI zCVlnkc{Euh1QA%fi<+Sd{iI8k-*t(j1P%{jgJg|IC5OCO%N6DnmjuJ9X^_1`?n`C~57HCwd8ni&b{Lf1H;v!1 z{uX9R-A7$R4y@Zs*4qiVTQ!?s#-e5|FAhd);=EZkDb3eM4-c?TDw>wssCZ}DSjK;Y zP$qHeI!Z&NCWw)NNG5vTL@iLhQSnm{136T{7<-EQJWF8AVwOthCe?#yk<@fzzk~!3bw9} z&hE+x*o?RVnONdZvAO^*s{j>#zcz&LbjM`|Lt+(ei z8q%`)oba74 zYL?WQlU^6*`6hl$!n`Q>HYAzxMi17kHb*hs8+cxw!i`<8(|w{Nl@3Sgvp^%A^4 zV4-r6uB@zpF7}1wW3UQ?(?*x-W3qAtqCZuTMUwQlJFmiClwcO#*8d zMoZJ*4%Y<7r+;}>`!@cMQGowsypb`Bc$ky9PBsr6@r?Uh9=onjW{hku`s{ZT?p+*t z+v9tW{j8fYi4vEZu@k;m@%m((e}fQfgiWE_q~PGBZ_$G=bI(V9W7@Rc=TFjXPmqr> z2itMtJ%)SERLGvgi=9eu$g`h zZ|-&p^?-ViWqjP)`9kbuiBsv{JNM$&E^_&tCal-)b<6RLz)Dw8Hix^!sSheg&3D;e29=Y z?f;ptVq}x^;lH^6n0fQRN7?@GTmC=$E&soLvqGFb;PMJP1(0wOmZ@RyWeQR?FsS7_ ziC2R3HkD~tysWg8IjHZ)kMiTBzstD&=L)no&KY=|?MFlYXJlfo2SF$pbM=KoX zfr&HL-_M&VK|w}#T}qlZVkF_Ccnip@zJ2@VFWLgqESjd@zY9yHCr}-KPZ(YcCj>_- zLMdRpUdRU|0HSP&m6jG3w8oO7V`5l?B5&!8!*(f!tv{TTolUZL{o}wqX`nP7m1sFp z&oi<|*kC#cheM}lzMv;CNZ;!53km%g7@+e5yZPm54a+tu7HxI2GP4enem+k9%Gs?0 zl8vdz&TWdL!$Z{CKQZV0AOAVS?G`qtW44r@GM}?ku#KZ>D(Mlgx?j`I0dguRe&y#c zO9g=DT)cn$Uk{_SnGC=7%NGr7qd^YH@`eq6W!qsG?*Xb1blo#kQ9 zq5HZJ2Z2w(=3wD#Mg1cRwYD8whNtOx#YPhvfp^PV{`vM#&!wJ>g?cJYt z`2JEDRBwIj0KD_={yD&7YxTTvTktRMgAPM+;EXtcA62FOl+< z(S|D6Y+IC60LB7Zr`%8!uLw8W!S0!C>- z8jnoVX!G#dZ=`PbSp)O647`w#5ExAm?<8a}lS9m-@pk64X5GtfO8F6k5>HuVTCV~G z;yzrYAa48csMUSUE$lOxA)Cd5J*?C2igrZ;0m9qv#%SH?PC-ZC2TRW9 zV8z@7F|j`Z*fJ)zFs;Lbg!|fcXG-bW11InnsQ|EQ?cR&4S;u74;2h1?fbsAK=gV<+ z)>atpPw1t0dz)&3FV?fDf)SAX!G}t~)PGs#6Tm|dH0SC$POk+0eX7Av#odMgw$cW> zbVI{B?~_A-6+z>;d>D9x(L69Uw@P)M6-+<1a~005f@SpQo9K_0FrJ2d)iAj{9igSA zWl{DwKZ3L4o-;PTCr_T-XLpIDS8)vO!}u7|G=UFnS2`LV#O7$@O+(LT-aY>^yNc{)zpykG;Mlc#eO9Gbwu4Ie;` zQYO~D1J54Ot&sfXi2Jj!0_wbT{%er;c!ETt2jlyOb`F5ADR6UXWMizI-!_&)w*4`- zx@Ue1V>>Jr0M_^ol_4tP-&qT)BS$gGx4-Abxosu~qJv=r5B8mWFm=VHd0MslP9$-NP%NC@k|G}z;{mLb!1|`pKZVin&^9l=CoEiHw4~+%*5v*K7y(Wq zl`&xWQUNK)vyAc`uZ&!Z!wSv7TBMs&p?Idk;X`TG>QOZMG{z_p9h57YVq zvNgTFKYTNZ;hok)2I0_OE2dckAnvk|QGi9x8=QCNCicjH=lKUIEvwyOub2fKE|M4t z%iz!q*o(r%eZ-W$Tp3c|R|ala!YrPSjwPjq&`kky54`(z;PP2f2)eHo@Z|J9-6l{E0AYery@R&AETZ z`c4U*@#OwDK_`9uORuO;7UY(fmtmj7s9<3`YIYS^k8)FEA_A-pb!E86=hX3_92nnl zy>MVY4j$Of`Vuf@_2k|bKy|~;?xxh|FJDkGU`+|>)E`r@GcdsYL4JldJpGu9mjit< z!aRQe`sZL?{wXv9IB4&f-8Ru;9uq7xvYH4G$0!A?x zwH^HbdME=S&_Pw?3%EstChg$l^bym*$Vdegg8)<^#Ha3Ex1~5)RU7nq-7rmH#uD&l-92X(E zb2&WpQv)Kry}jgW<9#~9A>f-N$HXxDg-4()<5y_^{$l;$r&B~R3H+#P8=du1Hu=-? zf7Zw_X+QLK0j3JnNGvJ7V$F)e)z#NvK1&9ljr`$)%hOYghu(12Qz5F*4L|F0vcP(5 z2|irDIU_j|wMXOY?USx9tE2Qe5~k#}H_pe=mMOUnS+Tz>%j!I*r?5sw7%1JB42>h; zXY%W?ei1@m`O84v2caFzauv~E{QRPP%bGMT%^s=4`qyME$?iK4{A#8ho^Lf*H$oI@ zB~O>#G*+}Is?&At=c~mMBXZ7!fy5o*I_!sV0el`au zrzX)yaPz(5j)PDLIAlZE7swQxhWFpWyLOFTI|fToCzs`Fg>CyPk?&0Fb@sfU4s$55 z^1k)@1Lo;DwCTOdyH7{!M@mMfUHtZZedK$1J!4E3-+nDDE~*fHgeTBXiG^yK)-Ym| zuo8G7lc`6~n_G=JL|J|i&uIa*xF@? z90XrZ=3AlQT@S~~B;);opmSP8m}hDwKS=%BNNAdl%>Gq6%T;Z;tnBPpFoxJJTF*c3 z8i{ne+fRAH7hS*e8u3e3eo#wer)9L%8UuP;=173^7I40Y3k*4L0ty6vM{gRZ;;4+F z3JA3KP2+l4FTsIqK;UoSR~%Q`osQZJl5(r*1A2{V2Nb0+rkz2>5JxU+-`A`2r7$UI zCtzt!c+R$7PwBBRv=yQ-sPp#v6REwBl>D-? zumHtXh&eP$Kqw5hoOcKV>GDd_(q{gKrp0m9srFBve1d=t>}egQK!gjOW`Onl2TsGL z8NTg@c}%F~o%1NYcqD1rq_+nX5g|aY-oPw_=okVDI3^~NMV=4Bp1j#~Ls^>kx-~8) zyMZllZ?l8*XM(n_my%M~>ucnu(EMy4Jb^~a+})bLLjxGw9U8*G>cgcROzVQ%1PkD{ z<}X#5Z}+3{pD%_G@)lP+NOCAp9`&_EkS2lCGGr_e3;L`~ z)cl;th5QN#kj_b*wfoaxQJ-hN8Ps5Sx*3Bnaa^bea&iv6a{HgQWmjmRnFLv&G!!r3 z@%a;gwYb886;`W01EN0qYGW+KeTj+Ho(G%ISfak(cX*jt%C%+!;|C8x9k|RpIH-0z zyMm#XgXZ z9W&pf(E)A<$Vq?3bF$1T2BSmvm1K=aGAxpi? zY_gHDv9YNs9R=RmoM2ti+wq$mdhm83+PiV%hT|x&R)Rfvl@FE!^^W7SfQ5DNkn{Md z7u?+WtRn(zI}?8JMlaUjSO?pZb=6vRgab7r@Q_r8MmB%^`0@LoxuJ0Bh7IZrR`9YyJkI{3 zP9e}~Cg1#|mivg5LKPBe=r{zk8ZF`B;nD9&w2ZrLT~Nc2#^E;S*}-0xE`X7W!lBj@ zrYv&)vO_X4D>;<*=yK7puYOSz4$^>nHe?*ZoV7x$W4I+zJCqLO5a5+K%v&l;qu;w? zS{r%MBrt|w&vMh~EApW6xO9*cO>9sHlUfSfnoacXvRp3iO^zRz+uvCueCaVjYd*?+ zM^1>M7L4r7+P)pPIzAS5;`1HpD#d|e30a6RVPNO_RIX$1K;$*V$UPOJqc5C{!TZpl zN=Q^xPeTJGvbA__?`q0Hr^W15{NP>}gqEisNWa#i&3E1qOc%9KEki>;Ou8s$c{P`> zjcoc3; zg76*MAR*Yo#X9@=y11?`?@q6gnaV@Iyu9PgV;L69716f#COdF>I}m3_#PVX|G}9n8ay$0twp`zG6OnCK6~>)mbkKq2N7YoNVI@?me7_x4Sn zjhnk-uLjvp#2NweN%%Yqd&eIjLhe-UZ6YyXO|W~ePD10G*L~*;6M-jKAG%`re07kz zZqK961*okVZ@gW7i_`2d0?nK1g`wA?zuQQwVvxN z@I-aIx5hBaKV8(QsmyWqUn_{iHoF& zxt5z$?P2Axz6Tl{DBN z2(T9_pZe>83BFDyg$ky;Gy!T^upK|X2aEl+YWmW$vW_aq%r2bcErm=Z{>0bp#0a#- zK$wD6IkLvQev|vE3G8ML4x6xa!U789;iD3Xqmlw>g64CW=`%VxNgXK7VOT3FEX-W? z2(yP=-29Ti>~I&9PsKybf+)BSx0pdK4#g#3V#$s??+lbfPTBh9l}nc|qfOen^oE^1 zd=Q<{W4ukqMIAAm_?Uh+cW>|kpkoV3K*{mn1x8K^joKuon4v4A!g@$=oXNY z^>OTHr<3%Tw<`{N4Z_U62S$@v2oAF(_OOr;sHF$r0GA%Zz}$)BDc>zTt56mA*lsUW`eZQJRTTrNqYrvFWXB z8su8Ax>1EON=O*?^L=?#kIXf3fgTLa#zk5-z^vF|tGzK4WI%2LC~^m7=3r@lS! zYGWY@q2qaba`;Po{%i@~6*=NdzLq1LET;8rh^LMFm@F&gE0(D+qyXu~-)hx~(Ec|K zxUSyo=R;>J?%^R&7+SOM68`OO7o4^3e&FDGmHar}P?$IMm$$F!L$zd1-PxtoS_zMf6>^5w_nz#jZ3*`H$Lc!Tj} z0d>0*Cqj>yCl=@@iA2iLV1!gr(uGIRdDx&9!`6g=AL=Pl0?(Sn5jvrjk z!u6@%vqOhc?B|MjRXMt!m4uH;U26`OFII~W$ zsTlBhou22tdo3kzfNK4?)SSwy@bJ2LD49A|#RsdEj;=5%$(V zgUC!*%_QUQMMMXXcK;wW(SXqW{wF9E+o(P5%Om*k*=|7!HCaWq13KvJP)?V3{4PRE z1M?hYVa`4LhZt%|k}R0X%?*>=Mg}Ig`q1x~2BHSOYmHp~%zj+{2dDaoUwD|WJcq9! ze%;P+bAD<3Q;&ne@y2<3GVd2IN%lfx&@sW#us{!qfsltl(-Nh#Hd?B1@E)omkkmuE zosI%@Gbj}-qLq#UV58scQCr6pyXw4as>=YHfSeB?k&R?l-;vflo~*-}MaC4L(~(A& zVe)fvvT$8-dTqs5`?)4l!i0>t1i29|AH+NK;q=fDu=hTlu^|ZL;Wz*rSWM3mOjnZ9 z>PC=P0>=#M zI2+1m+saV5&`Y=QyhfE*SZt#YgrW?0jBr5wI&}@{fwL%gktk&=H?Z5wo;Z6OMC`bK z%lO8r=N>(LL;I6ZUFUpF(d_~uWmWK^{g zfRiCDZTmi0JT7-(6ZpJxA|n9AMvybiwXv!aD`8(xxK$l{bw2VlLaFXg{C={%*pJa(L!-&= zWHEB=3qXWiKki;nCkbZvpFS=o7yn$FUMQs|R+LrrV<0xeU4v*r(DO-+9IM`IyxCZg z7qBP{6QezdWugl*Q$Jx?ovAR{uJt=Q?#TIoo`U>-Fja3r!5j;JI8OSIiR!f zl0m-6Y&yh-;sXk#g!}drCL(ue z9yG5n1I4=(Xlg>!1ZH|Am6amaXsF9z+V{~B3O`?otvR(01U_*_R&rL;EKqoheOqQ&zdsY*v8cA;CDhvEYd820Qct9|gSG@4 z1XL;>Cy#+L43Ab&Lp#cdA%ifgIODO7hPDQ<2^r)@Zl9d$g7%_~C;yysTk$q`zuqH% zZuT5Dg(0)f?GHOo{L%EoZMFwvl8-ppKn0`bt&ptoOSeK`zGKf`DJb=AOKR^%FlZ5Y z$~L2OyZ)$8U{dKZ`7v#}0#84pV?K{wgZYX7o@}OPxWio8C%#Gk4j`uWJW|FoCEd|} zN@HCBsbFLSTL;t|F=?`PboDV5TkIy1;Av>l5%xNdd%LBDdbLX zHM1FKdfq6b@2+fz=4T2wHWmw3Y8`0oH>~>kF3C-_XQzvIo$3Pn)^g*`HQosKHhH{` zRhE!AAdKp&yl=_)#-ZoV?jU?HHmItqPLso%%cbzN^`1%Hb*Xat?WWxB(~M>Kr3aF< zY4fm{C{1uM>zVOa5xCXBTibn4Co&;H72Lk=*DL>97gyavT4G=Dx~1G23B0$S}=iB^~vr}sQ@Tuq)#|Qi2nTfa}GK-g(#p6ihfXf zpnECJtJvPeY~xL$vw6ZlIn{&Nsq`VPs<9U@+Z*n@Df^_FoH#4Vz;iu#H0O#r4;eXS z66p%HNR;iAL;Oiu?vR}-v8|JFc#>ncx>2Vot@tfv#nw=D&aC*!2UmHEew;{g6h6P5 zY(3}~uYGjAk|!ycHj~jn4QWaGI>RzMz9brFvCbNy2Qmd>Xq$DagjZ#tuU}J-1d;)C zjK!e=$z-xy!R-FVj8wqSr&YEYmmCuJ=|5(d@aOzx}Ji?BeAkhfAx6dqVaMcg5qKGtHgEe!kl5^*?H@#>< zKgPoC#=W@=5%Ngutw}FbBvSaS^q576wCmgW+f?id!$-&&T$kgih1MVK(X1k8t3GCx zh6-l8E_txE&xZJB+!{vl_@ zL+l8yX?e{gkIxOuEaJ>|9rqedJ^4f(I65xB(j=0(F6`0zrE@!9es_HpHUXdl8{YC_ z?BY>Iyp;t?KA_e?Cn?lt`z`2S%NiQ=Ek7OrRtya%s#o`p)}iSq=&{hUvHr~;3qC~} z@|!ZddK(laE*u)qhO(V;ELc6wJJnKoUx3+DX(aO9bpCmfnO^Lq?``l5FC-`0WK8&K zb+av!bjzM*^KewuN2ONtwA?s0(C_-4&IV9pWv6-;5J+{Onaua%M0s~_&k`@v4~MqA zJ`ge+Vp|^t4S}{@I7m1Q-D+SOsfodA7^s}Z|llZ-&ZqD>Z)p~R2`PA zU)yuoexd)&dxXU3b7enN@}s@v_`QF zL{hO0d?6GRtdDnHx@to^6lhx7=n9@(?q@H zR+eR((IWbjL4UsKXcm6V%Z#~9j(3gAv0ziM{zdxrH;x}Y0xib(?%X&ZB8@t+8KiE% zxwhYUSAfrZ>g@C$vSTByQQEV~8?7VC&CNB&TAR{F0HbZoVGC-+|&l_Vb>t}AQD z5WA+}d_5+iS)J6pc1M@dG_gRq##$AAjjYZ_>Ey!gGR#fUS+DGZUg@J&U1HX6(EjyL zuqx!Qr1b(z;tI{IXrTP8Ohk#ISGg9UtRA+?0<(OL0$xFstwfXXb;s{Q!5ujgdIm>P zrL&&z9Lf!k&Ss?y+eVk#l?!_9x}Q+Tpggj<=8TY*dD%~*HdH*ugy9ke?c2F-#4l;1 z^%p*Ow?af}zncAX^YhC;`@5yLa*~GW_A%TgxlbH#0oT>WTEW&LvBu+x(zw?x7sElA zq4#xuYZc1u*cjg-F#H5Ln8eXYPy1m3^i@x<0J=h#L!cMC)(&Xaoa!FjkQm8TEra^$j=6A&u*Ak-l;EbwwTzBDCHZBO3}1A zOVNYCY<8a5qj*)_v8dt$j)^ypC~L;a33GC6_+^IZbJxGCS|^I_KE zjnm|>ogYN4Y1T(S#~317nGWql@@q)Sy2GzX^t5Cf+^N;WPC_i zdxUt@Lu+{JSwZHpSIlMPCuav@2~xQvgnL+E*Zrv9sslR-Y1lR8s#Q(ByctqT>dr^Q zT%lW2hBX^&8v|!;9w5@IhX2%~qG_gtC4zxhT&7obT{Tk|`=-u)w&`9Rv|Zwc%_)P) zPqJ9^w<}~M`}u9@9<(I-?c(QJagJ@!w4ee!_=@jc2p}pn0fuAX63_4W6pLiH3}B>@ zUIlM05Jo2L0)7be4C%gi0T2vAl>uBMGcsh&b&C~%(-3Eo9Ooj~CrGf$%B=H|WfbJc zdD=A~hWgk{O(GSd^pJP(jyd7m+6v?7wQS_rxDrtK9mSkHX85tSXTN-M-x<#bmsN>Is$R^iWWk zZJ^-Fbjbsu#h~m%*>o12h5-EE9elsefs$Z)>)<(*&0y8e1lAW!udlzNsXw21p8-9v z?zcZD#K+AO2HingIy&)l?ZB8r!w?3#(I`&Gxfk`AMvm~+bS?$FD?Xsc0I}H$oI@kh zdD3f7>8C4m(~TQ3vXfa_ZueAb_rA6N1SLgwYFk0wOcB$0{GK)~n}tnNQ<)cQ>;^Td z-($F@D#$0cb?)` zAZEEX*@m<7^8w$4J*KK)q!^l_I*aCx{8fKtjQoJ50&G1VE*t8->aEo}F1ADKfQayT zi11G?8F*|)H9>Z~hhtY-ws7yjtvP;)yR*sE)9J~|%ahBFri?c=d}ceptQUpS(ZkH5 z)?IqQ3+fs!ljVu4-ROApvrMztE1)M1+$Y@Q-g2nIF=04hPPyh$8}74XJmqRUJyxHE zoLItybBC>JBOCkZ)`h#h8>eRLLd6P)RRJJ_>A;Vqh*myrxUQ^-cXiL)B=)0TQj8Xa zW&E3bgIvVOUI*i+)7z7!E{$hXTN4Wvhp4u+18Fu9g4H{~8hI&-n@>WyK7X`kOct`s zy%1Yck#%@S@XHBbOX#iOYue`@nnnAEcsN6X&0%F&tdp-{)R_tibo_yXD7TURJRV&j zqzscv)|%^0_>mZZhben=k5W!n7K8r|y;}=wA7MLjv1JqB6WCu@n7o4+!E|=h>q-K6 zhJP!}anS5L^;L zsj(RZL61z|(-T>{WmH}Ii~Z<@0K%#Zh|}%p#AX?68bullM{a-SGc)STHxOgK@T+5Q z;S+b^6OVQN0yxL)6=E^Ci1hy=x?qSfvB_@y9XyJS0&=!50iueT3L*q{3M-NdgU|*6 zLQ7)3JH={*GNL0~x6qP>C+J%R!WLfz6~Jfj0z?HJs3kF#L0O;+`2!ebuf)(|g;@KB z0g8?P;70^OsjY>&Z?C`429Wh~@`MQ{?tb~<9HRUx20FVA&*s%5f2?0#K@R+Vs(ecN z|4I+yzeNio#{5CtG6%YshZ$AjcU`$1q6PSVF)S7eKD2Hs>>G6c# z$rQIg1x@{Z(!ea%%g_4xkVqAEG?+a~Jl@*J4=|Ks8$lH+UTsHATJBb_0;^B+Q9PbnabS)@vhM&w9{j9avPZ-Bn3|)_yN6am_OwGp+g#ZZWXO| z`D`A+bbSO~&BQXu)7qI<<&?t%WuHw)B)SvNx9U*}nilG$_@`&9<6ia@gGqvijt_gP zWVceuxTQkaMQJN9lrsgI-J@sN5puS5Q(`IAO~Bz9QF6Pd`t9MVYpeOS7c1s!rIL?X ze=FzvZ}~CWDcE53MAaa1trJ-Ev=eH+s$d&~LyyAS&11azlGJ@_yKm^`-6u38>nw zB-R1Cfdgv>4zTDr6SDv1%RRrn%|~MjWznq3g!^%OHxYWoJWxG`n=0{r+U~=T^AcKFDNMJbwXa1`}8J468RySJ{TI~z#9lA=mV_S z#b?h2INHI@#(v>Y`2;d|QC;2H)EnwGs4K0l2|($lDTH9G5;*dZWM?Fs1pPM%-^_{ovWMtgJ>jA3juH~m@>SRft1&_~% zT&R4h)JrIl&_>@AhObc@nnQTS$&CW5s;ldh6m}cBzhtDXD67BOF=)oWe}ZnV(|W{7 zplE>V>MaWTt;^5)_TQ{*ju30+aLzgGQwW3!Jqa&Z=8R~+J zWM?2aV4fxPhBQ1y8-kwO(w4AENP)rc5z8>;dZFE`{YEk*(Z_**C|MX+g8dWhNHX;* zJmU$b3*E->Jov`+Luu3AE#g;ATj6?Fw~-MU@_gCy7*yE*~5Y z_|k%uo*jzXKCIHru6o857Ik2xkIm>8kj$0$G^$zjtt8(V`@^RfWr;J#$v0etZIWfI zn-rLTuwcCxfWhT2NA1NIaUYy;Nr+0W7HM@RHnL2?cwz7(68&7R2ZKskY-iv+zG&eS zlk9Io3PTmB;o@S-GTIj$*X12YYc$Ga44yX+PU~xi-~KIhZk4_4Cy~XciZl_G+gW|o zvTO?dNU2uUGK;hicbmJveqtFV9?ETt)h@86j@w3*HoGrhZ9(;HrPkLdfWiBBqGH(PLJiMKYS#;!jb zt?B)qbaQ51>(E6K*@Zuwx?E`~YOEjQWn-K$J*%f|cB5@OR_M9hIeqV*&=3~*M-=bP z5R<()1x6BmDL$vnVd5btVr?7W%16t4xsP|CtXE%;pqWiMT};W%qb4&h`T?9icDoQJ zbGQ^o6T9v#hn)#CO+7f1$S}$|2WKd8n3BZhdY9l-e??Z-Hoeq+=Lew|7sFCc_R%pu zJ67lSQiwNPRN7S?Z&+|75zyxuKW|1qyL5#nDkBpYX}i`KSk~M%ftuSHwB>JAYA2HY zPQK$dDm2V!e#*zQ`xAZYs<7oQORS`6ea7W7*B7`o^GbG{C8APD#2!a>*Kx6_dH?RWA`hFTZKuOX zq31^lqXktLikLsdUVOwE-ecuyS9_4*S_GNMAm=J*3mE;zKp2u^_zpei(AKmfBb-7G zqc~B8o?lSqNHE_l!!hqcoqWc2i;ci_ zN1Qte3LobfzGXZtV8dN>l*6Wp8*{oCukq{~Ui;GrZ-YBloW9tHBn^zYM)7{)s%p7j z&#h0j)y$?ZI9zB7Y&PG8&KCsJl@qoN_unfRJx{WRx0v0>htOi5ExDD#tvbcB^=QL& zjP&jA1n506%Kx1wEpQLbW_~ah!C>*IA1RvfxWa~m-r)0PJ6`3z3OfRP8jUPUo{tjZ ziTjPtoChmG3Qh^gWAk z9alZBZqr1(ZL074IB&ZXZ#*3(x4*J`HHSMPiA}6gic&O?<04||Vt1=q5p*Zoiow`Z z0y##Ps|VPp`dqbB;GGQgHW~x+Gy*CSrzc=GP5hKo{n3xI7X&=qj@?VI5%TjHFk%ce zf6QB&bTV+%NcSkYv3m$_w6J{sXLMWcN@^yRbCEmB?UFBxB#z0&_(XPRFBKM!Y#9di zYHauU7JEfA2Gn5|gGF$n%c7|)GxvNpd3k~FpgpH_c4$ICFphg#suhLu^i{I=PhnjQ zR?EyM+n)oS*3#-Ke=SjI_VmWJ8-ac*-Plj~7ekQj}RxhOP z&Y|dTWkd4)M@}2zZS-=ClX>5wW1AMkmZyWo)`b(2wksPn_%72qt}+A=$sW9%`1DCA zOgW{rlAV=kJO7R!+vve?YKuSN3Hn}Is#C42471moh4O-)g<{0}9^dFE4*t?Fs+>gb z{vcwv5I}rl{$#-~4yX!?8oX-P*+Rg1MBh)T?m4=9cyv(g5iFgnd{LkTFaEBL*wZ)4 z+t&&lmHHi#!Nj*uupS+SH!vC2_j5cDb#_;|wJkf2M@>V=eH1Zh`y&1xGdeLiLXYWV z2)B&UYA-0`AlS!ok7OpgHqKnx#G?Oex8hDJQ(~uHzVR~Rap@zNDKIa}TsKCo3!oH> zTqtXr*}!2Z8zO)!_($AD+G!`UBQq+FRjHe#ta0Ai-_G)=GkUQkn%wBJmpx+OVmcS9 zc?LTm!U#U2QD#ODYjsY6nx8bzw=@J-+B?+;#QqQl+u#f`n}nzgl;mIEZI(`V7x7vY znPOWP>9u2^GDLjh{ISem3%eKa@1$B?>W;=As3&3AY*MYj14_lEzIBU`bM$9{gfxdb z5$3vJGiP_rX;{gs2#hG2d`KtP9fof}>cd)KW*fvyxIjo5rHR!?-OPjxVhnmJlr6YT zcVEHgr3`b(ZUU{K%$@s2Y#$*Qa8)g!3jPNc{t1V>X%7rKlBucntdge#1)Altdv`q1 zKe74!R39*zg-jexKDQema9Q{HsYLd6TodLZ$+`%4{edg zT=*$d#v+tp^q-OV1atpXy+?gc{hTT(x`dS@vnG&0wZhaI{exIjZdo>A8lsJ@nL5t> z{NAwAVM>nfumFp};5Xuaml)QhRHVpE-aV3Qlny~cIs~K@ zDQTozP}npg-FGfde82DB|L%Iua~?N)uf5lL*Bf(=G3IzB?^<&nU(&|LFTHJbbwdn2 zktukEKjO-jHqDq%n{2CWaszXcO_J(LY+qPR=#Et6JF~)D?_m+YWI=DzeU86}pDrII zPMIFkRrW280D74leuz#Jj=z(QY@mP6WqULcX+u3WI-BSH;c_@h(e3Kkzw4RMmR=3(aQ>I&RT6VF-SFXUn*pP&|3 z>}Wv=bkx|`*l9kGUFLh`c0~U#Uxi)fm^1T45#(=`)66h z{&4C?Gv)FpH^+anLCYy`P-jgnIgkyOO4f_%@M#!%^W~9X{6bGCEVL8t!W3%8O(^Kz z4^Wbt>EoJV^)vLBGL`^t3A)-)gy%=Zib!xC41x+!dUzjWyn%b+-*5~vQEwE#t~}R3 z2rB!Nqn#6|NfHKTmOhH8o62VN8texG0ndlnmC zd{zFYk&*3%8EW_$DJ#aPs(I%!ej#5`CB4_|?-z0!mS>i4pq~@tSytL{$?8@WSdI?3 zzuhZKq<>N1&rq!-;;sCnVOMX?z>n%-JQ263XL%LpIiIo@?i8);WD z=O|!k(nB&oXbMP5=kP!CI^4;xi*28F92S{*FWWZ|CY*5JQ@fTZQhtFju#xEuK0vY zt2o^9p$^UzA@ecOc9X{{ZR5HGMpsioAwx!`<5kN*6~6%fMCMQDuUD(u%f?ki6B0So zL=BDLiQP&~KKF->Cvg0?V#IOtBGY|^fw{aZYO3X%EfB`GC8`a~6~&-JA0#&1$7G7` z&Tny>DZXFiOO5UbyCJ6AoF5wet5wqB{VUGD+#B}z`0~!zQEFtuOxZ4+MMHgHeIo%I zMIPu5y2t+a3f`#xkN)kd?{A?#i?i~r;Y&tfjXm>nVG>%}c#e_bI**DxzX%oVB(DWw zO_hmkK%sbKo0Pet(c9sHb!iJ#4OEY_0oBk~2DMlu@%|4~w)v3ZTY7&ilvb}>7}_75 zgqFZni%sKQ*5*Q?LM86NUXzi>sBD${#;DI}RIu8$&7TM#u6^j|$k=>Q>!~S#k4nw? zKi`Ipe9oj%B|){B>R|80)$Pd>FgRFPni_uWT#Z8I;BRrDP#@^v;(o%#`AFF{;H8|1 zp?soGzk=%fHB{L})(a?>X$#v}zw|=*@r%g)l-%3LPR*o)%N&Zo)+#mR+~?Y;-@=Ls(=cx+amQg_bB)DI&HQb74c)jAfV!@HLFNLA4`j;^wOtfl$d1{)wP4& zRw`3aRxkyZ{#bg{9$CO&$4Xf5rCEs&&NXj#+a4wK%a4vN3%UP^(X1f&w=dEl9q9se zByE5ps&OUo=+Ztvc24-W0|p}~GN;hjTU!RiL}EVR_rtg)pT8UCumU`#b{E8_b5 zdWI8NCd>t|yB-3h1Vzxd1b%`cgynw48F3xt0{M^&)L|K^+bA77UQS-QEoSMg2JLe3 z=!+cV)d;bT4jv_ubw4)~`Y5W?V;3odc%5>H(6+mSKYm=Ndk?#|lHmtmyLJk`Ew8PK zc^!Uo>yo6uiyIdgr?a`EsH8+GPfbm|u&_WZrqL4y`aX!l^Czwugc#VD?VE4~b{lUH zNjMdJ_y-KqPC751{zvf4lAf4`$$15>Zhc{uCJIi4!A%(%%ZRaQcJw`y?U~{J1-9~R zmvgnfb{psYM_w!qthnC+c*5zy2(YEI&FbxbrWZ(_iW0zA4beWA(|n zv~QI&xvu~4&2?k^^gFHzLlbS;+`@Z?+&r4UCv;uaWZ5UYir<|RS!s5O9xCB+{JB+q z<;9nuxPBhAiTn`?_93J``l39dp8QD(Z0l;xciCRcL2S*NsU|B`oS-VpY8=MhT({n% z#cQBNm7e!*`vSY3bCkGN5v#5qMi-@wZZ-Qxe>GxlxcDAfDQwJh(8gXE6gnIn9E>#2 z_V%Sqmqhn|y>1fQg<{65LJr_q$^bdTT0mf+)D;WZOA<;*n!=%h!BN5us%|E|4y=2T zriEGJ^WI)b)V-~ZqMQ~C}Zu~ zpLqEhR@1=>uN;8Z$f+fQ8kTJWZ_=zn!X|g5-b2f``iUiU#Z`(g6x~dvMrDd$%8C!m zPycE_kv_B^KruVxPdkkAn}PVStK$j<23z`9KK>cycgnDd9vp~@pe5qk&Duz94*pxW zdPYX#?lXd}rHmZs0~82@P|Y%#o&pM<3nb~+0X;*Q@5gdnDGK%u1z9D*kKE`#;i$D33Hb94fxfeak7;u#_gUqk4>EJ{%g) zFY?1kZ;n7tIaM)-f|i^~l?7 zP5ZLg_lF+5X<+#h#5d58P;zGWqu6|Sh+weL8CGs4IAJ+dfsx?A&BuLOS)blQ;C0=r zE(O3)8GB}({i!t?>Mn*dZQ;^Q&t3G3%!}9Mb$*%}%`MHEezMe4pQTzF{T*jpbAdRJ zO?xEA(zeo9Wwt8!5{d@G0#z!=IKSm#lAqgrphtjIAhI1Nq?%07>oX1h1eRm1PkGr4 zk@6&sY_l6YrsrBDq817HrJ!LHRs=o$_%QZo8@D=kH%GXi6bj3huN^MSJCu(MJ#tp# z_~}>?jJYi<)^*)Cs9p}EYhg2Ea+sw3Yc*q0=bVxwqbg--Wwh($;F3jt*^C4pjEmPi zvF%yRuP|gyTy61#)%^bN*kNg)wti10jd$0!A7kF<px$N(g57DN8`wdvxesBf`ToHa@<&WxJg7`8*#dA+6*3r5Cx_FR~!|dbQ$Pia)<*b({ke~p0 zfaY%kw4tl%OHB1ZmFmWON414dTLUNL?4?I?{@2vv@S@Nk z3T2+X^JucQWbA3meid7*op#>B$@_sIUE)$z7ap^pT|=Q)ZZCOZ734bnO>y6DkbVd) zb5S~jV#C?uU=2zx9V|4eZ<_@_+dl+GyMM7fiE9ziCq1>q+0PNUYMv)r;aRuSX~p$e zgEm#AjJJ?7eWicyacSZLAy4&;!)O979n8m?6&ZEZceV!2Gc)DsYy;;vf*kMULN&CE zCEYXDN?}hm$syg3PY+)-PyY4jiI)D1N9sfO9$M$o+DebAM0-vlBdXM4-m7Ta&Ent~ zU1Vx;u2|HkP4XB@%f#~GgC(~W+(d1T9r`jA(z+gh0+$o0Sk(Wm298C_EM)Y4iFcm6 zxVpv?fse}u6h`J*k0pEUFM#SF%GXzHy`Njh)Nm*i5LI=(kS${8ir`@pwkfUR)S^2w zW?BugtkUiBKO0T7SwK2O8(zy~oted&8On>~nW(0+m303bG9 z5htP~^A5KU)50g?U6&J7&ioG&P#)m^u=HV;OLp(225V)vm~l+ z0-9JJ@S($Rmur91>cZ(9dmlGW-cy^Xfn-NL zvoA)|?Se)BbCnyKNtLv&OEkEsw|7P5@QwD`v;fV5K!Xt6-~f8zGxAbW>IRUK*0!b? zbYe4Wbz6gaevvacc%4mo0QBX#<+lAgh19rn9yxp)h`^jv&igi^+J00*cLc0s6Zy?# zK0|c%%;M9Dr)r4+j6>S4DbRA}4Q+=?IaxDJP9ZUW=w8Ao9-Z)z#l|pJJFtquU+@7* z2*vhI)5~TulY>8W@LN zT)J)lGR7kRUh>99ph48DQ8eU#bX12c9nEZQZ_@oj*w(E9ts##+`jdgFDKTDN_22p6 zqZdVRaEK8zx>Y+EqC;{XKNTM!@UL@pevCXZ`8Mq)k;m616In2S%=LK-AQim%o0cKhps`BZhKEVhE{nT^7vqBAv zf$d5F$_IAp%zrXHwLe$^yeDaJBghf~^C|)w2cUP$gb$ z;)uKpXnNJn{E_Frud>8ER$C>$tiuBEL5}4K9zjN6nKzewGFfwc?s$Ugx#k}H*6_h< z2R3f#OYZB9uyz)*C$?wFG<)eC8l=ZIfizc<^)bF0O>VMASB{?3?AcnC-ktF@b_x^? z-l9%PP?HI`GC+yWZ73-5K0Ve&kV>bKhI{XNz-d5g(gN_vb5kn|3vPfNcc>+MAG@Kg zW>h(;uU;+K6c2Q1a`rs|qBAuutT@ALt{K|@PwVSrT=${i$r#I;mic%9v;))ojYGj<>mM@HY$_Uc|BSq*Hh`=Fns^1?d z1gBws5fP5eo$YO#@lWe=M*FH@4&dg6W;1~@a3O-V)m2f)xsDCkCla1iu&&0b_+SI( z+fW(K&4VM$9kYC8#-1DBTWtc@Aehk-`Rc!3VMl_O+rL;Z)h}zYr!GIY8Q4NhgcnrO zEE6LSIZwl!5(&ljTd!V9Jj{M2dsYWANy5ys)q&Hx#Nxa#BgBi>#qFoq>FdnYMJ6sm z*HD^8$m*Z(_>(OA7UbUSUjG)^pbhEPDS&4Jv8V`x2Lwp5+Oq-~@{h}>Fu|?{)BIkR zhV3Ew4?NEF=9^*T9`FY};~92xCN%AF+JcEC_k=T=_Xl0IFa(f`R~B`?Lk&@=>-XPP zOw7zNWxrr|4ZxK_bYb+Y3xY}YG`;=Dy<0V97g5wfa!2wuql*C?3agtkz>nJZ-WGEF zvRK}KIk3~<)~&>bWs?vVY9a|hfo%v07|P5PH0JRi+g6H!R) z%=-Dwk-X~M_us5xB+DVWy9#Lc=4pa^+Uh3?tZH#9*Aj&DKMG#vuZYz-#R7o>8p-N^ z=aE=g!y{{-Srvbyzii-edS>|1W_C5ky?M7}vl;2N|E)O^cNTRf)Y7nR=XXSxFtO%*{A9 zjGv>T;1F*TsUq&Q-;(>!P4c36jiLK3OemI%r$E=Y#A6V#Wvd~0$=v1F1q@MVQ4Ucv zmqbvg=zHY=H>_Ch0xG~ko07Fu7uQs_D14<<#n%-lVYKM0k(?r zX+%Cl37_!^rt0!Xm#@{Ilyz19U%23Z=n0Et)2GHTbmpzhF|tg@w(PW2W@=O<0RrfV z<023XK7!Rrvpx<}l|I>-X5isrm0iGoevoHFb}EoLhq})9UJPYH2|$k>rz|U-$1#fn zYsO}lm=~JwwT+F<{=R^V&V(?^CkH_q#a$2>gc|`j!&KXZ=%STXdg%LOZJhfG*22XO z#mtU3-wxy#eP%Ce}>#gsp<->sC%*fiF+R1}hw`02Aw zjdqazcKc*a+eIMn-u4raTTR*uJD^XqL~@NOzbXg(84+ zQP)owX=`^yc>mL&srLj-2>hf5!s&@K#N{76`w}QbgB>Mk+r}tk&4JOhsYpRTs{y z(}?O?W~fvQN*`5g-s>-MR_L~jk8j5~RO%}p?Ge_oZC@}NKj!=sTBtkGtm<;ow4(yp zGN0eNJqpFx6dsMk4EaHUqkUhDoxxDP%@q`fRmO%tXJ>4lF#+Ooxd6ivdPrBe+>^e> zD)%Q?sq0j<@1wqd|Cr0iVQ>$6M2|5As`XMg?HSa42##P>2;XHTZ?cj7Kou6NxVD{)KtEb9L0u%SkPJp}gl$z?HMF<1E?x;VK83ss4<`Wi`c5 zkLLDAhrrlqJ%Py zzf>HN>nw&=UKS1PWXOCp(Eqnk%DK;?DS(#$_R8eUg76SRF@#Wj5viUDIa{T_{Ul+A zZ0){g(iKGarNH@21=jk%CZB%pv#F@0*1)B65W&zxQ8Qq?0bdPE z3Plp#udyE=-84_I3K;I%@{ZTsHQs)-|L5t<5lQLZxb>xk1eJt>B@5Bp32}SB+alXE z%+;udjwJD#bJYHmnQv*kp%eD9ymY02@LMXDTE}av@e1fc=2SYm+0*1{J^c=;p9#M0i*jS;xrt z?-Hz6XlQgd1+I#?MyggpsmDg6tB4nf?!Xn2iU7QVZ-ZxP{Bgcq346ica9LpI>-H?i zJzly-^Bn+oAar&fRX$*m5a#<<@JU!#z}>(Y8al;Ln!MsG<;7;dhN z(28N#mcD5ILXLv{`GmA9`FAu0@?VzW*oFpFH)*t_9Ym%IRMl;%DRf;oE!P)K8Y;;> zLJh$a)TKOr)HrpcpqN_kkBtehlUd``tjjLTV}cf@#ggZD3Ml?*@TT0Cs&g*8HLG^c zV|q9Zb+N_f=SAa7N9v$$s;81+H3n|2p z9}m5~Pap#9bYvpIlW6Ve=t!%7=I&ng>BhB#;g&`vfIdkiUS7S!7Hjr2Px15$q_(6Q}heBDv-a2ds*TnD#8vQp)fvq1{)^2`1aJ zNw%$@)*N6?g>fo^+7?{^W`MqDSDt2?AciFILCfR&#$+rTq#6*sFNi*4e9bO`jTJaU zqSGI@`36Y)vtG3YzthH2iQ9opmA?CqeY<0?6}C1CXZS}9^xgwC}oy)>I>Hf?{eZ@r3`aDu<-TV-+^)2jva`ZQ=U zPhrZC?qSc>`=9onNZe6H^SMA8&OLsW!igd+V=PnC8huHOl(hySUU4lW}kBZIGLC z^Dt>X4>#g0ly97pVwLMuNUU^{i2g_cl0L&{mc~*6j$LltciyV;Tuf2`s$L9~soBkX0M>LbOR8J1njBs+rR9~0gPg9ruenkby^#g78r{*wrQ6SDkqMCL z6~l~z5+<|DKQB$DFK5EGI^FF7cotMJJT)H(W z7$3;flU)KjV!@xs#ape~Z4NUgU<YoKRSf6JTobIGS9ul2Ma=N*IvZrCIrh(ygY z>Hk{r{VMc%N1Ag|X0TWqDucbPOA$GDQXP zIktwi*m#K7p9MdZs1trFbz~=J5wjR7=55?bQX02MwZ{N>uyHA87c`f!D_|c z;?SwtoeA}egqk@AHcidF?vq0$L{5IV+ahLoG<6l0uf)3&_t|(1>v!nb>3*#cO2a(mEW zQ11vS=$Zh0F5;ef@*r5oWU0Ra^>XifDRso+Pz&8dW5yfJu??{{YO!6c=^^xTO58RF zhn&ByRxRlCJOWC$)S}M%4BWdTM*)lU!ce$o9NcM zizJm+GfsgBro`NLEsb>k%v^L`-ztb%LC84grSUFaH7;1wh&f&MdHa>QIz^x`?w(xF zpgW=i2*36uWHe+z!4lH$GOk0sbzSw65)0WsU-~gJFHOqEiP4rp~wzE0W_9>Ie+;Qvuu)(E?1ucgOR!OOir`FRyBthM^G_ z8shyMs!*=+F0 zfPiHgAJac_{&tF9aeFXfN0O|cCpzWed|>BKXMgm5f`+=ajj-o~urC#K4qAroH0MSh zbK)#SfRv*>e9Chcd;XV5v@ zm*`0A=$3e#&~U;$G$q%e|LT^%is(iTsk7>7JYl5h;bXe*e2S7<45;v7szBbgR;jXS ztW}jq{ht_8g`D;i+lGv}ENh0?(R%2II44KPzM=Z!_C*(sd!UtWSQZ|l;8X(CoZnfQ4K;u1=cPXoWPWJ7s z{~KA&Hq&_wvp!eKCD&2Fx_g&;^tnE;bTOIPog;`YCA_4Oa9iy7;C^cR%I}*Zk!c~s z<5DL&%0dg{{Qzfj89u-K0%X@$&3aaTJAbqh5j%b!C#S2!_c%Y1mm33K?S)X7AKojcTMi92qy&%@T5zt+O2m2caymFZvrG%$n!yue^$vvIeJ4V4?`iud$SeM9~x=h~&CmXgm;m@xK2(DbkQ=@8E ztyz3B*X*m%J9{yTE(HYH;|K^meBVqILR0>x502JOe`-l?TsXy;4Wesd#pB}B3!fqI zts+vyCB9>ql(wW||LVegmF$tY={ln-uj8~9~nW&>9Ch$<Ngxp&0F|E0rq|>cNx*aWHyHP@?bA|bSUAS%mwcmcT(HG+=G~02 zO5`V`lQcM{WpuoDxd|A@w2doH)oKdC{Y{Y-Uo!=Z4>%*+vp&3*jcw4rb2+~NXl;^i zbEYRZ2X%Nqya!aU;%k=Uio=XA$#aMQ8+abD{%JvtT{)k*9#lEmx&^VycZ!-fDmPxs zy%n;_^GO#H$9@fvOb`o*_8vY=O{>2VCtonv0>C8{v*OXg&b|iK(wyBPGC{9#3ivHw zBa>LCLMOPb;SlWq*d2+0YGJLywjS?6RgifDDJyL0eD8gFd+h+VoxSK(kOuffedQ|Au-4qdhfSr$5`(f3f1 zX8~N@ZPTigzy+KXHm7)a; z#==Vx;9v*NvPFn_F89RzWuke7vJ{t?oYMePRj`y<`(iS6E6*WB$1hUeMmLO0Rrx#q z!Q4%8STouLC{Bf4I?Lmgr4SS?k4V2DoyMsMFk*)ro#~Ug2 zs}6?VN6zWOnkvvC;Xl!5jUs58Dz*Mn=(p?>KBLTVB?n^`UkV4HV=s(NvW_oFV~nc=LQ1 zbGOc@aC?y0xbX&3UBEQ?qaLK)c3rRI?1AoNFPhKcsq$~Ys*UZwLX3UFr;Ub=#g-K- zg==nGnXVYBb56#rtMG%3z@v<@f=@QTryM3s-cps{@6(Wev;FpVSRZ40dp;tHT;oGU zV;`A4_ys1(kpDomHu?P29~pMZxar;$(()6K{5iRswIAdCy_fW+pk0(0Nx-!m_Lut% zTdRV#$o#A)1lef}dr7yS(QJeU13{18IXK?zQwn9ic(QGK;^OSRv}NwzwS-@-XJh-b zA|#=LzlpUV6I2HbNt5{jW7B$5`yXoFl6PYT%f9U@TiDEyUgRrZ^-Hk5BrwG>NhwVp zWl?D(LnjwiM0n}TDF!UHgKA%l#lC>3O2fjaxEnGBO{1!t$bN2oaO_;de{Nu`0QxRI zv8Ke>+F{o>jWE*uJ5y|e^9NRbhYmDUdabsxuID@1Snwx2bvW;tT+XD0G>)}jsfVc8 zZGk&)1sOo;EDj;rj7HY2>ey>In^OLsw2iA=!(`;FoIDCzo#|qQh|DwqD8oZ_u9Sig zy|j|KR2rjjkIWU69z)pyR6_dyz~2sw*&Q;c)ehw|9{a}-c zXZg)a9Mhn7fSJ}wh>~MW-DMI>L*w7a=l@1 z81Q#|e=b)MDbLa2^T*y-6}Sddf=xP$B7YMg?w4Z9KZkIweOLh z=jYq0%iQRNUa6Vg>%6k<@B5r9CAm{^Q0@f@>Mg+*MqbAMQe7By3e=pr0~Y?~NET zoNO7LIKw-SN`!CUhB)rH)7Go>yD2M;ofSKXYo$ro^d|7N8zmhcUBpRyl|y)mM3k05dfZB!8p-T_E!Eg?rm`8a^ER;8J&Njh7R+BA&+A;6lcXAwQ2_;)}F zJ0TRrLd~ZC4K==e?vnN7`{a}E-q-aXt6+mj4S&ETQA7xcPK+RpWU?&p!qBqWyCLXh zYLqw^h)-|A10EM~;us8~Js&<6>8kCQvy`mt-Z^N?1 z;VxXo|7d5Ofe-jxCWtX{HR&pRDU-JppAil+O#bmHY*ggc|B(L1N*43~Fe5}=OHS}V zx<{Wcg2Ikm_!C1{3+?C6qrRQO+yCMJMZ7SL8c!RN0mE?wSAGBDznVxgo@OS)-B(2a zD2fI#JF2pr)>lyCWh!KU-l0YQq(28#U%VD{wTVmmeV;NH_e8vp*Qd-dyjgN?KZ=#^ z2yZ73tT6aRuDujd@3M*#J5ZP%JEJU>2pYpK=gwh?t&_b*JrJ`lrl+_s%PLsCd-B*O z|GZT>irs#tSg-F>fxQ6+Q8uTWu4z^ZwU7QT9?+U1taEDsU9CFNA4I>Z`zhv&&~(}q zhuSafXTm5B>B5V~DiW*<`;vkQ->Sz2-LNBRZuqIm;%0@ZDzik)Ihut|8ebP{h9$+O#5uf*osSa5<0+82$f^? zj@FeE{^lU0q2XAWh}2dMTk(S*j+3x8f5L=K)=U)zit+mPg{lJBI4;KmwsBitPE1bT zJ~)DO-dXUnOSQrBjUqFYPe5QRFggA6XPSq1>UQoZ^pQy!hXvD6bOm5>v``!Z>ywn6 zoEg13RX;T>fzSa^(yAz~iiLWAD&nr`XyTAk;ZV=IA-1+6Sg41mT|3hW|Lb><05##uYDuFBWb97EE*PH(Q+5{_8EIiv zZz>C{m#OX4@KKDXG+ICMrswIK9e1!(hveX4?{|Z;n-WF~UqK?-`GSX7k4(c9SRKW-xmKr;Z z9Yph1@Gl5@gh)?gCG7{*1C;W=FWT?|Kx&_m3beCi2ZaX;LeH=89yJv>FHNvhlhFKrqbV^L;X3G zI{(MG zVxT*F)nB`E4uvSCq0P1876=nBWB1coy+M(rMTba~qaz7Sm!D4^B)eIeT)>?9=eMO1 zev$IDFA&P-v4j*XMXO4ISqkwM$MUs*+VwNN9ovP6bja=Tns)y_+~{V0{XljBc222i$Zy6IN`N;;DJL`kLD>V$*J@3c^M{^~et<_*21n$U7xy z802ri{EDxv$fc zN0A;!#&fN(le8GF=)?b+qA6f?Q5Idkh!W?Y7yEbE{N4B5tY)+f-Js|K&5!0Qt_nx} zQ;t&8Chz^@BUNf;)efn(hpgs(d{+YK8yZ4 zVVzC^KnkG5@rFVF-@$VJF%Bw{T0n>Q=!N5BA6;d;hJcHt@MsuMt9O>eu%UbtUIGD0 ziF8}kUz^~V4M#sQ(o}yRsmTwoyZrkioB4F4pS~2ogLII8jztjN{QGZZrPD7ved*(l i+|EBoKk5H|?cqt2e5*93yEqeh`+=0AWP!xPzy2TWFi6V) literal 0 HcmV?d00001 From e63ddf42875abf2659d999b91e840b7368222978 Mon Sep 17 00:00:00 2001 From: Jiajun Li Date: Wed, 17 Sep 2025 12:22:29 +0000 Subject: [PATCH 2/4] delete search r1 --- examples/search-r1/README.md | 75 -------- examples/search-r1/README_zh.md | 75 -------- examples/search-r1/generate_with_search.py | 169 ----------------- examples/search-r1/google_search_server.py | 150 --------------- examples/search-r1/qa_em_format.py | 208 --------------------- examples/search-r1/run_qwen2.5_3B.sh | 138 -------------- 6 files changed, 815 deletions(-) delete mode 100644 examples/search-r1/README.md delete mode 100644 examples/search-r1/README_zh.md delete mode 100644 examples/search-r1/generate_with_search.py delete mode 100644 examples/search-r1/google_search_server.py delete mode 100644 examples/search-r1/qa_em_format.py delete mode 100644 examples/search-r1/run_qwen2.5_3B.sh diff --git a/examples/search-r1/README.md b/examples/search-r1/README.md deleted file mode 100644 index 53f21a7..0000000 --- a/examples/search-r1/README.md +++ /dev/null @@ -1,75 +0,0 @@ -# Example: Search-R1 lite - -[中文版](./README_zh.md) - -This is a minimal reproduction of [Search-R1](https://github.com/PeterGriffinJin/Search-R1) and an example of using multi-turn conversation and tool-calling in slime. - -## Environment Setup - -Use the `zhuzilin/slime:latest` image and initialize the environment required for Search-R1: - -```bash -cd /root/ -git clone https://github.com/THUDM/slime.git -pip install -e . -# for Search R1 -pip install chardet -``` - -Please refer to the script provided in Search-R1 to download the data: - -```bash -git clone https://github.com/PeterGriffinJin/Search-R1.git -cd Search-R1/ -python scripts/data_process/nq_search.py --local_dir /root/nq_search/ -``` - -Initialize the Qwen2.5-3B model: - -```bash -# hf checkpoint -huggingface-cli download Qwen/Qwen2.5-3B --local-dir /root/Qwen2.5-3B - -# mcore checkpoint -cd /root/slime -PYTHONPATH=/root/Megatron-LM python tools/convert_hf_to_torch_dist.py \ - --hf-checkpoint /root/Qwen2.5-3B \ - --save /root/Qwen2.5-3B_torch_dist -``` - -## Running the Script - -You need to configure your serper.dev API in `generate_with_search.py`: - -```python -SEARCH_R1_CONFIGS = { - "max_turns": 3, - "topk": 3, - "google_api_key": "YOUR_API_KEY", # Replace with your actual API key - "snippet_only": True, # Set to True to only return snippets - "proxy": None, # Set to your proxy if needed - "search_concurrency": 256, - # rm - "format_score": 0.2, -} -``` - -And run: - -```bash -cd slime/ -bash examples/search-r1/run_qwen2.5_3B.sh -``` - -## Code Structure - -To implement multi-turn conversation + tool-calling in slime, you only need to implement a custom data generation function and a reward model for the task. These correspond to the following 2 configuration items in the startup script: - -```bash -CUSTOM_ARGS=( - --custom-generate-function-path generate_with_search.generate - --custom-rm-path generate_with_search.reward_func -) -``` - -These are the `generate` and `reward_func` functions in `generate_with_search.py`. diff --git a/examples/search-r1/README_zh.md b/examples/search-r1/README_zh.md deleted file mode 100644 index cbf13b5..0000000 --- a/examples/search-r1/README_zh.md +++ /dev/null @@ -1,75 +0,0 @@ -# 示例:Search-R1 lite - -[English](./README.md) - -这里是一个对 [Search-R1](https://github.com/PeterGriffinJin/Search-R1) 的简单复现,以及是一个在 slime 中使用多轮对话和工具调用的样例。 - -## 配置环境 - -使用 `zhuzilin/slime:latest` 镜像,并初始化 Search-R1 需要的环境: - -```bash -cd /root/ -git clone https://github.com/THUDM/slime.git -pip install -e . -# for Search R1 -pip install chardet -``` - -请参照 Search-R1 中提供的脚本下载数据: - -```bash -git clone https://github.com/PeterGriffinJin/Search-R1.git -cd Search-R1/ -python scripts/data_process/nq_search.py --local_dir /root/nq_search/ -``` - -初始化 Qwen2.5-3B 模型: - -```bash -# hf checkpoint -huggingface-cli download Qwen/Qwen2.5-3B --local-dir /root/Qwen2.5-3B - -# mcore checkpoint -cd /root/slime -PYTHONPATH=/root/Megatron-LM python tools/convert_hf_to_torch_dist.py \ - --hf-checkpoint /root/Qwen2.5-3B \ - --save /root/Qwen2.5-3B_torch_dist -``` - -## 运行脚本 - -需要将你的 serper.dev API 配置在 `generate_with_search.py` 中: - -```python -SEARCH_R1_CONFIGS = { - "max_turns": 3, - "topk": 3, - "google_api_key": "YOUR_API_KEY", # Replace with your actual API key - "snippet_only": True, # Set to True to only return snippets - "proxy": None, # Set to your proxy if needed - "search_concurrency": 256, - # rm - "format_score": 0.2, -} -``` - -并运行: - -```bash -cd slime/ -bash examples/search-r1/run_qwen2.5_3B.sh -``` - -## 代码结构 - -为了实现多轮 + 工具调用,在 slime 中只需要实现一个自定义的数据生成函数,以及一个任务所需的 reward model,对应启动脚本中的这 2 个配置项: - -```bash -CUSTOM_ARGS=( - --custom-generate-function-path generate_with_search.generate - --custom-rm-path generate_with_search.reward_func -) -``` - -也就是 `generate_with_search.py` 中的 `generate` 和 `reward_func` 两个函数。 diff --git a/examples/search-r1/generate_with_search.py b/examples/search-r1/generate_with_search.py deleted file mode 100644 index bbe9760..0000000 --- a/examples/search-r1/generate_with_search.py +++ /dev/null @@ -1,169 +0,0 @@ -# Adapted form https://github.com/PeterGriffinJin/Search-R1/blob/ceee7b89655ed52f205b9beb98e1190c3eedcfb0/search_r1/llm_agent/generation.py -import asyncio -import re - -from google_search_server import google_search -from qa_em_format import compute_score_em - -from slime.rollout.sglang_example import GenerateState -from slime.utils.http_utils import post -from slime.utils.types import Sample - -SEARCH_R1_CONFIGS = { - "max_turns": 3, - "topk": 3, - "google_api_key": "YOUR_API_KEY", # Replace with your actual API key - "snippet_only": True, # Set to True to only return snippets - "proxy": None, # Set to your proxy if needed - "search_concurrency": 256, - # rm - "format_score": 0.2, -} - - -SEMAPHORE = asyncio.Semaphore(SEARCH_R1_CONFIGS["search_concurrency"]) - - -def _passages2string(retrieval_result): - format_reference = "" - for idx, doc_item in enumerate(retrieval_result): - - content = doc_item["document"]["contents"] - title = content.split("\n")[0] - text = "\n".join(content.split("\n")[1:]) - format_reference += f"Doc {idx+1}(Title: {title}) {text}\n" - - return format_reference - - -async def search(query: str) -> str: - result = await google_search( - SEARCH_R1_CONFIGS["google_api_key"], - query, - SEARCH_R1_CONFIGS["topk"], - snippet_only=SEARCH_R1_CONFIGS["snippet_only"], - proxy=SEARCH_R1_CONFIGS["proxy"], - ) - return _passages2string(result) - - -def postprocess_responses(resp: str) -> str: - return ( - resp.split("")[0] + "" - if "" in resp - else resp.split("")[0] + "" if "" in resp else resp - ) - - -def postprocess_predictions(prediction: str): - pattern = r"<(search|answer)>(.*?)" - match = re.search(pattern, prediction, re.DOTALL) - if match: - content = match.group(2).strip() # Return only the content inside the tags - action = match.group(1) - else: - content = "" - action = None - - return action, content - - -async def execute_predictions(prediction: str) -> str: - action, content = postprocess_predictions(prediction) - - if action == "search": - search_query = content - async with SEMAPHORE: - search_results = await search(search_query) - next_obs = f"\n\n{search_results.strip()}\n\n" - done = False - elif action == "answer": - next_obs = "" - done = True - else: - next_obs = f"\nMy previous action is invalid. \ -If I want to search, I should put the query between and . \ -If I want to give the final answer, I should put the answer between and . Let me try again.\n" - done = False - - return next_obs, done - - -async def generate(args, sample: Sample, sampling_params) -> Sample: - assert not args.partial_rollout, f"Partial rollout is not supported for this function at the moment." - - state = GenerateState(args) - - url = f"http://{args.sglang_router_ip}:{args.sglang_router_port}/generate" - - # Handle partial rollout samples: continue generation from existing response - prompt = sample.prompt - prompt_tokens_ids = state.tokenizer(sample.prompt, add_special_tokens=False)["input_ids"] - response = "" - response_token_ids = [] - loss_masks = [] - for _ in range(SEARCH_R1_CONFIGS["max_turns"]): - payload = { - "text": prompt + response, - "sampling_params": sampling_params, - } - output = await post(url, payload, use_http2=args.use_http2) - - # abort - if output["meta_info"]["finish_reason"]["type"] == "abort": - sample.status = Sample.Status.ABORTED - return sample - - cur_response = output["text"] - cur_response = postprocess_responses(cur_response) - - cur_response_token_ids = state.tokenizer(cur_response, add_special_tokens=False)["input_ids"] - response += cur_response - response_token_ids += cur_response_token_ids - loss_masks += [1] * len(cur_response_token_ids) - - if output["meta_info"]["finish_reason"]["type"] == "length": - break - - next_obs, done = await execute_predictions(cur_response) - if done: - break - - assert next_obs != "", "Next observation should not be empty." - obs_tokens_ids = state.tokenizer(next_obs, add_special_tokens=False)["input_ids"] - response += next_obs - response_token_ids += obs_tokens_ids - loss_masks += [0] * len(obs_tokens_ids) - - sample.tokens = prompt_tokens_ids + response_token_ids - sample.response_length = len(response_token_ids) - sample.response = response - sample.loss_masks = loss_masks - match output["meta_info"]["finish_reason"]["type"]: - case "length": - sample.status = Sample.Status.TRUNCATED - case "abort": - sample.status = Sample.Status.ABORTED - case "stop": - sample.status = Sample.Status.COMPLETED - - return sample - - -async def reward_func(args, sample, **kwargs): - """The reward function for retrieval-based question answering. - - Args: - args: the arguments - sample: the sample to evaluate - """ - if not isinstance(sample, Sample): - raise TypeError("Sample must be an instance of Sample class.") - - score = compute_score_em( - solution_str=sample.prompt + sample.response, - ground_truth=sample.label["ground_truth"], - format_score=SEARCH_R1_CONFIGS["format_score"], - ) - - return score diff --git a/examples/search-r1/google_search_server.py b/examples/search-r1/google_search_server.py deleted file mode 100644 index 6f19356..0000000 --- a/examples/search-r1/google_search_server.py +++ /dev/null @@ -1,150 +0,0 @@ -import asyncio -import os -import random -import re -from typing import Dict, List - -import aiohttp -import chardet - - -# --- Utilities --- -def parse_snippet(snippet: str) -> List[str]: - segments = snippet.split("...") - return [s.strip() for s in segments if len(s.strip().split()) > 5] - - -def sanitize_search_query(query: str) -> str: - # Remove or replace special characters that might cause issues. - # This is a basic example; you might need to add more characters or patterns. - sanitized_query = re.sub(r"[^\w\s]", " ", query) # Replace non-alphanumeric and non-whitespace with spaces. - sanitized_query = re.sub( - r"[\t\r\f\v\n]", " ", sanitized_query - ) # replace tab, return, formfeed, vertical tab with spaces. - sanitized_query = re.sub( - r"\s+", " ", sanitized_query - ).strip() # remove duplicate spaces, and trailing/leading spaces. - - return sanitized_query - - -def filter_links(search_results: List[Dict]) -> List[str]: - links = [] - for result in search_results: - for item in result.get("items", []): - if "mime" in item: - continue - ext = os.path.splitext(item["link"])[1] - if ext in ["", ".html", ".htm", ".shtml"]: - links.append(item["link"]) - return links - - -async def fetch(session: aiohttp.ClientSession, url: str, semaphore: asyncio.Semaphore) -> str: - if url == "": - return "" - user_agents = [ - "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5X Build/MMB29P)...", - "Mozilla/5.0 AppleWebKit/537.36...", - "Mozilla/5.0 (compatible; Googlebot/2.1; +https://www.google.com/bot.html)", - ] - headers = {"User-Agent": random.choice(user_agents)} - - async with semaphore: - try: - async with session.get(url, headers=headers) as response: - raw = await response.read() - detected = chardet.detect(raw) - encoding = detected["encoding"] or "utf-8" - return raw.decode(encoding, errors="ignore") - except (aiohttp.ClientError, asyncio.TimeoutError): - return "" - - -async def fetch_all(urls: List[str], limit: int = 8) -> List[str]: - semaphore = asyncio.Semaphore(limit) - timeout = aiohttp.ClientTimeout(total=5) - connector = aiohttp.TCPConnector(limit_per_host=limit, force_close=True) - - async with aiohttp.ClientSession(timeout=timeout, connector=connector) as session: - tasks = [fetch(session, url, semaphore) for url in urls] - return await asyncio.gather(*tasks) - - -def collect_context(snippet: str, doc: str) -> str: - snippets = parse_snippet(snippet) - ctx_paras = [] - - for s in snippets: - pos = doc.replace("\n", " ").find(s) - if pos == -1: - continue - sta = pos - while sta > 0 and doc[sta] != "\n": - sta -= 1 - end = pos + len(s) - while end < len(doc) and doc[end] != "\n": - end += 1 - para = doc[sta:end].strip() - if para not in ctx_paras: - ctx_paras.append(para) - - return "\n".join(ctx_paras) - - -async def google_search(api_key, query, top_k=5, timeout: int = 60, proxy=None, snippet_only=False) -> List[Dict]: - timeout_obj = aiohttp.ClientTimeout(total=timeout) - session_kwargs = {} - if proxy: - session_kwargs["proxy"] = proxy - async with aiohttp.ClientSession(**session_kwargs) as session: - async with session.post( - "https://google.serper.dev/search", - json={ - "q": query, - "num": top_k, - "gl": "us", - "hl": "en", - }, - headers={ - "Content-Type": "application/json", - "X-API-KEY": api_key, - }, - timeout=timeout_obj, - ) as resp: - resp.raise_for_status() - response = await resp.json() - items = response.get("organic", []) - - contexts = [] - if snippet_only: - for item in items: - title = item.get("title", "") - context = " ".join(parse_snippet(item.get("snippet", ""))) - if title != "" or context != "": - title = "No title." if not title else title - context = "No snippet available." if not context else context - contexts.append( - { - "document": {"contents": f'"{title}"\n{context}'}, - } - ) - else: - links = [item.get("link", "") for item in items if "link" in item] - web_contents = await fetch_all(links) - contexts = [] - for i, item in enumerate(items): - title = item.get("title", "") - snippet = item.get("snippet", "") - - context = collect_context(snippet, web_contents[i]) - if title != "" or context != "": - title = "No title." if not title else title - context = "No snippet available." if not context else context - contexts.append( - { - "document": {"contents": f'"{title}"\n{context}'}, - } - ) - - return contexts diff --git a/examples/search-r1/qa_em_format.py b/examples/search-r1/qa_em_format.py deleted file mode 100644 index 7820168..0000000 --- a/examples/search-r1/qa_em_format.py +++ /dev/null @@ -1,208 +0,0 @@ -# Adapt from https://github.com/PeterGriffinJin/Search-R1/blob/ceee7b89655ed52f205b9beb98e1190c3eedcfb0/verl/utils/reward_score/qa_em_format.py -# Copyright 2024 Bytedance Ltd. and/or its affiliates -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import random -import re -import string - - -def normalize_answer(s): - def remove_articles(text): - return re.sub(r"\b(a|an|the)\b", " ", text) - - def white_space_fix(text): - return " ".join(text.split()) - - def remove_punc(text): - exclude = set(string.punctuation) - return "".join(ch for ch in text if ch not in exclude) - - def lower(text): - return text.lower() - - return white_space_fix(remove_articles(remove_punc(lower(s)))) - - -def em_check(prediction, golden_answers): - if isinstance(golden_answers, str): - golden_answers = [golden_answers] - normalized_prediction = normalize_answer(prediction) - score = 0 - for golden_answer in golden_answers: - golden_answer = normalize_answer(golden_answer) - if golden_answer == normalized_prediction: - score = 1 - break - return score - - -def is_valid_sequence(text): - # Find the position of "<|im_start|>assistant" with potential whitespace - assistant_pattern = r"<\|im_start\|>assistant\s*" - assistant_match = re.search(assistant_pattern, text) - - if not assistant_match: - return False, "Missing assistant marker" - - # Extract the content after the assistant marker - start_pos = assistant_match.end() - content = text[start_pos:] - - # Check for balanced tags - tags_to_check = ["think", "search", "information", "answer"] - for tag in tags_to_check: - opening_count = len(re.findall(f"<{tag}>", content)) - closing_count = len(re.findall(f"", content)) - if opening_count != closing_count: - return False, f"Mismatch in {tag} tags: {opening_count} opening vs {closing_count} closing tags" - - # Now check for proper sequence pattern and no extraneous content - - # 1. First split the content by any tags we recognize - split_pattern = r"()" - parts = re.split(split_pattern, content) - - # 2. Keep track of the current position in the expected sequence - state = "start" # start -> think -> search -> information -> think -> ... -> answer -> end - - # 3. Check each part - for i, part in enumerate(parts): - # Skip empty parts - if not part.strip(): - continue - - # Check if this is a tag - if re.match(r"", part): - # This is a tag, check if it's valid in the current state - if part == "" and state in ["start", "information"]: - state = "in_think" - elif part == "" and state == "in_think": - state = "after_think" - elif part == "" and state == "after_think": - state = "in_search" - elif part == "" and state == "in_search": - state = "after_search" - elif part == "" and state == "after_search": - state = "in_information" - elif part == "" and state == "in_information": - state = "information" - elif part == "" and state == "after_think": - state = "in_answer" - elif part == "" and state == "in_answer": - state = "end" - else: - return False, f"Unexpected tag {part} in state {state}" - else: - # This is content, check if it's valid in the current state - if state in ["in_think", "in_search", "in_information", "in_answer"]: - # Content is allowed inside tags - pass - elif state in ["start", "after_think", "after_search", "information"]: - # Only whitespace is allowed between tags - if part.strip(): - return False, f"Unexpected content '{part.strip()}' between tags (state: {state})" - else: - return False, f"Unexpected content in state {state}" - - # Check final state - if state != "end": - return False, f"Incomplete sequence, ended in state {state}" - - return True, "Valid sequence format" - - -def extract_solution(solution_str): - """Extract the equation from the solution string.""" - - answer_pattern = r"(.*?)" - match = re.finditer(answer_pattern, solution_str, re.DOTALL) - matches = list(match) - - # If there are 0 or exactly 1 matches, return None - if len(matches) <= 1: - return None - - # If there are 2 or more matches, return the last one - return matches[-1].group(1).strip() - - -def extract_information_blocks(text: str) -> list[str]: - pattern = r"(.*?)" - matches = re.findall(pattern, text, re.DOTALL) - return [match.strip() for match in matches] - - -def is_retrieval_correct(text: str, golden_answers: list[str]) -> list[str]: - seqs = extract_information_blocks(text) - for seq in seqs: - for golden_answer in golden_answers: - if normalize_answer(golden_answer) in normalize_answer(seq): - return True - return False - - -def compute_score_em( - solution_str, - ground_truth, - method="strict", - structure_format_score=0, - final_format_score=0, - retrieval_score=0, - format_score=0, - score=1.0, -): - """The scoring function for exact match (EM). - - Args: - solution_str: the solution text - ground_truth: the ground truth - method: the method to extract the solution, choices are 'strict' and 'flexible' - format_score: the score for the format - score: the score for the correct answer - """ - is_valid_format, _ = is_valid_sequence(solution_str) - retrieval_correct = False - if is_valid_format: - retrieval_correct = is_retrieval_correct(solution_str, ground_truth["target"]) - answer = extract_solution(solution_str=solution_str) - do_print = random.randint(1, 64) == 1 - - if do_print: - print(f"--------------------------------") - print(f"Golden answers: {ground_truth['target']}") - print(f"Extracted answer: {answer}") - print(f"Solution string: {solution_str}") - - if answer is None: - if is_valid_format: - if retrieval_correct: - return structure_format_score + retrieval_score # 0.3 - else: - return structure_format_score # 0.2 - else: - return 0 - else: - if em_check(answer, ground_truth["target"]): - if is_valid_format: - return score # 1 - else: - return score - structure_format_score # 0.8 - elif is_valid_format: - if retrieval_correct: - return structure_format_score + retrieval_score # 0.3 - else: - return structure_format_score # 0.2 - else: - return final_format_score # 0.1 diff --git a/examples/search-r1/run_qwen2.5_3B.sh b/examples/search-r1/run_qwen2.5_3B.sh deleted file mode 100644 index 4161f07..0000000 --- a/examples/search-r1/run_qwen2.5_3B.sh +++ /dev/null @@ -1,138 +0,0 @@ -#!/bin/bash - -# for rerun the task -pkill -9 sglang -sleep 3 -ray stop --force -pkill -9 ray -pkill -9 python -sleep 3 -pkill -9 ray -pkill -9 python - -set -ex - -# will prevent ray from buffering stdout/stderr -export PYTHONBUFFERED=16 - -SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)" -source "${SCRIPT_DIR}/../../scripts/models/qwen2.5-3B.sh" - -CKPT_ARGS=( - --hf-checkpoint /root/Qwen2.5-3B/ - --ref-load /root/Qwen2.5-3B_torch_dist/ - --load /root/Qwen2.5-3B_slime/ - --save /root/Qwen2.5-3B_slime/ - --save-interval 20 -) - -ROLLOUT_ARGS=( - --prompt-data /root/nq_search/train.parquet - --input-key prompt - --label-key reward_model - --apply-chat-template - --rollout-shuffle - --num-rollout 3000 - --rollout-batch-size 32 - --n-samples-per-prompt 8 - --rollout-max-response-len 512 - --rollout-temperature 0.8 - - --global-batch-size 256 - --balance-data -) - -PERF_ARGS=( - --tensor-model-parallel-size 2 - --sequence-parallel - --pipeline-model-parallel-size 1 - --context-parallel-size 1 - --expert-model-parallel-size 1 - --expert-tensor-parallel-size 1 - - --recompute-granularity full - --recompute-method uniform - --recompute-num-layers 1 - - # --micro-batch-size 1 - --use-dynamic-batch-size - --max-tokens-per-gpu 9216 -) - -GRPO_ARGS=( - --advantage-estimator grpo - --use-kl-loss - --kl-loss-coef 0.00 - --kl-loss-type low_var_kl - --kl-coef 0.00 - --entropy-coef 0.00 - --eps-clip 0.2 - --eps-clip-high 0.28 -) - -OPTIMIZER_ARGS=( - --optimizer adam - --lr 1e-6 - --lr-decay-style constant - --weight-decay 0.1 - --adam-beta1 0.9 - --adam-beta2 0.98 -) - -WANDB_ARGS=( - # --use-wandb - # --wandb-project slime-dev - # --wandb-group search-r1_qwen2.5-3B-test - # --wandb-key ${WANDB_KEY} -) - -SGLANG_ARGS=( - --rollout-num-gpus-per-engine 2 - --sglang-mem-fraction-static 0.7 -) - -MISC_ARGS=( - # default dropout in megatron is 0.1 - --attention-dropout 0.0 - --hidden-dropout 0.0 - # should be good for model performance - --accumulate-allreduce-grads-in-fp32 - --attention-softmax-in-fp32 - # need to comment this when using model with MLA - --attention-backend flash -) - -CUSTOM_ARGS=( - --custom-generate-function-path generate_with_search.generate - --custom-rm-path generate_with_search.reward_func -) - -# launch the master node of ray in container -export MASTER_ADDR=${MASTER_ADDR:-"127.0.0.1"} -ray start --head --node-ip-address ${MASTER_ADDR} --num-gpus 8 --disable-usage-stats - -RUNTIME_ENV_JSON="{ - \"env_vars\": { - \"PYTHONPATH\": \"/root/Megatron-LM/:${SCRIPT_DIR}\", - \"CUDA_DEVICE_MAX_CONNECTIONS\": \"1\" - } -}" - -ray job submit --address="http://127.0.0.1:8265" \ - --runtime-env-json="${RUNTIME_ENV_JSON}" \ - -- python3 train.py \ - --actor-num-nodes 1 \ - --actor-num-gpus-per-node 4 \ - --rollout-num-gpus 4 \ - --colocate \ - ${MODEL_ARGS[@]} \ - ${CKPT_ARGS[@]} \ - ${ROLLOUT_ARGS[@]} \ - ${OPTIMIZER_ARGS[@]} \ - ${GRPO_ARGS[@]} \ - ${DISTRIBUTED_ARGS[@]} \ - ${WANDB_ARGS[@]} \ - ${PERF_ARGS[@]} \ - ${SGLANG_ARGS[@]} \ - ${MISC_ARGS[@]} \ - ${CUSTOM_ARGS[@]} From 6451b49dde37825091ca9d055b2840e3ed7e7dae Mon Sep 17 00:00:00 2001 From: Jiajun Li Date: Wed, 17 Sep 2025 12:26:45 +0000 Subject: [PATCH 3/4] delete async --- docs/en/models/qwen3-4B.md | 6 - docs/zh/models/qwen3-4B.md | 8 - slime_plugins/rollout_buffer/README.md | 50 --- slime_plugins/rollout_buffer/README_zh.md | 51 --- slime_plugins/rollout_buffer/buffer.py | 343 ----------------- .../rollout_buffer/generator/__init__.py | 6 - .../generator/base_generator.py | 352 ------------------ .../rollout_buffer/rollout_buffer_example.py | 301 --------------- .../rollout_buffer/rollout_buffer_example.sh | 134 ------- train_async.py | 80 ---- 10 files changed, 1331 deletions(-) delete mode 100644 slime_plugins/rollout_buffer/README.md delete mode 100644 slime_plugins/rollout_buffer/README_zh.md delete mode 100644 slime_plugins/rollout_buffer/buffer.py delete mode 100644 slime_plugins/rollout_buffer/generator/__init__.py delete mode 100644 slime_plugins/rollout_buffer/generator/base_generator.py delete mode 100644 slime_plugins/rollout_buffer/rollout_buffer_example.py delete mode 100644 slime_plugins/rollout_buffer/rollout_buffer_example.sh delete mode 100644 train_async.py diff --git a/docs/en/models/qwen3-4B.md b/docs/en/models/qwen3-4B.md index ee7817f..e006a7e 100644 --- a/docs/en/models/qwen3-4B.md +++ b/docs/en/models/qwen3-4B.md @@ -303,9 +303,3 @@ In this case, 2 GPUs will be allocated for training, and 6 GPUs will be allocate ```bash --sglang-cuda-graph-bs 1 2 4 8 $(seq 16 8 256) ``` - -### Asynchronous Training - -When you separate training and inference, you may notice that the training and inference GPUs are always waiting for each other. To prevent these resources from being idle, we can enable asynchronous training. This can be done by changing `train.py` to `train_async.py` in the startup script. By doing this, slime will generate data for the next rollout while training on the current one. - -The only difference between `train.py` and `train_async.py` lies in the synchronization logic of the training loop. We achieve this by using Ray's asynchronous features (`.remote`, `ray.get`). diff --git a/docs/zh/models/qwen3-4B.md b/docs/zh/models/qwen3-4B.md index e0ee960..04124ab 100644 --- a/docs/zh/models/qwen3-4B.md +++ b/docs/zh/models/qwen3-4B.md @@ -303,11 +303,3 @@ ray job submit ... \ ```bash --sglang-cuda-graph-bs 1 2 4 8 $(seq 16 8 256) ``` - -### 异步训练 - -当进行训推分离时,你会发现训练和推理的 GPU 总是相互等待着,为了避免这种资源空闲,我们可以开启异步训练。开启的方式即为将启动脚本中的 `train.py` 改变为 `train_async.py`。这样 slime 就会在进行当前 rollout 的训练时进行下一个 rollout 的数据生成了。 - -`train.py` 和 `train_async.py` 的差别只在于 train loop 的同步逻辑,我们通过 ray 的异步(`.remote`, `ray.get`)实现了这点。 - -⚠️ 在异步训练时,sglang 的性能检测日志与训练日志可能会混到一起,不易区分,可以通过 `--sglang-log-level` 来减少 sglang 的日志。 \ No newline at end of file diff --git a/slime_plugins/rollout_buffer/README.md b/slime_plugins/rollout_buffer/README.md deleted file mode 100644 index e85e68d..0000000 --- a/slime_plugins/rollout_buffer/README.md +++ /dev/null @@ -1,50 +0,0 @@ -# Rollout Buffer - -## Overview - -Rollout Buffer is an independent component for asynchronous agent trajectory generation, with the main function of using the LLM OpenAI Server launched by slime training to generate agent trajectories. - -### Workflow - -``` -slime Training Process ←─── HTTP API ───→ Rollout Buffer - ↓ ↓ - LLM Server ←─────── HTTP Requests ─────── Agent Framework - ↓ ↓ - Model Response ──────────────────────→ Trajectory Generation -``` - -For each different Agent task, there should be a corresponding independent Generator class, responsible for generating trajectories for that type of task. Rollout Buffer automatically reads and loads different types of Generators. - -## Quick Start - -### Basic Usage Process - -1. **Copy Template**: Copy `base_generator.py` as a template -2. **Modify Task Type**: Change `TASK_TYPE` to your task name (cannot duplicate with other Generators) -3. **Implement Core Function**: Implement the `run_rollout()` function -4. **Optional Customization**: Rewrite five optional functions as needed - - -Generator files must end with `_generator.py` and be placed in the `generator/` directory: - -``` -generator/ -├── base_generator.py # Math task implementation (default template) -└── your_task_generator.py # Your custom task -``` - -Each Generator file must define `TASK_TYPE` and `run_rollout()`. - -In addition, Rollout Buffer also provides some customizable functions to meet special needs of different tasks. If no custom implementation is provided, the system will use default implementations (located in `slime_plugins/rollout_buffer/default_func.py`). - -### Example Script - -First, you need to follow [Example: Qwen3-4B Model](../../docs/en/models/qwen3-4B.md) to configure the environment, download data and convert model checkpoints. And then run the following scripts: -```bash -cd slime_plugins/rollout_buffer -bash rollout_buffer_example.sh - -# In a different terminal -python buffer.py -``` diff --git a/slime_plugins/rollout_buffer/README_zh.md b/slime_plugins/rollout_buffer/README_zh.md deleted file mode 100644 index cfa689f..0000000 --- a/slime_plugins/rollout_buffer/README_zh.md +++ /dev/null @@ -1,51 +0,0 @@ -# Rollout Buffer - -## 概述 - -Rollout Buffer 是用于辅助纯异步 agent 训练的独立组件,其主要功能是使用 slime 训练启动的 LLM OpenAI Server 进行智能体轨迹的生成。 - -### 工作流程 - -``` -slime Training Process ←─── HTTP API ───→ Rollout Buffer - ↓ ↓ - LLM Server ←─────── HTTP Requests ─────── Agent Framework - ↓ ↓ - Model Response ──────────────────────→ Trajectory Generation -``` - -对于每一个不同的 Agent 任务,都应该对应一个独立的 Generator 类,负责生成该类任务的轨迹。Rollout Buffer 会自动读取并加载不同类型的 Generator。 - -## 快速开始 - -### 基本使用流程 - -1. **复制模板**:将 `base_generator.py` 作为模板进行复制 -2. **修改任务类型**:将 `TASK_TYPE` 修改为您的任务名称(不能与其他 Generator 重复) -3. **实现核心函数**:实现 `run_rollout()` 函数 -4. **可选定制**:根据需要重写五个可选函数 - - -Generator 文件必须以 `_generator.py` 结尾,并放置在 `generator/` 目录下: - -``` -generator/ -├── base_generator.py # Math 任务实现(默认模板) -└── your_task_generator.py # 您的自定义任务 -``` - -每个 Generator 文件必须定义 `TASK_TYPE` 与 `run_rollout()`。 - -此外,Rollout Buffer 还提供了一些可自定义的函数来满足不同任务的特殊需求。如果不提供自定义实现,系统将使用默认实现(位于 `slime_plugins/rollout_buffer/default_func.py`)。 - -### 示例脚本 - -请仿照 [示例:Qwen3-4B 模型](../../docs/zh/models/qwen3-4B.md) 文档中配置好 slime 的运行环境,下载数据,并转换模型 ckpt。之后分别运行 - -```bash -cd slime_plugins/rollout_buffer -bash rollout_buffer_example.sh - -# In a different terminal -python buffer.py -``` diff --git a/slime_plugins/rollout_buffer/buffer.py b/slime_plugins/rollout_buffer/buffer.py deleted file mode 100644 index be4086d..0000000 --- a/slime_plugins/rollout_buffer/buffer.py +++ /dev/null @@ -1,343 +0,0 @@ -import copy -import glob -import importlib.util -import json -import pathlib -import threading -import time -from typing import Any, Dict, Optional, List - -import uvicorn -from fastapi import BackgroundTasks, FastAPI, HTTPException, Request -from pydantic import BaseModel - -app = FastAPI(title="Rollout Buffer Server", debug=True) - - -def default_is_valid_group(group_data, min_valid_group_size, task_type): - return group_data >= min_valid_group_size - - -def default_get_group_data_meta_info(temp_data: Dict[str, List[Dict[str, Any]]]) -> Dict[str, Any]: - """ - Default implementation for getting meta information about the temporary data - collected between get_batch calls. - """ - if not temp_data: - return { - "total_samples": 0, - "num_groups": 0, - "avg_group_size": 0, - "avg_reward": 0, - } - - meta_info = {"total_samples": 0, "num_groups": len(temp_data)} - - all_rewards = [] - # Calculate per-group statistics - for instance_id, samples in temp_data.items(): - group_size = len(samples) - group_rewards = [s["reward"] for s in samples] # Calculate group reward standard deviation - meta_info["total_samples"] += group_size - all_rewards.extend(group_rewards) - # Calculate global statistics - meta_info["avg_group_size"] = meta_info["total_samples"] / meta_info["num_groups"] - - if all_rewards: - meta_info["avg_reward"] = sum(all_rewards) / len(all_rewards) - else: - meta_info["avg_reward"] = 0 - return meta_info - - -def discover_generators(): - """ - Automatically discover generator modules in the generator directory. - Returns a dictionary mapping task_type to module with run_rollout function. - """ - generator_map = {} - generator_dir = pathlib.Path(__file__).parent / "generator" - - # Find all files within generator_dir - for file_path in glob.glob(str(generator_dir / "*.py")): - if file_path.endswith("__init__.py"): - continue - - try: - # Load the module - spec = importlib.util.spec_from_file_location("generator_module", file_path) - if spec is None or spec.loader is None: - print(f"Warning: Could not load spec for {file_path}") - continue - - module = importlib.util.module_from_spec(spec) - spec.loader.exec_module(module) - - # Check if module has TASK_TYPE constant - if not hasattr(module, "TASK_TYPE"): - print(f"Warning: {file_path} does not define TASK_TYPE constant") - continue - - # Check if module has run_rollout function - if not hasattr(module, "run_rollout"): - print(f"Warning: {file_path} does not define run_rollout function") - continue - - task_type = getattr(module, "TASK_TYPE") - generator_info = { - "module": module, - "file_path": file_path, - "run_rollout": getattr(module, "run_rollout"), - } - - # Check for optional functions and use defaults if not present - for func_name in [ - "transform_group", - "is_valid_group", - "get_group_data_meta_info", - ]: - generator_info[func_name] = getattr(module, func_name, None) - - generator_map[task_type] = generator_info - print(f"Discovered generator: {task_type} -> {file_path}") - - except Exception as e: - print(f"Error loading generator from {file_path}: {str(e)}") - continue - - return generator_map - - -@app.middleware("http") -async def set_body_size(request: Request, call_next): - request._body_size_limit = 1_073_741_824 # 1GB - response = await call_next(request) - return response - - -class BufferResponse(BaseModel): - success: bool - message: str = "" - data: Optional[Dict[str, Any]] = None - - -class BufferQueue: - def __init__( - self, - group_size, - task_type="math", - transform_group_func=None, - is_valid_group_func=None, - get_group_data_meta_info_func=None, - ): - self.data = {} - self.temp_data = {} - self.group_timestamps = {} - self.group_size = group_size - self.task_type = task_type - - # Set up function handlers with defaults - self.is_valid_group_func = is_valid_group_func or default_is_valid_group - self.get_group_data_meta_info_func = get_group_data_meta_info_func or default_get_group_data_meta_info - self.transform_group_func = transform_group_func or (lambda group, task_type: group) - - def append(self, item): - instance_id = item["instance_id"] - current_time = time.time() - - # Update timestamp for this group - self.group_timestamps[instance_id] = current_time - - if instance_id not in self.temp_data: - self.temp_data[instance_id] = [copy.deepcopy(item)] - else: - self.temp_data[instance_id].append(copy.deepcopy(item)) - - if instance_id not in self.data: - self.data[instance_id] = [item] - else: - self.data[instance_id].append(item) - - def _get_valid_groups_with_timeout(self, del_data=False): - """Get valid groups including timeout-based groups""" - valid_groups = {} - timed_out_groups = {} - finished_groups = [] - - for instance_id, group_data in self.data.items(): - if self.is_valid_group_func((instance_id, group_data), self.min_valid_group_size, self.task_type): - valid_groups[instance_id] = group_data - - # Remove finished groups and timed out groups with insufficient data - if del_data: - for instance_id in finished_groups: - self.data.pop(instance_id, None) - self.group_timestamps.pop(instance_id, None) - print(f"Removed finished group {instance_id}") - - # Combine normal valid groups and timeout groups - all_valid_groups = {**valid_groups, **timed_out_groups} - - return all_valid_groups, finished_groups - - def get(self): - output = {"data": [], "meta_info": {}} - - # Get meta information about temp data before processing - meta_info = self.get_group_data_meta_info_func(self.temp_data) - output["meta_info"] = meta_info - - valid_groups, finished_groups = self._get_valid_groups_with_timeout(del_data=True) - output["meta_info"]["finished_groups"] = finished_groups - - print(f"meta info: {json.dumps(meta_info, indent=2)}") - - valid_groups = list(valid_groups.items()) - - for instance_id, group in valid_groups: - # First filter individual items - transformed_group = self.transform_group_func((instance_id, group), self.task_type) - output["data"].extend(transformed_group[1]) - - if instance_id in self.data: - self.data.pop(instance_id) - - return output - - def __len__(self): - valid_groups, _ = self._get_valid_groups_with_timeout() - num = sum([len(v) for v in valid_groups.values()]) - num_of_all_groups = sum([len(v) for v in self.data.values()]) - print(f"valid_groups: {len(valid_groups)}, num: {num}, num_of_all_groups: {num_of_all_groups}") - return num - - -class RolloutBuffer: - def __init__( - self, - group_size=16, - min_valid_group_size_ratio=1, - min_valid_item_size_ratio=1, - task_type="math", - transform_group_func=None, - is_valid_group_func=None, - get_group_data_meta_info_func=None, - ): - self.buffer = BufferQueue( - group_size=group_size, - min_valid_group_size_ratio=min_valid_group_size_ratio, - min_valid_item_size_ratio=min_valid_item_size_ratio, - task_type=task_type, - transform_group_func=transform_group_func, - is_valid_group_func=is_valid_group_func, - get_group_data_meta_info_func=get_group_data_meta_info_func, - ) - self.lock = threading.RLock() - self.not_empty = threading.Condition(self.lock) - self.total_written = 0 - self.total_read = 0 - self.task_type = task_type - - def write(self, data): - self.buffer.append(data) - self.total_written += 1 - - self.not_empty.notify_all() - return data - - def read(self): - with self.not_empty: - if len(self.buffer) == 0: - return {"data": [], "meta_info": {}} - - # Don't clear temp_data for regular read operations - result = self.buffer.get() - self.total_read += len(result["data"]) - return result - - -buffer = None - - -@app.post("/buffer/write", response_model=BufferResponse) -async def write_to_buffer(request: Request): - try: - data = await request.json() - item = buffer.write(data) - return BufferResponse( - success=True, - message="Data has been successfully written to buffer", - data={"data": [item], "meta_info": "write to buffer"}, - ) - except Exception as e: - print(f"Write failed: {str(e)}") - import traceback - - traceback.print_exc() - raise HTTPException(status_code=500, detail=f"Write failed: {str(e)}") - - -@app.post("/get_rollout_data", response_model=BufferResponse) -async def get_rollout_data(request: Request): - items = buffer.read() - - if not items["data"]: - return BufferResponse( - success=False, - message="No data available to read", - data={"data": [], "meta_info": items["meta_info"]}, - ) - - print(f"return {len(items['data'])} items and save them to local") - buffer.buffer.temp_data = {} - - return BufferResponse( - success=True, - message=f"Successfully read {len(items['data'])} items", - data=items, - ) - - -def run_rollout(data: dict): - global buffer - # Auto-discover generators - generator_map = discover_generators() - - task_type = data["task_type"] - if task_type not in generator_map: - print(f"Error: No generator found for task_type '{task_type}'") - print(f"Available generators: {list(generator_map.keys())}") - return - - generator_info = generator_map[task_type] - print(f"Using generator: {generator_info['file_path']} for task_type: {task_type}") - - buffer = RolloutBuffer( - group_size=int(data["num_repeat_per_sample"]), - task_type=task_type, - transform_group_func=generator_info.get("transform_group", None), - is_valid_group_func=generator_info.get("is_valid_group"), - get_group_data_meta_info_func=generator_info.get("get_group_data_meta_info"), - ) - - # Call the run_rollout function from the appropriate generator module - generator_info["run_rollout"](data) - print(f"Rollout completed successfully for task_type: {task_type}") - - -@app.post("/start_rollout") -async def start_rollout(request: Request, background: BackgroundTasks): - payload = await request.json() - background.add_task(run_rollout, payload) - return {"message": "Rollout started"} - - -if __name__ == "__main__": - uvicorn.run( - app, - host="0.0.0.0", - port=8889, - limit_concurrency=1000, # Connection concurrency limit - # limit_max_requests=1000000, # Maximum request limit - timeout_keep_alive=5, # Keep-alive timeout, - ) diff --git a/slime_plugins/rollout_buffer/generator/__init__.py b/slime_plugins/rollout_buffer/generator/__init__.py deleted file mode 100644 index 87090b1..0000000 --- a/slime_plugins/rollout_buffer/generator/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -from .base_generator import BaseGenerator, query_single_turn - -__all__ = [ - "BaseGenerator", - "query_single_turn", -] diff --git a/slime_plugins/rollout_buffer/generator/base_generator.py b/slime_plugins/rollout_buffer/generator/base_generator.py deleted file mode 100644 index 5fb732d..0000000 --- a/slime_plugins/rollout_buffer/generator/base_generator.py +++ /dev/null @@ -1,352 +0,0 @@ -import copy -import json -import random -import time -import uuid -from functools import partial -from multiprocessing import Process, Queue -from time import sleep -from typing import List, Optional - -import requests -from openai import OpenAI -from tqdm import tqdm -from slime.rollout.rm_hub import get_deepscaler_rule_based_reward -from slime.rollout.rm_hub import get_deepscaler_rule_based_reward - -TASK_TYPE = "math" - -SAMPLING_PARAMS = { - "top_p": 1, -} - - -def get_rule_based_math_reward(item): - messages = item["messages"] - label = item["label"] - assert messages[-1]["role"] == "assistant", "last message must be assistant, but got {}".format( - messages[-1]["role"] - ) - - response = messages[-1]["content"] - if response is None or len(response) == 0: - return 0 - - reward = get_deepscaler_rule_based_reward(response, label) - return reward - - -def query_single_turn(client, messages, sampling_params, tools=None): - base_payload = { - "messages": messages, - **sampling_params, - "model": "custom", - "stream": False, - "seed": random.randint(1, 10000000), - "tools": tools, - } - - text = None - accumulated_tokens = 0 - - for attempt in range(6): - try: - # Create a fresh payload for each attempt - current_payload = copy.deepcopy(base_payload) - - if text is not None: - # Update messages with current progress - current_messages = copy.deepcopy(messages) - current_messages.append({"role": "assistant", "content": text}) - current_payload["messages"] = current_messages - - # Adjust max_tokens based on accumulated tokens - if "max_tokens" in sampling_params: - current_payload["max_tokens"] = max(0, sampling_params["max_tokens"] - accumulated_tokens) - - # Add continue flag for partial rollouts - current_payload["extra_body"] = {"continue_final_message": True} - if current_payload["max_tokens"] == 0: - break - response = client.chat.completions.create(**current_payload) - - if len(response.choices) > 0: - finish_reason = response.choices[0].finish_reason - if finish_reason == "abort": - print( - f"query failed, reason: {response.choices[0].finish_reason}, currently generated: {response.usage.completion_tokens}" - ) - - accumulated_tokens += response.usage.completion_tokens - - if text is None: - text = response.choices[0].message.content - else: - text += response.choices[0].message.content - - sleep(10) - continue - if text is None: - text = response.choices[0].message.content - elif response.choices[0].message.content is not None: - text += response.choices[0].message.content - break - else: - print(f"Error in query, status code: {response.status_code}") - continue - except Exception as e: - print(f"query failed in single turn, error: {e}") - continue - - # Update final messages - if len(messages) > 0 and messages[-1]["role"] == "assistant": - messages = messages[:-1] - messages.append({"role": "assistant", "content": text}) - - return messages, finish_reason - - -def worker_process(task_queue, done_queue, rollout_func, reward_func, client, sampling_params): - - for line in iter(task_queue.get, "STOP"): - if isinstance(line, str): - item = json.loads(line) - else: - item = line - - # try: - messages, finish_reason = rollout_func(client, item["prompt"], sampling_params) - - item["uid"] = str(uuid.uuid4()) - item["messages"] = messages - reward = reward_func(item) - item["rollout_index"] = 1 - item["reward"] = reward - item["extra_info"] = {} - item.update(sampling_params) - item["timestamp"] = str(time.time()) - item["round_number"] = len([_ for _ in item["messages"] if _["role"] == "assistant"]) - item["finish_reason"] = finish_reason - - output_item = { - "uid": item.pop("uid"), - "messages": messages, - "reward": reward, - "instance_id": item.pop("instance_id"), - "extra_info": item, - } - - done_queue.put(output_item) - - done_queue.put("COMPLETE") - - -class BaseGenerator: - def __init__( - self, - remote_engine_url, - remote_buffer_url, - num_repeat_per_sample=1, - queue_size=1000000, - num_process=10, - task_type="math", - max_tokens=4096, - num_repeats=10, - skip_instance_ids: Optional[List[str]] = None, - ): - self.queue_size = queue_size - self.num_process = num_process - self.remote_engine_url = remote_engine_url - self.remote_buffer_url = remote_buffer_url - self.num_repeat_per_sample = num_repeat_per_sample - self.task_type = task_type - self.max_tokens = max_tokens - self.num_repeats = num_repeats - # Ensure skip_instance_ids is a mutable list (copy to avoid modifying original) - self.skip_instance_ids = list(skip_instance_ids) if skip_instance_ids is not None else None - - if self.skip_instance_ids is not None: - print(f"BaseGenerator initialized with {len(self.skip_instance_ids)} instance_ids to skip") - self.skip_instance_ids = self.skip_instance_ids * self.num_repeat_per_sample - - if "/v1" in remote_engine_url: - self.client = OpenAI(api_key="test", base_url=remote_engine_url) - else: - remote_engine_url = remote_engine_url.strip("/") + "/v1" - self.client = OpenAI(api_key="test", base_url=remote_engine_url) - - def send_data_to_buffer(self, data): - remote_buffer_url = self.remote_buffer_url.rstrip("/") + "/buffer/write" - - for _ in range(2): - try: - response = requests.post(remote_buffer_url, json=data) - if response.status_code == 200: - break - else: - print(f"send data to buffer failed, status code: {response.status_code}") - continue - except Exception as e: - print(f"send data to buffer failed, error: {e}") - continue - - def run(self, input_file, rollout_func, reward_func): - task_queue, done_queue = Queue(maxsize=self.queue_size), Queue(maxsize=self.queue_size) - - def read_data_into_queue(): - cnt = 0 - items = [] - skipped_count = 0 - with open(input_file, "r") as f: - for i, line in enumerate(f): - item = json.loads(line) - if "instance_id" not in item: - item["instance_id"] = i - items.append(item) - random.shuffle(items) - - for _ in range(self.num_repeats): - - for item in items: - for _ in range(self.num_repeat_per_sample): - item_repeat = copy.deepcopy(item) - - if "uid" not in item_repeat: - item_repeat["uid"] = str(uuid.uuid4()) - - # Check if instance_id should be skipped - if self.skip_instance_ids is not None and item_repeat["instance_id"] in self.skip_instance_ids: - print(f"Skipping instance_id: {item_repeat['instance_id']}") - # Remove from skip list to handle potential duplicates in multiple epochs - self.skip_instance_ids.remove(item_repeat["instance_id"]) - skipped_count += 1 - continue - - task_queue.put(item_repeat) - cnt += 1 - time.sleep(300) - - if skipped_count > 0: - remaining_skip_count = len(self.skip_instance_ids) if self.skip_instance_ids is not None else 0 - print( - f"Rollout summary: skipped {skipped_count} instance_ids, {remaining_skip_count} still in skip list" - ) - - for _ in range(self.num_process): - task_queue.put("STOP") - - processes = [] - SAMPLING_PARAMS["max_tokens"] = self.max_tokens - - for _ in range(self.num_process): - process = Process( - target=partial(worker_process, client=self.client, sampling_params=SAMPLING_PARAMS), - args=(task_queue, done_queue, rollout_func, reward_func), - ) - process.start() - processes.append(process) - - process = Process(target=read_data_into_queue) - process.start() - - progress_bar = tqdm() - num_finished = 0 - while num_finished < self.num_process: - item = done_queue.get() - if item == "COMPLETE": - num_finished += 1 - else: - assert "reward" in item, f"reward not in item: {item}" - assert "instance_id" in item, f"instance_id not in item: {item}" - self.send_data_to_buffer(item) - progress_bar.update(1) - - progress_bar.close() - - return "finished" - - def entry(self, input_file, rollout_func, reward_func, num_epoch=1): - for _ in range(num_epoch): - status = self.run(input_file, rollout_func, reward_func) - - -def run_rollout(data: dict): - - print(f"Starting math rollout with data: {data}") - - rollout_func = query_single_turn - reward_func = get_rule_based_math_reward - - print(f"Waiting for 10 seconds for buffer server to start") - time.sleep(10) - global SAMPLING_PARAMS - for k, v in data["sampling_params"].items(): - SAMPLING_PARAMS[k] = v - print(f"Set {k} to {v}", type(v)) - - generator = BaseGenerator( - data["remote_engine_url"], - data["remote_buffer_url"], - num_repeat_per_sample=int(data["num_repeat_per_sample"]), - queue_size=1000000, - max_tokens=int(data["sampling_params"]["max_tokens"]), - num_process=int(data.get("num_process", 100)), - task_type=data["task_type"], - skip_instance_ids=data.get("skip_instance_ids", None), - ) - - generator.entry(data["input_file"], rollout_func, reward_func, int(data.get("num_epoch", 1))) - - -def normalize_group_data(group, epsilon=1e-8, algo="grpo"): - print(f"Using math-specific normalization for group {group[0]}") - - assert algo == "grpo", "Only 'grpo' is supported for now." - - instance_id = group[0] - data = group[1] - rewards = [item["reward"] for item in data] - - valid_rewards = [r for r in rewards if 1 >= r >= 0] - - if set(valid_rewards) == {0}: - normalized_rewards = rewards - else: - mean_reward = sum(valid_rewards) / len(valid_rewards) - std_reward = (sum((r - mean_reward) ** 2 for r in valid_rewards) / len(valid_rewards)) ** 0.5 - - if std_reward < epsilon: - print(f"[Math Info] Zero variance in group {instance_id}, setting all to 0.") - normalized_rewards = [0.0 if 1 >= r >= 0 else r for r in rewards] - else: - normalized_rewards = [(r - mean_reward) / (std_reward + epsilon) if 1 >= r >= 0 else r for r in rewards] - - for i, item in enumerate(data): - item["reward"] = normalized_rewards[i] - item["raw_reward"] = rewards[i] - - return (instance_id, data) - - -def is_valid_group(group, min_valid_group_size, task_type="math"): - # Handle both tuple and list inputs - if isinstance(group, tuple): - instance_id, items = group - else: - items = group - - # Count valid items (non-empty responses) - valid_indices = [] - for i, item in enumerate(items): - if item["messages"][-1]["content"].strip(): - valid_indices.append(i) - - group_size = len(items) - valid_count = len(valid_indices) - - # A group is finished if it has reached the target size - is_finished = group_size >= min_valid_group_size - - is_valid = is_finished and valid_count >= min_valid_group_size - - return is_valid, is_finished diff --git a/slime_plugins/rollout_buffer/rollout_buffer_example.py b/slime_plugins/rollout_buffer/rollout_buffer_example.py deleted file mode 100644 index 0d98442..0000000 --- a/slime_plugins/rollout_buffer/rollout_buffer_example.py +++ /dev/null @@ -1,301 +0,0 @@ -import asyncio -import time -from typing import Any, Dict, List - -import aiohttp -import requests -from transformers import AutoTokenizer - -import wandb -from slime.ray.buffer import Buffer -from slime.utils.async_utils import run -from slime.utils.mask_utils import MultiTurnLossMaskGenerator -from slime.utils.types import Sample - -__all__ = ["generate_rollout"] - - -# Global variables for evaluation -TOKENIZER = None -START_ROLLOUT = True - - -def select_rollout_data(args, results, need_length): - """ - Select the most recent groups when there are too many samples. - Groups all samples by instance_id, sorts groups by timestamp. - - Args: - args: Arguments containing configuration - results: List of rollout data items with timestamps - - Returns: - Selected samples from the newest groups based on timestamp cutoff - """ - if not results: - return results - - # Group samples by instance_id - groups = {} - for item in results: - assert "instance_id" in item, "instance_id must be in item" - instance_id = item["instance_id"] - if instance_id not in groups: - groups[instance_id] = [] - groups[instance_id].append(item) - - print(f"📊 Total groups: {len(groups)}, total samples: {len(results)}") - - # If we don't have too many samples, return all - assert need_length < len(results), "need_length must be smaller than results length" - - # Get timestamp for each group (use the latest timestamp in the group) - def get_group_timestamp(group_items): - timestamps = [] - for item in group_items: - if "timestamp" in item: - timestamps.append(float(item["timestamp"])) - elif "extra_info" in item and "timestamp" in item["extra_info"]: - timestamps.append(float(item["extra_info"]["timestamp"])) - return max(timestamps) if timestamps else 0 - - # Create list of (group_id, timestamp, samples) and sort by timestamp - group_data = [] - for group_id, group_items in groups.items(): - group_timestamp = get_group_timestamp(group_items) - group_data.append((group_id, group_timestamp, group_items)) - - # Sort groups by timestamp (newest first) - group_data.sort(key=lambda x: x[1], reverse=True) - - selected_groups = group_data[:need_length] - - # Flatten selected groups back to sample list - selected_results = [] - for group_id, timestamp, group_items in selected_groups: - selected_results.extend(group_items) - - # Statistics for monitoring - if selected_groups: - newest_ts = selected_groups[0][1] - oldest_ts = selected_groups[-1][1] - print(f"📈 Selected {len(selected_groups)} groups with {len(selected_results)} samples") - print(f"📈 Group timestamp range: {oldest_ts:.2f} to {newest_ts:.2f}") - print(f"📈 Time span: {newest_ts - oldest_ts:.2f} seconds") - - return selected_results - - -def log_raw_info(args, all_meta_info, rollout_id): - final_meta_info = {} - if all_meta_info: - final_meta_info = { - "total_samples": sum(meta["total_samples"] for meta in all_meta_info if "total_samples" in meta) - } - - total_samples = final_meta_info["total_samples"] - if total_samples > 0: - weighted_reward_sum = sum( - meta["avg_reward"] * meta["total_samples"] - for meta in all_meta_info - if "avg_reward" in meta and "total_samples" in meta - ) - - final_meta_info.update( - { - "avg_reward": weighted_reward_sum / total_samples, - } - ) - if hasattr(args, "use_wandb") and args.use_wandb: - log_dict = { - f"rollout/no_filter/total_samples": final_meta_info["total_samples"], - f"rollout/no_filter/avg_reward": final_meta_info["avg_reward"], - } - try: - if args.use_wandb: - log_dict["rollout/step"] = ( - rollout_id - if not args.wandb_always_use_train_step - else rollout_id - * args.rollout_batch_size - * args.n_samples_per_prompt - // args.global_batch_size - ) - wandb.log(log_dict) - print(f"no filter rollout log {rollout_id}: {log_dict}") - except Exception as e: - print(f"Failed to log to wandb: {e}") - print(f"no filter rollout log {rollout_id}: {final_meta_info}") - else: - print(f"no filter rollout log {rollout_id}: {final_meta_info}") - - -async def get_rollout_data(api_base_url: str) -> tuple[List[Dict[str, Any]], Dict[str, Any]]: - start_time = time.time() - async with aiohttp.ClientSession() as session: - while True: - async with session.post( - f"{api_base_url}/get_rollout_data", json={}, timeout=aiohttp.ClientTimeout(total=120) - ) as response: - response.raise_for_status() - resp_json = await response.json() - if resp_json["success"]: - break - await asyncio.sleep(3) - if time.time() - start_time > 30: - print("rollout data is not ready, have been waiting for 30 seconds") - # Reset start_time to continue waiting or handle timeout differently - start_time = time.time() # Or raise an exception, or return empty list - - data = resp_json["data"] - meta_info = {} - if isinstance(data, list): - if "data" in data[0]: - data = [item["data"] for item in data] - elif isinstance(data, dict): - if "data" in data: - meta_info = data["meta_info"] - data = data["data"] - print(f"Meta info: {meta_info}") - required_keys = {"uid", "instance_id", "messages", "reward", "extra_info"} - for item in data: - if not required_keys.issubset(item.keys()): - raise ValueError(f"Missing required keys in response item: {item}") - - return data, meta_info - - -def start_rollout(api_base_url: str, args, metadata): - url = f"{api_base_url}/start_rollout" - print(f"metadata: {metadata}") - finished_groups_instance_id_list = [item for sublist in metadata.values() for item in sublist] - payload = { - "num_process": str(getattr(args, "rollout_num_process", 100)), - "num_epoch": str(args.num_epoch or 3), - "remote_engine_url": f"http://{args.sglang_router_ip}:{args.sglang_router_port}", - "remote_buffer_url": args.rollout_buffer_url, - "task_type": args.rollout_task_type, - "input_file": args.prompt_data, - "num_repeat_per_sample": str(args.n_samples_per_prompt), - "max_tokens": str(args.rollout_max_response_len), - "sampling_params": { - "max_tokens": args.rollout_max_response_len, - "temperature": args.rollout_temperature, - "top_p": args.rollout_top_p, - }, - "tokenizer_path": args.hf_checkpoint, - "skip_instance_ids": finished_groups_instance_id_list, - } - print("start rollout with payload: ", payload) - - while True: - try: - resp = requests.post(url, json=payload, timeout=10) - resp.raise_for_status() - data = resp.json() - print(f"[start_rollout] Success: {data}") - return data - except Exception as e: - print(f"[start_rollout] Failed to send rollout config: {e}") - - -async def generate_rollout_async( - args, rollout_id: int, data_buffer: Buffer, evaluation: bool = False -) -> Dict[str, Any]: - - global START_ROLLOUT - if evaluation: - raise NotImplementedError("Evaluation rollout is not implemented") - - if START_ROLLOUT: - metadata = data_buffer.get_metadata() - start_inform = start_rollout(args.rollout_buffer_url, args, metadata) - print(f"start rollout with payload: {start_inform}") - print(f"start rollout id: {rollout_id}") - START_ROLLOUT = False - - data_number_to_fetch = (args.rollout_batch_size - data_buffer.get_buffer_length()) * args.n_samples_per_prompt - if data_number_to_fetch <= 0: - print( - f"❕buffer length: {data_buffer.get_buffer_length()}, buffer has enough data, return {args.rollout_batch_size} prompts" - ) - return data_buffer.get_samples(args.rollout_batch_size) - assert ( - data_number_to_fetch % args.n_samples_per_prompt == 0 - ), "data_number_to_fetch must be a multiple of n_samples_per_prompt" - print(f"INFO: buffer length: {data_buffer.get_buffer_length()}, data_number_to_fetch: {data_number_to_fetch}") - base_url = args.rollout_buffer_url - tokenizer = AutoTokenizer.from_pretrained(args.hf_checkpoint, trust_remote_code=True) - retry_times = 0 - results = [] - all_meta_info = [] - - if args.fetch_trajectory_retry_times == -1: - print( - f"⚠️ [get_rollout_data] Fetch trajectory retry times set to -1, will retry indefinitely until sufficient data is collected" - ) - while args.fetch_trajectory_retry_times == -1 or retry_times < args.fetch_trajectory_retry_times: - try: - while len(results) < data_number_to_fetch: - time.sleep(5) - data, meta_info = await get_rollout_data(api_base_url=base_url) - results.extend(data) - if meta_info: - all_meta_info.append(meta_info) - print(f"get rollout data with length: {len(results)}") - break - except Exception as err: - print(f"[get_rollout_data] Failed to get rollout data: {err}, retry times: {retry_times}") - retry_times += 1 - - log_raw_info(args, all_meta_info, rollout_id) - - # Apply group-based data selection if there are too many samples - results = select_rollout_data(args, results, data_number_to_fetch // args.n_samples_per_prompt) - - if len(all_meta_info) > 0 and "finished_groups" in all_meta_info[0]: - finished_groups_instance_id_list = [] - for item in all_meta_info: - finished_groups_instance_id_list.extend(item["finished_groups"]) - - data_buffer.update_metadata({str(rollout_id): finished_groups_instance_id_list}) - - print("finally get rollout data with length: ", len(results)) - sample_results = [] - - for i, record in enumerate(results): - oai_messages = record["messages"] - - mask_generator = MultiTurnLossMaskGenerator(tokenizer, tokenizer_type=args.loss_mask_type) - token_ids, loss_mask = mask_generator.get_loss_mask(oai_messages) - response_length = mask_generator.get_response_lengths([loss_mask])[0] - - loss_mask = loss_mask[-response_length:] - - sample_results.append( - Sample( - index=record["instance_id"], - prompt=record["uid"], - tokens=token_ids, - response_length=response_length, - reward=record["reward"], - status=( - Sample.Status.COMPLETED - if "finish_reason" not in record["extra_info"] or record["extra_info"]["finish_reason"] != "length" - else Sample.Status.TRUNCATED - ), - loss_mask=loss_mask, - metadata={**record["extra_info"], "raw_reward": record["raw_reward"]}, - ) - ) - final_return_results = [] - - data_buffer.add_samples(sample_results) - final_return_results = data_buffer.get_samples(args.rollout_batch_size) - - return final_return_results - - -def generate_rollout(args, rollout_id, data_buffer, evaluation=False): - """Generate rollout for both training and evaluation.""" - return run(generate_rollout_async(args, rollout_id, data_buffer, evaluation)) diff --git a/slime_plugins/rollout_buffer/rollout_buffer_example.sh b/slime_plugins/rollout_buffer/rollout_buffer_example.sh deleted file mode 100644 index 2e7581e..0000000 --- a/slime_plugins/rollout_buffer/rollout_buffer_example.sh +++ /dev/null @@ -1,134 +0,0 @@ -#!/bin/bash - -# for rerun the task -pkill -9 sglang -sleep 3 -ray stop --force -pkill -9 ray -pkill -9 python -sleep 3 -pkill -9 ray -pkill -9 python - -set -ex - -export PYTHONBUFFERED=16 - -# DeepSeek-R1-Distill-Qwen-7B -MODEL_ARGS=( - --swiglu - --num-layers 28 - --hidden-size 3584 - --ffn-hidden-size 18944 - --num-attention-heads 28 - --group-query-attention - --num-query-groups 4 - --max-position-embeddings 131072 - --seq-length 4096 - --use-rotary-position-embeddings - --disable-bias-linear - --add-qkv-bias - --normalization "RMSNorm" - --norm-epsilon 1e-06 - --rotary-base 10000 - --vocab-size 152064 - --accumulate-allreduce-grads-in-fp32 - --attention-softmax-in-fp32 - --attention-backend flash - --moe-token-dispatcher-type alltoall - --untie-embeddings-and-output-weights - --attention-dropout 0.0 - --hidden-dropout 0.0 -) - -CKPT_ARGS=( - --hf-checkpoint /root/DeepSeek-R1-Distill-Qwen-7B - --ref-load /root/DeepSeek-R1-Distill-Qwen-7B_torch_dist - --save-interval 100 - --save /root/DeepSeek-R1-Distill-Qwen-7B_slime -) - -ROLLOUT_ARGS=( - --rollout-function-path slime_plugin.rollout_buffer.rollout_buffer_example.generate_rollout - --rm-type deepscaler - --prompt-data /root/dapo-math-17k/dapo-math-17k.jsonl - --input-key prompt - --label-key label - --num-rollout 3000 - --rollout-batch-size 128 - --rollout-max-response-len 8192 - --rollout-temperature 0.8 - --rollout-shuffle - --n-samples-per-prompt 8 - --global-batch-size 1024 - --micro-batch-size 8 - --ref-micro-batch-size 8 - --use-dynamic-batch-size - --max-tokens-per-gpu 9216 - --balance-data -) - -DISTRIBUTED_ARGS=( - --tensor-model-parallel-size 2 - --pipeline-model-parallel-size 1 - --context-parallel-size 1 - --sequence-parallel -) - -PERF_ARGS=( - --recompute-granularity full - --recompute-method uniform - --recompute-num-layers 1 -) - -GRPO_ARGS=( - --advantage-estimator grpo - --use-kl-loss - --kl-loss-coef 0.001 - --kl-loss-type low_var_kl - --kl-coef 0.00 - --entropy-coef 0.00 -) - -OPTIMIZER_ARGS=( - --lr 1e-6 - --lr-decay-style constant - --weight-decay 0.1 - --adam-beta1 0.9 - --adam-beta2 0.98 -) - -WANDB_ARGS=( - # --use-wandb -) - -# launch the master node of ray in container -export MASTER_ADDR=${MASTER_ADDR:-"127.0.0.1"} -ray start --head --node-ip-address ${MASTER_ADDR} --num-gpus 8 --disable-usage-stats - -ray job submit --address="http://127.0.0.1:8265" \ - --runtime-env-json='{ - "env_vars": { - "PYTHONPATH": "/root/Megatron-LM/", - "CUDA_DEVICE_MAX_CONNECTIONS": "1", - "NCCL_CUMEM_ENABLE": "0" - } - }' \ - -- python3 train_async.py \ - --actor-num-nodes 1 \ - --actor-num-gpus-per-node 4 \ - --rollout-num-gpus 4 \ - --rollout-num-gpus-per-engine 1 \ - ${MODEL_ARGS[@]} \ - ${CKPT_ARGS[@]} \ - ${ROLLOUT_ARGS[@]} \ - ${OPTIMIZER_ARGS[@]} \ - ${GRPO_ARGS[@]} \ - ${DISTRIBUTED_ARGS[@]} \ - ${WANDB_ARGS[@]} \ - ${PERF_ARGS[@]} \ - --rollout-buffer-url http://${MASTER_ADDR}:8889 \ - --keep-old-actor \ - --disable-rewards-normalization \ - --loss-mask-type distill_qwen \ - --log-passrate diff --git a/train_async.py b/train_async.py deleted file mode 100644 index a2e3c5d..0000000 --- a/train_async.py +++ /dev/null @@ -1,80 +0,0 @@ -import ray - -from slime.ray.placement_group import create_actor_group, create_placement_groups, create_rollout_group -from slime.utils.arguments import parse_args - - -def train(args): - assert not args.colocate, "Colocation is not supported for async training." - # allocate the GPUs - pgs = create_placement_groups(args) - - actor_model = create_actor_group(args, pgs["actor"]) - - # create the rollout generator, with sglang engines inside. - rollout_generator = create_rollout_group(args, pgs["rollout"]) - - # calculate num_rollout from num_epoch - num_rollout_per_epoch = None - if args.num_rollout is None: - num_rollout_per_epoch = ray.get(rollout_generator.data_buffer.get_num_rollout_per_epoch.remote()) - args.num_rollout = num_rollout_per_epoch * args.num_epoch - assert args.num_rollout > 0 - - # sync the initialization (model initalization, load checkpoint, etc.) - # Note that we initialize it earlier as megatron ckpt loading may have really large peak memory usage. - start_rollout_ids = ray.get( - actor_model.async_init(args, role="actor", with_ref=args.kl_coef != 0 or args.use_kl_loss) - ) - assert len(set(start_rollout_ids)) == 1 - if args.start_rollout_id is None: - args.start_rollout_id = start_rollout_ids[0] - - if args.rollout_global_dataset: - ray.get(rollout_generator.data_buffer.load.remote(args.start_rollout_id - 1)) - - # initialize the connection for weight update during training - ray.get(actor_model.async_init_weight_update_connections(rollout_generator)) - - # always update weight first so that sglang has the loaded weights from training. - ray.get(actor_model.async_update_weights()) - - # async train loop. - generation_handles = rollout_generator.async_generate(args.start_rollout_id) - for rollout_id in range(args.start_rollout_id, args.num_rollout): - # Sync the last generation - ray.get(generation_handles) - - # This is a synchronous call to ensure that the rollout data is ready - actor_model.get_rollout_data(rollout_id) - - # Start the next rollout early. - if rollout_id + 1 < args.num_rollout: - generation_handles = rollout_generator.async_generate(rollout_id + 1) - - ray.get(actor_model.async_train(rollout_id, with_data_fetching=False)) - - if args.save_interval is not None and ( - (rollout_id + 1) % args.save_interval == 0 - or (num_rollout_per_epoch is not None and (rollout_id + 1) % num_rollout_per_epoch == 0) - ): - ray.get(actor_model.async_save_model(rollout_id)) - if args.rollout_global_dataset: - ray.get(rollout_generator.data_buffer.save.remote(rollout_id)) - - if (rollout_id + 1) % args.update_weights_interval == 0: - # sync generate before update weights to prevent update weight in the middle of generation - ray.get(generation_handles) - ray.get(actor_model.async_update_weights()) - - if args.eval_interval is not None and ( - (rollout_id + 1) % args.eval_interval == 0 - or (num_rollout_per_epoch is not None and (rollout_id + 1) % num_rollout_per_epoch == 0) - ): - ray.get(rollout_generator.async_generate(rollout_id, evaluation=True)) - ray.get(actor_model.async_eval(rollout_id)) - - -if __name__ == "__main__": - args = parse_args() - train(args) From a6d134ac318af2744d58ed300bf51a38ff1e299d Mon Sep 17 00:00:00 2001 From: Jiajun Li Date: Wed, 17 Sep 2025 12:28:01 +0000 Subject: [PATCH 4/4] delete sft --- docs/en/sft.md | 87 ----------------- docs/zh/sft.md | 87 ----------------- scripts/run-qwen3-235B-A22B-sft.sh | 151 ----------------------------- scripts/run-qwen3-235B-A22B.sh | 2 +- scripts/run-qwen3-4B-base-sft.sh | 127 ------------------------ 5 files changed, 1 insertion(+), 453 deletions(-) delete mode 100644 docs/en/sft.md delete mode 100644 docs/zh/sft.md delete mode 100644 scripts/run-qwen3-235B-A22B-sft.sh delete mode 100644 scripts/run-qwen3-4B-base-sft.sh diff --git a/docs/en/sft.md b/docs/en/sft.md deleted file mode 100644 index bead865..0000000 --- a/docs/en/sft.md +++ /dev/null @@ -1,87 +0,0 @@ -# Example: Qwen3-4B-Base with OpenHermes-2.5 - -[中文版](../zh/sft.md) - -## Environment Preparation - -First, we need to create a mirror environment and convert the `Qwen3-4B-Base` model by following the [Example: Qwen3-4B Model](./models/qwen3-4B.md). - -After that, we will process the SFT data. Here, we use the classic [OpenHermes-2.5](https://huggingface.co/datasets/teknium/OpenHermes-2.5) as an example. First, we process the data into a format suitable for `slime` to load. You can use the following script to add a column that conforms to the OpenAI message format and save it to `/root/openhermes2_5.parquet`. - -```python -from datasets import load_dataset - -ds = load_dataset("teknium/OpenHermes-2.5")["train"] - -def convert(sample): - conversations = sample["conversations"] - - def convert_role(role): - if role == "human": - return "user" - elif role == "gpt": - return "assistant" - elif role == "system": - return "system" - else: - raise ValueError(f"Unknown role: {role}") - - messages = [ - { - "role": convert_role(turn["from"]), - "content": turn["value"], - } - for turn in conversations - ] - - return {"messages": messages} - -ds = ds.map(convert) -ds.to_parquet("/root/openhermes2_5.parquet") -``` - -## Execute Training - -Execute the training: - -```bash -cd /root/slime -bash script/run-qwen3-4B-base-sft.sh -``` - -### Parameter Introduction - -You can compare [run-qwen3-4B-base-sft.sh](../../scripts/run-qwen3-4B.sh) with [run-qwen3-4B.sh](../../scripts/run-qwen3-4B.sh). You will find that besides changing the model from the instruct version to the base model, the main adjustments are as follows: - -1. Removed `SGLANG_ARGS` and `GRPO_ARGS`. This is because it is not necessary to start SGLang or configure GRPO-related settings during the SFT process. - -2. Renamed `ROLLOUT_ARGS` to `SFT_ARGS` and configured it as follows: - - ```bash - SFT_ARGS=( - --rollout-function-path slime.rollout.sft_example.generate_rollout - --prompt-data /root/openhermes2_5.parquet - --input-key messages - --rollout-shuffle - --num-epoch 3 - --rollout-batch-size 128 - --global-batch-size 128 - - --loss-type sft_loss - --calculate-per-token-loss - --disable-compute-advantages-and-returns - --debug-train-only - ) - ``` - - SFT actually reuses the custom rollout functionality of slime. By using `--rollout-function-path`, the data generation part is switched from the RL rollout that uses `sglang` to the SFT version that reads data from a file, which is `slime.rollout.sft_example.generate_rollout`. - - For SFT, it is recommended to set `rollout_batch_size` and `global_batch_size` to the same value and not to configure `n_samples_per_prompt`. This is equivalent to training one batch right after reading one batch. - - `slime` also supports different loss types, and we configure the SFT loss using `--loss-type sft_loss`. - - As for `--calculate-per-token-loss`, this is because `slime` defaults to calculating the per-sample mean for GRPO. In general SFT training, the average is taken over all unmasked tokens in a batch, so it is recommended to configure this. - - Finally, `--disable-compute-advantages-and-returns` indicates that there is no need to pre-calculate log probabilities during the SFT process, and `--debug-train-only` means that `sglang` does not need to be initialized. - -3. Used `train_async.py` instead of `train.py`. This is to leverage the asynchronous training process to implement data prefetching. diff --git a/docs/zh/sft.md b/docs/zh/sft.md deleted file mode 100644 index ff58882..0000000 --- a/docs/zh/sft.md +++ /dev/null @@ -1,87 +0,0 @@ -# 示例:Qwen3-4B-Base + OpenHermes-2.5 - -[English](../en/sft.md) - -## 环境准备 - -首先需要我们仿照 [示例:Qwen3-4B 模型](./models/qwen3-4B.md) 创建镜像环境与转换 `Qwen3-4B-Base` 模型。 - -之后,我们处理 sft 数据。这里我们以经典的 [OpenHermes-2.5](https://huggingface.co/datasets/teknium/OpenHermes-2.5) 为例,首先把数据处理成适合 slime 加载的格式,可以用如下的脚本进行处理,增加一个符合 openai message 格式的列,并保存在 `/root/openhermes2_5.parquet`。 - -```python -from datasets import load_dataset - -ds = load_dataset("teknium/OpenHermes-2.5")["train"] - -def convert(sample): - conversations = sample["conversations"] - - def convert_role(role): - if role == "human": - return "user" - elif role == "gpt": - return "assistant" - elif role == "system": - return "system" - else: - raise ValueError(f"Unknown role: {role}") - - messages = [ - { - "role": convert_role(turn["from"]), - "content": turn["value"], - } - for turn in conversations - ] - - return {"messages": messages} - -ds = ds.map(convert) -ds.to_parquet("/root/openhermes2_5.parquet") -``` - -## 执行训练 - -执行训练: - -```bash -cd /root/slime -bash script/run-qwen3-4B-base-sft.sh -``` - -### 参数简介 - -可以将 [run-qwen3-4B-base-sft.sh](../../scripts/run-qwen3-4B-base-sft.sh) 与 [run-qwen3-4B.sh](../../scripts/run-qwen3-4B.sh) 进行对比。会发现除了我们将模型由 instruct 模型换为了 base 模型之外,主要进行了如下的几个调整: - -1. 移除了 `SGLANG_ARGS` 和 `GRPO_ARGS`。这是因为 sft 的过程中不需要启动 sglang 或者做 grpo 相关的配置; - -2. 将 `ROLLOUT_ARGS` 改名为了 `SFT_ARGS`,并配置为: - - ```bash - SFT_ARGS=( - --rollout-function-path slime.rollout.sft_example.generate_rollout - --prompt-data /root/openhermes2_5.parquet - --input-key messages - --rollout-shuffle - --num-epoch 3 - --rollout-batch-size 128 - --global-batch-size 128 - - --loss-type sft_loss - --calculate-per-token-loss - --disable-compute-advantages-and-returns - --debug-train-only - ) - ``` - - slime 中的 sft 实际上是复用了 slime 的 custom rollout 功能,通过 `--rollout-function-path` 将数据生成部分从使用 sglang 的 RL rollout,切换成了从文件中读取数据的 sft 版本,即 `slime.rollout.sft_example.generate_rollout`。 - - 对于 sft 来说,建议将 `rollout_batch_size` 与 `global_batch_size` 设置成相同的,并不要配置 `n_samples_per_prompt`,这样相当于是读一个 batch 就训一个 batch。 - - slime 还支持不同的 loss 类型,我们就是通过 `--loss-type sft_loss` 配置上 sft loss 的。 - - 至于 `--calculate-per-token-loss`,这是因为 slime 默认是以 GRPO 的 per sample mean 进行计算的,而一般 sft 训练都是按一个 batch 的所有不被 mask 的 token 取平均,所以建议配置上。 - - 最后 `--disable-compute-advantages-and-returns` 表示 sft 的过程中不需要预先计算 log prob,`--debug-train-only` 表示不需要初始化 sglang。 - -3. 使用了 `train_async.py` 而不是 `train.py`。这是为了利用异步训练的流程,来实现数据 prefetch。 diff --git a/scripts/run-qwen3-235B-A22B-sft.sh b/scripts/run-qwen3-235B-A22B-sft.sh deleted file mode 100644 index b2104a8..0000000 --- a/scripts/run-qwen3-235B-A22B-sft.sh +++ /dev/null @@ -1,151 +0,0 @@ -#!/bin/bash - -# for rerun the task -pkill -9 sglang -sleep 3 -ray stop --force -pkill -9 ray -pkill -9 python -sleep 3 -pkill -9 ray -pkill -9 python - -set -ex - -# if base folder not set raise error -if [ -z "${BASE_FOLDER}" ]; then - echo "BASE_FOLDER is not set. Please set it to the base directory of your checkpoints." - exit 1 -fi - -if [ -z "${MASTER_ADDR}" ]; then - echo "MASTER_ADDR is not set. Please set it to the master node address." - exit 1 -fi - -# will prevent ray from buffering stdout/stderr -export PYTHONBUFFERED=16 - -NVLINK_COUNT=$(nvidia-smi | grep -o "NVLink" | wc -l) -if [ "$NVLINK_COUNT" -gt 0 ]; then - HAS_NVLINK=1 -else - HAS_NVLINK=0 -fi -echo "HAS_NVLINK: $HAS_NVLINK (detected $NVLINK_COUNT NVLink references)" - -SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)" -source "${SCRIPT_DIR}/models/qwen3-235B-A22B.sh" - -CKPT_ARGS=( - --hf-checkpoint ${BASE_FOLDER}/Qwen3-235B-A22B - --ref-load ${BASE_FOLDER}/Qwen3-235B-A22B_torch_dist - --load ${BASE_FOLDER}/Qwen3-235B-A22B_slime/ - --save ${BASE_FOLDER}/Qwen3-235B-A22B_slime/ - --save-interval 1000 -) - -SFT_ARGS=( - --rollout-function-path slime.rollout.sft_example.generate_rollout - --prompt-data ${BASE_FOLDER}/openhermes2_5.parquet - --input-key messages - --rollout-shuffle - --num-epoch 3 - --rollout-batch-size 128 - --global-batch-size 128 - - --loss-type sft_loss - --calculate-per-token-loss - --disable-compute-advantages-and-returns - --debug-train-only -) - -PERF_ARGS=( - --tensor-model-parallel-size 4 - --sequence-parallel - --pipeline-model-parallel-size 1 - --context-parallel-size 1 - --expert-model-parallel-size 32 - --expert-tensor-parallel-size 1 - - --recompute-granularity full - --recompute-method uniform - --recompute-num-layers 1 - - # --micro-batch-size 1 - --use-dynamic-batch-size - --max-tokens-per-gpu 9216 -) - -OPTIMIZER_ARGS=( - --optimizer adam - --lr 1e-5 - --lr-warmup-iters 128 - --lr-decay-style cosine - --min-lr 1e-6 - --lr-warmup-fraction 0.9 - --weight-decay 0.1 - --adam-beta1 0.9 - --adam-beta2 0.98 - - --optimizer-cpu-offload - --overlap-cpu-optimizer-d2h-h2d - --use-precision-aware-optimizer -) - -WANDB_ARGS=( - # --use-wandb - # --wandb-project slime-dev - # --wandb-group qwen3-235B-sft -) - -MISC_ARGS=( - # default dropout in megatron is 0.1 - --attention-dropout 0.0 - --hidden-dropout 0.0 - # should be good for model performance - --accumulate-allreduce-grads-in-fp32 - --attention-softmax-in-fp32 - # need to comment this when using model with MLA - --attention-backend flash -) - -# launch the master node of ray in container -export no_proxy="127.0.0.1,${MASTER_ADDR}" -ray start --head --node-ip-address ${MASTER_ADDR} --num-gpus 8 --disable-usage-stats -for WORKER_IP in $(awk '{print $1}' /root/mpi_rack_hostfile); do - if [[ "$WORKER_IP" == "$MLP_WORKER_0_HOST" ]]; then - continue - fi - echo "Starting Ray worker on ${WORKER_IP}" - ssh root@"${WORKER_IP}" \ - "pkill -9 sglang ; ray stop --force ; pkill -9 python ; ray start --address=${MASTER_ADDR}:6379 --num-gpus 8 --node-ip-address ${WORKER_IP} --disable-usage-stats" & -done -wait - - -# Build the runtime environment JSON with proper variable substitution -RUNTIME_ENV_JSON="{ - \"env_vars\": { - \"PYTHONPATH\": \"/root/Megatron-LM/\", - \"CUDA_DEVICE_MAX_CONNECTIONS\": \"1\", - \"NCCL_NVLS_ENABLE\": \"${HAS_NVLINK}\" - \"no_proxy\": \"${no_proxy}\", - \"MASTER_ADDR\": \"${MASTER_ADDR}\" - } -}" - -ray job submit --address="http://127.0.0.1:8265" \ - --runtime-env-json="${RUNTIME_ENV_JSON}" \ - -- python3 train_async.py \ - --actor-num-nodes 4 \ - --actor-num-gpus-per-node 8 \ - ${MODEL_ARGS[@]} \ - ${CKPT_ARGS[@]} \ - ${SFT_ARGS[@]} \ - ${OPTIMIZER_ARGS[@]} \ - ${DISTRIBUTED_ARGS[@]} \ - ${WANDB_ARGS[@]} \ - ${PERF_ARGS[@]} \ - ${EVAL_ARGS[@]} \ - ${MISC_ARGS[@]} diff --git a/scripts/run-qwen3-235B-A22B.sh b/scripts/run-qwen3-235B-A22B.sh index 0585be0..9ba7ad8 100644 --- a/scripts/run-qwen3-235B-A22B.sh +++ b/scripts/run-qwen3-235B-A22B.sh @@ -118,7 +118,7 @@ OPTIMIZER_ARGS=( WANDB_ARGS=( # --use-wandb # --wandb-project slime-dev - # --wandb-group qwen3-235B-sft + # --wandb-group qwen3-235B ) SGLANG_ARGS=( diff --git a/scripts/run-qwen3-4B-base-sft.sh b/scripts/run-qwen3-4B-base-sft.sh deleted file mode 100644 index 70a88c6..0000000 --- a/scripts/run-qwen3-4B-base-sft.sh +++ /dev/null @@ -1,127 +0,0 @@ -#!/bin/bash - -# for rerun the task -pkill -9 sglang -sleep 3 -ray stop --force -pkill -9 ray -pkill -9 python -sleep 3 -pkill -9 ray -pkill -9 python - -set -ex - -# will prevent ray from buffering stdout/stderr -export PYTHONBUFFERED=16 - -NVLINK_COUNT=$(nvidia-smi | grep -o "NVLink" | wc -l) -if [ "$NVLINK_COUNT" -gt 0 ]; then - HAS_NVLINK=1 -else - HAS_NVLINK=0 -fi -echo "HAS_NVLINK: $HAS_NVLINK (detected $NVLINK_COUNT NVLink references)" - -SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)" -source "${SCRIPT_DIR}/models/qwen3-4B.sh" - -CKPT_ARGS=( - --hf-checkpoint /root/Qwen3-4B-Base/ - --ref-load /root/Qwen3-4B-Base_torch_dist - --load /root/Qwen3-4B-Base_slime/ - --save /root/Qwen3-4B-Base_slime/ - --save-interval 1000 -) - -SFT_ARGS=( - --rollout-function-path slime.rollout.sft_example.generate_rollout - --prompt-data /root/openhermes2_5.parquet - --input-key messages - --rollout-shuffle - --num-epoch 3 - --rollout-batch-size 128 - --global-batch-size 128 - - --loss-type sft_loss - --calculate-per-token-loss - --disable-compute-advantages-and-returns - --debug-train-only -) - -PERF_ARGS=( - --tensor-model-parallel-size 1 - --sequence-parallel - --pipeline-model-parallel-size 1 - --context-parallel-size 1 - --expert-model-parallel-size 1 - --expert-tensor-parallel-size 1 - - --recompute-granularity full - --recompute-method uniform - --recompute-num-layers 1 - - # --micro-batch-size 1 - --use-dynamic-batch-size - --max-tokens-per-gpu 9216 -) - -OPTIMIZER_ARGS=( - --optimizer adam - --lr 1e-5 - --lr-warmup-iters 128 - --lr-decay-style cosine - --min-lr 1e-6 - --lr-warmup-fraction 0.9 - --weight-decay 0.1 - --adam-beta1 0.9 - --adam-beta2 0.95 -) - -WANDB_ARGS=( - # --use-wandb - # --wandb-project slime-dev - # --wandb-group qwen3-4B-base-sft - # --wandb-key ${WANDB_KEY} -) - -MISC_ARGS=( - # default dropout in megatron is 0.1 - --attention-dropout 0.0 - --hidden-dropout 0.0 - # should be good for model performance - --accumulate-allreduce-grads-in-fp32 - --attention-softmax-in-fp32 - # need to comment this when using model with MLA - --attention-backend flash -) - -# launch the master node of ray in container -export MASTER_ADDR=${MASTER_ADDR:-"127.0.0.1"} -export no_proxy="127.0.0.1,${MASTER_ADDR}" -ray start --head --node-ip-address ${MASTER_ADDR} --num-gpus 8 --disable-usage-stats - - -# Build the runtime environment JSON with proper variable substitution -RUNTIME_ENV_JSON="{ - \"env_vars\": { - \"PYTHONPATH\": \"/root/Megatron-LM/\", - \"CUDA_DEVICE_MAX_CONNECTIONS\": \"1\", - \"NCCL_NVLS_ENABLE\": \"${HAS_NVLINK}\" - } -}" - -ray job submit --address="http://127.0.0.1:8265" \ - --runtime-env-json="${RUNTIME_ENV_JSON}" \ - -- python3 train_async.py \ - --actor-num-nodes 1 \ - --actor-num-gpus-per-node 8 \ - ${MODEL_ARGS[@]} \ - ${CKPT_ARGS[@]} \ - ${SFT_ARGS[@]} \ - ${OPTIMIZER_ARGS[@]} \ - ${DISTRIBUTED_ARGS[@]} \ - ${WANDB_ARGS[@]} \ - ${PERF_ARGS[@]} \ - ${EVAL_ARGS[@]} \ - ${MISC_ARGS[@]}