fmode-ng 0.0.39 → 0.0.41

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/esm2022/fmode-ng.mjs +5 -10
  2. package/esm2022/lib/aigc/agent/agent.prompt.mjs +122 -10
  3. package/esm2022/lib/aigc/agent/index.mjs +2 -10
  4. package/esm2022/lib/aigc/avatar/avatar.module.mjs +45 -10
  5. package/esm2022/lib/aigc/avatar/comp-avatar-particle/avatar.role.mjs +2 -10
  6. package/esm2022/lib/aigc/avatar/comp-avatar-particle/comp-avatar-particle.component.mjs +315 -10
  7. package/esm2022/lib/aigc/avatar/comp-avatar-particle/index.mjs +3 -10
  8. package/esm2022/lib/aigc/avatar/comp-avatar-particle/role-points.class.mjs +57 -10
  9. package/esm2022/lib/aigc/avatar/comp-avatar-role-image/comp-avatar-role-image.component.mjs +97 -10
  10. package/esm2022/lib/aigc/avatar/comp-avatar-role-video/comp-avatar-role-video.component.mjs +104 -10
  11. package/esm2022/lib/aigc/avatar/comp-avatar-talk/comp-avatar-talk.component.mjs +111 -10
  12. package/esm2022/lib/aigc/avatar/index.mjs +8 -10
  13. package/esm2022/lib/aigc/avatar/interface-avatar-role.mjs +2 -10
  14. package/esm2022/lib/aigc/avatar/modal-chat-voice-input/modal-chat-voice-input.component.mjs +166 -8
  15. package/esm2022/lib/aigc/chat/chat-header-area/comp-header-area.component.mjs +36 -10
  16. package/esm2022/lib/aigc/chat/chat-header-area/index.mjs +2 -10
  17. package/esm2022/lib/aigc/chat/chat-list/chat-list.component.mjs +141 -8
  18. package/esm2022/lib/aigc/chat/chat-list/index.mjs +2 -10
  19. package/esm2022/lib/aigc/chat/chat-message-area/comp-message-area.component.mjs +40 -10
  20. package/esm2022/lib/aigc/chat/chat-message-area/index.mjs +2 -10
  21. package/esm2022/lib/aigc/chat/chat-message-card/comp-message-card.component.mjs +92 -10
  22. package/esm2022/lib/aigc/chat/chat-message-card/index.mjs +2 -10
  23. package/esm2022/lib/aigc/chat/chat-modal-input/index.mjs +2 -10
  24. package/esm2022/lib/aigc/chat/chat-modal-input/modal-audio-message/modal-audio-message.component.mjs +207 -8
  25. package/esm2022/lib/aigc/chat/chat-modal-input/modal-input.component.mjs +236 -10
  26. package/esm2022/lib/aigc/chat/chat-panel/chat-panel.component.mjs +137 -10
  27. package/esm2022/lib/aigc/chat/comp-role-prompt/comp-role-prompt.component.mjs +69 -10
  28. package/esm2022/lib/aigc/chat/comp-role-prompt/index.mjs +2 -10
  29. package/esm2022/lib/aigc/chat/index.mjs +8 -10
  30. package/esm2022/lib/aigc/comp-markdown-preview/clipboard.service.mjs +82 -10
  31. package/esm2022/lib/aigc/comp-markdown-preview/markdown-parse.mjs +269 -8
  32. package/esm2022/lib/aigc/comp-markdown-preview/markdown-preview.component.mjs +51 -10
  33. package/esm2022/lib/aigc/comp-markdown-preview/markdown-preview.module.mjs +24 -10
  34. package/esm2022/lib/aigc/comp-markdown-preview/plugins/md-mathjax/index.mjs +94 -10
  35. package/esm2022/lib/aigc/index.mjs +13 -10
  36. package/esm2022/lib/aigc/service-fmai/fmai.service.mjs +21 -10
  37. package/esm2022/lib/aigc/service-fmai/service-chat/chat-class.mjs +736 -8
  38. package/esm2022/lib/aigc/service-fmai/service-chat/chat.service.mjs +181 -8
  39. package/esm2022/lib/aigc/service-fmai/service-chat/index.mjs +7 -10
  40. package/esm2022/lib/aigc/service-fmai/service-chat/mask-list.mjs +194 -9
  41. package/esm2022/lib/aigc/service-fmai/service-chat/pipes/chat-content.pipe.mjs +27 -10
  42. package/esm2022/lib/aigc/service-fmai/service-chat/pipes/hidexml.pipe.mjs +27 -10
  43. package/esm2022/lib/aigc/service-fmai/service-chat/utilnow.pipe.mjs +68 -10
  44. package/esm2022/lib/aigc/service-fmai/service-imagine/imagine.service.mjs +229 -8
  45. package/esm2022/lib/aigc/service-fmai/service-imagine/index.mjs +2 -10
  46. package/esm2022/lib/aigc/voice/audio.player.mjs +52 -10
  47. package/esm2022/lib/aigc/voice/class-asr.mjs +79 -8
  48. package/esm2022/lib/aigc/voice/fmode-voice.service.mjs +501 -8
  49. package/esm2022/lib/aigc/voice/index.mjs +3 -10
  50. package/esm2022/lib/aigc/voice/lib/pcm2wav.mjs +38 -10
  51. package/esm2022/lib/aigc/voice/lib/resample.mjs +34 -10
  52. package/esm2022/lib/aigc/voice/tts/fmode-tts-class.mjs +233 -8
  53. package/esm2022/lib/aigc/voice/tts/index.mjs +2 -10
  54. package/esm2022/lib/map/comp-poi-picker/comp-poi-picker.component.mjs +190 -10
  55. package/esm2022/lib/map/comp-poi-picker/comp-poi-picker.module.mjs +33 -10
  56. package/esm2022/lib/map/index.mjs +4 -10
  57. package/esm2022/lib/map/map.module.mjs +61 -10
  58. package/esm2022/lib/map/page-loca-scatter/page-loca-scatter.component.mjs +110 -10
  59. package/esm2022/lib/map/page-map.start/page-map.start.component.mjs +98 -8
  60. package/esm2022/lib/map/page-plan-route/page-plan-route.component.mjs +100 -8
  61. package/esm2022/lib/nova-cloud/index.mjs +2 -10
  62. package/esm2022/lib/nova-cloud/nova-cloud.service.mjs +148 -10
  63. package/esm2022/lib/platform/cross.service.mjs +63 -10
  64. package/esm2022/lib/platform/index.mjs +2 -10
  65. package/esm2022/lib/social/index.mjs +2 -10
  66. package/esm2022/lib/social/wechat/wechat-jssdk.service.mjs +236 -8
  67. package/esm2022/lib/storage/comp-hwobs-manager/hwobs-manager.component.mjs +59 -10
  68. package/esm2022/lib/storage/index.mjs +5 -10
  69. package/esm2022/lib/storage/service-hwobs/hwobs.service.mjs +130 -8
  70. package/esm2022/lib/storage/service-upload/index.mjs +2 -10
  71. package/esm2022/lib/storage/service-upload/nova-upload.service.mjs +462 -8
  72. package/esm2022/lib/storage/service-upload/util-file-md5.mjs +28 -10
  73. package/esm2022/lib/storage/storage.module.mjs +41 -10
  74. package/esm2022/lib/user/account/account.service.mjs +221 -10
  75. package/esm2022/lib/user/captcha/captcha.component.mjs +135 -10
  76. package/esm2022/lib/user/comp-user-avatar/comp-user-avatar.component.mjs +62 -10
  77. package/esm2022/lib/user/index.mjs +17 -10
  78. package/esm2022/lib/user/login/auth.guard.mjs +28 -10
  79. package/esm2022/lib/user/login/auth.service.mjs +373 -8
  80. package/esm2022/lib/user/login/login.component.mjs +913 -10
  81. package/esm2022/lib/user/modal-user-login/modal-user-login.component.mjs +273 -10
  82. package/esm2022/lib/user/profile/auth-profile.guard.mjs +27 -10
  83. package/esm2022/lib/user/profile/auth-profile.service.mjs +122 -10
  84. package/esm2022/lib/user/profile/profile-bind/profile-bind.component.mjs +115 -10
  85. package/esm2022/lib/user/profile/profile.module.mjs +57 -10
  86. package/esm2022/lib/user/staff/index.mjs +4 -10
  87. package/esm2022/lib/user/staff/staff.guard.mjs +26 -10
  88. package/esm2022/lib/user/staff/staff.module.mjs +18 -10
  89. package/esm2022/lib/user/staff/staff.service.mjs +85 -10
  90. package/esm2022/lib/user/user-name.pipe.mjs +29 -10
  91. package/esm2022/lib/user/user.module.mjs +106 -10
  92. package/esm2022/lib/video/fm-video/fm-video.component.mjs +67 -10
  93. package/esm2022/lib/video/index.mjs +2 -10
  94. package/esm2022/public-api.mjs +13 -10
  95. package/fesm2022/fmode-ng.mjs +8895 -7
  96. package/fesm2022/fmode-ng.mjs.map +1 -1
  97. package/lib/user/login/auth.service.d.ts +18 -3
  98. package/lib/user/modal-user-login/modal-user-login.component.d.ts +4 -2
  99. package/package.json +1 -1
  100. package/LICENSE.md +0 -8
