@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.
Files changed (151) hide show
  1. package/chat/charts/chart/chart.component.d.ts +13 -13
  2. package/chat/chat-message/chat-message.component.d.ts +85 -81
  3. package/chat/chat-message/i18n/en.json +11 -0
  4. package/chat/chat-message/i18n/fr.json +11 -0
  5. package/chat/chat-reference/chat-reference.component.d.ts +14 -14
  6. package/chat/chat-reference/i18n/en.json +4 -0
  7. package/chat/chat-reference/i18n/fr.json +4 -0
  8. package/chat/chat-settings-v3/chat-settings-v3.component.d.ts +48 -50
  9. package/chat/chat-settings-v3/i18n/en.json +14 -0
  10. package/chat/chat-settings-v3/i18n/fr.json +14 -0
  11. package/chat/chat.component.d.ts +388 -1405
  12. package/chat/chat.service.d.ts +247 -228
  13. package/chat/debug-message/debug-message.component.d.ts +17 -17
  14. package/chat/debug-message/i18n/en.json +3 -0
  15. package/chat/debug-message/i18n/fr.json +3 -0
  16. package/chat/dialogs/delete-saved-chat.component.d.ts +22 -0
  17. package/chat/dialogs/i18n/en.json +19 -0
  18. package/chat/dialogs/i18n/fr.json +19 -0
  19. package/chat/dialogs/rename-saved-chat.component.d.ts +21 -0
  20. package/chat/dialogs/updates.component.d.ts +15 -0
  21. package/chat/documents-upload/document-list/document-list.component.d.ts +68 -77
  22. package/chat/documents-upload/document-overview/document-overview.component.d.ts +31 -41
  23. package/chat/documents-upload/document-upload/document-upload.component.d.ts +96 -98
  24. package/chat/documents-upload/documents-upload.model.d.ts +66 -66
  25. package/chat/documents-upload/documents-upload.service.d.ts +170 -174
  26. package/chat/documents-upload/i18n/en.json +24 -0
  27. package/chat/documents-upload/i18n/fr.json +24 -0
  28. package/chat/format-icon/format-icon.component.d.ts +10 -10
  29. package/chat/format-icon/icons.d.ts +5 -5
  30. package/chat/i18n/en.json +42 -0
  31. package/chat/i18n/fr.json +42 -0
  32. package/chat/index.d.ts +5 -5
  33. package/chat/initials-avatar/initials-avatar.component.d.ts +35 -35
  34. package/chat/instance-manager.service.d.ts +28 -28
  35. package/chat/pipes/message-content.pipe.d.ts +16 -0
  36. package/chat/prompt.component.d.ts +25 -21
  37. package/chat/public-api.d.ts +17 -17
  38. package/chat/references/i18n/en.json +6 -0
  39. package/chat/references/i18n/fr.json +6 -0
  40. package/chat/references/inline-image-reference.d.ts +21 -0
  41. package/chat/references/inline-page-reference.d.ts +21 -0
  42. package/chat/rest-chat.service.d.ts +31 -33
  43. package/chat/saved-chats/i18n/en.json +4 -0
  44. package/chat/saved-chats/i18n/fr.json +4 -0
  45. package/chat/saved-chats/saved-chats.component.d.ts +30 -36
  46. package/chat/services/app.service.d.ts +8 -0
  47. package/chat/services/dialog.service.d.ts +12 -0
  48. package/chat/services/notification.service.d.ts +10 -0
  49. package/chat/services/principal.service.d.ts +7 -0
  50. package/chat/services/search.service.d.ts +7 -0
  51. package/chat/services/signalR.web.service.d.ts +45 -0
  52. package/chat/services/ui.service.d.ts +13 -0
  53. package/chat/services/user-settings.service.d.ts +7 -0
  54. package/chat/token-progress-bar/i18n/en.json +4 -0
  55. package/chat/token-progress-bar/i18n/fr.json +4 -0
  56. package/chat/token-progress-bar/token-progress-bar.component.d.ts +24 -27
  57. package/chat/tooltip/tooltip.component.d.ts +12 -0
  58. package/chat/tooltip/tooltip.directive.d.ts +81 -0
  59. package/chat/types/message-content.types.d.ts +54 -0
  60. package/chat/types/message-reference.types.d.ts +11 -0
  61. package/chat/types.d.ts +913 -873
  62. package/chat/unified-plugins/embedded-image-reference.plugin.d.ts +3 -0
  63. package/chat/unified-plugins/embedded-page-reference.plugin.d.ts +3 -0
  64. package/chat/utils/assistant-json.d.ts +2 -0
  65. package/chat/websocket-chat.service.d.ts +102 -103
  66. package/esm2022/chat/charts/chart/chart.component.mjs +40 -0
  67. package/esm2022/chat/chat-message/chat-message.component.mjs +351 -0
  68. package/esm2022/chat/chat-reference/chat-reference.component.mjs +40 -0
  69. package/esm2022/chat/chat-settings-v3/chat-settings-v3.component.mjs +118 -0
  70. package/esm2022/chat/chat.component.mjs +1090 -0
  71. package/esm2022/chat/chat.service.mjs +417 -0
  72. package/esm2022/chat/debug-message/debug-message.component.mjs +43 -0
  73. package/esm2022/chat/dialogs/delete-saved-chat.component.mjs +81 -0
  74. package/esm2022/chat/dialogs/rename-saved-chat.component.mjs +84 -0
  75. package/esm2022/chat/dialogs/updates.component.mjs +61 -0
  76. package/esm2022/chat/documents-upload/document-list/document-list.component.mjs +140 -0
  77. package/esm2022/chat/documents-upload/document-overview/document-overview.component.mjs +65 -0
  78. package/esm2022/chat/documents-upload/document-upload/document-upload.component.mjs +256 -0
  79. package/{esm2020 → esm2022}/chat/documents-upload/documents-upload.model.mjs +1 -1
  80. package/esm2022/chat/documents-upload/documents-upload.service.mjs +291 -0
  81. package/{esm2020 → esm2022}/chat/format-icon/format-icon.component.mjs +23 -23
  82. package/{esm2020 → esm2022}/chat/format-icon/icons.mjs +137 -137
  83. package/{esm2020 → esm2022}/chat/initials-avatar/initials-avatar.component.mjs +60 -60
  84. package/esm2022/chat/instance-manager.service.mjs +46 -0
  85. package/esm2022/chat/pipes/message-content.pipe.mjs +34 -0
  86. package/esm2022/chat/prompt.component.mjs +88 -0
  87. package/{esm2020 → esm2022}/chat/public-api.mjs +18 -18
  88. package/esm2022/chat/references/inline-image-reference.mjs +110 -0
  89. package/esm2022/chat/references/inline-page-reference.mjs +110 -0
  90. package/esm2022/chat/rest-chat.service.mjs +296 -0
  91. package/esm2022/chat/saved-chats/saved-chats.component.mjs +82 -0
  92. package/esm2022/chat/services/app.service.mjs +19 -0
  93. package/esm2022/chat/services/dialog.service.mjs +40 -0
  94. package/esm2022/chat/services/notification.service.mjs +25 -0
  95. package/esm2022/chat/services/principal.service.mjs +16 -0
  96. package/esm2022/chat/services/search.service.mjs +13 -0
  97. package/esm2022/chat/services/signalR.web.service.mjs +79 -0
  98. package/esm2022/chat/services/ui.service.mjs +61 -0
  99. package/esm2022/chat/services/user-settings.service.mjs +22 -0
  100. package/{esm2020 → esm2022}/chat/sinequa-assistant-chat.mjs +4 -4
  101. package/esm2022/chat/token-progress-bar/token-progress-bar.component.mjs +52 -0
  102. package/esm2022/chat/tooltip/tooltip.component.mjs +44 -0
  103. package/esm2022/chat/tooltip/tooltip.directive.mjs +203 -0
  104. package/esm2022/chat/types/message-content.types.mjs +2 -0
  105. package/esm2022/chat/types/message-reference.types.mjs +2 -0
  106. package/esm2022/chat/types.mjs +130 -0
  107. package/esm2022/chat/unified-plugins/embedded-image-reference.plugin.mjs +57 -0
  108. package/esm2022/chat/unified-plugins/embedded-page-reference.plugin.mjs +57 -0
  109. package/esm2022/chat/utils/assistant-json.mjs +12 -0
  110. package/esm2022/chat/websocket-chat.service.mjs +654 -0
  111. package/{esm2020 → esm2022}/public-api.mjs +2 -2
  112. package/{esm2020 → esm2022}/sinequa-assistant.mjs +4 -4
  113. package/fesm2022/sinequa-assistant-chat.mjs +5340 -0
  114. package/fesm2022/sinequa-assistant-chat.mjs.map +1 -0
  115. package/{fesm2015 → fesm2022}/sinequa-assistant.mjs +3 -3
  116. package/index.d.ts +5 -5
  117. package/package.json +52 -25
  118. package/public-api.d.ts +1 -1
  119. package/chat/messages/de.d.ts +0 -4
  120. package/chat/messages/en.d.ts +0 -4
  121. package/chat/messages/fr.d.ts +0 -4
  122. package/chat/messages/index.d.ts +0 -4
  123. package/esm2020/chat/charts/chart/chart.component.mjs +0 -40
  124. package/esm2020/chat/chat-message/chat-message.component.mjs +0 -263
  125. package/esm2020/chat/chat-reference/chat-reference.component.mjs +0 -40
  126. package/esm2020/chat/chat-settings-v3/chat-settings-v3.component.mjs +0 -117
  127. package/esm2020/chat/chat.component.mjs +0 -1069
  128. package/esm2020/chat/chat.service.mjs +0 -333
  129. package/esm2020/chat/debug-message/debug-message.component.mjs +0 -43
  130. package/esm2020/chat/documents-upload/document-list/document-list.component.mjs +0 -191
  131. package/esm2020/chat/documents-upload/document-overview/document-overview.component.mjs +0 -80
  132. package/esm2020/chat/documents-upload/document-upload/document-upload.component.mjs +0 -258
  133. package/esm2020/chat/documents-upload/documents-upload.service.mjs +0 -289
  134. package/esm2020/chat/instance-manager.service.mjs +0 -46
  135. package/esm2020/chat/messages/de.mjs +0 -4
  136. package/esm2020/chat/messages/en.mjs +0 -4
  137. package/esm2020/chat/messages/fr.mjs +0 -4
  138. package/esm2020/chat/messages/index.mjs +0 -9
  139. package/esm2020/chat/prompt.component.mjs +0 -88
  140. package/esm2020/chat/rest-chat.service.mjs +0 -241
  141. package/esm2020/chat/saved-chats/saved-chats.component.mjs +0 -175
  142. package/esm2020/chat/token-progress-bar/token-progress-bar.component.mjs +0 -54
  143. package/esm2020/chat/types.mjs +0 -112
  144. package/esm2020/chat/websocket-chat.service.mjs +0 -641
  145. package/fesm2015/sinequa-assistant-chat.mjs +0 -4200
  146. package/fesm2015/sinequa-assistant-chat.mjs.map +0 -1
  147. package/fesm2020/sinequa-assistant-chat.mjs +0 -4171
  148. package/fesm2020/sinequa-assistant-chat.mjs.map +0 -1
  149. package/fesm2020/sinequa-assistant.mjs +0 -9
  150. package/fesm2020/sinequa-assistant.mjs.map +0 -1
  151. /package/{fesm2015 → fesm2022}/sinequa-assistant.mjs.map +0 -0
