@sinequa/assistant 3.9.1 → 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 (48) hide show
  1. package/chat/chat.component.d.ts +35 -38
  2. package/chat/chat.service.d.ts +192 -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 +2 -1
  9. package/chat/saved-chats/i18n/fr.json +2 -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/services/signalR.web.service.d.ts +1 -0
  18. package/chat/types.d.ts +24 -3
  19. package/chat/utils/utils.service.d.ts +67 -0
  20. package/esm2022/chat/chat-message/chat-message.component.mjs +3 -3
  21. package/esm2022/chat/chat.component.mjs +199 -225
  22. package/esm2022/chat/chat.service.mjs +452 -267
  23. package/esm2022/chat/debug-message/debug-message-details/debug-message-details.component.mjs +43 -0
  24. package/esm2022/chat/debug-message/debug-message.component.mjs +27 -30
  25. package/esm2022/chat/debug-message/debug-message.service.mjs +52 -0
  26. package/esm2022/chat/dialogs/rename-saved-chat.component.mjs +6 -5
  27. package/esm2022/chat/documents-upload/document-list/document-list.component.mjs +4 -2
  28. package/esm2022/chat/documents-upload/document-upload/document-upload.component.mjs +3 -3
  29. package/esm2022/chat/pipes/message-content.pipe.mjs +5 -2
  30. package/esm2022/chat/public-api.mjs +1 -3
  31. package/esm2022/chat/saved-chats/saved-chats.component.mjs +11 -10
  32. package/esm2022/chat/saved-chats/saved-chats.service.mjs +165 -0
  33. package/esm2022/chat/services/assistant-configuration.service.mjs +171 -0
  34. package/esm2022/chat/services/assistant-metadata.service.mjs +67 -0
  35. package/esm2022/chat/services/assistant-tokens-tracking.service.mjs +57 -0
  36. package/esm2022/chat/services/assistant-ws-frames.service.mjs +392 -0
  37. package/esm2022/chat/services/signalR-connection.service.mjs +109 -0
  38. package/esm2022/chat/services/signalR.web.service.mjs +1 -1
  39. package/esm2022/chat/types.mjs +2 -1
  40. package/esm2022/chat/unified-plugins/embedded-image-reference.plugin.mjs +2 -3
  41. package/esm2022/chat/utils/utils.service.mjs +170 -0
  42. package/fesm2022/sinequa-assistant-chat.mjs +2037 -1647
  43. package/fesm2022/sinequa-assistant-chat.mjs.map +1 -1
  44. package/package.json +1 -1
  45. package/chat/rest-chat.service.d.ts +0 -31
  46. package/chat/websocket-chat.service.d.ts +0 -102
  47. package/esm2022/chat/rest-chat.service.mjs +0 -296
  48. package/esm2022/chat/websocket-chat.service.mjs +0 -654
@@ -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. */
@@ -31,6 +33,8 @@ export class ChatService {
31
33
  this.streaming$ = new BehaviorSubject(false);
32
34
  /** List of saved chats. */
33
35
  this.savedChats$ = new BehaviorSubject([]);
36
+ /** Whether there is an error with saved chats. */
37
+ this.savedChatsError$ = new BehaviorSubject(false);
34
38
  /** Emit the saved chat to load. */
35
39
  this.loadSavedChat$ = new BehaviorSubject(undefined);
36
40
  /** Emit the quota each time the chat is invoked. */
@@ -46,16 +50,287 @@ export class ChatService {
46
50
  this.userSettingsService = inject(UserSettingsWebService);
47
51
  this.notificationsService = inject(NotificationsService);
48
52
  this.appService = inject(AppService);
49
- this.modalService = inject(DialogService);
50
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);
51
63
  this.transloco = inject(TranslocoService);
52
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
+ }
53
332
  get assistants() {
54
- if (!this.userSettingsService.userSettings)
55
- this.userSettingsService.userSettings = {};
56
- if (!this.userSettingsService.userSettings["assistants"])
57
- this.userSettingsService.userSettings["assistants"] = {};
58
- return this.userSettingsService.userSettings["assistants"];
333
+ return this.assistantConfigurationService.getAssistantsSetting();
59
334
  }
