From 7703a266bf05a021f9f72916c9268caa468f31dc Mon Sep 17 00:00:00 2001
From: Song367 <601337784@qq.com>
Date: Wed, 23 Jul 2025 15:55:48 +0800
Subject: [PATCH] commit list
---
 README.md      | 185 ++++++++++++
 package.json   |  21 ++
 server.js      | 224 ++++++++++++++
 src/index.html |  82 +++++
 src/index.js   | 767 ++++++++++++++++++++++++++++++++++++++++++++++
 src/styles.css | 437 +++++++++++++++++++++++++++
 videos/asd.mp4 | Bin 0 -> 20272138 bytes
 videos/jkl.mp4 | Bin 0 -> 2592923 bytes
 videos/zxc.mp4 | Bin 0 -> 5934521 bytes
 yarn.lock      | 802 +++++++++++++++++++++++++++++++++++++++++++++++++
 10 files changed, 2518 insertions(+)
 create mode 100644 README.md
 create mode 100644 package.json
 create mode 100644 server.js
 create mode 100644 src/index.html
 create mode 100644 src/index.js
 create mode 100644 src/styles.css
 create mode 100644 videos/asd.mp4
 create mode 100644 videos/jkl.mp4
 create mode 100644 videos/zxc.mp4
 create mode 100644 yarn.lock
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..e43b18c
--- /dev/null
+++ b/README.md
@@ -0,0 +1,185 @@
+# WebRTC 音视频通话应用
+
+一个基于WebRTC的实时音视频通话web应用,使用WebRTC技术传输视频流。用户开始通话后会自动播放默认视频流,当用户进行音频或文本对话时会切换到相应的视频流,交互结束后自动回到默认视频流。
+
+## 功能特性
+
+- 🎤 **实时音频通话**: 基于WebRTC技术实现点对点音频通话
+- 📹 **WebRTC视频流传输**: 使用WebRTC技术传输视频流,而非播放本地文件
+- 📐 **固定视频比例**: 视频播放框固定9:16比例,适合移动端显示
+- 🎬 **无播放条界面**: 隐藏视频播放条,提供纯净的观看体验
+- 💬 **文本输入识别**: 根据输入的文本内容切换相应视频流
+- 🎤 **语音输入识别**: 支持语音输入并切换对应视频流
+- 🔄 **自动回退**: 交互结束后自动回到默认视频流
+- 🎨 **现代化UI**: 响应式设计,支持移动端和桌面端
+- 🔄 **实时同步**: 所有用户实时同步视频流状态
+
+## WebRTC视频流传输机制
+
+1. **视频流创建**: 将本地视频文件转换为MediaStream
+2. **Canvas渲染**: 使用Canvas将视频渲染为实时流
+3. **流切换**: 根据用户交互动态切换不同的视频流
+4. **实时同步**: 所有用户实时同步视频流状态
+5. **缓存机制**: 缓存已创建的视频流,提高切换效率
+6. **多用户传输**: 通过WebRTC技术向所有连接用户传输视频流
+
+## 技术栈
+
+- **前端**: HTML5, CSS3, JavaScript (ES6+)
+- **后端**: Node.js, Express.js
+- **实时通信**: Socket.IO
+- **音视频**: WebRTC API, Canvas API
+- **视频处理**: MediaStream API
+
+## 安装和运行
+
+### 前提条件
+
+- Node.js (版本 14 或更高)
+- 现代浏览器 (支持WebRTC和Canvas)
+
+### 安装依赖
+
+```bash
+# 使用npm安装依赖
+npm install
+
+# 或使用yarn安装依赖
+yarn install
+```
+
+### 启动应用
+
+```bash
+# 开发模式(自动重启)
+npm run dev
+
+# 或生产模式
+npm start
+```
+
+访问 `http://localhost:3000` 开始使用应用。
+
+## 项目结构
+
+```
+new_rtc/
+├── src/                    # 前端源代码
+│   ├── index.html         # 主HTML文件
+│   ├── index.js           # 主JavaScript文件
+│   └── styles.css         # 样式文件
+├── videos/                # 视频文件目录
+│   ├── asd.mp4           # 默认视频文件
+│   ├── zxc.mp4           # 示例视频文件
+│   └── jkl.mp4           # 示例视频文件
+├── server.js              # Express服务器
+├── package.json           # 项目配置
+└── README.md             # 项目说明
+```
+
+## 使用说明
+
+### 1. 开始音频通话
+
+1. 点击"开始音频通话"按钮
+2. 允许浏览器访问麦克风
+3. 音频状态将显示"已连接"
+4. 系统自动开始播放默认视频流(9:16比例,无播放条)
+
+### 2. 智能视频流切换
+
+1. **WebRTC视频流**: 使用WebRTC技术传输视频流,而非播放本地文件
+2. **固定比例显示**: 视频播放框固定9:16比例,适合移动端观看
+3. **纯净界面**: 隐藏播放条,提供沉浸式观看体验
+4. **文本输入**: 在文本框中输入内容,系统会根据关键词自动切换视频流
+5. **语音输入**: 点击语音按钮进行语音输入,系统会识别并切换视频流
+6. **自动回退**: 交互结束后10秒自动回到默认视频流
+7. **手动控制**: 点击"回到默认视频"按钮立即回到默认视频流
+
+### 3. 视频映射配置
+
+在 `server.js` 中可以配置文本到视频的映射关系:
+
+```javascript
+const videoMapping = {
+  '你好': 'asd.mp4',
+  'hello': 'asd.mp4',
+  '再见': 'zxc.mp4',
+  'goodbye': 'zxc.mp4',
+  '谢谢': 'jkl.mp4',
+  'thank you': 'jkl.mp4',
+  '默认': 'asd.mp4'
+};
+```
+
+### 4. 默认视频配置
+
+在 `server.js` 中可以修改默认视频:
+
+```javascript
+const DEFAULT_VIDEO = 'asd.mp4'; // 修改为您的默认视频文件名
+```
+
+## 添加新视频
+
+1. 将视频文件放入 `videos/` 目录
+2. 支持的格式: MP4, WebM, AVI
+3. 在 `server.js` 中更新视频映射配置
+4. 重启服务器
+
+## 语音识别
+
+当前版本使用模拟语音识别。要集成真实的语音识别,可以:
+
+1. 使用Web Speech API
+2. 集成第三方语音识别服务(如百度、阿里云等)
+3. 修改 `processVoiceInput` 方法中的语音识别逻辑
+
+## 浏览器兼容性
+
+- Chrome 60+
+- Firefox 55+
+- Safari 11+
+- Edge 79+
+
+## 注意事项
+
+1. 需要HTTPS环境才能使用麦克风(本地开发除外)
+2. 确保浏览器允许访问麦克风权限
+3. 视频文件应放在 `videos/` 目录中
+4. 建议使用现代浏览器以获得最佳体验
+5. 交互超时时间可在服务器端配置(默认10秒)
+6. 视频流使用Canvas渲染,确保浏览器支持Canvas API
+
+## 故障排除
+
+### 无法访问麦克风
+- 检查浏览器权限设置
+- 确保使用HTTPS或localhost
+- 检查设备是否被其他应用占用
+
+### 视频流无法创建或黑屏
+- 检查视频文件格式是否支持
+- 确认视频文件路径正确
+- 检查浏览器是否支持Canvas API
+- 查看浏览器控制台是否有错误信息
+- 使用"测试视频文件"按钮检查视频文件是否可访问
+- 确保视频文件在 `videos/` 目录中存在
+
+### 连接问题
+- 检查网络连接
+- 确认服务器正在运行
+- 检查防火墙设置
+
+### CSS样式问题
+- 确保 `src/styles.css` 文件存在
+- 检查浏览器控制台是否有404错误
+- 确认服务器正确配置了静态文件服务
+
+## 许可证
+
+MIT License
+
+## 贡献
+
+欢迎提交Issue和Pull Request来改进这个项目。 
\ No newline at end of file
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..0f44d8e
--- /dev/null
+++ b/package.json
@@ -0,0 +1,21 @@
+{
+  "name": "webrtc-video-chat",
+  "version": "1.0.0",
+  "description": "基于WebRTC的音视频通话应用,支持实时播放录制视频",
+  "main": "server.js",
+  "scripts": {
+    "start": "node server.js",
+    "dev": "nodemon server.js"
+  },
+  "dependencies": {
+    "express": "^4.18.2",
+    "socket.io": "^4.7.2",
+    "cors": "^2.8.5"
+  },
+  "devDependencies": {
+    "nodemon": "^3.0.1"
+  },
+  "keywords": ["webrtc", "video", "chat", "realtime"],
+  "author": "Your Name",
+  "license": "MIT"
+} 
\ No newline at end of file
diff --git a/server.js b/server.js
new file mode 100644
index 0000000..6057d2b
--- /dev/null
+++ b/server.js
@@ -0,0 +1,224 @@
+const express = require('express');
+const http = require('http');
+const socketIo = require('socket.io');
+const cors = require('cors');
+const path = require('path');
+const fs = require('fs');
+
+const app = express();
+const server = http.createServer(app);
+const io = socketIo(server, {
+  cors: {
+    origin: "*",
+    methods: ["GET", "POST"]
+  }
+});
+
+// 中间件
+app.use(cors());
+app.use(express.json());
+app.use(express.static('src'));
+app.use('/videos', express.static('videos'));
+
+// 存储连接的客户端和他们的视频流状态
+const connectedClients = new Map();
+
+// 视频映射配置
+const videoMapping = {
+  '你好': 'asd.mp4',
+  'hello': 'asd.mp4',
+  '再见': 'zxc.mp4',
+  'goodbye': 'zxc.mp4',
+  '谢谢': 'jkl.mp4',
+  'thank you': 'jkl.mp4',
+  '默认': 'asd.mp4'
+};
+
+// 默认视频流配置
+const DEFAULT_VIDEO = 'asd.mp4';
+const INTERACTION_TIMEOUT = 10000; // 10秒后回到默认视频
+
+// 获取视频列表
+app.get('/api/videos', (req, res) => {
+  const videosDir = path.join(__dirname, 'videos');
+  fs.readdir(videosDir, (err, files) => {
+    if (err) {
+      return res.status(500).json({ error: '无法读取视频目录' });
+    }
+    const videoFiles = files.filter(file => 
+      file.endsWith('.mp4') || file.endsWith('.webm') || file.endsWith('.avi')
+    );
+    res.json({ videos: videoFiles });
+  });
+});
+
+// 获取视频映射
+app.get('/api/video-mapping', (req, res) => {
+  res.json({ mapping: videoMapping });
+});
+
+// 获取默认视频
+app.get('/api/default-video', (req, res) => {
+  res.json({ 
+    defaultVideo: DEFAULT_VIDEO,
+    autoLoop: true
+  });
+});
+
+// Socket.IO 连接处理
+io.on('connection', (socket) => {
+  console.log('用户连接:', socket.id);
+  connectedClients.set(socket.id, {
+    socket: socket,
+    currentVideo: DEFAULT_VIDEO,
+    isInInteraction: false
+  });
+
+  // 处理WebRTC信令 - 用于传输视频流
+  socket.on('offer', (data) => {
+    console.log('收到offer:', socket.id);
+    socket.broadcast.emit('offer', {
+      ...data,
+      from: socket.id
+    });
+  });
+
+  socket.on('answer', (data) => {
+    console.log('收到answer:', socket.id);
+    socket.broadcast.emit('answer', {
+      ...data,
+      from: socket.id
+    });
+  });
+
+  socket.on('ice-candidate', (data) => {
+    console.log('收到ice-candidate:', socket.id);
+    socket.broadcast.emit('ice-candidate', {
+      ...data,
+      from: socket.id
+    });
+  });
+
+  // 处理视频流切换请求
+  socket.on('switch-video-stream', (data) => {
+    const { videoFile, type, text } = data;
+    console.log(`用户 ${socket.id} 请求切换视频流: ${videoFile} (${type})`);
+    
+    // 更新客户端状态
+    const client = connectedClients.get(socket.id);
+    if (client) {
+      client.currentVideo = videoFile;
+      client.isInInteraction = true;
+    }
+    
+    // 广播视频流切换指令给所有用户
+    io.emit('video-stream-switched', { 
+      videoFile, 
+      type, 
+      text,
+      from: socket.id 
+    });
+    
+    // 如果是交互类型,设置定时器回到默认视频
+    if (type === 'text' || type === 'voice') {
+      setTimeout(() => {
+        console.log(`交互超时,用户 ${socket.id} 回到默认视频`);
+        if (client) {
+          client.currentVideo = DEFAULT_VIDEO;
+          client.isInInteraction = false;
+        }
+        // 广播回到默认视频的指令
+        io.emit('video-stream-switched', { 
+          videoFile: DEFAULT_VIDEO, 
+          type: 'default',
+          from: socket.id 
+        });
+      }, INTERACTION_TIMEOUT);
+    }
+  });
+
+  // 处理通话开始
+  socket.on('call-started', () => {
+    console.log('通话开始,用户:', socket.id);
+    const client = connectedClients.get(socket.id);
+    if (client) {
+      client.currentVideo = DEFAULT_VIDEO;
+      client.isInInteraction = false;
+    }
+    io.emit('call-started', { from: socket.id });
+  });
+
+  // 处理文本输入
+  socket.on('text-input', (data) => {
+    const { text } = data;
+    console.log('收到文本输入:', text, '来自用户:', socket.id);
+    
+    // 根据文本查找对应视频
+    let videoFile = videoMapping['默认'];
+    for (const [key, value] of Object.entries(videoMapping)) {
+      if (text.toLowerCase().includes(key.toLowerCase())) {
+        videoFile = value;
+        break;
+      }
+    }
+    
+    console.log(`用户 ${socket.id} 文本输入 "${text}" 对应视频: ${videoFile}`);
+    
+    // 发送视频流切换请求
+    socket.emit('switch-video-stream', { 
+      videoFile, 
+      type: 'text', 
+      text 
+    });
+  });
+
+  // 处理语音输入
+  socket.on('voice-input', (data) => {
+    const { audioData, text } = data;
+    console.log('收到语音输入:', text, '来自用户:', socket.id);
+    
+    // 根据语音识别的文本查找对应视频
+    let videoFile = videoMapping['默认'];
+    for (const [key, value] of Object.entries(videoMapping)) {
+      if (text.toLowerCase().includes(key.toLowerCase())) {
+        videoFile = value;
+        break;
+      }
+    }
+    
+    console.log(`用户 ${socket.id} 语音输入 "${text}" 对应视频: ${videoFile}`);
+    
+    // 发送视频流切换请求
+    socket.emit('switch-video-stream', { 
+      videoFile, 
+      type: 'voice', 
+      text 
+    });
+  });
+
+  // 处理回到默认视频请求
+  socket.on('return-to-default', () => {
+    console.log('用户请求回到默认视频:', socket.id);
+    const client = connectedClients.get(socket.id);
+    if (client) {
+      client.currentVideo = DEFAULT_VIDEO;
+      client.isInInteraction = false;
+    }
+    socket.emit('switch-video-stream', { 
+      videoFile: DEFAULT_VIDEO, 
+      type: 'default' 
+    });
+  });
+
+  // 断开连接
+  socket.on('disconnect', () => {
+    console.log('用户断开连接:', socket.id);
+    connectedClients.delete(socket.id);
+  });
+});
+
+const PORT = process.env.PORT || 3000;
+server.listen(PORT, () => {
+  console.log(`服务器运行在端口 ${PORT}`);
+  console.log(`访问 http://localhost:${PORT} 开始使用`);
+}); 
\ No newline at end of file
diff --git a/src/index.html b/src/index.html
new file mode 100644
index 0000000..b5f8049
--- /dev/null
+++ b/src/index.html
@@ -0,0 +1,82 @@
+
+
+
+    
+    
+    WebRTC 音频通话
+    
+
+
+    
+        
+            WebRTC 音频通话
+            实时播放录制视频,支持文本和语音输入
+        
+
+        
+            
+            
+
+            
+            
+                
录制视频播放
+                
+                
+                    未选择视频
+                
+            
+
+            
+            
+                
+                
+                
+                
+                
+            
+
+            
+            
+
+            
+            
+
+            
+            
+        
+    
9j(31h%TN75jGwkSoKz<5Xlsx$
zx_#P!;Ag}gep?QTm@ulf(w6nrzE}Z#*S<F!INl#%I9nv7?09Q{%0`xuztZ1q|PmiCX-W2(c)Ow|l4bZ7q7%
z54|m*&!E4!`IC>0F_O{=2!v
z{YP4TV6fS8Y4b+2M&NGwXC6ambDo9eOn*zV?gQCIx{giZ%_)t=%Rrf*&HCVrEW!H+
z6b>hj+u`!b6Of3zPVz5J!OjDiI7unrFD>gSh@IV6zAMkAcs1`SVdKS0(l8Nv7;0v<
z&>tsNCRR{bn|L%!a0{%%984ym{W3$O=aP+B@C}C@YM9n*!Oa
zin?(G16oQ;ts^B77)2&Bn^CjO+0YjY5J^A;n^nE}8i*R?Z0U(#+Fm4yT+8&@Tg52*
zMd*ap{oht&?kyi$L*4*MWeYe}=*P+1(tMgmaf6Ns4Pr-uslQ?(Ftsf=VPr*_hj+xI
zGCuN2rARmXT^ivi#uI`!e^~cH>w=3pd;~jUQP0t&IB~is>9kEWP56GR-ulLB(=FQw8?c3
zjsS27M~a_2*(I;8OT@yN&atyBggd-6&>${VwmX?ni$(
z&SPxOto`}v-b_3Jcj37M*|W(;JN9)2f9G5&W1QcmVd@o2|
z?+GotX$cM5DF-VzRZ<`3;Fu$1{X^qnAI(p;J}BuMSa?SlToFc3_e%o!_zn-F9r36&
zt{!EFBq(1P&R(sWks@MTYys1p;ACaG@&~+jNv2$vGW|RR
z8AyDb)yhG8;ameVPKO|N!pIl|4RdFUIvBo$?8>%E^DyF06jQF_Sh}rUZ|rDDNI_mv
zdaUZWWh)OMyes{dV~YszA8&REh~x6aP^rOHklTa2jly0!q<=$1pc
zvZ_~XJ}eP!7Rwf<3O1usXT#a?TkyUdG7m<3THTEd=j$`2GF9y7V(tI^fiQup4Z1CwC6T#r
zHrW|d;ZXv#eHu9Vc!|IGOeB1$z;zE7f)LNv`JUOkNzwn+o;hQvqb4SnkgT+BWLuE?
zzEwg&n{mJTYK$aYDq)uO8l3YF->|jG0K432DGS1PN_Sy2T(wFmEAU
zOlh^wB`uGPBS}L5m+WGxFFA$tn>BVMrI1tK=iMb%_QYokm>BJZ9exLs?SOeWl-g@W
zm};cPBoB=W7$*0YZr%Eem)V
zBFu;zyY{w6*W^b7QcW)i?*My@Y}mMAkHNvq;by#Q0RHT~d|9{=2z{Hzdp(-%0YF
z=p|}8Vf;rb+Wx_J`}t$RgR7MWdg0i#9F_cpXJt8u8{WS;sG3f=Vw)weX+EA^^an_h
zBRk7@XhMQ>_l)PH`HK@noVU5$8_)<8ni5_XUb-E?ipSaKt8eMD%%)`#Qe9!@vu3m7
zIatKA@&vA0?s)27kl*Mw>FvfOQ#)~c@`{6_Wj_)KO8!Ch9k|uDM~6-oi-)NI5riE3
zS4Q!9^X<&`65p=219++(%0t!w|CQ3%5!jdnkl*Erk4R`3`<~#tKJ;bp%$sW?mL7yG
z(rXwbT$d(r*BFLpK3z%32(o)LXQV|XD5J<%x~_}3&yyZ@Ovs5qL^Bt_!dIVD$iF(f
zU9$pPQ&~#7GF6BFrEiUSgb#*`@1U^mR&p6vh#ZXXEkynj|hPPc$bGh?oAs1rcaD+rNYqR)1GRKj6-lk!XPw7TuAu(`mv{{oE20
z2S$2;SV%v(pMikWAz_aCq1mpns8Ai6`S3WzVIVqX9&OkKYY1fA9q}H$%%6w`wnK5L`
zt)@a*zaF$tu=%$U;@m!6sep2}J{)efAOd)S*ru&eNM7ipm5iLo^_fwkN@e^@r}Ufu
zr5;lXsu?6pg5dtQ2FZ|$%;VmJQ1bGYrH|xy-|kaqxdW$;uxWao8*y;QWwlmXpP)|n
zV8TV$&r{Mql=eBQ`9j$B}p)~
zeblOWQ-iK{h$=Y>&WP$Gcm$<^$O`EzT@0sFl$_cGt^vt+;WyI(#=v#suncyq@iaWR
zQVyxi)Cf_~qfHDIXBW0bbHFwD@gvfXV%<*7>_8Sz1X6sV1gqu{P%nGAwUa?9-Znd$
zS|bwRDSe>CwK5{`5r0dBpA*jHrdmjAu{EIYeRe7cn^?{mh`w+I(0orx_^-}k_m*OD
z)jF{`YZSXz0~t1|f92VVzd&SKMCJh~s;gmi?<{eM5JZxLhUa-!2HT$@AyFP;?WqGu
zOig3Z42!s{PAn73f$&6j`zG?|MOz=R6{%=sCkmMdBuWs{90y$95#sv~HnH#j%U3e7
zk+@^d=zND2LFw&-iOVEFAJK1zadzzcc6WH#mS3H*UXHJ!`)*-Y!k
zVpaEvPz(z7ExQg{r-fe!>61PgNAmDUJyVNR4n$9i^{tA`gDOQ-SRo2+17uZUD@_UW
zIs=vYndRu__MUOY7H9r3iVcTA{Mwu_KMzH2t<$Y+?o+4FCz=vzyGZPQ$^~|E$@@Po
zoi#q5N}tYX6;VDDUso<^D>B#KufZt9nx`cClRv+ch{Zf+YpJ_dz+Lobv>_d=EGU7(p6<>PreE=+uRB=zaw)R}iZuG{&^s~V
z_>BUC1--(kh#=z&a;7wHsv8rG$QGm_9k~aUoq{?88ut4NeA&Yx)lpF43QiGheVqNW
z?4TACaCQ{SHvDk+^gS)=+wxI6Gi7r1tERLFYrQluFaiw_W9$ulLE8gGPZFrXgQJIC
z+wb3V`k)kd5Qu|E%#wK0D4XU=*Z2RZUl2net(dO5Td`FrZDKB|q6y>*GhM(7TM_o<
zhSD%>Ldbih`3`UCGlkH|0?&*_LTSu(6~g;r)`T*KvT%Lj4=eCtjD2^NEl1vnXOMyt
zca_xy5e5`kKmRFP>$NF)J>9SnO+W|>-p>EmzkKa8wLG{bM%$SxB79mS4wrSzW_A@+
zzvFBf%6RENGzjrC`C%WB3Ed+SPduDZgLUdC5NG|?6i5_evMRz1v3w#1xg85
zTn>a5po+o;Xa3F7=h^1Sv)j`U0O6C;GJC%RKy9Bs$px;{)&uzrEyK(gj4mkvEr>r&6(7klB`8O-`CQ!I8+<jx{S{rd|%r7{a{qb@K`mqxZ@6tXoJWca-LUG4WAo!O$#zR
zP88P9^6=bJp|C%FM4UNetoab2VDe`*?mbg1iD%qj)@@acd9JjU;2wNfCRGhw@`!%5
ztPkA{bTsqzoJtDATPOYnVmX=1h~y!s;r!>^Ly+cx9fj{+A4x^i%une3rXoSIR)ljq
zsX+(m+ff;~V3}sz8Bw|%&q2Bxuo80a#~Q)3)}K6tRo?)Zx^m=kAMP~QoEoEjnR8q
ztHppPh+P?dYb*kQCp`3WN{Ilt`)lcNr@3SwNdDlW$vK6R?=CyURP(yni?G86ZH(W@
zvxiIwjVtKf+Cy>1%UyllvqeCq7E}E-^KCoZZS9hiYAM2s4)dk?RB}c0hY`@_69~GG
zg+eYl`7=9QFTn=76dbI&xQ~Ueu;a$Sqq>0Y}JI5cVpCB(@qOkP>bzW<9gsv6pa0GFcAdPc;iRs
z1fbw;eY#YvOG=o`TRZT!rSmS*Ni*U|#nhxM2M@HA)KMcCdOZalg6W>#LI@ufzrQ|9
zE)!WVu1E$u_`bfG;yf2?if`LMKq<=3C_B
z`n!G^K#A_s6Gg1$V3mu;I(EwOvMj!opyQ9aeVa6EaPndE@FHKo*7D$ZTDT3t}eravqsaMSr`X}2Y_7~GtBf+^0{I;DET
zO=;7as+!%~e6FOFcn(oEm`LnK9qO2ge=%%3>!Y@8dB?X7l?l=3oVP5(6}N*Z*XDaQ
z`17a}<&DD^cOhVZk@+hx(q#h%PV7P_?_>gE&OEFr(~uzy+O9`PPON#WnU!
z1L?;H6|M3kIwNt3kA~GNYgb{lSLbX`NinJUH%}~-5qoL&pjwBDFb|(wdNP|0M!#aI~eIqN=(|b
zpgIi~G~gGNzY%x^)g;^hNn=x^l
zKuMK>J>v&vhEJ(MV`YFIdQaZ~s8|OV)3?s4@ZcuLKjX{uexgU=Fgjc>W8=5f#Qymi
z0ZHf6o+ag_9<$8C=xpUaJU9k>v|_(8?lmLJEYI
zza9tmXxWXqqxTtmtBm^rusqt78##qv0OsgX*eW0y44fH*bH?{Dcak-0OE-p#R$MR>
zhg_3LCUo>W5-_baCEy@11S
zMT6v*Za~H{Sl}j{jQX$x>#7qf1h(+6Cf$-f-3g=TBJt&$5iZ{Qp3MjXe;V1F&$Yin
znMwo@10Evn7Zm?vF!`>vkYR3NDWDlzLz30^VV7~kP+^4IpE_VhP}kBgIhb!YIDBP^
z_cJ&Pem6yA^xI3Z%esTzo3krpa$Z)KfgC7YAI3+gS<`o-JHEI6ar+fMiz3RH$8Yp(
zC_zNJFY$s6uvQHv-O4MUtd!>QYca)%4E8&yn>cA~?oNv7^l;uj#2Cl#Q4h(rAhw)D
zLv4+k_y5wi
z6insj+Z!}oC414J*EOpgVHvK^8Btvx<^pjup+$1L7zi9Eb{l3R^xyYctyQ>+ksg8~
z_j<1iNPza73TN=kJQ9Z%ftp5e#3c)^nU#CAs1V;xWnxG>^^1gr+hJ`+?9@Y2Qc7`4
zhsG!F2X=&|E(TGHM<^kbWmPf8CWS~5^2yX586oD~LXa~U3Jj4j!f)>vCDr{(29}0^
zJv^x0txfL+KBJx`9b$xV_3?WNWRA`7|A`}|Ga{O$DXCm-zhzC|+PtCL60
z{~A4~DN8OD>XGa!{X>6e<^g%q4d*-+4+)aYNa|4NBp9XVk@wqkl`RM5E0}P|$Q5wy
zl~0;!$o-T3ewsQI?EG?{sgieO%E<#s!1FK`is?p5QEf~O4Tjud_ZKcT9@}`Ni$~{&
zw3$m$llzZ&d1Xj?SQ=}+GxWyzXe)-kh_O1sIA=zxycjZ^t|>T4DOF6q81xar^}xE>
z?5?0mP0d!|d_LB{k2k|&IlinPlsT84Q{uuGGW+GdX&{;oLXLrdT81`RX*$*uIgmYn
zzmW~0F@4pQ*+JzLq?3G)Ya2;PhowBd?-^5Cq;(_DQ%Tc2f%HkxZ|_7RVIvMiOPYe(=X$*A3i
z2NuCmSKBm{kh(+`%H5d|lxzTen;riZ`d_&QColn9VA=4!r_bg)=Y0P@*10Hsw?>3D
zkg1=UEYm0yL6Yz3D0%9hB9ejt)s|ynBG_xW*XLk`T02xOnrz>56SDm1ht(=L(~T;T
zdt$9mRRHFQ(tT$w>tt=nTUTwf6Pf&D4oeJp(x!oB?tEeXK=_?uX66
zn&QSwE0MdjV}S{VQr27PV;(t-<)p*T24gD#(XU*`FsS37d!cI;IvABN3Wmc|LN+9*
zG@l>il&$VfDFXWThO${^;-f+C$V3~>V!SO0~yq>ma9+EpjrF~qS>
zx?@hPAx&n)umO>DkmDXVnz@u*sp&HVSAQSWweDMI6^(!WdUA|P=u
zFXTCa>XXkiSjOIQR!IIP1o*_atN+BCP4C%Uw-Z&8&Q+|M*r0(P{i$|-S;V(->dBu!
zzTd{5sO}GE#Erc$Yhda)*!`-7nH{k7q_H*YSnE=fgpm9H
z-^zj1In&5h#EM%a-dt?zJR(K%RSFNYPVZUYA%#n9$^m~C$xnDSRolPK_9cO9q&tO$
z%fh3ZGrqY9F}xXbs$@iOMtAZ<~GBp1YGafzO@HN9Q
zEx10(U2lLEi2PP?w_
zz6FH@t#HXYi1*E*43=-vt*FLy$=;H=aRelfJ=T
z2a;69!0ESVS_5r(|6-kjIC37Z^dMr|V_Ai(-Fq(9r(qHTpzLNyP8eP!{!Eow!}L^7
z_JNfK$Jmbvo$b*IBB50hS_c=5m*@R{@csVml4`eSYN$@19N#PQ$iDO3+X^xex6dR7qr=!TO
z=Zq1L#gn&a7TiAl%#!~?)b2pWYNfLXc}>XgMa&U+0zr_4bnT&z$bcOW$>#gP2j43!
zP*@X!oi^bp17jdbc%Awkb$-+<=tADKvoFWSz6b)&;f7ug&uY9;kq@Cp+R_Y
zMZS(M{T-KVAm!3QLTqxzm!z!2o|$7q0sSLrI@8LgpY%Ybkh*2K-Q~3T#x5AMctN8)
z9tld~Hesb=nQ-8iLA$^PfwOyFgz8u(16cedquV#=+(m~t{;>`<3Jq8?rVrINfg+Z`
zp_gll;vAl9SPUXWUI(iM-GnIH#?$(MQw+CGUaO{sLw!~zU62Y!AVRV1TEj}!KJC1W
zScim+B&{GYzsgOm_6oObf`I7m&PYk5a>@Qj_b4To5w>Tzrx
z2&E2kWY(A^jJ-`_1f#cb~sQGFLClkYrvE*gztIS
zJB~Nc4*H7bg9w<)(CV^yYTX6uycPUv^Y7=SYV2~92tU}9=K$(n4~cH5`(jYtpv$iI
z8rt!1PutHzu*Q}hA!brnQkuI8T%pje2I(#WU~zB89#67JO%60eH`X!?<~#N-Gz^vb
zcD<4fHC9+?_T-mEz^Q#gaHN|7MLYN?O(VBodVEu0D1*LcrCf@>b49N3)gI^VdCh0O
z&IMY#6GYWCZslMGJ-#5
zoM56!?SY`CW=3TSS}G=UNR{J5UMnrrP+ykPt*(wJa5!M~qa>&yAO$zsAs{?-C-
zT$-`Iz!m~zlo>#e5~45DX3G-hD*`jeM|#d39vtm+KbAFKErr-BibyJe;8)5vXw+}H
zZSTB?QDAkxSOP6TcXQ^G%RWxtsPuY7zjFncJ5V&`ZwD^|M;k#E3@N_>25*Sgl&CYrIk7>B@rM-A=%2&Z5pUnQ!b`vo`aEz
zwwT_YgiOqX^FC2^JC^1&|Cw6P>`-xC&t5fu*PB0u=Rr?mF2B6I*l&wB!)1zMM*|D{^idb)Jf
z%(;G&`{V%T?aHq?t$zUIarDah@o1GZsG;4F9NfeiH43o~CkRYJh7#xg!Xp?NMsc+|
zYMMQ>y(pKa@SspPP3!i~qyO?_D!ezi33pwQt>a$5c-B^d*(Rdc6y
zU~9?COQ`wNwP{x*16mP02L7at6Gk4zhS$d^)oqh7eyQ4-6K3Wp&-G-@oj-sh(F~a(Mv80uHbgWz&U`Uk
z9wv?%<{I~FewViw!L_?;%bz+I3Pcn0Tpq|Kr62M;JsB#ZrsrMmmx@!xlPfk%*Hwa0
zCF`5W3!~h#AI#
zi<=mvTSI$+!4bokJ7=Bs{Kts_gMu?Bn8D=y19OD2+F$w0p6<^3EjH3m1bg{TB_}tx
zxO<_PtPO`;hJu9{mu3o*GLzyFmEiYt2Y^EnTw8U1oD#K+Z-m9$0*;5kWKNxQ8PU+d
z#Mi^5G4`8H4c|aJ>|i{-o4G?UpDxQ#p$jqW*;BAJVbvI6k)Bs{j~T6Q`v((kRmF4m
zr_DGE>-FxHra%@OF8&NFi^PAVXFK}|m2JK4_`QogMLL++_`6u+`a(d9>tROOI!g=I$LL8MKls
zHdy`1SoGzmQiNPetqlk6@Q$(ER6B4M&DbjH;0@=cyBVqHA5CwDdzcupheM}m8>d{q
zZaeL@_<-U$C)PG-n$Bh%Q8}{PK3eC6{=_c-RB=|XNWDrL6>nZsUrEVys#Ua7C)x?g
zZwPSVKc6>|XY#C(bi|-W!-Q2Ni;A<8Db1hQaY?$f{?M=2xLymOw_n+N{pr-xGL_R(
zHQ(VzI{Tm79&Gl|)P5k^+k-l$6A~yS!OGcthZ7I?PUQ%LtVyR*iC0Y)!X)3`m<05*;pN2Fsl@8=e{$FaHyUi>ph3c*Z2;4
zttf}b7ZR=XavFh`NE~BFvH;iLXWCJgbJI}?Q&0PiT{qhSIFTG>J0k>d(9)gs#-jiZ
zLY5-4;zEwdBkGv?=|T)yX$f(rQ$^!rlW9|GjrhnshCKZ0nk&%~P!7##3|5_QPL@3#
zMY$JK;?KQS|2;Qwn*iVOoqoe(fhBZlMoW8rx#Q8z3@kd6uxlYKnLEiRtr
znnV5*s}CYZufmqvFGvlwrsH-NtR`smOvS2aB!XGRZ(-ZmB2rvBDJA*#f2F?dim#n19*xM2%??pOq(r$|m8
z+|lyZ8i9A_>RerS3Q85eIaT{M!SI!{AB;s6WeJD)?s&!>3@O(Vb<
zOEKOfp0pNO^h8&W)O(=Kt0j?F5VZJMQtm1RxauxSI%KSTx@dX`wk*l$AI3p%x~h%r
z>pv`rRqZG07_n!P<1|y@SdIVj*GOn`GIpui@Jtx^yx8PRwu;nrCfA4(x*2)uancUf
zNHa!E6M5;JLTP-dlc-$9s@c6S%EVcD6Hwa35`|{`>JJoPR*BWo3t>R*ggf&1M>wnq
zcoB#?QP|n-3g~7vK?E_2a3iB?7|%|NbJ=~`ha4AueMYuUq9cd8Z_KfRX2KY^+=AyX
zl+bcJVd+otJ+`=b*8y5inSTY|*AMd;XxoN!3@Vn6(ZLFS2g1LGj<%=`5pP25{XDT#
zGQAf~XsF9A9MjCiL`XJO{f+uNI8+p%v8&if>JH0lbmQ|x{dCx|)PaSW6YN)h`XO_G
z?Qd~g%xQh1NQo#Y;J}@6I_2R4D}F_3pQ-HQm)=>V-S<-)>nf^yZs~$XGxxHO3PJ;o*hMJ&f#LoZJkS>)@Z0XV#30?jc%K1E$`OzHDTZ)&ge0ir+vc<
z&n*Vr_Ubc0>S%%K8shUUwi@80y8m7XF*-3nM|LefJX*X&oL-)t^&^Y{56@l8Og_)1
zlPhD4N=Pm-qkH)^$|qYkM4P_v7!(Y%n^C#8!hGE1c;ntmsSsik+gYT8FyG=R7Qr15
z#UHKUqH=2nforRmm6WcSJSgy@5xf`?x(>SBP~E}7&(c{>LVU{0=3l|1f2{Q4
z-J@>0Y8<^mb3W0v71PdWakKOlJOHZx^SPM_y6Mkk<)5ZUW&u7R=EDdm=hn&~jZ25^
z{D$)r5WBaYg+w<4!?T}}I(w_^Ad^tqf
zWzG0&r}~yEKt-W$v+nB5|bc*
z>CHS@By$r-j>hKngUR1=3JknUnX_d3<-jOR#BV=Em0&>{RdouoXA>vSsMF^6jFpk-
zLG^zRp1t_#ZE6R*y})WFZttlzO*W(>|3A8eA#!noA{1VNZ?x4TR=v$OD47_m`|OX)
zxfa3f2^*01NQ#Tai|)e!f6_>57u+G`B6fEgvx}s;Skj+cL<5bf$n%V%d$L9Sah2Lw
z$rJoIHZi@4KH`%@=8|jcJQ>@QONT5jm7Mi)516S(Cm&Q5*-In?Bt?lt4*N4olR!lb
zdc+Yu%iRBtr2`-<=F=+%xv?30rYJ$mJq*dILPmZvHdUG?~_mxNzp{H
zT3qaFZ*1?hob7{B1ardSoj9u`?3ElCkhf(?)x_o<3bY|$RObna&_9}-0n2n#88T#t
zVNZD%{n3&eKod`$7Dj{o12EqcxSbKH2BRU&>sjGMkPdIHCtM`hUFSR#)rMoTN)X}g
z6D?@@6@XOM-&_6|yw7^q(P24_CQ7!foiMxhF3AA0)}snGUa^8)J=@nFL5r#>xqf^99;<$gZ_hc3tTDgC!Q=)1l^Tdb5&
zmFf?AJqFk@kQ>b
z*Sw(Ff`v{=_UQp(LJHm>2+g#k4TBxScBSSV8a|@gyCoS&
z)H}J{!AaQ=_ly8FQEjNVPxG$XuxNd?p7m#Gg2Is}i?IxBam5BRl@6m!raUaTtffjTt~zIEp#fh_08<81i2R}fQ
z>B*c8c&&3m8OrZ9l&Ze7Tr(*Cx6~py_=t%{@^%wy%?|Vlm6#wkx6t1W-^#8$Ssc-J
z3}T_BC*6*lTuUHt1ANh}QIt?qZJz=CMqZ3%zkA%7Jwt87;p;c_GXN$j_{j};e>zD;
z^dt^>_e(P^gJRm>u3og@3-jdZAY|^z(4OjQj7aGMxza5|P&I055=+L1-~cYD=tFpr
zdS!36ARiKCtm+*G7PV>Vtw0fJhK&u+aHIKQ|H~VeGd%KnLgS_;hQt+#aM=kmBZn0j
zNvjVh48#|m0Y(iH68b&K95yzMvGmB&1+8#aQ+i8M_?loPqJFgCnqn$R4ZEl94HdXueRfg99H*jrUxH;fT2h@vhQu+EG)fq-$sR56Qhjr~C8j#Q(=0
zW)UDR+#dDuk#_x)ga%K{*O0kPt4k>_nmP0lyrl3>Sd{xtnO#t3m8^~%1A7wFd=tIh
zGZWGtvk)E14bd)h!?wC+8lynJSHeN8iTyEfpw;WON>L|Hd8S!wdp1%if{=y4PW)xoIkPOj
zq@eYZC;~&nLbNkInap|zxcC~bYP3awC0^*VWJ_V#g}4&&_@YG9(xMQ(i9Jzzg;Zcm!R
z=8-T-Uj}s`l}s#*-=-bc`#at=uqS0XzPEZ7oZ?oqy!EG4i^~V&U!H^Zhw$?Rk=IZ?
z=(1Y7CjZOvrh;5mGECK{C9YHRxuhtS2WNkMd*UKoN3iP8{;R)?XEqeY3mSoXkC|wB
zx>V$fZ(s;`Kcn0@Vns{^-Bo_V^PtI6X`~c8wdh(#5#R^2nlvjavowJo431=%loH6i9nN!i
z=c~C8LpaN+M*Ir;v)pl>?~Pyu>6pM5-x2PA`X=ULC6uhaZw310ax6kY;>O()_K^(y
zn=Y~MfX*f}fQ;hWb=RpVv7PXf?>-dxW>p}fZ64~_B`J?@%gm2A^j>or1P&r@E(MzoiHVcc-zY@=)hn7MHNCPLLPL$X-IB
zHX{5Jpwj+-1duzBA5yAMsWLYyEuC4=O;le8*1l
z{w~tU?KICeH_;pfT11N%HxHHAYcewTB;rS(@RFI3yo=-`70``bS~KvomOL>ewrQ>*
z>pV&p98pMO4^HsQ)Ul#7qk^j9R=2OHnShq4GDk`#FfFN@2iFhsp4#jAmmHMQzMI_#
zeV4nB1To82QO}k2bgB~tIm~=XAyR3ak!M~q{l&PiU3a`OkYqcP*`h5kpYqKk4oS6+dxRT!=o#TpOHRI414cX;
z%tCvQFyBa+WmN3`p#VET#J>W-X#NUU5U{CyvqtkAnGsI}=(xfFcc!eVm>(Kn(#W_U
zVAT10ZFC=x#cWcNs5)
zV8UlOfiYg9;g#OLkPGPL!H^uv+ue)8*0@$d)TTt5wYfnJxMkPhT502DKH2?^R-JB^
zD@)wq!7-b%$Bg&nEgtP74XD3S3D39%Cnfv_h-VW@Eh)O^2E>0A2it|o0qY3ZkZyx-
zQ39Vj?@?6XN&lx)?<$=kUGue;jP9|S5h?imAq!6%L4{GGxJ1+@R}zUT4VbK@sG9A_OB$R`p`uaDCIQq)VnpWuG1S?5e3
z-JlgYZ7QlEjX!cg)Ik0Wl?aVW1kY+9x|~z34_2Ofu&h$o>BL!NyM&WP7;#l9i(>}$
z4QIjQ%9`LgFu@tGf6*Cp&(G=hS?(m`*VbtO2Hx(f33rsL)v|qG18
zB(CpWdI_b;MzXow;C^+3-VVUqMxN<8p%PVimJt(A8?j5waihF$jZJ4k6V=
zms6>M>Y<3pX~6UcD(*%OB@WMOzrZWy*o<$iG#AeaEA6hL!X0AIM{VB0Xl=|Pe+Lu4
z3R7AoOK-!c?h--4PTPnM!LSM)(BWb2ekL~yn9V-^=ol2RfoM)jIg+d5>%%uJ6>*2l
z`2s?5d+|){CQKB`ObXS74LRxJNbYaQdu~vZI2c;Z%>w8C0+CUJK%psoZpkAWp)LjK
z0QW^pJP==~?p#B?Ir@I=vI06?8ui-8ObYjsgABCcC})D3Wfe;)gkz2zdN?mPJoWR8
zC%%^J?{wi-&Rt_hZPaBfHH^WLqf<4eqUgq+>+t(DhxC|_26>x;$`D@AJ)G3ryrnaAwoBB8B>o+-Ik{q87d+%|*st#)@ViCka$saP+s4tM_8c#lT_g6;8eiWD4PQwQ=J
z)NN}!PVo|&9eeV1y+A8)5XeFT?O0fL-13SCXG1vJ7)m@zmyjtFe?Vj$M9+`8#lS1_
z;`LEQnjSsU%Veay*f@VjOm^LY^RmD(t(f;Qt;l+*;d+`HnY0Os5~-5@%LSrm!OafS
zyJ$feN&G?gCMNAtv+|iFP!!Bdubz_DaPb@f{H$G{H}Kh~*TaT)Jv4yyl+}a|
zgG1bIx2R$rd}2lw71l`}%U4>=$+&-`LQ;HOdIr+*dwPLCVmGGs$-GN>Ni6j6PCoG^
zOSGVIUlHaJ5R3@-|IFM|#1h0IU^y_9xJ!hHeA&T|QbxhQd5Ufup%mNn|NSy`X
z8Z4wNrM+VFR``T$rE|;1Qef8}M3okmlKo8n3#+zQ*2JJ`>7B2Dt2~=!#ClWOeOAF~
zdyoZGE(~<+J`e
z8K8Ae6*8N*hbU$eE3%&d%53)2UTmn!zxRUztVJNU&p@j9i(xp@5ta7b&`v<$lr%pd
z+}uuFd$ZW9{39Hq=%VJvU^xeMduv3%W+13t>m
zPrT&E-vx`vw9Gp5G9}s&F^)QZ_~yOY8Iu+u$PL~}m;$(1U=qu2HFs|mjSe`?g=K1t
zR?ofEPR2rF#0)#vs7nmDwrtUSkdB|##UEXTp3d4uwR>K|ml0^5soDJQa1j?gpbv|?
zOw(!vr3bacnqiH}Wq_JwP3#uG1bKBe8Q-IeUyMeyHy3!Yp^r!#r3Fa33H&uo!mJHz
zOSx!uO~bRiRdzJywP9CvvnjjCA!p#9AJdsP)BS7_hc_EgQa##?%-#uniN|`vx=M(N
z%jJw0Anxzl_OJ(n9t6H|1s6;B$f$qWz5xfqqM3Oh7z~Qajy-C9tG?F0PMR$L2Q2;4
zV(H#0Bj;zc-6jF9h(PgvVvVBwmNpqY!6xOB^4JZuU8TW335S<)AM6B#s%6a@si7hI
zmL+M0y97_S?HE-WGBfew8
zYW>Q0fax?ewPl7WcEdc(ey0UtPgX!d>9tvLE(;*n$K%%v3W^0LQE2=I`ShFaYw#;;$H1V{@FLhmEWOC1X(wQcI3Nl47Sw1Sw=ydlSCa8B>jD5RZ=e?g1
z=?F40zk;<{NOs(Er%p>`oTw1CLaPBrQ^AsFcM>uvoYbCn_^2PLbusCG4O*LtPwFGKU20<-V2mf{40*^$Nt5apkG<
zUUmn1kQwgTCZZ*&jA5s7ZqqcSeTFKLPB&=!7tWX@PtmbobB}2ZUrDQ-_3N)iTP88@5sw0B`>&lQSGuIorpJ;4FRgaq~D>|QZ1!E$}
z{?As}s)AQ4iAX6A6dT%D?>EUlop`5fOwZ}gG~cr-4n}YHr3~Oy;GnIe6G1_Ovc-)d
zxjK|+f0o#T4E0xemA6Sb~goLa&e98%I3=5?WR3JjyGq!2hWHC-CwlywCIp+EfAiNuIOETP22GgwvsFLJ3c3c
zet0r0&jt?=Tc$>D;3uhfky9RHy{Hd1Q8-;x_BNsG)wmr4&<#nL=J%k5e~#K&V(Anr
ze^Q+6zOX)BGwFEi2+ef|o)akKp!uBaVGy}RuZI8H<1ieTsY0~60h(}h1?pNr^op!M
zoSU?=qj$d`J!w&qs%!ml#1WR-%#9`i#$EkV3@N1bfNDl@n02L)6wppuqHdJfjlc0}
zgNWVcNYgB8#rkgm1BAzW0~gcn-CV6Z0YL~CSU+|ZEo
zp>&O%Fo$MdUe#`LFa>V~W5zTF3|G`pRv(-6kez!tp8S7eEKnAlrmEOf4%APo`I%YU
zGY*q>?55;?06%;gd~ICmPmR}3s^9G`rD#Y3!!_I~8~aSu1iWnkmAa5IPYoflCJn+u
zchidQ7DoTlMtMHu~
zXr3bSLTT>#UQfFp1D6bK6{eXOuuho512dDVek(LRs1PT#zZh#_%J?}pe9a-nkUk~F
z89mIyT7KUYE_4j;yn%I^R)f?%8&6+J&npIuxH>jz6hbH9kFv=O5NeK8{`MvA6>^_FnFOM)wd+jK~S3-B7qeSQWVlaRwZTE0U;%5
z(zo9hl*~60{P+;L)3AVJlmfCWIpQSse((nPO_^Mr9W(WnO93
z$D22~RhFt~KA^?!-{g&SAc6$Y(EI+Egk;EGOrUWbb>vgT?sA&W4%8OfpDw
z!Ucp7Vns2F>a)}&8?aKy;*Pj<7`=zx`Hts}p*jGih}8CKJ&Y+TS--Bo9E6>I$o2kV
zt2JWJPjBT@E&^irPSr)ONBR&4=~^-|$WY{v^GDPz@$e)lWxpu8X#BTFE&xSmT;)qr
zpWRwXpiNAuF_)L;BmJejN(13`t4jEd*pG~$d(ulWRJ8ERjwu(
zH5maaTIaTVCZ>N{*vxUv`8Z}2Z1xlgxYe{)Ph^xMejS@N8%h&sxTVhy|{5nHOrtVM68ZL(M}=1qzzU`;Lm
z13W_--;U=zT`+cHFx@EM!)5BimAn#L5-JA}Rt}w`8Wv#!ap(BLCq?yS*lxt;^;V8-
zhJ8)kpT>8trBDWnX;^mO<%Iuu?Ln{x#Rv730d69=2B@TV+7wJ-gS0_w^nT4C;MPdYIh>73N_D_
zVrQeoYU)Zy^waU+E`m-%qiD0hsNc=31$LJqw*U5Bvm{2|s)Eqbnb}>r2YyYd
z0k@_0O;H>0Yh(D1*AbmPz}a@L`Je(F_b~Ar{-gyOnB;bkX~-!KuI;-B=Me_L>As
zJs6g)8#lWV%py$06nejie-0-$J7rS37S@k>zo}EkENk@W(|9uecE-H>S88cJ|
z`qp-UtCK_Ms3Xt&HiOF^q7{E)|H4?muNKb~;N6JF8dV;#VE|W*Los2AZiX}V5P3gT
zotI261-e*za^m{wX)17Hpq1PDEd%u`K5%z9@(i6C^wx(6Qz_Fl)c1IWJIVp4MRhSMXO851o*#y0z~RP{$+P<4(E^}T
zaCsqcd>IeGEkEu)tt&ac#?aUx49(rxE8*f1wN2m|YHv$l6!9ouRk!^#^zb-W1cC}TxTu7HlC7c`H$ueL4*Z@jnyAUs
z)LyO^_2|?A@A+y0-qkvBXvz8Ma(&>hOird5U>!rDjn7A-+KS3vY&W`Y>_^%Q3l=A#
za9%2riO9ozvH6wEja82^U%F_5!mRMgn}#RZQw!UxTB!|lG7Lcq-H-Wfzfe=wt!Tjf
z%=NTlkCyj|t(%nq%rye`D3jKjTaY>{9WA{cVrGpZ2hWOBs
z_P%kbWWpMs_sEC+FZ8Eqjdx^+cI(_n-G;LmzLq(-SZ_vNTW76(b4=z!^{B?cTQ9)o
zvD4lt*QkVvY{q?ya=&*8V)UQ16j*i2-Ej_qswUM?kh)W`=tTmbV83a)#*=jo4GpJ(
zAZccp2BU;RVWIb|P+%5rFD`7qceWr;DMfRnbh5!sYwrOJ?jx|qlkcYl3~|3-+IIqd
zr*_LXuZZnhJc;f>)0m3~yjn@bq-Eh-J!
zVgh)O!&4*LIwoTHdT_U+TjeN%DP-DVW*Efgr2>{G+0~JoL)6*8S@vo#CI})nE%S6WqGz?p-mo4p6SgS%gy*eOy&zd9
z|B};Gw@zdP?^+@~D#PMF>fnEv5c=9zNbnx}$UHZ#>?n}l6nbVrNOK`a&qnFDOGB0f
z(tvAu8wG)U7*yvcq#1&S^|bePS71bP3(j`pM58^vVU-&D6!N=(KXr?$p#zi4syt^s
z%VcCac9^D94s5$Uz9en3rt%lH_*Pr&VZy^?b!h4+w#7O!-qtnOMS!o_43G1iHP(=U
z>;P*@I6#S8x2E8(rGsWXAl&;R07tw&fN81^sr(o=+K$nz2eEs0Zfe_WzyK)&3J8`g
z7Yz+gD!ExbU1D~m_&v!-nwInIyC^6=U^TL#`W2|D
z5;9$(YRie0GfXt5LPf~hWp^4{0SqD)X9D%ie$EV*
zk+X)L6+9&%#%T$XVQfx)Z9@4B-z}4Uf6kG?q2u;Vaw4{sb2*Bhm&|Xu9XP|wpy*Y?&R5uSowV1oWPW
zS}B+3FscD~b#YNu$5x}UeprV=OzO(l5bk>H(!N%9uu`hsbczY#(M
znOJiOMoN@zQkj?#PnBLb^Y7@Dg%w-#pJMkF^-^U8B>9hRs^9s#jwHEWyj00wCxV{#
zq%X?>`%1nGwtXJAqMUh;|3vAAGTC{dB+6fV*>Ab~BY(bD1N1TXuAGaDWndyO`&X{$
z#)@rYl~Pp*QPM@@nv4{fo*~lSpW}BSM@OZqi-e$P6wI7g$wJ^2sr!VUb+Q%zIk5n&
z1~EpiqP|}4?-QnQb}ug7VkI=L$^Wa`nK=DYxnMgvG(9UBYd$?KO^~Jh-=57Q@P!RS
zKZ2NmHk=Fv*^`#)hE=C+Y-m?
zU!l{;1vA6~vug8AVbuqKHK5oFqbW(y?uGsWsH=ZxTtT2%RD@ObPk$aLpxTUWqAbuQxLq1G%UEKUTBmX@;le@bzEGtJ?=Zbdiu{14aMKhiY_MB>
z=DYd0Ms`5m;(sgfCV8TRjA1=CiU?4S@{>EHYsun&4X?ceXd3r5A)Z`BlfnTc8j?iN
zdaLVtF?K<;q(ODJN>2zHFzLNy0uPBm0>-Kz27IHR4z)R5u~(gFH_3QBfOi$iM#F|&
zRLOO2`z<=KZnSEh_iP#u^`u08H|`Z|gjp|IILfm5)1!sKl}2`F3qrzq>|K_Bx@pPWsInmZ;x%EY
zbC0j8-=4mxHb_FidFWjCU4hS7XA%wVqK0VppjmaG=tgZxBeAHN%M&~HKVEI$o&^P`
zC`6dy#4EHlizSHI!b66^TtCHlc5x3d+G?zXanPt2=57n%thlZzxwXng6lYQ)^I7h9U(rC(SF_yyc&EUi=tn-vnnMm(O9mE)$!E3S*
zk#HFy>?w`03oF%9f!R<#VkdKhp78I$NnP?4V1eSn5?m;P95Jes8%8c9xg=LkpLpTp
z#|R%Zv7kpkKk{{%U}8Gm5%#msSPUoYO^Vi{X6e~O7SWgLpcS*@{J83^d)3TKL*)#i
zq>Zp0uVY0InPRsR&;eA=LR#5hZJkY}Rq!d`Z@?TPV|ABfNTyNzg0h>u2RN2)cl4tZ
z9$R;Nm>D7l645d_qdF&b_OOB6F8HHT>7)0h7r-V2szJ
z{`ID^LQ(qdIkjR+D=mi+0(wa!QR|kU>lz9t>2~iQR7DmK&EiNL>A?2@;la^|HbRkf
zS~&hV9`fK72JJZCOr-5P=d65H_=sxCuG2KOp8*n)m#ZjYTSy9S+Y00r3q*;|
z8>OYR6ju7_6!i}~%4vsYnhNk4P)o5B%>U?$V}xtZ^6G{IW)N}Gl~);20eDU7At1Gu
z>i4+X-r8=
zia|cfbxF9j0Yv|=2=nU7yW-cIq<5z*Cb1C-0xLbOKh1t^?k9MvF~f7u@tirc2oC`K
z5~o@*b?57!hV1`IrV)hkrr&Y1qFXw1Ll{Kfja17LjF8SwFe(+j&Acx!X{@TYvz5+s
zuMlM%@5BEXsUow-JEr)<+PF+%-=a(k=@7r&YcCbC#i8
z@tj4L@MdmsHcm661iGI7`IFWLYlT;P8D%m9`$V#AoH8jU3tq;y7Bs&*9FJa!Q5)^*
zMF)i7U4^gsUoCa$s{!RN2!^kBNd~Eu`|~TN!d%v${TBZiGCLMWi5@1fHzbgfaXJy5
z=PDHXVSMO&9FP$*p&Is;yk1t*J`>-eI5f}*AXke>vr=lKk>m#@5aU!^+=WtGqdI0<
zYSmxNhL;n^06o^M4Zsemu|Gaz__2I)aX&)y0>g
zk#xCI1yzJ&7C|woS{XpNwBSanQ3?*gR5;$kg;p?o3&Ik
z5Z2xBn}*Dxn2sCQ!zTd7BDv64_NRO3dH8HWFDRc5`*zJ60BF
zWX%D$_#lwTBf2-Oj!}RXazKPa(%qq)Cb-Ev1T_hijSP5QJ1{F{`4G_7o`oJmX78$W
z<-{rA35P|7)=J#GU|j^C?&+&UaV^*%8<$x!B;(^RruVdPt%FIPLB7A!(zHjS0Tna4
zF{IgKy8HSiWGwx>mA8cuof|_}`D9z1>f_qpOfSPNyxq(gxJhOV8Y?NxuXX9@>Wyci
z&vc0W(&b1u?hsILa|Xmqa73lo3~Q$%9FcTgGblAk^5fiI8rOy}Zl?BUMqx5Ir8o`j
zax}u(izlQ$(S*7i;DULiksras?auf&F{&;g!GuthVUjsMKmogSc{P%#v?QBtlyZ$p
zc8>m%#|nX_Ca?r%fy4Um>nyi8q^P&1CA~WLm8UUa!!fc;G5PFEf?B^eXs^7gQmSfzt|Z)*)`6E&Y=)L
zSX5AOjBb4-bMhUG{yJ5AOt?}ILK*P$m?dv{uaH=B3iJVQ{SN4YOW-V?YWqrBK+r5KJ_NMPg>>6l!}r{EszIwn~24Ch(N4hEV{TQ{qS{K
zgx^%6%M{{;>dam3cz$XO!rr{?er1C_EZln0vEP?i1w6>mPDH%36S5gOb6AYdWw3q5
z&mN*%)&at#@rp>*`v@uQ`&iaNmU<+1I!TFkUhN*eJP?b1OjrZ`51F0nY#oMN?zFEs
zwIUWg@g$|;&BAjn1liUGe}2YSK=p}Vgc{!_Ofe!U-WY5~=p^QMDep8(@>E`_CeL4A
zH7$ZAK3b_Me(sJe{Ejgo1_W6G#h$yk@!bp<{{Qkk10BNBz^n-LDaN|w>}ew~
zq$jZWk1mk?rt_}nS;4V5}~i8b_coo(6->4@h4r5O04j3p}fg7aKw_d
z`9ak4`z$H8<7XWX`R3SL%nRW_5W&CA`6R}|*4VOWJSn5{RWScysCAfc%iN-W>TCfE
zzjSgME0X|bRH)MhzAQ*G^G7?5speK$7X_l{r6HO`Eo?mjgOIb&m90XlDHgw$0c^
ziv;E0woI~XzYhjbEy@d|ZU>oo06
zo8Z16klLQUAFYUF)};eOGtXg>JBb?M?cSHnYnncuw~X6`UWeC`dOjA*DD47WUfN=e
zPTfwnkjb*SaVXvIl~sl9&p)8m0#zv#n)vqZ0&}NS10uz}#c%#Ygh;1kY=jQLU}()S%czpCO-N
zn#qMg`CsD4D1c%)F}SO%gf^
zf#|}BY7v1VjJQMYSEIKRBBmz@`@HS((2Xw=e*W9fcX-XkNct6=i!flZ4;<&JoSgkE
zGAy;|XZ=LAVRz3k)3D4#UR%j>`)+wtChKUBDQeBs(k?(CjV$mP#^Xh2^h!}@*@e7A
zX3UB22xgu5`7f1~NTC9$yZjihnwzV5kehCGQ~e)*$o48qmAite6e>g}XP>K^BU^bk
z<)LpY5UV(h9zzuYrk
z3L86S1TAUVx@Hnop*t^1*?Z>0_`qi%3-m+XwUDc_g`lEf@dSm-yU3fBma_Zy=Vsm^u_c7Hmh+_w6L5-?1fHRZFe3M|cQA+N
z9QK23r`mcN=JwNpt7h~JufOv=;d^odPS;qFot6zpVTaPt5XV?Kqf4`2X57J2mcZ-4
zm6;XFzkOoyH!OC~gZ(iWi?Mou>cOhfz6`u&mWgu#AwuHlo
z7U0;yQZCjtnmj*H1<0R_J7h`0L(hwh(_m-$lr56Iuq9Suh3lS+(0+{U%Ps-wl;vkp
z&Rqxw4YeN27Xih6B5p!wfo%T9*lL-~z~zJbn%c~+u8O;>7>4
zf>gZT|cY`5kC{)+SK8!9Q|9
ziOwPf6f{9A@ztmkCa$9KPt1+uol48>>8*xzoR2)V_!2uv?l&Eniu&KW{UaK$$wAfi
zs7`R6ie==dWQKJpi+2)9r>VIne~rFfTFg^>)$uAj
zDe6{>3uZb+2wlx)yzp9Z(qvQ%15>CZU_dnz20w%<{YMatVoa6alP9d_O>0JB}p#Pc4=M?DKO2esQPR7
zYz?n#huOJ|PCG6UZsgt~3kr^wsID_a(sy#CV9Q*fALfN-?<~);>5OA0sa|S#2pvZ=
z1uAq$_0Z=LQrREzjpFix@uHJnO!OMpJ8xt#1vw&4(V~v9_jm%Tmcp&X{H#z(XwrN$
ze_l@_=q3oK2oaShA|p;k!hZ-);}qx4qrN0Z*aho3e4qE-)WvmBu7f79w^MON;>+=-
zzaxr@YHhP+2~lC2hW!gVhq*i)+Aq13skK=YBP=y$yHv!ZWO|UgzC_`k5q7?fjQ#t7
z%DuNKUmu*Dx4^=>sCx$wm*@WWmY%{oUss_D)sO?-8c)u=GB664pyqMH$s~#TQ!ARp
zkd6sz#m&JN!De||&B$yVqarWQ&ve>HJ{-(pmVf=yR_5H(;Q#+TZw*;;>x@ez4i3)t
zSTgf7NZgNe@LR+{{9iX^OM{RO!DZJQovP
z6q){)y<(Yzn&)DzI}0(`5nsH_0i#L*mK*!scS_O1dmUqB``|fl?D+7j{Sap*t#8xE
zJm8+lUK|T(EBsf!%w-hbJ0jGJZzjwm0E5&LzAE{~U5=8~UhkoKnzUP;D)}F5AQEZe
zeMSP@z=P$glk^=Q1Ejq0N_uSLb)nnzKlpoX4!F;}uY$H?^-gbDZqnzG^eFkh0B=H%
z%l-ro)tV}O0y|A1V5n*y4y09}Q7OB3nQVO&VHWN-t57om*v$Wie386_Hx0pLK$_1X
z2(j>x>TaJDrRKkW32f-4{JVKvK|1g_)PDENaSl>Hx*Q`Mi55Sdw6q=L?lr5D*v~^k
zu0ANsaJ$kAvNOBHpEo+~p%*p7v<&<6R~<|}s8`4Wr5P6y7%U+^OOkV1tg(?_FzoSd
zhexbO*OUC9046lD)EsOCq0%*nlpP?jA8|P|ah-h@JjgJ)Rd$|l-77JgwH)CLc*Jgw
zG9wpptf1#fT1!H#vRN;yF@x8P{l(uFROXi%RB}`lxLicvOKezlLlSwE?v(ey9Kf8N
zu?}g0Z?1c<*dly=4gnma8VMgcXs{3Z)aIAb1bkWGJ3F%FdR)y7qx31Rt?q#UnnQ9y
zHkqq9A0r6&m_TKe!Y!C1=9E|h2Gdr|5An8E^#5kP1a#V<0-+g=m7g#_@3NG+(5!<`
z_shuCm-ha1WBlrSpXLcK44Bng%l*fKuT5M#4QacD|NSnp68Q=5YuMq
zPw%-|rI$r4&AlI#?Hd`o6$exb;kc%qNjvIW5T_vXTs8?%`!#(9J6dH;C-FVv)lMnt
z@syPPkn?&^lxfnZ7W8!V5-(FYPo8D;z}wDywx4{jo~quhz&$1;S~+tY9(-Pa%n^++
zBflBUd4(1d3-r3iJA^7>%*5CtweUfPfW<4QeE_Iq`rHv+ex#X`%C7mSBK%_Gmtl;#
ztu%jNnFw|kg+T%lXbUSbtm$@EmU=cULNSerG{3zzcrXF_WPs&{5|LiZo-M&APO|%r
zu0t)?L(q)HUAZiDoRUP$v9AWE7i$U$;;0@bOleY_sD4zU^BAo_Ck?Zlyk7EZ+9=nl
zj9X*jeGTVlQ@B=wD&NA$`O7z;a7V3w2_7qN&jm!1t*s-P@$j}jHLj_7@giQx+hNU}
z;$`X-@Ib?SFq=ZHcii4ud?aOj9&u0W0@v(WLk(Vo+M@f(UBzDvGi
zQ01Q|G;`>}TgHXd3n!!qMA`mzf)K2`F0>)!TSJD9vpwGR_@PduQ*KBV-``h?22elA$
zdpajvHCQfM9r~_tOukf12FJ`9Mh%NHH_3~oFs#2#{ydX+8G7WVaEP2f0++iOk;%R1Y2zHF208Y(MqMsy+Nm&IZ=
z(FQ;E$J{gxEYEH1JY-jX%AjrtrXjsbp@n;wkwuvbj3cyq?CZ4{JU^pyIr74IRlX~=
znwZ1+B>$Y)%yfhUfH>a_?p&CUGkDveclvBuK-?4EjpNvHO_b{=R3ojTKPS0i67Pfk
z;GBF0m8}a_uI2uT6V-gn*tvDdv?maA;*QJ%fjUl4M^ko6N~SY>I7w7`A#vp)<)NLG
zBq<$0UN^ZF6=$bGxCoebvar&ub=FgJt{cjF(DqwxOpMQjlDYJS6=jcNN*!}_5K|(=
zhsgRR6Vez$ZYj0u6tTz2w9mT#tizO3xWSuw0@dJ%`AR)~zJ`y4l^ZA3jOz!TPYFZ~TlL(6B{wd35IpVn+#SXL6)+^E
zm@%7M1^~otvh?n<{orRQx$4&@w^e1H+z{cg1ChFs>PSj%m6(DcPFkaQ4z;l`LJ^51
z*;bOpO?uJ1uT?8NC|ZA$TSTlh!eB<8b`JuEs;l?B%19pA{K2`KOm2q1lh8_j7U&hq
zVFm+jX(r|V(90+cFEN+}COt)_{f>57;=U&kOa_l0#M1i6R!rDfB!BieUn&yoDCE-4
zP$NIDzg?%5erq^pl}!?MY-Ksu!ZF!{wtVW!X$~)PR}FUbhnCeyUEzcC5CGab@F3u7
zfMNW4iIgq^kL2;Odqz_h$3eGgyf{iU(B`y_}^>)&CJnJA!&4IDA1J)6jRGd7?u1*EUntq9l$5`u3?4<**w9{q#sfO2%q
z{noK_f9tL3@%!jqgajEb*nrw5VFA3lR`A0YMz@wj&b`BnQ7V?Gn|NT9Zu|<<$auW4
z<6V=vtW}NCu8|$;rO_lJ)KhBK&)NVWv2_^PzlJOxEfBkFSx{+x?;RBf-hb
zN|$VVEg3q8W+Lb9u>