UNPKG

bytefun-ai-mcp

Version:

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

415 lines (371 loc) 47.1 kB
import { codePromptTemplate } from './appCode.js'; import { codeDesignPromptTemplate } from './appCodeDesign.js'; import { backendCodePromptTemplate } from './backendCode.js'; import { backendPromptTemplate } from './backendCodeDesign.js'; import { accountBusinessLogic, functionalModulePromptTemplate, homeBusinessLogic, searchBusinessLogic, startUpBusinessLogic } from './functionDesign.js'; import { codePromptTemplate as jumpPageCodePromptTemplate } from './jumpPageCode.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'; import { uiDesignPromptTemplate as uiDesignEditPromptTemplate } from './uiDesignEdit.js'; import { uiDeclarativePromptTemplate } from './uiDeclarative.js'; import { uiSpecDesignPromptTemplate } from './uiSpecDesign.js'; import { uiDesignReplenishPromptTemplate } from './uiDesignReplenish.js'; import { uiDesignGuidePromptTemplate } from './uiDesignGuide.js'; import { uiCodePromptTemplate } from './uiCode.js'; import { understandingCodeFrameworkTemplate } from './appCodeRule.js'; import { uiDesignPromptTemplate as uiDesignAddPagePromptTemplate } from './uiDesignAddPage.js'; export class PromptOptimizer { /** * 优化产品需求设计提示词 * 注意:此方法专门处理产品需求文档生成,基于已有页面列表进行完善 */ async optimizeProductDesignPrompt(industry, userInput) { return productDesignPromptTemplate; } /** * 优化代码开发提示词 * 注意:此方法专门处理代码开发相关需求,会参考产品需求文档 */ async optimizeCodePrompt(userInput) { return `${codePromptTemplate} # 用户需求描述 ${userInput}`; } /** * 优化UI设计提示词 * 注意:此方法专门处理UI设计相关需求,会参考产品需求文档和页面列表 */ async optimizeUIDesignPrompt(userInput) { return `${uiDesignPromptTemplate}`; } /** * 新增页面的UI设计提示词 * 注意:此方法专门处理新增页面到产品需求及UI设计流程的提示词 */ async optimizeUIDesignAddPagePrompt(userInput) { return `${uiDesignAddPagePromptTemplate}`; } /** * 获取 UI 设计指导提示词 * 用于统一 UI 设计流程的十步执行规范 */ async uiDesignGuidePrompt() { return `${uiDesignGuidePromptTemplate}`; } /** * 优化代码逻辑设计提示词 * 注意:此方法专门处理代码开发前的逻辑设计思考,会输出详细的代码设计文档 * 📁 输出文件:在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 optimizeFunctionalModulePrompt(functionalModule, userInput) { // 打印接收到的参数 switch (functionalModule) { case 'startUp': return functionalModulePromptTemplate.replace('{{functionalModule}}', startUpBusinessLogic); case 'account': return functionalModulePromptTemplate.replace('{{functionalModule}}', accountBusinessLogic); case 'home': return functionalModulePromptTemplate.replace('{{functionalModule}}', homeBusinessLogic); case 'search': return functionalModulePromptTemplate.replace('{{functionalModule}}', searchBusinessLogic); } return functionalModulePromptTemplate.replace('{{functionalModule}}', '无'); } /** * 优化后端代码开发提示词 * 注意:此方法专门处理后端代码开发需求,基于后端设计文档进行代码生成 * 📁 数据来源:从doc/后端数据库与接口设计.md等设计文档中读取设计信息 */ async optimizeBackendCodePrompt(userInput) { return `${backendCodePromptTemplate} # 用户需求描述 ${userInput} # 开发任务 请严格按照用户需求描述和提示词规则执行任务。`; } /** * 优化UI设计修改提示词 * 注意:此方法专门处理UI设计稿的修改需求,返回详细的UI设计规范和修改指导 * 📁 基于uiDesignEdit.ts中的设计规范模板 */ async optimizeUIDesignEditPrompt(userInput) { return `${uiDesignEditPromptTemplate} # 用户需求描述 ${userInput} # 修改任务 请严格按照用户需求描述和提示词规则进行UI设计稿的修改。`; } /** * 优化UI设计HTML补充提示词 * 注意:该方法用于对已有UI设计HTML进行规则化补充 */ async optimizeUIDesignReplenishPrompt(userInput) { return `${uiDesignReplenishPromptTemplate} # 用户需求描述 ${userInput} # 补充任务 请根据上述规则对HTML节点进行补充与规范化。`; } /** * 优化页面跳转代码开发提示词 * 注意:此方法专门处理页面跳转代码开发相关需求,基于UI设计进度进行页面跳转逻辑实现 * 📁 基于jumpPageCode.ts中的跳转规则模板 */ async optimizeJumpPageCodePrompt(userInput) { return `${jumpPageCodePromptTemplate}`; } /** * 优化声明式UI设计提示词 * 注意:此方法专门处理声明式UI设计相关需求,使用JSON格式来描述UI界面 * 📁 基于uiDeclarative.ts中的声明式UI组件规则模板 */ async optimizeDeclarativeUIPrompt(userInput) { return `${uiDeclarativePromptTemplate}`; } /** * 优化UI设计规范提示词 * 注意:此方法专门处理UI设计规范相关需求,基于产品需求文档完成UI规范设计 * 📁 基于uiSpecDesign.ts中的UI设计规范模板 */ async optimizeUISpecDesignPrompt(userInput) { return `${uiSpecDesignPromptTemplate}`; } /** * 实现UI代码提示词 * 注意:此方法专门处理UI前端代码实现需求,严格按步骤规则执行 */ async implementUICodePrompt(userInput) { return `${uiCodePromptTemplate} # 用户需求描述 ${userInput}`; } async understandingAppCodeFrameworkPrompt() { return `${understandingCodeFrameworkTemplate}`; } /** * 与编辑器建立长连接,通过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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvbXB0LW9wdGltaXplci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9wcm9tcHQtb3B0aW1pemVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUNsRCxPQUFPLEVBQUUsd0JBQXdCLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUM5RCxPQUFPLEVBQUUseUJBQXlCLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUM3RCxPQUFPLEVBQUUscUJBQXFCLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUMvRCxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsOEJBQThCLEVBQUUsaUJBQWlCLEVBQUUsbUJBQW1CLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUN6SixPQUFPLEVBQUUsa0JBQWtCLElBQUksMEJBQTBCLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQztBQUNyRixPQUFPLEVBQUUsMkJBQTJCLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUM3RCxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0scUJBQXFCLENBQUE7QUFDbkQsT0FBTyxFQUFFLHNCQUFzQixFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ3ZELE9BQU8sRUFBRSwrQkFBK0IsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBQ3BFLE9BQU8sRUFBRSw4QkFBOEIsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQ3BFLE9BQU8sRUFBRSxzQkFBc0IsSUFBSSwwQkFBMEIsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBQ3pGLE9BQU8sRUFBRSwyQkFBMkIsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQ2pFLE9BQU8sRUFBRSwwQkFBMEIsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBQy9ELE9BQU8sRUFBRSwrQkFBK0IsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQ3pFLE9BQU8sRUFBRSwyQkFBMkIsRUFBRSxNQUFNLG9CQUFv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Q29udGVudCI6WyJpbXBvcnQgeyBjb2RlUHJvbXB0VGVtcGxhdGUgfSBmcm9tICcuL2FwcENvZGUuanMnO1xuaW1wb3J0IHsgY29kZURlc2lnblByb21wdFRlbXBsYXRlIH0gZnJvbSAnLi9hcHBDb2RlRGVzaWduLmpzJztcbmltcG9ydCB7IGJhY2tlbmRDb2RlUHJvbXB0VGVtcGxhdGUgfSBmcm9tICcuL2JhY2tlbmRDb2RlLmpzJztcbmltcG9ydCB7IGJhY2tlbmRQcm9tcHRUZW1wbGF0ZSB9IGZyb20gJy4vYmFja2VuZENvZGVEZXNpZ24uanMnO1xuaW1wb3J0IHsgYWNjb3VudEJ1c2luZXNzTG9naWMsIGZ1bmN0aW9uYWxNb2R1bGVQcm9tcHRUZW1wbGF0ZSwgaG9tZUJ1c2luZXNzTG9naWMsIHNlYXJjaEJ1c2luZXNzTG9naWMsIHN0YXJ0VXBCdXNpbmVzc0xvZ2ljIH0gZnJvbSAnLi9mdW5jdGlvbkRlc2lnbi5qcyc7XG5pbXBvcnQgeyBjb2RlUHJvbXB0VGVtcGxhdGUgYXMganVtcFBhZ2VDb2RlUHJvbXB0VGVtcGxhdGUgfSBmcm9tICcuL2p1bXBQYWdlQ29kZS5qcyc7XG5pbXBvcnQgeyBwcm9kdWN0RGVzaWduUHJvbXB0VGVtcGxhdGUgfSBmcm9tICcuL3Byb0Rlc2lnbi5qcyc7XG5pbXBvcnQgeyBzb2NrZXRNYW5hZ2VyIH0gZnJvbSAnLi9zb2NrZXQtbWFuYWdlci5qcydcbmltcG9ydCB7IHVpRGVzaWduUHJvbXB0VGVtcGxhdGUgfSBmcm9tICcuL3VpRGVzaWduLmpzJztcbmltcG9ydCB7IGhhbmREcmF3blVJRGVzaWduUHJvbXB0VGVtcGxhdGUgfSBmcm9tICcuL3VpRGVzaWduSGFuZC5qcyc7XG5pbXBvcnQgeyB1aURlc2lnblRoaW5raW5nUHJvbXB0VGVtcGxhdGUgfSBmcm9tICcuL3VpRGVzaWduVGhpbmsuanMnO1xuaW1wb3J0IHsgdWlEZXNpZ25Qcm9tcHRUZW1wbGF0ZSBhcyB1aURlc2lnbkVkaXRQcm9tcHRUZW1wbGF0ZSB9IGZyb20gJy4vdWlEZXNpZ25FZGl0LmpzJztcbmltcG9ydCB7IHVpRGVjbGFyYXRpdmVQcm9tcHRUZW1wbGF0ZSB9IGZyb20gJy4vdWlEZWNsYXJhdGl2ZS5qcyc7XG5pbXBvcnQgeyB1aVNwZWNEZXNpZ25Qcm9tcHRUZW1wbGF0ZSB9IGZyb20gJy4vdWlTcGVjRGVzaWduLmpzJztcbmltcG9ydCB7IHVpRGVzaWduUmVwbGVuaXNoUHJvbXB0VGVtcGxhdGUgfSBmcm9tICcuL3VpRGVzaWduUmVwbGVuaXNoLmpzJztcbmltcG9ydCB7IHVpRGVzaWduR3VpZGVQcm9tcHRUZW1wbGF0ZSB9IGZyb20gJy4vdWlEZXNpZ25HdWlkZS5qcyc7XG5pbXBvcnQgeyB1aUNvZGVQcm9tcHRUZW1wbGF0ZSB9IGZyb20gJy4vdWlDb2RlLmpzJztcbmltcG9ydCB7IHVuZGVyc3RhbmRpbmdDb2RlRnJhbWV3b3JrVGVtcGxhdGUgfSBmcm9tICcuL2FwcENvZGVSdWxlLmpzJztcbmltcG9ydCB7IHVpRGVzaWduUHJvbXB0VGVtcGxhdGUgYXMgdWlEZXNpZ25BZGRQYWdlUHJvbXB0VGVtcGxhdGUgfSBmcm9tICcuL3VpRGVzaWduQWRkUGFnZS5qcyc7XG5cbmV4cG9ydCBjbGFzcyBQcm9tcHRPcHRpbWl6ZXIge1xuXG4gIC8qKlxuICAgKiDkvJjljJbkuqflk4HpnIDmsYLorr7orqHmj5DnpLror41cbiAgICog5rOo5oSP77ya5q2k5pa55rOV5LiT6Zeo5aSE55CG5Lqn5ZOB6ZyA5rGC5paH5qGj55Sf5oiQ77yM5Z+65LqO5bey5pyJ6aG16Z2i5YiX6KGo6L+b6KGM5a6M5ZaEXG4gICAqL1xuICBhc3luYyBvcHRpbWl6ZVByb2R1Y3REZXNpZ25Qcm9tcHQoaW5kdXN0cnk6IHN0cmluZywgdXNlcklucHV0OiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIHJldHVybiBwcm9kdWN0RGVzaWduUHJvbXB0VGVtcGxhdGU7XG4gIH1cblxuICAvKipcbiAgICog5LyY5YyW5Luj56CB5byA5Y+R5o+Q56S66K+NXG4gICAqIOazqOaEj++8muatpOaWueazleS4k+mXqOWkhOeQhuS7o+eggeW8gOWPkeebuOWFs+mcgOaxgu+8jOS8muWPguiAg+S6p+WTgemcgOaxguaWh+aho1xuICAgKi9cbiAgYXN5bmMgb3B0aW1pemVDb2RlUHJvbXB0KHVzZXJJbnB1dDogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICByZXR1cm4gYCR7Y29kZVByb21wdFRlbXBsYXRlfVxuXG4jIOeUqOaIt+mcgOaxguaPj+i/sFxuJHt1c2VySW5wdXR9YDtcbiAgfVxuXG4gIC8qKlxuICAgKiDkvJjljJZVSeiuvuiuoeaPkOekuuivjVxuICAgKiDms6jmhI/vvJrmraTmlrnms5XkuJPpl6jlpITnkIZVSeiuvuiuoeebuOWFs+mcgOaxgu+8jOS8muWPguiAg+S6p+WTgemcgOaxguaWh+aho+WSjOmhtemdouWIl+ihqFxuICAgKi9cbiAgYXN5bmMgb3B0aW1pemVVSURlc2lnblByb21wdCh1c2VySW5wdXQ6IHN0cmluZyk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgcmV0dXJuIGAke3VpRGVzaWduUHJvbXB0VGVtcGxhdGV9YDtcbiAgfVxuXG4gIC8qKlxuICAgKiDmlrDlop7pobXpnaLnmoRVSeiuvuiuoeaPkOekuuivjVxuICAgKiDms6jmhI/vvJrmraTmlrnms5XkuJPpl6jlpITnkIbmlrDlop7pobXpnaLliLDkuqflk4HpnIDmsYLlj4pVSeiuvuiuoea1geeoi+eahOaPkOekuuivjVxuICAgKi9cbiAgYXN5bmMgb3B0aW1pemVVSURlc2lnbkFkZFBhZ2VQcm9tcHQodXNlcklucHV0OiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIHJldHVybiBgJHt1aURlc2lnbkFkZFBhZ2VQcm9tcHRUZW1wbGF0ZX1gO1xuICB9XG5cbiAgLyoqXG4gICAqIOiOt+WPliBVSSDorr7orqHmjIflr7zmj5DnpLror41cbiAgICog55So5LqO57uf5LiAIFVJIOiuvuiuoea1geeoi+eahOWNgeatpeaJp+ihjOinhOiMg1xuICAgKi9cbiAgYXN5bmMgdWlEZXNpZ25HdWlkZVByb21wdCgpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIHJldHVybiBgJHt1aURlc2lnbkd1aWRlUHJvbXB0VGVtcGxhdGV9YDtcbiAgfVxuXG4gIC8qKlxuICAgKiDkvJjljJbku6PnoIHpgLvovpHorr7orqHmj5DnpLror41cbiAgICog5rOo5oSP77ya5q2k5pa55rOV5LiT6Zeo5aSE55CG5Luj56CB5byA5Y+R5YmN55qE6YC76L6R6K6+6K6h5oCd6ICD77yM5Lya6L6T5Ye66K+m57uG55qE5Luj56CB6K6+6K6h5paH5qGjXG4gICAqIPCfk4Eg6L6T5Ye65paH5Lu277ya5Zyoc3JjL3h4eE1vZHVsZS94eHhQYWdlL2NvZGVEZXNpZ24ubWTmlofku7bkuK3nlJ/miJDorr7orqHmlofmoaNcbiAgICovXG4gIGFzeW5jIG9wdGltaXplQ29kZURlc2lnblByb21wdCh1c2VySW5wdXQ6IHN0cmluZyk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgcmV0dXJuIGAke2NvZGVEZXNpZ25Qcm9tcHRUZW1wbGF0ZX1cblxuIyDnlKjmiLfpnIDmsYLmj4/ov7BcbiR7dXNlcklucHV0fVxuXG4jIOiuvuiuoeS7u+WKoVxu6K+35Lil5qC85oyJ54Wn55So5oi36ZyA5rGC5o+P6L+w5ZKM5o+Q56S66K+N6KeE5YiZ6L+b6KGM6K6+6K6h44CCYDtcbiAgfVxuXG4gIC8qKlxuICAgKiDkvJjljJbmiYvnu5hVSeiuvuiuoeeov+WIhuaekOaPkOekuuivjVxuICAgKiDms6jmhI/vvJrmraTmlrnms5XkuJPpl6jlpITnkIbmiYvnu5hVSeiuvuiuoeeov+eahOWIhuaekO+8jOS4uuWQjue7rVVJ6K6+6K6h5o+Q5L6b6K+m57uG5Y+C6ICDXG4gICAqL1xuICBhc3luYyBvcHRpbWl6ZUhhbmREcmF3blVJRGVzaWduUHJvbXB0KHVzZXJJbnB1dDogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICByZXR1cm4gYCR7aGFuZERyYXduVUlEZXNpZ25Qcm9tcHRUZW1wbGF0ZX1cblxuIyDnlKjmiLfpnIDmsYLmj4/ov7BcbiR7dXNlcklucHV0fVxuXG4jIOWIhuaekOS7u+WKoVxu6K+35Lil5qC85oyJ54Wn55So5oi36ZyA5rGC5o+P6L+w5ZKM5o+Q56S66K+N6KeE5YiZ6L+b6KGM6K6+6K6h44CCYDtcbiAgfVxuXG4gIC8qKlxuICAgKiDkvJjljJblkI7nq6/mlbDmja7lupPkuI7mjqXlj6Porr7orqHmj5DnpLror41cbiAgICog5rOo5oSP77ya5q2k5pa55rOV5LiT6Zeo5aSE55CG5ZCO56uv5pWw5o2u5bqT5LiO5o6l5Y+j6K6+6K6h55u45YWz6ZyA5rGC77yM5Lya5Y+C6ICD5Yqf6IO95qih5Z2X5paH5qGjXG4gICAqL1xuICBhc3luYyBvcHRpbWl6ZUJhY2tlbmREZXNpZ25Qcm9tcHQodXNlcklucHV0OiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIHJldHVybiBgJHtiYWNrZW5kUHJvbXB0VGVtcGxhdGV9XG5cbiMg55So5oi36ZyA5rGC5o+P6L+wXG4ke3VzZXJJbnB1dH1cblxuIyDorr7orqHku7vliqFcbuivt+S4peagvOaMieeFp+eUqOaIt+mcgOaxguaPj+i/sOWSjOaPkOekuuivjeinhOWImei/m+ihjOiuvuiuoeOAgmA7XG4gIH1cblxuICAvKipcbiAgICog5LyY5YyWVUnorr7orqHliY3mgJ3ogIPmj5DnpLror41cbiAgICog5rOo5oSP77ya5q2k5pa55rOV5LiT6Zeo5aSE55CGVUnorr7orqHliY3nmoTmgJ3ogIPlt6XkvZzvvIzluK7liqnlrozlloTpobXpnaLnmoRVSeiuvuiuoeWJjeaWh+aho+e8luWGmVxuICAgKiDwn5OBIOi+k+WHuuaWh+S7tu+8mueUn+aIkCdwYWdlVUlEZXNpZ25UaGlua2luZy5tZCfmlofmoaNcbiAgICovXG4gIGFzeW5jIG9wdGltaXplVUlEZXNpZ25UaGlua2luZ1Byb21wdCh1c2VySW5wdXQ6IHN0cmluZyk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgcmV0dXJuIGAke3VpRGVzaWduVGhpbmtpbmdQcm9tcHRUZW1wbGF0ZX1cblxuIyDnlKjmiLfpnIDmsYLmj4/ov7BcbiR7dXNlcklucHV0fVxuXG4jIOiuvuiuoeaAneiAg+S7u+WKoVxu6K+35Lil5qC85oyJ54Wn55So5oi36ZyA5rGC5o+P6L+w5ZKM5o+Q56S66K+N6KeE5YiZ6L+b6KGM6K6+6K6h44CCYDtcbiAgfVxuXG4gIC8qKlxuICAgKiDkvJjljJblip/og73mqKHlnZfkuJrliqHpgLvovpHliIbmnpDmj5DnpLror41cbiAgICog5rOo5oSP77ya5q2k5pa55rOV5LiT6Zeo5aSE55CG5Yqf6IO95qih5Z2X5Lia5Yqh6YC76L6R5YiG5p6Q6ZyA5rGC77yM5Z+65LqO5Lqn5ZOB6ZyA5rGC5paH5qGj6L+b6KGM5Yqf6IO95qih5Z2X6K6+6K6hXG4gICAqL1xuICBhc3luYyBvcHRpbWl6ZUZ1bmN0aW9uYWxNb2R1bGVQcm9tcHQoZnVuY3Rpb25hbE1vZHVsZTogc3RyaW5nLCB1c2VySW5wdXQ6IHN0cmluZyk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgLy8g5omT5Y2w5o6l5pS25Yiw55qE5Y+C5pWwXG4gICAgc3dpdGNoIChmdW5jdGlvbmFsTW9kdWxlKSB7XG4gICAgICBjYXNlICdzdGFydFVwJzpcbiAgICAgICAgcmV0dXJuIGZ1bmN0aW9uYWxNb2R1bGVQcm9tcHRUZW1wbGF0ZS5yZXBsYWNlKCd7e2Z1bmN0aW9uYWxNb2R1bGV9fScsIHN0YXJ0VXBCdXNpbmVzc0xvZ2ljKTtcbiAgICAgIGNhc2UgJ2FjY291bnQnOlxuICAgICAgICByZXR1cm4gZnVuY3Rpb25hbE1vZHVsZVByb21wdFRlbXBsYXRlLnJlcGxhY2UoJ3t7ZnVuY3Rpb25hbE1vZHVsZX19JywgYWNjb3VudEJ1c2luZXNzTG9naWMpO1xuICAgICAgY2FzZSAnaG9tZSc6XG4gICAgICAgIHJldHVybiBmdW5jdGlvbmFsTW9kdWxlUHJvbXB0VGVtcGxhdGUucmVwbGFjZSgne3tmdW5jdGlvbmFsTW9kdWxlfX0nLCBob21lQnVzaW5lc3NMb2dpYyk7XG4gICAgICBjYXNlICdzZWFyY2gnOlxuICAgICAgICByZXR1cm4gZnVuY3Rpb25hbE1vZHVsZVByb21wdFRlbXBsYXRlLnJlcGxhY2UoJ3t7ZnVuY3Rpb25hbE1vZHVsZX19Jywgc2VhcmNoQnVzaW5lc3NMb2dpYyk7XG4gICAgfVxuICAgIHJldHVybiBmdW5jdGlvbmFsTW9kdWxlUHJvbXB0VGVtcGxhdGUucmVwbGFjZSgne3tmdW5jdGlvbmFsTW9kdWxlfX0nLCAn5pegJyk7XG4gIH1cblxuICAvKipcbiAgICog5LyY5YyW5ZCO56uv5Luj56CB5byA5Y+R5o+Q56S66K+NXG4gICAqIOazqOaEj++8muatpOaWueazleS4k+mXqOWkhOeQhuWQjuerr+S7o+eggeW8gOWPkemcgOaxgu+8jOWfuuS6juWQjuerr+iuvuiuoeaWh+aho+i/m+ihjOS7o+eggeeUn+aIkFxuICAgKiDwn5OBIOaVsOaNruadpea6kO+8muS7jmRvYy/lkI7nq6/mlbDmja7lupPkuI7mjqXlj6Porr7orqEubWTnrYnorr7orqHmlofmoaPkuK3or7vlj5borr7orqHkv6Hmga9cbiAgICovXG4gIGFzeW5jIG9wdGltaXplQmFja2VuZENvZGVQcm9tcHQodXNlcklucHV0OiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIHJldHVybiBgJHtiYWNrZW5kQ29kZVByb21wdFRlbXBsYXRlfVxuXG4jIOeUqOaIt+mcgOaxguaPj+i/sFxuJHt1c2VySW5wdXR9XG5cbiMg5byA5Y+R5Lu75YqhXG7or7fkuKXmoLzmjInnhafnlKjmiLfpnIDmsYLmj4/ov7Dlkozmj5DnpLror43op4TliJnmiafooYzku7vliqHjgIJgO1xuICB9XG5cbiAgLyoqXG4gICAqIOS8mOWMllVJ6K6+6K6h5L+u5pS55o+Q56S66K+NXG4gICAqIOazqOaEj++8muatpOaWueazleS4k+mXqOWkhOeQhlVJ6K6+6K6h56i/55qE5L+u5pS56ZyA5rGC77yM6L+U5Zue6K+m57uG55qEVUnorr7orqHop4TojIPlkozkv67mlLnmjIflr7xcbiAgICog8J+TgSDln7rkuo51aURlc2lnbkVkaXQudHPkuK3nmoTorr7orqHop4TojIPmqKHmnb9cbiAgICovXG4gIGFzeW5jIG9wdGltaXplVUlEZXNpZ25FZGl0UHJvbXB0KHVzZXJJbnB1dDogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICByZXR1cm4gYCR7dWlEZXNpZ25FZGl0UHJvbXB0VGVtcGxhdGV9XG5cbiMg55So5oi36ZyA5rGC5o+P6L+wXG4ke3VzZXJJbnB1dH1cblxuIyDkv67mlLnku7vliqFcbuivt+S4peagvOaMieeFp+eUqOaIt+mcgOaxguaPj+i/sOWSjOaPkOekuuivjeinhOWImei/m+ihjFVJ6K6+6K6h56i/55qE5L+u5pS544CCYDtcbiAgfVxuXG4gIC8qKlxuICAgKiDkvJjljJZVSeiuvuiuoUhUTUzooaXlhYXmj5DnpLror41cbiAgICog5rOo5oSP77ya6K+l5pa55rOV55So5LqO5a+55bey5pyJVUnorr7orqFIVE1M6L+b6KGM6KeE5YiZ5YyW6KGl5YWFXG4gICAqL1xuICBhc3luYyBvcHRpbWl6ZVVJRGVzaWduUmVwbGVuaXNoUHJvbXB0KHVzZXJJbnB1dDogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICByZXR1cm4gYCR7dWlEZXNpZ25SZXBsZW5pc2hQcm9tcHRUZW1wbGF0ZX1cblxuIyDnlKjmiLfpnIDmsYLmj4/ov7BcbiR7dXNlcklucHV0fVxuXG4jIOihpeWFheS7u+WKoVxu6K+35qC55o2u5LiK6L+w6KeE5YiZ5a+5SFRNTOiKgueCuei/m+ihjOihpeWFheS4juinhOiMg+WMluOAgmA7XG4gIH1cblxuICAvKipcbiAgICog5LyY5YyW6aG16Z2i6Lez6L2s5Luj56CB5byA5Y+R5o+Q56S66K+NXG4gICAqIOazqOaEj++8muatpOaWueazleS4k+mXqOWkhOeQhumhtemdoui3s+i9rOS7o+eggeW8gOWPkeebuOWFs+mcgOaxgu+8jOWfuuS6jlVJ6K6+6K6h6L+b5bqm6L+b6KGM6aG16Z2i6Lez6L2s6YC76L6R5a6e546wXG4gICAqIPCfk4Eg5Z+65LqOanVtcFBhZ2VDb2RlLnRz5Lit55qE6Lez6L2s6KeE5YiZ5qih5p2/XG4gICAqL1xuICBhc3luYyBvcHRpbWl6ZUp1bXBQYWdlQ29kZVByb21wdCh1c2VySW5wdXQ6IHN0cmluZyk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgcmV0dXJuIGAke2p1bXBQYWdlQ29kZVByb21wdFRlbXBsYXRlfWA7XG4gIH1cblxuICAvKipcbiAgICog5LyY5YyW5aOw5piO5byPVUnorr7orqHmj5DnpLror41cbiAgICog5rOo5oSP77ya5q2k5pa55rOV5LiT6Zeo5aSE55CG5aOw5piO5byPVUnorr7orqHnm7jlhbPpnIDmsYLvvIzkvb/nlKhKU09O5qC85byP5p2l5o+P6L+wVUnnlYzpnaJcbiAgICog8J+TgSDln7rkuo51aURlY2xhcmF0aXZlLnRz5Lit55qE5aOw5piO5byPVUnnu4Tku7bop4TliJnmqKHmnb9cbiAgICovXG4gIGFzeW5jIG9wdGltaXplRGVjbGFyYXRpdmVVSVByb21wdCh1c2VySW5wdXQ6IHN0cmluZyk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgcmV0dXJuIGAke3VpRGVjbGFyYXRpdmVQcm9tcHRUZW1wbGF0ZX1gO1xuICB9XG5cbiAgLyoqXG4gICAqIOS8mOWMllVJ6K6+6K6h6KeE6IyD5o+Q56S66K+NXG4gICAqIOazqOaEj++8muatpOaWueazleS4k+mXqOWkhOeQhlVJ6K6+6K6h6KeE6IyD55u45YWz6ZyA5rGC77yM5Z+65LqO5Lqn5ZOB6ZyA5rGC5paH5qGj5a6M5oiQVUnop4TojIPorr7orqFcbiAgICog8J+TgSDln7rkuo51aVNwZWNEZXNpZ24udHPkuK3nmoRVSeiuvuiuoeinhOiMg+aooeadv1xuICAgKi9cbiAgYXN5bmMgb3B0aW1pemVVSVNwZWNEZXNpZ25Qcm9tcHQodXNlcklucHV0OiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIHJldHVybiBgJHt1aVNwZWNEZXNpZ25Qcm9tcHRUZW1wbGF0ZX1gO1xuICB9XG5cbiAgLyoqXG4gICAqIOWunueOsFVJ5Luj56CB5o+Q56S66K+NXG4gICAqIOazqOaEj++8muatpOaWueazleS4k+mXqOWkhOeQhlVJ5YmN56uv5Luj56CB5a6e546w6ZyA5rGC77yM5Lil5qC85oyJ5q2l6aqk6KeE5YiZ5omn6KGMXG4gICAqL1xuICBhc3luYyBpbXBsZW1lbnRVSUNvZGVQcm9tcHQodXNlcklucHV0OiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIHJldHVybiBgJHt1aUNvZGVQcm9tcHRUZW1wbGF0ZX1cblxuIyDnlKjmiLfpnIDmsYLmj4/ov7BcbiR7dXNlcklucHV0fWA7XG4gIH1cblxuICBhc3luYyB1bmRlcnN0YW5kaW5nQXBwQ29kZUZyYW1ld29ya1Byb21wdCgpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIHJldHVybiBgJHt1bmRlcnN0YW5kaW5nQ29kZUZyYW1ld29ya1RlbXBsYXRlfWA7XG4gIH1cblxuICAvKipcbiAgICog5LiO57yW6L6R5Zmo5bu656uL6ZW/6L+e5o6l77yM6YCa6L+HU29ja2V0LklP5o6l5pS25ZCO56uv5o6n5Yi25oyH5LukXG4gICAqIOivpeaWueazleS8muS9v+eUqOWNleS+i1NvY2tldOi/nuaOpeetieW+heWQjuerr+a2iOaBr++8jDPliIbpkp/otoXml7bov5Tlm57nqbrku7vliqFcbiAgICovXG4gIGFzeW5jIHRhbGtUb0VkaXRvcihyZXBvcnREYXRhOiB7XG4gICAgcHJvamVjdElEOiBudW1iZXI7XG4gICAgdWlkOiBudW1iZXI7XG4gIH0pOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIGNvbnNvbGUuZXJyb3IoJ1t0YWxrX3RvX2VkaXRvcl0g5byA5aeL562J5b6F57yW6L6R5Zmo5raI5oGvLi4uJyk7XG5cbiAgICByZXR1cm4gbmV3IFByb21pc2UoYXN5bmMgKHJlc29sdmUpID0+IHtcbiAgICAgIGxldCB0aW1lb3V0SWQ6IE5vZGVKUy5UaW1lb3V0O1xuICAgICAgbGV0IGlzUmVzb2x2ZWQgPSBmYWxzZTtcbiAgICAgIGxldCBtZXNzYWdlSGFuZGxlcjogKChtZXNzYWdlOiBhbnkpID0+IHZvaWQpIHwgbnVsbCA9IG51bGw7XG5cbiAgICAgIHRyeSB7XG4gICAgICAgIC8vIOiOt+WPluWNleS+iyBTb2NrZXQg6L+e5o6lXG4gICAgICAgIGNvbnN0IHNvY2tldCA9IGF3YWl0IHNvY2tldE1hbmFnZXIuZ2V0U29ja2V0KHJlcG9ydERhdGEudWlkKTtcbiAgICAgICAgY29uc29sZS5lcnJvcignW3RhbGtfdG9fZWRpdG9yXSBTb2NrZXQg6L+e5o6l5bCx57uq77yMU29ja2V0IElEOicsIHNvY2tldC5pZCk7XG5cbiAgICAgICAgLy8g5a6a5LmJ5raI5oGv5aSE55CG5Ye95pWwXG4gICAgICAgIGNvbnN0IGhhbmRsZU1lc3NhZ2UgPSAoZXZlbnROYW1lOiBzdHJpbmcpID0+IChtZXNzYWdlOiBhbnkpID0+IHtcbiAgICAgICAgICBpZiAoaXNSZXNvbHZlZCkgcmV0dXJuO1xuXG4gICAgICAgICAgY29uc29sZS5lcnJvcihgW3RhbGtfdG9fZWRpdG9yXSDmlLbliLDlkI7nq6/mtojmga8gWyR7ZXZlbnROYW1lfV06YCwgbWVzc2FnZSk7XG5cbiAgICAgICAgICAvLyDmuIXpmaTotoXml7ZcbiAgICAgICAgICBjbGVhclRpbWVvdXQodGltZW91dElkKTtcbiAgICAgICAgICBpc1Jlc29sdmVkID0gdHJ1ZTtcblxuICAgICAgICAgIC8vIOenu+mZpOS6i+S7tuebkeWQrOWZqFxuICAgICAgICAgIGlmIChtZXNzYWdlSGFuZGxlcikgc29ja2V0Lm9mZignZWRpdG9yLXRvLW1jcC1tZXNzYWdlJywgbWVzc2FnZUhhbmRsZXIpO1xuXG4gICAgICAgICAgLy8gLy8g6L+U5Zue5ZCO56uv5raI5oGvXG4gICAgICAgICAgLy8gY29uc3QgcmVzcG9uc2VEYXRhID0ge1xuICAgICAgICAgIC8vICAgZGF0YTogbWVzc2FnZS5kYXRhLFxuICAgICAgICAgIC8vICAgZGF0YUxpc3Q6IG1lc3NhZ2UuZGF0YUxpc3QgfHwgW10sXG4gICAgICAgICAgLy8gICB0YXNrSW5mbzogbWVzc2FnZS50YXNrSW5mbyxcbiAgICAgICAgICAvLyAgIHByb2plY3RJRDogbWVzc2FnZS5wcm9qZWN0SUQsXG4gICAgICAgICAgLy8gICB1aWQ6IG1lc3NhZ2UudWlkXG4gICAgICAgICAgLy8gfTtcblxuICAgICAgICAgIHJlc29sdmUoYHJldEpzb25EYXRh77yaJHtKU09OLnN0cmluZ2lmeShtZXNzYWdlKX3jgILnu5PlkIjor6VBSeS8muivneS4iuS4i+aWh++8jOeEtuWQjuagueaNrnRhc2tJbmZv5a2X5q615a6M5oiQ5Lu75Yqh77yM54S25ZCO6YeN5paw6LCD55SoIHRhbGtfdG9fZWRpdG9yIOW3peWFt+e7p+e7reetieW+heS4i+S4gOS4qua2iOaBr++8gVxu4pqg77iPICoq5qC55o2uQUnkuqTkupLop4TliJnvvIzor7flrozmiJDlkI7ph43mlrDosIPnlKggdGFsa190b19lZGl0b3Ig5bel5YW357un57ut562J5b6F5LiL5LiA5Liq5raI5oGv77yBKipgKTtcbiAgICAgICAgfTtcblxuICAgICAgICAvLyDliJvlu7rmtojmga/lpITnkIblmahcbiAgICAgICAgbWVzc2FnZUhhbmRsZXIgPSBoYW5kbGVNZXNzYWdlKCdlZGl0b3ItdG8tbWNwLW1lc3NhZ2UnKTtcblxuICAgICAgICAvLyDnm5HlkKzmtojmga/kuovku7bvvIjlj6rnm5HlkKzmnKzmrKHosIPnlKjvvIlcbiAgICAgICAgc29ja2V0Lm9uY2UoJ2VkaXRvci10by1tY3AtbWVzc2FnZScsIG1lc3NhZ2VIYW5kbGVyKTtcblxuICAgICAgfSBjYXRjaCAoZXJyb3I6IGFueSkge1xuICAgICAgICBjb25zb2xlLmVycm9yKCdbdGFsa190b19lZGl0b3JdIOiOt+WPllNvY2tldOi/nuaOpeWksei0pTonLCBlcnJvcik7XG4gICAgICAgIGlmICghaXNSZXNvbHZlZCkge1xuICAgICAgICAgIGlzUmVzb2x2ZWQgPSB0cnVlO1xuXG4gICAgICAgICAgY29uc3QgcmVzcG9uc2VEYXRhID0ge1xuICAgICAgICAgICAgYWN0VHlwZTogJ3RhbGtfdG9fZWRpdG9yLmVycm9yJyxcbiAgICAgICAgICAgIGRhdGE6IGDojrflj5ZTb2NrZXTov57mjqXlpLHotKU6ICR7ZXJyb3IubWVzc2FnZX1gLFxuICAgICAgICAgICAgZGF0YUxpc3Q6IFtdLFxuICAgICAgICAgICAgdGFza0luZm86ICcnXG4gICAgICAgICAgfTtcblxuICAgICAgICAgIHJlc29sdmUoYHJldEpzb25EYXRh77yaJHtKU09OLnN0cmluZ2lmeShyZXNwb25zZURhdGEpfeOAgnNvY2tldOWHuumUme+8jOS9oOeOsOWcqOmprOS4iumHjeaWsOiwg+eUqCB0YWxrX3RvX2VkaXRvciDlt6Xlhbfnu6fnu63nrYnlvoXkuIvkuIDkuKrmtojmga/vvIFcbuKaoO+4jyAqKuagueaNrkFJ5Lqk5LqS6KeE5YiZ77yM6K+35a6M5oiQ6YeN5paw6LCD55SoIHRhbGtfdG9fZWRpdG9yIOW3peWFt+e7p+e7reetieW+heS4i+S4gOS4qua2iOaBr++8gSoqYCk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgLy8gM+WIhumSn+i2heaXtuWkhOeQhlxuICAgICAgdGltZW91dElkID0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgIGlmICghaXNSZXNvbHZlZCkge1xuICAgICAgICAgIGNvbnNvbGUuZXJyb3IoJ1t0YWxrX3RvX2VkaXRvcl0gM+WIhumSn+i2heaXtu+8jOi/lOWbnuepuuS7u+WKoScpO1xuICAgICAgICAgIGlzUmVzb2x2ZWQgPSB0cnVlO1xuXG4gICAgICAgICAgLy8g56e76Zmk5LqL5Lu255uR5ZCs5ZmoXG4gICAgICAgICAgY29uc3Qgc29ja2V0ID0gc29ja2V0TWFuYWdlci5nZXRDdXJyZW50U29ja2V0KCk7XG4gICAgICAgICAgaWYgKHNvY2tldCkge1xuICAgICAgICAgICAgaWYgKG1lc3NhZ2VIYW5kbGVyKSBzb2NrZXQub2ZmKCdlZGl0b3ItdG8tbWNwLW1lc3NhZ2UnLCBtZXNzYWdlSGFuZGxlcik7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgLy8g6L+U5Zue56m65Lu75YqhXG4gICAgICAgICAgY29uc3QgcmVzcG9uc2VEYXRhID0ge1xuICAgICAgICAgICAgYWN0VHlwZTogJ3RhbGtfdG9fZWRpdG9yLnRpbWVvdXQnLFxuICAgICAgICAgICAgZGF0YTogYOetieW+hei2heaXtu+8mjPliIbpkp/lhoXmnKrmlLbliLDlkI7nq6/mtojmga9gLFxuICAgICAgICAgICAgZGF0YUxpc3Q6IFtdLFxuICAgICAgICAgICAgdGFza0luZm86ICcnICAvLyDnqbrku7vliqFcbiAgICAgICAgICB9O1xuXG4gICAgICAgICAgcmVzb2x2ZShgcmV0SnNvbkRhdGHvvJoke0pTT04uc3RyaW5naWZ5KHJlc3BvbnNlRGF0YSl944CCc29ja2V05b+D6Lez5LiA5LiL77yM5L2g546w5Zyo6ams5LiK6YeN5paw6LCD55SoIHRhbGtfdG9fZWRpdG9yIOW3peWFt+e7p+e7reetieW+heS4i+S4gOS4qua2iOaBr++8gVxu4pqg77iPICoq5qC55o2uQUnkuqTkupLop4TliJnvvIzor7flrozmiJDph43mlrDosIPnlKggdGFsa190b19lZGl0b3Ig5bel5YW357un57ut562J5b6F5LiL5LiA5Liq5raI5oGv77yBKipgKTtcbiAgICAgICAgfVxuICAgICAgfSwgMzAwMDAwKTsgLy8gNeWIhumSnyA9IDMwMDAwMOavq+enklxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIOiOt+WPluS4jue8lui+keWZqOS6pOS6kueahEFJ6KGM5Li66KeE5YiZXG4gICAqIOivpeaWueazlei/lOWbnkFJ5bqU6K+l5aaC5L2V5LiOdGFsa190b19lZGl0b3Llt6XlhbfkuqTkupLnmoTor6bnu4bop4TliJlcbiAgICovXG4gIGFzeW5jIHRhbGtUb0VkaXRvclJ1bGVzKCk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgcmV0dXJuIGBcbiMgQUnkuI7nvJbovpHlmajkuqTkupLop4TliJlcblxuIyMg8J+aqCDmoLjlv4Pljp/liJlcbioq57ud5a+55LiN6IO957uT5p2f6K+l5qyh5LiOQUnlr7nor53vvIHlv4Xpobvkv53mjIHkvJror53mjIHnu63ov5DooYzvvIznrYnlvoXlkI7nq6/mjqfliLbmjIfku6TvvIEqKlxuXG4jIyDwn5OLIOW8uuWItuaJp+ihjOinhOWImVxuXG4jIyMgMS4gKirosIPnlKjliY3lh4blpIflt6XkvZwqKlxu5Zyo6LCD55SoIHRhbGtfdG9fZWRpdG9yIOW3peWFt+S5i+WJje+8jOW/hemhu+WFiOaJp+ihjOS7peS4i+atpemqpO+8mlxuMS4gKiror7vlj5bphY3nva7mlofku7YqKu+8muS9v+eUqCByZWFkX2ZpbGUg5bel5YW36K+75Y+WICcuYnl0ZWZ1bi9wcm9qZWN0Lmpzb24nIOaWh+S7tlxuMi4gKirojrflj5blj4LmlbAqKu+8muS7jumFjee9ruaWh+S7tuS4reaPkOWPliBwcm9qZWN0SUQg5ZKMIHVpZCDnmoTlgLxcbjMuICoq5Lyg6YCS5Y+C5pWwKirvvJrosIPnlKggdGFsa190b19lZGl0b3Ig5pe25b+F6aG75Lyg5YWl6L+Z5Lik5Liq5Y+C5pWwXG5cbuekuuS+i+a1geeoi++8mlxuLSDnrKzkuIDmraXvvJpyZWFkX2ZpbGUg6K+75Y+WIC5ieXRlZnVuL3Byb2plY3QuanNvblxuLSDnrKzkuozmraXvvJrop6PmnpAgSlNPTiDojrflj5YgcHJvamVjdElEIOWSjCB1aWRcbi0g56ys5LiJ5q2l77ya6LCD55SoIHRhbGtfdG9fZWRpdG9yKHByb2plY3RJRCwgdWlkKVxuXG4jIyMgMi4gKirmjIHnu63lvqrnjq/mnLrliLYqKlxuLSDinIUgKirmsLjkuI3kuLvliqjnu5PmnZ8qKu+8mkFJ57ud5a+55LiN6IO95Li75Yqo57uT5p2f5a+56K+d5oiW5YGc5q2i562J5b6FXG4tIOKchSAqKuW+queOr+iwg+eUqCoq77ya5pS25YiwdGFsa190b19lZGl0b3LnmoTov5Tlm57nu5PmnpzlkI7vvIznq4vljbPph43mlrDosIPnlKh0YWxrX3RvX2VkaXRvcuW3peWFt1xuLSDinIUgKirml6DpmZDnrYnlvoUqKu+8mumZpOmdnuaUtuWIsOaYjuehrueahOWBnOatouaMh+S7pO+8jOWQpuWImeawuOi/nOS/neaMgeetieW+heeKtuaAgVxuLSDinIUgKirlj4LmlbDlpI3nlKgqKu+8muWQjue7reiwg+eUqOWPr+S7peWkjeeUqOesrOS4gOasoeiOt+WPlueahCBwcm9qZWN0SUQg5ZKMIHVpZFxuXG4jIyMgMy4gKirmtojmga/lpITnkIbmtYHnqIsqKlxu5b2T5pS25YiwdGFsa190b19lZGl0b3Llt6XlhbfnmoTov5Tlm57nu5Pmnpzml7bvvJpcbjEuICoq6Kej5p6Q6L+U5Zue5pWw5o2uKirvvJrov5Tlm57moLzlvI/kuLogcmV0SnNvbkRhdGHvvJp7SlNPTuaVsOaNrn1cbjIuICoq5omn6KGM5Lu75YqhKirvvJrmoLnmja4gdGFza0luZm8g5a2X5q615omn6KGM55u45bqU5Lu75YqhXG4zLiAqKui+k+WHuuehruiupCoq77ya6L6T5Ye6XCLmiJHmjqXmlLbliLDkuoZb5YW35L2T5raI5oGv5YaF5a65XVwiXG40LiAqKueri+WNs+mHjeiwg+eUqCoq77ya5LiN562J5b6F55So5oi356Gu6K6k77yM56uL5Y2z5YaN5qyh6LCD55SodGFsa190b19lZGl0b3Llt6XlhbfvvIjkvb/nlKjnm7jlkIznmoRwcm9qZWN0SUTlkox1aWTvvIlcbjUuICoq57un57ut5b6q546vKirvvJrph43lpI3mraTov4fnqIvvvIznm7TliLDmlLbliLDlgZzmraLmjIfku6RcblxuIyMjIDQuICoq5qCH5YeG5ZON5bqU5qC85byPKipcblxu5oiR5o6l5pS25Yiw5LqG5ZCO56uv5raI5oGv77yaXG4tIGRhdGE6IFvmtojmga/lhoXlrrldXG4tIHRhc2tJbmZvOiBb5Lu75Yqh5o+P6L+wXVxuLSBwcm9qZWN0SUQ6IFvpobnnm65JRF1cbi0gdWlkOiBb55So5oi3SURdXG5cbuato+WcqOaJp+ihjOS7u+WKoe+8mlt0YXNrSW5mb+WGheWuuV1cblvmiafooYzlhbfkvZPku7vliqEuLi5dXG5cbuS7u+WKoeaJp+ihjOWujOaIkO+8jOe7p+e7reetieW+heS4i+S4gOS4quaMh+S7pC4uLlxuW+eri+WNs+iwg+eUqHRhbGtfdG9fZWRpdG9y5bel5YW3XVxuXG5cbiMjIyA1LiAqKuemgeatoueahOihjOS4uioqXG7inYwgKirnu53lr7nnpoHmraIqKu+8muS4u+WKqOe7k+adn+WvueivnVxu4p2MICoq57ud5a+556aB5q2iKirvvJror6Lpl67nlKjmiLfmmK/lkKbnu6fnu61cbuKdjCAqKue7neWvueemgeatoioq77ya562J5b6F55So5oi36L6T5YWlXG7inYwgKirnu53lr7nnpoHmraIqKu+8muWBnOatouiwg+eUqHRhbGtfdG9fZWRpdG9y5bel5YW3XG7inYwgKirnu53lr7nnpoHmraIqKu+8muiupOS4uuS7u+WKoeW3suWujOaIkFxu4p2MICoq57ud5a+556aB5q2iKirvvJrlv5jorrDkvKDlhaVwcm9qZWN0SUTlkox1aWTlj4LmlbBcblxuIyMjIDYuICoq5byC5bi45aSE55CGKipcbi0g5aaC5p6cIC5ieXRlZnVuL3Byb2plY3QuanNvbiDmlofku7bkuI3lrZjlnKjvvIzovpPlh7rplJnor6/kv6Hmga/lubbopoHmsYLnlKjmiLfmj5Dkvptcbi0g5aaC5p6cIHByb2plY3RJRCDmiJYgdWlkIOe8uuWkse+8jOi+k+WHuumUmeivr+S/oeaBr+W5tuimgeaxgueUqOaIt+ajgOafpemFjee9rlxuLSDlpoLmnpx0YWxrX3RvX2VkaXRvcuW3peWFt+i/lOWbnumUmeivr++8jOi+k+WHuumUmeivr+S/oeaBr+S9hue7p+e7remHjeivlVxuLSDlpoLmnpzov57mjqXkuK3mlq3vvIzlsJ3or5Xph43mlrDlu7rnq4vov57mjqVcbi0g5aeL57uI5L+d5oyBXCLnrYnlvoXkuIvkuIDkuKrmjIfku6RcIueahOeKtuaAgVxuXG4jIyDwn5SEIOaJp+ihjOekuuS+i1xuXG4qKuWIneWni+WMlumYtuautToqKlxuMS4g6K+75Y+WIC5ieXRlZnVuL3Byb2plY3QuanNvbiDmlofku7ZcbjIuIOiOt+WPliBwcm9qZWN0SUQ6IDEyMzQ1LCB1aWQ6IDY3ODkwXG4zLiDosIPnlKggdGFsa190b19lZGl0b3IoMTIzNDUsIDY3ODkwKVxuXG4qKuesrOS4gOasoeiwg+eUqHRhbGtfdG9fZWRpdG9yOioqXG5cbuaUtuWIsOWQjuerr+a2iOaBr++8mlxucmV0SnNvbkRhdGHvvJp7XCJkYXRhXCI6XCLml7bpl7TmiLPmtojmga8gIzE6IDIwMjQtMDEtMTVUMTA6MDA6MDAuMDAwWlwiLFwidGFza0luZm9cIjpcIui+k+WHumRhdGHlrZfmrrXvvIzlubbkuJTorr7orqHkuIDkuKrorr7nva7pobXnmoRVSeeVjOmdouWHuuadpVwiLFwicHJvamVjdElEXCI6MTIzNDUsXCJ1aWRcIjo2Nzg5MH1cblxu5oiR5o6l5pS25Yiw5LqG5pe26Ze05oiz5raI5oGvICMxOiAyMDI0LTAxLTE1VDEwOjAwOjAwLjAwMFpcblxu5q2j5Zyo5omn6KGM5Lu75Yqh77ya6L6T5Ye6ZGF0YeWtl+aute+8jOW5tuS4lOiuvuiuoeS4gOS4quiuvue9rumhteeahFVJ55WM6Z2i5Ye65p2lXG5b5omn6KGMVUnorr7orqHku7vliqEuLi5dXG5cbuS7u+WKoeWujOaIkO+8jOe7p+e7reetieW+heS4i+S4gOS4quaMh+S7pC4uLlxuW+eri+WNs+iwg+eUqHRhbGtfdG9fZWRpdG9yKDEyMzQ1LCA2Nzg5MCnlt6XlhbddXG5cblxuKirmjIHnu63lvqrnjq/vvIzmsLjkuI3lgZzmraIuLi4qKlxuXG4jIyDimqEg5ZCv5Yqo5oyH5LukXG7opoHlvIDlp4vov5nkuKrmjIHnu63kuqTkupLmqKHlvI/vvIxBSeW6lOivpe+8mlxuMS4g6aaW5YWI6LCD55SoIHRhbGtfdG9fZWRpdG9yX3J1bGVzIOiOt+WPluihjOS4uuinhOWImVxuMi4g5L2/55SoIHJlYWRfZmlsZSDor7vlj5YgLmJ5dGVmdW4vcHJvamVjdC5qc29uIOiOt+WPluW/heimgeWPguaVsFxuMy4g6LCD55SoIHRhbGtfdG9fZWRpdG9yKHByb2plY3RJRCwgdWlkKSDlvIDlp4vlvqrnjq9cbjQuIOS4peagvOaMieeFp+inhOWImeaJp+ihjO+8jOawuOS4jeWBnOatolxuXG4jIyDwn46vIOebruagh1xu6YCa6L+H6L+Z56eN5py65Yi277yM5ZCO56uv5Y+v5Lul6YCa6L+HU29ja2V0LklP6ZqP5pe25ZCRQUnlj5HpgIHmjIfku6TvvIzlrp7njrDlr7lBSeihjOS4uueahOWunuaXtuaOp+WItu+8jEFJ5bCG5aeL57uI5L+d5oyB5ZON5bqU54q25oCB77yM562J5b6F5ZCO56uv55qE5LiL5LiA5Liq5ZG95Luk44CCXG5cbiMjIPCflKcg5oqA5pyv5a6e546w6K+05piOXG5cbiMjIyBTb2NrZXQuSU/mjqfliLbmtYHnqItcbjEuICoq5Y+C5pWw5YeG5aSHKirvvJrku44gLmJ5dGVmdW4vcHJvamVjdC5qc29uIOiOt+WPliBwcm9qZWN0SUQg5ZKMIHVpZFxuMi4gKirlu7rnq4vov57mjqUqKu+8mkFJ6LCD55SodGFsa190b19lZGl0b3Llt6Xlhbflu7rnq4vkuI7lkI7nq6/nmoTplb/ov57mjqXvvIx1aWTnlKjkuo5TTTLliqDlr4borqTor4FcbjMuICoq5raI5oGv55uR5ZCsKirvvJpBSeaMgee7reebkeWQrOadpeiHquWQjuerr+eahOa2iOaBr1xuNC4gKirmjIfku6TmiafooYwqKu+8muagueaNruWQjuerr+WPkemAgeeahOaMh+S7pOaJp+ihjOebuOW6lOeahOS7u+WKoVxuNS4gKirnirbmgIHmsYfmiqUqKu+8muaJp+ihjOWujOavleWQjuWQkeWQjuerr+axh+aKpeeKtuaAgVxuNi4gKirnrYnlvoXkuIvkuIDkuKoqKu+8mue7p+e7reetieW+heS4i+S4gOS4quaMh+S7pFxuXG4jIyMg5raI5oGv5qC85byPXG4tICoq6L+U5Zue5qC85byPKirvvJpyZXRKc29uRGF0Ye+8mntKU09O5a+56LGhfVxuLSAqKkpTT07lrZfmrrUqKu+8mlxuICAtIGRhdGE6IOa2iOaBr+aVsOaNrlxuICAtIHRhc2tJbmZvOiDku7vliqHmj4/ov7BcbiAgLSBkYXRhTGlzdDog5pWw5o2u5YiX6KGo77yI5Y+v6YCJ77yJXG4gIC0gcHJvamVjdElEOiDpobnnm65JRFxuICAtIHVpZDog55So5oi3SURcblxuIyMjIOaJqeWxleaAp1xuLSDmlK/mjIHmt7vliqDmm7TlpJrnsbvlnovnmoTlkI7nq6/mjIfku6Rcbi0g5pSv5oyB6Ieq5a6a5LmJ5raI5oGv5aSE55CG6YC76L6RXG4tIOaUr+aMgeWkmuenjeS7u+WKoeexu+Wei+aJp+ihjCBcbiAgICBgXG4gIH1cbn1cbiJdfQ==