60
335
  /**
61
336
  * Get the instance ID of the chat service
@@ -72,29 +347,14 @@ export class ChatService {
72
347
  this._chatInstanceId = instanceId;
73
348
  }
74
349
  /**
75
- * Get the ID of the current chat discussion which is used to save/get/delete it
76
- * @returns The ID of the current chat discussion
77
- */
78
- get savedChatId() {
79
- return this._savedChatId;
80
- }
81
- /**
82
- * Persist the ID of the current chat discussion which is used to save/get/delete it
83
- * @param savedChatId The ID of the current chat discussion which is used to save/get/delete it
84
- */
85
- setSavedChatId(savedChatId) {
86
- this._savedChatId = savedChatId;
87
- }
88
- /**
89
- * 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
90
351
  * @returns The ID of the current chat discussion
91
352
  */
92
353
  get chatId() {
93
354
  return this._chatId;
94
355
  }
95
356
  /**
96
- * Generate an GUID for the current chat discussion which is used to identify audit events
97
- * 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
98
358
  * @param chatId if provided, it will be considered as the ID of the current chat discussion which is used to identify audit events
99
359
  */
100
360
  generateChatId(chatId) {
@@ -108,66 +368,7 @@ export class ChatService {
108
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.
109
369
  */
110
370
  async initChatConfig() {
111
- // fetch the standard app config to get the defaultValues of the chat config for the given instance
112
- // Persist the app in the app service
113
- const capp = await fetchApp();
114
- this.appService.app = capp;
115
- const settings = await fetchUserSettings();
116
- this.userSettingsService.userSettings = settings;
117
- const key = this.chatInstanceId;
118
- const userSettingsConfig = this.assistants[key] || {};
119
- const principal = await fetchPrincipal();
120
- this.principalService.principal = principal;
121
- const standardChatConfig = getAssistantJsonFromCCApp(this.appService.app, key);
122
- try {
123
- // Validate the whole config object against the schema
124
- chatConfigSchema.parse(standardChatConfig);
125
- // 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
126
- if (!userSettingsConfig.defaultValues) {
127
- this.assistantConfig$.next({ ...standardChatConfig });
128
- this.initConfig$.next(true);
129
- }
130
- 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
131
- // Retrieve already stored hashes in the user settings if exists
132
- const appliedDefaultValuesHash = userSettingsConfig.hashes?.["applied-defaultValues-hash"];
133
- const skippedDefaultValuesHash = userSettingsConfig.hashes?.["skipped-defaultValues-hash"];
134
- // Create a hash of the current defaultValues of the standardChatConfig
135
- const currentDefaultValuesHash = await sha512(JSON.stringify(standardChatConfig.defaultValues));
136
- // Implement the tracking mechanism to notify the user about the available updates in the defaultValues object of the standard app config
137
- const condition = (currentDefaultValuesHash !== appliedDefaultValuesHash) && (currentDefaultValuesHash !== skippedDefaultValuesHash);
138
- if (condition) {
139
- this.modalService.open(DialogUpdatesComponent)
140
- .then(res => {
141
- if (res === "dialog-confirm") {
142
- const hashes = { ...userSettingsConfig.hashes, "applied-defaultValues-hash": currentDefaultValuesHash, "skipped-defaultValues-hash": undefined };
143
- // Update the chat config and store its defaultValues in the user preferences
144
- this.updateChatConfig({ ...standardChatConfig }, hashes, true);
145
- this.initConfig$.next(true);
146
- this.generateAuditEvent("ast-configuration.click", { 'configuration': JSON.stringify({ ...standardChatConfig }) });
147
- }
148
- else if (res === "dialog-no") {
149
- // Do not notify the user about changes while this skipped version is not updated
150
- const hashes = { ...userSettingsConfig.hashes, "skipped-defaultValues-hash": currentDefaultValuesHash };
151
- this.updateChatConfig({ ...standardChatConfig, defaultValues: userSettingsConfig.defaultValues }, hashes, false);
152
- this.initConfig$.next(true);
153
- }
154
- else {
155
- // Just pick the version in the user settings, nothing to be updated
156
- this.assistantConfig$.next({ ...standardChatConfig, defaultValues: userSettingsConfig.defaultValues });
157
- this.initConfig$.next(true);
158
- }
159
- });
160
- }
161
- else { // No available updates Or updates has been already skipped, then just pick the version in the user settings
162
- this.assistantConfig$.next({ ...standardChatConfig, defaultValues: userSettingsConfig.defaultValues });
163
- this.initConfig$.next(true);
164
- }
165
- }
166
- }
167
- catch (error) {
168
- this.notificationsService.error(`Missing valid configuration for the assistant instance '${key}'. See the browser console messages for details on the missing or incorrect properties.`);
169
- throw new Error(`Missing valid configuration for the assistant instance '${key}' . \n ${JSON.stringify(error.issues, null, 2)}`);
170
- }
371
+ this.assistantConfigurationService.initChatConfig();
171
372
  }
172
373
  /**
173
374
  * Update the chat config and store its defaultValues in the user preferences
@@ -178,28 +379,55 @@ export class ChatService {
178
379
  * @param errorCallback The callback to execute if the update fails
179
380
  */
180
381
  updateChatConfig(config, hashes, notify = true, successCallback, errorCallback) {
181
- this.assistantConfig$.next(config);
182
- const assistants = Object.assign({}, this.assistants);
183
- assistants[this.chatInstanceId] = { ...assistants[this.chatInstanceId], defaultValues: config.defaultValues };
184
- if (hashes)
185
- assistants[this.chatInstanceId].hashes = hashes;
186
- this.userSettingsService.patch({ assistants }).subscribe(next => { }, error => {
187
- if (notify) {
188
- // eslint-disable-next-line @typescript-eslint/no-unused-expressions
189
- errorCallback
190
- ? errorCallback()
191
- : this.notificationsService.error(this.transloco.translate('chat.saveChatConfig.fail', { value: this.chatInstanceId }));
192
- }
193
- console.error("Could not patch assistants!", error);
194
- }, () => {
195
- if (notify) {
196
- // eslint-disable-next-line @typescript-eslint/no-unused-expressions
197
- successCallback
198
- ? successCallback()
199
- : this.notificationsService.success(this.transloco.translate('chat.saveChatConfig.success', { value: this.chatInstanceId }));
200
- }
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
201
405
  });
202
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
+ }
203
431
  /**
204
432
  * A handler for quota updates each time the chat is invoked.
205
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.
@@ -207,17 +435,7 @@ export class ChatService {
207
435
  * @param propagateError Whether to propagate the error to the caller
208
436
  */
209
437
  updateQuota(quota, propagateError = false) {
210
- this.quota$.next(quota);
211
- const nextResetDate = this.formatDateTime(quota.nextResetUTC + "+00:00"); // This +00:00 is to ensure dates will be properly converted to local time
212
- const consumptionPercentage = Math.round((quota.tokenCount * 100 / quota.periodTokens) * 100) / 100;
213
- this.userTokenConsumption$.next({ percentage: consumptionPercentage, nextResetDate });
214
- if (quota.maxQuotaReached) {
215
- this.generateAuditEvent('ast-quota.exceeded', {});
216
- const msg = `Sorry, you have exceeded the allowed quota. Please retry starting from ${nextResetDate}.`;
217
- this.notificationsService.error(msg);
218
- if (propagateError)
219
- throw new Error(msg);
220
- }
438
+ this.assistantTokensTrackingService.updateQuota(quota, propagateError);
221
439
  }
222
440
  /**
223
441
  * A handler for chat usage metrics each time the generation of the assistant response is completed.
@@ -225,10 +443,7 @@ export class ChatService {
225
443
  * @param chatUsageMetrics The chat usage metrics
226
444
  */
227
445
  updateChatUsageMetrics(chatUsageMetrics) {
228
- this.chatUsageMetrics$.next(chatUsageMetrics);
229
- const currentModel = this.getModel(this.assistantConfig$.value.defaultValues.service_id, this.assistantConfig$.value.defaultValues.model_id);
230
- const consumptionPercentage = Math.round((chatUsageMetrics.totalTokenCount * 100 / (currentModel.contextWindowSize - currentModel.maxGenerationSize)) * 100) / 100;
231
- this.chatTokenConsumption$.next({ percentage: consumptionPercentage });
446
+ this.assistantTokensTrackingService.updateChatUsageMetrics(chatUsageMetrics);
232
447
  }
233
448
  /**
234
449
  * Get the model description for the given (serviceId + modelId)
@@ -246,6 +461,110 @@ export class ChatService {
246
461
  }
247
462
  return model;
248
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
+ }
249
568
  /**
250
569
  * Generate an audit event with the given type and details. The generated audit event is sent afterwards via the AuditWebService
251
570
  * @param type Audit event type
@@ -260,9 +579,11 @@ export class ChatService {
260
579
  "instance-id": this.chatInstanceId,
261
580
  "chat-id": id || this.chatId,
262
581
  "service-id": this.assistantConfig$.value.defaultValues.service_id,
263
- "model-id": this.assistantConfig$.value.defaultValues.model_id,
264
- "is-user-input": false
582
+ "model-id": this.assistantConfig$.value.defaultValues.model_id
265
583
  };
584
+ if (type === "ast-message.message") {
585
+ baseDetails["is-user-input"] = false;
586
+ }
266
587
  const audit = {
267
588
  type,
268
589
  detail: {
@@ -270,143 +591,7 @@ export class ChatService {
270
591
  ...details
271
592
  }
272
593
  };
273
- const response = await Audit.notify(audit);
274
- console.log("Audit response", response);
275
- }
276
- /**
277
- * Traverse the array from the end and track the first 'assistant' message among the last group of "assistant" messages where display is true
278
- * @param array The array of ChatMessage to traverse
279
- * @returns The index of the first visible assistant message among the last group of "assistant" messages in the array
280
- */
281
- firstVisibleAssistantMessageIndex(array) {
282
- if (!array) {
283
- return -1;
284
- }
285
- let index = array.length - 1;
286
- let firstVisibleAssistantMessageIndex = -1;
287
- while (index >= 0 && array[index].role === 'assistant') {
288
- if (array[index].additionalProperties.display === true) {
289
- firstVisibleAssistantMessageIndex = index;
290
- }
291
- index--;
292
- }
293
- return firstVisibleAssistantMessageIndex;
294
- }
295
- /**
296
- * Traverse the array from the end and pick the last 'assistant' message among the last group of "assistant" messages where display is true
297
- * @param array The array of ChatMessage to traverse
298
- * @returns The index of the last visible assistant message among the last group of "assistant" messages in the array
299
- */
300
- lastVisibleAssistantMessageIndex(array) {
301
- if (!array) {
302
- return -1;
303
- }
304
- let index = array.length - 1;
305
- let lastVisibleAssistantMessageIndex = -1;
306
- while (index >= 0 && array[index].role === 'assistant') {
307
- if (array[index].additionalProperties.display === true) {
308
- lastVisibleAssistantMessageIndex = index;
309
- break;
310
- }
311
- index--;
312
- }
313
- return lastVisibleAssistantMessageIndex;
314
- }
315
- /**
316
- * Format a date string in UTC to a local date string
317
- * @param value Date string in UTC to format
318
- * @returns A formatted local date string
319
- */
320
- formatDateTime(value) {
321
- const localDate = toDate(parseISO(value));
322
- const formatter = new Intl.DateTimeFormat(undefined, {
323
- year: 'numeric',
324
- month: 'short',
325
- day: 'numeric',
326
- hour: '2-digit',
327
- minute: '2-digit',
328
- second: '2-digit',
329
- timeZoneName: 'short'
330
- });
331
- return formatter.format(localDate);
332
- }
333
- /**
334
- * Takes a text prompt that may contain placeholders for variables
335
- * and replaces these placeholders if it finds a match in the given
336
- * context object.
337
- *
338
- * @example
339
- * const p = "Hello, [[user.name]]! You have [[user.notifications.length]] new notifications.";
340
- * const context = {
341
- * user: {
342
- * name: "Alice",
343
- * notifications: ["Message from Bob", "Reminder for meeting"]
344
- * }
345
- * };
346
- * const formattedPrompt = formatPrompt(p, context);
347
- * console.log(formattedPrompt); // Output: "Hello, Alice! You have 2 new notifications."
348
- */
349
- static formatPrompt(prompt, context) {
350
- return prompt.replace(/\[\[(.*?)\]\]/g, (match, expr) => {
351
- // Simple dot notation resolver
352
- const keys = expr.trim().split(".");
353
- let value = context;
354
- for (const key of keys) {
355
- if (value && typeof value === "object" && key in value) {
356
- value = value[key];
357
- }
358
- else {
359
- return match;
360
- }
361
- }
362
- return value ?? match;
363
- });
364
- }
365
- /**
366
- * Determines a time-based key for a given date to be used for translations or formatting.
367
- * The key represents a relative time period such as "today", "yesterday", "this week", etc.
368
- * If the date does not fall into any predefined relative time period, it returns the year as a string.
369
- *
370
- * @param date - The date for which the time key is to be determined.
371
- * @returns A string representing the time key, which can be used for translation or display purposes.
372
- */
373
- getTimeKey(date) {
374
- if (isToday(date)) {
375
- return this.transloco.translate('chat.today');
376
- }
377
- else if (isYesterday(date)) {
378
- return this.transloco.translate('chat.yesterday');
379
- }
380
- else if (isThisWeek(date)) {
381
- return this.transloco.translate('chat.thisWeek');
382
- }
383
- else if (differenceInDays(endOfYesterday(), date) <= 7) {
384
- return this.transloco.translate('chat.lastWeek');
385
- }
386
- else if (isThisMonth(date)) {
387
- return this.transloco.translate('chat.thisMonth');
388
- }
389
- else if (differenceInMonths(endOfYesterday(), date) <= 1) {
390
- return this.transloco.translate('chat.lastMonth');
391
- }
392
- else if (isThisQuarter(date)) {
393
- return this.transloco.translate('chat.thisQuarter');
394
- }
395
- else if (differenceInMonths(endOfYesterday(), date) <= 3) {
396
- return this.transloco.translate('chat.lastQuarter');
397
- }
398
- else if (isThisYear(date)) {
399
- return this.transloco.translate('chat.thisYear');
400
- }
401
- else if (differenceInYears(endOfYesterday(), date) === 1) {
402
- return this.transloco.translate('chat.lastYear');
403
- }
404
- else {
405
- return format(date, 'yyyy');
406
- }
407
- }
408
- getCurrentLocaleName() {
409
- return this.localID || '';
594
+ await Audit.notify(audit);
410
595
  }
411
596
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ChatService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
412
597
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ChatService }); }
@@ -414,4 +599,4 @@ export class ChatService {
414
599
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ChatService, decorators: [{
415
600
  type: Injectable
416
601
  }] });
