@banta/sdk 6.0.3 → 7.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/banta-sdk.mjs +327 -6762
- package/fesm2022/banta-sdk.mjs.map +1 -1
- package/index.d.ts +1472 -3
- package/package.json +11 -13
- package/esm2022/banta-sdk.mjs +0 -5
- package/esm2022/lib/attachment-scraper.mjs +0 -2
- package/esm2022/lib/banta/banta.component.mjs +0 -207
- package/esm2022/lib/banta-logo.component.mjs +0 -11
- package/esm2022/lib/banta-sdk.module.mjs +0 -135
- package/esm2022/lib/chat/banta-chat/banta-chat.component.mjs +0 -209
- package/esm2022/lib/chat/chat-message/chat-message.component.mjs +0 -62
- package/esm2022/lib/chat/chat-view/chat-view.component.mjs +0 -166
- package/esm2022/lib/chat/chat.module.mjs +0 -51
- package/esm2022/lib/chat/index.mjs +0 -6
- package/esm2022/lib/chat/live-chat-message.component.mjs +0 -80
- package/esm2022/lib/chat-backend-base.mjs +0 -31
- package/esm2022/lib/chat-backend.mjs +0 -199
- package/esm2022/lib/chat-source-base.mjs +0 -2
- package/esm2022/lib/chat-source.mjs +0 -282
- package/esm2022/lib/comments/attachment-button/attachment-button.component.mjs +0 -75
- package/esm2022/lib/comments/attachment-scraper.directive.mjs +0 -101
- package/esm2022/lib/comments/banta-comments/banta-comments.component.mjs +0 -817
- package/esm2022/lib/comments/comment/comment.component.mjs +0 -224
- package/esm2022/lib/comments/comment-field/comment-field.component.mjs +0 -411
- package/esm2022/lib/comments/comment-sort/comment-sort.component.mjs +0 -37
- package/esm2022/lib/comments/comment-view/comment-view.component.mjs +0 -780
- package/esm2022/lib/comments/comments.module.mjs +0 -127
- package/esm2022/lib/comments/index.mjs +0 -12
- package/esm2022/lib/comments/inline-replies.directive.mjs +0 -13
- package/esm2022/lib/comments/live-comment.component.mjs +0 -80
- package/esm2022/lib/comments/reply-send-options.directive.mjs +0 -13
- package/esm2022/lib/common/attachment/attachment.component.mjs +0 -128
- package/esm2022/lib/common/attachments/attachments.component.mjs +0 -75
- package/esm2022/lib/common/common.module.mjs +0 -68
- package/esm2022/lib/common/index.mjs +0 -11
- package/esm2022/lib/common/lazy-connection.mjs +0 -15
- package/esm2022/lib/common/lightbox/lightbox.component.mjs +0 -31
- package/esm2022/lib/common/markdown-to-html.pipe.mjs +0 -83
- package/esm2022/lib/common/mention-linker.pipe.mjs +0 -35
- package/esm2022/lib/common/timer-pool.service.mjs +0 -85
- package/esm2022/lib/common/timestamp.component.mjs +0 -124
- package/esm2022/lib/common/trust-resource-url.pipe.mjs +0 -22
- package/esm2022/lib/emoji/emoji-selector-button.component.mjs +0 -115
- package/esm2022/lib/emoji/emoji-selector-panel/emoji-selector-panel.component.mjs +0 -93
- package/esm2022/lib/emoji/emoji.module.mjs +0 -55
- package/esm2022/lib/emoji/emojis.mjs +0 -6508
- package/esm2022/lib/emoji/index.mjs +0 -5
- package/esm2022/lib/giphy-attachments.mjs +0 -16
- package/esm2022/lib/index.mjs +0 -20
- package/esm2022/lib/live-message.component.mjs +0 -96
- package/esm2022/lib/message-menu-item.mjs +0 -2
- package/esm2022/lib/sdk-options.mjs +0 -3
- package/esm2022/lib/static-chat-source.mjs +0 -101
- package/esm2022/lib/tweet-attachments.mjs +0 -13
- package/esm2022/lib/url-attachments.mjs +0 -42
- package/esm2022/lib/youtube-attachments.mjs +0 -29
- package/esm2022/public-api.mjs +0 -5
- package/lib/attachment-scraper.d.ts +0 -15
- package/lib/banta/banta.component.d.ts +0 -59
- package/lib/banta-logo.component.d.ts +0 -5
- package/lib/banta-sdk.module.d.ts +0 -32
- package/lib/chat/banta-chat/banta-chat.component.d.ts +0 -79
- package/lib/chat/chat-message/chat-message.component.d.ts +0 -21
- package/lib/chat/chat-view/chat-view.component.d.ts +0 -52
- package/lib/chat/chat.module.d.ts +0 -15
- package/lib/chat/index.d.ts +0 -5
- package/lib/chat/live-chat-message.component.d.ts +0 -23
- package/lib/chat-backend-base.d.ts +0 -72
- package/lib/chat-backend.d.ts +0 -66
- package/lib/chat-source-base.d.ts +0 -51
- package/lib/chat-source.d.ts +0 -85
- package/lib/comments/attachment-button/attachment-button.component.d.ts +0 -17
- package/lib/comments/attachment-scraper.directive.d.ts +0 -21
- package/lib/comments/banta-comments/banta-comments.component.d.ts +0 -216
- package/lib/comments/comment/comment.component.d.ts +0 -90
- package/lib/comments/comment-field/comment-field.component.d.ts +0 -92
- package/lib/comments/comment-sort/comment-sort.component.d.ts +0 -16
- package/lib/comments/comment-view/comment-view.component.d.ts +0 -205
- package/lib/comments/comments.module.d.ts +0 -34
- package/lib/comments/index.d.ts +0 -11
- package/lib/comments/inline-replies.directive.d.ts +0 -5
- package/lib/comments/live-comment.component.d.ts +0 -23
- package/lib/comments/reply-send-options.directive.d.ts +0 -5
- package/lib/common/attachment/attachment.component.d.ts +0 -34
- package/lib/common/attachments/attachments.component.d.ts +0 -26
- package/lib/common/common.module.d.ts +0 -19
- package/lib/common/index.d.ts +0 -10
- package/lib/common/lazy-connection.d.ts +0 -6
- package/lib/common/lightbox/lightbox.component.d.ts +0 -14
- package/lib/common/markdown-to-html.pipe.d.ts +0 -13
- package/lib/common/mention-linker.pipe.d.ts +0 -13
- package/lib/common/timer-pool.service.d.ts +0 -15
- package/lib/common/timestamp.component.d.ts +0 -19
- package/lib/common/trust-resource-url.pipe.d.ts +0 -10
- package/lib/emoji/emoji-selector-button.component.d.ts +0 -30
- package/lib/emoji/emoji-selector-panel/emoji-selector-panel.component.d.ts +0 -23
- package/lib/emoji/emoji.module.d.ts +0 -16
- package/lib/emoji/emojis.d.ts +0 -6507
- package/lib/emoji/index.d.ts +0 -4
- package/lib/giphy-attachments.d.ts +0 -5
- package/lib/index.d.ts +0 -19
- package/lib/live-message.component.d.ts +0 -22
- package/lib/message-menu-item.d.ts +0 -6
- package/lib/sdk-options.d.ts +0 -8
- package/lib/static-chat-source.d.ts +0 -49
- package/lib/tweet-attachments.d.ts +0 -5
- package/lib/url-attachments.d.ts +0 -14
- package/lib/youtube-attachments.d.ts +0 -5
- package/public-api.d.ts +0 -1
|
@@ -1,780 +0,0 @@
|
|
|
1
|
-
import { Component, Input, ViewChild, Output, HostBinding, ViewChildren, TemplateRef, ContentChild } from "@angular/core";
|
|
2
|
-
import { CommentsOrder, FilterMode } from '@banta/common';
|
|
3
|
-
import { Subject, Subscription } from 'rxjs';
|
|
4
|
-
import { CommentComponent } from "../comment/comment.component";
|
|
5
|
-
import { BantaInlineRepliesDirective } from "../inline-replies.directive";
|
|
6
|
-
import * as i0 from "@angular/core";
|
|
7
|
-
import * as i1 from "../../chat-backend-base";
|
|
8
|
-
import * as i2 from "@angular/common";
|
|
9
|
-
import * as i3 from "@angular/material/icon";
|
|
10
|
-
import * as i4 from "@angular/material/button";
|
|
11
|
-
import * as i5 from "@angular/material/progress-spinner";
|
|
12
|
-
import * as i6 from "../comment/comment.component";
|
|
13
|
-
const DEFAULT_MAX_MESSAGES = 2000;
|
|
14
|
-
const DEFAULT_MAX_VISIBLE_MESSAGES = 200;
|
|
15
|
-
export class CommentViewComponent {
|
|
16
|
-
constructor(backend, elementRef) {
|
|
17
|
-
this.backend = backend;
|
|
18
|
-
this.elementRef = elementRef;
|
|
19
|
-
//#endregion
|
|
20
|
-
//#region Fields
|
|
21
|
-
this._sourceSubs = new Subscription();
|
|
22
|
-
this.menuMessage = null;
|
|
23
|
-
this.pinnedMessages = [];
|
|
24
|
-
this.messages = [];
|
|
25
|
-
this.customSortEnabled = false;
|
|
26
|
-
this.sourceLoaded = new Promise(r => this.markSourceLoaded = r);
|
|
27
|
-
this.isViewingMore = false;
|
|
28
|
-
this.isLoadingMore = false;
|
|
29
|
-
this.hasMore = false;
|
|
30
|
-
this.messageClicked = false;
|
|
31
|
-
/**
|
|
32
|
-
* While this is called "new" messages, it really represents the messages that would be visible *at the beginning
|
|
33
|
-
* of the sort order*, which can be flipped by the newestLast feature (used for replies mode).
|
|
34
|
-
*
|
|
35
|
-
* So, when newestLast is false (top-level comments), regardless of the current sortOrder, newMessages are conceptually
|
|
36
|
-
* *above* the visible set of messages.
|
|
37
|
-
*
|
|
38
|
-
* When newestLast is true (as in replies mode), regardless of the current sortOrder, newMessages are conceptually
|
|
39
|
-
* *below* the visible set of messages.
|
|
40
|
-
*/
|
|
41
|
-
this.newMessages = [];
|
|
42
|
-
/**
|
|
43
|
-
* While this is called "older" messages, it really represents the messages that would be visible *at the end of the
|
|
44
|
-
* sort order*, which can be flipped by the newestLast feature (useds for replies mode).
|
|
45
|
-
*
|
|
46
|
-
* So, when newestLast is false, regardless of the current sortOrder, olderMessages are conceptually *below*
|
|
47
|
-
* the visible set of messages.
|
|
48
|
-
*
|
|
49
|
-
* When newestLast is true (as in replies mode), regardless of the current sortOrder, olderMessages are conceptually
|
|
50
|
-
* *above* the visible set of messages.
|
|
51
|
-
*/
|
|
52
|
-
this.olderMessages = [];
|
|
53
|
-
this.collapsePins = false;
|
|
54
|
-
this.newestLast = false;
|
|
55
|
-
this.holdNewMessages = false;
|
|
56
|
-
this.showEmptyState = true;
|
|
57
|
-
this.emptyStateMessage = 'Be the first to comment!';
|
|
58
|
-
this.allowReplies = true;
|
|
59
|
-
this.enableHoldOnClick = false;
|
|
60
|
-
this.enableHoldOnScroll = true;
|
|
61
|
-
this.customMenuItems = [];
|
|
62
|
-
//#endregion
|
|
63
|
-
//#region Outputs
|
|
64
|
-
this._selected = new Subject();
|
|
65
|
-
this._liked = new Subject();
|
|
66
|
-
this._unliked = new Subject();
|
|
67
|
-
this._pinned = new Subject();
|
|
68
|
-
this._unpinned = new Subject();
|
|
69
|
-
this._reported = new Subject();
|
|
70
|
-
this._userSelected = new Subject();
|
|
71
|
-
this._usernameSelected = new Subject();
|
|
72
|
-
this._avatarSelected = new Subject();
|
|
73
|
-
this._shared = new Subject();
|
|
74
|
-
this._deleted = new Subject();
|
|
75
|
-
this._messageEdited = new Subject();
|
|
76
|
-
this._sortOrderChanged = new Subject();
|
|
77
|
-
this._filterModeChanged = new Subject();
|
|
78
|
-
this.userSelected = this._userSelected.asObservable();
|
|
79
|
-
this.reported = this._reported.asObservable();
|
|
80
|
-
this.liked = this._liked.asObservable();
|
|
81
|
-
this.unliked = this._unliked.asObservable();
|
|
82
|
-
this.pinned = this._pinned.asObservable();
|
|
83
|
-
this.unpinned = this._unpinned.asObservable();
|
|
84
|
-
this.usernameSelected = this._usernameSelected.asObservable();
|
|
85
|
-
this.avatarSelected = this._avatarSelected.asObservable();
|
|
86
|
-
this.shared = this._shared.asObservable();
|
|
87
|
-
this.deleted = this._deleted.asObservable();
|
|
88
|
-
this.selected = this._selected.asObservable();
|
|
89
|
-
this.messageEdited = this._messageEdited.asObservable();
|
|
90
|
-
this.sortOrderChanged = this._sortOrderChanged.asObservable();
|
|
91
|
-
this.filterModeChanged = this._filterModeChanged.asObservable();
|
|
92
|
-
this.heldMessages = [];
|
|
93
|
-
}
|
|
94
|
-
get source() { return this._source; }
|
|
95
|
-
set source(value) { this.setSource(value); }
|
|
96
|
-
get previousMessages() { return this.newestLast ? this.olderMessages : this.newMessages; }
|
|
97
|
-
get nextMessages() { return this.newestLast ? this.newMessages : this.olderMessages; }
|
|
98
|
-
set maxMessages(value) { this._maxMessages = value; }
|
|
99
|
-
get maxMessages() { return this._maxMessages ?? DEFAULT_MAX_MESSAGES; }
|
|
100
|
-
set maxVisibleMessages(value) { this._maxVisibleMessages = value; }
|
|
101
|
-
get maxVisibleMessages() { return this._maxVisibleMessages ?? DEFAULT_MAX_VISIBLE_MESSAGES; }
|
|
102
|
-
get comments() { return Array.from(this.commentsQuery); }
|
|
103
|
-
//#endregion
|
|
104
|
-
/**
|
|
105
|
-
* Returns true if this message can be found within one of the message buffers (older, current, newer)
|
|
106
|
-
* @param message
|
|
107
|
-
*/
|
|
108
|
-
isMessageLoadedInContext(message) {
|
|
109
|
-
return this.olderMessages.find(x => x.id === message.id)
|
|
110
|
-
|| this.messages.find(x => x.id === message.id)
|
|
111
|
-
|| this.newMessages.find(x => x.id === message.id);
|
|
112
|
-
}
|
|
113
|
-
async loadMessageInContext(message) {
|
|
114
|
-
await this.sourceLoaded;
|
|
115
|
-
console.log(`Loading message ${message.id} in context...`);
|
|
116
|
-
while (this.hasMore && !this.isMessageLoadedInContext(message)) {
|
|
117
|
-
console.log(`...Need to load more comments to find ${message.id}`);
|
|
118
|
-
await this.showMore();
|
|
119
|
-
}
|
|
120
|
-
if (!this.isMessageLoadedInContext(message)) {
|
|
121
|
-
console.error(`Error while loading message in context: Failed to find message ${message.id}, maybe it was deleted!`);
|
|
122
|
-
return false;
|
|
123
|
-
}
|
|
124
|
-
let items = [].concat(this.olderMessages, this.messages, this.newMessages);
|
|
125
|
-
let index = items.findIndex(x => x.id === message.id);
|
|
126
|
-
if (index < 0) {
|
|
127
|
-
console.error(`Error while loading message in context: Message was not present in message list!`);
|
|
128
|
-
return false;
|
|
129
|
-
}
|
|
130
|
-
let startIndex = Math.max(0, index - this.maxVisibleMessages / 2);
|
|
131
|
-
this.newMessages = items.splice(0, startIndex);
|
|
132
|
-
this.messages = items.splice(0, this.maxVisibleMessages);
|
|
133
|
-
this.olderMessages = items;
|
|
134
|
-
this.isViewingMore = true;
|
|
135
|
-
}
|
|
136
|
-
get shouldShowNewMessageIndicator() {
|
|
137
|
-
return this.isViewingMore
|
|
138
|
-
|| this.customSortEnabled
|
|
139
|
-
|| this.sourceFilterMode !== FilterMode.ALL
|
|
140
|
-
|| this.heldMessages.length > 0;
|
|
141
|
-
}
|
|
142
|
-
get shouldHoldNewMessages() {
|
|
143
|
-
if (this.customSortEnabled)
|
|
144
|
-
return true;
|
|
145
|
-
if (this.holdNewMessages || this.isViewingMore) {
|
|
146
|
-
console.log(`holding due to settings`);
|
|
147
|
-
return true;
|
|
148
|
-
}
|
|
149
|
-
if (this.enableHoldOnClick && this.messageClicked)
|
|
150
|
-
return true;
|
|
151
|
-
if (this.enableHoldOnScroll) {
|
|
152
|
-
let keyMessage;
|
|
153
|
-
if (this.newestLast)
|
|
154
|
-
keyMessage = this.messages[this.messages.length - 1];
|
|
155
|
-
else
|
|
156
|
-
keyMessage = this.messages[0];
|
|
157
|
-
if (keyMessage) {
|
|
158
|
-
const messageElement = this.getElementForComment(keyMessage.id);
|
|
159
|
-
if (messageElement) {
|
|
160
|
-
if (!this.isElementVisible(messageElement)) {
|
|
161
|
-
console.log(`key element is not visible`);
|
|
162
|
-
return true;
|
|
163
|
-
}
|
|
164
|
-
else {
|
|
165
|
-
console.log(`key element is visible`);
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
else {
|
|
169
|
-
console.log(`could not find key element`);
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
else {
|
|
173
|
-
console.log(`could not find key message`);
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
return false;
|
|
177
|
-
}
|
|
178
|
-
isElementVisible(element) {
|
|
179
|
-
const elementRect = element.getBoundingClientRect();
|
|
180
|
-
return !!elementRect
|
|
181
|
-
&& elementRect.bottom >= 0
|
|
182
|
-
&& elementRect.right >= 0
|
|
183
|
-
&& elementRect.left <= document.documentElement.clientWidth
|
|
184
|
-
&& elementRect.top <= document.documentElement.clientHeight;
|
|
185
|
-
}
|
|
186
|
-
/**
|
|
187
|
-
* Get the CommentComponent instantiated for the given ChatMessage,
|
|
188
|
-
* if it exists in the current view. Note that messages which are not
|
|
189
|
-
* currently shown to the user will not return a CommentComponent.
|
|
190
|
-
* @param message
|
|
191
|
-
* @returns
|
|
192
|
-
*/
|
|
193
|
-
getCommentComponentForMessage(message) {
|
|
194
|
-
if (!message)
|
|
195
|
-
throw new Error(`You must pass a valid ChatMessage`);
|
|
196
|
-
return this.comments.find(x => x.message?.id === message.id);
|
|
197
|
-
}
|
|
198
|
-
saveEdit(message, newMessage) {
|
|
199
|
-
this._messageEdited.next({ message, newMessage });
|
|
200
|
-
}
|
|
201
|
-
likeMessage(message) {
|
|
202
|
-
this._liked.next(message);
|
|
203
|
-
}
|
|
204
|
-
unlikeMessage(message) {
|
|
205
|
-
this._unliked.next(message);
|
|
206
|
-
}
|
|
207
|
-
pinMessage(message, options) {
|
|
208
|
-
this._pinned.next({ message, options });
|
|
209
|
-
}
|
|
210
|
-
unpinMessage(message) {
|
|
211
|
-
this._unpinned.next(message);
|
|
212
|
-
}
|
|
213
|
-
reportMessage(message) {
|
|
214
|
-
this._reported.next(message);
|
|
215
|
-
}
|
|
216
|
-
selectMessage(message) {
|
|
217
|
-
this._selected.next(message);
|
|
218
|
-
}
|
|
219
|
-
selectMessageUser(message) {
|
|
220
|
-
this._userSelected.next(message);
|
|
221
|
-
}
|
|
222
|
-
selectUsername(user) {
|
|
223
|
-
this._usernameSelected.next(user);
|
|
224
|
-
}
|
|
225
|
-
selectAvatar(user) {
|
|
226
|
-
this._avatarSelected.next(user);
|
|
227
|
-
}
|
|
228
|
-
sharedMessage(message) {
|
|
229
|
-
this._shared.next(message);
|
|
230
|
-
}
|
|
231
|
-
startEditing(message) {
|
|
232
|
-
this.messages.forEach(m => m.transientState.editing = false);
|
|
233
|
-
message.transientState.editing = true;
|
|
234
|
-
}
|
|
235
|
-
deleteMessage(message) {
|
|
236
|
-
this._deleted.next(message);
|
|
237
|
-
}
|
|
238
|
-
setSource(value) {
|
|
239
|
-
this.customSortEnabled = (value?.sortOrder ?? CommentsOrder.NEWEST) !== CommentsOrder.NEWEST;
|
|
240
|
-
this.newMessages = [];
|
|
241
|
-
this.olderMessages = [];
|
|
242
|
-
this.heldMessages = [];
|
|
243
|
-
window.bantaSourceDebug = value;
|
|
244
|
-
if (this._sourceSubs) {
|
|
245
|
-
this._sourceSubs.unsubscribe();
|
|
246
|
-
this._sourceSubs = null;
|
|
247
|
-
}
|
|
248
|
-
this._source = value;
|
|
249
|
-
if (value) {
|
|
250
|
-
const messages = (value.messages || []).slice();
|
|
251
|
-
this.messages = messages;
|
|
252
|
-
this.olderMessages = messages.splice(this.maxVisibleMessages, messages.length);
|
|
253
|
-
this.hasMore = true; //this.olderMessages.length > 0;
|
|
254
|
-
this._sourceSubs = new Subscription();
|
|
255
|
-
this._sourceSubs.add(this._source.messageReceived.subscribe(msg => this.messageReceived(msg)));
|
|
256
|
-
this._sourceSubs.add(this._source.messageSent.subscribe(msg => this.messageSent(msg)));
|
|
257
|
-
this._sourceSubs.add(this._source.messageUpdated.subscribe(msg => this.messageUpdated(msg)));
|
|
258
|
-
this._sourceSubs.add(this.backend.userChanged.subscribe(user => this.currentUser = user));
|
|
259
|
-
this.getInitialMessages();
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
async getInitialMessages() {
|
|
263
|
-
// Get the pinned messages
|
|
264
|
-
let pinnedMessages = await this._source.getPinnedMessages();
|
|
265
|
-
pinnedMessages.forEach(m => m.transientState ??= {});
|
|
266
|
-
this.pinnedMessages = pinnedMessages;
|
|
267
|
-
let messages = await this._source.getExistingMessages();
|
|
268
|
-
messages.forEach(m => m.transientState ??= {});
|
|
269
|
-
this.messages = this.newestLast ? messages.slice().reverse() : messages;
|
|
270
|
-
if (this.messages.length > this.maxVisibleMessages) {
|
|
271
|
-
if (this.newestLast) {
|
|
272
|
-
this.previousMessages.push(...this.messages.splice(0, this.messages.length - this.maxVisibleMessages));
|
|
273
|
-
}
|
|
274
|
-
else {
|
|
275
|
-
this.nextMessages.unshift(...this.messages.splice(this.maxVisibleMessages, this.messages.length));
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
this.debugMessages();
|
|
279
|
-
this.sortMessages();
|
|
280
|
-
if (this.markSourceLoaded)
|
|
281
|
-
this.markSourceLoaded();
|
|
282
|
-
}
|
|
283
|
-
debugMessages() {
|
|
284
|
-
if (!this.showDebug)
|
|
285
|
-
return;
|
|
286
|
-
// console.log([
|
|
287
|
-
// ...this.previousMessages.map(x => x.message),
|
|
288
|
-
// '[[',
|
|
289
|
-
// ...this.messages.map(x => x.message),
|
|
290
|
-
// ']]',
|
|
291
|
-
// ...this.nextMessages.map(x => x.message)
|
|
292
|
-
// ].map(x => /\d+/.test(x) ? this.zeroPad(x, 2) : x).join(" "));
|
|
293
|
-
}
|
|
294
|
-
zeroPad(number, count = 2) {
|
|
295
|
-
let str;
|
|
296
|
-
if (typeof number === 'number')
|
|
297
|
-
str = String(number);
|
|
298
|
-
else
|
|
299
|
-
str = number;
|
|
300
|
-
while (str.length < count)
|
|
301
|
-
str = '0' + str;
|
|
302
|
-
return str;
|
|
303
|
-
}
|
|
304
|
-
leftPad(str, count = 2) {
|
|
305
|
-
while (str.length < count)
|
|
306
|
-
str = ' ' + str;
|
|
307
|
-
return str;
|
|
308
|
-
}
|
|
309
|
-
messageIdentity(index, chatMessage) {
|
|
310
|
-
return chatMessage.id;
|
|
311
|
-
}
|
|
312
|
-
get sourceSortOrder() {
|
|
313
|
-
return this.source?.sortOrder ?? CommentsOrder.NEWEST;
|
|
314
|
-
}
|
|
315
|
-
get sourceFilterMode() {
|
|
316
|
-
return this.source?.filterMode ?? FilterMode.ALL;
|
|
317
|
-
}
|
|
318
|
-
/**
|
|
319
|
-
* Show the newest content.
|
|
320
|
-
* - If an unnatural sort order is active (ie Oldest or Likes), it will be changed to Newest.
|
|
321
|
-
* - The new content will be placed where new content goes based on newestLast (replies mode), so if it is true, the content is
|
|
322
|
-
* placed at the end, otherwise it is placed at the beginning.
|
|
323
|
-
*
|
|
324
|
-
* @param event
|
|
325
|
-
* @returns
|
|
326
|
-
*/
|
|
327
|
-
async showNewest(event) {
|
|
328
|
-
// Regardless of how we handle this, clear out our held messages
|
|
329
|
-
this.heldMessages = [];
|
|
330
|
-
this.messageClicked = false;
|
|
331
|
-
// If the sort order is not already Newest, switch to Newest and stop.
|
|
332
|
-
// The act of changing the sort order will cause the newest content to be loaded.
|
|
333
|
-
let naturalOrder = CommentsOrder.NEWEST;
|
|
334
|
-
if (this.sourceSortOrder !== naturalOrder || this.sourceFilterMode !== FilterMode.ALL) {
|
|
335
|
-
if (this.sourceSortOrder !== naturalOrder)
|
|
336
|
-
this._sortOrderChanged.next(naturalOrder);
|
|
337
|
-
if (this.sourceFilterMode !== FilterMode.ALL)
|
|
338
|
-
this._filterModeChanged.next(FilterMode.ALL);
|
|
339
|
-
return;
|
|
340
|
-
}
|
|
341
|
-
// On this path, we are already on Newest, but there is newer content available (such as when new content is
|
|
342
|
-
// being buffered due to user engagement on a comment)
|
|
343
|
-
this.isViewingMore = false;
|
|
344
|
-
// Move all newerMessages into messages, respecting the newestLast direction (normal or replies mode)
|
|
345
|
-
if (this.newestLast)
|
|
346
|
-
this.messages = this.messages.concat(this.newMessages.splice(0, this.newMessages.length));
|
|
347
|
-
else
|
|
348
|
-
this.messages = this.newMessages.splice(0, this.newMessages.length).concat(this.messages);
|
|
349
|
-
let overflow = this.messages.splice(this.maxVisibleMessages, this.messages.length);
|
|
350
|
-
this.olderMessages = overflow.concat(this.olderMessages);
|
|
351
|
-
this.olderMessages.splice(this.maxMessages - this.maxVisibleMessages, this.olderMessages.length);
|
|
352
|
-
this.hasMore = this.olderMessages.length > 0;
|
|
353
|
-
// Scroll to the newest comment.
|
|
354
|
-
if (this.messages.length > 0) {
|
|
355
|
-
if (this.newestLast) {
|
|
356
|
-
this.scrollToComment(this.messages[this.messages.length - 1].id);
|
|
357
|
-
}
|
|
358
|
-
else {
|
|
359
|
-
this.scrollToComment(this.messages[0].id);
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
get showDebug() {
|
|
364
|
-
if (typeof window === 'undefined')
|
|
365
|
-
return false;
|
|
366
|
-
return localStorage['banta:debug'] === '1';
|
|
367
|
-
}
|
|
368
|
-
get shouldShowNext() {
|
|
369
|
-
if (!this.newestLast) {
|
|
370
|
-
return this.hasMore || this.nextMessages.length > 0;
|
|
371
|
-
}
|
|
372
|
-
return this.nextMessages.length > 0;
|
|
373
|
-
}
|
|
374
|
-
get shouldShowPrevious() {
|
|
375
|
-
if (this.newestLast) {
|
|
376
|
-
return this.hasMore || this.previousMessages.length > 0;
|
|
377
|
-
}
|
|
378
|
-
return this.previousMessages.length > 0;
|
|
379
|
-
}
|
|
380
|
-
get pageSize() {
|
|
381
|
-
return Math.min(20, this.maxVisibleMessages || 20);
|
|
382
|
-
}
|
|
383
|
-
async showPrevious() {
|
|
384
|
-
this.isViewingMore = true;
|
|
385
|
-
let nextPageSize = this.pageSize;
|
|
386
|
-
this.isLoadingMore = false;
|
|
387
|
-
if (isNaN(nextPageSize))
|
|
388
|
-
throw new Error(`Not safe to load more with NaN page size`);
|
|
389
|
-
if (this.previousMessages.length > 0) {
|
|
390
|
-
const storedMessages = this.previousMessages.splice(Math.max(0, this.previousMessages.length - nextPageSize), nextPageSize);
|
|
391
|
-
this.messages = [...storedMessages, ...this.messages];
|
|
392
|
-
nextPageSize -= storedMessages.length;
|
|
393
|
-
}
|
|
394
|
-
// Load more from backend if needed
|
|
395
|
-
// Note: Backend only supports fetching more content in one direction.
|
|
396
|
-
let lastMessage = this.previousMessages[0] ?? this.messages[0];
|
|
397
|
-
if (nextPageSize > 0 && this.newestLast && lastMessage) {
|
|
398
|
-
this.isLoadingMore = true;
|
|
399
|
-
let messages = await this.source.loadAfter(lastMessage, nextPageSize);
|
|
400
|
-
messages = messages.slice().reverse(); // because newestLast === true
|
|
401
|
-
messages.forEach(m => m.transientState ??= {});
|
|
402
|
-
// In replies mode (newestLast), we want to put these new messages onto the *top* of the set of visible messages.
|
|
403
|
-
// Otherwise we want to put them on the *bottom*.
|
|
404
|
-
this.messages = [...messages, ...this.messages];
|
|
405
|
-
// If we didn't receive any messages at all, there's no more to fetch.
|
|
406
|
-
if (messages.length === 0)
|
|
407
|
-
this.hasMore = false;
|
|
408
|
-
this.isLoadingMore = false;
|
|
409
|
-
}
|
|
410
|
-
// Extract the messages that do not fit in the maxVisibleMessages buffer.
|
|
411
|
-
if (this.messages.length > this.maxVisibleMessages) {
|
|
412
|
-
let overflow = this.messages.splice(this.maxVisibleMessages, this.messages.length);
|
|
413
|
-
this.nextMessages.unshift(...overflow);
|
|
414
|
-
if (this.nextMessages.length > this.maxMessages)
|
|
415
|
-
this.nextMessages.splice(this.maxMessages, this.nextMessages.length);
|
|
416
|
-
}
|
|
417
|
-
this.debugMessages();
|
|
418
|
-
}
|
|
419
|
-
get sortNextLabel() {
|
|
420
|
-
if (this.sourceSortOrder === 'newest') {
|
|
421
|
-
return 'Older';
|
|
422
|
-
}
|
|
423
|
-
else if (this.sourceSortOrder === 'oldest') {
|
|
424
|
-
return 'Newer';
|
|
425
|
-
}
|
|
426
|
-
else if (this.sourceSortOrder === 'likes') {
|
|
427
|
-
return 'Less Likes';
|
|
428
|
-
}
|
|
429
|
-
return 'More';
|
|
430
|
-
}
|
|
431
|
-
get sortPreviousLabel() {
|
|
432
|
-
if (this.sourceSortOrder === 'newest') {
|
|
433
|
-
return 'Newer';
|
|
434
|
-
}
|
|
435
|
-
else if (this.sourceSortOrder === 'oldest') {
|
|
436
|
-
return 'Older';
|
|
437
|
-
}
|
|
438
|
-
else if (this.sourceSortOrder === 'likes') {
|
|
439
|
-
return 'More Likes';
|
|
440
|
-
}
|
|
441
|
-
return 'More';
|
|
442
|
-
}
|
|
443
|
-
get nextLabel() { return this.newestLast ? this.sortPreviousLabel : this.sortNextLabel; }
|
|
444
|
-
get previousLabel() { return this.newestLast ? this.sortNextLabel : this.sortPreviousLabel; }
|
|
445
|
-
/**
|
|
446
|
-
* Show more content
|
|
447
|
-
* - When in replies mode (newestLast), the content is added at the top
|
|
448
|
-
* - When in normal mode, the content is added at the bottom
|
|
449
|
-
* - The current sort order does *not* factor in here, which is why it is showMore() not showEarlier().
|
|
450
|
-
*
|
|
451
|
-
* @returns
|
|
452
|
-
*/
|
|
453
|
-
async showNext() {
|
|
454
|
-
this.isViewingMore = true;
|
|
455
|
-
let nextPageSize = this.pageSize;
|
|
456
|
-
if (isNaN(nextPageSize))
|
|
457
|
-
throw new Error(`Not safe to load more with NaN page size`);
|
|
458
|
-
this.isLoadingMore = false;
|
|
459
|
-
if (this.nextMessages.length > 0) {
|
|
460
|
-
const storedMessages = this.nextMessages.splice(0, nextPageSize);
|
|
461
|
-
this.messages = [...this.messages, ...storedMessages];
|
|
462
|
-
nextPageSize -= storedMessages.length;
|
|
463
|
-
}
|
|
464
|
-
const lastMessage = this.olderMessages[this.olderMessages.length - 1] ?? this.messages[this.messages.length - 1];
|
|
465
|
-
if (nextPageSize > 0 && !this.newestLast && lastMessage) {
|
|
466
|
-
// Load more from backend
|
|
467
|
-
this.isLoadingMore = true;
|
|
468
|
-
let messages = await this.source.loadAfter(lastMessage, nextPageSize);
|
|
469
|
-
messages.forEach(m => m.transientState ??= {});
|
|
470
|
-
this.messages = [...this.messages, ...messages];
|
|
471
|
-
// If we didn't receive any messages at all, there's no more to fetch.
|
|
472
|
-
if (messages.length === 0)
|
|
473
|
-
this.hasMore = false;
|
|
474
|
-
this.isLoadingMore = false;
|
|
475
|
-
}
|
|
476
|
-
// Extract the messages that do not fit in the maxVisibleMessages buffer.
|
|
477
|
-
if (this.messages.length > this.maxVisibleMessages) {
|
|
478
|
-
let overflow = this.messages.splice(0, this.messages.length - this.maxVisibleMessages);
|
|
479
|
-
// Regardless of the order (newestLast), newMessages represents the direction that is being pushed, since it's definition
|
|
480
|
-
// depends on that order. Move overflowing messages into newMessages.
|
|
481
|
-
this.previousMessages.push(...overflow);
|
|
482
|
-
if (this.previousMessages.length > this.maxMessages)
|
|
483
|
-
this.previousMessages.splice(0, this.previousMessages.length - this.maxMessages);
|
|
484
|
-
}
|
|
485
|
-
this.debugMessages();
|
|
486
|
-
}
|
|
487
|
-
/**
|
|
488
|
-
* Show more content
|
|
489
|
-
* - When in replies mode (newestLast), the content is added at the top
|
|
490
|
-
* - When in normal mode, the content is added at the bottom
|
|
491
|
-
* - The current sort order does *not* factor in here, which is why it is showMore() not showEarlier().
|
|
492
|
-
*
|
|
493
|
-
* @returns
|
|
494
|
-
*/
|
|
495
|
-
async showMore() {
|
|
496
|
-
this.isViewingMore = true;
|
|
497
|
-
let nextPageSize = this.pageSize;
|
|
498
|
-
if (isNaN(nextPageSize))
|
|
499
|
-
throw new Error(`Not safe to load more with NaN page size`);
|
|
500
|
-
this.isLoadingMore = false;
|
|
501
|
-
if (this.olderMessages.length > 0) {
|
|
502
|
-
const storedMessages = this.olderMessages.splice(0, nextPageSize);
|
|
503
|
-
this.messages = this.messages.concat(storedMessages);
|
|
504
|
-
nextPageSize -= storedMessages.length;
|
|
505
|
-
this.hasMore = this.olderMessages.length > 0;
|
|
506
|
-
}
|
|
507
|
-
let lastMessage;
|
|
508
|
-
if (this.newestLast) {
|
|
509
|
-
lastMessage = this.olderMessages[0] ?? this.messages[0];
|
|
510
|
-
}
|
|
511
|
-
else {
|
|
512
|
-
lastMessage = this.olderMessages[this.olderMessages.length - 1] ?? this.messages[this.messages.length - 1];
|
|
513
|
-
}
|
|
514
|
-
if (nextPageSize > 0 && lastMessage) {
|
|
515
|
-
// Load more from backend
|
|
516
|
-
this.isLoadingMore = true;
|
|
517
|
-
if (!lastMessage) {
|
|
518
|
-
this.isLoadingMore = false;
|
|
519
|
-
this.hasMore = false;
|
|
520
|
-
return;
|
|
521
|
-
}
|
|
522
|
-
let messages = await this.source.loadAfter(lastMessage, nextPageSize);
|
|
523
|
-
if (this.newestLast)
|
|
524
|
-
messages = messages.slice().reverse();
|
|
525
|
-
messages.forEach(m => m.transientState ??= {});
|
|
526
|
-
// In replies mode (newestLast), we want to put these new messages onto the *top* of the set of visible messages.
|
|
527
|
-
// Otherwise we want to put them on the *bottom*.
|
|
528
|
-
if (this.newestLast) {
|
|
529
|
-
this.messages = messages.concat(this.messages);
|
|
530
|
-
}
|
|
531
|
-
else {
|
|
532
|
-
this.messages = this.messages.concat(messages);
|
|
533
|
-
}
|
|
534
|
-
// If we didn't receive any messages at all, there's no more to fetch.
|
|
535
|
-
if (messages.length === 0) {
|
|
536
|
-
this.hasMore = false;
|
|
537
|
-
}
|
|
538
|
-
this.isLoadingMore = false;
|
|
539
|
-
}
|
|
540
|
-
// Extract the messages that do not fit in the maxVisibleMessages buffer.
|
|
541
|
-
if (this.messages.length > this.maxVisibleMessages) {
|
|
542
|
-
let overflow = [];
|
|
543
|
-
// Move overflowing messages into newMessages.
|
|
544
|
-
// Regardless of the order (newestLast), newMessages represents the direction that is being loaded,
|
|
545
|
-
// since it's definition depends on that order.
|
|
546
|
-
if (this.newestLast) {
|
|
547
|
-
overflow = this.messages.splice(this.maxVisibleMessages, this.messages.length);
|
|
548
|
-
this.newMessages = overflow.concat(this.newMessages);
|
|
549
|
-
this.newMessages.splice(this.maxMessages - this.maxVisibleMessages, this.newMessages.length);
|
|
550
|
-
}
|
|
551
|
-
else {
|
|
552
|
-
overflow = this.messages.splice(0, this.messages.length - this.maxVisibleMessages);
|
|
553
|
-
this.newMessages.push(...overflow);
|
|
554
|
-
if (this.newMessages.length > this.maxMessages - this.maxVisibleMessages)
|
|
555
|
-
this.newMessages.splice(0, this.newMessages.length - (this.maxMessages - this.maxVisibleMessages));
|
|
556
|
-
}
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
addMessage(message) {
|
|
560
|
-
if (!message.transientState)
|
|
561
|
-
message.transientState ??= {};
|
|
562
|
-
let destination = this.messages;
|
|
563
|
-
let bucket = this.olderMessages;
|
|
564
|
-
let newestLast = this.newestLast;
|
|
565
|
-
if (this.shouldHoldNewMessages) {
|
|
566
|
-
this.heldMessages.push(message);
|
|
567
|
-
destination = this.newMessages;
|
|
568
|
-
bucket = null;
|
|
569
|
-
}
|
|
570
|
-
// If we aren't on the newest sort order, new messages shouldn't be added at all
|
|
571
|
-
if (this.sourceSortOrder !== CommentsOrder.NEWEST)
|
|
572
|
-
return;
|
|
573
|
-
if (newestLast) {
|
|
574
|
-
destination.push(message);
|
|
575
|
-
if (this.maxVisibleMessages > 0) {
|
|
576
|
-
let overflow = destination.splice(this.maxVisibleMessages, destination.length);
|
|
577
|
-
bucket?.push(...overflow);
|
|
578
|
-
}
|
|
579
|
-
}
|
|
580
|
-
else {
|
|
581
|
-
destination.unshift(message);
|
|
582
|
-
if (this.maxVisibleMessages > 0) {
|
|
583
|
-
let overflow = destination.splice(this.maxVisibleMessages, destination.length);
|
|
584
|
-
bucket?.unshift(...overflow);
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
if (bucket?.length > 0)
|
|
588
|
-
this.hasMore = true;
|
|
589
|
-
message.pagingCursor = String(this.incrementPagingCursors());
|
|
590
|
-
this.sortMessages();
|
|
591
|
-
}
|
|
592
|
-
incrementPagingCursors() {
|
|
593
|
-
if (this.source.sortOrder !== CommentsOrder.NEWEST)
|
|
594
|
-
return;
|
|
595
|
-
let maxPagingCursor = 0;
|
|
596
|
-
for (let group of [this.messages, this.olderMessages, this.newMessages]) {
|
|
597
|
-
for (let message of group) {
|
|
598
|
-
if (message.pagingCursor) {
|
|
599
|
-
let pagingCursor = Number(message.pagingCursor) + 1;
|
|
600
|
-
if (pagingCursor > maxPagingCursor)
|
|
601
|
-
maxPagingCursor = pagingCursor;
|
|
602
|
-
message.pagingCursor = String(pagingCursor);
|
|
603
|
-
}
|
|
604
|
-
}
|
|
605
|
-
}
|
|
606
|
-
return maxPagingCursor;
|
|
607
|
-
}
|
|
608
|
-
/**
|
|
609
|
-
* Wait for all currently visible comments to be fully loaded, including all attachments.
|
|
610
|
-
* Doing this will prevent layout shift when scrolling to a specific comment.
|
|
611
|
-
*/
|
|
612
|
-
async waitForAllCommentsToLoad() {
|
|
613
|
-
await new Promise(r => setTimeout(r, 100));
|
|
614
|
-
await this.sourceLoaded;
|
|
615
|
-
await Promise.all(this.comments.map(x => x.waitForLoad()));
|
|
616
|
-
}
|
|
617
|
-
sortMessages() {
|
|
618
|
-
if (!this.source)
|
|
619
|
-
return;
|
|
620
|
-
let sorter;
|
|
621
|
-
if (this.source.sortOrder === CommentsOrder.LIKES)
|
|
622
|
-
sorter = (a, b) => b.likes - a.likes;
|
|
623
|
-
else if (this.source.sortOrder === CommentsOrder.NEWEST)
|
|
624
|
-
sorter = (a, b) => (b.sentAt - a.sentAt) * (this.newestLast ? -1 : 1);
|
|
625
|
-
else if (this.source.sortOrder === CommentsOrder.OLDEST)
|
|
626
|
-
sorter = (a, b) => (a.sentAt - b.sentAt) * (this.newestLast ? -1 : 1);
|
|
627
|
-
this.messages.sort(sorter);
|
|
628
|
-
this.olderMessages.sort(sorter);
|
|
629
|
-
this.newMessages.sort(sorter);
|
|
630
|
-
}
|
|
631
|
-
messageReceived(message) {
|
|
632
|
-
this.addMessage(message);
|
|
633
|
-
}
|
|
634
|
-
isScrolledToLatest() {
|
|
635
|
-
if (!this.messageContainer)
|
|
636
|
-
return false;
|
|
637
|
-
const el = this.messageContainer.nativeElement;
|
|
638
|
-
const currentScroll = el.scrollTop;
|
|
639
|
-
const currentTotal = el.scrollHeight - el.offsetHeight;
|
|
640
|
-
return currentScroll > currentTotal - 10;
|
|
641
|
-
}
|
|
642
|
-
messageSent(message) {
|
|
643
|
-
this.addMessage(message);
|
|
644
|
-
if (!this.messageContainer)
|
|
645
|
-
return;
|
|
646
|
-
this.scrollToLatest();
|
|
647
|
-
}
|
|
648
|
-
isPinned(message) {
|
|
649
|
-
return message.pinned && (!message.pinnedUntil || message.pinnedUntil > Date.now());
|
|
650
|
-
}
|
|
651
|
-
messageUpdated(message) {
|
|
652
|
-
let pinned = this.isPinned(message);
|
|
653
|
-
let inPins = this.pinnedMessages.some(x => x.id === message.id);
|
|
654
|
-
if (pinned && !inPins) {
|
|
655
|
-
this.pinnedMessages.unshift(message);
|
|
656
|
-
let index = this.messages.indexOf(message);
|
|
657
|
-
if (index >= 0) {
|
|
658
|
-
this.messages.splice(index, 1);
|
|
659
|
-
}
|
|
660
|
-
}
|
|
661
|
-
else if (!pinned && inPins) {
|
|
662
|
-
this.messages.push(message);
|
|
663
|
-
let index = this.pinnedMessages.indexOf(message);
|
|
664
|
-
if (index >= 0) {
|
|
665
|
-
this.pinnedMessages.splice(index, 1);
|
|
666
|
-
}
|
|
667
|
-
this.sortMessages();
|
|
668
|
-
}
|
|
669
|
-
}
|
|
670
|
-
scrollToLatest() {
|
|
671
|
-
if (!this.messageContainer) {
|
|
672
|
-
return;
|
|
673
|
-
}
|
|
674
|
-
const el = this.messageContainer.nativeElement;
|
|
675
|
-
el.scrollIntoView({ block: 'start' });
|
|
676
|
-
//el.scrollTop = el.scrollHeight;
|
|
677
|
-
}
|
|
678
|
-
get element() {
|
|
679
|
-
return this.elementRef.nativeElement;
|
|
680
|
-
}
|
|
681
|
-
async scrollToComment(commentId) {
|
|
682
|
-
if (typeof window === 'undefined')
|
|
683
|
-
return;
|
|
684
|
-
await this.waitForAllCommentsToLoad();
|
|
685
|
-
const comment = this.getElementForComment(commentId);
|
|
686
|
-
if (comment) {
|
|
687
|
-
comment.scrollIntoView({
|
|
688
|
-
inline: 'center',
|
|
689
|
-
block: 'center'
|
|
690
|
-
});
|
|
691
|
-
}
|
|
692
|
-
}
|
|
693
|
-
getElementForComment(commentId) {
|
|
694
|
-
return this.element.querySelector(`[data-comment-id="${commentId}"]`);
|
|
695
|
-
}
|
|
696
|
-
mentionsMe(message) {
|
|
697
|
-
if (!this.currentUser)
|
|
698
|
-
return false;
|
|
699
|
-
if (message.message.includes(`@${this.currentUser.username}`))
|
|
700
|
-
return true;
|
|
701
|
-
return false;
|
|
702
|
-
}
|
|
703
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: CommentViewComponent, deps: [{ token: i1.ChatBackendBase }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
704
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.9", type: CommentViewComponent, selector: "banta-comment-view", inputs: { source: "source", maxMessages: "maxMessages", maxVisibleMessages: "maxVisibleMessages", collapsePins: "collapsePins", newestLast: "newestLast", holdNewMessages: "holdNewMessages", showEmptyState: "showEmptyState", emptyStateMessage: "emptyStateMessage", allowReplies: "allowReplies", enableHoldOnClick: "enableHoldOnClick", enableHoldOnScroll: "enableHoldOnScroll", customMenuItems: "customMenuItems", fixedHeight: "fixedHeight", selectedMessage: "selectedMessage", genericAvatarUrl: "genericAvatarUrl" }, outputs: { userSelected: "userSelected", reported: "reported", liked: "liked", unliked: "unliked", pinned: "pinned", unpinned: "unpinned", usernameSelected: "usernameSelected", avatarSelected: "avatarSelected", shared: "shared", deleted: "deleted", selected: "selected", messageEdited: "messageEdited", sortOrderChanged: "sortOrderChanged", filterModeChanged: "filterModeChanged" }, host: { properties: { "class.fixed-height": "this.fixedHeight" } }, queries: [{ propertyName: "inlineRepliesTemplate", first: true, predicate: BantaInlineRepliesDirective, descendants: true, read: TemplateRef }], viewQueries: [{ propertyName: "messageContainer", first: true, predicate: ["messageContainer"], descendants: true }, { propertyName: "commentsQuery", predicate: CommentComponent, descendants: true }], ngImport: i0, template: "<div class=\"banta-message-container\" #messageContainer>\r\n <ng-content select=\"[data-before]\"></ng-content>\r\n\r\n @if (!collapsePins) {\r\n @for (message of pinnedMessages; track message.id) {\r\n @if (!message.hidden) {\r\n <banta-comment\r\n class=\"abbreviated\"\r\n [customMenuItems]=\"customMenuItems\"\r\n [message]=\"message\"\r\n [mine]=\"currentUser?.id === message.user?.id\"\r\n [permissions]=\"source?.permissions\"\r\n [showReplyAction]=\"allowReplies\"\r\n [editing]=\"message.transientState.editing\"\r\n [genericAvatarUrl]=\"genericAvatarUrl\"\r\n [readonly]=\"source?.readonly\"\r\n (click)=\"messageClicked = true\"\r\n (editStarted)=\"startEditing(message)\"\r\n (deleted)=\"deleteMessage(message)\"\r\n (editEnded)=\"message.transientState.editing = false\"\r\n (edited)=\"saveEdit(message, $event)\"\r\n (userSelected)=\"selectMessageUser(message)\"\r\n (avatarSelected)=\"selectAvatar($event)\"\r\n (usernameSelected)=\"selectUsername($event)\"\r\n (liked)=\"likeMessage(message)\"\r\n (pinned)=\"pinMessage(message, $event.options)\"\r\n (unpinned)=\"unpinMessage(message)\"\r\n (unliked)=\"unlikeMessage(message)\"\r\n (reported)=\"reportMessage(message)\"\r\n (selected)=\"selectMessage(message)\"\r\n (shared)=\"sharedMessage($event)\"\r\n />\r\n <div class=\"banta-inline-replies-container\" *ngIf=\"selectedMessage === message\">\r\n <ng-container *ngTemplateOutlet=\"inlineRepliesTemplate\" />\r\n </div>\r\n }\r\n }\r\n }\r\n\r\n <div class=\"banta-top-sticky\">\r\n @if (!newestLast) {\r\n <button\r\n mat-button\r\n class=\"banta-nav\"\r\n [class.visible]=\"shouldShowNewMessageIndicator\"\r\n href=\"javascript:;\"\r\n (click)=\"showNewest($event)\"\r\n >\r\n <mat-icon>file_upload</mat-icon>\r\n Newest\r\n @if (heldMessages.length > 0) {\r\n <span class=\"count\">{{ heldMessages.length | number }}</span>\r\n }\r\n </button>\r\n }\r\n </div>\r\n\r\n <button mat-button class=\"pager\" (click)=\"showPrevious()\" [class.visible]=\"shouldShowPrevious\" [disabled]=\"isLoadingMore\">\r\n <mat-icon>expand_less</mat-icon>\r\n {{ previousLabel }}\r\n </button>\r\n\r\n @for (message of messages; track message.id) {\r\n @if (!message.hidden) {\r\n <banta-comment\r\n class=\"abbreviated\"\r\n [customMenuItems]=\"customMenuItems\"\r\n [message]=\"message\"\r\n [mine]=\"currentUser?.id === message.user?.id\"\r\n [permissions]=\"source?.permissions\"\r\n [showReplyAction]=\"allowReplies\"\r\n [editing]=\"message.transientState.editing\"\r\n [genericAvatarUrl]=\"genericAvatarUrl\"\r\n [readonly]=\"source?.readonly\"\r\n (click)=\"messageClicked = true\"\r\n (editStarted)=\"startEditing(message)\"\r\n (deleted)=\"deleteMessage(message)\"\r\n (editEnded)=\"message.transientState.editing = false\"\r\n (edited)=\"saveEdit(message, $event)\"\r\n (userSelected)=\"selectMessageUser(message)\"\r\n (avatarSelected)=\"selectAvatar($event)\"\r\n (usernameSelected)=\"selectUsername($event)\"\r\n (liked)=\"likeMessage(message)\"\r\n (pinned)=\"pinMessage(message, $event.options)\"\r\n (unpinned)=\"unpinMessage(message)\"\r\n (unliked)=\"unlikeMessage(message)\"\r\n (reported)=\"reportMessage(message)\"\r\n (selected)=\"selectMessage(message)\"\r\n (shared)=\"sharedMessage($event)\"\r\n />\r\n <div class=\"banta-inline-replies-container\" *ngIf=\"selectedMessage === message\">\r\n <ng-container *ngTemplateOutlet=\"inlineRepliesTemplate\" />\r\n </div>\r\n }\r\n } @empty {\r\n <div class=\"banta-empty-state\" *ngIf=\"showEmptyState\">\r\n {{ emptyStateMessage }}\r\n </div>\r\n }\r\n\r\n <button mat-button class=\"pager\" (click)=\"showNext()\" [class.visible]=\"shouldShowNext\" [disabled]=\"isLoadingMore\">\r\n <mat-icon>expand_more</mat-icon>\r\n {{ nextLabel }}\r\n </button>\r\n\r\n <div class=\"banta-nav-point banta-bottom-sticky\">\r\n @if (newestLast) {\r\n <button\r\n [matBadge]=\"10\" matBadgeOverlap=\"false\"\r\n matBadgePosition=\"after\" matBadgeSize=\"large\"\r\n mat-button\r\n class=\"banta-nav\"\r\n [class.visible]=\"shouldShowNewMessageIndicator\"\r\n href=\"javascript:;\"\r\n (click)=\"showNewest($event)\"\r\n >\r\n <mat-icon>file_download</mat-icon>\r\n Newest\r\n @if (heldMessages.length > 0) {\r\n <span class=\"count\">{{ heldMessages.length | number }}</span>\r\n }\r\n </button>\r\n }\r\n </div>\r\n\r\n <div class=\"banta-loading-more\" *ngIf=\"isLoadingMore\">\r\n <mat-spinner></mat-spinner>\r\n </div>\r\n\r\n @if (showDebug) {\r\n <div style=\"color: #666\">\r\n ({{ previousMessages.length }} .. {{ messages.length }} .. {{ nextMessages.length }})\r\n\r\n dir={{newestLast ? '-1' : '1'}}\r\n v={{maxVisibleMessages}}, M={{maxMessages}}\r\n </div>\r\n }\r\n\r\n <ng-content select=\":not([data-before]):not(.inline-replies)\"></ng-content>\r\n</div>\r\n", styles: [":host{flex-grow:1;display:flex;flex-direction:column;opacity:1;transition:.2s opacity ease-in}.banta-message-container{flex-grow:1;color:#111;background:#fff;padding:.5em 1em 3em .5em;opacity:1;transition:.5s opacity ease-in-out;position:relative}.banta-message-container.no-scroll{height:auto;overflow-y:visible}.banta-message-container.faded{opacity:.25}.banta-message-container .overlay{position:absolute;inset:0;z-index:10}:host.fixed-height .banta-message-container{overflow-y:auto}:host-context(.mat-dark-theme) .banta-message-container{color:#fff;background:#111}::ng-deep .banta-empty-state{text-align:center;margin:3em;color:#666}:host-context(.mat-dark-theme) .empty-state{color:#666}button.banta-nav{position:absolute;right:.5em;z-index:10;text-align:center;opacity:0;transition:.4s opacity ease-in-out;pointer-events:none;border-radius:2em;background-color:#ddd}:host-context(.mat-dark-theme) button.banta-nav{background-color:#222;color:#fff}button.banta-nav span.count{background-color:#a93535;color:#fff;padding:4px 10px;border-radius:.5em;margin-left:.25em;font-size:90%}button.banta-nav.visible{opacity:1;pointer-events:initial}button.pager{appearance:none;border:none;width:100%;opacity:0;pointer-events:none;transition:.4s opacity ease-in-out}button.pager.visible{opacity:1;pointer-events:initial}.banta-top-sticky{position:sticky;top:.5em;z-index:10}.banta-bottom-sticky{position:sticky;bottom:3em;z-index:10}.banta-loading-more{padding:2em;text-align:center;margin:0 auto;width:fit-content}@media (max-width: 400px){.banta-message-container{padding:0 0 3em}}\n"], dependencies: [{ kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i4.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "component", type: i5.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "component", type: i6.CommentComponent, selector: "banta-comment", inputs: ["message", "customMenuItems", "showReplyAction", "maxLength", "permissions", "mine", "editing", "genericAvatarUrl", "readonly"], outputs: ["liked", "unliked", "selected", "edited", "deleted", "editStarted", "editEnded", "shared", "userSelected", "usernameSelected", "avatarSelected", "reported", "loaded", "pinned", "unpinned"] }, { kind: "pipe", type: i2.DecimalPipe, name: "number" }] }); }
|
|
705
|
-
}
|
|
706
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: CommentViewComponent, decorators: [{
|
|
707
|
-
type: Component,
|
|
708
|
-
args: [{ selector: 'banta-comment-view', template: "<div class=\"banta-message-container\" #messageContainer>\r\n <ng-content select=\"[data-before]\"></ng-content>\r\n\r\n @if (!collapsePins) {\r\n @for (message of pinnedMessages; track message.id) {\r\n @if (!message.hidden) {\r\n <banta-comment\r\n class=\"abbreviated\"\r\n [customMenuItems]=\"customMenuItems\"\r\n [message]=\"message\"\r\n [mine]=\"currentUser?.id === message.user?.id\"\r\n [permissions]=\"source?.permissions\"\r\n [showReplyAction]=\"allowReplies\"\r\n [editing]=\"message.transientState.editing\"\r\n [genericAvatarUrl]=\"genericAvatarUrl\"\r\n [readonly]=\"source?.readonly\"\r\n (click)=\"messageClicked = true\"\r\n (editStarted)=\"startEditing(message)\"\r\n (deleted)=\"deleteMessage(message)\"\r\n (editEnded)=\"message.transientState.editing = false\"\r\n (edited)=\"saveEdit(message, $event)\"\r\n (userSelected)=\"selectMessageUser(message)\"\r\n (avatarSelected)=\"selectAvatar($event)\"\r\n (usernameSelected)=\"selectUsername($event)\"\r\n (liked)=\"likeMessage(message)\"\r\n (pinned)=\"pinMessage(message, $event.options)\"\r\n (unpinned)=\"unpinMessage(message)\"\r\n (unliked)=\"unlikeMessage(message)\"\r\n (reported)=\"reportMessage(message)\"\r\n (selected)=\"selectMessage(message)\"\r\n (shared)=\"sharedMessage($event)\"\r\n />\r\n <div class=\"banta-inline-replies-container\" *ngIf=\"selectedMessage === message\">\r\n <ng-container *ngTemplateOutlet=\"inlineRepliesTemplate\" />\r\n </div>\r\n }\r\n }\r\n }\r\n\r\n <div class=\"banta-top-sticky\">\r\n @if (!newestLast) {\r\n <button\r\n mat-button\r\n class=\"banta-nav\"\r\n [class.visible]=\"shouldShowNewMessageIndicator\"\r\n href=\"javascript:;\"\r\n (click)=\"showNewest($event)\"\r\n >\r\n <mat-icon>file_upload</mat-icon>\r\n Newest\r\n @if (heldMessages.length > 0) {\r\n <span class=\"count\">{{ heldMessages.length | number }}</span>\r\n }\r\n </button>\r\n }\r\n </div>\r\n\r\n <button mat-button class=\"pager\" (click)=\"showPrevious()\" [class.visible]=\"shouldShowPrevious\" [disabled]=\"isLoadingMore\">\r\n <mat-icon>expand_less</mat-icon>\r\n {{ previousLabel }}\r\n </button>\r\n\r\n @for (message of messages; track message.id) {\r\n @if (!message.hidden) {\r\n <banta-comment\r\n class=\"abbreviated\"\r\n [customMenuItems]=\"customMenuItems\"\r\n [message]=\"message\"\r\n [mine]=\"currentUser?.id === message.user?.id\"\r\n [permissions]=\"source?.permissions\"\r\n [showReplyAction]=\"allowReplies\"\r\n [editing]=\"message.transientState.editing\"\r\n [genericAvatarUrl]=\"genericAvatarUrl\"\r\n [readonly]=\"source?.readonly\"\r\n (click)=\"messageClicked = true\"\r\n (editStarted)=\"startEditing(message)\"\r\n (deleted)=\"deleteMessage(message)\"\r\n (editEnded)=\"message.transientState.editing = false\"\r\n (edited)=\"saveEdit(message, $event)\"\r\n (userSelected)=\"selectMessageUser(message)\"\r\n (avatarSelected)=\"selectAvatar($event)\"\r\n (usernameSelected)=\"selectUsername($event)\"\r\n (liked)=\"likeMessage(message)\"\r\n (pinned)=\"pinMessage(message, $event.options)\"\r\n (unpinned)=\"unpinMessage(message)\"\r\n (unliked)=\"unlikeMessage(message)\"\r\n (reported)=\"reportMessage(message)\"\r\n (selected)=\"selectMessage(message)\"\r\n (shared)=\"sharedMessage($event)\"\r\n />\r\n <div class=\"banta-inline-replies-container\" *ngIf=\"selectedMessage === message\">\r\n <ng-container *ngTemplateOutlet=\"inlineRepliesTemplate\" />\r\n </div>\r\n }\r\n } @empty {\r\n <div class=\"banta-empty-state\" *ngIf=\"showEmptyState\">\r\n {{ emptyStateMessage }}\r\n </div>\r\n }\r\n\r\n <button mat-button class=\"pager\" (click)=\"showNext()\" [class.visible]=\"shouldShowNext\" [disabled]=\"isLoadingMore\">\r\n <mat-icon>expand_more</mat-icon>\r\n {{ nextLabel }}\r\n </button>\r\n\r\n <div class=\"banta-nav-point banta-bottom-sticky\">\r\n @if (newestLast) {\r\n <button\r\n [matBadge]=\"10\" matBadgeOverlap=\"false\"\r\n matBadgePosition=\"after\" matBadgeSize=\"large\"\r\n mat-button\r\n class=\"banta-nav\"\r\n [class.visible]=\"shouldShowNewMessageIndicator\"\r\n href=\"javascript:;\"\r\n (click)=\"showNewest($event)\"\r\n >\r\n <mat-icon>file_download</mat-icon>\r\n Newest\r\n @if (heldMessages.length > 0) {\r\n <span class=\"count\">{{ heldMessages.length | number }}</span>\r\n }\r\n </button>\r\n }\r\n </div>\r\n\r\n <div class=\"banta-loading-more\" *ngIf=\"isLoadingMore\">\r\n <mat-spinner></mat-spinner>\r\n </div>\r\n\r\n @if (showDebug) {\r\n <div style=\"color: #666\">\r\n ({{ previousMessages.length }} .. {{ messages.length }} .. {{ nextMessages.length }})\r\n\r\n dir={{newestLast ? '-1' : '1'}}\r\n v={{maxVisibleMessages}}, M={{maxMessages}}\r\n </div>\r\n }\r\n\r\n <ng-content select=\":not([data-before]):not(.inline-replies)\"></ng-content>\r\n</div>\r\n", styles: [":host{flex-grow:1;display:flex;flex-direction:column;opacity:1;transition:.2s opacity ease-in}.banta-message-container{flex-grow:1;color:#111;background:#fff;padding:.5em 1em 3em .5em;opacity:1;transition:.5s opacity ease-in-out;position:relative}.banta-message-container.no-scroll{height:auto;overflow-y:visible}.banta-message-container.faded{opacity:.25}.banta-message-container .overlay{position:absolute;inset:0;z-index:10}:host.fixed-height .banta-message-container{overflow-y:auto}:host-context(.mat-dark-theme) .banta-message-container{color:#fff;background:#111}::ng-deep .banta-empty-state{text-align:center;margin:3em;color:#666}:host-context(.mat-dark-theme) .empty-state{color:#666}button.banta-nav{position:absolute;right:.5em;z-index:10;text-align:center;opacity:0;transition:.4s opacity ease-in-out;pointer-events:none;border-radius:2em;background-color:#ddd}:host-context(.mat-dark-theme) button.banta-nav{background-color:#222;color:#fff}button.banta-nav span.count{background-color:#a93535;color:#fff;padding:4px 10px;border-radius:.5em;margin-left:.25em;font-size:90%}button.banta-nav.visible{opacity:1;pointer-events:initial}button.pager{appearance:none;border:none;width:100%;opacity:0;pointer-events:none;transition:.4s opacity ease-in-out}button.pager.visible{opacity:1;pointer-events:initial}.banta-top-sticky{position:sticky;top:.5em;z-index:10}.banta-bottom-sticky{position:sticky;bottom:3em;z-index:10}.banta-loading-more{padding:2em;text-align:center;margin:0 auto;width:fit-content}@media (max-width: 400px){.banta-message-container{padding:0 0 3em}}\n"] }]
|
|
709
|
-
}], ctorParameters: () => [{ type: i1.ChatBackendBase }, { type: i0.ElementRef }], propDecorators: { source: [{
|
|
710
|
-
type: Input
|
|
711
|
-
}], maxMessages: [{
|
|
712
|
-
type: Input
|
|
713
|
-
}], maxVisibleMessages: [{
|
|
714
|
-
type: Input
|
|
715
|
-
}], collapsePins: [{
|
|
716
|
-
type: Input
|
|
717
|
-
}], newestLast: [{
|
|
718
|
-
type: Input
|
|
719
|
-
}], holdNewMessages: [{
|
|
720
|
-
type: Input
|
|
721
|
-
}], showEmptyState: [{
|
|
722
|
-
type: Input
|
|
723
|
-
}], emptyStateMessage: [{
|
|
724
|
-
type: Input
|
|
725
|
-
}], allowReplies: [{
|
|
726
|
-
type: Input
|
|
727
|
-
}], enableHoldOnClick: [{
|
|
728
|
-
type: Input
|
|
729
|
-
}], enableHoldOnScroll: [{
|
|
730
|
-
type: Input
|
|
731
|
-
}], customMenuItems: [{
|
|
732
|
-
type: Input
|
|
733
|
-
}], fixedHeight: [{
|
|
734
|
-
type: Input
|
|
735
|
-
}, {
|
|
736
|
-
type: HostBinding,
|
|
737
|
-
args: ['class.fixed-height']
|
|
738
|
-
}], selectedMessage: [{
|
|
739
|
-
type: Input
|
|
740
|
-
}], genericAvatarUrl: [{
|
|
741
|
-
type: Input
|
|
742
|
-
}], inlineRepliesTemplate: [{
|
|
743
|
-
type: ContentChild,
|
|
744
|
-
args: [BantaInlineRepliesDirective, { read: TemplateRef }]
|
|
745
|
-
}], userSelected: [{
|
|
746
|
-
type: Output
|
|
747
|
-
}], reported: [{
|
|
748
|
-
type: Output
|
|
749
|
-
}], liked: [{
|
|
750
|
-
type: Output
|
|
751
|
-
}], unliked: [{
|
|
752
|
-
type: Output
|
|
753
|
-
}], pinned: [{
|
|
754
|
-
type: Output
|
|
755
|
-
}], unpinned: [{
|
|
756
|
-
type: Output
|
|
757
|
-
}], usernameSelected: [{
|
|
758
|
-
type: Output
|
|
759
|
-
}], avatarSelected: [{
|
|
760
|
-
type: Output
|
|
761
|
-
}], shared: [{
|
|
762
|
-
type: Output
|
|
763
|
-
}], deleted: [{
|
|
764
|
-
type: Output
|
|
765
|
-
}], selected: [{
|
|
766
|
-
type: Output
|
|
767
|
-
}], messageEdited: [{
|
|
768
|
-
type: Output
|
|
769
|
-
}], sortOrderChanged: [{
|
|
770
|
-
type: Output
|
|
771
|
-
}], filterModeChanged: [{
|
|
772
|
-
type: Output
|
|
773
|
-
}], commentsQuery: [{
|
|
774
|
-
type: ViewChildren,
|
|
775
|
-
args: [CommentComponent]
|
|
776
|
-
}], messageContainer: [{
|
|
777
|
-
type: ViewChild,
|
|
778
|
-
args: ['messageContainer']
|
|
779
|
-
}] } });
|
|
780
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29tbWVudC12aWV3LmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL3Nkay9zcmMvbGliL2NvbW1lbnRzL2NvbW1lbnQtdmlldy9jb21tZW50LXZpZXcuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvc2RrL3NyYy9saWIvY29tbWVudHMvY29tbWVudC12aWV3L2NvbW1lbnQtdmlldy5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFFLEtBQUssRUFBRSxTQUFTLEVBQWMsTUFBTSxFQUFFLFdBQVcsRUFBRSxZQUFZLEVBQWEsV0FBVyxFQUFFLFlBQVksRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUNqSixPQUFPLEVBQXFCLGFBQWEsRUFBRSxVQUFVLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDN0UsT0FBTyxFQUFFLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFJN0MsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFFaEUsT0FBTyxFQUFFLDJCQUEyQixFQUFFLE1BQU0sNkJBQTZCLENBQUM7Ozs7Ozs7O0FBTzFFLE1BQU0sb0JBQW9CLEdBQUcsSUFBSSxDQUFDO0FBQ2xDLE1BQU0sNEJBQTRCLEdBQUcsR0FBRyxDQUFDO0FBT3pDLE1BQU0sT0FBTyxvQkFBb0I7SUFDN0IsWUFDWSxPQUF3QixFQUN4QixVQUFtQztRQURuQyxZQUFPLEdBQVAsT0FBTyxDQUFpQjtRQUN4QixlQUFVLEdBQVYsVUFBVSxDQUF5QjtRQVUvQyxZQUFZO1FBQ1osZ0JBQWdCO1FBRVIsZ0JBQVcsR0FBRyxJQUFJLFlBQVksRUFBRSxDQUFDO1FBQ3pDLGdCQUFXLEdBQWdCLElBQUksQ0FBQztRQUNoQyxtQkFBYyxHQUFrQixFQUFFLENBQUM7UUFDbkMsYUFBUSxHQUFrQixFQUFFLENB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IHsgQ29tcG9uZW50LCBJbnB1dCwgVmlld0NoaWxkLCBFbGVtZW50UmVmLCBPdXRwdXQsIEhvc3RCaW5kaW5nLCBWaWV3Q2hpbGRyZW4sIFF1ZXJ5TGlzdCwgVGVtcGxhdGVSZWYsIENvbnRlbnRDaGlsZCB9IGZyb20gXCJAYW5ndWxhci9jb3JlXCI7XHJcbmltcG9ydCB7IFVzZXIsIENoYXRNZXNzYWdlLCBDb21tZW50c09yZGVyLCBGaWx0ZXJNb2RlIH0gZnJvbSAnQGJhbnRhL2NvbW1vbic7XHJcbmltcG9ydCB7IFN1YmplY3QsIFN1YnNjcmlwdGlvbiB9IGZyb20gJ3J4anMnO1xyXG5pbXBvcnQgeyBDaGF0QmFja2VuZEJhc2UgfSBmcm9tIFwiLi4vLi4vY2hhdC1iYWNrZW5kLWJhc2VcIjtcclxuaW1wb3J0IHsgQ2hhdFNvdXJjZUJhc2UgfSBmcm9tIFwiLi4vLi4vY2hhdC1zb3VyY2UtYmFzZVwiO1xyXG5pbXBvcnQgeyBNZXNzYWdlTWVudUl0ZW0gfSBmcm9tIFwiLi4vLi4vbWVzc2FnZS1tZW51LWl0ZW1cIjtcclxuaW1wb3J0IHsgQ29tbWVudENvbXBvbmVudCB9IGZyb20gXCIuLi9jb21tZW50L2NvbW1lbnQuY29tcG9uZW50XCI7XHJcbmltcG9ydCB7IFBpbk9wdGlvbnMgfSBmcm9tIFwiLi4vLi4vY2hhdC1zb3VyY2VcIjtcclxuaW1wb3J0IHsgQmFudGFJbmxpbmVSZXBsaWVzRGlyZWN0aXZlIH0gZnJvbSBcIi4uL2lubGluZS1yZXBsaWVzLmRpcmVjdGl2ZVwiO1xyXG5cclxuZXhwb3J0IGludGVyZmFjZSBFZGl0RXZlbnQge1xyXG4gICAgbWVzc2FnZTogQ2hhdE1lc3NhZ2U7XHJcbiAgICBuZXdNZXNzYWdlOiBzdHJpbmc7XHJcbn1cclxuXHJcbmNvbnN0IERFRkFVTFRfTUFYX01FU1NBR0VTID0gMjAwMDtcclxuY29uc3QgREVGQVVMVF9NQVhfVklTSUJMRV9NRVNTQUdFUyA9IDIwMDtcclxuXHJcbkBDb21wb25lbnQoe1xyXG4gICAgc2VsZWN0b3I6ICdiYW50YS1jb21tZW50LXZpZXcnLFxyXG4gICAgdGVtcGxhdGVVcmw6ICcuL2NvbW1lbnQtdmlldy5jb21wb25lbnQuaHRtbCcsXHJcbiAgICBzdHlsZVVybHM6IFsnLi9jb21tZW50LXZpZXcuY29tcG9uZW50LnNjc3MnXVxyXG59KVxyXG5leHBvcnQgY2xhc3MgQ29tbWVudFZpZXdDb21wb25lbnQge1xyXG4gICAgY29uc3RydWN0b3IoXHJcbiAgICAgICAgcHJpdmF0ZSBiYWNrZW5kOiBDaGF0QmFja2VuZEJhc2UsXHJcbiAgICAgICAgcHJpdmF0ZSBlbGVtZW50UmVmOiBFbGVtZW50UmVmPEhUTUxFbGVtZW50PlxyXG4gICAgKSB7XHJcbiAgICB9XHJcblxyXG4gICAgLy8jcmVnaW9uIFNvdXJjZVxyXG5cclxuICAgIHByaXZhdGUgX3NvdXJjZTogQ2hhdFNvdXJjZUJhc2U7XHJcbiAgICBASW5wdXQoKSBnZXQgc291cmNlKCkgeyByZXR1cm4gdGhpcy5fc291cmNlOyB9XHJcbiAgICBzZXQgc291cmNlKHZhbHVlKSB7IHRoaXMuc2V0U291cmNlKHZhbHVlKTsgfVxyXG5cclxuICAgIC8vI2VuZHJlZ2lvblxyXG4gICAgLy8jcmVnaW9uIEZpZWxkc1xyXG5cclxuICAgIHByaXZhdGUgX3NvdXJjZVN1YnMgPSBuZXcgU3Vic2NyaXB0aW9uKCk7XHJcbiAgICBtZW51TWVzc2FnZTogQ2hhdE1lc3NhZ2UgPSBudWxsO1xyXG4gICAgcGlubmVkTWVzc2FnZXM6IENoYXRNZXNzYWdlW10gPSBbXTtcclxuICAgIG1lc3NhZ2VzOiBDaGF0TWVzc2FnZVtdID0gW107XHJcbiAgICBjdXJyZW50VXNlcjogVXNlcjtcclxuICAgIGN1c3RvbVNvcnRFbmFibGVkID0gZmFsc2U7XHJcbiAgICBtYXJrU291cmNlTG9hZGVkOiAoKSA9PiB2b2lkO1xyXG4gICAgc291cmNlTG9hZGVkID0gbmV3IFByb21pc2U8dm9pZD4ociA9PiB0aGlzLm1hcmtTb3VyY2VMb2FkZWQgPSByKTtcclxuICAgIGlzVmlld2luZ01vcmUgPSBmYWxzZTtcclxuICAgIGlzTG9hZGluZ01vcmUgPSBmYWxzZTtcclxuICAgIGhhc01vcmUgPSBmYWxzZTtcclxuICAgIG1lc3NhZ2VDbGlja2VkID0gZmFsc2U7XHJcblxyXG4gICAgZ2V0IHByZXZpb3VzTWVzc2FnZXMoKSB7IHJldHVybiB0aGlzLm5ld2VzdExhc3QgPyB0aGlzLm9sZGVyTWVzc2FnZXMgOiB0aGlzLm5ld01lc3NhZ2VzOyB9XHJcbiAgICBnZXQgbmV4dE1lc3NhZ2VzKCkgeyByZXR1cm4gdGhpcy5uZXdlc3RMYXN0ID8gdGhpcy5uZXdNZXNzYWdlcyA6IHRoaXMub2xkZXJNZXNzYWdlczsgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogV2hpbGUgdGhpcyBpcyBjYWxsZWQgXCJuZXdcIiBtZXNzYWdlcywgaXQgcmVhbGx5IHJlcHJlc2VudHMgdGhlIG1lc3NhZ2VzIHRoYXQgd291bGQgYmUgdmlzaWJsZSAqYXQgdGhlIGJlZ2lubmluZ1xyXG4gICAgICogb2YgdGhlIHNvcnQgb3JkZXIqLCB3aGljaCBjYW4gYmUgZmxpcHBlZCBieSB0aGUgbmV3ZXN0TGFzdCBmZWF0dXJlICh1c2VkIGZvciByZXBsaWVzIG1vZGUpLlxyXG4gICAgICpcclxuICAgICAqIFNvLCB3aGVuIG5ld2VzdExhc3QgaXMgZmFsc2UgKHRvcC1sZXZlbCBjb21tZW50cyksIHJlZ2FyZGxlc3Mgb2YgdGhlIGN1cnJlbnQgc29ydE9yZGVyLCBuZXdNZXNzYWdlcyBhcmUgY29uY2VwdHVhbGx5XHJcbiAgICAgKiAqYWJvdmUqIHRoZSB2aXNpYmxlIHNldCBvZiBtZXNzYWdlcy5cclxuICAgICAqXHJcbiAgICAgKiBXaGVuIG5ld2VzdExhc3QgaXMgdHJ1ZSAoYXMgaW4gcmVwbGllcyBtb2RlKSwgcmVnYXJkbGVzcyBvZiB0aGUgY3VycmVudCBzb3J0T3JkZXIsIG5ld01lc3NhZ2VzIGFyZSBjb25jZXB0dWFsbHlcclxuICAgICAqICpiZWxvdyogdGhlIHZpc2libGUgc2V0IG9mIG1lc3NhZ2VzLlxyXG4gICAgICovXHJcbiAgICBuZXdNZXNzYWdlczogQ2hhdE1lc3NhZ2VbXSA9IFtdO1xyXG5cclxuICAgIC8qKlxyXG4gICAgICogV2hpbGUgdGhpcyBpcyBjYWxsZWQgXCJvbGRlclwiIG1lc3NhZ2VzLCBpdCByZWFsbHkgcmVwcmVzZW50cyB0aGUgbWVzc2FnZXMgdGhhdCB3b3VsZCBiZSB2aXNpYmxlICphdCB0aGUgZW5kIG9mIHRoZVxyXG4gICAgICogc29ydCBvcmRlciosIHdoaWNoIGNhbiBiZSBmbGlwcGVkIGJ5IHRoZSBuZXdlc3RMYXN0IGZlYXR1cmUgKHVzZWRzIGZvciByZXBsaWVzIG1vZGUpLlxyXG4gICAgICpcclxuICAgICAqIFNvLCB3aGVuIG5ld2VzdExhc3QgaXMgZmFsc2UsIHJlZ2FyZGxlc3Mgb2YgdGhlIGN1cnJlbnQgc29ydE9yZGVyLCBvbGRlck1lc3NhZ2VzIGFyZSBjb25jZXB0dWFsbHkgKmJlbG93KlxyXG4gICAgICogdGhlIHZpc2libGUgc2V0IG9mIG1lc3NhZ2VzLlxyXG4gICAgICpcclxuICAgICAqIFdoZW4gbmV3ZXN0TGFzdCBpcyB0cnVlIChhcyBpbiByZXBsaWVzIG1vZGUpLCByZWdhcmRsZXNzIG9mIHRoZSBjdXJyZW50IHNvcnRPcmRlciwgb2xkZXJNZXNzYWdlcyBhcmUgY29uY2VwdHVhbGx5XHJcbiAgICAgKiAqYWJvdmUqIHRoZSB2aXNpYmxlIHNldCBvZiBtZXNzYWdlcy5cclxuICAgICAqL1xyXG4gICAgb2xkZXJNZXNzYWdlczogQ2hhdE1lc3NhZ2VbXSA9IFtdO1xyXG5cclxuICAgIC8vI2VuZHJlZ2lvblxyXG4gICAgLy8jcmVnaW9uIElucHV0c1xyXG5cclxuICAgIHByaXZhdGUgX21heE1lc3NhZ2VzOiBudW1iZXI7XHJcbiAgICBASW5wdXQoKVxyXG4gICAgc2V0IG1heE1lc3NhZ2VzKHZhbHVlKSB7IHRoaXMuX21heE1lc3NhZ2VzID0gdmFsdWU7IH1cclxuICAgIGdldCBtYXhNZXNzYWdlcygpIHsgcmV0dXJuIHRoaXMuX21heE1lc3NhZ2VzID8/IERFRkFVTFRfTUFYX01FU1NBR0VTOyB9XHJcblxyXG4gICAgcHJpdmF0ZSBfbWF4VmlzaWJsZU1lc3NhZ2VzOiBudW1iZXI7XHJcbiAgICBASW5wdXQoKVxyXG4gICAgc2V0IG1heFZpc2libGVNZXNzYWdlcyh2YWx1ZSkgeyB0aGlzLl9tYXhWaXNpYmxlTWVzc2FnZXMgPSB2YWx1ZTsgfVxyXG4gICAgZ2V0IG1heFZpc2libGVNZXNzYWdlcygpIHsgcmV0dXJuIHRoaXMuX21heFZpc2libGVNZXNzYWdlcyA/PyBERUZBVUxUX01BWF9WSVNJQkxFX01FU1NBR0VTOyB9XHJcblxyXG4gICAgQElucHV0KCkgY29sbGFwc2VQaW5zID0gZmFsc2U7XHJcbiAgICBASW5wdXQoKSBuZXdlc3RMYXN0ID0gZmFsc2U7XHJcbiAgICBASW5wdXQoKSBob2xkTmV3TWVzc2FnZXMgPSBmYWxzZTtcclxuICAgIEBJbnB1dCgpIHNob3dFbXB0eVN0YXRlID0gdHJ1ZTtcclxuICAgIEBJbnB1dCgpIGVtcHR5U3RhdGVNZXNzYWdlID0gJ0JlIHRoZSBmaXJzdCB0byBjb21tZW50ISc7XHJcbiAgICBASW5wdXQoKSBhbGxvd1JlcGxpZXMgPSB0cnVlO1xyXG4gICAgQElucHV0KCkgZW5hYmxlSG9sZE9uQ2xpY2sgPSBmYWxzZTtcclxuICAgIEBJbnB1dCgpIGVuYWJsZUhvbGRPblNjcm9sbCA9IHRydWU7XHJcbiAgICBASW5wdXQoKSBjdXN0b21NZW51SXRlbXM6IE1lc3NhZ2VNZW51SXRlbVtdID0gW107XHJcbiAgICBASW5wdXQoKSBASG9zdEJpbmRpbmcoJ2NsYXNzLmZpeGVkLWhlaWdodCcpIGZpeGVkSGVpZ2h0OiBib29sZWFuO1xyXG4gICAgQElucHV0KCkgc2VsZWN0ZWRNZXNzYWdlOiBDaGF0TWVzc2FnZTtcclxuICAgIEBJbnB1dCgpIGdlbmVyaWNBdmF0YXJVcmw6IHN0cmluZztcclxuXHJcbiAgICBAQ29udGVudENoaWxkKEJhbnRhSW5saW5lUmVwbGllc0RpcmVjdGl2ZSwgeyByZWFkOiBUZW1wbGF0ZVJlZiB9KVxyXG4gICAgaW5saW5lUmVwbGllc1RlbXBsYXRlOiBUZW1wbGF0ZVJlZjxhbnk+O1xyXG5cclxuICAgIC8vI2VuZHJlZ2lvblxyXG4gICAgLy8jcmVnaW9uIE91dHB1dHNcclxuXHJcbiAgICBwcml2YXRlIF9zZWxlY3RlZCA9IG5ldyBTdWJqZWN0PENoYXRNZXNzYWdlPigpO1xyXG4gICAgcHJpdmF0ZSBfbGlrZWQgPSBuZXcgU3ViamVjdDxDaGF0TWVzc2FnZT4oKTtcclxuICAgIHByaXZhdGUgX3VubGlrZWQgPSBuZXcgU3ViamVjdDxDaGF0TWVzc2FnZT4oKTtcclxuICAgIHByaXZhdGUgX3Bpbm5lZCA9IG5ldyBTdWJqZWN0PHsgbWVzc2FnZTogQ2hhdE1lc3NhZ2UsIG9wdGlvbnM6IFBpbk9wdGlvbnMgfT4oKTtcclxuICAgIHByaXZhdGUgX3VucGlubmVkID0gbmV3IFN1YmplY3Q8Q2hhdE1lc3NhZ2U+KCk7XHJcbiAgICBwcml2YXRlIF9yZXBvcnRlZCA9IG5ldyBTdWJqZWN0PENoYXRNZXNzYWdlPigpO1xyXG4gICAgcHJpdmF0ZSBfdXNlclNlbGVjdGVkID0gbmV3IFN1YmplY3Q8Q2hhdE1lc3NhZ2U+KCk7XHJcbiAgICBwcml2YXRlIF91c2VybmFtZVNlbGVjdGVkID0gbmV3IFN1YmplY3Q8VXNlcj4oKTtcclxuICAgIHByaXZhdGUgX2F2YXRhclNlbGVjdGVkID0gbmV3IFN1YmplY3Q8VXNlcj4oKTtcclxuICAgIHByaXZhdGUgX3NoYXJlZCA9IG5ldyBTdWJqZWN0PENoYXRNZXNzYWdlPigpO1xyXG4gICAgcHJpdmF0ZSBfZGVsZXRlZCA9IG5ldyBTdWJqZWN0PENoYXRNZXNzYWdlPigpO1xyXG4gICAgcHJpdmF0ZSBfbWVzc2FnZUVkaXRlZCA9IG5ldyBTdWJqZWN0PEVkaXRFdmVudD4oKTtcclxuICAgIHByaXZhdGUgX3NvcnRPcmRlckNoYW5nZWQgPSBuZXcgU3ViamVjdDxDb21tZW50c09yZGVyPigpO1xyXG4gICAgcHJpdmF0ZSBfZmlsdGVyTW9kZUNoYW5nZWQgPSBuZXcgU3ViamVjdDxGaWx0ZXJNb2RlPigpO1xyXG5cclxuICAgIEBPdXRwdXQoKSByZWFkb25seSB1c2VyU2VsZWN0ZWQgPSB0aGlzLl91c2VyU2VsZWN0ZWQuYXNPYnNlcnZhYmxlKCk7XHJcbiAgICBAT3V0cHV0KCkgcmVhZG9ubHkgcmVwb3J0ZWQgPSB0aGlzLl9yZXBvcnRlZC5hc09ic2VydmFibGUoKTtcclxuICAgIEBPdXRwdXQoKSByZWFkb25seSBsaWtlZCA9IHRoaXMuX2xpa2VkLmFzT2JzZXJ2YWJsZSgpO1xyXG4gICAgQE91dHB1dCgpIHJlYWRvbmx5IHVubGlrZWQgPSB0aGlzLl91bmxpa2VkLmFzT2JzZXJ2YWJsZSgpO1xyXG4gICAgQE91dHB1dCgpIHJlYWRvbmx5IHBpbm5lZCA9IHRoaXMuX3Bpbm5lZC5hc09ic2VydmFibGUoKTtcclxuICAgIEBPdXRwdXQoKSByZWFkb25seSB1bnBpbm5lZCA9IHRoaXMuX3VucGlubmVkLmFzT2JzZXJ2YWJsZSgpO1xyXG4gICAgQE91dHB1dCgpIHJlYWRvbmx5IHVzZXJuYW1lU2VsZWN0ZWQgPSB0aGlzLl91c2VybmFtZVNlbGVjdGVkLmFzT2JzZXJ2YWJsZSgpO1xyXG4gICAgQE91dHB1dCgpIHJlYWRvbmx5IGF2YXRhclNlbGVjdGVkID0gdGhpcy5fYXZhdGFyU2VsZWN0ZWQuYXNPYnNlcnZhYmxlKCk7XHJcbiAgICBAT3V0cHV0KCkgcmVhZG9ubHkgc2hhcmVkID0gdGhpcy5fc2hhcmVkLmFzT2JzZXJ2YWJsZSgpO1xyXG4gICAgQE91dHB1dCgpIHJlYWRvbmx5IGRlbGV0ZWQgPSB0aGlzLl9kZWxldGVkLmFzT2JzZXJ2YWJsZSgpO1xyXG4gICAgQE91dHB1dCgpIHJlYWRvbmx5IHNlbGVjdGVkID0gdGhpcy5fc2VsZWN0ZWQuYXNPYnNlcnZhYmxlKCk7XHJcbiAgICBAT3V0cHV0KCkgcmVhZG9ubHkgbWVzc2FnZUVkaXRlZCA9IHRoaXMuX21lc3NhZ2VFZGl0ZWQuYXNPYnNlcnZhYmxlKCk7XHJcbiAgICBAT3V0cHV0KCkgcmVhZG9ubHkgc29ydE9yZGVyQ2hhbmdlZCA9IHRoaXMuX3NvcnRPcmRlckNoYW5nZWQuYXNPYnNlcnZhYmxlKCk7XHJcbiAgICBAT3V0cHV0KCkgcmVhZG9ubHkgZmlsdGVyTW9kZUNoYW5nZWQgPSB0aGlzLl9maWx0ZXJNb2RlQ2hhbmdlZC5hc09ic2VydmFibGUoKTtcclxuXHJcbiAgICAvLyNlbmRyZWdpb25cclxuICAgIC8vI3JlZ2lvbiBVSSBCaW5kaW5nc1xyXG5cclxuICAgIEBWaWV3Q2hpbGRyZW4oQ29tbWVudENvbXBvbmVudCkgY29tbWVudHNRdWVyeTogUXVlcnlMaXN0PENvbW1lbnRDb21wb25lbnQ+O1xyXG4gICAgQFZpZXdDaGlsZCgnbWVzc2FnZUNvbnRhaW5lcicpIG1lc3NhZ2VDb250YWluZXI6IEVsZW1lbnRSZWY8SFRNTEVsZW1lbnQ+O1xyXG4gICAgZ2V0IGNvbW1lbnRzKCkgeyByZXR1cm4gQXJyYXkuZnJvbSh0aGlzLmNvbW1lbnRzUXVlcnkpOyB9XHJcblxyXG4gICAgLy8jZW5kcmVnaW9uXHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBSZXR1cm5zIHRydWUgaWYgdGhpcyBtZXNzYWdlIGNhbiBiZSBmb3VuZCB3aXRoaW4gb25lIG9mIHRoZSBtZXNzYWdlIGJ1ZmZlcnMgKG9sZGVyLCBjdXJyZW50LCBuZXdlcilcclxuICAgICAqIEBwYXJhbSBtZXNzYWdlXHJcbiAgICAgKi9cclxuICAgIGlzTWVzc2FnZUxvYWRlZEluQ29udGV4dChtZXNzYWdlOiBDaGF0TWVzc2FnZSkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLm9sZGVyTWVzc2FnZXMuZmluZCh4ID0+IHguaWQgPT09IG1lc3NhZ2UuaWQpXHJcbiAgICAgICAgICAgIHx8IHRoaXMubWVzc2FnZXMuZmluZCh4ID0+IHguaWQgPT09IG1lc3NhZ2UuaWQpXHJcbiAgICAgICAgICAgIHx8IHRoaXMubmV3TWVzc2FnZXMuZmluZCh4ID0+IHguaWQgPT09IG1lc3NhZ2UuaWQpO1xyXG4gICAgfVxyXG5cclxuICAgIGFzeW5jIGxvYWRNZXNzYWdlSW5Db250ZXh0KG1lc3NhZ2U6IENoYXRNZXNzYWdlKSB7XHJcbiAgICAgICAgYXdhaXQgdGhpcy5zb3VyY2VMb2FkZWQ7XHJcblxyXG4gICAgICAgIGNvbnNvbGUubG9nKGBMb2FkaW5nIG1lc3NhZ2UgJHttZXNzYWdlLmlkfSBpbiBjb250ZXh0Li4uYCk7XHJcbiAgICAgICAgd2hpbGUgKHRoaXMuaGFzTW9yZSAmJiAhdGhpcy5pc01lc3NhZ2VMb2FkZWRJbkNvbnRleHQobWVzc2FnZSkpIHtcclxuICAgICAgICAgICAgY29uc29sZS5sb2coYC4uLk5lZWQgdG8gbG9hZCBtb3JlIGNvbW1lbnRzIHRvIGZpbmQgJHttZXNzYWdlLmlkfWApO1xyXG4gICAgICAgICAgICBhd2FpdCB0aGlzLnNob3dNb3JlKCk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBpZiAoIXRoaXMuaXNNZXNzYWdlTG9hZGVkSW5Db250ZXh0KG1lc3NhZ2UpKSB7XHJcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoYEVycm9yIHdoaWxlIGxvYWRpbmcgbWVzc2FnZSBpbiBjb250ZXh0OiBGYWlsZWQgdG8gZmluZCBtZXNzYWdlICR7bWVzc2FnZS5pZH0sIG1heWJlIGl0IHdhcyBkZWxldGVkIWApO1xyXG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBsZXQgaXRlbXMgPSBbXS5jb25jYXQodGhpcy5vbGRlck1lc3NhZ2VzLCB0aGlzLm1lc3NhZ2VzLCB0aGlzLm5ld01lc3NhZ2VzKTtcclxuICAgICAgICBsZXQgaW5kZXggPSBpdGVtcy5maW5kSW5kZXgoeCA9PiB4LmlkID09PSBtZXNzYWdlLmlkKTtcclxuXHJcbiAgICAgICAgaWYgKGluZGV4IDwgMCkge1xyXG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKGBFcnJvciB3aGlsZSBsb2FkaW5nIG1lc3NhZ2UgaW4gY29udGV4dDogTWVzc2FnZSB3YXMgbm90IHByZXNlbnQgaW4gbWVzc2FnZSBsaXN0IWApO1xyXG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBsZXQgc3RhcnRJbmRleCA9IE1hdGgubWF4KDAsIGluZGV4IC0gdGhpcy5tYXhWaXNpYmxlTWVzc2FnZXMgLyAyKTtcclxuICAgICAgICB0aGlzLm5ld01lc3NhZ2VzID0gaXRlbXMuc3BsaWNlKDAsIHN0YXJ0SW5kZXgpO1xyXG4gICAgICAgIHRoaXMubWVzc2FnZXMgPSBpdGVtcy5zcGxpY2UoMCwgdGhpcy5tYXhWaXNpYmxlTWVzc2FnZXMpO1xyXG4gICAgICAgIHRoaXMub2xkZXJNZXNzYWdlcyA9IGl0ZW1zO1xyXG4gICAgICAgIHRoaXMuaXNWaWV3aW5nTW9yZSA9IHRydWU7XHJcbiAgICB9XHJcblxyXG4gICAgZ2V0IHNob3VsZFNob3dOZXdNZXNzYWdlSW5kaWNhdG9yKCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLmlzVmlld2luZ01vcmVcclxuICAgICAgICAgICAgfHwgdGhpcy5jdXN0b21Tb3J0RW5hYmxlZFxyXG4gICAgICAgICAgICB8fCB0aGlzLnNvdXJjZUZpbHRlck1vZGUgIT09IEZpbHRlck1vZGUuQUxMXHJcbiAgICAgICAgICAgIHx8IHRoaXMuaGVsZE1lc3NhZ2VzLmxlbmd0aCA+IDA7XHJcbiAgICB9XHJcblxyXG4gICAgZ2V0IHNob3VsZEhvbGROZXdNZXNzYWdlcygpIHtcclxuICAgICAgICBpZiAodGhpcy5jdXN0b21Tb3J0RW5hYmxlZClcclxuICAgICAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgICAgaWYgKHRoaXMuaG9sZE5ld01lc3NhZ2VzIHx8IHRoaXMuaXNWaWV3aW5nTW9yZSkge1xyXG4gICAgICAgICAgICBjb25zb2xlLmxvZyhgaG9sZGluZyBkdWUgdG8gc2V0dGluZ3NgKTtcclxuICAgICAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBpZiAodGhpcy5lbmFibGVIb2xkT25DbGljayAmJiB0aGlzLm1lc3NhZ2VDbGlja2VkKVxyXG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcclxuXHJcbiAgICAgICAgaWYgKHRoaXMuZW5hYmxlSG9sZE9uU2Nyb2xsKSB7XHJcbiAgICAgICAgICAgIGxldCBrZXlNZXNzYWdlOiBDaGF0TWVzc2FnZTtcclxuXHJcbiAgICAgICAgICAgIGlmICh0aGlzLm5ld2VzdExhc3QpXHJcbiAgICAgICAgICAgICAgICBrZXlNZXNzYWdlID0gdGhpcy5tZXNzYWdlc1t0aGlzLm1lc3NhZ2VzLmxlbmd0aCAtIDFdO1xyXG4gICAgICAgICAgICBlbHNlXHJcbiAgICAgICAgICAgICAgICBrZXlNZXNzYWdlID0gdGhpcy5tZXNzYWdlc1swXTtcclxuXHJcbiAgICAgICAgICAgIGlmIChrZXlNZXNzYWdlKSB7XHJcbiAgICAgICAgICAgICAgICBjb25zdCBtZXNzYWdlRWxlbWVudCA9IHRoaXMuZ2V0RWxlbWVudEZvckNvbW1lbnQoa2V5TWVzc2FnZS5pZCk7XHJcbiAgICAgICAgICAgICAgICBpZiAobWVzc2FnZUVsZW1lbnQpIHtcclxuICAgICAgICAgICAgICAgICAgICBpZiAoIXRoaXMuaXNFbGVtZW50VmlzaWJsZShtZXNzYWdlRWxlbWVudCkpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2coYGtleSBlbGVtZW50IGlzIG5vdCB2aXNpYmxlYCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKGBrZXkgZWxlbWVudCBpcyB2aXNpYmxlYCk7XHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhgY291bGQgbm90IGZpbmQga2V5IGVsZW1lbnRgKTtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKGBjb3VsZCBub3QgZmluZCBrZXkgbWVzc2FnZWApO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICB9XHJcblxyXG4gICAgcHJpdmF0ZSBpc0VsZW1lbnRWaXNpYmxlKGVsZW1lbnQ6IEVsZW1lbnQpIHtcclxuICAgICAgICBjb25zdCBlbGVtZW50UmVjdCA9IGVsZW1lbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XHJcbiAgICAgICAgcmV0dXJuICEhZWxlbWVudFJlY3RcclxuICAgICAgICAgICAgJiYgZWxlbWVudFJlY3QuYm90dG9tID49IDBcclxuICAgICAgICAgICAgJiYgZWxlbWVudFJlY3QucmlnaHQgPj0gMFxyXG4gICAgICAgICAgICAmJiBlbGVtZW50UmVjdC5sZWZ0IDw9IGRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5jbGllbnRXaWR0aFxyXG4gICAgICAgICAgICAmJiBlbGVtZW50UmVjdC50b3AgPD0gZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LmNsaWVudEhlaWdodDtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIEdldCB0aGUgQ29tbWVudENvbXBvbmVudCBpbnN0YW50aWF0ZWQgZm9yIHRoZSBnaXZlbiBDaGF0TWVzc2FnZSxcclxuICAgICAqIGlmIGl0IGV4aXN0cyBpbiB0aGUgY3VycmVudCB2aWV3LiBOb3RlIHRoYXQgbWVzc2FnZXMgd2hpY2ggYXJlIG5vdFxyXG4gICAgICogY3VycmVudGx5IHNob3duIHRvIHRoZSB1c2VyIHdpbGwgbm90IHJldHVybiBhIENvbW1lbnRDb21wb25lbnQuXHJcbiAgICAgKiBAcGFyYW0gbWVzc2FnZVxyXG4gICAgICogQHJldHVybnNcclxuICAgICAqL1xyXG4gICAgZ2V0Q29tbWVudENvbXBvbmVudEZvck1lc3NhZ2UobWVzc2FnZTogQ2hhdE1lc3NhZ2UpIHtcclxuICAgICAgICBpZiAoIW1lc3NhZ2UpXHJcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgWW91IG11c3QgcGFzcyBhIHZhbGlkIENoYXRNZXNzYWdlYCk7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuY29tbWVudHMuZmluZCh4ID0+IHgubWVzc2FnZT8uaWQgPT09IG1lc3NhZ2UuaWQpO1xyXG4gICAgfVxyXG5cclxuICAgIHNhdmVFZGl0KG1lc3NhZ2U6IENoYXRNZXNzYWdlLCBuZXdNZXNzYWdlOiBzdHJpbmcpIHtcclxuICAgICAgICB0aGlzLl9tZXNzYWdlRWRpdGVkLm5leHQoeyBtZXNzYWdlLCBuZXdNZXNzYWdlIH0pO1xyXG4gICAgfVxyXG5cclxuICAgIGxpa2VNZXNzYWdlKG1lc3NhZ2U6IENoYXRNZXNzYWdlKSB7XHJcbiAgICAgICAgdGhpcy5fbGlrZWQubmV4dChtZXNzYWdlKTtcclxuICAgIH1cclxuXHJcbiAgICB1bmxpa2VNZXNzYWdlKG1lc3NhZ2U6IENoYXRNZXNzYWdlKSB7XHJcbiAgICAgICAgdGhpcy5fdW5saWtlZC5uZXh0KG1lc3NhZ2UpO1xyXG4gICAgfVxyXG5cclxuICAgIHBpbk1lc3NhZ2UobWVzc2FnZTogQ2hhdE1lc3NhZ2UsIG9wdGlvbnM6IFBpbk9wdGlvbnMpIHtcclxuICAgICAgICB0aGlzLl9waW5uZWQubmV4dCh7IG1lc3NhZ2UsIG9wdGlvbnMgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgdW5waW5NZXNzYWdlKG1lc3NhZ2U6IENoYXRNZXNzYWdlKSB7XHJcbiAgICAgICAgdGhpcy5fdW5waW5uZWQubmV4dChtZXNzYWdlKTtcclxuICAgIH1cclxuXHJcbiAgICByZXBvcnRNZXNzYWdlKG1lc3NhZ2U6IENoYXRNZXNzYWdlKSB7XHJcbiAgICAgICAgdGhpcy5fcmVwb3J0ZWQubmV4dChtZXNzYWdlKTtcclxuICAgIH1cclxuXHJcbiAgICBzZWxlY3RNZXNzYWdlKG1lc3NhZ2U6IENoYXRNZXNzYWdlKSB7XHJcbiAgICAgICAgdGhpcy5fc2VsZWN0ZWQubmV4dChtZXNzYWdlKTtcclxuICAgIH1cclxuXHJcbiAgICBzZWxlY3RNZXNzYWdlVXNlcihtZXNzYWdlOiBDaGF0TWVzc2FnZSkge1xyXG4gICAgICAgIHRoaXMuX3VzZXJTZWxlY3RlZC5uZXh0KG1lc3NhZ2UpO1xyXG4gICAgfVxyXG5cclxuICAgIHNlbGVjdFVzZXJuYW1lKHVzZXI6IFVzZXIpIHtcclxuICAgICAgICB0aGlzLl91c2VybmFtZVNlbGVjdGVkLm5leHQodXNlcik7XHJcbiAgICB9XHJcblxyXG4gICAgc2VsZWN0QXZhdGFyKHVzZXI6IFVzZXIpIHtcclxuICAgICAgICB0aGlzLl9hdmF0YXJTZWxlY3RlZC5uZXh0KHVzZXIpO1xyXG4gICAgfVxyXG5cclxuICAgIHNoYXJlZE1lc3NhZ2UobWVzc2FnZTogQ2hhdE1lc3NhZ2UpIHtcclxuICAgICAgICB0aGlzLl9zaGFyZWQubmV4dChtZXNzYWdlKTtcclxuICAgIH1cclxuXHJcbiAgICBzdGFydEVkaXRpbmcobWVzc2FnZTogQ2hhdE1lc3NhZ2UpIHtcclxuICAgICAgICB0aGlzLm1lc3NhZ2VzLmZvckVhY2gobSA9PiBtLnRyYW5zaWVudFN0YXRlLmVkaXRpbmcgPSBmYWxzZSk7XHJcbiAgICAgICAgbWVzc2FnZS50cmFuc2llbnRTdGF0ZS5lZGl0aW5nID0gdHJ1ZTtcclxuICAgIH1cclxuXHJcbiAgICBkZWxldGVNZXNzYWdlKG1lc3NhZ2U6IENoYXRNZXNzYWdlKSB7XHJcbiAgICAgICAgdGhpcy5fZGVsZXRlZC5uZXh0KG1lc3NhZ2UpO1xyXG4gICAgfVxyXG5cclxuICAgIHByaXZhdGUgc2V0U291cmNlKHZhbHVlOiBDaGF0U291cmNlQmFzZSkge1xyXG4gICAgICAgIHRoaXMuY3VzdG9tU29ydEVuYWJsZWQgPSAodmFsdWU/LnNvcnRPcmRlciA/PyBDb21tZW50c09yZGVyLk5FV0VTVCkgIT09IENvbW1lbnRzT3JkZXIuTkVXRVNUO1xyXG4gICAgICAgIHRoaXMubmV3TWVzc2FnZXMgPSBbXTtcclxuICAgICAgICB0aGlzLm9sZGVyTWVzc2FnZXMgPSBbXTtcclxuICAgICAgICB0aGlzLmhlbGRNZXNzYWdlcyA9IFtdO1xyXG5cclxuICAgICAgICAod2luZG93IGFzIGFueSkuYmFudGFTb3VyY2VEZWJ1ZyA9IHZhbHVlO1xyXG5cclxuICAgICAgICBpZiAodGhpcy5fc291cmNlU3Vicykge1xyXG4gICAgICAgICAgICB0aGlzLl9zb3VyY2VTdWJzLnVuc3Vic2NyaWJlKCk7XHJcbiAgICAgICAgICAgIHRoaXMuX3NvdXJjZVN1YnMgPSBudWxsO1xyXG4gICAgICAgIH1cclxuICAgICAgICB0aGlzLl9zb3VyY2UgPSB2YWx1ZTtcclxuXHJcbiAgICAgICAgaWYgKHZhbHVlKSB7XHJcbiAgICAgICAgICAgIGNvbnN0IG1lc3NhZ2VzID0gKHZhbHVlLm1lc3NhZ2VzIHx8IFtdKS5zbGljZSgpO1xyXG4gICAgICAgICAgICB0aGlzLm1lc3NhZ2VzID0gbWVzc2FnZXM7XHJcbiAgICAgICAgICAgIHRoaXMub2xkZXJNZXNzYWdlcyA9IG1lc3NhZ2VzLnNwbGljZSh0aGlzLm1heFZpc2libGVNZXNzYWdlcywgbWVzc2FnZXMubGVuZ3RoKTtcclxuICAgICAgICAgICAgdGhpcy5oYXNNb3JlID0gdHJ1ZTsgLy90aGlzLm9sZGVyTWVzc2FnZXMubGVuZ3RoID4gMDtcclxuXHJcbiAgICAgICAgICAgIHRoaXMuX3NvdXJjZVN1YnMgPSBuZXcgU3Vic2NyaXB0aW9uKCk7XHJcbiAgICAgICAgICAgIHRoaXMuX3NvdXJjZVN1YnMuYWRkKHRoaXMuX3NvdXJjZS5tZXNzYWdlUmVjZWl2ZWQuc3Vic2NyaWJlKG1zZyA9PiB0aGlzLm1lc3NhZ2VSZWNlaXZlZChtc2cpKSk7XHJcbiAgICAgICAgICAgIHRoaXMuX3NvdXJjZVN1YnMuYWRkKHRoaXMuX3NvdXJjZS5tZXNzYWdlU2VudC5zdWJzY3JpYmUobXNnID0+IHRoaXMubWVzc2FnZVNlbnQobXNnKSkpO1xyXG4gICAgICAgICAgICB0aGlzLl9zb3VyY2VTdWJzLmFkZCh0aGlzLl9zb3VyY2UubWVzc2FnZVVwZGF0ZWQuc3Vic2NyaWJlKG1zZyA9PiB0aGlzLm1lc3NhZ2VVcGRhdGVkKG1zZykpKTtcclxuXHJcbiAgICAgICAgICAgIHRoaXMuX3NvdXJjZVN1YnMuYWRkKFxyXG4gICAgICAgICAgICAgICAgdGhpcy5iYWNrZW5kLnVzZXJDaGFuZ2VkLnN1YnNjcmliZSh1c2VyID0+IHRoaXMuY3VycmVudFVzZXIgPSB1c2VyKVxyXG4gICAgICAgICAgICApO1xyXG5cclxuICAgICAgICAgICAgdGhpcy5nZXRJbml0aWFsTWVzc2FnZXMoKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgcHJpdmF0ZSBhc3luYyBnZXRJbml0aWFsTWVzc2FnZXMoKSB7XHJcblxyXG4gICAgICAgIC8vIEdldCB0aGUgcGlubmVkIG1lc3NhZ2VzXHJcbiAgICAgICAgbGV0IHBpbm5lZE1lc3NhZ2VzID0gYXdhaXQgdGhpcy5fc291cmNlLmdldFBpbm5lZE1lc3NhZ2VzKCk7XHJcbiAgICAgICAgcGlubmVkTWVzc2FnZXMuZm9yRWFjaChtID0+IG0udHJhbnNpZW50U3RhdGUgPz89IHt9KTtcclxuICAgICAgICB0aGlzLnBpbm5lZE1lc3NhZ2VzID0gcGlubmVkTWVzc2FnZXM7XHJcblxyXG5cclxuICAgICAgICBsZXQgbWVzc2FnZXMgPSBhd2FpdCB0aGlzLl9zb3VyY2UuZ2V0RXhpc3RpbmdNZXNzYWdlcygpO1xyXG4gICAgICAgIG1lc3NhZ2VzLmZvckVhY2gobSA9PiBtLnRyYW5zaWVudFN0YXRlID8/PSB7fSk7XHJcbiAgICAgICAgdGhpcy5tZXNzYWdlcyA9IHRoaXMubmV3ZXN0TGFzdCA/IG1lc3NhZ2VzLnNsaWNlKCkucmV2ZXJzZSgpIDogbWVzc2FnZXM7XHJcblxyXG4gICAgICAgIGlmICh0aGlzLm1lc3NhZ2VzLmxlbmd0aCA+IHRoaXMubWF4VmlzaWJsZU1lc3NhZ2VzKSB7XHJcbiAgICAgICAgICAgIGlmICh0aGlzLm5ld2VzdExhc3QpIHtcclxuICAgICAgICAgICAgICAgIHRoaXMucHJldmlvdXNNZXNzYWdlcy5wdXNoKC4uLnRoaXMubWVzc2FnZXMuc3BsaWNlKDAsIHRoaXMubWVzc2FnZXMubGVuZ3RoIC0gdGhpcy5tYXhWaXNpYmxlTWVzc2FnZXMpKTtcclxuICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgIHRoaXMubmV4dE1lc3NhZ2VzLnVuc2hpZnQoLi4udGhpcy5tZXNzYWdlcy5zcGxpY2UodGhpcy5tYXhWaXNpYmxlTWVzc2FnZXMsIHRoaXMubWVzc2FnZXMubGVuZ3RoKSk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHRoaXMuZGVidWdNZXNzYWdlcygpO1xyXG4gICAgICAgIHRoaXMuc29ydE1lc3NhZ2VzKCk7XHJcbiAgICAgICAgaWYgKHRoaXMubWFya1NvdXJjZUxvYWRlZClcclxuICAgICAgICAgICAgdGhpcy5tYXJrU291cmNlTG9hZGVkKCk7XHJcbiAgICB9XHJcblxyXG4gICAgZGVidWdNZXNzYWdlcygpIHtcclxuICAgICAgICBpZiAoIXRoaXMuc2hvd0RlYnVnKVxyXG4gICAgICAgICAgICByZXR1cm47XHJcblxyXG4gICAgICAgIC8vIGNvbnNvbGUubG9nKFtcclxuICAgICAgICAvLyAgICAgLi4udGhpcy5wcmV2aW91c01lc3NhZ2VzLm1hcCh4ID0+IHgubWVzc2FnZSksXHJcbiAgICAgICAgLy8gICAgICdbWycsXHJcbiAgICAgICAgLy8gICAgIC4uLnRoaXMubWVzc2FnZXMubWFwKHggPT4geC5tZXNzYWdlKSxcclxuICAgICAgICAvLyAgICAgJ11dJyxcclxuICAgICAgICAvLyAgICAgLi4udGhpcy5uZXh0TWVzc2FnZXMubWFwKHggPT4geC5tZXNzYWdlKVxyXG4gICAgICAgIC8vIF0ubWFwKHggPT4gL1xcZCsvLnRlc3QoeCkgPyB0aGlzLnplcm9QYWQoeCwgMikgOiB4KS5qb2luKFwiIFwiKSk7XHJcbiAgICB9XHJcblxyXG4gICAgemVyb1BhZChudW1iZXI6IG51bWJlciB8IHN0cmluZywgY291bnQ6IG51bWJlciA9IDIpIHtcclxuICAgICAgICBsZXQgc3RyOiBzdHJpbmc7XHJcblxyXG4gICAgICAgIGlmICh0eXBlb2YgbnVtYmVyID09PSAnbnVtYmVyJylcclxuICAgICAgICAgICAgc3RyID0gU3RyaW5nKG51bWJlcik7XHJcbiAgICAgICAgZWxzZVxyXG4gICAgICAgICAgICBzdHIgPSBudW1iZXI7XHJcblxyXG4gICAgICAgIHdoaWxlIChzdHIubGVuZ3RoIDwgY291bnQpXHJcbiAgICAgICAgICAgIHN0ciA9ICcwJyArIHN0cjtcclxuXHJcbiAgICAgICAgcmV0dXJuIHN0cjtcclxuICAgIH1cclxuICAgIGxlZnRQYWQoc3RyOiBzdHJpbmcsIGNvdW50OiBudW1iZXIgPSAyKSB7XHJcbiAgICAgICAgd2hpbGUgKHN0ci5sZW5ndGggPCBjb3VudClcclxuICAgICAgICAgICAgc3RyID0gJyAnICsgc3RyO1xyXG5cclxuICAgICAgICByZXR1cm4gc3RyO1xyXG4gICAgfVxyXG5cclxuICAgIG1lc3NhZ2VJZGVudGl0eShpbmRleDogbnVtYmVyLCBjaGF0TWVzc2FnZTogQ2hhdE1lc3NhZ2UpIHtcclxuICAgICAgICByZXR1cm4gY2hhdE1lc3NhZ2UuaWQ7XHJcbiAgICB9XHJcblxyXG4gICAgZ2V0IHNvdXJjZVNvcnRPcmRlcigpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5zb3VyY2U/LnNvcnRPcmRlciA/PyBDb21tZW50c09yZGVyLk5FV0VTVDtcclxuICAgIH1cclxuXHJcbiAgICBnZXQgc291cmNlRmlsdGVyTW9kZSgpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5zb3VyY2U/LmZpbHRlck1vZGUgPz8gRmlsdGVyTW9kZS5BTEw7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBTaG93IHRoZSBuZXdlc3QgY29udGVudC5cclxuICAgICAqIC0gSWYgYW4gdW5uYXR1cmFsIHNvcnQgb3JkZXIgaXMgYWN0aXZlIChpZSBPbGRlc3Qgb3IgTGlrZXMpLCBpdCB3aWxsIGJlIGNoYW5nZWQgdG8gTmV3ZXN0LlxyXG4gICAgICogLSBUaGUgbmV3IGNvbnRlbnQgd2lsbCBiZSBwbGFjZWQgd2hlcmUgbmV3IGNvbnRlbnQgZ29lcyBiYXNlZCBvbiBuZXdlc3RMYXN0IChyZXBsaWVzIG1vZGUpLCBzbyBpZiBpdCBpcyB0cnVlLCB0aGUgY29udGVudCBpc1xyXG4gICAgICogICBwbGFjZWQgYXQgdGhlIGVuZCwgb3RoZXJ3aXNlIGl0IGlzIHBsYWNlZCBhdCB0aGUgYmVnaW5uaW5nLlxyXG4gICAgICpcclxuICAgICAqIEBwYXJhbSBldmVudFxyXG4gICAgICogQHJldHVybnNcclxuICAgICAqL1xyXG4gICAgYXN5bmMgc2hvd05ld2VzdChldmVudDogTW91c2VFdmVudCkge1xyXG5cclxuICAgICAgICAvLyBSZWdhcmRsZXNzIG9mIGhvdyB3ZSBoYW5kbGUgdGhpcywgY2xlYXIgb3V0IG91ciBoZWxkIG1lc3NhZ2VzXHJcblxyXG4gICAgICAgIHRoaXMuaGVsZE1lc3NhZ2VzID0gW107XHJcbiAgICAgICAgdGhpcy5tZXNzYWdlQ2xpY2tlZCA9IGZhbHNlO1xyXG5cclxuICAgICAgICAvLyBJZiB0aGUgc29ydCBvcmRlciBpcyBub3QgYWxyZWFkeSBOZXdlc3QsIHN3aXRjaCB0byBOZXdlc3QgYW5kIHN0b3AuXHJcbiAgICAgICAgLy8gVGhlIGFjdCBvZiBjaGFuZ2luZyB0aGUgc29ydCBvcmRlciB3aWxsIGNhdXNlIHRoZSBuZXdlc3QgY29udGVudCB0byBiZSBsb2FkZWQuXHJcblxyXG4gICAgICAgIGxldCBuYXR1cmFsT3JkZXIgPSBDb21tZW50c09yZGVyLk5FV0VTVDtcclxuICAgICAgICBpZiAodGhpcy5zb3VyY2VTb3J0T3JkZXIgIT09IG5hdHVyYWxPcmRlciB8fCB0aGlzLnNvdXJjZUZpbHRlck1vZGUgIT09IEZpbHRlck1vZGUuQUxMKSB7XHJcbiAgICAgICAgICAgIGlmICh0aGlzLnNvdXJjZVNvcnRPcmRlciAhPT0gbmF0dXJhbE9yZGVyKVxyXG4gICAgICAgICAgICAgICAgdGhpcy5fc29ydE9yZGVyQ2hhbmdlZC5uZXh0KG5hdHVyYWxPcmRlcik7XHJcbiAgICAgICAgICAgIGlmICh0aGlzLnNvdXJjZUZpbHRlck1vZGUgIT09IEZpbHRlck1vZGUuQUxMKVxyXG4gICAgICAgICAgICAgICAgdGhpcy5fZmlsdGVyTW9kZUNoYW5nZWQubmV4dChGaWx0ZXJNb2RlLkFMTCk7XHJcbiAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIE9uIHRoaXMgcGF0aCwgd2UgYXJlIGFscmVhZHkgb24gTmV3ZXN0LCBidXQgdGhlcmUgaXMgbmV3ZXIgY29udGVudCBhdmFpbGFibGUgKHN1Y2ggYXMgd2hlbiBuZXcgY29udGVudCBpc1xyXG4gICAgICAgIC8vIGJlaW5nIGJ1ZmZlcmVkIGR1ZSB0byB1c2VyIGVuZ2FnZW1lbnQgb24gYSBjb21tZW50KVxyXG5cclxuICAgICAgICB0aGlzLmlzVmlld2luZ01vcmUgPSBmYWxzZTtcclxuXHJcbiAgICAgICAgLy8gTW92ZSBhbGwgbmV3ZXJNZXNzYWdlcyBpbnRvIG1lc3NhZ2VzLCByZXNwZWN0aW5nIHRoZSBuZXdlc3RMYXN0IGRpcmVjdGlvbiAobm9ybWFsIG9yIHJlcGxpZXMgbW9kZSlcclxuXHJcbiAgICAgICAgaWYgKHRoaXMubmV3ZXN0TGFzdClcclxuICAgICAgICAgICAgdGhpcy5tZXNzYWdlcyA9IHRoaXMubWVzc2FnZXMuY29uY2F0KHRoaXMubmV3TWVzc2FnZXMuc3BsaWNlKDAsIHRoaXMubmV3TWVzc2FnZXMubGVuZ3RoKSk7XHJcbiAgICAgICAgZWxzZVxyXG4gICAgICAgICAgICB0aGlzLm1lc3NhZ2VzID0gdGhpcy5uZXdNZXNzYWdlcy5zcGxpY2UoMCwgdGhpcy5uZXdNZXNzYWdlcy5sZW5ndGgpLmNvbmNhdCh0aGlzLm1lc3NhZ2VzKTtcclxuXHJcbiAgICAgICAgbGV0IG92ZXJmbG93ID0gdGhpcy5tZXNzYWdlcy5zcGxpY2UodGhpcy5tYXhWaXNpYmxlTWVzc2FnZXMsIHRoaXMubWVzc2FnZXMubGVuZ3RoKTtcclxuICAgICAgICB0aGlzLm9sZGVyTWVzc2FnZXMgPSBvdmVyZmxvdy5jb25jYXQodGhpcy5vbGRlck1lc3NhZ2VzKTtcclxuICAgICAgICB0aGlzLm9sZGVyTWVzc2FnZXMuc3BsaWNlKHRoaXMubWF4TWVzc2FnZXMgLSB0aGlzLm1heFZpc2libGVNZXNzYWdlcywgdGhpcy5vbGRlck1lc3NhZ2VzLmxlbmd0aCk7XHJcbiAgICAgICAgdGhpcy5oYXNNb3JlID0gdGhpcy5vbGRlck1lc3NhZ2VzLmxlbmd0aCA+IDA7XHJcblxyXG4gICAgICAgIC8vIFNjcm9sbCB0byB0aGUgbmV3ZXN0IGNvbW1lbnQuXHJcblxyXG4gICAgICAgIGlmICh0aGlzLm1lc3NhZ2VzLmxlbmd0aCA+IDApIHtcclxuICAgICAgICAgICAgaWYgKHRoaXMubmV3ZXN0TGFzdCkge1xyXG4gICAgICAgICAgICAgICAgdGhpcy5zY3JvbGxUb0NvbW1lbnQodGhpcy5tZXNzYWdlc1t0aGlzLm1lc3NhZ2VzLmxlbmd0aCAtIDFdLmlkKTtcclxuICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgIHRoaXMuc2Nyb2xsVG9Db21tZW50KHRoaXMubWVzc2FnZXNbMF0uaWQpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIGdldCBzaG93RGVidWcoKSB7XHJcbiAgICAgICAgaWYgKHR5cGVvZiB3aW5kb3cgPT09ICd1bmRlZmluZWQnKVxyXG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XHJcblxyXG4gICAgICAgIHJldHVybiBsb2NhbFN0b3JhZ2VbJ2JhbnRhOmRlYnVnJ10gPT09ICcxJztcclxuICAgIH1cclxuXHJcbiAgICBnZXQgc2hvdWxkU2hvd05leHQoKSB7XHJcbiAgICAgICAgaWYgKCF0aGlzLm5ld2VzdExhc3QpIHtcclxuICAgICAgICAgICAgcmV0dXJuIHRoaXMuaGFzTW9yZSB8fCB0aGlzLm5leHRNZXNzYWdlcy5sZW5ndGggPiAwO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgcmV0dXJuIHRoaXMubmV4dE1lc3NhZ2VzLmxlbmd0aCA+IDA7XHJcbiAgICB9XHJcblxyXG4gICAgZ2V0IHNob3VsZFNob3dQcmV2aW91cygpIHtcclxuICAgICAgICBpZiAodGhpcy5uZXdlc3RMYXN0KSB7XHJcbiAgICAgICAgICAgIHJldHVybiB0aGlzLmhhc01vcmUgfHwgdGhpcy5wcmV2aW91c01lc3NhZ2VzLmxlbmd0aCA+IDA7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICByZXR1cm4gdGhpcy5wcmV2aW91c01lc3NhZ2VzLmxlbmd0aCA+IDA7XHJcbiAgICB9XHJcblxyXG4gICAgZ2V0IHBhZ2VTaXplKCkge1xyXG4gICAgICAgIHJldHVybiBNYXRoLm1pbigyMCwgdGhpcy5tYXhWaXNpYmxlTWVzc2FnZXMgfHwgMjApO1xyXG4gICAgfVxyXG5cclxuICAgIGFzeW5jIHNob3dQcmV2aW91cygpIHtcclxuICAgICAgICB0aGlzLmlzVmlld2luZ01vcmUgPSB0cnVlO1xyXG4gICAgICAgIGxldCBuZXh0UGFnZVNpemUgPSB0aGlzLnBhZ2VTaXplO1xyXG4gICAgICAgIHRoaXMuaXNMb2FkaW5nTW9yZSA9IGZhbHNlO1xyXG5cclxuICAgICAgICBpZiAoaXNOYU4obmV4dFBhZ2VTaXplKSlcclxuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBOb3Qgc2FmZSB0byBsb2FkIG1vcmUgd2l0aCBOYU4gcGFnZSBzaXplYCk7XHJcblxyXG4gICAgICAgIGlmICh0aGlzLnByZXZpb3VzTWVzc2FnZXMubGVuZ3RoID4gMCkge1xyXG4gICAgICAgICAgICBjb25zdCBzdG9yZWRNZXNzYWdlcyA9IHRoaXMucHJldmlvdXNNZXNzYWdlcy5zcGxpY2UoTWF0aC5tYXgoMCwgdGhpcy5wcmV2aW91c01lc3NhZ2VzLmxlbmd0aCAtIG5leHRQYWdlU2l6ZSksIG5leHRQYWdlU2l6ZSk7XHJcbiAgICAgICAgICAgIHRoaXMubWVzc2FnZXMgPSBbLi4uc3RvcmVkTWVzc2FnZXMsIC4uLnRoaXMubWVzc2FnZXNdO1xyXG4gICAgICAgICAgICBuZXh0UGFnZVNpemUgLT0gc3RvcmVkTWVzc2FnZXMubGVuZ3RoO1xyXG4gICAgICAgIH1cclxuXHJcblxyXG4gICAgICAgIC8vIExvYWQgbW9yZSBmcm9tIGJhY2tlbmQgaWYgbmVlZGVkXHJcbiAgICAgICAgLy8gTm90ZTogQmFja2VuZCBvbmx5IHN1cHBvcnRzIGZldGNoaW5nIG1vcmUgY29udGVudCBpbiBvbmUgZGlyZWN0aW9uLlxyXG5cclxuICAgICAgICBsZXQgbGFzdE1lc3NhZ2UgPSB0aGlzLnByZXZpb3VzTWVzc2FnZXNbMF0gPz8gdGhpcy5tZXNzYWdlc1swXTtcclxuXHJcbiAgICAgICAgaWYgKG5leHRQYWdlU2l6ZSA+IDAgJiYgdGhpcy5uZXdlc3RMYXN0ICYmIGxhc3RNZXNzYWdlKSB7XHJcbiAgICAgICAgICAgIHRoaXMuaXNMb2FkaW5nTW9yZSA9IHRydWU7XHJcblxyXG4gICAgICAgICAgICBsZXQgbWVzc2FnZXMgPSBhd2FpdCB0aGlzLnNvdXJjZS5sb2FkQWZ0ZXIobGFzdE1lc3NhZ2UsIG5leHRQYWdlU2l6ZSk7XHJcblxyXG4gICAgICAgICAgICBtZXNzYWdlcyA9IG1lc3NhZ2VzLnNsaWNlKCkucmV2ZXJzZSgpOyAvLyBiZWNhdXNlIG5ld2VzdExhc3QgPT09IHRydWVcclxuICAgICAgICAgICAgbWVzc2FnZXMuZm9yRWFjaChtID0+IG0udHJhbnNpZW50U3RhdGUgPz89IHt9KTtcclxuXHJcbiAgICAgICAgICAgIC8vIEluIHJlcGxpZXMgbW9kZSAobmV3ZXN0TGFzdCksIHdlIHdhbnQgdG8gcHV0IHRoZXNlIG5ldyBtZXNzYWdlcyBvbnRvIHRoZSAqdG9wKiBvZiB0aGUgc2V0IG9mIHZpc2libGUgbWVzc2FnZXMuXHJcbiAgICAgICAgICAgIC8vIE90aGVyd2lzZSB3ZSB3YW50IHRvIHB1dCB0aGVtIG9uIHRoZSAqYm90dG9tKi5cclxuXHJcbiAgICAgICAgICAgIHRoaXMubWVzc2FnZXMgPSBbLi4ubWVzc2FnZXMsIC4uLnRoaXMubWVzc2FnZXNdO1xyXG5cclxuICAgICAgICAgICAgLy8gSWYgd2UgZGlkbid0IHJlY2VpdmUgYW55IG1lc3NhZ2VzIGF0IGFsbCwgdGhlcmUncyBubyBtb3JlIHRvIGZldGNoLlxyXG5cclxuICAgICAgICAgICAgaWYgKG1lc3NhZ2VzLmxlbmd0aCA9PT0gMClcclxuICAgICAgICAgICAgICAgIHRoaXMuaGFzTW9yZSA9IGZhbHNlO1xyXG5cclxuICAgICAgICAgICAgdGhpcy5pc0xvYWRpbmdNb3JlID0gZmFsc2U7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBFeHRyYWN0IHRoZSBtZXNzYWdlcyB0aGF0IGRvIG5vdCBmaXQgaW4gdGhlIG1heFZpc2libGVNZXNzYWdlcyBidWZmZXIuXHJcblxyXG4gICAgICAgIGlmICh0aGlzLm1lc3NhZ2VzLmxlbmd0aCA+IHRoaXMubWF4VmlzaWJsZU1lc3NhZ2VzKSB7XHJcbiAgICAgICAgICAgIGxldCBvdmVyZmxvdyA9IHRoaXMubWVzc2FnZXMuc3BsaWNlKHRoaXMubWF4VmlzaWJsZU1lc3NhZ2VzLCB0aGlzLm1lc3NhZ2VzLmxlbmd0aCk7XHJcbiAgICAgICAgICAgIHRoaXMubmV4dE1lc3NhZ2VzLnVuc2hpZnQoLi4ub3ZlcmZsb3cpO1xyXG4gICAgICAgICAgICBpZiAodGhpcy5uZXh0TWVzc2FnZXMubGVuZ3RoID4gdGhpcy5tYXhNZXNzYWdlcylcclxuICAgICAgICAgICAgICAgIHRoaXMubmV4dE1lc3NhZ2VzLnNwbGljZSh0aGlzLm1heE1lc3NhZ2VzLCB0aGlzLm5leHRNZXNzYWdlcy5sZW5ndGgpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgdGhpcy5kZWJ1Z01lc3NhZ2VzKCk7XHJcbiAgICB9XHJcblxyXG4gICAgZ2V0IHNvcnROZXh0TGFiZWwoKSB7XHJcbiAgICAgICAgaWYgKHRoaXMuc291cmNlU29ydE9yZGVyID09PSAnbmV3ZXN0Jykge1xyXG4gICAgICAgICAgICByZXR1cm4gJ09sZGVyJztcclxuICAgICAgICB9IGVsc2UgaWYgKHRoaXMuc291cmNlU29ydE9yZGVyID09PSAnb2xkZXN0Jykge1xyXG4gICAgICAgICAgICByZXR1cm4gJ05ld2VyJztcclxuICAgICAgICB9IGVsc2UgaWYgKHRoaXMuc291cmNlU29ydE9yZGVyID09PSAnbGlrZXMnKSB7XHJcbiAgICAgICAgICAgIHJldHVybiAnTGVzcyBMaWtlcyc7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICByZXR1cm4gJ01vcmUnO1xyXG4gICAgfVxyXG5cclxuICAgIGdldCBzb3J0UHJldmlvdXNMYWJlbCgpIHtcclxuICAgICAgICBpZiAodGhpcy5zb3VyY2VTb3J0T3JkZXIgPT09ICduZXdlc3QnKSB7XHJcbiAgICAgICAgICAgIHJldHVybiAnTmV3ZXInO1xyXG4gICAgICAgIH0gZWxzZSBpZiAodGhpcy5zb3VyY2VTb3J0T3JkZXIgPT09ICdvbGRlc3QnKSB7XHJcbiAgICAgICAgICAgIHJldHVybiAnT2xkZXInO1xyXG4gICAgICAgIH0gZWxzZSBpZiAodGhpcy5zb3VyY2VTb3J0T3JkZXIgPT09ICdsaWtlcycpIHtcclxuICAgICAgICAgICAgcmV0dXJuICdNb3JlIExpa2VzJztcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHJldHVybiAnTW9yZSc7XHJcbiAgICB9XHJcblxyXG4gICAgZ2V0IG5leHRMYWJlbCgpIHsgcmV0dXJuIHRoaXMubmV3ZXN0TGFzdCA/IHRoaXMuc29ydFByZXZpb3VzTGFiZWwgOiB0aGlzLnNvcnROZXh0TGFiZWw7IH1cclxuICAgIGdldCBwcmV2aW91c0xhYmVsKCkgeyByZXR1cm4gdGhpcy5uZXdlc3RMYXN0ID8gdGhpcy5zb3J0TmV4dExhYmVsIDogdGhpcy5zb3J0UHJldmlvdXNMYWJlbDsgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogU2hvdyBtb3JlIGNvbnRlbnRcclxuICAgICAqIC0gV2hlbiBpbiByZXBsaWVzIG1vZGUgKG5ld2VzdExhc3QpLCB0aGUgY29udGVudCBpcyBhZGRlZCBhdCB0aGUgdG9wXHJcbiAgICAgKiAtIFdoZW4gaW4gbm9ybWFsIG1vZGUsIHRoZSBjb250ZW50IGlzIGFkZGVkIGF0IHRoZSBib3R0b21cclxuICAgICAqIC0gVGhlIGN1cnJlbnQgc29ydCBvcmRlciBkb2VzICpub3QqIGZhY3RvciBpbiBoZXJlLCB3aGljaCBpcyB3aHkgaXQgaXMgc2hvd01vcmUoKSBub3Qgc2hvd0VhcmxpZXIoKS5cclxuICAgICAqXHJcbiAgICAgKiBAcmV0dXJuc1xyXG4gICAgICovXHJcbiAgICBhc3luYyBzaG93TmV4dCgpIHtcclxuICAgICAgICB0aGlzLmlzVmlld2luZ01vcmUgPSB0cnVlO1xyXG5cclxuICAgICAgICBsZXQgbmV4dFBhZ2VTaXplID0gdGhpcy5wYWdlU2l6ZTtcclxuXHJcbiAgICAgICAgaWYgKGlzTmFOKG5leHRQYWdlU2l6ZSkpXHJcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgTm90IHNhZmUgdG8gbG9hZCBtb3JlIHdpdGggTmFOIHBhZ2Ugc2l6ZWApO1xyXG5cclxuICAgICAgICB0aGlzLmlzTG9hZGluZ01vcmUgPSBmYWxzZTtcclxuXHJcbiAgICAgICAgaWYgKHRoaXMubmV4dE1lc3NhZ2VzLmxlbmd0aCA+IDApIHtcclxuICAgICAgICAgICAgY29uc3Qgc3RvcmVkTWVzc2FnZXMgPSB0aGlzLm5leHRNZXNzYWdlcy5zcGxpY2UoMCwgbmV4dFBhZ2VTaXplKTtcclxuICAgICAgICAgICAgdGhpcy5tZXNzYWdlcyA9IFsgLi4udGhpcy5tZXNzYWdlcywgLi4uc3RvcmVkTWVzc2FnZXMgXTtcclxuICAgICAgICAgICAgbmV4dFBhZ2VTaXplIC09IHN0b3JlZE1lc3NhZ2VzLmxlbmd0aDtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGNvbnN0IGxhc3RNZXNzYWdlID0gdGhpcy5vbGRlck1lc3NhZ2VzW3RoaXMub2xkZXJNZXNzYWdlcy5sZW5ndGggLSAxXSA/PyB0aGlzLm1lc3NhZ2VzW3RoaXMubWVzc2FnZXMubGVuZ3RoIC0gMV07XHJcblxyXG4gICAgICAgIGlmIChuZXh0UGFnZVNpemUgPiAwICYmICF0aGlzLm5ld2VzdExhc3QgJiYgbGFzdE1lc3NhZ2UpIHtcclxuICAgICAgICAgICAgLy8gTG9hZCBtb3JlIGZyb20gYmFja2VuZFxyXG5cclxuICAgICAgICAgICAgdGhpcy5pc0xvYWRpbmdNb3JlID0gdHJ1ZTtcclxuXHJcbiAgICAgICAgICAgIGxldCBtZXNzYWdlcyA9IGF3YWl0IHRoaXMuc291cmNlLmxvYWRBZnRlcihsYXN0TWVzc2FnZSwgbmV4dFBhZ2VTaXplKTtcclxuICAgICAgICAgICAgbWVzc2FnZXMuZm9yRWFjaChtID0+IG0udHJhbnNpZW50U3RhdGUgPz89IHt9KTtcclxuICAgICAgICAgICAgdGhpcy5tZXNzYWdlcyA9IFsgLi4udGhpcy5tZXNzYWdlcywgLi4ubWVzc2FnZXMgXTtcclxuXHJcbiAgICAgICAgICAgIC8vIElmIHdlIGRpZG4ndCByZWNlaXZlIGFueSBtZXNzYWdlcyBhdCBhbGwsIHRoZXJlJ3Mgbm8gbW9yZSB0byBmZXRjaC5cclxuXHJcbiAgICAgICAgICAgIGlmIChtZXNzYWdlcy5sZW5ndGggPT09IDApXHJcbiAgICAgICAgICAgICAgICB0aGlzLmhhc01vcmUgPSBmYWxzZTtcclxuXHJcbiAgICAgICAgICAgIHRoaXMuaXNMb2FkaW5nTW9yZSA9IGZhbHNlO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gRXh0cmFjdCB0aGUgbWVzc2FnZXMgdGhhdCBkbyBub3QgZml0IGluIHRoZSBtYXhWaXNpYmxlTWVzc2FnZXMgYnVmZmVyLlxyXG5cclxuXHJcbiAgICAgICAgaWYgKHRoaXMubWVzc2FnZXMubGVuZ3RoID4gdGhpcy5tYXhWaXNpYmxlTWVzc2FnZXMpIHtcclxuICAgICAgICAgICAgbGV0IG92ZXJmbG93ID0gdGhpcy5tZXNzYWdlcy5zcGxpY2UoMCwgdGhpcy5tZXNzYWdlcy5sZW5ndGggLSB0aGlzLm1heFZpc2libGVNZXNzYWdlcyk7XHJcblxyXG4gICAgICAgICAgICAvLyBSZWdhcmRsZXNzIG9mIHRoZSBvcmRlciAobmV3ZXN0TGFzdCksIG5ld01lc3NhZ2VzIHJlcHJlc2VudHMgdGhlIGRpcmVjdGlvbiB0aGF0IGlzIGJlaW5nIHB1c2hlZCwgc2luY2UgaXQncyBkZWZpbml0aW9uXHJcbiAgICAgICAgICAgIC8vIGRlcGVuZHMgb24gdGhhdCBvcmRlci4gTW92ZSBvdmVyZmxvd2luZyBtZXNzYWdlcyBpbnRvIG5ld01lc3NhZ2VzLlxyXG5cclxuICAgICAgICAgICAgdGhpcy5wcmV2aW91c01lc3NhZ2VzLnB1c2goLi4ub3ZlcmZsb3cpO1xyXG4gICAgICAgICAgICBpZiAodGhpcy5wcmV2aW91c01lc3NhZ2VzLmxlbmd0aCA+IHRoaXMubWF4TWVzc2FnZXMpXHJcbiAgICAgICAgICAgICAgICB0aGlzLnByZXZpb3VzTWVzc2FnZXMuc3BsaWNlKDAsIHRoaXMucHJldmlvdXNNZXNzYWdlcy5sZW5ndGggLSB0aGlzLm1heE1lc3NhZ2VzKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHRoaXMuZGVidWdNZXNzYWdlcygpO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogU2hvdyBtb3JlIGNvbnRlbnRcclxuICAgICAqIC0gV2hlbiBpbiByZXBsaWVzIG1vZGUgKG5ld2VzdExhc3QpLCB0aGUgY29udGVudCBpcyBhZGRlZCBhdCB0aGUgdG9wXHJcbiAgICAgKiAtIFdoZW4gaW4gbm9ybWFsIG1vZGUsIHRoZSBjb250ZW50IGlzIGFkZGVkIGF0IHRoZSBib3R0b21cclxuICAgICAqIC0gVGhlIGN1cnJlbnQgc29ydCBvcmRlciBkb2VzICpub3QqIGZhY3RvciBpbiBoZXJlLCB3aGljaCBpcyB3aHkgaXQgaXMgc2hvd01vcmUoKSBub3Qgc2hvd0VhcmxpZXIoKS5cclxuICAgICAqXHJcbiAgICAgKiBAcmV0dXJuc1xyXG4gICAgICovXHJcbiAgICBhc3luYyBzaG93TW9yZSgpIHtcclxuICAgICAgICB0aGlzLmlzVmlld2luZ01vcmUgPSB0cnVlO1xyXG5cclxuICAgICAgICBsZXQgbmV4dFBhZ2VTaXplID0gdGhpcy5wYWdlU2l6ZTtcclxuXHJcbiAgICAgICAgaWYgKGlzTmFOKG5leHRQYWdlU2l6ZSkpXHJcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgTm90IHNhZmUgdG8gbG9hZCBtb3JlIHdpdGggTmFOIHBhZ2Ugc2l6ZWApO1xyXG5cclxuICAgICAgICB0aGlzLmlzTG9hZGluZ01vcmUgPSBmYWxzZTtcclxuXHJcbiAgICAgICAgaWYgKHRoaXMub2xkZXJNZXNzYWdlcy5sZW5ndGggPiAwKSB7XHJcbiAgICAgICAgICAgIGNvbnN0IHN0b3JlZE1lc3NhZ2VzID0gdGhpcy5vbGRlck1lc3NhZ2VzLnNwbGljZSgwLCBuZXh0UGFnZVNpemUpO1xyXG4gICAgICAgICAgICB0aGlzLm1lc3NhZ2VzID0gdGhpcy5tZXNzYWdlcy5jb25jYXQoc3RvcmVkTWVzc2FnZXMpO1xyXG4gICAgICAgICAgICBuZXh0UGFnZVNpemUgLT0gc3RvcmVkTWVzc2FnZXMubGVuZ3RoO1xyXG4gICAgICAgICAgICB0aGlzLmhhc01vcmUgPSB0aGlzLm9sZGVyTWVzc2FnZXMubGVuZ3RoID4gMDtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGxldCBsYXN0TWVzc2FnZTogQ2hhdE1lc3NhZ2U7XHJcblxyXG4gICAgICAgIGlmICh0aGlzLm5ld2VzdExhc3QpIHtcclxuICAgICAgICAgICAgbGFzdE1lc3NhZ2UgPSB0aGlzLm9sZGVyTWVzc2FnZXNbMF0gPz8gdGhpcy5tZXNzYWdlc1swXTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICBsYXN0TWVzc2FnZSA9IHRoaXMub2xkZXJNZXNzYWdlc1t0aGlzLm9sZGVyTWVzc2FnZXMubGVuZ3RoIC0gMV0gPz8gdGhpcy5tZXNzYWdlc1t0aGlzLm1lc3NhZ2VzLmxlbmd0aCAtIDFdO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgaWYgKG5leHRQYWdlU2l6ZSA+IDAgJiYgbGFzdE1lc3NhZ2UpIHtcclxuICAgICAgICAgICAgLy8gTG9hZCBtb3JlIGZyb20gYmFja2VuZFxyXG5cclxuICAgICAgICAgICAgdGhpcy5pc0xvYWRpbmdNb3JlID0gdHJ1ZTtcclxuXHJcblxyXG4gICAgICAgICAgICBpZiAoIWxhc3RNZXNzYWdlKSB7XHJcbiAgICAgICAgICAgICAgICB0aGlzLmlzTG9hZGluZ01vcmUgPSBmYWxzZTtcclxuICAgICAgICAgICAgICAgIHRoaXMuaGFzTW9yZSA9IGZhbHNlO1xyXG4gICAgICAgICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICBsZXQgbWVzc2FnZXMgPSBhd2FpdCB0aGlzLnNvdXJjZS5sb2FkQWZ0ZXIobGFzdE1lc3NhZ2UsIG5leHRQYWdlU2l6ZSk7XHJcblxyXG4gICAgICAgICAgICBpZiAodGhpcy5uZXdlc3RMYXN0KVxyXG4gICAgICAgICAgICAgICAgbWVzc2FnZXMgPSBtZXNzYWdlcy5zbGljZSgpLnJldmVyc2UoKTtcclxuXHJcbiAgICAgICAgICAgIG1lc3NhZ2VzLmZvckVhY2gobSA9PiBtLnRyYW5zaWVudFN0YXRlID8/PSB7fSk7XHJcblxyXG4gICAgICAgICAgICAvLyBJbiByZXBsaWVzIG1vZGUgKG5ld2VzdExhc3QpLCB3ZSB3YW50IHRvIHB1dCB0aGVzZSBuZXcgbWVzc2FnZXMgb250byB0aGUgKnRvcCogb2YgdGhlIHNldCBvZiB2aXNpYmxlIG1lc3NhZ2VzLlxyXG4gICAgICAgICAgICAvLyBPdGhlcndpc2Ugd2Ugd2FudCB0byBwdXQgdGhlbSBvbiB0aGUgKmJvdHRvbSouXHJcblxyXG4gICAgICAgICAgICBpZiAodGhpcy5uZXdlc3RMYXN0KSB7XHJcbiAgICAgICAgICAgICAgICB0aGlzLm1lc3NhZ2VzID0gbWVzc2FnZXMuY29uY2F0KHRoaXMubWVzc2FnZXMpO1xyXG4gICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgdGhpcy5tZXNzYWdlcyA9IHRoaXMubWVzc2FnZXMuY29uY2F0KG1lc3NhZ2VzKTtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgLy8gSWYgd2UgZGlkbid0IHJlY2VpdmUgYW55IG1lc3NhZ2VzIGF0IGFsbCwgdGhlcmUncyBubyBtb3JlIHRvIGZldGNoLlxyXG5cclxuICAgICAgICAgICAgaWYgKG1lc3NhZ2VzLmxlbmd0aCA9PT0gMCkge1xyXG4gICAgICAgICAgICAgICAgdGhpcy5oYXNNb3JlID0gZmFsc2U7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIHRoaXMuaXNMb2FkaW5nTW9yZSA9IGZhbHNlO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gRXh0cmFjdCB0aGUgbWVzc2FnZXMgdGhhdCBkbyBub3QgZml0IGluIHRoZSBtYXhWaXNpYmxlTWVzc2FnZXMgYnVmZmVyLlxyXG5cclxuICAgICAgICBpZiAodGhpcy5tZXNzYWdlcy5sZW5ndGggPiB0aGlzLm1heFZpc2libGVNZXNzYWdlcykge1xyXG4gICAgICAgICAgICBsZXQgb3ZlcmZsb3c6IENoYXRNZXNzYWdlW10gPSBbXTtcclxuXHJcbiAgICAgICAgICAgIC8vIE1vdmUgb3ZlcmZsb3dpbmcgbWVzc2FnZXMgaW50byBuZXdNZXNzYWdlcy5cclxuICAgICAgICAgICAgLy8gUmVnYXJkbGVzcyBvZiB0aGUgb3JkZXIgKG5ld2VzdExhc3QpLCBuZXdNZXNzYWdlcyByZXByZXNlbnRzIHRoZSBkaXJlY3Rpb24gdGhhdCBpcyBiZWluZyBsb2FkZWQsXHJcbiAgICAgICAgICAgIC8vIHNpbmNlIGl0J3MgZGVmaW5pdGlvbiBkZXBlbmRzIG9uIHRoYXQgb3JkZXIuXHJcblxyXG4gICAgICAgICAgICBpZiAodGhpcy5uZXdlc3RMYXN0KSB7XHJcbiAgICAgICAgICAgICAgICBvdmVyZmxvdyA9IHRoaXMubWVzc2FnZXMuc3BsaWNlKHRoaXMubWF4VmlzaWJsZU1lc3NhZ2VzLCB0aGlzLm1lc3NhZ2VzLmxlbmd0aCk7XHJcbiAgICAgICAgICAgICAgICB0aGlzLm5ld01lc3NhZ2VzID0gb3ZlcmZsb3cuY29uY2F0KHRoaXMubmV3TWVzc2FnZXMpO1xyXG4gICAgICAgICAgICAgICAgdGhpcy5uZXdNZXNzYWdlcy5zcGxpY2UodGhpcy5tYXhNZXNzYWdlcyAtIHRoaXMubWF4VmlzaWJsZU1lc3NhZ2VzLCB0aGlzLm5ld01lc3NhZ2VzLmxlbmd0aCk7XHJcbiAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgICBvdmVyZmxvdyA9IHRoaXMubWVzc2FnZXMuc3BsaWNlKDAsIHRoaXMubWVzc2FnZXMubGVuZ3RoIC0gdGhpcy5tYXhWaXNpYmxlTWVzc2FnZXMpO1xyXG4gICAgICAgICAgICAgICAgdGhpcy5uZXdNZXNzYWdlcy5wdXNoKC4uLm92ZXJmbG93KTtcclxuICAgICAgICAgICAgICAgIGlmICh0aGlzLm5ld01lc3NhZ2VzLmxlbmd0aCA+IHRoaXMubWF4TWVzc2FnZXMgLSB0aGlzLm1heFZpc2libGVNZXNzYWdlcylcclxuICAgICAgICAgICAgICAgICAgICB0aGlzLm5ld01lc3NhZ2VzLnNwbGljZSgwLCB0aGlzLm5ld01lc3NhZ2VzLmxlbmd0aCAtICh0aGlzLm1heE1lc3NhZ2VzIC0gdGhpcy5tYXhWaXNpYmxlTWVzc2FnZXMpKTtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgcHJpdmF0ZSBoZWxkTWVzc2FnZXM6IENoYXRNZXNzYWdlW10gPSBbXTtcclxuXHJcbiAgICBwcml2YXRlIGFkZE1lc3NhZ2UobWVzc2FnZTogQ2hhdE1lc3NhZ2UpIHtcclxuXHJcbiAgICAgICAgaWYgKCFtZXNzYWdlLnRyYW5zaWVudFN0YXRlKVxyXG4gICAgICAgICAgICBtZXNzYWdlLnRyYW5zaWVudFN0YXRlID8/PSB7fTtcclxuXHJcbiAgICAgICAgbGV0IGRlc3RpbmF0aW9uID0gdGhpcy5tZXNzYWdlcztcclxuICAgICAgICBsZXQgYnVja2V0ID0gdGhpcy5vbGRlck1lc3NhZ2VzO1xyXG4gICAgICAgIGxldCBuZXdlc3RMYXN0ID0gdGhpcy5uZXdlc3RMYXN0O1xyXG5cclxuICAgICAgICBpZiAodGhpcy5zaG91bGRIb2xkTmV3TWVzc2FnZXMpIHtcclxuICAgICAgICAgICAgdGhpcy5oZWxkTWVzc2FnZXMucHVzaChtZXNzYWdlKTtcclxuICAgICAgICAgICAgZGVzdGluYXRpb24gPSB0aGlzLm5ld01lc3NhZ2VzO1xyXG4gICAgICAgICAgICBidWNrZXQgPSBudWxsO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gSWYgd2UgYXJlbid0IG9uIHRoZSBuZXdlc3Qgc29ydCBvcmRlciwgbmV3IG1lc3NhZ2VzIHNob3VsZG4ndCBiZSBhZGRlZCBhdCBhbGxcclxuICAgICAgICBpZiAodGhpcy5zb3VyY2VTb3J0T3JkZXIgIT09IENvbW1lbnRzT3JkZXIuTkVXRVNUKVxyXG4gICAgICAgICAgICByZXR1cm47XHJcblxyXG5cclxuICAgICAgICBpZiAobmV3ZXN0TGFzdCkge1xyXG4gICAgICAgICAgICBkZXN0aW5hdGlvbi5wdXNoKG1lc3NhZ2UpO1xyXG5cclxuICAgICAgICAgICAgaWYgKHRoaXMubWF4VmlzaWJsZU1lc3NhZ2VzID4gMCkge1xyXG4gICAgICAgICAgICAgICAgbGV0IG92ZXJmbG93ID0gZGVzdGluYXRpb24uc3BsaWNlKHRoaXMubWF4VmlzaWJsZU1lc3NhZ2VzLCBkZXN0aW5hdGlvbi5sZW5ndGgpO1xyXG4gICAgICAgICAgICAgICAgYnVja2V0Py5wdXNoKC4uLm92ZXJmbG93KTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIGRlc3RpbmF0aW9uLnVuc2hpZnQobWVzc2FnZSk7XHJcblxyXG4gICAgICAgICAgICBpZiAodGhpcy5tYXhWaXNpYmxlTWVzc2FnZXMgPiAwKSB7XHJcbiAgICAgICAgICAgICAgICBsZXQgb3ZlcmZsb3cgPSBkZXN0aW5hdGlvbi5zcGxpY2UodGhpcy5tYXhWaXNpYmxlTWVzc2FnZXMsIGRlc3RpbmF0aW9uLmxlbmd0aCk7XHJcbiAgICAgICAgICAgICAgICBidWNrZXQ/LnVuc2hpZnQoLi4ub3ZlcmZsb3cpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBpZiAoYnVja2V0Py5sZW5ndGggPiAwKVxyXG4gICAgICAgICAgICB0aGlzLmhhc01vcmUgPSB0cnVlO1xyXG5cclxuICAgICAgICBtZXNzYWdlLnBhZ2luZ0N1cnNvciA9IFN0cmluZyh0aGlzLmluY3JlbWVudFBhZ2luZ0N1cnNvcnMoKSk7XHJcbiAgICAgICAgdGhpcy5zb3J0TWVzc2FnZXMoKTtcclxuICAgIH1cclxuXHJcbiAgICBwcml2YXRlIGluY3JlbWVudFBhZ2luZ0N1cnNvcnMoKSB7XHJcbiAgICAgICAgaWYgKHRoaXMuc291cmNlLnNvcnRPcmRlciAhPT0gQ29tbWVudHNPcmRlci5ORVdFU1QpXHJcbiAgICAgICAgICAgIHJldHVybjtcclxuXHJcbiAgICAgICAgbGV0IG1heFBhZ2luZ0N1cnNvciA9IDA7XHJcbiAgICAgICAgZm9yIChsZXQgZ3JvdXAgb2YgW3RoaXMubWVzc2FnZXMsIHRoaXMub2xkZXJNZXNzYWdlcywgdGhpcy5uZXdNZXNzYWdlc10pIHtcclxuICAgICAgICAgICAgZm9yIChsZXQgbWVzc2FnZSBvZiBncm91cCkge1xyXG4gICAgICAgICAgICAgICAgaWYgKG1lc3NhZ2UucGFnaW5nQ3Vyc29yKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgbGV0IHBhZ2luZ0N1cnNvciA9IE51bWJlcihtZXNzYWdlLnBhZ2luZ0N1cnNvcikgKyAxO1xyXG4gICAgICAgICAgICAgICAgICAgIGlmIChwYWdpbmdDdXJzb3IgPiBtYXhQYWdpbmdDdXJzb3IpXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIG1heFBhZ2luZ0N1cnNvciA9IHBhZ2luZ0N1cnNvcjtcclxuICAgICAgICAgICAgICAgICAgICBtZXNzYWdlLnBhZ2luZ0N1cnNvciA9IFN0cmluZyhwYWdpbmdDdXJzb3IpO1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICByZXR1cm4gbWF4UGFnaW5nQ3Vyc29yO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogV2FpdCBmb3IgYWxsIGN1cnJlbnRseSB2aXNpYmxlIGNvbW1lbnRzIHRvIGJlIGZ1bGx5IGxvYWRlZCwgaW5jbHVkaW5nIGFsbCBhdHRhY2htZW50cy5cclxuICAgICAqIERvaW5nIHRoaXMgd2lsbCBwcmV2ZW50IGxheW91dCBzaGlmdCB3aGVuIHNjcm9sbGluZyB0byBhIHNwZWNpZmljIGNvbW1lbnQuXHJcbiAgICAgKi9cclxuICAgIGFzeW5jIHdhaXRGb3JBbGxDb21tZW50c1RvTG9hZCgpIHtcclxuICAgICAgICBhd2FpdCBuZXcgUHJvbWlzZShyID0+IHNldFRpbWVvdXQociwgMTAwKSk7XHJcbiAgICAgICAgYXdhaXQgdGhpcy5zb3VyY2VMb2FkZWQ7XHJcbiAgICAgICAgYXdhaXQgUHJvbWlzZS5hbGwodGhpcy5jb21tZW50cy5tYXAoeCA9PiB4LndhaXRGb3JMb2FkKCkpKTtcclxuICAgIH1cclxuXHJcbiAgICBwcml2YXRlIHNvcnRNZXNzYWdlcygpIHtcclxuICAgICAgICBpZiAoIXRoaXMuc291cmNlKVxyXG4gICAgICAgICAgICByZXR1cm47XHJcblxyXG4gICAgICAgIGxldCBzb3J0ZXI6IChhOiBDaGF0TWVzc2FnZSwgYjogQ2hhdE1lc3NhZ2UpID0+IG51bWJlcjtcclxuXHJcbiAgICAgICAgaWYgKHRoaXMuc291cmNlLnNvcnRPcmRlciA9PT0gQ29tbWVudHNPcmRlci5MSUtFUylcclxuICAgICAgICAgICAgc29ydGVyID0gKGEsIGIpID0+IGIubGlrZXMgLSBhLmxpa2VzO1xyXG4gICAgICAgIGVsc2UgaWYgKHRoaXMuc291cmNlLnNvcnRPcmRlciA9PT0gQ29tbWVudHNPcmRlci5ORVdFU1QpXHJcbiAgICAgICAgICAgIHNvcnRlciA9IChhLCBiKSA9PiAoYi5zZW50QXQgLSBhLnNlbnRBdCkgKiAodGhpcy5uZXdlc3RMYXN0ID8gLTEgOiAxKTtcclxuICAgICAgICBlbHNlIGlmICh0aGlzLnNvdXJjZS5zb3J0T3JkZXIgPT09IENvbW1lbnRzT3JkZXIuT0xERVNUKVxyXG4gICAgICAgICAgICBzb3J0ZXIgPSAoYSwgYikgPT4gKGEuc2VudEF0IC0gYi5zZW50QXQpICogKHRoaXMubmV3ZXN0TGFzdCA/IC0xIDogMSk7XHJcblxyXG4gICAgICAgIHRoaXMubWVzc2FnZXMuc29ydChzb3J0ZXIpO1xyXG4gICAgICAgIHRoaXMub2xkZXJNZXNzYWdlcy5zb3J0KHNvcnRlcik7XHJcbiAgICAgICAgdGhpcy5uZXdNZXNzYWdlcy5zb3J0KHNvcnRlcik7XHJcbiAgICB9XHJcblxyXG4gICAgcHJpdmF0ZSBtZXNzYWdlUmVjZWl2ZWQobWVzc2FnZTogQ2hhdE1lc3NhZ2UpIHtcclxuICAgICAgICB0aGlzLmFkZE1lc3NhZ2UobWVzc2FnZSk7XHJcbiAgICB9XHJcblxyXG4gICAgaXNTY3JvbGxlZFRvTGF0ZXN0KCkge1xyXG4gICAgICAgIGlmICghdGhpcy5tZXNzYWdlQ29udGFpbmVyKVxyXG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XHJcblxyXG4gICAgICAgIGNvbnN0IGVsID0gdGhpcy5tZXNzYWdlQ29udGFpbmVyLm5hdGl2ZUVsZW1lbnQ7XHJcbiAgICAgICAgY29uc3QgY3VycmVudFNjcm9sbCA9IGVsLnNjcm9sbFRvcDtcclxuICAgICAgICBjb25zdCBjdXJyZW50VG90YWwgPSBlbC5zY3JvbGxIZWlnaHQgLSBlbC5vZmZzZXRIZWlnaHQ7XHJcblxyXG4gICAgICAgIHJldHVybiBjdXJyZW50U2Nyb2xsID4gY3VycmVudFRvdGFsIC0gMTA7XHJcbiAgICB9XHJcblxyXG4gICAgcHJpdmF0ZSBtZXNzYWdlU2VudChtZXNzYWdlOiBDaGF0TWVzc2FnZSkge1xyXG4gICAgICAgIHRoaXMuYWRkTWVzc2FnZShtZXNzYWdlKTtcclxuXHJcbiAgICAgICAgaWYgKCF0aGlzLm1lc3NhZ2VDb250YWluZXIpXHJcbiAgICAgICAgICAgIHJldHVybjtcclxuXHJcbiAgICAgICAgdGhpcy5zY3JvbGxUb0xhdGVzdCgpO1xyXG4gICAgfVxyXG5cclxuICAgIHByaXZhdGUgaXNQaW5uZWQobWVzc2FnZTogQ2hhdE1lc3NhZ2UpIHtcclxuICAgICAgICByZXR1cm4gbWVzc2FnZS5waW5uZWQgJiYgKCFtZXNzYWdlLnBpbm5lZFVudGlsIHx8IG1lc3NhZ2UucGlubmVkVW50aWwgPiBEYXRlLm5vdygpKTtcclxuICAgIH1cclxuXHJcbiAgICBwcml2YXRlIG1lc3NhZ2VVcGRhdGVkKG1lc3NhZ2U6IENoYXRNZXNzYWdlKSB7XHJcbiAgICAgICAgbGV0IHBpbm5lZCA9IHRoaXMuaXNQaW5uZWQobWVzc2FnZSk7XHJcbiAgICAgICAgbGV0IGluUGlucyA9IHRoaXMucGlubmVkTWVzc2FnZXMuc29tZSh4ID0+IHguaWQgPT09IG1lc3NhZ2UuaWQpO1xyXG5cclxuICAgICAgICBpZiAocGlubmVkICYmICFpblBpbnMpIHtcclxuICAgICAgICAgICAgdGhpcy5waW5uZWRNZXNzYWdlcy51bnNoaWZ0KG1lc3NhZ2UpO1xyXG4gICAgICAgICAgICBsZXQgaW5kZXggPSB0aGlzLm1lc3NhZ2VzLmluZGV4T2YobWVzc2FnZSk7XHJcbiAgICAgICAgICAgIGlmIChpbmRleCA+PSAwKSB7XHJcbiAgICAgICAgICAgICAgICB0aGlzLm1lc3NhZ2VzLnNwbGljZShpbmRleCwgMSk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9IGVsc2UgaWYgKCFwaW5uZWQgJiYgaW5QaW5zKSB7XHJcbiAgICAgICAgICAgIHRoaXMubWVzc2FnZXMucHVzaChtZXNzYWdlKTtcclxuICAgICAgICAgICAgbGV0IGluZGV4ID0gdGhpcy5waW5uZWRNZXNzYWdlcy5pbmRleE9mKG1lc3NhZ2UpO1xyXG4gICAgICAgICAgICBpZiAoaW5kZXggPj0gMCkge1xyXG4gICAgICAgICAgICAgICAgdGhpcy5waW5uZWRNZXNzYWdlcy5zcGxpY2UoaW5kZXgsIDEpO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICB0aGlzLnNvcnRNZXNzYWdlcygpO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBzY3JvbGxUb0xhdGVzdCgpIHtcclxuICAgICAgICBpZiAoIXRoaXMubWVzc2FnZUNvbnRhaW5lcikge1xyXG4gICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBjb25zdCBlbCA9IHRoaXMubWVzc2FnZUNvbnRhaW5lci5uYXRpdmVFbGVtZW50O1xyXG5cclxuICAgICAgICBlbC5zY3JvbGxJbnRvVmlldyh7IGJsb2NrOiAnc3RhcnQnIH0pO1xyXG4gICAgICAgIC8vZWwuc2Nyb2xsVG9wID0gZWwuc2Nyb2xsSGVpZ2h0O1xyXG4gICAgfVxyXG5cclxuICAgIGdldCBlbGVtZW50KCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLmVsZW1lbnRSZWYubmF0aXZlRWxlbWVudDtcclxuICAgIH1cclxuXHJcbiAgICBhc3luYyBzY3JvbGxUb0NvbW1lbnQoY29tbWVudElkOiBDaGF0TWVzc2FnZVsnaWQnXSkge1xyXG4gICAgICAgIGlmICh0eXBlb2Ygd2luZG93ID09PSAndW5kZWZpbmVkJylcclxuICAgICAgICAgICAgcmV0dXJuO1xyXG5cclxuICAgICAgICBhd2FpdCB0aGlzLndhaXRGb3JBbGxDb21tZW50c1RvTG9hZCgpO1xyXG5cclxuICAgICAgICBjb25zdCBjb21tZW50ID0gdGhpcy5nZXRFbGVtZW50Rm9yQ29tbWVudChjb21tZW50SWQpO1xyXG4gICAgICAgIGlmIChjb21tZW50KSB7XHJcbiAgICAgICAgICAgIGNvbW1lbnQuc2Nyb2xsSW50b1ZpZXcoe1xyXG4gICAgICAgICAgICAgICAgaW5saW5lOiAnY2VudGVyJyxcclxuICAgICAgICAgICAgICAgIGJsb2NrOiAnY2VudGVyJ1xyXG4gICAgICAgICAgICB9KTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgZ2V0RWxlbWVudEZvckNvbW1lbnQoY29tbWVudElkOiBzdHJpbmcpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5lbGVtZW50LnF1ZXJ5U2VsZWN0b3IoYFtkYXRhLWNvbW1lbnQtaWQ9XCIke2NvbW1lbnRJZH1cIl1gKTtcclxuICAgIH1cclxuXHJcbiAgICBtZW50aW9uc01lKG1lc3NhZ2U6IENoYXRNZXNzYWdlKSB7XHJcbiAgICAgICAgaWYgKCF0aGlzLmN1cnJlbnRVc2VyKVxyXG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XHJcblxyXG4gICAgICAgIGlmIChtZXNzYWdlLm1lc3NhZ2UuaW5jbHVkZXMoYEAke3RoaXMuY3VycmVudFVzZXIudXNlcm5hbWV9YCkpXHJcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xyXG5cclxuICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICB9XHJcbn1cclxuIiwiPGRpdiBjbGFzcz1cImJhbnRhLW1lc3NhZ2UtY29udGFpbmVyXCIgI21lc3NhZ2VDb250YWluZXI+XHJcbiAgICA8bmctY29udGVudCBzZWxlY3Q9XCJbZGF0YS1iZWZvcmVdXCI+PC9uZy1jb250ZW50PlxyXG5cclxuICAgIEBpZiAoIWNvbGxhcHNlUGlucykge1xyXG4gICAgICAgIEBmb3IgKG1lc3NhZ2Ugb2YgcGlubmVkTWVzc2FnZXM7IHRyYWNrIG1lc3NhZ2UuaWQpIHtcclxuICAgICAgICAgICAgQGlmICghbWVzc2FnZS5oaWRkZW4pIHtcclxuICAgICAgICAgICAgICAgIDxiYW50YS1jb21tZW50XHJcbiAgICAgICAgICAgICAgICAgICAgY2xhc3M9XCJhYmJyZXZpYXRlZFwiXHJcbiAgICAgICAgICAgICAgICAgICAgW2N1c3RvbU1lbnVJdGVtc109XCJjdXN0b21NZW51SXRlbXNcIlxyXG4gICAgICAgICAgICAgICAgICAgIFttZXNzYWdlXT1cIm1lc3NhZ2VcIlxyXG4gICAgICAgICAgICAgICAgICAgIFttaW5lXT1cImN1cnJlbnRVc2VyPy5pZCA9PT0gbWVzc2FnZS51c2VyPy5pZFwiXHJcbiAgICAgICAgICAgICAgICAgICAgW3Blcm1pc3Npb25zXT1cInNvdXJjZT8ucGVybWlzc2lvbnNcIlxyXG4gICAgICAgICAgICAgICAgICAgIFtzaG93UmVwbHlBY3Rpb25dPVwiYWxsb3dSZXBsaWVzXCJcclxuICAgICAgICAgICAgICAgICAgICBbZWRpdGluZ109XCJtZXNzYWdlLnRyYW5zaWVudFN0YXRlLmVkaXRpbmdcIlxyXG4gICAgICAgICAgICAgICAgICAgIFtnZW5lcmljQXZhdGFyVXJsXT1cImdlbmVyaWNBdmF0YXJVcmxcIlxyXG4gICAgICAgICAgICAgICAgICAgIFtyZWFkb25seV09XCJzb3VyY2U/LnJlYWRvbmx5XCJcclxuICAgICAgICAgICAgICAgICAgICAoY2xpY2spPVwibWVzc2FnZUNsaWNrZWQgPSB0cnVlXCJcclxuICAgICAgICAgICAgICAgICAgICAoZWRpdFN0YXJ0ZWQpPVwic3RhcnRFZGl0aW5nKG1lc3NhZ2UpXCJcclxuICAgICAgICAgICAgICAgICAgICAoZGVsZXRlZCk9XCJkZWxldGVNZXNzYWdlKG1lc3NhZ2UpXCJcclxuICAgICAgICAgICAgICAgICAgICAoZWRpdEVuZGVkKT1cIm1lc3NhZ2UudHJhbnNpZW50U3RhdGUuZWRpdGluZyA9IGZhbHNlXCJcclxuICAgICAgICAgICAgICAgICAgICAoZWRpdGVkKT1cInNhdmVFZGl0KG1lc3NhZ2UsICRldmVudClcIlxyXG4gICAgICAgICAgICAgICAgICAgICh1c2VyU2VsZWN0ZWQpPVwic2VsZWN0TWVzc2FnZVVzZXIobWVzc2FnZSlcIlxyXG4gICAgICAgICAgICAgICAgICAgIChhdmF0YXJTZWxlY3RlZCk9XCJzZWxlY3RBdmF0YXIoJGV2ZW50KVwiXHJcbiAgICAgICAgICAgICAgICAgICAgKHVzZXJuYW1lU2VsZWN0ZWQpPVwic2VsZWN0VXNlcm5hbWUoJGV2ZW50KVwiXHJcbiAgICAgICAgICAgICAgICAgICAgKGxpa2VkKT1cImxpa2VNZXNzYWdlKG1lc3NhZ2UpXCJcclxuICAgICAgICAgICAgICAgICAgICAocGlubmVkKT1cInBpbk1lc3NhZ2UobWVzc2FnZSwgJGV2ZW50Lm9wdGlvbnMpXCJcclxuICAgICAgICAgICAgICAgICAgICAodW5waW5uZWQpPVwidW5waW5NZXNzYWdlKG1lc3NhZ2UpXCJcclxuICAgICAgICAgICAgICAgICAgICAodW5saWtlZCk9XCJ1bmxpa2VNZXNzYWdlKG1lc3NhZ2UpXCJcclxuICAgICAgICAgICAgICAgICAgICAocmVwb3J0ZWQpPVwicmVwb3J0TWVzc2FnZShtZXNzYWdlKVwiXHJcbiAgICAgICAgICAgICAgICAgICAgKHNlbGVjdGVkKT1cInNlbGVjdE1lc3NhZ2UobWVzc2FnZSlcIlxyXG4gICAgICAgICAgICAgICAgICAgIChzaGFyZWQpPVwic2hhcmVkTWVzc2FnZSgkZXZlbnQpXCJcclxuICAgICAgICAgICAgICAgICAgICAvPlxyXG4gICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImJhbnRhLWlubGluZS1yZXBsaWVzLWNvbnRhaW5lclwiICpuZ0lmPVwic2VsZWN0ZWRNZXNzYWdlID09PSBtZXNzYWdlXCI+XHJcbiAgICAgICAgICAgICAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdUZW1wbGF0ZU91dGxldD1cImlubGluZVJlcGxpZXNUZW1wbGF0ZVwiIC8+XHJcbiAgICAgICAgICAgICAgICA8L2Rpdj5cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICA8ZGl2IGNsYXNzPVwiYmFudGEtdG9wLXN0aWNreVwiPlxyXG4gICAgICAgIEBpZiAoIW5ld2VzdExhc3QpIHtcclxuICAgICAgICAgICAgPGJ1dHRvblxyXG4gICAgICAgICAgICAgICAgbWF0LWJ1dHRvblxyXG4gICAgICAgICAgICAgICAgY2xhc3M9XCJiYW50YS1uYXZcIlxyXG4gICAgICAgICAgICAgICAgW2NsYXNzLnZpc2libGVdPVwic2hvdWxkU2hvd05ld01lc3NhZ2VJbmRpY2F0b3JcIlxyXG4gICAgICAgICAgICAgICAgaHJlZj1cImphdmFzY3JpcHQ6O1wiXHJcbiAgICAgICAgICAgICAgICAoY2xpY2spPVwic2hvd05ld2VzdCgkZXZlbnQpXCJcclxuICAgICAgICAgICAgICAgID5cclxuICAgICAgICAgICAgICAgIDxtYXQtaWNvbj5maWxlX3VwbG9hZDwvbWF0LWljb24+XHJcbiAgICAgICAgICAgICAgICBOZXdlc3RcclxuICAgICAgICAgICAgICAgIEBpZiAoaGVsZE1lc3NhZ2VzLmxlbmd0aCA+IDApIHtcclxuICAgICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cImNvdW50XCI+e3sgaGVsZE1lc3NhZ2VzLmxlbmd0aCB8IG51bWJlciB9fTwvc3Bhbj5cclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgPC9idXR0b24+XHJcbiAgICAgICAgfVxyXG4gICAgPC9kaXY+XHJcblxyXG4gICAgPGJ1dHRvbiBtYXQtYnV0dG9uIGNsYXNzPVwicGFnZXJcIiAoY2xpY2spPVwic2hvd1ByZXZpb3VzKClcIiBbY2xhc3MudmlzaWJsZV09XCJzaG91bGRTaG93UHJldmlvdXNcIiBbZGlzYWJsZWRdPVwiaXNMb2FkaW5nTW9yZVwiPlxyXG4gICAgICAgIDxtYXQtaWNvbj5leHBhbmRfbGVzczwvbWF0LWljb24+XHJcbiAgICAgICAge3sgcHJldmlvdXNMYWJlbCB9fVxyXG4gICAgPC9idXR0b24+XHJcblxyXG4gICAgQGZvciAobWVzc2FnZSBvZiBtZXNzYWdlczsgdHJhY2sgbWVzc2FnZS5pZCkge1xyXG4gICAgICAgIEBpZiAoIW1lc3NhZ2UuaGlkZGVuKSB7XHJcbiAgICAgICAgICAgIDxiYW50YS1jb21tZW50XHJcbiAgICAgICAgICAgICAgICBjbGFzcz1cImFiYnJldmlhdGVkXCJcclxuICAgICAgICAgICAgICAgIFtjdXN0b21NZW51SXRlbXNdPVwiY3VzdG9tTWVudUl0ZW1zXCJcclxuICAgICAgICAgICAgICAgIFttZXNzYWdlXT1cIm1lc3NhZ2VcIlxyXG4gICAgICAgICAgICAgICAgW21pbmVdPVwiY3VycmVudFVzZXI/LmlkID09PSBtZXNzYWdlLnVzZXI/LmlkXCJcclxuICAgICAgICAgICAgICAgIFtwZXJtaXNzaW9uc109XCJzb3VyY2U/LnBlcm1pc3Npb25zXCJcclxuICAgICAgICAgICAgICAgIFtzaG93UmVwbHlBY3Rpb25dPVwiYWxsb3dSZXBsaWVzXCJcclxuICAgICAgICAgICAgICAgIFtlZGl0aW5nXT1cIm1lc3NhZ2UudHJhbnNpZW50U3RhdGUuZWRpdGluZ1wiXHJcbiAgICAgICAgICAgICAgICBbZ2VuZXJpY0F2YXRhclVybF09XCJnZW5lcmljQXZhdGFyVXJsXCJcclxuICAgICAgICAgICAgICAgIFtyZWFkb25seV09XCJzb3VyY2U/LnJlYWRvbmx5XCJcclxuICAgICAgICAgICAgICAgIChjbGljayk9XCJtZXNzYWdlQ2xpY2tlZCA9IHRydWVcIlxyXG4gICAgICAgICAgICAgICAgKGVkaXRTdGFydGVkKT1cInN0YXJ0RWRpdGluZyhtZXNzYWdlKVwiXHJcbiAgICAgICAgICAgICAgICAoZGVsZXRlZCk9XCJkZWxldGVNZXNzYWdlKG1lc3NhZ2UpXCJcclxuICAgICAgICAgICAgICAgIChlZGl0RW5kZWQpPVwibWVzc2FnZS50cmFuc2llbnRTdGF0ZS5lZGl0aW5nID0gZmFsc2VcIlxyXG4gICAgICAgICAgICAgICAgKGVkaXRlZCk9XCJzYXZlRWRpdChtZXNzYWdlLCAkZXZlbnQpXCJcclxuICAgICAgICAgICAgICAgICh1c2VyU2VsZWN0ZWQpPVwic2VsZWN0TWVzc2FnZVVzZXIobWVzc2FnZSlcIlxyXG4gICAgICAgICAgICAgICAgKGF2YXRhclNlbGVjdGVkKT1cInNlbGVjdEF2YXRhcigkZXZlbnQpXCJcclxuICAgICAgICAgICAgICAgICh1c2VybmFtZVNlbGVjdGVkKT1cInNlbGVjdFVzZXJuYW1lKCRldmVudClcIlxyXG4gICAgICAgICAgICAgICAgKGxpa2VkKT1cImxpa2VNZXNzYWdlKG1lc3NhZ2UpXCJcclxuICAgICAgICAgICAgICAgIChwaW5uZWQpPVwicGluTWVzc2FnZShtZXNzYWdlLCAkZXZlbnQub3B0aW9ucylcIlxyXG4gICAgICAgICAgICAgICAgKHVucGlubmVkKT1cInVucGluTWVzc2FnZShtZXNzYWdlKVwiXHJcbiAgICAgICAgICAgICAgICAodW5saWtlZCk9XCJ1bmxpa2VNZXNzYWdlKG1lc3NhZ2UpXCJcclxuICAgICAgICAgICAgICAgIChyZXBvcnRlZCk9XCJyZXBvcnRNZXNzYWdlKG1lc3NhZ2UpXCJcclxuICAgICAgICAgICAgICAgIChzZWxlY3RlZCk9XCJzZWxlY3RNZXNzYWdlKG1lc3NhZ2UpXCJcclxuICAgICAgICAgICAgICAgIChzaGFyZWQpPVwic2hhcmVkTWVzc2FnZSgkZXZlbnQpXCJcclxuICAgICAgICAgICAgICAgIC8+XHJcbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJiYW50YS1pbmxpbmUtcmVwbGllcy1jb250YWluZXJcIiAqbmdJZj1cInNlbGVjdGVkTWVzc2FnZSA9PT0gbWVzc2FnZVwiPlxyXG4gICAgICAgICAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdUZW1wbGF0ZU91dGxldD1cImlubGluZVJlcGxpZXNUZW1wbGF0ZVwiIC8+XHJcbiAgICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgIH1cclxuICAgIH0gQGVtcHR5IHtcclxuICAgICAgICA8ZGl2IGNsYXNzPVwiYmFudGEtZW1wdHktc3RhdGVcIiAqbmdJZj1cInNob3dFbXB0eVN0YXRlXCI+XHJcbiAgICAgICAgICAgIHt7IGVtcHR5U3RhdGVNZXNzYWdlIH19XHJcbiAgICAgICAgPC9kaXY+XHJcbiAgICB9XHJcblxyXG4gICAgPGJ1dHRvbiBtYXQtYnV0dG9uIGNsYXNzPVwicGFnZXJcIiAoY2xpY2spPVwic2hvd05leHQoKVwiIFtjbGFzcy52aXNpYmxlXT1cInNob3VsZFNob3dOZXh0XCIgW2Rpc2FibGVkXT1cImlzTG9hZGluZ01vcmVcIj5cclxuICAgICAgICA8bWF0LWljb24+ZXhwYW5kX21vcmU8L21hdC1pY29uPlxyXG4gICAgICAgIHt7IG5leHRMYWJlbCB9fVxyXG4gICAgPC9idXR0b24+XHJcblxyXG4gICAgPGRpdiBjbGFzcz1cImJhbnRhLW5hdi1wb2ludCBiYW50YS1ib3R0b20tc3RpY2t5XCI+XHJcbiAgICAgICAgQGlmIChuZXdlc3RMYXN0KSB7XHJcbiAgICAgICAgICAgIDxidXR0b25cclxuICAgICAgICAgICAgICAgIFttYXRCYWRnZV09XCIxMFwiIG1hdEJhZGdlT3ZlcmxhcD1cImZhbHNlXCJcclxuICAgICAgICAgICAgICAgIG1hdEJhZGdlUG9zaXRpb249XCJhZnRlclwiIG1hdEJhZGdlU2l6ZT1cImxhcmdlXCJcclxuICAgICAgICAgICAgICAgIG1hdC1idXR0b25cclxuICAgICAgICAgICAgICAgIGNsYXNzPVwiYmFudGEtbmF2XCJcclxuICAgICAgICAgICAgICAgIFtjbGFzcy52aXNpYmxlXT1cInNob3VsZFNob3dOZXdNZXNzYWdlSW5kaWNhdG9yXCJcclxuICAgICAgICAgICAgICAgIGhyZWY9XCJqYXZhc2NyaXB0OjtcIlxyXG4gICAgICAgICAgICAgICAgKGNsaWNrKT1cInNob3dOZXdlc3QoJGV2ZW50KVwiXHJcbiAgICAgICAgICAgICAgICA+XHJcbiAgICAgICAgICAgICAgICA8bWF0LWljb24+ZmlsZV9kb3dubG9hZDwvbWF0LWljb24+XHJcbiAgICAgICAgICAgICAgICBOZXdlc3RcclxuICAgICAgICAgICAgICAgIEBpZiAoaGVsZE1lc3NhZ2VzLmxlbmd0aCA+IDApIHtcclxuICAgICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cImNvdW50XCI+e3sgaGVsZE1lc3NhZ2VzLmxlbmd0aCB8IG51bWJlciB9fTwvc3Bhbj5cclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgPC9idXR0b24+XHJcbiAgICAgICAgfVxyXG4gICAgPC9kaXY+XHJcblxyXG4gICAgPGRpdiBjbGFzcz1cImJhbnRhLWxvYWRpbmctbW9yZVwiICpuZ0lmPVwiaXNMb2FkaW5nTW9yZVwiPlxyXG4gICAgICAgIDxtYXQtc3Bpbm5lcj48L21hdC1zcGlubmVyPlxyXG4gICAgPC9kaXY+XHJcblxyXG4gICAgQGlmIChzaG93RGVidWcpIHtcclxuICAgICAgICA8ZGl2IHN0eWxlPVwiY29sb3I6ICM2NjZcIj5cclxuICAgICAgICAgICAgKHt7IHByZXZpb3VzTWVzc2FnZXMubGVuZ3RoIH19IC4uIHt7IG1lc3NhZ2VzLmxlbmd0aCB9fSAuLiB7eyBuZXh0TWVzc2FnZXMubGVuZ3RoIH19KVxyXG5cclxuICAgICAgICAgICAgZGlyPXt7bmV3ZXN0TGFzdCA/ICctMScgOiAnMSd9fVxyXG4gICAgICAgICAgICB2PXt7bWF4VmlzaWJsZU1lc3NhZ2VzfX0sIE09e3ttYXhNZXNzYWdlc319XHJcbiAgICAgICAgPC9kaXY+XHJcbiAgICB9XHJcblxyXG4gICAgPG5nLWNvbnRlbnQgc2VsZWN0PVwiOm5vdChbZGF0YS1iZWZvcmVdKTpub3QoLmlubGluZS1yZXBsaWVzKVwiPjwvbmctY29udGVudD5cclxuPC9kaXY+XHJcbiJdfQ==
|