@muraai/mnl-chat 0.0.1

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 (88) hide show
  1. package/README.md +24 -0
  2. package/esm2020/lib/chat.module.mjs +87 -0
  3. package/esm2020/lib/components/ng-chat/ng-chat.component.mjs +588 -0
  4. package/esm2020/lib/components/ng-chat-friends-list/ng-chat-friends-list.component.mjs +128 -0
  5. package/esm2020/lib/components/ng-chat-options/ng-chat-options.component.mjs +29 -0
  6. package/esm2020/lib/components/ng-chat-window/ng-chat-window.component.mjs +247 -0
  7. package/esm2020/lib/core/chat-adapter.mjs +18 -0
  8. package/esm2020/lib/core/chat-controller.mjs +2 -0
  9. package/esm2020/lib/core/chat-group-adapter.mjs +2 -0
  10. package/esm2020/lib/core/chat-option.mjs +2 -0
  11. package/esm2020/lib/core/chat-participant-status-descriptor.mjs +6 -0
  12. package/esm2020/lib/core/chat-participant-status.enum.mjs +8 -0
  13. package/esm2020/lib/core/chat-participant-type.enum.mjs +6 -0
  14. package/esm2020/lib/core/chat-participant.mjs +2 -0
  15. package/esm2020/lib/core/default-file-upload-adapter.mjs +43 -0
  16. package/esm2020/lib/core/file-upload-adapter.mjs +2 -0
  17. package/esm2020/lib/core/group.mjs +14 -0
  18. package/esm2020/lib/core/guid.mjs +11 -0
  19. package/esm2020/lib/core/localization.mjs +2 -0
  20. package/esm2020/lib/core/message-counter.mjs +25 -0
  21. package/esm2020/lib/core/message-type.enum.mjs +7 -0
  22. package/esm2020/lib/core/message.mjs +7 -0
  23. package/esm2020/lib/core/paged-history-chat-adapter.mjs +9 -0
  24. package/esm2020/lib/core/participant-metadata.mjs +6 -0
  25. package/esm2020/lib/core/participant-response.mjs +3 -0
  26. package/esm2020/lib/core/scroll-direction.enum.mjs +6 -0
  27. package/esm2020/lib/core/theme.enum.mjs +7 -0
  28. package/esm2020/lib/core/user.mjs +7 -0
  29. package/esm2020/lib/core/window.mjs +20 -0
  30. package/esm2020/lib/firstLetter.pipe.mjs +20 -0
  31. package/esm2020/lib/material.module.mjs +50 -0
  32. package/esm2020/lib/pipes/emojify.pipe.mjs +41 -0
  33. package/esm2020/lib/pipes/group-message-display-name.pipe.mjs +24 -0
  34. package/esm2020/lib/pipes/linkfy.pipe.mjs +34 -0
  35. package/esm2020/lib/pipes/sanitize.pipe.mjs +21 -0
  36. package/esm2020/lib/services/chat.service.mjs +14 -0
  37. package/esm2020/muraai-mnl-chat.mjs +5 -0
  38. package/esm2020/public-api.mjs +25 -0
  39. package/fesm2015/muraai-mnl-chat.mjs +1426 -0
  40. package/fesm2015/muraai-mnl-chat.mjs.map +1 -0
  41. package/fesm2020/muraai-mnl-chat.mjs +1424 -0
  42. package/fesm2020/muraai-mnl-chat.mjs.map +1 -0
  43. package/index.d.ts +5 -0
  44. package/lib/chat.module.d.ts +24 -0
  45. package/lib/components/ng-chat/ng-chat.component.d.ts +130 -0
  46. package/lib/components/ng-chat-friends-list/ng-chat-friends-list.component.d.ts +45 -0
  47. package/lib/components/ng-chat-options/ng-chat-options.component.d.ts +12 -0
  48. package/lib/components/ng-chat-window/ng-chat-window.component.d.ts +65 -0
  49. package/lib/core/chat-adapter.d.ts +15 -0
  50. package/lib/core/chat-controller.d.ts +6 -0
  51. package/lib/core/chat-group-adapter.d.ts +4 -0
  52. package/lib/core/chat-option.d.ts +9 -0
  53. package/lib/core/chat-participant-status-descriptor.d.ts +3 -0
  54. package/lib/core/chat-participant-status.enum.d.ts +6 -0
  55. package/lib/core/chat-participant-type.enum.d.ts +4 -0
  56. package/lib/core/chat-participant.d.ts +9 -0
  57. package/lib/core/default-file-upload-adapter.d.ts +14 -0
  58. package/lib/core/file-upload-adapter.d.ts +5 -0
  59. package/lib/core/group.d.ts +13 -0
  60. package/lib/core/guid.d.ts +3 -0
  61. package/lib/core/localization.d.ts +15 -0
  62. package/lib/core/message-counter.d.ts +10 -0
  63. package/lib/core/message-type.enum.d.ts +5 -0
  64. package/lib/core/message.d.ts +10 -0
  65. package/lib/core/paged-history-chat-adapter.d.ts +10 -0
  66. package/lib/core/participant-metadata.d.ts +3 -0
  67. package/lib/core/participant-response.d.ts +6 -0
  68. package/lib/core/scroll-direction.enum.d.ts +4 -0
  69. package/lib/core/theme.enum.d.ts +5 -0
  70. package/lib/core/user.d.ts +10 -0
  71. package/lib/core/window.d.ts +13 -0
  72. package/lib/firstLetter.pipe.d.ts +7 -0
  73. package/lib/material.module.d.ts +14 -0
  74. package/lib/pipes/emojify.pipe.d.ts +7 -0
  75. package/lib/pipes/group-message-display-name.pipe.d.ts +9 -0
  76. package/lib/pipes/linkfy.pipe.d.ts +7 -0
  77. package/lib/pipes/sanitize.pipe.d.ts +10 -0
  78. package/lib/services/chat.service.d.ts +6 -0
  79. package/package.json +31 -0
  80. package/public-api.d.ts +21 -0
  81. package/src/assets/icons.css +140 -0
  82. package/src/assets/loading-spinner.css +59 -0
  83. package/src/assets/ng-chat.component.default.css +106 -0
  84. package/src/assets/notification.png +0 -0
  85. package/src/assets/notification.wav +0 -0
  86. package/src/assets/themes/ng-chat.theme.dark.scss +71 -0
  87. package/src/assets/themes/ng-chat.theme.default.scss +63 -0
  88. package/src/assets/user.png +0 -0