417
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hhdC5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vcHJvamVjdHMvYXNzaXN0YW50L2NoYXQvY2hhdC5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsU0FBUyxFQUFFLE1BQU0sRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUM5RCxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUN0RCxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsa0JBQWtCLEVBQUUsaUJBQWlCLEVBQUUsY0FBYyxFQUFFLE1BQU0sRUFBRSxXQUFXLEVBQUUsYUFBYSxFQUFFLFVBQVUsRUFBRSxVQUFVLEVBQUUsT0FBTyxFQUFFLFdBQVcsRUFBRSxRQUFRLEVBQUUsTUFBTSxFQUFFLE1BQU0sVUFBVSxDQUFDO0FBQ3ZNLE9BQU8sRUFBRSxlQUFlLEVBQWMsTUFBTSxNQUFNLENBQUM7QUFFbkQsT0FBTyxFQUFFLEtBQUssRUFBUyxRQUFRLEVBQUUsY0FBYyxFQUFFLGlCQUFpQixFQUFFLElBQUksRUFBRSxNQUFNLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUUxRyxPQUFPLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUNyRSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDcEQsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQzFELE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBQ3ZFLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBQ2hFLE9BQU8sRUFBRSxzQkFBc0IsRUFBRSxNQUFNLGtDQUFrQyxDQUFDO0FBQzFFLE9BQU8sRUFBdU4sZ0JBQWdCLEVBQUUsTUFBTSxTQUFTLENBQUM7QUFDaFEsT0FBTyxFQUFFLHlCQUF5QixFQUFFLE1BQU0sd0JBQXdC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Q0FBQyxjQUFjLEVBQUUsRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUMzRCxPQUFPLElBQUksQ0FBQyxTQUFTLENBQUMsU0FBUyxDQUFDLGVBQWUsQ0FBQyxDQUFDO1FBQ25ELENBQUM7YUFBTSxDQUFDO1lBQ04sT0FBTyxNQUFNLENBQUMsSUFBSSxFQUFFLE1BQU0sQ0FBQyxDQUFDO1FBQzlCLENBQUM7SUFDSCxDQUFDO0lBRUgsb0JBQW9CO1FBQ2xCLE9BQU8sSUFBSSxDQUFDLE9BQU8sSUFBSSxFQUFFLENBQUM7SUFDNUIsQ0FBQzsrR0FoZm1CLFdBQVc7bUhBQVgsV0FBVzs7NEZBQVgsV0FBVztrQkFEaEMsVUFBVSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEluamVjdGFibGUsIExPQ0FMRV9JRCwgaW5qZWN0IH0gZnJvbSBcIkBhbmd1bGFyL2NvcmVcIjtcbmltcG9ydCB7IFRyYW5zbG9jb1NlcnZpY2UgfSBmcm9tIFwiQGpzdmVyc2UvdHJhbnNsb2NvXCI7XG5pbXBvcnQgeyBkaWZmZXJlbmNlSW5EYXlzLCBkaWZmZXJlbmNlSW5Nb250aHMsIGRpZmZlcmVuY2VJblllYXJzLCBlbmRPZlllc3RlcmRheSwgZm9ybWF0LCBpc1RoaXNNb250aCwgaXNUaGlzUXVhcnRlciwgaXNUaGlzV2VlaywgaXNUaGlzWWVhciwgaXNUb2RheSwgaXNZZXN0ZXJkYXksIHBhcnNlSVNPLCB0b0RhdGUgfSBmcm9tIFwiZGF0ZS1mbnNcIjtcbmltcG9ydCB7IEJlaGF2aW9yU3ViamVjdCwgT2JzZXJ2YWJsZSB9IGZyb20gXCJyeGpzXCI7XG5cbmltcG9ydCB7IEF1ZGl0LCBRdWVyeSwgZmV0Y2hBcHAsIGZldGNoUHJpbmNpcGFsLCBmZXRjaFVzZXJTZXR0aW5ncywgZ3VpZCwgc2hhNTEyIH0gZnJvbSBcIkBzaW5lcXVhL2F0b21pY1wiO1xuXG5pbXBvcnQgeyBEaWFsb2dVcGRhdGVzQ29tcG9uZW50IH0gZnJvbSBcIi4vZGlhbG9ncy91cGRhdGVzLmNvbXBvbmVudFwiO1xuaW1wb3J0IHsgQXBwU2VydmljZSB9IGZyb20gXCIuL3NlcnZpY2VzL2FwcC5zZXJ2aWNlXCI7XG5pbXBvcnQgeyBEaWFsb2dTZXJ2aWNlIH0gZnJvbSBcIi4vc2VydmljZXMvZGlhbG9nLnNlcnZpY2VcIjtcbmltcG9ydCB7IE5vdGlmaWNhdGlvbnNTZXJ2aWNlIH0gZnJvbSBcIi4vc2VydmljZXMvbm90aWZpY2F0aW9uLnNlcnZpY2VcIjtcbmltcG9ydCB7IFByaW5jaXBhbFNlcnZpY2UgfSBmcm9tIFwiLi9zZXJ2aWNlcy9wcmluY2lwYWwuc2VydmljZVwiO1xuaW1wb3J0IHsgVXNlclNldHRpbmdzV2ViU2VydmljZSB9IGZyb20gXCIuL3NlcnZpY2VzL3VzZXItc2V0dGluZ3Muc2VydmljZVwiO1xuaW1wb3J0IHsgQ2hhdENvbmZpZywgQ2hhdE1lc3NhZ2UsIENoYXRSZXNwb25zZSwgQ2hhdFVzYWdlTWV0cmljcywgRGVsZXRlU2F2ZWRDaGF0UmVzcG9uc2UsIEdsbG1GdW5jdGlvbiwgR2xsbU1vZGVsRGVzY3JpcHRpb24sIFF1b3RhLCBTYXZlZENoYXQsIFNhdmVkQ2hhdEhpc3RvcnksIFNhdmVkQ2hhdFJlc3BvbnNlLCBUb2tlbkNvbnN1bXB0aW9uLCBVc2VyVG9rZW5Db25zdW1wdGlvbiwgY2hhdENvbmZpZ1NjaGVtYSB9IGZyb20gXCIuL3R5cGVzXCI7XG5pbXBvcnQgeyBnZXRBc3Npc3RhbnRKc29uRnJvbUNDQXBwIH0gZnJvbSBcIi4vdXRpbHMvYXNzaXN0YW50LWpzb25cIjtcblxuQEluamVjdGFibGUoKVxuZXhwb3J0IGFic3RyYWN0IGNsYXNzIENoYXRTZXJ2aWNlIHtcblxuICByZWFkb25seSBsb2NhbElEID0gaW5qZWN0KExPQ0FMRV9JRCwge29wdGlvbmFsOiB0cnVlfSk7XG5cbiAgLyoqIE5hbWUgb2YgdGhlIGFzc2lzdGFudCBwbHVnaW4gT1Igd2Vic29ja2V0IGVuZHBvaW50LiAqL1xuICBSRVFVRVNUX1VSTDogc3RyaW5nO1xuICAvKiogRW1pdCB0cnVlIG9uY2UgdGhlIGluaXRpYWxpemF0aW9uIG9mIHRoZSBhc3Npc3RhbnQgcHJvY2VzcyBpcyBkb25lLiAqL1xuICBpbml0UHJvY2VzcyQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PGJvb2xlYW4+KGZhbHNlKTtcbiAgLyoqIEVtaXQgdHJ1ZSBvbmNlIHRoZSBpbml0aWFsaXphdGlvbiBvZiB0aGUgYXNzaXN0YW50IGNvbmZpZyBpcyBkb25lLiAqL1xuICBpbml0Q29uZmlnJCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8Ym9vbGVhbj4oZmFsc2UpO1xuICAvKiogRW1pdCB0aGUgZ2xvYmFsIGNvbmZpZ3VyYXRpb24gb2YgdGhlIGFzc2lzdGFudC4gKi9cbiAgYXNzaXN0YW50Q29uZmlnJCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8Q2hhdENvbmZpZyB8IHVuZGVmaW5lZD4odW5kZWZpbmVkKTtcbiAgLyoqIEVtaXQgdHJ1ZSBpZiB0aGUgdXNlciBoYXMgYmVlbiBvdmVycmlkZGVuLCBmYWxzZSBvdGhlcndpc2UuICovXG4gIHVzZXJPdmVycmlkZSQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PGJvb2xlYW4gfCB1bmRlZmluZWQ+KHVuZGVmaW5lZCk7XG4gIC8qKlxuICAgKiBFbWl0IHRydWUgaWYgdGhlIGZldGNoIG9mIGFuIGFzc2lzdGFudCdzIHJlc3BvbnNlIGlzIG9uZ29pbmcgKGl0IGluY2x1ZGVzIFN0cmVhbWluZyBzdGF0dXMgb2YgdGhlIGFzc2lzdGFudCBlbmRwb2ludCBBTkQgc2F2aW5nIHRoZSBkaXNjdXNzaW9uIGlmIHNhdmUgQ2hhdCBpcyBlbmFibGVkKS5cbiAgICogVGhpcyBpcyB1c2VkIHRvIHByZXZlbnQgbXVsdGlwbGUgZmV0Y2hlcyBhdCB0aGUgc2FtZSB0aW1lLlxuICAgKiBUeXBpY2FsbHksIHRoZXJlIGlzIG5vIHByb2JsZW0gY2hhaW5pbmcgZmV0Y2hlcywgYnV0IHdoZW4gZm9yY2luZyBhIHJlbG9hZCBhZnRlciBxdWVyeSBjaGFuZ2VzIGNhc2VzLCBpdCBjYW4ndCBiZSBhbGxvd2VkIGJlY2F1c2UgaXQgYnJlYWtzIHRoZSB3aG9sZSBidXNpbmVzcyBsb2dpYy5cbiAgKi9cbiAgc3RyZWFtaW5nJCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8Ym9vbGVhbj4oZmFsc2UpO1xuICAvKiogU3RvcmUgdGhlIG1lc3NhZ2VzIGhpc3Rvcnkgb2YgdGhlIGN1cnJlbnQgY2hhdC4gKi9cbiAgY2hhdEhpc3Rvcnk6IENoYXRNZXNzYWdlW10gfCB1bmRlZmluZWQ7XG4gIC8qKiBMaXN0IG9mIG1vZGVscyBhdmFpbGFibGUgb24gdGhlIHNlcnZlci4gKi9cbiAgbW9kZWxzOiBHbGxtTW9kZWxEZXNjcmlwdGlvbltdIHwgdW5kZWZpbmVkO1xuICAvKiogTGlzdCBvZiBmdW5jdGlvbnMgYXZhaWxhYmxlIG9uIHRoZSBzZXJ2ZXIuICovXG4gIGZ1bmN0aW9uczogR2xsbUZ1bmN0aW9uW10gfCB1bmRlZmluZWQ7XG4gIC8qKiBMaXN0IG9mIHNhdmVkIGNoYXRzLiAqL1xuICBzYXZlZENoYXRzJCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8U2F2ZWRDaGF0W10+KFtdKTtcbiAgLyoqIEVtaXQgdGhlIHNhdmVkIGNoYXQgdG8gbG9hZC4gKi9cbiAgbG9hZFNhdmVkQ2hhdCQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PFNhdmVkQ2hhdCB8IHVuZGVmaW5lZD4odW5kZWZpbmVkKTtcbiAgLyoqIEVtaXQgdGhlIHF1b3RhIGVhY2ggdGltZSB0aGUgY2hhdCBpcyBpbnZva2VkLiAqL1xuICBxdW90YSQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PFF1b3RhIHwgdW5kZWZpbmVkPih1bmRlZmluZWQpO1xuICAvKiogRW1pdCB0aGUgY2FsY3VsYXRlZCB1c2VyJ3MgdG9rZW4gY29uc3VtcHRpb24gYmFzZWQgb24gdGhlIHF1b3RhLiAqL1xuICB1c2VyVG9rZW5Db25zdW1wdGlvbiQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PFVzZXJUb2tlbkNvbnN1bXB0aW9uIHwgdW5kZWZpbmVkPih1bmRlZmluZWQpO1xuICAvKiogRW1pdCB0aGUgY2hhdCB1c2FnZSBtZXRyaWNzIGVhY2ggdGltZSB0aGUgZ2VuZXJhdGlvbiBvZiB0aGUgYXNzaXN0YW50IHJlc3BvbnNlIGlzIGNvbXBsZXRlZC4gKi9cbiAgY2hhdFVzYWdlTWV0cmljcyQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PENoYXRVc2FnZU1ldHJpY3MgfCB1bmRlZmluZWQ+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