@sinequa/assistant 3.9.2 → 3.9.3
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.
- package/chat/chat.component.d.ts +35 -38
- package/chat/chat.service.d.ts +190 -84
- package/chat/debug-message/debug-message-details/debug-message-details.component.d.ts +19 -0
- package/chat/debug-message/debug-message.component.d.ts +9 -12
- package/chat/debug-message/debug-message.service.d.ts +15 -0
- package/chat/documents-upload/document-list/document-list.component.d.ts +1 -0
- package/chat/public-api.d.ts +0 -2
- package/chat/saved-chats/i18n/en.json +1 -1
- package/chat/saved-chats/i18n/fr.json +1 -1
- package/chat/saved-chats/saved-chats.component.d.ts +1 -0
- package/chat/saved-chats/saved-chats.service.d.ts +27 -0
- package/chat/services/assistant-configuration.service.d.ts +34 -0
- package/chat/services/assistant-metadata.service.d.ts +18 -0
- package/chat/services/assistant-tokens-tracking.service.d.ts +23 -0
- package/chat/services/assistant-ws-frames.service.d.ts +50 -0
- package/chat/services/signalR-connection.service.d.ts +25 -0
- package/chat/types.d.ts +12 -3
- package/chat/utils/utils.service.d.ts +67 -0
- package/esm2022/chat/chat.component.mjs +198 -227
- package/esm2022/chat/chat.service.mjs +450 -267
- package/esm2022/chat/debug-message/debug-message-details/debug-message-details.component.mjs +43 -0
- package/esm2022/chat/debug-message/debug-message.component.mjs +27 -30
- package/esm2022/chat/debug-message/debug-message.service.mjs +52 -0
- package/esm2022/chat/dialogs/rename-saved-chat.component.mjs +6 -5
- package/esm2022/chat/documents-upload/document-list/document-list.component.mjs +4 -2
- package/esm2022/chat/public-api.mjs +1 -3
- package/esm2022/chat/saved-chats/saved-chats.component.mjs +11 -10
- package/esm2022/chat/saved-chats/saved-chats.service.mjs +165 -0
- package/esm2022/chat/services/assistant-configuration.service.mjs +171 -0
- package/esm2022/chat/services/assistant-metadata.service.mjs +67 -0
- package/esm2022/chat/services/assistant-tokens-tracking.service.mjs +57 -0
- package/esm2022/chat/services/assistant-ws-frames.service.mjs +392 -0
- package/esm2022/chat/services/signalR-connection.service.mjs +109 -0
- package/esm2022/chat/types.mjs +1 -1
- package/esm2022/chat/unified-plugins/embedded-image-reference.plugin.mjs +2 -3
- package/esm2022/chat/utils/utils.service.mjs +170 -0
- package/fesm2022/sinequa-assistant-chat.mjs +2020 -1648
- package/fesm2022/sinequa-assistant-chat.mjs.map +1 -1
- package/package.json +1 -1
- package/chat/rest-chat.service.d.ts +0 -31
- package/chat/websocket-chat.service.d.ts +0 -102
- package/esm2022/chat/rest-chat.service.mjs +0 -300
- package/esm2022/chat/websocket-chat.service.mjs +0 -659
|
@@ -1,659 +0,0 @@
|
|
|
1
|
-
import { Injectable, inject } from "@angular/core";
|
|
2
|
-
import { HttpTransportType, LogLevel } from "@microsoft/signalr";
|
|
3
|
-
import { Observable, Subject, catchError, defer, forkJoin, from, fromEvent, map, merge, mergeMap, of, switchMap, take, takeUntil, tap, throwError } from "rxjs";
|
|
4
|
-
import { getToken, globalConfig } from "@sinequa/atomic";
|
|
5
|
-
import { ChatService } from "./chat.service";
|
|
6
|
-
import { SignalRWebService } from "./services/signalR.web.service";
|
|
7
|
-
import * as i0 from "@angular/core";
|
|
8
|
-
export class WebSocketChatService extends ChatService {
|
|
9
|
-
constructor() {
|
|
10
|
-
super();
|
|
11
|
-
this._messageHandlers = new Map();
|
|
12
|
-
this._actionMap = new Map();
|
|
13
|
-
this._progress = undefined;
|
|
14
|
-
this._attachments = [];
|
|
15
|
-
this._debugMessages = [];
|
|
16
|
-
this.signalRService = inject(SignalRWebService);
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* Initialize the assistant process.
|
|
20
|
-
* It includes building and starting a connection, executing parallel requests for models and functions, and handling errors during the process.
|
|
21
|
-
* ⚠️ This method MUST be called ONLY if the user is loggedIn and once when the assistant is initialized.
|
|
22
|
-
*
|
|
23
|
-
* @returns An Observable<boolean> indicating the success of the initialization process.
|
|
24
|
-
*/
|
|
25
|
-
init() {
|
|
26
|
-
// Ensure all logic is executed when subscribed to the observable
|
|
27
|
-
return defer(() => {
|
|
28
|
-
this.getRequestsUrl();
|
|
29
|
-
return from(
|
|
30
|
-
// Build the connection
|
|
31
|
-
this.buildConnection()).pipe(tap(() => this.initMessageHandlers()),
|
|
32
|
-
// Start the connection
|
|
33
|
-
switchMap(() => this.startConnection()),
|
|
34
|
-
// Execute parallel requests for models and functions
|
|
35
|
-
switchMap(() => forkJoin([
|
|
36
|
-
this.listModels(),
|
|
37
|
-
this.listFunctions()
|
|
38
|
-
])),
|
|
39
|
-
// Map the results of parallel requests to a boolean indicating success
|
|
40
|
-
map(([models, functions]) => {
|
|
41
|
-
const result = !!models && !!functions;
|
|
42
|
-
this.initProcess$.next(result);
|
|
43
|
-
return result;
|
|
44
|
-
}),
|
|
45
|
-
// Any errors during the process are caught, logged, and re-thrown to propagate the error further
|
|
46
|
-
catchError((error) => {
|
|
47
|
-
console.error('Error occurred:', error);
|
|
48
|
-
return throwError(() => error);
|
|
49
|
-
}), take(1));
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Define the assistant endpoint to use for the websocket requests
|
|
54
|
-
* It can be overridden by the app config
|
|
55
|
-
*/
|
|
56
|
-
getRequestsUrl() {
|
|
57
|
-
if (this.assistantConfig$.value.connectionSettings.websocketEndpoint) {
|
|
58
|
-
this.REQUEST_URL = this.assistantConfig$.value.connectionSettings.websocketEndpoint;
|
|
59
|
-
}
|
|
60
|
-
else {
|
|
61
|
-
throw new Error(`The property 'websocketEndpoint' must be provided when attempting to use 'WebSocket' in assistant instance`);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
overrideUser() {
|
|
65
|
-
const { userOverrideActive, userOverride } = globalConfig;
|
|
66
|
-
if (!(userOverrideActive && userOverride)) {
|
|
67
|
-
this.userOverride$.next(false);
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
// Prepare the payload to send to the OverrideUser method
|
|
71
|
-
const data = {
|
|
72
|
-
instanceId: this.chatInstanceId,
|
|
73
|
-
user: userOverride.username,
|
|
74
|
-
domain: userOverride.domain
|
|
75
|
-
};
|
|
76
|
-
// Invoke the OverrideUser method and handle errors
|
|
77
|
-
this.connection.invoke('OverrideUser', data)
|
|
78
|
-
.then((res) => this.userOverride$.next(!!res))
|
|
79
|
-
.catch(error => {
|
|
80
|
-
console.error('Error invoking OverrideUser:', error);
|
|
81
|
-
return Promise.resolve(); // Return a resolved promise to handle the error and prevent unhandled promise rejection when no further error handling exists downstream
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
listModels() {
|
|
85
|
-
const modelsSubject$ = new Subject();
|
|
86
|
-
this.connection.on('ListModels', (res) => {
|
|
87
|
-
this.models = res.models?.filter(model => !!model.enable);
|
|
88
|
-
modelsSubject$.next(this.models);
|
|
89
|
-
modelsSubject$.complete();
|
|
90
|
-
});
|
|
91
|
-
// Send the request to get the list of models
|
|
92
|
-
this.connection.invoke('ListModels', { debug: this.assistantConfig$.value.defaultValues.debug })
|
|
93
|
-
.catch(error => {
|
|
94
|
-
console.error('Error invoking ListModels:', error);
|
|
95
|
-
modelsSubject$.error(new Error(error));
|
|
96
|
-
return Promise.resolve(); // Return a resolved promise to handle the error and prevent unhandled promise rejection when no further error handling exists downstream
|
|
97
|
-
});
|
|
98
|
-
return modelsSubject$.asObservable();
|
|
99
|
-
}
|
|
100
|
-
listFunctions() {
|
|
101
|
-
const functionsSubject$ = new Subject();
|
|
102
|
-
this.connection.on('ListFunctions', (res) => {
|
|
103
|
-
this.functions = res.functions?.filter(func => func.enabled);
|
|
104
|
-
functionsSubject$.next(this.functions);
|
|
105
|
-
functionsSubject$.complete();
|
|
106
|
-
});
|
|
107
|
-
// Send the request to get the list of functions
|
|
108
|
-
this.connection.invoke('ListFunctions', { debug: this.assistantConfig$.value.defaultValues.debug })
|
|
109
|
-
.catch(error => {
|
|
110
|
-
console.error('Error invoking ListFunctions:', error);
|
|
111
|
-
functionsSubject$.error(new Error(error));
|
|
112
|
-
return Promise.resolve(); // Return a resolved promise to handle the error and prevent unhandled promise rejection when no further error handling exists downstream
|
|
113
|
-
});
|
|
114
|
-
return functionsSubject$.asObservable();
|
|
115
|
-
}
|
|
116
|
-
fetch(messages, query) {
|
|
117
|
-
// Start streaming by invoking the Chat method
|
|
118
|
-
this.streaming$.next(true);
|
|
119
|
-
// Prepare the payload to send to the Chat method
|
|
120
|
-
const data = {
|
|
121
|
-
history: messages,
|
|
122
|
-
functions: this.assistantConfig$.value.defaultValues.functions?.filter(func => func.enabled).map(func => func.name),
|
|
123
|
-
debug: this.assistantConfig$.value.defaultValues.debug,
|
|
124
|
-
serviceSettings: {
|
|
125
|
-
service_id: this.assistantConfig$.value.defaultValues.service_id,
|
|
126
|
-
model_id: this.assistantConfig$.value.defaultValues.model_id,
|
|
127
|
-
top_p: this.assistantConfig$.value.defaultValues.top_p,
|
|
128
|
-
temperature: this.assistantConfig$.value.defaultValues.temperature,
|
|
129
|
-
max_tokens: this.assistantConfig$.value.defaultValues.max_tokens,
|
|
130
|
-
...this.assistantConfig$.value.additionalServiceSettings
|
|
131
|
-
},
|
|
132
|
-
appQuery: {
|
|
133
|
-
app: this.appService.appName,
|
|
134
|
-
query
|
|
135
|
-
},
|
|
136
|
-
genericChatErrorMessage: this.assistantConfig$.value.globalSettings.genericChatErrorMessage ? this.transloco.translate(this.assistantConfig$.value.globalSettings.genericChatErrorMessage) : ""
|
|
137
|
-
};
|
|
138
|
-
if (this.assistantConfig$.value.savedChatSettings.enabled) {
|
|
139
|
-
data.instanceId = this.chatInstanceId;
|
|
140
|
-
data.savedChatId = this.savedChatId;
|
|
141
|
-
}
|
|
142
|
-
// Initialize the response with an empty assistant message
|
|
143
|
-
this._response = [{ role: "assistant", content: "", additionalProperties: { display: true } }]; // here display: true is needed in order to be able to show the progress
|
|
144
|
-
// Create a Subject to signal completion
|
|
145
|
-
const completion$ = new Subject();
|
|
146
|
-
// Create observables for each non-global handler in the _messageHandlers map (default and eventual custom ones) once it is triggered by the hub connection
|
|
147
|
-
const observables = Array
|
|
148
|
-
.from(this._messageHandlers.entries())
|
|
149
|
-
.filter(([eventName, eventHandler]) => !eventHandler.isGlobalHandler)
|
|
150
|
-
.map(([eventName, eventHandler]) => fromEvent(this.connection, eventName).pipe(mergeMap((event) => {
|
|
151
|
-
// Wrap the handler in a try-catch block to prevent the entire stream from failing if an error occurs in a single handler
|
|
152
|
-
try {
|
|
153
|
-
// Execute the handler and emit the result
|
|
154
|
-
// NB: here we could use [eventHandler.handler(event)] which behind the scenes mergeMap interprets this array as an observable sequence with one item, which it then emits
|
|
155
|
-
return of(eventHandler.handler(event));
|
|
156
|
-
}
|
|
157
|
-
catch (error) {
|
|
158
|
-
console.error(`Error in event handler for ${eventName}:`, error);
|
|
159
|
-
// Use throwError to propagate the error downstream
|
|
160
|
-
return throwError(() => new Error(`Error in event handler for ${eventName}: ${error}`));
|
|
161
|
-
}
|
|
162
|
-
})));
|
|
163
|
-
// Then merge them into a single observable in order to simulate the streaming behavior
|
|
164
|
-
const combined$ = merge(...observables).pipe(map(() => {
|
|
165
|
-
// Define $progress from the _actionMap
|
|
166
|
-
const actions = Array.from(this._actionMap.values());
|
|
167
|
-
this._progress = actions.length > 0
|
|
168
|
-
? actions.map((a) => ({
|
|
169
|
-
title: a.displayName ?? "",
|
|
170
|
-
content: a.displayValue ?? "",
|
|
171
|
-
done: a.executionTime !== undefined,
|
|
172
|
-
time: a.executionTime,
|
|
173
|
-
}))
|
|
174
|
-
: undefined;
|
|
175
|
-
// Always update ONLY the first assistant message of the _response with the new $progress, $attachment and $debug
|
|
176
|
-
// Assuming that the first assistant message is always visible since the hub does not send hidden messages by design
|
|
177
|
-
// So even if the first assistant message is hidden (display: false), the _response[0] will and should contain :
|
|
178
|
-
// - $progress, $attachment and $debug
|
|
179
|
-
// - the content of the first visible assistant message in the workflow
|
|
180
|
-
// This is mandatory in order to match the behavior of consecutive messages and maintain consistency with the chatHistory
|
|
181
|
-
if (!!this._progress || this._attachments.length > 0 || this._debugMessages.length > 0) {
|
|
182
|
-
this._response[0].additionalProperties.$progress = this._progress;
|
|
183
|
-
this._response[0].additionalProperties.$attachment = this._attachments;
|
|
184
|
-
this._response[0].additionalProperties.$debug = this._debugMessages;
|
|
185
|
-
}
|
|
186
|
-
// Return the result
|
|
187
|
-
return { history: [...messages, ...this._response], executionTime: this._executionTime, executionTimeMilliseconds: this._executionTimeMilliseconds };
|
|
188
|
-
}), takeUntil(completion$));
|
|
189
|
-
// return a new Observable that emits the result of the combined stream and handles the eventual errors of the invocation of the Chat method
|
|
190
|
-
return new Observable(observer => {
|
|
191
|
-
// Subscribe to combined stream
|
|
192
|
-
combined$.subscribe({
|
|
193
|
-
next: (value) => observer.next(value),
|
|
194
|
-
error: (err) => observer.error(err)
|
|
195
|
-
});
|
|
196
|
-
// Invoke the Chat method and handle errors
|
|
197
|
-
this.connection.invoke('Chat', data)
|
|
198
|
-
.then(() => {
|
|
199
|
-
// If a valid assistant message with (display: true) was found, update it
|
|
200
|
-
// and it should always the case
|
|
201
|
-
const index = this.firstVisibleAssistantMessageIndex(this.chatHistory);
|
|
202
|
-
if (index !== -1) {
|
|
203
|
-
this.chatHistory[index].additionalProperties.$progress = this._progress;
|
|
204
|
-
this.chatHistory[index].additionalProperties.$attachment = this._attachments;
|
|
205
|
-
this.chatHistory[index].additionalProperties.$debug = this._debugMessages;
|
|
206
|
-
}
|
|
207
|
-
// Save/update the chat if savedChat enabled
|
|
208
|
-
if (this.assistantConfig$.value.savedChatSettings.enabled && this.chatHistory.some((msg) => msg.additionalProperties?.isUserInput === true)) {
|
|
209
|
-
const action = !this.savedChatId ? this.addSavedChat(this.chatHistory).pipe(tap(() => this.listSavedChat())) : this.updateSavedChat(this.savedChatId, undefined, this.chatHistory);
|
|
210
|
-
action.pipe(take(1)).subscribe({
|
|
211
|
-
next: () => { },
|
|
212
|
-
error: (error) => {
|
|
213
|
-
this.streaming$.next(false);
|
|
214
|
-
observer.error(error);
|
|
215
|
-
},
|
|
216
|
-
complete: () => {
|
|
217
|
-
this.streaming$.next(false);
|
|
218
|
-
observer.complete();
|
|
219
|
-
}
|
|
220
|
-
});
|
|
221
|
-
}
|
|
222
|
-
else {
|
|
223
|
-
this.streaming$.next(false);
|
|
224
|
-
observer.complete();
|
|
225
|
-
}
|
|
226
|
-
})
|
|
227
|
-
.catch(error => {
|
|
228
|
-
console.error('Error invoking Chat:', error);
|
|
229
|
-
this.streaming$.next(false);
|
|
230
|
-
// Emit the error to the newly created observable
|
|
231
|
-
observer.error(error);
|
|
232
|
-
// Return a resolved promise to handle the error and prevent unhandled promise rejection
|
|
233
|
-
return Promise.resolve();
|
|
234
|
-
})
|
|
235
|
-
.finally(() => {
|
|
236
|
-
// This block concerns ONLY the completion of the "Chat" method invocation.
|
|
237
|
-
// This means the completion of the combined$ stream.
|
|
238
|
-
// It does not take into account the completion of the entire fetch method (the observable returned by fetch) and which depends on the completion of the save chat action if enabled
|
|
239
|
-
this._response = []; // Clear the _response
|
|
240
|
-
this._actionMap.clear(); // Clear the _actionMap
|
|
241
|
-
this._progress = undefined; // Clear the _progress
|
|
242
|
-
this._attachments = []; // Clear the _attachments
|
|
243
|
-
this._debugMessages = []; // Clear the _debugMessages
|
|
244
|
-
this._executionTime = ""; // Clear the _executionTime
|
|
245
|
-
this._executionTimeMilliseconds = undefined; // Clear the _executionTimeMilliseconds
|
|
246
|
-
completion$.next(); // Emit a signal to complete the observables
|
|
247
|
-
completion$.complete(); // Complete the subject
|
|
248
|
-
});
|
|
249
|
-
});
|
|
250
|
-
}
|
|
251
|
-
stopGeneration() {
|
|
252
|
-
// Start stopping generation by invoking the CancelTasks method
|
|
253
|
-
this.stoppingGeneration$.next(true);
|
|
254
|
-
// Create a Subject to hold the result of the CancelTasks method
|
|
255
|
-
const stopGenerationSubject$ = new Subject();
|
|
256
|
-
this.connection.on('CancelTasks', (res) => {
|
|
257
|
-
// When the generation is stopped before streaming any VISIBLE assistant message, this means that $progress, $attachment and $debug properties will be lost.
|
|
258
|
-
// However, the "ContextMessage" frames will be persisted in the chatHistory and the assistant may reference them in the next generation.
|
|
259
|
-
// This leads to the problem of referencing undisplayed attachments in the next generation.
|
|
260
|
-
// To solve this problem, we need to persist $progress, $attachment and $debug properties by adding a new assistant message with empty content and these properties.
|
|
261
|
-
if (this._response.length === 1 && this._response[0].content === "") {
|
|
262
|
-
this.chatHistory?.push({ role: "assistant", content: "", additionalProperties: { display: true, $progress: this._progress, $attachment: this._attachments, $debug: this._debugMessages } });
|
|
263
|
-
}
|
|
264
|
-
stopGenerationSubject$.next(!!res); // Emit the result of the CancelTasks method
|
|
265
|
-
stopGenerationSubject$.complete(); // Complete the subject
|
|
266
|
-
this.stoppingGeneration$.next(false); // Complete stopping generation
|
|
267
|
-
});
|
|
268
|
-
// Invoke the CancelTasks method and handle errors
|
|
269
|
-
this.connection.invoke('CancelTasks')
|
|
270
|
-
.catch(error => {
|
|
271
|
-
console.error('Error invoking CancelTasks:', error);
|
|
272
|
-
stopGenerationSubject$.error(new Error(error));
|
|
273
|
-
this.stoppingGeneration$.next(false); // Complete stopping generation
|
|
274
|
-
return Promise.resolve(); // Return a resolved promise to handle the error and prevent unhandled promise rejection when no further error handling exists downstream
|
|
275
|
-
});
|
|
276
|
-
return stopGenerationSubject$.asObservable();
|
|
277
|
-
}
|
|
278
|
-
listSavedChat() {
|
|
279
|
-
if (!this.assistantConfig$.value.savedChatSettings.enabled) {
|
|
280
|
-
return;
|
|
281
|
-
}
|
|
282
|
-
const data = {
|
|
283
|
-
appName: this.appService.appName,
|
|
284
|
-
instanceId: this.chatInstanceId,
|
|
285
|
-
debug: this.assistantConfig$.value.defaultValues.debug
|
|
286
|
-
};
|
|
287
|
-
this.connection.on('SavedChatList', (res) => {
|
|
288
|
-
this.savedChats$.next(res.savedChats); // emits the result to the savedChats$ subject
|
|
289
|
-
this.savedChatsError$.next(false);
|
|
290
|
-
});
|
|
291
|
-
// Invoke the method SavedChatList
|
|
292
|
-
this.connection.invoke('SavedChatList', data)
|
|
293
|
-
.catch(error => {
|
|
294
|
-
console.error('Error invoking SavedChatList:', error);
|
|
295
|
-
this.savedChatsError$.next(true);
|
|
296
|
-
return Promise.resolve();
|
|
297
|
-
});
|
|
298
|
-
}
|
|
299
|
-
getSavedChat(id) {
|
|
300
|
-
const savedChatSubject$ = new Subject();
|
|
301
|
-
const data = {
|
|
302
|
-
appName: this.appService.appName,
|
|
303
|
-
instanceId: this.chatInstanceId,
|
|
304
|
-
savedChatId: id,
|
|
305
|
-
debug: this.assistantConfig$.value.defaultValues.debug
|
|
306
|
-
};
|
|
307
|
-
this.connection.on('SavedChatGet', (res) => {
|
|
308
|
-
this.generateAuditEvent('ast-saved-chat.load', { duration: res.executionTimeMilliseconds }, res.savedChat.id);
|
|
309
|
-
savedChatSubject$.next(res.savedChat);
|
|
310
|
-
savedChatSubject$.complete();
|
|
311
|
-
});
|
|
312
|
-
// Invoke the method SavedChatGet
|
|
313
|
-
this.connection.invoke('SavedChatGet', data)
|
|
314
|
-
.catch(error => {
|
|
315
|
-
console.error('Error invoking SavedChatGet:', error);
|
|
316
|
-
savedChatSubject$.error(new Error(error));
|
|
317
|
-
return Promise.resolve(); // Return a resolved promise to handle the error and prevent unhandled promise rejection when no further error handling exists downstream
|
|
318
|
-
});
|
|
319
|
-
return savedChatSubject$.asObservable();
|
|
320
|
-
}
|
|
321
|
-
addSavedChat(messages) {
|
|
322
|
-
const addSavedChatSubject$ = new Subject();
|
|
323
|
-
const data = {
|
|
324
|
-
appName: this.appService.appName,
|
|
325
|
-
instanceId: this.chatInstanceId,
|
|
326
|
-
savedChatId: this.chatId,
|
|
327
|
-
history: messages,
|
|
328
|
-
debug: this.assistantConfig$.value.defaultValues.debug
|
|
329
|
-
};
|
|
330
|
-
this.connection.on('SavedChatAdd', (res) => {
|
|
331
|
-
this.setSavedChatId(res.savedChat.id); // Persist the savedChatId
|
|
332
|
-
this.generateAuditEvent('ast-saved-chat.add', { duration: res.executionTimeMilliseconds }, res.savedChat.id); // Generate audit event
|
|
333
|
-
addSavedChatSubject$.next(res);
|
|
334
|
-
addSavedChatSubject$.complete();
|
|
335
|
-
});
|
|
336
|
-
// Invoke the method SavedChatAdd
|
|
337
|
-
this.connection.invoke('SavedChatAdd', data)
|
|
338
|
-
.catch(error => {
|
|
339
|
-
console.error('Error invoking SavedChatAdd:', error);
|
|
340
|
-
addSavedChatSubject$.error(new Error(error));
|
|
341
|
-
return Promise.resolve(); // Return a resolved promise to handle the error and prevent unhandled promise rejection when no further error handling exists downstream
|
|
342
|
-
});
|
|
343
|
-
return addSavedChatSubject$.asObservable();
|
|
344
|
-
}
|
|
345
|
-
updateSavedChat(id, name, messages) {
|
|
346
|
-
const updateSavedChatSubject$ = new Subject();
|
|
347
|
-
const data = {
|
|
348
|
-
appName: this.appService.appName,
|
|
349
|
-
instanceId: this.chatInstanceId,
|
|
350
|
-
savedChatId: id,
|
|
351
|
-
debug: this.assistantConfig$.value.defaultValues.debug
|
|
352
|
-
};
|
|
353
|
-
if (name)
|
|
354
|
-
data["title"] = name;
|
|
355
|
-
if (messages)
|
|
356
|
-
data["history"] = messages;
|
|
357
|
-
this.connection.on('SavedChatUpdate', (res) => {
|
|
358
|
-
updateSavedChatSubject$.next(res);
|
|
359
|
-
updateSavedChatSubject$.complete();
|
|
360
|
-
});
|
|
361
|
-
// Invoke the method SavedChatUpdate
|
|
362
|
-
this.connection.invoke('SavedChatUpdate', data)
|
|
363
|
-
.catch(error => {
|
|
364
|
-
console.error('Error invoking SavedChatUpdate:', error);
|
|
365
|
-
updateSavedChatSubject$.error(new Error(error));
|
|
366
|
-
return Promise.resolve(); // Return a resolved promise to handle the error and prevent unhandled promise rejection when no further error handling exists downstream
|
|
367
|
-
});
|
|
368
|
-
return updateSavedChatSubject$.asObservable();
|
|
369
|
-
}
|
|
370
|
-
deleteSavedChat(ids) {
|
|
371
|
-
const deleteSavedChatSubject$ = new Subject();
|
|
372
|
-
const data = {
|
|
373
|
-
appName: this.appService.appName,
|
|
374
|
-
instanceId: this.chatInstanceId,
|
|
375
|
-
SavedChatIds: ids,
|
|
376
|
-
debug: this.assistantConfig$.value.defaultValues.debug
|
|
377
|
-
};
|
|
378
|
-
this.connection.on('SavedChatDelete', (res) => {
|
|
379
|
-
deleteSavedChatSubject$.next(res);
|
|
380
|
-
deleteSavedChatSubject$.complete();
|
|
381
|
-
});
|
|
382
|
-
// Invoke the method SavedChatDelete
|
|
383
|
-
this.connection.invoke('SavedChatDelete', data)
|
|
384
|
-
.catch(error => {
|
|
385
|
-
console.error('Error invoking SavedChatDelete:', error);
|
|
386
|
-
deleteSavedChatSubject$.error(new Error(error));
|
|
387
|
-
return Promise.resolve(); // Return a resolved promise to handle the error and prevent unhandled promise rejection when no further error handling exists downstream
|
|
388
|
-
});
|
|
389
|
-
return deleteSavedChatSubject$.asObservable();
|
|
390
|
-
}
|
|
391
|
-
/**
|
|
392
|
-
* Initialize out-of-the-box handlers
|
|
393
|
-
* It is a placeholder for non-streaming scenarios, where you invoke a specific hub method, and the server responds with frame message(s)
|
|
394
|
-
*/
|
|
395
|
-
initMessageHandlers() {
|
|
396
|
-
this.addMessageHandler("Error", {
|
|
397
|
-
handler: (error) => {
|
|
398
|
-
console.error(error);
|
|
399
|
-
this.notificationsService.error(error);
|
|
400
|
-
},
|
|
401
|
-
isGlobalHandler: true
|
|
402
|
-
});
|
|
403
|
-
this.addMessageHandler("Quota", {
|
|
404
|
-
handler: (message) => {
|
|
405
|
-
try {
|
|
406
|
-
this.updateQuota(message.quota);
|
|
407
|
-
}
|
|
408
|
-
catch (error) {
|
|
409
|
-
console.error(error);
|
|
410
|
-
}
|
|
411
|
-
},
|
|
412
|
-
isGlobalHandler: true
|
|
413
|
-
});
|
|
414
|
-
this.addMessageHandler("Debug", { handler: () => { },
|
|
415
|
-
isGlobalHandler: true
|
|
416
|
-
});
|
|
417
|
-
this.addMessageHandler("ActionStart", { handler: (action) => this._actionMap.set(action.guid, action),
|
|
418
|
-
isGlobalHandler: false });
|
|
419
|
-
this.addMessageHandler("ActionResult", {
|
|
420
|
-
handler: (action) => this._actionMap.set(action.guid, { ...this._actionMap.get(action.guid), ...action }),
|
|
421
|
-
isGlobalHandler: false
|
|
422
|
-
});
|
|
423
|
-
this.addMessageHandler("ActionStop", {
|
|
424
|
-
handler: (action) => this._actionMap.set(action.guid, { ...this._actionMap.get(action.guid), ...action }),
|
|
425
|
-
isGlobalHandler: false
|
|
426
|
-
});
|
|
427
|
-
this.addMessageHandler("ContextMessage", {
|
|
428
|
-
handler: (message) => {
|
|
429
|
-
this._attachments.push(message.additionalProperties);
|
|
430
|
-
},
|
|
431
|
-
isGlobalHandler: false
|
|
432
|
-
});
|
|
433
|
-
this.addMessageHandler("Message", {
|
|
434
|
-
handler: (message) => this._response.at(-1).content += message.delta ?? "",
|
|
435
|
-
isGlobalHandler: false
|
|
436
|
-
});
|
|
437
|
-
this.addMessageHandler("History", {
|
|
438
|
-
handler: (history) => {
|
|
439
|
-
// The ChatHistory is updated: it is the current copy concatenated with the new items ONLY (it can have multiple messages: the context messages + the response message)
|
|
440
|
-
// This is mandatory to not lose the previous updates of the chatHistory when the assistant is streaming multiple message steps
|
|
441
|
-
this.chatHistory = [...this.chatHistory, ...(history.history.slice(this.chatHistory.length))];
|
|
442
|
-
// Emit the updated chat usage metrics
|
|
443
|
-
if (!!this.chatHistory.at(-1)?.additionalProperties.usageMetrics) {
|
|
444
|
-
this.updateChatUsageMetrics(this.chatHistory.at(-1).additionalProperties.usageMetrics);
|
|
445
|
-
}
|
|
446
|
-
this._executionTime = history.executionTime;
|
|
447
|
-
this._executionTimeMilliseconds = history.executionTimeMilliseconds;
|
|
448
|
-
},
|
|
449
|
-
isGlobalHandler: false
|
|
450
|
-
});
|
|
451
|
-
this.addMessageHandler("SuggestedActions", {
|
|
452
|
-
handler: (message) => {
|
|
453
|
-
// Since after the "History" and "MessageBreak" that this event is caught,
|
|
454
|
-
// $suggestedAction needs to be updated directly to the last visible "assistant" message in the _response and the chatHistory
|
|
455
|
-
this._response.at(-1).additionalProperties.$suggestedAction = (this._response.at(-1).additionalProperties.$suggestedAction || []).concat(message.suggestedActions);
|
|
456
|
-
const index = this.lastVisibleAssistantMessageIndex(this.chatHistory);
|
|
457
|
-
if (index !== -1) {
|
|
458
|
-
this.chatHistory[index].additionalProperties.$suggestedAction = (this.chatHistory[index].additionalProperties.$suggestedAction || []).concat(message.suggestedActions);
|
|
459
|
-
}
|
|
460
|
-
},
|
|
461
|
-
isGlobalHandler: false
|
|
462
|
-
});
|
|
463
|
-
this.addMessageHandler("DebugDisplay", {
|
|
464
|
-
handler: (message) => this._debugMessages = this._debugMessages.concat(message),
|
|
465
|
-
isGlobalHandler: false
|
|
466
|
-
});
|
|
467
|
-
this.addMessageHandler("MessageBreak", {
|
|
468
|
-
handler: () => {
|
|
469
|
-
// Generate audit event
|
|
470
|
-
const details = {
|
|
471
|
-
'duration': this._executionTimeMilliseconds !== undefined ? this._executionTimeMilliseconds : this._executionTime,
|
|
472
|
-
'role': this.chatHistory.at(-1).role, // 'assistant'
|
|
473
|
-
'rank': this.chatHistory.length - 1,
|
|
474
|
-
'generation-tokencount': this.chatHistory.at(-1).additionalProperties.usageMetrics?.completionTokenCount,
|
|
475
|
-
'prompt-tokencount': this.chatHistory.at(-1).additionalProperties.usageMetrics?.promptTokenCount,
|
|
476
|
-
'attachments': JSON.stringify(this._attachments.map(({ recordId, contextId, parts, type }) => ({
|
|
477
|
-
recordId,
|
|
478
|
-
contextId,
|
|
479
|
-
parts: parts.map(({ partId, text }) => {
|
|
480
|
-
if (!!this.assistantConfig$.value?.auditSettings?.logContent)
|
|
481
|
-
return { partId, text };
|
|
482
|
-
return { partId };
|
|
483
|
-
}),
|
|
484
|
-
type
|
|
485
|
-
})))
|
|
486
|
-
};
|
|
487
|
-
if (!!this.assistantConfig$.value?.auditSettings?.logContent)
|
|
488
|
-
details['text'] = this.chatHistory.at(-1).content;
|
|
489
|
-
this.generateAuditEvent('ast-message', details);
|
|
490
|
-
// Push a new assistant message to the _response array ONLY if the content of the last message is not empty
|
|
491
|
-
if (this._response.at(-1).content !== "") {
|
|
492
|
-
this._response.push({ role: "assistant", content: "", additionalProperties: { display: true } });
|
|
493
|
-
}
|
|
494
|
-
},
|
|
495
|
-
isGlobalHandler: false
|
|
496
|
-
});
|
|
497
|
-
}
|
|
498
|
-
/**
|
|
499
|
-
* Override and register the entire _messageHandlers map by merging the provided map with the default one
|
|
500
|
-
* @param _messageHandlers
|
|
501
|
-
*/
|
|
502
|
-
overrideMessageHandlers(_messageHandlers) {
|
|
503
|
-
// Clear the already registered global chat handlers before merging the new ones
|
|
504
|
-
this._messageHandlers.forEach((eventHandler, eventName) => {
|
|
505
|
-
if (eventHandler.isGlobalHandler) {
|
|
506
|
-
this.unsubscribeMessageHandler(eventName);
|
|
507
|
-
}
|
|
508
|
-
});
|
|
509
|
-
// Merge the new event handlers with the existing ones
|
|
510
|
-
this._messageHandlers = new Map([...this._messageHandlers, ..._messageHandlers]);
|
|
511
|
-
// Register the global handlers among the merged map
|
|
512
|
-
this._messageHandlers.forEach((eventHandler, eventName) => {
|
|
513
|
-
if (eventHandler.isGlobalHandler) {
|
|
514
|
-
this.registerMessageHandler(eventName, eventHandler);
|
|
515
|
-
}
|
|
516
|
-
});
|
|
517
|
-
}
|
|
518
|
-
/**
|
|
519
|
-
* Add a listener for a specific event.
|
|
520
|
-
* If a listener for this same event already exists, it will be overridden.
|
|
521
|
-
* If the listener has "isGlobalHandler" set to true, it will be registered to the hub connection.
|
|
522
|
-
* @param eventName Name of the event to register a listener for
|
|
523
|
-
* @param eventHandler The handler to be called when the event is received
|
|
524
|
-
*/
|
|
525
|
-
addMessageHandler(eventName, eventHandler) {
|
|
526
|
-
this._messageHandlers.set(eventName, eventHandler);
|
|
527
|
-
if (eventHandler.isGlobalHandler) {
|
|
528
|
-
this.registerMessageHandler(eventName, eventHandler);
|
|
529
|
-
}
|
|
530
|
-
}
|
|
531
|
-
/**
|
|
532
|
-
* Dynamically register a listener for a specific event.
|
|
533
|
-
* If a listener for this event already exists, it will be overridden.
|
|
534
|
-
* @param eventName Name of the event to register a listener for
|
|
535
|
-
* @param eventHandler The handler to be called when the event is received
|
|
536
|
-
*/
|
|
537
|
-
registerMessageHandler(eventName, eventHandler) {
|
|
538
|
-
if (!this.connection) {
|
|
539
|
-
console.log("No connection found to register the listener" + eventName);
|
|
540
|
-
return;
|
|
541
|
-
}
|
|
542
|
-
this.connection.on(eventName, (data) => {
|
|
543
|
-
eventHandler.handler(data);
|
|
544
|
-
});
|
|
545
|
-
}
|
|
546
|
-
/**
|
|
547
|
-
* Remove a listener for a specific event from the _messageHandlers map and unsubscribe from receiving messages for this event from the SignalR hub.
|
|
548
|
-
* @param eventName Name of the event to remove the listener for
|
|
549
|
-
*/
|
|
550
|
-
removeMessageHandler(eventName) {
|
|
551
|
-
this._messageHandlers.delete(eventName);
|
|
552
|
-
this.unsubscribeMessageHandler(eventName);
|
|
553
|
-
}
|
|
554
|
-
/**
|
|
555
|
-
* Unsubscribe from receiving messages for a specific event from the SignalR hub.
|
|
556
|
-
* ALL its related listeners will be removed from hub connection
|
|
557
|
-
* This is needed to prevent accumulating old listeners when overriding the entire _messageHandlers map
|
|
558
|
-
* @param eventName Name of the event
|
|
559
|
-
*/
|
|
560
|
-
unsubscribeMessageHandler(eventName) {
|
|
561
|
-
this.connection.off(eventName);
|
|
562
|
-
}
|
|
563
|
-
/**
|
|
564
|
-
* Build a connection to the signalR websocket and register default listeners to the methods defined in the server hub class
|
|
565
|
-
* @param options The options for the connection. It overrides the default options
|
|
566
|
-
* @param logLevel Define the log level displayed in the console
|
|
567
|
-
* @returns Promise that resolves when the connection is built
|
|
568
|
-
*/
|
|
569
|
-
buildConnection(options) {
|
|
570
|
-
return new Promise((resolve, reject) => {
|
|
571
|
-
if (!this.REQUEST_URL) {
|
|
572
|
-
reject(new Error("No endpoint provided to connect the websocket to"));
|
|
573
|
-
return;
|
|
574
|
-
}
|
|
575
|
-
const logLevel = this._getLogLevel();
|
|
576
|
-
if (this.assistantConfig$.value?.connectionSettings.signalRSkipNegotiation === true)
|
|
577
|
-
options = { ...options, skipNegotiation: true };
|
|
578
|
-
this.connection = this.signalRService.buildConnection(this.REQUEST_URL, { ...this.defaultOptions, ...options }, logLevel, true);
|
|
579
|
-
const signalRServerTimeoutInMilliseconds = this.assistantConfig$.value?.connectionSettings.signalRServerTimeoutInMilliseconds;
|
|
580
|
-
if (signalRServerTimeoutInMilliseconds) {
|
|
581
|
-
this.connection.serverTimeoutInMilliseconds = signalRServerTimeoutInMilliseconds;
|
|
582
|
-
}
|
|
583
|
-
resolve();
|
|
584
|
-
});
|
|
585
|
-
}
|
|
586
|
-
/**
|
|
587
|
-
* Start the connection
|
|
588
|
-
* @returns Promise that resolves when the connection is started
|
|
589
|
-
*/
|
|
590
|
-
startConnection() {
|
|
591
|
-
return this.signalRService.startConnection(this.connection);
|
|
592
|
-
}
|
|
593
|
-
/**
|
|
594
|
-
* Stop the connection
|
|
595
|
-
* @returns Promise that resolves when the connection is stopped
|
|
596
|
-
*/
|
|
597
|
-
stopConnection() {
|
|
598
|
-
return this.signalRService.stopConnection(this.connection);
|
|
599
|
-
}
|
|
600
|
-
_getTransports() {
|
|
601
|
-
switch (this.assistantConfig$.value?.connectionSettings.signalRTransport) {
|
|
602
|
-
case "WebSockets":
|
|
603
|
-
return HttpTransportType.WebSockets;
|
|
604
|
-
case "ServerSentEvents":
|
|
605
|
-
return HttpTransportType.ServerSentEvents;
|
|
606
|
-
case "LongPolling":
|
|
607
|
-
return HttpTransportType.LongPolling;
|
|
608
|
-
default:
|
|
609
|
-
return HttpTransportType.None;
|
|
610
|
-
}
|
|
611
|
-
}
|
|
612
|
-
_getLogLevel() {
|
|
613
|
-
switch (this.assistantConfig$.value?.connectionSettings.signalRLogLevel) {
|
|
614
|
-
case "Critical":
|
|
615
|
-
return LogLevel.Critical; // Log level for diagnostic messages that indicate a failure that will terminate the entire application.
|
|
616
|
-
case "Debug":
|
|
617
|
-
return LogLevel.Debug; // Log level for low severity diagnostic messages.
|
|
618
|
-
case "Error":
|
|
619
|
-
return LogLevel.Error; // Log level for diagnostic messages that indicate a failure in the current operation.
|
|
620
|
-
case "Information":
|
|
621
|
-
return LogLevel.Information; // Log level for informational diagnostic messages.
|
|
622
|
-
case "None":
|
|
623
|
-
return LogLevel.None; // The highest possible log level. Used when configuring logging to indicate that no log messages should be emitted.
|
|
624
|
-
case "Trace":
|
|
625
|
-
return LogLevel.Trace; // Log level for very low severity diagnostic messages.
|
|
626
|
-
case "Warning":
|
|
627
|
-
return LogLevel.Warning; // Log level for diagnostic messages that indicate a non-fatal problem.
|
|
628
|
-
default:
|
|
629
|
-
return LogLevel.None; // The highest possible log level. Used when configuring logging to indicate that no log messages should be emitted.
|
|
630
|
-
}
|
|
631
|
-
}
|
|
632
|
-
get defaultOptions() {
|
|
633
|
-
let headers = {
|
|
634
|
-
"sinequa-force-camel-case": "true",
|
|
635
|
-
"x-language": this.getCurrentLocaleName(),
|
|
636
|
-
"ui-language": this.getCurrentLocaleName(),
|
|
637
|
-
};
|
|
638
|
-
const token = getToken();
|
|
639
|
-
if (token) {
|
|
640
|
-
headers = { ...headers, "sinequa-csrf-token": token };
|
|
641
|
-
}
|
|
642
|
-
// For the first GET request sent by signalR to start a WebSocket protocol,
|
|
643
|
-
// as far as we know, signalR only lets us tweak the request with this access token factory
|
|
644
|
-
// so we pass along the Sinequa CSRF token to pass the CSRF check..
|
|
645
|
-
return {
|
|
646
|
-
transport: this._getTransports(),
|
|
647
|
-
withCredentials: true,
|
|
648
|
-
headers,
|
|
649
|
-
skipNegotiation: false,
|
|
650
|
-
accessTokenFactory: () => token || ""
|
|
651
|
-
};
|
|
652
|
-
}
|
|
653
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: WebSocketChatService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
654
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: WebSocketChatService }); }
|
|
655
|
-
}
|
|
656
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: WebSocketChatService, decorators: [{
|
|
657
|
-
type: Injectable
|
|
658
|
-
}], ctorParameters: () => [] });
|
|
659
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2Vic29ja2V0LWNoYXQuc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3Byb2plY3RzL2Fzc2lzdGFudC9jaGF0L3dlYnNvY2tldC1jaGF0LnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDbkQsT0FBTyxFQUFFLGlCQUFpQixFQUFpQixRQUFRLEVBQWtCLE1BQU0sb0JBQW9CLENBQUM7QUFDaEcsT0FBTyxFQUFFLFVBQVUsRUFBRSxPQUFPLEVBQUUsVUFBVSxFQUFFLEtBQUssRUFBRSxRQUFRLEVBQUUsSUFBSSxFQUFFLFNBQVMsRUFBRSxHQUFHLEVBQUUsS0FBSyxFQUFFLFFBQVEsRUFBRSxFQUFFLEVBQUUsU0FBUyxFQUFFLElBQUksRUFBRSxTQUFTLEVBQUUsR0FBRyxFQUFFLFVBQVUsRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUVoSyxPQUFPLEVBQVMsUUFBUSxFQUFFLFlBQVksRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBRWhFLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUM3QyxPQUFPLEVBQXFCLGlCQUFpQixFQUFFLE1BQU0sZ0NBQWdDLENBQUM7O0FBSXRGLE1BQU0sT0FBTyxvQkFBcUIsU0FBUSxXQUFXO0lBZW5EO1FBQ0UsS0FBSyxFQUFFLENBQUM7UUFaRixxQkFBZ0IsR0FBcUMsSUFBSSxHQUFHLEVBQUUsQ0FBQztRQUUvRCxlQUFVLEdBQUcsSUFBSSxHQUFHLEVBQXlCLENBQUM7UUFDOUMsY0FBUyxHQUErQixTQUFTLENBQUM7UUFHbEQsaUJBQVksR0FBNEIsRUFBRSxDQUFDO1FBQzNDLG1CQUFjLEdBQW1CLEVBQUUsQ0FBQztRQUVyQyxtQkFBYyxHQUFHLE1BQU0sQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO0lBSWxELENBQUM7SUFFRDs7Ozs7O09BTUc7SUFDSCxJQUFJ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RSwyRkFBMkY7UUFDM0YsbUVBQW1FO1FBQ25FLE9BQU87WUFDTCxTQUFTLEVBQUUsSUFBSSxDQUFDLGNBQWMsRUFBRTtZQUNoQyxlQUFlLEVBQUUsSUFBSTtZQUNyQixPQUFPO1lBQ1AsZUFBZSxFQUFFLEtBQUs7WUFDdEIsa0JBQWtCLEVBQUUsR0FBRyxFQUFFLENBQUMsS0FBSyxJQUFJLEVBQUU7U0FDdEMsQ0FBQTtJQUNILENBQUM7K0dBaHdCVSxvQkFBb0I7bUhBQXBCLG9CQUFvQjs7NEZBQXBCLG9CQUFvQjtrQkFEaEMsVUFBVSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEluamVjdGFibGUsIGluamVjdCB9IGZyb20gXCJAYW5ndWxhci9jb3JlXCI7XG5pbXBvcnQgeyBIdHRwVHJhbnNwb3J0VHlwZSwgSHViQ29ubmVjdGlvbiwgTG9nTGV2ZWwsIE1lc3NhZ2VIZWFkZXJzIH0gZnJvbSBcIkBtaWNyb3NvZnQvc2lnbmFsclwiO1xuaW1wb3J0IHsgT2JzZXJ2YWJsZSwgU3ViamVjdCwgY2F0Y2hFcnJvciwgZGVmZXIsIGZvcmtKb2luLCBmcm9tLCBmcm9tRXZlbnQsIG1hcCwgbWVyZ2UsIG1lcmdlTWFwLCBvZiwgc3dpdGNoTWFwLCB0YWtlLCB0YWtlVW50aWwsIHRhcCwgdGhyb3dFcnJvciB9IGZyb20gXCJyeGpzXCI7XG5cbmltcG9ydCB7IFF1ZXJ5LCBnZXRUb2tlbiwgZ2xvYmFsQ29uZmlnIH0gZnJvbSBcIkBzaW5lcXVhL2F0b21pY1wiO1xuXG5pbXBvcnQgeyBDaGF0U2VydmljZSB9IGZyb20gXCIuL2NoYXQuc2VydmljZVwiO1xuaW1wb3J0IHsgQ29ubmVjdGlvbk9wdGlvbnMsIFNpZ25hbFJXZWJTZXJ2aWNlIH0gZnJvbSBcIi4vc2VydmljZXMvc2lnbmFsUi53ZWIuc2VydmljZVwiO1xuaW1wb3J0IHsgQWN0aW9uTWVzc2FnZSwgQWN0aW9uUmVzdWx0RXZlbnQsIEFjdGlvblN0YXJ0RXZlbnQsIEFjdGlvblN0b3BFdmVudCwgQ2hhdENvbnRleHRBdHRhY2htZW50LCBDaGF0TWVzc2FnZSwgQ2hhdFBheWxvYWQsIENoYXRQcm9ncmVzcywgQ2hhdFJlc3BvbnNlLCBDb250ZXh0TWVzc2FnZUV2ZW50LCBEZWJ1Z01lc3NhZ2UsIERlYnVnTWVzc2FnZUV2ZW50LCBEZWxldGVTYXZlZENoYXRSZXNwb25zZSwgRXJyb3JFdmVudCwgR2xsbUZ1bmN0aW9uLCBHbGxtTW9kZWxEZXNjcmlwdGlvbiwgSGlzdG9yeUV2ZW50LCBNZXNzYWdlRXZlbnQsIE1lc3NhZ2VIYW5kbGVyLCBRdW90YUV2ZW50LCBTYXZlZENoYXRIaXN0b3J5LCBTYXZlZENoYXRSZXNwb25zZSwgU3VnZ2VzdGVkQWN0aW9uc0V2ZW50IH0gZnJvbSBcIi4vdHlwZXNcIjtcblxuQEluamVjdGFibGUoKVxuZXhwb3J0IGNsYXNzIFdlYlNvY2tldENoYXRTZXJ2aWNlIGV4dGVuZHMgQ2hhdFNlcnZpY2Uge1xuXG4gIHB1YmxpYyBjb25uZWN0aW9uOiBIdWJDb25uZWN0aW9uIHwgdW5kZWZpbmVkO1xuXG4gIHByaXZhdGUgX21lc3NhZ2VIYW5kbGVyczogTWFwPHN0cmluZywgTWVzc2FnZUhhbmRsZXI8YW55Pj4gPSBuZXcgTWFwKCk7XG4gIHByaXZhdGUgX3Jlc3BvbnNlOiBDaGF0TWVzc2FnZVtdO1xuICBwcml2YXRlIF9hY3Rpb25NYXAgPSBuZXcgTWFwPHN0cmluZywgQWN0aW9uTWVzc2FnZT4oKTtcbiAgcHJpdmF0ZSBfcHJvZ3Jlc3M6IENoYXRQcm9ncmVzc1tdIHwgdW5kZWZpbmVkID0gdW5kZWZpbmVkO1xuICBwcml2YXRlIF9leGVjdXRpb25UaW1lOiBzdHJpbmc7XG4gIHByaXZhdGUgX2V4ZWN1dGlvblRpbWVNaWxsaXNlY29uZHM/OiBudW1iZXI7XG4gIHByaXZhdGUgX2F0dGFjaG1lbnRzOiBDaGF0Q29udGV4dEF0dGFjaG1lbnRbXSA9IFtdO1xuICBwcml2YXRlIF9kZWJ1Z01lc3NhZ2VzOiBEZWJ1Z01lc3NhZ2VbXSA9IFtdO1xuXG4gIHB1YmxpYyBzaWduYWxSU2VydmljZSA9IGluamVjdChTaWduYWxSV2ViU2VydmljZSk7XG5cbiAgY29uc3RydWN0b3IoKSB7XG4gICAgc3VwZXIoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBJbml0aWFsaXplIHRoZSBhc3Npc3RhbnQgcHJvY2Vzcy5cbiAgICogSXQgaW5jbHVkZXMgYnVpbGRpbmcgYW5kIHN0YXJ0aW5nIGEgY29ubmVjdGlvbiwgZXhlY3V0aW5nIHBhcmFsbGVsIHJlcXVlc3RzIGZvciBtb2RlbHMgYW5kIGZ1bmN0aW9ucywgYW5kIGhhbmRsaW5nIGVycm9ycyBkdXJpbmcgdGhlIHByb2Nlc3MuXG4gICAqIOKaoO+4jyBUaGlzIG1ldGhvZCBNVVNUIGJlIGNhbGxlZCBPTkxZIGlmIHRoZSB1c2VyIGlzIGxvZ2dlZEluIGFuZCBvbmNlIHdoZW4gdGhlIGFzc2lzdGFudCBpcyBpbml0aWFsaXplZC5cbiAgICpcbiAgICogQHJldHVybnMgQW4gT2JzZXJ2YWJsZTxib29sZWFuPiBpbmRpY2F0aW5nIHRoZSBzdWNjZXNzIG9mIHRoZSBpbml0aWFsaXphdGlvbiBwcm9jZXNzLlxuICAgKi9cbiAgaW5pdCgpOiBPYnNlcnZhYmxlPGJvb2xlYW4+IHtcbiAgICAvLyBFbnN1cmUgYWxsIGxvZ2ljIGlzIGV4ZWN1dGVkIHdoZW4gc3Vic2NyaWJlZCB0byB0aGUgb2JzZXJ2YWJsZVxuICAgIHJldHVybiBkZWZlcigoKSA9PiB7XG4gICAgICB0aGlzLmdldFJlcXVlc3RzVXJsKCk7XG5cbiAgICAgIHJldHVybiBmcm9tKFxuICAgICAgICAvLyBCdWlsZCB0aGUgY29ubmVjdGlvblxuICAgICAgICB0aGlzLmJ1aWxkQ29ubmVjdGlvbigpXG4gICAgICAgICkucGlwZShcbiAgICAgICAgdGFwKCgpID0+IHRoaXMuaW5pdE1lc3NhZ2VIYW5kbGVycygpKSxcbiAgICAgICAgLy8gU3RhcnQgdGhlIGNvbm5lY3Rpb25cbiAgICAgICAgc3dpdGNoTWFwKCgpID0+IHRoaXMuc3RhcnRDb25uZWN0aW9uKCkpLFxuICAgICAgICAvLyBFeGVjdXRlIHBhcmFsbGVsIHJlcXVlc3RzIGZvciBtb2RlbHMgYW5kIGZ1bmN0aW9uc1xuICAgICAgICBzd2l0Y2hNYXAoKCkgPT5cbiAgICAgICAgICBmb3JrSm9pbihbXG4gICAgICAgICAgICB0aGlzLmxpc3RNb2RlbHMoKSxcbiAgICAgICAgICAgIHRoaXMubGlzdEZ1bmN0aW9ucygpXG4gICAgICAgICAgXSlcbiAgICAgICAgKSxcbiAgICAgICAgLy8gTWFwIHRoZSByZXN1bHRzIG9mIHBhcmFsbGVsIHJlcXVlc3RzIHRvIGEgYm9vbGVhbiBpbmRpY2F0aW5nIHN1Y2Nlc3NcbiAgICAgICAgbWFwKChbbW9kZWxzLCBmdW5jdGlvbnNdKSA9PiB7XG4gICAgICAgICAgY29uc3QgcmVzdWx0ID0gISFtb2RlbHMgJiYgISFmdW5jdGlvbnM7XG4gICAgICAgICAgdGhpcy5pbml0UHJvY2VzcyQubmV4dChyZXN1bHQpO1xuICAgICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgICAgIH0pLFxuICAgICAgICAvLyBBbnkgZXJyb3JzIGR1cmluZyB0aGUgcHJvY2VzcyBhcmUgY2F1Z2h0LCBsb2dnZWQsIGFuZCByZS10aHJvd24gdG8gcHJvcGFnYXRlIHRoZSBlcnJvciBmdXJ0aGVyXG4gICAgICAgIGNhdGNoRXJyb3IoKGVycm9yKSA9PiB7XG4gICAgICAgICAgY29uc29sZS5lcnJvcignRXJyb3Igb2NjdXJyZWQ6JywgZXJyb3IpO1xuICAgICAgICAgIHJldHVybiB0aHJvd0Vycm9yKCgpID0+IGVycm9yKTtcbiAgICAgICAgfSksXG4gICAgICAgIHRha2UoMSlcbiAgICAgICk7XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogRGVmaW5lIHRoZSBhc3Npc3RhbnQgZW5kcG9pbnQgdG8gdXNlIGZvciB0aGUgd2Vic29ja2V0IHJlcXVlc3RzXG4gICAqIEl0IGNhbiBiZSBvdmVycmlkZGVuIGJ5IHRoZSBhcHAgY29uZmlnXG4gICAqL1xuICBnZXRSZXF1ZXN0c1VybCgpIHtcbiAgICBpZiAodGhpcy5hc3Npc3RhbnRDb25maWckLnZhbHVlIS5jb25uZWN0aW9uU2V0dGluZ3Mud2Vic29ja2V0RW5kcG9pbnQpIHtcbiAgICAgIHRoaXMuUkVRVUVTVF9VUkwgPSB0aGlzLmFzc2lzdGFudENvbmZpZyQudmFsdWUhLmNvbm5lY3Rpb25TZXR0aW5ncy53ZWJzb2NrZXRFbmRwb2ludDtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBUaGUgcHJvcGVydHkgJ3dlYnNvY2tldEVuZHBvaW50JyBtdXN0IGJlIHByb3ZpZGVkIHdoZW4gYXR0ZW1wdGluZyB0byB1c2UgJ1dlYlNvY2tldCcgaW4gYXNzaXN0YW50IGluc3RhbmNlYCk7XG4gICAgfVxuICB9XG5cbiAgb3ZlcnJpZGVVc2VyKCk6IHZvaWQge1xuICAgIGNvbnN0IHsgdXNlck92ZXJyaWRlQWN0aXZlLCB1c2VyT3ZlcnJpZGUgfSA9IGdsb2JhbENvbmZpZztcbiAgICBpZiAoISh1c2VyT3ZlcnJpZGVBY3RpdmUgJiYgdXNlck92ZXJyaWRlKSkge1xuICAgICAgdGhpcy51c2VyT3ZlcnJpZGUkLm5leHQoZmFsc2UpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIFByZXBhcmUgdGhlIHBheWxvYWQgdG8gc2VuZCB0byB0aGUgT3ZlcnJpZGVVc2VyIG1ldGhvZFxuICAgIGNvbnN0IGRhdGEgPSB7XG4gICAgICBpbnN0YW5jZUlkOiB0aGlzLmNoYXRJbnN0YW5jZUlkLFxuICAgICAgdXNlcjogdXNlck92ZXJyaWRlLnVzZXJuYW1lLFxuICAgICAgZG9tYWluOiB1c2VyT3ZlcnJpZGUuZG9tYWluXG4gICAgfVxuXG4gICAgLy8gSW52b2tlIHRoZSBPdmVycmlkZVVzZXIgbWV0aG9kIGFuZCBoYW5kbGUgZXJyb3JzXG4gICAgdGhpcy5jb25uZWN0aW9uIS5pbnZva2UoJ092ZXJyaWRlVXNlcicsIGRhdGEpXG4gICAgICAudGhlbigocmVzKSA9PiB0aGlzLnVzZXJPdmVycmlkZSQubmV4dCghIXJlcykpXG4gICAgICAuY2F0Y2goZXJyb3IgPT4ge1xuICAgICAgICBjb25zb2xlLmVycm9yKCdFcnJvciBpbnZva2luZyBPdmVycmlkZVVzZXI6JywgZXJyb3IpO1xuICAgICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKCk7IC8vIFJldHVybiBhIHJlc29sdmVkIHByb21pc2UgdG8gaGFuZGxlIHRoZSBlcnJvciBhbmQgcHJldmVudCB1bmhhbmRsZWQgcHJvbWlzZSByZWplY3Rpb24gd2hlbiBubyBmdXJ0aGVyIGVycm9yIGhhbmRsaW5nIGV4aXN0cyBkb3duc3RyZWFtXG4gICAgICB9KTtcbiAgfVxuXG4gIGxpc3RNb2RlbHMoKTogT2JzZXJ2YWJsZTxHbGxtTW9kZWxEZXNjcmlwdGlvbltdIHwgdW5kZWZpbmVkPiB7XG4gICAgY29uc3QgbW9kZWxzU3ViamVjdCQgPSBuZXcgU3ViamVjdDxHbGxtTW9kZWxEZXNjcmlwdGlvbltdIHwgdW5kZWZpbmVkPigpO1xuXG4gICAgdGhpcy5jb25uZWN0aW9uIS5vbignTGlzdE1vZGVscycsIChyZXMpID0+IHtcbiAgICAgIHRoaXMubW9kZWxzID0gKHJlcy5tb2RlbHMgYXMgR2xsbU1vZGVsRGVzY3JpcHRpb25bXSB8IHVuZGVmaW5lZCk/LmZpbHRlcihtb2RlbCA9PiAhIW1vZGVsLmVuYWJsZSk7XG4gICAgICBtb2RlbHNTdWJqZWN0JC5uZXh0KHRoaXMubW9kZWxzKTtcbiAgICAgIG1vZGVsc1N1YmplY3QkLmNvbXBsZXRlKClcbiAgICB9KTtcblxuICAgIC8vIFNlbmQgdGhlIHJlcXVlc3QgdG8gZ2V0IHRoZSBsaXN0IG9mIG1vZGVsc1xuICAgIHRoaXMuY29ubmVjdGlvbiEuaW52b2tlKCdMaXN0TW9kZWxzJywgeyBkZWJ1ZzogdGhpcy5hc3Npc3RhbnRDb25maWckLnZhbHVlIS5kZWZhdWx0VmFsdWVzLmRlYnVnIH0pXG4gICAgICAuY2F0Y2goZXJyb3IgPT4ge1xuICAgICAgICBjb25zb2xlLmVycm9yKCdFcnJvciBpbnZva2luZyBMaXN0TW9kZWxzOicsIGVycm9yKTtcbiAgICAgICAgbW9kZWxzU3ViamVjdCQuZXJyb3IobmV3IEVycm9yKGVycm9yKSk7XG4gICAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoKTsgLy8gUmV0dXJuIGEgcmVzb2x2ZWQgcHJvbWlzZSB0byBoYW5kbGUgdGhlIGVycm9yIGFuZCBwcmV2ZW50IHVuaGFuZGxlZCBwcm9taXNlIHJlamVjdGlvbiB3aGVuIG5vIGZ1cnRoZXIgZXJyb3IgaGFuZGxpbmcgZXhpc3RzIGRvd25zdHJlYW1cbiAgICAgIH0pXG5cbiAgICByZXR1cm4gbW9kZWxzU3ViamVjdCQuYXNPYnNlcnZhYmxlKCk7XG4gIH1cblxuICBsaXN0RnVuY3Rpb25zKCk6IE9ic2VydmFibGU8R2xsbUZ1bmN0aW9uW10gfCB1bmRlZmluZWQ+IHtcbiAgICBjb25zdCBmdW5jdGlvbnNTdWJqZWN0JCA9IG5ldyBTdWJqZWN0PEdsbG1GdW5jdGlvbltdIHwgdW5kZWZpbmVkPigpO1xuXG4gICAgdGhpcy5jb25uZWN0aW9uIS5vbignTGlzdEZ1bmN0aW9ucycsIChyZXMpID0+IHtcbiAgICAgIHRoaXMuZnVuY3Rpb25zID0gKHJlcy5mdW5jdGlvbnMgYXMgR2xsbUZ1bmN0aW9uW10gfCB1bmRlZmluZWQpPy5maWx0ZXIoZnVuYyA9PiBmdW5jLmVuYWJsZWQpO1xuICAgICAgZnVuY3Rpb25zU3ViamVjdCQubmV4dCh0aGlzLmZ1bmN0aW9ucyk7XG4gICAgICBmdW5jdGlvbnNTdWJqZWN0JC5jb21wbGV0ZSgpXG4gICAgfSk7XG5cbiAgICAvLyBTZW5kIHRoZSByZXF1ZXN0IHRvIGdldCB0aGUgbGlzdCBvZiBmdW5jdGlvbnNcbiAgICB0aGlzLmNvbm5lY3Rpb24hLmludm9rZSgnTGlzdEZ1bmN0aW9ucycsIHsgZGVidWc6IHRoaXMuYXNzaXN0YW50Q29uZmlnJC52YWx1ZSEuZGVmYXVsdFZhbHVlcy5kZWJ1ZyB9KVxuICAgICAgLmNhdGNoKGVycm9yID0+IHtcbiAgICAgICAgY29uc29sZS5lcnJvcignRXJyb3IgaW52b2tpbmcgTGlzdEZ1bmN0aW9uczonLCBlcnJvcik7XG4gICAgICAgIGZ1bmN0aW9uc1N1YmplY3QkLmVycm9yKG5ldyBFcnJvcihlcnJvcikpO1xuICAgICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKCk7IC8vIFJldHVybiBhIHJlc29sdmVkIHByb21pc2UgdG8gaGFuZGxlIHRoZSBlcnJvciBhbmQgcHJldmVudCB1bmhhbmRsZWQgcHJvbWlzZSByZWplY3Rpb24gd2hlbiBubyBmdXJ0aGVyIGVycm9yIGhhbmRsaW5nIGV4aXN0cyBkb3duc3RyZWFtXG4gICAgICB9KVxuXG4gICAgcmV0dXJuIGZ1bmN0aW9uc1N1YmplY3QkLmFzT2JzZXJ2YWJsZSgpO1xuICB9XG5cbiAgZmV0Y2gobWVzc2FnZXM6IENoYXRNZXNzYWdlW10sIHF1ZXJ5OiBRdWVyeSk6IE9ic2VydmFibGU8Q2hhdFJlc3BvbnNlPiB7XG4gICAgLy8gU3RhcnQgc3RyZWFtaW5nIGJ5IGludm9raW5nIHRoZSBDaGF0IG1ldGhvZFxuICAgIHRoaXMuc3RyZWFtaW5nJC5uZXh0KHRydWUpO1xuXG4gICAgLy8gUHJlcGFyZSB0aGUgcGF5bG9hZCB0byBzZW5kIHRvIHRoZSBDaGF0IG1ldGhvZFxuICAgIGNvbnN0IGRhdGE6IENoYXRQYXlsb2FkID0ge1xuICAgICAgaGlzdG9yeTogbWVzc2FnZXMsXG4gICAgICBmdW5jdGlvbnM6IHRoaXMuYXNzaXN0YW50Q29uZmlnJC52YWx1ZSEuZGVmYXVsdFZhbHVlcy5mdW5jdGlvbnM/LmZpbHRlcihmdW5jID0+IGZ1bmMuZW5hYmxlZCkubWFwKGZ1bmMgPT4gZnVuYy5uYW1lKSxcbiAgICAgIGRlYnVnOiB0aGlzLmFzc2lzdGFudENvbmZpZyQudmFsdWUhLmRlZmF1bHRWYWx1ZXMuZGVidWcsXG4gICAgICBzZXJ2aWNlU2V0dGluZ3M6IHtcbiAgICAgICAgc2VydmljZV9pZDogdGhpcy5hc3Npc3RhbnRDb25maWckLnZhbHVlIS5kZWZhdWx0VmFsdWVzLnNlcnZpY2VfaWQsXG4gICAgICAgIG1vZGVsX2lkOiB0aGlzLmFzc2lzdGFudENvbmZpZyQudmFsdWUhLmRlZmF1bHRWYWx1ZXMubW9kZWxfaWQsXG4gICAgICAgIHRvcF9wOiB0aGlzLmFzc2lzdGFudENvbmZpZyQudmFsdWUhLmRlZmF1bHRWYWx1ZXMudG9wX3AsXG4gICAgICAgIHRlbXBlcmF0dXJlOiB0aGlzLmFzc2lzdGFudENvbmZpZyQudmFsdWUhLmRlZmF1bHRWYWx1ZXMudGVtcGVyYXR1cmUsXG4gICAgICAgIG1heF90b2tlbnM6IHRoaXMuYXNzaXN0YW50Q29uZmlnJC52YWx1ZSEuZGVmYXVsdFZhbHVlcy5tYXhfdG9rZW5zLFxuICAgICAgICAuLi50aGlzLmFzc2lzdGFudENvbmZpZyQudmFsdWUhLmFkZGl0aW9uYWxTZXJ2aWNlU2V0dGluZ3NcbiAgICAgIH0sXG4gICAgICBhcHBRdWVyeToge1xuICAgICAgICBhcHA6IHRoaXMuYXBwU2VydmljZS5hcHBOYW1lLFxuICAgICAgICBxdWVyeVxuICAgICAgfSxcbiAgICAgIGdlbmVyaWNDaGF0RXJyb3JNZXNzYWdlOiB0aGlzLmFzc2lzdGFudENvbmZpZyQudmFsdWUhLmdsb2JhbFNldHRpbmdzLmdlbmVyaWNDaGF0RXJyb3JNZXNzYWdlID8gdGhpcy50cmFuc2xvY28udHJhbnNsYXRlKHRoaXMuYXNzaXN0YW50Q29uZmlnJC52YWx1ZSEuZ2xvYmFsU2V0dGluZ3MuZ2VuZXJpY0NoYXRFcnJvck1lc3NhZ2UpIDogXCJcIlxuICAgIH1cbiAgICBpZiAodGhpcy5hc3Npc3RhbnRDb25maWckLnZhbHVlIS5zYXZlZENoYXRTZXR0aW5ncy5lbmFibGVkKSB7XG4gICAgICBkYXRhLmluc3RhbmNlSWQgPSB0aGlzLmNoYXRJbnN0YW5jZUlkO1xuICAgICAgZGF0YS5zYXZlZENoYXRJZCA9IHRoaXMuc2F2ZWRDaGF0SWQ7XG4gICAgfVxuXG4gICAgLy8gSW5pdGlhbGl6ZSB0aGUgcmVzcG9uc2Ugd2l0aCBhbiBlbXB0eSBhc3Npc3RhbnQgbWVzc2FnZVxuICAgIHRoaXMuX3Jlc3BvbnNlID0gW3sgcm9sZTogXCJhc3Npc3RhbnRcIiwgY29udGVudDogXCJcIiwgYWRkaXRpb25hbFByb3BlcnRpZXM6IHsgZGlzcGxheTogdHJ1ZSB9IH1dIC8vIGhlcmUgZGlzcGxheTogdHJ1ZSBpcyBuZWVkZWQgaW4gb3JkZXIgdG8gYmUgYWJsZSB0byBzaG93IHRoZSBwcm9ncmVzc1xuXG4gICAgLy8gQ3JlYXRlIGEgU3ViamVjdCB0byBzaWduYWwgY29tcGxldGlvblxuICAgIGNvbnN0IGNvbXBsZXRpb24kID0gbmV3IFN1YmplY3Q8dm9pZD4oKTtcblxuICAgIC8vIENyZWF0ZSBvYnNlcnZhYmxlcyBmb3IgZWFjaCBub24tZ2xvYmFsIGhhbmRsZXIgaW4gdGhlIF9tZXNzYWdlSGFuZGxlcnMgbWFwIChkZWZhdWx0IGFuZCBldmVudHVhbCBjdXN0b20gb25lcykgb25jZSBpdCBpcyB0cmlnZ2VyZWQgYnkgdGhlIGh1YiBjb25uZWN0aW9uXG4gICAgY29uc3Qgb2JzZXJ2YWJsZXMgPSBBcnJheVxuICAgICAgLmZyb20odGhpcy5fbWVzc2FnZUhhbmRsZXJzLmVudHJpZXMoKSlcbiAgICAgIC5maWx0ZXIoKFtldmVudE5hbWUsIGV2ZW50SGFuZGxlcl0pID0+ICFldmVudEhhbmRsZXIuaXNHbG9iYWxIYW5kbGVyKVxuICAgICAgLm1hcCgoW2V2ZW50TmFtZSwgZXZlbnRIYW5kbGVyXSkgPT4gZnJvbUV2ZW50PGFueT4odGhpcy5jb25uZWN0aW9uISwgZXZlbnROYW1lKS5waXBlKFxuICAgICAgICAgIG1lcmdlTWFwKChldmVudCkgPT4ge1xuICAgICAgICAgICAgLy8gV3JhcCB0aGUgaGFuZGxlciBpbiBhIHRyeS1jYXRjaCBibG9jayB0byBwcmV2ZW50IHRoZSBlbnRpcmUgc3RyZWFtIGZyb20gZmFpbGluZyBpZiBhbiBlcnJvciBvY2N1cnMgaW4gYSBzaW5nbGUgaGFuZGxlclxuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgLy8gRXhlY3V0ZSB0aGUgaGFuZGxlciBhbmQgZW1pdCB0aGUgcmVzdWx0XG4gICAgICAgICAgICAgIC8vIE5COiBoZXJlIHdlIGNvdWxkIHVzZSBbZXZlbnRIYW5kbGVyLmhhbmRsZXIoZXZlbnQpXSB3aGljaCBiZWhpbmQgdGhlIHNjZW5lcyBtZXJnZU1hcCBpbnRlcnByZXRzIHRoaXMgYXJyYXkgYXMgYW4gb2JzZXJ2YWJsZSBzZXF1ZW5jZSB3aXRoIG9uZSBpdGVtLCB3aGljaCBpdCB0aGVuIGVtaXRzXG4gICAgICAgICAgICAgIHJldHVybiBvZihldmVudEhhbmRsZXIuaGFuZGxlcihldmVudCkpO1xuICAgICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihgRXJyb3IgaW4gZXZlbnQgaGFuZGxlciBmb3IgJHtldmVudE5hbWV9OmAsIGVycm9yKTtcbiAgICAgICAgICAgICAgLy8gVXNlIHRocm93RXJyb3IgdG8gcHJvcGFnYXRlIHRoZSBlcnJvciBkb3duc3RyZWFtXG4gICAgICAgICAgICAgIHJldHVybiB0aHJvd0Vycm9yKCgpID0+IG5ldyBFcnJvcihgRXJyb3IgaW4gZXZlbnQgaGFuZGxlciBmb3IgJHtldmVudE5hbWV9OiAke2Vycm9yfWApKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9KVxuICAgICAgICApKTtcblxuICAgIC8vIFRoZW4gbWVyZ2UgdGhlbSBpbnRvIGEgc2luZ2xlIG9ic2VydmFibGUgaW4gb3JkZXIgdG8gc2ltdWxhdGUgdGhlIHN0cmVhbWluZyBiZWhhdmlvclxuICAgIGNvbnN0IGNvbWJpbmVkJCA9IG1lcmdlKC4uLm9ic2VydmFibGVzKS5waXBlKFxuICAgICAgbWFwKCgpID0+IHtcbiAgICAgICAgLy8gRGVmaW5lICRwcm9ncmVzcyBmcm9tIHRoZSBfYWN0aW9uTWFwXG4gICAgICAgIGNvbnN0IGFjdGlvbnMgPSBBcnJheS5mcm9tKHRoaXMuX2FjdGlvbk1hcC52YWx1ZXMoKSk7XG4gICAgICAgIHRoaXMuX3Byb2dyZXNzID0gYWN0aW9ucy5sZW5ndGggPiAwXG4gICAgICAgICAgICAgICAgICAgICAgICAgID8gYWN0aW9ucy5tYXAoKGEpID0+ICh7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlOiBhLmRpc3BsYXlOYW1lID8/IFwiXCIsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRlbnQ6IGEuZGlzcGxheVZhbHVlID8/IFwiXCIsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRvbmU6IGEuZXhlY3V0aW9uVGltZSAhPT0gdW5kZWZpbmVkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aW1lOiBhLmV4ZWN1dGlvblRpbWUsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KSlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgOiB1bmRlZmluZWQ7XG5cbiAgICAgICAgLy8gQWx3YXlzIHVwZGF0ZSBPTkxZIHRoZSBmaXJzdCBhc3Npc3RhbnQgbWVzc2FnZSBvZiB0aGUgX3Jlc3BvbnNlIHdpdGggdGhlIG5ldyAkcHJvZ3Jlc3MsICRhdHRhY2htZW50IGFuZCAkZGVidWdcbiAgICAgICAgLy8gQXNzdW1pbmcgdGhhdCB0aGUgZmlyc3QgYXNzaXN0YW50IG1lc3NhZ2UgaXMgYWx3YXlzIHZpc2libGUgc2luY2UgdGhlIGh1YiBkb2VzIG5vdCBzZW5kIGhpZGRlbiBtZXNzYWdlcyBieSBkZXNpZ25cbiAgICAgICAgLy8gU28gZXZlbiBpZiB0aGUgZmlyc3QgYXNzaXN0YW50IG1lc3NhZ2UgaXMgaGlkZGVuIChkaXNwbGF5OiBmYWxzZSksIHRoZSBfcmVzcG9uc2VbMF0gd2lsbCBhbmQgc2hvdWxkIGNvbnRhaW4gOlxuICAgICAgICAvLyAgLSAkcHJvZ3Jlc3MsICRhdHRhY2htZW50IGFuZCAkZGVidWdcbiAgICAgICAgLy8gIC0gdGhlIGNvbnRlbnQgb2YgdGhlIGZpcnN0IHZpc2libGUgYXNzaXN0YW50IG1lc3NhZ2UgaW4gdGhlIHdvcmtmbG93XG4gICAgICAgIC8vIFRoaXMgaXMgbWFuZGF0b3J5IGluIG9yZGVyIHRvIG1hdGNoIHRoZSBiZWhhdmlvciBvZiBjb25zZWN1dGl2ZSBtZXNzYWdlcyBhbmQgbWFpbnRhaW4gY29uc2lzdGVuY3kgd2l0aCB0aGUgY2hhdEhpc3RvcnlcbiAgICAgICAgaWYoISF0aGlzLl9wcm9ncmVzcyB8fCB0aGlzLl9hdHRhY2htZW50cy5sZW5ndGggPiAwIHx8IHRoaXMuX2RlYnVnTWVzc2FnZXMubGVuZ3RoID4gMCkge1xuICAgICAgICAgIHRoaXMuX3Jlc3BvbnNlWzBdLmFkZGl0aW9uYWxQcm9wZXJ0aWVzLiRwcm9ncmVzcyA9IHRoaXMuX3Byb2dyZXNzO1xuICAgICAgICAgIHRoaXMuX3Jlc3BvbnNlWzBdLmFkZGl0aW9uYWxQcm9wZXJ0aWVzLiRhdHRhY2htZW50ID0gdGhpcy5fYXR0YWNobWVudHM7XG4gICAgICAgICAgdGhpcy5fcmVzcG9uc2VbMF0uYWRkaXRpb25hbFByb3BlcnRpZXMuJGRlYnVnID0gdGhpcy5fZGVidWdNZXNzYWdlcztcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFJldHVybiB0aGUgcmVzdWx0XG4gICAgICAgIHJldHVybiB7IGhpc3Rvcnk6IFsuLi5tZXNzYWdlcywgLi4udGhpcy5fcmVzcG9uc2VdLCBleGVjdXRpb25UaW1lOiB0aGlzLl9leGVjdXRpb25UaW1lLCBleGVjdXRpb25UaW1lTWlsbGlzZWNvbmRzOiB0aGlzLl9leGVjdXRpb25UaW1lTWlsbGlzZWNvbmRzIH07XG4gICAgICB9KSxcbiAgICAgIHRha2VVbnRpbChjb21wbGV0aW9uJCksIC8vIENvbXBsZXRlIHRoZSBvYnNlcnZhYmxlIHdoZW4gY29tcGxldGlvbiQgZW1pdHNcbiAgICApO1xuXG4gICAgLy8gcmV0dXJuIGEgbmV3IE9ic2VydmFibGUgdGhhdCBlbWl0cyB0aGUgcmVzdWx0IG9mIHRoZSBjb21iaW5lZCBzdHJlYW0gYW5kIGhhbmRsZXMgdGhlIGV2ZW50dWFsIGVycm9ycyBvZiB0aGUgaW52b2NhdGlvbiBvZiB0aGUgQ2hhdCBtZXRob2RcbiAgICByZXR1cm4gbmV3IE9ic2VydmFibGUob2JzZXJ2ZXIgPT4ge1xuICAgICAgLy8gU3Vic2NyaWJlIHRvIGNvbWJpbmVkIHN0cmVhbVxuICAgICAgY29tYmluZWQkLnN1YnNjcmliZSh7XG4gICAgICAgIG5leHQ6ICh2YWx1ZSkgPT4gb2JzZXJ2ZXIubmV4dCh2YWx1ZSksXG4gICAgICAgIGVycm9yOiAoZXJyKSA9PiBvYnNlcnZlci5lcnJvcihlcnIpXG4gICAgICB9KTtcblxuICAgICAgLy8gSW52b2tlIHRoZSBDaGF0IG1ldGhvZCBhbmQgaGFuZGxlIGVycm9yc1xuICAgICAgdGhpcy5jb25uZWN0aW9uIS5pbnZva2UoJ0NoYXQnLCBkYXRhKVxuICAgICAgICAudGhlbigoKSA9PiB7XG4gICAgICAgICAgLy8gSWYgYSB2YWxpZCBhc3Npc3RhbnQgbWVzc2FnZSB3aXRoIChkaXNwbGF5OiB0cnVlKSB3YXMgZm91bmQsIHVwZGF0ZSBpdFxuICAgICAgICAgIC8vIGFuZCBpdCBzaG91bGQgYWx3YXlzIHRoZSBjYXNlXG4gICAgICAgICAgY29uc3QgaW5kZXggPSB0aGlzLmZpcnN0VmlzaWJsZUFzc2lzdGFudE1lc3NhZ2VJbmRleCh0aGlzLmNoYXRIaXN0b3J5KTtcbiAgICAgICAgICBpZiAoaW5kZXggIT09IC0xKSB7XG4gICAgICAgICAgICB0aGlzLmNoYXRIaXN0b3J5IVtpbmRleF0uYWRkaXRpb25hbFByb3BlcnRpZXMuJHByb2dyZXNzID0gdGhpcy5fcHJvZ3Jlc3M7XG4gICAgICAgICAgICB0aGlzLmNoYXRIaXN0b3J5IVtpbmRleF0uYWRkaXRpb25hbFByb3BlcnRpZXMuJGF0dGFjaG1lbnQgPSB0aGlzLl9hdHRhY2htZW50cztcbiAgICAgICAgICAgIHRoaXMuY2hhdEhpc3RvcnkhW2luZGV4XS5hZGRpdGlvbmFsUHJvcGVydGllcy4kZGVidWcgPSB0aGlzLl9kZWJ1Z01lc3NhZ2VzO1xuICAgICAgICAgIH1cbiAgICAgICAgICAvLyBTYXZlL3VwZGF0ZSB0aGUgY2hhdCBpZiBzYXZlZENoYXQgZW5hYmxlZFxuICAgICAgICAgIGlmICh0aGlzLmFzc2lzdGFudENvbmZpZyQudmFsdWUhLnNhdmVkQ2hhdFNldHRpbmdzLmVuYWJsZWQgJiYgdGhpcy5jaGF0SGlzdG9yeSEuc29tZSgobXNnKSA9PiBtc2cuYWRkaXRpb25hbFByb3BlcnRpZXM/LmlzVXNlcklucHV0ID09PSB0cnVlKSkge1xuICAgICAgICAgICAgY29uc3QgYWN0aW9uID0gIXRoaXMuc2F2ZWRDaGF0SWQgPyB0aGlzLmFkZFNhdmVkQ2hhdCh0aGlzLmNoYXRIaXN0b3J5ISkucGlwZSh0YXAoKCkgPT4gdGhpcy5saXN0U2F2ZWRDaGF0KCkpKSA6IHRoaXMudXBkYXRlU2F2ZWRDaGF0KHRoaXMuc2F2ZWRDaGF0SWQsIHVuZGVmaW5lZCwgdGhpcy5jaGF0SGlzdG9yeSk7XG4gICAgICAgICAgICBhY3Rpb24ucGlwZSh0YWtlKDEpKS5zdWJzY3JpYmUoe1xuICAgICAgICAgICAgICBuZXh0OiAoKSA9PiB7fSxcbiAgICAgICAgICAgICAgZXJyb3I6IChlcnJvcikgPT4ge1xuICAgICAgICAgICAgICAgIHRoaXMuc3RyZWFtaW5nJC5uZXh0KGZhbHNlKTtcbiAgICAgICAgICAgICAgICBvYnNlcnZlci5lcnJvcihlcnJvcik7XG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgIGNvbXBsZXRlOiAoKSA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy5zdHJlYW1pbmckLm5leHQoZmFsc2UpO1xuICAgICAgICAgICAgICAgIG9ic2VydmVyLmNvbXBsZXRlKCk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLnN0cmVhbWluZyQubmV4dChmYWxzZSk7XG4gICAgICAgICAgICBvYnNlcnZlci5jb21wbGV0ZSgpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSlcbiAgICAgICAgLmNhdGNoKGVycm9yID0+IHtcbiAgICAgICAgICBjb25zb2xlLmVycm9yKCdFcnJvciBpbnZva2luZyBDaGF0OicsIGVycm9yKTtcbiAgICAgICAgICB0aGlzLnN0cmVhbWluZyQubmV4dChmYWxzZSk7XG4gICAgICAgICAgLy8gRW1pdCB0aGUgZXJyb3IgdG8gdGhlIG5ld2x5IGNyZWF0ZWQgb2JzZXJ2YWJsZVxuICAgICAgICAgIG9ic2VydmVyLmVycm9yKGVycm9yKTtcbiAgICAgICAgICAvLyBSZXR1cm4gYSByZXNvbHZlZCBwcm9taXNlIHRvIGhhbmRsZSB0aGUgZXJyb3IgYW5kIHByZXZlbnQgdW5oYW5kbGVkIHByb21pc2UgcmVqZWN0aW9uXG4gICAgICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpO1xuICAgICAgICB9KVxuICAgICAgICAuZmluYWxseSgoKSA9PiB7XG4gICAgICAgICAgLy8gVGhpcyBibG9jayBjb25jZXJucyBPTkxZIHRoZSBjb21wbGV0aW9uIG9mIHRoZSBcIkNoYXRcIiBtZXRob2QgaW52b2NhdGlvbi5cbiAgICAgICAgICAvLyBUaGlzIG1lYW5zIHRoZSBjb21wbGV0aW9uIG9mIHRoZSBjb21iaW5lZCQgc3RyZWFtLlxuICAgICAgICAgIC8vIEl0IGRvZXMgbm90IHRha2UgaW50byBhY2NvdW50IHRoZSBjb21wbGV0aW9uIG9mIHRoZSBlbnRpcmUgZmV0Y2ggbWV0aG9kICh0aGUgb2JzZXJ2YWJsZSByZXR1cm5lZCBieSBmZXRjaCkgYW5kIHdoaWNoIGRlcGVuZHMgb24gdGhlIGNvbXBsZXRpb24gb2YgdGhlIHNhdmUgY2hhdCBhY3Rpb24gaWYgZW5hYmxlZFxuICAgICAgICAgIHRoaXMuX3Jlc3BvbnNlID0gW107IC8vIENsZWFyIHRoZSBfcmVzcG9uc2VcbiAgICAgICAgICB0aGlzLl9hY3Rpb25NYXAuY2xlYXIoKTsgLy8gQ2xlYXIgdGhlIF9hY3Rpb25NYXBcbiAgICAgICAgICB0aGlzLl9wcm9ncmVzcyA9IHVuZGVmaW5lZDsgLy8gQ2xlYXIgdGhlIF9wcm9ncmVzc1xuICAgICAgICAgIHRoaXMuX2F0dGFjaG1lbnRzID0gW107IC8vIENsZWFyIHRoZSBfYXR0YWNobWVudHNcbiAgICAgICAgICB0aGlzLl9kZWJ1Z01lc3NhZ2VzID0gW107IC8vIENsZWFyIHRoZSBfZGVidWdNZXNzYWdlc1xuICAgICAgICAgIHRoaXMuX2V4ZWN1dGlvblRpbWUgPSBcIlwiOyAvLyBDbGVhciB0aGUgX2V4ZWN1dGlvblRpbWVcbiAgICAgICAgICB0aGlzLl9leGVjdXRpb25UaW1lTWlsbGlzZWNvbmRzID0gdW5kZWZpbmVkOyAvLyBDbGVhciB0aGUgX2V4ZWN1dGlvblRpbWVNaWxsaXNlY29uZHNcbiAgICAgICAgICBjb21wbGV0aW9uJC5uZXh0KCk7IC8vIEVtaXQgYSBzaWduYWwgdG8gY29tcGxldGUgdGhlIG9ic2VydmFibGVzXG4gICAgICAgICAgY29tcGxldGlvbiQuY29tcGxldGUoKTsgLy8gQ29tcGxldGUgdGhlIHN1YmplY3RcbiAgICAgICAgfSk7XG4gICAgfSk7XG4gIH1cblxuICBzdG9wR2VuZXJhdGlvbigpOiBPYnNlcnZhYmxlPGJvb2xlYW4+IHtcbiAgICAvLyBTdGFydCBzdG9wcGluZyBnZW5lcmF0aW9uIGJ5IGludm9raW5nIHRoZSBDYW5jZWxUYXNrcyBtZXRob2RcbiAgICB0aGlzLnN0b3BwaW5nR2VuZXJhdGlvbiQubmV4dCh0cnVlKTtcbiAgICAvLyBDcmVhdGUgYSBTdWJqZWN0IHRvIGhvbGQgdGhlIHJlc3VsdCBvZiB0aGUgQ2FuY2VsVGFza3MgbWV0aG9kXG4gICAgY29uc3Qgc3RvcEdlbmVyYXRpb25TdWJqZWN0JCA9IG5ldyBTdWJqZWN0PGJvb2xlYW4+KCk7XG5cbiAgICB0aGlzLmNvbm5lY3Rpb24hLm9uKCdDYW5jZWxUYXNrcycsIChyZXMpID0+IHtcbiAgICAgIC8vIFdoZW4gdGhlIGdlbmVyYXRpb24gaXMgc3RvcHBlZCBiZWZvcmUgc3RyZWFtaW5nIGFueSBWSVNJQkxFIGFzc2lzdGFudCBtZXNzYWdlLCB0aGlzIG1lYW5zIHRoYXQgJHByb2dyZXNzLCAkYXR0YWNobWVudCBhbmQgJGRlYnVnIHByb3BlcnRpZXMgd2lsbCBiZSBsb3N0LlxuICAgICAgLy8gSG93ZXZlciwgdGhlIFwiQ29udGV4dE1lc3NhZ2VcIiBmcmFtZXMgd2lsbCBiZSBwZXJzaXN0ZWQgaW4gdGhlIGNoYXRIaXN0b3J5IGFuZCB0aGUgYXNzaXN0YW50IG1heSByZWZlcmVuY2UgdGhlbSBpbiB0aGUgbmV4dCBnZW5lcmF0aW9uLlxuICAgICAgLy8gVGhpcyBsZWFkcyB0byB0aGUgcHJvYmxlbSBvZiByZWZlcmVuY2luZyB1bmRpc3BsYXllZCBhdHRhY2htZW50cyBpbiB0aGUgbmV4dCBnZW5lcmF0aW9uLlxuICAgICAgLy8gVG8gc29sdmUgdGhpcyBwcm9ibGVtLCB3ZSBuZWVkIHRvIHBlcnNpc3QgJHByb2dyZXNzLCAkYXR0YWNobWVudCBhbmQgJGRlYnVnIHByb3BlcnRpZXMgYnkgYWRkaW5nIGEgbmV3IGFzc2lzdGFudCBtZXNzYWdlIHdpdGggZW1wdHkgY29udGVudCBhbmQgdGhlc2UgcHJvcGVydGllcy5cbiAgICAgIGlmICh0aGlzLl9yZXNwb25zZS5sZW5ndGggPT09IDEgJiYgdGhpcy5fcmVzcG9uc2VbMF0uY29udGVudCA9PT0gXCJcIikge1xuICAgICAgICB0aGlzLmNoYXRIaXN0b3J5Py5wdXNoKHtyb2xlOiBcImFzc2lzdGFudFwiLCBjb250ZW50OiBcIlwiLCBhZGRpdGlvbmFsUHJvcGVydGllczoge2Rpc3BsYXk6IHRydWUsICRwcm9ncmVzczogdGhpcy5fcHJvZ3Jlc3MsICRhdHRhY2htZW50OiB0aGlzLl9hdHRhY2htZW50cywgJGRlYnVnOiB0aGlzLl9kZWJ1Z01lc3NhZ2VzfX0pO1xuICAgICAgfVxuICAgICAgc3RvcEdlbmVyYXRpb25TdWJqZWN0JC5uZXh0KCEhcmVzKTsgLy8gRW1pdCB0aGUgcmVzdWx0IG9mIHRoZSBDYW5jZWxUYXNrcyBtZXRob2RcbiAgICAgIHN0b3BHZW5lcmF0aW9uU3ViamVjdCQuY29tcGxldGUoKTsgLy8gQ29tcGxldGUgdGhlIHN1YmplY3RcbiAgICAgIHRoaXMuc3RvcHBpbmdHZW5lcmF0aW9uJC5uZXh0KGZhbHNlKTsgLy8gQ29tcGxldGUgc3RvcHBpbmcgZ2VuZXJhdGlvblxuICAgIH0pO1xuXG4gICAgLy8gSW52b2tlIHRoZSBDYW5jZWxUYXNrcyBtZXRob2QgYW5kIGhhbmRsZSBlcnJvcnNcbiAgICB0aGlzLmNvbm5lY3Rpb24hLmludm9rZSgnQ2FuY2VsVGFza3MnKVxuICAgICAgLmNhdGNoKGVycm9yID0+IHtcbiAgICAgICAgY29uc29sZS5lcnJvcignRXJyb3IgaW52b2tpbmcgQ2FuY2VsVGFza3M6JywgZXJyb3IpO1xuICAgICAgICBzdG9wR2VuZXJhdGlvblN1YmplY3QkLmVycm9yKG5ldyBFcnJvcihlcnJvcikpO1xuICAgICAgICB0aGlzLnN0b3BwaW5nR2VuZXJhdGlvbiQubmV4dChmYWxzZSk7IC8vIENvbXBsZXRlIHN0b3BwaW5nIGdlbmVyYXRpb25cbiAgICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpOyAvLyBSZXR1cm4gYSByZXNvbHZlZCBwcm9taXNlIHRvIGhhbmRsZSB0aGUgZXJyb3IgYW5kIHByZXZlbnQgdW5oYW5kbGVkIHByb21pc2UgcmVqZWN0aW9uIHdoZW4gbm8gZnVydGhlciBlcnJvciBoYW5kbGluZyBleGlzdHMgZG93bnN0cmVhbVxuICAgICAgfSk7XG5cbiAgICByZXR1cm4gc3RvcEdlbmVyYXRpb25TdWJqZWN0JC5hc09ic2VydmFibGUoKTtcbiAgfVxuXG4gIGxpc3RTYXZlZENoYXQoKTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLmFzc2lzdGFudENvbmZpZyQudmFsdWUhLnNhdmVkQ2hhdFNldHRpbmdzLmVuYWJsZWQpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCBkYXRhID0ge1xuICAgICAgYXBwTmFtZTogdGhpcy5hcHBTZXJ2aWNlLmFwcE5hbWUsXG4gICAgICBpbnN0YW5jZUlkOiB0aGlzLmNoYXRJbnN0YW5jZUlkLFxuICAgICAgZGVidWc6IHRoaXMuYXNzaXN0YW50Q29uZmlnJC52YWx1ZSEuZGVmYXVsdFZhbHVlcy5kZWJ1Z1xuICAgIH07XG5cbiAgICB0aGlzLmNvbm5lY3Rpb24hLm9uKCdTYXZlZENoYXRMaXN0JywgKHJlcykgPT4ge1xuICAgICAgdGhpcy5zYXZlZENoYXRzJC5uZXh0KHJlcy5zYXZlZENoYXRzKTsgLy8gZW1pdHMgdGhlIHJlc3VsdCB0byB0aGUgc2F2ZWRDaGF0cyQgc3ViamVjdFxuICAgICAgdGhpcy5zYXZlZENoYXRzRXJyb3IkLm5leHQoZmFsc2UpO1xuICAgIH0pO1xuXG4gICAgLy8gSW52b2tlIHRoZSBtZXRob2QgU2F2ZWRDaGF0TGlzdFxuICAgIHRoaXMuY29ubmVjdGlvbiEuaW52b2tlKCdTYXZlZENoYXRMaXN0JywgZGF0YSlcbiAgICAgIC5jYXRjaChlcnJvciA9PiB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoJ0Vycm9yIGludm9raW5nIFNhdmVkQ2hhdExpc3Q6JywgZXJyb3IpO1xuICAgICAgICB0aGlzLnNhdmVkQ2hhdHNFcnJvciQubmV4dCh0cnVlKTtcbiAgICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpO1xuICAgICAgfSk7XG4gIH1cblxuICBnZXRTYXZlZENoYXQoaWQ6IHN0cmluZyk6IE9ic2VydmFibGU8U2F2ZWRDaGF0SGlzdG9yeSB8IHVuZGVmaW5lZD4ge1xuICAgIGNvbnN0IHNhdmVkQ2hhdFN1YmplY3QkID0gbmV3IFN1YmplY3Q8U2F2ZWRDaGF0SGlzdG9yeSB8IHVuZGVmaW5lZD4oKTtcblxuICAgIGNvbnN0IGRhdGEgPSB7XG4gICAgICBhcHBOYW1lOiB0aGlzLmFwcFNlcnZpY2UuYXBwTmFtZSxcbiAgICAgIGluc3RhbmNlSWQ6IHRoaXMuY2hhdEluc3RhbmNlSWQsXG4gICAgICBzYXZlZENoYXRJZDogaWQsXG4gICAgICBkZWJ1ZzogdGhpcy5hc3Npc3RhbnRDb25maWckLnZhbHVlIS5kZWZhdWx0VmFsdWVzLmRlYnVnXG4gICAgfTtcblxuICAgIHRoaXMuY29ubmVjdGlvbiEub24oJ1NhdmVkQ2hhdEdldCcsIChyZXMpID0+IHtcbiAgICAgIHRoaXMuZ2VuZXJhdGVBdWRpdEV2ZW50KCdhc3Qtc2F2ZWQtY2hhdC5sb2FkJywgeyBkdXJhdGlvbjogcmVzLmV4ZWN1dGlvblRpbWVNaWxsaXNlY29uZHMgfSwgcmVzLnNhdmVkQ2hhdC5pZClcbiAgICAgIHNhdmVkQ2hhdFN1YmplY3QkLm5leHQocmVzLnNhdmVkQ2hhdCk7XG4gICAgICBzYXZlZENoYXRTdWJqZWN0JC5jb21wbGV0ZSgpXG4gICAgfSk7XG5cbiAgICAvLyBJbnZva2UgdGhlIG1ldGhvZCBTYXZlZENoYXRHZXRcbiAgICB0aGlzLmNvbm5lY3Rpb24hLmludm9rZSgnU2F2ZWRDaGF0R2V0JywgZGF0YSlcbiAgICAgIC5jYXRjaChlcnJvciA9PiB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoJ0Vycm9yIGludm9raW5nIFNhdmVkQ2hhdEdldDonLCBlcnJvcik7XG4gICAgICAgIHNhdmVkQ2hhdFN1YmplY3QkLmVycm9yKG5ldyBFcnJvcihlcnJvcikpO1xuICAgICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKCk7IC8vIFJldHVybiBhIHJlc29sdmVkIHByb21pc2UgdG8gaGFuZGxlIHRoZSBlcnJvciBhbmQgcHJldmVudCB1bmhhbmRsZWQgcHJvbWlzZSByZWplY3Rpb24gd2hlbiBubyBmdXJ0aGVyIGVycm9yIGhhbmRsaW5nIGV4aXN0cyBkb3duc3RyZWFtXG4gICAgICB9KVxuXG4gICAgcmV0dXJuIHNhdmVkQ2hhdFN1YmplY3QkLmFzT2JzZXJ2YWJsZSgpO1xuICB9XG5cbiAgYWRkU2F2ZWRDaGF0KG1lc3NhZ2VzOiBDaGF0TWVzc2FnZVtdKTogT2JzZXJ2YWJsZTxTYXZlZENoYXRSZXNwb25zZT4ge1xuICAgIGNvbnN0IGFkZFNhdmVkQ2hhdFN1YmplY3QkID0gbmV3IFN1YmplY3Q8U2F2ZWRDaGF0UmVzcG9uc2U+KCk7XG5cbiAgICBjb25zdCBkYXRhID0ge1xuICAgICAgYXBwTmFtZTogdGhpcy5hcHBTZXJ2aWNlLmFwcE5hbWUsXG4gICAgICBpbnN0YW5jZUlkOiB0aGlzLmNoYXRJbnN0YW5jZUlkLFxuICAgICAgc2F2ZWRDaGF0SWQ6IHRoaXMuY2hhdElkLFxuICAgICAgaGlzdG9yeTogbWVzc2FnZXMsXG4gICAgICBkZWJ1ZzogdGhpcy5hc3Npc3RhbnRDb25maWckLnZhbHVlIS5kZWZhdWx0VmFsdWVzLmRlYnVnXG4gICAgfTtcblxuICAgIHRoaXMuY29ubmVjdGlvbiEub24oJ1NhdmVkQ2hhdEFkZCcsIChyZXMpID0+IHtcbiAgICAgIHRoaXMuc2V0U2F2ZWRDaGF0SWQocmVzLnNhdmVkQ2hhdC5pZCk7IC8vIFBlcnNpc3QgdGhlIHNhdmVkQ2hhdElkXG4gICAgICB0aGlzLmdlbmVyYXRlQXVkaXRFdmVudCgnYXN0LXNhdmVkLWNoYXQuYWRkJywgeyBkdXJhdGlvbjogcmVzLmV4ZWN1dGlvblRpbWVNaWxsaXNlY29uZHMgfSwgcmVzLnNhdmVkQ2hhdC5pZCk7IC8vIEdlbmVyYXRlIGF1ZGl0IGV2ZW50XG4gICAgICBhZGRTYXZlZENoYXRTdWJqZWN0JC5uZXh0KHJlcyk7XG4gICAgICBhZGRTYXZlZENoYXRTdWJqZWN0JC5jb21wbGV0ZSgpXG4gICAgfSk7XG5cbiAgICAvLyBJbnZva2UgdGhlIG1ldGhvZCBTYXZlZENoYXRBZGRcbiAgICB0aGlzLmNvbm5lY3Rpb24hLmludm9rZSgnU2F2ZWRDaGF0QWRkJywgZGF0YSlcbiAgICAgIC5jYXRjaChlcnJvciA9PiB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoJ0Vycm9yIGludm9raW5nIFNhdmVkQ2hhdEFkZDonLCBlcnJvcik7XG4gICAgICAgIGFkZFNhdmVkQ2hhdFN1YmplY3QkLmVycm9yKG5ldyBFcnJvcihlcnJvcikpO1xuICAgICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKCk7IC8vIFJldHVybiBhIHJlc29sdmVkIHByb21pc2UgdG8gaGFuZGxlIHRoZSBlcnJvciBhbmQgcHJldmVudCB1bmhhbmRsZWQgcHJvbWlzZSByZWplY3Rpb24gd2hlbiBubyBmdXJ0aGVyIGVycm9yIGhhbmRsaW5nIGV4aXN0cyBkb3duc3RyZWFtXG4gICAgICB9KVxuXG4gICAgcmV0dXJuIGFkZFNhdmVkQ2hhdFN1YmplY3QkLmFzT2JzZXJ2YWJsZSgpO1xuICB9XG5cbiAgdXBkYXRlU2F2ZWRDaGF0KGlkOiBzdHJpbmcsIG5hbWU/OiBzdHJpbmcsIG1lc3NhZ2VzPzogQ2hhdE1lc3NhZ2VbXSk6IE9ic2VydmFibGU8U2F2ZWRDaGF0UmVzcG9uc2U+IHtcbiAgICBjb25zdCB1cGRhdGVTYXZlZENoYXRTdWJqZWN0JCA9IG5ldyBTdWJqZWN0PFNhdmVkQ2hhdFJlc3BvbnNlPigpO1xuXG4gICAgY29uc3QgZGF0YSA9IHtcbiAgICAgIGFwcE5hbWU6IHRoaXMuYXBwU2VydmljZS5hcHBOYW1lLFxuICAgICAgaW5zdGFuY2VJZDogdGhpcy5jaGF0SW5zdGFuY2VJZCxcbiAgICAgIHNhdmVkQ2hhdElkOiBpZCxcbiAgICAgIGRlYnVnOiB0aGlzLmFzc2lzdGFudENvbmZpZyQudmFsdWUhLmRlZmF1bHRWYWx1ZXMuZGVidWdcbiAgICB9O1xuXG4gICAgaWYobmFtZSkgZGF0YVtcInRpdGxlXCJdID0gbmFtZTtcbiAgICBpZihtZXNzYWdlcykgZGF0YVtcImhpc3RvcnlcIl0gPSBtZXNzYWdlcztcblxuICAgIHRoaXMuY29ubmVjdGlvbiEub24oJ1NhdmVkQ2hhdFVwZGF0ZScsIChyZXMpID0+IHtcbiAgICAgIHVwZGF0ZVNhdmVkQ2hhdFN1YmplY3QkLm5leHQocmVzKTtcbiAgICAgIHVwZGF0ZVNhdmVkQ2hhdFN1YmplY3QkLmNvbXBsZXRlKClcbiAgICB9KTtcblxuICAgIC8vIEludm9rZSB0aGUgbWV0aG9kIFNhdmVkQ2hhdFVwZGF0ZVxuICAgIHRoaXMuY29ubmVjdGlvbiEuaW52b2tlKCdTYXZlZENoYXRVcGRhdGUnLCBkYXRhKVxuICAgICAgLmNhdGNoKGVycm9yID0+IHtcbiAgICAgICAgY29uc29sZS5lcnJvcignRXJyb3IgaW52b2tpbmcgU2F2ZWRDaGF0VXBkYXRlOicsIGVycm9yKTtcbiAgICAgICAgdXBkYXRlU2F2ZWRDaGF0U3ViamVjdCQuZXJyb3IobmV3IEVycm9yKGVycm9yKSk7XG4gICAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoKTsgLy8gUmV0dXJuIGEgcmVzb2x2ZWQgcHJvbWlzZSB0byBoYW5kbGUgdGhlIGVycm9yIGFuZCBwcmV2ZW50IHVuaGFuZGxlZCBwcm9taXNlIHJlamVjdGlvbiB3aGVuIG5vIGZ1cnRoZXIgZXJyb3IgaGFuZGxpbmcgZXhpc3RzIGRvd25zdHJlYW1cbiAgICAgIH0pXG5cbiAgICByZXR1cm4gdXBkYXRlU2F2ZWRDaGF0U3ViamVjdCQuYXNPYnNlcnZhYmxlKCk7XG4gIH1cblxuICBkZWxldGVTYXZlZENoYXQoaWRzOiBzdHJpbmdbXSk6IE9ic2VydmFibGU8RGVsZXRlU2F2ZWRDaGF0UmVzcG9uc2U+IHtcbiAgICBjb25zdCBkZWxldGVTYXZlZENoYXRTdWJqZWN0JCA9IG5ldyBTdWJqZWN0PERlbGV0ZVNhdmVkQ2hhdFJlc3BvbnNlPigpO1xuXG4gICAgY29uc3QgZGF0YSA9IHtcbiAgICAgIGFwcE5hbWU6IHRoaXMuYXBwU2VydmljZS5hcHBOYW1lLFxuICAgICAgaW5zdGFuY2VJZDogdGhpcy5jaGF0SW5zdGFuY2VJZCxcbiAgICAgIFNhdmVkQ2hhdElkczogaWRzLFxuICAgICAgZGVidWc6IHRoaXMuYXNzaXN0YW50Q29uZmlnJC52YWx1ZSEuZGVmYXVsdFZhbHVlcy5kZWJ1Z1xuICAgIH07XG5cbiAgICB0aGlzLmNvbm5lY3Rpb24hLm9uKCdTYXZlZENoYXREZWxldGUnLCAocmVzKSA9PiB7XG4gICAgICBkZWxldGVTYXZlZENoYXRTdWJqZWN0JC5uZXh0KHJlcyk7XG4gICAgICBkZWxldGVTYXZlZENoYXRTdWJqZWN0JC5jb21wbGV0ZSgpO1xuICAgIH0pO1xuXG4gICAgLy8gSW52b2tlIHRoZSBtZXRob2QgU2F2ZWRDaGF0RGVsZXRlXG4gICAgdGhpcy5jb25uZWN0aW9uIS5pbnZva2UoJ1NhdmVkQ2hhdERlbGV0ZScsIGRhdGEpXG4gICAgICAuY2F0Y2goZXJyb3IgPT4ge1xuICAgICAgICBjb25zb2xlLmVycm9yKCdFcnJvciBpbnZva2luZyBTYXZlZENoYXREZWxldGU6JywgZXJyb3IpO1xuICAgICAgICBkZWxldGVTYXZlZENoYXRTdWJqZWN0JC5lcnJvcihuZXcgRXJyb3IoZXJyb3IpKTtcbiAgICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpOyAvLyBSZXR1cm4gYSByZXNvbHZlZCBwcm9taXNlIHRvIGhhbmRsZSB0aGUgZXJyb3IgYW5kIHByZXZlbnQgdW5oYW5kbGVkIHByb21pc2UgcmVqZWN0aW9uIHdoZW4gbm8gZnVydGhlciBlcnJvciBoYW5kbGluZyBleGlzdHMgZG93bnN0cmVhbVxuICAgICAgfSlcblxuICAgIHJldHVybiBkZWxldGVTYXZlZENoYXRTdWJqZWN0JC5hc09ic2VydmFibGUoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBJbml0aWFsaXplIG91dC1vZi10aGUtYm94IGhhbmRsZXJzXG4gICAqIEl0IGlzIGEgcGxhY2Vob2xkZXIgZm9yIG5vbi1zdHJlYW1pbmcgc2NlbmFyaW9zLCB3aGVyZSB5b3UgaW52b2tlIGEgc3BlY2lmaWMgaHViIG1ldGhvZCwgYW5kIHRoZSBzZXJ2ZXIgcmVzcG9uZHMgd2l0aCBmcmFtZSBtZXNzYWdlKHMpXG4gICAqL1xuICBpbml0TWVzc2FnZUhhbmRsZXJzKCkge1xuICAgIHRoaXMuYWRkTWVzc2FnZUhhbmRsZXIoXG4gICAgICBcIkVycm9yXCIsXG4gICAgICB7XG4gICAgICAgIGhhbmRsZXI6IChlcnJvcjogRXJyb3JFdmVudCkgPT4ge1xuICAgICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyb3IpO1xuICAgICAgICAgIHRoaXMubm90aWZpY2F0aW9uc1NlcnZpY2UuZXJyb3IoZXJyb3IpO1xuICAgICAgICB9LFxuICAgICAgICBpc0dsb2JhbEhhbmRsZXI6IHRydWVcbiAgICAgIH1cbiAgICApO1xuICAgIHRoaXMuYWRkTWVzc2FnZUhhbmRsZXIoXG4gICAgICBcIlF1b3RhXCIsXG4gICAgICB7XG4gICAgICAgIGhhbmRsZXI6IChtZXNzYWdlOiBRdW90YUV2ZW50KSA9PiB7XG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIHRoaXMudXBkYXRlUXVvdGEobWVzc2FnZS5xdW90YSlcbiAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgICAgY29uc29sZS5lcnJvcihlcnJvcik7XG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICBpc0dsb2JhbEhhbmRsZXI6IHRydWVcbiAgICAgIH1cbiAgICApO1xuICAgIHRoaXMuYWRkTWVzc2FnZUhhbmRsZXIoXG4gICAgICBcIkRlYnVnXCIsXG4gICAgICB7IGhhbmRsZXI6ICgpID0+IHt9LFxuICAgICAgICBpc0dsb2JhbEhhbmRsZXI6IHRydWVcbiAgICAgIH1cbiAgICApO1xuICAgIHRoaXMuYWRkTWVzc2FnZUhhbmRsZXIoXG4gICAgICBcIkFjdGlvblN0YXJ0XCIsXG4gICAgICB7IGhhbmRsZXI6IChhY3Rpb246IEFjdGlvblN0YXJ0RXZlbnQpID0+IHRoaXMuX2FjdGlvbk1hcC5zZXQoYWN0aW9uLmd1aWQsIGFjdGlvbiksXG4gICAgICAgIGlzR2xvYmFsSGFuZGxlcjogZmFsc2VcbiAgICAgIH1cbiAgICApO1xuICAgIHRoaXMuYWRkTWVzc2FnZUhhbmRsZXIoXG4gICAgICBcIkFjdGlvblJlc3VsdFwiLFxuICAgICAge1xuICAgICAgICBoYW5kbGVyOiAoYWN0aW9uOiBBY3Rpb25SZXN1bHRFdmVudCkgPT4gdGhpcy5fYWN0aW9uTWFwLnNldChhY3Rpb24uZ3VpZCwgeyAuLi50aGlzLl9hY3Rpb25NYXAuZ2V0KGFjdGlvbi5ndWlkKSwgLi4uYWN0aW9uIH0pLFxuICAgICAgICBpc0dsb2JhbEhhbmRsZXI6IGZhbHNlXG4gICAgICB9XG4gICAgKTtcbiAgICB0aGlzLmFkZE1lc3NhZ2VIYW5kbGVyKFxuICAgICAgXCJBY3Rpb25TdG9wXCIsXG4gICAgICB7XG4gICAgICAgIGhhbmRsZXI6IChhY3Rpb246IEFjdGlvblN0b3BFdmVudCkgPT4gdGhpcy5fYWN0aW9uTWFwLnNldChhY3Rpb24uZ3VpZCwgeyAuLi50aGlzLl9hY3Rpb25NYXAuZ2V0KGFjdGlvbi5ndWlkKSwgLi4uYWN0aW9uIH0pLFxuICAgICAgICBpc0dsb2JhbEhhbmRsZXI6IGZhbHNlXG4gICAgICB9XG4gICAgKTtcbiAgICB0aGlzLmFkZE1lc3NhZ2VIYW5kbGVyKFxuICAgICAgXCJDb250ZXh0TWVzc2FnZVwiLFxuICAgICAge1xuICAgICAgICBoYW5kbGVyOiAobWVzc2FnZTogQ29udGV4dE1lc3NhZ2VFdmVudCkgPT4ge1xuICAgICAgICAgIHRoaXMuX2F0dGFjaG1lbnRzLnB1c2gobWVzc2FnZS5hZGRpdGlvbmFsUHJvcGVydGllcyk7XG4gICAgICAgIH0sXG4gICAgICAgIGlzR2xvYmFsSGFuZGxlcjogZmFsc2VcbiAgICAgIH1cbiAgICApO1xuICAgIHRoaXMuYWRkTWVzc2FnZUhhbmRsZXIoXG4gICAgICBcIk1lc3NhZ2VcIixcbiAgICAgIHtcbiAgICAgICAgaGFuZGxlcjogKG1lc3NhZ2U6IE1lc3NhZ2VFdmVudCkgPT4gdGhpcy5fcmVzcG9uc2UuYXQoLTEpIS5jb250ZW50ICs9IG1lc3NhZ2UuZGVsdGEgPz8gXCJcIixcbiAgICAgICAgaXNHbG9iYWxIYW5kbGVyOiBmYWxzZVxuICAgICAgfVxuICAgICk7XG4gICAgdGhpcy5hZGRNZXNzYWdlSGFuZGxlcihcbiAgICAgIFwiSGlzdG9yeVwiLFxuICAgICAge1xuICAgICAgICBoYW5kbGVyOiAoaGlzdG9yeTogSGlzdG9yeUV2ZW50KSA9PiB7XG4gICAgICAgICAgLy8gVGhlIENoYXRIaXN0b3J5IGlzIHVwZGF0ZWQ6IGl0IGlzIHRoZSBjdXJyZW50IGNvcHkgY29uY2F0ZW5hdGVkIHdpdGggdGhlIG5ldyBpdGVtcyBPTkxZIChpdCBjYW4gaGF2ZSBtdWx0aXBsZSBtZXNzYWdlczogdGhlIGNvbnRleHQgbWVzc2FnZXMgKyB0aGUgcmVzcG9uc2UgbWVzc2FnZSlcbiAgICAgICAgICAvLyBUaGlzIGlzIG1hbmRhdG9yeSB0byBub3QgbG9zZSB0aGUgcHJldmlvdXMgdXBkYXRlcyBvZiB0aGUgY2hhdEhpc3Rvcnkgd2hlbiB0aGUgYXNzaXN0YW50IGlzIHN0cmVhbWluZyBtdWx0aXBsZSBtZXNzYWdlIHN0ZXBzXG4gICAgICAgICAgdGhpcy5jaGF0SGlzdG9yeSA9IFsuLi50aGlzLmNoYXRIaXN0b3J5ISwgLi4uKGhpc3RvcnkuaGlzdG9yeS5zbGljZSh0aGlzLmNoYXRIaXN0b3J5IS5sZW5ndGgpKV07XG4gICAgICAgICAgLy8gRW1pdCB0aGUgdXBkYXRlZCBjaGF0IHVzYWdlIG1ldHJpY3NcbiAgICAgICAgICBpZiAoISF0aGlzLmNoYXRIaXN0b3J5LmF0KC0xKT8uYWRkaXRpb25hbFByb3BlcnRpZXMudXNhZ2VNZXRyaWNzKSB7XG4gICAgICAgICAgICB0aGlzLnVwZGF0ZUNoYXRVc2FnZU1ldHJpY3ModGhpcy5jaGF0SGlzdG9yeS5hdCgtMSkhLmFkZGl0aW9uYWxQcm9wZXJ0aWVzLnVzYWdlTWV0cmljcyEpO1xuICAgICAgICAgIH1cbiAgICAgICAgICB0aGlzLl9leGVjdXRpb25UaW1lID0gaGlzdG9yeS5leGVjdXRpb25UaW1lO1xuICAgICAgICAgIHRoaXMuX2V4ZWN1dGlvblRpbWVNaWxsaXNlY29uZHMgPSBoaXN0b3J5LmV4ZWN1dGlvblRpbWVNaWxsaXNlY29uZHM7XG4gICAgICAgIH0sXG4gICAgICAgIGlzR2xvYmFsSGFuZGxlcjogZmFsc2VcbiAgICAgIH1cbiAgICApO1xuICAgIHRoaXMuYWRkTWVzc2FnZUhhbmRsZXIoXG4gICAgICBcIlN1Z2dlc3RlZEFjdGlvbnNcIixcbiAgICAgIHtcbiAgICAgICAgaGFuZGxlcjogKG1lc3NhZ2U6IFN1Z2dlc3RlZEFjdGlvbnNFdmVudCkgPT4ge1xuICAgICAgICAgIC8vIFNpbmNlIGFmdGVyIHRoZSBcIkhpc3RvcnlcIiBhbmQgXCJNZXNzYWdlQnJlYWtcIiB0aGF0IHRoaXMgZXZlbnQgaXMgY2F1Z2h0LFxuICAgICAgICAgIC8vICRzdWdnZXN0ZWRBY3Rpb24gbmVlZHMgdG8gYmUgdXBkYXRlZCBkaXJlY3RseSB0byB0aGUgbGFzdCB2aXNpYmxlIFwiYXNzaXN0YW50XCIgbWVzc2FnZSBpbiB0aGUgX3Jlc3BvbnNlIGFuZCB0aGUgY2hhdEhpc3RvcnlcbiAgICAgICAgICB0aGlzLl9yZXNwb25zZS5hdCgtMSkhLmFkZGl0aW9uYWxQcm9wZXJ0aWVzLiRzdWdnZXN0ZWRBY3Rpb24gPSAodGhpcy5fcmVzcG9uc2UuYXQoLTEpIS5hZGRpdGlvbmFsUHJvcGVydGllcy4kc3VnZ2VzdGVkQWN0aW9uIHx8IFtdKS5jb25jYXQobWVzc2FnZS5zdWdnZXN0ZWRBY3Rpb25zKTtcbiAgICAgICAgICBjb25zdCBpbmRleCA9IHRoaXMubGFzdFZpc2libGVBc3Npc3RhbnRNZXNzYWdlSW5kZXgodGhpcy5jaGF0SGlzdG9yeSk7XG4gICAgICAgICAgaWYgKGluZGV4ICE9PSAtMSkge1xuICAgICAgICAgICAgdGhpcy5jaGF0SGlzdG9yeSFbaW5kZXhdLmFkZGl0aW9uYWxQcm9wZXJ0aWVzLiRzdWdnZXN0ZWRBY3Rpb24gPSAodGhpcy5jaGF0SGlzdG9yeSFbaW5kZXhdLmFkZGl0aW9uYWxQcm9wZXJ0aWVzLiRzdWdnZXN0ZWRBY3Rpb24gfHwgW10pLmNvbmNhdChtZXNzYWdlLnN1Z2dlc3RlZEFjdGlvbnMpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAgaXNHbG9iYWxIYW5kbGVyOiBmYWxzZVxuICAgICAgfVxuICAgICk7XG4gICAgdGhpcy5hZGRNZXNzYWdlSGFuZGxlcihcbiAgICAgIFwiRGVidWdEaXNwbGF5XCIsXG4gICAgICB7XG4gICAgICAgIGhhbmRsZXI6IChtZXNzYWdlOiBEZWJ1Z01lc3NhZ2VFdmVudCkgPT4gdGhpcy5fZGVidWdNZXNzYWdlcyA9IHRoaXMuX2RlYnVnTWVzc2FnZXMuY29uY2F0KG1lc3NhZ2UpLFxuICAgICAgICBpc0dsb2JhbEhhbmRsZXI6IGZhbHNlXG4gICAgICB9XG4gICAgKTtcbiAgICB0aGlzLmFkZE1lc3NhZ2VIYW5kbGVyKFxuICAgICAgXCJNZXNzYWdlQnJlYWtcIixcbiAgICAgIHtcbiAgICAgICAgaGFuZGxlcjogKCkgPT4ge1xuICAgICAgICAgIC8vIEdlbmVyYXRlIGF1ZGl0IGV2ZW50XG4gICAgICAgICAgY29uc3QgZGV0YWlscyA9IHtcbiAgICAgICAgICAgICdkdXJhdGlvbic6IHRoaXMuX2V4ZWN1dGlvblRpbWVNaWxsaXNlY29uZHMgIT09IHVuZGVmaW5lZCA/IHRoaXMuX2V4ZWN1dGlvblRpbWVNaWxsaXNlY29uZHMgOiB0aGlzLl9leGVjdXRpb25UaW1lLFxuICAgICAgICAgICAgJ3JvbGUnOiB0aGlzLmNoYXRIaXN0b3J5IS5hdCgtMSkhLnJvbGUsIC8vICdhc3Npc3RhbnQnXG4gICAgICAgICAgICAncmFuayc6IHRoaXMuY2hhdEhpc3RvcnkhLmxlbmd0aCAtIDEsXG4gICAgICAgICAgICAnZ2VuZXJhdGlvbi10b2tlbmNvdW50JzogdGhpcy5jaGF0SGlzdG9yeSEuYXQoLTEpIS5hZGRpdGlvbmFsUHJvcGVydGllcy51c2FnZU1ldHJpY3M/LmNvbXBsZXRpb25Ub2tlbkNvdW50LFxuICAgICAgICAgICAgJ3Byb21wdC10b2tlbmNvdW50JzogdGhpcy5jaGF0SGlzdG9yeSEuYXQoLTEpIS5hZGRpdGlvbmFsUHJvcGVydGllcy51c2FnZU1ldHJpY3M/LnByb21wdFRva2VuQ291bnQsXG4gICAgICAgICAgICAnYXR0YWNobWVudHMnOiBKU09OLnN0cmluZ2lmeSh0aGlzLl9hdHRhY2htZW50cy5tYXAoKHsgcmVjb3JkSWQsIGNvbnRleHRJZCwgcGFydHMsIHR5cGUgfSkgPT4gKHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWNvcmRJZCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb250ZXh0SWQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFydHM6IHBhcnRzLm1hcCgoeyBwYXJ0SWQsIHRleHQgfSkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCEhdGhpcy5hc3Npc3RhbnRDb25maWckLnZhbHVlPy5hdWRpdFNldHRpbmdzPy5sb2dDb250ZW50KSByZXR1cm4geyBwYXJ0SWQsIHRleHQgfTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiB7IHBhcnRJZCB9O1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGVcbiAgICAgICAgICAgICAgICAgICAgICAgICAgfSkpKVxuICAgICAgICAgIH07XG5cbiAgICAgICAgICBpZiAoISF0aGlzLmFzc2lzdGFudENvbmZpZyQudmFsdWU/LmF1ZGl0U2V0dGluZ3M/LmxvZ0NvbnRlbnQpXG4gICAgICAgICAgICBkZXRhaWxzWyd0ZXh0J10gPSB0aGlzLmNoYXRIaXN0b3J5IS5hdCgtMSkhLmNvbnRlbnQ7XG5cbiAgICAgICAgICB0aGlzLmdlbmVyYXRlQXVkaXRFdmVudCgnYXN0LW1lc3NhZ2UnLCBkZXRhaWxzKTtcbiAgICAgICAgICAvLyBQdXNoIGEgbmV3IGFzc2lzdGFudCBtZXNzYWdlIHRvIHRoZSBfcmVzcG9uc2UgYXJyYXkgT05MWSBpZiB0aGUgY29udGVudCBvZiB0aGUgbGFzdCBtZXNzYWdlIGlzIG5vdCBlbXB0eVxuICAgICAgICAgIGlmICh0aGlzLl9yZXNwb25zZS5hdCgtMSkhLmNvbnRlbnQgIT09IFwiXCIpIHtcbiAgICAgICAgICAgIHRoaXMuX3Jlc3BvbnNlLnB1c2goe3JvbGU6IFwiYXNzaXN0YW50XCIsIGNvbnRlbnQ6IFwiXCIsIGFkZGl0aW9uYWxQcm9wZXJ0aWVzOiB7ZGlzcGxheTogdHJ1ZX19KVxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAgaXNHbG9iYWxIYW5kbGVyOiBmYWxzZVxuICAgICAgfVxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogT3ZlcnJpZGUgYW5kIHJlZ2lzdGVyIHRoZSBlbnRpcmUgX21lc3NhZ2VIYW5kbGVycyBtYXAgYnkgbWVyZ2luZyB0aGUgcHJvdmlkZWQgbWFwIHdpdGggdGhlIGRlZmF1bHQgb25lXG4gICAqIEBwYXJhbSBfbWVzc2FnZUhhbmRsZXJzXG4gICAqL1xuICBvdmVycmlkZU1lc3NhZ2VIYW5kbGVyczxUPihfbWVzc2FnZUhhbmRsZXJzOiBNYXA8c3RyaW5nLCBNZXNzYWdlSGFuZGxlcjxUPj4pIHtcbiAgICAvLyBDbGVhciB0aGUgYWxyZWFkeSByZWdpc3RlcmVkIGdsb2JhbCBjaGF0IGhhbmRsZXJzIGJlZm9yZSBtZXJnaW5nIHRoZSBuZXcgb25lc1xuICAgIHRoaXMuX21lc3NhZ2VIYW5kbGVycy5mb3JFYWNoKChldmVudEhhbmRsZXIsIGV2ZW50TmFtZSkgPT4ge1xuICAgICAgaWYoZXZlbnRIYW5kbGVyLmlzR2xvYmFsSGFuZGxlcikge1xuICAgICAgICB0aGlzLnVuc3Vic2NyaWJlTWVzc2FnZUhhbmRsZXIoZXZlbnROYW1lKTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIC8vIE1lcmdlIHRoZSBuZXcgZXZlbnQgaGFuZGxlcnMgd2l0aCB0aGUgZXhpc3Rpbmcgb25lc1xuICAgIHRoaXMuX21lc3NhZ2VIYW5kbGVycyA9IG5ldyBNYXAoWy4uLnRoaXMuX21lc3NhZ2VIYW5kbGVycywgLi4uX21lc3NhZ2VIYW5kbGVyc10pO1xuXG4gICAgLy8gUmVnaXN0ZXIgdGhlIGdsb2JhbCBoYW5kbGVycyBhbW9uZyB0aGUgbWVyZ2VkIG1hcFxuICAgIHRoaXMuX21lc3NhZ2VIYW5kbGVycy5mb3JFYWNoKChldmVudEhhbmRsZXIsIGV2ZW50TmFtZSkgPT4ge1xuICAgICAgaWYoZXZlbnRIYW5kbGVyLmlzR2xvYmFsSGFuZGxlcikge1xuICAgICAgICB0aGlzLnJlZ2lzdGVyTWVzc2FnZUhhbmRsZXIoZXZlbnROYW1lLCBldmVudEhhbmRsZXIpO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEFkZCBhIGxpc3RlbmVyIGZvciBhIHNwZWNpZmljIGV2ZW50LlxuICAgKiBJZiBhIGxpc3RlbmVyIGZvciB0aGlzIHNhbWUgZXZlbnQgYWxyZWFkeSBleGlzdHMsIGl0IHdpbGwgYmUgb3ZlcnJpZGRlbi5cbiAgICogSWYgdGhlIGxpc3RlbmVyIGhhcyBcImlzR2xvYmFsSGFuZGxlclwiIHNldCB0byB0cnVlLCBpdCB3aWxsIGJlIHJlZ2lzdGVyZWQgdG8gdGhlIGh1YiBjb25uZWN0aW9uLlxuICAgKiBAcGFyYW0gZXZlbnROYW1lIE5hbWUgb2YgdGhlIGV2ZW50IHRvIHJlZ2lzdGVyIGEgbGlzdGVuZXIgZm9yXG4gICAqIEBwYXJhbSBldmVudEhhbmRsZXIgVGhlIGhhbmRsZXIgdG8gYmUgY2FsbGVkIHdoZW4gdGhlIGV2ZW50IGlzIHJlY2VpdmVkXG4gICAqL1xuICBhZGRNZXNzYWdlSGFuZGxlcjxUPihldmVudE5hbWU6IHN0cmluZywgZXZlbnRIYW5kbGVyOiBNZXNzYWdlSGFuZGxlcjxUPikge1xuICAgIHRoaXMuX21lc3NhZ2VIYW5kbGVycy5zZXQoZXZlbnROYW1lLCBldmVudEhhbmRsZXIpO1xuICAgIGlmKGV2ZW50SGFuZGxlci5pc0dsb2JhbEhhbmRsZXIpIHtcbiAgICAgIHRoaXMucmVnaXN0ZXJNZXNzYWdlSGFuZGxlcihldmVudE5hbWUsIGV2ZW50SGFuZGxlcik7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIER5bmFtaWNhbGx5IHJlZ2lzdGVyIGEgbGlzdGVuZXIgZm9yIGEgc3BlY2lmaWMgZXZlbnQuXG4gICAqIElmIGEgbGlzdGVuZXIgZm9yIHRoaXMgZXZlbnQgYWxyZWFkeSBleGlzdHMsIGl0IHdpbGwgYmUgb3ZlcnJpZGRlbi5cbiAgICogQHBhcmFtIGV2ZW50TmFtZSBOYW1lIG9mIHRoZSBldmVudCB0byByZWdpc3RlciBhIGxpc3RlbmVyIGZvclxuICAgKiBAcGFyYW0gZXZlbnRIYW5kbGVyIFRoZSBoYW5kbGVyIHRvIGJlIGNhbGxlZCB3aGVuIHRoZSBldmVudCBpcyByZWNlaXZlZFxuICAgKi9cbiAgcHJvdGVjdGVkIHJlZ2lzdGVyTWVzc2FnZUhhbmRsZXI8VD4oZXZlbnROYW1lOiBzdHJpbmcsIGV2ZW50SGFuZGxlcjogTWVzc2FnZUhhbmRsZXI8VD4pIHtcbiAgICBpZiAoIXRoaXMuY29ubmVjdGlvbikge1xuICAgICAgY29uc29sZS5sb2coXCJObyBjb25uZWN0aW9uIGZvdW5kIHRvIHJlZ2lzdGVyIHRoZSBsaXN0ZW5lclwiICsgZXZlbnROYW1lKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0aGlzLmNvbm5lY3Rpb24ub24oZXZlbnROYW1lLCAoZGF0YTogVCkgPT4ge1xuICAgICAgZXZlbnRIYW5kbGVyLmhhbmRsZXIoZGF0YSk7XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogUmVtb3ZlIGEgbGlzdGVuZXIgZm9yIGEgc3BlY2lmaWMgZXZlbnQgZnJvbSB0aGUgX21lc3NhZ2VIYW5kbGVycyBtYXAgYW5kIHVuc3Vic2NyaWJlIGZyb20gcmVjZWl2aW5nIG1lc3NhZ2VzIGZvciB0aGlzIGV2ZW50IGZyb20gdGhlIFNpZ25hbFIgaHViLlxuICAgKiBAcGFyYW0gZXZlbnROYW1lIE5hbWUgb2YgdGhlIGV2ZW50IHRvIHJlbW92ZSB0aGUgbGlzdGVuZXIgZm9yXG4gICAqL1xuICByZW1vdmVNZXNzYWdlSGFuZGxlcihldmVudE5hbWU6IHN0cmluZykge1xuICAgIHRoaXMuX21lc3NhZ2VIYW5kbGVycy5kZWxldGUoZXZlbnROYW1lKTtcbiAgICB0aGlzLnVuc3Vic2NyaWJlTWVzc2FnZUhhbmRsZXIoZXZlbnROYW1lKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBVbnN1YnNjcmliZSBmcm9tIHJlY2VpdmluZyBtZXNzYWdlcyBmb3IgYSBzcGVjaWZpYyBldmVudCBmcm9tIHRoZSBTaWduYWxSIGh1Yi5cbiAgICogQUxMIGl0cyByZWxhdGVkIGxpc3RlbmVycyB3aWxsIGJlIHJlbW92ZWQgZnJvbSBodWIgY29ubmVjdGlvblxuICAgKiBUaGlzIGlzIG5lZWRlZCB0byBwcmV2ZW50IGFjY3VtdWxhdGluZyBvbGQgbGlzdGVuZXJzIHdoZW4gb3ZlcnJpZGluZyB0aGUgZW50aXJlIF9tZXNzYWdlSGFuZGxlcnMgbWFwXG4gICAqIEBwYXJhbSBldmVudE5hbWUgTmFtZSBvZiB0aGUgZXZlbnRcbiAgICovXG4gIHByb3RlY3RlZCB1bnN1YnNjcmliZU1lc3NhZ2VIYW5kbGVyKGV2ZW50TmFtZTogc3RyaW5nKSB7XG4gICAgdGhpcy5jb25uZWN0aW9uIS5vZmYoZXZlbnROYW1lKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBCdWlsZCBhIGNvbm5lY3Rpb24gdG8gdGhlIHNpZ25hbFIgd2Vic29ja2V0IGFuZCByZWdpc3RlciBkZWZhdWx0IGxpc3RlbmVycyB0byB0aGUgbWV0aG9kcyBkZWZpbmVkIGluIHRoZSBzZXJ2ZXIgaHViIGNsYXNzXG4gICAqIEBwYXJhbSBvcHRpb25zIFRoZSBvcHRpb25zIGZvciB0aGUgY29ubmVjdGlvbi4gSXQgb3ZlcnJpZGVzIHRoZSBkZWZhdWx0IG9wdGlvbnNcbiAgICogQHBhcmFtIGxvZ0xldmVsIERlZmluZSB0aGUgbG9nIGxldmVsIGRpc3BsYXllZCBpbiB0aGUgY29uc29sZVxuICAgKiBAcmV0dXJucyBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2hlbiB0aGUgY29ubmVjdGlvbiBpcyBidWlsdFxuICAgKi9cbiAgYnVpbGRDb25uZWN0aW9uKG9wdGlvbnM/OiBDb25uZWN0aW9uT3B0aW9ucyk6IFByb21pc2U8dm9pZD4ge1xuICAgIHJldHVybiBuZXcgUHJvbWlzZTx2b2lkPigocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICBpZiAoIXRoaXMuUkVRVUVTVF9VUkwpIHtcbiAgICAgICAgICByZWplY3QobmV3IEVycm9yKFwiTm8gZW5kcG9pbnQgcHJvdmlkZWQgdG8gY29ubmVjdCB0aGUgd2Vic29ja2V0IHRvXCIpKTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgICBjb25zdCBsb2dMZXZlbCA9IHRoaXMuX2dldExvZ0xldmVsKCk7XG5cbiAgICAgIGlmICh0aGlzLmFzc2lzdGFudENvbmZpZyQudmFsdWU/LmNvbm5lY3Rpb25TZXR0aW5ncy5zaWduYWxSU2tpcE5lZ290aWF0aW9uID09PSB0cnVlKVxuICAgICAgICBvcHRpb25zID0gey4uLm9wdGlvbnMsIHNraXBOZWdvdGlhdGlvbjogdHJ1ZX07XG5cbiAgICAgIHRoaXMuY29ubmVjdGlvbiA9IHRoaXMuc2lnbmFsUlNlcnZpY2UuYnVpbGRDb25uZWN0aW9uKHRoaXMuUkVRVUVTVF9VUkwsIHsuLi50aGlzLmRlZmF1bHRPcHRpb25zLCAuLi5vcHRpb25zfSwgbG9nTGV2ZWwsIHRydWUpO1xuXG4gICAgICBjb25zdCBzaWduYWxSU2VydmVyVGltZW91dEluTWlsbGlzZWNvbmRzID0gdGhpcy5hc3Npc3RhbnRDb25maWckLnZhbHVlPy5jb25uZWN0aW9uU2V0dGluZ3Muc2lnbmFsUlNlcnZlclRpbWVvdXRJbk1pbGxpc2Vjb25kcztcbiAgICAgIGlmIChzaWduYWxSU2VydmVyVGltZW91dEluTWlsbGlzZWNvbmRzKSB7XG4gICAgICAgIHRoaXMuY29ubmVjdGlvbi5zZXJ2ZXJUaW1lb3V0SW5NaWxsaXNlY29uZHMgPSBzaWduYWxSU2VydmVyVGltZW91dEluTWlsbGlzZWNvbmRzO1xuICAgICAgfVxuXG4gICAgICByZXNvbHZlKCk7XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogU3RhcnQgdGhlIGNvbm5lY3Rpb25cbiAgICogQHJldHVybnMgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHdoZW4gdGhlIGNvbm5lY3Rpb24gaXMgc3RhcnRlZFxuICAgKi9cbiAgc3RhcnRDb25uZWN0aW9uKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIHJldHVybiB0aGlzLnNpZ25hbFJTZXJ2aWNlLnN0YXJ0Q29ubmVjdGlvbih0aGlzLmNvbm5lY3Rpb24pO1xuICB9XG5cbiAgLyoqXG4gICAqIFN0b3AgdGhlIGNvbm5lY3Rpb25cbiAgICogQHJldHVybnMgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHdoZW4gdGhlIGNvbm5lY3Rpb24gaXMgc3RvcHBlZFxuICAgKi9cbiAgc3RvcENvbm5lY3Rpb24oKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgcmV0dXJuIHRoaXMuc2lnbmFsUlNlcnZpY2Uuc3RvcENvbm5lY3Rpb24odGhpcy5jb25uZWN0aW9uKTtcbiAgfVxuXG4gIHByaXZhdGUgX2dldFRyYW5zcG9ydHMoKTogSHR0cFRyYW5zcG9ydFR5cGUge1xuICAgIHN3aXRjaCAodGhpcy5hc3Npc3RhbnRDb25maWckLnZhbHVlPy5jb25uZWN0aW9uU2V0dGluZ3Muc2lnbmFsUlRyYW5zcG9ydCkge1xuICAgICAgY2FzZSBcIldlYlNvY2tldHNcIjpcbiAgICAgICAgcmV0dXJuIEh0dHBUcmFuc3BvcnRUeXBlLldlYlNvY2tldHM7XG4gICAgICBjYXNlIFwiU2VydmVyU2VudEV2ZW50c1wiOlxuICAgICAgICByZXR1cm4gSHR0cFRyYW5zcG9ydFR5cGUuU2VydmVyU2VudEV2ZW50cztcbiAgICAgIGNhc2UgXCJMb25nUG9sbGluZ1wiOlxuICAgICAgICByZXR1cm4gSHR0cFRyYW5zcG9ydFR5cGUuTG9uZ1BvbGxpbmc7XG4gICAgICBkZWZhdWx0OlxuICAgICAgICByZXR1cm4gSHR0cFRyYW5zcG9ydFR5cGUuTm9uZTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIF9nZXRMb2dMZXZlbCgpOiBMb2dMZXZlbCB7XG4gICAgc3dpdGNoICh0aGlzLmFzc2lzdGFudENvbmZpZyQudmFsdWU/LmNvbm5lY3Rpb25TZXR0aW5ncy5zaWduYWxSTG9nTGV2ZWwpIHtcbiAgICAgIGNhc2UgXCJDcml0aWNhbFwiOlxuICAgICAgICByZXR1cm4gTG9nTGV2ZWwuQ3JpdGljYWw7IC8vIExvZyBsZXZlbCBmb3IgZGlhZ25vc3RpYyBtZXNzYWdlcyB0aGF0IGluZGljYXRlIGEgZmFpbHVyZSB0aGF0IHdpbGwgdGVybWluYXRlIHRoZSBlbnRpcmUgYXBwbGljYXRpb24uXG4gICAgICBjYXNlIFwiRGVidWdcIjpcbiAgICAgICAgcmV0dXJuIExvZ0xldmVsLkRlYnVnOyAvLyBMb2cgbGV2ZWwgZm9yIGxvdyBzZXZlcml0eSBkaWFnbm9zdGljIG1lc3NhZ2VzLlxuICAgICAgY2FzZSBcIkVycm9yXCI6XG4gICAgICAgIHJldHVybiBMb2dMZXZlbC5FcnJvcjsgLy8gTG9nIGxldmVsIGZvciBkaWFnbm9zdGljIG1lc3NhZ2VzIHRoYXQgaW5kaWNhdGUgYSBmYWlsdXJlIGluIHRoZSBjdXJyZW50IG9wZXJhdGlvbi5cbiAgICAgIGNhc2UgXCJJbmZvcm1hdGlvblwiOlxuICAgICAgICByZXR1cm4gTG9nTGV2ZWwuSW5mb3JtYXRpb247IC8vIExvZyBsZXZlbCBmb3IgaW5mb3JtYXRpb25hbCBkaWFnbm9zdGljIG1lc3NhZ2VzLlxuICAgICAgY2FzZSBcIk5vbmVcIjpcbiAgICAgICAgcmV0dXJuIExvZ0xldmVsLk5vbmU7IC8vIFRoZSBoaWdoZXN0IHBvc3NpYmxlIGxvZyBsZXZlbC4gVXNlZCB3aGVuIGNvbmZpZ3VyaW5nIGxvZ2dpbmcgdG8gaW5kaWNhdGUgdGhhdCBubyBsb2cgbWVzc2FnZXMgc2hvdWxkIGJlIGVtaXR0ZWQuXG4gICAgICBjYXNlIFwiVHJhY2VcIjpcbiAgICAgICAgcmV0dXJuIExvZ0xldmVsLlRyYWNlOyAvLyBMb2cgbGV2ZWwgZm9yIHZlcnkgbG93IHNldmVyaXR5IGRpYWdub3N0aWMgbWVzc2FnZXMuXG4gICAgICBjYXNlIFwiV2FybmluZ1wiOlxuICAgICAgICByZXR1cm4gTG9nTGV2ZWwuV2FybmluZzsgLy8gTG9nIGxldmVsIGZvciBkaWFnbm9zdGljIG1lc3NhZ2VzIHRoYXQgaW5kaWNhdGUgYSBub24tZmF0YWwgcHJvYmxlbS5cbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHJldHVybiBMb2dMZXZlbC5Ob25lOyAvLyBUaGUgaGlnaGVzdCBwb3NzaWJsZSBsb2cgbGV2ZWwuIFVzZWQgd2hlbiBjb25maWd1cmluZyBsb2dnaW5nIHRvIGluZGljYXRlIHRoYXQgbm8gbG9nIG1lc3NhZ2VzIHNob3VsZCBiZSBlbWl0dGVkLlxuICAgIH1cbiAgfVxuXG4gIGdldCBkZWZhdWx0T3B0aW9ucygpOiBDb25uZWN0aW9uT3B0aW9ucyB7XG4gICAgbGV0IGhlYWRlcnM6IE1lc3NhZ2VIZWFkZXJzID0ge1xuICAgICAgXCJzaW5lcXVhLWZvcmNlLWNhbWVsLWNhc2VcIjogXCJ0cnVlXCIsXG4gICAgICBcIngtbGFuZ3VhZ2VcIjogdGhpcy5nZXRDdXJyZW50TG9jYWxlTmFtZSgpLFxuICAgICAgXCJ1aS1sYW5ndWFnZVwiOiB0aGlzLmdldEN1cnJlbnRMb2NhbGVOYW1lKCksXG4gICAgfTtcbiAgICBjb25zdCB0b2tlbiA9IGdldFRva2VuKCk7XG4gICAgaWYodG9rZW4pe1xuICAgICAgaGVhZGVycyA9IHsuLi5oZWFkZXJzLCBcInNpbmVxdWEtY3NyZi10b2tlblwiOiB0b2tlbn07XG4gICAgfVxuXG4gICAgLy8gRm9yIHRoZSBmaXJzdCBHRVQgcmVxdWVzdCBzZW50IGJ5IHNpZ25hbFIgdG8gc3RhcnQgYSBXZWJTb2NrZXQgcHJvdG9jb2wsXG4gICAgLy8gYXMgZmFyIGFzIHdlIGtub3csIHNpZ25hbFIgb25seSBsZXRzIHVzIHR3ZWFrIHRoZSByZXF1ZXN0IHdpdGggdGhpcyBhY2Nlc3MgdG9rZW4gZmFjdG9yeVxuICAgIC8vIHNvIHdlIHBhc3MgYWxvbmcgdGhlIFNpbmVxdWEgQ1NSRiB0b2tlbiB0byBwYXNzIHRoZSBDU1JGIGNoZWNrLi5cbiAgICByZXR1cm4ge1xuICAgICAgdHJhbnNwb3J0OiB0aGlzLl9nZXRUcmFuc3BvcnRzKCksXG4gICAgICB3aXRoQ3JlZGVudGlhbHM6IHRydWUsXG4gICAgICBoZWFkZXJzLFxuICAgICAgc2tpcE5lZ290aWF0aW9uOiBmYWxzZSxcbiAgICAgIGFjY2Vzc1Rva2VuRmFjdG9yeTogKCkgPT4gdG9rZW4gfHwgXCJcIlxuICAgIH1cbiAgfVxufVxuIl19
|