@@ -0,0 +1,417 @@
1
+ import { Injectable, LOCALE_ID, inject } from "@angular/core";
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";
7
+ import { AppService } from "./services/app.service";
8
+ import { DialogService } from "./services/dialog.service";
9
+ import { NotificationsService } from "./services/notification.service";
10
+ import { PrincipalService } from "./services/principal.service";
11
+ import { UserSettingsWebService } from "./services/user-settings.service";
12
+ import { chatConfigSchema } from "./types";
13
+ import { getAssistantJsonFromCCApp } from "./utils/assistant-json";
14
+ import * as i0 from "@angular/core";
15
+ export class ChatService {
16
+ constructor() {
17
+ this.localID = inject(LOCALE_ID, { optional: true });
18
+ /** Emit true once the initialization of the assistant process is done. */
19
+ this.initProcess$ = new BehaviorSubject(false);
20
+ /** Emit true once the initialization of the assistant config is done. */
21
+ this.initConfig$ = new BehaviorSubject(false);
22
+ /** Emit the global configuration of the assistant. */
23
+ this.assistantConfig$ = new BehaviorSubject(undefined);
24
+ /** Emit true if the user has been overridden, false otherwise. */
25
+ this.userOverride$ = new BehaviorSubject(undefined);
26
+ /**
27
+ * 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).
28
+ * This is used to prevent multiple fetches at the same time.
29
+ * 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.
30
+ */
31
+ this.streaming$ = new BehaviorSubject(false);
32
+ /** List of saved chats. */
33
+ this.savedChats$ = new BehaviorSubject([]);
34
+ /** Emit the saved chat to load. */
35
+ this.loadSavedChat$ = new BehaviorSubject(undefined);
36
+ /** Emit the quota each time the chat is invoked. */
37
+ this.quota$ = new BehaviorSubject(undefined);
38
+ /** Emit the calculated user's token consumption based on the quota. */
39
+ this.userTokenConsumption$ = new BehaviorSubject(undefined);
40
+ /** Emit the chat usage metrics each time the generation of the assistant response is completed. */
41
+ this.chatUsageMetrics$ = new BehaviorSubject(undefined);
42
+ /** Emit the calculated chat's token consumption based on the chat usage metrics. */
43
+ this.chatTokenConsumption$ = new BehaviorSubject(undefined);
44
+ /** Emit true if "CancelTasks" is ongoing. */
45
+ this.stoppingGeneration$ = new BehaviorSubject(false);
46
+ this.userSettingsService = inject(UserSettingsWebService);
47
+ this.notificationsService = inject(NotificationsService);
48
+ this.appService = inject(AppService);
49
+ this.modalService = inject(DialogService);
50
+ this.principalService = inject(PrincipalService);
51
+ this.transloco = inject(TranslocoService);
52
+ }
53
+ 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"];
59
+ }
60
+ /**
61
+ * Get the instance ID of the chat service
62
+ * @returns The instance ID of the chat service
63
+ */
64
+ get chatInstanceId() {
65
+ return this._chatInstanceId;
66
+ }
67
+ /**
68
+ * Persist the instance ID of the chat service
69
+ * @param instanceId The instance ID of the chat service
70
+ */
71
+ setChatInstanceId(instanceId) {
72
+ this._chatInstanceId = instanceId;
73
+ }
74
+ /**
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
90
+ * @returns The ID of the current chat discussion
91
+ */
92
+ get chatId() {
93
+ return this._chatId;
94
+ }
95
+ /**
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
98
+ * @param chatId if provided, it will be considered as the ID of the current chat discussion which is used to identify audit events
99
+ */
100
+ generateChatId(chatId) {
101
+ this._chatId = chatId || guid();
102
+ }
103
+ /**
104
+ * 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.
105
+ * 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.
106
+ * The rest of the config object coming from "standard app config" is used as it is without any override.
107
+ * Thus, the user preferences are used only for the defaultValues object.
108
+ * 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
+ */
110
+ 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
+ }
171
+ }
172
+ /**
173
+ * Update the chat config and store its defaultValues in the user preferences
174
+ * @param config The updated chat config
175
+ * @param hashes The updated hashes to store in the user preferences
176
+ * @param notify Whether to notify the user about the update
177
+ * @param successCallback The callback to execute if the update is successful
178
+ * @param errorCallback The callback to execute if the update fails
179
+ */
180
+ 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
+ }
201
+ });
202
+ }
203
+ /**
204
+ * A handler for quota updates each time the chat is invoked.
205
+ * 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.
206
+ * @param quota The updated quota
207
+ * @param propagateError Whether to propagate the error to the caller
208
+ */
209
+ 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
+ }
221
+ }
222
+ /**
223
+ * A handler for chat usage metrics each time the generation of the assistant response is completed.
224
+ * It emits the chat usage metrics to the chatUsageMetrics$ subject, emits accordingly the updated chat's tokens consumption
225
+ * @param chatUsageMetrics The chat usage metrics
226
+ */
227
+ 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 });
232
+ }
233
+ /**
234
+ * Get the model description for the given (serviceId + modelId)
235
+ * If a model is not found, an error message is returned
236
+ * @param serviceId The serviceId of the model
237
+ * @param modelId The modelId of the model
238
+ * @returns The model description
239
+ */
240
+ getModel(serviceId, modelId) {
241
+ const model = this.models?.find(m => m.serviceId === serviceId && m.modelId === modelId);
242
+ // Handle obsolete config
243
+ if (!model) {
244
+ this.notificationsService.error(`FATAL ERROR : The model (serviceId = '${serviceId}', modelId = '${modelId}') is no longer available. Please contact an admin for further information.`);
245
+ throw new Error(`FATAL ERROR : The model (serviceId = '${serviceId}', modelId = '${modelId}') is no longer available`);
246
+ }
247
+ return model;
248
+ }
249
+ /**
250
+ * Generate an audit event with the given type and details. The generated audit event is sent afterwards via the AuditWebService
251
+ * @param type Audit event type
252
+ * @param details Audit event details
253
+ * @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
254
+ */
255
+ async generateAuditEvent(type, details, id) {
256
+ const baseDetails = {
257
+ "url": decodeURIComponent(window.location.href),
258
+ "app": this.appService.appName,
259
+ "user-id": this.principalService.principal?.userId,
260
+ "instance-id": this.chatInstanceId,
261
+ "chat-id": id || this.chatId,
262
+ "service-id": this.assistantConfig$.value.defaultValues.service_id,
263
+ "model-id": this.assistantConfig$.value.defaultValues.model_id,
264
+ "is-user-input": false
265
+ };
266
+ const audit = {
267
+ type,
268
+ detail: {
269
+ ...baseDetails,
270
+ ...details
271
+ }
272
+ };
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 || '';
410
+ }
411
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ChatService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
412
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ChatService }); }
413
+ }
414
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ChatService, decorators: [{
415
+ type: Injectable
416
+ }] });
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=
@@ -0,0 +1,43 @@
1
+ import { CommonModule } from "@angular/common";
2
+ import { Component, Input } from "@angular/core";
3
+ import * as Prism from 'prismjs';
4
+ import { provideTranslocoScope, TranslocoPipe } from '@jsverse/transloco';
5
+ import * as i0 from "@angular/core";
6
+ import * as i1 from "../services/ui.service";
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 value !== null && typeof value === 'object';
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
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DebugMessageComponent, deps: [{ token: i1.UIService }], target: i0.ɵɵFactoryTarget.Component }); }
31
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: DebugMessageComponent, isStandalone: true, selector: "sq-debug-message", inputs: { data: "data", level: "level", parentColor: "parentColor" }, providers: [provideTranslocoScope('chat-debug-message')], 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=\"d-flex w-100 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> {{ 'chatDebugMessage.copyCode' | transloco }}</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=\"d-flex w-100 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}.d-flex{display:flex}.w-100{width:100%}.card{--bs-card-spacer-y: 1rem;--bs-card-spacer-x: 1rem;--bs-card-title-spacer-y: .5rem;--bs-card-title-color: ;--bs-card-subtitle-color: ;--bs-card-border-width: var(--bs-border-width);--bs-card-border-color: var(--bs-border-color-translucent);--bs-card-border-radius: var(--bs-border-radius);--bs-card-box-shadow: ;--bs-card-inner-border-radius: calc(var(--bs-border-radius) - (var(--bs-border-width)));--bs-card-cap-padding-y: .5rem;--bs-card-cap-padding-x: 1rem;--bs-card-cap-bg: rgba(var(--bs-body-color-rgb), .03);--bs-card-cap-color: ;--bs-card-height: ;--bs-card-color: ;--bs-card-bg: var(--bs-body-bg);--bs-card-img-overlay-padding: 1rem;--bs-card-group-margin: .75rem;position:relative;display:flex;flex-direction:column;min-width:0;height:var(--bs-card-height);color:var(--bs-body-color);word-wrap:break-word;background-color:var(--bs-card-bg);background-clip:border-box;border:var(--bs-card-border-width) solid var(--bs-card-border-color);border-radius:var(--bs-card-border-radius)}.card-header{padding:var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);margin-bottom:0;color:var(--bs-card-cap-color);background-color:var(--bs-card-cap-bg);border-bottom:var(--bs-card-border-width) solid var(--bs-card-border-color)}.btn{--bs-btn-padding-x: .75rem;--bs-btn-padding-y: .375rem;--bs-btn-font-family: ;--bs-btn-font-size: 1rem;--bs-btn-font-weight: 400;--bs-btn-line-height: 1.5;--bs-btn-color: var(--bs-body-color);--bs-btn-bg: transparent;--bs-btn-border-width: var(--bs-border-width);--bs-btn-border-color: transparent;--bs-btn-border-radius: var(--bs-border-radius);--bs-btn-hover-border-color: transparent;--bs-btn-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);--bs-btn-disabled-opacity: .65;--bs-btn-focus-box-shadow: 0 0 0 .25rem rgba(var(--bs-btn-focus-shadow-rgb), .5);display:inline-block;padding:var(--bs-btn-padding-y) var(--bs-btn-padding-x);font-family:var(--bs-btn-font-family);font-size:var(--bs-btn-font-size);font-weight:var(--bs-btn-font-weight);line-height:var(--bs-btn-line-height);color:var(--bs-btn-color);text-align:center;text-decoration:none;vertical-align:middle;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none;border:var(--bs-btn-border-width) solid var(--bs-btn-border-color);border-radius:var(--bs-btn-border-radius);background-color:var(--bs-btn-bg);transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}.btn-light{--bs-btn-color: #000;--bs-btn-bg: #f8f9fa;--bs-btn-border-color: #f8f9fa;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #d3d4d5;--bs-btn-hover-border-color: #c6c7c8;--bs-btn-focus-shadow-rgb: 211, 212, 213;--bs-btn-active-color: #000;--bs-btn-active-bg: #c6c7c8;--bs-btn-active-border-color: #babbbc;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #000;--bs-btn-disabled-bg: #f8f9fa;--bs-btn-disabled-border-color: #f8f9fa}.btn-sm,.btn-group-sm>.btn{--bs-btn-padding-y: .25rem;--bs-btn-padding-x: .5rem;--bs-btn-font-size: .875rem;--bs-btn-border-radius: var(--bs-border-radius-sm)}.rounded-0{border-radius:0!important}.rounded-bottom{border-bottom-right-radius:var(--bs-border-radius)!important;border-bottom-left-radius:var(--bs-border-radius)!important}\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" }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }] }); }
32
+ }
33
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DebugMessageComponent, decorators: [{
34
+ type: Component,
35
+ args: [{ selector: "sq-debug-message", standalone: true, imports: [CommonModule, TranslocoPipe], providers: [provideTranslocoScope('chat-debug-message')], 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=\"d-flex w-100 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> {{ 'chatDebugMessage.copyCode' | transloco }}</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=\"d-flex w-100 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}.d-flex{display:flex}.w-100{width:100%}.card{--bs-card-spacer-y: 1rem;--bs-card-spacer-x: 1rem;--bs-card-title-spacer-y: .5rem;--bs-card-title-color: ;--bs-card-subtitle-color: ;--bs-card-border-width: var(--bs-border-width);--bs-card-border-color: var(--bs-border-color-translucent);--bs-card-border-radius: var(--bs-border-radius);--bs-card-box-shadow: ;--bs-card-inner-border-radius: calc(var(--bs-border-radius) - (var(--bs-border-width)));--bs-card-cap-padding-y: .5rem;--bs-card-cap-padding-x: 1rem;--bs-card-cap-bg: rgba(var(--bs-body-color-rgb), .03);--bs-card-cap-color: ;--bs-card-height: ;--bs-card-color: ;--bs-card-bg: var(--bs-body-bg);--bs-card-img-overlay-padding: 1rem;--bs-card-group-margin: .75rem;position:relative;display:flex;flex-direction:column;min-width:0;height:var(--bs-card-height);color:var(--bs-body-color);word-wrap:break-word;background-color:var(--bs-card-bg);background-clip:border-box;border:var(--bs-card-border-width) solid var(--bs-card-border-color);border-radius:var(--bs-card-border-radius)}.card-header{padding:var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);margin-bottom:0;color:var(--bs-card-cap-color);background-color:var(--bs-card-cap-bg);border-bottom:var(--bs-card-border-width) solid var(--bs-card-border-color)}.btn{--bs-btn-padding-x: .75rem;--bs-btn-padding-y: .375rem;--bs-btn-font-family: ;--bs-btn-font-size: 1rem;--bs-btn-font-weight: 400;--bs-btn-line-height: 1.5;--bs-btn-color: var(--bs-body-color);--bs-btn-bg: transparent;--bs-btn-border-width: var(--bs-border-width);--bs-btn-border-color: transparent;--bs-btn-border-radius: var(--bs-border-radius);--bs-btn-hover-border-color: transparent;--bs-btn-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);--bs-btn-disabled-opacity: .65;--bs-btn-focus-box-shadow: 0 0 0 .25rem rgba(var(--bs-btn-focus-shadow-rgb), .5);display:inline-block;padding:var(--bs-btn-padding-y) var(--bs-btn-padding-x);font-family:var(--bs-btn-font-family);font-size:var(--bs-btn-font-size);font-weight:var(--bs-btn-font-weight);line-height:var(--bs-btn-line-height);color:var(--bs-btn-color);text-align:center;text-decoration:none;vertical-align:middle;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none;border:var(--bs-btn-border-width) solid var(--bs-btn-border-color);border-radius:var(--bs-btn-border-radius);background-color:var(--bs-btn-bg);transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}.btn-light{--bs-btn-color: #000;--bs-btn-bg: #f8f9fa;--bs-btn-border-color: #f8f9fa;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #d3d4d5;--bs-btn-hover-border-color: #c6c7c8;--bs-btn-focus-shadow-rgb: 211, 212, 213;--bs-btn-active-color: #000;--bs-btn-active-bg: #c6c7c8;--bs-btn-active-border-color: #babbbc;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #000;--bs-btn-disabled-bg: #f8f9fa;--bs-btn-disabled-border-color: #f8f9fa}.btn-sm,.btn-group-sm>.btn{--bs-btn-padding-y: .25rem;--bs-btn-padding-x: .5rem;--bs-btn-font-size: .875rem;--bs-btn-border-radius: var(--bs-border-radius-sm)}.rounded-0{border-radius:0!important}.rounded-bottom{border-bottom-right-radius:var(--bs-border-radius)!important;border-bottom-left-radius:var(--bs-border-radius)!important}\n"] }]
36
+ }], ctorParameters: () => [{ 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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVidWctbWVzc2FnZS5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9hc3Npc3RhbnQvY2hhdC9kZWJ1Zy1tZXNzYWdlL2RlYnVnLW1lc3NhZ2UuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvYXNzaXN0YW50L2NoYXQvZGVidWctbWVzc2FnZS9kZWJ1Zy1tZXNzYWdlLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUMvQyxPQUFPLEVBQWlCLFNBQVMsRUFBRSxLQUFLLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDaEUsT0FBTyxLQUFLLEtBQUssTUFBTSxTQUFTLENBQUM7QUFDakMsT0FBTyxFQUFFLHFCQUFxQixFQUFFLGFBQWEsRUFBRSxNQUFNLG9CQUFvQixDQUFDOzs7O0FBYTFFLE1BQU0sT0FBTyxxQkFBcUI7SUFLaEMsWUFBbUIsRUFBYTtRQUFiLE9BQUUsR0FBRixFQUFFLENBQVc7UUFIdkIsVUFBSyxHQUFXLENBQUMsQ0FBQyxDQUFFLDBCQUEwQjtRQUM5QyxnQkFBVyxHQUFXLEVBQUUsQ0FBQyxDQUFFLDZCQUE2QjtJQUU3QixDQUFDO0lBRXJDLGVBQWU7UUFDYixLQUFLLENBQUMsWUFBWSxFQUFFLENBQUM7SUFDdkIsQ0FBQztJQUVELFFBQVEsQ0FBQyxLQUFVO1FBQ2pCLE9BQU8sS0FBSyxLQUFLLElBQUksSUFBSSxPQUFPLEtBQUssS0FBSyxRQUFRLENBQUE7SUFDcEQsQ0FBQztJQUVELFdBQVcsQ0FBQyxJQUFrQixFQUFFLEtBQWE7UUFDM0MsSUFBSSxJQUFJLENBQUMsT0FBTztZQUFFLE9BQU8sV0FBVyxDQUFDO1FBQ3JDLElBQUksSUFBSSxDQUFDLEtBQUssS0FBSyxDQUFDO1lBQUUsT0FBTyxLQUFLLEdBQUcsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7UUFDdEUsT0FBTyxJQUFJLENBQUMsV0FBVyxDQUFDO0lBQzFCLENBQUM7SUFFRCxlQUFlLENBQUMsSUFBUztRQUN2QixJQUFJLENBQUMsRUFBRSxDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN6RCxDQUFDOytHQXZCVSxxQkFBcUI7bUdBQXJCLHFCQUFxQixxSUFGckIsQ0FBQyxxQkFBcUIsQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDLDBCQ2QxRCw0a0RBMkJBLHUvSERYYSxxQkFBcUIsc0dBSHRCLFlBQVksNFlBQUUsYUFBYTs7NEZBRzFCLHFCQUFxQjtrQkFSakMsU0FBUzsrQkFDRSxrQkFBa0IsY0FHaEIsSUFBSSxXQUNQLENBQUMsWUFBWSxFQUFFLGFBQWEsQ0FBQyxhQUMzQixDQUFDLHFCQUFxQixDQUFDLG9CQUFvQixDQUFDLENBQUM7OEVBRy9DLElBQUk7c0JBQVosS0FBSztnQkFDRyxLQUFLO3NCQUFiLEtBQUs7Z0JBQ0csV0FBVztzQkFBbkIsS0FBSyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbW1vbk1vZHVsZSB9IGZyb20gXCJAYW5ndWxhci9jb21tb25cIjtcbmltcG9ydCB7IEFmdGVyVmlld0luaXQsIENvbXBvbmVudCwgSW5wdXQgfSBmcm9tIFwiQGFuZ3VsYXIvY29yZVwiO1xuaW1wb3J0ICogYXMgUHJpc20gZnJvbSAncHJpc21qcyc7XG5pbXBvcnQgeyBwcm92aWRlVHJhbnNsb2NvU2NvcGUsIFRyYW5zbG9jb1BpcGUgfSBmcm9tICdAanN2ZXJzZS90cmFuc2xvY28nO1xuXG5pbXBvcnQgeyBEZWJ1Z01lc3NhZ2UgfSBmcm9tIFwiLi4vdHlwZXNcIjtcbmltcG9ydCB7IFVJU2VydmljZSB9IGZyb20gXCIuLi9zZXJ2aWNlcy91aS5zZXJ2aWNlXCI7XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogXCJzcS1kZWJ1Zy1tZXNzYWdlXCIsXG4gIHRlbXBsYXRlVXJsOiBcIi4vZGVidWctbWVzc2FnZS5jb21wb25lbnQuaHRtbFwiLFxuICBzdHlsZVVybHM6IFtcIi4vZGVidWctbWVzc2FnZS5jb21wb25lbnQuc2Nzc1wiXSxcbiAgc3RhbmRhbG9uZTogdHJ1ZSxcbiAgaW1wb3J0czogW0NvbW1vbk1vZHVsZSwgVHJhbnNsb2NvUGlwZV0sXG4gIHByb3ZpZGVyczogW3Byb3ZpZGVUcmFuc2xvY29TY29wZSgnY2hhdC1kZWJ1Zy1tZXNzYWdlJyldXG59KVxuZXhwb3J0IGNsYXNzIERlYnVnTWVzc2FnZUNvbXBvbmVudCBpbXBsZW1lbnRzIEFmdGVyVmlld0luaXQge1xuICBASW5wdXQoKSBkYXRhOiBEZWJ1Z01lc3NhZ2VbXSB8IHVuZGVmaW5lZDtcbiAgQElucHV0KCkgbGV2ZWw6IG51bWJlciA9IDA7ICAvLyBUcmFjayB0aGUgbmVzdGluZyBsZXZlbFxuICBASW5wdXQoKSBwYXJlbnRDb2xvcjogc3RyaW5nID0gJyc7ICAvLyBUcmFjayB0aGUgcGFyZW50IHJvdyBjb2xvclxuXG4gIGNvbnN0cnVjdG9yKHB1YmxpYyB1aTogVUlTZXJ2aWNlKSB7IH1cblxuICBuZ0FmdGVyVmlld0luaXQoKSB7XG4gICAgUHJpc20uaGlnaGxpZ2h0QWxsKCk7XG4gIH1cblxuICBpc09iamVjdCh2YWx1ZTogYW55KTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHZhbHVlICE9PSBudWxsICYmIHR5cGVvZiB2YWx1ZSA9PT0gJ29iamVjdCdcbiAgfVxuXG4gIGdldFJvd0NsYXNzKGl0ZW06IERlYnVnTWVzc2FnZSwgaW5kZXg6IG51bWJlcik6IHN0cmluZyB7XG4gICAgaWYgKGl0ZW0uaXNFcnJvcikgcmV0dXJuICdyb3ctZXJyb3InO1xuICAgIGlmICh0aGlzLmxldmVsID09PSAwKSByZXR1cm4gaW5kZXggJSAyID09PSAwID8gJ3Jvdy1ldmVuJyA6ICdyb3ctb2RkJztcbiAgICByZXR1cm4gdGhpcy5wYXJlbnRDb2xvcjtcbiAgfVxuXG4gIGNvcHlUb0NsaXBib2FyZChjb2RlOiBhbnkpIHtcbiAgICB0aGlzLnVpLmNvcHlUb0NsaXBib2FyZChKU09OLnN0cmluZ2lmeShjb2RlLCBudWxsLCAyKSk7XG4gIH1cbn1cbiIsIjxkaXYgKm5nSWY9XCJkYXRhXCIgY2xhc3M9XCJ0YWJsZS1yb290XCI+XG4gIDxuZy1jb250YWluZXIgKm5nRm9yPVwibGV0IGl0ZW0gb2YgZGF0YTsgbGV0IGkgPSBpbmRleFwiPlxuICAgIDxkaXYgKm5nSWY9XCJpdGVtLnR5cGUgPT09ICdLVidcIiBbbmdDbGFzc109XCJnZXRSb3dDbGFzcyhpdGVtLCBpKVwiIGNsYXNzPVwiZC1mbGV4IHctMTAwIGt2LW9iamVjdFwiPlxuICAgICAgPGRpdiBjbGFzcz1cImt2LWtleVwiPnt7IGl0ZW0uZGF0YS5rZXkgfX08L2Rpdj5cbiAgICAgIDxkaXYgY2xhc3M9XCJrdi12YWx1ZVwiPlxuICAgICAgICA8bmctY29udGFpbmVyICpuZ0lmPVwiaXNPYmplY3QoaXRlbS5kYXRhLnZhbHVlKTsgZWxzZSBub3JtYWxWYWx1ZVwiPlxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJjYXJkIG1iLTJcIj5cbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJjYXJkLWhlYWRlclwiPlxuICAgICAgICAgICAgICA8YnV0dG9uIGNsYXNzPVwiYnRuIGJ0bi1saWdodCBidG4tc21cIiAoY2xpY2spPVwiY29weVRvQ2xpcGJvYXJkKGl0ZW0uZGF0YS52YWx1ZSlcIj48aSBjbGFzcz1cImZhciBmYS1mdyBmYS1jbGlwYm9hcmRcIj48L2k+IHt7ICdjaGF0RGVidWdNZXNzYWdlLmNvcHlDb2RlJyB8IHRyYW5zbG9jbyB9fTwvYnV0dG9uPlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICA8cHJlIGNsYXNzPVwibGFuZ3VhZ2UtanNvbiBteS0wIHJvdW5kZWQtMCByb3VuZGVkLWJvdHRvbVwiPjxjb2RlIGNsYXNzPVwibGFuZ3VhZ2UtanNvblwiPnt7IGl0ZW0uZGF0YS52YWx1ZSB8IGpzb24gfX08L2NvZGU+PC9wcmU+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgIDwvbmctY29udGFpbmVyPlxuICAgICAgICA8bmctdGVtcGxhdGUgI25vcm1hbFZhbHVlPjxkaXYgY2xhc3M9XCJkYXRhLXZhbHVlXCI+e3sgaXRlbS5kYXRhLnZhbHVlIH19PC9kaXY+PC9uZy10ZW1wbGF0ZT5cbiAgICAgIDwvZGl2PlxuICAgIDwvZGl2PlxuICAgIDxkaXYgKm5nSWY9XCJpdGVtLnR5cGUgPT09ICdMSVNUJ1wiIFtuZ0NsYXNzXT1cImdldFJvd0NsYXNzKGl0ZW0sIGkpXCIgY2xhc3M9XCJkLWZsZXggdy0xMDAgbGlzdC1vYmplY3RcIj5cbiAgICAgIDxkaXYgY2xhc3M9XCJsaXN0LW5hbWUgdy0xMDBcIiBbY2xhc3MuZnctYm9sZF09XCJsZXZlbCA9PT0gMFwiIChjbGljayk9XCJpdGVtLmV4cGFuZGVkPSFpdGVtLmV4cGFuZGVkXCI+XG4gICAgICAgIDxpIGNsYXNzPVwiZmFzXCIgW2NsYXNzLmZhLWNoZXZyb24tdXBdPVwiaXRlbS5leHBhbmRlZFwiIFtjbGFzcy5mYS1jaGV2cm9uLWRvd25dPVwiIWl0ZW0uZXhwYW5kZWRcIj48L2k+XG4gICAgICAgIHt7IGl0ZW0ubmFtZSB9fVxuICAgICAgPC9kaXY+XG4gICAgICA8ZGl2IGNsYXNzPVwibGlzdC1pdGVtcyB3LTEwMFwiICpuZ0lmPVwiaXRlbS5leHBhbmRlZFwiPlxuICAgICAgICA8c3EtZGVidWctbWVzc2FnZSBbZGF0YV09XCJpdGVtLml0ZW1zXCIgW2xldmVsXT1cImxldmVsICsgMVwiIFtwYXJlbnRDb2xvcl09XCJnZXRSb3dDbGFzcyhpdGVtLCBpKVwiPjwvc3EtZGVidWctbWVzc2FnZT5cbiAgICAgIDwvZGl2PlxuICAgIDwvZGl2PlxuICA8L25nLWNvbnRhaW5lcj5cbjwvZGl2PlxuIl19