@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,20 +1,22 @@
1
- import { Injectable, LOCALE_ID, inject } from "@angular/core";
1
+ import { Injectable, inject } from "@angular/core";
2
2
  import { TranslocoService } from "@jsverse/transloco";
3
- import { differenceInDays, differenceInMonths, differenceInYears, endOfYesterday, format, isThisMonth, isThisQuarter, isThisWeek, isThisYear, isToday, isYesterday, parseISO, toDate } from "date-fns";
4
- import { BehaviorSubject } from "rxjs";
5
- import { Audit, fetchApp, fetchPrincipal, fetchUserSettings, guid, sha512 } from "@sinequa/atomic";
6
- import { DialogUpdatesComponent } from "./dialogs/updates.component";
3
+ import { BehaviorSubject, catchError, defer, filter, forkJoin, from, map, switchMap, take, tap, throwError } from "rxjs";
4
+ import { Audit, guid, globalConfig } from "@sinequa/atomic";
7
5
  import { AppService } from "./services/app.service";
8
- import { DialogService } from "./services/dialog.service";
9
6
  import { NotificationsService } from "./services/notification.service";
10
7
  import { PrincipalService } from "./services/principal.service";
11
8
  import { UserSettingsWebService } from "./services/user-settings.service";
12
- import { chatConfigSchema } from "./types";
13
- import { getAssistantJsonFromCCApp } from "./utils/assistant-json";
9
+ import { AssistantUtils } from "./utils/utils.service";
10
+ import { SavedChatsService } from "./saved-chats/saved-chats.service";
11
+ import { SignalRConnectionService } from "./services/signalR-connection.service";
12
+ import { AssistantConfigurationService } from "./services/assistant-configuration.service";
13
+ import { AssistantMetadataService } from "./services/assistant-metadata.service";
14
+ import { AssistantTokensTrackingService } from "./services/assistant-tokens-tracking.service";
15
+ import { AssistantWsFramesService } from "./services/assistant-ws-frames.service"; // Added
16
+ import { DebugMessageService } from "./debug-message/debug-message.service";
14
17
  import * as i0 from "@angular/core";