@@ -0,0 +1,588 @@
1
+ /* eslint-disable */
2
+ import { Component, Input, ViewChildren, HostListener, Output, EventEmitter, ViewEncapsulation } from '@angular/core';
3
+ import { MessageType } from "../../core/message-type.enum";
4
+ import { Window } from "../../core/window";
5
+ import { ChatParticipantStatus } from "../../core/chat-participant-status.enum";
6
+ import { ScrollDirection } from "../../core/scroll-direction.enum";
7
+ import { PagedHistoryChatAdapter } from '../../core/paged-history-chat-adapter';
8
+ import { DefaultFileUploadAdapter } from '../../core/default-file-upload-adapter';
9
+ import { Theme } from '../../core/theme.enum';
10
+ import { Group } from "../../core/group";
11
+ import { ChatParticipantType } from "../../core/chat-participant-type.enum";
12
+ import { map } from 'rxjs/operators';
13
+ import * as i0 from "@angular/core";
14
+ import * as i1 from "@angular/common/http";
15
+ import * as i2 from "@angular/common";
16
+ import * as i3 from "../ng-chat-friends-list/ng-chat-friends-list.component";
17
+ import * as i4 from "../ng-chat-window/ng-chat-window.component";
18
+ import * as i5 from "../../pipes/sanitize.pipe";
19
+ export class NgChat {
20
+ constructor(_httpClient) {
21
+ this._httpClient = _httpClient;
22
+ // Exposes enums for the ng-template
23
+ this.ChatParticipantType = ChatParticipantType;
24
+ this.ChatParticipantStatus = ChatParticipantStatus;
25
+ this.MessageType = MessageType;
26
+ this._isDisabled = false;
27
+ this.isCollapsed = false;
28
+ this.maximizeWindowOnNewMessage = true;
29
+ this.pollFriendsList = false;
30
+ this.pollingInterval = 5000;
31
+ this.historyEnabled = true;
32
+ this.emojisEnabled = true;
33
+ this.linkfyEnabled = true;
34
+ this.audioEnabled = true;
35
+ this.searchEnabled = true;
36
+ this.audioSource = '../../../assets/notification.wav';
37
+ this.persistWindowsState = true;
38
+ this.title = "Quick chat";
39
+ this.messagePlaceholder = "Type a message";
40
+ this.searchPlaceholder = "Search";
41
+ this.browserNotificationsEnabled = true;
42
+ this.browserNotificationIconSource = '../../../assets/notification.png';
43
+ this.browserNotificationTitle = "New message from";
44
+ this.historyPageSize = 10;
45
+ this.hideFriendsList = false;
46
+ this.hideFriendsListOnUnsupportedViewport = true;
47
+ this.theme = Theme.Light;
48
+ this.messageDatePipeFormat = "short";
49
+ this.showMessageDate = true;
50
+ this.isViewportOnMobileEnabled = false;
51
+ this.onParticipantClicked = new EventEmitter();
52
+ this.onParticipantChatOpened = new EventEmitter();
53
+ this.onParticipantChatClosed = new EventEmitter();
54
+ this.onMessagesSeen = new EventEmitter();
55
+ this.onCloseWindowClicked = new EventEmitter();
56
+ this.browserNotificationsBootstrapped = false;
57
+ this.hasPagedHistory = false;
58
+ // Don't want to add this as a setting to simplify usage. Previous placeholder and title settings available to be used, or use full Localization object.
59
+ this.statusDescription = {
60
+ online: 'Online',
61
+ busy: 'Busy',
62
+ away: 'Away',
63
+ offline: 'Offline'
64
+ };
65
+ this.participantsInteractedWith = [];
66
+ // Defines the size of each opened window to calculate how many windows can be opened on the viewport at the same time.
67
+ this.windowSizeFactor = 320;
68
+ // Total width size of the friends list section
69
+ this.friendsListWidth = 262;
70
+ // Set to true if there is no space to display at least one chat window and 'hideFriendsListOnUnsupportedViewport' is true
71
+ this.unsupportedViewport = false;
72
+ this.windows = [];
73
+ this.isBootstrapped = false;
74
+ }
75
+ get isDisabled() {
76
+ return this._isDisabled;
77
+ }
78
+ set isDisabled(value) {
79
+ this._isDisabled = value;
80
+ if (value) {
81
+ window.clearInterval(this.pollingIntervalWindowInstance);
82
+ }
83
+ else {
84
+ this.activateFriendListFetch();
85
+ }
86
+ }
87
+ get localStorageKey() {
88
+ return `ng-chat-users-${this.userId}`; // Appending the user id so the state is unique per user in a computer.
89
+ }
90
+ ;
91
+ ngOnInit() {
92
+ this.bootstrapChat();
93
+ }
94
+ onResize(event) {
95
+ this.viewPortTotalArea = event.target.innerWidth;
96
+ this.NormalizeWindows();
97
+ }
98
+ // Checks if there are more opened windows than the view port can display
99
+ NormalizeWindows() {
100
+ const maxSupportedOpenedWindows = Math.floor((this.viewPortTotalArea - (!this.hideFriendsList ? this.friendsListWidth : 0)) / this.windowSizeFactor);
101
+ const difference = this.windows.length - maxSupportedOpenedWindows;
102
+ if (difference >= 0) {
103
+ this.windows.splice(this.windows.length - difference);
104
+ }
105
+ this.updateWindowsState(this.windows);
106
+ // Viewport should have space for at least one chat window but should show in mobile if option is enabled.
107
+ this.unsupportedViewport = this.isViewportOnMobileEnabled ? false : this.hideFriendsListOnUnsupportedViewport && maxSupportedOpenedWindows < 1;
108
+ }
109
+ // Initializes the chat plugin and the messaging adapter
110
+ bootstrapChat() {
111
+ let initializationException = null;
112
+ if (this.adapter != null && this.userId != null) {
113
+ try {
114
+ this.viewPortTotalArea = window.innerWidth;
115
+ this.initializeTheme();
116
+ this.initializeDefaultText();
117
+ this.initializeBrowserNotifications();
118
+ // Binding event listeners
119
+ this.adapter.messageReceivedHandler = (participant, msg) => this.onMessageReceived(participant, msg);
120
+ this.adapter.friendsListChangedHandler = (participantsResponse) => this.onFriendsListChanged(participantsResponse);
121
+ this.activateFriendListFetch();
122
+ this.bufferAudioFile();
123
+ this.hasPagedHistory = this.adapter instanceof PagedHistoryChatAdapter;
124
+ if (this.fileUploadUrl && this.fileUploadUrl !== "") {
125
+ this.fileUploadAdapter = new DefaultFileUploadAdapter(this.fileUploadUrl, this._httpClient);
126
+ }
127
+ this.NormalizeWindows();
128
+ this.isBootstrapped = true;
129
+ }
130
+ catch (ex) {
131
+ initializationException = ex;
132
+ }
133
+ }
134
+ if (!this.isBootstrapped) {
135
+ console.error("ng-chat component couldn't be bootstrapped.");
136
+ if (this.userId == null) {
137
+ console.error("ng-chat can't be initialized without an user id. Please make sure you've provided an userId as a parameter of the ng-chat component.");
138
+ }
139
+ if (this.adapter == null) {
140
+ console.error("ng-chat can't be bootstrapped without a ChatAdapter. Please make sure you've provided a ChatAdapter implementation as a parameter of the ng-chat component.");
141
+ }
142
+ if (initializationException) {
143
+ console.error(`An exception has occurred while initializing ng-chat. Details: ${initializationException.message}`);
144
+ console.error(initializationException);
145
+ }
146
+ }
147
+ }
148
+ activateFriendListFetch() {
149
+ if (this.adapter) {
150
+ // Loading current users list
151
+ if (this.pollFriendsList) {
152
+ // Setting a long poll interval to update the friends list
153
+ this.fetchFriendsList(true);
154
+ this.pollingIntervalWindowInstance = window.setInterval(() => this.fetchFriendsList(false), this.pollingInterval);
155
+ }
156
+ else {
157
+ // Since polling was disabled, a friends list update mechanism will have to be implemented in the ChatAdapter.
158
+ this.fetchFriendsList(true);
159
+ }
160
+ }
161
+ }
162
+ // Initializes browser notifications
163
+ async initializeBrowserNotifications() {
164
+ if (this.browserNotificationsEnabled && ("Notification" in window)) {
165
+ if (await Notification.requestPermission() === "granted") {
166
+ this.browserNotificationsBootstrapped = true;
167
+ }
168
+ }
169
+ }
170
+ // Initializes default text
171
+ initializeDefaultText() {
172
+ if (!this.localization) {
173
+ this.localization = {
174
+ messagePlaceholder: this.messagePlaceholder,
175
+ searchPlaceholder: this.searchPlaceholder,
176
+ title: this.title,
177
+ statusDescription: this.statusDescription,
178
+ browserNotificationTitle: this.browserNotificationTitle,
179
+ loadMessageHistoryPlaceholder: "Load older messages"
180
+ };
181
+ }
182
+ }
183
+ initializeTheme() {
184
+ if (this.customTheme) {
185
+ this.theme = Theme.Custom;
186
+ }
187
+ else if (this.theme != Theme.Light && this.theme != Theme.Dark) {
188
+ // TODO: Use es2017 in future with Object.values(Theme).includes(this.theme) to do this check
189
+ throw new Error(`Invalid theme configuration for ng-chat. "${this.theme}" is not a valid theme value.`);
190
+ }
191
+ }
192
+ // Sends a request to load the friends list
193
+ fetchFriendsList(isBootstrapping) {
194
+ this.adapter.listFriends()
195
+ .pipe(map((participantsResponse) => {
196
+ this.participantsResponse = participantsResponse;
197
+ this.participants = participantsResponse.map((response) => {
198
+ return response.participant;
199
+ });
200
+ })).subscribe(() => {
201
+ if (isBootstrapping) {
202
+ this.restoreWindowsState();
203
+ }
204
+ });
205
+ }
206
+ fetchMessageHistory(window) {
207
+ // Not ideal but will keep this until we decide if we are shipping pagination with the default adapter
208
+ if (this.adapter instanceof PagedHistoryChatAdapter) {
209
+ window.isLoadingHistory = true;
210
+ this.adapter.getMessageHistoryByPage(window.participant.id, this.historyPageSize, ++window.historyPage)
211
+ .pipe(map((result) => {
212
+ result.forEach((message) => this.assertMessageType(message));
213
+ window.messages = result.concat(window.messages);
214
+ window.isLoadingHistory = false;
215
+ const direction = (window.historyPage == 1) ? ScrollDirection.Bottom : ScrollDirection.Top;
216
+ window.hasMoreMessages = result.length == this.historyPageSize;
217
+ setTimeout(() => this.onFetchMessageHistoryLoaded(result, window, direction, true));
218
+ })).subscribe();
219
+ }
220
+ else {
221
+ this.adapter.getMessageHistory(window.participant.id)
222
+ .pipe(map((result) => {
223
+ result.forEach((message) => this.assertMessageType(message));
224
+ window.messages = result.concat(window.messages);
225
+ window.isLoadingHistory = false;
226
+ setTimeout(() => this.onFetchMessageHistoryLoaded(result, window, ScrollDirection.Bottom));
227
+ })).subscribe();
228
+ }
229
+ }
230
+ onFetchMessageHistoryLoaded(messages, window, direction, forceMarkMessagesAsSeen = false) {
231
+ this.scrollChatWindow(window, direction);
232
+ if (window.hasFocus || forceMarkMessagesAsSeen) {
233
+ const unseenMessages = messages.filter(m => !m.dateSeen);
234
+ this.markMessagesAsRead(unseenMessages);
235
+ }
236
+ }
237
+ // Updates the friends list via the event handler
238
+ onFriendsListChanged(participantsResponse) {
239
+ if (participantsResponse) {
240
+ this.participantsResponse = participantsResponse;
241
+ this.participants = participantsResponse.map((response) => {
242
+ return response.participant;
243
+ });
244
+ this.participantsInteractedWith = [];
245
+ }
246
+ }
247
+ // Handles received messages by the adapter
248
+ onMessageReceived(participant, message) {
249
+ if (participant && message) {
250
+ const chatWindow = this.openChatWindow(participant);
251
+ this.assertMessageType(message);
252
+ if (!chatWindow[1] || !this.historyEnabled) {
253
+ chatWindow[0].messages.push(message);
254
+ this.scrollChatWindow(chatWindow[0], ScrollDirection.Bottom);
255
+ if (chatWindow[0].hasFocus) {
256
+ this.markMessagesAsRead([message]);
257
+ }
258
+ }
259
+ this.emitMessageSound(chatWindow[0]);
260
+ // Do not push browser notifications with message content for privacy purposes if the 'maximizeWindowOnNewMessage' setting is off and this is a new chat window.
261
+ if (this.maximizeWindowOnNewMessage || (!chatWindow[1] && !chatWindow[0].isCollapsed)) {
262
+ // Some messages are not pushed because they are loaded by fetching the history hence why we supply the message here
263
+ this.emitBrowserNotification(chatWindow[0], message);
264
+ }
265
+ }
266
+ }
267
+ onParticipantClickedFromFriendsList(participant) {
268
+ this.openChatWindow(participant, true, true);
269
+ }
270
+ cancelOptionPrompt() {
271
+ if (this.currentActiveOption) {
272
+ this.currentActiveOption.isActive = false;
273
+ this.currentActiveOption = null;
274
+ }
275
+ }
276
+ onOptionPromptCanceled() {
277
+ this.cancelOptionPrompt();
278
+ }
279
+ onOptionPromptConfirmed(event) {
280
+ // For now this is fine as there is only one option available. Introduce option types and type checking if a new option is added.
281
+ this.confirmNewGroup(event);
282
+ // Canceling current state
283
+ this.cancelOptionPrompt();
284
+ }
285
+ confirmNewGroup(users) {
286
+ const newGroup = new Group(users);
287
+ this.openChatWindow(newGroup);
288
+ if (this.groupAdapter) {
289
+ this.groupAdapter.groupCreated(newGroup);
290
+ }
291
+ }
292
+ // Opens a new chat whindow. Takes care of available viewport
293
+ // Works for opening a chat window for an user or for a group
294
+ // Returns => [Window: Window object reference, boolean: Indicates if this window is a new chat window]
295
+ openChatWindow(participant, focusOnNewWindow = false, invokedByUserClick = false) {
296
+ // Is this window opened?
297
+ const openedWindow = this.windows.find(x => x.participant.id == participant.id);
298
+ if (!openedWindow) {
299
+ if (invokedByUserClick) {
300
+ this.onParticipantClicked.emit(participant);
301
+ }
302
+ // Refer to issue #58 on Github
303
+ const collapseWindow = invokedByUserClick ? false : !this.maximizeWindowOnNewMessage;
304
+ const newChatWindow = new Window(participant, this.historyEnabled, collapseWindow);
305
+ // Loads the chat history via an RxJs Observable
306
+ if (this.historyEnabled) {
307
+ this.fetchMessageHistory(newChatWindow);
308
+ }
309
+ this.windows.unshift(newChatWindow);
310
+ // Is there enough space left in the view port ? but should be displayed in mobile if option is enabled
311
+ if (!this.isViewportOnMobileEnabled) {
312
+ if (this.windows.length * this.windowSizeFactor >= this.viewPortTotalArea - (!this.hideFriendsList ? this.friendsListWidth : 0)) {
313
+ this.windows.pop();
314
+ }
315
+ }
316
+ this.updateWindowsState(this.windows);
317
+ if (focusOnNewWindow && !collapseWindow) {
318
+ this.focusOnWindow(newChatWindow);
319
+ }
320
+ this.participantsInteractedWith.push(participant);
321
+ this.onParticipantChatOpened.emit(participant);
322
+ return [newChatWindow, true];
323
+ }
324
+ else {
325
+ // Returns the existing chat window
326
+ return [openedWindow, false];
327
+ }
328
+ }
329
+ // Focus on the input element of the supplied window
330
+ focusOnWindow(window, callback = () => { }) {
331
+ const windowIndex = this.windows.indexOf(window);
332
+ if (windowIndex >= 0) {
333
+ setTimeout(() => {
334
+ if (this.chatWindows) {
335
+ const chatWindowToFocus = this.chatWindows.toArray()[windowIndex];
336
+ chatWindowToFocus.chatWindowInput.nativeElement.focus();
337
+ }
338
+ callback();
339
+ });
340
+ }
341
+ }
342
+ assertMessageType(message) {
343
+ // Always fallback to "Text" messages to avoid rendenring issues
344
+ if (!message.type) {
345
+ message.type = MessageType.Text;
346
+ }
347
+ }
348
+ // Marks all messages provided as read with the current time.
349
+ markMessagesAsRead(messages) {
350
+ const currentDate = new Date();
351
+ messages.forEach((msg) => {
352
+ msg.dateSeen = currentDate;
353
+ });
354
+ this.onMessagesSeen.emit(messages);
355
+ }
356
+ // Buffers audio file (For component's bootstrapping)
357
+ bufferAudioFile() {
358
+ if (this.audioSource && this.audioSource.length > 0) {
359
+ this.audioFile = new Audio();
360
+ this.audioFile.src = this.audioSource;
361
+ this.audioFile.load();
362
+ }
363
+ }
364
+ // Emits a message notification audio if enabled after every message received
365
+ emitMessageSound(window) {
366
+ if (this.audioEnabled && !window.hasFocus && this.audioFile) {
367
+ this.audioFile.play();
368
+ }
369
+ }
370
+ // Emits a browser notification
371
+ emitBrowserNotification(window, message) {
372
+ // if (this.browserNotificationsBootstrapped && !window.hasFocus && message) {
373
+ if (this.browserNotificationsBootstrapped && message) {
374
+ const notification = new Notification(`${this.localization.browserNotificationTitle} ${window.participant.displayName}`, {
375
+ 'body': message.message,
376
+ 'icon': this.browserNotificationIconSource
377
+ });
378
+ setTimeout(() => {
379
+ notification.close();
380
+ }, message.message.length <= 50 ? 5000 : 7000); // More time to read longer messages
381
+ }
382
+ }
383
+ // Saves current windows state into local storage if persistence is enabled
384
+ updateWindowsState(windows) {
385
+ if (this.persistWindowsState) {
386
+ const participantIds = windows.map((w) => {
387
+ return w.participant.id;
388
+ });
389
+ localStorage.setItem(this.localStorageKey, JSON.stringify(participantIds));
390
+ }
391
+ }
392
+ restoreWindowsState() {
393
+ try {
394
+ if (this.persistWindowsState) {
395
+ const stringfiedParticipantIds = localStorage.getItem(this.localStorageKey);
396
+ if (stringfiedParticipantIds && stringfiedParticipantIds.length > 0) {
397
+ const participantIds = JSON.parse(stringfiedParticipantIds);
398
+ const participantsToRestore = this.participants.filter(u => participantIds.indexOf(u.id) >= 0);
399
+ participantsToRestore.forEach((participant) => {
400
+ this.openChatWindow(participant);
401
+ });
402
+ }
403
+ }
404
+ }
405
+ catch (ex) {
406
+ console.error(`An error occurred while restoring ng-chat windows state. Details: ${ex}`);
407
+ }
408
+ }
409
+ // Gets closest open window if any. Most recent opened has priority (Right)
410
+ getClosestWindow(window) {
411
+ const index = this.windows.indexOf(window);
412
+ if (index > 0) {
413
+ return this.windows[index - 1];
414
+ }
415
+ else if (index == 0 && this.windows.length > 1) {
416
+ return this.windows[index + 1];
417
+ }
418
+ }
419
+ closeWindow(window) {
420
+ const index = this.windows.indexOf(window);
421
+ this.windows.splice(index, 1);
422
+ this.updateWindowsState(this.windows);
423
+ this.onParticipantChatClosed.emit(window.participant);
424
+ }
425
+ getChatWindowComponentInstance(targetWindow) {
426
+ const windowIndex = this.windows.indexOf(targetWindow);
427
+ if (this.chatWindows) {
428
+ let targetWindow = this.chatWindows.toArray()[windowIndex];
429
+ return targetWindow;
430
+ }
431
+ return null;
432
+ }
433
+ // Scrolls a chat window message flow to the bottom
434
+ scrollChatWindow(window, direction) {
435
+ const chatWindow = this.getChatWindowComponentInstance(window);
436
+ if (chatWindow) {
437
+ chatWindow.scrollChatWindow(window, direction);
438
+ }
439
+ }
440
+ onWindowMessagesSeen(messagesSeen) {
441
+ this.markMessagesAsRead(messagesSeen);
442
+ }
443
+ onWindowChatClosed(payload) {
444
+ const { closedWindow, closedViaEscapeKey } = payload;
445
+ if (closedViaEscapeKey) {
446
+ let closestWindow = this.getClosestWindow(closedWindow);
447
+ if (closestWindow) {
448
+ this.focusOnWindow(closestWindow, () => { this.closeWindow(closedWindow); });
449
+ }
450
+ else {
451
+ this.closeWindow(closedWindow);
452
+ }
453
+ }
454
+ else {
455
+ this.closeWindow(closedWindow);
456
+ }
457
+ }
458
+ onWindowTabTriggered(payload) {
459
+ const { triggeringWindow, shiftKeyPressed } = payload;
460
+ const currentWindowIndex = this.windows.indexOf(triggeringWindow);
461
+ let windowToFocus = this.windows[currentWindowIndex + (shiftKeyPressed ? 1 : -1)]; // Goes back on shift + tab
462
+ if (!windowToFocus) {
463
+ // Edge windows, go to start or end
464
+ windowToFocus = this.windows[currentWindowIndex > 0 ? 0 : this.chatWindows.length - 1];
465
+ }
466
+ this.focusOnWindow(windowToFocus);
467
+ }
468
+ onWindowMessageSent(messageSent) {
469
+ this.adapter.sendMessage(messageSent);
470
+ }
471
+ onWindowOptionTriggered(option) {
472
+ this.currentActiveOption = option;
473
+ }
474
+ triggerOpenChatWindow(user) {
475
+ if (user) {
476
+ this.openChatWindow(user);
477
+ }
478
+ }
479
+ triggerCloseChatWindow(userId) {
480
+ const openedWindow = this.windows.find(x => x.participant.id == userId);
481
+ if (openedWindow) {
482
+ this.closeWindow(openedWindow);
483
+ }
484
+ }
485
+ triggerToggleChatWindowVisibility(userId) {
486
+ const openedWindow = this.windows.find(x => x.participant.id == userId);
487
+ if (openedWindow) {
488
+ const chatWindow = this.getChatWindowComponentInstance(openedWindow);
489
+ if (chatWindow) {
490
+ chatWindow.onChatWindowClicked(openedWindow);
491
+ }
492
+ }
493
+ }
494
+ // closeFriendList(){
495
+ // this.hideFriendsList = !this.hideFriendsList
496
+ // this.hideFriendsListChange.emit(this.hideFriendsList)
497
+ // }
498
+ onCloseWindowClick(click) {
499
+ this.onCloseWindowClicked.emit(click);
500
+ }
501
+ }
502
+ NgChat.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: NgChat, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Component });
503
+ NgChat.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: NgChat, selector: "mnl-chat", inputs: { isDisabled: "isDisabled", adapter: "adapter", groupAdapter: "groupAdapter", userId: "userId", isCollapsed: "isCollapsed", maximizeWindowOnNewMessage: "maximizeWindowOnNewMessage", pollFriendsList: "pollFriendsList", pollingInterval: "pollingInterval", historyEnabled: "historyEnabled", emojisEnabled: "emojisEnabled", linkfyEnabled: "linkfyEnabled", audioEnabled: "audioEnabled", searchEnabled: "searchEnabled", audioSource: "audioSource", persistWindowsState: "persistWindowsState", title: "title", messagePlaceholder: "messagePlaceholder", searchPlaceholder: "searchPlaceholder", browserNotificationsEnabled: "browserNotificationsEnabled", browserNotificationIconSource: "browserNotificationIconSource", browserNotificationTitle: "browserNotificationTitle", historyPageSize: "historyPageSize", localization: "localization", hideFriendsList: "hideFriendsList", hideFriendsListOnUnsupportedViewport: "hideFriendsListOnUnsupportedViewport", fileUploadUrl: "fileUploadUrl", theme: "theme", customTheme: "customTheme", messageDatePipeFormat: "messageDatePipeFormat", showMessageDate: "showMessageDate", isViewportOnMobileEnabled: "isViewportOnMobileEnabled", fileUploadAdapter: "fileUploadAdapter" }, outputs: { onParticipantClicked: "onParticipantClicked", onParticipantChatOpened: "onParticipantChatOpened", onParticipantChatClosed: "onParticipantChatClosed", onMessagesSeen: "onMessagesSeen", onCloseWindowClicked: "onCloseWindowClicked" }, host: { listeners: { "window:resize": "onResize($event)" } }, viewQueries: [{ propertyName: "chatWindows", predicate: ["chatWindow"], descendants: true }], ngImport: i0, template: "<link *ngIf=\"customTheme\" rel=\"stylesheet\" [href]='customTheme | sanitize'>\n\n<div id=\"ng-chat\" *ngIf=\"!isDisabled && isBootstrapped && !unsupportedViewport\" [ngClass]=\"theme\">\n <ng-chat-friends-list\n [localization]=\"localization\"\n [shouldDisplay]=\"!hideFriendsList\"\n [userId]=\"userId\"\n [isCollapsed]=\"isCollapsed\"\n [searchEnabled]=\"searchEnabled\"\n [participants]=\"participants\"\n [participantsResponse]=\"participantsResponse\"\n [participantsInteractedWith]=\"participantsInteractedWith\"\n [windows]=\"windows\"\n [currentActiveOption]=\"currentActiveOption\"\n (onParticipantClicked)=\"onParticipantClickedFromFriendsList($event)\"\n (onOptionPromptCanceled)=\"onOptionPromptCanceled()\"\n (onOptionPromptConfirmed)=\"onOptionPromptConfirmed($event)\"\n (onCloseWindowClick)=\"onCloseWindowClick($event)\"\n >\n </ng-chat-friends-list>\n\n <div *ngFor=\"let window of windows; let i = index\" [ngClass]=\"{'ng-chat-window': true, 'primary-outline-color': true, 'ng-chat-window-collapsed': window.isCollapsed}\" [ngStyle]=\"{'right': (!hideFriendsList ? friendsListWidth : 0) + 20 + windowSizeFactor * i + 'px'}\">\n <ng-chat-window\n #chatWindow\n [fileUploadAdapter]=\"fileUploadAdapter\"\n [localization]=\"localization\"\n [userId]=\"userId\"\n [window]=\"window\"\n [showOptions]=\"groupAdapter\"\n [emojisEnabled]=\"emojisEnabled\"\n [linkfyEnabled]=\"linkfyEnabled\"\n [showMessageDate]=\"showMessageDate\"\n [messageDatePipeFormat]=\"messageDatePipeFormat\"\n [hasPagedHistory]=\"hasPagedHistory\"\n (onMessagesSeen)=\"onWindowMessagesSeen($event)\"\n (onMessageSent)=\"onWindowMessageSent($event)\"\n (onTabTriggered)=\"onWindowTabTriggered($event)\"\n (onChatWindowClosed)=\"onWindowChatClosed($event)\"\n (onOptionTriggered)=\"onWindowOptionTriggered($event)\"\n (onLoadHistoryTriggered)=\"fetchMessageHistory($event)\"\n >\n </ng-chat-window>\n </div>\n</div>\n", styles: [".user-icon{box-sizing:border-box;background-color:#fff;border:2px solid;width:32px;height:20px;border-radius:64px 64px 0 0/64px;margin-top:14px;margin-left:-1px;display:inline-block;vertical-align:middle;position:relative;font-style:normal;color:#ddd;text-align:left;text-indent:-9999px}.user-icon:before{border:2px solid;background-color:#fff;width:12px;height:12px;top:-19px;border-radius:50%;position:absolute;left:50%;transform:translate(-50%)}.user-icon:before,.user-icon:after{content:\"\";pointer-events:none}.upload-icon{position:absolute;margin-left:3px;margin-top:12px;width:13px;height:4px;border:solid 1px currentColor;border-top:none;border-radius:1px}.upload-icon:before{content:\"\";position:absolute;top:-8px;left:6px;width:1px;height:9px;background-color:currentColor}.upload-icon:after{content:\"\";position:absolute;top:-8px;left:4px;width:4px;height:4px;border-top:solid 1px currentColor;border-right:solid 1px currentColor;transform:rotate(-45deg)}.paperclip-icon{position:absolute;margin-left:9px;margin-top:2px;width:6px;height:12px;border-radius:4px 4px 0 0;border-left:solid 1px currentColor;border-right:solid 1px currentColor;border-top:solid 1px currentColor;transform:rotate(45deg)}.paperclip-icon:before{content:\"\";position:absolute;top:11px;left:-1px;width:4px;height:6px;border-radius:0 0 3px 3px;border-left:solid 1px currentColor;border-right:solid 1px currentColor;border-bottom:solid 1px currentColor}.paperclip-icon:after{content:\"\";position:absolute;left:1px;top:1px;width:2px;height:10px;border-radius:4px 4px 0 0;border-left:solid 1px currentColor;border-right:solid 1px currentColor;border-top:solid 1px currentColor}.check-icon{color:#000;position:absolute;margin-left:3px;margin-top:4px;width:14px;height:8px;border-bottom:solid 1px currentColor;border-left:solid 1px currentColor;transform:rotate(-45deg)}.remove-icon{color:#000;position:absolute;margin-left:3px;margin-top:10px}.remove-icon:before{content:\"\";position:absolute;width:15px;height:1px;background-color:currentColor;transform:rotate(45deg)}.remove-icon:after{content:\"\";position:absolute;width:15px;height:1px;background-color:currentColor;transform:rotate(-45deg)}\n", ".loader,.loader:before,.loader:after{background:#E3E3E3;animation:load1 1s infinite ease-in-out;width:1em;height:4em}.loader{color:#e3e3e3;text-indent:-9999em;margin:4px auto 0;position:relative;font-size:4px;transform:translateZ(0);animation-delay:-.16s}.loader:before,.loader:after{position:absolute;top:0;content:\"\"}.loader:before{left:-1.5em;animation-delay:-.32s}.loader:after{left:1.5em}@keyframes load1{0%,80%,to{box-shadow:0 0;height:4em}40%{box-shadow:0 -2em;height:5em}}\n", "#ng-chat{position:fixed;z-index:999;right:0;bottom:0;box-sizing:initial;font-size:11pt;text-align:left}#ng-chat input{outline:none}#ng-chat .shadowed{box-shadow:0 4px 8px #00000040}.ng-chat-loading-wrapper{height:30px;text-align:center;font-size:.9em}.ng-chat-close{text-decoration:none!important;color:red!important;float:right!important;font-weight:900!important;font-size:15px!important}.ng-chat-title,.ng-chat-title:hover{position:relative;z-index:2;height:30px;line-height:30px;font-size:.9em;padding:0 10px;display:block;text-decoration:none;color:#fff!important;font-weight:600!important;cursor:pointer;background-color:#1b1b70!important}.ng-chat-title .ng-chat-title-visibility-toggle-area{display:inline-block;width:85%}.ng-chat-title .ng-chat-title-visibility-toggle-area>strong{font-weight:600;display:block;overflow:hidden;height:30px;text-overflow:ellipsis;white-space:nowrap;max-width:85%;float:left}.ng-chat-title .ng-chat-title-visibility-toggle-area .ng-chat-participant-status{float:left;margin-left:5px}.ng-chat-participant-status{display:inline-block;border-radius:25px;width:8px;height:8px;margin-top:10px}.ng-chat-participant-status.online{background-color:#92a400}.ng-chat-participant-status.busy{background-color:#f91c1e}.ng-chat-participant-status.away{background-color:#f7d21b}.ng-chat-participant-status.offline{background-color:#bababa}.ng-chat-unread-messages-count{margin-left:5px;padding:0 5px;border-radius:25px;font-size:.9em;line-height:30px}.ng-chat-options-container{float:right;margin-right:5px}\n", "#ng-chat.light-theme .primary-text,#ng-chat.light-theme{color:#5c5c5c;font-family:Arial,Helvetica,sans-serif}#ng-chat.light-theme .primary-background{background-color:#fff}#ng-chat.light-theme .secondary-background{background-color:#fafafa}#ng-chat.light-theme .primary-outline-color{border-color:#a3a3a3}#ng-chat.light-theme .friends-search-bar{background-color:#fff}#ng-chat.light-theme .unread-messages-counter-container,#ng-chat.light-theme .ng-chat-people-action,#ng-chat.light-theme .ng-chat-people-action>i{color:#5c5c5c;background-color:#e3e3e3}#ng-chat.light-theme .load-history-action{background-color:#e3e3e3}#ng-chat.light-theme .chat-window-input{background-color:#fff}#ng-chat.light-theme .sent-chat-message-container,#ng-chat.light-theme .file-message-container{background-color:#e3e3e3;border-color:#e3e3e3}#ng-chat.light-theme .received-chat-message-container,#ng-chat.light-theme .file-message-container.received{background-color:#fff;border-color:#e3e3e3}body{font-family:Roboto,Helvetica Neue,sans-serif!important}*{box-shadow:none!important}\n", "#ng-chat.dark-theme .primary-text,#ng-chat.dark-theme{color:#fff;font-family:Arial,Helvetica,sans-serif}#ng-chat.dark-theme .primary-background{background-color:#565656}#ng-chat.dark-theme .secondary-background{background-color:#444}#ng-chat.dark-theme .primary-outline-color{border-color:#353535}#ng-chat.dark-theme .friends-search-bar{background-color:#444;border:1px solid #444;color:#fff}#ng-chat.dark-theme .unread-messages-counter-container,#ng-chat.dark-theme .ng-chat-people-action,#ng-chat.dark-theme .ng-chat-people-action>i{background-color:#fff;color:#444}#ng-chat.dark-theme .load-history-action{background-color:#444}#ng-chat.dark-theme .chat-window-input{background-color:#444;color:#fff}#ng-chat.dark-theme .sent-chat-message-container,#ng-chat.dark-theme .file-message-container{border-color:#444;background-color:#444}#ng-chat.dark-theme .received-chat-message-container,#ng-chat.dark-theme .file-message-container.received{background-color:#565656;border-color:#444}#ng-chat.dark-theme .ng-chat-footer{background-color:#444}#ng-chat.dark-theme .ng-chat-message a{color:#fff}body{font-family:Roboto,Helvetica Neue,sans-serif!important}\n"], dependencies: [{ 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: "directive", type: i2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: i3.NgChatFriendsListComponent, selector: "ng-chat-friends-list", inputs: ["participants", "participantsResponse", "participantsInteractedWith", "windows", "userId", "localization", "shouldDisplay", "isCollapsed", "searchEnabled", "currentActiveOption", "hideFriendsList"], outputs: ["onParticipantClicked", "onOptionPromptCanceled", "onOptionPromptConfirmed", "onCloseWindowClick"] }, { kind: "component", type: i4.NgChatWindowComponent, selector: "ng-chat-window", inputs: ["fileUploadAdapter", "window", "userId", "localization", "showOptions", "emojisEnabled", "linkfyEnabled", "showMessageDate", "messageDatePipeFormat", "hasPagedHistory"], outputs: ["onChatWindowClosed", "onMessagesSeen", "onMessageSent", "onTabTriggered", "onOptionTriggered", "onLoadHistoryTriggered"] }, { kind: "pipe", type: i5.SanitizePipe, name: "sanitize" }], encapsulation: i0.ViewEncapsulation.None });
504
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: NgChat, decorators: [{
505
+ type: Component,
506
+ args: [{ selector: 'mnl-chat', encapsulation: ViewEncapsulation.None, template: "<link *ngIf=\"customTheme\" rel=\"stylesheet\" [href]='customTheme | sanitize'>\n\n<div id=\"ng-chat\" *ngIf=\"!isDisabled && isBootstrapped && !unsupportedViewport\" [ngClass]=\"theme\">\n <ng-chat-friends-list\n [localization]=\"localization\"\n [shouldDisplay]=\"!hideFriendsList\"\n [userId]=\"userId\"\n [isCollapsed]=\"isCollapsed\"\n [searchEnabled]=\"searchEnabled\"\n [participants]=\"participants\"\n [participantsResponse]=\"participantsResponse\"\n [participantsInteractedWith]=\"participantsInteractedWith\"\n [windows]=\"windows\"\n [currentActiveOption]=\"currentActiveOption\"\n (onParticipantClicked)=\"onParticipantClickedFromFriendsList($event)\"\n (onOptionPromptCanceled)=\"onOptionPromptCanceled()\"\n (onOptionPromptConfirmed)=\"onOptionPromptConfirmed($event)\"\n (onCloseWindowClick)=\"onCloseWindowClick($event)\"\n >\n </ng-chat-friends-list>\n\n <div *ngFor=\"let window of windows; let i = index\" [ngClass]=\"{'ng-chat-window': true, 'primary-outline-color': true, 'ng-chat-window-collapsed': window.isCollapsed}\" [ngStyle]=\"{'right': (!hideFriendsList ? friendsListWidth : 0) + 20 + windowSizeFactor * i + 'px'}\">\n <ng-chat-window\n #chatWindow\n [fileUploadAdapter]=\"fileUploadAdapter\"\n [localization]=\"localization\"\n [userId]=\"userId\"\n [window]=\"window\"\n [showOptions]=\"groupAdapter\"\n [emojisEnabled]=\"emojisEnabled\"\n [linkfyEnabled]=\"linkfyEnabled\"\n [showMessageDate]=\"showMessageDate\"\n [messageDatePipeFormat]=\"messageDatePipeFormat\"\n [hasPagedHistory]=\"hasPagedHistory\"\n (onMessagesSeen)=\"onWindowMessagesSeen($event)\"\n (onMessageSent)=\"onWindowMessageSent($event)\"\n (onTabTriggered)=\"onWindowTabTriggered($event)\"\n (onChatWindowClosed)=\"onWindowChatClosed($event)\"\n (onOptionTriggered)=\"onWindowOptionTriggered($event)\"\n (onLoadHistoryTriggered)=\"fetchMessageHistory($event)\"\n >\n </ng-chat-window>\n </div>\n</div>\n", styles: [".user-icon{box-sizing:border-box;background-color:#fff;border:2px solid;width:32px;height:20px;border-radius:64px 64px 0 0/64px;margin-top:14px;margin-left:-1px;display:inline-block;vertical-align:middle;position:relative;font-style:normal;color:#ddd;text-align:left;text-indent:-9999px}.user-icon:before{border:2px solid;background-color:#fff;width:12px;height:12px;top:-19px;border-radius:50%;position:absolute;left:50%;transform:translate(-50%)}.user-icon:before,.user-icon:after{content:\"\";pointer-events:none}.upload-icon{position:absolute;margin-left:3px;margin-top:12px;width:13px;height:4px;border:solid 1px currentColor;border-top:none;border-radius:1px}.upload-icon:before{content:\"\";position:absolute;top:-8px;left:6px;width:1px;height:9px;background-color:currentColor}.upload-icon:after{content:\"\";position:absolute;top:-8px;left:4px;width:4px;height:4px;border-top:solid 1px currentColor;border-right:solid 1px currentColor;transform:rotate(-45deg)}.paperclip-icon{position:absolute;margin-left:9px;margin-top:2px;width:6px;height:12px;border-radius:4px 4px 0 0;border-left:solid 1px currentColor;border-right:solid 1px currentColor;border-top:solid 1px currentColor;transform:rotate(45deg)}.paperclip-icon:before{content:\"\";position:absolute;top:11px;left:-1px;width:4px;height:6px;border-radius:0 0 3px 3px;border-left:solid 1px currentColor;border-right:solid 1px currentColor;border-bottom:solid 1px currentColor}.paperclip-icon:after{content:\"\";position:absolute;left:1px;top:1px;width:2px;height:10px;border-radius:4px 4px 0 0;border-left:solid 1px currentColor;border-right:solid 1px currentColor;border-top:solid 1px currentColor}.check-icon{color:#000;position:absolute;margin-left:3px;margin-top:4px;width:14px;height:8px;border-bottom:solid 1px currentColor;border-left:solid 1px currentColor;transform:rotate(-45deg)}.remove-icon{color:#000;position:absolute;margin-left:3px;margin-top:10px}.remove-icon:before{content:\"\";position:absolute;width:15px;height:1px;background-color:currentColor;transform:rotate(45deg)}.remove-icon:after{content:\"\";position:absolute;width:15px;height:1px;background-color:currentColor;transform:rotate(-45deg)}\n", ".loader,.loader:before,.loader:after{background:#E3E3E3;animation:load1 1s infinite ease-in-out;width:1em;height:4em}.loader{color:#e3e3e3;text-indent:-9999em;margin:4px auto 0;position:relative;font-size:4px;transform:translateZ(0);animation-delay:-.16s}.loader:before,.loader:after{position:absolute;top:0;content:\"\"}.loader:before{left:-1.5em;animation-delay:-.32s}.loader:after{left:1.5em}@keyframes load1{0%,80%,to{box-shadow:0 0;height:4em}40%{box-shadow:0 -2em;height:5em}}\n", "#ng-chat{position:fixed;z-index:999;right:0;bottom:0;box-sizing:initial;font-size:11pt;text-align:left}#ng-chat input{outline:none}#ng-chat .shadowed{box-shadow:0 4px 8px #00000040}.ng-chat-loading-wrapper{height:30px;text-align:center;font-size:.9em}.ng-chat-close{text-decoration:none!important;color:red!important;float:right!important;font-weight:900!important;font-size:15px!important}.ng-chat-title,.ng-chat-title:hover{position:relative;z-index:2;height:30px;line-height:30px;font-size:.9em;padding:0 10px;display:block;text-decoration:none;color:#fff!important;font-weight:600!important;cursor:pointer;background-color:#1b1b70!important}.ng-chat-title .ng-chat-title-visibility-toggle-area{display:inline-block;width:85%}.ng-chat-title .ng-chat-title-visibility-toggle-area>strong{font-weight:600;display:block;overflow:hidden;height:30px;text-overflow:ellipsis;white-space:nowrap;max-width:85%;float:left}.ng-chat-title .ng-chat-title-visibility-toggle-area .ng-chat-participant-status{float:left;margin-left:5px}.ng-chat-participant-status{display:inline-block;border-radius:25px;width:8px;height:8px;margin-top:10px}.ng-chat-participant-status.online{background-color:#92a400}.ng-chat-participant-status.busy{background-color:#f91c1e}.ng-chat-participant-status.away{background-color:#f7d21b}.ng-chat-participant-status.offline{background-color:#bababa}.ng-chat-unread-messages-count{margin-left:5px;padding:0 5px;border-radius:25px;font-size:.9em;line-height:30px}.ng-chat-options-container{float:right;margin-right:5px}\n", "#ng-chat.light-theme .primary-text,#ng-chat.light-theme{color:#5c5c5c;font-family:Arial,Helvetica,sans-serif}#ng-chat.light-theme .primary-background{background-color:#fff}#ng-chat.light-theme .secondary-background{background-color:#fafafa}#ng-chat.light-theme .primary-outline-color{border-color:#a3a3a3}#ng-chat.light-theme .friends-search-bar{background-color:#fff}#ng-chat.light-theme .unread-messages-counter-container,#ng-chat.light-theme .ng-chat-people-action,#ng-chat.light-theme .ng-chat-people-action>i{color:#5c5c5c;background-color:#e3e3e3}#ng-chat.light-theme .load-history-action{background-color:#e3e3e3}#ng-chat.light-theme .chat-window-input{background-color:#fff}#ng-chat.light-theme .sent-chat-message-container,#ng-chat.light-theme .file-message-container{background-color:#e3e3e3;border-color:#e3e3e3}#ng-chat.light-theme .received-chat-message-container,#ng-chat.light-theme .file-message-container.received{background-color:#fff;border-color:#e3e3e3}body{font-family:Roboto,Helvetica Neue,sans-serif!important}*{box-shadow:none!important}\n", "#ng-chat.dark-theme .primary-text,#ng-chat.dark-theme{color:#fff;font-family:Arial,Helvetica,sans-serif}#ng-chat.dark-theme .primary-background{background-color:#565656}#ng-chat.dark-theme .secondary-background{background-color:#444}#ng-chat.dark-theme .primary-outline-color{border-color:#353535}#ng-chat.dark-theme .friends-search-bar{background-color:#444;border:1px solid #444;color:#fff}#ng-chat.dark-theme .unread-messages-counter-container,#ng-chat.dark-theme .ng-chat-people-action,#ng-chat.dark-theme .ng-chat-people-action>i{background-color:#fff;color:#444}#ng-chat.dark-theme .load-history-action{background-color:#444}#ng-chat.dark-theme .chat-window-input{background-color:#444;color:#fff}#ng-chat.dark-theme .sent-chat-message-container,#ng-chat.dark-theme .file-message-container{border-color:#444;background-color:#444}#ng-chat.dark-theme .received-chat-message-container,#ng-chat.dark-theme .file-message-container.received{background-color:#565656;border-color:#444}#ng-chat.dark-theme .ng-chat-footer{background-color:#444}#ng-chat.dark-theme .ng-chat-message a{color:#fff}body{font-family:Roboto,Helvetica Neue,sans-serif!important}\n"] }]
507
+ }], ctorParameters: function () { return [{ type: i1.HttpClient }]; }, propDecorators: { isDisabled: [{
508
+ type: Input
509
+ }], adapter: [{
510
+ type: Input
511
+ }], groupAdapter: [{
512
+ type: Input
513
+ }], userId: [{
514
+ type: Input
515
+ }], isCollapsed: [{
516
+ type: Input
517
+ }], maximizeWindowOnNewMessage: [{
518
+ type: Input
519
+ }], pollFriendsList: [{
520
+ type: Input
521
+ }], pollingInterval: [{
522
+ type: Input
523
+ }], historyEnabled: [{
524
+ type: Input
525
+ }], emojisEnabled: [{
526
+ type: Input
527
+ }], linkfyEnabled: [{
528
+ type: Input
529
+ }], audioEnabled: [{
530
+ type: Input
531
+ }], searchEnabled: [{
532
+ type: Input
533
+ }], audioSource: [{
534
+ type: Input
535
+ }], persistWindowsState: [{
536
+ type: Input
537
+ }], title: [{
538
+ type: Input
539
+ }], messagePlaceholder: [{
540
+ type: Input
541
+ }], searchPlaceholder: [{
542
+ type: Input
543
+ }], browserNotificationsEnabled: [{
544
+ type: Input
545
+ }], browserNotificationIconSource: [{
546
+ type: Input
547
+ }], browserNotificationTitle: [{
548
+ type: Input
549
+ }], historyPageSize: [{
550
+ type: Input
551
+ }], localization: [{
552
+ type: Input
553
+ }], hideFriendsList: [{
554
+ type: Input
555
+ }], hideFriendsListOnUnsupportedViewport: [{
556
+ type: Input
557
+ }], fileUploadUrl: [{
558
+ type: Input
559
+ }], theme: [{
560
+ type: Input
561
+ }], customTheme: [{
562
+ type: Input
563
+ }], messageDatePipeFormat: [{
564
+ type: Input
565
+ }], showMessageDate: [{
566
+ type: Input
567
+ }], isViewportOnMobileEnabled: [{
568
+ type: Input
569
+ }], fileUploadAdapter: [{
570
+ type: Input
571
+ }], onParticipantClicked: [{
572
+ type: Output
573
+ }], onParticipantChatOpened: [{
574
+ type: Output
575
+ }], onParticipantChatClosed: [{
576
+ type: Output
577
+ }], onMessagesSeen: [{
578
+ type: Output
579
+ }], onCloseWindowClicked: [{
580
+ type: Output
581
+ }], chatWindows: [{
582
+ type: ViewChildren,
583
+ args: ['chatWindow']
584
+ }], onResize: [{
585
+ type: HostListener,
586
+ args: ['window:resize', ['$event']]
587
+ }] } });
588
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmctY2hhdC5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9jaGF0L3NyYy9saWIvY29tcG9uZW50cy9uZy1jaGF0L25nLWNoYXQuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvY2hhdC9zcmMvbGliL2NvbXBvbmVudHMvbmctY2hhdC9uZy1jaGF0LmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLG9CQUFvQjtBQUNwQixPQUFPLEVBQUUsU0FBUyxFQUFFLEtBQUssRUFBVSxZQUFZLEVBQWEsWUFBWSxFQUFFLE1BQU0sRUFBRSxZQUFZLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFPekksT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBQzNELE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQztBQUMzQyxPQUFPLEVBQUUscUJBQXFCLEVBQUUsTUFBTSx5Q0FBeUMsQ0FBQztBQUNoRixPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sa0NBQWtDLENBQUM7QUFHbkUsT0FBTyxFQUFFLHVCQUF1QixFQUFFLE1BQU0sdUNBQXVDLENBQUM7QUFFaEYsT0FBTyxFQUFFLHdCQUF3QixFQUFFLE1BQU0sd0NBQXdDLENBQUM7QUFDbEYsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBRTlDLE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUN6QyxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSx1Q0FBdUMsQ0FBQztBQUU1RSxPQUFPLEVBQUUsR0FBRyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7Ozs7Ozs7QUFpQnJDLE1BQU0sT0FBTyxNQUFNO0lBQ2YsWUFBb0IsV0FBdUI7UUFBdkIsZ0JBQVcsR0FBWCxXQUFXLENBQVk7UUFFM0Msb0NB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QixLQUFLO2dCQUlDLFlBQVk7c0JBRGxCLEtBQUs7Z0JBSUMsZUFBZTtzQkFEckIsS0FBSztnQkFJQyxvQ0FBb0M7c0JBRDFDLEtBQUs7Z0JBSUMsYUFBYTtzQkFEbkIsS0FBSztnQkFJQyxLQUFLO3NCQURYLEtBQUs7Z0JBSUMsV0FBVztzQkFEakIsS0FBSztnQkFJQyxxQkFBcUI7c0JBRDNCLEtBQUs7Z0JBSUMsZUFBZTtzQkFEckIsS0FBSztnQkFJQyx5QkFBeUI7c0JBRC9CLEtBQUs7Z0JBSUMsaUJBQWlCO3NCQUR2QixLQUFLO2dCQUlDLG9CQUFvQjtzQkFEMUIsTUFBTTtnQkFJQSx1QkFBdUI7c0JBRDdCLE1BQU07Z0JBSUEsdUJBQXVCO3NCQUQ3QixNQUFNO2dCQUlBLGNBQWM7c0JBRHBCLE1BQU07Z0JBSUEsb0JBQW9CO3NCQUQxQixNQUFNO2dCQStDcUIsV0FBVztzQkFBdEMsWUFBWTt1QkFBQyxZQUFZO2dCQU8xQixRQUFRO3NCQURQLFlBQVk7dUJBQUMsZUFBZSxFQUFFLENBQUMsUUFBUSxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyogZXNsaW50LWRpc2FibGUgKi9cbmltcG9ydCB7IENvbXBvbmVudCwgSW5wdXQsIE9uSW5pdCwgVmlld0NoaWxkcmVuLCBRdWVyeUxpc3QsIEhvc3RMaXN0ZW5lciwgT3V0cHV0LCBFdmVudEVtaXR0ZXIsIFZpZXdFbmNhcHN1bGF0aW9uIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBIdHRwQ2xpZW50IH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uL2h0dHAnO1xuaW1wb3J0IHsgQ2hhdEFkYXB0ZXIgfSBmcm9tICcuLi8uLi9jb3JlL2NoYXQtYWRhcHRlcic7XG5pbXBvcnQgeyBJQ2hhdEdyb3VwQWRhcHRlciB9IGZyb20gJy4uLy4uL2NvcmUvY2hhdC1ncm91cC1hZGFwdGVyJztcbmltcG9ydCB7IFVzZXIgfSBmcm9tIFwiLi4vLi4vY29yZS91c2VyXCI7XG5pbXBvcnQgeyBQYXJ0aWNpcGFudFJlc3BvbnNlIH0gZnJvbSBcIi4uLy4uL2NvcmUvcGFydGljaXBhbnQtcmVzcG9uc2VcIjtcbmltcG9ydCB7IE1lc3NhZ2UgfSBmcm9tIFwiLi4vLi4vY29yZS9tZXNzYWdlXCI7XG5pbXBvcnQgeyBNZXNzYWdlVHlwZSB9IGZyb20gXCIuLi8uLi9jb3JlL21lc3NhZ2UtdHlwZS5lbnVtXCI7XG5pbXBvcnQgeyBXaW5kb3cgfSBmcm9tIFwiLi4vLi4vY29yZS93aW5kb3dcIjtcbmltcG9ydCB7IENoYXRQYXJ0aWNpcGFudFN0YXR1cyB9IGZyb20gXCIuLi8uLi9jb3JlL2NoYXQtcGFydGljaXBhbnQtc3RhdHVzLmVudW1cIjtcbmltcG9ydCB7IFNjcm9sbERpcmVjdGlvbiB9IGZyb20gXCIuLi8uLi9jb3JlL3Njcm9sbC1kaXJlY3Rpb24uZW51bVwiO1xuaW1wb3J0IHsgTG9jYWxpemF0aW9uLCBTdGF0dXNEZXNjcmlwdGlvbiB9IGZyb20gJy4uLy4uL2NvcmUvbG9jYWxpemF0aW9uJztcbmltcG9ydCB7IElDaGF0Q29udHJvbGxlciB9IGZyb20gJy4uLy4uL2NvcmUvY2hhdC1jb250cm9sbGVyJztcbmltcG9ydCB7IFBhZ2VkSGlzdG9yeUNoYXRBZGFwdGVyIH0gZnJvbSAnLi4vLi4vY29yZS9wYWdlZC1oaXN0b3J5LWNoYXQtYWRhcHRlcic7XG5pbXBvcnQgeyBJRmlsZVVwbG9hZEFkYXB0ZXIgfSBmcm9tICcuLi8uLi9jb3JlL2ZpbGUtdXBsb2FkLWFkYXB0ZXInO1xuaW1wb3J0IHsgRGVmYXVsdEZpbGVVcGxvYWRBZGFwdGVyIH0gZnJvbSAnLi4vLi4vY29yZS9kZWZhdWx0LWZpbGUtdXBsb2FkLWFkYXB0ZXInO1xuaW1wb3J0IHsgVGhlbWUgfSBmcm9tICcuLi8uLi9jb3JlL3RoZW1lLmVudW0nO1xuaW1wb3J0IHsgSUNoYXRPcHRpb24gfSBmcm9tICcuLi8uLi9jb3JlL2NoYXQtb3B0aW9uJztcbmltcG9ydCB7IEdyb3VwIH0gZnJvbSBcIi4uLy4uL2NvcmUvZ3JvdXBcIjtcbmltcG9ydCB7IENoYXRQYXJ0aWNpcGFudFR5cGUgfSBmcm9tIFwiLi4vLi4vY29yZS9jaGF0LXBhcnRpY2lwYW50LXR5cGUuZW51bVwiO1xuaW1wb3J0IHsgSUNoYXRQYXJ0aWNpcGFudCB9IGZyb20gXCIuLi8uLi9jb3JlL2NoYXQtcGFydGljaXBhbnRcIjtcbmltcG9ydCB7IG1hcCB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcbmltcG9ydCB7IE5nQ2hhdFdpbmRvd0NvbXBvbmVudCB9IGZyb20gJy4uL25nLWNoYXQtd2luZG93L25nLWNoYXQtd2luZG93LmNvbXBvbmVudCc7XG5cblxuQENvbXBvbmVudCh7XG4gICAgc2VsZWN0b3I6ICdtbmwtY2hhdCcsXG4gICAgdGVtcGxhdGVVcmw6ICduZy1jaGF0LmNvbXBvbmVudC5odG1sJyxcbiAgICBzdHlsZVVybHM6IFtcbiAgICAgICAgJy4uLy4uLy4uL2Fzc2V0cy9pY29ucy5jc3MnLFxuICAgICAgICAnLi4vLi4vLi4vYXNzZXRzL2xvYWRpbmctc3Bpbm5lci5jc3MnLFxuICAgICAgICAnLi4vLi4vLi4vYXNzZXRzL25nLWNoYXQuY29tcG9uZW50LmRlZmF1bHQuY3NzJyxcbiAgICAgICAgJy4uLy4uLy4uL2Fzc2V0cy90aGVtZXMvbmctY2hhdC50aGVtZS5kZWZhdWx0LnNjc3MnLFxuICAgICAgICAnLi4vLi4vLi4vYXNzZXRzL3RoZW1lcy9uZy1jaGF0LnRoZW1lLmRhcmsuc2NzcydcbiAgICBdLFxuICAgIGVuY2Fwc3VsYXRpb246IFZpZXdFbmNhcHN1bGF0aW9uLk5vbmVcbn0pXG5cbmV4cG9ydCBjbGFzcyBOZ0NoYXQgaW1wbGVtZW50cyBPbkluaXQsIElDaGF0Q29udHJvbGxlciB7XG4gICAgY29uc3RydWN0b3IocHJpdmF0ZSBfaHR0cENsaWVudDogSHR0cENsaWVudCkgeyB9XG5cbiAgICAvLyBFeHBvc2VzIGVudW1zIGZvciB0aGUgbmctdGVtcGxhdGVcbiAgICBwdWJsaWMgQ2hhdFBhcnRpY2lwYW50VHlwZSA9IENoYXRQYXJ0aWNpcGFudFR5cGU7XG4gICAgcHVibGljIENoYXRQYXJ0aWNpcGFudFN0YXR1cyA9IENoYXRQYXJ0aWNpcGFudFN0YXR1cztcbiAgICBwdWJsaWMgTWVzc2FnZVR5cGUgPSBNZXNzYWdlVHlwZTtcblxuICAgIHByaXZhdGUgX2lzRGlzYWJsZWQ6IGJvb2xlYW4gPSBmYWxzZTtcblxuICAgIGdldCBpc0Rpc2FibGVkKCk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gdGhpcy5faXNEaXNhYmxlZDtcbiAgICB9XG5cbiAgICBASW5wdXQoKVxuICAgIHNldCBpc0Rpc2FibGVkKHZhbHVlOiBib29sZWFuKSB7XG4gICAgICAgIHRoaXMuX2lzRGlzYWJsZWQgPSB2YWx1ZTtcblxuICAgICAgICBpZiAodmFsdWUpXG4gICAgICAgIHtcbiAgICAgICAgICAgIHdpbmRvdy5jbGVhckludGVydmFsKHRoaXMucG9sbGluZ0ludGVydmFsV2luZG93SW5zdGFuY2UpXG4gICAgICAgIH1cbiAgICAgICAgZWxzZVxuICAgICAgICB7XG4gICAgICAgICAgICB0aGlzLmFjdGl2YXRlRnJpZW5kTGlzdEZldGNoKCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBASW5wdXQoKVxuICAgIHB1YmxpYyBhZGFwdGVyOiBDaGF0QWRhcHRlcjtcblxuICAgIEBJbnB1dCgpXG4gICAgcHVibGljIGdyb3VwQWRhcHRlcjogSUNoYXRHcm91cEFkYXB0ZXI7XG5cbiAgICBASW5wdXQoKVxuICAgIHB1YmxpYyB1c2VySWQ6IGFueTtcblxuICAgIEBJbnB1dCgpXG4gICAgcHVibGljIGlzQ29sbGFwc2VkOiBib29sZWFuID0gZmFsc2U7XG5cbiAgICBASW5wdXQoKVxuICAgIHB1YmxpYyBtYXhpbWl6ZVdpbmRvd09uTmV3TWVzc2FnZTogYm9vbGVhbiA9IHRydWU7XG5cbiAgICBASW5wdXQoKVxuICAgIHB1YmxpYyBwb2xsRnJpZW5kc0xpc3Q6IGJvb2xlYW4gPSBmYWxzZTtcblxuICAgIEBJbnB1dCgpXG4gICAgcHVibGljIHBvbGxpbmdJbnRlcnZhbDogbnVtYmVyID0gNTAwMDtcblxuICAgIEBJbnB1dCgpXG4gICAgcHVibGljIGhpc3RvcnlFbmFibGVkOiBib29sZWFuID0gdHJ1ZTtcblxuICAgIEBJbnB1dCgpXG4gICAgcHVibGljIGVtb2ppc0VuYWJsZWQ6IGJvb2xlYW4gPSB0cnVlO1xuXG4gICAgQElucHV0KClcbiAgICBwdWJsaWMgbGlua2Z5RW5hYmxlZDogYm9vbGVhbiA9IHRydWU7XG5cbiAgICBASW5wdXQoKVxuICAgIHB1YmxpYyBhdWRpb0VuYWJsZWQ6IGJvb2xlYW4gPSB0cnVlO1xuXG4gICAgQElucHV0KClcbiAgICBwdWJsaWMgc2VhcmNoRW5hYmxlZDogYm9vbGVhbiA9IHRydWU7XG5cbiAgICBASW5wdXQoKSAvLyBUT0RPOiBUaGlzIG1pZ2h0IG5lZWQgYSBiZXR0ZXIgY29udGVudCBzdHJhdGVneVxuICAgIHB1YmxpYyBhdWRpb1NvdXJjZTogc3RyaW5nID0gJy4uLy4uLy4uL2Fzc2V0cy9ub3RpZmljYXRpb24ud2F2JztcblxuICAgIEBJbnB1dCgpXG4gICAgcHVibGljIHBlcnNpc3RXaW5kb3dzU3RhdGU6IGJvb2xlYW4gPSB0cnVlO1xuXG4gICAgQElucHV0KClcbiAgICBwdWJsaWMgdGl0bGU6IHN0cmluZyA9IFwiUXVpY2sgY2hhdFwiO1xuXG4gICAgQElucHV0KClcbiAgICBwdWJsaWMgbWVzc2FnZVBsYWNlaG9sZGVyOiBzdHJpbmcgPSBcIlR5cGUgYSBtZXNzYWdlXCI7XG5cbiAgICBASW5wdXQoKVxuICAgIHB1YmxpYyBzZWFyY2hQbGFjZWhvbGRlcjogc3RyaW5nID0gXCJTZWFyY2hcIjtcblxuICAgIEBJbnB1dCgpXG4gICAgcHVibGljIGJyb3dzZXJOb3RpZmljYXRpb25zRW5hYmxlZDogYm9vbGVhbiA9IHRydWU7XG5cbiAgICBASW5wdXQoKSAvLyBUT0RPOiBUaGlzIG1pZ2h0IG5lZWQgYSBiZXR0ZXIgY29udGVudCBzdHJhdGVneVxuICAgIHB1YmxpYyBicm93c2VyTm90aWZpY2F0aW9uSWNvblNvdXJjZTogc3RyaW5nID0gJy4uLy4uLy4uL2Fzc2V0cy9ub3RpZmljYXRpb24ucG5nJztcblxuICAgIEBJbnB1dCgpXG4gICAgcHVibGljIGJyb3dzZXJOb3RpZmljYXRpb25UaXRsZTogc3RyaW5nID0gXCJOZXcgbWVzc2FnZSBmcm9tXCI7XG5cbiAgICBASW5wdXQoKVxuICAgIHB1YmxpYyBoaXN0b3J5UGFnZVNpemU6IG51bWJlciA9IDEwO1xuXG4gICAgQElucHV0KClcbiAgICBwdWJsaWMgbG9jYWxpemF0aW9uOiBMb2NhbGl6YXRpb247XG5cbiAgICBASW5wdXQoKVxuICAgIHB1YmxpYyBoaWRlRnJpZW5kc0xpc3Q6IGJvb2xlYW4gPSBmYWxzZTtcblxuICAgIEBJbnB1dCgpXG4gICAgcHVibGljIGhpZGVGcmllbmRzTGlzdE9uVW5zdXBwb3J0ZWRWaWV3cG9ydDogYm9vbGVhbiA9IHRydWU7XG5cbiAgICBASW5wdXQoKVxuICAgIHB1YmxpYyBmaWxlVXBsb2FkVXJsOiBzdHJpbmc7XG5cbiAgICBASW5wdXQoKVxuICAgIHB1YmxpYyB0aGVtZTogVGhlbWUgPSBUaGVtZS5MaWdodDtcblxuICAgIEBJbnB1dCgpXG4gICAgcHVibGljIGN1c3RvbVRoZW1lOiBzdHJpbmc7XG5cbiAgICBASW5wdXQoKVxuICAgIHB1YmxpYyBtZXNzYWdlRGF0ZVBpcGVGb3JtYXQ6IHN0cmluZyA9IFwic2hvcnRcIjtcblxuICAgIEBJbnB1dCgpXG4gICAgcHVibGljIHNob3dNZXNzYWdlRGF0ZTogYm9vbGVhbiA9IHRydWU7XG5cbiAgICBASW5wdXQoKVxuICAgIHB1YmxpYyBpc1ZpZXdwb3J0T25Nb2JpbGVFbmFibGVkOiBib29sZWFuID0gZmFsc2U7XG5cbiAgICBASW5wdXQoKVxuICAgIHB1YmxpYyBmaWxlVXBsb2FkQWRhcHRlcjogSUZpbGVVcGxvYWRBZGFwdGVyO1xuXG4gICAgQE91dHB1dCgpXG4gICAgcHVibGljIG9uUGFydGljaXBhbnRDbGlja2VkOiBFdmVudEVtaXR0ZXI8SUNoYXRQYXJ0aWNpcGFudD4gPSBuZXcgRXZlbnRFbWl0dGVyPElDaGF0UGFydGljaXBhbnQ+KCk7XG5cbiAgICBAT3V0cHV0KClcbiAgICBwdWJsaWMgb25QYXJ0aWNpcGFudENoYXRPcGVuZWQ6IEV2ZW50RW1pdHRlcjxJQ2hhdFBhcnRpY2lwYW50PiA9IG5ldyBFdmVudEVtaXR0ZXI8SUNoYXRQYXJ0aWNpcGFudD4oKTtcblxuICAgIEBPdXRwdXQoKVxuICAgIHB1YmxpYyBvblBhcnRpY2lwYW50Q2hhdENsb3NlZDogRXZlbnRFbWl0dGVyPElDaGF0UGFydGljaXBhbnQ+ID0gbmV3IEV2ZW50RW1pdHRlcjxJQ2hhdFBhcnRpY2lwYW50PigpO1xuXG4gICAgQE91dHB1dCgpXG4gICAgcHVibGljIG9uTWVzc2FnZXNTZWVuOiBFdmVudEVtaXR0ZXI8TWVzc2FnZVtdPiA9IG5ldyBFdmVudEVtaXR0ZXI8TWVzc2FnZVtdPigpO1xuXG4gICAgQE91dHB1dCgpXG4gICAgcHVibGljIG9uQ2xvc2VXaW5kb3dDbGlja2VkOkV2ZW50RW1pdHRlcjxib29sZWFuPiA9IG5ldyBFdmVudEVtaXR0ZXI8Ym9vbGVhbj4oKVxuXG4gICAgcHJpdmF0ZSBicm93c2VyTm90aWZpY2F0aW9uc0Jvb3RzdHJhcHBlZDogYm9vbGVhbiA9IGZhbHNlO1xuXG4gICAgcHVibGljIGhhc1BhZ2VkSGlzdG9yeTogYm9vbGVhbiA9IGZhbHNlO1xuXG4gICAgLy8gRG9uJ3Qgd2FudCB0byBhZGQgdGhpcyBhcyBhIHNldHRpbmcgdG8gc2ltcGxpZnkgdXNhZ2UuIFByZXZpb3VzIHBsYWNlaG9sZGVyIGFuZCB0aXRsZSBzZXR0aW5ncyBhdmFpbGFibGUgdG8gYmUgdXNlZCwgb3IgdXNlIGZ1bGwgTG9jYWxpemF0aW9uIG9iamVjdC5cbiAgICBwcml2YXRlIHN0YXR1c0Rlc2NyaXB0aW9uOiBTdGF0dXNEZXNjcmlwdGlvbiA9IHtcbiAgICAgICAgb25saW5lOiAnT25saW5lJyxcbiAgICAgICAgYnVzeTogJ0J1c3knLFxuICAgICAgICBhd2F5OiAnQXdheScsXG4gICAgICAgIG9mZmxpbmU6ICdPZmZsaW5lJ1xuICAgIH07XG5cbiAgICBwcml2YXRlIGF1ZGlvRmlsZTogSFRNTEF1ZGlvRWxlbWVudDtcblxuICAgIHB1YmxpYyBwYXJ0aWNpcGFudHM6IElDaGF0UGFydGljaXBhbnRbXTtcblxuICAgIHB1YmxpYyBwYXJ0aWNpcGFudHNSZXNwb25zZTogUGFydGljaXBhbnRSZXNwb25zZVtdO1xuXG4gICAgcHVibGljIHBhcnRpY2lwYW50c0ludGVyYWN0ZWRXaXRoOiBJQ2hhdFBhcnRpY2lwYW50W10gPSBbXTtcblxuICAgIHB1YmxpYyBjdXJyZW50QWN0aXZlT3B0aW9uOiBJQ2hhdE9wdGlvbiB8IG51bGw7XG5cbiAgICBwcml2YXRlIHBvbGxpbmdJbnRlcnZhbFdpbmRvd0luc3RhbmNlOiBudW1iZXI7XG5cbiAgICBwcml2YXRlIGdldCBsb2NhbFN0b3JhZ2VLZXkoKTogc3RyaW5nXG4gICAge1xuICAgICAgICByZXR1cm4gYG5nLWNoYXQtdXNlcnMtJHt0aGlzLnVzZXJJZH1gOyAvLyBBcHBlbmRpbmcgdGhlIHVzZXIgaWQgc28gdGhlIHN0YXRlIGlzIHVuaXF1ZSBwZXIgdXNlciBpbiBhIGNvbXB1dGVyLlxuICAgIH07XG5cbiAgICAvLyBEZWZpbmVzIHRoZSBzaXplIG9mIGVhY2ggb3BlbmVkIHdpbmRvdyB0byBjYWxjdWxhdGUgaG93IG1hbnkgd2luZG93cyBjYW4gYmUgb3BlbmVkIG9uIHRoZSB2aWV3cG9ydCBhdCB0aGUgc2FtZSB0aW1lLlxuICAgIHB1YmxpYyB3aW5kb3dTaXplRmFjdG9yOiBudW1iZXIgPSAzMjA7XG5cbiAgICAvLyBUb3RhbCB3aWR0aCBzaXplIG9mIHRoZSBmcmllbmRzIGxpc3Qgc2VjdGlvblxuICAgIHB1YmxpYyBmcmllbmRzTGlzdFdpZHRoOiBudW1iZXIgPSAyNjI7XG5cbiAgICAvLyBBdmFpbGFibGUgYXJlYSB0byByZW5kZXIgdGhlIHBsdWdpblxuICAgIHByaXZhdGUgdmlld1BvcnRUb3RhbEFyZWE6IG51bWJlcjtcblxuICAgIC8vIFNldCB0byB0cnVlIGlmIHRoZXJlIGlzIG5vIHNwYWNlIHRvIGRpc3BsYXkgYXQgbGVhc3Qgb25lIGNoYXQgd2luZG93IGFuZCAnaGlkZUZyaWVuZHNMaXN0T25VbnN1cHBvcnRlZFZpZXdwb3J0JyBpcyB0cnVlXG4gICAgcHVibGljIHVuc3VwcG9ydGVkVmlld3BvcnQ6IGJvb2xlYW4gPSBmYWxzZTtcblxuICAgIHdpbmRvd3M6IFdpbmRvd1tdID0gW107XG4gICAgaXNCb290c3RyYXBwZWQ6IGJvb2xlYW4gPSBmYWxzZTtcblxuICAgIEBWaWV3Q2hpbGRyZW4oJ2NoYXRXaW5kb3cnKSBjaGF0V2luZG93czogUXVlcnlMaXN0PE5nQ2hhdFdpbmRvd0NvbXBvbmVudD47XG5cbiAgICBuZ09uSW5pdCgpIHtcbiAgICAgICAgdGhpcy5ib290c3RyYXBDaGF0KCk7XG4gICAgfVxuXG4gICAgQEhvc3RMaXN0ZW5lcignd2luZG93OnJlc2l6ZScsIFsnJGV2ZW50J10pXG4gICAgb25SZXNpemUoZXZlbnQ6IGFueSl7XG4gICAgICAgdGhpcy52aWV3UG9ydFRvdGFsQXJlYSA9IGV2ZW50LnRhcmdldC5pbm5lcldpZHRoO1xuXG4gICAgICAgdGhpcy5Ob3JtYWxpemVXaW5kb3dzKCk7XG4gICAgfVxuXG4gICAgLy8gQ2hlY2tzIGlmIHRoZXJlIGFyZSBtb3JlIG9wZW5lZCB3aW5kb3dzIHRoYW4gdGhlIHZpZXcgcG9ydCBjYW4gZGlzcGxheVxuICAgIHByaXZhdGUgTm9ybWFsaXplV2luZG93cygpOiB2b2lkXG4gICAge1xuICAgICAgICBjb25zdCBtYXhTdXBwb3J0ZWRPcGVuZWRXaW5kb3dzID0gTWF0aC5mbG9vcigodGhpcy52aWV3UG9ydFRvdGFsQXJlYSAtICghdGhpcy5oaWRlRnJpZW5kc0xpc3QgPyB0aGlzLmZyaWVuZHNMaXN0V2lkdGggOiAwKSkgLyB0aGlzLndpbmRvd1NpemVGYWN0b3IpO1xuICAgICAgICBjb25zdCBkaWZmZXJlbmNlID0gdGhpcy53aW5kb3dzLmxlbmd0aCAtIG1heFN1cHBvcnRlZE9wZW5lZFdpbmRvd3M7XG5cbiAgICAgICAgaWYgKGRpZmZlcmVuY2UgPj0gMClcbiAgICAgICAge1xuICAgICAgICAgICAgdGhpcy53aW5kb3dzLnNwbGljZSh0aGlzLndpbmRvd3MubGVuZ3RoIC0gZGlmZmVyZW5jZSk7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnVwZGF0ZVdpbmRvd3NTdGF0ZSh0aGlzLndpbmRvd3MpO1xuXG4gICAgICAgIC8vIFZpZXdwb3J0IHNob3VsZCBoYXZlIHNwYWNlIGZvciBhdCBsZWFzdCBvbmUgY2hhdCB3aW5kb3cgYnV0IHNob3VsZCBzaG93IGluIG1vYmlsZSBpZiBvcHRpb24gaXMgZW5hYmxlZC5cbiAgICAgICAgdGhpcy51bnN1cHBvcnRlZFZpZXdwb3J0ID0gdGhpcy5pc1ZpZXdwb3J0T25Nb2JpbGVFbmFibGVkPyBmYWxzZSA6IHRoaXMuaGlkZUZyaWVuZHNMaXN0T25VbnN1cHBvcnRlZFZpZXdwb3J0ICYmIG1heFN1cHBvcnRlZE9wZW5lZFdpbmRvd3MgPCAxO1xuICAgIH1cblxuICAgIC8vIEluaXRpYWxpemVzIHRoZSBjaGF0IHBsdWdpbiBhbmQgdGhlIG1lc3NhZ2luZyBhZGFwdGVyXG4gICAgcHJpdmF0ZSBib290c3RyYXBDaGF0KCk6IHZvaWRcbiAgICB7XG4gICAgICAgIGxldCBpbml0aWFsaXphdGlvbkV4Y2VwdGlvbiA9IG51bGw7XG5cbiAgICAgICAgaWYgKHRoaXMuYWRhcHRlciAhPSBudWxsICYmIHRoaXMudXNlcklkICE9IG51bGwpXG4gICAgICAgIHtcbiAgICAgICAgICAgIHRyeVxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIHRoaXMudmlld1BvcnRUb3RhbEFyZWEgPSB3aW5kb3cuaW5uZXJXaWR0aDtcblxuICAgICAgICAgICAgICAgIHRoaXMuaW5pdGlhbGl6ZVRoZW1lKCk7XG4gICAgICAgICAgICAgICAgdGhpcy5pbml0aWFsaXplRGVmYXVsdFRleHQoKTtcbiAgICAgICAgICAgICAgICB0aGlzLmluaXRpYWxpemVCcm93c2VyTm90aWZpY2F0aW9ucygpO1xuXG4gICAgICAgICAgICAgICAgLy8gQmluZGluZyBldmVudCBsaXN0ZW5lcnNcbiAgICAgICAgICAgICAgICB0aGlzLmFkYXB0ZXIubWVzc2FnZVJlY2VpdmVkSGFuZGxlciA9IChwYXJ0aWNpcGFudCwgbXNnKSA9PiB0aGlzLm9uTWVzc2FnZVJlY2VpdmVkKHBhcnRpY2lwYW50LCBtc2cpO1xuICAgICAgICAgICAgICAgIHRoaXMuYWRhcHRlci5mcmllbmRzTGlzdENoYW5nZWRIYW5kbGVyID0gKHBhcnRpY2lwYW50c1Jlc3BvbnNlKSA9PiB0aGlzLm9uRnJpZW5kc0xpc3RDaGFuZ2VkKHBhcnRpY2lwYW50c1Jlc3BvbnNlKTtcblxuICAgICAgICAgICAgICAgIHRoaXMuYWN0aXZhdGVGcmllbmRMaXN0RmV0Y2goKTtcblxuICAgICAgICAgICAgICAgIHRoaXMuYnVmZmVyQXVkaW9GaWxlKCk7XG5cbiAgICAgICAgICAgICAgICB0aGlzLmhhc1BhZ2VkSGlzdG9yeSA9IHRoaXMuYWRhcHRlciBpbnN0YW5jZW9mIFBhZ2VkSGlzdG9yeUNoYXRBZGFwdGVyO1xuXG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuZmlsZVVwbG9hZFVybCAmJiB0aGlzLmZpbGVVcGxvYWRVcmwgIT09IFwiXCIpXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmZpbGVVcGxvYWRBZGFwdGVyID0gbmV3IERlZmF1bHRGaWxlVXBsb2FkQWRhcHRlcih0aGlzLmZpbGVVcGxvYWRVcmwsIHRoaXMuX2h0dHBDbGllbnQpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHRoaXMuTm9ybWFsaXplV2luZG93cygpO1xuXG4gICAgICAgICAgICAgICAgdGhpcy5pc0Jvb3RzdHJhcHBlZCA9IHRydWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjYXRjaChleClcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBpbml0aWFsaXphdGlvbkV4Y2VwdGlvbiA9IGV4O1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCF0aGlzLmlzQm9vdHN0cmFwcGVkKXtcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXCJuZy1jaGF0IGNvbXBvbmVudCBjb3VsZG4ndCBiZSBib290c3RyYXBwZWQuXCIpO1xuXG4gICAgICAgICAgICBpZiAodGhpcy51c2VySWQgPT0gbnVsbCl7XG4gICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihcIm5nLWNoYXQgY2FuJ3QgYmUgaW5pdGlhbGl6ZWQgd2l0aG91dCBhbiB1c2VyIGlkLiBQbGVhc2UgbWFrZSBzdXJlIHlvdSd2ZSBwcm92aWRlZCBhbiB1c2VySWQgYXMgYSBwYXJhbWV0ZXIgb2YgdGhlIG5nLWNoYXQgY29tcG9uZW50LlwiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICh0aGlzLmFkYXB0ZXIgPT0gbnVsbCl7XG4gICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihcIm5nLWNoYXQgY2FuJ3QgYmUgYm9vdHN0cmFwcGVkIHdpdGhvdXQgYSBDaGF0QWRhcHRlci4gUGxlYXNlIG1ha2Ugc3VyZSB5b3UndmUgcHJvdmlkZWQgYSBDaGF0QWRhcHRlciBpbXBsZW1lbnRhdGlvbiBhcyBhIHBhcmFtZXRlciBvZiB0aGUgbmctY2hhdCBjb21wb25lbnQuXCIpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGluaXRpYWxpemF0aW9uRXhjZXB0aW9uKVxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoYEFuIGV4Y2VwdGlvbiBoYXMgb2NjdXJyZWQgd2hpbGUgaW5pdGlhbGl6aW5nIG5nLWNoYXQuIERldGFpbHM6ICR7aW5pdGlhbGl6YXRpb25FeGNlcHRpb24ubWVzc2FnZX1gKTtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKGluaXRpYWxpemF0aW9uRXhjZXB0aW9uKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgYWN0aXZhdGVGcmllbmRMaXN0RmV0Y2goKTogdm9pZCB7XG4gICAgICAgIGlmICh0aGlzLmFkYXB0ZXIpXG4gICAgICAgIHtcbiAgICAgICAgICAgIC8vIExvYWRpbmcgY3VycmVudCB1c2VycyBsaXN0XG4gICAgICAgICAgICBpZiAodGhpcy5wb2xsRnJpZW5kc0xpc3Qpe1xuICAgICAgICAgICAgICAgIC8vIFNldHRpbmcgYSBsb25nIHBvbGwgaW50ZXJ2YWwgdG8gdXBkYXRlIHRoZSBmcmllbmRzIGxpc3RcbiAgICAgICAgICAgICAgICB0aGlzLmZldGNoRnJpZW5kc0xpc3QodHJ1ZSk7XG4gICAgICAgICAgICAgICAgdGhpcy5wb2xsaW5nSW50ZXJ2YWxXaW5kb3dJbnN0YW5jZSA9IHdpbmRvdy5zZXRJbnRlcnZhbCgoKSA9PiB0aGlzLmZldGNoRnJpZW5kc0xpc3QoZmFsc2UpLCB0aGlzLnBvbGxpbmdJbnRlcnZhbCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgLy8gU2luY2UgcG9sbGluZyB3YXMgZGlzYWJsZWQsIGEgZnJpZW5kcyBsaXN0IHVwZGF0ZSBtZWNoYW5pc20gd2lsbCBoYXZlIHRvIGJlIGltcGxlbWVudGVkIGluIHRoZSBDaGF0QWRhcHRlci5cbiAgICAgICAgICAgICAgICB0aGlzLmZldGNoRnJpZW5kc0xpc3QodHJ1ZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBJbml0aWFsaXplcyBicm93c2VyIG5vdGlmaWNhdGlvbnNcbiAgICBwcml2YXRlIGFzeW5jIGluaXRpYWxpemVCcm93c2VyTm90aWZpY2F0aW9ucygpXG4gICAge1xuICAgICAgICBpZiAodGhpcy5icm93c2VyTm90aWZpY2F0aW9uc0VuYWJsZWQgJiYgKFwiTm90aWZpY2F0aW9uXCIgaW4gd2luZG93KSlcbiAgICAgICAge1xuICAgICAgICAgICAgaWYgKGF3YWl0IE5vdGlmaWNhdGlvbi5yZXF1ZXN0UGVybWlzc2lvbigpID09PSBcImdyYW50ZWRcIilcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICB0aGlzLmJyb3dzZXJOb3RpZmljYXRpb25zQm9vdHN0cmFwcGVkID0gdHJ1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8vIEluaXRpYWxpemVzIGRlZmF1bHQgdGV4dFxuICAgIHByaXZhdGUgaW5pdGlhbGl6ZURlZmF1bHRUZXh0KCkgOiB2b2lkXG4gICAge1xuICAgICAgICBpZiAoIXRoaXMubG9jYWxpemF0aW9uKVxuICAgICAgICB7XG4gICAgICAgICAgICB0aGlzLmxvY2FsaXphdGlvbiA9IHtcbiAgICAgICAgICAgICAgICBtZXNzYWdlUGxhY2Vob2xkZXI6IHRoaXMubWVzc2FnZVBsYWNlaG9sZGVyLFxuICAgICAgICAgICAgICAgIHNlYXJjaFBsYWNlaG9sZGVyOiB0aGlzLnNlYXJjaFBsYWNlaG9sZGVyLFxuICAgICAgICAgICAgICAgIHRpdGxlOiB0aGlzLnRpdGxlLFxuICAgICAgICAgICAgICAgIHN0YXR1c0Rlc2NyaXB0aW9uOiB0aGlzLnN0YXR1c0Rlc2NyaXB0aW9uLFxuICAgICAgICAgICAgICAgIGJyb3dzZXJOb3RpZmljYXRpb25UaXRsZTogdGhpcy5icm93c2VyTm90aWZpY2F0aW9uVGl0bGUsXG4gICAgICAgICAgICAgICAgbG9hZE1lc3NhZ2VIaXN0b3J5UGxhY2Vob2xkZXI6IFwiTG9hZCBvbGRlciBtZXNzYWdlc1wiXG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBpbml0aWFsaXplVGhlbWUoKTogdm9pZFxuICAgIHtcbiAgICAgICAgaWYgKHRoaXMuY3VzdG9tVGhlbWUpXG4gICAgICAgIHtcbiAgICAgICAgICAgIHRoaXMudGhlbWUgPSBUaGVtZS5DdXN0b207XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAodGhpcy50aGVtZSAhPSBUaGVtZS5MaWdodCAmJiB0aGlzLnRoZW1lICE9IFRoZW1lLkRhcmspXG4gICAgICAgIHtcbiAgICAgICAgICAgIC8vIFRPRE86IFVzZSBlczIwMTcgaW4gZnV0dXJlIHdpdGggT2JqZWN0LnZhbHVlcyhUaGVtZSkuaW5jbHVkZXModGhpcy50aGVtZSkgdG8gZG8gdGhpcyBjaGVja1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIHRoZW1lIGNvbmZpZ3VyYXRpb24gZm9yIG5nLWNoYXQuIFwiJHt0aGlzLnRoZW1lfVwiIGlzIG5vdCBhIHZhbGlkIHRoZW1lIHZhbHVlLmApO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLy8gU2VuZHMgYSByZXF1ZXN0IHRvIGxvYWQgdGhlIGZyaWVuZHMgbGlzdFxuICAgIHByaXZhdGUgZmV0Y2hGcmllbmRzTGlzdChpc0Jvb3RzdHJhcHBpbmc6IGJvb2xlYW4pOiB2b2lkXG4gICAge1xuICAgICAgICB0aGlzLmFkYXB0ZXIubGlzdEZyaWVuZHMoKVxuICAgICAgICAucGlwZShcbiAgICAgICAgICAgIG1hcCgocGFydGljaXBhbnRzUmVzcG9uc2U6IFBhcnRpY2lwYW50UmVzcG9uc2VbXSkgPT4ge1xuICAgICAgICAgICAgICAgIHRoaXMucGFydGljaXBhbnRzUmVzcG9uc2UgPSBwYXJ0aWNpcGFudHNSZXNwb25zZTtcblxuICAgICAgICAgICAgICAgIHRoaXMucGFydGljaXBhbnRzID0gcGFydGljaXBhbnRzUmVzcG9uc2UubWFwKChyZXNwb25zZTogUGFydGljaXBhbnRSZXNwb25zZSkgPT4ge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gcmVzcG9uc2UucGFydGljaXBhbnQ7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9KVxuICAgICAgICApLnN1YnNjcmliZSgoKSA9PiB7XG4gICAgICAgICAgICBpZiAoaXNCb290c3RyYXBwaW5nKVxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIHRoaXMucmVzdG9yZVdpbmRvd3NTdGF0ZSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBmZXRjaE1lc3NhZ2VIaXN0b3J5KHdpbmRvdzogV2luZG93KSB7XG4gICAgICAgIC8vIE5vdCBpZGVhbCBidXQgd2lsbCBrZWVwIHRoaXMgdW50aWwgd2UgZGVjaWRlIGlmIHdlIGFyZSBzaGlwcGluZyBwYWdpbmF0aW9uIHdpdGggdGhlIGRlZmF1bHQgYWRhcHRlclxuICAgICAgICBpZiAodGhpcy5hZGFwdGVyIGluc3RhbmNlb2YgUGFnZWRIaXN0b3J5Q2hhdEFkYXB0ZXIpXG4gICAgICAgIHtcbiAgICAgICAgICAgIHdpbmRvdy5pc0xvYWRpbmdIaXN0b3J5ID0gdHJ1ZTtcblxuICAgICAgICAgICAgdGhpcy5hZGFwdGVyLmdldE1lc3NhZ2VIaXN0b3J5QnlQYWdlKHdpbmRvdy5wYXJ0aWNpcGFudC5pZCwgdGhpcy5oaXN0b3J5UGFnZVNpemUsICsrd2luZG93Lmhpc3RvcnlQYWdlKVxuICAgICAgICAgICAgLnBpcGUoXG4gICAgICAgICAgICAgICAgbWFwKChyZXN1bHQ6IE1lc3NhZ2VbXSkgPT4ge1xuICAgICAgICAgICAgICAgICAgICByZXN1bHQuZm9yRWFjaCgobWVzc2FnZSkgPT4gdGhpcy5hc3NlcnRNZXNzYWdlVHlwZShtZXNzYWdlKSk7XG5cbiAgICAgICAgICAgICAgICAgICAgd2luZG93Lm1lc3NhZ2VzID0gcmVzdWx0LmNvbmNhdCh3aW5kb3cubWVzc2FnZXMpO1xuICAgICAgICAgICAgICAgICAgICB3aW5kb3cuaXNMb2FkaW5nSGlzdG9yeSA9IGZhbHNlO1xuXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGRpcmVjdGlvbjogU2Nyb2xsRGlyZWN0aW9uID0gKHdpbmRvdy5oaXN0b3J5UGFnZSA9PSAxKSA/IFNjcm9sbERpcmVjdGlvbi5Cb3R0b20gOiBTY3JvbGxEaXJlY3Rpb24uVG9wO1xuICAgICAgICAgICAgICAgICAgICB3aW5kb3cuaGFzTW9yZU1lc3NhZ2VzID0gcmVzdWx0Lmxlbmd0aCA9PSB0aGlzLmhpc3RvcnlQYWdlU2l6ZTtcblxuICAgICAgICAgICAgICAgICAgICBzZXRUaW1lb3V0KCgpID0+IHRoaXMub25GZXRjaE1lc3NhZ2VIaXN0b3J5TG9hZGVkKHJlc3VsdCwgd2luZG93LCBkaXJlY3Rpb24sIHRydWUpKTtcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgKS5zdWJzY3JpYmUoKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlXG4gICAgICAgIHtcbiAgICAgICAgICAgIHRoaXMuYWRhcHRlci5nZXRNZXNzYWdlSGlzdG9yeSh3aW5kb3cucGFydGljaXBhbnQuaWQpXG4gICAgICAgICAgICAucGlwZShcbiAgICAgICAgICAgICAgICBtYXAoKHJlc3VsdDogTWVzc2FnZVtdKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIHJlc3VsdC5mb3JFYWNoKChtZXNzYWdlKSA9PiB0aGlzLmFzc2VydE1lc3NhZ2VUeXBlKG1lc3NhZ2UpKTtcblxuICAgICAgICAgICAgICAgICAgICB3aW5kb3cubWVzc2FnZXMgPSByZXN1bHQuY29uY2F0KHdpbmRvdy5tZXNzYWdlcyk7XG4gICAgICAgICAgICAgICAgICAgIHdpbmRvdy5pc0xvYWRpbmdIaXN0b3J5ID0gZmFsc2U7XG5cbiAgICAgICAgICAgICAgICAgICAgc2V0VGltZW91dCgoKSA9PiB0aGlzLm9uRmV0Y2hNZXNzYWdlSGlzdG9yeUxvYWRlZChyZXN1bHQsIHdpbmRvdywgU2Nyb2xsRGlyZWN0aW9uLkJvdHRvbSkpO1xuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICApLnN1YnNjcmliZSgpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBvbkZldGNoTWVzc2FnZUhpc3RvcnlMb2FkZWQobWVzc2FnZXM6IE1lc3NhZ2VbXSwgd2luZG93OiBXaW5kb3csIGRpcmVjdGlvbjogU2Nyb2xsRGlyZWN0aW9uLCBmb3JjZU1hcmtNZXNzYWdlc0FzU2VlbjogYm9vbGVhbiA9IGZhbHNlKTogdm9pZFxuICAgIHtcbiAgICAgICAgdGhpcy5zY3JvbGxDaGF0V2luZG93KHdpbmRvdywgZGlyZWN0aW9uKVxuXG4gICAgICAgIGlmICh3aW5kb3cuaGFzRm9jdXMgfHwgZm9yY2VNYXJrTWVzc2FnZXNBc1NlZW4pXG4gICAgICAgIHtcbiAgICAgICAgICAgIGNvbnN0IHVuc2Vlbk1lc3NhZ2VzID0gbWVzc2FnZXMuZmlsdGVyKG0gPT4gIW0uZGF0ZVNlZW4pO1xuXG4gICAgICAgICAgICB0aGlzLm1hcmtNZXNzYWdlc0FzUmVhZCh1bnNlZW5NZXNzYWdlcyk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBVcGRhdGVzIHRoZSBmcmllbmRzIGxpc3QgdmlhIHRoZSBldmVudCBoYW5kbGVyXG4gICAgcHJpdmF0ZSBvbkZyaWVuZHNMaXN0Q2hhbmdlZChwYXJ0aWNpcGFudHNSZXNwb25zZTogUGFydGljaXBhbnRSZXNwb25zZVtdKTogdm9pZFxuICAgIHtcbiAgICAgICAgaWYgKHBhcnRpY2lwYW50c1Jlc3BvbnNlKVxuICAgICAgICB7XG4gICAgICAgICAgICB0aGlzLnBhcnRpY2lwYW50c1Jlc3BvbnNlID0gcGFydGljaXBhbnRzUmVzcG9uc2U7XG5cbiAgICAgICAgICAgIHRoaXMucGFydGljaXBhbnRzID0gcGFydGljaXBhbnRzUmVzcG9uc2UubWFwKChyZXNwb25zZTogUGFydGljaXBhbnRSZXNwb25zZSkgPT4ge1xuICAgICAgICAgICAgICAgIHJldHVybiByZXNwb25zZS5wYXJ0aWNpcGFudDtcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICB0aGlzLnBhcnRpY2lwYW50c0ludGVyYWN0ZWRXaXRoID0gW107XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBIYW5kbGVzIHJlY2VpdmVkIG1lc3NhZ2VzIGJ5IHRoZSBhZGFwdGVyXG4gICAgcHJpdmF0ZSBvbk1lc3NhZ2VSZWNlaXZlZChwYXJ0aWNpcGFudDogSUNoYXRQYXJ0aWNpcGFudCwgbWVzc2FnZTogTWVzc2FnZSlcbiAgICB7XG4gICAgICAgIGlmIChwYXJ0aWNpcGFudCAmJiBtZXNzYWdlKVxuICAgICAgICB7XG4gICAgICAgICAgICBjb25zdCBjaGF0V2luZG93ID0gdGhpcy5vcGVuQ2hhdFdpbmRvdyhwYXJ0aWNpcGFudCk7XG5cbiAgICAgICAgICAgIHRoaXMuYXNzZXJ0TWVzc2FnZVR5cGUobWVzc2FnZSk7XG5cbiAgICAgICAgICAgIGlmICghY2hhdFdpbmRvd1sxXSB8fCAhdGhpcy5oaXN0b3J5RW5hYmxlZCl7XG4gICAgICAgICAgICAgICAgY2hhdFdpbmRvd1swXS5tZXNzYWdlcy5wdXNoKG1lc3NhZ2UpO1xuXG4gICAgICAgICAgICAgICAgdGhpcy5zY3JvbGxDaGF0V2luZG93KGNoYXRXaW5kb3dbMF0sIFNjcm9sbERpcmVjdGlvbi5Cb3R0b20pO1xuXG4gICAgICAgICAgICAgICAgaWYgKGNoYXRXaW5kb3dbMF0uaGFzRm9jdXMpXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLm1hcmtNZXNzYWdlc0FzUmVhZChbbWVzc2FnZV0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdGhpcy5lbWl0TWVzc2FnZVNvdW5kKGNoYXRXaW5kb3dbMF0pO1xuXG4gICAgICAgICAgICAvLyBEbyBub3QgcHVzaCBicm93c2VyIG5vdGlmaWNhdGlvbnMgd2l0aCBtZXNzYWdlIGNvbnRlbnQgZm9yIHByaXZhY3kgcHVycG9zZXMgaWYgdGhlICdtYXhpbWl6ZVdpbmRvd09uTmV3TWVzc2FnZScgc2V0dGluZyBpcyBvZmYgYW5kIHRoaXMgaXMgYSBuZXcgY2hhdCB3aW5kb3cuXG4gICAgICAgICAgICBpZiAodGhpcy5tYXhpbWl6ZVdpbmRvd09uTmV3TWVzc2FnZSB8fCAoIWNoYXRXaW5kb3dbMV0gJiYgIWNoYXRXaW5kb3dbMF0uaXNDb2xsYXBzZWQpKVxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIC8vIFNvbWUgbWVzc2FnZXMgYXJlIG5vdCBwdXNoZWQgYmVjYXVzZSB0aGV5IGFyZSBsb2FkZWQgYnkgZmV0Y2hpbmcgdGhlIGhpc3RvcnkgaGVuY2Ugd2h5IHdlIHN1cHBseSB0aGUgbWVzc2FnZSBoZXJlXG4gICAgICAgICAgICAgICAgdGhpcy5lbWl0QnJvd3Nlck5vdGlmaWNhdGlvbihjaGF0V2luZG93WzBdLCBtZXNzYWdlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIG9uUGFydGljaXBhbnRDbGlja2VkRnJvbUZyaWVuZHNMaXN0KHBhcnRpY2lwYW50OiBJQ2hhdFBhcnRpY2lwYW50KTogdm9pZCB7XG4gICAgICAgIHRoaXMub3BlbkNoYXRXaW5kb3cocGFydGljaXBhbnQsIHRydWUsIHRydWUpO1xuICAgIH1cblxuICAgIHByaXZhdGUgY2FuY2VsT3B0aW9uUHJvbXB0KCk6IHZvaWQge1xuICAgICAgICBpZiAodGhpcy5jdXJyZW50QWN0aXZlT3B0aW9uKVxuICAgICAgICB7XG4gICAgICAgICAgICB0aGlzLmN1cnJlbnRBY3RpdmVPcHRpb24uaXNBY3RpdmUgPSBmYWxzZTtcbiAgICAgICAgICAgIHRoaXMuY3VycmVudEFjdGl2ZU9wdGlvbiA9IG51bGw7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBvbk9wdGlvblByb21wdENhbmNlbGVkKCk6IHZvaWQge1xuICAgICAgICB0aGlzLmNhbmNlbE9wdGlvblByb21wdCgpO1xuICAgIH1cblxuICAgIG9uT3B0aW9uUHJvbXB0Q29uZmlybWVkKGV2ZW50OiBhbnkpOiB2b2lkIHtcbiAgICAgICAgLy8gRm9yIG5vdyB0aGlzIGlzIGZpbmUgYXMgdGhlcmUgaXMgb25seSBvbmUgb3B0aW9uIGF2YWlsYWJsZS4gSW50cm9kdWNlIG9wdGlvbiB0eXBlcyBhbmQgdHlwZSBjaGVja2luZyBpZiBhIG5ldyBvcHRpb24gaXMgYWRkZWQuXG4gICAgICAgIHRoaXMuY29uZmlybU5ld0dyb3VwKGV2ZW50KTtcblxuICAgICAgICAvLyBDYW5jZWxpbmcgY3VycmVudCBzdGF0ZVxuICAgICAgICB0aGlzLmNhbmNlbE9wdGlvblByb21wdCgpO1xuICAgIH1cblxuICAgIHByaXZhdGUgY29uZmlybU5ld0dyb3VwKHVzZXJzOiBVc2VyW10pOiB2b2lkIHtcbiAgICAgICAgY29uc3QgbmV3R3JvdXAgPSBuZXcgR3JvdXAodXNlcnMpO1xuXG4gICAgICAgIHRoaXMub3BlbkNoYXRXaW5kb3cobmV3R3JvdXApO1xuXG4gICAgICAgIGlmICh0aGlzLmdyb3VwQWRhcHRlcilcbiAgICAgICAge1xuICAgICAgICAgICAgdGhpcy5ncm91cEFkYXB0ZXIuZ3JvdXBDcmVhdGVkKG5ld0dyb3VwKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8vIE9wZW5zIGEgbmV3IGNoYXQgd2hpbmRvdy4gVGFrZXMgY2FyZSBvZiBhdmFpbGFibGUgdmlld3BvcnRcbiAgICAvLyBXb3JrcyBmb3Igb3BlbmluZyBhIGNoYXQgd2luZG93IGZvciBhbiB1c2VyIG9yIGZvciBhIGdyb3VwXG4gICAgLy8gUmV0dXJucyA9PiBbV2luZG93OiBXaW5kb3cgb2JqZWN0IHJlZmVyZW5jZSwgYm9vbGVhbjogSW5kaWNhdGVzIGlmIHRoaXMgd2luZG93IGlzIGEgbmV3IGNoYXQgd2luZG93XVxuICAgIHByaXZhdGUgb3BlbkNoYXRXaW5kb3cocGFydGljaXBhbnQ6IElDaGF0UGFydGljaXBhbnQsIGZvY3VzT25OZXdXaW5kb3c6IGJvb2xlYW4gPSBmYWxzZSwgaW52b2tlZEJ5VXNlckNsaWNrOiBib29sZWFuID0gZmFsc2UpOiBbV2luZG93LCBib29sZWFuXVxuICAgIHtcbiAgICAgICAgLy8gSXMgdGhpcyB3aW5kb3cgb3BlbmVkP1xuICAgICAgICBjb25zdCBvcGVuZWRXaW5kb3cgPSB0aGlzLndpbmRvd3MuZmluZCh4ID0+IHgucGFydGljaXBhbnQuaWQgPT0gcGFydGljaXBhbnQuaWQpO1xuXG4gICAgICAgIGlmICghb3BlbmVkV2luZG93KVxuICAgICAgICB7XG4gICAgICAgICAgICBpZiAoaW52b2tlZEJ5VXNlckNsaWNrKVxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIHRoaXMub25QYXJ0aWNpcGFudENsaWNrZWQuZW1pdChwYXJ0aWNpcGFudCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIFJlZmVyIHRvIGlzc3VlICM1OCBvbiBHaXRodWJcbiAgICAgICAgICAgIGNvbnN0IGNvbGxhcHNlV2luZG93ID0gaW52b2tlZEJ5VXNlckNsaWNrID8gZmFsc2UgOiAhdGhpcy5tYXhpbWl6ZVdpbmRvd09uTmV3TWVzc2FnZTtcblxuICAgICAgICAgICAgY29uc3QgbmV3Q2hhdFdpbmRvdzogV2luZG93ID0gbmV3IFdpbmRvdyhwYXJ0aWNpcGFudCwgdGhpcy5oaXN0b3J5RW5hYmxlZCwgY29sbGFwc2VXaW5kb3cpO1xuXG4gICAgICAgICAgICAvLyBMb2FkcyB0aGUgY2hhdCBoaXN0b3J5IHZpYSBhbiBSeEpzIE9ic2VydmFibGVcbiAgICAgICAgICAgIGlmICh0aGlzLmhpc3RvcnlFbmFibGVkKVxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIHRoaXMuZmV0Y2hNZXNzYWdlSGlzdG9yeShuZXdDaGF0V2luZG93KTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdGhpcy53aW5kb3dzLnVuc2hpZnQobmV3Q2hhdFdpbmRvdyk7XG5cbiAgICAgICAgICAgIC8vIElzIHRoZXJlIGVub3VnaCBzcGFjZSBsZWZ0IGluIHRoZSB2aWV3IHBvcnQgPyBidXQgc2hvdWxkIGJlIGRpc3BsYXllZCBpbiBtb2JpbGUgaWYgb3B0aW9uIGlzIGVuYWJsZWRcbiAgICAgICAgICAgIGlmICghdGhpcy5pc1ZpZXdwb3J0T25Nb2JpbGVFbmFibGVkKSB7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMud2luZG93cy5sZW5ndGggKiB0aGlzLndpbmRvd1NpemVGYWN0b3IgPj0gdGhpcy52aWV3UG9ydFRvdGFsQXJlYSAtICghdGhpcy5oaWRlRnJpZW5kc0xpc3QgPyB0aGlzLmZyaWVuZHNMaXN0V2lkdGggOiAwKSkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLndpbmRvd3MucG9wKCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB0aGlzLnVwZGF0ZVdpbmRvd3NTdGF0ZSh0aGlzLndpbmRvd3MpO1xuXG4gICAgICAgICAgICBpZiAoZm9jdXNPbk5ld1dpbmRvdyAmJiAhY29sbGFwc2VXaW5kb3cpXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgdGhpcy5mb2N1c09uV2luZG93KG5ld0NoYXRXaW5kb3cpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB0aGlzLnBhcnRpY2lwYW50c0ludGVyYWN0ZWRXaXRoLnB1c2gocGFydGljaXBhbnQpO1xuICAgICAgICAgICAgdGhpcy5vblBhcnRpY2lwYW50Q2hhdE9wZW5lZC5lbWl0KHBhcnRpY2lwYW50KTtcblxuICAgICAgICAgICAgcmV0dXJuIFtuZXdDaGF0V2luZG93LCB0cnVlXTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlXG4gICAgICAgIHtcbiAgICAgICAgICAgIC8vIFJldHVybnMgdGhlIGV4aXN0aW5nIGNoYXQgd2luZG93XG4gICAgICAgICAgICByZXR1cm4gW29wZW5lZFdpbmRvdywgZmFsc2VdO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLy8gRm9jdXMgb24gdGhlIGlucHV0IGVsZW1lbnQgb2YgdGhlIHN1cHBsaWVkIHdpbmRvd1xuICAgIHByaXZhdGUgZm9jdXNPbldpbmRvdyh3aW5kb3c6IFdpbmRvdywgY2FsbGJhY2s6IEZ1bmN0aW9uID0gKCkgPT4ge30pIDogdm9pZFxuICAgIHtcbiAgICAgICAgY29uc3Qgd2luZG93SW5kZXggPSB0aGlzLndpbmRvd3MuaW5kZXhPZih3aW5kb3cpO1xuICAgICAgICBpZiAod2luZG93SW5kZXggPj0gMClcbiAgICAgICAge1xuICAgICAgICAgICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuY2hhdFdpbmRvd3MpXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBjaGF0V2luZG93VG9Gb2N1cyA9IHRoaXMuY2hhdFdpbmRvd3MudG9BcnJheSgpW3dpbmRvd0luZGV4XTtcblxuICAgICAgICAgICAgICAgICAgICBjaGF0V2luZG93VG9Gb2N1cy5jaGF0V2luZG93SW5wdXQubmF0aXZlRWxlbWVudC5mb2N1cygpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGNhbGxiYWNrKCk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgYXNzZXJ0TWVzc2FnZVR5cGUobWVzc2FnZTogTWVzc2FnZSk6IHZvaWQge1xuICAgICAgICAvLyBBbHdheXMgZmFsbGJhY2sgdG8gXCJUZXh0XCIgbWVzc2FnZXMgdG8gYXZvaWQgcmVuZGVucmluZyBpc3N1ZXNcbiAgICAgICAgaWYgKCFtZXNzYWdlLnR5cGUpXG4gICAgICAgIHtcbiAgICAgICAgICAgIG1lc3NhZ2UudHlwZSA9IE1lc3NhZ2VUeXBlLlRleHQ7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBNYXJrcyBhbGwgbWVzc2FnZXMgcHJvdmlkZWQgYXMgcmVhZCB3aXRoIHRoZSBjdXJyZW50IHRpbWUuXG4gICAgbWFya01lc3NhZ2VzQXNSZWFkKG1lc3NhZ2VzOiBNZXNzYWdlW10pOiB2b2lkXG4gICAge1xuICAgICAgICBjb25zdCBjdXJyZW50RGF0ZSA9IG5ldyBEYXRlKCk7XG5cbiAgICAgICAgbWVzc2FnZXMuZm9yRWFjaCgobXNnKT0+e1xuICAgICAgICAgICAgbXNnLmRhdGVTZWVuID0gY3VycmVudERhdGU7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHRoaXMub25NZXNzYWdlc1NlZW4uZW1pdChtZXNzYWdlcyk7XG4gICAgfVxuXG4gICAgLy8gQnVmZmVycyBhdWRpbyBmaWxlIChGb3IgY29tcG9uZW50J3MgYm9vdHN0cmFwcGluZylcbiAgICBwcml2YXRlIGJ1ZmZlckF1ZGlvRmlsZSgpOiB2b2lkIHtcbiAgICAgICAgaWYgKHRoaXMuYXVkaW9Tb3VyY2UgJiYgdGhpcy5hdWRpb1NvdXJjZS5sZW5ndGggPiAwKVxuICAgICAgICB7XG4gICAgICAgICAgICB0aGlzLmF1ZGlvRmlsZSA9IG5ldyBBdWRpbygpO1xuICAgICAgICAgICAgdGhpcy5hdWRpb0ZpbGUuc3JjID0gdGhpcy5hdWRpb1NvdXJjZTtcbiAgICAgICAgICAgIHRoaXMuYXVkaW9GaWxlLmxvYWQoKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8vIEVtaXRzIGEgbWVzc2FnZSBub3RpZmljYXRpb24gYXVkaW8gaWYgZW5hYmxlZCBhZnRlciBldmVyeSBtZXNzYWdlIHJlY2VpdmVkXG4gICAgcHJpdmF0ZSBlbWl0TWVzc2FnZVNvdW5kKHdpbmRvdzogV2luZG93KTogdm9pZFxuICAgIHtcbiAgICAgICAgaWYgKHRoaXMuYXVkaW9FbmFibGVkICYmICF3aW5kb3cuaGFzRm9jdXMgJiYgdGhpcy5hdWRpb0ZpbGUpIHtcbiAgICAgICAgICAgIHRoaXMuYXVkaW9GaWxlLnBsYXkoKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8vIEVtaXRzIGEgYnJvd3NlciBub3RpZmljYXRpb25cbiAgICBwcml2YXRlIGVtaXRCcm93c2VyTm90aWZpY2F0aW9uKHdpbmRvdzogV2luZG93LCBtZXNzYWdlOiBNZXNzYWdlKTogdm9pZFxuICAgIHtcbiAgICAgICAgLy8gaWYgKHRoaXMuYnJvd3Nlck5vdGlmaWNhdGlvbnNCb290c3RyYXBwZWQgJiYgIXdpbmRvdy5oYXNGb2N1cyAmJiBtZXNzYWdlKSB7XG4gICAgICAgIGlmICh0aGlzLmJyb3dzZXJOb3RpZmljYXRpb25zQm9vdHN0cmFwcGVkICYmIG1lc3NhZ2UpIHtcbiAgICAgICAgICAgIGNvbnN0IG5vdGlmaWNhdGlvbiA9IG5ldyBOb3RpZmljYXRpb24oYCR7dGhpcy5sb2NhbGl6YXRpb24uYnJvd3Nlck5vdGlmaWNhdGlvblRpdGxlfSAke3dpbmRvdy5wYXJ0aWNpcGFudC5kaXNwbGF5TmFtZX1gLCB7XG4gICAgICAgICAgICAgICAgJ2JvZHknOiBtZXNzYWdlLm1lc3NhZ2UsXG4gICAgICAgICAgICAgICAgJ2ljb24nOiB0aGlzLmJyb3dzZXJOb3RpZmljYXRpb25JY29uU291cmNlXG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgICAgICAgICAgbm90aWZpY2F0aW9uLmNsb3NlKCk7XG4gICAgICAgICAgICB9LCBtZXNzYWdlLm1lc3NhZ2UubGVuZ3RoIDw9IDUwID8gNTAwMCA6IDcwMDApOyAvLyBNb3JlIHRpbWUgdG8gcmVhZCBsb25nZXIgbWVzc2FnZXNcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8vIFNhdmVzIGN1cnJlbnQgd2luZG93cyBzdGF0ZSBpbnRvIGxvY2FsIHN0b3JhZ2UgaWYgcGVyc2lzdGVuY2UgaXMgZW5hYmxlZFxuICAgIHByaXZhdGUgdXBkYXRlV2luZG93c1N0YXRlKHdpbmRvd3M6IFdpbmRvd1tdKTogdm9pZFxuICAgIHtcbiAgICAgICAgaWYgKHRoaXMucGVyc2lzdFdpbmRvd3NTdGF0ZSlcbiAgICAgICAge1xuICAgICAgICAgICAgY29uc3QgcGFydGljaXBhbnRJZHMgPSB3aW5kb3dzLm1hcCgodykgPT4ge1xuICAgICAgICAgICAgICAgIHJldHVybiB3LnBhcnRpY2lwYW50LmlkO1xuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIGxvY2FsU3RvcmFnZS5zZXRJdGVtKHRoaXMubG9jYWxTdG9yYWdlS2V5LCBKU09OLnN0cmluZ2lmeShwYXJ0aWNpcGFudElkcykpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJpdmF0ZSByZXN0b3JlV2luZG93c1N0YXRlKCk6IHZvaWRcbiAgICB7XG4gICAgICAgIHRyeVxuICAgICAgICB7XG4gICAgICAgICAgICBpZiAodGhpcy5wZXJzaXN0V2luZG93c1N0YXRlKVxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIGNvbnN0IHN0cmluZ2ZpZWRQYXJ0aWNpcGFudElkcyA9IGxvY2FsU3RvcmFnZS5nZXRJdGVtKHRoaXMubG9jYWxTdG9yYWdlS2V5KTtcblxuICAgICAgICAgICAgICAgIGlmIChzdHJpbmdmaWVkUGFydGljaXBhbnRJZHMgJiYgc3RyaW5nZmllZFBhcnRpY2lwYW50SWRzLmxlbmd0aCA+IDApXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBwYXJ0aWNpcGFudElkcyA9IDxudW1iZXJbXT5KU09OLnBhcnNlKHN0cmluZ2ZpZWRQYXJ0aWNpcGFudElkcyk7XG5cbiAgICAgICAgICAgICAgICAgICAgY29uc3QgcGFydGljaXBhbnRzVG9SZXN0b3JlID0gdGhpcy5wYXJ0aWNpcGFudHMuZmlsdGVyKHUgPT4gcGFydGljaXBhbnRJZHMuaW5kZXhPZih1LmlkKSA+PSAwKTtcblxuICAgICAgICAgICAgICAgICAgICBwYXJ0aWNpcGFudHNUb1Jlc3RvcmUuZm9yRWFjaCgocGFydGljaXBhbnQpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMub3BlbkNoYXRXaW5kb3cocGFydGljaXBhbnQpO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgY2F0Y2ggKGV4KVxuICAgICAgICB7XG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKGBBbiBlcnJvciBvY2N1cnJlZCB3aGlsZSByZXN0b3JpbmcgbmctY2hhdCB3aW5kb3dzIHN0YXRlLiBEZXRhaWxzOiAke2V4fWApO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLy8gR2V0cyBjbG9zZXN0IG9wZW4gd2luZG93IGlmIGFueS4gTW9zdCByZWNlbnQgb3BlbmVkIGhhcyBwcmlvcml0eSAoUmlnaHQpXG4gICAgcHJpdmF0ZSBnZXRDbG9zZXN0V2luZG93KHdpbmRvdzogV2luZG93KTogV2luZG93IHwgdW5kZWZpbmVkXG4gICAge1xuICAgICAgICBjb25zdCBpbmRleCA9IHRoaXMud2luZG93cy5pbmRleE9mKHdpbmRvdyk7XG5cbiAgICAgICAgaWYgKGluZGV4ID4gMClcbiAgICAgICAge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMud2luZG93c1tpbmRleCAtIDFdO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKGluZGV4ID09IDAgJiYgdGhpcy53aW5kb3dzLmxlbmd0aCA+IDEpXG4gICAgICAgIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLndpbmRvd3NbaW5kZXggKyAxXTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgY2xvc2VXaW5kb3cod2luZG93OiBXaW5kb3cpOiB2b2lkXG4gICAge1xuICAgICAgICBjb25zdCBpbmRleCA9IHRoaXMud2luZG93cy5pbmRleE9mKHdpbmRvdyk7XG5cbiAgICAgICAgdGhpcy53aW5kb3dzLnNwbGljZShpbmRleCwgMSk7XG5cbiAgICAgICAgdGhpcy51cGRhdGVXaW5kb3dzU3RhdGUodGhpcy53aW5kb3dzKTtcblxuICAgICAgICB0aGlzLm9uUGFydGljaXBhbnRDaGF0Q2xvc2VkLmVtaXQod2luZG93LnBhcnRpY2lwYW50KTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGdldENoYXRXaW5kb3dDb21wb25lbnRJbnN0YW5jZSh0YXJnZXRXaW5kb3c6IFdpbmRvdyk6IE5nQ2hhdFdpbmRvd0NvbXBvbmVudCB8IG51bGwge1xuICAgICAgICBjb25zdCB3aW5kb3dJbmRleCA9IHRoaXMud2luZG93cy5pbmRleE9mKHRhcmdldFdpbmRvdyk7XG5cbiAgICAgICAgaWYgKHRoaXMuY2hhdFdpbmRvd3Mpe1xuICAgICAgICAgICAgbGV0IHRhcmdldFdpbmRvdyA9IHRoaXMuY2hhdFdpbmRvd3MudG9BcnJheSgpW3dpbmRvd0luZGV4XTtcblxuICAgICAgICAgICAgcmV0dXJuIHRhcmdldFdpbmRvdztcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIC8vIFNjcm9sbHMgYSBjaGF0IHdpbmRvdyBtZXNzYWdlIGZsb3cgdG8gdGhlIGJvdHRvbVxuICAgIHByaXZhdGUgc2Nyb2xsQ2hhdFdpbmRvdyh3aW5kb3c6IFdpbmRvdywgZGlyZWN0aW9uOiBTY3JvbGxEaXJlY3Rpb24pOiB2b2lkXG4gICAge1xuICAgICAgICBjb25zdCBjaGF0V2luZG93ID0gdGhpcy5nZXRDaGF0V2luZG93Q29tcG9uZW50SW5zdGFuY2Uod2luZG93KTtcblxuICAgICAgICBpZiAoY2hhdFdpbmRvdyl7XG4gICAgICAgICAgICBjaGF0V2luZG93LnNjcm9sbENoYXRXaW5kb3cod2luZG93LCBkaXJlY3Rpb24pO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgb25XaW5kb3dNZXNzYWdlc1NlZW4obWVzc2FnZXNTZWVuOiBNZXNzYWdlW10pOiB2b2lkIHtcbiAgICAgICAgdGhpcy5tYXJrTWVzc2FnZXNBc1JlYWQobWVzc2FnZXNTZWVuKTtcbiAgICB9XG5cbiAgICBvbldpbmRvd0NoYXRDbG9zZWQocGF5bG9hZDogeyBjbG9zZWRXaW5kb3c6IFdpbmRvdywgY2xvc2VkVmlhRXNjYXBlS2V5OiBib29sZWFuIH0pOiB2b2lkIHtcbiAgICAgICAgY29uc3QgeyBjbG9zZWRXaW5kb3csIGNsb3NlZFZpYUVzY2FwZUtleSB9ID0gcGF5bG9hZDtcblxuICAgICAgICBpZiAoY2xvc2VkVmlhRXNjYXBlS2V5KSB7XG4gICAgICAgICAgICBsZXQgY2xvc2VzdFdpbmRvdyA9IHRoaXMuZ2V0Q2xvc2VzdFdpbmRvdyhjbG9zZWRXaW5kb3cpO1xuXG4gICAgICAgICAgICBpZiAoY2xvc2VzdFdpbmRvdylcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICB0aGlzLmZvY3VzT25XaW5kb3coY2xvc2VzdFdpbmRvdywgKCkgPT4geyB0aGlzLmNsb3NlV2luZG93KGNsb3NlZFdpbmRvdyk7IH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZVxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIHRoaXMuY2xvc2VXaW5kb3coY2xvc2VkV2luZG93KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuY2xvc2VXaW5kb3coY2xvc2VkV2luZG93KTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIG9uV2luZG93VGFiVHJpZ2dlcmVkKHBheWxvYWQ6IHsgdHJpZ2dlcmluZ1dpbmRvdzogV2luZG93LCBzaGlmdEtleVByZXNzZWQ6IGJvb2xlYW4gfSk6IHZvaWQge1xuICAgICAgICBjb25zdCB7IHRyaWdnZXJpbmdXaW5kb3csIHNoaWZ0S2V5UHJlc3NlZCB9ID0gcGF5bG9hZDtcblxuICAgICAgICBjb25zdCBjdXJyZW50V2luZG93SW5kZXggPSB0aGlzLndpbmRvd3MuaW5kZXhPZih0cmlnZ2VyaW5nV2luZG93KTtcbiAgICAgICAgbGV0IHdpbmRvd1RvRm9jdXMgPSB0aGlzLndpbmRvd3NbY3VycmVudFdpbmRvd0luZGV4ICsgKHNoaWZ0S2V5UHJlc3NlZCA/IDEgOiAtMSldOyAvLyBHb2VzIGJhY2sgb24gc2hpZnQgKyB0YWJcblxuICAgICAgICBpZiAoIXdpbmRvd1RvRm9jdXMpXG4gICAgICAgIHtcbiAgICAgICAgICAgIC8vIEVkZ2Ugd2luZG93cywgZ28gdG8gc3RhcnQgb3IgZW5kXG4gICAgICAgICAgICB3aW5kb3dUb0ZvY3VzID0gdGhpcy53aW5kb3dzW2N1cnJlbnRXaW5kb3dJbmRleCA+IDAgPyAwIDogdGhpcy5jaGF0V2luZG93cy5sZW5ndGggLSAxXTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuZm9jdXNPbldpbmRvdyh3aW5kb3dUb0ZvY3VzKTtcbiAgICB9XG5cbiAgICBvbldpbmRvd01lc3NhZ2VTZW50KG1lc3NhZ2VTZW50OiBNZXNzYWdlKTogdm9pZCB7XG4gICAgICAgIHRoaXMuYWRhcHRlci5zZW5kTWVzc2FnZShtZXNzYWdlU2VudCk7XG4gICAgfVxuXG4gICAgb25XaW5kb3dPcHRpb25UcmlnZ2VyZWQob3B0aW9uOiBJQ2hhdE9wdGlvbik6IHZvaWQge1xuICAgICAgICB0aGlzLmN1cnJlbnRBY3RpdmVPcHRpb24gPSBvcHRpb247XG4gICAgfVxuXG4gICAgdHJpZ2dlck9wZW5DaGF0V2luZG93KHVzZXI6IFVzZXIpOiB2b2lkIHtcbiAgICAgICAgaWYgKHVzZXIpXG4gICAgICAgIHtcbiAgICAgICAgICAgIHRoaXMub3BlbkNoYXRXaW5kb3codXNlcik7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgcHVibGljICB0cmlnZ2VyQ2xvc2VDaGF0V2luZG93KHVzZXJJZDogYW55KTogdm9pZCB7XG4gICAgICAgIGNvbnN0IG9wZW5lZFdpbmRvdyA9IHRoaXMud2luZG93cy5maW5kKHggPT4geC5wYXJ0aWNpcGFudC5pZCA9PSB1c2VySWQpO1xuXG4gICAgICAgIGlmIChvcGVuZWRXaW5kb3cpXG4gICAgICAgIHtcbiAgICAgICAgICAgIHRoaXMuY2xvc2VXaW5kb3cob3BlbmVkV2luZG93KTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHRyaWdnZXJUb2dnbGVDaGF0V2luZG93VmlzaWJpbGl0eSh1c2VySWQ6IGFueSk6IHZvaWQge1xuICAgICAgICBjb25zdCBvcGVuZWRXaW5kb3cgPSB0aGlzLndpbmRvd3MuZmluZCh4ID0+IHgucGFydGljaXBhbnQuaWQgPT0gdXNlcklkKTtcblxuICAgICAgICBpZiAob3BlbmVkV2luZG93KVxuICAgICAgICB7XG4gICAgICAgICAgICBjb25zdCBjaGF0V2luZG93ID0gdGhpcy5nZXRDaGF0V2luZG93Q29tcG9uZW50SW5zdGFuY2Uob3BlbmVkV2luZG93KTtcblxuICAgICAgICAgICAgaWYgKGNoYXRXaW5kb3cpe1xuICAgICAgICAgICAgICAgIGNoYXRXaW5kb3cub25DaGF0V2luZG93Q2xpY2tlZChvcGVuZWRXaW5kb3cpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgLy8gY2xvc2VGcmllbmRMaXN0KCl7XG4gICAgLy8gICAgIHRoaXMuaGlkZUZyaWVuZHNMaXN0ID0gIXRoaXMuaGlkZUZyaWVuZHNMaXN0XG4gICAgLy8gICAgIHRoaXMuaGlkZUZyaWVuZHNMaXN0Q2hhbmdlLmVtaXQodGhpcy5oaWRlRnJpZW5kc0xpc3QpXG4gICAgLy8gfVxuICAgIG9uQ2xvc2VXaW5kb3dDbGljayhjbGljazpib29sZWFuKXtcblxuICAgICAgICB0aGlzLm9uQ2xvc2VXaW5kb3dDbGlja2VkLmVtaXQoY2xpY2spXG5cblxuXG4gICAgfVxufVxuLyogZXNsaW50LWVuYWJsZSAqLyIsIjxsaW5rICpuZ0lmPVwiY3VzdG9tVGhlbWVcIiByZWw9XCJzdHlsZXNoZWV0XCIgW2hyZWZdPSdjdXN0b21UaGVtZSB8IHNhbml0aXplJz5cblxuPGRpdiBpZD1cIm5nLWNoYXRcIiAqbmdJZj1cIiFpc0Rpc2FibGVkICYmIGlzQm9vdHN0cmFwcGVkICYmICF1bnN1cHBvcnRlZFZpZXdwb3J0XCIgW25nQ2xhc3NdPVwidGhlbWVcIj5cbiAgICA8bmctY2hhdC1mcmllbmRzLWxpc3RcbiAgICAgICAgW2xvY2FsaXphdGlvbl09XCJsb2NhbGl6YXRpb25cIlxuICAgICAgICBbc2hvdWxkRGlzcGxheV09XCIhaGlkZUZyaWVuZHNMaXN0XCJcbiAgICAgICAgW3VzZXJJZF09XCJ1c2VySWRcIlxuICAgICAgICBbaXNDb2xsYXBzZWRdPVwiaXNDb2xsYXBzZWRcIlxuICAgICAgICBbc2VhcmNoRW5hYmxlZF09XCJzZWFyY2hFbmFibGVkXCJcbiAgICAgICAgW3BhcnRpY2lwYW50c109XCJwYXJ0aWNpcGFudHNcIlxuICAgICAgICBbcGFydGljaXBhbnRzUmVzcG9uc2VdPVwicGFydGljaXBhbnRzUmVzcG9uc2VcIlxuICAgICAgICBbcGFydGljaXBhbnRzSW50ZXJhY3RlZFdpdGhdPVwicGFydGljaXBhbnRzSW50ZXJhY3RlZFdpdGhcIlxuICAgICAgICBbd2luZG93c109XCJ3aW5kb3dzXCJcbiAgICAgICAgW2N1cnJlbnRBY3RpdmVPcHRpb25dPVwiY3VycmVudEFjdGl2ZU9wdGlvblwiXG4gICAgICAgIChvblBhcnRpY2lwYW50Q2xpY2tlZCk9XCJvblBhcnRpY2lwYW50Q2xpY2tlZEZyb21GcmllbmRzTGlzdCgkZXZlbnQpXCJcbiAgICAgICAgKG9uT3B0aW9uUHJvbXB0Q2FuY2VsZWQpPVwib25PcHRpb25Qcm9tcHRDYW5jZWxlZCgpXCJcbiAgICAgICAgKG9uT3B0aW9uUHJvbXB0Q29uZmlybWVkKT1cIm9uT3B0aW9uUHJvbXB0Q29uZmlybWVkKCRldmVudClcIlxuICAgICAgICAob25DbG9zZVdpbmRvd0NsaWNrKT1cIm9uQ2xvc2VXaW5kb3dDbGljaygkZXZlbnQpXCJcbiAgICA+XG4gICAgPC9uZy1jaGF0LWZyaWVuZHMtbGlzdD5cblxuICAgIDxkaXYgKm5nRm9yPVwibGV0IHdpbmRvdyBvZiB3aW5kb3dzOyBsZXQgaSA9IGluZGV4XCIgW25nQ2xhc3NdPVwieyduZy1jaGF0LXdpbmRvdyc6IHRydWUsICdwcmltYXJ5LW91dGxpbmUtY29sb3InOiB0cnVlLCAnbmctY2hhdC13aW5kb3ctY29sbGFwc2VkJzogd2luZG93LmlzQ29sbGFwc2VkfVwiIFtuZ1N0eWxlXT1cInsncmlnaHQnOiAoIWhpZGVGcmllbmRzTGlzdCA/IGZyaWVuZHNMaXN0V2lkdGggOiAwKSArIDIwICsgd2luZG93U2l6ZUZhY3RvciAqIGkgKyAncHgnfVwiPlxuICAgICAgICA8bmctY2hhdC13aW5kb3dcbiAgICAgICAgICAgICNjaGF0V2luZG93XG4gICAgICAgICAgICBbZmlsZVVwbG9hZEFkYXB0ZXJdPVwiZmlsZVVwbG9hZEFkYXB0ZXJcIlxuICAgICAgICAgICAgW2xvY2FsaXphdGlvbl09XCJsb2NhbGl6YXRpb25cIlxuICAgICAgICAgICAgW3VzZXJJZF09XCJ1c2VySWRcIlxuICAgICAgICAgICAgW3dpbmRvd109XCJ3aW5kb3dcIlxuICAgICAgICAgICAgW3Nob3dPcHRpb25zXT1cImdyb3VwQWRhcHRlclwiXG4gICAgICAgICAgICBbZW1vamlzRW5hYmxlZF09XCJlbW9qaXNFbmFibGVkXCJcbiAgICAgICAgICAgIFtsaW5rZnlFbmFibGVkXT1cImxpbmtmeUVuYWJsZWRcIlxuICAgICAgICAgICAgW3Nob3dNZXNzYWdlRGF0ZV09XCJzaG93TWVzc2FnZURhdGVcIlxuICAgICAgICAgICAgW21lc3NhZ2VEYXRlUGlwZUZvcm1hdF09XCJtZXNzYWdlRGF0ZVBpcGVGb3JtYXRcIlxuICAgICAgICAgICAgW2hhc1BhZ2VkSGlzdG9yeV09XCJoYXNQYWdlZEhpc3RvcnlcIlxuICAgICAgICAgICAgKG9uTWVzc2FnZXNTZWVuKT1cIm9uV2luZG93TWVzc2FnZXNTZWVuKCRldmVudClcIlxuICAgICAgICAgICAgKG9uTWVzc2FnZVNlbnQpPVwib25XaW5kb3dNZXNzYWdlU2VudCgkZXZlbnQpXCJcbiAgICAgICAgICAgIChvblRhYlRyaWdnZXJlZCk9XCJvbldpbmRvd1RhYlRyaWdnZXJlZCgkZXZlbnQpXCJcbiAgICAgICAgICAgIChvbkNoYXRXaW5kb3dDbG9zZWQpPVwib25XaW5kb3dDaGF0Q2xvc2VkKCRldmVudClcIlxuICAgICAgICAgICAgKG9uT3B0aW9uVHJpZ2dlcmVkKT1cIm9uV2luZG93T3B0aW9uVHJpZ2dlcmVkKCRldmVudClcIlxuICAgICAgICAgICAgKG9uTG9hZEhpc3RvcnlUcmlnZ2VyZWQpPVwiZmV0Y2hNZXNzYWdlSGlzdG9yeSgkZXZlbnQpXCJcbiAgICAgICAgPlxuICAgICAgICA8L25nLWNoYXQtd2luZG93PlxuICAgIDwvZGl2PlxuPC9kaXY+XG4iXX0=