@@ -1,10 +1,738 @@
1
-
1
+ import { bufferTime, concatMap, Observable, delay, finalize } from "rxjs";
2
+ // var bufferTime:any, concatMap:any, Observable:any, Observer:any,delay:any, finalize:any,Observer:any
3
+ import Parse from "parse";
4
+ import { AgentPrompt } from "../../agent";
5
+ import { FmodeTTS } from "../../voice/tts";
6
+ import { PromptTemplate } from "@langchain/core/prompts";
7
+ // var Parse:any = {}
8
+ // const API_BASE:string = "http://127.0.0.1:7337/api/apig/aigc/gpt"
9
+ const API_BASE = "https://server.fmode.cn/api/apig/aigc/gpt";
10
+ // const API_BASE:string = "https://test.fmode.cn/api/apig/aigc/gpt"
11
+ const agentPrompt = new AgentPrompt();
12
+ const PromptTplTalkSSMLOutputCode = "talk-ssml-output-tpl";
13
+ const PromptTplTalkTextSSMLCode = "talk-text-ssml-tpl";
14
+ export function getMessageContentText(content) {
15
+ let text = "";
16
+ if (typeof content == "string")
17
+ text = content;
18
+ if (typeof content == "object")
19
+ text = content?.find(item => item?.text)?.text || "";
20
+ return text;
21
+ }
22
+ export function getMessageImageUrl(content) {
23
+ if (typeof content == "object")
24
+ return content?.find(item => item?.image_url)?.image_url?.url || "";
25
+ return null;
26
+ }
27
+ /**
28
+ * FmodeChat 聊天对话类
29
+ * @public
30
+ */
31
+ export class FmodeChat {
32
+ showAvatar() {
33
+ this.avatarConfig = this.role?.get("avatarConfig");
34
+ if (this.avatarConfig) {
35
+ this.isAvatarShow = true;
36
+ if (this.avatarConfig?.image) {
37
+ this.avatarConfig.image.waiting = this.avatarConfig.image.waiting || this.role?.get("thumb") || this.role?.get("avatar");
38
+ this.avatarMode = "image";
39
+ }
40
+ if (this.avatarConfig?.video) {
41
+ this.avatarConfig.video.waiting = this.avatarConfig.video.waiting;
42
+ this.avatarMode = "video";
43
+ }
44
+ }
45
+ }
46
+ constructor(sessionId, role, chatSession, chatServ, navCtrl, ncloud, uploadServ) {
47
+ this.ChatSession = Parse.Object.extend("ChatSession");
48
+ this.messageList = [{ role: "system", content: "系统提示:AI仅供参考" }];
49
+ this.latestAIResponse = ``;
50
+ this.userInput = ``;
51
+ this.userImage = ``;
52
+ this.isDirect = false;
53
+ /**
54
+ * 虚拟形象展示状态
55
+ */
56
+ this.isAvatarShow = false;
57
+ this.avatarMode = "";
58
+ /**
59
+ * 预置提示词弹窗是否展示
60
+ */
61
+ this.isPromptModalOpen = false;
62
+ this.isPromptMessageAreaShow = true;
63
+ this.promptList = [];
64
+ this.leftButtons = [
65
+ // 提示 当角色配置预设提示词时 显示
66
+ { title: "灵感", icon: "color-wand-outline", onClick: () => {
67
+ this.isPromptModalOpen = true;
68
+ }, show: () => {
69
+ return this?.promptList?.length;
70
+ } },
71
+ { title: "角色", icon: "people-outline", onClick: () => {
72
+ this.navCtrl?.navigateRoot("/chat/pro/mask");
73
+ }, show: () => { return true; } },
74
+ { title: "呼叫", icon: "call-outline", onClick: () => {
75
+ this.chatServ?.callRole(this.role);
76
+ }, show: () => {
77
+ return this?.role?.get('voiceConfig');
78
+ } },
79
+ ];
80
+ /**
81
+ * 是否开启语音消息模式(单次)
82
+ */
83
+ this.isVoiceInputMode = false;
84
+ this.isTexting = false;
85
+ this.isTalkMode = false;
86
+ this.SSMLRoleVoice = "zh-CN-XiaoxiaoNeural";
87
+ /**
88
+ * 会话Avatar控制
89
+ */
90
+ this.playAnimation = (animName) => {
91
+ console.log(animName);
92
+ return;
93
+ };
94
+ this.welcome = async () => {
95
+ let msglist = this.messageList?.filter(item => item?.role == "assistant");
96
+ if (msglist?.length)
97
+ return; // 已有对话不开场问候
98
+ let user = Parse.User.current();
99
+ let person = await this.loadSelf("Person", "userVerify");
100
+ let profile = await this.loadSelf("Profile", "user");
101
+ let name = user?.get("realname") || profile?.get("name") || person?.get("name") || user?.get("nickname") || user?.get("name");
102
+ // 问候语/首个话题
103
+ let tpl = this.role.get("voiceConfig")?.welcome?.prompt;
104
+ if (!tpl)
105
+ return; // 无模板则返回
106
+ let welcomeContent = await PromptTemplate.fromTemplate(tpl, {
107
+ templateFormat: "mustache"
108
+ }).format({
109
+ name: name,
110
+ timeOfDay: this.getTimeOfDay()
111
+ });
112
+ // let callName = name?`${name},`:"";
113
+ // let callTime = `${this.getTimeOfDay()}好`;
114
+ // let welcomeContent = `${callName}${callTime},期待聆听您的人生故事,想和我聊些什么呢?`;
115
+ // 生成ChatVoice并播放
116
+ let voice = await this.getVoiceByContentText(welcomeContent);
117
+ let message = {
118
+ role: "assistant",
119
+ voice: voice,
120
+ content: welcomeContent,
121
+ complete: true
122
+ };
123
+ this.voiceMap[voice?.id];
124
+ this.playChatVoice(this.voiceMap[voice?.id]);
125
+ this.messageList.push(message);
126
+ };
127
+ this.self = {};
128
+ this.voiceMap = {};
129
+ this.chatServ = chatServ;
130
+ this.role = role;
131
+ this.sessionId = sessionId;
132
+ this.navCtrl = navCtrl;
133
+ this.ncloud = ncloud;
134
+ this.uploadServ = uploadServ;
135
+ if (chatSession?.id) {
136
+ this.chatSession = chatSession;
137
+ this.messageList = this.chatSession.get("messageList");
138
+ this.sessionId = chatSession?.id;
139
+ }
140
+ if (this.role?.id) {
141
+ this.voiceConfig = this.role?.get("voiceConfig");
142
+ if (this.voiceConfig?.autoTalk) {
143
+ this.isTalkMode = true;
144
+ this.isDirect = true;
145
+ }
146
+ }
147
+ }
148
+ getTimeOfDay() {
149
+ const now = new Date();
150
+ const hours = now.getHours();
151
+ if (hours >= 5 && hours < 12) {
152
+ return "早上";
153
+ }
154
+ else if (hours >= 12 && hours < 14) {
155
+ return "中午";
156
+ }
157
+ else if (hours >= 14 && hours < 18) {
158
+ return "下午";
159
+ }
160
+ else {
161
+ return "晚上";
162
+ }
163
+ }
164
+ async loadSelf(className, userKey) {
165
+ if (this.self[className])
166
+ return this.self[className];
167
+ let user = Parse.User.current();
168
+ let query = new Parse.Query(className);
169
+ query.equalTo(userKey, user?.id);
170
+ this.self[className] = await query.first();
171
+ }
2
172
  /**
3
- * @copyright © 未来飞马 © 未来全栈 www.fmode.cn
4
- * 版权所有 © 未来飞马 © 江西脑控科技有限公司 Copyright © Fmode Technology Co., Ltd.
5
- * 保留所有权利 All Rights Reserved.
6
- * /home/ryan/workspace/nova/nova-admin/dist/fmode-ng/esm2022/lib/aigc/service-fmai/service-chat/chat-class.mjs
173
+ * 对话模型提示词
7
174
  */
8
- import{bufferTime,concatMap,Observable,delay,finalize}from"rxjs";import Parse from"parse";import{AgentPrompt}from"../../agent";import{FmodeTTS}from"../../voice/tts";import{PromptTemplate}from"@langchain/core/prompts";const API_BASE="https://server.fmode.cn/api/apig/aigc/gpt",agentPrompt=new AgentPrompt,PromptTplTalkSSMLOutputCode="talk-ssml-output-tpl",PromptTplTalkTextSSMLCode="talk-text-ssml-tpl";export function getMessageContentText(t){let e="";return"string"==typeof t&&(e=t),"object"==typeof t&&(e=t?.find((t=>t?.text))?.text||""),e}export function getMessageImageUrl(t){return"object"==typeof t?t?.find((t=>t?.image_url))?.image_url?.url||"":null}export class FmodeChat{showAvatar(){this.avatarConfig=this.role?.get("avatarConfig"),this.avatarConfig&&(this.isAvatarShow=!0,this.avatarConfig?.image&&(this.avatarConfig.image.waiting=this.avatarConfig.image.waiting||this.role?.get("thumb")||this.role?.get("avatar"),this.avatarMode="image"),this.avatarConfig?.video&&(this.avatarConfig.video.waiting=this.avatarConfig.video.waiting,this.avatarMode="video"))}constructor(t,e,s,i,o,n,a){this.ChatSession=Parse.Object.extend("ChatSession"),this.messageList=[{role:"system",content:"系统提示:AI仅供参考"}],this.latestAIResponse="",this.userInput="",this.userImage="",this.isDirect=!1,this.isAvatarShow=!1,this.avatarMode="",this.isPromptModalOpen=!1,this.isPromptMessageAreaShow=!0,this.promptList=[],this.leftButtons=[{title:"灵感",icon:"color-wand-outline",onClick:()=>{this.isPromptModalOpen=!0},show:()=>this?.promptList?.length},{title:"角色",icon:"people-outline",onClick:()=>{this.navCtrl?.navigateRoot("/chat/pro/mask")},show:()=>!0},{title:"呼叫",icon:"call-outline",onClick:()=>{this.chatServ?.callRole(this.role)},show:()=>this?.role?.get("voiceConfig")}],this.isVoiceInputMode=!1,this.isTexting=!1,this.isTalkMode=!1,this.SSMLRoleVoice="zh-CN-XiaoxiaoNeural",this.playAnimation=t=>{console.log(t)},this.welcome=async()=>{let t=this.messageList?.filter((t=>"assistant"==t?.role));if(t?.length)return;let e=Parse.User.current(),s=await this.loadSelf("Person","userVerify"),i=await this.loadSelf("Profile","user"),o=e?.get("realname")||i?.get("name")||s?.get("name")||e?.get("nickname")||e?.get("name"),n=this.role.get("voiceConfig")?.welcome?.prompt;if(!n)return;let a=await PromptTemplate.fromTemplate(n,{templateFormat:"mustache"}).format({name:o,timeOfDay:this.getTimeOfDay()}),r=await this.getVoiceByContentText(a),l={role:"assistant",voice:r,content:a,complete:!0};this.voiceMap[r?.id],this.playChatVoice(this.voiceMap[r?.id]),this.messageList.push(l)},this.self={},this.voiceMap={},this.chatServ=i,this.role=e,this.sessionId=t,this.navCtrl=o,this.ncloud=n,this.uploadServ=a,s?.id&&(this.chatSession=s,this.messageList=this.chatSession.get("messageList"),this.sessionId=s?.id),this.role?.id&&(this.voiceConfig=this.role?.get("voiceConfig"),this.voiceConfig?.autoTalk&&(this.isTalkMode=!0,this.isDirect=!0))}getTimeOfDay(){const t=(new Date).getHours();return t>=5&&t<12?"早上":t>=12&&t<14?"中午":t>=14&&t<18?"下午":"晚上"}async loadSelf(t,e){if(this.self[t])return this.self[t];let s=Parse.User.current(),i=new Parse.Query(t);i.equalTo(e,s?.id),this.self[t]=await i.first()}async loadTalkSystemPrompt(t){if(!this.isTalkMode)return;if(!t)return;"男"==t?.get("gender")?this.SSMLRoleVoice="zh-CN-YunyeNeural":this.SSMLRoleVoice="zh-CN-XiaoxiaoNeural",this.SSMLRoleVoice=t?.get("voiceConfig")?.voice||this.SSMLRoleVoice;let e=await agentPrompt.getFormatTpl("talk-ssml-output-tpl",{SSMLRoleVoice:this.SSMLRoleVoice}),s=t.get("prompt")||"请你扮演飞码AI的人工智能专家。";s+=e;let i={role:"user",content:s,hidden:!0},o=this.messageList?.map((t=>t?.content)).join();if(o.indexOf(s)>-1)return;let n=this.messageList?.findIndex((t=>"system"==t?.role)),a=n+1;this.messageList.splice(a,0,i)}loadRolePrompt(){let t=this.role?.get("prompt"),e={role:"user",content:t,hidden:!0};if(!t)return;let s=this.messageList?.map((t=>t?.content)).join();if(s.indexOf(t)>-1)return;let i=this.messageList?.findIndex((t=>"system"==t?.role)),o=i+1;this.messageList.splice(o,0,e)}async sendMessage(t="FmodeAiTest测试问题",e,s,i,o){if(this.isPromptMessageAreaShow=!1,this.loadRolePrompt(),e){let s={role:"user",content:[{type:"image_url",image_url:{url:e}},{type:"text",text:t}],complete:!0,createdAt:new Date};o&&(s.voice={id:o?.id}),this.messageList.push({role:"user",content:[{type:"image_url",image_url:{url:e}},{type:"text",text:t}],complete:!0,createdAt:new Date})}else{let e={role:"user",content:t,complete:!0,createdAt:new Date};o&&(e.voice={id:o?.id,duration:o?.duration}),this.messageList.push(e)}let n=new FmodeChatCompletion(this.fixMessageList(this.messageList),{model:this.chatServ?.currentModel?.get("code")||"fmode-4.5-128k"});this.userInput="",this.userImage="";let a=this.isDirect||!1;this.isTalkMode&&(a=!0);let r=n.sendCompletion({isDirect:a,onComplete:s||null}).pipe(finalize((async()=>{if(this.isTalkMode){let t=this.messageList[n.indexOfList]?.content,e=await this.getVoiceByContentText(t,i);i?.onSSMLComplete&&i?.onSSMLComplete(e),this.messageList[n.indexOfList].voice=e,this.playChatVoice(this.voiceMap[e?.id])}this.messageList[n.indexOfList].complete=!0}))).subscribe((t=>{this.messageList[n.indexOfList]=t,this.latestAIResponse=this.getContentText(t?.content);let e=this.chatSession?.get("messageList")?.length;this.messageList?.length>e&&this.saveChatSession(),t?.complete&&(this.saveChatSession(),r.unsubscribe())}))}getVoiceByContentText(t,e,s=!1){let i=this.getContentText(t),o=new(Parse.Object.extend("ChatVoice")),n="";return this.SSMLRoleVoice=this.role?.get("voiceConfig")?.voice||this.SSMLRoleVoice,new Promise((async(t,e)=>{let resolveChatVoice=async()=>{o.set("content",i),o.set("ssml",n),o.set("role","assistant");let e=localStorage.getItem("company");e&&o.set("company",{__type:"Pointer",className:"Company",objectId:e}),Parse.User.current()?.id&&o.set("user",Parse.User.current().toPointer()),this.chatSession?.id&&o.set("session",this.chatSession?.toPointer()),o=await o.save(),this.voiceMap[o?.id]=o,t({id:o?.id})};if(0==s&&(n=`<speak xmlns="http://www.w3.org/2001/10/synthesis" xmlns:mstts="http://www.w3.org/2001/mstts" xmlns:emo="http://www.w3.org/2009/10/emotionml" version="1.0" xml:lang="zh-CN"><voice name="${this.SSMLRoleVoice}">${i}</voice></speak>`,resolveChatVoice()),1==s){let t=await agentPrompt.getFormatTpl("talk-text-ssml-tpl",{content:i,SSMLRoleVoice:this.SSMLRoleVoice});new FmodeChatCompletion(this.fixMessageList([{role:"user",content:t}]),{model:this.chatServ?.currentModel?.get("code")||"fmode-4.5-128k"}).sendCompletion({isDirect:!0}).subscribe((async t=>{t?.complete&&(n=this.getContentText(t?.content),resolveChatVoice())}))}}))}getContentText(t){return"string"==typeof t?t:t?.[0]?.text||""}async initTTS(){let t=await this.ncloud.apig("voice/tts/token",{company:localStorage.getItem("company")});if(console.log(t),t?.token){let e=new FmodeTTS(t,this.uploadServ);this.tts=e}}async playChatVoice(t,e){if(await this.initTTS(),this.tts)try{this.playAnimation("talking"),await this.tts.speakAsync(t?.get("ssml"),t,{onLoaded:t=>{e?.onLoaded&&e?.onLoaded(t)},onStop:()=>{e?.onStop&&e?.onStop(),this.playAnimation("waiting")}})}catch(t){console.error(t)}}async saveChatSession(){if("new"==this.sessionId&&(this.chatSession=new this.ChatSession),this.chatSession.set("title",this.genTitle()),this.chatSession.set("role",this.role?.toPointer()),this.chatSession.set("messageList",this.messageList),this.chatSession.set("user",Parse.User.current()?.toPointer()),this.chatSession=await this.chatSession.save(),this.sessionId=this.chatSession?.id,this.sessionId){let t=`${window.location.origin}/chat/pro/chat/${this.sessionId}`;window.location?.pathname?.indexOf("chat/session")>-1&&(t=`${window.location.origin}/chat/session/chat/${this.sessionId}`),t=this.getInviteUrl(t),window.history.replaceState(null,null,t+window.location.search);let e={sid:this.chatSession?.id,rid:this.role?.id,name:this.role?.get("name"),message:this.chatSession?.get("messageList")?.[this.chatSession?.get("messageList")?.length-1]?.content?.slice(0,20),latest:this.chatSession?.createdAt};this.chatServ?.chatList?.length||(this.chatServ.chatList=[]);let s=this.chatServ?.chatList?.find((t=>t?.sid==e?.sid));s>-1?this.chatServ.chatList[s]=e:this.chatServ?.chatList.unshift(e)}}getInviteUrl(t){let e="?";e=t?.indexOf("?")>-1?"&":"?";let s=Parse.User?.current()?.id;if(-1==t?.indexOf("invite="+s)){if(!s)return t;t+=e+"invite="+s}return t}genTitle(){if(this.title)return this.title;let t=this.messageList.find((t=>"user"==t.role))?.content;return"string"==typeof t&&(this.title=t?.slice(0,15)||""),"object"==typeof t&&(this.title=t?.find((t=>t?.text))?.text||""),this.title}fixMessageList(t){return t.map((t=>({role:t.role,content:t.content})))}nowStr(){let t=new Date;return`${t.getFullYear()}/${t.getMonth()+1}/${t.getDate()} ${t.getHours()}:${t.getMinutes()}:${t.getSeconds()}`}}export class FmodeChatCompletion{constructor(t,e){this.content="",this.contentBuffer=[],this.isCompleted=!1,this.indexOfList=Number(t.length),this.messages=t,this.model=e?.model||"fmode-4.5-128k"}sendCompletion(t={}){t.intTime=t?.intTime||50,t.isDirect=t?.isDirect||!1,t?.isDirect&&(t.intTime=1);let e={messages:this.messages,stream:!0,model:this.model,temperature:.5,presence_penalty:0,frequency_penalty:0};return new Observable((s=>{let i=RequestFmodeChatApi("/v1/chat/completions",e).subscribe((e=>{let o=String(e);if("data: [DONE]"==o&&(this.isCompleted=!0,t?.isDirect&&this.isCompleted&&(s.next({role:"assistant",content:this.content,complete:!0,createdAt:new Date}),i.unsubscribe(),t?.onComplete&&t.onComplete({role:"assistant",content:this.content,complete:!0,createdAt:new Date}),s.complete())),o.indexOf("data: {")>-1){let e=chunkToJson(o),n=e?.choices?.[0]?.delta?.content||"";this.contentBuffer.push(n),t?.isDirect&&(this.content+=n||"",this.isCompleted||s.next({role:"assistant",cid:e?.id,content:this.content,createdAt:new Date})),t?.isDirect||this.contentPusher||(this.contentPusher=setInterval((()=>{this.isCompleted&&0==this.contentBuffer?.length&&(s.next({role:"assistant",cid:e?.id,content:this.content,complete:!0,createdAt:new Date}),i.unsubscribe(),clearInterval(this.contentPusher),s.complete()),this.contentBuffer?.length>=0&&(this.contentBuffer?.length>0&&(this.content+=this.contentBuffer.shift()),s.next({role:"assistant",cid:e?.id,content:this.content,createdAt:new Date}))}),t?.intTime))}}))})).pipe(bufferTime(100),concatMap((t=>t)),delay(200))}}function chunkToJson(t){let e;try{e=JSON.parse(t.replaceAll("data: ",""))}catch(t){console.error(t)}return e||{}}function RequestFmodeChatApi(t,e,s="POST"){return new Observable((i=>{let o=API_BASE+t,n=`Bearer ${Parse.User.current()?.getSessionToken()||localStorage.getItem("FMODE_AI_TOKEN")}`;return e.token=n,e&&(e=JSON.stringify(e)),fetch(o,{headers:{"Content-Type":"text/plain","Cache-Control":"no-cache"},body:e||null,method:s,credentials:"omit",mode:"cors"}).then((t=>{let e="";{let s=t.body?.getReader();const o=new TextDecoder;let n=new ReadableStream({start(t){!function read(){s.read().then((({done:e,value:s})=>{if(e)return t.close(),void i.complete();t.enqueue(s),read()}))}()}}).getReader();n.read().then((function processStream({done:t,value:s}){if(t)return;!function processData(t){let s=(e+t).split("\n");if(s?.length>1){for(let t=0;t<s.length-1;t++){let e=s[t];i.next(e)}e=s[s.length-1]}}(o.decode(s)),n.read().then(processStream)}))}})).catch((t=>i.error(t))),()=>{}}))}function JsonToFormData(t){const e=new FormData;return function appendFormData(t,s=""){Array.isArray(t)?t.forEach(((t,e)=>{appendFormData(t,`${s}[${e}]`)})):"object"==typeof t&&null!==t?Object.keys(t).forEach((e=>{const i=s?`${s}.${e}`:e;appendFormData(t[e],i)})):e.append(s,t)}(t),e}
9
- var MODULE_PATH_NEED = `6K+l5paH5Lu25piv5pys6aG555uu55qE5LiA6YOo5YiGIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIHRoZSBDb21wb25lbnRzIGluIEZtb2RlIEluYy4KICAgIOeJiOadg+aJgOaciSDCqSDmnKrmnaXpo57pqawgwqkg5rGf6KW/6ISR5o6n56eR5oqA5pyJ6ZmQ5YWs5Y+4IENvcHlyaWdodCDCqSBGbW9kZSBUZWNobm9sb2d5IENvLiwgTHRkLgogICAg5L+d55WZ5omA5pyJ5p2D5YipIEFsbCBSaWdodHMgUmVzZXJ2ZWQuCiAgICDkuKXnpoHlnKjmnKrnu4/mjojmnYPnmoTmg4XlhrXkuIvvvIzpgJrov4fku7vkvZXlqpLku4vlpI3liLbmraTmlofku7YgVW5hdXRob3JpemVkIGNvcHlpbmcgb2YgdGhpcyBmaWxlLCB2aWEgYW55IG1lZGl1bSBpcyBzdHJpY3RseSBwcm9oaWJpdGVkCiAgICDor6Xmlofku7bmmK/kuJPmnInnmoTmnLrlr4bmlofku7YgUHJvcHJpZXRhcnkgYW5kIGNvbmZpZGVudGlhbAogICAKICAgIENvcHlyaWdodCAyMDIxLW5vdyBGbW9kZSBJbmMuIHN1cHBvcnRAZm1vZGUuY24uIDE4NjA3MDA3MDczLgogICAg5L+d55WZ5omA5pyJ5p2D5YipIEFsbCByaWdodHMgcmVzZXJ2ZWQuCgogICAgUEFUSDovaG9tZS9yeWFuL3dvcmtzcGFjZS9ub3ZhL25vdmEtYWRtaW4vZGlzdC9mbW9kZS1uZy9lc20yMDIyL2xpYi9haWdjL3NlcnZpY2UtZm1haS9zZXJ2aWNlLWNoYXQvY2hhdC1jbGFzcy5tanM=`
10
-
175
+ async loadTalkSystemPrompt(role) {
176
+ if (!this.isTalkMode)
177
+ return;
178
+ if (!role)
179
+ return;
180
+ // 加载声音模型:默认为晓晓
181
+ if (role?.get('gender') == '男') {
182
+ this.SSMLRoleVoice = "zh-CN-YunyeNeural";
183
+ }
184
+ else {
185
+ this.SSMLRoleVoice = "zh-CN-XiaoxiaoNeural";
186
+ }
187
+ this.SSMLRoleVoice = role?.get("voiceConfig")?.voice || this.SSMLRoleVoice;
188
+ let SSMLPromptTemplate = await agentPrompt.getFormatTpl(PromptTplTalkSSMLOutputCode, {
189
+ SSMLRoleVoice: this.SSMLRoleVoice, // SSML
190
+ });
191
+ let prompt = role.get("prompt") || "请你扮演飞码AI的人工智能专家。";
192
+ prompt += SSMLPromptTemplate;
193
+ let promptMsg = { role: "user", content: prompt, hidden: true };
194
+ // 查重
195
+ let content = this.messageList?.map(item => item?.content).join();
196
+ if (content.indexOf(prompt) > -1) {
197
+ // 提示词已经存在
198
+ return;
199
+ }
200
+ // 补全提示词
201
+ let systemIndex = this.messageList?.findIndex(item => item?.role == "system");
202
+ let insertIndex = systemIndex + 1;
203
+ this.messageList.splice(insertIndex, 0, promptMsg);
204
+ return;
205
+ }
206
+ /**
207
+ * 角色提示词
208
+ * @returns
209
+ */
210
+ loadRolePrompt() {
211
+ // 角色提示
212
+ let prompt = this.role?.get("prompt");
213
+ let promptMsg = { role: "user", content: prompt, hidden: true };
214
+ if (!prompt)
215
+ return; // 无提示词无需添加
216
+ // 内容检查
217
+ let content = this.messageList?.map(item => item?.content).join();
218
+ if (content.indexOf(prompt) > -1) {
219
+ // 提示词已经存在
220
+ return;
221
+ }
222
+ // 补全提示词
223
+ let systemIndex = this.messageList?.findIndex(item => item?.role == "system");
224
+ let insertIndex = systemIndex + 1;
225
+ this.messageList.splice(insertIndex, 0, promptMsg);
226
+ // console.log(this.messageList)
227
+ }
228
+ /**
229
+ * 发送消息
230
+ * @param message
231
+ * @param imageUrl
232
+ */
233
+ async sendMessage(message = "FmodeAiTest测试问题", imageUrl, onComplete, eventMap, voice) {
234
+ // 为消息列表补全提示词
235
+ // await this.loadTalkSystemPrompt(this.role);
236
+ this.isPromptMessageAreaShow = false; // 发送第一条消息后,关闭提示看板
237
+ this.loadRolePrompt();
238
+ // 用户输入消息,添加到历史消息清单中
239
+ if (!imageUrl) { // 纯文本
240
+ // console.log("纯文本")
241
+ let msg = {
242
+ role: "user",
243
+ content: message,
244
+ complete: true,
245
+ createdAt: new Date()
246
+ };
247
+ if (voice) {
248
+ msg.voice = { id: voice?.id, duration: voice?.duration };
249
+ }
250
+ this.messageList.push(msg);
251
+ }
252
+ else { // 带图片
253
+ let msg = {
254
+ "role": "user",
255
+ "content": [
256
+ {
257
+ "type": "image_url",
258
+ "image_url": { "url": imageUrl },
259
+ },
260
+ {
261
+ "type": "text",
262
+ "text": message
263
+ },
264
+ ],
265
+ complete: true,
266
+ createdAt: new Date()
267
+ };
268
+ if (voice) {
269
+ msg.voice = { id: voice?.id };
270
+ }
271
+ this.messageList.push({
272
+ "role": "user",
273
+ "content": [
274
+ {
275
+ "type": "image_url",
276
+ "image_url": { "url": imageUrl },
277
+ },
278
+ {
279
+ "type": "text",
280
+ "text": message
281
+ },
282
+ ],
283
+ complete: true,
284
+ createdAt: new Date()
285
+ });
286
+ }
287
+ // 创建并发起一条新的消息补全
288
+ // console.log("send",this.messageList)
289
+ let completion = new FmodeChatCompletion(this.fixMessageList(this.messageList), {
290
+ model: this.chatServ?.currentModel?.get("code") || "fmode-4.5-128k"
291
+ });
292
+ this.userInput = "";
293
+ this.userImage = "";
294
+ // console.log(this.chatServ?.currentModel?.toJSON())
295
+ // 持续更新事件推送的消息体内容至消息列表
296
+ let isDirect = this.isDirect || false;
297
+ if (this.isTalkMode) {
298
+ isDirect = true;
299
+ }
300
+ let send$ = completion.sendCompletion({
301
+ isDirect: isDirect,
302
+ onComplete: onComplete || null
303
+ }).pipe(finalize(async () => {
304
+ if (this.isTalkMode) {
305
+ let content = this.messageList[completion.indexOfList]?.content;
306
+ let voice = await this.getVoiceByContentText(content, eventMap);
307
+ eventMap?.onSSMLComplete && eventMap?.onSSMLComplete(voice);
308
+ this.messageList[completion.indexOfList].voice = voice;
309
+ this.playChatVoice(this.voiceMap[voice?.id]);
310
+ }
311
+ this.messageList[completion.indexOfList].complete = true;
312
+ })).subscribe(message => {
313
+ this.messageList[completion.indexOfList] = message;
314
+ this.latestAIResponse = this.getContentText(message?.content);
315
+ let savedList = this.chatSession?.get("messageList")?.length;
316
+ // 生命周期:会话创建后,有新消息时,创建保存会话
317
+ if (this.messageList?.length > savedList) {
318
+ // console.log("cycle新会话")
319
+ this.saveChatSession();
320
+ }
321
+ if (message?.complete) {
322
+ // 生命周期:消息发送完成后,保存聊天记录
323
+ this.saveChatSession();
324
+ send$.unsubscribe();
325
+ }
326
+ // console.log(message)
327
+ });
328
+ }
329
+ getVoiceByContentText(content, eventMap, promptEnabled = false) {
330
+ let contentText = this.getContentText(content);
331
+ let ChatVoice = Parse.Object.extend("ChatVoice");
332
+ let chatVoice = new ChatVoice();
333
+ let contentSSML = ``;
334
+ this.SSMLRoleVoice = this.role?.get("voiceConfig")?.voice || this.SSMLRoleVoice;
335
+ return new Promise(async (resolve, reject) => {
336
+ let resolveChatVoice = async () => {
337
+ chatVoice.set("content", contentText);
338
+ chatVoice.set("ssml", contentSSML);
339
+ chatVoice.set("role", "assistant");
340
+ let company = localStorage.getItem("company");
341
+ company && chatVoice.set("company", { __type: "Pointer", className: "Company", objectId: company });
342
+ Parse.User.current()?.id && chatVoice.set("user", Parse.User.current().toPointer());
343
+ this.chatSession?.id && chatVoice.set("session", this.chatSession?.toPointer());
344
+ chatVoice = await chatVoice.save();
345
+ this.voiceMap[chatVoice?.id] = chatVoice;
346
+ resolve({
347
+ id: chatVoice?.id,
348
+ });
349
+ };
350
+ /**
351
+ * 方法一:高级语音直接读文本,速度快,但细节情绪标记不足。
352
+ */
353
+ if (promptEnabled == false) {
354
+ contentSSML = `<speak xmlns="http://www.w3.org/2001/10/synthesis" xmlns:mstts="http://www.w3.org/2001/mstts" xmlns:emo="http://www.w3.org/2009/10/emotionml" version="1.0" xml:lang="zh-CN"><voice name="${this.SSMLRoleVoice}">${contentText}</voice></speak>`;
355
+ resolveChatVoice();
356
+ }
357
+ /**
358
+ * promptEnabled == true
359
+ * 方法二:通过大模型再次拼接SSML脚本,实现更优质的语音标记,但是生成时间太慢
360
+ */
361
+ if (promptEnabled == true) {
362
+ // 拼接Prompt
363
+ let TextSSMLPrompt = await agentPrompt.getFormatTpl(PromptTplTalkTextSSMLCode, {
364
+ content: contentText, // 文本内容
365
+ SSMLRoleVoice: this.SSMLRoleVoice, // SSML 演说者
366
+ });
367
+ // 生成SSML
368
+ let completion = new FmodeChatCompletion(this.fixMessageList([{
369
+ role: "user",
370
+ content: TextSSMLPrompt
371
+ }]), {
372
+ model: this.chatServ?.currentModel?.get("code") || "fmode-4.5-128k"
373
+ });
374
+ let send$ = completion.sendCompletion({
375
+ isDirect: true,
376
+ }).subscribe(async (message) => {
377
+ if (message?.complete) {
378
+ contentSSML = this.getContentText(message?.content);
379
+ resolveChatVoice();
380
+ }
381
+ });
382
+ }
383
+ });
384
+ }
385
+ getContentText(content) {
386
+ if (typeof content == "string") {
387
+ return content;
388
+ }
389
+ else {
390
+ return content?.[0]?.text || ``;
391
+ }
392
+ }
393
+ async initTTS() {
394
+ // if(this.tts) return // 待明确sts有效期和次数进行优化,避免每次重复获取
395
+ let config = await this.ncloud.apig("voice/tts/token", { company: localStorage.getItem("company") });
396
+ // 有TTS资源,使用情绪合成
397
+ console.log(config);
398
+ if (config?.token) {
399
+ let tts = new FmodeTTS(config, this.uploadServ);
400
+ this.tts = tts;
401
+ }
402
+ }
403
+ async playChatVoice(voice, eventMap) {
404
+ await this.initTTS();
405
+ // console.log(this.tts)
406
+ if (this.tts) {
407
+ try {
408
+ // console.log(textOrSSML)
409
+ // 完整的消息,通过TTS合成进行讲话
410
+ this.playAnimation("talking"); // Talking动画,暂时用wating代替
411
+ await this.tts.speakAsync(voice?.get("ssml"), voice, {
412
+ onLoaded: (audio) => {
413
+ eventMap?.onLoaded && eventMap?.onLoaded(audio); // 事件传递
414
+ },
415
+ onStop: () => {
416
+ eventMap?.onStop && eventMap?.onStop(); // 事件传递
417
+ this.playAnimation("waiting"); // Talking动画,暂时用wating代替
418
+ }
419
+ });
420
+ }
421
+ catch (ttserr) {
422
+ console.error(ttserr);
423
+ }
424
+ }
425
+ // 无TSS资源,调用Edge Speech
426
+ }
427
+ /**
428
+ * 保存单次会话
429
+ */
430
+ async saveChatSession() {
431
+ if (this.sessionId == "new") {
432
+ this.chatSession = new this.ChatSession();
433
+ }
434
+ this.chatSession.set("title", this.genTitle());
435
+ this.chatSession.set("role", this.role?.toPointer());
436
+ this.chatSession.set("messageList", this.messageList);
437
+ this.chatSession.set("user", Parse.User.current()?.toPointer());
438
+ this.chatSession = await this.chatSession.save();
439
+ this.sessionId = this.chatSession?.id;
440
+ if (this.sessionId) {
441
+ // 修改URL地址为sessionId,方便分享或切换 角色页面 => 会话页面
442
+ let newHref = `${window.location.origin}/chat/pro/chat/${this.sessionId}`;
443
+ if (window.location?.pathname?.indexOf("chat/session") > -1) {
444
+ newHref = `${window.location.origin}/chat/session/chat/${this.sessionId}`;
445
+ }
446
+ newHref = this.getInviteUrl(newHref);
447
+ window.history.replaceState(null, null, newHref + window.location.search);
448
+ // 修改最新条chatList数据
449
+ let newChat = {
450
+ sid: this.chatSession?.id,
451
+ rid: this.role?.id,
452
+ name: this.role?.get('name'),
453
+ message: this.chatSession?.get('messageList')?.[this.chatSession?.get('messageList')?.length - 1]?.content?.slice(0, 20),
454
+ latest: this.chatSession?.createdAt
455
+ };
456
+ if (!this.chatServ?.chatList?.length)
457
+ this.chatServ.chatList = [];
458
+ let index = this.chatServ?.chatList?.find(item => item?.sid == newChat?.sid);
459
+ if (index > -1) {
460
+ this.chatServ.chatList[index] = newChat;
461
+ }
462
+ else {
463
+ this.chatServ?.chatList.unshift(newChat);
464
+ }
465
+ }
466
+ }
467
+ getInviteUrl(url) {
468
+ // 判断是否有参数
469
+ let connectChar = "?";
470
+ if (url?.indexOf("?") > -1) {
471
+ connectChar = "&";
472
+ }
473
+ else {
474
+ connectChar = "?";
475
+ }
476
+ // 附加invite参数
477
+ let id = Parse.User?.current()?.id;
478
+ if (url?.indexOf("invite=" + id) == -1) {
479
+ if (!id)
480
+ return url;
481
+ url += connectChar + 'invite=' + id;
482
+ }
483
+ return url;
484
+ }
485
+ // 根据聊天内容及问题,生成标题
486
+ genTitle() {
487
+ if (this.title)
488
+ return this.title;
489
+ let content = this.messageList.find(item => item.role == "user")?.content;
490
+ if (typeof content == "string") { // 截图文本内容文字部分
491
+ this.title = content?.slice(0, 15) || "";
492
+ }
493
+ if (typeof content == "object") { // 截图复合内容文字部分
494
+ this.title = content?.find(item => item?.text)?.text || "";
495
+ }
496
+ return this.title;
497
+ }
498
+ fixMessageList(messages) {
499
+ return messages.map(msg => { return { role: msg.role, content: msg.content }; });
500
+ }
501
+ nowStr() {
502
+ let now = new Date();
503
+ return `${now.getFullYear()}/${now.getMonth() + 1}/${now.getDate()} ${now.getHours()}:${now.getMinutes()}:${now.getSeconds()}`;
504
+ }
505
+ }
506
+ /**
507
+ * FmodeChatCompletion 文本补全类
508
+ * @public
509
+ */
510
+ export class FmodeChatCompletion {
511
+ constructor(messages, options) {
512
+ this.content = ""; // 本次接收消息结果
513
+ this.contentBuffer = [];
514
+ this.isCompleted = false;
515
+ this.indexOfList = Number(messages.length);
516
+ this.messages = messages;
517
+ this.model = options?.model || "fmode-4.5-128k";
518
+ }
519
+ /**
520
+ * @param options
521
+ * @param options.isDirect 是否不等待逐字获取,直接完成内容推送
522
+ * @param options.intTime 是否不等待逐字获取,直接完成内容推送
523
+ * @returns
524
+ */
525
+ sendCompletion(options = {}) {
526
+ options.intTime = options?.intTime || 50; // 按毫秒逐字推送
527
+ options.isDirect = options?.isDirect || false;
528
+ if (options?.isDirect)
529
+ options.intTime = 1;
530
+ let that = this;
531
+ let opts = {
532
+ "messages": this.messages,
533
+ "stream": true,
534
+ "model": this.model,
535
+ "temperature": 0.5,
536
+ "presence_penalty": 0,
537
+ "frequency_penalty": 0
538
+ };
539
+ // console.log(opts)
540
+ let $messageReceiver = new Observable((observer) => {
541
+ let subscription = RequestFmodeChatApi("/v1/chat/completions", opts)
542
+ .subscribe(data => {
543
+ // Handle each chunk of data
544
+ /** Chunk文本数据格式如下:
545
+ 正常消息:
546
+ 'data: {"id":"chatcmpl-y2PLKqPDnwAFJIj2L5aqdH5TWK9Yv","object":"chat.completion.chunk","created":1696770162,"model":"gpt-3.5-turbo-0613","choices":[{"index":0,"delta":{"content":"本提示词仅用于测试。"},"finish_reason":null}]}',
547
+ 终止原因:
548
+ 'data: {"id":"chatcmpl-y2PLKqPDnwAFJIj2L5aqdH5TWK9Yv","object":"chat.completion.chunk","created":1696770162,"model":"gpt-3.5-turbo-0613","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}',
549
+ 结束消息:
550
+ 'data: [DONE]'
551
+ */
552
+ let chunk = String(data);
553
+ // Check if the completion message is received
554
+ // console.log(chunk)
555
+ if (chunk == 'data: [DONE]') {
556
+ this.isCompleted = true; // 标记完成 => 等待interval推送
557
+ // console.log(options?.isDirect,this.isCompleted)
558
+ if (options?.isDirect && this.isCompleted) {
559
+ observer.next({
560
+ role: "assistant",
561
+ // cid:chunkjson?.['id'],
562
+ content: this.content,
563
+ complete: true, // 推送完成
564
+ createdAt: new Date()
565
+ });
566
+ subscription.unsubscribe(); // Unsubscribe when done
567
+ options?.onComplete && options.onComplete({
568
+ role: "assistant",
569
+ // cid:chunkjson?.['id'],
570
+ content: this.content,
571
+ complete: true, // 推送完成
572
+ createdAt: new Date()
573
+ });
574
+ observer.complete();
575
+ }
576
+ }
577
+ // console.log(chunk)
578
+ if (chunk.indexOf("data:\ {") > -1) {
579
+ let chunkjson = chunkToJson(chunk);
580
+ // console.log(chunk)
581
+ // console.log(chunkjson?.choices?.[0]?.delta)
582
+ let words = chunkjson?.choices?.[0]?.delta?.content || "";
583
+ this.contentBuffer.push(words);
584
+ // 消息返回模式:定时器推送,模拟逐字输出
585
+ if (options?.isDirect) {
586
+ this.content += (words || "");
587
+ // 默认累加消息结果
588
+ if (!this.isCompleted) {
589
+ observer.next({
590
+ role: "assistant",
591
+ cid: chunkjson?.['id'],
592
+ content: this.content,
593
+ createdAt: new Date()
594
+ });
595
+ }
596
+ }
597
+ if (!options?.isDirect && !this.contentPusher) {
598
+ this.contentPusher = setInterval(() => {
599
+ if (this.isCompleted && this.contentBuffer?.length == 0) { // 推送完毕,清除计时器
600
+ observer.next({
601
+ role: "assistant",
602
+ cid: chunkjson?.['id'],
603
+ content: this.content,
604
+ complete: true, // 推送完成
605
+ createdAt: new Date()
606
+ });
607
+ subscription.unsubscribe(); // Unsubscribe when done
608
+ clearInterval(this.contentPusher);
609
+ observer.complete();
610
+ }
611
+ if (this.contentBuffer?.length >= 0) {
612
+ if (this.contentBuffer?.length > 0) {
613
+ this.content += this.contentBuffer.shift();
614
+ }
615
+ observer.next({
616
+ role: "assistant",
617
+ cid: chunkjson?.['id'],
618
+ content: this.content,
619
+ createdAt: new Date()
620
+ });
621
+ }
622
+ }, options?.intTime);
623
+ }
624
+ // console.log(this.content)
625
+ }
626
+ });
627
+ });
628
+ return $messageReceiver.pipe(bufferTime(100), // 每100ms收集消息
629
+ concatMap(messages => messages), // 使用 concatMap 逐个发送消息
630
+ delay(200) // 延迟200ms输出每条消息
631
+ );
632
+ }
633
+ }
634
+ function chunkToJson(chunk) {
635
+ let chunkjson;
636
+ try {
637
+ chunkjson = JSON.parse(chunk.replaceAll("data:\ ", ""));
638
+ }
639
+ catch (errdj) {
640
+ console.error(errdj);
641
+ }
642
+ return chunkjson || {};
643
+ }
644
+ function RequestFmodeChatApi(apipath, body, method = "POST") {
645
+ return new Observable((observer) => {
646
+ let url = API_BASE + apipath;
647
+ let API_TOKEN = Parse.User.current()?.getSessionToken() || localStorage.getItem("FMODE_AI_TOKEN");
648
+ // 通过body传递token参数,避免no-cors模式下Authoriztion头部无效
649
+ let AUTH_TOKEN = `Bearer ${API_TOKEN}`;
650
+ body.token = AUTH_TOKEN;
651
+ if (body)
652
+ body = JSON.stringify(body);
653
+ fetch(url, {
654
+ "headers": {
655
+ // "Authorization": AUTH_TOKEN,
656
+ "Content-Type": "text/plain",
657
+ "Cache-Control": "no-cache"
658
+ },
659
+ "body": body || null,
660
+ "method": method,
661
+ "credentials": "omit",
662
+ "mode": "cors"
663
+ }).then(response => {
664
+ let isStream = true || response.headers?.get("Content-Type")?.indexOf("text/event-stream") > -1;
665
+ let remainingData = ``;
666
+ function processData(data) {
667
+ let combinedData = remainingData + data;
668
+ let messages = combinedData.split('\n');
669
+ if (messages?.length > 1) { // 至少分割2条消息时进行处理
670
+ // 处理每个完整的消息
671
+ for (let i = 0; i < messages.length - 1; i++) {
672
+ let message = messages[i];
673
+ observer.next(message);
674
+ }
675
+ // 保存最后一个不完整的消息
676
+ remainingData = messages[messages.length - 1];
677
+ }
678
+ }
679
+ if (isStream) {
680
+ let greader = response.body?.getReader();
681
+ const decoder = new TextDecoder();
682
+ let rstream = new ReadableStream({
683
+ start(controller) {
684
+ function read() {
685
+ greader.read().then(({ done, value }) => {
686
+ if (done) {
687
+ controller.close();
688
+ observer.complete(); // Complete the observer when stream processing is done
689
+ return;
690
+ }
691
+ controller.enqueue(value);
692
+ read();
693
+ });
694
+ }
695
+ read();
696
+ }
697
+ });
698
+ let reader = rstream.getReader();
699
+ function processStream({ done, value }) {
700
+ if (done) {
701
+ return;
702
+ }
703
+ let text = decoder.decode(value);
704
+ processData(text); // Emit each chunk of data
705
+ reader.read().then(processStream);
706
+ }
707
+ reader.read().then(processStream);
708
+ }
709
+ })
710
+ .catch(error => observer.error(error)); // Handle any errors
711
+ // Return the subscription logic
712
+ return () => {
713
+ // Clean up logic, if needed
714
+ };
715
+ });
716
+ }
717
+ function JsonToFormData(json) {
718
+ const formData = new FormData();
719
+ function appendFormData(data, path = '') {
720
+ if (Array.isArray(data)) {
721
+ data.forEach((value, index) => {
722
+ appendFormData(value, `${path}[${index}]`);
723
+ });
724
+ }
725
+ else if (typeof data === 'object' && data !== null) {
726
+ Object.keys(data).forEach(key => {
727
+ const newPath = path ? `${path}.${key}` : key;
728
+ appendFormData(data[key], newPath);
729
+ });
730
+ }
731
+ else {
732
+ formData.append(path, data);
733
+ }
734
+ }
735
+ appendFormData(json);
736
+ return formData;
737
+ }
738
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hhdC1jbGFzcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2Ztb2RlLW5nL3NyYy9saWIvYWlnYy9zZXJ2aWNlLWZtYWkvc2VydmljZS1jaGF0L2NoYXQtY2xhc3MudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxTQUFTLEVBQUUsVUFBVSxFQUFXLEtBQUssRUFBRSxRQUFRLEVBQUUsTUFBTSxNQUFNLENBQUE7QUFDbEYsdUdBQXVHO0FBQ3ZHLE9BQU8sS0FBSyxNQUFNLE9BQU8sQ0FBQztBQUMxQixPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBRTFDLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUczQyxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDekQscUJBQXFCO0FBQ3JCLG9FQUFvRTtBQUNwRSxNQUFNLFFBQVEsR0FBVSwyQ0FBMkMsQ0FBQTtBQUNuRSxvRUFBb0U7QUFFcEUsTUFBTSxXQUFXLEdBQUcsSUFBSSxXQUFXLEVBQUUsQ0FBQztBQUN0QyxNQUFNLDJCQUEyQixHQUFHLHNCQUFzQixDQUFDO0FBQzNELE1BQU0seUJBQXlCLEdBQUcsb0JBQW9CLENBQUM7QUFzQnZELE1BQU0sVUFBVSxxQkFBcUIsQ0FBQyxPQUE4QztJQUNoRixJQUFJLElBQUksR0FBRyxFQUFFLENBQUE7SUFDYixJQUFHLE9BQU8sT0FBTyxJQUFJLFFBQVE7UUFBRSxJQUFJLEdBQUcsT0FBTyxDQUFBO0lBQzdDLElBQUcsT0FBTyxPQUFPLElBQUksUUFBUTtRQUFFLElBQUksR0FBRyxPQUFPLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQSxFQUFFLENBQUEsSUFBSSxFQUFFLElBQUksQ0FBQyxFQUFFLElBQUksSUFBSSxFQUFFLENBQUE7SUFDakYsT0FBTyxJQUFJLENBQUE7QUFDZixDQUFDO0FB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QUksRUFBRSxJQUFJLENBQUMsQ0FBQztRQUM5QixDQUFDO0lBQ0gsQ0FBQztJQUVELGNBQWMsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUVyQixPQUFPLFFBQVEsQ0FBQztBQUNsQixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgYnVmZmVyVGltZSwgY29uY2F0TWFwLCBPYnNlcnZhYmxlLCBPYnNlcnZlcixkZWxheSwgZmluYWxpemUgfSBmcm9tIFwicnhqc1wiXG4vLyB2YXIgYnVmZmVyVGltZTphbnksIGNvbmNhdE1hcDphbnksIE9ic2VydmFibGU6YW55LCBPYnNlcnZlcjphbnksZGVsYXk6YW55LCBmaW5hbGl6ZTphbnksT2JzZXJ2ZXI6YW55XG5pbXBvcnQgUGFyc2UgZnJvbSBcInBhcnNlXCI7XG5pbXBvcnQgeyBBZ2VudFByb21wdCB9IGZyb20gXCIuLi8uLi9hZ2VudFwiO1xuaW1wb3J0IHsgTmF2Q29udHJvbGxlciB9IGZyb20gXCJAaW9uaWMvYW5ndWxhclwiO1xuaW1wb3J0IHsgRm1vZGVUVFMgfSBmcm9tIFwiLi4vLi4vdm9pY2UvdHRzXCI7XG5pbXBvcnQgeyBOb3ZhQ2xvdWRTZXJ2aWNlIH0gZnJvbSBcIi4uLy4uLy4uL25vdmEtY2xvdWRcIjtcbmltcG9ydCB7IE5vdmFVcGxvYWRTZXJ2aWNlIH0gZnJvbSBcIi4uLy4uLy4uL3N0b3JhZ2Uvc2VydmljZS11cGxvYWQvbm92YS11cGxvYWQuc2VydmljZVwiO1xuaW1wb3J0IHsgUHJvbXB0VGVtcGxhdGUgfSBmcm9tIFwiQGxhbmdjaGFpbi9jb3JlL3Byb21wdHNcIjtcbi8vIHZhciBQYXJzZTphbnkgPSB7fVxuLy8gY29uc3QgQVBJX0JBU0U6c3RyaW5nID0gXCJodHRwOi8vMTI3LjAuMC4xOjczMzcvYXBpL2FwaWcvYWlnYy9ncHRcIlxuY29uc3QgQVBJX0JBU0U6c3RyaW5nID0gXCJodHRwczovL3NlcnZlci5mbW9kZS5jbi9hcGkvYXBpZy9haWdjL2dwdFwiXG4vLyBjb25zdCBBUElfQkFTRTpzdHJpbmcgPSBcImh0dHBzOi8vdGVzdC5mbW9kZS5jbi9hcGkvYXBpZy9haWdjL2dwdFwiXG5cbmNvbnN0IGFnZW50UHJvbXB0ID0gbmV3IEFnZW50UHJvbXB0KCk7XG5jb25zdCBQcm9tcHRUcGxUYWxrU1NNTE91dHB1dENvZGUgPSBcInRhbGstc3NtbC1vdXRwdXQtdHBsXCI7XG5jb25zdCBQcm9tcHRUcGxUYWxrVGV4dFNTTUxDb2RlID0gXCJ0YWxrLXRleHQtc3NtbC10cGxcIjtcbmV4cG9ydCBpbnRlcmZhY2UgRm1vZGVDaGF0TWVzc2FnZVZvaWNle1xuICAgIGlkOnN0cmluZyxcbiAgICBkdXJhdGlvbj86bnVtYmVyLFxuICAgIHNzbWw/OnN0cmluZyxcbiAgICB2b2ljZVVybD86c3RyaW5nLFxufVxuZXhwb3J0IGludGVyZmFjZSBGbW9kZUNoYXRFdmVudE1hcCB7XG4gICAgLy8g5paH5pys6KGl5YWo5LqL5Lu2XG4gICAgb25Db21wbGV0ZT8oRm1vZGVDaGF0TWVzc2FnZSk6dm9pZDtcbiAgICAvLyDor63pn7PlkIjmiJDkuovku7ZcbiAgICBvblNTTUxDb21wbGV0ZT8oRm1vZGVDaGF0TWVzc2FnZVZvaWNlKTp2b2lkOyAvLyBzc21s6ISa5pys5ZCI5oiQXG59IFxuXG5leHBvcnQgaW50ZXJmYWNlIEZtb2RlQ2hhdFZvaWNlQ29uZmlne1xuICAgIHZvaWNlOnN0cmluZyAvLyDlo7Dpn7PmupDop5LoibLku6PnoIFcbiAgICBhdXRvVGFsazpib29sZWFuIC8vIOiHquWKqOivremfs+WbnuWkjVxuICAgIHdlbGNvbWU6e1xuICAgICAgICBlbmFibGVkOnRydWUgLy8g5byA5ZCv5qyi6L+O6K+t6Z+zXG4gICAgfVxufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2V0TWVzc2FnZUNvbnRlbnRUZXh0KGNvbnRlbnQ6YW55fHN0cmluZ3xBcnJheTxDaGF0SW1hZ2VDb250ZW50SXRlbT4pe1xuICAgIGxldCB0ZXh0ID0gXCJcIlxuICAgIGlmKHR5cGVvZiBjb250ZW50ID09IFwic3RyaW5nXCIpIHRleHQgPSBjb250ZW50XG4gICAgaWYodHlwZW9mIGNvbnRlbnQgPT0gXCJvYmplY3RcIikgdGV4dCA9IGNvbnRlbnQ/LmZpbmQoaXRlbT0+aXRlbT8udGV4dCk/LnRleHQgfHwgXCJcIlxuICAgIHJldHVybiB0ZXh0XG59XG5leHBvcnQgZnVuY3Rpb24gZ2V0TWVzc2FnZUltYWdlVXJsKGNvbnRlbnQ6YW55fHN0cmluZ3xBcnJheTxDaGF0SW1hZ2VDb250ZW50SXRlbT4pe1xuICAgIGlmKHR5cGVvZiBjb250ZW50ID09IFwib2JqZWN0XCIpIHJldHVybiBjb250ZW50Py5maW5kKGl0ZW09Pml0ZW0/LmltYWdlX3VybCk/LmltYWdlX3VybD8udXJsIHx8IFwiXCJcbiAgICByZXR1cm4gbnVsbFxuICB9XG5cbmV4cG9ydCBpbnRlcmZhY2UgQ2hhdEltYWdlQ29udGVudEl0ZW17dHlwZTpzdHJpbmcsdGV4dD86c3RyaW5nLGltYWdlX3VybD86e3VybDpzdHJpbmd9fVxuXG5leHBvcnQgaW50ZXJmYWNlIEZtb2RlQ2hhdE1lc3NhZ2V7XG4gICAgcm9sZTpzdHJpbmcgLy8gdXNlciDnlKjmiLcgYXNzaXN0YW50IEFJIHN5c3RlbSDns7vnu59cbiAgICBjb250ZW50OnN0cmluZ3xBcnJheTxDaGF0SW1hZ2VDb250ZW50SXRlbT4gLy8g5raI5oGv5YaF5a65XG4gICAganNvbj86YW55XG4gICAgaGlkZGVuPzpib29sZWFuXG4gICAgY3JlYXRlZEF0PzpEYXRlIC8vIOWIm+W7uuaXtumXtFxuICAgIGNvbXBsZXRlPzpib29sZWFuIC8vIFN0cmVhbea1geW8j+WKoOi9veWujOaIkFxuICAgIHZvaWNlPzpGbW9kZUNoYXRNZXNzYWdlVm9pY2VcbiAgICAvKipBSeWbnuWkjea2iOaBr+Wtl+autSAqL1xuICAgIGNpZD86c3RyaW5nIC8vIEFJ6KGl5YWo5YaF5a6577yM5YyF5ZCrY2lk77yM5oyH5ZCR5pWw5o2u5bqTIGNoYXRjbXBsLXVEZkdGT3dJSHlpNHZNOUxrQjZrVnhjZzRpMURaXG59XG5cbi8qKlxuICogRm1vZGVDaGF0IOiBiuWkqeWvueivneexu1xuICogQHB1YmxpY1xuICovXG5leHBvcnQgY2xhc3MgRm1vZGVDaGF0e1xuXG4gICAgdGl0bGU6c3RyaW5nXG4gICAgc2Vzc2lvbklkOnN0cmluZ1xuICAgIENoYXRTZXNzaW9uID0gUGFyc2UuT2JqZWN0LmV4dGVuZChcIkNoYXRTZXNzaW9uXCIpXG4gICAgY2hhdFNlc3Npb246UGFyc2UuT2JqZWN0XG4gICAgcm9sZTphbnlcbiAgICBtZXNzYWdlTGlzdDpGbW9kZUNoYXRNZXNzYWdlW10gPSBbe3JvbGU6XCJzeXN0ZW1cIixjb250ZW50Olwi57O757uf5o+Q56S677yaQUnku4Xkvpvlj4LogINcIn1dXG4gICAgbGF0ZXN0QUlSZXNwb25zZTpzdHJpbmd8dW5kZWZpbmVkID0gYGBcbiAgICBjaGF0U2VydjphbnlcbiAgICBwdWJsaWMgdXNlcklucHV0OnN0cmluZyA9IGBgO1xuICAgIHB1YmxpYyB1c2VySW1hZ2U6c3RyaW5nID0gYGA7XG4gICAgaXNEaXJlY3Q6Ym9vbGVhbiA9IGZhbHNlO1xuXG5cbiAgICAvKiogXG4gICAgICog6Jma5ouf5b2i6LGh5bGV56S654q25oCBXG4gICAgICovXG4gICAgaXNBdmF0YXJTaG93OmJvb2xlYW4gPSBmYWxzZTtcbiAgICBhdmF0YXJNb2RlOnN0cmluZyA9IFwiXCI7XG4gICAgYXZhdGFyQ29uZmlnOmFueXx1bmRlZmluZWQ7XG4gICAgc2hvd0F2YXRhcigpe1xuICAgICAgICB0aGlzLmF2YXRhckNvbmZpZyA9IHRoaXMucm9sZT8uZ2V0KFwiYXZhdGFyQ29uZmlnXCIpXG4gICAgICAgIGlmKHRoaXMuYXZhdGFyQ29uZmlnKXtcbiAgICAgICAgICAgIHRoaXMuaXNBdmF0YXJTaG93ID0gdHJ1ZTtcbiAgICAgICAgICAgIGlmKHRoaXMuYXZhdGFyQ29uZmlnPy5pbWFnZSl7XG4gICAgICAgICAgICAgICAgdGhpcy5hdmF0YXJDb25maWcuaW1hZ2Uud2FpdGluZyA9IHRoaXMuYXZhdGFyQ29uZmlnLmltYWdlLndhaXRpbmcgfHwgdGhpcy5yb2xlPy5nZXQoXCJ0aHVtYlwiKSB8fCB0aGlzLnJvbGU/LmdldChcImF2YXRhclwiKVxuICAgICAgICAgICAgICAgIHRoaXMuYXZhdGFyTW9kZSA9IFwiaW1hZ2VcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYodGhpcy5hdmF0YXJDb25maWc/LnZpZGVvKXtcbiAgICAgICAgICAgICAgICB0aGlzLmF2YXRhckNvbmZpZy52aWRlby53YWl0aW5nID0gdGhpcy5hdmF0YXJDb25maWcudmlkZW8ud2FpdGluZ1xuICAgICAgICAgICAgICAgIHRoaXMuYXZhdGFyTW9kZSA9IFwidmlkZW9cIlxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICog6aKE572u5o+Q56S66K+N5by556qX5piv5ZCm5bGV56S6XG4gICAgICovXG4gICAgaXNQcm9tcHRNb2RhbE9wZW46Ym9vbGVhbiA9IGZhbHNlO1xuICAgIGlzUHJvbXB0TWVzc2FnZUFyZWFTaG93OmJvb2xlYW4gPSB0cnVlO1xuICAgIHByb21wdExpc3Q6YW55ID0gW11cblxuICAgIC8qKlxuICAgICAqIOi+k+WFpeaMiemSruWMuuWfn1xuICAgICAqL1xuICAgIG5hdkN0cmw6TmF2Q29udHJvbGxlclxuICAgICBsZWZ0QnV0dG9uczpBcnJheTxhbnk+ID0gW1xuICAgICAgICAvLyDmj5DnpLog5b2T6KeS6Imy6YWN572u6aKE6K6+5o+Q56S66K+N5pe2IOaYvuekulxuICAgICAgICB7dGl0bGU6XCLngbXmhJ9cIixpY29uOlwiY29sb3Itd2FuZC1vdXRsaW5lXCIsb25DbGljazooKT0+e1xuICAgICAgICAgIHRoaXMuaXNQcm9tcHRNb2RhbE9wZW4gPSB0cnVlXG4gICAgICAgIH0sc2hvdzooKT0+e1xuICAgICAgICAgIHJldHVybiB0aGlzPy5wcm9tcHRMaXN0Py5sZW5ndGhcbiAgICAgICAgfX0sXG4gICAgICAgIHt0aXRsZTpcIuinkuiJslwiLGljb246XCJwZW9wbGUtb3V0bGluZVwiLG9uQ2xpY2s6KCk9PntcbiAgICAgICAgICB0aGlzLm5hdkN0cmw/Lm5hdmlnYXRlUm9vdChcIi9jaGF0L3Byby9tYXNrXCIpO1xuICAgICAgICB9LHNob3c6KCk9PntyZXR1cm4gdHJ1ZX19LFxuICAgICAgICB7dGl0bGU6XCLlkbzlj6tcIixpY29uOlwiY2FsbC1vdXRsaW5lXCIsb25DbGljazooKT0+e1xuICAgICAgICAgICAgdGhpcy5jaGF0U2Vydj8uY2FsbFJvbGUodGhpcy5yb2xlKVxuICAgICAgICB9LHNob3c6KCk9PntcbiAgICAgICAgICByZXR1cm4gdGhpcz8ucm9sZT8uZ2V0KCd2b2ljZUNvbmZpZycpO1xuICAgICAgICB9fSxcbiAgICAgIF1cblxuICAgIC8qKlxuICAgICAqIOaYr+WQpuW8gOWQr+ivremfs+a2iOaBr+aooeW8j++8iOWNleasoe+8iVxuICAgICAqL1xuICAgIGlzVm9pY2VJbnB1dE1vZGU6Ym9vbGVhbiA9IGZhbHNlO1xuICAgIGlzVGV4dGluZzpib29sZWFuID0gZmFsc2U7XG5cbiAgICAvKipcbiAgICAgKiDmmK/lkKblvIDlkK/lrp7ml7blr7nor53mqKHlvI/vvIjlrp7ml7bvvIlcbiAgICAgKiBAZGVzY1xuICAgICAqIOW8gOWQr3NzbWwgc3lzdGVt5o+Q56S66K+NXG4gICAgICog5byA5ZCv5Zue562U5paH5pys6ZmkeG1s5pi+56S65qih5byPXG4gICAgICovXG4gICAgdm9pY2VDb25maWc6Rm1vZGVDaGF0Vm9pY2VDb25maWd8dW5kZWZpbmVkXG4gICAgaXNUYWxrTW9kZTpib29sZWFuID0gZmFsc2U7XG4gICAgU1NNTFJvbGVWb2ljZTpzdHJpbmcgPSBcInpoLUNOLVhpYW94aWFvTmV1cmFsXCI7XG5cbiAgICBuY2xvdWQ6Tm92YUNsb3VkU2VydmljZVxuICAgIHVwbG9hZFNlcnY6Tm92YVVwbG9hZFNlcnZpY2VcblxuICAgIGNvbnN0cnVjdG9yKFxuICAgICAgICBzZXNzaW9uSWQ6c3RyaW5nLHJvbGU/OlBhcnNlLk9iamVjdCxjaGF0U2Vzc2lvbj86UGFyc2UuT2JqZWN0LGNoYXRTZXJ2PzphbnksXG4gICAgICAgIG5hdkN0cmw/Ok5hdkNvbnRyb2xsZXIsXG4gICAgICAgIG5jbG91ZD86Tm92YUNsb3VkU2VydmljZSxcbiAgICAgICAgdXBsb2FkU2Vydj86Tm92YVVwbG9hZFNlcnZpY2UsXG4gICAgICAgICl7XG4gICAgICAgIHRoaXMuY2hhdFNlcnYgPSBjaGF0U2VydlxuICAgICAgICB0aGlzLnJvbGUgPSByb2xlXG4gICAgICAgIHRoaXMuc2Vzc2lvbklkID0gc2Vzc2lvbklkXG4gICAgICAgIHRoaXMubmF2Q3RybCA9IG5hdkN0cmxcbiAgICAgICAgdGhpcy5uY2xvdWQgPSBuY2xvdWRcbiAgICAgICAgdGhpcy51cGxvYWRTZXJ2ID0gdXBsb2FkU2VydlxuICAgICAgICBpZihjaGF0U2Vzc2lvbj8uaWQpe1xuICAgICAgICAgICAgdGhpcy5jaGF0U2Vzc2lvbiA9IGNoYXRTZXNzaW9uO1xuICAgICAgICAgICAgdGhpcy5tZXNzYWdlTGlzdCA9IHRoaXMuY2hhdFNlc3Npb24uZ2V0KFwibWVzc2FnZUxpc3RcIik7XG4gICAgICAgICAgICB0aGlzLnNlc3Npb25JZCA9IGNoYXRTZXNzaW9uPy5pZDtcbiAgICAgICAgfVxuICAgICAgICBpZih0aGlzLnJvbGU/LmlkKXtcbiAgICAgICAgICAgIHRoaXMudm9pY2VDb25maWcgPSB0aGlzLnJvbGU/LmdldChcInZvaWNlQ29uZmlnXCIpXG4gICAgICAgICAgICBpZih0aGlzLnZvaWNlQ29uZmlnPy5hdXRvVGFsayl7XG4gICAgICAgICAgICAgICAgdGhpcy5pc1RhbGtNb2RlID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICB0aGlzLmlzRGlyZWN0ID0gdHJ1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cbiAgICAvKipcbiAgICAgKiDkvJror51BdmF0YXLmjqfliLZcbiAgICAgKi9cbiAgICBwbGF5QW5pbWF0aW9uID0gKGFuaW1OYW1lOnN0cmluZyk9PntcbiAgICAgICAgY29uc29sZS5sb2coYW5pbU5hbWUpXG4gICAgICAgIHJldHVyblxuICAgIH1cbiAgICB3ZWxjb21lID0gYXN5bmMgKCk9PntcbiAgICAgICAgbGV0IG1zZ2xpc3QgPSB0aGlzLm1lc3NhZ2VMaXN0Py5maWx0ZXIoaXRlbT0+aXRlbT8ucm9sZT09XCJhc3Npc3RhbnRcIik7XG4gICAgICAgIGlmKG1zZ2xpc3Q/Lmxlbmd0aCkgcmV0dXJuIC8vIOW3suacieWvueivneS4jeW8gOWcuumXruWAmVxuXG4gICAgICAgIGxldCB1c2VyID0gUGFyc2UuVXNlci5jdXJyZW50KCk7XG4gICAgICAgIGxldCBwZXJzb24gPSBhd2FpdCB0aGlzLmxvYWRTZWxmKFwiUGVyc29uXCIsXCJ1c2VyVmVyaWZ5XCIpXG4gICAgICAgIGxldCBwcm9maWxlID0gYXdhaXQgdGhpcy5sb2FkU2VsZihcIlByb2ZpbGVcIixcInVzZXJcIilcbiAgICAgICAgbGV0IG5hbWUgPSB1c2VyPy5nZXQoXCJyZWFsbmFtZVwiKSB8fCBwcm9maWxlPy5nZXQoXCJuYW1lXCIpIHx8IHBlcnNvbj8uZ2V0KFwibmFtZVwiKSB8fCB1c2VyPy5nZXQoXCJuaWNrbmFtZVwiKSB8fCB1c2VyPy5nZXQoXCJuYW1lXCIpO1xuXG4gICAgICAgIC8vIOmXruWAmeivrS/pppbkuKror53pophcbiAgICAgICAgbGV0IHRwbCA9IHRoaXMucm9sZS5nZXQoXCJ2b2ljZUNvbmZpZ1wiKT8ud2VsY29tZT8ucHJvbXB0XG4gICAgICAgIGlmKCF0cGwpIHJldHVybiAvLyDml6DmqKHmnb/liJnov5Tlm55cbiAgICAgICAgbGV0IHdlbGNvbWVDb250ZW50ID0gYXdhaXQgUHJvbXB0VGVtcGxhdGUuZnJvbVRlbXBsYXRlKHRwbCx7XG4gICAgICAgICAgICB0ZW1wbGF0ZUZvcm1hdDpcIm11c3RhY2hlXCJcbiAgICAgICAgfSkuZm9ybWF0KHtcbiAgICAgICAgICAgIG5hbWU6bmFtZSxcbiAgICAgICAgICAgIHRpbWVPZkRheTp0aGlzLmdldFRpbWVPZkRheSgpXG4gICAgICAgIH0pXG4gICAgICAgIC8vIGxldCBjYWxsTmFtZSA9IG5hbWU/YCR7bmFtZX3vvIxgOlwiXCI7XG4gICAgICAgIC8vIGxldCBjYWxsVGltZSA9IGAke3RoaXMuZ2V0VGltZU9mRGF5KCl95aW9YDtcbiAgICAgICAgLy8gbGV0IHdlbGNvbWVDb250ZW50ID0gYCR7Y2FsbE5hbWV9JHtjYWxsVGltZX3vvIzmnJ/lvoXogYblkKzmgqjnmoTkurrnlJ/mlYXkuovvvIzmg7PlkozmiJHogYrkupvku4DkuYjlkaLvvJ9gO1xuXG4gICAgICAgIC8vIOeUn+aIkENoYXRWb2ljZeW5tuaSreaUvlxuICAgICAgICBsZXQgdm9pY2UgPSBhd2FpdCB0aGlzLmdldFZvaWNlQnlDb250ZW50VGV4dCh3ZWxjb21lQ29udGVudCk7XG4gICAgICAgIGxldCBtZXNzYWdlID0ge1xuICAgICAgICAgICAgcm9sZTpcImFzc2lzdGFudFwiLFxuICAgICAgICAgICAgdm9pY2U6IHZvaWNlLFxuICAgICAgICAgICAgY29udGVudDp3ZWxjb21lQ29udGVudCxcbiAgICAgICAgICAgIGNvbXBsZXRlOnRydWVcbiAgICAgICAgfVxuICAgICAgICB0aGlzLnZvaWNlTWFwW3ZvaWNlPy5pZF1cbiAgICAgICAgdGhpcy5wbGF5Q2hhdFZvaWNlKHRoaXMudm9pY2VNYXBbdm9pY2U/LmlkXSlcbiAgICAgICAgdGhpcy5tZXNzYWdlTGlzdC5wdXNoKG1lc3NhZ2UpXG4gICAgfVxuICAgIGdldFRpbWVPZkRheSgpIHtcbiAgICAgICAgY29uc3Qgbm93ID0gbmV3IERhdGUoKTtcbiAgICAgICAgY29uc3QgaG91cnMgPSBub3cuZ2V0SG91cnMoKTtcbiAgICAgICAgaWYgKGhvdXJzID49IDUgJiYgaG91cnMgPCAxMikge1xuICAgICAgICAgICAgcmV0dXJuIFwi5pep5LiKXCI7XG4gICAgICAgIH0gZWxzZSBpZiAoaG91cnMgPj0gMTIgJiYgaG91cnMgPCAxNCkge1xuICAgICAgICAgICAgcmV0dXJuIFwi5Lit5Y2IXCI7XG4gICAgICAgIH0gZWxzZSBpZiAoaG91cnMgPj0gMTQgJiYgaG91cnMgPCAxOCkge1xuICAgICAgICAgICAgcmV0dXJuIFwi5LiL5Y2IXCI7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4gXCLmmZrkuIpcIjtcbiAgICAgICAgfVxuICAgIH1cbiAgICBzZWxmOntcbiAgICAgICAgUGVyc29uPzpQYXJzZS5PYmplY3R8dW5kZWZpbmVkXG4gICAgICAgIFByb2ZpbGU/OlBhcnNlLk9iamVjdHx1bmRlZmluZWRcbiAgICB9ID0ge31cbiAgICBhc3luYyBsb2FkU2VsZihjbGFzc05hbWUsdXNlcktleSl7XG4gICAgICAgIGlmKHRoaXMuc2VsZltjbGFzc05hbWVdKSByZXR1cm4gdGhpcy5zZWxmW2NsYXNzTmFtZV1cbiAgICAgICAgbGV0IHVzZXIgPSBQYXJzZS5Vc2VyLmN1cnJlbnQoKTtcbiAgICAgICAgbGV0IHF1ZXJ5ID0gbmV3IFBhcnNlLlF1ZXJ5KGNsYXNzTmFtZSk7XG4gICAgICAgIHF1ZXJ5LmVxdWFsVG8odXNlcktleSx1c2VyPy5pZCk7XG4gICAgICAgIHRoaXMuc2VsZltjbGFzc05hbWVdID0gYXdhaXQgcXVlcnkuZmlyc3QoKTtcbiAgICB9XG5cblxuICAgIC8qKlxuICAgICAqIOWvueivneaooeWei+aPkOekuuivjVxuICAgICAqL1xuICAgICBhc3luYyBsb2FkVGFsa1N5c3RlbVByb21wdChyb2xlOlBhcnNlLk9iamVjdCl7XG4gICAgICAgIGlmKCF0aGlzLmlzVGFsa01vZGUpIHJldHVyblxuICAgICAgICBpZighcm9sZSkgcmV0dXJuXG4gICAgICAgIC8vIOWKoOi9veWjsOmfs+aooeWei++8mum7mOiupOS4uuaZk+aZk1xuICAgICAgICBpZihyb2xlPy5nZXQoJ2dlbmRlcicpPT0n55S3Jyl7XG4gICAgICAgICAgdGhpcy5TU01MUm9sZVZvaWNlID0gXCJ6aC1DTi1ZdW55ZU5ldXJhbFwiXG4gICAgICAgIH1lbHNle1xuICAgICAgICAgIHRoaXMuU1NNTFJvbGVWb2ljZSA9IFwiemgtQ04tWGlhb3hpYW9OZXVyYWxcIlxuICAgICAgICB9XG4gICAgICAgIHRoaXMuU1NNTFJvbGVWb2ljZSA9IHJvbGU/LmdldChcInZvaWNlQ29uZmlnXCIpPy52b2ljZSB8fCB0aGlzLlNTTUxSb2xlVm9pY2UgXG4gICAgICAgIGxldCBTU01MUHJvbXB0VGVtcGxhdGUgPSBhd2FpdCBhZ2VudFByb21wdC5nZXRGb3JtYXRUcGwoUHJvbXB0VHBsVGFsa1NTTUxPdXRwdXRDb2RlLHtcbiAgICAgICAgICAgIFNTTUxSb2xlVm9pY2U6IHRoaXMuU1NNTFJvbGVWb2ljZSwgLy8gU1NNTCBcbiAgICAgICAgfSlcblxuICAgICAgICBsZXQgcHJvbXB0ID0gcm9sZS5nZXQoXCJwcm9tcHRcIikgfHwgXCLor7fkvaDmia7mvJTpo57noIFBSeeahOS6uuW3peaZuuiDveS4k+WutuOAglwiXG4gICAgICAgIHByb21wdCArPSBTU01MUHJvbXB0VGVtcGxhdGU7XG4gICAgICAgIGxldCBwcm9tcHRNc2c6Rm1vZGVDaGF0TWVzc2FnZSA9IHtyb2xlOlwidXNlclwiLGNvbnRlbnQ6cHJvbXB0LGhpZGRlbjp0cnVlfVxuXG4gICAgICAgIC8vIOafpemHjVxuICAgICAgICBsZXQgY29udGVudCA9IHRoaXMubWVzc2FnZUxpc3Q/Lm1hcChpdGVtPT5pdGVtPy5jb250ZW50KS5qb2luKClcbiAgICAgICAgaWYoY29udGVudC5pbmRleE9mKHByb21wdCk+LTEpe1xuICAgICAgICAgICAgLy8g5o+Q56S66K+N5bey57uP5a2Y5ZyoXG4gICAgICAgICAgICByZXR1cm5cbiAgICAgICAgfVxuICAgICAgICAvLyDooaXlhajmj5DnpLror41cbiAgICAgICAgbGV0IHN5c3RlbUluZGV4ID0gdGhpcy5tZXNzYWdlTGlzdD8uZmluZEluZGV4KGl0ZW09Pml0ZW0/LnJvbGU9PVwic3lzdGVtXCIpO1xuICAgICAgICBsZXQgaW5zZXJ0SW5kZXggPSBzeXN0ZW1JbmRleCsxXG4gICAgICAgIHRoaXMubWVzc2FnZUxpc3Quc3BsaWNlKGluc2VydEluZGV4LDAscHJvbXB0TXNnKVxuICAgICAgICByZXR1cm4gXG4gICAgfVxuICAgIC8qKlxuICAgICAqIOinkuiJsuaPkOekuuivjVxuICAgICAqIEByZXR1cm5zIFxuICAgICAqL1xuICAgIGxvYWRSb2xlUHJvbXB0KCl7XG4gICAgICAgIC8vIOinkuiJsuaPkOekulxuICAgICAgICBsZXQgcHJvbXB0ID0gdGhpcy5yb2xlPy5nZXQoXCJwcm9tcHRcIilcbiAgICAgICAgbGV0IHByb21wdE1zZzpGbW9kZUNoYXRNZXNzYWdlID0ge3JvbGU6XCJ1c2VyXCIsY29udGVudDpwcm9tcHQsaGlkZGVuOnRydWV9XG4gICAgICAgIGlmKCFwcm9tcHQpIHJldHVybiAvLyDml6Dmj5DnpLror43ml6DpnIDmt7vliqBcbiAgICAgICAgLy8g5YaF5a655qOA5p+lXG4gICAgICAgIGxldCBjb250ZW50ID0gdGhpcy5tZXNzYWdlTGlzdD8ubWFwKGl0ZW09Pml0ZW0/LmNvbnRlbnQpLmpvaW4oKVxuICAgICAgICBpZihjb250ZW50LmluZGV4T2YocHJvbXB0KT4tMSl7XG4gICAgICAgICAgICAvLyDmj5DnpLror43lt7Lnu4/lrZjlnKhcbiAgICAgICAgICAgIHJldHVyblxuICAgICAgICB9XG4gICAgICAgIC8vIOihpeWFqOaPkOekuuivjVxuICAgICAgICBsZXQgc3lzdGVtSW5kZXggPSB0aGlzLm1lc3NhZ2VMaXN0Py5maW5kSW5kZXgoaXRlbT0+aXRlbT8ucm9sZT09XCJzeXN0ZW1cIik7XG4gICAgICAgIGxldCBpbnNlcnRJbmRleCA9IHN5c3RlbUluZGV4KzFcbiAgICAgICAgdGhpcy5tZXNzYWdlTGlzdC5zcGxpY2UoaW5zZXJ0SW5kZXgsMCxwcm9tcHRNc2cpXG4gICAgICAgIC8vIGNvbnNvbGUubG9nKHRoaXMubWVzc2FnZUxpc3QpXG4gICAgfVxuICAgIC8qKlxuICAgICAqIOWPkemAgea2iOaBr1xuICAgICAqIEBwYXJhbSBtZXNzYWdlIFxuICAgICAqIEBwYXJhbSBpbWFnZVVybCBcbiAgICAgKi9cbiAgICBhc3luYyBzZW5kTWVzc2FnZShtZXNzYWdlOnN0cmluZz1cIkZtb2RlQWlUZXN05rWL6K+V6Zeu6aKYXCIsaW1hZ2VVcmw/OnN0cmluZyxvbkNvbXBsZXRlPzpGdW5jdGlvbixldmVudE1hcD86Rm1vZGVDaGF0RXZlbnRNYXAsdm9pY2U/OkZtb2RlQ2hhdE1lc3NhZ2VWb2ljZSl7XG4gICAgICAgIC8vIOS4uua2iOaBr+WIl+ihqOihpeWFqOaPkOekuuivjVxuICAgICAgICAvLyBhd2FpdCB0aGlzLmxvYWRUYWxrU3lzdGVtUHJvbXB0KHRoaXMucm9sZSk7XG4gICAgICAgIHRoaXMuaXNQcm9tcHRNZXNzYWdlQXJlYVNob3cgPSBmYWxzZTsgLy8g5Y+R6YCB56ys5LiA5p2h5raI5oGv5ZCO77yM5YWz6Zet5o+Q56S655yL5p2/XG4gICAgICAgIHRoaXMubG9hZFJvbGVQcm9tcHQoKTtcbiAgICAgICAgLy8g55So5oi36L6T5YWl5raI5oGv77yM5re75Yqg5Yiw5Y6G5Y+y5raI5oGv5riF5Y2V5LitXG4gICAgICAgIGlmKCFpbWFnZVVybCl7IC8vIOe6r+aWh+acrFxuICAgICAgICAgICAgLy8gY29uc29sZS5sb2coXCLnuq/mlofmnKxcIilcbiAgICAgICAgICAgIGxldCBtc2c6Rm1vZGVDaGF0TWVzc2FnZSA9IHtcbiAgICAgICAgICAgICAgICByb2xlOlwidXNlclwiLFxuICAgICAgICAgICAgICAgIGNvbnRlbnQ6bWVzc2FnZSxcbiAgICAgICAgICAgICAgICBjb21wbGV0ZTp0cnVlLFxuICAgICAgICAgICAgICAgIGNyZWF0ZWRBdDpuZXcgRGF0ZSgpXG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZih2b2ljZSl7XG4gICAgICAgICAgICAgICAgbXNnLnZvaWNlID0ge2lkOnZvaWNlPy5pZCxkdXJhdGlvbjp2b2ljZT8uZHVyYXRpb259XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLm1lc3NhZ2VMaXN0LnB1c2gobXNnKVxuICAgICAgICB9ZWxzZXsgLy8g5bim5Zu+54mHXG4gICAgICAgICAgICBsZXQgbXNnOkZtb2RlQ2hhdE1lc3NhZ2UgPSB7XG4gICAgICAgICAgICAgICAgXCJyb2xlXCI6IFwidXNlclwiLFxuICAgICAgICAgICAgICAgIFwiY29udGVudFwiOiBbXG4gICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIFwidHlwZVwiOiBcImltYWdlX3VybFwiLFxuICAgICAgICAgICAgICAgICAgICAgICAgXCJpbWFnZV91cmxcIjoge1widXJsXCI6aW1hZ2VVcmx9LFxuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICBcInR5cGVcIjogXCJ0ZXh0XCIsIFxuICAgICAgICAgICAgICAgICAgICAgICAgXCJ0ZXh0XCI6IG1lc3NhZ2VcbiAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICAgIGNvbXBsZXRlOnRydWUsXG4gICAgICAgICAgICAgICAgY3JlYXRlZEF0Om5ldyBEYXRlKClcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmKHZvaWNlKXtcbiAgICAgICAgICAgICAgICBtc2cudm9pY2UgPSB7aWQ6dm9pY2U/LmlkfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhpcy5tZXNzYWdlTGlzdC5wdXNoKHtcbiAgICAgICAgICAgICAgICBcInJvbGVcIjogXCJ1c2VyXCIsXG4gICAgICAgICAgICAgICAgXCJjb250ZW50XCI6IFtcbiAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwiaW1hZ2VfdXJsXCIsXG4gICAgICAgICAgICAgICAgICAgICAgICBcImltYWdlX3VybFwiOiB7XCJ1cmxcIjppbWFnZVVybH0sXG4gICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIFwidHlwZVwiOiBcInRleHRcIiwgXG4gICAgICAgICAgICAgICAgICAgICAgICBcInRleHRcIjogbWVzc2FnZVxuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgICAgY29tcGxldGU6dHJ1ZSxcbiAgICAgICAgICAgICAgICBjcmVhdGVkQXQ6bmV3IERhdGUoKVxuICAgICAgICAgICAgfSlcbiAgICAgICAgfVxuICAgICAgICAvLyDliJvlu7rlubblj5HotbfkuIDmnaHmlrDnmoTmtojmga/ooaXlhahcbiAgICAgICAgLy8gY29uc29sZS5sb2coXCJzZW5kXCIsdGhpcy5tZXNzYWdlTGlzdClcbiAgICAgICAgbGV0IGNvbXBsZXRpb24gPSBuZXcgRm1vZGVDaGF0Q29tcGxldGlvbih0aGlzLmZpeE1lc3NhZ2VMaXN0KHRoaXMubWVzc2FnZUxpc3QpLHtcbiAgICAgICAgICAgIG1vZGVsOnRoaXMuY2hhdFNlcnY/LmN1cnJlbnRNb2RlbD8uZ2V0KFwiY29kZVwiKSB8fCBcImZtb2RlLTQuNS0xMjhrXCJcbiAgICAgICAgfSlcblxuICAgICAgICB0aGlzLnVzZXJJbnB1dCA9IFwiXCI7XG4gICAgICAgIHRoaXMudXNlckltYWdlID0gXCJcIjtcbiAgICAgICAgLy8gY29uc29sZS5sb2codGhpcy5jaGF0U2Vydj8uY3VycmVudE1vZGVsPy50b0pTT04oKSlcbiAgICAgICAgLy8g5oyB57ut5pu05paw5LqL5Lu25o6o6YCB55qE5raI5oGv5L2T5YaF5a656Iez5raI5oGv5YiX6KGoXG4gICAgICAgIGxldCBpc0RpcmVjdCA9IHRoaXMuaXNEaXJlY3QgfHwgZmFsc2VcbiAgICAgICAgaWYodGhpcy5pc1RhbGtNb2RlKXtcbiAgICAgICAgICAgIGlzRGlyZWN0ID0gdHJ1ZVxuICAgICAgICB9XG4gICAgICAgIGxldCBzZW5kJCA9IGNvbXBsZXRpb24uc2VuZENvbXBsZXRpb24oe1xuICAgICAgICAgICAgaXNEaXJlY3Q6aXNEaXJlY3QsXG4gICAgICAgICAgICBvbkNvbXBsZXRlOm9uQ29tcGxldGV8fG51bGxcbiAgICAgICAgfSkucGlwZShmaW5hbGl6ZShhc3luYyAoKT0+eyAvLyDnrqHpgZNmaW5hbGl6Zeabv+S7o+S6huaXp+eJiOeahChjb21wbGV0ZSk9Pnt9XG5cbiAgICAgICAgICAgIGlmKHRoaXMuaXNUYWxrTW9kZSl7XG4gICAgICAgICAgICAgICAgbGV0IGNvbnRlbnQgPSB0aGlzLm1lc3NhZ2VMaXN0W2NvbXBsZXRpb24uaW5kZXhPZkxpc3RdPy5jb250ZW50O1xuICAgICAgICAgICAgICAgIGxldCB2b2ljZSA9IGF3YWl0IHRoaXMuZ2V0Vm9pY2VCeUNvbnRlbnRUZXh0KGNvbnRlbnQsZXZlbnRNYXApO1xuICAgICAgICAgICAgICAgIGV2ZW50TWFwPy5vblNTTUxDb21wbGV0ZSYmZXZlbnRNYXA/Lm9uU1NNTENvbXBsZXRlKHZvaWNlKTtcbiAgICAgICAgICAgICAgICB0aGlzLm1lc3NhZ2VMaXN0W2NvbXBsZXRpb24uaW5kZXhPZkxpc3RdLnZvaWNlID0gdm9pY2U7XG4gICAgICAgICAgICAgICAgdGhpcy5wbGF5Q2hhdFZvaWNlKHRoaXMudm9pY2VNYXBbdm9pY2U/LmlkXSlcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdGhpcy5tZXNzYWdlTGlzdFtjb21wbGV0aW9uLmluZGV4T2ZMaXN0XS5jb21wbGV0ZSA9IHRydWVcbiAgICAgICAgfSkpLnN1YnNjcmliZShtZXNzYWdlPT57XG4gICAgICAgICAgICB0aGlzLm1lc3NhZ2VMaXN0W2NvbXBsZXRpb24uaW5kZXhPZkxpc3RdID0gbWVzc2FnZTtcbiAgICAgICAgICAgIHRoaXMubGF0ZXN0QUlSZXNwb25zZSA9IHRoaXMuZ2V0Q29udGVudFRleHQobWVzc2FnZT8uY29udGVudClcbiAgICAgICAgICAgXG4gICAgICAgICAgICBsZXQgc2F2ZWRMaXN0ID0gdGhpcy5jaGF0U2Vzc2lvbj8uZ2V0KFwibWVzc2FnZUxpc3RcIik/Lmxlbmd0aDtcbiAgICAgICAgICAgICAgICAvLyDnlJ/lkb3lkajmnJ/vvJrkvJror53liJvlu7rlkI7vvIzmnInmlrDmtojmga/ml7bvvIzliJvlu7rkv53lrZjkvJror51cbiAgICAgICAgICAgIGlmKHRoaXMubWVzc2FnZUxpc3Q/Lmxlbmd0aCA+IHNhdmVkTGlzdCl7XG4gICAgICAgICAgICAgICAgLy8gY29uc29sZS5sb2coXCJjeWNsZeaWsOS8muivnVwiKVxuICAgICAgICAgICAgICAgIHRoaXMuc2F2ZUNoYXRTZXNzaW9uKCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmKG1lc3NhZ2U/LmNvbXBsZXRlKXtcbiAgICAgICAgICAgICAgICAvLyDnlJ/lkb3lkajmnJ/vvJrmtojmga/lj5HpgIHlrozmiJDlkI7vvIzkv53lrZjogYrlpKnorrDlvZVcbiAgICAgICAgICAgICAgICB0aGlzLnNhdmVDaGF0U2Vzc2lvbigpOyBcbiAgICAgICAgICAgICAgICBzZW5kJC51bnN1YnNjcmliZSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gY29uc29sZS5sb2cobWVzc2FnZSlcbiAgICAgICAgfSlcbiAgICB9XG5cbiAgICBnZXRWb2ljZUJ5Q29udGVudFRleHQoY29udGVudDpzdHJpbmd8Q2hhdEltYWdlQ29udGVudEl0ZW1bXSxldmVudE1hcD86Rm1vZGVDaGF0RXZlbnRNYXAscHJvbXB0RW5hYmxlZDpib29sZWFuPWZhbHNlKTpQcm9taXNlPEZtb2RlQ2hhdE1lc3NhZ2VWb2ljZT57XG4gICAgICAgIGxldCBjb250ZW50VGV4dCA9IHRoaXMuZ2V0Q29udGVudFRleHQoY29udGVudCk7XG4gICAgICAgIGxldCBDaGF0Vm9pY2UgPSBQYXJzZS5PYmplY3QuZXh0ZW5kKFwiQ2hhdFZvaWNlXCIpO1xuICAgICAgICBsZXQgY2hhdFZvaWNlID0gbmV3IENoYXRWb2ljZSgpO1xuICAgICAgICBsZXQgY29udGVudFNTTUwgPSBgYDtcbiAgICAgICAgdGhpcy5TU01MUm9sZVZvaWNlID0gdGhpcy5yb2xlPy5nZXQoXCJ2b2ljZUNvbmZpZ1wiKT8udm9pY2UgfHwgdGhpcy5TU01MUm9sZVZvaWNlIFxuXG4gICAgICAgIHJldHVybiBuZXcgUHJvbWlzZShhc3luYyAocmVzb2x2ZSxyZWplY3QpPT57XG4gICAgICAgICAgICBsZXQgcmVzb2x2ZUNoYXRWb2ljZSA9IGFzeW5jICgpPT57XG4gICAgICAgICAgICAgICAgY2hhdFZvaWNlLnNldChcImNvbnRlbnRcIixjb250ZW50VGV4dCk7XG4gICAgICAgICAgICAgICAgY2hhdFZvaWNlLnNldChcInNzbWxcIixjb250ZW50U1NNTCk7XG4gICAgICAgICAgICAgICAgY2hhdFZvaWNlLnNldChcInJvbGVcIixcImFzc2lzdGFudFwiKTtcbiAgICAgICAgICAgICAgICBsZXQgY29tcGFueSA9IGxvY2FsU3RvcmFnZS5nZXRJdGVtKFwiY29tcGFueVwiKVxuICAgICAgICAgICAgICAgIGNvbXBhbnkmJmNoYXRWb2ljZS5zZXQoXCJjb21wYW55XCIse19fdHlwZTpcIlBvaW50ZXJcIixjbGFzc05hbWU6XCJDb21wYW55XCIsb2JqZWN0SWQ6Y29tcGFueX0pO1xuICAgICAgICAgICAgICAgIFBhcnNlLlVzZXIuY3VycmVudCgpPy5pZCYmY2hhdFZvaWNlLnNldChcInVzZXJcIixQYXJzZS5Vc2VyLmN1cnJlbnQoKS50b1BvaW50ZXIoKSk7XG4gICAgICAgICAgICAgICAgdGhpcy5jaGF0U2Vzc2lvbj8uaWQmJmNoYXRWb2ljZS5zZXQoXCJzZXNzaW9uXCIsdGhpcy5jaGF0U2Vzc2lvbj8udG9Qb2ludGVyKCkpO1xuICAgICAgICAgICAgICAgIGNoYXRWb2ljZSA9IGF3YWl0IGNoYXRWb2ljZS5zYXZlKCk7XG4gICAgICAgICAgICAgICAgdGhpcy52b2ljZU1hcFtjaGF0Vm9pY2U/LmlkXSA9IGNoYXRWb2ljZTtcbiAgICAgICAgICAgICAgICByZXNvbHZlKHtcbiAgICAgICAgICAgICAgICAgICAgaWQ6Y2hhdFZvaWNlPy5pZCxcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLyoqXG4gICAgICAgICAgICAgKiDmlrnms5XkuIDvvJrpq5jnuqfor63pn7Pnm7TmjqXor7vmlofmnKzvvIzpgJ/luqblv6vvvIzkvYbnu4boioLmg4Xnu6rmoIforrDkuI3otrPjgIJcbiAgICAgICAgICAgICAqL1xuICAgICAgICAgICAgIGlmKHByb21wdEVuYWJsZWQ9PWZhbHNlKXtcbiAgICAgICAgICAgICAgICBjb250ZW50U1NNTCA9IGA8c3BlYWsgeG1sbnM9XCJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzEwL3N5bnRoZXNpc1wiIHhtbG5zOm1zdHRzPVwiaHR0cDovL3d3dy53My5vcmcvMjAwMS9tc3R0c1wiIHhtbG5zOmVtbz1cImh0dHA6Ly93d3cudzMub3JnLzIwMDkvMTAvZW1vdGlvbm1sXCIgdmVyc2lvbj1cIjEuMFwiIHhtbDpsYW5nPVwiemgtQ05cIj48dm9pY2UgbmFtZT1cIiR7dGhpcy5TU01MUm9sZVZvaWNlfVwiPiR7Y29udGVudFRleHR9PC92b2ljZT48L3NwZWFrPmBcbiAgICAgICAgICAgICAgICByZXNvbHZlQ2hhdFZvaWNlKClcbiAgICAgICAgICAgICB9XG4gICAgICAgICAgICAvKipcbiAgICAgICAgICAgICAqIHByb21wdEVuYWJsZWQgPT0gdHJ1ZVxuICAgICAgICAgICAgICog5pa55rOV5LqM77ya6YCa6L+H5aSn5qih5Z6L5YaN5qyh5ou85o6lU1NNTOiEmuacrO+8jOWunueOsOabtOS8mOi0qOeahOivremfs+agh+iusO+8jOS9huaYr+eUn+aIkOaXtumXtOWkquaFolxuICAgICAgICAgICAgICovXG4gICAgICAgICAgICBpZihwcm9tcHRFbmFibGVkPT10cnVlKXtcbiAgICAgICAgICAgICAgICAvLyDmi7zmjqVQcm9tcHRcbiAgICAgICAgICAgICAgICBsZXQgVGV4dFNTTUxQcm9tcHQgPSBhd2FpdCBhZ2VudFByb21wdC5nZXRGb3JtYXRUcGwoUHJvbXB0VHBsVGFsa1RleHRTU01MQ29kZSx7XG4gICAgICAgICAgICAgICAgICAgIGNvbnRlbnQ6Y29udGVudFRleHQsIC8vIOaWh+acrOWGheWuuVxuICAgICAgICAgICAgICAgICAgICBTU01MUm9sZVZvaWNlOiB0aGlzLlNTTUxSb2xlVm9pY2UsIC8vIFNTTUwg5ryU6K+06ICFXG4gICAgICAgICAgICAgICAgfSlcblxuICAgICAgICAgICAgICAgIC8vIOeUn+aIkFNTTUxcbiAgICAgICAgICAgICAgICBsZXQgY29tcGxldGlvbiA9IG5ldyBGbW9kZUNoYXRDb21wbGV0aW9uKHRoaXMuZml4TWVzc2FnZUxpc3QoW3tcbiAgICAgICAgICAgICAgICAgICAgcm9sZTpcInVzZXJcIixcbiAgICAgICAgICAgICAgICAgICAgY29udGVudDpUZXh0U1NNTFByb21wdFxuICAgICAgICAgICAgICAgIH1dKSx7XG4gICAgICAgICAgICAgICAgICAgIG1vZGVsOnRoaXMuY2hhdFNlcnY/LmN1cnJlbnRNb2RlbD8uZ2V0KFwiY29kZVwiKSB8fCBcImZtb2RlLTQuNS0xMjhrXCJcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgIGxldCBzZW5kJCA9IGNvbXBsZXRpb24uc2VuZENvbXBsZXRpb24oe1xuICAgICAgICAgICAgICAgICAgICBpc0RpcmVjdDp0cnVlLFxuICAgICAgICAgICAgICAgIH0pLnN1YnNjcmliZShhc3luYyBtZXNzYWdlPT57XG4gICAgICAgICAgICAgICAgICAgIGlmKG1lc3NhZ2U/LmNvbXBsZXRlKXtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRlbnRTU01MID0gdGhpcy5nZXRDb250ZW50VGV4dChtZXNzYWdlPy5jb250ZW50KVxuICAgICAgICAgICAgICAgICAgICAgICAgcmVzb2x2ZUNoYXRWb2ljZSgpXG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgXG4gICAgICAgIH0pXG4gICAgfVxuICAgIGdldENvbnRlbnRUZXh0KGNvbnRlbnQ6c3RyaW5nfENoYXRJbWFnZUNvbnRlbnRJdGVtW10pe1xuICAgICAgICBpZih0eXBlb2YgY29udGVudCA9PSBcInN0cmluZ1wiKXtcbiAgICAgICAgICAgIHJldHVybiBjb250ZW50XG4gICAgICAgIH1lbHNle1xuICAgICAgICAgICAgcmV0dXJuIGNvbnRlbnQ/LlswXT8udGV4dCB8fCBgYFxuICAgICAgICB9XG4gICAgfVxuICAgIC8qKlxuICAgICAqIFRUUyAtIOivremfs+WQiOaIkFxuICAgICAqIFxuICAgICAqL1xuICAgIHR0czpGbW9kZVRUU1xuICAgIGFzeW5jIGluaXRUVFMoKXtcbiAgICAvLyBpZih0aGlzLnR0cykgcmV0dXJuIC8vIOW+heaYjuehrnN0c+acieaViOacn+WSjOasoeaVsOi/m+ihjOS8mOWMlu+8jOmBv+WFjeavj+asoemHjeWkjeiOt+WPllxuICAgICAgICBsZXQgY29uZmlnOmFueSA9IGF3YWl0IHRoaXMubmNsb3VkLmFwaWcoXCJ2b2ljZS90dHMvdG9rZW5cIix7Y29tcGFueTpsb2NhbFN0b3JhZ2UuZ2V0SXRlbShcImNvbXBhbnlcIil9KVxuICAgICAgICAvLyDmnIlUVFPotYTmupDvvIzkvb/nlKjmg4Xnu6rlkIjmiJBcbiAgICAgICAgY29uc29sZS5sb2coY29uZmlnKVxuICAgICAgICBpZihjb25maWc/LnRva2VuKXtcbiAgICAgICAgbGV0IHR0cyA9IG5ldyBGbW9kZVRUUyhjb25maWcsdGhpcy51cGxvYWRTZXJ2KTtcbiAgICAgICAgdGhpcy50dHM9dHRzO1xuICAgICAgICB9XG4gICAgfVxuICAgIHZvaWNlTWFwOmFueSA9IHt9XG4gICAgYXN5bmMgcGxheUNoYXRWb2ljZSh2b2ljZTpQYXJzZS5PYmplY3QsZXZlbnRNYXA/OmFueSl7XG4gICAgICAgIGF3YWl0IHRoaXMuaW5pdFRUUygpO1xuICAgICAgICAvLyBjb25zb2xlLmxvZyh0aGlzLnR0cylcbiAgICAgICAgaWYodGhpcy50dHMpe1xuICAgICAgICAgICAgdHJ5e1xuICAgICAgICAgICAgICAgIC8vIGNvbnNvbGUubG9nKHRleHRPclNTTUwpXG4gICAgICAgICAgICAgICAgLy8g5a6M5pW055qE5raI5oGv77yM6YCa6L+HVFRT5ZCI5oiQ6L+b6KGM6K6y6K+dXG4gICAgICAgICAgICAgICAgdGhpcy5wbGF5QW5pbWF0aW9uKFwidGFsa2luZ1wiKSAvLyBUYWxraW5n5Yqo55S777yM5pqC5pe255Sod2F0aW5n5Luj5pu/XG4gICAgICAgICAgICAgICAgYXdhaXQgdGhpcy50dHMuc3BlYWtBc3luYyh2b2ljZT8uZ2V0KFwic3NtbFwiKSx2b2ljZSx7XG4gICAgICAgICAgICAgICAgICAgIG9uTG9hZGVkOihhdWRpbzphbnkpPT57XG4gICAgICAgICAgICAgICAgICAgICAgICBldmVudE1hcD8ub25Mb2FkZWQmJmV2ZW50TWFwPy5vbkxvYWRlZChhdWRpbyk7IC8vIOS6i+S7tuS8oOmAklxuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICBvblN0b3A6ICgpPT57XG4gICAgICAgICAgICAgICAgICAgICAgICBldmVudE1hcD8ub25TdG9wJiZldmVudE1hcD8ub25TdG9wKCk7IC8vIOS6i+S7tuS8oOmAklxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5wbGF5QW5pbWF0aW9uKFwid2FpdGluZ1wiKSAvLyBUYWxraW5n5Yqo55S777yM5pqC5pe255Sod2F0aW5n5Luj5pu/XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgfWNhdGNoKHR0c2Vycil7XG4gICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcih0dHNlcnIpXG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgIC8vIOaXoFRTU+i1hOa6kO+8jOiwg+eUqEVkZ2UgU3BlZWNoXG4gICAgfVxuICAgIC8qKlxuICAgICAqIOS/neWtmOWNleasoeS8muivnVxuICAgICAqL1xuICAgIGFzeW5jIHNhdmVDaGF0U2Vzc2lvbigpe1xuICAgICAgICBpZih0aGlzLnNlc3Npb25JZCA9PSBcIm5ld1wiKXtcbiAgICAgICAgICAgIHRoaXMuY2hhdFNlc3Npb24gPSBuZXcgdGhpcy5DaGF0U2Vzc2lvbigpXG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLmNoYXRTZXNzaW9uLnNldChcInRpdGxlXCIsdGhpcy5nZW5UaXRsZSgpKVxuICAgICAgICB0aGlzLmNoYXRTZXNzaW9uLnNldChcInJvbGVcIix0aGlzLnJvbGU/LnRvUG9pbnRlcigpKVxuICAgICAgICB0aGlzLmNoYXRTZXNzaW9uLnNldChcIm1lc3NhZ2VMaXN0XCIsdGhpcy5tZXNzYWdlTGlzdClcbiAgICAgICAgdGhpcy5jaGF0U2Vzc2lvbi5zZXQoXCJ1c2VyXCIsUGFyc2UuVXNlci5jdXJyZW50KCk/LnRvUG9pbnRlcigpKVxuICAgICAgICB0aGlzLmNoYXRTZXNzaW9uID0gYXdhaXQgdGhpcy5jaGF0U2Vzc2lvbi5zYXZlKCk7XG4gICAgICAgIHRoaXMuc2Vzc2lvbklkID0gdGhpcy5jaGF0U2Vzc2lvbj8uaWRcbiAgICAgICAgaWYodGhpcy5zZXNzaW9uSWQpeyBcbiAgICAgICAgICAgIC8vIOS/ruaUuVVSTOWcsOWdgOS4unNlc3Npb25JZO+8jOaWueS+v+WIhuS6q+aIluWIh+aNoiDop5LoibLpobXpnaIgPT4g5Lya6K+d6aG16Z2iXG4gICAgICAgICAgICBsZXQgbmV3SHJlZiA9IGAke3dpbmRvdy5sb2NhdGlvbi5vcmlnaW59L2NoYXQvcHJvL2NoYXQvJHt0aGlzLnNlc3Npb25JZH1gXG4gICAgICAgICAgICBpZih3aW5kb3cubG9jYXRpb24/LnBhdGhuYW1lPy5pbmRleE9mKFwiY2hhdC9zZXNzaW9uXCIpPi0xKXtcbiAgICAgICAgICAgICAgICBuZXdIcmVmID0gYCR7d2luZG93LmxvY2F0aW9uLm9yaWdpbn0vY2hhdC9zZXNzaW9uL2NoYXQvJHt0aGlzLnNlc3Npb25JZH1gXG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBuZXdIcmVmID0gdGhpcy5nZXRJbnZpdGVVcmwobmV3SHJlZilcbiAgICAgICAgICAgIHdpbmRvdy5oaXN0b3J5LnJlcGxhY2VTdGF0ZShudWxsLCBudWxsLCBuZXdIcmVmK3dpbmRvdy5sb2NhdGlvbi5zZWFyY2gpO1xuICAgICAgICAgICAgLy8g5L+u5pS55pyA5paw5p2hY2hhdExpc3TmlbDmja5cbiAgICAgICAgICAgIGxldCBuZXdDaGF0ID0ge1xuICAgICAgICAgICAgICAgIHNpZDp0aGlzLmNoYXRTZXNzaW9uPy5pZCxcbiAgICAgICAgICAgICAgICByaWQ6dGhpcy5yb2xlPy5pZCxcbiAgICAgICAgICAgICAgICBuYW1lOnRoaXMucm9sZT8uZ2V0KCduYW1lJyksXG4gICAgICAgICAgICAgICAgbWVzc2FnZTp0aGlzLmNoYXRTZXNzaW9uPy5nZXQoJ21lc3NhZ2VMaXN0Jyk/Llt0aGlzLmNoYXRTZXNzaW9uPy5nZXQoJ21lc3NhZ2VMaXN0Jyk/Lmxlbmd0aC0xXT8uY29udGVudD8uc2xpY2UoMCwyMCksXG4gICAgICAgICAgICAgICAgbGF0ZXN0OnRoaXMuY2hhdFNlc3Npb24/LmNyZWF0ZWRBdFxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYoIXRoaXMuY2hhdFNlcnY/LmNoYXRMaXN0Py5sZW5ndGgpIHRoaXMuY2hhdFNlcnYuY2hhdExpc3QgPSBbXVxuICAgICAgICAgICAgbGV0IGluZGV4ID0gdGhpcy5jaGF0U2Vydj8uY2hhdExpc3Q/LmZpbmQoaXRlbT0+aXRlbT8uc2lkPT1uZXdDaGF0Py5zaWQpXG4gICAgICAgICAgICBpZihpbmRleD4tMSl7XG4gICAgICAgICAgICAgICAgdGhpcy5jaGF0U2Vydi5jaGF0TGlzdFtpbmRleF0gPSBuZXdDaGF0O1xuICAgICAgICAgICAgfSBlbHNle1xuICAgICAgICAgICAgICAgIHRoaXMuY2hhdFNlcnY/LmNoYXRMaXN0LnVuc2hpZnQobmV3Q2hhdClcbiAgICAgICAgICAgIH1cblxuICAgICAgICB9XG4gICAgfVxuICAgIGdldEludml0ZVVybCh1cmwpe1xuICAgICAgICAvLyDliKTmlq3mmK/lkKbmnInlj4LmlbBcbiAgICAgICAgbGV0IGNvbm5lY3RDaGFyID0gXCI/XCJcbiAgICAgICAgaWYodXJsPy5pbmRleE9mKFwiP1wiKT4tMSl7XG4gICAgICAgICAgY29ubmVjdENoYXIgPSBcIiZcIlxuICAgICAgICB9ZWxzZXtcbiAgICAgICAgICBjb25uZWN0Q2hhciA9IFwiP1wiXG4gICAgICAgIH1cbiAgICAgICAgLy8g6ZmE5YqgaW52aXRl5Y+C5pWwXG4gICAgICAgIGxldCBpZCA9IFBhcnNlLlVzZXI/LmN1cnJlbnQoKT8uaWRcbiAgICAgICAgaWYodXJsPy5pbmRleE9mKFwiaW52aXRlPVwiK2lkKT09LTEpe1xuICAgICAgICAgIGlmKCFpZCkgcmV0dXJuIHVybFxuICAgICAgICAgIHVybCArPSBjb25uZWN0Q2hhcisgJ2ludml0ZT0nICsgaWRcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdXJsXG4gICAgICB9XG4gICAgLy8g5qC55o2u6IGK5aSp5YaF5a655Y+K6Zeu6aKY77yM55Sf5oiQ5qCH6aKYXG4gICAgZ2VuVGl0bGUoKXtcbiAgICAgICAgaWYodGhpcy50aXRsZSkgcmV0dXJuIHRoaXMudGl0bGVcbiAgICAgICAgbGV0IGNvbnRlbnQ6c3RyaW5nfEFycmF5PENoYXRJbWFnZUNvbnRlbnRJdGVtPiA9ICB0aGlzLm1lc3NhZ2VMaXN0LmZpbmQoaXRlbT0+aXRlbS5yb2xlPT1cInVzZXJcIik/LmNvbnRlbnRcbiAgICAgICAgaWYodHlwZW9mIGNvbnRlbnQ9PVwic3RyaW5nXCIpeyAvLyDmiKrlm77mlofmnKzlhoXlrrnmloflrZfpg6jliIZcbiAgICAgICAgICAgIHRoaXMudGl0bGUgPSBjb250ZW50Py5zbGljZSgwLDE1KSB8fCBcIlwiXG4gICAgICAgIH1cbiAgICAgICAgaWYodHlwZW9mIGNvbnRlbnQ9PVwib2JqZWN0XCIpeyAvLyDmiKrlm77lpI3lkIjlhoXlrrnmloflrZfpg6jliIZcbiAgICAgICAgICAgIHRoaXMudGl0bGUgPSBjb250ZW50Py5maW5kKGl0ZW09Pml0ZW0/LnRleHQpPy50ZXh0IHx8IFwiXCJcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdGhpcy50aXRsZVxuICAgIH1cbiAgICBmaXhNZXNzYWdlTGlzdChtZXNzYWdlczpGbW9kZUNoYXRNZXNzYWdlW10pe1xuICAgICAgICByZXR1cm4gbWVzc2FnZXMubWFwKG1zZz0+e3JldHVybiB7cm9sZTptc2cucm9sZSxjb250ZW50Om1zZy5jb250ZW50fX0pXG4gICAgfVxuXG4gICAgbm93U3RyKCl7XG4gICAgICAgIGxldCBub3cgPSBuZXcgRGF0ZSgpO1xuICAgICAgICByZXR1cm4gYCR7bm93LmdldEZ1bGxZZWFyKCl9LyR7bm93LmdldE1vbnRoKCkrMX0vJHtub3cuZ2V0RGF0ZSgpfSAke25vdy5nZXRIb3VycygpfToke25vdy5nZXRNaW51dGVzKCl9OiR7bm93LmdldFNlY29uZHMoKX1gXG4gICAgfVxuICAgIFxufVxuXG4vKipcbiAqIEZtb2RlQ2hhdENvbXBsZXRpb24g5paH5pys6KGl5YWo57G7XG4gKiBAcHVibGljXG4gKi9cbmV4cG9ydCBjbGFzcyBGbW9kZUNoYXRDb21wbGV0aW9ue1xuICAgIGluZGV4T2ZMaXN0Om51bWJlclxuICAgIG1vZGVsOnN0cmluZ1xuICAgIG1lc3NhZ2VzOkZtb2RlQ2hhdE1lc3NhZ2VbXSAvLyDooaXlhajliY3mj5DnpLror43liJfooahcbiAgICBjb250ZW50OnN0cmluZyA9IFwiXCIgLy8g5pys5qyh5o6l5pS25raI5oGv57uT5p6cXG4gICAgY29udGVudEJ1ZmZlcjpzdHJpbmdbXSA9IFtdXG4gICAgY29udGVudFB1c2hlcjphbnlcbiAgICBpc0NvbXBsZXRlZDpib29sZWFuID0gZmFsc2U7XG4gICAgY29uc3RydWN0b3IoXG4gICAgICAgIG1lc3NhZ2VzOkZtb2RlQ2hhdE1lc3NhZ2VbXSxvcHRpb25zPzp7XG4gICAgICAgICAgICBtb2RlbD86c3RyaW5nXG4gICAgICAgIH1cbiAgICApe1xuICAgICAgICB0aGlzLmluZGV4T2ZMaXN0ID0gTnVtYmVyKG1lc3NhZ2VzLmxlbmd0aClcbiAgICAgICAgdGhpcy5tZXNzYWdlcyA9IG1lc3NhZ2VzXG4gICAgICAgIHRoaXMubW9kZWwgPSBvcHRpb25zPy5tb2RlbCB8fCBcImZtb2RlLTQuNS0xMjhrXCJcbiAgICB9XG4gICAgLyoqXG4gICAgICogQHBhcmFtIG9wdGlvbnNcbiAgICAgKiBAcGFyYW0gb3B0aW9ucy5pc0RpcmVjdCDmmK/lkKbkuI3nrYnlvoXpgJDlrZfojrflj5bvvIznm7TmjqXlrozmiJDlhoXlrrnmjqjpgIFcbiAgICAgKiBAcGFyYW0gb3B0aW9ucy5pbnRUaW1lIOaYr+WQpuS4jeetieW+hemAkOWtl+iOt+WPlu+8jOebtOaOpeWujOaIkOWGheWuueaOqOmAgVxuICAgICAqIEByZXR1cm5zIFxuICAgICAqL1xuICAgIHNlbmRDb21wbGV0aW9uKG9wdGlvbnM6e1xuICAgICAgICBpc0RpcmVjdD86Ym9vbGVhbixcbiAgICAgICAgaW50VGltZT86bnVtYmVyLFxuICAgICAgICBvbkNvbXBsZXRlPzpGdW5jdGlvblxuICAgIH09e30pOk9ic2VydmFibGU8Rm1vZGVDaGF0TWVzc2FnZT57XG4gICAgICAgIG9wdGlvbnMuaW50VGltZSA9IG9wdGlvbnM/LmludFRpbWUgfHwgNTAgLy8g5oyJ5q+r56eS6YCQ5a2X5o6o6YCBXG4gICAgICAgIG9wdGlvbnMuaXNEaXJlY3QgPSBvcHRpb25zPy5pc0RpcmVjdCB8fCBmYWxzZVxuICAgICAgICBpZihvcHRpb25zPy5pc0RpcmVjdCkgb3B0aW9ucy5pbnRUaW1lID0gMVxuXG4gICAgICAgIGxldCB0aGF0ID0gdGhpcztcbiAgICAgICAgbGV0IG9wdHMgPSB7XG4gICAgICAgICAgICBcIm1lc3NhZ2VzXCI6dGhpcy5tZXNzYWdlcyxcbiAgICAgICAgICAgIFwic3RyZWFtXCI6dHJ1ZSxcbiAgICAgICAgICAgIFwibW9kZWxcIjp0aGlzLm1vZGVsLFxuICAgICAgICAgICAgXCJ0ZW1wZXJhdHVyZVwiOjAuNSxcbiAgICAgICAgICAgIFwicHJlc2VuY2VfcGVuYWx0eVwiOjAsXG4gICAgICAgICAgICBcImZyZXF1ZW5jeV9wZW5hbHR5XCI6MFxuICAgICAgICB9XG4gICAgICAgIC8vIGNvbnNvbGUubG9nKG9wdHMpXG4gICAgICAgIGxldCAkbWVzc2FnZVJlY2VpdmVyID0gbmV3IE9ic2VydmFibGUoKG9ic2VydmVyOiBPYnNlcnZlcjxGbW9kZUNoYXRNZXNzYWdlPikgPT4ge1xuICAgICAgICAgICAgbGV0IHN1YnNjcmlwdGlvbiA9IFJlcXVlc3RGbW9kZUNoYXRBcGkoXCIvdjEvY2hhdC9jb21wbGV0aW9uc1wiLCBvcHRzKVxuICAgICAgICAgICAgLnN1YnNjcmliZShkYXRhID0+IHtcbiAgICAgICAgICAgICAgICAvLyBIYW5kbGUgZWFjaCBjaHVuayBvZiBkYXRhXG4gICAgICAgICAgICAgICAgLyoqIENodW5r5paH5pys5pWw5o2u5qC85byP5aaC5LiL77yaXG4gICAgICAgICAgICAgICAg5q2j5bi45raI5oGv77yaXG4gICAgICAgICAgICAgICAgJ2RhdGE6IHtcImlkXCI6XCJjaGF0Y21wbC15MlBMS3FQRG53QUZKSWoyTDVhcWRINVRXSzlZdlwiLFwib2JqZWN0XCI6XCJjaGF0LmNvbXBsZXRpb24uY2h1bmtcIixcImNyZWF0ZWRcIjoxNjk2NzcwMTYyLFwibW9kZWxcIjpcImdwdC0zLjUtdHVyYm8tMDYxM1wiLFwiY2hvaWNlc1wiOlt7XCJpbmRleFwiOjAsXCJkZWx0YVwiOntcImNvbnRlbnRcIjpcIuacrOaPkOekuuivjeS7heeUqOS6jua1i+ivleOAglwifSxcImZpbmlzaF9yZWFzb25cIjpudWxsfV19JyxcbiAgICAgICAgICAgICAgICDnu4jmraLljp/lm6DvvJpcbiAgICAgICAgICAgICAgICAnZGF0YToge1wiaWRcIjpcImNoYXRjbXBsLXkyUExLcVBEbndBRkpJajJMNWFxZEg1VFdLOVl2XCIsXCJvYmplY3RcIjpcImNoYXQuY29tcGxldGlvbi5jaHVua1wiLFwiY3JlYXRlZFwiOjE2OTY3NzAxNjIsXCJtb2RlbFwiOlwiZ3B0LTMuNS10dXJiby0wNjEzXCIsXCJjaG9pY2VzXCI6W3tcImluZGV4XCI6MCxcImRlbHRhXCI6e30sXCJmaW5pc2hfcmVhc29uXCI6XCJzdG9wXCJ9XX0nLFxuICAgICAgICAgICAgICAgIOe7k+adn+a2iOaBr++8mlxuICAgICAgICAgICAgICAgICdkYXRhOiBbRE9ORV0nXG4gICAgICAgICAgICAgICAgKi9cbiAgICAgICAgICAgICAgICBsZXQgY2h1bmsgPSBTdHJpbmcoZGF0YSk7XG4gICAgICAgICAgICAgICAgLy8gQ2hlY2sgaWYgdGhlIGNvbXBsZXRpb24gbWVzc2FnZSBpcyByZWNlaXZlZFxuICAgICAgICAgICAgICAgIC8vIGNvbnNvbGUubG9nKGNodW5rKVxuICAgICAgICAgICAgICAgIGlmIChjaHVuayA9PSAnZGF0YTogW0RPTkVdJykgeyBcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5pc0NvbXBsZXRlZCA9IHRydWU7IC8vIOagh+iusOWujOaIkCA9PiDnrYnlvoVpbnRlcnZhbOaOqOmAgVxuICAgICAgICAgICAgICAgICAgICAvLyBjb25zb2xlLmxvZyhvcHRpb25zPy5pc0RpcmVjdCx0aGlzLmlzQ29tcGxldGVkKVxuICAgICAgICAgICAgICAgICAgICBpZihvcHRpb25zPy5pc0RpcmVjdCAmJiB0aGlzLmlzQ29tcGxldGVkKXtcbiAgICAgICAgICAgICAgICAgICAgICAgIG9ic2VydmVyLm5leHQoe1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJvbGU6XCJhc3Npc3RhbnRcIixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBjaWQ6Y2h1bmtqc29uPy5bJ2lkJ10sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udGVudDp0aGlzLmNvbnRlbnQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY29tcGxldGU6dHJ1ZSwgLy8g5o6o6YCB5a6M5oiQXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY3JlYXRlZEF0Om5ldyBEYXRlKClcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgICAgICAgICBzdWJzY3JpcHRpb24udW5zdWJzY3JpYmUoKTsgLy8gVW5zdWJzY3JpYmUgd2hlbiBkb25lXG4gICAgICAgICAgICAgICAgICAgICAgICBvcHRpb25zPy5vbkNvbXBsZXRlJiZvcHRpb25zLm9uQ29tcGxldGUoe1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJvbGU6XCJhc3Npc3RhbnRcIixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBjaWQ6Y2h1bmtqc29uPy5bJ2lkJ10sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udGVudDp0aGlzLmNvbnRlbnQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY29tcGxldGU6dHJ1ZSwgLy8g5o6o6YCB5a6M5oiQXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY3JlYXRlZEF0Om5ldyBEYXRlKClcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgICAgICAgICBvYnNlcnZlci5jb21wbGV0ZSgpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIC8vIGNvbnNvbGUubG9nKGNodW5rKVxuICAgICAgICAgICAgICAgIGlmKGNodW5rLmluZGV4T2YoXCJkYXRhOlxcIHtcIik+LTEpe1xuICAgICAgICAgICAgICAgICAgICBsZXQgY2h1bmtqc29uID0gY2h1bmtUb0pzb24oY2h1bmspXG4gICAgICAgICAgICAgICAgICAgIC8vIGNvbnNvbGUubG9nKGNodW5rKVxuICAgICAgICAgICAgICAgICAgICAvLyBjb25zb2xlLmxvZyhjaHVua2pzb24/LmNob2ljZXM/LlswXT8uZGVsdGEpXG4gICAgICAgICAgICAgICAgICAgIGxldCB3b3JkcyA9IGNodW5ranNvbj8uY2hvaWNlcz8uWzBdPy5kZWx0YT8uY29udGVudCB8fCBcIlwiXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuY29udGVudEJ1ZmZlci5wdXNoKHdvcmRzKTtcblxuICAgICAgICAgICAgICAgICAgICAvLyDmtojmga/ov5Tlm57mqKHlvI/vvJrlrprml7blmajmjqjpgIHvvIzmqKHmi5/pgJDlrZfovpPlh7pcbiAgICAgICAgICAgICAgICAgICAgaWYob3B0aW9ucz8uaXNEaXJlY3Qpe1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuY29udGVudCArPSAod29yZHMgfHwgXCJcIik7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICBcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyDpu5jorqTntK/liqDmtojmga/nu5PmnpxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZighdGhpcy5pc0NvbXBsZXRlZCl7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9ic2VydmVyLm5leHQoe1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcm9sZTpcImFzc2lzdGFudFwiLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2lkOmNodW5ranNvbj8uWydpZCddLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udGVudDp0aGlzLmNvbnRlbnQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjcmVhdGVkQXQ6bmV3IERhdGUoKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBpZighb3B0aW9ucz8uaXNEaXJlY3QmJiF0aGlzLmNvbnRlbnRQdXNoZXIpe1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5jb250ZW50UHVzaGVyID0gc2V0SW50ZXJ2YWwoKCk9PntcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZih0aGlzLmlzQ29tcGxldGVkICYmIHRoaXMuY29udGVudEJ1ZmZlcj8ubGVuZ3RoPT0wKXsgLy8g5o6o6YCB5a6M5q+V77yM5riF6Zmk6K6h5pe25ZmoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9ic2VydmVyLm5leHQoe1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcm9sZTpcImFzc2lzdGFudFwiLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2lkOmNodW5ranNvbj8uWydpZCddLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udGVudDp0aGlzLmNvbnRlbnQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb21wbGV0ZTp0cnVlLCAvLyDmjqjpgIHlrozmiJBcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNyZWF0ZWRBdDpuZXcgRGF0ZSgpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1YnNjcmlwdGlvbi51bnN1YnNjcmliZSgpOyAvLyBVbnN1YnNjcmliZSB3aGVuIGRvbmVcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2xlYXJJbnRlcnZhbCh0aGlzLmNvbnRlbnRQdXNoZXIpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9ic2VydmVyLmNvbXBsZXRlKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmKHRoaXMuY29udGVudEJ1ZmZlcj8ubGVuZ3RoPj0wKXtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYodGhpcy5jb250ZW50QnVmZmVyPy5sZW5ndGg+MCl7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmNvbnRlbnQgKz0gdGhpcy5jb250ZW50QnVmZmVyLnNoaWZ0KClcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvYnNlcnZlci5uZXh0KHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJvbGU6XCJhc3Npc3RhbnRcIixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNpZDpjaHVua2pzb24/LlsnaWQnXSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRlbnQ6dGhpcy5jb250ZW50LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY3JlYXRlZEF0Om5ldyBEYXRlKClcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICB9LG9wdGlvbnM/LmludFRpbWUpXG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgLy8gY29uc29sZS5sb2codGhpcy5jb250ZW50KVxuICAgICAgICAgICAgICAgICAgICBcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KVxuICAgICAgICByZXR1cm4gJG1lc3NhZ2VSZWNlaXZlci5waXBlKFxuICAgICAgICAgICAgYnVmZmVyVGltZSgxMDApLCAvLyDmr48xMDBtc+aUtumbhua2iOaBr1xuICAgICAgICAgICAgY29uY2F0TWFwKG1lc3NhZ2VzID0+IG1lc3NhZ2VzKSwgLy8g5L2/55SoIGNvbmNhdE1hcCDpgJDkuKrlj5HpgIHmtojmga9cbiAgICAgICAgICAgIGRlbGF5KDIwMCkgLy8g5bu26L+fMjAwbXPovpPlh7rmr4/mnaHmtojmga9cbiAgICAgICAgKVxuICAgIH1cblxufVxuXG5mdW5jdGlvbiBjaHVua1RvSnNvbihjaHVuayl7XG4gICAgbGV0IGNodW5ranNvbjphbnlcbiAgICB0cnl7XG4gICAgICAgIGNodW5ranNvbiA9IEpTT04ucGFyc2UoY2h1bmsucmVwbGFjZUFsbChcImRhdGE6XFwgXCIsXCJcIikpO1xuICAgIH1jYXRjaChlcnJkail7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyZGopXG4gICAgfVxuICAgIHJldHVybiBjaHVua2pzb24gfHwge31cbn1cbmZ1bmN0aW9uIFJlcXVlc3RGbW9kZUNoYXRBcGkoYXBpcGF0aCwgYm9keSwgbWV0aG9kID0gXCJQT1NUXCIpIHtcbiAgICByZXR1cm4gbmV3IE9ic2VydmFibGUoKG9ic2VydmVyOiBPYnNlcnZlcjxhbnk+KSA9PiB7XG4gICAgICAgIGxldCB1cmwgPSBBUElfQkFTRSArIGFwaXBhdGg7XG4gICAgICAgIGxldCBBUElfVE9LRU4gPSBQYXJzZS5Vc2VyLmN1cnJlbnQoKT8uZ2V0U2Vzc2lvblRva2VuKCkgfHwgbG9jYWxTdG9yYWdlLmdldEl0ZW0oXCJGTU9ERV9BSV9UT0tFTlwiKTtcbiAgICAgICAgICAgIC8vIOmAmui/h2JvZHnkvKDpgJJ0b2tlbuWPguaVsO+8jOmBv+WFjW5vLWNvcnPmqKHlvI/kuItBdXRob3JpenRpb27lpLTpg6jml6DmlYhcbiAgICAgICAgbGV0IEFVVEhfVE9LRU4gPSBgQmVhcmVyICR7QVBJX1RPS0VOfWBcbiAgICAgICAgYm9keS50b2tlbiA9IEFVVEhfVE9LRU47XG4gICAgICAgIGlmKGJvZHkpIGJvZHkgPSBKU09OLnN0cmluZ2lmeShib2R5KVxuICAgICAgICBmZXRjaCh1cmwsIHtcbiAgICAgICAgICAgIFwiaGVhZGVyc1wiOiB7XG4gICAgICAgICAgICAgICAgLy8gXCJBdXRob3JpemF0aW9uXCI6IEFVVEhfVE9LRU4sXG4gICAgICAgICAgICAgICAgXCJDb250ZW50LVR5cGVcIjogXCJ0ZXh0L3BsYWluXCIsXG4gICAgICAgICAgICAgICAgXCJDYWNoZS1Db250cm9sXCI6IFwibm8tY2FjaGVcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwiYm9keVwiOiBib2R5IHx8IG51bGwsXG4gICAgICAgICAgICBcIm1ldGhvZFwiOiBtZXRob2QsXG4gICAgICAgICAgICBcImNyZWRlbnRpYWxzXCI6XCJvbWl0XCIsXG4gICAgICAgICAgICBcIm1vZGVcIjogXCJjb3JzXCJcbiAgICAgICAgfSkudGhlbihyZXNwb25zZSA9PiB7XG4gICAgICAgICAgICBsZXQgaXNTdHJlYW0gPSB0cnVlIHx8IHJlc3BvbnNlLmhlYWRlcnM/LmdldChcIkNvbnRlbnQtVHlwZVwiKT8uaW5kZXhPZihcInRleHQvZXZlbnQtc3RyZWFtXCIpID4gLTFcbiAgICAgICAgICAgIGxldCByZW1haW5pbmdEYXRhID0gYGA7XG5cbiAgICAgICAgICAgIGZ1bmN0aW9uIHByb2Nlc3NEYXRhKGRhdGEpIHtcbiAgICAgICAgICAgICAgICBsZXQgY29tYmluZWREYXRhID0gcmVtYWluaW5nRGF0YSArIGRhdGE7XG4gICAgICAgICAgICAgICAgbGV0IG1lc3NhZ2VzID0gY29tYmluZWREYXRhLnNwbGl0KCdcXG4nKTtcbiAgICAgICAgICAgICAgXG4gICAgICAgICAgICAgICAgaWYobWVzc2FnZXM/Lmxlbmd0aD4xKXsgLy8g6Iez5bCR5YiG5YmyMuadoea2iOaBr+aXtui/m+ihjOWkhOeQhlxuICAgICAgICAgICAgICAgICAgICAvLyDlpITnkIbmr4/kuKrlrozmlbTnmoTmtojmga9cbiAgICAgICAgICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBtZXNzYWdlcy5sZW5ndGggLSAxOyBpKyspIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGxldCBtZXNzYWdlID0gbWVzc2FnZXNbaV07XG4gICAgICAgICAgICAgICAgICAgICAgICBvYnNlcnZlci5uZXh0KG1lc3NhZ2UpXG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAvLyDkv53lrZjmnIDlkI7kuIDkuKrkuI3lrozmlbTnmoTmtojmga9cbiAgICAgICAgICAgICAgICAgICAgcmVtYWluaW5nRGF0YSA9IG1lc3NhZ2VzW21lc3NhZ2VzLmxlbmd0aCAtIDFdO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAoaXNTdHJlYW0pIHtcbiAgICAgICAgICAgICAgICBsZXQgZ3JlYWRlciA9IHJlc3BvbnNlLmJvZHk/LmdldFJlYWRlcigpO1xuICAgICAgICAgICAgICAgIGNvbnN0IGRlY29kZXIgPSBuZXcgVGV4dERlY29kZXIoKTtcblxuICAgICAgICAgICAgICAgIGxldCByc3RyZWFtID0gbmV3IFJlYWRhYmxlU3RyZWFtKHtcbiAgICAgICAgICAgICAgICAgICAgc3RhcnQoY29udHJvbGxlcikge1xuICAgICAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24gcmVhZCgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmVhZGVyLnJlYWQoKS50aGVuKCh7IGRvbmUsIHZhbHVlIH0pID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGRvbmUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udHJvbGxlci5jbG9zZSgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvYnNlcnZlci5jb21wbGV0ZSgpOyAvLyBDb21wbGV0ZSB0aGUgb2JzZXJ2ZXIgd2hlbiBzdHJlYW0gcHJvY2Vzc2luZyBpcyBkb25lXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb250cm9sbGVyLmVucXVldWUodmFsdWUpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWFkKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIHJlYWQoKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAgICAgbGV0IHJlYWRlciA9IHJzdHJlYW0uZ2V0UmVhZGVyKCk7XG5cbiAgICAgICAgICAgICAgICBmdW5jdGlvbiBwcm9jZXNzU3RyZWFtKHsgZG9uZSwgdmFsdWUgfSkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoZG9uZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgbGV0IHRleHQgPSBkZWNvZGVyLmRlY29kZSh2YWx1ZSlcbiAgICAgICAgICAgICAgICAgICAgcHJvY2Vzc0RhdGEodGV4dCkgLy8gRW1pdCBlYWNoIGNodW5rIG9mIGRhdGFcbiAgICAgICAgICAgICAgICAgICAgcmVhZGVyLnJlYWQoKS50aGVuKHByb2Nlc3NTdHJlYW0pO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJlYWRlci5yZWFkKCkudGhlbihwcm9jZXNzU3RyZWFtKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAuY2F0Y2goZXJyb3IgPT4gb2JzZXJ2ZXIuZXJyb3IoZXJyb3IpKTsgLy8gSGFuZGxlIGFueSBlcnJvcnNcblxuICAgICAgICAvLyBSZXR1cm4gdGhlIHN1YnNjcmlwdGlvbiBsb2dpY1xuICAgICAgICByZXR1cm4gKCkgPT4ge1xuICAgICAgICAgICAgLy8gQ2xlYW4gdXAgbG9naWMsIGlmIG5lZWRlZFxuICAgICAgICB9O1xuICAgIH0pO1xuICB9XG4gIFxuICBmdW5jdGlvbiBKc29uVG9Gb3JtRGF0YShqc29uKSB7XG4gICAgY29uc3QgZm9ybURhdGEgPSBuZXcgRm9ybURhdGEoKTtcbiAgXG4gICAgZnVuY3Rpb24gYXBwZW5kRm9ybURhdGEoZGF0YSwgcGF0aCA9ICcnKSB7XG4gICAgICBpZiAoQXJyYXkuaXNBcnJheShkYXRhKSkge1xuICAgICAgICBkYXRhLmZvckVhY2goKHZhbHVlLCBpbmRleCkgPT4ge1xuICAgICAgICAgIGFwcGVuZEZvcm1EYXRhKHZhbHVlLCBgJHtwYXRofVske2luZGV4fV1gKTtcbiAgICAgICAgfSk7XG4gICAgICB9IGVsc2UgaWYgKHR5cGVvZiBkYXRhID09PSAnb2JqZWN0JyAmJiBkYXRhICE9PSBudWxsKSB7XG4gICAgICAgIE9iamVjdC5rZXlzKGRhdGEpLmZvckVhY2goa2V5ID0+IHtcbiAgICAgICAgICBjb25zdCBuZXdQYXRoID0gcGF0aCA/IGAke3BhdGh9LiR7a2V5fWAgOiBrZXk7XG4gICAgICAgICAgYXBwZW5kRm9ybURhdGEoZGF0YVtrZXldLCBuZXdQYXRoKTtcbiAgICAgICAgfSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBmb3JtRGF0YS5hcHBlbmQocGF0aCwgZGF0YSk7XG4gICAgICB9XG4gICAgfVxuICBcbiAgICBhcHBlbmRGb3JtRGF0YShqc29uKTtcbiAgXG4gICAgcmV0dXJuIGZvcm1EYXRhO1xuICB9Il19