From 8163804f23a6df51c178f353eda1ccaa1f8824b9 Mon Sep 17 00:00:00 2001 From: hailin Date: Thu, 25 Dec 2025 06:50:03 -0800 Subject: [PATCH] =?UTF-8?q?fix(contract-signing):=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E5=90=88=E5=90=8C=E7=AD=BE=E7=BD=B2=E6=B5=81=E7=A8=8B=E7=9A=84?= =?UTF-8?q?=E6=8C=81=E4=BB=93=E6=9B=B4=E6=96=B0=E6=97=B6=E6=9C=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 问题:支付后直接更新持仓和开启挖矿,导致款还在冻结中树就种下去了 修复: - planting-application.service: 支付时不再更新持仓和开启挖矿 - contract-signing.service: signContract 在事务里同时完成合同+持仓+挖矿 - contract-signing.service: handleExpiredTasks 超时也更新持仓+挖矿(钱扣总部) - KYCVerifiedEvent 添加 accountSequence 字段 - kyc-verified-event.consumer 直接用事件里的 accountSequence 流程变为:支付冻结 → 签署合同 → [事务: 合同+持仓+挖矿] → 发事件 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .claude/settings.local.json | 4 +- .../user-account/user-account.aggregate.ts | 1 + .../src/domain/events/index.ts | 2 +- .../services/contract-signing.service.ts | 106 ++++++++++++++++-- .../services/planting-application.service.ts | 20 +--- .../kafka/kyc-verified-event.consumer.ts | 20 ++-- .../kyc/presentation/pages/kyc_id_page.dart | 3 + ...df => 榴莲树认种权益协议_form.pdf | Bin 172775 -> 165674 bytes 8 files changed, 119 insertions(+), 37 deletions(-) rename 榴莲树认种权益协议.pdf => 榴莲树认种权益协议_form.pdf (88%) diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 499e70da..9340b45d 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -405,7 +405,9 @@ "Bash(git branch:*)", "Bash(echo \"docker exec rwa-planting-service npx prisma db execute --stdin <<< \"\"SELECT template_id, version, title, is_active FROM contract_templates;\"\"\")", "Bash(npm uninstall:*)", - "Bash(git commit -m \"$\\(cat <<''EOF''\nfeat\\(contract\\): 使用合同编号代替订单号\n\n合同编号格式: accountSequence-yyyyMMddHHmm\n例如: 10001-202512251003\n\n修改内容:\n- 数据库: 添加 contract_no 字段\n- 后端: 聚合根、Repository、Service、PDF生成器支持 contractNo\n- 前端: 显示合同编号代替订单号\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 \nEOF\n\\)\")" + "Bash(git commit -m \"$\\(cat <<''EOF''\nfeat\\(contract\\): 使用合同编号代替订单号\n\n合同编号格式: accountSequence-yyyyMMddHHmm\n例如: 10001-202512251003\n\n修改内容:\n- 数据库: 添加 contract_no 字段\n- 后端: 聚合根、Repository、Service、PDF生成器支持 contractNo\n- 前端: 显示合同编号代替订单号\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 \nEOF\n\\)\")", + "Bash(npx ts-node:*)", + "Bash(node -e \"\nconst { ethers } = require\\(''ethers''\\);\n\nconst KAVA_TESTNET_RPC = ''https://evm.testnet.kava.io'';\nconst privateKey = ''0xd42a6e6021ebd884f3f179d3793a32e97b9f1001db6ff44441ec455d748b9aa6'';\nconst USDT_CONTRACT = ''0xc12f6A4A7Fd0965085B044A67a39CcA2ff7fe0dF'';\nconst TO_ADDRESS = ''0xab2ecb00ef473cfbbf3df13faa7ed3ff84eea229'';\n\nasync function transfer\\(\\) {\n const provider = new ethers.JsonRpcProvider\\(KAVA_TESTNET_RPC\\);\n const wallet = new ethers.Wallet\\(privateKey, provider\\);\n \n const abi = [''function transfer\\(address to, uint256 amount\\) returns \\(bool\\)'', ''function balanceOf\\(address\\) view returns \\(uint256\\)''];\n const contract = new ethers.Contract\\(USDT_CONTRACT, abi, wallet\\);\n \n const amount = BigInt\\(1000000\\) * BigInt\\(1000000\\);\n \n console.log\\(''Transferring 1,000,000 USDT to'', TO_ADDRESS\\);\n const tx = await contract.transfer\\(TO_ADDRESS, amount, { gasLimit: 100000 }\\);\n console.log\\(''TX Hash:'', tx.hash\\);\n await tx.wait\\(\\);\n \n const newBalance = await contract.balanceOf\\(TO_ADDRESS\\);\n console.log\\(''New balance:'', Number\\(newBalance\\) / 1e6, ''USDT''\\);\n}\n\ntransfer\\(\\).catch\\(e => console.error\\(''Error:'', e.message\\)\\);\n\")" ], "deny": [], "ask": [] diff --git a/backend/services/identity-service/src/domain/aggregates/user-account/user-account.aggregate.ts b/backend/services/identity-service/src/domain/aggregates/user-account/user-account.aggregate.ts index 49bec9cc..8f2c12f3 100644 --- a/backend/services/identity-service/src/domain/aggregates/user-account/user-account.aggregate.ts +++ b/backend/services/identity-service/src/domain/aggregates/user-account/user-account.aggregate.ts @@ -425,6 +425,7 @@ export class UserAccount { this.addDomainEvent( new KYCVerifiedEvent({ userId: this.userId.toString(), + accountSequence: this.accountSequence.value, verifiedAt: new Date(), }), ); diff --git a/backend/services/identity-service/src/domain/events/index.ts b/backend/services/identity-service/src/domain/events/index.ts index 38a5ce0b..6fa8b298 100644 --- a/backend/services/identity-service/src/domain/events/index.ts +++ b/backend/services/identity-service/src/domain/events/index.ts @@ -136,7 +136,7 @@ export class KYCSubmittedEvent extends DomainEvent { } export class KYCVerifiedEvent extends DomainEvent { - constructor(public readonly payload: { userId: string; verifiedAt: Date }) { + constructor(public readonly payload: { userId: string; accountSequence: string; verifiedAt: Date }) { super(); } diff --git a/backend/services/planting-service/src/application/services/contract-signing.service.ts b/backend/services/planting-service/src/application/services/contract-signing.service.ts index e11435f6..52fa660d 100644 --- a/backend/services/planting-service/src/application/services/contract-signing.service.ts +++ b/backend/services/planting-service/src/application/services/contract-signing.service.ts @@ -4,6 +4,8 @@ import { CONTRACT_TEMPLATE_REPOSITORY, IContractSigningTaskRepository, CONTRACT_SIGNING_TASK_REPOSITORY, + IPlantingOrderRepository, + PLANTING_ORDER_REPOSITORY, } from '../../domain/repositories'; import { ContractTemplate, @@ -12,6 +14,7 @@ import { } from '../../domain/aggregates'; import { ContractSigningStatus } from '../../domain/value-objects'; import { EventPublisherService } from '../../infrastructure/kafka/event-publisher.service'; +import { UnitOfWork, UNIT_OF_WORK } from '../../infrastructure/persistence/unit-of-work'; /** * 创建签署任务的参数 @@ -71,6 +74,10 @@ export class ContractSigningService { private readonly templateRepo: IContractTemplateRepository, @Inject(CONTRACT_SIGNING_TASK_REPOSITORY) private readonly taskRepo: IContractSigningTaskRepository, + @Inject(PLANTING_ORDER_REPOSITORY) + private readonly orderRepo: IPlantingOrderRepository, + @Inject(UNIT_OF_WORK) + private readonly unitOfWork: UnitOfWork, private readonly eventPublisher: EventPublisherService, ) {} @@ -200,7 +207,8 @@ export class ContractSigningService { /** * 完成签署 - * 发布 contract.signed 事件,触发 reward-service 执行奖励分配 + * 在同一个事务里:更新合同状态 + 更新持仓 + 开启挖矿 + * 事务成功后发布 contract.signed 事件 */ async signContract( orderNo: string, @@ -212,11 +220,52 @@ export class ContractSigningService { throw new Error('签署任务不存在'); } - task.sign(params); - await this.taskRepo.save(task); - this.logger.log(`User ${userId} signed contract for order: ${orderNo}`); + // 幂等性检查:如果已签署,直接返回 + if (task.status === ContractSigningStatus.SIGNED) { + this.logger.log(`Contract already signed for order: ${orderNo}`); + return; + } - // 发布合同签署完成事件,触发奖励分配 + // 获取订单 + const order = await this.orderRepo.findByOrderNo(orderNo); + if (!order) { + throw new Error('订单不存在'); + } + + // 幂等性检查:如果订单已开启挖矿,直接返回 + if (order.isMiningEnabled) { + this.logger.log(`Mining already enabled for order: ${orderNo}`); + return; + } + + const selection = order.provinceCitySelection; + if (!selection) { + throw new Error('订单缺少省市选择信息'); + } + + // 在同一个事务里完成所有操作 + await this.unitOfWork.executeInTransaction(async (uow) => { + // 1. 更新合同状态 + task.sign(params); + await this.taskRepo.save(task); + + // 2. 更新用户持仓 + const position = await uow.getOrCreatePosition(userId); + position.addPlanting( + order.treeCount.value, + selection.provinceCode, + selection.cityCode, + ); + await uow.savePosition(position); + + // 3. 开启挖矿 + order.enableMining(); + await uow.saveOrder(order); + }); + + this.logger.log(`User ${userId} signed contract for order: ${orderNo}, position updated, mining enabled`); + + // 事务成功后发布事件(给 reward-service) await this.eventPublisher.publishContractSigned({ orderNo: task.orderNo, userId: task.userId.toString(), @@ -250,7 +299,8 @@ export class ContractSigningService { /** * 处理过期未签署的任务 * 由定时任务调用 - * 发布 contract.expired 事件,触发 reward-service 执行系统账户分配 + * 在同一个事务里:更新合同状态 + 更新持仓 + 开启挖矿 + * 事务成功后发布 contract.expired 事件,触发 reward-service 执行系统账户分配 */ async handleExpiredTasks(): Promise { const expiredTasks = await this.taskRepo.findExpiredPendingTasks(); @@ -258,10 +308,46 @@ export class ContractSigningService { for (const task of expiredTasks) { try { - task.markAsTimeout(); - await this.taskRepo.save(task); + // 获取订单 + const order = await this.orderRepo.findByOrderNo(task.orderNo); + if (!order) { + this.logger.error(`Order not found for expired task: ${task.orderNo}`); + continue; + } - // 发布合同超时事件,触发系统账户奖励分配 + // 幂等性检查 + if (order.isMiningEnabled) { + this.logger.log(`Mining already enabled for expired order: ${task.orderNo}`); + continue; + } + + const selection = order.provinceCitySelection; + if (!selection) { + this.logger.error(`Order ${task.orderNo} has no province/city selection`); + continue; + } + + // 在同一个事务里完成所有操作 + await this.unitOfWork.executeInTransaction(async (uow) => { + // 1. 更新合同状态为超时 + task.markAsTimeout(); + await this.taskRepo.save(task); + + // 2. 更新用户持仓(树还是种了,权益归总部) + const position = await uow.getOrCreatePosition(task.userId); + position.addPlanting( + order.treeCount.value, + selection.provinceCode, + selection.cityCode, + ); + await uow.savePosition(position); + + // 3. 开启挖矿 + order.enableMining(); + await uow.saveOrder(order); + }); + + // 事务成功后发布合同超时事件,触发系统账户奖励分配 await this.eventPublisher.publishContractExpired({ orderNo: task.orderNo, userId: task.userId.toString(), @@ -274,7 +360,7 @@ export class ContractSigningService { }); count++; - this.logger.log(`Marked task as timeout and published contract.expired: orderNo=${task.orderNo}`); + this.logger.log(`Expired task processed: orderNo=${task.orderNo}, position updated, mining enabled`); } catch (error) { this.logger.error(`Failed to handle expired task: orderNo=${task.orderNo}`, error); } diff --git a/backend/services/planting-service/src/application/services/planting-application.service.ts b/backend/services/planting-service/src/application/services/planting-application.service.ts index 72fec8e5..92744f1d 100644 --- a/backend/services/planting-service/src/application/services/planting-application.service.ts +++ b/backend/services/planting-service/src/application/services/planting-application.service.ts @@ -257,23 +257,15 @@ export class PlantingApplicationService { order.markAsPaid(accountSequence || ''); // 7. 使用事务保存本地数据库的所有变更 + Outbox事件 - // 这确保了订单状态、用户持仓、批次数据、以及事件发布的原子性 + // 这确保了订单状态和事件发布的原子性 + // 注意:用户持仓更新和挖矿开启在合同签署完成后执行 await this.unitOfWork.executeInTransaction(async (uow) => { - // 保存订单状态 + // 保存订单状态(此时为 PAID 状态,资金冻结中) await uow.saveOrder(order); - // 更新用户持仓(直接生效) - const position = await uow.getOrCreatePosition(userId); - position.addPlanting( - order.treeCount.value, - selection.provinceCode, - selection.cityCode, - ); - await uow.savePosition(position); - - // 直接开启挖矿(跳过底池注入流程) - order.enableMining(); - await uow.saveOrder(order); + // 注意:不在此处更新用户持仓和开启挖矿 + // 持仓更新和挖矿开启在合同签署完成后由 contract.signed 事件触发 + // 这确保了正确的业务流程:支付冻结 -> 签署合同 -> 确认扣款 -> 更新持仓 // 8. 添加 Outbox 事件(在同一事务中保存) // 使用 Outbox Pattern 保证事件发布的可靠性 diff --git a/backend/services/planting-service/src/infrastructure/kafka/kyc-verified-event.consumer.ts b/backend/services/planting-service/src/infrastructure/kafka/kyc-verified-event.consumer.ts index ec3ca6af..4437e3f4 100644 --- a/backend/services/planting-service/src/infrastructure/kafka/kyc-verified-event.consumer.ts +++ b/backend/services/planting-service/src/infrastructure/kafka/kyc-verified-event.consumer.ts @@ -17,6 +17,7 @@ interface KYCVerifiedEventMessage { aggregateId: string; payload: { userId: string; + accountSequence: string; verifiedAt: string; }; _outbox?: { @@ -49,20 +50,17 @@ export class KycVerifiedEventConsumer { @EventPattern('identity.KYCVerified') async handleKycVerified(@Payload() message: KYCVerifiedEventMessage): Promise { const userId = message.payload?.userId || message.aggregateId; + const accountSequence = message.payload?.accountSequence; - this.logger.log(`[KYC-VERIFIED] Received KYCVerified event for user: ${userId}`); + this.logger.log(`[KYC-VERIFIED] Received KYCVerified event for user: ${userId}, accountSequence: ${accountSequence}`); + + if (!accountSequence) { + this.logger.error(`[KYC-VERIFIED] Missing accountSequence in event payload for userId: ${userId}`); + return; + } try { - // 1. 获取用户的 accountSequence(从 identity-service) - const userDetail = await this.identityServiceClient.getUserDetailBySequence(userId); - if (!userDetail) { - // userId 可能是数字 ID,尝试查找 - this.logger.warn(`[KYC-VERIFIED] Could not find user detail for: ${userId}`); - return; - } - - const accountSequence = userDetail.accountSequence; - const userIdBigint = BigInt(userDetail.userId); + const userIdBigint = BigInt(userId); this.logger.log( `[KYC-VERIFIED] User ${accountSequence} completed KYC, checking for pending contracts...`, diff --git a/frontend/mobile-app/lib/features/kyc/presentation/pages/kyc_id_page.dart b/frontend/mobile-app/lib/features/kyc/presentation/pages/kyc_id_page.dart index 589421ec..f5245a45 100644 --- a/frontend/mobile-app/lib/features/kyc/presentation/pages/kyc_id_page.dart +++ b/frontend/mobile-app/lib/features/kyc/presentation/pages/kyc_id_page.dart @@ -3,6 +3,9 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:go_router/go_router.dart'; import 'kyc_entry_page.dart'; +import '../../../home/presentation/pages/home_shell_page.dart'; +import '../../../../core/di/injection_container.dart'; +import '../../../../routes/route_paths.dart'; /// KYC 层级1: 实名认证页面 (三要素验证: 姓名+身份证号+手机号) class KycIdPage extends ConsumerStatefulWidget { diff --git a/榴莲树认种权益协议.pdf b/榴莲树认种权益协议_form.pdf similarity index 88% rename from 榴莲树认种权益协议.pdf rename to 榴莲树认种权益协议_form.pdf index 0c369945bdc43518e1fdc8c109cd31320db347d8..3fa5219bf4ad57098df4a0563a65566ed3b3c269 100644 GIT binary patch delta 12335 zcmb_?1yq!6wD$*q-A<_s)3Q`K( z;Zwi<&$;K^J8M|$Wk0by=H2_#TY~5D1hnj$vhutjK0#vkrRCu$^_tDToUGYkv^s566L0NuOpaDaxDqmGx0xH!Vg6K?53Okn@9 zQ*YLF7DjeXCEj&gJ6cc$BMhw$&Mu!-t5};QM=S;eeuW-f;%nra2bB0dQN?UHj}pQ;6F^Er<&kVu_S|?e zOH(4CE}f_ZG7id}+ppQ)P!l06+|{RmUCxz|a9tMc3O0Fwlphv|k8j=Zn8S@up*z`G z_;Fj-`i!_wntImrJ5#nwOwJHT|7Md@#xVFo#1CLHZXXk6(5E`)<5Jxbhlym zJc42%GyzmZO&05Wnbj+|`i@pF(<&dzTXXLv&?nq@+nd(1&i{pk7WuND-qF||*@55m zk;$~Pk=3FuB&p0K*L*jC0MIjiF=hw^Yi4~B7oki~M~I$O8eD+)ZPMl{0&ZJO2D+S| zhupNNx393Bjx*Z^k8Pp%-LLyD+kPl+Vz>}SOxb~qf+P;42j412aJM-*#Wa*`w@LD#jN&6*dMyz0tC*xq^W9@Y|iAb!WN{Wm<5EXI)PCzJc-~{r>R&scT#(Gwn0MUmXR#d8#fa6APrcC zzD1r0&WV7Y>!kAt#RBbiWeU^O<^%kKM*jHgc2tz_H~Qx4?g6t3iX8SwrxpN6JRlk# z;tmTj0o>K*r#r!2No}q?ksk#5lTX5b_$2g~M}mc}9P&T;Be+@;VHJ_Us3(U1pX5yv%g~k|JRswf5U{HBvplmj)O)%jnVqAC?J1AVgEN2 zkpCKmzz=4yub8nV>!X)83Mn=WLBm9I=f}zXS7iKuLiRJ7fdzhvP5=r;am4?hWEZH5 zie*5ebE?aZt`BL2l3E>i#CSSJ(3}oNNCNVBXRdRZl<-YgS1|E%l$$r*=w%zeSt4Up zswdE|-|sy5`I&Q@sck8?TaB7e5OMwbMk#U|Q*=4MZ7fK~YR~;4L)EA9@JPdmvCxIY z^t;BEA@d(p8|QoIIoApD*SSk!{hAJG=LxbhC+!b*yzV3yw6R2{lbsZgI#Ft8s$ZOTLguS=Nyz4{LS3Wrc6V(8GX3&>Hh^UQo6hd_)1^YLOh(|WW{b31& zWpRuF>@MzSNvX7PvaQswRVTBMOR5_bVldtD{D4qng!$fFR{oni=%g$Y$)h|=?h$q# zl@<{#?=7$#@mpjsig>ds>@;QVPOXvHdR}kv)SX}4#X7owc8$S=j+(;Y$USN8g${H- z)O)xo*es-qczFI$phLloa$=$QT@I-Xf$$4$nQ<5kEMr}+bZ_>oC(Pk9b1gj`?+YvD zbt{2+o|~uRz_XMxmclrxg~o?|JI`dy<&tSS*YvgoP?$?aj9h71tS2nC9 z`6j;f!u!Yc!U9G8bNCF+I?`26rF-rt#Nanl8=1Uv#;$p6QO8<@$NNF0@o|SQ#=P1> zGsMEi`yEyg@YYnX`?2&Kp|?c-j>1qf7L&>66RzaXC-G@rm;^W2V=4HQjp%hOlF(0& zTY4m=Ic|=HtFo#P$`i_K0R213%=$-Egt*4IHjboJc-Q_weer#S!J#O9Z~5}ubRmj$)qyZx()L;q>we^|J{f9bLU^(cp` zta|4=1Q_Jj0*)OIsdB~()B!P~aX6{Nlqi4>Bpkdqmn7Ivl9*$dyh+KJG z9Gv|4pX3mtf|bBO>48Chxf}?>{~JmFF<`amyAlC^D{jHkQ5npsAw;62FIR-}v$ zNztFwpK%w6EMW9`ms3bkmeReE^%Xi3yexK`A6@SG6Vt7k8ph#)<3YccE_`+#{Ic50 z3?vP&>NQFhdBE)wHdV6Blp8q4@`)kQb+pywGeWGfR5Q5ia`^?GRskkEIZNIwJ+Duu zhvG%2<`Mwk=FNGV#$M$*KYn@842R&oFl%}1)W%6VRJmNaD^H|h&r)QCUq^C3HS)%n zrN^RFvfqtzUK&^n3>kE4ZSV~RoqmhiwW{r^S@cxwbjqPx@pXa8MBCh|&3+ey_5D;hWS& zZPy|tRZ76%b9m}A`ducb?D-0d?S_C^nd3;yNs<`Xw*4oKF2XZd-wxh7((efR*qvwj zP?*kt+;+IU~`5a&yzK*!MsTygd%U~FIX_$=K<98wV14jY%1Rd+c|P)?-ldr z-s2#Tl?ghd)hpG^!U?oi6Q#Hc@OI3!SXuU>! zpUUk$pRzJf8|KShE}pb5*6A70QKm6>(oT^QmM8X9dytYcI3p5BNCWN)=hda~C@hd; zdtF=;6UA~}){u}!*V^XJ;0D(NHkTq~>kQ<8`ZO>6HQJ*TYa1*IT3h~`ID}Xq-~^bG zLs6{NYa>^znPNWE+X5+(!6lVMEzU76i6L%Xzfwk!V6zliKtJ>_AuMM9&-BFrsO4_#f=Ja;C4LOF9e|}e{u;%-`)+T#! zl}*k>CTjZLc9eCRa(IcXzGEa@_6-k+A~t0jKX8v|{dNBhaS*}%NvGPF!QNdw(nH$xZ7 zFPv{Yc8xK*cR?Db*JWGVZXEpn&R2++&S{fL3ru|8zZF?tAHRaA?~rN!jx5$tH<&mZ z^)}xhl@s7{VdA^v)j4d|RI#w*AN2VG9PB?|E_G6Y|2m?ZIqVxx)V;M}V#|xcTV$}6 z0-w_?$@U<;FZVth0P5?>30Y3a&`vcuhtE0m0`D!FTPE#OV4gl;-qGLgfPRt7E{)Dg zfRul+kBykDCghP={_a;dPlT)iEHb)c91H7S+i%UAtR_J%TpTv-UI_Yq>j{wD^w2RX z<9;L2(5G+aA^4I>E>+LlUm(z#Sl>4al;_+XX#V3wPFK;H=8szPXMrd9&*%(- zLBYS`GXx}f^#czK1pcS0sMciOjlPli!eFf`Xy#@~ZpUIst#2eFUpkIQh&cWCN~OAZ zk0aMgj}Vp1v*7IfF0;D=b?V#w@$wKRr9_suh5UR(%L}6kOAAZPNIp`UV>X$h(Ay{I zVx21y1DHxnQdaam_#cx)zr&ue<}EHK%t?k`6BeaC>1~k5U++kcI);2y{g{tAr7CJO z($|pKgZWTeM!msyJ1?}ifR%LMDFZ9*I(wxJ`5~6*H7Z1BGl`7@7L`O;Fd7XL^Zsp2 z+@p1TdkcHU^(ZEMYGhf6@W!_xyTiOi8rII@x3}cDM;u5?WT}-hDD#N%5`Y4<9?3uw zW}MyxCCUD{Cp>w*9@ohF*ekHc77V@DFlo6k4%fmd7}2q%*FEkb{P-CAjpJx=9*3G{K330yh1?=J@dRj$O!S@z5k(+IG#t+_B7#mj+!6bTn4IHA ztN>eA19b|;i!x;9{TxY}R*&#ttO#_x6wr*KW)WUNeqZO)=ogs^Zn_(?qO{NN#tLjc zy>%%6_$$_<0t2}8A}Hi$gCt%E@Ni|khuYuMksuZ(wTK4iFCrgH2ot84RTjp3y-aye zVDC0M7f@4~ydd;kCt@E@xQErY*}`g#yoqw4P4&4-LeC2%f?S8^Ko<9+X!!MweUdnS`ilGRDv6mAgRYp+8+K~OT*PFAL3`%_ z+)kAZXZ;FoyJ)zSfj`IyP^!O8L$}=Bc!7D>?ZM)l6AEj)wJavi`3{o?=#{WO^e`+ zrS!>tsx6iv-=3#I!`OF*Q%WDJ6kng>rrEEk-KIQ@wB+;9e*K89L)JR$&w4+*?20@-YM9-SjxNU)tMEa7IIsRD96p%!W^m{I z_N_Y}UsLPNCAI}__;v$!pB;asC-I#}l2!wbz9HYt9qpV|&YNz1oOdy!-z~pvm9uX8 z_N{w+-}2y~du~U4dhxH6Ka69f6BF=vKAc*w`VF8Fn?o%I z^0zwdTz~M6qTrVNZveZ)>~{$HVH&YNJ@ipl(nt!R_iSm{27i$srW12JY~-sn0_g}qt+uAGg8D?(EF-;8}%&NNp#Qmz{T z5BN`;erWE$*R#JoxHGx-tr##&?r?DCI1(7t)f!B6d*~)dy3m7++BKfc0SR|nwN)nA zLyj+`*^15`YpR)@67F1}vJ8Zhp)XkNBNJ?PmA{gOO_0bPV{~GTBj;pj9jc4-Z>`8UigU_60SZA-@&ibSS z&9`EmzlN7}s;|QZ{lXhs{>Tkl;z>8Zv^-c7t^O<(`+*&#=)+d^b)O95L{a@G0yvK> zV#aloGguZ%unw^9OR#{O?rO}@8`Qc@;@8q<@vl$G^0;YL=|4^p-|tNA#M`aIp1YnR8gs zqTt+C)6oqq28ogSHKLqGI;q>eN!zIb1x`k}DK9ES>$fy`z9lD}^A5)`83Z<%ss;Ds zysef>L`G}$5~K%|@2F{LcNy$+PcJ#>ivae%f8waRJF+25>~gWpHCZ0|a<^kLIAvEX zYDQkOTX~*YZnI-_3SFFzF>rRFBu6+Ojx~zuBeu|G)Fj(mi>1g&2h|%+9%pgeK}#nq zpYV?PxHS`Q_x$7&&IJ#{LUo&a!P^D`5`F>DW8^)IXYxgk*ZNMXJqG7n2Ijza=esr*%`q)8jPhw{6JJhsq} zGq{d^|JsW{FY*($t2n8sN}uADO>W;Yxf!QTENY+_ARX&JtDg2+xAD`2ix?+1pYi-! zvbKFqSY}F?@wCs2I?TeYN@OfHU;o~nz4jrAU} z+L_J8uiRaB68=(ECsxuezE;|6mu2tVZ0|g4pFO%+$8pPSZq2522*GpQ)mDshdS$SY&=3Vdz`!}bPU(`?TA(_n@JPt0%Qp=E+?ACi%_r5VgFCytkW(tU{g ztBjQa!WK~4vYG5^zhl$8(!a?Lm)hw~BdoleO`+bn)L%K-+dHmMj%^1WCEnwZr0p6sxj3JjzI^$1>RhwSxlYYIE{?Eg{6>T5dW*I7u4YCX( z&s`6OOAwq4XOT|ltNfXJQAfk`#VM_fFbUereqTYmnAB%R5#b273!js{uk`a{JXr{P zP{=M?x{cyPZDYn2jRuwOCq0D!}!6Q zBC)Sr&yz{&WEffk`#jD{aA$`&(v4R}nVttM>#UfaOdZ^3dVHGFxpEu2sx89@UH;NC z9+Lj;b^C|@M;f}SyQ^c5R@?S?Z)K?>3w_KEl~xTs%+AN}mznm~MRu%Geo%JQS$L#-M6#*j<7s#q zZdZQe1>;3vdGd>ixU9-HOuFG_>X-MUgslp3I6ZOe#9OCv);>kXj~6{WQ!QG#-e`Jd zd@@(|c~Ia!@S*77j1EUoKzpwurrX8hZmmA^cp6-~ok+Y!8c)KQzEd#1DU&DO80%PU zVG47IVWDZ|yXhVhn;NahNDAklZ=FytonZg+vj&8EoBXqF1%e7)z3RP!{D;QXQ)871 zDnX(PZlk)=X~nW}IqWCJUXg~9F}JUolHJEX|9YP7SIlwD82Z4A?{2I_`?8<> z%BT!cV^;^h3<2k-1g;BXd?A${WUIAvKCs7=6nd|`Q`4j?14C~ll^&)a%MPU2V^_2t zK_pC8mgnoOQpjj@gep`BORL9*E4>P*)RIv)^6lV&;#^NQ%~!-INMdI9R+W9bzKlWX z$H7HRv3GNV+UtSdDweR;V~QxbRCSEyJWGtRaXps_W{wfrz38N`Osm-a$S2@!<$_HL zJRRL;y<%bMj)JfvY5z@0@=!!KNh!f|f|zPtW!(w9l-ri!8S>1rWMh^(`g;B`7E>}0 zXk&)*JEST(tzI|D3GR>s^Vc%o18Nf;9&+Cp!#YG`9-H*b%8#PNzji|@1m85tf({Dflw$PuhO8Hp4#7yZgpk(g0t-a5hWLqk zp$eJR7GO%JP!&C)&_z}I5Uod;DvBN_5p>zam<=VNdAo|VCo(Kv;rrK8l}M7R!Ed4} zrR!{D37!jDqntUJa-=O&>Wj4`BwU^-Q0Q8i<9pctE;`; zq`4R0Px`ac-FD}57pgJKMJ%#qX|Tzk7BCN0J**nagcZS4-tHqQ;U4jD@g%#1*=4Sy zedr?>Em#2M4&4H+Z^vC+Q{RqS%ryp}qbbwzW1P$+z({RVb70MSZdc)RS<;+MqqkeG z)1$sak&I#;vJ*@36Aqwp_ z=o)XkXh_NnQZr4Qmw6&S1Rm}CV^%7>ZNcOdv6w+WATjjm2s*51wRnedWBYncT5*+$ zWI^1)#kEgC>`pWkkvT~|R}A@dc;l*ySbRhuuBVEtZhL_ocvsDAd|mdl)f2sNd#am5 z(IYL>RRU~-`ED^H3$>U-B0pqzg`pwtSYIuXF^F??l5&HjF{q8f+$E$Oe_JJlQ#gFn zX+~6Z@?|#sxT43bI&+ku#pIB;DuTY^J7RuPEcdwAy=?Zt{#)0xsyKbR%n2M8x`&@| z&#RDbhc<_UE6`*Gj)!VFJfD4HH(G}4(rRDCwNoQOL7j)>V>+q;2Rl)^95qs*6&eWv zap%CPlf8ul=dO!yVS@8RuJ@yY9@UKF^pPyqhEnBb)?ed2+fxx#naFpX?=Ta?n{c?y zWLwc<*$wF@$!M`O+mu2qr4vSW7QEOBX?~9!MZo)qqI2IT%`^0^)nf9Q_mu}vnR2=M z$nyZOqY4zLKBD)NG$0#Q4nH6Jnz6op#1F?8ZZ40$lKVmvW)TB$Hw2FRL7)Tb-~X}k zy!h=j7SGp^7=`H;^b6yAD-i2J$go;#@WI#6ySO}b3kCV&0gl0br)xKGmP|Uh0Z1Z_ zp&8%LlVwKrA3qqoeoiQpsteBe?0^8*j4+ihTQ4|3jZFMa7GFMbf*u=Aj76(+*9~hS zGOlfL)i@2ff||1*>Is!?IzZVCv+VBVK=0PrJyr|$!C80B6@HW*b9BkR&aKt9{I(;q zkoW~pW3|tjIrPlbPbeV#n3%^to&~9&%>^J9PF8UhBT@OXreKW0&eynw0 zC;DkQ@RNV`_LjgIy^RO<-Hq(WD0?Vks1($nrYrr>`bunKF6m*W$)=VYA=Aq`zn4a| zt833C`!9Li!%*V(>8Qp$im34K_xxISdm;d?uP}YC5rU33=RjTmBQ@RlF%5xgd^4;_Vxfq-Bo)B2l{#VIF)&N0i)x-e9CG(y#vDt zB_5>-_bMdJl z`Z%bYL_gEK4|yep<6LwS|8$bxq}Gtirc8qL<j@R zQ}-jo=KOP#Vff2kQS8foqW-0mNO1c5gwt?8Q7a#&swR1Q^{8&vwR&=-Oe)3rzUEsd zO`6BW@y}>KJjMw#)4&u^`+x+JxB)M&S)jdV#CLo3FG~8ohwmQ2h|Mnu6Bn=Pm3oa& z`qLnP?-yPzgTNqh@oKd@c)wPEFQl$k1^ER~he!2?2*`dO{_}VcYYmmPA@1)hzoXr= zLftC_MV(x7YR5wUI{B*=FDeRj4 zt8#+?)GWO`9sEo{Klfjq`P1_qfHoZA=Iv<>N1$%j^mMb5v!gxQYZDi{i)Y!}Gv2`8{6(E2y)fq?&H_&<#r)dYv3O!EgWLp9YOhN%Yk zvb3@EvJ@9jH}S#{Lnlbj@WSAglR~8tIJ2ReCbNv2C!AT356Ei`1fmcN@qr*vL2Ds6 z4~haX2mllWfcSZVKw*fGFjRo~=Z8g{0QHnU?1dqX^8=Jl?v24fcm@6WN$2y%;Q9*y z?(;W*i!TP?FFRViF?ebJbO$rDpNq3ALfF#A-p$(AHr?F^<2t*PwWphvrI*wd%)rgl z$=2D;7l86zzz?E+piejU#sCxiaaDSv4+iYd|M&V}2qXVk7xi;-7glq#aj?BBYv~0S zze;+%ATTc&stX1QLx93i5H}De35nh(A)^H_Rac^%28(~XZC1-RSTiUMrpeqa0R0c+G$rk9)NZwBy7 z*UX}xHnze#aF4%2QOjvQ7>s}71O*WV{Bth~owe{kFBbi&cVQIYD4l>r0e=PjiLhS_ zK5$P2iU)BJ-ygfhgnvPQ9{53mEF59&>EM3F@^57SfNIOiixZ%fER0gK3rd&b^;Lct zA-L&e0T>}D=TQj3VB-Cmd?2u2BXp>6a%GiQ>3|s`bOqH0s9L((-G;kzChD=GRPh@~ z)6x!(V1@`@r9*9ij+dvmwU@3Z9Iox==Ecl^HR7WE!)awu4(se@2hewb`@%gnJ>j-+ zPdG~RsKcnNhT0}BPW(F&zajx@ww3`~Ku8dkBJD8-G01=4@GH|Kqq1*u$O(2$tDtPLsSt6X6A+W2G6~*??2&LqLlEz<> zC&0kL#tYZ}>Pi$3Yq({6fAH`taHDtt*F24Q?(xUc@5Kd*|MWz3^y`r&=;-w&=omnc zKbZVgF8?Pc6+A8P{;#etGZa;cz-=6?QSQeK0;39%f2t*YJ_O?yQUEFhk>wWz3rT^61m*dq zqy&Xzfc(-BDUg(uyc859eg~y9TQ`&`{?N(K3<3oM0l(Se56edB%E2Gb%n$zge#=lB zZVNCl0Wm|EL8vn5kNND{G%*!SDY6K=ua)VqZsvn+k;Y`g`1Dk<;-l>GkvuE~v@#Eb*~Ep_4aX#cv&%?@ zBC=mA*J;{qLhi|cM`pNQ2n6(<370Kl8x@RwhKFz0epnxdKv5TF88dxE>X=1eO7;w=ceKt7fzyE za>Fw(4Mn^Oc;`G*n67iLe&&VVbqszZSm%+`0d#v;Ir|X#F?sSNJn%Gf0I=dzM%Mnp z-2mz0isMhG+ru+Sv`=Z8a8tIXsX62Gd(jywJDkVaJM8pZ{MvUi?~O%UZ5SaujJ#PF z*9d%=o9DJJ89xgi<+|LOk5_OF$c2TKRn15g&s@jQqdT;4!JU#Svl_06^(Q{Z5RS}z zU_DrFGQJ*#D<{;BK950!Mkb%J`=ijk^_SnOsNn7C<%f!4!~`G#ewYx5n1G#KPD7rU G;Qs)L@*TJU delta 19359 zcmdsf2|Scv`?shpr6h@pMxvFO`@YR4Nr+T-*;*KkonZ{2a;KjqiIlRG5+zY8X;Eok zEKx~GDXofBNPdyhd+xCfbDsaR{GZSJc|Y$kGxwZ1%k{m^b>v^fzP2K-V)=W_ zW&6(~k*#^$U{{_Em(8}~aCjt?NqnEI=cI~bH2yW&){DJ?&9&gN-Pv5WzbmK%qf>}n zy1LR*Y=1X?V??#XTIIJ!HsA#N^GG!EN-wvdH6)BEMM4<-HsFb|vaE@dLVJlKA=nWi7ZIS8FzJ z4H@X3Y{L%a^<~iSdo$>JGa*orP1$ZVF3UeCfI#aSMmDe}8?r;ZT-jE}`k;CnmP-)G($|T7 z8VMp%1UrVPnXkNL@_r?88k0_ZS@g-NN_0rUgr0^em{1|vI@pCr*pCf2n9Y~SjOE7$ zY9;Hlg4p~V`UZx}mMvRg!1DES;d+sm`MYx5y!<`Lc3%EV{e!#)KNFb^*+H&cuK*s0 zOXBx2*$DUI2Js9$SzHo^0)y!LPHS@ckFXafyjC@%h zphA>v0)~Q@>r#IYUp5J+ke3Fz5;jDqQh-+bt~F5b!GIO8obBb|+4t4b5D&gcBr1xK zO1QZN$H00}|0C^*qBFakn5 zMqa*b6d>l?fnfI$W;qP;pxu)7P03~)t{=;n?8+h`f`teR{-=cu@TJ2`5!OAdRKNWX z8UlY5^z{xHM^th@SmM%vUvu(<{tzW|Oup=So!1lT(_fa43s z9ZA-m0v;5ZtH0H9xKxguJ?7pE% z^aM;`83Bp;0uwSyASlKkNEa61qRpcPWE7fx|EHmZ4jW2FU?{C*dD;By0}1Jy{Qkj6 zVp4}jQvaMbG?Ms5hbeRTARRW8h9rXyBnmz-kQh|v&_F`85P^Y2d^I$Xz*rd?NEABb ze;P=u*eqgJArbZU4=Re_pwgn_Bn|K-uptZ~fp$iWDgJaLI6U|qAcTF;%!#>kcZFGNFO8G0qOZy!=x9Sh|RgU8=DJyXzoBez^$-idw2!$xM6db z0{?(b_!+?g0lsWMVj396PyA+tI^!SA=|k{`86rL~r4P>N|91@$@1Nea=>Mi63Qg36 z*Yt0AHvRq#4qTf7C+A;rZT{Py4G!%6AG$V3pBFjIxA~7|9wOLe_F?UZ&c7n|KI2s8>VBT>LDG|wP<`h?xEe6643D= zV+^bi{y(&1J`?`8bgVT@$AgqgEQBNw28~ZcMZcEXiwh`Okl6T(p8pS(+`rTvT5SGr z44FDi$%D(4J|!be{?|pZCf5X)k5P`d3z-1Fxb9?`Y zn2LCbxQcK^I3hvd=`O+(IVnOCu>;p!5jSv!icmxl5!yf@FOI(N6+yw1 zu0_YF_yP)J4uvuYfx>nRMO6x2{brrc_Vf zNd8NDMdfwurO{>Sy6&GD2J3Bu^U5?WE3((@+&y9Dj~52pQ;!tZ=%h24)O5_tgCm_&&(XYV3osXw}U4|mn>hU{J^;6ePrg@12=V=!;J3AC5AE%`EF;-&0i6ypLg!A>Fk1p z5bHLEI&}=b$Sb}wn&B0DW{ghjmYFw?EJowSu#B{8rnPkfKzmDaXE68a!m)m3J%PZ>M=en^*@0o0(u#@{XrM)XygjRj1c}9)BEJO}+I{ zzRo-GG_qi0OyQMCs`KoYT^Ux_B~LhwdA|*vyG)%VzG4)!diL_Vs>fR1d*mEFv(sDj3ySx2 z*^17?0^Qq;lN}D>dHSo}<9+HTyb#^Huyt;LmwLUPCc0+S%SGdUPcM?SJony3=@mflO)DBAWNQE$~uWBk1vw)kd!}} z-J~;Nb@prP8<8}rgOhbKM-}K>%+_5$(OFArj^PJ!|H-l)Vt=G?Nw?M4^~bhr%O+}V z6E(D1Nb)*9>eTf)b0VbtC?!ue(@pvO7bJtyZ{4%06KH>(^CBR0H)qT#Mdq{a88w>rvlvztl=kh|UUo zq%a{xXOwEWxt@iRa?A`o`;65N!@CEfw%hC)ukIoDOUlD$s-s)&>xH~XkL5Nw%;U1> zX7!9IN`1yDXYSq{GJ9Q!d}e!-?7`@rzowi&eD$G|-uh)T(^Mm>XSZfJkFUCrG^R=X zOH^hS<%r~_(fgL}i~MRc?`KSUx8~w$~YY2>-FYSnBJd%eRe>cp{Cs#^{Bt;l|+Y4Iz-XmO5Nnxf95HamuT#lGMQ z&yJ`P-!Khs8TFdxzw3^|1Mi zfBPSuQl`AfxVIuDHX^6lG^O#;`|uPq)6{cvzE$$lZ{tcBKZ{I#k-1`teiPHhe~&(R zuXjm@^epl7%QbrzX(Y2}RinQ1RBn`Ad2r@>%A5-kdnO&IU*fplI#TKPa_aykT*<`R zNolc(^|=}AOs0-m>cz87teh&9>Y7}2bfSkdwLp4ZyYEx(^n2gN9$o79#6i;i{oLcn za%;VRZp-DkIq9q3z$)U)3sf4fqjukeThorG<;2joc5J-CP5qkm$2HS+b!YO^zAD`$lJ1%y6* zm@Ky6fmY6NJ-%|{m^h94KyUeya*%jrqDSRY7xV2AisdTYDIUJ<9`hBLZcXjGl--+Z zc1gtON_RJ2IpGttS?hfZm<=#`1c4wIzL{+amR~XVz6J{N!bef)^L1q872ZfK9349u5!pfj#pP{@%s6~Dd|&!}Z_jbt=a$|5DXLa&kfoLXVp7E; zye!cpW$8F=pO7U=YLzmNEw|`)zi(5j*_Yco@zjJ@N)cV}Qs2FKQuB^;DpR*7;8$qZ zr&6!pAH1%wU-o2n*T3rhmHTZ)lHK~>+zohV?b8iEIDfvq+JGPEy6S!PkIU}U)QAJT zj;gcTZ0sPaaA%KSi)ov`UxmLxg?8@e{qy!e!RN(F&#TYi`X2pko0~y9@;Rs?-vn8t zS13KBDB3mO1igIF&0Fl=T2{LEqsoHZ^yk+xyU?Ti41-$Yj?ySqQ;z1TKUp8Kn%dm> z>(j4K=M%4Fyt3dOGa*m4%hfPBUOYvQKFZ%scW=dqW0K~pCf{m#l74#Qs24F-q1JBI zx^|^(T)sBmrf!_f57A>ZMgPb8lU6u&r7;fe^*jFjqN2qqT9J{AcF8n7&&e%~(28Tcc0QKJnJLtdFp}fJ@3fZQ1RW>;Xz0oD@Y1Gm?4k zK67c40xpu}_X{M9F_H=CxbgMFUoWe~>-`UaPgq6B5l<0TvfLDtojG?(QzI5mD?esg zU1sBW-9~G{UU|wCX_K7Gdsd9wC1tz2!C=&iF?Y^4N4%@gs|pyKY-?8`zt^>HzQ?61 z|HLn+zT)xc%bBCAKh(+??q6#l;};^m^m`>!q?-0o=61y4pTCVd{mK=$)^TjEy*hUF zOPzsCPuQCu9kb3(&sN#?+eo@6VcOr*sh{cIb+bywZ>h>LW$o}uA@97H_-b!TG^@bj z>M9S#%@#R(U1qPGcTr9Cfck?;b1%3#FPA(m>%4l4qV;^dyHR}RM~U~=$sUsL#m_mn zY^@5|qgltgm%I9NfY~Wd=a?+FfXQ2*CmhvL?~&3Sk6poHSs0?Sd=Xq-eIt@N>;#qteJsAzTd?n&DwI2e(hyIn+R=*MQe z9J8FrU1gIEUfPcBUNrlR*x~PfV|VDKou|E+>s)4impjkupw?aM8rsi^e2abn!7}rcxdwe)!llz9c*Pn2O*H4|!v!a~TYRJ=H zx7^Cj$WA`B&;ERT)(btk5>-D{nf?2iWSt#h=UM*U7f#oQ+`e}zRl1(lDRKMg!KA1H zo4APw?(PQA4!%8aPzhvKF(PTNpo>;})s7{t%~hp}7A~93q}u2Q<{P~&(RwSJY9*Uy zC7aGw8XMDIm|ckL`W$>_d*X_C8#MUt#8_WwDWg) z@f{VH^=J2XOsc<{CH~gDuAB(bt##;Uk!Nq+oF#Lc9o&`6WKLxN(r|2RLxOXNYB8>Uvp_|>{Y{DgoTqu?qdum;%gOTmxT@f3bMbVQFGd!As;@lj zzo9u+8u}M&%J4bHEnjl9)n`VY?ooMuR&i?+;wCc7_jF=~kIe0bD7I2x)A6mwrMqji z-n4wsHV(A(3z%aYFvr8epav;W&`a~;vgoPoq`hvAE?nZj*4E2ukr(>8 zc2ZGfv}u;AzL-p5=`HEM{1%bIb!Kd7Y7Y>}F1Z=B?US=*m`5ljSFY*rB7%Mu^cP! z{zSH}N+Lfl;N6(H; z7PoiRkFI(UYZzPc>dm_n){J2B+wy*xtPV;Ief;5YI(>Zh*DXyFH4?YgX=x=Nt-I%! z@7LXXDerK^fwj`B?zE(biDY|ZjoOyzvP19t4jqwduUlXc>pY`e^ zoqD`99nosmH;LQwcQ9E);@@%G(aeeSHL-IM25~E>OZLo3zj5x(x|d-dzn4cpOK{$x zTC8zS-ExlgVY3e|H3t@)cw-tALOLSdC>a)X1Gm~8@XXce=J@ZEHvS4N+?e~#EQUEw zDWtCRm8N%m;6;SB&i*mh6yF-FK@J{|Z}&Sf*SGYWn9LuOP*|Bul;C6K8|B3cY9N>dstoCiru)*?tZ2 zXRSq=Z&L%~9UR5G586G-On&k$^`|)n=yo}&8E(hf8<|ICm)D2!?bfCdPtc5y%oogCZezohU zVCO4|{!fv&+IRO|IC$SUeY%F2f7rNY?w-9-yPXubI$z4OSOt zj4}SSPFn*%_c7^$o~ChN(7fD9`stSz+Ei$SCtpz4G!8qdS%19VC_Fu$T!P&{aRFOk@i_U6Sh zUk^4cd2z4vT}{uQ7jI@e{cd^F{xMToIYPIG-1_V1*U(Ka>X{Q>y|@ywDKzBw&JA6E zKL5;YZPnE&*&OojN$d|!;)8=4&94hD?A$POV&*lxr(SjYx8CMk?QPN8zuvu3wf_CR zxASsr>4~3K6JPcI-EN0(>RR>WmO2u5zh2wp@O!@lMQe$d`QRmU|EK!PJ4>DLg{dBD z+aHX{+ilDXv5>$6o*1XutO9kDA6#ulQ!R&)TWSoK9{?9n+G# zto~!IqsB>}mdzK>bmvoN;%jGad^zrPypM@TKtaPrx=QnHHu;w3NpkAfb)80L3m%Wo zy(?;dyg+j*CvV!6MV;$E+&SksBPX?b&29tq=@YeF&4(@tTj_pa& z;;-QvAD@sfx!nt^&g}^de0fl1^VjF=%#yEu`gS1kOY@nJuim}Av^enZOA8$Eo$i6_ zu00^s;51*{bftUZ}zW_OPQ@xpQa)=T3RE+01L{yc1?aWZu#Gg#zs#OJO%!S-uQ z?*zBL^F(a9Kkd2kKG%vT#JB97X@~dL{1G{<(`Cv(vmMyA8wiF%sDm5&V6Wbsyb5e= z@?Xq?{apA*r66*{pFOl+h=Z^#hG6`~zfeY63e_6i)Be|*k(TO<%R;d_~+jP8I;9=-~{%f7MEudg1H9w zOo`p&RHpPOc~DoZx%8+D=F*~+z@csWz9Z>=7!+`V4i2@~kx1AYAS!Xe7`Q;FgI9fN zM23I%Bx(Yc_En{Y3|!H0TL0y6@PoVA{BQd;+SiDnLWzcnzkfjhex8B6Lv`Romjjgz zrTp_NKAxc%gTC-Sz77WtluX$?mK%r`91Ml9H(fNx>7oB zuG+4BTl~5@L`G|Npl-6Ft@8Z7a>Pd+vS6lvP+eJHi=EbtWV(%Z@<%?KVq>;Wkre3 zNp+7BRS{iB;-53nnf$}u0m(u$sI`)3R|U_w-rln@+A#i+{-RTxoh;sj&62Z{)Uerh zW)Ib5zx=5vt1Q{QM;1=WN%(uSliZ5!R$ebrGXogCG2`nl6g+O3p2(KT5U&fldSi~mws(5UR^v*`1d z@MAmIomLIGiQo6!wytpcv_o#e}iiH6o%20`x)sBM*9MJFk};I+04FQa+JhcL#LW-r!0q?%|jXU5LS0kgE<&E_qo z^GeHO_L1MpWo)kr7#seYml4;{6t|us?vXX|=Ud;5_=qNa=O~43Hy9KDqKuv@rptRyP6U21)) zPv`|k?CRA)q2ip^ekE}i+H_N1FWwZDV;|GlB{I`xOs%t;?%g@|(NDVMGT$uPlt^w< zt9`p*Qv#<=BjWlG``DT7SnZ-Y-xk%GcS&D+ZTBm2NxL}hwbL&=`da(M-VW)o=?nZC zr#z{8cvq$}>4D50@C5G`y&(7IwUX_+andih z8-8D4h4M^Y>aO2zdvv>Lsl(q((wtuuLb*K@#6e3-QNRF1!CU_WL`~DERE$a@zUqGv zflb7NafJVG#Vt0 z4oPD`(jeBa1p%Uk;KGH07KD&!L6B$-N5U5x_`kwsAwWP}USB?3V0;1t5iSft0)~@N zJ}RV3s1P7v9WbmcU;n^Bh9weEs1PJzcnaqmKq3Hy3IRfe0HIMxVE!2~OVJ=mz=#me zHv$PEG#J~$`5-`OgFwJKhbTxqKv1c0VF(g%6N*qiaQlgH8UzS^BoIRXbO;hU1PL92 zgg%I52nd*vgoS|s0doqNe@3VuOt(UX84x6lkw^d#Fa-;jg#cj;0l^2=&wwCdK#(vX zNWe-}s9`1q2vZ0M&_5G`gb6_c=5*mkhL8*bVM2f~AwZY}5PXFCnZiiGQc|d41kC*- zg+VC7KtKRGB%c6~zWEnW2}KwQLJ>xSfW^0P!@^yHP#{2nZ!oefj(|I%MkXTQUI5`V z2oez2E}Rbn1jLgI=i>vxhq*`ypikk95F{XkS12EdOBGIo06_(T^y?qoeFG^BK>{{N zgd2f$30Q6k=Ys&jA^eU&_#J`pI|AG*p++zW5D2{^ARLV-3;drU;y^G65)6U_gCK$M zJ8=t!kbuMKy-)uLgx?VezatQSN3{Ek5Q9r(s05Mx>h zZKO{~xV-(gg$t@5!tV$b(j^dn2R`(Oh6x`UGD=3!J753cBpXr~Vq6e@N5BF`sE>#E zeUKFq2)zT%2>X8sgx?VezawBpB-F4FzXL5m=pDp=_Lmj#{}2ejBM^Q^ApDNdA)|!g z_Yw4tjHGu${|JQN5eUB{5PnA(14slcU4Y*QSP`shAi~gv{XYc4?}!kWgQX{NuLbcK zT)+Sz!u$@>AhtC`??e6{0^xTMEi5cGgx?VezaxBpA5QOx5WNHaqY!>aA^Z-4hlPYe zA^eU~gu4WV&^t=d`$+!}h44E{5jHLq!tW@A-%$v?qXP6k=>MVM9=MU#ibD7u1#5rd ze8R>BmducRLO^f|VMsz1Liiml!Xfz}T{4W{`6fz1A@mNyz(IW@{6FFVL|7OI5(vMe zkUbw1Lhq;`z4!4SFhU5wqY!>aA^eU)_#N%%cR_jwcc==1!%+yoqY!=vwj~Kw4&iqc!tW@A-%$v^qa*m8P#g-OcNE-8PY5&2|3e}Cjzahy zh44EH;dc~xK0=6x(|e!(i9Qy}2;p}W!tW@A-_b#SA7VwY=>};7hx7@A-%$v^qY!>a zNAf$Neh9sz1N1KF|Dh0mM%A^YWe<+0CQ3$`I5PnC6_?_556}ByGklqFSKMca}7=+(32)|{Ek8R9fR;Y2H|&1fZqrFKMX?e7@&8d{XY!C?-*qLjzRdH*!>ln+5WNHaW8hFhxDf~v2)~0Hw}i_I z@;lM#;DJHt9V6&{r2mIO_#K1rI|ku*48rdigx)a$dLQ)vFbKbcwW}~X2)|