@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.
Files changed (43) hide show
  1. package/chat/chat.component.d.ts +35 -38
  2. package/chat/chat.service.d.ts +190 -84
  3. package/chat/debug-message/debug-message-details/debug-message-details.component.d.ts +19 -0
  4. package/chat/debug-message/debug-message.component.d.ts +9 -12
  5. package/chat/debug-message/debug-message.service.d.ts +15 -0
  6. package/chat/documents-upload/document-list/document-list.component.d.ts +1 -0
  7. package/chat/public-api.d.ts +0 -2
  8. package/chat/saved-chats/i18n/en.json +1 -1
  9. package/chat/saved-chats/i18n/fr.json +1 -1
  10. package/chat/saved-chats/saved-chats.component.d.ts +1 -0
  11. package/chat/saved-chats/saved-chats.service.d.ts +27 -0
  12. package/chat/services/assistant-configuration.service.d.ts +34 -0
  13. package/chat/services/assistant-metadata.service.d.ts +18 -0
  14. package/chat/services/assistant-tokens-tracking.service.d.ts +23 -0
  15. package/chat/services/assistant-ws-frames.service.d.ts +50 -0
  16. package/chat/services/signalR-connection.service.d.ts +25 -0
  17. package/chat/types.d.ts +12 -3
  18. package/chat/utils/utils.service.d.ts +67 -0
  19. package/esm2022/chat/chat.component.mjs +198 -227
  20. package/esm2022/chat/chat.service.mjs +450 -267
  21. package/esm2022/chat/debug-message/debug-message-details/debug-message-details.component.mjs +43 -0
  22. package/esm2022/chat/debug-message/debug-message.component.mjs +27 -30
  23. package/esm2022/chat/debug-message/debug-message.service.mjs +52 -0
  24. package/esm2022/chat/dialogs/rename-saved-chat.component.mjs +6 -5
  25. package/esm2022/chat/documents-upload/document-list/document-list.component.mjs +4 -2
  26. package/esm2022/chat/public-api.mjs +1 -3
  27. package/esm2022/chat/saved-chats/saved-chats.component.mjs +11 -10
  28. package/esm2022/chat/saved-chats/saved-chats.service.mjs +165 -0
  29. package/esm2022/chat/services/assistant-configuration.service.mjs +171 -0
  30. package/esm2022/chat/services/assistant-metadata.service.mjs +67 -0
  31. package/esm2022/chat/services/assistant-tokens-tracking.service.mjs +57 -0
  32. package/esm2022/chat/services/assistant-ws-frames.service.mjs +392 -0
  33. package/esm2022/chat/services/signalR-connection.service.mjs +109 -0
  34. package/esm2022/chat/types.mjs +1 -1
  35. package/esm2022/chat/unified-plugins/embedded-image-reference.plugin.mjs +2 -3
  36. package/esm2022/chat/utils/utils.service.mjs +170 -0
  37. package/fesm2022/sinequa-assistant-chat.mjs +2020 -1648
  38. package/fesm2022/sinequa-assistant-chat.mjs.map +1 -1
  39. package/package.json +1 -1
  40. package/chat/rest-chat.service.d.ts +0 -31
  41. package/chat/websocket-chat.service.d.ts +0 -102
  42. package/esm2022/chat/rest-chat.service.mjs +0 -300
  43. 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