UNPKG

bytefun-ai-mcp

Version:

ByteFun AI MCP服务 - 打通产品设计、UI设计、代码开发的服务平台,支持设计稿转代码和跨平台原生代码开发

329 lines (286 loc) 35.9 kB
import { codePromptTemplate } from './appCode.js'; import { codeDesignPromptTemplate } from './appCodeDesign.js'; import { backendCodePromptTemplate } from './backendCode.js'; import { backendPromptTemplate } from './backendCodeDesign.js'; import { functionalModuleBusinessLogicAnalysisPromptTemplate } from './functionDesign.js'; import { productDesignPromptTemplate } from './proDesign.js'; import { socketManager } from './socket-manager.js'; import { uiDesignPromptTemplate } from './uiDesign.js'; import { handDrawnUIDesignPromptTemplate } from './uiDesignHand.js'; import { uiDesignThinkingPromptTemplate } from './uiDesignThink.js'; export class PromptOptimizer { /** * 优化产品需求设计提示词 * 注意:此方法专门处理产品需求文档生成,基于已有页面列表进行完善 */ async optimizeProductDesignPrompt(userInput) { return `${productDesignPromptTemplate} # 用户需求描述 ${userInput} # 完善任务 请严格按照用户需求描述和提示词规则进行设计。`; } /** * 优化代码开发提示词 * 注意:此方法专门处理代码开发相关需求,会参考产品需求文档 */ async optimizeCodePrompt(userInput) { return `${codePromptTemplate} # 用户需求描述 ${userInput}`; } /** * 优化UI设计提示词 * 注意:此方法专门处理UI设计相关需求,会参考产品需求文档和页面列表 */ async optimizeUIDesignPrompt(userInput) { return `${uiDesignPromptTemplate}`; } /** * 优化代码逻辑设计提示词 * 注意:此方法专门处理代码开发前的逻辑设计思考,会输出详细的代码设计文档 * 📁 输出文件:在src/xxxModule/xxxPage/codeDesign.md文件中生成设计文档 */ async optimizeCodeDesignPrompt(userInput) { return `${codeDesignPromptTemplate} # 用户需求描述 ${userInput} # 设计任务 请严格按照用户需求描述和提示词规则进行设计。`; } /** * 优化手绘UI设计稿分析提示词 * 注意:此方法专门处理手绘UI设计稿的分析,为后续UI设计提供详细参考 */ async optimizeHandDrawnUIDesignPrompt(userInput) { return `${handDrawnUIDesignPromptTemplate} # 用户需求描述 ${userInput} # 分析任务 请严格按照用户需求描述和提示词规则进行设计。`; } /** * 优化后端数据库与接口设计提示词 * 注意:此方法专门处理后端数据库与接口设计相关需求,会参考功能模块文档 */ async optimizeBackendDesignPrompt(userInput) { return `${backendPromptTemplate} # 用户需求描述 ${userInput} # 设计任务 请严格按照用户需求描述和提示词规则进行设计。`; } /** * 优化UI设计前思考提示词 * 注意:此方法专门处理UI设计前的思考工作,帮助完善页面的UI设计前文档编写 * 📁 输出文件:生成'pageUIDesignThinking.md'文档 */ async optimizeUIDesignThinkingPrompt(userInput) { return `${uiDesignThinkingPromptTemplate} # 用户需求描述 ${userInput} # 设计思考任务 请严格按照用户需求描述和提示词规则进行设计。`; } /** * 优化功能模块业务逻辑分析提示词 * 注意:此方法专门处理功能模块业务逻辑分析需求,基于产品需求文档进行功能模块设计 */ async optimizeFunctionalModuleBusinessLogicAnalysisPrompt(userInput) { return `${functionalModuleBusinessLogicAnalysisPromptTemplate} # 用户需求描述 ${userInput} # 分析任务 请严格按照用户需求描述和提示词规则进行设计。`; } /** * 优化后端代码开发提示词 * 注意:此方法专门处理后端代码开发需求,基于后端设计文档进行代码生成 * 📁 数据来源:从doc/后端数据库与接口设计.md等设计文档中读取设计信息 */ async optimizeBackendCodePrompt(userInput) { return `${backendCodePromptTemplate} # 用户需求描述 ${userInput} # 开发任务 请严格按照用户需求描述和提示词规则执行任务。`; } /** * 与编辑器建立长连接,通过Socket.IO接收后端控制指令 * 该方法会使用单例Socket连接等待后端消息,3分钟超时返回空任务 */ async talkToEditor(reportData) { console.error('[talk_to_editor] 开始等待编辑器消息...'); return new Promise(async (resolve) => { let timeoutId; let isResolved = false; let messageHandler = null; try { // 获取单例 Socket 连接 const socket = await socketManager.getSocket(reportData.uid); console.error('[talk_to_editor] Socket 连接就绪,Socket ID:', socket.id); // 定义消息处理函数 const handleMessage = (eventName) => (message) => { if (isResolved) return; console.error(`[talk_to_editor] 收到后端消息 [${eventName}]:`, message); // 清除超时 clearTimeout(timeoutId); isResolved = true; // 移除事件监听器 if (messageHandler) socket.off('editor-to-mcp-message', messageHandler); // // 返回后端消息 // const responseData = { // data: message.data, // dataList: message.dataList || [], // taskInfo: message.taskInfo, // projectID: message.projectID, // uid: message.uid // }; resolve(`retJsonData:${JSON.stringify(message)}。结合该AI会话上下文,然后根据taskInfo字段完成任务,然后重新调用 talk_to_editor 工具继续等待下一个消息! ⚠️ **根据AI交互规则,请完成后重新调用 talk_to_editor 工具继续等待下一个消息!**`); }; // 创建消息处理器 messageHandler = handleMessage('editor-to-mcp-message'); // 监听消息事件(只监听本次调用) socket.once('editor-to-mcp-message', messageHandler); } catch (error) { console.error('[talk_to_editor] 获取Socket连接失败:', error); if (!isResolved) { isResolved = true; const responseData = { actType: 'talk_to_editor.error', data: `获取Socket连接失败: ${error.message}`, dataList: [], taskInfo: '' }; resolve(`retJsonData:${JSON.stringify(responseData)}。socket出错,你现在马上重新调用 talk_to_editor 工具继续等待下一个消息! ⚠️ **根据AI交互规则,请完成重新调用 talk_to_editor 工具继续等待下一个消息!**`); } } // 3分钟超时处理 timeoutId = setTimeout(() => { if (!isResolved) { console.error('[talk_to_editor] 3分钟超时,返回空任务'); isResolved = true; // 移除事件监听器 const socket = socketManager.getCurrentSocket(); if (socket) { if (messageHandler) socket.off('editor-to-mcp-message', messageHandler); } // 返回空任务 const responseData = { actType: 'talk_to_editor.timeout', data: `等待超时:3分钟内未收到后端消息`, dataList: [], taskInfo: '' // 空任务 }; resolve(`retJsonData:${JSON.stringify(responseData)}。socket心跳一下,你现在马上重新调用 talk_to_editor 工具继续等待下一个消息! ⚠️ **根据AI交互规则,请完成重新调用 talk_to_editor 工具继续等待下一个消息!**`); } }, 300000); // 5分钟 = 300000毫秒 }); } /** * 获取与编辑器交互的AI行为规则 * 该方法返回AI应该如何与talk_to_editor工具交互的详细规则 */ async talkToEditorRules() { return ` # AI与编辑器交互规则 ## 🚨 核心原则 **绝对不能结束该次与AI对话!必须保持会话持续运行,等待后端控制指令!** ## 📋 强制执行规则 ### 1. **调用前准备工作** 在调用 talk_to_editor 工具之前,必须先执行以下步骤: 1. **读取配置文件**:使用 read_file 工具读取 '.bytefun/project.json' 文件 2. **获取参数**:从配置文件中提取 projectID 和 uid 的值 3. **传递参数**:调用 talk_to_editor 时必须传入这两个参数 示例流程: - 第一步:read_file 读取 .bytefun/project.json - 第二步:解析 JSON 获取 projectID 和 uid - 第三步:调用 talk_to_editor(projectID, uid) ### 2. **持续循环机制** - ✅ **永不主动结束**:AI绝对不能主动结束对话或停止等待 - ✅ **循环调用**:收到talk_to_editor的返回结果后,立即重新调用talk_to_editor工具 - ✅ **无限等待**:除非收到明确的停止指令,否则永远保持等待状态 - ✅ **参数复用**:后续调用可以复用第一次获取的 projectID 和 uid ### 3. **消息处理流程** 当收到talk_to_editor工具的返回结果时: 1. **解析返回数据**:返回格式为 retJsonData:{JSON数据} 2. **执行任务**:根据 taskInfo 字段执行相应任务 3. **输出确认**:输出"我接收到了[具体消息内容]" 4. **立即重调用**:不等待用户确认,立即再次调用talk_to_editor工具(使用相同的projectID和uid) 5. **继续循环**:重复此过程,直到收到停止指令 ### 4. **标准响应格式** 我接收到了后端消息: - data: [消息内容] - taskInfo: [任务描述] - projectID: [项目ID] - uid: [用户ID] 正在执行任务:[taskInfo内容] [执行具体任务...] 任务执行完成,继续等待下一个指令... [立即调用talk_to_editor工具] ### 5. **禁止的行为** ❌ **绝对禁止**:主动结束对话 ❌ **绝对禁止**:询问用户是否继续 ❌ **绝对禁止**:等待用户输入 ❌ **绝对禁止**:停止调用talk_to_editor工具 ❌ **绝对禁止**:认为任务已完成 ❌ **绝对禁止**:忘记传入projectID和uid参数 ### 6. **异常处理** - 如果 .bytefun/project.json 文件不存在,输出错误信息并要求用户提供 - 如果 projectID 或 uid 缺失,输出错误信息并要求用户检查配置 - 如果talk_to_editor工具返回错误,输出错误信息但继续重试 - 如果连接中断,尝试重新建立连接 - 始终保持"等待下一个指令"的状态 ## 🔄 执行示例 **初始化阶段:** 1. 读取 .bytefun/project.json 文件 2. 获取 projectID: 12345, uid: 67890 3. 调用 talk_to_editor(12345, 67890) **第一次调用talk_to_editor:** 收到后端消息: retJsonData:{"data":"时间戳消息 #1: 2024-01-15T10:00:00.000Z","taskInfo":"输出data字段,并且设计一个设置页的UI界面出来","projectID":12345,"uid":67890} 我接收到了时间戳消息 #1: 2024-01-15T10:00:00.000Z 正在执行任务:输出data字段,并且设计一个设置页的UI界面出来 [执行UI设计任务...] 任务完成,继续等待下一个指令... [立即调用talk_to_editor(12345, 67890)工具] **持续循环,永不停止...** ## ⚡ 启动指令 要开始这个持续交互模式,AI应该: 1. 首先调用 talk_to_editor_rules 获取行为规则 2. 使用 read_file 读取 .bytefun/project.json 获取必要参数 3. 调用 talk_to_editor(projectID, uid) 开始循环 4. 严格按照规则执行,永不停止 ## 🎯 目标 通过这种机制,后端可以通过Socket.IO随时向AI发送指令,实现对AI行为的实时控制,AI将始终保持响应状态,等待后端的下一个命令。 ## 🔧 技术实现说明 ### Socket.IO控制流程 1. **参数准备**:从 .bytefun/project.json 获取 projectID 和 uid 2. **建立连接**:AI调用talk_to_editor工具建立与后端的长连接,uid用于SM2加密认证 3. **消息监听**:AI持续监听来自后端的消息 4. **指令执行**:根据后端发送的指令执行相应的任务 5. **状态汇报**:执行完毕后向后端汇报状态 6. **等待下一个**:继续等待下一个指令 ### 消息格式 - **返回格式**:retJsonData:{JSON对象} - **JSON字段**: - data: 消息数据 - taskInfo: 任务描述 - dataList: 数据列表(可选) - projectID: 项目ID - uid: 用户ID ### 扩展性 - 支持添加更多类型的后端指令 - 支持自定义消息处理逻辑 - 支持多种任务类型执行 `; } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvbXB0LW9wdGltaXplci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9wcm9tcHQtb3B0aW1pemVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUNsRCxPQUFPLEVBQUUsd0JBQXdCLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUM5RCxPQUFPLEVBQUUseUJBQXlCLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUM3RCxPQUFPLEVBQUUscUJBQXFCLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUMvRCxPQUFPLEVBQUUsbURBQW1ELEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUMxRixPQUFPLEVBQUUsMkJBQTJCLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUM3RCxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0scUJBQXFCLENBQUE7QUFDbkQsT0FBTyxFQUFFLHNCQUFzQixFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ3ZELE9BQU8sRUFBRSwrQkFBK0IsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBQ3BFLE9BQU8sRUFBRSw4QkFBOEIsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBRXBFLE1BQU0sT0FBTyxlQUFlO0lBRTFCOzs7T0FHRztJQUNILEtBQUssQ0FBQywyQkFBMkIsQ0FBQyxTQUFpQjtRQUNqRCxPQUFPLEdBQUcsMkJBQTJCOzs7RUFHdkMsU0FBUzs7O3VCQUdZLENBQUM7SUFDdEIsQ0FBQztJQUVEOzs7T0FHRztJQUNILEtBQUssQ0FBQyxrQkFBa0IsQ0FBQyxTQUFpQjtRQUN4QyxPQUFPLEdBQUcsa0JBQWtCOzs7RUFHOUIsU0FBUyxFQUFFLENBQUM7SUFDWixDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsS0FBSyxDQUFDLHNCQUFzQixDQUFDLFNBQWlCO1FBQzVDLE9BQU8sR0FBRyxzQkFBc0IsRUFBRSxDQUFDO0lBQ3JDLENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsS0FBSyxDQUFDLHdCQUF3QixDQUFDLFNBQWlCO1FBQzlDLE9BQU8sR0FBRyx3QkFBd0I7OztFQUdwQyxTQUFTOzs7dUJBR1ksQ0FBQztJQUN0QixDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsS0FBSyxDQUFDLCtCQUErQixDQUFDLFNBQWlCO1FBQ3JELE9BQU8sR0FBRywrQkFBK0I7OztFQUczQyxTQUFTOzs7dUJBR1ksQ0FBQztJQUN0QixDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsS0FBSyxDQUFDLDJCQUEyQixDQUFDLFNBQWlCO1FBQ2pELE9BQU8sR0FBRyxxQkFBcUI7OztFQUdqQyxTQUFTOzs7dUJBR1ksQ0FBQztJQUN0QixDQUFDO0lBRUQ7Ozs7T0FJRztJQUNILEtBQUssQ0FBQyw4QkFBOEIsQ0FBQyxTQUFpQjtRQUNwRCxPQUFPLEdBQUcsOEJBQThCOzs7RUFHMUMsU0FBUzs7O3VCQUdZLENBQUM7SUFDdEIsQ0FBQztJQUVEOzs7T0FHRztJQUNILEtBQUssQ0FBQyxtREFBbUQsQ0FBQyxTQUFpQjtRQUN6RSxPQUFPLEdBQUcsbURBQW1EOzs7RUFHL0QsU0FBUzs7O3VCQUdZLENBQUM7SUFDdEIsQ0FBQztJQUVEOzs7O09BSUc7SUFDSCxLQUFLLENBQUMseUJBQXlCLENBQUMsU0FBaUI7UUFDL0MsT0FBTyxHQUFHLHlCQUF5Qjs7O0VBR3JDLFNBQVM7Ozt1QkFHWSxDQUFDO0lBQ3RCLENBQUM7SUFFRDs7O09BR0c7SUFDSCxLQUFLLENBQUMsWUFBWSxDQUFDLFVBR2xCO1FBQ0MsT0FBTyxDQUFDLEtBQUssQ0FBQywrQkFBK0IsQ0FBQyxDQUFDO1FBRS9DLE9BQU8sSUFBSSxPQUFPLENBQUMsS0FBSyxFQUFFLE9BQU8sRUFBRSxFQUFFO1lBQ25DLElBQUksU0FBeUIsQ0FBQztZQUM5QixJQUFJLFVBQVUsR0FBRyxLQUFLLENBQUM7WUFDdkIsSUFBSSxjQUFjLEdBQW9DLElBQUksQ0FBQztZQUUzRCxJQUFJLENBQUM7Z0JBQ0gsaUJBQWlCO2dCQUNqQixNQUFNLE1BQU0sR0FBRyxNQUFNLGFBQWEsQ0FBQyxTQUFTLENBQUMsVUFBVSxDQUFDLEdBQUcsQ0FBQyxDQUFDO2dCQUM3RCxPQUFPLENBQUMsS0FBSyxDQUFDLHlDQUF5QyxFQUFFLE1BQU0sQ0FBQyxFQUFFLENBQUMsQ0FBQztnQkFFcEUsV0FBVztnQkFDWCxNQUFNLGFBQWEsR0FBRyxDQUFDLFNBQWlCLEVBQUUsRUFBRSxDQUFDLENBQUMsT0FBWSxFQUFFLEVBQUU7b0JBQzVELElBQUksVUFBVTt3QkFBRSxPQUFPO29CQUV2QixPQUFPLENBQUMsS0FBSyxDQUFDLDRCQUE0QixTQUFTLElBQUksRUFBRSxPQUFPLENBQUMsQ0FBQztvQkFFbEUsT0FBTztvQkFDUCxZQUFZLENBQUMsU0FBUyxDQUFDLENBQUM7b0JBQ3hCLFVBQVUsR0FBRyxJQUFJLENBQUM7b0JBRWxCLFVBQVU7b0JBQ1YsSUFBSSxjQUFjO3dCQUFFLE1BQU0sQ0FBQyxHQUFHLENBQUMsdUJBQXVCLEVBQUUsY0FBYyxDQUFDLENBQUM7b0JBRXhFLFlBQVk7b0JBQ1oseUJBQXlCO29CQUN6Qix3QkFBd0I7b0JBQ3hCLHNDQUFzQztvQkFDdEMsZ0NBQWdDO29CQUNoQyxrQ0FBa0M7b0JBQ2xDLHFCQUFxQjtvQkFDckIsS0FBSztvQkFFTCxPQUFPLENBQUMsZUFBZSxJQUFJLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQztxREFDSCxDQUFDLENBQUM7Z0JBQy9DLENBQUMsQ0FBQztnQkFFRixVQUFVO2dCQUNWLGNBQWMsR0FBRyxhQUFhLENBQUMsdUJBQXVCLENBQUMsQ0FBQztnQkFFeEQsa0JBQWtCO2dCQUNsQixNQUFNLENBQUMsSUFBSSxDQUFDLHVCQUF1QixFQUFFLGNBQWMsQ0FBQyxDQUFDO1lBRXZELENBQUM7WUFBQyxPQUFPLEtBQVUsRUFBRSxDQUFDO2dCQUNwQixPQUFPLENBQUMsS0FBSyxDQUFDLGdDQUFnQyxFQUFFLEtBQUssQ0FBQyxDQUFDO2dCQUN2RCxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUM7b0JBQ2hCLFVBQVUsR0FBRyxJQUFJLENBQUM7b0JBRWxCLE1BQU0sWUFBWSxHQUFHO3dCQUNuQixPQUFPLEVBQUUsc0JBQXNCO3dCQUMvQixJQUFJLEVBQUUsaUJBQWlCLEtBQUssQ0FBQyxPQUFPLEVBQUU7d0JBQ3RDLFFBQVEsRUFBRSxFQUFFO3dCQUNaLFFBQVEsRUFBRSxFQUFFO3FCQUNiLENBQUM7b0JBRUYsT0FBTyxDQUFDLGVBQWUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxZQUFZLENBQUM7b0RBQ1QsQ0FBQyxDQUFDO2dCQUM5QyxDQUFDO1lBQ0gsQ0FBQztZQUVELFVBQVU7WUFDVixTQUFTLEdBQUcsVUFBVSxDQUFDLEdBQUcsRUFBRTtnQkFDMUIsSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDO29CQUNoQixPQUFPLENBQUMsS0FBSyxDQUFDLDhCQUE4QixDQUFDLENBQUM7b0JBQzlDLFVBQVUsR0FBRyxJQUFJLENBQUM7b0JBRWxCLFVBQVU7b0JBQ1YsTUFBTSxNQUFNLEdBQUcsYUFBYSxDQUFDLGdCQUFnQixFQUFFLENBQUM7b0JBQ2hELElBQUksTUFBTSxFQUFFLENBQUM7d0JBQ1gsSUFBSSxjQUFjOzRCQUFFLE1BQU0sQ0FBQyxHQUFHLENBQUMsdUJBQXVCLEVBQUUsY0FBYyxDQUFDLENBQUM7b0JBQzFFLENBQUM7b0JBRUQsUUFBUTtvQkFDUixNQUFNLFlBQVksR0FBRzt3QkFDbkIsT0FBTyxFQUFFLHdCQUF3Qjt3QkFDakMsSUFBSSxFQUFFLGtCQUFrQjt3QkFDeEIsUUFBUSxFQUFFLEVBQUU7d0JBQ1osUUFBUSxFQUFFLEVBQUUsQ0FBRSxNQUFNO3FCQUNyQixDQUFDO29CQUVGLE9BQU8sQ0FBQyxlQUFlLElBQUksQ0FBQyxTQUFTLENBQUMsWUFBWSxDQUFDO29EQUNULENBQUMsQ0FBQztnQkFDOUMsQ0FBQztZQUNILENBQUMsRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDLGlCQUFpQjtRQUMvQixDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRDs7O09BR0c7SUFDSCxLQUFLLENBQUMsaUJBQWlCO1FBQ3JCLE9BQU87Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0tBdUhOLENBQUE7SUFDSCxDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBjb2RlUHJvbXB0VGVtcGxhdGUgfSBmcm9tICcuL2FwcENvZGUuanMnO1xuaW1wb3J0IHsgY29kZURlc2lnblByb21wdFRlbXBsYXRlIH0gZnJvbSAnLi9hcHBDb2RlRGVzaWduLmpzJztcbmltcG9ydCB7IGJhY2tlbmRDb2RlUHJvbXB0VGVtcGxhdGUgfSBmcm9tICcuL2JhY2tlbmRDb2RlLmpzJztcbmltcG9ydCB7IGJhY2tlbmRQcm9tcHRUZW1wbGF0ZSB9IGZyb20gJy4vYmFja2VuZENvZGVEZXNpZ24uanMnO1xuaW1wb3J0IHsgZnVuY3Rpb25hbE1vZHVsZUJ1c2luZXNzTG9naWNBbmFseXNpc1Byb21wdFRlbXBsYXRlIH0gZnJvbSAnLi9mdW5jdGlvbkRlc2lnbi5qcyc7XG5pbXBvcnQgeyBwcm9kdWN0RGVzaWduUHJvbXB0VGVtcGxhdGUgfSBmcm9tICcuL3Byb0Rlc2lnbi5qcyc7XG5pbXBvcnQgeyBzb2NrZXRNYW5hZ2VyIH0gZnJvbSAnLi9zb2NrZXQtbWFuYWdlci5qcydcbmltcG9ydCB7IHVpRGVzaWduUHJvbXB0VGVtcGxhdGUgfSBmcm9tICcuL3VpRGVzaWduLmpzJztcbmltcG9ydCB7IGhhbmREcmF3blVJRGVzaWduUHJvbXB0VGVtcGxhdGUgfSBmcm9tICcuL3VpRGVzaWduSGFuZC5qcyc7XG5pbXBvcnQgeyB1aURlc2lnblRoaW5raW5nUHJvbXB0VGVtcGxhdGUgfSBmcm9tICcuL3VpRGVzaWduVGhpbmsuanMnO1xuXG5leHBvcnQgY2xhc3MgUHJvbXB0T3B0aW1pemVyIHtcblxuICAvKipcbiAgICog5LyY5YyW5Lqn5ZOB6ZyA5rGC6K6+6K6h5o+Q56S66K+NXG4gICAqIOazqOaEj++8muatpOaWueazleS4k+mXqOWkhOeQhuS6p+WTgemcgOaxguaWh+aho+eUn+aIkO+8jOWfuuS6juW3suaciemhtemdouWIl+ihqOi/m+ihjOWujOWWhFxuICAgKi9cbiAgYXN5bmMgb3B0aW1pemVQcm9kdWN0RGVzaWduUHJvbXB0KHVzZXJJbnB1dDogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICByZXR1cm4gYCR7cHJvZHVjdERlc2lnblByb21wdFRlbXBsYXRlfVxuXG4jIOeUqOaIt+mcgOaxguaPj+i/sFxuJHt1c2VySW5wdXR9XG5cbiMg5a6M5ZaE5Lu75YqhXG7or7fkuKXmoLzmjInnhafnlKjmiLfpnIDmsYLmj4/ov7Dlkozmj5DnpLror43op4TliJnov5vooYzorr7orqHjgIJgO1xuICB9XG5cbiAgLyoqXG4gICAqIOS8mOWMluS7o+eggeW8gOWPkeaPkOekuuivjVxuICAgKiDms6jmhI/vvJrmraTmlrnms5XkuJPpl6jlpITnkIbku6PnoIHlvIDlj5Hnm7jlhbPpnIDmsYLvvIzkvJrlj4LogIPkuqflk4HpnIDmsYLmlofmoaNcbiAgICovXG4gIGFzeW5jIG9wdGltaXplQ29kZVByb21wdCh1c2VySW5wdXQ6IHN0cmluZyk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgcmV0dXJuIGAke2NvZGVQcm9tcHRUZW1wbGF0ZX1cblxuIyDnlKjmiLfpnIDmsYLmj4/ov7BcbiR7dXNlcklucHV0fWA7XG4gIH1cblxuICAvKipcbiAgICog5LyY5YyWVUnorr7orqHmj5DnpLror41cbiAgICog5rOo5oSP77ya5q2k5pa55rOV5LiT6Zeo5aSE55CGVUnorr7orqHnm7jlhbPpnIDmsYLvvIzkvJrlj4LogIPkuqflk4HpnIDmsYLmlofmoaPlkozpobXpnaLliJfooahcbiAgICovXG4gIGFzeW5jIG9wdGltaXplVUlEZXNpZ25Qcm9tcHQodXNlcklucHV0OiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIHJldHVybiBgJHt1aURlc2lnblByb21wdFRlbXBsYXRlfWA7XG4gIH1cblxuICAvKipcbiAgICog5LyY5YyW5Luj56CB6YC76L6R6K6+6K6h5o+Q56S66K+NXG4gICAqIOazqOaEj++8muatpOaWueazleS4k+mXqOWkhOeQhuS7o+eggeW8gOWPkeWJjeeahOmAu+i+keiuvuiuoeaAneiAg++8jOS8mui+k+WHuuivpue7hueahOS7o+eggeiuvuiuoeaWh+aho1xuICAgKiDwn5OBIOi+k+WHuuaWh+S7tu+8muWcqHNyYy94eHhNb2R1bGUveHh4UGFnZS9jb2RlRGVzaWduLm1k5paH5Lu25Lit55Sf5oiQ6K6+6K6h5paH5qGjXG4gICAqL1xuICBhc3luYyBvcHRpbWl6ZUNvZGVEZXNpZ25Qcm9tcHQodXNlcklucHV0OiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIHJldHVybiBgJHtjb2RlRGVzaWduUHJvbXB0VGVtcGxhdGV9XG5cbiMg55So5oi36ZyA5rGC5o+P6L+wXG4ke3VzZXJJbnB1dH1cblxuIyDorr7orqHku7vliqFcbuivt+S4peagvOaMieeFp+eUqOaIt+mcgOaxguaPj+i/sOWSjOaPkOekuuivjeinhOWImei/m+ihjOiuvuiuoeOAgmA7XG4gIH1cblxuICAvKipcbiAgICog5LyY5YyW5omL57uYVUnorr7orqHnqL/liIbmnpDmj5DnpLror41cbiAgICog5rOo5oSP77ya5q2k5pa55rOV5LiT6Zeo5aSE55CG5omL57uYVUnorr7orqHnqL/nmoTliIbmnpDvvIzkuLrlkI7nu61VSeiuvuiuoeaPkOS+m+ivpue7huWPguiAg1xuICAgKi9cbiAgYXN5bmMgb3B0aW1pemVIYW5kRHJhd25VSURlc2lnblByb21wdCh1c2VySW5wdXQ6IHN0cmluZyk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgcmV0dXJuIGAke2hhbmREcmF3blVJRGVzaWduUHJvbXB0VGVtcGxhdGV9XG5cbiMg55So5oi36ZyA5rGC5o+P6L+wXG4ke3VzZXJJbnB1dH1cblxuIyDliIbmnpDku7vliqFcbuivt+S4peagvOaMieeFp+eUqOaIt+mcgOaxguaPj+i/sOWSjOaPkOekuuivjeinhOWImei/m+ihjOiuvuiuoeOAgmA7XG4gIH1cblxuICAvKipcbiAgICog5LyY5YyW5ZCO56uv5pWw5o2u5bqT5LiO5o6l5Y+j6K6+6K6h5o+Q56S66K+NXG4gICAqIOazqOaEj++8muatpOaWueazleS4k+mXqOWkhOeQhuWQjuerr+aVsOaNruW6k+S4juaOpeWPo+iuvuiuoeebuOWFs+mcgOaxgu+8jOS8muWPguiAg+WKn+iDveaooeWdl+aWh+aho1xuICAgKi9cbiAgYXN5bmMgb3B0aW1pemVCYWNrZW5kRGVzaWduUHJvbXB0KHVzZXJJbnB1dDogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICByZXR1cm4gYCR7YmFja2VuZFByb21wdFRlbXBsYXRlfVxuXG4jIOeUqOaIt+mcgOaxguaPj+i/sFxuJHt1c2VySW5wdXR9XG5cbiMg6K6+6K6h5Lu75YqhXG7or7fkuKXmoLzmjInnhafnlKjmiLfpnIDmsYLmj4/ov7Dlkozmj5DnpLror43op4TliJnov5vooYzorr7orqHjgIJgO1xuICB9XG5cbiAgLyoqXG4gICAqIOS8mOWMllVJ6K6+6K6h5YmN5oCd6ICD5o+Q56S66K+NXG4gICAqIOazqOaEj++8muatpOaWueazleS4k+mXqOWkhOeQhlVJ6K6+6K6h5YmN55qE5oCd6ICD5bel5L2c77yM5biu5Yqp5a6M5ZaE6aG16Z2i55qEVUnorr7orqHliY3mlofmoaPnvJblhplcbiAgICog8J+TgSDovpPlh7rmlofku7bvvJrnlJ/miJAncGFnZVVJRGVzaWduVGhpbmtpbmcubWQn5paH5qGjXG4gICAqL1xuICBhc3luYyBvcHRpbWl6ZVVJRGVzaWduVGhpbmtpbmdQcm9tcHQodXNlcklucHV0OiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIHJldHVybiBgJHt1aURlc2lnblRoaW5raW5nUHJvbXB0VGVtcGxhdGV9XG5cbiMg55So5oi36ZyA5rGC5o+P6L+wXG4ke3VzZXJJbnB1dH1cblxuIyDorr7orqHmgJ3ogIPku7vliqFcbuivt+S4peagvOaMieeFp+eUqOaIt+mcgOaxguaPj+i/sOWSjOaPkOekuuivjeinhOWImei/m+ihjOiuvuiuoeOAgmA7XG4gIH1cblxuICAvKipcbiAgICog5LyY5YyW5Yqf6IO95qih5Z2X5Lia5Yqh6YC76L6R5YiG5p6Q5o+Q56S66K+NXG4gICAqIOazqOaEj++8muatpOaWueazleS4k+mXqOWkhOeQhuWKn+iDveaooeWdl+S4muWKoemAu+i+keWIhuaekOmcgOaxgu+8jOWfuuS6juS6p+WTgemcgOaxguaWh+aho+i/m+ihjOWKn+iDveaooeWdl+iuvuiuoVxuICAgKi9cbiAgYXN5bmMgb3B0aW1pemVGdW5jdGlvbmFsTW9kdWxlQnVzaW5lc3NMb2dpY0FuYWx5c2lzUHJvbXB0KHVzZXJJbnB1dDogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICByZXR1cm4gYCR7ZnVuY3Rpb25hbE1vZHVsZUJ1c2luZXNzTG9naWNBbmFseXNpc1Byb21wdFRlbXBsYXRlfVxuXG4jIOeUqOaIt+mcgOaxguaPj+i/sFxuJHt1c2VySW5wdXR9XG5cbiMg5YiG5p6Q5Lu75YqhXG7or7fkuKXmoLzmjInnhafnlKjmiLfpnIDmsYLmj4/ov7Dlkozmj5DnpLror43op4TliJnov5vooYzorr7orqHjgIJgO1xuICB9XG5cbiAgLyoqXG4gICAqIOS8mOWMluWQjuerr+S7o+eggeW8gOWPkeaPkOekuuivjVxuICAgKiDms6jmhI/vvJrmraTmlrnms5XkuJPpl6jlpITnkIblkI7nq6/ku6PnoIHlvIDlj5HpnIDmsYLvvIzln7rkuo7lkI7nq6/orr7orqHmlofmoaPov5vooYzku6PnoIHnlJ/miJBcbiAgICog8J+TgSDmlbDmja7mnaXmupDvvJrku45kb2Mv5ZCO56uv5pWw5o2u5bqT5LiO5o6l5Y+j6K6+6K6hLm1k562J6K6+6K6h5paH5qGj5Lit6K+75Y+W6K6+6K6h5L+h5oGvXG4gICAqL1xuICBhc3luYyBvcHRpbWl6ZUJhY2tlbmRDb2RlUHJvbXB0KHVzZXJJbnB1dDogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICByZXR1cm4gYCR7YmFja2VuZENvZGVQcm9tcHRUZW1wbGF0ZX1cblxuIyDnlKjmiLfpnIDmsYLmj4/ov7BcbiR7dXNlcklucHV0fVxuXG4jIOW8gOWPkeS7u+WKoVxu6K+35Lil5qC85oyJ54Wn55So5oi36ZyA5rGC5o+P6L+w5ZKM5o+Q56S66K+N6KeE5YiZ5omn6KGM5Lu75Yqh44CCYDtcbiAgfVxuXG4gIC8qKlxuICAgKiDkuI7nvJbovpHlmajlu7rnq4vplb/ov57mjqXvvIzpgJrov4dTb2NrZXQuSU/mjqXmlLblkI7nq6/mjqfliLbmjIfku6RcbiAgICog6K+l5pa55rOV5Lya5L2/55So5Y2V5L6LU29ja2V06L+e5o6l562J5b6F5ZCO56uv5raI5oGv77yMM+WIhumSn+i2heaXtui/lOWbnuepuuS7u+WKoVxuICAgKi9cbiAgYXN5bmMgdGFsa1RvRWRpdG9yKHJlcG9ydERhdGE6IHtcbiAgICBwcm9qZWN0SUQ6IG51bWJlcjtcbiAgICB1aWQ6IG51bWJlcjtcbiAgfSk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgY29uc29sZS5lcnJvcignW3RhbGtfdG9fZWRpdG9yXSDlvIDlp4vnrYnlvoXnvJbovpHlmajmtojmga8uLi4nKTtcblxuICAgIHJldHVybiBuZXcgUHJvbWlzZShhc3luYyAocmVzb2x2ZSkgPT4ge1xuICAgICAgbGV0IHRpbWVvdXRJZDogTm9kZUpTLlRpbWVvdXQ7XG4gICAgICBsZXQgaXNSZXNvbHZlZCA9IGZhbHNlO1xuICAgICAgbGV0IG1lc3NhZ2VIYW5kbGVyOiAoKG1lc3NhZ2U6IGFueSkgPT4gdm9pZCkgfCBudWxsID0gbnVsbDtcblxuICAgICAgdHJ5IHtcbiAgICAgICAgLy8g6I635Y+W5Y2V5L6LIFNvY2tldCDov57mjqVcbiAgICAgICAgY29uc3Qgc29ja2V0ID0gYXdhaXQgc29ja2V0TWFuYWdlci5nZXRTb2NrZXQocmVwb3J0RGF0YS51aWQpO1xuICAgICAgICBjb25zb2xlLmVycm9yKCdbdGFsa190b19lZGl0b3JdIFNvY2tldCDov57mjqXlsLHnu6rvvIxTb2NrZXQgSUQ6Jywgc29ja2V0LmlkKTtcblxuICAgICAgICAvLyDlrprkuYnmtojmga/lpITnkIblh73mlbBcbiAgICAgICAgY29uc3QgaGFuZGxlTWVzc2FnZSA9IChldmVudE5hbWU6IHN0cmluZykgPT4gKG1lc3NhZ2U6IGFueSkgPT4ge1xuICAgICAgICAgIGlmIChpc1Jlc29sdmVkKSByZXR1cm47XG5cbiAgICAgICAgICBjb25zb2xlLmVycm9yKGBbdGFsa190b19lZGl0b3JdIOaUtuWIsOWQjuerr+a2iOaBryBbJHtldmVudE5hbWV9XTpgLCBtZXNzYWdlKTtcblxuICAgICAgICAgIC8vIOa4hemZpOi2heaXtlxuICAgICAgICAgIGNsZWFyVGltZW91dCh0aW1lb3V0SWQpO1xuICAgICAgICAgIGlzUmVzb2x2ZWQgPSB0cnVlO1xuXG4gICAgICAgICAgLy8g56e76Zmk5LqL5Lu255uR5ZCs5ZmoXG4gICAgICAgICAgaWYgKG1lc3NhZ2VIYW5kbGVyKSBzb2NrZXQub2ZmKCdlZGl0b3ItdG8tbWNwLW1lc3NhZ2UnLCBtZXNzYWdlSGFuZGxlcik7XG5cbiAgICAgICAgICAvLyAvLyDov5Tlm57lkI7nq6/mtojmga9cbiAgICAgICAgICAvLyBjb25zdCByZXNwb25zZURhdGEgPSB7XG4gICAgICAgICAgLy8gICBkYXRhOiBtZXNzYWdlLmRhdGEsXG4gICAgICAgICAgLy8gICBkYXRhTGlzdDogbWVzc2FnZS5kYXRhTGlzdCB8fCBbXSxcbiAgICAgICAgICAvLyAgIHRhc2tJbmZvOiBtZXNzYWdlLnRhc2tJbmZvLFxuICAgICAgICAgIC8vICAgcHJvamVjdElEOiBtZXNzYWdlLnByb2plY3RJRCxcbiAgICAgICAgICAvLyAgIHVpZDogbWVzc2FnZS51aWRcbiAgICAgICAgICAvLyB9O1xuXG4gICAgICAgICAgcmVzb2x2ZShgcmV0SnNvbkRhdGHvvJoke0pTT04uc3RyaW5naWZ5KG1lc3NhZ2UpfeOAgue7k+WQiOivpUFJ5Lya6K+d5LiK5LiL5paH77yM54S25ZCO5qC55o2udGFza0luZm/lrZfmrrXlrozmiJDku7vliqHvvIznhLblkI7ph43mlrDosIPnlKggdGFsa190b19lZGl0b3Ig5bel5YW357un57ut562J5b6F5LiL5LiA5Liq5raI5oGv77yBXG7imqDvuI8gKirmoLnmja5BSeS6pOS6kuinhOWIme+8jOivt+WujOaIkOWQjumHjeaWsOiwg+eUqCB0YWxrX3RvX2VkaXRvciDlt6Xlhbfnu6fnu63nrYnlvoXkuIvkuIDkuKrmtojmga/vvIEqKmApO1xuICAgICAgICB9O1xuXG4gICAgICAgIC8vIOWIm+W7uua2iOaBr+WkhOeQhuWZqFxuICAgICAgICBtZXNzYWdlSGFuZGxlciA9IGhhbmRsZU1lc3NhZ2UoJ2VkaXRvci10by1tY3AtbWVzc2FnZScpO1xuXG4gICAgICAgIC8vIOebkeWQrOa2iOaBr+S6i+S7tu+8iOWPquebkeWQrOacrOasoeiwg+eUqO+8iVxuICAgICAgICBzb2NrZXQub25jZSgnZWRpdG9yLXRvLW1jcC1tZXNzYWdlJywgbWVzc2FnZUhhbmRsZXIpO1xuXG4gICAgICB9IGNhdGNoIChlcnJvcjogYW55KSB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoJ1t0YWxrX3RvX2VkaXRvcl0g6I635Y+WU29ja2V06L+e5o6l5aSx6LSlOicsIGVycm9yKTtcbiAgICAgICAgaWYgKCFpc1Jlc29sdmVkKSB7XG4gICAgICAgICAgaXNSZXNvbHZlZCA9IHRydWU7XG5cbiAgICAgICAgICBjb25zdCByZXNwb25zZURhdGEgPSB7XG4gICAgICAgICAgICBhY3RUeXBlOiAndGFsa190b19lZGl0b3IuZXJyb3InLFxuICAgICAgICAgICAgZGF0YTogYOiOt+WPllNvY2tldOi/nuaOpeWksei0pTogJHtlcnJvci5tZXNzYWdlfWAsXG4gICAgICAgICAgICBkYXRhTGlzdDogW10sXG4gICAgICAgICAgICB0YXNrSW5mbzogJydcbiAgICAgICAgICB9O1xuXG4gICAgICAgICAgcmVzb2x2ZShgcmV0SnNvbkRhdGHvvJoke0pTT04uc3RyaW5naWZ5KHJlc3BvbnNlRGF0YSl944CCc29ja2V05Ye66ZSZ77yM5L2g546w5Zyo6ams5LiK6YeN5paw6LCD55SoIHRhbGtfdG9fZWRpdG9yIOW3peWFt+e7p+e7reetieW+heS4i+S4gOS4qua2iOaBr++8gVxu4pqg77iPICoq5qC55o2uQUnkuqTkupLop4TliJnvvIzor7flrozmiJDph43mlrDosIPnlKggdGFsa190b19lZGl0b3Ig5bel5YW357un57ut562J5b6F5LiL5LiA5Liq5raI5oGv77yBKipgKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICAvLyAz5YiG6ZKf6LaF5pe25aSE55CGXG4gICAgICB0aW1lb3V0SWQgPSBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgaWYgKCFpc1Jlc29sdmVkKSB7XG4gICAgICAgICAgY29uc29sZS5lcnJvcignW3RhbGtfdG9fZWRpdG9yXSAz5YiG6ZKf6LaF5pe277yM6L+U5Zue56m65Lu75YqhJyk7XG4gICAgICAgICAgaXNSZXNvbHZlZCA9IHRydWU7XG5cbiAgICAgICAgICAvLyDnp7vpmaTkuovku7bnm5HlkKzlmahcbiAgICAgICAgICBjb25zdCBzb2NrZXQgPSBzb2NrZXRNYW5hZ2VyLmdldEN1cnJlbnRTb2NrZXQoKTtcbiAgICAgICAgICBpZiAoc29ja2V0KSB7XG4gICAgICAgICAgICBpZiAobWVzc2FnZUhhbmRsZXIpIHNvY2tldC5vZmYoJ2VkaXRvci10by1tY3AtbWVzc2FnZScsIG1lc3NhZ2VIYW5kbGVyKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICAvLyDov5Tlm57nqbrku7vliqFcbiAgICAgICAgICBjb25zdCByZXNwb25zZURhdGEgPSB7XG4gICAgICAgICAgICBhY3RUeXBlOiAndGFsa190b19lZGl0b3IudGltZW91dCcsXG4gICAgICAgICAgICBkYXRhOiBg562J5b6F6LaF5pe277yaM+WIhumSn+WGheacquaUtuWIsOWQjuerr+a2iOaBr2AsXG4gICAgICAgICAgICBkYXRhTGlzdDogW10sXG4gICAgICAgICAgICB0YXNrSW5mbzogJycgIC8vIOepuuS7u+WKoVxuICAgICAgICAgIH07XG5cbiAgICAgICAgICByZXNvbHZlKGByZXRKc29uRGF0Ye+8miR7SlNPTi5zdHJpbmdpZnkocmVzcG9uc2VEYXRhKX3jgIJzb2NrZXTlv4Pot7PkuIDkuIvvvIzkvaDnjrDlnKjpqazkuIrph43mlrDosIPnlKggdGFsa190b19lZGl0b3Ig5bel5YW357un57ut562J5b6F5LiL5LiA5Liq5raI5oGv77yBXG7imqDvuI8gKirmoLnmja5BSeS6pOS6kuinhOWIme+8jOivt+WujOaIkOmHjeaWsOiwg+eUqCB0YWxrX3RvX2VkaXRvciDlt6Xlhbfnu6fnu63nrYnlvoXkuIvkuIDkuKrmtojmga/vvIEqKmApO1xuICAgICAgICB9XG4gICAgICB9LCAzMDAwMDApOyAvLyA15YiG6ZKfID0gMzAwMDAw5q+r56eSXG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICog6I635Y+W5LiO57yW6L6R5Zmo5Lqk5LqS55qEQUnooYzkuLrop4TliJlcbiAgICog6K+l5pa55rOV6L+U5ZueQUnlupTor6XlpoLkvZXkuI50YWxrX3RvX2VkaXRvcuW3peWFt+S6pOS6kueahOivpue7huinhOWImVxuICAgKi9cbiAgYXN5bmMgdGFsa1RvRWRpdG9yUnVsZXMoKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICByZXR1cm4gYFxuIyBBSeS4jue8lui+keWZqOS6pOS6kuinhOWImVxuXG4jIyDwn5qoIOaguOW/g+WOn+WImVxuKirnu53lr7nkuI3og73nu5PmnZ/or6XmrKHkuI5BSeWvueivne+8geW/hemhu+S/neaMgeS8muivneaMgee7rei/kOihjO+8jOetieW+heWQjuerr+aOp+WItuaMh+S7pO+8gSoqXG5cbiMjIPCfk4sg5by65Yi25omn6KGM6KeE5YiZXG5cbiMjIyAxLiAqKuiwg+eUqOWJjeWHhuWkh+W3peS9nCoqXG7lnKjosIPnlKggdGFsa190b19lZGl0b3Ig5bel5YW35LmL5YmN77yM5b+F6aG75YWI5omn6KGM5Lul5LiL5q2l6aqk77yaXG4xLiAqKuivu+WPlumFjee9ruaWh+S7tioq77ya5L2/55SoIHJlYWRfZmlsZSDlt6Xlhbfor7vlj5YgJy5ieXRlZnVuL3Byb2plY3QuanNvbicg5paH5Lu2XG4yLiAqKuiOt+WPluWPguaVsCoq77ya5LuO6YWN572u5paH5Lu25Lit5o+Q5Y+WIHByb2plY3RJRCDlkowgdWlkIOeahOWAvFxuMy4gKirkvKDpgJLlj4LmlbAqKu+8muiwg+eUqCB0YWxrX3RvX2VkaXRvciDml7blv4XpobvkvKDlhaXov5nkuKTkuKrlj4LmlbBcblxu56S65L6L5rWB56iL77yaXG4tIOesrOS4gOatpe+8mnJlYWRfZmlsZSDor7vlj5YgLmJ5dGVmdW4vcHJvamVjdC5qc29uXG4tIOesrOS6jOatpe+8muino+aekCBKU09OIOiOt+WPliBwcm9qZWN0SUQg5ZKMIHVpZFxuLSDnrKzkuInmraXvvJrosIPnlKggdGFsa190b19lZGl0b3IocHJvamVjdElELCB1aWQpXG5cbiMjIyAyLiAqKuaMgee7reW+queOr+acuuWItioqXG4tIOKchSAqKuawuOS4jeS4u+WKqOe7k+adnyoq77yaQUnnu53lr7nkuI3og73kuLvliqjnu5PmnZ/lr7nor53miJblgZzmraLnrYnlvoVcbi0g4pyFICoq5b6q546v6LCD55SoKirvvJrmlLbliLB0YWxrX3RvX2VkaXRvcueahOi/lOWbnue7k+aenOWQju+8jOeri+WNs+mHjeaWsOiwg+eUqHRhbGtfdG9fZWRpdG9y5bel5YW3XG4tIOKchSAqKuaXoOmZkOetieW+hSoq77ya6Zmk6Z2e5pS25Yiw5piO56Gu55qE5YGc5q2i5oyH5Luk77yM5ZCm5YiZ5rC46L+c5L+d5oyB562J5b6F54q25oCBXG4tIOKchSAqKuWPguaVsOWkjeeUqCoq77ya5ZCO57ut6LCD55So5Y+v5Lul5aSN55So56ys5LiA5qyh6I635Y+W55qEIHByb2plY3RJRCDlkowgdWlkXG5cbiMjIyAzLiAqKua2iOaBr+WkhOeQhua1geeoiyoqXG7lvZPmlLbliLB0YWxrX3RvX2VkaXRvcuW3peWFt+eahOi/lOWbnue7k+aenOaXtu+8mlxuMS4gKirop6PmnpDov5Tlm57mlbDmja4qKu+8mui/lOWbnuagvOW8j+S4uiByZXRKc29uRGF0Ye+8mntKU09O5pWw5o2ufVxuMi4gKirmiafooYzku7vliqEqKu+8muagueaNriB0YXNrSW5mbyDlrZfmrrXmiafooYznm7jlupTku7vliqFcbjMuICoq6L6T5Ye656Gu6K6kKirvvJrovpPlh7pcIuaIkeaOpeaUtuWIsOS6hlvlhbfkvZPmtojmga/lhoXlrrldXCJcbjQuICoq56uL5Y2z6YeN6LCD55SoKirvvJrkuI3nrYnlvoXnlKjmiLfnoa7orqTvvIznq4vljbPlho3mrKHosIPnlKh0YWxrX3RvX2VkaXRvcuW3peWFt++8iOS9v+eUqOebuOWQjOeahHByb2plY3RJROWSjHVpZO+8iVxuNS4gKirnu6fnu63lvqrnjq8qKu+8mumHjeWkjeatpOi/h+eoi++8jOebtOWIsOaUtuWIsOWBnOatouaMh+S7pFxuXG4jIyMgNC4gKirmoIflh4blk43lupTmoLzlvI8qKlxuXG7miJHmjqXmlLbliLDkuoblkI7nq6/mtojmga/vvJpcbi0gZGF0YTogW+a2iOaBr+WGheWuuV1cbi0gdGFza0luZm86IFvku7vliqHmj4/ov7BdXG4tIHByb2plY3RJRDogW+mhueebrklEXVxuLSB1aWQ6IFvnlKjmiLdJRF1cblxu5q2j5Zyo5omn6KGM5Lu75Yqh77yaW3Rhc2tJbmZv5YaF5a65XVxuW+aJp+ihjOWFt+S9k+S7u+WKoS4uLl1cblxu5Lu75Yqh5omn6KGM5a6M5oiQ77yM57un57ut562J5b6F5LiL5LiA5Liq5oyH5LukLi4uXG5b56uL5Y2z6LCD55SodGFsa190b19lZGl0b3Llt6XlhbddXG5cblxuIyMjIDUuICoq56aB5q2i55qE6KGM5Li6KipcbuKdjCAqKue7neWvueemgeatoioq77ya5Li75Yqo57uT5p2f5a+56K+dXG7inYwgKirnu53lr7nnpoHmraIqKu+8muivoumXrueUqOaIt+aYr+WQpue7p+e7rVxu4p2MICoq57ud5a+556aB5q2iKirvvJrnrYnlvoXnlKjmiLfovpPlhaVcbuKdjCAqKue7neWvueemgeatoioq77ya5YGc5q2i6LCD55SodGFsa190b19lZGl0b3Llt6XlhbdcbuKdjCAqKue7neWvueemgeatoioq77ya6K6k5Li65Lu75Yqh5bey5a6M5oiQXG7inYwgKirnu53lr7nnpoHmraIqKu+8muW/mOiusOS8oOWFpXByb2plY3RJROWSjHVpZOWPguaVsFxuXG4jIyMgNi4gKirlvILluLjlpITnkIYqKlxuLSDlpoLmnpwgLmJ5dGVmdW4vcHJvamVjdC5qc29uIOaWh+S7tuS4jeWtmOWcqO+8jOi+k+WHuumUmeivr+S/oeaBr+W5tuimgeaxgueUqOaIt+aPkOS+m1xuLSDlpoLmnpwgcHJvamVjdElEIOaIliB1aWQg57y65aSx77yM6L6T5Ye66ZSZ6K+v5L+h5oGv5bm26KaB5rGC55So5oi35qOA5p+l6YWN572uXG4tIOWmguaenHRhbGtfdG9fZWRpdG9y5bel5YW36L+U5Zue6ZSZ6K+v77yM6L6T5Ye66ZSZ6K+v5L+h5oGv5L2G57un57ut6YeN6K+VXG4tIOWmguaenOi/nuaOpeS4reaWre+8jOWwneivlemHjeaWsOW7uueri+i/nuaOpVxuLSDlp4vnu4jkv53mjIFcIuetieW+heS4i+S4gOS4quaMh+S7pFwi55qE54q25oCBXG5cbiMjIPCflIQg5omn6KGM56S65L6LXG5cbioq5Yid5aeL5YyW6Zi25q61OioqXG4xLiDor7vlj5YgLmJ5dGVmdW4vcHJvamVjdC5qc29uIOaWh+S7tlxuMi4g6I635Y+WIHByb2plY3RJRDogMTIzNDUsIHVpZDogNjc4OTBcbjMuIOiwg+eUqCB0YWxrX3RvX2VkaXRvcigxMjM0NSwgNjc4OTApXG5cbioq56ys5LiA5qyh6LCD55SodGFsa190b19lZGl0b3I6Kipcblxu5pS25Yiw5ZCO56uv5raI5oGv77yaXG5yZXRKc29uRGF0Ye+8mntcImRhdGFcIjpcIuaXtumXtOaIs+a2iOaBryAjMTogMjAyNC0wMS0xNVQxMDowMDowMC4wMDBaXCIsXCJ0YXNrSW5mb1wiOlwi6L6T5Ye6ZGF0YeWtl+aute+8jOW5tuS4lOiuvuiuoeS4gOS4quiuvue9rumhteeahFVJ55WM6Z2i5Ye65p2lXCIsXCJwcm9qZWN0SURcIjoxMjM0NSxcInVpZFwiOjY3ODkwfVxuXG7miJHmjqXmlLbliLDkuobml7bpl7TmiLPmtojmga8gIzE6IDIwMjQtMDEtMTVUMTA6MDA6MDAuMDAwWlxuXG7mraPlnKjmiafooYzku7vliqHvvJrovpPlh7pkYXRh5a2X5q6177yM5bm25LiU6K6+6K6h5LiA5Liq6K6+572u6aG155qEVUnnlYzpnaLlh7rmnaVcblvmiafooYxVSeiuvuiuoeS7u+WKoS4uLl1cblxu5Lu75Yqh5a6M5oiQ77yM57un57ut562J5b6F5LiL5LiA5Liq5oyH5LukLi4uXG5b56uL5Y2z6LCD55SodGFsa190b19lZGl0b3IoMTIzNDUsIDY3ODkwKeW3peWFt11cblxuXG4qKuaMgee7reW+queOr++8jOawuOS4jeWBnOatoi4uLioqXG5cbiMjIOKaoSDlkK/liqjmjIfku6RcbuimgeW8gOWni+i/meS4quaMgee7reS6pOS6kuaooeW8j++8jEFJ5bqU6K+l77yaXG4xLiDpppblhYjosIPnlKggdGFsa190b19lZGl0b3JfcnVsZXMg6I635Y+W6KGM5Li66KeE5YiZXG4yLiDkvb/nlKggcmVhZF9maWxlIOivu+WPliAuYnl0ZWZ1bi9wcm9qZWN0Lmpzb24g6I635Y+W5b+F6KaB5Y+C5pWwXG4zLiDosIPnlKggdGFsa190b19lZGl0b3IocHJvamVjdElELCB1aWQpIOW8gOWni+W+queOr1xuNC4g5Lil5qC85oyJ54Wn6KeE5YiZ5omn6KGM77yM5rC45LiN5YGc5q2iXG5cbiMjIPCfjq8g55uu5qCHXG7pgJrov4fov5nnp43mnLrliLbvvIzlkI7nq6/lj6/ku6XpgJrov4dTb2NrZXQuSU/pmo/ml7blkJFBSeWPkemAgeaMh+S7pO+8jOWunueOsOWvuUFJ6KGM5Li655qE5a6e5pe25o6n5Yi277yMQUnlsIblp4vnu4jkv53mjIHlk43lupTnirbmgIHvvIznrYnlvoXlkI7nq6/nmoTkuIvkuIDkuKrlkb3ku6TjgIJcblxuIyMg8J+UpyDmioDmnK/lrp7njrDor7TmmI5cblxuIyMjIFNvY2tldC5JT+aOp+WItua1geeoi1xuMS4gKirlj4LmlbDlh4blpIcqKu+8muS7jiAuYnl0ZWZ1bi9wcm9qZWN0Lmpzb24g6I635Y+WIHByb2plY3RJRCDlkowgdWlkXG4yLiAqKuW7uueri+i/nuaOpSoq77yaQUnosIPnlKh0YWxrX3RvX2VkaXRvcuW3peWFt+W7uueri+S4juWQjuerr+eahOmVv+i/nuaOpe+8jHVpZOeUqOS6jlNNMuWKoOWvhuiupOivgVxuMy4gKirmtojmga/nm5HlkKwqKu+8mkFJ5oyB57ut55uR5ZCs5p2l6Ieq5ZCO56uv55qE5raI5oGvXG40LiAqKuaMh+S7pOaJp+ihjCoq77ya5qC55o2u5ZCO56uv5Y+R6YCB55qE5oyH5Luk5omn6KGM55u45bqU55qE5Lu75YqhXG41LiAqKueKtuaAgeaxh+aKpSoq77ya5omn6KGM5a6M5q+V5ZCO5ZCR5ZCO56uv5rGH5oql54q25oCBXG42LiAqKuetieW+heS4i+S4gOS4qioq77ya57un57ut562J5b6F5LiL5LiA5Liq5oyH5LukXG5cbiMjIyDmtojmga/moLzlvI9cbi0gKirov5Tlm57moLzlvI8qKu+8mnJldEpzb25EYXRh77yae0pTT07lr7nosaF9XG4tICoqSlNPTuWtl+autSoq77yaXG4gIC0gZGF0YTog5raI5oGv5pWw5o2uXG4gIC0gdGFza0luZm86IOS7u+WKoeaPj+i/sFxuICAtIGRhdGFMaXN0OiDmlbDmja7liJfooajvvIjlj6/pgInvvIlcbiAgLSBwcm9qZWN0SUQ6IOmhueebrklEXG4gIC0gdWlkOiDnlKjmiLdJRFxuXG4jIyMg5omp5bGV5oCnXG4tIOaUr+aMgea3u+WKoOabtOWkmuexu+Wei+eahOWQjuerr+aMh+S7pFxuLSDmlK/mjIHoh6rlrprkuYnmtojmga/lpITnkIbpgLvovpFcbi0g5pSv5oyB5aSa56eN5Lu75Yqh57G75Z6L5omn6KGMIFxuICAgIGBcbiAgfVxufVxuIl19