@sinequa/assistant 3.8.0 → 3.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/chat/charts/chart/chart.component.d.ts +13 -13
- package/chat/chat-message/chat-message.component.d.ts +85 -81
- package/chat/chat-message/i18n/en.json +11 -0
- package/chat/chat-message/i18n/fr.json +11 -0
- package/chat/chat-reference/chat-reference.component.d.ts +14 -14
- package/chat/chat-reference/i18n/en.json +4 -0
- package/chat/chat-reference/i18n/fr.json +4 -0
- package/chat/chat-settings-v3/chat-settings-v3.component.d.ts +48 -50
- package/chat/chat-settings-v3/i18n/en.json +14 -0
- package/chat/chat-settings-v3/i18n/fr.json +14 -0
- package/chat/chat.component.d.ts +388 -1405
- package/chat/chat.service.d.ts +247 -228
- package/chat/debug-message/debug-message.component.d.ts +17 -17
- package/chat/debug-message/i18n/en.json +3 -0
- package/chat/debug-message/i18n/fr.json +3 -0
- package/chat/dialogs/delete-saved-chat.component.d.ts +22 -0
- package/chat/dialogs/i18n/en.json +19 -0
- package/chat/dialogs/i18n/fr.json +19 -0
- package/chat/dialogs/rename-saved-chat.component.d.ts +21 -0
- package/chat/dialogs/updates.component.d.ts +15 -0
- package/chat/documents-upload/document-list/document-list.component.d.ts +68 -77
- package/chat/documents-upload/document-overview/document-overview.component.d.ts +31 -41
- package/chat/documents-upload/document-upload/document-upload.component.d.ts +96 -98
- package/chat/documents-upload/documents-upload.model.d.ts +66 -66
- package/chat/documents-upload/documents-upload.service.d.ts +170 -174
- package/chat/documents-upload/i18n/en.json +24 -0
- package/chat/documents-upload/i18n/fr.json +24 -0
- package/chat/format-icon/format-icon.component.d.ts +10 -10
- package/chat/format-icon/icons.d.ts +5 -5
- package/chat/i18n/en.json +42 -0
- package/chat/i18n/fr.json +42 -0
- package/chat/index.d.ts +5 -5
- package/chat/initials-avatar/initials-avatar.component.d.ts +35 -35
- package/chat/instance-manager.service.d.ts +28 -28
- package/chat/pipes/message-content.pipe.d.ts +16 -0
- package/chat/prompt.component.d.ts +25 -21
- package/chat/public-api.d.ts +17 -17
- package/chat/references/i18n/en.json +6 -0
- package/chat/references/i18n/fr.json +6 -0
- package/chat/references/inline-image-reference.d.ts +21 -0
- package/chat/references/inline-page-reference.d.ts +21 -0
- package/chat/rest-chat.service.d.ts +31 -33
- package/chat/saved-chats/i18n/en.json +4 -0
- package/chat/saved-chats/i18n/fr.json +4 -0
- package/chat/saved-chats/saved-chats.component.d.ts +30 -36
- package/chat/services/app.service.d.ts +8 -0
- package/chat/services/dialog.service.d.ts +12 -0
- package/chat/services/notification.service.d.ts +10 -0
- package/chat/services/principal.service.d.ts +7 -0
- package/chat/services/search.service.d.ts +7 -0
- package/chat/services/signalR.web.service.d.ts +45 -0
- package/chat/services/ui.service.d.ts +13 -0
- package/chat/services/user-settings.service.d.ts +7 -0
- package/chat/token-progress-bar/i18n/en.json +4 -0
- package/chat/token-progress-bar/i18n/fr.json +4 -0
- package/chat/token-progress-bar/token-progress-bar.component.d.ts +24 -27
- package/chat/tooltip/tooltip.component.d.ts +12 -0
- package/chat/tooltip/tooltip.directive.d.ts +81 -0
- package/chat/types/message-content.types.d.ts +54 -0
- package/chat/types/message-reference.types.d.ts +11 -0
- package/chat/types.d.ts +913 -873
- package/chat/unified-plugins/embedded-image-reference.plugin.d.ts +3 -0
- package/chat/unified-plugins/embedded-page-reference.plugin.d.ts +3 -0
- package/chat/utils/assistant-json.d.ts +2 -0
- package/chat/websocket-chat.service.d.ts +102 -103
- package/esm2022/chat/charts/chart/chart.component.mjs +40 -0
- package/esm2022/chat/chat-message/chat-message.component.mjs +351 -0
- package/esm2022/chat/chat-reference/chat-reference.component.mjs +40 -0
- package/esm2022/chat/chat-settings-v3/chat-settings-v3.component.mjs +118 -0
- package/esm2022/chat/chat.component.mjs +1090 -0
- package/esm2022/chat/chat.service.mjs +417 -0
- package/esm2022/chat/debug-message/debug-message.component.mjs +43 -0
- package/esm2022/chat/dialogs/delete-saved-chat.component.mjs +81 -0
- package/esm2022/chat/dialogs/rename-saved-chat.component.mjs +84 -0
- package/esm2022/chat/dialogs/updates.component.mjs +61 -0
- package/esm2022/chat/documents-upload/document-list/document-list.component.mjs +140 -0
- package/esm2022/chat/documents-upload/document-overview/document-overview.component.mjs +65 -0
- package/esm2022/chat/documents-upload/document-upload/document-upload.component.mjs +256 -0
- package/{esm2020 → esm2022}/chat/documents-upload/documents-upload.model.mjs +1 -1
- package/esm2022/chat/documents-upload/documents-upload.service.mjs +291 -0
- package/{esm2020 → esm2022}/chat/format-icon/format-icon.component.mjs +23 -23
- package/{esm2020 → esm2022}/chat/format-icon/icons.mjs +137 -137
- package/{esm2020 → esm2022}/chat/initials-avatar/initials-avatar.component.mjs +60 -60
- package/esm2022/chat/instance-manager.service.mjs +46 -0
- package/esm2022/chat/pipes/message-content.pipe.mjs +34 -0
- package/esm2022/chat/prompt.component.mjs +88 -0
- package/{esm2020 → esm2022}/chat/public-api.mjs +18 -18
- package/esm2022/chat/references/inline-image-reference.mjs +110 -0
- package/esm2022/chat/references/inline-page-reference.mjs +110 -0
- package/esm2022/chat/rest-chat.service.mjs +296 -0
- package/esm2022/chat/saved-chats/saved-chats.component.mjs +82 -0
- package/esm2022/chat/services/app.service.mjs +19 -0
- package/esm2022/chat/services/dialog.service.mjs +40 -0
- package/esm2022/chat/services/notification.service.mjs +25 -0
- package/esm2022/chat/services/principal.service.mjs +16 -0
- package/esm2022/chat/services/search.service.mjs +13 -0
- package/esm2022/chat/services/signalR.web.service.mjs +79 -0
- package/esm2022/chat/services/ui.service.mjs +61 -0
- package/esm2022/chat/services/user-settings.service.mjs +22 -0
- package/{esm2020 → esm2022}/chat/sinequa-assistant-chat.mjs +4 -4
- package/esm2022/chat/token-progress-bar/token-progress-bar.component.mjs +52 -0
- package/esm2022/chat/tooltip/tooltip.component.mjs +44 -0
- package/esm2022/chat/tooltip/tooltip.directive.mjs +203 -0
- package/esm2022/chat/types/message-content.types.mjs +2 -0
- package/esm2022/chat/types/message-reference.types.mjs +2 -0
- package/esm2022/chat/types.mjs +130 -0
- package/esm2022/chat/unified-plugins/embedded-image-reference.plugin.mjs +57 -0
- package/esm2022/chat/unified-plugins/embedded-page-reference.plugin.mjs +57 -0
- package/esm2022/chat/utils/assistant-json.mjs +12 -0
- package/esm2022/chat/websocket-chat.service.mjs +654 -0
- package/{esm2020 → esm2022}/public-api.mjs +2 -2
- package/{esm2020 → esm2022}/sinequa-assistant.mjs +4 -4
- package/fesm2022/sinequa-assistant-chat.mjs +5340 -0
- package/fesm2022/sinequa-assistant-chat.mjs.map +1 -0
- package/{fesm2015 → fesm2022}/sinequa-assistant.mjs +3 -3
- package/index.d.ts +5 -5
- package/package.json +52 -25
- package/public-api.d.ts +1 -1
- package/chat/messages/de.d.ts +0 -4
- package/chat/messages/en.d.ts +0 -4
- package/chat/messages/fr.d.ts +0 -4
- package/chat/messages/index.d.ts +0 -4
- package/esm2020/chat/charts/chart/chart.component.mjs +0 -40
- package/esm2020/chat/chat-message/chat-message.component.mjs +0 -263
- package/esm2020/chat/chat-reference/chat-reference.component.mjs +0 -40
- package/esm2020/chat/chat-settings-v3/chat-settings-v3.component.mjs +0 -117
- package/esm2020/chat/chat.component.mjs +0 -1069
- package/esm2020/chat/chat.service.mjs +0 -333
- package/esm2020/chat/debug-message/debug-message.component.mjs +0 -43
- package/esm2020/chat/documents-upload/document-list/document-list.component.mjs +0 -191
- package/esm2020/chat/documents-upload/document-overview/document-overview.component.mjs +0 -80
- package/esm2020/chat/documents-upload/document-upload/document-upload.component.mjs +0 -258
- package/esm2020/chat/documents-upload/documents-upload.service.mjs +0 -289
- package/esm2020/chat/instance-manager.service.mjs +0 -46
- package/esm2020/chat/messages/de.mjs +0 -4
- package/esm2020/chat/messages/en.mjs +0 -4
- package/esm2020/chat/messages/fr.mjs +0 -4
- package/esm2020/chat/messages/index.mjs +0 -9
- package/esm2020/chat/prompt.component.mjs +0 -88
- package/esm2020/chat/rest-chat.service.mjs +0 -241
- package/esm2020/chat/saved-chats/saved-chats.component.mjs +0 -175
- package/esm2020/chat/token-progress-bar/token-progress-bar.component.mjs +0 -54
- package/esm2020/chat/types.mjs +0 -112
- package/esm2020/chat/websocket-chat.service.mjs +0 -641
- package/fesm2015/sinequa-assistant-chat.mjs +0 -4200
- package/fesm2015/sinequa-assistant-chat.mjs.map +0 -1
- package/fesm2020/sinequa-assistant-chat.mjs +0 -4171
- package/fesm2020/sinequa-assistant-chat.mjs.map +0 -1
- package/fesm2020/sinequa-assistant.mjs +0 -9
- package/fesm2020/sinequa-assistant.mjs.map +0 -1
- /package/{fesm2015 → fesm2022}/sinequa-assistant.mjs.map +0 -0
|
@@ -1,333 +0,0 @@
|
|
|
1
|
-
import { Injectable, inject } from "@angular/core";
|
|
2
|
-
import { parseISO, toDate } from "date-fns";
|
|
3
|
-
import get from "lodash/get";
|
|
4
|
-
import { BehaviorSubject } from "rxjs";
|
|
5
|
-
import { UserPreferences } from "@sinequa/components/user-settings";
|
|
6
|
-
import { AppService } from "@sinequa/core/app-utils";
|
|
7
|
-
import { Utils } from "@sinequa/core/base";
|
|
8
|
-
import { IntlService } from "@sinequa/core/intl";
|
|
9
|
-
import { LoginService } from "@sinequa/core/login";
|
|
10
|
-
import { ModalButton, ModalService } from "@sinequa/core/modal";
|
|
11
|
-
import { NotificationsService } from "@sinequa/core/notification";
|
|
12
|
-
import { AuditWebService, PrincipalWebService, UserSettingsWebService } from "@sinequa/core/web-services";
|
|
13
|
-
import { chatConfigSchema } from "./types";
|
|
14
|
-
import * as i0 from "@angular/core";
|
|
15
|
-
export class ChatService {
|
|
16
|
-
constructor() {
|
|
17
|
-
/** Emit true once the initialization of the assistant process is done. */
|
|
18
|
-
this.initProcess$ = new BehaviorSubject(false);
|
|
19
|
-
/** Emit true once the initialization of the assistant config is done. */
|
|
20
|
-
this.initConfig$ = new BehaviorSubject(false);
|
|
21
|
-
/** Emit the global configuration of the assistant. */
|
|
22
|
-
this.assistantConfig$ = new BehaviorSubject(undefined);
|
|
23
|
-
/** Emit true if the user has been overridden, false otherwise. */
|
|
24
|
-
this.userOverride$ = new BehaviorSubject(undefined);
|
|
25
|
-
/**
|
|
26
|
-
* Emit true if the fetch of an assistant's response is ongoing (it includes Streaming status of the assistant endpoint AND saving the discussion if save Chat is enabled).
|
|
27
|
-
* This is used to prevent multiple fetches at the same time.
|
|
28
|
-
* Typically, there is no problem chaining fetches, but when forcing a reload after query changes cases, it can't be allowed because it breaks the whole business logic.
|
|
29
|
-
*/
|
|
30
|
-
this.streaming$ = new BehaviorSubject(false);
|
|
31
|
-
/** List of saved chats. */
|
|
32
|
-
this.savedChats$ = new BehaviorSubject([]);
|
|
33
|
-
/** Emit the saved chat to load. */
|
|
34
|
-
this.loadSavedChat$ = new BehaviorSubject(undefined);
|
|
35
|
-
/** Emit the quota each time the chat is invoked. */
|
|
36
|
-
this.quota$ = new BehaviorSubject(undefined);
|
|
37
|
-
/** Emit the calculated user's token consumption based on the quota. */
|
|
38
|
-
this.userTokenConsumption$ = new BehaviorSubject(undefined);
|
|
39
|
-
/** Emit the chat usage metrics each time the generation of the assistant response is completed. */
|
|
40
|
-
this.chatUsageMetrics$ = new BehaviorSubject(undefined);
|
|
41
|
-
/** Emit the calculated chat's token consumption based on the chat usage metrics. */
|
|
42
|
-
this.chatTokenConsumption$ = new BehaviorSubject(undefined);
|
|
43
|
-
/** Emit true if "CancelTasks" is ongoing. */
|
|
44
|
-
this.stoppingGeneration$ = new BehaviorSubject(false);
|
|
45
|
-
this.userSettingsService = inject(UserSettingsWebService);
|
|
46
|
-
this.notificationsService = inject(NotificationsService);
|
|
47
|
-
this.auditService = inject(AuditWebService);
|
|
48
|
-
this.prefs = inject(UserPreferences);
|
|
49
|
-
this.loginService = inject(LoginService);
|
|
50
|
-
this.appService = inject(AppService);
|
|
51
|
-
this.intlService = inject(IntlService);
|
|
52
|
-
this.modalService = inject(ModalService);
|
|
53
|
-
this.principalService = inject(PrincipalWebService);
|
|
54
|
-
}
|
|
55
|
-
get assistants() {
|
|
56
|
-
if (!this.userSettingsService.userSettings)
|
|
57
|
-
this.userSettingsService.userSettings = {};
|
|
58
|
-
if (!this.userSettingsService.userSettings["assistants"])
|
|
59
|
-
this.userSettingsService.userSettings["assistants"] = {};
|
|
60
|
-
return this.userSettingsService.userSettings["assistants"];
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
* Get the instance ID of the chat service
|
|
64
|
-
* @returns The instance ID of the chat service
|
|
65
|
-
*/
|
|
66
|
-
get chatInstanceId() {
|
|
67
|
-
return this._chatInstanceId;
|
|
68
|
-
}
|
|
69
|
-
/**
|
|
70
|
-
* Persist the instance ID of the chat service
|
|
71
|
-
* @param instanceId The instance ID of the chat service
|
|
72
|
-
*/
|
|
73
|
-
setChatInstanceId(instanceId) {
|
|
74
|
-
this._chatInstanceId = instanceId;
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* Get the ID of the current chat discussion which is used to save/get/delete it
|
|
78
|
-
* @returns The ID of the current chat discussion
|
|
79
|
-
*/
|
|
80
|
-
get savedChatId() {
|
|
81
|
-
return this._savedChatId;
|
|
82
|
-
}
|
|
83
|
-
/**
|
|
84
|
-
* Persist the ID of the current chat discussion which is used to save/get/delete it
|
|
85
|
-
* @param savedChatId The ID of the current chat discussion which is used to save/get/delete it
|
|
86
|
-
*/
|
|
87
|
-
setSavedChatId(savedChatId) {
|
|
88
|
-
this._savedChatId = savedChatId;
|
|
89
|
-
}
|
|
90
|
-
/**
|
|
91
|
-
* Get the ID of the current chat discussion which is used to identify audit events
|
|
92
|
-
* @returns The ID of the current chat discussion
|
|
93
|
-
*/
|
|
94
|
-
get chatId() {
|
|
95
|
-
return this._chatId;
|
|
96
|
-
}
|
|
97
|
-
/**
|
|
98
|
-
* Generate an GUID for the current chat discussion which is used to identify audit events
|
|
99
|
-
* If the discussion is saved, the savedChatId is initialized with the value of this chatId
|
|
100
|
-
* @param chatId if provided, it will be considered as the ID of the current chat discussion which is used to identify audit events
|
|
101
|
-
*/
|
|
102
|
-
generateChatId(chatId) {
|
|
103
|
-
this._chatId = chatId || Utils.guid();
|
|
104
|
-
}
|
|
105
|
-
/**
|
|
106
|
-
* Initialize the chat config by managing ONLY sub-object **defaultValues** configs of the standard app config (defined in the customization json tab ) and the user preferences.
|
|
107
|
-
* To do so, a tracking mechanism is implemented to notify the user about the available updates in the defaultValues object of the standard app config.
|
|
108
|
-
* The rest of the config object coming from "standard app config" is used as it is without any override.
|
|
109
|
-
* Thus, the user preferences are used only for the defaultValues object.
|
|
110
|
-
* This provide a centralized way to manage the rest of the config object by admins and ensure a unique common behavior for all users.
|
|
111
|
-
*/
|
|
112
|
-
initChatConfig() {
|
|
113
|
-
const key = this.chatInstanceId;
|
|
114
|
-
const userSettingsConfig = this.assistants[key] || {};
|
|
115
|
-
const standardChatConfig = this.appService.app?.data?.assistants?.[key];
|
|
116
|
-
try {
|
|
117
|
-
// Validate the whole config object against the schema
|
|
118
|
-
chatConfigSchema.parse(standardChatConfig);
|
|
119
|
-
// 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
|
|
120
|
-
if (!userSettingsConfig.defaultValues) {
|
|
121
|
-
this.assistantConfig$.next({ ...standardChatConfig });
|
|
122
|
-
this.initConfig$.next(true);
|
|
123
|
-
}
|
|
124
|
-
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
|
|
125
|
-
// Retrieve already stored hashes in the user settings if exists
|
|
126
|
-
const appliedDefaultValuesHash = userSettingsConfig.hashes?.["applied-defaultValues-hash"];
|
|
127
|
-
const skippedDefaultValuesHash = userSettingsConfig.hashes?.["skipped-defaultValues-hash"];
|
|
128
|
-
// Create a hash of the current defaultValues of the standardChatConfig
|
|
129
|
-
const currentDefaultValuesHash = Utils.sha512(JSON.stringify(standardChatConfig.defaultValues));
|
|
130
|
-
// Implement the tracking mechanism to notify the user about the available updates in the defaultValues object of the standard app config
|
|
131
|
-
const condition = (currentDefaultValuesHash !== appliedDefaultValuesHash) && (currentDefaultValuesHash !== skippedDefaultValuesHash);
|
|
132
|
-
if (condition) {
|
|
133
|
-
this.modalService
|
|
134
|
-
.confirm({
|
|
135
|
-
title: "Available updates !",
|
|
136
|
-
message: "Changes have been made to the default configuration. Do you want to update your own version ?",
|
|
137
|
-
buttons: [
|
|
138
|
-
new ModalButton({ result: -4 /* ModalResult.No */, text: "See no more" }),
|
|
139
|
-
new ModalButton({ result: -7 /* ModalResult.Ignore */, text: "Remind me later" }),
|
|
140
|
-
new ModalButton({ result: -1 /* ModalResult.OK */, text: "Update", primary: true })
|
|
141
|
-
],
|
|
142
|
-
confirmType: 2 /* ConfirmType.Warning */
|
|
143
|
-
}).then(res => {
|
|
144
|
-
if (res === -1 /* ModalResult.OK */) {
|
|
145
|
-
const hashes = { ...userSettingsConfig.hashes, "applied-defaultValues-hash": currentDefaultValuesHash, "skipped-defaultValues-hash": undefined };
|
|
146
|
-
// Update the chat config and store its defaultValues in the user preferences
|
|
147
|
-
this.updateChatConfig({ ...standardChatConfig }, hashes, true);
|
|
148
|
-
this.initConfig$.next(true);
|
|
149
|
-
this.generateAuditEvent("configuration.edit", { 'configuration': JSON.stringify({ ...standardChatConfig }) });
|
|
150
|
-
}
|
|
151
|
-
else if (res === -4 /* ModalResult.No */) {
|
|
152
|
-
// Do not notify the user about changes while this skipped version is not updated
|
|
153
|
-
const hashes = { ...userSettingsConfig.hashes, "skipped-defaultValues-hash": currentDefaultValuesHash };
|
|
154
|
-
this.updateChatConfig({ ...standardChatConfig, defaultValues: userSettingsConfig.defaultValues }, hashes, false);
|
|
155
|
-
this.initConfig$.next(true);
|
|
156
|
-
}
|
|
157
|
-
else {
|
|
158
|
-
// Just pick the version in the user settings, nothing to be updated
|
|
159
|
-
this.assistantConfig$.next({ ...standardChatConfig, defaultValues: userSettingsConfig.defaultValues });
|
|
160
|
-
this.initConfig$.next(true);
|
|
161
|
-
}
|
|
162
|
-
});
|
|
163
|
-
}
|
|
164
|
-
else { // No available updates Or updates has been already skipped, then just pick the version in the user settings
|
|
165
|
-
this.assistantConfig$.next({ ...standardChatConfig, defaultValues: userSettingsConfig.defaultValues });
|
|
166
|
-
this.initConfig$.next(true);
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
catch (error) {
|
|
171
|
-
this.notificationsService.error(`Missing valid configuration for the assistant instance '${key}'. See the browser console messages for details on the missing or incorrect properties.`);
|
|
172
|
-
throw new Error(`Missing valid configuration for the assistant instance '${key}' . \n ${JSON.stringify(error.issues, null, 2)}`);
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
/**
|
|
176
|
-
* Update the chat config and store its defaultValues in the user preferences
|
|
177
|
-
* @param config The updated chat config
|
|
178
|
-
* @param hashes The updated hashes to store in the user preferences
|
|
179
|
-
* @param notify Whether to notify the user about the update
|
|
180
|
-
* @param successCallback The callback to execute if the update is successful
|
|
181
|
-
* @param errorCallback The callback to execute if the update fails
|
|
182
|
-
*/
|
|
183
|
-
updateChatConfig(config, hashes, notify = true, successCallback, errorCallback) {
|
|
184
|
-
this.assistantConfig$.next(config);
|
|
185
|
-
const assistants = Object.assign({}, this.assistants);
|
|
186
|
-
assistants[this.chatInstanceId] = { ...assistants[this.chatInstanceId], defaultValues: config.defaultValues };
|
|
187
|
-
if (hashes)
|
|
188
|
-
assistants[this.chatInstanceId].hashes = hashes;
|
|
189
|
-
this.userSettingsService.patch({ assistants }).subscribe(next => { }, error => {
|
|
190
|
-
if (notify) {
|
|
191
|
-
errorCallback ? errorCallback() : this.notificationsService.error(`The update of the assistant instance '${this.chatInstanceId}' configuration failed`);
|
|
192
|
-
}
|
|
193
|
-
console.error("Could not patch assistants!", error);
|
|
194
|
-
}, () => {
|
|
195
|
-
if (notify) {
|
|
196
|
-
successCallback ? successCallback() : this.notificationsService.success(`The assistant instance '${this.chatInstanceId}' configuration has been successfully updated`);
|
|
197
|
-
}
|
|
198
|
-
});
|
|
199
|
-
}
|
|
200
|
-
/**
|
|
201
|
-
* A handler for quota updates each time the chat is invoked.
|
|
202
|
-
* 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.
|
|
203
|
-
* @param quota The updated quota
|
|
204
|
-
* @param propagateError Whether to propagate the error to the caller
|
|
205
|
-
*/
|
|
206
|
-
updateQuota(quota, propagateError = false) {
|
|
207
|
-
this.quota$.next(quota);
|
|
208
|
-
const nextResetDate = this.formatDateTime(quota.nextResetUTC + "+00:00"); // This +00:00 is to ensure dates will be properly converted to local time
|
|
209
|
-
const consumptionPercentage = Math.round((quota.tokenCount * 100 / quota.periodTokens) * 100) / 100;
|
|
210
|
-
this.userTokenConsumption$.next({ percentage: consumptionPercentage, nextResetDate });
|
|
211
|
-
if (quota.maxQuotaReached) {
|
|
212
|
-
this.generateAuditEvent('quota.exceeded', {});
|
|
213
|
-
const msg = `Sorry, you have exceeded the allowed quota. Please retry starting from ${nextResetDate}.`;
|
|
214
|
-
this.notificationsService.error(msg);
|
|
215
|
-
if (propagateError)
|
|
216
|
-
throw new Error(msg);
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
/**
|
|
220
|
-
* A handler for chat usage metrics each time the generation of the assistant response is completed.
|
|
221
|
-
* It emits the chat usage metrics to the chatUsageMetrics$ subject, emits accordingly the updated chat's tokens consumption
|
|
222
|
-
* @param chatUsageMetrics The chat usage metrics
|
|
223
|
-
*/
|
|
224
|
-
updateChatUsageMetrics(chatUsageMetrics) {
|
|
225
|
-
this.chatUsageMetrics$.next(chatUsageMetrics);
|
|
226
|
-
const currentModel = this.getModel(this.assistantConfig$.value.defaultValues.service_id, this.assistantConfig$.value.defaultValues.model_id);
|
|
227
|
-
const consumptionPercentage = Math.round((chatUsageMetrics.totalTokenCount * 100 / (currentModel.contextWindowSize - currentModel.maxGenerationSize)) * 100) / 100;
|
|
228
|
-
this.chatTokenConsumption$.next({ percentage: consumptionPercentage });
|
|
229
|
-
}
|
|
230
|
-
/**
|
|
231
|
-
* Get the model description for the given (serviceId + modelId)
|
|
232
|
-
* If a model is not found, an error message is returned
|
|
233
|
-
* @param serviceId The serviceId of the model
|
|
234
|
-
* @param modelId The modelId of the model
|
|
235
|
-
* @returns The model description
|
|
236
|
-
*/
|
|
237
|
-
getModel(serviceId, modelId) {
|
|
238
|
-
let model = this.models?.find(m => m.serviceId === serviceId && m.modelId === modelId);
|
|
239
|
-
// Handle obsolete config
|
|
240
|
-
if (!model) {
|
|
241
|
-
this.notificationsService.error(`FATAL ERROR : The model (serviceId = '${serviceId}', modelId = '${modelId}') is no longer available. Please contact an admin for further information.`);
|
|
242
|
-
throw new Error(`FATAL ERROR : The model (serviceId = '${serviceId}', modelId = '${modelId}') is no longer available`);
|
|
243
|
-
}
|
|
244
|
-
return model;
|
|
245
|
-
}
|
|
246
|
-
/**
|
|
247
|
-
* Generate an audit event with the given type and details. The generated audit event is sent afterwards via the AuditWebService
|
|
248
|
-
* @param type Audit event type
|
|
249
|
-
* @param details Audit event details
|
|
250
|
-
* @param id Actions (savedChat delete/rename/...) may occur on a specific chat different than the current one stored in this service, so the chat id can be provided
|
|
251
|
-
*/
|
|
252
|
-
generateAuditEvent(type, details, id) {
|
|
253
|
-
const baseDetails = {
|
|
254
|
-
"url": decodeURIComponent(window.location.href),
|
|
255
|
-
"app": this.appService.appName,
|
|
256
|
-
"user-id": this.principalService.principal?.userId,
|
|
257
|
-
"instance-id": this.chatInstanceId,
|
|
258
|
-
"chat-id": id || this.chatId,
|
|
259
|
-
"service-id": this.assistantConfig$.value.defaultValues.service_id,
|
|
260
|
-
"model-id": this.assistantConfig$.value.defaultValues.model_id,
|
|
261
|
-
};
|
|
262
|
-
const audit = {
|
|
263
|
-
type,
|
|
264
|
-
detail: {
|
|
265
|
-
...baseDetails,
|
|
266
|
-
...details
|
|
267
|
-
}
|
|
268
|
-
};
|
|
269
|
-
this.auditService.notify(audit);
|
|
270
|
-
}
|
|
271
|
-
/**
|
|
272
|
-
* Traverse the array from the end and track the first 'assistant' message among the last group of "assistant" messages where display is true
|
|
273
|
-
* @param array The array of ChatMessage to traverse
|
|
274
|
-
* @returns The index of the first visible assistant message among the last group of "assistant" messages in the array
|
|
275
|
-
*/
|
|
276
|
-
firstVisibleAssistantMessageIndex(array) {
|
|
277
|
-
if (!array) {
|
|
278
|
-
return -1;
|
|
279
|
-
}
|
|
280
|
-
let index = array.length - 1;
|
|
281
|
-
let firstVisibleAssistantMessageIndex = -1;
|
|
282
|
-
while (index >= 0 && array[index].role === 'assistant') {
|
|
283
|
-
if (array[index].additionalProperties.display === true) {
|
|
284
|
-
firstVisibleAssistantMessageIndex = index;
|
|
285
|
-
}
|
|
286
|
-
index--;
|
|
287
|
-
}
|
|
288
|
-
return firstVisibleAssistantMessageIndex;
|
|
289
|
-
}
|
|
290
|
-
/**
|
|
291
|
-
* Traverse the array from the end and pick the last 'assistant' message among the last group of "assistant" messages where display is true
|
|
292
|
-
* @param array The array of ChatMessage to traverse
|
|
293
|
-
* @returns The index of the last visible assistant message among the last group of "assistant" messages in the array
|
|
294
|
-
*/
|
|
295
|
-
lastVisibleAssistantMessageIndex(array) {
|
|
296
|
-
if (!array) {
|
|
297
|
-
return -1;
|
|
298
|
-
}
|
|
299
|
-
let index = array.length - 1;
|
|
300
|
-
let lastVisibleAssistantMessageIndex = -1;
|
|
301
|
-
while (index >= 0 && array[index].role === 'assistant') {
|
|
302
|
-
if (array[index].additionalProperties.display === true) {
|
|
303
|
-
lastVisibleAssistantMessageIndex = index;
|
|
304
|
-
break;
|
|
305
|
-
}
|
|
306
|
-
index--;
|
|
307
|
-
}
|
|
308
|
-
return lastVisibleAssistantMessageIndex;
|
|
309
|
-
}
|
|
310
|
-
/**
|
|
311
|
-
* Format a date string in UTC to a local date string
|
|
312
|
-
* @param value Date string in UTC to format
|
|
313
|
-
* @returns A formatted local date string
|
|
314
|
-
*/
|
|
315
|
-
formatDateTime(value) {
|
|
316
|
-
const localDate = toDate(parseISO(value));
|
|
317
|
-
return this.intlService["formatTime"](localDate, { day: "numeric", month: "short", year: "numeric", timeZoneName: 'short' });
|
|
318
|
-
}
|
|
319
|
-
/**
|
|
320
|
-
* Takes a text prompt that may contain placeholders for variables
|
|
321
|
-
* and replaces these placeholders if it finds a match in the given
|
|
322
|
-
* context object.
|
|
323
|
-
*/
|
|
324
|
-
static formatPrompt(prompt, context) {
|
|
325
|
-
return prompt.replace(/{{(.*?)}}/g, (match, expr) => get(context, expr) ?? match);
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
ChatService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ChatService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
329
|
-
ChatService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ChatService });
|
|
330
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ChatService, decorators: [{
|
|
331
|
-
type: Injectable
|
|
332
|
-
}] });
|
|
333
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hhdC5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vcHJvamVjdHMvYXNzaXN0YW50L2NoYXQvY2hhdC5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ25ELE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxFQUFFLE1BQU0sVUFBVSxDQUFDO0FBQzVDLE9BQU8sR0FBRyxNQUFNLFlBQVksQ0FBQztBQUM3QixPQUFPLEVBQUUsZUFBZSxFQUFjLE1BQU0sTUFBTSxDQUFDO0FBRW5ELE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxtQ0FBbUMsQ0FBQztBQUNwRSxPQUFPLEVBQUUsVUFBVSxFQUFTLE1BQU0seUJBQXlCLENBQUM7QUFDNUQsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQzNDLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUNqRCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDbkQsT0FBTyxFQUFlLFdBQVcsRUFBZSxZQUFZLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUMxRixPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUNsRSxPQUFPLEVBQUUsZUFBZSxFQUFFLG1CQUFtQixFQUFFLHNCQUFzQixFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFFMUcsT0FBTyxFQUEySyxnQkFBZ0IsRUFBRSxNQUFNLFNBQVMsQ0FBQzs7QUFHcE4sTUFBTSxPQUFnQixXQUFXO0lBRGpDO1FBSUUsMEVBQTBFO1FBQzFFLGlCQUFZLEdBQUcsSUFBSSxlQUFlLENBQVUsS0FBSyxDQUFDLENBQUM7UUFDbkQseUVBQXlFO1FBQ3pFLGdCQUFXLEdBQUcsSUFBSSxlQUFlLENBQVUsS0FBSyxDQUFDLENBQUM7UUFDbEQsc0RBQXNE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S0FBSyxXQUFXLEVBQUU7WUFDdEQsSUFBSSxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUMsb0JBQW9CLENBQUMsT0FBTyxLQUFLLElBQUksRUFBRTtnQkFDdEQsZ0NBQWdDLEdBQUcsS0FBSyxDQUFDO2dCQUN6QyxNQUFNO2FBQ1A7WUFDRCxLQUFLLEVBQUUsQ0FBQztTQUNUO1FBQ0QsT0FBTyxnQ0FBZ0MsQ0FBQztJQUMxQyxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNPLGNBQWMsQ0FBQyxLQUFhO1FBQ3BDLE1BQU0sU0FBUyxHQUFHLE1BQU0sQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztRQUMxQyxPQUFPLElBQUksQ0FBQyxXQUFXLENBQUMsWUFBWSxDQUFDLENBQUMsU0FBUyxFQUFFLEVBQUMsR0FBRyxFQUFFLFNBQVMsRUFBRSxLQUFLLEVBQUUsT0FBTyxFQUFFLElBQUksRUFBRSxTQUFTLEVBQUUsWUFBWSxFQUFFLE9BQU8sRUFBQyxDQUFDLENBQUM7SUFDN0gsQ0FBQztJQUVEOzs7O09BSUc7SUFDSCxNQUFNLENBQUMsWUFBWSxDQUFDLE1BQWMsRUFBRSxPQUFZO1FBQzlDLE9BQU8sTUFBTSxDQUFDLE9BQU8sQ0FDbkIsWUFBWSxFQUNaLENBQUMsS0FBSyxFQUFFLElBQUksRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxJQUFJLENBQUMsSUFBSSxLQUFLLENBQzdDLENBQUM7SUFDSixDQUFDOzt3R0FoYW1CLFdBQVc7NEdBQVgsV0FBVzsyRkFBWCxXQUFXO2tCQURoQyxVQUFVIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5qZWN0YWJsZSwgaW5qZWN0IH0gZnJvbSBcIkBhbmd1bGFyL2NvcmVcIjtcbmltcG9ydCB7IHBhcnNlSVNPLCB0b0RhdGUgfSBmcm9tIFwiZGF0ZS1mbnNcIjtcbmltcG9ydCBnZXQgZnJvbSBcImxvZGFzaC9nZXRcIjtcbmltcG9ydCB7IEJlaGF2aW9yU3ViamVjdCwgT2JzZXJ2YWJsZSB9IGZyb20gXCJyeGpzXCI7XG5cbmltcG9ydCB7IFVzZXJQcmVmZXJlbmNlcyB9IGZyb20gXCJAc2luZXF1YS9jb21wb25lbnRzL3VzZXItc2V0dGluZ3NcIjtcbmltcG9ydCB7IEFwcFNlcnZpY2UsIFF1ZXJ5IH0gZnJvbSBcIkBzaW5lcXVhL2NvcmUvYXBwLXV0aWxzXCI7XG5pbXBvcnQgeyBVdGlscyB9IGZyb20gXCJAc2luZXF1YS9jb3JlL2Jhc2VcIjtcbmltcG9ydCB7IEludGxTZXJ2aWNlIH0gZnJvbSBcIkBzaW5lcXVhL2NvcmUvaW50bFwiO1xuaW1wb3J0IHsgTG9naW5TZXJ2aWNlIH0gZnJvbSBcIkBzaW5lcXVhL2NvcmUvbG9naW5cIjtcbmltcG9ydCB7IENvbmZpcm1UeXBlLCBNb2RhbEJ1dHRvbiwgTW9kYWxSZXN1bHQsIE1vZGFsU2VydmljZSB9IGZyb20gXCJAc2luZXF1YS9jb3JlL21vZGFsXCI7XG5pbXBvcnQgeyBOb3RpZmljYXRpb25zU2VydmljZSB9IGZyb20gXCJAc2luZXF1YS9jb3JlL25vdGlmaWNhdGlvblwiO1xuaW1wb3J0IHsgQXVkaXRXZWJTZXJ2aWNlLCBQcmluY2lwYWxXZWJTZXJ2aWNlLCBVc2VyU2V0dGluZ3NXZWJTZXJ2aWNlIH0gZnJvbSBcIkBzaW5lcXVhL2NvcmUvd2ViLXNlcnZpY2VzXCI7XG5cbmltcG9ydCB7IENoYXRDb25maWcsIENoYXRNZXNzYWdlLCBDaGF0UmVzcG9uc2UsIENoYXRVc2FnZU1ldHJpY3MsIEdsbG1GdW5jdGlvbiwgR2xsbU1vZGVsRGVzY3JpcHRpb24sIFF1b3RhLCBTYXZlZENoYXQsIFNhdmVkQ2hhdEhpc3RvcnksIFRva2VuQ29uc3VtcHRpb24sIFVzZXJUb2tlbkNvbnN1bXB0aW9uLCBjaGF0Q29uZmlnU2NoZW1hIH0gZnJvbSBcIi4vdHlwZXNcIjtcblxuQEluamVjdGFibGUoKVxuZXhwb3J0IGFic3RyYWN0IGNsYXNzIENoYXRTZXJ2aWNlIHtcbiAgLyoqIE5hbWUgb2YgdGhlIGFzc2lzdGFudCBwbHVnaW4gT1Igd2Vic29ja2V0IGVuZHBvaW50LiAqL1xuICBSRVFVRVNUX1VSTDogc3RyaW5nO1xuICAvKiogRW1pdCB0cnVlIG9uY2UgdGhlIGluaXRpYWxpemF0aW9uIG9mIHRoZSBhc3Npc3RhbnQgcHJvY2VzcyBpcyBkb25lLiAqL1xuICBpbml0UHJvY2VzcyQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PGJvb2xlYW4+KGZhbHNlKTtcbiAgLyoqIEVtaXQgdHJ1ZSBvbmNlIHRoZSBpbml0aWFsaXphdGlvbiBvZiB0aGUgYXNzaXN0YW50IGNvbmZpZyBpcyBkb25lLiAqL1xuICBpbml0Q29uZmlnJCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8Ym9vbGVhbj4oZmFsc2UpO1xuICAvKiogRW1pdCB0aGUgZ2xvYmFsIGNvbmZpZ3VyYXRpb24gb2YgdGhlIGFzc2lzdGFudC4gKi9cbiAgYXNzaXN0YW50Q29uZmlnJCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8Q2hhdENvbmZpZyB8IHVuZGVmaW5lZD4odW5kZWZpbmVkKTtcbiAgLyoqIEVtaXQgdHJ1ZSBpZiB0aGUgdXNlciBoYXMgYmVlbiBvdmVycmlkZGVuLCBmYWxzZSBvdGhlcndpc2UuICovXG4gIHVzZXJPdmVycmlkZSQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PGJvb2xlYW4gfCB1bmRlZmluZWQ+KHVuZGVmaW5lZCk7XG4gIC8qKlxuICAgKiBFbWl0IHRydWUgaWYgdGhlIGZldGNoIG9mIGFuIGFzc2lzdGFudCdzIHJlc3BvbnNlIGlzIG9uZ29pbmcgKGl0IGluY2x1ZGVzIFN0cmVhbWluZyBzdGF0dXMgb2YgdGhlIGFzc2lzdGFudCBlbmRwb2ludCBBTkQgc2F2aW5nIHRoZSBkaXNjdXNzaW9uIGlmIHNhdmUgQ2hhdCBpcyBlbmFibGVkKS5cbiAgICogVGhpcyBpcyB1c2VkIHRvIHByZXZlbnQgbXVsdGlwbGUgZmV0Y2hlcyBhdCB0aGUgc2FtZSB0aW1lLlxuICAgKiBUeXBpY2FsbHksIHRoZXJlIGlzIG5vIHByb2JsZW0gY2hhaW5pbmcgZmV0Y2hlcywgYnV0IHdoZW4gZm9yY2luZyBhIHJlbG9hZCBhZnRlciBxdWVyeSBjaGFuZ2VzIGNhc2VzLCBpdCBjYW4ndCBiZSBhbGxvd2VkIGJlY2F1c2UgaXQgYnJlYWtzIHRoZSB3aG9sZSBidXNpbmVzcyBsb2dpYy5cbiAgKi9cbiAgc3RyZWFtaW5nJCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8Ym9vbGVhbj4oZmFsc2UpO1xuICAvKiogU3RvcmUgdGhlIG1lc3NhZ2VzIGhpc3Rvcnkgb2YgdGhlIGN1cnJlbnQgY2hhdC4gKi9cbiAgY2hhdEhpc3Rvcnk6IENoYXRNZXNzYWdlW10gfCB1bmRlZmluZWQ7XG4gIC8qKiBMaXN0IG9mIG1vZGVscyBhdmFpbGFibGUgb24gdGhlIHNlcnZlci4gKi9cbiAgbW9kZWxzOiBHbGxtTW9kZWxEZXNjcmlwdGlvbltdIHwgdW5kZWZpbmVkO1xuICAvKiogTGlzdCBvZiBmdW5jdGlvbnMgYXZhaWxhYmxlIG9uIHRoZSBzZXJ2ZXIuICovXG4gIGZ1bmN0aW9uczogR2xsbUZ1bmN0aW9uW10gfCB1bmRlZmluZWQ7XG4gIC8qKiBMaXN0IG9mIHNhdmVkIGNoYXRzLiAqL1xuICBzYXZlZENoYXRzJCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8U2F2ZWRDaGF0W10+KFtdKTtcbiAgLyoqIEVtaXQgdGhlIHNhdmVkIGNoYXQgdG8gbG9hZC4gKi9cbiAgbG9hZFNhdmVkQ2hhdCQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PFNhdmVkQ2hhdCB8IHVuZGVmaW5lZD4odW5kZWZpbmVkKTtcbiAgLyoqIEVtaXQgdGhlIHF1b3RhIGVhY2ggdGltZSB0aGUgY2hhdCBpcyBpbnZva2VkLiAqL1xuICBxdW90YSQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PFF1b3RhIHwgdW5kZWZpbmVkPih1bmRlZmluZWQpO1xuICAvKiogRW1pdCB0aGUgY2FsY3VsYXRlZCB1c2VyJ3MgdG9rZW4gY29uc3VtcHRpb24gYmFzZWQgb24gdGhlIHF1b3RhLiAqL1xuICB1c2VyVG9rZW5Db25zdW1wdGlvbiQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PFVzZXJUb2tlbkNvbnN1bXB0aW9uIHwgdW5kZWZpbmVkPih1bmRlZmluZWQpO1xuICAvKiogRW1pdCB0aGUgY2hhdCB1c2FnZSBtZXRyaWNzIGVhY2ggdGltZSB0aGUgZ2VuZXJhdGlvbiBvZiB0aGUgYXNzaXN0YW50IHJlc3BvbnNlIGlzIGNvbXBsZXRlZC4gKi9cbiAgY2hhdFVzYWdlTWV0cmljcyQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PENoYXRVc2FnZU1ldHJpY3MgfCB1bmRlZmluZWQ+KHVuZGVmaW5lZCk7XG4gIC8qKiBFbWl0IHRoZSBjYWxjdWxhdGVkIGNoYXQncyB0b2tlbiBjb25zdW1wdGlvbiBiYXNlZCBvbiB0aGUgY2hhdCB1c2FnZSBtZXRyaWNzLiAqL1xuICBjaGF0VG9rZW5Db25zdW1wdGlvbiQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PFRva2VuQ29uc3VtcHRpb24gfCB1bmRlZmluZWQ+KHVuZGVmaW5lZCk7XG4gIC8qKiBFbWl0IHRydWUgaWYgXCJDYW5jZWxUYXNrc1wiIGlzIG9uZ29pbmcuICovXG4gIHN0b3BwaW5nR2VuZXJhdGlvbiQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PGJvb2xlYW4+KGZhbHNlKTtcbiAgLyoqIEluc3RhbmNlIElEIG9mIHRoZSBjaGF0IHNlcnZpY2UgZGVmaW5pbmcgdGhlIGFzc2lzdGFudCBpbnN0YW5jZS4gKi9cbiAgcHJpdmF0ZSBfY2hhdEluc3RhbmNlSWQ6IHN0cmluZztcbiAgLyoqIElEIG9mIHRoZSBjdXJyZW50ICoqc2F2ZWQgY2hhdCoqIGRpc2N1c3Npb24gd2hpY2ggaXMgdXNlZCB0byB1cGRhdGUvZ2V0L2RlbGV0ZSBpdC4gKi9cbiAgcHJpdmF0ZSBfc2F2ZWRDaGF0SWQ6IHN0cmluZyB8IHVuZGVmaW5lZDtcbiAgLyoqIEdlbmVyYXRlZCBHVUlEIGZvciB0aGUgY3VycmVudCBub24tc2F2ZWQgY2hhdCBkaXNjdXNzaW9uIHVzZWQgdG8gaWRlbnRpZnkgYXVkaXQgZXZlbnRzLlxuICAgKiBJZiB0aGUgY2hhdCBpcyBzYXZlZCwgdGhlIHNhdmVkQ2hhdElkIGlzIGluaXRpYWxpemVkIHdpdGggdGhlIHZhbHVlIG9mIHRoaXMgY2hhdElkLlxuICAgKi9cbiAgcHJpdmF0ZSBfY2hhdElkOiBzdHJpbmc7XG5cbiAgcHVibGljIHVzZXJTZXR0aW5nc1NlcnZpY2UgPSBpbmplY3QoVXNlclNldHRpbmdzV2ViU2VydmljZSk7XG4gIHB1YmxpYyBub3RpZmljYXRpb25zU2VydmljZSA9IGluamVjdChOb3RpZmljYXRpb25zU2VydmljZSk7XG4gIHB1YmxpYyBhdWRpdFNlcnZpY2UgPSBpbmplY3QoQXVkaXRXZWJTZXJ2aWNlKTtcbiAgcHVibGljIHByZWZzID0gaW5qZWN0KFVzZXJQcmVmZXJlbmNlcyk7XG4gIHB1YmxpYyBsb2dpblNlcnZpY2UgPSBpbmplY3QoTG9naW5TZXJ2aWNlKTtcbiAgcHVibGljIGFwcFNlcnZpY2UgPSBpbmplY3QoQXBwU2VydmljZSk7XG4gIHB1YmxpYyBpbnRsU2VydmljZSA9IGluamVjdChJbnRsU2VydmljZSk7XG4gIHB1YmxpYyBtb2RhbFNlcnZpY2UgPSBpbmplY3QoTW9kYWxTZXJ2aWNlKTtcbiAgcHVibGljIHByaW5jaXBhbFNlcnZpY2UgPSBpbmplY3QoUHJpbmNpcGFsV2ViU2VydmljZSk7XG4gIC8qKlxuICAgKiBJbml0aWFsaXplIHRoZSBjaGF0IHByb2Nlc3NcbiAgICovXG4gIGFic3RyYWN0IGluaXQoKTogT2JzZXJ2YWJsZTxib29sZWFuPjtcblxuICAvKipcbiAgICogSW5pdGlhbGl6ZSB0aGUgUkVRVUVTVF9VUkxcbiAgICovXG4gIGFic3RyYWN0IGdldFJlcXVlc3RzVXJsKCk6IHZvaWQ7XG5cbiAgZ2V0IGFzc2lzdGFudHMoKTogYW55IHtcbiAgICBpZiAoIXRoaXMudXNlclNldHRpbmdzU2VydmljZS51c2VyU2V0dGluZ3MpXG4gICAgICB0aGlzLnVzZXJTZXR0aW5nc1NlcnZpY2UudXNlclNldHRpbmdzID0ge307XG4gICAgaWYgKCF0aGlzLnVzZXJTZXR0aW5nc1NlcnZpY2UudXNlclNldHRpbmdzW1wiYXNzaXN0YW50c1wiXSlcbiAgICAgIHRoaXMudXNlclNldHRpbmdzU2VydmljZS51c2VyU2V0dGluZ3NbXCJhc3Npc3RhbnRzXCJdID0ge307XG4gICAgcmV0dXJuICB0aGlzLnVzZXJTZXR0aW5nc1NlcnZpY2UudXNlclNldHRpbmdzW1wiYXNzaXN0YW50c1wiXTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgdGhlIGluc3RhbmNlIElEIG9mIHRoZSBjaGF0IHNlcnZpY2VcbiAgICogQHJldHVybnMgVGhlIGluc3RhbmNlIElEIG9mIHRoZSBjaGF0IHNlcnZpY2VcbiAgICovXG4gIGdldCBjaGF0SW5zdGFuY2VJZCgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLl9jaGF0SW5zdGFuY2VJZDtcbiAgfVxuXG4gIC8qKlxuICAgKiBQZXJzaXN0IHRoZSBpbnN0YW5jZSBJRCBvZiB0aGUgY2hhdCBzZXJ2aWNlXG4gICAqIEBwYXJhbSBpbnN0YW5jZUlkIFRoZSBpbnN0YW5jZSBJRCBvZiB0aGUgY2hhdCBzZXJ2aWNlXG4gICAqL1xuICBzZXRDaGF0SW5zdGFuY2VJZChpbnN0YW5jZUlkOiBzdHJpbmcpIHtcbiAgICB0aGlzLl9jaGF0SW5zdGFuY2VJZCA9IGluc3RhbmNlSWQ7XG4gIH1cblxuICAvKipcbiAgICogR2V0IHRoZSBJRCBvZiB0aGUgY3VycmVudCBjaGF0IGRpc2N1c3Npb24gd2hpY2ggaXMgdXNlZCB0byBzYXZlL2dldC9kZWxldGUgaXRcbiAgICogQHJldHVybnMgVGhlIElEIG9mIHRoZSBjdXJyZW50IGNoYXQgZGlzY3Vzc2lvblxuICAgKi9cbiAgZ2V0IHNhdmVkQ2hhdElkKCk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIHRoaXMuX3NhdmVkQ2hhdElkO1xuICB9XG5cbiAgLyoqXG4gICAqIFBlcnNpc3QgdGhlIElEIG9mIHRoZSBjdXJyZW50IGNoYXQgZGlzY3Vzc2lvbiB3aGljaCBpcyB1c2VkIHRvIHNhdmUvZ2V0L2RlbGV0ZSBpdFxuICAgKiBAcGFyYW0gc2F2ZWRDaGF0SWQgVGhlIElEIG9mIHRoZSBjdXJyZW50IGNoYXQgZGlzY3Vzc2lvbiB3aGljaCBpcyB1c2VkIHRvIHNhdmUvZ2V0L2RlbGV0ZSBpdFxuICAgKi9cbiAgc2V0U2F2ZWRDaGF0SWQoc2F2ZWRDaGF0SWQ6IHN0cmluZyB8IHVuZGVmaW5lZCkge1xuICAgIHRoaXMuX3NhdmVkQ2hhdElkID0gc2F2ZWRDaGF0SWQ7XG4gIH1cblxuICAvKipcbiAgICogR2V0IHRoZSBJRCBvZiB0aGUgY3VycmVudCBjaGF0IGRpc2N1c3Npb24gd2hpY2ggaXMgdXNlZCB0byBpZGVudGlmeSBhdWRpdCBldmVudHNcbiAgICogQHJldHVybnMgVGhlIElEIG9mIHRoZSBjdXJyZW50IGNoYXQgZGlzY3Vzc2lvblxuICAgKi9cbiAgZ2V0IGNoYXRJZCgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLl9jaGF0SWQ7XG4gIH1cblxuICAvKipcbiAgICogR2VuZXJhdGUgYW4gR1VJRCBmb3IgdGhlIGN1cnJlbnQgY2hhdCBkaXNjdXNzaW9uIHdoaWNoIGlzIHVzZWQgdG8gaWRlbnRpZnkgYXVkaXQgZXZlbnRzXG4gICAqIElmIHRoZSBkaXNjdXNzaW9uIGlzIHNhdmVkLCB0aGUgc2F2ZWRDaGF0SWQgaXMgaW5pdGlhbGl6ZWQgd2l0aCB0aGUgdmFsdWUgb2YgdGhpcyBjaGF0SWRcbiAgICogQHBhcmFtIGNoYXRJZCBpZiBwcm92aWRlZCwgaXQgd2lsbCBiZSBjb25zaWRlcmVkIGFzIHRoZSBJRCBvZiB0aGUgY3VycmVudCBjaGF0IGRpc2N1c3Npb24gd2hpY2ggaXMgdXNlZCB0byBpZGVudGlmeSBhdWRpdCBldmVudHNcbiAgICovXG4gIGdlbmVyYXRlQ2hhdElkKGNoYXRJZD86IHN0cmluZykge1xuICAgIHRoaXMuX2NoYXRJZCA9IGNoYXRJZCB8fCBVdGlscy5ndWlkKCk7XG4gIH1cblxuICAvKipcbiAgICogSW5pdGlhbGl6ZSB0aGUgY2hhdCBjb25maWcgYnkgbWFuYWdpbmcgT05MWSBzdWItb2JqZWN0ICoqZGVmYXVsdFZhbHVlcyoqIGNvbmZpZ3Mgb2YgdGhlIHN0YW5kYXJkIGFwcCBjb25maWcgKGRlZmluZWQgaW4gdGhlIGN1c3RvbWl6YXRpb24ganNvbiB0YWIgKSBhbmQgdGhlIHVzZXIgcHJlZmVyZW5jZXMuXG4gICAqIFRvIGRvIHNvLCBhIHRyYWNraW5nIG1lY2hhbmlzbSBpcyBpbXBsZW1lbnRlZCB0byBub3RpZnkgdGhlIHVzZXIgYWJvdXQgdGhlIGF2YWlsYWJsZSB1cGRhdGVzIGluIHRoZSBkZWZhdWx0VmFsdWVzIG9iamVjdCBvZiB0aGUgc3RhbmRhcmQgYXBwIGNvbmZpZy5cbiAgICogVGhlIHJlc3Qgb2YgdGhlIGNvbmZpZyBvYmplY3QgY29taW5nIGZyb20gXCJzdGFuZGFyZCBhcHAgY29uZmlnXCIgaXMgdXNlZCBhcyBpdCBpcyB3aXRob3V0IGFueSBvdmVycmlkZS5cbiAgICogVGh1cywgdGhlIHVzZXIgcHJlZmVyZW5jZXMgYXJlIHVzZWQgb25seSBmb3IgdGhlIGRlZmF1bHRWYWx1ZXMgb2JqZWN0LlxuICAgKiBUaGlzIHByb3ZpZGUgYSBjZW50cmFsaXplZCB3YXkgdG8gbWFuYWdlIHRoZSByZXN0IG9mIHRoZSBjb25maWcgb2JqZWN0IGJ5IGFkbWlucyBhbmQgZW5zdXJlIGEgdW5pcXVlIGNvbW1vbiBiZWhhdmlvciBmb3IgYWxsIHVzZXJzLlxuICAgKi9cbiAgaW5pdENoYXRDb25maWcoKSB7XG4gICAgY29uc3Qga2V5ID0gdGhpcy5jaGF0SW5zdGFuY2VJZDtcbiAgICBjb25zdCB1c2VyU2V0dGluZ3NDb25maWcgPSB0aGlzLmFzc2lzdGFudHNba2V5XSB8fCB7fTtcbiAgICBjb25zdCBzdGFuZGFyZENoYXRDb25maWcgPSB0aGlzLmFwcFNlcnZpY2UuYXBwPy5kYXRhPy5hc3Npc3RhbnRzPy5ba2V5XTtcblxuICAgIHRyeSB7XG4gICAgICAvLyBWYWxpZGF0ZSB0aGUgd2hvbGUgY29uZmlnIG9iamVjdCBhZ2FpbnN0IHRoZSBzY2hlbWFcbiAgICAgIGNoYXRDb25maWdTY2hlbWEucGFyc2Uoc3RhbmRhcmRDaGF0Q29uZmlnKTtcbiAgICAgIC8vIElmIHRoZSB1c2VyIHByZWZlcmVuY2VzIGRvIG5vdCBjb250YWluIGEgY29uZmlnJ3MgZGVmYXVsdFZhbHVlcyBvYmplY3QsIGtlZXAgdXNpbmcgdGhlIHN0YW5kYXJkIGFwcCBjb25maWcgYW5kIG5vdGhpbmcgdG8gc3RvcmUgaW4gdGhlIHVzZXIgcHJlZmVyZW5jZXNcbiAgICAgIGlmICghdXNlclNldHRpbmdzQ29uZmlnLmRlZmF1bHRWYWx1ZXMpIHtcbiAgICAgICAgdGhpcy5hc3Npc3RhbnRDb25maWckLm5leHQoey4uLnN0YW5kYXJkQ2hhdENvbmZpZ30pO1xuICAgICAgICB0aGlzLmluaXRDb25maWckLm5leHQodHJ1ZSk7XG4gICAgICB9IGVsc2UgeyAvLyBJZiB0aGUgdXNlciBoYXMgaXRzIG93biBkZWZhdWx0VmFsdWVzIGluIGl0cyB1c2VyU2V0dGluZ3MsIHRoZW4gd2UgbmVlZCB0byBjaGVjayBmb3IgcG90ZW50aWFsIHVwZGF0ZXMgbWFkZSBieSBhZG1pbnMgaW4gdGhlIG1lYW50aW1lIGFuZCBob3cgaGUgd2FudHMgdG8gbWFuYWdlIHRoZW1cblxuICAgICAgICAvLyBSZXRyaWV2ZSBhbHJlYWR5IHN0b3JlZCBoYXNoZXMgaW4gdGhlIHVzZXIgc2V0dGluZ3MgaWYgZXhpc3RzXG4gICAgICAgIGNvbnN0IGFwcGxpZWREZWZhdWx0VmFsdWVzSGFzaCA9IHVzZXJTZXR0aW5nc0NvbmZpZy5oYXNoZXM/LltcImFwcGxpZWQtZGVmYXVsdFZhbHVlcy1oYXNoXCJdO1xuICAgICAgICBjb25zdCBza2lwcGVkRGVmYXVsdFZhbHVlc0hhc2ggPSB1c2VyU2V0dGluZ3NDb25maWcuaGFzaGVzPy5bXCJza2lwcGVkLWRlZmF1bHRWYWx1ZXMtaGFzaFwiXTtcbiAgICAgICAgLy8gQ3JlYXRlIGEgaGFzaCBvZiB0aGUgY3VycmVudCBkZWZhdWx0VmFsdWVzIG9mIHRoZSBzdGFuZGFyZENoYXRDb25maWdcbiAgICAgICAgY29uc3QgY3VycmVudERlZmF1bHRWYWx1ZXNIYXNoID0gVXRpbHMuc2hhNTEyKEpTT04uc3RyaW5naWZ5KHN0YW5kYXJkQ2hhdENvbmZpZy5kZWZhdWx0VmFsdWVzKSk7XG5cbiAgICAgICAgLy8gSW1wbGVtZW50IHRoZSB0cmFja2luZyBtZWNoYW5pc20gdG8gbm90aWZ5IHRoZSB1c2VyIGFib3V0IHRoZSBhdmFpbGFibGUgdXBkYXRlcyBpbiB0aGUgZGVmYXVsdFZhbHVlcyBvYmplY3Qgb2YgdGhlIHN0YW5kYXJkIGFwcCBjb25maWdcbiAgICAgICAgY29uc3QgY29uZGl0aW9uID0gKGN1cnJlbnREZWZhdWx0VmFsdWVzSGFzaCAhPT0gYXBwbGllZERlZmF1bHRWYWx1ZXNIYXNoKSAmJiAoY3VycmVudERlZmF1bHRWYWx1ZXNIYXNoICE9PSBza2lwcGVkRGVmYXVsdFZhbHVlc0hhc2gpO1xuICAgICAgICBpZiAoY29uZGl0aW9uKSB7XG4gICAgICAgICAgdGhpcy5tb2RhbFNlcnZpY2VcbiAgICAgICAgICAgIC5jb25maXJtKHtcbiAgICAgICAgICAgICAgdGl0bGU6IFwiQXZhaWxhYmxlIHVwZGF0ZXMgIVwiLFxuICAgICAgICAgICAgICBtZXNzYWdlOiBcIkNoYW5nZXMgaGF2ZSBiZWVuIG1hZGUgdG8gdGhlIGRlZmF1bHQgY29uZmlndXJhdGlvbi4gRG8geW91IHdhbnQgdG8gdXBkYXRlIHlvdXIgb3duIHZlcnNpb24gP1wiLFxuICAgICAgICAgICAgICBidXR0b25zOiBbXG4gICAgICAgICAgICAgICAgICBuZXcgTW9kYWxCdXR0b24oe3Jlc3VsdDogTW9kYWxSZXN1bHQuTm8sIHRleHQ6IFwiU2VlIG5vIG1vcmVcIn0pLFxuICAgICAgICAgICAgICAgICAgbmV3IE1vZGFsQnV0dG9uKHtyZXN1bHQ6IE1vZGFsUmVzdWx0Lklnbm9yZSwgdGV4dDogXCJSZW1pbmQgbWUgbGF0ZXJcIn0pLFxuICAgICAgICAgICAgICAgICAgbmV3IE1vZGFsQnV0dG9uKHtyZXN1bHQ6IE1vZGFsUmVzdWx0Lk9LLCB0ZXh0OiBcIlVwZGF0ZVwiLCBwcmltYXJ5OiB0cnVlfSlcbiAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgICAgY29uZmlybVR5cGU6IENvbmZpcm1UeXBlLldhcm5pbmdcbiAgICAgICAgICAgIH0pLnRoZW4ocmVzID0+IHtcbiAgICAgICAgICAgICAgICBpZihyZXMgPT09IE1vZGFsUmVzdWx0Lk9LKSB7XG4gICAgICAgICAgICAgICAgICBjb25zdCBoYXNoZXMgPSB7IC4uLnVzZXJTZXR0aW5nc0NvbmZpZy5oYXNoZXMsIFwiYXBwbGllZC1kZWZhdWx0VmFsdWVzLWhhc2hcIjogY3VycmVudERlZmF1bHRWYWx1ZXNIYXNoLCBcInNraXBwZWQtZGVmYXVsdFZhbHVlcy1oYXNoXCI6IHVuZGVmaW5lZCB9O1xuICAgICAgICAgICAgICAgICAgLy8gVXBkYXRlIHRoZSBjaGF0IGNvbmZpZyBhbmQgc3RvcmUgaXRzIGRlZmF1bHRWYWx1ZXMgaW4gdGhlIHVzZXIgcHJlZmVyZW5jZXNcbiAgICAgICAgICAgICAgICAgIHRoaXMudXBkYXRlQ2hhdENvbmZpZyh7Li4uc3RhbmRhcmRDaGF0Q29uZmlnfSwgaGFzaGVzLCB0cnVlKTtcbiAgICAgICAgICAgICAgICAgIHRoaXMuaW5pdENvbmZpZyQubmV4dCh0cnVlKTtcbiAgICAgICAgICAgICAgICAgIHRoaXMuZ2VuZXJhdGVBdWRpdEV2ZW50KFwiY29uZmlndXJhdGlvbi5lZGl0XCIsIHsgJ2NvbmZpZ3VyYXRpb24nOiBKU09OLnN0cmluZ2lmeSh7Li4uc3RhbmRhcmRDaGF0Q29uZmlnfSkgfSk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmKHJlcyA9PT0gTW9kYWxSZXN1bHQuTm8pIHtcbiAgICAgICAgICAgICAgICAgIC8vIERvIG5vdCBub3RpZnkgdGhlIHVzZXIgYWJvdXQgY2hhbmdlcyB3aGlsZSB0aGlzIHNraXBwZWQgdmVyc2lvbiBpcyBub3QgdXBkYXRlZFxuICAgICAgICAgICAgICAgICAgY29uc3QgaGFzaGVzID0geyAuLi51c2VyU2V0dGluZ3NDb25maWcuaGFzaGVzLCBcInNraXBwZWQtZGVmYXVsdFZhbHVlcy1oYXNoXCI6IGN1cnJlbnREZWZhdWx0VmFsdWVzSGFzaCB9O1xuICAgICAgICAgICAgICAgICAgdGhpcy51cGRhdGVDaGF0Q29uZmlnKHsuLi5zdGFuZGFyZENoYXRDb25maWcsIGRlZmF1bHRWYWx1ZXM6IHVzZXJTZXR0aW5nc0NvbmZpZy5kZWZhdWx0VmFsdWVzfSwgaGFzaGVzLCBmYWxzZSk7XG4gICAgICAgICAgICAgICAgICB0aGlzLmluaXRDb25maWckLm5leHQodHJ1ZSk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgIC8vIEp1c3QgcGljayB0aGUgdmVyc2lvbiBpbiB0aGUgdXNlciBzZXR0aW5ncywgbm90aGluZyB0byBiZSB1cGRhdGVkXG4gICAgICAgICAgICAgICAgICB0aGlzLmFzc2lzdGFudENvbmZpZyQubmV4dCh7Li4uc3RhbmRhcmRDaGF0Q29uZmlnLCBkZWZhdWx0VmFsdWVzOiB1c2VyU2V0dGluZ3NDb25maWcuZGVmYXVsdFZhbHVlc30pO1xuICAgICAgICAgICAgICAgICAgdGhpcy5pbml0Q29uZmlnJC5uZXh0KHRydWUpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2UgeyAvLyBObyBhdmFpbGFibGUgdXBkYXRlcyBPciB1cGRhdGVzIGhhcyBiZWVuIGFscmVhZHkgc2tpcHBlZCwgdGhlbiBqdXN0IHBpY2sgdGhlIHZlcnNpb24gaW4gdGhlIHVzZXIgc2V0dGluZ3NcbiAgICAgICAgICB0aGlzLmFzc2lzdGFudENvbmZpZyQubmV4dCh7Li4uc3RhbmRhcmRDaGF0Q29uZmlnLCBkZWZhdWx0VmFsdWVzOiB1c2VyU2V0dGluZ3NDb25maWcuZGVmYXVsdFZhbHVlc30pO1xuICAgICAgICAgIHRoaXMuaW5pdENvbmZpZyQubmV4dCh0cnVlKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICB0aGlzLm5vdGlmaWNhdGlvbnNTZXJ2aWNlLmVycm9yKGBNaXNzaW5nIHZhbGlkIGNvbmZpZ3VyYXRpb24gZm9yIHRoZSBhc3Npc3RhbnQgaW5zdGFuY2UgJyR7a2V5fScuIFNlZSB0aGUgYnJvd3NlciBjb25zb2xlIG1lc3NhZ2VzIGZvciBkZXRhaWxzIG9uIHRoZSBtaXNzaW5nIG9yIGluY29ycmVjdCBwcm9wZXJ0aWVzLmApO1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBNaXNzaW5nIHZhbGlkIGNvbmZpZ3VyYXRpb24gZm9yIHRoZSBhc3Npc3RhbnQgaW5zdGFuY2UgJyR7a2V5fScgLiBcXG4gJHtKU09OLnN0cmluZ2lmeShlcnJvci5pc3N1ZXMsIG51bGwsIDIpfWApO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBVcGRhdGUgdGhlIGNoYXQgY29uZmlnIGFuZCBzdG9yZSBpdHMgZGVmYXVsdFZhbHVlcyBpbiB0aGUgdXNlciBwcmVmZXJlbmNlc1xuICAgKiBAcGFyYW0gY29uZmlnICBUaGUgdXBkYXRlZCBjaGF0IGNvbmZpZ1xuICAgKiBAcGFyYW0gaGFzaGVzICBUaGUgdXBkYXRlZCBoYXNoZXMgdG8gc3RvcmUgaW4gdGhlIHVzZXIgcHJlZmVyZW5jZXNcbiAgICogQHBhcmFtIG5vdGlmeSAgV2hldGhlciB0byBub3RpZnkgdGhlIHVzZXIgYWJvdXQgdGhlIHVwZGF0ZVxuICAgKiBAcGFyYW0gc3VjY2Vzc0NhbGxiYWNrICBUaGUgY2FsbGJhY2sgdG8gZXhlY3V0ZSBpZiB0aGUgdXBkYXRlIGlzIHN1Y2Nlc3NmdWxcbiAgICogQHBhcmFtIGVycm9yQ2FsbGJhY2sgIFRoZSBjYWxsYmFjayB0byBleGVjdXRlIGlmIHRoZSB1cGRhdGUgZmFpbHNcbiAgICovXG4gIHVwZGF0ZUNoYXRDb25maWcoY29uZmlnOiBDaGF0Q29uZmlnLCBoYXNoZXM/OiB7XCJhcHBsaWVkLWRlZmF1bHRWYWx1ZXMtaGFzaFwiPzogc3RyaW5nLCBcInNraXBwZWQtZGVmYXVsdFZhbHVlcy1oYXNoXCI/OiBzdHJpbmd9LCAgbm90aWZ5ID0gdHJ1ZSwgc3VjY2Vzc0NhbGxiYWNrPzogKCkgPT4gYW55LCBlcnJvckNhbGxiYWNrPzogKCkgPT4gYW55KSB7XG4gICAgdGhpcy5hc3Npc3RhbnRDb25maWckLm5leHQoY29uZmlnKTtcbiAgICBjb25zdCBhc3Npc3RhbnRzID0gT2JqZWN0LmFzc2lnbih7fSwgdGhpcy5hc3Npc3RhbnRzKTtcbiAgICBhc3Npc3RhbnRzW3RoaXMuY2hhdEluc3RhbmNlSWRdID0geyAuLi5hc3Npc3RhbnRzW3RoaXMuY2hhdEluc3RhbmNlSWRdLCBkZWZhdWx0VmFsdWVzOiBjb25maWcuZGVmYXVsdFZhbHVlcyB9O1xuICAgIGlmKGhhc2hlcykgYXNzaXN0YW50c1t0aGlzLmNoYXRJbnN0YW5jZUlkXS5oYXNoZXMgPSBoYXNoZXM7XG4gICAgdGhpcy51c2VyU2V0dGluZ3NTZXJ2aWNlLnBhdGNoKHsgYXNzaXN0YW50cyB9KS5zdWJzY3JpYmUoXG4gICAgICBuZXh0ID0+IHt9LFxuICAgICAgZXJyb3IgPT4ge1xuICAgICAgICBpZihub3RpZnkpIHtcbiAgICAgICAgICBlcnJvckNhbGxiYWNrID8gZXJyb3JDYWxsYmFjaygpIDogdGhpcy5ub3RpZmljYXRpb25zU2VydmljZS5lcnJvcihgVGhlIHVwZGF0ZSBvZiB0aGUgYXNzaXN0YW50IGluc3RhbmNlICcke3RoaXMuY2hhdEluc3RhbmNlSWR9JyBjb25maWd1cmF0aW9uIGZhaWxlZGApO1xuICAgICAgICB9XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoXCJDb3VsZCBub3QgcGF0Y2ggYXNzaXN0YW50cyFcIiwgZXJyb3IpO1xuICAgICAgfSxcbiAgICAgICgpID0+IHtcbiAgICAgICAgaWYobm90aWZ5KSB7XG4gICAgICAgICAgc3VjY2Vzc0NhbGxiYWNrID8gc3VjY2Vzc0NhbGxiYWNrKCkgOiB0aGlzLm5vdGlmaWNhdGlvbnNTZXJ2aWNlLnN1Y2Nlc3MoYFRoZSBhc3Npc3RhbnQgaW5zdGFuY2UgJyR7dGhpcy5jaGF0SW5zdGFuY2VJZH0nIGNvbmZpZ3VyYXRpb24gaGFzIGJlZW4gc3VjY2Vzc2Z1bGx5IHVwZGF0ZWRgKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogT3ZlcnJpZGVzIHRoZSBsb2dnZWQgaW4gdXNlclxuICAgKi9cbiAgYWJzdHJhY3Qgb3ZlcnJpZGVVc2VyKCk6IHZvaWQ7XG5cbiAgLyoqXG4gICAqIENhbGxzIHRoZSBGZXRjaCBBUEkgdG8gcmV0cmlldmUgYSBuZXcgbWVzc2FnZSBnaXZlbiBhbGwgcHJldmlvdXMgbWVzc2FnZXNcbiAgICovXG4gIGFic3RyYWN0IGZldGNoKG1lc3NhZ2VzOiBDaGF0TWVzc2FnZVtdLCBxdWVyeTogUXVlcnkpOiBPYnNlcnZhYmxlPENoYXRSZXNwb25zZT5cblxuICAvKipcbiAgICogUmV0dXJuIHRoZSBsaXN0IG9mIG1vZGVscyBhdmFpbGFibGUgb24gdGhlIHNlcnZlclxuICAgKi9cbiAgYWJzdHJhY3QgbGlzdE1vZGVscygpOiBPYnNlcnZhYmxlPEdsbG1Nb2RlbERlc2NyaXB0aW9uW10gfCB1bmRlZmluZWQ+O1xuXG4gIC8qKlxuICAgKiBSZXR1cm4gdGhlIGxpc3Qgb2YgZnVuY3Rpb25zIGF2YWlsYWJsZSBvbiB0aGUgc2VydmVyIEFORCBtYXRjaGluZyBlbmFibGVkIGZ1bmN0aW9ucyBpbiB0aGUgY2hhdCBjb25maWdcbiAgICovXG4gIGFic3RyYWN0IGxpc3RGdW5jdGlvbnMoKTogT2JzZXJ2YWJsZTxHbGxtRnVuY3Rpb25bXSB8IHVuZGVmaW5lZD47XG5cbiAgLyoqXG4gICAqIFN0b3BzIHRoZSBhc3Npc3RhbnQgYW5zd2VyIGdlbmVyYXRpb24gYW5kIGNhbmNlbHMgYWxsIHRoZSBvbmdvaW5nIGFuZCBwZW5kaW5nIHJlbGF0ZWQgdGFza3NcbiAgICovXG4gIGFic3RyYWN0IHN0b3BHZW5lcmF0aW9uKCk6IE9ic2VydmFibGU8YW55PlxuXG4gIC8qKlxuICAgKiBBIGhhbmRsZXIgZm9yIHF1b3RhIHVwZGF0ZXMgZWFjaCB0aW1lIHRoZSBjaGF0IGlzIGludm9rZWQuXG4gICAqIEl0IGVtaXRzIHRoZSB1cGRhdGVkIHF1b3RhIHRvIHRoZSBxdW90YSQgc3ViamVjdCwgZW1pdHMgYWNjb3JkaW5nbHkgdGhlIHVwZGF0ZWQgdXNlcidzIHRva2VucyBjb25zdW1wdGlvbiBhbmQgbm90aWZpZXMgdGhlIHVzZXIgaWYgdGhlIG1heCBxdW90YSBpcyByZWFjaGVkLlxuICAgKiBAcGFyYW0gcXVvdGEgVGhlIHVwZGF0ZWQgcXVvdGFcbiAgICogQHBhcmFtIHByb3BhZ2F0ZUVycm9yIFdoZXRoZXIgdG8gcHJvcGFnYXRlIHRoZSBlcnJvciB0byB0aGUgY2FsbGVyXG4gICAqL1xuICB1cGRhdGVRdW90YShxdW90YTogUXVvdGEsIHByb3BhZ2F0ZUVycm9yID0gZmFsc2UpIHtcbiAgICB0aGlzLnF1b3RhJC5uZXh0KHF1b3RhKTtcbiAgICBjb25zdCBuZXh0UmVzZXREYXRlID0gdGhpcy5mb3JtYXREYXRlVGltZShxdW90YS5uZXh0UmVzZXRVVEMrXCIrMDA6MDBcIik7IC8vIFRoaXMgKzAwOjAwIGlzIHRvIGVuc3VyZSBkYXRlcyB3aWxsIGJlIHByb3Blcmx5IGNvbnZlcnRlZCB0byBsb2NhbCB0aW1lXG4gICAgY29uc3QgY29uc3VtcHRpb25QZXJjZW50YWdlID0gTWF0aC5yb3VuZCgocXVvdGEudG9rZW5Db3VudCAqIDEwMCAvIHF1b3RhLnBlcmlvZFRva2VucykgKiAxMDApIC8gMTAwO1xuICAgIHRoaXMudXNlclRva2VuQ29uc3VtcHRpb24kLm5leHQoe3BlcmNlbnRhZ2U6IGNvbnN1bXB0aW9uUGVyY2VudGFnZSwgbmV4dFJlc2V0RGF0ZX0pO1xuICAgIGlmKHF1b3RhLm1heFF1b3RhUmVhY2hlZCkge1xuICAgICAgdGhpcy5nZW5lcmF0ZUF1ZGl0RXZlbnQoJ3F1b3RhLmV4Y2VlZGVkJywge30pO1xuICAgICAgY29uc3QgbXNnID0gYFNvcnJ5LCB5b3UgaGF2ZSBleGNlZWRlZCB0aGUgYWxsb3dlZCBxdW90YS4gUGxlYXNlIHJldHJ5IHN0YXJ0aW5nIGZyb20gJHtuZXh0UmVzZXREYXRlfS5gO1xuICAgICAgdGhpcy5ub3RpZmljYXRpb25zU2VydmljZS5lcnJvcihtc2cpO1xuICAgICAgaWYocHJvcGFnYXRlRXJyb3IpIHRocm93IG5ldyBFcnJvcihtc2cpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBBIGhhbmRsZXIgZm9yIGNoYXQgdXNhZ2UgbWV0cmljcyBlYWNoIHRpbWUgdGhlIGdlbmVyYXRpb24gb2YgdGhlIGFzc2lzdGFudCByZXNwb25zZSBpcyBjb21wbGV0ZWQuXG4gICAqIEl0IGVtaXRzIHRoZSBjaGF0IHVzYWdlIG1ldHJpY3MgdG8gdGhlIGNoYXRVc2FnZU1ldHJpY3MkIHN1YmplY3QsIGVtaXRzIGFjY29yZGluZ2x5IHRoZSB1cGRhdGVkIGNoYXQncyB0b2tlbnMgY29uc3VtcHRpb25cbiAgICogQHBhcmFtIGNoYXRVc2FnZU1ldHJpY3MgVGhlIGNoYXQgdXNhZ2UgbWV0cmljc1xuICAgKi9cbiAgdXBkYXRlQ2hhdFVzYWdlTWV0cmljcyhjaGF0VXNhZ2VNZXRyaWNzOiBDaGF0VXNhZ2VNZXRyaWNzKSB7XG4gICAgdGhpcy5jaGF0VXNhZ2VNZXRyaWNzJC5uZXh0KGNoYXRVc2FnZU1ldHJpY3MpO1xuICAgIGNvbnN0IGN1cnJlbnRNb2RlbCA9IHRoaXMuZ2V0TW9kZWwodGhpcy5hc3Npc3RhbnRDb25maWckLnZhbHVlIS5kZWZhdWx0VmFsdWVzLnNlcnZpY2VfaWQsIHRoaXMuYXNzaXN0YW50Q29uZmlnJC52YWx1ZSEuZGVmYXVsdFZhbHVlcy5tb2RlbF9pZCk7XG4gICAgY29uc3QgY29uc3VtcHRpb25QZXJjZW50YWdlID0gTWF0aC5yb3VuZCgoY2hhdFVzYWdlTWV0cmljcy50b3RhbFRva2VuQ291bnQgKiAxMDAgLyAoY3VycmVudE1vZGVsIS5jb250ZXh0V2luZG93U2l6ZSAtIGN1cnJlbnRNb2RlbCEubWF4R2VuZXJhdGlvblNpemUpKSAqIDEwMCkgLyAxMDA7XG4gICAgdGhpcy5jaGF0VG9rZW5Db25zdW1wdGlvbiQubmV4dCh7cGVyY2VudGFnZTogY29uc3VtcHRpb25QZXJjZW50YWdlfSk7XG4gIH1cblxuICAvKipcbiAgICogR2V0IHRoZSBtb2RlbCBkZXNjcmlwdGlvbiBmb3IgdGhlIGdpdmVuIChzZXJ2aWNlSWQgKyBtb2RlbElkKVxuICAgKiBJZiBhIG1vZGVsIGlzIG5vdCBmb3VuZCwgYW4gZXJyb3IgbWVzc2FnZSBpcyByZXR1cm5lZFxuICAgKiBAcGFyYW0gc2VydmljZUlkIFRoZSBzZXJ2aWNlSWQgb2YgdGhlIG1vZGVsXG4gICAqIEBwYXJhbSBtb2RlbElkIFRoZSBtb2RlbElkIG9mIHRoZSBtb2RlbFxuICAgKiBAcmV0dXJucyBUaGUgbW9kZWwgZGVzY3JpcHRpb25cbiAgICovXG4gIGdldE1vZGVsKHNlcnZpY2VJZDogc3RyaW5nLCBtb2RlbElkOiBzdHJpbmcpOiBHbGxtTW9kZWxEZXNjcmlwdGlvbiB8IHVuZGVmaW5lZHtcbiAgICBsZXQgbW9kZWwgPSB0aGlzLm1vZGVscz8uZmluZChtID0+IG0uc2VydmljZUlkID09PSBzZXJ2aWNlSWQgJiYgbS5tb2RlbElkID09PSBtb2RlbElkKTtcbiAgICAvLyBIYW5kbGUgb2Jzb2xldGUgY29uZmlnXG4gICAgaWYoIW1vZGVsKSB7XG4gICAgICB0aGlzLm5vdGlmaWNhdGlvbnNTZXJ2aWNlLmVycm9yKGBGQVRBTCBFUlJPUiA6IFRoZSBtb2RlbCAoc2VydmljZUlkID0gJyR7c2VydmljZUlkfScsIG1vZGVsSWQgPSAnJHttb2RlbElkfScpIGlzIG5vIGxvbmdlciBhdmFpbGFibGUuIFBsZWFzZSBjb250YWN0IGFuIGFkbWluIGZvciBmdXJ0aGVyIGluZm9ybWF0aW9uLmApO1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBGQVRBTCBFUlJPUiA6IFRoZSBtb2RlbCAoc2VydmljZUlkID0gJyR7c2VydmljZUlkfScsIG1vZGVsSWQgPSAnJHttb2RlbElkfScpIGlzIG5vIGxvbmdlciBhdmFpbGFibGVgKTtcbiAgICB9XG4gICAgcmV0dXJuIG1vZGVsO1xuICB9XG5cbiAgLyoqXG4gICAqIEZldGNoIHRoZSBsaXN0IHNhdmVkIGNoYXRzIGJlbG9uZ2luZyB0byBhIHNwZWNpZmljIGluc3RhbmNlIG9mIHRoZSBhc3Npc3RhbnRcbiAgICovXG4gIGFic3RyYWN0IGxpc3RTYXZlZENoYXQoKTogdm9pZDtcblxuICAvKipcbiAgICogUmV0dXJuIHRoZSBzYXZlZCBjaGF0IHdpdGggdGhlIGdpdmVuIGlkLCBpZiBleGlzdHMuIE90aGVyd2lzZSwgcmV0dXJuIHVuZGVmaW5lZFxuICAgKiBAcGFyYW0gaWQgVGhlIGlkIG9mIHRoZSBzYXZlZCBjaGF0XG4gICAqL1xuICBhYnN0cmFjdCBnZXRTYXZlZENoYXQoaWQ6IHN0cmluZyk6IE9ic2VydmFibGU8U2F2ZWRDaGF0SGlzdG9yeSB8IHVuZGVmaW5lZD47XG5cbiAgLyoqXG4gICAqIFNhdmUgYSBjaGF0IHdpdGggdGhlIGdpdmVuIG1lc3NhZ2VzXG4gICAqIEBwYXJhbSBtZXNzYWdlcyBUaGUgbWVzc2FnZXMgdG8gYWRkIHRvIHRoZSBzYXZlZCBjaGF0IGluZGV4XG4gICAqIEByZXR1cm5zIFRoZSBzYXZlZCBjaGF0XG4gICAqL1xuICBhYnN0cmFjdCBhZGRTYXZlZENoYXQobWVzc2FnZXM6IENoYXRNZXNzYWdlW10pOiBPYnNlcnZhYmxlPFNhdmVkQ2hhdD47XG5cbiAgLyoqXG4gICAqIFVwZGF0ZSBhIHNhdmVkIGNoYXQgd2l0aCB0aGUgZ2l2ZW4gaWQuXG4gICAqIEBwYXJhbSBpZCBUaGUgaWQgb2YgdGhlIHNhdmVkIGNoYXRcbiAgICogQHBhcmFtIG5hbWUgVGhlIG5ldyBuYW1lIG9mIHRoZSBzYXZlZCBjaGF0LCBpZiBwcm92aWRlZFxuICAgKiBAcGFyYW0gbWVzc2FnZXMgVGhlIG1lc3NhZ2VzIHRvIHVwZGF0ZSB0aGUgc2F2ZWQgY2hhdCBoaXN0b3J5LCBpZiBwcm92aWRlZFxuICAgKiBAcmV0dXJucyBUcnVlIGlmIHRoZSBzYXZlZCBjaGF0IGhhcyBiZWVuIHN1Y2Nlc3NmdWxseSB1cGRhdGVkXG4gICAqL1xuICBhYnN0cmFjdCB1cGRhdGVTYXZlZENoYXQoaWQ6IHN0cmluZywgbmFtZT86IHN0cmluZywgbWVzc2FnZXM/OiBDaGF0TWVzc2FnZVtdKTogT2JzZXJ2YWJsZTxTYXZlZENoYXQ+O1xuXG4gIC8qKlxuICAgKiBCdWxrIGRlbGV0ZSBvZiBzYXZlZCBjaGF0cyBtYXRjaGluZyB0aGUgZ2l2ZW4gaWRzXG4gICAqIEBwYXJhbSBpZHMgTGlzdCBvZiBpZHMgb2YgdGhlIHNhdmVkIGNoYXRzIHRvIGRlbGV0ZVxuICAgKiBAcmV0dXJucyBUaGUgbnVtYmVyIG9mIGRlbGV0ZWQgY2hhdHNcbiAgICovXG4gIGFic3RyYWN0IGRlbGV0ZVNhdmVkQ2hhdChpZHM6IHN0cmluZ1tdKTogT2JzZXJ2YWJsZTxudW1iZXI+O1xuXG4gIC8qKlxuICAgKiBHZW5lcmF0ZSBhbiBhdWRpdCBldmVudCB3aXRoIHRoZSBnaXZlbiB0eXBlIGFuZCBkZXRhaWxzLiBUaGUgZ2VuZXJhdGVkIGF1ZGl0IGV2ZW50IGlzIHNlbnQgYWZ0ZXJ3YXJkcyB2aWEgdGhlIEF1ZGl0V2ViU2VydmljZVxuICAgKiBAcGFyYW0gdHlwZSBBdWRpdCBldmVudCB0eXBlXG4gICAqIEBwYXJhbSBkZXRhaWxzIEF1ZGl0IGV2ZW50IGRldGFpbHNcbiAgICogQHBhcmFtIGlkIEFjdGlvbnMgKHNhdmVkQ2hhdCBkZWxldGUvcmVuYW1lLy4uLikgbWF5IG9jY3VyIG9uIGEgc3BlY2lmaWMgY2hhdCBkaWZmZXJlbnQgdGhhbiB0aGUgY3VycmVudCBvbmUgc3RvcmVkIGluIHRoaXMgc2VydmljZSwgc28gdGhlIGNoYXQgaWQgY2FuIGJlIHByb3ZpZGVkXG4gICAqL1xuICBnZW5lcmF0ZUF1ZGl0RXZlbnQodHlwZTogc3RyaW5nLCBkZXRhaWxzOiBSZWNvcmQ8c3RyaW5nLCBhbnk+LCBpZD86IHN0cmluZyk6IHZvaWQge1xuICAgIGNvbnN0IGJhc2VEZXRhaWxzID0ge1xuICAgICAgXCJ1cmxcIjogZGVjb2RlVVJJQ29tcG9uZW50KHdpbmRvdy5sb2NhdGlvbi5ocmVmKSxcbiAgICAgIFwiYXBwXCI6IHRoaXMuYXBwU2VydmljZS5hcHBOYW1lLFxuICAgICAgXCJ1c2VyLWlkXCI6IHRoaXMucHJpbmNpcGFsU2VydmljZS5wcmluY2lwYWw/LnVzZXJJZCxcbiAgICAgIFwiaW5zdGFuY2UtaWRcIjogdGhpcy5jaGF0SW5zdGFuY2VJZCxcbiAgICAgIFwiY2hhdC1pZFwiOiBpZCB8fCB0aGlzLmNoYXRJZCxcbiAgICAgIFwic2VydmljZS1pZFwiOiB0aGlzLmFzc2lzdGFudENvbmZpZyQudmFsdWUhLmRlZmF1bHRWYWx1ZXMuc2VydmljZV9pZCxcbiAgICAgIFwibW9kZWwtaWRcIjogdGhpcy5hc3Npc3RhbnRDb25maWckLnZhbHVlIS5kZWZhdWx0VmFsdWVzLm1vZGVsX2lkLFxuICAgIH07XG4gICAgY29uc3QgYXVkaXQgPSB7XG4gICAgICB0eXBlLFxuICAgICAgZGV0YWlsOiB7XG4gICAgICAgIC4uLmJhc2VEZXRhaWxzLFxuICAgICAgICAuLi5kZXRhaWxzXG4gICAgICB9XG4gICAgfVxuICAgIHRoaXMuYXVkaXRTZXJ2aWNlLm5vdGlmeShhdWRpdCk7XG4gIH1cblxuXG5cbiAgLyoqXG4gICAqIFRyYXZlcnNlIHRoZSBhcnJheSBmcm9tIHRoZSBlbmQgYW5kIHRyYWNrIHRoZSBmaXJzdCAnYXNzaXN0YW50JyBtZXNzYWdlIGFtb25nIHRoZSBsYXN0IGdyb3VwIG9mIFwiYXNzaXN0YW50XCIgbWVzc2FnZXMgd2hlcmUgZGlzcGxheSBpcyB0cnVlXG4gICAqIEBwYXJhbSBhcnJheSBUaGUgYXJyYXkgb2YgQ2hhdE1lc3NhZ2UgdG8gdHJhdmVyc2VcbiAgICogQHJldHVybnMgVGhlIGluZGV4IG9mIHRoZSBmaXJzdCB2aXNpYmxlIGFzc2lzdGFudCBtZXNzYWdlIGFtb25nIHRoZSBsYXN0IGdyb3VwIG9mIFwiYXNzaXN0YW50XCIgbWVzc2FnZXMgaW4gdGhlIGFycmF5XG4gICAqL1xuICBmaXJzdFZpc2libGVBc3Npc3RhbnRNZXNzYWdlSW5kZXgoYXJyYXk6IENoYXRNZXNzYWdlW118IHVuZGVmaW5lZCk6IG51bWJlciB7XG4gICAgaWYgKCFhcnJheSkge1xuICAgICAgcmV0dXJuIC0xO1xuICAgIH1cbiAgICBsZXQgaW5kZXggPSBhcnJheS5sZW5ndGggLSAxO1xuICAgIGxldCBmaXJzdFZpc2libGVBc3Npc3RhbnRNZXNzYWdlSW5kZXggPSAtMTtcbiAgICB3aGlsZSAoaW5kZXggPj0gMCAmJiBhcnJheVtpbmRleF0ucm9sZSA9PT0gJ2Fzc2lzdGFudCcpIHtcbiAgICAgIGlmIChhcnJheVtpbmRleF0uYWRkaXRpb25hbFByb3BlcnRpZXMuZGlzcGxheSA9PT0gdHJ1ZSkge1xuICAgICAgICBmaXJzdFZpc2libGVBc3Npc3RhbnRNZXNzYWdlSW5kZXggPSBpbmRleDtcbiAgICAgIH1cbiAgICAgIGluZGV4LS07XG4gICAgfVxuICAgIHJldHVybiBmaXJzdFZpc2libGVBc3Npc3RhbnRNZXNzYWdlSW5kZXg7XG4gIH1cblxuICAvKipcbiAgICogVHJhdmVyc2UgdGhlIGFycmF5IGZyb20gdGhlIGVuZCBhbmQgcGljayB0aGUgbGFzdCAnYXNzaXN0YW50JyBtZXNzYWdlIGFtb25nIHRoZSBsYXN0IGdyb3VwIG9mIFwiYXNzaXN0YW50XCIgbWVzc2FnZXMgd2hlcmUgZGlzcGxheSBpcyB0cnVlXG4gICAqIEBwYXJhbSBhcnJheSBUaGUgYXJyYXkgb2YgQ2hhdE1lc3NhZ2UgdG8gdHJhdmVyc2VcbiAgICogQHJldHVybnMgVGhlIGluZGV4IG9mIHRoZSBsYXN0IHZpc2libGUgYXNzaXN0YW50IG1lc3NhZ2UgYW1vbmcgdGhlIGxhc3QgZ3JvdXAgb2YgXCJhc3Npc3RhbnRcIiBtZXNzYWdlcyBpbiB0aGUgYXJyYXlcbiAgICovXG4gIGxhc3RWaXNpYmxlQXNzaXN0YW50TWVzc2FnZUluZGV4KGFycmF5OiBDaGF0TWVzc2FnZVtdfCB1bmRlZmluZWQpOiBudW1iZXIge1xuICAgIGlmICghYXJyYXkpIHtcbiAgICAgIHJldHVybiAtMTtcbiAgICB9XG4gICAgbGV0IGluZGV4ID0gYXJyYXkubGVuZ3RoIC0gMTtcbiAgICBsZXQgbGFzdFZpc2libGVBc3Npc3RhbnRNZXNzYWdlSW5kZXggPSAtMTtcbiAgICB3aGlsZSAoaW5kZXggPj0gMCAmJiBhcnJheVtpbmRleF0ucm9sZSA9PT0gJ2Fzc2lzdGFudCcpIHtcbiAgICAgIGlmIChhcnJheVtpbmRleF0uYWRkaXRpb25hbFByb3BlcnRpZXMuZGlzcGxheSA9PT0gdHJ1ZSkge1xuICAgICAgICBsYXN0VmlzaWJsZUFzc2lzdGFudE1lc3NhZ2VJbmRleCA9IGluZGV4O1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICAgIGluZGV4LS07XG4gICAgfVxuICAgIHJldHVybiBsYXN0VmlzaWJsZUFzc2lzdGFudE1lc3NhZ2VJbmRleDtcbiAgfVxuXG4gIC8qKlxuICAgKiBGb3JtYXQgYSBkYXRlIHN0cmluZyBpbiBVVEMgdG8gYSBsb2NhbCBkYXRlIHN0cmluZ1xuICAgKiBAcGFyYW0gdmFsdWUgRGF0ZSBzdHJpbmcgaW4gVVRDIHRvIGZvcm1hdFxuICAgKiBAcmV0dXJucyBBIGZvcm1hdHRlZCBsb2NhbCBkYXRlIHN0cmluZ1xuICAgKi9cbiAgcHJvdGVjdGVkIGZvcm1hdERhdGVUaW1lKHZhbHVlOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIGNvbnN0IGxvY2FsRGF0ZSA9IHRvRGF0ZShwYXJzZUlTTyh2YWx1ZSkpO1xuICAgIHJldHVybiB0aGlzLmludGxTZXJ2aWNlW1wiZm9ybWF0VGltZVwiXShsb2NhbERhdGUsIHtkYXk6IFwibnVtZXJpY1wiLCBtb250aDogXCJzaG9ydFwiLCB5ZWFyOiBcIm51bWVyaWNcIiwgdGltZVpvbmVOYW1lOiAnc2hvcnQnfSk7XG4gIH1cblxuICAvKipcbiAgICogVGFrZXMgYSB0ZXh0IHByb21wdCB0aGF0IG1heSBjb250YWluIHBsYWNlaG9sZGVycyBmb3IgdmFyaWFibGVzXG4gICAqIGFuZCByZXBsYWNlcyB0aGVzZSBwbGFjZWhvbGRlcnMgaWYgaXQgZmluZHMgYSBtYXRjaCBpbiB0aGUgZ2l2ZW5cbiAgICogY29udGV4dCBvYmplY3QuXG4gICAqL1xuICBzdGF0aWMgZm9ybWF0UHJvbXB0KHByb21wdDogc3RyaW5nLCBjb250ZXh0OiBhbnkpIHtcbiAgICByZXR1cm4gcHJvbXB0LnJlcGxhY2UoXG4gICAgICAve3soLio/KX19L2csXG4gICAgICAobWF0Y2gsIGV4cHIpID0+IGdldChjb250ZXh0LCBleHByKSA/PyBtYXRjaFxuICAgICk7XG4gIH1cblxufVxuIl19
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { CommonModule } from "@angular/common";
|
|
2
|
-
import { Component, Input } from "@angular/core";
|
|
3
|
-
import { Utils } from "@sinequa/core/base";
|
|
4
|
-
import * as Prism from 'prismjs';
|
|
5
|
-
import * as i0 from "@angular/core";
|
|
6
|
-
import * as i1 from "@sinequa/components/utils";
|
|
7
|
-
import * as i2 from "@angular/common";
|
|
8
|
-
export class DebugMessageComponent {
|
|
9
|
-
constructor(ui) {
|
|
10
|
-
this.ui = ui;
|
|
11
|
-
this.level = 0; // Track the nesting level
|
|
12
|
-
this.parentColor = ''; // Track the parent row color
|
|
13
|
-
}
|
|
14
|
-
ngAfterViewInit() {
|
|
15
|
-
Prism.highlightAll();
|
|
16
|
-
}
|
|
17
|
-
isObject(value) {
|
|
18
|
-
return Utils.isObject(value);
|
|
19
|
-
}
|
|
20
|
-
getRowClass(item, index) {
|
|
21
|
-
if (item.isError)
|
|
22
|
-
return 'row-error';
|
|
23
|
-
if (this.level === 0)
|
|
24
|
-
return index % 2 === 0 ? 'row-even' : 'row-odd';
|
|
25
|
-
return this.parentColor;
|
|
26
|
-
}
|
|
27
|
-
copyToClipboard(code) {
|
|
28
|
-
this.ui.copyToClipboard(JSON.stringify(code, null, 2));
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
DebugMessageComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: DebugMessageComponent, deps: [{ token: i1.UIService }], target: i0.ɵɵFactoryTarget.Component });
|
|
32
|
-
DebugMessageComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.6", type: DebugMessageComponent, isStandalone: true, selector: "sq-debug-message", inputs: { data: "data", level: "level", parentColor: "parentColor" }, ngImport: i0, template: "<div *ngIf=\"data\" class=\"table-root\">\n <ng-container *ngFor=\"let item of data; let i = index\">\n <div *ngIf=\"item.type === 'KV'\" [ngClass]=\"getRowClass(item, i)\" class=\"table-row kv-object\">\n <div class=\"kv-key\">{{ item.data.key }}</div>\n <div class=\"kv-value\">\n <ng-container *ngIf=\"isObject(item.data.value); else normalValue\">\n <div class=\"card mb-2\">\n <div class=\"card-header\">\n <button class=\"btn btn-light btn-sm\" (click)=\"copyToClipboard(item.data.value)\"><i class=\"far fa-fw fa-clipboard\"></i> Copy code</button>\n </div>\n <pre class=\"language-json my-0 rounded-0 rounded-bottom\"><code class=\"language-json\">{{ item.data.value | json }}</code></pre>\n </div>\n </ng-container>\n <ng-template #normalValue><div class=\"data-value\">{{ item.data.value }}</div></ng-template>\n </div>\n </div>\n <div *ngIf=\"item.type === 'LIST'\" [ngClass]=\"getRowClass(item, i)\" class=\"table-row list-object\">\n <div class=\"list-name w-100\" [class.fw-bold]=\"level === 0\" (click)=\"item.expanded=!item.expanded\">\n <i class=\"fas\" [class.fa-chevron-up]=\"item.expanded\" [class.fa-chevron-down]=\"!item.expanded\"></i>\n {{ item.name }}\n </div>\n <div class=\"list-items w-100\" *ngIf=\"item.expanded\">\n <sq-debug-message [data]=\"item.items\" [level]=\"level + 1\" [parentColor]=\"getRowClass(item, i)\"></sq-debug-message>\n </div>\n </div>\n </ng-container>\n</div>\n", styles: [".table-root{display:flex;flex-direction:column;border:1px solid #ccc;width:100%;border-spacing:0}.table-row{display:flex;width:100%}.list-name{width:15%;cursor:pointer}.list-items{width:85%}.kv-key,.kv-value,.list-name{padding:8px;border:1px solid #ccc;box-sizing:border-box;word-wrap:break-word}.kv-key{width:20%}.kv-value{width:80%}.kv-value .data-value{white-space:pre-line}.kv-object,.list-object{display:flex;flex:1}.list-object{flex-direction:column}.row-even{background-color:#fff}.row-odd{background-color:#f2f8fe}.row-error{background-color:#f08080}.table-row:not(:last-child){border-bottom:1px solid #ccc}.kv-key:last-child,.kv-value:last-child,.list-name:last-child{border-right:none}\n"], dependencies: [{ kind: "component", type: DebugMessageComponent, selector: "sq-debug-message", inputs: ["data", "level", "parentColor"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i2.JsonPipe, name: "json" }] });
|
|
33
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: DebugMessageComponent, decorators: [{
|
|
34
|
-
type: Component,
|
|
35
|
-
args: [{ selector: "sq-debug-message", standalone: true, imports: [CommonModule], template: "<div *ngIf=\"data\" class=\"table-root\">\n <ng-container *ngFor=\"let item of data; let i = index\">\n <div *ngIf=\"item.type === 'KV'\" [ngClass]=\"getRowClass(item, i)\" class=\"table-row kv-object\">\n <div class=\"kv-key\">{{ item.data.key }}</div>\n <div class=\"kv-value\">\n <ng-container *ngIf=\"isObject(item.data.value); else normalValue\">\n <div class=\"card mb-2\">\n <div class=\"card-header\">\n <button class=\"btn btn-light btn-sm\" (click)=\"copyToClipboard(item.data.value)\"><i class=\"far fa-fw fa-clipboard\"></i> Copy code</button>\n </div>\n <pre class=\"language-json my-0 rounded-0 rounded-bottom\"><code class=\"language-json\">{{ item.data.value | json }}</code></pre>\n </div>\n </ng-container>\n <ng-template #normalValue><div class=\"data-value\">{{ item.data.value }}</div></ng-template>\n </div>\n </div>\n <div *ngIf=\"item.type === 'LIST'\" [ngClass]=\"getRowClass(item, i)\" class=\"table-row list-object\">\n <div class=\"list-name w-100\" [class.fw-bold]=\"level === 0\" (click)=\"item.expanded=!item.expanded\">\n <i class=\"fas\" [class.fa-chevron-up]=\"item.expanded\" [class.fa-chevron-down]=\"!item.expanded\"></i>\n {{ item.name }}\n </div>\n <div class=\"list-items w-100\" *ngIf=\"item.expanded\">\n <sq-debug-message [data]=\"item.items\" [level]=\"level + 1\" [parentColor]=\"getRowClass(item, i)\"></sq-debug-message>\n </div>\n </div>\n </ng-container>\n</div>\n", styles: [".table-root{display:flex;flex-direction:column;border:1px solid #ccc;width:100%;border-spacing:0}.table-row{display:flex;width:100%}.list-name{width:15%;cursor:pointer}.list-items{width:85%}.kv-key,.kv-value,.list-name{padding:8px;border:1px solid #ccc;box-sizing:border-box;word-wrap:break-word}.kv-key{width:20%}.kv-value{width:80%}.kv-value .data-value{white-space:pre-line}.kv-object,.list-object{display:flex;flex:1}.list-object{flex-direction:column}.row-even{background-color:#fff}.row-odd{background-color:#f2f8fe}.row-error{background-color:#f08080}.table-row:not(:last-child){border-bottom:1px solid #ccc}.kv-key:last-child,.kv-value:last-child,.list-name:last-child{border-right:none}\n"] }]
|
|
36
|
-
}], ctorParameters: function () { return [{ type: i1.UIService }]; }, propDecorators: { data: [{
|
|
37
|
-
type: Input
|
|
38
|
-
}], level: [{
|
|
39
|
-
type: Input
|
|
40
|
-
}], parentColor: [{
|
|
41
|
-
type: Input
|
|
42
|
-
}] } });
|
|
43
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVidWctbWVzc2FnZS5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9hc3Npc3RhbnQvY2hhdC9kZWJ1Zy1tZXNzYWdlL2RlYnVnLW1lc3NhZ2UuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvYXNzaXN0YW50L2NoYXQvZGVidWctbWVzc2FnZS9kZWJ1Zy1tZXNzYWdlLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUMvQyxPQUFPLEVBQWtCLFNBQVMsRUFBRSxLQUFLLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFFakUsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQzNDLE9BQU8sS0FBSyxLQUFLLE1BQU0sU0FBUyxDQUFDOzs7O0FBVWpDLE1BQU0sT0FBTyxxQkFBcUI7SUFLaEMsWUFBbUIsRUFBYTtRQUFiLE9BQUUsR0FBRixFQUFFLENBQVc7UUFIdkIsVUFBSyxHQUFXLENBQUMsQ0FBQyxDQUFFLDBCQUEwQjtRQUM5QyxnQkFBVyxHQUFXLEVBQUUsQ0FBQyxDQUFFLDZCQUE2QjtJQUU3QixDQUFDO0lBRXJDLGVBQWU7UUFDYixLQUFLLENBQUMsWUFBWSxFQUFFLENBQUM7SUFDdkIsQ0FBQztJQUVELFFBQVEsQ0FBQyxLQUFVO1FBQ2pCLE9BQU8sS0FBSyxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUMvQixDQUFDO0lBRUQsV0FBVyxDQUFDLElBQWtCLEVBQUUsS0FBYTtRQUMzQyxJQUFJLElBQUksQ0FBQyxPQUFPO1lBQUUsT0FBTyxXQUFXLENBQUM7UUFDckMsSUFBSSxJQUFJLENBQUMsS0FBSyxLQUFLLENBQUM7WUFBRSxPQUFPLEtBQUssR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQztRQUN0RSxPQUFPLElBQUksQ0FBQyxXQUFXLENBQUM7SUFDMUIsQ0FBQztJQUVELGVBQWUsQ0FBQyxJQUFTO1FBQ3ZCLElBQUksQ0FBQyxFQUFFLENBQUMsZUFBZSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxFQUFFLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3pELENBQUM7O2tIQXZCVSxxQkFBcUI7c0dBQXJCLHFCQUFxQixrSkNkbEMsa2lEQTJCQSxtdkJEYmEscUJBQXFCLHNHQUZ0QixZQUFZOzJGQUVYLHFCQUFxQjtrQkFQakMsU0FBUzsrQkFDRSxrQkFBa0IsY0FHaEIsSUFBSSxXQUNQLENBQUMsWUFBWSxDQUFDO2dHQUdkLElBQUk7c0JBQVosS0FBSztnQkFDRyxLQUFLO3NCQUFiLEtBQUs7Z0JBQ0csV0FBVztzQkFBbkIsS0FBSyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbW1vbk1vZHVsZSB9IGZyb20gXCJAYW5ndWxhci9jb21tb25cIjtcbmltcG9ydCB7ICBBZnRlclZpZXdJbml0LCBDb21wb25lbnQsIElucHV0IH0gZnJvbSBcIkBhbmd1bGFyL2NvcmVcIjtcbmltcG9ydCB7IERlYnVnTWVzc2FnZSB9IGZyb20gXCIuLi90eXBlc1wiO1xuaW1wb3J0IHsgVXRpbHMgfSBmcm9tIFwiQHNpbmVxdWEvY29yZS9iYXNlXCI7XG5pbXBvcnQgKiBhcyBQcmlzbSBmcm9tICdwcmlzbWpzJztcbmltcG9ydCB7IFVJU2VydmljZSB9IGZyb20gXCJAc2luZXF1YS9jb21wb25lbnRzL3V0aWxzXCI7XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogXCJzcS1kZWJ1Zy1tZXNzYWdlXCIsXG4gIHRlbXBsYXRlVXJsOiBcIi4vZGVidWctbWVzc2FnZS5jb21wb25lbnQuaHRtbFwiLFxuICBzdHlsZVVybHM6IFtcIi4vZGVidWctbWVzc2FnZS5jb21wb25lbnQuc2Nzc1wiXSxcbiAgc3RhbmRhbG9uZTogdHJ1ZSxcbiAgaW1wb3J0czogW0NvbW1vbk1vZHVsZV1cbn0pXG5leHBvcnQgY2xhc3MgRGVidWdNZXNzYWdlQ29tcG9uZW50IGltcGxlbWVudHMgQWZ0ZXJWaWV3SW5pdCB7XG4gIEBJbnB1dCgpIGRhdGE6IERlYnVnTWVzc2FnZVtdIHwgdW5kZWZpbmVkO1xuICBASW5wdXQoKSBsZXZlbDogbnVtYmVyID0gMDsgIC8vIFRyYWNrIHRoZSBuZXN0aW5nIGxldmVsXG4gIEBJbnB1dCgpIHBhcmVudENvbG9yOiBzdHJpbmcgPSAnJzsgIC8vIFRyYWNrIHRoZSBwYXJlbnQgcm93IGNvbG9yXG5cbiAgY29uc3RydWN0b3IocHVibGljIHVpOiBVSVNlcnZpY2UpIHsgfVxuXG4gIG5nQWZ0ZXJWaWV3SW5pdCgpIHtcbiAgICBQcmlzbS5oaWdobGlnaHRBbGwoKTtcbiAgfVxuXG4gIGlzT2JqZWN0KHZhbHVlOiBhbnkpOiBib29sZWFuIHtcbiAgICByZXR1cm4gVXRpbHMuaXNPYmplY3QodmFsdWUpO1xuICB9XG5cbiAgZ2V0Um93Q2xhc3MoaXRlbTogRGVidWdNZXNzYWdlLCBpbmRleDogbnVtYmVyKTogc3RyaW5nIHtcbiAgICBpZiAoaXRlbS5pc0Vycm9yKSByZXR1cm4gJ3Jvdy1lcnJvcic7XG4gICAgaWYgKHRoaXMubGV2ZWwgPT09IDApIHJldHVybiBpbmRleCAlIDIgPT09IDAgPyAncm93LWV2ZW4nIDogJ3Jvdy1vZGQnO1xuICAgIHJldHVybiB0aGlzLnBhcmVudENvbG9yO1xuICB9XG5cbiAgY29weVRvQ2xpcGJvYXJkKGNvZGU6IGFueSkge1xuICAgIHRoaXMudWkuY29weVRvQ2xpcGJvYXJkKEpTT04uc3RyaW5naWZ5KGNvZGUsIG51bGwsIDIpKTtcbiAgfVxufVxuIiwiPGRpdiAqbmdJZj1cImRhdGFcIiBjbGFzcz1cInRhYmxlLXJvb3RcIj5cbiAgPG5nLWNvbnRhaW5lciAqbmdGb3I9XCJsZXQgaXRlbSBvZiBkYXRhOyBsZXQgaSA9IGluZGV4XCI+XG4gICAgPGRpdiAqbmdJZj1cIml0ZW0udHlwZSA9PT0gJ0tWJ1wiIFtuZ0NsYXNzXT1cImdldFJvd0NsYXNzKGl0ZW0sIGkpXCIgY2xhc3M9XCJ0YWJsZS1yb3cga3Ytb2JqZWN0XCI+XG4gICAgICA8ZGl2IGNsYXNzPVwia3Yta2V5XCI+e3sgaXRlbS5kYXRhLmtleSB9fTwvZGl2PlxuICAgICAgPGRpdiBjbGFzcz1cImt2LXZhbHVlXCI+XG4gICAgICAgIDxuZy1jb250YWluZXIgKm5nSWY9XCJpc09iamVjdChpdGVtLmRhdGEudmFsdWUpOyBlbHNlIG5vcm1hbFZhbHVlXCI+XG4gICAgICAgICAgPGRpdiBjbGFzcz1cImNhcmQgbWItMlwiPlxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cImNhcmQtaGVhZGVyXCI+XG4gICAgICAgICAgICAgIDxidXR0b24gY2xhc3M9XCJidG4gYnRuLWxpZ2h0IGJ0bi1zbVwiIChjbGljayk9XCJjb3B5VG9DbGlwYm9hcmQoaXRlbS5kYXRhLnZhbHVlKVwiPjxpIGNsYXNzPVwiZmFyIGZhLWZ3IGZhLWNsaXBib2FyZFwiPjwvaT4gQ29weSBjb2RlPC9idXR0b24+XG4gICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgIDxwcmUgY2xhc3M9XCJsYW5ndWFnZS1qc29uIG15LTAgcm91bmRlZC0wIHJvdW5kZWQtYm90dG9tXCI+PGNvZGUgY2xhc3M9XCJsYW5ndWFnZS1qc29uXCI+e3sgaXRlbS5kYXRhLnZhbHVlIHwganNvbiB9fTwvY29kZT48L3ByZT5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgPC9uZy1jb250YWluZXI+XG4gICAgICAgIDxuZy10ZW1wbGF0ZSAjbm9ybWFsVmFsdWU+PGRpdiBjbGFzcz1cImRhdGEtdmFsdWVcIj57eyBpdGVtLmRhdGEudmFsdWUgfX08L2Rpdj48L25nLXRlbXBsYXRlPlxuICAgICAgPC9kaXY+XG4gICAgPC9kaXY+XG4gICAgPGRpdiAqbmdJZj1cIml0ZW0udHlwZSA9PT0gJ0xJU1QnXCIgW25nQ2xhc3NdPVwiZ2V0Um93Q2xhc3MoaXRlbSwgaSlcIiBjbGFzcz1cInRhYmxlLXJvdyBsaXN0LW9iamVjdFwiPlxuICAgICAgPGRpdiBjbGFzcz1cImxpc3QtbmFtZSB3LTEwMFwiIFtjbGFzcy5mdy1ib2xkXT1cImxldmVsID09PSAwXCIgKGNsaWNrKT1cIml0ZW0uZXhwYW5kZWQ9IWl0ZW0uZXhwYW5kZWRcIj5cbiAgICAgICAgPGkgY2xhc3M9XCJmYXNcIiBbY2xhc3MuZmEtY2hldnJvbi11cF09XCJpdGVtLmV4cGFuZGVkXCIgW2NsYXNzLmZhLWNoZXZyb24tZG93bl09XCIhaXRlbS5leHBhbmRlZFwiPjwvaT5cbiAgICAgICAge3sgaXRlbS5uYW1lIH19XG4gICAgICA8L2Rpdj5cbiAgICAgIDxkaXYgY2xhc3M9XCJsaXN0LWl0ZW1zIHctMTAwXCIgKm5nSWY9XCJpdGVtLmV4cGFuZGVkXCI+XG4gICAgICAgIDxzcS1kZWJ1Zy1tZXNzYWdlIFtkYXRhXT1cIml0ZW0uaXRlbXNcIiBbbGV2ZWxdPVwibGV2ZWwgKyAxXCIgW3BhcmVudENvbG9yXT1cImdldFJvd0NsYXNzKGl0ZW0sIGkpXCI+PC9zcS1kZWJ1Zy1tZXNzYWdlPlxuICAgICAgPC9kaXY+XG4gICAgPC9kaXY+XG4gIDwvbmctY29udGFpbmVyPlxuPC9kaXY+XG4iXX0=
|