stream-chat-angular 5.12.5 → 6.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/i18n/en.d.ts +1 -0
- package/assets/version.d.ts +1 -1
- package/{esm2020 → esm2022}/assets/i18n/en.mjs +2 -1
- package/{esm2020 → esm2022}/assets/version.mjs +2 -2
- package/{esm2020 → esm2022}/lib/attachment-configuration.service.mjs +4 -4
- package/esm2022/lib/attachment-list/attachment-list.component.mjs +212 -0
- package/esm2022/lib/attachment-preview-list/attachment-preview-list.component.mjs +55 -0
- package/{esm2020 → esm2022}/lib/attachment.service.mjs +5 -5
- package/esm2022/lib/avatar/avatar.component.mjs +157 -0
- package/{esm2020 → esm2022}/lib/avatar-placeholder/avatar-placeholder.component.mjs +6 -6
- package/esm2022/lib/channel/channel.component.mjs +45 -0
- package/esm2022/lib/channel-header/channel-header.component.mjs +72 -0
- package/esm2022/lib/channel-list/channel-list.component.mjs +50 -0
- package/esm2022/lib/channel-preview/channel-preview.component.mjs +150 -0
- package/esm2022/lib/channel.service.mjs +1381 -0
- package/esm2022/lib/chat-client.service.mjs +227 -0
- package/{esm2020 → esm2022}/lib/custom-templates.service.mjs +5 -5
- package/{esm2020 → esm2022}/lib/date-parser.service.mjs +5 -5
- package/esm2022/lib/file-utils.mjs +35 -0
- package/{esm2020 → esm2022}/lib/get-channel-display-text.mjs +1 -1
- package/{esm2020 → esm2022}/lib/get-message-translation.mjs +1 -1
- package/{esm2020 → esm2022}/lib/icon/icon-placeholder/icon-placeholder.component.mjs +6 -6
- package/{esm2020 → esm2022}/lib/icon/icon.component.mjs +5 -5
- package/{esm2020 → esm2022}/lib/icon/icon.module.mjs +11 -11
- package/{esm2020 → esm2022}/lib/icon/loading-indicator/loading-indicator.component.mjs +5 -5
- package/{esm2020 → esm2022}/lib/icon/loading-indicator-placeholder/loading-indicator-placeholder.component.mjs +6 -6
- package/{esm2020 → esm2022}/lib/list-users.mjs +1 -1
- package/esm2022/lib/message/message.component.mjs +486 -0
- package/esm2022/lib/message-actions-box/message-actions-box.component.mjs +120 -0
- package/{esm2020 → esm2022}/lib/message-actions.service.mjs +5 -5
- package/esm2022/lib/message-bounce-prompt/message-bounce-prompt.component.mjs +71 -0
- package/{esm2020 → esm2022}/lib/message-input/autocomplete-textarea/autocomplete-textarea.component.mjs +6 -6
- package/{esm2020 → esm2022}/lib/message-input/emoji-input.service.mjs +5 -5
- package/{esm2020 → esm2022}/lib/message-input/message-input-config.service.mjs +5 -5
- package/esm2022/lib/message-input/message-input.component.mjs +507 -0
- package/{esm2020 → esm2022}/lib/message-input/textarea/textarea.component.mjs +5 -5
- package/{esm2020 → esm2022}/lib/message-input/textarea.directive.mjs +5 -5
- package/{esm2020 → esm2022}/lib/message-input/voice-recorder.service.mjs +5 -5
- package/{esm2020 → esm2022}/lib/message-list/group-styles.mjs +1 -1
- package/esm2022/lib/message-list/message-list.component.mjs +715 -0
- package/{esm2020 → esm2022}/lib/message-preview.mjs +1 -1
- package/esm2022/lib/message-reactions/message-reactions.component.mjs +165 -0
- package/esm2022/lib/message-reactions-selector/message-reactions-selector.component.mjs +57 -0
- package/{esm2020 → esm2022}/lib/message-reactions.service.mjs +5 -5
- package/{esm2020 → esm2022}/lib/message-text/message-text.component.mjs +6 -6
- package/esm2022/lib/message.service.mjs +43 -0
- package/{esm2020 → esm2022}/lib/modal/modal.component.mjs +6 -6
- package/{esm2020 → esm2022}/lib/notification/notification.component.mjs +6 -6
- package/esm2022/lib/notification-list/notification-list.component.mjs +33 -0
- package/{esm2020 → esm2022}/lib/notification.service.mjs +5 -5
- package/esm2022/lib/paginated-list/paginated-list.component.mjs +94 -0
- package/{esm2020 → esm2022}/lib/parse-date.mjs +1 -1
- package/{esm2020 → esm2022}/lib/read-by.mjs +1 -1
- package/esm2022/lib/stream-autocomplete-textarea.module.mjs +33 -0
- package/{esm2020 → esm2022}/lib/stream-avatar.module.mjs +5 -5
- package/{esm2020 → esm2022}/lib/stream-chat.module.mjs +59 -59
- package/{esm2020 → esm2022}/lib/stream-i18n.service.mjs +5 -5
- package/esm2022/lib/stream-textarea.module.mjs +31 -0
- package/{esm2020 → esm2022}/lib/theme.service.mjs +5 -5
- package/{esm2020 → esm2022}/lib/thread/thread.component.mjs +6 -6
- package/{esm2020 → esm2022}/lib/transliteration.service.mjs +5 -5
- package/esm2022/lib/types.mjs +2 -0
- package/{esm2020 → esm2022}/lib/user-list/user-list.component.mjs +5 -5
- package/esm2022/lib/virtualized-list.service.mjs +273 -0
- package/{esm2020 → esm2022}/lib/virtualized-message-list.service.mjs +1 -1
- package/{esm2020 → esm2022}/lib/voice-recorder/amplitude-recorder.service.mjs +5 -5
- package/{esm2020 → esm2022}/lib/voice-recorder/audio-recorder.service.mjs +5 -5
- package/{esm2020 → esm2022}/lib/voice-recorder/media-recorder.mjs +1 -1
- package/esm2022/lib/voice-recorder/mp3-transcoder.mjs +61 -0
- package/esm2022/lib/voice-recorder/transcoder.service.mjs +121 -0
- package/esm2022/lib/voice-recorder/voice-recorder-wavebar/voice-recorder-wavebar.component.mjs +32 -0
- package/esm2022/lib/voice-recorder/voice-recorder.component.mjs +80 -0
- package/{esm2020 → esm2022}/lib/voice-recorder/voice-recorder.module.mjs +9 -9
- package/esm2022/lib/voice-recording/voice-recording-wavebar/voice-recording-wavebar.component.mjs +112 -0
- package/esm2022/lib/voice-recording/voice-recording.component.mjs +91 -0
- package/{esm2020 → esm2022}/lib/voice-recording/voice-recording.module.mjs +5 -5
- package/{esm2020 → esm2022}/lib/wave-form-sampler.mjs +1 -1
- package/esm2022/public-api.mjs +82 -0
- package/{fesm2020 → fesm2022}/stream-chat-angular.mjs +854 -1126
- package/fesm2022/stream-chat-angular.mjs.map +1 -0
- package/lib/attachment-list/attachment-list.component.d.ts +2 -5
- package/lib/attachment-preview-list/attachment-preview-list.component.d.ts +2 -2
- package/lib/attachment.service.d.ts +1 -1
- package/lib/avatar/avatar.component.d.ts +4 -4
- package/lib/avatar-placeholder/avatar-placeholder.component.d.ts +1 -1
- package/lib/channel-list/channel-list.component.d.ts +1 -0
- package/lib/channel-preview/channel-preview.component.d.ts +3 -4
- package/lib/channel.service.d.ts +40 -106
- package/lib/chat-client.service.d.ts +1 -4
- package/lib/custom-templates.service.d.ts +10 -10
- package/lib/icon/icon-placeholder/icon-placeholder.component.d.ts +1 -1
- package/lib/icon/icon.component.d.ts +2 -2
- package/lib/message/message.component.d.ts +2 -2
- package/lib/message-actions-box/message-actions-box.component.d.ts +2 -3
- package/lib/message-actions.service.d.ts +1 -1
- package/lib/message-input/autocomplete-textarea/autocomplete-textarea.component.d.ts +2 -2
- package/lib/message-input/message-input.component.d.ts +2 -2
- package/lib/message-input/textarea/textarea.component.d.ts +1 -1
- package/lib/message-input/textarea.directive.d.ts +2 -2
- package/lib/message-list/group-styles.d.ts +1 -1
- package/lib/message-list/message-list.component.d.ts +2 -3
- package/lib/message-reactions/message-reactions.component.d.ts +2 -3
- package/lib/message-reactions-selector/message-reactions-selector.component.d.ts +1 -2
- package/lib/message-text/message-text.component.d.ts +2 -2
- package/lib/modal/modal.component.d.ts +1 -1
- package/lib/notification/notification.component.d.ts +1 -1
- package/lib/notification-list/notification-list.component.d.ts +0 -1
- package/lib/paginated-list/paginated-list.component.d.ts +5 -2
- package/lib/read-by.d.ts +1 -1
- package/lib/types.d.ts +98 -84
- package/lib/user-list/user-list.component.d.ts +1 -1
- package/lib/voice-recorder/amplitude-recorder.service.d.ts +2 -2
- package/lib/voice-recorder/media-recorder.d.ts +2 -2
- package/lib/voice-recorder/transcoder.service.d.ts +4 -4
- package/lib/voice-recorder/voice-recorder-wavebar/voice-recorder-wavebar.component.d.ts +0 -1
- package/lib/voice-recorder/voice-recorder.component.d.ts +2 -2
- package/lib/voice-recording/voice-recording-wavebar/voice-recording-wavebar.component.d.ts +3 -3
- package/lib/voice-recording/voice-recording.component.d.ts +1 -1
- package/package.json +15 -21
- package/public-api.d.ts +0 -1
- package/src/assets/i18n/en.ts +1 -0
- package/src/assets/version.ts +1 -1
- package/esm2020/lib/attachment-list/attachment-list.component.mjs +0 -224
- package/esm2020/lib/attachment-preview-list/attachment-preview-list.component.mjs +0 -55
- package/esm2020/lib/avatar/avatar.component.mjs +0 -160
- package/esm2020/lib/channel/channel.component.mjs +0 -45
- package/esm2020/lib/channel-header/channel-header.component.mjs +0 -72
- package/esm2020/lib/channel-list/channel-list.component.mjs +0 -47
- package/esm2020/lib/channel-preview/channel-preview.component.mjs +0 -155
- package/esm2020/lib/channel-query.mjs +0 -77
- package/esm2020/lib/channel.service.mjs +0 -1546
- package/esm2020/lib/chat-client.service.mjs +0 -227
- package/esm2020/lib/file-utils.mjs +0 -35
- package/esm2020/lib/message/message.component.mjs +0 -486
- package/esm2020/lib/message-actions-box/message-actions-box.component.mjs +0 -123
- package/esm2020/lib/message-bounce-prompt/message-bounce-prompt.component.mjs +0 -71
- package/esm2020/lib/message-input/message-input.component.mjs +0 -507
- package/esm2020/lib/message-list/message-list.component.mjs +0 -717
- package/esm2020/lib/message-reactions/message-reactions.component.mjs +0 -168
- package/esm2020/lib/message-reactions-selector/message-reactions-selector.component.mjs +0 -61
- package/esm2020/lib/message.service.mjs +0 -43
- package/esm2020/lib/notification-list/notification-list.component.mjs +0 -36
- package/esm2020/lib/paginated-list/paginated-list.component.mjs +0 -94
- package/esm2020/lib/stream-autocomplete-textarea.module.mjs +0 -33
- package/esm2020/lib/stream-textarea.module.mjs +0 -31
- package/esm2020/lib/types.mjs +0 -2
- package/esm2020/lib/virtualized-list.service.mjs +0 -271
- package/esm2020/lib/voice-recorder/mp3-transcoder.mjs +0 -61
- package/esm2020/lib/voice-recorder/transcoder.service.mjs +0 -121
- package/esm2020/lib/voice-recorder/voice-recorder-wavebar/voice-recorder-wavebar.component.mjs +0 -35
- package/esm2020/lib/voice-recorder/voice-recorder.component.mjs +0 -80
- package/esm2020/lib/voice-recording/voice-recording-wavebar/voice-recording-wavebar.component.mjs +0 -112
- package/esm2020/lib/voice-recording/voice-recording.component.mjs +0 -91
- package/esm2020/public-api.mjs +0 -83
- package/fesm2015/stream-chat-angular.mjs +0 -9141
- package/fesm2015/stream-chat-angular.mjs.map +0 -1
- package/fesm2020/stream-chat-angular.mjs.map +0 -1
- package/lib/channel-query.d.ts +0 -26
- /package/{esm2020 → esm2022}/lib/format-duration.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/injection-tokens.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/is-image-attachment.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/is-on-separate-date.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/is-safari.mjs +0 -0
- /package/{esm2020 → esm2022}/lib/message-input/textarea.interface.mjs +0 -0
- /package/{esm2020 → esm2022}/stream-chat-angular.mjs +0 -0
|
@@ -0,0 +1,1381 @@
|
|
|
1
|
+
import { Injectable } from '@angular/core';
|
|
2
|
+
import { BehaviorSubject, combineLatest, ReplaySubject, } from 'rxjs';
|
|
3
|
+
import { distinctUntilChanged, filter, first, map, shareReplay, take, } from 'rxjs/operators';
|
|
4
|
+
import { ChannelManager, promoteChannel, } from 'stream-chat';
|
|
5
|
+
import { getMessageTranslation } from './get-message-translation';
|
|
6
|
+
import { createMessagePreview } from './message-preview';
|
|
7
|
+
import { getReadBy } from './read-by';
|
|
8
|
+
import * as i0 from "@angular/core";
|
|
9
|
+
import * as i1 from "./chat-client.service";
|
|
10
|
+
import * as i2 from "./notification.service";
|
|
11
|
+
/**
|
|
12
|
+
* The `ChannelService` provides data and interaction for the channel list and message list.
|
|
13
|
+
*/
|
|
14
|
+
export class ChannelService {
|
|
15
|
+
/**
|
|
16
|
+
* @internal
|
|
17
|
+
*/
|
|
18
|
+
static { this.MAX_MESSAGE_REACTIONS_TO_FETCH = 1200; }
|
|
19
|
+
constructor(chatClientService, ngZone, notificationService) {
|
|
20
|
+
this.chatClientService = chatClientService;
|
|
21
|
+
this.ngZone = ngZone;
|
|
22
|
+
this.notificationService = notificationService;
|
|
23
|
+
/**
|
|
24
|
+
* @internal
|
|
25
|
+
*/
|
|
26
|
+
this.isMessageLoadingInProgress = false;
|
|
27
|
+
/**
|
|
28
|
+
* @internal
|
|
29
|
+
*/
|
|
30
|
+
this.messagePageSize = 25;
|
|
31
|
+
this.channelsSubject = new BehaviorSubject(undefined);
|
|
32
|
+
this.activeChannelSubject = new BehaviorSubject(undefined);
|
|
33
|
+
this.activeChannelMessagesSubject = new BehaviorSubject([]);
|
|
34
|
+
this.activeChannelPinnedMessagesSubject = new BehaviorSubject([]);
|
|
35
|
+
this.hasMoreChannelsSubject = new ReplaySubject(1);
|
|
36
|
+
this.activeChannelSubscriptions = [];
|
|
37
|
+
this.activeParentMessageIdSubject = new BehaviorSubject(undefined);
|
|
38
|
+
this.activeThreadMessagesSubject = new BehaviorSubject([]);
|
|
39
|
+
this.jumpToMessageSubject = new BehaviorSubject({ id: undefined, parentId: undefined });
|
|
40
|
+
this.latestMessageDateByUserByChannelsSubject = new BehaviorSubject({});
|
|
41
|
+
this.attachmentMaxSizeFallbackInMB = 100;
|
|
42
|
+
this.messageToQuoteSubject = new BehaviorSubject(undefined);
|
|
43
|
+
this.usersTypingInChannelSubject = new BehaviorSubject([]);
|
|
44
|
+
this.usersTypingInThreadSubject = new BehaviorSubject([]);
|
|
45
|
+
this._shouldMarkActiveChannelAsRead = true;
|
|
46
|
+
this.shouldSetActiveChannel = true;
|
|
47
|
+
this.isStateRecoveryInProgress$ = new BehaviorSubject(false);
|
|
48
|
+
this.channelQueryStateSubject = new BehaviorSubject(undefined);
|
|
49
|
+
this.areReadEventsPaused = false;
|
|
50
|
+
this.markReadThrottleTime = 1050;
|
|
51
|
+
this.channelManagerSubscriptions = [];
|
|
52
|
+
this.channels$ = this.channelsSubject.asObservable().pipe(shareReplay(1));
|
|
53
|
+
this.activeChannel$ = this.activeChannelSubject
|
|
54
|
+
.asObservable()
|
|
55
|
+
.pipe(shareReplay(1));
|
|
56
|
+
this.activeChannelMessages$ = this.activeChannelMessagesSubject.pipe(map((messages) => {
|
|
57
|
+
const channel = this.activeChannelSubject.getValue();
|
|
58
|
+
return messages.map((message) => this.transformToStreamMessage(message, channel));
|
|
59
|
+
}), shareReplay(1));
|
|
60
|
+
this.bouncedMessage$ = new BehaviorSubject(undefined);
|
|
61
|
+
this.hasMoreChannels$ = this.hasMoreChannelsSubject
|
|
62
|
+
.asObservable()
|
|
63
|
+
.pipe(shareReplay(1));
|
|
64
|
+
this.activeParentMessageId$ = this.activeParentMessageIdSubject
|
|
65
|
+
.asObservable()
|
|
66
|
+
.pipe(shareReplay(1));
|
|
67
|
+
this.activeThreadMessages$ = this.activeThreadMessagesSubject.pipe(map((messages) => {
|
|
68
|
+
const channel = this.activeChannelSubject.getValue();
|
|
69
|
+
return messages.map((message) => this.transformToStreamMessage(message, channel));
|
|
70
|
+
}), shareReplay(1));
|
|
71
|
+
this.activeParentMessage$ = combineLatest([
|
|
72
|
+
this.activeChannelMessages$,
|
|
73
|
+
this.activeParentMessageId$,
|
|
74
|
+
]).pipe(map(([messages, parentMessageId]) => {
|
|
75
|
+
if (!parentMessageId) {
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
const message = messages.find((m) => m.id === parentMessageId);
|
|
80
|
+
if (!message) {
|
|
81
|
+
void this.setAsActiveParentMessage(undefined);
|
|
82
|
+
return undefined;
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
return message;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}), shareReplay(1));
|
|
89
|
+
this.messageToQuote$ = this.messageToQuoteSubject
|
|
90
|
+
.asObservable()
|
|
91
|
+
.pipe(shareReplay(1));
|
|
92
|
+
this.jumpToMessage$ = this.jumpToMessageSubject
|
|
93
|
+
.asObservable()
|
|
94
|
+
.pipe(shareReplay(1));
|
|
95
|
+
this.usersTypingInChannel$ = this.usersTypingInChannelSubject
|
|
96
|
+
.asObservable()
|
|
97
|
+
.pipe(shareReplay(1));
|
|
98
|
+
this.usersTypingInThread$ = this.usersTypingInThreadSubject
|
|
99
|
+
.asObservable()
|
|
100
|
+
.pipe(shareReplay(1));
|
|
101
|
+
this.latestMessageDateByUserByChannels$ =
|
|
102
|
+
this.latestMessageDateByUserByChannelsSubject
|
|
103
|
+
.asObservable()
|
|
104
|
+
.pipe(shareReplay(1));
|
|
105
|
+
this.activeChannelPinnedMessages$ = this.activeChannelPinnedMessagesSubject
|
|
106
|
+
.asObservable()
|
|
107
|
+
.pipe(shareReplay(1));
|
|
108
|
+
this.channelQueryState$ = this.channelQueryStateSubject
|
|
109
|
+
.asObservable()
|
|
110
|
+
.pipe(shareReplay(1));
|
|
111
|
+
this.shouldRecoverState$ = combineLatest([
|
|
112
|
+
this.channels$,
|
|
113
|
+
this.channelQueryState$,
|
|
114
|
+
this.isStateRecoveryInProgress$,
|
|
115
|
+
]).pipe(map(([channels, queryState, isStateRecoveryInProgress]) => {
|
|
116
|
+
return ((!channels || channels.length === 0) &&
|
|
117
|
+
queryState?.state === 'error' &&
|
|
118
|
+
!isStateRecoveryInProgress);
|
|
119
|
+
}), distinctUntilChanged());
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* If set to false, read events won't be sent as new messages are received. If set to true active channel (if any) will immediately be marked as read.
|
|
123
|
+
*/
|
|
124
|
+
get shouldMarkActiveChannelAsRead() {
|
|
125
|
+
return this._shouldMarkActiveChannelAsRead;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* If set to false, read events won't be sent as new messages are received. If set to true active channel (if any) will immediately be marked as read.
|
|
129
|
+
*/
|
|
130
|
+
set shouldMarkActiveChannelAsRead(shouldMarkActiveChannelAsRead) {
|
|
131
|
+
if (!this._shouldMarkActiveChannelAsRead && shouldMarkActiveChannelAsRead) {
|
|
132
|
+
const activeChannel = this.activeChannelSubject.getValue();
|
|
133
|
+
if (activeChannel && this.canSendReadEvents) {
|
|
134
|
+
void activeChannel.markRead();
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
this._shouldMarkActiveChannelAsRead = shouldMarkActiveChannelAsRead;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Sets the given `channel` as active and marks it as read.
|
|
141
|
+
* If the channel wasn't previously part of the channel, it will be added to the beginning of the list.
|
|
142
|
+
* @param channel
|
|
143
|
+
*/
|
|
144
|
+
setAsActiveChannel(channel) {
|
|
145
|
+
const prevActiveChannel = this.activeChannelSubject.getValue();
|
|
146
|
+
if (prevActiveChannel?.cid === channel.cid) {
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
this.stopWatchForActiveChannelEvents(prevActiveChannel);
|
|
150
|
+
this.flushMarkReadQueue();
|
|
151
|
+
this.areReadEventsPaused = false;
|
|
152
|
+
this.isMessageLoadingInProgress = false;
|
|
153
|
+
const readState = channel.state.read[this.chatClientService.chatClient.user?.id || ''];
|
|
154
|
+
this.activeChannelLastReadMessageId = readState?.last_read_message_id;
|
|
155
|
+
if (channel.state.latestMessages[channel.state.latestMessages.length - 1]
|
|
156
|
+
?.id === this.activeChannelLastReadMessageId) {
|
|
157
|
+
this.activeChannelLastReadMessageId = undefined;
|
|
158
|
+
}
|
|
159
|
+
this.activeChannelUnreadCount = readState?.unread_messages || 0;
|
|
160
|
+
this.watchForActiveChannelEvents(channel);
|
|
161
|
+
this.addChannel(channel);
|
|
162
|
+
this.activeChannelSubject.next(channel);
|
|
163
|
+
const channelStateLength = channel.state.latestMessages.length;
|
|
164
|
+
if (channelStateLength > 2 * this.messagePageSize) {
|
|
165
|
+
channel.state.latestMessages = channel.state.latestMessages.slice(channelStateLength - 2 * this.messagePageSize);
|
|
166
|
+
}
|
|
167
|
+
this.setChannelState(channel);
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Deselects the currently active (if any) channel
|
|
171
|
+
*/
|
|
172
|
+
deselectActiveChannel() {
|
|
173
|
+
const activeChannel = this.activeChannelSubject.getValue();
|
|
174
|
+
if (!activeChannel) {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
this.stopWatchForActiveChannelEvents(activeChannel);
|
|
178
|
+
this.flushMarkReadQueue();
|
|
179
|
+
this.activeChannelMessagesSubject.next([]);
|
|
180
|
+
this.activeChannelSubject.next(undefined);
|
|
181
|
+
this.activeParentMessageIdSubject.next(undefined);
|
|
182
|
+
this.activeThreadMessagesSubject.next([]);
|
|
183
|
+
this.latestMessageDateByUserByChannelsSubject.next({});
|
|
184
|
+
this.selectMessageToQuote(undefined);
|
|
185
|
+
this.jumpToMessageSubject.next({ id: undefined, parentId: undefined });
|
|
186
|
+
this.activeChannelPinnedMessagesSubject.next([]);
|
|
187
|
+
this.usersTypingInChannelSubject.next([]);
|
|
188
|
+
this.usersTypingInThreadSubject.next([]);
|
|
189
|
+
this.activeChannelLastReadMessageId = undefined;
|
|
190
|
+
this.activeChannelUnreadCount = undefined;
|
|
191
|
+
this.areReadEventsPaused = false;
|
|
192
|
+
this.isMessageLoadingInProgress = false;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Sets the given `message` as an active parent message. If `undefined` is provided, it will deleselect the current parent message.
|
|
196
|
+
* @param message
|
|
197
|
+
* @param loadMessagesForm
|
|
198
|
+
*/
|
|
199
|
+
async setAsActiveParentMessage(message, loadMessagesForm = 'request') {
|
|
200
|
+
const messageToQuote = this.messageToQuoteSubject.getValue();
|
|
201
|
+
if (messageToQuote && !!messageToQuote.parent_id) {
|
|
202
|
+
this.messageToQuoteSubject.next(undefined);
|
|
203
|
+
}
|
|
204
|
+
if (!message) {
|
|
205
|
+
this.activeParentMessageIdSubject.next(undefined);
|
|
206
|
+
this.activeThreadMessagesSubject.next([]);
|
|
207
|
+
const messageToJumpTo = this.jumpToMessageSubject.getValue();
|
|
208
|
+
if (messageToJumpTo && !!messageToJumpTo.parentId) {
|
|
209
|
+
this.jumpToMessageSubject.next({ id: undefined, parentId: undefined });
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
this.activeParentMessageIdSubject.next(message.id);
|
|
214
|
+
const activeChannel = this.activeChannelSubject.getValue();
|
|
215
|
+
if (loadMessagesForm === 'request') {
|
|
216
|
+
const result = await activeChannel?.getReplies(message.id, {
|
|
217
|
+
limit: this.messagePageSize,
|
|
218
|
+
});
|
|
219
|
+
this.activeThreadMessagesSubject.next(result?.messages || []);
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
this.activeThreadMessagesSubject.next(activeChannel?.state.threads[message.id] || []);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Loads the next page of messages of the active channel. The page size can be set in the [query option](/chat/docs/javascript/query_channels/#query-options) object.
|
|
228
|
+
* @param direction
|
|
229
|
+
*/
|
|
230
|
+
loadMoreMessages(direction = 'older') {
|
|
231
|
+
const activeChnannel = this.activeChannelSubject.getValue();
|
|
232
|
+
const messages = this.activeChannelMessagesSubject.getValue();
|
|
233
|
+
const lastMessageId = messages[direction === 'older' ? 0 : messages.length - 1]?.id;
|
|
234
|
+
if (direction === 'newer' &&
|
|
235
|
+
activeChnannel?.state?.latestMessages === activeChnannel?.state?.messages) {
|
|
236
|
+
// If we are on latest message set, activeChannelMessages$ will be refreshed by WS events, no need for a request
|
|
237
|
+
return false;
|
|
238
|
+
}
|
|
239
|
+
return activeChnannel
|
|
240
|
+
?.query({
|
|
241
|
+
messages: {
|
|
242
|
+
limit: this.messagePageSize,
|
|
243
|
+
[direction === 'older' ? 'id_lt' : 'id_gt']: lastMessageId,
|
|
244
|
+
},
|
|
245
|
+
members: { limit: 0 },
|
|
246
|
+
watchers: { limit: 0 },
|
|
247
|
+
})
|
|
248
|
+
.then((res) => {
|
|
249
|
+
if (activeChnannel?.data?.id ===
|
|
250
|
+
this.activeChannelSubject.getValue()?.data?.id) {
|
|
251
|
+
this.activeChannelMessagesSubject.next([
|
|
252
|
+
...activeChnannel.state.messages,
|
|
253
|
+
]);
|
|
254
|
+
}
|
|
255
|
+
return res;
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Loads the next page of messages of the active thread. The page size can be set in the [query option](/chat/docs/javascript/query_channels/#query-options) object.
|
|
260
|
+
* @param direction
|
|
261
|
+
*/
|
|
262
|
+
loadMoreThreadReplies(direction = 'older') {
|
|
263
|
+
if (direction === 'newer') {
|
|
264
|
+
// Thread replies aren't broke into different message sets, activeThreadMessages$ will be refreshed by WS events, no need for a request
|
|
265
|
+
return false;
|
|
266
|
+
}
|
|
267
|
+
const activeChnannel = this.activeChannelSubject.getValue();
|
|
268
|
+
const parentMessageId = this.activeParentMessageIdSubject.getValue();
|
|
269
|
+
if (!parentMessageId || !activeChnannel) {
|
|
270
|
+
return false;
|
|
271
|
+
}
|
|
272
|
+
const threadMessages = this.activeThreadMessagesSubject.getValue();
|
|
273
|
+
const lastMessageId = threadMessages[direction === 'older' ? 0 : threadMessages.length - 1]?.id;
|
|
274
|
+
return activeChnannel
|
|
275
|
+
.getReplies(parentMessageId, {
|
|
276
|
+
limit: this.messagePageSize,
|
|
277
|
+
[direction === 'older' ? 'id_lt' : 'id_gt']: lastMessageId,
|
|
278
|
+
})
|
|
279
|
+
.then(() => {
|
|
280
|
+
this.activeThreadMessagesSubject.next(activeChnannel?.state.threads[parentMessageId] || []);
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Queries the channels with the given filters, sorts and options. More info about [channel querying](/chat/docs/javascript/query_channels/) can be found in the platform documentation. By default the first channel in the list will be set as active channel and will be marked as read.
|
|
285
|
+
* @param queryConfig the filter, sort and options for the query
|
|
286
|
+
* @param options behavior customization for the channel list and WebSocket event handling
|
|
287
|
+
* @returns the list of channels found by the query
|
|
288
|
+
*/
|
|
289
|
+
init(queryConfig, options) {
|
|
290
|
+
this.channelQueryConfig = {
|
|
291
|
+
filters: queryConfig.filters,
|
|
292
|
+
sort: queryConfig.sort ?? { last_message_at: -1 },
|
|
293
|
+
options: {
|
|
294
|
+
limit: 25,
|
|
295
|
+
state: true,
|
|
296
|
+
presence: true,
|
|
297
|
+
watch: true,
|
|
298
|
+
message_limit: this.messagePageSize,
|
|
299
|
+
...queryConfig.options,
|
|
300
|
+
},
|
|
301
|
+
};
|
|
302
|
+
return this._init({
|
|
303
|
+
...options,
|
|
304
|
+
messagePageSize: queryConfig.options?.message_limit ?? this.messagePageSize,
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Queries the channels with the given query function. More info about [channel querying](/chat/docs/javascript/query_channels/) can be found in the platform documentation.
|
|
309
|
+
* @param query
|
|
310
|
+
* @param options behavior customization for the channel list and WebSocket event handling
|
|
311
|
+
* @param options.messagePageSize How many messages should we load? The default is 25
|
|
312
|
+
* @returns the channels that were loaded
|
|
313
|
+
*/
|
|
314
|
+
initWithCustomQuery(query, options = {
|
|
315
|
+
shouldSetActiveChannel: true,
|
|
316
|
+
messagePageSize: this.messagePageSize,
|
|
317
|
+
}) {
|
|
318
|
+
this.messagePageSize = options?.messagePageSize ?? this.messagePageSize;
|
|
319
|
+
this.shouldSetActiveChannel =
|
|
320
|
+
options?.shouldSetActiveChannel ?? this.shouldSetActiveChannel;
|
|
321
|
+
const eventHandlerOverrides = options?.eventHandlerOverrides;
|
|
322
|
+
const managerOptions = { ...options };
|
|
323
|
+
delete managerOptions?.eventHandlerOverrides;
|
|
324
|
+
delete managerOptions?.shouldSetActiveChannel;
|
|
325
|
+
this.customChannelQuery = query;
|
|
326
|
+
this.createChannelManager({
|
|
327
|
+
eventHandlerOverrides,
|
|
328
|
+
options: managerOptions,
|
|
329
|
+
});
|
|
330
|
+
return this._init(options);
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Resets the `activeChannel$`, `channels$` and `activeChannelMessages$` Observables. Useful when disconnecting a chat user, use in combination with [`disconnectUser`](/chat/docs/sdk/angular/services/ChatClientService/#disconnectuser/).
|
|
334
|
+
*/
|
|
335
|
+
reset() {
|
|
336
|
+
this.deselectActiveChannel();
|
|
337
|
+
this.channelQueryStateSubject.next(undefined);
|
|
338
|
+
this.clientEventsSubscription?.unsubscribe();
|
|
339
|
+
this.dismissErrorNotification?.();
|
|
340
|
+
this.dismissErrorNotification = undefined;
|
|
341
|
+
this.channelQueryConfig = undefined;
|
|
342
|
+
this.destroyChannelManager();
|
|
343
|
+
this.isStateRecoveryInProgress$.next(false);
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Loads the next page of channels. The page size can be set in the [query option](/chat/docs/javascript/query_channels/#query-options) object.
|
|
347
|
+
*/
|
|
348
|
+
async loadMoreChannels() {
|
|
349
|
+
await this.queryChannels('next-page');
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Adds a reaction to a message.
|
|
353
|
+
* @param messageId The id of the message to add the reaction to
|
|
354
|
+
* @param reactionType The type of the reaction
|
|
355
|
+
* @param customData
|
|
356
|
+
*/
|
|
357
|
+
async addReaction(messageId, reactionType, customData) {
|
|
358
|
+
await this.activeChannelSubject.getValue()?.sendReaction(messageId, {
|
|
359
|
+
type: reactionType,
|
|
360
|
+
...customData,
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Removes a reaction from a message.
|
|
365
|
+
* @param messageId The id of the message to remove the reaction from
|
|
366
|
+
* @param reactionType Thr type of reaction to remove
|
|
367
|
+
*/
|
|
368
|
+
async removeReaction(messageId, reactionType) {
|
|
369
|
+
await this.activeChannelSubject
|
|
370
|
+
.getValue()
|
|
371
|
+
?.deleteReaction(messageId, reactionType);
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Sends a message to the active channel. The message is immediately added to the message list, if an error occurs and the message can't be sent, the error is indicated in `state` of the message.
|
|
375
|
+
* @param text The text of the message
|
|
376
|
+
* @param attachments The attachments
|
|
377
|
+
* @param mentionedUsers Mentioned users
|
|
378
|
+
* @param parentId Id of the parent message (if sending a thread reply)
|
|
379
|
+
* @param quotedMessageId Id of the message to quote (if sending a quote reply)
|
|
380
|
+
* @param customData
|
|
381
|
+
*/
|
|
382
|
+
async sendMessage(text, attachments = [], mentionedUsers = [], parentId = undefined, quotedMessageId = undefined, customData = undefined) {
|
|
383
|
+
let input = {
|
|
384
|
+
text,
|
|
385
|
+
attachments,
|
|
386
|
+
mentionedUsers,
|
|
387
|
+
parentId,
|
|
388
|
+
quotedMessageId,
|
|
389
|
+
customData,
|
|
390
|
+
};
|
|
391
|
+
if (this.beforeSendMessage) {
|
|
392
|
+
input = await this.beforeSendMessage(input);
|
|
393
|
+
}
|
|
394
|
+
const preview = createMessagePreview(this.chatClientService.chatClient.user, input.text, input.attachments, input.mentionedUsers, input.parentId, input.quotedMessageId, input.customData);
|
|
395
|
+
const channel = this.activeChannelSubject.getValue();
|
|
396
|
+
preview.readBy = [];
|
|
397
|
+
channel.state.addMessageSorted(preview, true);
|
|
398
|
+
const response = await this.sendMessageRequest(preview, input.customData);
|
|
399
|
+
return response;
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Resends the given message to the active channel
|
|
403
|
+
* @param message The message to resend
|
|
404
|
+
*/
|
|
405
|
+
async resendMessage(message) {
|
|
406
|
+
const channel = this.activeChannelSubject.getValue();
|
|
407
|
+
channel.state.addMessageSorted({
|
|
408
|
+
...message,
|
|
409
|
+
errorStatusCode: undefined,
|
|
410
|
+
status: 'sending',
|
|
411
|
+
}, true);
|
|
412
|
+
return this.sendMessageRequest(message, undefined, true);
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* Updates the message in the active channel
|
|
416
|
+
* @param message Mesage to be updated
|
|
417
|
+
*/
|
|
418
|
+
async updateMessage(message) {
|
|
419
|
+
let messageToUpdate = {
|
|
420
|
+
...message,
|
|
421
|
+
};
|
|
422
|
+
delete messageToUpdate.i18n;
|
|
423
|
+
if (this.beforeUpdateMessage) {
|
|
424
|
+
messageToUpdate = await this.beforeUpdateMessage(messageToUpdate);
|
|
425
|
+
}
|
|
426
|
+
if (messageToUpdate.readBy) {
|
|
427
|
+
delete messageToUpdate.readBy;
|
|
428
|
+
}
|
|
429
|
+
if (message.moderation_details) {
|
|
430
|
+
return this.resendMessage(message);
|
|
431
|
+
}
|
|
432
|
+
const response = await this.chatClientService.chatClient.updateMessage(messageToUpdate);
|
|
433
|
+
const channel = this.channelsSubject
|
|
434
|
+
.getValue()
|
|
435
|
+
?.find((c) => c.cid === message.cid);
|
|
436
|
+
if (response.message.type === 'error' &&
|
|
437
|
+
response.message.moderation_details) {
|
|
438
|
+
this.notificationService.addTemporaryNotification('streamChat.This message did not meet our content guidelines');
|
|
439
|
+
return message;
|
|
440
|
+
}
|
|
441
|
+
return this.transformToStreamMessage(response.message, channel);
|
|
442
|
+
}
|
|
443
|
+
/**
|
|
444
|
+
* Deletes the message from the active channel
|
|
445
|
+
* @param message Message to be deleted
|
|
446
|
+
* @param isLocalDelete set this `true` if you want to delete a message that's only part of the local state, not yet saved on the backend
|
|
447
|
+
*/
|
|
448
|
+
async deleteMessage(message, isLocalDelete = false) {
|
|
449
|
+
if (isLocalDelete && this.activeChannel) {
|
|
450
|
+
const result = this.activeChannel.state.removeMessage({
|
|
451
|
+
id: message.id,
|
|
452
|
+
parent_id: message.parent_id,
|
|
453
|
+
});
|
|
454
|
+
if (result) {
|
|
455
|
+
message.parent_id
|
|
456
|
+
? this.activeThreadMessagesSubject.next(this.activeChannel.state.threads[message.parent_id])
|
|
457
|
+
: this.activeChannelMessagesSubject.next(this.activeChannel.state.messages);
|
|
458
|
+
}
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
461
|
+
if (this.messageDeleteConfirmationHandler) {
|
|
462
|
+
const result = await this.messageDeleteConfirmationHandler(message);
|
|
463
|
+
if (result) {
|
|
464
|
+
await this.chatClientService.chatClient.deleteMessage(message.id);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
else {
|
|
468
|
+
await this.chatClientService.chatClient.deleteMessage(message.id);
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
/**
|
|
472
|
+
* Uploads files to the channel. If you want to know more about [file uploads](/chat/docs/javascript/file_uploads/) check out the platform documentation.
|
|
473
|
+
* @param uploads the attachments to upload (output of the [`AttachmentService`](/chat/docs/sdk/angular/services/AttachmentService/))
|
|
474
|
+
* @returns the result of file upload requests
|
|
475
|
+
*/
|
|
476
|
+
async uploadAttachments(uploads) {
|
|
477
|
+
const result = [];
|
|
478
|
+
const channel = this.activeChannelSubject.getValue();
|
|
479
|
+
const uploadResults = await Promise.allSettled(uploads.map((upload) => upload.type === 'image'
|
|
480
|
+
? this.customImageUploadRequest
|
|
481
|
+
? this.customImageUploadRequest(upload.file, channel)
|
|
482
|
+
: channel.sendImage(upload.file, upload.file.name, upload.file.type)
|
|
483
|
+
: this.customFileUploadRequest
|
|
484
|
+
? this.customFileUploadRequest(upload.file, channel)
|
|
485
|
+
: channel.sendFile(upload.file, upload.file.name, upload.file.type)));
|
|
486
|
+
uploadResults.forEach((uploadResult, i) => {
|
|
487
|
+
const file = uploads[i].file;
|
|
488
|
+
const type = uploads[i].type;
|
|
489
|
+
if (uploadResult.status === 'fulfilled') {
|
|
490
|
+
result.push({
|
|
491
|
+
file,
|
|
492
|
+
type,
|
|
493
|
+
state: 'success',
|
|
494
|
+
url: uploadResult.value.file,
|
|
495
|
+
/* eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any */
|
|
496
|
+
thumb_url: uploadResult.value.thumb_url,
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
else {
|
|
500
|
+
let reason = 'unknown';
|
|
501
|
+
let extraData;
|
|
502
|
+
/* eslint-disable-next-line @typescript-eslint/no-unsafe-assignment */
|
|
503
|
+
const message =
|
|
504
|
+
/* eslint-disable-next-line @typescript-eslint/no-unsafe-member-access */
|
|
505
|
+
uploadResult.reason.response?.data?.message;
|
|
506
|
+
/* eslint-disable-next-line @typescript-eslint/no-unsafe-assignment */
|
|
507
|
+
const code =
|
|
508
|
+
/* eslint-disable-next-line @typescript-eslint/no-unsafe-member-access */
|
|
509
|
+
uploadResult.reason.response?.data?.code;
|
|
510
|
+
if (code === 22 ||
|
|
511
|
+
(code === 4 && message?.toLowerCase()?.includes('bytes'))) {
|
|
512
|
+
reason = 'file-size';
|
|
513
|
+
extraData = {
|
|
514
|
+
param: /\d+MB|\d+\s?bytes/.exec(message || '')?.[0] ||
|
|
515
|
+
`${this.attachmentMaxSizeFallbackInMB}MB`,
|
|
516
|
+
};
|
|
517
|
+
if (extraData.param.includes('bytes')) {
|
|
518
|
+
const limitInBytes = +(/\d+/.exec(extraData.param)?.[0] ||
|
|
519
|
+
this.attachmentMaxSizeFallbackInMB * 1024 * 1024);
|
|
520
|
+
extraData.param = `${limitInBytes / (1024 * 1024)}MB`;
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
else if (code === 4 &&
|
|
524
|
+
message?.toLowerCase()?.includes('file extension')) {
|
|
525
|
+
reason = 'file-extension';
|
|
526
|
+
extraData = { param: /\.\w+/.exec(message)?.[0] || '' };
|
|
527
|
+
}
|
|
528
|
+
result.push({
|
|
529
|
+
file,
|
|
530
|
+
type,
|
|
531
|
+
state: 'error',
|
|
532
|
+
errorReason: reason,
|
|
533
|
+
errorExtraInfo: extraData ? [extraData] : undefined,
|
|
534
|
+
});
|
|
535
|
+
}
|
|
536
|
+
});
|
|
537
|
+
return result;
|
|
538
|
+
}
|
|
539
|
+
/**
|
|
540
|
+
* Deletes an uploaded file by URL. If you want to know more about [file uploads](/chat/docs/javascript/file_uploads/) check out the platform documentation
|
|
541
|
+
* @param attachmentUpload Attachment to be deleted (output of the [`AttachmentService`](/chat/docs/sdk/angular/services/AttachmentService/))
|
|
542
|
+
*/
|
|
543
|
+
async deleteAttachment(attachmentUpload) {
|
|
544
|
+
const channel = this.activeChannelSubject.getValue();
|
|
545
|
+
await (attachmentUpload.type === 'image'
|
|
546
|
+
? this.customImageDeleteRequest
|
|
547
|
+
? this.customImageDeleteRequest(attachmentUpload.url, channel)
|
|
548
|
+
: channel.deleteImage(attachmentUpload.url)
|
|
549
|
+
: this.customFileDeleteRequest
|
|
550
|
+
? this.customFileDeleteRequest(attachmentUpload.url, channel)
|
|
551
|
+
: channel.deleteFile(attachmentUpload.url));
|
|
552
|
+
}
|
|
553
|
+
/**
|
|
554
|
+
* Returns the autocomplete options for current channel members. If the channel has less than 100 members, it returns the channel members, otherwise sends a [search request](/chat/docs/javascript/query_members/#pagination-and-ordering) with the given search term.
|
|
555
|
+
* @param searchTerm Text to search for in the names of members
|
|
556
|
+
* @returns The list of members matching the search filter
|
|
557
|
+
*/
|
|
558
|
+
async autocompleteMembers(searchTerm) {
|
|
559
|
+
const activeChannel = this.activeChannelSubject.getValue();
|
|
560
|
+
if (!activeChannel) {
|
|
561
|
+
return [];
|
|
562
|
+
}
|
|
563
|
+
if (Object.keys(activeChannel.state.members).length < 100) {
|
|
564
|
+
return Object.values(activeChannel.state.members).filter((m) => m.user?.id !== this.chatClientService.chatClient.userID);
|
|
565
|
+
}
|
|
566
|
+
else {
|
|
567
|
+
if (!searchTerm) {
|
|
568
|
+
return [];
|
|
569
|
+
}
|
|
570
|
+
const result = await activeChannel.queryMembers({
|
|
571
|
+
name: { $autocomplete: searchTerm },
|
|
572
|
+
}); // TODO: find out why we need typecast here
|
|
573
|
+
return result.members.filter((m) => m.user_id !== this.chatClientService.chatClient?.user?.id);
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
/**
|
|
577
|
+
* [Runs a message action](https://getstream.io/chat/docs/rest/#messages-runmessageaction) in the current channel. Updates the message list based on the action result (if no message is returned, the message will be removed from the message list).
|
|
578
|
+
* @param messageId
|
|
579
|
+
* @param formData
|
|
580
|
+
* @param parentMessageId
|
|
581
|
+
*/
|
|
582
|
+
async sendAction(messageId, formData, parentMessageId) {
|
|
583
|
+
const channel = this.activeChannelSubject.getValue();
|
|
584
|
+
const response = await channel.sendAction(messageId, formData);
|
|
585
|
+
if (response?.message) {
|
|
586
|
+
channel.state.addMessageSorted({
|
|
587
|
+
...response.message,
|
|
588
|
+
status: 'received',
|
|
589
|
+
});
|
|
590
|
+
const isThreadReply = !!response.message.parent_id;
|
|
591
|
+
isThreadReply
|
|
592
|
+
? this.activeThreadMessagesSubject.next([
|
|
593
|
+
...channel.state.threads[response.message.parent_id],
|
|
594
|
+
])
|
|
595
|
+
: this.activeChannelMessagesSubject.next([...channel.state.messages]);
|
|
596
|
+
}
|
|
597
|
+
else {
|
|
598
|
+
channel.state.removeMessage({
|
|
599
|
+
id: messageId,
|
|
600
|
+
parent_id: parentMessageId,
|
|
601
|
+
});
|
|
602
|
+
if (parentMessageId) {
|
|
603
|
+
this.activeThreadMessagesSubject.next(channel.state.threads[this.activeParentMessageIdSubject.getValue()]);
|
|
604
|
+
}
|
|
605
|
+
else {
|
|
606
|
+
this.activeChannelMessagesSubject.next([...channel.state.messages]);
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
/**
|
|
611
|
+
* Selects or deselects the current message to quote reply to
|
|
612
|
+
* @param message The message to select, if called with `undefined`, it deselects the message
|
|
613
|
+
*/
|
|
614
|
+
selectMessageToQuote(message) {
|
|
615
|
+
this.messageToQuoteSubject.next(message);
|
|
616
|
+
}
|
|
617
|
+
/**
|
|
618
|
+
* Add a new channel to the channel list
|
|
619
|
+
* The channel will be added to the beginning of the channel list
|
|
620
|
+
* @param channel
|
|
621
|
+
*/
|
|
622
|
+
addChannel(channel) {
|
|
623
|
+
if (!this.channelManager) {
|
|
624
|
+
throw new Error('Channel service not initialized');
|
|
625
|
+
}
|
|
626
|
+
if (!this.channels.find((c) => c.cid === channel.cid)) {
|
|
627
|
+
this.channelManager?.setChannels(promoteChannel({
|
|
628
|
+
channels: this.channels,
|
|
629
|
+
channelToMove: channel,
|
|
630
|
+
sort: this.channelQueryConfig?.sort ?? [],
|
|
631
|
+
}));
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
/**
|
|
635
|
+
*
|
|
636
|
+
* @param cid
|
|
637
|
+
*/
|
|
638
|
+
removeChannel(cid) {
|
|
639
|
+
if (!this.channelManager) {
|
|
640
|
+
throw new Error('Channel service not initialized');
|
|
641
|
+
}
|
|
642
|
+
const remainingChannels = this.channels.filter((c) => c.cid !== cid);
|
|
643
|
+
this.channelManager?.setChannels(remainingChannels);
|
|
644
|
+
}
|
|
645
|
+
async sendMessageRequest(preview, customData, isResend = false) {
|
|
646
|
+
const channel = this.activeChannelSubject.getValue();
|
|
647
|
+
const isThreadReply = !!preview.parent_id;
|
|
648
|
+
isThreadReply
|
|
649
|
+
? this.activeThreadMessagesSubject.next([
|
|
650
|
+
...channel.state.threads[preview.parent_id],
|
|
651
|
+
])
|
|
652
|
+
: this.activeChannelMessagesSubject.next([...channel.state.messages]);
|
|
653
|
+
try {
|
|
654
|
+
const response = await channel.sendMessage({
|
|
655
|
+
id: preview.id,
|
|
656
|
+
text: preview.text,
|
|
657
|
+
attachments: preview.attachments,
|
|
658
|
+
mentioned_users: preview.mentioned_users?.map((u) => u.id),
|
|
659
|
+
parent_id: preview.parent_id,
|
|
660
|
+
quoted_message_id: preview.quoted_message_id,
|
|
661
|
+
...customData,
|
|
662
|
+
}); // TODO: find out why we need typecast here
|
|
663
|
+
channel.state.addMessageSorted({
|
|
664
|
+
...response.message,
|
|
665
|
+
status: 'received',
|
|
666
|
+
}, true);
|
|
667
|
+
isThreadReply
|
|
668
|
+
? this.activeThreadMessagesSubject.next([
|
|
669
|
+
...channel.state.threads[preview.parent_id],
|
|
670
|
+
])
|
|
671
|
+
: this.activeChannelMessagesSubject.next([...channel.state.messages]);
|
|
672
|
+
let messages;
|
|
673
|
+
(isThreadReply ? this.activeThreadMessages$ : this.activeChannelMessages$)
|
|
674
|
+
.pipe(take(1))
|
|
675
|
+
.subscribe((m) => (messages = m));
|
|
676
|
+
const newMessage = messages[messages.length - 1];
|
|
677
|
+
return newMessage;
|
|
678
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
679
|
+
}
|
|
680
|
+
catch (error) {
|
|
681
|
+
const stringError = JSON.stringify(error);
|
|
682
|
+
const parsedError = stringError ? JSON.parse(stringError) : {};
|
|
683
|
+
let isAlreadyExists = false;
|
|
684
|
+
if (isResend) {
|
|
685
|
+
if (parsedError.status === 400 &&
|
|
686
|
+
parsedError.code === 4 &&
|
|
687
|
+
parsedError?.response?.data?.message?.includes('already exists')) {
|
|
688
|
+
isAlreadyExists = true;
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
channel.state.addMessageSorted({
|
|
692
|
+
...preview,
|
|
693
|
+
errorStatusCode: isAlreadyExists
|
|
694
|
+
? undefined
|
|
695
|
+
: parsedError.status || undefined,
|
|
696
|
+
status: isAlreadyExists ? 'received' : 'failed',
|
|
697
|
+
}, true);
|
|
698
|
+
isThreadReply
|
|
699
|
+
? this.activeThreadMessagesSubject.next([
|
|
700
|
+
...channel.state.threads[preview.parent_id],
|
|
701
|
+
])
|
|
702
|
+
: this.activeChannelMessagesSubject.next([...channel.state.messages]);
|
|
703
|
+
let messages;
|
|
704
|
+
(isThreadReply ? this.activeThreadMessages$ : this.activeChannelMessages$)
|
|
705
|
+
.pipe(take(1))
|
|
706
|
+
.subscribe((m) => (messages = m));
|
|
707
|
+
const newMessage = messages[messages.length - 1];
|
|
708
|
+
return newMessage;
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
/**
|
|
712
|
+
* Jumps to the selected message inside the message list, if the message is not yet loaded, it'll load the message (and it's surroundings) from the API.
|
|
713
|
+
* @param messageId The ID of the message to be loaded, 'latest' means jump to the latest messages
|
|
714
|
+
* @param parentMessageId The ID of the parent message if we want to load a thread message
|
|
715
|
+
*/
|
|
716
|
+
async jumpToMessage(messageId, parentMessageId) {
|
|
717
|
+
this.isMessageLoadingInProgress = true;
|
|
718
|
+
const activeChannel = this.activeChannelSubject.getValue();
|
|
719
|
+
try {
|
|
720
|
+
await activeChannel?.state.loadMessageIntoState(messageId, parentMessageId);
|
|
721
|
+
const messages = activeChannel?.state.messages || [];
|
|
722
|
+
this.activeChannelMessagesSubject.next([...messages]);
|
|
723
|
+
if (parentMessageId) {
|
|
724
|
+
const parentMessage = messages.find((m) => m.id === parentMessageId);
|
|
725
|
+
void this.setAsActiveParentMessage(parentMessage, 'state');
|
|
726
|
+
}
|
|
727
|
+
this.jumpToMessageSubject.next({
|
|
728
|
+
id: messageId,
|
|
729
|
+
parentId: parentMessageId,
|
|
730
|
+
});
|
|
731
|
+
}
|
|
732
|
+
catch (error) {
|
|
733
|
+
this.notificationService.addTemporaryNotification('streamChat.Message not found');
|
|
734
|
+
throw error;
|
|
735
|
+
}
|
|
736
|
+
finally {
|
|
737
|
+
this.isMessageLoadingInProgress = false;
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
/**
|
|
741
|
+
* Clears the currently selected message to jump
|
|
742
|
+
*/
|
|
743
|
+
clearMessageJump() {
|
|
744
|
+
this.jumpToMessageSubject.next({ id: undefined, parentId: undefined });
|
|
745
|
+
}
|
|
746
|
+
/**
|
|
747
|
+
* Pins the given message in the channel
|
|
748
|
+
* @param message
|
|
749
|
+
*/
|
|
750
|
+
async pinMessage(message) {
|
|
751
|
+
try {
|
|
752
|
+
await this.chatClientService.chatClient?.pinMessage(message);
|
|
753
|
+
this.notificationService.addTemporaryNotification('streamChat.Message pinned', 'success');
|
|
754
|
+
}
|
|
755
|
+
catch (error) {
|
|
756
|
+
this.notificationService.addTemporaryNotification('streamChat.Error pinning message');
|
|
757
|
+
throw error;
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
/**
|
|
761
|
+
* Removes the given message from pinned messages
|
|
762
|
+
* @param message
|
|
763
|
+
*/
|
|
764
|
+
async unpinMessage(message) {
|
|
765
|
+
try {
|
|
766
|
+
await this.chatClientService.chatClient?.unpinMessage(message);
|
|
767
|
+
this.notificationService.addTemporaryNotification('streamChat.Message unpinned', 'success');
|
|
768
|
+
}
|
|
769
|
+
catch (error) {
|
|
770
|
+
this.notificationService.addTemporaryNotification('streamChat.Error removing message pin');
|
|
771
|
+
throw error;
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
/**
|
|
775
|
+
* Reloads all channels and messages. Useful if state is empty due to an error.
|
|
776
|
+
*
|
|
777
|
+
* The SDK will automatically call this after `connection.recovered` event. In other cases it's up to integrators to recover state.
|
|
778
|
+
*
|
|
779
|
+
* Use the `shouldRecoverState$` to know if state recover is necessary.
|
|
780
|
+
* @returns when recovery is completed
|
|
781
|
+
*/
|
|
782
|
+
async recoverState() {
|
|
783
|
+
if (this.isStateRecoveryInProgress$.getValue()) {
|
|
784
|
+
return;
|
|
785
|
+
}
|
|
786
|
+
this.isStateRecoveryInProgress$.next(true);
|
|
787
|
+
try {
|
|
788
|
+
await this.queryChannels('recover-state');
|
|
789
|
+
if (this.activeChannelSubject.getValue()) {
|
|
790
|
+
// Thread messages are not refetched so active thread gets deselected to avoid displaying stale messages
|
|
791
|
+
void this.setAsActiveParentMessage(undefined);
|
|
792
|
+
// Update and reselect message to quote
|
|
793
|
+
const messageToQuote = this.messageToQuoteSubject.getValue();
|
|
794
|
+
this.setChannelState(this.activeChannelSubject.getValue());
|
|
795
|
+
let messages;
|
|
796
|
+
this.activeChannelMessages$
|
|
797
|
+
.pipe(take(1))
|
|
798
|
+
.subscribe((m) => (messages = m));
|
|
799
|
+
const updatedMessageToQuote = messages.find((m) => m.id === messageToQuote?.id);
|
|
800
|
+
if (updatedMessageToQuote) {
|
|
801
|
+
this.selectMessageToQuote(updatedMessageToQuote);
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
finally {
|
|
806
|
+
this.isStateRecoveryInProgress$.next(false);
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
handleNotification(clientEvent) {
|
|
810
|
+
switch (clientEvent.eventType) {
|
|
811
|
+
case 'connection.recovered': {
|
|
812
|
+
void this.recoverState().catch((error) => this.chatClientService.chatClient.logger('warn', `Failed to recover state after connection recovery: ${error}`));
|
|
813
|
+
break;
|
|
814
|
+
}
|
|
815
|
+
case 'user.updated': {
|
|
816
|
+
const activeChannel = this.activeChannelSubject.getValue();
|
|
817
|
+
if (activeChannel) {
|
|
818
|
+
this.activeChannelSubject.next(this.chatClientService.chatClient.activeChannels[activeChannel.cid] || activeChannel);
|
|
819
|
+
this.activeChannelMessagesSubject.next(activeChannel.state.messages.map((m) => {
|
|
820
|
+
m.readBy = getReadBy(m, activeChannel);
|
|
821
|
+
return { ...m };
|
|
822
|
+
}));
|
|
823
|
+
const activeParentMessage = this.activeParentMessageIdSubject.getValue();
|
|
824
|
+
if (activeParentMessage) {
|
|
825
|
+
const messages = activeChannel.state.threads[activeParentMessage];
|
|
826
|
+
this.activeThreadMessagesSubject.next([...messages]);
|
|
827
|
+
}
|
|
828
|
+
this.activeChannelPinnedMessagesSubject.next([
|
|
829
|
+
...activeChannel.state.pinnedMessages,
|
|
830
|
+
]);
|
|
831
|
+
}
|
|
832
|
+
break;
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
watchForActiveChannelEvents(channel) {
|
|
837
|
+
this.activeChannelSubscriptions.push(channel.on('message.new', (event) => {
|
|
838
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
|
839
|
+
event.message && event.message.parent_id
|
|
840
|
+
? event.message.parent_id ===
|
|
841
|
+
this.activeParentMessageIdSubject.getValue()
|
|
842
|
+
? this.activeThreadMessagesSubject.next([
|
|
843
|
+
...channel.state.threads[event.message.parent_id],
|
|
844
|
+
])
|
|
845
|
+
: null
|
|
846
|
+
: this.activeChannelMessagesSubject.next([...channel.state.messages]);
|
|
847
|
+
this.activeChannel$.pipe(first()).subscribe((c) => {
|
|
848
|
+
if (c) {
|
|
849
|
+
this.markRead(c);
|
|
850
|
+
}
|
|
851
|
+
});
|
|
852
|
+
this.updateLatestMessages(event);
|
|
853
|
+
}));
|
|
854
|
+
this.activeChannelSubscriptions.push(channel.on('message.updated', (event) => this.messageUpdated(event)));
|
|
855
|
+
this.activeChannelSubscriptions.push(channel.on('message.deleted', (event) => this.messageUpdated(event)));
|
|
856
|
+
this.activeChannelSubscriptions.push(channel.on('reaction.new', (e) => this.messageReactionEventReceived(e)));
|
|
857
|
+
this.activeChannelSubscriptions.push(channel.on('reaction.deleted', (e) => this.messageReactionEventReceived(e)));
|
|
858
|
+
this.activeChannelSubscriptions.push(channel.on('reaction.updated', (e) => this.messageReactionEventReceived(e)));
|
|
859
|
+
this.activeChannelSubscriptions.push(channel.on('message.read', (e) => {
|
|
860
|
+
let latestMessage;
|
|
861
|
+
let messages;
|
|
862
|
+
this.activeChannelMessages$.pipe(first()).subscribe((m) => {
|
|
863
|
+
messages = m;
|
|
864
|
+
latestMessage = messages[messages.length - 1];
|
|
865
|
+
});
|
|
866
|
+
if (!latestMessage || !e.user) {
|
|
867
|
+
return;
|
|
868
|
+
}
|
|
869
|
+
if (latestMessage.readBy) {
|
|
870
|
+
latestMessage.readBy.splice(0, latestMessage.readBy.length);
|
|
871
|
+
}
|
|
872
|
+
else {
|
|
873
|
+
latestMessage.readBy = [];
|
|
874
|
+
}
|
|
875
|
+
latestMessage.readBy.push(...getReadBy(latestMessage, channel));
|
|
876
|
+
messages[messages.length - 1] = { ...latestMessage };
|
|
877
|
+
this.activeChannelMessagesSubject.next([...messages]);
|
|
878
|
+
}));
|
|
879
|
+
this.activeChannelSubscriptions.push(this.chatClientService.events$
|
|
880
|
+
.pipe(filter((e) => e.eventType === 'notification.mark_unread' &&
|
|
881
|
+
e.event.channel_id === channel.id), map((e) => e.event))
|
|
882
|
+
.subscribe((e) => {
|
|
883
|
+
this.activeChannelLastReadMessageId = e.last_read_message_id;
|
|
884
|
+
this.activeChannelUnreadCount = e.unread_messages;
|
|
885
|
+
this.activeChannelSubject.next(this.activeChannel);
|
|
886
|
+
}));
|
|
887
|
+
this.activeChannelSubscriptions.push(channel.on('typing.start', (e) => this.handleTypingStartEvent(e)));
|
|
888
|
+
this.activeChannelSubscriptions.push(
|
|
889
|
+
// client._startCleaning can emit typing.stop events
|
|
890
|
+
// since client._startCleaning runs outside Angular, we need to reenter Angular here
|
|
891
|
+
channel.on('typing.stop', (e) => this.ngZone.run(() => this.handleTypingStopEvent(e))));
|
|
892
|
+
this.activeChannelSubscriptions.push(channel.on('capabilities.changed', (_) => {
|
|
893
|
+
this.activeChannelSubject.next(this.activeChannelSubject.getValue());
|
|
894
|
+
}));
|
|
895
|
+
this.activeChannelSubscriptions.push(channel.on('channel.updated', (_) => {
|
|
896
|
+
this.activeChannelSubject.next(this.activeChannelSubject.getValue());
|
|
897
|
+
}));
|
|
898
|
+
this.activeChannelSubscriptions.push(channel.on('channel.truncated', (_) => {
|
|
899
|
+
this.activeChannelSubject.next(this.activeChannelSubject.getValue());
|
|
900
|
+
this.activeChannelMessagesSubject.next([]);
|
|
901
|
+
void this.setAsActiveParentMessage(undefined);
|
|
902
|
+
}));
|
|
903
|
+
}
|
|
904
|
+
/**
|
|
905
|
+
* Call this method if user started typing in the active channel
|
|
906
|
+
* @param parentId The id of the parent message, if user is typing in a thread
|
|
907
|
+
*/
|
|
908
|
+
async typingStarted(parentId) {
|
|
909
|
+
const activeChannel = this.activeChannelSubject.getValue();
|
|
910
|
+
await activeChannel?.keystroke(parentId);
|
|
911
|
+
}
|
|
912
|
+
/**
|
|
913
|
+
* Call this method if user stopped typing in the active channel
|
|
914
|
+
* @param parentId The id of the parent message, if user were typing in a thread
|
|
915
|
+
*/
|
|
916
|
+
async typingStopped(parentId) {
|
|
917
|
+
const activeChannel = this.activeChannelSubject.getValue();
|
|
918
|
+
await activeChannel?.stopTyping(parentId);
|
|
919
|
+
}
|
|
920
|
+
/**
|
|
921
|
+
* The current list of channels
|
|
922
|
+
*/
|
|
923
|
+
get channels() {
|
|
924
|
+
return this.channelsSubject.getValue() || [];
|
|
925
|
+
}
|
|
926
|
+
/**
|
|
927
|
+
* The current active channel
|
|
928
|
+
*/
|
|
929
|
+
get activeChannel() {
|
|
930
|
+
return this.activeChannelSubject.getValue() || undefined;
|
|
931
|
+
}
|
|
932
|
+
/**
|
|
933
|
+
* The current active channel messages
|
|
934
|
+
*/
|
|
935
|
+
get activeChannelMessages() {
|
|
936
|
+
return this.activeChannelMessagesSubject.getValue() || [];
|
|
937
|
+
}
|
|
938
|
+
/**
|
|
939
|
+
* The current thread replies
|
|
940
|
+
*/
|
|
941
|
+
get activeChannelThreadReplies() {
|
|
942
|
+
return this.activeThreadMessagesSubject.getValue() || [];
|
|
943
|
+
}
|
|
944
|
+
/**
|
|
945
|
+
* Get the last 1200 reactions of a message in the current active channel. If you need to fetch more reactions please use the [following endpoint](/chat/docs/javascript/send_reaction/#paginating-reactions).
|
|
946
|
+
* @deprecated use [`messageReactionsService.queryReactions()`](/chat/docs/sdk/angular/services/MessageReactionsService/#queryreactions) instead
|
|
947
|
+
* @param messageId
|
|
948
|
+
* @returns all reactions of a message
|
|
949
|
+
*/
|
|
950
|
+
async getMessageReactions(messageId) {
|
|
951
|
+
const reactions = [];
|
|
952
|
+
const limit = 300;
|
|
953
|
+
let offset = 0;
|
|
954
|
+
const reactionsLimit = ChannelService.MAX_MESSAGE_REACTIONS_TO_FETCH;
|
|
955
|
+
let lastPageSize = limit;
|
|
956
|
+
while (lastPageSize === limit && reactions.length < reactionsLimit) {
|
|
957
|
+
try {
|
|
958
|
+
const response = await this.activeChannel?.getReactions(messageId, {
|
|
959
|
+
offset,
|
|
960
|
+
limit,
|
|
961
|
+
});
|
|
962
|
+
lastPageSize = response?.reactions?.length || 0;
|
|
963
|
+
if (lastPageSize > 0) {
|
|
964
|
+
reactions.push(...response.reactions);
|
|
965
|
+
}
|
|
966
|
+
offset += lastPageSize;
|
|
967
|
+
}
|
|
968
|
+
catch (e) {
|
|
969
|
+
this.notificationService.addTemporaryNotification('streamChat.Error loading reactions');
|
|
970
|
+
throw e;
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
return reactions;
|
|
974
|
+
}
|
|
975
|
+
/**
|
|
976
|
+
* Marks the channel from the given message as unread
|
|
977
|
+
* @param messageId
|
|
978
|
+
* @returns the result of the request
|
|
979
|
+
*/
|
|
980
|
+
async markMessageUnread(messageId) {
|
|
981
|
+
if (!this.activeChannel) {
|
|
982
|
+
return;
|
|
983
|
+
}
|
|
984
|
+
try {
|
|
985
|
+
const response = await this.activeChannel.markUnread({
|
|
986
|
+
message_id: messageId,
|
|
987
|
+
});
|
|
988
|
+
this.areReadEventsPaused = true;
|
|
989
|
+
return response;
|
|
990
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
991
|
+
}
|
|
992
|
+
catch (e) {
|
|
993
|
+
const error = JSON.parse(JSON.stringify(e));
|
|
994
|
+
const data = error?.response?.data;
|
|
995
|
+
if (data &&
|
|
996
|
+
data.code === 4 &&
|
|
997
|
+
data.StatusCode === 400 &&
|
|
998
|
+
data.message?.includes('it is older than last')) {
|
|
999
|
+
const count = /\d+ channel messages/
|
|
1000
|
+
.exec(data.message)?.[0]
|
|
1001
|
+
.match(/\d+/)?.[0];
|
|
1002
|
+
if (count) {
|
|
1003
|
+
this.notificationService.addTemporaryNotification('streamChat.Error, only the first {{count}} message can be marked as unread', undefined, undefined, { count });
|
|
1004
|
+
throw e;
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
this.notificationService.addTemporaryNotification('streamChat.Error marking message as unread');
|
|
1008
|
+
throw e;
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
messageUpdated(event) {
|
|
1012
|
+
const isThreadReply = event.message && event.message.parent_id;
|
|
1013
|
+
const channel = this.activeChannelSubject.getValue();
|
|
1014
|
+
if (!channel) {
|
|
1015
|
+
return;
|
|
1016
|
+
}
|
|
1017
|
+
// Get messages from state as message order could change, and message could've been deleted
|
|
1018
|
+
const messages = isThreadReply
|
|
1019
|
+
? channel.state.threads[event?.message?.parent_id || '']
|
|
1020
|
+
: channel.state.messages;
|
|
1021
|
+
if (!messages) {
|
|
1022
|
+
return;
|
|
1023
|
+
}
|
|
1024
|
+
const messageIndex = messages.findIndex((m) => m.id === event?.message?.id);
|
|
1025
|
+
if (messageIndex !== -1 || event.type === 'message.deleted') {
|
|
1026
|
+
isThreadReply
|
|
1027
|
+
? this.activeThreadMessagesSubject.next([...messages])
|
|
1028
|
+
: this.activeChannelMessagesSubject.next([...messages]);
|
|
1029
|
+
this.activeChannelPinnedMessagesSubject.next([
|
|
1030
|
+
...channel.state.pinnedMessages,
|
|
1031
|
+
]);
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
messageReactionEventReceived(e) {
|
|
1035
|
+
const isThreadMessage = e.message && e.message.parent_id;
|
|
1036
|
+
let messages;
|
|
1037
|
+
(isThreadMessage ? this.activeThreadMessages$ : this.activeChannelMessages$)
|
|
1038
|
+
.pipe(first())
|
|
1039
|
+
.subscribe((m) => (messages = m));
|
|
1040
|
+
const messageIndex = messages.findIndex((m) => m.id === e?.message?.id);
|
|
1041
|
+
if (messageIndex === -1) {
|
|
1042
|
+
return;
|
|
1043
|
+
}
|
|
1044
|
+
const message = messages[messageIndex];
|
|
1045
|
+
message.reaction_counts = { ...e.message?.reaction_counts };
|
|
1046
|
+
message.reaction_scores = { ...e.message?.reaction_scores };
|
|
1047
|
+
message.latest_reactions = [...(e.message?.latest_reactions || [])];
|
|
1048
|
+
message.own_reactions = [...(e.message?.own_reactions || [])];
|
|
1049
|
+
message.reaction_groups = { ...e.message?.reaction_groups };
|
|
1050
|
+
messages[messageIndex] = { ...message };
|
|
1051
|
+
isThreadMessage
|
|
1052
|
+
? this.activeThreadMessagesSubject.next([...messages])
|
|
1053
|
+
: this.activeChannelMessagesSubject.next([...messages]);
|
|
1054
|
+
}
|
|
1055
|
+
formatMessage(message) {
|
|
1056
|
+
const m = message;
|
|
1057
|
+
m.pinned_at = message.pinned_at ? new Date(message.pinned_at) : null;
|
|
1058
|
+
m.created_at = message.created_at
|
|
1059
|
+
? new Date(message.created_at)
|
|
1060
|
+
: new Date();
|
|
1061
|
+
m.updated_at = message.updated_at
|
|
1062
|
+
? new Date(message.updated_at)
|
|
1063
|
+
: new Date();
|
|
1064
|
+
message.status = message.status || 'received';
|
|
1065
|
+
return m;
|
|
1066
|
+
}
|
|
1067
|
+
isStreamMessage(message) {
|
|
1068
|
+
return !!message.readBy;
|
|
1069
|
+
}
|
|
1070
|
+
isFormatMessageResponse(message) {
|
|
1071
|
+
return message.created_at instanceof Date;
|
|
1072
|
+
}
|
|
1073
|
+
stopWatchForActiveChannelEvents(channel) {
|
|
1074
|
+
if (!channel) {
|
|
1075
|
+
return;
|
|
1076
|
+
}
|
|
1077
|
+
this.activeChannelSubscriptions.forEach((s) => s.unsubscribe());
|
|
1078
|
+
this.activeChannelSubscriptions = [];
|
|
1079
|
+
}
|
|
1080
|
+
async queryChannels(queryType) {
|
|
1081
|
+
if (!this.channelManager) {
|
|
1082
|
+
throw new Error('Query channels called before initializing ChannelService');
|
|
1083
|
+
}
|
|
1084
|
+
try {
|
|
1085
|
+
this.channelQueryStateSubject.next({ state: 'in-progress' });
|
|
1086
|
+
if (this.customChannelQuery) {
|
|
1087
|
+
const result = await this.customChannelQuery(queryType);
|
|
1088
|
+
const currentChannels = this.channels;
|
|
1089
|
+
const filteredChannels = result.channels.filter((channel, index) => !currentChannels.slice(0, index).find((c) => c.cid === channel.cid));
|
|
1090
|
+
this.channelManager.setChannels(filteredChannels);
|
|
1091
|
+
this.hasMoreChannelsSubject.next(result.hasMorePage);
|
|
1092
|
+
}
|
|
1093
|
+
else {
|
|
1094
|
+
if (queryType === 'first-page' || queryType === 'recover-state') {
|
|
1095
|
+
if (!this.channelQueryConfig) {
|
|
1096
|
+
throw new Error('Channel query config not initialized');
|
|
1097
|
+
}
|
|
1098
|
+
await this.channelManager.queryChannels({ ...this.channelQueryConfig.filters }, this.channelQueryConfig.sort, this.channelQueryConfig.options);
|
|
1099
|
+
}
|
|
1100
|
+
else {
|
|
1101
|
+
await this.channelManager.loadNext();
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
if (this.channelManagerSubscriptions.length === 0) {
|
|
1105
|
+
this.channelManagerSubscriptions.push(this.channelManager.state.subscribeWithSelector((s) => ({ channels: s.channels }), ({ channels }) => {
|
|
1106
|
+
const activeChannel = this.activeChannel;
|
|
1107
|
+
if (!this.isStateRecoveryInProgress$.getValue() &&
|
|
1108
|
+
activeChannel &&
|
|
1109
|
+
!channels.find((c) => c.cid === activeChannel.cid)) {
|
|
1110
|
+
this.deselectActiveChannel();
|
|
1111
|
+
}
|
|
1112
|
+
this.channelsSubject.next(channels);
|
|
1113
|
+
}));
|
|
1114
|
+
if (!this.customChannelQuery) {
|
|
1115
|
+
this.channelManagerSubscriptions.push(this.channelManager.state.subscribeWithSelector((s) => ({ hasNext: s.pagination?.hasNext ?? true }), ({ hasNext }) => this.hasMoreChannelsSubject.next(hasNext)));
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
if (queryType === 'recover-state') {
|
|
1119
|
+
await this.maybeRestoreActiveChannelAfterRecovery();
|
|
1120
|
+
}
|
|
1121
|
+
const activeChannel = this.activeChannelSubject.getValue();
|
|
1122
|
+
const shouldSetActiveChannel = queryType === 'next-page' ? false : this.shouldSetActiveChannel;
|
|
1123
|
+
if (this.channels.length > 0 &&
|
|
1124
|
+
!activeChannel &&
|
|
1125
|
+
shouldSetActiveChannel) {
|
|
1126
|
+
this.setAsActiveChannel(this.channels[0]);
|
|
1127
|
+
}
|
|
1128
|
+
this.channelQueryStateSubject.next({ state: 'success' });
|
|
1129
|
+
this.dismissErrorNotification?.();
|
|
1130
|
+
return this.channels;
|
|
1131
|
+
}
|
|
1132
|
+
catch (error) {
|
|
1133
|
+
this.channelQueryStateSubject.next({
|
|
1134
|
+
state: 'error',
|
|
1135
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
1136
|
+
error,
|
|
1137
|
+
});
|
|
1138
|
+
if (queryType === 'recover-state') {
|
|
1139
|
+
this.deselectActiveChannel();
|
|
1140
|
+
this.channelManager.setChannels([]);
|
|
1141
|
+
}
|
|
1142
|
+
if (queryType !== 'next-page') {
|
|
1143
|
+
this.dismissErrorNotification =
|
|
1144
|
+
this.notificationService.addPermanentNotification('streamChat.Error loading channels', 'error');
|
|
1145
|
+
}
|
|
1146
|
+
throw error;
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
get canSendReadEvents() {
|
|
1150
|
+
const channel = this.activeChannelSubject.getValue();
|
|
1151
|
+
if (!channel) {
|
|
1152
|
+
return false;
|
|
1153
|
+
}
|
|
1154
|
+
const capabilites = channel.data?.own_capabilities;
|
|
1155
|
+
return capabilites.indexOf('read-events') !== -1;
|
|
1156
|
+
}
|
|
1157
|
+
transformToStreamMessage(message, channel) {
|
|
1158
|
+
const isThreadMessage = !!message.parent_id;
|
|
1159
|
+
if (this.isStreamMessage(message) &&
|
|
1160
|
+
this.isFormatMessageResponse(message)) {
|
|
1161
|
+
if (message.quoted_message) {
|
|
1162
|
+
message.quoted_message.translation = getMessageTranslation(message.quoted_message, channel, this.chatClientService.chatClient.user);
|
|
1163
|
+
}
|
|
1164
|
+
message.translation = getMessageTranslation(message, channel, this.chatClientService.chatClient.user);
|
|
1165
|
+
return message;
|
|
1166
|
+
}
|
|
1167
|
+
else {
|
|
1168
|
+
if (message.quoted_message) {
|
|
1169
|
+
message.quoted_message.translation = getMessageTranslation(message.quoted_message, channel, this.chatClientService.chatClient.user);
|
|
1170
|
+
}
|
|
1171
|
+
if (this.isFormatMessageResponse(message)) {
|
|
1172
|
+
message.readBy = isThreadMessage
|
|
1173
|
+
? []
|
|
1174
|
+
: channel
|
|
1175
|
+
? getReadBy(message, channel)
|
|
1176
|
+
: [];
|
|
1177
|
+
message.translation = getMessageTranslation(message, channel, this.chatClientService.chatClient.user);
|
|
1178
|
+
return message;
|
|
1179
|
+
}
|
|
1180
|
+
else {
|
|
1181
|
+
message = this.formatMessage(message);
|
|
1182
|
+
message.readBy = isThreadMessage
|
|
1183
|
+
? []
|
|
1184
|
+
: channel
|
|
1185
|
+
? getReadBy(message, channel)
|
|
1186
|
+
: [];
|
|
1187
|
+
message.translation = getMessageTranslation(message, channel, this.chatClientService.chatClient.user);
|
|
1188
|
+
return message;
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
handleTypingStartEvent(event) {
|
|
1193
|
+
if (event.user?.id === this.chatClientService.chatClient.user?.id) {
|
|
1194
|
+
return;
|
|
1195
|
+
}
|
|
1196
|
+
const isTypingInThread = !!event.parent_id;
|
|
1197
|
+
if (isTypingInThread &&
|
|
1198
|
+
event.parent_id !== this.activeParentMessageIdSubject.getValue()) {
|
|
1199
|
+
return;
|
|
1200
|
+
}
|
|
1201
|
+
const subject = isTypingInThread
|
|
1202
|
+
? this.usersTypingInThreadSubject
|
|
1203
|
+
: this.usersTypingInChannelSubject;
|
|
1204
|
+
const users = subject.getValue();
|
|
1205
|
+
const user = event.user;
|
|
1206
|
+
if (user && !users.find((u) => u.id === user.id)) {
|
|
1207
|
+
users.push(user);
|
|
1208
|
+
subject.next([...users]);
|
|
1209
|
+
}
|
|
1210
|
+
}
|
|
1211
|
+
handleTypingStopEvent(event) {
|
|
1212
|
+
const usersTypingInChannel = this.usersTypingInChannelSubject.getValue();
|
|
1213
|
+
const usersTypingInThread = this.usersTypingInThreadSubject.getValue();
|
|
1214
|
+
const user = event.user;
|
|
1215
|
+
if (user && usersTypingInChannel.find((u) => u.id === user.id)) {
|
|
1216
|
+
usersTypingInChannel.splice(usersTypingInChannel.findIndex((u) => u.id === user.id), 1);
|
|
1217
|
+
this.usersTypingInChannelSubject.next([...usersTypingInChannel]);
|
|
1218
|
+
return;
|
|
1219
|
+
}
|
|
1220
|
+
if (user && usersTypingInThread.find((u) => u.id === user.id)) {
|
|
1221
|
+
usersTypingInThread.splice(usersTypingInThread.findIndex((u) => u.id === user.id), 1);
|
|
1222
|
+
this.usersTypingInThreadSubject.next([...usersTypingInThread]);
|
|
1223
|
+
return;
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
updateLatestMessages(event) {
|
|
1227
|
+
if (event.message?.user?.id !== this.chatClientService?.chatClient.user?.id) {
|
|
1228
|
+
return;
|
|
1229
|
+
}
|
|
1230
|
+
const latestMessages = this.latestMessageDateByUserByChannelsSubject.getValue();
|
|
1231
|
+
if (!event.message?.created_at) {
|
|
1232
|
+
return;
|
|
1233
|
+
}
|
|
1234
|
+
const channelId = event?.message?.cid;
|
|
1235
|
+
if (!channelId) {
|
|
1236
|
+
return;
|
|
1237
|
+
}
|
|
1238
|
+
const messageDate = new Date(event.message.created_at);
|
|
1239
|
+
if (!latestMessages[channelId] ||
|
|
1240
|
+
latestMessages[channelId]?.getTime() < messageDate.getTime()) {
|
|
1241
|
+
latestMessages[channelId] = messageDate;
|
|
1242
|
+
this.latestMessageDateByUserByChannelsSubject.next({
|
|
1243
|
+
...latestMessages,
|
|
1244
|
+
});
|
|
1245
|
+
}
|
|
1246
|
+
}
|
|
1247
|
+
setChannelState(channel) {
|
|
1248
|
+
channel.state.messages.forEach((m) => {
|
|
1249
|
+
m.readBy = getReadBy(m, channel);
|
|
1250
|
+
m.translation = getMessageTranslation(m, channel, this.chatClientService.chatClient.user);
|
|
1251
|
+
if (m.quoted_message) {
|
|
1252
|
+
m.quoted_message.translation = getMessageTranslation(m.quoted_message, channel, this.chatClientService.chatClient.user);
|
|
1253
|
+
}
|
|
1254
|
+
});
|
|
1255
|
+
this.markRead(channel);
|
|
1256
|
+
this.activeChannelMessagesSubject.next([...channel.state.messages]);
|
|
1257
|
+
this.activeChannelPinnedMessagesSubject.next([
|
|
1258
|
+
...channel.state.pinnedMessages,
|
|
1259
|
+
]);
|
|
1260
|
+
this.activeParentMessageIdSubject.next(undefined);
|
|
1261
|
+
this.activeThreadMessagesSubject.next([]);
|
|
1262
|
+
this.messageToQuoteSubject.next(undefined);
|
|
1263
|
+
this.usersTypingInChannelSubject.next([]);
|
|
1264
|
+
this.usersTypingInThreadSubject.next([]);
|
|
1265
|
+
}
|
|
1266
|
+
markRead(channel, isThrottled = true) {
|
|
1267
|
+
if (this.canSendReadEvents &&
|
|
1268
|
+
this.shouldMarkActiveChannelAsRead &&
|
|
1269
|
+
!this.areReadEventsPaused) {
|
|
1270
|
+
if (isThrottled) {
|
|
1271
|
+
this.markReadThrottled(channel);
|
|
1272
|
+
}
|
|
1273
|
+
else {
|
|
1274
|
+
void channel.markRead();
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
markReadThrottled(channel) {
|
|
1279
|
+
if (!this.markReadTimeout) {
|
|
1280
|
+
this.markRead(channel, false);
|
|
1281
|
+
this.markReadTimeout = setTimeout(() => {
|
|
1282
|
+
this.flushMarkReadQueue();
|
|
1283
|
+
}, this.markReadThrottleTime);
|
|
1284
|
+
}
|
|
1285
|
+
else {
|
|
1286
|
+
clearTimeout(this.markReadTimeout);
|
|
1287
|
+
this.scheduledMarkReadRequest = () => this.markRead(channel, false);
|
|
1288
|
+
this.markReadTimeout = setTimeout(() => {
|
|
1289
|
+
this.flushMarkReadQueue();
|
|
1290
|
+
}, this.markReadThrottleTime);
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
flushMarkReadQueue() {
|
|
1294
|
+
this.scheduledMarkReadRequest?.();
|
|
1295
|
+
this.scheduledMarkReadRequest = undefined;
|
|
1296
|
+
clearTimeout(this.markReadTimeout);
|
|
1297
|
+
this.markReadTimeout = undefined;
|
|
1298
|
+
}
|
|
1299
|
+
_init(options) {
|
|
1300
|
+
this.messagePageSize = options.messagePageSize;
|
|
1301
|
+
this.shouldSetActiveChannel =
|
|
1302
|
+
options?.shouldSetActiveChannel ?? this.shouldSetActiveChannel;
|
|
1303
|
+
const eventHandlerOverrides = options?.eventHandlerOverrides;
|
|
1304
|
+
const managerOptions = { ...options };
|
|
1305
|
+
delete managerOptions?.eventHandlerOverrides;
|
|
1306
|
+
delete managerOptions?.shouldSetActiveChannel;
|
|
1307
|
+
this.createChannelManager({
|
|
1308
|
+
eventHandlerOverrides,
|
|
1309
|
+
options: managerOptions,
|
|
1310
|
+
});
|
|
1311
|
+
this.clientEventsSubscription = this.chatClientService.events$.subscribe((notification) => void this.handleNotification(notification));
|
|
1312
|
+
return this.queryChannels('first-page');
|
|
1313
|
+
}
|
|
1314
|
+
createChannelManager({ eventHandlerOverrides, options, }) {
|
|
1315
|
+
this.channelManager = new ChannelManager({
|
|
1316
|
+
client: this.chatClientService.chatClient,
|
|
1317
|
+
options: {
|
|
1318
|
+
...options,
|
|
1319
|
+
allowNotLoadedChannelPromotionForEvent: {
|
|
1320
|
+
'message.new': false,
|
|
1321
|
+
'channel.visible': true,
|
|
1322
|
+
'notification.added_to_channel': true,
|
|
1323
|
+
'notification.message_new': true,
|
|
1324
|
+
...options?.allowNotLoadedChannelPromotionForEvent,
|
|
1325
|
+
},
|
|
1326
|
+
},
|
|
1327
|
+
eventHandlerOverrides,
|
|
1328
|
+
});
|
|
1329
|
+
this.channelManager.registerSubscriptions();
|
|
1330
|
+
}
|
|
1331
|
+
destroyChannelManager() {
|
|
1332
|
+
this.channelManager?.unregisterSubscriptions();
|
|
1333
|
+
this.channelManager = undefined;
|
|
1334
|
+
this.channelManagerSubscriptions.forEach((unsubscribe) => unsubscribe());
|
|
1335
|
+
this.channelManagerSubscriptions = [];
|
|
1336
|
+
this.channelsSubject.next(undefined);
|
|
1337
|
+
this.hasMoreChannelsSubject.next(true);
|
|
1338
|
+
}
|
|
1339
|
+
async maybeRestoreActiveChannelAfterRecovery() {
|
|
1340
|
+
const previousActiveChannel = this.activeChannelSubject.getValue();
|
|
1341
|
+
if (!previousActiveChannel) {
|
|
1342
|
+
return;
|
|
1343
|
+
}
|
|
1344
|
+
try {
|
|
1345
|
+
if (!this.channels.find((c) => c.cid === previousActiveChannel?.cid)) {
|
|
1346
|
+
await previousActiveChannel.watch();
|
|
1347
|
+
// Thread messages are not refetched so active thread gets deselected to avoid displaying stale messages
|
|
1348
|
+
void this.setAsActiveParentMessage(undefined);
|
|
1349
|
+
// Update and reselect message to quote
|
|
1350
|
+
const messageToQuote = this.messageToQuoteSubject.getValue();
|
|
1351
|
+
this.setChannelState(previousActiveChannel);
|
|
1352
|
+
let messages;
|
|
1353
|
+
this.activeChannelMessages$
|
|
1354
|
+
.pipe(take(1))
|
|
1355
|
+
.subscribe((m) => (messages = m));
|
|
1356
|
+
const updatedMessageToQuote = messages.find((m) => m.id === messageToQuote?.id);
|
|
1357
|
+
if (updatedMessageToQuote) {
|
|
1358
|
+
this.selectMessageToQuote(updatedMessageToQuote);
|
|
1359
|
+
}
|
|
1360
|
+
this.channelManager?.setChannels(promoteChannel({
|
|
1361
|
+
channels: this.channels,
|
|
1362
|
+
channelToMove: previousActiveChannel,
|
|
1363
|
+
sort: this.channelQueryConfig?.sort ?? [],
|
|
1364
|
+
}));
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
1367
|
+
catch (error) {
|
|
1368
|
+
this.chatClientService.chatClient.logger('warn', 'Unable to refetch active channel after state recover', error);
|
|
1369
|
+
this.deselectActiveChannel();
|
|
1370
|
+
}
|
|
1371
|
+
}
|
|
1372
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0", ngImport: i0, type: ChannelService, deps: [{ token: i1.ChatClientService }, { token: i0.NgZone }, { token: i2.NotificationService }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1373
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.0", ngImport: i0, type: ChannelService, providedIn: 'root' }); }
|
|
1374
|
+
}
|
|
1375
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0", ngImport: i0, type: ChannelService, decorators: [{
|
|
1376
|
+
type: Injectable,
|
|
1377
|
+
args: [{
|
|
1378
|
+
providedIn: 'root',
|
|
1379
|
+
}]
|
|
1380
|
+
}], ctorParameters: () => [{ type: i1.ChatClientService }, { type: i0.NgZone }, { type: i2.NotificationService }] });
|
|
1381
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hhbm5lbC5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vcHJvamVjdHMvc3RyZWFtLWNoYXQtYW5ndWxhci9zcmMvbGliL2NoYW5uZWwuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFVLE1BQU0sZUFBZSxDQUFDO0FBQ25ELE9BQU8sRUFDTCxlQUFlLEVBQ2YsYUFBYSxFQUViLGFBQWEsR0FFZCxNQUFNLE1BQU0sQ0FBQztBQUNkLE9BQU8sRUFDTCxvQkFBb0IsRUFDcEIsTUFBTSxFQUNOLEtBQUssRUFDTCxHQUFHLEVBQ0gsV0FBVyxFQUNYLElBQUksR0FDTCxNQUFNLGdCQUFnQixDQUFDO0FBQ3hCLE9BQU8sRUFHTCxjQUFjLEVBUWQsY0FBYyxHQUtmLE1BQU0sYUFBYSxDQUFDO0FBRXJCLE9BQU8sRUFBRSxxQkFBcUIsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQ2xFLE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBRXpELE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxXQUFXLENBQUM7Ozs7QUFnQnRDOztHQUVHO0FBSUgsTUFBTSxPQUFPLGNBQWM7SUFnSXpCOztPQUVHO2FBQ2EsbUNBQThCLEdBQUcsSUFBSSxBQUFQLENBQVE7SUFpRXRELFlBQ1UsaUJBQXVDLEVBQ3ZDLE1BQWMsRUFDZCxtQkFBd0M7UUFGeEMsc0JBQWlCLEdBQWpCLGlCQUFpQixDQUFzQjtRQUN2QyxXQUFNLEdBQU4sTUFBTSxDQUFRO1FBQ2Qsd0JBQW1CLEdBQW5CLG1CQUFtQixDQUFxQjtRQW5FbEQ7O1dBRUc7UUFDSCwrQkFBMEIsR0FBRyxLQUFLLENBQUM7UUFDbkM7O1dBRUc7UUFDSCxvQkFBZSxHQUFHLEVBQUUsQ0FBQztRQUNiLG9CQUFlLEdBQUcsSUFBSSxlQUFlLENBQzNDLFNBQVMsQ0FDVixDQUFDO1FBQ00seUJBQW9CLEdBQUcsSUFBSSxl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Q0FBQyxVQUFVLENBQUMsTUFBTSxDQUN0QyxNQUFNLEVBQ04sc0RBQXNELEVBQ3RELEtBQWdDLENBQ2pDLENBQUM7WUFDRixJQUFJLENBQUMscUJBQXFCLEVBQUUsQ0FBQztTQUM5QjtJQUNILENBQUM7OEdBLzFEVSxjQUFjO2tIQUFkLGNBQWMsY0FGYixNQUFNOzsyRkFFUCxjQUFjO2tCQUgxQixVQUFVO21CQUFDO29CQUNWLFVBQVUsRUFBRSxNQUFNO2lCQUNuQiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEluamVjdGFibGUsIE5nWm9uZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHtcbiAgQmVoYXZpb3JTdWJqZWN0LFxuICBjb21iaW5lTGF0ZXN0LFxuICBPYnNlcnZhYmxlLFxuICBSZXBsYXlTdWJqZWN0LFxuICBTdWJzY3JpcHRpb24sXG59IGZyb20gJ3J4anMnO1xuaW1wb3J0IHtcbiAgZGlzdGluY3RVbnRpbENoYW5nZWQsXG4gIGZpbHRlcixcbiAgZmlyc3QsXG4gIG1hcCxcbiAgc2hhcmVSZXBsYXksXG4gIHRha2UsXG59IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcbmltcG9ydCB7XG4gIEF0dGFjaG1lbnQsXG4gIENoYW5uZWwsXG4gIENoYW5uZWxNYW5hZ2VyLFxuICBDaGFubmVsTWFuYWdlckV2ZW50SGFuZGxlck92ZXJyaWRlcyxcbiAgQ2hhbm5lbE1hbmFnZXJPcHRpb25zLFxuICBFdmVudCxcbiAgRm9ybWF0TWVzc2FnZVJlc3BvbnNlLFxuICBNZW1iZXJGaWx0ZXJzLFxuICBNZXNzYWdlLFxuICBNZXNzYWdlUmVzcG9uc2UsXG4gIHByb21vdGVDaGFubmVsLFxuICBSZWFjdGlvblJlc3BvbnNlLFxuICBVbnN1YnNjcmliZSxcbiAgVXBkYXRlZE1lc3NhZ2UsXG4gIFVzZXJSZXNwb25zZSxcbn0gZnJvbSAnc3RyZWFtLWNoYXQnO1xuaW1wb3J0IHsgQ2hhdENsaWVudFNlcnZpY2UsIENsaWVudEV2ZW50IH0gZnJvbSAnLi9jaGF0LWNsaWVudC5zZXJ2aWNlJztcbmltcG9ydCB7IGdldE1lc3NhZ2VUcmFuc2xhdGlvbiB9IGZyb20gJy4vZ2V0LW1lc3NhZ2UtdHJhbnNsYXRpb24nO1xuaW1wb3J0IHsgY3JlYXRlTWVzc2FnZVByZXZpZXcgfSBmcm9tICcuL21lc3NhZ2UtcHJldmlldyc7XG5pbXBvcnQgeyBOb3RpZmljYXRpb25TZXJ2aWNlIH0gZnJvbSAnLi9ub3RpZmljYXRpb24uc2VydmljZSc7XG5pbXBvcnQgeyBnZXRSZWFkQnkgfSBmcm9tICcuL3JlYWQtYnknO1xuaW1wb3J0IHtcbiAgQXR0YWNobWVudFVwbG9hZCxcbiAgQXR0YWNobWVudFVwbG9hZEVycm9yUmVhc29uLFxuICBDaGFubmVsUXVlcnlDb25maWcsXG4gIENoYW5uZWxRdWVyeUNvbmZpZ0lucHV0LFxuICBDaGFubmVsUXVlcnlSZXN1bHQsXG4gIENoYW5uZWxRdWVyeVN0YXRlLFxuICBDaGFubmVsUXVlcnlUeXBlLFxuICBDaGFubmVsU2VydmljZU9wdGlvbnMsXG4gIERlZmF1bHRTdHJlYW1DaGF0R2VuZXJpY3MsXG4gIE1lc3NhZ2VJbnB1dCxcbiAgTWVzc2FnZVJlYWN0aW9uVHlwZSxcbiAgU3RyZWFtTWVzc2FnZSxcbn0gZnJvbSAnLi90eXBlcyc7XG5cbi8qKlxuICogVGhlIGBDaGFubmVsU2VydmljZWAgcHJvdmlkZXMgZGF0YSBhbmQgaW50ZXJhY3Rpb24gZm9yIHRoZSBjaGFubmVsIGxpc3QgYW5kIG1lc3NhZ2UgbGlzdC5cbiAqL1xuQEluamVjdGFibGUoe1xuICBwcm92aWRlZEluOiAncm9vdCcsXG59KVxuZXhwb3J0IGNsYXNzIENoYW5uZWxTZXJ2aWNlPFxuICBUIGV4dGVuZHMgRGVmYXVsdFN0cmVhbUNoYXRHZW5lcmljcyA9IERlZmF1bHRTdHJlYW1DaGF0R2VuZXJpY3MsXG4+IHtcbiAgLyoqXG4gICAqIEVtaXRzIGBmYWxzZWAgaWYgdGhlcmUgYXJlIG5vIG1vcmUgcGFnZXMgb2YgY2hhbm5lbHMgdGhhdCBjYW4gYmUgbG9hZGVkLlxuICAgKi9cbiAgaGFzTW9yZUNoYW5uZWxzJDogT2JzZXJ2YWJsZTxib29sZWFuPjtcbiAgLyoqXG4gICAqIEVtaXRzIHRoZSBjdXJyZW50bHkgbG9hZGVkIGFuZCBbd2F0Y2hlZF0oL2NoYXQvZG9jcy9qYXZhc2NyaXB0L3dhdGNoX2NoYW5uZWwvKSBjaGFubmVsIGxpc3QuXG4gICAqL1xuICBjaGFubmVscyQ6IE9ic2VydmFibGU8Q2hhbm5lbDxUPltdIHwgdW5kZWZpbmVkPjtcbiAgLyoqXG4gICAqIFRoZSByZXN1bHQgb2YgdGhlIGxhdGVzdCBjaGFubmVsIHF1ZXJ5IHJlcXVlc3QuXG4gICAqL1xuICBjaGFubmVsUXVlcnlTdGF0ZSQ6IE9ic2VydmFibGU8Q2hhbm5lbFF1ZXJ5U3RhdGUgfCB1bmRlZmluZWQ+O1xuICAvKipcbiAgICogRW1pdHMgYHRydWVgIHdoZW4gdGhlIHN0YXRlIG5lZWRzIHRvIGJlIHJlY292ZXJlZCBhZnRlciBhbiBlcnJvclxuICAgKlxuICAgKiBZb3UgY2FuIHJlY292ZXIgaXQgYnkgY2FsbGluZyB0aGUgYHJlY292ZXJTdGF0ZWAgbWV0aG9kXG4gICAqL1xuICBzaG91bGRSZWNvdmVyU3RhdGUkOiBPYnNlcnZhYmxlPGJvb2xlYW4+O1xuICAvKipcbiAgICogRW1pdHMgdGhlIGN1cnJlbnRseSBhY3RpdmUgY2hhbm5lbC5cbiAgICpcbiAgICogVGhlIGFjdGl2ZSBjaGFubmVsIHdpbGwgYWx3YXlzIGJlIG1hcmtlZCBhcyByZWFkIHdoZW4gYSBuZXcgbWVzc2FnZSBpcyByZWNlaXZlZFxuICAgKi9cbiAgYWN0aXZlQ2hhbm5lbCQ6IE9ic2VydmFibGU8Q2hhbm5lbDxUPiB8IHVuZGVmaW5lZD47XG4gIC8qKlxuICAgKiBFbWl0cyB0aGUgbGlzdCBvZiBjdXJyZW50bHkgbG9hZGVkIG1lc3NhZ2VzIG9mIHRoZSBhY3RpdmUgY2hhbm5lbC5cbiAgICovXG4gIGFjdGl2ZUNoYW5uZWxNZXNzYWdlcyQ6IE9ic2VydmFibGU8U3RyZWFtTWVzc2FnZTxUPltdPjtcbiAgLyoqXG4gICAqIEVtaXRzIHRoZSBsaXN0IG9mIHBpbm5lZCBtZXNzYWdlcyBvZiB0aGUgYWN0aXZlIGNoYW5uZWwuXG4gICAqL1xuICBhY3RpdmVDaGFubmVsUGlubmVkTWVzc2FnZXMkOiBPYnNlcnZhYmxlPFN0cmVhbU1lc3NhZ2U8VD5bXT47XG4gIC8qKlxuICAgKiBFbWl0cyB0aGUgaWQgb2YgdGhlIGN1cnJlbnRseSBzZWxlY3RlZCBwYXJlbnQgbWVzc2FnZS4gSWYgbm8gbWVzc2FnZSBpcyBzZWxlY3RlZCwgaXQgZW1pdHMgdW5kZWZpbmVkLlxuICAgKi9cbiAgYWN0aXZlUGFyZW50TWVzc2FnZUlkJDogT2JzZXJ2YWJsZTxzdHJpbmcgfCB1bmRlZmluZWQ+O1xuICAvKipcbiAgICogRW1pdHMgdGhlIGxpc3Qgb2YgY3VycmVudGx5IGxvYWRlZCB0aHJlYWQgcmVwbGllcyBiZWxvbmdpbmcgdG8gdGhlIHNlbGVjdGVkIHBhcmVudCBtZXNzYWdlLiBJZiB0aGVyZSBpcyBubyBjdXJyZW50bHkgYWN0aXZlIHRocmVhZCBpdCBlbWl0cyBhbiBlbXB0eSBhcnJheS5cbiAgICovXG4gIGFjdGl2ZVRocmVhZE1lc3NhZ2VzJDogT2JzZXJ2YWJsZTxTdHJlYW1NZXNzYWdlPFQ+W10+O1xuICAvKipcbiAgICogRW1pdHMgdGhlIGN1cnJlbnRseSBzZWxlY3RlZCBwYXJlbnQgbWVzc2FnZS4gSWYgbm8gbWVzc2FnZSBpcyBzZWxlY3RlZCwgaXQgZW1pdHMgdW5kZWZpbmVkLlxuICAgKi9cbiAgYWN0aXZlUGFyZW50TWVzc2FnZSQ6IE9ic2VydmFibGU8U3RyZWFtTWVzc2FnZTxUPiB8IHVuZGVmaW5lZD47XG4gIC8qKlxuICAgKiBFbWl0cyB0aGUgY3VycmVudGx5IHNlbGVjdGVkIG1lc3NhZ2UgdG8gcXVvdGVcbiAgICovXG4gIG1lc3NhZ2VUb1F1b3RlJDogT2JzZXJ2YWJsZTxTdHJlYW1NZXNzYWdlPFQ+IHwgdW5kZWZpbmVkPjtcbiAgLyoqXG4gICAqIEVtaXRzIHRoZSBJRCBvZiB0aGUgbWVzc2FnZSB0aGUgbWVzc2FnZSBsaXN0IHNob3VsZCBqdW1wIHRvIChjYW4gYmUgYSBjaGFubmVsIG1lc3NhZ2Ugb3IgdGhyZWFkIG1lc3NhZ2UpXG4gICAqL1xuICBqdW1wVG9NZXNzYWdlJDogT2JzZXJ2YWJsZTx7IGlkPzogc3RyaW5nOyBwYXJlbnRJZD86IHN0cmluZyB9PjtcbiAgLyoqXG4gICAqIEVtaXRzIHRoZSBsaXN0IG9mIHVzZXJzIHRoYXQgYXJlIGN1cnJlbnRseSB0eXBpbmcgaW4gdGhlIGNoYW5uZWwgKGN1cnJlbnQgdXNlciBpcyBub3QgaW5jbHVkZWQpXG4gICAqL1xuICB1c2Vyc1R5cGluZ0luQ2hhbm5lbCQ6IE9ic2VydmFibGU8VXNlclJlc3BvbnNlPFQ+W10+O1xuICAvKipcbiAgICogRW1pdHMgdGhlIGxpc3Qgb2YgdXNlcnMgdGhhdCBhcmUgY3VycmVudGx5IHR5cGluZyBpbiB0aGUgYWN0aXZlIHRocmVhZCAoY3VycmVudCB1c2VyIGlzIG5vdCBpbmNsdWRlZClcbiAgICovXG4gIHVzZXJzVHlwaW5nSW5UaHJlYWQkOiBPYnNlcnZhYmxlPFVzZXJSZXNwb25zZTxUPltdPjtcbiAgLyoqXG4gICAqIEVtaXRzIGEgbWFwIHRoYXQgY29udGFpbnMgdGhlIGRhdGUgb2YgdGhlIGxhdGVzdCBtZXNzYWdlIHNlbnQgYnkgdGhlIGN1cnJlbnQgdXNlciBieSBjaGFubmVscyAodGhpcyBpcyB1c2VkIHRvIGRldGVjdCBpZiBzbG93IG1vZGUgY291bnRkb3duIHNob3VsZCBiZSBzdGFydGVkKVxuICAgKi9cbiAgbGF0ZXN0TWVzc2FnZURhdGVCeVVzZXJCeUNoYW5uZWxzJDogT2JzZXJ2YWJsZTx7IFtrZXk6IHN0cmluZ106IERhdGUgfT47XG4gIC8qKlxuICAgKiBJZiB5b3UncmUgdXNpbmcgW3NlbWFudGljIGZpbHRlcnMgZm9yIG1vZGVyYXRpb25dKC9tb2RlcmF0aW9uL2RvY3MvKSB5b3UgY2FuIHNldCB1cCBydWxlcyBmb3IgYm91bmNpbmcgbWVzc2FnZXMuXG4gICAqXG4gICAqIElmIGEgbWVzc2FnZSBpcyBib3VuY2VkLCBpdCB3aWxsIGJlIGVtaXR0ZWQgdmlhIHRoaXMgYE9ic2VydmFibGVgLiBUaGUgYnVpbHQtaW4gW2BNZXNzYWdlQm91bmNlUHJvbXB0YCBjb21wb25lbnRdKC9jaGF0L2RvY3Mvc2RrL2FuZ3VsYXIvY29tcG9uZW50cy9NZXNzYWdlQm91bmNlUHJvbXB0Q29tcG9uZW50Lykgd2lsbCBkaXNwbGF5IHRoZSBib3VuY2Ugb3B0aW9uIHRvIHRoZSB1c2VyIGlmIGEgYm91bmNlZCBtZXNzYWdlIGlzIGNsaWNrZWQuXG4gICAqL1xuICBib3VuY2VkTWVzc2FnZSQ6IEJlaGF2aW9yU3ViamVjdDxTdHJlYW1NZXNzYWdlPFQ+IHwgdW5kZWZpbmVkPjtcbiAgLyoqXG4gICAqIFRoZSBsYXN0IHJlYWQgbWVzc2FnZSBpZCBvZiB0aGUgYWN0aXZlIGNoYW5uZWwsIGl0J3MgdXNlZCBieSB0aGUgbWVzc2FnZSBsaXN0IGNvbXBvbmVudCB0byBkaXNwbGF5IHVucmVhZCBVSSwgYW5kIGp1bXAgdG8gbGF0ZXN0IHJlYWQgbWVzc2FnZVxuICAgKlxuICAgKiBUaGlzIHByb3BlcnR5IGlzbid0IGFsd2F5cyB1cGRhdGVkLCBwbGVhc2UgdXNlIGBjaGFubmVsLnJlYWRgIHRvIGRpc3BsYXkgdXAtdG8tZGF0ZSByZWFkIGluZm9ybWF0aW9uXG4gICAqL1xuICBhY3RpdmVDaGFubmVsTGFzdFJlYWRNZXNzYWdlSWQ/OiBzdHJpbmc7XG4gIC8qKlxuICAgKiBUaGUgdW5yZWFkIGNvdW50IG9mIHRoZSBhY3RpdmUgY2hhbm5lbCwgaXQncyB1c2VkIGJ5IHRoZSBtZXNzYWdlIGxpc3QgY29tcG9uZW50IHRvIGRpc3BsYXkgdW5yZWFkIFVJXG4gICAqXG4gICAqIFRoaXMgcHJvcGVydHkgaXNuJ3QgYWx3YXlzIHVwZGF0ZWQsIHBsZWFzZSB1c2UgYGNoYW5uZWwucmVhZGAgdG8gZGlzcGxheSB1cC10by1kYXRlIHJlYWQgaW5mb3JtYXRpb25cbiAgICovXG4gIGFjdGl2ZUNoYW5uZWxVbnJlYWRDb3VudD86IG51bWJlcjtcbiAgLyoqXG4gICAqIFlvdSBjYW4gb3ZlcnJpZGUgdGhlIGRlZmF1bHQgZmlsZSB1cGxvYWQgcmVxdWVzdCAtIHlvdSBjYW4gdXNlIHRoaXMgdG8gdXBsb2FkIGZpbGVzIHRvIHlvdXIgb3duIENETlxuICAgKi9cbiAgY3VzdG9tRmlsZVVwbG9hZFJlcXVlc3Q/OiAoXG4gICAgZmlsZTogRmlsZSxcbiAgICBjaGFubmVsOiBDaGFubmVsPFQ+LFxuICApID0+IFByb21pc2U8eyBmaWxlOiBzdHJpbmcgfT47XG4gIC8qKlxuICAgKiBZb3UgY2FuIG92ZXJyaWRlIHRoZSBkZWZhdWx0IGltYWdlIHVwbG9hZCByZXF1ZXN0IC0geW91IGNhbiB1c2UgdGhpcyB0byB1cGxvYWQgaW1hZ2VzIHRvIHlvdXIgb3duIENETlxuICAgKi9cbiAgY3VzdG9tSW1hZ2VVcGxvYWRSZXF1ZXN0PzogKFxuICAgIGZpbGU6IEZpbGUsXG4gICAgY2hhbm5lbDogQ2hhbm5lbDxUPixcbiAgKSA9PiBQcm9taXNlPHsgZmlsZTogc3RyaW5nIH0+O1xuICAvKipcbiAgICogWW91IGNhbiBvdmVycmlkZSB0aGUgZGVmYXVsdCBmaWxlIGRlbGV0ZSByZXF1ZXN0IC0gb3ZlcnJpZGUgdGhpcyBpZiB5b3UgdXNlIHlvdXIgb3duIENETlxuICAgKi9cbiAgY3VzdG9tRmlsZURlbGV0ZVJlcXVlc3Q/OiAodXJsOiBzdHJpbmcsIGNoYW5uZWw6IENoYW5uZWw8VD4pID0+IFByb21pc2U8dm9pZD47XG4gIC8qKlxuICAgKiBZb3UgY2FuIG92ZXJyaWRlIHRoZSBkZWZhdWx0IGltYWdlIGRlbGV0ZSByZXF1ZXN0IC0gb3ZlcnJpZGUgdGhpcyBpZiB5b3UgdXNlIHlvdXIgb3duIENETlxuICAgKi9cbiAgY3VzdG9tSW1hZ2VEZWxldGVSZXF1ZXN0PzogKFxuICAgIHVybDogc3RyaW5nLFxuICAgIGNoYW5uZWw6IENoYW5uZWw8VD4sXG4gICkgPT4gUHJvbWlzZTx2b2lkPjtcbiAgLyoqXG4gICAqIFRoZSBwcm92aWRlZCBtZXRob2Qgd2lsbCBiZSBjYWxsZWQgYmVmb3JlIGRlbGV0aW5nIGEgbWVzc2FnZS4gSWYgdGhlIHJldHVybmVkIFByb21pc2UgcmVzb2x2ZXMgdG8gYHRydWVgIHRvIGRlbGV0aW9uIHdpbGwgZ28gYWhlYWQuIElmIGBmYWxzZWAgaXMgcmV0dXJuZWQsIHRoZSBtZXNzYWdlIHdvbid0IGJlIGRlbGV0ZWQuXG4gICAqL1xuICBtZXNzYWdlRGVsZXRlQ29uZmlybWF0aW9uSGFuZGxlcj86IChcbiAgICBtZXNzYWdlOiBTdHJlYW1NZXNzYWdlPFQ+LFxuICApID0+IFByb21pc2U8Ym9vbGVhbj47XG4gIC8qKlxuICAgKiBUaGUgcHJvdmlkZWQgbWV0aG9kIHdpbGwgYmUgY2FsbGVkIGJlZm9yZSBhIG5ldyBtZXNzYWdlIGlzIHNlbnQgdG8gU3RyZWFtJ3MgQVBJLiBZb3UgY2FuIHVzZSB0aGlzIGhvb2sgdG8gdHJhbmZyb20gb3IgZW5yaWNoIHRoZSBtZXNzYWdlIGJlaW5nIHNlbnQuXG4gICAqL1xuICBiZWZvcmVTZW5kTWVzc2FnZT86IChcbiAgICBpbnB1dDogTWVzc2FnZUlucHV0PFQ+LFxuICApID0+IE1lc3NhZ2VJbnB1dDxUPiB8IFByb21pc2U8TWVzc2FnZUlucHV0PFQ+PjtcbiAgLyoqXG4gICAqIFRoZSBwcm92aWRlZCBtZXRob2Qgd2lsbCBiZSBjYWxsZWQgYmVmb3JlIGEgbWVzc2FnZSBpcyBzZW50IHRvIFN0cmVhbSdzIEFQSSBmb3IgdXBkYXRlLiBZb3UgY2FuIHVzZSB0aGlzIGhvb2sgdG8gdHJhbmZyb20gb3IgZW5yaWNoIHRoZSBtZXNzYWdlIGJlaW5nIHVwZGF0ZWQuXG4gICAqL1xuICBiZWZvcmVVcGRhdGVNZXNzYWdlPzogKFxuICAgIG1lc3NhZ2U6IFN0cmVhbU1lc3NhZ2U8VD4sXG4gICkgPT4gU3RyZWFtTWVzc2FnZTxUPiB8IFByb21pc2U8U3RyZWFtTWVzc2FnZTxUPj47XG4gIC8qKlxuICAgKiBAaW50ZXJuYWxcbiAgICovXG4gIHN0YXRpYyByZWFkb25seSBNQVhfTUVTU0FHRV9SRUFDVElPTlNfVE9fRkVUQ0ggPSAxMjAwO1xuICAvKipcbiAgICogQGludGVybmFsXG4gICAqL1xuICBpc01lc3NhZ2VMb2FkaW5nSW5Qcm9ncmVzcyA9IGZhbHNlO1xuICAvKipcbiAgICogQGludGVybmFsXG4gICAqL1xuICBtZXNzYWdlUGFnZVNpemUgPSAyNTtcbiAgcHJpdmF0ZSBjaGFubmVsc1N1YmplY3QgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PENoYW5uZWw8VD5bXSB8IHVuZGVmaW5lZD4oXG4gICAgdW5kZWZpbmVkLFxuICApO1xuICBwcml2YXRlIGFjdGl2ZUNoYW5uZWxTdWJqZWN0ID0gbmV3IEJlaGF2aW9yU3ViamVjdDxDaGFubmVsPFQ+IHwgdW5kZWZpbmVkPihcbiAgICB1bmRlZmluZWQsXG4gICk7XG4gIHByaXZhdGUgYWN0aXZlQ2hhbm5lbE1lc3NhZ2VzU3ViamVjdCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8XG4gICAgKFN0cmVhbU1lc3NhZ2U8VD4gfCBNZXNzYWdlUmVzcG9uc2U8VD4gfCBGb3JtYXRNZXNzYWdlUmVzcG9uc2U8VD4pW11cbiAgPihbXSk7XG4gIHByaXZhdGUgYWN0aXZlQ2hhbm5lbFBpbm5lZE1lc3NhZ2VzU3ViamVjdCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8XG4gICAgU3RyZWFtTWVzc2FnZVtdXG4gID4oW10pO1xuICBwcml2YXRlIGhhc01vcmVDaGFubmVsc1N1YmplY3QgPSBuZXcgUmVwbGF5U3ViamVjdDxib29sZWFuPigxKTtcbiAgcHJpdmF0ZSBhY3RpdmVDaGFubmVsU3Vic2NyaXB0aW9uczogeyB1bnN1YnNjcmliZTogKCkgPT4gdm9pZCB9W10gPSBbXTtcbiAgcHJpdmF0ZSBhY3RpdmVQYXJlbnRNZXNzYWdlSWRTdWJqZWN0ID0gbmV3IEJlaGF2aW9yU3ViamVjdDxcbiAgICBzdHJpbmcgfCB1bmRlZmluZWRcbiAgPih1bmRlZmluZWQpO1xuICBwcml2YXRlIGFjdGl2ZVRocmVhZE1lc3NhZ2VzU3ViamVjdCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8XG4gICAgKFN0cmVhbU1lc3NhZ2U8VD4gfCBNZXNzYWdlUmVzcG9uc2U8VD4gfCBGb3JtYXRNZXNzYWdlUmVzcG9uc2U8VD4pW11cbiAgPihbXSk7XG4gIHByaXZhdGUganVtcFRvTWVzc2FnZVN1YmplY3QgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PHtcbiAgICBpZD86IHN0cmluZztcbiAgICBwYXJlbnRJZD86IHN0cmluZztcbiAgfT4oeyBpZDogdW5kZWZpbmVkLCBwYXJlbnRJZDogdW5kZWZpbmVkIH0pO1xuICBwcml2YXRlIGxhdGVzdE1lc3NhZ2VEYXRlQnlVc2VyQnlDaGFubmVsc1N1YmplY3QgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PHtcbiAgICBba2V5OiBzdHJpbmddOiBEYXRlO1xuICB9Pih7fSk7XG4gIHByaXZhdGUgcmVhZG9ubHkgYXR0YWNobWVudE1heFNpemVGYWxsYmFja0luTUIgPSAxMDA7XG4gIHByaXZhdGUgbWVzc2FnZVRvUXVvdGVTdWJqZWN0ID0gbmV3IEJlaGF2aW9yU3ViamVjdDxcbiAgICBTdHJlYW1NZXNzYWdlPFQ+IHwgdW5kZWZpbmVkXG4gID4odW5kZWZpbmVkKTtcbiAgcHJpdmF0ZSB1c2Vyc1R5cGluZ0luQ2hhbm5lbFN1YmplY3QgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PFVzZXJSZXNwb25zZTxUPltdPihcbiAgICBbXSxcbiAgKTtcbiAgcHJpdmF0ZSB1c2Vyc1R5cGluZ0luVGhyZWFkU3ViamVjdCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8VXNlclJlc3BvbnNlPFQ+W10+KFxuICAgIFtdLFxuICApO1xuICBwcml2YXRlIF9zaG91bGRNYXJrQWN0aXZlQ2hhbm5lbEFzUmVhZCA9IHRydWU7XG4gIHByaXZhdGUgc2hvdWxkU2V0QWN0aXZlQ2hhbm5lbCA9IHRydWU7XG4gIHByaXZhdGUgY2xpZW50RXZlbnRzU3Vic2NyaXB0aW9uOiBTdWJzY3JpcHRpb24gfCB1bmRlZmluZWQ7XG4gIHByaXZhdGUgaXNTdGF0ZVJlY292ZXJ5SW5Qcm9ncmVzcyQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0KGZhbHNlKTtcbiAgcHJpdmF0ZSBjaGFubmVsUXVlcnlTdGF0ZVN1YmplY3QgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PFxuICAgIENoYW5uZWxRdWVyeVN0YXRlIHwgdW5kZWZpbmVkXG4gID4odW5kZWZpbmVkKTtcbiAgcHJpdmF0ZSBjdXN0b21DaGFubmVsUXVlcnk/OiAoXG4gICAgcXVlcnlUeXBlOiBDaGFubmVsUXVlcnlUeXBlLFxuICApID0+IFByb21pc2U8Q2hhbm5lbFF1ZXJ5UmVzdWx0PFQ+PjtcbiAgcHJpdmF0ZSBjaGFubmVsTWFuYWdlcj86IENoYW5uZWxNYW5hZ2VyPFQ+O1xuICBwcml2YXRlIGNoYW5uZWxRdWVyeUNvbmZpZz86IENoYW5uZWxRdWVyeUNvbmZpZzxUPjtcbiAgcHJpdmF0ZSBkaXNtaXNzRXJyb3JOb3RpZmljYXRpb24/OiAoKSA9PiB2b2lkO1xuICBwcml2YXRlIGFyZVJlYWRFdmVudHNQYXVzZWQgPSBmYWxzZTtcbiAgcHJpdmF0ZSBtYXJrUmVhZFRocm90dGxlVGltZSA9IDEwNTA7XG4gIHByaXZhdGUgbWFya1JlYWRUaW1lb3V0PzogUmV0dXJuVHlwZTx0eXBlb2Ygc2V0VGltZW91dD47XG4gIHByaXZhdGUgc2NoZWR1bGVkTWFya1JlYWRSZXF1ZXN0PzogKCkgPT4gdm9pZDtcbiAgcHJpdmF0ZSBjaGFubmVsTWFuYWdlclN1YnNjcmlwdGlvbnM6IFVuc3Vic2NyaWJlW10gPSBbXTtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIGNoYXRDbGllbnRTZXJ2aWNlOiBDaGF0Q2xpZW50U2VydmljZTxUPixcbiAgICBwcml2YXRlIG5nWm9uZTogTmdab25lLFxuICAgIHByaXZhdGUgbm90aWZpY2F0aW9uU2VydmljZTogTm90aWZpY2F0aW9uU2VydmljZSxcbiAgKSB7XG4gICAgdGhpcy5jaGFubmVscyQgPSB0aGlzLmNoYW5uZWxzU3ViamVjdC5hc09ic2VydmFibGUoKS5waXBlKHNoYXJlUmVwbGF5KDEpKTtcbiAgICB0aGlzLmFjdGl2ZUNoYW5uZWwkID0gdGhpcy5hY3RpdmVDaGFubmVsU3ViamVjdFxuICAgICAgLmFzT2JzZXJ2YWJsZSgpXG4gICAgICAucGlwZShzaGFyZVJlcGxheSgxKSk7XG4gICAgdGhpcy5hY3RpdmVDaGFubmVsTWVzc2FnZXMkID0gdGhpcy5hY3RpdmVDaGFubmVsTWVzc2FnZXNTdWJqZWN0LnBpcGUoXG4gICAgICBtYXAoKG1lc3NhZ2VzKSA9PiB7XG4gICAgICAgIGNvbnN0IGNoYW5uZWwgPSB0aGlzLmFjdGl2ZUNoYW5uZWxTdWJqZWN0LmdldFZhbHVlKCkhO1xuICAgICAgICByZXR1cm4gbWVzc2FnZXMubWFwKChtZXNzYWdlKSA9PlxuICAgICAgICAgIHRoaXMudHJhbnNmb3JtVG9TdHJlYW1NZXNzYWdlKG1lc3NhZ2UsIGNoYW5uZWwpLFxuICAgICAgICApO1xuICAgICAgfSksXG4gICAgICBzaGFyZVJlcGxheSgxKSxcbiAgICApO1xuICAgIHRoaXMuYm91bmNlZE1lc3NhZ2UkID0gbmV3IEJlaGF2aW9yU3ViamVjdDxTdHJlYW1NZXNzYWdlPFQ+IHwgdW5kZWZpbmVkPihcbiAgICAgIHVuZGVmaW5lZCxcbiAgICApO1xuICAgIHRoaXMuaGFzTW9yZUNoYW5uZWxzJCA9IHRoaXMuaGFzTW9yZUNoYW5uZWxzU3ViamVjdFxuICAgICAgLmFzT2JzZXJ2YWJsZSgpXG4gICAgICAucGlwZShzaGFyZVJlcGxheSgxKSk7XG4gICAgdGhpcy5hY3RpdmVQYXJlbnRNZXNzYWdlSWQkID0gdGhpcy5hY3RpdmVQYXJlbnRNZXNzYWdlSWRTdWJqZWN0XG4gICAgICAuYXNPYnNlcnZhYmxlKClcbiAgICAgIC5waXBlKHNoYXJlUmVwbGF5KDEpKTtcbiAgICB0aGlzLmFjdGl2ZVRocmVhZE1lc3NhZ2VzJCA9IHRoaXMuYWN0aXZlVGhyZWFkTWVzc2FnZXNTdWJqZWN0LnBpcGUoXG4gICAgICBtYXAoKG1lc3NhZ2VzKSA9PiB7XG4gICAgICAgIGNvbnN0IGNoYW5uZWwgPSB0aGlzLmFjdGl2ZUNoYW5uZWxTdWJqZWN0LmdldFZhbHVlKCkhO1xuICAgICAgICByZXR1cm4gbWVzc2FnZXMubWFwKChtZXNzYWdlKSA9PlxuICAgICAgICAgIHRoaXMudHJhbnNmb3JtVG9TdHJlYW1NZXNzYWdlKG1lc3NhZ2UsIGNoYW5uZWwpLFxuICAgICAgICApO1xuICAgICAgfSksXG4gICAgICBzaGFyZVJlcGxheSgxKSxcbiAgICApO1xuICAgIHRoaXMuYWN0aXZlUGFyZW50TWVzc2FnZSQgPSBjb21iaW5lTGF0ZXN0KFtcbiAgICAgIHRoaXMuYWN0aXZlQ2hhbm5lbE1lc3NhZ2VzJCxcbiAgICAgIHRoaXMuYWN0aXZlUGFyZW50TWVzc2FnZUlkJCxcbiAgICBdKS5waXBlKFxuICAgICAgbWFwKFxuICAgICAgICAoW21lc3NhZ2VzLCBwYXJlbnRNZXNzYWdlSWRdOiBbXG4gICAgICAgICAgU3RyZWFtTWVzc2FnZVtdLFxuICAgICAgICAgIHN0cmluZyB8IHVuZGVmaW5lZCxcbiAgICAgICAgXSkgPT4ge1xuICAgICAgICAgIGlmICghcGFyZW50TWVzc2FnZUlkKSB7XG4gICAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjb25zdCBtZXNzYWdlID0gbWVzc2FnZXMuZmluZCgobSkgPT4gbS5pZCA9PT0gcGFyZW50TWVzc2FnZUlkKTtcbiAgICAgICAgICAgIGlmICghbWVzc2FnZSkge1xuICAgICAgICAgICAgICB2b2lkIHRoaXMuc2V0QXNBY3RpdmVQYXJlbnRNZXNzYWdlKHVuZGVmaW5lZCk7XG4gICAgICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICByZXR1cm4gbWVzc2FnZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICApLFxuICAgICAgc2hhcmVSZXBsYXkoMSksXG4gICAgKTtcbiAgICB0aGlzLm1lc3NhZ2VUb1F1b3RlJCA9IHRoaXMubWVzc2FnZVRvUXVvdGVTdWJqZWN0XG4gICAgICAuYXNPYnNlcnZhYmxlKClcbiAgICAgIC5waXBlKHNoYXJlUmVwbGF5KDEpKTtcbiAgICB0aGlzLmp1bXBUb01lc3NhZ2UkID0gdGhpcy5qdW1wVG9NZXNzYWdlU3ViamVjdFxuICAgICAgLmFzT2JzZXJ2YWJsZSgpXG4gICAgICAucGlwZShzaGFyZVJlcGxheSgxKSk7XG5cbiAgICB0aGlzLnVzZXJzVHlwaW5nSW5DaGFubmVsJCA9IHRoaXMudXNlcnNUeXBpbmdJbkNoYW5uZWxTdWJqZWN0XG4gICAgICAuYXNPYnNlcnZhYmxlKClcbiAgICAgIC5waXBlKHNoYXJlUmVwbGF5KDEpKTtcbiAgICB0aGlzLnVzZXJzVHlwaW5nSW5UaHJlYWQkID0gdGhpcy51c2Vyc1R5cGluZ0luVGhyZWFkU3ViamVjdFxuICAgICAgLmFzT2JzZXJ2YWJsZSgpXG4gICAgICAucGlwZShzaGFyZVJlcGxheSgxKSk7XG4gICAgdGhpcy5sYXRlc3RNZXNzYWdlRGF0ZUJ5VXNlckJ5Q2hhbm5lbHMkID1cbiAgICAgIHRoaXMubGF0ZXN0TWVzc2FnZURhdGVCeVVzZXJCeUNoYW5uZWxzU3ViamVjdFxuICAgICAgICAuYXNPYnNlcnZhYmxlKClcbiAgICAgICAgLnBpcGUoc2hhcmVSZXBsYXkoMSkpO1xuICAgIHRoaXMuYWN0aXZlQ2hhbm5lbFBpbm5lZE1lc3NhZ2VzJCA9IHRoaXMuYWN0aXZlQ2hhbm5lbFBpbm5lZE1lc3NhZ2VzU3ViamVjdFxuICAgICAgLmFzT2JzZXJ2YWJsZSgpXG4gICAgICAucGlwZShzaGFyZVJlcGxheSgxKSk7XG4gICAgdGhpcy5jaGFubmVsUXVlcnlTdGF0ZSQgPSB0aGlzLmNoYW5uZWxRdWVyeVN0YXRlU3ViamVjdFxuICAgICAgLmFzT2JzZXJ2YWJsZSgpXG4gICAgICAucGlwZShzaGFyZVJlcGxheSgxKSk7XG4gICAgdGhpcy5zaG91bGRSZWNvdmVyU3RhdGUkID0gY29tYmluZUxhdGVzdChbXG4gICAgICB0aGlzLmNoYW5uZWxzJCxcbiAgICAgIHRoaXMuY2hhbm5lbFF1ZXJ5U3RhdGUkLFxuICAgICAgdGhpcy5pc1N0YXRlUmVjb3ZlcnlJblByb2dyZXNzJCxcbiAgICBdKS5waXBlKFxuICAgICAgbWFwKChbY2hhbm5lbHMsIHF1ZXJ5U3RhdGUsIGlzU3RhdGVSZWNvdmVyeUluUHJvZ3Jlc3NdKSA9PiB7XG4gICAgICAgIHJldHVybiAoXG4gICAgICAgICAgKCFjaGFubmVscyB8fCBjaGFubmVscy5sZW5ndGggPT09IDApICYmXG4gICAgICAgICAgcXVlcnlTdGF0ZT8uc3RhdGUgPT09ICdlcnJvcicgJiZcbiAgICAgICAgICAhaXNTdGF0ZVJlY292ZXJ5SW5Qcm9ncmVzc1xuICAgICAgICApO1xuICAgICAgfSksXG4gICAgICBkaXN0aW5jdFVudGlsQ2hhbmdlZCgpLFxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogSWYgc2V0IHRvIGZhbHNlLCByZWFkIGV2ZW50cyB3b24ndCBiZSBzZW50IGFzIG5ldyBtZXNzYWdlcyBhcmUgcmVjZWl2ZWQuIElmIHNldCB0byB0cnVlIGFjdGl2ZSBjaGFubmVsIChpZiBhbnkpIHdpbGwgaW1tZWRpYXRlbHkgYmUgbWFya2VkIGFzIHJlYWQuXG4gICAqL1xuICBnZXQgc2hvdWxkTWFya0FjdGl2ZUNoYW5uZWxBc1JlYWQoKSB7XG4gICAgcmV0dXJuIHRoaXMuX3Nob3VsZE1hcmtBY3RpdmVDaGFubmVsQXNSZWFkO1xuICB9XG5cbiAgLyoqXG4gICAqIElmIHNldCB0byBmYWxzZSwgcmVhZCBldmVudHMgd29uJ3QgYmUgc2VudCBhcyBuZXcgbWVzc2FnZXMgYXJlIHJlY2VpdmVkLiBJZiBzZXQgdG8gdHJ1ZSBhY3RpdmUgY2hhbm5lbCAoaWYgYW55KSB3aWxsIGltbWVkaWF0ZWx5IGJlIG1hcmtlZCBhcyByZWFkLlxuICAgKi9cbiAgc2V0IHNob3VsZE1hcmtBY3RpdmVDaGFubmVsQXNSZWFkKHNob3VsZE1hcmtBY3RpdmVDaGFubmVsQXNSZWFkOiBib29sZWFuKSB7XG4gICAgaWYgKCF0aGlzLl9zaG91bGRNYXJrQWN0aXZlQ2hhbm5lbEFzUmVhZCAmJiBzaG91bGRNYXJrQWN0aXZlQ2hhbm5lbEFzUmVhZCkge1xuICAgICAgY29uc3QgYWN0aXZlQ2hhbm5lbCA9IHRoaXMuYWN0aXZlQ2hhbm5lbFN1YmplY3QuZ2V0VmFsdWUoKTtcbiAgICAgIGlmIChhY3RpdmVDaGFubmVsICYmIHRoaXMuY2FuU2VuZFJlYWRFdmVudHMpIHtcbiAgICAgICAgdm9pZCBhY3RpdmVDaGFubmVsLm1hcmtSZWFkKCk7XG4gICAgICB9XG4gICAgfVxuICAgIHRoaXMuX3Nob3VsZE1hcmtBY3RpdmVDaGFubmVsQXNSZWFkID0gc2hvdWxkTWFya0FjdGl2ZUNoYW5uZWxBc1JlYWQ7XG4gIH1cblxuICAvKipcbiAgICogU2V0cyB0aGUgZ2l2ZW4gYGNoYW5uZWxgIGFzIGFjdGl2ZSBhbmQgbWFya3MgaXQgYXMgcmVhZC5cbiAgICogSWYgdGhlIGNoYW5uZWwgd2Fzbid0IHByZXZpb3VzbHkgcGFydCBvZiB0aGUgY2hhbm5lbCwgaXQgd2lsbCBiZSBhZGRlZCB0byB0aGUgYmVnaW5uaW5nIG9mIHRoZSBsaXN0LlxuICAgKiBAcGFyYW0gY2hhbm5lbFxuICAgKi9cbiAgc2V0QXNBY3RpdmVDaGFubmVsKGNoYW5uZWw6IENoYW5uZWw8VD4pIHtcbiAgICBjb25zdCBwcmV2QWN0aXZlQ2hhbm5lbCA9IHRoaXMuYWN0aXZlQ2hhbm5lbFN1YmplY3QuZ2V0VmFsdWUoKTtcbiAgICBpZiAocHJldkFjdGl2ZUNoYW5uZWw/LmNpZCA9PT0gY2hhbm5lbC5jaWQpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGhpcy5zdG9wV2F0Y2hGb3JBY3RpdmVDaGFubmVsRXZlbnRzKHByZXZBY3RpdmVDaGFubmVsKTtcbiAgICB0aGlzLmZsdXNoTWFya1JlYWRRdWV1ZSgpO1xuICAgIHRoaXMuYXJlUmVhZEV2ZW50c1BhdXNlZCA9IGZhbHNlO1xuICAgIHRoaXMuaXNNZXNzYWdlTG9hZGluZ0luUHJvZ3Jlc3MgPSBmYWxzZTtcbiAgICBjb25zdCByZWFkU3RhdGUgPVxuICAgICAgY2hhbm5lbC5zdGF0ZS5yZWFkW3RoaXMuY2hhdENsaWVudFNlcnZpY2UuY2hhdENsaWVudC51c2VyPy5pZCB8fCAnJ107XG4gICAgdGhpcy5hY3RpdmVDaGFubmVsTGFzdFJlYWRNZXNzYWdlSWQgPSByZWFkU3RhdGU/Lmxhc3RfcmVhZF9tZXNzYWdlX2lkO1xuICAgIGlmIChcbiAgICAgIGNoYW5uZWwuc3RhdGUubGF0ZXN0TWVzc2FnZXNbY2hhbm5lbC5zdGF0ZS5sYXRlc3RNZXNzYWdlcy5sZW5ndGggLSAxXVxuICAgICAgICA/LmlkID09PSB0aGlzLmFjdGl2ZUNoYW5uZWxMYXN0UmVhZE1lc3NhZ2VJZFxuICAgICkge1xuICAgICAgdGhpcy5hY3RpdmVDaGFubmVsTGFzdFJlYWRNZXNzYWdlSWQgPSB1bmRlZmluZWQ7XG4gICAgfVxuICAgIHRoaXMuYWN0aXZlQ2hhbm5lbFVucmVhZENvdW50ID0gcmVhZFN0YXRlPy51bnJlYWRfbWVzc2FnZXMgfHwgMDtcbiAgICB0aGlzLndhdGNoRm9yQWN0aXZlQ2hhbm5lbEV2ZW50cyhjaGFubmVsKTtcbiAgICB0aGlzLmFkZENoYW5uZWwoY2hhbm5lbCk7XG4gICAgdGhpcy5hY3RpdmVDaGFubmVsU3ViamVjdC5uZXh0KGNoYW5uZWwpO1xuICAgIGNvbnN0IGNoYW5uZWxTdGF0ZUxlbmd0aCA9IGNoYW5uZWwuc3RhdGUubGF0ZXN0TWVzc2FnZXMubGVuZ3RoO1xuICAgIGlmIChjaGFubmVsU3RhdGVMZW5ndGggPiAyICogdGhpcy5tZXNzYWdlUGFnZVNpemUpIHtcbiAgICAgIGNoYW5uZWwuc3RhdGUubGF0ZXN0TWVzc2FnZXMgPSBjaGFubmVsLnN0YXRlLmxhdGVzdE1lc3NhZ2VzLnNsaWNlKFxuICAgICAgICBjaGFubmVsU3RhdGVMZW5ndGggLSAyICogdGhpcy5tZXNzYWdlUGFnZVNpemUsXG4gICAgICApO1xuICAgIH1cbiAgICB0aGlzLnNldENoYW5uZWxTdGF0ZShjaGFubmVsKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBEZXNlbGVjdHMgdGhlIGN1cnJlbnRseSBhY3RpdmUgKGlmIGFueSkgY2hhbm5lbFxuICAgKi9cbiAgZGVzZWxlY3RBY3RpdmVDaGFubmVsKCkge1xuICAgIGNvbnN0IGFjdGl2ZUNoYW5uZWwgPSB0aGlzLmFjdGl2ZUNoYW5uZWxTdWJqZWN0LmdldFZhbHVlKCk7XG4gICAgaWYgKCFhY3RpdmVDaGFubmVsKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIHRoaXMuc3RvcFdhdGNoRm9yQWN0aXZlQ2hhbm5lbEV2ZW50cyhhY3RpdmVDaGFubmVsKTtcbiAgICB0aGlzLmZsdXNoTWFya1JlYWRRdWV1ZSgpO1xuICAgIHRoaXMuYWN0aXZlQ2hhbm5lbE1lc3NhZ2VzU3ViamVjdC5uZXh0KFtdKTtcbiAgICB0aGlzLmFjdGl2ZUNoYW5uZWxTdWJqZWN0Lm5leHQodW5kZWZpbmVkKTtcbiAgICB0aGlzLmFjdGl2ZVBhcmVudE1lc3NhZ2VJZFN1YmplY3QubmV4dCh1bmRlZmluZWQpO1xuICAgIHRoaXMuYWN0aXZlVGhyZWFkTWVzc2FnZXNTdWJqZWN0Lm5leHQoW10pO1xuICAgIHRoaXMubGF0ZXN0TWVzc2FnZURhdGVCeVVzZXJCeUNoYW5uZWxzU3ViamVjdC5uZXh0KHt9KTtcbiAgICB0aGlzLnNlbGVjdE1lc3NhZ2VUb1F1b3RlKHVuZGVmaW5lZCk7XG4gICAgdGhpcy5qdW1wVG9NZXNzYWdlU3ViamVjdC5uZXh0KHsgaWQ6IHVuZGVmaW5lZCwgcGFyZW50SWQ6IHVuZGVmaW5lZCB9KTtcbiAgICB0aGlzLmFjdGl2ZUNoYW5uZWxQaW5uZWRNZXNzYWdlc1N1YmplY3QubmV4dChbXSk7XG4gICAgdGhpcy51c2Vyc1R5cGluZ0luQ2hhbm5lbFN1YmplY3QubmV4dChbXSk7XG4gICAgdGhpcy51c2Vyc1R5cGluZ0luVGhyZWFkU3ViamVjdC5uZXh0KFtdKTtcbiAgICB0aGlzLmFjdGl2ZUNoYW5uZWxMYXN0UmVhZE1lc3NhZ2VJZCA9IHVuZGVmaW5lZDtcbiAgICB0aGlzLmFjdGl2ZUNoYW5uZWxVbnJlYWRDb3VudCA9IHVuZGVmaW5lZDtcbiAgICB0aGlzLmFyZVJlYWRFdmVudHNQYXVzZWQgPSBmYWxzZTtcbiAgICB0aGlzLmlzTWVzc2FnZUxvYWRpbmdJblByb2dyZXNzID0gZmFsc2U7XG4gIH1cblxuICAvKipcbiAgICogU2V0cyB0aGUgZ2l2ZW4gYG1lc3NhZ2VgIGFzIGFuIGFjdGl2ZSBwYXJlbnQgbWVzc2FnZS4gSWYgYHVuZGVmaW5lZGAgaXMgcHJvdmlkZWQsIGl0IHdpbGwgZGVsZXNlbGVjdCB0aGUgY3VycmVudCBwYXJlbnQgbWVzc2FnZS5cbiAgICogQHBhcmFtIG1lc3NhZ2VcbiAgICogQHBhcmFtIGxvYWRNZXNzYWdlc0Zvcm1cbiAgICovXG4gIGFzeW5jIHNldEFzQWN0aXZlUGFyZW50TWVzc2FnZShcbiAgICBtZXNzYWdlOiBTdHJlYW1NZXNzYWdlPFQ+IHwgdW5kZWZpbmVkLFxuICAgIGxvYWRNZXNzYWdlc0Zvcm06ICdyZXF1ZXN0JyB8ICdzdGF0ZScgPSAncmVxdWVzdCcsXG4gICkge1xuICAgIGNvbnN0IG1lc3NhZ2VUb1F1b3RlID0gdGhpcy5tZXNzYWdlVG9RdW90ZVN1YmplY3QuZ2V0VmFsdWUoKTtcbiAgICBpZiAobWVzc2FnZVRvUXVvdGUgJiYgISFtZXNzYWdlVG9RdW90ZS5wYXJlbnRfaWQpIHtcbiAgICAgIHRoaXMubWVzc2FnZVRvUXVvdGVTdWJqZWN0Lm5leHQodW5kZWZpbmVkKTtcbiAgICB9XG4gICAgaWYgKCFtZXNzYWdlKSB7XG4gICAgICB0aGlzLmFjdGl2ZVBhcmVudE1lc3NhZ2VJZFN1YmplY3QubmV4dCh1bmRlZmluZWQpO1xuICAgICAgdGhpcy5hY3RpdmVUaHJlYWRNZXNzYWdlc1N1YmplY3QubmV4dChbXSk7XG4gICAgICBjb25zdCBtZXNzYWdlVG9KdW1wVG8gPSB0aGlzLmp1bXBUb01lc3NhZ2VTdWJqZWN0LmdldFZhbHVlKCk7XG4gICAgICBpZiAobWVzc2FnZVRvSnVtcFRvICYmICEhbWVzc2FnZVRvSnVtcFRvLnBhcmVudElkKSB7XG4gICAgICAgIHRoaXMuanVtcFRvTWVzc2FnZVN1YmplY3QubmV4dCh7IGlkOiB1bmRlZmluZWQsIHBhcmVudElkOiB1bmRlZmluZWQgfSk7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuYWN0aXZlUGFyZW50TWVzc2FnZUlkU3ViamVjdC5uZXh0KG1lc3NhZ2UuaWQpO1xuICAgICAgY29uc3QgYWN0aXZlQ2hhbm5lbCA9IHRoaXMuYWN0aXZlQ2hhbm5lbFN1YmplY3QuZ2V0VmFsdWUoKTtcbiAgICAgIGlmIChsb2FkTWVzc2FnZXNGb3JtID09PSAncmVxdWVzdCcpIHtcbiAgICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgYWN0aXZlQ2hhbm5lbD8uZ2V0UmVwbGllcyhtZXNzYWdlLmlkLCB7XG4gICAgICAgICAgbGltaXQ6IHRoaXMubWVzc2FnZVBhZ2VTaXplLFxuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy5hY3RpdmVUaHJlYWRNZXNzYWdlc1N1YmplY3QubmV4dChyZXN1bHQ/Lm1lc3NhZ2VzIHx8IFtdKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMuYWN0aXZlVGhyZWFkTWVzc2FnZXNTdWJqZWN0Lm5leHQoXG4gICAgICAgICAgYWN0aXZlQ2hhbm5lbD8uc3RhdGUudGhyZWFkc1ttZXNzYWdlLmlkXSB8fCBbXSxcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogTG9hZHMgdGhlIG5leHQgcGFnZSBvZiBtZXNzYWdlcyBvZiB0aGUgYWN0aXZlIGNoYW5uZWwuIFRoZSBwYWdlIHNpemUgY2FuIGJlIHNldCBpbiB0aGUgW3F1ZXJ5IG9wdGlvbl0oL2NoYXQvZG9jcy9qYXZhc2NyaXB0L3F1ZXJ5X2NoYW5uZWxzLyNxdWVyeS1vcHRpb25zKSBvYmplY3QuXG4gICAqIEBwYXJhbSBkaXJlY3Rpb25cbiAgICovXG4gIGxvYWRNb3JlTWVzc2FnZXMoZGlyZWN0aW9uOiAnb2xkZXInIHwgJ25ld2VyJyA9ICdvbGRlcicpIHtcbiAgICBjb25zdCBhY3RpdmVDaG5hbm5lbCA9IHRoaXMuYWN0aXZlQ2hhbm5lbFN1YmplY3QuZ2V0VmFsdWUoKTtcbiAgICBjb25zdCBtZXNzYWdlcyA9IHRoaXMuYWN0aXZlQ2hhbm5lbE1lc3NhZ2VzU3ViamVjdC5nZXRWYWx1ZSgpO1xuICAgIGNvbnN0IGxhc3RNZXNzYWdlSWQgPVxuICAgICAgbWVzc2FnZXNbZGlyZWN0aW9uID09PSAnb2xkZXInID8gMCA6IG1lc3NhZ2VzLmxlbmd0aCAtIDFdPy5pZDtcbiAgICBpZiAoXG4gICAgICBkaXJlY3Rpb24gPT09ICduZXdlcicgJiZcbiAgICAgIGFjdGl2ZUNobmFubmVsPy5zdGF0ZT8ubGF0ZXN0TWVzc2FnZXMgPT09IGFjdGl2ZUNobmFubmVsPy5zdGF0ZT8ubWVzc2FnZXNcbiAgICApIHtcbiAgICAgIC8vIElmIHdlIGFyZSBvbiBsYXRlc3QgbWVzc2FnZSBzZXQsIGFjdGl2ZUNoYW5uZWxNZXNzYWdlcyQgd2lsbCBiZSByZWZyZXNoZWQgYnkgV1MgZXZlbnRzLCBubyBuZWVkIGZvciBhIHJlcXVlc3RcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgcmV0dXJuIGFjdGl2ZUNobmFubmVsXG4gICAgICA/LnF1ZXJ5KHtcbiAgICAgICAgbWVzc2FnZXM6IHtcbiAgICAgICAgICBsaW1pdDogdGhpcy5tZXNzYWdlUGFnZVNpemUsXG4gICAgICAgICAgW2RpcmVjdGlvbiA9PT0gJ29sZGVyJyA/ICdpZF9sdCcgOiAnaWRfZ3QnXTogbGFzdE1lc3NhZ2VJZCxcbiAgICAgICAgfSxcbiAgICAgICAgbWVtYmVyczogeyBsaW1pdDogMCB9LFxuICAgICAgICB3YXRjaGVyczogeyBsaW1pdDogMCB9LFxuICAgICAgfSlcbiAgICAgIC50aGVuKChyZXMpID0+IHtcbiAgICAgICAgaWYgKFxuICAgICAgICAgIGFjdGl2ZUNobmFubmVsPy5kYXRhPy5pZCA9PT1cbiAgICAgICAgICB0aGlzLmFjdGl2ZUNoYW5uZWxTdWJqZWN0LmdldFZhbHVlKCk/LmRhdGE/LmlkXG4gICAgICAgICkge1xuICAgICAgICAgIHRoaXMuYWN0aXZlQ2hhbm5lbE1lc3NhZ2VzU3ViamVjdC5uZXh0KFtcbiAgICAgICAgICAgIC4uLmFjdGl2ZUNobmFubmVsLnN0YXRlLm1lc3NhZ2VzLFxuICAgICAgICAgIF0pO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHJlcztcbiAgICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIExvYWRzIHRoZSBuZXh0IHBhZ2Ugb2YgbWVzc2FnZXMgb2YgdGhlIGFjdGl2ZSB0aHJlYWQuIFRoZSBwYWdlIHNpemUgY2FuIGJlIHNldCBpbiB0aGUgW3F1ZXJ5IG9wdGlvbl0oL2NoYXQvZG9jcy9qYXZhc2NyaXB0L3F1ZXJ5X2NoYW5uZWxzLyNxdWVyeS1vcHRpb25zKSBvYmplY3QuXG4gICAqIEBwYXJhbSBkaXJlY3Rpb25cbiAgICovXG4gIGxvYWRNb3JlVGhyZWFkUmVwbGllcyhkaXJlY3Rpb246ICdvbGRlcicgfCAnbmV3ZXInID0gJ29sZGVyJykge1xuICAgIGlmIChkaXJlY3Rpb24gPT09ICduZXdlcicpIHtcbiAgICAgIC8vIFRocmVhZCByZXBsaWVzIGFyZW4ndCBicm9rZSBpbnRvIGRpZmZlcmVudCBtZXNzYWdlIHNldHMsIGFjdGl2ZVRocmVhZE1lc3NhZ2VzJCB3aWxsIGJlIHJlZnJlc2hlZCBieSBXUyBldmVudHMsIG5vIG5lZWQgZm9yIGEgcmVxdWVzdFxuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICBjb25zdCBhY3RpdmVDaG5hbm5lbCA9IHRoaXMuYWN0aXZlQ2hhbm5lbFN1YmplY3QuZ2V0VmFsdWUoKTtcbiAgICBjb25zdCBwYXJlbnRNZXNzYWdlSWQgPSB0aGlzLmFjdGl2ZVBhcmVudE1lc3NhZ2VJZFN1YmplY3QuZ2V0VmFsdWUoKTtcbiAgICBpZiAoIXBhcmVudE1lc3NhZ2VJZCB8fCAhYWN0aXZlQ2huYW5uZWwpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgY29uc3QgdGhyZWFkTWVzc2FnZXMgPSB0aGlzLmFjdGl2ZVRocmVhZE1lc3NhZ2VzU3ViamVjdC5nZXRWYWx1ZSgpO1xuICAgIGNvbnN0IGxhc3RNZXNzYWdlSWQgPVxuICAgICAgdGhyZWFkTWVzc2FnZXNbZGlyZWN0aW9uID09PSAnb2xkZXInID8gMCA6IHRocmVhZE1lc3NhZ2VzLmxlbmd0aCAtIDFdPy5pZDtcbiAgICByZXR1cm4gYWN0aXZlQ2huYW5uZWxcbiAgICAgIC5nZXRSZXBsaWVzKHBhcmVudE1lc3NhZ2VJZCwge1xuICAgICAgICBsaW1pdDogdGhpcy5tZXNzYWdlUGFnZVNpemUsXG4gICAgICAgIFtkaXJlY3Rpb24gPT09ICdvbGRlcicgPyAnaWRfbHQnIDogJ2lkX2d0J106IGxhc3RNZXNzYWdlSWQsXG4gICAgICB9KVxuICAgICAgLnRoZW4oKCkgPT4ge1xuICAgICAgICB0aGlzLmFjdGl2ZVRocmVhZE1lc3NhZ2VzU3ViamVjdC5uZXh0KFxuICAgICAgICAgIGFjdGl2ZUNobmFubmVsPy5zdGF0ZS50aHJlYWRzW3BhcmVudE1lc3NhZ2VJZF0gfHwgW10sXG4gICAgICAgICk7XG4gICAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBRdWVyaWVzIHRoZSBjaGFubmVscyB3aXRoIHRoZSBnaXZlbiBmaWx0ZXJzLCBzb3J0cyBhbmQgb3B0aW9ucy4gTW9yZSBpbmZvIGFib3V0IFtjaGFubmVsIHF1ZXJ5aW5nXSgvY2hhdC9kb2NzL2phdmFzY3JpcHQvcXVlcnlfY2hhbm5lbHMvKSBjYW4gYmUgZm91bmQgaW4gdGhlIHBsYXRmb3JtIGRvY3VtZW50YXRpb24uIEJ5IGRlZmF1bHQgdGhlIGZpcnN0IGNoYW5uZWwgaW4gdGhlIGxpc3Qgd2lsbCBiZSBzZXQgYXMgYWN0aXZlIGNoYW5uZWwgYW5kIHdpbGwgYmUgbWFya2VkIGFzIHJlYWQuXG4gICAqIEBwYXJhbSBxdWVyeUNvbmZpZyB0aGUgZmlsdGVyLCBzb3J0IGFuZCBvcHRpb25zIGZvciB0aGUgcXVlcnlcbiAgICogQHBhcmFtIG9wdGlvbnMgYmVoYXZpb3IgY3VzdG9taXphdGlvbiBmb3IgdGhlIGNoYW5uZWwgbGlzdCBhbmQgV2ViU29ja2V0IGV2ZW50IGhhbmRsaW5nXG4gICAqIEByZXR1cm5zIHRoZSBsaXN0IG9mIGNoYW5uZWxzIGZvdW5kIGJ5IHRoZSBxdWVyeVxuICAgKi9cbiAgaW5pdChcbiAgICBxdWVyeUNvbmZpZzogQ2hhbm5lbFF1ZXJ5Q29uZmlnSW5wdXQ8VD4sXG4gICAgb3B0aW9ucz86IENoYW5uZWxTZXJ2aWNlT3B0aW9uczxUPixcbiAgKSB7XG4gICAgdGhpcy5jaGFubmVsUXVlcnlDb25maWcgPSB7XG4gICAgICBmaWx0ZXJzOiBxdWVyeUNvbmZpZy5maWx0ZXJzLFxuICAgICAgc29ydDogcXVlcnlDb25maWcuc29ydCA/PyB7IGxhc3RfbWVzc2FnZV9hdDogLTEgfSxcbiAgICAgIG9wdGlvbnM6IHtcbiAgICAgICAgbGltaXQ6IDI1LFxuICAgICAgICBzdGF0ZTogdHJ1ZSxcbiAgICAgICAgcHJlc2VuY2U6IHRydWUsXG4gICAgICAgIHdhdGNoOiB0cnVlLFxuICAgICAgICBtZXNzYWdlX2xpbWl0OiB0aGlzLm1lc3NhZ2VQYWdlU2l6ZSxcbiAgICAgICAgLi4ucXVlcnlDb25maWcub3B0aW9ucyxcbiAgICAgIH0sXG4gICAgfTtcblxuICAgIHJldHVybiB0aGlzLl9pbml0KHtcbiAgICAgIC4uLm9wdGlvbnMsXG4gICAgICBtZXNzYWdlUGFnZVNpemU6XG4gICAgICAgIHF1ZXJ5Q29uZmlnLm9wdGlvbnM/Lm1lc3NhZ2VfbGltaXQgPz8gdGhpcy5tZXNzYWdlUGFnZVNpemUsXG4gICAgfSk7XG4gIH1cbiAgLyoqXG4gICAqIFF1ZXJpZXMgdGhlIGNoYW5uZWxzIHdpdGggdGhlIGdpdmVuIHF1ZXJ5IGZ1bmN0aW9uLiBNb3JlIGluZm8gYWJvdXQgW2NoYW5uZWwgcXVlcnlpbmddKC9jaGF0L2RvY3MvamF2YXNjcmlwdC9xdWVyeV9jaGFubmVscy8pIGNhbiBiZSBmb3VuZCBpbiB0aGUgcGxhdGZvcm0gZG9jdW1lbnRhdGlvbi5cbiAgICogQHBhcmFtIHF1ZXJ5XG4gICAqIEBwYXJhbSBvcHRpb25zIGJlaGF2aW9yIGN1c3RvbWl6YXRpb24gZm9yIHRoZSBjaGFubmVsIGxpc3QgYW5kIFdlYlNvY2tldCBldmVudCBoYW5kbGluZ1xuICAgKiBAcGFyYW0gb3B0aW9ucy5tZXNzYWdlUGFnZVNpemUgSG93IG1hbnkgbWVzc2FnZXMgc2hvdWxkIHdlIGxvYWQ/IFRoZSBkZWZhdWx0IGlzIDI1XG4gICAqIEByZXR1cm5zIHRoZSBjaGFubmVscyB0aGF0IHdlcmUgbG9hZGVkXG4gICAqL1xuICBpbml0V2l0aEN1c3RvbVF1ZXJ5KFxuICAgIHF1ZXJ5OiAocXVlcnlUeXBlOiBDaGFubmVsUXVlcnlUeXBlKSA9PiBQcm9taXNlPENoYW5uZWxRdWVyeVJlc3VsdDxUPj4sXG4gICAgb3B0aW9uczogQ2hhbm5lbFNlcnZpY2VPcHRpb25zPFQ+ICYgeyBtZXNzYWdlUGFnZVNpemU6IG51bWJlciB9ID0ge1xuICAgICAgc2hvdWxkU2V0QWN0aXZlQ2hhbm5lbDogdHJ1ZSxcbiAgICAgIG1lc3NhZ2VQYWdlU2l6ZTogdGhpcy5tZXNzYWdlUGFnZVNpemUsXG4gICAgfSxcbiAgKSB7XG4gICAgdGhpcy5tZXNzYWdlUGFnZVNpemUgPSBvcHRpb25zPy5tZXNzYWdlUGFnZVNpemUgPz8gdGhpcy5tZXNzYWdlUGFnZVNpemU7XG5cbiAgICB0aGlzLnNob3VsZFNldEFjdGl2ZUNoYW5uZWwgPVxuICAgICAgb3B0aW9ucz8uc2hvdWxkU2V0QWN0aXZlQ2hhbm5lbCA/PyB0aGlzLnNob3VsZFNldEFjdGl2ZUNoYW5uZWw7XG4gICAgY29uc3QgZXZlbnRIYW5kbGVyT3ZlcnJpZGVzID0gb3B0aW9ucz8uZXZlbnRIYW5kbGVyT3ZlcnJpZGVzO1xuICAgIGNvbnN0IG1hbmFnZXJPcHRpb25zID0geyAuLi5vcHRpb25zIH07XG4gICAgZGVsZXRlIG1hbmFnZXJPcHRpb25zPy5ldmVudEhhbmRsZXJPdmVycmlkZXM7XG4gICAgZGVsZXRlIG1hbmFnZXJPcHRpb25zPy5zaG91bGRTZXRBY3RpdmVDaGFubmVsO1xuXG4gICAgdGhpcy5jdXN0b21DaGFubmVsUXVlcnkgPSBxdWVyeTtcbiAgICB0aGlzLmNyZWF0ZUNoYW5uZWxNYW5hZ2VyKHtcbiAgICAgIGV2ZW50SGFuZGxlck92ZXJyaWRlcyxcbiAgICAgIG9wdGlvbnM6IG1hbmFnZXJPcHRpb25zLFxuICAgIH0pO1xuXG4gICAgcmV0dXJuIHRoaXMuX2luaXQob3B0aW9ucyk7XG4gIH1cblxuICAvKipcbiAgICogUmVzZXRzIHRoZSBgYWN0aXZlQ2hhbm5lbCRgLCBgY2hhbm5lbHMkYCBhbmQgYGFjdGl2ZUNoYW5uZWxNZXNzYWdlcyRgIE9ic2VydmFibGVzLiBVc2VmdWwgd2hlbiBkaXNjb25uZWN0aW5nIGEgY2hhdCB1c2VyLCB1c2UgaW4gY29tYmluYXRpb24gd2l0aCBbYGRpc2Nvbm5lY3RVc2VyYF0oL2NoYXQvZG9jcy9zZGsvYW5ndWxhci9zZXJ2aWNlcy9DaGF0Q2xpZW50U2VydmljZS8jZGlzY29ubmVjdHVzZXIvKS5cbiAgICovXG4gIHJlc2V0KCkge1xuICAgIHRoaXMuZGVzZWxlY3RBY3RpdmVDaGFubmVsKCk7XG4gICAgdGhpcy5jaGFubmVsUXVlcnlTdGF0ZVN1YmplY3QubmV4dCh1bmRlZmluZWQpO1xuICAgIHRoaXMuY2xpZW50RXZlbnRzU3Vic2NyaXB0aW9uPy51bnN1YnNjcmliZSgpO1xuICAgIHRoaXMuZGlzbWlzc0Vycm9yTm90aWZpY2F0aW9uPy4oKTtcbiAgICB0aGlzLmRpc21pc3NFcnJvck5vdGlmaWNhdGlvbiA9IHVuZGVmaW5lZDtcbiAgICB0aGlzLmNoYW5uZWxRdWVyeUNvbmZpZyA9IHVuZGVmaW5lZDtcbiAgICB0aGlzLmRlc3Ryb3lDaGFubmVsTWFuYWdlcigpO1xuICAgIHRoaXMuaXNTdGF0ZVJlY292ZXJ5SW5Qcm9ncmVzcyQubmV4dChmYWxzZSk7XG4gIH1cblxuICAvKipcbiAgICogTG9hZHMgdGhlIG5leHQgcGFnZSBvZiBjaGFubmVscy4gVGhlIHBhZ2Ugc2l6ZSBjYW4gYmUgc2V0IGluIHRoZSBbcXVlcnkgb3B0aW9uXSgvY2hhdC9kb2NzL2phdmFzY3JpcHQvcXVlcnlfY2hhbm5lbHMvI3F1ZXJ5LW9wdGlvbnMpIG9iamVjdC5cbiAgICovXG4gIGFzeW5jIGxvYWRNb3JlQ2hhbm5lbHMoKSB7XG4gICAgYXdhaXQgdGhpcy5xdWVyeUNoYW5uZWxzKCduZXh0LXBhZ2UnKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGRzIGEgcmVhY3Rpb24gdG8gYSBtZXNzYWdlLlxuICAgKiBAcGFyYW0gbWVzc2FnZUlkIFRoZSBpZCBvZiB0aGUgbWVzc2FnZSB0byBhZGQgdGhlIHJlYWN0aW9uIHRvXG4gICAqIEBwYXJhbSByZWFjdGlvblR5cGUgVGhlIHR5cGUgb2YgdGhlIHJlYWN0aW9uXG4gICAqIEBwYXJhbSBjdXN0b21EYXRhXG4gICAqL1xuICBhc3luYyBhZGRSZWFjdGlvbihcbiAgICBtZXNzYWdlSWQ6IHN0cmluZyxcbiAgICByZWFjdGlvblR5cGU6IE1lc3NhZ2VSZWFjdGlvblR5cGUsXG4gICAgY3VzdG9tRGF0YT86IFRbJ3JlYWN0aW9uVHlwZSddLFxuICApIHtcbiAgICBhd2FpdCB0aGlzLmFjdGl2ZUNoYW5uZWxTdWJqZWN0LmdldFZhbHVlKCk/LnNlbmRSZWFjdGlvbihtZXNzYWdlSWQsIHtcbiAgICAgIHR5cGU6IHJlYWN0aW9uVHlwZSxcbiAgICAgIC4uLmN1c3RvbURhdGEsXG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogUmVtb3ZlcyBhIHJlYWN0aW9uIGZyb20gYSBtZXNzYWdlLlxuICAgKiBAcGFyYW0gbWVzc2FnZUlkIFRoZSBpZCBvZiB0aGUgbWVzc2FnZSB0byByZW1vdmUgdGhlIHJlYWN0aW9uIGZyb21cbiAgICogQHBhcmFtIHJlYWN0aW9uVHlwZSBUaHIgdHlwZSBvZiByZWFjdGlvbiB0byByZW1vdmVcbiAgICovXG4gIGFzeW5jIHJlbW92ZVJlYWN0aW9uKG1lc3NhZ2VJZDogc3RyaW5nLCByZWFjdGlvblR5cGU6IE1lc3NhZ2VSZWFjdGlvblR5cGUpIHtcbiAgICBhd2FpdCB0aGlzLmFjdGl2ZUNoYW5uZWxTdWJqZWN0XG4gICAgICAuZ2V0VmFsdWUoKVxuICAgICAgPy5kZWxldGVSZWFjdGlvbihtZXNzYWdlSWQsIHJlYWN0aW9uVHlwZSk7XG4gIH1cblxuICAvKipcbiAgICogU2VuZHMgYSBtZXNzYWdlIHRvIHRoZSBhY3RpdmUgY2hhbm5lbC4gVGhlIG1lc3NhZ2UgaXMgaW1tZWRpYXRlbHkgYWRkZWQgdG8gdGhlIG1lc3NhZ2UgbGlzdCwgaWYgYW4gZXJyb3Igb2NjdXJzIGFuZCB0aGUgbWVzc2FnZSBjYW4ndCBiZSBzZW50LCB0aGUgZXJyb3IgaXMgaW5kaWNhdGVkIGluIGBzdGF0ZWAgb2YgdGhlIG1lc3NhZ2UuXG4gICAqIEBwYXJhbSB0ZXh0IFRoZSB0ZXh0IG9mIHRoZSBtZXNzYWdlXG4gICAqIEBwYXJhbSBhdHRhY2htZW50cyBUaGUgYXR0YWNobWVudHNcbiAgICogQHBhcmFtIG1lbnRpb25lZFVzZXJzIE1lbnRpb25lZCB1c2Vyc1xuICAgKiBAcGFyYW0gcGFyZW50SWQgSWQgb2YgdGhlIHBhcmVudCBtZXNzYWdlIChpZiBzZW5kaW5nIGEgdGhyZWFkIHJlcGx5KVxuICAgKiBAcGFyYW0gcXVvdGVkTWVzc2FnZUlkIElkIG9mIHRoZSBtZXNzYWdlIHRvIHF1b3RlIChpZiBzZW5kaW5nIGEgcXVvdGUgcmVwbHkpXG4gICAqIEBwYXJhbSBjdXN0b21EYXRhXG4gICAqL1xuICBhc3luYyBzZW5kTWVzc2FnZShcbiAgICB0ZXh0OiBzdHJpbmcsXG4gICAgYXR0YWNobWVudHM6IEF0dGFjaG1lbnQ8VD5bXSA9IFtdLFxuICAgIG1lbnRpb25lZFVzZXJzOiBVc2VyUmVzcG9uc2U8VD5bXSA9IFtdLFxuICAgIHBhcmVudElkOiBzdHJpbmcgfCB1bmRlZmluZWQgPSB1bmRlZmluZWQsXG4gICAgcXVvdGVkTWVzc2FnZUlkOiBzdHJpbmcgfCB1bmRlZmluZWQgPSB1bmRlZmluZWQsXG4gICAgY3VzdG9tRGF0YTogdW5kZWZpbmVkIHwgUGFydGlhbDxUWydtZXNzYWdlVHlwZSddPiA9IHVuZGVmaW5lZCxcbiAgKSB7XG4gICAgbGV0IGlucHV0OiBNZXNzYWdlSW5wdXQ8VD4gPSB7XG4gICAgICB0ZXh0LFxuICAgICAgYXR0YWNobWVudHMsXG4gICAgICBtZW50aW9uZWRVc2VycyxcbiAgICAgIHBhcmVudElkLFxuICAgICAgcXVvdGVkTWVzc2FnZUlkLFxuICAgICAgY3VzdG9tRGF0YSxcbiAgICB9O1xuICAgIGlmICh0aGlzLmJlZm9yZVNlbmRNZXNzYWdlKSB7XG4gICAgICBpbnB1dCA9IGF3YWl0IHRoaXMuYmVmb3JlU2VuZE1lc3NhZ2UoaW5wdXQpO1xuICAgIH1cbiAgICBjb25zdCBwcmV2aWV3ID0gY3JlYXRlTWVzc2FnZVByZXZpZXcoXG4gICAgICB0aGlzLmNoYXRDbGllbnRTZXJ2aWNlLmNoYXRDbGllbnQudXNlciEsXG4gICAgICBpbnB1dC50ZXh0LFxuICAgICAgaW5wdXQuYXR0YWNobWVudHMsXG4gICAgICBpbnB1dC5tZW50aW9uZWRVc2VycyxcbiAgICAgIGlucHV0LnBhcmVudElkLFxuICAgICAgaW5wdXQucXVvdGVkTWVzc2FnZUlkLFxuICAgICAgaW5wdXQuY3VzdG9tRGF0YSxcbiAgICApO1xuICAgIGNvbnN0IGNoYW5uZWwgPSB0aGlzLmFjdGl2ZUNoYW5uZWxTdWJqZWN0LmdldFZhbHVlKCkhO1xuICAgIHByZXZpZXcucmVhZEJ5ID0gW107XG4gICAgY2hhbm5lbC5zdGF0ZS5hZGRNZXNzYWdlU29ydGVkKHByZXZpZXcsIHRydWUpO1xuICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgdGhpcy5zZW5kTWVzc2FnZVJlcXVlc3QocHJldmlldywgaW5wdXQuY3VzdG9tRGF0YSk7XG4gICAgcmV0dXJuIHJlc3BvbnNlO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlc2VuZHMgdGhlIGdpdmVuIG1lc3NhZ2UgdG8gdGhlIGFjdGl2ZSBjaGFubmVsXG4gICAqIEBwYXJhbSBtZXNzYWdlIFRoZSBtZXNzYWdlIHRvIHJlc2VuZFxuICAgKi9cbiAgYXN5bmMgcmVzZW5kTWVzc2FnZShtZXNzYWdlOiBTdHJlYW1NZXNzYWdlKSB7XG4gICAgY29uc3QgY2hhbm5lbCA9IHRoaXMuYWN0aXZlQ2hhbm5lbFN1YmplY3QuZ2V0VmFsdWUoKSE7XG4gICAgY2hhbm5lbC5zdGF0ZS5hZGRNZXNzYWdlU29ydGVkKFxuICAgICAge1xuICAgICAgICAuLi4obWVzc2FnZSBhcyB1bmtub3duIGFzIE1lc3NhZ2VSZXNwb25zZTxUPiksXG4gICAgICAgIGVycm9yU3RhdHVzQ29kZTogdW5kZWZpbmVkLFxuICAgICAgICBzdGF0dXM6ICdzZW5kaW5nJyxcbiAgICAgIH0sXG4gICAgICB0cnVlLFxuICAgICk7XG4gICAgcmV0dXJuIHRoaXMuc2VuZE1lc3NhZ2VSZXF1ZXN0KG1lc3NhZ2UsIHVuZGVmaW5lZCwgdHJ1ZSk7XG4gIH1cblxuICAvKipcbiAgICogVXBkYXRlcyB0aGUgbWVzc2FnZSBpbiB0aGUgYWN0aXZlIGNoYW5uZWxcbiAgICogQHBhcmFtIG1lc3NhZ2UgTWVzYWdlIHRvIGJlIHVwZGF0ZWRcbiAgICovXG4gIGFzeW5jIHVwZGF0ZU1lc3NhZ2UobWVzc2FnZTogU3RyZWFtTWVzc2FnZTxUPikge1xuICAgIGxldCBtZXNzYWdlVG9VcGRhdGUgPSB7XG4gICAgICAuLi5tZXNzYWdlLFxuICAgIH07XG4gICAgZGVsZXRlIG1lc3NhZ2VUb1VwZGF0ZS5pMThuO1xuICAgIGlmICh0aGlzLmJlZm9yZVVwZGF0ZU1lc3NhZ2UpIHtcbiAgICAgIG1lc3NhZ2VUb1VwZGF0ZSA9IGF3YWl0IHRoaXMuYmVmb3JlVXBkYXRlTWVzc2FnZShcbiAgICAgICAgbWVzc2FnZVRvVXBkYXRlIGFzIFN0cmVhbU1lc3NhZ2UsXG4gICAgICApO1xuICAgIH1cbiAgICBpZiAobWVzc2FnZVRvVXBkYXRlLnJlYWRCeSkge1xuICAgICAgZGVsZXRlIChtZXNzYWdlVG9VcGRhdGUgYXMgT21pdDxTdHJlYW1NZXNzYWdlPFQ+LCAncmVhZEJ5Jz4pLnJlYWRCeTtcbiAgICB9XG4gICAgaWYgKG1lc3NhZ2UubW9kZXJhdGlvbl9kZXRhaWxzKSB7XG4gICAgICByZXR1cm4gdGhpcy5yZXNlbmRNZXNzYWdlKG1lc3NhZ2UpO1xuICAgIH1cbiAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IHRoaXMuY2hhdENsaWVudFNlcnZpY2UuY2hhdENsaWVudC51cGRhdGVNZXNzYWdlKFxuICAgICAgbWVzc2FnZVRvVXBkYXRlIGFzIHVua25vd24gYXMgVXBkYXRlZE1lc3NhZ2U8VD4sXG4gICAgKTtcblxuICAgIGNvbnN0IGNoYW5uZWwgPSB0aGlzLmNoYW5uZWxzU3ViamVjdFxuICAgICAgLmdldFZhbHVlKClcbiAgICAgID8uZmluZCgoYykgPT4gYy5jaWQgPT09IG1lc3NhZ2UuY2lkKTtcblxuICAgIGlmIChcbiAgICAgIHJlc3BvbnNlLm1lc3NhZ2UudHlwZSA9PT0gJ2Vycm9yJyAmJlxuICAgICAgcmVzcG9uc2UubWVzc2FnZS5tb2RlcmF0aW9uX2RldGFpbHNcbiAgICApIHtcbiAgICAgIHRoaXMubm90aWZpY2F0aW9uU2VydmljZS5hZGRUZW1wb3JhcnlOb3RpZmljYXRpb24oXG4gICAgICAgICdzdHJlYW1DaGF0LlRoaXMgbWVzc2FnZSBkaWQgbm90IG1lZXQgb3VyIGNvbnRlbnQgZ3VpZGVsaW5lcycsXG4gICAgICApO1xuICAgICAgcmV0dXJuIG1lc3NhZ2U7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMudHJhbnNmb3JtVG9TdHJlYW1NZXNzYWdlKHJlc3BvbnNlLm1lc3NhZ2UsIGNoYW5uZWwpO1xuICB9XG5cbiAgLyoqXG4gICAqIERlbGV0ZXMgdGhlIG1lc3NhZ2UgZnJvbSB0aGUgYWN0aXZlIGNoYW5uZWxcbiAgICogQHBhcmFtIG1lc3NhZ2UgTWVzc2FnZSB0byBiZSBkZWxldGVkXG4gICAqIEBwYXJhbSBpc0xvY2FsRGVsZXRlIHNldCB0aGlzIGB0cnVlYCBpZiB5b3Ugd2FudCB0byBkZWxldGUgYSBtZXNzYWdlIHRoYXQncyBvbmx5IHBhcnQgb2YgdGhlIGxvY2FsIHN0YXRlLCBub3QgeWV0IHNhdmVkIG9uIHRoZSBiYWNrZW5kXG4gICAqL1xuICBhc3luYyBkZWxldGVNZXNzYWdlKG1lc3NhZ2U6IFN0cmVhbU1lc3NhZ2UsIGlzTG9jYWxEZWxldGUgPSBmYWxzZSkge1xuICAgIGlmIChpc0xvY2FsRGVsZXRlICYmIHRoaXMuYWN0aXZlQ2hhbm5lbCkge1xuICAgICAgY29uc3QgcmVzdWx0ID0gdGhpcy5hY3RpdmVDaGFubmVsLnN0YXRlLnJlbW92ZU1lc3NhZ2Uoe1xuICAgICAgICBpZDogbWVzc2FnZS5pZCxcbiAgICAgICAgcGFyZW50X2lkOiBtZXNzYWdlLnBhcmVudF9pZCxcbiAgICAgIH0pO1xuICAgICAgaWYgKHJlc3VsdCkge1xuICAgICAgICBtZXNzYWdlLnBhcmVudF9pZFxuICAgICAgICAgID8gdGhpcy5hY3RpdmVUaHJlYWRNZXNzYWdlc1N1YmplY3QubmV4dChcbiAgICAgICAgICAgICAgdGhpcy5hY3RpdmVDaGFubmVsLnN0YXRlLnRocmVhZHNbbWVzc2FnZS5wYXJlbnRfaWRdLFxuICAgICAgICAgICAgKVxuICAgICAgICAgIDogdGhpcy5hY3RpdmVDaGFubmVsTWVzc2FnZXNTdWJqZWN0Lm5leHQoXG4gICAgICAgICAgICAgIHRoaXMuYWN0aXZlQ2hhbm5lbC5zdGF0ZS5tZXNzYWdlcyxcbiAgICAgICAgICAgICk7XG4gICAgICB9XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGlmICh0aGlzLm1lc3NhZ2VEZWxldGVDb25maXJtYXRpb25IYW5kbGVyKSB7XG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCB0aGlzLm1lc3NhZ2VEZWxldGVDb25maXJtYXRpb25IYW5kbGVyKG1lc3NhZ2UpO1xuICAgICAgaWYgKHJlc3VsdCkge1xuICAgICAgICBhd2FpdCB0aGlzLmNoYXRDbGllbnRTZXJ2aWNlLmNoYXRDbGllbnQuZGVsZXRlTWVzc2FnZShtZXNzYWdlLmlkKTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgYXdhaXQgdGhpcy5jaGF0Q2xpZW50U2VydmljZS5jaGF0Q2xpZW50LmRlbGV0ZU1lc3NhZ2UobWVzc2FnZS5pZCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFVwbG9hZHMgZmlsZXMgdG8gdGhlIGNoYW5uZWwuIElmIHlvdSB3YW50IHRvIGtub3cgbW9yZSBhYm91dCBbZmlsZSB1cGxvYWRzXSgvY2hhdC9kb2NzL2phdmFzY3JpcHQvZmlsZV91cGxvYWRzLykgY2hlY2sgb3V0IHRoZSBwbGF0Zm9ybSBkb2N1bWVudGF0aW9uLlxuICAgKiBAcGFyYW0gdXBsb2FkcyB0aGUgYXR0YWNobWVudHMgdG8gdXBsb2FkIChvdXRwdXQgb2YgdGhlIFtgQXR0YWNobWVudFNlcnZpY2VgXSgvY2hhdC9kb2NzL3Nkay9hbmd1bGFyL3NlcnZpY2VzL0F0dGFjaG1lbnRTZXJ2aWNlLykpXG4gICAqIEByZXR1cm5zIHRoZSByZXN1bHQgb2YgZmlsZSB1cGxvYWQgcmVxdWVzdHNcbiAgICovXG4gIGFzeW5jIHVwbG9hZEF0dGFjaG1lbnRzKFxuICAgIHVwbG9hZHM6IEF0dGFjaG1lbnRVcGxvYWRbXSxcbiAgKTogUHJvbWlzZTxBdHRhY2htZW50VXBsb2FkW10+IHtcbiAgICBjb25zdCByZXN1bHQ6IEF0dGFjaG1lbnRVcGxvYWRbXSA9IFtdO1xuICAgIGNvbnN0IGNoYW5uZWwgPSB0aGlzLmFjdGl2ZUNoYW5uZWxTdWJqZWN0LmdldFZhbHVlKCkhO1xuICAgIGNvbnN0IHVwbG9hZFJlc3VsdHMgPSBhd2FpdCBQcm9taXNlLmFsbFNldHRsZWQoXG4gICAgICB1cGxvYWRzLm1hcCgodXBsb2FkKSA9PlxuICAgICAgICB1cGxvYWQudHlwZSA9PT0gJ2ltYWdlJ1xuICAgICAgICAgID8gdGhpcy5jdXN0b21JbWFnZVVwbG9hZFJlcXVlc3RcbiAgICAgICAgICAgID8gdGhpcy5jdXN0b21JbWFnZVVwbG9hZFJlcXVlc3QodXBsb2FkLmZpbGUsIGNoYW5uZWwpXG4gICAgICAgICAgICA6IGNoYW5uZWwuc2VuZEltYWdlKHVwbG9hZC5maWxlLCB1cGxvYWQuZmlsZS5uYW1lLCB1cGxvYWQuZmlsZS50eXBlKVxuICAgICAgICAgIDogdGhpcy5jdXN0b21GaWxlVXBsb2FkUmVxdWVzdFxuICAgICAgICAgICAgPyB0aGlzLmN1c3RvbUZpbGVVcGxvYWRSZXF1ZXN0KHVwbG9hZC5maWxlLCBjaGFubmVsKVxuICAgICAgICAgICAgOiBjaGFubmVsLnNlbmRGaWxlKHVwbG9hZC5maWxlLCB1cGxvYWQuZmlsZS5uYW1lLCB1cGxvYWQuZmlsZS50eXBlKSxcbiAgICAgICksXG4gICAgKTtcbiAgICB1cGxvYWRSZXN1bHRzLmZvckVhY2goKHVwbG9hZFJlc3VsdCwgaSkgPT4ge1xuICAgICAgY29uc3QgZmlsZSA9IHVwbG9hZHNbaV0uZmlsZTtcbiAgICAgIGNvbnN0IHR5cGUgPSB1cGxvYWRzW2ldLnR5cGU7XG4gICAgICBpZiAodXBsb2FkUmVzdWx0LnN0YXR1cyA9PT0gJ2Z1bGZpbGxlZCcpIHtcbiAgICAgICAgcmVzdWx0LnB1c2goe1xuICAgICAgICAgIGZpbGUsXG4gICAgICAgICAgdHlwZSxcbiAgICAgICAgICBzdGF0ZTogJ3N1Y2Nlc3MnLFxuICAgICAgICAgIHVybDogdXBsb2FkUmVzdWx0LnZhbHVlLmZpbGUsXG4gICAgICAgICAgLyogZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnNhZmUtYXNzaWdubWVudCwgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVuc2FmZS1tZW1iZXItYWNjZXNzLCBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tZXhwbGljaXQtYW55ICovXG4gICAgICAgICAgdGh1bWJfdXJsOiAodXBsb2FkUmVzdWx0LnZhbHVlIGFzIGFueSkudGh1bWJfdXJsLFxuICAgICAgICB9KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGxldCByZWFzb246IEF0dGFjaG1lbnRVcGxvYWRFcnJvclJlYXNvbiA9ICd1bmtub3duJztcbiAgICAgICAgbGV0IGV4dHJhRGF0YTogeyBwYXJhbTogc3RyaW5nIH0gfCB1bmRlZmluZWQ7XG4gICAgICAgIC8qIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW5zYWZlLWFzc2lnbm1lbnQgKi9cbiAgICAgICAgY29uc3QgbWVzc2FnZTogc3RyaW5nIHwgdW5kZWZpbmVkID1cbiAgICAgICAgICAvKiBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVuc2FmZS1tZW1iZXItYWNjZXNzICovXG4gICAgICAgICAgdXBsb2FkUmVzdWx0LnJlYXNvbi5yZXNwb25zZT8uZGF0YT8ubWVzc2FnZTtcbiAgICAgICAgLyogZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnNhZmUtYXNzaWdubWVudCAqL1xuICAgICAgICBjb25zdCBjb2RlOiBudW1iZXIgfCB1bmRlZmluZWQgPVxuICAgICAgICAgIC8qIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW5zYWZlLW1lbWJlci1hY2Nlc3MgKi9cbiAgICAgICAgICB1cGxvYWRSZXN1bHQucmVhc29uLnJlc3BvbnNlPy5kYXRhPy5jb2RlO1xuICAgICAgICBpZiAoXG4gICAgICAgICAgY29kZSA9PT0gMjIgfHxcbiAgICAgICAgICAoY29kZSA9PT0gNCAmJiBtZXNzYWdlPy50b0xvd2VyQ2FzZSgpPy5pbmNsdWRlcygnYnl0ZXMnKSlcbiAgICAgICAgKSB7XG4gICAgICAgICAgcmVhc29uID0gJ2ZpbGUtc2l6ZSc7XG4gICAgICAgICAgZXh0cmFEYXRhID0ge1xuICAgICAgICAgICAgcGFyYW06XG4gICAgICAgICAgICAgIC9cXGQrTUJ8XFxkK1xccz9ieXRlcy8uZXhlYyhtZXNzYWdlIHx8ICcnKT8uWzBdIHx8XG4gICAgICAgICAgICAgIGAke3RoaXMuYXR0YWNobWVudE1heFNpemVGYWxsYmFja0luTUJ9TUJgLFxuICAgICAgICAgIH07XG4gICAgICAgICAgaWYgKGV4dHJhRGF0YS5wYXJhbS5pbmNsdWRlcygnYnl0ZXMnKSkge1xuICAgICAgICAgICAgY29uc3QgbGltaXRJbkJ5dGVzID0gKyhcbiAgICAgICAgICAgICAgL1xcZCsvLmV4ZWMoZXh0cmFEYXRhLnBhcmFtKT8uWzBdIHx8XG4gICAgICAgICAgICAgIHRoaXMuYXR0YWNobWVudE1heFNpemVGYWxsYmFja0luTUIgKiAxMDI0ICogMTAyNFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIGV4dHJhRGF0YS5wYXJhbSA9IGAke2xpbWl0SW5CeXRlcyAvICgxMDI0ICogMTAyNCl9TUJgO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIGlmIChcbiAgICAgICAgICBjb2RlID09PSA0ICYmXG4gICAgICAgICAgbWVzc2FnZT8udG9Mb3dlckNhc2UoKT8uaW5jbHVkZXMoJ2ZpbGUgZXh0ZW5zaW9uJylcbiAgICAgICAgKSB7XG4gICAgICAgICAgcmVhc29uID0gJ2ZpbGUtZXh0ZW5zaW9uJztcbiAgICAgICAgICBleHRyYURhdGEgPSB7IHBhcmFtOiAvXFwuXFx3Ky8uZXhlYyhtZXNzYWdlKT8uWzBdIHx8ICcnIH07XG4gICAgICAgIH1cbiAgICAgICAgcmVzdWx0LnB1c2goe1xuICAgICAgICAgIGZpbGUsXG4gICAgICAgICAgdHlwZSxcbiAgICAgICAgICBzdGF0ZTogJ2Vycm9yJyxcbiAgICAgICAgICBlcnJvclJlYXNvbjogcmVhc29uLFxuICAgICAgICAgIGVycm9yRXh0cmFJbmZvOiBleHRyYURhdGEgPyBbZXh0cmFEYXRhXSA6IHVuZGVmaW5lZCxcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG5cbiAgLyoqXG4gICAqIERlbGV0ZXMgYW4gdXBsb2FkZWQgZmlsZSBieSBVUkwuIElmIHlvdSB3YW50IHRvIGtub3cgbW9yZSBhYm91dCBbZmlsZSB1cGxvYWRzXSgvY2hhdC9kb2NzL2phdmFzY3JpcHQvZmlsZV91cGxvYWRzLykgY2hlY2sgb3V0IHRoZSBwbGF0Zm9ybSBkb2N1bWVudGF0aW9uXG4gICAqIEBwYXJhbSBhdHRhY2htZW50VXBsb2FkIEF0dGFjaG1lbnQgdG8gYmUgZGVsZXRlZCAob3V0cHV0IG9mIHRoZSBbYEF0dGFjaG1lbnRTZXJ2aWNlYF0oL2NoYXQvZG9jcy9zZGsvYW5ndWxhci9zZXJ2aWNlcy9BdHRhY2htZW50U2VydmljZS8pKVxuICAgKi9cbiAgYXN5bmMgZGVsZXRlQXR0YWNobWVudChhdHRhY2htZW50VXBsb2FkOiBBdHRhY2htZW50VXBsb2FkKSB7XG4gICAgY29uc3QgY2hhbm5lbCA9IHRoaXMuYWN0aXZlQ2hhbm5lbFN1YmplY3QuZ2V0VmFsdWUoKSE7XG4gICAgYXdhaXQgKGF0dGFjaG1lbnRVcGxvYWQudHlwZSA9PT0gJ2ltYWdlJ1xuICAgICAgPyB0aGlzLmN1c3RvbUltYWdlRGVsZXRlUmVxdWVzdFxuICAgICAgICA/IHRoaXMuY3VzdG9tSW1hZ2VEZWxldGVSZXF1ZXN0KGF0dGFjaG1lbnRVcGxvYWQudXJsISwgY2hhbm5lbClcbiAgICAgICAgOiBjaGFubmVsLmRlbGV0ZUltYWdlKGF0dGFjaG1lbnRVcGxvYWQudXJsISlcbiAgICAgIDogdGhpcy5jdXN0b21GaWxlRGVsZXRlUmVxdWVzdFxuICAgICAgICA/IHRoaXMuY3VzdG9tRmlsZURlbGV0ZVJlcXVlc3QoYXR0YWNobWVudFVwbG9hZC51cmwhLCBjaGFubmVsKVxuICAgICAgICA6IGNoYW5uZWwuZGVsZXRlRmlsZShhdHRhY2htZW50VXBsb2FkLnVybCEpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBhdXRvY29tcGxldGUgb3B0aW9ucyBmb3IgY3VycmVudCBjaGFubmVsIG1lbWJlcnMuIElmIHRoZSBjaGFubmVsIGhhcyBsZXNzIHRoYW4gMTAwIG1lbWJlcnMsIGl0IHJldHVybnMgdGhlIGNoYW5uZWwgbWVtYmVycywgb3RoZXJ3aXNlIHNlbmRzIGEgW3NlYXJjaCByZXF1ZXN0XSgvY2hhdC9kb2NzL2phdmFzY3JpcHQvcXVlcnlfbWVtYmVycy8jcGFnaW5hdGlvbi1hbmQtb3JkZXJpbmcpIHdpdGggdGhlIGdpdmVuIHNlYXJjaCB0ZXJtLlxuICAgKiBAcGFyYW0gc2VhcmNoVGVybSBUZXh0IHRvIHNlYXJjaCBmb3IgaW4gdGhlIG5hbWVzIG9mIG1lbWJlcnNcbiAgICogQHJldHVybnMgVGhlIGxpc3Qgb2YgbWVtYmVycyBtYXRjaGluZyB0aGUgc2VhcmNoIGZpbHRlclxuICAgKi9cbiAgYXN5bmMgYXV0b2NvbXBsZXRlTWVtYmVycyhzZWFyY2hUZXJtOiBzdHJpbmcpIHtcbiAgICBjb25zdCBhY3RpdmVDaGFubmVsID0gdGhpcy5hY3RpdmVDaGFubmVsU3ViamVjdC5nZXRWYWx1ZSgpO1xuICAgIGlmICghYWN0aXZlQ2hhbm5lbCkge1xuICAgICAgcmV0dXJuIFtdO1xuICAgIH1cbiAgICBpZiAoT2JqZWN0LmtleXMoYWN0aXZlQ2hhbm5lbC5zdGF0ZS5tZW1iZXJzKS5sZW5ndGggPCAxMDApIHtcbiAgICAgIHJldHVybiBPYmplY3QudmFsdWVzKGFjdGl2ZUNoYW5uZWwuc3RhdGUubWVtYmVycykuZmlsdGVyKFxuICAgICAgICAobSkgPT4gbS51c2VyPy5pZCAhPT0gdGhpcy5jaGF0Q2xpZW50U2VydmljZS5jaGF0Q2xpZW50LnVzZXJJRCEsXG4gICAgICApO1xuICAgIH0gZWxzZSB7XG4gICAgICBpZiAoIXNlYXJjaFRlcm0pIHtcbiAgICAgICAgcmV0dXJuIFtdO1xuICAgICAgfVxuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgYWN0aXZlQ2hhbm5lbC5xdWVyeU1lbWJlcnMoe1xuICAgICAgICBuYW1lOiB7ICRhdXRvY29tcGxldGU6IHNlYXJjaFRlcm0gfSxcbiAgICAgIH0gYXMgTWVtYmVyRmlsdGVyczxUPik7IC8vIFRPRE86IGZpbmQgb3V0IHdoeSB3ZSBuZWVkIHR5cGVjYXN0IGhlcmVcblxuICAgICAgcmV0dXJuIHJlc3VsdC5tZW1iZXJzLmZpbHRlcihcbiAgICAgICAgKG0pID0+IG0udXNlcl9pZCAhPT0gdGhpcy5jaGF0Q2xpZW50U2VydmljZS5jaGF0Q2xpZW50Py51c2VyPy5pZCxcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFtSdW5zIGEgbWVzc2FnZSBhY3Rpb25dKGh0dHBzOi8vZ2V0c3RyZWFtLmlvL2NoYXQvZG9jcy9yZXN0LyNtZXNzYWdlcy1ydW5tZXNzYWdlYWN0aW9uKSBpbiB0aGUgY3VycmVudCBjaGFubmVsLiBVcGRhdGVzIHRoZSBtZXNzYWdlIGxpc3QgYmFzZWQgb24gdGhlIGFjdGlvbiByZXN1bHQgKGlmIG5vIG1lc3NhZ2UgaXMgcmV0dXJuZWQsIHRoZSBtZXNzYWdlIHdpbGwgYmUgcmVtb3ZlZCBmcm9tIHRoZSBtZXNzYWdlIGxpc3QpLlxuICAgKiBAcGFyYW0gbWVzc2FnZUlkXG4gICAqIEBwYXJhbSBmb3JtRGF0YVxuICAgKiBAcGFyYW0gcGFyZW50TWVzc2FnZUlkXG4gICAqL1xuICBhc3luYyBzZW5kQWN0aW9uKFxuICAgIG1lc3NhZ2VJZDogc3RyaW5nLFxuICAgIGZvcm1EYXRhOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+LFxuICAgIHBhcmVudE1lc3NhZ2VJZD86IHN0cmluZyxcbiAgKSB7XG4gICAgY29uc3QgY2hhbm5lbCA9IHRoaXMuYWN0aXZlQ2hhbm5lbFN1YmplY3QuZ2V0VmFsdWUoKSE7XG4gICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBjaGFubmVsLnNlbmRBY3Rpb24obWVzc2FnZUlkLCBmb3JtRGF0YSk7XG4gICAgaWYgKHJlc3BvbnNlPy5tZXNzYWdlKSB7XG4gICAgICBjaGFubmVsLnN0YXRlLmFkZE1lc3NhZ2VTb3J0ZWQoe1xuICAgICAgICAuLi5yZXNwb25zZS5tZXNzYWdlLFxuICAgICAgICBzdGF0dXM6ICdyZWNlaXZlZCcsXG4gICAgICB9KTtcbiAgICAgIGNvbnN0IGlzVGhyZWFkUmVwbHkgPSAhIXJlc3BvbnNlLm1lc3NhZ2UucGFyZW50X2lkO1xuICAgICAgaXNUaHJlYWRSZXBseVxuICAgICAgICA/IHRoaXMuYWN0aXZlVGhyZWFkTWVzc2FnZXNTdWJqZWN0Lm5leHQoW1xuICAgICAgICAgICAgLi4uY2hhbm5lbC5zdGF0ZS50aHJlYWRzW3Jlc3BvbnNlLm1lc3NhZ2UucGFyZW50X2lkIV0sXG4gICAgICAgICAgXSlcbiAgICAgICAgOiB0aGlzLmFjdGl2ZUNoYW5uZWxNZXNzYWdlc1N1YmplY3QubmV4dChbLi4uY2hhbm5lbC5zdGF0ZS5tZXNzYWdlc10pO1xuICAgIH0gZWxzZSB7XG4gICAgICBjaGFubmVsLnN0YXRlLnJlbW92ZU1lc3NhZ2Uoe1xuICAgICAgICBpZDogbWVzc2FnZUlkLFxuICAgICAgICBwYXJlbnRfaWQ6IHBhcmVudE1lc3NhZ2VJZCxcbiAgICAgIH0pO1xuICAgICAgaWYgKHBhcmVudE1lc3NhZ2VJZCkge1xuICAgICAgICB0aGlzLmFjdGl2ZVRocmVhZE1lc3NhZ2VzU3ViamVjdC5uZXh0KFxuICAgICAgICAgIGNoYW5uZWwuc3RhdGUudGhyZWFkc1t0aGlzLmFjdGl2ZVBhcmVudE1lc3NhZ2VJZFN1YmplY3QuZ2V0VmFsdWUoKSFdLFxuICAgICAgICApO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5hY3RpdmVDaGFubmVsTWVzc2FnZXNTdWJqZWN0Lm5leHQoWy4uLmNoYW5uZWwuc3RhdGUubWVzc2FnZXNdKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogU2VsZWN0cyBvciBkZXNlbGVjdHMgdGhlIGN1cnJlbnQgbWVzc2FnZSB0byBxdW90ZSByZXBseSB0b1xuICAgKiBAcGFyYW0gbWVzc2FnZSBUaGUgbWVzc2FnZSB0byBzZWxlY3QsIGlmIGNhbGxlZCB3aXRoIGB1bmRlZmluZWRgLCBpdCBkZXNlbGVjdHMgdGhlIG1lc3NhZ2VcbiAgICovXG4gIHNlbGVjdE1lc3NhZ2VUb1F1b3RlKG1lc3NhZ2U6IFN0cmVhbU1lc3NhZ2UgfCB1bmRlZmluZWQpIHtcbiAgICB0aGlzLm1lc3NhZ2VUb1F1b3RlU3ViamVjdC5uZXh0KG1lc3NhZ2UpO1xuICB9XG5cbiAgLyoqXG4gICAqIEFkZCBhIG5ldyBjaGFubmVsIHRvIHRoZSBjaGFubmVsIGxpc3RcbiAgICogVGhlIGNoYW5uZWwgd2lsbCBiZSBhZGRlZCB0byB0aGUgYmVnaW5uaW5nIG9mIHRoZSBjaGFubmVsIGxpc3RcbiAgICogQHBhcmFtIGNoYW5uZWxcbiAgICovXG4gIGFkZENoYW5uZWwoY2hhbm5lbDogQ2hhbm5lbDxUPikge1xuICAgIGlmICghdGhpcy5jaGFubmVsTWFuYWdlcikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdDaGFubmVsIHNlcnZpY2Ugbm90IGluaXRpYWxpemVkJyk7XG4gICAgfVxuICAgIGlmICghdGhpcy5jaGFubmVscy5maW5kKChjKSA9PiBjLmNpZCA9PT0gY2hhbm5lbC5jaWQpKSB7XG4gICAgICB0aGlzLmNoYW5uZWxNYW5hZ2VyPy5zZXRDaGFubmVscyhcbiAgICAgICAgcHJvbW90ZUNoYW5uZWwoe1xuICAgICAgICAgIGNoYW5uZWxzOiB0aGlzLmNoYW5uZWxzLFxuICAgICAgICAgIGNoYW5uZWxUb01vdmU6IGNoYW5uZWwsXG4gICAgICAgICAgc29ydDogdGhpcy5jaGFubmVsUXVlcnlDb25maWc/LnNvcnQgPz8gW10sXG4gICAgICAgIH0pLFxuICAgICAgKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICpcbiAgICogQHBhcmFtIGNpZFxuICAgKi9cbiAgcmVtb3ZlQ2hhbm5lbChjaWQ6IHN0cmluZykge1xuICAgIGlmICghdGhpcy5jaGFubmVsTWFuYWdlcikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdDaGFubmVsIHNlcnZpY2Ugbm90IGluaXRpYWxpemVkJyk7XG4gICAgfVxuICAgIGNvbnN0IHJlbWFpbmluZ0NoYW5uZWxzID0gdGhpcy5jaGFubmVscy5maWx0ZXIoKGMpID0+IGMuY2lkICE9PSBjaWQpO1xuXG4gICAgdGhpcy5jaGFubmVsTWFuYWdlcj8uc2V0Q2hhbm5lbHMocmVtYWluaW5nQ2hhbm5lbHMpO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBzZW5kTWVzc2FnZVJlcXVlc3QoXG4gICAgcHJldmlldzogTWVzc2FnZVJlc3BvbnNlPFQ+IHwgU3RyZWFtTWVzc2FnZTxUPixcbiAgICBjdXN0b21EYXRhPzogUGFydGlhbDxUWydtZXNzYWdlVHlwZSddPixcbiAgICBpc1Jlc2VuZCA9IGZhbHNlLFxuICApIHtcbiAgICBjb25zdCBjaGFubmVsID0gdGhpcy5hY3RpdmVDaGFubmVsU3ViamVjdC5nZXRWYWx1ZSgpITtcbiAgICBjb25zdCBpc1RocmVhZFJlcGx5ID0gISFwcmV2aWV3LnBhcmVudF9pZDtcbiAgICBpc1RocmVhZFJlcGx5XG4gICAgICA/IHRoaXMuYWN0aXZlVGhyZWFkTWVzc2FnZXNTdWJqZWN0Lm5leHQoW1xuICAgICAgICAgIC4uLmNoYW5uZWwuc3RhdGUudGhyZWFkc1twcmV2aWV3LnBhcmVudF9pZCFdLFxuICAgICAgICBdKVxuICAgICAgOiB0aGlzLmFjdGl2ZUNoYW5uZWxNZXNzYWdlc1N1YmplY3QubmV4dChbLi4uY2hhbm5lbC5zdGF0ZS5tZXNzYWdlc10pO1xuICAgIHRyeSB7XG4gICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGNoYW5uZWwuc2VuZE1lc3NhZ2Uoe1xuICAgICAgICBpZDogcHJldmlldy5pZCxcbiAgICAgICAgdGV4dDogcHJldmlldy50ZXh0LFxuICAgICAgICBhdHRhY2htZW50czogcHJldmlldy5hdHRhY2htZW50cyxcbiAgICAgICAgbWVudGlvbmVkX3VzZXJzOiBwcmV2aWV3Lm1lbnRpb25lZF91c2Vycz8ubWFwKCh1KSA9PiB1LmlkKSxcbiAgICAgICAgcGFyZW50X2lkOiBwcmV2aWV3LnBhcmVudF9pZCxcbiAgICAgICAgcXVvdGVkX21lc3NhZ2VfaWQ6IHByZXZpZXcucXVvdGVkX21lc3NhZ2VfaWQsXG4gICAgICAgIC4uLmN1c3RvbURhdGEsXG4gICAgICB9IGFzIE1lc3NhZ2U8VD4pOyAvLyBUT0RPOiBmaW5kIG91dCB3aHkgd2UgbmVlZCB0eXBlY2FzdCBoZXJlXG4gICAgICBjaGFubmVsLnN0YXRlLmFkZE1lc3NhZ2VTb3J0ZWQoXG4gICAgICAgIHtcbiAgICAgICAgICAuLi5yZXNwb25zZS5tZXNzYWdlLFxuICAgICAgICAgIHN0YXR1czogJ3JlY2VpdmVkJyxcbiAgICAgICAgfSxcbiAgICAgICAgdHJ1ZSxcbiAgICAgICk7XG4gICAgICBpc1RocmVhZFJlcGx5XG4gICAgICAgID8gdGhpcy5hY3RpdmVUaHJlYWRNZXNzYWdlc1N1YmplY3QubmV4dChbXG4gICAgICAgICAgICAuLi5jaGFubmVsLnN0YXRlLnRocmVhZHNbcHJldmlldy5wYXJlbnRfaWQhXSxcbiAgICAgICAgICBdKVxuICAgICAgICA6IHRoaXMuYWN0aXZlQ2hhbm5lbE1lc3NhZ2VzU3ViamVjdC5uZXh0KFsuLi5jaGFubmVsLnN0YXRlLm1lc3NhZ2VzXSk7XG4gICAgICBsZXQgbWVzc2FnZXMhOiBTdHJlYW1NZXNzYWdlPFQ+W107XG4gICAgICAoaXNUaHJlYWRSZXBseSA/IHRoaXMuYWN0aXZlVGhyZWFkTWVzc2FnZXMkIDogdGhpcy5hY3RpdmVDaGFubmVsTWVzc2FnZXMkKVxuICAgICAgICAucGlwZSh0YWtlKDEpKVxuICAgICAgICAuc3Vic2NyaWJlKChtKSA9PiAobWVzc2FnZXMgPSBtKSk7XG4gICAgICBjb25zdCBuZXdNZXNzYWdlID0gbWVzc2FnZXNbbWVzc2FnZXMubGVuZ3RoIC0gMV07XG4gICAgICByZXR1cm4gbmV3TWVzc2FnZTtcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tZXhwbGljaXQtYW55XG4gICAgfSBjYXRjaCAoZXJyb3I6IGFueSkge1xuICAgICAgY29uc3Qgc3RyaW5nRXJyb3IgPSBKU09OLnN0cmluZ2lmeShlcnJvcik7XG4gICAgICBjb25zdCBwYXJzZWRFcnJvcjoge1xuICAgICAgICBzdGF0dXM/OiBudW1iZXI7XG4gICAgICAgIGNvZGU/OiBudW1iZXI7XG4gICAgICAgIHJlc3BvbnNlPzogeyBkYXRhPzogeyBtZXNzYWdlPzogc3RyaW5nIH0gfTtcbiAgICAgIH0gPSBzdHJpbmdFcnJvciA/IChKU09OLnBhcnNlKHN0cmluZ0Vycm9yKSBhcyB7IHN0YXR1cz86IG51bWJlciB9KSA6IHt9O1xuXG4gICAgICBsZXQgaXNBbHJlYWR5RXhpc3RzID0gZmFsc2U7XG4gICAgICBpZiAoaXNSZXNlbmQpIHtcbiAgICAgICAgaWYgKFxuICAgICAgICAgIHBhcnNlZEVycm9yLnN0YXR1cyA9PT0gNDAwICYmXG4gICAgICAgICAgcGFyc2VkRXJyb3IuY29kZSA9PT0gNCAmJlxuICAgICAgICAgIHBhcnNlZEVycm9yPy5yZXNwb25zZT8uZGF0YT8ubWVzc2FnZT8uaW5jbHVkZXMoJ2FscmVhZHkgZXhpc3RzJylcbiAgICAgICAgKSB7XG4gICAgICAgICAgaXNBbHJlYWR5RXhpc3RzID0gdHJ1ZTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBjaGFubmVsLnN0YXRlLmFkZE1lc3NhZ2VTb3J0ZWQoXG4gICAgICAgIHtcbiAgICAgICAgICAuLi4ocHJldmlldyBhcyBNZXNzYWdlUmVzcG9uc2U8VD4pLFxuICAgICAgICAgIGVycm9yU3RhdHVzQ29kZTogaXNBbHJlYWR5RXhpc3RzXG4gICAgICAgICAgICA/IHVuZGVmaW5lZFxuICAgICAgICAgICAgOiBwYXJzZWRFcnJvci5zdGF0dXMgfHwgdW5kZWZpbmVkLFxuICAgICAgICAgIHN0YXR1czogaXNBbHJlYWR5RXhpc3RzID8gJ3JlY2VpdmVkJyA6ICdmYWlsZWQnLFxuICAgICAgICB9LFxuICAgICAgICB0cnVlLFxuICAgICAgKTtcbiAgICAgIGlzVGhyZWFkUmVwbHlcbiAgICAgICAgPyB0aGlzLmFjdGl2ZVRocmVhZE1lc3NhZ2VzU3ViamVjdC5uZXh0KFtcbiAgICAgICAgICAgIC4uLmNoYW5uZWwuc3RhdGUudGhyZWFkc1twcmV2aWV3LnBhcmVudF9pZCFdLFxuICAgICAgICAgIF0pXG4gICAgICAgIDogdGhpcy5hY3RpdmVDaGFubmVsTWVzc2FnZXNTdWJqZWN0Lm5leHQoWy4uLmNoYW5uZWwuc3RhdGUubWVzc2FnZXNdKTtcbiAgICAgIGxldCBtZXNzYWdlcyE6IFN0cmVhbU1lc3NhZ2U8VD5bXTtcbiAgICAgIChpc1RocmVhZFJlcGx5ID8gdGhpcy5hY3RpdmVUaHJlYWRNZXNzYWdlcyQgOiB0aGlzLmFjdGl2ZUNoYW5uZWxNZXNzYWdlcyQpXG4gICAgICAgIC5waXBlKHRha2UoMSkpXG4gICAgICAgIC5zdWJzY3JpYmUoKG0pID0+IChtZXNzYWdlcyA9IG0pKTtcbiAgICAgIGNvbnN0IG5ld01lc3NhZ2UgPSBtZXNzYWdlc1ttZXNzYWdlcy5sZW5ndGggLSAxXTtcbiAgICAgIHJldHVybiBuZXdNZXNzYWdlO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBKdW1wcyB0byB0aGUgc2VsZWN0ZWQgbWVzc2FnZSBpbnNpZGUgdGhlIG1lc3NhZ2UgbGlzdCwgaWYgdGhlIG1lc3NhZ2UgaXMgbm90IHlldCBsb2FkZWQsIGl0J2xsIGxvYWQgdGhlIG1lc3NhZ2UgKGFuZCBpdCdzIHN1cnJvdW5kaW5ncykgZnJvbSB0aGUgQVBJLlxuICAgKiBAcGFyYW0gbWVzc2FnZUlkIFRoZSBJRCBvZiB0aGUgbWVzc2FnZSB0byBiZSBsb2FkZWQsICdsYXRlc3QnIG1lYW5zIGp1bXAgdG8gdGhlIGxhdGVzdCBtZXNzYWdlc1xuICAgKiBAcGFyYW0gcGFyZW50TWVzc2FnZUlkIFRoZSBJRCBvZiB0aGUgcGFyZW50IG1lc3NhZ2UgaWYgd2Ugd2FudCB0byBsb2FkIGEgdGhyZWFkIG1lc3NhZ2VcbiAgICovXG4gIGFzeW5jIGp1bXBUb01lc3NhZ2UobWVzc2FnZUlkOiBzdHJpbmcsIHBhcmVudE1lc3NhZ2VJZD86IHN0cmluZykge1xuICAgIHRoaXMuaXNNZXNzYWdlTG9hZGluZ0luUHJvZ3Jlc3MgPSB0cnVlO1xuICAgIGNvbnN0IGFjdGl2ZUNoYW5uZWwgPSB0aGlzLmFjdGl2ZUNoYW5uZWxTdWJqZWN0LmdldFZhbHVlKCk7XG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IGFjdGl2ZUNoYW5uZWw/LnN0YXRlLmxvYWRNZXNzYWdlSW50b1N0YXRlKFxuICAgICAgICBtZXNzYWdlSWQsXG4gICAgICAgIHBhcmVudE1lc3NhZ2VJZCxcbiAgICAgICk7XG4gICAgICBjb25zdCBtZXNzYWdlcyA9IGFjdGl2ZUNoYW5uZWw/LnN0YXRlLm1lc3NhZ2VzIHx8IFtdO1xuICAgICAgdGhpcy5hY3RpdmVDaGFubmVsTWVzc2FnZXNTdWJqZWN0Lm5leHQoWy4uLm1lc3NhZ2VzXSk7XG4gICAgICBpZiAocGFyZW50TWVzc2FnZUlkKSB7XG4gICAgICAgIGNvbnN0IHBhcmVudE1lc3NhZ2UgPSBtZXNzYWdlcy5maW5kKChtKSA9PiBtLmlkID09PSBwYXJlbnRNZXNzYWdlSWQpO1xuICAgICAgICB2b2lkIHRoaXMuc2V0QXNBY3RpdmVQYXJlbnRNZXNzYWdlKHBhcmVudE1lc3NhZ2UsICdzdGF0ZScpO1xuICAgICAgfVxuICAgICAgdGhpcy5qdW1wVG9NZXNzYWdlU3ViamVjdC5uZXh0KHtcbiAgICAgICAgaWQ6IG1lc3NhZ2VJZCxcbiAgICAgICAgcGFyZW50SWQ6IHBhcmVudE1lc3NhZ2VJZCxcbiAgICAgIH0pO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICB0aGlzLm5vdGlmaWNhdGlvblNlcnZpY2UuYWRkVGVtcG9yYXJ5Tm90aWZpY2F0aW9uKFxuICAgICAgICAnc3RyZWFtQ2hhdC5NZXNzYWdlIG5vdCBmb3VuZCcsXG4gICAgICApO1xuICAgICAgdGhyb3cgZXJyb3I7XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIHRoaXMuaXNNZXNzYWdlTG9hZGluZ0luUHJvZ3Jlc3MgPSBmYWxzZTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQ2xlYXJzIHRoZSBjdXJyZW50bHkgc2VsZWN0ZWQgbWVzc2FnZSB0byBqdW1wXG4gICAqL1xuICBjbGVhck1lc3NhZ2VKdW1wKCkge1xuICAgIHRoaXMuanVtcFRvTWVzc2FnZVN1YmplY3QubmV4dCh7IGlkOiB1bmRlZmluZWQsIHBhcmVudElkOiB1bmRlZmluZWQgfSk7XG4gIH1cblxuICAvKipcbiAgICogUGlucyB0aGUgZ2l2ZW4gbWVzc2FnZSBpbiB0aGUgY2hhbm5lbFxuICAgKiBAcGFyYW0gbWVzc2FnZVxuICAgKi9cbiAgYXN5bmMgcGluTWVzc2FnZShtZXNzYWdlOiBTdHJlYW1NZXNzYWdlPERlZmF1bHRTdHJlYW1DaGF0R2VuZXJpY3M+KSB7XG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IHRoaXMuY2hhdENsaWVudFNlcnZpY2UuY2hhdENsaWVudD8ucGluTWVzc2FnZShtZXNzYWdlKTtcbiAgICAgIHRoaXMubm90aWZpY2F0aW9uU2VydmljZS5hZGRUZW1wb3JhcnlOb3RpZmljYXRpb24oXG4gICAgICAgICdzdHJlYW1DaGF0Lk1lc3NhZ2UgcGlubmVkJyxcbiAgICAgICAgJ3N1Y2Nlc3MnLFxuICAgICAgKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgdGhpcy5ub3RpZmljYXRpb25TZXJ2aWNlLmFkZFRlbXBvcmFyeU5vdGlmaWNhdGlvbihcbiAgICAgICAgJ3N0cmVhbUNoYXQuRXJyb3IgcGlubmluZyBtZXNzYWdlJyxcbiAgICAgICk7XG4gICAgICB0aHJvdyBlcnJvcjtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUmVtb3ZlcyB0aGUgZ2l2ZW4gbWVzc2FnZSBmcm9tIHBpbm5lZCBtZXNzYWdlc1xuICAgKiBAcGFyYW0gbWVzc2FnZVxuICAgKi9cbiAgYXN5bmMgdW5waW5NZXNzYWdlKG1lc3NhZ2U6IFN0cmVhbU1lc3NhZ2U8RGVmYXVsdFN0cmVhbUNoYXRHZW5lcmljcz4pIHtcbiAgICB0cnkge1xuICAgICAgYXdhaXQgdGhpcy5jaGF0Q2xpZW50U2VydmljZS5jaGF0Q2xpZW50Py51bnBpbk1lc3NhZ2UobWVzc2FnZSk7XG4gICAgICB0aGlzLm5vdGlmaWNhdGlvblNlcnZpY2UuYWRkVGVtcG9yYXJ5Tm90aWZpY2F0aW9uKFxuICAgICAgICAnc3RyZWFtQ2hhdC5NZXNzYWdlIHVucGlubmVkJyxcbiAgICAgICAgJ3N1Y2Nlc3MnLFxuICAgICAgKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgdGhpcy5ub3RpZmljYXRpb25TZXJ2aWNlLmFkZFRlbXBvcmFyeU5vdGlmaWNhdGlvbihcbiAgICAgICAgJ3N0cmVhbUNoYXQuRXJyb3IgcmVtb3ZpbmcgbWVzc2FnZSBwaW4nLFxuICAgICAgKTtcbiAgICAgIHRocm93IGVycm9yO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBSZWxvYWRzIGFsbCBjaGFubmVscyBhbmQgbWVzc2FnZXMuIFVzZWZ1bCBpZiBzdGF0ZSBpcyBlbXB0eSBkdWUgdG8gYW4gZXJyb3IuXG4gICAqXG4gICAqIFRoZSBTREsgd2lsbCBhdXRvbWF0aWNhbGx5IGNhbGwgdGhpcyBhZnRlciBgY29ubmVjdGlvbi5yZWNvdmVyZWRgIGV2ZW50LiBJbiBvdGhlciBjYXNlcyBpdCdzIHVwIHRvIGludGVncmF0b3JzIHRvIHJlY292ZXIgc3RhdGUuXG4gICAqXG4gICAqIFVzZSB0aGUgYHNob3VsZFJlY292ZXJTdGF0ZSRgIHRvIGtub3cgaWYgc3RhdGUgcmVjb3ZlciBpcyBuZWNlc3NhcnkuXG4gICAqIEByZXR1cm5zIHdoZW4gcmVjb3ZlcnkgaXMgY29tcGxldGVkXG4gICAqL1xuICBhc3luYyByZWNvdmVyU3RhdGUoKSB7XG4gICAgaWYgKHRoaXMuaXNTdGF0ZVJlY292ZXJ5SW5Qcm9ncmVzcyQuZ2V0VmFsdWUoKSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICB0aGlzLmlzU3RhdGVSZWNvdmVyeUluUHJvZ3Jlc3MkLm5leHQodHJ1ZSk7XG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IHRoaXMucXVlcnlDaGFubmVscygncmVjb3Zlci1zdGF0ZScpO1xuICAgICAgaWYgKHRoaXMuYWN0aXZlQ2hhbm5lbFN1YmplY3QuZ2V0VmFsdWUoKSkge1xuICAgICAgICAvLyBUaHJlYWQgbWVzc2FnZXMgYXJlIG5vdCByZWZldGNoZWQgc28gYWN0aXZlIHRocmVhZCBnZXRzIGRlc2VsZWN0ZWQgdG8gYXZvaWQgZGlzcGxheWluZyBzdGFsZSBtZXNzYWdlc1xuICAgICAgICB2b2lkIHRoaXMuc2V0QXNBY3RpdmVQYXJlbnRNZXNzYWdlKHVuZGVmaW5lZCk7XG4gICAgICAgIC8vIFVwZGF0ZSBhbmQgcmVzZWxlY3QgbWVzc2FnZSB0byBxdW90ZVxuICAgICAgICBjb25zdCBtZXNzYWdlVG9RdW90ZSA9IHRoaXMubWVzc2FnZVRvUXVvdGVTdWJqZWN0LmdldFZhbHVlKCk7XG4gICAgICAgIHRoaXMuc2V0Q2hhbm5lbFN0YXRlKHRoaXMuYWN0aXZlQ2hhbm5lbFN1YmplY3QuZ2V0VmFsdWUoKSEpO1xuICAgICAgICBsZXQgbWVzc2FnZXMhOiBTdHJlYW1NZXNzYWdlPFQ+W107XG4gICAgICAgIHRoaXMuYWN0aXZlQ2hhbm5lbE1lc3NhZ2VzJFxuICAgICAgICAgIC5waXBlKHRha2UoMSkpXG4gICAgICAgICAgLnN1YnNjcmliZSgobSkgPT4gKG1lc3NhZ2VzID0gbSkpO1xuICAgICAgICBjb25zdCB1cGRhdGVkTWVzc2FnZVRvUXVvdGUgPSBtZXNzYWdlcy5maW5kKFxuICAgICAgICAgIChtKSA9PiBtLmlkID09PSBtZXNzYWdlVG9RdW90ZT8uaWQsXG4gICAgICAgICk7XG4gICAgICAgIGlmICh1cGRhdGVkTWVzc2FnZVRvUXVvdGUpIHtcbiAgICAgICAgICB0aGlzLnNlbGVjdE1lc3NhZ2VUb1F1b3RlKHVwZGF0ZWRNZXNzYWdlVG9RdW90ZSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9IGZpbmFsbHkge1xuICAgICAgdGhpcy5pc1N0YXRlUmVjb3ZlcnlJblByb2dyZXNzJC5uZXh0KGZhbHNlKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGhhbmRsZU5vdGlmaWNhdGlvbihjbGllbnRFdmVudDogQ2xpZW50RXZlbnQ8VD4pIHtcbiAgICBzd2l0Y2ggKGNsaWVudEV2ZW50LmV2ZW50VHlwZSkge1xuICAgICAgY2FzZSAnY29ubmVjdGlvbi5yZWNvdmVyZWQnOiB7XG4gICAgICAgIHZvaWQgdGhpcy5yZWNvdmVyU3RhdGUoKS5jYXRjaCgoZXJyb3IpID0+XG4gICAgICAgICAgdGhpcy5jaGF0Q2xpZW50U2VydmljZS5jaGF0Q2xpZW50LmxvZ2dlcihcbiAgICAgICAgICAgICd3YXJuJyxcbiAgICAgICAgICAgIGBGYWlsZWQgdG8gcmVjb3ZlciBzdGF0ZSBhZnRlciBjb25uZWN0aW9uIHJlY292ZXJ5OiAke2Vycm9yfWAsXG4gICAgICAgICAgKSxcbiAgICAgICAgKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgICBjYXNlICd1c2VyLnVwZGF0ZWQnOiB7XG4gICAgICAgIGNvbnN0IGFjdGl2ZUNoYW5uZWwgPSB0aGlzLmFjdGl2ZUNoYW5uZWxTdWJqZWN0LmdldFZhbHVlKCk7XG4gICAgICAgIGlmIChhY3RpdmVDaGFubmVsKSB7XG4gICAgICAgICAgdGhpcy5hY3RpdmVDaGFubmVsU3ViamVjdC5uZXh0KFxuICAgICAgICAgICAgdGhpcy5jaGF0Q2xpZW50U2VydmljZS5jaGF0Q2xpZW50LmFjdGl2ZUNoYW5uZWxzW1xuICAgICAgICAgICAgICBhY3RpdmVDaGFubmVsLmNpZFxuICAgICAgICAgICAgXSB8fCBhY3RpdmVDaGFubmVsLFxuICAgICAgICAgICk7XG4gICAgICAgICAgdGhpcy5hY3RpdmVDaGFubmVsTWVzc2FnZXNTdWJqZWN0Lm5leHQoXG4gICAgICAgICAgICBhY3RpdmVDaGFubmVsLnN0YXRlLm1lc3NhZ2VzLm1hcCgobSkgPT4ge1xuICAgICAgICAgICAgICBtLnJlYWRCeSA9IGdldFJlYWRCeShtLCBhY3RpdmVDaGFubmVsKTtcbiAgICAgICAgICAgICAgcmV0dXJuIHsgLi4ubSB9O1xuICAgICAgICAgICAgfSksXG4gICAgICAgICAgKTtcbiAgICAgICAgICBjb25zdCBhY3RpdmVQYXJlbnRNZXNzYWdlID1cbiAgICAgICAgICAgIHRoaXMuYWN0aXZlUGFyZW50TWVzc2FnZUlkU3ViamVjdC5nZXRWYWx1ZSgpO1xuICAgICAgICAgIGlmIChhY3RpdmVQYXJlbnRNZXNzYWdlKSB7XG4gICAgICAgICAgICBjb25zdCBtZXNzYWdlcyA9IGFjdGl2ZUNoYW5uZWwuc3RhdGUudGhyZWFkc1thY3RpdmVQYXJlbnRNZXNzYWdlXTtcbiAgICAgICAgICAgIHRoaXMuYWN0aXZlVGhyZWFkTWVzc2FnZXNTdWJqZWN0Lm5leHQoWy4uLm1lc3NhZ2VzXSk7XG4gICAgICAgICAgfVxuICAgICAgICAgIHRoaXMuYWN0aXZlQ2hhbm5lbFBpbm5lZE1lc3NhZ2VzU3ViamVjdC5uZXh0KFtcbiAgICAgICAgICAgIC4uLmFjdGl2ZUNoYW5uZWwuc3RhdGUucGlubmVkTWVzc2FnZXMsXG4gICAgICAgICAgXSk7XG4gICAgICAgIH1cbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSB3YXRjaEZvckFjdGl2ZUNoYW5uZWxFdmVudHMoY2hhbm5lbDogQ2hhbm5lbDxUPikge1xuICAgIHRoaXMuYWN0aXZlQ2hhbm5lbFN1YnNjcmlwdGlvbnMucHVzaChcbiAgICAgIGNoYW5uZWwub24oJ21lc3NhZ2UubmV3JywgKGV2ZW50KSA9PiB7XG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW51c2VkLWV4cHJlc3Npb25zXG4gICAgICAgIGV2ZW50Lm1lc3NhZ2UgJiYgZXZlbnQubWVzc2FnZS5wYXJlbnRfaWRcbiAgICAgICAgICA/IGV2ZW50Lm1lc3NhZ2UucGFyZW50X2lkID09PVxuICAgICAgICAgICAgdGhpcy5hY3RpdmVQYXJlbnRNZXNzYWdlSWRTdWJqZWN0LmdldFZhbHVlKClcbiAgICAgICAgICAgID8gdGhpcy5hY3RpdmVUaHJlYWRNZXNzYWdlc1N1YmplY3QubmV4dChbXG4gICAgICAgICAgICAgICAgLi4uY2hhbm5lbC5zdGF0ZS50aHJlYWRzW2V2ZW50Lm1lc3NhZ2UucGFyZW50X2lkXSxcbiAgICAgICAgICAgICAgXSlcbiAgICAgICAgICAgIDogbnVsbFxuICAgICAgICAgIDogdGhpcy5hY3RpdmVDaGFubmVsTWVzc2FnZXNTdWJqZWN0Lm5leHQoWy4uLmNoYW5uZWwuc3RhdGUubWVzc2FnZXNdKTtcbiAgICAgICAgdGhpcy5hY3RpdmVDaGFubmVsJC5waXBlKGZpcnN0KCkpLnN1YnNjcmliZSgoYykgPT4ge1xuICAgICAgICAgIGlmIChjKSB7XG4gICAgICAgICAgICB0aGlzLm1hcmtSZWFkKGMpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMudXBkYXRlTGF0ZXN0TWVzc2FnZXMoZXZlbnQpO1xuICAgICAgfSksXG4gICAgKTtcbiAgICB0aGlzLmFjdGl2ZUNoYW5uZWxTdWJzY3JpcHRpb25zLnB1c2goXG4gICAgICBjaGFubmVsLm9uKCdtZXNzYWdlLnVwZGF0ZWQnLCAoZXZlbnQpID0+IHRoaXMubWVzc2FnZVVwZGF0ZWQoZXZlbnQpKSxcbiAgICApO1xuICAgIHRoaXMuYWN0aXZlQ2hhbm5lbFN1YnNjcmlwdGlvbnMucHVzaChcbiAgICAgIGNoYW5uZWwub24oJ21lc3NhZ2UuZGVsZXRlZCcsIChldmVudCkgPT4gdGhpcy5tZXNzYWdlVXBkYXRlZChldmVudCkpLFxuICAgICk7XG4gICAgdGhpcy5hY3RpdmVDaGFubmVsU3Vic2NyaXB0aW9ucy5wdXNoKFxuICAgICAgY2hhbm5lbC5vbigncmVhY3Rpb24ubmV3JywgKGUpID0+IHRoaXMubWVzc2FnZVJlYWN0aW9uRXZlbnRSZWNlaXZlZChlKSksXG4gICAgKTtcbiAgICB0aGlzLmFjdGl2ZUNoYW5uZWxTdWJzY3JpcHRpb25zLnB1c2goXG4gICAgICBjaGFubmVsLm9uKCdyZWFjdGlvbi5kZWxldGVkJywgKGUpID0+XG4gICAgICAgIHRoaXMubWVzc2FnZVJlYWN0aW9uRXZlbnRSZWNlaXZlZChlKSxcbiAgICAgICksXG4gICAgKTtcbiAgICB0aGlzLmFjdGl2ZUNoYW5uZWxTdWJzY3JpcHRpb25zLnB1c2goXG4gICAgICBjaGFubmVsLm9uKCdyZWFjdGlvbi51cGRhdGVkJywgKGUpID0+XG4gICAgICAgIHRoaXMubWVzc2FnZVJlYWN0aW9uRXZlbnRSZWNlaXZlZChlKSxcbiAgICAgICksXG4gICAgKTtcbiAgICB0aGlzLmFjdGl2ZUNoYW5uZWxTdWJzY3JpcHRpb25zLnB1c2goXG4gICAgICBjaGFubmVsLm9uKCdtZXNzYWdlLnJlYWQnLCAoZSkgPT4ge1xuICAgICAgICBsZXQgbGF0ZXN0TWVzc2FnZSE6IFN0cmVhbU1lc3NhZ2U7XG4gICAgICAgIGxldCBtZXNzYWdlcyE6IFN0cmVhbU1lc3NhZ2VbXTtcbiAgICAgICAgdGhpcy5hY3RpdmVDaGFubmVsTWVzc2FnZXMkLnBpcGUoZmlyc3QoKSkuc3Vic2NyaWJlKChtKSA9PiB7XG4gICAgICAgICAgbWVzc2FnZXMgPSBtO1xuICAgICAgICAgIGxhdGVzdE1lc3NhZ2UgPSBtZXNzYWdlc1ttZXNzYWdlcy5sZW5ndGggLSAxXTtcbiAgICAgICAgfSk7XG4gICAgICAgIGlmICghbGF0ZXN0TWVzc2FnZSB8fCAhZS51c2VyKSB7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGlmIChsYXRlc3RNZXNzYWdlLnJlYWRCeSkge1xuICAgICAgICAgIGxhdGVzdE1lc3NhZ2UucmVhZEJ5LnNwbGljZSgwLCBsYXRlc3RNZXNzYWdlLnJlYWRCeS5sZW5ndGgpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGxhdGVzdE1lc3NhZ2UucmVhZEJ5ID0gW107XG4gICAgICAgIH1cbiAgICAgICAgbGF0ZXN0TWVzc2FnZS5yZWFkQnkucHVzaCguLi5nZXRSZWFkQnkobGF0ZXN0TWVzc2FnZSwgY2hhbm5lbCkpO1xuICAgICAgICBtZXNzYWdlc1ttZXNzYWdlcy5sZW5ndGggLSAxXSA9IHsgLi4ubGF0ZXN0TWVzc2FnZSB9O1xuXG4gICAgICAgIHRoaXMuYWN0aXZlQ2hhbm5lbE1lc3NhZ2VzU3ViamVjdC5uZXh0KFsuLi5tZXNzYWdlc10pO1xuICAgICAgfSksXG4gICAgKTtcbiAgICB0aGlzLmFjdGl2ZUNoYW5uZWxTdWJzY3JpcHRpb25zLnB1c2goXG4gICAgICB0aGlzLmNoYXRDbGllbnRTZXJ2aWNlLmV2ZW50cyRcbiAgICAgICAgLnBpcGUoXG4gICAgICAgICAgZmlsdGVyKFxuICAgICAgICAgICAgKGUpID0+XG4gICAgICAgICAgICAgIGUuZXZlbnRUeXBlID09PSAnbm90aWZpY2F0aW9uLm1hcmtfdW5yZWFkJyAmJlxuICAgICAgICAgICAgICBlLmV2ZW50LmNoYW5uZWxfaWQgPT09IGNoYW5uZWwuaWQsXG4gICAgICAgICAgKSxcbiAgICAgICAgICBtYXAoKGUpID0+IGUuZXZlbnQpLFxuICAgICAgICApXG4gICAgICAgIC5zdWJzY3JpYmUoKGUpID0+IHtcbiAgICAgICAgICB0aGlzLmFjdGl2ZUNoYW5uZWxMYXN0UmVhZE1lc3NhZ2VJZCA9IGUubGFzdF9yZWFkX21lc3NhZ2VfaWQ7XG4gICAgICAgICAgdGhpcy5hY3RpdmVDaGFubmVsVW5yZWFkQ291bnQgPSBlLnVucmVhZF9tZXNzYWdlcztcbiAgICAgICAgICB0aGlzLmFjdGl2ZUNoYW5uZWxTdWJqZWN0Lm5leHQodGhpcy5hY3RpdmVDaGFubmVsKTtcbiAgICAgICAgfSksXG4gICAgKTtcbiAgICB0aGlzLmFjdGl2ZUNoYW5uZWxTdWJzY3JpcHRpb25zLnB1c2goXG4gICAgICBjaGFubmVsLm9uKCd0eXBpbmcuc3RhcnQnLCAoZSkgPT4gdGhpcy5oYW5kbGVUeXBpbmdTdGFydEV2ZW50KGUpKSxcbiAgICApO1xuICAgIHRoaXMuYWN0aXZlQ2hhbm5lbFN1YnNjcmlwdGlvbnMucHVzaChcbiAgICAgIC8vIGNsaWVudC5fc3RhcnRDbGVhbmluZyBjYW4gZW1pdCB0eXBpbmcuc3RvcCBldmVudHNcbiAgICAgIC8vIHNpbmNlIGNsaWVudC5fc3RhcnRDbGVhbmluZyBydW5zIG91dHNpZGUgQW5ndWxhciwgd2UgbmVlZCB0byByZWVudGVyIEFuZ3VsYXIgaGVyZVxuICAgICAgY2hhbm5lbC5vbigndHlwaW5nLnN0b3AnLCAoZSkgPT5cbiAgICAgICAgdGhpcy5uZ1pvbmUucnVuKCgpID0+IHRoaXMuaGFuZGxlVHlwaW5nU3RvcEV2ZW50KGUpKSxcbiAgICAgICksXG4gICAgKTtcbiAgICB0aGlzLmFjdGl2ZUNoYW5uZWxTdWJzY3JpcHRpb25zLnB1c2goXG4gICAgICBjaGFubmVsLm9uKCdjYXBhYmlsaXRpZXMuY2hhbmdlZCcsIChfKSA9PiB7XG4gICAgICAgIHRoaXMuYWN0aXZlQ2hhbm5lbFN1YmplY3QubmV4dCh0aGlzLmFjdGl2ZUNoYW5uZWxTdWJqZWN0LmdldFZhbHVlKCkpO1xuICAgICAgfSksXG4gICAgKTtcbiAgICB0aGlzLmFjdGl2ZUNoYW5uZWxTdWJzY3JpcHRpb25zLnB1c2goXG4gICAgICBjaGFubmVsLm9uKCdjaGFubmVsLnVwZGF0ZWQnLCAoXykgPT4ge1xuICAgICAgICB0aGlzLmFjdGl2ZUNoYW5uZWxTdWJqZWN0Lm5leHQodGhpcy5hY3RpdmVDaGFubmVsU3ViamVjdC5nZXRWYWx1ZSgpKTtcbiAgICAgIH0pLFxuICAgICk7XG4gICAgdGhpcy5hY3RpdmVDaGFubmVsU3Vic2NyaXB0aW9ucy5wdXNoKFxuICAgICAgY2hhbm5lbC5vbignY2hhbm5lbC50cnVuY2F0ZWQnLCAoXykgPT4ge1xuICAgICAgICB0aGlzLmFjdGl2ZUNoYW5uZWxTdWJqZWN0Lm5leHQodGhpcy5hY3RpdmVDaGFubmVsU3ViamVjdC5nZXRWYWx1ZSgpKTtcbiAgICAgICAgdGhpcy5hY3RpdmVDaGFubmVsTWVzc2FnZXNTdWJqZWN0Lm5leHQoW10pO1xuICAgICAgICB2b2lkIHRoaXMuc2V0QXNBY3RpdmVQYXJlbnRNZXNzYWdlKHVuZGVmaW5lZCk7XG4gICAgICB9KSxcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIENhbGwgdGhpcyBtZXRob2QgaWYgdXNlciBzdGFydGVkIHR5cGluZyBpbiB0aGUgYWN0aXZlIGNoYW5uZWxcbiAgICogQHBhcmFtIHBhcmVudElkIFRoZSBpZCBvZiB0aGUgcGFyZW50IG1lc3NhZ2UsIGlmIHVzZXIgaXMgdHlwaW5nIGluIGEgdGhyZWFkXG4gICAqL1xuICBhc3luYyB0eXBpbmdTdGFydGVkKHBhcmVudElkPzogc3RyaW5nKSB7XG4gICAgY29uc3QgYWN0aXZlQ2hhbm5lbCA9IHRoaXMuYWN0aXZlQ2hhbm5lbFN1YmplY3QuZ2V0VmFsdWUoKTtcbiAgICBhd2FpdCBhY3RpdmVDaGFubmVsPy5rZXlzdHJva2UocGFyZW50SWQpO1xuICB9XG5cbiAgLyoqXG4gICAqIENhbGwgdGhpcyBtZXRob2QgaWYgdXNlciBzdG9wcGVkIHR5cGluZyBpbiB0aGUgYWN0aXZlIGNoYW5uZWxcbiAgICogQHBhcmFtIHBhcmVudElkIFRoZSBpZCBvZiB0aGUgcGFyZW50IG1lc3NhZ2UsIGlmIHVzZXIgd2VyZSB0eXBpbmcgaW4gYSB0aHJlYWRcbiAgICovXG4gIGFzeW5jIHR5cGluZ1N0b3BwZWQocGFyZW50SWQ/OiBzdHJpbmcpIHtcbiAgICBjb25zdCBhY3RpdmVDaGFubmVsID0gdGhpcy5hY3RpdmVDaGFubmVsU3ViamVjdC5nZXRWYWx1ZSgpO1xuICAgIGF3YWl0IGFjdGl2ZUNoYW5uZWw/LnN0b3BUeXBpbmcocGFyZW50SWQpO1xuICB9XG5cbiAgLyoqXG4gICAqIFRoZSBjdXJyZW50IGxpc3Qgb2YgY2hhbm5lbHNcbiAgICovXG4gIGdldCBjaGFubmVscygpIHtcbiAgICByZXR1cm4gdGhpcy5jaGFubmVsc1N1YmplY3QuZ2V0VmFsdWUoKSB8fCBbXTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUaGUgY3VycmVudCBhY3RpdmUgY2hhbm5lbFxuICAgKi9cbiAgZ2V0IGFjdGl2ZUNoYW5uZWwoKSB7XG4gICAgcmV0dXJuIHRoaXMuYWN0aXZlQ2hhbm5lbFN1YmplY3QuZ2V0VmFsdWUoKSB8fCB1bmRlZmluZWQ7XG4gIH1cblxuICAvKipcbiAgICogVGhlIGN1cnJlbnQgYWN0aXZlIGNoYW5uZWwgbWVzc2FnZXNcbiAgICovXG4gIGdldCBhY3RpdmVDaGFubmVsTWVzc2FnZXMoKSB7XG4gICAgcmV0dXJuIHRoaXMuYWN0aXZlQ2hhbm5lbE1lc3NhZ2VzU3ViamVjdC5nZXRWYWx1ZSgpIHx8IFtdO1xuICB9XG5cbiAgLyoqXG4gICAqIFRoZSBjdXJyZW50IHRocmVhZCByZXBsaWVzXG4gICAqL1xuICBnZXQgYWN0aXZlQ2hhbm5lbFRocmVhZFJlcGxpZXMoKSB7XG4gICAgcmV0dXJuIHRoaXMuYWN0aXZlVGhyZWFkTWVzc2FnZXNTdWJqZWN0LmdldFZhbHVlKCkgfHwgW107XG4gIH1cblxuICAvKipcbiAgICogR2V0IHRoZSBsYXN0IDEyMDAgcmVhY3Rpb25zIG9mIGEgbWVzc2FnZSBpbiB0aGUgY3VycmVudCBhY3RpdmUgY2hhbm5lbC4gSWYgeW91IG5lZWQgdG8gZmV0Y2ggbW9yZSByZWFjdGlvbnMgcGxlYXNlIHVzZSB0aGUgW2ZvbGxvd2luZyBlbmRwb2ludF0oL2NoYXQvZG9jcy9qYXZhc2NyaXB0L3NlbmRfcmVhY3Rpb24vI3BhZ2luYXRpbmctcmVhY3Rpb25zKS5cbiAgICogQGRlcHJlY2F0ZWQgdXNlIFtgbWVzc2FnZVJlYWN0aW9uc1NlcnZpY2UucXVlcnlSZWFjdGlvbnMoKWBdKC9jaGF0L2RvY3Mvc2RrL2FuZ3VsYXIvc2VydmljZXMvTWVzc2FnZVJlYWN0aW9uc1NlcnZpY2UvI3F1ZXJ5cmVhY3Rpb25zKSBpbnN0ZWFkXG4gICAqIEBwYXJhbSBtZXNzYWdlSWRcbiAgICogQHJldHVybnMgYWxsIHJlYWN0aW9ucyBvZiBhIG1lc3NhZ2VcbiAgICovXG4gIGFzeW5jIGdldE1lc3NhZ2VSZWFjdGlvbnMobWVzc2FnZUlkOiBzdHJpbmcpIHtcbiAgICBjb25zdCByZWFjdGlvbnM6IFJlYWN0aW9uUmVzcG9uc2U8VD5bXSA9IFtdO1xuICAgIGNvbnN0IGxpbWl0ID0gMzAwO1xuICAgIGxldCBvZmZzZXQgPSAwO1xuICAgIGNvbnN0IHJlYWN0aW9uc0xpbWl0ID0gQ2hhbm5lbFNlcnZpY2UuTUFYX01FU1NBR0VfUkVBQ1RJT05TX1RPX0ZFVENIO1xuICAgIGxldCBsYXN0UGFnZVNpemUgPSBsaW1pdDtcblxuICAgIHdoaWxlIChsYXN0UGFnZVNpemUgPT09IGxpbWl0ICYmIHJlYWN0aW9ucy5sZW5ndGggPCByZWFjdGlvbnNMaW1pdCkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCB0aGlzLmFjdGl2ZUNoYW5uZWw/LmdldFJlYWN0aW9ucyhtZXNzYWdlSWQsIHtcbiAgICAgICAgICBvZmZzZXQsXG4gICAgICAgICAgbGltaXQsXG4gICAgICAgIH0pO1xuICAgICAgICBsYXN0UGFnZVNpemUgPSByZXNwb25zZT8ucmVhY3Rpb25zPy5sZW5ndGggfHwgMDtcbiAgICAgICAgaWYgKGxhc3RQYWdlU2l6ZSA+IDApIHtcbiAgICAgICAgICByZWFjdGlvbnMucHVzaCguLi5yZXNwb25zZSEucmVhY3Rpb25zKTtcbiAgICAgICAgfVxuICAgICAgICBvZmZzZXQgKz0gbGFzdFBhZ2VTaXplO1xuICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICB0aGlzLm5vdGlmaWNhdGlvblNlcnZpY2UuYWRkVGVtcG9yYXJ5Tm90aWZpY2F0aW9uKFxuICAgICAgICAgICdzdHJlYW1DaGF0LkVycm9yIGxvYWRpbmcgcmVhY3Rpb25zJyxcbiAgICAgICAgKTtcbiAgICAgICAgdGhyb3cgZTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHJlYWN0aW9ucztcbiAgfVxuXG4gIC8qKlxuICAgKiBNYXJrcyB0aGUgY2hhbm5lbCBmcm9tIHRoZSBnaXZlbiBtZXNzYWdlIGFzIHVucmVhZFxuICAgKiBAcGFyYW0gbWVzc2FnZUlkXG4gICAqIEByZXR1cm5zIHRoZSByZXN1bHQgb2YgdGhlIHJlcXVlc3RcbiAgICovXG4gIGFzeW5jIG1hcmtNZXNzYWdlVW5yZWFkKG1lc3NhZ2VJZDogc3RyaW5nKSB7XG4gICAgaWYgKCF0aGlzLmFjdGl2ZUNoYW5uZWwpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0cnkge1xuICAgICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCB0aGlzLmFjdGl2ZUNoYW5uZWwubWFya1VucmVhZCh7XG4gICAgICAgIG1lc3NhZ2VfaWQ6IG1lc3NhZ2VJZCxcbiAgICAgIH0pO1xuICAgICAgdGhpcy5hcmVSZWFkRXZlbnRzUGF1c2VkID0gdHJ1ZTtcbiAgICAgIHJldHVybiByZXNwb25zZTtcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tZXhwbGljaXQtYW55XG4gICAgfSBjYXRjaCAoZTogYW55KSB7XG4gICAgICBjb25zdCBlcnJvcjoge1xuICAgICAgICByZXNwb25zZT86IHtcbiAgICAgICAgICBkYXRhPzogeyBjb2RlPzogbnVtYmVyOyBtZXNzYWdlPzogc3RyaW5nOyBTdGF0dXNDb2RlPzogbnVtYmVyIH07XG4gICAgICAgIH07XG4gICAgICB9ID0gSlNPTi5wYXJzZShKU09OLnN0cmluZ2lmeShlKSkgYXMge1xuICAgICAgICByZXNwb25zZT86IHtcbiAgICAgICAgICBkYXRhPzogeyBjb2RlPzogbnVtYmVyOyBtZXNzYWdlPzogc3RyaW5nOyBTdGF0dXNDb2RlPzogbnVtYmVyIH07XG4gICAgICAgIH07XG4gICAgICB9O1xuICAgICAgY29uc3QgZGF0YSA9IGVycm9yPy5yZXNwb25zZT8uZGF0YTtcbiAgICAgIGlmIChcbiAgICAgICAgZGF0YSAmJlxuICAgICAgICBkYXRhLmNvZGUgPT09IDQgJiZcbiAgICAgICAgZGF0YS5TdGF0dXNDb2RlID09PSA0MDAgJiZcbiAgICAgICAgZGF0YS5tZXNzYWdlPy5pbmNsdWRlcygnaXQgaXMgb2xkZXIgdGhhbiBsYXN0JylcbiAgICAgICkge1xuICAgICAgICBjb25zdCBjb3VudCA9IC9cXGQrIGNoYW5uZWwgbWVzc2FnZXMvXG4gICAgICAgICAgLmV4ZWMoZGF0YS5tZXNzYWdlKT8uWzBdXG4gICAgICAgICAgLm1hdGNoKC9cXGQrLyk/LlswXTtcbiAgICAgICAgaWYgKGNvdW50KSB7XG4gICAgICAgICAgdGhpcy5ub3RpZmljYXRpb25TZXJ2aWNlLmFkZFRlbXBvcmFyeU5vdGlmaWNhdGlvbihcbiAgICAgICAgICAgICdzdHJlYW1DaGF0LkVycm9yLCBvbmx5IHRoZSBmaXJzdCB7e2NvdW50fX0gbWVzc2FnZSBjYW4gYmUgbWFya2VkIGFzIHVucmVhZCcsXG4gICAgICAgICAgICB1bmRlZmluZWQsXG4gICAgICAgICAgICB1bmRlZmluZWQsXG4gICAgICAgICAgICB7IGNvdW50IH0sXG4gICAgICAgICAgKTtcbiAgICAgICAgICB0aHJvdyBlO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICB0aGlzLm5vdGlmaWNhdGlvblNlcnZpY2UuYWRkVGVtcG9yYXJ5Tm90aWZpY2F0aW9uKFxuICAgICAgICAnc3RyZWFtQ2hhdC5FcnJvciBtYXJraW5nIG1lc3NhZ2UgYXMgdW5yZWFkJyxcbiAgICAgICk7XG4gICAgICB0aHJvdyBlO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgbWVzc2FnZVVwZGF0ZWQoZXZlbnQ6IEV2ZW50PFQ+KSB7XG4gICAgY29uc3QgaXNUaHJlYWRSZXBseSA9IGV2ZW50Lm1lc3NhZ2UgJiYgZXZlbnQubWVzc2FnZS5wYXJlbnRfaWQ7XG4gICAgY29uc3QgY2hhbm5lbCA9IHRoaXMuYWN0aXZlQ2hhbm5lbFN1YmplY3QuZ2V0VmFsdWUoKTtcbiAgICBpZiAoIWNoYW5uZWwpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgLy8gR2V0IG1lc3NhZ2VzIGZyb20gc3RhdGUgYXMgbWVzc2FnZSBvcmRlciBjb3VsZCBjaGFuZ2UsIGFuZCBtZXNzYWdlIGNvdWxkJ3ZlIGJlZW4gZGVsZXRlZFxuICAgIGNvbnN0IG1lc3NhZ2VzOiBGb3JtYXRNZXNzYWdlUmVzcG9uc2U8VD5bXSA9IGlzVGhyZWFkUmVwbHlcbiAgICAgID8gY2hhbm5lbC5zdGF0ZS50aHJlYWRzW2V2ZW50Py5tZXNzYWdlPy5wYXJlbnRfaWQgfHwgJyddXG4gICAgICA6IGNoYW5uZWwuc3RhdGUubWVzc2FnZXM7XG4gICAgaWYgKCFtZXNzYWdlcykge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjb25zdCBtZXNzYWdlSW5kZXggPSBtZXNzYWdlcy5maW5kSW5kZXgoKG0pID0+IG0uaWQgPT09IGV2ZW50Py5tZXNzYWdlPy5pZCk7XG4gICAgaWYgKG1lc3NhZ2VJbmRleCAhPT0gLTEgfHwgZXZlbnQudHlwZSA9PT0gJ21lc3NhZ2UuZGVsZXRlZCcpIHtcbiAgICAgIGlzVGhyZWFkUmVwbHlcbiAgICAgICAgPyB0aGlzLmFjdGl2ZVRocmVhZE1lc3NhZ2VzU3ViamVjdC5uZXh0KFsuLi5tZXNzYWdlc10pXG4gICAgICAgIDogdGhpcy5hY3RpdmVDaGFubmVsTWVzc2FnZXNTdWJqZWN0Lm5leHQoWy4uLm1lc3NhZ2VzXSk7XG4gICAgICB0aGlzLmFjdGl2ZUNoYW5uZWxQaW5uZWRNZXNzYWdlc1N1YmplY3QubmV4dChbXG4gICAgICAgIC4uLmNoYW5uZWwuc3RhdGUucGlubmVkTWVzc2FnZXMsXG4gICAgICBdKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIG1lc3NhZ2VSZWFjdGlvbkV2ZW50UmVjZWl2ZWQoZTogRXZlbnQ8VD4pIHtcbiAgICBjb25zdCBpc1RocmVhZE1lc3NhZ2UgPSBlLm1lc3NhZ2UgJiYgZS5tZXNzYWdlLnBhcmVudF9pZDtcbiAgICBsZXQgbWVzc2FnZXMhOiBTdHJlYW1NZXNzYWdlW107XG4gICAgKGlzVGhyZWFkTWVzc2FnZSA/IHRoaXMuYWN0aXZlVGhyZWFkTWVzc2FnZXMkIDogdGhpcy5hY3RpdmVDaGFubmVsTWVzc2FnZXMkKVxuICAgICAgLnBpcGUoZmlyc3QoKSlcbiAgICAgIC5zdWJzY3JpYmUoKG0pID0+IChtZXNzYWdlcyA9IG0pKTtcbiAgICBjb25zdCBtZXNzYWdlSW5kZXggPSBtZXNzYWdlcy5maW5kSW5kZXgoKG0pID0+IG0uaWQgPT09IGU/Lm1lc3NhZ2U/LmlkKTtcbiAgICBpZiAobWVzc2FnZUluZGV4ID09PSAtMSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjb25zdCBtZXNzYWdlID0gbWVzc2FnZXNbbWVzc2FnZUluZGV4XTtcbiAgICBtZXNzYWdlLnJlYWN0aW9uX2NvdW50cyA9IHsgLi4uZS5tZXNzYWdlPy5yZWFjdGlvbl9jb3VudHMgfTtcbiAgICBtZXNzYWdlLnJlYWN0aW9uX3Njb3JlcyA9IHsgLi4uZS5tZXNzYWdlPy5yZWFjdGlvbl9zY29yZXMgfTtcbiAgICBtZXNzYWdlLmxhdGVzdF9yZWFjdGlvbnMgPSBbLi4uKGUubWVzc2FnZT8ubGF0ZXN0X3JlYWN0aW9ucyB8fCBbXSldO1xuICAgIG1lc3NhZ2Uub3duX3JlYWN0aW9ucyA9IFsuLi4oZS5tZXNzYWdlPy5vd25fcmVhY3Rpb25zIHx8IFtdKV07XG4gICAgbWVzc2FnZS5yZWFjdGlvbl9ncm91cHMgPSB7IC4uLmUubWVzc2FnZT8ucmVhY3Rpb25fZ3JvdXBzIH07XG5cbiAgICBtZXNzYWdlc1ttZXNzYWdlSW5kZXhdID0geyAuLi5tZXNzYWdlIH07XG4gICAgaXNUaHJlYWRNZXNzYWdlXG4gICAgICA/IHRoaXMuYWN0aXZlVGhyZWFkTWVzc2FnZXNTdWJqZWN0Lm5leHQoWy4uLm1lc3NhZ2VzXSlcbiAgICAgIDogdGhpcy5hY3RpdmVDaGFubmVsTWVzc2FnZXNTdWJqZWN0Lm5leHQoWy4uLm1lc3NhZ2VzXSk7XG4gIH1cblxuICBwcml2YXRlIGZvcm1hdE1lc3NhZ2UobWVzc2FnZTogTWVzc2FnZVJlc3BvbnNlPFQ+KSB7XG4gICAgY29uc3QgbSA9IG1lc3NhZ2UgYXMgdW5rbm93biBhcyBGb3JtYXRNZXNzYWdlUmVzcG9uc2U8VD47XG4gICAgbS5waW5uZWRfYXQgPSBtZXNzYWdlLnBpbm5lZF9hdCA/IG5ldyBEYXRlKG1lc3NhZ2UucGlubmVkX2F0KSA6IG51bGw7XG4gICAgbS5jcmVhdGVkX2F0ID0gbWVzc2FnZS5jcmVhdGVkX2F0XG4gICAgICA/IG5ldyBEYXRlKG1lc3NhZ2UuY3JlYXRlZF9hdClcbiAgICAgIDogbmV3IERhdGUoKTtcbiAgICBtLnVwZGF0ZWRfYXQgPSBtZXNzYWdlLnVwZGF0ZWRfYXRcbiAgICAgID8gbmV3IERhdGUobWVzc2FnZS51cGRhdGVkX2F0KVxuICAgICAgOiBuZXcgRGF0ZSgpO1xuICAgIG1lc3NhZ2Uuc3RhdHVzID0gbWVzc2FnZS5zdGF0dXMgfHwgJ3JlY2VpdmVkJztcblxuICAgIHJldHVybiBtO1xuICB9XG5cbiAgcHJpdmF0ZSBpc1N0cmVhbU1lc3NhZ2UoXG4gICAgbWVzc2FnZTogU3RyZWFtTWVzc2FnZSB8IEZvcm1hdE1lc3NhZ2VSZXNwb25zZSB8IE1lc3NhZ2VSZXNwb25zZSxcbiAgKTogbWVzc2FnZSBpcyBTdHJlYW1NZXNzYWdlIHtcbiAgICByZXR1cm4gISFtZXNzYWdlLnJlYWRCeTtcbiAgfVxuXG4gIHByaXZhdGUgaXNGb3JtYXRNZXNzYWdlUmVzcG9uc2UoXG4gICAgbWVzc2FnZTogU3RyZWFtTWVzc2FnZSB8IEZvcm1hdE1lc3NhZ2VSZXNwb25zZSB8IE1lc3NhZ2VSZXNwb25zZSxcbiAgKTogbWVzc2FnZSBpcyBGb3JtYXRNZXNzYWdlUmVzcG9uc2Uge1xuICAgIHJldHVybiBtZXNzYWdlLmNyZWF0ZWRfYXQgaW5zdGFuY2VvZiBEYXRlO1xuICB9XG5cbiAgcHJpdmF0ZSBzdG9wV2F0Y2hGb3JBY3RpdmVDaGFubmVsRXZlbnRzKGNoYW5uZWw6IENoYW5uZWw8VD4gfCB1bmRlZmluZWQpIHtcbiAgICBpZiAoIWNoYW5uZWwpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGhpcy5hY3RpdmVDaGFubmVsU3Vic2NyaXB0aW9ucy5mb3JFYWNoKChzKSA9PiBzLnVuc3Vic2NyaWJlKCkpO1xuICAgIHRoaXMuYWN0aXZlQ2hhbm5lbFN1YnNjcmlwdGlvbnMgPSBbXTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgcXVlcnlDaGFubmVscyhxdWVyeVR5cGU6IENoYW5uZWxRdWVyeVR5cGUpIHtcbiAgICBpZiAoIXRoaXMuY2hhbm5lbE1hbmFnZXIpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgJ1F1ZXJ5IGNoYW5uZWxzIGNhbGxlZCBiZWZvcmUgaW5pdGlhbGl6aW5nIENoYW5uZWxTZXJ2aWNlJyxcbiAgICAgICk7XG4gICAgfVxuICAgIHRyeSB7XG4gICAgICB0aGlzLmNoYW5uZWxRdWVyeVN0YXRlU3ViamVjdC5uZXh0KHsgc3RhdGU6ICdpbi1wcm9ncmVzcycgfSk7XG5cbiAgICAgIGlmICh0aGlzLmN1c3RvbUNoYW5uZWxRdWVyeSkge1xuICAgICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCB0aGlzLmN1c3RvbUNoYW5uZWxRdWVyeShxdWVyeVR5cGUpO1xuICAgICAgICBjb25zdCBjdXJyZW50Q2hhbm5lbHMgPSB0aGlzLmNoYW5uZWxzO1xuICAgICAgICBjb25zdCBmaWx0ZXJlZENoYW5uZWxzID0gcmVzdWx0LmNoYW5uZWxzLmZpbHRlcihcbiAgICAgICAgICAoY2hhbm5lbCwgaW5kZXgpID0+XG4gICAgICAgICAgICAhY3VycmVudENoYW5uZWxzLnNsaWNlKDAsIGluZGV4KS5maW5kKChjKSA9PiBjLmNpZCA9PT0gY2hhbm5lbC5jaWQpLFxuICAgICAgICApO1xuICAgICAgICB0aGlzLmNoYW5uZWxNYW5hZ2VyLnNldENoYW5uZWxzKGZpbHRlcmVkQ2hhbm5lbHMpO1xuICAgICAgICB0aGlzLmhhc01vcmVDaGFubmVsc1N1YmplY3QubmV4dChyZXN1bHQuaGFzTW9yZVBhZ2UpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgaWYgKHF1ZXJ5VHlwZSA9PT0gJ2ZpcnN0LXBhZ2UnIHx8IHF1ZXJ5VHlwZSA9PT0gJ3JlY292ZXItc3RhdGUnKSB7XG4gICAgICAgICAgaWYgKCF0aGlzLmNoYW5uZWxRdWVyeUNvbmZpZykge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdDaGFubmVsIHF1ZXJ5IGNvbmZpZyBub3QgaW5pdGlhbGl6ZWQnKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgYXdhaXQgdGhpcy5jaGFubmVsTWFuYWdlci5xdWVyeUNoYW5uZWxzKFxuICAgICAgICAgICAgeyAuLi50aGlzLmNoYW5uZWxRdWVyeUNvbmZpZy5maWx0ZXJzIH0sXG4gICAgICAgICAgICB0aGlzLmNoYW5uZWxRdWVyeUNvbmZpZy5zb3J0LFxuICAgICAgICAgICAgdGhpcy5jaGFubmVsUXVlcnlDb25maWcub3B0aW9ucyxcbiAgICAgICAgICApO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGF3YWl0IHRoaXMuY2hhbm5lbE1hbmFnZXIubG9hZE5leHQoKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5jaGFubmVsTWFuYWdlclN1YnNjcmlwdGlvbnMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgIHRoaXMuY2hhbm5lbE1hbmFnZXJTdWJzY3JpcHRpb25zLnB1c2goXG4gICAgICAgICAgdGhpcy5jaGFubmVsTWFuYWdlci5zdGF0ZS5zdWJzY3JpYmVXaXRoU2VsZWN0b3IoXG4gICAgICAgICAgICAocykgPT4gKHsgY2hhbm5lbHM6IHMuY2hhbm5lbHMgfSksXG4gICAgICAgICAgICAoeyBjaGFubmVscyB9KSA9PiB7XG4gICAgICAgICAgICAgIGNvbnN0IGFjdGl2ZUNoYW5uZWwgPSB0aGlzLmFjdGl2ZUNoYW5uZWw7XG4gICAgICAgICAgICAgIGlmIChcbiAgICAgICAgICAgICAgICAhdGhpcy5pc1N0YXRlUmVjb3ZlcnlJblByb2dyZXNzJC5nZXRWYWx1ZSgpICYmXG4gICAgICAgICAgICAgICAgYWN0aXZlQ2hhbm5lbCAmJlxuICAgICAgICAgICAgICAgICFjaGFubmVscy5maW5kKChjKSA9PiBjLmNpZCA9PT0gYWN0aXZlQ2hhbm5lbC5jaWQpXG4gICAgICAgICAgICAgICkge1xuICAgICAgICAgICAgICAgIHRoaXMuZGVzZWxlY3RBY3RpdmVDaGFubmVsKCk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgdGhpcy5jaGFubmVsc1N1YmplY3QubmV4dChjaGFubmVscyk7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICksXG4gICAgICAgICk7XG4gICAgICAgIGlmICghdGhpcy5jdXN0b21DaGFubmVsUXVlcnkpIHtcbiAgICAgICAgICB0aGlzLmNoYW5uZWxNYW5hZ2VyU3Vic2NyaXB0aW9ucy5wdXNoKFxuICAgICAgICAgICAgdGhpcy5jaGFubmVsTWFuYWdlci5zdGF0ZS5zdWJzY3JpYmVXaXRoU2VsZWN0b3IoXG4gICAgICAgICAgICAgIChzKSA9PiAoeyBoYXNOZXh0OiBzLnBhZ2luYXRpb24/Lmhhc05leHQgPz8gdHJ1ZSB9KSxcbiAgICAgICAgICAgICAgKHsgaGFzTmV4dCB9KSA9PiB0aGlzLmhhc01vcmVDaGFubmVsc1N1YmplY3QubmV4dChoYXNOZXh0KSxcbiAgICAgICAgICAgICksXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAocXVlcnlUeXBlID09PSAncmVjb3Zlci1zdGF0ZScpIHtcbiAgICAgICAgYXdhaXQgdGhpcy5tYXliZVJlc3RvcmVBY3RpdmVDaGFubmVsQWZ0ZXJSZWNvdmVyeSgpO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBhY3RpdmVDaGFubmVsID0gdGhpcy5hY3RpdmVDaGFubmVsU3ViamVjdC5nZXRWYWx1ZSgpO1xuICAgICAgY29uc3Qgc2hvdWxkU2V0QWN0aXZlQ2hhbm5lbCA9XG4gICAgICAgIHF1ZXJ5VHlwZSA9PT0gJ25leHQtcGFnZScgPyBmYWxzZSA6IHRoaXMuc2hvdWxkU2V0QWN0aXZlQ2hhbm5lbDtcbiAgICAgIGlmIChcbiAgICAgICAgdGhpcy5jaGFubmVscy5sZW5ndGggPiAwICYmXG4gICAgICAgICFhY3RpdmVDaGFubmVsICYmXG4gICAgICAgIHNob3VsZFNldEFjdGl2ZUNoYW5uZWxcbiAgICAgICkge1xuICAgICAgICB0aGlzLnNldEFzQWN0aXZlQ2hhbm5lbCh0aGlzLmNoYW5uZWxzWzBdKTtcbiAgICAgIH1cblxuICAgICAgdGhpcy5jaGFubmVsUXVlcnlTdGF0ZVN1YmplY3QubmV4dCh7IHN0YXRlOiAnc3VjY2VzcycgfSk7XG4gICAgICB0aGlzLmRpc21pc3NFcnJvck5vdGlmaWNhdGlvbj8uKCk7XG4gICAgICByZXR1cm4gdGhpcy5jaGFubmVscztcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgdGhpcy5jaGFubmVsUXVlcnlTdGF0ZVN1YmplY3QubmV4dCh7XG4gICAgICAgIHN0YXRlOiAnZXJyb3InLFxuICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVuc2FmZS1hc3NpZ25tZW50XG4gICAgICAgIGVycm9yLFxuICAgICAgfSk7XG4gICAgICBpZiAocXVlcnlUeXBlID09PSAncmVjb3Zlci1zdGF0ZScpIHtcbiAgICAgICAgdGhpcy5kZXNlbGVjdEFjdGl2ZUNoYW5uZWwoKTtcbiAgICAgICAgdGhpcy5jaGFubmVsTWFuYWdlci5zZXRDaGFubmVscyhbXSk7XG4gICAgICB9XG4gICAgICBpZiAocXVlcnlUeXBlICE9PSAnbmV4dC1wYWdlJykge1xuICAgICAgICB0aGlzLmRpc21pc3NFcnJvck5vdGlmaWNhdGlvbiA9XG4gICAgICAgICAgdGhpcy5ub3RpZmljYXRpb25TZXJ2aWNlLmFkZFBlcm1hbmVudE5vdGlmaWNhdGlvbihcbiAgICAgICAgICAgICdzdHJlYW1DaGF0LkVycm9yIGxvYWRpbmcgY2hhbm5lbHMnLFxuICAgICAgICAgICAgJ2Vycm9yJyxcbiAgICAgICAgICApO1xuICAgICAgfVxuICAgICAgdGhyb3cgZXJyb3I7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBnZXQgY2FuU2VuZFJlYWRFdmVudHMoKSB7XG4gICAgY29uc3QgY2hhbm5lbCA9IHRoaXMuYWN0aXZlQ2hhbm5lbFN1YmplY3QuZ2V0VmFsdWUoKTtcbiAgICBpZiAoIWNoYW5uZWwpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgY29uc3QgY2FwYWJpbGl0ZXMgPSBjaGFubmVsLmRhdGE/Lm93bl9jYXBhYmlsaXRpZXMgYXMgc3RyaW5nW107XG4gICAgcmV0dXJuIGNhcGFiaWxpdGVzLmluZGV4T2YoJ3JlYWQtZXZlbnRzJykgIT09IC0xO1xuICB9XG5cbiAgcHJpdmF0ZSB0cmFuc2Zvcm1Ub1N0cmVhbU1lc3NhZ2UoXG4gICAgbWVzc2FnZTogU3RyZWFtTWVzc2FnZTxUPiB8IE1lc3NhZ2VSZXNwb25zZTxUPiB8IEZvcm1hdE1lc3NhZ2VSZXNwb25zZTxUPixcbiAgICBjaGFubmVsPzogQ2hhbm5lbDxUPixcbiAgKSB7XG4gICAgY29uc3QgaXNUaHJlYWRNZXNzYWdlID0gISFtZXNzYWdlLnBhcmVudF9pZDtcbiAgICBpZiAoXG4gICAgICB0aGlzLmlzU3RyZWFtTWVzc2FnZShtZXNzYWdlKSAmJlxuICAgICAgdGhpcy5pc0Zvcm1hdE1lc3NhZ2VSZXNwb25zZShtZXNzYWdlKVxuICAgICkge1xuICAgICAgaWYgKG1lc3NhZ2UucXVvdGVkX21lc3NhZ2UpIHtcbiAgICAgICAgbWVzc2FnZS5xdW90ZWRfbWVzc2FnZS50cmFuc2xhdGlvbiA9IGdldE1lc3NhZ2VUcmFuc2xhdGlvbihcbiAgICAgICAgICBtZXNzYWdlLnF1b3RlZF9tZXNzYWdlLFxuICAgICAgICAgIGNoYW5uZWwsXG4gICAgICAgICAgdGhpcy5jaGF0Q2xpZW50U2VydmljZS5jaGF0Q2xpZW50LnVzZXIsXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgICBtZXNzYWdlLnRyYW5zbGF0aW9uID0gZ2V0TWVzc2FnZVRyYW5zbGF0aW9uKFxuICAgICAgICBtZXNzYWdlLFxuICAgICAgICBjaGFubmVsLFxuICAgICAgICB0aGlzLmNoYXRDbGllbnRTZXJ2aWNlLmNoYXRDbGllbnQudXNlcixcbiAgICAgICk7XG4gICAgICByZXR1cm4gbWVzc2FnZTtcbiAgICB9IGVsc2Uge1xuICAgICAgaWYgKG1lc3NhZ2UucXVvdGVkX21lc3NhZ2UpIHtcbiAgICAgICAgbWVzc2FnZS5xdW90ZWRfbWVzc2FnZS50cmFuc2xhdGlvbiA9IGdldE1lc3NhZ2VUcmFuc2xhdGlvbihcbiAgICAgICAgICBtZXNzYWdlLnF1b3RlZF9tZXNzYWdlLFxuICAgICAgICAgIGNoYW5uZWwsXG4gICAgICAgICAgdGhpcy5jaGF0Q2xpZW50U2VydmljZS5jaGF0Q2xpZW50LnVzZXIsXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgICBpZiAodGhpcy5pc0Zvcm1hdE1lc3NhZ2VSZXNwb25zZShtZXNzYWdlKSkge1xuICAgICAgICBtZXNzYWdlLnJlYWRCeSA9IGlzVGhyZWFkTWVzc2FnZVxuICAgICAgICAgID8gW11cbiAgICAgICAgICA6IGNoYW5uZWxcbiAgICAgICAgICAgID8gZ2V0UmVhZEJ5KG1lc3NhZ2UsIGNoYW5uZWwpXG4gICAgICAgICAgICA6IFtdO1xuICAgICAgICBtZXNzYWdlLnRyYW5zbGF0aW9uID0gZ2V0TWVzc2FnZVRyYW5zbGF0aW9uKFxuICAgICAgICAgIG1lc3NhZ2UsXG4gICAgICAgICAgY2hhbm5lbCxcbiAgICAgICAgICB0aGlzLmNoYXRDbGllbnRTZXJ2aWNlLmNoYXRDbGllbnQudXNlcixcbiAgICAgICAgKTtcblxuICAgICAgICByZXR1cm4gbWVzc2FnZTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIG1lc3NhZ2UgPSB0aGlzLmZvcm1hdE1lc3NhZ2UobWVzc2FnZSk7XG4gICAgICAgIG1lc3NhZ2UucmVhZEJ5ID0gaXNUaHJlYWRNZXNzYWdlXG4gICAgICAgICAgPyBbXVxuICAgICAgICAgIDogY2hhbm5lbFxuICAgICAgICAgICAgPyBnZXRSZWFkQnkobWVzc2FnZSwgY2hhbm5lbClcbiAgICAgICAgICAgIDogW107XG4gICAgICAgIG1lc3NhZ2UudHJhbnNsYXRpb24gPSBnZXRNZXNzYWdlVHJhbnNsYXRpb24oXG4gICAgICAgICAgbWVzc2FnZSxcbiAgICAgICAgICBjaGFubmVsLFxuICAgICAgICAgIHRoaXMuY2hhdENsaWVudFNlcnZpY2UuY2hhdENsaWVudC51c2VyLFxuICAgICAgICApO1xuICAgICAgICByZXR1cm4gbWVzc2FnZTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGhhbmRsZVR5cGluZ1N0YXJ0RXZlbnQoZXZlbnQ6IEV2ZW50KSB7XG4gICAgaWYgKGV2ZW50LnVzZXI/LmlkID09PSB0aGlzLmNoYXRDbGllbnRTZXJ2aWNlLmNoYXRDbGllbnQudXNlcj8uaWQpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc3QgaXNUeXBpbmdJblRocmVhZCA9ICEhZXZlbnQucGFyZW50X2lkO1xuICAgIGlmIChcbiAgICAgIGlzVHlwaW5nSW5UaHJlYWQgJiZcbiAgICAgIGV2ZW50LnBhcmVudF9pZCAhPT0gdGhpcy5hY3RpdmVQYXJlbnRNZXNzYWdlSWRTdWJqZWN0LmdldFZhbHVlKClcbiAgICApIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc3Qgc3ViamVjdCA9IGlzVHlwaW5nSW5UaHJlYWRcbiAgICAgID8gdGhpcy51c2Vyc1R5cGluZ0luVGhyZWFkU3ViamVjdFxuICAgICAgOiB0aGlzLnVzZXJzVHlwaW5nSW5DaGFubmVsU3ViamVjdDtcbiAgICBjb25zdCB1c2VyczogVXNlclJlc3BvbnNlW10gPSBzdWJqZWN0LmdldFZhbHVlKCk7XG4gICAgY29uc3QgdXNlciA9IGV2ZW50LnVzZXI7XG4gICAgaWYgKHVzZXIgJiYgIXVzZXJzLmZpbmQoKHUpID0+IHUuaWQgPT09IHVzZXIuaWQpKSB7XG4gICAgICB1c2Vycy5wdXNoKHVzZXIpO1xuICAgICAgc3ViamVjdC5uZXh0KFsuLi51c2Vyc10pO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgaGFuZGxlVHlwaW5nU3RvcEV2ZW50KGV2ZW50OiBFdmVudCkge1xuICAgIGNvbnN0IHVzZXJzVHlwaW5nSW5DaGFubmVsID0gdGhpcy51c2Vyc1R5cGluZ0luQ2hhbm5lbFN1YmplY3QuZ2V0VmFsdWUoKTtcbiAgICBjb25zdCB1c2Vyc1R5cGluZ0luVGhyZWFkID0gdGhpcy51c2Vyc1R5cGluZ0luVGhyZWFkU3ViamVjdC5nZXRWYWx1ZSgpO1xuICAgIGNvbnN0IHVzZXIgPSBldmVudC51c2VyO1xuICAgIGlmICh1c2VyICYmIHVzZXJzVHlwaW5nSW5DaGFubmVsLmZpbmQoKHUpID0+IHUuaWQgPT09IHVzZXIuaWQpKSB7XG4gICAgICB1c2Vyc1R5cGluZ0luQ2hhbm5lbC5zcGxpY2UoXG4gICAgICAgIHVzZXJzVHlwaW5nSW5DaGFubmVsLmZpbmRJbmRleCgodSkgPT4gdS5pZCA9PT0gdXNlci5pZCksXG4gICAgICAgIDEsXG4gICAgICApO1xuICAgICAgdGhpcy51c2Vyc1R5cGluZ0luQ2hhbm5lbFN1YmplY3QubmV4dChbLi4udXNlcnNUeXBpbmdJbkNoYW5uZWxdKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgaWYgKHVzZXIgJiYgdXNlcnNUeXBpbmdJblRocmVhZC5maW5kKCh1KSA9PiB1LmlkID09PSB1c2VyLmlkKSkge1xuICAgICAgdXNlcnNUeXBpbmdJblRocmVhZC5zcGxpY2UoXG4gICAgICAgIHVzZXJzVHlwaW5nSW5UaHJlYWQuZmluZEluZGV4KCh1KSA9PiB1LmlkID09PSB1c2VyLmlkKSxcbiAgICAgICAgMSxcbiAgICAgICk7XG4gICAgICB0aGlzLnVzZXJzVHlwaW5nSW5UaHJlYWRTdWJqZWN0Lm5leHQoWy4uLnVzZXJzVHlwaW5nSW5UaHJlYWRdKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHVwZGF0ZUxhdGVzdE1lc3NhZ2VzKGV2ZW50OiBFdmVudCkge1xuICAgIGlmIChcbiAgICAgIGV2ZW50Lm1lc3NhZ2U/LnVzZXI/LmlkICE9PSB0aGlzLmNoYXRDbGllbnRTZXJ2aWNlPy5jaGF0Q2xpZW50LnVzZXI/LmlkXG4gICAgKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGNvbnN0IGxhdGVzdE1lc3NhZ2VzID1cbiAgICAgIHRoaXMubGF0ZXN0TWVzc2FnZURhdGVCeVVzZXJCeUNoYW5uZWxzU3ViamVjdC5nZXRWYWx1ZSgpO1xuICAgIGlmICghZXZlbnQubWVzc2FnZT8uY3JlYXRlZF9hdCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjb25zdCBjaGFubmVsSWQgPSBldmVudD8ubWVzc2FnZT8uY2lkO1xuICAgIGlmICghY2hhbm5lbElkKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGNvbnN0IG1lc3NhZ2VEYXRlID0gbmV3IERhdGUoZXZlbnQubWVzc2FnZS5jcmVhdGVkX2F0KTtcbiAgICBpZiAoXG4gICAgICAhbGF0ZXN0TWVzc2FnZXNbY2hhbm5lbElkXSB8fFxuICAgICAgbGF0ZXN0TWVzc2FnZXNbY2hhbm5lbElkXT8uZ2V0VGltZSgpIDwgbWVzc2FnZURhdGUuZ2V0VGltZSgpXG4gICAgKSB7XG4gICAgICBsYXRlc3RNZXNzYWdlc1tjaGFubmVsSWRdID0gbWVzc2FnZURhdGU7XG4gICAgICB0aGlzLmxhdGVzdE1lc3NhZ2VEYXRlQnlVc2VyQnlDaGFubmVsc1N1YmplY3QubmV4dCh7XG4gICAgICAgIC4uLmxhdGVzdE1lc3NhZ2VzLFxuICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBzZXRDaGFubmVsU3RhdGUoY2hhbm5lbDogQ2hhbm5lbDxUPikge1xuICAgIGNoYW5uZWwuc3RhdGUubWVzc2FnZXMuZm9yRWFjaCgobSkgPT4ge1xuICAgICAgbS5yZWFkQnkgPSBnZXRSZWFkQnkobSwgY2hhbm5lbCk7XG4gICAgICBtLnRyYW5zbGF0aW9uID0gZ2V0TWVzc2FnZVRyYW5zbGF0aW9uKFxuICAgICAgICBtLFxuICAgICAgICBjaGFubmVsLFxuICAgICAgICB0aGlzLmNoYXRDbGllbnRTZXJ2aWNlLmNoYXRDbGllbnQudXNlcixcbiAgICAgICk7XG4gICAgICBpZiAobS5xdW90ZWRfbWVzc2FnZSkge1xuICAgICAgICBtLnF1b3RlZF9tZXNzYWdlLnRyYW5zbGF0aW9uID0gZ2V0TWVzc2FnZVRyYW5zbGF0aW9uKFxuICAgICAgICAgIG0ucXVvdGVkX21lc3NhZ2UsXG4gICAgICAgICAgY2hhbm5lbCxcbiAgICAgICAgICB0aGlzLmNoYXRDbGllbnRTZXJ2aWNlLmNoYXRDbGllbnQudXNlcixcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICB0aGlzLm1hcmtSZWFkKGNoYW5uZWwpO1xuICAgIHRoaXMuYWN0aXZlQ2hhbm5lbE1lc3NhZ2VzU3ViamVjdC5uZXh0KFsuLi5jaGFubmVsLnN0YXRlLm1lc3NhZ2VzXSk7XG4gICAgdGhpcy5hY3RpdmVDaGFubmVsUGlubmVkTWVzc2FnZXNTdWJqZWN0Lm5leHQoW1xuICAgICAgLi4uY2hhbm5lbC5zdGF0ZS5waW5uZWRNZXNzYWdlcyxcbiAgICBdKTtcbiAgICB0aGlzLmFjdGl2ZVBhcmVudE1lc3NhZ2VJZFN1YmplY3QubmV4dCh1bmRlZmluZWQpO1xuICAgIHRoaXMuYWN0aXZlVGhyZWFkTWVzc2FnZXNTdWJqZWN0Lm5leHQoW10pO1xuICAgIHRoaXMubWVzc2FnZVRvUXVvdGVTdWJqZWN0Lm5leHQodW5kZWZpbmVkKTtcbiAgICB0aGlzLnVzZXJzVHlwaW5nSW5DaGFubmVsU3ViamVjdC5uZXh0KFtdKTtcbiAgICB0aGlzLnVzZXJzVHlwaW5nSW5UaHJlYWRTdWJqZWN0Lm5leHQoW10pO1xuICB9XG5cbiAgcHJpdmF0ZSBtYXJrUmVhZChjaGFubmVsOiBDaGFubmVsPFQ+LCBpc1Rocm90dGxlZCA9IHRydWUpIHtcbiAgICBpZiAoXG4gICAgICB0aGlzLmNhblNlbmRSZWFkRXZlbnRzICYmXG4gICAgICB0aGlzLnNob3VsZE1hcmtBY3RpdmVDaGFubmVsQXNSZWFkICYmXG4gICAgICAhdGhpcy5hcmVSZWFkRXZlbnRzUGF1c2VkXG4gICAgKSB7XG4gICAgICBpZiAoaXNUaHJvdHRsZWQpIHtcbiAgICAgICAgdGhpcy5tYXJrUmVhZFRocm90dGxlZChjaGFubmVsKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHZvaWQgY2hhbm5lbC5tYXJrUmVhZCgpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgbWFya1JlYWRUaHJvdHRsZWQoY2hhbm5lbDogQ2hhbm5lbDxUPikge1xuICAgIGlmICghdGhpcy5tYXJrUmVhZFRpbWVvdXQpIHtcbiAgICAgIHRoaXMubWFya1JlYWQoY2hhbm5lbCwgZmFsc2UpO1xuICAgICAgdGhpcy5tYXJrUmVhZFRpbWVvdXQgPSBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgdGhpcy5mbHVzaE1hcmtSZWFkUXVldWUoKTtcbiAgICAgIH0sIHRoaXMubWFya1JlYWRUaHJvdHRsZVRpbWUpO1xuICAgIH0gZWxzZSB7XG4gICAgICBjbGVhclRpbWVvdXQodGhpcy5tYXJrUmVhZFRpbWVvdXQpO1xuICAgICAgdGhpcy5zY2hlZHVsZWRNYXJrUmVhZFJlcXVlc3QgPSAoKSA9PiB0aGlzLm1hcmtSZWFkKGNoYW5uZWwsIGZhbHNlKTtcbiAgICAgIHRoaXMubWFya1JlYWRUaW1lb3V0ID0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgIHRoaXMuZmx1c2hNYXJrUmVhZFF1ZXVlKCk7XG4gICAgICB9LCB0aGlzLm1hcmtSZWFkVGhyb3R0bGVUaW1lKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGZsdXNoTWFya1JlYWRRdWV1ZSgpIHtcbiAgICB0aGlzLnNjaGVkdWxlZE1hcmtSZWFkUmVxdWVzdD8uKCk7XG4gICAgdGhpcy5zY2hlZHVsZWRNYXJrUmVhZFJlcXVlc3QgPSB1bmRlZmluZWQ7XG4gICAgY2xlYXJUaW1lb3V0KHRoaXMubWFya1JlYWRUaW1lb3V0KTtcbiAgICB0aGlzLm1hcmtSZWFkVGltZW91dCA9IHVuZGVmaW5lZDtcbiAgfVxuXG4gIHByaXZhdGUgX2luaXQoXG4gICAgb3B0aW9uczogQ2hhbm5lbFNlcnZpY2VPcHRpb25zPFQ+ICYgeyBtZXNzYWdlUGFnZVNpemU6IG51bWJlciB9LFxuICApIHtcbiAgICB0aGlzLm1lc3NhZ2VQYWdlU2l6ZSA9IG9wdGlvbnMubWVzc2FnZVBhZ2VTaXplO1xuXG4gICAgdGhpcy5zaG91bGRTZXRBY3RpdmVDaGFubmVsID1cbiAgICAgIG9wdGlvbnM/LnNob3VsZFNldEFjdGl2ZUNoYW5uZWwgPz8gdGhpcy5zaG91bGRTZXRBY3RpdmVDaGFubmVsO1xuICAgIGNvbnN0IGV2ZW50SGFuZGxlck92ZXJyaWRlcyA9IG9wdGlvbnM/LmV2ZW50SGFuZGxlck92ZXJyaWRlcztcbiAgICBjb25zdCBtYW5hZ2VyT3B0aW9ucyA9IHsgLi4ub3B0aW9ucyB9O1xuICAgIGRlbGV0ZSBtYW5hZ2VyT3B0aW9ucz8uZXZlbnRIYW5kbGVyT3ZlcnJpZGVzO1xuICAgIGRlbGV0ZSBtYW5hZ2VyT3B0aW9ucz8uc2hvdWxkU2V0QWN0aXZlQ2hhbm5lbDtcblxuICAgIHRoaXMuY3JlYXRlQ2hhbm5lbE1hbmFnZXIoe1xuICAgICAgZXZlbnRIYW5kbGVyT3ZlcnJpZGVzLFxuICAgICAgb3B0aW9uczogbWFuYWdlck9wdGlvbnMsXG4gICAgfSk7XG5cbiAgICB0aGlzLmNsaWVudEV2ZW50c1N1YnNjcmlwdGlvbiA9IHRoaXMuY2hhdENsaWVudFNlcnZpY2UuZXZlbnRzJC5zdWJzY3JpYmUoXG4gICAgICAobm90aWZpY2F0aW9uKSA9PiB2b2lkIHRoaXMuaGFuZGxlTm90aWZpY2F0aW9uKG5vdGlmaWNhdGlvbiksXG4gICAgKTtcbiAgICByZXR1cm4gdGhpcy5xdWVyeUNoYW5uZWxzKCdmaXJzdC1wYWdlJyk7XG4gIH1cblxuICBwcml2YXRlIGNyZWF0ZUNoYW5uZWxNYW5hZ2VyKHtcbiAgICBldmVudEhhbmRsZXJPdmVycmlkZXMsXG4gICAgb3B0aW9ucyxcbiAgfToge1xuICAgIGV2ZW50SGFuZGxlck92ZXJyaWRlcz86IENoYW5uZWxNYW5hZ2VyRXZlbnRIYW5kbGVyT3ZlcnJpZGVzPFQ+O1xuICAgIG9wdGlvbnM/OiBDaGFubmVsTWFuYWdlck9wdGlvbnM7XG4gIH0pIHtcbiAgICB0aGlzLmNoYW5uZWxNYW5hZ2VyID0gbmV3IENoYW5uZWxNYW5hZ2VyKHtcbiAgICAgIGNsaWVudDogdGhpcy5jaGF0Q2xpZW50U2VydmljZS5jaGF0Q2xpZW50LFxuICAgICAgb3B0aW9uczoge1xuICAgICAgICAuLi5vcHRpb25zLFxuICAgICAgICBhbGxvd05vdExvYWRlZENoYW5uZWxQcm9tb3Rpb25Gb3JFdmVudDoge1xuICAgICAgICAgICdtZXNzYWdlLm5ldyc6IGZhbHNlLFxuICAgICAgICAgICdjaGFubmVsLnZpc2libGUnOiB0cnVlLFxuICAgICAgICAgICdub3RpZmljYXRpb24uYWRkZWRfdG9fY2hhbm5lbCc6IHRydWUsXG4gICAgICAgICAgJ25vdGlmaWNhdGlvbi5tZXNzYWdlX25ldyc6IHRydWUsXG4gICAgICAgICAgLi4ub3B0aW9ucz8uYWxsb3dOb3RMb2FkZWRDaGFubmVsUHJvbW90aW9uRm9yRXZlbnQsXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgICAgZXZlbnRIYW5kbGVyT3ZlcnJpZGVzLFxuICAgIH0pO1xuICAgIHRoaXMuY2hhbm5lbE1hbmFnZXIucmVnaXN0ZXJTdWJzY3JpcHRpb25zKCk7XG4gIH1cblxuICBwcml2YXRlIGRlc3Ryb3lDaGFubmVsTWFuYWdlcigpIHtcbiAgICB0aGlzLmNoYW5uZWxNYW5hZ2VyPy51bnJlZ2lzdGVyU3Vic2NyaXB0aW9ucygpO1xuICAgIHRoaXMuY2hhbm5lbE1hbmFnZXIgPSB1bmRlZmluZWQ7XG4gICAgdGhpcy5jaGFubmVsTWFuYWdlclN1YnNjcmlwdGlvbnMuZm9yRWFjaCgodW5zdWJzY3JpYmUpID0+IHVuc3Vic2NyaWJlKCkpO1xuICAgIHRoaXMuY2hhbm5lbE1hbmFnZXJTdWJzY3JpcHRpb25zID0gW107XG4gICAgdGhpcy5jaGFubmVsc1N1YmplY3QubmV4dCh1bmRlZmluZWQpO1xuICAgIHRoaXMuaGFzTW9yZUNoYW5uZWxzU3ViamVjdC5uZXh0KHRydWUpO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBtYXliZVJlc3RvcmVBY3RpdmVDaGFubmVsQWZ0ZXJSZWNvdmVyeSgpIHtcbiAgICBjb25zdCBwcmV2aW91c0FjdGl2ZUNoYW5uZWwgPSB0aGlzLmFjdGl2ZUNoYW5uZWxTdWJqZWN0LmdldFZhbHVlKCk7XG4gICAgaWYgKCFwcmV2aW91c0FjdGl2ZUNoYW5uZWwpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdHJ5IHtcbiAgICAgIGlmICghdGhpcy5jaGFubmVscy5maW5kKChjKSA9PiBjLmNpZCA9PT0gcHJldmlvdXNBY3RpdmVDaGFubmVsPy5jaWQpKSB7XG4gICAgICAgIGF3YWl0IHByZXZpb3VzQWN0aXZlQ2hhbm5lbC53YXRjaCgpO1xuICAgICAgICAvLyBUaHJlYWQgbWVzc2FnZXMgYXJlIG5vdCByZWZldGNoZWQgc28gYWN0aXZlIHRocmVhZCBnZXRzIGRlc2VsZWN0ZWQgdG8gYXZvaWQgZGlzcGxheWluZyBzdGFsZSBtZXNzYWdlc1xuICAgICAgICB2b2lkIHRoaXMuc2V0QXNBY3RpdmVQYXJlbnRNZXNzYWdlKHVuZGVmaW5lZCk7XG4gICAgICAgIC8vIFVwZGF0ZSBhbmQgcmVzZWxlY3QgbWVzc2FnZSB0byBxdW90ZVxuICAgICAgICBjb25zdCBtZXNzYWdlVG9RdW90ZSA9IHRoaXMubWVzc2FnZVRvUXVvdGVTdWJqZWN0LmdldFZhbHVlKCk7XG4gICAgICAgIHRoaXMuc2V0Q2hhbm5lbFN0YXRlKHByZXZpb3VzQWN0aXZlQ2hhbm5lbCk7XG4gICAgICAgIGxldCBtZXNzYWdlcyE6IFN0cmVhbU1lc3NhZ2U8VD5bXTtcbiAgICAgICAgdGhpcy5hY3RpdmVDaGFubmVsTWVzc2FnZXMkXG4gICAgICAgICAgLnBpcGUodGFrZSgxKSlcbiAgICAgICAgICAuc3Vic2NyaWJlKChtKSA9PiAobWVzc2FnZXMgPSBtKSk7XG4gICAgICAgIGNvbnN0IHVwZGF0ZWRNZXNzYWdlVG9RdW90ZSA9IG1lc3NhZ2VzLmZpbmQoXG4gICAgICAgICAgKG0pID0+IG0uaWQgPT09IG1lc3NhZ2VUb1F1b3RlPy5pZCxcbiAgICAgICAgKTtcbiAgICAgICAgaWYgKHVwZGF0ZWRNZXNzYWdlVG9RdW90ZSkge1xuICAgICAgICAgIHRoaXMuc2VsZWN0TWVzc2FnZVRvUXVvdGUodXBkYXRlZE1lc3NhZ2VUb1F1b3RlKTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLmNoYW5uZWxNYW5hZ2VyPy5zZXRDaGFubmVscyhcbiAgICAgICAgICBwcm9tb3RlQ2hhbm5lbCh7XG4gICAgICAgICAgICBjaGFubmVsczogdGhpcy5jaGFubmVscyxcbiAgICAgICAgICAgIGNoYW5uZWxUb01vdmU6IHByZXZpb3VzQWN0aXZlQ2hhbm5lbCxcbiAgICAgICAgICAgIHNvcnQ6IHRoaXMuY2hhbm5lbFF1ZXJ5Q29uZmlnPy5zb3J0ID8/IFtdLFxuICAgICAgICAgIH0pLFxuICAgICAgICApO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICB0aGlzLmNoYXRDbGllbnRTZXJ2aWNlLmNoYXRDbGllbnQubG9nZ2VyKFxuICAgICAgICAnd2FybicsXG4gICAgICAgICdVbmFibGUgdG8gcmVmZXRjaCBhY3RpdmUgY2hhbm5lbCBhZnRlciBzdGF0ZSByZWNvdmVyJyxcbiAgICAgICAgZXJyb3IgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4sXG4gICAgICApO1xuICAgICAgdGhpcy5kZXNlbGVjdEFjdGl2ZUNoYW5uZWwoKTtcbiAgICB9XG4gIH1cbn1cbiJdfQ==
|