15
18
  export class ChatService {
16
19
  constructor() {
17
- this.localID = inject(LOCALE_ID, { optional: true });
18
20
  /** Emit true once the initialization of the assistant process is done. */
19
21
  this.initProcess$ = new BehaviorSubject(false);
20
22
  /** Emit true once the initialization of the assistant config is done. */
@@ -48,16 +50,287 @@ export class ChatService {
48
50
  this.userSettingsService = inject(UserSettingsWebService);
49
51
  this.notificationsService = inject(NotificationsService);
50
52
  this.appService = inject(AppService);
51
- this.modalService = inject(DialogService);
52
53
  this.principalService = inject(PrincipalService);
54
+ this.assistantUtils = inject(AssistantUtils);
55
+ this.savedChatsService = inject(SavedChatsService);
56
+ this.signalRConnectionService = inject(SignalRConnectionService);
57
+ this.assistantConfigurationService = inject(AssistantConfigurationService);
58
+ this.assistantMetadataService = inject(AssistantMetadataService);
59
+ this.assistantTokensTrackingService = inject(AssistantTokensTrackingService);
60
+ this.debugMessageService = inject(DebugMessageService);
61
+ // Inject the AssistantWsFramesService using 'new' to ensure a separate local instance for each ChatService instance
62
+ this.assistantWsFramesService = new (AssistantWsFramesService);
53
63
  this.transloco = inject(TranslocoService);
54
64
  }
65
+ /**
66
+ * Initialize the assistant process.
67
+ * It includes building and starting a connection, executing parallel requests for models and functions, and handling errors during the process.
68
+ * ⚠️ This method MUST be called ONLY if the user is loggedIn and once when the assistant is initialized.
69
+ *
70
+ * @returns An Observable<boolean> indicating the success of the initialization process.
71
+ */
72
+ init() {
73
+ // Ensure all logic is executed when subscribed to the observable
74
+ return defer(() => {
75
+ this._initAssistantConfigurationService();
76
+ return from(this.initChatConfig());
77
+ }).pipe(
78
+ // Wait for the configuration to be initialized
79
+ switchMap(() => this.initConfig$.pipe(filter(Boolean), take(1))), tap(() => {
80
+ this.getWSRequestsUrl();
81
+ this.getRESTRequestsUrl();
82
+ this._initAssistantMetadataService();
83
+ this._initAssistantTokensTrackingService();
84
+ this._initSavedChatsService();
85
+ this._initDebugMessageService();
86
+ this._initSignalRConnectionService();
87
+ }),
88
+ // Build and start the SignalR connection
89
+ switchMap(() => this.buildConnection()), tap(() => {
90
+ // Initialize AssistantWsFramesService here, now that 'this.connection' is set
91
+ this._initAssistantWsFramesService();
92
+ this.initMessageHandlers();
93
+ }),
94
+ // Start the connection
95
+ switchMap(() => this.startConnection()),
96
+ // Fetch metadata in parallel
97
+ switchMap(() => forkJoin([
98
+ this.listModels(),
99
+ this.listFunctions()
100
+ ])),
101
+ // Map the results of parallel requests to a boolean indicating success
102
+ map(([models, functions]) => {
103
+ const result = !!models && !!functions;
104
+ this.initProcess$.next(result);
105
+ return result;
106
+ }),
107
+ // Any errors during the process are caught, logged, and re-thrown to propagate the error further
108
+ catchError((error) => {
109
+ console.error('Error occurred:', error);
110
+ return throwError(() => error);
111
+ }), take(1));
112
+ }
113
+ /**
114
+ * Define the endpoint to use for the websocket requests
115
+ * It can be overridden by the app config
116
+ */
117
+ getWSRequestsUrl() {
118
+ this.assistantConfigurationService.getWSRequestsUrl();
119
+ }
120
+ /**
121
+ * Define the endpoint to use for the http requests
122
+ * It can be overridden by the app config
123
+ */
124
+ getRESTRequestsUrl() {
125
+ this.assistantConfigurationService.getRESTRequestsUrl();
126
+ }
127
+ /**
128
+ * Initializes the SavedChatsService with the necessary configuration.
129
+ *
130
+ * This method sets up the `SavedChatsService` by providing it with a configuration object
131
+ * (`SavedChatsOperationConfig`) that includes various callbacks and properties required
132
+ * for its operation. The initialization will only proceed if both `assistantConfig$` and
133
+ * `REST_REQUEST_URL` are available.
134
+ *
135
+ * The configuration object includes:
136
+ * - Application name retrieval.
137
+ * - Instance ID retrieval.
138
+ * - REST API URL retrieval.
139
+ * - Debug flag retrieval.
140
+ * - Chat ID for new saves.
141
+ * - Saved chats enablement check.
142
+ * - Methods for setting a saved chat ID, updating the saved chats list, and generating audit events.
143
+ *
144
+ * If the required dependencies are not ready, an error is logged to the console.
145
+ *
146
+ * @private
147
+ */
148
+ _initSavedChatsService() {
149
+ if (this.assistantConfig$.value && this.REST_REQUEST_URL) {
150
+ const savedChatsOpConfig = {
151
+ getAppName: () => this.appService.appName,
152
+ getInstanceId: () => this.chatInstanceId,
153
+ getRestUrl: () => this.REST_REQUEST_URL,
154
+ getDebugFlag: () => this.assistantConfig$.value.defaultValues.debug,
155
+ isSavedChatsEnabled: () => !!this.assistantConfig$.value?.savedChatSettings.enabled,
156
+ setSavedChatsErrorStatus: (hasError) => this.savedChatsError$.next(hasError),
157
+ updateSavedChatsList: (chats) => this.savedChats$.next(chats),
158
+ generateAuditEvent: (type, details, id) => this.generateAuditEvent(type, details, id),
159
+ };
160
+ this.savedChatsService.init(savedChatsOpConfig);
161
+ }
162
+ else {
163
+ // This case should ideally not happen if init order is correct
164
+ console.error("Cannot initialize SavedChatsService: assistantConfig or REST_REQUEST_URL not ready.");
165
+ }
166
+ }
167
+ /**
168
+ * Initializes the SignalR connection service with the necessary configuration.
169
+ *
170
+ * This method ensures that the SignalR connection service is properly set up
171
+ * by providing it with the required configuration values, such as the WebSocket
172
+ * request URL and assistant configuration. It also manages the SignalR hub connection
173
+ * instance.
174
+ *
175
+ * Preconditions:
176
+ * - `assistantConfig$.value` must be available.
177
+ * - `WS_REQUEST_URL` must be defined.
178
+ *
179
+ * If these preconditions are not met, an error is logged to the console.
180
+ *
181
+ * @private
182
+ */
183
+ _initSignalRConnectionService() {
184
+ if (this.assistantConfig$.value && this.WS_REQUEST_URL) {
185
+ const signalROpConfig = {
186
+ getWsRequestUrl: () => this.WS_REQUEST_URL,
187
+ getAssistantConfigValue: () => this.assistantConfig$.value,
188
+ getHubConnection: () => this.connection, // Using getHubConnection as per user's file
189
+ setHubConnection: (conn) => { this.connection = conn; }
190
+ };
191
+ this.signalRConnectionService.init(signalROpConfig);
192
+ }
193
+ else {
194
+ // This case should ideally not happen if init order is correct
195
+ console.error("Cannot initialize SignalRConnectionService: assistantConfig or WS_REQUEST_URL not ready.");
196
+ }
197
+ }
198
+ /**
199
+ * Initializes the Assistant Configuration Service with the necessary operation context.
200
+ * This method sets up the configuration context by providing various utility functions
201
+ * and state management mechanisms required for the assistant's configuration operations.
202
+ *
203
+ * The operation context includes:
204
+ * - Methods to retrieve chat instance and chat IDs.
205
+ * - Methods to get and set assistant configuration values.
206
+ * - Methods to set WebSocket and REST request URLs.
207
+ * - Methods to update the initialization configuration status.
208
+ * - A method to generate audit events for tracking operations.
209
+ *
210
+ * @private
211
+ */
212
+ _initAssistantConfigurationService() {
213
+ const configOpContext = {
214
+ getChatInstanceId: () => this.chatInstanceId,
215
+ getChatId: () => this.chatId,
216
+ getAssistantConfigValue: () => this.assistantConfig$.value,
217
+ setWSRequestsUrl: (url) => this.WS_REQUEST_URL = url,
218
+ setRESTRequestsUrl: (url) => this.REST_REQUEST_URL = url,
219
+ setAssistantConfig: (config) => this.assistantConfig$.next(config),
220
+ setInitConfigStatus: (status) => this.initConfig$.next(status),
221
+ generateAuditEvent: (type, details, id) => this.generateAuditEvent(type, details, id)
222
+ };
223
+ this.assistantConfigurationService.init(configOpContext);
224
+ }
225
+ /**
226
+ * Initializes the AssistantMetadataService with the necessary operation context.
227
+ *
228
+ * This method checks if the `assistantConfig$` value and `REST_REQUEST_URL` are available.
229
+ * If both are ready, it creates an `AssistantMetadataOperationContext` object and
230
+ * initializes the `assistantMetadataService` with it. The operation context provides
231
+ * methods to retrieve the REST URL, assistant configuration, and to set models and functions.
232
+ *
233
+ * If the required values are not ready, an error is logged to the console.
234
+ *
235
+ * @private
236
+ */
237
+ _initAssistantMetadataService() {
238
+ if (this.assistantConfig$.value && this.REST_REQUEST_URL) {
239
+ const metadataOpContext = {
240
+ getRestUrl: () => this.REST_REQUEST_URL,
241
+ getAssistantConfigValue: () => this.assistantConfig$.value,
242
+ setModels: (models) => { this.models = models; },
243
+ setFunctions: (functions) => { this.functions = functions; }
244
+ };
245
+ this.assistantMetadataService.init(metadataOpContext);
246
+ }
247
+ else {
248
+ console.error("Cannot initialize AssistantMetadataService: assistantConfig or REST_REQUEST_URL not ready.");
249
+ }
250
+ }
251
+ /**
252
+ * Initializes the Assistant Tokens Tracking Service with the necessary operation context.
253
+ * This method sets up the service by providing it with functions to manage quotas,
254
+ * token consumption, usage metrics, and audit events, as well as access to assistant configuration
255
+ * and model retrieval.
256
+ *
257
+ * The initialization will only proceed if the assistant configuration is available.
258
+ * If the configuration is not ready, an error message is logged to the console.
259
+ *
260
+ * @private
261
+ */
262
+ _initAssistantTokensTrackingService() {
263
+ if (this.assistantConfig$.value) {
264
+ const tokensOpContext = {
265
+ getAssistantConfigValue: () => this.assistantConfig$.value,
266
+ setQuota: (quota) => this.quota$.next(quota),
267
+ setUserTokenConsumption: (consumption) => this.userTokenConsumption$.next(consumption),
268
+ setChatUsageMetrics: (metrics) => this.chatUsageMetrics$.next(metrics),
269
+ setChatTokenConsumption: (consumption) => this.chatTokenConsumption$.next(consumption),
270
+ generateAuditEvent: (type, details, id) => this.generateAuditEvent(type, details, id),
271
+ getModel: (serviceId, modelId) => this.getModel(serviceId, modelId)
272
+ };
273
+ this.assistantTokensTrackingService.init(tokensOpContext);
274
+ }
275
+ else {
276
+ console.error("Cannot initialize AssistantTokensTrackingService: assistantConfig not ready.");
277
+ }
278
+ }
279
+ /**
280
+ * Initializes the Assistant WebSocket Frames Service with the necessary operation context.
281
+ * This method sets up the required dependencies and configuration for the service to function properly.
282
+ * It ensures that the assistant configuration and connection are available before initializing the service.
283
+ *
284
+ * The operation context provides various utility functions and state management methods, including:
285
+ * - Accessing the assistant configuration, chat instance ID, saved chat ID, and chat history.
286
+ * - Managing streaming and stopping generation statuses.
287
+ * - Updating quota and chat usage metrics.
288
+ * - Generating audit events.
289
+ * - Managing saved chats (adding, updating, and listing).
290
+ *
291
+ * If the required dependencies (`assistantConfig$` and `connection`) are not ready, an error is logged.
292
+ *
293
+ * @private
294
+ */
295
+ _initAssistantWsFramesService() {
296
+ if (this.assistantConfig$.value && this.connection) {
297
+ const wsFramesOpContext = {
298
+ getAssistantConfig: () => this.assistantConfig$.value,
299
+ getChatInstanceId: () => this.chatInstanceId,
300
+ getChatId: () => this.chatId,
301
+ getHubConnection: () => this.connection,
302
+ getChatHistory: () => this.chatHistory,
303
+ setStreamingStatus: (isStreaming) => this.streaming$.next(isStreaming),
304
+ setChatHistory: (history) => { this.chatHistory = history; },
305
+ setStoppingGenerationStatus: (isStopping) => this.stoppingGeneration$.next(isStopping),
306
+ setSavedChatsErrorStatus: (hasError) => this.savedChatsError$.next(hasError),
307
+ updateQuota: (quota, propagateError) => this.updateQuota(quota, propagateError),
308
+ updateChatUsageMetrics: (metrics) => this.updateChatUsageMetrics(metrics),
309
+ generateAuditEvent: (type, details, id) => this.generateAuditEvent(type, details, id),
310
+ addSavedChat: (id, messages) => this.addSavedChat(id, messages),
311
+ updateSavedChat: (id, name, messages) => this.updateSavedChat(id, name, messages),
312
+ listSavedChat: () => this.listSavedChat(),
313
+ isExistingSavedChat: (id) => this.isExistingSavedChat(id)
314
+ };
315
+ this.assistantWsFramesService.init(wsFramesOpContext);
316
+ }
317
+ else {
318
+ console.error("Cannot initialize AssistantWsFramesService: core dependencies not ready.");
319
+ }
320
+ }
321
+ _initDebugMessageService() {
322
+ if (this.assistantConfig$.value && this.REST_REQUEST_URL) {
323
+ const debugMessageOpContext = {
324
+ getRestUrl: () => this.REST_REQUEST_URL
325
+ };
326
+ this.debugMessageService.init(debugMessageOpContext);
327
+ }
328
+ else {
329
+ console.error("Cannot initialize DebugMessageService: assistantConfig or REST_REQUEST_URL not ready.");
330
+ }
331
+ }
55
332
  get assistants() {
56
- if (!this.userSettingsService.userSettings)
57
- this.userSettingsService.userSettings = {};
58
- if (!this.userSettingsService.userSettings["assistants"])
59
- this.userSettingsService.userSettings["assistants"] = {};
60
- return this.userSettingsService.userSettings["assistants"];
333
+ return this.assistantConfigurationService.getAssistantsSetting();
61
334
  }
62
335
  /**
63
336
  * Get the instance ID of the chat service
@@ -74,29 +347,14 @@ export class ChatService {
74
347
  this._chatInstanceId = instanceId;
75
348
  }
76
349
  /**
77
- * Get the ID of the current chat discussion which is used to save/get/delete it
78
- * @returns The ID of the current chat discussion
79
- */
80
- get savedChatId() {
81
- return this._savedChatId;
82
- }
83
- /**
84
- * Persist the ID of the current chat discussion which is used to save/get/delete it
85
- * @param savedChatId The ID of the current chat discussion which is used to save/get/delete it
86
- */
87
- setSavedChatId(savedChatId) {
88
- this._savedChatId = savedChatId;
89
- }
90
- /**
91
- * Get the ID of the current chat discussion which is used to identify audit events
350
+ * Get the ID of the current chat discussion which is used to save/get/delete the discussion and identify audit events
92
351
  * @returns The ID of the current chat discussion
93
352
  */
94
353
  get chatId() {
95
354
  return this._chatId;
96
355
  }
97
356
  /**
98
- * Generate an GUID for the current chat discussion which is used to identify audit events
99
- * If the discussion is saved, the savedChatId is initialized with the value of this chatId
357
+ * Generate an GUID for the current chat discussion which is used to save/get/delete it and identify audit events
100
358
  * @param chatId if provided, it will be considered as the ID of the current chat discussion which is used to identify audit events
101
359
  */
102
360
  generateChatId(chatId) {
@@ -110,66 +368,7 @@ export class ChatService {
110
368
  * This provide a centralized way to manage the rest of the config object by admins and ensure a unique common behavior for all users.
111
369
  */
112
370
  async initChatConfig() {
113
- // fetch the standard app config to get the defaultValues of the chat config for the given instance
114
- // Persist the app in the app service
115
- const capp = await fetchApp();
116
- this.appService.app = capp;
117
- const settings = await fetchUserSettings();
118
- this.userSettingsService.userSettings = settings;
119
- const key = this.chatInstanceId;
120
- const userSettingsConfig = this.assistants[key] || {};
121
- const principal = await fetchPrincipal();
122
- this.principalService.principal = principal;
123
- const standardChatConfig = getAssistantJsonFromCCApp(this.appService.app, key);
124
- try {
125
- // Validate the whole config object against the schema
126
- chatConfigSchema.parse(standardChatConfig);
127
- // If the user preferences do not contain a config's defaultValues object, keep using the standard app config and nothing to store in the user preferences
128
- if (!userSettingsConfig.defaultValues) {
129
- this.assistantConfig$.next({ ...standardChatConfig });
130
- this.initConfig$.next(true);
131
- }
132
- else { // If the user has its own defaultValues in its userSettings, then we need to check for potential updates made by admins in the meantime and how he wants to manage them
133
- // Retrieve already stored hashes in the user settings if exists
134
- const appliedDefaultValuesHash = userSettingsConfig.hashes?.["applied-defaultValues-hash"];
135
- const skippedDefaultValuesHash = userSettingsConfig.hashes?.["skipped-defaultValues-hash"];
136
- // Create a hash of the current defaultValues of the standardChatConfig
137
- const currentDefaultValuesHash = await sha512(JSON.stringify(standardChatConfig.defaultValues));
138
- // Implement the tracking mechanism to notify the user about the available updates in the defaultValues object of the standard app config
139
- const condition = (currentDefaultValuesHash !== appliedDefaultValuesHash) && (currentDefaultValuesHash !== skippedDefaultValuesHash);
140
- if (condition) {
141
- this.modalService.open(DialogUpdatesComponent)
142
- .then(res => {
143
- if (res === "dialog-confirm") {
144
- const hashes = { ...userSettingsConfig.hashes, "applied-defaultValues-hash": currentDefaultValuesHash, "skipped-defaultValues-hash": undefined };
145
- // Update the chat config and store its defaultValues in the user preferences
146
- this.updateChatConfig({ ...standardChatConfig }, hashes, true);
147
- this.initConfig$.next(true);
148
- this.generateAuditEvent("ast-configuration.click", { 'configuration': JSON.stringify({ ...standardChatConfig }) });
149
- }
150
- else if (res === "dialog-no") {
151
- // Do not notify the user about changes while this skipped version is not updated
152
- const hashes = { ...userSettingsConfig.hashes, "skipped-defaultValues-hash": currentDefaultValuesHash };
153
- this.updateChatConfig({ ...standardChatConfig, defaultValues: userSettingsConfig.defaultValues }, hashes, false);
154
- this.initConfig$.next(true);
155
- }
156
- else {
157
- // Just pick the version in the user settings, nothing to be updated
158
- this.assistantConfig$.next({ ...standardChatConfig, defaultValues: userSettingsConfig.defaultValues });
159
- this.initConfig$.next(true);
160
- }
161
- });
162
- }
163
- else { // No available updates Or updates has been already skipped, then just pick the version in the user settings
164
- this.assistantConfig$.next({ ...standardChatConfig, defaultValues: userSettingsConfig.defaultValues });
165
- this.initConfig$.next(true);
166
- }
167
- }
168
- }
169
- catch (error) {
170
- this.notificationsService.error(`Missing valid configuration for the assistant instance '${key}'. See the browser console messages for details on the missing or incorrect properties.`);
171
- throw new Error(`Missing valid configuration for the assistant instance '${key}' . \n ${JSON.stringify(error.issues, null, 2)}`);
172
- }
371
+ this.assistantConfigurationService.initChatConfig();
173
372
  }
174
373
  /**
175
374
  * Update the chat config and store its defaultValues in the user preferences
@@ -180,28 +379,55 @@ export class ChatService {
180
379
  * @param errorCallback The callback to execute if the update fails
181
380
  */
182
381
  updateChatConfig(config, hashes, notify = true, successCallback, errorCallback) {
183
- this.assistantConfig$.next(config);
184
- const assistants = Object.assign({}, this.assistants);
185
- assistants[this.chatInstanceId] = { ...assistants[this.chatInstanceId], defaultValues: config.defaultValues };
186
- if (hashes)
187
- assistants[this.chatInstanceId].hashes = hashes;
188
- this.userSettingsService.patch({ assistants }).subscribe(next => { }, error => {
189
- if (notify) {
190
- // eslint-disable-next-line @typescript-eslint/no-unused-expressions
191
- errorCallback
192
- ? errorCallback()
193
- : this.notificationsService.error(this.transloco.translate('chat.saveChatConfig.fail', { value: this.chatInstanceId }));
194
- }
195
- console.error("Could not patch assistants!", error);
196
- }, () => {
197
- if (notify) {
198
- // eslint-disable-next-line @typescript-eslint/no-unused-expressions
199
- successCallback
200
- ? successCallback()
201
- : this.notificationsService.success(this.transloco.translate('chat.saveChatConfig.success', { value: this.chatInstanceId }));
202
- }
382
+ this.assistantConfigurationService.updateChatConfig(config, hashes, notify, successCallback, errorCallback);
383
+ }
384
+ /**
385
+ * Overrides the logged in user
386
+ */
387
+ overrideUser() {
388
+ const { userOverrideActive, userOverride } = globalConfig;
389
+ if (!(userOverrideActive && userOverride)) {
390
+ this.userOverride$.next(false);
391
+ return;
392
+ }
393
+ // Prepare the payload to send to the OverrideUser method
394
+ const data = {
395
+ instanceId: this.chatInstanceId,
396
+ user: userOverride.username,
397
+ domain: userOverride.domain
398
+ };
399
+ // Invoke the OverrideUser method and handle errors
400
+ this.connection.invoke('OverrideUser', data)
401
+ .then((res) => this.userOverride$.next(!!res))
402
+ .catch(error => {
403
+ console.error('Error invoking OverrideUser:', error);
404
+ return Promise.resolve(); // Return a resolved promise to handle the error and prevent unhandled promise rejection when no further error handling exists downstream
203
405
  });
204
406
  }
407
+ /**
408
+ * Calls the Fetch API to retrieve a new message given all previous messages
409
+ */
410
+ fetch(messages, query) {
411
+ return this.assistantWsFramesService.fetch(messages, query);
412
+ }
413
+ /**
414
+ * Return the list of models available on the server
415
+ */
416
+ listModels() {
417
+ return this.assistantMetadataService.listModels();
418
+ }
419
+ /**
420
+ * Return the list of functions available on the server AND matching enabled functions in the chat config
421
+ */
422
+ listFunctions() {
423
+ return this.assistantMetadataService.listFunctions();
424
+ }
425
+ /**
426
+ * Stops the assistant answer generation and cancels all the ongoing and pending related tasks
427
+ */
428
+ stopGeneration() {
429
+ return this.assistantWsFramesService.stopGeneration();
430
+ }
205
431
  /**
206
432
  * A handler for quota updates each time the chat is invoked.
207
433
  * It emits the updated quota to the quota$ subject, emits accordingly the updated user's tokens consumption and notifies the user if the max quota is reached.
@@ -209,17 +435,7 @@ export class ChatService {
209
435
  * @param propagateError Whether to propagate the error to the caller
210
436
  */
211
437
  updateQuota(quota, propagateError = false) {
212
- this.quota$.next(quota);
213
- const nextResetDate = this.formatDateTime(quota.nextResetUTC + "+00:00"); // This +00:00 is to ensure dates will be properly converted to local time
214
- const consumptionPercentage = Math.round((quota.tokenCount * 100 / quota.periodTokens) * 100) / 100;
215
- this.userTokenConsumption$.next({ percentage: consumptionPercentage, nextResetDate });
216
- if (quota.maxQuotaReached) {
217
- this.generateAuditEvent('ast-quota.exceeded', {});
218
- const msg = `Sorry, you have exceeded the allowed quota. Please retry starting from ${nextResetDate}.`;
219
- this.notificationsService.error(msg);
220
- if (propagateError)
221
- throw new Error(msg);
222
- }
438
+ this.assistantTokensTrackingService.updateQuota(quota, propagateError);
223
439
  }
224
440
  /**
225
441
  * A handler for chat usage metrics each time the generation of the assistant response is completed.
@@ -227,10 +443,7 @@ export class ChatService {
227
443
  * @param chatUsageMetrics The chat usage metrics
228
444
  */
229
445
  updateChatUsageMetrics(chatUsageMetrics) {
230
- this.chatUsageMetrics$.next(chatUsageMetrics);
231
- const currentModel = this.getModel(this.assistantConfig$.value.defaultValues.service_id, this.assistantConfig$.value.defaultValues.model_id);
232
- const consumptionPercentage = Math.round((chatUsageMetrics.totalTokenCount * 100 / (currentModel.contextWindowSize - currentModel.maxGenerationSize)) * 100) / 100;
233
- this.chatTokenConsumption$.next({ percentage: consumptionPercentage });
446
+ this.assistantTokensTrackingService.updateChatUsageMetrics(chatUsageMetrics);
234
447
  }
235
448
  /**
236
449
  * Get the model description for the given (serviceId + modelId)
@@ -248,6 +461,110 @@ export class ChatService {
248
461
  }
249
462
  return model;
250
463
  }
464
+ /**
465
+ * Fetch the list saved chats belonging to a specific instance of the assistant
466
+ */
467
+ listSavedChat() {
468
+ this.savedChatsService.listChats();
469
+ }
470
+ /**
471
+ * Return the saved chat with the given id, if exists. Otherwise, return undefined
472
+ * @param id The id of the saved chat
473
+ */
474
+ getSavedChat(id) {
475
+ return this.savedChatsService.getChatById(id);
476
+ }
477
+ /**
478
+ * Check if a saved chat with the given id already exists
479
+ * @param id The id of the saved chat
480
+ * @returns True if the saved chat exists, false otherwise
481
+ */
482
+ isExistingSavedChat(id) {
483
+ return this.savedChatsService.isExistingChat(id);
484
+ }
485
+ /**
486
+ * Save a chat with the given messages
487
+ * @param messages The messages to add to the saved chat index
488
+ * @returns The saved chat
489
+ */
490
+ addSavedChat(id, messages) {
491
+ return this.savedChatsService.addChat(id, messages);
492
+ }
493
+ /**
494
+ * Update a saved chat with the given id.
495
+ * @param id The id of the saved chat
496
+ * @param name The new name of the saved chat, if provided
497
+ * @param messages The messages to update the saved chat history, if provided
498
+ * @returns True if the saved chat has been successfully updated
499
+ */
500
+ updateSavedChat(id, name, messages) {
501
+ return this.savedChatsService.updateChat(id, name, messages);
502
+ }
503
+ /**
504
+ * Bulk delete of saved chats matching the given ids
505
+ * @param ids List of ids of the saved chats to delete
506
+ * @returns The number of deleted chats
507
+ */
508
+ deleteSavedChat(ids) {
509
+ return this.savedChatsService.deleteChat(ids);
510
+ }
511
+ getDebugMessage(message) {
512
+ return this.debugMessageService.getDebugMessage(message);
513
+ }
514
+ /**
515
+ * Initialize out-of-the-box handlers
516
+ * It is a placeholder for non-streaming scenarios, where you invoke a specific hub method, and the server responds with frame message(s)
517
+ */
518
+ initMessageHandlers() {
519
+ this.assistantWsFramesService.initMessageHandlers();
520
+ }
521
+ /**
522
+ * Override and register the entire _messageHandlers map by merging the provided map with the default one
523
+ * @param _messageHandlers
524
+ */
525
+ overrideMessageHandlers(_messageHandlers) {
526
+ this.assistantWsFramesService.overrideMessageHandlers(_messageHandlers);
527
+ }
528
+ /**
529
+ * Add a listener for a specific event.
530
+ * If a listener for this same event already exists, it will be overridden.
531
+ * If the listener has "isGlobalHandler" set to true, it will be registered to the hub connection.
532
+ * @param eventName Name of the event to register a listener for
533
+ * @param eventHandler The handler to be called when the event is received
534
+ */
535
+ addMessageHandler(eventName, eventHandler) {
536
+ this.assistantWsFramesService.addMessageHandler(eventName, eventHandler);
537
+ }
538
+ /**
539
+ * Remove a listener for a specific event from the _messageHandlers map and unsubscribe from receiving messages for this event from the SignalR hub.
540
+ * @param eventName Name of the event to remove the listener for
541
+ */
542
+ removeMessageHandler(eventName) {
543
+ this.assistantWsFramesService.removeMessageHandler(eventName);
544
+ }
545
+ /**
546
+ * Build a connection to the signalR websocket and register default listeners to the methods defined in the server hub class
547
+ * @param options The options for the connection. It overrides the default options
548
+ * @param logLevel Define the log level displayed in the console
549
+ * @returns Promise that resolves when the connection is built
550
+ */
551
+ buildConnection(options) {
552
+ return this.signalRConnectionService.buildConnection(options);
553
+ }
554
+ /**
555
+ * Start the connection
556
+ * @returns Promise that resolves when the connection is started
557
+ */
558
+ startConnection() {
559
+ return this.signalRConnectionService.startConnection();
560
+ }
561
+ /**
562
+ * Stop the connection
563
+ * @returns Promise that resolves when the connection is stopped
564
+ */
565
+ stopConnection() {
566
+ return this.signalRConnectionService.stopConnection();
567
+ }
251
568
  /**
252
569
  * Generate an audit event with the given type and details. The generated audit event is sent afterwards via the AuditWebService
253
570
  * @param type Audit event type
@@ -262,9 +579,11 @@ export class ChatService {
262
579
  "instance-id": this.chatInstanceId,
263
580
  "chat-id": id || this.chatId,
264
581
  "service-id": this.assistantConfig$.value.defaultValues.service_id,
265
- "model-id": this.assistantConfig$.value.defaultValues.model_id,
266
- "is-user-input": false
582
+ "model-id": this.assistantConfig$.value.defaultValues.model_id
267
583
  };
584
+ if (type === "ast-message.message") {
585
+ baseDetails["is-user-input"] = false;
586
+ }
268
587
  const audit = {
269
588
  type,
270
589
  detail: {
@@ -272,143 +591,7 @@ export class ChatService {
272
591
  ...details
273
592
  }
274
593
  };
275
- const response = await Audit.notify(audit);
276
- console.log("Audit response", response);
277
- }
278
- /**
279
- * Traverse the array from the end and track the first 'assistant' message among the last group of "assistant" messages where display is true
280
- * @param array The array of ChatMessage to traverse
281
- * @returns The index of the first visible assistant message among the last group of "assistant" messages in the array
282
- */
283
- firstVisibleAssistantMessageIndex(array) {
284
- if (!array) {
285
- return -1;
286
- }
287
- let index = array.length - 1;
288
- let firstVisibleAssistantMessageIndex = -1;
289
- while (index >= 0 && array[index].role === 'assistant') {
290
- if (array[index].additionalProperties.display === true) {
291
- firstVisibleAssistantMessageIndex = index;
292
- }
293
- index--;
294
- }
295
- return firstVisibleAssistantMessageIndex;
296
- }
297
- /**
298
- * Traverse the array from the end and pick the last 'assistant' message among the last group of "assistant" messages where display is true
299
- * @param array The array of ChatMessage to traverse
300
- * @returns The index of the last visible assistant message among the last group of "assistant" messages in the array
301
- */
302
- lastVisibleAssistantMessageIndex(array) {
303
- if (!array) {
304
- return -1;
305
- }
306
- let index = array.length - 1;
307
- let lastVisibleAssistantMessageIndex = -1;
308
- while (index >= 0 && array[index].role === 'assistant') {
309
- if (array[index].additionalProperties.display === true) {
310
- lastVisibleAssistantMessageIndex = index;
311
- break;
312
- }
313
- index--;
314
- }
315
- return lastVisibleAssistantMessageIndex;
316
- }
317
- /**
318
- * Format a date string in UTC to a local date string
319
- * @param value Date string in UTC to format
320
- * @returns A formatted local date string
321
- */
322
- formatDateTime(value) {
323
- const localDate = toDate(parseISO(value));
324
- const formatter = new Intl.DateTimeFormat(undefined, {
325
- year: 'numeric',
326
- month: 'short',
327
- day: 'numeric',
328
- hour: '2-digit',
329
- minute: '2-digit',
330
- second: '2-digit',
331
- timeZoneName: 'short'
332
- });
333
- return formatter.format(localDate);
334
- }
335
- /**
336
- * Takes a text prompt that may contain placeholders for variables
337
- * and replaces these placeholders if it finds a match in the given
338
- * context object.
339
- *
340
- * @example
341
- * const p = "Hello, [[user.name]]! You have [[user.notifications.length]] new notifications.";
342
- * const context = {
343
- * user: {
344
- * name: "Alice",
345
- * notifications: ["Message from Bob", "Reminder for meeting"]
346
- * }
347
- * };
348
- * const formattedPrompt = formatPrompt(p, context);
349
- * console.log(formattedPrompt); // Output: "Hello, Alice! You have 2 new notifications."
350
- */
351
- static formatPrompt(prompt, context) {
352
- return prompt.replace(/\[\[(.*?)\]\]/g, (match, expr) => {
353
- // Simple dot notation resolver
354
- const keys = expr.trim().split(".");
355
- let value = context;
356
- for (const key of keys) {
357
- if (value && typeof value === "object" && key in value) {
358
- value = value[key];
359
- }
360
- else {
361
- return match;
362
- }
363
- }
364
- return value ?? match;
365
- });
366
- }
367
- /**
368
- * Determines a time-based key for a given date to be used for translations or formatting.
369
- * The key represents a relative time period such as "today", "yesterday", "this week", etc.
370
- * If the date does not fall into any predefined relative time period, it returns the year as a string.
371
- *
372
- * @param date - The date for which the time key is to be determined.
373
- * @returns A string representing the time key, which can be used for translation or display purposes.
374
- */
375
- getTimeKey(date) {
376
- if (isToday(date)) {
377
- return this.transloco.translate('chat.today');
378
- }
379
- else if (isYesterday(date)) {
380
- return this.transloco.translate('chat.yesterday');
381
- }
382
- else if (isThisWeek(date)) {
383
- return this.transloco.translate('chat.thisWeek');
384
- }
385
- else if (differenceInDays(endOfYesterday(), date) <= 7) {
386
- return this.transloco.translate('chat.lastWeek');
387
- }
388
- else if (isThisMonth(date)) {
389
- return this.transloco.translate('chat.thisMonth');
390
- }
391
- else if (differenceInMonths(endOfYesterday(), date) <= 1) {
392
- return this.transloco.translate('chat.lastMonth');
393
- }
394
- else if (isThisQuarter(date)) {
395
- return this.transloco.translate('chat.thisQuarter');
396
- }
397
- else if (differenceInMonths(endOfYesterday(), date) <= 3) {
398
- return this.transloco.translate('chat.lastQuarter');
399
- }
400
- else if (isThisYear(date)) {
401
- return this.transloco.translate('chat.thisYear');
402
- }
403
- else if (differenceInYears(endOfYesterday(), date) === 1) {
404
- return this.transloco.translate('chat.lastYear');
405
- }
406
- else {
407
- return format(date, 'yyyy');
408
- }
409
- }
410
- getCurrentLocaleName() {
411
- return this.localID || '';
594
+ await Audit.notify(audit);
412
595
  }
413
596
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ChatService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
414
597
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ChatService }); }
@@ -416,4 +599,4 @@ export class ChatService {
416
599
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ChatService, decorators: [{
417
600
  type: Injectable
418
601
  }] });
419
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hhdC5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vcHJvamVjdHMvYXNzaXN0YW50L2NoYXQvY2hhdC5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsU0FBUyxFQUFFLE1BQU0sRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUM5RCxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUN0RCxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsa0JBQWtCLEVBQUUsaUJBQWlCLEVBQUUsY0FBYyxFQUFFLE1BQU0sRUFBRSxXQUFXLEVBQUUsYUFBYSxFQUFFLFVBQVUsRUFBRSxVQUFVLEVBQUUsT0FBTyxFQUFFLFdBQVcsRUFBRSxRQUFRLEVBQUUsTUFBTSxFQUFFLE1BQU0sVUFBVSxDQUFDO0FBQ3ZNLE9BQU8sRUFBRSxlQUFlLEVBQWMsTUFBTSxNQUFNLENBQUM7QUFFbkQsT0FBTyxFQUFFLEtBQUssRUFBUyxRQUFRLEVBQUUsY0FBYyxFQUFFLGlCQUFpQixFQUFFLElBQUksRUFBRSxNQUFNLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUUxRyxPQUFPLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUNyRSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDcEQsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQzFELE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBQ3ZFLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBQ2hFLE9BQU8sRUFBRSxzQkFBc0IsRUFBRSxNQUFNLGtDQUFrQyxDQUFDO0FBQzFFLE9BQU8sRUFBdU4sZ0JBQWdCLEVBQUUsTUFBTSxTQUFTLENBQUM7QUFDaFEsT0FBTyxFQUFFLHlCQUF5QixFQUFFLE1BQU0sd0JBQXdC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QVMsQ0FBQyxTQUFTLENBQUMsZUFBZSxDQUFDLENBQUM7UUFDbkQsQ0FBQzthQUFNLElBQUksaUJBQWlCLENBQUMsY0FBYyxFQUFFLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7WUFDM0QsT0FBTyxJQUFJLENBQUMsU0FBUyxDQUFDLFNBQVMsQ0FBQyxlQUFlLENBQUMsQ0FBQztRQUNuRCxDQUFDO2FBQU0sQ0FBQztZQUNOLE9BQU8sTUFBTSxDQUFDLElBQUksRUFBRSxNQUFNLENBQUMsQ0FBQztRQUM5QixDQUFDO0lBQ0gsQ0FBQztJQUVILG9CQUFvQjtRQUNsQixPQUFPLElBQUksQ0FBQyxPQUFPLElBQUksRUFBRSxDQUFDO0lBQzVCLENBQUM7K0dBbGZtQixXQUFXO21IQUFYLFdBQVc7OzRGQUFYLFdBQVc7a0JBRGhDLFVBQVUiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3RhYmxlLCBMT0NBTEVfSUQsIGluamVjdCB9IGZyb20gXCJAYW5ndWxhci9jb3JlXCI7XG5pbXBvcnQgeyBUcmFuc2xvY29TZXJ2aWNlIH0gZnJvbSBcIkBqc3ZlcnNlL3RyYW5zbG9jb1wiO1xuaW1wb3J0IHsgZGlmZmVyZW5jZUluRGF5cywgZGlmZmVyZW5jZUluTW9udGhzLCBkaWZmZXJlbmNlSW5ZZWFycywgZW5kT2ZZZXN0ZXJkYXksIGZvcm1hdCwgaXNUaGlzTW9udGgsIGlzVGhpc1F1YXJ0ZXIsIGlzVGhpc1dlZWssIGlzVGhpc1llYXIsIGlzVG9kYXksIGlzWWVzdGVyZGF5LCBwYXJzZUlTTywgdG9EYXRlIH0gZnJvbSBcImRhdGUtZm5zXCI7XG5pbXBvcnQgeyBCZWhhdmlvclN1YmplY3QsIE9ic2VydmFibGUgfSBmcm9tIFwicnhqc1wiO1xuXG5pbXBvcnQgeyBBdWRpdCwgUXVlcnksIGZldGNoQXBwLCBmZXRjaFByaW5jaXBhbCwgZmV0Y2hVc2VyU2V0dGluZ3MsIGd1aWQsIHNoYTUxMiB9IGZyb20gXCJAc2luZXF1YS9hdG9taWNcIjtcblxuaW1wb3J0IHsgRGlhbG9nVXBkYXRlc0NvbXBvbmVudCB9IGZyb20gXCIuL2RpYWxvZ3MvdXBkYXRlcy5jb21wb25lbnRcIjtcbmltcG9ydCB7IEFwcFNlcnZpY2UgfSBmcm9tIFwiLi9zZXJ2aWNlcy9hcHAuc2VydmljZVwiO1xuaW1wb3J0IHsgRGlhbG9nU2VydmljZSB9IGZyb20gXCIuL3NlcnZpY2VzL2RpYWxvZy5zZXJ2aWNlXCI7XG5pbXBvcnQgeyBOb3RpZmljYXRpb25zU2VydmljZSB9IGZyb20gXCIuL3NlcnZpY2VzL25vdGlmaWNhdGlvbi5zZXJ2aWNlXCI7XG5pbXBvcnQgeyBQcmluY2lwYWxTZXJ2aWNlIH0gZnJvbSBcIi4vc2VydmljZXMvcHJpbmNpcGFsLnNlcnZpY2VcIjtcbmltcG9ydCB7IFVzZXJTZXR0aW5nc1dlYlNlcnZpY2UgfSBmcm9tIFwiLi9zZXJ2aWNlcy91c2VyLXNldHRpbmdzLnNlcnZpY2VcIjtcbmltcG9ydCB7IENoYXRDb25maWcsIENoYXRNZXNzYWdlLCBDaGF0UmVzcG9uc2UsIENoYXRVc2FnZU1ldHJpY3MsIERlbGV0ZVNhdmVkQ2hhdFJlc3BvbnNlLCBHbGxtRnVuY3Rpb24sIEdsbG1Nb2RlbERlc2NyaXB0aW9uLCBRdW90YSwgU2F2ZWRDaGF0LCBTYXZlZENoYXRIaXN0b3J5LCBTYXZlZENoYXRSZXNwb25zZSwgVG9rZW5Db25zdW1wdGlvbiwgVXNlclRva2VuQ29uc3VtcHRpb24sIGNoYXRDb25maWdTY2hlbWEgfSBmcm9tIFwiLi90eXBlc1wiO1xuaW1wb3J0IHsgZ2V0QXNzaXN0YW50SnNvbkZyb21DQ0FwcCB9IGZyb20gXCIuL3V0aWxzL2Fzc2lzdGFudC1qc29uXCI7XG5cbkBJbmplY3RhYmxlKClcbmV4cG9ydCBhYnN0cmFjdCBjbGFzcyBDaGF0U2VydmljZSB7XG5cbiAgcmVhZG9ubHkgbG9jYWxJRCA9IGluamVjdChMT0NBTEVfSUQsIHtvcHRpb25hbDogdHJ1ZX0pO1xuXG4gIC8qKiBOYW1lIG9mIHRoZSBhc3Npc3RhbnQgcGx1Z2luIE9SIHdlYnNvY2tldCBlbmRwb2ludC4gKi9cbiAgUkVRVUVTVF9VUkw6IHN0cmluZztcbiAgLyoqIEVtaXQgdHJ1ZSBvbmNlIHRoZSBpbml0aWFsaXphdGlvbiBvZiB0aGUgYXNzaXN0YW50IHByb2Nlc3MgaXMgZG9uZS4gKi9cbiAgaW5pdFByb2Nlc3MkID0gbmV3IEJlaGF2aW9yU3ViamVjdDxib29sZWFuPihmYWxzZSk7XG4gIC8qKiBFbWl0IHRydWUgb25jZSB0aGUgaW5pdGlhbGl6YXRpb24gb2YgdGhlIGFzc2lzdGFudCBjb25maWcgaXMgZG9uZS4gKi9cbiAgaW5pdENvbmZpZyQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PGJvb2xlYW4+KGZhbHNlKTtcbiAgLyoqIEVtaXQgdGhlIGdsb2JhbCBjb25maWd1cmF0aW9uIG9mIHRoZSBhc3Npc3RhbnQuICovXG4gIGFzc2lzdGFudENvbmZpZyQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PENoYXRDb25maWcgfCB1bmRlZmluZWQ+KHVuZGVmaW5lZCk7XG4gIC8qKiBFbWl0IHRydWUgaWYgdGhlIHVzZXIgaGFzIGJlZW4gb3ZlcnJpZGRlbiwgZmFsc2Ugb3RoZXJ3aXNlLiAqL1xuICB1c2VyT3ZlcnJpZGUkID0gbmV3IEJlaGF2aW9yU3ViamVjdDxib29sZWFuIHwgdW5kZWZpbmVkPih1bmRlZmluZWQpO1xuICAvKipcbiAgICogRW1pdCB0cnVlIGlmIHRoZSBmZXRjaCBvZiBhbiBhc3Npc3RhbnQncyByZXNwb25zZSBpcyBvbmdvaW5nIChpdCBpbmNsdWRlcyBTdHJlYW1pbmcgc3RhdHVzIG9mIHRoZSBhc3Npc3RhbnQgZW5kcG9pbnQgQU5EIHNhdmluZyB0aGUgZGlzY3Vzc2lvbiBpZiBzYXZlIENoYXQgaXMgZW5hYmxlZCkuXG4gICAqIFRoaXMgaXMgdXNlZCB0byBwcmV2ZW50IG11bHRpcGxlIGZldGNoZXMgYXQgdGhlIHNhbWUgdGltZS5cbiAgICogVHlwaWNhbGx5LCB0aGVyZSBpcyBubyBwcm9ibGVtIGNoYWluaW5nIGZldGNoZXMsIGJ1dCB3aGVuIGZvcmNpbmcgYSByZWxvYWQgYWZ0ZXIgcXVlcnkgY2hhbmdlcyBjYXNlcywgaXQgY2FuJ3QgYmUgYWxsb3dlZCBiZWNhdXNlIGl0IGJyZWFrcyB0aGUgd2hvbGUgYnVzaW5lc3MgbG9naWMuXG4gICovXG4gIHN0cmVhbWluZyQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PGJvb2xlYW4+KGZhbHNlKTtcbiAgLyoqIFN0b3JlIHRoZSBtZXNzYWdlcyBoaXN0b3J5IG9mIHRoZSBjdXJyZW50IGNoYXQuICovXG4gIGNoYXRIaXN0b3J5OiBDaGF0TWVzc2FnZVtdIHwgdW5kZWZpbmVkO1xuICAvKiogTGlzdCBvZiBtb2RlbHMgYXZhaWxhYmxlIG9uIHRoZSBzZXJ2ZXIuICovXG4gIG1vZGVsczogR2xsbU1vZGVsRGVzY3JpcHRpb25bXSB8IHVuZGVmaW5lZDtcbiAgLyoqIExpc3Qgb2YgZnVuY3Rpb25zIGF2YWlsYWJsZSBvbiB0aGUgc2VydmVyLiAqL1xuICBmdW5jdGlvbnM6IEdsbG1GdW5jdGlvbltdIHwgdW5kZWZpbmVkO1xuICAvKiogTGlzdCBvZiBzYXZlZCBjaGF0cy4gKi9cbiAgc2F2ZWRDaGF0cyQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PFNhdmVkQ2hhdFtdPihbXSk7XG4gIC8qKiBXaGV0aGVyIHRoZXJlIGlzIGFuIGVycm9yIHdpdGggc2F2ZWQgY2hhdHMuICovXG4gIHNhdmVkQ2hhdHNFcnJvciQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PGJvb2xlYW4+KGZhbHNlKTtcbiAgLyoqIEVtaXQgdGhlIHNhdmVkIGNoYXQgdG8gbG9hZC4gKi9cbiAgbG9hZFNhdmVkQ2hhdCQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PFNhdmVkQ2hhdCB8IHVuZGVmaW5lZD4odW5kZWZpbmVkKTtcbiAgLyoqIEVtaXQgdGhlIHF1b3RhIGVhY2ggdGltZSB0aGUgY2hhdCBpcyBpbnZva2VkLiAqL1xuICBxdW90YSQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PFF1b3RhIHwgdW5kZWZpbmVkPih1bmRlZmluZWQpO1xuICAvKiogRW1pdCB0aGUgY2FsY3VsYXRlZCB1c2VyJ3MgdG9rZW4gY29uc3VtcHRpb24gYmFzZWQgb24gdGhlIHF1b3RhLiAqL1xuICB1c2VyVG9rZW5Db25zdW1wdGlvbiQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PFVzZXJUb2tlbkNvbnN1bXB0aW9uIHwgdW5kZWZpbmVkPih1bmRlZmluZWQpO1xuICAvKiogRW1pdCB0aGUgY2hhdCB1c2FnZSBtZXRyaWNzIGVhY2ggdGltZSB0aGUgZ2VuZXJhdGlvbiBvZiB0aGUgYXNzaXN0YW50IHJlc3BvbnNlIGlzIGNvbXBsZXRlZC4gKi9cbiAgY2hhdFVzYWdlTWV0cmljcyQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PENoYXRVc2FnZU1ldHJpY3MgfCB1bmRlZmluZWQ+KHVuZGVmaW5lZCk7XG4gIC8qKiBFbWl0IHRoZSBjYWxjdWxhdGVkIGNoYXQncyB0b2tlbiBjb25zdW1wdGlvbiBiYXNlZCBvbiB0aGUgY2hhdCB1c2FnZSBtZXRyaWNzLiAqL1xuICBjaGF0VG9rZW5Db25zdW1wdGlvbiQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PFRva2VuQ29uc3VtcHRpb24gfCB1bmRlZmluZWQ+KHVuZGVmaW5lZCk7XG4gIC8qKiBFbWl0IHRydWUgaWYgXCJDYW5jZWxUYXNrc1wiIGlzIG9uZ29pbmcuICovXG4gIHN0b3BwaW5nR2VuZXJhdGlvbiQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PGJvb2xlYW4+KGZhbHNlKTtcbiAgLyoqIEluc3RhbmNlIElEIG9mIHRoZSBjaGF0IHNlcnZpY2UgZGVmaW5pbmcgdGhlIGFzc2lzdGFudCBpbnN0YW5jZS4gKi9cbiAgcHJpdmF0ZSBfY2hhdEluc3RhbmNlSWQ6IHN0cmluZztcbiAgLyoqIElEIG9mIHRoZSBjdXJyZW50ICoqc2F2ZWQgY2hhdCoqIGRpc2N1c3Npb24gd2hpY2ggaXMgdXNlZCB0byB1cGRhdGUvZ2V0L2RlbGV0ZSBpdC4gKi9cbiAgcHJpdmF0ZSBfc2F2ZWRDaGF0SWQ6IHN0cmluZyB8IHVuZGVmaW5lZDtcbiAgLyoqIEdlbmVyYXRlZCBHVUlEIGZvciB0aGUgY3VycmVudCBub24tc2F2ZWQgY2hhdCBkaXNjdXNzaW9uIHVzZWQgdG8gaWRlbnRpZnkgYXVkaXQgZXZlbnRzLlxuICAgKiBJZiB0aGUgY2hhdCBpcyBzYXZlZCwgdGhlIHNhdmVkQ2hhdElkIGlzIGluaXRpYWxpemVkIHdpdGggdGhlIHZhbHVlIG9mIHRoaXMgY2hhdElkLlxuICAgKi9cbiAgcHJpdmF0ZSBfY2hhdElkOiBzdHJpbmc7XG5cbiAgcHVibGljIHVzZXJTZXR0aW5nc1NlcnZpY2UgPSBpbmplY3QoVXNlclNldHRpbmdzV2ViU2VydmljZSk7XG4gIHB1YmxpYyBub3RpZmljYXRpb25zU2VydmljZSA9IGluamVjdChOb3RpZmljYXRpb25zU2VydmljZSk7XG4gIHB1YmxpYyBhcHBTZXJ2aWNlID0gaW5qZWN0KEFwcFNlcnZpY2UpO1xuICBwdWJsaWMgbW9kYWxTZXJ2aWNlID0gaW5qZWN0KERpYWxvZ1NlcnZpY2UpO1xuICBwdWJsaWMgcHJpbmNpcGFsU2VydmljZSA9IGluamVjdChQcmluY2lwYWxTZXJ2aWNlKTtcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IHRyYW5zbG9jbyA9IGluamVjdChUcmFuc2xvY29TZXJ2aWNlKTtcbiAgLyoqXG4gICAqIEluaXRpYWxpemUgdGhlIGNoYXQgcHJvY2Vzc1xuICAgKi9cbiAgYWJzdHJhY3QgaW5pdCgpOiBPYnNlcnZhYmxlPGJvb2xlYW4+O1xuXG4gIC8qKlxuICAgKiBJbml0aWFsaXplIHRoZSBSRVFVRVNUX1VSTFxuICAgKi9cbiAgYWJzdHJhY3QgZ2V0UmVxdWVzdHNVcmwoKTogdm9pZDtcblxuICBnZXQgYXNzaXN0YW50cygpOiBhbnkge1xuICAgIGlmICghdGhpcy51c2VyU2V0dGluZ3NTZXJ2aWNlLnVzZXJTZXR0aW5ncylcbiAgICAgIHRoaXMudXNlclNldHRpbmdzU2VydmljZS51c2VyU2V0dGluZ3MgPSB7fTtcbiAgICBpZiAoIXRoaXMudXNlclNldHRpbmdzU2VydmljZS51c2VyU2V0dGluZ3NbXCJhc3Npc3RhbnRzXCJdKVxuICAgICAgdGhpcy51c2VyU2V0dGluZ3NTZXJ2aWNlLnVzZXJTZXR0aW5nc1tcImFzc2lzdGFudHNcIl0gPSB7fTtcbiAgICByZXR1cm4gIHRoaXMudXNlclNldHRpbmdzU2VydmljZS51c2VyU2V0dGluZ3NbXCJhc3Npc3RhbnRzXCJdO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCB0aGUgaW5zdGFuY2UgSUQgb2YgdGhlIGNoYXQgc2VydmljZVxuICAgKiBAcmV0dXJucyBUaGUgaW5zdGFuY2UgSUQgb2YgdGhlIGNoYXQgc2VydmljZVxuICAgKi9cbiAgZ2V0IGNoYXRJbnN0YW5jZUlkKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMuX2NoYXRJbnN0YW5jZUlkO1xuICB9XG5cbiAgLyoqXG4gICAqIFBlcnNpc3QgdGhlIGluc3RhbmNlIElEIG9mIHRoZSBjaGF0IHNlcnZpY2VcbiAgICogQHBhcmFtIGluc3RhbmNlSWQgVGhlIGluc3RhbmNlIElEIG9mIHRoZSBjaGF0IHNlcnZpY2VcbiAgICovXG4gIHNldENoYXRJbnN0YW5jZUlkKGluc3RhbmNlSWQ6IHN0cmluZykge1xuICAgIHRoaXMuX2NoYXRJbnN0YW5jZUlkID0gaW5zdGFuY2VJZDtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgdGhlIElEIG9mIHRoZSBjdXJyZW50IGNoYXQgZGlzY3Vzc2lvbiB3aGljaCBpcyB1c2VkIHRvIHNhdmUvZ2V0L2RlbGV0ZSBpdFxuICAgKiBAcmV0dXJucyBUaGUgSUQgb2YgdGhlIGN1cnJlbnQgY2hhdCBkaXNjdXNzaW9uXG4gICAqL1xuICBnZXQgc2F2ZWRDaGF0SWQoKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgICByZXR1cm4gdGhpcy5fc2F2ZWRDaGF0SWQ7XG4gIH1cblxuICAvKipcbiAgICogUGVyc2lzdCB0aGUgSUQgb2YgdGhlIGN1cnJlbnQgY2hhdCBkaXNjdXNzaW9uIHdoaWNoIGlzIHVzZWQgdG8gc2F2ZS9nZXQvZGVsZXRlIGl0XG4gICAqIEBwYXJhbSBzYXZlZENoYXRJZCBUaGUgSUQgb2YgdGhlIGN1cnJlbnQgY2hhdCBkaXNjdXNzaW9uIHdoaWNoIGlzIHVzZWQgdG8gc2F2ZS9nZXQvZGVsZXRlIGl0XG4gICAqL1xuICBzZXRTYXZlZENoYXRJZChzYXZlZENoYXRJZDogc3RyaW5nIHwgdW5kZWZpbmVkKSB7XG4gICAgdGhpcy5fc2F2ZWRDaGF0SWQgPSBzYXZlZENoYXRJZDtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgdGhlIElEIG9mIHRoZSBjdXJyZW50IGNoYXQgZGlzY3Vzc2lvbiB3aGljaCBpcyB1c2VkIHRvIGlkZW50aWZ5IGF1ZGl0IGV2ZW50c1xuICAgKiBAcmV0dXJucyBUaGUgSUQgb2YgdGhlIGN1cnJlbnQgY2hhdCBkaXNjdXNzaW9uXG4gICAqL1xuICBnZXQgY2hhdElkKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMuX2NoYXRJZDtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZW5lcmF0ZSBhbiBHVUlEIGZvciB0aGUgY3VycmVudCBjaGF0IGRpc2N1c3Npb24gd2hpY2ggaXMgdXNlZCB0byBpZGVudGlmeSBhdWRpdCBldmVudHNcbiAgICogSWYgdGhlIGRpc2N1c3Npb24gaXMgc2F2ZWQsIHRoZSBzYXZlZENoYXRJZCBpcyBpbml0aWFsaXplZCB3aXRoIHRoZSB2YWx1ZSBvZiB0aGlzIGNoYXRJZFxuICAgKiBAcGFyYW0gY2hhdElkIGlmIHByb3ZpZGVkLCBpdCB3aWxsIGJlIGNvbnNpZGVyZWQgYXMgdGhlIElEIG9mIHRoZSBjdXJyZW50IGNoYXQgZGlzY3Vzc2lvbiB3aGljaCBpcyB1c2VkIHRvIGlkZW50aWZ5IGF1ZGl0IGV2ZW50c1xuICAgKi9cbiAgZ2VuZXJhdGVDaGF0SWQoY2hhdElkPzogc3RyaW5nKSB7XG4gICAgdGhpcy5fY2hhdElkID0gY2hhdElkIHx8IGd1aWQoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBJbml0aWFsaXplIHRoZSBjaGF0IGNvbmZpZyBieSBtYW5hZ2luZyBPTkxZIHN1Yi1vYmplY3QgKipkZWZhdWx0VmFsdWVzKiogY29uZmlncyBvZiB0aGUgc3RhbmRhcmQgYXBwIGNvbmZpZyAoZGVmaW5lZCBpbiB0aGUgY3VzdG9taXphdGlvbiBqc29uIHRhYiApIGFuZCB0aGUgdXNlciBwcmVmZXJlbmNlcy5cbiAgICogVG8gZG8gc28sIGEgdHJhY2tpbmcgbWVjaGFuaXNtIGlzIGltcGxlbWVudGVkIHRvIG5vdGlmeSB0aGUgdXNlciBhYm91dCB0aGUgYXZhaWxhYmxlIHVwZGF0ZXMgaW4gdGhlIGRlZmF1bHRWYWx1ZXMgb2JqZWN0IG9mIHRoZSBzdGFuZGFyZCBhcHAgY29uZmlnLlxuICAgKiBUaGUgcmVzdCBvZiB0aGUgY29uZmlnIG9iamVjdCBjb21pbmcgZnJvbSBcInN0YW5kYXJkIGFwcCBjb25maWdcIiBpcyB1c2VkIGFzIGl0IGlzIHdpdGhvdXQgYW55IG92ZXJyaWRlLlxuICAgKiBUaHVzLCB0aGUgdXNlciBwcmVmZXJlbmNlcyBhcmUgdXNlZCBvbmx5IGZvciB0aGUgZGVmYXVsdFZhbHVlcyBvYmplY3QuXG4gICAqIFRoaXMgcHJvdmlkZSBhIGNlbnRyYWxpemVkIHdheSB0byBtYW5hZ2UgdGhlIHJlc3Qgb2YgdGhlIGNvbmZpZyBvYmplY3QgYnkgYWRtaW5zIGFuZCBlbnN1cmUgYSB1bmlxdWUgY29tbW9uIGJlaGF2aW9yIGZvciBhbGwgdXNlcnMuXG4gICAqL1xuICBhc3luYyBpbml0Q2hhdENvbmZpZygpIHtcbiAgICAvLyBmZXRjaCB0aGUgc3RhbmRhcmQgYXBwIGNvbmZpZyB0byBnZXQgdGhlIGRlZmF1bHRWYWx1ZXMgb2YgdGhlIGNoYXQgY29uZmlnIGZvciB0aGUgZ2l2ZW4gaW5zdGFuY2VcbiAgICAvLyBQZXJzaXN0IHRoZSBhcHAgaW4gdGhlIGFwcCBzZXJ2aWNlXG4gICAgY29uc3QgY2FwcCA9IGF3YWl0IGZldGNoQXBwKCk7XG4gICAgdGhpcy5hcHBTZXJ2aWNlLmFwcCA9IGNhcHA7XG5cbiAgICBjb25zdCBzZXR0aW5ncyA9IGF3YWl0IGZldGNoVXNlclNldHRpbmdzPHt9PigpO1xuICAgIHRoaXMudXNlclNldHRpbmdzU2VydmljZS51c2VyU2V0dGluZ3MgPSBzZXR0aW5ncztcbiAgICBjb25zdCBrZXkgPSB0aGlzLmNoYXRJbnN0YW5jZUlkO1xuICAgIGNvbnN0IHVzZXJTZXR0aW5nc0NvbmZpZyA9IHRoaXMuYXNzaXN0YW50c1trZXldIHx8IHt9O1xuXG4gICAgY29uc3QgcHJpbmNpcGFsID0gYXdhaXQgZmV0Y2hQcmluY2lwYWwoKTtcbiAgICB0aGlzLnByaW5jaXBhbFNlcnZpY2UucHJpbmNpcGFsID0gcHJpbmNpcGFsO1xuXG4gICAgY29uc3Qgc3RhbmRhcmRDaGF0Q29uZmlnID0gZ2V0QXNzaXN0YW50SnNvbkZyb21DQ0FwcCh0aGlzLmFwcFNlcnZpY2UuYXBwLCBrZXkpO1xuXG4gICAgdHJ5IHtcbiAgICAgIC8vIFZhbGlkYXRlIHRoZSB3aG9sZSBjb25maWcgb2JqZWN0IGFnYWluc3QgdGhlIHNjaGVtYVxuICAgICAgY2hhdENvbmZpZ1NjaGVtYS5wYXJzZShzdGFuZGFyZENoYXRDb25maWcpO1xuICAgICAgLy8gSWYgdGhlIHVzZXIgcHJlZmVyZW5jZXMgZG8gbm90IGNvbnRhaW4gYSBjb25maWcncyBkZWZhdWx0VmFsdWVzIG9iamVjdCwga2VlcCB1c2luZyB0aGUgc3RhbmRhcmQgYXBwIGNvbmZpZyBhbmQgbm90aGluZyB0byBzdG9yZSBpbiB0aGUgdXNlciBwcmVmZXJlbmNlc1xuICAgICAgaWYgKCF1c2VyU2V0dGluZ3NDb25maWcuZGVmYXVsdFZhbHVlcykge1xuICAgICAgICB0aGlzLmFzc2lzdGFudENvbmZpZyQubmV4dCh7Li4uc3RhbmRhcmRDaGF0Q29uZmlnfSk7XG4gICAgICAgIHRoaXMuaW5pdENvbmZpZyQubmV4dCh0cnVlKTtcbiAgICAgIH0gZWxzZSB7IC8vIElmIHRoZSB1c2VyIGhhcyBpdHMgb3duIGRlZmF1bHRWYWx1ZXMgaW4gaXRzIHVzZXJTZXR0aW5ncywgdGhlbiB3ZSBuZWVkIHRvIGNoZWNrIGZvciBwb3RlbnRpYWwgdXBkYXRlcyBtYWRlIGJ5IGFkbWlucyBpbiB0aGUgbWVhbnRpbWUgYW5kIGhvdyBoZSB3YW50cyB0byBtYW5hZ2UgdGhlbVxuXG4gICAgICAgIC8vIFJldHJpZXZlIGFscmVhZHkgc3RvcmVkIGhhc2hlcyBpbiB0aGUgdXNlciBzZXR0aW5ncyBpZiBleGlzdHNcbiAgICAgICAgY29uc3QgYXBwbGllZERlZmF1bHRWYWx1ZXNIYXNoID0gdXNlclNldHRpbmdzQ29uZmlnLmhhc2hlcz8uW1wiYXBwbGllZC1kZWZhdWx0VmFsdWVzLWhhc2hcIl07XG4gICAgICAgIGNvbnN0IHNraXBwZWREZWZhdWx0VmFsdWVzSGFzaCA9IHVzZXJTZXR0aW5nc0NvbmZpZy5oYXNoZXM/LltcInNraXBwZWQtZGVmYXVsdFZhbHVlcy1oYXNoXCJdO1xuICAgICAgICAvLyBDcmVhdGUgYSBoYXNoIG9mIHRoZSBjdXJyZW50IGRlZmF1bHRWYWx1ZXMgb2YgdGhlIHN0YW5kYXJkQ2hhdENvbmZpZ1xuICAgICAgICBjb25zdCBjdXJyZW50RGVmYXVsdFZhbHVlc0hhc2ggPSBhd2FpdCBzaGE1MTIoSlNPTi5zdHJpbmdpZnkoc3RhbmRhcmRDaGF0Q29uZmlnLmRlZmF1bHRWYWx1ZXMpKTtcblxuICAgICAgICAvLyBJbXBsZW1lbnQgdGhlIHRyYWNraW5nIG1lY2hhbmlzbSB0byBub3RpZnkgdGhlIHVzZXIgYWJvdXQgdGhlIGF2YWlsYWJsZSB1cGRhdGVzIGluIHRoZSBkZWZhdWx0VmFsdWVzIG9iamVjdCBvZiB0aGUgc3RhbmRhcmQgYXBwIGNvbmZpZ1xuICAgICAgICBjb25zdCBjb25kaXRpb24gPSAoY3VycmVudERlZmF1bHRWYWx1ZXNIYXNoICE9PSBhcHBsaWVkRGVmYXVsdFZhbHVlc0hhc2gpICYmIChjdXJyZW50RGVmYXVsdFZhbHVlc0hhc2ggIT09IHNraXBwZWREZWZhdWx0VmFsdWVzSGFzaCk7XG4gICAgICAgIGlmIChjb25kaXRpb24pIHtcbiAgICAgICAgICB0aGlzLm1vZGFsU2VydmljZS5vcGVuKERpYWxvZ1VwZGF0ZXNDb21wb25lbnQpXG4gICAgICAgICAgICAudGhlbihyZXMgPT4ge1xuICAgICAgICAgICAgICAgIGlmKHJlcyA9PT0gXCJkaWFsb2ctY29uZmlybVwiKSB7XG4gICAgICAgICAgICAgICAgICBjb25zdCBoYXNoZXMgPSB7IC4uLnVzZXJTZXR0aW5nc0NvbmZpZy5oYXNoZXMsIFwiYXBwbGllZC1kZWZhdWx0VmFsdWVzLWhhc2hcIjogY3VycmVudERlZmF1bHRWYWx1ZXNIYXNoLCBcInNraXBwZWQtZGVmYXVsdFZhbHVlcy1oYXNoXCI6IHVuZGVmaW5lZCB9O1xuICAgICAgICAgICAgICAgICAgLy8gVXBkYXRlIHRoZSBjaGF0IGNvbmZpZyBhbmQgc3RvcmUgaXRzIGRlZmF1bHRWYWx1ZXMgaW4gdGhlIHVzZXIgcHJlZmVyZW5jZXNcbiAgICAgICAgICAgICAgICAgIHRoaXMudXBkYXRlQ2hhdENvbmZpZyh7Li4uc3RhbmRhcmRDaGF0Q29uZmlnfSwgaGFzaGVzLCB0cnVlKTtcbiAgICAgICAgICAgICAgICAgIHRoaXMuaW5pdENvbmZpZyQubmV4dCh0cnVlKTtcbiAgICAgICAgICAgICAgICAgIHRoaXMuZ2VuZXJhdGVBdWRpdEV2ZW50KFwiYXN0LWNvbmZpZ3VyYXRpb24uY2xpY2tcIiwgeyAnY29uZmlndXJhdGlvbic6IEpTT04uc3RyaW5naWZ5KHsuLi5zdGFuZGFyZENoYXRDb25maWd9KSB9KTtcbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYocmVzID09PSBcImRpYWxvZy1ub1wiKSB7XG4gICAgICAgICAgICAgICAgICAvLyBEbyBub3Qgbm90aWZ5IHRoZSB1c2VyIGFib3V0IGNoYW5nZXMgd2hpbGUgdGhpcyBza2lwcGVkIHZlcnNpb24gaXMgbm90IHVwZGF0ZWRcbiAgICAgICAgICAgICAgICAgIGNvbnN0IGhhc2hlcyA9IHsgLi4udXNlclNldHRpbmdzQ29uZmlnLmhhc2hlcywgXCJza2lwcGVkLWRlZmF1bHRWYWx1ZXMtaGFzaFwiOiBjdXJyZW50RGVmYXVsdFZhbHVlc0hhc2ggfTtcbiAgICAgICAgICAgICAgICAgIHRoaXMudXBkYXRlQ2hhdENvbmZpZyh7Li4uc3RhbmRhcmRDaGF0Q29uZmlnLCBkZWZhdWx0VmFsdWVzOiB1c2VyU2V0dGluZ3NDb25maWcuZGVmYXVsdFZhbHVlc30sIGhhc2hlcywgZmFsc2UpO1xuICAgICAgICAgICAgICAgICAgdGhpcy5pbml0Q29uZmlnJC5uZXh0KHRydWUpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAvLyBKdXN0IHBpY2sgdGhlIHZlcnNpb24gaW4gdGhlIHVzZXIgc2V0dGluZ3MsIG5vdGhpbmcgdG8gYmUgdXBkYXRlZFxuICAgICAgICAgICAgICAgICAgdGhpcy5hc3Npc3RhbnRDb25maWckLm5leHQoey4uLnN0YW5kYXJkQ2hhdENvbmZpZywgZGVmYXVsdFZhbHVlczogdXNlclNldHRpbmdzQ29uZmlnLmRlZmF1bHRWYWx1ZXN9KTtcbiAgICAgICAgICAgICAgICAgIHRoaXMuaW5pdENvbmZpZyQubmV4dCh0cnVlKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIHsgLy8gTm8gYXZhaWxhYmxlIHVwZGF0ZXMgT3IgdXBkYXRlcyBoYXMgYmVlbiBhbHJlYWR5IHNraXBwZWQsIHRoZW4ganVzdCBwaWNrIHRoZSB2ZXJzaW9uIGluIHRoZSB1c2VyIHNldHRpbmdzXG4gICAgICAgICAgdGhpcy5hc3Npc3RhbnRDb25maWckLm5leHQoey4uLnN0YW5kYXJkQ2hhdENvbmZpZywgZGVmYXVsdFZhbHVlczogdXNlclNldHRpbmdzQ29uZmlnLmRlZmF1bHRWYWx1ZXN9KTtcbiAgICAgICAgICB0aGlzLmluaXRDb25maWckLm5leHQodHJ1ZSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgdGhpcy5ub3RpZmljYXRpb25zU2VydmljZS5lcnJvcihgTWlzc2luZyB2YWxpZCBjb25maWd1cmF0aW9uIGZvciB0aGUgYXNzaXN0YW50IGluc3RhbmNlICcke2tleX0nLiBTZWUgdGhlIGJyb3dzZXIgY29uc29sZSBtZXNzYWdlcyBmb3IgZGV0YWlscyBvbiB0aGUgbWlzc2luZyBvciBpbmNvcnJlY3QgcHJvcGVydGllcy5gKTtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgTWlzc2luZyB2YWxpZCBjb25maWd1cmF0aW9uIGZvciB0aGUgYXNzaXN0YW50IGluc3RhbmNlICcke2tleX0nIC4gXFxuICR7SlNPTi5zdHJpbmdpZnkoZXJyb3IuaXNzdWVzLCBudWxsLCAyKX1gKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogVXBkYXRlIHRoZSBjaGF0IGNvbmZpZyBhbmQgc3RvcmUgaXRzIGRlZmF1bHRWYWx1ZXMgaW4gdGhlIHVzZXIgcHJlZmVyZW5jZXNcbiAgICogQHBhcmFtIGNvbmZpZyAgVGhlIHVwZGF0ZWQgY2hhdCBjb25maWdcbiAgICogQHBhcmFtIGhhc2hlcyAgVGhlIHVwZGF0ZWQgaGFzaGVzIHRvIHN0b3JlIGluIHRoZSB1c2VyIHByZWZlcmVuY2VzXG4gICAqIEBwYXJhbSBub3RpZnkgIFdoZXRoZXIgdG8gbm90aWZ5IHRoZSB1c2VyIGFib3V0IHRoZSB1cGRhdGVcbiAgICogQHBhcmFtIHN1Y2Nlc3NDYWxsYmFjayAgVGhlIGNhbGxiYWNrIHRvIGV4ZWN1dGUgaWYgdGhlIHVwZGF0ZSBpcyBzdWNjZXNzZnVsXG4gICAqIEBwYXJhbSBlcnJvckNhbGxiYWNrICBUaGUgY2FsbGJhY2sgdG8gZXhlY3V0ZSBpZiB0aGUgdXBkYXRlIGZhaWxzXG4gICAqL1xuICB1cGRhdGVDaGF0Q29uZmlnKGNvbmZpZzogQ2hhdENvbmZpZywgaGFzaGVzPzoge1wiYXBwbGllZC1kZWZhdWx0VmFsdWVzLWhhc2hcIj86IHN0cmluZywgXCJza2lwcGVkLWRlZmF1bHRWYWx1ZXMtaGFzaFwiPzogc3RyaW5nfSwgIG5vdGlmeSA9IHRydWUsIHN1Y2Nlc3NDYWxsYmFjaz86ICgpID0+IGFueSwgZXJyb3JDYWxsYmFjaz86ICgpID0+IGFueSkge1xuICAgIHRoaXMuYXNzaXN0YW50Q29uZmlnJC5uZXh0KGNvbmZpZyk7XG4gICAgY29uc3QgYXNzaXN0YW50cyA9IE9iamVjdC5hc3NpZ24oe30sIHRoaXMuYXNzaXN0YW50cyk7XG4gICAgYXNzaXN0YW50c1t0aGlzLmNoYXRJbnN0YW5jZUlkXSA9IHsgLi4uYXNzaXN0YW50c1t0aGlzLmNoYXRJbnN0YW5jZUlkXSwgZGVmYXVsdFZhbHVlczogY29uZmlnLmRlZmF1bHRWYWx1ZXMgfTtcbiAgICBpZihoYXNoZXMpIGFzc2lzdGFudHNbdGhpcy5jaGF0SW5zdGFuY2VJZF0uaGFzaGVzID0gaGFzaGVzO1xuICAgIHRoaXMudXNlclNldHRpbmdzU2VydmljZS5wYXRjaCh7IGFzc2lzdGFudHMgfSkuc3Vic2NyaWJlKFxuICAgICAgbmV4dCA9PiB7fSxcbiAgICAgIGVycm9yID0+IHtcbiAgICAgICAgaWYobm90aWZ5KSB7XG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnVzZWQtZXhwcmVzc2lvbnNcbiAgICAgICAgICBlcnJvckNhbGxiYWNrXG4gICAgICAgICAgICA/IGVycm9yQ2FsbGJhY2soKVxuICAgICAgICAgICAgOiB0aGlzLm5vdGlmaWNhdGlvbnNTZXJ2aWNlLmVycm9yKHRoaXMudHJhbnNsb2NvLnRyYW5zbGF0ZSgnY2hhdC5zYXZlQ2hhdENvbmZpZy5mYWlsJywgeyB2YWx1ZTogdGhpcy5jaGF0SW5zdGFuY2VJZCB9KSk7XG4gICAgICAgIH1cbiAgICAgICAgY29uc29sZS5lcnJvcihcIkNvdWxkIG5vdCBwYXRjaCBhc3Npc3RhbnRzIVwiLCBlcnJvcik7XG4gICAgICB9LFxuICAgICAgKCkgPT4ge1xuICAgICAgICBpZihub3RpZnkpIHtcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVudXNlZC1leHByZXNzaW9uc1xuICAgICAgICAgIHN1Y2Nlc3NDYWxsYmFja1xuICAgICAgICAgICAgPyBzdWNjZXNzQ2FsbGJhY2soKVxuICAgICAgICAgICAgOiB0aGlzLm5vdGlmaWNhdGlvbnNTZXJ2aWNlLnN1Y2Nlc3ModGhpcy50cmFuc2xvY28udHJhbnNsYXRlKCdjaGF0LnNhdmVDaGF0Q29uZmlnLnN1Y2Nlc3MnLCB7IHZhbHVlOiB0aGlzLmNoYXRJbnN0YW5jZUlkIH0pKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogT3ZlcnJpZGVzIHRoZSBsb2dnZWQgaW4gdXNlclxuICAgKi9cbiAgYWJzdHJhY3Qgb3ZlcnJpZGVVc2VyKCk6IHZvaWQ7XG5cbiAgLyoqXG4gICAqIENhbGxzIHRoZSBGZXRjaCBBUEkgdG8gcmV0cmlldmUgYSBuZXcgbWVzc2FnZSBnaXZlbiBhbGwgcHJldmlvdXMgbWVzc2FnZXNcbiAgICovXG4gIGFic3RyYWN0IGZldGNoKG1lc3NhZ2VzOiBDaGF0TWVzc2FnZVtdLCBxdWVyeTogUXVlcnkpOiBPYnNlcnZhYmxlPENoYXRSZXNwb25zZT5cblxuICAvKipcbiAgICogUmV0dXJuIHRoZSBsaXN0IG9mIG1vZGVscyBhdmFpbGFibGUgb24gdGhlIHNlcnZlclxuICAgKi9cbiAgYWJzdHJhY3QgbGlzdE1vZGVscygpOiBPYnNlcnZhYmxlPEdsbG1Nb2RlbERlc2NyaXB0aW9uW10gfCB1bmRlZmluZWQ+O1xuXG4gIC8qKlxuICAgKiBSZXR1cm4gdGhlIGxpc3Qgb2YgZnVuY3Rpb25zIGF2YWlsYWJsZSBvbiB0aGUgc2VydmVyIEFORCBtYXRjaGluZyBlbmFibGVkIGZ1bmN0aW9ucyBpbiB0aGUgY2hhdCBjb25maWdcbiAgICovXG4gIGFic3RyYWN0IGxpc3RGdW5jdGlvbnMoKTogT2JzZXJ2YWJsZTxHbGxtRnVuY3Rpb25bXSB8IHVuZGVmaW5lZD47XG5cbiAgLyoqXG4gICAqIFN0b3BzIHRoZSBhc3Npc3RhbnQgYW5zd2VyIGdlbmVyYXRpb24gYW5kIGNhbmNlbHMgYWxsIHRoZSBvbmdvaW5nIGFuZCBwZW5kaW5nIHJlbGF0ZWQgdGFza3NcbiAgICovXG4gIGFic3RyYWN0IHN0b3BHZW5lcmF0aW9uKCk6IE9ic2VydmFibGU8YW55PlxuXG4gIC8qKlxuICAgKiBBIGhhbmRsZXIgZm9yIHF1b3RhIHVwZGF0ZXMgZWFjaCB0aW1lIHRoZSBjaGF0IGlzIGludm9rZWQuXG4gICAqIEl0IGVtaXRzIHRoZSB1cGRhdGVkIHF1b3RhIHRvIHRoZSBxdW90YSQgc3ViamVjdCwgZW1pdHMgYWNjb3JkaW5nbHkgdGhlIHVwZGF0ZWQgdXNlcidzIHRva2VucyBjb25zdW1wdGlvbiBhbmQgbm90aWZpZXMgdGhlIHVzZXIgaWYgdGhlIG1heCBxdW90YSBpcyByZWFjaGVkLlxuICAgKiBAcGFyYW0gcXVvdGEgVGhlIHVwZGF0ZWQgcXVvdGFcbiAgICogQHBhcmFtIHByb3BhZ2F0ZUVycm9yIFdoZXRoZXIgdG8gcHJvcGFnYXRlIHRoZSBlcnJvciB0byB0aGUgY2FsbGVyXG4gICAqL1xuICB1cGRhdGVRdW90YShxdW90YTogUXVvdGEsIHByb3BhZ2F0ZUVycm9yID0gZmFsc2UpIHtcbiAgICB0aGlzLnF1b3RhJC5uZXh0KHF1b3RhKTtcbiAgICBjb25zdCBuZXh0UmVzZXREYXRlID0gdGhpcy5mb3JtYXREYXRlVGltZShxdW90YS5uZXh0UmVzZXRVVEMrXCIrMDA6MDBcIik7IC8vIFRoaXMgKzAwOjAwIGlzIHRvIGVuc3VyZSBkYXRlcyB3aWxsIGJlIHByb3Blcmx5IGNvbnZlcnRlZCB0byBsb2NhbCB0aW1lXG4gICAgY29uc3QgY29uc3VtcHRpb25QZXJjZW50YWdlID0gTWF0aC5yb3VuZCgocXVvdGEudG9rZW5Db3VudCAqIDEwMCAvIHF1b3RhLnBlcmlvZFRva2VucykgKiAxMDApIC8gMTAwO1xuICAgIHRoaXMudXNlclRva2VuQ29uc3VtcHRpb24kLm5leHQoe3BlcmNlbnRhZ2U6IGNvbnN1bXB0aW9uUGVyY2VudGFnZSwgbmV4dFJlc2V0RGF0ZX0pO1xuICAgIGlmKHF1b3RhLm1heFF1b3RhUmVhY2hlZCkge1xuICAgICAgdGhpcy5nZW5lcmF0ZUF1ZGl0RXZlbnQoJ2FzdC1xdW90YS5leGNlZWRlZCcsIHt9KTtcbiAgICAgIGNvbnN0IG1zZyA9IGBTb3JyeSwgeW91IGhhdmUgZXhjZWVkZWQgdGhlIGFsbG93ZWQgcXVvdGEuIFBsZWFzZSByZXRyeSBzdGFydGluZyBmcm9tICR7bmV4dFJlc2V0RGF0ZX0uYDtcbiAgICAgIHRoaXMubm90aWZpY2F0aW9uc1NlcnZpY2UuZXJyb3IobXNnKTtcbiAgICAgIGlmKHByb3BhZ2F0ZUVycm9yKSB0aHJvdyBuZXcgRXJyb3IobXNnKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQSBoYW5kbGVyIGZvciBjaGF0IHVzYWdlIG1ldHJpY3MgZWFjaCB0aW1lIHRoZSBnZW5lcmF0aW9uIG9mIHRoZSBhc3Npc3RhbnQgcmVzcG9uc2UgaXMgY29tcGxldGVkLlxuICAgKiBJdCBlbWl0cyB0aGUgY2hhdCB1c2FnZSBtZXRyaWNzIHRvIHRoZSBjaGF0VXNhZ2VNZXRyaWNzJCBzdWJqZWN0LCBlbWl0cyBhY2NvcmRpbmdseSB0aGUgdXBkYXRlZCBjaGF0J3MgdG9rZW5zIGNvbnN1bXB0aW9uXG4gICAqIEBwYXJhbSBjaGF0VXNhZ2VNZXRyaWNzIFRoZSBjaGF0IHVzYWdlIG1ldHJpY3NcbiAgICovXG4gIHVwZGF0ZUNoYXRVc2FnZU1ldHJpY3MoY2hhdFVzYWdlTWV0cmljczogQ2hhdFVzYWdlTWV0cmljcykge1xuICAgIHRoaXMuY2hhdFVzYWdlTWV0cmljcyQubmV4dChjaGF0VXNhZ2VNZXRyaWNzKTtcbiAgICBjb25zdCBjdXJyZW50TW9kZWwgPSB0aGlzLmdldE1vZGVsKHRoaXMuYXNzaXN0YW50Q29uZmlnJC52YWx1ZSEuZGVmYXVsdFZhbHVlcy5zZXJ2aWNlX2lkLCB0aGlzLmFzc2lzdGFudENvbmZpZyQudmFsdWUhLmRlZmF1bHRWYWx1ZXMubW9kZWxfaWQpO1xuICAgIGNvbnN0IGNvbnN1bXB0aW9uUGVyY2VudGFnZSA9IE1hdGgucm91bmQoKGNoYXRVc2FnZU1ldHJpY3MudG90YWxUb2tlbkNvdW50ICogMTAwIC8gKGN1cnJlbnRNb2RlbCEuY29udGV4dFdpbmRvd1NpemUgLSBjdXJyZW50TW9kZWwhLm1heEdlbmVyYXRpb25TaXplKSkgKiAxMDApIC8gMTAwO1xuICAgIHRoaXMuY2hhdFRva2VuQ29uc3VtcHRpb24kLm5leHQoe3BlcmNlbnRhZ2U6IGNvbnN1bXB0aW9uUGVyY2VudGFnZX0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCB0aGUgbW9kZWwgZGVzY3JpcHRpb24gZm9yIHRoZSBnaXZlbiAoc2VydmljZUlkICsgbW9kZWxJZClcbiAgICogSWYgYSBtb2RlbCBpcyBub3QgZm91bmQsIGFuIGVycm9yIG1lc3NhZ2UgaXMgcmV0dXJuZWRcbiAgICogQHBhcmFtIHNlcnZpY2VJZCBUaGUgc2VydmljZUlkIG9mIHRoZSBtb2RlbFxuICAgKiBAcGFyYW0gbW9kZWxJZCBUaGUgbW9kZWxJZCBvZiB0aGUgbW9kZWxcbiAgICogQHJldHVybnMgVGhlIG1vZGVsIGRlc2NyaXB0aW9uXG4gICAqL1xuICBnZXRNb2RlbChzZXJ2aWNlSWQ6IHN0cmluZywgbW9kZWxJZDogc3RyaW5nKTogR2xsbU1vZGVsRGVzY3JpcHRpb24gfCB1bmRlZmluZWR7XG4gICAgY29uc3QgbW9kZWwgPSB0aGlzLm1vZGVscz8uZmluZChtID0+IG0uc2VydmljZUlkID09PSBzZXJ2aWNlSWQgJiYgbS5tb2RlbElkID09PSBtb2RlbElkKTtcbiAgICAvLyBIYW5kbGUgb2Jzb2xldGUgY29uZmlnXG4gICAgaWYoIW1vZGVsKSB7XG4gICAgICB0aGlzLm5vdGlmaWNhdGlvbnNTZXJ2aWNlLmVycm9yKGBGQVRBTCBFUlJPUiA6IFRoZSBtb2RlbCAoc2VydmljZUlkID0gJyR7c2VydmljZUlkfScsIG1vZGVsSWQgPSAnJHttb2RlbElkfScpIGlzIG5vIGxvbmdlciBhdmFpbGFibGUuIFBsZWFzZSBjb250YWN0IGFuIGFkbWluIGZvciBmdXJ0aGVyIGluZm9ybWF0aW9uLmApO1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBGQVRBTCBFUlJPUiA6IFRoZSBtb2RlbCAoc2VydmljZUlkID0gJyR7c2VydmljZUlkfScsIG1vZGVsSWQgPSAnJHttb2RlbElkfScpIGlzIG5vIGxvbmdlciBhdmFpbGFibGVgKTtcbiAgICB9XG4gICAgcmV0dXJuIG1vZGVsO1xuICB9XG5cbiAgLyoqXG4gICAqIEZldGNoIHRoZSBsaXN0IHNhdmVkIGNoYXRzIGJlbG9uZ2luZyB0byBhIHNwZWNpZmljIGluc3RhbmNlIG9mIHRoZSBhc3Npc3RhbnRcbiAgICovXG4gIGFic3RyYWN0IGxpc3RTYXZlZENoYXQoKTogdm9pZDtcblxuICAvKipcbiAgICogUmV0dXJuIHRoZSBzYXZlZCBjaGF0IHdpdGggdGhlIGdpdmVuIGlkLCBpZiBleGlzdHMuIE90aGVyd2lzZSwgcmV0dXJuIHVuZGVmaW5lZFxuICAgKiBAcGFyYW0gaWQgVGhlIGlkIG9mIHRoZSBzYXZlZCBjaGF0XG4gICAqL1xuICBhYnN0cmFjdCBnZXRTYXZlZENoYXQoaWQ6IHN0cmluZyk6IE9ic2VydmFibGU8U2F2ZWRDaGF0SGlzdG9yeSB8IHVuZGVmaW5lZD47XG5cbiAgLyoqXG4gICAqIFNhdmUgYSBjaGF0IHdpdGggdGhlIGdpdmVuIG1lc3NhZ2VzXG4gICAqIEBwYXJhbSBtZXNzYWdlcyBUaGUgbWVzc2FnZXMgdG8gYWRkIHRvIHRoZSBzYXZlZCBjaGF0IGluZGV4XG4gICAqIEByZXR1cm5zIFRoZSBzYXZlZCBjaGF0XG4gICAqL1xuICBhYnN0cmFjdCBhZGRTYXZlZENoYXQobWVzc2FnZXM6IENoYXRNZXNzYWdlW10pOiBPYnNlcnZhYmxlPFNhdmVkQ2hhdFJlc3BvbnNlPjtcblxuICAvKipcbiAgICogVXBkYXRlIGEgc2F2ZWQgY2hhdCB3aXRoIHRoZSBnaXZlbiBpZC5cbiAgICogQHBhcmFtIGlkIFRoZSBpZCBvZiB0aGUgc2F2ZWQgY2hhdFxuICAgKiBAcGFyYW0gbmFtZSBUaGUgbmV3IG5hbWUgb2YgdGhlIHNhdmVkIGNoYXQsIGlmIHByb3ZpZGVkXG4gICAqIEBwYXJhbSBtZXNzYWdlcyBUaGUgbWVzc2FnZXMgdG8gdXBkYXRlIHRoZSBzYXZlZCBjaGF0IGhpc3RvcnksIGlmIHByb3ZpZGVkXG4gICAqIEByZXR1cm5zIFRydWUgaWYgdGhlIHNhdmVkIGNoYXQgaGFzIGJlZW4gc3VjY2Vzc2Z1bGx5IHVwZGF0ZWRcbiAgICovXG4gIGFic3RyYWN0IHVwZGF0ZVNhdmVkQ2hhdChpZDogc3RyaW5nLCBuYW1lPzogc3RyaW5nLCBtZXNzYWdlcz86IENoYXRNZXNzYWdlW10pOiBPYnNlcnZhYmxlPFNhdmVkQ2hhdFJlc3BvbnNlPjtcblxuICAvKipcbiAgICogQnVsayBkZWxldGUgb2Ygc2F2ZWQgY2hhdHMgbWF0Y2hpbmcgdGhlIGdpdmVuIGlkc1xuICAgKiBAcGFyYW0gaWRzIExpc3Qgb2YgaWRzIG9mIHRoZSBzYXZlZCBjaGF0cyB0byBkZWxldGVcbiAgICogQHJldHVybnMgVGhlIG51bWJlciBvZiBkZWxldGVkIGNoYXRzXG4gICAqL1xuICBhYnN0cmFjdCBkZWxldGVTYXZlZENoYXQoaWRzOiBzdHJpbmdbXSk6IE9ic2VydmFibGU8RGVsZXRlU2F2ZWRDaGF0UmVzcG9uc2U+O1xuXG4gIC8qKlxuICAgKiBHZW5lcmF0ZSBhbiBhdWRpdCBldmVudCB3aXRoIHRoZSBnaXZlbiB0eXBlIGFuZCBkZXRhaWxzLiBUaGUgZ2VuZXJhdGVkIGF1ZGl0IGV2ZW50IGlzIHNlbnQgYWZ0ZXJ3YXJkcyB2aWEgdGhlIEF1ZGl0V2ViU2VydmljZVxuICAgKiBAcGFyYW0gdHlwZSBBdWRpdCBldmVudCB0eXBlXG4gICAqIEBwYXJhbSBkZXRhaWxzIEF1ZGl0IGV2ZW50IGRldGFpbHNcbiAgICogQHBhcmFtIGlkIEFjdGlvbnMgKHNhdmVkQ2hhdCBkZWxldGUvcmVuYW1lLy4uLikgbWF5IG9jY3VyIG9uIGEgc3BlY2lmaWMgY2hhdCBkaWZmZXJlbnQgdGhhbiB0aGUgY3VycmVudCBvbmUgc3RvcmVkIGluIHRoaXMgc2VydmljZSwgc28gdGhlIGNoYXQgaWQgY2FuIGJlIHByb3ZpZGVkXG4gICAqL1xuICBhc3luYyBnZW5lcmF0ZUF1ZGl0RXZlbnQodHlwZTogc3RyaW5nLCBkZXRhaWxzOiBSZWNvcmQ8c3RyaW5nLCBhbnk+LCBpZD86IHN0cmluZykge1xuICAgIGNvbnN0IGJhc2VEZXRhaWxzID0ge1xuICAgICAgXCJ1cmxcIjogZGVjb2RlVVJJQ29tcG9uZW50KHdpbmRvdy5sb2NhdGlvbi5ocmVmKSxcbiAgICAgIFwiYXBwXCI6IHRoaXMuYXBwU2VydmljZS5hcHBOYW1lLFxuICAgICAgXCJ1c2VyLWlkXCI6IHRoaXMucHJpbmNpcGFsU2VydmljZS5wcmluY2lwYWw/LnVzZXJJZCxcbiAgICAgIFwiaW5zdGFuY2UtaWRcIjogdGhpcy5jaGF0SW5zdGFuY2VJZCxcbiAgICAgIFwiY2hhdC1pZFwiOiBpZCB8fCB0aGlzLmNoYXRJZCxcbiAgICAgIFwic2VydmljZS1pZFwiOiB0aGlzLmFzc2lzdGFudENvbmZpZyQudmFsdWUhLmRlZmF1bHRWYWx1ZXMuc2VydmljZV9pZCxcbiAgICAgIFwibW9kZWwtaWRcIjogdGhpcy5hc3Npc3RhbnRDb25maWckLnZhbHVlIS5kZWZhdWx0VmFsdWVzLm1vZGVsX2lkLFxuICAgICAgXCJpcy11c2VyLWlucHV0XCI6IGZhbHNlXG4gICAgfTtcbiAgICBjb25zdCBhdWRpdCA9IHtcbiAgICAgIHR5cGUsXG4gICAgICBkZXRhaWw6IHtcbiAgICAgICAgLi4uYmFzZURldGFpbHMsXG4gICAgICAgIC4uLmRldGFpbHNcbiAgICAgIH1cbiAgICB9XG4gICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBBdWRpdC5ub3RpZnkoYXVkaXQpO1xuICAgIGNvbnNvbGUubG9nKFwiQXVkaXQgcmVzcG9uc2VcIiwgcmVzcG9uc2UpO1xuICB9XG5cblxuXG4gIC8qKlxuICAgKiBUcmF2ZXJzZSB0aGUgYXJyYXkgZnJvbSB0aGUgZW5kIGFuZCB0cmFjayB0aGUgZmlyc3QgJ2Fzc2lzdGFudCcgbWVzc2FnZSBhbW9uZyB0aGUgbGFzdCBncm91cCBvZiBcImFzc2lzdGFudFwiIG1lc3NhZ2VzIHdoZXJlIGRpc3BsYXkgaXMgdHJ1ZVxuICAgKiBAcGFyYW0gYXJyYXkgVGhlIGFycmF5IG9mIENoYXRNZXNzYWdlIHRvIHRyYXZlcnNlXG4gICAqIEByZXR1cm5zIFRoZSBpbmRleCBvZiB0aGUgZmlyc3QgdmlzaWJsZSBhc3Npc3RhbnQgbWVzc2FnZSBhbW9uZyB0aGUgbGFzdCBncm91cCBvZiBcImFzc2lzdGFudFwiIG1lc3NhZ2VzIGluIHRoZSBhcnJheVxuICAgKi9cbiAgZmlyc3RWaXNpYmxlQXNzaXN0YW50TWVzc2FnZUluZGV4KGFycmF5OiBDaGF0TWVzc2FnZVtdfCB1bmRlZmluZWQpOiBudW1iZXIge1xuICAgIGlmICghYXJyYXkpIHtcbiAgICAgIHJldHVybiAtMTtcbiAgICB9XG4gICAgbGV0IGluZGV4ID0gYXJyYXkubGVuZ3RoIC0gMTtcbiAgICBsZXQgZmlyc3RWaXNpYmxlQXNzaXN0YW50TWVzc2FnZUluZGV4ID0gLTE7XG4gICAgd2hpbGUgKGluZGV4ID49IDAgJiYgYXJyYXlbaW5kZXhdLnJvbGUgPT09ICdhc3Npc3RhbnQnKSB7XG4gICAgICBpZiAoYXJyYXlbaW5kZXhdLmFkZGl0aW9uYWxQcm9wZXJ0aWVzLmRpc3BsYXkgPT09IHRydWUpIHtcbiAgICAgICAgZmlyc3RWaXNpYmxlQXNzaXN0YW50TWVzc2FnZUluZGV4ID0gaW5kZXg7XG4gICAgICB9XG4gICAgICBpbmRleC0tO1xuICAgIH1cbiAgICByZXR1cm4gZmlyc3RWaXNpYmxlQXNzaXN0YW50TWVzc2FnZUluZGV4O1xuICB9XG5cbiAgLyoqXG4gICAqIFRyYXZlcnNlIHRoZSBhcnJheSBmcm9tIHRoZSBlbmQgYW5kIHBpY2sgdGhlIGxhc3QgJ2Fzc2lzdGFudCcgbWVzc2FnZSBhbW9uZyB0aGUgbGFzdCBncm91cCBvZiBcImFzc2lzdGFudFwiIG1lc3NhZ2VzIHdoZXJlIGRpc3BsYXkgaXMgdHJ1ZVxuICAgKiBAcGFyYW0gYXJyYXkgVGhlIGFycmF5IG9mIENoYXRNZXNzYWdlIHRvIHRyYXZlcnNlXG4gICAqIEByZXR1cm5zIFRoZSBpbmRleCBvZiB0aGUgbGFzdCB2aXNpYmxlIGFzc2lzdGFudCBtZXNzYWdlIGFtb25nIHRoZSBsYXN0IGdyb3VwIG9mIFwiYXNzaXN0YW50XCIgbWVzc2FnZXMgaW4gdGhlIGFycmF5XG4gICAqL1xuICBsYXN0VmlzaWJsZUFzc2lzdGFudE1lc3NhZ2VJbmRleChhcnJheTogQ2hhdE1lc3NhZ2VbXXwgdW5kZWZpbmVkKTogbnVtYmVyIHtcbiAgICBpZiAoIWFycmF5KSB7XG4gICAgICByZXR1cm4gLTE7XG4gICAgfVxuICAgIGxldCBpbmRleCA9IGFycmF5Lmxlbmd0aCAtIDE7XG4gICAgbGV0IGxhc3RWaXNpYmxlQXNzaXN0YW50TWVzc2FnZUluZGV4ID0gLTE7XG4gICAgd2hpbGUgKGluZGV4ID49IDAgJiYgYXJyYXlbaW5kZXhdLnJvbGUgPT09ICdhc3Npc3RhbnQnKSB7XG4gICAgICBpZiAoYXJyYXlbaW5kZXhdLmFkZGl0aW9uYWxQcm9wZXJ0aWVzLmRpc3BsYXkgPT09IHRydWUpIHtcbiAgICAgICAgbGFzdFZpc2libGVBc3Npc3RhbnRNZXNzYWdlSW5kZXggPSBpbmRleDtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgICBpbmRleC0tO1xuICAgIH1cbiAgICByZXR1cm4gbGFzdFZpc2libGVBc3Npc3RhbnRNZXNzYWdlSW5kZXg7XG4gIH1cblxuICAvKipcbiAgICogRm9ybWF0IGEgZGF0ZSBzdHJpbmcgaW4gVVRDIHRvIGEgbG9jYWwgZGF0ZSBzdHJpbmdcbiAgICogQHBhcmFtIHZhbHVlIERhdGUgc3RyaW5nIGluIFVUQyB0byBmb3JtYXRcbiAgICogQHJldHVybnMgQSBmb3JtYXR0ZWQgbG9jYWwgZGF0ZSBzdHJpbmdcbiAgICovXG4gIHByb3RlY3RlZCBmb3JtYXREYXRlVGltZSh2YWx1ZTogc3RyaW5nKTogc3RyaW5nIHtcbiAgICBjb25zdCBsb2NhbERhdGUgPSB0b0RhdGUocGFyc2VJU08odmFsdWUpKTtcbiAgICBjb25zdCBmb3JtYXR0ZXIgPSBuZXcgSW50bC5EYXRlVGltZUZvcm1hdCh1bmRlZmluZWQsIHtcbiAgICAgIHllYXI6ICdudW1lcmljJyxcbiAgICAgIG1vbnRoOiAnc2hvcnQnLFxuICAgICAgZGF5OiAnbnVtZXJpYycsXG4gICAgICBob3VyOiAnMi1kaWdpdCcsXG4gICAgICBtaW51dGU6ICcyLWRpZ2l0JyxcbiAgICAgIHNlY29uZDogJzItZGlnaXQnLFxuICAgICAgdGltZVpvbmVOYW1lOiAnc2hvcnQnXG4gICAgfSk7XG4gICAgcmV0dXJuIGZvcm1hdHRlci5mb3JtYXQobG9jYWxEYXRlKTtcbiAgfVxuXG4gICAgLyoqXG4gICAqIFRha2VzIGEgdGV4dCBwcm9tcHQgdGhhdCBtYXkgY29udGFpbiBwbGFjZWhvbGRlcnMgZm9yIHZhcmlhYmxlc1xuICAgKiBhbmQgcmVwbGFjZXMgdGhlc2UgcGxhY2Vob2xkZXJzIGlmIGl0IGZpbmRzIGEgbWF0Y2ggaW4gdGhlIGdpdmVuXG4gICAqIGNvbnRleHQgb2JqZWN0LlxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiBjb25zdCBwID0gXCJIZWxsbywgW1t1c2VyLm5hbWVdXSEgWW91IGhhdmUgW1t1c2VyLm5vdGlmaWNhdGlvbnMubGVuZ3RoXV0gbmV3IG5vdGlmaWNhdGlvbnMuXCI7XG4gICAqIGNvbnN0IGNvbnRleHQgPSB7XG4gICAqICAgICB1c2VyOiB7XG4gICAqICAgICAgICAgbmFtZTogXCJBbGljZVwiLFxuICAgKiAgICAgICAgIG5vdGlmaWNhdGlvbnM6IFtcIk1lc3NhZ2UgZnJvbSBCb2JcIiwgXCJSZW1pbmRlciBmb3IgbWVldGluZ1wiXVxuICAgKiAgICAgfVxuICAgKiB9O1xuICAgKiBjb25zdCBmb3JtYXR0ZWRQcm9tcHQgPSBmb3JtYXRQcm9tcHQocCwgY29udGV4dCk7XG4gICAqIGNvbnNvbGUubG9nKGZvcm1hdHRlZFByb21wdCk7IC8vIE91dHB1dDogXCJIZWxsbywgQWxpY2UhIFlvdSBoYXZlIDIgbmV3IG5vdGlmaWNhdGlvbnMuXCJcbiAgICovXG4gIHN0YXRpYyBmb3JtYXRQcm9tcHQocHJvbXB0OiBzdHJpbmcsIGNvbnRleHQ6IGFueSkge1xuICAgIHJldHVybiBwcm9tcHQucmVwbGFjZShcbiAgICAgIC9cXFtcXFsoLio/KVxcXVxcXS9nLFxuICAgICAgKG1hdGNoLCBleHByKSA9PiB7XG4gICAgICAvLyBTaW1wbGUgZG90IG5vdGF0aW9uIHJlc29sdmVyXG4gICAgICBjb25zdCBrZXlzID0gZXhwci50cmltKCkuc3BsaXQoXCIuXCIpO1xuICAgICAgbGV0IHZhbHVlID0gY29udGV4dDtcbiAgICAgIGZvciAoY29uc3Qga2V5IG9mIGtleXMpIHtcbiAgICAgICAgaWYgKHZhbHVlICYmIHR5cGVvZiB2YWx1ZSA9PT0gXCJvYmplY3RcIiAmJiBrZXkgaW4gdmFsdWUpIHtcbiAgICAgICAgdmFsdWUgPSB2YWx1ZVtrZXldO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICByZXR1cm4gbWF0Y2g7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHJldHVybiB2YWx1ZSA/PyBtYXRjaDtcbiAgICAgIH1cbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIERldGVybWluZXMgYSB0aW1lLWJhc2VkIGtleSBmb3IgYSBnaXZlbiBkYXRlIHRvIGJlIHVzZWQgZm9yIHRyYW5zbGF0aW9ucyBvciBmb3JtYXR0aW5nLlxuICAgKiBUaGUga2V5IHJlcHJlc2VudHMgYSByZWxhdGl2ZSB0aW1lIHBlcmlvZCBzdWNoIGFzIFwidG9kYXlcIiwgXCJ5ZXN0ZXJkYXlcIiwgXCJ0aGlzIHdlZWtcIiwgZXRjLlxuICAgKiBJZiB0aGUgZGF0ZSBkb2VzIG5vdCBmYWxsIGludG8gYW55IHByZWRlZmluZWQgcmVsYXRpdmUgdGltZSBwZXJpb2QsIGl0IHJldHVybnMgdGhlIHllYXIgYXMgYSBzdHJpbmcuXG4gICAqXG4gICAqIEBwYXJhbSBkYXRlIC0gVGhlIGRhdGUgZm9yIHdoaWNoIHRoZSB0aW1lIGtleSBpcyB0byBiZSBkZXRlcm1pbmVkLlxuICAgKiBAcmV0dXJucyBBIHN0cmluZyByZXByZXNlbnRpbmcgdGhlIHRpbWUga2V5LCB3aGljaCBjYW4gYmUgdXNlZCBmb3IgdHJhbnNsYXRpb24gb3IgZGlzcGxheSBwdXJwb3Nlcy5cbiAgICovXG4gIGdldFRpbWVLZXkoZGF0ZTogRGF0ZSk6IHN0cmluZyB7XG4gICAgICBpZiAoaXNUb2RheShkYXRlKSkge1xuICAgICAgICByZXR1cm4gdGhpcy50cmFuc2xvY28udHJhbnNsYXRlKCdjaGF0LnRvZGF5Jyk7XG4gICAgICB9IGVsc2UgaWYgKGlzWWVzdGVyZGF5KGRhdGUpKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnRyYW5zbG9jby50cmFuc2xhdGUoJ2NoYXQueWVzdGVyZGF5Jyk7XG4gICAgICB9IGVsc2UgaWYgKGlzVGhpc1dlZWsoZGF0ZSkpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMudHJhbnNsb2NvLnRyYW5zbGF0ZSgnY2hhdC50aGlzV2VlaycpO1xuICAgICAgfSBlbHNlIGlmIChkaWZmZXJlbmNlSW5EYXlzKGVuZE9mWWVzdGVyZGF5KCksIGRhdGUpIDw9IDcpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMudHJhbnNsb2NvLnRyYW5zbGF0ZSgnY2hhdC5sYXN0V2VlaycpO1xuICAgICAgfSBlbHNlIGlmIChpc1RoaXNNb250aChkYXRlKSkge1xuICAgICAgICByZXR1cm4gdGhpcy50cmFuc2xvY28udHJhbnNsYXRlKCdjaGF0LnRoaXNNb250aCcpO1xuICAgICAgfSBlbHNlIGlmIChkaWZmZXJlbmNlSW5Nb250aHMoZW5kT2ZZZXN0ZXJkYXkoKSwgZGF0ZSkgPD0gMSkge1xuICAgICAgICByZXR1cm4gdGhpcy50cmFuc2xvY28udHJhbnNsYXRlKCdjaGF0Lmxhc3RNb250aCcpO1xuICAgICAgfSBlbHNlIGlmIChpc1RoaXNRdWFydGVyKGRhdGUpKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnRyYW5zbG9jby50cmFuc2xhdGUoJ2NoYXQudGhpc1F1YXJ0ZXInKTtcbiAgICAgIH0gZWxzZSBpZiAoZGlmZmVyZW5jZUluTW9udGhzKGVuZE9mWWVzdGVyZGF5KCksIGRhdGUpIDw9IDMpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMudHJhbnNsb2NvLnRyYW5zbGF0ZSgnY2hhdC5sYXN0UXVhcnRlcicpO1xuICAgICAgfSBlbHNlIGlmIChpc1RoaXNZZWFyKGRhdGUpKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnRyYW5zbG9jby50cmFuc2xhdGUoJ2NoYXQudGhpc1llYXInKTtcbiAgICAgIH0gZWxzZSBpZiAoZGlmZmVyZW5jZUluWWVhcnMoZW5kT2ZZZXN0ZXJkYXkoKSwgZGF0ZSkgPT09IDEpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMudHJhbnNsb2NvLnRyYW5zbGF0ZSgnY2hhdC5sYXN0WWVhcicpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmV0dXJuIGZvcm1hdChkYXRlLCAneXl5eScpO1xuICAgICAgfVxuICAgIH1cblxuICBnZXRDdXJyZW50TG9jYWxlTmFtZSgpIHtcbiAgICByZXR1cm4gdGhpcy5sb2NhbElEIHx8ICcnO1xuICB9XG59XG4iXX0=
602
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hhdC5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vcHJvamVjdHMvYXNzaXN0YW50L2NoYXQvY2hhdC5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ25ELE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQ3RELE9BQU8sRUFDTCxlQUFlLEVBQ2YsVUFBVSxFQUNWLEtBQUssRUFDTCxNQUFNLEVBQ04sUUFBUSxFQUNSLElBQUksRUFDSixHQUFHLEVBRUgsU0FBUyxFQUNULElBQUksRUFDSixHQUFHLEVBQ0gsVUFBVSxFQUNYLE1BQU0sTUFBTSxDQUFDO0FBRWQsT0FBTyxFQUNMLEtBQUssRUFFTCxJQUFJLEVBQ0osWUFBWSxFQUNiLE1BQU0saUJBQWlCLENBQUM7QUFFekIsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQ3BELE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBQ3ZFLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBQ2hFLE9BQU8sRUFBRSxzQkFBc0IsRUFBRSxNQUFNLGtDQUFrQyxDQUFDO0FBcUIxRSxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDdkQsT0FBTyxFQUFFLGlCQUFpQixFQUE2QixNQUFNLG1DQUFtQyxDQUFDO0FBQ2pHLE9BQU8sRUFBRSx3QkFBd0IsRUFBb0MsTUFBTSx1Q0FBdUMsQ0FBQztBQUNuSCxPQUFPLEVBQUUsNkJBQTZCLEVBQTBDLE1BQU0sNENBQTRDLENBQUM7QUFDbkksT0FBTyxFQUFFLHdCQUF3QixFQUFxQyxNQUFNLHVDQUF1QyxDQUFDO0FBQ3BILE9BQU8sRUFBRSw4QkFBOEIsRUFBMkMsTUFBTSw4Q0FBOEMsQ0FBQztBQUN2SSxP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LENBQUM7UUFFRixJQUFJLElBQUksS0FBSyxxQkFBcUIsRUFBRSxDQUFDO1lBQ25DLFdBQVcsQ0FBQyxlQUFlLENBQUMsR0FBRyxLQUFLLENBQUM7UUFDdkMsQ0FBQztRQUVELE1BQU0sS0FBSyxHQUFHO1lBQ1osSUFBSTtZQUNKLE1BQU0sRUFBRTtnQkFDTixHQUFHLFdBQVc7Z0JBQ2QsR0FBRyxPQUFPO2FBQ1g7U0FDRixDQUFBO1FBQ0QsTUFBTSxLQUFLLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQzVCLENBQUM7K0dBbm9CVSxXQUFXO21IQUFYLFdBQVc7OzRGQUFYLFdBQVc7a0JBRHZCLFVBQVUiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3RhYmxlLCBpbmplY3QgfSBmcm9tIFwiQGFuZ3VsYXIvY29yZVwiO1xuaW1wb3J0IHsgVHJhbnNsb2NvU2VydmljZSB9IGZyb20gXCJAanN2ZXJzZS90cmFuc2xvY29cIjtcbmltcG9ydCB7XG4gIEJlaGF2aW9yU3ViamVjdCxcbiAgY2F0Y2hFcnJvcixcbiAgZGVmZXIsXG4gIGZpbHRlcixcbiAgZm9ya0pvaW4sXG4gIGZyb20sXG4gIG1hcCxcbiAgT2JzZXJ2YWJsZSxcbiAgc3dpdGNoTWFwLFxuICB0YWtlLFxuICB0YXAsXG4gIHRocm93RXJyb3Jcbn0gZnJvbSBcInJ4anNcIjtcbmltcG9ydCB7IEh1YkNvbm5lY3Rpb24gfSBmcm9tIFwiQG1pY3Jvc29mdC9zaWduYWxyXCI7XG5pbXBvcnQge1xuICBBdWRpdCxcbiAgUXVlcnksXG4gIGd1aWQsXG4gIGdsb2JhbENvbmZpZ1xufSBmcm9tIFwiQHNpbmVxdWEvYXRvbWljXCI7XG5cbmltcG9ydCB7IEFwcFNlcnZpY2UgfSBmcm9tIFwiLi9zZXJ2aWNlcy9hcHAuc2VydmljZVwiO1xuaW1wb3J0IHsgTm90aWZpY2F0aW9uc1NlcnZpY2UgfSBmcm9tIFwiLi9zZXJ2aWNlcy9ub3RpZmljYXRpb24uc2VydmljZVwiO1xuaW1wb3J0IHsgUHJpbmNpcGFsU2VydmljZSB9IGZyb20gXCIuL3NlcnZpY2VzL3ByaW5jaXBhbC5zZXJ2aWNlXCI7XG5pbXBvcnQgeyBVc2VyU2V0dGluZ3NXZWJTZXJ2aWNlIH0gZnJvbSBcIi4vc2VydmljZXMvdXNlci1zZXR0aW5ncy5zZXJ2aWNlXCI7XG5pbXBvcnQge1xuICBDaGF0Q29uZmlnLFxuICBDaGF0TWVzc2FnZSxcbiAgQ2hhdFJlc3BvbnNlLFxuICBDaGF0VXNhZ2VNZXRyaWNzLFxuICBEZWJ1Z01lc3NhZ2UsXG4gIERlbGV0ZVNhdmVkQ2hhdFJlc3BvbnNlLFxuICBHbGxtRnVuY3Rpb24sXG4gIEdsbG1Nb2RlbERlc2NyaXB0aW9uLFxuICBLdk9iamVjdCxcbiAgTGlzdE9iamVjdCxcbiAgTWVzc2FnZUhhbmRsZXIsXG4gIFF1b3RhLFxuICBTYXZlZENoYXQsXG4gIFNhdmVkQ2hhdEhpc3RvcnksXG4gIFNhdmVkQ2hhdFJlc3BvbnNlLFxuICBUb2tlbkNvbnN1bXB0aW9uLFxuICBVc2VyVG9rZW5Db25zdW1wdGlvblxufSBmcm9tIFwiLi90eXBlc1wiO1xuaW1wb3J0IHsgQ29ubmVjdGlvbk9wdGlvbnMgfSBmcm9tIFwiLi9zZXJ2aWNlcy9zaWduYWxSLndlYi5zZXJ2aWNlXCI7XG5pbXBvcnQgeyBBc3Npc3RhbnRVdGlscyB9IGZyb20gXCIuL3V0aWxzL3V0aWxzLnNlcnZpY2VcIjtcbmltcG9ydCB7IFNhdmVkQ2hhdHNTZXJ2aWNlLCBTYXZlZENoYXRzT3BlcmF0aW9uQ29uZmlnIH0gZnJvbSBcIi4vc2F2ZWQtY2hhdHMvc2F2ZWQtY2hhdHMuc2VydmljZVwiO1xuaW1wb3J0IHsgU2lnbmFsUkNvbm5lY3Rpb25TZXJ2aWNlLCBTaWduYWxSQ29ubmVjdGlvbk9wZXJhdGlvbkNvbmZpZyB9IGZyb20gXCIuL3NlcnZpY2VzL3NpZ25hbFItY29ubmVjdGlvbi5zZXJ2aWNlXCI7XG5pbXBvcnQgeyBBc3Npc3RhbnRDb25maWd1cmF0aW9uU2VydmljZSwgQXNzaXN0YW50Q29uZmlndXJhdGlvbk9wZXJhdGlvbkNvbnRleHQgfSBmcm9tIFwiLi9zZXJ2aWNlcy9hc3Npc3RhbnQtY29uZmlndXJhdGlvbi5zZXJ2aWNlXCI7XG5pbXBvcnQgeyBBc3Npc3RhbnRNZXRhZGF0YVNlcnZpY2UsIEFzc2lzdGFudE1ldGFkYXRhT3BlcmF0aW9uQ29udGV4dCB9IGZyb20gXCIuL3NlcnZpY2VzL2Fzc2lzdGFudC1tZXRhZGF0YS5zZXJ2aWNlXCI7XG5pbXBvcnQgeyBBc3Npc3RhbnRUb2tlbnNUcmFja2luZ1NlcnZpY2UsIEFzc2lzdGFudFRva2Vuc1RyYWNraW5nT3BlcmF0aW9uQ29udGV4dCB9IGZyb20gXCIuL3NlcnZpY2VzL2Fzc2lzdGFudC10b2tlbnMtdHJhY2tpbmcuc2VydmljZVwiO1xuaW1wb3J0IHsgQXNzaXN0YW50V3NGcmFtZXNTZXJ2aWNlLCBBc3Npc3RhbnRXc0ZyYW1lc0NvbnRleHQgfSBmcm9tIFwiLi9zZXJ2aWNlcy9hc3Npc3RhbnQtd3MtZnJhbWVzLnNlcnZpY2VcIjsgLy8gQWRkZWRcbmltcG9ydCB7IERlYnVnTWVzc2FnZU9wZXJhdGlvbkNvbmZpZywgRGVidWdNZXNzYWdlU2VydmljZSB9IGZyb20gXCIuL2RlYnVnLW1lc3NhZ2UvZGVidWctbWVzc2FnZS5zZXJ2aWNlXCI7XG5cbkBJbmplY3RhYmxlKClcbmV4cG9ydCBjbGFzcyBDaGF0U2VydmljZSB7XG5cbiAgLyoqIE5hbWUgb2YgdGhlIGFzc2lzdGFudCB3ZWJzb2NrZXQgZW5kcG9pbnQuICovXG4gIFdTX1JFUVVFU1RfVVJMOiBzdHJpbmc7XG4gIC8qKiBOYW1lIG9mIHRoZSBhc3Npc3RhbnQgUkVTVCBlbmRwb2ludC4gKi9cbiAgUkVTVF9SRVFVRVNUX1VSTDogc3RyaW5nO1xuICAvKiogU2lnbmFsUiBjb25uZWN0aW9uIGluc3RhbmNlICovXG4gIHB1YmxpYyBjb25uZWN0aW9uOiBIdWJDb25uZWN0aW9uIHwgdW5kZWZpbmVkO1xuICAvKiogRW1pdCB0cnVlIG9uY2UgdGhlIGluaXRpYWxpemF0aW9uIG9mIHRoZSBhc3Npc3RhbnQgcHJvY2VzcyBpcyBkb25lLiAqL1xuICBpbml0UHJvY2VzcyQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PGJvb2xlYW4+KGZhbHNlKTtcbiAgLyoqIEVtaXQgdHJ1ZSBvbmNlIHRoZSBpbml0aWFsaXphdGlvbiBvZiB0aGUgYXNzaXN0YW50IGNvbmZpZyBpcyBkb25lLiAqL1xuICBpbml0Q29uZmlnJCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8Ym9vbGVhbj4oZmFsc2UpO1xuICAvKiogRW1pdCB0aGUgZ2xvYmFsIGNvbmZpZ3VyYXRpb24gb2YgdGhlIGFzc2lzdGFudC4gKi9cbiAgYXNzaXN0YW50Q29uZmlnJCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8Q2hhdENvbmZpZyB8IHVuZGVmaW5lZD4odW5kZWZpbmVkKTtcbiAgLyoqIEVtaXQgdHJ1ZSBpZiB0aGUgdXNlciBoYXMgYmVlbiBvdmVycmlkZGVuLCBmYWxzZSBvdGhlcndpc2UuICovXG4gIHVzZXJPdmVycmlkZSQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PGJvb2xlYW4gfCB1bmRlZmluZWQ+KHVuZGVmaW5lZCk7XG4gIC8qKlxuICAgKiBFbWl0IHRydWUgaWYgdGhlIGZldGNoIG9mIGFuIGFzc2lzdGFudCdzIHJlc3BvbnNlIGlzIG9uZ29pbmcgKGl0IGluY2x1ZGVzIFN0cmVhbWluZyBzdGF0dXMgb2YgdGhlIGFzc2lzdGFudCBlbmRwb2ludCBBTkQgc2F2aW5nIHRoZSBkaXNjdXNzaW9uIGlmIHNhdmUgQ2hhdCBpcyBlbmFibGVkKS5cbiAgICogVGhpcyBpcyB1c2VkIHRvIHByZXZlbnQgbXVsdGlwbGUgZmV0Y2hlcyBhdCB0aGUgc2FtZSB0aW1lLlxuICAgKiBUeXBpY2FsbHksIHRoZXJlIGlzIG5vIHByb2JsZW0gY2hhaW5pbmcgZmV0Y2hlcywgYnV0IHdoZW4gZm9yY2luZyBhIHJlbG9hZCBhZnRlciBxdWVyeSBjaGFuZ2VzIGNhc2VzLCBpdCBjYW4ndCBiZSBhbGxvd2VkIGJlY2F1c2UgaXQgYnJlYWtzIHRoZSB3aG9sZSBidXNpbmVzcyBsb2dpYy5cbiAgKi9cbiAgc3RyZWFtaW5nJCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8Ym9vbGVhbj4oZmFsc2UpO1xuICAvKiogU3RvcmUgdGhlIG1lc3NhZ2VzIGhpc3Rvcnkgb2YgdGhlIGN1cnJlbnQgY2hhdC4gKi9cbiAgY2hhdEhpc3Rvcnk6IENoYXRNZXNzYWdlW10gfCB1bmRlZmluZWQ7XG4gIC8qKiBMaXN0IG9mIG1vZGVscyBhdmFpbGFibGUgb24gdGhlIHNlcnZlci4gKi9cbiAgbW9kZWxzOiBHbGxtTW9kZWxEZXNjcmlwdGlvbltdIHwgdW5kZWZpbmVkO1xuICAvKiogTGlzdCBvZiBmdW5jdGlvbnMgYXZhaWxhYmxlIG9uIHRoZSBzZXJ2ZXIuICovXG4gIGZ1bmN0aW9uczogR2xsbUZ1bmN0aW9uW10gfCB1bmRlZmluZWQ7XG4gIC8qKiBMaXN0IG9mIHNhdmVkIGNoYXRzLiAqL1xuICBzYXZlZENoYXRzJCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8U2F2ZWRDaGF0W10+KFtdKTtcbiAgLyoqIFdoZXRoZXIgdGhlcmUgaXMgYW4gZXJyb3Igd2l0aCBzYXZlZCBjaGF0cy4gKi9cbiAgc2F2ZWRDaGF0c0Vycm9yJCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8Ym9vbGVhbj4oZmFsc2UpO1xuICAvKiogRW1pdCB0aGUgc2F2ZWQgY2hhdCB0byBsb2FkLiAqL1xuICBsb2FkU2F2ZWRDaGF0JCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8U2F2ZWRDaGF0IHwgdW5kZWZpbmVkPih1bmRlZmluZWQpO1xuICAvKiogRW1pdCB0aGUgcXVvdGEgZWFjaCB0aW1lIHRoZSBjaGF0IGlzIGludm9rZWQuICovXG4gIHF1b3RhJCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8UXVvdGEgfCB1bmRlZmluZWQ+KHVuZGVmaW5lZCk7XG4gIC8qKiBFbWl0IHRoZSBjYWxjdWxhdGVkIHVzZXIncyB0b2tlbiBjb25zdW1wdGlvbiBiYXNlZCBvbiB0aGUgcXVvdGEuICovXG4gIHVzZXJUb2tlbkNvbnN1bXB0aW9uJCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8VXNlclRva2VuQ29uc3VtcHRpb24gfCB1bmRlZmluZWQ+KHVuZGVmaW5lZCk7XG4gIC8qKiBFbWl0IHRoZSBjaGF0IHVzYWdlIG1ldHJpY3MgZWFjaCB0aW1lIHRoZSBnZW5lcmF0aW9uIG9mIHRoZSBhc3Npc3RhbnQgcmVzcG9uc2UgaXMgY29tcGxldGVkLiAqL1xuICBjaGF0VXNhZ2VNZXRyaWNzJCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8Q2hhdFVzYWdlTWV0cmljcyB8IHVuZGVmaW5lZD4odW5kZWZpbmVkKTtcbiAgLyoqIEVtaXQgdGhlIGNhbGN1bGF0ZWQgY2hhdCdzIHRva2VuIGNvbnN1bXB0aW9uIGJhc2VkIG9uIHRoZSBjaGF0IHVzYWdlIG1ldHJpY3MuICovXG4gIGNoYXRUb2tlbkNvbnN1bXB0aW9uJCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8VG9rZW5Db25zdW1wdGlvbiB8IHVuZGVmaW5lZD4odW5kZWZpbmVkKTtcbiAgLyoqIEVtaXQgdHJ1ZSBpZiBcIkNhbmNlbFRhc2tzXCIgaXMgb25nb2luZy4gKi9cbiAgc3RvcHBpbmdHZW5lcmF0aW9uJCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8Ym9vbGVhbj4oZmFsc2UpO1xuICAvKiogSW5zdGFuY2UgSUQgb2YgdGhlIGNoYXQgc2VydmljZSBkZWZpbmluZyB0aGUgYXNzaXN0YW50IGluc3RhbmNlLiAqL1xuICBwcml2YXRlIF9jaGF0SW5zdGFuY2VJZDogc3RyaW5nO1xuICAvKiogR2VuZXJhdGVkIEdVSUQgZm9yIHRoZSBjdXJyZW50IGNoYXQgZGlzY3Vzc2lvbiB1c2VkIHRvIHNhdmUvZ2V0L2RlbGV0ZSBpdCBhbmQgaWRlbnRpZnkgYXVkaXQgZXZlbnRzLiAqL1xuICBwcml2YXRlIF9jaGF0SWQ6IHN0cmluZztcblxuICBwdWJsaWMgdXNlclNldHRpbmdzU2VydmljZSA9IGluamVjdChVc2VyU2V0dGluZ3NXZWJTZXJ2aWNlKTtcbiAgcHVibGljIG5vdGlmaWNhdGlvbnNTZXJ2aWNlID0gaW5qZWN0KE5vdGlmaWNhdGlvbnNTZXJ2aWNlKTtcbiAgcHVibGljIGFwcFNlcnZpY2UgPSBpbmplY3QoQXBwU2VydmljZSk7XG4gIHB1YmxpYyBwcmluY2lwYWxTZXJ2aWNlID0gaW5qZWN0KFByaW5jaXBhbFNlcnZpY2UpO1xuICBwdWJsaWMgYXNzaXN0YW50VXRpbHMgPSBpbmplY3QoQXNzaXN0YW50VXRpbHMpO1xuICBwcml2YXRlIHNhdmVkQ2hhdHNTZXJ2aWNlID0gaW5qZWN0KFNhdmVkQ2hhdHNTZXJ2aWNlKTtcbiAgcHJpdmF0ZSBzaWduYWxSQ29ubmVjdGlvblNlcnZpY2UgPSBpbmplY3QoU2lnbmFsUkNvbm5lY3Rpb25TZXJ2aWNlKTtcbiAgcHJpdmF0ZSBhc3Npc3RhbnRDb25maWd1cmF0aW9uU2VydmljZSA9IGluamVjdChBc3Npc3RhbnRDb25maWd1cmF0aW9uU2VydmljZSk7XG4gIHByaXZhdGUgYXNzaXN0YW50TWV0YWRhdGFTZXJ2aWNlID0gaW5qZWN0KEFzc2lzdGFudE1ldGFkYXRhU2VydmljZSk7XG4gIHByaXZhdGUgYXNzaXN0YW50VG9rZW5zVHJhY2tpbmdTZXJ2aWNlID0gaW5qZWN0KEFzc2lzdGFudFRva2Vuc1RyYWNraW5nU2VydmljZSk7XG4gIHByaXZhdGUgZGVidWdNZXNzYWdlU2VydmljZSA9IGluamVjdChEZWJ1Z01lc3NhZ2VTZXJ2aWNlKTtcbiAgLy8gSW5qZWN0IHRoZSBBc3Npc3RhbnRXc0ZyYW1lc1NlcnZpY2UgdXNpbmcgJ25ldycgdG8gZW5zdXJlIGEgc2VwYXJhdGUgbG9jYWwgaW5zdGFuY2UgZm9yIGVhY2ggQ2hhdFNlcnZpY2UgaW5zdGFuY2VcbiAgcHJpdmF0ZSBhc3Npc3RhbnRXc0ZyYW1lc1NlcnZpY2UgPSBuZXcoQXNzaXN0YW50V3NGcmFtZXNTZXJ2aWNlKTtcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IHRyYW5zbG9jbyA9IGluamVjdChUcmFuc2xvY29TZXJ2aWNlKTtcblxuICAvKipcbiAgICogSW5pdGlhbGl6ZSB0aGUgYXNzaXN0YW50IHByb2Nlc3MuXG4gICAqIEl0IGluY2x1ZGVzIGJ1aWxkaW5nIGFuZCBzdGFydGluZyBhIGNvbm5lY3Rpb24sIGV4ZWN1dGluZyBwYXJhbGxlbCByZXF1ZXN0cyBmb3IgbW9kZWxzIGFuZCBmdW5jdGlvbnMsIGFuZCBoYW5kbGluZyBlcnJvcnMgZHVyaW5nIHRoZSBwcm9jZXNzLlxuICAgKiDimqDvuI8gVGhpcyBtZXRob2QgTVVTVCBiZSBjYWxsZWQgT05MWSBpZiB0aGUgdXNlciBpcyBsb2dnZWRJbiBhbmQgb25jZSB3aGVuIHRoZSBhc3Npc3RhbnQgaXMgaW5pdGlhbGl6ZWQuXG4gICAqXG4gICAqIEByZXR1cm5zIEFuIE9ic2VydmFibGU8Ym9vbGVhbj4gaW5kaWNhdGluZyB0aGUgc3VjY2VzcyBvZiB0aGUgaW5pdGlhbGl6YXRpb24gcHJvY2Vzcy5cbiAgICovXG4gIGluaXQoKTogT2JzZXJ2YWJsZTxib29sZWFuPiB7XG4gICAgLy8gRW5zdXJlIGFsbCBsb2dpYyBpcyBleGVjdXRlZCB3aGVuIHN1YnNjcmliZWQgdG8gdGhlIG9ic2VydmFibGVcbiAgICByZXR1cm4gZGVmZXIoKCkgPT4ge1xuICAgICAgdGhpcy5faW5pdEFzc2lzdGFudENvbmZpZ3VyYXRpb25TZXJ2aWNlKCk7XG4gICAgICByZXR1cm4gZnJvbSh0aGlzLmluaXRDaGF0Q29uZmlnKCkpO1xuICAgIH0pLnBpcGUoXG4gICAgICAvLyBXYWl0IGZvciB0aGUgY29uZmlndXJhdGlvbiB0byBiZSBpbml0aWFsaXplZFxuICAgICAgc3dpdGNoTWFwKCgpID0+IHRoaXMuaW5pdENvbmZpZyQucGlwZShmaWx0ZXIoQm9vbGVhbiksIHRha2UoMSkpKSxcbiAgICAgIHRhcCgoKSA9PiB7XG4gICAgICAgIHRoaXMuZ2V0V1NSZXF1ZXN0c1VybCgpO1xuICAgICAgICB0aGlzLmdldFJFU1RSZXF1ZXN0c1VybCgpO1xuICAgICAgICB0aGlzLl9pbml0QXNzaXN0YW50TWV0YWRhdGFTZXJ2aWNlKCk7XG4gICAgICAgIHRoaXMuX2luaXRBc3Npc3RhbnRUb2tlbnNUcmFja2luZ1NlcnZpY2UoKTtcbiAgICAgICAgdGhpcy5faW5pdFNhdmVkQ2hhdHNTZXJ2aWNlKCk7XG4gICAgICAgIHRoaXMuX2luaXREZWJ1Z01lc3NhZ2VTZXJ2aWNlKCk7XG4gICAgICAgIHRoaXMuX2luaXRTaWduYWxSQ29ubmVjdGlvblNlcnZpY2UoKTtcbiAgICAgIH0pLFxuICAgICAgLy8gQnVpbGQgYW5kIHN0YXJ0IHRoZSBTaWduYWxSIGNvbm5lY3Rpb25cbiAgICAgIHN3aXRjaE1hcCgoKSA9PiB0aGlzLmJ1aWxkQ29ubmVjdGlvbigpKSxcbiAgICAgIHRhcCgoKSA9PiB7XG4gICAgICAgIC8vIEluaXRpYWxpemUgQXNzaXN0YW50V3NGcmFtZXNTZXJ2aWNlIGhlcmUsIG5vdyB0aGF0ICd0aGlzLmNvbm5lY3Rpb24nIGlzIHNldFxuICAgICAgICB0aGlzLl9pbml0QXNzaXN0YW50V3NGcmFtZXNTZXJ2aWNlKCk7XG4gICAgICAgIHRoaXMuaW5pdE1lc3NhZ2VIYW5kbGVycygpO1xuICAgICAgfSksXG4gICAgICAvLyBTdGFydCB0aGUgY29ubmVjdGlvblxuICAgICAgc3dpdGNoTWFwKCgpID0+IHRoaXMuc3RhcnRDb25uZWN0aW9uKCkpLFxuICAgICAgLy8gRmV0Y2ggbWV0YWRhdGEgaW4gcGFyYWxsZWxcbiAgICAgIHN3aXRjaE1hcCgoKSA9PlxuICAgICAgICBmb3JrSm9pbihbXG4gICAgICAgICAgdGhpcy5saXN0TW9kZWxzKCksXG4gICAgICAgICAgdGhpcy5saXN0RnVuY3Rpb25zKClcbiAgICAgICAgXSlcbiAgICAgICksXG4gICAgICAvLyBNYXAgdGhlIHJlc3VsdHMgb2YgcGFyYWxsZWwgcmVxdWVzdHMgdG8gYSBib29sZWFuIGluZGljYXRpbmcgc3VjY2Vzc1xuICAgICAgbWFwKChbbW9kZWxzLCBmdW5jdGlvbnNdKSA9PiB7XG4gICAgICAgIGNvbnN0IHJlc3VsdCA9ICEhbW9kZWxzICYmICEhZnVuY3Rpb25zO1xuICAgICAgICB0aGlzLmluaXRQcm9jZXNzJC5uZXh0KHJlc3VsdCk7XG4gICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgICB9KSxcbiAgICAgIC8vIEFueSBlcnJvcnMgZHVyaW5nIHRoZSBwcm9jZXNzIGFyZSBjYXVnaHQsIGxvZ2dlZCwgYW5kIHJlLXRocm93biB0byBwcm9wYWdhdGUgdGhlIGVycm9yIGZ1cnRoZXJcbiAgICAgIGNhdGNoRXJyb3IoKGVycm9yKSA9PiB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoJ0Vycm9yIG9jY3VycmVkOicsIGVycm9yKTtcbiAgICAgICAgcmV0dXJuIHRocm93RXJyb3IoKCkgPT4gZXJyb3IpO1xuICAgICAgfSksXG4gICAgICB0YWtlKDEpXG4gICAgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBEZWZpbmUgdGhlIGVuZHBvaW50IHRvIHVzZSBmb3IgdGhlIHdlYnNvY2tldCByZXF1ZXN0c1xuICAgKiBJdCBjYW4gYmUgb3ZlcnJpZGRlbiBieSB0aGUgYXBwIGNvbmZpZ1xuICAgKi9cbiAgZ2V0V1NSZXF1ZXN0c1VybCgpIHtcbiAgICB0aGlzLmFzc2lzdGFudENvbmZpZ3VyYXRpb25TZXJ2aWNlLmdldFdTUmVxdWVzdHNVcmwoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBEZWZpbmUgdGhlIGVuZHBvaW50IHRvIHVzZSBmb3IgdGhlIGh0dHAgcmVxdWVzdHNcbiAgICogSXQgY2FuIGJlIG92ZXJyaWRkZW4gYnkgdGhlIGFwcCBjb25maWdcbiAgICovXG4gIGdldFJFU1RSZXF1ZXN0c1VybCgpIHtcbiAgICB0aGlzLmFzc2lzdGFudENvbmZpZ3VyYXRpb25TZXJ2aWNlLmdldFJFU1RSZXF1ZXN0c1VybCgpO1xuICB9XG5cbiAgLyoqXG4gICAqIEluaXRpYWxpemVzIHRoZSBTYXZlZENoYXRzU2VydmljZSB3aXRoIHRoZSBuZWNlc3NhcnkgY29uZmlndXJhdGlvbi5cbiAgICpcbiAgICogVGhpcyBtZXRob2Qgc2V0cyB1cCB0aGUgYFNhdmVkQ2hhdHNTZXJ2aWNlYCBieSBwcm92aWRpbmcgaXQgd2l0aCBhIGNvbmZpZ3VyYXRpb24gb2JqZWN0XG4gICAqIChgU2F2ZWRDaGF0c09wZXJhdGlvbkNvbmZpZ2ApIHRoYXQgaW5jbHVkZXMgdmFyaW91cyBjYWxsYmFja3MgYW5kIHByb3BlcnRpZXMgcmVxdWlyZWRcbiAgICogZm9yIGl0cyBvcGVyYXRpb24uIFRoZSBpbml0aWFsaXphdGlvbiB3aWxsIG9ubHkgcHJvY2VlZCBpZiBib3RoIGBhc3Npc3RhbnRDb25maWckYCBhbmRcbiAgICogYFJFU1RfUkVRVUVTVF9VUkxgIGFyZSBhdmFpbGFibGUuXG4gICAqXG4gICAqIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBpbmNsdWRlczpcbiAgICogLSBBcHBsaWNhdGlvbiBuYW1lIHJldHJpZXZhbC5cbiAgICogLSBJbnN0YW5jZSBJRCByZXRyaWV2YWwuXG4gICAqIC0gUkVTVCBBUEkgVVJMIHJldHJpZXZhbC5cbiAgICogLSBEZWJ1ZyBmbGFnIHJldHJpZXZhbC5cbiAgICogLSBDaGF0IElEIGZvciBuZXcgc2F2ZXMuXG4gICAqIC0gU2F2ZWQgY2hhdHMgZW5hYmxlbWVudCBjaGVjay5cbiAgICogLSBNZXRob2RzIGZvciBzZXR0aW5nIGEgc2F2ZWQgY2hhdCBJRCwgdXBkYXRpbmcgdGhlIHNhdmVkIGNoYXRzIGxpc3QsIGFuZCBnZW5lcmF0aW5nIGF1ZGl0IGV2ZW50cy5cbiAgICpcbiAgICogSWYgdGhlIHJlcXVpcmVkIGRlcGVuZGVuY2llcyBhcmUgbm90IHJlYWR5LCBhbiBlcnJvciBpcyBsb2dnZWQgdG8gdGhlIGNvbnNvbGUuXG4gICAqXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBwcml2YXRlIF9pbml0U2F2ZWRDaGF0c1NlcnZpY2UoKSB7XG4gICAgaWYgKHRoaXMuYXNzaXN0YW50Q29uZmlnJC52YWx1ZSAmJiB0aGlzLlJFU1RfUkVRVUVTVF9VUkwpIHtcbiAgICAgIGNvbnN0IHNhdmVkQ2hhdHNPcENvbmZpZzogU2F2ZWRDaGF0c09wZXJhdGlvbkNvbmZpZyA9IHtcbiAgICAgICAgZ2V0QXBwTmFtZTogKCkgPT4gdGhpcy5hcHBTZXJ2aWNlLmFwcE5hbWUsXG4gICAgICAgIGdldEluc3RhbmNlSWQ6ICgpID0+IHRoaXMuY2hhdEluc3RhbmNlSWQsXG4gICAgICAgIGdldFJlc3RVcmw6ICgpID0+IHRoaXMuUkVTVF9SRVFVRVNUX1VSTCxcbiAgICAgICAgZ2V0RGVidWdGbGFnOiAoKSA9PiB0aGlzLmFzc2lzdGFudENvbmZpZyQudmFsdWUhLmRlZmF1bHRWYWx1ZXMuZGVidWcsXG4gICAgICAgIGlzU2F2ZWRDaGF0c0VuYWJsZWQ6ICgpID0+ICEhdGhpcy5hc3Npc3RhbnRDb25maWckLnZhbHVlPy5zYXZlZENoYXRTZXR0aW5ncy5lbmFibGVkLFxuICAgICAgICBzZXRTYXZlZENoYXRzRXJyb3JTdGF0dXM6IChoYXNFcnJvcikgPT4gdGhpcy5zYXZlZENoYXRzRXJyb3IkLm5leHQoaGFzRXJyb3IpLFxuICAgICAgICB1cGRhdGVTYXZlZENoYXRzTGlzdDogKGNoYXRzKSA9PiB0aGlzLnNhdmVkQ2hhdHMkLm5leHQoY2hhdHMpLFxuICAgICAgICBnZW5lcmF0ZUF1ZGl0RXZlbnQ6ICh0eXBlLCBkZXRhaWxzLCBpZCkgPT4gdGhpcy5nZW5lcmF0ZUF1ZGl0RXZlbnQodHlwZSwgZGV0YWlscywgaWQpLFxuICAgICAgfTtcbiAgICAgIHRoaXMuc2F2ZWRDaGF0c1NlcnZpY2UuaW5pdChzYXZlZENoYXRzT3BDb25maWcpO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBUaGlzIGNhc2Ugc2hvdWxkIGlkZWFsbHkgbm90IGhhcHBlbiBpZiBpbml0IG9yZGVyIGlzIGNvcnJlY3RcbiAgICAgIGNvbnNvbGUuZXJyb3IoXCJDYW5ub3QgaW5pdGlhbGl6ZSBTYXZlZENoYXRzU2VydmljZTogYXNzaXN0YW50Q29uZmlnIG9yIFJFU1RfUkVRVUVTVF9VUkwgbm90IHJlYWR5LlwiKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogSW5pdGlhbGl6ZXMgdGhlIFNpZ25hbFIgY29ubmVjdGlvbiBzZXJ2aWNlIHdpdGggdGhlIG5lY2Vzc2FyeSBjb25maWd1cmF0aW9uLlxuICAgKlxuICAgKiBUaGlzIG1ldGhvZCBlbnN1cmVzIHRoYXQgdGhlIFNpZ25hbFIgY29ubmVjdGlvbiBzZXJ2aWNlIGlzIHByb3Blcmx5IHNldCB1cFxuICAgKiBieSBwcm92aWRpbmcgaXQgd2l0aCB0aGUgcmVxdWlyZWQgY29uZmlndXJhdGlvbiB2YWx1ZXMsIHN1Y2ggYXMgdGhlIFdlYlNvY2tldFxuICAgKiByZXF1ZXN0IFVSTCBhbmQgYXNzaXN0YW50IGNvbmZpZ3VyYXRpb24uIEl0IGFsc28gbWFuYWdlcyB0aGUgU2lnbmFsUiBodWIgY29ubmVjdGlvblxuICAgKiBpbnN0YW5jZS5cbiAgICpcbiAgICogUHJlY29uZGl0aW9uczpcbiAgICogLSBgYXNzaXN0YW50Q29uZmlnJC52YWx1ZWAgbXVzdCBiZSBhdmFpbGFibGUuXG4gICAqIC0gYFdTX1JFUVVFU1RfVVJMYCBtdXN0IGJlIGRlZmluZWQuXG4gICAqXG4gICAqIElmIHRoZXNlIHByZWNvbmRpdGlvbnMgYXJlIG5vdCBtZXQsIGFuIGVycm9yIGlzIGxvZ2dlZCB0byB0aGUgY29uc29sZS5cbiAgICpcbiAgICogQHByaXZhdGVcbiAgICovXG4gIHByaXZhdGUgX2luaXRTaWduYWxSQ29ubmVjdGlvblNlcnZpY2UoKSB7XG4gICAgaWYgKHRoaXMuYXNzaXN0YW50Q29uZmlnJC52YWx1ZSAmJiB0aGlzLldTX1JFUVVFU1RfVVJMKSB7XG4gICAgICAgIGNvbnN0IHNpZ25hbFJPcENvbmZpZzogU2lnbmFsUkNvbm5lY3Rpb25PcGVyYXRpb25Db25maWcgPSB7XG4gICAgICAgICAgICBnZXRXc1JlcXVlc3RVcmw6ICgpID0+IHRoaXMuV1NfUkVRVUVTVF9VUkwsXG4gICAgICAgICAgICBnZXRBc3Npc3RhbnRDb25maWdWYWx1ZTogKCkgPT4gdGhpcy5hc3Npc3RhbnRDb25maWckLnZhbHVlLFxuICAgICAgICAgICAgZ2V0SHViQ29ubmVjdGlvbjogKCkgPT4gdGhpcy5jb25uZWN0aW9uLCAvLyBVc2luZyBnZXRIdWJDb25uZWN0aW9uIGFzIHBlciB1c2VyJ3MgZmlsZVxuICAgICAgICAgICAgc2V0SHViQ29ubmVjdGlvbjogKGNvbm4pID0+IHsgdGhpcy5jb25uZWN0aW9uID0gY29ubjsgfVxuICAgICAgICB9O1xuICAgICAgICB0aGlzLnNpZ25hbFJDb25uZWN0aW9uU2VydmljZS5pbml0KHNpZ25hbFJPcENvbmZpZyk7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIFRoaXMgY2FzZSBzaG91bGQgaWRlYWxseSBub3QgaGFwcGVuIGlmIGluaXQgb3JkZXIgaXMgY29ycmVjdFxuICAgICAgICBjb25zb2xlLmVycm9yKFwiQ2Fubm90IGluaXRpYWxpemUgU2lnbmFsUkNvbm5lY3Rpb25TZXJ2aWNlOiBhc3Npc3RhbnRDb25maWcgb3IgV1NfUkVRVUVTVF9VUkwgbm90IHJlYWR5LlwiKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogSW5pdGlhbGl6ZXMgdGhlIEFzc2lzdGFudCBDb25maWd1cmF0aW9uIFNlcnZpY2Ugd2l0aCB0aGUgbmVjZXNzYXJ5IG9wZXJhdGlvbiBjb250ZXh0LlxuICAgKiBUaGlzIG1ldGhvZCBzZXRzIHVwIHRoZSBjb25maWd1cmF0aW9uIGNvbnRleHQgYnkgcHJvdmlkaW5nIHZhcmlvdXMgdXRpbGl0eSBmdW5jdGlvbnNcbiAgICogYW5kIHN0YXRlIG1hbmFnZW1lbnQgbWVjaGFuaXNtcyByZXF1aXJlZCBmb3IgdGhlIGFzc2lzdGFudCdzIGNvbmZpZ3VyYXRpb24gb3BlcmF0aW9ucy5cbiAgICpcbiAgICogVGhlIG9wZXJhdGlvbiBjb250ZXh0IGluY2x1ZGVzOlxuICAgKiAtIE1ldGhvZHMgdG8gcmV0cmlldmUgY2hhdCBpbnN0YW5jZSBhbmQgY2hhdCBJRHMuXG4gICAqIC0gTWV0aG9kcyB0byBnZXQgYW5kIHNldCBhc3Npc3RhbnQgY29uZmlndXJhdGlvbiB2YWx1ZXMuXG4gICAqIC0gTWV0aG9kcyB0byBzZXQgV2ViU29ja2V0IGFuZCBSRVNUIHJlcXVlc3QgVVJMcy5cbiAgICogLSBNZXRob2RzIHRvIHVwZGF0ZSB0aGUgaW5pdGlhbGl6YXRpb24gY29uZmlndXJhdGlvbiBzdGF0dXMuXG4gICAqIC0gQSBtZXRob2QgdG8gZ2VuZXJhdGUgYXVkaXQgZXZlbnRzIGZvciB0cmFja2luZyBvcGVyYXRpb25zLlxuICAgKlxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgcHJpdmF0ZSBfaW5pdEFzc2lzdGFudENvbmZpZ3VyYXRpb25TZXJ2aWNlKCkge1xuICAgIGNvbnN0IGNvbmZpZ09wQ29udGV4dDogQXNzaXN0YW50Q29uZmlndXJhdGlvbk9wZXJhdGlvbkNvbnRleHQgPSB7XG4gICAgICAgIGdldENoYXRJbnN0YW5jZUlkOiAoKSA9PiB0aGlzLmNoYXRJbnN0YW5jZUlkLFxuICAgICAgICBnZXRDaGF0SWQ6ICgpID0+IHRoaXMuY2hhdElkLFxuICAgICAgICBnZXRBc3Npc3RhbnRDb25maWdWYWx1ZTogKCkgPT4gdGhpcy5hc3Npc3RhbnRDb25maWckLnZhbHVlLFxuICAgICAgICBzZXRXU1JlcXVlc3RzVXJsOiAodXJsKSA9PiB0aGlzLldTX1JFUVVFU1RfVVJMID0gdXJsLFxuICAgICAgICBzZXRSRVNUUmVxdWVzdHNVcmw6ICh1cmwpID0+IHRoaXMuUkVTVF9SRVFVRVNUX1VSTCA9IHVybCxcbiAgICAgICAgc2V0QXNzaXN0YW50Q29uZmlnOiAoY29uZmlnKSA9PiB0aGlzLmFzc2lzdGFudENvbmZpZyQubmV4dChjb25maWcpLFxuICAgICAgICBzZXRJbml0Q29uZmlnU3RhdHVzOiAoc3RhdHVzKSA9PiB0aGlzLmluaXRDb25maWckLm5leHQoc3RhdHVzKSxcbiAgICAgICAgZ2VuZXJhdGVBdWRpdEV2ZW50OiAodHlwZSwgZGV0YWlscywgaWQpID0+IHRoaXMuZ2VuZXJhdGVBdWRpdEV2ZW50KHR5cGUsIGRldGFpbHMsIGlkKVxuICAgIH07XG4gICAgdGhpcy5hc3Npc3RhbnRDb25maWd1cmF0aW9uU2VydmljZS5pbml0KGNvbmZpZ09wQ29udGV4dCk7XG4gIH1cblxuICAvKipcbiAgICogSW5pdGlhbGl6ZXMgdGhlIEFzc2lzdGFudE1ldGFkYXRhU2VydmljZSB3aXRoIHRoZSBuZWNlc3Nhcnkgb3BlcmF0aW9uIGNvbnRleHQuXG4gICAqXG4gICAqIFRoaXMgbWV0aG9kIGNoZWNrcyBpZiB0aGUgYGFzc2lzdGFudENvbmZpZyRgIHZhbHVlIGFuZCBgUkVTVF9SRVFVRVNUX1VSTGAgYXJlIGF2YWlsYWJsZS5cbiAgICogSWYgYm90aCBhcmUgcmVhZHksIGl0IGNyZWF0ZXMgYW4gYEFzc2lzdGFudE1ldGFkYXRhT3BlcmF0aW9uQ29udGV4dGAgb2JqZWN0IGFuZFxuICAgKiBpbml0aWFsaXplcyB0aGUgYGFzc2lzdGFudE1ldGFkYXRhU2VydmljZWAgd2l0aCBpdC4gVGhlIG9wZXJhdGlvbiBjb250ZXh0IHByb3ZpZGVzXG4gICAqIG1ldGhvZHMgdG8gcmV0cmlldmUgdGhlIFJFU1QgVVJMLCBhc3Npc3RhbnQgY29uZmlndXJhdGlvbiwgYW5kIHRvIHNldCBtb2RlbHMgYW5kIGZ1bmN0aW9ucy5cbiAgICpcbiAgICogSWYgdGhlIHJlcXVpcmVkIHZhbHVlcyBhcmUgbm90IHJlYWR5LCBhbiBlcnJvciBpcyBsb2dnZWQgdG8gdGhlIGNvbnNvbGUuXG4gICAqXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBwcml2YXRlIF9pbml0QXNzaXN0YW50TWV0YWRhdGFTZXJ2aWNlKCkge1xuICAgIGlmICh0aGlzLmFzc2lzdGFudENvbmZpZyQudmFsdWUgJiYgdGhpcy5SRVNUX1JFUVVFU1RfVVJMKSB7XG4gICAgICBjb25zdCBtZXRhZGF0YU9wQ29udGV4dDogQXNzaXN0YW50TWV0YWRhdGFPcGVyYXRpb25Db250ZXh0ID0ge1xuICAgICAgICBnZXRSZXN0VXJsOiAoKSA9PiB0aGlzLlJFU1RfUkVRVUVTVF9VUkwsXG4gICAgICAgIGdldEFzc2lzdGFudENvbmZpZ1ZhbHVlOiAoKSA9PiB0aGlzLmFzc2lzdGFudENvbmZpZyQudmFsdWUsXG4gICAgICAgIHNldE1vZGVsczogKG1vZGVscykgPT4geyB0aGlzLm1vZGVscyA9IG1vZGVsczsgfSxcbiAgICAgICAgc2V0RnVuY3Rpb25zOiAoZnVuY3Rpb25zKSA9PiB7IHRoaXMuZnVuY3Rpb25zID0gZnVuY3Rpb25zOyB9XG4gICAgICB9O1xuICAgICAgdGhpcy5hc3Npc3RhbnRNZXRhZGF0YVNlcnZpY2UuaW5pdChtZXRhZGF0YU9wQ29udGV4dCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoXCJDYW5ub3QgaW5pdGlhbGl6ZSBBc3Npc3RhbnRNZXRhZGF0YVNlcnZpY2U6IGFzc2lzdGFudENvbmZpZyBvciBSRVNUX1JFUVVFU1RfVVJMIG5vdCByZWFkeS5cIik7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEluaXRpYWxpemVzIHRoZSBBc3Npc3RhbnQgVG9rZW5zIFRyYWNraW5nIFNlcnZpY2Ugd2l0aCB0aGUgbmVjZXNzYXJ5IG9wZXJhdGlvbiBjb250ZXh0LlxuICAgKiBUaGlzIG1ldGhvZCBzZXRzIHVwIHRoZSBzZXJ2aWNlIGJ5IHByb3ZpZGluZyBpdCB3aXRoIGZ1bmN0aW9ucyB0byBtYW5hZ2UgcXVvdGFzLFxuICAgKiB0b2tlbiBjb25zdW1wdGlvbiwgdXNhZ2UgbWV0cmljcywgYW5kIGF1ZGl0IGV2ZW50cywgYXMgd2VsbCBhcyBhY2Nlc3MgdG8gYXNzaXN0YW50IGNvbmZpZ3VyYXRpb25cbiAgICogYW5kIG1vZGVsIHJldHJpZXZhbC5cbiAgICpcbiAgICogVGhlIGluaXRpYWxpemF0aW9uIHdpbGwgb25seSBwcm9jZWVkIGlmIHRoZSBhc3Npc3RhbnQgY29uZmlndXJhdGlvbiBpcyBhdmFpbGFibGUuXG4gICAqIElmIHRoZSBjb25maWd1cmF0aW9uIGlzIG5vdCByZWFkeSwgYW4gZXJyb3IgbWVzc2FnZSBpcyBsb2dnZWQgdG8gdGhlIGNvbnNvbGUuXG4gICAqXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBwcml2YXRlIF9pbml0QXNzaXN0YW50VG9rZW5zVHJhY2tpbmdTZXJ2aWNlKCkge1xuICAgIGlmICh0aGlzLmFzc2lzdGFudENvbmZpZyQudmFsdWUpIHtcbiAgICAgIGNvbnN0IHRva2Vuc09wQ29udGV4dDogQXNzaXN0YW50VG9rZW5zVHJhY2tpbmdPcGVyYXRpb25Db250ZXh0ID0ge1xuICAgICAgICBnZXRBc3Npc3RhbnRDb25maWdWYWx1ZTogKCkgPT4gdGhpcy5hc3Npc3RhbnRDb25maWckLnZhbHVlLFxuICAgICAgICBzZXRRdW90YTogKHF1b3RhKSA9PiB0aGlzLnF1b3RhJC5uZXh0KHF1b3RhKSxcbiAgICAgICAgc2V0VXNlclRva2VuQ29uc3VtcHRpb246IChjb25zdW1wdGlvbikgPT4gdGhpcy51c2VyVG9rZW5Db25zdW1wdGlvbiQubmV4dChjb25zdW1wdGlvbiksXG4gICAgICAgIHNldENoYXRVc2FnZU1ldHJpY3M6IChtZXRyaWNzKSA9PiB0aGlzLmNoYXRVc2FnZU1ldHJpY3MkLm5leHQobWV0cmljcyksXG4gICAgICAgIHNldENoYXRUb2tlbkNvbnN1bXB0aW9uOiAoY29uc3VtcHRpb24pID0+IHRoaXMuY2hhdFRva2VuQ29uc3VtcHRpb24kLm5leHQoY29uc3VtcHRpb24pLFxuICAgICAgICBnZW5lcmF0ZUF1ZGl0RXZlbnQ6ICh0eXBlLCBkZXRhaWxzLCBpZCkgPT4gdGhpcy5nZW5lcmF0ZUF1ZGl0RXZlbnQodHlwZSwgZGV0YWlscywgaWQpLFxuICAgICAgICBnZXRNb2RlbDogKHNlcnZpY2VJZCwgbW9kZWxJZCkgPT4gdGhpcy5nZXRNb2RlbChzZXJ2aWNlSWQsIG1vZGVsSWQpXG4gICAgICB9O1xuICAgICAgdGhpcy5hc3Npc3RhbnRUb2tlbnNUcmFja2luZ1NlcnZpY2UuaW5pdCh0b2tlbnNPcENvbnRleHQpO1xuICAgIH0gZWxzZSB7XG4gICAgICBjb25zb2xlLmVycm9yKFwiQ2Fubm90IGluaXRpYWxpemUgQXNzaXN0YW50VG9rZW5zVHJhY2tpbmdTZXJ2aWNlOiBhc3Npc3RhbnRDb25maWcgbm90IHJlYWR5LlwiKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogSW5pdGlhbGl6ZXMgdGhlIEFzc2lzdGFudCBXZWJTb2NrZXQgRnJhbWVzIFNlcnZpY2Ugd2l0aCB0aGUgbmVjZXNzYXJ5IG9wZXJhdGlvbiBjb250ZXh0LlxuICAgKiBUaGlzIG1ldGhvZCBzZXRzIHVwIHRoZSByZXF1aXJlZCBkZXBlbmRlbmNpZXMgYW5kIGNvbmZpZ3VyYXRpb24gZm9yIHRoZSBzZXJ2aWNlIHRvIGZ1bmN0aW9uIHByb3Blcmx5LlxuICAgKiBJdCBlbnN1cmVzIHRoYXQgdGhlIGFzc2lzdGFudCBjb25maWd1cmF0aW9uIGFuZCBjb25uZWN0aW9uIGFyZSBhdmFpbGFibGUgYmVmb3JlIGluaXRpYWxpemluZyB0aGUgc2VydmljZS5cbiAgICpcbiAgICogVGhlIG9wZXJhdGlvbiBjb250ZXh0IHByb3ZpZGVzIHZhcmlvdXMgdXRpbGl0eSBmdW5jdGlvbnMgYW5kIHN0YXRlIG1hbmFnZW1lbnQgbWV0aG9kcywgaW5jbHVkaW5nOlxuICAgKiAtIEFjY2Vzc2luZyB0aGUgYXNzaXN0YW50IGNvbmZpZ3VyYXRpb24sIGNoYXQgaW5zdGFuY2UgSUQsIHNhdmVkIGNoYXQgSUQsIGFuZCBjaGF0IGhpc3RvcnkuXG4gICAqIC0gTWFuYWdpbmcgc3RyZWFtaW5nIGFuZCBzdG9wcGluZyBnZW5lcmF0aW9uIHN0YXR1c2VzLlxuICAgKiAtIFVwZGF0aW5nIHF1b3RhIGFuZCBjaGF0IHVzYWdlIG1ldHJpY3MuXG4gICAqIC0gR2VuZXJhdGluZyBhdWRpdCBldmVudHMuXG4gICAqIC0gTWFuYWdpbmcgc2F2ZWQgY2hhdHMgKGFkZGluZywgdXBkYXRpbmcsIGFuZCBsaXN0aW5nKS5cbiAgICpcbiAgICogSWYgdGhlIHJlcXVpcmVkIGRlcGVuZGVuY2llcyAoYGFzc2lzdGFudENvbmZpZyRgIGFuZCBgY29ubmVjdGlvbmApIGFyZSBub3QgcmVhZHksIGFuIGVycm9yIGlzIGxvZ2dlZC5cbiAgICpcbiAgICogQHByaXZhdGVcbiAgICovXG4gIHByaXZhdGUgX2luaXRBc3Npc3RhbnRXc0ZyYW1lc1NlcnZpY2UoKSB7XG4gICAgaWYgKHRoaXMuYXNzaXN0YW50Q29uZmlnJC52YWx1ZSAmJiB0aGlzLmNvbm5lY3Rpb24pIHtcbiAgICAgIGNvbnN0IHdzRnJhbWVzT3BDb250ZXh0OiBBc3Npc3RhbnRXc0ZyYW1lc0NvbnRleHQgPSB7XG4gICAgICAgIGdldEFzc2lzdGFudENvbmZpZzogKCkgPT4gdGhpcy5hc3Npc3RhbnRDb25maWckLnZhbHVlLFxuICAgICAgICBnZXRDaGF0SW5zdGFuY2VJZDogKCkgPT4gdGhpcy5jaGF0SW5zdGFuY2VJZCxcbiAgICAgICAgZ2V0Q2hhdElkOiAoKSA9PiB0aGlzLmNoYXRJZCxcbiAgICAgICAgZ2V0SHViQ29ubmVjdGlvbjogKCkgPT4gdGhpcy5jb25uZWN0aW9uLFxuICAgICAgICBnZXRDaGF0SGlzdG9yeTogKCkgPT4gdGhpcy5jaGF0SGlzdG9yeSxcbiAgICAgICAgc2V0U3RyZWFtaW5nU3RhdHVzOiAoaXNTdHJlYW1pbmcpID0+IHRoaXMuc3RyZWFtaW5nJC5uZXh0KGlzU3RyZWFtaW5nKSxcbiAgICAgICAgc2V0Q2hhdEhpc3Rvcnk6IChoaXN0b3J5KSA9PiB7IHRoaXMuY2hhdEhpc3RvcnkgPSBoaXN0b3J5OyB9LFxuICAgICAgICBzZXRTdG9wcGluZ0dlbmVyYXRpb25TdGF0dXM6IChpc1N0b3BwaW5nKSA9PiB0aGlzLnN0b3BwaW5nR2VuZXJhdGlvbiQubmV4dChpc1N0b3BwaW5nKSxcbiAgICAgICAgc2V0U2F2ZWRDaGF0c0Vycm9yU3RhdHVzOiAoaGFzRXJyb3IpID0+IHRoaXMuc2F2ZWRDaGF0c0Vycm9yJC5uZXh0KGhhc0Vycm9yKSxcbiAgICAgICAgdXBkYXRlUXVvdGE6IChxdW90YSwgcHJvcGFnYXRlRXJyb3IpID0+IHRoaXMudXBkYXRlUXVvdGEocXVvdGEsIHByb3BhZ2F0ZUVycm9yKSxcbiAgICAgICAgdXBkYXRlQ2hhdFVzYWdlTWV0cmljczogKG1ldHJpY3MpID0+IHRoaXMudXBkYXRlQ2hhdFVzYWdlTWV0cmljcyhtZXRyaWNzKSxcbiAgICAgICAgZ2VuZXJhdGVBdWRpdEV2ZW50OiAodHlwZSwgZGV0YWlscywgaWQpID0+IHRoaXMuZ2VuZXJhdGVBdWRpdEV2ZW50KHR5cGUsIGRldGFpbHMsIGlkKSxcbiAgICAgICAgYWRkU2F2ZWRDaGF0OiAoaWQsIG1lc3NhZ2VzKSA9PiB0aGlzLmFkZFNhdmVkQ2hhdChpZCwgbWVzc2FnZXMpLFxuICAgICAgICB1cGRhdGVTYXZlZENoYXQ6IChpZCwgbmFtZSwgbWVzc2FnZXMpID0+IHRoaXMudXBkYXRlU2F2ZWRDaGF0KGlkLCBuYW1lLCBtZXNzYWdlcyksXG4gICAgICAgIGxpc3RTYXZlZENoYXQ6ICgpID0+IHRoaXMubGlzdFNhdmVkQ2hhdCgpLFxuICAgICAgICBpc0V4aXN0aW5nU2F2ZWRDaGF0OiAoaWQpID0+IHRoaXMuaXNFeGlzdGluZ1NhdmVkQ2hhdChpZClcbiAgICAgIH07XG4gICAgICB0aGlzLmFzc2lzdGFudFdzRnJhbWVzU2VydmljZS5pbml0KHdzRnJhbWVzT3BDb250ZXh0KTtcbiAgICB9IGVsc2Uge1xuICAgICAgICBjb25zb2xlLmVycm9yKFwiQ2Fubm90IGluaXRpYWxpemUgQXNzaXN0YW50V3NGcmFtZXNTZXJ2aWNlOiBjb3JlIGRlcGVuZGVuY2llcyBub3QgcmVhZHkuXCIpO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgX2luaXREZWJ1Z01lc3NhZ2VTZXJ2aWNlKCkge1xuICAgIGlmICh0aGlzLmFzc2lzdGFudENvbmZpZyQudmFsdWUgJiYgdGhpcy5SRVNUX1JFUVVFU1RfVVJMKSB7XG4gICAgICBjb25zdCBkZWJ1Z01lc3NhZ2VPcENvbnRleHQ6IERlYnVnTWVzc2FnZU9wZXJhdGlvbkNvbmZpZyA9IHtcbiAgICAgICAgZ2V0UmVzdFVybDogKCkgPT4gdGhpcy5SRVNUX1JFUVVFU1RfVVJMXG4gICAgICB9O1xuICAgICAgdGhpcy5kZWJ1Z01lc3NhZ2VTZXJ2aWNlLmluaXQoZGVidWdNZXNzYWdlT3BDb250ZXh0KTtcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc29sZS5lcnJvcihcIkNhbm5vdCBpbml0aWFsaXplIERlYnVnTWVzc2FnZVNlcnZpY2U6IGFzc2lzdGFudENvbmZpZyBvciBSRVNUX1JFUVVFU1RfVVJMIG5vdCByZWFkeS5cIik7XG4gICAgfVxuICB9XG5cbiAgZ2V0IGFzc2lzdGFudHMoKTogYW55IHtcbiAgICByZXR1cm4gdGhpcy5hc3Npc3RhbnRDb25maWd1cmF0aW9uU2VydmljZS5nZXRBc3Npc3RhbnRzU2V0dGluZygpO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCB0aGUgaW5zdGFuY2UgSUQgb2YgdGhlIGNoYXQgc2VydmljZVxuICAgKiBAcmV0dXJucyBUaGUgaW5zdGFuY2UgSUQgb2YgdGhlIGNoYXQgc2VydmljZVxuICAgKi9cbiAgZ2V0IGNoYXRJbnN0YW5jZUlkKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMuX2NoYXRJbnN0YW5jZUlkO1xuICB9XG5cbiAgLyoqXG4gICAqIFBlcnNpc3QgdGhlIGluc3RhbmNlIElEIG9mIHRoZSBjaGF0IHNlcnZpY2VcbiAgICogQHBhcmFtIGluc3RhbmNlSWQgVGhlIGluc3RhbmNlIElEIG9mIHRoZSBjaGF0IHNlcnZpY2VcbiAgICovXG4gIHNldENoYXRJbnN0YW5jZUlkKGluc3RhbmNlSWQ6IHN0cmluZykge1xuICAgIHRoaXMuX2NoYXRJbnN0YW5jZUlkID0gaW5zdGFuY2VJZDtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgdGhlIElEIG9mIHRoZSBjdXJyZW50IGNoYXQgZGlzY3Vzc2lvbiB3aGljaCBpcyB1c2VkIHRvIHNhdmUvZ2V0L2RlbGV0ZSB0aGUgZGlzY3Vzc2lvbiBhbmQgaWRlbnRpZnkgYXVkaXQgZXZlbnRzXG4gICAqIEByZXR1cm5zIFRoZSBJRCBvZiB0aGUgY3VycmVudCBjaGF0IGRpc2N1c3Npb25cbiAgICovXG4gIGdldCBjaGF0SWQoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5fY2hhdElkO1xuICB9XG5cbiAgLyoqXG4gICAqIEdlbmVyYXRlIGFuIEdVSUQgZm9yIHRoZSBjdXJyZW50IGNoYXQgZGlzY3Vzc2lvbiB3aGljaCBpcyB1c2VkIHRvIHNhdmUvZ2V0L2RlbGV0ZSBpdCBhbmQgaWRlbnRpZnkgYXVkaXQgZXZlbnRzXG4gICAqIEBwYXJhbSBjaGF0SWQgaWYgcHJvdmlkZWQsIGl0IHdpbGwgYmUgY29uc2lkZXJlZCBhcyB0aGUgSUQgb2YgdGhlIGN1cnJlbnQgY2hhdCBkaXNjdXNzaW9uIHdoaWNoIGlzIHVzZWQgdG8gaWRlbnRpZnkgYXVkaXQgZXZlbnRzXG4gICAqL1xuICBnZW5lcmF0ZUNoYXRJZChjaGF0SWQ/OiBzdHJpbmcpIHtcbiAgICB0aGlzLl9jaGF0SWQgPSBjaGF0SWQgfHwgZ3VpZCgpO1xuICB9XG5cbiAgLyoqXG4gICAqIEluaXRpYWxpemUgdGhlIGNoYXQgY29uZmlnIGJ5IG1hbmFnaW5nIE9OTFkgc3ViLW9iamVjdCAqKmRlZmF1bHRWYWx1ZXMqKiBjb25maWdzIG9mIHRoZSBzdGFuZGFyZCBhcHAgY29uZmlnIChkZWZpbmVkIGluIHRoZSBjdXN0b21pemF0aW9uIGpzb24gdGFiICkgYW5kIHRoZSB1c2VyIHByZWZlcmVuY2VzLlxuICAgKiBUbyBkbyBzbywgYSB0cmFja2luZyBtZWNoYW5pc20gaXMgaW1wbGVtZW50ZWQgdG8gbm90aWZ5IHRoZSB1c2VyIGFib3V0IHRoZSBhdmFpbGFibGUgdXBkYXRlcyBpbiB0aGUgZGVmYXVsdFZhbHVlcyBvYmplY3Qgb2YgdGhlIHN0YW5kYXJkIGFwcCBjb25maWcuXG4gICAqIFRoZSByZXN0IG9mIHRoZSBjb25maWcgb2JqZWN0IGNvbWluZyBmcm9tIFwic3RhbmRhcmQgYXBwIGNvbmZpZ1wiIGlzIHVzZWQgYXMgaXQgaXMgd2l0aG91dCBhbnkgb3ZlcnJpZGUuXG4gICAqIFRodXMsIHRoZSB1c2VyIHByZWZlcmVuY2VzIGFyZSB1c2VkIG9ubHkgZm9yIHRoZSBkZWZhdWx0VmFsdWVzIG9iamVjdC5cbiAgICogVGhpcyBwcm92aWRlIGEgY2VudHJhbGl6ZWQgd2F5IHRvIG1hbmFnZSB0aGUgcmVzdCBvZiB0aGUgY29uZmlnIG9iamVjdCBieSBhZG1pbnMgYW5kIGVuc3VyZSBhIHVuaXF1ZSBjb21tb24gYmVoYXZpb3IgZm9yIGFsbCB1c2Vycy5cbiAgICovXG4gIGFzeW5jIGluaXRDaGF0Q29uZmlnKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRoaXMuYXNzaXN0YW50Q29uZmlndXJhdGlvblNlcnZpY2UuaW5pdENoYXRDb25maWcoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBVcGRhdGUgdGhlIGNoYXQgY29uZmlnIGFuZCBzdG9yZSBpdHMgZGVmYXVsdFZhbHVlcyBpbiB0aGUgdXNlciBwcmVmZXJlbmNlc1xuICAgKiBAcGFyYW0gY29uZmlnICBUaGUgdXBkYXRlZCBjaGF0IGNvbmZpZ1xuICAgKiBAcGFyYW0gaGFzaGVzICBUaGUgdXBkYXRlZCBoYXNoZXMgdG8gc3RvcmUgaW4gdGhlIHVzZXIgcHJlZmVyZW5jZXNcbiAgICogQHBhcmFtIG5vdGlmeSAgV2hldGhlciB0byBub3RpZnkgdGhlIHVzZXIgYWJvdXQgdGhlIHVwZGF0ZVxuICAgKiBAcGFyYW0gc3VjY2Vzc0NhbGxiYWNrICBUaGUgY2FsbGJhY2sgdG8gZXhlY3V0ZSBpZiB0aGUgdXBkYXRlIGlzIHN1Y2Nlc3NmdWxcbiAgICogQHBhcmFtIGVycm9yQ2FsbGJhY2sgIFRoZSBjYWxsYmFjayB0byBleGVjdXRlIGlmIHRoZSB1cGRhdGUgZmFpbHNcbiAgICovXG4gIHVwZGF0ZUNoYXRDb25maWcoXG4gICAgY29uZmlnOiBDaGF0Q29uZmlnLFxuICAgIGhhc2hlcz86IHsgXCJhcHBsaWVkLWRlZmF1bHRWYWx1ZXMtaGFzaFwiPzogc3RyaW5nOyBcInNraXBwZWQtZGVmYXVsdFZhbHVlcy1oYXNoXCI/OiBzdHJpbmcgfSxcbiAgICBub3RpZnkgPSB0cnVlLFxuICAgIHN1Y2Nlc3NDYWxsYmFjaz86ICgpID0+IGFueSxcbiAgICBlcnJvckNhbGxiYWNrPzogKCkgPT4gYW55XG4gICk6IHZvaWQge1xuICAgIHRoaXMuYXNzaXN0YW50Q29uZmlndXJhdGlvblNlcnZpY2UudXBkYXRlQ2hhdENvbmZpZyhjb25maWcsIGhhc2hlcywgbm90aWZ5LCBzdWNjZXNzQ2FsbGJhY2ssIGVycm9yQ2FsbGJhY2spO1xuICB9XG5cbiAgLyoqXG4gICAqIE92ZXJyaWRlcyB0aGUgbG9nZ2VkIGluIHVzZXJcbiAgICovXG4gIG92ZXJyaWRlVXNlcigpOiB2b2lkIHtcbiAgICBjb25zdCB7IHVzZXJPdmVycmlkZUFjdGl2ZSwgdXNlck92ZXJyaWRlIH0gPSBnbG9iYWxDb25maWc7XG4gICAgaWYgKCEodXNlck92ZXJyaWRlQWN0aXZlICYmIHVzZXJPdmVycmlkZSkpIHtcbiAgICAgIHRoaXMudXNlck92ZXJyaWRlJC5uZXh0KGZhbHNlKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBQcmVwYXJlIHRoZSBwYXlsb2FkIHRvIHNlbmQgdG8gdGhlIE92ZXJyaWRlVXNlciBtZXRob2RcbiAgICBjb25zdCBkYXRhID0ge1xuICAgICAgaW5zdGFuY2VJZDogdGhpcy5jaGF0SW5zdGFuY2VJZCxcbiAgICAgIHVzZXI6IHVzZXJPdmVycmlkZS51c2VybmFtZSxcbiAgICAgIGRvbWFpbjogdXNlck92ZXJyaWRlLmRvbWFpblxuICAgIH1cblxuICAgIC8vIEludm9rZSB0aGUgT3ZlcnJpZGVVc2VyIG1ldGhvZCBhbmQgaGFuZGxlIGVycm9yc1xuICAgIHRoaXMuY29ubmVjdGlvbiEuaW52b2tlKCdPdmVycmlkZVVzZXInLCBkYXRhKVxuICAgICAgLnRoZW4oKHJlcykgPT4gdGhpcy51c2VyT3ZlcnJpZGUkLm5leHQoISFyZXMpKVxuICAgICAgLmNhdGNoKGVycm9yID0+IHtcbiAgICAgICAgY29uc29sZS5lcnJvcignRXJyb3IgaW52b2tpbmcgT3ZlcnJpZGVVc2VyOicsIGVycm9yKTtcbiAgICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpOyAvLyBSZXR1cm4gYSByZXNvbHZlZCBwcm9taXNlIHRvIGhhbmRsZSB0aGUgZXJyb3IgYW5kIHByZXZlbnQgdW5oYW5kbGVkIHByb21pc2UgcmVqZWN0aW9uIHdoZW4gbm8gZnVydGhlciBlcnJvciBoYW5kbGluZyBleGlzdHMgZG93bnN0cmVhbVxuICAgICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogQ2FsbHMgdGhlIEZldGNoIEFQSSB0byByZXRyaWV2ZSBhIG5ldyBtZXNzYWdlIGdpdmVuIGFsbCBwcmV2aW91cyBtZXNzYWdlc1xuICAgKi9cbiAgZmV0Y2gobWVzc2FnZXM6IENoYXRNZXNzYWdlW10sIHF1ZXJ5OiBRdWVyeSk6IE9ic2VydmFibGU8Q2hhdFJlc3BvbnNlPiB7XG4gICAgcmV0dXJuIHRoaXMuYXNzaXN0YW50V3NGcmFtZXNTZXJ2aWNlLmZldGNoKG1lc3NhZ2VzLCBxdWVyeSk7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJuIHRoZSBsaXN0IG9mIG1vZGVscyBhdmFpbGFibGUgb24gdGhlIHNlcnZlclxuICAgKi9cbiAgbGlzdE1vZGVscygpOiBPYnNlcnZhYmxlPEdsbG1Nb2RlbERlc2NyaXB0aW9uW10gfCB1bmRlZmluZWQ+IHtcbiAgICByZXR1cm4gdGhpcy5hc3Npc3RhbnRNZXRhZGF0YVNlcnZpY2UubGlzdE1vZGVscygpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybiB0aGUgbGlzdCBvZiBmdW5jdGlvbnMgYXZhaWxhYmxlIG9uIHRoZSBzZXJ2ZXIgQU5EIG1hdGNoaW5nIGVuYWJsZWQgZnVuY3Rpb25zIGluIHRoZSBjaGF0IGNvbmZpZ1xuICAgKi9cbiAgbGlzdEZ1bmN0aW9ucygpOiBPYnNlcnZhYmxlPEdsbG1GdW5jdGlvbltdIHwgdW5kZWZpbmVkPiB7XG4gICAgcmV0dXJuIHRoaXMuYXNzaXN0YW50TWV0YWRhdGFTZXJ2aWNlLmxpc3RGdW5jdGlvbnMoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTdG9wcyB0aGUgYXNzaXN0YW50IGFuc3dlciBnZW5lcmF0aW9uIGFuZCBjYW5jZWxzIGFsbCB0aGUgb25nb2luZyBhbmQgcGVuZGluZyByZWxhdGVkIHRhc2tzXG4gICAqL1xuICBzdG9wR2VuZXJhdGlvbigpOiBPYnNlcnZhYmxlPGJvb2xlYW4+IHtcbiAgICByZXR1cm4gdGhpcy5hc3Npc3RhbnRXc0ZyYW1lc1NlcnZpY2Uuc3RvcEdlbmVyYXRpb24oKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBIGhhbmRsZXIgZm9yIHF1b3RhIHVwZGF0ZXMgZWFjaCB0aW1lIHRoZSBjaGF0IGlzIGludm9rZWQuXG4gICAqIEl0IGVtaXRzIHRoZSB1cGRhdGVkIHF1b3RhIHRvIHRoZSBxdW90YSQgc3ViamVjdCwgZW1pdHMgYWNjb3JkaW5nbHkgdGhlIHVwZGF0ZWQgdXNlcidzIHRva2VucyBjb25zdW1wdGlvbiBhbmQgbm90aWZpZXMgdGhlIHVzZXIgaWYgdGhlIG1heCBxdW90YSBpcyByZWFjaGVkLlxuICAgKiBAcGFyYW0gcXVvdGEgVGhlIHVwZGF0ZWQgcXVvdGFcbiAgICogQHBhcmFtIHByb3BhZ2F0ZUVycm9yIFdoZXRoZXIgdG8gcHJvcGFnYXRlIHRoZSBlcnJvciB0byB0aGUgY2FsbGVyXG4gICAqL1xuICB1cGRhdGVRdW90YShxdW90YTogUXVvdGEsIHByb3BhZ2F0ZUVycm9yID0gZmFsc2UpOiB2b2lkIHtcbiAgICB0aGlzLmFzc2lzdGFudFRva2Vuc1RyYWNraW5nU2VydmljZS51cGRhdGVRdW90YShxdW90YSwgcHJvcGFnYXRlRXJyb3IpO1xuICB9XG5cbiAgLyoqXG4gICAqIEEgaGFuZGxlciBmb3IgY2hhdCB1c2FnZSBtZXRyaWNzIGVhY2ggdGltZSB0aGUgZ2VuZXJhdGlvbiBvZiB0aGUgYXNzaXN0YW50IHJlc3BvbnNlIGlzIGNvbXBsZXRlZC5cbiAgICogSXQgZW1pdHMgdGhlIGNoYXQgdXNhZ2UgbWV0cmljcyB0byB0aGUgY2hhdFVzYWdlTWV0cmljcyQgc3ViamVjdCwgZW1pdHMgYWNjb3JkaW5nbHkgdGhlIHVwZGF0ZWQgY2hhdCdzIHRva2VucyBjb25zdW1wdGlvblxuICAgKiBAcGFyYW0gY2hhdFVzYWdlTWV0cmljcyBUaGUgY2hhdCB1c2FnZSBtZXRyaWNzXG4gICAqL1xuICB1cGRhdGVDaGF0VXNhZ2VNZXRyaWNzKGNoYXRVc2FnZU1ldHJpY3M6IENoYXRVc2FnZU1ldHJpY3MpOiB2b2lkIHtcbiAgICB0aGlzLmFzc2lzdGFudFRva2Vuc1RyYWNraW5nU2VydmljZS51cGRhdGVDaGF0VXNhZ2VNZXRyaWNzKGNoYXRVc2FnZU1ldHJpY3MpO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCB0aGUgbW9kZWwgZGVzY3JpcHRpb24gZm9yIHRoZSBnaXZlbiAoc2VydmljZUlkICsgbW9kZWxJZClcbiAgICogSWYgYSBtb2RlbCBpcyBub3QgZm91bmQsIGFuIGVycm9yIG1lc3NhZ2UgaXMgcmV0dXJuZWRcbiAgICogQHBhcmFtIHNlcnZpY2VJZCBUaGUgc2VydmljZUlkIG9mIHRoZSBtb2RlbFxuICAgKiBAcGFyYW0gbW9kZWxJZCBUaGUgbW9kZWxJZCBvZiB0aGUgbW9kZWxcbiAgICogQHJldHVybnMgVGhlIG1vZGVsIGRlc2NyaXB0aW9uXG4gICAqL1xuICBnZXRNb2RlbChzZXJ2aWNlSWQ6IHN0cmluZywgbW9kZWxJZDogc3RyaW5nKTogR2xsbU1vZGVsRGVzY3JpcHRpb24gfCB1bmRlZmluZWR7XG4gICAgY29uc3QgbW9kZWwgPSB0aGlzLm1vZGVscz8uZmluZChtID0+IG0uc2VydmljZUlkID09PSBzZXJ2aWNlSWQgJiYgbS5tb2RlbElkID09PSBtb2RlbElkKTtcbiAgICAvLyBIYW5kbGUgb2Jzb2xldGUgY29uZmlnXG4gICAgaWYoIW1vZGVsKSB7XG4gICAgICB0aGlzLm5vdGlmaWNhdGlvbnNTZXJ2aWNlLmVycm9yKGBGQVRBTCBFUlJPUiA6IFRoZSBtb2RlbCAoc2VydmljZUlkID0gJyR7c2VydmljZUlkfScsIG1vZGVsSWQgPSAnJHttb2RlbElkfScpIGlzIG5vIGxvbmdlciBhdmFpbGFibGUuIFBsZWFzZSBjb250YWN0IGFuIGFkbWluIGZvciBmdXJ0aGVyIGluZm9ybWF0aW9uLmApO1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBGQVRBTCBFUlJPUiA6IFRoZSBtb2RlbCAoc2VydmljZUlkID0gJyR7c2VydmljZUlkfScsIG1vZGVsSWQgPSAnJHttb2RlbElkfScpIGlzIG5vIGxvbmdlciBhdmFpbGFibGVgKTtcbiAgICB9XG4gICAgcmV0dXJuIG1vZGVsO1xuICB9XG5cbiAgLyoqXG4gICAqIEZldGNoIHRoZSBsaXN0IHNhdmVkIGNoYXRzIGJlbG9uZ2luZyB0byBhIHNwZWNpZmljIGluc3RhbmNlIG9mIHRoZSBhc3Npc3RhbnRcbiAgICovXG4gIGxpc3RTYXZlZENoYXQoKTogdm9pZCB7XG4gICAgdGhpcy5zYXZlZENoYXRzU2VydmljZS5saXN0Q2hhdHMoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm4gdGhlIHNhdmVkIGNoYXQgd2l0aCB0aGUgZ2l2ZW4gaWQsIGlmIGV4aXN0cy4gT3RoZXJ3aXNlLCByZXR1cm4gdW5kZWZpbmVkXG4gICAqIEBwYXJhbSBpZCBUaGUgaWQgb2YgdGhlIHNhdmVkIGNoYXRcbiAgICovXG4gIGdldFNhdmVkQ2hhdChpZDogc3RyaW5nKTogT2JzZXJ2YWJsZTxTYXZlZENoYXRIaXN0b3J5IHwgdW5kZWZpbmVkPiB7XG4gICAgcmV0dXJuIHRoaXMuc2F2ZWRDaGF0c1NlcnZpY2UuZ2V0Q2hhdEJ5SWQoaWQpO1xuICB9XG5cbiAgLyoqXG4gICAqIENoZWNrIGlmIGEgc2F2ZWQgY2hhdCB3aXRoIHRoZSBnaXZlbiBpZCBhbHJlYWR5IGV4aXN0c1xuICAgKiBAcGFyYW0gaWQgVGhlIGlkIG9mIHRoZSBzYXZlZCBjaGF0XG4gICAqIEByZXR1cm5zIFRydWUgaWYgdGhlIHNhdmVkIGNoYXQgZXhpc3RzLCBmYWxzZSBvdGhlcndpc2VcbiAgICovXG4gIGlzRXhpc3RpbmdTYXZlZENoYXQoaWQ6IHN0cmluZyk6IE9ic2VydmFibGU8Ym9vbGVhbj4ge1xuICAgIHJldHVybiB0aGlzLnNhdmVkQ2hhdHNTZXJ2aWNlLmlzRXhpc3RpbmdDaGF0KGlkKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTYXZlIGEgY2hhdCB3aXRoIHRoZSBnaXZlbiBtZXNzYWdlc1xuICAgKiBAcGFyYW0gbWVzc2FnZXMgVGhlIG1lc3NhZ2VzIHRvIGFkZCB0byB0aGUgc2F2ZWQgY2hhdCBpbmRleFxuICAgKiBAcmV0dXJucyBUaGUgc2F2ZWQgY2hhdFxuICAgKi9cbiAgYWRkU2F2ZWRDaGF0KGlkOiBzdHJpbmcsIG1lc3NhZ2VzOiBDaGF0TWVzc2FnZVtdKTogT2JzZXJ2YWJsZTxTYXZlZENoYXRSZXNwb25zZT4ge1xuICAgIHJldHVybiB0aGlzLnNhdmVkQ2hhdHNTZXJ2aWNlLmFkZENoYXQoaWQsIG1lc3NhZ2VzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBVcGRhdGUgYSBzYXZlZCBjaGF0IHdpdGggdGhlIGdpdmVuIGlkLlxuICAgKiBAcGFyYW0gaWQgVGhlIGlkIG9mIHRoZSBzYXZlZCBjaGF0XG4gICAqIEBwYXJhbSBuYW1lIFRoZSBuZXcgbmFtZSBvZiB0aGUgc2F2ZWQgY2hhdCwgaWYgcHJvdmlkZWRcbiAgICogQHBhcmFtIG1lc3NhZ2VzIFRoZSBtZXNzYWdlcyB0byB1cGRhdGUgdGhlIHNhdmVkIGNoYXQgaGlzdG9yeSwgaWYgcHJvdmlkZWRcbiAgICogQHJldHVybnMgVHJ1ZSBpZiB0aGUgc2F2ZWQgY2hhdCBoYXMgYmVlbiBzdWNjZXNzZnVsbHkgdXBkYXRlZFxuICAgKi9cbiAgdXBkYXRlU2F2ZWRDaGF0KGlkOiBzdHJpbmcsIG5hbWU/OiBzdHJpbmcsIG1lc3NhZ2VzPzogQ2hhdE1lc3NhZ2VbXSk6IE9ic2VydmFibGU8U2F2ZWRDaGF0UmVzcG9uc2U+IHtcbiAgICByZXR1cm4gdGhpcy5zYXZlZENoYXRzU2VydmljZS51cGRhdGVDaGF0KGlkLCBuYW1lLCBtZXNzYWdlcyk7XG4gIH1cblxuICAvKipcbiAgICogQnVsayBkZWxldGUgb2Ygc2F2ZWQgY2hhdHMgbWF0Y2hpbmcgdGhlIGdpdmVuIGlkc1xuICAgKiBAcGFyYW0gaWRzIExpc3Qgb2YgaWRzIG9mIHRoZSBzYXZlZCBjaGF0cyB0byBkZWxldGVcbiAgICogQHJldHVybnMgVGhlIG51bWJlciBvZiBkZWxldGVkIGNoYXRzXG4gICAqL1xuICBkZWxldGVTYXZlZENoYXQoaWRzOiBzdHJpbmdbXSk6IE9ic2VydmFibGU8RGVsZXRlU2F2ZWRDaGF0UmVzcG9uc2U+IHtcbiAgICByZXR1cm4gdGhpcy5zYXZlZENoYXRzU2VydmljZS5kZWxldGVDaGF0KGlkcyk7XG4gIH1cblxuICBwdWJsaWMgZ2V0RGVidWdNZXNzYWdlKG1lc3NhZ2U6IERlYnVnTWVzc2FnZSk6IE9ic2VydmFibGU8S3ZPYmplY3QgfCBMaXN0T2JqZWN0IHwgdW5kZWZpbmVkPiB7XG4gICAgcmV0dXJuIHRoaXMuZGVidWdNZXNzYWdlU2VydmljZS5nZXREZWJ1Z01lc3NhZ2UobWVzc2FnZSk7XG4gIH1cblxuICAvKipcbiAgICogSW5pdGlhbGl6ZSBvdXQtb2YtdGhlLWJveCBoYW5kbGVyc1xuICAgKiBJdCBpcyBhIHBsYWNlaG9sZGVyIGZvciBub24tc3RyZWFtaW5nIHNjZW5hcmlvcywgd2hlcmUgeW91IGludm9rZSBhIHNwZWNpZmljIGh1YiBtZXRob2QsIGFuZCB0aGUgc2VydmVyIHJlc3BvbmRzIHdpdGggZnJhbWUgbWVzc2FnZShzKVxuICAgKi9cbiAgaW5pdE1lc3NhZ2VIYW5kbGVycygpOiB2b2lkIHtcbiAgICB0aGlzLmFzc2lzdGFudFdzRnJhbWVzU2VydmljZS5pbml0TWVzc2FnZUhhbmRsZXJzKCk7XG4gIH1cblxuICAvKipcbiAgICogT3ZlcnJpZGUgYW5kIHJlZ2lzdGVyIHRoZSBlbnRpcmUgX21lc3NhZ2VIYW5kbGVycyBtYXAgYnkgbWVyZ2luZyB0aGUgcHJvdmlkZWQgbWFwIHdpdGggdGhlIGRlZmF1bHQgb25lXG4gICAqIEBwYXJhbSBfbWVzc2FnZUhhbmRsZXJzXG4gICAqL1xuICBvdmVycmlkZU1lc3NhZ2VIYW5kbGVyczxUPihfbWVzc2FnZUhhbmRsZXJzOiBNYXA8c3RyaW5nLCBNZXNzYWdlSGFuZGxlcjxUPj4pOiB2b2lkIHtcbiAgICB0aGlzLmFzc2lzdGFudFdzRnJhbWVzU2VydmljZS5vdmVycmlkZU1lc3NhZ2VIYW5kbGVycyhfbWVzc2FnZUhhbmRsZXJzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGQgYSBsaXN0ZW5lciBmb3IgYSBzcGVjaWZpYyBldmVudC5cbiAgICogSWYgYSBsaXN0ZW5lciBmb3IgdGhpcyBzYW1lIGV2ZW50IGFscmVhZHkgZXhpc3RzLCBpdCB3aWxsIGJlIG92ZXJyaWRkZW4uXG4gICAqIElmIHRoZSBsaXN0ZW5lciBoYXMgXCJpc0dsb2JhbEhhbmRsZXJcIiBzZXQgdG8gdHJ1ZSwgaXQgd2lsbCBiZSByZWdpc3RlcmVkIHRvIHRoZSBodWIgY29ubmVjdGlvbi5cbiAgICogQHBhcmFtIGV2ZW50TmFtZSBOYW1lIG9mIHRoZSBldmVudCB0byByZWdpc3RlciBhIGxpc3RlbmVyIGZvclxuICAgKiBAcGFyYW0gZXZlbnRIYW5kbGVyIFRoZSBoYW5kbGVyIHRvIGJlIGNhbGxlZCB3aGVuIHRoZSBldmVudCBpcyByZWNlaXZlZFxuICAgKi9cbiAgYWRkTWVzc2FnZUhhbmRsZXI8VD4oZXZlbnROYW1lOiBzdHJpbmcsIGV2ZW50SGFuZGxlcjogTWVzc2FnZUhhbmRsZXI8VD4pOiB2b2lkIHtcbiAgICB0aGlzLmFzc2lzdGFudFdzRnJhbWVzU2VydmljZS5hZGRNZXNzYWdlSGFuZGxlcihldmVudE5hbWUsIGV2ZW50SGFuZGxlcik7XG4gIH1cblxuICAvKipcbiAgICogUmVtb3ZlIGEgbGlzdGVuZXIgZm9yIGEgc3BlY2lmaWMgZXZlbnQgZnJvbSB0aGUgX21lc3NhZ2VIYW5kbGVycyBtYXAgYW5kIHVuc3Vic2NyaWJlIGZyb20gcmVjZWl2aW5nIG1lc3NhZ2VzIGZvciB0aGlzIGV2ZW50IGZyb20gdGhlIFNpZ25hbFIgaHViLlxuICAgKiBAcGFyYW0gZXZlbnROYW1lIE5hbWUgb2YgdGhlIGV2ZW50IHRvIHJlbW92ZSB0aGUgbGlzdGVuZXIgZm9yXG4gICAqL1xuICByZW1vdmVNZXNzYWdlSGFuZGxlcihldmVudE5hbWU6IHN0cmluZyk6IHZvaWQge1xuICAgIHRoaXMuYXNzaXN0YW50V3NGcmFtZXNTZXJ2aWNlLnJlbW92ZU1lc3NhZ2VIYW5kbGVyKGV2ZW50TmFtZSk7XG4gIH1cblxuICAvKipcbiAgICogQnVpbGQgYSBjb25uZWN0aW9uIHRvIHRoZSBzaWduYWxSIHdlYnNvY2tldCBhbmQgcmVnaXN0ZXIgZGVmYXVsdCBsaXN0ZW5lcnMgdG8gdGhlIG1ldGhvZHMgZGVmaW5lZCBpbiB0aGUgc2VydmVyIGh1YiBjbGFzc1xuICAgKiBAcGFyYW0gb3B0aW9ucyBUaGUgb3B0aW9ucyBmb3IgdGhlIGNvbm5lY3Rpb24uIEl0IG92ZXJyaWRlcyB0aGUgZGVmYXVsdCBvcHRpb25zXG4gICAqIEBwYXJhbSBsb2dMZXZlbCBEZWZpbmUgdGhlIGxvZyBsZXZlbCBkaXNwbGF5ZWQgaW4gdGhlIGNvbnNvbGVcbiAgICogQHJldHVybnMgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHdoZW4gdGhlIGNvbm5lY3Rpb24gaXMgYnVpbHRcbiAgICovXG4gIGJ1aWxkQ29ubmVjdGlvbihvcHRpb25zPzogQ29ubmVjdGlvbk9wdGlvbnMpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICByZXR1cm4gdGhpcy5zaWduYWxSQ29ubmVjdGlvblNlcnZpY2UuYnVpbGRDb25uZWN0aW9uKG9wdGlvbnMpO1xuICB9XG5cbiAgLyoqXG4gICAqIFN0YXJ0IHRoZSBjb25uZWN0aW9uXG4gICAqIEByZXR1cm5zIFByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIHRoZSBjb25uZWN0aW9uIGlzIHN0YXJ0ZWRcbiAgICovXG4gIHN0YXJ0Q29ubmVjdGlvbigpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICByZXR1cm4gdGhpcy5zaWduYWxSQ29ubmVjdGlvblNlcnZpY2Uuc3RhcnRDb25uZWN0aW9uKCk7XG4gIH1cblxuICAvKipcbiAgICogU3RvcCB0aGUgY29ubmVjdGlvblxuICAgKiBAcmV0dXJucyBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2hlbiB0aGUgY29ubmVjdGlvbiBpcyBzdG9wcGVkXG4gICAqL1xuICBzdG9wQ29ubmVjdGlvbigpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICByZXR1cm4gdGhpcy5zaWduYWxSQ29ubmVjdGlvblNlcnZpY2Uuc3RvcENvbm5lY3Rpb24oKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZW5lcmF0ZSBhbiBhdWRpdCBldmVudCB3aXRoIHRoZSBnaXZlbiB0eXBlIGFuZCBkZXRhaWxzLiBUaGUgZ2VuZXJhdGVkIGF1ZGl0IGV2ZW50IGlzIHNlbnQgYWZ0ZXJ3YXJkcyB2aWEgdGhlIEF1ZGl0V2ViU2VydmljZVxuICAgKiBAcGFyYW0gdHlwZSBBdWRpdCBldmVudCB0eXBlXG4gICAqIEBwYXJhbSBkZXRhaWxzIEF1ZGl0IGV2ZW50IGRldGFpbHNcbiAgICogQHBhcmFtIGlkIEFjdGlvbnMgKHNhdmVkQ2hhdCBkZWxldGUvcmVuYW1lLy4uLikgbWF5IG9jY3VyIG9uIGEgc3BlY2lmaWMgY2hhdCBkaWZmZXJlbnQgdGhhbiB0aGUgY3VycmVudCBvbmUgc3RvcmVkIGluIHRoaXMgc2VydmljZSwgc28gdGhlIGNoYXQgaWQgY2FuIGJlIHByb3ZpZGVkXG4gICAqL1xuICBhc3luYyBnZW5lcmF0ZUF1ZGl0RXZlbnQodHlwZTogc3RyaW5nLCBkZXRhaWxzOiBSZWNvcmQ8c3RyaW5nLCBhbnk+LCBpZD86IHN0cmluZykge1xuICAgIGNvbnN0IGJhc2VEZXRhaWxzID0ge1xuICAgICAgXCJ1cmxcIjogZGVjb2RlVVJJQ29tcG9uZW50KHdpbmRvdy5sb2NhdGlvbi5ocmVmKSxcbiAgICAgIFwiYXBwXCI6IHRoaXMuYXBwU2VydmljZS5hcHBOYW1lLFxuICAgICAgXCJ1c2VyLWlkXCI6IHRoaXMucHJpbmNpcGFsU2VydmljZS5wcmluY2lwYWw/LnVzZXJJZCxcbiAgICAgIFwiaW5zdGFuY2UtaWRcIjogdGhpcy5jaGF0SW5zdGFuY2VJZCxcbiAgICAgIFwiY2hhdC1pZFwiOiBpZCB8fCB0aGlzLmNoYXRJZCxcbiAgICAgIFwic2VydmljZS1pZFwiOiB0aGlzLmFzc2lzdGFudENvbmZpZyQudmFsdWUhLmRlZmF1bHRWYWx1ZXMuc2VydmljZV9pZCxcbiAgICAgIFwibW9kZWwtaWRcIjogdGhpcy5hc3Npc3RhbnRDb25maWckLnZhbHVlIS5kZWZhdWx0VmFsdWVzLm1vZGVsX2lkXG4gICAgfTtcblxuICAgIGlmICh0eXBlID09PSBcImFzdC1tZXNzYWdlLm1lc3NhZ2VcIikge1xuICAgICAgYmFzZURldGFpbHNbXCJpcy11c2VyLWlucHV0XCJdID0gZmFsc2U7XG4gICAgfVxuXG4gICAgY29uc3QgYXVkaXQgPSB7XG4gICAgICB0eXBlLFxuICAgICAgZGV0YWlsOiB7XG4gICAgICAgIC4uLmJhc2VEZXRhaWxzLFxuICAgICAgICAuLi5kZXRhaWxzXG4gICAgICB9XG4gICAgfVxuICAgIGF3YWl0IEF1ZGl0Lm5vdGlmeShhdWRpdCk7XG4gIH1cblxufVxuIl19